summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS1
-rw-r--r--Documentation/ABI/testing/configfs-iio21
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget-sourcesink2
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget-tcm6
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-ina2xx-adc24
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb27
-rw-r--r--Documentation/ABI/testing/sysfs-class-watchdog51
-rw-r--r--Documentation/ABI/testing/sysfs-fs-f2fs6
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-livepatch6
-rw-r--r--Documentation/ABI/testing/sysfs-ptp2
-rw-r--r--Documentation/CodingStyle2
-rw-r--r--Documentation/DMA-API.txt2
-rw-r--r--Documentation/DocBook/Makefile10
-rw-r--r--Documentation/DocBook/device-drivers.tmpl1
-rw-r--r--Documentation/DocBook/gpu.tmpl1003
-rw-r--r--Documentation/DocBook/iio.tmpl2
-rw-r--r--Documentation/DocBook/media/v4l/media-controller.xml44
-rw-r--r--Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml104
-rw-r--r--Documentation/DocBook/media/v4l/media-ioc-enum-links.xml56
-rw-r--r--Documentation/DocBook/media/v4l/media-ioc-g-topology.xml394
-rw-r--r--Documentation/DocBook/media/v4l/media-types.xml240
-rw-r--r--Documentation/DocBook/mtdnand.tmpl35
-rw-r--r--Documentation/HOWTO2
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/accounting/getdelays.c3
-rw-r--r--Documentation/arm/Marvell/README19
-rw-r--r--Documentation/arm/pxa/mfp.txt26
-rw-r--r--Documentation/block/cfq-iosched.txt15
-rw-r--r--Documentation/cpu-hotplug.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/arm,scpi.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt7
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt39
-rw-r--r--Documentation/devicetree/bindings/arm/compulab-boards.txt25
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/fsl.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt16
-rw-r--r--Documentation/devicetree/bindings/arm/marvell,kirkwood.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt18
-rw-r--r--Documentation/devicetree/bindings/arm/psci.txt25
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip.txt26
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt3
-rw-r--r--Documentation/devicetree/bindings/arm/scu.txt3
-rw-r--r--Documentation/devicetree/bindings/arm/secure.txt53
-rw-r--r--Documentation/devicetree/bindings/arm/shmobile.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/technologic.txt6
-rw-r--r--Documentation/devicetree/bindings/bus/uniphier-system-bus.txt66
-rw-r--r--Documentation/devicetree/bindings/clock/arm-syscon-icst.txt40
-rw-r--r--Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt31
-rw-r--r--Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt5
-rw-r--r--Documentation/devicetree/bindings/clock/cs2000-cp.txt22
-rw-r--r--Documentation/devicetree/bindings/clock/dove-divider-clock.txt28
-rw-r--r--Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt56
-rw-r--r--Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt30
-rw-r--r--Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt22
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gcc.txt1
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,mmcc.txt1
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt4
-rw-r--r--Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt56
-rw-r--r--Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt58
-rw-r--r--Documentation/devicetree/bindings/clock/samsung,s2mps11.txt49
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt10
-rw-r--r--Documentation/devicetree/bindings/clock/tango4-clock.txt23
-rw-r--r--Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt2
-rw-r--r--Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt2
-rw-r--r--Documentation/devicetree/bindings/display/bridge/tda998x.txt4
-rw-r--r--Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt54
-rw-r--r--Documentation/devicetree/bindings/display/exynos/exynos_dp.txt41
-rw-r--r--Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt7
-rw-r--r--Documentation/devicetree/bindings/display/msm/dsi.txt12
-rw-r--r--Documentation/devicetree/bindings/display/msm/mdp.txt26
-rw-r--r--Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt7
-rw-r--r--Documentation/devicetree/bindings/display/panel/innolux,g121x1-l03.txt7
-rw-r--r--Documentation/devicetree/bindings/display/panel/kyo,tcg121xglp.txt7
-rw-r--r--Documentation/devicetree/bindings/display/panel/panasonic,vvx10f034n00.txt20
-rw-r--r--Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt7
-rw-r--r--Documentation/devicetree/bindings/display/panel/sharp,ls043t1le01.txt22
-rw-r--r--Documentation/devicetree/bindings/display/panel/startek,startek-kd050c.txt4
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt60
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt1
-rw-r--r--Documentation/devicetree/bindings/display/simple-framebuffer.txt13
-rw-r--r--Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt13
-rw-r--r--Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt10
-rw-r--r--Documentation/devicetree/bindings/dma/stm32-dma.txt82
-rw-r--r--Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt6
-rw-r--r--Documentation/devicetree/bindings/eeprom/eeprom.txt21
-rw-r--r--Documentation/devicetree/bindings/extcon/extcon-arizona.txt60
-rw-r--r--Documentation/devicetree/bindings/extcon/extcon-max3355.txt21
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-pca953x.txt1
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-sx150x.txt3
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-tps65086.txt16
-rw-r--r--Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt2
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-at91.txt5
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt2
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-rcar.txt4
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c.txt36
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt16
-rw-r--r--Documentation/devicetree/bindings/iio/accel/mma8452.txt6
-rw-r--r--Documentation/devicetree/bindings/iio/adc/imx7d-adc.txt22
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mcp320x.txt30
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mcp3422.txt3
-rw-r--r--Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt48
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt20
-rw-r--r--Documentation/devicetree/bindings/iio/health/max30100.txt21
-rw-r--r--Documentation/devicetree/bindings/iio/light/us5182d.txt11
-rw-r--r--Documentation/devicetree/bindings/iio/st-sensors.txt1
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/goodix.txt14
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt4
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/ts4800-ts.txt11
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt1
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/qca,ath79-misc-intc.txt2
-rw-r--r--Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt12
-rw-r--r--Documentation/devicetree/bindings/media/exynos5-gsc.txt4
-rw-r--r--Documentation/devicetree/bindings/media/i2c/adp1653.txt7
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ath79-ddr-controller.txt8
-rw-r--r--Documentation/devicetree/bindings/mfd/arizona.txt24
-rw-r--r--Documentation/devicetree/bindings/mfd/palmas.txt2
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mpa01.txt90
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mps11.txt153
-rw-r--r--Documentation/devicetree/bindings/mfd/samsung,sec-core.txt88
-rw-r--r--Documentation/devicetree/bindings/mfd/syscon.txt4
-rw-r--r--Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt32
-rw-r--r--Documentation/devicetree/bindings/mtd/fsl-quadspi.txt3
-rw-r--r--Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt86
-rw-r--r--Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt56
-rw-r--r--Documentation/devicetree/bindings/mtd/mtk-quadspi.txt41
-rw-r--r--Documentation/devicetree/bindings/mtd/partition.txt2
-rw-r--r--Documentation/devicetree/bindings/net/cdns-emac.txt20
-rw-r--r--Documentation/devicetree/bindings/net/macb.txt3
-rw-r--r--Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt1
-rw-r--r--Documentation/devicetree/bindings/phy/phy-hi6220-usb.txt16
-rw-r--r--Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt39
-rw-r--r--Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt6
-rw-r--r--Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt1
-rw-r--r--Documentation/devicetree/bindings/phy/ti-phy.txt20
-rw-r--r--Documentation/devicetree/bindings/regulator/lm363x-regulator.txt34
-rw-r--r--Documentation/devicetree/bindings/regulator/pv88060.txt124
-rw-r--r--Documentation/devicetree/bindings/regulator/pv88090.txt65
-rw-r--r--Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt (renamed from Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt)84
-rw-r--r--Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt163
-rw-r--r--Documentation/devicetree/bindings/regulator/samsung,s2mpa01.txt79
-rw-r--r--Documentation/devicetree/bindings/regulator/samsung,s2mps11.txt102
-rw-r--r--Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt145
-rw-r--r--Documentation/devicetree/bindings/regulator/tps65217.txt10
-rw-r--r--Documentation/devicetree/bindings/reset/hisilicon,hi6220-reset.txt34
-rw-r--r--Documentation/devicetree/bindings/scsi/hisilicon-sas.txt69
-rw-r--r--Documentation/devicetree/bindings/serial/8250.txt1
-rw-r--r--Documentation/devicetree/bindings/serial/mtk-uart.txt14
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci-serial.txt44
-rw-r--r--Documentation/devicetree/bindings/soc/bcm/raspberrypi,bcm2835-power.txt47
-rw-r--r--Documentation/devicetree/bindings/soc/dove/pmu.txt56
-rw-r--r--Documentation/devicetree/bindings/soc/mediatek/scpsys.txt12
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt58
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt104
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smsm.txt104
-rw-r--r--Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt57
-rw-r--r--Documentation/devicetree/bindings/sound/ak4613.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/atmel-classd.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/atmel-pdmic.txt55
-rw-r--r--Documentation/devicetree/bindings/sound/da7218.txt104
-rw-r--r--Documentation/devicetree/bindings/sound/da7219.txt8
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,asrc.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,spdif.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/img,i2s-in.txt47
-rw-r--r--Documentation/devicetree/bindings/sound/img,i2s-out.txt51
-rw-r--r--Documentation/devicetree/bindings/sound/img,parallel-out.txt44
-rw-r--r--Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt18
-rw-r--r--Documentation/devicetree/bindings/sound/img,spdif-in.txt41
-rw-r--r--Documentation/devicetree/bindings/sound/img,spdif-out.txt44
-rw-r--r--Documentation/devicetree/bindings/sound/inno-rk3036.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/pcm179x.txt (renamed from Documentation/devicetree/bindings/sound/pcm1792a.txt)2
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt82
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-i2s.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/rt5616.txt26
-rw-r--r--Documentation/devicetree/bindings/sound/rt5651.txt41
-rw-r--r--Documentation/devicetree/bindings/sound/rt5659.txt75
-rw-r--r--Documentation/devicetree/bindings/sound/rt5677.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/sun4i-codec.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/ti,pcm3168a.txt48
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8974.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/wm8994.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/sh-msiof.txt1
-rw-r--r--Documentation/devicetree/bindings/spi/spi-mt65xx.txt9
-rw-r--r--Documentation/devicetree/bindings/spi/ti_qspi.txt22
-rw-r--r--Documentation/devicetree/bindings/sram/rockchip-pmu-sram.txt (renamed from Documentation/devicetree/bindings/arm/rockchip/pmu-sram.txt)0
-rw-r--r--Documentation/devicetree/bindings/sram/rockchip-smp-sram.txt (renamed from Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt)2
-rw-r--r--Documentation/devicetree/bindings/sram/samsung-sram.txt (renamed from Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt)2
-rw-r--r--Documentation/devicetree/bindings/sram/sram.txt (renamed from Documentation/devicetree/bindings/misc/sram.txt)0
-rw-r--r--Documentation/devicetree/bindings/sram/sunxi-sram.txt (renamed from Documentation/devicetree/bindings/soc/sunxi/sram.txt)2
-rw-r--r--Documentation/devicetree/bindings/staging/ion/hi6220-ion.txt31
-rw-r--r--Documentation/devicetree/bindings/thermal/qoriq-thermal.txt63
-rw-r--r--Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt1
-rw-r--r--Documentation/devicetree/bindings/usb/dwc2.txt1
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3-xilinx.txt33
-rw-r--r--Documentation/devicetree/bindings/usb/mt8173-xhci.txt51
-rw-r--r--Documentation/devicetree/bindings/usb/octeon-usb.txt62
-rw-r--r--Documentation/devicetree/bindings/usb/renesas_usb3.txt23
-rw-r--r--Documentation/devicetree/bindings/usb/renesas_usbhs.txt22
-rw-r--r--Documentation/devicetree/bindings/usb/usb-xhci.txt4
-rw-r--r--Documentation/devicetree/bindings/usb/usb3503.txt5
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt8
-rw-r--r--Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt35
-rw-r--r--Documentation/devicetree/bindings/watchdog/meson-wdt.txt (renamed from Documentation/devicetree/bindings/watchdog/meson6-wdt.txt)2
-rw-r--r--Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt12
-rw-r--r--Documentation/devicetree/bindings/watchdog/mtk-wdt.txt6
-rw-r--r--Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt18
-rw-r--r--Documentation/devicetree/bindings/watchdog/sp805-wdt.txt31
-rw-r--r--Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt25
-rw-r--r--Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt19
-rw-r--r--Documentation/dmaengine/client.txt59
-rw-r--r--Documentation/dmaengine/provider.txt20
-rw-r--r--Documentation/features/vm/pmdp_splitting_flush/arch-support.txt40
-rw-r--r--Documentation/filesystems/f2fs.txt10
-rw-r--r--Documentation/filesystems/porting6
-rw-r--r--Documentation/filesystems/proc.txt25
-rw-r--r--Documentation/filesystems/sharedsubtree.txt2
-rw-r--r--Documentation/filesystems/tmpfs.txt8
-rw-r--r--Documentation/gpio/consumer.txt2
-rw-r--r--Documentation/gpio/driver.txt6
-rw-r--r--Documentation/gpio/drivers-on-gpio.txt6
-rw-r--r--Documentation/iio/iio_configfs.txt93
-rw-r--r--Documentation/ioctl/botching-up-ioctls.txt6
-rw-r--r--Documentation/ja_JP/HOWTO3
-rw-r--r--Documentation/kernel-docs.txt2
-rw-r--r--Documentation/kernel-parameters.txt49
-rw-r--r--Documentation/ko_KR/HOWTO29
-rw-r--r--Documentation/md-cluster.txt314
-rw-r--r--Documentation/media-framework.txt372
-rw-r--r--Documentation/memory-barriers.txt28
-rw-r--r--Documentation/mtd/nand_ecc.txt58
-rw-r--r--Documentation/networking/can.txt9
-rw-r--r--Documentation/printk-formats.txt9
-rw-r--r--Documentation/s390/zfcpdump.txt22
-rw-r--r--Documentation/security/keys-trusted-encrypted.txt31
-rw-r--r--Documentation/sound/alsa/img,spdif-in.txt49
-rw-r--r--Documentation/spi/00-INDEX4
-rw-r--r--Documentation/spi/Makefile8
-rw-r--r--Documentation/stable_kernel_rules.txt2
-rw-r--r--Documentation/sysctl/vm.txt33
-rw-r--r--Documentation/thermal/sysfs-api.txt1
-rw-r--r--Documentation/usb/chipidea.txt4
-rw-r--r--Documentation/usb/gadget-testing.txt4
-rw-r--r--Documentation/usb/power-management.txt11
-rw-r--r--Documentation/video4linux/v4l2-framework.txt12
-rw-r--r--Documentation/vm/slub.txt2
-rw-r--r--Documentation/vm/transhuge.txt151
-rw-r--r--Documentation/watchdog/watchdog-kernel-api.txt77
-rw-r--r--Documentation/zh_CN/video4linux/v4l2-framework.txt8
-rw-r--r--MAINTAINERS137
-rw-r--r--Makefile8
-rw-r--r--arch/Kconfig68
-rw-r--r--arch/alpha/include/uapi/asm/mman.h2
-rw-r--r--arch/alpha/kernel/module.c2
-rw-r--r--arch/arc/Kconfig3
-rw-r--r--arch/arc/kernel/unwind.c4
-rw-r--r--arch/arc/mm/cache.c4
-rw-r--r--arch/arm/Kconfig127
-rw-r--r--arch/arm/Kconfig.debug415
-rw-r--r--arch/arm/Makefile6
-rw-r--r--arch/arm/boot/dts/Makefile63
-rw-r--r--arch/arm/boot/dts/am335x-baltos-ir5221.dts186
-rw-r--r--arch/arm/boot/dts/am335x-bone-common.dtsi118
-rw-r--r--arch/arm/boot/dts/am335x-boneblack.dts44
-rw-r--r--arch/arm/boot/dts/am335x-bonegreen.dts4
-rw-r--r--arch/arm/boot/dts/am335x-chiliboard.dts20
-rw-r--r--arch/arm/boot/dts/am335x-chilisom.dtsi94
-rw-r--r--arch/arm/boot/dts/am335x-cm-t335.dts396
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts233
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts280
-rw-r--r--arch/arm/boot/dts/am335x-lxm.dts120
-rw-r--r--arch/arm/boot/dts/am335x-nano.dts154
-rw-r--r--arch/arm/boot/dts/am335x-pepper.dts231
-rw-r--r--arch/arm/boot/dts/am335x-phycore-som.dtsi60
-rw-r--r--arch/arm/boot/dts/am335x-sbc-t335.dts219
-rw-r--r--arch/arm/boot/dts/am335x-shc.dts577
-rw-r--r--arch/arm/boot/dts/am335x-sl50.dts13
-rw-r--r--arch/arm/boot/dts/am335x-wega.dtsi58
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi96
-rw-r--r--arch/arm/boot/dts/am3517-craneboard.dts2
-rw-r--r--arch/arm/boot/dts/am4372.dtsi87
-rw-r--r--arch/arm/boot/dts/am437x-cm-t43.dts422
-rw-r--r--arch/arm/boot/dts/am437x-gp-evm.dts389
-rw-r--r--arch/arm/boot/dts/am437x-idk-evm.dts128
-rw-r--r--arch/arm/boot/dts/am437x-sbc-t43.dts180
-rw-r--r--arch/arm/boot/dts/am437x-sk-evm.dts298
-rw-r--r--arch/arm/boot/dts/am43x-epos-evm.dts246
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15.dts198
-rw-r--r--arch/arm/boot/dts/am57xx-cl-som-am57x.dts617
-rw-r--r--arch/arm/boot/dts/am57xx-sbc-am57x.dts179
-rw-r--r--arch/arm/boot/dts/arm-realview-pb11mp.dts681
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn102.dts2
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn104.dts2
-rw-r--r--arch/arm/boot/dts/armada-388-clearfog.dts456
-rw-r--r--arch/arm/boot/dts/armada-388-gp.dts10
-rw-r--r--arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi115
-rw-r--r--arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts72
-rw-r--r--arch/arm/boot/dts/armada-xp-netgear-rn2120.dts2
-rw-r--r--arch/arm/boot/dts/at91-sama5d2_xplained.dts21
-rw-r--r--arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi127
-rw-r--r--arch/arm/boot/dts/at91-sama5d4_ma5d4evk.dts170
-rw-r--r--arch/arm/boot/dts/at91-vinco.dts256
-rw-r--r--arch/arm/boot/dts/bcm-cygnus.dtsi101
-rw-r--r--arch/arm/boot/dts/bcm-nsp.dtsi232
-rw-r--r--arch/arm/boot/dts/bcm11351.dtsi2
-rw-r--r--arch/arm/boot/dts/bcm21664.dtsi2
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-a-plus.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-plus.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi.dtsi2
-rw-r--r--arch/arm/boot/dts/bcm2835.dtsi194
-rw-r--r--arch/arm/boot/dts/bcm2836-rpi-2-b.dts35
-rw-r--r--arch/arm/boot/dts/bcm2836.dtsi78
-rw-r--r--arch/arm/boot/dts/bcm283x.dtsi212
-rw-r--r--arch/arm/boot/dts/bcm4708.dtsi2
-rw-r--r--arch/arm/boot/dts/bcm4709-netgear-r8000.dts30
-rw-r--r--arch/arm/boot/dts/bcm5301x.dtsi92
-rw-r--r--arch/arm/boot/dts/bcm63138.dtsi36
-rw-r--r--arch/arm/boot/dts/bcm94708.dts56
-rw-r--r--arch/arm/boot/dts/bcm94709.dts56
-rw-r--r--arch/arm/boot/dts/bcm953012k.dts63
-rw-r--r--arch/arm/boot/dts/bcm958625k.dts59
-rw-r--r--arch/arm/boot/dts/berlin2.dtsi23
-rw-r--r--arch/arm/boot/dts/berlin2cd.dtsi23
-rw-r--r--arch/arm/boot/dts/berlin2q-marvell-dmp.dts38
-rw-r--r--arch/arm/boot/dts/berlin2q.dtsi34
-rw-r--r--arch/arm/boot/dts/compulab-sb-som.dtsi49
-rw-r--r--arch/arm/boot/dts/da850-enbw-cmc.dts8
-rw-r--r--arch/arm/boot/dts/da850-evm.dts8
-rw-r--r--arch/arm/boot/dts/da850.dtsi58
-rw-r--r--arch/arm/boot/dts/dm8148-evm.dts55
-rw-r--r--arch/arm/boot/dts/dm8148-t410.dts70
-rw-r--r--arch/arm/boot/dts/dm814x-clocks.dtsi109
-rw-r--r--arch/arm/boot/dts/dm814x.dtsi259
-rw-r--r--arch/arm/boot/dts/dm816x.dtsi14
-rw-r--r--arch/arm/boot/dts/dove-cubox.dts8
-rw-r--r--arch/arm/boot/dts/dove.dtsi22
-rw-r--r--arch/arm/boot/dts/dra62x-clocks.dtsi23
-rw-r--r--arch/arm/boot/dts/dra62x-j5eco-evm.dts80
-rw-r--r--arch/arm/boot/dts/dra62x.dtsi23
-rw-r--r--arch/arm/boot/dts/dra7-evm.dts255
-rw-r--r--arch/arm/boot/dts/dra7.dtsi7
-rw-r--r--arch/arm/boot/dts/dra72-evm.dts204
-rw-r--r--arch/arm/boot/dts/ea3250.dts41
-rw-r--r--arch/arm/boot/dts/emev2.dtsi2
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi14
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi32
-rw-r--r--arch/arm/boot/dts/exynos4210-origen.dts4
-rw-r--r--arch/arm/boot/dts/exynos4210-smdkv310.dts4
-rw-r--r--arch/arm/boot/dts/exynos4210-universal_c210.dts8
-rw-r--r--arch/arm/boot/dts/exynos4210.dtsi14
-rw-r--r--arch/arm/boot/dts/exynos4412-odroid-common.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidu3.dts1
-rw-r--r--arch/arm/boot/dts/exynos4412-origen.dts4
-rw-r--r--arch/arm/boot/dts/exynos4412-smdk4412.dts4
-rw-r--r--arch/arm/boot/dts/exynos4412-trats2.dts4
-rw-r--r--arch/arm/boot/dts/exynos4x12.dtsi5
-rw-r--r--arch/arm/boot/dts/exynos5.dtsi14
-rw-r--r--arch/arm/boot/dts/exynos5250-snow-common.dtsi6
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi9
-rw-r--r--arch/arm/boot/dts/exynos5410.dtsi14
-rw-r--r--arch/arm/boot/dts/exynos5420-peach-pit.dts5
-rw-r--r--arch/arm/boot/dts/exynos5420.dtsi19
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi5
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts2
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3.dts2
-rw-r--r--arch/arm/boot/dts/exynos5800-peach-pi.dts20
-rw-r--r--arch/arm/boot/dts/imx25-pinfunc.h3
-rw-r--r--arch/arm/boot/dts/imx25.dtsi4
-rw-r--r--arch/arm/boot/dts/imx28-cfa10057.dts4
-rw-r--r--arch/arm/boot/dts/imx28.dtsi11
-rw-r--r--arch/arm/boot/dts/imx51-ts4800.dts302
-rw-r--r--arch/arm/boot/dts/imx6dl.dtsi7
-rw-r--r--arch/arm/boot/dts/imx6q-novena.dts785
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi52
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw51xx.dtsi36
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw52xx.dtsi48
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw53xx.dtsi33
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw54xx.dtsi47
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw551x.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw552x.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi61
-rw-r--r--arch/arm/boot/dts/imx6sl.dtsi11
-rw-r--r--arch/arm/boot/dts/imx6sx.dtsi19
-rw-r--r--arch/arm/boot/dts/imx6ul.dtsi18
-rw-r--r--arch/arm/boot/dts/imx7d-cl-som-imx7.dts286
-rw-r--r--arch/arm/boot/dts/imx7d-sbc-imx7.dts42
-rw-r--r--arch/arm/boot/dts/imx7d-sdb.dts10
-rw-r--r--arch/arm/boot/dts/imx7d.dtsi22
-rw-r--r--arch/arm/boot/dts/kirkwood-nsa325.dts238
-rw-r--r--arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts178
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts155
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-som.dtsi44
-rw-r--r--arch/arm/boot/dts/lpc18xx.dtsi11
-rw-r--r--arch/arm/boot/dts/lpc32xx.dtsi142
-rw-r--r--arch/arm/boot/dts/lpc4337-ciaa.dts34
-rw-r--r--arch/arm/boot/dts/lpc4357-ea4357-devkit.dts5
-rw-r--r--arch/arm/boot/dts/lpc4357.dtsi4
-rw-r--r--arch/arm/boot/dts/ls1021a-qds.dts4
-rw-r--r--arch/arm/boot/dts/ls1021a-twr.dts13
-rw-r--r--arch/arm/boot/dts/ls1021a.dtsi21
-rw-r--r--arch/arm/boot/dts/meson8b-odroidc1.dts11
-rw-r--r--arch/arm/boot/dts/meson8b.dtsi6
-rw-r--r--arch/arm/boot/dts/mt2701-evb.dts (renamed from arch/arm/mach-netx/include/mach/param.h)29
-rw-r--r--arch/arm/boot/dts/mt2701.dtsi146
-rw-r--r--arch/arm/boot/dts/mt8135.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-beagle-xm.dts20
-rw-r--r--arch/arm/boot/dts/omap3-beagle.dts66
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3x.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-evm-37xx.dts54
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-igep0020.dts24
-rw-r--r--arch/arm/boot/dts/omap3-igep0030.dts24
-rw-r--r--arch/arm/boot/dts/omap3-ldp.dts60
-rw-r--r--arch/arm/boot/dts/omap3-lilly-a83x.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-n900.dts116
-rw-r--r--arch/arm/boot/dts/omap3-n950-n9.dtsi12
-rw-r--r--arch/arm/boot/dts/omap3-overo-alto35-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-palo35-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-palo43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-pandora-common.dtsi34
-rw-r--r--arch/arm/boot/dts/omap3-panel-sharp-ls037v7dw01.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-zoom3.dts60
-rw-r--r--arch/arm/boot/dts/omap3.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4-duovero-parlor.dts2
-rw-r--r--arch/arm/boot/dts/omap4-panda-a4.dts6
-rw-r--r--arch/arm/boot/dts/omap4-panda-common.dtsi164
-rw-r--r--arch/arm/boot/dts/omap4-panda-es.dts10
-rw-r--r--arch/arm/boot/dts/omap4-sdp-es23plus.dts6
-rw-r--r--arch/arm/boot/dts/omap4-sdp.dts110
-rw-r--r--arch/arm/boot/dts/omap4-var-om44customboard.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4.dtsi10
-rw-r--r--arch/arm/boot/dts/omap5-board-common.dtsi94
-rw-r--r--arch/arm/boot/dts/omap5-cm-t54.dts4
-rw-r--r--arch/arm/boot/dts/omap5-uevm.dts4
-rw-r--r--arch/arm/boot/dts/omap5.dtsi2
-rw-r--r--arch/arm/boot/dts/phy3250.dts41
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts16
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-ifc6410.dts22
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts436
-rw-r--r--arch/arm/boot/dts/qcom-apq8064.dtsi130
-rw-r--r--arch/arm/boot/dts/qcom-apq8074-dragonboard.dts2
-rw-r--r--arch/arm/boot/dts/qcom-apq8084-ifc6540.dts3
-rw-r--r--arch/arm/boot/dts/qcom-apq8084-mtp.dts1
-rw-r--r--arch/arm/boot/dts/qcom-apq8084.dtsi108
-rw-r--r--arch/arm/boot/dts/qcom-msm8960.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts382
-rw-r--r--arch/arm/boot/dts/qcom-msm8974.dtsi11
-rw-r--r--arch/arm/boot/dts/qcom-pm8841.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom-pm8941.dtsi21
-rw-r--r--arch/arm/boot/dts/qcom-pma8084.dtsi12
-rw-r--r--arch/arm/boot/dts/r7s72100.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a73a4-ape6evm.dts4
-rw-r--r--arch/arm/boot/dts/r8a7740-armadillo800eva.dts2
-rw-r--r--arch/arm/boot/dts/r8a7740.dtsi15
-rw-r--r--arch/arm/boot/dts/r8a7778-bockw.dts33
-rw-r--r--arch/arm/boot/dts/r8a7778.dtsi9
-rw-r--r--arch/arm/boot/dts/r8a7790-lager.dts56
-rw-r--r--arch/arm/boot/dts/r8a7790.dtsi32
-rw-r--r--arch/arm/boot/dts/r8a7791-henninger.dts320
-rw-r--r--arch/arm/boot/dts/r8a7791-koelsch.dts60
-rw-r--r--arch/arm/boot/dts/r8a7791-porter.dts56
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi65
-rw-r--r--arch/arm/boot/dts/r8a7793-gose.dts77
-rw-r--r--arch/arm/boot/dts/r8a7793.dtsi534
-rw-r--r--arch/arm/boot/dts/r8a7794-alt.dts140
-rw-r--r--arch/arm/boot/dts/r8a7794-silk.dts76
-rw-r--r--arch/arm/boot/dts/r8a7794.dtsi68
-rw-r--r--arch/arm/boot/dts/rk3036-evb.dts64
-rw-r--r--arch/arm/boot/dts/rk3036-kylin.dts300
-rw-r--r--arch/arm/boot/dts/rk3036.dtsi622
-rw-r--r--arch/arm/boot/dts/rk3066a.dtsi19
-rw-r--r--arch/arm/boot/dts/rk3188.dtsi15
-rw-r--r--arch/arm/boot/dts/rk3228-evb.dts66
-rw-r--r--arch/arm/boot/dts/rk3228.dtsi442
-rw-r--r--arch/arm/boot/dts/rk3288-evb-act8846.dts44
-rw-r--r--arch/arm/boot/dts/rk3288-evb-rk808.dts27
-rw-r--r--arch/arm/boot/dts/rk3288-evb.dtsi37
-rw-r--r--arch/arm/boot/dts/rk3288-r89.dts13
-rw-r--r--arch/arm/boot/dts/rk3288-rock2-som.dtsi1
-rw-r--r--arch/arm/boot/dts/rk3288-rock2-square.dts13
-rw-r--r--arch/arm/boot/dts/rk3288-thermal.dtsi14
-rw-r--r--arch/arm/boot/dts/rk3288-veyron-brain.dts139
-rw-r--r--arch/arm/boot/dts/rk3288-veyron-mickey.dts250
-rw-r--r--arch/arm/boot/dts/rk3288-veyron-minnie.dts12
-rw-r--r--arch/arm/boot/dts/rk3288-veyron-speedy.dts8
-rw-r--r--arch/arm/boot/dts/rk3288-veyron.dtsi5
-rw-r--r--arch/arm/boot/dts/rk3288.dtsi30
-rw-r--r--arch/arm/boot/dts/rk3xxx.dtsi1
-rw-r--r--arch/arm/boot/dts/sama5d2.dtsi31
-rw-r--r--arch/arm/boot/dts/sama5d4.dtsi26
-rw-r--r--arch/arm/boot/dts/sh73a0-kzm9g.dts2
-rw-r--r--arch/arm/boot/dts/sh73a0.dtsi86
-rw-r--r--arch/arm/boot/dts/socfpga.dtsi1
-rw-r--r--arch/arm/boot/dts/socfpga_arria5_socdk.dts1
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts1
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi34
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts94
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_socdk.dts1
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_sockit.dts1
-rw-r--r--arch/arm/boot/dts/ste-dbx5x0.dtsi33
-rw-r--r--arch/arm/boot/dts/ste-href-stuib.dtsi23
-rw-r--r--arch/arm/boot/dts/ste-href-tvk1281618.dtsi52
-rw-r--r--arch/arm/boot/dts/ste-hrefv60plus.dtsi18
-rw-r--r--arch/arm/boot/dts/ste-nomadik-s8815.dts2
-rw-r--r--arch/arm/boot/dts/ste-snowball.dts7
-rw-r--r--arch/arm/boot/dts/ste-u300.dts10
-rw-r--r--arch/arm/boot/dts/sun4i-a10-gemei-g9.dts54
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet1.dts48
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts164
-rw-r--r--arch/arm/boot/dts/sun4i-a10-mk802.dts4
-rw-r--r--arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts61
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi45
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts14
-rw-r--r--arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts241
-rw-r--r--arch/arm/boot/dts/sun5i-a13-utoo-p66.dts30
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts85
-rw-r--r--arch/arm/boot/dts/sun7i-a20-bananapi.dts4
-rw-r--r--arch/arm/boot/dts/sun7i-a20-icnova-swac.dts169
-rw-r--r--arch/arm/boot/dts/sun7i-a20-mk808c.dts4
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts77
-rw-r--r--arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts4
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts4
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3.dts4
-rw-r--r--arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts57
-rw-r--r--arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts12
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi41
-rw-r--r--arch/arm/boot/dts/sun8i-a23-a33.dtsi2
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts77
-rw-r--r--arch/arm/boot/dts/sun8i-h3.dtsi497
-rw-r--r--arch/arm/boot/dts/sun9i-a80-cubieboard4.dts30
-rw-r--r--arch/arm/boot/dts/sun9i-a80-optimus.dts24
-rw-r--r--arch/arm/boot/dts/sun9i-a80.dtsi159
-rw-r--r--arch/arm/boot/dts/tango4-common.dtsi130
-rw-r--r--arch/arm/boot/dts/tango4-smp8758.dtsi31
-rw-r--r--arch/arm/boot/dts/tango4-vantage-1172.dts37
-rw-r--r--arch/arm/boot/dts/tps65217.dtsi56
-rw-r--r--arch/arm/boot/dts/twl4030_omap3.dtsi2
-rw-r--r--arch/arm/boot/dts/twl6030_omap4.dtsi4
-rw-r--r--arch/arm/boot/dts/uniphier-common32.dtsi135
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld4.dtsi265
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi2
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro4.dtsi288
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro5.dtsi274
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld8.dtsi266
-rw-r--r--arch/arm/boot/dts/uniphier-proxstream2.dtsi269
-rw-r--r--arch/arm/boot/dts/versatile-ab.dts62
-rw-r--r--arch/arm/boot/dts/vf-colibri.dtsi26
-rw-r--r--arch/arm/boot/dts/vf610m4-cosmic.dts90
-rw-r--r--arch/arm/boot/dts/vfxxx.dtsi24
-rw-r--r--arch/arm/boot/dts/wm8505.dtsi4
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi8
-rw-r--r--arch/arm/boot/dts/zynq-zc702.dts4
-rw-r--r--arch/arm/common/mcpm_platsmp.c2
-rw-r--r--arch/arm/common/scoop.c2
-rw-r--r--arch/arm/configs/bcm2835_defconfig29
-rw-r--r--arch/arm/configs/ep93xx_defconfig1
-rw-r--r--arch/arm/configs/exynos_defconfig18
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig5
-rw-r--r--arch/arm/configs/lpc18xx_defconfig5
-rw-r--r--arch/arm/configs/lpc32xx_defconfig1
-rw-r--r--arch/arm/configs/multi_v5_defconfig43
-rw-r--r--arch/arm/configs/multi_v7_defconfig100
-rw-r--r--arch/arm/configs/mv78xx0_defconfig4
-rw-r--r--arch/arm/configs/mvebu_v5_defconfig40
-rw-r--r--arch/arm/configs/netwinder_defconfig1
-rw-r--r--arch/arm/configs/orion5x_defconfig4
-rw-r--r--arch/arm/configs/pxa_defconfig783
-rw-r--r--arch/arm/configs/qcom_defconfig16
-rw-r--r--arch/arm/configs/realview-smp_defconfig38
-rw-r--r--arch/arm/configs/realview_defconfig34
-rw-r--r--arch/arm/configs/s3c6400_defconfig2
-rw-r--r--arch/arm/configs/sama5_defconfig3
-rw-r--r--arch/arm/configs/shmobile_defconfig14
-rw-r--r--arch/arm/configs/socfpga_defconfig6
-rw-r--r--arch/arm/configs/stm32_defconfig2
-rw-r--r--arch/arm/configs/sunxi_defconfig14
-rw-r--r--arch/arm/configs/versatile_defconfig14
-rw-r--r--arch/arm/configs/zx_defconfig1
-rw-r--r--arch/arm/include/asm/barrier.h35
-rw-r--r--arch/arm/include/asm/cputype.h22
-rw-r--r--arch/arm/include/asm/div64.h283
-rw-r--r--arch/arm/include/asm/kvm_mmu.h5
-rw-r--r--arch/arm/include/asm/pgtable-3level.h10
-rw-r--r--arch/arm/include/asm/psci.h2
-rw-r--r--arch/arm/include/debug/dc21285.S (renamed from arch/arm/mach-footbridge/include/mach/debug-macro.S)0
-rw-r--r--arch/arm/kernel/devtree.c2
-rw-r--r--arch/arm/kernel/module-plts.c2
-rw-r--r--arch/arm/kernel/psci_smp.c2
-rw-r--r--arch/arm/kernel/xscale-cp0.c7
-rw-r--r--arch/arm/kvm/mmu.c10
-rw-r--r--arch/arm/lib/uaccess_with_memcpy.c5
-rw-r--r--arch/arm/mach-alpine/Kconfig3
-rw-r--r--arch/arm/mach-alpine/platsmp.c2
-rw-r--r--arch/arm/mach-at91/Kconfig15
-rw-r--r--arch/arm/mach-axxia/Kconfig3
-rw-r--r--arch/arm/mach-axxia/platsmp.c2
-rw-r--r--arch/arm/mach-bcm/Kconfig41
-rw-r--r--arch/arm/mach-bcm/Makefile11
-rw-r--r--arch/arm/mach-bcm/bcm63xx_smp.c2
-rw-r--r--arch/arm/mach-bcm/bcm_5301x.c35
-rw-r--r--arch/arm/mach-bcm/board_bcm2835.c5
-rw-r--r--arch/arm/mach-bcm/platsmp-brcmstb.c2
-rw-r--r--arch/arm/mach-bcm/platsmp.c (renamed from arch/arm/mach-bcm/kona_smp.c)146
-rw-r--r--arch/arm/mach-berlin/Kconfig3
-rw-r--r--arch/arm/mach-berlin/platsmp.c2
-rw-r--r--arch/arm/mach-clps711x/board-autcpu12.c2
-rw-r--r--arch/arm/mach-clps711x/board-p720t.c2
-rw-r--r--arch/arm/mach-cns3xxx/Kconfig3
-rw-r--r--arch/arm/mach-davinci/Kconfig3
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c2
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-dm355-leopard.c4
-rw-r--r--arch/arm/mach-davinci/board-mityomapl138.c2
-rw-r--r--arch/arm/mach-davinci/board-omapl138-hawk.c2
-rw-r--r--arch/arm/mach-davinci/clock.c2
-rw-r--r--arch/arm/mach-davinci/cp_intc.c2
-rw-r--r--arch/arm/mach-davinci/cp_intc.h (renamed from arch/arm/mach-davinci/include/mach/cp_intc.h)0
-rw-r--r--arch/arm/mach-davinci/cpuidle.c4
-rw-r--r--arch/arm/mach-davinci/cpuidle.h (renamed from arch/arm/mach-davinci/include/mach/cpuidle.h)0
-rw-r--r--arch/arm/mach-davinci/da830.c2
-rw-r--r--arch/arm/mach-davinci/da850.c2
-rw-r--r--arch/arm/mach-davinci/da8xx-dt.c2
-rw-r--r--arch/arm/mach-davinci/ddr2.h (renamed from arch/arm/mach-davinci/include/mach/ddr2.h)0
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c4
-rw-r--r--arch/arm/mach-davinci/dm355.c2
-rw-r--r--arch/arm/mach-davinci/dm365.c2
-rw-r--r--arch/arm/mach-davinci/dm644x.c2
-rw-r--r--arch/arm/mach-davinci/dm646x.c2
-rw-r--r--arch/arm/mach-davinci/pm.c2
-rw-r--r--arch/arm/mach-davinci/psc.c2
-rw-r--r--arch/arm/mach-davinci/psc.h (renamed from arch/arm/mach-davinci/include/mach/psc.h)0
-rw-r--r--arch/arm/mach-davinci/sleep.S4
-rw-r--r--arch/arm/mach-davinci/sram.c2
-rw-r--r--arch/arm/mach-davinci/sram.h (renamed from arch/arm/mach-davinci/include/mach/sram.h)0
-rw-r--r--arch/arm/mach-dove/cm-a510.c1
-rw-r--r--arch/arm/mach-dove/common.c43
-rw-r--r--arch/arm/mach-dove/dove-db-setup.c1
-rw-r--r--arch/arm/mach-dove/include/mach/dove.h2
-rw-r--r--arch/arm/mach-dove/include/mach/entry-macro.S33
-rw-r--r--arch/arm/mach-dove/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-dove/include/mach/pm.h20
-rw-r--r--arch/arm/mach-dove/irq.c100
-rw-r--r--arch/arm/mach-ep93xx/snappercl15.c4
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c4
-rw-r--r--arch/arm/mach-exynos/Kconfig6
-rw-r--r--arch/arm/mach-exynos/common.h2
-rw-r--r--arch/arm/mach-exynos/platsmp.c2
-rw-r--r--arch/arm/mach-exynos/pmu.c45
-rw-r--r--arch/arm/mach-exynos/regs-pmu.h9
-rw-r--r--arch/arm/mach-highbank/Kconfig3
-rw-r--r--arch/arm/mach-hisi/Kconfig12
-rw-r--r--arch/arm/mach-hisi/core.h3
-rw-r--r--arch/arm/mach-hisi/platmcpm.c2
-rw-r--r--arch/arm/mach-hisi/platsmp.c6
-rw-r--r--arch/arm/mach-imx/Kconfig7
-rw-r--r--arch/arm/mach-imx/common.h4
-rw-r--r--arch/arm/mach-imx/iomux-imx31.c2
-rw-r--r--arch/arm/mach-imx/mach-imx6ul.c2
-rw-r--r--arch/arm/mach-imx/mach-imx7d.c6
-rw-r--r--arch/arm/mach-imx/mach-mx21ads.c2
-rw-r--r--arch/arm/mach-imx/mach-qong.c2
-rw-r--r--arch/arm/mach-imx/platsmp.c4
-rw-r--r--arch/arm/mach-integrator/Kconfig135
-rw-r--r--arch/arm/mach-iop13xx/include/mach/pci.h57
-rw-r--r--arch/arm/mach-iop13xx/iq81340mc.c2
-rw-r--r--arch/arm/mach-iop13xx/iq81340sc.c2
-rw-r--r--arch/arm/mach-iop13xx/irq.c2
-rw-r--r--arch/arm/mach-iop13xx/msi.h (renamed from arch/arm/mach-iop13xx/include/mach/msi.h)0
-rw-r--r--arch/arm/mach-iop13xx/pci.c2
-rw-r--r--arch/arm/mach-iop13xx/pci.h58
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-setup.c6
-rw-r--r--arch/arm/mach-keystone/keystone.h2
-rw-r--r--arch/arm/mach-keystone/platsmp.c2
-rw-r--r--arch/arm/mach-ks8695/board-acs5k.c2
-rw-r--r--arch/arm/mach-ks8695/board-dsm320.c2
-rw-r--r--arch/arm/mach-ks8695/board-micrel.c2
-rw-r--r--arch/arm/mach-ks8695/board-og.c2
-rw-r--r--arch/arm/mach-ks8695/board-sg.c2
-rw-r--r--arch/arm/mach-ks8695/cpu.c2
-rw-r--r--arch/arm/mach-ks8695/devices.c6
-rw-r--r--arch/arm/mach-ks8695/devices.h (renamed from arch/arm/mach-ks8695/include/mach/devices.h)0
-rw-r--r--arch/arm/mach-ks8695/pci.c4
-rw-r--r--arch/arm/mach-ks8695/regs-hpna.h (renamed from arch/arm/mach-ks8695/include/mach/regs-hpna.h)0
-rw-r--r--arch/arm/mach-ks8695/regs-lan.h (renamed from arch/arm/mach-ks8695/include/mach/regs-lan.h)0
-rw-r--r--arch/arm/mach-ks8695/regs-mem.h (renamed from arch/arm/mach-ks8695/include/mach/regs-mem.h)0
-rw-r--r--arch/arm/mach-ks8695/regs-pci.h (renamed from arch/arm/mach-ks8695/include/mach/regs-pci.h)0
-rw-r--r--arch/arm/mach-ks8695/regs-sys.h (renamed from arch/arm/mach-ks8695/include/mach/regs-sys.h)0
-rw-r--r--arch/arm/mach-ks8695/regs-wan.h (renamed from arch/arm/mach-ks8695/include/mach/regs-wan.h)0
-rw-r--r--arch/arm/mach-mediatek/Kconfig3
-rw-r--r--arch/arm/mach-mediatek/mediatek.c1
-rw-r--r--arch/arm/mach-mediatek/platsmp.c4
-rw-r--r--arch/arm/mach-meson/Kconfig3
-rw-r--r--arch/arm/mach-mmp/Kconfig34
-rw-r--r--arch/arm/mach-mmp/Makefile1
-rw-r--r--arch/arm/mach-mmp/addr-map.h (renamed from arch/arm/mach-mmp/include/mach/addr-map.h)2
-rw-r--r--arch/arm/mach-mmp/aspenite.c8
-rw-r--r--arch/arm/mach-mmp/avengers_lite.c8
-rw-r--r--arch/arm/mach-mmp/brownstone.c8
-rw-r--r--arch/arm/mach-mmp/clock-mmp2.c6
-rw-r--r--arch/arm/mach-mmp/clock-pxa168.c6
-rw-r--r--arch/arm/mach-mmp/clock-pxa910.c6
-rw-r--r--arch/arm/mach-mmp/clock.c2
-rw-r--r--arch/arm/mach-mmp/clock.h2
-rw-r--r--arch/arm/mach-mmp/common.c4
-rw-r--r--arch/arm/mach-mmp/common.h3
-rw-r--r--arch/arm/mach-mmp/cputype.h (renamed from arch/arm/mach-mmp/include/mach/cputype.h)0
-rw-r--r--arch/arm/mach-mmp/devices.c13
-rw-r--r--arch/arm/mach-mmp/devices.h (renamed from arch/arm/mach-mmp/include/mach/devices.h)0
-rw-r--r--arch/arm/mach-mmp/flint.c8
-rw-r--r--arch/arm/mach-mmp/gplugd.c6
-rw-r--r--arch/arm/mach-mmp/include/mach/dma.h13
-rw-r--r--arch/arm/mach-mmp/include/mach/hardware.h4
-rw-r--r--arch/arm/mach-mmp/include/mach/regs-smc.h37
-rw-r--r--arch/arm/mach-mmp/include/mach/uncompress.h45
-rw-r--r--arch/arm/mach-mmp/irqs.h (renamed from arch/arm/mach-mmp/include/mach/irqs.h)0
-rw-r--r--arch/arm/mach-mmp/jasper.c8
-rw-r--r--arch/arm/mach-mmp/mfp-mmp2.h (renamed from arch/arm/mach-mmp/include/mach/mfp-mmp2.h)2
-rw-r--r--arch/arm/mach-mmp/mfp-pxa168.h (renamed from arch/arm/mach-mmp/include/mach/mfp-pxa168.h)2
-rw-r--r--arch/arm/mach-mmp/mfp-pxa910.h (renamed from arch/arm/mach-mmp/include/mach/mfp-pxa910.h)2
-rw-r--r--arch/arm/mach-mmp/mfp.h (renamed from arch/arm/mach-mmp/include/mach/mfp.h)0
-rw-r--r--arch/arm/mach-mmp/mmp2.c23
-rw-r--r--arch/arm/mach-mmp/mmp2.h (renamed from arch/arm/mach-mmp/include/mach/mmp2.h)3
-rw-r--r--arch/arm/mach-mmp/pm-mmp2.c12
-rw-r--r--arch/arm/mach-mmp/pm-mmp2.h (renamed from arch/arm/mach-mmp/include/mach/pm-mmp2.h)2
-rw-r--r--arch/arm/mach-mmp/pm-pxa910.c12
-rw-r--r--arch/arm/mach-mmp/pm-pxa910.h (renamed from arch/arm/mach-mmp/include/mach/pm-pxa910.h)0
-rw-r--r--arch/arm/mach-mmp/pxa168.c29
-rw-r--r--arch/arm/mach-mmp/pxa168.h (renamed from arch/arm/mach-mmp/include/mach/pxa168.h)5
-rw-r--r--arch/arm/mach-mmp/pxa910.c24
-rw-r--r--arch/arm/mach-mmp/pxa910.h (renamed from arch/arm/mach-mmp/include/mach/pxa910.h)3
-rw-r--r--arch/arm/mach-mmp/regs-apbc.h (renamed from arch/arm/mach-mmp/include/mach/regs-apbc.h)4
-rw-r--r--arch/arm/mach-mmp/regs-apmu.h (renamed from arch/arm/mach-mmp/include/mach/regs-apmu.h)4
-rw-r--r--arch/arm/mach-mmp/regs-icu.h (renamed from arch/arm/mach-mmp/include/mach/regs-icu.h)4
-rw-r--r--arch/arm/mach-mmp/regs-timers.h (renamed from arch/arm/mach-mmp/include/mach/regs-timers.h)4
-rw-r--r--arch/arm/mach-mmp/regs-usb.h (renamed from arch/arm/mach-mmp/include/mach/regs-usb.h)0
-rw-r--r--arch/arm/mach-mmp/tavorevb.c8
-rw-r--r--arch/arm/mach-mmp/teton_bga.c10
-rw-r--r--arch/arm/mach-mmp/teton_bga.h (renamed from arch/arm/mach-mmp/include/mach/teton_bga.h)2
-rw-r--r--arch/arm/mach-mmp/time.c11
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c10
-rw-r--r--arch/arm/mach-moxart/Kconfig3
-rw-r--r--arch/arm/mach-mv78xx0/Kconfig15
-rw-r--r--arch/arm/mach-mv78xx0/Makefile2
-rw-r--r--arch/arm/mach-mv78xx0/bridge-regs.h (renamed from arch/arm/mach-mv78xx0/include/mach/bridge-regs.h)4
-rw-r--r--arch/arm/mach-mv78xx0/buffalo-wxl-setup.c3
-rw-r--r--arch/arm/mach-mv78xx0/common.c4
-rw-r--r--arch/arm/mach-mv78xx0/db78x00-bp-setup.c3
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/entry-macro.S41
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/hardware.h14
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/uncompress.h46
-rw-r--r--arch/arm/mach-mv78xx0/irq.c35
-rw-r--r--arch/arm/mach-mv78xx0/irqs.h (renamed from arch/arm/mach-mv78xx0/include/mach/irqs.h)4
-rw-r--r--arch/arm/mach-mv78xx0/mpp.c2
-rw-r--r--arch/arm/mach-mv78xx0/mv78xx0.h (renamed from arch/arm/mach-mv78xx0/include/mach/mv78xx0.h)4
-rw-r--r--arch/arm/mach-mv78xx0/pcie.c2
-rw-r--r--arch/arm/mach-mv78xx0/rd78x00-masa-setup.c3
-rw-r--r--arch/arm/mach-mvebu/Kconfig24
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h2
-rw-r--r--arch/arm/mach-mvebu/include/mach/gpio.h1
-rw-r--r--arch/arm/mach-mvebu/platsmp-a9.c4
-rw-r--r--arch/arm/mach-mvebu/platsmp.c2
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c4
-rw-r--r--arch/arm/mach-omap1/board-fsample.c2
-rw-r--r--arch/arm/mach-omap1/board-h2.c2
-rw-r--r--arch/arm/mach-omap1/board-h3.c2
-rw-r--r--arch/arm/mach-omap1/board-innovator.c2
-rw-r--r--arch/arm/mach-omap1/board-nand.c2
-rw-r--r--arch/arm/mach-omap1/board-osk.c2
-rw-r--r--arch/arm/mach-omap1/board-palmte.c2
-rw-r--r--arch/arm/mach-omap1/board-palmtt.c2
-rw-r--r--arch/arm/mach-omap1/board-palmz71.c2
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c2
-rw-r--r--arch/arm/mach-omap1/board-sx1-mmc.c2
-rw-r--r--arch/arm/mach-omap1/board-sx1.c4
-rw-r--r--arch/arm/mach-omap1/board-sx1.h (renamed from arch/arm/mach-omap1/include/mach/board-sx1.h)0
-rw-r--r--arch/arm/mach-omap1/camera.h (renamed from arch/arm/mach-omap1/include/mach/camera.h)0
-rw-r--r--arch/arm/mach-omap1/devices.c21
-rw-r--r--arch/arm/mach-omap1/flash.c2
-rw-r--r--arch/arm/mach-omap1/flash.h (renamed from arch/arm/mach-omap1/include/mach/flash.h)0
-rw-r--r--arch/arm/mach-omap2/Makefile2
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c2
-rw-r--r--arch/arm/mach-omap2/clock.c4
-rw-r--r--arch/arm/mach-omap2/clockdomains81xx_data.c29
-rw-r--r--arch/arm/mach-omap2/cm81xx.h6
-rw-r--r--arch/arm/mach-omap2/common.h2
-rw-r--r--arch/arm/mach-omap2/devices.c25
-rw-r--r--arch/arm/mach-omap2/id.c4
-rw-r--r--arch/arm/mach-omap2/io.c3
-rw-r--r--arch/arm/mach-omap2/omap-iommu.c66
-rw-r--r--arch/arm/mach-omap2/omap-smp.c2
-rw-r--r--arch/arm/mach-omap2/omap2-restart.c2
-rw-r--r--arch/arm/mach-omap2/omap_device.c2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c42
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c41
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_7xx_data.c2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_81xx_data.c178
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c26
-rw-r--r--arch/arm/mach-omap2/powerdomains3xxx_data.c10
-rw-r--r--arch/arm/mach-omap2/prm_common.c8
-rw-r--r--arch/arm/mach-omap2/serial.c2
-rw-r--r--arch/arm/mach-omap2/timer.c6
-rw-r--r--arch/arm/mach-orion5x/Kconfig18
-rw-r--r--arch/arm/mach-orion5x/Makefile2
-rw-r--r--arch/arm/mach-orion5x/board-d2net.c2
-rw-r--r--arch/arm/mach-orion5x/board-dt.c4
-rw-r--r--arch/arm/mach-orion5x/board-mss2.c4
-rw-r--r--arch/arm/mach-orion5x/board-rd88f5182.c2
-rw-r--r--arch/arm/mach-orion5x/bridge-regs.h (renamed from arch/arm/mach-orion5x/include/mach/bridge-regs.h)4
-rw-r--r--arch/arm/mach-orion5x/common.c20
-rw-r--r--arch/arm/mach-orion5x/db88f5281-setup.c3
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c3
-rw-r--r--arch/arm/mach-orion5x/include/mach/entry-macro.S25
-rw-r--r--arch/arm/mach-orion5x/include/mach/uncompress.h48
-rw-r--r--arch/arm/mach-orion5x/irq.c13
-rw-r--r--arch/arm/mach-orion5x/irqs.h (renamed from arch/arm/mach-orion5x/include/mach/irqs.h)4
-rw-r--r--arch/arm/mach-orion5x/kurobox_pro-setup.c4
-rw-r--r--arch/arm/mach-orion5x/ls-chl-setup.c3
-rw-r--r--arch/arm/mach-orion5x/ls_hgl-setup.c3
-rw-r--r--arch/arm/mach-orion5x/mpp.c2
-rw-r--r--arch/arm/mach-orion5x/mv2120-setup.c3
-rw-r--r--arch/arm/mach-orion5x/net2big-setup.c3
-rw-r--r--arch/arm/mach-orion5x/orion5x.h (renamed from arch/arm/mach-orion5x/include/mach/orion5x.h)4
-rw-r--r--arch/arm/mach-orion5x/pci.c2
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c3
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c3
-rw-r--r--arch/arm/mach-orion5x/rd88f5182-setup.c3
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c3
-rw-r--r--arch/arm/mach-orion5x/terastation_pro2-setup.c3
-rw-r--r--arch/arm/mach-orion5x/ts209-setup.c3
-rw-r--r--arch/arm/mach-orion5x/ts409-setup.c3
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c9
-rw-r--r--arch/arm/mach-orion5x/tsx09-common.c2
-rw-r--r--arch/arm/mach-orion5x/wnr854t-setup.c3
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c3
-rw-r--r--arch/arm/mach-picoxcell/Kconfig3
-rw-r--r--arch/arm/mach-prima2/Kconfig3
-rw-r--r--arch/arm/mach-prima2/common.h2
-rw-r--r--arch/arm/mach-prima2/platsmp.c2
-rw-r--r--arch/arm/mach-pxa/am200epd.c4
-rw-r--r--arch/arm/mach-pxa/am300epd.c4
-rw-r--r--arch/arm/mach-pxa/balloon3.c8
-rw-r--r--arch/arm/mach-pxa/capc7117.c4
-rw-r--r--arch/arm/mach-pxa/cm-x255.c2
-rw-r--r--arch/arm/mach-pxa/cm-x270.c2
-rw-r--r--arch/arm/mach-pxa/cm-x2xx.c13
-rw-r--r--arch/arm/mach-pxa/cm-x300.c4
-rw-r--r--arch/arm/mach-pxa/colibri-evalboard.c6
-rw-r--r--arch/arm/mach-pxa/colibri-pxa270-income.c4
-rw-r--r--arch/arm/mach-pxa/colibri-pxa270.c4
-rw-r--r--arch/arm/mach-pxa/colibri-pxa300.c4
-rw-r--r--arch/arm/mach-pxa/colibri-pxa320.c8
-rw-r--r--arch/arm/mach-pxa/colibri-pxa3xx.c4
-rw-r--r--arch/arm/mach-pxa/colibri.h (renamed from arch/arm/mach-pxa/include/mach/colibri.h)0
-rw-r--r--arch/arm/mach-pxa/corgi.c6
-rw-r--r--arch/arm/mach-pxa/corgi_pm.c2
-rw-r--r--arch/arm/mach-pxa/csb726.c4
-rw-r--r--arch/arm/mach-pxa/csb726.h (renamed from arch/arm/mach-pxa/include/mach/csb726.h)2
-rw-r--r--arch/arm/mach-pxa/devices.c2
-rw-r--r--arch/arm/mach-pxa/em-x270.c6
-rw-r--r--arch/arm/mach-pxa/eseries-irq.h (renamed from arch/arm/mach-pxa/include/mach/eseries-irq.h)0
-rw-r--r--arch/arm/mach-pxa/eseries.c6
-rw-r--r--arch/arm/mach-pxa/ezx.c12
-rw-r--r--arch/arm/mach-pxa/gumstix.c6
-rw-r--r--arch/arm/mach-pxa/gumstix.h (renamed from arch/arm/mach-pxa/include/mach/gumstix.h)2
-rw-r--r--arch/arm/mach-pxa/h5000.c6
-rw-r--r--arch/arm/mach-pxa/h5000.h (renamed from arch/arm/mach-pxa/include/mach/h5000.h)2
-rw-r--r--arch/arm/mach-pxa/himalaya.c2
-rw-r--r--arch/arm/mach-pxa/hx4700.c2
-rw-r--r--arch/arm/mach-pxa/icontrol.c4
-rw-r--r--arch/arm/mach-pxa/idp.c4
-rw-r--r--arch/arm/mach-pxa/idp.h (renamed from arch/arm/mach-pxa/include/mach/idp.h)2
-rw-r--r--arch/arm/mach-pxa/littleton.c4
-rw-r--r--arch/arm/mach-pxa/littleton.h (renamed from arch/arm/mach-pxa/include/mach/littleton.h)0
-rw-r--r--arch/arm/mach-pxa/lpd270.c4
-rw-r--r--arch/arm/mach-pxa/lpd270.h (renamed from arch/arm/mach-pxa/include/mach/lpd270.h)0
-rw-r--r--arch/arm/mach-pxa/lubbock.c6
-rw-r--r--arch/arm/mach-pxa/magician.c6
-rw-r--r--arch/arm/mach-pxa/mainstone.c2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa25x.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa25x.h)2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa27x.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa27x.h)2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h)0
-rw-r--r--arch/arm/mach-pxa/mfp-pxa300.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa300.h)2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa320.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa320.h)2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa3xx.c2
-rw-r--r--arch/arm/mach-pxa/mfp-pxa3xx.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h)0
-rw-r--r--arch/arm/mach-pxa/mfp-pxa930.h (renamed from arch/arm/mach-pxa/include/mach/mfp-pxa930.h)2
-rw-r--r--arch/arm/mach-pxa/mioa701.c10
-rw-r--r--arch/arm/mach-pxa/mioa701.h (renamed from arch/arm/mach-pxa/include/mach/mioa701.h)0
-rw-r--r--arch/arm/mach-pxa/mp900.c2
-rw-r--r--arch/arm/mach-pxa/mxm8x10.c4
-rw-r--r--arch/arm/mach-pxa/mxm8x10.h (renamed from arch/arm/mach-pxa/include/mach/mxm8x10.h)0
-rw-r--r--arch/arm/mach-pxa/palm27x.c6
-rw-r--r--arch/arm/mach-pxa/palm27x.h (renamed from arch/arm/mach-pxa/include/mach/palm27x.h)0
-rw-r--r--arch/arm/mach-pxa/palmld.c4
-rw-r--r--arch/arm/mach-pxa/palmt5.c8
-rw-r--r--arch/arm/mach-pxa/palmt5.h (renamed from arch/arm/mach-pxa/include/mach/palmt5.h)2
-rw-r--r--arch/arm/mach-pxa/palmtc.c4
-rw-r--r--arch/arm/mach-pxa/palmte2.c6
-rw-r--r--arch/arm/mach-pxa/palmte2.h (renamed from arch/arm/mach-pxa/include/mach/palmte2.h)0
-rw-r--r--arch/arm/mach-pxa/palmtreo.c10
-rw-r--r--arch/arm/mach-pxa/palmtreo.h (renamed from arch/arm/mach-pxa/include/mach/palmtreo.h)0
-rw-r--r--arch/arm/mach-pxa/palmtx.c8
-rw-r--r--arch/arm/mach-pxa/palmz72.c10
-rw-r--r--arch/arm/mach-pxa/palmz72.h (renamed from arch/arm/mach-pxa/include/mach/palmz72.h)0
-rw-r--r--arch/arm/mach-pxa/pcm027.c4
-rw-r--r--arch/arm/mach-pxa/pcm027.h (renamed from arch/arm/mach-pxa/include/mach/pcm027.h)2
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c4
-rw-r--r--arch/arm/mach-pxa/pcm990_baseboard.h (renamed from arch/arm/mach-pxa/include/mach/pcm990_baseboard.h)4
-rw-r--r--arch/arm/mach-pxa/pm.c2
-rw-r--r--arch/arm/mach-pxa/pm.h (renamed from arch/arm/mach-pxa/include/mach/pm.h)0
-rw-r--r--arch/arm/mach-pxa/poodle.c4
-rw-r--r--arch/arm/mach-pxa/pxa25x.c4
-rw-r--r--arch/arm/mach-pxa/pxa25x.h (renamed from arch/arm/mach-pxa/include/mach/pxa25x.h)2
-rw-r--r--arch/arm/mach-pxa/pxa27x-udc.h (renamed from arch/arm/mach-pxa/include/mach/pxa27x-udc.h)0
-rw-r--r--arch/arm/mach-pxa/pxa27x.c4
-rw-r--r--arch/arm/mach-pxa/pxa27x.h (renamed from arch/arm/mach-pxa/include/mach/pxa27x.h)2
-rw-r--r--arch/arm/mach-pxa/pxa2xx.c2
-rw-r--r--arch/arm/mach-pxa/pxa300.c2
-rw-r--r--arch/arm/mach-pxa/pxa300.h (renamed from arch/arm/mach-pxa/include/mach/pxa300.h)4
-rw-r--r--arch/arm/mach-pxa/pxa320.c2
-rw-r--r--arch/arm/mach-pxa/pxa320.h (renamed from arch/arm/mach-pxa/include/mach/pxa320.h)4
-rw-r--r--arch/arm/mach-pxa/pxa3xx-ulpi.c2
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c2
-rw-r--r--arch/arm/mach-pxa/pxa3xx.h (renamed from arch/arm/mach-pxa/include/mach/pxa3xx.h)0
-rw-r--r--arch/arm/mach-pxa/pxa930.c2
-rw-r--r--arch/arm/mach-pxa/pxa930.h (renamed from arch/arm/mach-pxa/include/mach/pxa930.h)4
-rw-r--r--arch/arm/mach-pxa/raumfeld.c8
-rw-r--r--arch/arm/mach-pxa/regs-rtc.h (renamed from arch/arm/mach-pxa/include/mach/regs-rtc.h)0
-rw-r--r--arch/arm/mach-pxa/regs-u2d.h (renamed from arch/arm/mach-pxa/include/mach/regs-u2d.h)0
-rw-r--r--arch/arm/mach-pxa/saar.c2
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.c6
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.h (renamed from arch/arm/mach-pxa/include/mach/sharpsl_pm.h)0
-rw-r--r--arch/arm/mach-pxa/spitz.c6
-rw-r--r--arch/arm/mach-pxa/spitz_pm.c4
-rw-r--r--arch/arm/mach-pxa/stargate2.c6
-rw-r--r--arch/arm/mach-pxa/tavorevb.c2
-rw-r--r--arch/arm/mach-pxa/tosa-bt.c2
-rw-r--r--arch/arm/mach-pxa/tosa.c6
-rw-r--r--arch/arm/mach-pxa/tosa_bt.h (renamed from arch/arm/mach-pxa/include/mach/tosa_bt.h)0
-rw-r--r--arch/arm/mach-pxa/trizeps4.c2
-rw-r--r--arch/arm/mach-pxa/udc.h (renamed from arch/arm/mach-pxa/include/mach/udc.h)0
-rw-r--r--arch/arm/mach-pxa/viper.c4
-rw-r--r--arch/arm/mach-pxa/viper.h (renamed from arch/arm/mach-pxa/include/mach/viper.h)0
-rw-r--r--arch/arm/mach-pxa/vpac270.c6
-rw-r--r--arch/arm/mach-pxa/xcep.c2
-rw-r--r--arch/arm/mach-pxa/z2.c6
-rw-r--r--arch/arm/mach-pxa/zeus.c10
-rw-r--r--arch/arm/mach-pxa/zeus.h (renamed from arch/arm/mach-pxa/include/mach/zeus.h)0
-rw-r--r--arch/arm/mach-pxa/zylonite.c4
-rw-r--r--arch/arm/mach-pxa/zylonite.h (renamed from arch/arm/mach-pxa/include/mach/zylonite.h)0
-rw-r--r--arch/arm/mach-pxa/zylonite_pxa300.c4
-rw-r--r--arch/arm/mach-pxa/zylonite_pxa320.c4
-rw-r--r--arch/arm/mach-qcom/Kconfig3
-rw-r--r--arch/arm/mach-qcom/platsmp.c6
-rw-r--r--arch/arm/mach-realview/Kconfig66
-rw-r--r--arch/arm/mach-realview/Makefile9
-rw-r--r--arch/arm/mach-realview/board-eb.h (renamed from arch/arm/mach-realview/include/mach/board-eb.h)4
-rw-r--r--arch/arm/mach-realview/board-pb1176.h (renamed from arch/arm/mach-realview/include/mach/board-pb1176.h)4
-rw-r--r--arch/arm/mach-realview/board-pb11mp.h (renamed from arch/arm/mach-realview/include/mach/board-pb11mp.h)4
-rw-r--r--arch/arm/mach-realview/board-pba8.h (renamed from arch/arm/mach-realview/include/mach/board-pba8.h)4
-rw-r--r--arch/arm/mach-realview/board-pbx.h (renamed from arch/arm/mach-realview/include/mach/board-pbx.h)4
-rw-r--r--arch/arm/mach-realview/core.c6
-rw-r--r--arch/arm/mach-realview/core.h4
-rw-r--r--arch/arm/mach-realview/hardware.h (renamed from arch/arm/mach-realview/include/mach/hardware.h)2
-rw-r--r--arch/arm/mach-realview/include/mach/barriers.h8
-rw-r--r--arch/arm/mach-realview/include/mach/irqs.h40
-rw-r--r--arch/arm/mach-realview/include/mach/memory.h64
-rw-r--r--arch/arm/mach-realview/include/mach/uncompress.h77
-rw-r--r--arch/arm/mach-realview/irqs-eb.h (renamed from arch/arm/mach-realview/include/mach/irqs-eb.h)20
-rw-r--r--arch/arm/mach-realview/irqs-pb1176.h (renamed from arch/arm/mach-realview/include/mach/irqs-pb1176.h)23
-rw-r--r--arch/arm/mach-realview/irqs-pb11mp.h (renamed from arch/arm/mach-realview/include/mach/irqs-pb11mp.h)27
-rw-r--r--arch/arm/mach-realview/irqs-pba8.h (renamed from arch/arm/mach-realview/include/mach/irqs-pba8.h)23
-rw-r--r--arch/arm/mach-realview/irqs-pbx.h (renamed from arch/arm/mach-realview/include/mach/irqs-pbx.h)24
-rw-r--r--arch/arm/mach-realview/platform.h (renamed from arch/arm/mach-realview/include/mach/platform.h)2
-rw-r--r--arch/arm/mach-realview/platsmp-dt.c91
-rw-r--r--arch/arm/mach-realview/platsmp.c10
-rw-r--r--arch/arm/mach-realview/realview-dt.c1
-rw-r--r--arch/arm/mach-realview/realview_eb.c13
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c6
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c12
-rw-r--r--arch/arm/mach-realview/realview_pba8.c14
-rw-r--r--arch/arm/mach-realview/realview_pbx.c14
-rw-r--r--arch/arm/mach-rockchip/Kconfig3
-rw-r--r--arch/arm/mach-rockchip/platsmp.c47
-rw-r--r--arch/arm/mach-rockchip/rockchip.c1
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/pm-core.h14
-rw-r--r--arch/arm/mach-s3c24xx/irq-pm.c11
-rw-r--r--arch/arm/mach-s3c64xx/Kconfig31
-rw-r--r--arch/arm/mach-s3c64xx/Makefile24
-rw-r--r--arch/arm/mach-s3c64xx/common.c5
-rw-r--r--arch/arm/mach-s3c64xx/cpuidle.c5
-rw-r--r--arch/arm/mach-s3c64xx/dev-audio.c47
-rw-r--r--arch/arm/mach-s3c64xx/dev-uart.c1
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/debug-macro.S38
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/dma.h52
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/gpio-samsung.h3
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/irqs.h20
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/pm-core.h9
-rw-r--r--arch/arm/mach-s3c64xx/irq-pm.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-anw6410.c3
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410-module.c6
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-hmt.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-mini6410.c5
-rw-r--r--arch/arm/mach-s3c64xx/mach-ncp.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-real6410.c6
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq.c16
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq5.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq7.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6400.c3
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c6
-rw-r--r--arch/arm/mach-s3c64xx/pl080.c4
-rw-r--r--arch/arm/mach-s3c64xx/pm.c4
-rw-r--r--arch/arm/mach-s3c64xx/s3c6400.c2
-rw-r--r--arch/arm/mach-s3c64xx/s3c6410.c2
-rw-r--r--arch/arm/mach-s5pv210/Kconfig3
-rw-r--r--arch/arm/mach-sa1100/simpad.c4
-rw-r--r--arch/arm/mach-shmobile/Kconfig14
-rw-r--r--arch/arm/mach-shmobile/include/mach/irqs.h10
-rw-r--r--arch/arm/mach-shmobile/irqs.h15
-rw-r--r--arch/arm/mach-shmobile/r8a7779.h2
-rw-r--r--arch/arm/mach-shmobile/r8a7790.h2
-rw-r--r--arch/arm/mach-shmobile/r8a7791.h2
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c2
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7778.c1
-rw-r--r--arch/arm/mach-shmobile/sh73a0.h2
-rw-r--r--arch/arm/mach-shmobile/smp-emev2.c2
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7779.c2
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7790.c2
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7791.c2
-rw-r--r--arch/arm/mach-shmobile/smp-sh73a0.c2
-rw-r--r--arch/arm/mach-socfpga/Kconfig3
-rw-r--r--arch/arm/mach-socfpga/platsmp.c4
-rw-r--r--arch/arm/mach-spear/Kconfig3
-rw-r--r--arch/arm/mach-spear/generic.h2
-rw-r--r--arch/arm/mach-spear/platsmp.c2
-rw-r--r--arch/arm/mach-sti/Kconfig3
-rw-r--r--arch/arm/mach-sti/platsmp.c2
-rw-r--r--arch/arm/mach-sti/smp.h2
-rw-r--r--arch/arm/mach-sunxi/Kconfig3
-rw-r--r--arch/arm/mach-sunxi/platsmp.c4
-rw-r--r--arch/arm/mach-tango/Kconfig12
-rw-r--r--arch/arm/mach-tango/Makefile5
-rw-r--r--arch/arm/mach-tango/platsmp.c16
-rw-r--r--arch/arm/mach-tango/setup.c17
-rw-r--r--arch/arm/mach-tango/smc.S9
-rw-r--r--arch/arm/mach-tango/smc.h5
-rw-r--r--arch/arm/mach-tegra/Kconfig3
-rw-r--r--arch/arm/mach-tegra/common.h2
-rw-r--r--arch/arm/mach-tegra/platsmp.c2
-rw-r--r--arch/arm/mach-u300/Kconfig4
-rw-r--r--arch/arm/mach-uniphier/Kconfig1
-rw-r--r--arch/arm/mach-uniphier/platsmp.c2
-rw-r--r--arch/arm/mach-ux500/Kconfig4
-rw-r--r--arch/arm/mach-ux500/Makefile2
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c2
-rw-r--r--arch/arm/mach-ux500/cpu.c1
-rw-r--r--arch/arm/mach-ux500/platsmp.c2
-rw-r--r--arch/arm/mach-ux500/setup.h3
-rw-r--r--arch/arm/mach-ux500/timer.c48
-rw-r--r--arch/arm/mach-versatile/Kconfig41
-rw-r--r--arch/arm/mach-versatile/Makefile6
-rw-r--r--arch/arm/mach-versatile/Makefile.boot4
-rw-r--r--arch/arm/mach-versatile/core.c808
-rw-r--r--arch/arm/mach-versatile/core.h46
-rw-r--r--arch/arm/mach-versatile/include/mach/clkdev.h16
-rw-r--r--arch/arm/mach-versatile/include/mach/hardware.h38
-rw-r--r--arch/arm/mach-versatile/include/mach/irqs.h134
-rw-r--r--arch/arm/mach-versatile/include/mach/platform.h416
-rw-r--r--arch/arm/mach-versatile/include/mach/uncompress.h45
-rw-r--r--arch/arm/mach-versatile/pci.c368
-rw-r--r--arch/arm/mach-versatile/versatile_ab.c44
-rw-r--r--arch/arm/mach-versatile/versatile_dt.c376
-rw-r--r--arch/arm/mach-versatile/versatile_pb.c91
-rw-r--r--arch/arm/mach-vexpress/Kconfig3
-rw-r--r--arch/arm/mach-vexpress/core.h2
-rw-r--r--arch/arm/mach-vexpress/platsmp.c2
-rw-r--r--arch/arm/mach-w90x900/cpu.c4
-rw-r--r--arch/arm/mach-w90x900/regs-ebi.h (renamed from arch/arm/mach-w90x900/include/mach/regs-ebi.h)0
-rw-r--r--arch/arm/mach-w90x900/regs-gcr.h (renamed from arch/arm/mach-w90x900/include/mach/regs-gcr.h)0
-rw-r--r--arch/arm/mach-w90x900/regs-timer.h (renamed from arch/arm/mach-w90x900/include/mach/regs-timer.h)0
-rw-r--r--arch/arm/mach-w90x900/regs-usb.h (renamed from arch/arm/mach-w90x900/include/mach/regs-usb.h)0
-rw-r--r--arch/arm/mach-w90x900/time.c2
-rw-r--r--arch/arm/mach-zx/Kconfig3
-rw-r--r--arch/arm/mach-zx/platsmp.c2
-rw-r--r--arch/arm/mach-zynq/Kconfig4
-rw-r--r--arch/arm/mach-zynq/common.h2
-rw-r--r--arch/arm/mach-zynq/platsmp.c2
-rw-r--r--arch/arm/mm/Kconfig32
-rw-r--r--arch/arm/mm/flush.c17
-rw-r--r--arch/arm/mm/idmap.c2
-rw-r--r--arch/arm/mm/mmap.c3
-rw-r--r--arch/arm/mm/mmu.c2
-rw-r--r--arch/arm/mm/proc-mohawk.S2
-rw-r--r--arch/arm/plat-omap/dmtimer.c42
-rw-r--r--arch/arm/plat-orion/common.c21
-rw-r--r--arch/arm/plat-orion/include/plat/common.h2
-rw-r--r--arch/arm/plat-orion/irq.c1
-rw-r--r--arch/arm/plat-orion/mpp.c1
-rw-r--r--arch/arm/plat-pxa/Makefile3
-rw-r--r--arch/arm/plat-pxa/ssp.c1
-rw-r--r--arch/arm/plat-samsung/Kconfig5
-rw-r--r--arch/arm/plat-samsung/Makefile5
-rw-r--r--arch/arm/plat-samsung/devs.c64
-rw-r--r--arch/arm/plat-samsung/gpio-samsung.c (renamed from drivers/gpio/gpio-samsung.c)16
-rw-r--r--arch/arm/plat-samsung/include/plat/pm.h8
-rw-r--r--arch/arm/plat-samsung/init.c5
-rw-r--r--arch/arm/plat-samsung/pm.c4
-rw-r--r--arch/arm64/Kconfig30
-rw-r--r--arch/arm64/Kconfig.debug14
-rw-r--r--arch/arm64/Kconfig.platforms25
-rw-r--r--arch/arm64/boot/dts/Makefile2
-rw-r--r--arch/arm64/boot/dts/apm/apm-merlin.dts12
-rw-r--r--arch/arm64/boot/dts/apm/apm-mustang.dts4
-rw-r--r--arch/arm64/boot/dts/apm/apm-shadowcat.dtsi391
-rw-r--r--arch/arm64/boot/dts/apm/apm-storm.dtsi114
-rw-r--r--arch/arm64/boot/dts/arm/juno-r1.dts28
-rw-r--r--arch/arm64/boot/dts/arm/juno.dts28
-rw-r--r--arch/arm64/boot/dts/broadcom/ns2-svk.dts26
-rw-r--r--arch/arm64/boot/dts/broadcom/ns2.dtsi200
-rw-r--r--arch/arm64/boot/dts/exynos/exynos7-espresso.dts282
-rw-r--r--arch/arm64/boot/dts/exynos/exynos7.dtsi7
-rw-r--r--arch/arm64/boot/dts/freescale/Makefile1
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts116
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi527
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi68
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts7
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220.dtsi1
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05.dtsi5
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi4
-rw-r--r--arch/arm64/boot/dts/marvell/berlin4ct.dtsi63
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173-evb.dts29
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173.dtsi77
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi18
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-mtp.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi1
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-pins.dtsi19
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi107
-rw-r--r--arch/arm64/boot/dts/qcom/pm8916.dtsi6
-rw-r--r--arch/arm64/boot/dts/renesas/Makefile4
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts251
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7795.dtsi779
-rw-r--r--arch/arm64/boot/dts/rockchip/Makefile1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-evb-act8846.dts176
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi281
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-r88.dts6
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-thermal.dtsi112
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368.dtsi105
-rw-r--r--arch/arm64/boot/dts/socionext/Makefile4
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts95
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi280
l---------arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi1
l---------arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi1
-rw-r--r--arch/arm64/boot/dts/xilinx/zynqmp.dtsi2
-rw-r--r--arch/arm64/configs/defconfig27
-rw-r--r--arch/arm64/include/asm/barrier.h19
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h3
-rw-r--r--arch/arm64/include/asm/pgtable.h9
-rw-r--r--arch/arm64/kernel/insn.c165
-rw-r--r--arch/arm64/mm/flush.c16
-rw-r--r--arch/arm64/mm/mmap.c8
-rw-r--r--arch/arm64/net/bpf_jit_comp.c22
-rw-r--r--arch/avr32/include/asm/page.h8
-rw-r--r--arch/avr32/include/uapi/asm/unistd.h4
-rw-r--r--arch/avr32/kernel/module.c12
-rw-r--r--arch/avr32/kernel/syscall_table.S4
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c31
-rw-r--r--arch/avr32/mach-at32ap/pio.c14
-rw-r--r--arch/blackfin/include/asm/barrier.h4
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c2
-rw-r--r--arch/blackfin/mach-bf561/boards/acvilon.c2
-rw-r--r--arch/cris/arch-v32/drivers/mach-a3/nandflash.c8
-rw-r--r--arch/cris/arch-v32/drivers/mach-fs/nandflash.c8
-rw-r--r--arch/frv/Kconfig1
-rw-r--r--arch/frv/include/asm/page.h2
-rw-r--r--arch/ia64/include/asm/barrier.h24
-rw-r--r--arch/ia64/include/asm/early_ioremap.h10
-rw-r--r--arch/ia64/include/asm/io.h5
-rw-r--r--arch/ia64/include/asm/page.h1
-rw-r--r--arch/ia64/kernel/iosapic.c6
-rw-r--r--arch/ia64/kernel/module.c14
-rw-r--r--arch/ia64/kernel/perfmon.c3
-rw-r--r--arch/m32r/Kconfig1
-rw-r--r--arch/m32r/kernel/setup.c3
-rw-r--r--arch/metag/Kconfig3
-rw-r--r--arch/metag/include/asm/barrier.h55
-rw-r--r--arch/metag/kernel/module.c4
-rw-r--r--arch/microblaze/Kconfig3
-rw-r--r--arch/mips/alchemy/devboards/db1200.c2
-rw-r--r--arch/mips/alchemy/devboards/db1300.c2
-rw-r--r--arch/mips/alchemy/devboards/db1550.c2
-rw-r--r--arch/mips/include/asm/barrier.h51
-rw-r--r--arch/mips/include/asm/kvm_host.h6
-rw-r--r--arch/mips/include/asm/pgtable-bits.h10
-rw-r--r--arch/mips/include/asm/pgtable.h18
-rw-r--r--arch/mips/include/uapi/asm/mman.h2
-rw-r--r--arch/mips/kernel/vpe.c6
-rw-r--r--arch/mips/kvm/emulate.c2
-rw-r--r--arch/mips/kvm/tlb.c14
-rw-r--r--arch/mips/mm/c-r4k.c3
-rw-r--r--arch/mips/mm/cache.c2
-rw-r--r--arch/mips/mm/gup.c17
-rw-r--r--arch/mips/mm/init.c6
-rw-r--r--arch/mips/mm/pgtable-64.c14
-rw-r--r--arch/mips/mm/tlbex.c1
-rw-r--r--arch/mips/pnx833x/common/platform.c2
-rw-r--r--arch/mips/rb532/devices.c2
-rw-r--r--arch/mn10300/include/asm/page.h1
-rw-r--r--arch/parisc/Kconfig3
-rw-r--r--arch/parisc/include/asm/hugetlb.h20
-rw-r--r--arch/parisc/include/asm/pci.h1
-rw-r--r--arch/parisc/include/asm/pdc.h2
-rw-r--r--arch/parisc/include/asm/processor.h17
-rw-r--r--arch/parisc/include/uapi/asm/mman.h2
-rw-r--r--arch/parisc/include/uapi/asm/siginfo.h7
-rw-r--r--arch/parisc/kernel/cache.c26
-rw-r--r--arch/parisc/kernel/module.c32
-rw-r--r--arch/parisc/kernel/pci.c26
-rw-r--r--arch/parisc/kernel/processor.c10
-rw-r--r--arch/parisc/mm/hugetlbpage.c60
-rw-r--r--arch/powerpc/Kconfig8
-rw-r--r--arch/powerpc/Kconfig.debug18
-rw-r--r--arch/powerpc/boot/Makefile2
-rw-r--r--arch/powerpc/boot/dts/fsl/b4si-post.dtsi5
-rw-r--r--arch/powerpc/boot/dts/fsl/bsc9132qds.dts15
-rw-r--r--arch/powerpc/boot/dts/fsl/bsc9132si-post.dtsi28
-rw-r--r--arch/powerpc/boot/dts/fsl/bsc9132si-pre.dtsi1
-rw-r--r--arch/powerpc/boot/dts/fsl/p1010rdb.dtsi16
-rw-r--r--arch/powerpc/boot/dts/fsl/t1023rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1023si-post.dtsi86
-rw-r--r--arch/powerpc/boot/dts/fsl/t1024qds.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1024rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1024si-post.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1040d4rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1040qds.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1040rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1040si-post.dtsi94
-rw-r--r--arch/powerpc/boot/dts/fsl/t1042d4rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1042qds.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1042rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts2
-rw-r--r--arch/powerpc/boot/dts/fsl/t1042si-post.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/t104xsi-pre.dtsi4
-rwxr-xr-xarch/powerpc/boot/wrapper2
-rw-r--r--arch/powerpc/configs/mpc85xx_basic_defconfig1
-rw-r--r--arch/powerpc/configs/ppc64_defconfig1
-rw-r--r--arch/powerpc/crypto/aes-spe-glue.c1
-rw-r--r--arch/powerpc/crypto/sha1-spe-glue.c1
-rw-r--r--arch/powerpc/crypto/sha256-spe-glue.c1
-rw-r--r--arch/powerpc/include/asm/barrier.h33
-rw-r--r--arch/powerpc/include/asm/book3s/32/hash.h (renamed from arch/powerpc/include/asm/pte-hash32.h)6
-rw-r--r--arch/powerpc/include/asm/book3s/32/pgtable.h482
-rw-r--r--arch/powerpc/include/asm/book3s/64/hash-4k.h132
-rw-r--r--arch/powerpc/include/asm/book3s/64/hash-64k.h300
-rw-r--r--arch/powerpc/include/asm/book3s/64/hash.h545
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h298
-rw-r--r--arch/powerpc/include/asm/book3s/pgtable.h29
-rw-r--r--arch/powerpc/include/asm/cmpxchg.h16
-rw-r--r--arch/powerpc/include/asm/cpm.h44
-rw-r--r--arch/powerpc/include/asm/exception-64s.h40
-rw-r--r--arch/powerpc/include/asm/firmware.h5
-rw-r--r--arch/powerpc/include/asm/io.h11
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h4
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h2
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h2
-rw-r--r--arch/powerpc/include/asm/nohash/32/pgtable.h (renamed from arch/powerpc/include/asm/pgtable-ppc32.h)25
-rw-r--r--arch/powerpc/include/asm/nohash/32/pte-40x.h (renamed from arch/powerpc/include/asm/pte-40x.h)6
-rw-r--r--arch/powerpc/include/asm/nohash/32/pte-44x.h (renamed from arch/powerpc/include/asm/pte-44x.h)6
-rw-r--r--arch/powerpc/include/asm/nohash/32/pte-8xx.h (renamed from arch/powerpc/include/asm/pte-8xx.h)6
-rw-r--r--arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h (renamed from arch/powerpc/include/asm/pte-fsl-booke.h)6
-rw-r--r--arch/powerpc/include/asm/nohash/64/pgtable-4k.h (renamed from arch/powerpc/include/asm/pgtable-ppc64-4k.h)12
-rw-r--r--arch/powerpc/include/asm/nohash/64/pgtable-64k.h (renamed from arch/powerpc/include/asm/pgtable-ppc64-64k.h)27
-rw-r--r--arch/powerpc/include/asm/nohash/64/pgtable.h (renamed from arch/powerpc/include/asm/pgtable-ppc64.h)336
-rw-r--r--arch/powerpc/include/asm/nohash/pgtable.h252
-rw-r--r--arch/powerpc/include/asm/nohash/pte-book3e.h (renamed from arch/powerpc/include/asm/pte-book3e.h)6
-rw-r--r--arch/powerpc/include/asm/opal-api.h3
-rw-r--r--arch/powerpc/include/asm/opal.h3
-rw-r--r--arch/powerpc/include/asm/paca.h29
-rw-r--r--arch/powerpc/include/asm/page.h86
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h1
-rw-r--r--arch/powerpc/include/asm/pci.h4
-rw-r--r--arch/powerpc/include/asm/pgalloc-32.h34
-rw-r--r--arch/powerpc/include/asm/pgalloc-64.h27
-rw-r--r--arch/powerpc/include/asm/pgtable.h200
-rw-r--r--arch/powerpc/include/asm/plpar_wrappers.h17
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h18
-rw-r--r--arch/powerpc/include/asm/processor.h9
-rw-r--r--arch/powerpc/include/asm/pte-common.h5
-rw-r--r--arch/powerpc/include/asm/pte-hash64-4k.h17
-rw-r--r--arch/powerpc/include/asm/pte-hash64-64k.h102
-rw-r--r--arch/powerpc/include/asm/pte-hash64.h54
-rw-r--r--arch/powerpc/include/asm/reg.h17
-rw-r--r--arch/powerpc/include/asm/rtas.h3
-rw-r--r--arch/powerpc/include/asm/switch_to.h65
-rw-r--r--arch/powerpc/include/asm/synch.h2
-rw-r--r--arch/powerpc/include/asm/time.h1
-rw-r--r--arch/powerpc/include/asm/unistd.h3
-rw-r--r--arch/powerpc/include/asm/vdso_datapage.h2
-rw-r--r--arch/powerpc/include/uapi/asm/cputable.h2
-rw-r--r--arch/powerpc/include/uapi/asm/elf.h2
-rw-r--r--arch/powerpc/kernel/align.c2
-rw-r--r--arch/powerpc/kernel/asm-offsets.c10
-rw-r--r--arch/powerpc/kernel/entry_64.S89
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S77
-rw-r--r--arch/powerpc/kernel/fpu.S73
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S42
-rw-r--r--arch/powerpc/kernel/idle_power7.S7
-rw-r--r--arch/powerpc/kernel/misc_32.S2
-rw-r--r--arch/powerpc/kernel/module_32.c6
-rw-r--r--arch/powerpc/kernel/module_64.c27
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c6
-rw-r--r--arch/powerpc/kernel/process.c541
-rw-r--r--arch/powerpc/kernel/prom_init.c1
-rw-r--r--arch/powerpc/kernel/ptrace.c1
-rw-r--r--arch/powerpc/kernel/rtas.c59
-rw-r--r--arch/powerpc/kernel/signal_32.c22
-rw-r--r--arch/powerpc/kernel/signal_64.c22
-rw-r--r--arch/powerpc/kernel/stacktrace.c7
-rw-r--r--arch/powerpc/kernel/swsusp.c4
-rw-r--r--arch/powerpc/kernel/systbl_chk.c2
-rw-r--r--arch/powerpc/kernel/systbl_chk.sh2
-rw-r--r--arch/powerpc/kernel/time.c36
-rw-r--r--arch/powerpc/kernel/traps.c7
-rw-r--r--arch/powerpc/kernel/vdso.c2
-rw-r--r--arch/powerpc/kernel/vdso32/datapage.S2
-rw-r--r--arch/powerpc/kernel/vdso64/datapage.S2
-rw-r--r--arch/powerpc/kernel/vector.S112
-rw-r--r--arch/powerpc/kvm/book3s.c6
-rw-r--r--arch/powerpc/kvm/book3s_32_mmu_host.c2
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_host.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv.c5
-rw-r--r--arch/powerpc/kvm/book3s_paired_singles.c1
-rw-r--r--arch/powerpc/kvm/book3s_pr.c21
-rw-r--r--arch/powerpc/kvm/booke.c4
-rw-r--r--arch/powerpc/kvm/e500.h2
-rw-r--r--arch/powerpc/kvm/e500_mmu_host.c8
-rw-r--r--arch/powerpc/kvm/trace_pr.h2
-rw-r--r--arch/powerpc/lib/vmx-helper.c2
-rw-r--r--arch/powerpc/lib/xor_vmx.c4
-rw-r--r--arch/powerpc/mm/40x_mmu.c10
-rw-r--r--arch/powerpc/mm/Makefile9
-rw-r--r--arch/powerpc/mm/hash64_4k.c123
-rw-r--r--arch/powerpc/mm/hash64_64k.c322
-rw-r--r--arch/powerpc/mm/hash_low_64.S1003
-rw-r--r--arch/powerpc/mm/hash_native_64.c10
-rw-r--r--arch/powerpc/mm/hash_utils_64.c119
-rw-r--r--arch/powerpc/mm/hugepage-hash64.c25
-rw-r--r--arch/powerpc/mm/hugetlbpage-book3e.c46
-rw-r--r--arch/powerpc/mm/hugetlbpage-hash64.c33
-rw-r--r--arch/powerpc/mm/hugetlbpage.c93
-rw-r--r--arch/powerpc/mm/init_64.c4
-rw-r--r--arch/powerpc/mm/pgtable.c4
-rw-r--r--arch/powerpc/mm/pgtable_64.c75
-rw-r--r--arch/powerpc/mm/slb.c2
-rw-r--r--arch/powerpc/mm/slice.c3
-rw-r--r--arch/powerpc/mm/subpage-prot.c2
-rw-r--r--arch/powerpc/platforms/83xx/km83xx.c6
-rw-r--r--arch/powerpc/platforms/83xx/misc.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c6
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c6
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_mds.c6
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_rdk.c7
-rw-r--r--arch/powerpc/platforms/85xx/bsc913x_qds.c8
-rw-r--r--arch/powerpc/platforms/85xx/common.c3
-rw-r--r--arch/powerpc/platforms/85xx/corenet_generic.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c15
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c4
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_rdb.c4
-rw-r--r--arch/powerpc/platforms/85xx/twr_p102x.c4
-rw-r--r--arch/powerpc/platforms/Kconfig13
-rw-r--r--arch/powerpc/platforms/cell/Kconfig5
-rw-r--r--arch/powerpc/platforms/cell/Makefile4
-rw-r--r--arch/powerpc/platforms/cell/qpace_setup.c148
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c2
-rw-r--r--arch/powerpc/platforms/maple/time.c2
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c1
-rw-r--r--arch/powerpc/platforms/powermac/pic.c3
-rw-r--r--arch/powerpc/platforms/powernv/Makefile3
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c4
-rw-r--r--arch/powerpc/platforms/powernv/idle.c2
-rw-r--r--arch/powerpc/platforms/powernv/npu-dma.c348
-rw-r--r--arch/powerpc/platforms/powernv/opal-kmsg.c75
-rw-r--r--arch/powerpc/platforms/powernv/opal-prd.c1
-rw-r--r--arch/powerpc/platforms/powernv/opal-rtc.c5
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S1
-rw-r--r--arch/powerpc/platforms/powernv/opal-xscom.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal.c41
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c216
-rw-r--r--arch/powerpc/platforms/powernv/pci.c6
-rw-r--r--arch/powerpc/platforms/powernv/pci.h19
-rw-r--r--arch/powerpc/platforms/powernv/setup.c12
-rw-r--r--arch/powerpc/platforms/powernv/smp.c74
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c197
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c550
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c64
-rw-r--r--arch/powerpc/platforms/pseries/pseries.h9
-rw-r--r--arch/powerpc/platforms/pseries/ras.c55
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/axonram.c10
-rw-r--r--arch/powerpc/sysdev/cpm_common.c158
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c2
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c13
-rw-r--r--arch/powerpc/xmon/xmon.c18
-rw-r--r--arch/s390/Kconfig15
-rw-r--r--arch/s390/Kconfig.debug12
-rw-r--r--arch/s390/Makefile9
-rw-r--r--arch/s390/configs/default_defconfig27
-rw-r--r--arch/s390/configs/gcov_defconfig24
-rw-r--r--arch/s390/configs/performance_defconfig24
-rw-r--r--arch/s390/configs/zfcpdump_defconfig10
-rw-r--r--arch/s390/defconfig30
-rw-r--r--arch/s390/include/asm/barrier.h23
-rw-r--r--arch/s390/include/asm/compat.h2
-rw-r--r--arch/s390/include/asm/crw.h14
-rw-r--r--arch/s390/include/asm/elf.h11
-rw-r--r--arch/s390/include/asm/facilities_src.h58
-rw-r--r--arch/s390/include/asm/facility.h17
-rw-r--r--arch/s390/include/asm/fpu/internal.h10
-rw-r--r--arch/s390/include/asm/ipl.h14
-rw-r--r--arch/s390/include/asm/lowcore.h27
-rw-r--r--arch/s390/include/asm/os_info.h2
-rw-r--r--arch/s390/include/asm/pci_dma.h2
-rw-r--r--arch/s390/include/asm/pgtable.h16
-rw-r--r--arch/s390/include/asm/processor.h12
-rw-r--r--arch/s390/include/asm/ptrace.h38
-rw-r--r--arch/s390/include/asm/reset.h3
-rw-r--r--arch/s390/include/asm/sclp.h13
-rw-r--r--arch/s390/include/asm/setup.h31
-rw-r--r--arch/s390/include/asm/smp.h2
-rw-r--r--arch/s390/include/asm/sysinfo.h17
-rw-r--r--arch/s390/include/asm/thread_info.h2
-rw-r--r--arch/s390/include/asm/topology.h6
-rw-r--r--arch/s390/include/asm/vdso.h6
-rw-r--r--arch/s390/kernel/Makefile8
-rw-r--r--arch/s390/kernel/asm-offsets.c175
-rw-r--r--arch/s390/kernel/crash_dump.c454
-rw-r--r--arch/s390/kernel/dis.c4
-rw-r--r--arch/s390/kernel/early.c9
-rw-r--r--arch/s390/kernel/entry.S2
-rw-r--r--arch/s390/kernel/head.S47
-rw-r--r--arch/s390/kernel/head64.S2
-rw-r--r--arch/s390/kernel/ipl.c21
-rw-r--r--arch/s390/kernel/machine_kexec.c110
-rw-r--r--arch/s390/kernel/module.c22
-rw-r--r--arch/s390/kernel/os_info.c7
-rw-r--r--arch/s390/kernel/reipl.S94
-rw-r--r--arch/s390/kernel/sclp.c65
-rw-r--r--arch/s390/kernel/setup.c23
-rw-r--r--arch/s390/kernel/smp.c161
-rw-r--r--arch/s390/kernel/sysinfo.c20
-rw-r--r--arch/s390/kernel/traps.c3
-rw-r--r--arch/s390/kernel/vdso.c17
-rw-r--r--arch/s390/kernel/vdso32/Makefile2
-rw-r--r--arch/s390/kernel/vdso32/getcpu.S43
-rw-r--r--arch/s390/kernel/vdso32/vdso32.lds.S1
-rw-r--r--arch/s390/kernel/vdso64/Makefile2
-rw-r--r--arch/s390/kernel/vdso64/getcpu.S42
-rw-r--r--arch/s390/kernel/vdso64/vdso64.lds.S1
-rw-r--r--arch/s390/kvm/interrupt.c4
-rw-r--r--arch/s390/kvm/kvm-s390.c30
-rw-r--r--arch/s390/kvm/priv.c2
-rw-r--r--arch/s390/lib/spinlock.c45
-rw-r--r--arch/s390/mm/extable.c8
-rw-r--r--arch/s390/mm/extmem.c4
-rw-r--r--arch/s390/mm/fault.c2
-rw-r--r--arch/s390/mm/gup.c25
-rw-r--r--arch/s390/mm/maccess.c4
-rw-r--r--arch/s390/mm/mem_detect.c7
-rw-r--r--arch/s390/mm/pgtable.c52
-rw-r--r--arch/s390/pci/pci.c3
-rw-r--r--arch/s390/pci/pci_dma.c19
-rw-r--r--arch/s390/tools/.gitignore1
-rw-r--r--arch/s390/tools/Makefile15
-rw-r--r--arch/s390/tools/gen_facilities.c67
-rw-r--r--arch/sh/Kconfig3
-rw-r--r--arch/sh/boards/mach-migor/setup.c2
-rw-r--r--arch/sh/include/asm/barrier.h3
-rw-r--r--arch/sh/include/asm/cmpxchg-grb.h22
-rw-r--r--arch/sh/include/asm/cmpxchg-irq.h11
-rw-r--r--arch/sh/include/asm/cmpxchg-llsc.h25
-rw-r--r--arch/sh/include/asm/cmpxchg-xchg.h51
-rw-r--r--arch/sh/include/asm/cmpxchg.h3
-rw-r--r--arch/sh/kernel/cpu/clock-cpg.c1
-rw-r--r--arch/sh/kernel/cpu/sh2a/clock-sh7264.c9
-rw-r--r--arch/sh/kernel/cpu/sh2a/clock-sh7269.c16
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7343.c8
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7366.c6
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7723.c12
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7734.c12
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7757.c6
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7785.c12
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7786.c12
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-shx3.c8
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7734.c12
-rw-r--r--arch/sh/mm/cache-sh4.c2
-rw-r--r--arch/sh/mm/cache.c8
-rw-r--r--arch/sparc/Kconfig4
-rw-r--r--arch/sparc/include/asm/barrier_32.h1
-rw-r--r--arch/sparc/include/asm/barrier_64.h29
-rw-r--r--arch/sparc/include/asm/pgtable_64.h19
-rw-r--r--arch/sparc/include/asm/processor.h3
-rw-r--r--arch/sparc/kernel/sys_sparc_64.c2
-rw-r--r--arch/sparc/mm/fault_64.c3
-rw-r--r--arch/sparc/mm/gup.c16
-rw-r--r--arch/sparc/mm/init_64.c15
-rw-r--r--arch/tile/Kconfig5
-rw-r--r--arch/tile/include/asm/barrier.h9
-rw-r--r--arch/tile/include/asm/insn.h59
-rw-r--r--arch/tile/include/asm/io.h16
-rw-r--r--arch/tile/include/asm/jump_label.h58
-rw-r--r--arch/tile/include/asm/page.h10
-rw-r--r--arch/tile/include/asm/pgtable.h10
-rw-r--r--arch/tile/include/asm/processor.h2
-rw-r--r--arch/tile/include/asm/thread_info.h8
-rw-r--r--arch/tile/include/asm/topology.h3
-rw-r--r--arch/tile/kernel/Makefile1
-rw-r--r--arch/tile/kernel/ftrace.c13
-rw-r--r--arch/tile/kernel/intvec_32.S51
-rw-r--r--arch/tile/kernel/intvec_64.S56
-rw-r--r--arch/tile/kernel/jump_label.c64
-rw-r--r--arch/tile/kernel/kgdb.c2
-rw-r--r--arch/tile/kernel/kprobes.c4
-rw-r--r--arch/tile/kernel/process.c79
-rw-r--r--arch/tile/kernel/ptrace.c15
-rw-r--r--arch/tile/kernel/setup.c2
-rw-r--r--arch/tile/kernel/single_step.c3
-rw-r--r--arch/tile/kernel/stack.c17
-rw-r--r--arch/tile/kernel/traps.c13
-rw-r--r--arch/tile/kernel/unaligned.c13
-rw-r--r--arch/tile/mm/fault.c3
-rw-r--r--arch/um/include/asm/page.h7
-rw-r--r--arch/um/include/asm/pgtable-3level.h4
-rw-r--r--arch/um/include/asm/pgtable.h2
-rw-r--r--arch/unicore32/Kconfig4
-rw-r--r--arch/unicore32/Kconfig.debug14
-rw-r--r--arch/x86/Kconfig20
-rw-r--r--arch/x86/Kconfig.debug17
-rw-r--r--arch/x86/entry/vdso/vclock_gettime.c12
-rw-r--r--arch/x86/include/asm/barrier.h36
-rw-r--r--arch/x86/include/asm/boot.h2
-rw-r--r--arch/x86/include/asm/fpu/internal.h1
-rw-r--r--arch/x86/include/asm/fpu/xstate.h11
-rw-r--r--arch/x86/include/asm/intel_punit_ipc.h101
-rw-r--r--arch/x86/include/asm/intel_telemetry.h147
-rw-r--r--arch/x86/include/asm/lguest.h4
-rw-r--r--arch/x86/include/asm/mmu_context.h34
-rw-r--r--arch/x86/include/asm/pgtable.h40
-rw-r--r--arch/x86/include/asm/pgtable_types.h9
-rw-r--r--arch/x86/include/asm/platform_sst_audio.h1
-rw-r--r--arch/x86/include/asm/pmem.h7
-rw-r--r--arch/x86/kernel/cpu/amd.c3
-rw-r--r--arch/x86/kernel/early-quirks.c1
-rw-r--r--arch/x86/kernel/fpu/init.c161
-rw-r--r--arch/x86/kernel/fpu/xstate.c4
-rw-r--r--arch/x86/kernel/livepatch.c29
-rw-r--r--arch/x86/kernel/reboot.c8
-rw-r--r--arch/x86/kernel/verify_cpu.S50
-rw-r--r--arch/x86/kernel/vm86_32.c6
-rw-r--r--arch/x86/kvm/iommu.c11
-rw-r--r--arch/x86/kvm/mmu.c37
-rw-r--r--arch/x86/kvm/mmu_audit.c2
-rw-r--r--arch/x86/kvm/paging_tmpl.h6
-rw-r--r--arch/x86/kvm/vmx.c2
-rw-r--r--arch/x86/kvm/x86.c2
-rw-r--r--arch/x86/mm/gup.c74
-rw-r--r--arch/x86/mm/init_64.c36
-rw-r--r--arch/x86/mm/mmap.c12
-rw-r--r--arch/x86/mm/pageattr.c3
-rw-r--r--arch/x86/mm/pat.c5
-rw-r--r--arch/x86/mm/pgtable.c13
-rw-r--r--arch/x86/mm/tlb.c29
-rw-r--r--arch/x86/um/asm/barrier.h9
-rw-r--r--arch/xtensa/include/asm/barrier.h4
-rw-r--r--arch/xtensa/include/uapi/asm/mman.h2
-rw-r--r--arch/xtensa/mm/tlb.c2
-rw-r--r--block/Makefile2
-rw-r--r--block/badblocks.c585
-rw-r--r--block/bio.c4
-rw-r--r--block/blk-core.c15
-rw-r--r--block/blk-merge.c22
-rw-r--r--block/blk-mq-cpumap.c2
-rw-r--r--block/blk-mq-tag.c11
-rw-r--r--block/blk-mq.c31
-rw-r--r--block/blk-mq.h11
-rw-r--r--block/blk-timeout.c6
-rw-r--r--block/genhd.c32
-rw-r--r--block/ioctl.c71
-rw-r--r--crypto/asymmetric_keys/x509_public_key.c2
-rw-r--r--crypto/hash_info.c2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/nfit.c203
-rw-r--r--drivers/base/firmware_class.c8
-rw-r--r--drivers/base/memory.c35
-rw-r--r--drivers/bcma/driver_gpio.c25
-rw-r--r--drivers/block/brd.c7
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/floppy.c5
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c2
-rw-r--r--drivers/block/null_blk.c2
-rw-r--r--drivers/block/zram/zcomp.c24
-rw-r--r--drivers/block/zram/zcomp.h2
-rw-r--r--drivers/block/zram/zcomp_lz4.c15
-rw-r--r--drivers/block/zram/zcomp_lzo.c15
-rw-r--r--drivers/block/zram/zram_drv.c7
-rw-r--r--drivers/bus/Kconfig8
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/uniphier-system-bus.c281
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c7
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c28
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c1
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/char/tpm/tpm-interface.c23
-rw-r--r--drivers/char/tpm/tpm.h11
-rw-r--r--drivers/char/tpm/tpm2-cmd.c60
-rw-r--r--drivers/char/tpm/tpm_crb.c14
-rw-r--r--drivers/char/tpm/tpm_ibmvtpm.c22
-rw-r--r--drivers/char/tpm/tpm_ibmvtpm.h1
-rw-r--r--drivers/char/tpm/tpm_tis.c256
-rw-r--r--drivers/clk/Kconfig12
-rw-r--r--drivers/clk/Makefile5
-rw-r--r--drivers/clk/at91/clk-slow.c29
-rw-r--r--drivers/clk/bcm/Kconfig10
-rw-r--r--drivers/clk/bcm/Makefile2
-rw-r--r--drivers/clk/bcm/clk-bcm2835-aux.c85
-rw-r--r--drivers/clk/bcm/clk-bcm2835.c155
-rw-r--r--drivers/clk/bcm/clk-bcm63xx.c22
-rw-r--r--drivers/clk/clk-cs2000-cp.c510
-rw-r--r--drivers/clk/clk-divider.c9
-rw-r--r--drivers/clk/clk-gpio.c28
-rw-r--r--drivers/clk/clk-mux.c5
-rw-r--r--drivers/clk/clk-si5351.c7
-rw-r--r--drivers/clk/clk-tango4.c61
-rw-r--r--drivers/clk/clk-xgene.c3
-rw-r--r--drivers/clk/clk.c35
-rw-r--r--drivers/clk/imx/clk-imx25.c18
-rw-r--r--drivers/clk/imx/clk-imx51-imx53.c8
-rw-r--r--drivers/clk/imx/clk-imx6q.c3
-rw-r--r--drivers/clk/imx/clk-imx6ul.c4
-rw-r--r--drivers/clk/imx/clk-imx7d.c11
-rw-r--r--drivers/clk/imx/clk-pllv3.c14
-rw-r--r--drivers/clk/mmp/clk-mmp2.c11
-rw-r--r--drivers/clk/mmp/clk-pxa168.c11
-rw-r--r--drivers/clk/mmp/clk-pxa910.c13
-rw-r--r--drivers/clk/mvebu/Makefile2
-rw-r--r--drivers/clk/mvebu/dove-divider.c262
-rw-r--r--drivers/clk/mvebu/dove-divider.h6
-rw-r--r--drivers/clk/mvebu/dove.c6
-rw-r--r--drivers/clk/nxp/Makefile1
-rw-r--r--drivers/clk/nxp/clk-lpc32xx.c1569
-rw-r--r--drivers/clk/pxa/clk-pxa25x.c1
-rw-r--r--drivers/clk/qcom/Kconfig17
-rw-r--r--drivers/clk/qcom/Makefile3
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c355
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h57
-rw-r--r--drivers/clk/qcom/clk-rcg.h1
-rw-r--r--drivers/clk/qcom/clk-rcg2.c87
-rw-r--r--drivers/clk/qcom/common.c87
-rw-r--r--drivers/clk/qcom/common.h4
-rw-r--r--drivers/clk/qcom/gcc-apq8084.c17
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c15
-rw-r--r--drivers/clk/qcom/gcc-msm8660.c16
-rw-r--r--drivers/clk/qcom/gcc-msm8916.c17
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c16
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c18
-rw-r--r--drivers/clk/qcom/gcc-msm8996.c3422
-rw-r--r--drivers/clk/qcom/lcc-ipq806x.c1
-rw-r--r--drivers/clk/qcom/lcc-msm8960.c1
-rw-r--r--drivers/clk/qcom/mmcc-apq8084.c1
-rw-r--r--drivers/clk/qcom/mmcc-msm8960.c2
-rw-r--r--drivers/clk/qcom/mmcc-msm8974.c1
-rw-r--r--drivers/clk/qcom/mmcc-msm8996.c3217
-rw-r--r--drivers/clk/rockchip/Makefile2
-rw-r--r--drivers/clk/rockchip/clk-cpu.c4
-rw-r--r--drivers/clk/rockchip/clk-pll.c258
-rw-r--r--drivers/clk/rockchip/clk-rk3036.c493
-rw-r--r--drivers/clk/rockchip/clk-rk3188.c112
-rw-r--r--drivers/clk/rockchip/clk-rk3228.c678
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c136
-rw-r--r--drivers/clk/rockchip/clk-rk3368.c13
-rw-r--r--drivers/clk/rockchip/clk.c144
-rw-r--r--drivers/clk/rockchip/clk.h62
-rw-r--r--drivers/clk/samsung/clk-cpu.c10
-rw-r--r--drivers/clk/samsung/clk-exynos4.c1
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c98
-rw-r--r--drivers/clk/samsung/clk-s3c2410-dclk.c3
-rw-r--r--drivers/clk/shmobile/Makefile24
-rw-r--r--drivers/clk/shmobile/clk-div6.c137
-rw-r--r--drivers/clk/shmobile/clk-div6.h7
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c4
-rw-r--r--drivers/clk/shmobile/r8a7795-cpg-mssr.c383
-rw-r--r--drivers/clk/shmobile/renesas-cpg-mssr.c596
-rw-r--r--drivers/clk/shmobile/renesas-cpg-mssr.h132
-rw-r--r--drivers/clk/st/clkgen-fsyn.c17
-rw-r--r--drivers/clk/sunxi/Makefile5
-rw-r--r--drivers/clk/sunxi/clk-a10-ve.c171
-rw-r--r--drivers/clk/sunxi/clk-simple-gates.c14
-rw-r--r--drivers/clk/sunxi/clk-sun8i-apb0.c80
-rw-r--r--drivers/clk/sunxi/clk-sun8i-bus-gates.c112
-rw-r--r--drivers/clk/sunxi/clk-sun9i-cpus.c240
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c6
-rw-r--r--drivers/clk/sunxi/clk-usb.c12
-rw-r--r--drivers/clk/tegra/Makefile1
-rw-r--r--drivers/clk/tegra/clk-divider.c4
-rw-r--r--drivers/clk/tegra/clk-id.h75
-rw-r--r--drivers/clk/tegra/clk-pll.c834
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c371
-rw-r--r--drivers/clk/tegra/clk-tegra-super-gen4.c142
-rw-r--r--drivers/clk/tegra/clk-tegra114.c339
-rw-r--r--drivers/clk/tegra/clk-tegra124.c453
-rw-r--r--drivers/clk/tegra/clk-tegra20.c314
-rw-r--r--drivers/clk/tegra/clk-tegra210.c2852
-rw-r--r--drivers/clk/tegra/clk-tegra30.c426
-rw-r--r--drivers/clk/tegra/clk.h101
-rw-r--r--drivers/clk/ti/apll.c2
-rw-r--r--drivers/clk/ti/clk-814x.c4
-rw-r--r--drivers/clk/ti/dpll3xxx.c25
-rw-r--r--drivers/clk/versatile/Kconfig5
-rw-r--r--drivers/clk/versatile/clk-icst.c194
-rw-r--r--drivers/clk/versatile/clk-realview.c10
-rw-r--r--drivers/clk/versatile/clk-sp810.c5
-rw-r--r--drivers/clocksource/Kconfig13
-rw-r--r--drivers/clocksource/clksrc-dbx500-prcmu.c9
-rw-r--r--drivers/clocksource/vt8500_timer.c6
-rw-r--r--drivers/cpufreq/powernv-cpufreq.c2
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c2
-rw-r--r--drivers/crypto/vmx/aes.c6
-rw-r--r--drivers/crypto/vmx/aes_cbc.c6
-rw-r--r--drivers/crypto/vmx/aes_ctr.c6
-rw-r--r--drivers/crypto/vmx/ghash.c12
-rw-r--r--drivers/dca/dca-core.c3
-rw-r--r--drivers/dma/Kconfig14
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/acpi-dma.c5
-rw-r--r--drivers/dma/at_xdmac.c23
-rw-r--r--drivers/dma/dma-axi-dmac.c8
-rw-r--r--drivers/dma/dmaengine.c178
-rw-r--r--drivers/dma/dw/core.c44
-rw-r--r--drivers/dma/dw/platform.c7
-rw-r--r--drivers/dma/edma.c12
-rw-r--r--drivers/dma/fsl-edma.c85
-rw-r--r--drivers/dma/hsu/hsu.c17
-rw-r--r--drivers/dma/hsu/hsu.h1
-rw-r--r--drivers/dma/idma64.c22
-rw-r--r--drivers/dma/idma64.h3
-rw-r--r--drivers/dma/img-mdc-dma.c78
-rw-r--r--drivers/dma/ioat/dca.c2
-rw-r--r--drivers/dma/ioat/dma.h34
-rw-r--r--drivers/dma/ioat/registers.h16
-rw-r--r--drivers/dma/mv_xor.c95
-rw-r--r--drivers/dma/mv_xor.h2
-rw-r--r--drivers/dma/omap-dma.c82
-rw-r--r--drivers/dma/pxa_dma.c1
-rw-r--r--drivers/dma/sh/Kconfig6
-rw-r--r--drivers/dma/sh/Makefile1
-rw-r--r--drivers/dma/sh/rcar-hpbdma.c669
-rw-r--r--drivers/dma/sh/usb-dmac.c4
-rw-r--r--drivers/dma/ste_dma40.c87
-rw-r--r--drivers/dma/stm32-dma.c1141
-rw-r--r--drivers/dma/tegra20-apb-dma.c73
-rw-r--r--drivers/dma/ti-dma-crossbar.c81
-rw-r--r--drivers/dma/virt-dma.c46
-rw-r--r--drivers/dma/virt-dma.h25
-rw-r--r--drivers/extcon/Kconfig9
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-arizona.c71
-rw-r--r--drivers/extcon/extcon-max14577.c2
-rw-r--r--drivers/extcon/extcon-max3355.c146
-rw-r--r--drivers/extcon/extcon-max77693.c4
-rw-r--r--drivers/extcon/extcon-max77843.c2
-rw-r--r--drivers/extcon/extcon-rt8973a.c2
-rw-r--r--drivers/firmware/dmi_scan.c62
-rw-r--r--drivers/firmware/efi/efi.c2
-rw-r--r--drivers/firmware/efi/libstub/fdt.c2
-rw-r--r--drivers/gpio/Kconfig39
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-104-idi-48.c343
-rw-r--r--drivers/gpio/gpio-104-idio-16.c156
-rw-r--r--drivers/gpio/gpio-74x164.c79
-rw-r--r--drivers/gpio/gpio-74xx-mmio.c37
-rw-r--r--drivers/gpio/gpio-adnp.c47
-rw-r--r--drivers/gpio/gpio-adp5520.c10
-rw-r--r--drivers/gpio/gpio-adp5588.c18
-rw-r--r--drivers/gpio/gpio-altera.c25
-rw-r--r--drivers/gpio/gpio-amd8111.c18
-rw-r--r--drivers/gpio/gpio-amdpt.c34
-rw-r--r--drivers/gpio/gpio-arizona.c21
-rw-r--r--drivers/gpio/gpio-ath79.c20
-rw-r--r--drivers/gpio/gpio-bcm-kona.c31
-rw-r--r--drivers/gpio/gpio-brcmstb.c95
-rw-r--r--drivers/gpio/gpio-bt8xx.c10
-rw-r--r--drivers/gpio/gpio-clps711x.c28
-rw-r--r--drivers/gpio/gpio-crystalcove.c34
-rw-r--r--drivers/gpio/gpio-cs5535.c15
-rw-r--r--drivers/gpio/gpio-da9052.c26
-rw-r--r--drivers/gpio/gpio-da9055.c17
-rw-r--r--drivers/gpio/gpio-davinci.c25
-rw-r--r--drivers/gpio/gpio-dln2.c38
-rw-r--r--drivers/gpio/gpio-dwapb.c92
-rw-r--r--drivers/gpio/gpio-em.c10
-rw-r--r--drivers/gpio/gpio-ep93xx.c25
-rw-r--r--drivers/gpio/gpio-etraxfs.c49
-rw-r--r--drivers/gpio/gpio-f7188x.c18
-rw-r--r--drivers/gpio/gpio-ge.c24
-rw-r--r--drivers/gpio/gpio-generic.c295
-rw-r--r--drivers/gpio/gpio-grgpio.c73
-rw-r--r--drivers/gpio/gpio-ich.c4
-rw-r--r--drivers/gpio/gpio-intel-mid.c23
-rw-r--r--drivers/gpio/gpio-iop.c2
-rw-r--r--drivers/gpio/gpio-it87.c17
-rw-r--r--drivers/gpio/gpio-janz-ttl.c10
-rw-r--r--drivers/gpio/gpio-kempld.c21
-rw-r--r--drivers/gpio/gpio-ks8695.c2
-rw-r--r--drivers/gpio/gpio-loongson.c2
-rw-r--r--drivers/gpio/gpio-lp3943.c21
-rw-r--r--drivers/gpio/gpio-lpc18xx.c15
-rw-r--r--drivers/gpio/gpio-lpc32xx.c41
-rw-r--r--drivers/gpio/gpio-lynxpoint.c24
-rw-r--r--drivers/gpio/gpio-max7300.c1
-rw-r--r--drivers/gpio/gpio-max730x.c12
-rw-r--r--drivers/gpio/gpio-max732x.c34
-rw-r--r--drivers/gpio/gpio-mb86s7x.c21
-rw-r--r--drivers/gpio/gpio-mc33880.c6
-rw-r--r--drivers/gpio/gpio-mc9s08dz60.c17
-rw-r--r--drivers/gpio/gpio-mcp23s08.c30
-rw-r--r--drivers/gpio/gpio-ml-ioh.c14
-rw-r--r--drivers/gpio/gpio-mm-lantiq.c6
-rw-r--r--drivers/gpio/gpio-moxart.c29
-rw-r--r--drivers/gpio/gpio-mpc5200.c39
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c26
-rw-r--r--drivers/gpio/gpio-msic.c8
-rw-r--r--drivers/gpio/gpio-mvebu.c25
-rw-r--r--drivers/gpio/gpio-mxc.c27
-rw-r--r--drivers/gpio/gpio-mxs.c33
-rw-r--r--drivers/gpio/gpio-octeon.c14
-rw-r--r--drivers/gpio/gpio-omap.c24
-rw-r--r--drivers/gpio/gpio-palmas.c31
-rw-r--r--drivers/gpio/gpio-pca953x.c141
-rw-r--r--drivers/gpio/gpio-pcf857x.c13
-rw-r--r--drivers/gpio/gpio-pch.c19
-rw-r--r--drivers/gpio/gpio-pl061.c41
-rw-r--r--drivers/gpio/gpio-pxa.c413
-rw-r--r--drivers/gpio/gpio-rc5t583.c21
-rw-r--r--drivers/gpio/gpio-rcar.c123
-rw-r--r--drivers/gpio/gpio-rdc321x.c10
-rw-r--r--drivers/gpio/gpio-sa1100.c4
-rw-r--r--drivers/gpio/gpio-sch.c16
-rw-r--r--drivers/gpio/gpio-sch311x.c29
-rw-r--r--drivers/gpio/gpio-sodaville.c13
-rw-r--r--drivers/gpio/gpio-spear-spics.c13
-rw-r--r--drivers/gpio/gpio-sta2x11.c14
-rw-r--r--drivers/gpio/gpio-stmpe.c31
-rw-r--r--drivers/gpio/gpio-stp-xway.c12
-rw-r--r--drivers/gpio/gpio-sx150x.c83
-rw-r--r--drivers/gpio/gpio-syscon.c21
-rw-r--r--drivers/gpio/gpio-tb10x.c19
-rw-r--r--drivers/gpio/gpio-tc3589x.c29
-rw-r--r--drivers/gpio/gpio-tegra.c2
-rw-r--r--drivers/gpio/gpio-timberdale.c10
-rw-r--r--drivers/gpio/gpio-tps6586x.c17
-rw-r--r--drivers/gpio/gpio-tps65910.c17
-rw-r--r--drivers/gpio/gpio-tps65912.c14
-rw-r--r--drivers/gpio/gpio-ts5500.c22
-rw-r--r--drivers/gpio/gpio-twl4030.c27
-rw-r--r--drivers/gpio/gpio-twl6040.c8
-rw-r--r--drivers/gpio/gpio-tz1090-pdc.c17
-rw-r--r--drivers/gpio/gpio-tz1090.c21
-rw-r--r--drivers/gpio/gpio-ucb1400.c13
-rw-r--r--drivers/gpio/gpio-vf610.c25
-rw-r--r--drivers/gpio/gpio-viperboard.c46
-rw-r--r--drivers/gpio/gpio-vr41xx.c6
-rw-r--r--drivers/gpio/gpio-vx855.c8
-rw-r--r--drivers/gpio/gpio-wm831x.c23
-rw-r--r--drivers/gpio/gpio-wm8350.c19
-rw-r--r--drivers/gpio/gpio-wm8994.c23
-rw-r--r--drivers/gpio/gpio-xgene-sb.c40
-rw-r--r--drivers/gpio/gpio-xgene.c19
-rw-r--r--drivers/gpio/gpio-xilinx.c18
-rw-r--r--drivers/gpio/gpio-xlp.c25
-rw-r--r--drivers/gpio/gpio-xtensa.c4
-rw-r--r--drivers/gpio/gpio-zevio.c19
-rw-r--r--drivers/gpio/gpio-zx.c25
-rw-r--r--drivers/gpio/gpio-zynq.c52
-rw-r--r--drivers/gpio/gpiolib-acpi.c90
-rw-r--r--drivers/gpio/gpiolib-of.c16
-rw-r--r--drivers/gpio/gpiolib-sysfs.c5
-rw-r--r--drivers/gpio/gpiolib.c113
-rw-r--r--drivers/gpio/gpiolib.h10
-rw-r--r--drivers/gpu/drm/Kconfig3
-rw-r--r--drivers/gpu/drm/Makefile5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h140
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c328
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c41
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c163
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c109
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c235
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c317
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c116
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_dp.c96
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik.c67
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_ih.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.c273
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_ih.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/fiji_dpm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/fiji_ppsmc.h182
-rw-r--r--drivers/gpu/drm/amd/amdgpu/fiji_smc.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/fiji_smum.h (renamed from drivers/gpu/drm/amd/amdgpu/fiji_smumgr.h)0
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c2987
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c177
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_ih.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c129
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_dpm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ih.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ppsmc.h198
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_smc.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_smum.h (renamed from drivers/gpu/drm/amd/amdgpu/tonga_smumgr.h)0
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c261
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c238
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.c153
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c3
-rw-r--r--drivers/gpu/drm/amd/include/amd_acpi.h (renamed from drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h)61
-rw-r--r--drivers/gpu/drm/amd/include/amd_pcie.h50
-rw-r--r--drivers/gpu/drm/amd/include/amd_pcie_helpers.h141
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h21
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h1
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h13
-rw-r--r--drivers/gpu/drm/amd/include/atombios.h79
-rw-r--r--drivers/gpu/drm/amd/include/cgs_common.h124
-rw-r--r--drivers/gpu/drm/amd/powerplay/Kconfig6
-rw-r--r--drivers/gpu/drm/amd/powerplay/Makefile22
-rw-r--r--drivers/gpu/drm/amd/powerplay/amd_powerplay.c660
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/Makefile11
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c289
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h62
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c195
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h34
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c215
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h59
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c114
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c410
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h100
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c438
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h88
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/psm.c117
-rw-r--r--drivers/gpu/drm/amd/powerplay/eventmgr/psm.h38
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/Makefile15
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c252
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h37
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c1737
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h326
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c114
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h35
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h105
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c5127
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h361
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c553
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h66
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c687
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h62
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c155
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c334
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c563
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h105
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c76
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c1207
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h246
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h612
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c64
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h31
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c1688
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h47
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c350
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h36
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h107
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c6075
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h408
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h66
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h406
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c1142
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h35
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c590
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h61
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h299
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h (renamed from drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h)1
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/eventmanager.h109
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/eventmgr.h125
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h412
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/fiji_pwrvirus.h10299
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h385
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hwmgr.h801
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/power_state.h200
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h28
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h47
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_debug.h47
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_feature.h67
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_instance.h39
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h36
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h46
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu7.h (renamed from drivers/gpu/drm/amd/amdgpu/smu7.h)0
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu72.h664
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h760
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu73.h720
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h799
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h (renamed from drivers/gpu/drm/amd/amdgpu/smu7_discrete.h)0
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h (renamed from drivers/gpu/drm/amd/amdgpu/smu7_fusion.h)0
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu8.h (renamed from drivers/gpu/drm/amd/amdgpu/smu8.h)0
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h (renamed from drivers/gpu/drm/amd/amdgpu/smu8_fusion.h)8
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h (renamed from drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_cz.h)0
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h100
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smumgr.h182
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h420
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/Makefile9
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c858
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h102
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c1042
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h77
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c263
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c819
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h53
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.c27
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.h9
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c15
-rw-r--r--drivers/gpu/drm/armada/armada_debugfs.c4
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h3
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c1
-rw-r--r--drivers/gpu/drm/armada/armada_fb.c4
-rw-r--r--drivers/gpu/drm/armada/armada_fb.h2
-rw-r--r--drivers/gpu/drm/armada/armada_gem.c29
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c2
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h3
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c2
-rw-r--r--drivers/gpu/drm/ast/ast_main.c4
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c11
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c6
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c2
-rw-r--r--drivers/gpu/drm/bochs/bochs.h2
-rw-r--r--drivers/gpu/drm/bochs/bochs_fbdev.c2
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c10
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c4
-rw-r--r--drivers/gpu/drm/bridge/Kconfig1
-rw-r--r--drivers/gpu/drm/bridge/Makefile4
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c (renamed from drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c)2
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi-audio.h (renamed from drivers/gpu/drm/bridge/dw_hdmi-audio.h)0
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi.c (renamed from drivers/gpu/drm/bridge/dw_hdmi.c)33
-rw-r--r--drivers/gpu/drm/bridge/dw-hdmi.h (renamed from drivers/gpu/drm/bridge/dw_hdmi.h)0
-rw-r--r--drivers/gpu/drm/bridge/nxp-ptn3460.c6
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h3
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_main.c4
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_mode.c6
-rw-r--r--drivers/gpu/drm/drm_atomic.c153
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c372
-rw-r--r--drivers/gpu/drm/drm_bridge.c69
-rw-r--r--drivers/gpu/drm/drm_crtc.c113
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c101
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c183
-rw-r--r--drivers/gpu/drm/drm_drv.c30
-rw-r--r--drivers/gpu/drm/drm_edid.c136
-rw-r--r--drivers/gpu/drm/drm_encoder_slave.c2
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c13
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c2
-rw-r--r--drivers/gpu/drm/drm_fops.c58
-rw-r--r--drivers/gpu/drm/drm_gem.c144
-rw-r--r--drivers/gpu/drm/drm_gem_cma_helper.c14
-rw-r--r--drivers/gpu/drm/drm_irq.c3
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c38
-rw-r--r--drivers/gpu/drm/drm_modes.c90
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c103
-rw-r--r--drivers/gpu/drm/drm_pci.c20
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c13
-rw-r--r--drivers/gpu/drm/drm_prime.c16
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c174
-rw-r--r--drivers/gpu/drm/drm_rect.c7
-rw-r--r--drivers/gpu/drm/drm_sysfs.c56
-rw-r--r--drivers/gpu/drm/etnaviv/Kconfig20
-rw-r--r--drivers/gpu/drm/etnaviv/Makefile14
-rw-r--r--drivers/gpu/drm/etnaviv/cmdstream.xml.h218
-rw-r--r--drivers/gpu/drm/etnaviv/common.xml.h249
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_buffer.c268
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c209
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.c707
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.h161
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_dump.c227
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_dump.h54
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.c899
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.h117
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c122
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c443
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c1647
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h209
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_iommu.c240
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_iommu.h28
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c33
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h25
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.c299
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.h71
-rw-r--r--drivers/gpu/drm/etnaviv/state.xml.h351
-rw-r--r--drivers/gpu/drm/etnaviv/state_hi.xml.h407
-rw-r--r--drivers/gpu/drm/exynos/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c124
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c179
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.c189
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c75
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c81
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h97
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c161
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c25
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.h7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c160
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h28
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c35
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c259
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.h9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c41
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c59
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c384
-rw-r--r--drivers/gpu/drm/exynos/regs-gsc.h4
-rw-r--r--drivers/gpu/drm/exynos/regs-mixer.h4
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c1
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_crt.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_dp.c3
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c7
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_lvds.c6
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c22
-rw-r--r--drivers/gpu/drm/gma500/gem.c19
-rw-r--r--drivers/gpu/drm/gma500/gma_display.c13
-rw-r--r--drivers/gpu/drm/gma500/gtt.c1
-rw-r--r--drivers/gpu/drm/gma500/mdfld_device.c2
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_dpi.c12
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.c5
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_device.c2
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi.c2
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_lvds.c2
-rw-r--r--drivers/gpu/drm/gma500/power.c4
-rw-r--r--drivers/gpu/drm/gma500/psb_device.c22
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h4
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c2
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h3
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_lvds.c7
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c8
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c2
-rw-r--r--drivers/gpu/drm/i2c/ch7006_drv.c2
-rw-r--r--drivers/gpu/drm/i2c/sil164_drv.c2
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c29
-rw-r--r--drivers/gpu/drm/i915/Kconfig1
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/dvo.h15
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7017.c2
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7xxx.c2
-rw-r--r--drivers/gpu/drm/i915/dvo_ivch.c2
-rw-r--r--drivers/gpu/drm/i915/dvo_ns2501.c2
-rw-r--r--drivers/gpu/drm/i915/dvo_sil164.c2
-rw-r--r--drivers/gpu/drm/i915/dvo_tfp410.c2
-rw-r--r--drivers/gpu/drm/i915/i915_cmd_parser.c37
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c427
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c55
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c379
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h300
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c164
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c27
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c39
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c80
-rw-r--r--drivers/gpu/drm/i915/i915_gem_fence.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c139
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h56
-rw-r--r--drivers/gpu/drm/i915/i915_gem_render_state.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c3
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c4
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c40
-rw-r--r--drivers/gpu/drm/i915/i915_guc_reg.h53
-rw-r--r--drivers/gpu/drm/i915/i915_guc_submission.c51
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c307
-rw-r--r--drivers/gpu/drm/i915/i915_params.c10
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h2806
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c4
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c13
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h4
-rw-r--r--drivers/gpu/drm/i915/i915_vgpu.c6
-rw-r--r--drivers/gpu/drm/i915/i915_vgpu.h14
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c5
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c2
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c118
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c168
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h4
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c51
-rw-r--r--drivers/gpu/drm/i915/intel_csr.c295
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c200
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1225
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c1137
-rw-r--r--drivers/gpu/drm/i915/intel_dp_link_training.c323
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c44
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h264
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c101
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.h2
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_pll.c6
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c29
-rw-r--r--drivers/gpu/drm/i915/intel_fbc.c742
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c62
-rw-r--r--drivers/gpu/drm/i915/intel_fifo_underrun.c143
-rw-r--r--drivers/gpu/drm/i915/intel_guc.h12
-rw-r--r--drivers/gpu/drm/i915/intel_guc_fwif.h72
-rw-r--r--drivers/gpu/drm/i915/intel_guc_loader.c105
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c130
-rw-r--r--drivers/gpu/drm/i915/intel_hotplug.c11
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c82
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c176
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.h19
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c13
-rw-r--r--drivers/gpu/drm/i915/intel_mocs.c61
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c79
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c2
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c201
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c682
-rw-r--r--drivers/gpu/drm/i915/intel_psr.c146
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c206
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h15
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c637
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c64
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c34
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c2
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c284
-rw-r--r--drivers/gpu/drm/imx/Kconfig9
-rw-r--r--drivers/gpu/drm/imx/dw_hdmi-imx.c6
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c38
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h2
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c10
-rw-r--r--drivers/gpu/drm/imx/imx-tve.c10
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c3
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c12
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c4
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c8
-rw-r--r--drivers/gpu/drm/msm/Kconfig8
-rw-r--r--drivers/gpu/drm/msm/Makefile3
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c52
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h6
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.c35
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.h4
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c508
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c6
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.c4
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.h1
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c195
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.c3
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.h10
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c533
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c87
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c198
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c278
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h15
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c13
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c23
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c4
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c20
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c129
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c2
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c76
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h11
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c4
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c4
-rw-r--r--drivers/gpu/drm/nouveau/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c5
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dac.c10
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dfp.c9
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.c43
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv04.c8
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv17.c14
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl0002.h66
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl0046.h28
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl006b.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl0080.h45
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl506e.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl506f.h13
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl5070.h99
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl507a.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl507b.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl507c.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl507d.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl507e.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl826e.h14
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl826f.h15
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl906f.h14
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl9097.h44
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cla06f.h21
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/class.h701
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/device.h3
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0000.h12
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0001.h46
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0002.h38
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0003.h33
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0004.h13
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0005.h4
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/ioctl.h8
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/unpack.h34
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h16
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c35
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_crtc.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c224
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.h35
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c23
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hwmon.c50
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_platform.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sysfs.c197
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sysfs.h21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_usif.c25
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv17_fence.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c30
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fence.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/client.c9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/ioctl.c56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c54
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/user.c17
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c22
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h332
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c116
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c34
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm204.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c192
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm204.c63
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c92
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c18
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c57
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf106.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/gk104.c228
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c165
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h33
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h1366
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h1284
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h338
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h1516
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c2
-rw-r--r--drivers/gpu/drm/omapdrm/Kconfig10
-rw-r--r--drivers/gpu/drm/omapdrm/Makefile6
-rw-r--r--drivers/gpu/drm/omapdrm/displays/Kconfig (renamed from drivers/video/fbdev/omap2/displays-new/Kconfig)3
-rw-r--r--drivers/gpu/drm/omapdrm/displays/Makefile (renamed from drivers/video/fbdev/omap2/displays-new/Makefile)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c (renamed from drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-dvi.c (renamed from drivers/video/fbdev/omap2/displays-new/connector-dvi.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-hdmi.c (renamed from drivers/video/fbdev/omap2/displays-new/connector-hdmi.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-opa362.c (renamed from drivers/video/fbdev/omap2/displays-new/encoder-opa362.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c (renamed from drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c (renamed from drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dpi.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-dpi.c)8
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-dsi-cm.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c (renamed from drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/Kconfig (renamed from drivers/video/fbdev/omap2/dss/Kconfig)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/Makefile (renamed from drivers/video/fbdev/omap2/dss/Makefile)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/apply.c (renamed from drivers/video/fbdev/omap2/dss/apply.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/core.c (renamed from drivers/video/fbdev/omap2/dss/core.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc-compat.c (renamed from drivers/video/fbdev/omap2/dss/dispc-compat.c)6
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc-compat.h (renamed from drivers/video/fbdev/omap2/dss/dispc-compat.h)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c (renamed from drivers/video/fbdev/omap2/dss/dispc.c)163
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.h (renamed from drivers/video/fbdev/omap2/dss/dispc.h)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc_coefs.c (renamed from drivers/video/fbdev/omap2/dss/dispc_coefs.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/display-sysfs.c (renamed from drivers/video/fbdev/omap2/dss/display-sysfs.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/display.c (renamed from drivers/video/fbdev/omap2/dss/display.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dpi.c (renamed from drivers/video/fbdev/omap2/dss/dpi.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c (renamed from drivers/video/fbdev/omap2/dss/dsi.c)4
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss-of.c (renamed from drivers/video/fbdev/omap2/dss/dss-of.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.c (renamed from drivers/video/fbdev/omap2/dss/dss.c)6
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.h (renamed from drivers/video/fbdev/omap2/dss/dss.h)8
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss_features.c (renamed from drivers/video/fbdev/omap2/dss/dss_features.c)11
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss_features.h (renamed from drivers/video/fbdev/omap2/dss/dss_features.h)5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi.h (renamed from drivers/video/fbdev/omap2/dss/hdmi.h)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c (renamed from drivers/video/fbdev/omap2/dss/hdmi4.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.c (renamed from drivers/video/fbdev/omap2/dss/hdmi4_core.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.h (renamed from drivers/video/fbdev/omap2/dss/hdmi4_core.h)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c (renamed from drivers/video/fbdev/omap2/dss/hdmi5.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.c (renamed from drivers/video/fbdev/omap2/dss/hdmi5_core.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.h (renamed from drivers/video/fbdev/omap2/dss/hdmi5_core.h)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_common.c (renamed from drivers/video/fbdev/omap2/dss/hdmi_common.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_phy.c (renamed from drivers/video/fbdev/omap2/dss/hdmi_phy.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_pll.c (renamed from drivers/video/fbdev/omap2/dss/hdmi_pll.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_wp.c (renamed from drivers/video/fbdev/omap2/dss/hdmi_wp.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/manager-sysfs.c (renamed from drivers/video/fbdev/omap2/dss/manager-sysfs.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/manager.c (renamed from drivers/video/fbdev/omap2/dss/manager.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c (renamed from drivers/video/fbdev/omap2/dss/omapdss-boot-init.c)4
-rw-r--r--drivers/gpu/drm/omapdrm/dss/output.c (renamed from drivers/video/fbdev/omap2/dss/output.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c (renamed from drivers/video/fbdev/omap2/dss/overlay-sysfs.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/overlay.c (renamed from drivers/video/fbdev/omap2/dss/overlay.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/pll.c (renamed from drivers/video/fbdev/omap2/dss/pll.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/dss/rfbi.c (renamed from drivers/video/fbdev/omap2/dss/rfbi.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/sdi.c (renamed from drivers/video/fbdev/omap2/dss/sdi.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/venc.c (renamed from drivers/video/fbdev/omap2/dss/venc.c)2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/video-pll.c (renamed from drivers/video/fbdev/omap2/dss/video-pll.c)0
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_debugfs.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_tiler.c15
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c44
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h23
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c311
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c55
-rw-r--r--drivers/gpu/drm/omapdrm/tcm-sita.c804
-rw-r--r--drivers/gpu/drm/omapdrm/tcm.h26
-rw-r--r--drivers/gpu/drm/panel/Kconfig19
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c334
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c387
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c123
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c20
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h2
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c3
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c4
-rw-r--r--drivers/gpu/drm/radeon/Kconfig9
-rw-r--r--drivers/gpu/drm/radeon/Makefile4
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c1
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c108
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c30
-rw-r--r--drivers/gpu/drm/radeon/cik.c4
-rw-r--r--drivers/gpu/drm/radeon/dce6_afmt.c16
-rw-r--r--drivers/gpu/drm/radeon/drm_buffer.c177
-rw-r--r--drivers/gpu/drm/radeon/drm_buffer.h148
-rw-r--r--drivers/gpu/drm/radeon/r100.c5
-rw-r--r--drivers/gpu/drm/radeon/r300_cmdbuf.c1186
-rw-r--r--drivers/gpu/drm/radeon/r600_blit.c874
-rw-r--r--drivers/gpu/drm/radeon/r600_cp.c2660
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c95
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c38
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c19
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c2243
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_dp_mst.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c97
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h2048
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq.c402
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c24
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_mem.c302
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c3261
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c12
-rw-r--r--drivers/gpu/drm/radeon/sid.h5
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c10
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c3
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig10
-rw-r--r--drivers/gpu/drm/rockchip/Makefile4
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi.c1194
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c20
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c25
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h20
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.c131
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.h2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c1208
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h230
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.c316
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.h169
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_crtc.c4
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_kms.c2
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c2
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c1
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c7
-rw-r--r--drivers/gpu/drm/tegra/Kconfig12
-rw-r--r--drivers/gpu/drm/tegra/dc.c15
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c41
-rw-r--r--drivers/gpu/drm/tegra/drm.c94
-rw-r--r--drivers/gpu/drm/tegra/drm.h35
-rw-r--r--drivers/gpu/drm/tegra/dsi.c15
-rw-r--r--drivers/gpu/drm/tegra/fb.c42
-rw-r--r--drivers/gpu/drm/tegra/gem.c15
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c2
-rw-r--r--drivers/gpu/drm/tegra/rgb.c2
-rw-r--r--drivers/gpu/drm/tegra/sor.c147
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c3
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c31
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c4
-rw-r--r--drivers/gpu/drm/udl/udl_connector.c4
-rw-r--r--drivers/gpu/drm/udl/udl_drv.h2
-rw-r--r--drivers/gpu/drm/udl/udl_encoder.c3
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c5
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c2
-rw-r--r--drivers/gpu/drm/vc4/Makefile11
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c517
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c103
-rw-r--r--drivers/gpu/drm/vc4/vc4_debugfs.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c36
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h318
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c866
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c210
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c149
-rw-r--r--drivers/gpu/drm/vc4/vc4_packet.h399
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c42
-rw-r--r--drivers/gpu/drm/vc4/vc4_qpu_defines.h264
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h2
-rw-r--r--drivers/gpu/drm/vc4/vc4_render_cl.c634
-rw-r--r--drivers/gpu/drm/vc4/vc4_trace.h63
-rw-r--r--drivers/gpu/drm/vc4/vc4_trace_points.c (renamed from arch/arm/mach-orion5x/include/mach/hardware.h)10
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c262
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate.c900
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate_shaders.c513
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c22
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fb.c1
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_kms.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_plane.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c30
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c12
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c14
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c12
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c9
-rw-r--r--drivers/gpu/host1x/Makefile3
-rw-r--r--drivers/gpu/host1x/bus.c2
-rw-r--r--drivers/gpu/host1x/dev.c33
-rw-r--r--drivers/gpu/host1x/hw/host1x05.c42
-rw-r--r--drivers/gpu/host1x/hw/host1x05.h26
-rw-r--r--drivers/gpu/host1x/hw/host1x05_hardware.h142
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x05_channel.h121
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x05_sync.h243
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x05_uclass.h181
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c2
-rw-r--r--drivers/hid/hid-core.c49
-rw-r--r--drivers/hid/hid-corsair.c13
-rw-r--r--drivers/hid/hid-cp2112.c26
-rw-r--r--drivers/hid/hid-debug.c4
-rw-r--r--drivers/hid/hid-gt683r.c8
-rw-r--r--drivers/hid/hid-ids.h3
-rw-r--r--drivers/hid/hid-input.c21
-rw-r--r--drivers/hid/hid-lenovo.c36
-rw-r--r--drivers/hid/hid-lg4ff.c6
-rw-r--r--drivers/hid/hid-logitech-hidpp.c286
-rw-r--r--drivers/hid/hid-multitouch.c24
-rw-r--r--drivers/hid/hid-ntrig.c32
-rw-r--r--drivers/hid/hid-picolcd_leds.c4
-rw-r--r--drivers/hid/hid-prodikeys.c12
-rw-r--r--drivers/hid/hid-roccat-arvo.c6
-rw-r--r--drivers/hid/hid-roccat-common.c6
-rw-r--r--drivers/hid/hid-roccat-isku.c6
-rw-r--r--drivers/hid/hid-roccat-kone.c12
-rw-r--r--drivers/hid/hid-roccat-koneplus.c12
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c12
-rw-r--r--drivers/hid/hid-roccat-lua.c4
-rw-r--r--drivers/hid/hid-roccat-pyra.c15
-rw-r--r--drivers/hid/hid-sensor-hub.c6
-rw-r--r--drivers/hid/hid-sony.c107
-rw-r--r--drivers/hid/hid-steelseries.c8
-rw-r--r--drivers/hid/hid-wiimote-modules.c8
-rw-r--r--drivers/hid/hid-wiimote.h3
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c22
-rw-r--r--drivers/hid/usbhid/hid-core.c6
-rw-r--r--drivers/hid/usbhid/usbhid.h2
-rw-r--r--drivers/hid/wacom_sys.c23
-rw-r--r--drivers/hid/wacom_wac.c617
-rw-r--r--drivers/hid/wacom_wac.h5
-rw-r--r--drivers/hsi/controllers/omap_ssi.c7
-rw-r--r--drivers/hsi/controllers/omap_ssi_port.c8
-rw-r--r--drivers/hv/channel.c138
-rw-r--r--drivers/hv/channel_mgmt.c48
-rw-r--r--drivers/hv/connection.c18
-rw-r--r--drivers/hv/hv.c29
-rw-r--r--drivers/hv/hv_fcopy.c37
-rw-r--r--drivers/hv/hv_kvp.c33
-rw-r--r--drivers/hv/hv_snapshot.c36
-rw-r--r--drivers/hv/hv_utils_transport.c130
-rw-r--r--drivers/hv/hv_utils_transport.h3
-rw-r--r--drivers/hv/hyperv_vmbus.h26
-rw-r--r--drivers/hv/ring_buffer.c218
-rw-r--r--drivers/hv/vmbus_drv.c82
-rw-r--r--drivers/hwmon/sch56xx-common.c31
-rw-r--r--drivers/hwtracing/coresight/Kconfig2
-rw-r--r--drivers/hwtracing/coresight/coresight.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c6
-rw-r--r--drivers/i2c/busses/Kconfig9
-rw-r--r--drivers/i2c/busses/i2c-at91.c53
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c10
-rw-r--r--drivers/i2c/busses/i2c-brcmstb.c80
-rw-r--r--drivers/i2c/busses/i2c-cadence.c73
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c23
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c4
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c32
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c1
-rw-r--r--drivers/i2c/busses/i2c-emev2.c112
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c4
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c92
-rw-r--r--drivers/i2c/busses/i2c-imx.c109
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c54
-rw-r--r--drivers/i2c/busses/i2c-piix4.c202
-rw-r--r--drivers/i2c/busses/i2c-rcar.c319
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c6
-rw-r--r--drivers/i2c/busses/i2c-st.c3
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c8
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c11
-rw-r--r--drivers/i2c/busses/i2c-uniphier.c11
-rw-r--r--drivers/i2c/busses/i2c-xiic.c12
-rw-r--r--drivers/i2c/busses/i2c-xlr.c250
-rw-r--r--drivers/i2c/i2c-core.c56
-rw-r--r--drivers/ide/ide-scan-pci.c3
-rw-r--r--drivers/ide/ide.c16
-rw-r--r--drivers/ide/it821x.c2
-rw-r--r--drivers/ide/trm290.c2
-rw-r--r--drivers/iio/Kconfig18
-rw-r--r--drivers/iio/Makefile4
-rw-r--r--drivers/iio/accel/Kconfig42
-rw-r--r--drivers/iio/accel/Makefile6
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c20
-rw-r--r--drivers/iio/accel/kxcjk-1013.c20
-rw-r--r--drivers/iio/accel/mma7455.h19
-rw-r--r--drivers/iio/accel/mma7455_core.c311
-rw-r--r--drivers/iio/accel/mma7455_i2c.c56
-rw-r--r--drivers/iio/accel/mma7455_spi.c52
-rw-r--r--drivers/iio/accel/mma8452.c61
-rw-r--r--drivers/iio/accel/mma9551.c19
-rw-r--r--drivers/iio/accel/mma9553.c20
-rw-r--r--drivers/iio/accel/mxc6255.c198
-rw-r--r--drivers/iio/accel/st_accel.h1
-rw-r--r--drivers/iio/accel/st_accel_core.c1
-rw-r--r--drivers/iio/accel/st_accel_i2c.c5
-rw-r--r--drivers/iio/accel/st_accel_spi.c1
-rw-r--r--drivers/iio/adc/Kconfig43
-rw-r--r--drivers/iio/adc/Makefile4
-rw-r--r--drivers/iio/adc/ad7793.c5
-rw-r--r--drivers/iio/adc/at91_adc.c2
-rw-r--r--drivers/iio/adc/exynos_adc.c224
-rw-r--r--drivers/iio/adc/imx7d_adc.c609
-rw-r--r--drivers/iio/adc/ina2xx-adc.c745
-rw-r--r--drivers/iio/adc/mcp320x.c28
-rw-r--r--drivers/iio/adc/mcp3422.c9
-rw-r--r--drivers/iio/adc/palmas_gpadc.c859
-rw-r--r--drivers/iio/adc/ti-adc128s052.c13
-rw-r--r--drivers/iio/adc/ti-ads8688.c486
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c2
-rw-r--r--drivers/iio/buffer/Kconfig20
-rw-r--r--drivers/iio/buffer/Makefile2
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dma.c683
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c213
-rw-r--r--drivers/iio/chemical/Kconfig8
-rw-r--r--drivers/iio/chemical/Makefile1
-rw-r--r--drivers/iio/chemical/ams-iaq-core.c200
-rw-r--r--drivers/iio/chemical/vz89x.c66
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c3
-rw-r--r--drivers/iio/dummy/Kconfig36
-rw-r--r--drivers/iio/dummy/Makefile10
-rw-r--r--drivers/iio/dummy/iio_dummy_evgen.c (renamed from drivers/staging/iio/iio_dummy_evgen.c)0
-rw-r--r--drivers/iio/dummy/iio_dummy_evgen.h (renamed from drivers/staging/iio/iio_dummy_evgen.h)0
-rw-r--r--drivers/iio/dummy/iio_simple_dummy.c (renamed from drivers/staging/iio/iio_simple_dummy.c)0
-rw-r--r--drivers/iio/dummy/iio_simple_dummy.h (renamed from drivers/staging/iio/iio_simple_dummy.h)0
-rw-r--r--drivers/iio/dummy/iio_simple_dummy_buffer.c (renamed from drivers/staging/iio/iio_simple_dummy_buffer.c)0
-rw-r--r--drivers/iio/dummy/iio_simple_dummy_events.c (renamed from drivers/staging/iio/iio_simple_dummy_events.c)0
-rw-r--r--drivers/iio/gyro/adis16136.c4
-rw-r--r--drivers/iio/gyro/bmg160_core.c19
-rw-r--r--drivers/iio/health/Kconfig21
-rw-r--r--drivers/iio/health/Makefile7
-rw-r--r--drivers/iio/health/max30100.c453
-rw-r--r--drivers/iio/imu/adis16400_core.c6
-rw-r--r--drivers/iio/imu/adis16480.c4
-rw-r--r--drivers/iio/imu/kmx61.c24
-rw-r--r--drivers/iio/industrialio-buffer.c58
-rw-r--r--drivers/iio/industrialio-configfs.c51
-rw-r--r--drivers/iio/industrialio-core.c19
-rw-r--r--drivers/iio/industrialio-sw-trigger.c184
-rw-r--r--drivers/iio/inkern.c6
-rw-r--r--drivers/iio/light/lm3533-als.c4
-rw-r--r--drivers/iio/light/pa12203001.c16
-rw-r--r--drivers/iio/light/rpr0521.c14
-rw-r--r--drivers/iio/light/us5182d.c609
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c20
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c151
-rw-r--r--drivers/iio/trigger/Kconfig10
-rw-r--r--drivers/iio/trigger/Makefile2
-rw-r--r--drivers/iio/trigger/iio-trig-hrtimer.c193
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c2
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c2
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c7
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c103
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.h8
-rw-r--r--drivers/input/keyboard/gpio_keys.c29
-rw-r--r--drivers/input/keyboard/omap-keypad.c10
-rw-r--r--drivers/input/misc/bma150.c2
-rw-r--r--drivers/input/misc/da9063_onkey.c8
-rw-r--r--drivers/input/misc/sparcspkr.c18
-rw-r--r--drivers/input/misc/uinput.c158
-rw-r--r--drivers/input/mouse/alps.c22
-rw-r--r--drivers/input/mouse/elantech.c2
-rw-r--r--drivers/input/mouse/focaltech.c22
-rw-r--r--drivers/input/mouse/focaltech.h8
-rw-r--r--drivers/input/mouse/logips2pp.c2
-rw-r--r--drivers/input/mouse/logips2pp.h4
-rw-r--r--drivers/input/mouse/psmouse-base.c770
-rw-r--r--drivers/input/serio/hyperv-keyboard.c10
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h7
-rw-r--r--drivers/input/touchscreen/Kconfig29
-rw-r--r--drivers/input/touchscreen/Makefile2
-rw-r--r--drivers/input/touchscreen/ad7879.c2
-rw-r--r--drivers/input/touchscreen/egalax_ts_serial.c194
-rw-r--r--drivers/input/touchscreen/goodix.c513
-rw-r--r--drivers/input/touchscreen/pcap_ts.c2
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c41
-rw-r--r--drivers/input/touchscreen/rohm_bu21023.c2
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c2
-rw-r--r--drivers/input/touchscreen/ts4800-ts.c216
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c325
-rw-r--r--drivers/iommu/Kconfig75
-rw-r--r--drivers/iommu/Makefile2
-rw-r--r--drivers/iommu/amd_iommu.c396
-rw-r--r--drivers/iommu/amd_iommu_types.h40
-rw-r--r--drivers/iommu/amd_iommu_v2.c38
-rw-r--r--drivers/iommu/arm-smmu-v3.c210
-rw-r--r--drivers/iommu/arm-smmu.c23
-rw-r--r--drivers/iommu/dmar.c12
-rw-r--r--drivers/iommu/io-pgtable-arm.c49
-rw-r--r--drivers/iommu/io-pgtable.h6
-rw-r--r--drivers/iommu/ipmmu-vmsa.c4
-rw-r--r--drivers/iommu/msm_iommu_dev.c25
-rw-r--r--drivers/iommu/s390-iommu.c4
-rw-r--r--drivers/iommu/shmobile-iommu.c402
-rw-r--r--drivers/iommu/shmobile-ipmmu.c129
-rw-r--r--drivers/iommu/shmobile-ipmmu.h34
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c5
-rw-r--r--drivers/leds/leds-pca9532.c14
-rw-r--r--drivers/leds/leds-tca6507.c6
-rw-r--r--drivers/lguest/core.c74
-rw-r--r--drivers/macintosh/rack-meter.c1
-rw-r--r--drivers/macintosh/via-pmu.c5
-rw-r--r--drivers/mailbox/mailbox-sti.c2
-rw-r--r--drivers/md/md-cluster.c164
-rw-r--r--drivers/md/md-cluster.h2
-rw-r--r--drivers/md/md.c687
-rw-r--r--drivers/md/md.h51
-rw-r--r--drivers/md/multipath.c6
-rw-r--r--drivers/md/raid0.c4
-rw-r--r--drivers/md/raid1.c6
-rw-r--r--drivers/md/raid10.c6
-rw-r--r--drivers/md/raid5-cache.c158
-rw-r--r--drivers/md/raid5.c36
-rw-r--r--drivers/media/Kconfig1
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c2
-rw-r--r--drivers/media/common/siano/smsdvb-main.c7
-rw-r--r--drivers/media/dvb-core/dmxdev.c4
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c2
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c11
-rw-r--r--drivers/media/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb-core/dvbdev.c488
-rw-r--r--drivers/media/dvb-core/dvbdev.h58
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c17
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h12
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c2
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c2
-rw-r--r--drivers/media/dvb-frontends/si2165.c4
-rw-r--r--drivers/media/firewire/firedtv-ci.c2
-rw-r--r--drivers/media/i2c/ad9389b.c2
-rw-r--r--drivers/media/i2c/adp1653.c4
-rw-r--r--drivers/media/i2c/adv7180.c4
-rw-r--r--drivers/media/i2c/adv7511.c2
-rw-r--r--drivers/media/i2c/adv7604.c4
-rw-r--r--drivers/media/i2c/adv7842.c2
-rw-r--r--drivers/media/i2c/as3645a.c4
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c6
-rw-r--r--drivers/media/i2c/lm3560.c4
-rw-r--r--drivers/media/i2c/lm3646.c4
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c4
-rw-r--r--drivers/media/i2c/mt9m032.c2
-rw-r--r--drivers/media/i2c/mt9p031.c2
-rw-r--r--drivers/media/i2c/mt9t001.c2
-rw-r--r--drivers/media/i2c/mt9v032.c2
-rw-r--r--drivers/media/i2c/noon010pc30.c4
-rw-r--r--drivers/media/i2c/ov2659.c4
-rw-r--r--drivers/media/i2c/ov9650.c4
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c16
-rw-r--r--drivers/media/i2c/s5k4ecgx.c4
-rw-r--r--drivers/media/i2c/s5k5baf.c12
-rw-r--r--drivers/media/i2c/s5k6a3.c2
-rw-r--r--drivers/media/i2c/s5k6aa.c4
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c32
-rw-r--r--drivers/media/i2c/tc358743.c2
-rw-r--r--drivers/media/i2c/tvp514x.c4
-rw-r--r--drivers/media/i2c/tvp7002.c4
-rw-r--r--drivers/media/media-device.c441
-rw-r--r--drivers/media/media-devnode.c24
-rw-r--r--drivers/media/media-entity.c724
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.c3
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c2
-rw-r--r--drivers/media/pci/netup_unidvb/netup_unidvb_core.c2
-rw-r--r--drivers/media/pci/ngene/ngene-core.c2
-rw-r--r--drivers/media/pci/ttpci/av7110.c2
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c4
-rw-r--r--drivers/media/pci/ttpci/av7110_ca.c2
-rw-r--r--drivers/media/platform/exynos4-is/common.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c11
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c11
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c24
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c2
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c73
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h9
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c4
-rw-r--r--drivers/media/platform/omap/Kconfig2
-rw-r--r--drivers/media/platform/omap3isp/isp.c306
-rw-r--r--drivers/media/platform/omap3isp/isp.h9
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c31
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c27
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c21
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c30
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c28
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c2
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c49
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h5
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c8
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c21
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c50
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c29
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h5
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c64
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c40
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c21
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c16
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c4
-rw-r--r--drivers/media/usb/au0828/au0828-core.c171
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c12
-rw-r--r--drivers/media/usb/au0828/au0828-video.c126
-rw-r--r--drivers/media/usb/au0828/au0828.h10
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c81
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c6
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c14
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c42
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c20
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.h5
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-dvb.c43
-rw-r--r--drivers/media/usb/siano/smsusb.c5
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c11
-rw-r--r--drivers/media/usb/uvc/uvc_entity.c38
-rw-r--r--drivers/media/v4l2-core/tuner-core.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c111
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c39
-rw-r--r--drivers/media/v4l2-core/v4l2-flash-led-class.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c8
-rw-r--r--drivers/memory/tegra/tegra124.c1
-rw-r--r--drivers/mfd/88pm80x.c4
-rw-r--r--drivers/mfd/88pm860x-core.c13
-rw-r--r--drivers/mfd/Kconfig20
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/aat2870-core.c5
-rw-r--r--drivers/mfd/ab3100-core.c23
-rw-r--r--drivers/mfd/ab3100-otp.c5
-rw-r--r--drivers/mfd/ab8500-core.c506
-rw-r--r--drivers/mfd/ab8500-debugfs.c25
-rw-r--r--drivers/mfd/ab8500-gpadc.c145
-rw-r--r--drivers/mfd/ab8500-sysctrl.c13
-rw-r--r--drivers/mfd/adp5520.c6
-rw-r--r--drivers/mfd/arizona-core.c92
-rw-r--r--drivers/mfd/arizona-i2c.c2
-rw-r--r--drivers/mfd/arizona-irq.c95
-rw-r--r--drivers/mfd/arizona-spi.c7
-rw-r--r--drivers/mfd/arizona.h4
-rw-r--r--drivers/mfd/as3711.c28
-rw-r--r--drivers/mfd/as3722.c30
-rw-r--r--drivers/mfd/asic3.c30
-rw-r--r--drivers/mfd/cros_ec_i2c.c2
-rw-r--r--drivers/mfd/cros_ec_spi.c34
-rw-r--r--drivers/mfd/cs47l24-tables.c1629
-rw-r--r--drivers/mfd/cs5535-mfd.c6
-rw-r--r--drivers/mfd/da903x.c14
-rw-r--r--drivers/mfd/da9052-i2c.c2
-rw-r--r--drivers/mfd/da9052-irq.c2
-rw-r--r--drivers/mfd/davinci_voicecodec.c5
-rw-r--r--drivers/mfd/dm355evm_msp.c4
-rw-r--r--drivers/mfd/htc-egpio.c4
-rw-r--r--drivers/mfd/htc-i2cpld.c4
-rw-r--r--drivers/mfd/lpc_ich.c15
-rw-r--r--drivers/mfd/max14577.c4
-rw-r--r--drivers/mfd/max77686.c4
-rw-r--r--drivers/mfd/max77693.c4
-rw-r--r--drivers/mfd/max77843.c4
-rw-r--r--drivers/mfd/max8925-i2c.c4
-rw-r--r--drivers/mfd/max8997.c8
-rw-r--r--drivers/mfd/max8998.c8
-rw-r--r--drivers/mfd/mc13xxx-core.c8
-rw-r--r--drivers/mfd/qcom-spmi-pmic.c4
-rw-r--r--drivers/mfd/qcom_rpm.c2
-rw-r--r--drivers/mfd/sec-core.c43
-rw-r--r--drivers/mfd/sec-irq.c8
-rw-r--r--drivers/mfd/sta2x11-mfd.c36
-rw-r--r--drivers/mfd/syscon.c13
-rw-r--r--drivers/mfd/tc6393xb.c4
-rw-r--r--drivers/mfd/tps65010.c6
-rw-r--r--drivers/mfd/ucb1x00-core.c4
-rw-r--r--drivers/mfd/vexpress-sysreg.c8
-rw-r--r--drivers/mfd/wm5110-tables.c6
-rw-r--r--drivers/mfd/wm831x-otp.c10
-rw-r--r--drivers/misc/cxl/Makefile3
-rw-r--r--drivers/misc/cxl/api.c6
-rw-r--r--drivers/misc/cxl/context.c15
-rw-r--r--drivers/misc/cxl/cxl.h15
-rw-r--r--drivers/misc/cxl/fault.c129
-rw-r--r--drivers/misc/cxl/file.c25
-rw-r--r--drivers/misc/cxl/pci.c1
-rw-r--r--drivers/misc/cxl/vphb.c2
-rw-r--r--drivers/misc/ibmasm/ibmasm.h2
-rw-r--r--drivers/misc/mei/main.c6
-rw-r--r--drivers/misc/mic/card/mic_virtio.c2
-rw-r--r--drivers/mmc/host/atmel-mci.c18
-rw-r--r--drivers/mtd/Kconfig2
-rw-r--r--drivers/mtd/afs.c82
-rw-r--r--drivers/mtd/ar7part.c18
-rw-r--r--drivers/mtd/bcm47xxpart.c18
-rw-r--r--drivers/mtd/bcm63xxpart.c18
-rw-r--r--drivers/mtd/chips/Kconfig4
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c8
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c6
-rw-r--r--drivers/mtd/cmdlinepart.c3
-rw-r--r--drivers/mtd/devices/m25p80.c44
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c5
-rw-r--r--drivers/mtd/devices/spear_smi.c6
-rw-r--r--drivers/mtd/devices/st_spi_fsm.c5
-rw-r--r--drivers/mtd/ftl.c8
-rw-r--r--drivers/mtd/maps/lantiq-flash.c5
-rw-r--r--drivers/mtd/maps/physmap_of.c6
-rw-r--r--drivers/mtd/mtdcore.c40
-rw-r--r--drivers/mtd/mtdcore.h7
-rw-r--r--drivers/mtd/mtdpart.c133
-rw-r--r--drivers/mtd/nand/Kconfig11
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/ams-delta.c26
-rw-r--r--drivers/mtd/nand/atmel_nand.c134
-rw-r--r--drivers/mtd/nand/au1550nd.c40
-rw-r--r--drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h1
-rw-r--r--drivers/mtd/nand/bcm47xxnflash/main.c16
-rw-r--r--drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c34
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c45
-rw-r--r--drivers/mtd/nand/brcmnand/Makefile1
-rw-r--r--drivers/mtd/nand/brcmnand/bcm6368_nand.c142
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.c166
-rw-r--r--drivers/mtd/nand/cafe_nand.c43
-rw-r--r--drivers/mtd/nand/cmx270_nand.c23
-rw-r--r--drivers/mtd/nand/cs553x_nand.c34
-rw-r--r--drivers/mtd/nand/davinci_nand.c60
-rw-r--r--drivers/mtd/nand/denali.c75
-rw-r--r--drivers/mtd/nand/denali.h1
-rw-r--r--drivers/mtd/nand/diskonchip.c189
-rw-r--r--drivers/mtd/nand/docg4.c102
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c64
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c74
-rw-r--r--drivers/mtd/nand/fsl_upm.c35
-rw-r--r--drivers/mtd/nand/fsmc_nand.c69
-rw-r--r--drivers/mtd/nand/gpio.c26
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c2
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c71
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h1
-rw-r--r--drivers/mtd/nand/hisi504_nand.c53
-rw-r--r--drivers/mtd/nand/jz4740_nand.c37
-rw-r--r--drivers/mtd/nand/jz4780_bch.c381
-rw-r--r--drivers/mtd/nand/jz4780_bch.h43
-rw-r--r--drivers/mtd/nand/jz4780_nand.c428
-rw-r--r--drivers/mtd/nand/lpc32xx_mlc.c40
-rw-r--r--drivers/mtd/nand/lpc32xx_slc.c49
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c57
-rw-r--r--drivers/mtd/nand/mxc_nand.c88
-rw-r--r--drivers/mtd/nand/nand_base.c157
-rw-r--r--drivers/mtd/nand/nand_bbt.c32
-rw-r--r--drivers/mtd/nand/nand_bch.c6
-rw-r--r--drivers/mtd/nand/nand_ecc.c6
-rw-r--r--drivers/mtd/nand/nandsim.c41
-rw-r--r--drivers/mtd/nand/ndfc.c55
-rw-r--r--drivers/mtd/nand/nuc900_nand.c40
-rw-r--r--drivers/mtd/nand/omap2.c92
-rw-r--r--drivers/mtd/nand/omap_elm.c2
-rw-r--r--drivers/mtd/nand/orion_nand.c19
-rw-r--r--drivers/mtd/nand/pasemi_nand.c21
-rw-r--r--drivers/mtd/nand/plat_nand.c18
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c169
-rw-r--r--drivers/mtd/nand/r852.c46
-rw-r--r--drivers/mtd/nand/r852.h1
-rw-r--r--drivers/mtd/nand/s3c2410.c31
-rw-r--r--drivers/mtd/nand/sh_flctl.c20
-rw-r--r--drivers/mtd/nand/sharpsl.c23
-rw-r--r--drivers/mtd/nand/sm_common.c2
-rw-r--r--drivers/mtd/nand/socrates_nand.c30
-rw-r--r--drivers/mtd/nand/sunxi_nand.c50
-rw-r--r--drivers/mtd/nand/tmio_nand.c13
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c25
-rw-r--r--drivers/mtd/nand/vf610_nfc.c23
-rw-r--r--drivers/mtd/nand/xway_nand.c4
-rw-r--r--drivers/mtd/ofpart.c53
-rw-r--r--drivers/mtd/onenand/omap2.c8
-rw-r--r--drivers/mtd/redboot.c19
-rw-r--r--drivers/mtd/sm_ftl.c3
-rw-r--r--drivers/mtd/spi-nor/Kconfig7
-rw-r--r--drivers/mtd/spi-nor/Makefile1
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c14
-rw-r--r--drivers/mtd/spi-nor/mtk-quadspi.c485
-rw-r--r--drivers/mtd/spi-nor/nxp-spifi.c6
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c77
-rw-r--r--drivers/mtd/tests/pagetest.c3
-rw-r--r--drivers/net/ethernet/3com/3c59x.c9
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c5
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c37
-rw-r--r--drivers/net/ethernet/cadence/macb.c4
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_dtsec.c1
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c2
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c8
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.h8
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c5
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c13
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h3
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h5
-rw-r--r--drivers/net/ethernet/hisilicon/hns_mdio.c2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c1
-rw-r--r--drivers/net/ethernet/smsc/Kconfig4
-rw-r--r--drivers/net/ethernet/smsc/smc91x.h11
-rw-r--r--drivers/net/phy/at803x.c110
-rw-r--r--drivers/net/phy/phy_device.c5
-rw-r--r--drivers/net/team/team.c6
-rw-r--r--drivers/net/wan/x25_asy.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/calib.c2
-rw-r--r--drivers/net/xen-netback/interface.c17
-rw-r--r--drivers/net/xen-netback/netback.c20
-rw-r--r--drivers/nvdimm/core.c169
-rw-r--r--drivers/nvdimm/namespace_devs.c132
-rw-r--r--drivers/nvdimm/nd-core.h2
-rw-r--r--drivers/nvdimm/nd.h16
-rw-r--r--drivers/nvdimm/pfn_devs.c96
-rw-r--r--drivers/nvdimm/pmem.c163
-rw-r--r--drivers/nvdimm/region_devs.c66
-rw-r--r--drivers/nvme/host/lightnvm.c2
-rw-r--r--drivers/nvme/host/pci.c11
-rw-r--r--drivers/of/address.c2
-rw-r--r--drivers/of/dynamic.c65
-rw-r--r--drivers/of/irq.c27
-rw-r--r--drivers/of/of_private.h2
-rw-r--r--drivers/of/overlay.c8
-rw-r--r--drivers/of/platform.c1
-rw-r--r--drivers/of/unittest.c18
-rw-r--r--drivers/parisc/dino.c4
-rw-r--r--drivers/parisc/lba_pci.c4
-rw-r--r--drivers/parport/share.c246
-rw-r--r--drivers/pci/quirks.c4
-rw-r--r--drivers/phy/Kconfig20
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/phy/phy-berlin-usb.c3
-rw-r--r--drivers/phy/phy-brcmstb-sata.c47
-rw-r--r--drivers/phy/phy-hi6220-usb.c168
-rw-r--r--drivers/phy/phy-mt65xx-usb3.c106
-rw-r--r--drivers/phy/phy-omap-usb2.c94
-rw-r--r--drivers/phy/phy-rcar-gen3-usb2.c378
-rw-r--r--drivers/phy/phy-rockchip-usb.c287
-rw-r--r--drivers/phy/phy-sun4i-usb.c158
-rw-r--r--drivers/phy/phy-ti-pipe3.c302
-rw-r--r--drivers/phy/phy-twl4030-usb.c32
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c12
-rw-r--r--drivers/pinctrl/bcm/pinctrl-iproc-gpio.c2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-nsp-gpio.c21
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c36
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c22
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c17
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c16
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c19
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c34
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik.c33
-rw-r--r--drivers/pinctrl/pinctrl-adi2.c16
-rw-r--r--drivers/pinctrl/pinctrl-amd.c35
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c15
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c16
-rw-r--r--drivers/pinctrl/pinctrl-at91.c28
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c35
-rw-r--r--drivers/pinctrl/pinctrl-digicolor.c12
-rw-r--r--drivers/pinctrl/pinctrl-pistachio.c25
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c17
-rw-r--r--drivers/pinctrl/pinctrl-st.c23
-rw-r--r--drivers/pinctrl/pinctrl-xway.c12
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c31
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c23
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c23
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c16
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c18
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c3
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos5440.c16
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c17
-rw-r--r--drivers/pinctrl/sh-pfc/gpio.c18
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas7.c31
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c31
-rw-r--r--drivers/pinctrl/spear/pinctrl-plgpio.c24
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c16
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c12
-rw-r--r--drivers/platform/x86/Kconfig48
-rw-r--r--drivers/platform/x86/Makefile6
-rw-r--r--drivers/platform/x86/apple-gmux.c123
-rw-r--r--drivers/platform/x86/asus-wireless.c84
-rw-r--r--drivers/platform/x86/asus-wmi.c3
-rw-r--r--drivers/platform/x86/dell-wmi.c182
-rw-r--r--drivers/platform/x86/ideapad-laptop.c7
-rw-r--r--drivers/platform/x86/intel-hid.c289
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c214
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c4
-rw-r--r--drivers/platform/x86/intel_punit_ipc.c342
-rw-r--r--drivers/platform/x86/intel_telemetry_core.c464
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c1030
-rw-r--r--drivers/platform/x86/intel_telemetry_pltdrv.c1206
-rw-r--r--drivers/platform/x86/sony-laptop.c65
-rw-r--r--drivers/platform/x86/surfacepro3_button.c12
-rw-r--r--drivers/platform/x86/tc1100-wmi.c2
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c206
-rw-r--r--drivers/platform/x86/toshiba_acpi.c246
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c2
-rw-r--r--drivers/power/Kconfig17
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/bq2415x_charger.c6
-rw-r--r--drivers/power/bq27xxx_battery.c348
-rw-r--r--drivers/power/bq27xxx_battery_i2c.c150
-rw-r--r--drivers/power/ds2782_battery.c4
-rw-r--r--drivers/power/generic-adc-battery.c2
-rw-r--r--drivers/power/isp1704_charger.c2
-rw-r--r--drivers/power/max8903_charger.c24
-rw-r--r--drivers/power/reset/at91-reset.c1
-rw-r--r--drivers/power/test_power.c2
-rw-r--r--drivers/regulator/Kconfig37
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/axp20x-regulator.c4
-rw-r--r--drivers/regulator/core.c41
-rw-r--r--drivers/regulator/da903x.c10
-rw-r--r--drivers/regulator/da9052-regulator.c4
-rw-r--r--drivers/regulator/da9055-regulator.c4
-rw-r--r--drivers/regulator/da9062-regulator.c4
-rw-r--r--drivers/regulator/da9063-regulator.c4
-rw-r--r--drivers/regulator/da9210-regulator.c2
-rw-r--r--drivers/regulator/da9211-regulator.c2
-rw-r--r--drivers/regulator/devres.c7
-rw-r--r--drivers/regulator/lm363x-regulator.c291
-rw-r--r--drivers/regulator/lp872x.c17
-rw-r--r--drivers/regulator/lp8788-buck.c4
-rw-r--r--drivers/regulator/lp8788-ldo.c20
-rw-r--r--drivers/regulator/mt6311-regulator.c1
-rw-r--r--drivers/regulator/palmas-regulator.c39
-rw-r--r--drivers/regulator/pv88060-regulator.c437
-rw-r--r--drivers/regulator/pv88060-regulator.h69
-rw-r--r--drivers/regulator/pv88090-regulator.c458
-rw-r--r--drivers/regulator/pv88090-regulator.h98
-rw-r--r--drivers/regulator/qcom_smd-regulator.c159
-rw-r--r--drivers/regulator/s2mps11.c143
-rw-r--r--drivers/regulator/tps6105x-regulator.c95
-rw-r--r--drivers/regulator/tps65086-regulator.c251
-rw-r--r--drivers/regulator/tps65218-regulator.c137
-rw-r--r--drivers/regulator/wm831x-dcdc.c39
-rw-r--r--drivers/regulator/wm831x-isink.c2
-rw-r--r--drivers/regulator/wm831x-ldo.c33
-rw-r--r--drivers/regulator/wm8350-regulator.c8
-rw-r--r--drivers/regulator/wm8400-regulator.c4
-rw-r--r--drivers/regulator/wm8994-regulator.c4
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c2
-rw-r--r--drivers/reset/Kconfig1
-rw-r--r--drivers/reset/Makefile3
-rw-r--r--drivers/reset/core.c60
-rw-r--r--drivers/reset/hisilicon/Kconfig5
-rw-r--r--drivers/reset/hisilicon/Makefile1
-rw-r--r--drivers/reset/hisilicon/hi6220_reset.c109
-rw-r--r--drivers/reset/reset-ath79.c30
-rw-r--r--drivers/reset/reset-berlin.c4
-rw-r--r--drivers/reset/reset-socfpga.c3
-rw-r--r--drivers/reset/reset-sunxi.c5
-rw-r--r--drivers/reset/reset-zynq.c3
-rw-r--r--drivers/reset/sti/reset-stih407.c5
-rw-r--r--drivers/reset/sti/reset-syscfg.c27
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c2
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-abx80x.c146
-rw-r--r--drivers/rtc/rtc-cmos.c2
-rw-r--r--drivers/rtc/rtc-da9063.c23
-rw-r--r--drivers/rtc/rtc-ds1305.c8
-rw-r--r--drivers/rtc/rtc-ds1307.c17
-rw-r--r--drivers/rtc/rtc-ds1685.c22
-rw-r--r--drivers/rtc/rtc-ds2404.c4
-rw-r--r--drivers/rtc/rtc-efi.c66
-rw-r--r--drivers/rtc/rtc-gemini.c1
-rw-r--r--drivers/rtc/rtc-imxdi.c2
-rw-r--r--drivers/rtc/rtc-lpc32xx.c2
-rw-r--r--drivers/rtc/rtc-opal.c2
-rw-r--r--drivers/rtc/rtc-pcf8523.c11
-rw-r--r--drivers/rtc/rtc-proc.c8
-rw-r--r--drivers/rtc/rtc-rv8803.c3
-rw-r--r--drivers/rtc/rtc-rx8010.c523
-rw-r--r--drivers/rtc/rtc-s5m.c131
-rw-r--r--drivers/rtc/rtc-sunxi.c18
-rw-r--r--drivers/rtc/rtc-sysfs.c11
-rw-r--r--drivers/rtc/rtc-v3020.c6
-rw-r--r--drivers/s390/block/dasd.c8
-rw-r--r--drivers/s390/block/dcssblk.c11
-rw-r--r--drivers/s390/char/Kconfig21
-rw-r--r--drivers/s390/char/Makefile5
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/con3270.c2
-rw-r--r--drivers/s390/char/hmcdrv_ftp.c6
-rw-r--r--drivers/s390/char/sclp.c5
-rw-r--r--drivers/s390/char/sclp_config.c102
-rw-r--r--drivers/s390/char/sclp_cpi.c40
-rw-r--r--drivers/s390/char/zcore.c450
-rw-r--r--drivers/s390/cio/Makefile5
-rw-r--r--drivers/s390/cio/airq.c1
-rw-r--r--drivers/s390/cio/chsc_sch.c5
-rw-r--r--drivers/s390/cio/cio.c37
-rw-r--r--drivers/s390/cio/cio.h12
-rw-r--r--drivers/s390/cio/crw.c1
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/cio/device_fsm.c2
-rw-r--r--drivers/s390/cio/io_sch.h45
-rw-r--r--drivers/s390/cio/ioasm.c224
-rw-r--r--drivers/s390/cio/ioasm.h169
-rw-r--r--drivers/s390/cio/qdio_debug.c6
-rw-r--r--drivers/s390/cio/trace.c24
-rw-r--r--drivers/s390/cio/trace.h363
-rw-r--r--drivers/s390/crypto/zcrypt_api.c6
-rw-r--r--drivers/s390/virtio/kvm_virtio.c2
-rw-r--r--drivers/s390/virtio/virtio_ccw.c2
-rw-r--r--drivers/scsi/Kconfig2
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/aacraid/linit.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h4
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h5
-rw-r--r--drivers/scsi/aic7xxx/queue.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h49
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h14
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c209
-rw-r--r--drivers/scsi/atp870u.c3635
-rw-r--r--drivers/scsi/atp870u.h4
-rw-r--r--drivers/scsi/bfa/bfa.h7
-rw-r--r--drivers/scsi/bfa/bfa_core.c7
-rw-r--r--drivers/scsi/bfa/bfa_cs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs_fcs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h7
-rw-r--r--drivers/scsi/bfa/bfa_fc.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h9
-rw-r--r--drivers/scsi/bfa/bfa_fcs_fcpim.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c9
-rw-r--r--drivers/scsi/bfa/bfa_fcs_rport.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c9
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h7
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_modules.h7
-rw-r--r--drivers/scsi/bfa/bfa_plog.h7
-rw-r--r--drivers/scsi/bfa/bfa_port.c7
-rw-r--r--drivers/scsi/bfa/bfa_port.h7
-rw-r--r--drivers/scsi/bfa/bfa_svc.c7
-rw-r--r--drivers/scsi/bfa/bfa_svc.h7
-rw-r--r--drivers/scsi/bfa/bfad.c24
-rw-r--r--drivers/scsi/bfa/bfad_attr.c75
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c7
-rw-r--r--drivers/scsi/bfa/bfad_bsg.h7
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c7
-rw-r--r--drivers/scsi/bfa/bfad_drv.h9
-rw-r--r--drivers/scsi/bfa/bfad_im.c35
-rw-r--r--drivers/scsi/bfa/bfad_im.h7
-rw-r--r--drivers/scsi/bfa/bfi.h7
-rw-r--r--drivers/scsi/bfa/bfi_ms.h7
-rw-r--r--drivers/scsi/bfa/bfi_reg.h9
-rw-r--r--drivers/scsi/cxlflash/common.h2
-rw-r--r--drivers/scsi/cxlflash/main.c54
-rw-r--r--drivers/scsi/cxlflash/main.h5
-rw-r--r--drivers/scsi/cxlflash/superpipe.c8
-rw-r--r--drivers/scsi/cxlflash/vlun.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c294
-rw-r--r--drivers/scsi/hisi_sas/Kconfig6
-rw-r--r--drivers/scsi/hisi_sas/Makefile2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h341
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c1358
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c1839
-rw-r--r--drivers/scsi/hpsa.c117
-rw-r--r--drivers/scsi/hpsa.h2
-rw-r--r--drivers/scsi/hpsa_cmd.h13
-rw-r--r--drivers/scsi/initio.c16
-rw-r--r--drivers/scsi/lpfc/lpfc.h16
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c48
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c1864
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c484
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c65
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h184
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h52
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c198
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c41
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c23
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c8
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c4
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c134
-rw-r--r--drivers/scsi/mvsas/mv_94xx.h71
-rw-r--r--drivers/scsi/mvsas/mv_init.c2
-rw-r--r--drivers/scsi/mvsas/mv_sas.c17
-rw-r--r--drivers/scsi/mvsas/mv_sas.h5
-rw-r--r--drivers/scsi/osd/osd_initiator.c5
-rw-r--r--drivers/scsi/qla2xxx/Kconfig3
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c36
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h83
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c106
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h18
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c188
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c126
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c265
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c168
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c645
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h34
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c38
-rw-r--r--drivers/scsi/scsi.c20
-rw-r--r--drivers/scsi/scsi_debug.c14
-rw-r--r--drivers/scsi/scsi_dh.c72
-rw-r--r--drivers/scsi/scsi_lib.c188
-rw-r--r--drivers/scsi/scsi_priv.h3
-rw-r--r--drivers/scsi/scsi_scan.c4
-rw-r--r--drivers/scsi/scsi_sysfs.c90
-rw-r--r--drivers/scsi/scsi_transport_fc.c12
-rw-r--r--drivers/scsi/scsi_transport_sas.c30
-rw-r--r--drivers/scsi/ses.c22
-rw-r--r--drivers/scsi/st.h2
-rw-r--r--drivers/scsi/storvsc_drv.c309
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c2
-rw-r--r--drivers/scsi/vmw_pvscsi.c45
-rw-r--r--drivers/scsi/vmw_pvscsi.h2
-rw-r--r--drivers/sh/clk/core.c100
-rw-r--r--drivers/soc/Kconfig2
-rw-r--r--drivers/soc/Makefile3
-rw-r--r--drivers/soc/bcm/Kconfig9
-rw-r--r--drivers/soc/bcm/Makefile1
-rw-r--r--drivers/soc/bcm/raspberrypi-power.c247
-rw-r--r--drivers/soc/dove/pmu.c43
-rw-r--r--drivers/soc/fsl/Makefile6
-rw-r--r--drivers/soc/fsl/qe/Kconfig (renamed from arch/powerpc/sysdev/qe_lib/Kconfig)11
-rw-r--r--drivers/soc/fsl/qe/Makefile (renamed from arch/powerpc/sysdev/qe_lib/Makefile)4
-rw-r--r--drivers/soc/fsl/qe/gpio.c (renamed from arch/powerpc/sysdev/qe_lib/gpio.c)2
-rw-r--r--drivers/soc/fsl/qe/qe.c (renamed from arch/powerpc/sysdev/qe_lib/qe.c)17
-rw-r--r--drivers/soc/fsl/qe/qe_common.c235
-rw-r--r--drivers/soc/fsl/qe/qe_ic.c (renamed from arch/powerpc/sysdev/qe_lib/qe_ic.c)5
-rw-r--r--drivers/soc/fsl/qe/qe_ic.h (renamed from arch/powerpc/sysdev/qe_lib/qe_ic.h)4
-rw-r--r--drivers/soc/fsl/qe/qe_io.c (renamed from arch/powerpc/sysdev/qe_lib/qe_io.c)2
-rw-r--r--drivers/soc/fsl/qe/ucc.c (renamed from arch/powerpc/sysdev/qe_lib/ucc.c)6
-rw-r--r--drivers/soc/fsl/qe/ucc_fast.c (renamed from arch/powerpc/sysdev/qe_lib/ucc_fast.c)8
-rw-r--r--drivers/soc/fsl/qe/ucc_slow.c (renamed from arch/powerpc/sysdev/qe_lib/ucc_slow.c)8
-rw-r--r--drivers/soc/fsl/qe/usb.c (renamed from arch/powerpc/sysdev/qe_lib/usb.c)4
-rw-r--r--drivers/soc/mediatek/mtk-scpsys.c32
-rw-r--r--drivers/soc/qcom/Kconfig27
-rw-r--r--drivers/soc/qcom/Makefile4
-rw-r--r--drivers/soc/qcom/smd-rpm.c2
-rw-r--r--drivers/soc/qcom/smem_state.c201
-rw-r--r--drivers/soc/qcom/smp2p.c578
-rw-r--r--drivers/soc/qcom/smsm.c625
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c272
-rw-r--r--drivers/soc/ti/Kconfig10
-rw-r--r--drivers/soc/ti/Makefile1
-rw-r--r--drivers/soc/ti/knav_dma.c2
-rw-r--r--drivers/soc/ti/wkup_m3_ipc.c508
-rw-r--r--drivers/soc/versatile/soc-realview.c4
-rw-r--r--drivers/spi/Kconfig11
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-bcm63xx.c7
-rw-r--r--drivers/spi/spi-butterfly.c30
-rw-r--r--drivers/spi/spi-cadence.c6
-rw-r--r--drivers/spi/spi-davinci.c17
-rw-r--r--drivers/spi/spi-dw-mid.c2
-rw-r--r--drivers/spi/spi-dw.c2
-rw-r--r--drivers/spi/spi-dw.h2
-rw-r--r--drivers/spi/spi-fsl-cpm.c2
-rw-r--r--drivers/spi/spi-fsl-espi.c6
-rw-r--r--drivers/spi/spi-imx.c101
-rw-r--r--drivers/spi/spi-lm70llp.c43
-rw-r--r--drivers/spi/spi-loopback-test.c1005
-rw-r--r--drivers/spi/spi-mt65xx.c64
-rw-r--r--drivers/spi/spi-omap2-mcspi.c31
-rw-r--r--drivers/spi/spi-pxa2xx.c3
-rw-r--r--drivers/spi/spi-s3c64xx.c33
-rw-r--r--drivers/spi/spi-sun4i.c14
-rw-r--r--drivers/spi/spi-sun6i.c8
-rw-r--r--drivers/spi/spi-test.h136
-rw-r--r--drivers/spi/spi-zynqmp-gqspi.c8
-rw-r--r--drivers/spi/spi.c32
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/staging/android/TODO8
-rw-r--r--drivers/staging/android/ashmem.c15
-rw-r--r--drivers/staging/android/ion/Kconfig7
-rw-r--r--drivers/staging/android/ion/Makefile1
-rw-r--r--drivers/staging/android/ion/compat_ion.c6
-rw-r--r--drivers/staging/android/ion/hisilicon/Kconfig5
-rw-r--r--drivers/staging/android/ion/hisilicon/Makefile1
-rw-r--r--drivers/staging/android/ion/hisilicon/hi6220_ion.c223
-rw-r--r--drivers/staging/android/lowmemorykiller.c6
-rw-r--r--drivers/staging/android/sync.c41
-rw-r--r--drivers/staging/android/sync.h10
-rw-r--r--drivers/staging/android/sync_debug.c42
-rw-r--r--drivers/staging/android/timed_gpio.c11
-rw-r--r--drivers/staging/board/armadillo800eva.c2
-rw-r--r--drivers/staging/board/kzm9d.c2
-rw-r--r--drivers/staging/comedi/Kconfig24
-rw-r--r--drivers/staging/comedi/comedi.h307
-rw-r--r--drivers/staging/comedi/comedi_fops.c124
-rw-r--r--drivers/staging/comedi/comedilib.h32
-rw-r--r--drivers/staging/comedi/drivers/Makefile2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c3
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c542
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1720.c195
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1760.c432
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c1125
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c11
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c6
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c4
-rw-r--r--drivers/staging/comedi/drivers/das16.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c24
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c54
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c100
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h126
-rw-r--r--drivers/staging/comedi/drivers/s526.c197
-rw-r--r--drivers/staging/dgnc/dgnc_cls.c2
-rw-r--r--drivers/staging/dgnc/dgnc_neo.c10
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c2
-rw-r--r--drivers/staging/dgnc/dgnc_utils.c1
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c40
-rw-r--r--drivers/staging/fwserial/fwserial.c3
-rw-r--r--drivers/staging/fwserial/fwserial.h10
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c2
-rw-r--r--drivers/staging/gdm724x/gdm_tty.c2
-rw-r--r--drivers/staging/gdm724x/netlink_k.c5
-rw-r--r--drivers/staging/gdm724x/netlink_k.h1
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.c52
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c13
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.h4
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c21
-rw-r--r--drivers/staging/gdm72xx/wm_ioctl.h7
-rw-r--r--drivers/staging/iio/Kconfig29
-rw-r--r--drivers/staging/iio/Makefile7
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c2
-rw-r--r--drivers/staging/iio/adc/Kconfig4
-rw-r--r--drivers/staging/iio/adc/Makefile7
-rw-r--r--drivers/staging/iio/adc/ad7192.c2
-rw-r--r--drivers/staging/iio/adc/ad7280a.c2
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c4
-rw-r--r--drivers/staging/iio/adc/ad7780.c36
-rw-r--r--drivers/staging/iio/adc/ad7780.h30
-rw-r--r--drivers/staging/iio/adc/ad7816.c2
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c4
-rw-r--r--drivers/staging/iio/frequency/ad9832.c2
-rw-r--r--drivers/staging/iio/frequency/ad9834.c2
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs.h9
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h3
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h156
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_private.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/api.h6
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-lnet.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/nidstr.h2
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c4
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h2
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c2
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c13
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h3
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c21
-rw-r--r--drivers/staging/lustre/lnet/lnet/config.c26
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c18
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-move.c3
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-socket.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/module.c4
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/brw_test.c6
-rw-r--r--drivers/staging/lustre/lnet/selftest/conctl.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c88
-rw-r--r--drivers/staging/lustre/lnet/selftest/framework.c8
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c25
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h16
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c25
-rw-r--r--drivers/staging/lustre/lustre/fid/lproc_fid.c2
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c35
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h11
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c4
-rw-r--r--drivers/staging/lustre/lustre/fld/lproc_fld.c2
-rw-r--r--drivers/staging/lustre/lustre/include/cl_object.h3
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lu_object.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_user.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_disk.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_eacl.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_export.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fld.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_ha.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_log.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mds.h6
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_param.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_req_layout.h2
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h324
-rw-r--r--drivers/staging/lustre/lustre/include/obd_cksum.h23
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h18
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h2
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c6
-rw-r--r--drivers/staging/lustre/lustre/ldlm/interval_tree.c16
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_extent.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_pool.c49
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c23
-rw-r--r--drivers/staging/lustre/lustre/libcfs/fail.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/hash.c383
-rw-r--r--drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_mem.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_string.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c33
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-crypto-adler.c9
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c1
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.h48
-rw-r--r--drivers/staging/lustre/lustre/libcfs/module.c8
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c27
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.h29
-rw-r--r--drivers/staging/lustre/lustre/libcfs/workitem.c58
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c13
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h12
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/lproc_llite.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/rw.c14
-rw-r--r--drivers/staging/lustre/lustre/llite/rw26.c5
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c78
-rw-r--r--drivers/staging/lustre/lustre/llite/super25.c5
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_dev.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_object.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_page.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c7
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr_cache.c2
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_intent.c23
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_internal.h16
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c96
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_cl_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_dev.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_internal.h17
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_merge.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_obd.c62
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_offset.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c17
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_page.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pool.c3
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c18
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_dev.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_object.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lproc_lov.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/lproc_mdc.c79
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_internal.h17
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_reint.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c141
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c36
-rw-r--r--drivers/staging/lustre/lustre/obdclass/acl.c9
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c28
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_lock.c3
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c5
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_page.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/class_obd.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c8
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_cat.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_obd.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_swab.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c23
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c12
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c18
-rw-r--r--drivers/staging/lustre/lustre/osc/lproc_osc.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c12
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cl_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_dev.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_internal.h8
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_io.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_object.c6
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_quota.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_request.c73
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/llog_client.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pers.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pinger.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c3
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/recover.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c5
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_plain.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/wiretest.c2
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c393
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c11
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c17
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c17
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c39
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c10
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c58
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h1
-rw-r--r--drivers/staging/media/omap4iss/iss.c199
-rw-r--r--drivers/staging/media/omap4iss/iss.h8
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c48
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.h1
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c11
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c44
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.h1
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c42
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.h1
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c61
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h5
-rw-r--r--drivers/staging/most/aim-network/networking.h2
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_errors.h2
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hal.c133
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hal.h53
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hdm.c60
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_reg.h5
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_sysfs.h3
-rw-r--r--drivers/staging/most/mostcore/core.c3
-rw-r--r--drivers/staging/most/mostcore/mostcore.h2
-rw-r--r--drivers/staging/mt29f_spinand/mt29f_spinand.c24
-rw-r--r--drivers/staging/nvec/README2
-rw-r--r--drivers/staging/nvec/nvec.c20
-rw-r--r--drivers/staging/octeon/ethernet-defines.h2
-rw-r--r--drivers/staging/rdma/amso1100/c2.c17
-rw-r--r--drivers/staging/rdma/amso1100/c2.h80
-rw-r--r--drivers/staging/rdma/amso1100/c2_mq.h14
-rw-r--r--drivers/staging/rdma/amso1100/c2_provider.c10
-rw-r--r--drivers/staging/rdma/amso1100/c2_rnic.c5
-rw-r--r--drivers/staging/rdma/amso1100/c2_vq.h20
-rw-r--r--drivers/staging/rdma/ehca/ehca_av.c6
-rw-r--r--drivers/staging/rdma/ehca/ehca_cq.c3
-rw-r--r--drivers/staging/rdma/ehca/ehca_main.c3
-rw-r--r--drivers/staging/rdma/ehca/ehca_mrmw.c6
-rw-r--r--drivers/staging/rdma/ehca/ehca_pd.c3
-rw-r--r--drivers/staging/rdma/ehca/ehca_qp.c3
-rw-r--r--drivers/staging/rdma/hfi1/Makefile2
-rw-r--r--drivers/staging/rdma/hfi1/chip.c3550
-rw-r--r--drivers/staging/rdma/hfi1/chip.h273
-rw-r--r--drivers/staging/rdma/hfi1/chip_registers.h4
-rw-r--r--drivers/staging/rdma/hfi1/common.h15
-rw-r--r--drivers/staging/rdma/hfi1/diag.c499
-rw-r--r--drivers/staging/rdma/hfi1/driver.c215
-rw-r--r--drivers/staging/rdma/hfi1/efivar.c169
-rw-r--r--drivers/staging/rdma/hfi1/efivar.h60
-rw-r--r--drivers/staging/rdma/hfi1/eprom.c119
-rw-r--r--drivers/staging/rdma/hfi1/file_ops.c207
-rw-r--r--drivers/staging/rdma/hfi1/firmware.c193
-rw-r--r--drivers/staging/rdma/hfi1/hfi.h104
-rw-r--r--drivers/staging/rdma/hfi1/init.c101
-rw-r--r--drivers/staging/rdma/hfi1/iowait.h6
-rw-r--r--drivers/staging/rdma/hfi1/mad.c227
-rw-r--r--drivers/staging/rdma/hfi1/mad.h114
-rw-r--r--drivers/staging/rdma/hfi1/pcie.c36
-rw-r--r--drivers/staging/rdma/hfi1/pio.c68
-rw-r--r--drivers/staging/rdma/hfi1/pio.h2
-rw-r--r--drivers/staging/rdma/hfi1/pio_copy.c6
-rw-r--r--drivers/staging/rdma/hfi1/qp.c48
-rw-r--r--drivers/staging/rdma/hfi1/qp.h46
-rw-r--r--drivers/staging/rdma/hfi1/qsfp.c5
-rw-r--r--drivers/staging/rdma/hfi1/rc.c81
-rw-r--r--drivers/staging/rdma/hfi1/ruc.c55
-rw-r--r--drivers/staging/rdma/hfi1/sdma.c67
-rw-r--r--drivers/staging/rdma/hfi1/sdma.h15
-rw-r--r--drivers/staging/rdma/hfi1/trace.c29
-rw-r--r--drivers/staging/rdma/hfi1/trace.h3
-rw-r--r--drivers/staging/rdma/hfi1/uc.c15
-rw-r--r--drivers/staging/rdma/hfi1/ud.c22
-rw-r--r--drivers/staging/rdma/hfi1/user_exp_rcv.h74
-rw-r--r--drivers/staging/rdma/hfi1/user_pages.c97
-rw-r--r--drivers/staging/rdma/hfi1/user_sdma.c363
-rw-r--r--drivers/staging/rdma/hfi1/user_sdma.h12
-rw-r--r--drivers/staging/rdma/hfi1/verbs.c130
-rw-r--r--drivers/staging/rdma/hfi1/verbs.h50
-rw-r--r--drivers/staging/rdma/ipath/ipath_file_ops.c8
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c54
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c100
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c7
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c22
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c84
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_pwrctrl.c14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c11
-rw-r--r--drivers/staging/rtl8188eu/hal/fw.c40
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_com.c14
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c7
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c34
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c10
-rw-r--r--drivers/staging/rtl8188eu/include/HalVerDef.h33
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_xmit.h1
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c10
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c6
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c5
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c15
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c25
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c8
-rw-r--r--drivers/staging/rtl8723au/core/rtw_efuse.c45
-rw-r--r--drivers/staging/sm750fb/modedb.h233
-rw-r--r--drivers/staging/sm750fb/sm750.c2
-rw-r--r--drivers/staging/unisys/include/channel.h114
-rw-r--r--drivers/staging/unisys/include/iochannel.h157
-rw-r--r--drivers/staging/unisys/include/vbushelper.h3
-rw-r--r--drivers/staging/unisys/include/visorbus.h4
-rw-r--r--drivers/staging/unisys/visorbus/Kconfig7
-rw-r--r--drivers/staging/unisys/visorbus/controlvmcompletionstatus.h24
-rw-r--r--drivers/staging/unisys/visorbus/periodic_work.c11
-rw-r--r--drivers/staging/unisys/visorbus/vbuschannel.h9
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_main.c15
-rw-r--r--drivers/staging/unisys/visorbus/visorchannel.c4
-rw-r--r--drivers/staging/unisys/visorbus/vmcallinterface.h34
-rw-r--r--drivers/staging/unisys/visorhba/visorhba_main.c16
-rw-r--r--drivers/staging/unisys/visorinput/Kconfig7
-rw-r--r--drivers/staging/unisys/visorinput/visorinput.c4
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c1
-rw-r--r--drivers/staging/vme/devices/vme_pio2_cntr.c2
-rw-r--r--drivers/staging/vme/devices/vme_pio2_core.c22
-rw-r--r--drivers/staging/vme/devices/vme_pio2_gpio.c32
-rw-r--r--drivers/staging/vme/devices/vme_user.c22
-rw-r--r--drivers/staging/vme/devices/vme_user.h2
-rw-r--r--drivers/staging/vt6656/baseband.c4
-rw-r--r--drivers/staging/vt6656/baseband.h4
-rw-r--r--drivers/staging/vt6656/card.c3
-rw-r--r--drivers/staging/vt6656/card.h3
-rw-r--r--drivers/staging/vt6656/channel.c4
-rw-r--r--drivers/staging/vt6656/channel.h4
-rw-r--r--drivers/staging/vt6656/desc.h3
-rw-r--r--drivers/staging/vt6656/device.h3
-rw-r--r--drivers/staging/vt6656/dpc.c3
-rw-r--r--drivers/staging/vt6656/dpc.h3
-rw-r--r--drivers/staging/vt6656/firmware.c4
-rw-r--r--drivers/staging/vt6656/firmware.h4
-rw-r--r--drivers/staging/vt6656/int.c4
-rw-r--r--drivers/staging/vt6656/int.h4
-rw-r--r--drivers/staging/vt6656/key.c5
-rw-r--r--drivers/staging/vt6656/key.h4
-rw-r--r--drivers/staging/vt6656/mac.c4
-rw-r--r--drivers/staging/vt6656/mac.h4
-rw-r--r--drivers/staging/vt6656/main_usb.c3
-rw-r--r--drivers/staging/vt6656/power.c4
-rw-r--r--drivers/staging/vt6656/power.h3
-rw-r--r--drivers/staging/vt6656/rf.c4
-rw-r--r--drivers/staging/vt6656/rf.h4
-rw-r--r--drivers/staging/vt6656/rxtx.c3
-rw-r--r--drivers/staging/vt6656/rxtx.h3
-rw-r--r--drivers/staging/vt6656/usbpipe.c4
-rw-r--r--drivers/staging/vt6656/usbpipe.h4
-rw-r--r--drivers/staging/vt6656/wcmd.c3
-rw-r--r--drivers/staging/vt6656/wcmd.h3
-rw-r--r--drivers/staging/wilc1000/Kconfig46
-rw-r--r--drivers/staging/wilc1000/Makefile22
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.c34
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.h24
-rw-r--r--drivers/staging/wilc1000/host_interface.c2360
-rw-r--r--drivers/staging/wilc1000/host_interface.h1034
-rw-r--r--drivers/staging/wilc1000/linux_mon.c13
-rw-r--r--drivers/staging/wilc1000/linux_wlan.c1252
-rw-r--r--drivers/staging/wilc1000/linux_wlan_common.h24
-rw-r--r--drivers/staging/wilc1000/linux_wlan_sdio.c251
-rw-r--r--drivers/staging/wilc1000/linux_wlan_sdio.h14
-rw-r--r--drivers/staging/wilc1000/linux_wlan_spi.c409
-rw-r--r--drivers/staging/wilc1000/linux_wlan_spi.h14
-rw-r--r--drivers/staging/wilc1000/wilc_debugfs.c26
-rw-r--r--drivers/staging/wilc1000/wilc_msgqueue.c9
-rw-r--r--drivers/staging/wilc1000/wilc_msgqueue.h12
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c717
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c714
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c2061
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.h87
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h80
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c1542
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h384
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c25
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.h4
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h38
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c34
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h1
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.h1
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c5
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c21
-rw-r--r--drivers/target/iscsi/iscsi_target.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c17
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c10
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.h2
-rw-r--r--drivers/target/loopback/tcm_loop.c14
-rw-r--r--drivers/target/sbp/sbp_target.c2
-rw-r--r--drivers/target/target_core_configfs.c47
-rw-r--r--drivers/target/target_core_device.c2
-rw-r--r--drivers/target/target_core_iblock.c2
-rw-r--r--drivers/target/target_core_pr.c11
-rw-r--r--drivers/target/target_core_sbc.c10
-rw-r--r--drivers/target/target_core_spc.c12
-rw-r--r--drivers/target/target_core_tmr.c2
-rw-r--r--drivers/target/target_core_tpg.c197
-rw-r--r--drivers/target/target_core_transport.c33
-rw-r--r--drivers/target/target_core_user.c9
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h1
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c47
-rw-r--r--drivers/target/tcm_fc/tfc_io.c8
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c42
-rw-r--r--drivers/tty/amiserial.c1
-rw-r--r--drivers/tty/cyclades.c8
-rw-r--r--drivers/tty/isicom.c4
-rw-r--r--drivers/tty/moxa.c1
-rw-r--r--drivers/tty/n_tty.c55
-rw-r--r--drivers/tty/pty.c2
-rw-r--r--drivers/tty/serial/68328serial.c130
-rw-r--r--drivers/tty/serial/8250/8250_core.c7
-rw-r--r--drivers/tty/serial/8250/8250_early.c29
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c2
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c35
-rw-r--r--drivers/tty/serial/8250/8250_of.c (renamed from drivers/tty/serial/of_serial.c)38
-rw-r--r--drivers/tty/serial/8250/8250_port.c20
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c24
-rw-r--r--drivers/tty/serial/8250/Kconfig14
-rw-r--r--drivers/tty/serial/8250/Makefile1
-rw-r--r--drivers/tty/serial/Kconfig35
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/amba-pl011.c341
-rw-r--r--drivers/tty/serial/amba-pl011.h34
-rw-r--r--drivers/tty/serial/atmel_serial.c187
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c2
-rw-r--r--drivers/tty/serial/bfin_uart.c27
-rw-r--r--drivers/tty/serial/earlycon.c15
-rw-r--r--drivers/tty/serial/icom.c1
-rw-r--r--drivers/tty/serial/imx.c189
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c4
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c2
-rw-r--r--drivers/tty/serial/m32r_sio.c2
-rw-r--r--drivers/tty/serial/max310x.c2
-rw-r--r--drivers/tty/serial/men_z135_uart.c2
-rw-r--r--drivers/tty/serial/meson_uart.c80
-rw-r--r--drivers/tty/serial/nwpserial.c477
-rw-r--r--drivers/tty/serial/omap-serial.c2
-rw-r--r--drivers/tty/serial/pxa.c2
-rw-r--r--drivers/tty/serial/sc16is7xx.c15
-rw-r--r--drivers/tty/serial/serial_core.c11
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c2
-rw-r--r--drivers/tty/serial/sh-sci.c589
-rw-r--r--drivers/tty/serial/sh-sci.h10
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/tty/serial/sunsu.c2
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/serial/vt8500_serial.c2
-rw-r--r--drivers/tty/synclink_gt.c4
-rw-r--r--drivers/tty/tty_io.c88
-rw-r--r--drivers/tty/tty_ioctl.c21
-rw-r--r--drivers/tty/tty_ldisc.c51
-rw-r--r--drivers/tty/tty_ldsem.c4
-rw-r--r--drivers/tty/tty_mutex.c10
-rw-r--r--drivers/tty/tty_port.c9
-rw-r--r--drivers/tty/vt/vt.c2
-rw-r--r--drivers/usb/chipidea/Kconfig5
-rw-r--r--drivers/usb/chipidea/Makefile5
-rw-r--r--drivers/usb/chipidea/ci.h3
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c6
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c3
-rw-r--r--drivers/usb/chipidea/core.c59
-rw-r--r--drivers/usb/chipidea/debug.c1
-rw-r--r--drivers/usb/chipidea/debug.h30
-rw-r--r--drivers/usb/chipidea/host.c2
-rw-r--r--drivers/usb/chipidea/otg_fsm.c26
-rw-r--r--drivers/usb/chipidea/otg_fsm.h2
-rw-r--r--drivers/usb/chipidea/udc.c31
-rw-r--r--drivers/usb/common/common.c60
-rw-r--r--drivers/usb/core/devio.c25
-rw-r--r--drivers/usb/core/hcd.c4
-rw-r--r--drivers/usb/core/hub.c68
-rw-r--r--drivers/usb/core/hub.h5
-rw-r--r--drivers/usb/core/port.c89
-rw-r--r--drivers/usb/core/sysfs.c31
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/usb/dwc2/core.c429
-rw-r--r--drivers/usb/dwc2/core.h66
-rw-r--r--drivers/usb/dwc2/core_intr.c53
-rw-r--r--drivers/usb/dwc2/gadget.c109
-rw-r--r--drivers/usb/dwc2/hcd.c128
-rw-r--r--drivers/usb/dwc2/hcd.h31
-rw-r--r--drivers/usb/dwc2/hcd_ddma.c240
-rw-r--r--drivers/usb/dwc2/hcd_intr.c39
-rw-r--r--drivers/usb/dwc2/hcd_queue.c2
-rw-r--r--drivers/usb/dwc2/hw.h4
-rw-r--r--drivers/usb/dwc2/platform.c158
-rw-r--r--drivers/usb/dwc3/Kconfig17
-rw-r--r--drivers/usb/dwc3/Makefile2
-rw-r--r--drivers/usb/dwc3/core.c8
-rw-r--r--drivers/usb/dwc3/core.h3
-rw-r--r--drivers/usb/dwc3/dwc3-of-simple.c180
-rw-r--r--drivers/usb/dwc3/dwc3-qcom.c130
-rw-r--r--drivers/usb/dwc3/ep0.c12
-rw-r--r--drivers/usb/dwc3/gadget.c133
-rw-r--r--drivers/usb/dwc3/trace.h11
-rw-r--r--drivers/usb/gadget/Kconfig23
-rw-r--r--drivers/usb/gadget/configfs.c29
-rw-r--r--drivers/usb/gadget/function/Makefile2
-rw-r--r--drivers/usb/gadget/function/f_midi.c192
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c149
-rw-r--r--drivers/usb/gadget/function/f_tcm.c2381
-rw-r--r--drivers/usb/gadget/function/g_zero.h7
-rw-r--r--drivers/usb/gadget/function/tcm.h (renamed from drivers/usb/gadget/legacy/tcm_usb_gadget.h)9
-rw-r--r--drivers/usb/gadget/function/u_ether.c18
-rw-r--r--drivers/usb/gadget/function/u_serial.c258
-rw-r--r--drivers/usb/gadget/function/u_tcm.h50
-rw-r--r--drivers/usb/gadget/legacy/Kconfig1
-rw-r--r--drivers/usb/gadget/legacy/acm_ms.c2
-rw-r--r--drivers/usb/gadget/legacy/audio.c2
-rw-r--r--drivers/usb/gadget/legacy/cdc2.c2
-rw-r--r--drivers/usb/gadget/legacy/ether.c2
-rw-r--r--drivers/usb/gadget/legacy/g_ffs.c2
-rw-r--r--drivers/usb/gadget/legacy/gmidi.c12
-rw-r--r--drivers/usb/gadget/legacy/hid.c2
-rw-r--r--drivers/usb/gadget/legacy/inode.c3
-rw-r--r--drivers/usb/gadget/legacy/mass_storage.c2
-rw-r--r--drivers/usb/gadget/legacy/multi.c2
-rw-r--r--drivers/usb/gadget/legacy/ncm.c2
-rw-r--r--drivers/usb/gadget/legacy/nokia.c2
-rw-r--r--drivers/usb/gadget/legacy/printer.c2
-rw-r--r--drivers/usb/gadget/legacy/serial.c2
-rw-r--r--drivers/usb/gadget/legacy/tcm_usb_gadget.c2167
-rw-r--r--drivers/usb/gadget/legacy/webcam.c2
-rw-r--r--drivers/usb/gadget/legacy/zero.c14
-rw-r--r--drivers/usb/gadget/u_f.c1
-rw-r--r--drivers/usb/gadget/u_f.h10
-rw-r--r--drivers/usb/gadget/udc/Kconfig11
-rw-r--r--drivers/usb/gadget/udc/Makefile1
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c7
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c3
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c35
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c1975
-rw-r--r--drivers/usb/gadget/udc/s3c-hsudc.c2
-rw-r--r--drivers/usb/gadget/udc/udc-core.c79
-rw-r--r--drivers/usb/host/Kconfig9
-rw-r--r--drivers/usb/host/Makefile4
-rw-r--r--drivers/usb/host/bcma-hcd.c21
-rw-r--r--drivers/usb/host/ehci-dbg.c15
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-mem.c18
-rw-r--r--drivers/usb/host/ehci-msm.c4
-rw-r--r--drivers/usb/host/ehci-q.c9
-rw-r--r--drivers/usb/host/ehci.h1
-rw-r--r--drivers/usb/host/fhci-hcd.c2
-rw-r--r--drivers/usb/host/fhci-hub.c2
-rw-r--r--drivers/usb/host/fhci-sched.c2
-rw-r--r--drivers/usb/host/fhci-tds.c2
-rw-r--r--drivers/usb/host/fhci.h4
-rw-r--r--drivers/usb/host/ohci-hcd.c4
-rw-r--r--drivers/usb/host/ohci-pxa27x.c14
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c8
-rw-r--r--drivers/usb/host/pci-quirks.c25
-rw-r--r--drivers/usb/host/u132-hcd.c2
-rw-r--r--drivers/usb/host/uhci-q.c3
-rw-r--r--drivers/usb/host/whci/qset.c5
-rw-r--r--drivers/usb/host/xhci-ext-caps.h83
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-mem.c81
-rw-r--r--drivers/usb/host/xhci-mtk-sch.c415
-rw-r--r--drivers/usb/host/xhci-mtk.c763
-rw-r--r--drivers/usb/host/xhci-mtk.h162
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-plat.c88
-rw-r--r--drivers/usb/host/xhci-plat.h39
-rw-r--r--drivers/usb/host/xhci-rcar.c44
-rw-r--r--drivers/usb/host/xhci-rcar.h3
-rw-r--r--drivers/usb/host/xhci-ring.c16
-rw-r--r--drivers/usb/host/xhci.c25
-rw-r--r--drivers/usb/host/xhci.h4
-rw-r--r--drivers/usb/misc/usbtest.c233
-rw-r--r--drivers/usb/mon/mon_bin.c17
-rw-r--r--drivers/usb/mon/mon_main.c2
-rw-r--r--drivers/usb/mon/mon_text.c15
-rw-r--r--drivers/usb/musb/musb_core.c48
-rw-r--r--drivers/usb/musb/musb_core.h2
-rw-r--r--drivers/usb/musb/musb_gadget.c5
-rw-r--r--drivers/usb/musb/omap2430.c30
-rw-r--r--drivers/usb/phy/Kconfig14
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/phy-am335x-control.c16
-rw-r--r--drivers/usb/phy/phy-am335x-control.h (renamed from drivers/usb/phy/am35x-phy-control.h)8
-rw-r--r--drivers/usb/phy/phy-am335x.c17
-rw-r--r--drivers/usb/phy/phy-rcar-usb.c247
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c30
-rw-r--r--drivers/usb/renesas_usbhs/common.c78
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c19
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c11
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c112
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h1
-rw-r--r--drivers/usb/serial/Kconfig16
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/cp210x.c187
-rw-r--r--drivers/usb/serial/io_edgeport.c35
-rw-r--r--drivers/usb/serial/mos7840.c2
-rw-r--r--drivers/usb/serial/mxu11x0.c986
-rw-r--r--drivers/usb/storage/uas.c48
-rw-r--r--drivers/uwb/uwbd.c1
-rw-r--r--drivers/vfio/Kconfig15
-rw-r--r--drivers/vfio/pci/vfio_pci.c8
-rw-r--r--drivers/vfio/platform/reset/vfio_platform_amdxgbe.c2
-rw-r--r--drivers/vfio/vfio.c184
-rw-r--r--drivers/vfio/vfio_iommu_type1.c2
-rw-r--r--drivers/video/backlight/adp8860_bl.c18
-rw-r--r--drivers/video/backlight/adp8870_bl.c10
-rw-r--r--drivers/video/backlight/gpio_backlight.c10
-rw-r--r--drivers/video/backlight/pwm_bl.c28
-rw-r--r--drivers/video/backlight/tps65217_bl.c9
-rw-r--r--drivers/video/fbdev/Kconfig17
-rw-r--r--drivers/video/fbdev/Makefile1
-rw-r--r--drivers/video/fbdev/auo_k190x.c11
-rw-r--r--drivers/video/fbdev/core/Makefile2
-rw-r--r--drivers/video/fbdev/core/fbmem.c14
-rw-r--r--drivers/video/fbdev/geode/display_gx1.c2
-rw-r--r--drivers/video/fbdev/geode/display_gx1.h2
-rw-r--r--drivers/video/fbdev/geode/geodefb.h4
-rw-r--r--drivers/video/fbdev/geode/video_cs5530.c2
-rw-r--r--drivers/video/fbdev/geode/video_cs5530.h2
-rw-r--r--drivers/video/fbdev/i740fb.c8
-rw-r--r--drivers/video/fbdev/omap2/Kconfig5
-rw-r--r--drivers/video/fbdev/omap2/Makefile6
-rw-r--r--drivers/video/fbdev/omap2/omapfb/Kconfig14
-rw-r--r--drivers/video/fbdev/omap2/omapfb/Makefile3
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/Kconfig86
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/Makefile14
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c320
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c398
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c348
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c278
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c320
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c328
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c328
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c1388
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c404
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c437
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c415
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c917
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c511
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c686
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/Kconfig129
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/Makefile18
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/apply.c1702
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/core.c343
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c667
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h30
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc.c4234
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc.h918
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c325
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c356
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/display.c338
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dpi.c899
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dsi.c5607
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss-of.c183
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss.c1329
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss.h468
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss_features.c951
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss_features.h108
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi.h370
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c839
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c904
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h273
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c876
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c916
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h304
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_common.c148
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c247
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c255
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c282
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c531
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/manager.c263
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c225
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/output.c267
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c456
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/overlay.c202
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/pll.c389
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/rfbi.c1078
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/sdi.c454
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/venc.c997
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/video-pll.c211
-rw-r--r--drivers/video/fbdev/omap2/omapfb/vrfb.c (renamed from drivers/video/fbdev/omap2/vrfb.c)0
-rw-r--r--drivers/video/fbdev/pxafb.c210
-rw-r--r--drivers/video/fbdev/pxafb.h2
-rw-r--r--drivers/video/fbdev/riva/fbdev.c1
-rw-r--r--drivers/video/fbdev/sh_mobile_hdmi.c1489
-rw-r--r--drivers/video/fbdev/simplefb.c120
-rw-r--r--drivers/video/fbdev/sm712fb.c16
-rw-r--r--drivers/video/fbdev/via/via-gpio.c19
-rw-r--r--drivers/virtio/virtio_balloon.c4
-rw-r--r--drivers/virtio/virtio_input.c2
-rw-r--r--drivers/virtio/virtio_mmio.c2
-rw-r--r--drivers/virtio/virtio_pci_common.c4
-rw-r--r--drivers/virtio/virtio_pci_common.h2
-rw-r--r--drivers/virtio/virtio_pci_modern.c2
-rw-r--r--drivers/virtio/virtio_ring.c15
-rw-r--r--drivers/watchdog/Kconfig65
-rw-r--r--drivers/watchdog/Makefile6
-rw-r--r--drivers/watchdog/asm9260_wdt.c403
-rw-r--r--drivers/watchdog/atlas7_wdt.c242
-rw-r--r--drivers/watchdog/bcm2835_wdt.c1
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c55
-rw-r--r--drivers/watchdog/cadence_wdt.c42
-rw-r--r--drivers/watchdog/da9052_wdt.c24
-rw-r--r--drivers/watchdog/da9055_wdt.c24
-rw-r--r--drivers/watchdog/da9063_wdt.c23
-rw-r--r--drivers/watchdog/diag288_wdt.c26
-rw-r--r--drivers/watchdog/digicolor_wdt.c18
-rw-r--r--drivers/watchdog/dw_wdt.c2
-rw-r--r--drivers/watchdog/gpio_wdt.c38
-rw-r--r--drivers/watchdog/hpwdt.c12
-rw-r--r--drivers/watchdog/imgpdc_wdt.c34
-rw-r--r--drivers/watchdog/imx2_wdt.c23
-rw-r--r--drivers/watchdog/lpc18xx_wdt.c52
-rw-r--r--drivers/watchdog/mena21_wdt.c4
-rw-r--r--drivers/watchdog/meson_wdt.c88
-rw-r--r--drivers/watchdog/moxart_wdt.c23
-rw-r--r--drivers/watchdog/mt7621_wdt.c186
-rw-r--r--drivers/watchdog/mtk_wdt.c22
-rw-r--r--drivers/watchdog/omap_wdt.c7
-rw-r--r--drivers/watchdog/qcom-wdt.c50
-rw-r--r--drivers/watchdog/s3c2410_wdt.c60
-rw-r--r--drivers/watchdog/softdog.c38
-rw-r--r--drivers/watchdog/sp5100_tco.c32
-rw-r--r--drivers/watchdog/stmp3xxx_rtc_wdt.c25
-rw-r--r--drivers/watchdog/sunxi_wdt.c23
-rw-r--r--drivers/watchdog/tangox_wdt.c225
-rw-r--r--drivers/watchdog/ts4800_wdt.c215
-rw-r--r--drivers/watchdog/w83627hf_wdt.c32
-rw-r--r--drivers/watchdog/watchdog_core.c115
-rw-r--r--drivers/watchdog/watchdog_core.h2
-rw-r--r--drivers/watchdog/watchdog_dev.c572
-rw-r--r--drivers/watchdog/ziirave_wdt.c367
-rw-r--r--drivers/xen/events/events_fifo.c3
-rw-r--r--drivers/xen/xenbus/xenbus_comms.c8
-rw-r--r--fs/9p/v9fs.c2
-rw-r--r--fs/Kconfig3
-rw-r--r--fs/adfs/super.c2
-rw-r--r--fs/affs/super.c2
-rw-r--r--fs/afs/super.c2
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/bfs/inode.c2
-rw-r--r--fs/block_dev.c149
-rw-r--r--fs/btrfs/Makefile5
-rw-r--r--fs/btrfs/acl.c4
-rw-r--r--fs/btrfs/async-thread.c4
-rw-r--r--fs/btrfs/backref.c23
-rw-r--r--fs/btrfs/btrfs_inode.h4
-rw-r--r--fs/btrfs/check-integrity.c105
-rw-r--r--fs/btrfs/ctree.c11
-rw-r--r--fs/btrfs/ctree.h178
-rw-r--r--fs/btrfs/delayed-inode.c7
-rw-r--r--fs/btrfs/delayed-ref.c4
-rw-r--r--fs/btrfs/delayed-ref.h8
-rw-r--r--fs/btrfs/disk-io.c49
-rw-r--r--fs/btrfs/disk-io.h5
-rw-r--r--fs/btrfs/extent-tree.c200
-rw-r--r--fs/btrfs/extent-tree.h0
-rw-r--r--fs/btrfs/extent_io.c310
-rw-r--r--fs/btrfs/extent_io.h136
-rw-r--r--fs/btrfs/file-item.c4
-rw-r--r--fs/btrfs/file.c8
-rw-r--r--fs/btrfs/free-space-cache.c28
-rw-r--r--fs/btrfs/free-space-cache.h2
-rw-r--r--fs/btrfs/free-space-tree.c1591
-rw-r--r--fs/btrfs/free-space-tree.h72
-rw-r--r--fs/btrfs/inode-map.c8
-rw-r--r--fs/btrfs/inode.c315
-rw-r--r--fs/btrfs/ioctl.c74
-rw-r--r--fs/btrfs/locking.c2
-rw-r--r--fs/btrfs/raid56.c2
-rw-r--r--fs/btrfs/relocation.c12
-rw-r--r--fs/btrfs/scrub.c16
-rw-r--r--fs/btrfs/send.c16
-rw-r--r--fs/btrfs/send.h4
-rw-r--r--fs/btrfs/super.c84
-rw-r--r--fs/btrfs/tests/btrfs-tests.c58
-rw-r--r--fs/btrfs/tests/btrfs-tests.h10
-rw-r--r--fs/btrfs/tests/extent-io-tests.c149
-rw-r--r--fs/btrfs/tests/free-space-tests.c239
-rw-r--r--fs/btrfs/tests/free-space-tree-tests.c571
-rw-r--r--fs/btrfs/tests/inode-tests.c2
-rw-r--r--fs/btrfs/tests/qgroup-tests.c20
-rw-r--r--fs/btrfs/transaction.c50
-rw-r--r--fs/btrfs/transaction.h2
-rw-r--r--fs/btrfs/tree-defrag.c27
-rw-r--r--fs/btrfs/volumes.c93
-rw-r--r--fs/btrfs/volumes.h3
-rw-r--r--fs/btrfs/xattr.c4
-rw-r--r--fs/ceph/super.c4
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/cifs/file.c8
-rw-r--r--fs/coda/inode.c6
-rw-r--r--fs/configfs/dir.c150
-rw-r--r--fs/dax.c301
-rw-r--r--fs/dcache.c5
-rw-r--r--fs/ecryptfs/main.c6
-rw-r--r--fs/efs/super.c6
-rw-r--r--fs/eventfd.c4
-rw-r--r--fs/exofs/super.c4
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext4/super.c2
-rw-r--r--fs/f2fs/checkpoint.c177
-rw-r--r--fs/f2fs/data.c377
-rw-r--r--fs/f2fs/debug.c29
-rw-r--r--fs/f2fs/dir.c38
-rw-r--r--fs/f2fs/extent_cache.c122
-rw-r--r--fs/f2fs/f2fs.h142
-rw-r--r--fs/f2fs/file.c344
-rw-r--r--fs/f2fs/gc.c9
-rw-r--r--fs/f2fs/gc.h8
-rw-r--r--fs/f2fs/inline.c9
-rw-r--r--fs/f2fs/inode.c28
-rw-r--r--fs/f2fs/namei.c59
-rw-r--r--fs/f2fs/node.c170
-rw-r--r--fs/f2fs/node.h6
-rw-r--r--fs/f2fs/recovery.c40
-rw-r--r--fs/f2fs/segment.c122
-rw-r--r--fs/f2fs/shrinker.c3
-rw-r--r--fs/f2fs/super.c258
-rw-r--r--fs/f2fs/xattr.c3
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/file.c7
-rw-r--r--fs/fs-writeback.c2
-rw-r--r--fs/fuse/inode.c4
-rw-r--r--fs/gfs2/glops.c2
-rw-r--r--fs/gfs2/main.c3
-rw-r--r--fs/hfs/super.c4
-rw-r--r--fs/hfsplus/super.c2
-rw-r--r--fs/hostfs/hostfs_kern.c2
-rw-r--r--fs/hpfs/super.c2
-rw-r--r--fs/hugetlbfs/inode.c174
-rw-r--r--fs/inode.c2
-rw-r--r--fs/isofs/inode.c2
-rw-r--r--fs/jffs2/super.c2
-rw-r--r--fs/jffs2/wbuf.c2
-rw-r--r--fs/jfs/super.c2
-rw-r--r--fs/kernfs/dir.c9
-rw-r--r--fs/lockd/svc.c79
-rw-r--r--fs/logfs/Kconfig2
-rw-r--r--fs/logfs/inode.c3
-rw-r--r--fs/logfs/logfs.h2
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/nfs/callback_proc.c52
-rw-r--r--fs/nfs/dir.c26
-rw-r--r--fs/nfs/direct.c48
-rw-r--r--fs/nfs/file.c6
-rw-r--r--fs/nfs/filelayout/filelayout.c18
-rw-r--r--fs/nfs/flexfilelayout/flexfilelayout.c205
-rw-r--r--fs/nfs/flexfilelayout/flexfilelayout.h1
-rw-r--r--fs/nfs/flexfilelayout/flexfilelayoutdev.c16
-rw-r--r--fs/nfs/inode.c80
-rw-r--r--fs/nfs/internal.h39
-rw-r--r--fs/nfs/nfs42proc.c29
-rw-r--r--fs/nfs/nfs4proc.c71
-rw-r--r--fs/nfs/nfs4sysctl.c2
-rw-r--r--fs/nfs/nfs4trace.c1
-rw-r--r--fs/nfs/nfs4trace.h431
-rw-r--r--fs/nfs/nfstrace.h1
-rw-r--r--fs/nfs/pagelist.c126
-rw-r--r--fs/nfs/pnfs.c180
-rw-r--r--fs/nfs/pnfs.h54
-rw-r--r--fs/nfs/pnfs_nfs.c10
-rw-r--r--fs/nfs/read.c43
-rw-r--r--fs/nfs/write.c133
-rw-r--r--fs/nfsd/lockd.c2
-rw-r--r--fs/nfsd/netns.h2
-rw-r--r--fs/nfsd/nfs4callback.c6
-rw-r--r--fs/nfsd/nfs4layouts.c39
-rw-r--r--fs/nfsd/nfs4recover.c6
-rw-r--r--fs/nfsd/nfs4state.c65
-rw-r--r--fs/nfsd/nfsfh.h23
-rw-r--r--fs/nfsd/nfssvc.c75
-rw-r--r--fs/nfsd/state.h4
-rw-r--r--fs/nfsd/trace.h41
-rw-r--r--fs/nfsd/vfs.c15
-rw-r--r--fs/nilfs2/super.c3
-rw-r--r--fs/notify/inode_mark.c3
-rw-r--r--fs/notify/mark.c66
-rw-r--r--fs/ntfs/super.c4
-rw-r--r--fs/ocfs2/alloc.c15
-rw-r--r--fs/ocfs2/alloc.h2
-rw-r--r--fs/ocfs2/cluster/heartbeat.c4
-rw-r--r--fs/ocfs2/cluster/nodemanager.c2
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h11
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c35
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c15
-rw-r--r--fs/ocfs2/dlm/dlmunlock.c2
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c2
-rw-r--r--fs/ocfs2/dlmglue.c8
-rw-r--r--fs/ocfs2/file.c8
-rw-r--r--fs/ocfs2/ioctl.c4
-rw-r--r--fs/ocfs2/journal.c10
-rw-r--r--fs/ocfs2/localalloc.c10
-rw-r--r--fs/ocfs2/namei.c21
-rw-r--r--fs/ocfs2/quota.h2
-rw-r--r--fs/ocfs2/quota_global.c2
-rw-r--r--fs/ocfs2/slot_map.c14
-rw-r--r--fs/ocfs2/super.c13
-rw-r--r--fs/openpromfs/inode.c2
-rw-r--r--fs/proc/inode.c3
-rw-r--r--fs/proc/meminfo.c5
-rw-r--r--fs/proc/page.c4
-rw-r--r--fs/proc/task_mmu.c133
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/qnx6/inode.c2
-rw-r--r--fs/quota/dquot.c2
-rw-r--r--fs/quota/netlink.c5
-rw-r--r--fs/quota/quota_v2.c4
-rw-r--r--fs/reiserfs/super.c3
-rw-r--r--fs/romfs/super.c4
-rw-r--r--fs/squashfs/super.c3
-rw-r--r--fs/stat.c2
-rw-r--r--fs/super.c2
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/ubifs/super.c4
-rw-r--r--fs/udf/balloc.c98
-rw-r--r--fs/udf/inode.c243
-rw-r--r--fs/udf/super.c17
-rw-r--r--fs/udf/udfdecl.h4
-rw-r--r--fs/udf/unicode.c21
-rw-r--r--fs/ufs/super.c2
-rw-r--r--fs/xfs/kmem.h1
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c4
-rw-r--r--fs/xfs/libxfs/xfs_alloc.h1
-rw-r--r--fs/xfs/libxfs/xfs_alloc_btree.c35
-rw-r--r--fs/xfs/libxfs/xfs_attr.c141
-rw-r--r--fs/xfs/libxfs/xfs_attr_leaf.c1
-rw-r--r--fs/xfs/libxfs/xfs_attr_remote.c32
-rw-r--r--fs/xfs/libxfs/xfs_bit.c6
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c43
-rw-r--r--fs/xfs/libxfs/xfs_bmap.h2
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.c1
-rw-r--r--fs/xfs/libxfs/xfs_btree.c58
-rw-r--r--fs/xfs/libxfs/xfs_btree.h3
-rw-r--r--fs/xfs/libxfs/xfs_da_btree.c1
-rw-r--r--fs/xfs/libxfs/xfs_dir2_block.c1
-rw-r--r--fs/xfs/libxfs/xfs_dir2_data.c2
-rw-r--r--fs/xfs/libxfs/xfs_dir2_leaf.c2
-rw-r--r--fs/xfs/libxfs/xfs_dir2_node.c1
-rw-r--r--fs/xfs/libxfs/xfs_dquot_buf.c37
-rw-r--r--fs/xfs/libxfs/xfs_format.h2
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c1
-rw-r--r--fs/xfs/libxfs/xfs_ialloc_btree.c27
-rw-r--r--fs/xfs/libxfs/xfs_inode_buf.c16
-rw-r--r--fs/xfs/libxfs/xfs_log_recover.h1
-rw-r--r--fs/xfs/libxfs/xfs_quota_defs.h2
-rw-r--r--fs/xfs/libxfs/xfs_sb.c2
-rw-r--r--fs/xfs/libxfs/xfs_shared.h1
-rw-r--r--fs/xfs/libxfs/xfs_symlink_remote.c1
-rw-r--r--fs/xfs/xfs_aops.c2
-rw-r--r--fs/xfs/xfs_bmap_util.c43
-rw-r--r--fs/xfs/xfs_buf.c9
-rw-r--r--fs/xfs/xfs_buf.h1
-rw-r--r--fs/xfs/xfs_dquot.c13
-rw-r--r--fs/xfs/xfs_error.c4
-rw-r--r--fs/xfs/xfs_file.c25
-rw-r--r--fs/xfs/xfs_inode.c25
-rw-r--r--fs/xfs/xfs_iomap.c21
-rw-r--r--fs/xfs/xfs_log.c51
-rw-r--r--fs/xfs/xfs_log_priv.h3
-rw-r--r--fs/xfs/xfs_log_recover.c581
-rw-r--r--fs/xfs/xfs_rtalloc.c3
-rw-r--r--fs/xfs/xfs_super.c6
-rw-r--r--fs/xfs/xfs_symlink.c12
-rw-r--r--fs/xfs/xfs_sysfs.c36
-rw-r--r--fs/xfs/xfs_trace.h26
-rw-r--r--fs/xfs/xfs_trans_dquot.c14
-rw-r--r--include/asm-generic/barrier.h106
-rw-r--r--include/asm-generic/div64.h178
-rw-r--r--include/asm-generic/memory_model.h4
-rw-r--r--include/asm-generic/pgtable.h15
-rw-r--r--include/asm-generic/sections.h65
-rw-r--r--include/crypto/hash_info.h3
-rw-r--r--include/drm/drmP.h15
-rw-r--r--include/drm/drm_atomic.h10
-rw-r--r--include/drm/drm_atomic_helper.h10
-rw-r--r--include/drm/drm_crtc.h1242
-rw-r--r--include/drm/drm_crtc_helper.h167
-rw-r--r--include/drm/drm_dp_helper.h36
-rw-r--r--include/drm/drm_dp_mst_helper.h11
-rw-r--r--include/drm/drm_encoder_slave.h2
-rw-r--r--include/drm/drm_fb_cma_helper.h2
-rw-r--r--include/drm/drm_fb_helper.h101
-rw-r--r--include/drm/drm_gem.h106
-rw-r--r--include/drm/drm_mipi_dsi.h27
-rw-r--r--include/drm/drm_mm.h26
-rw-r--r--include/drm/drm_modes.h347
-rw-r--r--include/drm/drm_modeset_helper_vtables.h928
-rw-r--r--include/drm/drm_modeset_lock.h4
-rw-r--r--include/drm/drm_plane_helper.h38
-rw-r--r--include/drm/drm_rect.h3
-rw-r--r--include/drm/i915_component.h83
-rw-r--r--include/drm/i915_pciids.h49
-rw-r--r--include/drm/ttm/ttm_bo_api.h10
-rw-r--r--include/drm/ttm/ttm_bo_driver.h4
-rw-r--r--include/dt-bindings/clock/bcm2835-aux.h17
-rw-r--r--include/dt-bindings/clock/bcm2835.h3
-rw-r--r--include/dt-bindings/clock/exynos4.h1
-rw-r--r--include/dt-bindings/clock/exynos5420.h4
-rw-r--r--include/dt-bindings/clock/imx7d-clock.h3
-rw-r--r--include/dt-bindings/clock/lpc32xx-clock.h56
-rw-r--r--include/dt-bindings/clock/qcom,gcc-msm8996.h339
-rw-r--r--include/dt-bindings/clock/qcom,mmcc-msm8996.h285
-rw-r--r--include/dt-bindings/clock/r8a7791-clock.h1
-rw-r--r--include/dt-bindings/clock/r8a7794-clock.h1
-rw-r--r--include/dt-bindings/clock/rk3036-cru.h193
-rw-r--r--include/dt-bindings/clock/rk3228-cru.h220
-rw-r--r--include/dt-bindings/clock/rk3288-cru.h4
-rw-r--r--include/dt-bindings/clock/sh73a0-clock.h6
-rw-r--r--include/dt-bindings/clock/tegra210-car.h401
-rw-r--r--include/dt-bindings/leds/common.h2
-rw-r--r--include/dt-bindings/mfd/palmas.h2
-rw-r--r--include/dt-bindings/pinctrl/am43xx.h6
-rw-r--r--include/dt-bindings/pinctrl/dm814x.h48
-rw-r--r--include/dt-bindings/pinctrl/dra.h6
-rw-r--r--include/dt-bindings/pinctrl/omap.h3
-rw-r--r--include/dt-bindings/power/raspberrypi-power.h41
-rw-r--r--include/dt-bindings/reset/hisi,hi6220-resets.h67
-rw-r--r--include/dt-bindings/reset/mt8135-resets.h (renamed from include/dt-bindings/reset-controller/mt8135-resets.h)0
-rw-r--r--include/dt-bindings/reset/mt8173-resets.h (renamed from include/dt-bindings/reset-controller/mt8173-resets.h)0
-rw-r--r--include/dt-bindings/reset/stih407-resets.h4
-rw-r--r--include/keys/system_keyring.h24
-rw-r--r--include/keys/trusted-type.h5
-rw-r--r--include/linux/amba/serial.h18
-rw-r--r--include/linux/atmel-mci.h4
-rw-r--r--include/linux/audit.h212
-rw-r--r--include/linux/badblocks.h65
-rw-r--r--include/linux/basic_mmio_gpio.h80
-rw-r--r--include/linux/bcm47xx_wdt.h3
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h6
-rw-r--r--include/linux/blk-mq.h8
-rw-r--r--include/linux/blkdev.h22
-rw-r--r--include/linux/capability.h22
-rw-r--r--include/linux/clk-provider.h9
-rw-r--r--include/linux/clk/mmp.h17
-rw-r--r--include/linux/clk/ti.h2
-rw-r--r--include/linux/clksrc-dbx500-prcmu.h20
-rw-r--r--include/linux/configfs.h21
-rw-r--r--include/linux/console.h1
-rw-r--r--include/linux/dca.h5
-rw-r--r--include/linux/dcache.h4
-rw-r--r--include/linux/dmaengine.h145
-rw-r--r--include/linux/dmi.h1
-rw-r--r--include/linux/dqblk_qtree.h2
-rw-r--r--include/linux/err.h2
-rw-r--r--include/linux/evm.h7
-rw-r--r--include/linux/f2fs_fs.h3
-rw-r--r--include/linux/fb.h18
-rw-r--r--include/linux/fs.h11
-rw-r--r--include/linux/fsnotify_backend.h5
-rw-r--r--include/linux/genalloc.h38
-rw-r--r--include/linux/genhd.h2
-rw-r--r--include/linux/gfp.h22
-rw-r--r--include/linux/gpio/driver.h75
-rw-r--r--include/linux/hid.h8
-rw-r--r--include/linux/hsi/hsi.h3
-rw-r--r--include/linux/huge_mm.h79
-rw-r--r--include/linux/hugetlb.h11
-rw-r--r--include/linux/hyperv.h133
-rw-r--r--include/linux/i2c.h47
-rw-r--r--include/linux/iio/buffer-dma.h152
-rw-r--r--include/linux/iio/buffer-dmaengine.h18
-rw-r--r--include/linux/iio/buffer.h16
-rw-r--r--include/linux/iio/configfs.h15
-rw-r--r--include/linux/iio/iio.h2
-rw-r--r--include/linux/iio/sw_trigger.h70
-rw-r--r--include/linux/io.h15
-rw-r--r--include/linux/kdev_t.h5
-rw-r--r--include/linux/kernel.h36
-rw-r--r--include/linux/key.h1
-rw-r--r--include/linux/kvm_host.h37
-rw-r--r--include/linux/kvm_types.h2
-rw-r--r--include/linux/libnvdimm.h1
-rw-r--r--include/linux/list.h11
-rw-r--r--include/linux/livepatch.h24
-rw-r--r--include/linux/lockd/bind.h2
-rw-r--r--include/linux/lsm_hooks.h10
-rw-r--r--include/linux/memblock.h31
-rw-r--r--include/linux/memcontrol.h118
-rw-r--r--include/linux/memory_hotplug.h3
-rw-r--r--include/linux/mempolicy.h2
-rw-r--r--include/linux/memremap.h114
-rw-r--r--include/linux/mfd/arizona/core.h3
-rw-r--r--include/linux/mfd/arizona/pdata.h2
-rw-r--r--include/linux/mfd/palmas.h75
-rw-r--r--include/linux/mfd/samsung/core.h1
-rw-r--r--include/linux/mfd/samsung/rtc.h4
-rw-r--r--include/linux/mfd/samsung/s2mps15.h158
-rw-r--r--include/linux/mfd/tps65218.h7
-rw-r--r--include/linux/mlx5/cq.h2
-rw-r--r--include/linux/mlx5/driver.h5
-rw-r--r--include/linux/mm.h245
-rw-r--r--include/linux/mm_inline.h2
-rw-r--r--include/linux/mm_types.h34
-rw-r--r--include/linux/mmdebug.h6
-rw-r--r--include/linux/mmzone.h37
-rw-r--r--include/linux/mod_devicetable.h2
-rw-r--r--include/linux/module.h68
-rw-r--r--include/linux/mtd/map.h2
-rw-r--r--include/linux/mtd/mtd.h11
-rw-r--r--include/linux/mtd/nand.h71
-rw-r--r--include/linux/mtd/nand_bch.h2
-rw-r--r--include/linux/mtd/partitions.h27
-rw-r--r--include/linux/mtd/sh_flctl.h4
-rw-r--r--include/linux/mtd/spi-nor.h19
-rw-r--r--include/linux/nfs4.h14
-rw-r--r--include/linux/nfs_fs.h23
-rw-r--r--include/linux/nfs_fs_sb.h1
-rw-r--r--include/linux/nfs_xdr.h6
-rw-r--r--include/linux/nwpserial.h18
-rw-r--r--include/linux/of_address.h19
-rw-r--r--include/linux/of_gpio.h13
-rw-r--r--include/linux/omap-dma.h6
-rw-r--r--include/linux/page-flags.h286
-rw-r--r--include/linux/pagemap.h38
-rw-r--r--include/linux/pfn.h10
-rw-r--r--include/linux/pfn_t.h102
-rw-r--r--include/linux/phy/omap_usb.h23
-rw-r--r--include/linux/platform_data/asoc-s3c.h8
-rw-r--r--include/linux/platform_data/dma-rcar-hpbdma.h103
-rw-r--r--include/linux/platform_data/edma.h7
-rw-r--r--include/linux/platform_data/gpio-rcar.h29
-rw-r--r--include/linux/platform_data/iommu-omap.h9
-rw-r--r--include/linux/platform_data/mmc-atmel-mci.h22
-rw-r--r--include/linux/platform_data/spi-s3c64xx.h2
-rw-r--r--include/linux/platform_data/touchscreen-s3c2410.h1
-rw-r--r--include/linux/platform_data/usb-rcar-phy.h28
-rw-r--r--include/linux/poison.h6
-rw-r--r--include/linux/power/bq27xxx_battery.h57
-rw-r--r--include/linux/printk.h12
-rw-r--r--include/linux/regulator/consumer.h3
-rw-r--r--include/linux/regulator/driver.h2
-rw-r--r--include/linux/reset.h17
-rw-r--r--include/linux/rmap.h37
-rw-r--r--include/linux/security.h13
-rw-r--r--include/linux/serial_core.h3
-rw-r--r--include/linux/serial_sci.h1
-rw-r--r--include/linux/sh_clk.h4
-rw-r--r--include/linux/shmem_fs.h4
-rw-r--r--include/linux/skbuff.h3
-rw-r--r--include/linux/slab.h5
-rw-r--r--include/linux/soc/dove/pmu.h19
-rw-r--r--include/linux/soc/qcom/smem_state.h18
-rw-r--r--include/linux/spi/spi.h29
-rw-r--r--include/linux/sunrpc/svc_xprt.h1
-rw-r--r--include/linux/sunrpc/svcauth.h9
-rw-r--r--include/linux/swap.h5
-rw-r--r--include/linux/thread_info.h5
-rw-r--r--include/linux/topology.h4
-rw-r--r--include/linux/tty.h23
-rw-r--r--include/linux/uinput.h5
-rw-r--r--include/linux/usb.h6
-rw-r--r--include/linux/usb/gadget.h11
-rw-r--r--include/linux/usb/hcd.h4
-rw-r--r--include/linux/usb/musb-omap.h30
-rw-r--r--include/linux/usb/musb.h15
-rw-r--r--include/linux/usb/of.h6
-rw-r--r--include/linux/usb/renesas_usbhs.h18
-rw-r--r--include/linux/vfio.h3
-rw-r--r--include/linux/virtio_config.h2
-rw-r--r--include/linux/virtio_ring.h21
-rw-r--r--include/linux/vm_event_item.h5
-rw-r--r--include/linux/vmalloc.h1
-rw-r--r--include/linux/vmpressure.h7
-rw-r--r--include/linux/vmstat.h2
-rw-r--r--include/linux/watchdog.h38
-rw-r--r--include/linux/wkup_m3_ipc.h55
-rw-r--r--include/media/media-device.h469
-rw-r--r--include/media/media-devnode.h54
-rw-r--r--include/media/media-entity.h904
-rw-r--r--include/media/tuner.h8
-rw-r--r--include/media/v4l2-dev.h1
-rw-r--r--include/net/inet_ecn.h19
-rw-r--r--include/net/sock.h138
-rw-r--r--include/net/tcp.h5
-rw-r--r--include/net/tcp_memcontrol.h4
-rw-r--r--include/scsi/sas.h74
-rw-r--r--include/scsi/scsi_dbg.h2
-rw-r--r--include/scsi/scsi_device.h7
-rw-r--r--include/scsi/scsi_transport_sas.h10
-rw-r--r--include/soc/bcm2835/raspberrypi-firmware.h2
-rw-r--r--include/soc/fsl/qe/immap_qe.h (renamed from arch/powerpc/include/asm/immap_qe.h)0
-rw-r--r--include/soc/fsl/qe/qe.h (renamed from arch/powerpc/include/asm/qe.h)52
-rw-r--r--include/soc/fsl/qe/qe_ic.h (renamed from arch/powerpc/include/asm/qe_ic.h)0
-rw-r--r--include/soc/fsl/qe/ucc.h (renamed from arch/powerpc/include/asm/ucc.h)4
-rw-r--r--include/soc/fsl/qe/ucc_fast.h (renamed from arch/powerpc/include/asm/ucc_fast.h)6
-rw-r--r--include/soc/fsl/qe/ucc_slow.h (renamed from arch/powerpc/include/asm/ucc_slow.h)6
-rw-r--r--include/sound/ac97_codec.h3
-rw-r--r--include/sound/compress_driver.h7
-rw-r--r--include/sound/core.h1
-rw-r--r--include/sound/da7218.h109
-rw-r--r--include/sound/da7219.h14
-rw-r--r--include/sound/designware_i2s.h6
-rw-r--r--include/sound/hda_i915.h14
-rw-r--r--include/sound/hda_register.h9
-rw-r--r--include/sound/hdaudio_ext.h21
-rw-r--r--include/sound/i2c.h2
-rw-r--r--include/sound/rawmidi.h2
-rw-r--r--include/sound/rt5659.h49
-rw-r--r--include/sound/soc-dai.h1
-rw-r--r--include/sound/soc-dapm.h4
-rw-r--r--include/sound/soc-topology.h6
-rw-r--r--include/sound/soc.h53
-rw-r--r--include/target/target_core_base.h6
-rw-r--r--include/target/target_core_fabric.h9
-rw-r--r--include/trace/events/btrfs.h3
-rw-r--r--include/trace/events/f2fs.h38
-rw-r--r--include/trace/events/huge_memory.h137
-rw-r--r--include/trace/events/page_isolation.h38
-rw-r--r--include/trace/events/vmscan.h21
-rw-r--r--include/uapi/asm-generic/mman-common.h1
-rw-r--r--include/uapi/drm/Kbuild2
-rw-r--r--include/uapi/drm/amdgpu_drm.h290
-rw-r--r--include/uapi/drm/armada_drm.h2
-rw-r--r--include/uapi/drm/drm.h9
-rw-r--r--include/uapi/drm/drm_fourcc.h2
-rw-r--r--include/uapi/drm/drm_mode.h18
-rw-r--r--include/uapi/drm/drm_sarea.h2
-rw-r--r--include/uapi/drm/etnaviv_drm.h222
-rw-r--r--include/uapi/drm/exynos_drm.h8
-rw-r--r--include/uapi/drm/i810_drm.h2
-rw-r--r--include/uapi/drm/i915_drm.h25
-rw-r--r--include/uapi/drm/mga_drm.h2
-rw-r--r--include/uapi/drm/msm_drm.h5
-rw-r--r--include/uapi/drm/nouveau_drm.h86
-rw-r--r--include/uapi/drm/omap_drm.h8
-rw-r--r--include/uapi/drm/qxl_drm.h77
-rw-r--r--include/uapi/drm/r128_drm.h2
-rw-r--r--include/uapi/drm/radeon_drm.h128
-rw-r--r--include/uapi/drm/savage_drm.h2
-rw-r--r--include/uapi/drm/tegra_drm.h2
-rw-r--r--include/uapi/drm/vc4_drm.h279
-rw-r--r--include/uapi/drm/via_drm.h5
-rw-r--r--include/uapi/drm/virtgpu_drm.h101
-rw-r--r--include/uapi/drm/vmwgfx_drm.h268
-rw-r--r--include/uapi/linux/agpgart.h1
-rw-r--r--include/uapi/linux/fs.h2
-rw-r--r--include/uapi/linux/hash_info.h1
-rw-r--r--include/uapi/linux/hyperv.h1
-rw-r--r--include/uapi/linux/media.h228
-rw-r--r--include/uapi/linux/raid/md_u.h4
-rw-r--r--include/uapi/linux/serial.h1
-rw-r--r--include/uapi/linux/serial_core.h2
-rw-r--r--include/uapi/linux/serio.h1
-rw-r--r--include/uapi/linux/uinput.h80
-rw-r--r--include/uapi/linux/vfio.h9
-rw-r--r--include/uapi/linux/virtio_gpu.h2
-rw-r--r--include/uapi/rdma/hfi/hfi1_user.h38
-rw-r--r--include/uapi/scsi/cxlflash_ioctl.h10
-rw-r--r--include/uapi/sound/asoc.h2
-rw-r--r--include/uapi/sound/compress_params.h5
-rw-r--r--include/video/omapdss.h5
-rw-r--r--include/video/sh_mobile_hdmi.h49
-rw-r--r--include/xen/interface/io/ring.h16
-rw-r--r--init/Kconfig13
-rw-r--r--init/do_mounts_rd.c7
-rw-r--r--ipc/mqueue.c2
-rw-r--r--kernel/async.c1
-rw-r--r--kernel/audit.c19
-rw-r--r--kernel/audit.h2
-rw-r--r--kernel/auditsc.c6
-rw-r--r--kernel/cred.c4
-rw-r--r--kernel/debug/kdb/kdb_main.c4
-rw-r--r--kernel/delayacct.c2
-rw-r--r--kernel/events/uprobes.c13
-rw-r--r--kernel/fork.c27
-rw-r--r--kernel/futex.c65
-rw-r--r--kernel/gcov/base.c7
-rw-r--r--kernel/livepatch/core.c176
-rw-r--r--kernel/memremap.c219
-rw-r--r--kernel/module.c349
-rw-r--r--kernel/panic.c3
-rw-r--r--kernel/pid.c2
-rw-r--r--kernel/printk/printk.c67
-rw-r--r--kernel/resource.c11
-rw-r--r--kernel/sched/idle.c1
-rw-r--r--kernel/stop_machine.c4
-rw-r--r--kernel/sysctl.c22
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/Kconfig.debug47
-rw-r--r--lib/div64.c6
-rw-r--r--lib/dma-debug.c2
-rw-r--r--lib/genalloc.c93
-rw-r--r--lib/kasprintf.c10
-rw-r--r--lib/list_debug.c9
-rw-r--r--lib/raid6/altivec.uc1
-rw-r--r--lib/test_firmware.c79
-rw-r--r--lib/test_printf.c121
-rw-r--r--lib/vsprintf.c252
-rw-r--r--mm/backing-dev.c2
-rw-r--r--mm/balloon_compaction.c4
-rw-r--r--mm/compaction.c18
-rw-r--r--mm/debug.c12
-rw-r--r--mm/filemap.c34
-rw-r--r--mm/gup.c172
-rw-r--r--mm/huge_memory.c1670
-rw-r--r--mm/hugetlb.c51
-rw-r--r--mm/internal.h70
-rw-r--r--mm/kmemleak.c3
-rw-r--r--mm/ksm.c89
-rw-r--r--mm/madvise.c201
-rw-r--r--mm/memblock.c45
-rw-r--r--mm/memcontrol.c416
-rw-r--r--mm/memory-failure.c125
-rw-r--r--mm/memory.c148
-rw-r--r--mm/memory_hotplug.c76
-rw-r--r--mm/mempolicy.c75
-rw-r--r--mm/migrate.c21
-rw-r--r--mm/mincore.c2
-rw-r--r--mm/mlock.c29
-rw-r--r--mm/mmap.c106
-rw-r--r--mm/mmzone.c8
-rw-r--r--mm/mprotect.c15
-rw-r--r--mm/mremap.c22
-rw-r--r--mm/nommu.c2
-rw-r--r--mm/oom_kill.c5
-rw-r--r--mm/page-writeback.c14
-rw-r--r--mm/page_alloc.c205
-rw-r--r--mm/page_idle.c27
-rw-r--r--mm/page_isolation.c28
-rw-r--r--mm/pagewalk.c2
-rw-r--r--mm/pgtable-generic.c23
-rw-r--r--mm/readahead.c9
-rw-r--r--mm/rmap.c387
-rw-r--r--mm/shmem.c110
-rw-r--r--mm/slab.c48
-rw-r--r--mm/slab.h5
-rw-r--r--mm/slab_common.c3
-rw-r--r--mm/slub.c4
-rw-r--r--mm/sparse-vmemmap.c76
-rw-r--r--mm/sparse.c8
-rw-r--r--mm/swap.c319
-rw-r--r--mm/swap_state.c9
-rw-r--r--mm/swapfile.c57
-rw-r--r--mm/userfaultfd.c8
-rw-r--r--mm/util.c24
-rw-r--r--mm/vmalloc.c27
-rw-r--r--mm/vmpressure.c78
-rw-r--r--mm/vmscan.c56
-rw-r--r--mm/vmstat.c74
-rw-r--r--mm/zbud.c5
-rw-r--r--mm/zsmalloc.c4
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c10
-rw-r--r--net/batman-adv/hard-interface.h12
-rw-r--r--net/batman-adv/multicast.c2
-rw-r--r--net/batman-adv/network-coding.c19
-rw-r--r--net/batman-adv/originator.c186
-rw-r--r--net/batman-adv/originator.h1
-rw-r--r--net/batman-adv/translation-table.c28
-rw-r--r--net/bridge/br_device.c8
-rw-r--r--net/core/dev.c5
-rw-r--r--net/core/sock.c78
-rw-r--r--net/ipv4/ip_output.c1
-rw-r--r--net/ipv4/tcp.c3
-rw-r--r--net/ipv4/tcp_ipv4.c9
-rw-r--r--net/ipv4/tcp_memcontrol.c91
-rw-r--r--net/ipv4/tcp_output.c7
-rw-r--r--net/ipv6/tcp_ipv6.c3
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c2
-rw-r--r--net/netlink/genetlink.c2
-rw-r--r--net/openvswitch/actions.c19
-rw-r--r--net/openvswitch/datapath.c5
-rw-r--r--net/sctp/endpointola.c2
-rw-r--r--net/sctp/input.c46
-rw-r--r--net/sctp/proc.c6
-rw-r--r--net/socket.c2
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.c3
-rw-r--r--net/sunrpc/clnt.c1
-rw-r--r--net/sunrpc/rpc_pipe.c2
-rw-r--r--net/sunrpc/svc_xprt.c45
-rw-r--r--net/sunrpc/svcauth.c2
-rw-r--r--net/sunrpc/svcauth_unix.c8
-rw-r--r--net/sunrpc/xprtrdma/backchannel.c26
-rw-r--r--net/sunrpc/xprtrdma/fmr_ops.c64
-rw-r--r--net/sunrpc/xprtrdma/frwr_ops.c174
-rw-r--r--net/sunrpc/xprtrdma/physical_ops.c13
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c16
-rw-r--r--net/sunrpc/xprtrdma/transport.c3
-rw-r--r--net/sunrpc/xprtrdma/verbs.c16
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h14
-rw-r--r--net/sunrpc/xprtsock.c63
-rw-r--r--net/xfrm/xfrm_output.c2
-rw-r--r--scripts/Makefile.build8
-rw-r--r--scripts/Makefile.extrawarn2
-rw-r--r--scripts/Makefile.lib7
-rw-r--r--scripts/basic/fixdep.c2
-rwxr-xr-xscripts/bloat-o-meter8
-rwxr-xr-xscripts/checkkconfigsymbols.py234
-rwxr-xr-xscripts/checkpatch.pl33
-rw-r--r--scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci75
-rw-r--r--scripts/genksyms/genksyms.c6
-rw-r--r--scripts/kconfig/conf.c7
-rw-r--r--scripts/kconfig/menu.c2
-rw-r--r--scripts/kconfig/qconf.cc2
-rwxr-xr-xscripts/kernel-doc5
-rw-r--r--scripts/mod/file2alias.c5
-rw-r--r--scripts/package/Makefile4
-rwxr-xr-xscripts/recordmcount.pl3
-rwxr-xr-xscripts/tags.sh217
-rw-r--r--security/integrity/Kconfig11
-rw-r--r--security/integrity/digsig.c14
-rw-r--r--security/integrity/digsig_asymmetric.c14
-rw-r--r--security/integrity/evm/Kconfig17
-rw-r--r--security/integrity/evm/evm.h3
-rw-r--r--security/integrity/evm/evm_crypto.c54
-rw-r--r--security/integrity/evm/evm_main.c32
-rw-r--r--security/integrity/evm/evm_secfs.c12
-rw-r--r--security/integrity/iint.c1
-rw-r--r--security/integrity/ima/Kconfig44
-rw-r--r--security/integrity/ima/Makefile1
-rw-r--r--security/integrity/ima/ima.h24
-rw-r--r--security/integrity/ima/ima_fs.c53
-rw-r--r--security/integrity/ima/ima_init.c2
-rw-r--r--security/integrity/ima/ima_mok.c55
-rw-r--r--security/integrity/ima/ima_policy.c301
-rw-r--r--security/integrity/integrity.h13
-rw-r--r--security/keys/Kconfig1
-rw-r--r--security/keys/key.c5
-rw-r--r--security/keys/keyctl.c49
-rw-r--r--security/keys/process_keys.c1
-rw-r--r--security/keys/trusted.c56
-rw-r--r--security/security.c12
-rw-r--r--security/selinux/hooks.c200
-rw-r--r--security/selinux/include/classmap.h2
-rw-r--r--security/selinux/include/objsec.h6
-rw-r--r--security/selinux/include/security.h3
-rw-r--r--security/selinux/selinuxfs.c80
-rw-r--r--security/selinux/ss/services.c34
-rw-r--r--security/smack/smack_lsm.c28
-rw-r--r--sound/core/compress_offload.c99
-rw-r--r--sound/core/init.c3
-rw-r--r--sound/core/oss/mixer_oss.c8
-rw-r--r--sound/core/oss/pcm_oss.c10
-rw-r--r--sound/core/pcm_dmaengine.c9
-rw-r--r--sound/core/pcm_native.c26
-rw-r--r--sound/core/seq/oss/seq_oss.c7
-rw-r--r--sound/core/seq/seq_clientmgr.c2
-rw-r--r--sound/core/seq/seq_queue.c2
-rw-r--r--sound/core/seq/seq_virmidi.c2
-rw-r--r--sound/core/timer.c76
-rw-r--r--sound/drivers/dummy.c4
-rw-r--r--sound/drivers/pcm-indirect2.c2
-rw-r--r--sound/firewire/Kconfig12
-rw-r--r--sound/firewire/Makefile2
-rw-r--r--sound/firewire/dice/dice-transaction.c123
-rw-r--r--sound/firewire/dice/dice.c227
-rw-r--r--sound/firewire/dice/dice.h3
-rw-r--r--sound/firewire/fireworks/fireworks.h4
-rw-r--r--sound/firewire/fireworks/fireworks_midi.c16
-rw-r--r--sound/firewire/fireworks/fireworks_pcm.c28
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c32
-rw-r--r--sound/firewire/oxfw/Makefile4
-rw-r--r--sound/firewire/oxfw/oxfw-scs1x.c406
-rw-r--r--sound/firewire/oxfw/oxfw-spkr.c (renamed from sound/firewire/oxfw/oxfw-control.c)142
-rw-r--r--sound/firewire/oxfw/oxfw.c110
-rw-r--r--sound/firewire/oxfw/oxfw.h23
-rw-r--r--sound/firewire/scs1x.c530
-rw-r--r--sound/hda/ext/hdac_ext_controller.c29
-rw-r--r--sound/hda/ext/hdac_ext_stream.c72
-rw-r--r--sound/hda/hdac_i915.c66
-rw-r--r--sound/i2c/i2c.c2
-rw-r--r--sound/oss/Kconfig2
-rw-r--r--sound/pci/atiixp.c6
-rw-r--r--sound/pci/atiixp_modem.c4
-rw-r--r--sound/pci/azt3328.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c4
-rw-r--r--sound/pci/fm801.c145
-rw-r--r--sound/pci/hda/hda_controller.c10
-rw-r--r--sound/pci/hda/hda_controller.h14
-rw-r--r--sound/pci/hda/hda_eld.c1
-rw-r--r--sound/pci/hda/hda_generic.c108
-rw-r--r--sound/pci/hda/hda_generic.h5
-rw-r--r--sound/pci/hda/hda_intel.c78
-rw-r--r--sound/pci/hda/hda_tegra.c5
-rw-r--r--sound/pci/hda/patch_conexant.c3
-rw-r--r--sound/pci/hda/patch_hdmi.c245
-rw-r--r--sound/pci/hda/patch_realtek.c14
-rw-r--r--sound/pci/ice1712/delta.c2
-rw-r--r--sound/soc/Kconfig2
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/amd/Kconfig4
-rw-r--r--sound/soc/amd/Makefile3
-rw-r--r--sound/soc/amd/acp-pcm-dma.c1043
-rw-r--r--sound/soc/amd/acp.h118
-rw-r--r--sound/soc/amd/include/acp_2_2_d.h609
-rw-r--r--sound/soc/amd/include/acp_2_2_enum.h1068
-rw-r--r--sound/soc/amd/include/acp_2_2_sh_mask.h2292
-rw-r--r--sound/soc/atmel/Kconfig9
-rw-r--r--sound/soc/atmel/Makefile2
-rw-r--r--sound/soc/atmel/atmel-classd.c26
-rw-r--r--sound/soc/atmel/atmel-pdmic.c738
-rw-r--r--sound/soc/atmel/atmel-pdmic.h80
-rw-r--r--sound/soc/atmel/atmel_wm8904.c1
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c12
-rw-r--r--sound/soc/codecs/Kconfig62
-rw-r--r--sound/soc/codecs/Makefile22
-rw-r--r--sound/soc/codecs/ak4613.c118
-rw-r--r--sound/soc/codecs/arizona.c146
-rw-r--r--sound/soc/codecs/arizona.h17
-rw-r--r--sound/soc/codecs/cs47l24.c1148
-rw-r--r--sound/soc/codecs/cs47l24.h23
-rw-r--r--sound/soc/codecs/da7218.c3341
-rw-r--r--sound/soc/codecs/da7218.h1414
-rw-r--r--sound/soc/codecs/da7219.c163
-rw-r--r--sound/soc/codecs/da7219.h9
-rw-r--r--sound/soc/codecs/hdac_hdmi.c697
-rw-r--r--sound/soc/codecs/inno_rk3036.c490
-rw-r--r--sound/soc/codecs/inno_rk3036.h123
-rw-r--r--sound/soc/codecs/max98357a.c10
-rw-r--r--sound/soc/codecs/pcm1792a.c271
-rw-r--r--sound/soc/codecs/pcm179x.c271
-rw-r--r--sound/soc/codecs/pcm179x.h (renamed from sound/soc/codecs/pcm1792a.h)6
-rw-r--r--sound/soc/codecs/pcm3168a-i2c.c66
-rw-r--r--sound/soc/codecs/pcm3168a-spi.c65
-rw-r--r--sound/soc/codecs/pcm3168a.c767
-rw-r--r--sound/soc/codecs/pcm3168a.h100
-rw-r--r--sound/soc/codecs/rt286.c6
-rw-r--r--sound/soc/codecs/rt298.c2
-rw-r--r--sound/soc/codecs/rt5616.c1381
-rw-r--r--sound/soc/codecs/rt5616.h1819
-rw-r--r--sound/soc/codecs/rt5640.c103
-rw-r--r--sound/soc/codecs/rt5640.h17
-rw-r--r--sound/soc/codecs/rt5645.c322
-rw-r--r--sound/soc/codecs/rt5651.c31
-rw-r--r--sound/soc/codecs/rt5659.c4223
-rw-r--r--sound/soc/codecs/rt5659.h1819
-rw-r--r--sound/soc/codecs/rt5677.c15
-rw-r--r--sound/soc/codecs/ssm2518.c2
-rw-r--r--sound/soc/codecs/twl6040.c3
-rw-r--r--sound/soc/codecs/wm5100.c2
-rw-r--r--sound/soc/codecs/wm5110.c252
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8904.c2
-rw-r--r--sound/soc/codecs/wm8960.c24
-rw-r--r--sound/soc/codecs/wm8962.c5
-rw-r--r--sound/soc/codecs/wm8974.c7
-rw-r--r--sound/soc/codecs/wm8996.c2
-rw-r--r--sound/soc/codecs/wm8998.c46
-rw-r--r--sound/soc/codecs/wm9713.c296
-rw-r--r--sound/soc/codecs/wm_adsp.c1095
-rw-r--r--sound/soc/codecs/wm_adsp.h28
-rw-r--r--sound/soc/dwc/designware_i2s.c117
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c21
-rw-r--r--sound/soc/fsl/fsl_asrc.c62
-rw-r--r--sound/soc/fsl/fsl_asrc.h9
-rw-r--r--sound/soc/fsl/fsl_esai.c63
-rw-r--r--sound/soc/fsl/fsl_sai.c98
-rw-r--r--sound/soc/fsl/fsl_sai.h3
-rw-r--r--sound/soc/fsl/fsl_spdif.c35
-rw-r--r--sound/soc/fsl/fsl_ssi.c49
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c2
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c4
-rw-r--r--sound/soc/fsl/imx-wm8962.c10
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c3
-rw-r--r--sound/soc/fsl/p1022_ds.c3
-rw-r--r--sound/soc/fsl/p1022_rdk.c3
-rw-r--r--sound/soc/generic/simple-card.c12
-rw-r--r--sound/soc/img/Kconfig52
-rw-r--r--sound/soc/img/Makefile7
-rw-r--r--sound/soc/img/img-i2s-in.c516
-rw-r--r--sound/soc/img/img-i2s-out.c565
-rw-r--r--sound/soc/img/img-parallel-out.c327
-rw-r--r--sound/soc/img/img-spdif-in.c806
-rw-r--r--sound/soc/img/img-spdif-out.c441
-rw-r--r--sound/soc/img/pistachio-internal-dac.c287
-rw-r--r--sound/soc/intel/Kconfig58
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c5
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.h1
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c32
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c82
-rw-r--r--sound/soc/intel/atom/sst/sst_stream.c2
-rw-r--r--sound/soc/intel/baytrail/sst-baytrail-pcm.c2
-rw-r--r--sound/soc/intel/boards/Makefile6
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c266
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c332
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c19
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c19
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c19
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c485
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c536
-rw-r--r--sound/soc/intel/boards/skl_rt286.c128
-rw-r--r--sound/soc/intel/common/Makefile12
-rw-r--r--sound/soc/intel/common/sst-acpi.c41
-rw-r--r--sound/soc/intel/common/sst-acpi.h33
-rw-r--r--sound/soc/intel/common/sst-dsp-priv.h8
-rw-r--r--sound/soc/intel/common/sst-dsp.c2
-rw-r--r--sound/soc/intel/common/sst-dsp.h2
-rw-r--r--sound/soc/intel/common/sst-firmware.c20
-rw-r--r--sound/soc/intel/common/sst-match-acpi.c43
-rw-r--r--sound/soc/intel/haswell/sst-haswell-dsp.c2
-rw-r--r--sound/soc/intel/haswell/sst-haswell-ipc.c31
-rw-r--r--sound/soc/intel/skylake/skl-messages.c280
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c19
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c310
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c97
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h21
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c123
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h14
-rw-r--r--sound/soc/intel/skylake/skl-sst.c217
-rw-r--r--sound/soc/intel/skylake/skl-topology.c658
-rw-r--r--sound/soc/intel/skylake/skl-topology.h63
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h105
-rw-r--r--sound/soc/intel/skylake/skl.c213
-rw-r--r--sound/soc/intel/skylake/skl.h8
-rw-r--r--sound/soc/mediatek/mtk-afe-common.h1
-rw-r--r--sound/soc/mediatek/mtk-afe-pcm.c59
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c2
-rw-r--r--sound/soc/pxa/brownstone.c3
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c6
-rw-r--r--sound/soc/qcom/lpass-cpu.c1
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c139
-rw-r--r--sound/soc/rockchip/rockchip_max98090.c6
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c6
-rw-r--r--sound/soc/samsung/Kconfig2
-rw-r--r--sound/soc/samsung/ac97.c29
-rw-r--r--sound/soc/samsung/bells.c40
-rw-r--r--sound/soc/samsung/dma.h6
-rw-r--r--sound/soc/samsung/dmaengine.c20
-rw-r--r--sound/soc/samsung/i2s.c31
-rw-r--r--sound/soc/samsung/littlemill.c32
-rw-r--r--sound/soc/samsung/odroidx2_max98090.c9
-rw-r--r--sound/soc/samsung/pcm.c25
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c16
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c16
-rw-r--r--sound/soc/samsung/smartq_wm8987.c76
-rw-r--r--sound/soc/samsung/snow.c9
-rw-r--r--sound/soc/samsung/spdif.c17
-rw-r--r--sound/soc/samsung/speyside.c12
-rw-r--r--sound/soc/samsung/tobermory.c21
-rw-r--r--sound/soc/sh/Kconfig1
-rw-r--r--sound/soc/sh/fsi.c11
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/adg.c118
-rw-r--r--sound/soc/sh/rcar/cmd.c171
-rw-r--r--sound/soc/sh/rcar/core.c586
-rw-r--r--sound/soc/sh/rcar/ctu.c99
-rw-r--r--sound/soc/sh/rcar/dma.c245
-rw-r--r--sound/soc/sh/rcar/dvc.c273
-rw-r--r--sound/soc/sh/rcar/gen.c133
-rw-r--r--sound/soc/sh/rcar/mix.c158
-rw-r--r--sound/soc/sh/rcar/rcar_snd.h117
-rw-r--r--sound/soc/sh/rcar/rsnd.h335
-rw-r--r--sound/soc/sh/rcar/rsrc-card.c129
-rw-r--r--sound/soc/sh/rcar/src.c898
-rw-r--r--sound/soc/sh/rcar/ssi.c755
-rw-r--r--sound/soc/sh/rcar/ssiu.c225
-rw-r--r--sound/soc/soc-ac97.c125
-rw-r--r--sound/soc/soc-compress.c31
-rw-r--r--sound/soc/soc-core.c866
-rw-r--r--sound/soc/soc-dapm.c14
-rw-r--r--sound/soc/soc-ops.c4
-rw-r--r--sound/soc/soc-pcm.c110
-rw-r--r--sound/soc/sti/uniperif_player.c3
-rw-r--r--sound/soc/sunxi/sun4i-codec.c279
-rw-r--r--sound/soc/tegra/tegra_alc5632.c12
-rw-r--r--sound/soc/tegra/tegra_wm8903.c3
-rw-r--r--sound/synth/emux/emux_nrpn.c9
-rw-r--r--sound/usb/6fire/firmware.c2
-rw-r--r--sound/usb/card.c2
-rw-r--r--sound/usb/midi.c27
-rw-r--r--sound/usb/misc/ua101.c4
-rw-r--r--sound/usb/mixer_quirks.c2
-rw-r--r--sound/usb/quirks.c1
-rw-r--r--sound/usb/stream.c6
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c2
-rw-r--r--tools/Makefile50
-rw-r--r--tools/build/feature/test-all.c5
-rw-r--r--tools/build/feature/test-bpf.c20
-rw-r--r--tools/hv/hv_fcopy_daemon.c24
-rw-r--r--tools/hv/hv_vss_daemon.c2
-rw-r--r--tools/include/linux/list.h753
-rw-r--r--tools/lib/bpf/Makefile18
-rw-r--r--tools/lib/bpf/bpf.c4
-rw-r--r--tools/lib/lockdep/Makefile2
-rw-r--r--tools/lib/subcmd/parse-options.h4
-rw-r--r--tools/perf/Build1
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Documentation/tips.txt15
-rw-r--r--tools/perf/MANIFEST2
-rw-r--r--tools/perf/builtin-record.c26
-rw-r--r--tools/perf/builtin-report.c10
-rw-r--r--tools/perf/builtin-stat.c8
-rw-r--r--tools/perf/config/Makefile7
-rw-r--r--tools/perf/tests/hists_common.c5
-rw-r--r--tools/perf/tests/hists_cumulate.c1
-rw-r--r--tools/perf/tests/hists_filter.c1
-rw-r--r--tools/perf/tests/hists_link.c1
-rw-r--r--tools/perf/tests/hists_output.c1
-rw-r--r--tools/perf/tests/make18
-rw-r--r--tools/perf/ui/browsers/hists.c2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/strlist.c8
-rw-r--r--tools/perf/util/strlist.h9
-rw-r--r--tools/perf/util/util.c11
-rw-r--r--tools/scripts/Makefile.arch (renamed from tools/perf/config/Makefile.arch)0
-rw-r--r--tools/spi/.gitignore (renamed from Documentation/spi/.gitignore)0
-rw-r--r--tools/spi/Makefile4
-rw-r--r--tools/spi/spidev_fdx.c (renamed from Documentation/spi/spidev_fdx.c)0
-rw-r--r--tools/spi/spidev_test.c (renamed from Documentation/spi/spidev_test.c)119
-rw-r--r--tools/testing/nvdimm/Kbuild2
-rw-r--r--tools/testing/nvdimm/test/iomap.c93
-rw-r--r--tools/testing/nvdimm/test/nfit.c11
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/breakpoints/.gitignore1
-rw-r--r--tools/testing/selftests/capabilities/Makefile21
-rwxr-xr-xtools/testing/selftests/firmware/fw_filesystem.sh29
-rw-r--r--tools/testing/selftests/intel_pstate/Makefile15
-rw-r--r--tools/testing/selftests/intel_pstate/aperf.c80
-rw-r--r--tools/testing/selftests/intel_pstate/msr.c39
-rwxr-xr-xtools/testing/selftests/intel_pstate/run.sh113
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/context_switch.c466
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c8
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c8
-rw-r--r--tools/testing/selftests/powerpc/harness.c43
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile3
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c3
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c26
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h1
-rwxr-xr-xtools/testing/selftests/powerpc/scripts/hmi.sh89
-rw-r--r--tools/testing/selftests/powerpc/tm/.gitignore3
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-resched-dscr.c3
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c74
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-stack.c76
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-syscall.c13
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-vmxcopy.c103
-rw-r--r--tools/testing/selftests/powerpc/tm/tm.h34
-rw-r--r--tools/testing/selftests/powerpc/utils.c87
-rw-r--r--tools/testing/selftests/powerpc/utils.h7
-rw-r--r--tools/testing/selftests/ptrace/.gitignore1
-rw-r--r--tools/testing/selftests/seccomp/test_harness.h5
-rw-r--r--tools/testing/selftests/timers/.gitignore1
-rw-r--r--tools/testing/selftests/vm/.gitignore5
-rw-r--r--tools/testing/selftests/x86/Makefile6
-rw-r--r--tools/testing/selftests/x86/vdso_restorer.c88
-rw-r--r--virt/kvm/kvm_main.c47
5346 files changed, 327349 insertions, 104384 deletions
diff --git a/CREDITS b/CREDITS
index af67a84517d7..25133c5adae7 100644
--- a/CREDITS
+++ b/CREDITS
@@ -534,6 +534,7 @@ N: NeilBrown
E: neil@brown.name
P: 4096R/566281B9 1BC6 29EB D390 D870 7B5F 497A 39EC 9EDD 5662 81B9
D: NFSD Maintainer 2000-2007
+D: MD Maintainer 2001-2016
N: Zach Brown
E: zab@zabbo.net
diff --git a/Documentation/ABI/testing/configfs-iio b/Documentation/ABI/testing/configfs-iio
new file mode 100644
index 000000000000..2483756fccf5
--- /dev/null
+++ b/Documentation/ABI/testing/configfs-iio
@@ -0,0 +1,21 @@
+What: /config/iio
+Date: October 2015
+KernelVersion: 4.4
+Contact: linux-iio@vger.kernel.org
+Description:
+ This represents Industrial IO configuration entry point
+ directory. It contains sub-groups corresponding to IIO
+ objects.
+
+What: /config/iio/triggers
+Date: October 2015
+KernelVersion: 4.4
+Description:
+ Industrial IO software triggers directory.
+
+What: /config/iio/triggers/hrtimers
+Date: October 2015
+KernelVersion: 4.4
+Description:
+ High resolution timers directory. Creating a directory here
+ will result in creating a hrtimer trigger in the IIO subsystem.
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink
index bc7ff731aa0c..f56335af2d88 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink
+++ b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink
@@ -10,3 +10,5 @@ Description:
isoc_mult - 0..2 (hs/ss only)
isoc_maxburst - 0..15 (ss only)
buflen - buffer length
+ bulk_qlen - depth of queue for bulk
+ iso_qlen - depth of queue for iso
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-tcm b/Documentation/ABI/testing/configfs-usb-gadget-tcm
new file mode 100644
index 000000000000..a29ed2dd6173
--- /dev/null
+++ b/Documentation/ABI/testing/configfs-usb-gadget-tcm
@@ -0,0 +1,6 @@
+What: /config/usb-gadget/gadget/functions/tcm.name
+Date: Dec 2015
+KernelVersion: 4.5
+Description:
+ There are no attributes because all the configuration
+ is performed in the "target" subsystem of configfs.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-ina2xx-adc b/Documentation/ABI/testing/sysfs-bus-iio-ina2xx-adc
new file mode 100644
index 000000000000..8916f7ec6507
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-ina2xx-adc
@@ -0,0 +1,24 @@
+What: /sys/bus/iio/devices/iio:deviceX/in_allow_async_readout
+Date: December 2015
+KernelVersion: 4.4
+Contact: linux-iio@vger.kernel.org
+Description:
+ By default (value '0'), the capture thread checks for the Conversion
+ Ready Flag to being set prior to committing a new value to the sample
+ buffer. This synchronizes the in-chip conversion rate with the
+ in-driver readout rate at the cost of an additional register read.
+
+ Writing '1' will remove the polling for the Conversion Ready Flags to
+ save the additional i2c transaction, which will improve the bandwidth
+ available for reading data. However, samples can be occasionally skipped
+ or repeated, depending on the beat between the capture and conversion
+ rates.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_shunt_resistor
+Date: December 2015
+KernelVersion: 4.4
+Contact: linux-iio@vger.kernel.org
+Description:
+ The value of the shunt resistor may be known only at runtime fom an
+ eeprom content read by a client application. This attribute allows to
+ set its value in ohms.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 3a4abfc44f5e..0bd731cbb50c 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -134,19 +134,21 @@ Description:
enabled for the device. Developer can write y/Y/1 or n/N/0 to
the file to enable/disable the feature.
-What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm
-Date: June 2015
+What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm_u1
+ /sys/bus/usb/devices/.../power/usb3_hardware_lpm_u2
+Date: November 2015
Contact: Kevin Strasser <kevin.strasser@linux.intel.com>
+ Lu Baolu <baolu.lu@linux.intel.com>
Description:
If CONFIG_PM is set and a USB 3.0 lpm-capable device is plugged
in to a xHCI host which supports link PM, it will check if U1
and U2 exit latencies have been set in the BOS descriptor; if
- the check is is passed and the host supports USB3 hardware LPM,
+ the check is passed and the host supports USB3 hardware LPM,
USB3 hardware LPM will be enabled for the device and the USB
- device directory will contain a file named
- power/usb3_hardware_lpm. The file holds a string value (enable
- or disable) indicating whether or not USB3 hardware LPM is
- enabled for the device.
+ device directory will contain two files named
+ power/usb3_hardware_lpm_u1 and power/usb3_hardware_lpm_u2. These
+ files hold a string value (enable or disable) indicating whether
+ or not USB3 hardware LPM U1 or U2 is enabled for the device.
What: /sys/bus/usb/devices/.../removable
Date: February 2012
@@ -187,6 +189,17 @@ Description:
The file will read "hotplug", "wired" and "not used" if the
information is available, and "unknown" otherwise.
+What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit
+Date: November 2015
+Contact: Lu Baolu <baolu.lu@linux.intel.com>
+Description:
+ Some USB3.0 devices are not friendly to USB3 LPM. usb3_lpm_permit
+ attribute allows enabling/disabling usb3 lpm of a port. It takes
+ effect both before and after a usb device is enumerated. Supported
+ values are "0" if both u1 and u2 are NOT permitted, "u1" if only u1
+ is permitted, "u2" if only u2 is permitted, "u1_u2" if both u1 and
+ u2 are permitted.
+
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
Date: May 2013
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog
new file mode 100644
index 000000000000..736046b33040
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-watchdog
@@ -0,0 +1,51 @@
+What: /sys/class/watchdog/watchdogn/bootstatus
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. It contains status of the watchdog
+ device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
+ ioctl interface.
+
+What: /sys/class/watchdog/watchdogn/identity
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. It contains identity string of
+ watchdog device.
+
+What: /sys/class/watchdog/watchdogn/nowayout
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. While reading, it gives '1' if that
+ device supports nowayout feature else, it gives '0'.
+
+What: /sys/class/watchdog/watchdogn/state
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. It gives active/inactive status of
+ watchdog device.
+
+What: /sys/class/watchdog/watchdogn/status
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. It contains watchdog device's
+ internal status bits. It is equivalent to WDIOC_GETSTATUS
+ of ioctl interface.
+
+What: /sys/class/watchdog/watchdogn/timeleft
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. It contains value of time left for
+ reset generation. It is equivalent to WDIOC_GETTIMELEFT of
+ ioctl interface.
+
+What: /sys/class/watchdog/watchdogn/timeout
+Date: August 2015
+Contact: Wim Van Sebroeck <wim@iguana.be>
+Description:
+ It is a read only file. It is read to know about current
+ value of timeout programmed.
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index 0345f2d1c727..e5200f354abf 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -87,6 +87,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
Controls the checkpoint timing.
+What: /sys/fs/f2fs/<disk>/idle_interval
+Date: January 2016
+Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+ Controls the idle timing.
+
What: /sys/fs/f2fs/<disk>/ra_nid_pages
Date: October 2015
Contact: "Chao Yu" <chao2.yu@samsung.com>
diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch
index 5bf42a840b22..da87f43aec58 100644
--- a/Documentation/ABI/testing/sysfs-kernel-livepatch
+++ b/Documentation/ABI/testing/sysfs-kernel-livepatch
@@ -33,7 +33,7 @@ Description:
The object directory contains subdirectories for each function
that is patched within the object.
-What: /sys/kernel/livepatch/<patch>/<object>/<function>
+What: /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
Date: Nov 2014
KernelVersion: 3.19.0
Contact: live-patching@vger.kernel.org
@@ -41,4 +41,8 @@ Description:
The function directory contains attributes regarding the
properties and state of the patched function.
+ The directory name contains the patched function name and a
+ sympos number corresponding to the nth occurrence of the symbol
+ name in kallsyms for the patched object.
+
There are currently no such attributes.
diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
index 44806a678f12..a17f817a9309 100644
--- a/Documentation/ABI/testing/sysfs-ptp
+++ b/Documentation/ABI/testing/sysfs-ptp
@@ -74,7 +74,7 @@ Description:
assignment may be changed by two writing numbers into
the file.
-What: /sys/class/ptp/ptpN/pps_avaiable
+What: /sys/class/ptp/ptpN/pps_available
Date: September 2010
Contact: Richard Cochran <richardcochran@gmail.com>
Description:
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index c06f817b3091..db653774c0b7 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -430,7 +430,7 @@ The rationale for using gotos is:
return result;
}
-A common type of bug to be aware of it "one err bugs" which look like this:
+A common type of bug to be aware of is "one err bugs" which look like this:
err:
kfree(foo->bar);
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index 1e98a7e6bccc..45ef3f279c3b 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -236,7 +236,7 @@ are guaranteed also to be cache line boundaries).
DMA_TO_DEVICE synchronisation must be done after the last modification
of the memory region by the software and before it is handed off to
-the driver. Once this primitive is used, memory covered by this
+the device. Once this primitive is used, memory covered by this
primitive should be treated as read-only by the device. If the device
may write to it at any point, it should be DMA_BIDIRECTIONAL (see
below).
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 91f6d89bb19f..d70f9b68174e 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -50,8 +50,7 @@ pdfdocs: $(PDF)
HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
htmldocs: $(HTML)
- $(call build_main_index)
- $(call build_images)
+ $(call cmd,build_main_index)
$(call install_media_images)
MAN := $(patsubst %.xml, %.9, $(BOOKS))
@@ -139,7 +138,8 @@ quiet_cmd_db2pdf = PDF $@
index = index.html
main_idx = $(obj)/$(index)
-build_main_index = rm -rf $(main_idx); \
+quiet_cmd_build_main_index = HTML $(main_idx)
+ cmd_build_main_index = rm -rf $(main_idx); \
echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
cat $(HTML) >> $(main_idx)
@@ -227,6 +227,10 @@ dochelp:
@echo ' mandocs - man pages'
@echo ' installmandocs - install man pages generated by mandocs'
@echo ' cleandocs - clean all generated DocBook files'
+ @echo
+ @echo 'make DOCBOOKS="s1.xml s2.xml" [target] Generate only docs s1.xml s2.xml'
+ @echo ' valid values for DOCBOOKS are: $(DOCBOOKS)'
+
###
# Temporary files left by various tools
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 7b3fcc5effcd..cdd8b24db68d 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -263,6 +263,7 @@ X!Isound/sound_firmware.c
!Iinclude/media/lirc_dev.h
</sect1>
<sect1><title>Media Controller devices</title>
+!Pinclude/media/media-device.h Media Controller
!Iinclude/media/media-device.h
!Iinclude/media/media-devnode.h
!Iinclude/media/media-entity.h
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl
index 201dcd3c2e9d..a8669330b456 100644
--- a/Documentation/DocBook/gpu.tmpl
+++ b/Documentation/DocBook/gpu.tmpl
@@ -124,6 +124,43 @@
<para>
[Insert diagram of typical DRM stack here]
</para>
+ <sect1>
+ <title>Style Guidelines</title>
+ <para>
+ For consistency this documentation uses American English. Abbreviations
+ are written as all-uppercase, for example: DRM, KMS, IOCTL, CRTC, and so
+ on. To aid in reading, documentations make full use of the markup
+ characters kerneldoc provides: @parameter for function parameters, @member
+ for structure members, &amp;structure to reference structures and
+ function() for functions. These all get automatically hyperlinked if
+ kerneldoc for the referenced objects exists. When referencing entries in
+ function vtables please use -&gt;vfunc(). Note that kerneldoc does
+ not support referencing struct members directly, so please add a reference
+ to the vtable struct somewhere in the same paragraph or at least section.
+ </para>
+ <para>
+ Except in special situations (to separate locked from unlocked variants)
+ locking requirements for functions aren't documented in the kerneldoc.
+ Instead locking should be check at runtime using e.g.
+ <code>WARN_ON(!mutex_is_locked(...));</code>. Since it's much easier to
+ ignore documentation than runtime noise this provides more value. And on
+ top of that runtime checks do need to be updated when the locking rules
+ change, increasing the chances that they're correct. Within the
+ documentation the locking rules should be explained in the relevant
+ structures: Either in the comment for the lock explaining what it
+ protects, or data fields need a note about which lock protects them, or
+ both.
+ </para>
+ <para>
+ Functions which have a non-<code>void</code> return value should have a
+ section called "Returns" explaining the expected return values in
+ different cases and their meanings. Currently there's no consensus whether
+ that section name should be all upper-case or not, and whether it should
+ end in a colon or not. Go with the file-local style. Other common section
+ names are "Notes" with information for dangerous or tricky corner cases,
+ and "FIXME" where the interface could be cleaned up.
+ </para>
+ </sect1>
</chapter>
<!-- Internals -->
@@ -615,18 +652,6 @@ char *date;</synopsis>
<function>drm_gem_object_init</function>. Storage for private GEM
objects must be managed by drivers.
</para>
- <para>
- Drivers that do not need to extend GEM objects with private information
- can call the <function>drm_gem_object_alloc</function> function to
- allocate and initialize a struct <structname>drm_gem_object</structname>
- instance. The GEM core will call the optional driver
- <methodname>gem_init_object</methodname> operation after initializing
- the GEM object with <function>drm_gem_object_init</function>.
- <synopsis>int (*gem_init_object) (struct drm_gem_object *obj);</synopsis>
- </para>
- <para>
- No alloc-and-init function exists for private GEM objects.
- </para>
</sect3>
<sect3>
<title>GEM Objects Lifetime</title>
@@ -635,10 +660,10 @@ char *date;</synopsis>
acquired and release by <function>calling drm_gem_object_reference</function>
and <function>drm_gem_object_unreference</function> respectively. The
caller must hold the <structname>drm_device</structname>
- <structfield>struct_mutex</structfield> lock. As a convenience, GEM
- provides the <function>drm_gem_object_reference_unlocked</function> and
- <function>drm_gem_object_unreference_unlocked</function> functions that
- can be called without holding the lock.
+ <structfield>struct_mutex</structfield> lock when calling
+ <function>drm_gem_object_reference</function>. As a convenience, GEM
+ provides <function>drm_gem_object_unreference_unlocked</function>
+ functions that can be called without holding the lock.
</para>
<para>
When the last reference to a GEM object is released the GEM core calls
@@ -649,15 +674,9 @@ char *date;</synopsis>
</para>
<para>
<synopsis>void (*gem_free_object) (struct drm_gem_object *obj);</synopsis>
- Drivers are responsible for freeing all GEM object resources, including
- the resources created by the GEM core. If an mmap offset has been
- created for the object (in which case
- <structname>drm_gem_object</structname>::<structfield>map_list</structfield>::<structfield>map</structfield>
- is not NULL) it must be freed by a call to
- <function>drm_gem_free_mmap_offset</function>. The shmfs backing store
- must be released by calling <function>drm_gem_object_release</function>
- (that function can safely be called if no shmfs backing store has been
- created).
+ Drivers are responsible for freeing all GEM object resources. This includes
+ the resources created by the GEM core, which need to be released with
+ <function>drm_gem_object_release</function>.
</para>
</sect3>
<sect3>
@@ -740,17 +759,10 @@ char *date;</synopsis>
DRM identifies the GEM object to be mapped by a fake offset passed
through the mmap offset argument. Prior to being mapped, a GEM object
must thus be associated with a fake offset. To do so, drivers must call
- <function>drm_gem_create_mmap_offset</function> on the object. The
- function allocates a fake offset range from a pool and stores the
- offset divided by PAGE_SIZE in
- <literal>obj-&gt;map_list.hash.key</literal>. Care must be taken not to
- call <function>drm_gem_create_mmap_offset</function> if a fake offset
- has already been allocated for the object. This can be tested by
- <literal>obj-&gt;map_list.map</literal> being non-NULL.
+ <function>drm_gem_create_mmap_offset</function> on the object.
</para>
<para>
Once allocated, the fake offset value
- (<literal>obj-&gt;map_list.hash.key &lt;&lt; PAGE_SHIFT</literal>)
must be passed to the application in a driver-specific way and can then
be used as the mmap offset argument.
</para>
@@ -836,10 +848,11 @@ char *date;</synopsis>
abstracted from the client in libdrm.
</para>
</sect3>
- <sect3>
- <title>GEM Function Reference</title>
+ </sect2>
+ <sect2>
+ <title>GEM Function Reference</title>
!Edrivers/gpu/drm/drm_gem.c
- </sect3>
+!Iinclude/drm/drm_gem.h
</sect2>
<sect2>
<title>VMA Offset Manager</title>
@@ -970,12 +983,10 @@ int max_width, max_height;</synopsis>
<sect2>
<title>Atomic Mode Setting Function Reference</title>
!Edrivers/gpu/drm/drm_atomic.c
+!Idrivers/gpu/drm/drm_atomic.c
</sect2>
<sect2>
- <title>Frame Buffer Creation</title>
- <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
- struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd);</synopsis>
+ <title>Frame Buffer Abstraction</title>
<para>
Frame buffers are abstract memory objects that provide a source of
pixels to scanout to a CRTC. Applications explicitly request the
@@ -994,73 +1005,6 @@ int max_width, max_height;</synopsis>
and so expects TTM handles in the create ioctl and not GEM handles.
</para>
<para>
- Drivers must first validate the requested frame buffer parameters passed
- through the mode_cmd argument. In particular this is where invalid
- sizes, pixel formats or pitches can be caught.
- </para>
- <para>
- If the parameters are deemed valid, drivers then create, initialize and
- return an instance of struct <structname>drm_framebuffer</structname>.
- If desired the instance can be embedded in a larger driver-specific
- structure. Drivers must fill its <structfield>width</structfield>,
- <structfield>height</structfield>, <structfield>pitches</structfield>,
- <structfield>offsets</structfield>, <structfield>depth</structfield>,
- <structfield>bits_per_pixel</structfield> and
- <structfield>pixel_format</structfield> fields from the values passed
- through the <parameter>drm_mode_fb_cmd2</parameter> argument. They
- should call the <function>drm_helper_mode_fill_fb_struct</function>
- helper function to do so.
- </para>
-
- <para>
- The initialization of the new framebuffer instance is finalized with a
- call to <function>drm_framebuffer_init</function> which takes a pointer
- to DRM frame buffer operations (struct
- <structname>drm_framebuffer_funcs</structname>). Note that this function
- publishes the framebuffer and so from this point on it can be accessed
- concurrently from other threads. Hence it must be the last step in the
- driver's framebuffer initialization sequence. Frame buffer operations
- are
- <itemizedlist>
- <listitem>
- <synopsis>int (*create_handle)(struct drm_framebuffer *fb,
- struct drm_file *file_priv, unsigned int *handle);</synopsis>
- <para>
- Create a handle to the frame buffer underlying memory object. If
- the frame buffer uses a multi-plane format, the handle will
- reference the memory object associated with the first plane.
- </para>
- <para>
- Drivers call <function>drm_gem_handle_create</function> to create
- the handle.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*destroy)(struct drm_framebuffer *framebuffer);</synopsis>
- <para>
- Destroy the frame buffer object and frees all associated
- resources. Drivers must call
- <function>drm_framebuffer_cleanup</function> to free resources
- allocated by the DRM core for the frame buffer object, and must
- make sure to unreference all memory objects associated with the
- frame buffer. Handles created by the
- <methodname>create_handle</methodname> operation are released by
- the DRM core.
- </para>
- </listitem>
- <listitem>
- <synopsis>int (*dirty)(struct drm_framebuffer *framebuffer,
- struct drm_file *file_priv, unsigned flags, unsigned color,
- struct drm_clip_rect *clips, unsigned num_clips);</synopsis>
- <para>
- This optional operation notifies the driver that a region of the
- frame buffer has changed in response to a DRM_IOCTL_MODE_DIRTYFB
- ioctl call.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
The lifetime of a drm framebuffer is controlled with a reference count,
drivers can grab additional references with
<function>drm_framebuffer_reference</function>and drop them
@@ -1197,137 +1141,6 @@ int max_width, max_height;</synopsis>
pointer to CRTC functions.
</para>
</sect3>
- <sect3 id="drm-kms-crtcops">
- <title>CRTC Operations</title>
- <sect4>
- <title>Set Configuration</title>
- <synopsis>int (*set_config)(struct drm_mode_set *set);</synopsis>
- <para>
- Apply a new CRTC configuration to the device. The configuration
- specifies a CRTC, a frame buffer to scan out from, a (x,y) position in
- the frame buffer, a display mode and an array of connectors to drive
- with the CRTC if possible.
- </para>
- <para>
- If the frame buffer specified in the configuration is NULL, the driver
- must detach all encoders connected to the CRTC and all connectors
- attached to those encoders and disable them.
- </para>
- <para>
- This operation is called with the mode config lock held.
- </para>
- <note><para>
- Note that the drm core has no notion of restoring the mode setting
- state after resume, since all resume handling is in the full
- responsibility of the driver. The common mode setting helper library
- though provides a helper which can be used for this:
- <function>drm_helper_resume_force_mode</function>.
- </para></note>
- </sect4>
- <sect4>
- <title>Page Flipping</title>
- <synopsis>int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event);</synopsis>
- <para>
- Schedule a page flip to the given frame buffer for the CRTC. This
- operation is called with the mode config mutex held.
- </para>
- <para>
- Page flipping is a synchronization mechanism that replaces the frame
- buffer being scanned out by the CRTC with a new frame buffer during
- vertical blanking, avoiding tearing. When an application requests a page
- flip the DRM core verifies that the new frame buffer is large enough to
- be scanned out by the CRTC in the currently configured mode and then
- calls the CRTC <methodname>page_flip</methodname> operation with a
- pointer to the new frame buffer.
- </para>
- <para>
- The <methodname>page_flip</methodname> operation schedules a page flip.
- Once any pending rendering targeting the new frame buffer has
- completed, the CRTC will be reprogrammed to display that frame buffer
- after the next vertical refresh. The operation must return immediately
- without waiting for rendering or page flip to complete and must block
- any new rendering to the frame buffer until the page flip completes.
- </para>
- <para>
- If a page flip can be successfully scheduled the driver must set the
- <code>drm_crtc-&gt;fb</code> field to the new framebuffer pointed to
- by <code>fb</code>. This is important so that the reference counting
- on framebuffers stays balanced.
- </para>
- <para>
- If a page flip is already pending, the
- <methodname>page_flip</methodname> operation must return
- -<errorname>EBUSY</errorname>.
- </para>
- <para>
- To synchronize page flip to vertical blanking the driver will likely
- need to enable vertical blanking interrupts. It should call
- <function>drm_vblank_get</function> for that purpose, and call
- <function>drm_vblank_put</function> after the page flip completes.
- </para>
- <para>
- If the application has requested to be notified when page flip completes
- the <methodname>page_flip</methodname> operation will be called with a
- non-NULL <parameter>event</parameter> argument pointing to a
- <structname>drm_pending_vblank_event</structname> instance. Upon page
- flip completion the driver must call <methodname>drm_send_vblank_event</methodname>
- to fill in the event and send to wake up any waiting processes.
- This can be performed with
- <programlisting><![CDATA[
- spin_lock_irqsave(&dev->event_lock, flags);
- ...
- drm_send_vblank_event(dev, pipe, event);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- ]]></programlisting>
- </para>
- <note><para>
- FIXME: Could drivers that don't need to wait for rendering to complete
- just add the event to <literal>dev-&gt;vblank_event_list</literal> and
- let the DRM core handle everything, as for "normal" vertical blanking
- events?
- </para></note>
- <para>
- While waiting for the page flip to complete, the
- <literal>event-&gt;base.link</literal> list head can be used freely by
- the driver to store the pending event in a driver-specific list.
- </para>
- <para>
- If the file handle is closed before the event is signaled, drivers must
- take care to destroy the event in their
- <methodname>preclose</methodname> operation (and, if needed, call
- <function>drm_vblank_put</function>).
- </para>
- </sect4>
- <sect4>
- <title>Miscellaneous</title>
- <itemizedlist>
- <listitem>
- <synopsis>void (*set_property)(struct drm_crtc *crtc,
- struct drm_property *property, uint64_t value);</synopsis>
- <para>
- Set the value of the given CRTC property to
- <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
- for more information about properties.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
- uint32_t start, uint32_t size);</synopsis>
- <para>
- Apply a gamma table to the device. The operation is optional.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*destroy)(struct drm_crtc *crtc);</synopsis>
- <para>
- Destroy the CRTC when not needed anymore. See
- <xref linkend="drm-kms-init"/>.
- </para>
- </listitem>
- </itemizedlist>
- </sect4>
- </sect3>
</sect2>
<sect2>
<title>Planes (struct <structname>drm_plane</structname>)</title>
@@ -1344,7 +1157,7 @@ int max_width, max_height;</synopsis>
<listitem>
DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC. Primary
planes are the planes operated upon by CRTC modesetting and flipping
- operations described in <xref linkend="drm-kms-crtcops"/>.
+ operations described in the page_flip hook in <structname>drm_crtc_funcs</structname>.
</listitem>
<listitem>
DRM_PLANE_TYPE_CURSOR represents a "cursor" plane for a CRTC. Cursor
@@ -1381,52 +1194,6 @@ int max_width, max_height;</synopsis>
primary plane with standard capabilities.
</para>
</sect3>
- <sect3>
- <title>Plane Operations</title>
- <itemizedlist>
- <listitem>
- <synopsis>int (*update_plane)(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h);</synopsis>
- <para>
- Enable and configure the plane to use the given CRTC and frame buffer.
- </para>
- <para>
- The source rectangle in frame buffer memory coordinates is given by
- the <parameter>src_x</parameter>, <parameter>src_y</parameter>,
- <parameter>src_w</parameter> and <parameter>src_h</parameter>
- parameters (as 16.16 fixed point values). Devices that don't support
- subpixel plane coordinates can ignore the fractional part.
- </para>
- <para>
- The destination rectangle in CRTC coordinates is given by the
- <parameter>crtc_x</parameter>, <parameter>crtc_y</parameter>,
- <parameter>crtc_w</parameter> and <parameter>crtc_h</parameter>
- parameters (as integer values). Devices scale the source rectangle to
- the destination rectangle. If scaling is not supported, and the source
- rectangle size doesn't match the destination rectangle size, the
- driver must return a -<errorname>EINVAL</errorname> error.
- </para>
- </listitem>
- <listitem>
- <synopsis>int (*disable_plane)(struct drm_plane *plane);</synopsis>
- <para>
- Disable the plane. The DRM core calls this method in response to a
- DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set to 0.
- Disabled planes must not be processed by the CRTC.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*destroy)(struct drm_plane *plane);</synopsis>
- <para>
- Destroy the plane when not needed anymore. See
- <xref linkend="drm-kms-init"/>.
- </para>
- </listitem>
- </itemizedlist>
- </sect3>
</sect2>
<sect2>
<title>Encoders (struct <structname>drm_encoder</structname>)</title>
@@ -1483,27 +1250,6 @@ int max_width, max_height;</synopsis>
encoders they want to use to a CRTC.
</para>
</sect3>
- <sect3>
- <title>Encoder Operations</title>
- <itemizedlist>
- <listitem>
- <synopsis>void (*destroy)(struct drm_encoder *encoder);</synopsis>
- <para>
- Called to destroy the encoder when not needed anymore. See
- <xref linkend="drm-kms-init"/>.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*set_property)(struct drm_plane *plane,
- struct drm_property *property, uint64_t value);</synopsis>
- <para>
- Set the value of the given plane property to
- <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
- for more information about properties.
- </para>
- </listitem>
- </itemizedlist>
- </sect3>
</sect2>
<sect2>
<title>Connectors (struct <structname>drm_connector</structname>)</title>
@@ -1707,27 +1453,6 @@ int max_width, max_height;</synopsis>
connector_status_unknown.
</para>
</sect4>
- <sect4>
- <title>Miscellaneous</title>
- <itemizedlist>
- <listitem>
- <synopsis>void (*set_property)(struct drm_connector *connector,
- struct drm_property *property, uint64_t value);</synopsis>
- <para>
- Set the value of the given connector property to
- <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
- for more information about properties.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*destroy)(struct drm_connector *connector);</synopsis>
- <para>
- Destroy the connector when not needed anymore. See
- <xref linkend="drm-kms-init"/>.
- </para>
- </listitem>
- </itemizedlist>
- </sect4>
</sect3>
</sect2>
<sect2>
@@ -1854,462 +1579,6 @@ void intel_crt_init(struct drm_device *dev)
entities.
</para>
<sect2>
- <title>Helper Functions</title>
- <itemizedlist>
- <listitem>
- <synopsis>int drm_crtc_helper_set_config(struct drm_mode_set *set);</synopsis>
- <para>
- The <function>drm_crtc_helper_set_config</function> helper function
- is a CRTC <methodname>set_config</methodname> implementation. It
- first tries to locate the best encoder for each connector by calling
- the connector <methodname>best_encoder</methodname> helper
- operation.
- </para>
- <para>
- After locating the appropriate encoders, the helper function will
- call the <methodname>mode_fixup</methodname> encoder and CRTC helper
- operations to adjust the requested mode, or reject it completely in
- which case an error will be returned to the application. If the new
- configuration after mode adjustment is identical to the current
- configuration the helper function will return without performing any
- other operation.
- </para>
- <para>
- If the adjusted mode is identical to the current mode but changes to
- the frame buffer need to be applied, the
- <function>drm_crtc_helper_set_config</function> function will call
- the CRTC <methodname>mode_set_base</methodname> helper operation. If
- the adjusted mode differs from the current mode, or if the
- <methodname>mode_set_base</methodname> helper operation is not
- provided, the helper function performs a full mode set sequence by
- calling the <methodname>prepare</methodname>,
- <methodname>mode_set</methodname> and
- <methodname>commit</methodname> CRTC and encoder helper operations,
- in that order.
- </para>
- </listitem>
- <listitem>
- <synopsis>void drm_helper_connector_dpms(struct drm_connector *connector, int mode);</synopsis>
- <para>
- The <function>drm_helper_connector_dpms</function> helper function
- is a connector <methodname>dpms</methodname> implementation that
- tracks power state of connectors. To use the function, drivers must
- provide <methodname>dpms</methodname> helper operations for CRTCs
- and encoders to apply the DPMS state to the device.
- </para>
- <para>
- The mid-layer doesn't track the power state of CRTCs and encoders.
- The <methodname>dpms</methodname> helper operations can thus be
- called with a mode identical to the currently active mode.
- </para>
- </listitem>
- <listitem>
- <synopsis>int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
- uint32_t maxX, uint32_t maxY);</synopsis>
- <para>
- The <function>drm_helper_probe_single_connector_modes</function> helper
- function is a connector <methodname>fill_modes</methodname>
- implementation that updates the connection status for the connector
- and then retrieves a list of modes by calling the connector
- <methodname>get_modes</methodname> helper operation.
- </para>
- <para>
- If the helper operation returns no mode, and if the connector status
- is connector_status_connected, standard VESA DMT modes up to
- 1024x768 are automatically added to the modes list by a call to
- <function>drm_add_modes_noedid</function>.
- </para>
- <para>
- The function then filters out modes larger than
- <parameter>max_width</parameter> and <parameter>max_height</parameter>
- if specified. It finally calls the optional connector
- <methodname>mode_valid</methodname> helper operation for each mode in
- the probed list to check whether the mode is valid for the connector.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2>
- <title>CRTC Helper Operations</title>
- <itemizedlist>
- <listitem id="drm-helper-crtc-mode-fixup">
- <synopsis>bool (*mode_fixup)(struct drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);</synopsis>
- <para>
- Let CRTCs adjust the requested mode or reject it completely. This
- operation returns true if the mode is accepted (possibly after being
- adjusted) or false if it is rejected.
- </para>
- <para>
- The <methodname>mode_fixup</methodname> operation should reject the
- mode if it can't reasonably use it. The definition of "reasonable"
- is currently fuzzy in this context. One possible behaviour would be
- to set the adjusted mode to the panel timings when a fixed-mode
- panel is used with hardware capable of scaling. Another behaviour
- would be to accept any input mode and adjust it to the closest mode
- supported by the hardware (FIXME: This needs to be clarified).
- </para>
- </listitem>
- <listitem>
- <synopsis>int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)</synopsis>
- <para>
- Move the CRTC on the current frame buffer (stored in
- <literal>crtc-&gt;fb</literal>) to position (x,y). Any of the frame
- buffer, x position or y position may have been modified.
- </para>
- <para>
- This helper operation is optional. If not provided, the
- <function>drm_crtc_helper_set_config</function> function will fall
- back to the <methodname>mode_set</methodname> helper operation.
- </para>
- <note><para>
- FIXME: Why are x and y passed as arguments, as they can be accessed
- through <literal>crtc-&gt;x</literal> and
- <literal>crtc-&gt;y</literal>?
- </para></note>
- </listitem>
- <listitem>
- <synopsis>void (*prepare)(struct drm_crtc *crtc);</synopsis>
- <para>
- Prepare the CRTC for mode setting. This operation is called after
- validating the requested mode. Drivers use it to perform
- device-specific operations required before setting the new mode.
- </para>
- </listitem>
- <listitem>
- <synopsis>int (*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);</synopsis>
- <para>
- Set a new mode, position and frame buffer. Depending on the device
- requirements, the mode can be stored internally by the driver and
- applied in the <methodname>commit</methodname> operation, or
- programmed to the hardware immediately.
- </para>
- <para>
- The <methodname>mode_set</methodname> operation returns 0 on success
- or a negative error code if an error occurs.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*commit)(struct drm_crtc *crtc);</synopsis>
- <para>
- Commit a mode. This operation is called after setting the new mode.
- Upon return the device must use the new mode and be fully
- operational.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2>
- <title>Encoder Helper Operations</title>
- <itemizedlist>
- <listitem>
- <synopsis>bool (*mode_fixup)(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);</synopsis>
- <para>
- Let encoders adjust the requested mode or reject it completely. This
- operation returns true if the mode is accepted (possibly after being
- adjusted) or false if it is rejected. See the
- <link linkend="drm-helper-crtc-mode-fixup">mode_fixup CRTC helper
- operation</link> for an explanation of the allowed adjustments.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*prepare)(struct drm_encoder *encoder);</synopsis>
- <para>
- Prepare the encoder for mode setting. This operation is called after
- validating the requested mode. Drivers use it to perform
- device-specific operations required before setting the new mode.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*mode_set)(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);</synopsis>
- <para>
- Set a new mode. Depending on the device requirements, the mode can
- be stored internally by the driver and applied in the
- <methodname>commit</methodname> operation, or programmed to the
- hardware immediately.
- </para>
- </listitem>
- <listitem>
- <synopsis>void (*commit)(struct drm_encoder *encoder);</synopsis>
- <para>
- Commit a mode. This operation is called after setting the new mode.
- Upon return the device must use the new mode and be fully
- operational.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2>
- <title>Connector Helper Operations</title>
- <itemizedlist>
- <listitem>
- <synopsis>struct drm_encoder *(*best_encoder)(struct drm_connector *connector);</synopsis>
- <para>
- Return a pointer to the best encoder for the connecter. Device that
- map connectors to encoders 1:1 simply return the pointer to the
- associated encoder. This operation is mandatory.
- </para>
- </listitem>
- <listitem>
- <synopsis>int (*get_modes)(struct drm_connector *connector);</synopsis>
- <para>
- Fill the connector's <structfield>probed_modes</structfield> list
- by parsing EDID data with <function>drm_add_edid_modes</function>,
- adding standard VESA DMT modes with <function>drm_add_modes_noedid</function>,
- or calling <function>drm_mode_probed_add</function> directly for every
- supported mode and return the number of modes it has detected. This
- operation is mandatory.
- </para>
- <para>
- Note that the caller function will automatically add standard VESA
- DMT modes up to 1024x768 if the <methodname>get_modes</methodname>
- helper operation returns no mode and if the connector status is
- connector_status_connected. There is no need to call
- <function>drm_add_edid_modes</function> manually in that case.
- </para>
- <para>
- When adding modes manually the driver creates each mode with a call to
- <function>drm_mode_create</function> and must fill the following fields.
- <itemizedlist>
- <listitem>
- <synopsis>__u32 type;</synopsis>
- <para>
- Mode type bitmask, a combination of
- <variablelist>
- <varlistentry>
- <term>DRM_MODE_TYPE_BUILTIN</term>
- <listitem><para>not used?</para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_TYPE_CLOCK_C</term>
- <listitem><para>not used?</para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_TYPE_CRTC_C</term>
- <listitem><para>not used?</para></listitem>
- </varlistentry>
- <varlistentry>
- <term>
- DRM_MODE_TYPE_PREFERRED - The preferred mode for the connector
- </term>
- <listitem>
- <para>not used?</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_TYPE_DEFAULT</term>
- <listitem><para>not used?</para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_TYPE_USERDEF</term>
- <listitem><para>not used?</para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_TYPE_DRIVER</term>
- <listitem>
- <para>
- The mode has been created by the driver (as opposed to
- to user-created modes).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- Drivers must set the DRM_MODE_TYPE_DRIVER bit for all modes they
- create, and set the DRM_MODE_TYPE_PREFERRED bit for the preferred
- mode.
- </para>
- </listitem>
- <listitem>
- <synopsis>__u32 clock;</synopsis>
- <para>Pixel clock frequency in kHz unit</para>
- </listitem>
- <listitem>
- <synopsis>__u16 hdisplay, hsync_start, hsync_end, htotal;
- __u16 vdisplay, vsync_start, vsync_end, vtotal;</synopsis>
- <para>Horizontal and vertical timing information</para>
- <screen><![CDATA[
- Active Front Sync Back
- Region Porch Porch
- <-----------------------><----------------><-------------><-------------->
-
- //////////////////////|
- ////////////////////// |
- ////////////////////// |.................. ................
- _______________
-
- <----- [hv]display ----->
- <------------- [hv]sync_start ------------>
- <--------------------- [hv]sync_end --------------------->
- <-------------------------------- [hv]total ----------------------------->
-]]></screen>
- </listitem>
- <listitem>
- <synopsis>__u16 hskew;
- __u16 vscan;</synopsis>
- <para>Unknown</para>
- </listitem>
- <listitem>
- <synopsis>__u32 flags;</synopsis>
- <para>
- Mode flags, a combination of
- <variablelist>
- <varlistentry>
- <term>DRM_MODE_FLAG_PHSYNC</term>
- <listitem><para>
- Horizontal sync is active high
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_NHSYNC</term>
- <listitem><para>
- Horizontal sync is active low
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_PVSYNC</term>
- <listitem><para>
- Vertical sync is active high
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_NVSYNC</term>
- <listitem><para>
- Vertical sync is active low
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_INTERLACE</term>
- <listitem><para>
- Mode is interlaced
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_DBLSCAN</term>
- <listitem><para>
- Mode uses doublescan
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_CSYNC</term>
- <listitem><para>
- Mode uses composite sync
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_PCSYNC</term>
- <listitem><para>
- Composite sync is active high
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_NCSYNC</term>
- <listitem><para>
- Composite sync is active low
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_HSKEW</term>
- <listitem><para>
- hskew provided (not used?)
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_BCAST</term>
- <listitem><para>
- not used?
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_PIXMUX</term>
- <listitem><para>
- not used?
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_DBLCLK</term>
- <listitem><para>
- not used?
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term>DRM_MODE_FLAG_CLKDIV2</term>
- <listitem><para>
- ?
- </para></listitem>
- </varlistentry>
- </variablelist>
- </para>
- <para>
- Note that modes marked with the INTERLACE or DBLSCAN flags will be
- filtered out by
- <function>drm_helper_probe_single_connector_modes</function> if
- the connector's <structfield>interlace_allowed</structfield> or
- <structfield>doublescan_allowed</structfield> field is set to 0.
- </para>
- </listitem>
- <listitem>
- <synopsis>char name[DRM_DISPLAY_MODE_LEN];</synopsis>
- <para>
- Mode name. The driver must call
- <function>drm_mode_set_name</function> to fill the mode name from
- <structfield>hdisplay</structfield>,
- <structfield>vdisplay</structfield> and interlace flag after
- filling the corresponding fields.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The <structfield>vrefresh</structfield> value is computed by
- <function>drm_helper_probe_single_connector_modes</function>.
- </para>
- <para>
- When parsing EDID data, <function>drm_add_edid_modes</function> fills the
- connector <structfield>display_info</structfield>
- <structfield>width_mm</structfield> and
- <structfield>height_mm</structfield> fields. When creating modes
- manually the <methodname>get_modes</methodname> helper operation must
- set the <structfield>display_info</structfield>
- <structfield>width_mm</structfield> and
- <structfield>height_mm</structfield> fields if they haven't been set
- already (for instance at initialization time when a fixed-size panel is
- attached to the connector). The mode <structfield>width_mm</structfield>
- and <structfield>height_mm</structfield> fields are only used internally
- during EDID parsing and should not be set when creating modes manually.
- </para>
- </listitem>
- <listitem>
- <synopsis>int (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);</synopsis>
- <para>
- Verify whether a mode is valid for the connector. Return MODE_OK for
- supported modes and one of the enum drm_mode_status values (MODE_*)
- for unsupported modes. This operation is optional.
- </para>
- <para>
- As the mode rejection reason is currently not used beside for
- immediately removing the unsupported mode, an implementation can
- return MODE_BAD regardless of the exact reason why the mode is not
- valid.
- </para>
- <note><para>
- Note that the <methodname>mode_valid</methodname> helper operation is
- only called for modes detected by the device, and
- <emphasis>not</emphasis> for modes set by the user through the CRTC
- <methodname>set_config</methodname> operation.
- </para></note>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2>
<title>Atomic Modeset Helper Functions Reference</title>
<sect3>
<title>Overview</title>
@@ -2327,8 +1596,12 @@ void intel_crt_init(struct drm_device *dev)
!Edrivers/gpu/drm/drm_atomic_helper.c
</sect2>
<sect2>
- <title>Modeset Helper Functions Reference</title>
-!Iinclude/drm/drm_crtc_helper.h
+ <title>Modeset Helper Reference for Common Vtables</title>
+!Iinclude/drm/drm_modeset_helper_vtables.h
+!Pinclude/drm/drm_modeset_helper_vtables.h overview
+ </sect2>
+ <sect2>
+ <title>Legacy CRTC/Modeset Helper Functions Reference</title>
!Edrivers/gpu/drm/drm_crtc_helper.c
!Pdrivers/gpu/drm/drm_crtc_helper.c overview
</sect2>
@@ -4039,92 +3312,6 @@ int num_ioctls;</synopsis>
<sect2>
<title>DPIO</title>
!Pdrivers/gpu/drm/i915/i915_reg.h DPIO
- <table id="dpiox2">
- <title>Dual channel PHY (VLV/CHV/BXT)</title>
- <tgroup cols="8">
- <colspec colname="c0" />
- <colspec colname="c1" />
- <colspec colname="c2" />
- <colspec colname="c3" />
- <colspec colname="c4" />
- <colspec colname="c5" />
- <colspec colname="c6" />
- <colspec colname="c7" />
- <spanspec spanname="ch0" namest="c0" nameend="c3" />
- <spanspec spanname="ch1" namest="c4" nameend="c7" />
- <spanspec spanname="ch0pcs01" namest="c0" nameend="c1" />
- <spanspec spanname="ch0pcs23" namest="c2" nameend="c3" />
- <spanspec spanname="ch1pcs01" namest="c4" nameend="c5" />
- <spanspec spanname="ch1pcs23" namest="c6" nameend="c7" />
- <thead>
- <row>
- <entry spanname="ch0">CH0</entry>
- <entry spanname="ch1">CH1</entry>
- </row>
- </thead>
- <tbody valign="top" align="center">
- <row>
- <entry spanname="ch0">CMN/PLL/REF</entry>
- <entry spanname="ch1">CMN/PLL/REF</entry>
- </row>
- <row>
- <entry spanname="ch0pcs01">PCS01</entry>
- <entry spanname="ch0pcs23">PCS23</entry>
- <entry spanname="ch1pcs01">PCS01</entry>
- <entry spanname="ch1pcs23">PCS23</entry>
- </row>
- <row>
- <entry>TX0</entry>
- <entry>TX1</entry>
- <entry>TX2</entry>
- <entry>TX3</entry>
- <entry>TX0</entry>
- <entry>TX1</entry>
- <entry>TX2</entry>
- <entry>TX3</entry>
- </row>
- <row>
- <entry spanname="ch0">DDI0</entry>
- <entry spanname="ch1">DDI1</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <table id="dpiox1">
- <title>Single channel PHY (CHV/BXT)</title>
- <tgroup cols="4">
- <colspec colname="c0" />
- <colspec colname="c1" />
- <colspec colname="c2" />
- <colspec colname="c3" />
- <spanspec spanname="ch0" namest="c0" nameend="c3" />
- <spanspec spanname="ch0pcs01" namest="c0" nameend="c1" />
- <spanspec spanname="ch0pcs23" namest="c2" nameend="c3" />
- <thead>
- <row>
- <entry spanname="ch0">CH0</entry>
- </row>
- </thead>
- <tbody valign="top" align="center">
- <row>
- <entry spanname="ch0">CMN/PLL/REF</entry>
- </row>
- <row>
- <entry spanname="ch0pcs01">PCS01</entry>
- <entry spanname="ch0pcs23">PCS23</entry>
- </row>
- <row>
- <entry>TX0</entry>
- <entry>TX1</entry>
- <entry>TX2</entry>
- <entry>TX3</entry>
- </row>
- <row>
- <entry spanname="ch0">DDI2</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
</sect2>
<sect2>
@@ -4201,17 +3388,21 @@ int num_ioctls;</synopsis>
</sect2>
</sect1>
<sect1>
- <title>GuC-based Command Submission</title>
+ <title>GuC</title>
<sect2>
- <title>GuC</title>
+ <title>GuC-specific firmware loader</title>
!Pdrivers/gpu/drm/i915/intel_guc_loader.c GuC-specific firmware loader
!Idrivers/gpu/drm/i915/intel_guc_loader.c
</sect2>
<sect2>
- <title>GuC Client</title>
-!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submissison
+ <title>GuC-based command submission</title>
+!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submission
!Idrivers/gpu/drm/i915/i915_guc_submission.c
</sect2>
+ <sect2>
+ <title>GuC Firmware Layout</title>
+!Pdrivers/gpu/drm/i915/intel_guc_fwif.h GuC Firmware Layout
+ </sect2>
</sect1>
<sect1>
@@ -4246,41 +3437,63 @@ int num_ioctls;</synopsis>
<chapter id="modes_of_use">
<title>Modes of Use</title>
- <sect1>
- <title>Manual switching and manual power control</title>
+ <sect1>
+ <title>Manual switching and manual power control</title>
!Pdrivers/gpu/vga/vga_switcheroo.c Manual switching and manual power control
- </sect1>
- <sect1>
- <title>Driver power control</title>
+ </sect1>
+ <sect1>
+ <title>Driver power control</title>
!Pdrivers/gpu/vga/vga_switcheroo.c Driver power control
- </sect1>
+ </sect1>
</chapter>
- <chapter id="pubfunctions">
- <title>Public functions</title>
+ <chapter id="api">
+ <title>API</title>
+ <sect1>
+ <title>Public functions</title>
!Edrivers/gpu/vga/vga_switcheroo.c
- </chapter>
-
- <chapter id="pubstructures">
- <title>Public structures</title>
+ </sect1>
+ <sect1>
+ <title>Public structures</title>
!Finclude/linux/vga_switcheroo.h vga_switcheroo_handler
!Finclude/linux/vga_switcheroo.h vga_switcheroo_client_ops
- </chapter>
-
- <chapter id="pubconstants">
- <title>Public constants</title>
+ </sect1>
+ <sect1>
+ <title>Public constants</title>
!Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id
!Finclude/linux/vga_switcheroo.h vga_switcheroo_state
- </chapter>
-
- <chapter id="privstructures">
- <title>Private structures</title>
+ </sect1>
+ <sect1>
+ <title>Private structures</title>
!Fdrivers/gpu/vga/vga_switcheroo.c vgasr_priv
!Fdrivers/gpu/vga/vga_switcheroo.c vga_switcheroo_client
+ </sect1>
+ </chapter>
+
+ <chapter id="handlers">
+ <title>Handlers</title>
+ <sect1>
+ <title>apple-gmux Handler</title>
+!Pdrivers/platform/x86/apple-gmux.c Overview
+!Pdrivers/platform/x86/apple-gmux.c Interrupt
+ <sect2>
+ <title>Graphics mux</title>
+!Pdrivers/platform/x86/apple-gmux.c Graphics mux
+ </sect2>
+ <sect2>
+ <title>Power control</title>
+!Pdrivers/platform/x86/apple-gmux.c Power control
+ </sect2>
+ <sect2>
+ <title>Backlight control</title>
+!Pdrivers/platform/x86/apple-gmux.c Backlight control
+ </sect2>
+ </sect1>
</chapter>
!Cdrivers/gpu/vga/vga_switcheroo.c
!Cinclude/linux/vga_switcheroo.h
+!Cdrivers/platform/x86/apple-gmux.c
</part>
</book>
diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl
index 98be322673da..f525bf56d1dd 100644
--- a/Documentation/DocBook/iio.tmpl
+++ b/Documentation/DocBook/iio.tmpl
@@ -458,7 +458,7 @@
.scan_type = {
.sign = 's',
.realbits = 12,
- .storgebits = 16,
+ .storagebits = 16,
.shift = 4,
.endianness = IIO_LE,
},
diff --git a/Documentation/DocBook/media/v4l/media-controller.xml b/Documentation/DocBook/media/v4l/media-controller.xml
index 873ac3a621f0..5f2fc07a93d7 100644
--- a/Documentation/DocBook/media/v4l/media-controller.xml
+++ b/Documentation/DocBook/media/v4l/media-controller.xml
@@ -58,21 +58,36 @@
<title>Media device model</title>
<para>Discovering a device internal topology, and configuring it at runtime,
is one of the goals of the media controller API. To achieve this, hardware
- devices are modelled as an oriented graph of building blocks called entities
- connected through pads.</para>
- <para>An entity is a basic media hardware or software building block. It can
- correspond to a large variety of logical blocks such as physical hardware
- devices (CMOS sensor for instance), logical hardware devices (a building
- block in a System-on-Chip image processing pipeline), DMA channels or
- physical connectors.</para>
- <para>A pad is a connection endpoint through which an entity can interact
- with other entities. Data (not restricted to video) produced by an entity
- flows from the entity's output to one or more entity inputs. Pads should not
- be confused with physical pins at chip boundaries.</para>
- <para>A link is a point-to-point oriented connection between two pads,
- either on the same entity or on different entities. Data flows from a source
- pad to a sink pad.</para>
+ devices and Linux Kernel interfaces are modelled as graph objects on
+ an oriented graph. The object types that constitute the graph are:</para>
+ <itemizedlist>
+ <listitem><para>An <emphasis role="bold">entity</emphasis>
+ is a basic media hardware or software building block. It can correspond to
+ a large variety of logical blocks such as physical hardware devices
+ (CMOS sensor for instance), logical hardware devices (a building block in
+ a System-on-Chip image processing pipeline), DMA channels or physical
+ connectors.</para></listitem>
+ <listitem><para>An <emphasis role="bold">interface</emphasis>
+ is a graph representation of a Linux Kernel userspace API interface,
+ like a device node or a sysfs file that controls one or more entities
+ in the graph.</para></listitem>
+ <listitem><para>A <emphasis role="bold">pad</emphasis>
+ is a data connection endpoint through which an entity can interact with
+ other entities. Data (not restricted to video) produced by an entity
+ flows from the entity's output to one or more entity inputs. Pads should
+ not be confused with physical pins at chip boundaries.</para></listitem>
+ <listitem><para>A <emphasis role="bold">data link</emphasis>
+ is a point-to-point oriented connection between two pads, either on the
+ same entity or on different entities. Data flows from a source pad to a
+ sink pad.</para></listitem>
+ <listitem><para>An <emphasis role="bold">interface link</emphasis>
+ is a point-to-point bidirectional control connection between a Linux
+ Kernel interface and an entity.m</para></listitem>
+ </itemizedlist>
</section>
+
+ <!-- All non-ioctl specific data types go here. -->
+ &sub-media-types;
</chapter>
<appendix id="media-user-func">
@@ -83,6 +98,7 @@
&sub-media-func-ioctl;
<!-- All ioctls go here. -->
&sub-media-ioc-device-info;
+ &sub-media-ioc-g-topology;
&sub-media-ioc-enum-entities;
&sub-media-ioc-enum-links;
&sub-media-ioc-setup-link;
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
index 5872f8bbf774..0c4f96bfc2de 100644
--- a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
+++ b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
@@ -59,15 +59,6 @@
<para>Entity IDs can be non-contiguous. Applications must
<emphasis>not</emphasis> try to enumerate entities by calling
MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
- <para>Two or more entities that share a common non-zero
- <structfield>group_id</structfield> value are considered as logically
- grouped. Groups are used to report
- <itemizedlist>
- <listitem><para>ALSA, VBI and video nodes that carry the same media
- stream</para></listitem>
- <listitem><para>lens and flash controllers associated with a sensor</para></listitem>
- </itemizedlist>
- </para>
<table pgwide="1" frame="none" id="media-entity-desc">
<title>struct <structname>media_entity_desc</structname></title>
@@ -106,7 +97,7 @@
<entry><structfield>revision</structfield></entry>
<entry></entry>
<entry></entry>
- <entry>Entity revision in a driver/hardware specific format.</entry>
+ <entry>Entity revision. Always zero (obsolete)</entry>
</row>
<row>
<entry>__u32</entry>
@@ -120,7 +111,7 @@
<entry><structfield>group_id</structfield></entry>
<entry></entry>
<entry></entry>
- <entry>Entity group ID</entry>
+ <entry>Entity group ID. Always zero (obsolete)</entry>
</row>
<row>
<entry>__u16</entry>
@@ -171,97 +162,6 @@
</tbody>
</tgroup>
</table>
-
- <table frame="none" pgwide="1" id="media-entity-type">
- <title>Media entity types</title>
- <tgroup cols="2">
- <colspec colname="c1"/>
- <colspec colname="c2"/>
- <tbody valign="top">
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE</constant></entry>
- <entry>Unknown device node</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_V4L</constant></entry>
- <entry>V4L video, radio or vbi device node</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_FB</constant></entry>
- <entry>Frame buffer device node</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_ALSA</constant></entry>
- <entry>ALSA card</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_FE</constant></entry>
- <entry>DVB frontend devnode</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_DEMUX</constant></entry>
- <entry>DVB demux devnode</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_DVR</constant></entry>
- <entry>DVB DVR devnode</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_CA</constant></entry>
- <entry>DVB CAM devnode</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_NET</constant></entry>
- <entry>DVB network devnode</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
- <entry>Unknown V4L sub-device</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_SENSOR</constant></entry>
- <entry>Video sensor</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_FLASH</constant></entry>
- <entry>Flash controller</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
- <entry>Lens controller</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_DECODER</constant></entry>
- <entry>Video decoder, the basic function of the video decoder is to
- accept analogue video from a wide variety of sources such as
- broadcast, DVD players, cameras and video cassette recorders, in
- either NTSC, PAL or HD format and still occasionally SECAM, separate
- it into its component parts, luminance and chrominance, and output
- it in some digital video standard, with appropriate embedded timing
- signals.</entry>
- </row>
- <row>
- <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_TUNER</constant></entry>
- <entry>TV and/or radio tuner</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table frame="none" pgwide="1" id="media-entity-flag">
- <title>Media entity flags</title>
- <tgroup cols="2">
- <colspec colname="c1"/>
- <colspec colname="c2"/>
- <tbody valign="top">
- <row>
- <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
- <entry>Default entity for its type. Used to discover the default
- audio, VBI and video devices, the default camera sensor, ...</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
</refsect1>
<refsect1>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml
index 74fb394ec667..2bbeea9f3e18 100644
--- a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml
+++ b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml
@@ -118,35 +118,6 @@
</tgroup>
</table>
- <table frame="none" pgwide="1" id="media-pad-flag">
- <title>Media pad flags</title>
- <tgroup cols="2">
- <colspec colname="c1"/>
- <colspec colname="c2"/>
- <tbody valign="top">
- <row>
- <entry><constant>MEDIA_PAD_FL_SINK</constant></entry>
- <entry>Input pad, relative to the entity. Input pads sink data and
- are targets of links.</entry>
- </row>
- <row>
- <entry><constant>MEDIA_PAD_FL_SOURCE</constant></entry>
- <entry>Output pad, relative to the entity. Output pads source data
- and are origins of links.</entry>
- </row>
- <row>
- <entry><constant>MEDIA_PAD_FL_MUST_CONNECT</constant></entry>
- <entry>If this flag is set and the pad is linked to any other
- pad, then at least one of those links must be enabled for the
- entity to be able to stream. There could be temporary reasons
- (e.g. device configuration dependent) for the pad to need
- enabled links even when this flag isn't set; the absence of the
- flag doesn't imply there is none.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
<table pgwide="1" frame="none" id="media-link-desc">
<title>struct <structname>media_link_desc</structname></title>
<tgroup cols="3">
@@ -171,33 +142,6 @@
</tgroup>
</table>
- <table frame="none" pgwide="1" id="media-link-flag">
- <title>Media link flags</title>
- <tgroup cols="2">
- <colspec colname="c1"/>
- <colspec colname="c2"/>
- <tbody valign="top">
- <row>
- <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
- <entry>The link is enabled and can be used to transfer media data.
- When two or more links target a sink pad, only one of them can be
- enabled at a time.</entry>
- </row>
- <row>
- <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
- <entry>The link enabled state can't be modified at runtime. An
- immutable link is always enabled.</entry>
- </row>
- <row>
- <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
- <entry>The link enabled state can be modified during streaming. This
- flag is set by drivers and is read-only for applications.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>One and only one of <constant>MEDIA_PAD_FL_SINK</constant> and
- <constant>MEDIA_PAD_FL_SOURCE</constant> must be set for every pad.</para>
</refsect1>
<refsect1>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-g-topology.xml b/Documentation/DocBook/media/v4l/media-ioc-g-topology.xml
new file mode 100644
index 000000000000..63152ab9efba
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/media-ioc-g-topology.xml
@@ -0,0 +1,394 @@
+<refentry id="media-g-topology">
+ <refmeta>
+ <refentrytitle>ioctl MEDIA_IOC_G_TOPOLOGY</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>MEDIA_IOC_G_TOPOLOGY</refname>
+ <refpurpose>Enumerate the graph topology and graph element properties</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct media_v2_topology *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>File descriptor returned by
+ <link linkend='media-func-open'><function>open()</function></link>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>MEDIA_IOC_G_TOPOLOGY</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><emphasis role="bold">NOTE:</emphasis> This new ioctl is programmed to be added on Kernel 4.6. Its definition/arguments may change until its final version.</para>
+
+ <para>The typical usage of this ioctl is to call it twice.
+ On the first call, the structure defined at &media-v2-topology; should
+ be zeroed. At return, if no errors happen, this ioctl will return the
+ <constant>topology_version</constant> and the total number of entities,
+ interfaces, pads and links.</para>
+ <para>Before the second call, the userspace should allocate arrays to
+ store the graph elements that are desired, putting the pointers to them
+ at the ptr_entities, ptr_interfaces, ptr_links and/or ptr_pads, keeping
+ the other values untouched.</para>
+ <para>If the <constant>topology_version</constant> remains the same, the
+ ioctl should fill the desired arrays with the media graph elements.</para>
+
+ <table pgwide="1" frame="none" id="media-v2-topology">
+ <title>struct <structname>media_v2_topology</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>topology_version</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Version of the media graph topology. When the graph is
+ created, this field starts with zero. Every time a graph
+ element is added or removed, this field is
+ incremented.</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>num_entities</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Number of entities in the graph</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>ptr_entities</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>A pointer to a memory area where the entities array
+ will be stored, converted to a 64-bits integer.
+ It can be zero. if zero, the ioctl won't store the
+ entities. It will just update
+ <constant>num_entities</constant></entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>num_interfaces</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Number of interfaces in the graph</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>ptr_interfaces</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>A pointer to a memory area where the interfaces array
+ will be stored, converted to a 64-bits integer.
+ It can be zero. if zero, the ioctl won't store the
+ interfaces. It will just update
+ <constant>num_interfaces</constant></entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>num_pads</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Total number of pads in the graph</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>ptr_pads</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>A pointer to a memory area where the pads array
+ will be stored, converted to a 64-bits integer.
+ It can be zero. if zero, the ioctl won't store the
+ pads. It will just update
+ <constant>num_pads</constant></entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>num_links</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Total number of data and interface links in the graph</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>ptr_links</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>A pointer to a memory area where the links array
+ will be stored, converted to a 64-bits integer.
+ It can be zero. if zero, the ioctl won't store the
+ links. It will just update
+ <constant>num_links</constant></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-v2-entity">
+ <title>struct <structname>media_v2_entity</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Unique ID for the entity.</entry>
+ </row>
+ <row>
+ <entry>char</entry>
+ <entry><structfield>name</structfield>[64]</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>function</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity main function, see <xref linkend="media-entity-type" /> for details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[12]</entry>
+ <entry>Reserved for future extensions. Drivers and applications must
+ set this array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-v2-interface">
+ <title>struct <structname>media_v2_interface</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Unique ID for the interface.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>intf_type</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Interface type, see <xref linkend="media-intf-type" /> for details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Interface flags. Currently unused.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[9]</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Reserved for future extensions. Drivers and applications must
+ set this array to zero.</entry>
+ </row>
+ <row>
+ <entry>struct media_v2_intf_devnode</entry>
+ <entry><structfield>devnode</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Used only for device node interfaces. See <xref linkend="media-v2-intf-devnode" /> for details..</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-v2-intf-devnode">
+ <title>struct <structname>media_v2_interface</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>major</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Device node major number.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>minor</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Device node minor number.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-v2-pad">
+ <title>struct <structname>media_v2_pad</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Unique ID for the pad.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>entity_id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Unique ID for the entity where this pad belongs.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[9]</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Reserved for future extensions. Drivers and applications must
+ set this array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-v2-link">
+ <title>struct <structname>media_v2_pad</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Unique ID for the pad.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>source_id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>
+ <para>On pad to pad links: unique ID for the source pad.</para>
+ <para>On interface to entity links: unique ID for the interface.</para>
+ </entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>sink_id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>
+ <para>On pad to pad links: unique ID for the sink pad.</para>
+ <para>On interface to entity links: unique ID for the entity.</para>
+ </entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[5]</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Reserved for future extensions. Drivers and applications must
+ set this array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>ENOSPC</errorcode></term>
+ <listitem>
+ <para>This is returned when either one or more of the num_entities,
+ num_interfaces, num_links or num_pads are non-zero and are smaller
+ than the actual number of elements inside the graph. This may happen
+ if the <constant>topology_version</constant> changed when compared
+ to the last time this ioctl was called. Userspace should usually
+ free the area for the pointers, zero the struct elements and call
+ this ioctl again.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-types.xml b/Documentation/DocBook/media/v4l/media-types.xml
new file mode 100644
index 000000000000..1af384250910
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/media-types.xml
@@ -0,0 +1,240 @@
+<section id="media-controller-types">
+<title>Types and flags used to represent the media graph elements</title>
+
+ <table frame="none" pgwide="1" id="media-entity-type">
+ <title>Media entity types</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_ENT_F_UNKNOWN</constant> and <constant>MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN</constant></entry>
+ <entry>Unknown entity. That generally indicates that
+ a driver didn't initialize properly the entity, with is a Kernel bug</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_IO_V4L</constant></entry>
+ <entry>Data streaming input and/or output entity.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_IO_VBI</constant></entry>
+ <entry>V4L VBI streaming input or output entity</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_IO_SWRADIO</constant></entry>
+ <entry>V4L Software Digital Radio (SDR) streaming input or output entity</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_IO_DTV</constant></entry>
+ <entry>DVB Digital TV streaming input or output entity</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_DTV_DEMOD</constant></entry>
+ <entry>Digital TV demodulator entity.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_TS_DEMUX</constant></entry>
+ <entry>MPEG Transport stream demux entity. Could be implemented on hardware or in Kernelspace by the Linux DVB subsystem.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_DTV_CA</constant></entry>
+ <entry>Digital TV Conditional Access module (CAM) entity</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_DTV_NET_DECAP</constant></entry>
+ <entry>Digital TV network ULE/MLE desencapsulation entity. Could be implemented on hardware or in Kernelspace</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_CONN_RF</constant></entry>
+ <entry>Connector for a Radio Frequency (RF) signal.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_CONN_SVIDEO</constant></entry>
+ <entry>Connector for a S-Video signal.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_CONN_COMPOSITE</constant></entry>
+ <entry>Connector for a RGB composite signal.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_CONN_TEST</constant></entry>
+ <entry>Connector for a test generator.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_CAM_SENSOR</constant></entry>
+ <entry>Camera video sensor entity.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_FLASH</constant></entry>
+ <entry>Flash controller entity.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_LENS</constant></entry>
+ <entry>Lens controller entity.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_ATV_DECODER</constant></entry>
+ <entry>Analog video decoder, the basic function of the video decoder
+ is to accept analogue video from a wide variety of sources such as
+ broadcast, DVD players, cameras and video cassette recorders, in
+ either NTSC, PAL, SECAM or HD format, separating the stream
+ into its component parts, luminance and chrominance, and output
+ it in some digital video standard, with appropriate timing
+ signals.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_F_TUNER</constant></entry>
+ <entry>Digital TV, analog TV, radio and/or software radio tuner.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-entity-flag">
+ <title>Media entity flags</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
+ <entry>Default entity for its type. Used to discover the default
+ audio, VBI and video devices, the default camera sensor, ...</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENT_FL_CONNECTOR</constant></entry>
+ <entry>The entity represents a data conector</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-intf-type">
+ <title>Media interface types</title>
+ <tgroup cols="3">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <colspec colname="c3"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_INTF_T_DVB_FE</constant></entry>
+ <entry>Device node interface for the Digital TV frontend</entry>
+ <entry>typically, /dev/dvb/adapter?/frontend?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_DVB_DEMUX</constant></entry>
+ <entry>Device node interface for the Digital TV demux</entry>
+ <entry>typically, /dev/dvb/adapter?/demux?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_DVB_DVR</constant></entry>
+ <entry>Device node interface for the Digital TV DVR</entry>
+ <entry>typically, /dev/dvb/adapter?/dvr?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_DVB_CA</constant></entry>
+ <entry>Device node interface for the Digital TV Conditional Access</entry>
+ <entry>typically, /dev/dvb/adapter?/ca?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_DVB_FE</constant></entry>
+ <entry>Device node interface for the Digital TV network control</entry>
+ <entry>typically, /dev/dvb/adapter?/net?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_V4L_VIDEO</constant></entry>
+ <entry>Device node interface for video (V4L)</entry>
+ <entry>typically, /dev/video?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_V4L_VBI</constant></entry>
+ <entry>Device node interface for VBI (V4L)</entry>
+ <entry>typically, /dev/vbi?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_V4L_RADIO</constant></entry>
+ <entry>Device node interface for radio (V4L)</entry>
+ <entry>typically, /dev/vbi?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_V4L_SUBDEV</constant></entry>
+ <entry>Device node interface for a V4L subdevice</entry>
+ <entry>typically, /dev/v4l-subdev?</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_INTF_T_V4L_SWRADIO</constant></entry>
+ <entry>Device node interface for Software Defined Radio (V4L)</entry>
+ <entry>typically, /dev/swradio?</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-pad-flag">
+ <title>Media pad flags</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_PAD_FL_SINK</constant></entry>
+ <entry>Input pad, relative to the entity. Input pads sink data and
+ are targets of links.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_PAD_FL_SOURCE</constant></entry>
+ <entry>Output pad, relative to the entity. Output pads source data
+ and are origins of links.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_PAD_FL_MUST_CONNECT</constant></entry>
+ <entry>If this flag is set and the pad is linked to any other
+ pad, then at least one of those links must be enabled for the
+ entity to be able to stream. There could be temporary reasons
+ (e.g. device configuration dependent) for the pad to need
+ enabled links even when this flag isn't set; the absence of the
+ flag doesn't imply there is none.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>One and only one of <constant>MEDIA_PAD_FL_SINK</constant> and
+ <constant>MEDIA_PAD_FL_SOURCE</constant> must be set for every pad.</para>
+
+ <table frame="none" pgwide="1" id="media-link-flag">
+ <title>Media link flags</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
+ <entry>The link is enabled and can be used to transfer media data.
+ When two or more links target a sink pad, only one of them can be
+ enabled at a time.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
+ <entry>The link enabled state can't be modified at runtime. An
+ immutable link is always enabled.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
+ <entry>The link enabled state can be modified during streaming. This
+ flag is set by drivers and is read-only for applications.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_LNK_FL_LINK_TYPE</constant></entry>
+ <entry><para>This is a bitmask that defines the type of the link.
+ Currently, two types of links are supported:</para>
+ <para><constant>MEDIA_LNK_FL_DATA_LINK</constant>
+ if the link is between two pads</para>
+ <para><constant>MEDIA_LNK_FL_INTERFACE_LINK</constant>
+ if the link is between an interface and an entity</para></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+</section>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index 7da8f0402af5..b442921bca54 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -162,12 +162,15 @@
<sect1 id="Basic_defines">
<title>Basic defines</title>
<para>
- At least you have to provide a mtd structure and
- a storage for the ioremap'ed chip address.
- You can allocate the mtd structure using kmalloc
- or you can allocate it statically.
- In case of static allocation you have to allocate
- a nand_chip structure too.
+ At least you have to provide a nand_chip structure
+ and a storage for the ioremap'ed chip address.
+ You can allocate the nand_chip structure using
+ kmalloc or you can allocate it statically.
+ The NAND chip structure embeds an mtd structure
+ which will be registered to the MTD subsystem.
+ You can extract a pointer to the mtd structure
+ from a nand_chip pointer using the nand_to_mtd()
+ helper.
</para>
<para>
Kmalloc based example
@@ -180,7 +183,6 @@ static void __iomem *baseaddr;
Static example
</para>
<programlisting>
-static struct mtd_info board_mtd;
static struct nand_chip board_chip;
static void __iomem *baseaddr;
</programlisting>
@@ -235,7 +237,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd)
<programlisting>
static void board_hwcontrol(struct mtd_info *mtd, int cmd)
{
- struct nand_chip *this = (struct nand_chip *) mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
switch(cmd){
case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT; break;
case NAND_CTL_CLRCLE: this->IO_ADDR_W &amp;= ~CLE_ADRR_BIT; break;
@@ -274,13 +276,15 @@ static int __init board_init (void)
int err = 0;
/* Allocate memory for MTD device structure and private data */
- board_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
- if (!board_mtd) {
+ this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+ if (!this) {
printk ("Unable to allocate NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
+ board_mtd = nand_to_mtd(this);
+
/* map physical address */
baseaddr = ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
if (!baseaddr) {
@@ -289,11 +293,6 @@ static int __init board_init (void)
goto out_mtd;
}
- /* Get pointer to private data */
- this = (struct nand_chip *) ();
- /* Link the private data with the MTD structure */
- board_mtd->priv = this;
-
/* Set address of NAND IO lines */
this->IO_ADDR_R = baseaddr;
this->IO_ADDR_W = baseaddr;
@@ -317,7 +316,7 @@ static int __init board_init (void)
out_ior:
iounmap(baseaddr);
out_mtd:
- kfree (board_mtd);
+ kfree (this);
out:
return err;
}
@@ -343,7 +342,7 @@ static void __exit board_cleanup (void)
iounmap(baseaddr);
/* Free the MTD device structure */
- kfree (board_mtd);
+ kfree (mtd_to_nand(board_mtd));
}
module_exit(board_cleanup);
#endif
@@ -399,7 +398,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
<programlisting>
static void board_select_chip (struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = (struct nand_chip *) mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
/* Deselect all chips */
this->IO_ADDR_R &amp;= ~BOARD_NAND_ADDR_MASK;
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 21152d397b88..d5a699d5a551 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -209,7 +209,7 @@ tools. One such tool that is particularly recommended is the Linux
Cross-Reference project, which is able to present source code in a
self-referential, indexed webpage format. An excellent up-to-date
repository of the kernel code may be found at:
- http://lxr.linux.no/+trees
+ http://lxr.free-electrons.com/
The development process
diff --git a/Documentation/Makefile b/Documentation/Makefile
index bc0548201755..1207d7907650 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,4 +1,4 @@
subdir-y := accounting auxdisplay blackfin connector \
filesystems filesystems ia64 laptops mic misc-devices \
- networking pcmcia prctl ptp spi timers vDSO video4linux \
+ networking pcmcia prctl ptp timers vDSO video4linux \
watchdog
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index f40578026a04..7785fb5eb93f 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -375,7 +375,8 @@ int main(int argc, char *argv[])
}
}
- if ((nl_sd = create_nl_socket(NETLINK_GENERIC)) < 0)
+ nl_sd = create_nl_socket(NETLINK_GENERIC);
+ if (nl_sd < 0)
err(1, "error creating Netlink socket\n");
diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README
index 18a775d10172..ae89b67d8e23 100644
--- a/Documentation/arm/Marvell/README
+++ b/Documentation/arm/Marvell/README
@@ -233,29 +233,30 @@ MMP/MMP2 family (communication processor)
Linux kernel mach directory: arch/arm/mach-mmp
Linux kernel plat directory: arch/arm/plat-pxa
-Berlin family (Digital Entertainment)
+Berlin family (Multimedia Solutions)
-------------------------------------
Flavors:
- 88DE3005, Armada 1500-mini
+ 88DE3005, Armada 1500 Mini
Design name: BG2CD
Core: ARM Cortex-A9, PL310 L2CC
- Homepage: http://www.marvell.com/digital-entertainment/armada-1500-mini/
+ Homepage: http://www.marvell.com/multimedia-solutions/armada-1500-mini/
+ 88DE3006, Armada 1500 Mini Plus
+ Design name: BG2CDP
+ Core: Dual Core ARM Cortex-A7
+ Homepage: http://www.marvell.com/multimedia-solutions/armada-1500-mini-plus/
88DE3100, Armada 1500
Design name: BG2
Core: Marvell PJ4B (ARMv7), Tauros3 L2CC
- Homepage: http://www.marvell.com/digital-entertainment/armada-1500/
- Product Brief: http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf
+ Product Brief: http://www.marvell.com/multimedia-solutions/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf
88DE3114, Armada 1500 Pro
- Design name: BG2-Q
+ Design name: BG2Q
Core: Quad Core ARM Cortex-A9, PL310 L2CC
- Homepage: http://www.marvell.com/digital-entertainment/armada-1500-pro/
- Product Brief: http://www.marvell.com/digital-entertainment/armada-1500-pro/assets/Marvell_ARMADA_1500_PRO-01_product_brief.pdf
88DE????
Design name: BG3
Core: ARM Cortex-A15, CA15 integrated L2CC
- Homepage: http://www.marvell.com/digital-entertainment/
+ Homepage: http://www.marvell.com/multimedia-solutions/
Directory: arch/arm/mach-berlin
Comments:
diff --git a/Documentation/arm/pxa/mfp.txt b/Documentation/arm/pxa/mfp.txt
index a179e5bc02c9..0b7cab978c02 100644
--- a/Documentation/arm/pxa/mfp.txt
+++ b/Documentation/arm/pxa/mfp.txt
@@ -49,7 +49,7 @@ to this new MFP mechanism, here are several key points:
internal controllers like PWM, SSP and UART, with 128 internal signals
which can be routed to external through one or more MFPs (e.g. GPIO<0>
can be routed through either MFP_PIN_GPIO0 as well as MFP_PIN_GPIO0_2,
- see arch/arm/mach-pxa/mach/include/mfp-pxa300.h)
+ see arch/arm/mach-pxa/mfp-pxa300.h)
2. Alternate function configuration is removed from this GPIO controller,
the remaining functions are pure GPIO-specific, i.e.
@@ -76,11 +76,11 @@ For board code writers, here are some guidelines:
1. include ONE of the following header files in your <board>.c:
- - #include <mach/mfp-pxa25x.h>
- - #include <mach/mfp-pxa27x.h>
- - #include <mach/mfp-pxa300.h>
- - #include <mach/mfp-pxa320.h>
- - #include <mach/mfp-pxa930.h>
+ - #include "mfp-pxa25x.h"
+ - #include "mfp-pxa27x.h"
+ - #include "mfp-pxa300.h"
+ - #include "mfp-pxa320.h"
+ - #include "mfp-pxa930.h"
NOTE: only one file in your <board>.c, depending on the processors used,
because pin configuration definitions may conflict in these file (i.e.
@@ -203,20 +203,20 @@ make them effective there-after.
1. Unified pin definitions - enum constants for all configurable pins
2. processor-neutral bit definitions for a possible MFP configuration
- - arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h
+ - arch/arm/mach-pxa/mfp-pxa3xx.h
for PXA3xx specific MFPR register bit definitions and PXA3xx common pin
configurations
- - arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
+ - arch/arm/mach-pxa/mfp-pxa2xx.h
for PXA2xx specific definitions and PXA25x/PXA27x common pin configurations
- - arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
- arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
- arch/arm/mach-pxa/include/mach/mfp-pxa300.h
- arch/arm/mach-pxa/include/mach/mfp-pxa320.h
- arch/arm/mach-pxa/include/mach/mfp-pxa930.h
+ - arch/arm/mach-pxa/mfp-pxa25x.h
+ arch/arm/mach-pxa/mfp-pxa27x.h
+ arch/arm/mach-pxa/mfp-pxa300.h
+ arch/arm/mach-pxa/mfp-pxa320.h
+ arch/arm/mach-pxa/mfp-pxa930.h
for processor specific definitions
diff --git a/Documentation/block/cfq-iosched.txt b/Documentation/block/cfq-iosched.txt
index f3bc72945cbd..1e4f835a659d 100644
--- a/Documentation/block/cfq-iosched.txt
+++ b/Documentation/block/cfq-iosched.txt
@@ -81,14 +81,13 @@ on higher end storage.
Default value for this parameter is 8ms.
-latency
--------
-This parameter is used to enable/disable the latency mode of the CFQ
-scheduler. If latency mode (called low_latency) is enabled, CFQ tries
-to recompute the slice time for each process based on the target_latency set
-for the system. This favors fairness over throughput. Disabling low
-latency (setting it to 0) ignores target latency, allowing each process in the
-system to get a full time slice.
+low_latency
+-----------
+This parameter is used to enable/disable the low latency mode of the CFQ
+scheduler. If enabled, CFQ tries to recompute the slice time for each process
+based on the target_latency set for the system. This favors fairness over
+throughput. Disabling low latency (setting it to 0) ignores target latency,
+allowing each process in the system to get a full time slice.
By default low latency mode is enabled.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index f9ad5e048b11..dd68821c22d4 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -150,7 +150,7 @@ an entry as shown below in the output.
If this is not mounted, do the following.
- #mkdir /sysfs
+ #mkdir /sys
#mount -t sysfs sys /sys
Now you should see entries for all present cpu, the following is an example
diff --git a/Documentation/devicetree/bindings/arm/arm,scpi.txt b/Documentation/devicetree/bindings/arm/arm,scpi.txt
index 86302de67c2c..313dabdc14f9 100644
--- a/Documentation/devicetree/bindings/arm/arm,scpi.txt
+++ b/Documentation/devicetree/bindings/arm/arm,scpi.txt
@@ -63,7 +63,7 @@ Required properties:
- compatible : should be "arm,juno-sram-ns" for Non-secure SRAM on Juno
The rest of the properties should follow the generic mmio-sram description
-found in ../../misc/sysram.txt
+found in ../../sram/sram.txt
Each sub-node represents the reserved area for SCPI.
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
index c78576bb7729..11d3056dc2bd 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
@@ -26,6 +26,10 @@ Raspberry Pi Model B+
Required root node properties:
compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+Raspberry Pi 2 Model B
+Required root node properties:
+compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+
Raspberry Pi Compute Module
Required root node properties:
compatible = "raspberrypi,compute-module", "brcm,bcm2835";
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt
index 6b0f49f6f499..8608a776caa7 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt
@@ -5,4 +5,11 @@ Boards with the BCM4708 SoC shall have the following properties:
Required root node property:
+bcm4708
compatible = "brcm,bcm4708";
+
+bcm4709
+compatible = "brcm,bcm4709";
+
+bcm53012
+compatible = "brcm,bcm53012";
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt
new file mode 100644
index 000000000000..677ef9d9f445
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt
@@ -0,0 +1,39 @@
+Broadcom Northstar Plus SoC CPU Enable Method
+---------------------------------------------
+This binding defines the enable method used for starting secondary
+CPU in the following Broadcom SoCs:
+ BCM58522, BCM58525, BCM58535, BCM58622, BCM58623, BCM58625, BCM88312
+
+The enable method is specified by defining the following required
+properties in the corresponding secondary "cpu" device tree node:
+ - enable-method = "brcm,bcm-nsp-smp";
+ - secondary-boot-reg = <...>;
+
+The secondary-boot-reg property is a u32 value that specifies the
+physical address of the register which should hold the common
+entry point for a secondary CPU. This entry is cpu node specific
+and should be added per cpu. E.g., in case of NSP (BCM58625) which
+is a dual core CPU SoC, this entry should be added to cpu1 node.
+
+
+Example:
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0>;
+ };
+
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ enable-method = "brcm,bcm-nsp-smp";
+ secondary-boot-reg = <0xffff042c>;
+ reg = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/compulab-boards.txt b/Documentation/devicetree/bindings/arm/compulab-boards.txt
new file mode 100644
index 000000000000..42a10285af9c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/compulab-boards.txt
@@ -0,0 +1,25 @@
+CompuLab SB-SOM is a multi-module baseboard capable of carrying:
+ - CM-T43
+ - CM-T54
+ - CM-QS600
+ - CL-SOM-AM57x
+ - CL-SOM-iMX7
+modules with minor modifications to the SB-SOM assembly.
+
+Required root node properties:
+ - compatible = should be "compulab,sb-som"
+
+Compulab CL-SOM-iMX7 is a miniature System-on-Module (SoM) based on
+Freescale i.MX7 ARM Cortex-A7 System-on-Chip.
+
+Required root node properties:
+ - compatible = "compulab,cl-som-imx7", "fsl,imx7d";
+
+Compulab SBC-iMX7 is a single board computer based on the
+Freescale i.MX7 system-on-chip. SBC-iMX7 is implemented with
+the CL-SOM-iMX7 System-on-Module providing most of the functions,
+and SB-SOM-iMX7 carrier board providing additional peripheral
+functions and connectors.
+
+Required root node properties:
+ - compatible = "compulab,sbc-imx7", "compulab,cl-som-imx7", "fsl,imx7d";
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 6aca64f289b6..ae9be074d09f 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -157,6 +157,7 @@ nodes to be present and contain the properties described below.
"arm,cortex-a17"
"arm,cortex-a53"
"arm,cortex-a57"
+ "arm,cortex-a72"
"arm,cortex-m0"
"arm,cortex-m0+"
"arm,cortex-m1"
@@ -190,6 +191,8 @@ nodes to be present and contain the properties described below.
"allwinner,sun6i-a31"
"allwinner,sun8i-a23"
"arm,psci"
+ "arm,realview-smp"
+ "brcm,bcm-nsp-smp"
"brcm,brahma-b15"
"marvell,armada-375-smp"
"marvell,armada-380-smp"
@@ -200,6 +203,7 @@ nodes to be present and contain the properties described below.
"qcom,gcc-msm8660"
"qcom,kpss-acc-v1"
"qcom,kpss-acc-v2"
+ "rockchip,rk3036-smp"
"rockchip,rk3066-smp"
"ste,dbx500-smp"
diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 34c88b0c7ab4..752a685d926f 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -131,6 +131,10 @@ Example:
Freescale ARMv8 based Layerscape SoC family Device Tree Bindings
----------------------------------------------------------------
+LS1043A ARMv8 based RDB Board
+Required root node properties:
+ - compatible = "fsl,ls1043a-rdb", "fsl,ls1043a";
+
LS2080A ARMv8 based Simulator model
Required root node properties:
- compatible = "fsl,ls2080a-simu", "fsl,ls2080a";
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 6ac7c000af22..e3ccab114006 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -187,6 +187,22 @@ Example:
reg = <0xb0000000 0x10000>;
};
+Hisilicon HiP05 PERISUB system controller
+
+Required properties:
+- compatible : "hisilicon,hip05-perisubc", "syscon";
+- reg : Register address and size
+
+The HiP05 PERISUB system controller is shared by peripheral controllers in
+HiP05 Soc to implement some basic configurations. The peripheral
+controllers include mdio, ddr, iic, uart, timer and so on.
+
+Example:
+ /* for HiP05 perisub-ctrl-c system */
+ peri_c_subctrl: syscon@80000000 {
+ compatible = "hisilicon,hip05-perisubc", "syscon";
+ reg = <0x0 0x80000000 0x0 0x10000>;
+ };
-----------------------------------------------------------------------
Hisilicon CPU controller
diff --git a/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt b/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt
index 5171ad8f48ff..ab0c9cdf388e 100644
--- a/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt
+++ b/Documentation/devicetree/bindings/arm/marvell,kirkwood.txt
@@ -24,6 +24,8 @@ board. Currently known boards are:
"buffalo,lswxl"
"buffalo,lsxhl"
"buffalo,lsxl"
+"cloudengines,pogo02"
+"cloudengines,pogoplugv4"
"dlink,dns-320"
"dlink,dns-320-a1"
"dlink,dns-325"
diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt
index 618a91994a18..54f43bc2df44 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek.txt
@@ -6,6 +6,7 @@ following property:
Required root node property:
compatible: Must contain one of
+ "mediatek,mt2701"
"mediatek,mt6580"
"mediatek,mt6589"
"mediatek,mt6592"
@@ -17,6 +18,9 @@ compatible: Must contain one of
Supported boards:
+- Evaluation board for MT2701:
+ Required root node properties:
+ - compatible = "mediatek,mt2701-evb", "mediatek,mt2701";
- Evaluation board for MT6580:
Required root node properties:
- compatible = "mediatek,mt6580-evbp1", "mediatek,mt6580";
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
index f6cd3e4192ff..aaf8d1460c4d 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
@@ -18,7 +18,7 @@ The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Also it uses the common reset controller binding from
Documentation/devicetree/bindings/reset/reset.txt.
The available reset outputs are defined in
-dt-bindings/reset-controller/mt*-resets.h
+dt-bindings/reset/mt*-resets.h
Example:
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
index f25b85499a6f..2f6ff86df49f 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
@@ -18,7 +18,7 @@ The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Also it uses the common reset controller binding from
Documentation/devicetree/bindings/reset/reset.txt.
The available reset outputs are defined in
-dt-bindings/reset-controller/mt*-resets.h
+dt-bindings/reset/mt*-resets.h
Example:
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index 9f4e5136e568..a2bd593881ca 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -138,9 +138,21 @@ Boards:
- AM335X phyBOARD-WEGA: Single Board Computer dev kit
compatible = "phytec,am335x-wega", "phytec,am335x-phycore-som", "ti,am33xx"
+- AM335X CM-T335 : System On Module, built around the Sitara AM3352/4
+ compatible = "compulab,cm-t335", "ti,am33xx"
+
+- AM335X SBC-T335 : single board computer, built around the Sitara AM3352/4
+ compatible = "compulab,sbc-t335", "compulab,cm-t335", "ti,am33xx"
+
- OMAP5 EVM : Evaluation Module
compatible = "ti,omap5-evm", "ti,omap5"
+- AM437x CM-T43
+ compatible = "compulab,am437x-cm-t43", "ti,am4372", "ti,am43"
+
+- AM437x SBC-T43
+ compatible = "compulab,am437x-sbc-t43", "compulab,am437x-cm-t43", "ti,am4372", "ti,am43"
+
- AM43x EPOS EVM
compatible = "ti,am43x-epos-evm", "ti,am4372", "ti,am43"
@@ -150,6 +162,12 @@ Boards:
- AM437x SK EVM: AM437x StarterKit Evaluation Module
compatible = "ti,am437x-sk-evm", "ti,am4372", "ti,am43"
+- AM57XX CL-SOM-AM57x
+ compatible = "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7"
+
+- AM57XX SBC-AM57x
+ compatible = "compulab,sbc-am57x", "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7"
+
- DRA742 EVM: Software Development Board for DRA742
compatible = "ti,dra7-evm", "ti,dra742", "ti,dra74", "ti,dra7"
diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
index a9adab84e2fe..a2c4f1d52492 100644
--- a/Documentation/devicetree/bindings/arm/psci.txt
+++ b/Documentation/devicetree/bindings/arm/psci.txt
@@ -23,17 +23,20 @@ Main node required properties:
- compatible : should contain at least one of:
- * "arm,psci" : for implementations complying to PSCI versions prior to
- 0.2. For these cases function IDs must be provided.
-
- * "arm,psci-0.2" : for implementations complying to PSCI 0.2. Function
- IDs are not required and should be ignored by an OS with PSCI 0.2
- support, but are permitted to be present for compatibility with
- existing software when "arm,psci" is later in the compatible list.
-
- * "arm,psci-1.0" : for implementations complying to PSCI 1.0. PSCI 1.0 is
- backward compatible with PSCI 0.2 with minor specification updates,
- as defined in the PSCI specification[2].
+ * "arm,psci" : For implementations complying to PSCI versions prior
+ to 0.2.
+ For these cases function IDs must be provided.
+
+ * "arm,psci-0.2" : For implementations complying to PSCI 0.2.
+ Function IDs are not required and should be ignored by
+ an OS with PSCI 0.2 support, but are permitted to be
+ present for compatibility with existing software when
+ "arm,psci" is later in the compatible list.
+
+ * "arm,psci-1.0" : For implementations complying to PSCI 1.0.
+ PSCI 1.0 is backward compatible with PSCI 0.2 with
+ minor specification updates, as defined in the PSCI
+ specification[2].
- method : The method of calling the PSCI firmware. Permitted
values are:
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index 8e985dd2f181..078c14fcdaaa 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -1,6 +1,10 @@
Rockchip platforms device tree bindings
---------------------------------------
+- Kylin RK3036 board:
+ Required root node properties:
+ - compatible = "rockchip,kylin-rk3036", "rockchip,rk3036";
+
- MarsBoard RK3066 board:
Required root node properties:
- compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a";
@@ -35,6 +39,11 @@ Rockchip platforms device tree bindings
Required root node properties:
- compatible = "netxeon,r89", "rockchip,rk3288";
+- Google Brain (dev-board):
+ Required root node properties:
+ - compatible = "google,veyron-brain-rev0", "google,veyron-brain",
+ "google,veyron", "rockchip,rk3288";
+
- Google Jaq (Haier Chromebook 11 and more):
Required root node properties:
- compatible = "google,veyron-jaq-rev5", "google,veyron-jaq-rev4",
@@ -49,6 +58,15 @@ Rockchip platforms device tree bindings
"google,veyron-jerry-rev3", "google,veyron-jerry",
"google,veyron", "rockchip,rk3288";
+- Google Mickey (Asus Chromebit CS10):
+ Required root node properties:
+ - compatible = "google,veyron-mickey-rev8", "google,veyron-mickey-rev7",
+ "google,veyron-mickey-rev6", "google,veyron-mickey-rev5",
+ "google,veyron-mickey-rev4", "google,veyron-mickey-rev3",
+ "google,veyron-mickey-rev2", "google,veyron-mickey-rev1",
+ "google,veyron-mickey-rev0", "google,veyron-mickey",
+ "google,veyron", "rockchip,rk3288";
+
- Google Minnie (Asus Chromebook Flip C100P):
Required root node properties:
- compatible = "google,veyron-minnie-rev4", "google,veyron-minnie-rev3",
@@ -69,6 +87,14 @@ Rockchip platforms device tree bindings
"google,veyron-speedy-rev3", "google,veyron-speedy-rev2",
"google,veyron-speedy", "google,veyron", "rockchip,rk3288";
+- Rockchip RK3368 evb:
+ Required root node properties:
+ - compatible = "rockchip,rk3368-evb-act8846", "rockchip,rk3368";
+
- Rockchip R88 board:
Required root node properties:
- compatible = "rockchip,r88", "rockchip,rk3368";
+
+- Rockchip RK3228 Evaluation board:
+ Required root node properties:
+ - compatible = "rockchip,rk3228-evb", "rockchip,rk3228";
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
index f46ca9a316a2..ccaaec6014bd 100644
--- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
@@ -47,6 +47,9 @@ Required properties:
- samsung,syscon-phandle Contains the PMU system controller node
(To access the ADC_PHY register on Exynos5250/5420/5800/3250)
+Optional properties:
+- has-touchscreen: If present, indicates that a touchscreen is
+ connected an usable.
Note: child nodes can be added for auto probing from device tree.
diff --git a/Documentation/devicetree/bindings/arm/scu.txt b/Documentation/devicetree/bindings/arm/scu.txt
index c447680519bb..08a587875996 100644
--- a/Documentation/devicetree/bindings/arm/scu.txt
+++ b/Documentation/devicetree/bindings/arm/scu.txt
@@ -10,10 +10,13 @@ References:
Revision r2p0
- Cortex-A5: see DDI0434B Cortex-A5 MPCore Technical Reference Manual
Revision r0p1
+- ARM11 MPCore: see DDI0360F ARM 11 MPCore Processor Technical Reference
+ Manial Revision r2p0
- compatible : Should be:
"arm,cortex-a9-scu"
"arm,cortex-a5-scu"
+ "arm,arm11mp-scu"
- reg : Specify the base address and the size of the SCU register window.
diff --git a/Documentation/devicetree/bindings/arm/secure.txt b/Documentation/devicetree/bindings/arm/secure.txt
new file mode 100644
index 000000000000..e31303fb233a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/secure.txt
@@ -0,0 +1,53 @@
+* ARM Secure world bindings
+
+ARM CPUs with TrustZone support have two distinct address spaces,
+"Normal" and "Secure". Most devicetree consumers (including the Linux
+kernel) are not TrustZone aware and run entirely in either the Normal
+world or the Secure world. However some devicetree consumers are
+TrustZone aware and need to be able to determine whether devices are
+visible only in the Secure address space, only in the Normal address
+space, or visible in both. (One example of that situation would be a
+virtual machine which boots Secure firmware and wants to tell the
+firmware about the layout of the machine via devicetree.)
+
+The general principle of the naming scheme for Secure world bindings
+is that any property that needs a different value in the Secure world
+can be supported by prefixing the property name with "secure-". So for
+instance "secure-foo" would override "foo". For property names with
+a vendor prefix, the Secure variant of "vendor,foo" would be
+"vendor,secure-foo". If there is no "secure-" property then the Secure
+world value is the same as specified for the Normal world by the
+non-prefixed property. However, only the properties listed below may
+validly have "secure-" versions; this list will be enlarged on a
+case-by-case basis.
+
+Defining the bindings in this way means that a device tree which has
+been annotated to indicate the presence of Secure-only devices can
+still be processed unmodified by existing Non-secure software (and in
+particular by the kernel).
+
+Note that it is still valid for bindings intended for purely Secure
+world consumers (like kernels that run entirely in Secure) to simply
+describe the view of Secure world using the standard bindings. These
+secure- bindings only need to be used where both the Secure and Normal
+world views need to be described in a single device tree.
+
+Valid Secure world properties:
+
+- secure-status : specifies whether the device is present and usable
+ in the secure world. The combination of this with "status" allows
+ the various possible combinations of device visibility to be
+ specified. If "secure-status" is not specified it defaults to the
+ same value as "status"; if "status" is not specified either then
+ both default to "okay". This means the following combinations are
+ possible:
+
+ /* Neither specified: default to visible in both S and NS */
+ secure-status = "okay"; /* visible in both */
+ status = "okay"; /* visible in both */
+ status = "okay"; secure-status = "okay"; /* visible in both */
+ secure-status = "disabled"; /* NS-only */
+ status = "okay"; secure-status = "disabled"; /* NS-only */
+ status = "disabled"; secure-status = "okay"; /* S-only */
+ status = "disabled"; /* disabled in both */
+ status = "disabled"; secure-status = "disabled"; /* disabled in both */
diff --git a/Documentation/devicetree/bindings/arm/shmobile.txt b/Documentation/devicetree/bindings/arm/shmobile.txt
index 40bb9007cd0d..9cf67e48f222 100644
--- a/Documentation/devicetree/bindings/arm/shmobile.txt
+++ b/Documentation/devicetree/bindings/arm/shmobile.txt
@@ -27,6 +27,8 @@ SoCs:
compatible = "renesas,r8a7793"
- R-Car E2 (R8A77940)
compatible = "renesas,r8a7794"
+ - R-Car H3 (R8A77950)
+ compatible = "renesas,r8a7795"
Boards:
@@ -57,5 +59,7 @@ Boards:
compatible = "renesas,marzen", "renesas,r8a7779"
- Porter (M2-LCDP)
compatible = "renesas,porter", "renesas,r8a7791"
+ - Salvator-X (RTP0RC7795SIPB0010S)
+ compatible = "renesas,salvator-x", "renesas,r8a7795";
- SILK (RTP0RC7794LCB00011S)
compatible = "renesas,silk", "renesas,r8a7794"
diff --git a/Documentation/devicetree/bindings/arm/technologic.txt b/Documentation/devicetree/bindings/arm/technologic.txt
new file mode 100644
index 000000000000..842298894cf0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/technologic.txt
@@ -0,0 +1,6 @@
+Technologic Systems Platforms Device Tree Bindings
+--------------------------------------------------
+
+TS-4800 board
+Required root node properties:
+ - compatible = "technologic,imx51-ts4800", "fsl,imx51";
diff --git a/Documentation/devicetree/bindings/bus/uniphier-system-bus.txt b/Documentation/devicetree/bindings/bus/uniphier-system-bus.txt
new file mode 100644
index 000000000000..68ef80afff16
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/uniphier-system-bus.txt
@@ -0,0 +1,66 @@
+UniPhier System Bus
+
+The UniPhier System Bus is an external bus that connects on-board devices to
+the UniPhier SoC. It is a simple (semi-)parallel bus with address, data, and
+some control signals. It supports up to 8 banks (chip selects).
+
+Before any access to the bus, the bus controller must be configured; the bus
+controller registers provide the control for the translation from the offset
+within each bank to the CPU-viewed address. The needed setup includes the base
+address, the size of each bank. Optionally, some timing parameters can be
+optimized for faster bus access.
+
+Required properties:
+- compatible: should be "socionext,uniphier-system-bus".
+- reg: offset and length of the register set for the bus controller device.
+- #address-cells: should be 2. The first cell is the bank number (chip select).
+ The second cell is the address offset within the bank.
+- #size-cells: should be 1.
+- ranges: should provide a proper address translation from the System Bus to
+ the parent bus.
+
+Note:
+The address region(s) that can be assigned for the System Bus is implementation
+defined. Some SoCs can use 0x00000000-0x0fffffff and 0x40000000-0x4fffffff,
+while other SoCs can only use 0x40000000-0x4fffffff. There might be additional
+limitations depending on SoCs and the boot mode. The address translation is
+arbitrary as long as the banks are assigned in the supported address space with
+the required alignment and they do not overlap one another.
+For example, it is possible to map:
+ bank 0 to 0x42000000-0x43ffffff, bank 5 to 0x46000000-0x46ffffff
+It is also possible to map:
+ bank 0 to 0x48000000-0x49ffffff, bank 5 to 0x44000000-0x44ffffff
+There is no reason to stick to a particular translation mapping, but the
+"ranges" property should provide a "reasonable" default that is known to work.
+The software should initialize the bus controller according to it.
+
+Example:
+
+ system-bus {
+ compatible = "socionext,uniphier-system-bus";
+ reg = <0x58c00000 0x400>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <1 0x00000000 0x42000000 0x02000000
+ 5 0x00000000 0x46000000 0x01000000>;
+
+ ethernet@1,01f00000 {
+ compatible = "smsc,lan9115";
+ reg = <1 0x01f00000 0x1000>;
+ interrupts = <0 48 4>
+ phy-mode = "mii";
+ };
+
+ uart@5,00200000 {
+ compatible = "ns16550a";
+ reg = <5 0x00200000 0x20>;
+ interrupts = <0 49 4>
+ clock-frequency = <12288000>;
+ };
+ };
+
+In this example,
+ - the Ethernet device is connected at the offset 0x01f00000 of CS1 and
+ mapped to 0x43f00000 of the parent bus.
+ - the UART device is connected at the offset 0x00200000 of CS5 and
+ mapped to 0x46200000 of the parent bus.
diff --git a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt b/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt
new file mode 100644
index 000000000000..8b7177cecb36
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt
@@ -0,0 +1,40 @@
+ARM System Controller ICST clocks
+
+The ICS525 and ICS307 oscillators are produced by Integrated Devices
+Technology (IDT). ARM integrated these oscillators deeply into their
+reference designs by adding special control registers that manage such
+oscillators to their system controllers.
+
+The ARM system controller contains logic to serialize and initialize
+an ICST clock request after a write to the 32 bit register at an offset
+into the system controller. Furthermore, to even be able to alter one of
+these frequencies, the system controller must first be unlocked by
+writing a special token to another offset in the system controller.
+
+The ICST oscillator must be provided inside a system controller node.
+
+Required properties:
+- lock-offset: the offset address into the system controller where the
+ unlocking register is located
+- vco-offset: the offset address into the system controller where the
+ ICST control register is located (even 32 bit address)
+- compatible: must be one of "arm,syscon-icst525" or "arm,syscon-icst307"
+- #clock-cells: must be <0>
+- clocks: parent clock, since the ICST needs a parent clock to derive its
+ frequency from, this attribute is compulsory.
+
+Example:
+
+syscon: syscon@10000000 {
+ compatible = "syscon";
+ reg = <0x10000000 0x1000>;
+
+ oscclk0: osc0@0c {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0x0c>;
+ clocks = <&xtal24mhz>;
+ };
+ (...)
+};
diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
new file mode 100644
index 000000000000..7a837d2182ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
@@ -0,0 +1,31 @@
+Broadcom BCM2835 auxiliary peripheral support
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The auxiliary peripherals (UART, SPI1, and SPI2) have a small register
+area controlling clock gating to the peripherals, and providing an IRQ
+status register.
+
+Required properties:
+- compatible: Should be "brcm,bcm2835-aux"
+- #clock-cells: Should be <1>. The permitted clock-specifier values can be
+ found in include/dt-bindings/clock/bcm2835-aux.h
+- reg: Specifies base physical address and size of the registers
+- clocks: The parent clock phandle
+
+Example:
+
+ clocks: cprman@7e101000 {
+ compatible = "brcm,bcm2835-cprman";
+ #clock-cells = <1>;
+ reg = <0x7e101000 0x2000>;
+ clocks = <&clk_osc>;
+ };
+
+ aux: aux@0x7e215004 {
+ compatible = "brcm,bcm2835-aux";
+ #clock-cells = <1>;
+ reg = <0x7e215000 0x8>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
index ede65a55e21b..0b35e71b39e8 100644
--- a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
@@ -208,3 +208,8 @@ These clock IDs are defined in:
ch3_unused lcpll_ports 4 BCM_NS2_LCPLL_PORTS_CH3_UNUSED
ch4_unused lcpll_ports 5 BCM_NS2_LCPLL_PORTS_CH4_UNUSED
ch5_unused lcpll_ports 6 BCM_NS2_LCPLL_PORTS_CH5_UNUSED
+
+BCM63138
+--------
+PLL and leaf clock compatible strings for BCM63138 are:
+ "brcm,bcm63138-armpll"
diff --git a/Documentation/devicetree/bindings/clock/cs2000-cp.txt b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
new file mode 100644
index 000000000000..54e6df0bee8a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
@@ -0,0 +1,22 @@
+CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
+
+Required properties:
+
+- compatible: "cirrus,cs2000-cp"
+- reg: The chip select number on the I2C bus
+- clocks: common clock binding for CLK_IN, XTI/REF_CLK
+- clock-names: CLK_IN : clk_in, XTI/REF_CLK : ref_clk
+- #clock-cells: must be <0>
+
+Example:
+
+&i2c2 {
+ ...
+ cs2000: clk_multiplier@4f {
+ #clock-cells = <0>;
+ compatible = "cirrus,cs2000-cp";
+ reg = <0x4f>;
+ clocks = <&rcar_sound 0>, <&x12_clk>;
+ clock-names = "clk_in", "ref_clk";
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/dove-divider-clock.txt b/Documentation/devicetree/bindings/clock/dove-divider-clock.txt
new file mode 100644
index 000000000000..e3eb0f657c5e
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/dove-divider-clock.txt
@@ -0,0 +1,28 @@
+PLL divider based Dove clocks
+
+Marvell Dove has a 2GHz PLL, which feeds into a set of dividers to provide
+high speed clocks for a number of peripherals. These dividers are part of
+the PMU, and thus this node should be a child of the PMU node.
+
+The following clocks are provided:
+
+ID Clock
+-------------
+0 AXI bus clock
+1 GPU clock
+2 VMeta clock
+3 LCD clock
+
+Required properties:
+- compatible : shall be "marvell,dove-divider-clock"
+- reg : shall be the register address of the Core PLL and Clock Divider
+ Control 0 register. This will cover that register, as well as the
+ Core PLL and Clock Divider Control 1 register. Thus, it will have
+ a size of 8.
+- #clock-cells : from common clock binding; shall be set to 1
+
+divider_clk: core-clock@0064 {
+ compatible = "marvell,dove-divider-clock";
+ reg = <0x0064 0x8>;
+ #clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
new file mode 100644
index 000000000000..26f237f641b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
@@ -0,0 +1,56 @@
+NVIDIA Tegra210 Clock And Reset Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
+for muxing and gating Tegra's clocks, and setting their rates.
+
+Required properties :
+- compatible : Should be "nvidia,tegra210-car"
+- reg : Should contain CAR registers location and length
+- clocks : Should contain phandle and clock specifiers for two clocks:
+ the 32 KHz "32k_in".
+- #clock-cells : Should be 1.
+ In clock consumers, this cell represents the clock ID exposed by the
+ CAR. The assignments may be found in header file
+ <dt-bindings/clock/tegra210-car.h>.
+- #reset-cells : Should be 1.
+ In clock consumers, this cell represents the bit number in the CAR's
+ array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
+
+Example SoC include file:
+
+/ {
+ tegra_car: clock {
+ compatible = "nvidia,tegra210-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ usb@c5004000 {
+ clocks = <&tegra_car TEGRA210_CLK_USB2>;
+ };
+};
+
+Example board file:
+
+/ {
+ clocks {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ clk_32k: clock@1 {
+ compatible = "fixed-clock";
+ reg = <1>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+ };
+
+ &tegra_car {
+ clocks = <&clk_32k>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt
new file mode 100644
index 000000000000..20cbca3f41d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt
@@ -0,0 +1,30 @@
+NXP LPC32xx Clock Controller
+
+Required properties:
+- compatible: should be "nxp,lpc3220-clk"
+- reg: should contain clock controller registers location and length
+- #clock-cells: must be 1, the cell holds id of a clock provided by the
+ clock controller
+- clocks: phandles of external oscillators, the list must contain one
+ 32768 Hz oscillator and may have one optional high frequency oscillator
+- clock-names: list of external oscillator clock names, must contain
+ "xtal_32k" and may have optional "xtal"
+
+Examples:
+
+ /* System Control Block */
+ scb {
+ compatible = "simple-bus";
+ ranges = <0x0 0x040004000 0x00001000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ clk: clock-controller@0 {
+ compatible = "nxp,lpc3220-clk";
+ reg = <0x00 0x114>;
+ #clock-cells = <1>;
+
+ clocks = <&xtal_32k>, <&xtal>;
+ clock-names = "xtal_32k", "xtal";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt
new file mode 100644
index 000000000000..0aa249409b51
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt
@@ -0,0 +1,22 @@
+NXP LPC32xx USB Clock Controller
+
+Required properties:
+- compatible: should be "nxp,lpc3220-usb-clk"
+- reg: should contain clock controller registers location and length
+- #clock-cells: must be 1, the cell holds id of a clock provided by the
+ USB clock controller
+
+Examples:
+
+ usb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x31020000 0x00001000>;
+
+ usbclk: clock-controller@f00 {
+ compatible = "nxp,lpc3220-usb-clk";
+ reg = <0xf00 0x100>;
+ #clock-cells = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 152dfaab2575..72f82f444091 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -13,6 +13,7 @@ Required properties :
"qcom,gcc-msm8974"
"qcom,gcc-msm8974pro"
"qcom,gcc-msm8974pro-ac"
+ "qcom,gcc-msm8996"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
index 34e7614d5074..8b0f7841af8d 100644
--- a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
@@ -9,6 +9,7 @@ Required properties :
"qcom,mmcc-msm8660"
"qcom,mmcc-msm8960"
"qcom,mmcc-msm8974"
+ "qcom,mmcc-msm8996"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
index 38dcf0370143..ae36ab842919 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
@@ -20,6 +20,10 @@ Required Properties:
clocks must be specified. For clocks with multiple parents, invalid
settings must be specified as "<0>".
- #clock-cells: Must be 0
+
+
+Optional Properties:
+
- clock-output-names: The name of the clock as a free-form string
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
new file mode 100644
index 000000000000..ace05992a262
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
@@ -0,0 +1,56 @@
+* Rockchip RK3036 Clock and Reset Unit
+
+The RK3036 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3036-cru"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+ If missing pll rates are not changeable, due to the missing pll lock status.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3036-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "ext_i2s" - external I2S clock - optional,
+ - "ext_gmac" - external GMAC clock - optional
+
+Example: Clock controller node:
+
+ cru: cru@20000000 {
+ compatible = "rockchip,rk3036-cru";
+ reg = <0x20000000 0x1000>;
+ rockchip,grf = <&grf>;
+
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+Example: UART controller node that consumes the clock generated by the clock
+ controller:
+
+ uart0: serial@20060000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x20060000 0x100>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&cru SCLK_UART0>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt
new file mode 100644
index 000000000000..f323048127eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt
@@ -0,0 +1,58 @@
+* Rockchip RK3228 Clock and Reset Unit
+
+The RK3228 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3228-cru"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+ If missing pll rates are not changeable, due to the missing pll lock status.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3228-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "ext_i2s" - external I2S clock - optional,
+ - "ext_gmac" - external GMAC clock - optional
+ - "ext_hsadc" - external HSADC clock - optional
+ - "phy_50m_out" - output clock of the pll in the mac phy
+
+Example: Clock controller node:
+
+ cru: cru@20000000 {
+ compatible = "rockchip,rk3228-cru";
+ reg = <0x20000000 0x1000>;
+ rockchip,grf = <&grf>;
+
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+Example: UART controller node that consumes the clock generated by the clock
+ controller:
+
+ uart0: serial@10110000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x10110000 0x100>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&cru SCLK_UART0>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/samsung,s2mps11.txt b/Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
new file mode 100644
index 000000000000..2726c1d58a79
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
@@ -0,0 +1,49 @@
+Binding for Samsung S2M and S5M family clock generator block
+============================================================
+
+This is a part of device tree bindings for S2M and S5M family multi-function
+devices.
+More information can be found in bindings/mfd/sec-core.txt file.
+
+The S2MPS11/13/15 and S5M8767 provide three(AP/CP/BT) buffered 32.768 kHz
+outputs. The S2MPS14 provides two (AP/BT) buffered 32.768 KHz outputs.
+
+To register these as clocks with common clock framework instantiate under
+main device node a sub-node named "clocks".
+
+It uses the common clock binding documented in:
+ - Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+
+Required properties of the "clocks" sub-node:
+ - #clock-cells: should be 1.
+ - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps13-clk",
+ "samsung,s2mps14-clk", "samsung,s5m8767-clk"
+ The S2MPS15 uses the same compatible as S2MPS13, as both provides similar
+ clocks.
+
+
+Each clock is assigned an identifier and client nodes use this identifier
+to specify the clock which they consume.
+ Clock ID Devices
+ ----------------------------------------------------------
+ 32KhzAP 0 S2MPS11/13/14/15, S5M8767
+ 32KhzCP 1 S2MPS11/13/15, S5M8767
+ 32KhzBT 2 S2MPS11/13/14/15, S5M8767
+
+Include dt-bindings/clock/samsung,s2mps11.h file to use preprocessor defines
+in device tree sources.
+
+
+Example:
+
+ s2mps11_pmic@66 {
+ compatible = "samsung,s2mps11-pmic";
+ reg = <0x66>;
+
+ s2m_osc: clocks {
+ compatible = "samsung,s2mps11-clk";
+ #clock-cells = <1>;
+ clock-output-names = "xx", "yy", "zz";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 8a47b77abfca..e59f57b24777 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -27,7 +27,9 @@ Required properties:
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
+ "allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
+ "allwinner,sun8i-h3-ahb2-clk" - for the AHB2 clock on H3
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
"allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80
@@ -55,6 +57,9 @@ Required properties:
"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
+ "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3
+ "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
+ "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
@@ -68,8 +73,10 @@ Required properties:
"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
"allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23
+ "allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3
"allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
+ "allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
Required properties for all clocks:
- reg : shall be the control register address for the clock.
@@ -89,6 +96,9 @@ Required properties for all clocks:
And "allwinner,*-usb-clk" clocks also require:
- reset-cells : shall be set to 1
+The "allwinner,sun4i-a10-ve-clk" clock also requires:
+- reset-cells : shall be set to 0
+
The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
- #reset-cells : shall be set to 1
- resets : shall be the reset control phandle for the mmc block.
diff --git a/Documentation/devicetree/bindings/clock/tango4-clock.txt b/Documentation/devicetree/bindings/clock/tango4-clock.txt
new file mode 100644
index 000000000000..19c580a7bda2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/tango4-clock.txt
@@ -0,0 +1,23 @@
+* Sigma Designs Tango4 Clock Generator
+
+The Tango4 clock generator outputs cpu_clk and sys_clk (the latter is used
+for RAM and various peripheral devices). The clock binding described here
+is applicable to all Tango4 SoCs.
+
+Required Properties:
+
+- compatible: should be "sigma,tango4-clkgen".
+- reg: physical base address of the device and length of memory mapped region.
+- clocks: phandle of the input clock (crystal oscillator).
+- clock-output-names: should be "cpuclk" and "sysclk".
+- #clock-cells: should be set to 1.
+
+Example:
+
+ clkgen: clkgen@10000 {
+ compatible = "sigma,tango4-clkgen";
+ reg = <0x10000 0x40>;
+ clocks = <&xtal>;
+ clock-output-names = "cpuclk", "sysclk";
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
index 0715695e94a9..2aa06ac0fac5 100644
--- a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
+++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
@@ -12,7 +12,7 @@ must be present contiguously. Generic DT driver will check only node 'x' for
cpu:x.
Required properties:
-- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt
for details
Optional properties:
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
index e41c98ffbccb..dd3929e85dec 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
@@ -11,7 +11,7 @@ Required properties:
- None
Optional properties:
-- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt for
+- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt for
details. OPPs *must* be supplied either via DT, i.e. this property, or
populated at runtime.
- clock-latency: Specify the possible maximum transition latency for clock,
diff --git a/Documentation/devicetree/bindings/display/bridge/tda998x.txt b/Documentation/devicetree/bindings/display/bridge/tda998x.txt
index e9e4bce40760..e178e6b9f9ee 100644
--- a/Documentation/devicetree/bindings/display/bridge/tda998x.txt
+++ b/Documentation/devicetree/bindings/display/bridge/tda998x.txt
@@ -5,6 +5,10 @@ Required properties;
- reg: I2C address
+Required node:
+ - port: Input port node with endpoint definition, as described
+ in Documentation/devicetree/bindings/graph.txt
+
Optional properties:
- interrupts: interrupt number and trigger type
default: polling
diff --git a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
new file mode 100644
index 000000000000..ed5e0a7894ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
@@ -0,0 +1,54 @@
+Etnaviv DRM master device
+=========================
+
+The Etnaviv DRM master device is a virtual device needed to list all
+Vivante GPU cores that comprise the GPU subsystem.
+
+Required properties:
+- compatible: Should be one of
+ "fsl,imx-gpu-subsystem"
+ "marvell,dove-gpu-subsystem"
+- cores: Should contain a list of phandles pointing to Vivante GPU devices
+
+example:
+
+gpu-subsystem {
+ compatible = "fsl,imx-gpu-subsystem";
+ cores = <&gpu_2d>, <&gpu_3d>;
+};
+
+
+Vivante GPU core devices
+========================
+
+Required properties:
+- compatible: Should be "vivante,gc"
+ A more specific compatible is not needed, as the cores contain chip
+ identification registers at fixed locations, which provide all the
+ necessary information to the driver.
+- reg: should be register base and length as documented in the
+ datasheet
+- interrupts: Should contain the cores interrupt line
+- clocks: should contain one clock for entry in clock-names
+ see Documentation/devicetree/bindings/clock/clock-bindings.txt
+- clock-names:
+ - "bus": AXI/register clock
+ - "core": GPU core clock
+ - "shader": Shader clock (only required if GPU has feature PIPE_3D)
+
+Optional properties:
+- power-domains: a power domain consumer specifier according to
+ Documentation/devicetree/bindings/power/power_domain.txt
+
+example:
+
+gpu_3d: gpu@00130000 {
+ compatible = "vivante,gc";
+ reg = <0x00130000 0x4000>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_GPU3D_AXI>,
+ <&clks IMX6QDL_CLK_GPU3D_CORE>,
+ <&clks IMX6QDL_CLK_GPU3D_SHADER>;
+ clock-names = "bus", "core", "shader";
+ power-domains = <&gpc 1>;
+};
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt
index 64693f2ebc51..fe4a7a2dea9c 100644
--- a/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt
+++ b/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt
@@ -1,3 +1,20 @@
+Device-Tree bindings for Samsung Exynos Embedded DisplayPort Transmitter(eDP)
+
+DisplayPort is industry standard to accommodate the growing board adoption
+of digital display technology within the PC and CE industries.
+It consolidates the internal and external connection methods to reduce device
+complexity and cost. It also supports necessary features for important cross
+industry applications and provides performance scalability to enable the next
+generation of displays that feature higher color depths, refresh rates, and
+display resolutions.
+
+eDP (embedded display port) device is compliant with Embedded DisplayPort
+standard as follows,
+- DisplayPort standard 1.1a for Exynos5250 and Exynos5260.
+- DisplayPort standard 1.3 for Exynos5422s and Exynos5800.
+
+eDP resides between FIMD and panel or FIMD and bridge such as LVDS.
+
The Exynos display port interface should be configured based on
the type of panel connected to it.
@@ -66,8 +83,15 @@ Optional properties for dp-controller:
Hotplug detect GPIO.
Indicates which GPIO should be used for hotplug
detection
- -video interfaces: Device node can contain video interface port
- nodes according to [1].
+Video interfaces:
+ Device node can contain video interface port nodes according to [1].
+ The following are properties specific to those nodes:
+
+ endpoint node connected to bridge or panel node:
+ - remote-endpoint: specifies the endpoint in panel or bridge node.
+ This node is required in all kinds of exynos dp
+ to represent the connection between dp and bridge
+ or dp and panel.
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
@@ -111,9 +135,18 @@ Board Specific portion:
};
ports {
- port@0 {
+ port {
dp_out: endpoint {
- remote-endpoint = <&bridge_in>;
+ remote-endpoint = <&dp_in>;
+ };
+ };
+ };
+
+ panel {
+ ...
+ port {
+ dp_in: endpoint {
+ remote-endpoint = <&dp_out>;
};
};
};
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt b/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
index 1fd8cf9cbfac..d474f59be6d6 100644
--- a/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
+++ b/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
@@ -2,10 +2,9 @@ Device-Tree bindings for drm hdmi driver
Required properties:
- compatible: value should be one among the following:
- 1) "samsung,exynos5-hdmi" <DEPRECATED>
- 2) "samsung,exynos4210-hdmi"
- 3) "samsung,exynos4212-hdmi"
- 4) "samsung,exynos5420-hdmi"
+ 1) "samsung,exynos4210-hdmi"
+ 2) "samsung,exynos4212-hdmi"
+ 3) "samsung,exynos5420-hdmi"
- reg: physical base address of the hdmi and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt
index f344b9e49198..e7423bea1424 100644
--- a/Documentation/devicetree/bindings/display/msm/dsi.txt
+++ b/Documentation/devicetree/bindings/display/msm/dsi.txt
@@ -14,17 +14,20 @@ Required properties:
- clocks: device clocks
See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
- clock-names: the following clocks are required:
+ * "mdp_core_clk"
+ * "iface_clk"
* "bus_clk"
- * "byte_clk"
- * "core_clk"
* "core_mmss_clk"
- * "iface_clk"
- * "mdp_core_clk"
+ * "byte_clk"
* "pixel_clk"
+ * "core_clk"
+ For DSIv2, we need an additional clock:
+ * "src_clk"
- vdd-supply: phandle to vdd regulator device node
- vddio-supply: phandle to vdd-io regulator device node
- vdda-supply: phandle to vdda regulator device node
- qcom,dsi-phy: phandle to DSI PHY device node
+- syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2)
Optional properties:
- panel@0: Node of panel connected to this DSI controller.
@@ -51,6 +54,7 @@ Required properties:
* "qcom,dsi-phy-28nm-hpm"
* "qcom,dsi-phy-28nm-lp"
* "qcom,dsi-phy-20nm"
+ * "qcom,dsi-phy-28nm-8960"
- reg: Physical base address and length of the registers of PLL, PHY and PHY
regulator
- reg-names: The names of register regions. The following regions are required:
diff --git a/Documentation/devicetree/bindings/display/msm/mdp.txt b/Documentation/devicetree/bindings/display/msm/mdp.txt
index 0833edaba4c3..a214f6cd0363 100644
--- a/Documentation/devicetree/bindings/display/msm/mdp.txt
+++ b/Documentation/devicetree/bindings/display/msm/mdp.txt
@@ -2,18 +2,28 @@ Qualcomm adreno/snapdragon display controller
Required properties:
- compatible:
- * "qcom,mdp" - mdp4
+ * "qcom,mdp4" - mdp4
+ * "qcom,mdp5" - mdp5
- reg: Physical base address and length of the controller's registers.
- interrupts: The interrupt signal from the display controller.
- connectors: array of phandles for output device(s)
- clocks: device clocks
See ../clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required:
- * "core_clk"
- * "iface_clk"
- * "src_clk"
- * "hdmi_clk"
- * "mpd_clk"
+- clock-names: the following clocks are required.
+ For MDP4:
+ * "core_clk"
+ * "iface_clk"
+ * "lut_clk"
+ * "src_clk"
+ * "hdmi_clk"
+ * "mdp_clk"
+ For MDP5:
+ * "bus_clk"
+ * "iface_clk"
+ * "core_clk_src"
+ * "core_clk"
+ * "lut_clk" (some MDP5 versions may not need this)
+ * "vsync_clk"
Optional properties:
- gpus: phandle for gpu device
@@ -26,7 +36,7 @@ Example:
...
mdp: qcom,mdp@5100000 {
- compatible = "qcom,mdp";
+ compatible = "qcom,mdp4";
reg = <0x05100000 0xf0000>;
interrupts = <GIC_SPI 75 0>;
connectors = <&hdmi>;
diff --git a/Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt b/Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt
new file mode 100644
index 000000000000..50be5e2438b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt
@@ -0,0 +1,7 @@
+Boe Corporation 8.0" WUXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "boe,tv080wum-nl0"
+
+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/innolux,g121x1-l03.txt b/Documentation/devicetree/bindings/display/panel/innolux,g121x1-l03.txt
new file mode 100644
index 000000000000..649744620ae1
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/innolux,g121x1-l03.txt
@@ -0,0 +1,7 @@
+Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,g121x1-l03"
+
+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/kyo,tcg121xglp.txt b/Documentation/devicetree/bindings/display/panel/kyo,tcg121xglp.txt
new file mode 100644
index 000000000000..a8e940fe731e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/kyo,tcg121xglp.txt
@@ -0,0 +1,7 @@
+Kyocera Corporation 12.1" XGA (1024x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "kyo,tcg121xglp"
+
+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/panasonic,vvx10f034n00.txt b/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f034n00.txt
new file mode 100644
index 000000000000..37dedf6a6702
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f034n00.txt
@@ -0,0 +1,20 @@
+Panasonic 10" WUXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "panasonic,vvx10f034n00"
+- reg: DSI virtual channel of the peripheral
+- power-supply: phandle of the regulator that provides the supply voltage
+
+Optional properties:
+- backlight: phandle of the backlight device attached to the panel
+
+Example:
+
+ mdss_dsi@fd922800 {
+ panel@0 {
+ compatible = "panasonic,vvx10f034n00";
+ reg = <0>;
+ power-supply = <&vreg_vsp>;
+ backlight = <&lp8566_wled>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt b/Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt
new file mode 100644
index 000000000000..0fbdab89ac3d
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt
@@ -0,0 +1,7 @@
+QiaoDian XianShi Corporation 4"3 TFT LCD panel
+
+Required properties:
+- compatible: should be "qiaodian,qd43003c0-40"
+
+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/sharp,ls043t1le01.txt b/Documentation/devicetree/bindings/display/panel/sharp,ls043t1le01.txt
new file mode 100644
index 000000000000..3770a111968b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/sharp,ls043t1le01.txt
@@ -0,0 +1,22 @@
+Sharp Microelectronics 4.3" qHD TFT LCD panel
+
+Required properties:
+- compatible: should be "sharp,ls043t1le01-qhd"
+- reg: DSI virtual channel of the peripheral
+- power-supply: phandle of the regulator that provides the supply voltage
+
+Optional properties:
+- backlight: phandle of the backlight device attached to the panel
+- reset-gpios: a GPIO spec for the reset pin
+
+Example:
+
+ mdss_dsi@fd922800 {
+ panel@0 {
+ compatible = "sharp,ls043t1le01-qhd";
+ reg = <0>;
+ avdd-supply = <&pm8941_l22>;
+ backlight = <&pm8941_wled>;
+ reset-gpios = <&pm8941_gpios 19 GPIO_ACTIVE_HIGH>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/panel/startek,startek-kd050c.txt b/Documentation/devicetree/bindings/display/panel/startek,startek-kd050c.txt
new file mode 100644
index 000000000000..70cd8d18d841
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/startek,startek-kd050c.txt
@@ -0,0 +1,4 @@
+Startek Electronic Technology Co. KD050C 5.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "startek,startek-kd050c"
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
new file mode 100644
index 000000000000..1753f0cc6fad
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -0,0 +1,60 @@
+Rockchip specific extensions to the Synopsys Designware MIPI DSI
+================================
+
+Required properties:
+- #address-cells: Should be <1>.
+- #size-cells: Should be <0>.
+- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
+- reg: Represent the physical address range of the controller.
+- interrupts: Represent the controller's interrupt to the CPU(s).
+- clocks, clock-names: Phandles to the controller's pll reference
+ clock(ref) and APB clock(pclk), as described in [1].
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- ports: contain a port node with endpoint definitions as defined in [2].
+ For vopb,set the reg = <0> and set the reg = <1> for vopl.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+ mipi_dsi: mipi@ff960000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi";
+ reg = <0xff960000 0x4000>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_MIPI_24M>, <&cru PCLK_MIPI_DSI0>;
+ clock-names = "ref", "pclk";
+ rockchip,grf = <&grf>;
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ mipi_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mipi_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_mipi>;
+ };
+ mipi_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_mipi>;
+ };
+ };
+ };
+
+ panel {
+ compatible ="boe,tv080wum-nl0";
+ reg = <0>;
+
+ enable-gpios = <&gpio7 3 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_en>;
+ backlight = <&backlight>;
+ status = "okay";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
index d15351f2313d..5489b59e3d41 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
@@ -7,6 +7,7 @@ buffer to an external LCD interface.
Required properties:
- compatible: value should be one of the following
"rockchip,rk3288-vop";
+ "rockchip,rk3036-vop";
- interrupts: should contain a list of all VOP IP block interrupts in the
order: VSYNC, LCD_SYSTEM. The interrupt specifier
diff --git a/Documentation/devicetree/bindings/display/simple-framebuffer.txt b/Documentation/devicetree/bindings/display/simple-framebuffer.txt
index 4474ef6e0b95..8c9e9f515c87 100644
--- a/Documentation/devicetree/bindings/display/simple-framebuffer.txt
+++ b/Documentation/devicetree/bindings/display/simple-framebuffer.txt
@@ -47,10 +47,14 @@ Required properties:
- a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r).
Optional properties:
-- clocks : List of clocks used by the framebuffer. Clocks listed here
- are expected to already be configured correctly. The OS must
- ensure these clocks are not modified or disabled while the
- simple framebuffer remains active.
+- clocks : List of clocks used by the framebuffer.
+- *-supply : Any number of regulators used by the framebuffer. These should
+ be named according to the names in the device's design.
+
+ The above resources are expected to already be configured correctly.
+ The OS must ensure they are not modified or disabled while the simple
+ framebuffer remains active.
+
- display : phandle pointing to the primary display hardware node
Example:
@@ -68,6 +72,7 @@ chosen {
stride = <(1600 * 2)>;
format = "r5g6b5";
clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>;
+ lcd-supply = <&reg_dc1sw>;
display = <&lcdc0>;
};
stdout-path = "display0";
diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
index 09daeef1ff22..5b902ac8d97e 100644
--- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
+++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
@@ -14,7 +14,14 @@ not described in these device tree bindings.
Required Properties:
-- compatible: must contain "renesas,rcar-dmac"
+- compatible: "renesas,dmac-<soctype>", "renesas,rcar-dmac" as fallback.
+ Examples with soctypes are:
+ - "renesas,dmac-r8a7790" (R-Car H2)
+ - "renesas,dmac-r8a7791" (R-Car M2-W)
+ - "renesas,dmac-r8a7792" (R-Car V2H)
+ - "renesas,dmac-r8a7793" (R-Car M2-N)
+ - "renesas,dmac-r8a7794" (R-Car E2)
+ - "renesas,dmac-r8a7795" (R-Car H3)
- reg: base address and length of the registers block for the DMAC
@@ -35,7 +42,7 @@ Required Properties:
Example: R8A7790 (R-Car H2) SYS-DMACs
dmac0: dma-controller@e6700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xe6700000 0 0x20000>;
interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH
0 200 IRQ_TYPE_LEVEL_HIGH
@@ -65,7 +72,7 @@ Example: R8A7790 (R-Car H2) SYS-DMACs
};
dmac1: dma-controller@e6720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xe6720000 0 0x20000>;
interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
0 216 IRQ_TYPE_LEVEL_HIGH
diff --git a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt
index 040f365954cc..e7780a186a36 100644
--- a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt
+++ b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt
@@ -1,7 +1,13 @@
* Renesas USB DMA Controller Device Tree bindings
Required Properties:
-- compatible: must contain "renesas,usb-dmac"
+-compatible: "renesas,<soctype>-usb-dmac", "renesas,usb-dmac" as fallback.
+ Examples with soctypes are:
+ - "renesas,r8a7790-usb-dmac" (R-Car H2)
+ - "renesas,r8a7791-usb-dmac" (R-Car M2-W)
+ - "renesas,r8a7793-usb-dmac" (R-Car M2-N)
+ - "renesas,r8a7794-usb-dmac" (R-Car E2)
+ - "renesas,r8a7795-usb-dmac" (R-Car H3)
- reg: base address and length of the registers block for the DMAC
- interrupts: interrupt specifiers for the DMAC, one for each entry in
interrupt-names.
@@ -15,7 +21,7 @@ Required Properties:
Example: R8A7790 (R-Car H2) USB-DMACs
usb_dmac0: dma-controller@e65a0000 {
- compatible = "renesas,usb-dmac";
+ compatible = "renesas,r8a7790-usb-dmac", "renesas,usb-dmac";
reg = <0 0xe65a0000 0 0x100>;
interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH
0 109 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/dma/stm32-dma.txt b/Documentation/devicetree/bindings/dma/stm32-dma.txt
new file mode 100644
index 000000000000..70cd13f1588a
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/stm32-dma.txt
@@ -0,0 +1,82 @@
+* STMicroelectronics STM32 DMA controller
+
+The STM32 DMA is a general-purpose direct memory access controller capable of
+supporting 8 independent DMA channels. Each channel can have up to 8 requests.
+
+Required properties:
+- compatible: Should be "st,stm32-dma"
+- reg: Should contain DMA registers location and length. This should include
+ all of the per-channel registers.
+- interrupts: Should contain all of the per-channel DMA interrupts in
+ ascending order with respect to the DMA channel index.
+- clocks: Should contain the input clock of the DMA instance.
+- #dma-cells : Must be <4>. See DMA client paragraph for more details.
+
+Optional properties:
+- resets: Reference to a reset controller asserting the DMA controller
+- st,mem2mem: boolean; if defined, it indicates that the controller supports
+ memory-to-memory transfer
+
+Example:
+
+ dma2: dma-controller@40026400 {
+ compatible = "st,stm32-dma";
+ reg = <0x40026400 0x400>;
+ interrupts = <56>,
+ <57>,
+ <58>,
+ <59>,
+ <60>,
+ <68>,
+ <69>,
+ <70>;
+ clocks = <&clk_hclk>;
+ #dma-cells = <4>;
+ st,mem2mem;
+ resets = <&rcc 150>;
+ };
+
+* DMA client
+
+DMA clients connected to the STM32 DMA controller must use the format
+described in the dma.txt file, using a five-cell specifier for each
+channel: a phandle plus four integer cells.
+The four cells in order are:
+
+1. The channel id
+2. The request line number
+3. A 32bit mask specifying the DMA channel configuration which are device
+ dependent:
+ -bit 9: Peripheral Increment Address
+ 0x0: no address increment between transfers
+ 0x1: increment address between transfers
+ -bit 10: Memory Increment Address
+ 0x0: no address increment between transfers
+ 0x1: increment address between transfers
+ -bit 15: Peripheral Increment Offset Size
+ 0x0: offset size is linked to the peripheral bus width
+ 0x1: offset size is fixed to 4 (32-bit alignment)
+ -bit 16-17: Priority level
+ 0x0: low
+ 0x1: medium
+ 0x2: high
+ 0x3: very high
+5. A 32bit mask specifying the DMA FIFO threshold configuration which are device
+ dependent:
+ -bit 0-1: Fifo threshold
+ 0x0: 1/4 full FIFO
+ 0x1: 1/2 full FIFO
+ 0x2: 3/4 full FIFO
+ 0x3: full FIFO
+
+Example:
+
+ usart1: serial@40011000 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40011000 0x400>;
+ interrupts = <37>;
+ clocks = <&clk_pclk2>;
+ dmas = <&dma2 2 4 0x10400 0x3>,
+ <&dma2 7 5 0x10200 0x3>;
+ dma-names = "rx", "tx";
+ };
diff --git a/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt b/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
index b152a75dceae..aead5869a28d 100644
--- a/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
+++ b/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
@@ -14,6 +14,10 @@ The DMA controller node need to have the following poroperties:
Optional properties:
- ti,dma-safe-map: Safe routing value for unused request lines
+- ti,reserved-dma-request-ranges: DMA request ranges which should not be used
+ when mapping xbar input to DMA request, they are either
+ allocated to be used by for example the DSP or they are used as
+ memcpy channels in eDMA.
Notes:
When requesting channel via ti,dra7-dma-crossbar, the DMA clinet must request
@@ -46,6 +50,8 @@ sdma_xbar: dma-router@4a002b78 {
#dma-cells = <1>;
dma-requests = <205>;
ti,dma-safe-map = <0>;
+ /* Protect the sDMA request ranges: 10-14 and 100-126 */
+ ti,reserved-dma-request-ranges = <10 5>, <100 27>;
dma-masters = <&sdma>;
};
diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
index 4342c10de1bf..735bc94444bb 100644
--- a/Documentation/devicetree/bindings/eeprom/eeprom.txt
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -2,11 +2,22 @@ EEPROMs (I2C)
Required properties:
- - compatible : should be "<manufacturer>,<type>"
- If there is no specific driver for <manufacturer>, a generic
- driver based on <type> is selected. Possible types are:
- 24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
- 24c128, 24c256, 24c512, 24c1024, spd
+ - compatible : should be "<manufacturer>,<type>", like these:
+
+ "atmel,24c00", "atmel,24c01", "atmel,24c02", "atmel,24c04",
+ "atmel,24c08", "atmel,24c16", "atmel,24c32", "atmel,24c64",
+ "atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024"
+
+ "catalyst,24c32"
+
+ "ramtron,24c64"
+
+ "renesas,r1ex24002"
+
+ If there is no specific driver for <manufacturer>, a generic
+ driver based on <type> is selected. Possible types are:
+ "24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64",
+ "24c128", "24c256", "24c512", "24c1024", "spd"
- reg : the I2C address of the EEPROM
diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt
index e1705fae63a8..e27341f8a4c7 100644
--- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt
+++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt
@@ -13,3 +13,63 @@ Optional properties:
ARIZONA_ACCDET_MODE_HPR or 2 - Headphone detect mode is set to HPDETR
If this node is not mentioned or if the value is unknown, then
headphone detection mode is set to HPDETL.
+
+ - wlf,use-jd2 : Use the additional JD input along with JD1 for dual pin jack
+ detection.
+ - wlf,use-jd2-nopull : Internal pull on JD2 is disabled when used for
+ jack detection.
+ - wlf,jd-invert : Invert the polarity of the jack detection switch
+
+ - wlf,micd-software-compare : Use a software comparison to determine mic
+ presence
+ - wlf,micd-detect-debounce : Additional software microphone detection
+ debounce specified in milliseconds.
+ - wlf,micd-pol-gpio : GPIO specifier for the GPIO controlling the headset
+ polarity if one exists.
+ - wlf,micd-bias-start-time : Time allowed for MICBIAS to startup prior to
+ performing microphone detection, specified as per the ARIZONA_MICD_TIME_XXX
+ defines.
+ - wlf,micd-rate : Delay between successive microphone detection measurements,
+ specified as per the ARIZONA_MICD_TIME_XXX defines.
+ - wlf,micd-dbtime : Microphone detection hardware debounces specified as the
+ number of measurements to take, valid values being 2 and 4.
+ - wlf,micd-timeout-ms : Timeout for microphone detection, specified in
+ milliseconds.
+ - wlf,micd-force-micbias : Force MICBIAS continuously on during microphone
+ detection.
+ - wlf,micd-configs : Headset polarity configurations (generally used for
+ detection of CTIA / OMTP headsets), the field can be of variable length
+ but should always be a multiple of 3 cells long, each three cell group
+ represents one polarity configuration.
+ The first cell defines the accessory detection pin, zero will use MICDET1
+ and all other values will use MICDET2.
+ The second cell represents the MICBIAS to be used.
+ The third cell represents the value of the micd-pol-gpio pin.
+
+ - wlf,gpsw : Settings for the general purpose switch
+
+Example:
+
+codec: wm8280@0 {
+ compatible = "wlf,wm8280";
+ reg = <0>;
+ ...
+
+ wlf,use-jd2;
+ wlf,use-jd2-nopull;
+ wlf,jd-invert;
+
+ wlf,micd-software-compare;
+ wlf,micd-detect-debounce = <0>;
+ wlf,micd-pol-gpio = <&codec 2 0>;
+ wlf,micd-rate = <ARIZONA_MICD_TIME_8MS>;
+ wlf,micd-dbtime = <4>;
+ wlf,micd-timeout-ms = <100>;
+ wlf,micd-force-micbias;
+ wlf,micd-configs = <
+ 0 1 0 /* MICDET1 MICBIAS1 GPIO=low */
+ 1 2 1 /* MICDET2 MICBIAS2 GPIO=high */
+ >;
+
+ wlf,gpsw = <0>;
+};
diff --git a/Documentation/devicetree/bindings/extcon/extcon-max3355.txt b/Documentation/devicetree/bindings/extcon/extcon-max3355.txt
new file mode 100644
index 000000000000..f2288ea9eb82
--- /dev/null
+++ b/Documentation/devicetree/bindings/extcon/extcon-max3355.txt
@@ -0,0 +1,21 @@
+Maxim Integrated MAX3355 USB OTG chip
+-------------------------------------
+
+MAX3355 integrates a charge pump and comparators to enable a system with an
+integrated USB OTG dual-role transceiver to function as a USB OTG dual-role
+device.
+
+Required properties:
+- compatible: should be "maxim,max3355";
+- maxim,shdn-gpios: should contain a phandle and GPIO specifier for the GPIO pin
+ connected to the MAX3355's SHDN# pin;
+- id-gpios: should contain a phandle and GPIO specifier for the GPIO pin
+ connected to the MAX3355's ID_OUT pin.
+
+Example:
+
+ usb-otg {
+ compatible = "maxim,max3355";
+ maxim,shdn-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
+ id-gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
index 13df9933f4cd..6b4a98f74be3 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
@@ -25,6 +25,7 @@ Required properties:
ti,tca6416
ti,tca6424
ti,tca9539
+ onsemi,pca9654
exar,xra1202
Example:
diff --git a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
index ba2bb84eeac3..c809acb9c71b 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
@@ -5,7 +5,8 @@ Required properties:
- compatible: should be "semtech,sx1506q",
"semtech,sx1508q",
- "semtech,sx1509q".
+ "semtech,sx1509q",
+ "semtech,sx1502q".
- reg: The I2C slave address for this device.
diff --git a/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt b/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt
new file mode 100644
index 000000000000..ba051074bedc
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt
@@ -0,0 +1,16 @@
+* TPS65086 GPO Controller bindings
+
+Required properties:
+ - compatible : Should be "ti,tps65086-gpio".
+ - gpio-controller : Marks the device node as a GPIO Controller.
+ - #gpio-cells : Should be two. The first cell is the pin number
+ and the second cell is used to specify flags.
+ See ../gpio/gpio.txt for possible values.
+
+Example:
+
+ gpio4: gpio {
+ compatible = "ti,tps65086-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
index dd5d2c0394b1..4d6c8cdc8586 100644
--- a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
@@ -24,7 +24,7 @@ controller.
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt. Shall be set to 2. The first cell defines the interrupt number,
the second encodes the triger flags encoded as described in
- Documentation/devicetree/bindings/interrupts.txt
+ Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- interrupt-parent : The parent interrupt controller.
- interrupts : The interrupt to the parent controller raised when GPIOs
generate the interrupts.
diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
index 6e81dc153f3b..ef973a0343c7 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
@@ -3,7 +3,7 @@ I2C for Atmel platforms
Required properties :
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
- "atmel,at91sam9x5-i2c" or "atmel,sama5d2-i2c"
+ "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
@@ -17,6 +17,8 @@ Optional properties:
- dma-names: should contain "tx" and "rx".
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
capable I2C controllers.
+- i2c-sda-hold-time-ns: TWD hold time, only available for "atmel,sama5d4-i2c"
+ and "atmel,sama5d2-i2c".
- Child nodes conforming to i2c bus binding
Examples :
@@ -52,6 +54,7 @@ i2c0: i2c@f8034600 {
#size-cells = <0>;
clocks = <&flx0>;
atmel,fifo-size = <16>;
+ i2c-sda-hold-time-ns = <336>;
wm8731: wm8731@1a {
compatible = "wm8731";
diff --git a/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt b/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt
index d6f724efdcf2..aeceaceba3c5 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt
@@ -2,7 +2,7 @@ Broadcom stb bsc iic master controller
Required properties:
-- compatible: should be "brcm,brcmstb-i2c"
+- compatible: should be "brcm,brcmstb-i2c" or "brcm,brcmper-i2c"
- clock-frequency: 32-bit decimal value of iic master clock freqency in Hz
valid values are 375000, 390000, 187500, 200000
93750, 97500, 46875 and 50000
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
index ea406eb20fa5..95e97223a71c 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
@@ -20,6 +20,10 @@ Optional properties:
propoerty indicates the default frequency 100 kHz.
- clocks: clock specifier.
+- i2c-scl-falling-time-ns: see i2c.txt
+- i2c-scl-internal-delay-ns: see i2c.txt
+- i2c-scl-rising-time-ns: see i2c.txt
+
Examples :
i2c0: i2c@e6508000 {
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
index 8a99150ac3a7..c8d977ed847f 100644
--- a/Documentation/devicetree/bindings/i2c/i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c.txt
@@ -29,12 +29,38 @@ Optional properties
These properties may not be supported by all drivers. However, if a driver
wants to support one of the below features, it should adapt the bindings below.
-- clock-frequency - frequency of bus clock in Hz.
-- wakeup-source - device can be used as a wakeup source.
+- clock-frequency
+ frequency of bus clock in Hz.
-- interrupts - interrupts used by the device.
-- interrupt-names - "irq" and "wakeup" names are recognized by I2C core,
- other names are left to individual drivers.
+- i2c-scl-falling-time-ns
+ Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C
+ specification.
+
+- i2c-scl-internal-delay-ns
+ Number of nanoseconds the IP core additionally needs to setup SCL.
+
+- i2c-scl-rising-time-ns
+ Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C
+ specification.
+
+- i2c-sda-falling-time-ns
+ Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
+ specification.
+
+- interrupts
+ interrupts used by the device.
+
+- interrupt-names
+ "irq" and "wakeup" names are recognized by I2C core, other names are
+ left to individual drivers.
+
+- multi-master
+ states that there is another master active on this bus. The OS can use
+ this information to adapt power management to keep the arbitration awake
+ all the time, for example.
+
+- wakeup-source
+ device can be used as a wakeup source.
Binding may contain optional "interrupts" property, describing interrupts
used by the device. I2C core will assign "irq" interrupt (or the very first
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index c50cf13c852e..539874490492 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -20,22 +20,11 @@ adi,adt7476 +/-1C TDM Extended Temp Range I.C
adi,adt7490 +/-1C TDM Extended Temp Range I.C
adi,adxl345 Three-Axis Digital Accelerometer
adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
+ams,iaq-core AMS iAQ-Core VOC Sensor
at,24c08 i2c serial eeprom (24cxx)
-atmel,24c00 i2c serial eeprom (24cxx)
-atmel,24c01 i2c serial eeprom (24cxx)
-atmel,24c02 i2c serial eeprom (24cxx)
-atmel,24c04 i2c serial eeprom (24cxx)
-atmel,24c16 i2c serial eeprom (24cxx)
-atmel,24c32 i2c serial eeprom (24cxx)
-atmel,24c64 i2c serial eeprom (24cxx)
-atmel,24c128 i2c serial eeprom (24cxx)
-atmel,24c256 i2c serial eeprom (24cxx)
-atmel,24c512 i2c serial eeprom (24cxx)
-atmel,24c1024 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor
capella,cm3232 CM3232: Ambient Light Sensor
-catalyst,24c32 i2c serial eeprom
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
dallas,ds1338 I2C RTC with 56-Byte NV RAM
@@ -49,11 +38,13 @@ dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
dallas,ds75 Digital Thermometer and Thermostat
dlg,da9053 DA9053: flexible system level PMIC with multicore support
dlg,da9063 DA9063: system PMIC for quad-core application processors
+epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE
epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
+fsl,mpl3115 MPL3115: Absolute Digital Pressure Sensor
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
@@ -80,7 +71,6 @@ ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI an
pericom,pt7c4338 Real-time Clock Module
plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
pulsedlight,lidar-lite-v2 Pulsedlight LIDAR range-finding sensor
-ramtron,24c64 i2c serial eeprom (24cxx)
ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
diff --git a/Documentation/devicetree/bindings/iio/accel/mma8452.txt b/Documentation/devicetree/bindings/iio/accel/mma8452.txt
index e3c37467d7da..3c10e8581144 100644
--- a/Documentation/devicetree/bindings/iio/accel/mma8452.txt
+++ b/Documentation/devicetree/bindings/iio/accel/mma8452.txt
@@ -7,13 +7,18 @@ Required properties:
* "fsl,mma8453"
* "fsl,mma8652"
* "fsl,mma8653"
+
- reg: the I2C address of the chip
Optional properties:
- interrupt-parent: should be the phandle for the interrupt controller
+
- interrupts: interrupt mapping for GPIO IRQ
+ - interrupt-names: should contain "INT1" and/or "INT2", the accelerometer's
+ interrupt line in use.
+
Example:
mma8453fc@1d {
@@ -21,4 +26,5 @@ Example:
reg = <0x1d>;
interrupt-parent = <&gpio1>;
interrupts = <5 0>;
+ interrupt-names = "INT2";
};
diff --git a/Documentation/devicetree/bindings/iio/adc/imx7d-adc.txt b/Documentation/devicetree/bindings/iio/adc/imx7d-adc.txt
new file mode 100644
index 000000000000..5c184b940669
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/imx7d-adc.txt
@@ -0,0 +1,22 @@
+Freescale imx7d ADC bindings
+
+The devicetree bindings are for the ADC driver written for
+imx7d SoC.
+
+Required properties:
+- compatible: Should be "fsl,imx7d-adc"
+- reg: Offset and length of the register set for the ADC device
+- interrupts: The interrupt number for the ADC device
+- clocks: The root clock of the ADC controller
+- clock-names: Must contain "adc", matching entry in the clocks property
+- vref-supply: The regulator supply ADC reference voltage
+
+Example:
+adc1: adc@30610000 {
+ compatible = "fsl,imx7d-adc";
+ reg = <0x30610000 0x10000>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_ADC_ROOT_CLK>;
+ clock-names = "adc";
+ vref-supply = <&reg_vcc_3v3_mcu>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
index 2a1f3af30155..bcd3ac8e6e0c 100644
--- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
@@ -10,16 +10,28 @@ must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
- "mcp3001"
- "mcp3002"
- "mcp3004"
- "mcp3008"
- "mcp3201"
- "mcp3202"
- "mcp3204"
- "mcp3208"
- "mcp3301"
+ "mcp3001" (DEPRECATED)
+ "mcp3002" (DEPRECATED)
+ "mcp3004" (DEPRECATED)
+ "mcp3008" (DEPRECATED)
+ "mcp3201" (DEPRECATED)
+ "mcp3202" (DEPRECATED)
+ "mcp3204" (DEPRECATED)
+ "mcp3208" (DEPRECATED)
+ "mcp3301" (DEPRECATED)
+ "microchip,mcp3001"
+ "microchip,mcp3002"
+ "microchip,mcp3004"
+ "microchip,mcp3008"
+ "microchip,mcp3201"
+ "microchip,mcp3202"
+ "microchip,mcp3204"
+ "microchip,mcp3208"
+ "microchip,mcp3301"
+
+ NOTE: The use of the compatibles with no vendor prefix
+ is deprecated and only listed because old DT use them.
Examples:
spi_controller {
diff --git a/Documentation/devicetree/bindings/iio/adc/mcp3422.txt b/Documentation/devicetree/bindings/iio/adc/mcp3422.txt
index 333139cc0bfb..dcae4ccfcc52 100644
--- a/Documentation/devicetree/bindings/iio/adc/mcp3422.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mcp3422.txt
@@ -1,7 +1,8 @@
-* Microchip mcp3422/3/4/6/7/8 chip family (ADC)
+* Microchip mcp3421/2/3/4/6/7/8 chip family (ADC)
Required properties:
- compatible: Should be
+ "microchip,mcp3421" or
"microchip,mcp3422" or
"microchip,mcp3423" or
"microchip,mcp3424" or
diff --git a/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt b/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt
new file mode 100644
index 000000000000..4bb9a86065d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt
@@ -0,0 +1,48 @@
+* Palmas general purpose ADC IP block devicetree bindings
+
+Channels list:
+ 0 battery type
+ 1 battery temp NTC (optional current source)
+ 2 GP
+ 3 temp (with ext. diode, optional current source)
+ 4 GP
+ 5 GP
+ 6 VBAT_SENSE
+ 7 VCC_SENSE
+ 8 Backup Battery voltage
+ 9 external charger (VCHG)
+ 10 VBUS
+ 11 DC-DC current probe (how does this work?)
+ 12 internal die temp
+ 13 internal die temp
+ 14 USB ID pin voltage
+ 15 test network
+
+Required properties:
+- compatible : Must be "ti,palmas-gpadc".
+- #io-channel-cells: Should be set to <1>.
+
+Optional sub-nodes:
+ti,channel0-current-microamp: Channel 0 current in uA.
+ Values are rounded to derive 0uA, 5uA, 15uA, 20uA.
+ti,channel3-current-microamp: Channel 3 current in uA.
+ Values are rounded to derive 0uA, 10uA, 400uA, 800uA.
+ti,enable-extended-delay: Enable extended delay.
+
+Example:
+
+pmic {
+ compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
+ ...
+ gpadc {
+ compatible = "ti,palmas-gpadc";
+ interrupts = <18 0
+ 16 0
+ 17 0>;
+ #io-channel-cells = <1>;
+ ti,channel0-current-microamp = <5>;
+ ti,channel3-current-microamp = <10>;
+ };
+ };
+ ...
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
index 15ca6b47958e..daa2b2c29428 100644
--- a/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
+++ b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
@@ -1,7 +1,7 @@
-* Texas Instruments' ADC128S052 and ADC122S021 ADC chip
+* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
Required properties:
- - compatible: Should be "ti,adc128s052" or "ti,adc122s021"
+ - compatible: Should be "ti,adc128s052", "ti,adc122s021" or "ti,adc124s021"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt b/Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt
new file mode 100644
index 000000000000..a02337d7efa4
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt
@@ -0,0 +1,20 @@
+* Texas Instruments' ADS8684 and ADS8688 ADC chip
+
+Required properties:
+ - compatible: Should be "ti,ads8684" or "ti,ads8688"
+ - reg: spi chip select number for the device
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional properties:
+ - vref-supply: The regulator supply for ADC reference voltage
+
+Example:
+adc@0 {
+ compatible = "ti,ads8688";
+ reg = <0>;
+ vref-supply = <&vdd_supply>;
+ spi-max-frequency = <1000000>;
+};
diff --git a/Documentation/devicetree/bindings/iio/health/max30100.txt b/Documentation/devicetree/bindings/iio/health/max30100.txt
new file mode 100644
index 000000000000..f6fbac66ad06
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/health/max30100.txt
@@ -0,0 +1,21 @@
+Maxim MAX30100 heart rate and pulse oximeter sensor
+
+* https://datasheets.maximintegrated.com/en/ds/MAX30100.pdf
+
+Required properties:
+ - compatible: must be "maxim,max30100"
+ - reg: the I2C address of the sensor
+ - interrupt-parent: should be the phandle for the interrupt controller
+ - interrupts: the sole interrupt generated by the device
+
+ Refer to interrupt-controller/interrupts.txt for generic
+ interrupt client node bindings.
+
+Example:
+
+max30100@057 {
+ compatible = "maxim,max30100";
+ reg = <57>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <16 2>;
+};
diff --git a/Documentation/devicetree/bindings/iio/light/us5182d.txt b/Documentation/devicetree/bindings/iio/light/us5182d.txt
index 6f0a530144fd..a61979997f37 100644
--- a/Documentation/devicetree/bindings/iio/light/us5182d.txt
+++ b/Documentation/devicetree/bindings/iio/light/us5182d.txt
@@ -7,13 +7,24 @@ Required properties:
Optional properties:
- upisemi,glass-coef: glass attenuation factor - compensation factor of
resolution 1000 for material transmittance.
+
- upisemi,dark-ths: array of 8 elements containing 16-bit thresholds (adc
counts) corresponding to every scale.
+
- upisemi,upper-dark-gain: 8-bit dark gain compensation factor(4 int and 4
fractional bits - Q4.4) applied when light > threshold
+
- upisemi,lower-dark-gain: 8-bit dark gain compensation factor(4 int and 4
fractional bits - Q4.4) applied when light < threshold
+- upisemi,continuous: This chip has two power modes: one-shot (chip takes one
+ measurement and then shuts itself down) and continuous (
+ chip takes continuous measurements). The one-shot mode is
+ more power-friendly but the continuous mode may be more
+ reliable. If this property is specified the continuous
+ mode will be used instead of the default one-shot one for
+ raw reads.
+
If the optional properties are not specified these factors will default to the
values in the below example.
The glass-coef defaults to no compensation for the covering material.
diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt
index d3ccdb190c53..d4b87cc1e446 100644
--- a/Documentation/devicetree/bindings/iio/st-sensors.txt
+++ b/Documentation/devicetree/bindings/iio/st-sensors.txt
@@ -36,6 +36,7 @@ Accelerometers:
- st,lsm303dlm-accel
- st,lsm330-accel
- st,lsm303agr-accel
+- st,lis2dh12-accel
Gyroscopes:
- st,l3g4200d-gyro
diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
index 8ba98eec765b..c98757a69110 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
@@ -13,6 +13,17 @@ Required properties:
- interrupt-parent : Interrupt controller to which the chip is connected
- interrupts : Interrupt to which the chip is connected
+Optional properties:
+
+ - irq-gpios : GPIO pin used for IRQ. The driver uses the
+ interrupt gpio pin as output to reset the device.
+ - reset-gpios : GPIO pin used for reset
+
+ - touchscreen-inverted-x : X axis is inverted (boolean)
+ - touchscreen-inverted-y : Y axis is inverted (boolean)
+ - touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
+ (swapping is done after inverting the axis)
+
Example:
i2c@00000000 {
@@ -23,6 +34,9 @@ Example:
reg = <0x5d>;
interrupt-parent = <&gpio>;
interrupts = <0 0>;
+
+ irq-gpios = <&gpio1 0 0>;
+ reset-gpios = <&gpio1 1 0>;
};
/* ... */
diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
index 8eb240a287c8..697a3e7831e7 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -9,7 +9,9 @@ Required properties:
- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
Optional properties:
-- reset-gpio: GPIO connected to the RESET line of the chip
+- reset-gpios: GPIO connected to the RESET line of the chip
+- enable-gpios: GPIO connected to the ENABLE line of the chip
+- wake-gpios: GPIO connected to the WAKE line of the chip
Example:
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ts4800-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ts4800-ts.txt
new file mode 100644
index 000000000000..4c1c092c276b
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/ts4800-ts.txt
@@ -0,0 +1,11 @@
+* TS-4800 Touchscreen bindings
+
+Required properties:
+- compatible: must be "technologic,ts4800-ts"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- syscon: phandle / integers array that points to the syscon node which
+ describes the FPGA's syscon registers.
+ - phandle to FPGA's syscon
+ - offset to the touchscreen register
+ - offset to the touchscreen enable bit
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt
index afef6a85ac51..b8e1674c7837 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt
@@ -14,6 +14,7 @@ Required properties:
"mediatek,mt6582-sysirq"
"mediatek,mt6580-sysirq"
"mediatek,mt6577-sysirq"
+ "mediatek,mt2701-sysirq"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Use the same format as specified by GIC in
Documentation/devicetree/bindings/arm/gic.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qca,ath79-misc-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/qca,ath79-misc-intc.txt
index ec96b1f01478..475ae9bd562b 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qca,ath79-misc-intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qca,ath79-misc-intc.txt
@@ -22,7 +22,7 @@ Interrupt Controllers bindings used by client devices.
Example:
interrupt-controller@18060010 {
- compatible = "qca,ar9132-misc-intc", qca,ar7100-misc-intc";
+ compatible = "qca,ar9132-misc-intc", "qca,ar7100-misc-intc";
reg = <0x18060010 0x4>;
interrupt-parent = <&cpuintc>;
diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
index cd29083e16ec..48ffb38f699e 100644
--- a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
+++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
@@ -7,7 +7,15 @@ connected to the IPMMU through a port called micro-TLB.
Required Properties:
- - compatible: Must contain "renesas,ipmmu-vmsa".
+ - compatible: Must contain SoC-specific and generic entries from below.
+
+ - "renesas,ipmmu-r8a73a4" for the R8A73A4 (R-Mobile APE6) IPMMU.
+ - "renesas,ipmmu-r8a7790" for the R8A7790 (R-Car H2) IPMMU.
+ - "renesas,ipmmu-r8a7791" for the R8A7791 (R-Car M2-W) IPMMU.
+ - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU.
+ - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU.
+ - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU.
+
- reg: Base address and size of the IPMMU registers.
- interrupts: Specifiers for the MMU fault interrupts. For instances that
support secure mode two interrupts must be specified, for non-secure and
@@ -27,7 +35,7 @@ node with the following property:
Example: R8A7791 IPMMU-MX and VSP1-D0 bus master
ipmmu_mx: mmu@fe951000 {
- compatible = "renasas,ipmmu-vmsa";
+ compatible = "renasas,ipmmu-r8a7791", "renasas,ipmmu-vmsa";
reg = <0 0xfe951000 0 0x1000>;
interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
<0 221 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/media/exynos5-gsc.txt b/Documentation/devicetree/bindings/media/exynos5-gsc.txt
index 0604d42f38d1..5fe9372abb37 100644
--- a/Documentation/devicetree/bindings/media/exynos5-gsc.txt
+++ b/Documentation/devicetree/bindings/media/exynos5-gsc.txt
@@ -7,6 +7,10 @@ Required properties:
- reg: should contain G-Scaler physical address location and length.
- interrupts: should contain G-Scaler interrupt number
+Optional properties:
+- samsung,sysreg: handle to syscon used to control the system registers to
+ set writeback input and destination
+
Example:
gsc_0: gsc@0x13e00000 {
diff --git a/Documentation/devicetree/bindings/media/i2c/adp1653.txt b/Documentation/devicetree/bindings/media/i2c/adp1653.txt
index 5ce66f2104e3..4cce0de40ee9 100644
--- a/Documentation/devicetree/bindings/media/i2c/adp1653.txt
+++ b/Documentation/devicetree/bindings/media/i2c/adp1653.txt
@@ -12,12 +12,13 @@ There are two LED outputs available - flash and indicator. One LED is
represented by one child node, nodes need to be named "flash" and "indicator".
Required properties of the LED child node:
-- max-microamp : see Documentation/devicetree/bindings/leds/common.txt
+- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
Required properties of the flash LED child node:
- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
- flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
+- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
Example:
@@ -29,9 +30,9 @@ Example:
flash {
flash-timeout-us = <500000>;
flash-max-microamp = <320000>;
- max-microamp = <50000>;
+ led-max-microamp = <50000>;
};
indicator {
- max-microamp = <17500>;
+ led-max-microamp = <17500>;
};
};
diff --git a/Documentation/devicetree/bindings/memory-controllers/ath79-ddr-controller.txt b/Documentation/devicetree/bindings/memory-controllers/ath79-ddr-controller.txt
index efe35a065714..c81af75bcd88 100644
--- a/Documentation/devicetree/bindings/memory-controllers/ath79-ddr-controller.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/ath79-ddr-controller.txt
@@ -1,6 +1,6 @@
Binding for Qualcomm Atheros AR7xxx/AR9xxx DDR controller
-The DDR controller of the ARxxx and AR9xxx families provides an interface
+The DDR controller of the AR7xxx and AR9xxx families provides an interface
to flush the FIFO between various devices and the DDR. This is mainly used
by the IRQ controller to flush the FIFO before running the interrupt handler
of such devices.
@@ -11,9 +11,9 @@ Required properties:
"qca,[ar7100|ar7240]-ddr-controller" as fallback.
On SoC with PCI support "qca,ar7100-ddr-controller" should be used as
fallback, otherwise "qca,ar7240-ddr-controller" should be used.
-- reg: Base address and size of the controllers memory area
-- #qca,ddr-wb-channel-cells: has to be 1, the index of the write buffer
- channel
+- reg: Base address and size of the controller's memory area
+- #qca,ddr-wb-channel-cells: Specifies the number of cells needed to encode
+ the write buffer channel index, should be 1.
Example:
diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt
index 18be0cbfb456..9b30011ecabe 100644
--- a/Documentation/devicetree/bindings/mfd/arizona.txt
+++ b/Documentation/devicetree/bindings/mfd/arizona.txt
@@ -1,4 +1,4 @@
-Wolfson Arizona class audio SoCs
+Cirrus Logic/Wolfson Microelectronics Arizona class audio SoCs
These devices are audio SoCs with extensive digital capabilites and a range
of analogue I/O.
@@ -6,12 +6,14 @@ of analogue I/O.
Required properties:
- compatible : One of the following chip-specific strings:
+ "cirrus,cs47l24"
"wlf,wm5102"
"wlf,wm5110"
"wlf,wm8280"
"wlf,wm8997"
"wlf,wm8998"
"wlf,wm1814"
+ "wlf,wm1831"
- reg : I2C slave address when connected using I2C, chip select number when
using SPI.
@@ -24,7 +26,7 @@ Required properties:
- #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
The first cell is the IRQ number.
The second cell is the flags, encoded as the trigger masks from
- Documentation/devicetree/bindings/interrupts.txt
+ Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- gpio-controller : Indicates this device is a GPIO controller.
- #gpio-cells : Must be 2. The first cell is the pin number and the
@@ -41,10 +43,21 @@ Required properties:
- SPKVDD-supply : Speaker driver power supply (wm8997)
+ - DCVDD-supply : Main power supply (cs47l24, wm1831)
+
+ - MICVDD-supply : Microphone power supply (cs47l24, wm1831)
+
Optional properties:
- wlf,reset : GPIO specifier for the GPIO controlling /RESET
+ - clocks: Should reference the clocks supplied on MCLK1 and MCLK2
+ - clock-names: Should contains two strings:
+ "mclk1" for the clock supplied on MCLK1, recommended to be a high
+ quality audio reference clock
+ "mclk2" for the clock supplied on MCLK2, recommended to be an always on
+ 32k clock
+
- wlf,gpio-defaults : A list of GPIO configuration register values. Defines
for the appropriate values can found in <dt-bindings/mfd/arizona.txt>. If
absent, no configuration of these registers is performed. If any entry has
@@ -59,6 +72,12 @@ Optional properties:
that have not been specified are set to 0 by default. Entries are:
<IN1, IN2, IN3, IN4> (wm5102, wm5110, wm8280, wm8997)
<IN1A, IN2A, IN1B, IN2B> (wm8998, wm1814)
+ - wlf,out-mono : A list of boolean values indicating whether each output is
+ mono or stereo. Position within the list indicates the output affected
+ (eg. First entry in the list corresponds to output 1). A non-zero value
+ indicates a mono output. If present, the number of values should be less
+ than or equal to the number of outputs, if less values are supplied the
+ additional outputs will be treated as stereo.
- wlf,dmic-ref : DMIC reference voltage source for each input, can be
selected from either MICVDD or one of the MICBIAS's, defines
@@ -69,6 +88,7 @@ Optional properties:
- DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if
they are being externally supplied. As covered in
Documentation/devicetree/bindings/regulator/regulator.txt
+ (wm5102, wm5110, wm8280, wm8997, wm8998, wm1814)
Also see child specific device properties:
Regulator - ../regulator/arizona-regulator.txt
diff --git a/Documentation/devicetree/bindings/mfd/palmas.txt b/Documentation/devicetree/bindings/mfd/palmas.txt
index eda898978d33..8ae1a32bfb7e 100644
--- a/Documentation/devicetree/bindings/mfd/palmas.txt
+++ b/Documentation/devicetree/bindings/mfd/palmas.txt
@@ -24,7 +24,7 @@ and also the generic series names
- #interrupt-cells : should be set to 2 for IRQ number and flags
The first cell is the IRQ number.
The second cell is the flags, encoded as the trigger masks from
- Documentation/devicetree/bindings/interrupts.txt
+ Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- interrupt-parent : The parent interrupt controller.
Optional properties:
diff --git a/Documentation/devicetree/bindings/mfd/s2mpa01.txt b/Documentation/devicetree/bindings/mfd/s2mpa01.txt
deleted file mode 100644
index c13d3d8c3947..000000000000
--- a/Documentation/devicetree/bindings/mfd/s2mpa01.txt
+++ /dev/null
@@ -1,90 +0,0 @@
-
-* Samsung S2MPA01 Voltage and Current Regulator
-
-The Samsung S2MPA01 is a multi-function device which includes high
-efficiency buck converters including Dual-Phase buck converter, various LDOs,
-and an RTC. It is interfaced to the host controller using an I2C interface.
-Each sub-block is addressed by the host system using different I2C slave
-addresses.
-
-Required properties:
-- compatible: Should be "samsung,s2mpa01-pmic".
-- reg: Specifies the I2C slave address of the PMIC block. It should be 0x66.
-
-Optional properties:
-- interrupt-parent: Specifies the phandle of the interrupt controller to which
- the interrupts from s2mpa01 are delivered to.
-- interrupts: An interrupt specifier for the sole interrupt generated by the
- device.
-
-Optional nodes:
-- regulators: The regulators of s2mpa01 that have to be instantiated should be
- included in a sub-node named 'regulators'. Regulator nodes and constraints
- included in this sub-node use the standard regulator bindings which are
- documented elsewhere.
-
-Properties for BUCK regulator nodes:
-- regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500
- (default), 25000, or 50000. May be 0 for disabling the ramp delay on
- BUCK{1,2,3,4}.
-
- In the absence of the regulator-ramp-delay property, the default ramp
- delay will be used.
-
- NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set
- for a particular group of BUCKs. So provide same regulator-ramp-delay=<value>.
-
- The following BUCKs share ramp settings:
- * 1 and 6
- * 2 and 4
- * 8, 9, and 10
-
-The following are the names of the regulators that the s2mpa01 PMIC block
-supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
-as per the datasheet of s2mpa01.
-
- - LDOn
- - valid values for n are 1 to 26
- - Example: LDO1, LD02, LDO26
- - BUCKn
- - valid values for n are 1 to 10.
- - Example: BUCK1, BUCK2, BUCK9
-
-Example:
-
- s2mpa01_pmic@66 {
- compatible = "samsung,s2mpa01-pmic";
- reg = <0x66>;
-
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ALIVE";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "VDDQ_MMC2";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- regulator-ramp-delay = <50000>;
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
deleted file mode 100644
index 09b94c97faac..000000000000
--- a/Documentation/devicetree/bindings/mfd/s2mps11.txt
+++ /dev/null
@@ -1,153 +0,0 @@
-
-* Samsung S2MPS11/13/14/15 and S2MPU02 Voltage and Current Regulator
-
-The Samsung S2MPS11 is a multi-function device which includes voltage and
-current regulators, RTC, charger controller and other sub-blocks. It is
-interfaced to the host controller using an I2C interface. Each sub-block is
-addressed by the host system using different I2C slave addresses.
-
-Required properties:
-- compatible: Should be one of the following
- - "samsung,s2mps11-pmic"
- - "samsung,s2mps13-pmic"
- - "samsung,s2mps14-pmic"
- - "samsung,s2mps15-pmic"
- - "samsung,s2mpu02-pmic".
-- reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
-
-Optional properties:
-- interrupt-parent: Specifies the phandle of the interrupt controller to which
- the interrupts from s2mps11 are delivered to.
-- interrupts: Interrupt specifiers for interrupt sources.
-- samsung,s2mps11-wrstbi-ground: Indicates that WRSTBI pin of PMIC is pulled
- down. When the system is suspended it will always go down thus triggerring
- unwanted buck warm reset (setting buck voltages to default values).
-- samsung,s2mps11-acokb-ground: Indicates that ACOKB pin of S2MPS11 PMIC is
- connected to the ground so the PMIC must manually set PWRHOLD bit in CTRL1
- register to turn off the power. Usually the ACOKB is pulled up to VBATT so
- when PWRHOLD pin goes low, the rising ACOKB will trigger power off.
-
-Optional nodes:
-- clocks: s2mps11, s2mps13, s2mps15 and s5m8767 provide three(AP/CP/BT) buffered 32.768
- KHz outputs, so to register these as clocks with common clock framework
- instantiate a sub-node named "clocks". It uses the common clock binding
- documented in :
- [Documentation/devicetree/bindings/clock/clock-bindings.txt]
- The s2mps14 provides two (AP/BT) buffered 32.768 KHz outputs.
- - #clock-cells: should be 1.
-
- - The following is the list of clocks generated by the controller. Each clock
- is assigned an identifier and client nodes use this identifier to specify
- the clock which they consume.
- Clock ID Devices
- ----------------------------------------------------------
- 32KhzAP 0 S2MPS11, S2MPS13, S2MPS14, S2MPS15, S5M8767
- 32KhzCP 1 S2MPS11, S2MPS13, S2MPS15, S5M8767
- 32KhzBT 2 S2MPS11, S2MPS13, S2MPS14, S2MPS15, S5M8767
-
- - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps13-clk",
- "samsung,s2mps14-clk", "samsung,s5m8767-clk"
- The s2msp15 uses the same compatible as s2mps13, as both provides similar clocks.
-
-- regulators: The regulators of s2mps11 that have to be instantiated should be
-included in a sub-node named 'regulators'. Regulator nodes included in this
-sub-node should be of the format as listed below.
-
- regulator_name {
- [standard regulator constraints....];
- };
-
- regulator-ramp-delay for BUCKs = [6250/12500/25000(default)/50000] uV/us
-
- BUCK[2/3/4/6] supports disabling ramp delay on hardware, so explicitly
- regulator-ramp-delay = <0> can be used for them to disable ramp delay.
- In the absence of the regulator-ramp-delay property, the default ramp
- delay will be used.
-
-NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set
-for a particular group of BUCKs. So provide same regulator-ramp-delay<value>.
-Grouping of BUCKs sharing ramp rate setting is as follow : BUCK[1, 6],
-BUCK[3, 4], and BUCK[7, 8, 10]
-
-On S2MPS14 the LDO10, LDO11 and LDO12 can be configured to external control
-over GPIO. To turn this feature on this property must be added to the regulator
-sub-node:
- - samsung,ext-control-gpios: GPIO specifier for one GPIO
- controlling this regulator (enable/disable);
-Example:
- LDO12 {
- regulator-name = "V_EMMC_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- samsung,ext-control-gpios = <&gpk0 2 0>;
- };
-
-
-The regulator constraints inside the regulator nodes use the standard regulator
-bindings which are documented elsewhere.
-
-The following are the names of the regulators that the s2mps11 pmic block
-supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
-as per the datasheet of s2mps11.
-
- - LDOn
- - valid values for n are:
- - S2MPS11: 1 to 38
- - S2MPS13: 1 to 40
- - S2MPS14: 1 to 25
- - S2MPS15: 1 to 27
- - S2MPU02: 1 to 28
- - Example: LDO1, LDO2, LDO28
- - BUCKn
- - valid values for n are:
- - S2MPS11: 1 to 10
- - S2MPS13: 1 to 10
- - S2MPS14: 1 to 5
- - S2MPS15: 1 to 10
- - S2MPU02: 1 to 7
- - Example: BUCK1, BUCK2, BUCK9
-
-Example:
-
- s2mps11_pmic@66 {
- compatible = "samsung,s2mps11-pmic";
- reg = <0x66>;
-
- s2m_osc: clocks {
- compatible = "samsung,s2mps11-clk";
- #clock-cells = <1>;
- clock-output-names = "xx", "yy", "zz";
- };
-
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ABB_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "VDD_ALIVE_1.1V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- regulator-ramp-delay = <50000>;
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/mfd/samsung,sec-core.txt b/Documentation/devicetree/bindings/mfd/samsung,sec-core.txt
new file mode 100644
index 000000000000..cdd079bfc287
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/samsung,sec-core.txt
@@ -0,0 +1,88 @@
+Binding for Samsung S2M and S5M family multi-function device
+============================================================
+
+This is a part of device tree bindings for S2M and S5M family multi-function
+devices.
+
+The Samsung S2MPA01, S2MPS11/13/14/15, S2MPU02 and S5M8767 is a family
+of multi-function devices which include voltage and current regulators, RTC,
+charger controller, clock outputs and other sub-blocks. It is interfaced
+to the host controller using an I2C interface. Each sub-block is usually
+addressed by the host system using different I2C slave addresses.
+
+
+This document describes bindings for main device node. Optional sub-blocks
+must be a sub-nodes to it. Bindings for them can be found in:
+ - bindings/regulator/samsung,s2mpa01.txt
+ - bindings/regulator/samsung,s2mps11.txt
+ - bindings/regulator/samsung,s5m8767.txt
+ - bindings/clock/samsung,s2mps11.txt
+
+
+Required properties:
+ - compatible: Should be one of the following
+ - "samsung,s2mpa01-pmic",
+ - "samsung,s2mps11-pmic",
+ - "samsung,s2mps13-pmic",
+ - "samsung,s2mps14-pmic",
+ - "samsung,s2mps15-pmic",
+ - "samsung,s2mpu02-pmic",
+ - "samsung,s5m8767-pmic".
+ - reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
+
+Optional properties:
+ - interrupt-parent: Specifies the phandle of the interrupt controller to which
+ the interrupts from s2mps11 are delivered to.
+ - interrupts: Interrupt specifiers for interrupt sources.
+ - samsung,s2mps11-wrstbi-ground: Indicates that WRSTBI pin of PMIC is pulled
+ down. When the system is suspended it will always go down thus triggerring
+ unwanted buck warm reset (setting buck voltages to default values).
+ - samsung,s2mps11-acokb-ground: Indicates that ACOKB pin of S2MPS11 PMIC is
+ connected to the ground so the PMIC must manually set PWRHOLD bit in CTRL1
+ register to turn off the power. Usually the ACOKB is pulled up to VBATT so
+ when PWRHOLD pin goes low, the rising ACOKB will trigger power off.
+
+Example:
+
+ s2mps11_pmic@66 {
+ compatible = "samsung,s2mps11-pmic";
+ reg = <0x66>;
+
+ s2m_osc: clocks {
+ compatible = "samsung,s2mps11-clk";
+ #clock-cells = <1>;
+ clock-output-names = "xx", "yy", "zz";
+ };
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ABB_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_ALIVE_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <50000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt
index fe8150bb3248..408f768686f1 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.txt
+++ b/Documentation/devicetree/bindings/mfd/syscon.txt
@@ -13,6 +13,10 @@ Required properties:
- compatible: Should contain "syscon".
- reg: the register region can be accessed from syscon
+Optional property:
+- reg-io-width: the size (in bytes) of the IO accesses that should be
+ performed on the device.
+
Examples:
gpr: iomuxc-gpr@020e0000 {
compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
index 4ff7128ee3b2..c2546ced9c02 100644
--- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
+++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
@@ -45,6 +45,8 @@ Required properties:
- #size-cells : <0>
Optional properties:
+- clock : reference to the clock for the NAND controller
+- clock-names : "nand" (required for the above clock)
- brcm,nand-has-wp : Some versions of this IP include a write-protect
(WP) control bit. It is always available on >=
v7.0. Use this property to describe the rare
@@ -72,6 +74,12 @@ we define additional 'compatible' properties and associated register resources w
and enable registers
- reg-names: (required) "nand-int-base"
+ * "brcm,nand-bcm6368"
+ - compatible: should contain "brcm,nand-bcm<soc>", "brcm,nand-bcm6368"
+ - reg: (required) the 'NAND_INTR_BASE' register range, with combined status
+ and enable registers, and boot address registers
+ - reg-names: (required) "nand-int-base"
+
* "brcm,nand-iproc"
- reg: (required) the "IDM" register range, for interrupt enable and APB
bus access endianness configuration, and the "EXT" register range,
@@ -148,3 +156,27 @@ nand@f0442800 {
};
};
};
+
+nand@10000200 {
+ compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368",
+ "brcm,brcmnand-v4.0", "brcm,brcmnand";
+ reg = <0x10000200 0x180>,
+ <0x10000600 0x200>,
+ <0x100000b0 0x10>;
+ reg-names = "nand", "nand-cache", "nand-int-base";
+ interrupt-parent = <&periph_intc>;
+ interrupts = <50>;
+ clocks = <&periph_clk 20>;
+ clock-names = "nand";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand0: nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+ nand-ecc-strength = <1>;
+ nand-ecc-step-size = <512>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
index 862aa2f8837a..00c587b3d3ae 100644
--- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
+++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt
@@ -2,7 +2,8 @@
Required properties:
- compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi",
- "fsl,imx7d-qspi", "fsl,imx6ul-qspi"
+ "fsl,imx7d-qspi", "fsl,imx6ul-qspi",
+ "fsl,ls1021-qspi"
- reg : the first contains the register location and length,
the second contains the memory mapping address and length
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
diff --git a/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt
new file mode 100644
index 000000000000..29ea5853ca91
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt
@@ -0,0 +1,86 @@
+* Ingenic JZ4780 NAND/BCH
+
+This file documents the device tree bindings for NAND flash devices on the
+JZ4780. NAND devices are connected to the NEMC controller (described in
+memory-controllers/ingenic,jz4780-nemc.txt), and thus NAND device nodes must
+be children of the NEMC node.
+
+Required NAND controller device properties:
+- compatible: Should be set to "ingenic,jz4780-nand".
+- reg: For each bank with a NAND chip attached, should specify a bank number,
+ an offset of 0 and a size of 0x1000000 (i.e. the whole NEMC bank).
+
+Optional NAND controller device properties:
+- ingenic,bch-controller: To make use of the hardware BCH controller, this
+ property must contain a phandle for the BCH controller node. The required
+ properties for this node are described below. If this is not specified,
+ software BCH will be used instead.
+
+Optional children nodes:
+- Individual NAND chips are children of the NAND controller node.
+
+Required children node properties:
+- reg: An integer ranging from 1 to 6 representing the CS line to use.
+
+Optional children node properties:
+- nand-ecc-step-size: ECC block size in bytes.
+- nand-ecc-strength: ECC strength (max number of correctable bits).
+- nand-ecc-mode: String, operation mode of the NAND ecc mode. "hw" by default
+- nand-on-flash-bbt: boolean to enable on flash bbt option, if not present false
+- rb-gpios: GPIO specifier for the busy pin.
+- wp-gpios: GPIO specifier for the write protect pin.
+
+Optional child node of NAND chip nodes:
+- partitions: see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+nemc: nemc@13410000 {
+ ...
+
+ nandc: nand-controller@1 {
+ compatible = "ingenic,jz4780-nand";
+ reg = <1 0 0x1000000>; /* Bank 1 */
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ingenic,bch-controller = <&bch>;
+
+ nand@1 {
+ reg = <1>;
+
+ nand-ecc-step-size = <1024>;
+ nand-ecc-strength = <24>;
+ nand-ecc-mode = "hw";
+ nand-on-flash-bbt;
+
+ rb-gpios = <&gpa 20 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpf 22 GPIO_ACTIVE_LOW>;
+
+ partitions {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ...
+ }
+ };
+ };
+};
+
+The BCH controller is a separate SoC component used for error correction on
+NAND devices. The following is a description of the device properties for a
+BCH controller.
+
+Required BCH properties:
+- compatible: Should be set to "ingenic,jz4780-bch".
+- reg: Should specify the BCH controller registers location and length.
+- clocks: Clock for the BCH controller.
+
+Example:
+
+bch: bch@134d0000 {
+ compatible = "ingenic,jz4780-bch";
+ reg = <0x134d0000 0x10000>;
+
+ clocks = <&cgu JZ4780_CLK_BCH>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
index 2bee68103b01..2c91c03e7eb0 100644
--- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
+++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
@@ -1,15 +1,61 @@
-* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
+* SPI NOR flash: ST M25Pxx (and similar) serial flash chips
Required properties:
- #address-cells, #size-cells : Must be present if the device has sub-nodes
representing partitions.
- compatible : May include a device-specific string consisting of the
- manufacturer and name of the chip. Bear in mind the DT binding
- is not Linux-only, but in case of Linux, see the "m25p_ids"
- table in drivers/mtd/devices/m25p80.c for the list of supported
- chips.
+ manufacturer and name of the chip. A list of supported chip
+ names follows.
Must also include "jedec,spi-nor" for any SPI NOR flash that can
be identified by the JEDEC READ ID opcode (0x9F).
+
+ Supported chip names:
+ at25df321a
+ at25df641
+ at26df081a
+ mr25h256
+ mx25l4005a
+ mx25l1606e
+ mx25l6405d
+ mx25l12805d
+ mx25l25635e
+ n25q064
+ n25q128a11
+ n25q128a13
+ n25q512a
+ s25fl256s1
+ s25fl512s
+ s25sl12801
+ s25fl008k
+ s25fl064k
+ sst25vf040b
+ m25p40
+ m25p80
+ m25p16
+ m25p32
+ m25p64
+ m25p128
+ w25x80
+ w25x32
+ w25q32
+ w25q32dw
+ w25q80bl
+ w25q128
+ w25q256
+
+ The following chip names have been used historically to
+ designate quirky versions of flash chips that do not support the
+ JEDEC READ ID opcode (0x9F):
+ m25p05-nonjedec
+ m25p10-nonjedec
+ m25p20-nonjedec
+ m25p40-nonjedec
+ m25p80-nonjedec
+ m25p16-nonjedec
+ m25p32-nonjedec
+ m25p64-nonjedec
+ m25p128-nonjedec
+
- reg : Chip-Select number
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
diff --git a/Documentation/devicetree/bindings/mtd/mtk-quadspi.txt b/Documentation/devicetree/bindings/mtd/mtk-quadspi.txt
new file mode 100644
index 000000000000..fb314f09861b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/mtk-quadspi.txt
@@ -0,0 +1,41 @@
+* Serial NOR flash controller for MTK MT81xx (and similar)
+
+Required properties:
+- compatible: should be "mediatek,mt8173-nor";
+- reg: physical base address and length of the controller's register
+- clocks: the phandle of the clocks needed by the nor controller
+- clock-names: the names of the clocks
+ the clocks should be named "spi" and "sf". "spi" is used for spi bus,
+ and "sf" is used for controller, these are the clocks witch
+ hardware needs to enabling nor flash and nor flash controller.
+ See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
+- #address-cells: should be <1>
+- #size-cells: should be <0>
+
+The SPI flash must be a child of the nor_flash node and must have a
+compatible property. Also see jedec,spi-nor.txt.
+
+Required properties:
+- compatible: May include a device-specific string consisting of the manufacturer
+ and name of the chip. Must also include "jedec,spi-nor" for any
+ SPI NOR flash that can be identified by the JEDEC READ ID opcode (0x9F).
+- reg : Chip-Select number
+
+Example:
+
+nor_flash: spi@1100d000 {
+ compatible = "mediatek,mt8173-nor";
+ reg = <0 0x1100d000 0 0xe0>;
+ clocks = <&pericfg CLK_PERI_SPI>,
+ <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
+ clock-names = "spi", "sf";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ };
+};
+
diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
index 1c63e40659fc..81a224da63be 100644
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ b/Documentation/devicetree/bindings/mtd/partition.txt
@@ -32,6 +32,8 @@ Optional properties:
partition should only be mounted read-only. This is usually used for flash
partitions containing early-boot firmware images or data which should not be
clobbered.
+- lock : Do not unlock the partition at initialization time (not supported on
+ all devices)
Examples:
diff --git a/Documentation/devicetree/bindings/net/cdns-emac.txt b/Documentation/devicetree/bindings/net/cdns-emac.txt
deleted file mode 100644
index 4451ee973223..000000000000
--- a/Documentation/devicetree/bindings/net/cdns-emac.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-* Cadence EMAC Ethernet controller
-
-Required properties:
-- compatible: Should be "cdns,[<chip>-]{emac}"
- Use "cdns,at91rm9200-emac" Atmel at91rm9200 SoC.
- Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC.
- Or the generic form: "cdns,emac".
-- reg: Address and length of the register set for the device
-- interrupts: Should contain macb interrupt
-- phy-mode: see ethernet.txt file in the same directory.
-
-Examples:
-
- macb0: ethernet@fffc4000 {
- compatible = "cdns,at91rm9200-emac";
- reg = <0xfffc4000 0x4000>;
- interrupts = <21>;
- phy-mode = "rmii";
- local-mac-address = [3a 0e 03 04 05 06];
- };
diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt
index 5c397ca14cfe..d2e243b1ec0e 100644
--- a/Documentation/devicetree/bindings/net/macb.txt
+++ b/Documentation/devicetree/bindings/net/macb.txt
@@ -2,6 +2,7 @@
Required properties:
- compatible: Should be "cdns,[<chip>-]{macb|gem}"
+ Use "cdns,at91rm9200-emac" Atmel at91rm9200 SoC.
Use "cdns,at91sam9260-macb" for Atmel at91sam9 SoCs or the 10/100Mbit IP
available on sama5d3 SoCs.
Use "cdns,np4-macb" for NP4 SoC devices.
@@ -11,7 +12,9 @@ Required properties:
Use "atmel,sama5d2-gem" for the GEM IP (10/100) available on Atmel sama5d2 SoCs.
Use "atmel,sama5d3-gem" for the Gigabit IP available on Atmel sama5d3 SoCs.
Use "atmel,sama5d4-gem" for the GEM IP (10/100) available on Atmel sama5d4 SoCs.
+ Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC.
Use "cdns,zynqmp-gem" for Zynq Ultrascale+ MPSoC.
+ Or the generic form: "cdns,emac".
- reg: Address and length of the register set for the device
- interrupts: Should contain macb interrupt
- phy-mode: See ethernet.txt file in the same directory.
diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
index 7f81ef90146a..d87ab7c127b8 100644
--- a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
+++ b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
@@ -2,6 +2,7 @@
Required properties:
- compatible: should be one or more of
+ "brcm,bcm7425-sata-phy"
"brcm,bcm7445-sata-phy"
"brcm,phy-sata3"
- address-cells: should be 1
diff --git a/Documentation/devicetree/bindings/phy/phy-hi6220-usb.txt b/Documentation/devicetree/bindings/phy/phy-hi6220-usb.txt
new file mode 100644
index 000000000000..f17a56e2152f
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-hi6220-usb.txt
@@ -0,0 +1,16 @@
+Hisilicon hi6220 usb PHY
+-----------------------
+
+Required properties:
+- compatible: should be "hisilicon,hi6220-usb-phy"
+- #phy-cells: must be 0
+- hisilicon,peripheral-syscon: phandle of syscon used to control phy.
+Refer to phy/phy-bindings.txt for the generic PHY binding properties
+
+Example:
+ usb_phy: usbphy {
+ compatible = "hisilicon,hi6220-usb-phy";
+ #phy-cells = <0>;
+ phy-supply = <&fixed_5v_hub>;
+ hisilicon,peripheral-syscon = <&sys_ctrl>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
new file mode 100644
index 000000000000..2390e4e9c84c
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
@@ -0,0 +1,39 @@
+* Renesas R-Car generation 3 USB 2.0 PHY
+
+This file provides information on what the device node for the R-Car generation
+3 USB 2.0 PHY contains.
+
+Required properties:
+- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
+ SoC.
+- reg: offset and length of the partial USB 2.0 Host register block.
+- reg-names: must be "usb2_host".
+- clocks: clock phandle and specifier pair(s).
+- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
+
+Optional properties:
+To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
+combined, the device tree node should set HSUSB properties to reg and reg-names
+properties. This is because HSUSB has registers to select USB 2.0 host or
+peripheral at that channel:
+- reg: offset and length of the partial HSUSB register block.
+- reg-names: must be "hsusb".
+- interrupts: interrupt specifier for the PHY.
+
+Example (R-Car H3):
+
+ usb-phy@ee080200 {
+ compatible = "renesas,usb2-phy-r8a7795";
+ reg = <0 0xee080200 0 0x700>, <0 0xe6590100 0 0x100>;
+ reg-names = "usb2_host", "hsusb";
+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7795_CLK_EHCI0>,
+ <&mstp7_clks R8A7795_CLK_HSUSB>;
+ };
+
+ usb-phy@ee0a0200 {
+ compatible = "renesas,usb2-phy-r8a7795";
+ reg = <0 0xee0a0200 0 0x700>;
+ reg-names = "usb2_host";
+ clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
index 826454ac43bb..68498d560354 100644
--- a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
@@ -1,7 +1,10 @@
ROCKCHIP USB2 PHY
Required properties:
- - compatible: rockchip,rk3288-usb-phy
+ - compatible: matching the soc type, one of
+ "rockchip,rk3066a-usb-phy"
+ "rockchip,rk3188-usb-phy"
+ "rockchip,rk3288-usb-phy"
- rockchip,grf : phandle to the syscon managing the "general
register files"
- #address-cells: should be 1
@@ -21,6 +24,7 @@ required properties:
Optional Properties:
- clocks : phandle + clock specifier for the phy clocks
- clock-names: string, clock name, must be "phyclk"
+- #clock-cells: for users of the phy-pll, should be 0
Example:
diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
index 0cebf7454517..95736d77fbb7 100644
--- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -9,6 +9,7 @@ Required properties:
* allwinner,sun7i-a20-usb-phy
* allwinner,sun8i-a23-usb-phy
* allwinner,sun8i-a33-usb-phy
+ * allwinner,sun8i-h3-usb-phy
- reg : a list of offset + length pairs
- reg-names :
* "phy_ctrl"
diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
index 9cf9446eaf2e..a3b394587874 100644
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -31,6 +31,8 @@ OMAP USB2 PHY
Required properties:
- compatible: Should be "ti,omap-usb2"
+ Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY
+ in DRA7x
- reg : Address and length of the register set for the device.
- #phy-cells: determine the number of cells that should be given in the
phandle while referencing this phy.
@@ -40,10 +42,14 @@ Required properties:
* "wkupclk" - wakeup clock.
* "refclk" - reference clock (optional).
-Optional properties:
+Deprecated properties:
- ctrl-module : phandle of the control module used by PHY driver to power on
the PHY.
+Recommended properies:
+- syscon-phy-power : phandle/offset pair. Phandle to the system control
+ module and the register offset to power on/off the PHY.
+
This is usually a subnode of ocp2scp to which it is connected.
usb2phy@4a0ad080 {
@@ -77,14 +83,22 @@ Required properties:
* "div-clk" - apll clock
Optional properties:
- - ctrl-module : phandle of the control module used by PHY driver to power on
- the PHY.
- id: If there are multiple instance of the same type, in order to
differentiate between each instance "id" can be used (e.g., multi-lane PCIe
PHY). If "id" is not provided, it is set to default value of '1'.
- syscon-pllreset: Handle to system control region that contains the
CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
+ - syscon-pcs : phandle/offset pair. Phandle to the system control module and the
+ register offset to write the PCS delay value.
+
+Deprecated properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
+
+Recommended properies:
+ - syscon-phy-power : phandle/offset pair. Phandle to the system control
+ module and the register offset to power on/off the PHY.
This is usually a subnode of ocp2scp to which it is connected.
diff --git a/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt b/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt
new file mode 100644
index 000000000000..8f14df9d1205
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/lm363x-regulator.txt
@@ -0,0 +1,34 @@
+TI LMU LM363x regulator device tree bindings
+
+LM363x regulator driver supports LM3631 and LM3632.
+LM3631 has five regulators and LM3632 supports three regulators.
+
+Required property:
+ - compatible: "ti,lm363x-regulator"
+
+Optional properties:
+ LM3632 has external enable pins for two LDOs.
+ - ti,lcm-en1-gpio: A GPIO specifier for Vpos control pin.
+ - ti,lcm-en2-gpio: A GPIO specifier for Vneg control pin.
+
+Child nodes:
+ LM3631
+ - vboost
+ - vcont
+ - voref
+ - vpos
+ - vneg
+
+ LM3632
+ - vboost
+ - vpos
+ - vneg
+
+ Optional properties of a child node:
+ Each sub-node should contain the constraints and initialization.
+ Please refer to [1].
+
+Examples: Please refer to ti-lmu dt-bindings [2].
+
+[1] ../regulator/regulator.txt
+[2] ../mfd/ti-lmu.txt
diff --git a/Documentation/devicetree/bindings/regulator/pv88060.txt b/Documentation/devicetree/bindings/regulator/pv88060.txt
new file mode 100644
index 000000000000..10a6dadc008e
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/pv88060.txt
@@ -0,0 +1,124 @@
+* Powerventure Semiconductor PV88060 Voltage Regulator
+
+Required properties:
+- compatible: "pvs,pv88060".
+- reg: I2C slave address, usually 0x49.
+- interrupts: the interrupt outputs of the controller
+- regulators: A node that houses a sub-node for each regulator within the
+ device. Each sub-node is identified using the node's name, with valid
+ values listed below. The content of each sub-node is defined by the
+ standard binding for regulators; see regulator.txt.
+ BUCK1, LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, SW1, SW2, SW3, SW4,
+ SW5, and SW6.
+
+Optional properties:
+- Any optional property defined in regulator.txt
+
+Example
+
+ pmic: pv88060@49 {
+ compatible = "pvs,pv88060";
+ reg = <0x49>;
+ interrupt-parent = <&gpio>;
+ interrupts = <24 24>;
+
+ regulators {
+ BUCK1 {
+ regulator-name = "buck1";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <4387500>;
+ regulator-min-microamp = <1496000>;
+ regulator-max-microamp = <4189000>;
+ regulator-boot-on;
+ };
+
+ LDO1 {
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ LDO2 {
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ LDO3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ LDO4 {
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ LDO5 {
+ regulator-name = "ldo5";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ LDO6 {
+ regulator-name = "ldo6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ LDO7 {
+ regulator-name = "ldo7";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3350000>;
+ regulator-boot-on;
+ };
+
+ SW1 {
+ regulator-name = "sw1";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ SW2 {
+ regulator-name = "sw2";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+
+ SW3 {
+ regulator-name = "sw3";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+
+ SW4 {
+ regulator-name = "sw4";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+
+ SW5 {
+ regulator-name = "sw5";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+
+ SW6 {
+ regulator-name = "sw6";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+ };
+ }; \ No newline at end of file
diff --git a/Documentation/devicetree/bindings/regulator/pv88090.txt b/Documentation/devicetree/bindings/regulator/pv88090.txt
new file mode 100644
index 000000000000..e52b2a95cdde
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/pv88090.txt
@@ -0,0 +1,65 @@
+* Powerventure Semiconductor PV88090 Voltage Regulator
+
+Required properties:
+- compatible: "pvs,pv88090".
+- reg: I2C slave address, usually 0x48.
+- interrupts: the interrupt outputs of the controller
+- regulators: A node that houses a sub-node for each regulator within the
+ device. Each sub-node is identified using the node's name, with valid
+ values listed below. The content of each sub-node is defined by the
+ standard binding for regulators; see regulator.txt.
+ BUCK1, BUCK2, BUCK3, LDO1, and LDO2.
+
+Optional properties:
+- Any optional property defined in regulator.txt
+
+Example
+
+ pmic: pv88090@48 {
+ compatible = "pvs,pv88090";
+ reg = <0x48>;
+ interrupt-parent = <&gpio>;
+ interrupts = <24 24>;
+
+ regulators {
+ BUCK1 {
+ regulator-name = "buck1";
+ regulator-min-microvolt = < 600000>;
+ regulator-max-microvolt = <1393750>;
+ regulator-min-microamp = < 220000>;
+ regulator-max-microamp = <7040000>;
+ regulator-boot-on;
+ };
+
+ BUCK2 {
+ regulator-name = "buck2";
+ regulator-min-microvolt = < 600000>;
+ regulator-max-microvolt = <1393750>;
+ regulator-min-microamp = <1496000>;
+ regulator-max-microamp = <4189000>;
+ };
+
+ BUCK3 {
+ regulator-name = "buck3";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1393750>;
+ regulator-min-microamp = <1496000>;
+ regulator-max-microamp = <4189000>;
+ regulator-boot-on;
+ };
+
+ LDO1 {
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <4350000>;
+ regulator-boot-on;
+ };
+
+ LDO2 {
+ regulator-name = "ldo2";
+ regulator-min-microvolt = < 650000>;
+ regulator-max-microvolt = <2225000>;
+ regulator-boot-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
index e27f5c4c54fd..1f8d6f84b657 100644
--- a/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt
+++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
@@ -1,27 +1,17 @@
-Qualcomm Resource Power Manager (RPM) over SMD
+QCOM SMD RPM REGULATOR
-This driver is used to interface with the Resource Power Manager (RPM) found in
-various Qualcomm platforms. The RPM allows each component in the system to vote
-for state of the system resources, such as clocks, regulators and bus
-frequencies.
+The Qualcomm RPM over SMD regulator is modelled as a subdevice of the RPM.
+Because SMD is used as the communication transport mechanism, the RPM resides as
+a subnode of the SMD. As such, the SMD-RPM regulator requires that the SMD and
+RPM nodes be present.
-- compatible:
- Usage: required
- Value type: <string>
- Definition: must be one of:
- "qcom,rpm-msm8974"
+Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt for
+information pertaining to the SMD node.
-- qcom,smd-channels:
- Usage: required
- Value type: <stringlist>
- Definition: Shared Memory channel used for communication with the RPM
+Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt for
+information regarding the RPM node.
-= SUBDEVICES
-
-The RPM exposes resources to its subnodes. The below bindings specify the set
-of valid subnodes that can operate on these resources.
-
-== Regulators
+== Regulator
Regulator nodes are identified by their compatible:
@@ -30,7 +20,9 @@ Regulator nodes are identified by their compatible:
Value type: <string>
Definition: must be one of:
"qcom,rpm-pm8841-regulators"
+ "qcom,rpm-pm8916-regulators"
"qcom,rpm-pm8941-regulators"
+ "qcom,rpm-pma8084-regulators"
- vdd_s1-supply:
- vdd_s2-supply:
@@ -48,6 +40,19 @@ Regulator nodes are identified by their compatible:
- vdd_s1-supply:
- vdd_s2-supply:
- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_l1_l2_l3-supply:
+- vdd_l4_l5_l6-supply:
+- vdd_l7-supply:
+- vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18-supply:
+ Usage: optional (pm8916 only)
+ Value type: <phandle>
+ Definition: reference to regulator supplying the input pin, as
+ described in the data sheet
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
- vdd_l1_l3-supply:
- vdd_l2_lvs1_2_3-supply:
- vdd_l4_l11-supply:
@@ -63,6 +68,35 @@ Regulator nodes are identified by their compatible:
Definition: reference to regulator supplying the input pin, as
described in the data sheet
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_s5-supply:
+- vdd_s6-supply:
+- vdd_s7-supply:
+- vdd_s8-supply:
+- vdd_s9-supply:
+- vdd_s10-supply:
+- vdd_s11-supply:
+- vdd_s12-supply:
+- vdd_l1_l11-supply:
+- vdd_l2_l3_l4_l27-supply:
+- vdd_l5_l7-supply:
+- vdd_l6_l12_l14_l15_l26-supply:
+- vdd_l8-supply:
+- vdd_l9_l10_l13_l20_l23_l24-supply:
+- vdd_l16_l25-supply:
+- vdd_l17-supply:
+- vdd_l18-supply:
+- vdd_l19-supply:
+- vdd_l21-supply:
+- vdd_l22-supply:
+ Usage: optional (pma8084 only)
+ Value type: <phandle>
+ Definition: reference to regulator supplying the input pin, as
+ described in the data sheet
+
The regulator node houses sub-nodes for each regulator within the device. Each
sub-node is identified using the node's name, with valid values listed for each
of the pmics below.
@@ -70,11 +104,20 @@ of the pmics below.
pm8841:
s1, s2, s3, s4, s5, s6, s7, s8
+pm8916:
+ s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
+ l14, l15, l16, l17, l18
+
pm8941:
s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
lvs3, 5vs1, 5vs2
+pma8084:
+ s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
+ l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
+ l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1
+
The content of each sub-node is defined by the standard binding for regulators -
see regulator.txt.
@@ -114,4 +157,3 @@ see regulator.txt.
};
};
};
-
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
deleted file mode 100644
index 20191315e444..000000000000
--- a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
+++ /dev/null
@@ -1,163 +0,0 @@
-* Samsung S5M8767 Voltage and Current Regulator
-
-The Samsung S5M8767 is a multi-function device which includes voltage and
-current regulators, rtc, charger controller and other sub-blocks. It is
-interfaced to the host controller using a i2c interface. Each sub-block is
-addressed by the host system using different i2c slave address. This document
-describes the bindings for 'pmic' sub-block of s5m8767.
-
-Required properties:
-- compatible: Should be "samsung,s5m8767-pmic".
-- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
-
-- s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
- units for buck2 when changing voltage using gpio dvs. Refer to [1] below
- for additional information.
-
-- s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
- units for buck3 when changing voltage using gpio dvs. Refer to [1] below
- for additional information.
-
-- s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
- units for buck4 when changing voltage using gpio dvs. Refer to [1] below
- for additional information.
-
-- s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
- for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
-
-[1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
- property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage'
- property should specify atleast one voltage level (which would be a
- safe operating voltage).
-
- If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
- property is specified, then all the eight voltage values for the
- 's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
-
-Optional properties:
-- interrupt-parent: Specifies the phandle of the interrupt controller to which
- the interrupts from s5m8767 are delivered to.
-- interrupts: Interrupt specifiers for two interrupt sources.
- - First interrupt specifier is for 'irq1' interrupt.
- - Second interrupt specifier is for 'alert' interrupt.
-- s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
-- s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs.
-- s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs.
-
-Additional properties required if either of the optional properties are used:
-
-- s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from
- the possible 8 options selectable by the dvs gpios. The value of this
- property should be between 0 and 7. If not specified or if out of range, the
- default value of this property is set to 0.
-
-- s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used
- for dvs. The format of the gpio specifier depends in the gpio controller.
-
-Regulators: The regulators of s5m8767 that have to be instantiated should be
-included in a sub-node named 'regulators'. Regulator nodes included in this
-sub-node should be of the format as listed below.
-
- regulator_name {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ALIVE_1.0V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
- };
-The above regulator entries are defined in regulator bindings documentation
-except these properties:
- - op_mode: describes the different operating modes of the LDO's with
- power mode change in SOC. The different possible values are,
- 0 - always off mode
- 1 - on in normal mode
- 2 - low power mode
- 3 - suspend mode
- - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one
- GPIO controlling this regulator (enable/disable); This is
- valid only for buck9.
-
-The following are the names of the regulators that the s5m8767 pmic block
-supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
-as per the datasheet of s5m8767.
-
- - LDOn
- - valid values for n are 1 to 28
- - Example: LDO1, LDO2, LDO28
- - BUCKn
- - valid values for n are 1 to 9.
- - Example: BUCK1, BUCK2, BUCK9
-
-The bindings inside the regulator nodes use the standard regulator bindings
-which are documented elsewhere.
-
-Example:
-
- s5m8767_pmic@66 {
- compatible = "samsung,s5m8767-pmic";
- reg = <0x66>;
-
- s5m8767,pmic-buck2-uses-gpio-dvs;
- s5m8767,pmic-buck3-uses-gpio-dvs;
- s5m8767,pmic-buck4-uses-gpio-dvs;
-
- s5m8767,pmic-buck-default-dvs-idx = <0>;
-
- s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 0>, /* DVS1 */
- <&gpx0 1 0>, /* DVS2 */
- <&gpx0 2 0>; /* DVS3 */
-
- s5m8767,pmic-buck-ds-gpios = <&gpx2 3 0>, /* SET1 */
- <&gpx2 4 0>, /* SET2 */
- <&gpx2 5 0>; /* SET3 */
-
- s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
- <1250000>, <1200000>,
- <1150000>, <1100000>,
- <1000000>, <950000>;
-
- s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
- <1100000>, <1100000>,
- <1000000>, <1000000>,
- <1000000>, <1000000>;
-
- s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>;
-
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ABB_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "VDD_ALIVE_1.1V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "VDD_MIF_1.2V";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- vemmc_reg: BUCK9 {
- regulator-name = "VMEM_VDD_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- op_mode = <3>; /* Standby Mode */
- s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>;
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/regulator/samsung,s2mpa01.txt b/Documentation/devicetree/bindings/regulator/samsung,s2mpa01.txt
new file mode 100644
index 000000000000..bae3c7f838cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/samsung,s2mpa01.txt
@@ -0,0 +1,79 @@
+Binding for Samsung S2MPA01 regulator block
+===========================================
+
+This is a part of device tree bindings for S2M family multi-function devices.
+More information can be found in bindings/mfd/sec-core.txt file.
+
+The S2MPA01 device provide buck and LDO regulators.
+
+To register these with regulator framework instantiate under main device node
+a sub-node named "regulators" with more sub-nodes for each regulator using the
+common regulator binding documented in:
+ - Documentation/devicetree/bindings/regulator/regulator.txt
+
+
+Names of regulators supported by S2MPA01 device:
+ - LDOn
+ - valid values for n are 1 to 26
+ - Example: LDO1, LD02, LDO26
+ - BUCKn
+ - valid values for n are 1 to 10.
+ - Example: BUCK1, BUCK2, BUCK9
+Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of device.
+
+
+Optional properties of buck regulator nodes under "regulators" sub-node:
+ - regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500
+ (default), 25000, or 50000. May be 0 for disabling the ramp delay on
+ BUCK{1,2,3,4}.
+
+ In the absence of the regulator-ramp-delay property, the default ramp
+ delay will be used.
+
+ Note: Some bucks share the ramp rate setting i.e. same ramp value
+ will be set for a particular group of bucks so provide the same
+ regulator-ramp-delay value for them.
+ Groups sharing ramp rate:
+ - buck{1,6},
+ - buck{2,4},
+ - buck{8,9,10}.
+
+Example:
+
+ s2mpa01_pmic@66 {
+ compatible = "samsung,s2mpa01-pmic";
+ reg = <0x66>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDDQ_MMC2";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <50000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/samsung,s2mps11.txt b/Documentation/devicetree/bindings/regulator/samsung,s2mps11.txt
new file mode 100644
index 000000000000..27a48bf1b185
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/samsung,s2mps11.txt
@@ -0,0 +1,102 @@
+Binding for Samsung S2M family regulator block
+==============================================
+
+This is a part of device tree bindings for S2M family multi-function devices.
+More information can be found in bindings/mfd/sec-core.txt file.
+
+The S2MPS11/13/14/15 and S2MPU02 devices provide buck and LDO regulators.
+
+To register these with regulator framework instantiate under main device node
+a sub-node named "regulators" with more sub-nodes for each regulator using the
+common regulator binding documented in:
+ - Documentation/devicetree/bindings/regulator/regulator.txt
+
+
+Names of regulators supported by different devices:
+ - LDOn
+ - valid values for n are:
+ - S2MPS11: 1 to 38
+ - S2MPS13: 1 to 40
+ - S2MPS14: 1 to 25
+ - S2MPS15: 1 to 27
+ - S2MPU02: 1 to 28
+ - Example: LDO1, LDO2, LDO28
+ - BUCKn
+ - valid values for n are:
+ - S2MPS11: 1 to 10
+ - S2MPS13: 1 to 10
+ - S2MPS14: 1 to 5
+ - S2MPS15: 1 to 10
+ - S2MPU02: 1 to 7
+ - Example: BUCK1, BUCK2, BUCK9
+Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of device.
+
+
+Optional properties of the nodes under "regulators" sub-node:
+ - regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500,
+ 25000 (default) or 50000.
+
+ Additionally S2MPS11 supports disabling ramp delay for BUCK{2,3,4,6}
+ by setting it to <0>.
+
+ Note: On S2MPS11 some bucks share the ramp rate setting i.e. same ramp value
+ will be set for a particular group of bucks so provide the same
+ regulator-ramp-delay value for them.
+ Groups sharing ramp rate:
+ - buck{1,6},
+ - buck{3,4},
+ - buck{7,8,10}.
+
+ - samsung,ext-control-gpios: On S2MPS14 the LDO10, LDO11 and LDO12 can be
+ configured to external control over GPIO. To turn this feature on this
+ property must be added to the regulator sub-node:
+ - samsung,ext-control-gpios: GPIO specifier for one GPIO
+ controlling this regulator (enable/disable)
+ Example:
+ LDO12 {
+ regulator-name = "V_EMMC_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+
+Example:
+
+ s2mps11_pmic@66 {
+ compatible = "samsung,s2mps11-pmic";
+ reg = <0x66>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ABB_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_ALIVE_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <50000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt b/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
new file mode 100644
index 000000000000..093edda0c8df
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
@@ -0,0 +1,145 @@
+Binding for Samsung S5M8767 regulator block
+===========================================
+
+This is a part of device tree bindings for S5M family multi-function devices.
+More information can be found in bindings/mfd/sec-core.txt file.
+
+The S5M8767 device provide buck and LDO regulators.
+
+To register these with regulator framework instantiate under main device node
+a sub-node named "regulators" with more sub-nodes for each regulator using the
+common regulator binding documented in:
+ - Documentation/devicetree/bindings/regulator/regulator.txt
+
+
+Required properties of the main device node (the parent!):
+ - s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+ units for buck2 when changing voltage using gpio dvs. Refer to [1] below
+ for additional information.
+
+ - s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+ units for buck3 when changing voltage using gpio dvs. Refer to [1] below
+ for additional information.
+
+ - s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+ units for buck4 when changing voltage using gpio dvs. Refer to [1] below
+ for additional information.
+
+ - s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
+ for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
+
+ [1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+ property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage'
+ property should specify atleast one voltage level (which would be a
+ safe operating voltage).
+
+ If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+ property is specified, then all the eight voltage values for the
+ 's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
+
+Optional properties of the main device node (the parent!):
+ - s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
+ - s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs.
+ - s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs.
+
+Additional properties required if either of the optional properties are used:
+
+ - s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from
+ the possible 8 options selectable by the dvs gpios. The value of this
+ property should be between 0 and 7. If not specified or if out of range, the
+ default value of this property is set to 0.
+
+ - s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used
+ for dvs. The format of the gpio specifier depends in the gpio controller.
+
+
+Names of regulators supported by S5M8767 device:
+ - LDOn
+ - valid values for n are 1 to 28
+ - Example: LDO1, LDO2, LDO28
+ - BUCKn
+ - valid values for n are 1 to 9.
+ - Example: BUCK1, BUCK2, BUCK9
+Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of device.
+
+
+Optional properties of the nodes under "regulators" sub-node:
+ - op_mode: describes the different operating modes of the LDO's with
+ power mode change in SOC. The different possible values are,
+ 0 - always off mode
+ 1 - on in normal mode
+ 2 - low power mode
+ 3 - suspend mode
+ - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one
+ GPIO controlling this regulator
+ (enable/disable); This is valid only
+ for buck9.
+
+Example:
+
+ s5m8767_pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+
+ s5m8767,pmic-buck2-uses-gpio-dvs;
+ s5m8767,pmic-buck3-uses-gpio-dvs;
+ s5m8767,pmic-buck4-uses-gpio-dvs;
+
+ s5m8767,pmic-buck-default-dvs-idx = <0>;
+
+ s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 0>, /* DVS1 */
+ <&gpx0 1 0>, /* DVS2 */
+ <&gpx0 2 0>; /* DVS3 */
+
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 0>, /* SET1 */
+ <&gpx2 4 0>, /* SET2 */
+ <&gpx2 5 0>; /* SET3 */
+
+ s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
+ <1250000>, <1200000>,
+ <1150000>, <1100000>,
+ <1000000>, <950000>;
+
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
+ <1100000>, <1100000>,
+ <1000000>, <1000000>,
+ <1000000>, <1000000>;
+
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ABB_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_ALIVE_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "VDD_MIF_1.2V";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vemmc_reg: BUCK9 {
+ regulator-name = "VMEM_VDD_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ op_mode = <3>; /* Standby Mode */
+ s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/tps65217.txt b/Documentation/devicetree/bindings/regulator/tps65217.txt
index 4f05d208c95c..d18109657da6 100644
--- a/Documentation/devicetree/bindings/regulator/tps65217.txt
+++ b/Documentation/devicetree/bindings/regulator/tps65217.txt
@@ -26,7 +26,11 @@ Example:
ti,pmic-shutdown-controller;
regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
dcdc1_reg: dcdc1 {
+ reg = <0>;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
@@ -34,6 +38,7 @@ Example:
};
dcdc2_reg: dcdc2 {
+ reg = <1>;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
@@ -41,6 +46,7 @@ Example:
};
dcdc3_reg: dcc3 {
+ reg = <2>;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1500000>;
regulator-boot-on;
@@ -48,6 +54,7 @@ Example:
};
ldo1_reg: ldo1 {
+ reg = <3>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
@@ -55,6 +62,7 @@ Example:
};
ldo2_reg: ldo2 {
+ reg = <4>;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
@@ -62,6 +70,7 @@ Example:
};
ldo3_reg: ldo3 {
+ reg = <5>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
@@ -69,6 +78,7 @@ Example:
};
ldo4_reg: ldo4 {
+ reg = <6>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi6220-reset.txt b/Documentation/devicetree/bindings/reset/hisilicon,hi6220-reset.txt
new file mode 100644
index 000000000000..e0b185a944ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/hisilicon,hi6220-reset.txt
@@ -0,0 +1,34 @@
+Hisilicon System Reset Controller
+======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+The reset controller registers are part of the system-ctl block on
+hi6220 SoC.
+
+Required properties:
+- compatible: may be "hisilicon,hi6220-sysctrl"
+- reg: should be register base and length as documented in the
+ datasheet
+- #reset-cells: 1, see below
+
+Example:
+sys_ctrl: sys_ctrl@f7030000 {
+ compatible = "hisilicon,hi6220-sysctrl", "syscon";
+ reg = <0x0 0xf7030000 0x0 0x2000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+};
+
+Specifying reset lines connected to IP modules
+==============================================
+example:
+
+ uart1: serial@..... {
+ ...
+ resets = <&sys_ctrl PERIPH_RSTEN3_UART1>;
+ ...
+ };
+
+The index could be found in <dt-bindings/reset/hisi,hi6220-resets.h>.
diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
new file mode 100644
index 000000000000..f67e761bcc18
--- /dev/null
+++ b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
@@ -0,0 +1,69 @@
+* HiSilicon SAS controller
+
+The HiSilicon SAS controller supports SAS/SATA.
+
+Main node required properties:
+ - compatible : value should be as follows:
+ (a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset
+ - sas-addr : array of 8 bytes for host SAS address
+ - reg : Address and length of the SAS register
+ - hisilicon,sas-syscon: phandle of syscon used for sas control
+ - ctrl-reset-reg : offset to controller reset register in ctrl reg
+ - ctrl-reset-sts-reg : offset to controller reset status register in ctrl reg
+ - ctrl-clock-ena-reg : offset to controller clock enable register in ctrl reg
+ - queue-count : number of delivery and completion queues in the controller
+ - phy-count : number of phys accessible by the controller
+ - interrupts : Interrupts for phys, completion queues, and fatal
+ sources; the interrupts are ordered in 3 groups, as follows:
+ - Phy interrupts
+ - Completion queue interrupts
+ - Fatal interrupts
+ Phy interrupts : Each phy has 3 interrupt sources:
+ - broadcast
+ - phyup
+ - abnormal
+ The phy interrupts are ordered into groups of 3 per phy
+ (broadcast, phyup, and abnormal) in increasing order.
+ Completion queue interrupts : each completion queue has 1
+ interrupt source.
+ The interrupts are ordered in increasing order.
+ Fatal interrupts : the fatal interrupts are ordered as follows:
+ - ECC
+ - AXI bus
+
+Example:
+ sas0: sas@c1000000 {
+ compatible = "hisilicon,hip05-sas-v1";
+ sas-addr = [50 01 88 20 16 00 00 0a];
+ reg = <0x0 0xc1000000 0x0 0x10000>;
+ hisilicon,sas-syscon = <&pcie_sas>;
+ ctrl-reset-reg = <0xa60>;
+ ctrl-reset-sts-reg = <0x5a30>;
+ ctrl-clock-ena-reg = <0x338>;
+ queue-count = <32>;
+ phy-count = <8>;
+ dma-coherent;
+ interrupt-parent = <&mbigen_dsa>;
+ interrupts = <259 4>,<263 4>,<264 4>,/* phy0 */
+ <269 4>,<273 4>,<274 4>,/* phy1 */
+ <279 4>,<283 4>,<284 4>,/* phy2 */
+ <289 4>,<293 4>,<294 4>,/* phy3 */
+ <299 4>,<303 4>,<304 4>,/* phy4 */
+ <309 4>,<313 4>,<314 4>,/* phy5 */
+ <319 4>,<323 4>,<324 4>,/* phy6 */
+ <329 4>,<333 4>,<334 4>,/* phy7 */
+ <336 1>,<337 1>,<338 1>,/* cq0-2 */
+ <339 1>,<340 1>,<341 1>,/* cq3-5 */
+ <342 1>,<343 1>,<344 1>,/* cq6-8 */
+ <345 1>,<346 1>,<347 1>,/* cq9-11 */
+ <348 1>,<349 1>,<350 1>,/* cq12-14 */
+ <351 1>,<352 1>,<353 1>,/* cq15-17 */
+ <354 1>,<355 1>,<356 1>,/* cq18-20 */
+ <357 1>,<358 1>,<359 1>,/* cq21-23 */
+ <360 1>,<361 1>,<362 1>,/* cq24-26 */
+ <363 1>,<364 1>,<365 1>,/* cq27-29 */
+ <366 1>,<367 1>/* cq30-31 */
+ <376 4>,/* fatal ecc */
+ <381 4>;/* fatal axi */
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt
index 91d5ab0e60fc..936ab5b87324 100644
--- a/Documentation/devicetree/bindings/serial/8250.txt
+++ b/Documentation/devicetree/bindings/serial/8250.txt
@@ -14,7 +14,6 @@ Required properties:
tegra132, or tegra210.
- "nxp,lpc3220-uart"
- "ralink,rt2880-uart"
- - "ibm,qpace-nwp-serial"
- "altr,16550-FIFO32"
- "altr,16550-FIFO64"
- "altr,16550-FIFO128"
diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
index 2d47add34765..a833a016f656 100644
--- a/Documentation/devicetree/bindings/serial/mtk-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -2,15 +2,15 @@
Required properties:
- compatible should contain:
- * "mediatek,mt8135-uart" for MT8135 compatible UARTS
+ * "mediatek,mt2701-uart" for MT2701 compatible UARTS
+ * "mediatek,mt6580-uart" for MT6580 compatible UARTS
+ * "mediatek,mt6582-uart" for MT6582 compatible UARTS
+ * "mediatek,mt6589-uart" for MT6589 compatible UARTS
+ * "mediatek,mt6795-uart" for MT6795 compatible UARTS
* "mediatek,mt8127-uart" for MT8127 compatible UARTS
+ * "mediatek,mt8135-uart" for MT8135 compatible UARTS
* "mediatek,mt8173-uart" for MT8173 compatible UARTS
- * "mediatek,mt6795-uart" for MT6795 compatible UARTS
- * "mediatek,mt6589-uart" for MT6589 compatible UARTS
- * "mediatek,mt6582-uart" for MT6582 compatible UARTS
- * "mediatek,mt6580-uart" for MT6580 compatible UARTS
- * "mediatek,mt6577-uart" for all compatible UARTS (MT8173, MT6795,
- MT6589, MT6582, MT6580, MT6577)
+ * "mediatek,mt6577-uart" for MT6577 and all of the above
- reg: The base address of the UART register bank.
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
index 73f825e5e644..401b1b33c2c4 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
+++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
@@ -2,7 +2,7 @@
Required properties:
- - compatible: Must contain one of the following:
+ - compatible: Must contain one or more of the following:
- "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART.
- "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART.
@@ -15,10 +15,14 @@ Required properties:
- "renesas,scifa-r8a7790" for R8A7790 (R-Car H2) SCIFA compatible UART.
- "renesas,scifb-r8a7790" for R8A7790 (R-Car H2) SCIFB compatible UART.
- "renesas,hscif-r8a7790" for R8A7790 (R-Car H2) HSCIF compatible UART.
- - "renesas,scif-r8a7791" for R8A7791 (R-Car M2) SCIF compatible UART.
- - "renesas,scifa-r8a7791" for R8A7791 (R-Car M2) SCIFA compatible UART.
- - "renesas,scifb-r8a7791" for R8A7791 (R-Car M2) SCIFB compatible UART.
- - "renesas,hscif-r8a7791" for R8A7791 (R-Car M2) HSCIF compatible UART.
+ - "renesas,scif-r8a7791" for R8A7791 (R-Car M2-W) SCIF compatible UART.
+ - "renesas,scifa-r8a7791" for R8A7791 (R-Car M2-W) SCIFA compatible UART.
+ - "renesas,scifb-r8a7791" for R8A7791 (R-Car M2-W) SCIFB compatible UART.
+ - "renesas,hscif-r8a7791" for R8A7791 (R-Car M2-W) HSCIF compatible UART.
+ - "renesas,scif-r8a7793" for R8A7793 (R-Car M2-N) SCIF compatible UART.
+ - "renesas,scifa-r8a7793" for R8A7793 (R-Car M2-N) SCIFA compatible UART.
+ - "renesas,scifb-r8a7793" for R8A7793 (R-Car M2-N) SCIFB compatible UART.
+ - "renesas,hscif-r8a7793" for R8A7793 (R-Car M2-N) HSCIF compatible UART.
- "renesas,scif-r8a7794" for R8A7794 (R-Car E2) SCIF compatible UART.
- "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART.
- "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART.
@@ -27,6 +31,14 @@ Required properties:
- "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
+ - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,
+ - "renesas,rcar-gen2-scif" for R-Car Gen2 SCIF compatible UART,
+ - "renesas,rcar-gen3-scif" for R-Car Gen3 SCIF compatible UART,
+ - "renesas,rcar-gen2-scifa" for R-Car Gen2 SCIFA compatible UART,
+ - "renesas,rcar-gen2-scifb" for R-Car Gen2 SCIFB compatible UART,
+ - "renesas,rcar-gen1-hscif" for R-Car Gen1 HSCIF compatible UART,
+ - "renesas,rcar-gen2-hscif" for R-Car Gen2 HSCIF compatible UART,
+ - "renesas,rcar-gen3-hscif" for R-Car Gen3 HSCIF compatible UART,
- "renesas,scif" for generic SCIF compatible UART.
- "renesas,scifa" for generic SCIFA compatible UART.
- "renesas,scifb" for generic SCIFB compatible UART.
@@ -34,15 +46,26 @@ Required properties:
- "renesas,sci" for generic SCI compatible UART.
When compatible with the generic version, nodes must list the
- SoC-specific version corresponding to the platform first followed by the
- generic version.
+ SoC-specific version corresponding to the platform first, followed by the
+ family-specific and/or generic versions.
- reg: Base address and length of the I/O registers used by the UART.
- interrupts: Must contain an interrupt-specifier for the SCIx interrupt.
- clocks: Must contain a phandle and clock-specifier pair for each entry
in clock-names.
- - clock-names: Must contain "sci_ick" for the SCIx UART interface clock.
+ - clock-names: Must contain "fck" for the SCIx UART functional clock.
+ Apart from the divided functional clock, there may be other possible
+ sources for the sampling clock, depending on SCIx variant.
+ On (H)SCI(F) and some SCIFA, an additional clock may be specified:
+ - "hsck" for the optional external clock input (on HSCIF),
+ - "sck" for the optional external clock input (on other variants).
+ On UARTs equipped with a Baud Rate Generator for External Clock (BRG)
+ (some SCIF and HSCIF), additional clocks may be specified:
+ - "brg_int" for the optional internal clock source for the frequency
+ divider (typically the (AXI or SHwy) bus clock),
+ - "scif_clk" for the optional external clock source for the frequency
+ divider (SCIF_CLK).
Note: Each enabled SCIx UART should have an alias correctly numbered in the
"aliases" node.
@@ -58,12 +81,13 @@ Example:
};
scifa0: serial@e6c40000 {
- compatible = "renesas,scifa-r8a7790", "renesas,scifa";
+ compatible = "renesas,scifa-r8a7790",
+ "renesas,rcar-gen2-scifa", "renesas,scifa";
reg = <0 0xe6c40000 0 64>;
interrupt-parent = <&gic>;
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
- clock-names = "sci_ick";
+ clock-names = "fck";
dmas = <&dmac0 0x21>, <&dmac0 0x22>;
dma-names = "tx", "rx";
};
diff --git a/Documentation/devicetree/bindings/soc/bcm/raspberrypi,bcm2835-power.txt b/Documentation/devicetree/bindings/soc/bcm/raspberrypi,bcm2835-power.txt
new file mode 100644
index 000000000000..30942cf7992b
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/bcm/raspberrypi,bcm2835-power.txt
@@ -0,0 +1,47 @@
+Raspberry Pi power domain driver
+
+Required properties:
+
+- compatible: Should be "raspberrypi,bcm2835-power".
+- firmware: Reference to the RPi firmware device node.
+- #power-domain-cells: Should be <1>, we providing multiple power domains.
+
+The valid defines for power domain are:
+
+ RPI_POWER_DOMAIN_I2C0
+ RPI_POWER_DOMAIN_I2C1
+ RPI_POWER_DOMAIN_I2C2
+ RPI_POWER_DOMAIN_VIDEO_SCALER
+ RPI_POWER_DOMAIN_VPU1
+ RPI_POWER_DOMAIN_HDMI
+ RPI_POWER_DOMAIN_USB
+ RPI_POWER_DOMAIN_VEC
+ RPI_POWER_DOMAIN_JPEG
+ RPI_POWER_DOMAIN_H264
+ RPI_POWER_DOMAIN_V3D
+ RPI_POWER_DOMAIN_ISP
+ RPI_POWER_DOMAIN_UNICAM0
+ RPI_POWER_DOMAIN_UNICAM1
+ RPI_POWER_DOMAIN_CCP2RX
+ RPI_POWER_DOMAIN_CSI2
+ RPI_POWER_DOMAIN_CPI
+ RPI_POWER_DOMAIN_DSI0
+ RPI_POWER_DOMAIN_DSI1
+ RPI_POWER_DOMAIN_TRANSPOSER
+ RPI_POWER_DOMAIN_CCP2TX
+ RPI_POWER_DOMAIN_CDP
+ RPI_POWER_DOMAIN_ARM
+
+Example:
+
+power: power {
+ compatible = "raspberrypi,bcm2835-power";
+ firmware = <&firmware>;
+ #power-domain-cells = <1>;
+};
+
+Example for using power domain:
+
+&usb {
+ power-domains = <&power RPI_POWER_DOMAIN_USB>;
+};
diff --git a/Documentation/devicetree/bindings/soc/dove/pmu.txt b/Documentation/devicetree/bindings/soc/dove/pmu.txt
new file mode 100644
index 000000000000..edd40b796b74
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/dove/pmu.txt
@@ -0,0 +1,56 @@
+Device Tree bindings for Marvell PMU
+
+Required properties:
+ - compatible: value should be "marvell,dove-pmu".
+ May also include "simple-bus" if there are child devices, in which
+ case the ranges node is required.
+ - reg: two base addresses and sizes of the PM controller and PMU.
+ - interrupts: single interrupt number for the PMU interrupt
+ - interrupt-controller: must be specified as the PMU itself is an
+ interrupt controller.
+ - #interrupt-cells: must be 1.
+ - #reset-cells: must be 1.
+ - domains: sub-node containing domain descriptions
+
+Optional properties:
+ - ranges: defines the address mapping for child devices, as per the
+ standard property of this name. Required when compatible includes
+ "simple-bus".
+
+Power domain descriptions are listed as child nodes of the "domains"
+sub-node. Each domain has the following properties:
+
+Required properties:
+ - #power-domain-cells: must be 0.
+
+Optional properties:
+ - marvell,pmu_pwr_mask: specifies the mask value for PMU power register
+ - marvell,pmu_iso_mask: specifies the mask value for PMU isolation register
+ - resets: points to the reset manager (PMU node) and reset index.
+
+Example:
+
+ pmu: power-management@d0000 {
+ compatible = "marvell,dove-pmu";
+ reg = <0xd0000 0x8000>, <0xd8000 0x8000>;
+ interrupts = <33>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #reset-cells = <1>;
+
+ domains {
+ vpu_domain: vpu-domain {
+ #power-domain-cells = <0>;
+ marvell,pmu_pwr_mask = <0x00000008>;
+ marvell,pmu_iso_mask = <0x00000001>;
+ resets = <&pmu 16>;
+ };
+
+ gpu_domain: gpu-domain {
+ #power-domain-cells = <0>;
+ marvell,pmu_pwr_mask = <0x00000004>;
+ marvell,pmu_iso_mask = <0x00000002>;
+ resets = <&pmu 18>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
index a6c8afc8385a..e8f15e34027f 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
@@ -21,6 +21,18 @@ Required properties:
These are the clocks which hardware needs to be enabled
before enabling certain power domains.
+Optional properties:
+- vdec-supply: Power supply for the vdec power domain
+- venc-supply: Power supply for the venc power domain
+- isp-supply: Power supply for the isp power domain
+- mm-supply: Power supply for the mm power domain
+- venc_lt-supply: Power supply for the venc_lt power domain
+- audio-supply: Power supply for the audio power domain
+- usb-supply: Power supply for the usb power domain
+- mfg_async-supply: Power supply for the mfg_async power domain
+- mfg_2d-supply: Power supply for the mfg_2d power domain
+- mfg-supply: Power supply for the mfg power domain
+
Example:
scpsys: scpsys@10006000 {
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
new file mode 100644
index 000000000000..a48049ccf6d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
@@ -0,0 +1,58 @@
+Qualcomm Resource Power Manager (RPM) over SMD
+
+This driver is used to interface with the Resource Power Manager (RPM) found in
+various Qualcomm platforms. The RPM allows each component in the system to vote
+for state of the system resources, such as clocks, regulators and bus
+frequencies.
+
+The SMD information for the RPM edge should be filled out. See qcom,smd.txt for
+the required edge properties. All SMD related properties will reside within the
+RPM node itself.
+
+= SUBDEVICES
+
+The RPM exposes resources to its subnodes. The rpm_requests node must be
+present and this subnode may contain children that designate regulator
+resources.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-apq8084"
+ "qcom,rpm-msm8916"
+ "qcom,rpm-msm8974"
+
+- qcom,smd-channels:
+ Usage: required
+ Value type: <string>
+ Definition: must be "rpm_requests"
+
+Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
+for information on the regulator subnodes that can exist under the rpm_requests.
+
+Example:
+
+ soc {
+ apcs: syscon@f9011000 {
+ compatible = "syscon";
+ reg = <0xf9011000 0x1000>;
+ };
+ };
+
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <0 168 1>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-msm8974";
+ qcom,smd-channels = "rpm_requests";
+
+ ...
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt
new file mode 100644
index 000000000000..5cc82b8353d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt
@@ -0,0 +1,104 @@
+Qualcomm Shared Memory Point 2 Point binding
+
+The Shared Memory Point to Point (SMP2P) protocol facilitates communication of
+a single 32-bit value between two processors. Each value has a single writer
+(the local side) and a single reader (the remote side). Values are uniquely
+identified in the system by the directed edge (local processor ID to remote
+processor ID) and a string identifier.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,smp2p"
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: one entry specifying the smp2p notification interrupt
+
+- qcom,ipc:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: three entries specifying the outgoing ipc bit used for
+ signaling the remote end of the smp2p edge:
+ - phandle to a syscon node representing the apcs registers
+ - u32 representing offset to the register within the syscon
+ - u32 representing the ipc bit within the register
+
+- qcom,smem:
+ Usage: required
+ Value type: <u32 array>
+ Definition: two identifiers of the inbound and outbound smem items used
+ for this edge
+
+- qcom,local-pid:
+ Usage: required
+ Value type: <u32>
+ Definition: specifies the identfier of the local endpoint of this edge
+
+- qcom,remote-pid:
+ Usage: required
+ Value type: <u32>
+ Definition: specifies the identfier of the remote endpoint of this edge
+
+= SUBNODES
+Each SMP2P pair contain a set of inbound and outbound entries, these are
+described in subnodes of the smp2p device node. The node names are not
+important.
+
+- qcom,entry-name:
+ Usage: required
+ Value type: <string>
+ Definition: specifies the name of this entry, for inbound entries this
+ will be used to match against the remotely allocated entry
+ and for outbound entries this name is used for allocating
+ entries
+
+- interrupt-controller:
+ Usage: required for incoming entries
+ Value type: <empty>
+ Definition: marks the entry as inbound; the node should be specified
+ as a two cell interrupt-controller as defined in
+ "../interrupt-controller/interrupts.txt"
+ If not specified this node will denote the outgoing entry
+
+- #interrupt-cells:
+ Usage: required for incoming entries
+ Value type: <u32>
+ Definition: must be 2 - denoting the bit in the entry and IRQ flags
+
+- #qcom,state-cells:
+ Usage: required for outgoing entries
+ Value type: <u32>
+ Definition: must be 1 - denoting the bit in the entry
+
+= EXAMPLE
+The following example shows the SMP2P setup with the wireless processor,
+defined from the 8974 apps processor's point-of-view. It encompasses one
+inbound and one outbound entry:
+
+wcnss-smp2p {
+ compatible = "qcom,smp2p";
+ qcom,smem = <431>, <451>;
+
+ interrupts = <0 143 1>;
+
+ qcom,ipc = <&apcs 8 18>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <4>;
+
+ wcnss_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+
+ #qcom,state-cells = <1>;
+ };
+
+ wcnss_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smsm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smsm.txt
new file mode 100644
index 000000000000..a6634c70850d
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smsm.txt
@@ -0,0 +1,104 @@
+Qualcomm Shared Memory State Machine
+
+The Shared Memory State Machine facilitates broadcasting of single bit state
+information between the processors in a Qualcomm SoC. Each processor is
+assigned 32 bits of state that can be modified. A processor can through a
+matrix of bitmaps signal subscription of notifications upon changes to a
+certain bit owned by a certain remote processor.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,smsm"
+
+- qcom,ipc-N:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: three entries specifying the outgoing ipc bit used for
+ signaling the N:th remote processor
+ - phandle to a syscon node representing the apcs registers
+ - u32 representing offset to the register within the syscon
+ - u32 representing the ipc bit within the register
+
+- qcom,local-host:
+ Usage: optional
+ Value type: <u32>
+ Definition: identifier of the local processor in the list of hosts, or
+ in other words specifier of the column in the subscription
+ matrix representing the local processor
+ defaults to host 0
+
+- #address-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 1
+
+- #size-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 0
+
+= SUBNODES
+Each processor's state bits are described by a subnode of the smsm device node.
+Nodes can either be flagged as an interrupt-controller to denote a remote
+processor's state bits or the local processors bits. The node names are not
+important.
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: specifies the offset, in words, of the first bit for this
+ entry
+
+- #qcom,state-cells:
+ Usage: required for local entry
+ Value type: <u32>
+ Definition: must be 1 - denotes bit number
+
+- interrupt-controller:
+ Usage: required for remote entries
+ Value type: <empty>
+ Definition: marks the entry as a interrupt-controller and the state bits
+ to belong to a remote processor
+
+- #interrupt-cells:
+ Usage: required for remote entries
+ Value type: <u32>
+ Definition: must be 2 - denotes bit number and IRQ flags
+
+- interrupts:
+ Usage: required for remote entries
+ Value type: <prop-encoded-array>
+ Definition: one entry specifying remote IRQ used by the remote processor
+ to signal changes of its state bits
+
+
+= EXAMPLE
+The following example shows the SMEM setup for controlling properties of the
+wireless processor, defined from the 8974 apps processor's point-of-view. It
+encompasses one outbound entry and the outgoing interrupt for the wireless
+processor.
+
+smsm {
+ compatible = "qcom,smsm";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ipc-3 = <&apcs 8 19>;
+
+ apps_smsm: apps@0 {
+ reg = <0>;
+
+ #qcom,state-cells = <1>;
+ };
+
+ wcnss_smsm: wcnss@7 {
+ reg = <7>;
+ interrupts = <0 144 1>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt b/Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt
new file mode 100644
index 000000000000..401550487ed6
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt
@@ -0,0 +1,57 @@
+Wakeup M3 IPC Driver
+=====================
+
+The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor
+(commonly referred to as Wakeup M3 or CM3) to help with various low power tasks
+that cannot be controlled from the MPU, like suspend/resume and certain deep
+C-states for CPU Idle. Once the wkup_m3_ipc driver uses the wkup_m3_rproc driver
+to boot the wkup_m3, it handles communication with the CM3 using IPC registers
+present in the SoC's control module and a mailbox. The wkup_m3_ipc exposes an
+API to allow the SoC PM code to execute specific PM tasks.
+
+Wkup M3 Device Node:
+====================
+A wkup_m3_ipc device node is used to represent the IPC registers within an
+SoC.
+
+Required properties:
+--------------------
+- compatible: Should be,
+ "ti,am3352-wkup-m3-ipc" for AM33xx SoCs
+ "ti,am4372-wkup-m3-ipc" for AM43xx SoCs
+- reg: Contains the IPC register address space to communicate
+ with the Wakeup M3 processor
+- interrupts: Contains the interrupt information for the wkup_m3
+ interrupt that signals the MPU.
+- ti,rproc: phandle to the wkup_m3 rproc node so the IPC driver
+ can boot it.
+- mboxes: phandles used by IPC framework to get correct mbox
+ channel for communication. Must point to appropriate
+ mbox_wkupm3 child node.
+
+Example:
+--------
+/* AM33xx */
+ l4_wkup: l4_wkup@44c00000 {
+ ...
+
+ scm: scm@210000 {
+ compatible = "ti,am3-scm", "simple-bus";
+ reg = <0x210000 0x2000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x210000 0x2000>;
+
+ ...
+
+ wkup_m3_ipc: wkup_m3_ipc@1324 {
+ compatible = "ti,am3352-wkup-m3-ipc";
+ reg = <0x1324 0x24>;
+ interrupts = <78>;
+ ti,rproc = <&wkup_m3>;
+ mboxes = <&mailbox &mbox_wkupm3>;
+ };
+
+ ...
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt
index 15a919522b42..1783f9ef0930 100644
--- a/Documentation/devicetree/bindings/sound/ak4613.txt
+++ b/Documentation/devicetree/bindings/sound/ak4613.txt
@@ -7,6 +7,16 @@ Required properties:
- compatible : "asahi-kasei,ak4613"
- reg : The chip select number on the I2C bus
+Optional properties:
+- asahi-kasei,in1-single-end : Boolean. Indicate input / output pins are single-ended.
+- asahi-kasei,in2-single-end rather than differential.
+- asahi-kasei,out1-single-end
+- asahi-kasei,out2-single-end
+- asahi-kasei,out3-single-end
+- asahi-kasei,out4-single-end
+- asahi-kasei,out5-single-end
+- asahi-kasei,out6-single-end
+
Example:
&i2c {
diff --git a/Documentation/devicetree/bindings/sound/atmel-classd.txt b/Documentation/devicetree/bindings/sound/atmel-classd.txt
index 0018451c4351..549e701cb7a1 100644
--- a/Documentation/devicetree/bindings/sound/atmel-classd.txt
+++ b/Documentation/devicetree/bindings/sound/atmel-classd.txt
@@ -16,6 +16,10 @@ Required properties:
Required elements: "pclk", "gclk" and "aclk".
- clocks
Please refer to clock-bindings.txt.
+- assigned-clocks
+ Should be <&classd_gclk>.
+- assigned-clock-parents
+ Should be <&audio_pll_pmc>.
Optional properties:
- pinctrl-names, pinctrl-0
@@ -43,6 +47,8 @@ classd: classd@fc048000 {
dma-names = "tx";
clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
clock-names = "pclk", "gclk", "aclk";
+ assigned-clocks = <&classd_gclk>;
+ assigned-clock-parents = <&audio_pll_pmc>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_classd_default>;
diff --git a/Documentation/devicetree/bindings/sound/atmel-pdmic.txt b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt
new file mode 100644
index 000000000000..e0875f17c229
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt
@@ -0,0 +1,55 @@
+* Atmel PDMIC driver under ALSA SoC architecture
+
+Required properties:
+- compatible
+ Should be "atmel,sama5d2-pdmic".
+- reg
+ Should contain PDMIC registers location and length.
+- interrupts
+ Should contain the IRQ line for the PDMIC.
+- dmas
+ One DMA specifiers as described in atmel-dma.txt and dma.txt files.
+- dma-names
+ Must be "rx".
+- clock-names
+ Required elements:
+ - "pclk" peripheral clock
+ - "gclk" generated clock
+- clocks
+ Must contain an entry for each required entry in clock-names.
+ Please refer to clock-bindings.txt.
+- atmel,mic-min-freq
+ The minimal frequency that the micphone supports.
+- atmel,mic-max-freq
+ The maximal frequency that the micphone supports.
+
+Optional properties:
+- pinctrl-names, pinctrl-0
+ Please refer to pinctrl-bindings.txt.
+- atmel,model
+ The user-visible name of this sound card.
+ The default value is "PDMIC".
+- atmel,mic-offset
+ The offset that should be added.
+ The range is from -32768 to 32767.
+ The default value is 0.
+
+Example:
+ pdmic@f8018000 {
+ compatible = "atmel,sama5d2-pdmic";
+ reg = <0xf8018000 0x124>;
+ interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(50))>;
+ dma-names = "rx";
+ clocks = <&pdmic_clk>, <&pdmic_gclk>;
+ clock-names = "pclk", "gclk";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pdmic_default>;
+ atmel,model = "PDMIC @ sama5d2_xplained";
+ atmel,mic-min-freq = <1000000>;
+ atmel,mic-max-freq = <3246000>;
+ atmel,mic-offset = <0x0>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/da7218.txt b/Documentation/devicetree/bindings/sound/da7218.txt
new file mode 100644
index 000000000000..5ca5a709b6aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/da7218.txt
@@ -0,0 +1,104 @@
+Dialog Semiconductor DA7218 Audio Codec bindings
+
+DA7218 is an audio codec with HP detect feature.
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7217" or "dlg,da7218"
+- reg: Specifies the I2C slave address
+
+- VDD-supply: VDD power supply for the device
+- VDDMIC-supply: VDDMIC power supply for the device
+- VDDIO-supply: VDDIO power supply for the device
+ (See Documentation/devicetree/bindings/regulator/regulator.txt for further
+ information relating to regulators)
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+ the IRQs from DA7218 are delivered to.
+- interrupts: IRQ line info for DA7218 chip.
+ (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+ further information relating to interrupt properties)
+- interrupt-names : Name associated with interrupt line. Should be "wakeup" if
+ interrupt is to be used to wake system, otherwise "irq" should be used.
+- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
+
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,micbias1-lvl-millivolt : Voltage (mV) for Mic Bias 1
+ [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>]
+- dlg,micbias2-lvl-millivolt : Voltage (mV) for Mic Bias 2
+ [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>]
+- dlg,mic1-amp-in-sel : Mic1 input source type
+ ["diff", "se_p", "se_n"]
+- dlg,mic2-amp-in-sel : Mic2 input source type
+ ["diff", "se_p", "se_n"]
+- dlg,dmic1-data-sel : DMIC1 channel select based on clock edge.
+ ["lrise_rfall", "lfall_rrise"]
+- dlg,dmic1-samplephase : When to sample audio from DMIC1.
+ ["on_clkedge", "between_clkedge"]
+- dlg,dmic1-clkrate-hz : DMic1 clock frequency (Hz).
+ [<1500000>, <3000000>]
+- dlg,dmic2-data-sel : DMic2 channel select based on clock edge.
+ ["lrise_rfall", "lfall_rrise"]
+- dlg,dmic2-samplephase : When to sample audio from DMic2.
+ ["on_clkedge", "between_clkedge"]
+- dlg,dmic2-clkrate-hz : DMic2 clock frequency (Hz).
+ [<1500000>, <3000000>]
+- dlg,hp-diff-single-supply : Boolean flag, use single supply for HP
+ (DA7217 only)
+
+======
+
+Optional Child node - 'da7218_hpldet' (DA7218 only):
+
+Optional properties:
+- dlg,jack-rate-us : Time between jack detect measurements (us)
+ [<5>, <10>, <20>, <40>, <80>, <160>, <320>, <640>]
+- dlg,jack-debounce : Number of debounce measurements taken for jack detect
+ [<0>, <2>, <3>, <4>]
+- dlg,jack-threshold-pct : Threshold level for jack detection (% of VDD)
+ [<84>, <88>, <92>, <96>]
+- dlg,comp-inv : Boolean flag, invert comparator output
+- dlg,hyst : Boolean flag, enable hysteresis
+- dlg,discharge : Boolean flag, auto discharge of Mic Bias on jack removal
+
+======
+
+Example:
+
+ codec: da7218@1a {
+ compatible = "dlg,da7218";
+ reg = <0x1a>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+ wakeup-source;
+
+ VDD-supply = <&reg_audio>;
+ VDDMIC-supply = <&reg_audio>;
+ VDDIO-supply = <&reg_audio>;
+
+ clocks = <&clks 201>;
+ clock-names = "mclk";
+
+ dlg,micbias1-lvl-millivolt = <2600>;
+ dlg,micbias2-lvl-millivolt = <2600>;
+ dlg,mic1-amp-in-sel = "diff";
+ dlg,mic2-amp-in-sel = "diff";
+
+ dlg,dmic1-data-sel = "lrise_rfall";
+ dlg,dmic1-samplephase = "on_clkedge";
+ dlg,dmic1-clkrate-hz = <3000000>;
+ dlg,dmic2-data-sel = "lrise_rfall";
+ dlg,dmic2-samplephase = "on_clkedge";
+ dlg,dmic2-clkrate-hz = <3000000>;
+
+ da7218_hpldet {
+ dlg,jack-rate-us = <40>;
+ dlg,jack-debounce = <2>;
+ dlg,jack-threshold-pct = <84>;
+ dlg,hyst;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt
index 1b7030911a3b..cf61681826b6 100644
--- a/Documentation/devicetree/bindings/sound/da7219.txt
+++ b/Documentation/devicetree/bindings/sound/da7219.txt
@@ -28,13 +28,15 @@ Optional properties:
- clocks : phandle and clock specifier for codec MCLK.
- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
-- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
- [<1050>, <1100>, <1200>, <1400>]
- dlg,micbias-lvl : Voltage (mV) for Mic Bias
- [<1800>, <2000>, <2200>, <2400>, <2600>]
+ [<1600>, <1800>, <2000>, <2200>, <2400>, <2600>]
- dlg,mic-amp-in-sel : Mic input source type
["diff", "se_p", "se_n"]
+Deprecated properties:
+- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
+ (LDO unavailable in production HW so property no longer required).
+
======
Child node - 'da7219_aad':
diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
index b93362a570be..3e26a9478e57 100644
--- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
@@ -25,6 +25,11 @@ Required properties:
"mem" Peripheral access clock to access registers.
"ipg" Peripheral clock to driver module.
"asrck_<0-f>" Clock sources for input and output clock.
+ "spba" The spba clock is required when ASRC is placed as a
+ bus slave of the Shared Peripheral Bus and when two
+ or more bus masters (CPU, DMA or DSP) try to access
+ it. This property is optional depending on the SoC
+ design.
- big-endian : If this property is absent, the little endian mode
will be in use as default. Otherwise, the big endian
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index d3b6b5f48010..cd3ee5d84f03 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -27,6 +27,11 @@ Required properties:
derive HCK, SCK and FS.
"fsys" The system clock derived from ahb clock used to
derive HCK, SCK and FS.
+ "spba" The spba clock is required when ESAI is placed as a
+ bus slave of the Shared Peripheral Bus and when two
+ or more bus masters (CPU, DMA or DSP) try to access
+ it. This property is optional depending on the SoC
+ design.
- fsl,fifo-depth : The number of elements in the transmit and receive
FIFOs. This number is the maximum allowed value for
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
index b5ee32ee3706..4ca39ddc0417 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -27,6 +27,11 @@ Required properties:
Transceiver Clock Diagram" of SoC reference manual.
It can also be referred to TxClk_Source bit of
register SPDIF_STC.
+ "spba" The spba clock is required when SPDIF is placed as a
+ bus slave of the Shared Peripheral Bus and when two
+ or more bus masters (CPU, DMA or DSP) try to access
+ it. This property is optional depending on the SoC
+ design.
- big-endian : If this property is absent, the native endian mode
will be in use as default, or the big endian mode
diff --git a/Documentation/devicetree/bindings/sound/img,i2s-in.txt b/Documentation/devicetree/bindings/sound/img,i2s-in.txt
new file mode 100644
index 000000000000..423265cfc3d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,i2s-in.txt
@@ -0,0 +1,47 @@
+Imagination Technologies I2S Input Controller
+
+Required Properties:
+
+ - compatible : Compatible list, must contain "img,i2s-in"
+
+ - #sound-dai-cells : Must be equal to 0
+
+ - reg : Offset and length of the register set for the device
+
+ - clocks : Contains an entry for each entry in clock-names
+
+ - clock-names : Must include the following entry:
+ "sys" The system clock
+
+ - dmas: Contains an entry for each entry in dma-names.
+
+ - dma-names: Must include the following entry:
+ "rx" Single DMA channel used by all active I2S channels
+
+ - img,i2s-channels : Number of I2S channels instantiated in the I2S in block
+
+Optional Properties:
+
+ - interrupts : Contains the I2S in interrupts. Depending on
+ the configuration, there may be no interrupts, one interrupt,
+ or an interrupt per I2S channel. For the case where there is
+ one interrupt per channel, the interrupts should be listed
+ in ascending channel order
+
+ - resets: Contains a phandle to the I2S in reset signal
+
+ - reset-names: Contains the reset signal name "rst"
+
+Example:
+
+i2s_in: i2s-in@18100800 {
+ compatible = "img,i2s-in";
+ reg = <0x18100800 0x200>;
+ interrupts = <GIC_SHARED 7 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&mdc 30 0xffffffff 0>;
+ dma-names = "rx";
+ clocks = <&cr_periph SYS_CLK_I2S_IN>;
+ clock-names = "sys";
+ img,i2s-channels = <6>;
+ #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,i2s-out.txt b/Documentation/devicetree/bindings/sound/img,i2s-out.txt
new file mode 100644
index 000000000000..0159415b3338
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,i2s-out.txt
@@ -0,0 +1,51 @@
+Imagination Technologies I2S Output Controller
+
+Required Properties:
+
+ - compatible : Compatible list, must contain "img,i2s-out"
+
+ - #sound-dai-cells : Must be equal to 0
+
+ - reg : Offset and length of the register set for the device
+
+ - clocks : Contains an entry for each entry in clock-names
+
+ - clock-names : Must include the following entries:
+ "sys" The system clock
+ "ref" The reference clock
+
+ - dmas: Contains an entry for each entry in dma-names.
+
+ - dma-names: Must include the following entry:
+ "tx" Single DMA channel used by all active I2S channels
+
+ - img,i2s-channels : Number of I2S channels instantiated in the I2S out block
+
+ - resets: Contains a phandle to the I2S out reset signal
+
+ - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+ - interrupts : Contains the I2S out interrupts. Depending on
+ the configuration, there may be no interrupts, one interrupt,
+ or an interrupt per I2S channel. For the case where there is
+ one interrupt per channel, the interrupts should be listed
+ in ascending channel order
+
+Example:
+
+i2s_out: i2s-out@18100A00 {
+ compatible = "img,i2s-out";
+ reg = <0x18100A00 0x200>;
+ interrupts = <GIC_SHARED 13 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&mdc 23 0xffffffff 0>;
+ dma-names = "tx";
+ clocks = <&cr_periph SYS_CLK_I2S_OUT>,
+ <&clk_core CLK_I2S>;
+ clock-names = "sys", "ref";
+ img,i2s-channels = <6>;
+ resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>;
+ reset-names = "rst";
+ #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,parallel-out.txt b/Documentation/devicetree/bindings/sound/img,parallel-out.txt
new file mode 100644
index 000000000000..a3015d2a06e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,parallel-out.txt
@@ -0,0 +1,44 @@
+Imagination Technologies Parallel Output Controller
+
+Required Properties:
+
+ - compatible : Compatible list, must contain "img,parallel-out".
+
+ - #sound-dai-cells : Must be equal to 0
+
+ - reg : Offset and length of the register set for the device.
+
+ - dmas: Contains an entry for each entry in dma-names.
+
+ - dma-names: Must include the following entry:
+ "tx"
+
+ - clocks : Contains an entry for each entry in clock-names.
+
+ - clock-names : Includes the following entries:
+ "sys" The system clock
+ "ref" The reference clock
+
+ - resets: Contains a phandle to the parallel out reset signal
+
+ - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+ - interrupts : Contains the parallel out interrupt, if present
+
+Example:
+
+parallel_out: parallel-out@18100C00 {
+ compatible = "img,parallel-out";
+ reg = <0x18100C00 0x100>;
+ interrupts = <GIC_SHARED 19 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&mdc 16 0xffffffff 0>;
+ dma-names = "tx";
+ clocks = <&cr_periph SYS_CLK_PAUD_OUT>,
+ <&clk_core CLK_AUDIO_DAC>;
+ clock-names = "sys", "ref";
+ resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>;
+ reset-names = "rst";
+ #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt
new file mode 100644
index 000000000000..4cc18fc0477e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt
@@ -0,0 +1,18 @@
+Pistachio internal DAC DT bindings
+
+Required properties:
+
+ - compatible: "img,pistachio-internal-dac"
+
+ - img,cr-top : Must contain a phandle to the top level control syscon
+ node which contains the internal dac control registers
+
+ - VDD-supply : Digital power supply regulator (+1.8V or +3.3V)
+
+Examples:
+
+internal_dac: internal-dac {
+ compatible = "img,pistachio-internal-dac";
+ img,cr-top = <&cr_top>;
+ VDD-supply = <&supply3v3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,spdif-in.txt b/Documentation/devicetree/bindings/sound/img,spdif-in.txt
new file mode 100644
index 000000000000..aab9a81f7e13
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,spdif-in.txt
@@ -0,0 +1,41 @@
+Imagination Technologies SPDIF Input Controller
+
+Required Properties:
+
+ - compatible : Compatible list, must contain "img,spdif-in"
+
+ - #sound-dai-cells : Must be equal to 0
+
+ - reg : Offset and length of the register set for the device
+
+ - dmas: Contains an entry for each entry in dma-names.
+
+ - dma-names: Must include the following entry:
+ "rx"
+
+ - clocks : Contains an entry for each entry in clock-names
+
+ - clock-names : Includes the following entries:
+ "sys" The system clock
+
+Optional Properties:
+
+ - resets: Should contain a phandle to the spdif in reset signal, if any
+
+ - reset-names: Should contain the reset signal name "rst", if a
+ reset phandle is given
+
+ - interrupts : Contains the spdif in interrupt, if present
+
+Example:
+
+spdif_in: spdif-in@18100E00 {
+ compatible = "img,spdif-in";
+ reg = <0x18100E00 0x100>;
+ interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&mdc 15 0xffffffff 0>;
+ dma-names = "rx";
+ clocks = <&cr_periph SYS_CLK_SPDIF_IN>;
+ clock-names = "sys";
+ #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,spdif-out.txt b/Documentation/devicetree/bindings/sound/img,spdif-out.txt
new file mode 100644
index 000000000000..470a5191e101
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,spdif-out.txt
@@ -0,0 +1,44 @@
+Imagination Technologies SPDIF Output Controller
+
+Required Properties:
+
+ - compatible : Compatible list, must contain "img,spdif-out"
+
+ - #sound-dai-cells : Must be equal to 0
+
+ - reg : Offset and length of the register set for the device
+
+ - dmas: Contains an entry for each entry in dma-names.
+
+ - dma-names: Must include the following entry:
+ "tx"
+
+ - clocks : Contains an entry for each entry in clock-names.
+
+ - clock-names : Includes the following entries:
+ "sys" The system clock
+ "ref" The reference clock
+
+ - resets: Contains a phandle to the spdif out reset signal
+
+ - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+ - interrupts : Contains the parallel out interrupt, if present
+
+Example:
+
+spdif_out: spdif-out@18100D00 {
+ compatible = "img,spdif-out";
+ reg = <0x18100D00 0x100>;
+ interrupts = <GIC_SHARED 21 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&mdc 14 0xffffffff 0>;
+ dma-names = "tx";
+ clocks = <&cr_periph SYS_CLK_SPDIF_OUT>,
+ <&clk_core CLK_SPDIF>;
+ clock-names = "sys", "ref";
+ resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>;
+ reset-names = "rst";
+ #sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt
new file mode 100644
index 000000000000..758de8e27561
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/inno-rk3036.txt
@@ -0,0 +1,20 @@
+Inno audio codec for RK3036
+
+Inno audio codec is integrated inside RK3036 SoC.
+
+Required properties:
+- compatible : Should be "rockchip,rk3036-codec".
+- reg : The registers of codec.
+- clock-names : Should be "acodec_pclk".
+- clocks : The clock of codec.
+- rockchip,grf : The phandle of grf device node.
+
+Example:
+
+ acodec: acodec-ana@20030000 {
+ compatible = "rk3036-codec";
+ reg = <0x20030000 0x4000>;
+ rockchip,grf = <&grf>;
+ clock-names = "acodec_pclk";
+ clocks = <&cru ACLK_VCODEC>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/pcm1792a.txt b/Documentation/devicetree/bindings/sound/pcm179x.txt
index 970ba1ed576f..4ae70d3462d6 100644
--- a/Documentation/devicetree/bindings/sound/pcm1792a.txt
+++ b/Documentation/devicetree/bindings/sound/pcm179x.txt
@@ -1,4 +1,4 @@
-Texas Instruments pcm1792a DT bindings
+Texas Instruments pcm179x DT bindings
This driver supports the SPI bus.
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index c57cbd65736c..8ee0fa91e4a0 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -7,8 +7,11 @@ Required properties:
"renesas,rcar_sound-gen3" if generation3
Examples with soctypes are:
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
+ - "renesas,rcar_sound-r8a7779" (R-Car H1)
- "renesas,rcar_sound-r8a7790" (R-Car H2)
- "renesas,rcar_sound-r8a7791" (R-Car M2-W)
+ - "renesas,rcar_sound-r8a7793" (R-Car M2-N)
+ - "renesas,rcar_sound-r8a7794" (R-Car E2)
- "renesas,rcar_sound-r8a7795" (R-Car H3)
- reg : Should contain the register physical address.
required register is
@@ -34,6 +37,8 @@ Required properties:
see below for detail.
- #sound-dai-cells : it must be 0 if your system is using single DAI
it must be 1 if your system is using multi DAI
+
+Optional properties:
- #clock-cells : it must be 0 if your system has audio_clkout
it must be 1 if your system has audio_clkout0/1/2/3
- clock-frequency : for all audio_clkout0/1/2/3
@@ -244,3 +249,80 @@ rcar_sound: sound@ec500000 {
};
};
};
+
+Example: simple sound card
+
+ rsnd_ak4643: sound {
+ compatible = "simple-audio-card";
+
+ 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>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4643>;
+ clocks = <&audio_clock>;
+ };
+ };
+
+&rcar_sound {
+ pinctrl-0 = <&sound_pins &sound_clk_pins>;
+ pinctrl-names = "default";
+
+ /* Single DAI */
+ #sound-dai-cells = <0>;
+
+ status = "okay";
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0 &src2 &dvc0>;
+ capture = <&ssi1 &src3 &dvc1>;
+ };
+ };
+};
+
+&ssi1 {
+ shared-pin;
+};
+
+Example: simple sound card for TDM
+
+ 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>;
+
+ 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 Multi channel
+
+&rcar_sound {
+ pinctrl-0 = <&sound_pins &sound_clk_pins>;
+ pinctrl-names = "default";
+
+ /* Single DAI */
+ #sound-dai-cells = <0>;
+
+ status = "okay";
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
index 962748a8d919..2b2caa281ce3 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
@@ -4,8 +4,8 @@ Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC
Required properties:
-- compatible : "renesas,rsrc-card,<board>"
- Examples with soctypes are:
+- compatible : "renesas,rsrc-card{,<board>}"
+ Examples with boards are:
- "renesas,rsrc-card"
- "renesas,rsrc-card,lager"
- "renesas,rsrc-card,koelsch"
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt
index 2267d249ca0e..b7f3a9325ebd 100644
--- a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt
@@ -19,6 +19,7 @@ Required properties:
- clock-names: should contain followings:
- "i2s_hclk": clock for I2S BUS
- "i2s_clk" : clock for I2S controller
+- rockchip,playback-channels: max playback channels, if not set, 8 channels default.
- rockchip,capture-channels: max capture channels, if not set, 2 channels default.
Example for rk3288 I2S controller:
@@ -31,5 +32,6 @@ i2s@ff890000 {
dma-names = "tx", "rx";
clock-names = "i2s_hclk", "i2s_clk";
clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+ rockchip,playback-channels = <8>;
rockchip,capture-channels = <2>;
};
diff --git a/Documentation/devicetree/bindings/sound/rt5616.txt b/Documentation/devicetree/bindings/sound/rt5616.txt
new file mode 100644
index 000000000000..efc48c65198d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5616.txt
@@ -0,0 +1,26 @@
+RT5616 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5616".
+
+- reg : The I2C address of the device.
+
+Pins on the device (for linking into audio routes) for RT5616:
+
+ * IN1P
+ * IN2P
+ * IN2N
+ * LOUTL
+ * LOUTR
+ * HPOL
+ * HPOR
+
+Example:
+
+codec: rt5616@1b {
+ compatible = "realtek,rt5616";
+ reg = <0x1b>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5651.txt b/Documentation/devicetree/bindings/sound/rt5651.txt
new file mode 100644
index 000000000000..3875233095f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5651.txt
@@ -0,0 +1,41 @@
+RT5651 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5651".
+
+- reg : The I2C address of the device.
+
+Optional properties:
+
+- realtek,in2-differential
+ Boolean. Indicate MIC2 input are differential, rather than single-ended.
+
+- realtek,dmic-en
+ Boolean. true if dmic is used.
+
+Pins on the device (for linking into audio routes) for RT5651:
+
+ * DMIC L1
+ * DMIC R1
+ * IN1P
+ * IN2P
+ * IN2N
+ * IN3P
+ * HPOL
+ * HPOR
+ * LOUTL
+ * LOUTR
+ * PDML
+ * PDMR
+
+Example:
+
+codec: rt5651@1a {
+ compatible = "realtek,rt5651";
+ reg = <0x1a>;
+ realtek,dmic-en = "true";
+ realtek,in2-diff = "false";
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
new file mode 100644
index 000000000000..5f79e7fde032
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5659.txt
@@ -0,0 +1,75 @@
+RT5659/RT5658 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5659" or "realtek,rt5658".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in3-differential
+- realtek,in4-differential
+ Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended.
+
+- realtek,dmic1-data-pin
+ 0: dmic1 is not used
+ 1: using IN2N pin as dmic1 data pin
+ 2: using GPIO5 pin as dmic1 data pin
+ 3: using GPIO9 pin as dmic1 data pin
+ 4: using GPIO11 pin as dmic1 data pin
+
+- realtek,dmic2-data-pin
+ 0: dmic2 is not used
+ 1: using IN2P pin as dmic2 data pin
+ 2: using GPIO6 pin as dmic2 data pin
+ 3: using GPIO10 pin as dmic2 data pin
+ 4: using GPIO12 pin as dmic2 data pin
+
+- realtek,jd-src
+ 0: No JD is used
+ 1: using JD3 as JD source
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin.
+
+Pins on the device (for linking into audio routes) for RT5659/RT5658:
+
+ * DMIC L1
+ * DMIC R1
+ * DMIC L2
+ * DMIC R2
+ * IN1P
+ * IN1N
+ * IN2P
+ * IN2N
+ * IN3P
+ * IN3N
+ * IN4P
+ * IN4N
+ * HPOL
+ * HPOR
+ * SPOL
+ * SPOR
+ * LOUTL
+ * LOUTR
+ * MONOOUT
+ * PDML
+ * PDMR
+ * SPDIF
+
+Example:
+
+rt5659 {
+ compatible = "realtek,rt5659";
+ reg = <0x1b>;
+ interrupt-parent = <&gpio>;
+ interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+ realtek,ldo1-en-gpios =
+ <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
index f07078997f87..1b3c13d206ff 100644
--- a/Documentation/devicetree/bindings/sound/rt5677.txt
+++ b/Documentation/devicetree/bindings/sound/rt5677.txt
@@ -18,7 +18,7 @@ Required properties:
Optional properties:
- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
-- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
+- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low.
- realtek,in1-differential
- realtek,in2-differential
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index c92966bd5488..0dce690f78f5 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -14,6 +14,9 @@ Required properties:
- "apb": the parent APB clock for this controller
- "codec": the parent module clock
+Optional properties:
+- allwinner,pa-gpios: gpio to enable external amplifier
+
Example:
codec: codec@01c22c00 {
#sound-dai-cells = <0>;
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
new file mode 100644
index 000000000000..5d9cb84c661d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
@@ -0,0 +1,48 @@
+Texas Instruments pcm3168a DT bindings
+
+This driver supports both SPI and I2C bus access for this codec
+
+Required properties:
+
+ - compatible: "ti,pcm3168a"
+
+ - clocks : Contains an entry for each entry in clock-names
+
+ - clock-names : Includes the following entries:
+ "scki" The system clock
+
+ - VDD1-supply : Digital power supply regulator 1 (+3.3V)
+
+ - VDD2-supply : Digital power supply regulator 2 (+3.3V)
+
+ - VCCAD1-supply : ADC power supply regulator 1 (+5V)
+
+ - VCCAD2-supply : ADC power supply regulator 2 (+5V)
+
+ - VCCDA1-supply : DAC power supply regulator 1 (+5V)
+
+ - VCCDA2-supply : DAC power supply regulator 2 (+5V)
+
+For required properties on SPI/I2C, consult SPI/I2C device tree documentation
+
+Examples:
+
+i2c0: i2c0@0 {
+
+ ...
+
+ pcm3168a: audio-codec@44 {
+ compatible = "ti,pcm3168a";
+ reg = <0x44>;
+ clocks = <&clk_core CLK_AUDIO>;
+ clock-names = "scki";
+ VDD1-supply = <&supply3v3>;
+ VDD2-supply = <&supply3v3>;
+ VCCAD1-supply = <&supply5v0>;
+ VCCAD2-supply = <&supply5v0>;
+ VCCDA1-supply = <&supply5v0>;
+ VCCDA2-supply = <&supply5v0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dac_clk_pin>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8974.txt b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
new file mode 100644
index 000000000000..01d3a7c83419
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
@@ -0,0 +1,15 @@
+WM8974 audio CODEC
+
+This device supports both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+ - compatible: "wlf,wm8974"
+ - reg: the I2C address or SPI chip select number of the device
+
+Examples:
+
+codec: wm8974@1a {
+ compatible = "wlf,wm8974";
+ reg = <0x1a>;
+};
diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt
index e045e90a0924..68c4e8d96bed 100644
--- a/Documentation/devicetree/bindings/sound/wm8994.txt
+++ b/Documentation/devicetree/bindings/sound/wm8994.txt
@@ -30,7 +30,7 @@ Optional properties:
- #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
The first cell is the IRQ number.
The second cell is the flags, encoded as the trigger masks from
- Documentation/devicetree/bindings/interrupts.txt
+ Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- clocks : A list of up to two phandle and clock specifier pairs
- clock-names : A list of clock names sorted in the same order as clocks.
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index 705075da2f10..aa005c1d10d9 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -10,6 +10,7 @@ Required properties:
"renesas,msiof-r8a7792" (R-Car V2H)
"renesas,msiof-r8a7793" (R-Car M2-N)
"renesas,msiof-r8a7794" (R-Car E2)
+ "renesas,msiof-sh73a0" (SH-Mobile AG5)
- reg : A list of offsets and lengths of the register sets for
the device.
If only one register set is present, it is to be used
diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt
index ce363c923f44..e43f4cf4cf35 100644
--- a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt
+++ b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt
@@ -2,9 +2,10 @@ Binding for MTK SPI controller
Required properties:
- compatible: should be one of the following.
- - mediatek,mt8173-spi: for mt8173 platforms
- - mediatek,mt8135-spi: for mt8135 platforms
+ - mediatek,mt2701-spi: for mt2701 platforms
- mediatek,mt6589-spi: for mt6589 platforms
+ - mediatek,mt8135-spi: for mt8135 platforms
+ - mediatek,mt8173-spi: for mt8173 platforms
- #address-cells: should be 1.
@@ -29,10 +30,10 @@ Required properties:
muxes clock, and "spi-clk" for the clock gate.
Optional properties:
--cs-gpios: see spi-bus.txt, only required for MT8173.
+-cs-gpios: see spi-bus.txt.
- mediatek,pad-select: specify which pins group(ck/mi/mo/cs) spi
- controller used. This is a array, the element value should be 0~3,
+ controller used. This is an array, the element value should be 0~3,
only required for MT8173.
0: specify GPIO69,70,71,72 for spi pins.
1: specify GPIO102,103,104,105 for spi pins.
diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt
index 601a360531a5..cc8304aa64ac 100644
--- a/Documentation/devicetree/bindings/spi/ti_qspi.txt
+++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt
@@ -15,14 +15,32 @@ Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
+Optional properties:
+- syscon-chipselects: Handle to system control region contains QSPI
+ chipselect register and offset of that register.
+
Example:
+For am4372:
qspi: qspi@4b300000 {
- compatible = "ti,dra7xxx-qspi";
- reg = <0x47900000 0x100>, <0x30000000 0x3ffffff>;
+ compatible = "ti,am4372-qspi";
+ reg = <0x47900000 0x100>, <0x30000000 0x4000000>;
reg-names = "qspi_base", "qspi_mmap";
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <25000000>;
ti,hwmods = "qspi";
};
+
+For dra7xx:
+qspi: qspi@4b300000 {
+ compatible = "ti,dra7xxx-qspi";
+ reg = <0x4b300000 0x100>,
+ <0x5c000000 0x4000000>,
+ reg-names = "qspi_base", "qspi_mmap";
+ syscon-chipselects = <&scm_conf 0x558>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ spi-max-frequency = <48000000>;
+ ti,hwmods = "qspi";
+};
diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu-sram.txt b/Documentation/devicetree/bindings/sram/rockchip-pmu-sram.txt
index 6b42fda306ff..6b42fda306ff 100644
--- a/Documentation/devicetree/bindings/arm/rockchip/pmu-sram.txt
+++ b/Documentation/devicetree/bindings/sram/rockchip-pmu-sram.txt
diff --git a/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt b/Documentation/devicetree/bindings/sram/rockchip-smp-sram.txt
index d9416fb8db6f..800701ecffca 100644
--- a/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
+++ b/Documentation/devicetree/bindings/sram/rockchip-smp-sram.txt
@@ -12,7 +12,7 @@ Required sub-node properties:
- compatible : should be "rockchip,rk3066-smp-sram"
The rest of the properties should follow the generic mmio-sram discription
-found in ../../misc/sram.txt
+found in Documentation/devicetree/bindings/sram/sram.txt
Example:
diff --git a/Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt b/Documentation/devicetree/bindings/sram/samsung-sram.txt
index 4a0a4f70a0ce..6bc474b2b885 100644
--- a/Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt
+++ b/Documentation/devicetree/bindings/sram/samsung-sram.txt
@@ -15,7 +15,7 @@ Required sub-node properties:
"samsung,exynos4210-sysram-ns" : for Non-secure SYSRAM
The rest of the properties should follow the generic mmio-sram discription
-found in ../../misc/sysram.txt
+found in Documentation/devicetree/bindings/sram/sram.txt
Example:
diff --git a/Documentation/devicetree/bindings/misc/sram.txt b/Documentation/devicetree/bindings/sram/sram.txt
index 42ee9438b771..42ee9438b771 100644
--- a/Documentation/devicetree/bindings/misc/sram.txt
+++ b/Documentation/devicetree/bindings/sram/sram.txt
diff --git a/Documentation/devicetree/bindings/soc/sunxi/sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index 067698112f5f..8d5665468fe7 100644
--- a/Documentation/devicetree/bindings/soc/sunxi/sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -16,7 +16,7 @@ SRAM nodes
----------
Each SRAM is described using the mmio-sram bindings documented in
-Documentation/devicetree/bindings/misc/sram.txt
+Documentation/devicetree/bindings/sram/sram.txt
Each SRAM will have SRAM sections that are going to be handled by the
SRAM controller as subnodes. These sections are represented following
diff --git a/Documentation/devicetree/bindings/staging/ion/hi6220-ion.txt b/Documentation/devicetree/bindings/staging/ion/hi6220-ion.txt
new file mode 100644
index 000000000000..c59e27c632c1
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/ion/hi6220-ion.txt
@@ -0,0 +1,31 @@
+Hi6220 SoC ION
+===================================================================
+Required properties:
+- compatible : "hisilicon,hi6220-ion"
+- list of the ION heaps
+ - heap name : maybe heap_sys_user@0
+ - heap id : id should be unique in the system.
+ - heap base : base ddr address of the heap,0 means that
+ it is dynamic.
+ - heap size : memory size and 0 means it is dynamic.
+ - heap type : the heap type of the heap, please also
+ see the define in ion.h(drivers/staging/android/uapi/ion.h)
+-------------------------------------------------------------------
+Example:
+ hi6220-ion {
+ compatible = "hisilicon,hi6220-ion";
+ heap_sys_user@0 {
+ heap-name = "sys_user";
+ heap-id = <0x0>;
+ heap-base = <0x0>;
+ heap-size = <0x0>;
+ heap-type = "ion_system";
+ };
+ heap_sys_contig@0 {
+ heap-name = "sys_contig";
+ heap-id = <0x1>;
+ heap-base = <0x0>;
+ heap-size = <0x0>;
+ heap-type = "ion_system_contig";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt b/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt
new file mode 100644
index 000000000000..66223d561972
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt
@@ -0,0 +1,63 @@
+* Thermal Monitoring Unit (TMU) on Freescale QorIQ SoCs
+
+Required properties:
+- compatible : Must include "fsl,qoriq-tmu". The version of the device is
+ determined by the TMU IP Block Revision Register (IPBRR0) at
+ offset 0x0BF8.
+ Table of correspondences between IPBRR0 values and example chips:
+ Value Device
+ ---------- -----
+ 0x01900102 T1040
+- reg : Address range of TMU registers.
+- interrupts : Contains the interrupt for TMU.
+- fsl,tmu-range : The values to be programmed into TTRnCR, as specified by
+ the SoC reference manual. The first cell is TTR0CR, the second is
+ TTR1CR, etc.
+- fsl,tmu-calibration : A list of cell pairs containing temperature
+ calibration data, as specified by the SoC reference manual.
+ The first cell of each pair is the value to be written to TTCFGR,
+ and the second is the value to be written to TSCFGR.
+
+Example:
+
+tmu@f0000 {
+ compatible = "fsl,qoriq-tmu";
+ reg = <0xf0000 0x1000>;
+ interrupts = <18 2 0 0>;
+ fsl,tmu-range = <0x000a0000 0x00090026 0x0008004a 0x0001006a>;
+ fsl,tmu-calibration = <0x00000000 0x00000025
+ 0x00000001 0x00000028
+ 0x00000002 0x0000002d
+ 0x00000003 0x00000031
+ 0x00000004 0x00000036
+ 0x00000005 0x0000003a
+ 0x00000006 0x00000040
+ 0x00000007 0x00000044
+ 0x00000008 0x0000004a
+ 0x00000009 0x0000004f
+ 0x0000000a 0x00000054
+
+ 0x00010000 0x0000000d
+ 0x00010001 0x00000013
+ 0x00010002 0x00000019
+ 0x00010003 0x0000001f
+ 0x00010004 0x00000025
+ 0x00010005 0x0000002d
+ 0x00010006 0x00000033
+ 0x00010007 0x00000043
+ 0x00010008 0x0000004b
+ 0x00010009 0x00000053
+
+ 0x00020000 0x00000010
+ 0x00020001 0x00000017
+ 0x00020002 0x0000001f
+ 0x00020003 0x00000029
+ 0x00020004 0x00000031
+ 0x00020005 0x0000003c
+ 0x00020006 0x00000042
+ 0x00020007 0x0000004d
+ 0x00020008 0x00000056
+
+ 0x00030000 0x00000012
+ 0x00030001 0x0000001d>;
+};
diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
index 64083bc5633c..8ff54eb464dc 100644
--- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
+++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
@@ -3,6 +3,7 @@ Mediatek MT6577, MT6572 and MT6589 Timers
Required properties:
- compatible should contain:
+ * "mediatek,mt2701-timer" for MT2701 compatible timers
* "mediatek,mt6580-timer" for MT6580 compatible timers
* "mediatek,mt6589-timer" for MT6589 compatible timers
* "mediatek,mt8127-timer" for MT8127 compatible timers
diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt
index fd132cbee70e..221368207ca4 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.txt
+++ b/Documentation/devicetree/bindings/usb/dwc2.txt
@@ -4,6 +4,7 @@ Platform DesignWare HS OTG USB 2.0 controller
Required properties:
- compatible : One of:
- brcm,bcm2835-usb: The DWC2 USB controller instance in the BCM2835 SoC.
+ - hisilicon,hi6220-usb: The DWC2 USB controller instance in the hi6220 SoC.
- rockchip,rk3066-usb: The DWC2 USB controller instance in the rk3066 Soc;
- "rockchip,rk3188-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3188 Soc;
- "rockchip,rk3288-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3288 Soc;
diff --git a/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt b/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt
new file mode 100644
index 000000000000..30361b32a460
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/dwc3-xilinx.txt
@@ -0,0 +1,33 @@
+Xilinx SuperSpeed DWC3 USB SoC controller
+
+Required properties:
+- compatible: Should contain "xlnx,zynqmp-dwc3"
+- clocks: A list of phandles for the clocks listed in clock-names
+- clock-names: Should contain the following:
+ "bus_clk" Master/Core clock, have to be >= 125 MHz for SS
+ operation and >= 60MHz for HS operation
+
+ "ref_clk" Clock source to core during PHY power down
+
+Required child node:
+A child node must exist to represent the core DWC3 IP block. The name of
+the node is not important. The content of the node is defined in dwc3.txt.
+
+Example device node:
+
+ usb@0 {
+ #address-cells = <0x2>;
+ #size-cells = <0x1>;
+ status = "okay";
+ compatible = "xlnx,zynqmp-dwc3";
+ clock-names = "bus_clk" "ref_clk";
+ clocks = <&clk125>, <&clk125>;
+ ranges;
+
+ dwc3@fe200000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xfe200000 0x40000>;
+ interrupts = <0x0 0x41 0x4>;
+ dr_mode = "host";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
new file mode 100644
index 000000000000..b3a7ffa48852
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
@@ -0,0 +1,51 @@
+MT8173 xHCI
+
+The device node for Mediatek SOC USB3.0 host controller
+
+Required properties:
+ - compatible : should contain "mediatek,mt8173-xhci"
+ - reg : specifies physical base address and size of the registers,
+ the first one for MAC, the second for IPPC
+ - interrupts : interrupt used by the controller
+ - power-domains : a phandle to USB power domain node to control USB's
+ mtcmos
+ - vusb33-supply : regulator of USB avdd3.3v
+
+ - clocks : a list of phandle + clock-specifier pairs, one for each
+ entry in clock-names
+ - clock-names : must contain
+ "sys_ck": for clock of xHCI MAC
+ "wakeup_deb_p0": for USB wakeup debounce clock of port0
+ "wakeup_deb_p1": for USB wakeup debounce clock of port1
+
+ - phys : a list of phandle + phy specifier pairs
+
+Optional properties:
+ - mediatek,wakeup-src : 1: ip sleep wakeup mode; 2: line state wakeup
+ mode;
+ - mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
+ control register, it depends on "mediatek,wakeup-src".
+ - vbus-supply : reference to the VBUS regulator;
+ - usb3-lpm-capable : supports USB3.0 LPM
+
+Example:
+usb30: usb@11270000 {
+ compatible = "mediatek,mt8173-xhci";
+ reg = <0 0x11270000 0 0x1000>,
+ <0 0x11280700 0 0x0100>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+ clocks = <&topckgen CLK_TOP_USB30_SEL>,
+ <&pericfg CLK_PERI_USB0>,
+ <&pericfg CLK_PERI_USB1>;
+ clock-names = "sys_ck",
+ "wakeup_deb_p0",
+ "wakeup_deb_p1";
+ phys = <&phy_port0 PHY_TYPE_USB3>,
+ <&phy_port1 PHY_TYPE_USB2>;
+ vusb33-supply = <&mt6397_vusb_reg>;
+ vbus-supply = <&usb_p1_vbus>;
+ usb3-lpm-capable;
+ mediatek,syscon-wakeup = <&pericfg>;
+ mediatek,wakeup-src = <1>;
+};
diff --git a/Documentation/devicetree/bindings/usb/octeon-usb.txt b/Documentation/devicetree/bindings/usb/octeon-usb.txt
new file mode 100644
index 000000000000..205c8d24d6e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/octeon-usb.txt
@@ -0,0 +1,62 @@
+OCTEON/OCTEON+ USB BLOCK
+
+1) Main node
+
+ Required properties:
+
+ - compatible: must be "cavium,octeon-5750-usbn"
+
+ - reg: specifies the physical base address of the USBN block and
+ the length of the memory mapped region.
+
+ - #address-cells: specifies the number of cells needed to encode an
+ address. The value must be 2.
+
+ - #size-cells: specifies the number of cells used to represent the size
+ of an address. The value must be 2.
+
+ - ranges: specifies the translation between child address space and parent
+ address space.
+
+ - clock-frequency: speed of the USB reference clock. Allowed values are
+ 12000000, 24000000 or 48000000.
+
+ - cavium,refclk-type: type of the USB reference clock. Allowed values are
+ "crystal" or "external".
+
+ - refclk-frequency: deprecated, use "clock-frequency".
+
+ - refclk-type: deprecated, use "cavium,refclk-type".
+
+2) Child node
+
+ The main node must have one child node which describes the built-in
+ USB controller.
+
+ Required properties:
+
+ - compatible: must be "cavium,octeon-5750-usbc"
+
+ - reg: specifies the physical base address of the USBC block and
+ the length of the memory mapped region.
+
+ - interrupts: specifies the interrupt number for the USB controller.
+
+3) Example:
+
+ usbn: usbn@1180068000000 {
+ compatible = "cavium,octeon-5750-usbn";
+ reg = <0x11800 0x68000000 0x0 0x1000>;
+ ranges; /* Direct mapping */
+ #address-cells = <2>;
+ #size-cells = <2>;
+ clock-frequency = <12000000>;
+ cavium,refclk-type = "crystal";
+
+ usbc@16f0010000000 {
+ compatible = "cavium,octeon-5750-usbc";
+ reg = <0x16f00 0x10000000 0x0 0x80000>;
+ interrupts = <0 56>;
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt
new file mode 100644
index 000000000000..8d52766f07b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt
@@ -0,0 +1,23 @@
+Renesas Electronics USB3.0 Peripheral driver
+
+Required properties:
+ - compatible: Must contain one of the following:
+ - "renesas,r8a7795-usb3-peri"
+ - reg: Base address and length of the register for the USB3.0 Peripheral
+ - interrupts: Interrupt specifier for the USB3.0 Peripheral
+ - clocks: clock phandle and specifier pair
+
+Example:
+ usb3_peri0: usb@ee020000 {
+ compatible = "renesas,r8a7795-usb3-peri";
+ reg = <0 0xee020000 0 0x400>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 328>;
+ };
+
+ usb3_peri1: usb@ee060000 {
+ compatible = "renesas,r8a7795-usb3-peri";
+ reg = <0 0xee060000 0 0x400>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 327>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
index 7d48f63db44e..b6040563e51a 100644
--- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
+++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
@@ -1,11 +1,21 @@
Renesas Electronics USBHS driver
Required properties:
- - compatible: Must contain one of the following:
- - "renesas,usbhs-r8a7790"
- - "renesas,usbhs-r8a7791"
- - "renesas,usbhs-r8a7794"
- - "renesas,usbhs-r8a7795"
+ - compatible: Must contain one or more of the following:
+
+ - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
+ - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
+ - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
+ - "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device
+ - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
+ - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
+ - "renesas,rcar-gen2-usbhs" for R-Car Gen2 compatible device
+ - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
+
+ When compatible with the generic version, nodes must list the
+ SoC-specific version corresponding to the platform first followed
+ by the generic version.
+
- reg: Base address and length of the register for the USBHS
- interrupts: Interrupt specifier for the USBHS
- clocks: A list of phandle + clock specifier pairs
@@ -22,7 +32,7 @@ Optional properties:
Example:
usbhs: usb@e6590000 {
- compatible = "renesas,usbhs-r8a7790";
+ compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs";
reg = <0 0xe6590000 0 0x100>;
interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7790_CLK_HSUSB>;
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
index 86f67f0886bc..082573289f1e 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -3,8 +3,8 @@ USB xHCI controllers
Required properties:
- compatible: should be one of "generic-xhci",
"marvell,armada-375-xhci", "marvell,armada-380-xhci",
- "renesas,xhci-r8a7790", "renesas,xhci-r8a7791" (deprecated:
- "xhci-platform").
+ "renesas,xhci-r8a7790", "renesas,xhci-r8a7791", "renesas,xhci-r8a7793",
+ "renesas,xhci-r8a7795" (deprecated: "xhci-platform").
- reg: should contain address and length of the standard XHCI
register set for the device.
- interrupts: one XHCI interrupt should be described here.
diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt
index 52493b1480e2..c1a0a9191d26 100644
--- a/Documentation/devicetree/bindings/usb/usb3503.txt
+++ b/Documentation/devicetree/bindings/usb/usb3503.txt
@@ -18,7 +18,8 @@ Optional properties:
- refclk: Clock used for driving REFCLK signal (optional, if not provided
the driver assumes that clock signal is always available, its
rate is specified by REF_SEL pins and a value from the primary
- reference clock frequencies table is used)
+ reference clock frequencies table is used). Use clocks and
+ clock-names in order to assign it
- refclk-frequency: Frequency of the REFCLK signal as defined by REF_SEL
pins (optional, if not provided, driver will not set rate of the
REFCLK signal and assume that a value from the primary reference
@@ -33,4 +34,6 @@ Examples:
intn-gpios = <&gpx3 4 1>;
reset-gpios = <&gpx3 5 1>;
initial-mode = <1>;
+ clocks = <&clks 80>;
+ clock-names = "refclk";
};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 55df1d444e9f..72e2c5a2b327 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -33,6 +33,7 @@ auo AU Optronics Corporation
avago Avago Technologies
avic Shanghai AVIC Optoelectronics Co., Ltd.
axis Axis Communications AB
+boe BOE Technology Group Co., Ltd.
bosch Bosch Sensortec GmbH
boundary Boundary Devices Inc.
brcm Broadcom Corporation
@@ -123,6 +124,8 @@ jedec JEDEC Solid State Technology Association
karo Ka-Ro electronics GmbH
keymile Keymile GmbH
kinetic Kinetic Technologies
+kosagi Sutajio Ko-Usagi PTE Ltd.
+kyo Kyocera Corporation
lacie LaCie
lantiq Lantiq Semiconductor
lenovo Lenovo Group Ltd.
@@ -161,6 +164,7 @@ nuvoton Nuvoton Technology Corporation
nvidia NVIDIA
nxp NXP Semiconductors
okaya Okaya Electric America, Inc.
+olimex OLIMEX Ltd.
onnn ON Semiconductor Corp.
opencores OpenCores.org
option Option NV
@@ -180,6 +184,7 @@ qca Qualcomm Atheros, Inc.
qcom Qualcomm Technologies, Inc
qemu QEMU, a generic and open source machine emulator and virtualizer
qi Qi Hardware
+qiaodian QiaoDian XianShi Corporation
qnap QNAP Systems, Inc.
radxa Radxa
raidsonic RaidSonic Technology GmbH
@@ -218,11 +223,13 @@ sony Sony Corporation
spansion Spansion Inc.
sprd Spreadtrum Communications Inc.
st STMicroelectronics
+startek Startek
ste ST-Ericsson
stericsson ST-Ericsson
synology Synology, Inc.
tbs TBS Technologies
tcl Toby Churchill Ltd.
+technologic Technologic Systems
thine THine Electronics, Inc.
ti Texas Instruments
tlm Trusted Logic Mobility
@@ -238,6 +245,7 @@ v3 V3 Semiconductor
variscite Variscite Ltd.
via VIA Technologies, Inc.
virtio Virtual I/O Device Specification, developed by the OASIS consortium
+vivante Vivante Corporation
voipac Voipac Technologies s.r.o.
wexler Wexler
winbond Winbond Electronics corp.
diff --git a/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt b/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt
new file mode 100644
index 000000000000..75b265a04047
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt
@@ -0,0 +1,35 @@
+Alphascale asm9260 Watchdog timer
+
+Required properties:
+
+- compatible : should be "alphascale,asm9260-wdt".
+- reg : Specifies base physical address and size of the registers.
+- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt
+- clock-names : should be set to
+ "mod" - source for tick counter.
+ "ahb" - ahb gate.
+- resets : phandle pointing to the system reset controller with
+ line index for the watchdog.
+- reset-names : should be set to "wdt_rst".
+
+Optional properties:
+- timeout-sec : shall contain the default watchdog timeout in seconds,
+ if unset, the default timeout is 30 seconds.
+- alphascale,mode : three modes are supported
+ "hw" - hw reset (default).
+ "sw" - sw reset.
+ "debug" - no action is taken.
+
+Example:
+
+watchdog0: watchdog@80048000 {
+ compatible = "alphascale,asm9260-wdt";
+ reg = <0x80048000 0x10>;
+ clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>;
+ clock-names = "mod", "ahb";
+ interrupts = <55>;
+ resets = <&rst WDT_RESET>;
+ reset-names = "wdt_rst";
+ timeout-sec = <30>;
+ alphascale,mode = "hw";
+};
diff --git a/Documentation/devicetree/bindings/watchdog/meson6-wdt.txt b/Documentation/devicetree/bindings/watchdog/meson-wdt.txt
index 9200fc2d508c..ae70185d96e6 100644
--- a/Documentation/devicetree/bindings/watchdog/meson6-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/meson-wdt.txt
@@ -2,7 +2,7 @@ Meson SoCs Watchdog timer
Required properties:
-- compatible : should be "amlogic,meson6-wdt"
+- compatible : should be "amlogic,meson6-wdt" or "amlogic,meson8b-wdt"
- reg : Specifies base physical address and size of the registers.
Example:
diff --git a/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt b/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt
new file mode 100644
index 000000000000..c15ef0ef609f
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt
@@ -0,0 +1,12 @@
+Ralink Watchdog Timers
+
+Required properties:
+- compatible: must be "mediatek,mt7621-wdt"
+- reg: physical base address of the controller and length of the register range
+
+Example:
+
+ watchdog@100 {
+ compatible = "mediatek,mt7621-wdt";
+ reg = <0x100 0x10>;
+ };
diff --git a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
index af9eb5b8a253..6a00939a059a 100644
--- a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
@@ -2,7 +2,11 @@ Mediatek SoCs Watchdog timer
Required properties:
-- compatible : should be "mediatek,mt6589-wdt"
+- compatible should contain:
+ * "mediatek,mt2701-wdt" for MT2701 compatible watchdog timers
+ * "mediatek,mt6589-wdt" for all compatible watchdog timers (MT2701,
+ MT6589)
+
- reg : Specifies base physical address and size of the registers.
Example:
diff --git a/Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt b/Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt
new file mode 100644
index 000000000000..5b7ec2c707d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt
@@ -0,0 +1,18 @@
+Sigma Designs SMP86xx/SMP87xx watchdog
+
+Required properties:
+- compatible: Should be "sigma,smp8642-wdt"
+- reg: Specifies the physical address region
+- clocks: Should be a phandle to the clock
+
+Optional properties:
+- timeout-sec: watchdog timeout in seconds
+
+Example:
+
+watchdog@1fd00 {
+ compatible = "sigma,smp8642-wdt";
+ reg = <0x1fd00 8>;
+ clocks = <&xtal_in_clk>;
+ timeout-sec = <30>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/sp805-wdt.txt b/Documentation/devicetree/bindings/watchdog/sp805-wdt.txt
new file mode 100644
index 000000000000..edc4f0ea54a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/sp805-wdt.txt
@@ -0,0 +1,31 @@
+* ARM SP805 Watchdog Timer (WDT) Controller
+
+SP805 WDT is a ARM Primecell Peripheral and has a standard-id register that
+can be used to identify the peripheral type, vendor, and revision.
+This value can be used for driver matching.
+
+As SP805 WDT is a primecell IP, it follows the base bindings specified in
+'arm/primecell.txt'
+
+Required properties:
+- compatible : Should be "arm,sp805-wdt", "arm,primecell"
+- reg : Base address and size of the watchdog timer registers.
+- clocks : From common clock binding.
+ First clock is PCLK and the second is WDOGCLK.
+ WDOGCLK can be equal to or be a sub-multiple of the PCLK frequency.
+- clock-names : From common clock binding.
+ Shall be "apb_pclk" for first clock and "wdog_clk" for the
+ second one.
+
+Optional properties:
+- interrupts : Should specify WDT interrupt number.
+
+Examples:
+
+ cluster1_core0_watchdog: wdt@c000000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc000000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
diff --git a/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt b/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt
new file mode 100644
index 000000000000..8f6caad4258d
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt
@@ -0,0 +1,25 @@
+Technologic Systems Watchdog
+
+Required properties:
+- compatible: must be "technologic,ts4800-wdt"
+- syscon: phandle / integer array that points to the syscon node which
+ describes the FPGA's syscon registers.
+ - phandle to FPGA's syscon
+ - offset to the watchdog register
+
+Optional property:
+- timeout-sec: contains the watchdog timeout in seconds.
+
+Example:
+
+syscon: syscon@b0010000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0xb0010000 0x3d>;
+ reg-io-width = <2>;
+
+ wdt@e {
+ compatible = "technologic,ts4800-wdt";
+ syscon = <&syscon 0xe>;
+ timeout-sec = <10>;
+ };
+}
diff --git a/Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt b/Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt
new file mode 100644
index 000000000000..3d878184ec3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt
@@ -0,0 +1,19 @@
+Zodiac RAVE Watchdog Timer
+
+Required properties:
+- compatible: must be "zii,rave-wdt"
+- reg: i2c slave address of device, usually 0x38
+
+Optional Properties:
+- timeout-sec: Watchdog timeout value in seconds.
+- reset-duration-ms: Duration of the pulse generated when the watchdog times
+ out. Value in milliseconds.
+
+Example:
+
+ watchdog@38 {
+ compatible = "zii,rave-wdt";
+ reg = <0x38>;
+ timeout-sec = <30>;
+ reset-duration-ms = <30>;
+ };
diff --git a/Documentation/dmaengine/client.txt b/Documentation/dmaengine/client.txt
index 11fb87ff6cd0..9e33189745f0 100644
--- a/Documentation/dmaengine/client.txt
+++ b/Documentation/dmaengine/client.txt
@@ -22,25 +22,14 @@ The slave DMA usage consists of following steps:
Channel allocation is slightly different in the slave DMA context,
client drivers typically need a channel from a particular DMA
controller only and even in some cases a specific channel is desired.
- To request a channel dma_request_channel() API is used.
+ To request a channel dma_request_chan() API is used.
Interface:
- struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
- dma_filter_fn filter_fn,
- void *filter_param);
- where dma_filter_fn is defined as:
- typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+ struct dma_chan *dma_request_chan(struct device *dev, const char *name);
- The 'filter_fn' parameter is optional, but highly recommended for
- slave and cyclic channels as they typically need to obtain a specific
- DMA channel.
-
- When the optional 'filter_fn' parameter is NULL, dma_request_channel()
- simply returns the first channel that satisfies the capability mask.
-
- Otherwise, the 'filter_fn' routine will be called once for each free
- channel which has a capability in 'mask'. 'filter_fn' is expected to
- return 'true' when the desired DMA channel is found.
+ Which will find and return the 'name' DMA channel associated with the 'dev'
+ device. The association is done via DT, ACPI or board file based
+ dma_slave_map matching table.
A channel allocated via this interface is exclusive to the caller,
until dma_release_channel() is called.
@@ -128,7 +117,7 @@ The slave DMA usage consists of following steps:
transaction.
For cyclic DMA, a callback function may wish to terminate the
- DMA via dmaengine_terminate_all().
+ DMA via dmaengine_terminate_async().
Therefore, it is important that DMA engine drivers drop any
locks before calling the callback function which may cause a
@@ -166,12 +155,29 @@ The slave DMA usage consists of following steps:
Further APIs:
-1. int dmaengine_terminate_all(struct dma_chan *chan)
+1. int dmaengine_terminate_sync(struct dma_chan *chan)
+ int dmaengine_terminate_async(struct dma_chan *chan)
+ int dmaengine_terminate_all(struct dma_chan *chan) /* DEPRECATED */
This causes all activity for the DMA channel to be stopped, and may
discard data in the DMA FIFO which hasn't been fully transferred.
No callback functions will be called for any incomplete transfers.
+ Two variants of this function are available.
+
+ dmaengine_terminate_async() might not wait until the DMA has been fully
+ stopped or until any running complete callbacks have finished. But it is
+ possible to call dmaengine_terminate_async() from atomic context or from
+ within a complete callback. dmaengine_synchronize() must be called before it
+ is safe to free the memory accessed by the DMA transfer or free resources
+ accessed from within the complete callback.
+
+ dmaengine_terminate_sync() will wait for the transfer and any running
+ complete callbacks to finish before it returns. But the function must not be
+ called from atomic context or from within a complete callback.
+
+ dmaengine_terminate_all() is deprecated and should not be used in new code.
+
2. int dmaengine_pause(struct dma_chan *chan)
This pauses activity on the DMA channel without data loss.
@@ -197,3 +203,20 @@ Further APIs:
a running DMA channel. It is recommended that DMA engine users
pause or stop (via dmaengine_terminate_all()) the channel before
using this API.
+
+5. void dmaengine_synchronize(struct dma_chan *chan)
+
+ Synchronize the termination of the DMA channel to the current context.
+
+ This function should be used after dmaengine_terminate_async() to synchronize
+ the termination of the DMA channel to the current context. The function will
+ wait for the transfer and any running complete callbacks to finish before it
+ returns.
+
+ If dmaengine_terminate_async() is used to stop the DMA channel this function
+ must be called before it is safe to free memory accessed by previously
+ submitted descriptors or to free any resources accessed within the complete
+ callback of previously submitted descriptors.
+
+ The behavior of this function is undefined if dma_async_issue_pending() has
+ been called between dmaengine_terminate_async() and this function.
diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt
index 67d4ce4df109..122b7f4876bb 100644
--- a/Documentation/dmaengine/provider.txt
+++ b/Documentation/dmaengine/provider.txt
@@ -327,8 +327,24 @@ supported.
* device_terminate_all
- Aborts all the pending and ongoing transfers on the channel
- - This command should operate synchronously on the channel,
- terminating right away all the channels
+ - For aborted transfers the complete callback should not be called
+ - Can be called from atomic context or from within a complete
+ callback of a descriptor. Must not sleep. Drivers must be able
+ to handle this correctly.
+ - Termination may be asynchronous. The driver does not have to
+ wait until the currently active transfer has completely stopped.
+ See device_synchronize.
+
+ * device_synchronize
+ - Must synchronize the termination of a channel to the current
+ context.
+ - Must make sure that memory for previously submitted
+ descriptors is no longer accessed by the DMA controller.
+ - Must make sure that all complete callbacks for previously
+ submitted descriptors have finished running and none are
+ scheduled to run.
+ - May sleep.
+
Misc notes (stuff that should be documented, but don't really know
where to put them)
diff --git a/Documentation/features/vm/pmdp_splitting_flush/arch-support.txt b/Documentation/features/vm/pmdp_splitting_flush/arch-support.txt
deleted file mode 100644
index 26f74b457e0b..000000000000
--- a/Documentation/features/vm/pmdp_splitting_flush/arch-support.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Feature name: pmdp_splitting_flush
-# Kconfig: __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-# description: arch supports the pmdp_splitting_flush() VM API
-#
- -----------------------
- | arch |status|
- -----------------------
- | alpha: | TODO |
- | arc: | TODO |
- | arm: | ok |
- | arm64: | ok |
- | avr32: | TODO |
- | blackfin: | TODO |
- | c6x: | TODO |
- | cris: | TODO |
- | frv: | TODO |
- | h8300: | TODO |
- | hexagon: | TODO |
- | ia64: | TODO |
- | m32r: | TODO |
- | m68k: | TODO |
- | metag: | TODO |
- | microblaze: | TODO |
- | mips: | ok |
- | mn10300: | TODO |
- | nios2: | TODO |
- | openrisc: | TODO |
- | parisc: | TODO |
- | powerpc: | ok |
- | s390: | ok |
- | score: | TODO |
- | sh: | TODO |
- | sparc: | TODO |
- | tile: | TODO |
- | um: | TODO |
- | unicore32: | TODO |
- | x86: | ok |
- | xtensa: | TODO |
- -----------------------
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
index b102b436563e..e1c9f0849da6 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -102,7 +102,7 @@ background_gc=%s Turn on/off cleaning operations, namely garbage
collection, triggered in background when I/O subsystem is
idle. If background_gc=on, it will turn on the garbage
collection and if background_gc=off, garbage collection
- will be truned off. If background_gc=sync, it will turn
+ will be turned off. If background_gc=sync, it will turn
on synchronous garbage collection running in background.
Default value for this option is on. So garbage
collection is on by default.
@@ -145,10 +145,12 @@ extent_cache Enable an extent cache based on rb-tree, it can cache
as many as extent which map between contiguous logical
address and physical address per inode, resulting in
increasing the cache hit ratio. Set by default.
-noextent_cache Diable an extent cache based on rb-tree explicitly, see
+noextent_cache Disable an extent cache based on rb-tree explicitly, see
the above extent_cache mount option.
noinline_data Disable the inline data feature, inline data feature is
enabled by default.
+data_flush Enable data flushing before checkpoint in order to
+ persist data of regular and symlink.
================================================================================
DEBUGFS ENTRIES
@@ -192,7 +194,7 @@ Files in /sys/fs/f2fs/<devname>
policy for garbage collection. Setting gc_idle = 0
(default) will disable this option. Setting
gc_idle = 1 will select the Cost Benefit approach
- & setting gc_idle = 2 will select the greedy aproach.
+ & setting gc_idle = 2 will select the greedy approach.
reclaim_segments This parameter controls the number of prefree
segments to be reclaimed. If the number of prefree
@@ -298,7 +300,7 @@ The dump.f2fs shows the information of specific inode and dumps SSA and SIT to
file. Each file is dump_ssa and dump_sit.
The dump.f2fs is used to debug on-disk data structures of the f2fs filesystem.
-It shows on-disk inode information reconized by a given inode number, and is
+It shows on-disk inode information recognized by a given inode number, and is
able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and
./dump_sit respectively.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 0f88e6020487..f1b87d8aa2da 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -508,7 +508,11 @@ in your dentry operations instead.
[mandatory]
any symlink that might use page_follow_link_light/page_put_link() must
have inode_nohighmem(inode) called before anything might start playing with
- its pagecache.
+ its pagecache. No highmem pages should end up in the pagecache of such
+ symlinks. That includes any preseeding that might be done during symlink
+ creation. __page_symlink() will honour the mapping gfp flags, so once
+ you've done inode_nohighmem() it's safe to use, but if you allocate and
+ insert the page manually, make sure to use the right gfp flags.
--
[mandatory]
->follow_link() is replaced with ->get_link(); same API, except that
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 402ab99e409f..fde9fd06fa98 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -169,6 +169,9 @@ read the file /proc/PID/status:
VmLck: 0 kB
VmHWM: 476 kB
VmRSS: 476 kB
+ RssAnon: 352 kB
+ RssFile: 120 kB
+ RssShmem: 4 kB
VmData: 156 kB
VmStk: 88 kB
VmExe: 68 kB
@@ -231,14 +234,20 @@ Table 1-2: Contents of the status files (as of 4.1)
VmSize total program size
VmLck locked memory size
VmHWM peak resident set size ("high water mark")
- VmRSS size of memory portions
+ VmRSS size of memory portions. It contains the three
+ following parts (VmRSS = RssAnon + RssFile + RssShmem)
+ RssAnon size of resident anonymous memory
+ RssFile size of resident file mappings
+ RssShmem size of resident shmem memory (includes SysV shm,
+ mapping of tmpfs and shared anonymous mappings)
VmData size of data, stack, and text segments
VmStk size of data, stack, and text segments
VmExe size of text segment
VmLib size of shared library code
VmPTE size of page table entries
VmPMD size of second level page tables
- VmSwap size of swap usage (the number of referred swapents)
+ VmSwap amount of swap used by anonymous private data
+ (shmem swap usage is not included)
HugetlbPages size of hugetlb memory portions
Threads number of threads
SigQ number of signals queued/max. number for queue
@@ -265,7 +274,8 @@ Table 1-3: Contents of the statm files (as of 2.6.8-rc3)
Field Content
size total program size (pages) (same as VmSize in status)
resident size of memory portions (pages) (same as VmRSS in status)
- shared number of pages that are shared (i.e. backed by a file)
+ shared number of pages that are shared (i.e. backed by a file, same
+ as RssFile+RssShmem in status)
trs number of pages that are 'code' (not including libs; broken,
includes data segment)
lrs number of pages of library (always 0 on 2.6)
@@ -459,7 +469,10 @@ and a page is modified, the file page is replaced by a private anonymous copy.
hugetlbfs page which is *not* counted in "RSS" or "PSS" field for historical
reasons. And these are not included in {Shared,Private}_{Clean,Dirty} field.
"Swap" shows how much would-be-anonymous memory is also used, but out on swap.
-"SwapPss" shows proportional swap share of this mapping.
+For shmem mappings, "Swap" includes also the size of the mapped (and not
+replaced by copy-on-write) part of the underlying shmem object out on swap.
+"SwapPss" shows proportional swap share of this mapping. Unlike "Swap", this
+does not take into account swapped out page of underlying shmem objects.
"Locked" indicates whether the mapping is locked in memory or not.
"VmFlags" field deserves a separate description. This member represents the kernel
@@ -807,7 +820,7 @@ by migrate-type and finishes with details on how many page blocks of each
type exist.
If min_free_kbytes has been tuned correctly (recommendations made by hugeadm
-from libhugetlbfs http://sourceforge.net/projects/libhugetlbfs/), one can
+from libhugetlbfs https://github.com/libhugetlbfs/libhugetlbfs/), one can
make an estimate of the likely number of huge pages that can be allocated
at a given point in time. All the "Movable" blocks should be allocatable
unless memory has been mlock()'d. Some of the Reclaimable blocks should
@@ -842,6 +855,7 @@ Dirty: 968 kB
Writeback: 0 kB
AnonPages: 861800 kB
Mapped: 280372 kB
+Shmem: 644 kB
Slab: 284364 kB
SReclaimable: 159856 kB
SUnreclaim: 124508 kB
@@ -898,6 +912,7 @@ MemAvailable: An estimate of how much memory is available for starting new
AnonPages: Non-file backed pages mapped into userspace page tables
AnonHugePages: Non-file backed huge pages mapped into userspace page tables
Mapped: files which have been mmaped, such as libraries
+ Shmem: Total memory used by shared memory (shmem) and tmpfs
Slab: in-kernel data structures cache
SReclaimable: Part of Slab, that might be reclaimed, such as caches
SUnreclaim: Part of Slab, that cannot be reclaimed on memory pressure
diff --git a/Documentation/filesystems/sharedsubtree.txt b/Documentation/filesystems/sharedsubtree.txt
index 32a173dd3158..e3f4c778eb98 100644
--- a/Documentation/filesystems/sharedsubtree.txt
+++ b/Documentation/filesystems/sharedsubtree.txt
@@ -664,7 +664,7 @@ replicas continue to be exactly same.
if one rbind mounts a tree within the same subtree 'n' times
the number of mounts created is an exponential function of 'n'.
Having unbindable mount can help prune the unneeded bind
- mounts. Here is a example.
+ mounts. Here is an example.
step 1:
let's say the root tree has just two directories with
diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt
index 98ef55124158..d392e1505f17 100644
--- a/Documentation/filesystems/tmpfs.txt
+++ b/Documentation/filesystems/tmpfs.txt
@@ -17,10 +17,10 @@ RAM, where you have to create an ordinary filesystem on top. Ramdisks
cannot swap and you do not have the possibility to resize them.
Since tmpfs lives completely in the page cache and on swap, all tmpfs
-pages currently in memory will show up as cached. It will not show up
-as shared or something like that. Further on you can check the actual
-RAM+swap use of a tmpfs instance with df(1) and du(1).
-
+pages will be shown as "Shmem" in /proc/meminfo and "Shared" in
+free(1). Notice that these counters also include shared memory
+(shmem, see ipcs(1)). The most reliable way to get the count is
+using df(1) and du(1).
tmpfs has the following uses:
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index e000502fde20..05676fdacfe3 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -260,7 +260,7 @@ will be driven low.
To summarize:
-Function (example) active-low proporty physical line
+Function (example) active-low property physical line
gpiod_set_raw_value(desc, 0); don't care low
gpiod_set_raw_value(desc, 1); don't care high
gpiod_set_value(desc, 0); default (active-high) low
diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index 12a61948ec91..bbeec415f406 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -113,8 +113,8 @@ GPIO irqchips usually fall in one of two categories:
it will be threaded IRQ handler on -RT and hard IRQ handler on non-RT
(for example, see [3]).
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
- so IRQ core will complain if it will be called from IRQ handler wich is forced
- thread. The "fake?" raw lock can be used to W/A this problem:
+ so IRQ core will complain if it will be called from IRQ handler which is
+ forced thread. The "fake?" raw lock can be used to W/A this problem:
raw_spinlock_t wa_lock;
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
@@ -224,7 +224,7 @@ Real-Time compliance for GPIO IRQ chips
---------------------------------------
Any provider of irqchips needs to be carefully tailored to support Real Time
-preemption. It is desireable that all irqchips in the GPIO subsystem keep this
+preemption. It is desirable that all irqchips in the GPIO subsystem keep this
in mind and does the proper testing to assure they are real time-enabled.
So, pay attention on above " RT_FULL:" notes, please.
The following is a checklist to follow when preparing a driver for real
diff --git a/Documentation/gpio/drivers-on-gpio.txt b/Documentation/gpio/drivers-on-gpio.txt
index f6121328630f..14bf95a13bae 100644
--- a/Documentation/gpio/drivers-on-gpio.txt
+++ b/Documentation/gpio/drivers-on-gpio.txt
@@ -54,7 +54,7 @@ hardware descriptions such as device tree or ACPI:
drivers for the I2C devices on the bus like any other I2C bus driver.
- spi_gpio: drivers/spi/spi-gpio.c is used to drive an SPI bus (variable number
- of wires, atleast SCK and optionally MISO, MOSI and chip select lines) using
+ of wires, at least SCK and optionally MISO, MOSI and chip select lines) using
GPIO hammering (bitbang). It will appear as any other SPI bus on the system
and makes it possible to connect drivers for SPI devices on the bus like
any other SPI bus driver. For example any MMC/SD card can then be connected
@@ -75,7 +75,7 @@ hardware descriptions such as device tree or ACPI:
- gpio-wdt: drivers/watchdog/gpio_wdt.c is used to provide a watchdog timer
that will periodically "ping" a hardware connected to a GPIO line by toggling
- it from 1-to-0-to-1. If that hardware does not recieve its "ping"
+ it from 1-to-0-to-1. If that hardware does not receive its "ping"
periodically, it will reset the system.
- gpio-nand: drivers/mtd/nand/gpio.c is used to connect a NAND flash chip to
@@ -91,5 +91,5 @@ usually connected directly to the flash.
Use those instead of talking directly to the GPIOs using sysfs; they integrate
with kernel frameworks better than your userspace code could. Needless to say,
-just using the apropriate kernel drivers will simplify and speed up your
+just using the appropriate kernel drivers will simplify and speed up your
embedded hacking in particular by providing ready-made components.
diff --git a/Documentation/iio/iio_configfs.txt b/Documentation/iio/iio_configfs.txt
new file mode 100644
index 000000000000..f0add35cd52e
--- /dev/null
+++ b/Documentation/iio/iio_configfs.txt
@@ -0,0 +1,93 @@
+Industrial IIO configfs support
+
+1. Overview
+
+Configfs is a filesystem-based manager of kernel objects. IIO uses some
+objects that could be easily configured using configfs (e.g.: devices,
+triggers).
+
+See Documentation/filesystems/configfs/configfs.txt for more information
+about how configfs works.
+
+2. Usage
+
+In order to use configfs support in IIO we need to select it at compile
+time via CONFIG_IIO_CONFIGFS config option.
+
+Then, mount the configfs filesystem (usually under /config directory):
+
+$ mkdir /config
+$ mount -t configfs none /config
+
+At this point, all default IIO groups will be created and can be accessed
+under /config/iio. Next chapters will describe available IIO configuration
+objects.
+
+3. Software triggers
+
+One of the IIO default configfs groups is the "triggers" group. It is
+automagically accessible when the configfs is mounted and can be found
+under /config/iio/triggers.
+
+IIO software triggers implementation offers support for creating multiple
+trigger types. A new trigger type is usually implemented as a separate
+kernel module following the interface in include/linux/iio/sw_trigger.h:
+
+/*
+ * drivers/iio/trigger/iio-trig-sample.c
+ * sample kernel module implementing a new trigger type
+ */
+#include <linux/iio/sw_trigger.h>
+
+
+static struct iio_sw_trigger *iio_trig_sample_probe(const char *name)
+{
+ /*
+ * This allocates and registers an IIO trigger plus other
+ * trigger type specific initialization.
+ */
+}
+
+static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
+{
+ /*
+ * This undoes the actions in iio_trig_sample_probe
+ */
+}
+
+static const struct iio_sw_trigger_ops iio_trig_sample_ops = {
+ .probe = iio_trig_sample_probe,
+ .remove = iio_trig_sample_remove,
+};
+
+static struct iio_sw_trigger_type iio_trig_sample = {
+ .name = "trig-sample",
+ .owner = THIS_MODULE,
+ .ops = &iio_trig_sample_ops,
+};
+
+module_iio_sw_trigger_driver(iio_trig_sample);
+
+Each trigger type has its own directory under /config/iio/triggers. Loading
+iio-trig-sample module will create 'trig-sample' trigger type directory
+/config/iio/triggers/trig-sample.
+
+We support the following interrupt sources (trigger types):
+ * hrtimer, uses high resolution timers as interrupt source
+
+3.1 Hrtimer triggers creation and destruction
+
+Loading iio-trig-hrtimer module will register hrtimer trigger types allowing
+users to create hrtimer triggers under /config/iio/triggers/hrtimer.
+
+e.g:
+
+$ mkdir /config/triggers/hrtimer/instance1
+$ rmdir /config/triggers/hrtimer/instance1
+
+Each trigger can have one or more attributes specific to the trigger type.
+
+3.2 "hrtimer" trigger types attributes
+
+"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
+It does introduce the sampling_frequency attribute to trigger directory.
diff --git a/Documentation/ioctl/botching-up-ioctls.txt b/Documentation/ioctl/botching-up-ioctls.txt
index 45fe78c58019..cc30b14791cb 100644
--- a/Documentation/ioctl/botching-up-ioctls.txt
+++ b/Documentation/ioctl/botching-up-ioctls.txt
@@ -122,7 +122,7 @@ Time, Waiting and Missing it
----------------------------
GPUs do most everything asynchronously, so we have a need to time operations and
-wait for oustanding ones. This is really tricky business; at the moment none of
+wait for outstanding ones. This is really tricky business; at the moment none of
the ioctls supported by the drm/i915 get this fully right, which means there's
still tons more lessons to learn here.
@@ -146,7 +146,7 @@ still tons more lessons to learn here.
ioctl restartable relative timeouts tend to be too coarse and can
indefinitely extend your wait time due to rounding on each restart.
Especially if your reference clock is something really slow like the display
- frame counter. With a spec laywer hat on this isn't a bug since timeouts can
+ frame counter. With a spec lawyer hat on this isn't a bug since timeouts can
always be extended - but users will surely hate you if their neat animations
starts to stutter due to this.
@@ -176,7 +176,7 @@ entails its own little set of pitfalls:
* Ensure that you have sufficient insulation between different clients. By
default pick a private per-fd namespace which forces any sharing to be done
- explictly. Only go with a more global per-device namespace if the objects
+ explicitly. Only go with a more global per-device namespace if the objects
are truly device-unique. One counterexample in the drm modeset interfaces is
that the per-device modeset objects like connectors share a namespace with
framebuffer objects, which mostly are not shared at all. A separate
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index 5a0f2bdc2cf9..8d5465d3fdef 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -245,7 +245,7 @@ Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã®ä¸­ã«å«ã¾ã‚Œã‚‹ã€ãã‚Œã„ã«ã—ã€ä¿
自己å‚照方å¼ã§ã€ç´¢å¼•ãŒã¤ã„㟠web å½¢å¼ã§ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã‚’å‚ç…§ã™ã‚‹ã“ã¨ãŒ
ã§ãã¾ã™ã€‚ã“ã®æœ€æ–°ã®ç´ æ™´ã—ã„カーãƒãƒ«ã‚³ãƒ¼ãƒ‰ã®ãƒªãƒã‚¸ãƒˆãƒªã¯ä»¥ä¸‹ã§è¦‹ã¤ã‹ã‚Š
ã¾ã™-
- http://lxr.linux.no/+trees
+ http://lxr.free-electrons.com/
開発プロセス
-----------------------
@@ -366,7 +366,6 @@ http://patchwork.kernel.org/ ã§ãƒªã‚¹ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚
ã«å…¨ã‚µãƒ–システムツリーã‹ã‚‰ã»ã¼æ¯Žæ—¥ãƒ—ルã•ã‚Œã¦ã§ãる特別ãªãƒ†ã‚¹ãƒˆç”¨ã®ãƒª
ãƒã‚¸ãƒˆãƒªãŒå­˜åœ¨ã—ã¾ã™-
http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
- http://linux.f-seidel.de/linux-next/pmwiki/
ã“ã®ã‚„ã‚Šæ–¹ã«ã‚ˆã£ã¦ã€-next カーãƒãƒ«ã¯æ¬¡ã®ãƒžãƒ¼ã‚¸æ©Ÿä¼šã§ã©ã‚“ãªã‚‚ã®ãŒãƒ¡ã‚¤ãƒ³
ラインカーãƒãƒ«ã«ãƒžãƒ¼ã‚¸ã•ã‚Œã‚‹ã‹ã€ãŠãŠã¾ã‹ãªã®å±•æœ›ã‚’æä¾›ã—ã¾ã™ã€‚-next
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index 08913361e054..fe217c1c2f7f 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -631,7 +631,7 @@
between two versions of a file".
* Name: "Cross-Referencing Linux"
- URL: http://lxr.linux.no/source/
+ URL: http://lxr.free-electrons.com/
Keywords: Browsing source code.
Description: Another web-based Linux kernel source code browser.
Lots of cross references to variables and functions. You can see
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 1a8169ba29e6..3ea869d7a31c 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -608,6 +608,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
cut the overhead, others just disable the usage. So
only cgroup_disable=memory is actually worthy}
+ cgroup.memory= [KNL] Pass options to the cgroup memory controller.
+ Format: <string>
+ nosocket -- Disable socket memory accounting.
+
checkreqprot [SELINUX] Set initial checkreqprot flag value.
Format: { "0" | "1" }
See security/selinux/Kconfig help text.
@@ -730,16 +734,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
+ uart[8250],mmio16,<addr>[,options]
uart[8250],mmio32,<addr>[,options]
uart[8250],0x<addr>[,options]
Start an early, polled-mode console on the 8250/16550
UART at the specified I/O port or MMIO address,
switching to the matching ttyS device later.
MMIO inter-register address stride is either 8-bit
- (mmio) or 32-bit (mmio32).
- If none of [io|mmio|mmio32], <addr> is assumed to be
- equivalent to 'mmio'. 'options' are specified in the
- same format described for ttyS above; if unspecified,
+ (mmio), 16-bit (mmio16), or 32-bit (mmio32).
+ If none of [io|mmio|mmio16|mmio32], <addr> is assumed
+ to be equivalent to 'mmio'. 'options' are specified in
+ the same format described for ttyS above; if unspecified,
the h/w is not re-initialized.
hvc<n> Use the hypervisor console device <n>. This is for
@@ -1011,10 +1016,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
unspecified, the h/w is not initialized.
pl011,<addr>
+ pl011,mmio32,<addr>
Start an early, polled-mode console on a pl011 serial
port at the specified address. The pl011 serial port
must already be setup and configured. Options are not
- yet supported.
+ yet supported. If 'mmio32' is specified, then only
+ the driver will use only 32-bit accessors to read/write
+ the device registers.
msm_serial,<addr>
Start an early, polled-mode console on an msm serial
@@ -2584,8 +2592,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
notsc [BUGS=X86-32] Disable Time Stamp Counter
- nousb [USB] Disable the USB subsystem
-
nowatchdog [KNL] Disable both lockup detectors, i.e.
soft-lockup and NMI watchdog (hard-lockup).
@@ -2742,10 +2748,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
hardware access methods are allowed. Use this
if you experience crashes upon bootup and you
suspect they are caused by the BIOS.
- conf1 [X86] Force use of PCI Configuration
- Mechanism 1.
- conf2 [X86] Force use of PCI Configuration
- Mechanism 2.
+ conf1 [X86] Force use of PCI Configuration Access
+ Mechanism 1 (config address in IO port 0xCF8,
+ data in IO port 0xCFC, both 32-bit).
+ conf2 [X86] Force use of PCI Configuration Access
+ Mechanism 2 (IO port 0xCF8 is an 8-bit port for
+ the function, IO port 0xCFA, also 8-bit, sets
+ bus number. The config space is then accessed
+ through ports 0xC000-0xCFFF).
+ See http://wiki.osdev.org/PCI for more info
+ on the configuration access mechanisms.
noaer [PCIE] If the PCIEAER kernel config parameter is
enabled, this kernel boot option can be used to
disable the use of PCIE advanced error reporting.
@@ -2987,6 +2999,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
may be specified.
Format: <port>,<port>....
+ ppc_strict_facility_enable
+ [PPC] This option catches any kernel floating point,
+ Altivec, VSX and SPE outside of regions specifically
+ allowed (eg kernel_enable_fpu()/kernel_disable_fpu()).
+ There is some performance impact when enabling this.
+
print-fatal-signals=
[KNL] debug: print fatal signals
@@ -3059,9 +3077,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
raid= [HW,RAID]
See Documentation/md.txt.
- ramdisk_blocksize= [RAM]
- See Documentation/blockdev/ramdisk.txt.
-
ramdisk_size= [RAM] Sizes of RAM disks in kilobytes
See Documentation/blockdev/ramdisk.txt.
@@ -3900,6 +3915,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
usbcore.usbfs_snoop=
[USB] Set to log all usbfs traffic (default 0 = off).
+ usbcore.usbfs_snoop_max=
+ [USB] Maximum number of bytes to snoop in each URB
+ (default = 65536).
+
usbcore.blinkenlights=
[USB] Set to cycle leds on hubs (default 0 = off).
@@ -3920,6 +3939,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
USB_REQ_GET_DESCRIPTOR request in milliseconds
(default 5000 = 5.0 seconds).
+ usbcore.nousb [USB] Disable the USB subsystem
+
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.
diff --git a/Documentation/ko_KR/HOWTO b/Documentation/ko_KR/HOWTO
index dc2ff8f611e0..1aef53e6cb98 100644
--- a/Documentation/ko_KR/HOWTO
+++ b/Documentation/ko_KR/HOWTO
@@ -213,7 +213,7 @@ Documentation/DocBook/ 디렉토리 ë‚´ì—ì„œ 만들어지며 PDF, Postscript, H
ê²ƒì€ Linux Cross-Reference projectì´ë©° ê·¸ê²ƒì€ ìžê¸° 참조 ë°©ì‹ì´ë©°
소스코드를 ì¸ë±ìŠ¤ëœ 웹 페ì´ì§€ë“¤ì˜ 형태로 보여준다. ìµœì‹ ì˜ ë©‹ì§„ 커ë„
코드 저장소는 다ìŒì„ 통하여 참조할 수 있다.
- http://lxr.linux.no/+trees
+ http://lxr.free-electrons.com/
개발 프로세스
@@ -222,16 +222,16 @@ Documentation/DocBook/ 디렉토리 ë‚´ì—ì„œ 만들어지며 PDF, Postscript, H
리눅스 ì»¤ë„ ê°œë°œ 프로세스는 현재 몇몇 다른 ë©”ì¸ ì»¤ë„ "브랜치들"ê³¼
ì„œë¸Œì‹œìŠ¤í…œì— íŠ¹í™”ëœ ì»¤ë„ ë¸Œëžœì¹˜ë“¤ë¡œ 구성ëœë‹¤. 몇몇 다른 ë©”ì¸
ë¸Œëžœì¹˜ë“¤ì€ ë‹¤ìŒê³¼ 같다.
- - main 3.x ì»¤ë„ íŠ¸ë¦¬
- - 3.x.y - ì•ˆì •ëœ ì»¤ë„ íŠ¸ë¦¬
- - 3.x -git ì»¤ë„ íŒ¨ì¹˜ë“¤
+ - main 4.x ì»¤ë„ íŠ¸ë¦¬
+ - 4.x.y - ì•ˆì •ëœ ì»¤ë„ íŠ¸ë¦¬
+ - 4.x -git ì»¤ë„ íŒ¨ì¹˜ë“¤
- ì„œë¸Œì‹œìŠ¤í…œì„ ìœ„í•œ ì»¤ë„ íŠ¸ë¦¬ë“¤ê³¼ 패치들
- - 3.x - 통합 테스트를 위한 next ì»¤ë„ íŠ¸ë¦¬
+ - 4.x - 통합 테스트를 위한 next ì»¤ë„ íŠ¸ë¦¬
-3.x ì»¤ë„ íŠ¸ë¦¬
+4.x ì»¤ë„ íŠ¸ë¦¬
---------------
-3.x 커ë„ë“¤ì€ Linux Torvaldsê°€ 관리하며 kernel.orgì˜ pub/linux/kernel/v3.x/
+4.x 커ë„ë“¤ì€ Linux Torvaldsê°€ 관리하며 kernel.orgì˜ pub/linux/kernel/v4.x/
디렉토리ì—ì„œ ì°¸ì¡°ë  ìˆ˜ 있다.개발 프로세스는 다ìŒê³¼ 같다.
- 새로운 커ë„ì´ ë°°í¬ë˜ìžë§ˆìž 2ì£¼ì˜ ì‹œê°„ì´ ì£¼ì–´ì§„ë‹¤. ì´ ê¸°ê°„ë™ì€
ë©”ì¸í…Œì´ë„ˆë“¤ì€ í° diffë“¤ì„ Linusì—게 제출할 수 있다. 대개 ì´ íŒ¨ì¹˜ë“¤ì€
@@ -262,20 +262,20 @@ Andrew Mortonì˜ ê¸€ì´ ìžˆë‹¤.
ë²„ê·¸ì˜ ìƒí™©ì— ë”°ë¼ ë°°í¬ë˜ëŠ” 것ì´ì§€ 미리정해 ë†“ì€ ì‹œê°„ì— ë”°ë¼
ë°°í¬ë˜ëŠ” ê²ƒì€ ì•„ë‹ˆê¸° 때문ì´ë‹¤."
-3.x.y - 안정 ì»¤ë„ íŠ¸ë¦¬
+4.x.y - 안정 ì»¤ë„ íŠ¸ë¦¬
------------------------
-3 ìžë¦¬ 숫ìžë¡œ ì´ë£¨ì–´ì§„ ë²„ì ¼ì˜ ì»¤ë„ë“¤ì€ -stable 커ë„들ì´ë‹¤. ê·¸ê²ƒë“¤ì€ 3.x
+3 ìžë¦¬ 숫ìžë¡œ ì´ë£¨ì–´ì§„ ë²„ì ¼ì˜ ì»¤ë„ë“¤ì€ -stable 커ë„들ì´ë‹¤. ê·¸ê²ƒë“¤ì€ 4.x
커ë„ì—ì„œ ë°œê²¬ëœ í° íšŒê·€ë“¤ì´ë‚˜ 보안 문제들 중 비êµì  ìž‘ê³  중요한 수정들ì„
í¬í•¨í•œë‹¤.
ì´ê²ƒì€ 가장 ìµœê·¼ì˜ ì•ˆì •ì ì¸ 커ë„ì„ ì›í•˜ëŠ” 사용ìžì—게 추천ë˜ëŠ” 브랜치ì´ë©°,
개발/ì‹¤í—˜ì  ë²„ì ¼ì„ í…ŒìŠ¤íŠ¸í•˜ëŠ” ê²ƒì„ ë•ê³ ìž 하는 사용ìžë“¤ê³¼ëŠ” 별로 ê´€ë ¨ì´ ì—†ë‹¤.
-ì–´ë–¤ 3.x.y 커ë„ë„ ì‚¬ìš©í•  수 없다면 그때는 가장 ë†’ì€ ìˆ«ìžì˜ 3.x
+ì–´ë–¤ 4.x.y 커ë„ë„ ì‚¬ìš©í•  수 없다면 그때는 가장 ë†’ì€ ìˆ«ìžì˜ 4.x
커ë„ì´ í˜„ìž¬ì˜ ì•ˆì • 커ë„ì´ë‹¤.
-3.x.y는 "stable" 팀<stable@vger.kernel.org>ì— ì˜í•´ 관리ë˜ë©° ê±°ì˜ ë§¤ë²ˆ 격주로
+4.x.y는 "stable" 팀<stable@vger.kernel.org>ì— ì˜í•´ 관리ë˜ë©° ê±°ì˜ ë§¤ë²ˆ 격주로
ë°°í¬ëœë‹¤.
ì»¤ë„ íŠ¸ë¦¬ 문서들 ë‚´ì— Documentation/stable_kernel_rules.txt 파ì¼ì€ ì–´ë–¤
@@ -283,7 +283,7 @@ Andrew Mortonì˜ ê¸€ì´ ìžˆë‹¤.
진행ë˜ëŠ”지를 설명한다.
-3.x -git 패치들
+4.x -git 패치들
------------------
git 저장소(그러므로 -gitì´ë¼ëŠ” ì´ë¦„ì´ ë¶™ìŒ)ì—는 날마다 관리ë˜ëŠ” Linusì˜
ì»¤ë„ íŠ¸ë¦¬ì˜ snapshot ë“¤ì´ ìžˆë‹¤. ì´ íŒ¨ì¹˜ë“¤ì€ ì¼ë°˜ì ìœ¼ë¡œ 날마다 ë°°í¬ë˜ë©°
@@ -312,13 +312,12 @@ Linusì˜ íŠ¸ë¦¬ì˜ í˜„ìž¬ ìƒíƒœë¥¼ 나타낸다. ì´ íŒ¨ì¹˜ë“¤ì€ ì •ìƒì ì¸ì
ëŒ€ë¶€ë¶„ì˜ ì´ëŸ¬í•œ patchwork 사ì´íŠ¸ëŠ” http://patchwork.kernel.org/ ë˜ëŠ”
http://patchwork.ozlabs.org/ ì— ë‚˜ì—´ë˜ì–´ 있다.
-3.x - 통합 테스트를 위한 next ì»¤ë„ íŠ¸ë¦¬
+4.x - 통합 테스트를 위한 next ì»¤ë„ íŠ¸ë¦¬
-----------------------------------------
-서브시스템 íŠ¸ë¦¬ë“¤ì˜ ë³€ê²½ì‚¬í•­ë“¤ì€ mainline 3.x 트리로 들어오기 ì „ì— í†µí•©
+서브시스템 íŠ¸ë¦¬ë“¤ì˜ ë³€ê²½ì‚¬í•­ë“¤ì€ mainline 4.x 트리로 들어오기 ì „ì— í†µí•©
테스트를 ê±°ì³ì•¼ 한다. ì´ëŸ° 목ì ìœ¼ë¡œ, 모든 서브시스템 íŠ¸ë¦¬ì˜ ë³€ê²½ì‚¬í•­ì„ ê±°ì˜
ë§¤ì¼ ë°›ì•„ê°€ëŠ” 특수한 테스트 저장소가 존재한다:
http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
- http://linux.f-seidel.de/linux-next/pmwiki/
ì´ëŸ° ì‹ìœ¼ë¡œ, -next 커ë„ì„ í†µí•´ ë‹¤ìŒ ë¨¸ì§€ ê¸°ê°„ì— ë©”ì¸ë¼ì¸ 커ë„ì— ì–´ë–¤ 변경ì´
가해질 것ì¸ì§€ 간략히 ì•Œ 수 있다. 모험심 ê°•í•œ 테스터ë¼ë©´ -next 커ë„ì—ì„œ 테스트를
diff --git a/Documentation/md-cluster.txt b/Documentation/md-cluster.txt
index 1b794369e03a..c100c7163507 100644
--- a/Documentation/md-cluster.txt
+++ b/Documentation/md-cluster.txt
@@ -3,7 +3,7 @@ The cluster MD is a shared-device RAID for a cluster.
1. On-disk format
-Separate write-intent-bitmap are used for each cluster node.
+Separate write-intent-bitmaps are used for each cluster node.
The bitmaps record all writes that may have been started on that node,
and may not yet have finished. The on-disk layout is:
@@ -14,117 +14,161 @@ and may not yet have finished. The on-disk layout is:
| bm super[2] + bits | bm bits [2, contd] | bm super[3] + bits |
| bm bits [3, contd] | | |
-During "normal" functioning we assume the filesystem ensures that only one
-node writes to any given block at a time, so a write
-request will
+During "normal" functioning we assume the filesystem ensures that only
+one node writes to any given block at a time, so a write request will
+
- set the appropriate bit (if not already set)
- commit the write to all mirrors
- schedule the bit to be cleared after a timeout.
-Reads are just handled normally. It is up to the filesystem to
-ensure one node doesn't read from a location where another node (or the same
+Reads are just handled normally. It is up to the filesystem to ensure
+one node doesn't read from a location where another node (or the same
node) is writing.
2. DLM Locks for management
-There are two locks for managing the device:
+There are three groups of locks for managing the device:
2.1 Bitmap lock resource (bm_lockres)
- The bm_lockres protects individual node bitmaps. They are named in the
- form bitmap001 for node 1, bitmap002 for node and so on. When a node
- joins the cluster, it acquires the lock in PW mode and it stays so
- during the lifetime the node is part of the cluster. The lock resource
- number is based on the slot number returned by the DLM subsystem. Since
- DLM starts node count from one and bitmap slots start from zero, one is
- subtracted from the DLM slot number to arrive at the bitmap slot number.
+ The bm_lockres protects individual node bitmaps. They are named in
+ the form bitmap000 for node 1, bitmap001 for node 2 and so on. When a
+ node joins the cluster, it acquires the lock in PW mode and it stays
+ so during the lifetime the node is part of the cluster. The lock
+ resource number is based on the slot number returned by the DLM
+ subsystem. Since DLM starts node count from one and bitmap slots
+ start from zero, one is subtracted from the DLM slot number to arrive
+ at the bitmap slot number.
+
+ The LVB of the bitmap lock for a particular node records the range
+ of sectors that are being re-synced by that node. No other
+ node may write to those sectors. This is used when a new nodes
+ joins the cluster.
+
+2.2 Message passing locks
+
+ Each node has to communicate with other nodes when starting or ending
+ resync, and for metadata superblock updates. This communication is
+ managed through three locks: "token", "message", and "ack", together
+ with the Lock Value Block (LVB) of one of the "message" lock.
+
+2.3 new-device management
+
+ A single lock: "no-new-dev" is used to co-ordinate the addition of
+ new devices - this must be synchronized across the array.
+ Normally all nodes hold a concurrent-read lock on this device.
3. Communication
-Each node has to communicate with other nodes when starting or ending
-resync, and metadata superblock updates.
+ Messages can be broadcast to all nodes, and the sender waits for all
+ other nodes to acknowledge the message before proceeding. Only one
+ message can be processed at a time.
3.1 Message Types
- There are 3 types, of messages which are passed
+ There are six types of messages which are passed:
- 3.1.1 METADATA_UPDATED: informs other nodes that the metadata has been
- updated, and the node must re-read the md superblock. This is performed
- synchronously.
+ 3.1.1 METADATA_UPDATED: informs other nodes that the metadata has
+ been updated, and the node must re-read the md superblock. This is
+ performed synchronously. It is primarily used to signal device
+ failure.
- 3.1.2 RESYNC: informs other nodes that a resync is initiated or ended
- so that each node may suspend or resume the region.
+ 3.1.2 RESYNCING: informs other nodes that a resync is initiated or
+ ended so that each node may suspend or resume the region. Each
+ RESYNCING message identifies a range of the devices that the
+ sending node is about to resync. This over-rides any pervious
+ notification from that node: only one ranged can be resynced at a
+ time per-node.
+
+ 3.1.3 NEWDISK: informs other nodes that a device is being added to
+ the array. Message contains an identifier for that device. See
+ below for further details.
+
+ 3.1.4 REMOVE: A failed or spare device is being removed from the
+ array. The slot-number of the device is included in the message.
+
+ 3.1.5 RE_ADD: A failed device is being re-activated - the assumption
+ is that it has been determined to be working again.
+
+ 3.1.6 BITMAP_NEEDS_SYNC: if a node is stopped locally but the bitmap
+ isn't clean, then another node is informed to take the ownership of
+ resync.
3.2 Communication mechanism
The DLM LVB is used to communicate within nodes of the cluster. There
are three resources used for the purpose:
- 3.2.1 Token: The resource which protects the entire communication
+ 3.2.1 token: The resource which protects the entire communication
system. The node having the token resource is allowed to
communicate.
- 3.2.2 Message: The lock resource which carries the data to
+ 3.2.2 message: The lock resource which carries the data to
communicate.
- 3.2.3 Ack: The resource, acquiring which means the message has been
+ 3.2.3 ack: The resource, acquiring which means the message has been
acknowledged by all nodes in the cluster. The BAST of the resource
- is used to inform the receive node that a node wants to communicate.
+ is used to inform the receiving node that a node wants to
+ communicate.
The algorithm is:
- 1. receive status
+ 1. receive status - all nodes have concurrent-reader lock on "ack".
- sender receiver receiver
- ACK:CR ACK:CR ACK:CR
+ sender receiver receiver
+ "ack":CR "ack":CR "ack":CR
- 2. sender get EX of TOKEN
- sender get EX of MESSAGE
+ 2. sender get EX on "token"
+ sender get EX on "message"
sender receiver receiver
- TOKEN:EX ACK:CR ACK:CR
- MESSAGE:EX
- ACK:CR
+ "token":EX "ack":CR "ack":CR
+ "message":EX
+ "ack":CR
- Sender checks that it still needs to send a message. Messages received
- or other events that happened while waiting for the TOKEN may have made
- this message inappropriate or redundant.
+ Sender checks that it still needs to send a message. Messages
+ received or other events that happened while waiting for the
+ "token" may have made this message inappropriate or redundant.
- 3. sender write LVB.
- sender down-convert MESSAGE from EX to CW
- sender try to get EX of ACK
- [ wait until all receiver has *processed* the MESSAGE ]
+ 3. sender writes LVB.
+ sender down-convert "message" from EX to CW
+ sender try to get EX of "ack"
+ [ wait until all receivers have *processed* the "message" ]
- [ triggered by bast of ACK ]
- receiver get CR of MESSAGE
+ [ triggered by bast of "ack" ]
+ receiver get CR on "message"
receiver read LVB
receiver processes the message
[ wait finish ]
- receiver release ACK
-
- sender receiver receiver
- TOKEN:EX MESSAGE:CR MESSAGE:CR
- MESSAGE:CR
- ACK:EX
-
- 4. triggered by grant of EX on ACK (indicating all receivers have processed
- message)
- sender down-convert ACK from EX to CR
- sender release MESSAGE
- sender release TOKEN
- receiver upconvert to PR of MESSAGE
- receiver get CR of ACK
- receiver release MESSAGE
+ receiver releases "ack"
+ receiver tries to get PR on "message"
+
+ sender receiver receiver
+ "token":EX "message":CR "message":CR
+ "message":CW
+ "ack":EX
+
+ 4. triggered by grant of EX on "ack" (indicating all receivers
+ have processed message)
+ sender down-converts "ack" from EX to CR
+ sender releases "message"
+ sender releases "token"
+ receiver upconvert to PR on "message"
+ receiver get CR of "ack"
+ receiver release "message"
sender receiver receiver
- ACK:CR ACK:CR ACK:CR
+ "ack":CR "ack":CR "ack":CR
4. Handling Failures
4.1 Node Failure
- When a node fails, the DLM informs the cluster with the slot. The node
- starts a cluster recovery thread. The cluster recovery thread:
+
+ When a node fails, the DLM informs the cluster with the slot
+ number. The node starts a cluster recovery thread. The cluster
+ recovery thread:
+
- acquires the bitmap<number> lock of the failed node
- opens the bitmap
- reads the bitmap of the failed node
@@ -132,45 +176,143 @@ The algorithm is:
- cleans the bitmap of the failed node
- releases bitmap<number> lock of the failed node
- initiates resync of the bitmap on the current node
+ md_check_recovery is invoked within recover_bitmaps,
+ then md_check_recovery -> metadata_update_start/finish,
+ it will lock the communication by lock_comm.
+ Which means when one node is resyncing it blocks all
+ other nodes from writing anywhere on the array.
- The resync process, is the regular md resync. However, in a clustered
+ The resync process is the regular md resync. However, in a clustered
environment when a resync is performed, it needs to tell other nodes
of the areas which are suspended. Before a resync starts, the node
- send out RESYNC_START with the (lo,hi) range of the area which needs
- to be suspended. Each node maintains a suspend_list, which contains
- the list of ranges which are currently suspended. On receiving
- RESYNC_START, the node adds the range to the suspend_list. Similarly,
- when the node performing resync finishes, it send RESYNC_FINISHED
- to other nodes and other nodes remove the corresponding entry from
- the suspend_list.
+ send out RESYNCING with the (lo,hi) range of the area which needs to
+ be suspended. Each node maintains a suspend_list, which contains the
+ list of ranges which are currently suspended. On receiving RESYNCING,
+ the node adds the range to the suspend_list. Similarly, when the node
+ performing resync finishes, it sends RESYNCING with an empty range to
+ other nodes and other nodes remove the corresponding entry from the
+ suspend_list.
- A helper function, should_suspend() can be used to check if a particular
- I/O range should be suspended or not.
+ A helper function, ->area_resyncing() can be used to check if a
+ particular I/O range should be suspended or not.
4.2 Device Failure
+
Device failures are handled and communicated with the metadata update
- routine.
+ routine. When a node detects a device failure it does not allow
+ any further writes to that device until the failure has been
+ acknowledged by all other nodes.
5. Adding a new Device
-For adding a new device, it is necessary that all nodes "see" the new device
-to be added. For this, the following algorithm is used:
+
+ For adding a new device, it is necessary that all nodes "see" the new
+ device to be added. For this, the following algorithm is used:
1. Node 1 issues mdadm --manage /dev/mdX --add /dev/sdYY which issues
- ioctl(ADD_NEW_DISC with disc.state set to MD_DISK_CLUSTER_ADD)
- 2. Node 1 sends NEWDISK with uuid and slot number
+ ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CLUSTER_ADD)
+ 2. Node 1 sends a NEWDISK message with uuid and slot number
3. Other nodes issue kobject_uevent_env with uuid and slot number
(Steps 4,5 could be a udev rule)
4. In userspace, the node searches for the disk, perhaps
using blkid -t SUB_UUID=""
- 5. Other nodes issue either of the following depending on whether the disk
- was found:
+ 5. Other nodes issue either of the following depending on whether
+ the disk was found:
ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CANDIDATE and
- disc.number set to slot number)
+ disc.number set to slot number)
ioctl(CLUSTERED_DISK_NACK)
- 6. Other nodes drop lock on no-new-devs (CR) if device is found
- 7. Node 1 attempts EX lock on no-new-devs
- 8. If node 1 gets the lock, it sends METADATA_UPDATED after unmarking the disk
- as SpareLocal
- 9. If not (get no-new-dev lock), it fails the operation and sends METADATA_UPDATED
- 10. Other nodes get the information whether a disk is added or not
- by the following METADATA_UPDATED.
+ 6. Other nodes drop lock on "no-new-devs" (CR) if device is found
+ 7. Node 1 attempts EX lock on "no-new-dev"
+ 8. If node 1 gets the lock, it sends METADATA_UPDATED after
+ unmarking the disk as SpareLocal
+ 9. If not (get "no-new-dev" lock), it fails the operation and sends
+ METADATA_UPDATED.
+ 10. Other nodes get the information whether a disk is added or not
+ by the following METADATA_UPDATED.
+
+6. Module interface.
+
+ There are 17 call-backs which the md core can make to the cluster
+ module. Understanding these can give a good overview of the whole
+ process.
+
+6.1 join(nodes) and leave()
+
+ These are called when an array is started with a clustered bitmap,
+ and when the array is stopped. join() ensures the cluster is
+ available and initializes the various resources.
+ Only the first 'nodes' nodes in the cluster can use the array.
+
+6.2 slot_number()
+
+ Reports the slot number advised by the cluster infrastructure.
+ Range is from 0 to nodes-1.
+
+6.3 resync_info_update()
+
+ This updates the resync range that is stored in the bitmap lock.
+ The starting point is updated as the resync progresses. The
+ end point is always the end of the array.
+ It does *not* send a RESYNCING message.
+
+6.4 resync_start(), resync_finish()
+
+ These are called when resync/recovery/reshape starts or stops.
+ They update the resyncing range in the bitmap lock and also
+ send a RESYNCING message. resync_start reports the whole
+ array as resyncing, resync_finish reports none of it.
+
+ resync_finish() also sends a BITMAP_NEEDS_SYNC message which
+ allows some other node to take over.
+
+6.5 metadata_update_start(), metadata_update_finish(),
+ metadata_update_cancel().
+
+ metadata_update_start is used to get exclusive access to
+ the metadata. If a change is still needed once that access is
+ gained, metadata_update_finish() will send a METADATA_UPDATE
+ message to all other nodes, otherwise metadata_update_cancel()
+ can be used to release the lock.
+
+6.6 area_resyncing()
+
+ This combines two elements of functionality.
+
+ Firstly, it will check if any node is currently resyncing
+ anything in a given range of sectors. If any resync is found,
+ then the caller will avoid writing or read-balancing in that
+ range.
+
+ Secondly, while node recovery is happening it reports that
+ all areas are resyncing for READ requests. This avoids races
+ between the cluster-filesystem and the cluster-RAID handling
+ a node failure.
+
+6.7 add_new_disk_start(), add_new_disk_finish(), new_disk_ack()
+
+ These are used to manage the new-disk protocol described above.
+ When a new device is added, add_new_disk_start() is called before
+ it is bound to the array and, if that succeeds, add_new_disk_finish()
+ is called the device is fully added.
+
+ When a device is added in acknowledgement to a previous
+ request, or when the device is declared "unavailable",
+ new_disk_ack() is called.
+
+6.8 remove_disk()
+
+ This is called when a spare or failed device is removed from
+ the array. It causes a REMOVE message to be send to other nodes.
+
+6.9 gather_bitmaps()
+
+ This sends a RE_ADD message to all other nodes and then
+ gathers bitmap information from all bitmaps. This combined
+ bitmap is then used to recovery the re-added device.
+
+6.10 lock_all_bitmaps() and unlock_all_bitmaps()
+
+ These are called when change bitmap to none. If a node plans
+ to clear the cluster raid's bitmap, it need to make sure no other
+ nodes are using the raid which is achieved by lock all bitmap
+ locks within the cluster, and also those locks are unlocked
+ accordingly.
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
deleted file mode 100644
index f552a75c0e70..000000000000
--- a/Documentation/media-framework.txt
+++ /dev/null
@@ -1,372 +0,0 @@
-Linux kernel media framework
-============================
-
-This document describes the Linux kernel media framework, its data structures,
-functions and their usage.
-
-
-Introduction
-------------
-
-The media controller API is documented in DocBook format in
-Documentation/DocBook/media/v4l/media-controller.xml. This document will focus
-on the kernel-side implementation of the media framework.
-
-
-Abstract media device model
----------------------------
-
-Discovering a device internal topology, and configuring it at runtime, is one
-of the goals of the media framework. To achieve this, hardware devices are
-modelled as an oriented graph of building blocks called entities connected
-through pads.
-
-An entity is a basic media hardware building block. It can correspond to
-a large variety of logical blocks such as physical hardware devices
-(CMOS sensor for instance), logical hardware devices (a building block
-in a System-on-Chip image processing pipeline), DMA channels or physical
-connectors.
-
-A pad is a connection endpoint through which an entity can interact with
-other entities. Data (not restricted to video) produced by an entity
-flows from the entity's output to one or more entity inputs. Pads should
-not be confused with physical pins at chip boundaries.
-
-A link is a point-to-point oriented connection between two pads, either
-on the same entity or on different entities. Data flows from a source
-pad to a sink pad.
-
-
-Media device
-------------
-
-A media device is represented by a struct media_device instance, defined in
-include/media/media-device.h. Allocation of the structure is handled by the
-media device driver, usually by embedding the media_device instance in a
-larger driver-specific structure.
-
-Drivers register media device instances by calling
-
- media_device_register(struct media_device *mdev);
-
-The caller is responsible for initializing the media_device structure before
-registration. The following fields must be set:
-
- - dev must point to the parent device (usually a pci_dev, usb_interface or
- platform_device instance).
-
- - model must be filled with the device model name as a NUL-terminated UTF-8
- string. The device/model revision must not be stored in this field.
-
-The following fields are optional:
-
- - serial is a unique serial number stored as a NUL-terminated ASCII string.
- The field is big enough to store a GUID in text form. If the hardware
- doesn't provide a unique serial number this field must be left empty.
-
- - bus_info represents the location of the device in the system as a
- NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
- "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
- the usb_make_path() function must be used. This field is used by
- applications to distinguish between otherwise identical devices that don't
- provide a serial number.
-
- - hw_revision is the hardware device revision in a driver-specific format.
- When possible the revision should be formatted with the KERNEL_VERSION
- macro.
-
- - driver_version is formatted with the KERNEL_VERSION macro. The version
- minor must be incremented when new features are added to the userspace API
- without breaking binary compatibility. The version major must be
- incremented when binary compatibility is broken.
-
-Upon successful registration a character device named media[0-9]+ is created.
-The device major and minor numbers are dynamic. The model name is exported as
-a sysfs attribute.
-
-Drivers unregister media device instances by calling
-
- media_device_unregister(struct media_device *mdev);
-
-Unregistering a media device that hasn't been registered is *NOT* safe.
-
-
-Entities, pads and links
-------------------------
-
-- Entities
-
-Entities are represented by a struct media_entity instance, defined in
-include/media/media-entity.h. The structure is usually embedded into a
-higher-level structure, such as a v4l2_subdev or video_device instance,
-although drivers can allocate entities directly.
-
-Drivers initialize entities by calling
-
- media_entity_init(struct media_entity *entity, u16 num_pads,
- struct media_pad *pads, u16 extra_links);
-
-The media_entity name, type, flags, revision and group_id fields can be
-initialized before or after calling media_entity_init. Entities embedded in
-higher-level standard structures can have some of those fields set by the
-higher-level framework.
-
-As the number of pads is known in advance, the pads array is not allocated
-dynamically but is managed by the entity driver. Most drivers will embed the
-pads array in a driver-specific structure, avoiding dynamic allocation.
-
-Drivers must set the direction of every pad in the pads array before calling
-media_entity_init. The function will initialize the other pads fields.
-
-Unlike the number of pads, the total number of links isn't always known in
-advance by the entity driver. As an initial estimate, media_entity_init
-pre-allocates a number of links equal to the number of pads plus an optional
-number of extra links. The links array will be reallocated if it grows beyond
-the initial estimate.
-
-Drivers register entities with a media device by calling
-
- media_device_register_entity(struct media_device *mdev,
- struct media_entity *entity);
-
-Entities are identified by a unique positive integer ID. Drivers can provide an
-ID by filling the media_entity id field prior to registration, or request the
-media controller framework to assign an ID automatically. Drivers that provide
-IDs manually must ensure that all IDs are unique. IDs are not guaranteed to be
-contiguous even when they are all assigned automatically by the framework.
-
-Drivers unregister entities by calling
-
- media_device_unregister_entity(struct media_entity *entity);
-
-Unregistering an entity will not change the IDs of the other entities, and the
-ID will never be reused for a newly registered entity.
-
-When a media device is unregistered, all its entities are unregistered
-automatically. No manual entities unregistration is then required.
-
-Drivers free resources associated with an entity by calling
-
- media_entity_cleanup(struct media_entity *entity);
-
-This function must be called during the cleanup phase after unregistering the
-entity. Note that the media_entity instance itself must be freed explicitly by
-the driver if required.
-
-Entities have flags that describe the entity capabilities and state.
-
- MEDIA_ENT_FL_DEFAULT indicates the default entity for a given type.
- This can be used to report the default audio and video devices or the
- default camera sensor.
-
-Logical entity groups can be defined by setting the group ID of all member
-entities to the same non-zero value. An entity group serves no purpose in the
-kernel, but is reported to userspace during entities enumeration. The group_id
-field belongs to the media device driver and must not by touched by entity
-drivers.
-
-Media device drivers should define groups if several entities are logically
-bound together. Example usages include reporting
-
- - ALSA, VBI and video nodes that carry the same media stream
- - lens and flash controllers associated with a sensor
-
-- Pads
-
-Pads are represented by a struct media_pad instance, defined in
-include/media/media-entity.h. Each entity stores its pads in a pads array
-managed by the entity driver. Drivers usually embed the array in a
-driver-specific structure.
-
-Pads are identified by their entity and their 0-based index in the pads array.
-Both information are stored in the media_pad structure, making the media_pad
-pointer the canonical way to store and pass link references.
-
-Pads have flags that describe the pad capabilities and state.
-
- MEDIA_PAD_FL_SINK indicates that the pad supports sinking data.
- MEDIA_PAD_FL_SOURCE indicates that the pad supports sourcing data.
-
-One and only one of MEDIA_PAD_FL_SINK and MEDIA_PAD_FL_SOURCE must be set for
-each pad.
-
-- Links
-
-Links are represented by a struct media_link instance, defined in
-include/media/media-entity.h. Each entity stores all links originating at or
-targeting any of its pads in a links array. A given link is thus stored
-twice, once in the source entity and once in the target entity. The array is
-pre-allocated and grows dynamically as needed.
-
-Drivers create links by calling
-
- media_entity_create_link(struct media_entity *source, u16 source_pad,
- struct media_entity *sink, u16 sink_pad,
- u32 flags);
-
-An entry in the link array of each entity is allocated and stores pointers
-to source and sink pads.
-
-Links have flags that describe the link capabilities and state.
-
- MEDIA_LNK_FL_ENABLED indicates that the link is enabled and can be used
- to transfer media data. When two or more links target a sink pad, only
- one of them can be enabled at a time.
- MEDIA_LNK_FL_IMMUTABLE indicates that the link enabled state can't be
- modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
- MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
- enabled.
-
-
-Graph traversal
----------------
-
-The media framework provides APIs to iterate over entities in a graph.
-
-To iterate over all entities belonging to a media device, drivers can use the
-media_device_for_each_entity macro, defined in include/media/media-device.h.
-
- struct media_entity *entity;
-
- media_device_for_each_entity(entity, mdev) {
- /* entity will point to each entity in turn */
- ...
- }
-
-Drivers might also need to iterate over all entities in a graph that can be
-reached only through enabled links starting at a given entity. The media
-framework provides a depth-first graph traversal API for that purpose.
-
-Note that graphs with cycles (whether directed or undirected) are *NOT*
-supported by the graph traversal API. To prevent infinite loops, the graph
-traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
-currently defined as 16.
-
-Drivers initiate a graph traversal by calling
-
- media_entity_graph_walk_start(struct media_entity_graph *graph,
- struct media_entity *entity);
-
-The graph structure, provided by the caller, is initialized to start graph
-traversal at the given entity.
-
-Drivers can then retrieve the next entity by calling
-
- media_entity_graph_walk_next(struct media_entity_graph *graph);
-
-When the graph traversal is complete the function will return NULL.
-
-Graph traversal can be interrupted at any moment. No cleanup function call is
-required and the graph structure can be freed normally.
-
-Helper functions can be used to find a link between two given pads, or a pad
-connected to another pad through an enabled link
-
- media_entity_find_link(struct media_pad *source,
- struct media_pad *sink);
-
- media_entity_remote_pad(struct media_pad *pad);
-
-Refer to the kerneldoc documentation for more information.
-
-
-Use count and power handling
-----------------------------
-
-Due to the wide differences between drivers regarding power management needs,
-the media controller does not implement power management. However, the
-media_entity structure includes a use_count field that media drivers can use to
-track the number of users of every entity for power management needs.
-
-The use_count field is owned by media drivers and must not be touched by entity
-drivers. Access to the field must be protected by the media device graph_mutex
-lock.
-
-
-Links setup
------------
-
-Link properties can be modified at runtime by calling
-
- media_entity_setup_link(struct media_link *link, u32 flags);
-
-The flags argument contains the requested new link flags.
-
-The only configurable property is the ENABLED link flag to enable/disable a
-link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
-
-When a link is enabled or disabled, the media framework calls the
-link_setup operation for the two entities at the source and sink of the link,
-in that order. If the second link_setup call fails, another link_setup call is
-made on the first entity to restore the original link flags.
-
-Media device drivers can be notified of link setup operations by setting the
-media_device::link_notify pointer to a callback function. If provided, the
-notification callback will be called before enabling and after disabling
-links.
-
-Entity drivers must implement the link_setup operation if any of their links
-is non-immutable. The operation must either configure the hardware or store
-the configuration information to be applied later.
-
-Link configuration must not have any side effect on other links. If an enabled
-link at a sink pad prevents another link at the same pad from being enabled,
-the link_setup operation must return -EBUSY and can't implicitly disable the
-first enabled link.
-
-
-Pipelines and media streams
----------------------------
-
-When starting streaming, drivers must notify all entities in the pipeline to
-prevent link states from being modified during streaming by calling
-
- media_entity_pipeline_start(struct media_entity *entity,
- struct media_pipeline *pipe);
-
-The function will mark all entities connected to the given entity through
-enabled links, either directly or indirectly, as streaming.
-
-The media_pipeline instance pointed to by the pipe argument will be stored in
-every entity in the pipeline. Drivers should embed the media_pipeline structure
-in higher-level pipeline structures and can then access the pipeline through
-the media_entity pipe field.
-
-Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
-be identical for all nested calls to the function.
-
-media_entity_pipeline_start() may return an error. In that case, it will
-clean up any of the changes it did by itself.
-
-When stopping the stream, drivers must notify the entities with
-
- media_entity_pipeline_stop(struct media_entity *entity);
-
-If multiple calls to media_entity_pipeline_start() have been made the same
-number of media_entity_pipeline_stop() calls are required to stop streaming. The
-media_entity pipe field is reset to NULL on the last nested stop call.
-
-Link configuration will fail with -EBUSY by default if either end of the link is
-a streaming entity. Links that can be modified while streaming must be marked
-with the MEDIA_LNK_FL_DYNAMIC flag.
-
-If other operations need to be disallowed on streaming entities (such as
-changing entities configuration parameters) drivers can explicitly check the
-media_entity stream_count field to find out if an entity is streaming. This
-operation must be done with the media_device graph_mutex held.
-
-
-Link validation
----------------
-
-Link validation is performed by media_entity_pipeline_start() for any
-entity which has sink pads in the pipeline. The
-media_entity::link_validate() callback is used for that purpose. In
-link_validate() callback, entity driver should check that the properties of
-the source pad of the connected entity and its own sink pad match. It is up
-to the type of the entity (and in the end, the properties of the hardware)
-what matching actually means.
-
-Subsystems should facilitate link validation by providing subsystem specific
-helper functions to provide easy access for commonly needed information, and
-in the end provide a way to use driver-specific callbacks.
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index a61be39c7b51..904ee42d078e 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -1655,17 +1655,18 @@ macro is a good place to start looking.
SMP memory barriers are reduced to compiler barriers on uniprocessor compiled
systems because it is assumed that a CPU will appear to be self-consistent,
and will order overlapping accesses correctly with respect to itself.
+However, see the subsection on "Virtual Machine Guests" below.
[!] Note that SMP memory barriers _must_ be used to control the ordering of
references to shared memory on SMP systems, though the use of locking instead
is sufficient.
Mandatory barriers should not be used to control SMP effects, since mandatory
-barriers unnecessarily impose overhead on UP systems. They may, however, be
-used to control MMIO effects on accesses through relaxed memory I/O windows.
-These are required even on non-SMP systems as they affect the order in which
-memory operations appear to a device by prohibiting both the compiler and the
-CPU from reordering them.
+barriers impose unnecessary overhead on both SMP and UP systems. They may,
+however, be used to control MMIO effects on accesses through relaxed memory I/O
+windows. These barriers are required even on non-SMP systems as they affect
+the order in which memory operations appear to a device by prohibiting both the
+compiler and the CPU from reordering them.
There are some more advanced barrier functions:
@@ -2948,6 +2949,23 @@ The Alpha defines the Linux kernel's memory barrier model.
See the subsection on "Cache Coherency" above.
+VIRTUAL MACHINE GUESTS
+-------------------
+
+Guests running within virtual machines might be affected by SMP effects even if
+the guest itself is compiled without SMP support. This is an artifact of
+interfacing with an SMP host while running an UP kernel. Using mandatory
+barriers for this use-case would be possible but is often suboptimal.
+
+To handle this case optimally, low-level virt_mb() etc macros are available.
+These have the same effect as smp_mb() etc when SMP is enabled, but generate
+identical code for SMP and non-SMP systems. For example, virtual machine guests
+should use virt_mb() rather than smp_mb() when synchronizing against a
+(possibly SMP) host.
+
+These are equivalent to smp_mb() etc counterparts in all other respects,
+in particular, they do not control MMIO effects: to control
+MMIO effects, use mandatory barriers.
============
EXAMPLE USES
diff --git a/Documentation/mtd/nand_ecc.txt b/Documentation/mtd/nand_ecc.txt
index e129b2479ea8..f8c3284bf6a7 100644
--- a/Documentation/mtd/nand_ecc.txt
+++ b/Documentation/mtd/nand_ecc.txt
@@ -107,7 +107,7 @@ for (i = 0; i < 256; i++)
if (i & 0x01)
rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1;
else
- rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1;
+ rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp0;
if (i & 0x02)
rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp3;
else
@@ -127,7 +127,7 @@ for (i = 0; i < 256; i++)
if (i & 0x20)
rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp11;
else
- rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10;
+ rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10;
if (i & 0x40)
rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp13;
else
@@ -158,7 +158,7 @@ the values in any order. So instead of calculating all the bits
individually, let us try to rearrange things.
For the column parity this is easy. We can just xor the bytes and in the
end filter out the relevant bits. This is pretty nice as it will bring
-all cp calculation out of the if loop.
+all cp calculation out of the for loop.
Similarly we can first xor the bytes for the various rows.
This leads to:
@@ -271,11 +271,11 @@ to write our code in such a way that we process data in 32 bit chunks.
Of course this means some modification as the row parity is byte by
byte. A quick analysis:
for the column parity we use the par variable. When extending to 32 bits
-we can in the end easily calculate p0 and p1 from it.
+we can in the end easily calculate rp0 and rp1 from it.
(because par now consists of 4 bytes, contributing to rp1, rp0, rp1, rp0
-respectively)
+respectively, from MSB to LSB)
also rp2 and rp3 can be easily retrieved from par as rp3 covers the
-first two bytes and rp2 the last two bytes.
+first two MSBs and rp2 covers the last two LSBs.
Note that of course now the loop is executed only 64 times (256/4).
And note that care must taken wrt byte ordering. The way bytes are
@@ -387,11 +387,11 @@ Analysis 2
The code (of course) works, and hurray: we are a little bit faster than
the linux driver code (about 15%). But wait, don't cheer too quickly.
-THere is more to be gained.
+There is more to be gained.
If we look at e.g. rp14 and rp15 we see that we either xor our data with
rp14 or with rp15. However we also have par which goes over all data.
This means there is no need to calculate rp14 as it can be calculated from
-rp15 through rp14 = par ^ rp15;
+rp15 through rp14 = par ^ rp15, because par = rp14 ^ rp15;
(or if desired we can avoid calculating rp15 and calculate it from
rp14). That is why some places refer to inverse parity.
Of course the same thing holds for rp4/5, rp6/7, rp8/9, rp10/11 and rp12/13.
@@ -419,12 +419,12 @@ with
if (i & 0x20) rp15 ^= cur;
and outside the loop added:
- rp4 = par ^ rp5;
- rp6 = par ^ rp7;
- rp8 = par ^ rp9;
- rp10 = par ^ rp11;
- rp12 = par ^ rp13;
- rp14 = par ^ rp15;
+ rp4 = par ^ rp5;
+ rp6 = par ^ rp7;
+ rp8 = par ^ rp9;
+ rp10 = par ^ rp11;
+ rp12 = par ^ rp13;
+ rp14 = par ^ rp15;
And after that the code takes about 30% more time, although the number of
statements is reduced. This is also reflected in the assembly code.
@@ -524,12 +524,12 @@ THe code within the for loop was changed to:
cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
cur = *bp++; tmppar ^= cur; rp6 ^= cur;
- cur = *bp++; tmppar ^= cur; rp4 ^= cur;
- cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
+ cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+ cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
- cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur;
+ cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur;
cur = *bp++; tmppar ^= cur; rp6 ^= cur; rp8 ^= cur;
- cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur;
+ cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur;
cur = *bp++; tmppar ^= cur; rp8 ^= cur;
cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur;
@@ -537,7 +537,7 @@ THe code within the for loop was changed to:
cur = *bp++; tmppar ^= cur; rp4 ^= cur;
cur = *bp++; tmppar ^= cur;
- par ^= tmppar;
+ par ^= tmppar;
if ((i & 0x1) == 0) rp12 ^= tmppar;
if ((i & 0x2) == 0) rp14 ^= tmppar;
}
@@ -548,8 +548,8 @@ to rp12 and rp14.
While making the changes I also found that I could exploit that tmppar
contains the running parity for this iteration. So instead of having:
-rp4 ^= cur; rp6 = cur;
-I removed the rp6 = cur; statement and did rp6 ^= tmppar; on next
+rp4 ^= cur; rp6 ^= cur;
+I removed the rp6 ^= cur; statement and did rp6 ^= tmppar; on next
statement. A similar change was done for rp8 and rp10
@@ -593,22 +593,22 @@ The new code now looks like:
cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
cur = *bp++; tmppar ^= cur; rp6 ^= cur;
- cur = *bp++; tmppar ^= cur; rp4 ^= cur;
- cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
+ cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+ cur = *bp++; tmppar ^= cur; rp10 ^= tmppar;
- notrp8 = tmppar;
- cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
+ notrp8 = tmppar;
+ cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
cur = *bp++; tmppar ^= cur; rp6 ^= cur;
- cur = *bp++; tmppar ^= cur; rp4 ^= cur;
+ cur = *bp++; tmppar ^= cur; rp4 ^= cur;
cur = *bp++; tmppar ^= cur;
- rp8 = rp8 ^ tmppar ^ notrp8;
+ rp8 = rp8 ^ tmppar ^ notrp8;
cur = *bp++; tmppar ^= cur; rp4_6 ^= cur;
cur = *bp++; tmppar ^= cur; rp6 ^= cur;
cur = *bp++; tmppar ^= cur; rp4 ^= cur;
cur = *bp++; tmppar ^= cur;
- par ^= tmppar;
+ par ^= tmppar;
if ((i & 0x1) == 0) rp12 ^= tmppar;
if ((i & 0x2) == 0) rp14 ^= tmppar;
}
@@ -700,7 +700,7 @@ Conclusion
The gain when calculating the ecc is tremendous. Om my development hardware
a speedup of a factor of 18 for ecc calculation was achieved. On a test on an
embedded system with a MIPS core a factor 7 was obtained.
-On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor
+On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor
5 (big endian mode, gcc 4.1.2, -O3)
For correction not much gain could be obtained (as bitflips are rare). Then
again there are also much less cycles spent there.
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 05fd83bb3596..6ab619fcc517 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -372,6 +372,15 @@ solution for a couple of reasons:
nbytes = sendto(s, &frame, sizeof(struct can_frame),
0, (struct sockaddr*)&addr, sizeof(addr));
+ An accurate timestamp can be obtained with an ioctl(2) call after reading
+ a message from the socket:
+
+ struct timeval tv;
+ ioctl(s, SIOCGSTAMP, &tv);
+
+ The timestamp has a resolution of one microsecond and is set automatically
+ at the reception of a CAN frame.
+
Remark about CAN FD (flexible data rate) support:
Generally the handling of CAN FD is very similar to the formerly described
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 6389551bbad6..5d1128bf0282 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -306,15 +306,6 @@ Network device features:
Passed by reference.
-Command from struct task_struct
-
- %pT ls
-
- For printing executable name excluding path from struct
- task_struct.
-
- Passed by reference.
-
If you add other %p extensions, please extend lib/test_printf.c with
one or more test cases, if at all feasible.
diff --git a/Documentation/s390/zfcpdump.txt b/Documentation/s390/zfcpdump.txt
index dc929be96016..b064aa59714d 100644
--- a/Documentation/s390/zfcpdump.txt
+++ b/Documentation/s390/zfcpdump.txt
@@ -15,19 +15,15 @@ the s390-tools package) to make the device bootable. The operator of a Linux
system can then trigger a SCSI dump by booting the SCSI disk, where zfcpdump
resides on.
-The kernel part of zfcpdump is implemented as a debugfs file under "zcore/mem",
-which exports memory and registers of the crashed Linux in an s390
-standalone dump format. It can be used in the same way as e.g. /dev/mem. The
-dump format defines a 4K header followed by plain uncompressed memory. The
-register sets are stored in the prefix pages of the respective CPUs. To build a
-dump enabled kernel with the zcore driver, the kernel config option
-CONFIG_CRASH_DUMP has to be set. When reading from "zcore/mem", the part of
-memory, which has been saved by hardware is read by the driver via the SCLP
-hardware interface. The second part is just copied from the non overwritten real
-memory.
-
-Since kernel version 3.12 also the /proc/vmcore file can also be used to access
-the dump.
+The user space dump tool accesses the memory of the crashed system by means
+of the /proc/vmcore interface. This interface exports the crashed system's
+memory and registers in ELF core dump format. To access the memory which has
+been saved by the hardware SCLP requests will be created at the time the data
+is needed by /proc/vmcore. The tail part of the crashed systems memory which
+has not been stashed by hardware can just be copied from real memory.
+
+To build a dump enabled kernel the kernel config option CONFIG_CRASH_DUMP
+has to be set.
To get a valid zfcpdump kernel configuration use "make zfcpdump_defconfig".
diff --git a/Documentation/security/keys-trusted-encrypted.txt b/Documentation/security/keys-trusted-encrypted.txt
index e105ae97a4f5..324ddf5223b3 100644
--- a/Documentation/security/keys-trusted-encrypted.txt
+++ b/Documentation/security/keys-trusted-encrypted.txt
@@ -27,17 +27,26 @@ Usage:
keyctl print keyid
options:
- keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
- keyauth= ascii hex auth for sealing key default 0x00...i
- (40 ascii zeros)
- blobauth= ascii hex auth for sealed data default 0x00...
- (40 ascii zeros)
- blobauth= ascii hex auth for sealed data default 0x00...
- (40 ascii zeros)
- pcrinfo= ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
- pcrlock= pcr number to be extended to "lock" blob
- migratable= 0|1 indicating permission to reseal to new PCR values,
- default 1 (resealing allowed)
+ keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
+ keyauth= ascii hex auth for sealing key default 0x00...i
+ (40 ascii zeros)
+ blobauth= ascii hex auth for sealed data default 0x00...
+ (40 ascii zeros)
+ blobauth= ascii hex auth for sealed data default 0x00...
+ (40 ascii zeros)
+ pcrinfo= ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
+ pcrlock= pcr number to be extended to "lock" blob
+ migratable= 0|1 indicating permission to reseal to new PCR values,
+ default 1 (resealing allowed)
+ hash= hash algorithm name as a string. For TPM 1.x the only
+ allowed value is sha1. For TPM 2.x the allowed values
+ are sha1, sha256, sha384, sha512 and sm3-256.
+ policydigest= digest for the authorization policy. must be calculated
+ with the same hash algorithm as specified by the 'hash='
+ option.
+ policyhandle= handle to an authorization policy session that defines the
+ same policy and with the same hash algorithm as was used to
+ seal the key.
"keyctl print" returns an ascii hex copy of the sealed key, which is in standard
TPM_STORED_DATA format. The key length for new keys are always in bytes.
diff --git a/Documentation/sound/alsa/img,spdif-in.txt b/Documentation/sound/alsa/img,spdif-in.txt
new file mode 100644
index 000000000000..8b7505785fa6
--- /dev/null
+++ b/Documentation/sound/alsa/img,spdif-in.txt
@@ -0,0 +1,49 @@
+The Imagination Technologies SPDIF Input controller contains the following
+controls:
+
+name='IEC958 Capture Mask',index=0
+
+This control returns a mask that shows which of the IEC958 status bits
+can be read using the 'IEC958 Capture Default' control.
+
+name='IEC958 Capture Default',index=0
+
+This control returns the status bits contained within the SPDIF stream that
+is being received. The 'IEC958 Capture Mask' shows which bits can be read
+from this control.
+
+name='SPDIF In Multi Frequency Acquire',index=0
+name='SPDIF In Multi Frequency Acquire',index=1
+name='SPDIF In Multi Frequency Acquire',index=2
+name='SPDIF In Multi Frequency Acquire',index=3
+
+This control is used to attempt acquisition of up to four different sample
+rates. The active rate can be obtained by reading the 'SPDIF In Lock Frequency'
+control.
+
+When the value of this control is set to {0,0,0,0}, the rate given to hw_params
+will determine the single rate the block will capture. Else, the rate given to
+hw_params will be ignored, and the block will attempt capture for each of the
+four sample rates set here.
+
+If less than four rates are required, the same rate can be specified more than
+once
+
+name='SPDIF In Lock Frequency',index=0
+
+This control returns the active capture rate, or 0 if a lock has not been
+acquired
+
+name='SPDIF In Lock TRK',index=0
+
+This control is used to modify the locking/jitter rejection characteristics
+of the block. Larger values increase the locking range, but reduce jitter
+rejection.
+
+name='SPDIF In Lock Acquire Threshold',index=0
+
+This control is used to change the threshold at which a lock is acquired.
+
+name='SPDIF In Lock Release Threshold',index=0
+
+This control is used to change the threshold at which a lock is released.
diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX
index a128fa835512..4644bf0d9832 100644
--- a/Documentation/spi/00-INDEX
+++ b/Documentation/spi/00-INDEX
@@ -10,13 +10,9 @@ pxa2xx
- PXA2xx SPI master controller build by spi_message fifo wq
spidev
- Intro to the userspace API for spi devices
-spidev_fdx.c
- - spidev example file
spi-lm70llp
- Connecting an LM70-LLP sensor to the kernel via the SPI subsys.
spi-sc18is602
- NXP SC18IS602/603 I2C-bus to SPI bridge
spi-summary
- (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here.
-spidev_test.c
- - SPI testing utility.
diff --git a/Documentation/spi/Makefile b/Documentation/spi/Makefile
deleted file mode 100644
index efa255813e9d..000000000000
--- a/Documentation/spi/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# List of programs to build
-hostprogs-y := spidev_test spidev_fdx
-
-# Tell kbuild to always build the programs
-always := $(hostprogs-y)
-
-HOSTCFLAGS_spidev_test.o += -I$(objtree)/usr/include
-HOSTCFLAGS_spidev_fdx.o += -I$(objtree)/usr/include
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index 3049a612291b..ffd4575ec9f2 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -93,7 +93,7 @@ format in the sign-off area:
Also, some patches may have kernel version prerequisites. This can be
specified in the following format in the sign-off area:
- Cc: <stable@vger.kernel.org> # 3.3.x-
+ Cc: <stable@vger.kernel.org> # 3.3.x-
The tag has the meaning of:
git cherry-pick <this commit>
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index f72370b440b1..89a887c76629 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -42,6 +42,8 @@ Currently, these files are in /proc/sys/vm:
- min_slab_ratio
- min_unmapped_ratio
- mmap_min_addr
+- mmap_rnd_bits
+- mmap_rnd_compat_bits
- nr_hugepages
- nr_overcommit_hugepages
- nr_trim_pages (only if CONFIG_MMU=n)
@@ -135,7 +137,7 @@ Contains, as a percentage of total available memory that contains free pages
and reclaimable pages, the number of pages at which the background kernel
flusher threads will start writing out dirty data.
-The total avaiable memory is not equal to total system memory.
+The total available memory is not equal to total system memory.
==============================================================
@@ -170,7 +172,7 @@ Contains, as a percentage of total available memory that contains free pages
and reclaimable pages, the number of pages at which a process which is
generating disk writes will itself start writing out dirty data.
-The total avaiable memory is not equal to total system memory.
+The total available memory is not equal to total system memory.
==============================================================
@@ -485,6 +487,33 @@ against future potential kernel bugs.
==============================================================
+mmap_rnd_bits:
+
+This value can be used to select the number of bits to use to
+determine the random offset to the base address of vma regions
+resulting from mmap allocations on architectures which support
+tuning address space randomization. This value will be bounded
+by the architecture's minimum and maximum supported values.
+
+This value can be changed after boot using the
+/proc/sys/vm/mmap_rnd_bits tunable
+
+==============================================================
+
+mmap_rnd_compat_bits:
+
+This value can be used to select the number of bits to use to
+determine the random offset to the base address of vma regions
+resulting from mmap allocations for applications run in
+compatibility mode on architectures which support tuning address
+space randomization. This value will be bounded by the
+architecture's minimum and maximum supported values.
+
+This value can be changed after boot using the
+/proc/sys/vm/mmap_rnd_compat_bits tunable
+
+==============================================================
+
nr_hugepages
Change the minimum size of the hugepage pool.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 10f062ea6bc2..8c745c8931da 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -364,6 +364,7 @@ integral_cutoff
accumulates error when temperature is above the desired
temperature trip point. For more information see
Documentation/thermal/power_allocator.txt
+ Unit: millidegree Celsius
RW, Optional
slope
diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt
index 3f848c1f2940..05f735a1b5a5 100644
--- a/Documentation/usb/chipidea.txt
+++ b/Documentation/usb/chipidea.txt
@@ -7,8 +7,8 @@ with 2 Freescale i.MX6Q sabre SD boards.
---------------------------------------
Select CONFIG_USB_OTG_FSM, rebuild kernel Image and modules.
If you want to check some internal variables for otg fsm,
-select CONFIG_USB_CHIPIDEA_DEBUG, there are 2 files which
-can show otg fsm variables and some controller registers value:
+mount debugfs, there are 2 files which can show otg fsm
+variables and some controller registers value:
cat /sys/kernel/debug/ci_hdrc.0/otg
cat /sys/kernel/debug/ci_hdrc.0/registers
diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt
index b24d3ef89166..581960574889 100644
--- a/Documentation/usb/gadget-testing.txt
+++ b/Documentation/usb/gadget-testing.txt
@@ -434,7 +434,7 @@ On host: serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \
where seriald and serialc are Felipe's utilities found here:
-https://git.gitorious.org/usb/usb-tools.git master
+https://github.com/felipebalbi/usb-tools.git master
12. PHONET function
===================
@@ -579,6 +579,8 @@ The SOURCESINK function provides these attributes in its function directory:
isoc_mult - 0..2 (hs/ss only)
isoc_maxburst - 0..15 (ss only)
bulk_buflen - buffer length
+ bulk_qlen - depth of queue for bulk
+ iso_qlen - depth of queue for iso
Testing the SOURCESINK function
-------------------------------
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
index 4a15c90bc11d..0a94ffe17ab6 100644
--- a/Documentation/usb/power-management.txt
+++ b/Documentation/usb/power-management.txt
@@ -537,17 +537,18 @@ relevant attribute files are usb2_hardware_lpm and usb3_hardware_lpm.
can write y/Y/1 or n/N/0 to the file to enable/disable
USB2 hardware LPM manually. This is for test purpose mainly.
- power/usb3_hardware_lpm
+ power/usb3_hardware_lpm_u1
+ power/usb3_hardware_lpm_u2
When a USB 3.0 lpm-capable device is plugged in to a
xHCI host which supports link PM, it will check if U1
and U2 exit latencies have been set in the BOS
descriptor; if the check is is passed and the host
supports USB3 hardware LPM, USB3 hardware LPM will be
- enabled for the device and this file will be created.
- The file holds a string value (enable or disable)
- indicating whether or not USB3 hardware LPM is
- enabled for the device.
+ enabled for the device and these files will be created.
+ The files hold a string value (enable or disable)
+ indicating whether or not USB3 hardware LPM U1 or U2
+ is enabled for the device.
USB Port Power Control
----------------------
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 75d5c18d689a..fa41608ab2b4 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -295,16 +295,16 @@ module owner. This is done for you if you use the i2c helper functions.
If integration with the media framework is needed, you must initialize the
media_entity struct embedded in the v4l2_subdev struct (entity field) by
-calling media_entity_init():
+calling media_entity_pads_init(), if the entity has pads:
struct media_pad *pads = &my_sd->pads;
int err;
- err = media_entity_init(&sd->entity, npads, pads, 0);
+ err = media_entity_pads_init(&sd->entity, npads, pads);
The pads array must have been previously initialized. There is no need to
-manually set the struct media_entity type and name fields, but the revision
-field must be initialized if needed.
+manually set the struct media_entity function and name fields, but the
+revision field must be initialized if needed.
A reference to the entity will be automatically acquired/released when the
subdev device node (if any) is opened/closed.
@@ -695,12 +695,12 @@ difference is that the inode argument is omitted since it is never used.
If integration with the media framework is needed, you must initialize the
media_entity struct embedded in the video_device struct (entity field) by
-calling media_entity_init():
+calling media_entity_pads_init():
struct media_pad *pad = &my_vdev->pad;
int err;
- err = media_entity_init(&vdev->entity, 1, pad, 0);
+ err = media_entity_pads_init(&vdev->entity, 1, pad);
The pads array must have been previously initialized. There is no need to
manually set the struct media_entity type and name fields.
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index 699d8ea5c230..f0d340959319 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -8,7 +8,7 @@ SLUB can enable debugging only for selected slabs in order to avoid
an impact on overall system performance which may make a bug more
difficult to find.
-In order to switch debugging on one can add a option "slub_debug"
+In order to switch debugging on one can add an option "slub_debug"
to the kernel command line. That will enable full debugging for
all slabs.
diff --git a/Documentation/vm/transhuge.txt b/Documentation/vm/transhuge.txt
index 8a282687ee06..21cf34f3ddb2 100644
--- a/Documentation/vm/transhuge.txt
+++ b/Documentation/vm/transhuge.txt
@@ -35,10 +35,10 @@ miss is going to run faster.
== Design ==
-- "graceful fallback": mm components which don't have transparent
- hugepage knowledge fall back to breaking a transparent hugepage and
- working on the regular pages and their respective regular pmd/pte
- mappings
+- "graceful fallback": mm components which don't have transparent hugepage
+ knowledge fall back to breaking huge pmd mapping into table of ptes and,
+ if necessary, split a transparent hugepage. Therefore these components
+ can continue working on the regular pages or regular pte mappings.
- if a hugepage allocation fails because of memory fragmentation,
regular pages should be gracefully allocated instead and mixed in
@@ -221,9 +221,18 @@ thp_collapse_alloc_failed is incremented if khugepaged found a range
of pages that should be collapsed into one huge page but failed
the allocation.
-thp_split is incremented every time a huge page is split into base
+thp_split_page is incremented every time a huge page is split into base
pages. This can happen for a variety of reasons but a common
reason is that a huge page is old and is being reclaimed.
+ This action implies splitting all PMD the page mapped with.
+
+thp_split_page_failed is is incremented if kernel fails to split huge
+ page. This can happen if the page was pinned by somebody.
+
+thp_split_pmd is incremented every time a PMD split into table of PTEs.
+ This can happen, for instance, when application calls mprotect() or
+ munmap() on part of huge page. It doesn't split huge page, only
+ page table entry.
thp_zero_page_alloc is incremented every time a huge zero page is
successfully allocated. It includes allocations which where
@@ -274,10 +283,8 @@ is complete, so they won't ever notice the fact the page is huge. But
if any driver is going to mangle over the page structure of the tail
page (like for checking page->mapping or other bits that are relevant
for the head page and not the tail page), it should be updated to jump
-to check head page instead (while serializing properly against
-split_huge_page() to avoid the head and tail pages to disappear from
-under it, see the futex code to see an example of that, hugetlbfs also
-needed special handling in futex code for similar reasons).
+to check head page instead. Taking reference on any head/tail page would
+prevent page from being split by anyone.
NOTE: these aren't new constraints to the GUP API, and they match the
same constrains that applies to hugetlbfs too, so any driver capable
@@ -312,9 +319,9 @@ unaffected. libhugetlbfs will also work fine as usual.
== Graceful fallback ==
Code walking pagetables but unware about huge pmds can simply call
-split_huge_page_pmd(vma, addr, pmd) where the pmd is the one returned by
+split_huge_pmd(vma, pmd, addr) where the pmd is the one returned by
pmd_offset. It's trivial to make the code transparent hugepage aware
-by just grepping for "pmd_offset" and adding split_huge_page_pmd where
+by just grepping for "pmd_offset" and adding split_huge_pmd where
missing after pmd_offset returns the pmd. Thanks to the graceful
fallback design, with a one liner change, you can avoid to write
hundred if not thousand of lines of complex code to make your code
@@ -323,7 +330,8 @@ hugepage aware.
If you're not walking pagetables but you run into a physical hugepage
but you can't handle it natively in your code, you can split it by
calling split_huge_page(page). This is what the Linux VM does before
-it tries to swapout the hugepage for example.
+it tries to swapout the hugepage for example. split_huge_page() can fail
+if the page is pinned and you must handle this correctly.
Example to make mremap.c transparent hugepage aware with a one liner
change:
@@ -335,14 +343,14 @@ diff --git a/mm/mremap.c b/mm/mremap.c
return NULL;
pmd = pmd_offset(pud, addr);
-+ split_huge_page_pmd(vma, addr, pmd);
++ split_huge_pmd(vma, pmd, addr);
if (pmd_none_or_clear_bad(pmd))
return NULL;
== Locking in hugepage aware code ==
We want as much code as possible hugepage aware, as calling
-split_huge_page() or split_huge_page_pmd() has a cost.
+split_huge_page() or split_huge_pmd() has a cost.
To make pagetable walks huge pmd aware, all you need to do is to call
pmd_trans_huge() on the pmd returned by pmd_offset. You must hold the
@@ -351,47 +359,80 @@ created from under you by khugepaged (khugepaged collapse_huge_page
takes the mmap_sem in write mode in addition to the anon_vma lock). If
pmd_trans_huge returns false, you just fallback in the old code
paths. If instead pmd_trans_huge returns true, you have to take the
-mm->page_table_lock and re-run pmd_trans_huge. Taking the
-page_table_lock will prevent the huge pmd to be converted into a
-regular pmd from under you (split_huge_page can run in parallel to the
+page table lock (pmd_lock()) and re-run pmd_trans_huge. Taking the
+page table lock will prevent the huge pmd to be converted into a
+regular pmd from under you (split_huge_pmd can run in parallel to the
pagetable walk). If the second pmd_trans_huge returns false, you
-should just drop the page_table_lock and fallback to the old code as
-before. Otherwise you should run pmd_trans_splitting on the pmd. In
-case pmd_trans_splitting returns true, it means split_huge_page is
-already in the middle of splitting the page. So if pmd_trans_splitting
-returns true it's enough to drop the page_table_lock and call
-wait_split_huge_page and then fallback the old code paths. You are
-guaranteed by the time wait_split_huge_page returns, the pmd isn't
-huge anymore. If pmd_trans_splitting returns false, you can proceed to
-process the huge pmd and the hugepage natively. Once finished you can
-drop the page_table_lock.
-
-== compound_lock, get_user_pages and put_page ==
+should just drop the page table lock and fallback to the old code as
+before. Otherwise you can proceed to process the huge pmd and the
+hugepage natively. Once finished you can drop the page table lock.
+
+== Refcounts and transparent huge pages ==
+
+Refcounting on THP is mostly consistent with refcounting on other compound
+pages:
+
+ - get_page()/put_page() and GUP operate in head page's ->_count.
+
+ - ->_count in tail pages is always zero: get_page_unless_zero() never
+ succeed on tail pages.
+
+ - map/unmap of the pages with PTE entry increment/decrement ->_mapcount
+ on relevant sub-page of the compound page.
+
+ - map/unmap of the whole compound page accounted in compound_mapcount
+ (stored in first tail page).
+
+PageDoubleMap() indicates that ->_mapcount in all subpages is offset up by one.
+This additional reference is required to get race-free detection of unmap of
+subpages when we have them mapped with both PMDs and PTEs.
+
+This is optimization required to lower overhead of per-subpage mapcount
+tracking. The alternative is alter ->_mapcount in all subpages on each
+map/unmap of the whole compound page.
+
+We set PG_double_map when a PMD of the page got split for the first time,
+but still have PMD mapping. The addtional references go away with last
+compound_mapcount.
split_huge_page internally has to distribute the refcounts in the head
-page to the tail pages before clearing all PG_head/tail bits from the
-page structures. It can do that easily for refcounts taken by huge pmd
-mappings. But the GUI API as created by hugetlbfs (that returns head
-and tail pages if running get_user_pages on an address backed by any
-hugepage), requires the refcount to be accounted on the tail pages and
-not only in the head pages, if we want to be able to run
-split_huge_page while there are gup pins established on any tail
-page. Failure to be able to run split_huge_page if there's any gup pin
-on any tail page, would mean having to split all hugepages upfront in
-get_user_pages which is unacceptable as too many gup users are
-performance critical and they must work natively on hugepages like
-they work natively on hugetlbfs already (hugetlbfs is simpler because
-hugetlbfs pages cannot be split so there wouldn't be requirement of
-accounting the pins on the tail pages for hugetlbfs). If we wouldn't
-account the gup refcounts on the tail pages during gup, we won't know
-anymore which tail page is pinned by gup and which is not while we run
-split_huge_page. But we still have to add the gup pin to the head page
-too, to know when we can free the compound page in case it's never
-split during its lifetime. That requires changing not just
-get_page, but put_page as well so that when put_page runs on a tail
-page (and only on a tail page) it will find its respective head page,
-and then it will decrease the head page refcount in addition to the
-tail page refcount. To obtain a head page reliably and to decrease its
-refcount without race conditions, put_page has to serialize against
-__split_huge_page_refcount using a special per-page lock called
-compound_lock.
+page to the tail pages before clearing all PG_head/tail bits from the page
+structures. It can be done easily for refcounts taken by page table
+entries. But we don't have enough information on how to distribute any
+additional pins (i.e. from get_user_pages). split_huge_page() fails any
+requests to split pinned huge page: it expects page count to be equal to
+sum of mapcount of all sub-pages plus one (split_huge_page caller must
+have reference for head page).
+
+split_huge_page uses migration entries to stabilize page->_count and
+page->_mapcount.
+
+We safe against physical memory scanners too: the only legitimate way
+scanner can get reference to a page is get_page_unless_zero().
+
+All tail pages has zero ->_count until atomic_add(). It prevent scanner
+from geting reference to tail page up to the point. After the atomic_add()
+we don't care about ->_count value. We already known how many references
+with should uncharge from head page.
+
+For head page get_page_unless_zero() will succeed and we don't mind. It's
+clear where reference should go after split: it will stay on head page.
+
+Note that split_huge_pmd() doesn't have any limitation on refcounting:
+pmd can be split at any point and never fails.
+
+== Partial unmap and deferred_split_huge_page() ==
+
+Unmapping part of THP (with munmap() or other way) is not going to free
+memory immediately. Instead, we detect that a subpage of THP is not in use
+in page_remove_rmap() and queue the THP for splitting if memory pressure
+comes. Splitting will free up unused subpages.
+
+Splitting the page right away is not an option due to locking context in
+the place where we can detect partial unmap. It's also might be
+counterproductive since in many cases partial unmap unmap happens during
+exit(2) if an THP crosses VMA boundary.
+
+Function deferred_split_huge_page() is used to queue page for splitting.
+The splitting itself will happen when we get memory pressure via shrinker
+interface.
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index d8b0d3367706..55120a055a14 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -44,17 +44,18 @@ The watchdog device structure looks like this:
struct watchdog_device {
int id;
- struct cdev cdev;
- struct device *dev;
struct device *parent;
+ const struct attribute_group **groups;
const struct watchdog_info *info;
const struct watchdog_ops *ops;
unsigned int bootstatus;
unsigned int timeout;
unsigned int min_timeout;
unsigned int max_timeout;
+ struct notifier_block reboot_nb;
+ struct notifier_block restart_nb;
void *driver_data;
- struct mutex lock;
+ struct watchdog_core_data *wd_data;
unsigned long status;
struct list_head deferred;
};
@@ -64,27 +65,32 @@ It contains following fields:
/dev/watchdog0 cdev (dynamic major, minor 0) as well as the old
/dev/watchdog miscdev. The id is set automatically when calling
watchdog_register_device.
-* cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This
- field is also populated by watchdog_register_device.
-* dev: device under the watchdog class (created by watchdog_register_device).
* parent: set this to the parent device (or NULL) before calling
watchdog_register_device.
+* groups: List of sysfs attribute groups to create when creating the watchdog
+ device.
* info: a pointer to a watchdog_info structure. This structure gives some
additional information about the watchdog timer itself. (Like it's unique name)
* ops: a pointer to the list of watchdog operations that the watchdog supports.
* timeout: the watchdog timer's timeout value (in seconds).
* min_timeout: the watchdog timer's minimum timeout value (in seconds).
* max_timeout: the watchdog timer's maximum timeout value (in seconds).
+* reboot_nb: notifier block that is registered for reboot notifications, for
+ internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core
+ will stop the watchdog on such notifications.
+* restart_nb: notifier block that is registered for machine restart, for
+ internal use only. If a watchdog is capable of restarting the machine, it
+ should define ops->restart. Priority can be changed through
+ watchdog_set_restart_priority.
* bootstatus: status of the device after booting (reported with watchdog
WDIOF_* status bits).
* driver_data: a pointer to the drivers private data of a watchdog device.
This data should only be accessed via the watchdog_set_drvdata and
watchdog_get_drvdata routines.
-* lock: Mutex for WatchDog Timer Driver Core internal use only.
+* wd_data: a pointer to watchdog core internal data.
* status: this field contains a number of status bits that give extra
information about the status of the device (Like: is the watchdog timer
- running/active, is the nowayout bit set, is the device opened via
- the /dev/watchdog interface or not, ...).
+ running/active, or is the nowayout bit set).
* deferred: entry in wtd_deferred_reg_list which is used to
register early initialized watchdogs.
@@ -100,8 +106,9 @@ struct watchdog_ops {
unsigned int (*status)(struct watchdog_device *);
int (*set_timeout)(struct watchdog_device *, unsigned int);
unsigned int (*get_timeleft)(struct watchdog_device *);
- void (*ref)(struct watchdog_device *);
- void (*unref)(struct watchdog_device *);
+ int (*restart)(struct watchdog_device *);
+ void (*ref)(struct watchdog_device *) __deprecated;
+ void (*unref)(struct watchdog_device *) __deprecated;
long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
};
@@ -110,20 +117,6 @@ driver's operations. This module owner will be used to lock the module when
the watchdog is active. (This to avoid a system crash when you unload the
module and /dev/watchdog is still open).
-If the watchdog_device struct is dynamically allocated, just locking the module
-is not enough and a driver also needs to define the ref and unref operations to
-ensure the structure holding the watchdog_device does not go away.
-
-The simplest (and usually sufficient) implementation of this is to:
-1) Add a kref struct to the same structure which is holding the watchdog_device
-2) Define a release callback for the kref which frees the struct holding both
-3) Call kref_init on this kref *before* calling watchdog_register_device()
-4) Define a ref operation calling kref_get on this kref
-5) Define a unref operation calling kref_put on this kref
-6) When it is time to cleanup:
- * Do not kfree() the struct holding both, the last kref_put will do this!
- * *After* calling watchdog_unregister_device() call kref_put on the kref
-
Some operations are mandatory and some are optional. The mandatory operations
are:
* start: this is a pointer to the routine that starts the watchdog timer
@@ -164,34 +157,23 @@ they are supported. These optional routines/operations are:
(Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
watchdog's info structure).
* get_timeleft: this routines returns the time that's left before a reset.
-* ref: the operation that calls kref_get on the kref of a dynamically
- allocated watchdog_device struct.
-* unref: the operation that calls kref_put on the kref of a dynamically
- allocated watchdog_device struct.
+* restart: this routine restarts the machine. It returns 0 on success or a
+ negative errno code for failure.
* ioctl: if this routine is present then it will be called first before we do
our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
if a command is not supported. The parameters that are passed to the ioctl
call are: watchdog_device, cmd and arg.
+The 'ref' and 'unref' operations are no longer used and deprecated.
+
The status bits should (preferably) be set with the set_bit and clear_bit alike
bit-operations. The status bits that are defined are:
* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
is active or not. When the watchdog is active after booting, then you should
set this status bit (Note: when you register the watchdog timer device with
this bit set, then opening /dev/watchdog will skip the start operation)
-* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
- was opened via /dev/watchdog.
- (This bit should only be used by the WatchDog Timer Driver Core).
-* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character
- has been sent (so that we can support the magic close feature).
- (This bit should only be used by the WatchDog Timer Driver Core).
* WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog.
If this bit is set then the watchdog timer will not be able to stop.
-* WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core
- after calling watchdog_unregister_device, and then checked before calling
- any watchdog_ops, so that you can be sure that no operations (other then
- unref) will get called after unregister, even if userspace still holds a
- reference to /dev/watchdog
To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog
timer device) you can either:
@@ -231,3 +213,18 @@ the device tree (if the module timeout parameter is invalid). Best practice is
to set the default timeout value as timeout value in the watchdog_device and
then use this function to set the user "preferred" timeout value.
This routine returns zero on success and a negative errno code for failure.
+
+To disable the watchdog on reboot, the user must call the following helper:
+
+static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd);
+
+To change the priority of the restart handler the following helper should be
+used:
+
+void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
+
+User should follow the following guidelines for setting the priority:
+* 0: should be called in last resort, has limited restart capabilities
+* 128: default restart handler, use if no other handler is expected to be
+ available, and/or if restart is sufficient to restart the entire system
+* 255: highest priority, will preempt all other restart handlers
diff --git a/Documentation/zh_CN/video4linux/v4l2-framework.txt b/Documentation/zh_CN/video4linux/v4l2-framework.txt
index 2b828e631e31..698660b7f21f 100644
--- a/Documentation/zh_CN/video4linux/v4l2-framework.txt
+++ b/Documentation/zh_CN/video4linux/v4l2-framework.txt
@@ -289,13 +289,13 @@ struct v4l2_subdev_ops {
然åŽï¼Œä½ å¿…须用一个唯一的åå­—åˆå§‹åŒ– subdev->name,并åˆå§‹åŒ–模å—çš„
owner 域。若使用 i2c 辅助函数,这些都会帮你处ç†å¥½ã€‚
-若需åŒåª’体框架整åˆï¼Œä½ å¿…须调用 media_entity_init() åˆå§‹åŒ– v4l2_subdev
+若需åŒåª’体框架整åˆï¼Œä½ å¿…须调用 media_entity_pads_init() åˆå§‹åŒ– v4l2_subdev
结构体中的 media_entity 结构体(entity 域):
struct media_pad *pads = &my_sd->pads;
int err;
- err = media_entity_init(&sd->entity, npads, pads, 0);
+ err = media_entity_pads_init(&sd->entity, npads, pads);
pads 数组必须预先åˆå§‹åŒ–。无须手动设置 media_entity çš„ type å’Œ
name 域,但如有必è¦ï¼Œrevision 域必须åˆå§‹åŒ–。
@@ -596,13 +596,13 @@ void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd);
v4l2_file_operations 结构体是 file_operations 的一个å­é›†ã€‚其主è¦
区别在于:因 inode å‚数从未被使用,它将被忽略。
-如果需è¦ä¸Žåª’体框架整åˆï¼Œä½ å¿…须通过调用 media_entity_init() åˆå§‹åŒ–
+如果需è¦ä¸Žåª’体框架整åˆï¼Œä½ å¿…须通过调用 media_entity_pads_init() åˆå§‹åŒ–
嵌入在 video_device 结构体中的 media_entity(entity 域)结构体:
struct media_pad *pad = &my_vdev->pad;
int err;
- err = media_entity_init(&vdev->entity, 1, pad, 0);
+ err = media_entity_pads_init(&vdev->entity, 1, pad);
pads 数组必须预先åˆå§‹åŒ–。没有必è¦æ‰‹åŠ¨è®¾ç½® media_entity çš„ type å’Œ
name 域。
diff --git a/MAINTAINERS b/MAINTAINERS
index 530f7d8fccb5..293874ca4d4e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -240,6 +240,12 @@ L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/abituguru3.c
+ACCES 104-IDI-48 GPIO DRIVER
+M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
+L: linux-gpio@vger.kernel.org
+S: Maintained
+F: drivers/gpio/gpio-104-idi-48.c
+
ACCES 104-IDIO-16 GPIO DRIVER
M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
L: linux-gpio@vger.kernel.org
@@ -1409,12 +1415,13 @@ W: http://www.arm.linux.org.uk/
S: Maintained
ARM/QUALCOMM SUPPORT
-M: Kumar Gala <galak@codeaurora.org>
-M: Andy Gross <agross@codeaurora.org>
-M: David Brown <davidb@codeaurora.org>
+M: Andy Gross <andy.gross@linaro.org>
+M: David Brown <david.brown@linaro.org>
L: linux-arm-msm@vger.kernel.org
L: linux-soc@vger.kernel.org
S: Maintained
+F: arch/arm/boot/dts/qcom-*.dts
+F: arch/arm/boot/dts/qcom-*.dtsi
F: arch/arm/mach-qcom/
F: drivers/soc/qcom/
F: drivers/tty/serial/msm_serial.h
@@ -1422,13 +1429,22 @@ F: drivers/tty/serial/msm_serial.c
F: drivers/*/pm8???-*
F: drivers/mfd/ssbi.c
F: drivers/firmware/qcom_scm.c
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git
ARM/RADISYS ENP2611 MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+ARM/RENESAS ARM64 ARCHITECTURE
+M: Simon Horman <horms@verge.net.au>
+M: Magnus Damm <magnus.damm@gmail.com>
+L: linux-sh@vger.kernel.org
+Q: http://patchwork.kernel.org/project/linux-sh/list/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next
+S: Supported
+F: arch/arm64/boot/dts/renesas/
+
ARM/RISCPC ARCHITECTURE
M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1525,9 +1541,8 @@ F: drivers/media/platform/s5p-jpeg/
ARM/SHMOBILE ARM ARCHITECTURE
M: Simon Horman <horms@verge.net.au>
M: Magnus Damm <magnus.damm@gmail.com>
-L: linux-sh@vger.kernel.org
-W: http://oss.renesas.com
-Q: http://patchwork.kernel.org/project/linux-sh/list/
+L: linux-renesas-soc@vger.kernel.org
+Q: http://patchwork.kernel.org/project/linux-renesas-soc/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next
S: Supported
F: arch/arm/boot/dts/emev2*
@@ -1597,6 +1612,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
N: stm32
F: drivers/clocksource/armv7m_systick.c
+ARM/TANGO ARCHITECTURE
+M: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
+L: linux-arm-kernel@lists.infradead.org
+S: Maintained
+F: arch/arm/mach-tango/
+F: arch/arm/boot/dts/tango*
+
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1651,6 +1673,8 @@ F: arch/arm/boot/dts/uniphier*
F: arch/arm/include/asm/hardware/cache-uniphier.h
F: arch/arm/mach-uniphier/
F: arch/arm/mm/cache-uniphier.c
+F: arch/arm64/boot/dts/socionext/
+F: drivers/bus/uniphier-system-bus.c
F: drivers/i2c/busses/i2c-uniphier*
F: drivers/pinctrl/uniphier/
F: drivers/tty/serial/8250/8250_uniphier.c
@@ -1800,6 +1824,12 @@ S: Maintained
F: drivers/platform/x86/asus*.c
F: drivers/platform/x86/eeepc*.c
+ASUS WIRELESS RADIO CONTROL DRIVER
+M: João Paulo Rechi Vita <jprvita@gmail.com>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/asus-wireless.c
+
ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
R: Dan Williams <dan.j.williams@intel.com>
W: http://sourceforge.net/projects/xscaleiop
@@ -2365,6 +2395,7 @@ M: Brian Norris <computersforpeace@gmail.com>
M: Gregory Fong <gregory.0xf0@gmail.com>
M: Florian Fainelli <f.fainelli@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/stblinux.git
S: Maintained
F: arch/arm/mach-bcm/*brcmstb*
@@ -2438,7 +2469,7 @@ N: bcm88312
BROADCOM BRCMSTB GPIO DRIVER
M: Gregory Fong <gregory.0xf0@gmail.com>
-L: bcm-kernel-feedback-list@broadcom.com>
+L: bcm-kernel-feedback-list@broadcom.com
S: Supported
F: drivers/gpio/gpio-brcmstb.c
F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
@@ -2700,10 +2731,11 @@ F: fs/ceph/
CERTIFICATE HANDLING:
M: David Howells <dhowells@redhat.com>
M: David Woodhouse <dwmw2@infradead.org>
-L: keyrings@linux-nfs.org
+L: keyrings@vger.kernel.org
S: Maintained
F: Documentation/module-signing.txt
F: certs/
+F: scripts/sign-file.c
F: scripts/extract-cert.c
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
@@ -2767,7 +2799,7 @@ S: Maintained
F: Documentation/zh_CN/
CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
-M: Peter Chen <Peter.Chen@freescale.com>
+M: Peter Chen <Peter.Chen@nxp.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
L: linux-usb@vger.kernel.org
S: Maintained
@@ -3752,7 +3784,7 @@ F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
DRM DRIVERS FOR RENESAS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: dri-devel@lists.freedesktop.org
-L: linux-sh@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
T: git git://people.freedesktop.org/~airlied/linux
S: Supported
F: drivers/gpu/drm/rcar-du/
@@ -3775,6 +3807,15 @@ S: Maintained
F: drivers/gpu/drm/sti
F: Documentation/devicetree/bindings/display/st,stih4xx.txt
+DRM DRIVERS FOR VIVANTE GPU IP
+M: Lucas Stach <l.stach@pengutronix.de>
+R: Russell King <linux+etnaviv@arm.linux.org.uk>
+R: Christian Gmeiner <christian.gmeiner@gmail.com>
+L: dri-devel@lists.freedesktop.org
+S: Maintained
+F: drivers/gpu/drm/etnaviv
+F: Documentation/devicetree/bindings/display/etnaviv
+
DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org
@@ -4503,8 +4544,9 @@ F: include/linux/fs_enet_pd.h
FREESCALE QUICC ENGINE LIBRARY
L: linuxppc-dev@lists.ozlabs.org
S: Orphan
-F: arch/powerpc/sysdev/qe_lib/
-F: arch/powerpc/include/asm/*qe.h
+F: drivers/soc/fsl/qe/
+F: include/soc/fsl/*qe*.h
+F: include/soc/fsl/*ucc*.h
FREESCALE USB PERIPHERAL DRIVERS
M: Li Yang <leoli@freescale.com>
@@ -4596,8 +4638,7 @@ F: include/linux/f2fs_fs.h
F: include/trace/events/f2fs.h
FUJITSU FR-V (FRV) PORT
-M: David Howells <dhowells@redhat.com>
-S: Maintained
+S: Orphan
F: arch/frv/
FUJITSU LAPTOP EXTRAS
@@ -4997,6 +5038,7 @@ F: arch/*/include/asm/suspend*.h
HID CORE LAYER
M: Jiri Kosina <jikos@kernel.org>
+R: Benjamin Tissoires <benjamin.tissoires@redhat.com>
L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained
@@ -5051,6 +5093,13 @@ F: include/uapi/linux/if_hippi.h
F: net/802/hippi.c
F: drivers/net/hippi/
+HISILICON SAS Controller
+M: John Garry <john.garry@huawei.com>
+W: http://www.hisilicon.com
+S: Supported
+F: drivers/scsi/hisi_sas/
+F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
+
HOST AP DRIVER
M: Jouni Malinen <j@w1.fi>
L: hostap@shmoo.com (subscribers-only)
@@ -5521,6 +5570,12 @@ T: git git://git.code.sf.net/p/intel-sas/isci
S: Supported
F: drivers/scsi/isci/
+INTEL HID EVENT DRIVER
+M: Alex Hung <alex.hung@canonical.com>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/intel-hid.c
+
INTEL IDLE DRIVER
M: Len Brown <lenb@kernel.org>
L: linux-pm@vger.kernel.org
@@ -5701,12 +5756,23 @@ F: drivers/dma/mic_x100_dma.c
F: drivers/dma/mic_x100_dma.h
F Documentation/mic/
-INTEL PMC IPC DRIVER
+INTEL PMC/P-Unit IPC DRIVER
M: Zha Qipeng<qipeng.zha@intel.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel_pmc_ipc.c
+F: drivers/platform/x86/intel_punit_ipc.c
F: arch/x86/include/asm/intel_pmc_ipc.h
+F: arch/x86/include/asm/intel_punit_ipc.h
+
+INTEL TELEMETRY DRIVER
+M: Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/intel_telemetry_core.c
+F: arch/x86/include/asm/intel_telemetry.h
+F: drivers/platform/x86/intel_telemetry_pltdrv.c
+F: drivers/platform/x86/intel_telemetry_debugfs.c
IOC3 ETHERNET DRIVER
M: Ralf Baechle <ralf@linux-mips.org>
@@ -6449,7 +6515,7 @@ S: Maintained
F: arch/powerpc/platforms/8xx/
LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
-M: Scott Wood <scottwood@freescale.com>
+M: Scott Wood <oss@buserror.net>
M: Kumar Gala <galak@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@lists.ozlabs.org
@@ -6847,7 +6913,7 @@ F: drivers/iio/potentiometer/mcp4531.c
MEDIA DRIVERS FOR RENESAS - VSP1
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
-L: linux-sh@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
S: Supported
F: Documentation/devicetree/bindings/media/renesas,vsp1.txt
@@ -7825,11 +7891,12 @@ F: drivers/usb/*/*omap*
F: arch/arm/*omap*/usb*
OMAP GPIO DRIVER
-M: Javier Martinez Canillas <javier@dowhile0.org>
+M: Grygorii Strashko <grygorii.strashko@ti.com>
M: Santosh Shilimkar <ssantosh@kernel.org>
M: Kevin Hilman <khilman@deeprootsystems.com>
L: linux-omap@vger.kernel.org
S: Maintained
+F: Documentation/devicetree/bindings/gpio/gpio-omap.txt
F: drivers/gpio/gpio-omap.c
OMAP/NEWFLOW NANOBONE MACHINE SUPPORT
@@ -8223,7 +8290,7 @@ F: drivers/pci/host/pci-dra7xx.c
PCI DRIVER FOR RENESAS R-CAR
M: Simon Horman <horms@verge.net.au>
L: linux-pci@vger.kernel.org
-L: linux-sh@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
S: Maintained
F: drivers/pci/host/*rcar*
@@ -8401,7 +8468,7 @@ F: drivers/pinctrl/intel/
PIN CONTROLLER - RENESAS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
M: Geert Uytterhoeven <geert+renesas@glider.be>
-L: linux-sh@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
S: Maintained
F: drivers/pinctrl/sh-pfc/
@@ -8689,6 +8756,12 @@ F: include/sound/pxa2xx-lib.h
F: sound/arm/pxa*
F: sound/soc/pxa/
+PXA GPIO DRIVER
+M: Robert Jarzmik <robert.jarzmik@free.fr>
+L: linux-gpio@vger.kernel.org
+S: Maintained
+F: drivers/gpio/gpio-pxa.c
+
PXA3xx NAND FLASH DRIVER
M: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
L: linux-mtd@lists.infradead.org
@@ -9001,10 +9074,16 @@ F: include/linux/rpmsg.h
RENESAS ETHERNET DRIVERS
R: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
L: netdev@vger.kernel.org
-L: linux-sh@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
F: drivers/net/ethernet/renesas/
F: include/linux/sh_eth.h
+RENESAS USB2 PHY DRIVER
+M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+L: linux-renesas-soc@vger.kernel.org
+S: Maintained
+F: drivers/phy/phy-rcar-gen3-usb2.c
+
RESET CONTROLLER FRAMEWORK
M: Philipp Zabel <p.zabel@pengutronix.de>
S: Maintained
@@ -9285,8 +9364,10 @@ F: drivers/regulator/s5m*.c
F: drivers/clk/clk-s2mps11.c
F: drivers/rtc/rtc-s5m.c
F: include/linux/mfd/samsung/
-F: Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
-F: Documentation/devicetree/bindings/mfd/s2mp*.txt
+F: Documentation/devicetree/bindings/mfd/samsung,sec-core.txt
+F: Documentation/devicetree/bindings/regulator/samsung,s2m*.txt
+F: Documentation/devicetree/bindings/regulator/samsung,s5m*.txt
+F: Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
M: Kyungmin Park <kyungmin.park@samsung.com>
@@ -9996,7 +10077,6 @@ S: Supported
F: drivers/media/pci/solo6x10/
SOFTWARE RAID (Multiple Disks) SUPPORT
-M: Neil Brown <neilb@suse.com>
L: linux-raid@vger.kernel.org
S: Supported
F: drivers/md/
@@ -10786,6 +10866,7 @@ F: net/tipc/
TILE ARCHITECTURE
M: Chris Metcalf <cmetcalf@ezchip.com>
W: http://www.ezchip.com/scm/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git
S: Supported
F: arch/tile/
F: drivers/char/tile-srom.c
@@ -11160,6 +11241,7 @@ F: include/linux/usb/gadget*
USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
M: Jiri Kosina <jikos@kernel.org>
+R: Benjamin Tissoires <benjamin.tissoires@redhat.com>
L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained
@@ -11201,7 +11283,7 @@ F: Documentation/usb/ohci.txt
F: drivers/usb/host/ohci*
USB OTG FSM (Finite State Machine)
-M: Peter Chen <Peter.Chen@freescale.com>
+M: Peter Chen <Peter.Chen@nxp.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
L: linux-usb@vger.kernel.org
S: Maintained
@@ -11672,6 +11754,7 @@ F: drivers/input/tablet/wacom_serial4.c
WATCHDOG DEVICE DRIVERS
M: Wim Van Sebroeck <wim@iguana.be>
+R: Guenter Roeck <linux@roeck-us.net>
L: linux-watchdog@vger.kernel.org
W: http://www.linux-watchdog.org/
T: git git://www.linux-watchdog.org/linux-watchdog.git
@@ -11743,6 +11826,7 @@ F: drivers/input/touchscreen/wm831x-ts.c
F: drivers/input/touchscreen/wm97*.c
F: drivers/mfd/arizona*
F: drivers/mfd/wm*.c
+F: drivers/mfd/cs47l24*
F: drivers/power/wm83*.c
F: drivers/rtc/rtc-wm83*.c
F: drivers/regulator/wm8*.c
@@ -11756,6 +11840,7 @@ F: include/linux/wm97xx.h
F: include/sound/wm????.h
F: sound/soc/codecs/arizona.?
F: sound/soc/codecs/wm*
+F: sound/soc/codecs/cs47l24*
WORKQUEUE
M: Tejun Heo <tj@kernel.org>
diff --git a/Makefile b/Makefile
index 70dea02f1346..7f4ac1ee4a2b 100644
--- a/Makefile
+++ b/Makefile
@@ -495,6 +495,12 @@ ifeq ($(KBUILD_EXTMOD),)
endif
endif
endif
+# install and module_install need also be processed one by one
+ifneq ($(filter install,$(MAKECMDGOALS)),)
+ ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
+ mixed-targets := 1
+ endif
+endif
ifeq ($(mixed-targets),1)
# ===========================================================================
@@ -1259,7 +1265,7 @@ help:
@echo ' firmware_install- Install all firmware to INSTALL_FW_PATH'
@echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
@echo ' dir/ - Build all files in dir and below'
- @echo ' dir/file.[oisS] - Build specified target only'
+ @echo ' dir/file.[ois] - Build specified target only'
@echo ' dir/file.lst - Build specified mixed source/assembly target only'
@echo ' (requires a recent binutils and recent build (System.map))'
@echo ' dir/file.ko - Build module including final link'
diff --git a/arch/Kconfig b/arch/Kconfig
index 4e949e58b192..ba1b626bca00 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -511,6 +511,74 @@ config ARCH_HAS_ELF_RANDOMIZE
- arch_mmap_rnd()
- arch_randomize_brk()
+config HAVE_ARCH_MMAP_RND_BITS
+ bool
+ help
+ An arch should select this symbol if it supports setting a variable
+ number of bits for use in establishing the base address for mmap
+ allocations, has MMU enabled and provides values for both:
+ - ARCH_MMAP_RND_BITS_MIN
+ - ARCH_MMAP_RND_BITS_MAX
+
+config ARCH_MMAP_RND_BITS_MIN
+ int
+
+config ARCH_MMAP_RND_BITS_MAX
+ int
+
+config ARCH_MMAP_RND_BITS_DEFAULT
+ int
+
+config ARCH_MMAP_RND_BITS
+ int "Number of bits to use for ASLR of mmap base address" if EXPERT
+ range ARCH_MMAP_RND_BITS_MIN ARCH_MMAP_RND_BITS_MAX
+ default ARCH_MMAP_RND_BITS_DEFAULT if ARCH_MMAP_RND_BITS_DEFAULT
+ default ARCH_MMAP_RND_BITS_MIN
+ depends on HAVE_ARCH_MMAP_RND_BITS
+ help
+ This value can be used to select the number of bits to use to
+ determine the random offset to the base address of vma regions
+ resulting from mmap allocations. This value will be bounded
+ by the architecture's minimum and maximum supported values.
+
+ This value can be changed after boot using the
+ /proc/sys/vm/mmap_rnd_bits tunable
+
+config HAVE_ARCH_MMAP_RND_COMPAT_BITS
+ bool
+ help
+ An arch should select this symbol if it supports running applications
+ in compatibility mode, supports setting a variable number of bits for
+ use in establishing the base address for mmap allocations, has MMU
+ enabled and provides values for both:
+ - ARCH_MMAP_RND_COMPAT_BITS_MIN
+ - ARCH_MMAP_RND_COMPAT_BITS_MAX
+
+config ARCH_MMAP_RND_COMPAT_BITS_MIN
+ int
+
+config ARCH_MMAP_RND_COMPAT_BITS_MAX
+ int
+
+config ARCH_MMAP_RND_COMPAT_BITS_DEFAULT
+ int
+
+config ARCH_MMAP_RND_COMPAT_BITS
+ int "Number of bits to use for ASLR of mmap base address for compatible applications" if EXPERT
+ range ARCH_MMAP_RND_COMPAT_BITS_MIN ARCH_MMAP_RND_COMPAT_BITS_MAX
+ default ARCH_MMAP_RND_COMPAT_BITS_DEFAULT if ARCH_MMAP_RND_COMPAT_BITS_DEFAULT
+ default ARCH_MMAP_RND_COMPAT_BITS_MIN
+ depends on HAVE_ARCH_MMAP_RND_COMPAT_BITS
+ help
+ This value can be used to select the number of bits to use to
+ determine the random offset to the base address of vma regions
+ resulting from mmap allocations for compatible applications This
+ value will be bounded by the architecture's minimum and maximum
+ supported values.
+
+ This value can be changed after boot using the
+ /proc/sys/vm/mmap_rnd_compat_bits tunable
+
config HAVE_COPY_THREAD_TLS
bool
help
diff --git a/arch/alpha/include/uapi/asm/mman.h b/arch/alpha/include/uapi/asm/mman.h
index f2f949671798..ab336c06153e 100644
--- a/arch/alpha/include/uapi/asm/mman.h
+++ b/arch/alpha/include/uapi/asm/mman.h
@@ -47,8 +47,10 @@
#define MADV_WILLNEED 3 /* will need these pages */
#define MADV_SPACEAVAIL 5 /* ensure resources are available */
#define MADV_DONTNEED 6 /* don't need these pages */
+#define MADV_FREE 7 /* free pages only if memory pressure */
/* common/generic parameters */
+#define MADV_FREE 8 /* free pages only if memory pressure */
#define MADV_REMOVE 9 /* remove these pages & resources */
#define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */
diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c
index 2fd00b7077e4..936bc8f89a67 100644
--- a/arch/alpha/kernel/module.c
+++ b/arch/alpha/kernel/module.c
@@ -160,7 +160,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
/* The small sections were sorted to the end of the segment.
The following should definitely cover them. */
- gp = (u64)me->module_core + me->core_size - 0x8000;
+ gp = (u64)me->core_layout.base + me->core_layout.size - 0x8000;
got = sechdrs[me->arch.gotsecindex].sh_addr;
for (i = 0; i < n; i++) {
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 6312f607932f..76dde9db7934 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -73,9 +73,6 @@ config STACKTRACE_SUPPORT
def_bool y
select STACKTRACE
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
def_bool y
depends on ARC_MMU_V4
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 5eb707640e9c..0587bf121d11 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -385,8 +385,8 @@ void *unwind_add_table(struct module *module, const void *table_start,
return NULL;
init_unwind_table(table, module->name,
- module->module_core, module->core_size,
- module->module_init, module->init_size,
+ module->core_layout.base, module->core_layout.size,
+ module->init_layout.base, module->init_layout.size,
table_start, table_size,
NULL, 0);
diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c
index ff7ff6cbb811..b65f797e9ad6 100644
--- a/arch/arc/mm/cache.c
+++ b/arch/arc/mm/cache.c
@@ -617,7 +617,7 @@ void flush_dcache_page(struct page *page)
*/
if (!mapping_mapped(mapping)) {
clear_bit(PG_dc_clean, &page->flags);
- } else if (page_mapped(page)) {
+ } else if (page_mapcount(page)) {
/* kernel reading from page with U-mapping */
phys_addr_t paddr = (unsigned long)page_address(page);
@@ -857,7 +857,7 @@ void copy_user_highpage(struct page *to, struct page *from,
* For !VIPT cache, all of this gets compiled out as
* addr_not_cache_congruent() is 0
*/
- if (page_mapped(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
+ if (page_mapcount(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
__flush_dcache_page((unsigned long)kfrom, u_vaddr);
clean_src_k_mappings = 1;
}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 426115f7cb63..37c7951ca4f5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2,6 +2,7 @@ config ARM
bool
default y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAVE_CUSTOM_GPIO_H
@@ -36,6 +37,7 @@ config ARM
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
+ select HAVE_ARCH_MMAP_RND_BITS if MMU
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_TRACEHOOK
select HAVE_ARM_SMCCC if CPU_V7
@@ -166,11 +168,6 @@ config STACKTRACE_SUPPORT
bool
default y
-config HAVE_LATENCYTOP_SUPPORT
- bool
- depends on !SMP
- default y
-
config LOCKDEP_SUPPORT
bool
default y
@@ -243,7 +240,6 @@ config ARM_PATCH_PHYS_VIRT
bool "Patch physical to virtual translations at runtime" if EMBEDDED
default y
depends on !XIP_KERNEL && MMU
- depends on !ARCH_REALVIEW || !SPARSEMEM
help
Patch phys-to-virt and virt-to-phys translation functions at
boot and module load time according to the position of the
@@ -310,13 +306,21 @@ config MMU
Select if you want MMU-based virtualised addressing space
support by paged memory management. If unsure, say 'Y'.
+config ARCH_MMAP_RND_BITS_MIN
+ default 8
+
+config ARCH_MMAP_RND_BITS_MAX
+ default 14 if PAGE_OFFSET=0x40000000
+ default 15 if PAGE_OFFSET=0x80000000
+ default 16
+
#
# The "ARM system type" choice list is ordered alphabetically by option
# text. Please add new entries in the option alphabetic order.
#
choice
prompt "ARM system type"
- default ARCH_VERSATILE if !MMU
+ default ARM_SINGLE_ARMV7M if !MMU
default ARCH_MULTIPLATFORM if MMU
config ARCH_MULTIPLATFORM
@@ -348,38 +352,6 @@ config ARM_SINGLE_ARMV7M
select SPARSE_IRQ
select USE_OF
-config ARCH_REALVIEW
- bool "ARM Ltd. RealView family"
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select ARM_AMBA
- select ARM_TIMER_SP804
- select COMMON_CLK
- select COMMON_CLK_VERSATILE
- select GENERIC_CLOCKEVENTS
- select GPIO_PL061 if GPIOLIB
- select ICST
- select NEED_MACH_MEMORY_H
- select PLAT_VERSATILE
- select PLAT_VERSATILE_SCHED_CLOCK
- help
- This enables support for ARM Ltd RealView boards.
-
-config ARCH_VERSATILE
- bool "ARM Ltd. Versatile family"
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select ARM_AMBA
- select ARM_TIMER_SP804
- select ARM_VIC
- select CLKDEV_LOOKUP
- select GENERIC_CLOCKEVENTS
- select HAVE_MACH_CLKDEV
- select ICST
- select PLAT_VERSATILE
- select PLAT_VERSATILE_CLOCK
- select PLAT_VERSATILE_SCHED_CLOCK
- select VERSATILE_FPGA_IRQ
- help
- This enables support for ARM Ltd Versatile board.
config ARCH_CLPS711X
bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
@@ -514,55 +486,15 @@ config ARCH_DOVE
select CPU_PJ4
select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_PCI
+ select MULTI_IRQ_HANDLER
select MVEBU_MBUS
select PINCTRL
select PINCTRL_DOVE
select PLAT_ORION_LEGACY
- help
- Support for the Marvell Dove SoC 88AP510
-
-config ARCH_MV78XX0
- bool "Marvell MV78xx0"
- select ARCH_REQUIRE_GPIOLIB
- select CPU_FEROCEON
- select GENERIC_CLOCKEVENTS
- select MVEBU_MBUS
- select PCI
- select PLAT_ORION_LEGACY
- help
- Support for the following Marvell MV78xx0 series SoCs:
- MV781x0, MV782x0.
-
-config ARCH_ORION5X
- bool "Marvell Orion"
- depends on MMU
- select ARCH_REQUIRE_GPIOLIB
- select CPU_FEROCEON
- select GENERIC_CLOCKEVENTS
- select MVEBU_MBUS
- select PCI
- select PLAT_ORION_LEGACY
- select MULTI_IRQ_HANDLER
- help
- Support for the following Marvell Orion 5x series SoCs:
- Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
- Orion-2 (5281), Orion-1-90 (6183).
-
-config ARCH_MMP
- bool "Marvell PXA168/910/MMP2"
- depends on MMU
- select ARCH_REQUIRE_GPIOLIB
- select CLKDEV_LOOKUP
- select GENERIC_ALLOCATOR
- select GENERIC_CLOCKEVENTS
- select GPIO_PXA
- select IRQ_DOMAIN
- select MULTI_IRQ_HANDLER
- select PINCTRL
- select PLAT_PXA
select SPARSE_IRQ
+ select PM_GENERIC_DOMAINS if PM
help
- Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
+ Support for the Marvell Dove SoC 88AP510
config ARCH_KS8695
bool "Micrel/Kendin KS8695"
@@ -687,32 +619,6 @@ config ARCH_S3C24XX
(<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or the
Samsung SMDK2410 development board (and derivatives).
-config ARCH_S3C64XX
- bool "Samsung S3C64XX"
- select ARCH_REQUIRE_GPIOLIB
- select ARM_AMBA
- select ARM_VIC
- select ATAGS
- select CLKDEV_LOOKUP
- select CLKSRC_SAMSUNG_PWM
- select COMMON_CLK_SAMSUNG
- select CPU_V6K
- select GENERIC_CLOCKEVENTS
- select GPIO_SAMSUNG
- select HAVE_S3C2410_I2C if I2C
- select HAVE_S3C2410_WATCHDOG if WATCHDOG
- select HAVE_TCM
- select NO_IOPORT_MAP
- select PLAT_SAMSUNG
- select PM_GENERIC_DOMAINS if PM
- select S3C_DEV_NAND
- select S3C_GPIO_TRACK
- select SAMSUNG_ATAGS
- select SAMSUNG_WAKEMASK
- select SAMSUNG_WDT_RESET
- help
- Samsung S3C64XX series based systems
-
config ARCH_DAVINCI
bool "TI DaVinci"
select ARCH_HAS_HOLES_MEMORYMODEL
@@ -801,7 +707,8 @@ config ARCH_MULTI_CPU_AUTO
endmenu
config ARCH_VIRT
- bool "Dummy Virtual Machine" if ARCH_MULTI_V7
+ bool "Dummy Virtual Machine"
+ depends on ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
select ARM_GIC_V2M if PCI_MSI
@@ -924,6 +831,8 @@ source "arch/arm/mach-sunxi/Kconfig"
source "arch/arm/mach-prima2/Kconfig"
+source "arch/arm/mach-tango/Kconfig"
+
source "arch/arm/mach-tegra/Kconfig"
source "arch/arm/mach-u300/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 259c0ca9c99a..5c0e5cc8ed10 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -15,20 +15,6 @@ config ARM_PTDUMP
kernel.
If in doubt, say "N"
-config STRICT_DEVMEM
- bool "Filter access to /dev/mem"
- depends on MMU
- ---help---
- If this option is disabled, you allow userspace (root) access to all
- of memory, including kernel and userspace memory. Accidental
- access to this is obviously disastrous, but specific access can
- be used by people debugging the kernel.
-
- If this option is switched on, the /dev/mem file only allows
- userspace access to memory mapped peripherals.
-
- If in doubt, say Y.
-
# RMK wants arm kernels compiled with frame pointers or stack unwinding.
# If you know what you are doing and are willing to live without stack
# traces, you can get a slightly smaller kernel by setting this option to
@@ -143,7 +129,12 @@ choice
config DEBUG_BCM2835
bool "Kernel low-level debugging on BCM2835 PL011 UART"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 && ARCH_MULTI_V6
+ select DEBUG_UART_PL01X
+
+ config DEBUG_BCM2836
+ bool "Kernel low-level debugging on BCM2836 PL011 UART"
+ depends on ARCH_BCM2835 && ARCH_MULTI_V7
select DEBUG_UART_PL01X
config DEBUG_BCM_5301X
@@ -232,23 +223,6 @@ choice
Say Y here if you want the debug print routines to direct
their output to UART0 serial port on DaVinci DMx devices.
- config DEBUG_ZYNQ_UART0
- bool "Kernel low-level debugging on Xilinx Zynq using UART0"
- depends on ARCH_ZYNQ
- help
- Say Y here if you want the debug print routines to direct
- their output to UART0 on the Zynq platform.
-
- config DEBUG_ZYNQ_UART1
- bool "Kernel low-level debugging on Xilinx Zynq using UART1"
- depends on ARCH_ZYNQ
- help
- Say Y here if you want the debug print routines to direct
- their output to UART1 on the Zynq platform.
-
- If you have a ZC702 board and want early boot messages to
- appear on the USB serial adaptor, select this option.
-
config DEBUG_DC21285_PORT
bool "Kernel low-level debugging messages via footbridge serial port"
depends on FOOTBRIDGE
@@ -263,13 +237,30 @@ choice
Say Y here if you want the debug print routines to direct
their output to the UA0 serial port in the CX92755.
+ config DEBUG_EP93XX
+ bool "Kernel low-level debugging messages via ep93xx UART"
+ depends on ARCH_EP93XX
+ select DEBUG_UART_PL01X
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Cirrus Logic EP93xx based platforms.
+
config DEBUG_FOOTBRIDGE_COM1
bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
depends on FOOTBRIDGE
+ select DEBUG_UART_8250
help
Say Y here if you want the debug print routines to direct
their output to the 8250 at PCI COM1.
+ config DEBUG_GEMINI
+ bool "Kernel low-level debugging messages via Cortina Systems Gemini UART"
+ depends on ARCH_GEMINI
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Cortina Gemini based platforms.
+
config DEBUG_HI3620_UART
bool "Hisilicon HI3620 Debug UART"
depends on ARCH_HI3xxx
@@ -425,6 +416,14 @@ choice
Say Y here if you want kernel low-level debugging support
on i.MX7D.
+ config DEBUG_INTEGRATOR
+ bool "Kernel low-level debugging messages via ARM Integrator UART"
+ depends on ARCH_INTEGRATOR
+ select DEBUG_UART_PL01X
+ help
+ Say Y here if you want kernel low-level debugging support
+ on ARM Integrator platforms.
+
config DEBUG_KEYSTONE_UART0
bool "Kernel low-level debugging on KEYSTONE2 using UART0"
depends on ARCH_KEYSTONE
@@ -456,6 +455,14 @@ choice
Say Y here if you want kernel low-level debugging support
on NXP LPC18xx/43xx UART0.
+ config DEBUG_LPC32XX
+ bool "Kernel low-level debugging messages via NXP LPC32xx UART"
+ depends on ARCH_LPC32XX
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ on NXP LPC32xx based platforms.
+
config DEBUG_MESON_UARTAO
bool "Kernel low-level debugging via Meson6 UARTAO"
depends on ARCH_MESON
@@ -479,26 +486,10 @@ choice
Say Y here if you want kernel low-level debugging support
on MMP UART3.
- config DEBUG_QCOM_UARTDM
- bool "Kernel low-level debugging messages via QCOM UARTDM"
- depends on ARCH_QCOM
- help
- Say Y here if you want the debug print routines to direct
- their output to the serial port on Qualcomm devices.
-
- ARCH DEBUG_UART_PHYS DEBUG_UART_VIRT
- APQ8064 0x16640000 0xf0040000
- APQ8084 0xf995e000 0xfa75e000
- MSM8X60 0x19c40000 0xf0040000
- MSM8960 0x16440000 0xf0040000
- MSM8974 0xf991e000 0xfa71e000
-
- Please adjust DEBUG_UART_PHYS and DEBUG_UART_BASE configuration
- options based on your needs.
-
config DEBUG_MVEBU_UART0
bool "Kernel low-level debugging messages via MVEBU UART0 (old bootloaders)"
depends on ARCH_MVEBU
+ depends on ARCH_MVEBU && CPU_V7
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
@@ -511,17 +502,23 @@ choice
Plathome OpenBlocks AX3, when using the original
bootloader.
+ This option will not work on older Marvell platforms
+ (Kirkwood, Dove, MV78xx0, Orion5x), which should pick
+ the "new bootloader" variant.
+
If the wrong DEBUG_MVEBU_UART* option is selected,
when u-boot hands over to the kernel, the system
silently crashes, with no serial output at all.
config DEBUG_MVEBU_UART0_ALTERNATE
bool "Kernel low-level debugging messages via MVEBU UART0 (new bootloaders)"
- depends on ARCH_MVEBU
+ depends on ARCH_MVEBU || ARCH_DOVE || ARCH_MV78XX0 || ARCH_ORION5X
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
- on MVEBU based platforms on UART0.
+ on MVEBU based platforms on UART0. (Armada XP, Armada 3xx,
+ Kirkwood, Dove, MV78xx0, Orion5x).
+
This option should be used with the new bootloaders
that remap the internal registers at 0xf1000000.
@@ -536,21 +533,41 @@ choice
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
- on MVEBU based platforms on UART1.
+ on MVEBU based platforms on UART1. (Armada XP, Armada 3xx,
+ Kirkwood, Dove, MV78xx0, Orion5x).
This option should be used with the new bootloaders
that remap the internal registers at 0xf1000000.
+ All of the older (pre Armada XP/370) platforms also use
+ this address, regardless of the boot loader version.
If the wrong DEBUG_MVEBU_UART* option is selected,
when u-boot hands over to the kernel, the system
silently crashes, with no serial output at all.
- config DEBUG_VF_UART
- bool "Vybrid UART"
- depends on SOC_VF610
+ config DEBUG_MT6589_UART0
+ bool "Mediatek mt6589 UART0"
+ depends on ARCH_MEDIATEK
+ select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
- on Vybrid based platforms.
+ for Mediatek mt6589 based platforms on UART0.
+
+ config DEBUG_MT8127_UART0
+ bool "Mediatek mt8127/mt6592 UART0"
+ depends on ARCH_MEDIATEK
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ for Mediatek mt8127 based platforms on UART0.
+
+ config DEBUG_MT8135_UART3
+ bool "Mediatek mt8135 UART3"
+ depends on ARCH_MEDIATEK
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ for Mediatek mt8135 based platforms on UART3.
config DEBUG_NETX_UART
bool "Kernel low-level debugging messages via NetX UART"
@@ -714,6 +731,23 @@ choice
Say Y here if you want kernel low-level debugging support
on PXA UART1.
+ config DEBUG_QCOM_UARTDM
+ bool "Kernel low-level debugging messages via QCOM UARTDM"
+ depends on ARCH_QCOM
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on Qualcomm devices.
+
+ ARCH DEBUG_UART_PHYS DEBUG_UART_VIRT
+ APQ8064 0x16640000 0xf0040000
+ APQ8084 0xf995e000 0xfa75e000
+ MSM8X60 0x19c40000 0xf0040000
+ MSM8960 0x16440000 0xf0040000
+ MSM8974 0xf991e000 0xfa71e000
+
+ Please adjust DEBUG_UART_PHYS and DEBUG_UART_BASE configuration
+ options based on your needs.
+
config DEBUG_REALVIEW_STD_PORT
bool "RealView Default UART"
depends on ARCH_REALVIEW
@@ -857,6 +891,7 @@ choice
depends on PLAT_SAMSUNG
select DEBUG_EXYNOS_UART if ARCH_EXYNOS
select DEBUG_S3C24XX_UART if ARCH_S3C24XX
+ select DEBUG_S3C64XX_UART if ARCH_S3C64XX
select DEBUG_S5PV210_UART if ARCH_S5PV210
bool "Use Samsung S3C UART 0 for low-level debug"
help
@@ -868,6 +903,7 @@ choice
depends on PLAT_SAMSUNG
select DEBUG_EXYNOS_UART if ARCH_EXYNOS
select DEBUG_S3C24XX_UART if ARCH_S3C24XX
+ select DEBUG_S3C64XX_UART if ARCH_S3C64XX
select DEBUG_S5PV210_UART if ARCH_S5PV210
bool "Use Samsung S3C UART 1 for low-level debug"
help
@@ -879,6 +915,7 @@ choice
depends on PLAT_SAMSUNG
select DEBUG_EXYNOS_UART if ARCH_EXYNOS
select DEBUG_S3C24XX_UART if ARCH_S3C24XX
+ select DEBUG_S3C64XX_UART if ARCH_S3C64XX
select DEBUG_S5PV210_UART if ARCH_S5PV210
bool "Use Samsung S3C UART 2 for low-level debug"
help
@@ -889,6 +926,7 @@ choice
config DEBUG_S3C_UART3
depends on PLAT_SAMSUNG && (ARCH_EXYNOS || ARCH_S5PV210)
select DEBUG_EXYNOS_UART if ARCH_EXYNOS
+ select DEBUG_S3C64XX_UART if ARCH_S3C64XX
select DEBUG_S5PV210_UART if ARCH_S5PV210
bool "Use Samsung S3C UART 3 for low-level debug"
help
@@ -980,6 +1018,70 @@ choice
Say Y here if you want kernel low-level debugging support
on Allwinner A31/A23 based platforms on the R_UART.
+ config DEBUG_SIRFPRIMA2_UART1
+ bool "Kernel low-level debugging messages via SiRFprimaII UART1"
+ depends on ARCH_PRIMA2
+ select DEBUG_SIRFSOC_UART
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the uart1 port on SiRFprimaII devices.
+
+ config DEBUG_SIRFATLAS7_UART0
+ bool "Kernel low-level debugging messages via SiRFatlas7 UART0"
+ depends on ARCH_ATLAS7
+ select DEBUG_SIRFSOC_UART
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the uart0 port on SiRFATLAS7 devices.The uart0
+ is used on SiRFATLAS7 as a extra debug port.sometimes an extra
+ debug port can be very useful.
+
+ config DEBUG_SIRFATLAS7_UART1
+ bool "Kernel low-level debugging messages via SiRFatlas7 UART1"
+ depends on ARCH_ATLAS7
+ select DEBUG_SIRFSOC_UART
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the uart1 port on SiRFATLAS7 devices.
+
+ config DEBUG_SPEAR3XX
+ bool "Kernel low-level debugging messages via ST SPEAr 3xx/6xx UART"
+ depends on ARCH_SPEAR3XX || ARCH_SPEAR6XX
+ select DEBUG_UART_PL01X
+ help
+ Say Y here if you want kernel low-level debugging support
+ on ST SPEAr based platforms.
+
+ config DEBUG_SPEAR13XX
+ bool "Kernel low-level debugging messages via ST SPEAr 13xx UART"
+ depends on ARCH_SPEAR13XX
+ select DEBUG_UART_PL01X
+ help
+ Say Y here if you want kernel low-level debugging support
+ on ST SPEAr13xx based platforms.
+
+ config STIH41X_DEBUG_ASC2
+ bool "Use StiH415/416 ASC2 UART for low-level debug"
+ depends on ARCH_STI
+ select DEBUG_STI_UART
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STiH415/416 based platforms like b2000, which has
+ default UART wired up to ASC2.
+
+ If unsure, say N.
+
+ config STIH41X_DEBUG_SBC_ASC1
+ bool "Use StiH415/416 SBC ASC1 UART for low-level debug"
+ depends on ARCH_STI
+ select DEBUG_STI_UART
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STiH415/416 based platforms like b2020. which has
+ default UART wired up to SBC ASC1.
+
+ If unsure, say N.
+
config TEGRA_DEBUG_UART_AUTO_ODMDATA
bool "Kernel low-level debugging messages via Tegra UART via ODMDATA"
depends on ARCH_TEGRA
@@ -1032,54 +1134,6 @@ choice
Say Y here if you want kernel low-level debugging support
on Tegra based platforms.
- config DEBUG_SIRFPRIMA2_UART1
- bool "Kernel low-level debugging messages via SiRFprimaII UART1"
- depends on ARCH_PRIMA2
- select DEBUG_SIRFSOC_UART
- help
- Say Y here if you want the debug print routines to direct
- their output to the uart1 port on SiRFprimaII devices.
-
- config DEBUG_SIRFATLAS7_UART0
- bool "Kernel low-level debugging messages via SiRFatlas7 UART0"
- depends on ARCH_ATLAS7
- select DEBUG_SIRFSOC_UART
- help
- Say Y here if you want the debug print routines to direct
- their output to the uart0 port on SiRFATLAS7 devices.The uart0
- is used on SiRFATLAS7 as a extra debug port.sometimes an extra
- debug port can be very useful.
-
- config DEBUG_SIRFATLAS7_UART1
- bool "Kernel low-level debugging messages via SiRFatlas7 UART1"
- depends on ARCH_ATLAS7
- select DEBUG_SIRFSOC_UART
- help
- Say Y here if you want the debug print routines to direct
- their output to the uart1 port on SiRFATLAS7 devices.
-
- config STIH41X_DEBUG_ASC2
- bool "Use StiH415/416 ASC2 UART for low-level debug"
- depends on ARCH_STI
- select DEBUG_STI_UART
- help
- Say Y here if you want kernel low-level debugging support
- on STiH415/416 based platforms like b2000, which has
- default UART wired up to ASC2.
-
- If unsure, say N.
-
- config STIH41X_DEBUG_SBC_ASC1
- bool "Use StiH415/416 SBC ASC1 UART for low-level debug"
- depends on ARCH_STI
- select DEBUG_STI_UART
- help
- Say Y here if you want kernel low-level debugging support
- on STiH415/416 based platforms like b2020. which has
- default UART wired up to SBC ASC1.
-
- If unsure, say N.
-
config DEBUG_U300_UART
bool "Kernel low-level debugging messages via U300 UART0"
depends on ARCH_U300
@@ -1095,29 +1149,13 @@ choice
Say Y here if you want kernel low-level debugging support
on Ux500 based platforms.
- config DEBUG_MT6589_UART0
- bool "Mediatek mt6589 UART0"
- depends on ARCH_MEDIATEK
- select DEBUG_UART_8250
- help
- Say Y here if you want kernel low-level debugging support
- for Mediatek mt6589 based platforms on UART0.
-
- config DEBUG_MT8127_UART0
- bool "Mediatek mt8127/mt6592 UART0"
- depends on ARCH_MEDIATEK
- select DEBUG_UART_8250
- help
- Say Y here if you want kernel low-level debugging support
- for Mediatek mt8127 based platforms on UART0.
-
- config DEBUG_MT8135_UART3
- bool "Mediatek mt8135 UART3"
- depends on ARCH_MEDIATEK
- select DEBUG_UART_8250
+ config DEBUG_VERSATILE
+ bool "Kernel low-level debugging messages via ARM Versatile UART"
+ depends on ARCH_VERSATILE
+ select DEBUG_UART_PL01X
help
Say Y here if you want kernel low-level debugging support
- for Mediatek mt8135 based platforms on UART3.
+ on ARM Versatile platforms.
config DEBUG_VEXPRESS_UART0_DETECT
bool "Autodetect UART0 on Versatile Express Cortex-A core tiles"
@@ -1155,6 +1193,13 @@ choice
This option selects UART0 at 0xb0090000. This is appropriate for
Cortex-R series tiles and SMMs, such as Cortex-R5 and Cortex-R7
+ config DEBUG_VF_UART
+ bool "Vybrid UART"
+ depends on SOC_VF610
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Vybrid based platforms.
+
config DEBUG_VT8500_UART0
bool "Use UART0 on VIA/Wondermedia SoCs"
depends on ARCH_VT8500
@@ -1162,6 +1207,35 @@ choice
This option selects UART0 on VIA/Wondermedia System-on-a-chip
devices, including VT8500, WM8505, WM8650 and WM8850.
+ config DEBUG_ZTE_ZX
+ bool "Use ZTE ZX UART"
+ select DEBUG_UART_PL01X
+ depends on ARCH_ZX
+ help
+ Say Y here if you are enabling ZTE ZX296702 SOC and need
+ debug uart support.
+
+ This option is preferred over the platform specific
+ options; the platform specific options are deprecated
+ and will be soon removed.
+
+ config DEBUG_ZYNQ_UART0
+ bool "Kernel low-level debugging on Xilinx Zynq using UART0"
+ depends on ARCH_ZYNQ
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to UART0 on the Zynq platform.
+
+ config DEBUG_ZYNQ_UART1
+ bool "Kernel low-level debugging on Xilinx Zynq using UART1"
+ depends on ARCH_ZYNQ
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to UART1 on the Zynq platform.
+
+ If you have a ZC702 board and want early boot messages to
+ appear on the USB serial adaptor, select this option.
+
config DEBUG_ICEDCC
bool "Kernel low-level debugging via EmbeddedICE DCC channel"
help
@@ -1189,18 +1263,6 @@ choice
For more details about semihosting, please see
chapter 8 of DUI0203I_rvct_developer_guide.pdf from ARM Ltd.
- config DEBUG_ZTE_ZX
- bool "Use ZTE ZX UART"
- select DEBUG_UART_PL01X
- depends on ARCH_ZX
- help
- Say Y here if you are enabling ZTE ZX296702 SOC and need
- debug uart support.
-
- This option is preferred over the platform specific
- options; the platform specific options are deprecated
- and will be soon removed.
-
config DEBUG_LL_UART_8250
bool "Kernel low-level debugging via 8250 UART"
help
@@ -1253,6 +1315,9 @@ config DEBUG_S3C2410_UART
config DEBUG_S3C24XX_UART
bool
+config DEBUG_S3C64XX_UART
+ bool
+
config DEBUG_S5PV210_UART
bool
@@ -1308,6 +1373,7 @@ config DEBUG_LL_INCLUDE
default "debug/at91.S" if DEBUG_AT91_UART
default "debug/asm9260.S" if DEBUG_ASM9260_UART
default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2
+ default "debug/dc21285.S" if DEBUG_DC21285_PORT
default "debug/meson.S" if DEBUG_MESON_UARTAO
default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X
default "debug/exynos.S" if DEBUG_EXYNOS_UART
@@ -1338,7 +1404,7 @@ config DEBUG_LL_INCLUDE
default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA0
default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA1
default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4
- default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART
+ default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART || DEBUG_S3C64XX_UART
default "debug/s5pv210.S" if DEBUG_S5PV210_UART
default "debug/sirf.S" if DEBUG_SIRFSOC_UART
default "debug/sti.S" if DEBUG_STI_UART
@@ -1358,11 +1424,9 @@ config DEBUG_UART_PL01X
# Compatibility options for 8250
config DEBUG_UART_8250
- def_bool ARCH_DOVE || ARCH_EBSA110 || \
- (FOOTBRIDGE && !DEBUG_DC21285_PORT) || \
- ARCH_GEMINI || ARCH_IOP13XX || ARCH_IOP32X || \
- ARCH_IOP33X || ARCH_IXP4XX || \
- ARCH_LPC32XX || ARCH_MV78XX0 || ARCH_ORION5X || ARCH_RPC
+ def_bool ARCH_EBSA110 || \
+ ARCH_IOP13XX || ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || \
+ ARCH_RPC
# Compatibility options for BCM63xx
config DEBUG_UART_BCM63XX
@@ -1387,12 +1451,12 @@ config DEBUG_UART_PHYS
default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT
default 0x10124000 if DEBUG_RK3X_UART0
default 0x10126000 if DEBUG_RK3X_UART1
- default 0x101f1000 if ARCH_VERSATILE
+ default 0x101f1000 if DEBUG_VERSATILE
default 0x101fb000 if DEBUG_NOMADIK_UART
default 0x11002000 if DEBUG_MT8127_UART0
default 0x11006000 if DEBUG_MT6589_UART0
default 0x11009000 if DEBUG_MT8135_UART3
- default 0x16000000 if ARCH_INTEGRATOR
+ default 0x16000000 if DEBUG_INTEGRATOR
default 0x18000300 if DEBUG_BCM_5301X
default 0x18010000 if DEBUG_SIRFATLAS7_UART0
default 0x18020000 if DEBUG_SIRFATLAS7_UART1
@@ -1402,12 +1466,13 @@ config DEBUG_UART_PHYS
default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
default 0x20068000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
default 0x20201000 if DEBUG_BCM2835
+ default 0x3f201000 if DEBUG_BCM2836
default 0x3e000000 if DEBUG_BCM_KONA_UART
default 0x4000e400 if DEBUG_LL_UART_EFM32
default 0x40081000 if DEBUG_LPC18XX_UART0
- default 0x40090000 if ARCH_LPC32XX
+ default 0x40090000 if DEBUG_LPC32XX
default 0x40100000 if DEBUG_PXA_UART1
- default 0x42000000 if ARCH_GEMINI
+ default 0x42000000 if DEBUG_GEMINI
default 0x50000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \
DEBUG_S3C2410_UART0)
default 0x50004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \
@@ -1415,24 +1480,28 @@ config DEBUG_UART_PHYS
default 0x50008000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART2 || \
DEBUG_S3C2410_UART2)
default 0x78000000 if DEBUG_CNS3XXX
- default 0x7c0003f8 if FOOTBRIDGE
+ default 0x7c0003f8 if DEBUG_FOOTBRIDGE_COM1
+ default 0x7f005000 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART0
+ default 0x7f005400 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART1
+ default 0x7f005800 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART2
+ default 0x7f005c00 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART3
default 0x80010000 if DEBUG_ASM9260_UART
default 0x80070000 if DEBUG_IMX23_UART
default 0x80074000 if DEBUG_IMX28_UART
default 0x80230000 if DEBUG_PICOXCELL_UART
- default 0x808c0000 if ARCH_EP93XX
+ default 0x808c0000 if DEBUG_EP93XX || ARCH_EP93XX
default 0x90020000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
default 0xb0060000 if DEBUG_SIRFPRIMA2_UART1
default 0xb0090000 if DEBUG_VEXPRESS_UART0_CRX
default 0xc0013000 if DEBUG_U300_UART
default 0xc8000000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
default 0xc8000003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
- default 0xd0000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
+ default 0xd0000000 if DEBUG_SPEAR3XX
default 0xd0012000 if DEBUG_MVEBU_UART0
default 0xc81004c0 if DEBUG_MESON_UARTAO
default 0xd4017000 if DEBUG_MMP_UART2
default 0xd4018000 if DEBUG_MMP_UART3
- default 0xe0000000 if ARCH_SPEAR13XX
+ default 0xe0000000 if DEBUG_SPEAR13XX
default 0xe4007000 if DEBUG_HIP04_UART
default 0xe6c40000 if DEBUG_RMOBILE_SCIFA0
default 0xe6c50000 if DEBUG_RMOBILE_SCIFA1
@@ -1444,8 +1513,6 @@ config DEBUG_UART_PHYS
default 0xf040ab00 if DEBUG_BRCMSTB_UART
default 0xf1012000 if DEBUG_MVEBU_UART0_ALTERNATE
default 0xf1012100 if DEBUG_MVEBU_UART1_ALTERNATE
- default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \
- ARCH_ORION5X
default 0xf7fc9000 if DEBUG_BERLIN_UART
default 0xf8b00000 if DEBUG_HIX5HD2_UART
default 0xf991e000 if DEBUG_QCOM_UARTDM
@@ -1474,6 +1541,7 @@ config DEBUG_UART_PHYS
DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \
DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
+ DEBUG_S3C64XX_UART || \
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
DEBUG_AT91_UART
@@ -1485,22 +1553,27 @@ config DEBUG_UART_VIRT
default 0xf0000be0 if ARCH_EBSA110
default 0xf0010000 if DEBUG_ASM9260_UART
default 0xf01fb000 if DEBUG_NOMADIK_UART
- default 0xf0201000 if DEBUG_BCM2835
+ default 0xf0201000 if DEBUG_BCM2835 || DEBUG_BCM2836
default 0xf1000300 if DEBUG_BCM_5301X
default 0xf1002000 if DEBUG_MT8127_UART0
default 0xf1006000 if DEBUG_MT6589_UART0
default 0xf1009000 if DEBUG_MT8135_UART3
- default 0xf11f1000 if ARCH_VERSATILE
- default 0xf1600000 if ARCH_INTEGRATOR
+ default 0xf11f1000 if DEBUG_VERSATILE
+ default 0xf1600000 if DEBUG_INTEGRATOR
default 0xf1c28000 if DEBUG_SUNXI_UART0
default 0xf1c28400 if DEBUG_SUNXI_UART1
default 0xf1f02800 if DEBUG_SUNXI_R_UART
+ default 0xf31004c0 if DEBUG_MESON_UARTAO
+ default 0xf4090000 if DEBUG_LPC32XX
+ default 0xf4200000 if DEBUG_GEMINI
default 0xf6200000 if DEBUG_PXA_UART1
- default 0xf4090000 if ARCH_LPC32XX
- default 0xf4200000 if ARCH_GEMINI
default 0xf7000000 if DEBUG_SUN9I_UART0
+ default 0xf7000000 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART0
default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \
DEBUG_S3C2410_UART0)
+ default 0xf7000400 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART1
+ default 0xf7000800 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART2
+ default 0xf7000c00 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART3
default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \
DEBUG_S3C2410_UART1)
default 0xf7008000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART2 || \
@@ -1516,13 +1589,11 @@ config DEBUG_UART_VIRT
default 0xfc40ab00 if DEBUG_BRCMSTB_UART
default 0xfc705000 if DEBUG_ZTE_ZX
default 0xfcfe8600 if DEBUG_UART_BCM63XX
- default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
- default 0xfd000000 if ARCH_SPEAR13XX
- default 0xfd012000 if ARCH_MV78XX0
+ default 0xfd000000 if DEBUG_SPEAR3XX || DEBUG_SPEAR13XX
+ default 0xfd012000 if DEBUG_MVEBU_UART0_ALTERNATE && ARCH_MV78XX0
default 0xfd883000 if DEBUG_ALPINE_UART0
- default 0xfde12000 if ARCH_DOVE
- default 0xfe012000 if ARCH_ORION5X
- default 0xf31004c0 if DEBUG_MESON_UARTAO
+ default 0xfde12000 if DEBUG_MVEBU_UART0_ALTERNATE && ARCH_DOVE
+ default 0xfe012000 if DEBUG_MVEBU_UART0_ALTERNATE && ARCH_ORION5X
default 0xfe017000 if DEBUG_MMP_UART2
default 0xfe018000 if DEBUG_MMP_UART3
default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART
@@ -1536,7 +1607,7 @@ config DEBUG_UART_VIRT
default 0xfeb31000 if DEBUG_KEYSTONE_UART1
default 0xfec02000 if DEBUG_SOCFPGA_UART0
default 0xfec02100 if DEBUG_SOCFPGA_UART1
- default 0xfec12000 if DEBUG_MVEBU_UART0 || DEBUG_MVEBU_UART0_ALTERNATE
+ default 0xfec12000 if (DEBUG_MVEBU_UART0 || DEBUG_MVEBU_UART0_ALTERNATE) && ARCH_MVEBU
default 0xfec12100 if DEBUG_MVEBU_UART1_ALTERNATE
default 0xfec10000 if DEBUG_SIRFATLAS7_UART0
default 0xfec20000 if DEBUG_DAVINCI_DMx_UART0
@@ -1548,8 +1619,8 @@ config DEBUG_UART_VIRT
default 0xfed60000 if DEBUG_RK29_UART0
default 0xfed64000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
default 0xfed68000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
- default 0xfedc0000 if ARCH_EP93XX
- default 0xfee003f8 if FOOTBRIDGE
+ default 0xfedc0000 if DEBUG_EP93XX
+ default 0xfee003f8 if DEBUG_FOOTBRIDGE_COM1
default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
default 0xfee82340 if ARCH_IOP13XX
default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
@@ -1566,13 +1637,14 @@ config DEBUG_UART_VIRT
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
DEBUG_NETX_UART || \
DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
+ DEBUG_S3C64XX_UART || \
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0
config DEBUG_UART_8250_SHIFT
int "Register offset shift for the 8250 debug UART"
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
- default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X || \
+ default 0 if DEBUG_FOOTBRIDGE_COM1 || ARCH_IOP32X || DEBUG_BCM_5301X || \
DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || DEBUG_OMAP7XXUART3
default 2
@@ -1580,8 +1652,9 @@ config DEBUG_UART_8250_WORD
bool "Use 32-bit accesses for 8250 UART"
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
depends on DEBUG_UART_8250_SHIFT >= 2
- default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART0 || \
- DEBUG_SOCFPGA_UART1 || ARCH_KEYSTONE || \
+ default y if DEBUG_PICOXCELL_UART || \
+ DEBUG_SOCFPGA_UART0 || DEBUG_SOCFPGA_UART1 || \
+ DEBUG_KEYSTONE_UART0 || DEBUG_KEYSTONE_UART1 || \
DEBUG_ALPINE_UART0 || \
DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
DEBUG_DAVINCI_DA8XX_UART2 || \
@@ -1591,7 +1664,7 @@ config DEBUG_UART_8250_WORD
config DEBUG_UART_8250_FLOW_CONTROL
bool "Enable flow control for 8250 UART"
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
- default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_GEMINI || ARCH_RPC
+ default y if ARCH_EBSA110 || DEBUG_FOOTBRIDGE_COM1 || DEBUG_GEMINI || ARCH_RPC
config DEBUG_UNCOMPRESS
bool
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2c2b28ee4811..fe254108d1d9 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -30,9 +30,8 @@ GZFLAGS :=-9
# Never generate .eh_frame
KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
-# Do not use arch/arm/defconfig - it's always outdated.
-# Select a platform tht is kept up-to-date
-KBUILD_DEFCONFIG := versatile_defconfig
+# This should work on most of the modern platforms
+KBUILD_DEFCONFIG := multi_v7_defconfig
# defines filename extension depending memory management type.
ifeq ($(CONFIG_MMU),)
@@ -211,6 +210,7 @@ machine-$(CONFIG_ARCH_SOCFPGA) += socfpga
machine-$(CONFIG_ARCH_STI) += sti
machine-$(CONFIG_ARCH_STM32) += stm32
machine-$(CONFIG_ARCH_SUNXI) += sunxi
+machine-$(CONFIG_ARCH_TANGO) += tango
machine-$(CONFIG_ARCH_TEGRA) += tegra
machine-$(CONFIG_ARCH_U300) += u300
machine-$(CONFIG_ARCH_U8500) += ux500
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 30bbc3746130..a4a6d70e8b26 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -48,8 +48,10 @@ dtb-$(CONFIG_SOC_SAM_V7) += \
sama5d34ek.dtb \
sama5d35ek.dtb \
sama5d36ek.dtb \
+ at91-sama5d4_ma5d4evk.dtb \
at91-sama5d4_xplained.dtb \
- at91-sama5d4ek.dtb
+ at91-sama5d4ek.dtb \
+ at91-vinco.dtb
dtb-$(CONFIG_ARCH_ATLAS6) += \
atlas6-evb.dtb
dtb-$(CONFIG_ARCH_ATLAS7) += \
@@ -60,7 +62,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
bcm2835-rpi-b.dtb \
bcm2835-rpi-b-rev2.dtb \
bcm2835-rpi-b-plus.dtb \
- bcm2835-rpi-a-plus.dtb
+ bcm2835-rpi-a-plus.dtb \
+ bcm2836-rpi-2-b.dtb
dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4708-asus-rt-ac56u.dtb \
bcm4708-asus-rt-ac68u.dtb \
@@ -75,7 +78,10 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4709-asus-rt-ac87u.dtb \
bcm4709-buffalo-wxr-1900dhp.dtb \
bcm4709-netgear-r7000.dtb \
- bcm4709-netgear-r8000.dtb
+ bcm4709-netgear-r8000.dtb \
+ bcm94708.dtb \
+ bcm94709.dtb \
+ bcm953012k.dtb
dtb-$(CONFIG_ARCH_BCM_63XX) += \
bcm963138dvt.dtb
dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \
@@ -200,12 +206,14 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += \
kirkwood-ns2mini.dtb \
kirkwood-nsa310.dtb \
kirkwood-nsa310a.dtb \
+ kirkwood-nsa325.dtb \
kirkwood-openblocks_a6.dtb \
kirkwood-openblocks_a7.dtb \
kirkwood-openrd-base.dtb \
kirkwood-openrd-client.dtb \
kirkwood-openrd-ultimate.dtb \
kirkwood-pogo_e02.dtb \
+ kirkwood-pogoplug-series-4.dtb \
kirkwood-rd88f6192.dtb \
kirkwood-rd88f6281-z0.dtb \
kirkwood-rd88f6281-a.dtb \
@@ -268,7 +276,8 @@ dtb-$(CONFIG_SOC_IMX51) += \
imx51-apf51dev.dtb \
imx51-babbage.dtb \
imx51-digi-connectcore-jsk.dtb \
- imx51-eukrea-mbimxsd51-baseboard.dtb
+ imx51-eukrea-mbimxsd51-baseboard.dtb \
+ imx51-ts4800.dtb
dtb-$(CONFIG_SOC_IMX53) += \
imx53-ard.dtb \
imx53-m53evk.dtb \
@@ -325,6 +334,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-hummingboard.dtb \
imx6q-nitrogen6x.dtb \
imx6q-nitrogen6_max.dtb \
+ imx6q-novena.dtb \
imx6q-phytec-pbab01.dtb \
imx6q-rex-pro.dtb \
imx6q-sabreauto.dtb \
@@ -350,6 +360,8 @@ dtb-$(CONFIG_SOC_IMX6SX) += \
dtb-$(CONFIG_SOC_IMX6UL) += \
imx6ul-14x14-evk.dtb
dtb-$(CONFIG_SOC_IMX7D) += \
+ imx7d-cl-som-imx7.dtb \
+ imx7d-sbc-imx7.dtb \
imx7d-sdb.dtb
dtb-$(CONFIG_SOC_LS1021A) += \
ls1021a-qds.dtb \
@@ -359,6 +371,7 @@ dtb-$(CONFIG_SOC_VF610) += \
vf610-colibri-eval-v3.dtb \
vf610m4-colibri.dtb \
vf610-cosmic.dtb \
+ vf610m4-cosmic.dtb \
vf610-twr.dtb
dtb-$(CONFIG_ARCH_MXS) += \
imx23-evk.dtb \
@@ -452,20 +465,24 @@ dtb-$(CONFIG_ARCH_OMAP3) += \
dtb-$(CONFIG_SOC_TI81XX) += \
dm8148-evm.dtb \
dm8148-t410.dtb \
- dm8168-evm.dtb
+ dm8168-evm.dtb \
+ dra62x-j5eco-evm.dtb
dtb-$(CONFIG_SOC_AM33XX) += \
am335x-baltos-ir5221.dtb \
am335x-base0033.dtb \
am335x-bone.dtb \
am335x-boneblack.dtb \
am335x-bonegreen.dtb \
- am335x-sl50.dtb \
+ am335x-chiliboard.dtb \
+ am335x-cm-t335.dtb \
am335x-evm.dtb \
am335x-evmsk.dtb \
+ am335x-lxm.dtb \
am335x-nano.dtb \
am335x-pepper.dtb \
- am335x-lxm.dtb \
- am335x-chiliboard.dtb \
+ am335x-shc.dtb \
+ am335x-sbc-t335.dtb \
+ am335x-sl50.dtb \
am335x-wega-rdk.dtb
dtb-$(CONFIG_ARCH_OMAP4) += \
omap4-duovero-parlor.dtb \
@@ -478,17 +495,21 @@ dtb-$(CONFIG_ARCH_OMAP4) += \
omap4-var-stk-om44.dtb
dtb-$(CONFIG_SOC_AM43XX) += \
am43x-epos-evm.dtb \
- am437x-sk-evm.dtb \
+ am437x-cm-t43.dtb \
+ am437x-gp-evm.dtb \
am437x-idk-evm.dtb \
- am437x-gp-evm.dtb
+ am437x-sbc-t43.dtb \
+ am437x-sk-evm.dtb
dtb-$(CONFIG_SOC_OMAP5) += \
omap5-cm-t54.dtb \
omap5-igep0050.dtb \
omap5-sbc-t54.dtb \
omap5-uevm.dtb
dtb-$(CONFIG_SOC_DRA7XX) += \
- dra7-evm.dtb \
am57xx-beagle-x15.dtb \
+ am57xx-cl-som-am57x.dtb \
+ am57xx-sbc-am57x.dtb \
+ dra7-evm.dtb \
dra72-evm.dtb
dtb-$(CONFIG_ARCH_ORION5X) += \
orion5x-lacie-d2-network.dtb \
@@ -502,6 +523,7 @@ dtb-$(CONFIG_ARCH_PRIMA2) += \
dtb-$(CONFIG_ARCH_QCOM) += \
qcom-apq8064-cm-qs600.dtb \
qcom-apq8064-ifc6410.dtb \
+ qcom-apq8064-sony-xperia-yuga.dtb \
qcom-apq8074-dragonboard.dtb \
qcom-apq8084-ifc6540.dtb \
qcom-apq8084-mtp.dtb \
@@ -510,12 +532,16 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-msm8960-cdp.dtb \
qcom-msm8974-sony-xperia-honami.dtb
dtb-$(CONFIG_ARCH_REALVIEW) += \
- arm-realview-pb1176.dtb
+ arm-realview-pb1176.dtb \
+ arm-realview-pb11mp.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += \
+ rk3036-evb.dtb \
+ rk3036-kylin.dtb \
rk3066a-bqcurie2.dtb \
rk3066a-marsboard.dtb \
rk3066a-rayeager.dtb \
rk3188-radxarock.dtb \
+ rk3228-evb.dtb \
rk3288-evb-act8846.dtb \
rk3288-evb-rk808.dtb \
rk3288-firefly-beta.dtb \
@@ -523,8 +549,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rk3288-popmetal.dtb \
rk3288-r89.dtb \
rk3288-rock2-square.dtb \
+ rk3288-veyron-brain.dtb \
rk3288-veyron-jaq.dtb \
rk3288-veyron-jerry.dtb \
+ rk3288-veyron-mickey.dtb \
rk3288-veyron-minnie.dtb \
rk3288-veyron-pinky.dtb \
rk3288-veyron-speedy.dtb
@@ -547,7 +575,6 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
r8a7778-bockw.dtb \
r8a7779-marzen.dtb \
r8a7790-lager.dtb \
- r8a7791-henninger.dtb \
r8a7791-koelsch.dtb \
r8a7791-porter.dtb \
r8a7793-gose.dtb \
@@ -557,6 +584,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
dtb-$(CONFIG_ARCH_SOCFPGA) += \
socfpga_arria5_socdk.dtb \
socfpga_arria10_socdk_sdmmc.dtb \
+ socfpga_cyclone5_mcvevk.dtb \
socfpga_cyclone5_socdk.dtb \
socfpga_cyclone5_de0_sockit.dtb \
socfpga_cyclone5_sockit.dtb \
@@ -612,6 +640,7 @@ dtb-$(CONFIG_MACH_SUN5I) += \
sun5i-a10s-olinuxino-micro.dtb \
sun5i-a10s-r7-tv-dongle.dtb \
sun5i-a10s-wobo-i5.dtb \
+ sun5i-a13-empire-electronix-d709.dtb \
sun5i-a13-hsg-h702.dtb \
sun5i-a13-inet-98v-rev2.dtb \
sun5i-a13-olinuxino.dtb \
@@ -638,6 +667,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-cubietruck.dtb \
sun7i-a20-hummingbird.dtb \
sun7i-a20-i12-tvbox.dtb \
+ sun7i-a20-icnova-swac.dtb \
sun7i-a20-m3.dtb \
sun7i-a20-mk808c.dtb \
sun7i-a20-olimex-som-evb.dtb \
@@ -660,10 +690,13 @@ dtb-$(CONFIG_MACH_SUN8I) += \
sun8i-a33-ga10h-v1.1.dtb \
sun8i-a33-ippo-q8h-v1.2.dtb \
sun8i-a33-q8-tablet.dtb \
- sun8i-a33-sinlinx-sina33.dtb
+ sun8i-a33-sinlinx-sina33.dtb \
+ sun8i-h3-orangepi-plus.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
sun9i-a80-cubieboard4.dtb
+dtb-$(CONFIG_ARCH_TANGO) += \
+ tango4-vantage-1172.dtb
dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += \
tegra20-harmony.dtb \
tegra20-iris-512.dtb \
@@ -748,6 +781,7 @@ dtb-$(CONFIG_MACH_ARMADA_38X) += \
armada-385-db-ap.dtb \
armada-385-linksys-caiman.dtb \
armada-385-linksys-cobra.dtb \
+ armada-388-clearfog.dtb \
armada-388-db.dtb \
armada-388-gp.dtb \
armada-388-rd.dtb
@@ -771,6 +805,7 @@ dtb-$(CONFIG_MACH_DOVE) += \
dove-dove-db.dtb \
dove-sbc-a510.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += \
+ mt2701-evb.dtb \
mt6580-evbp1.dtb \
mt6589-aquaris5.dtb \
mt6592-evb.dtb \
diff --git a/arch/arm/boot/dts/am335x-baltos-ir5221.dts b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
index 7d36601697da..ded1eb64ea52 100644
--- a/arch/arm/boot/dts/am335x-baltos-ir5221.dts
+++ b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
@@ -56,175 +56,171 @@
&am33xx_pinmux {
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x020 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad8.mmc1_dat0_mux0 */
- 0x024 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad9.mmc1_dat1_mux0 */
- 0x028 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad10.mmc1_dat2_mux0 */
- 0x02c (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad11.mmc1_dat3_mux0 */
- 0x080 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk_mux0 */
- 0x084 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd_mux0 */
- 0x1e4 (PIN_INPUT_PULLUP | MUX_MODE7) /* emu0.gpio3[7] */
+ AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad8.mmc1_dat0_mux0 */
+ AM33XX_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad9.mmc1_dat1_mux0 */
+ AM33XX_IOPAD(0x828, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad10.mmc1_dat2_mux0 */
+ AM33XX_IOPAD(0x82c, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad11.mmc1_dat3_mux0 */
+ AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk_mux0 */
+ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd_mux0 */
+ AM33XX_IOPAD(0x9e4, PIN_INPUT_PULLUP | MUX_MODE7) /* emu0.gpio3[7] */
>;
};
wl12xx_gpio: pinmux_wl12xx_gpio {
pinctrl-single,pins = <
- 0x1e8 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* emu1.gpio3[8] */
+ AM33XX_IOPAD(0x9e8, PIN_OUTPUT_PULLUP | MUX_MODE7) /* emu1.gpio3[8] */
>;
};
tps65910_pins: pinmux_tps65910_pins {
pinctrl-single,pins = <
- 0x078 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_ben1.gpio1[28] */
+ AM33XX_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_ben1.gpio1[28] */
>;
};
tca6416_pins: pinmux_tca6416_pins {
pinctrl-single,pins = <
- 0x1b4 (PIN_INPUT_PULLUP | MUX_MODE7) /* xdma_event_intr1.gpio0[20] tca6416 stuff */
+ AM33XX_IOPAD(0x9b4, PIN_INPUT_PULLUP | MUX_MODE7) /* xdma_event_intr1.gpio0[20] tca6416 stuff */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x158 0x2a /* spi0_d1.i2c1_sda_mux3, INPUT | MODE2 */
- 0x15c 0x2a /* spi0_cs0.i2c1_scl_mux3, INPUT | MODE2 */
+ AM33XX_IOPAD(0x958, PIN_INPUT | MUX_MODE2) /* spi0_d1.i2c1_sda_mux3 */
+ AM33XX_IOPAD(0x95c, PIN_INPUT | MUX_MODE2) /* spi0_cs0.i2c1_scl_mux3 */
>;
};
dcan1_pins: pinmux_dcan1_pins {
pinctrl-single,pins = <
- 0x168 0x0a /* uart0_ctsn.dcan1_tx_mux0, OUTPUT | MODE2 */
- 0x16c 0x2a /* uart0_rtsn.dcan1_rx_mux0, INPUT | MODE2 */
+ AM33XX_IOPAD(0x968, PIN_OUTPUT | MUX_MODE2) /* uart0_ctsn.dcan1_tx_mux0 */
+ AM33XX_IOPAD(0x96c, PIN_INPUT | MUX_MODE2) /* uart0_rtsn.dcan1_rx_mux0 */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x180 0x28 /* uart1_rxd, INPUT | MODE0 */
- 0x184 0x28 /* uart1_txd, INPUT | MODE0 */
- /*0x178 0x28*/ /* uart1_ctsn, INPUT | MODE0 */
- /*0x17c 0x08*/ /* uart1_rtsn, OUTPUT | MODE0 */
- 0x178 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* uart1_ctsn, INPUT | MODE0 */
- 0x17c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* uart1_rtsn, OUTPUT | MODE0 */
- 0x0e0 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* lcd_vsync.gpio2[22] DTR */
- 0x0e4 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_hsync.gpio2[23] DSR */
- 0x0e8 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_pclk.gpio2[24] DCD */
- 0x0ec (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_ac_bias_en.gpio2[25] RI */
+ AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0) /* uart1_rxd */
+ AM33XX_IOPAD(0x984, PIN_INPUT | MUX_MODE0) /* uart1_txd */
+ AM33XX_IOPAD(0x978, PIN_INPUT_PULLDOWN | MUX_MODE7) /* uart1_ctsn, INPUT | MODE0 */
+ AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* uart1_rtsn, OUTPUT | MODE0 */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* lcd_vsync.gpio2[22] DTR */
+ AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_hsync.gpio2[23] DSR */
+ AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_pclk.gpio2[24] DCD */
+ AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_ac_bias_en.gpio2[25] RI */
>;
};
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0x150 0x29 /* spi0_sclk.uart2_rxd_mux3, INPUT | MODE1 */
- 0x154 0x09 /* spi0_d0.uart2_txd_mux3, OUTPUT | MODE1 */
- /*0x188 0x2a*/ /* i2c0_sda.uart2_ctsn_mux0, INPUT | MODE2 */
- /*0x18c 0x2a*/ /* i2c0_scl.uart2_rtsn_mux0, INPUT | MODE2 */
- 0x188 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* i2c0_sda.uart2_ctsn_mux0 */
- 0x18c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* i2c0_scl.uart2_rtsn_mux0 */
- 0x030 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad12.gpio1[12] DTR */
- 0x034 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad13.gpio1[13] DSR */
- 0x038 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad14.gpio1[14] DCD */
- 0x03c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad15.gpio1[15] RI */
-
- 0x1a0 (PIN_INPUT_PULLUP | MUX_MODE7) /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
+ AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd_mux3 */
+ AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd_mux3 */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLDOWN | MUX_MODE7) /* i2c0_sda.uart2_ctsn_mux0 */
+ AM33XX_IOPAD(0x98c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* i2c0_scl.uart2_rtsn_mux0 */
+ AM33XX_IOPAD(0x830, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad12.gpio1[12] DTR */
+ AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad13.gpio1[13] DSR */
+ AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad14.gpio1[14] DCD */
+ AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad15.gpio1[15] RI */
+
+ AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7) /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs_dv */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_tx_en.rmii1_txen */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_ref_clk.rmii1_refclk */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs_dv */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_tx_en.rmii1_txen */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_ref_clk.rmii1_refclk */
/* Slave 2 */
- 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a1.rgmii2_rctl */
- 0x48 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
- 0x4c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
- 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
- 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
- 0x58 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
- 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
- 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
+ AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a1.rgmii2_rctl */
+ AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
+ AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
+ AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
+ AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
+ AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
+ AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
/* Slave 2 reset value*/
- 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x848, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x84c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
nandflash_pins_s0: nandflash_pins_s0 {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x74 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_30 */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_30 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index 5d370d54bd30..f3db13d2d90e 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -67,112 +67,112 @@
user_leds_s0: user_leds_s0 {
pinctrl-single,pins = <
- 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
- 0x58 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
- 0x5c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
- 0x60 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+ AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
+ AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
+ AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
>;
};
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
- 0x178 (PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_ctsn.i2c2_sda */
- 0x17c (PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_rtsn.i2c2_scl */
+ AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_ctsn.i2c2_sda */
+ AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_rtsn.i2c2_scl */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
clkout2_pin: pinmux_clkout2_pin {
pinctrl-single,pins = <
- 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+ AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
- 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
- 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
- 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_txclk.mii1_txclk */
- 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxclk.mii1_rxclk */
- 0x134 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd3.mii1_rxd3 */
- 0x138 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd2.mii1_rxd2 */
- 0x13c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd1.mii1_rxd1 */
- 0x140 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd0.mii1_rxd0 */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
+ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
+ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_txclk.mii1_txclk */
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxclk.mii1_rxclk */
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd3.mii1_rxd3 */
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd2.mii1_rxd2 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd1.mii1_rxd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd0.mii1_rxd0 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x160 (PIN_INPUT | MUX_MODE7) /* GPIO0_6 */
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* GPIO0_6 */
>;
};
emmc_pins: pinmux_emmc_pins {
pinctrl-single,pins = <
- 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
- 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
- 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
- 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
- 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
- 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+ AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
>;
};
};
@@ -285,10 +285,8 @@
};
};
-
-/include/ "tps65217.dtsi"
-
&tps {
+ compatible = "ti,tps65217";
/*
* Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
* mode") at poweroff. Most BeagleBone versions do not support RTC-only
@@ -309,12 +307,17 @@
ti,pmic-shutdown-controller;
regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
dcdc1_reg: regulator@0 {
+ reg = <0>;
regulator-name = "vdds_dpr";
regulator-always-on;
};
dcdc2_reg: regulator@1 {
+ reg = <1>;
/* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
regulator-name = "vdd_mpu";
regulator-min-microvolt = <925000>;
@@ -324,6 +327,7 @@
};
dcdc3_reg: regulator@2 {
+ reg = <2>;
/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
regulator-name = "vdd_core";
regulator-min-microvolt = <925000>;
@@ -333,21 +337,25 @@
};
ldo1_reg: regulator@3 {
+ reg = <3>;
regulator-name = "vio,vrtc,vdds";
regulator-always-on;
};
ldo2_reg: regulator@4 {
+ reg = <4>;
regulator-name = "vdd_3v3aux";
regulator-always-on;
};
ldo3_reg: regulator@5 {
+ reg = <5>;
regulator-name = "vdd_1v8";
regulator-always-on;
};
ldo4_reg: regulator@6 {
+ reg = <6>;
regulator-name = "vdd_3v3a";
regulator-always-on;
};
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
index eadbba32386d..55c0e954b146 100644
--- a/arch/arm/boot/dts/am335x-boneblack.dts
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
@@ -36,32 +36,32 @@
&am33xx_pinmux {
nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
pinctrl-single,pins = <
- 0x1b0 0x03 /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */
- 0xa0 0x08 /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xa4 0x08 /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xa8 0x08 /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xac 0x08 /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xb0 0x08 /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xb4 0x08 /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xb8 0x08 /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xbc 0x08 /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xc0 0x08 /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xc4 0x08 /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xc8 0x08 /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xcc 0x08 /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xd0 0x08 /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xd4 0x08 /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xd8 0x08 /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xdc 0x08 /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
- 0xe0 0x00 /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
- 0xe4 0x00 /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
- 0xe8 0x00 /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
- 0xec 0x00 /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
>;
};
nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
pinctrl-single,pins = <
- 0x1b0 0x03 /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */
+ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-bonegreen.dts b/arch/arm/boot/dts/am335x-bonegreen.dts
index 0f65bdaaa583..dce3c8657e04 100644
--- a/arch/arm/boot/dts/am335x-bonegreen.dts
+++ b/arch/arm/boot/dts/am335x-bonegreen.dts
@@ -36,8 +36,8 @@
&am33xx_pinmux {
uart2_pins: uart2_pins {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd */
- 0x154 (PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd */
+ AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd */
+ AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-chiliboard.dts b/arch/arm/boot/dts/am335x-chiliboard.dts
index 310da20a8aa7..15d47ab28865 100644
--- a/arch/arm/boot/dts/am335x-chiliboard.dts
+++ b/arch/arm/boot/dts/am335x-chiliboard.dts
@@ -37,26 +37,26 @@
&am33xx_pinmux {
usb1_drvvbus: usb1_drvvbus {
pinctrl-single,pins = <
- 0x234 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* usb1_drvvbus.usb1_drvvbus */
+ AM33XX_IOPAD(0xa34, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* usb1_drvvbus.usb1_drvvbus */
>;
};
sd_pins: pinmux_sd_card {
pinctrl-single,pins = <
- 0xf0 (PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
- 0xf4 (PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
- 0xf8 (PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
- 0xfc (PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
- 0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- 0x104 (PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM33XX_IOPAD(0x8f0, PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM33XX_IOPAD(0x900, PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM33XX_IOPAD(0x904, PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
led_gpio_pins: led_gpio_pins {
pinctrl-single,pins = <
- 0x1e4 (PIN_OUTPUT | MUX_MODE7) /* emu0.gpio3_7 */
- 0x1e8 (PIN_OUTPUT | MUX_MODE7) /* emu1.gpio3_8 */
+ AM33XX_IOPAD(0x9e4, PIN_OUTPUT | MUX_MODE7) /* emu0.gpio3_7 */
+ AM33XX_IOPAD(0x9e8, PIN_OUTPUT | MUX_MODE7) /* emu1.gpio3_8 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-chilisom.dtsi b/arch/arm/boot/dts/am335x-chilisom.dtsi
index 7e9a34dffe21..fda457b07e15 100644
--- a/arch/arm/boot/dts/am335x-chilisom.dtsi
+++ b/arch/arm/boot/dts/am335x-chilisom.dtsi
@@ -29,81 +29,81 @@
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs */
- 0x110 (PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxerr.rmii1_rxerr */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txen.rmii1_txen */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
- 0x13c (PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
- 0x140 (PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_ref_clk.rmii_ref_clk */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxerr.rmii1_rxerr */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txen.rmii1_txen */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_ref_clk.rmii_ref_clk */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* mdio_data.mdio_data */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
/* mdio_clk.mdio_clk */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
nandflash_pins: nandflash_pins {
pinctrl-single,pins = <
- 0x00 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x04 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x08 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0x0c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
-
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x7c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x890, PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
};
@@ -128,16 +128,21 @@
};
-/include/ "tps65217.dtsi"
-
&tps {
+ compatible = "ti,tps65217";
+
regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
dcdc1_reg: regulator@0 {
+ reg = <0>;
regulator-name = "vdds_dpr";
regulator-always-on;
};
dcdc2_reg: regulator@1 {
+ reg = <1>;
/* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
regulator-name = "vdd_mpu";
regulator-min-microvolt = <925000>;
@@ -147,6 +152,7 @@
};
dcdc3_reg: regulator@2 {
+ reg = <2>;
/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
regulator-name = "vdd_core";
regulator-min-microvolt = <925000>;
@@ -156,24 +162,28 @@
};
ldo1_reg: regulator@3 {
+ reg = <3>;
regulator-name = "vio,vrtc,vdds";
regulator-boot-on;
regulator-always-on;
};
ldo2_reg: regulator@4 {
+ reg = <4>;
regulator-name = "vdd_3v3aux";
regulator-boot-on;
regulator-always-on;
};
ldo3_reg: regulator@5 {
+ reg = <5>;
regulator-name = "vdd_1v8";
regulator-boot-on;
regulator-always-on;
};
ldo4_reg: regulator@6 {
+ reg = <6>;
regulator-name = "vdd_3v3d";
regulator-boot-on;
regulator-always-on;
diff --git a/arch/arm/boot/dts/am335x-cm-t335.dts b/arch/arm/boot/dts/am335x-cm-t335.dts
new file mode 100644
index 000000000000..42e9b665582a
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-cm-t335.dts
@@ -0,0 +1,396 @@
+/*
+ * am335x-cm-t335.dts - Device Tree file for Compulab CM-T335
+ *
+ * Copyright (C) 2014 - 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "am33xx.dtsi"
+
+/ {
+ model = "CompuLab CM-T335";
+ compatible = "compulab,cm-t335", "ti,am33xx";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x8000000>; /* 128 MB */
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_led_pins>;
+ led@0 {
+ label = "cm_t335:green";
+ gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; /* gpio2_0 */
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ /* regulator for mmc */
+ vmmc_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmc_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&ecap0 0 50000 0>;
+ brightness-levels = <0 51 53 56 62 75 101 152 255>;
+ default-brightness-level = <8>;
+ };
+};
+
+&am33xx_pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&bluetooth_pins>;
+
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)
+ >;
+ };
+
+ i2c1_pins: pinmux_i2c1_pins {
+ pinctrl-single,pins = <
+ /* uart0_ctsn.i2c1_sda */
+ AM33XX_IOPAD(0x968, PIN_INPUT_PULLUP | MUX_MODE2)
+ /* uart0_rtsn.i2c1_scl */
+ AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE2)
+ >;
+ };
+
+ gpio_led_pins: pinmux_gpio_led_pins {
+ pinctrl-single,pins = <
+ /* gpmc_csn3.gpio2_0 */
+ AM33XX_IOPAD(0x888, PIN_OUTPUT | MUX_MODE7)
+ >;
+ };
+
+ nandflash_pins: pinmux_nandflash_pins {
+ pinctrl-single,pins = <
+ /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_ad7.gpmc_ad7 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* gpmc_wpn.gpio0_30 */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7)
+ /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)
+ /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)
+ /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)
+ /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)
+ /* gpmc_ben0_cle.gpmc_ben0_cle */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)
+ >;
+ };
+
+ uart0_pins: pinmux_uart0_pins {
+ pinctrl-single,pins = <
+ /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ >;
+ };
+
+ uart1_pins: pinmux_uart1_pins {
+ pinctrl-single,pins = <
+ /* uart1_ctsn.uart1_ctsn */
+ AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)
+ /* uart1_rtsn.uart1_rtsn */
+ AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ /* uart1_rxd.uart1_rxd */
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* uart1_txd.uart1_txd */
+ AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ >;
+ };
+
+ ecap0_pins: pinmux_ecap0_pins {
+ pinctrl-single,pins = <
+ /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
+ AM33XX_IOPAD(0x964, 0x0)
+ >;
+ };
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ /* mii1_tx_en.rgmii1_tctl */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_rxdv.rgmii1_rctl */
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_txd3.rgmii1_td3 */
+ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_txd2.rgmii1_td2 */
+ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_txd1.rgmii1_td1 */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_txd0.rgmii1_td0 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_txclk.rgmii1_tclk */
+ AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_rxclk.rgmii1_rclk */
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_rxd3.rgmii1_rd3 */
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_rxd2.rgmii1_rd2 */
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_rxd1.rgmii1_rd1 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2)
+ /* mii1_rxd0.rgmii1_rd0 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2)
+ >;
+ };
+
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 reset value */
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
+ /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ /* MDIO reset value */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ /* mmc0_dat3.mmc0_dat3 */
+ AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* mmc0_dat2.mmc0_dat2 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* mmc0_dat1.mmc0_dat1 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* mmc0_dat0.mmc0_dat0 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* mmc0_clk.mmc0_clk */
+ AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)
+ /* mmc0_cmd.mmc0_cmd */
+ AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)
+ >;
+ };
+
+ /* wl1271 bluetooth */
+ bluetooth_pins: pinmux_bluetooth_pins {
+ pinctrl-single,pins = <
+ /* XDMA_EVENT_INTR0.gpio0_19 - bluetooth enable */
+ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLUP | MUX_MODE7)
+ >;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+
+ status = "okay";
+};
+
+/* WLS1271 bluetooth */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+
+status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+
+ status = "okay";
+ clock-frequency = <400000>;
+ /* CM-T335 board EEPROM */
+ eeprom: 24c02@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+ /* Real Time Clock */
+ ext_rtc: em3027@56 {
+ compatible = "emmicro,em3027";
+ reg = <0x56>;
+ };
+};
+
+&usb {
+ status = "okay";
+};
+
+&usb_ctrl_mod {
+ status = "okay";
+};
+
+&usb0_phy {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&cppi41dma {
+ status = "okay";
+};
+
+&epwmss0 {
+ status = "okay";
+
+ ecap0: ecap@48300100 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&ecap0_pins>;
+ };
+};
+
+&gpmc {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&nandflash_pins>;
+ ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
+ nand@0,0 {
+ reg = <0 0 0>; /* CS0, offset 0 */
+ ti,nand-ecc-opt = "bch8";
+ ti,elm-id = <&elm>;
+ nand-bus-width = <8>;
+ gpmc,device-width = <1>;
+ gpmc,sync-clk-ps = <0>;
+ gpmc,cs-on-ns = <0>;
+ gpmc,cs-rd-off-ns = <44>;
+ gpmc,cs-wr-off-ns = <44>;
+ gpmc,adv-on-ns = <6>;
+ gpmc,adv-rd-off-ns = <34>;
+ gpmc,adv-wr-off-ns = <44>;
+ gpmc,we-on-ns = <0>;
+ gpmc,we-off-ns = <40>;
+ gpmc,oe-on-ns = <0>;
+ gpmc,oe-off-ns = <54>;
+ gpmc,access-ns = <64>;
+ gpmc,rd-cycle-ns = <82>;
+ gpmc,wr-cycle-ns = <82>;
+ gpmc,wait-on-read = "true";
+ gpmc,wait-on-write = "true";
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-delay-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,wr-access-ns = <40>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ /* MTD partition table */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "spl";
+ reg = <0x00000000 0x00200000>;
+ };
+ partition@1 {
+ label = "uboot";
+ reg = <0x00200000 0x00100000>;
+ };
+ partition@2 {
+ label = "uboot environment";
+ reg = <0x00300000 0x00100000>;
+ };
+ partition@3 {
+ label = "dtb";
+ reg = <0x00400000 0x00100000>;
+ };
+ partition@4 {
+ label = "splash";
+ reg = <0x00500000 0x00400000>;
+ };
+ partition@5 {
+ label = "linux";
+ reg = <0x00900000 0x00600000>;
+ };
+ partition@6 {
+ label = "rootfs";
+ reg = <0x00F00000 0>;
+ };
+ };
+};
+
+&elm {
+ status = "okay";
+};
+
+&mac {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+ slaves = <1>;
+ status = "okay";
+};
+
+&davinci_mdio {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_default>;
+ pinctrl-1 = <&davinci_mdio_sleep>;
+ status = "okay";
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii-txid";
+};
+
+&mmc1 {
+ status = "okay";
+ vmmc-supply = <&vmmc_fixed>;
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index d9d00ab863a2..0d6a68ce434a 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -83,14 +83,14 @@
label = "volume-up";
linux,code = <115>;
gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
- gpio-key,wakeup;
+ wakeup-source;
};
switch@10 {
label = "volume-down";
linux,code = <114>;
gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
@@ -168,215 +168,215 @@
matrix_keypad_s0: matrix_keypad_s0 {
pinctrl-single,pins = <
- 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
- 0x58 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a6.gpio1_22 */
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a9.gpio1_25 */
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a10.gpio1_26 */
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.gpio1_27 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+ AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a6.gpio1_22 */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a9.gpio1_25 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a10.gpio1_26 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.gpio1_27 */
>;
};
volume_keys_s0: volume_keys_s0 {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_sclk.gpio0_2 */
- 0x154 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_d0.gpio0_3 */
+ AM33XX_IOPAD(0x950, PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_sclk.gpio0_2 */
+ AM33XX_IOPAD(0x954, PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_d0.gpio0_3 */
>;
};
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x158 (PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_d1.i2c1_sda */
- 0x15c (PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_cs0.i2c1_scl */
+ AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_d1.i2c1_sda */
+ AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_cs0.i2c1_scl */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x178 (PIN_INPUT | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
- 0x17C (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
- 0x180 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
- 0x184 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
+ AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
+ AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
+ AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
>;
};
clkout2_pin: pinmux_clkout2_pin {
pinctrl-single,pins = <
- 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+ AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
>;
};
nandflash_pins_s0: nandflash_pins_s0 {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x74 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_30 */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_30 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
ecap0_pins: backlight_pins {
pinctrl-single,pins = <
- 0x164 0x0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
+ AM33XX_IOPAD(0x964, MUX_MODE0) /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
- 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
- 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
- 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd3.rgmii1_rd3 */
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd2.rgmii1_rd2 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
+ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
+ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
+ AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd3.rgmii1_rd3 */
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd2.rgmii1_rd2 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
mmc3_pins: pinmux_mmc3_pins {
pinctrl-single,pins = <
- 0x44 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a1.mmc2_dat0, INPUT_PULLUP | MODE3 */
- 0x48 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a2.mmc2_dat1, INPUT_PULLUP | MODE3 */
- 0x4C (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a3.mmc2_dat2, INPUT_PULLUP | MODE3 */
- 0x78 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_ben1.mmc2_dat3, INPUT_PULLUP | MODE3 */
- 0x88 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_csn3.mmc2_cmd, INPUT_PULLUP | MODE3 */
- 0x8C (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_clk.mmc2_clk, INPUT_PULLUP | MODE3 */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a1.mmc2_dat0, INPUT_PULLUP | MODE3 */
+ AM33XX_IOPAD(0x848, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a2.mmc2_dat1, INPUT_PULLUP | MODE3 */
+ AM33XX_IOPAD(0x84c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a3.mmc2_dat2, INPUT_PULLUP | MODE3 */
+ AM33XX_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_ben1.mmc2_dat3, INPUT_PULLUP | MODE3 */
+ AM33XX_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_csn3.mmc2_cmd, INPUT_PULLUP | MODE3 */
+ AM33XX_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_clk.mmc2_clk, INPUT_PULLUP | MODE3 */
>;
};
wlan_pins: pinmux_wlan_pins {
pinctrl-single,pins = <
- 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a0.gpio1_16 */
- 0x19C (PIN_INPUT | MUX_MODE7) /* mcasp0_ahclkr.gpio3_17 */
- 0x1AC (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mcasp0_ahclkx.gpio3_21 */
+ AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a0.gpio1_16 */
+ AM33XX_IOPAD(0x99c, PIN_INPUT | MUX_MODE7) /* mcasp0_ahclkr.gpio3_17 */
+ AM33XX_IOPAD(0x9ac, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mcasp0_ahclkx.gpio3_21 */
>;
};
lcd_pins_s0: lcd_pins_s0 {
pinctrl-single,pins = <
- 0x20 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data23 */
- 0x24 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad9.lcd_data22 */
- 0x28 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad10.lcd_data21 */
- 0x2c (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad11.lcd_data20 */
- 0x30 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad12.lcd_data19 */
- 0x34 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad13.lcd_data18 */
- 0x38 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad14.lcd_data17 */
- 0x3c (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad15.lcd_data16 */
- 0xa0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
- 0xa4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
- 0xa8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
- 0xac (PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
- 0xb0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
- 0xb4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
- 0xb8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
- 0xbc (PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
- 0xc0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
- 0xc4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
- 0xc8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
- 0xcc (PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
- 0xd4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
- 0xd8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
- 0xdc (PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
- 0xe0 (PIN_OUTPUT | MUX_MODE0) /* lcd_vsync.lcd_vsync */
- 0xe4 (PIN_OUTPUT | MUX_MODE0) /* lcd_hsync.lcd_hsync */
- 0xe8 (PIN_OUTPUT | MUX_MODE0) /* lcd_pclk.lcd_pclk */
- 0xec (PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
+ AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data23 */
+ AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad9.lcd_data22 */
+ AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad10.lcd_data21 */
+ AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad11.lcd_data20 */
+ AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad12.lcd_data19 */
+ AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad13.lcd_data18 */
+ AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad14.lcd_data17 */
+ AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad15.lcd_data16 */
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0) /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0) /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0) /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
>;
};
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
- 0x108 (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
+ AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
>;
};
mcasp1_pins_sleep: mcasp1_pins_sleep {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
dcan1_pins_default: dcan1_pins_default {
pinctrl-single,pins = <
- 0x168 (PIN_OUTPUT | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
- 0x16c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
+ AM33XX_IOPAD(0x968, PIN_OUTPUT | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
+ AM33XX_IOPAD(0x96c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
>;
};
};
@@ -743,8 +743,8 @@
&mmc3 {
/* these are on the crossbar and are outlined in the
xbar-event-map element */
- dmas = <&edma 12
- &edma 13>;
+ dmas = <&edma_xbar 12 0 1
+ &edma_xbar 13 0 2>;
dma-names = "tx", "rx";
status = "okay";
vmmc-supply = <&wlan_en_reg>;
@@ -766,11 +766,6 @@
};
};
-&edma {
- ti,edma-xbar-event-map = /bits/ 16 <1 12
- 2 13>;
-};
-
&sham {
status = "okay";
};
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 89442e98a837..282fe1b37095 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -123,7 +123,7 @@
label = "button2";
linux,code = <0x102>;
gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
- gpio-key,wakeup;
+ wakeup-source;
};
switch@4 {
@@ -204,234 +204,234 @@
lcd_pins_default: lcd_pins_default {
pinctrl-single,pins = <
- 0x20 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data23 */
- 0x24 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad9.lcd_data22 */
- 0x28 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad10.lcd_data21 */
- 0x2c (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad11.lcd_data20 */
- 0x30 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad12.lcd_data19 */
- 0x34 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad13.lcd_data18 */
- 0x38 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad14.lcd_data17 */
- 0x3c (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad15.lcd_data16 */
- 0xa0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
- 0xa4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
- 0xa8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
- 0xac (PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
- 0xb0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
- 0xb4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
- 0xb8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
- 0xbc (PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
- 0xc0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
- 0xc4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
- 0xc8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
- 0xcc (PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
- 0xd4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
- 0xd8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
- 0xdc (PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
- 0xe0 (PIN_OUTPUT | MUX_MODE0) /* lcd_vsync.lcd_vsync */
- 0xe4 (PIN_OUTPUT | MUX_MODE0) /* lcd_hsync.lcd_hsync */
- 0xe8 (PIN_OUTPUT | MUX_MODE0) /* lcd_pclk.lcd_pclk */
- 0xec (PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
+ AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data23 */
+ AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad9.lcd_data22 */
+ AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad10.lcd_data21 */
+ AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad11.lcd_data20 */
+ AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad12.lcd_data19 */
+ AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad13.lcd_data18 */
+ AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad14.lcd_data17 */
+ AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad15.lcd_data16 */
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0) /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0) /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0) /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
>;
};
lcd_pins_sleep: lcd_pins_sleep {
pinctrl-single,pins = <
- 0x20 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad8.lcd_data23 */
- 0x24 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad9.lcd_data22 */
- 0x28 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad10.lcd_data21 */
- 0x2c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad11.lcd_data20 */
- 0x30 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad12.lcd_data19 */
- 0x34 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad13.lcd_data18 */
- 0x38 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad14.lcd_data17 */
- 0x3c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad15.lcd_data16 */
- 0xa0 (PULL_DISABLE | MUX_MODE7) /* lcd_data0.lcd_data0 */
- 0xa4 (PULL_DISABLE | MUX_MODE7) /* lcd_data1.lcd_data1 */
- 0xa8 (PULL_DISABLE | MUX_MODE7) /* lcd_data2.lcd_data2 */
- 0xac (PULL_DISABLE | MUX_MODE7) /* lcd_data3.lcd_data3 */
- 0xb0 (PULL_DISABLE | MUX_MODE7) /* lcd_data4.lcd_data4 */
- 0xb4 (PULL_DISABLE | MUX_MODE7) /* lcd_data5.lcd_data5 */
- 0xb8 (PULL_DISABLE | MUX_MODE7) /* lcd_data6.lcd_data6 */
- 0xbc (PULL_DISABLE | MUX_MODE7) /* lcd_data7.lcd_data7 */
- 0xc0 (PULL_DISABLE | MUX_MODE7) /* lcd_data8.lcd_data8 */
- 0xc4 (PULL_DISABLE | MUX_MODE7) /* lcd_data9.lcd_data9 */
- 0xc8 (PULL_DISABLE | MUX_MODE7) /* lcd_data10.lcd_data10 */
- 0xcc (PULL_DISABLE | MUX_MODE7) /* lcd_data11.lcd_data11 */
- 0xd0 (PULL_DISABLE | MUX_MODE7) /* lcd_data12.lcd_data12 */
- 0xd4 (PULL_DISABLE | MUX_MODE7) /* lcd_data13.lcd_data13 */
- 0xd8 (PULL_DISABLE | MUX_MODE7) /* lcd_data14.lcd_data14 */
- 0xdc (PULL_DISABLE | MUX_MODE7) /* lcd_data15.lcd_data15 */
- 0xe0 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_vsync.lcd_vsync */
- 0xe4 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_hsync.lcd_hsync */
- 0xe8 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_pclk.lcd_pclk */
- 0xec (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_ac_bias_en.lcd_ac_bias_en */
+ AM33XX_IOPAD(0x820, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad8.lcd_data23 */
+ AM33XX_IOPAD(0x824, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad9.lcd_data22 */
+ AM33XX_IOPAD(0x828, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad10.lcd_data21 */
+ AM33XX_IOPAD(0x82c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad11.lcd_data20 */
+ AM33XX_IOPAD(0x830, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad12.lcd_data19 */
+ AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad13.lcd_data18 */
+ AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad14.lcd_data17 */
+ AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad15.lcd_data16 */
+ AM33XX_IOPAD(0x8a0, PULL_DISABLE | MUX_MODE7) /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a4, PULL_DISABLE | MUX_MODE7) /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a8, PULL_DISABLE | MUX_MODE7) /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8ac, PULL_DISABLE | MUX_MODE7) /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8b0, PULL_DISABLE | MUX_MODE7) /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b4, PULL_DISABLE | MUX_MODE7) /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b8, PULL_DISABLE | MUX_MODE7) /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8bc, PULL_DISABLE | MUX_MODE7) /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8c0, PULL_DISABLE | MUX_MODE7) /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c4, PULL_DISABLE | MUX_MODE7) /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c8, PULL_DISABLE | MUX_MODE7) /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8cc, PULL_DISABLE | MUX_MODE7) /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8d0, PULL_DISABLE | MUX_MODE7) /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d4, PULL_DISABLE | MUX_MODE7) /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d8, PULL_DISABLE | MUX_MODE7) /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8dc, PULL_DISABLE | MUX_MODE7) /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x8e0, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_ac_bias_en.lcd_ac_bias_en */
>;
};
user_leds_s0: user_leds_s0 {
pinctrl-single,pins = <
- 0x10 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad4.gpio1_4 */
- 0x14 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad5.gpio1_5 */
- 0x18 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad6.gpio1_6 */
- 0x1c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad7.gpio1_7 */
+ AM33XX_IOPAD(0x810, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad4.gpio1_4 */
+ AM33XX_IOPAD(0x814, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad5.gpio1_5 */
+ AM33XX_IOPAD(0x818, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad6.gpio1_6 */
+ AM33XX_IOPAD(0x81c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad7.gpio1_7 */
>;
};
gpio_keys_s0: gpio_keys_s0 {
pinctrl-single,pins = <
- 0x94 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_oen_ren.gpio2_3 */
- 0x90 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_advn_ale.gpio2_2 */
- 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_wait0.gpio0_30 */
- 0x9c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ben0_cle.gpio2_5 */
+ AM33XX_IOPAD(0x894, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_oen_ren.gpio2_3 */
+ AM33XX_IOPAD(0x890, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_advn_ale.gpio2_2 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_wait0.gpio0_30 */
+ AM33XX_IOPAD(0x89c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ben0_cle.gpio2_5 */
>;
};
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
clkout2_pin: pinmux_clkout2_pin {
pinctrl-single,pins = <
- 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+ AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
>;
};
ecap2_pins: backlight_pins {
pinctrl-single,pins = <
- 0x19c 0x4 /* mcasp0_ahclkr.ecap2_in_pwm2_out MODE4 */
+ AM33XX_IOPAD(0x99c, MUX_MODE4) /* mcasp0_ahclkr.ecap2_in_pwm2_out */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
- 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
- 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
- 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd3.rgmii1_rd3 */
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd2.rgmii1_rd2 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
+ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
+ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
+ AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd3.rgmii1_rd3 */
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd2.rgmii1_rd2 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
/* Slave 2 */
- 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a1.rgmii2_rctl */
- 0x48 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
- 0x4c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
- 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
- 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
- 0x58 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
- 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
- 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
+ AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a1.rgmii2_rctl */
+ AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
+ AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
+ AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
+ AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
+ AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
+ AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
/* Slave 2 reset value*/
- 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x848, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x84c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
- 0x108 (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
+ AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
>;
};
mcasp1_pins_sleep: mcasp1_pins_sleep {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x74 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
- 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
- 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
- 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
- 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
- 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
- 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
+ AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
>;
};
wl12xx_gpio: pinmux_wl12xx_gpio {
pinctrl-single,pins = <
- 0x7c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_csn0.gpio1_29 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_csn0.gpio1_29 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-lxm.dts b/arch/arm/boot/dts/am335x-lxm.dts
index 5c5667a3624d..d97b0efa43f3 100644
--- a/arch/arm/boot/dts/am335x-lxm.dts
+++ b/arch/arm/boot/dts/am335x-lxm.dts
@@ -46,109 +46,109 @@
&am33xx_pinmux {
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3 */
- 0xf4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2 */
- 0xf8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1 */
- 0xfc (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0 */
- 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk */
- 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd */
+ AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0 */
+ AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk */
+ AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd */
>;
};
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_crs_dv */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rxer */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_txen */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td0 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd0 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_crs_dv */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rxer */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_txen */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td0 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd0 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk */
/* Slave 2 */
- 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_txen */
- 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td1 */
- 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td0 */
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd1 */
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd0 */
- 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_crs_dv */
- 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rxer */
- 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */
- 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii2_refclk */
+ AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_txen */
+ AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td1 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td0 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd1 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd0 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_crs_dv */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rxer */
+ AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */
+ AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii2_refclk */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_crs_dv */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rxer */
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_txen */
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td1 */
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td0 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd0 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_refclk */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_crs_dv */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rxer */
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_txen */
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td1 */
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td0 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd0 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_refclk */
/* Slave 2 reset value*/
- 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_txen */
- 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td1 */
- 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td0 */
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd1 */
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd0 */
- 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_crs_dv */
- 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rxer */
- 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */
- 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_refclk */
+ AM33XX_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_txen */
+ AM33XX_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td1 */
+ AM33XX_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td0 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd1 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd0 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_crs_dv */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rxer */
+ AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */
+ AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_refclk */
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
emmc_pins: pinmux_emmc_pins {
pinctrl-single,pins = <
- 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
- 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
- 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
- 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
- 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
- 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+ AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-nano.dts b/arch/arm/boot/dts/am335x-nano.dts
index 5ed4ca6eaf55..77559a1ded60 100644
--- a/arch/arm/boot/dts/am335x-nano.dts
+++ b/arch/arm/boot/dts/am335x-nano.dts
@@ -41,121 +41,121 @@
misc_pins: misc_pins {
pinctrl-single,pins = <
- 0x15c (PIN_OUTPUT | MUX_MODE7) /* spi0_cs0.gpio0_5 */
+ AM33XX_IOPAD(0x95c, PIN_OUTPUT | MUX_MODE7) /* spi0_cs0.gpio0_5 */
>;
};
gpmc_pins: gpmc_pins {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x20 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad8.gpmc_ad8 */
- 0x24 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad9.gpmc_ad9 */
- 0x28 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad10.gpmc_ad10 */
- 0x2c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad11.gpmc_ad11 */
- 0x30 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad12.gpmc_ad12 */
- 0x34 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad13.gpmc_ad13 */
- 0x38 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad14.gpmc_ad14 */
- 0x3c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad15.gpmc_ad15 */
-
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x80 (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn1.gpmc_csn1 */
- 0x84 (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn2.gpmc_csn2 */
- 0x88 (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn3.gpmc_csn3 */
-
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_ben0_cle.gpmc_ben0_cle */
-
- 0xa4 (PIN_OUTPUT | MUX_MODE1) /* lcd_data1.gpmc_a1 */
- 0xa8 (PIN_OUTPUT | MUX_MODE1) /* lcd_data2.gpmc_a2 */
- 0xac (PIN_OUTPUT | MUX_MODE1) /* lcd_data3.gpmc_a3 */
- 0xb0 (PIN_OUTPUT | MUX_MODE1) /* lcd_data4.gpmc_a4 */
- 0xb4 (PIN_OUTPUT | MUX_MODE1) /* lcd_data5.gpmc_a5 */
- 0xb8 (PIN_OUTPUT | MUX_MODE1) /* lcd_data6.gpmc_a6 */
- 0xbc (PIN_OUTPUT | MUX_MODE1) /* lcd_data7.gpmc_a7 */
-
- 0xe0 (PIN_OUTPUT | MUX_MODE1) /* lcd_vsync.gpmc_a8 */
- 0xe4 (PIN_OUTPUT | MUX_MODE1) /* lcd_hsync.gpmc_a9 */
- 0xe8 (PIN_OUTPUT | MUX_MODE1) /* lcd_pclk.gpmc_a10 */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad8.gpmc_ad8 */
+ AM33XX_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad9.gpmc_ad9 */
+ AM33XX_IOPAD(0x828, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad10.gpmc_ad10 */
+ AM33XX_IOPAD(0x82c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad11.gpmc_ad11 */
+ AM33XX_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad12.gpmc_ad12 */
+ AM33XX_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad13.gpmc_ad13 */
+ AM33XX_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad14.gpmc_ad14 */
+ AM33XX_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad15.gpmc_ad15 */
+
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x880, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn1.gpmc_csn1 */
+ AM33XX_IOPAD(0x884, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn2.gpmc_csn2 */
+ AM33XX_IOPAD(0x888, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn3.gpmc_csn3 */
+
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_ben0_cle.gpmc_ben0_cle */
+
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE1) /* lcd_data1.gpmc_a1 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE1) /* lcd_data2.gpmc_a2 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE1) /* lcd_data3.gpmc_a3 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE1) /* lcd_data4.gpmc_a4 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE1) /* lcd_data5.gpmc_a5 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE1) /* lcd_data6.gpmc_a6 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE1) /* lcd_data7.gpmc_a7 */
+
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE1) /* lcd_vsync.gpmc_a8 */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE1) /* lcd_hsync.gpmc_a9 */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE1) /* lcd_pclk.gpmc_a10 */
>;
};
i2c0_pins: i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLDOWN | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
uart0_pins: uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart1_pins: uart1_pins {
pinctrl-single,pins = <
- 0x178 (PIN_OUTPUT | MUX_MODE7) /* uart1_ctsn.uart1_ctsn */
- 0x17c (PIN_OUTPUT | MUX_MODE7) /* uart1_rtsn.uart1_rtsn */
- 0x180 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
- 0x184 (PIN_OUTPUT | MUX_MODE0) /* uart1_txd.uart1_txd */
+ AM33XX_IOPAD(0x978, PIN_OUTPUT | MUX_MODE7) /* uart1_ctsn.uart1_ctsn */
+ AM33XX_IOPAD(0x97c, PIN_OUTPUT | MUX_MODE7) /* uart1_rtsn.uart1_rtsn */
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
+ AM33XX_IOPAD(0x984, PIN_OUTPUT | MUX_MODE0) /* uart1_txd.uart1_txd */
>;
};
uart2_pins: uart2_pins {
pinctrl-single,pins = <
- 0xc0 (PIN_INPUT_PULLUP | MUX_MODE7) /* lcd_data8.gpio2[14] */
- 0xc4 (PIN_OUTPUT | MUX_MODE7) /* lcd_data9.gpio2[15] */
- 0x150 (PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd */
- 0x154 (PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd */
+ AM33XX_IOPAD(0x8c0, PIN_INPUT_PULLUP | MUX_MODE7) /* lcd_data8.gpio2[14] */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE7) /* lcd_data9.gpio2[15] */
+ AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd */
+ AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd */
>;
};
uart3_pins: uart3_pins {
pinctrl-single,pins = <
- 0xc8 (PIN_INPUT_PULLUP | MUX_MODE6) /* lcd_data10.uart3_ctsn */
- 0xcc (PIN_OUTPUT | MUX_MODE6) /* lcd_data11.uart3_rtsn */
- 0x160 (PIN_INPUT | MUX_MODE1) /* spi0_cs1.uart3_rxd */
- 0x164 (PIN_OUTPUT | MUX_MODE1) /* ecap0_in_pwm0_out.uart3_txd */
+ AM33XX_IOPAD(0x8c8, PIN_INPUT_PULLUP | MUX_MODE6) /* lcd_data10.uart3_ctsn */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE6) /* lcd_data11.uart3_rtsn */
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE1) /* spi0_cs1.uart3_rxd */
+ AM33XX_IOPAD(0x964, PIN_OUTPUT | MUX_MODE1) /* ecap0_in_pwm0_out.uart3_txd */
>;
};
uart4_pins: uart4_pins {
pinctrl-single,pins = <
- 0xd0 (PIN_INPUT_PULLUP | MUX_MODE6) /* lcd_data12.uart4_ctsn */
- 0xd4 (PIN_OUTPUT | MUX_MODE6) /* lcd_data13.uart4_rtsn */
- 0x168 (PIN_INPUT | MUX_MODE1) /* uart0_ctsn.uart4_rxd */
- 0x16c (PIN_OUTPUT | MUX_MODE1) /* uart0_rtsn.uart4_txd */
+ AM33XX_IOPAD(0x8d0, PIN_INPUT_PULLUP | MUX_MODE6) /* lcd_data12.uart4_ctsn */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE6) /* lcd_data13.uart4_rtsn */
+ AM33XX_IOPAD(0x968, PIN_INPUT | MUX_MODE1) /* uart0_ctsn.uart4_rxd */
+ AM33XX_IOPAD(0x96c, PIN_OUTPUT | MUX_MODE1) /* uart0_rtsn.uart4_txd */
>;
};
uart5_pins: uart5_pins {
pinctrl-single,pins = <
- 0xd8 (PIN_INPUT | MUX_MODE4) /* lcd_data14.uart5_rxd */
- 0x144 (PIN_OUTPUT | MUX_MODE3) /* rmiii1_refclk.uart5_txd */
+ AM33XX_IOPAD(0x8d8, PIN_INPUT | MUX_MODE4) /* lcd_data14.uart5_rxd */
+ AM33XX_IOPAD(0x944, PIN_OUTPUT | MUX_MODE3) /* rmiii1_refclk.uart5_txd */
>;
};
mmc1_pins: mmc1_pins {
pinctrl-single,pins = <
- 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
- 0xf4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
- 0xf8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
- 0xfc (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
- 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
- 0x1e8 (PIN_INPUT_PULLUP | MUX_MODE7) /* emu1.gpio3[8] */
- 0x1a0 (PIN_INPUT_PULLUP | MUX_MODE7) /* mcasp0_aclkr.gpio3[18] */
+ AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM33XX_IOPAD(0x9e8, PIN_INPUT_PULLUP | MUX_MODE7) /* emu1.gpio3[8] */
+ AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7) /* mcasp0_aclkr.gpio3[18] */
>;
};
};
@@ -375,11 +375,15 @@
wp-gpios = <&gpio3 18 0>;
};
-#include "tps65217.dtsi"
-
&tps {
+ compatible = "ti,tps65217";
+
regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
dcdc1_reg: regulator@0 {
+ reg = <0>;
/* +1.5V voltage with ±4% tolerance */
regulator-min-microvolt = <1450000>;
regulator-max-microvolt = <1550000>;
@@ -388,6 +392,7 @@
};
dcdc2_reg: regulator@1 {
+ reg = <1>;
/* VDD_MPU voltage limits 0.95V - 1.1V with ±4% tolerance */
regulator-name = "vdd_mpu";
regulator-min-microvolt = <915000>;
@@ -397,6 +402,7 @@
};
dcdc3_reg: regulator@2 {
+ reg = <2>;
/* VDD_CORE voltage limits 0.95V - 1.1V with ±4% tolerance */
regulator-name = "vdd_core";
regulator-min-microvolt = <915000>;
@@ -406,6 +412,7 @@
};
ldo1_reg: regulator@3 {
+ reg = <3>;
/* +1.8V voltage with ±4% tolerance */
regulator-min-microvolt = <1750000>;
regulator-max-microvolt = <1870000>;
@@ -414,6 +421,7 @@
};
ldo2_reg: regulator@4 {
+ reg = <4>;
/* +3.3V voltage with ±4% tolerance */
regulator-min-microvolt = <3175000>;
regulator-max-microvolt = <3430000>;
@@ -422,6 +430,7 @@
};
ldo3_reg: regulator@5 {
+ reg = <5>;
/* +1.8V voltage with ±4% tolerance */
regulator-min-microvolt = <1750000>;
regulator-max-microvolt = <1870000>;
@@ -430,6 +439,7 @@
};
ldo4_reg: regulator@6 {
+ reg = <6>;
/* +3.3V voltage with ±4% tolerance */
regulator-min-microvolt = <3175000>;
regulator-max-microvolt = <3430000>;
diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts
index 7106114c7464..471a3a70ea1f 100644
--- a/arch/arm/boot/dts/am335x-pepper.dts
+++ b/arch/arm/boot/dts/am335x-pepper.dts
@@ -93,14 +93,14 @@
&am33xx_pinmux {
i2c0_pins: pinmux_i2c0 {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
i2c1_pins: pinmux_i2c1 {
pinctrl-single,pins = <
- 0x10C (PIN_INPUT_PULLUP | MUX_MODE3) /* mii1_crs,i2c1_sda */
- 0x110 (PIN_INPUT_PULLUP | MUX_MODE3) /* mii1_rxerr,i2c1_scl */
+ AM33XX_IOPAD(0x90C, PIN_INPUT_PULLUP | MUX_MODE3) /* mii1_crs,i2c1_sda */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE3) /* mii1_rxerr,i2c1_scl */
>;
};
};
@@ -130,7 +130,7 @@
&am33xx_pinmux {
accel_pins: pinmux_accel {
pinctrl-single,pins = <
- 0x98 (PIN_INPUT | MUX_MODE7) /* gpmc_wen.gpio2_4 */
+ AM33XX_IOPAD(0x898, PIN_INPUT | MUX_MODE7) /* gpmc_wen.gpio2_4 */
>;
};
};
@@ -177,12 +177,12 @@
&am33xx_pinmux {
audio_pins: pinmux_audio {
pinctrl-single,pins = <
- 0x1AC (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
- 0x194 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
- 0x190 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
- 0x198 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr0.mcasp0_axr0 */
- 0x1A8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr1.mcasp0_axr1 */
- 0x40 (PIN_OUTPUT | MUX_MODE7) /* gpmc_a0.gpio1_16 */
+ AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
+ AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
+ AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
+ AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr0.mcasp0_axr0 */
+ AM33XX_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr1.mcasp0_axr1 */
+ AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE7) /* gpmc_a0.gpio1_16 */
>;
};
};
@@ -228,36 +228,36 @@
&am33xx_pinmux {
lcd_pins: pinmux_lcd {
pinctrl-single,pins = <
- 0xa0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
- 0xa4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
- 0xa8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
- 0xac (PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
- 0xb0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
- 0xb4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
- 0xb8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
- 0xbc (PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
- 0xc0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
- 0xc4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
- 0xc8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
- 0xcc (PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
- 0xd4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
- 0xd8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
- 0xdc (PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
- 0x20 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data16 */
- 0x24 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad9.lcd_data17 */
- 0x28 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad10.lcd_data18 */
- 0x2c (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad11.lcd_data19 */
- 0x30 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad12.lcd_data20 */
- 0x34 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad13.lcd_data21 */
- 0x38 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad14.lcd_data22 */
- 0x3c (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad15.lcd_data23 */
- 0xe0 (PIN_OUTPUT | MUX_MODE0) /* lcd_vsync.lcd_vsync */
- 0xe4 (PIN_OUTPUT | MUX_MODE0) /* lcd_hsync.lcd_hsync */
- 0xe8 (PIN_OUTPUT | MUX_MODE0) /* lcd_pclk.lcd_pclk */
- 0xec (PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data16 */
+ AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad9.lcd_data17 */
+ AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad10.lcd_data18 */
+ AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad11.lcd_data19 */
+ AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad12.lcd_data20 */
+ AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad13.lcd_data21 */
+ AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad14.lcd_data22 */
+ AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1) /* gpmc_ad15.lcd_data23 */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0) /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0) /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0) /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
/* Display Enable */
- 0x6c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a11.gpio1_27 */
+ AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a11.gpio1_27 */
>;
};
};
@@ -291,29 +291,29 @@
&am33xx_pinmux {
ethernet_pins: pinmux_ethernet {
pinctrl-single,pins = <
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
- 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
- 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
- 0x12c (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
- 0x130 (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
- 0x134 (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd3.rgmii1_rxd3 */
- 0x138 (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd2.rgmii1_rxd2 */
- 0x13c (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd1 */
- 0x140 (PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd0 */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
+ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
+ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd3.rgmii1_rxd3 */
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd2.rgmii1_rxd2 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd0 */
/* ethernet interrupt */
- 0x144 (PIN_INPUT_PULLUP | MUX_MODE7) /* rmii2_refclk.gpio0_29 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLUP | MUX_MODE7) /* rmii2_refclk.gpio0_29 */
/* ethernet PHY nReset */
- 0x108 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* mii1_col.gpio3_0 */
+ AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLUP | MUX_MODE7) /* mii1_col.gpio3_0 */
>;
};
mdio_pins: pinmux_mdio {
pinctrl-single,pins = <
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
};
@@ -339,13 +339,6 @@
ti,non-removable;
};
-&edma {
- /* Map eDMA MMC2 Events from Crossbar */
- ti,edma-xbar-event-map = /bits/ 16 <1 12
- 2 13>;
-};
-
-
&mmc3 {
/* Wifi & Bluetooth on MMC #3 */
status = "okay";
@@ -354,8 +347,8 @@
vmmmc-supply = <&v3v3c_reg>;
bus-width = <4>;
ti,non-removable;
- dmas = <&edma 12
- &edma 13>;
+ dmas = <&edma_xbar 12 0 1
+ &edma_xbar 13 0 2>;
dma-names = "tx", "rx";
};
@@ -363,45 +356,45 @@
&am33xx_pinmux {
sd_pins: pinmux_sd_card {
pinctrl-single,pins = <
- 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
- 0xf4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
- 0xf8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
- 0xfc (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
- 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
emmc_pins: pinmux_emmc {
pinctrl-single,pins = <
- 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
- 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
- 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
- 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
- 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
- 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+ AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
/* EMMC nReset */
- 0x74 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
+ AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
>;
};
wireless_pins: pinmux_wireless {
pinctrl-single,pins = <
- 0x44 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a1.mmc2_dat0 */
- 0x48 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a2.mmc2_dat1 */
- 0x4c (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a3.mmc2_dat2 */
- 0x78 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_ben1.mmc2_dat3 */
- 0x88 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_csn3.mmc2_cmd */
- 0x8c (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_clk.mmc1_clk */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a1.mmc2_dat0 */
+ AM33XX_IOPAD(0x848, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a2.mmc2_dat1 */
+ AM33XX_IOPAD(0x84c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a3.mmc2_dat2 */
+ AM33XX_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_ben1.mmc2_dat3 */
+ AM33XX_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_csn3.mmc2_cmd */
+ AM33XX_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_clk.mmc1_clk */
/* WLAN nReset */
- 0x60 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
+ AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
/* WLAN nPower down */
- 0x70 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wait0.gpio0_30 */
+ AM33XX_IOPAD(0x870, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wait0.gpio0_30 */
/* 32kHz Clock */
- 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+ AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
>;
};
};
@@ -427,9 +420,9 @@
vin-supply = <&vbat>;
};
-/include/ "tps65217.dtsi"
-
&tps {
+ compatible = "ti,tps65217";
+
backlight {
isel = <1>; /* ISET1 */
fdim = <200>; /* TPS65217_BL_FDIM_200HZ */
@@ -437,12 +430,17 @@
};
regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
dcdc1_reg: regulator@0 {
+ reg = <0>;
/* VDD_1V8 system supply */
regulator-always-on;
};
dcdc2_reg: regulator@1 {
+ reg = <1>;
/* VDD_CORE voltage limits 0.95V - 1.26V with +/-4% tolerance */
regulator-name = "vdd_core";
regulator-min-microvolt = <925000>;
@@ -452,6 +450,7 @@
};
dcdc3_reg: regulator@2 {
+ reg = <2>;
/* VDD_MPU voltage limits 0.95V - 1.1V with +/-4% tolerance */
regulator-name = "vdd_mpu";
regulator-min-microvolt = <925000>;
@@ -461,18 +460,21 @@
};
ldo1_reg: regulator@3 {
+ reg = <3>;
/* VRTC 1.8V always-on supply */
regulator-name = "vrtc,vdds";
regulator-always-on;
};
ldo2_reg: regulator@4 {
+ reg = <4>;
/* 3.3V rail */
regulator-name = "vdd_3v3aux";
regulator-always-on;
};
ldo3_reg: regulator@5 {
+ reg = <5>;
/* VDD_3V3A 3.3V rail */
regulator-name = "vdd_3v3a";
regulator-min-microvolt = <3300000>;
@@ -480,6 +482,7 @@
};
ldo4_reg: regulator@6 {
+ reg = <6>;
/* VDD_3V3B 3.3V rail */
regulator-name = "vdd_3v3b";
regulator-always-on;
@@ -497,10 +500,10 @@
&am33xx_pinmux {
spi0_pins: pinmux_spi0 {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_sclk.spi0_sclk */
- 0x15C (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
- 0x154 (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d0.spi0_d0 */
- 0x158 (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
+ AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_sclk.spi0_sclk */
+ AM33XX_IOPAD(0x95C, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
+ AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d0.spi0_d0 */
+ AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
>;
};
};
@@ -538,16 +541,16 @@
&am33xx_pinmux {
uart0_pins: pinmux_uart0 {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart1_pins: pinmux_uart1 {
pinctrl-single,pins = <
- 0x178 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
- 0x17C (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
- 0x180 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
- 0x184 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
+ AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
+ AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
+ AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
>;
};
};
@@ -590,9 +593,9 @@
usb_pins: pinmux_usb {
pinctrl-single,pins = <
/* USB0 Over-Current (active low) */
- 0x64 (PIN_INPUT | MUX_MODE7) /* gpmc_a9.gpio1_25 */
+ AM33XX_IOPAD(0x864, PIN_INPUT | MUX_MODE7) /* gpmc_a9.gpio1_25 */
/* USB1 Over-Current (active low) */
- 0x68 (PIN_INPUT | MUX_MODE7) /* gpmc_a10.gpio1_26 */
+ AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE7) /* gpmc_a10.gpio1_26 */
>;
};
};
@@ -627,37 +630,37 @@
label = "home";
linux,code = <KEY_HOME>;
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
- gpio-key,wakeup;
+ wakeup-source;
};
button@1 {
label = "menu";
linux,code = <KEY_MENU>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
- gpio-key,wakeup;
+ wakeup-source;
};
buttons@2 {
label = "power";
linux,code = <KEY_POWER>;
gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
&am33xx_pinmux {
user_leds_pins: pinmux_user_leds {
pinctrl-single,pins = <
- 0x50 (PIN_OUTPUT | MUX_MODE7) /* gpmc_a4.gpio1_20 */
- 0x54 (PIN_OUTPUT | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+ AM33XX_IOPAD(0x850, PIN_OUTPUT | MUX_MODE7) /* gpmc_a4.gpio1_20 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7) /* gpmc_a5.gpio1_21 */
>;
};
user_buttons_pins: pinmux_user_buttons {
pinctrl-single,pins = <
- 0x58 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
- 0x5C (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a7.gpio1_21 */
- 0x164 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio0_7 */
+ AM33XX_IOPAD(0x858, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
+ AM33XX_IOPAD(0x85C, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a7.gpio1_21 */
+ AM33XX_IOPAD(0x964, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio0_7 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-phycore-som.dtsi b/arch/arm/boot/dts/am335x-phycore-som.dtsi
index 2f43e458ea4a..c20ae6c6f6c7 100644
--- a/arch/arm/boot/dts/am335x-phycore-som.dtsi
+++ b/arch/arm/boot/dts/am335x-phycore-som.dtsi
@@ -56,22 +56,22 @@
&am33xx_pinmux {
ethernet0_pins: pinmux_ethernet0 {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs_dv */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxerr.rmii1_rxerr */
- 0x114 (PIN_OUTPUT | MUX_MODE1) /* mii1_txen.rmii1_txen */
- 0x124 (PIN_OUTPUT | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
- 0x128 (PIN_OUTPUT | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk.rmii1_refclk */
+ AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs_dv */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxerr.rmii1_rxerr */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT | MUX_MODE1) /* mii1_txen.rmii1_txen */
+ AM33XX_IOPAD(0x924, PIN_OUTPUT | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
+ AM33XX_IOPAD(0x928, PIN_OUTPUT | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk.rmii1_refclk */
>;
};
mdio_pins: pinmux_mdio {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
};
@@ -103,8 +103,8 @@
&am33xx_pinmux {
i2c0_pins: pinmux_i2c0 {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
};
@@ -137,20 +137,20 @@
&am33xx_pinmux {
nandflash_pins: pinmux_nandflash {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
};
@@ -324,10 +324,10 @@
&am33xx_pinmux {
spi0_pins: pinmux_spi0 {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* spi0_clk.spi0_clk */
- 0x154 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* spi0_d0.spi0_d0 */
- 0x158 (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
- 0x15c (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
+ AM33XX_IOPAD(0x950, PIN_INPUT_PULLDOWN | MUX_MODE0) /* spi0_clk.spi0_clk */
+ AM33XX_IOPAD(0x954, PIN_INPUT_PULLDOWN | MUX_MODE0) /* spi0_d0.spi0_d0 */
+ AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
+ AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-sbc-t335.dts b/arch/arm/boot/dts/am335x-sbc-t335.dts
new file mode 100644
index 000000000000..917d7ccc9109
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-sbc-t335.dts
@@ -0,0 +1,219 @@
+/*
+ * am335x-sbc-t335.dts - Device Tree file for Compulab SBC-T335
+ *
+ * Copyright (C) 2014 - 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ *
+ * 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 "am335x-cm-t335.dts"
+
+/ {
+ model = "CompuLab CM-T335 on SB-T335";
+ compatible = "compulab,sbc-t335", "compulab,cm-t335", "ti,am33xx";
+
+ /* DRM display driver */
+ panel {
+ compatible = "ti,tilcdc,panel";
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&lcd_pins_default>;
+ pinctrl-1 = <&lcd_pins_sleep>;
+
+ panel-info {
+ ac-bias = <255>;
+ ac-bias-intrpt = <0>;
+ dma-burst-sz = <16>;
+ bpp = <32>;
+ fdd = <0x80>;
+ sync-edge = <0>;
+ sync-ctrl = <1>;
+ raster-order = <0>;
+ fifo-th = <0>;
+ };
+ display-timings {
+ /* Timing selection performed by U-Boot */
+ timing0: lcd {/* 800x480p62 */
+ clock-frequency = <30000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hfront-porch = <39>;
+ hback-porch = <39>;
+ hsync-len = <47>;
+ vback-porch = <29>;
+ vfront-porch = <13>;
+ vsync-len = <2>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ };
+ timing1: dvi { /* 1024x768p60 */
+ clock-frequency = <65000000>;
+ hactive = <1024>;
+ hfront-porch = <24>;
+ hback-porch = <160>;
+ hsync-len = <136>;
+ vactive = <768>;
+ vfront-porch = <3>;
+ vback-porch = <29>;
+ vsync-len = <6>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ };
+ };
+ };
+};
+
+&am33xx_pinmux {
+ /* Display */
+ lcd_pins_default: lcd_pins_default {
+ pinctrl-single,pins = <
+ /* gpmc_ad8.lcd_data23 */
+ AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad9.lcd_data22 */
+ AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad10.lcd_data21 */
+ AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad11.lcd_data20 */
+ AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad12.lcd_data19 */
+ AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad13.lcd_data18 */
+ AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad14.lcd_data17 */
+ AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1)
+ /* gpmc_ad15.lcd_data16 */
+ AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1)
+ /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)
+ /* lcd_ac_bias_en.lcd_ac_bias_en */
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)
+ >;
+ };
+
+ lcd_pins_sleep: lcd_pins_sleep {
+ pinctrl-single,pins = <
+ /* gpmc_ad8.lcd_data23 */
+ AM33XX_IOPAD(0x820, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad9.lcd_data22 */
+ AM33XX_IOPAD(0x824, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad10.lcd_data21 */
+ AM33XX_IOPAD(0x828, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad11.lcd_data20 */
+ AM33XX_IOPAD(0x82c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad12.lcd_data19 */
+ AM33XX_IOPAD(0x830, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad13.lcd_data18 */
+ AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad14.lcd_data17 */
+ AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* gpmc_ad15.lcd_data16 */
+ AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* lcd_data0.lcd_data0 */
+ AM33XX_IOPAD(0x8a0, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data1.lcd_data1 */
+ AM33XX_IOPAD(0x8a4, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data2.lcd_data2 */
+ AM33XX_IOPAD(0x8a8, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data3.lcd_data3 */
+ AM33XX_IOPAD(0x8ac, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data4.lcd_data4 */
+ AM33XX_IOPAD(0x8b0, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data5.lcd_data5 */
+ AM33XX_IOPAD(0x8b4, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data6.lcd_data6 */
+ AM33XX_IOPAD(0x8b8, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data7.lcd_data7 */
+ AM33XX_IOPAD(0x8bc, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data8.lcd_data8 */
+ AM33XX_IOPAD(0x8c0, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data9.lcd_data9 */
+ AM33XX_IOPAD(0x8c4, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data10.lcd_data10 */
+ AM33XX_IOPAD(0x8c8, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data11.lcd_data11 */
+ AM33XX_IOPAD(0x8cc, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data12.lcd_data12 */
+ AM33XX_IOPAD(0x8d0, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data13.lcd_data13 */
+ AM33XX_IOPAD(0x8d4, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data14.lcd_data14 */
+ AM33XX_IOPAD(0x8d8, PULL_DISABLE | MUX_MODE7)
+ /* lcd_data15.lcd_data15 */
+ AM33XX_IOPAD(0x8dc, PULL_DISABLE | MUX_MODE7)
+ /* lcd_vsync.lcd_vsync */
+ AM33XX_IOPAD(0x8e0, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* lcd_hsync.lcd_hsync */
+ AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* lcd_pclk.lcd_pclk */
+ AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ /* lcd_ac_bias_en.lcd_ac_bias_en */
+ AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+};
+
+&i2c0 {
+ /* GPIO extender */
+ gpio_ext: pca9555@26 {
+ compatible = "nxp,pca9555";
+ pinctrl-names = "default";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x26>;
+ dvi_ena {
+ gpio-hog;
+ gpios = <13 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "dvi-enable";
+ };
+ lcd_ena {
+ gpio-hog;
+ gpios = <11 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "lcd-enable";
+ };
+ };
+};
+
+/* Display */
+&lcdc {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/am335x-shc.dts b/arch/arm/boot/dts/am335x-shc.dts
new file mode 100644
index 000000000000..1b5b044fcd91
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-shc.dts
@@ -0,0 +1,577 @@
+/*
+ * support for the bosch am335x based shc c3 board
+ *
+ * Copyright, C) 2015 Heiko Schocher <hs@denx.de>
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Bosch SHC";
+ compatible = "ti,am335x-shc", "ti,am335x-bone", "ti,am33xx";
+
+ aliases {
+ mmcblk0 = &mmc1;
+ mmcblk1 = &mmc2;
+ };
+
+ cpus {
+ cpu@0 {
+ /*
+ * To consider voltage drop between PMIC and SoC,
+ * tolerance value is reduced to 2% from 4% and
+ * voltage value is increased as a precaution.
+ */
+ operating-points = <
+ /* kHz uV */
+ 594000 1225000
+ 294000 1125000
+ >;
+ voltage-tolerance = <2>; /* 2 percentage */
+ cpu0-supply = <&dcdc2_reg>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ back_button {
+ label = "Back Button";
+ gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
+ linux,code = <KEY_BACK>;
+ debounce-interval = <1000>;
+ gpio-key,wakeup;
+ };
+
+ front_button {
+ label = "Front Button";
+ gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>;
+ linux,code = <KEY_FRONT>;
+ debounce-interval = <1000>;
+ gpio-key,wakeup;
+ };
+ };
+
+ leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_leds_s0>;
+
+ compatible = "gpio-leds";
+
+ led@1 {
+ label = "shc:power:red";
+ gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ led@2 {
+ label = "shc:power:bl";
+ gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "timer";
+ default-state = "on";
+ };
+
+ led@3 {
+ label = "shc:lan:red";
+ gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ led@4 {
+ label = "shc:lan:bl";
+ gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ led@5 {
+ label = "shc:cloud:red";
+ gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ led@6 {
+ label = "shc:cloud:bl";
+ gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>; /* 512 MB */
+ };
+
+ vmmcsd_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
+
+&aes {
+ status = "okay";
+};
+
+&cppi41dma {
+ status = "okay";
+};
+
+&davinci_mdio {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_default>;
+ pinctrl-1 = <&davinci_mdio_sleep>;
+ status = "okay";
+
+ ethernetphy0: ethernet-phy@0 {
+ reg = <0>;
+ smsc,disable-energy-detect;
+ };
+};
+
+&epwmss1 {
+ status = "okay";
+
+ ehrpwm1: ehrpwm@48302200 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ehrpwm1_pins>;
+ status = "okay";
+ };
+};
+
+&gpio1 {
+ hmtc_rst {
+ gpio-hog;
+ gpios = <24 GPIO_ACTIVE_LOW>;
+ output-high;
+ line-name = "homematic_reset";
+ };
+
+ hmtc_prog {
+ gpio-hog;
+ gpios = <27 GPIO_ACTIVE_LOW>;
+ output-high;
+ line-name = "homematic_program";
+ };
+};
+
+&gpio3 {
+ zgb_rst {
+ gpio-hog;
+ gpios = <18 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "zigbee_reset";
+ };
+
+ zgb_boot {
+ gpio-hog;
+ gpios = <19 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "zigbee_boot";
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "okay";
+ clock-frequency = <400000>;
+
+ tps: tps@24 {
+ reg = <0x24>;
+ };
+
+ at24@50 {
+ compatible = "at24,24c32";
+ pagesize = <32>;
+ reg = <0x50>;
+ };
+
+ pcf8563@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+&mac {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+ status = "okay";
+ slaves = <1>;
+ cpsw_emac0: slave@4a100200 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "mii";
+ phy-handle = <&ethernetphy0>;
+ };
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ bus-width = <0x4>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-inverted;
+ max-frequency = <26000000>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pins>;
+ bus-width = <8>;
+ max-frequency = <26000000>;
+ sd-uhs-sdr25;
+ vmmc-supply = <&vmmcsd_fixed>;
+ status = "okay";
+};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins>;
+ bus-width = <4>;
+ cap-power-off-card;
+ max-frequency = <26000000>;
+ sd-uhs-sdr25;
+ vmmc-supply = <&vmmcsd_fixed>;
+ status = "okay";
+};
+
+&rtc {
+ ti,no-init;
+};
+
+&sham {
+ status = "okay";
+};
+
+&tps {
+ compatible = "ti,tps65217";
+ ti,pmic-shutdown-controller;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dcdc1_reg: regulator@0 {
+ reg = <0>;
+ regulator-name = "vdds_dpr";
+ regulator-compatible = "dcdc1";
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1450000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc2_reg: regulator@1 {
+ reg = <1>;
+ /*
+ * VDD_MPU voltage limits 0.95V - 1.26V with
+ * +/-4% tolerance
+ */
+ regulator-compatible = "dcdc2";
+ regulator-name = "vdd_mpu";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1375000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <70000>;
+ };
+
+ dcdc3_reg: regulator@2 {
+ reg = <2>;
+ /*
+ * VDD_CORE voltage limits 0.95V - 1.1V with
+ * +/-4% tolerance
+ */
+ regulator-name = "vdd_core";
+ regulator-compatible = "dcdc3";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1125000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: regulator@3 {
+ reg = <3>;
+ regulator-name = "vio,vrtc,vdds";
+ regulator-compatible = "ldo1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: regulator@4 {
+ reg = <4>;
+ regulator-name = "vdd_3v3aux";
+ regulator-compatible = "ldo2";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: regulator@5 {
+ reg = <5>;
+ regulator-name = "vdd_1v8";
+ regulator-compatible = "ldo3";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo4_reg: regulator@6 {
+ reg = <6>;
+ regulator-name = "vdd_3v3a";
+ regulator-compatible = "ldo4";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins>;
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+};
+
+&usb_ctrl_mod {
+ status = "okay";
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&am33xx_pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&clkout2_pin>;
+
+ clkout2_pin: pinmux_clkout2_pin {
+ pinctrl-single,pins = <
+ /* xdma_event_intr1.clkout2 */
+ AM33XX_IOPAD(0x9b4, PIN_INPUT | MUX_MODE6)
+ >;
+ };
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0)
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ >;
+ };
+
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 reset value */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ /* mdio_data.mdio_data */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
+ /* mdio_clk.mdio_clk */
+ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ /* MDIO reset value */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ ehrpwm1_pins: pinmux_ehrpwm1 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE6) /* gpmc_a3.gpio1_19 */
+ >;
+ };
+
+ emmc_pins: pinmux_emmc_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x880, PIN_INPUT | MUX_MODE2)
+ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1)
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1)
+ >;
+ };
+
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0)
+ AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0)
+ >;
+ };
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE5)
+ >;
+ };
+
+ mmc3_pins: pinmux_mmc3_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x830, PIN_INPUT | MUX_MODE3)
+ AM33XX_IOPAD(0x834, PIN_INPUT | MUX_MODE3)
+ AM33XX_IOPAD(0x838, PIN_INPUT | MUX_MODE3)
+ AM33XX_IOPAD(0x83c, PIN_INPUT | MUX_MODE3)
+ AM33XX_IOPAD(0x888, PIN_INPUT | MUX_MODE3)
+ AM33XX_IOPAD(0x88c, PIN_INPUT | MUX_MODE3)
+ >;
+ };
+
+ uart0_pins: pinmux_uart0_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x968, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x96c, PIN_OUTPUT | MUX_MODE0)
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x974, PIN_OUTPUT | MUX_MODE0)
+ >;
+ };
+
+ uart1_pins: pinmux_uart1 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x978, PIN_INPUT_PULLDOWN | MUX_MODE0)
+ AM33XX_IOPAD(0x97C, PIN_OUTPUT | MUX_MODE0)
+ AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0)
+ AM33XX_IOPAD(0x984, PIN_OUTPUT | MUX_MODE0)
+ >;
+ };
+
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)
+ AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)
+ >;
+ };
+
+ uart4_pins: pinmux_uart4_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6)
+ AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE6)
+ >;
+ };
+
+ user_leds_s0: user_leds_s0 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x844, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x858, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLUP | MUX_MODE7)
+ AM33XX_IOPAD(0x860, PIN_INPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x864, PIN_INPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x86c, PIN_INPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x878, PIN_OUTPUT_PULLUP | MUX_MODE7)
+ AM33XX_IOPAD(0x87c, PIN_INPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x894, PIN_INPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x958, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x95c, PIN_OUTPUT | MUX_MODE7)
+ AM33XX_IOPAD(0x964, PIN_OUTPUT_PULLUP | MUX_MODE7)
+ AM33XX_IOPAD(0x9a0, PIN_OUTPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x9a4, PIN_OUTPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE7)
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/am335x-sl50.dts b/arch/arm/boot/dts/am335x-sl50.dts
index 3303c281697b..d38edfa53bb9 100644
--- a/arch/arm/boot/dts/am335x-sl50.dts
+++ b/arch/arm/boot/dts/am335x-sl50.dts
@@ -375,16 +375,19 @@
pinctrl-0 = <&uart4_pins>;
};
-#include "tps65217.dtsi"
-
&tps {
+ compatible = "ti,tps65217";
ti,pmic-shutdown-controller;
interrupt-parent = <&intc>;
interrupts = <7>; /* NNMI */
regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
dcdc1_reg: regulator@0 {
+ reg = <0>;
/* VDDS_DDR */
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
@@ -392,6 +395,7 @@
};
dcdc2_reg: regulator@1 {
+ reg = <1>;
/* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
regulator-name = "vdd_mpu";
regulator-min-microvolt = <925000>;
@@ -401,6 +405,7 @@
};
dcdc3_reg: regulator@2 {
+ reg = <2>;
/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
regulator-name = "vdd_core";
regulator-min-microvolt = <925000>;
@@ -410,6 +415,7 @@
};
ldo1_reg: regulator@3 {
+ reg = <3>;
/* VRTC / VIO / VDDS*/
regulator-always-on;
regulator-min-microvolt = <1800000>;
@@ -417,6 +423,7 @@
};
ldo2_reg: regulator@4 {
+ reg = <4>;
/* VDD_3V3AUX */
regulator-always-on;
regulator-min-microvolt = <3300000>;
@@ -424,6 +431,7 @@
};
ldo3_reg: regulator@5 {
+ reg = <5>;
/* VDD_1V8 */
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -431,6 +439,7 @@
};
ldo4_reg: regulator@6 {
+ reg = <6>;
/* VDD_3V3A */
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/am335x-wega.dtsi b/arch/arm/boot/dts/am335x-wega.dtsi
index 2cecb3951e1b..282f6d4b27bc 100644
--- a/arch/arm/boot/dts/am335x-wega.dtsi
+++ b/arch/arm/boot/dts/am335x-wega.dtsi
@@ -28,8 +28,8 @@
&am33xx_pinmux {
dcan1_pins: pinmux_dcan1 {
pinctrl-single,pins = <
- 0x168 (PIN_OUTPUT_PULLUP | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
- 0x16c (PIN_INPUT_PULLUP | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
+ AM33XX_IOPAD(0x968, PIN_OUTPUT_PULLUP | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
+ AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
>;
};
};
@@ -44,20 +44,20 @@
&am33xx_pinmux {
ethernet1_pins: pinmux_ethernet1 {
pinctrl-single,pins = <
- 0x40 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a0.mii2_txen */
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a1.mii2_rxdv */
- 0x48 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a2.mii2_txd3 */
- 0x4c (PIN_OUTPUT | MUX_MODE1) /* gpmc_a3.mii2_txd2 */
- 0x50 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a4.mii2_txd1 */
- 0x54 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a5.mii2_txd0 */
- 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a6.mii2_txclk */
- 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a7.mii2_rxclk */
- 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a8.mii2_rxd3 */
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a9.mii2_rxd2 */
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a10.mii2_rxd1 */
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a11.mii2_rxd0 */
- 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_wpn.mii2_rxerr */
- 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_ben1.mii2_col */
+ AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE1) /* gpmc_a0.mii2_txen */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a1.mii2_rxdv */
+ AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE1) /* gpmc_a2.mii2_txd3 */
+ AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE1) /* gpmc_a3.mii2_txd2 */
+ AM33XX_IOPAD(0x850, PIN_OUTPUT | MUX_MODE1) /* gpmc_a4.mii2_txd1 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE1) /* gpmc_a5.mii2_txd0 */
+ AM33XX_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a6.mii2_txclk */
+ AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a7.mii2_rxclk */
+ AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a8.mii2_rxd3 */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a9.mii2_rxd2 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a10.mii2_rxd1 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_a11.mii2_rxd0 */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_wpn.mii2_rxerr */
+ AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE1) /* gpmc_ben1.mii2_col */
>;
};
};
@@ -79,13 +79,13 @@
&am33xx_pinmux {
mmc1_pins: pinmux_mmc1 {
pinctrl-single,pins = <
- 0x0F0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
- 0x0F4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
- 0x0F8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
- 0x0FC (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
- 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
- 0x160 (PIN_INPUT_PULLUP | MUX_MODE7) /* spi0_cs1.mmc0_sdcd */
+ AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE7) /* spi0_cs1.mmc0_sdcd */
>;
};
};
@@ -103,17 +103,17 @@
&am33xx_pinmux {
uart0_pins: pinmux_uart0 {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x180 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
- 0x184 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
- 0x178 (PIN_INPUT | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
- 0x17c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
+ AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
+ AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
+ AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
>;
};
};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index d23e2524d694..04885f9f959e 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -161,6 +161,14 @@
mboxes = <&mailbox &mbox_wkupm3>;
};
+ edma_xbar: dma-router@f90 {
+ compatible = "ti,am335x-edma-crossbar";
+ reg = <0xf90 0x40>;
+ #dma-cells = <3>;
+ dma-requests = <32>;
+ dma-masters = <&edma>;
+ };
+
scm_clockdomains: clockdomains {
};
};
@@ -174,12 +182,44 @@
};
edma: edma@49000000 {
- compatible = "ti,edma3";
- ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
- reg = <0x49000000 0x10000>,
- <0x44e10f90 0x40>;
+ compatible = "ti,edma3-tpcc";
+ ti,hwmods = "tpcc";
+ reg = <0x49000000 0x10000>;
+ reg-names = "edma3_cc";
interrupts = <12 13 14>;
- #dma-cells = <1>;
+ interrupt-names = "edma3_ccint", "emda3_mperr",
+ "edma3_ccerrint";
+ dma-requests = <64>;
+ #dma-cells = <2>;
+
+ ti,tptcs = <&edma_tptc0 7>, <&edma_tptc1 5>,
+ <&edma_tptc2 0>;
+
+ ti,edma-memcpy-channels = <20 21>;
+ };
+
+ edma_tptc0: tptc@49800000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc0";
+ reg = <0x49800000 0x100000>;
+ interrupts = <112>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc1: tptc@49900000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc1";
+ reg = <0x49900000 0x100000>;
+ interrupts = <113>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc2: tptc@49a00000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc2";
+ reg = <0x49a00000 0x100000>;
+ interrupts = <114>;
+ interrupt-names = "edma3_tcerrint";
};
gpio0: gpio@44e07000 {
@@ -233,7 +273,7 @@
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "disabled";
- dmas = <&edma 26>, <&edma 27>;
+ dmas = <&edma 26 0>, <&edma 27 0>;
dma-names = "tx", "rx";
};
@@ -244,7 +284,7 @@
reg = <0x48022000 0x2000>;
interrupts = <73>;
status = "disabled";
- dmas = <&edma 28>, <&edma 29>;
+ dmas = <&edma 28 0>, <&edma 29 0>;
dma-names = "tx", "rx";
};
@@ -255,7 +295,7 @@
reg = <0x48024000 0x2000>;
interrupts = <74>;
status = "disabled";
- dmas = <&edma 30>, <&edma 31>;
+ dmas = <&edma 30 0>, <&edma 31 0>;
dma-names = "tx", "rx";
};
@@ -322,8 +362,8 @@
ti,dual-volt;
ti,needs-special-reset;
ti,needs-special-hs-handling;
- dmas = <&edma 24
- &edma 25>;
+ dmas = <&edma_xbar 24 0 0
+ &edma_xbar 25 0 0>;
dma-names = "tx", "rx";
interrupts = <64>;
interrupt-parent = <&intc>;
@@ -335,8 +375,8 @@
compatible = "ti,omap4-hsmmc";
ti,hwmods = "mmc2";
ti,needs-special-reset;
- dmas = <&edma 2
- &edma 3>;
+ dmas = <&edma 2 0
+ &edma 3 0>;
dma-names = "tx", "rx";
interrupts = <28>;
interrupt-parent = <&intc>;
@@ -474,10 +514,10 @@
interrupts = <65>;
ti,spi-num-cs = <2>;
ti,hwmods = "spi0";
- dmas = <&edma 16
- &edma 17
- &edma 18
- &edma 19>;
+ dmas = <&edma 16 0
+ &edma 17 0
+ &edma 18 0
+ &edma 19 0>;
dma-names = "tx0", "rx0", "tx1", "rx1";
status = "disabled";
};
@@ -490,10 +530,10 @@
interrupts = <125>;
ti,spi-num-cs = <2>;
ti,hwmods = "spi1";
- dmas = <&edma 42
- &edma 43
- &edma 44
- &edma 45>;
+ dmas = <&edma 42 0
+ &edma 43 0
+ &edma 44 0
+ &edma 45 0>;
dma-names = "tx0", "rx0", "tx1", "rx1";
status = "disabled";
};
@@ -819,6 +859,8 @@
ti,no-idle-on-init;
reg = <0x50000000 0x2000>;
interrupts = <100>;
+ dmas = <&edma 52>;
+ dma-names = "rxtx";
gpmc,num-cs = <7>;
gpmc,num-waitpins = <2>;
#address-cells = <2>;
@@ -831,7 +873,7 @@
ti,hwmods = "sham";
reg = <0x53100000 0x200>;
interrupts = <109>;
- dmas = <&edma 36>;
+ dmas = <&edma 36 0>;
dma-names = "rx";
};
@@ -840,8 +882,8 @@
ti,hwmods = "aes";
reg = <0x53500000 0xa0>;
interrupts = <103>;
- dmas = <&edma 6>,
- <&edma 5>;
+ dmas = <&edma 6 0>,
+ <&edma 5 0>;
dma-names = "tx", "rx";
};
@@ -854,8 +896,8 @@
interrupts = <80>, <81>;
interrupt-names = "tx", "rx";
status = "disabled";
- dmas = <&edma 8>,
- <&edma 9>;
+ dmas = <&edma 8 2>,
+ <&edma 9 2>;
dma-names = "tx", "rx";
};
@@ -868,8 +910,8 @@
interrupts = <82>, <83>;
interrupt-names = "tx", "rx";
status = "disabled";
- dmas = <&edma 10>,
- <&edma 11>;
+ dmas = <&edma 10 2>,
+ <&edma 11 2>;
dma-names = "tx", "rx";
};
diff --git a/arch/arm/boot/dts/am3517-craneboard.dts b/arch/arm/boot/dts/am3517-craneboard.dts
index 2d40b3f241cd..cb7de1d4e05f 100644
--- a/arch/arm/boot/dts/am3517-craneboard.dts
+++ b/arch/arm/boot/dts/am3517-craneboard.dts
@@ -77,7 +77,7 @@
&omap3_pmx_core {
tps_pins: pinmux_tps_pins {
pinctrl-single,pins = <
- 0x1b0 (PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq.sys_nirq */
+ OMAP3_CORE1_IOPAD(0x21e0, PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq.sys_nirq */
>;
};
};
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index de8791a4d131..df955ba4dc62 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -30,6 +30,7 @@
serial5 = &uart5;
ethernet0 = &cpsw_emac0;
ethernet1 = &cpsw_emac1;
+ spi0 = &qspi;
};
cpus {
@@ -171,6 +172,14 @@
mboxes = <&mailbox &mbox_wkupm3>;
};
+ edma_xbar: dma-router@f90 {
+ compatible = "ti,am335x-edma-crossbar";
+ reg = <0xf90 0x40>;
+ #dma-cells = <3>;
+ dma-requests = <64>;
+ dma-masters = <&edma>;
+ };
+
scm_clockdomains: clockdomains {
};
};
@@ -183,14 +192,46 @@
};
edma: edma@49000000 {
- compatible = "ti,edma3";
- ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
- reg = <0x49000000 0x10000>,
- <0x44e10f90 0x10>;
+ compatible = "ti,edma3-tpcc";
+ ti,hwmods = "tpcc";
+ reg = <0x49000000 0x10000>;
+ reg-names = "edma3_cc";
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
- #dma-cells = <1>;
+ <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma3_ccint", "emda3_mperr",
+ "edma3_ccerrint";
+ dma-requests = <64>;
+ #dma-cells = <2>;
+
+ ti,tptcs = <&edma_tptc0 7>, <&edma_tptc1 5>,
+ <&edma_tptc2 0>;
+
+ ti,edma-memcpy-channels = <32 33>;
+ };
+
+ edma_tptc0: tptc@49800000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc0";
+ reg = <0x49800000 0x100000>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc1: tptc@49900000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc1";
+ reg = <0x49900000 0x100000>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc2: tptc@49a00000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc2";
+ reg = <0x49a00000 0x100000>;
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma3_tcerrint";
};
uart0: serial@44e09000 {
@@ -495,8 +536,8 @@
ti,hwmods = "mmc1";
ti,dual-volt;
ti,needs-special-reset;
- dmas = <&edma 24
- &edma 25>;
+ dmas = <&edma 24 0>,
+ <&edma 25 0>;
dma-names = "tx", "rx";
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -507,8 +548,8 @@
reg = <0x481d8000 0x1000>;
ti,hwmods = "mmc2";
ti,needs-special-reset;
- dmas = <&edma 2
- &edma 3>;
+ dmas = <&edma 2 0>,
+ <&edma 3 0>;
dma-names = "tx", "rx";
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -776,7 +817,7 @@
compatible = "ti,omap5-sham";
ti,hwmods = "sham";
reg = <0x53100000 0x300>;
- dmas = <&edma 36>;
+ dmas = <&edma 36 0>;
dma-names = "rx";
interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
};
@@ -786,8 +827,8 @@
ti,hwmods = "aes";
reg = <0x53501000 0xa0>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&edma 6
- &edma 5>;
+ dmas = <&edma 6 0>,
+ <&edma 5 0>;
dma-names = "tx", "rx";
};
@@ -796,8 +837,8 @@
ti,hwmods = "des";
reg = <0x53701000 0xa0>;
interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&edma 34
- &edma 33>;
+ dmas = <&edma 34 0>,
+ <&edma 33 0>;
dma-names = "tx", "rx";
};
@@ -810,8 +851,8 @@
interrupts = <80>, <81>;
interrupt-names = "tx", "rx";
status = "disabled";
- dmas = <&edma 8>,
- <&edma 9>;
+ dmas = <&edma 8 2>,
+ <&edma 9 2>;
dma-names = "tx", "rx";
};
@@ -824,8 +865,8 @@
interrupts = <82>, <83>;
interrupt-names = "tx", "rx";
status = "disabled";
- dmas = <&edma 10>,
- <&edma 11>;
+ dmas = <&edma 10 2>,
+ <&edma 11 2>;
dma-names = "tx", "rx";
};
@@ -842,6 +883,8 @@
gpmc: gpmc@50000000 {
compatible = "ti,am3352-gpmc";
ti,hwmods = "gpmc";
+ dmas = <&edma 52>;
+ dma-names = "rxtx";
clocks = <&l3s_gclk>;
clock-names = "fck";
reg = <0x50000000 0x2000>;
@@ -963,7 +1006,9 @@
qspi: qspi@47900000 {
compatible = "ti,am4372-qspi";
- reg = <0x47900000 0x100>;
+ reg = <0x47900000 0x100>,
+ <0x30000000 0x4000000>;
+ reg-names = "qspi_base", "qspi_mmap";
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "qspi";
diff --git a/arch/arm/boot/dts/am437x-cm-t43.dts b/arch/arm/boot/dts/am437x-cm-t43.dts
new file mode 100644
index 000000000000..8677f4cce9e9
--- /dev/null
+++ b/arch/arm/boot/dts/am437x-cm-t43.dts
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2015 CompuLab, Ltd. - http://www.compulab.co.il/
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/pinctrl/am43xx.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "am4372.dtsi"
+
+/ {
+ model = "CompuLab CM-T43";
+ compatible = "compulab,am437x-cm-t43", "ti,am4372", "ti,am43";
+
+ leds {
+ compatible = "gpio-leds";
+
+ ledb {
+ label = "cm-t43:green";
+ gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ vmmc_3v3: fixedregulator-v3_3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmc_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ enable-active-high;
+ };
+};
+
+&am43xx_pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cm_t43_led_pins>;
+
+ cm_t43_led_pins: cm_t43_led_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0xa78, MUX_MODE7)
+ >;
+ };
+
+ i2c0_pins: i2c0_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x988, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM4372_IOPAD(0x98c, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ >;
+ };
+
+ emmc_pins: emmc_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad8.mmc1_dat0 */
+ AM4372_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad9.mmc1_dat1 */
+ AM4372_IOPAD(0x828, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad10.mmc1_dat2 */
+ AM4372_IOPAD(0x82c, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad11.mmc1_dat3 */
+ AM4372_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad12.mmc1_dat4 */
+ AM4372_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad13.mmc1_dat5 */
+ AM4372_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad14.mmc1_dat6 */
+ AM4372_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_ad15.mmc1_dat7 */
+ AM4372_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ AM4372_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ >;
+ };
+
+ spi0_pins: pinmux_spi0_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x950, PIN_INPUT | MUX_MODE0) /* spi0_sclk.spi0_sclk */
+ AM4372_IOPAD(0x954, PIN_INPUT | MUX_MODE0) /* spi0_d0.spi0_d0 */
+ AM4372_IOPAD(0x958, PIN_OUTPUT | MUX_MODE0) /* spi0_d1.spi0_d1 */
+ AM4372_IOPAD(0x95C, PIN_OUTPUT | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
+ >;
+ };
+
+ nand_flash_x8: nand_flash_x8 {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x800, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x804, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x808, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x80c, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x810, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x814, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x818, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x81c, PIN_INPUT | PULL_DISABLE | MUX_MODE0)
+ AM4372_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x87c, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x898, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ AM4372_IOPAD(0x894, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ AM4372_IOPAD(0x890, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ AM4372_IOPAD(0x89c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+ >;
+ };
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ AM4372_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_txen */
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rxctl */
+ AM4372_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_txd3 */
+ AM4372_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_txd2 */
+ AM4372_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_txd1 */
+ AM4372_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_txd0 */
+ AM4372_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rmii1_tclk */
+ AM4372_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
+ AM4372_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd3 */
+ AM4372_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd2 */
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd1 */
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd0 */
+ AM4372_IOPAD(0xa74, MUX_MODE3)
+ /* Slave 2 */
+ AM4372_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a0.txen */
+ AM4372_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a1.rxctl */
+ AM4372_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a2.txd3 */
+ AM4372_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a3.txd2 */
+ AM4372_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a4.txd1 */
+ AM4372_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a5.txd0 */
+ AM4372_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a6.tclk */
+ AM4372_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a7.rclk */
+ AM4372_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a8.rxd3 */
+ AM4372_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a9.rxd2 */
+ AM4372_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a10.rxd1 */
+ AM4372_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a11.rxd0 */
+ AM4372_IOPAD(0xa38, MUX_MODE7)
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ /* MDIO */
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM4372_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ >;
+ };
+};
+
+&gpmc {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_flash_x8>;
+ ranges = <0 0 0x08000000 0x1000000>;
+ nand@0,0 {
+ reg = <0 0 0>;
+ ti,nand-ecc-opt = "bch8";
+ ti,elm-id = <&elm>;
+
+ nand-bus-width = <8>;
+ gpmc,device-width = <1>;
+ gpmc,sync-clk-ps = <0>;
+ gpmc,cs-on-ns = <0>;
+ gpmc,cs-rd-off-ns = <44>;
+ gpmc,cs-wr-off-ns = <44>;
+ gpmc,adv-on-ns = <6>;
+ gpmc,adv-rd-off-ns = <34>;
+ gpmc,adv-wr-off-ns = <44>;
+ gpmc,we-on-ns = <0>;
+ gpmc,we-off-ns = <40>;
+ gpmc,oe-on-ns = <0>;
+ gpmc,oe-off-ns = <54>;
+ gpmc,access-ns = <64>;
+ gpmc,rd-cycle-ns = <82>;
+ gpmc,wr-cycle-ns = <82>;
+ gpmc,wait-on-read = "true";
+ gpmc,wait-on-write = "true";
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-delay-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,wr-access-ns = <40>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+
+ gpmc,wait-pin = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* MTD partition table */
+ partition@0 {
+ label = "kernel";
+ reg = <0x0 0x00980000>;
+ };
+ partition@980000 {
+ label = "dtb";
+ reg = <0x00980000 0x00080000>;
+ };
+ partition@a00000 {
+ label = "rootfs";
+ reg = <0x00a00000 0x0>;
+ };
+ };
+};
+
+&i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ clock-frequency = <100000>;
+
+ tps65218: tps65218@24 {
+ compatible = "ti,tps65218";
+ reg = <0x24>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */
+ interrupt-parent = <&gic>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ dcdc1: regulator-dcdc1 {
+ compatible = "ti,tps65218-dcdc1";
+ regulator-name = "vdd_core";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <1144000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc2: regulator-dcdc2 {
+ compatible = "ti,tps65218-dcdc2";
+ regulator-name = "vdd_mpu";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <1378000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc3: regulator-dcdc3 {
+ compatible = "ti,tps65218-dcdc3";
+ regulator-name = "vdcdc3";
+ regulator-suspend-enable;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc5: regulator-dcdc5 {
+ compatible = "ti,tps65218-dcdc5";
+ regulator-name = "v1_0bat";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc6: regulator-dcdc6 {
+ compatible = "ti,tps65218-dcdc6";
+ regulator-name = "v1_8bat";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1: regulator-ldo1 {
+ compatible = "ti,tps65218-ldo1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+
+ eeprom_module: at24@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+};
+
+&gpio0 {
+ status = "okay";
+};
+
+&gpio1 {
+ status = "okay";
+};
+
+&gpio2 {
+ status = "okay";
+};
+
+&gpio3 {
+ status = "okay";
+};
+
+&gpio4 {
+ status = "okay";
+};
+
+&gpio5 {
+ status = "okay";
+};
+
+&mmc2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pins>;
+ vmmc-supply = <&vmmc_3v3>;
+ bus-width = <8>;
+ ti,non-removable;
+};
+
+&spi0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins>;
+ dmas = <&edma 16
+ &edma 17>;
+ dma-names = "tx0", "rx0";
+
+ flash: w25q64cvzpig@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ partition@0 {
+ label = "uboot";
+ reg = <0x0 0xc0000>;
+ };
+
+ partition@c0000 {
+ label = "uboot environment";
+ reg = <0xc0000 0x40000>;
+ };
+
+ partition@100000 {
+ label = "reserved";
+ reg = <0x100000 0x100000>;
+ };
+ };
+};
+
+&mac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpsw_default>;
+ dual_emac = <1>;
+ status = "okay";
+};
+
+&davinci_mdio {
+ pinctrl-names = "default";
+ pinctrl-0 = <&davinci_mdio_default>;
+ status = "okay";
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii-txid";
+ dual_emac_res_vlan = <1>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii-txid";
+ dual_emac_res_vlan = <2>;
+};
+
+&dwc3_1 {
+ status = "okay";
+};
+
+&usb2_phy1 {
+ status = "okay";
+};
+
+&usb1 {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&dwc3_2 {
+ status = "okay";
+};
+
+&usb2_phy2 {
+ status = "okay";
+};
+
+&usb2 {
+ dr_mode = "host";
+ status = "okay";
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "peripheral", "host", "otg";
+};
+
+&elm {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&tscadc {
+ status = "okay";
+ tsc {
+ ti,wires = <4>;
+ ti,x-plate-resistance = <200>;
+ ti,coordiante-readouts = <5>;
+ ti,wire-config = <0x00 0x11 0x22 0x33>;
+ };
+
+ adc {
+ ti,adc-channels = <4 5 6 7>;
+ };
+};
+
+&cpu {
+ cpu0-supply = <&dcdc2>;
+ operating-points = <1000000 1330000>,
+ <800000 1260000>,
+ <720000 1200000>,
+ <600000 1100000>,
+ <300000 950000>;
+};
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index d2450ab0a380..64d43325bcbc 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -154,138 +154,138 @@
i2c0_pins: i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM4372_IOPAD(0x988, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM4372_IOPAD(0x98c, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
i2c1_pins: i2c1_pins {
pinctrl-single,pins = <
- 0x15c (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
- 0x158 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
+ AM4372_IOPAD(0x95c, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
+ AM4372_IOPAD(0x958, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM4372_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
ecap0_pins: backlight_pins {
pinctrl-single,pins = <
- 0x164 MUX_MODE0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
+ AM4372_IOPAD(0x964, MUX_MODE0) /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
>;
};
pixcir_ts_pins: pixcir_ts_pins {
pinctrl-single,pins = <
- 0x264 (PIN_INPUT_PULLUP | MUX_MODE7) /* spi2_d0.gpio3_22 */
+ AM4372_IOPAD(0xa64, PIN_INPUT_PULLUP | MUX_MODE7) /* spi2_d0.gpio3_22 */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_txen */
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rxctl */
- 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_txd3 */
- 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_txd2 */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_txd1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_txd0 */
- 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rmii1_tclk */
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd3 */
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd2 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd0 */
+ AM4372_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_txen */
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rxctl */
+ AM4372_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_txd3 */
+ AM4372_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_txd2 */
+ AM4372_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_txd1 */
+ AM4372_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_txd0 */
+ AM4372_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rmii1_tclk */
+ AM4372_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
+ AM4372_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd3 */
+ AM4372_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd2 */
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rxd1 */
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rxd0 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM4372_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
nand_flash_x8: nand_flash_x8 {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x74 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpmc_wpn */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM4372_IOPAD(0x800, PIN_INPUT | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM4372_IOPAD(0x804, PIN_INPUT | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM4372_IOPAD(0x808, PIN_INPUT | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM4372_IOPAD(0x80c, PIN_INPUT | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM4372_IOPAD(0x810, PIN_INPUT | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM4372_IOPAD(0x814, PIN_INPUT | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM4372_IOPAD(0x818, PIN_INPUT | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM4372_IOPAD(0x81c, PIN_INPUT | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM4372_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM4372_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpmc_wpn */
+ AM4372_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM4372_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM4372_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM4372_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM4372_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
dss_pins: dss_pins {
pinctrl-single,pins = <
- 0x020 (PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 8 -> DSS DATA 23 */
- 0x024 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x028 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x02c (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x030 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x034 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x038 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x03c (PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 15 -> DSS DATA 16 */
- 0x0a0 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 0 */
- 0x0a4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0a8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0ac (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0b0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0b4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0b8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0bc (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0c0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0c4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0c8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0cc (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0d0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0d4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0d8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0dc (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 15 */
- 0x0e0 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS VSYNC */
- 0x0e4 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS HSYNC */
- 0x0e8 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS PCLK */
- 0x0ec (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS AC BIAS EN */
+ AM4372_IOPAD(0x820, PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 8 -> DSS DATA 23 */
+ AM4372_IOPAD(0x824, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x828, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x82c, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x830, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x834, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x838, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x83c, PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 15 -> DSS DATA 16 */
+ AM4372_IOPAD(0x8a0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 0 */
+ AM4372_IOPAD(0x8a4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8a8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8ac, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8bc, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8cc, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8dc, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 15 */
+ AM4372_IOPAD(0x8e0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS VSYNC */
+ AM4372_IOPAD(0x8e4, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS HSYNC */
+ AM4372_IOPAD(0x8e8, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS PCLK */
+ AM4372_IOPAD(0x8ec, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS AC BIAS EN */
>;
};
@@ -293,208 +293,208 @@
display_mux_pins: display_mux_pins {
pinctrl-single,pins = <
/* GPIO 5_8 to select LCD / HDMI */
- 0x238 (PIN_OUTPUT_PULLUP | MUX_MODE7)
+ AM4372_IOPAD(0xa38, PIN_OUTPUT_PULLUP | MUX_MODE7)
>;
};
dcan0_default: dcan0_default_pins {
pinctrl-single,pins = <
- 0x178 (PIN_OUTPUT | MUX_MODE2) /* uart1_ctsn.d_can0_tx */
- 0x17c (PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_rtsn.d_can0_rx */
+ AM4372_IOPAD(0x978, PIN_OUTPUT | MUX_MODE2) /* uart1_ctsn.d_can0_tx */
+ AM4372_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_rtsn.d_can0_rx */
>;
};
dcan0_sleep: dcan0_sleep_pins {
pinctrl-single,pins = <
- 0x178 (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_ctsn.gpio0_12 */
- 0x17c (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_rtsn.gpio0_13 */
+ AM4372_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_ctsn.gpio0_12 */
+ AM4372_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_rtsn.gpio0_13 */
>;
};
dcan1_default: dcan1_default_pins {
pinctrl-single,pins = <
- 0x180 (PIN_OUTPUT | MUX_MODE2) /* uart1_rxd.d_can1_tx */
- 0x184 (PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_txd.d_can1_rx */
+ AM4372_IOPAD(0x980, PIN_OUTPUT | MUX_MODE2) /* uart1_rxd.d_can1_tx */
+ AM4372_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_txd.d_can1_rx */
>;
};
dcan1_sleep: dcan1_sleep_pins {
pinctrl-single,pins = <
- 0x180 (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_rxd.gpio0_14 */
- 0x184 (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_txd.gpio0_15 */
+ AM4372_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_rxd.gpio0_14 */
+ AM4372_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_txd.gpio0_15 */
>;
};
vpfe0_pins_default: vpfe0_pins_default {
pinctrl-single,pins = <
- 0x1B0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_hd mode 0*/
- 0x1B4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_vd mode 0*/
- 0x1C0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_pclk mode 0*/
- 0x1C4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data8 mode 0*/
- 0x1C8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data9 mode 0*/
- 0x208 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data0 mode 0*/
- 0x20C (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data1 mode 0*/
- 0x210 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data2 mode 0*/
- 0x214 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data3 mode 0*/
- 0x218 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data4 mode 0*/
- 0x21C (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data5 mode 0*/
- 0x220 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data6 mode 0*/
- 0x224 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data7 mode 0*/
+ AM4372_IOPAD(0x9b0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_hd mode 0*/
+ AM4372_IOPAD(0x9b4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_vd mode 0*/
+ AM4372_IOPAD(0x9c0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_pclk mode 0*/
+ AM4372_IOPAD(0x9c4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data8 mode 0*/
+ AM4372_IOPAD(0x9c8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data9 mode 0*/
+ AM4372_IOPAD(0xa08, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data0 mode 0*/
+ AM4372_IOPAD(0xa0c, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data1 mode 0*/
+ AM4372_IOPAD(0xa10, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data2 mode 0*/
+ AM4372_IOPAD(0xa14, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data3 mode 0*/
+ AM4372_IOPAD(0xa18, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data4 mode 0*/
+ AM4372_IOPAD(0xa1c, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data5 mode 0*/
+ AM4372_IOPAD(0xa20, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data6 mode 0*/
+ AM4372_IOPAD(0xa24, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data7 mode 0*/
>;
};
vpfe0_pins_sleep: vpfe0_pins_sleep {
pinctrl-single,pins = <
- 0x1B0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_hd mode 0*/
- 0x1B4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_vd mode 0*/
- 0x1C0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_pclk mode 0*/
- 0x1C4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data8 mode 0*/
- 0x1C8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data9 mode 0*/
- 0x208 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data0 mode 0*/
- 0x20C (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data1 mode 0*/
- 0x210 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data2 mode 0*/
- 0x214 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data3 mode 0*/
- 0x218 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data4 mode 0*/
- 0x21C (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data5 mode 0*/
- 0x220 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data6 mode 0*/
- 0x224 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data7 mode 0*/
+ AM4372_IOPAD(0x9b0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_hd mode 0*/
+ AM4372_IOPAD(0x9b4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_vd mode 0*/
+ AM4372_IOPAD(0x9c0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_pclk mode 0*/
+ AM4372_IOPAD(0x9c4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data8 mode 0*/
+ AM4372_IOPAD(0x9c8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data9 mode 0*/
+ AM4372_IOPAD(0xa08, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data0 mode 0*/
+ AM4372_IOPAD(0xa0c, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data1 mode 0*/
+ AM4372_IOPAD(0xa10, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data2 mode 0*/
+ AM4372_IOPAD(0xa14, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data3 mode 0*/
+ AM4372_IOPAD(0xa18, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data4 mode 0*/
+ AM4372_IOPAD(0xa1c, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data5 mode 0*/
+ AM4372_IOPAD(0xa20, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data6 mode 0*/
+ AM4372_IOPAD(0xa24, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam0_data7 mode 0*/
>;
};
vpfe1_pins_default: vpfe1_pins_default {
pinctrl-single,pins = <
- 0x1CC (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data9 mode 0*/
- 0x1D0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data8 mode 0*/
- 0x1D4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_hd mode 0*/
- 0x1D8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_vd mode 0*/
- 0x1DC (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_pclk mode 0*/
- 0x1E8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data0 mode 0*/
- 0x1EC (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data1 mode 0*/
- 0x1F0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data2 mode 0*/
- 0x1F4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data3 mode 0*/
- 0x1F8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data4 mode 0*/
- 0x1FC (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data5 mode 0*/
- 0x200 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data6 mode 0*/
- 0x204 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data7 mode 0*/
+ AM4372_IOPAD(0x9cc, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data9 mode 0*/
+ AM4372_IOPAD(0x9d0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data8 mode 0*/
+ AM4372_IOPAD(0x9d4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_hd mode 0*/
+ AM4372_IOPAD(0x9d8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_vd mode 0*/
+ AM4372_IOPAD(0x9dC, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_pclk mode 0*/
+ AM4372_IOPAD(0x9e8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data0 mode 0*/
+ AM4372_IOPAD(0x9ec, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data1 mode 0*/
+ AM4372_IOPAD(0x9f0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data2 mode 0*/
+ AM4372_IOPAD(0x9f4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data3 mode 0*/
+ AM4372_IOPAD(0x9f8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data4 mode 0*/
+ AM4372_IOPAD(0x9fc, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data5 mode 0*/
+ AM4372_IOPAD(0xa00, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data6 mode 0*/
+ AM4372_IOPAD(0xa04, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data7 mode 0*/
>;
};
vpfe1_pins_sleep: vpfe1_pins_sleep {
pinctrl-single,pins = <
- 0x1CC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data9 mode 0*/
- 0x1D0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data8 mode 0*/
- 0x1D4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_hd mode 0*/
- 0x1D8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_vd mode 0*/
- 0x1DC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_pclk mode 0*/
- 0x1E8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data0 mode 0*/
- 0x1EC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data1 mode 0*/
- 0x1F0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data2 mode 0*/
- 0x1F4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data3 mode 0*/
- 0x1F8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data4 mode 0*/
- 0x1FC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data5 mode 0*/
- 0x200 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data6 mode 0*/
- 0x204 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data7 mode 0*/
+ AM4372_IOPAD(0x9cc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data9 mode 0*/
+ AM4372_IOPAD(0x9d0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data8 mode 0*/
+ AM4372_IOPAD(0x9d4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_hd mode 0*/
+ AM4372_IOPAD(0x9d8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_vd mode 0*/
+ AM4372_IOPAD(0x9dc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_pclk mode 0*/
+ AM4372_IOPAD(0x9e8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data0 mode 0*/
+ AM4372_IOPAD(0x9ec, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data1 mode 0*/
+ AM4372_IOPAD(0x9f0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data2 mode 0*/
+ AM4372_IOPAD(0x9f4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data3 mode 0*/
+ AM4372_IOPAD(0x9f8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data4 mode 0*/
+ AM4372_IOPAD(0x9fc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data5 mode 0*/
+ AM4372_IOPAD(0xa00, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data6 mode 0*/
+ AM4372_IOPAD(0xa04, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7) /* cam1_data7 mode 0*/
>;
};
mmc3_pins_default: pinmux_mmc3_pins_default {
pinctrl-single,pins = <
- 0x8c (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_clk.mmc2_clk */
- 0x88 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_csn3.mmc2_cmd */
- 0x44 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a1.mmc2_dat0 */
- 0x48 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a2.mmc2_dat1 */
- 0x4c (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a3.mmc2_dat2 */
- 0x78 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_be1n.mmc2_dat3 */
+ AM4372_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_clk.mmc2_clk */
+ AM4372_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_csn3.mmc2_cmd */
+ AM4372_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a1.mmc2_dat0 */
+ AM4372_IOPAD(0x848, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a2.mmc2_dat1 */
+ AM4372_IOPAD(0x84c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a3.mmc2_dat2 */
+ AM4372_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_be1n.mmc2_dat3 */
>;
};
mmc3_pins_sleep: pinmux_mmc3_pins_sleep {
pinctrl-single,pins = <
- 0x8c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_clk.mmc2_clk */
- 0x88 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn3.mmc2_cmd */
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a1.mmc2_dat0 */
- 0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a2.mmc2_dat1 */
- 0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a3.mmc2_dat2 */
- 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_be1n.mmc2_dat3 */
+ AM4372_IOPAD(0x88c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_clk.mmc2_clk */
+ AM4372_IOPAD(0x888, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn3.mmc2_cmd */
+ AM4372_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a1.mmc2_dat0 */
+ AM4372_IOPAD(0x848, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a2.mmc2_dat1 */
+ AM4372_IOPAD(0x84c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a3.mmc2_dat2 */
+ AM4372_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_be1n.mmc2_dat3 */
>;
};
wlan_pins_default: pinmux_wlan_pins_default {
pinctrl-single,pins = <
- 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a4.gpio1_20 WL_EN */
- 0x5c (PIN_INPUT | WAKEUP_ENABLE | MUX_MODE7) /* gpmc_a7.gpio1_23 WL_IRQ*/
- 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a0.gpio1_16 BT_EN*/
+ AM4372_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a4.gpio1_20 WL_EN */
+ AM4372_IOPAD(0x85c, PIN_INPUT | WAKEUP_ENABLE | MUX_MODE7) /* gpmc_a7.gpio1_23 WL_IRQ*/
+ AM4372_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a0.gpio1_16 BT_EN*/
>;
};
wlan_pins_sleep: pinmux_wlan_pins_sleep {
pinctrl-single,pins = <
- 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a4.gpio1_20 WL_EN */
- 0x5c (PIN_INPUT | WAKEUP_ENABLE | MUX_MODE7) /* gpmc_a7.gpio1_23 WL_IRQ*/
- 0x40 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a0.gpio1_16 BT_EN*/
+ AM4372_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a4.gpio1_20 WL_EN */
+ AM4372_IOPAD(0x85c, PIN_INPUT | WAKEUP_ENABLE | MUX_MODE7) /* gpmc_a7.gpio1_23 WL_IRQ*/
+ AM4372_IOPAD(0x840, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a0.gpio1_16 BT_EN*/
>;
};
uart3_pins: uart3_pins {
pinctrl-single,pins = <
- 0x228 (PIN_INPUT | MUX_MODE0) /* uart3_rxd.uart3_rxd */
- 0x22c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart3_txd.uart3_txd */
- 0x230 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_ctsn.uart3_ctsn */
- 0x234 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart3_rtsn.uart3_rtsn */
+ AM4372_IOPAD(0xa28, PIN_INPUT | MUX_MODE0) /* uart3_rxd.uart3_rxd */
+ AM4372_IOPAD(0xa2c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart3_txd.uart3_txd */
+ AM4372_IOPAD(0xa30, PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_ctsn.uart3_ctsn */
+ AM4372_IOPAD(0xa34, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart3_rtsn.uart3_rtsn */
>;
};
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
- 0x108 (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
+ AM4372_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
+ AM4372_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
+ AM4372_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
+ AM4372_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
>;
};
mcasp1_sleep_pins: mcasp1_sleep_pins {
pinctrl-single,pins = <
- 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
gpio0_pins: gpio0_pins {
pinctrl-single,pins = <
- 0x26c (PIN_OUTPUT | MUX_MODE9) /* spi2_cs0.gpio0_23 SEL_eMMCorNANDn */
+ AM4372_IOPAD(0xa6c, PIN_OUTPUT | MUX_MODE9) /* spi2_cs0.gpio0_23 SEL_eMMCorNANDn */
>;
};
emmc_pins_default: emmc_pins_default {
pinctrl-single,pins = <
- 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
- 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
- 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
- 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
- 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
- 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ AM4372_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ AM4372_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ AM4372_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ AM4372_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ AM4372_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+ AM4372_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+ AM4372_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+ AM4372_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+ AM4372_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ AM4372_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
>;
};
emmc_pins_sleep: emmc_pins_sleep {
pinctrl-single,pins = <
- 0x00 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad0.gpio1_0 */
- 0x04 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad1.gpio1_1 */
- 0x08 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad2.gpio1_2 */
- 0x0c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad3.gpio1_3 */
- 0x10 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad4.gpio1_4 */
- 0x14 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad5.gpio1_5 */
- 0x18 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad6.gpio1_6 */
- 0x1c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad7.gpio1_7 */
- 0x80 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn1.gpio1_30 */
- 0x84 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn2.gpio1_31 */
+ AM4372_IOPAD(0x800, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad0.gpio1_0 */
+ AM4372_IOPAD(0x804, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad1.gpio1_1 */
+ AM4372_IOPAD(0x808, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad2.gpio1_2 */
+ AM4372_IOPAD(0x80c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad3.gpio1_3 */
+ AM4372_IOPAD(0x810, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad4.gpio1_4 */
+ AM4372_IOPAD(0x814, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad5.gpio1_5 */
+ AM4372_IOPAD(0x818, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad6.gpio1_6 */
+ AM4372_IOPAD(0x81c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad7.gpio1_7 */
+ AM4372_IOPAD(0x880, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn1.gpio1_30 */
+ AM4372_IOPAD(0x884, PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn2.gpio1_31 */
>;
};
};
@@ -734,8 +734,8 @@
status = "okay";
/* these are on the crossbar and are outlined in the
xbar-event-map element */
- dmas = <&edma 30
- &edma 31>;
+ dmas = <&edma_xbar 30 0 1>,
+ <&edma_xbar 31 0 2>;
dma-names = "tx", "rx";
vmmc-supply = <&vmmcwl_fixed>;
bus-width = <4>;
@@ -756,11 +756,6 @@
};
};
-&edma {
- ti,edma-xbar-event-map = /bits/ 16 <1 30
- 2 31>;
-};
-
&uart3 {
status = "okay";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts
index 337fb91ee74c..76dcfc6d5f0d 100644
--- a/arch/arm/boot/dts/am437x-idk-evm.dts
+++ b/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -122,137 +122,137 @@
&am43xx_pinmux {
gpio_keys_pins_default: gpio_keys_pins_default {
pinctrl-single,pins = <
- 0x1b8 (PIN_INPUT | MUX_MODE7) /* cam0_field.gpio4_2 */
+ AM4372_IOPAD(0x9b8, PIN_INPUT | MUX_MODE7) /* cam0_field.gpio4_2 */
>;
};
i2c0_pins_default: i2c0_pins_default {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM4372_IOPAD(0x988, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM4372_IOPAD(0x98c, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
i2c0_pins_sleep: i2c0_pins_sleep {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x18c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x988, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x98c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
i2c2_pins_default: i2c2_pins_default {
pinctrl-single,pins = <
- 0x1e8 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE3) /* cam1_data1.i2c2_scl */
- 0x1ec (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE3) /* cam1_data0.i2c2_sda */
+ AM4372_IOPAD(0x9e8, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE3) /* cam1_data1.i2c2_scl */
+ AM4372_IOPAD(0x9ec, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE3) /* cam1_data0.i2c2_sda */
>;
};
i2c2_pins_sleep: i2c2_pins_sleep {
pinctrl-single,pins = <
- 0x1e8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1ec (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9e8, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9ec, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
mmc1_pins_default: pinmux_mmc1_pins_default {
pinctrl-single,pins = <
- 0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- 0x104 (PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
- 0x1f0 (PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
- 0x1f4 (PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
- 0x1f8 (PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
- 0x1fc (PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM4372_IOPAD(0x900, PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM4372_IOPAD(0x904, PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM4372_IOPAD(0x9f0, PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM4372_IOPAD(0x9f4, PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM4372_IOPAD(0x9f8, PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM4372_IOPAD(0x9fc, PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM4372_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
mmc1_pins_sleep: pinmux_mmc1_pins_sleep {
pinctrl-single,pins = <
- 0x100 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x104 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1f0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1f4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1f8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1fc (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x160 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x900, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x904, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9f0, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9f4, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9f8, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9fc, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x960, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
ecap0_pins_default: backlight_pins_default {
pinctrl-single,pins = <
- 0x164 (PIN_OUTPUT | MUX_MODE0) /* ecap0_in_pwm0_out.ecap0_in_pwm0_out */
+ AM4372_IOPAD(0x964, PIN_OUTPUT | MUX_MODE0) /* ecap0_in_pwm0_out.ecap0_in_pwm0_out */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
- 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
- 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td2 */
- 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td3 */
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd2 */
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd3 */
+ AM4372_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
+ AM4372_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
+ AM4372_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
+ AM4372_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
+ AM4372_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td2 */
+ AM4372_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td3 */
+ AM4372_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
+ AM4372_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd2 */
+ AM4372_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd3 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
- 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM4372_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
qspi_pins_default: qspi_pins_default {
pinctrl-single,pins = <
- 0x7c (PIN_OUTPUT_PULLUP | MUX_MODE3) /* gpmc_csn0.qspi_csn */
- 0x88 (PIN_OUTPUT | MUX_MODE2) /* gpmc_csn3.qspi_clk */
- 0x90 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_advn_ale.qspi_d0 */
- 0x94 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_oen_ren.qspi_d1 */
- 0x98 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_wen.qspi_d2 */
- 0x9c (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_be0n_cle.qspi_d3 */
+ AM4372_IOPAD(0x87c, PIN_OUTPUT_PULLUP | MUX_MODE3) /* gpmc_csn0.qspi_csn */
+ AM4372_IOPAD(0x888, PIN_OUTPUT | MUX_MODE2) /* gpmc_csn3.qspi_clk */
+ AM4372_IOPAD(0x890, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_advn_ale.qspi_d0 */
+ AM4372_IOPAD(0x894, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_oen_ren.qspi_d1 */
+ AM4372_IOPAD(0x898, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_wen.qspi_d2 */
+ AM4372_IOPAD(0x89c, PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_be0n_cle.qspi_d3 */
>;
};
qspi_pins_sleep: qspi_pins_sleep{
pinctrl-single,pins = <
- 0x7c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x88 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x90 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x94 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x98 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x9c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x87c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x888, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x890, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x894, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x898, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x89c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
};
diff --git a/arch/arm/boot/dts/am437x-sbc-t43.dts b/arch/arm/boot/dts/am437x-sbc-t43.dts
new file mode 100644
index 000000000000..5f750c0ed6c9
--- /dev/null
+++ b/arch/arm/boot/dts/am437x-sbc-t43.dts
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2015 CompuLab, Ltd. - http://www.compulab.co.il/
+ *
+ * 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 "am437x-cm-t43.dts"
+#include "compulab-sb-som.dtsi"
+
+/ {
+ model = "CompuLab CM-T43 on SB-SOM-T43";
+ compatible = "compulab,am437x-sbc-t43", "compulab,am437x-cm-t43", "ti,am4372", "ti,am43";
+
+ aliases {
+ display0 = &lcd0;
+ };
+};
+
+&am43xx_pinmux {
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM4372_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM4372_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM4372_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM4372_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM4372_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM4372_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM4372_IOPAD(0x964, PIN_INPUT | MUX_MODE7) /* ecap0_in_pwm0_out.gpio0_7 */
+ >;
+ };
+
+ dss_pinctrl_default: dss_pinctrl_default {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x9b0, PIN_OUTPUT_PULLUP | MUX_MODE2) /* cam0 hd -> DSS DATA 23 */
+ AM4372_IOPAD(0x9b4, PIN_OUTPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x9b8, PIN_OUTPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x9bc, PIN_OUTPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x9c0, PIN_OUTPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x9c4, PIN_OUTPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x9c8, PIN_OUTPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x9cc, PIN_OUTPUT_PULLUP | MUX_MODE2) /* cam1 data 9 -> DSS DATA 16 */
+
+ AM4372_IOPAD(0x8a0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 0 */
+ AM4372_IOPAD(0x8a4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8a8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8ac, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8bc, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8cc, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8dc, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 15 */
+ AM4372_IOPAD(0x8e0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS VSYNC */
+ AM4372_IOPAD(0x8e4, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS HSYNC */
+ AM4372_IOPAD(0x8e8, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS PCLK */
+ AM4372_IOPAD(0x8ec, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS AC BIAS EN */
+ AM4372_IOPAD(0xa20, PIN_OUTPUT_PULLUP | MUX_MODE7)
+ >;
+ };
+
+ uart0_pins_default: uart0_pins_default {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x968, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE0)
+ AM4372_IOPAD(0x96C, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE0)
+ AM4372_IOPAD(0x970, PIN_INPUT_PULLUP | SLEWCTRL_FAST | DS0_PULL_UP_DOWN_EN | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM4372_IOPAD(0x974, PIN_INPUT | PULL_DISABLE | SLEWCTRL_FAST | DS0_PULL_UP_DOWN_EN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ >;
+ };
+
+ i2c1_pins: i2c1_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0xa6c, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE1) /* spi2_cs0.i2c1_sda */
+ AM4372_IOPAD(0xa60, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE1) /* spi2_sclk.i2c1_scl */
+ >;
+ };
+
+ i2c2_pins: i2c2_pins {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0x978, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE3) /* uart1_ctsn.i2c2_sda */
+ AM4372_IOPAD(0x97c, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE3) /* uart1_rtsn.i2c2_scl */
+ >;
+ };
+
+ usb2_phy1_default: usb2_phy1_default {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0xac0, DS0_PULL_UP_DOWN_EN | PIN_INPUT_PULLDOWN | MUX_MODE0)
+ >;
+ };
+
+ usb2_phy2_default: usb2_phy2_default {
+ pinctrl-single,pins = <
+ AM4372_IOPAD(0xac4, DS0_PULL_UP_DOWN_EN | PIN_INPUT_PULLDOWN | MUX_MODE0)
+ >;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
+ pca9555: pca9555@20 {
+ compatible = "nxp,pca9555";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ eeprom_base: at24@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+};
+
+&mmc1 {
+ status = "okay";
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ vmmc-supply = <&vsb_3v3>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ wp-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+};
+
+&dss {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&dss_pinctrl_default>;
+
+ port {
+ dpi_lcd_out: endpoint@0 {
+ remote-endpoint = <&lcd_in>;
+ data-lines = <24>;
+ };
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_default>;
+};
+
+&dwc3_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_phy1_default>;
+};
+
+&dwc3_2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_phy2_default>;
+};
+
+&lcd0 {
+ enable-gpios = <&pca9555 14 GPIO_ACTIVE_HIGH
+ &gpio4 28 GPIO_ACTIVE_HIGH>;
+
+ port {
+ lcd_in: endpoint {
+ remote-endpoint = <&dpi_lcd_out>;
+ data-lines = <24>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 63de2a1b4315..d82dd6e3f9b1 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -157,259 +157,259 @@
&am43xx_pinmux {
matrix_keypad_pins: matrix_keypad_pins {
pinctrl-single,pins = <
- 0x24c (PIN_OUTPUT | MUX_MODE7) /* gpio5_13.gpio5_13 */
- 0x250 (PIN_OUTPUT | MUX_MODE7) /* spi4_sclk.gpio5_4 */
- 0x254 (PIN_INPUT | MUX_MODE7) /* spi4_d0.gpio5_5 */
- 0x258 (PIN_INPUT | MUX_MODE7) /* spi4_d1.gpio5_5 */
+ AM4372_IOPAD(0xa4c, PIN_OUTPUT | MUX_MODE7) /* gpio5_13.gpio5_13 */
+ AM4372_IOPAD(0xa50, PIN_OUTPUT | MUX_MODE7) /* spi4_sclk.gpio5_4 */
+ AM4372_IOPAD(0xa54, PIN_INPUT | MUX_MODE7) /* spi4_d0.gpio5_5 */
+ AM4372_IOPAD(0xa58, PIN_INPUT | MUX_MODE7) /* spi4_d1.gpio5_5 */
>;
};
leds_pins: leds_pins {
pinctrl-single,pins = <
- 0x228 (PIN_OUTPUT | MUX_MODE7) /* uart3_rxd.gpio5_2 */
- 0x22c (PIN_OUTPUT | MUX_MODE7) /* uart3_txd.gpio5_3 */
- 0x230 (PIN_OUTPUT | MUX_MODE7) /* uart3_ctsn.gpio5_0 */
- 0x234 (PIN_OUTPUT | MUX_MODE7) /* uart3_rtsn.gpio5_1 */
+ AM4372_IOPAD(0xa28, PIN_OUTPUT | MUX_MODE7) /* uart3_rxd.gpio5_2 */
+ AM4372_IOPAD(0xa2c, PIN_OUTPUT | MUX_MODE7) /* uart3_txd.gpio5_3 */
+ AM4372_IOPAD(0xa30, PIN_OUTPUT | MUX_MODE7) /* uart3_ctsn.gpio5_0 */
+ AM4372_IOPAD(0xa34, PIN_OUTPUT | MUX_MODE7) /* uart3_rtsn.gpio5_1 */
>;
};
i2c0_pins: i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM4372_IOPAD(0x988, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM4372_IOPAD(0x98c, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
i2c1_pins: i2c1_pins {
pinctrl-single,pins = <
- 0x15c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
- 0x158 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
+ AM4372_IOPAD(0x95c, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
+ AM4372_IOPAD(0x958, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x0f0 (PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
- 0x0f4 (PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
- 0x0f8 (PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
- 0x0fc (PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
- 0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
- 0x104 (PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM4372_IOPAD(0x8f0, PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM4372_IOPAD(0x8f4, PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM4372_IOPAD(0x8f8, PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM4372_IOPAD(0x8fc, PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM4372_IOPAD(0x900, PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM4372_IOPAD(0x904, PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM4372_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
ecap0_pins: backlight_pins {
pinctrl-single,pins = <
- 0x164 (PIN_OUTPUT | MUX_MODE0) /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out */
+ AM4372_IOPAD(0x964, PIN_OUTPUT | MUX_MODE0) /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out */
>;
};
edt_ft5306_ts_pins: edt_ft5306_ts_pins {
pinctrl-single,pins = <
- 0x74 (PIN_INPUT | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
- 0x78 (PIN_OUTPUT | MUX_MODE7) /* gpmc_be1n.gpio1_28 */
+ AM4372_IOPAD(0x874, PIN_INPUT | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
+ AM4372_IOPAD(0x878, PIN_OUTPUT | MUX_MODE7) /* gpmc_be1n.gpio1_28 */
>;
};
vpfe0_pins_default: vpfe0_pins_default {
pinctrl-single,pins = <
- 0x1b0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_hd mode 0*/
- 0x1b4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_vd mode 0*/
- 0x1b8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_field mode 0*/
- 0x1bc (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_wen mode 0*/
- 0x1c0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_pclk mode 0*/
- 0x1c4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data8 mode 0*/
- 0x1c8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data9 mode 0*/
- 0x208 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data0 mode 0*/
- 0x20c (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data1 mode 0*/
- 0x210 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data2 mode 0*/
- 0x214 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data3 mode 0*/
- 0x218 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data4 mode 0*/
- 0x21c (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data5 mode 0*/
- 0x220 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data6 mode 0*/
- 0x224 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data7 mode 0*/
+ AM4372_IOPAD(0x9b0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_hd mode 0*/
+ AM4372_IOPAD(0x9b4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_vd mode 0*/
+ AM4372_IOPAD(0x9b8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_field mode 0*/
+ AM4372_IOPAD(0x9bc, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_wen mode 0*/
+ AM4372_IOPAD(0x9c0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_pclk mode 0*/
+ AM4372_IOPAD(0x9c4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data8 mode 0*/
+ AM4372_IOPAD(0x9c8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data9 mode 0*/
+ AM4372_IOPAD(0xa08, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data0 mode 0*/
+ AM4372_IOPAD(0xa0c, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data1 mode 0*/
+ AM4372_IOPAD(0xa10, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data2 mode 0*/
+ AM4372_IOPAD(0xa14, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data3 mode 0*/
+ AM4372_IOPAD(0xa18, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data4 mode 0*/
+ AM4372_IOPAD(0xa1c, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data5 mode 0*/
+ AM4372_IOPAD(0xa20, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data6 mode 0*/
+ AM4372_IOPAD(0xa24, PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_data7 mode 0*/
>;
};
vpfe0_pins_sleep: vpfe0_pins_sleep {
pinctrl-single,pins = <
- 0x1b0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1b4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1b8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1bc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1c0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1c4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1c8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x208 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x20c (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x210 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x214 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x218 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x21c (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x220 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x224 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9b0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9b4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9b8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9bc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9c0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9c4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9c8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa08, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa0c, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa10, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa14, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa18, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa1c, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa20, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa24, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x12c (PIN_OUTPUT | MUX_MODE2) /* mii1_txclk.rmii1_tclk */
- 0x114 (PIN_OUTPUT | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
- 0x128 (PIN_OUTPUT | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
- 0x124 (PIN_OUTPUT | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
- 0x120 (PIN_OUTPUT | MUX_MODE2) /* mii1_txd0.rgmii1_td2 */
- 0x11c (PIN_OUTPUT | MUX_MODE2) /* mii1_txd1.rgmii1_td3 */
- 0x130 (PIN_INPUT | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
- 0x118 (PIN_INPUT | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
- 0x140 (PIN_INPUT | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
- 0x13c (PIN_INPUT | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
- 0x138 (PIN_INPUT | MUX_MODE2) /* mii1_rxd0.rgmii1_rd2 */
- 0x134 (PIN_INPUT | MUX_MODE2) /* mii1_rxd1.rgmii1_rd3 */
+ AM4372_IOPAD(0x92c, PIN_OUTPUT | MUX_MODE2) /* mii1_txclk.rmii1_tclk */
+ AM4372_IOPAD(0x914, PIN_OUTPUT | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
+ AM4372_IOPAD(0x928, PIN_OUTPUT | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
+ AM4372_IOPAD(0x924, PIN_OUTPUT | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
+ AM4372_IOPAD(0x920, PIN_OUTPUT | MUX_MODE2) /* mii1_txd0.rgmii1_td2 */
+ AM4372_IOPAD(0x91c, PIN_OUTPUT | MUX_MODE2) /* mii1_txd1.rgmii1_td3 */
+ AM4372_IOPAD(0x930, PIN_INPUT | MUX_MODE2) /* mii1_rxclk.rmii1_rclk */
+ AM4372_IOPAD(0x918, PIN_INPUT | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
+ AM4372_IOPAD(0x940, PIN_INPUT | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
+ AM4372_IOPAD(0x93c, PIN_INPUT | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
+ AM4372_IOPAD(0x938, PIN_INPUT | MUX_MODE2) /* mii1_rxd0.rgmii1_rd2 */
+ AM4372_IOPAD(0x934, PIN_INPUT | MUX_MODE2) /* mii1_rxd1.rgmii1_rd3 */
/* Slave 2 */
- 0x58 (PIN_OUTPUT | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
- 0x40 (PIN_OUTPUT | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
- 0x54 (PIN_OUTPUT | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
- 0x50 (PIN_OUTPUT | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
- 0x4c (PIN_OUTPUT | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
- 0x48 (PIN_OUTPUT | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
- 0x5c (PIN_INPUT | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
- 0x44 (PIN_INPUT | MUX_MODE2) /* gpmc_a1.rgmii2_rtcl */
- 0x6c (PIN_INPUT | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
- 0x68 (PIN_INPUT | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
- 0x64 (PIN_INPUT | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
- 0x60 (PIN_INPUT | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
+ AM4372_IOPAD(0x858, PIN_OUTPUT | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
+ AM4372_IOPAD(0x840, PIN_OUTPUT | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
+ AM4372_IOPAD(0x854, PIN_OUTPUT | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
+ AM4372_IOPAD(0x850, PIN_OUTPUT | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
+ AM4372_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
+ AM4372_IOPAD(0x848, PIN_OUTPUT | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
+ AM4372_IOPAD(0x85c, PIN_INPUT | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
+ AM4372_IOPAD(0x844, PIN_INPUT | MUX_MODE2) /* gpmc_a1.rgmii2_rtcl */
+ AM4372_IOPAD(0x86c, PIN_INPUT | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
+ AM4372_IOPAD(0x868, PIN_INPUT | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
+ AM4372_IOPAD(0x864, PIN_INPUT | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
+ AM4372_IOPAD(0x860, PIN_INPUT | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
/* Slave 2 reset value */
- 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x84c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x848, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM4372_IOPAD(0x948, PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM4372_IOPAD(0x94c, PIN_OUTPUT | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
dss_pins: dss_pins {
pinctrl-single,pins = <
- 0x020 (PIN_OUTPUT | MUX_MODE1) /* gpmc ad 8 -> DSS DATA 23 */
- 0x024 (PIN_OUTPUT | MUX_MODE1)
- 0x028 (PIN_OUTPUT | MUX_MODE1)
- 0x02c (PIN_OUTPUT | MUX_MODE1)
- 0x030 (PIN_OUTPUT | MUX_MODE1)
- 0x034 (PIN_OUTPUT | MUX_MODE1)
- 0x038 (PIN_OUTPUT | MUX_MODE1)
- 0x03c (PIN_OUTPUT | MUX_MODE1) /* gpmc ad 15 -> DSS DATA 16 */
- 0x0a0 (PIN_OUTPUT | MUX_MODE0) /* DSS DATA 0 */
- 0x0a4 (PIN_OUTPUT | MUX_MODE0)
- 0x0a8 (PIN_OUTPUT | MUX_MODE0)
- 0x0ac (PIN_OUTPUT | MUX_MODE0)
- 0x0b0 (PIN_OUTPUT | MUX_MODE0)
- 0x0b4 (PIN_OUTPUT | MUX_MODE0)
- 0x0b8 (PIN_OUTPUT | MUX_MODE0)
- 0x0bc (PIN_OUTPUT | MUX_MODE0)
- 0x0c0 (PIN_OUTPUT | MUX_MODE0)
- 0x0c4 (PIN_OUTPUT | MUX_MODE0)
- 0x0c8 (PIN_OUTPUT | MUX_MODE0)
- 0x0cc (PIN_OUTPUT | MUX_MODE0)
- 0x0d0 (PIN_OUTPUT | MUX_MODE0)
- 0x0d4 (PIN_OUTPUT | MUX_MODE0)
- 0x0d8 (PIN_OUTPUT | MUX_MODE0)
- 0x0dc (PIN_OUTPUT | MUX_MODE0) /* DSS DATA 15 */
- 0x0e0 (PIN_OUTPUT | MUX_MODE0) /* DSS VSYNC */
- 0x0e4 (PIN_OUTPUT | MUX_MODE0) /* DSS HSYNC */
- 0x0e8 (PIN_OUTPUT | MUX_MODE0) /* DSS PCLK */
- 0x0ec (PIN_OUTPUT | MUX_MODE0) /* DSS AC BIAS EN */
+ AM4372_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1) /* gpmc ad 8 -> DSS DATA 23 */
+ AM4372_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1)
+ AM4372_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1)
+ AM4372_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1)
+ AM4372_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1)
+ AM4372_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1)
+ AM4372_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1)
+ AM4372_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1) /* gpmc ad 15 -> DSS DATA 16 */
+ AM4372_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* DSS DATA 0 */
+ AM4372_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)
+ AM4372_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* DSS DATA 15 */
+ AM4372_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0) /* DSS VSYNC */
+ AM4372_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0) /* DSS HSYNC */
+ AM4372_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0) /* DSS PCLK */
+ AM4372_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0) /* DSS AC BIAS EN */
>;
};
qspi_pins: qspi_pins {
pinctrl-single,pins = <
- 0x7c (PIN_OUTPUT | MUX_MODE3) /* gpmc_csn0.qspi_csn */
- 0x88 (PIN_OUTPUT | MUX_MODE2) /* gpmc_csn3.qspi_clk */
- 0x90 (PIN_INPUT | MUX_MODE3) /* gpmc_advn_ale.qspi_d0 */
- 0x94 (PIN_INPUT | MUX_MODE3) /* gpmc_oen_ren.qspi_d1 */
- 0x98 (PIN_INPUT | MUX_MODE3) /* gpmc_wen.qspi_d2 */
- 0x9c (PIN_INPUT | MUX_MODE3) /* gpmc_be0n_cle.qspi_d3 */
+ AM4372_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE3) /* gpmc_csn0.qspi_csn */
+ AM4372_IOPAD(0x888, PIN_OUTPUT | MUX_MODE2) /* gpmc_csn3.qspi_clk */
+ AM4372_IOPAD(0x890, PIN_INPUT | MUX_MODE3) /* gpmc_advn_ale.qspi_d0 */
+ AM4372_IOPAD(0x894, PIN_INPUT | MUX_MODE3) /* gpmc_oen_ren.qspi_d1 */
+ AM4372_IOPAD(0x898, PIN_INPUT | MUX_MODE3) /* gpmc_wen.qspi_d2 */
+ AM4372_IOPAD(0x89c, PIN_INPUT | MUX_MODE3) /* gpmc_be0n_cle.qspi_d3 */
>;
};
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
- 0x108 (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
+ AM4372_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
+ AM4372_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
+ AM4372_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
+ AM4372_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
>;
};
mcasp1_pins_sleep: mcasp1_pins_sleep {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
lcd_pins: lcd_pins {
pinctrl-single,pins = <
- 0x1c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpcm_ad7.gpio1_7 */
+ AM4372_IOPAD(0x81c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpcm_ad7.gpio1_7 */
>;
};
usb1_pins: usb1_pins {
pinctrl-single,pins = <
- 0x2c0 (PIN_OUTPUT | MUX_MODE0) /* usb0_drvvbus.usb0_drvvbus */
+ AM4372_IOPAD(0xac0, PIN_OUTPUT | MUX_MODE0) /* usb0_drvvbus.usb0_drvvbus */
>;
};
usb2_pins: usb2_pins {
pinctrl-single,pins = <
- 0x2c4 (PIN_OUTPUT | MUX_MODE0) /* usb0_drvvbus.usb0_drvvbus */
+ AM4372_IOPAD(0xac4, PIN_OUTPUT | MUX_MODE0) /* usb0_drvvbus.usb0_drvvbus */
>;
};
};
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 47954ed990f8..746fd2b17958 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -144,228 +144,228 @@
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs */
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxerr.rmii1_rxerr */
- 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txen.rmii1_txen */
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxdv.rmii1_rxdv */
- 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
- 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk.rmii1_refclk */
+ AM4372_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_crs.rmii1_crs */
+ AM4372_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxerr.rmii1_rxerr */
+ AM4372_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txen.rmii1_txen */
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxdv.rmii1_rxdv */
+ AM4372_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
+ AM4372_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rxd1 */
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rxd0 */
+ AM4372_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk.rmii1_refclk */
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
- 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
- 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ AM4372_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
- 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM4372_IOPAD(0x988, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM4372_IOPAD(0x98c, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
nand_flash_x8: nand_flash_x8 {
pinctrl-single,pins = <
- 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a0.SELQSPIorNAND/GPIO */
- 0x0 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x74 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpmc_wpn */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM4372_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a0.SELQSPIorNAND/GPIO */
+ AM4372_IOPAD(0x800, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM4372_IOPAD(0x804, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM4372_IOPAD(0x808, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM4372_IOPAD(0x80c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM4372_IOPAD(0x810, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM4372_IOPAD(0x814, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM4372_IOPAD(0x818, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM4372_IOPAD(0x81c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM4372_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM4372_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpmc_wpn */
+ AM4372_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM4372_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM4372_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM4372_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM4372_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
ecap0_pins: backlight_pins {
pinctrl-single,pins = <
- 0x164 MUX_MODE0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
+ AM4372_IOPAD(0x964, MUX_MODE0) /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
- 0x1c0 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE8) /* i2c2_sda.i2c2_sda */
- 0x1c4 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE8) /* i2c2_scl.i2c2_scl */
+ AM4372_IOPAD(0x9c0, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE8) /* i2c2_sda.i2c2_sda */
+ AM4372_IOPAD(0x9c4, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE8) /* i2c2_scl.i2c2_scl */
>;
};
spi0_pins: pinmux_spi0_pins {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT | MUX_MODE0) /* spi0_clk.spi0_clk */
- 0x154 (PIN_OUTPUT | MUX_MODE0) /* spi0_d0.spi0_d0 */
- 0x158 (PIN_INPUT | MUX_MODE0) /* spi0_d1.spi0_d1 */
- 0x15c (PIN_OUTPUT | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
+ AM4372_IOPAD(0x950, PIN_INPUT | MUX_MODE0) /* spi0_clk.spi0_clk */
+ AM4372_IOPAD(0x954, PIN_OUTPUT | MUX_MODE0) /* spi0_d0.spi0_d0 */
+ AM4372_IOPAD(0x958, PIN_INPUT | MUX_MODE0) /* spi0_d1.spi0_d1 */
+ AM4372_IOPAD(0x95c, PIN_OUTPUT | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
>;
};
spi1_pins: pinmux_spi1_pins {
pinctrl-single,pins = <
- 0x190 (PIN_INPUT | MUX_MODE3) /* mcasp0_aclkx.spi1_clk */
- 0x194 (PIN_OUTPUT | MUX_MODE3) /* mcasp0_fsx.spi1_d0 */
- 0x198 (PIN_INPUT | MUX_MODE3) /* mcasp0_axr0.spi1_d1 */
- 0x19c (PIN_OUTPUT | MUX_MODE3) /* mcasp0_ahclkr.spi1_cs0 */
+ AM4372_IOPAD(0x990, PIN_INPUT | MUX_MODE3) /* mcasp0_aclkx.spi1_clk */
+ AM4372_IOPAD(0x994, PIN_OUTPUT | MUX_MODE3) /* mcasp0_fsx.spi1_d0 */
+ AM4372_IOPAD(0x998, PIN_INPUT | MUX_MODE3) /* mcasp0_axr0.spi1_d1 */
+ AM4372_IOPAD(0x99c, PIN_OUTPUT | MUX_MODE3) /* mcasp0_ahclkr.spi1_cs0 */
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ AM4372_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
qspi1_default: qspi1_default {
pinctrl-single,pins = <
- 0x7c (PIN_INPUT_PULLUP | MUX_MODE3)
- 0x88 (PIN_INPUT_PULLUP | MUX_MODE2)
- 0x90 (PIN_INPUT_PULLUP | MUX_MODE3)
- 0x94 (PIN_INPUT_PULLUP | MUX_MODE3)
- 0x98 (PIN_INPUT_PULLUP | MUX_MODE3)
- 0x9c (PIN_INPUT_PULLUP | MUX_MODE3)
+ AM4372_IOPAD(0x87c, PIN_INPUT_PULLUP | MUX_MODE3)
+ AM4372_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE2)
+ AM4372_IOPAD(0x890, PIN_INPUT_PULLUP | MUX_MODE3)
+ AM4372_IOPAD(0x894, PIN_INPUT_PULLUP | MUX_MODE3)
+ AM4372_IOPAD(0x898, PIN_INPUT_PULLUP | MUX_MODE3)
+ AM4372_IOPAD(0x89c, PIN_INPUT_PULLUP | MUX_MODE3)
>;
};
pixcir_ts_pins: pixcir_ts_pins {
pinctrl-single,pins = <
- 0x44 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a1.gpio1_17 */
+ AM4372_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_a1.gpio1_17 */
>;
};
hdq_pins: pinmux_hdq_pins {
pinctrl-single,pins = <
- 0x234 (PIN_INPUT_PULLUP | MUX_MODE1) /* cam1_wen.hdq_gpio */
+ AM4372_IOPAD(0xa34, PIN_INPUT_PULLUP | MUX_MODE1) /* cam1_wen.hdq_gpio */
>;
};
dss_pins: dss_pins {
pinctrl-single,pins = <
- 0x020 (PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 8 -> DSS DATA 23 */
- 0x024 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x028 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x02C (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x030 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x034 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x038 (PIN_OUTPUT_PULLUP | MUX_MODE1)
- 0x03C (PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 15 -> DSS DATA 16 */
- 0x0A0 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 0 */
- 0x0A4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0A8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0AC (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0B0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0B4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0B8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0BC (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0C0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0C4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0C8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0CC (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0D0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0D4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0D8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
- 0x0DC (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 15 */
- 0x0E0 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS VSYNC */
- 0x0E4 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS HSYNC */
- 0x0E8 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS PCLK */
- 0x0EC (PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS AC BIAS EN */
+ AM4372_IOPAD(0x820, PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 8 -> DSS DATA 23 */
+ AM4372_IOPAD(0x824, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x828, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x82c, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x830, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x834, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x838, PIN_OUTPUT_PULLUP | MUX_MODE1)
+ AM4372_IOPAD(0x83c, PIN_OUTPUT_PULLUP | MUX_MODE1) /*gpmc ad 15 -> DSS DATA 16 */
+ AM4372_IOPAD(0x8a0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 0 */
+ AM4372_IOPAD(0x8a4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8a8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8ac, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8b4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8B8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8bc, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8c8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8cc, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d0, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d4, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8d8, PIN_OUTPUT_PULLUP | MUX_MODE0)
+ AM4372_IOPAD(0x8dc, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS DATA 15 */
+ AM4372_IOPAD(0x8e0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS VSYNC */
+ AM4372_IOPAD(0x8e4, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS HSYNC */
+ AM4372_IOPAD(0x8e8, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS PCLK */
+ AM4372_IOPAD(0x8ec, PIN_OUTPUT_PULLUP | MUX_MODE0) /* DSS AC BIAS EN */
>;
};
display_mux_pins: display_mux_pins {
pinctrl-single,pins = <
/* GPMC CLK -> GPIO 2_1 to select LCD / HDMI */
- 0x08C (PIN_OUTPUT_PULLUP | MUX_MODE7)
+ AM4372_IOPAD(0x88C, PIN_OUTPUT_PULLUP | MUX_MODE7)
>;
};
vpfe1_pins_default: vpfe1_pins_default {
pinctrl-single,pins = <
- 0x1cc (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data9 mode 0 */
- 0x1d0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data8 mode 0 */
- 0x1d4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_hd mode 0 */
- 0x1d8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_vd mode 0 */
- 0x1dc (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_pclk mode 0 */
- 0x1e8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data0 mode 0 */
- 0x1ec (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data1 mode 0 */
- 0x1f0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data2 mode 0 */
- 0x1f4 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data3 mode 0 */
- 0x1f8 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data4 mode 0 */
- 0x1fc (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data5 mode 0 */
- 0x200 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data6 mode 0 */
- 0x204 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data7 mode 0 */
+ AM4372_IOPAD(0x9cc, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data9 mode 0 */
+ AM4372_IOPAD(0x9d0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data8 mode 0 */
+ AM4372_IOPAD(0x9d4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_hd mode 0 */
+ AM4372_IOPAD(0x9d8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_vd mode 0 */
+ AM4372_IOPAD(0x9dc, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_pclk mode 0 */
+ AM4372_IOPAD(0x9e8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data0 mode 0 */
+ AM4372_IOPAD(0x9ec, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data1 mode 0 */
+ AM4372_IOPAD(0x9f0, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data2 mode 0 */
+ AM4372_IOPAD(0x9f4, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data3 mode 0 */
+ AM4372_IOPAD(0x9f8, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data4 mode 0 */
+ AM4372_IOPAD(0x9fc, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data5 mode 0 */
+ AM4372_IOPAD(0xa00, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data6 mode 0 */
+ AM4372_IOPAD(0xa04, PIN_INPUT_PULLUP | MUX_MODE0) /* cam1_data7 mode 0 */
>;
};
vpfe1_pins_sleep: vpfe1_pins_sleep {
pinctrl-single,pins = <
- 0x1cc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1d0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1d4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1d8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1dc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1e8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1ec (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1f0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1f4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1f8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x1fc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x200 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
- 0x204 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9cc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9d0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9d4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9d8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9dc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9e8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9ec, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9f0, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9f4, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9f8, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0x9fc, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa00, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+ AM4372_IOPAD(0xa04, DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
>;
};
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
- 0x1a0 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* MCASP0_ACLKR/MCASP1_ACLKX */
- 0x1a4 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* MCASP0_FSR/MCASP1_FSX */
- 0x1a8 (PIN_OUTPUT_PULLDOWN | MUX_MODE3)/* MCASP0_AXR1/MCASP1_AXR0 */
- 0x1ac (PIN_INPUT_PULLDOWN | MUX_MODE3) /* MCASP0_AHCLKX/MCASP1_AXR1 */
+ AM4372_IOPAD(0x9a0, PIN_INPUT_PULLDOWN | MUX_MODE3) /* MCASP0_ACLKR/MCASP1_ACLKX */
+ AM4372_IOPAD(0x9a4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* MCASP0_FSR/MCASP1_FSX */
+ AM4372_IOPAD(0x9a8, PIN_OUTPUT_PULLDOWN | MUX_MODE3)/* MCASP0_AXR1/MCASP1_AXR0 */
+ AM4372_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE3) /* MCASP0_AHCLKX/MCASP1_AXR1 */
>;
};
mcasp1_sleep_pins: mcasp1_sleep_pins {
pinctrl-single,pins = <
- 0x1a0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1a4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1a8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
- 0x1ac (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9a0, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9a4, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM4372_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
};
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
index 00352e761b8c..36c0fa6c362a 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -181,97 +181,97 @@
&dra7_pmx_core {
leds_pins_default: leds_pins_default {
pinctrl-single,pins = <
- 0x3a8 (PIN_OUTPUT | MUX_MODE14) /* spi1_d1.gpio7_8 */
- 0x3ac (PIN_OUTPUT | MUX_MODE14) /* spi1_d0.gpio7_9 */
- 0x3c0 (PIN_OUTPUT | MUX_MODE14) /* spi2_sclk.gpio7_14 */
- 0x3c4 (PIN_OUTPUT | MUX_MODE14) /* spi2_d1.gpio7_15 */
+ DRA7XX_CORE_IOPAD(0x37a8, PIN_OUTPUT | MUX_MODE14) /* spi1_d1.gpio7_8 */
+ DRA7XX_CORE_IOPAD(0x37ac, PIN_OUTPUT | MUX_MODE14) /* spi1_d0.gpio7_9 */
+ DRA7XX_CORE_IOPAD(0x37c0, PIN_OUTPUT | MUX_MODE14) /* spi2_sclk.gpio7_14 */
+ DRA7XX_CORE_IOPAD(0x37c4, PIN_OUTPUT | MUX_MODE14) /* spi2_d1.gpio7_15 */
>;
};
i2c1_pins_default: i2c1_pins_default {
pinctrl-single,pins = <
- 0x400 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda.sda */
- 0x404 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl.scl */
+ DRA7XX_CORE_IOPAD(0x3800, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda.sda */
+ DRA7XX_CORE_IOPAD(0x3804, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl.scl */
>;
};
hdmi_pins: pinmux_hdmi_pins {
pinctrl-single,pins = <
- 0x408 (PIN_INPUT | MUX_MODE1) /* i2c2_sda.hdmi1_ddc_scl */
- 0x40c (PIN_INPUT | MUX_MODE1) /* i2c2_scl.hdmi1_ddc_sda */
+ DRA7XX_CORE_IOPAD(0x3808, PIN_INPUT | MUX_MODE1) /* i2c2_sda.hdmi1_ddc_scl */
+ DRA7XX_CORE_IOPAD(0x380c, PIN_INPUT | MUX_MODE1) /* i2c2_scl.hdmi1_ddc_sda */
>;
};
i2c3_pins_default: i2c3_pins_default {
pinctrl-single,pins = <
- 0x2a4 (PIN_INPUT| MUX_MODE10) /* mcasp1_aclkx.i2c3_sda */
- 0x2a8 (PIN_INPUT| MUX_MODE10) /* mcasp1_fsx.i2c3_scl */
+ DRA7XX_CORE_IOPAD(0x36a4, PIN_INPUT| MUX_MODE10) /* mcasp1_aclkx.i2c3_sda */
+ DRA7XX_CORE_IOPAD(0x36a8, PIN_INPUT| MUX_MODE10) /* mcasp1_fsx.i2c3_scl */
>;
};
uart3_pins_default: uart3_pins_default {
pinctrl-single,pins = <
- 0x3f8 (PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
- 0x3fc (PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
+ DRA7XX_CORE_IOPAD(0x37f8, PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
+ DRA7XX_CORE_IOPAD(0x37fc, PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
>;
};
mmc1_pins_default: mmc1_pins_default {
pinctrl-single,pins = <
- 0x36c (PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
- 0x354 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
- 0x358 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
- 0x35c (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
- 0x360 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
- 0x364 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
- 0x368 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
+ DRA7XX_CORE_IOPAD(0x376c, PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
+ DRA7XX_CORE_IOPAD(0x3754, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
+ DRA7XX_CORE_IOPAD(0x3758, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
+ DRA7XX_CORE_IOPAD(0x375c, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
+ DRA7XX_CORE_IOPAD(0x3760, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
+ DRA7XX_CORE_IOPAD(0x3764, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
+ DRA7XX_CORE_IOPAD(0x3768, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
>;
};
mmc2_pins_default: mmc2_pins_default {
pinctrl-single,pins = <
- 0x9c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
- 0xb0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
- 0xa0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
- 0xa4 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
- 0xa8 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
- 0xac (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
- 0x8c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
- 0x90 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
- 0x94 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
- 0x98 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+ DRA7XX_CORE_IOPAD(0x349c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+ DRA7XX_CORE_IOPAD(0x34b0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+ DRA7XX_CORE_IOPAD(0x34a0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+ DRA7XX_CORE_IOPAD(0x34a4, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+ DRA7XX_CORE_IOPAD(0x34a8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+ DRA7XX_CORE_IOPAD(0x34ac, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+ DRA7XX_CORE_IOPAD(0x348c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+ DRA7XX_CORE_IOPAD(0x3490, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+ DRA7XX_CORE_IOPAD(0x3494, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+ DRA7XX_CORE_IOPAD(0x3498, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
>;
};
cpsw_pins_default: cpsw_pins_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x250 (PIN_OUTPUT | MUX_MODE0) /* rgmii1_tclk */
- 0x254 (PIN_OUTPUT | MUX_MODE0) /* rgmii1_tctl */
- 0x258 (PIN_OUTPUT | MUX_MODE0) /* rgmii1_td3 */
- 0x25c (PIN_OUTPUT | MUX_MODE0) /* rgmii1_td2 */
- 0x260 (PIN_OUTPUT | MUX_MODE0) /* rgmii1_td1 */
- 0x264 (PIN_OUTPUT | MUX_MODE0) /* rgmii1_td0 */
- 0x268 (PIN_INPUT | MUX_MODE0) /* rgmii1_rclk */
- 0x26c (PIN_INPUT | MUX_MODE0) /* rgmii1_rctl */
- 0x270 (PIN_INPUT | MUX_MODE0) /* rgmii1_rd3 */
- 0x274 (PIN_INPUT | MUX_MODE0) /* rgmii1_rd2 */
- 0x278 (PIN_INPUT | MUX_MODE0) /* rgmii1_rd1 */
- 0x27c (PIN_INPUT | MUX_MODE0) /* rgmii1_rd0 */
+ DRA7XX_CORE_IOPAD(0x3650, PIN_OUTPUT | MUX_MODE0) /* rgmii1_tclk */
+ DRA7XX_CORE_IOPAD(0x3654, PIN_OUTPUT | MUX_MODE0) /* rgmii1_tctl */
+ DRA7XX_CORE_IOPAD(0x3658, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td3 */
+ DRA7XX_CORE_IOPAD(0x365c, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td2 */
+ DRA7XX_CORE_IOPAD(0x3660, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td1 */
+ DRA7XX_CORE_IOPAD(0x3664, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td0 */
+ DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT | MUX_MODE0) /* rgmii1_rclk */
+ DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT | MUX_MODE0) /* rgmii1_rctl */
+ DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT | MUX_MODE0) /* rgmii1_rd3 */
+ DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT | MUX_MODE0) /* rgmii1_rd2 */
+ DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT | MUX_MODE0) /* rgmii1_rd1 */
+ DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT | MUX_MODE0) /* rgmii1_rd0 */
/* Slave 2 */
- 0x198 (PIN_OUTPUT | MUX_MODE3) /* rgmii2_tclk */
- 0x19c (PIN_OUTPUT | MUX_MODE3) /* rgmii2_tctl */
- 0x1a0 (PIN_OUTPUT | MUX_MODE3) /* rgmii2_td3 */
- 0x1a4 (PIN_OUTPUT | MUX_MODE3) /* rgmii2_td2 */
- 0x1a8 (PIN_OUTPUT | MUX_MODE3) /* rgmii2_td1 */
- 0x1ac (PIN_OUTPUT | MUX_MODE3) /* rgmii2_td0 */
- 0x1b0 (PIN_INPUT | MUX_MODE3) /* rgmii2_rclk */
- 0x1b4 (PIN_INPUT | MUX_MODE3) /* rgmii2_rctl */
- 0x1b8 (PIN_INPUT | MUX_MODE3) /* rgmii2_rd3 */
- 0x1bc (PIN_INPUT | MUX_MODE3) /* rgmii2_rd2 */
- 0x1c0 (PIN_INPUT | MUX_MODE3) /* rgmii2_rd1 */
- 0x1c4 (PIN_INPUT | MUX_MODE3) /* rgmii2_rd0 */
+ DRA7XX_CORE_IOPAD(0x3598, PIN_OUTPUT | MUX_MODE3) /* rgmii2_tclk */
+ DRA7XX_CORE_IOPAD(0x359c, PIN_OUTPUT | MUX_MODE3) /* rgmii2_tctl */
+ DRA7XX_CORE_IOPAD(0x35a0, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td3 */
+ DRA7XX_CORE_IOPAD(0x35a4, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td2 */
+ DRA7XX_CORE_IOPAD(0x35a8, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td1 */
+ DRA7XX_CORE_IOPAD(0x35ac, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td0 */
+ DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE3) /* rgmii2_rclk */
+ DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE3) /* rgmii2_rctl */
+ DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE3) /* rgmii2_rd3 */
+ DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE3) /* rgmii2_rd2 */
+ DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE3) /* rgmii2_rd1 */
+ DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE3) /* rgmii2_rd0 */
>;
};
@@ -279,115 +279,115 @@
cpsw_pins_sleep: cpsw_pins_sleep {
pinctrl-single,pins = <
/* Slave 1 */
- 0x250 (PIN_INPUT | MUX_MODE15)
- 0x254 (PIN_INPUT | MUX_MODE15)
- 0x258 (PIN_INPUT | MUX_MODE15)
- 0x25c (PIN_INPUT | MUX_MODE15)
- 0x260 (PIN_INPUT | MUX_MODE15)
- 0x264 (PIN_INPUT | MUX_MODE15)
- 0x268 (PIN_INPUT | MUX_MODE15)
- 0x26c (PIN_INPUT | MUX_MODE15)
- 0x270 (PIN_INPUT | MUX_MODE15)
- 0x274 (PIN_INPUT | MUX_MODE15)
- 0x278 (PIN_INPUT | MUX_MODE15)
- 0x27c (PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3650, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3654, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3658, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x365c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3660, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3664, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT | MUX_MODE15)
/* Slave 2 */
- 0x198 (PIN_INPUT | MUX_MODE15)
- 0x19c (PIN_INPUT | MUX_MODE15)
- 0x1a0 (PIN_INPUT | MUX_MODE15)
- 0x1a4 (PIN_INPUT | MUX_MODE15)
- 0x1a8 (PIN_INPUT | MUX_MODE15)
- 0x1ac (PIN_INPUT | MUX_MODE15)
- 0x1b0 (PIN_INPUT | MUX_MODE15)
- 0x1b4 (PIN_INPUT | MUX_MODE15)
- 0x1b8 (PIN_INPUT | MUX_MODE15)
- 0x1bc (PIN_INPUT | MUX_MODE15)
- 0x1c0 (PIN_INPUT | MUX_MODE15)
- 0x1c4 (PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3598, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x359c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a0, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a4, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a8, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35ac, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE15)
>;
};
davinci_mdio_pins_default: davinci_mdio_pins_default {
pinctrl-single,pins = <
/* MDIO */
- 0x23c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_mclk */
- 0x240 (PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_d */
+ DRA7XX_CORE_IOPAD(0x363c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_mclk */
+ DRA7XX_CORE_IOPAD(0x3640, PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_d */
>;
};
davinci_mdio_pins_sleep: davinci_mdio_pins_sleep {
pinctrl-single,pins = <
- 0x23c (PIN_INPUT | MUX_MODE15)
- 0x240 (PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x363c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3640, PIN_INPUT | MUX_MODE15)
>;
};
tps659038_pins_default: tps659038_pins_default {
pinctrl-single,pins = <
- 0x418 (PIN_INPUT_PULLUP | MUX_MODE14) /* wakeup0.gpio1_0 */
+ DRA7XX_CORE_IOPAD(0x3818, PIN_INPUT_PULLUP | MUX_MODE14) /* wakeup0.gpio1_0 */
>;
};
tmp102_pins_default: tmp102_pins_default {
pinctrl-single,pins = <
- 0x3C8 (PIN_INPUT_PULLUP | MUX_MODE14) /* spi2_d0.gpio7_16 */
+ DRA7XX_CORE_IOPAD(0x37c8, PIN_INPUT_PULLUP | MUX_MODE14) /* spi2_d0.gpio7_16 */
>;
};
mcp79410_pins_default: mcp79410_pins_default {
pinctrl-single,pins = <
- 0x424 (PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
+ DRA7XX_CORE_IOPAD(0x3824, PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
>;
};
usb1_pins: pinmux_usb1_pins {
pinctrl-single,pins = <
- 0x280 (PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
+ DRA7XX_CORE_IOPAD(0x3680, PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
>;
};
extcon_usb1_pins: extcon_usb1_pins {
pinctrl-single,pins = <
- 0x3ec (PIN_INPUT_PULLUP | MUX_MODE14) /* uart1_rtsn.gpio7_25 */
+ DRA7XX_CORE_IOPAD(0x37ec, PIN_INPUT_PULLUP | MUX_MODE14) /* uart1_rtsn.gpio7_25 */
>;
};
tpd12s015_pins: pinmux_tpd12s015_pins {
pinctrl-single,pins = <
- 0x3b0 (PIN_OUTPUT | MUX_MODE14) /* gpio7_10 CT_CP_HPD */
- 0x3b8 (PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
- 0x370 (PIN_OUTPUT | MUX_MODE14) /* gpio6_28 LS_OE */
+ DRA7XX_CORE_IOPAD(0x37b0, PIN_OUTPUT | MUX_MODE14) /* gpio7_10 CT_CP_HPD */
+ DRA7XX_CORE_IOPAD(0x37b8, PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
+ DRA7XX_CORE_IOPAD(0x3770, PIN_OUTPUT | MUX_MODE14) /* gpio6_28 LS_OE */
>;
};
clkout2_pins_default: clkout2_pins_default {
pinctrl-single,pins = <
- 0x294 (PIN_OUTPUT_PULLDOWN | MUX_MODE9) /* xref_clk0.clkout2 */
+ DRA7XX_CORE_IOPAD(0x3694, PIN_OUTPUT_PULLDOWN | MUX_MODE9) /* xref_clk0.clkout2 */
>;
};
clkout2_pins_sleep: clkout2_pins_sleep {
pinctrl-single,pins = <
- 0x294 (PIN_INPUT | MUX_MODE15) /* xref_clk0.clkout2 */
+ DRA7XX_CORE_IOPAD(0x3694, PIN_INPUT | MUX_MODE15) /* xref_clk0.clkout2 */
>;
};
mcasp3_pins_default: mcasp3_pins_default {
pinctrl-single,pins = <
- 0x324 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx.mcasp3_aclkx */
- 0x328 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx.mcasp3_fsx */
- 0x32c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0.mcasp3_axr0 */
- 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1.mcasp3_axr1 */
+ DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx.mcasp3_aclkx */
+ DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx.mcasp3_fsx */
+ DRA7XX_CORE_IOPAD(0x372c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0.mcasp3_axr0 */
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1.mcasp3_axr1 */
>;
};
mcasp3_pins_sleep: mcasp3_pins_sleep {
pinctrl-single,pins = <
- 0x324 (PIN_INPUT | MUX_MODE15)
- 0x328 (PIN_INPUT | MUX_MODE15)
- 0x32c (PIN_INPUT | MUX_MODE15)
- 0x330 (PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x372c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT | MUX_MODE15)
>;
};
};
diff --git a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
new file mode 100644
index 000000000000..c53882643ae9
--- /dev/null
+++ b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
@@ -0,0 +1,617 @@
+/*
+ * Support for CompuLab CL-SOM-AM57x System-on-Module
+ *
+ * Copyright (C) 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Author: Dmitry Lifshitz <lifshitz@compulab.co.il>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "dra74x.dtsi"
+
+/ {
+ model = "CompuLab CL-SOM-AM57x";
+ compatible = "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>; /* 512 MB - minimal configuration */
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_pins_default>;
+
+ led@0 {
+ label = "cl-som-am57x:green";
+ gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+ };
+
+ vdd_3v3: fixedregulator-vdd_3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ads7846reg: fixedregulator-ads7846-reg {
+ compatible = "regulator-fixed";
+ regulator-name = "ads7846-reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ sound0: sound@0 {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "CL-SOM-AM57x-Sound-Card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&dailink0_master>;
+ simple-audio-card,frame-master = <&dailink0_master>;
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack",
+ "Microphone", "Microphone Jack",
+ "Line", "Line Jack";
+ simple-audio-card,routing =
+ "Headphone Jack", "RHPOUT",
+ "Headphone Jack", "LHPOUT",
+ "LLINEIN", "Line Jack",
+ "MICIN", "Mic Bias",
+ "Mic Bias", "Microphone Jack";
+
+ dailink0_master: simple-audio-card,cpu {
+ sound-dai = <&mcasp3>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&wm8731>;
+ system-clock-frequency = <12000000>;
+ };
+ };
+};
+
+&dra7_pmx_core {
+ leds_pins_default: leds_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x347c, PIN_OUTPUT | MUX_MODE14) /* gpmc_a15.gpio2_5 */
+ >;
+ };
+
+ i2c1_pins_default: i2c1_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3800, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda.sda */
+ DRA7XX_CORE_IOPAD(0x3804, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl.scl */
+ >;
+ };
+
+ i2c3_pins_default: i2c3_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x36a4, PIN_INPUT| MUX_MODE10) /* mcasp1_aclkx.i2c3_sda */
+ DRA7XX_CORE_IOPAD(0x36a8, PIN_INPUT| MUX_MODE10) /* mcasp1_fsx.i2c3_scl */
+ >;
+ };
+
+ i2c4_pins_default: i2c4_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x36ac, PIN_INPUT| MUX_MODE10) /* mcasp1_acl.i2c4_sda */
+ DRA7XX_CORE_IOPAD(0x36b0, PIN_INPUT| MUX_MODE10) /* mcasp1_fsr.i2c4_scl */
+ >;
+ };
+
+ tps659038_pins_default: tps659038_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3818, PIN_INPUT_PULLUP | MUX_MODE14) /* wakeup0.gpio1_0 */
+ >;
+ };
+
+ mmc2_pins_default: mmc2_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x349c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+ DRA7XX_CORE_IOPAD(0x34b0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+ DRA7XX_CORE_IOPAD(0x34a0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+ DRA7XX_CORE_IOPAD(0x34a4, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+ DRA7XX_CORE_IOPAD(0x34a8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+ DRA7XX_CORE_IOPAD(0x34ac, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+ DRA7XX_CORE_IOPAD(0x348c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+ DRA7XX_CORE_IOPAD(0x3490, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+ DRA7XX_CORE_IOPAD(0x3494, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+ DRA7XX_CORE_IOPAD(0x3498, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+ >;
+ };
+
+ qspi1_pins: pinmux_qspi1_pins {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3474, PIN_INPUT | MUX_MODE1) /* gpmc_a13.qspi1_rtclk */
+ DRA7XX_CORE_IOPAD(0x3480, PIN_INPUT | MUX_MODE1) /* gpmc_a16.qspi1_d0 */
+ DRA7XX_CORE_IOPAD(0x3484, PIN_INPUT | MUX_MODE1) /* gpmc_a17.qspi1_d1 */
+ DRA7XX_CORE_IOPAD(0x3488, PIN_INPUT | MUX_MODE1) /* qpmc_a18.qspi1_sclk */
+ DRA7XX_CORE_IOPAD(0x34b8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs2.qspi1_cs0 */
+ DRA7XX_CORE_IOPAD(0x34bc, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs3.qspi1_cs1 */
+ >;
+ };
+
+ cpsw_pins_default: cpsw_pins_default {
+ pinctrl-single,pins = <
+ /* Slave at addr 0x0 */
+ DRA7XX_CORE_IOPAD(0x3650, PIN_OUTPUT | MUX_MODE0) /* rgmii0_tclk */
+ DRA7XX_CORE_IOPAD(0x3654, PIN_OUTPUT | MUX_MODE0) /* rgmii0_tctl */
+ DRA7XX_CORE_IOPAD(0x3658, PIN_OUTPUT | MUX_MODE0) /* rgmii0_td3 */
+ DRA7XX_CORE_IOPAD(0x365c, PIN_OUTPUT | MUX_MODE0) /* rgmii0_td2 */
+ DRA7XX_CORE_IOPAD(0x3660, PIN_OUTPUT | MUX_MODE0) /* rgmii0_td1 */
+ DRA7XX_CORE_IOPAD(0x3664, PIN_OUTPUT | MUX_MODE0) /* rgmii0_td0 */
+ DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rgmii0_rclk */
+ DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rgmii0_rctl */
+ DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rgmii0_rd3 */
+ DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rgmii0_rd2 */
+ DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rgmii0_rd1 */
+ DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rgmii0_rd0 */
+
+ /* Slave at addr 0x1 */
+ DRA7XX_CORE_IOPAD(0x3598, PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_tclk */
+ DRA7XX_CORE_IOPAD(0x359c, PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
+ DRA7XX_CORE_IOPAD(0x35a0, PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
+ DRA7XX_CORE_IOPAD(0x35a4, PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
+ DRA7XX_CORE_IOPAD(0x35a8, PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
+ DRA7XX_CORE_IOPAD(0x35ac, PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
+ DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
+ DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
+ DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
+ DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
+ DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
+ DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT_PULLUP | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
+ >;
+ };
+
+ cpsw_pins_sleep: cpsw_pins_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ DRA7XX_CORE_IOPAD(0x3650, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3654, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3658, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x365c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3660, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3664, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT | MUX_MODE15)
+
+ /* Slave 2 */
+ DRA7XX_CORE_IOPAD(0x3598, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x359c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a0, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a4, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a8, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35ac, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE15)
+ >;
+ };
+
+ davinci_mdio_pins_default: davinci_mdio_pins_default {
+ pinctrl-single,pins = <
+ /* MDIO */
+ DRA7XX_CORE_IOPAD(0x3590, PIN_OUTPUT_PULLUP | MUX_MODE3)/* vin2a_d10.mdio_mclk */
+ DRA7XX_CORE_IOPAD(0x3594, PIN_INPUT_PULLUP | MUX_MODE3) /* vin2a_d11.mdio_d */
+ >;
+ };
+
+ davinci_mdio_pins_sleep: davinci_mdio_pins_sleep {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3590, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3594, PIN_INPUT | MUX_MODE15)
+ >;
+ };
+
+ ads7846_pins: pinmux_ads7846_pins {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3464, PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpmc_a9.gpio1_31 */
+ >;
+ };
+
+ mcasp3_pins_default: mcasp3_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx.mcasp3_aclkx */
+ DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx.mcasp3_fsx */
+ DRA7XX_CORE_IOPAD(0x372c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0.mcasp3_axr0 */
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1.mcasp3_axr1 */
+ >;
+ };
+
+ mcasp3_pins_sleep: mcasp3_pins_sleep {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x372c, PIN_INPUT | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT | MUX_MODE15)
+ >;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_default>;
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins_default>;
+ clock-frequency = <400000>;
+};
+
+&i2c4 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_default>;
+ clock-frequency = <400000>;
+
+ tps659038: tps659038@58 {
+ compatible = "ti,tps659038";
+ reg = <0x58>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tps659038_pins_default>;
+
+ #interrupt-cells = <2>;
+ interrupt-controller;
+
+ ti,system-power-controller;
+
+ tps659038_pmic {
+ compatible = "ti,tps659038-pmic";
+
+ regulators {
+ smps12_reg: smps12 {
+ /* VDD_MPU */
+ regulator-name = "smps12";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps3_reg: smps3 {
+ /* VDD_DDR */
+ regulator-name = "smps3";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps45_reg: smps45 {
+ /* VDD_DSPEVE */
+ regulator-name = "smps45";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps6_reg: smps6 {
+ /* VDD_GPU */
+ regulator-name = "smps6";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps7_reg: smps7 {
+ /* VDD_CORE */
+ regulator-name = "smps7";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1160000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps8_reg: smps8 {
+ /* VDD_IVA */
+ regulator-name = "smps8";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps9_reg: smps9 {
+ /* PMIC_3V3 */
+ regulator-name = "smps9";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+
+ ldo1_reg: ldo1 {
+ /* VDD_SD / VDDSHV8 */
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2_reg: ldo2 {
+ /* VDD_1V8 */
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo3_reg: ldo3 {
+ /* VDDA_1V8_PHYA - supplies VDDA_SATA, VDDA_USB1/2/3 */
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo4_reg: ldo4 {
+ /* VDDA_1V8_PHYB - supplies VDDA_HDMI, VDDA_PCIE/0/1 */
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo9_reg: ldo9 {
+ /* VDD_RTC */
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldoln_reg: ldoln {
+ /* VDDA_1V8_PLL */
+ regulator-name = "ldoln";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldousb_reg: ldousb {
+ /* VDDA_3V_USB: VDDA_USBHS33 */
+ regulator-name = "ldousb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* regen1 not used */
+ };
+ };
+
+ tps659038_pwr_button: tps659038_pwr_button {
+ compatible = "ti,palmas-pwrbutton";
+ interrupt-parent = <&tps659038>;
+ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
+ ti,palmas-long-press-seconds = <12>;
+ };
+
+ tps659038_gpio: tps659038_gpio {
+ compatible = "ti,palmas-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
+
+ rtc0: rtc@56 {
+ compatible = "emmicro,em3027";
+ reg = <0x56>;
+ };
+
+ eeprom_module: atmel@50 {
+ compatible = "atmel,24c08";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+
+ wm8731: wm8731@1a {
+ #sound-dai-cells = <0>;
+ compatible = "wlf,wm8731";
+ reg = <0x1a>;
+ status = "okay";
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&smps12_reg>;
+ voltage-tolerance = <1>;
+};
+
+&sata {
+ status = "okay";
+};
+
+&mailbox5 {
+ status = "okay";
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ status = "okay";
+ };
+};
+
+&mailbox6 {
+ status = "okay";
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp2_ipc3x: mbox_dsp2_ipc3x {
+ status = "okay";
+ };
+};
+
+&mmc2 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_default>;
+
+ vmmc-supply = <&vdd_3v3>;
+ bus-width = <8>;
+ ti,non-removable;
+ cap-mmc-dual-data-rate;
+};
+
+&qspi {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&qspi1_pins>;
+
+ spi-max-frequency = <20000000>;
+
+ spi_flash: spi_flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spansion,m25p80", "jedec,spi-nor";
+ reg = <0>; /* CS0 */
+ spi-max-frequency = <20000000>;
+
+ partition@0 {
+ label = "uboot";
+ reg = <0x0 0xc0000>;
+ };
+
+ partition@c0000 {
+ label = "uboot environment";
+ reg = <0xc0000 0x40000>;
+ };
+
+ partition@100000 {
+ label = "reserved";
+ reg = <0x100000 0x0>;
+ };
+ };
+
+ /* touch controller */
+ ads7846@0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ads7846_pins>;
+
+ compatible = "ti,ads7846";
+ vcc-supply = <&ads7846reg>;
+
+ reg = <1>; /* CS1 */
+ spi-max-frequency = <1500000>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <31 0>;
+ pendown-gpio = <&gpio1 31 0>;
+
+
+ ti,x-min = /bits/ 16 <0x0>;
+ ti,x-max = /bits/ 16 <0x0fff>;
+ ti,y-min = /bits/ 16 <0x0>;
+ ti,y-max = /bits/ 16 <0x0fff>;
+
+ ti,x-plate-ohms = /bits/ 16 <180>;
+ ti,pressure-max = /bits/ 16 <255>;
+
+ ti,debounce-max = /bits/ 16 <30>;
+ ti,debounce-tol = /bits/ 16 <10>;
+ ti,debounce-rep = /bits/ 16 <1>;
+
+ linux,wakeup;
+ };
+};
+
+&mac {
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_pins_default>;
+ pinctrl-1 = <&cpsw_pins_sleep>;
+ dual_emac;
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii";
+ dual_emac_res_vlan = <0>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii";
+ dual_emac_res_vlan = <1>;
+};
+
+&davinci_mdio {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_pins_default>;
+ pinctrl-1 = <&davinci_mdio_pins_sleep>;
+};
+
+&usb2_phy1 {
+ phy-supply = <&ldousb_reg>;
+};
+
+&usb2_phy2 {
+ phy-supply = <&ldousb_reg>;
+};
+
+&usb1 {
+ dr_mode = "host";
+};
+
+&usb2 {
+ dr_mode = "peripheral";
+};
+
+&mcasp3 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&mcasp3_pins_default>;
+ pinctrl-1 = <&mcasp3_pins_sleep>;
+ status = "okay";
+
+ op-mode = <0>; /* MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ /* 4 serializers */
+ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
+ 1 2 0 0
+ >;
+};
+
+&gpio3 {
+ status = "okay";
+ ti,no-reset-on-init;
+};
+
+&gpio2 {
+ status = "okay";
+ ti,no-reset-on-init;
+};
diff --git a/arch/arm/boot/dts/am57xx-sbc-am57x.dts b/arch/arm/boot/dts/am57xx-sbc-am57x.dts
new file mode 100644
index 000000000000..77bb8e17401a
--- /dev/null
+++ b/arch/arm/boot/dts/am57xx-sbc-am57x.dts
@@ -0,0 +1,179 @@
+/*
+ * Support for CompuLab SBC-AM57x single board computer
+ *
+ * Copyright (C) 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Author: Dmitry Lifshitz <lifshitz@compulab.co.il>
+ *
+ * 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 "am57xx-cl-som-am57x.dts"
+#include "compulab-sb-som.dtsi"
+
+/ {
+ model = "CompuLab CL-SOM-AM57x on SB-SOM-AM57x";
+ compatible = "compulab,sbc-am57x", "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7";
+
+ aliases {
+ display0 = &lcd0;
+ display1 = &hdmi;
+ };
+};
+
+&dra7_pmx_core {
+ uart3_pins_default: uart3_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x37f8, PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
+ DRA7XX_CORE_IOPAD(0x37fc, PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
+ >;
+ };
+
+ mmc1_pins_default: mmc1_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3754, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
+ DRA7XX_CORE_IOPAD(0x3758, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
+ DRA7XX_CORE_IOPAD(0x375c, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
+ DRA7XX_CORE_IOPAD(0x3760, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
+ DRA7XX_CORE_IOPAD(0x3764, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
+ DRA7XX_CORE_IOPAD(0x3768, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
+ DRA7XX_CORE_IOPAD(0x376c, PIN_INPUT | MUX_MODE14) /* mmc1_sdcd.gpio6_27 */
+ DRA7XX_CORE_IOPAD(0x377c, PIN_INPUT | MUX_MODE14) /* mmc1_sdwp.gpio6_28 */
+ >;
+ };
+
+ usb1_pins: pinmux_usb1_pins {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3680, PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
+ >;
+ };
+
+ i2c5_pins_default: i2c5_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x36b4, PIN_INPUT| MUX_MODE10) /* mcasp1_axr0.i2c5_sda */
+ DRA7XX_CORE_IOPAD(0x36b8, PIN_INPUT| MUX_MODE10) /* mcasp1_axr1.i2c5_scl */
+ >;
+ };
+
+ lcd_pins_default: lcd_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3564, PIN_OUTPUT | MUX_MODE14) /* vin2a_vsync0.gpio4_0 */
+ >;
+ };
+
+ hdmi_pins: pinmux_hdmi_pins {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x3808, PIN_INPUT | MUX_MODE1) /* i2c2_sda.hdmi1_ddc_scl */
+ DRA7XX_CORE_IOPAD(0x380c, PIN_INPUT | MUX_MODE1) /* i2c2_scl.hdmi1_ddc_sda */
+ >;
+ };
+
+ hdmi_conn_pins: pinmux_hdmi_conn_pins {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x37b8, PIN_INPUT | MUX_MODE14) /* spi1_cs2.gpio7_12 */
+ >;
+ };
+};
+
+&uart3 {
+ status = "okay";
+ interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+ <&dra7_pmx_core 0x3f8>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_default>;
+};
+
+&mmc1 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_default>;
+
+ vmmc-supply = <&ldo1_reg>;
+ bus-width = <4>;
+ cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio6 28 GPIO_ACTIVE_HIGH>;
+};
+
+&usb1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_pins>;
+};
+
+&i2c5 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c5_pins_default>;
+ clock-frequency = <400000>;
+
+ eeprom_base: atmel@50 {
+ compatible = "atmel,24c08";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+
+ pca9555: pca9555@20 {
+ compatible = "nxp,pca9555";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+};
+
+&dss {
+ status = "ok";
+
+ vdda_video-supply = <&ldoln_reg>;
+
+ port {
+ dpi_lcd_out: endpoint@0 {
+ remote-endpoint = <&lcd_in>;
+ data-lines = <24>;
+ };
+ };
+};
+
+&lcd0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_pins_default>;
+
+ enable-gpios = <&pca9555 14 GPIO_ACTIVE_HIGH
+ &gpio4 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ lcd_in: endpoint {
+ remote-endpoint = <&dpi_lcd_out>;
+ data-lines = <24>;
+ };
+ };
+};
+
+&hdmi {
+ status = "ok";
+ vdda-supply = <&ldo4_reg>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pins>;
+
+ port {
+ hdmi_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ lanes = <1 0 3 2 5 4 7 6>;
+ };
+ };
+};
+
+&hdmi_conn {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_conn_pins>;
+
+ hpd-gpios = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/arm-realview-pb11mp.dts b/arch/arm/boot/dts/arm-realview-pb11mp.dts
new file mode 100644
index 000000000000..da755c9851a7
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-pb11mp.dts
@@ -0,0 +1,681 @@
+/*
+ * Copyright 2015 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "skeleton.dtsi"
+
+/ {
+ model = "ARM RealView PB11MPcore";
+ compatible = "arm,realview-pb11mp";
+
+ chosen { };
+
+ aliases {
+ serial0 = &pb11mp_serial0;
+ serial1 = &pb11mp_serial1;
+ serial2 = &pb11mp_serial2;
+ serial3 = &pb11mp_serial3;
+ };
+
+ memory {
+ /*
+ * The PB11MPCore has 512 MiB memory @ 0x70000000
+ * and the first 256 are also remapped @ 0x00000000
+ */
+ reg = <0x70000000 0x20000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "arm,realview-smp";
+
+ MP11_0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,arm11mpcore";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ };
+
+ MP11_1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,arm11mpcore";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ };
+
+ MP11_2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,arm11mpcore";
+ reg = <2>;
+ next-level-cache = <&L2>;
+ };
+
+ MP11_3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,arm11mpcore";
+ reg = <3>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ /* Primary TestChip GIC synthesized with the CPU */
+ intc_tc11mp: interrupt-controller@1f000100 {
+ compatible = "arm,tc11mp-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x1f001000 0x1000>,
+ <0x1f000100 0x100>;
+ };
+
+ L2: l2-cache {
+ compatible = "arm,l220-cache";
+ reg = <0x1f002000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>,
+ <0 30 IRQ_TYPE_LEVEL_HIGH>,
+ <0 31 IRQ_TYPE_LEVEL_HIGH>;
+ cache-unified;
+ cache-level = <2>;
+ /*
+ * Override default cache size, sets and
+ * associativity as these may be erroneously set
+ * up by boot loader(s), probably for safety
+ * since th outer sync operation can cause the
+ * cache to hang unless disabled.
+ */
+ cache-size = <1048576>; // 1MB
+ cache-sets = <4096>;
+ cache-line-size = <32>;
+ arm,shared-override;
+ arm,parity-enable;
+ arm,outer-sync-disable;
+ };
+
+ scu@1f000000 {
+ compatible = "arm,arm11mp-scu";
+ reg = <0x1f000000 0x100>;
+ };
+
+ timer@1f000600 {
+ compatible = "arm,arm11mp-twd-timer";
+ reg = <0x1f000600 0x20>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <1 13 0xf04>;
+ };
+
+ watchdog@1f000620 {
+ compatible = "arm,arm11mp-twd-wdt";
+ reg = <0x1f000620 0x20>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <1 14 0xf04>;
+ };
+
+ /* PMU with one IRQ line per core */
+ pmu {
+ compatible = "arm,arm11mpcore-pmu";
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 17 IRQ_TYPE_LEVEL_HIGH>,
+ <0 18 IRQ_TYPE_LEVEL_HIGH>,
+ <0 19 IRQ_TYPE_LEVEL_HIGH>,
+ <0 20 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&MP11_0>, <&MP11_1>, <&MP11_2>, <&MP11_3>;
+ };
+
+ /* The voltage to the MMC card is hardwired at 3.3V */
+ vmmc: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ veth: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "veth";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ xtal24mhz: xtal24mhz@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ };
+
+ refclk32khz: refclk32khz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ timclk: timclk@1M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <24>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ mclk: mclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ kmiclk: kmiclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ sspclk: sspclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ uartclk: uartclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ wdogclk: wdogclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ /* FIXME: this actually hangs off the PLL clocks */
+ pclk: pclk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ flash0@40000000 {
+ /* 2 * 32MiB NOR Flash memory */
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0x40000000 0x04000000>;
+ bank-width = <4>;
+ };
+
+ flash1@44000000 {
+ // 2 * 32MiB NOR Flash memory
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0x44000000 0x04000000>;
+ bank-width = <4>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,realview-pb11mp-soc", "simple-bus";
+ regmap = <&pb11mp_syscon>;
+ ranges;
+
+ pb11mp_syscon: syscon@10000000 {
+ compatible = "arm,realview-pb11mp-syscon", "syscon", "simple-mfd";
+ reg = <0x10000000 0x1000>;
+
+ led@08.0 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x01>;
+ label = "versatile:0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ led@08.1 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x02>;
+ label = "versatile:1";
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+ led@08.2 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x04>;
+ label = "versatile:2";
+ linux,default-trigger = "cpu0";
+ default-state = "off";
+ };
+ led@08.3 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x08>;
+ label = "versatile:3";
+ linux,default-trigger = "cpu1";
+ default-state = "off";
+ };
+ led@08.4 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x10>;
+ label = "versatile:4";
+ linux,default-trigger = "cpu2";
+ default-state = "off";
+ };
+ led@08.5 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x20>;
+ label = "versatile:5";
+ linux,default-trigger = "cpu3";
+ default-state = "off";
+ };
+ led@08.6 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x40>;
+ label = "versatile:6";
+ default-state = "off";
+ };
+ led@08.7 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x80>;
+ label = "versatile:7";
+ default-state = "off";
+ };
+
+ oscclk0: osc0@0c {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0x0C>;
+ clocks = <&xtal24mhz>;
+ };
+ oscclk1: osc1@10 {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0x10>;
+ clocks = <&xtal24mhz>;
+ };
+ oscclk2: osc2@14 {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0x14>;
+ clocks = <&xtal24mhz>;
+ };
+ oscclk3: osc3@18 {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0x18>;
+ clocks = <&xtal24mhz>;
+ };
+ oscclk4: osc4@1c {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0x1c>;
+ clocks = <&xtal24mhz>;
+ };
+ oscclk5: osc5@d4 {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0xd4>;
+ clocks = <&xtal24mhz>;
+ };
+ oscclk6: osc6@d8 {
+ compatible = "arm,syscon-icst307";
+ #clock-cells = <0>;
+ lock-offset = <0x20>;
+ vco-offset = <0xd8>;
+ clocks = <&xtal24mhz>;
+ };
+ };
+
+ sp810_syscon: sysctl@10001000 {
+ compatible = "arm,sp810", "arm,primecell";
+ reg = <0x10001000 0x1000>;
+ clocks = <&refclk32khz>, <&timclk>, <&xtal24mhz>;
+ clock-names = "refclk", "timclk", "apb_pclk";
+ #clock-cells = <1>;
+ clock-output-names = "timerclk0",
+ "timerclk1",
+ "timerclk2",
+ "timerclk3";
+ assigned-clocks = <&sp810_syscon 0>,
+ <&sp810_syscon 1>,
+ <&sp810_syscon 2>,
+ <&sp810_syscon 3>;
+ assigned-clock-parents = <&timclk>,
+ <&timclk>,
+ <&timclk>,
+ <&timclk>;
+ };
+
+ i2c0: i2c@10002000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "arm,versatile-i2c";
+ reg = <0x10002000 0x1000>;
+
+ rtc@68 {
+ compatible = "dallas,ds1338";
+ reg = <0x68>;
+ };
+ };
+
+ aaci: aaci@10004000 {
+ compatible = "arm,pl041", "arm,primecell";
+ reg = <0x10004000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ mci: mmcsd@10005000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ reg = <0x10005000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>,
+ <0 15 IRQ_TYPE_LEVEL_HIGH>;
+ /* Due to frequent FIFO overruns, use just 500 kHz */
+ max-frequency = <500000>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ clocks = <&mclk>, <&pclk>;
+ clock-names = "mclk", "apb_pclk";
+ vmmc-supply = <&vmmc>;
+ cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+ };
+
+ kmi0: kmi@10006000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x10006000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&kmiclk>, <&pclk>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ kmi1: kmi@10007000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x10007000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&kmiclk>, <&pclk>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ pb11mp_serial0: serial@10009000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x10009000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ pb11mp_serial1: serial@1000a000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1000a000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ pb11mp_serial2: serial@1000b000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1000b000 0x1000>;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ pb11mp_serial3: serial@1000c000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1000c000 0x1000>;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ ssp@1000d000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0x1000d000 0x1000>;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sspclk>, <&pclk>;
+ clock-names = "SSPCLK", "apb_pclk";
+ };
+
+ watchdog@1000f000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x1000f000 0x1000>;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&wdogclk>, <&pclk>;
+ clock-names = "wdogclk", "apb_pclk";
+ status = "disabled";
+ };
+
+ watchdog@10010000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x10010000 0x1000>;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&wdogclk>, <&pclk>;
+ clock-names = "wdogclk", "apb_pclk";
+ };
+
+ timer01: timer@10011000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x10011000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 1 IRQ_TYPE_LEVEL_HIGH>;
+ arm,sp804-has-irq = <1>;
+ clocks = <&sp810_syscon 0>,
+ <&sp810_syscon 1>,
+ <&pclk>;
+ clock-names = "timerclk0",
+ "timerclk1",
+ "apb_pclk";
+ };
+
+ timer23: timer@10012000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x10012000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>;
+ arm,sp804-has-irq = <1>;
+ clocks = <&sp810_syscon 2>,
+ <&sp810_syscon 3>,
+ <&pclk>;
+ clock-names = "timerclk2",
+ "timerclk3",
+ "apb_pclk";
+ };
+
+ gpio0: gpio@10013000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x10013000 0x1000>;
+ gpio-controller;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ gpio1: gpio@10014000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x10014000 0x1000>;
+ gpio-controller;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ gpio2: gpio@10015000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x10015000 0x1000>;
+ gpio-controller;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ rtc: rtc@10017000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x10017000 0x1000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ timer45: timer@10018000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x10018000 0x1000>;
+ clocks = <&timclk>, <&pclk>;
+ clock-names = "timer", "apb_pclk";
+ status = "disabled";
+ };
+
+ timer67: timer@10019000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x10019000 0x1000>;
+ clocks = <&timclk>, <&pclk>;
+ clock-names = "timer", "apb_pclk";
+ status = "disabled";
+ };
+
+
+ clcd@10020000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x10020000 0x1000>;
+ interrupt-parent = <&intc_pb11mp>;
+ interrupt-names = "combined";
+ interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&oscclk4>, <&pclk>;
+ clock-names = "clcdclk", "apb_pclk";
+ max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */
+
+ port {
+ clcd_pads: endpoint {
+ remote-endpoint = <&clcd_panel>;
+ arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+ };
+ };
+
+ panel {
+ compatible = "panel-dpi";
+
+ port {
+ clcd_panel: endpoint {
+ remote-endpoint = <&clcd_pads>;
+ };
+ };
+
+ panel-timing {
+ clock-frequency = <63500127>;
+ hactive = <1024>;
+ hback-porch = <152>;
+ hfront-porch = <48>;
+ hsync-len = <104>;
+ vactive = <768>;
+ vback-porch = <23>;
+ vfront-porch = <3>;
+ vsync-len = <4>;
+ };
+ };
+ };
+
+ /*
+ * This GIC on the Platform Baseboard is cascaded off the
+ * TestChip GIC
+ */
+ intc_pb11mp: interrupt-controller@1e000000 {
+ compatible = "arm,arm11mp-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x1e001000 0x1000>,
+ <0x1e000000 0x100>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ /* SMSC 9118 ethernet with PHY and EEPROM */
+ ethernet@4e000000 {
+ compatible = "smsc,lan9118", "smsc,lan9115";
+ reg = <0x4e000000 0x10000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ phy-mode = "mii";
+ reg-io-width = <4>;
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
+ vdd33a-supply = <&veth>;
+ vddvario-supply = <&veth>;
+ };
+
+ usb@4f000000 {
+ compatible = "nxp,usb-isp1761";
+ reg = <0x4f000000 0x20000>;
+ interrupt-parent = <&intc_tc11mp>;
+ interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>;
+ port1-otg;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index 5555875f44f9..39181b3fa90d 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -127,7 +127,7 @@
isl12057: isl12057@68 {
compatible = "isil,isl12057";
reg = <0x68>;
- isil,irq2-can-wakeup-machine;
+ wakeup-source;
};
g762: g762@3e {
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index 78b563c02f3c..faa474874cb8 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -133,7 +133,7 @@
isl12057: isl12057@68 {
compatible = "isil,isl12057";
reg = <0x68>;
- isil,irq2-can-wakeup-machine;
+ wakeup-source;
};
g762: g762@3e {
diff --git a/arch/arm/boot/dts/armada-388-clearfog.dts b/arch/arm/boot/dts/armada-388-clearfog.dts
new file mode 100644
index 000000000000..c6e180eb3b11
--- /dev/null
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
@@ -0,0 +1,456 @@
+/*
+ * Device Tree file for SolidRun Clearfog revision A1 rev 2.0 (88F6828)
+ *
+ * Copyright (C) 2015 Russell King
+ *
+ * This board is in development; the contents of this file work with
+ * the A1 rev 2.0 of the board, which does not represent final
+ * production board. Things will change, don't expect this file to
+ * remain compatible info the future.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 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 , 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.
+ */
+
+/dts-v1/;
+#include "armada-388.dtsi"
+#include "armada-38x-solidrun-microsom.dtsi"
+
+/ {
+ model = "SolidRun Clearfog A1";
+ compatible = "solidrun,clearfog-a1", "marvell,armada388",
+ "marvell,armada385", "marvell,armada380";
+
+ aliases {
+ /* So that mvebu u-boot can update the MAC addresses */
+ ethernet1 = &eth0;
+ ethernet2 = &eth1;
+ ethernet3 = &eth2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ soc {
+ internal-regs {
+ ethernet@30000 {
+ phy-mode = "sgmii";
+ status = "okay";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ ethernet@34000 {
+ phy-mode = "sgmii";
+ status = "okay";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ i2c@11000 {
+ /* Is there anything on this? */
+ clock-frequency = <100000>;
+ pinctrl-0 = <&i2c0_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ /*
+ * PCA9655 GPIO expander, up to 1MHz clock.
+ * 0-CON3 CLKREQ#
+ * 1-CON3 PERST#
+ * 2-CON2 PERST#
+ * 3-CON3 W_DISABLE
+ * 4-CON2 CLKREQ#
+ * 5-USB3 overcurrent
+ * 6-USB3 power
+ * 7-CON2 W_DISABLE
+ * 8-JP4 P1
+ * 9-JP4 P4
+ * 10-JP4 P5
+ * 11-m.2 DEVSLP
+ * 12-SFP_LOS
+ * 13-SFP_TX_FAULT
+ * 14-SFP_TX_DISABLE
+ * 15-SFP_MOD_DEF0
+ */
+ expander0: gpio-expander@20 {
+ /*
+ * This is how it should be:
+ * compatible = "onnn,pca9655",
+ * "nxp,pca9555";
+ * but you can't do this because of
+ * the way I2C works.
+ */
+ compatible = "nxp,pca9555";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x20>;
+
+ pcie1_0_clkreq {
+ gpio-hog;
+ gpios = <0 GPIO_ACTIVE_LOW>;
+ input;
+ line-name = "pcie1.0-clkreq";
+ };
+ pcie1_0_w_disable {
+ gpio-hog;
+ gpios = <3 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "pcie1.0-w-disable";
+ };
+ pcie2_0_clkreq {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_LOW>;
+ input;
+ line-name = "pcie2.0-clkreq";
+ };
+ pcie2_0_w_disable {
+ gpio-hog;
+ gpios = <7 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "pcie2.0-w-disable";
+ };
+ usb3_ilimit {
+ gpio-hog;
+ gpios = <5 GPIO_ACTIVE_LOW>;
+ input;
+ line-name = "usb3-current-limit";
+ };
+ usb3_power {
+ gpio-hog;
+ gpios = <6 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "usb3-power";
+ };
+ m2_devslp {
+ gpio-hog;
+ gpios = <11 GPIO_ACTIVE_HIGH>;
+ output-low;
+ line-name = "m.2 devslp";
+ };
+ sfp_los {
+ /* SFP loss of signal */
+ gpio-hog;
+ gpios = <12 GPIO_ACTIVE_HIGH>;
+ input;
+ line-name = "sfp-los";
+ };
+ sfp_tx_fault {
+ /* SFP laser fault */
+ gpio-hog;
+ gpios = <13 GPIO_ACTIVE_HIGH>;
+ input;
+ line-name = "sfp-tx-fault";
+ };
+ sfp_tx_disable {
+ /* SFP transmit disable */
+ gpio-hog;
+ gpios = <14 GPIO_ACTIVE_HIGH>;
+ output-low;
+ line-name = "sfp-tx-disable";
+ };
+ sfp_mod_def0 {
+ /* SFP module present */
+ gpio-hog;
+ gpios = <15 GPIO_ACTIVE_LOW>;
+ input;
+ line-name = "sfp-mod-def0";
+ };
+ };
+
+ /* The MCP3021 is 100kHz clock only */
+ mikrobus_adc: mcp3021@4c {
+ compatible = "microchip,mcp3021";
+ reg = <0x4c>;
+ };
+
+ /* Also something at 0x64 */
+ };
+
+ i2c@11100 {
+ /*
+ * Routed to SFP, mikrobus, and PCIe.
+ * SFP limits this to 100kHz, and requires
+ * an AT24C01A/02/04 with address pins tied
+ * low, which takes addresses 0x50 and 0x51.
+ * Mikrobus doesn't specify beyond an I2C
+ * bus being present.
+ * PCIe uses ARP to assign addresses, or
+ * 0x63-0x64.
+ */
+ clock-frequency = <100000>;
+ pinctrl-0 = <&clearfog_i2c1_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+ };
+
+ mdio@72004 {
+ pinctrl-0 = <&mdio_pins>;
+ pinctrl-names = "default";
+
+ phy_dedicated: ethernet-phy@0 {
+ /*
+ * Annoyingly, the marvell phy driver
+ * configures the LED register, rather
+ * than preserving reset-loaded setting.
+ * We undo that rubbish here.
+ */
+ marvell,reg-init = <3 16 0 0x101e>;
+ reg = <0>;
+ };
+ };
+
+ pinctrl@18000 {
+ clearfog_dsa0_clk_pins: clearfog-dsa0-clk-pins {
+ marvell,pins = "mpp46";
+ marvell,function = "ref";
+ };
+ clearfog_dsa0_pins: clearfog-dsa0-pins {
+ marvell,pins = "mpp23", "mpp41";
+ marvell,function = "gpio";
+ };
+ clearfog_i2c1_pins: i2c1-pins {
+ /* SFP, PCIe, mSATA, mikrobus */
+ marvell,pins = "mpp26", "mpp27";
+ marvell,function = "i2c1";
+ };
+ clearfog_sdhci_cd_pins: clearfog-sdhci-cd-pins {
+ marvell,pins = "mpp20";
+ marvell,function = "gpio";
+ };
+ clearfog_sdhci_pins: clearfog-sdhci-pins {
+ marvell,pins = "mpp21", "mpp28",
+ "mpp37", "mpp38",
+ "mpp39", "mpp40";
+ marvell,function = "sd0";
+ };
+ clearfog_spi1_cs_pins: spi1-cs-pins {
+ marvell,pins = "mpp55";
+ marvell,function = "spi1";
+ };
+ mikro_pins: mikro-pins {
+ /* int: mpp22 rst: mpp29 */
+ marvell,pins = "mpp22", "mpp29";
+ marvell,function = "gpio";
+ };
+ mikro_spi_pins: mikro-spi-pins {
+ marvell,pins = "mpp43";
+ marvell,function = "spi1";
+ };
+ mikro_uart_pins: mikro-uart-pins {
+ marvell,pins = "mpp24", "mpp25";
+ marvell,function = "ua1";
+ };
+ rear_button_pins: rear-button-pins {
+ marvell,pins = "mpp34";
+ marvell,function = "gpio";
+ };
+ };
+
+ sata@a8000 {
+ /* pinctrl? */
+ status = "okay";
+ };
+
+ sata@e0000 {
+ /* pinctrl? */
+ status = "okay";
+ };
+
+ sdhci@d8000 {
+ bus-width = <4>;
+ cd-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
+ no-1-8-v;
+ pinctrl-0 = <&clearfog_sdhci_pins
+ &clearfog_sdhci_cd_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+ vmmc = <&reg_3p3v>;
+ wp-inverted;
+ };
+
+ serial@12100 {
+ /* mikrobus uart */
+ pinctrl-0 = <&mikro_uart_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+ };
+
+ spi@10680 {
+ /*
+ * We don't seem to have the W25Q32 on the
+ * A1 Rev 2.0 boards, so disable SPI.
+ * CS0: W25Q32 (doesn't appear to be present)
+ * CS1:
+ * CS2: mikrobus
+ */
+ pinctrl-0 = <&spi1_pins
+ &clearfog_spi1_cs_pins
+ &mikro_spi_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "w25q32", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <3000000>;
+ status = "disabled";
+ };
+ };
+
+ usb@58000 {
+ /* CON3, nearest power. */
+ status = "okay";
+ };
+
+ usb3@f0000 {
+ /* CON2, nearest CPU, USB2 only. */
+ status = "okay";
+ };
+
+ usb3@f8000 {
+ /* CON7 */
+ status = "okay";
+ };
+ };
+
+ pcie-controller {
+ status = "okay";
+ /*
+ * The two PCIe units are accessible through
+ * the mini-PCIe connectors on the board.
+ */
+ pcie@2,0 {
+ /* Port 1, Lane 0. CON3, nearest power. */
+ reset-gpios = <&expander0 1 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ };
+ pcie@3,0 {
+ /* Port 2, Lane 0. CON2, nearest CPU. */
+ reset-gpios = <&expander0 2 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ };
+ };
+ };
+
+ dsa@0 {
+ compatible = "marvell,dsa";
+ dsa,ethernet = <&eth1>;
+ dsa,mii-bus = <&mdio>;
+ pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>;
+ pinctrl-names = "default";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ switch@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4 0>;
+
+ port@0 {
+ reg = <0>;
+ label = "lan1";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan2";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan3";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan4";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "lan5";
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "cpu";
+ };
+
+ port@6 {
+ /* 88E1512 external phy */
+ reg = <6>;
+ label = "lan6";
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&rear_button_pins>;
+ pinctrl-names = "default";
+
+ button_0 {
+ /* The rear SW3 button */
+ label = "Rear Button";
+ gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+ linux,can-disable;
+ linux,code = <BTN_0>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index a633be3defda..cd316021d6ce 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -303,16 +303,6 @@
gpio = <&expander0 4 GPIO_ACTIVE_HIGH>;
};
- reg_usb2_1_vbus: v5-vbus1 {
- compatible = "regulator-fixed";
- regulator-name = "v5.0-vbus1";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- enable-active-high;
- regulator-always-on;
- gpio = <&expander0 4 GPIO_ACTIVE_HIGH>;
- };
-
reg_sata0: pwr-sata0 {
compatible = "regulator-fixed";
regulator-name = "pwr_en_sata0";
diff --git a/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi b/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
new file mode 100644
index 000000000000..3f792a563c05
--- /dev/null
+++ b/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
@@ -0,0 +1,115 @@
+/*
+ * Device Tree file for SolidRun Armada 38x Microsom
+ *
+ * Copyright (C) 2015 Russell King
+ *
+ * This board is in development; the contents of this file work with
+ * the A1 rev 2.0 of the board, which does not represent final
+ * production board. Things will change, don't expect this file to
+ * remain compatible info the future.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 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 , 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 <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>; /* 256 MB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
+
+ internal-regs {
+ ethernet@70000 {
+ pinctrl-0 = <&ge0_rgmii_pins>;
+ pinctrl-names = "default";
+ phy = <&phy_dedicated>;
+ phy-mode = "rgmii-id";
+ status = "okay";
+ };
+
+ mdio@72004 {
+ /*
+ * Add the phy clock here, so the phy can be
+ * accessed to read its IDs prior to binding
+ * with the driver.
+ */
+ pinctrl-0 = <&mdio_pins &microsom_phy_clk_pins>;
+ pinctrl-names = "default";
+
+ phy_dedicated: ethernet-phy@0 {
+ /*
+ * Annoyingly, the marvell phy driver
+ * configures the LED register, rather
+ * than preserving reset-loaded setting.
+ * We undo that rubbish here.
+ */
+ marvell,reg-init = <3 16 0 0x101e>;
+ reg = <0>;
+ };
+ };
+
+ pinctrl@18000 {
+ microsom_phy_clk_pins: microsom-phy-clk-pins {
+ marvell,pins = "mpp45";
+ marvell,function = "ref";
+ };
+ };
+
+ rtc@a3800 {
+ /*
+ * If the rtc doesn't work, run "date reset"
+ * twice in u-boot.
+ */
+ status = "okay";
+ };
+
+ serial@12000 {
+ pinctrl-0 = <&uart0_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
index 58b500873bfd..13cf69a8d0fb 100644
--- a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
+++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
@@ -151,42 +151,42 @@
marvell,nand-enable-arbiter;
nand-on-flash-bbt;
- partition@0 {
- label = "u-boot";
- reg = <0x0000000 0xe0000>;
- read-only;
- };
-
- partition@e0000 {
- label = "u-boot-env";
- reg = <0xe0000 0x20000>;
- read-only;
- };
-
- partition@100000 {
- label = "u-boot-env2";
- reg = <0x100000 0x20000>;
- read-only;
- };
-
- partition@120000 {
- label = "zImage";
- reg = <0x120000 0x400000>;
- };
-
- partition@520000 {
- label = "initrd";
- reg = <0x520000 0x400000>;
- };
-
- partition@xE00000 {
- label = "boot";
- reg = <0xE00000 0x3F200000>;
- };
-
- partition@flash {
- label = "flash";
- reg = <0x0 0x40000000>;
+ partitions {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x00000000 0x000e0000>;
+ read-only;
+ };
+
+ partition@e0000 {
+ label = "u-boot-env";
+ reg = <0x000e0000 0x00020000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u-boot-env2";
+ reg = <0x00100000 0x00020000>;
+ read-only;
+ };
+
+ partition@120000 {
+ label = "zImage";
+ reg = <0x00120000 0x00400000>;
+ };
+
+ partition@520000 {
+ label = "initrd";
+ reg = <0x00520000 0x00400000>;
+ };
+
+ partition@e00000 {
+ label = "boot";
+ reg = <0x00e00000 0x3f200000>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index 6fe8972de0a2..62175a8848bc 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -141,7 +141,7 @@
isl12057: isl12057@68 {
compatible = "isil,isl12057";
reg = <0x68>;
- isil,irq2-can-wakeup-machine;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index e74df327cdd3..77ddff036409 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -119,6 +119,16 @@
status = "okay";
};
+ pdmic@f8018000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pdmic_default>;
+ atmel,model = "PDMIC @ sama5d2_xplained";
+ atmel,mic-min-freq = <1000000>;
+ atmel,mic-max-freq = <3246000>;
+ atmel,mic-offset = <0x0>;
+ status = "okay";
+ };
+
uart1: serial@f8020000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1_default>;
@@ -129,6 +139,7 @@
dmas = <0>, <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0_default>;
+ i2c-sda-hold-time-ns = <350>;
status = "okay";
pmic: act8865@5b {
@@ -207,6 +218,10 @@
};
};
+ watchdog@f8048040 {
+ status = "okay";
+ };
+
uart3: serial@fc008000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart3_default>;
@@ -285,6 +300,12 @@
bias-disable;
};
+ pinctrl_pdmic_default: pdmic_default {
+ pinmux = <PIN_PB26__PDMIC_DAT>,
+ <PIN_PB27__PDMIC_CLK>;
+ bias-disable;
+ };
+
pinctrl_sdmmc0_default: sdmmc0_default {
cmd_data {
pinmux = <PIN_PA1__SDMMC0_CMD>,
diff --git a/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi b/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi
new file mode 100644
index 000000000000..e7b2109fc85a
--- /dev/null
+++ b/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "sama5d4.dtsi"
+
+/ {
+ model = "DENX MA5D4";
+ compatible = "denx,ma5d4", "atmel,sama5d4", "atmel,sama5";
+
+ memory {
+ reg = <0x20000000 0x10000000>;
+ };
+
+ clocks {
+ main_clock: main_clock {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+
+ clk20m: clk20m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <20000000>;
+ clock-output-names = "clk20m";
+ };
+ };
+
+ ahb {
+ apb {
+ mmc0: mmc@f8000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7>;
+ vmmc-supply = <&vcc_mmc0_reg>;
+ vqmmc-supply = <&vcc_3v3_reg>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ broken-cd;
+ };
+ };
+
+ spi0: spi@f8010000 {
+ cs-gpios = <&pioC 3 0>, <0>, <0>, <0>;
+ status = "okay";
+
+ m25p80@0 {
+ compatible = "atmel,at25df321a";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+ };
+
+ i2c0: i2c@f8014000 {
+ status = "okay";
+ };
+
+ spi1: spi@fc018000 {
+ cs-gpios = <&pioB 22 0>, <&pioB 23 0>, <0>, <0>;
+ status = "okay";
+
+ can0: can@0 {
+ compatible = "microchip,mcp2515";
+ reg = <0>;
+ clocks = <&clk20m>;
+ interrupt-parent = <&pioE>;
+ interrupts = <6 GPIO_ACTIVE_LOW>;
+ spi-max-frequency = <10000000>;
+ };
+
+ can1: can@1 {
+ compatible = "microchip,mcp2515";
+ reg = <1>;
+ clocks = <&clk20m>;
+ interrupt-parent = <&pioE>;
+ interrupts = <7 GPIO_ACTIVE_LOW>;
+ spi-max-frequency = <10000000>;
+ };
+ };
+
+ adc0: adc@fc034000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ /* external trigger conflicts with USBA_VBUS */
+ &pinctrl_adc0_ad0
+ &pinctrl_adc0_ad1
+ &pinctrl_adc0_ad2
+ &pinctrl_adc0_ad3
+ &pinctrl_adc0_ad4
+ >;
+ atmel,adc-vref = <3300>;
+ status = "okay";
+ };
+
+ watchdog@fc068640 {
+ status = "okay";
+ };
+ };
+ };
+
+ vcc_3v3_reg: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "VCC 3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vcc_mmc0_reg: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ gpio = <&pioE 15 GPIO_ACTIVE_HIGH>;
+ regulator-name = "RST_n MCI0";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc_3v3_reg>;
+ regulator-boot-on;
+ };
+};
diff --git a/arch/arm/boot/dts/at91-sama5d4_ma5d4evk.dts b/arch/arm/boot/dts/at91-sama5d4_ma5d4evk.dts
new file mode 100644
index 000000000000..abaaba58fbec
--- /dev/null
+++ b/arch/arm/boot/dts/at91-sama5d4_ma5d4evk.dts
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include "at91-sama5d4_ma5d4.dtsi"
+
+/ {
+ model = "DENX MA5D4EVK";
+ compatible = "denx,ma5d4evk", "atmel,sama5d4", "atmel,sama5";
+
+ chosen {
+ stdout-path = "serial3:115200n8";
+ };
+
+ ahb {
+ usb0: gadget@00400000 {
+ atmel,vbus-gpio = <&pioE 31 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usba_vbus>;
+ status = "okay";
+ };
+
+ usb1: ohci@00500000 {
+ num-ports = <3>;
+ atmel,vbus-gpio = <0
+ &pioE 11 GPIO_ACTIVE_LOW
+ &pioE 14 GPIO_ACTIVE_LOW
+ >;
+ status = "okay";
+ };
+
+ usb2: ehci@00600000 {
+ status = "okay";
+ };
+
+ apb {
+ hlcdc: hlcdc@f0000000 {
+ status = "okay";
+
+ hlcdc-display-controller {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+
+ port@0 {
+ hlcdc_panel_output: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&panel_input>;
+ };
+ };
+ };
+
+ };
+
+ macb0: ethernet@f8020000 {
+ phy-mode = "rmii";
+ status = "okay";
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
+ usart0: serial@f802c000 {
+ status = "okay";
+ };
+
+ usart1: serial@f8030000 {
+ status = "okay";
+ };
+
+ mmc1: mmc@fc000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>;
+ vmmc-supply = <&vcc_mmc1_reg>;
+ vqmmc-supply = <&vcc_3v3_reg>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioE 5 0>;
+ };
+ };
+
+ adc0: adc@fc034000 {
+ atmel,adc-ts-wires = <4>;
+ atmel,adc-ts-pressure-threshold = <10000>;
+ };
+
+
+ pinctrl@fc06a000 {
+ board {
+ pinctrl_mmc1_cd: mmc1_cd {
+ atmel,pins = <AT91_PIOE 5 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+ };
+ pinctrl_usba_vbus: usba_vbus {
+ atmel,pins =
+ <AT91_PIOE 31 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;
+ };
+ };
+ };
+ };
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&hlcdc_pwm 0 50000 0>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <6>;
+ status = "okay";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ status = "okay";
+
+ user1 {
+ label = "user1";
+ gpios = <&pioD 28 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ user2 {
+ label = "user2";
+ gpios = <&pioD 29 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ user3 {
+ label = "user3";
+ gpios = <&pioD 30 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ panel: panel {
+ /* Actually Ampire 800480R2 */
+ compatible = "foxlink,fl500wvr00-a0t", "simple-panel";
+ backlight = <&backlight>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel_input: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&hlcdc_panel_output>;
+ };
+ };
+ };
+
+ vcc_mmc1_reg: fixedregulator@2 {
+ compatible = "regulator-fixed";
+ gpio = <&pioE 17 GPIO_ACTIVE_LOW>;
+ regulator-name = "VDD MCI1";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc_3v3_reg>;
+ };
+};
diff --git a/arch/arm/boot/dts/at91-vinco.dts b/arch/arm/boot/dts/at91-vinco.dts
new file mode 100644
index 000000000000..79aec55e1ebc
--- /dev/null
+++ b/arch/arm/boot/dts/at91-vinco.dts
@@ -0,0 +1,256 @@
+/*
+ * Device Tree file for VInCo platform
+ *
+ * Copyright (C) 2014 Atmel,
+ * 2014 Nicolas Ferre <nicolas.ferre@atmel.com>
+ * 2015 Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/dts-v1/;
+#include "sama5d4.dtsi"
+
+/ {
+ model = "L+G VInCo platform";
+ compatible = "l+g,vinco", "atmel,sama5d4", "atmel,sama5";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ slow_xtal {
+ clock-frequency = <32768>;
+ };
+
+ main_xtal {
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+
+ adc0: adc@fc034000 {
+ status = "okay"; /* Enable ADC IIO support */
+ };
+
+ mmc0: mmc@f8000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0
+ &pinctrl_mmc0_dat1_3
+ &pinctrl_mmc0_dat4_7>;
+ vqmmc-supply = <&vcc_3v3_reg>;
+ vmmc-supply = <&vcc_3v3_reg>;
+ no-1-8-v;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ non-removable;
+ broken-cd;
+ status = "okay";
+ };
+ };
+
+ spi0: spi@f8010000 {
+ cs-gpios = <&pioC 3 0>, <0>, <0>, <0>;
+ status = "okay";
+ m25p80@0 {
+ compatible = "n25q32b", "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+ };
+
+ i2c0: i2c@f8014000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@f8018000 {
+ status = "okay";
+ /* kerkey security module */
+ };
+
+ macb0: ethernet@f8020000 {
+ phy-mode = "rmii";
+ status = "okay";
+
+ ethernet-phy@1 {
+ reg = <0x1>;
+ reset-gpios = <&pioE 8 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&pioB>;
+ interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
+ };
+
+ };
+
+ i2c2: i2c@f8024000 {
+ status = "okay";
+
+ rtc1: rtc@64 {
+ compatible = "epson,rx8900";
+ reg = <0x32>;
+ };
+ };
+
+ usart2: serial@fc008000 {
+ /* MBUS */
+ status = "okay";
+ };
+
+ usart3: serial@fc00c000 {
+ /* debug */
+ status = "okay";
+ };
+
+ usart4: serial@fc010000 {
+ /* LMN */
+ pinctrl-0 = <&pinctrl_usart4 &pinctrl_usart4_rts>;
+ linux,rs485-enabled-at-boot-time;
+ status = "okay";
+ };
+
+ macb1: ethernet@fc028000 {
+ phy-mode = "rmii";
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ ethernet-phy@1 {
+ reg = <0x1>;
+ interrupt-parent = <&pioB>;
+ interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
+ reset-gpios = <&pioE 6 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ watchdog@fc068640 {
+ status = "okay";
+ };
+
+ pinctrl@fc06a000 {
+ board {
+ pinctrl_usba_vbus: usba_vbus {
+ atmel,pins =
+ <AT91_PIOE 31 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;
+ };
+ };
+ };
+ };
+
+ usb0: gadget@00400000 {
+ atmel,vbus-gpio = <&pioE 31 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usba_vbus>;
+ status = "disable";
+ };
+
+ usb1: ohci@00500000 {
+ num-ports = <3>;
+ atmel,vbus-gpio = <0
+ &pioE 11 GPIO_ACTIVE_LOW
+ &pioE 12 GPIO_ACTIVE_LOW
+ >;
+ status = "disable";
+ };
+
+ usb2: ehci@00600000 {
+ /* 4G Modem */
+ status = "okay";
+ };
+
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ status = "okay";
+
+ led_err {
+ label = "err";
+ gpios = <&pioA 7 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_rssi {
+ label = "rssi";
+ gpios = <&pioA 9 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_tls {
+ label = "tls";
+ gpios = <&pioA 24 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_lmc {
+ label = "lmc";
+ gpios = <&pioA 25 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_wmt {
+ label = "wmt";
+ gpios = <&pioA 29 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led_pwr {
+ label = "pwr";
+ gpios = <&pioA 26 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ };
+
+ };
+
+ vcc_3v3_reg: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "VCC 3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+};
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
index 2778533502d9..3878793364f0 100644
--- a/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -91,6 +91,23 @@
#address-cells = <1>;
#size-cells = <1>;
+ pcie_phy: phy@0301d0a0 {
+ compatible = "brcm,cygnus-pcie-phy";
+ reg = <0x0301d0a0 0x14>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pcie0_phy: phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ pcie1_phy: phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
+
pinctrl: pinctrl@0x0301d0c8 {
compatible = "brcm,cygnus-pinmux";
reg = <0x0301d0c8 0x30>,
@@ -101,6 +118,7 @@
compatible = "brcm,cygnus-crmu-gpio";
reg = <0x03024800 0x50>,
<0x03024008 0x18>;
+ ngpios = <6>;
#gpio-cells = <2>;
gpio-controller;
};
@@ -127,6 +145,7 @@
compatible = "brcm,cygnus-ccm-gpio";
reg = <0x1800a000 0x50>,
<0x0301d164 0x20>;
+ ngpios = <24>;
#gpio-cells = <2>;
gpio-controller;
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
@@ -161,7 +180,21 @@
ranges = <0x81000000 0 0 0x28000000 0 0x00010000
0x82000000 0 0x20000000 0x20000000 0 0x04000000>;
+ phys = <&pcie0_phy>;
+ phy-names = "pcie-phy";
+
status = "disabled";
+
+ msi-parent = <&msi0>;
+ msi0: msi@18012000 {
+ compatible = "brcm,iproc-msi";
+ msi-controller;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>,
+ <GIC_SPI 97 IRQ_TYPE_NONE>,
+ <GIC_SPI 98 IRQ_TYPE_NONE>,
+ <GIC_SPI 99 IRQ_TYPE_NONE>;
+ };
};
pcie1: pcie@18013000 {
@@ -182,7 +215,21 @@
ranges = <0x81000000 0 0 0x48000000 0 0x00010000
0x82000000 0 0x40000000 0x40000000 0 0x04000000>;
+ phys = <&pcie1_phy>;
+ phy-names = "pcie-phy";
+
status = "disabled";
+
+ msi-parent = <&msi1>;
+ msi1: msi@18013000 {
+ compatible = "brcm,iproc-msi";
+ msi-controller;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_NONE>,
+ <GIC_SPI 103 IRQ_TYPE_NONE>,
+ <GIC_SPI 104 IRQ_TYPE_NONE>,
+ <GIC_SPI 105 IRQ_TYPE_NONE>;
+ };
};
uart0: serial@18020000 {
@@ -245,13 +292,63 @@
gpio_asiu: gpio@180a5000 {
compatible = "brcm,cygnus-asiu-gpio";
reg = <0x180a5000 0x668>;
+ ngpios = <146>;
#gpio-cells = <2>;
gpio-controller;
- pinmux = <&pinctrl>;
-
interrupt-controller;
interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 42 1>,
+ <&pinctrl 1 44 3>,
+ <&pinctrl 4 48 1>,
+ <&pinctrl 5 50 3>,
+ <&pinctrl 8 126 1>,
+ <&pinctrl 9 155 1>,
+ <&pinctrl 10 152 1>,
+ <&pinctrl 11 154 1>,
+ <&pinctrl 12 153 1>,
+ <&pinctrl 13 127 3>,
+ <&pinctrl 16 140 1>,
+ <&pinctrl 17 145 7>,
+ <&pinctrl 24 130 10>,
+ <&pinctrl 34 141 4>,
+ <&pinctrl 38 54 1>,
+ <&pinctrl 39 56 3>,
+ <&pinctrl 42 60 3>,
+ <&pinctrl 45 64 3>,
+ <&pinctrl 48 68 2>,
+ <&pinctrl 50 84 6>,
+ <&pinctrl 56 94 6>,
+ <&pinctrl 62 72 1>,
+ <&pinctrl 63 70 1>,
+ <&pinctrl 64 80 1>,
+ <&pinctrl 65 74 3>,
+ <&pinctrl 68 78 1>,
+ <&pinctrl 69 82 1>,
+ <&pinctrl 70 156 17>,
+ <&pinctrl 87 104 12>,
+ <&pinctrl 99 102 2>,
+ <&pinctrl 101 90 4>,
+ <&pinctrl 105 116 6>,
+ <&pinctrl 111 100 2>,
+ <&pinctrl 113 122 4>,
+ <&pinctrl 123 11 1>,
+ <&pinctrl 124 38 4>,
+ <&pinctrl 128 43 1>,
+ <&pinctrl 129 47 1>,
+ <&pinctrl 130 49 1>,
+ <&pinctrl 131 53 1>,
+ <&pinctrl 132 55 1>,
+ <&pinctrl 133 59 1>,
+ <&pinctrl 134 63 1>,
+ <&pinctrl 135 67 1>,
+ <&pinctrl 136 71 1>,
+ <&pinctrl 137 73 1>,
+ <&pinctrl 138 77 1>,
+ <&pinctrl 139 79 1>,
+ <&pinctrl 140 81 1>,
+ <&pinctrl 141 83 1>,
+ <&pinctrl 142 10 1>;
};
touchscreen: tsc@180a6000 {
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index 58aca277e4a7..10bdef557ba0 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -32,6 +32,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/bcm-nsp.h>
#include "skeleton.dtsi"
@@ -40,9 +41,30 @@
model = "Broadcom Northstar Plus SoC";
interrupt-parent = <&gic>;
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ enable-method = "brcm,bcm-nsp-smp";
+ secondary-boot-reg = <0xffff042c>;
+ reg = <0x1>;
+ };
+ };
+
mpcore {
compatible = "simple-bus";
- ranges = <0x00000000 0x19020000 0x00003000>;
+ ranges = <0x00000000 0x19000000 0x00023000>;
#address-cells = <1>;
#size-cells = <1>;
@@ -58,27 +80,50 @@
};
};
- L2: l2-cache {
- compatible = "arm,pl310-cache";
- reg = <0x2000 0x1000>;
- cache-unified;
- cache-level = <2>;
+ a9pll: arm_clk@00000 {
+ #clock-cells = <0>;
+ compatible = "brcm,nsp-armpll";
+ clocks = <&osc>;
+ reg = <0x00000 0x1000>;
+ };
+
+ timer@20200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x20200 0x100>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&periph_clk>;
+ };
+
+ twd-timer@20600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x20600 0x20>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
+ IRQ_TYPE_LEVEL_HIGH)>;
+ clocks = <&periph_clk>;
+ };
+
+ twd-watchdog@20620 {
+ compatible = "arm,cortex-a9-twd-wdt";
+ reg = <0x20620 0x20>;
+ interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) |
+ IRQ_TYPE_LEVEL_HIGH)>;
+ clocks = <&periph_clk>;
};
- gic: interrupt-controller@19021000 {
+ gic: interrupt-controller@21000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
- reg = <0x1000 0x1000>,
- <0x0100 0x100>;
+ reg = <0x21000 0x1000>,
+ <0x20100 0x100>;
};
- timer@19020200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x0200 0x100>;
- interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&periph_clk>;
+ L2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0x22000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
};
};
@@ -87,33 +132,178 @@
#size-cells = <1>;
ranges;
- periph_clk: periph_clk {
+ osc: oscillator {
+ #clock-cells = <0>;
compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ iprocmed: iprocmed {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ iprocslow: iprocslow {
#clock-cells = <0>;
- clock-frequency = <500000000>;
+ compatible = "fixed-factor-clock";
+ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>;
+ clock-div = <4>;
+ clock-mult = <1>;
+ };
+
+ periph_clk: periph_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&a9pll>;
+ clock-div = <2>;
+ clock-mult = <1>;
};
};
axi {
compatible = "simple-bus";
- ranges = <0x00000000 0x18000000 0x00001000>;
+ ranges = <0x00000000 0x18000000 0x0011ba08>;
#address-cells = <1>;
#size-cells = <1>;
- uart0: serial@18000300 {
+ uart0: serial@0300 {
compatible = "ns16550a";
reg = <0x0300 0x100>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <62499840>;
+ clocks = <&osc>;
status = "disabled";
};
- uart1: serial@18000400 {
+ uart1: serial@0400 {
compatible = "ns16550a";
reg = <0x0400 0x100>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <62499840>;
+ clocks = <&osc>;
+ status = "disabled";
+ };
+
+ pcie0: pcie@12000 {
+ compatible = "brcm,iproc-pcie";
+ reg = <0x12000 0x1000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_NONE>;
+
+ linux,pci-domain = <0>;
+
+ bus-range = <0x00 0xff>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+
+ /* Note: The HW does not support I/O resources. So,
+ * only the memory resource range is being specified.
+ */
+ ranges = <0x82000000 0 0x08000000 0x08000000 0 0x8000000>;
+
+ status = "disabled";
+ };
+
+ pcie1: pcie@13000 {
+ compatible = "brcm,iproc-pcie";
+ reg = <0x13000 0x1000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 137 IRQ_TYPE_NONE>;
+
+ linux,pci-domain = <1>;
+
+ bus-range = <0x00 0xff>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+
+ /* Note: The HW does not support I/O resources. So,
+ * only the memory resource range is being specified.
+ */
+ ranges = <0x82000000 0 0x40000000 0x40000000 0 0x8000000>;
+
+ status = "disabled";
+ };
+
+ pcie2: pcie@14000 {
+ compatible = "brcm,iproc-pcie";
+ reg = <0x14000 0x1000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 143 IRQ_TYPE_NONE>;
+
+ linux,pci-domain = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+
+ /* Note: The HW does not support I/O resources. So,
+ * only the memory resource range is being specified.
+ */
+ ranges = <0x82000000 0 0x48000000 0x48000000 0 0x8000000>;
+
status = "disabled";
};
+
+ nand: nand@26000 {
+ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
+ reg = <0x026000 0x600>,
+ <0x11b408 0x600>,
+ <0x026f00 0x20>;
+ reg-names = "nand", "iproc-idm", "iproc-ext";
+ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ brcm,nand-has-wp;
+ };
+
+ i2c0: i2c@38000 {
+ compatible = "brcm,iproc-i2c";
+ reg = <0x38000 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
+ clock-frequency = <100000>;
+ };
+
+ lcpll0: lcpll0@3f100 {
+ #clock-cells = <1>;
+ compatible = "brcm,nsp-lcpll0";
+ reg = <0x3f100 0x14>;
+ clocks = <&osc>;
+ clock-output-names = "lcpll0", "pcie_phy", "sdio",
+ "ddr_phy";
+ };
+
+ genpll: genpll@3f140 {
+ #clock-cells = <1>;
+ compatible = "brcm,nsp-genpll";
+ reg = <0x3f140 0x24>;
+ clocks = <&osc>;
+ clock-output-names = "genpll", "phy", "ethernetclk",
+ "usbclk", "iprocfast", "sata1",
+ "sata2";
+ };
+
+ pinctrl: pinctrl@3f1c0 {
+ compatible = "brcm,nsp-pinmux";
+ reg = <0x3f1c0 0x04>,
+ <0x30028 0x04>,
+ <0x3f408 0x04>;
+ };
};
};
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index 2ddaa5136611..3dc7a8cc5812 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -31,7 +31,6 @@
#address-cells = <1>;
#size-cells = <0>;
enable-method = "brcm,bcm11351-cpu-method";
- secondary-boot-reg = <0x3500417c>;
cpu0: cpu@0 {
device_type = "cpu";
@@ -42,6 +41,7 @@
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
+ secondary-boot-reg = <0x3500417c>;
reg = <1>;
};
};
diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi
index 2016b72a8fb7..3f525be28fd0 100644
--- a/arch/arm/boot/dts/bcm21664.dtsi
+++ b/arch/arm/boot/dts/bcm21664.dtsi
@@ -31,7 +31,6 @@
#address-cells = <1>;
#size-cells = <0>;
enable-method = "brcm,bcm11351-cpu-method";
- secondary-boot-reg = <0x35004178>;
cpu0: cpu@0 {
device_type = "cpu";
@@ -42,6 +41,7 @@
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
+ secondary-boot-reg = <0x35004178>;
reg = <1>;
};
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
index b2bff43b135c..228614ffff44 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
@@ -1,4 +1,5 @@
/dts-v1/;
+#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
/ {
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
index 668442b1bda5..ef5405025223 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
@@ -1,4 +1,5 @@
/dts-v1/;
+#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
/ {
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
index eab8b5916e8a..86f1f2f598a7 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
@@ -1,4 +1,5 @@
/dts-v1/;
+#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
/ {
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index ff6b2d1c6c90..4859e9d81b23 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -1,4 +1,5 @@
/dts-v1/;
+#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
/ {
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 3572f0367baf..3afb9fefe2d1 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -1,5 +1,3 @@
-#include "bcm2835.dtsi"
-
/ {
memory {
reg = <0 0x10000000>;
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index aef64de77495..b83b32639358 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -1,206 +1,14 @@
-#include <dt-bindings/pinctrl/bcm2835.h>
-#include <dt-bindings/clock/bcm2835.h>
-#include "skeleton.dtsi"
+#include "bcm283x.dtsi"
/ {
compatible = "brcm,bcm2835";
- model = "BCM2835";
- interrupt-parent = <&intc>;
-
- chosen {
- bootargs = "earlyprintk console=ttyAMA0";
- };
soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
ranges = <0x7e000000 0x20000000 0x02000000>;
dma-ranges = <0x40000000 0x00000000 0x20000000>;
- timer@7e003000 {
- compatible = "brcm,bcm2835-system-timer";
- reg = <0x7e003000 0x1000>;
- interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
- /* This could be a reference to BCM2835_CLOCK_TIMER,
- * but we don't have the driver using the common clock
- * support yet.
- */
- clock-frequency = <1000000>;
- };
-
- dma: dma@7e007000 {
- compatible = "brcm,bcm2835-dma";
- reg = <0x7e007000 0xf00>;
- interrupts = <1 16>,
- <1 17>,
- <1 18>,
- <1 19>,
- <1 20>,
- <1 21>,
- <1 22>,
- <1 23>,
- <1 24>,
- <1 25>,
- <1 26>,
- <1 27>,
- <1 28>;
-
- #dma-cells = <1>;
- brcm,dma-channel-mask = <0x7f35>;
- };
-
- intc: interrupt-controller@7e00b200 {
- compatible = "brcm,bcm2835-armctrl-ic";
- reg = <0x7e00b200 0x200>;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
-
- watchdog@7e100000 {
- compatible = "brcm,bcm2835-pm-wdt";
- reg = <0x7e100000 0x28>;
- };
-
- clocks: cprman@7e101000 {
- compatible = "brcm,bcm2835-cprman";
- #clock-cells = <1>;
- reg = <0x7e101000 0x2000>;
-
- /* CPRMAN derives everything from the platform's
- * oscillator.
- */
- clocks = <&clk_osc>;
- };
-
- rng@7e104000 {
- compatible = "brcm,bcm2835-rng";
- reg = <0x7e104000 0x10>;
- };
-
- mailbox: mailbox@7e00b800 {
- compatible = "brcm,bcm2835-mbox";
- reg = <0x7e00b880 0x40>;
- interrupts = <0 1>;
- #mbox-cells = <0>;
- };
-
- gpio: gpio@7e200000 {
- compatible = "brcm,bcm2835-gpio";
- reg = <0x7e200000 0xb4>;
- /*
- * The GPIO IP block is designed for 3 banks of GPIOs.
- * Each bank has a GPIO interrupt for itself.
- * There is an overall "any bank" interrupt.
- * In order, these are GIC interrupts 17, 18, 19, 20.
- * Since the BCM2835 only has 2 banks, the 2nd bank
- * interrupt output appears to be mirrored onto the
- * 3rd bank's interrupt signal.
- * So, a bank0 interrupt shows up on 17, 20, and
- * a bank1 interrupt shows up on 18, 19, 20!
- */
- interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- interrupt-controller;
- #interrupt-cells = <2>;
- };
-
- uart0: uart@7e201000 {
- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
- reg = <0x7e201000 0x1000>;
- interrupts = <2 25>;
- clocks = <&clocks BCM2835_CLOCK_UART>,
- <&clocks BCM2835_CLOCK_VPU>;
- clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
- };
-
- i2s: i2s@7e203000 {
- compatible = "brcm,bcm2835-i2s";
- reg = <0x7e203000 0x20>,
- <0x7e101098 0x02>;
-
- dmas = <&dma 2>,
- <&dma 3>;
- dma-names = "tx", "rx";
- status = "disabled";
- };
-
- spi: spi@7e204000 {
- compatible = "brcm,bcm2835-spi";
- reg = <0x7e204000 0x1000>;
- interrupts = <2 22>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
- };
-
- i2c0: i2c@7e205000 {
- compatible = "brcm,bcm2835-i2c";
- reg = <0x7e205000 0x1000>;
- interrupts = <2 21>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
- };
-
- sdhci: sdhci@7e300000 {
- compatible = "brcm,bcm2835-sdhci";
- reg = <0x7e300000 0x100>;
- interrupts = <2 30>;
- clocks = <&clocks BCM2835_CLOCK_EMMC>;
- status = "disabled";
- };
-
- i2c1: i2c@7e804000 {
- compatible = "brcm,bcm2835-i2c";
- reg = <0x7e804000 0x1000>;
- interrupts = <2 21>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
- };
-
- i2c2: i2c@7e805000 {
- compatible = "brcm,bcm2835-i2c";
- reg = <0x7e805000 0x1000>;
- interrupts = <2 21>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
- };
-
- usb@7e980000 {
- compatible = "brcm,bcm2835-usb";
- reg = <0x7e980000 0x10000>;
- interrupts = <1 9>;
- };
-
arm-pmu {
compatible = "arm,arm1176-pmu";
};
};
-
- clocks {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <0>;
-
- /* The oscillator is the root of the clock tree. */
- clk_osc: clock@3 {
- compatible = "fixed-clock";
- reg = <3>;
- #clock-cells = <0>;
- clock-output-names = "osc";
- clock-frequency = <19200000>;
- };
-
- };
};
diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
new file mode 100644
index 000000000000..ff946661bd13
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+#include "bcm2836.dtsi"
+#include "bcm2835-rpi.dtsi"
+
+/ {
+ compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+ model = "Raspberry Pi 2 Model B";
+
+ memory {
+ reg = <0 0x40000000>;
+ };
+
+ leds {
+ act {
+ gpios = <&gpio 47 0>;
+ };
+
+ pwr {
+ label = "PWR";
+ gpios = <&gpio 35 0>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+ };
+};
+
+&gpio {
+ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
+
+ /* I2S interface */
+ i2s_alt0: i2s_alt0 {
+ brcm,pins = <18 19 20 21>;
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+};
diff --git a/arch/arm/boot/dts/bcm2836.dtsi b/arch/arm/boot/dts/bcm2836.dtsi
new file mode 100644
index 000000000000..9d0651d8f373
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2836.dtsi
@@ -0,0 +1,78 @@
+#include "bcm283x.dtsi"
+
+/ {
+ compatible = "brcm,bcm2836";
+
+ soc {
+ ranges = <0x7e000000 0x3f000000 0x1000000>,
+ <0x40000000 0x40000000 0x00001000>;
+ dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
+
+ local_intc: local_intc {
+ compatible = "brcm,bcm2836-l1-intc";
+ reg = <0x40000000 0x100>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&local_intc>;
+ };
+
+ arm-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ interrupt-parent = <&local_intc>;
+ interrupts = <9>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupt-parent = <&local_intc>;
+ interrupts = <0>, // PHYS_SECURE_PPI
+ <1>, // PHYS_NONSECURE_PPI
+ <3>, // VIRT_PPI
+ <2>; // HYP_PPI
+ always-on;
+ };
+
+ cpus: cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ v7_cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf00>;
+ clock-frequency = <800000000>;
+ };
+
+ v7_cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf01>;
+ clock-frequency = <800000000>;
+ };
+
+ v7_cpu2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf02>;
+ clock-frequency = <800000000>;
+ };
+
+ v7_cpu3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf03>;
+ clock-frequency = <800000000>;
+ };
+ };
+};
+
+/* Make the BCM2835-style global interrupt controller be a child of the
+ * CPU-local interrupt controller.
+ */
+&intc {
+ compatible = "brcm,bcm2836-armctrl-ic";
+ reg = <0x7e00b200 0x200>;
+ interrupt-parent = <&local_intc>;
+ interrupts = <8>;
+};
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
new file mode 100644
index 000000000000..971e741e5467
--- /dev/null
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -0,0 +1,212 @@
+#include <dt-bindings/pinctrl/bcm2835.h>
+#include <dt-bindings/clock/bcm2835.h>
+#include "skeleton.dtsi"
+
+/* This include file covers the common peripherals and configuration between
+ * bcm2835 and bcm2836 implementations, leaving the CPU configuration to
+ * bcm2835.dtsi and bcm2836.dtsi.
+ */
+
+/ {
+ compatible = "brcm,bcm2835";
+ model = "BCM2835";
+ interrupt-parent = <&intc>;
+
+ chosen {
+ bootargs = "earlyprintk console=ttyAMA0";
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ timer@7e003000 {
+ compatible = "brcm,bcm2835-system-timer";
+ reg = <0x7e003000 0x1000>;
+ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+ /* This could be a reference to BCM2835_CLOCK_TIMER,
+ * but we don't have the driver using the common clock
+ * support yet.
+ */
+ clock-frequency = <1000000>;
+ };
+
+ dma: dma@7e007000 {
+ compatible = "brcm,bcm2835-dma";
+ reg = <0x7e007000 0xf00>;
+ interrupts = <1 16>,
+ <1 17>,
+ <1 18>,
+ <1 19>,
+ <1 20>,
+ <1 21>,
+ <1 22>,
+ <1 23>,
+ <1 24>,
+ <1 25>,
+ <1 26>,
+ <1 27>,
+ <1 28>;
+
+ #dma-cells = <1>;
+ brcm,dma-channel-mask = <0x7f35>;
+ };
+
+ intc: interrupt-controller@7e00b200 {
+ compatible = "brcm,bcm2835-armctrl-ic";
+ reg = <0x7e00b200 0x200>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ watchdog@7e100000 {
+ compatible = "brcm,bcm2835-pm-wdt";
+ reg = <0x7e100000 0x28>;
+ };
+
+ clocks: cprman@7e101000 {
+ compatible = "brcm,bcm2835-cprman";
+ #clock-cells = <1>;
+ reg = <0x7e101000 0x2000>;
+
+ /* CPRMAN derives everything from the platform's
+ * oscillator.
+ */
+ clocks = <&clk_osc>;
+ };
+
+ rng@7e104000 {
+ compatible = "brcm,bcm2835-rng";
+ reg = <0x7e104000 0x10>;
+ };
+
+ mailbox: mailbox@7e00b800 {
+ compatible = "brcm,bcm2835-mbox";
+ reg = <0x7e00b880 0x40>;
+ interrupts = <0 1>;
+ #mbox-cells = <0>;
+ };
+
+ gpio: gpio@7e200000 {
+ compatible = "brcm,bcm2835-gpio";
+ reg = <0x7e200000 0xb4>;
+ /*
+ * The GPIO IP block is designed for 3 banks of GPIOs.
+ * Each bank has a GPIO interrupt for itself.
+ * There is an overall "any bank" interrupt.
+ * In order, these are GIC interrupts 17, 18, 19, 20.
+ * Since the BCM2835 only has 2 banks, the 2nd bank
+ * interrupt output appears to be mirrored onto the
+ * 3rd bank's interrupt signal.
+ * So, a bank0 interrupt shows up on 17, 20, and
+ * a bank1 interrupt shows up on 18, 19, 20!
+ */
+ interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ uart0: uart@7e201000 {
+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+ reg = <0x7e201000 0x1000>;
+ interrupts = <2 25>;
+ clocks = <&clocks BCM2835_CLOCK_UART>,
+ <&clocks BCM2835_CLOCK_VPU>;
+ clock-names = "uartclk", "apb_pclk";
+ arm,primecell-periphid = <0x00241011>;
+ };
+
+ i2s: i2s@7e203000 {
+ compatible = "brcm,bcm2835-i2s";
+ reg = <0x7e203000 0x20>,
+ <0x7e101098 0x02>;
+
+ dmas = <&dma 2>,
+ <&dma 3>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ spi: spi@7e204000 {
+ compatible = "brcm,bcm2835-spi";
+ reg = <0x7e204000 0x1000>;
+ interrupts = <2 22>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@7e205000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e205000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ aux: aux@0x7e215000 {
+ compatible = "brcm,bcm2835-aux";
+ #clock-cells = <1>;
+ reg = <0x7e215000 0x8>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ };
+
+ sdhci: sdhci@7e300000 {
+ compatible = "brcm,bcm2835-sdhci";
+ reg = <0x7e300000 0x100>;
+ interrupts = <2 30>;
+ clocks = <&clocks BCM2835_CLOCK_EMMC>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@7e804000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e804000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@7e805000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e805000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ usb@7e980000 {
+ compatible = "brcm,bcm2835-usb";
+ reg = <0x7e980000 0x10000>;
+ interrupts = <1 9>;
+ };
+ };
+
+ clocks {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* The oscillator is the root of the clock tree. */
+ clk_osc: clock@3 {
+ compatible = "fixed-clock";
+ reg = <3>;
+ #clock-cells = <0>;
+ clock-output-names = "osc";
+ clock-frequency = <19200000>;
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e83fedd..eed4dd159995 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -15,6 +15,7 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ enable-method = "brcm,bcm-nsp-smp";
cpu@0 {
device_type = "cpu";
@@ -27,6 +28,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
next-level-cache = <&L2>;
+ secondary-boot-reg = <0xffff0400>;
reg = <0x1>;
};
};
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
index 446c586cd473..b52927c94e35 100644
--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
@@ -50,6 +50,36 @@
gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
linux,default-trigger = "default-off";
};
+
+ wireless {
+ label = "bcm53xx:white:wireless";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wps {
+ label = "bcm53xx:white:wps";
+ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ 5ghz-2 {
+ label = "bcm53xx:white:5ghz-2";
+ gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb3 {
+ label = "bcm53xx:white:usb3";
+ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb2 {
+ label = "bcm53xx:white:usb2";
+ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
};
gpio-keys {
diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
index 6f50f672efbd..65a1309bd6e2 100644
--- a/arch/arm/boot/dts/bcm5301x.dtsi
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
@@ -8,6 +8,7 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <dt-bindings/clock/bcm-nsp.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
@@ -27,7 +28,7 @@
compatible = "ns16550";
reg = <0x0300 0x100>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <100000000>;
+ clocks = <&iprocslow>;
status = "disabled";
};
@@ -35,48 +36,55 @@
compatible = "ns16550";
reg = <0x0400 0x100>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <100000000>;
+ clocks = <&iprocslow>;
status = "disabled";
};
};
mpcore {
compatible = "simple-bus";
- ranges = <0x00000000 0x19020000 0x00003000>;
+ ranges = <0x00000000 0x19000000 0x00023000>;
#address-cells = <1>;
#size-cells = <1>;
- scu@0000 {
+ a9pll: arm_clk@00000 {
+ #clock-cells = <0>;
+ compatible = "brcm,nsp-armpll";
+ clocks = <&osc>;
+ reg = <0x00000 0x1000>;
+ };
+
+ scu@20000 {
compatible = "arm,cortex-a9-scu";
- reg = <0x0000 0x100>;
+ reg = <0x20000 0x100>;
};
- timer@0200 {
+ timer@20200 {
compatible = "arm,cortex-a9-global-timer";
- reg = <0x0200 0x100>;
+ reg = <0x20200 0x100>;
interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_periph>;
+ clocks = <&periph_clk>;
};
- local-timer@0600 {
+ local-timer@20600 {
compatible = "arm,cortex-a9-twd-timer";
- reg = <0x0600 0x100>;
+ reg = <0x20600 0x100>;
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_periph>;
+ clocks = <&periph_clk>;
};
- gic: interrupt-controller@1000 {
+ gic: interrupt-controller@21000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
- reg = <0x1000 0x1000>,
- <0x0100 0x100>;
+ reg = <0x21000 0x1000>,
+ <0x20100 0x100>;
};
- L2: cache-controller@2000 {
+ L2: cache-controller@22000 {
compatible = "arm,pl310-cache";
- reg = <0x2000 0x1000>;
+ reg = <0x22000 0x1000>;
cache-unified;
arm,shared-override;
prefetch-data = <1>;
@@ -94,14 +102,37 @@
clocks {
#address-cells = <1>;
- #size-cells = <0>;
+ #size-cells = <1>;
+ ranges;
- /* As long as we do not have a real clock driver us this
- * fixed clock */
- clk_periph: periph {
+ osc: oscillator {
+ #clock-cells = <0>;
compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ iprocmed: iprocmed {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ iprocslow: iprocslow {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>;
+ clock-div = <4>;
+ clock-mult = <1>;
+ };
+
+ periph_clk: periph_clk {
#clock-cells = <0>;
- clock-frequency = <400000000>;
+ compatible = "fixed-factor-clock";
+ clocks = <&a9pll>;
+ clock-div = <2>;
+ clock-mult = <1>;
};
};
@@ -178,6 +209,25 @@
};
};
+ lcpll0: lcpll0@1800c100 {
+ #clock-cells = <1>;
+ compatible = "brcm,nsp-lcpll0";
+ reg = <0x1800c100 0x14>;
+ clocks = <&osc>;
+ clock-output-names = "lcpll0", "pcie_phy", "sdio",
+ "ddr_phy";
+ };
+
+ genpll: genpll@1800c140 {
+ #clock-cells = <1>;
+ compatible = "brcm,nsp-genpll";
+ reg = <0x1800c140 0x24>;
+ clocks = <&osc>;
+ clock-output-names = "genpll", "phy", "ethernetclk",
+ "usbclk", "iprocfast", "sata1",
+ "sata2";
+ };
+
nand: nand@18028000 {
compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand";
reg = <0x18028000 0x600>, <0x1811a408 0x600>, <0x18028f00 0x20>;
diff --git a/arch/arm/boot/dts/bcm63138.dtsi b/arch/arm/boot/dts/bcm63138.dtsi
index 34cd64051250..d0560e8cd6de 100644
--- a/arch/arm/boot/dts/bcm63138.dtsi
+++ b/arch/arm/boot/dts/bcm63138.dtsi
@@ -43,18 +43,31 @@
#address-cells = <1>;
#size-cells = <0>;
- arm_timer_clk: arm_timer_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <500000000>;
- };
-
+ /* UBUS peripheral clock */
periph_clk: periph_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
clock-output-names = "periph";
};
+
+ /* peripheral clock for system timer */
+ axi_clk: axi_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&armpll>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ /* APB bus clock */
+ apb_clk: apb_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&armpll>;
+ clock-div = <4>;
+ clock-mult = <1>;
+ };
};
/* ARM bus */
@@ -93,14 +106,14 @@
compatible = "arm,cortex-a9-global-timer";
reg = <0x1e200 0x20>;
interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&arm_timer_clk>;
+ clocks = <&axi_clk>;
};
local_timer: local-timer@1e600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x1e600 0x20>;
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&arm_timer_clk>;
+ clocks = <&axi_clk>;
};
twd_watchdog: watchdog@1e620 {
@@ -109,6 +122,13 @@
interrupts = <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>;
};
+ armpll: armpll {
+ #clock-cells = <0>;
+ compatible = "brcm,bcm63138-armpll";
+ clocks = <&periph_clk>;
+ reg = <0x20000 0xf00>;
+ };
+
pmb0: reset-controller@4800c0 {
compatible = "brcm,bcm63138-pmb";
reg = <0x4800c0 0x10>;
diff --git a/arch/arm/boot/dts/bcm94708.dts b/arch/arm/boot/dts/bcm94708.dts
new file mode 100644
index 000000000000..251a486f2da6
--- /dev/null
+++ b/arch/arm/boot/dts/bcm94708.dts
@@ -0,0 +1,56 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ model = "NorthStar SVK (BCM94708)";
+ compatible = "brcm,bcm94708", "brcm,bcm4708";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm94709.dts b/arch/arm/boot/dts/bcm94709.dts
new file mode 100644
index 000000000000..b16cac92904f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm94709.dts
@@ -0,0 +1,56 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ model = "NorthStar SVK (BCM94709)";
+ compatible = "brcm,bcm94709", "brcm,bcm4709", "brcm,bcm4708";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm953012k.dts b/arch/arm/boot/dts/bcm953012k.dts
new file mode 100644
index 000000000000..05a985a20378
--- /dev/null
+++ b/arch/arm/boot/dts/bcm953012k.dts
@@ -0,0 +1,63 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ model = "NorthStar SVK (BCM953012K)";
+ compatible = "brcm,bcm953012k", "brcm,brcm53012", "brcm,bcm4708";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x00000000 0x10000000>;
+ };
+};
+
+&uart0 {
+ clock-frequency = <62499840>;
+ status = "okay";
+};
+
+&uart1 {
+ clock-frequency = <62499840>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index 16303dbd35df..e298450b49b2 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -55,3 +55,62 @@
&uart1 {
status = "okay";
};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pcie2 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+
+ partition@0 {
+ label = "nboot";
+ reg = <0x00000000 0x00200000>;
+ read-only;
+ };
+ partition@1 {
+ label = "nenv";
+ reg = <0x00200000 0x00400000>;
+ };
+ partition@2 {
+ label = "nsystem";
+ reg = <0x00600000 0x00a00000>;
+ };
+ partition@3 {
+ label = "nrootfs";
+ reg = <0x01000000 0x03000000>;
+ };
+ partition@4 {
+ label = "ncustfs";
+ reg = <0x04000000 0x3c000000>;
+ };
+ };
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index eaadac3bdd44..ae81009741ff 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -435,6 +435,29 @@
ranges = <0 0xfc0000 0x10000>;
interrupt-parent = <&sic>;
+ wdt0: watchdog@1000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x1000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <0>;
+ };
+
+ wdt1: watchdog@2000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x2000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <1>;
+ status = "disabled";
+ };
+
+ wdt2: watchdog@3000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x3000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <2>;
+ status = "disabled";
+ };
+
sm_gpio1: gpio@5000 {
compatible = "snps,dw-apb-gpio";
reg = <0x5000 0x400>;
diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index b16df157214d..6d06b6118d83 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -396,6 +396,29 @@
ranges = <0 0xfc0000 0x10000>;
interrupt-parent = <&sic>;
+ wdt0: watchdog@1000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x1000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <0>;
+ };
+
+ wdt1: watchdog@2000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x2000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <1>;
+ status = "disabled";
+ };
+
+ wdt2: watchdog@3000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x3000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <2>;
+ status = "disabled";
+ };
+
sm_gpio1: gpio@5000 {
compatible = "snps,dw-apb-gpio";
reg = <0x5000 0x400>;
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index da28c9704a9d..33b28757b8f6 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -84,17 +84,49 @@
gpio = <&portb 12 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
+
+ reg_sdio1_vmmc: regulator@3 {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "sdio1_vmmc";
+ enable-active-high;
+ regulator-boot-on;
+ gpio = <&portb 21 GPIO_ACTIVE_HIGH>;
+ };
+
+ reg_sdio1_vqmmc: regulator@4 {
+ compatible = "regulator-gpio";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "sdio1_vqmmc";
+ regulator-type = "voltage";
+ enable-active-high;
+ gpios = <&portb 16 GPIO_ACTIVE_HIGH>;
+ states = <3300000 0x1
+ 1800000 0x0>;
+ };
+ };
+};
+
+&soc_pinctrl {
+ sd1gpio_pmux: sd1pwr-pmux {
+ groups = "G23", "G32";
+ function = "gpio";
};
};
&sdhci1 {
- broken-cd;
- sdhci,wp-inverted;
+ vmmc-supply = <&reg_sdio1_vmmc>;
+ vqmmc-supply = <&reg_sdio1_vqmmc>;
+ cd-gpios = <&portc 30 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&portd 0 GPIO_ACTIVE_HIGH>;
+ pinctrl-0 = <&sd1gpio_pmux>, <&sd1_pmux>;
+ pinctrl-names = "default";
status = "okay";
};
&sdhci2 {
- broken-cd;
bus-width = <8>;
non-removable;
status = "okay";
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index fb1da99996ea..2c34bfb13632 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -311,7 +311,6 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x1400 0x100>;
- interrupt-parent = <&aic>;
interrupts = <4>;
clocks = <&chip_clk CLKID_CFG>;
pinctrl-0 = <&twsi0_pmux>;
@@ -324,7 +323,6 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x1800 0x100>;
- interrupt-parent = <&aic>;
interrupts = <5>;
clocks = <&chip_clk CLKID_CFG>;
pinctrl-0 = <&twsi1_pmux>;
@@ -419,6 +417,11 @@
soc_pinctrl: pin-controller {
compatible = "marvell,berlin2q-soc-pinctrl";
+ sd1_pmux: sd1-pmux {
+ groups = "G31";
+ function = "sd1";
+ };
+
twsi0_pmux: twsi0-pmux {
groups = "G6";
function = "twsi0";
@@ -510,6 +513,29 @@
ranges = <0 0xfc0000 0x10000>;
interrupt-parent = <&sic>;
+ wdt0: watchdog@1000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x1000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <0>;
+ };
+
+ wdt1: watchdog@2000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x2000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <1>;
+ status = "disabled";
+ };
+
+ wdt2: watchdog@3000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x3000 0x100>;
+ clocks = <&refclk>;
+ interrupts = <2>;
+ status = "disabled";
+ };
+
sm_gpio1: gpio@5000 {
compatible = "snps,dw-apb-gpio";
reg = <0x5000 0x400>;
@@ -530,7 +556,6 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x7000 0x100>;
- interrupt-parent = <&sic>;
interrupts = <6>;
clocks = <&refclk>;
pinctrl-0 = <&twsi2_pmux>;
@@ -543,7 +568,6 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x8000 0x100>;
- interrupt-parent = <&sic>;
interrupts = <7>;
clocks = <&refclk>;
pinctrl-0 = <&twsi3_pmux>;
@@ -554,7 +578,6 @@
uart0: uart@9000 {
compatible = "snps,dw-apb-uart";
reg = <0x9000 0x100>;
- interrupt-parent = <&sic>;
interrupts = <8>;
clocks = <&refclk>;
reg-shift = <2>;
@@ -566,7 +589,6 @@
uart1: uart@a000 {
compatible = "snps,dw-apb-uart";
reg = <0xa000 0x100>;
- interrupt-parent = <&sic>;
interrupts = <9>;
clocks = <&refclk>;
reg-shift = <2>;
diff --git a/arch/arm/boot/dts/compulab-sb-som.dtsi b/arch/arm/boot/dts/compulab-sb-som.dtsi
new file mode 100644
index 000000000000..93d7e235bc80
--- /dev/null
+++ b/arch/arm/boot/dts/compulab-sb-som.dtsi
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 CompuLab, Ltd. - http://www.compulab.co.il/
+ *
+ * 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.
+ */
+
+/ {
+ model = "CompuLab SB-SOM";
+ compatible = "compulab,sb-som";
+
+ vsb_3v3: fixedregulator-v3_3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vsb_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ enable-active-high;
+ };
+
+ lcd0: display {
+ compatible = "startek,startek-kd050c", "panel-dpi";
+ label = "lcd";
+
+ panel-timing {
+ clock-frequency = <33000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hfront-porch = <40>;
+ hback-porch = <40>;
+ hsync-len = <43>;
+ vback-porch = <29>;
+ vfront-porch = <13>;
+ vsync-len = <3>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <1>;
+ };
+ };
+
+ hdmi_conn: connector@0 {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+
+ type = "a";
+ };
+};
diff --git a/arch/arm/boot/dts/da850-enbw-cmc.dts b/arch/arm/boot/dts/da850-enbw-cmc.dts
index e750ab9086d5..645549e14237 100644
--- a/arch/arm/boot/dts/da850-enbw-cmc.dts
+++ b/arch/arm/boot/dts/da850-enbw-cmc.dts
@@ -28,3 +28,11 @@
};
};
};
+
+&edma0 {
+ ti,edma-reserved-slot-ranges = <32 50>;
+};
+
+&edma1 {
+ ti,edma-reserved-slot-ranges = <32 90>;
+};
diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts
index 4f935ad9f27b..ef061e9a2315 100644
--- a/arch/arm/boot/dts/da850-evm.dts
+++ b/arch/arm/boot/dts/da850-evm.dts
@@ -242,3 +242,11 @@
tx-num-evt = <32>;
rx-num-evt = <32>;
};
+
+&edma0 {
+ ti,edma-reserved-slot-ranges = <32 50>;
+};
+
+&edma1 {
+ ti,edma-reserved-slot-ranges = <32 90>;
+};
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 0bd98cd00816..226cda76e77c 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -151,10 +151,44 @@
};
edma0: edma@01c00000 {
- compatible = "ti,edma3";
- reg = <0x0 0x10000>;
- interrupts = <11 13 12>;
- #dma-cells = <1>;
+ compatible = "ti,edma3-tpcc";
+ /* eDMA3 CC0: 0x01c0 0000 - 0x01c0 7fff */
+ reg = <0x0 0x8000>;
+ reg-names = "edma3_cc";
+ interrupts = <11 12>;
+ interrupt-names = "edma3_ccint", "edma3_ccerrint";
+ #dma-cells = <2>;
+
+ ti,tptcs = <&edma0_tptc0 7>, <&edma0_tptc1 0>;
+ };
+ edma0_tptc0: tptc@01c08000 {
+ compatible = "ti,edma3-tptc";
+ reg = <0x8000 0x400>;
+ interrupts = <13>;
+ interrupt-names = "edm3_tcerrint";
+ };
+ edma0_tptc1: tptc@01c08400 {
+ compatible = "ti,edma3-tptc";
+ reg = <0x8400 0x400>;
+ interrupts = <32>;
+ interrupt-names = "edm3_tcerrint";
+ };
+ edma1: edma@01e30000 {
+ compatible = "ti,edma3-tpcc";
+ /* eDMA3 CC1: 0x01e3 0000 - 0x01e3 7fff */
+ reg = <0x230000 0x8000>;
+ reg-names = "edma3_cc";
+ interrupts = <93 94>;
+ interrupt-names = "edma3_ccint", "edma3_ccerrint";
+ #dma-cells = <2>;
+
+ ti,tptcs = <&edma1_tptc0 7>;
+ };
+ edma1_tptc0: tptc@01e38000 {
+ compatible = "ti,edma3-tptc";
+ reg = <0x238000 0x400>;
+ interrupts = <95>;
+ interrupt-names = "edm3_tcerrint";
};
serial0: serial@1c42000 {
compatible = "ns16550a";
@@ -201,6 +235,16 @@
compatible = "ti,da830-mmc";
reg = <0x40000 0x1000>;
interrupts = <16>;
+ dmas = <&edma0 16 0>, <&edma0 17 0>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+ mmc1: mmc@1e1b000 {
+ compatible = "ti,da830-mmc";
+ reg = <0x21b000 0x1000>;
+ interrupts = <72>;
+ dmas = <&edma1 28 0>, <&edma1 29 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
ehrpwm0: ehrpwm@01f00000 {
@@ -241,6 +285,8 @@
num-cs = <4>;
ti,davinci-spi-intr-line = <1>;
interrupts = <56>;
+ dmas = <&edma0 18 0>, <&edma0 19 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
mdio: mdio@1e24000 {
@@ -285,8 +331,8 @@
interrupts = <54>;
interrupt-names = "common";
status = "disabled";
- dmas = <&edma0 1>,
- <&edma0 0>;
+ dmas = <&edma0 1 1>,
+ <&edma0 0 1>;
dma-names = "tx", "rx";
};
};
diff --git a/arch/arm/boot/dts/dm8148-evm.dts b/arch/arm/boot/dts/dm8148-evm.dts
index 109fd4711647..e070862b1038 100644
--- a/arch/arm/boot/dts/dm8148-evm.dts
+++ b/arch/arm/boot/dts/dm8148-evm.dts
@@ -15,6 +15,14 @@
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
+
+ /* MIC94060YC6 controlled by SD1_POW pin */
+ vmmcsd_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
};
&cpsw_emac0 {
@@ -26,3 +34,50 @@
phy_id = <&davinci_mdio>, <1>;
phy-mode = "rgmii";
};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_pins>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ bus-width = <4>;
+ cd-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
+};
+
+&pincntl {
+ sd1_pins: pinmux_sd1_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0800, PIN_INPUT | 0x1) /* SD1_CLK */
+ DM814X_IOPAD(0x0804, PIN_INPUT_PULLUP | 0x1) /* SD1_CMD */
+ DM814X_IOPAD(0x0808, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[0] */
+ DM814X_IOPAD(0x080c, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[1] */
+ DM814X_IOPAD(0x0810, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[2] */
+ DM814X_IOPAD(0x0814, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[3] */
+ DM814X_IOPAD(0x0924, PIN_OUTPUT | 0x40) /* SD1_POW */
+ DM814X_IOPAD(0x093C, PIN_INPUT_PULLUP | 0x80) /* GP1[6] */
+ >;
+ };
+
+ usb0_pins: pinmux_usb0_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0c34, PIN_OUTPUT | 0x1) /* USB0_DRVVBUS */
+ >;
+ };
+
+ usb1_pins: pinmux_usb1_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0834, PIN_OUTPUT | 0x80) /* USB1_DRVVBUS */
+ >;
+ };
+};
+
+&usb0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_pins>;
+ dr_mode = "host";
+};
+
+&usb1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_pins>;
+ dr_mode = "host";
+};
diff --git a/arch/arm/boot/dts/dm8148-t410.dts b/arch/arm/boot/dts/dm8148-t410.dts
index 79838dd8dee7..5d4313fd5a46 100644
--- a/arch/arm/boot/dts/dm8148-t410.dts
+++ b/arch/arm/boot/dts/dm8148-t410.dts
@@ -15,6 +15,24 @@
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
+
+ /* gpio9 seems to control USB VBUS regulator and/or hub power */
+ usb_power: regulator@9 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ vmmcsd_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
};
&cpsw_emac0 {
@@ -26,3 +44,55 @@
phy_id = <&davinci_mdio>, <1>;
phy-mode = "rgmii";
};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_pins>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ bus-width = <8>;
+ dmas = <&edma_xbar 8 0 1 /* use SDTXEVT1 instead of MCASP0TX */
+ &edma_xbar 9 0 2>; /* use SDRXEVT1 instead of MCASP0RX */
+ dma-names = "tx", "rx";
+};
+
+&pincntl {
+ sd2_pins: pinmux_sd2_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x09c0, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[7] */
+ DM814X_IOPAD(0x09c4, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[6] */
+ DM814X_IOPAD(0x09c8, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[5] */
+ DM814X_IOPAD(0x09cc, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[4] */
+ DM814X_IOPAD(0x09d0, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[3] */
+ DM814X_IOPAD(0x09d4, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[2] */
+ DM814X_IOPAD(0x09d8, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[1] */
+ DM814X_IOPAD(0x09dc, PIN_INPUT_PULLUP | 0x1) /* SD2_DAT[0] */
+ DM814X_IOPAD(0x09e0, PIN_INPUT | 0x1) /* SD2_CLK */
+ DM814X_IOPAD(0x09f4, PIN_INPUT_PULLUP | 0x2) /* SD2_CMD */
+ DM814X_IOPAD(0x0920, PIN_INPUT | 40) /* SD2_SDCD */
+ >;
+ };
+
+ usb0_pins: pinmux_usb0_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0c34, PIN_OUTPUT | 0x1) /* USB0_DRVVBUS */
+ >;
+ };
+
+ usb1_pins: pinmux_usb1_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0834, PIN_OUTPUT | 0x80) /* USB1_DRVVBUS */
+ >;
+ };
+};
+
+&usb0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_pins>;
+ dr_mode = "host";
+};
+
+&usb1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_pins>;
+ dr_mode = "host";
+};
diff --git a/arch/arm/boot/dts/dm814x-clocks.dtsi b/arch/arm/boot/dts/dm814x-clocks.dtsi
index ef1e8e7a6cc6..26001585673a 100644
--- a/arch/arm/boot/dts/dm814x-clocks.dtsi
+++ b/arch/arm/boot/dts/dm814x-clocks.dtsi
@@ -4,25 +4,74 @@
* published by the Free Software Foundation.
*/
+&pllss_clocks {
+ timer1_fck: timer1_fck {
+ #clock-cells = <0>;
+ compatible = "ti,mux-clock";
+ clocks = <&sysclk18_ck &aud_clkin0_ck &aud_clkin1_ck
+ &aud_clkin2_ck &devosc_ck &auxosc_ck &tclkin_ck>;
+ ti,bit-shift = <3>;
+ reg = <0x2e0>;
+ };
+
+ timer2_fck: timer2_fck {
+ #clock-cells = <0>;
+ compatible = "ti,mux-clock";
+ clocks = <&sysclk18_ck &aud_clkin0_ck &aud_clkin1_ck
+ &aud_clkin2_ck &devosc_ck &auxosc_ck &tclkin_ck>;
+ ti,bit-shift = <6>;
+ reg = <0x2e0>;
+ };
+
+ sysclk18_ck: sysclk18_ck {
+ #clock-cells = <0>;
+ compatible = "ti,mux-clock";
+ clocks = <&rtcosc_ck>, <&rtcdivider_ck>;
+ ti,bit-shift = <0>;
+ reg = <0x02f0>;
+ };
+};
+
&scm_clocks {
+ devosc_ck: devosc_ck {
+ #clock-cells = <0>;
+ compatible = "ti,mux-clock";
+ clocks = <&virt_20000000_ck>, <&virt_19200000_ck>;
+ ti,bit-shift = <21>;
+ reg = <0x0040>;
+ };
- tclkin_ck: tclkin_ck {
+ /* Optional auxosc, 20 - 30 MHz range, assume 27 MHz by default */
+ auxosc_ck: auxosc_ck {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <27000000>;
+ };
+
+ /* Optional 32768Hz crystal or clock on RTCOSC pins */
+ rtcosc_ck: rtcosc_ck {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
};
- devosc_ck: devosc_ck {
+ /* Optional external clock on TCLKIN pin, set rate in baord dts file */
+ tclkin_ck: tclkin_ck {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ virt_20000000_ck: virt_20000000_ck {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <20000000>;
};
- /* Optional auxosc, 20 - 30 MHz range, assume 27 MHz by default */
- auxosc_ck: auxosc_ck {
+ virt_19200000_ck: virt_19200000_ck {
#clock-cells = <0>;
compatible = "fixed-clock";
- clock-frequency = <27000000>;
+ clock-frequency = <19200000>;
};
mpu_ck: mpu_ck {
@@ -49,12 +98,6 @@
clock-frequency = <48000000>;
};
- sysclk18_ck: sysclk18_ck {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32768>;
- };
-
cpsw_125mhz_gclk: cpsw_125mhz_gclk {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -69,7 +112,31 @@
};
-&pllss_clocks {
+&prcm_clocks {
+ osc_src_ck: osc_src_ck {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&devosc_ck>;
+ clock-mult = <1>;
+ clock-div = <1>;
+ };
+
+ mpu_clksrc_ck: mpu_clksrc_ck {
+ #clock-cells = <0>;
+ compatible = "ti,mux-clock";
+ clocks = <&devosc_ck>, <&rtcdivider_ck>;
+ ti,bit-shift = <0>;
+ reg = <0x0040>;
+ };
+
+ /* Fixed divider clock 0.0016384 * devosc */
+ rtcdivider_ck: rtcdivider_ck {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&devosc_ck>;
+ clock-mult = <128>;
+ clock-div = <78125>;
+ };
aud_clkin0_ck: aud_clkin0_ck {
#clock-cells = <0>;
@@ -88,22 +155,4 @@
compatible = "fixed-clock";
clock-frequency = <20000000>;
};
-
- timer1_mux_ck: timer1_mux_ck {
- #clock-cells = <0>;
- compatible = "ti,mux-clock";
- clocks = <&sysclk18_ck &aud_clkin0_ck &aud_clkin1_ck
- &aud_clkin2_ck &devosc_ck &auxosc_ck &tclkin_ck>;
- ti,bit-shift = <3>;
- reg = <0x2e0>;
- };
-
- timer2_mux_ck: timer2_mux_ck {
- #clock-cells = <0>;
- compatible = "ti,mux-clock";
- clocks = <&sysclk18_ck &aud_clkin0_ck &aud_clkin1_ck
- &aud_clkin2_ck &devosc_ck &auxosc_ck &tclkin_ck>;
- ti,bit-shift = <6>;
- reg = <0x2e0>;
- };
};
diff --git a/arch/arm/boot/dts/dm814x.dtsi b/arch/arm/boot/dts/dm814x.dtsi
index 7988b42e5764..a25cd51e39ab 100644
--- a/arch/arm/boot/dts/dm814x.dtsi
+++ b/arch/arm/boot/dts/dm814x.dtsi
@@ -5,7 +5,7 @@
*/
#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/pinctrl/omap.h>
+#include <dt-bindings/pinctrl/dm814x.h>
#include "skeleton.dtsi"
@@ -21,6 +21,10 @@
serial2 = &uart3;
ethernet0 = &cpsw_emac0;
ethernet1 = &cpsw_emac1;
+ usb0 = &usb0;
+ usb1 = &usb1;
+ phy0 = &usb0_phy;
+ phy1 = &usb1_phy;
};
cpus {
@@ -57,9 +61,118 @@
ranges;
ti,hwmods = "l3_main";
+ usb: usb@47400000 {
+ compatible = "ti,am33xx-usb";
+ reg = <0x47400000 0x1000>;
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ti,hwmods = "usb_otg_hs";
+
+ usb0_phy: usb-phy@47401300 {
+ compatible = "ti,am335x-usb-phy";
+ reg = <0x47401300 0x100>;
+ reg-names = "phy";
+ ti,ctrl_mod = <&usb_ctrl_mod>;
+ };
+
+ usb0: usb@47401000 {
+ compatible = "ti,musb-am33xx";
+ reg = <0x47401400 0x400
+ 0x47401000 0x200>;
+ reg-names = "mc", "control";
+
+ interrupts = <18>;
+ interrupt-names = "mc";
+ dr_mode = "otg";
+ mentor,multipoint = <1>;
+ mentor,num-eps = <16>;
+ mentor,ram-bits = <12>;
+ mentor,power = <500>;
+ phys = <&usb0_phy>;
+
+ dmas = <&cppi41dma 0 0 &cppi41dma 1 0
+ &cppi41dma 2 0 &cppi41dma 3 0
+ &cppi41dma 4 0 &cppi41dma 5 0
+ &cppi41dma 6 0 &cppi41dma 7 0
+ &cppi41dma 8 0 &cppi41dma 9 0
+ &cppi41dma 10 0 &cppi41dma 11 0
+ &cppi41dma 12 0 &cppi41dma 13 0
+ &cppi41dma 14 0 &cppi41dma 0 1
+ &cppi41dma 1 1 &cppi41dma 2 1
+ &cppi41dma 3 1 &cppi41dma 4 1
+ &cppi41dma 5 1 &cppi41dma 6 1
+ &cppi41dma 7 1 &cppi41dma 8 1
+ &cppi41dma 9 1 &cppi41dma 10 1
+ &cppi41dma 11 1 &cppi41dma 12 1
+ &cppi41dma 13 1 &cppi41dma 14 1>;
+ dma-names =
+ "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+ "rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+ "rx14", "rx15",
+ "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+ "tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+ "tx14", "tx15";
+ };
+
+ usb1: usb@47401800 {
+ compatible = "ti,musb-am33xx";
+ reg = <0x47401c00 0x400
+ 0x47401800 0x200>;
+ reg-names = "mc", "control";
+ interrupts = <19>;
+ interrupt-names = "mc";
+ dr_mode = "otg";
+ mentor,multipoint = <1>;
+ mentor,num-eps = <16>;
+ mentor,ram-bits = <12>;
+ mentor,power = <500>;
+ phys = <&usb1_phy>;
+
+ dmas = <&cppi41dma 15 0 &cppi41dma 16 0
+ &cppi41dma 17 0 &cppi41dma 18 0
+ &cppi41dma 19 0 &cppi41dma 20 0
+ &cppi41dma 21 0 &cppi41dma 22 0
+ &cppi41dma 23 0 &cppi41dma 24 0
+ &cppi41dma 25 0 &cppi41dma 26 0
+ &cppi41dma 27 0 &cppi41dma 28 0
+ &cppi41dma 29 0 &cppi41dma 15 1
+ &cppi41dma 16 1 &cppi41dma 17 1
+ &cppi41dma 18 1 &cppi41dma 19 1
+ &cppi41dma 20 1 &cppi41dma 21 1
+ &cppi41dma 22 1 &cppi41dma 23 1
+ &cppi41dma 24 1 &cppi41dma 25 1
+ &cppi41dma 26 1 &cppi41dma 27 1
+ &cppi41dma 28 1 &cppi41dma 29 1>;
+ dma-names =
+ "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+ "rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+ "rx14", "rx15",
+ "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+ "tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+ "tx14", "tx15";
+ };
+
+ cppi41dma: dma-controller@47402000 {
+ compatible = "ti,am3359-cppi41";
+ reg = <0x47400000 0x1000
+ 0x47402000 0x1000
+ 0x47403000 0x1000
+ 0x47404000 0x4000>;
+ reg-names = "glue", "controller", "scheduler", "queuemgr";
+ interrupts = <17>;
+ interrupt-names = "glue";
+ #dma-cells = <2>;
+ #dma-channels = <30>;
+ #dma-requests = <256>;
+ };
+ };
+
/*
- * See TRM "Table 1-317. L4LS Instance Summary", just deduct
- * 0x1000 from the 1-317 addresses to get the device address
+ * See TRM "Table 1-317. L4LS Instance Summary" for hints.
+ * It shows the module target agent registers though, so the
+ * actual device is typically 0x1000 before the target agent
+ * except in cases where the module is larger than 0x1000.
*/
l4ls: l4ls@48000000 {
compatible = "ti,dm814-l4ls", "simple-bus";
@@ -124,8 +237,8 @@
interrupts = <65>;
ti,spi-num-cs = <4>;
ti,hwmods = "mcspi1";
- dmas = <&edma 16 &edma 17
- &edma 18 &edma 19>;
+ dmas = <&edma 16 0 &edma 17 0
+ &edma 18 0 &edma 19 0>;
dma-names = "tx0", "rx0", "tx1", "rx1";
};
@@ -143,7 +256,7 @@
reg = <0x20000 0x2000>;
clock-frequency = <48000000>;
interrupts = <72>;
- dmas = <&edma 26 &edma 27>;
+ dmas = <&edma 26 0 &edma 27 0>;
dma-names = "tx", "rx";
};
@@ -153,7 +266,7 @@
reg = <0x22000 0x2000>;
clock-frequency = <48000000>;
interrupts = <73>;
- dmas = <&edma 28 &edma 29>;
+ dmas = <&edma 28 0 &edma 29 0>;
dma-names = "tx", "rx";
};
@@ -163,7 +276,7 @@
reg = <0x24000 0x2000>;
clock-frequency = <48000000>;
interrupts = <74>;
- dmas = <&edma 30 &edma 31>;
+ dmas = <&edma 30 0 &edma 31 0>;
dma-names = "tx", "rx";
};
@@ -181,12 +294,34 @@
ti,hwmods = "timer3";
};
+ mmc1: mmc@60000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc1";
+ dmas = <&edma 24 0
+ &edma 25 0>;
+ dma-names = "tx", "rx";
+ interrupts = <64>;
+ interrupt-parent = <&intc>;
+ reg = <0x60000 0x1000>;
+ };
+
+ mmc2: mmc@1d8000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc2";
+ dmas = <&edma 2 0
+ &edma 3 0>;
+ dma-names = "tx", "rx";
+ interrupts = <28>;
+ interrupt-parent = <&intc>;
+ reg = <0x1d8000 0x1000>;
+ };
+
control: control@140000 {
compatible = "ti,dm814-scm", "simple-bus";
- reg = <0x140000 0x16d000>;
+ reg = <0x140000 0x20000>;
#address-cells = <1>;
#size-cells = <1>;
- ranges = <0 0x160000 0x16d000>;
+ ranges = <0 0x140000 0x20000>;
scm_conf: scm_conf@0 {
compatible = "syscon";
@@ -203,19 +338,52 @@
};
};
+ usb_ctrl_mod: control@620 {
+ compatible = "ti,am335x-usb-ctrl-module";
+ reg = <0x620 0x10
+ 0x648 0x4>;
+ reg-names = "phy_ctrl", "wakeup";
+ };
+
+ edma_xbar: dma-router@f90 {
+ compatible = "ti,am335x-edma-crossbar";
+ reg = <0xf90 0x40>;
+ #dma-cells = <3>;
+ dma-requests = <32>;
+ dma-masters = <&edma>;
+ };
+
+ /*
+ * Note that silicon revision 2.1 and older
+ * require input enabled (bit 18 set) for all
+ * 3.3V I/Os to avoid cumulative hardware damage.
+ * For more info, see errata advisory 2.1.87.
+ * We leave bit 18 out of function-mask and rely
+ * on the bootloader for it.
+ */
pincntl: pinmux@800 {
compatible = "pinctrl-single";
- reg = <0x800 0xc38>;
+ reg = <0x800 0x438>;
#address-cells = <1>;
#size-cells = <0>;
pinctrl-single,register-width = <32>;
- pinctrl-single,function-mask = <0x300ff>;
+ pinctrl-single,function-mask = <0x307ff>;
+ };
+
+ usb1_phy: usb-phy@1b00 {
+ compatible = "ti,am335x-usb-phy";
+ reg = <0x1b00 0x100>;
+ reg-names = "phy";
+ ti,ctrl_mod = <&usb_ctrl_mod>;
};
};
prcm: prcm@180000 {
compatible = "ti,dm814-prcm", "simple-bus";
- reg = <0x180000 0x4000>;
+ reg = <0x180000 0x2000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x180000 0x2000>;
prcm_clocks: clocks {
#address-cells = <1>;
@@ -226,9 +394,13 @@
};
};
+ /* See TRM PLL_SUBSYS_BASE and "PLLSS Registers" */
pllss: pllss@1c5000 {
compatible = "ti,dm814-pllss", "simple-bus";
- reg = <0x1c5000 0x2000>;
+ reg = <0x1c5000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x1c5000 0x1000>;
pllss_clocks: clocks {
#address-cells = <1>;
@@ -254,13 +426,62 @@
reg = <0x48200000 0x1000>;
};
+ /* Board must configure evtmux with edma_xbar for EDMA */
+ mmc3: mmc@47810000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc3";
+ interrupts = <29>;
+ interrupt-parent = <&intc>;
+ reg = <0x47810000 0x1000>;
+ };
+
edma: edma@49000000 {
- compatible = "ti,edma3";
- ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
- reg = <0x49000000 0x10000>,
- <0x44e10f90 0x40>;
+ compatible = "ti,edma3-tpcc";
+ ti,hwmods = "tpcc";
+ reg = <0x49000000 0x10000>;
+ reg-names = "edma3_cc";
interrupts = <12 13 14>;
- #dma-cells = <1>;
+ interrupt-names = "edma3_ccint", "emda3_mperr",
+ "edma3_ccerrint";
+ dma-requests = <64>;
+ #dma-cells = <2>;
+
+ ti,tptcs = <&edma_tptc0 7>, <&edma_tptc1 5>,
+ <&edma_tptc2 3>, <&edma_tptc3 0>;
+
+ ti,edma-memcpy-channels = <20 21>;
+ };
+
+ edma_tptc0: tptc@49800000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc0";
+ reg = <0x49800000 0x100000>;
+ interrupts = <112>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc1: tptc@49900000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc1";
+ reg = <0x49900000 0x100000>;
+ interrupts = <113>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc2: tptc@49a00000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc2";
+ reg = <0x49a00000 0x100000>;
+ interrupts = <114>;
+ interrupt-names = "edma3_tcerrint";
+ };
+
+ edma_tptc3: tptc@49b00000 {
+ compatible = "ti,edma3-tptc";
+ ti,hwmods = "tptc3";
+ reg = <0x49b00000 0x100000>;
+ interrupts = <115>;
+ interrupt-names = "edma3_tcerrint";
};
/* See TRM "Table 1-318. L4HS Instance Summary" */
diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi
index eee636de4cd8..c3b8811a3e58 100644
--- a/arch/arm/boot/dts/dm816x.dtsi
+++ b/arch/arm/boot/dts/dm816x.dtsi
@@ -64,7 +64,6 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
- ti,hwmods = "l3_main";
prcm: prcm@48180000 {
compatible = "ti,dm816-prcm";
@@ -180,6 +179,8 @@
#address-cells = <2>;
#size-cells = <1>;
interrupts = <100>;
+ dmas = <&edma 52>;
+ dma-names = "rxtx";
gpmc,num-cs = <6>;
gpmc,num-waitpins = <2>;
};
@@ -227,6 +228,13 @@
};
};
+ spinbox: spinbox@480ca000 {
+ compatible = "ti,omap4-hwspinlock";
+ reg = <0x480ca000 0x2000>;
+ ti,hwmods = "spinbox";
+ #hwlock-cells = <1>;
+ };
+
mdio: mdio@4a100800 {
compatible = "ti,davinci_mdio";
#address-cells = <1>;
@@ -323,6 +331,7 @@
reg = <0x48044000 0x2000>;
interrupts = <92>;
ti,hwmods = "timer4";
+ ti,timer-pwm;
};
timer5: timer@48046000 {
@@ -330,6 +339,7 @@
reg = <0x48046000 0x2000>;
interrupts = <93>;
ti,hwmods = "timer5";
+ ti,timer-pwm;
};
timer6: timer@48048000 {
@@ -337,6 +347,7 @@
reg = <0x48048000 0x2000>;
interrupts = <94>;
ti,hwmods = "timer6";
+ ti,timer-pwm;
};
timer7: timer@4804a000 {
@@ -344,6 +355,7 @@
reg = <0x4804a000 0x2000>;
interrupts = <95>;
ti,hwmods = "timer7";
+ ti,timer-pwm;
};
uart1: uart@48020000 {
diff --git a/arch/arm/boot/dts/dove-cubox.dts b/arch/arm/boot/dts/dove-cubox.dts
index e6fa251e17b9..af3cb633135f 100644
--- a/arch/arm/boot/dts/dove-cubox.dts
+++ b/arch/arm/boot/dts/dove-cubox.dts
@@ -62,6 +62,10 @@
pinctrl-0 = <&pmx_gpio_19>;
pinctrl-names = "default";
};
+
+ gpu-subsystem {
+ status = "okay";
+ };
};
&uart0 { status = "okay"; };
@@ -74,6 +78,10 @@
reg = <1>;
};
+&gpu {
+ status = "okay";
+};
+
&i2c0 {
status = "okay";
clock-frequency = <100000>;
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index cd58c2e62757..698d58cea20d 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -33,6 +33,12 @@
marvell,tauros2-cache-features = <0>;
};
+ gpu-subsystem {
+ compatible = "marvell,dove-gpu-subsystem";
+ cores = <&gpu>;
+ status = "disabled";
+ };
+
i2c-mux {
compatible = "i2c-mux-pinctrl";
#address-cells = <1>;
@@ -460,6 +466,12 @@
#clock-cells = <1>;
};
+ divider_clk: core-clock@0064 {
+ compatible = "marvell,dove-divider-clock";
+ reg = <0x0064 0x8>;
+ #clock-cells = <1>;
+ };
+
pinctrl: pin-ctrl@0200 {
compatible = "marvell,dove-pinctrl";
reg = <0x0200 0x14>,
@@ -776,6 +788,16 @@
#address-cells = <1>;
#size-cells = <1>;
};
+
+ gpu: gpu@840000 {
+ clocks = <&divider_clk 1>;
+ clock-names = "core";
+ compatible = "vivante,gc";
+ interrupts = <48>;
+ power-domains = <&gpu_domain>;
+ reg = <0x840000 0x4000>;
+ status = "disabled";
+ };
};
};
};
diff --git a/arch/arm/boot/dts/dra62x-clocks.dtsi b/arch/arm/boot/dts/dra62x-clocks.dtsi
new file mode 100644
index 000000000000..6f98dc8df9dd
--- /dev/null
+++ b/arch/arm/boot/dts/dra62x-clocks.dtsi
@@ -0,0 +1,23 @@
+/*
+ * 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 "dm814x-clocks.dtsi"
+
+/*
+ * Compared to dm814x, dra62x has different shifts and more mux options.
+ * Please add the extra options for ysclk_14 and 16 if really needed.
+ */
+&timer1_fck {
+ clocks = <&sysclk18_ck &aud_clkin0_ck &aud_clkin1_ck
+ &aud_clkin2_ck &devosc_ck &auxosc_ck &tclkin_ck>;
+ ti,bit-shift = <4>;
+};
+
+&timer2_fck {
+ clocks = <&sysclk18_ck &aud_clkin0_ck &aud_clkin1_ck
+ &aud_clkin2_ck &devosc_ck &auxosc_ck &tclkin_ck>;
+ ti,bit-shift = <8>;
+};
diff --git a/arch/arm/boot/dts/dra62x-j5eco-evm.dts b/arch/arm/boot/dts/dra62x-j5eco-evm.dts
new file mode 100644
index 000000000000..79008069020d
--- /dev/null
+++ b/arch/arm/boot/dts/dra62x-j5eco-evm.dts
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+/dts-v1/;
+
+#include "dra62x.dtsi"
+
+/ {
+ model = "DRA62x J5 Eco EVM";
+ compatible = "ti,dra62x-j5eco-evm", "ti,dra62x", "ti,dm8148";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>; /* 1 GB */
+ };
+
+ /* MIC94060YC6 controlled by SD1_POW pin */
+ vmmcsd_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii";
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_pins>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ bus-width = <4>;
+ cd-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
+};
+
+&pincntl {
+ sd1_pins: pinmux_sd1_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0800, PIN_INPUT | 0x1) /* SD1_CLK */
+ DM814X_IOPAD(0x0804, PIN_INPUT_PULLUP | 0x1) /* SD1_CMD */
+ DM814X_IOPAD(0x0808, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[0] */
+ DM814X_IOPAD(0x080c, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[1] */
+ DM814X_IOPAD(0x0810, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[2] */
+ DM814X_IOPAD(0x0814, PIN_INPUT_PULLUP | 0x1) /* SD1_DAT[3] */
+ DM814X_IOPAD(0x0924, PIN_OUTPUT | 0x40) /* SD1_POW */
+ DM814X_IOPAD(0x093C, PIN_INPUT_PULLUP | 0x80) /* GP1[6] */
+ >;
+ };
+
+ usb0_pins: pinmux_usb0_pins {
+ pinctrl-single,pins = <
+ DM814X_IOPAD(0x0c34, PIN_OUTPUT | 0x1) /* USB0_DRVVBUS */
+ >;
+ };
+};
+
+/* USB0_ID pin state: SW10[1] = 0 cable detection, SW10[1] = 1 ID grounded */
+&usb0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_pins>;
+ dr_mode = "otg";
+};
+
+&usb1_phy {
+ status = "disabled";
+};
+
+&usb1 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/dra62x.dtsi b/arch/arm/boot/dts/dra62x.dtsi
new file mode 100644
index 000000000000..d3cbb4ea35a8
--- /dev/null
+++ b/arch/arm/boot/dts/dra62x.dtsi
@@ -0,0 +1,23 @@
+/*
+ * 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 "dm814x.dtsi"
+
+/ {
+ compatible = "ti,dra62x";
+};
+
+/* Compared to dm814x, dra62x has different offsets for Ethernet */
+&mac {
+ reg = <0x4a100000 0x800
+ 0x4a101200 0x100>;
+};
+
+&davinci_mdio {
+ reg = <0x4a101000 0x100>;
+};
+
+#include "dra62x-clocks.dtsi"
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 864f60020124..cfc24e52244e 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -154,100 +154,100 @@
vtt_pin: pinmux_vtt_pin {
pinctrl-single,pins = <
- 0x3b4 (PIN_OUTPUT | MUX_MODE14) /* spi1_cs1.gpio7_11 */
+ DRA7XX_CORE_IOPAD(0x37b4, PIN_OUTPUT | MUX_MODE14) /* spi1_cs1.gpio7_11 */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x400 (PIN_INPUT | MUX_MODE0) /* i2c1_sda */
- 0x404 (PIN_INPUT | MUX_MODE0) /* i2c1_scl */
+ DRA7XX_CORE_IOPAD(0x3800, PIN_INPUT | MUX_MODE0) /* i2c1_sda */
+ DRA7XX_CORE_IOPAD(0x3804, PIN_INPUT | MUX_MODE0) /* i2c1_scl */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
- 0x408 (PIN_INPUT | MUX_MODE0) /* i2c2_sda */
- 0x40c (PIN_INPUT | MUX_MODE0) /* i2c2_scl */
+ DRA7XX_CORE_IOPAD(0x3808, PIN_INPUT | MUX_MODE0) /* i2c2_sda */
+ DRA7XX_CORE_IOPAD(0x380c, PIN_INPUT | MUX_MODE0) /* i2c2_scl */
>;
};
i2c3_pins: pinmux_i2c3_pins {
pinctrl-single,pins = <
- 0x288 (PIN_INPUT | MUX_MODE9) /* gpio6_14.i2c3_sda */
- 0x28c (PIN_INPUT | MUX_MODE9) /* gpio6_15.i2c3_scl */
+ DRA7XX_CORE_IOPAD(0x3688, PIN_INPUT | MUX_MODE9) /* gpio6_14.i2c3_sda */
+ DRA7XX_CORE_IOPAD(0x368c, PIN_INPUT | MUX_MODE9) /* gpio6_15.i2c3_scl */
>;
};
mcspi1_pins: pinmux_mcspi1_pins {
pinctrl-single,pins = <
- 0x3a4 (PIN_INPUT | MUX_MODE0) /* spi1_sclk */
- 0x3a8 (PIN_INPUT | MUX_MODE0) /* spi1_d1 */
- 0x3ac (PIN_INPUT | MUX_MODE0) /* spi1_d0 */
- 0x3b0 (PIN_INPUT_SLEW | MUX_MODE0) /* spi1_cs0 */
- 0x3b8 (PIN_INPUT_SLEW | MUX_MODE6) /* spi1_cs2.hdmi1_hpd */
- 0x3bc (PIN_INPUT_SLEW | MUX_MODE6) /* spi1_cs3.hdmi1_cec */
+ DRA7XX_CORE_IOPAD(0x37a4, PIN_INPUT | MUX_MODE0) /* spi1_sclk */
+ DRA7XX_CORE_IOPAD(0x37a8, PIN_INPUT | MUX_MODE0) /* spi1_d1 */
+ DRA7XX_CORE_IOPAD(0x37ac, PIN_INPUT | MUX_MODE0) /* spi1_d0 */
+ DRA7XX_CORE_IOPAD(0x37b0, PIN_INPUT_SLEW | MUX_MODE0) /* spi1_cs0 */
+ DRA7XX_CORE_IOPAD(0x37b8, PIN_INPUT_SLEW | MUX_MODE6) /* spi1_cs2.hdmi1_hpd */
+ DRA7XX_CORE_IOPAD(0x37bc, PIN_INPUT_SLEW | MUX_MODE6) /* spi1_cs3.hdmi1_cec */
>;
};
mcspi2_pins: pinmux_mcspi2_pins {
pinctrl-single,pins = <
- 0x3c0 (PIN_INPUT | MUX_MODE0) /* spi2_sclk */
- 0x3c4 (PIN_INPUT_SLEW | MUX_MODE0) /* spi2_d1 */
- 0x3c8 (PIN_INPUT_SLEW | MUX_MODE0) /* spi2_d1 */
- 0x3cc (PIN_INPUT_SLEW | MUX_MODE0) /* spi2_cs0 */
+ DRA7XX_CORE_IOPAD(0x37c0, PIN_INPUT | MUX_MODE0) /* spi2_sclk */
+ DRA7XX_CORE_IOPAD(0x37c4, PIN_INPUT_SLEW | MUX_MODE0) /* spi2_d1 */
+ DRA7XX_CORE_IOPAD(0x37c8, PIN_INPUT_SLEW | MUX_MODE0) /* spi2_d1 */
+ DRA7XX_CORE_IOPAD(0x37cc, PIN_INPUT_SLEW | MUX_MODE0) /* spi2_cs0 */
>;
};
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x3e0 (PIN_INPUT_SLEW | MUX_MODE0) /* uart1_rxd */
- 0x3e4 (PIN_INPUT_SLEW | MUX_MODE0) /* uart1_txd */
- 0x3e8 (PIN_INPUT | MUX_MODE3) /* uart1_ctsn */
- 0x3ec (PIN_INPUT | MUX_MODE3) /* uart1_rtsn */
+ DRA7XX_CORE_IOPAD(0x37e0, PIN_INPUT_SLEW | MUX_MODE0) /* uart1_rxd */
+ DRA7XX_CORE_IOPAD(0x37e4, PIN_INPUT_SLEW | MUX_MODE0) /* uart1_txd */
+ DRA7XX_CORE_IOPAD(0x37e8, PIN_INPUT | MUX_MODE3) /* uart1_ctsn */
+ DRA7XX_CORE_IOPAD(0x37ec, PIN_INPUT | MUX_MODE3) /* uart1_rtsn */
>;
};
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0x3f0 (PIN_INPUT | MUX_MODE0) /* uart2_rxd */
- 0x3f4 (PIN_INPUT | MUX_MODE0) /* uart2_txd */
- 0x3f8 (PIN_INPUT | MUX_MODE0) /* uart2_ctsn */
- 0x3fc (PIN_INPUT | MUX_MODE0) /* uart2_rtsn */
+ DRA7XX_CORE_IOPAD(0x37f0, PIN_INPUT | MUX_MODE0) /* uart2_rxd */
+ DRA7XX_CORE_IOPAD(0x37f4, PIN_INPUT | MUX_MODE0) /* uart2_txd */
+ DRA7XX_CORE_IOPAD(0x37f8, PIN_INPUT | MUX_MODE0) /* uart2_ctsn */
+ DRA7XX_CORE_IOPAD(0x37fc, PIN_INPUT | MUX_MODE0) /* uart2_rtsn */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd */
- 0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd */
+ DRA7XX_CORE_IOPAD(0x3648, PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd */
+ DRA7XX_CORE_IOPAD(0x364c, PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd */
>;
};
qspi1_pins: pinmux_qspi1_pins {
pinctrl-single,pins = <
- 0x4c (PIN_INPUT | MUX_MODE1) /* gpmc_a3.qspi1_cs2 */
- 0x50 (PIN_INPUT | MUX_MODE1) /* gpmc_a4.qspi1_cs3 */
- 0x74 (PIN_INPUT | MUX_MODE1) /* gpmc_a13.qspi1_rtclk */
- 0x78 (PIN_INPUT | MUX_MODE1) /* gpmc_a14.qspi1_d3 */
- 0x7c (PIN_INPUT | MUX_MODE1) /* gpmc_a15.qspi1_d2 */
- 0x80 (PIN_INPUT | MUX_MODE1) /* gpmc_a16.qspi1_d1 */
- 0x84 (PIN_INPUT | MUX_MODE1) /* gpmc_a17.qspi1_d0 */
- 0x88 (PIN_INPUT | MUX_MODE1) /* qpmc_a18.qspi1_sclk */
- 0xb8 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs2.qspi1_cs0 */
- 0xbc (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs3.qspi1_cs1 */
+ DRA7XX_CORE_IOPAD(0x344c, PIN_INPUT | MUX_MODE1) /* gpmc_a3.qspi1_cs2 */
+ DRA7XX_CORE_IOPAD(0x3450, PIN_INPUT | MUX_MODE1) /* gpmc_a4.qspi1_cs3 */
+ DRA7XX_CORE_IOPAD(0x3474, PIN_INPUT | MUX_MODE1) /* gpmc_a13.qspi1_rtclk */
+ DRA7XX_CORE_IOPAD(0x3478, PIN_INPUT | MUX_MODE1) /* gpmc_a14.qspi1_d3 */
+ DRA7XX_CORE_IOPAD(0x347c, PIN_INPUT | MUX_MODE1) /* gpmc_a15.qspi1_d2 */
+ DRA7XX_CORE_IOPAD(0x3480, PIN_INPUT | MUX_MODE1) /* gpmc_a16.qspi1_d1 */
+ DRA7XX_CORE_IOPAD(0x3484, PIN_INPUT | MUX_MODE1) /* gpmc_a17.qspi1_d0 */
+ DRA7XX_CORE_IOPAD(0x3488, PIN_INPUT | MUX_MODE1) /* qpmc_a18.qspi1_sclk */
+ DRA7XX_CORE_IOPAD(0x34b8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs2.qspi1_cs0 */
+ DRA7XX_CORE_IOPAD(0x34bc, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs3.qspi1_cs1 */
>;
};
usb1_pins: pinmux_usb1_pins {
pinctrl-single,pins = <
- 0x280 (PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
+ DRA7XX_CORE_IOPAD(0x3680, PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
>;
};
usb2_pins: pinmux_usb2_pins {
pinctrl-single,pins = <
- 0x284 (PIN_INPUT_SLEW | MUX_MODE0) /* usb2_drvvbus */
+ DRA7XX_CORE_IOPAD(0x3684, PIN_INPUT_SLEW | MUX_MODE0) /* usb2_drvvbus */
>;
};
@@ -257,60 +257,60 @@
* SW5.9 (GPMC_WPN) = LOW
* SW5.1 (NAND_BOOTn) = HIGH */
pinctrl-single,pins = <
- 0x0 (PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
- 0x4 (PIN_INPUT | MUX_MODE0) /* gpmc_ad1 */
- 0x8 (PIN_INPUT | MUX_MODE0) /* gpmc_ad2 */
- 0xc (PIN_INPUT | MUX_MODE0) /* gpmc_ad3 */
- 0x10 (PIN_INPUT | MUX_MODE0) /* gpmc_ad4 */
- 0x14 (PIN_INPUT | MUX_MODE0) /* gpmc_ad5 */
- 0x18 (PIN_INPUT | MUX_MODE0) /* gpmc_ad6 */
- 0x1c (PIN_INPUT | MUX_MODE0) /* gpmc_ad7 */
- 0x20 (PIN_INPUT | MUX_MODE0) /* gpmc_ad8 */
- 0x24 (PIN_INPUT | MUX_MODE0) /* gpmc_ad9 */
- 0x28 (PIN_INPUT | MUX_MODE0) /* gpmc_ad10 */
- 0x2c (PIN_INPUT | MUX_MODE0) /* gpmc_ad11 */
- 0x30 (PIN_INPUT | MUX_MODE0) /* gpmc_ad12 */
- 0x34 (PIN_INPUT | MUX_MODE0) /* gpmc_ad13 */
- 0x38 (PIN_INPUT | MUX_MODE0) /* gpmc_ad14 */
- 0x3c (PIN_INPUT | MUX_MODE0) /* gpmc_ad15 */
- 0xd8 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0 */
- 0xcc (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen */
- 0xb4 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0 */
- 0xc4 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale */
- 0xc8 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren */
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle */
+ DRA7XX_CORE_IOPAD(0x3400, PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
+ DRA7XX_CORE_IOPAD(0x3404, PIN_INPUT | MUX_MODE0) /* gpmc_ad1 */
+ DRA7XX_CORE_IOPAD(0x3408, PIN_INPUT | MUX_MODE0) /* gpmc_ad2 */
+ DRA7XX_CORE_IOPAD(0x340c, PIN_INPUT | MUX_MODE0) /* gpmc_ad3 */
+ DRA7XX_CORE_IOPAD(0x3410, PIN_INPUT | MUX_MODE0) /* gpmc_ad4 */
+ DRA7XX_CORE_IOPAD(0x3414, PIN_INPUT | MUX_MODE0) /* gpmc_ad5 */
+ DRA7XX_CORE_IOPAD(0x3418, PIN_INPUT | MUX_MODE0) /* gpmc_ad6 */
+ DRA7XX_CORE_IOPAD(0x341c, PIN_INPUT | MUX_MODE0) /* gpmc_ad7 */
+ DRA7XX_CORE_IOPAD(0x3420, PIN_INPUT | MUX_MODE0) /* gpmc_ad8 */
+ DRA7XX_CORE_IOPAD(0x3424, PIN_INPUT | MUX_MODE0) /* gpmc_ad9 */
+ DRA7XX_CORE_IOPAD(0x3428, PIN_INPUT | MUX_MODE0) /* gpmc_ad10 */
+ DRA7XX_CORE_IOPAD(0x342c, PIN_INPUT | MUX_MODE0) /* gpmc_ad11 */
+ DRA7XX_CORE_IOPAD(0x3430, PIN_INPUT | MUX_MODE0) /* gpmc_ad12 */
+ DRA7XX_CORE_IOPAD(0x3434, PIN_INPUT | MUX_MODE0) /* gpmc_ad13 */
+ DRA7XX_CORE_IOPAD(0x3438, PIN_INPUT | MUX_MODE0) /* gpmc_ad14 */
+ DRA7XX_CORE_IOPAD(0x343c, PIN_INPUT | MUX_MODE0) /* gpmc_ad15 */
+ DRA7XX_CORE_IOPAD(0x34d8, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0 */
+ DRA7XX_CORE_IOPAD(0x34cc, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen */
+ DRA7XX_CORE_IOPAD(0x34b4, PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0 */
+ DRA7XX_CORE_IOPAD(0x34c4, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale */
+ DRA7XX_CORE_IOPAD(0x34c8, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren */
+ DRA7XX_CORE_IOPAD(0x34d0, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle */
>;
};
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1 */
- 0x250 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txc.rgmii0_txc */
- 0x254 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txctl.rgmii0_txctl */
- 0x258 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_td3.rgmii0_txd3 */
- 0x25c (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd2.rgmii0_txd2 */
- 0x260 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd1.rgmii0_txd1 */
- 0x264 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd0.rgmii0_txd0 */
- 0x268 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxc.rgmii0_rxc */
- 0x26c (PIN_INPUT | MUX_MODE0) /* rgmii0_rxctl.rgmii0_rxctl */
- 0x270 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd3.rgmii0_rxd3 */
- 0x274 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd2.rgmii0_rxd2 */
- 0x278 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd1.rgmii0_rxd1 */
- 0x27c (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd0.rgmii0_rxd0 */
+ DRA7XX_CORE_IOPAD(0x3650, PIN_OUTPUT | MUX_MODE0) /* rgmii0_txc.rgmii0_txc */
+ DRA7XX_CORE_IOPAD(0x3654, PIN_OUTPUT | MUX_MODE0) /* rgmii0_txctl.rgmii0_txctl */
+ DRA7XX_CORE_IOPAD(0x3658, PIN_OUTPUT | MUX_MODE0) /* rgmii0_td3.rgmii0_txd3 */
+ DRA7XX_CORE_IOPAD(0x365c, PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd2.rgmii0_txd2 */
+ DRA7XX_CORE_IOPAD(0x3660, PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd1.rgmii0_txd1 */
+ DRA7XX_CORE_IOPAD(0x3664, PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd0.rgmii0_txd0 */
+ DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT | MUX_MODE0) /* rgmii0_rxc.rgmii0_rxc */
+ DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT | MUX_MODE0) /* rgmii0_rxctl.rgmii0_rxctl */
+ DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT | MUX_MODE0) /* rgmii0_rxd3.rgmii0_rxd3 */
+ DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT | MUX_MODE0) /* rgmii0_rxd2.rgmii0_rxd2 */
+ DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT | MUX_MODE0) /* rgmii0_rxd1.rgmii0_rxd1 */
+ DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT | MUX_MODE0) /* rgmii0_rxd0.rgmii0_rxd0 */
/* Slave 2 */
- 0x198 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_txc */
- 0x19c (PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
- 0x1a0 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
- 0x1a4 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
- 0x1a8 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
- 0x1ac (PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
- 0x1b0 (PIN_INPUT | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
- 0x1b4 (PIN_INPUT | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
- 0x1b8 (PIN_INPUT | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
- 0x1bc (PIN_INPUT | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
- 0x1c0 (PIN_INPUT | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
- 0x1c4 (PIN_INPUT | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
+ DRA7XX_CORE_IOPAD(0x3598, PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_txc */
+ DRA7XX_CORE_IOPAD(0x359c, PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
+ DRA7XX_CORE_IOPAD(0x35a0, PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
+ DRA7XX_CORE_IOPAD(0x35a4, PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
+ DRA7XX_CORE_IOPAD(0x35a8, PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
+ DRA7XX_CORE_IOPAD(0x35ac, PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
+ DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
+ DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
+ DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
+ DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
+ DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
+ DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
>;
};
@@ -318,85 +318,85 @@
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 */
- 0x250 (MUX_MODE15)
- 0x254 (MUX_MODE15)
- 0x258 (MUX_MODE15)
- 0x25c (MUX_MODE15)
- 0x260 (MUX_MODE15)
- 0x264 (MUX_MODE15)
- 0x268 (MUX_MODE15)
- 0x26c (MUX_MODE15)
- 0x270 (MUX_MODE15)
- 0x274 (MUX_MODE15)
- 0x278 (MUX_MODE15)
- 0x27c (MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3650, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3654, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3658, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x365c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3660, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3664, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3668, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x366c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3670, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3674, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3678, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x367c, MUX_MODE15)
/* Slave 2 */
- 0x198 (MUX_MODE15)
- 0x19c (MUX_MODE15)
- 0x1a0 (MUX_MODE15)
- 0x1a4 (MUX_MODE15)
- 0x1a8 (MUX_MODE15)
- 0x1ac (MUX_MODE15)
- 0x1b0 (MUX_MODE15)
- 0x1b4 (MUX_MODE15)
- 0x1b8 (MUX_MODE15)
- 0x1bc (MUX_MODE15)
- 0x1c0 (MUX_MODE15)
- 0x1c4 (MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3598, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x359c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a0, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a4, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a8, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35ac, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b0, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b4, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b8, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35bc, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c0, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c4, MUX_MODE15)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
- 0x23c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_d.mdio_d */
- 0x240 (PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ DRA7XX_CORE_IOPAD(0x363c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_d.mdio_d */
+ DRA7XX_CORE_IOPAD(0x3640, PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
- 0x23c (MUX_MODE15)
- 0x240 (MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x363c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3640, MUX_MODE15)
>;
};
dcan1_pins_default: dcan1_pins_default {
pinctrl-single,pins = <
- 0x3d0 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
- 0x418 (PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
+ DRA7XX_CORE_IOPAD(0x37d0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+ DRA7XX_CORE_IOPAD(0x3818, PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
>;
};
dcan1_pins_sleep: dcan1_pins_sleep {
pinctrl-single,pins = <
- 0x3d0 (MUX_MODE15 | PULL_UP) /* dcan1_tx.off */
- 0x418 (MUX_MODE15 | PULL_UP) /* wakeup0.off */
+ DRA7XX_CORE_IOPAD(0x37d0, MUX_MODE15 | PULL_UP) /* dcan1_tx.off */
+ DRA7XX_CORE_IOPAD(0x3818, MUX_MODE15 | PULL_UP) /* wakeup0.off */
>;
};
atl_pins: pinmux_atl_pins {
pinctrl-single,pins = <
- 0x298 (PIN_OUTPUT | MUX_MODE5) /* xref_clk1.atl_clk1 */
- 0x29c (PIN_OUTPUT | MUX_MODE5) /* xref_clk2.atl_clk2 */
+ DRA7XX_CORE_IOPAD(0x3698, PIN_OUTPUT | MUX_MODE5) /* xref_clk1.atl_clk1 */
+ DRA7XX_CORE_IOPAD(0x369c, PIN_OUTPUT | MUX_MODE5) /* xref_clk2.atl_clk2 */
>;
};
mcasp3_pins: pinmux_mcasp3_pins {
pinctrl-single,pins = <
- 0x324 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx */
- 0x328 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx */
- 0x32c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0 */
- 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1 */
+ DRA7XX_CORE_IOPAD(0x3724, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx */
+ DRA7XX_CORE_IOPAD(0x3728, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx */
+ DRA7XX_CORE_IOPAD(0x372c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0 */
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1 */
>;
};
mcasp3_sleep_pins: pinmux_mcasp3_sleep_pins {
pinctrl-single,pins = <
- 0x324 (MUX_MODE15)
- 0x328 (MUX_MODE15)
- 0x32c (MUX_MODE15)
- 0x330 (MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3724, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3728, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x372c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3730, MUX_MODE15)
>;
};
};
@@ -504,6 +504,7 @@
regulator-max-microvolt = <1050000>;
regulator-always-on;
regulator-boot-on;
+ regulator-allow-bypass;
};
ldoln_reg: ldoln {
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index fe99231cbde5..c4d9175b90dc 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -41,6 +41,7 @@
ethernet1 = &cpsw_emac1;
d_can0 = &dcan1;
d_can1 = &dcan2;
+ spi0 = &qspi;
};
timer {
@@ -1153,8 +1154,10 @@
qspi: qspi@4b300000 {
compatible = "ti,dra7xxx-qspi";
- reg = <0x4b300000 0x100>;
- reg-names = "qspi_base";
+ reg = <0x4b300000 0x100>,
+ <0x5c000000 0x4000000>;
+ reg-names = "qspi_base", "qspi_mmap";
+ syscon-chipselects = <&scm_conf 0x558>;
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "qspi";
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index d6104d5f0c01..00b12002c07c 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -142,158 +142,158 @@
&dra7_pmx_core {
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x400 (PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */
- 0x404 (PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */
+ DRA7XX_CORE_IOPAD(0x3800, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */
+ DRA7XX_CORE_IOPAD(0x3804, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */
>;
};
i2c5_pins: pinmux_i2c5_pins {
pinctrl-single,pins = <
- 0x2b4 (PIN_INPUT | MUX_MODE10) /* mcasp1_axr0.i2c5_sda */
- 0x2b8 (PIN_INPUT | MUX_MODE10) /* mcasp1_axr1.i2c5_scl */
+ DRA7XX_CORE_IOPAD(0x36b4, PIN_INPUT | MUX_MODE10) /* mcasp1_axr0.i2c5_sda */
+ DRA7XX_CORE_IOPAD(0x36b8, PIN_INPUT | MUX_MODE10) /* mcasp1_axr1.i2c5_scl */
>;
};
i2c5_pins: pinmux_i2c5_pins {
pinctrl-single,pins = <
- 0x2b4 (PIN_INPUT | MUX_MODE10) /* mcasp1_axr0.i2c5_sda */
- 0x2b8 (PIN_INPUT | MUX_MODE10) /* mcasp1_axr1.i2c5_scl */
+ DRA7XX_CORE_IOPAD(0x36b4, PIN_INPUT | MUX_MODE10) /* mcasp1_axr0.i2c5_sda */
+ DRA7XX_CORE_IOPAD(0x36b8, PIN_INPUT | MUX_MODE10) /* mcasp1_axr1.i2c5_scl */
>;
};
nand_default: nand_default {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
- 0x4 (PIN_INPUT | MUX_MODE0) /* gpmc_ad1 */
- 0x8 (PIN_INPUT | MUX_MODE0) /* gpmc_ad2 */
- 0xc (PIN_INPUT | MUX_MODE0) /* gpmc_ad3 */
- 0x10 (PIN_INPUT | MUX_MODE0) /* gpmc_ad4 */
- 0x14 (PIN_INPUT | MUX_MODE0) /* gpmc_ad5 */
- 0x18 (PIN_INPUT | MUX_MODE0) /* gpmc_ad6 */
- 0x1c (PIN_INPUT | MUX_MODE0) /* gpmc_ad7 */
- 0x20 (PIN_INPUT | MUX_MODE0) /* gpmc_ad8 */
- 0x24 (PIN_INPUT | MUX_MODE0) /* gpmc_ad9 */
- 0x28 (PIN_INPUT | MUX_MODE0) /* gpmc_ad10 */
- 0x2c (PIN_INPUT | MUX_MODE0) /* gpmc_ad11 */
- 0x30 (PIN_INPUT | MUX_MODE0) /* gpmc_ad12 */
- 0x34 (PIN_INPUT | MUX_MODE0) /* gpmc_ad13 */
- 0x38 (PIN_INPUT | MUX_MODE0) /* gpmc_ad14 */
- 0x3c (PIN_INPUT | MUX_MODE0) /* gpmc_ad15 */
- 0xb4 (PIN_OUTPUT | MUX_MODE0) /* gpmc_cs0 */
- 0xc4 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale */
- 0xcc (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen */
- 0xc8 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren */
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* gpmc_ben0 */
- 0xd8 (PIN_INPUT | MUX_MODE0) /* gpmc_wait0 */
+ DRA7XX_CORE_IOPAD(0x3400, PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
+ DRA7XX_CORE_IOPAD(0x3404, PIN_INPUT | MUX_MODE0) /* gpmc_ad1 */
+ DRA7XX_CORE_IOPAD(0x3408, PIN_INPUT | MUX_MODE0) /* gpmc_ad2 */
+ DRA7XX_CORE_IOPAD(0x340c, PIN_INPUT | MUX_MODE0) /* gpmc_ad3 */
+ DRA7XX_CORE_IOPAD(0x3410, PIN_INPUT | MUX_MODE0) /* gpmc_ad4 */
+ DRA7XX_CORE_IOPAD(0x3414, PIN_INPUT | MUX_MODE0) /* gpmc_ad5 */
+ DRA7XX_CORE_IOPAD(0x3418, PIN_INPUT | MUX_MODE0) /* gpmc_ad6 */
+ DRA7XX_CORE_IOPAD(0x341c, PIN_INPUT | MUX_MODE0) /* gpmc_ad7 */
+ DRA7XX_CORE_IOPAD(0x3420, PIN_INPUT | MUX_MODE0) /* gpmc_ad8 */
+ DRA7XX_CORE_IOPAD(0x3424, PIN_INPUT | MUX_MODE0) /* gpmc_ad9 */
+ DRA7XX_CORE_IOPAD(0x3428, PIN_INPUT | MUX_MODE0) /* gpmc_ad10 */
+ DRA7XX_CORE_IOPAD(0x342c, PIN_INPUT | MUX_MODE0) /* gpmc_ad11 */
+ DRA7XX_CORE_IOPAD(0x3430, PIN_INPUT | MUX_MODE0) /* gpmc_ad12 */
+ DRA7XX_CORE_IOPAD(0x3434, PIN_INPUT | MUX_MODE0) /* gpmc_ad13 */
+ DRA7XX_CORE_IOPAD(0x3438, PIN_INPUT | MUX_MODE0) /* gpmc_ad14 */
+ DRA7XX_CORE_IOPAD(0x343c, PIN_INPUT | MUX_MODE0) /* gpmc_ad15 */
+ DRA7XX_CORE_IOPAD(0x34b4, PIN_OUTPUT | MUX_MODE0) /* gpmc_cs0 */
+ DRA7XX_CORE_IOPAD(0x34c4, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale */
+ DRA7XX_CORE_IOPAD(0x34cc, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen */
+ DRA7XX_CORE_IOPAD(0x34c8, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren */
+ DRA7XX_CORE_IOPAD(0x34d0, PIN_OUTPUT | MUX_MODE0) /* gpmc_ben0 */
+ DRA7XX_CORE_IOPAD(0x34d8, PIN_INPUT | MUX_MODE0) /* gpmc_wait0 */
>;
};
usb1_pins: pinmux_usb1_pins {
pinctrl-single,pins = <
- 0x280 (PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
+ DRA7XX_CORE_IOPAD(0x3680, PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
>;
};
usb2_pins: pinmux_usb2_pins {
pinctrl-single,pins = <
- 0x284 (PIN_INPUT_SLEW | MUX_MODE0) /* usb2_drvvbus */
+ DRA7XX_CORE_IOPAD(0x3684, PIN_INPUT_SLEW | MUX_MODE0) /* usb2_drvvbus */
>;
};
tps65917_pins_default: tps65917_pins_default {
pinctrl-single,pins = <
- 0x424 (PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
+ DRA7XX_CORE_IOPAD(0x3824, PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
>;
};
mmc1_pins_default: mmc1_pins_default {
pinctrl-single,pins = <
- 0x36c (PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
- 0x354 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
- 0x358 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
- 0x35c (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
- 0x360 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
- 0x364 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
- 0x368 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
+ DRA7XX_CORE_IOPAD(0x376c, PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
+ DRA7XX_CORE_IOPAD(0x3754, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
+ DRA7XX_CORE_IOPAD(0x3758, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
+ DRA7XX_CORE_IOPAD(0x375c, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
+ DRA7XX_CORE_IOPAD(0x3760, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
+ DRA7XX_CORE_IOPAD(0x3764, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
+ DRA7XX_CORE_IOPAD(0x3768, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
>;
};
mmc2_pins_default: mmc2_pins_default {
pinctrl-single,pins = <
- 0x9c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
- 0xb0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
- 0xa0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
- 0xa4 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
- 0xa8 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
- 0xac (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
- 0x8c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
- 0x90 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
- 0x94 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
- 0x98 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+ DRA7XX_CORE_IOPAD(0x349c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+ DRA7XX_CORE_IOPAD(0x34b0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+ DRA7XX_CORE_IOPAD(0x34a0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+ DRA7XX_CORE_IOPAD(0x34a4, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+ DRA7XX_CORE_IOPAD(0x34a8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+ DRA7XX_CORE_IOPAD(0x34ac, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+ DRA7XX_CORE_IOPAD(0x348c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+ DRA7XX_CORE_IOPAD(0x3490, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+ DRA7XX_CORE_IOPAD(0x3494, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+ DRA7XX_CORE_IOPAD(0x3498, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
>;
};
dcan1_pins_default: dcan1_pins_default {
pinctrl-single,pins = <
- 0x3d0 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
- 0x418 (PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
+ DRA7XX_CORE_IOPAD(0x37d0, PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+ DRA7XX_CORE_IOPAD(0x3818, PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
>;
};
dcan1_pins_sleep: dcan1_pins_sleep {
pinctrl-single,pins = <
- 0x3d0 (MUX_MODE15 | PULL_UP) /* dcan1_tx.off */
- 0x418 (MUX_MODE15 | PULL_UP) /* wakeup0.off */
+ DRA7XX_CORE_IOPAD(0x37d0, MUX_MODE15 | PULL_UP) /* dcan1_tx.off */
+ DRA7XX_CORE_IOPAD(0x3818, MUX_MODE15 | PULL_UP) /* wakeup0.off */
>;
};
qspi1_pins: pinmux_qspi1_pins {
pinctrl-single,pins = <
- 0x74 (PIN_OUTPUT | MUX_MODE1) /* gpmc_a13.qspi1_rtclk */
- 0x78 (PIN_INPUT | MUX_MODE1) /* gpmc_a14.qspi1_d3 */
- 0x7c (PIN_INPUT | MUX_MODE1) /* gpmc_a15.qspi1_d2 */
- 0x80 (PIN_INPUT | MUX_MODE1) /* gpmc_a16.qspi1_d1 */
- 0x84 (PIN_INPUT | MUX_MODE1) /* gpmc_a17.qspi1_d0 */
- 0x88 (PIN_OUTPUT | MUX_MODE1) /* qpmc_a18.qspi1_sclk */
- 0xb8 (PIN_OUTPUT | MUX_MODE1) /* gpmc_cs2.qspi1_cs0 */
+ DRA7XX_CORE_IOPAD(0x3474, PIN_OUTPUT | MUX_MODE1) /* gpmc_a13.qspi1_rtclk */
+ DRA7XX_CORE_IOPAD(0x3478, PIN_INPUT | MUX_MODE1) /* gpmc_a14.qspi1_d3 */
+ DRA7XX_CORE_IOPAD(0x347c, PIN_INPUT | MUX_MODE1) /* gpmc_a15.qspi1_d2 */
+ DRA7XX_CORE_IOPAD(0x3480, PIN_INPUT | MUX_MODE1) /* gpmc_a16.qspi1_d1 */
+ DRA7XX_CORE_IOPAD(0x3484, PIN_INPUT | MUX_MODE1) /* gpmc_a17.qspi1_d0 */
+ DRA7XX_CORE_IOPAD(0x3488, PIN_OUTPUT | MUX_MODE1) /* qpmc_a18.qspi1_sclk */
+ DRA7XX_CORE_IOPAD(0x34b8, PIN_OUTPUT | MUX_MODE1) /* gpmc_cs2.qspi1_cs0 */
>;
};
hdmi_pins: pinmux_hdmi_pins {
pinctrl-single,pins = <
- 0x408 (PIN_INPUT | MUX_MODE1) /* i2c2_sda.hdmi1_ddc_scl */
- 0x40c (PIN_INPUT | MUX_MODE1) /* i2c2_scl.hdmi1_ddc_sda */
+ DRA7XX_CORE_IOPAD(0x3808, PIN_INPUT | MUX_MODE1) /* i2c2_sda.hdmi1_ddc_scl */
+ DRA7XX_CORE_IOPAD(0x380c, PIN_INPUT | MUX_MODE1) /* i2c2_scl.hdmi1_ddc_sda */
>;
};
tpd12s015_pins: pinmux_tpd12s015_pins {
pinctrl-single,pins = <
- 0x3b8 (PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
+ DRA7XX_CORE_IOPAD(0x37b8, PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
>;
};
atl_pins: pinmux_atl_pins {
pinctrl-single,pins = <
- 0x298 (PIN_OUTPUT | MUX_MODE5) /* xref_clk1.atl_clk1 */
- 0x29c (PIN_OUTPUT | MUX_MODE5) /* xref_clk2.atl_clk2 */
+ DRA7XX_CORE_IOPAD(0x3698, PIN_OUTPUT | MUX_MODE5) /* xref_clk1.atl_clk1 */
+ DRA7XX_CORE_IOPAD(0x369c, PIN_OUTPUT | MUX_MODE5) /* xref_clk2.atl_clk2 */
>;
};
mcasp3_pins: pinmux_mcasp3_pins {
pinctrl-single,pins = <
- 0x324 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx */
- 0x328 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx */
- 0x32c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0 */
- 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1 */
+ DRA7XX_CORE_IOPAD(0x3724, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx */
+ DRA7XX_CORE_IOPAD(0x3728, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx */
+ DRA7XX_CORE_IOPAD(0x372c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0 */
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1 */
>;
};
mcasp3_sleep_pins: pinmux_mcasp3_sleep_pins {
pinctrl-single,pins = <
- 0x324 (PIN_INPUT_PULLDOWN | MUX_MODE15)
- 0x328 (PIN_INPUT_PULLDOWN | MUX_MODE15)
- 0x32c (PIN_INPUT_PULLDOWN | MUX_MODE15)
- 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT_PULLDOWN | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT_PULLDOWN | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x372c, PIN_INPUT_PULLDOWN | MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT_PULLDOWN | MUX_MODE15)
>;
};
};
@@ -373,6 +373,7 @@
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
+ regulator-allow-bypass;
};
ldo2_reg: ldo2 {
@@ -380,6 +381,7 @@
regulator-name = "ldo2";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
+ regulator-allow-bypass;
};
ldo3_reg: ldo3 {
@@ -478,6 +480,8 @@
&uart1 {
status = "okay";
+ interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+ <&dra7_pmx_core 0x3e0>;
};
&elm {
@@ -627,18 +631,18 @@
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 2 */
- 0x198 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_txc */
- 0x19c (PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
- 0x1a0 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
- 0x1a4 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
- 0x1a8 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
- 0x1ac (PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
- 0x1b0 (PIN_INPUT | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
- 0x1b4 (PIN_INPUT | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
- 0x1b8 (PIN_INPUT | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
- 0x1bc (PIN_INPUT | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
- 0x1c0 (PIN_INPUT | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
- 0x1c4 (PIN_INPUT | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
+ DRA7XX_CORE_IOPAD(0x3598, PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_txc */
+ DRA7XX_CORE_IOPAD(0x359c, PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
+ DRA7XX_CORE_IOPAD(0x35a0, PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
+ DRA7XX_CORE_IOPAD(0x35a4, PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
+ DRA7XX_CORE_IOPAD(0x35a8, PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
+ DRA7XX_CORE_IOPAD(0x35ac, PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
+ DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
+ DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
+ DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
+ DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
+ DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
+ DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
>;
};
@@ -646,33 +650,33 @@
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 2 */
- 0x198 (MUX_MODE15)
- 0x19c (MUX_MODE15)
- 0x1a0 (MUX_MODE15)
- 0x1a4 (MUX_MODE15)
- 0x1a8 (MUX_MODE15)
- 0x1ac (MUX_MODE15)
- 0x1b0 (MUX_MODE15)
- 0x1b4 (MUX_MODE15)
- 0x1b8 (MUX_MODE15)
- 0x1bc (MUX_MODE15)
- 0x1c0 (MUX_MODE15)
- 0x1c4 (MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3598, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x359c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a0, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a4, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35a8, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35ac, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b0, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b4, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35b8, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35bc, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c0, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x35c4, MUX_MODE15)
>;
};
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
- 0x23c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_d.mdio_d */
- 0x240 (PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ DRA7XX_CORE_IOPAD(0x363c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_d.mdio_d */
+ DRA7XX_CORE_IOPAD(0x3640, PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
- 0x23c (MUX_MODE15)
- 0x240 (MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x363c, MUX_MODE15)
+ DRA7XX_CORE_IOPAD(0x3640, MUX_MODE15)
>;
};
};
diff --git a/arch/arm/boot/dts/ea3250.dts b/arch/arm/boot/dts/ea3250.dts
index a4ba31b23c88..a4a281fe82af 100644
--- a/arch/arm/boot/dts/ea3250.dts
+++ b/arch/arm/boot/dts/ea3250.dts
@@ -12,7 +12,7 @@
*/
/dts-v1/;
-/include/ "lpc32xx.dtsi"
+#include "lpc32xx.dtsi"
/ {
model = "Embedded Artists LPC3250 board based on NXP LPC3250";
@@ -22,7 +22,7 @@
memory {
device_type = "memory";
- reg = <0 0x4000000>;
+ reg = <0x80000000 0x4000000>;
};
ahb {
@@ -31,19 +31,6 @@
use-iram;
};
- /* Here, choose exactly one from: ohci, usbd */
- ohci@31020000 {
- transceiver = <&isp1301>;
- status = "okay";
- };
-
-/*
- usbd@31020000 {
- transceiver = <&isp1301>;
- status = "okay";
- };
-*/
-
/* 128MB Flash via SLC NAND controller */
slc: flash@20020000 {
status = "okay";
@@ -130,15 +117,6 @@
clock-frequency = <100000>;
};
- i2cusb: i2c@31020300 {
- clock-frequency = <100000>;
-
- isp1301: usb-transceiver@2d {
- compatible = "nxp,isp1301";
- reg = <0x2d>;
- };
- };
-
sd@20098000 {
wp-gpios = <&pca9532 5 0>;
cd-gpios = <&pca9532 4 0>;
@@ -279,3 +257,18 @@
};
};
};
+
+/* Here, choose exactly one from: ohci, usbd */
+&ohci /* &usbd */ {
+ transceiver = <&isp1301>;
+ status = "okay";
+};
+
+&i2cusb {
+ clock-frequency = <100000>;
+
+ isp1301: usb-transceiver@2d {
+ compatible = "nxp,isp1301";
+ reg = <0x2d>;
+ };
+};
diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi
index edad0c4eea35..57795da616cb 100644
--- a/arch/arm/boot/dts/emev2.dtsi
+++ b/arch/arm/boot/dts/emev2.dtsi
@@ -44,7 +44,7 @@
};
gic: interrupt-controller@e0020000 {
- compatible = "arm,cortex-a9-gic";
+ compatible = "arm,pl390";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0xe0028000 0x1000>,
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 2f30d632f1cc..18e3deffbf48 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -152,6 +152,20 @@
interrupt-parent = <&gic>;
};
+ poweroff: syscon-poweroff {
+ compatible = "syscon-poweroff";
+ regmap = <&pmu_system_controller>;
+ offset = <0x330C>; /* PS_HOLD_CONTROL */
+ mask = <0x5200>; /* Reset value */
+ };
+
+ reboot: syscon-reboot {
+ compatible = "syscon-reboot";
+ regmap = <&pmu_system_controller>;
+ offset = <0x0400>; /* SWRESET */
+ mask = <0x1>;
+ };
+
mipi_phy: video-phy@10020710 {
compatible = "samsung,s5pv210-mipi-video-phy";
#phy-cells = <1>;
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 3184e10f260a..045785c44c04 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -158,6 +158,20 @@
interrupt-parent = <&gic>;
};
+ poweroff: syscon-poweroff {
+ compatible = "syscon-poweroff";
+ regmap = <&pmu_system_controller>;
+ offset = <0x330C>; /* PS_HOLD_CONTROL */
+ mask = <0x5200>; /* reset value */
+ };
+
+ reboot: syscon-reboot {
+ compatible = "syscon-reboot";
+ regmap = <&pmu_system_controller>;
+ offset = <0x0400>; /* SWRESET */
+ mask = <0x1>;
+ };
+
dsi_0: dsi@11C80000 {
compatible = "samsung,exynos4210-mipi-dsi";
reg = <0x11C80000 0x10000>;
@@ -713,6 +727,15 @@
iommus = <&sysmmu_jpeg>;
};
+ rotator: rotator@12810000 {
+ compatible = "samsung,exynos4210-rotator";
+ reg = <0x12810000 0x64>;
+ interrupts = <0 83 0>;
+ clocks = <&clock CLK_ROTATOR>;
+ clock-names = "rotator";
+ iommus = <&sysmmu_rotator>;
+ };
+
hdmi: hdmi@12D00000 {
compatible = "samsung,exynos4210-hdmi";
reg = <0x12D00000 0x70000>;
@@ -940,7 +963,6 @@
interrupts = <5 0>;
clock-names = "sysmmu", "master";
clocks = <&clock CLK_SMMU_ROTATOR>, <&clock CLK_ROTATOR>;
- power-domains = <&pd_lcd0>;
#iommu-cells = <0>;
};
@@ -954,4 +976,12 @@
power-domains = <&pd_lcd0>;
#iommu-cells = <0>;
};
+
+ prng: rng@10830400 {
+ compatible = "samsung,exynos4-rng";
+ reg = <0x10830400 0x200>;
+ clocks = <&clock CLK_SSS>;
+ clock-names = "secss";
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
index b8f866991bdd..5821ad87e32c 100644
--- a/arch/arm/boot/dts/exynos4210-origen.dts
+++ b/arch/arm/boot/dts/exynos4210-origen.dts
@@ -138,10 +138,6 @@
status = "okay";
};
-&g2d {
- status = "okay";
-};
-
&i2c_0 {
status = "okay";
samsung,i2c-sda-delay = <100>;
diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts
index bc1448ba95d3..104cbb33d2bb 100644
--- a/arch/arm/boot/dts/exynos4210-smdkv310.dts
+++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts
@@ -44,10 +44,6 @@
};
};
-&g2d {
- status = "okay";
-};
-
&i2c_0 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index 81b7ec7b3e31..4f5d37920c8d 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -560,16 +560,24 @@
&serial_0 {
status = "okay";
+ /delete-property/dmas;
+ /delete-property/dma-names;
};
&serial_1 {
status = "okay";
+ /delete-property/dmas;
+ /delete-property/dma-names;
};
&serial_2 {
status = "okay";
+ /delete-property/dmas;
+ /delete-property/dma-names;
};
&serial_3 {
status = "okay";
+ /delete-property/dmas;
+ /delete-property/dma-names;
};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 3e5ba665d200..c1cb8df6da07 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -185,8 +185,8 @@
interrupts = <0 89 0>;
clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
clock-names = "sclk_fimg2d", "fimg2d";
+ power-domains = <&pd_lcd0>;
iommus = <&sysmmu_g2d>;
- status = "disabled";
};
camera {
@@ -271,6 +271,10 @@
<0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
};
+&mdma1 {
+ power-domains = <&pd_lcd0>;
+};
+
&pmu_system_controller {
clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
"clkout4", "clkout8", "clkout9";
@@ -279,3 +283,11 @@
<&clock CLK_OUT_CPU>, <&clock CLK_XXTI>, <&clock CLK_XUSBXTI>;
#clock-cells = <1>;
};
+
+&rotator {
+ power-domains = <&pd_lcd0>;
+};
+
+&sysmmu_rotator {
+ power-domains = <&pd_lcd0>;
+};
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index edf0fc8db6ff..395c3ca9601e 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -177,10 +177,6 @@
assigned-clock-rates = <0>, <176000000>;
};
-&g2d {
- status = "okay";
-};
-
&hdmi {
hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts
index 646ff0bd001a..dd89f7b37c9f 100644
--- a/arch/arm/boot/dts/exynos4412-odroidu3.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts
@@ -13,7 +13,6 @@
/dts-v1/;
#include "exynos4412-odroid-common.dtsi"
-#include <dt-bindings/gpio/gpio.h>
/ {
model = "Hardkernel ODROID-U3 board based on Exynos4412";
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index c8d86af2fb98..9e2e24c6177a 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -89,10 +89,6 @@
status = "okay";
};
-&g2d {
- status = "okay";
-};
-
&i2c_0 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts
index c2421df1fa43..a130ab39fa77 100644
--- a/arch/arm/boot/dts/exynos4412-smdk4412.dts
+++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts
@@ -41,10 +41,6 @@
};
};
-&g2d {
- status = "okay";
-};
-
&keypad {
samsung,keypad-num-rows = <3>;
samsung,keypad-num-columns = <8>;
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 40a474c4374b..a6f78c3da935 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -1234,6 +1234,10 @@
status = "okay";
};
+&prng {
+ status = "okay";
+};
+
&rtc {
status = "okay";
clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index b77dac61ffb5..84a23f962946 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -116,7 +116,6 @@
clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
clock-names = "sclk_fimg2d", "fimg2d";
iommus = <&sysmmu_g2d>;
- status = "disabled";
};
camera {
@@ -339,6 +338,10 @@
compatible = "samsung,exynos4212-jpeg";
};
+&rotator {
+ compatible = "samsung,exynos4212-rotator";
+};
+
&mixer {
compatible = "samsung,exynos4212-mixer";
clock-names = "mixer", "hdmi", "sclk_hdmi", "vp";
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi
index 110dbd4fb884..e2439e87ee4a 100644
--- a/arch/arm/boot/dts/exynos5.dtsi
+++ b/arch/arm/boot/dts/exynos5.dtsi
@@ -88,6 +88,20 @@
status = "disabled";
};
+ poweroff: syscon-poweroff {
+ compatible = "syscon-poweroff";
+ regmap = <&pmu_system_controller>;
+ offset = <0x330C>; /* PS_HOLD_CONTROL */
+ mask = <0x5200>; /* reset value */
+ };
+
+ reboot: syscon-reboot {
+ compatible = "syscon-reboot";
+ regmap = <&pmu_system_controller>;
+ offset = <0x0400>; /* SWRESET */
+ mask = <0x1>;
+ };
+
fimd: fimd@14400000 {
compatible = "samsung,exynos5250-fimd";
interrupt-parent = <&combiner>;
diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi
index 0a7f408824d8..5cb33ba5e296 100644
--- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi
+++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi
@@ -520,8 +520,7 @@
&mmc_0 {
status = "okay";
num-slots = <1>;
- broken-cd;
- card-detect-delay = <200>;
+ non-removable;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <2 3>;
samsung,dw-mshc-ddr-timing = <1 2>;
@@ -552,10 +551,9 @@
&mmc_3 {
status = "okay";
num-slots = <1>;
- broken-cd;
+ non-removable;
cap-sdio-irq;
keep-power-in-suspend;
- card-detect-delay = <200>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <2 3>;
samsung,dw-mshc-ddr-timing = <1 2>;
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 88b9cf5f226f..33e2d5f7315b 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -269,6 +269,15 @@
iommu-names = "left", "right";
};
+ rotator: rotator@11C00000 {
+ compatible = "samsung,exynos5250-rotator";
+ reg = <0x11C00000 0x64>;
+ interrupts = <0 84 0>;
+ clocks = <&clock CLK_ROTATOR>;
+ clock-names = "rotator";
+ iommus = <&sysmmu_rotator>;
+ };
+
tmu: tmu@10060000 {
compatible = "samsung,exynos5250-tmu";
reg = <0x10060000 0x100>;
diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi
index 731eefd23fa9..fad0779b1b6e 100644
--- a/arch/arm/boot/dts/exynos5410.dtsi
+++ b/arch/arm/boot/dts/exynos5410.dtsi
@@ -102,6 +102,20 @@
reg = <0x10040000 0x5000>;
};
+ poweroff: syscon-poweroff {
+ compatible = "syscon-poweroff";
+ regmap = <&pmu_system_controller>;
+ offset = <0x330C>; /* PS_HOLD_CONTROL */
+ mask = <0x5200>; /* reset value */
+ };
+
+ reboot: syscon-reboot {
+ compatible = "syscon-reboot";
+ regmap = <&pmu_system_controller>;
+ offset = <0x0400>; /* SWRESET */
+ mask = <0x1>;
+ };
+
mct: mct@101C0000 {
compatible = "samsung,exynos4210-mct";
reg = <0x101C0000 0xB00>;
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 72ba6f032ed7..35cfb07dc4bb 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -690,11 +690,9 @@
&mmc_0 {
status = "okay";
num-slots = <1>;
- broken-cd;
mmc-hs200-1_8v;
cap-mmc-highspeed;
non-removable;
- card-detect-delay = <200>;
clock-frequency = <400000000>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <0 4>;
@@ -709,10 +707,9 @@
&mmc_1 {
status = "okay";
num-slots = <1>;
- broken-cd;
+ non-removable;
cap-sdio-irq;
keep-power-in-suspend;
- card-detect-delay = <200>;
clock-frequency = <400000000>;
samsung,dw-mshc-ciu-div = <1>;
samsung,dw-mshc-sdr-timing = <0 1>;
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 1b3d6c769a3c..48a0a55314f5 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -717,6 +717,15 @@
iommus = <&sysmmu_tv>;
};
+ rotator: rotator@11C00000 {
+ compatible = "samsung,exynos5250-rotator";
+ reg = <0x11C00000 0x64>;
+ interrupts = <0 84 0>;
+ clocks = <&clock CLK_ROTATOR>;
+ clock-names = "rotator";
+ iommus = <&sysmmu_rotator>;
+ };
+
gsc_0: video-scaler@13e00000 {
compatible = "samsung,exynos5-gsc";
reg = <0x13e00000 0x1000>;
@@ -1059,6 +1068,16 @@
#iommu-cells = <0>;
};
+ sysmmu_rotator: sysmmu@0x11D40000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11D40000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_ROTATOR>, <&clock CLK_ROTATOR>;
+ #iommu-cells = <0>;
+ };
+
sysmmu_jpeg0: sysmmu@0x11F10000 {
compatible = "samsung,exynos-sysmmu";
reg = <0x11F10000 0x1000>;
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
index 1af5bdc2bdb1..9134217446b8 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
@@ -67,11 +67,6 @@
<19200000>;
};
-&fimd {
- status = "okay";
-};
-
-
&hdmi {
status = "okay";
hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
index b1b36081f343..2ae1cf41dcb6 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
@@ -67,5 +67,5 @@
};
&usbdrd_dwc3_1 {
- dr_mode = "otg";
+ dr_mode = "peripheral";
};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
index 0c0bbdbfd85f..432406db85de 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3.dts
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
@@ -98,5 +98,5 @@
};
&usbdrd_dwc3_1 {
- dr_mode = "otg";
+ dr_mode = "peripheral";
};
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 49a4f43e5ac2..064176f201e7 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -122,6 +122,12 @@
compatible = "auo,b133htn01";
power-supply = <&tps65090_fet6>;
backlight = <&backlight>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dp_out>;
+ };
+ };
};
mmc1_pwrseq: mmc1_pwrseq {
@@ -148,7 +154,14 @@
samsung,link-rate = <0x0a>;
samsung,lane-count = <2>;
samsung,hpd-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
- panel = <&panel>;
+
+ ports {
+ port {
+ dp_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
};
&fimd {
@@ -652,12 +665,10 @@
&mmc_0 {
status = "okay";
num-slots = <1>;
- broken-cd;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
cap-mmc-highspeed;
non-removable;
- card-detect-delay = <200>;
clock-frequency = <800000000>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <0 4>;
@@ -672,10 +683,9 @@
&mmc_1 {
status = "okay";
num-slots = <1>;
- broken-cd;
+ non-removable;
cap-sdio-irq;
keep-power-in-suspend;
- card-detect-delay = <200>;
clock-frequency = <400000000>;
samsung,dw-mshc-ciu-div = <1>;
samsung,dw-mshc-sdr-timing = <0 1>;
diff --git a/arch/arm/boot/dts/imx25-pinfunc.h b/arch/arm/boot/dts/imx25-pinfunc.h
index 7c4b9f2f9aad..848ffa785b63 100644
--- a/arch/arm/boot/dts/imx25-pinfunc.h
+++ b/arch/arm/boot/dts/imx25-pinfunc.h
@@ -284,6 +284,7 @@
#define MX25_PAD_CONTRAST__CC4 0x118 0x310 0x000 0x11 0x000
#define MX25_PAD_CONTRAST__PWM4_PWMO 0x118 0x310 0x000 0x14 0x000
#define MX25_PAD_CONTRAST__FEC_CRS 0x118 0x310 0x508 0x15 0x001
+#define MX25_PAD_CONTRAST__USBH2_PWR 0x118 0x310 0x000 0x16 0x000
#define MX25_PAD_PWM__PWM 0x11c 0x314 0x000 0x10 0x000
#define MX25_PAD_PWM__GPIO_1_26 0x11c 0x314 0x000 0x15 0x000
@@ -439,6 +440,7 @@
#define MX25_PAD_SD1_DATA3__GPIO_2_28 0x1a4 0x39c 0x000 0x15 0x000
#define MX25_PAD_KPP_ROW0__KPP_ROW0 0x1a8 0x3a0 0x000 0x10 0x000
+#define MX25_PAD_KPP_ROW0__UART1_DTR 0x1a8 0x3a0 0x000 0x14 0x000
#define MX25_PAD_KPP_ROW0__GPIO_2_29 0x1a8 0x3a0 0x000 0x15 0x000
#define MX25_PAD_KPP_ROW1__KPP_ROW1 0x1ac 0x3a4 0x000 0x10 0x000
@@ -446,6 +448,7 @@
#define MX25_PAD_KPP_ROW2__KPP_ROW2 0x1b0 0x3a8 0x000 0x10 0x000
#define MX25_PAD_KPP_ROW2__CSI_D0 0x1b0 0x3a8 0x488 0x13 0x002
+#define MX25_PAD_KPP_ROW2__UART1_DCD 0x1b0 0x3a8 0x000 0x14 0x000
#define MX25_PAD_KPP_ROW2__GPIO_2_31 0x1b0 0x3a8 0x000 0x15 0x000
#define MX25_PAD_KPP_ROW3__KPP_ROW3 0x1b4 0x3ac 0x000 0x10 0x000
diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi
index 677f81d9dcd5..cde329e9b9e3 100644
--- a/arch/arm/boot/dts/imx25.dtsi
+++ b/arch/arm/boot/dts/imx25.dtsi
@@ -24,6 +24,10 @@
i2c2 = &i2c3;
mmc0 = &esdhc1;
mmc1 = &esdhc2;
+ pwm0 = &pwm1;
+ pwm1 = &pwm2;
+ pwm2 = &pwm3;
+ pwm3 = &pwm4;
serial0 = &uart1;
serial1 = &uart2;
serial2 = &uart3;
diff --git a/arch/arm/boot/dts/imx28-cfa10057.dts b/arch/arm/boot/dts/imx28-cfa10057.dts
index 5df0b24eaf59..7a80bd686c40 100644
--- a/arch/arm/boot/dts/imx28-cfa10057.dts
+++ b/arch/arm/boot/dts/imx28-cfa10057.dts
@@ -115,7 +115,7 @@
pwm: pwm@80064000 {
pinctrl-names = "default";
- pinctrl-0 = <&pwm3_pins_b>;
+ pinctrl-0 = <&pwm4_pins_a>;
status = "okay";
};
@@ -170,7 +170,7 @@
backlight {
compatible = "pwm-backlight";
- pwms = <&pwm 3 5000000>;
+ pwms = <&pwm 4 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
};
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index c5b57d4adade..fae7b9069fc4 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -405,6 +405,17 @@
fsl,pull-up = <MXS_PULL_DISABLE>;
};
+ auart4_2pins_b: auart4@1 {
+ reg = <1>;
+ fsl,pinmux-ids = <
+ MX28_PAD_AUART0_CTS__AUART4_RX
+ MX28_PAD_AUART0_RTS__AUART4_TX
+ >;
+ fsl,drive-strength = <MXS_DRIVE_4mA>;
+ fsl,voltage = <MXS_VOLTAGE_HIGH>;
+ fsl,pull-up = <MXS_PULL_DISABLE>;
+ };
+
mac0_pins_a: mac0@0 {
reg = <0>;
fsl,pinmux-ids = <
diff --git a/arch/arm/boot/dts/imx51-ts4800.dts b/arch/arm/boot/dts/imx51-ts4800.dts
new file mode 100644
index 000000000000..0ff76a1bc0f1
--- /dev/null
+++ b/arch/arm/boot/dts/imx51-ts4800.dts
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2015 Savoir-faire Linux
+ *
+ * This device tree is based on imx51-babbage.dts
+ *
+ * Licensed under the X11 license or the GPL v2 (or later)
+ */
+
+/dts-v1/;
+#include "imx51.dtsi"
+
+/ {
+ model = "Technologic Systems TS-4800";
+ compatible = "technologic,imx51-ts4800", "fsl,imx51";
+
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory {
+ reg = <0x90000000 0x10000000>;
+ };
+
+ clocks {
+ ckih1 {
+ clock-frequency = <22579200>;
+ };
+
+ ckih2 {
+ clock-frequency = <24576000>;
+ };
+ };
+
+ backlight_reg: regulator-backlight {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enable_lcd>;
+ regulator-name = "enable_lcd_reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio4 9 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm1 0 78770>;
+ brightness-levels = <0 150 200 255>;
+ default-brightness-level = <1>;
+ power-supply = <&backlight_reg>;
+ };
+
+ display0: display@di0 {
+ compatible = "fsl,imx-parallel-display";
+ interface-pix-fmt = "rgb24";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcd>;
+
+ display-timings {
+ 800x480p60 {
+ native-mode;
+ clock-frequency = <30066000>;
+ hactive = <800>;
+ vactive = <480>;
+ hfront-porch = <50>;
+ hback-porch = <70>;
+ hsync-len = <50>;
+ vback-porch = <0>;
+ vfront-porch = <0>;
+ vsync-len = <50>;
+ };
+ };
+
+ port@0 {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
+ };
+};
+
+&esdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_esdhc1>;
+ cd-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec>;
+ phy-mode = "mii";
+ phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
+ phy-reset-duration = <1>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+
+ rtc: m41t00@68 {
+ compatible = "stm,m41t00";
+ reg = <0x68>;
+ };
+};
+
+&ipu_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm_backlight>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&weim {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_weim>;
+ status = "okay";
+
+ fpga@0 {
+ compatible = "simple-bus";
+ fsl,weim-cs-timing = <0x0061008F 0x00000002 0x1c022000
+ 0x00000000 0x1c092480 0x00000000>;
+ reg = <0 0x0000000 0x1d000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0x1d000>;
+
+ syscon: syscon@b0010000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x10000 0x3d>;
+ reg-io-width = <2>;
+
+ wdt@e {
+ compatible = "technologic,ts4800-wdt";
+ syscon = <&syscon 0xe>;
+ };
+ };
+
+ touchscreen {
+ compatible = "technologic,ts4800-ts";
+ reg = <0x12000 0x1000>;
+ syscon = <&syscon 0x10 6>;
+ };
+ };
+};
+
+&iomuxc {
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185
+ MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185
+ MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185
+ MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */
+ >;
+ };
+
+ pinctrl_enable_lcd: enablelcdgrp {
+ fsl,pins = <
+ MX51_PAD_CSI2_D12__GPIO4_9 0x1c5
+ >;
+ };
+
+ pinctrl_esdhc1: esdhc1grp {
+ fsl,pins = <
+ MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5
+ MX51_PAD_SD1_CLK__SD1_CLK 0x20d5
+ MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5
+ MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5
+ MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5
+ MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5
+ MX51_PAD_GPIO1_0__GPIO1_0 0x100
+ MX51_PAD_GPIO1_1__GPIO1_1 0x100
+ >;
+ };
+
+ pinctrl_fec: fecgrp {
+ fsl,pins = <
+ MX51_PAD_EIM_EB2__FEC_MDIO 0x000001f5
+ MX51_PAD_EIM_EB3__FEC_RDATA1 0x00000085
+ MX51_PAD_EIM_CS2__FEC_RDATA2 0x00000085
+ MX51_PAD_EIM_CS3__FEC_RDATA3 0x00000085
+ MX51_PAD_EIM_CS4__FEC_RX_ER 0x00000180
+ MX51_PAD_EIM_CS5__FEC_CRS 0x00000180
+ MX51_PAD_DISP2_DAT10__FEC_COL 0x00000180
+ MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x00000180
+ MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x00002180
+ MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x00002004
+ MX51_PAD_NANDF_CS2__FEC_TX_ER 0x00002004
+ MX51_PAD_DI2_PIN2__FEC_MDC 0x00002004
+ MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x00002004
+ MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x00002004
+ MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x00002004
+ MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x00002004
+ MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x00002180
+ MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x000020a4
+ MX51_PAD_EIM_A20__GPIO2_14 0x00000085 /* Phy Reset */
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed
+ MX51_PAD_KEY_COL5__I2C2_SDA 0x400001ed
+ >;
+ };
+
+ pinctrl_lcd: lcdgrp {
+ fsl,pins = <
+ MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5
+ MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5
+ MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5
+ MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5
+ MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5
+ MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5
+ MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5
+ MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5
+ MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5
+ MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5
+ MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5
+ MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5
+ MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5
+ MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5
+ MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5
+ MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5
+ MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5
+ MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5
+ MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5
+ MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5
+ MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5
+ MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5
+ MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5
+ MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5
+ MX51_PAD_DI1_PIN2__DI1_PIN2 0x5
+ MX51_PAD_DI1_PIN3__DI1_PIN3 0x5
+ MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 0x5
+ MX51_PAD_DI_GP4__DI2_PIN15 0x5
+ >;
+ };
+
+ pinctrl_pwm_backlight: backlightgrp {
+ fsl,pins = <
+ MX51_PAD_GPIO1_2__PWM1_PWMO 0x80000000
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX51_PAD_UART1_RXD__UART1_RXD 0x1c5
+ MX51_PAD_UART1_TXD__UART1_TXD 0x1c5
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX51_PAD_UART2_RXD__UART2_RXD 0x1c5
+ MX51_PAD_UART2_TXD__UART2_TXD 0x1c5
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX51_PAD_EIM_D25__UART3_RXD 0x1c5
+ MX51_PAD_EIM_D26__UART3_TXD 0x1c5
+ >;
+ };
+
+ pinctrl_weim: weimgrp {
+ fsl,pins = <
+ MX51_PAD_EIM_DTACK__EIM_DTACK 0x85
+ MX51_PAD_EIM_CS0__EIM_CS0 0x0
+ MX51_PAD_EIM_CS1__EIM_CS1 0x0
+ MX51_PAD_EIM_EB0__EIM_EB0 0x85
+ MX51_PAD_EIM_EB1__EIM_EB1 0x85
+ MX51_PAD_EIM_OE__EIM_OE 0x85
+ MX51_PAD_EIM_LBA__EIM_LBA 0x85
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 4b0ec0703825..c13a73aa55ca 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -104,10 +104,15 @@
compatible = "fsl,imx-display-subsystem";
ports = <&ipu1_di0>, <&ipu1_di1>;
};
+
+ gpu-subsystem {
+ compatible = "fsl,imx-gpu-subsystem";
+ cores = <&gpu_2d>, <&gpu_3d>;
+ };
};
&gpt {
- compatible = "fsl,imx6dl-gpt", "fsl,imx6q-gpt";
+ compatible = "fsl,imx6dl-gpt";
};
&hdmi {
diff --git a/arch/arm/boot/dts/imx6q-novena.dts b/arch/arm/boot/dts/imx6q-novena.dts
new file mode 100644
index 000000000000..5acd0c63b33b
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-novena.dts
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2015 Sutajio Ko-Usagi PTE LTD
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Kosagi Novena Dual/Quad";
+ compatible = "kosagi,imx6q-novena", "fsl,imx6q";
+
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm1 0 10000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_backlight_novena>;
+ power-supply = <&reg_lvds_lcd>;
+ brightness-levels = <0 3 6 12 16 24 32 48 64 96 128 192 255>;
+ default-brightness-level = <12>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys_novena>;
+
+ user-button {
+ label = "User Button";
+ gpios = <&gpio4 14 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
+ };
+
+ lid {
+ label = "Lid";
+ gpios = <&gpio4 12 GPIO_ACTIVE_LOW>;
+ linux,input-type = <5>; /* EV_SW */
+ linux,code = <0>; /* SW_LID */
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_leds_novena>;
+
+ heartbeat {
+ label = "novena:white:panel";
+ gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+ };
+
+ panel: panel {
+ compatible = "innolux,n133hse-ea1", "simple-panel";
+ backlight = <&backlight>;
+ };
+
+ reg_2p5v: regulator-2p5v {
+ compatible = "regulator-fixed";
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_audio_codec: regulator-audio-codec {
+ compatible = "regulator-fixed";
+ regulator-name = "es8328-power";
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <400000>;
+ gpio = <&gpio5 17 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_display: regulator-display {
+ compatible = "regulator-fixed";
+ regulator-name = "lcd-display-power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <200000>;
+ gpio = <&gpio5 28 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_lvds_lcd: regulator-lvds-lcd {
+ compatible = "regulator-fixed";
+ regulator-name = "lcd-lvds-power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_pcie: regulator-pcie {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie-bus-power";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ reg_sata: regulator-sata {
+ compatible = "regulator-fixed";
+ regulator-name = "sata-power";
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <10000>;
+ gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usb_otg_vbus: regulator-usb-otg-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ };
+
+ sound {
+ compatible = "fsl,imx-audio-es8328";
+ model = "imx-audio-es8328";
+ ssi-controller = <&ssi1>;
+ audio-codec = <&codec>;
+ audio-amp-supply = <&reg_audio_codec>;
+ jack-gpio = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+ audio-routing =
+ "Speaker", "LOUT2",
+ "Speaker", "ROUT2",
+ "Speaker", "audio-amp",
+ "Headphone", "ROUT1",
+ "Headphone", "LOUT1",
+ "LINPUT1", "Mic Jack",
+ "RINPUT1", "Mic Jack",
+ "Mic Jack", "Mic Bias";
+ mux-int-port = <0x1>;
+ mux-ext-port = <0x3>;
+ };
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux_novena>;
+ status = "okay";
+};
+
+&ecspi3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi3_novena>;
+ fsl,spi-num-chipselects = <3>;
+ status = "okay";
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet_novena>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
+ rxc-skew-ps = <3000>;
+ rxdv-skew-ps = <0>;
+ txc-skew-ps = <3000>;
+ txen-skew-ps = <0>;
+ rxd0-skew-ps = <0>;
+ rxd1-skew-ps = <0>;
+ rxd2-skew-ps = <0>;
+ rxd3-skew-ps = <0>;
+ txd0-skew-ps = <3000>;
+ txd1-skew-ps = <3000>;
+ txd2-skew-ps = <3000>;
+ txd3-skew-ps = <3000>;
+ status = "okay";
+};
+
+&hdmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hdmi_novena>;
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1_novena>;
+ status = "okay";
+
+ accel: mma8452@1c {
+ compatible = "fsl,mma8452";
+ reg = <0x1c>;
+ };
+
+ rtc: pcf8523@68 {
+ compatible = "nxp,pcf8523";
+ reg = <0x68>;
+ };
+
+ sbs_battery: bq20z75@0b {
+ compatible = "sbs,sbs-battery";
+ reg = <0x0b>;
+ sbs,i2c-retry-count = <50>;
+ };
+
+ touch: stmpe811@44 {
+ compatible = "st,stmpe811";
+ reg = <0x44>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ irq-gpio = <&gpio5 13 GPIO_ACTIVE_HIGH>;
+ id = <0>;
+ blocks = <0x5>;
+ irq-trigger = <0x1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_stmpe_novena>;
+ vio-supply = <&reg_3p3v>;
+ vcc-supply = <&reg_3p3v>;
+
+ stmpe_touchscreen {
+ compatible = "st,stmpe-ts";
+ st,sample-time = <4>;
+ st,mod-12b = <1>;
+ st,ref-sel = <0>;
+ st,adc-freq = <1>;
+ st,ave-ctrl = <1>;
+ st,touch-det-delay = <2>;
+ st,settling = <2>;
+ st,fraction-z = <7>;
+ st,i-drive = <1>;
+ };
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2_novena>;
+ status = "okay";
+
+ pmic: pfuze100@08 {
+ compatible = "fsl,pfuze100";
+ reg = <0x08>;
+
+ regulators {
+ reg_sw1a: sw1a {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ reg_sw1c: sw1c {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_sw2: sw2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_sw3a: sw3a {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_sw3b: sw3b {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_sw4: sw4 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_swbst: swbst {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5150000>;
+ regulator-boot-on;
+ };
+
+ reg_snvs: vsnvs {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_vref: vrefddr {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_vgen1: vgen1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ reg_vgen2: vgen2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ reg_vgen3: vgen3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_vgen4: vgen4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_vgen5: vgen5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_vgen6: vgen6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3_novena>;
+ status = "okay";
+
+ codec: es8328@11 {
+ compatible = "everest,es8328";
+ reg = <0x11>;
+ DVDD-supply = <&reg_audio_codec>;
+ AVDD-supply = <&reg_audio_codec>;
+ PVDD-supply = <&reg_audio_codec>;
+ HPVDD-supply = <&reg_audio_codec>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sound_novena>;
+ clocks = <&clks IMX6QDL_CLK_CKO1>;
+ assigned-clocks = <&clks IMX6QDL_CLK_CKO>,
+ <&clks IMX6QDL_CLK_CKO1_SEL>,
+ <&clks IMX6QDL_CLK_PLL4_AUDIO>,
+ <&clks IMX6QDL_CLK_CKO1>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_CKO1>,
+ <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>,
+ <&clks IMX6QDL_CLK_OSC>,
+ <&clks IMX6QDL_CLK_CKO1_PODF>;
+ assigned-clock-rates = <0 0 722534400 22579200>;
+ };
+};
+
+&kpp {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_kpp_novena>;
+ linux,keymap = <
+ MATRIX_KEY(1, 1, KEY_CONFIG)
+ >;
+ status = "okay";
+};
+
+&ldb {
+ fsl,dual-channel;
+ status = "okay";
+
+ lvds-channel@0 {
+ fsl,data-mapping = "jeida";
+ fsl,data-width = <24>;
+ fsl,panel = <&panel>;
+ status = "okay";
+ };
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie_novena>;
+ reset-gpio = <&gpio3 29 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&sata {
+ target-supply = <&reg_sata>;
+ fsl,transmit-level-mV = <1025>;
+ fsl,transmit-boost-mdB = <0>;
+ fsl,transmit-atten-16ths = <8>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2_novena>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3_novena>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4_novena>;
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ dr_mode = "otg";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg_novena>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_swbst>;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2_novena>;
+ cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3_novena>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_audmux_novena: audmuxgrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
+ >;
+ };
+
+ pinctrl_backlight_novena: backlightgrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT10__GPIO5_IO28 0x1b0b1
+ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x1b0b1
+ >;
+ };
+
+ pinctrl_ecspi3_novena: ecspi3grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1
+ MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1
+ MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1
+ >;
+ };
+
+ pinctrl_enet_novena: enetgrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b020
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b028
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b028
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b028
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b028
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b028
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
+ /* Ethernet reset */
+ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b0b1
+ >;
+ };
+
+ pinctrl_fpga_gpio: fpgagpiogrp-novena {
+ fsl,pins = <
+ /* FPGA power */
+ MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b1
+ /* Reset */
+ MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x1b0b1
+ /* FPGA GPIOs */
+ MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x1b0b1
+ MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x1b0b1
+ MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x1b0b1
+ MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x1b0b1
+ MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b0b1
+ MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1
+ MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x1b0b1
+ MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x1b0b1
+ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x1b0b1
+ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x1b0b1
+ MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x1b0b1
+ MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x1b0b1
+ MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x1b0b1
+ MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x1b0b1
+ MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x1b0b1
+ MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x1b0b1
+ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x1b0b1
+ MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x1b0b1
+ MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x1b0b1
+ MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x1b0b1
+ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x1b0b1
+ MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b0b1
+ MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x1b0b1
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1b0b1
+ MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0x1b0b1
+ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x1b0b1
+ >;
+ };
+
+ pinctrl_fpga_eim: fpgaeimgrp-novena {
+ fsl,pins = <
+ /* FPGA power */
+ MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b1
+ /* Reset */
+ MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x1b0b1
+ /* FPGA GPIOs */
+ MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0f1
+ MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0f1
+ MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0f1
+ MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0f1
+ MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0f1
+ MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0f1
+ MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0f1
+ MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0f1
+ MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0f1
+ MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0f1
+ MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0f1
+ MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0f1
+ MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0f1
+ MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0f1
+ MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0f1
+ MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0f1
+ MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0f1
+ MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0f1
+ MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0f1
+ MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0f1
+ MX6QDL_PAD_EIM_CS1__EIM_CS1_B 0xb0f1
+ MX6QDL_PAD_EIM_LBA__EIM_LBA_B 0xb0f1
+ MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0f1
+ MX6QDL_PAD_EIM_RW__EIM_RW 0xb0f1
+ MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb0f1
+ MX6QDL_PAD_EIM_BCLK__EIM_BCLK 0xb0f1
+ >;
+ };
+
+ pinctrl_gpio_keys_novena: gpiokeysgrp-novena {
+ fsl,pins = <
+ /* User button */
+ MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0
+ /* PCIe Wakeup */
+ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1f0e0
+ /* Lid switch */
+ MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x1b0b0
+ >;
+ };
+
+ pinctrl_hdmi_novena: hdmigrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
+ MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x1b0b1
+ >;
+ };
+
+ pinctrl_i2c1_novena: i2c1grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2_novena: i2c2grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3_novena: i2c3grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_kpp_novena: kppgrp-novena {
+ fsl,pins = <
+ /* Front panel button */
+ MX6QDL_PAD_KEY_ROW1__KEY_ROW1 0x1b0b1
+ /* Fake column driver, not connected */
+ MX6QDL_PAD_KEY_COL1__KEY_COL1 0x1b0b1
+ >;
+ };
+
+ pinctrl_leds_novena: ledsgrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x1b0b1
+ >;
+ };
+
+ pinctrl_pcie_novena: pciegrp-novena {
+ fsl,pins = <
+ /* Reset */
+ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b1
+ /* Power On */
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b1
+ /* Wifi kill */
+ MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x1b0b1
+ >;
+ };
+
+ pinctrl_sata_novena: satagrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x1b0b1
+ >;
+ };
+
+ pinctrl_senoko_novena: senokogrp-novena {
+ fsl,pins = <
+ /* Senoko IRQ line */
+ MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x13048
+ /* Senoko reset line */
+ MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x1b0b1
+ >;
+ };
+
+ pinctrl_sound_novena: soundgrp-novena {
+ fsl,pins = <
+ /* Audio power regulator */
+ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x1b0b1
+ /* Headphone plug */
+ MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x1b0b1
+ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0
+ >;
+ };
+
+ pinctrl_stmpe_novena: stmpegrp-novena {
+ fsl,pins = <
+ /* Touchscreen interrupt */
+ MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2_novena: uart2grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3_novena: uart3grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4_novena: uart4grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg_novena: usbotggrp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
+ >;
+ };
+
+ pinctrl_usdhc2_novena: usdhc2grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170f9
+ /* Write protect */
+ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b1
+ /* Card detect */
+ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc3_novena: usdhc3grp-novena {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 399103b8e2c9..0d93c0e8f9ba 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -14,6 +14,7 @@
/ {
aliases {
+ ipu1 = &ipu2;
spi4 = &ecspi5;
};
@@ -103,42 +104,6 @@
iomuxc: iomuxc@020e0000 {
compatible = "fsl,imx6q-iomuxc";
-
- ipu2 {
- pinctrl_ipu2_1: ipu2grp-1 {
- fsl,pins = <
- MX6QDL_PAD_DI0_DISP_CLK__IPU2_DI0_DISP_CLK 0x10
- MX6QDL_PAD_DI0_PIN15__IPU2_DI0_PIN15 0x10
- MX6QDL_PAD_DI0_PIN2__IPU2_DI0_PIN02 0x10
- MX6QDL_PAD_DI0_PIN3__IPU2_DI0_PIN03 0x10
- MX6QDL_PAD_DI0_PIN4__IPU2_DI0_PIN04 0x80000000
- MX6QDL_PAD_DISP0_DAT0__IPU2_DISP0_DATA00 0x10
- MX6QDL_PAD_DISP0_DAT1__IPU2_DISP0_DATA01 0x10
- MX6QDL_PAD_DISP0_DAT2__IPU2_DISP0_DATA02 0x10
- MX6QDL_PAD_DISP0_DAT3__IPU2_DISP0_DATA03 0x10
- MX6QDL_PAD_DISP0_DAT4__IPU2_DISP0_DATA04 0x10
- MX6QDL_PAD_DISP0_DAT5__IPU2_DISP0_DATA05 0x10
- MX6QDL_PAD_DISP0_DAT6__IPU2_DISP0_DATA06 0x10
- MX6QDL_PAD_DISP0_DAT7__IPU2_DISP0_DATA07 0x10
- MX6QDL_PAD_DISP0_DAT8__IPU2_DISP0_DATA08 0x10
- MX6QDL_PAD_DISP0_DAT9__IPU2_DISP0_DATA09 0x10
- MX6QDL_PAD_DISP0_DAT10__IPU2_DISP0_DATA10 0x10
- MX6QDL_PAD_DISP0_DAT11__IPU2_DISP0_DATA11 0x10
- MX6QDL_PAD_DISP0_DAT12__IPU2_DISP0_DATA12 0x10
- MX6QDL_PAD_DISP0_DAT13__IPU2_DISP0_DATA13 0x10
- MX6QDL_PAD_DISP0_DAT14__IPU2_DISP0_DATA14 0x10
- MX6QDL_PAD_DISP0_DAT15__IPU2_DISP0_DATA15 0x10
- MX6QDL_PAD_DISP0_DAT16__IPU2_DISP0_DATA16 0x10
- MX6QDL_PAD_DISP0_DAT17__IPU2_DISP0_DATA17 0x10
- MX6QDL_PAD_DISP0_DAT18__IPU2_DISP0_DATA18 0x10
- MX6QDL_PAD_DISP0_DAT19__IPU2_DISP0_DATA19 0x10
- MX6QDL_PAD_DISP0_DAT20__IPU2_DISP0_DATA20 0x10
- MX6QDL_PAD_DISP0_DAT21__IPU2_DISP0_DATA21 0x10
- MX6QDL_PAD_DISP0_DAT22__IPU2_DISP0_DATA22 0x10
- MX6QDL_PAD_DISP0_DAT23__IPU2_DISP0_DATA23 0x10
- >;
- };
- };
};
};
@@ -153,6 +118,16 @@
status = "disabled";
};
+ gpu_vg: gpu@02204000 {
+ compatible = "vivante,gc";
+ reg = <0x02204000 0x4000>;
+ interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_OPENVG_AXI>,
+ <&clks IMX6QDL_CLK_GPU2D_CORE>;
+ clock-names = "bus", "core";
+ power-domains = <&gpc 1>;
+ };
+
ipu2: ipu@02800000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -225,6 +200,11 @@
compatible = "fsl,imx-display-subsystem";
ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>;
};
+
+ gpu-subsystem {
+ compatible = "fsl,imx-gpu-subsystem";
+ cores = <&gpu_2d>, <&gpu_3d>, <&gpu_vg>;
+ };
};
&hdmi {
diff --git a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
index dc0cebfe22d7..5cd16f2178b8 100644
--- a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
@@ -174,6 +174,24 @@
status = "okay";
};
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
+&pwm4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm4>; /* MX6_DIO3 */
+ status = "disabled";
+};
+
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
@@ -294,6 +312,24 @@
>;
};
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm4: pwm4grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x1b0b1
+ >;
+ };
+
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
index 18cd4114a23e..9fa8a10c7cc8 100644
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -151,6 +151,21 @@
status = "okay";
};
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
+&ecspi3 {
+ fsl,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi3>;
+ status = "okay";
+};
+
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
@@ -275,6 +290,18 @@
status = "okay";
};
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
&pwm4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm4>;
@@ -338,6 +365,15 @@
>;
};
+ pinctrl_ecspi3: escpi3grp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1
+ MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1
+ MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1
+ MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x100b1
+ >;
+ };
+
pinctrl_enet: enetgrp {
fsl,pins = <
MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
@@ -429,6 +465,18 @@
>;
};
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
pinctrl_pwm4: pwm4grp {
fsl,pins = <
MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
index eea90f37bbb8..e8375e173873 100644
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -152,6 +152,13 @@
status = "okay";
};
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
@@ -247,7 +254,7 @@
&ldb {
status = "okay";
- lvds-channel@1 {
+ lvds-channel@0 {
fsl,data-mapping = "spwg";
fsl,data-width = <18>;
status = "okay";
@@ -280,6 +287,18 @@
};
};
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
&pwm4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm4>;
@@ -435,6 +454,18 @@
>;
};
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
pinctrl_pwm4: pwm4grp {
fsl,pins = <
MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index 6c11a2ae35ef..66983dc5cbda 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -142,6 +142,13 @@
status = "okay";
};
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
@@ -260,6 +267,8 @@
swbst_reg: swbst {
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5150000>;
+ regulator-boot-on;
+ regulator-always-on;
};
snvs_reg: vsnvs {
@@ -336,7 +345,7 @@
&ldb {
status = "okay";
- lvds-channel@1 {
+ lvds-channel@0 {
fsl,data-mapping = "spwg";
fsl,data-width = <18>;
status = "okay";
@@ -369,6 +378,24 @@
};
};
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>; /* MX6_DIO0 */
+ status = "disabled";
+};
+
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
&pwm4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm4>;
@@ -528,6 +555,24 @@
>;
};
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
pinctrl_pwm4: pwm4grp {
fsl,pins = <
MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
index 741f3d529e3e..118bea524dab 100644
--- a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
@@ -198,6 +198,18 @@
status = "okay";
};
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
&ssi1 {
status = "okay";
};
@@ -290,6 +302,18 @@
>;
};
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
pinctrl_uart2: uart2grp {
fsl,pins = <
MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
index d1e5048b00b5..cca39f194017 100644
--- a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
@@ -164,6 +164,18 @@
status = "okay";
};
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
@@ -242,6 +254,18 @@
>;
};
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
pinctrl_uart2: uart2grp {
fsl,pins = <
MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 2b6cc8bf3c5c..4f6ae921656f 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -30,6 +30,7 @@
i2c0 = &i2c1;
i2c1 = &i2c2;
i2c2 = &i2c3;
+ ipu0 = &ipu1;
mmc0 = &usdhc1;
mmc1 = &usdhc2;
mmc2 = &usdhc3;
@@ -47,15 +48,6 @@
usbphy1 = &usbphy2;
};
- intc: interrupt-controller@00a01000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x00a01000 0x1000>,
- <0x00a00100 0x100>;
- interrupt-parent = <&intc>;
- };
-
clocks {
#address-cells = <1>;
#size-cells = <0>;
@@ -147,6 +139,27 @@
};
};
+ gpu_3d: gpu@00130000 {
+ compatible = "vivante,gc";
+ reg = <0x00130000 0x4000>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_GPU3D_AXI>,
+ <&clks IMX6QDL_CLK_GPU3D_CORE>,
+ <&clks IMX6QDL_CLK_GPU3D_SHADER>;
+ clock-names = "bus", "core", "shader";
+ power-domains = <&gpc 1>;
+ };
+
+ gpu_2d: gpu@00134000 {
+ compatible = "vivante,gc";
+ reg = <0x00134000 0x4000>;
+ interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_GPU2D_AXI>,
+ <&clks IMX6QDL_CLK_GPU2D_CORE>;
+ clock-names = "bus", "core";
+ power-domains = <&gpc 1>;
+ };
+
timer@00a00600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x00a00600 0x20>;
@@ -155,6 +168,15 @@
clocks = <&clks IMX6QDL_CLK_TWD>;
};
+ intc: interrupt-controller@00a01000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x00a01000 0x1000>,
+ <0x00a00100 0x100>;
+ interrupt-parent = <&intc>;
+ };
+
L2: l2-cache@00a02000 {
compatible = "arm,pl310-cache";
reg = <0x00a02000 0x1000>;
@@ -173,8 +195,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
- ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* configuration space */
- 0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */
+ ranges = <0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
num-lanes = <1>;
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
@@ -227,7 +248,7 @@
"rxtx1", "rxtx2",
"rxtx3", "rxtx4",
"rxtx5", "rxtx6",
- "rxtx7", "dma";
+ "rxtx7", "spba";
status = "disabled";
};
@@ -309,7 +330,7 @@
<&clks IMX6QDL_CLK_ESAI_EXTAL>,
<&clks IMX6QDL_CLK_ESAI_IPG>,
<&clks IMX6QDL_CLK_SPBA>;
- clock-names = "core", "mem", "extal", "fsys", "dma";
+ clock-names = "core", "mem", "extal", "fsys", "spba";
dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
dma-names = "rx", "tx";
status = "disabled";
@@ -378,7 +399,7 @@
"asrck_1", "asrck_2", "asrck_3", "asrck_4",
"asrck_5", "asrck_6", "asrck_7", "asrck_8",
"asrck_9", "asrck_a", "asrck_b", "asrck_c",
- "asrck_d", "asrck_e", "asrck_f", "dma";
+ "asrck_d", "asrck_e", "asrck_f", "spba";
dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
dma-names = "rxa", "rxb", "rxc",
@@ -906,6 +927,9 @@
clocks = <&clks IMX6QDL_CLK_USBOH3>;
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -917,6 +941,9 @@
fsl,usbphy = <&usbphy2>;
fsl,usbmisc = <&usbmisc 1>;
dr_mode = "host";
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -927,6 +954,9 @@
clocks = <&clks IMX6QDL_CLK_USBOH3>;
fsl,usbmisc = <&usbmisc 2>;
dr_mode = "host";
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -937,6 +967,9 @@
clocks = <&clks IMX6QDL_CLK_USBOH3>;
fsl,usbmisc = <&usbmisc 3>;
dr_mode = "host";
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index d8ba99f1d87b..d12b250342a6 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -151,7 +151,7 @@
"rxtx1", "rxtx2",
"rxtx3", "rxtx4",
"rxtx5", "rxtx6",
- "rxtx7", "dma";
+ "rxtx7", "spba";
status = "disabled";
};
@@ -708,6 +708,9 @@
clocks = <&clks IMX6SL_CLK_USBOH3>;
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -718,6 +721,9 @@
clocks = <&clks IMX6SL_CLK_USBOH3>;
fsl,usbphy = <&usbphy2>;
fsl,usbmisc = <&usbmisc 1>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -728,6 +734,9 @@
clocks = <&clks IMX6SL_CLK_USBOH3>;
fsl,usbmisc = <&usbmisc 2>;
dr_mode = "host";
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 167f77b3bd43..a5f76025a0ce 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -222,7 +222,7 @@
"rxtx1", "rxtx2",
"rxtx3", "rxtx4",
"rxtx5", "rxtx6",
- "rxtx7", "dma";
+ "rxtx7", "spba";
status = "disabled";
};
@@ -295,7 +295,7 @@
<&clks IMX6SX_CLK_ESAI_IPG>,
<&clks IMX6SX_CLK_SPBA>;
clock-names = "core", "mem", "extal",
- "fsys", "dma";
+ "fsys", "spba";
status = "disabled";
};
@@ -348,7 +348,7 @@
<&clks IMX6SX_CLK_ASRC_IPG>,
<&clks IMX6SX_CLK_SPDIF>,
<&clks IMX6SX_CLK_SPBA>;
- clock-names = "mem", "ipg", "asrck", "dma";
+ clock-names = "mem", "ipg", "asrck", "spba";
dmas = <&sdma 17 20 1>, <&sdma 18 20 1>,
<&sdma 19 20 1>, <&sdma 20 20 1>,
<&sdma 21 20 1>, <&sdma 22 20 1>;
@@ -783,6 +783,9 @@
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
fsl,anatop = <&anatop>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -793,6 +796,9 @@
clocks = <&clks IMX6SX_CLK_USBOH3>;
fsl,usbphy = <&usbphy2>;
fsl,usbmisc = <&usbmisc 1>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -805,6 +811,9 @@
phy_type = "hsic";
fsl,anatop = <&anatop>;
dr_mode = "host";
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -1152,6 +1161,8 @@
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6SX_CLK_IPG>;
clock-names = "adc";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
status = "disabled";
};
@@ -1161,6 +1172,8 @@
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6SX_CLK_IPG>;
clock-names = "adc";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index d00e994bdbd2..99b646506fc9 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -548,6 +548,9 @@
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
fsl,anatop = <&anatop>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -558,6 +561,9 @@
clocks = <&clks IMX6UL_CLK_USBOH3>;
fsl,usbphy = <&usbphy2>;
fsl,usbmisc = <&usbmisc 1>;
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
status = "disabled";
};
@@ -619,6 +625,18 @@
status = "disabled";
};
+ adc1: adc@02198000 {
+ compatible = "fsl,imx6ul-adc", "fsl,vf610-adc";
+ reg = <0x02198000 0x4000>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6UL_CLK_ADC1>;
+ num-channels = <2>;
+ clock-names = "adc";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
+ status = "disabled";
+ };
+
i2c1: i2c@021a0000 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
new file mode 100644
index 000000000000..48634519d13a
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
@@ -0,0 +1,286 @@
+/*
+ * Support for CompuLab CL-SOM-iMX7 System-on-Module
+ *
+ * Copyright (C) 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Author: Ilya Ledvich <ilya@compulab.co.il>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "imx7d.dtsi"
+
+/ {
+ model = "CompuLab CL-SOM-iMX7";
+ compatible = "compulab,cl-som-imx7", "fsl,imx7d";
+
+ memory {
+ reg = <0x80000000 0x10000000>; /* 256 MB - minimal configuration */
+ };
+
+ reg_usb_otg1_vbus: regulator-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&cpu0 {
+ arm-supply = <&sw1a_reg>;
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1>;
+ assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>,
+ <&clks IMX7D_ENET1_TIME_ROOT_CLK>;
+ assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
+ assigned-clock-rates = <0>, <100000000>;
+ phy-mode = "rgmii";
+ phy-handle = <&ethphy0>;
+ fsl,magic-packet;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2>;
+ assigned-clocks = <&clks IMX7D_ENET2_TIME_ROOT_SRC>,
+ <&clks IMX7D_ENET2_TIME_ROOT_CLK>;
+ assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
+ assigned-clock-rates = <0>, <100000000>;
+ phy-mode = "rgmii";
+ phy-handle = <&ethphy1>;
+ fsl,magic-packet;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+
+ pmic: pmic@8 {
+ compatible = "fsl,pfuze3000";
+ reg = <0x08>;
+
+ regulators {
+ sw1a_reg: sw1a {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1475000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ /* use sw1c_reg to align with pfuze100/pfuze200 */
+ sw1c_reg: sw1b {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1475000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1850000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3a_reg: sw3 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1650000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ swbst_reg: swbst {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5150000>;
+ };
+
+ snvs_reg: vsnvs {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vref_reg: vrefddr {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vgen1_reg: vldo1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen2_reg: vldo2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen3_reg: vccsd {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen4_reg: v33 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen5_reg: vldo3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen6_reg: vldo4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+
+ pca9555: pca9555@20 {
+ compatible = "nxp,pca9555";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x20>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c08";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>;
+ assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+ status = "okay";
+};
+
+&usbotg1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg1>;
+ vbus-supply = <&reg_usb_otg1_vbus>;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
+ assigned-clock-rates = <400000000>;
+ bus-width = <8>;
+ fsl,tuning-step = <2>;
+ non-removable;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_enet1: enet1grp {
+ fsl,pins = <
+ MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x3
+ MX7D_PAD_SD2_WP__ENET1_MDC 0x3
+ MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1
+ MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1
+ MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1
+ MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1
+ MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1
+ MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1
+ MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1
+ MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1
+ MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1
+ MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1
+ MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1
+ MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1
+ >;
+ };
+
+ pinctrl_enet2: enet2grp {
+ fsl,pins = <
+ MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x1
+ MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x1
+ MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x1
+ MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x1
+ MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x1
+ MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x1
+ MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x1
+ MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x1
+ MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x1
+ MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x1
+ MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x1
+ MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX7D_PAD_I2C2_SDA__I2C2_SDA 0x4000007f
+ MX7D_PAD_I2C2_SCL__I2C2_SCL 0x4000007f
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79
+ MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x79
+ >;
+ };
+
+ pinctrl_usbotg1: usbotg1grp {
+ fsl,pins = <
+ MX7D_PAD_GPIO1_IO05__GPIO1_IO5 0x14 /* OTG PWREN */
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX7D_PAD_SD3_CMD__SD3_CMD 0x59
+ MX7D_PAD_SD3_CLK__SD3_CLK 0x19
+ MX7D_PAD_SD3_DATA0__SD3_DATA0 0x59
+ MX7D_PAD_SD3_DATA1__SD3_DATA1 0x59
+ MX7D_PAD_SD3_DATA2__SD3_DATA2 0x59
+ MX7D_PAD_SD3_DATA3__SD3_DATA3 0x59
+ MX7D_PAD_SD3_DATA4__SD3_DATA4 0x59
+ MX7D_PAD_SD3_DATA5__SD3_DATA5 0x59
+ MX7D_PAD_SD3_DATA6__SD3_DATA6 0x59
+ MX7D_PAD_SD3_DATA7__SD3_DATA7 0x59
+ MX7D_PAD_SD3_STROBE__SD3_STROBE 0x19
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx7d-sbc-imx7.dts b/arch/arm/boot/dts/imx7d-sbc-imx7.dts
new file mode 100644
index 000000000000..d63c597c0783
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d-sbc-imx7.dts
@@ -0,0 +1,42 @@
+/*
+ * Support for CompuLab SBC-iMX7 Single Board Computer
+ *
+ * Copyright (C) 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Author: Ilya Ledvich <ilya@compulab.co.il>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ */
+
+#include "imx7d-cl-som-imx7.dts"
+
+/ {
+ model = "CompuLab SBC-iMX7";
+ compatible = "compulab,sbc-imx7", "compulab,cl-som-imx7", "fsl,imx7d";
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+ enable-sdio-wakeup;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX7D_PAD_SD1_CMD__SD1_CMD 0x59
+ MX7D_PAD_SD1_CLK__SD1_CLK 0x19
+ MX7D_PAD_SD1_DATA0__SD1_DATA0 0x59
+ MX7D_PAD_SD1_DATA1__SD1_DATA1 0x59
+ MX7D_PAD_SD1_DATA2__SD1_DATA2 0x59
+ MX7D_PAD_SD1_DATA3__SD1_DATA3 0x59
+ MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x59 /* CD */
+ MX7D_PAD_SD1_WP__GPIO5_IO1 0x59 /* WP */
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
index 432aaf5d5ef7..b2c453662905 100644
--- a/arch/arm/boot/dts/imx7d-sdb.dts
+++ b/arch/arm/boot/dts/imx7d-sdb.dts
@@ -97,6 +97,16 @@
};
};
+&adc1 {
+ vref-supply = <&reg_vref_1v8>;
+ status = "okay";
+};
+
+&adc2 {
+ vref-supply = <&reg_vref_1v8>;
+ status = "okay";
+};
+
&cpu0 {
arm-supply = <&sw1a_reg>;
};
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index ebc053a06405..25ad30978740 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -85,9 +85,7 @@
792000 975000
>;
clock-latency = <61036>; /* two CLK32 periods */
- clocks = <&clks IMX7D_ARM_A7_ROOT_CLK>, <&clks IMX7D_ARM_A7_ROOT_SRC>,
- <&clks IMX7D_PLL_ARM_MAIN_CLK>, <&clks IMX7D_PLL_SYS_MAIN_CLK>;
- clock-names = "arm", "arm_root_src", "pll_arm", "pll_sys_main";
+ clocks = <&clks IMX7D_CLK_ARM>;
};
cpu1: cpu@1 {
@@ -583,6 +581,24 @@
reg = <0x30400000 0x400000>;
ranges;
+ adc1: adc@30610000 {
+ compatible = "fsl,imx7d-adc";
+ reg = <0x30610000 0x10000>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_ADC_ROOT_CLK>;
+ clock-names = "adc";
+ status = "disabled";
+ };
+
+ adc2: adc@30620000 {
+ compatible = "fsl,imx7d-adc";
+ reg = <0x30620000 0x10000>;
+ interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_ADC_ROOT_CLK>;
+ clock-names = "adc";
+ status = "disabled";
+ };
+
pwm1: pwm@30660000 {
compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm";
reg = <0x30660000 0x10000>;
diff --git a/arch/arm/boot/dts/kirkwood-nsa325.dts b/arch/arm/boot/dts/kirkwood-nsa325.dts
new file mode 100644
index 000000000000..bc4ec9332387
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-nsa325.dts
@@ -0,0 +1,238 @@
+/* Device tree file for the Zyxel NSA 325 NAS box.
+ *
+ * Copyright (c) 2015, Hans Ulli Kroll <ulli.kroll@googlemail.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.
+ *
+ * Based upon the board setup file created by Peter Schildmann
+ */
+
+/dts-v1/;
+
+#include "kirkwood-nsa3x0-common.dtsi"
+
+/ {
+ model = "ZyXEL NSA325";
+ compatible = "zyxel,nsa325", "marvell,kirkwood-88f6282", "marvell,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ mbus {
+ pcie-controller {
+ status = "okay";
+
+ pcie@1,0 {
+ status = "okay";
+ };
+ };
+ };
+
+ ocp@f1000000 {
+ pinctrl: pin-controller@10000 {
+ pinctrl-names = "default";
+
+ pmx_led_hdd2_green: pmx-led-hdd2-green {
+ marvell,pins = "mpp12";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_hdd2_red: pmx-led-hdd2-red {
+ marvell,pins = "mpp13";
+ marvell,function = "gpio";
+ };
+
+ pmx_mcu_data: pmx-mcu-data {
+ marvell,pins = "mpp14";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_usb_green: pmx-led-usb-green {
+ marvell,pins = "mpp15";
+ marvell,function = "gpio";
+ };
+
+ pmx_mcu_clk: pmx-mcu-clk {
+ marvell,pins = "mpp16";
+ marvell,function = "gpio";
+ };
+
+ pmx_mcu_act: pmx-mcu-act {
+ marvell,pins = "mpp17";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_sys_green: pmx-led-sys-green {
+ marvell,pins = "mpp28";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_sys_orange: pmx-led-sys-orange {
+ marvell,pins = "mpp29";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_hdd1_green: pmx-led-hdd1-green {
+ marvell,pins = "mpp41";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_hdd1_red: pmx-led-hdd1-red {
+ marvell,pins = "mpp42";
+ marvell,function = "gpio";
+ };
+
+ pmx_htp: pmx-htp {
+ marvell,pins = "mpp43";
+ marvell,function = "gpio";
+ };
+
+ /*
+ * Buzzer needs to be switched at around 1kHz so is
+ * not compatible with the gpio-beeper driver.
+ */
+ pmx_buzzer: pmx-buzzer {
+ marvell,pins = "mpp44";
+ marvell,function = "gpio";
+ };
+
+ pmx_vid_b1: pmx-vid-b1 {
+ marvell,pins = "mpp45";
+ marvell,function = "gpio";
+ };
+
+ pmx_power_resume_data: pmx-power-resume-data {
+ marvell,pins = "mpp47";
+ marvell,function = "gpio";
+ };
+
+ pmx_power_resume_clk: pmx-power-resume-clk {
+ marvell,pins = "mpp49";
+ marvell,function = "gpio";
+ };
+
+ pmx_pwr_sata1: pmx-pwr-sata1 {
+ marvell,pins = "mpp47";
+ marvell,function = "gpio";
+ };
+ };
+
+ /* This board uses the pcf8563 RTC instead of the SoC RTC */
+ rtc@10300 {
+ status = "disabled";
+ };
+
+ i2c@11000 {
+ status = "okay";
+
+ pcf8563: pcf8563@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&pmx_pwr_sata1>;
+ pinctrl-names = "default";
+
+ usb0_power: regulator@1 {
+ enable-active-high;
+ };
+
+ sata1_power: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "SATA1 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&pmx_led_hdd2_green &pmx_led_hdd2_red
+ &pmx_led_usb_green
+ &pmx_led_sys_green &pmx_led_sys_orange
+ &pmx_led_copy_green &pmx_led_copy_red
+ &pmx_led_hdd1_green &pmx_led_hdd1_red>;
+ pinctrl-names = "default";
+
+ green-sys {
+ label = "nsa325:green:sys";
+ gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
+ };
+ orange-sys {
+ label = "nsa325:orange:sys";
+ gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
+ };
+ green-hdd1 {
+ label = "nsa325:green:hdd1";
+ gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+ };
+ red-hdd1 {
+ label = "nsa325:red:hdd1";
+ gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+ };
+ green-hdd2 {
+ label = "nsa325:green:hdd2";
+ gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ };
+ red-hdd2 {
+ label = "nsa325:red:hdd2";
+ gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
+ };
+ green-usb {
+ label = "nsa325:green:usb";
+ gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
+ };
+ green-copy {
+ label = "nsa325:green:copy";
+ gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+ };
+ red-copy {
+ label = "nsa325:red:copy";
+ gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+ };
+
+ /* The following pins are currently not assigned to a driver,
+ some of them should be configured as inputs.
+ pinctrl-0 = <&pmx_mcu_data &pmx_mcu_clk &pmx_mcu_act
+ &pmx_htp &pmx_vid_b1
+ &pmx_power_resume_data &pmx_power_resume_clk>; */
+ };
+
+
+};
+
+&mdio {
+ status = "okay";
+ ethphy0: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&eth0 {
+ status = "okay";
+ ethernet0-port@0 {
+ phy-handle = <&ethphy0>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts b/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts
new file mode 100644
index 000000000000..1db6f2c506cc
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts
@@ -0,0 +1,178 @@
+/*
+ * kirkwood-pogoplug-series-4.dts - Device tree file for PogoPlug Series 4
+ * inspired by the board files made by Kevin Mihelich for ArchLinux,
+ * and their DTS file.
+ *
+ * Copyright (C) 2015 Linus Walleij <linus.walleij@linaro.org>
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6192.dtsi"
+#include <dt-bindings/input/linux-event-codes.h>
+
+/ {
+ model = "Cloud Engines PogoPlug Series 4";
+ compatible = "cloudengines,pogoplugv4", "marvell,kirkwood-88f6192",
+ "marvell,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>;
+ };
+
+ chosen {
+ stdout-path = "uart0:115200n8";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&pmx_button_eject>;
+ pinctrl-names = "default";
+
+ button@1 {
+ debounce_interval = <50>;
+ wakeup-source;
+ linux,code = <KEY_EJECTCD>;
+ label = "Eject Button";
+ gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&pmx_led_green &pmx_led_red>;
+ pinctrl-names = "default";
+
+ health {
+ label = "pogoplugv4:green:health";
+ gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ };
+ fault {
+ label = "pogoplugv4:red:fault";
+ gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&pinctrl {
+ pmx_sata0: pmx-sata0 {
+ marvell,pins = "mpp21";
+ marvell,function = "sata0";
+ };
+
+ pmx_sata1: pmx-sata1 {
+ marvell,pins = "mpp20";
+ marvell,function = "sata1";
+ };
+
+ pmx_sdio_cd: pmx-sdio-cd {
+ marvell,pins = "mpp27";
+ marvell,function = "gpio";
+ };
+
+ pmx_sdio_wp: pmx-sdio-wp {
+ marvell,pins = "mpp28";
+ marvell,function = "gpio";
+ };
+
+ pmx_button_eject: pmx-button-eject {
+ marvell,pins = "mpp29";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_green: pmx-led-green {
+ marvell,pins = "mpp22";
+ marvell,function = "gpio";
+ };
+
+ pmx_led_red: pmx-led-red {
+ marvell,pins = "mpp24";
+ marvell,function = "gpio";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+/*
+ * This PCIE controller has a USB 3.0 XHCI controller at 1,0
+ */
+&pciec {
+ status = "okay";
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+ pinctrl-0 = <&pmx_sata0 &pmx_sata1>;
+ pinctrl-names = "default";
+ nr-ports = <1>;
+};
+
+&sdio {
+ status = "okay";
+ pinctrl-0 = <&pmx_sdio &pmx_sdio_cd &pmx_sdio_wp>;
+ pinctrl-names = "default";
+ cd-gpios = <&gpio0 27 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
+};
+
+&nand {
+ /* 128 MiB of NAND flash */
+ chip-delay = <40>;
+ status = "okay";
+ partitions {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x00000000 0x200000>;
+ read-only;
+ };
+
+ partition@200000 {
+ label = "uImage";
+ reg = <0x00200000 0x300000>;
+ };
+
+ partition@500000 {
+ label = "uImage2";
+ reg = <0x00500000 0x300000>;
+ };
+
+ partition@800000 {
+ label = "failsafe";
+ reg = <0x00800000 0x800000>;
+ };
+
+ partition@1000000 {
+ label = "root";
+ reg = <0x01000000 0x7000000>;
+ };
+ };
+};
+
+&mdio {
+ status = "okay";
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+};
+
+&eth0 {
+ status = "okay";
+ ethernet0-port@0 {
+ phy-handle = <&ethphy0>;
+ };
+};
diff --git a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
index 5b0430041ec6..fb13f18c08cc 100644
--- a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
+++ b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
@@ -23,31 +23,37 @@
label = "sysboot2";
gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* gpio2 */
linux,code = <BTN_0>;
- gpio-key,wakeup;
+ wakeup-source;
};
sysboot5 {
label = "sysboot5";
gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; /* gpio7 */
linux,code = <BTN_1>;
- gpio-key,wakeup;
+ wakeup-source;
};
gpio1 {
label = "gpio1";
gpios = <&gpio6 21 GPIO_ACTIVE_LOW>; /* gpio181 */
linux,code = <BTN_2>;
- gpio-key,wakeup;
+ wakeup-source;
};
gpio2 {
label = "gpio2";
gpios = <&gpio6 18 GPIO_ACTIVE_LOW>; /* gpio178 */
linux,code = <BTN_3>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
+ sound {
+ compatible = "ti,omap-twl4030";
+ ti,model = "omap3logic";
+ ti,mcbsp = <&mcbsp2>;
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
@@ -67,6 +73,20 @@
};
};
+&vaux1 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+};
+
+&vaux4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+};
+
+&mcbsp2 {
+ status = "okay";
+};
+
&charger {
ti,bb-uvolt = <3200000>;
ti,bb-uamp = <150>;
@@ -84,6 +104,70 @@
};
};
+&vpll2 {
+ regulator-always-on;
+};
+
+&dss {
+ status = "ok";
+ vdds_dsi-supply = <&vpll2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dss_dpi_pins1>;
+ port {
+ dpi_out: endpoint {
+ remote-endpoint = <&lcd_in>;
+ data-lines = <16>;
+ };
+ };
+};
+
+/ {
+ aliases {
+ display0 = &lcd0;
+ };
+
+ lcd0: display@0 {
+ compatible = "panel-dpi";
+ label = "15";
+ status = "okay";
+ /* default-on; */
+ pinctrl-names = "default";
+ enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd INI */
+
+ port {
+ lcd_in: endpoint {
+ remote-endpoint = <&dpi_out>;
+ };
+ };
+
+ panel-timing {
+ clock-frequency = <9000000>;
+ hactive = <480>;
+ vactive = <272>;
+ hfront-porch = <3>;
+ hback-porch = <2>;
+ hsync-len = <42>;
+ vback-porch = <3>;
+ vfront-porch = <4>;
+ vsync-len = <11>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <1>;
+ };
+ };
+
+ bl: backlight {
+ compatible = "gpio-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&backlight_pins>;
+
+ gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>, /* gpio_56 */
+ <&gpio5 26 GPIO_ACTIVE_HIGH>; /* gpio_154 */
+ default-on;
+ };
+};
+
&mmc1 {
interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>;
pinctrl-names = "default";
@@ -119,6 +203,48 @@
OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
>;
};
+
+ tsc2004_pins: pinmux_tsc2004_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2186, PIN_INPUT | MUX_MODE4) /* mcbsp4_dr.gpio_153 */
+ >;
+ };
+
+ backlight_pins: pinmux_backlight_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20B8, PIN_OUTPUT | MUX_MODE4) /* gpmc_ncs5.gpio_56 */
+ OMAP3_CORE1_IOPAD(0x2188, PIN_OUTPUT | MUX_MODE4) /* mcbsp4_dx.gpio_154 */
+ >;
+ };
+
+ dss_dpi_pins1: pinmux_dss_dpi_pins1 {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+
+ OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+
+ OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE3) /* dss_data18.dss_data0 */
+ OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE3) /* dss_data19.dss_data1 */
+ OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE3) /* dss_data20.dss_data2 */
+ OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE3) /* dss_data21.dss_data3 */
+ OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE3) /* dss_data22.dss_data4 */
+ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE3) /* dss_data23.dss_data5 */
+ >;
+ };
};
&omap3_pmx_wkup {
@@ -142,6 +268,27 @@
};
};
+&i2c3 {
+ touchscreen: tsc2004@48 {
+ compatible = "ti,tsc2004";
+ reg = <0x48>;
+ vio-supply = <&vaux1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tsc2004_pins>;
+ interrupts-extended = <&gpio5 25 IRQ_TYPE_EDGE_RISING>; /* gpio 153 */
+
+ touchscreen-fuzz-x = <4>;
+ touchscreen-fuzz-y = <7>;
+ touchscreen-fuzz-pressure = <2>;
+ touchscreen-size-x = <4096>;
+ touchscreen-size-y = <4096>;
+ touchscreen-max-pressure = <2048>;
+
+ ti,x-plate-ohms = <280>;
+ ti,esd-recovery-timeout-ms = <8000>;
+ };
+};
+
&uart1 {
interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>;
};
diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
index 36387b11451d..7fed0bd4f3de 100644
--- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
+++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
@@ -96,9 +96,30 @@
reg = <0x48>;
interrupts = <7>; /* SYS_NIRQ cascaded to intc */
interrupt-parent = <&intc>;
+ twl_audio: audio {
+ compatible = "ti,twl4030-audio";
+ codec {
+ };
+ };
};
};
+&i2c2 {
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ clock-frequency = <400000>;
+};
+
+&i2c2 {
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ clock-frequency = <400000>;
+};
+
/*
* Only found on the wireless SOM. For the SOM without wireless, the pins for
* MMC3 can be routed with jumpers to the second MMC slot on the devkit and
@@ -136,6 +157,29 @@
OMAP3_CORE1_IOPAD(0x218e, PIN_OUTPUT | MUX_MODE4) /* mcbsp1_fsr.gpio_157 */
>;
};
+ mcbsp2_pins: pinmux_mcbsp2_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x213c, PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx */
+ OMAP3_CORE1_IOPAD(0x213e, PIN_INPUT | MUX_MODE0) /* mcbsp2_clkx */
+ OMAP3_CORE1_IOPAD(0x2140, PIN_INPUT | MUX_MODE0) /* mcbsp2_dr */
+ OMAP3_CORE1_IOPAD(0x2142, PIN_OUTPUT | MUX_MODE0) /* mcbsp2_dx */
+ >;
+ };
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT | MUX_MODE0) /* uart2_cts.uart2_cts */
+ OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts .uart2_rts*/
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
+ OMAP3_CORE1_IOPAD(0x2198, PIN_OUTPUT | MUX_MODE4) /* GPIO_162,BT_EN */
+ >;
+ };
+};
+
+&uart2 {
+ interrupts-extended = <&intc 73 &omap3_pmx_core OMAP3_UART2_RX>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
};
&omap3_pmx_core2 {
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index 52591d83e8cd..053a1f54f4bb 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -166,6 +166,17 @@
status = "disabled";
};
+ eeprom: eeprom@4000e000 {
+ compatible = "nxp,lpc1857-eeprom";
+ reg = <0x4000e000 0x1000>, <0x20040000 0x4000>;
+ reg-names = "reg", "mem";
+ clocks = <&ccu1 CLK_CPU_EEPROM>;
+ clock-names = "eeprom";
+ resets = <&rgu 27>;
+ interrupts = <4>;
+ status = "disabled";
+ };
+
mac: ethernet@40010000 {
compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac";
reg = <0x40010000 0x2000>;
diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi
index 3abebb75fc57..c85cf979725e 100644
--- a/arch/arm/boot/dts/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/lpc32xx.dtsi
@@ -11,19 +11,20 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
/ {
compatible = "nxp,lpc3220";
interrupt-parent = <&mic>;
cpus {
- #address-cells = <0>;
+ #address-cells = <1>;
#size-cells = <0>;
- cpu {
+ cpu@0 {
compatible = "arm,arm926ej-s";
device_type = "cpu";
+ reg = <0x0>;
};
};
@@ -31,7 +32,8 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
- ranges = <0x20000000 0x20000000 0x30000000>;
+ ranges = <0x20000000 0x20000000 0x30000000>,
+ <0xe0000000 0xe0000000 0x04000000>;
/*
* Enable either SLC or MLC
@@ -49,30 +51,46 @@
status = "disabled";
};
- dma@31000000 {
+ dma: dma@31000000 {
compatible = "arm,pl080", "arm,primecell";
reg = <0x31000000 0x1000>;
interrupts = <0x1c 0>;
};
- /*
- * Enable either ohci or usbd (gadget)!
- */
- ohci@31020000 {
- compatible = "nxp,ohci-nxp", "usb-ohci";
- reg = <0x31020000 0x300>;
- interrupts = <0x3b 0>;
- status = "disabled";
- };
+ usb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x31020000 0x00001000>;
- usbd@31020000 {
- compatible = "nxp,lpc3220-udc";
- reg = <0x31020000 0x300>;
- interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
- status = "disabled";
+ /*
+ * Enable either ohci or usbd (gadget)!
+ */
+ ohci: ohci@0 {
+ compatible = "nxp,ohci-nxp", "usb-ohci";
+ reg = <0x0 0x300>;
+ interrupts = <0x3b 0>;
+ status = "disabled";
+ };
+
+ usbd: usbd@0 {
+ compatible = "nxp,lpc3220-udc";
+ reg = <0x0 0x300>;
+ interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+ status = "disabled";
+ };
+
+ i2cusb: i2c@300 {
+ compatible = "nxp,pnx-i2c";
+ reg = <0x300 0x100>;
+ interrupts = <0x3f 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pnx,timeout = <0x64>;
+ };
};
- clcd@31040000 {
+ clcd: clcd@31040000 {
compatible = "arm,pl110", "arm,primecell";
reg = <0x31040000 0x1000>;
interrupts = <0x0e 0>;
@@ -85,6 +103,19 @@
interrupts = <0x1d 0>;
};
+ emc: memory-controller@31080000 {
+ compatible = "arm,pl175", "arm,primecell";
+ reg = <0x31080000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ranges = <0 0xe0000000 0x01000000>,
+ <1 0xe1000000 0x01000000>,
+ <2 0xe2000000 0x01000000>,
+ <3 0xe3000000 0x01000000>;
+ status = "disabled";
+ };
+
apb {
#address-cells = <1>;
#size-cells = <1>;
@@ -118,7 +149,7 @@
reg = <0x20094000 0x1000>;
};
- sd@20098000 {
+ sd: sd@20098000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x20098000 0x1000>;
interrupts = <0x0f 0>, <0x0d 0>;
@@ -192,15 +223,6 @@
status = "disabled";
#pwm-cells = <2>;
};
-
- i2cusb: i2c@31020300 {
- compatible = "nxp,pnx-i2c";
- reg = <0x31020300 0x100>;
- interrupts = <0x3f 0>;
- #address-cells = <1>;
- #size-cells = <0>;
- pnx,timeout = <0x64>;
- };
};
fab {
@@ -243,7 +265,7 @@
status = "disabled";
};
- rtc@40024000 {
+ rtc: rtc@40024000 {
compatible = "nxp,lpc3220-rtc";
reg = <0x40024000 0x1000>;
interrupts = <0x34 0>;
@@ -256,11 +278,31 @@
#gpio-cells = <3>; /* bank, pin, flags */
};
- watchdog@4003C000 {
+ timer4: timer@4002C000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x4002C000 0x1000>;
+ interrupts = <0x3 0>;
+ status = "disabled";
+ };
+
+ timer5: timer@40030000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40030000 0x1000>;
+ interrupts = <0x4 0>;
+ status = "disabled";
+ };
+
+ watchdog: watchdog@4003C000 {
compatible = "nxp,pnx4008-wdt";
reg = <0x4003C000 0x1000>;
};
+ timer0: timer@40044000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40044000 0x1000>;
+ interrupts = <0x10 0>;
+ };
+
/*
* TSC vs. ADC: Since those two share the same
* hardware, you need to choose from one of the
@@ -268,30 +310,56 @@
* them
*/
- adc@40048000 {
+ adc: adc@40048000 {
compatible = "nxp,lpc3220-adc";
reg = <0x40048000 0x1000>;
interrupts = <0x27 0>;
status = "disabled";
};
- tsc@40048000 {
+ tsc: tsc@40048000 {
compatible = "nxp,lpc3220-tsc";
reg = <0x40048000 0x1000>;
interrupts = <0x27 0>;
status = "disabled";
};
- key@40050000 {
+ timer1: timer@4004C000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x4004C000 0x1000>;
+ interrupts = <0x11 0>;
+ };
+
+ key: key@40050000 {
compatible = "nxp,lpc3220-key";
reg = <0x40050000 0x1000>;
interrupts = <54 0>;
status = "disabled";
};
- pwm: pwm@4005C000 {
+ timer2: timer@40058000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40058000 0x1000>;
+ interrupts = <0x12 0>;
+ status = "disabled";
+ };
+
+ pwm1: pwm@4005C000 {
compatible = "nxp,lpc3220-pwm";
- reg = <0x4005C000 0x8>;
+ reg = <0x4005C000 0x4>;
+ status = "disabled";
+ };
+
+ pwm2: pwm@4005C004 {
+ compatible = "nxp,lpc3220-pwm";
+ reg = <0x4005C004 0x4>;
+ status = "disabled";
+ };
+
+ timer3: timer@40060000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40060000 0x1000>;
+ interrupts = <0x13 0>;
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/lpc4337-ciaa.dts b/arch/arm/boot/dts/lpc4337-ciaa.dts
index 5f500c1ad89c..5cfadb06c8df 100644
--- a/arch/arm/boot/dts/lpc4337-ciaa.dts
+++ b/arch/arm/boot/dts/lpc4337-ciaa.dts
@@ -99,6 +99,14 @@
};
};
+ i2c0_pins: i2c0-pins {
+ i2c0_pins_cfg {
+ pins = "i2c0_scl", "i2c0_sda";
+ function = "i2c0";
+ input-enable;
+ };
+ };
+
ssp_pins: ssp-pins {
ssp1_cs {
pins = "p6_7";
@@ -159,6 +167,28 @@
clock-frequency = <50000000>;
};
+&i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ clock-frequency = <400000>;
+
+ eeprom@50 {
+ compatible = "microchip,24c512";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "microchip,24c02";
+ reg = <0x51>;
+ };
+
+ eeprom@54 {
+ compatible = "microchip,24c512";
+ reg = <0x54>;
+ };
+};
+
&mac {
status = "okay";
phy-mode = "rmii";
@@ -166,6 +196,10 @@
pinctrl-0 = <&enet_rmii_pins>;
};
+&sct_pwm {
+ status = "okay";
+};
+
&ssp1 {
status = "okay";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
index 391121d24daa..079d3cf8c00b 100644
--- a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
+++ b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
@@ -467,6 +467,11 @@
pinctrl-0 = <&i2c0_pins>;
clock-frequency = <400000>;
+ mma7455@1d {
+ compatible = "fsl,mma7455";
+ reg = <0x1d>;
+ };
+
lm75@48 {
compatible = "nxp,lm75";
reg = <0x48>;
diff --git a/arch/arm/boot/dts/lpc4357.dtsi b/arch/arm/boot/dts/lpc4357.dtsi
index fb9ecc754e8d..72f12db8d53a 100644
--- a/arch/arm/boot/dts/lpc4357.dtsi
+++ b/arch/arm/boot/dts/lpc4357.dtsi
@@ -37,3 +37,7 @@
};
};
};
+
+&eeprom {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts
index 0521e6864cb7..940875316d0f 100644
--- a/arch/arm/boot/dts/ls1021a-qds.dts
+++ b/arch/arm/boot/dts/ls1021a-qds.dts
@@ -320,6 +320,10 @@
status = "okay";
};
+&sata {
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts
index fbb89d13401e..75ecaed32ae5 100644
--- a/arch/arm/boot/dts/ls1021a-twr.dts
+++ b/arch/arm/boot/dts/ls1021a-twr.dts
@@ -105,6 +105,15 @@
bitclock-master;
};
};
+
+ panel: panel {
+ compatible = "nec,nl4827hc19-05b";
+ };
+};
+
+&dcu {
+ fsl,panel = <&panel>;
+ status = "okay";
};
&dspi1 {
@@ -212,6 +221,10 @@
status = "okay";
};
+&sata {
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 9430a9928199..2c84ca236473 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -143,6 +143,17 @@
status = "disabled";
};
+ sata: sata@3200000 {
+ compatible = "fsl,ls1021a-ahci";
+ reg = <0x0 0x3200000 0x0 0x10000>,
+ <0x0 0x20220520 0x0 0x4>;
+ reg-names = "ahci", "sata-ecc";
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ dma-coherent;
+ status = "disabled";
+ };
+
scfg: scfg@1570000 {
compatible = "fsl,ls1021a-scfg", "syscon";
reg = <0x0 0x1570000 0x0 0x10000>;
@@ -428,6 +439,16 @@
<&platform_clk 1>;
};
+ dcu: dcu@2ce0000 {
+ compatible = "fsl,ls1021a-dcu";
+ reg = <0x0 0x2ce0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 0>;
+ clock-names = "dcu";
+ big-endian;
+ status = "disabled";
+ };
+
mdio0: mdio@2d24000 {
compatible = "gianfar";
device_type = "mdio";
diff --git a/arch/arm/boot/dts/meson8b-odroidc1.dts b/arch/arm/boot/dts/meson8b-odroidc1.dts
index a8e2911b2cbe..e50f1a1fdbc7 100644
--- a/arch/arm/boot/dts/meson8b-odroidc1.dts
+++ b/arch/arm/boot/dts/meson8b-odroidc1.dts
@@ -46,6 +46,7 @@
/dts-v1/;
#include "meson8b.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Hardkernel ODROID-C1";
@@ -58,6 +59,16 @@
memory {
reg = <0x40000000 0x40000000>;
};
+
+ leds {
+ compatible = "gpio-leds";
+ blue {
+ label = "c1:blue:alive";
+ gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+ };
};
&uart_AO {
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index ee352bf687ff..8bad5571af46 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -105,6 +105,12 @@
#interrupt-cells = <3>;
};
+ wdt: watchdog@c1109900 {
+ compatible = "amlogic,meson8b-wdt";
+ reg = <0xc1109900 0x8>;
+ interrupts = <0 0 1>;
+ };
+
timer@c1109940 {
compatible = "amlogic,meson6-timer";
reg = <0xc1109940 0x18>;
diff --git a/arch/arm/mach-netx/include/mach/param.h b/arch/arm/boot/dts/mt2701-evb.dts
index a771459206aa..082ca8807c62 100644
--- a/arch/arm/mach-netx/include/mach/param.h
+++ b/arch/arm/boot/dts/mt2701-evb.dts
@@ -1,18 +1,29 @@
/*
- * arch/arm/mach-netx/include/mach/param.h
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Erin Lo <erin.lo@mediatek.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.
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
+/dts-v1/;
+#include "mt2701.dtsi"
+
+/ {
+ model = "MediaTek MT2701 evaluation board";
+ compatible = "mediatek,mt2701-evb", "mediatek,mt2701";
+
+ memory {
+ reg = <0 0x80000000 0 0x40000000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
new file mode 100644
index 000000000000..3766904b60f3
--- /dev/null
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Erin.Lo <erin.lo@mediatek.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 <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "skeleton64.dtsi"
+
+/ {
+ compatible = "mediatek,mt2701";
+ interrupt-parent = <&sysirq>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x1>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x3>;
+ };
+ };
+
+ system_clk: dummy13m {
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ #clock-cells = <0>;
+ };
+
+ rtc_clk: dummy32k {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+
+ uart_clk: dummy26m {
+ compatible = "fixed-clock";
+ clock-frequency = <26000000>;
+ #clock-cells = <0>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ watchdog: watchdog@10007000 {
+ compatible = "mediatek,mt2701-wdt",
+ "mediatek,mt6589-wdt";
+ reg = <0 0x10007000 0 0x100>;
+ };
+
+ timer: timer@10008000 {
+ compatible = "mediatek,mt2701-timer",
+ "mediatek,mt6577-timer";
+ reg = <0 0x10008000 0 0x80>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&system_clk>, <&rtc_clk>;
+ clock-names = "system-clk", "rtc-clk";
+ };
+
+ sysirq: interrupt-controller@10200100 {
+ compatible = "mediatek,mt2701-sysirq",
+ "mediatek,mt6577-sysirq";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ reg = <0 0x10200100 0 0x1c>;
+ };
+
+ gic: interrupt-controller@10211000 {
+ compatible = "arm,cortex-a7-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ reg = <0 0x10211000 0 0x1000>,
+ <0 0x10212000 0 0x1000>,
+ <0 0x10214000 0 0x2000>,
+ <0 0x10216000 0 0x2000>;
+ };
+
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt2701-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11002000 0 0x400>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart1: serial@11003000 {
+ compatible = "mediatek,mt2701-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11003000 0 0x400>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart2: serial@11004000 {
+ compatible = "mediatek,mt2701-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11004000 0 0x400>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart3: serial@11005000 {
+ compatible = "mediatek,mt2701-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11005000 0 0x400>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
index cb99b02d2ccc..1d7f92bdcb9c 100644
--- a/arch/arm/boot/dts/mt8135.dtsi
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -15,7 +15,7 @@
#include <dt-bindings/clock/mt8135-clk.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <dt-bindings/reset-controller/mt8135-resets.h>
+#include <dt-bindings/reset/mt8135-resets.h>
#include "skeleton64.dtsi"
#include "mt8135-pinfunc.h"
diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
index 73f1e3a8f62c..01e1e2d5c735 100644
--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
+++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
@@ -69,7 +69,7 @@
label = "user";
gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
linux,code = <0x114>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
@@ -176,18 +176,18 @@
&omap3_pmx_wkup {
gpio1_pins: pinmux_gpio1_pins {
pinctrl-single,pins = <
- 0x0e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE4) /* sys_boot2.gpio_4 */
+ OMAP3_WKUP_IOPAD(0x2a0e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE4) /* sys_boot2.gpio_4 */
>;
};
dss_dpi_pins2: pinmux_dss_dpi_pins1 {
pinctrl-single,pins = <
- 0x0a (PIN_OUTPUT | MUX_MODE3) /* sys_boot0.dss_data18 */
- 0x0c (PIN_OUTPUT | MUX_MODE3) /* sys_boot1.dss_data19 */
- 0x10 (PIN_OUTPUT | MUX_MODE3) /* sys_boot3.dss_data20 */
- 0x12 (PIN_OUTPUT | MUX_MODE3) /* sys_boot4.dss_data21 */
- 0x14 (PIN_OUTPUT | MUX_MODE3) /* sys_boot5.dss_data22 */
- 0x16 (PIN_OUTPUT | MUX_MODE3) /* sys_boot6.dss_data23 */
+ OMAP3_WKUP_IOPAD(0x2a0a, PIN_OUTPUT | MUX_MODE3) /* sys_boot0.dss_data18 */
+ OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE3) /* sys_boot1.dss_data19 */
+ OMAP3_WKUP_IOPAD(0x2a10, PIN_OUTPUT | MUX_MODE3) /* sys_boot3.dss_data20 */
+ OMAP3_WKUP_IOPAD(0x2a12, PIN_OUTPUT | MUX_MODE3) /* sys_boot4.dss_data21 */
+ OMAP3_WKUP_IOPAD(0x2a14, PIN_OUTPUT | MUX_MODE3) /* sys_boot5.dss_data22 */
+ OMAP3_WKUP_IOPAD(0x2a16, PIN_OUTPUT | MUX_MODE3) /* sys_boot6.dss_data23 */
>;
};
};
@@ -200,8 +200,8 @@
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16e (PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx OUTPUT | MODE0 */
+ OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx OUTPUT | MODE0 */
>;
};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 274c2c482aaa..8ba465d57635 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -80,7 +80,7 @@
label = "user";
gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
linux,code = <0x114>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
@@ -171,7 +171,7 @@
&omap3_pmx_wkup {
gpio1_pins: pinmux_gpio1_pins {
pinctrl-single,pins = <
- 0x14 (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE4) /* sys_boot5.gpio_7 */
+ OMAP3_WKUP_IOPAD(0x2a14, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE4) /* sys_boot5.gpio_7 */
>;
};
};
@@ -195,47 +195,47 @@
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
+ OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
>;
};
tfp410_pins: pinmux_tfp410_pins {
pinctrl-single,pins = <
- 0x196 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */
+ OMAP3_CORE1_IOPAD(0x21c6, PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */
>;
};
dss_dpi_pins: pinmux_dss_dpi_pins {
pinctrl-single,pins = <
- 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
- 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
- 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
- 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
- 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
- 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
- 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
- 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
- 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
- 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
- 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
- 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
- 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
- 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
- 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
- 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
- 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
- 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
- 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
- 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
- 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
- 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
- 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
- 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
- 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
- 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
- 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
- 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
+ OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+ OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
+ OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
+ OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
+ OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
+ OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
+ OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
+ OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+ OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
+ OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
+ OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
+ OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
+ OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
+ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
>;
};
};
diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
index 8c813e77b17f..e5f7f5c92c1a 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
@@ -238,7 +238,7 @@
ti,debounce-tol = /bits/ 16 <10>;
ti,debounce-rep = /bits/ 16 <1>;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-devkit8000-common.dtsi b/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
index 9ca2865a83d6..86850bb311eb 100644
--- a/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
+++ b/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
@@ -64,7 +64,7 @@
label = "user";
gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
linux,code = <BTN_EXTRA>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi b/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
index 4813e96157b3..738910db5c0c 100644
--- a/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
+++ b/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
@@ -68,6 +68,6 @@
ti,keep-vref-on = <1>;
ti,settle-delay-usec = /bits/ 16 <150>;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts
index bb339d1648e0..ac188657a95d 100644
--- a/arch/arm/boot/dts/omap3-evm-37xx.dts
+++ b/arch/arm/boot/dts/omap3-evm-37xx.dts
@@ -66,48 +66,48 @@
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x114 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
- 0x116 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
- 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
- 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
- 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
- 0x120 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat4.sdmmc1_dat4 */
- 0x122 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat5.sdmmc1_dat5 */
- 0x124 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat6.sdmmc1_dat6 */
- 0x126 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat7.sdmmc1_dat7 */
+ OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
+ OMAP3_CORE1_IOPAD(0x2150, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat4.sdmmc1_dat4 */
+ OMAP3_CORE1_IOPAD(0x2152, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat5.sdmmc1_dat5 */
+ OMAP3_CORE1_IOPAD(0x2154, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat6.sdmmc1_dat6 */
+ OMAP3_CORE1_IOPAD(0x2156, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat7.sdmmc1_dat7 */
>;
};
/* NOTE: Clocked externally, needs INPUT also for sdmmc2_clk.sdmmc2_clk */
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
- 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
- 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
- 0x12e (WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
- 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
- 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
+ OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
+ OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
+ OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
+ OMAP3_CORE1_IOPAD(0x215e, WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
+ OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
+ OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16e (WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
+ OMAP3_CORE1_IOPAD(0x219e, WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
>;
};
wl12xx_gpio: pinmux_wl12xx_gpio {
pinctrl-single,pins = <
- 0x150 (PIN_OUTPUT | MUX_MODE4) /* uart1_cts.gpio_150 */
- 0x14e (PIN_INPUT | MUX_MODE4) /* uart1_rts.gpio_149 */
+ OMAP3_CORE1_IOPAD(0x2180, PIN_OUTPUT | MUX_MODE4) /* uart1_cts.gpio_150 */
+ OMAP3_CORE1_IOPAD(0x217e, PIN_INPUT | MUX_MODE4) /* uart1_rts.gpio_149 */
>;
};
smsc911x_pins: pinmux_smsc911x_pins {
pinctrl-single,pins = <
- 0x1a2 (PIN_INPUT | MUX_MODE4) /* mcspi1_cs2.gpio_176 */
+ OMAP3_CORE1_IOPAD(0x21d2, PIN_INPUT | MUX_MODE4) /* mcspi1_cs2.gpio_176 */
>;
};
};
@@ -115,12 +115,12 @@
&omap3_pmx_wkup {
dss_dpi_pins2: pinmux_dss_dpi_pins1 {
pinctrl-single,pins = <
- 0x0a (PIN_OUTPUT | MUX_MODE3) /* sys_boot0.dss_data18 */
- 0x0c (PIN_OUTPUT | MUX_MODE3) /* sys_boot1.dss_data19 */
- 0x10 (PIN_OUTPUT | MUX_MODE3) /* sys_boot3.dss_data20 */
- 0x12 (PIN_OUTPUT | MUX_MODE3) /* sys_boot4.dss_data21 */
- 0x14 (PIN_OUTPUT | MUX_MODE3) /* sys_boot5.dss_data22 */
- 0x16 (PIN_OUTPUT | MUX_MODE3) /* sys_boot6.dss_data23 */
+ OMAP3_WKUP_IOPAD(0x2a0a, PIN_OUTPUT | MUX_MODE3) /* sys_boot0.dss_data18 */
+ OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE3) /* sys_boot1.dss_data19 */
+ OMAP3_WKUP_IOPAD(0x2a10, PIN_OUTPUT | MUX_MODE3) /* sys_boot3.dss_data20 */
+ OMAP3_WKUP_IOPAD(0x2a12, PIN_OUTPUT | MUX_MODE3) /* sys_boot4.dss_data21 */
+ OMAP3_WKUP_IOPAD(0x2a14, PIN_OUTPUT | MUX_MODE3) /* sys_boot5.dss_data22 */
+ OMAP3_WKUP_IOPAD(0x2a16, PIN_OUTPUT | MUX_MODE3) /* sys_boot6.dss_data23 */
>;
};
};
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index e14d15e5abc8..5e2d6433d939 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -37,7 +37,7 @@
label = "aux";
linux,code = <169>;
gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index 3835e1569c29..33d6b4ead092 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -15,25 +15,17 @@
model = "IGEPv2 Rev. C (TI OMAP AM/DM37x)";
compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
- /* Regulator to trigger the WIFI_PDN signal of the Wifi module */
- lbee1usjyc_pdn: lbee1usjyc_pdn {
+ vmmcsdio_fixed: fixedregulator-mmcsdio {
compatible = "regulator-fixed";
- regulator-name = "regulator-lbee1usjyc-pdn";
+ regulator-name = "vmmcsdio_fixed";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>; /* gpio_138 - WIFI_PDN */
- startup-delay-us = <10000>;
- enable-active-high;
};
- /* Regulator to trigger the RESET_N_W signal of the Wifi module */
- lbee1usjyc_reset_n_w: lbee1usjyc_reset_n_w {
- compatible = "regulator-fixed";
- regulator-name = "regulator-lbee1usjyc-reset-n-w";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; /* gpio_139 - RESET_N_W */
- enable-active-high;
+ mmc2_pwrseq: mmc2_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>, /* gpio_139 - RESET_N_W */
+ <&gpio5 10 GPIO_ACTIVE_LOW>; /* gpio_138 - WIFI_PDN */
};
};
@@ -51,8 +43,8 @@
&mmc2 {
pinctrl-names = "default";
pinctrl-0 = <&mmc2_pins &lbee1usjyc_pins>;
- vmmc-supply = <&lbee1usjyc_pdn>;
- vmmc_aux-supply = <&lbee1usjyc_reset_n_w>;
+ vmmc-supply = <&vmmcsdio_fixed>;
+ mmc-pwrseq = <&mmc2_pwrseq>;
bus-width = <4>;
non-removable;
};
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 468608dab30a..55b0cc4f5ee5 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -15,25 +15,17 @@
model = "IGEP COM MODULE Rev. E (TI OMAP AM/DM37x)";
compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
- /* Regulator to trigger the WIFI_PDN signal of the Wifi module */
- lbee1usjyc_pdn: lbee1usjyc_pdn {
+ vmmcsdio_fixed: fixedregulator-mmcsdio {
compatible = "regulator-fixed";
- regulator-name = "regulator-lbee1usjyc-pdn";
+ regulator-name = "vmmcsdio_fixed";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>; /* gpio_138 - WIFI_PDN */
- startup-delay-us = <10000>;
- enable-active-high;
};
- /* Regulator to trigger the RESET_N_W signal of the Wifi module */
- lbee1usjyc_reset_n_w: lbee1usjyc_reset_n_w {
- compatible = "regulator-fixed";
- regulator-name = "regulator-lbee1usjyc-reset-n-w";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; /* gpio_139 - RESET_N_W */
- enable-active-high;
+ mmc2_pwrseq: mmc2_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>, /* gpio_139 - RESET_N_W */
+ <&gpio5 10 GPIO_ACTIVE_LOW>; /* gpio_138 - WIFI_PDN */
};
};
@@ -62,8 +54,8 @@
&mmc2 {
pinctrl-names = "default";
pinctrl-0 = <&mmc2_pins &lbee1usjyc_pins>;
- vmmc-supply = <&lbee1usjyc_pdn>;
- vmmc_aux-supply = <&lbee1usjyc_reset_n_w>;
+ vmmc-supply = <&vmmcsdio_fixed>;
+ mmc-pwrseq = <&mmc2_pwrseq>;
bus-width = <4>;
non-removable;
};
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index d2fab8c0d4f8..540163025dd3 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -35,63 +35,63 @@
label = "enter";
gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* gpio101 */
linux,code = <KEY_ENTER>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_f1 {
label = "f1";
gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* gpio102 */
linux,code = <KEY_F1>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_f2 {
label = "f2";
gpios = <&gpio4 7 GPIO_ACTIVE_LOW>; /* gpio103 */
linux,code = <KEY_F2>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_f3 {
label = "f3";
gpios = <&gpio4 8 GPIO_ACTIVE_LOW>; /* gpio104 */
linux,code = <KEY_F3>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_f4 {
label = "f4";
gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; /* gpio105 */
linux,code = <KEY_F4>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_left {
label = "left";
gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; /* gpio106 */
linux,code = <KEY_LEFT>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_right {
label = "right";
gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; /* gpio107 */
linux,code = <KEY_RIGHT>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_up {
label = "up";
gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; /* gpio108 */
linux,code = <KEY_UP>;
- gpio-key,wakeup;
+ wakeup-source;
};
key_down {
label = "down";
gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; /* gpio109 */
linux,code = <KEY_DOWN>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
@@ -224,32 +224,32 @@
&omap3_pmx_core {
gpio_key_pins: pinmux_gpio_key_pins {
pinctrl-single,pins = <
- 0xea (PIN_INPUT | MUX_MODE4) /* cam_d2.gpio_101 */
- 0xec (PIN_INPUT | MUX_MODE4) /* cam_d3.gpio_102 */
- 0xee (PIN_INPUT | MUX_MODE4) /* cam_d4.gpio_103 */
- 0xf0 (PIN_INPUT | MUX_MODE4) /* cam_d5.gpio_104 */
- 0xf2 (PIN_INPUT | MUX_MODE4) /* cam_d6.gpio_105 */
- 0xf4 (PIN_INPUT | MUX_MODE4) /* cam_d7.gpio_106 */
- 0xf6 (PIN_INPUT | MUX_MODE4) /* cam_d8.gpio_107 */
- 0xf8 (PIN_INPUT | MUX_MODE4) /* cam_d9.gpio_108 */
- 0xfa (PIN_INPUT | MUX_MODE4) /* cam_d10.gpio_109 */
+ OMAP3_CORE1_IOPAD(0x211a, PIN_INPUT | MUX_MODE4) /* cam_d2.gpio_101 */
+ OMAP3_CORE1_IOPAD(0x211c, PIN_INPUT | MUX_MODE4) /* cam_d3.gpio_102 */
+ OMAP3_CORE1_IOPAD(0x211e, PIN_INPUT | MUX_MODE4) /* cam_d4.gpio_103 */
+ OMAP3_CORE1_IOPAD(0x2120, PIN_INPUT | MUX_MODE4) /* cam_d5.gpio_104 */
+ OMAP3_CORE1_IOPAD(0x2122, PIN_INPUT | MUX_MODE4) /* cam_d6.gpio_105 */
+ OMAP3_CORE1_IOPAD(0x2124, PIN_INPUT | MUX_MODE4) /* cam_d7.gpio_106 */
+ OMAP3_CORE1_IOPAD(0x2126, PIN_INPUT | MUX_MODE4) /* cam_d8.gpio_107 */
+ OMAP3_CORE1_IOPAD(0x2128, PIN_INPUT | MUX_MODE4) /* cam_d9.gpio_108 */
+ OMAP3_CORE1_IOPAD(0x212a, PIN_INPUT | MUX_MODE4) /* cam_d10.gpio_109 */
>;
};
musb_pins: pinmux_musb_pins {
pinctrl-single,pins = <
- 0x172 (PIN_INPUT | MUX_MODE0) /* hsusb0_clk.hsusb0_clk */
- 0x17a (PIN_INPUT | MUX_MODE0) /* hsusb0_data0.hsusb0_data0 */
- 0x17c (PIN_INPUT | MUX_MODE0) /* hsusb0_data1.hsusb0_data1 */
- 0x17e (PIN_INPUT | MUX_MODE0) /* hsusb0_data2.hsusb0_data2 */
- 0x180 (PIN_INPUT | MUX_MODE0) /* hsusb0_data3.hsusb0_data3 */
- 0x182 (PIN_INPUT | MUX_MODE0) /* hsusb0_data4.hsusb0_data4 */
- 0x184 (PIN_INPUT | MUX_MODE0) /* hsusb0_data5.hsusb0_data5 */
- 0x186 (PIN_INPUT | MUX_MODE0) /* hsusb0_data6.hsusb0_data6 */
- 0x188 (PIN_INPUT | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */
- 0x176 (PIN_INPUT | MUX_MODE0) /* hsusb0_dir.hsusb0_dir */
- 0x178 (PIN_INPUT | MUX_MODE0) /* hsusb0_nxt.hsusb0_nxt */
- 0x174 (PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */
+ OMAP3_CORE1_IOPAD(0x21a2, PIN_INPUT | MUX_MODE0) /* hsusb0_clk.hsusb0_clk */
+ OMAP3_CORE1_IOPAD(0x21aa, PIN_INPUT | MUX_MODE0) /* hsusb0_data0.hsusb0_data0 */
+ OMAP3_CORE1_IOPAD(0x21ac, PIN_INPUT | MUX_MODE0) /* hsusb0_data1.hsusb0_data1 */
+ OMAP3_CORE1_IOPAD(0x21ae, PIN_INPUT | MUX_MODE0) /* hsusb0_data2.hsusb0_data2 */
+ OMAP3_CORE1_IOPAD(0x21b0, PIN_INPUT | MUX_MODE0) /* hsusb0_data3.hsusb0_data3 */
+ OMAP3_CORE1_IOPAD(0x21b2, PIN_INPUT | MUX_MODE0) /* hsusb0_data4.hsusb0_data4 */
+ OMAP3_CORE1_IOPAD(0x21b4, PIN_INPUT | MUX_MODE0) /* hsusb0_data5.hsusb0_data5 */
+ OMAP3_CORE1_IOPAD(0x21b6, PIN_INPUT | MUX_MODE0) /* hsusb0_data6.hsusb0_data6 */
+ OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */
+ OMAP3_CORE1_IOPAD(0x21a6, PIN_INPUT | MUX_MODE0) /* hsusb0_dir.hsusb0_dir */
+ OMAP3_CORE1_IOPAD(0x21a8, PIN_INPUT | MUX_MODE0) /* hsusb0_nxt.hsusb0_nxt */
+ OMAP3_CORE1_IOPAD(0x21a4, PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */
>;
};
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index 57d7c93cc72b..93f8dfe20f13 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -327,7 +327,7 @@
ti,pressure-max = /bits/ 16 <255>;
ti,swap-xy;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 5f5e0f3d5b64..74d8f7eb5563 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -67,28 +67,28 @@
gpios = <&gpio4 14 GPIO_ACTIVE_LOW>; /* 110 */
linux,input-type = <5>; /* EV_SW */
linux,code = <0x09>; /* SW_CAMERA_LENS_COVER */
- gpio-key,wakeup;
+ wakeup-source;
};
camera_focus {
label = "Camera Focus";
gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; /* 68 */
linux,code = <0x210>; /* KEY_CAMERA_FOCUS */
- gpio-key,wakeup;
+ wakeup-source;
};
camera_capture {
label = "Camera Capture";
gpios = <&gpio3 5 GPIO_ACTIVE_LOW>; /* 69 */
linux,code = <0xd4>; /* KEY_CAMERA */
- gpio-key,wakeup;
+ wakeup-source;
};
lock_button {
label = "Lock Button";
gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; /* 113 */
linux,code = <0x98>; /* KEY_SCREENLOCK */
- gpio-key,wakeup;
+ wakeup-source;
};
keypad_slide {
@@ -96,7 +96,7 @@
gpios = <&gpio3 7 GPIO_ACTIVE_LOW>; /* 71 */
linux,input-type = <5>; /* EV_SW */
linux,code = <0x0a>; /* SW_KEYPAD_SLIDE */
- gpio-key,wakeup;
+ wakeup-source;
};
proximity_sensor {
@@ -149,15 +149,15 @@
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0x14a (PIN_INPUT | MUX_MODE0) /* uart2_rx */
- 0x148 (PIN_OUTPUT | MUX_MODE0) /* uart2_tx */
+ OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx */
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16e (PIN_INPUT | MUX_MODE0) /* uart3_rx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx */
+ OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | MUX_MODE0) /* uart3_rx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx */
>;
};
@@ -198,22 +198,22 @@
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x18a (PIN_INPUT | MUX_MODE0) /* i2c1_scl */
- 0x18c (PIN_INPUT | MUX_MODE0) /* i2c1_sda */
+ OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl */
+ OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
- 0x18e (PIN_INPUT | MUX_MODE0) /* i2c2_scl */
- 0x190 (PIN_INPUT | MUX_MODE0) /* i2c2_sda */
+ OMAP3_CORE1_IOPAD(0x21be, PIN_INPUT | MUX_MODE0) /* i2c2_scl */
+ OMAP3_CORE1_IOPAD(0x21c0, PIN_INPUT | MUX_MODE0) /* i2c2_sda */
>;
};
i2c3_pins: pinmux_i2c3_pins {
pinctrl-single,pins = <
- 0x192 (PIN_INPUT | MUX_MODE0) /* i2c3_scl */
- 0x194 (PIN_INPUT | MUX_MODE0) /* i2c3_sda */
+ OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl */
+ OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda */
>;
};
@@ -225,85 +225,85 @@
mcspi4_pins: pinmux_mcspi4_pins {
pinctrl-single,pins = <
- 0x15c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mcspi4_clk */
- 0x162 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* mcspi4_somi */
- 0x160 (PIN_OUTPUT | MUX_MODE1) /* mcspi4_simo */
- 0x166 (PIN_OUTPUT | MUX_MODE1) /* mcspi4_cs0 */
+ OMAP3_CORE1_IOPAD(0x218c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mcspi4_clk */
+ OMAP3_CORE1_IOPAD(0x2192, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mcspi4_somi */
+ OMAP3_CORE1_IOPAD(0x2190, PIN_OUTPUT | MUX_MODE1) /* mcspi4_simo */
+ OMAP3_CORE1_IOPAD(0x2196, PIN_OUTPUT | MUX_MODE1) /* mcspi4_cs0 */
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x114 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk */
- 0x116 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0 */
- 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1 */
- 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2 */
- 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3 */
+ OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3 */
>;
};
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk */
- 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd */
- 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0 */
- 0x12e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1 */
- 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2 */
- 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3 */
- 0x134 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat4 */
- 0x136 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat5 */
- 0x138 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat6 */
- 0x13a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat7 */
+ OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk */
+ OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd */
+ OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0 */
+ OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1 */
+ OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2 */
+ OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3 */
+ OMAP3_CORE1_IOPAD(0x2164, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat4 */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat5 */
+ OMAP3_CORE1_IOPAD(0x2168, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat6 */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat7 */
>;
};
acx565akm_pins: pinmux_acx565akm_pins {
pinctrl-single,pins = <
- 0x0d4 (PIN_OUTPUT | MUX_MODE4) /* RX51_LCD_RESET_GPIO */
+ OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE4) /* RX51_LCD_RESET_GPIO */
>;
};
dss_sdi_pins: pinmux_dss_sdi_pins {
pinctrl-single,pins = <
- 0x0c0 (PIN_OUTPUT | MUX_MODE1) /* dss_data10.sdi_dat1n */
- 0x0c2 (PIN_OUTPUT | MUX_MODE1) /* dss_data11.sdi_dat1p */
- 0x0c4 (PIN_OUTPUT | MUX_MODE1) /* dss_data12.sdi_dat2n */
- 0x0c6 (PIN_OUTPUT | MUX_MODE1) /* dss_data13.sdi_dat2p */
+ OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE1) /* dss_data10.sdi_dat1n */
+ OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE1) /* dss_data11.sdi_dat1p */
+ OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE1) /* dss_data12.sdi_dat2n */
+ OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE1) /* dss_data13.sdi_dat2p */
- 0x0d8 (PIN_OUTPUT | MUX_MODE1) /* dss_data22.sdi_clkp */
- 0x0da (PIN_OUTPUT | MUX_MODE1) /* dss_data23.sdi_clkn */
+ OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE1) /* dss_data22.sdi_clkp */
+ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE1) /* dss_data23.sdi_clkn */
>;
};
wl1251_pins: pinmux_wl1251 {
pinctrl-single,pins = <
- 0x0ce (PIN_OUTPUT | MUX_MODE4) /* gpio 87 => wl1251 enable */
- 0x05a (PIN_INPUT | MUX_MODE4) /* gpio 42 => wl1251 irq */
+ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE4) /* gpio 87 => wl1251 enable */
+ OMAP3_CORE1_IOPAD(0x208a, PIN_INPUT | MUX_MODE4) /* gpio 42 => wl1251 irq */
>;
};
ssi_pins: pinmux_ssi {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT_PULLUP | MUX_MODE1) /* ssi1_rdy_tx */
- 0x14e (PIN_OUTPUT | MUX_MODE1) /* ssi1_flag_tx */
- 0x152 (PIN_INPUT | WAKEUP_EN | MUX_MODE4) /* ssi1_wake_tx (cawake) */
- 0x14c (PIN_OUTPUT | MUX_MODE1) /* ssi1_dat_tx */
- 0x154 (PIN_INPUT | MUX_MODE1) /* ssi1_dat_rx */
- 0x156 (PIN_INPUT | MUX_MODE1) /* ssi1_flag_rx */
- 0x158 (PIN_OUTPUT | MUX_MODE1) /* ssi1_rdy_rx */
- 0x15a (PIN_OUTPUT | MUX_MODE1) /* ssi1_wake */
+ OMAP3_CORE1_IOPAD(0x2180, PIN_INPUT_PULLUP | MUX_MODE1) /* ssi1_rdy_tx */
+ OMAP3_CORE1_IOPAD(0x217e, PIN_OUTPUT | MUX_MODE1) /* ssi1_flag_tx */
+ OMAP3_CORE1_IOPAD(0x2182, PIN_INPUT | WAKEUP_EN | MUX_MODE4) /* ssi1_wake_tx (cawake) */
+ OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE1) /* ssi1_dat_tx */
+ OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT | MUX_MODE1) /* ssi1_dat_rx */
+ OMAP3_CORE1_IOPAD(0x2186, PIN_INPUT | MUX_MODE1) /* ssi1_flag_rx */
+ OMAP3_CORE1_IOPAD(0x2188, PIN_OUTPUT | MUX_MODE1) /* ssi1_rdy_rx */
+ OMAP3_CORE1_IOPAD(0x218a, PIN_OUTPUT | MUX_MODE1) /* ssi1_wake */
>;
};
modem_pins: pinmux_modem {
pinctrl-single,pins = <
- 0x0ac (PIN_OUTPUT | MUX_MODE4) /* gpio 70 => cmt_apeslpx */
- 0x0b0 (PIN_INPUT | WAKEUP_EN | MUX_MODE4) /* gpio 72 => ape_rst_rq */
- 0x0b2 (PIN_OUTPUT | MUX_MODE4) /* gpio 73 => cmt_rst_rq */
- 0x0b4 (PIN_OUTPUT | MUX_MODE4) /* gpio 74 => cmt_en */
- 0x0b6 (PIN_OUTPUT | MUX_MODE4) /* gpio 75 => cmt_rst */
- 0x15e (PIN_OUTPUT | MUX_MODE4) /* gpio 157 => cmt_bsi */
+ OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE4) /* gpio 70 => cmt_apeslpx */
+ OMAP3_CORE1_IOPAD(0x20e0, PIN_INPUT | WAKEUP_EN | MUX_MODE4) /* gpio 72 => ape_rst_rq */
+ OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE4) /* gpio 73 => cmt_rst_rq */
+ OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE4) /* gpio 74 => cmt_en */
+ OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE4) /* gpio 75 => cmt_rst */
+ OMAP3_CORE1_IOPAD(0x218e, PIN_OUTPUT | MUX_MODE4) /* gpio 157 => cmt_bsi */
>;
};
};
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index e9ee1df0e467..a2c2b8d8dd2c 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -36,12 +36,12 @@
&omap3_pmx_core {
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk */
- 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd */
- 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0 */
- 0x12e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1 */
- 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2 */
- 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3 */
+ OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk */
+ OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd */
+ OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0 */
+ OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1 */
+ OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2 */
+ OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3 */
>;
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
index 7aae8fb82c1f..3b3a75997f81 100644
--- a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
@@ -48,7 +48,7 @@
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* gpio_10 */
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
index 17b82f82638a..7df27926ead2 100644
--- a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
@@ -41,13 +41,13 @@
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
- gpio-key,wakeup;
+ wakeup-source;
};
button1@14 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
index b09cedf66117..6314da2580f5 100644
--- a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
@@ -161,6 +161,6 @@
ti,x-plate-ohms = /bits/ 16 <180>;
ti,pressure-max = /bits/ 16 <255>;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
index 5f979590571b..7e3fe85a8ad9 100644
--- a/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
@@ -172,7 +172,7 @@
ti,x-plate-ohms = /bits/ 16 <180>;
ti,pressure-max = /bits/ 16 <255>;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
index 49d2254a99b0..250cc7fe5d5e 100644
--- a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
@@ -41,13 +41,13 @@
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
- gpio-key,wakeup;
+ wakeup-source;
};
button1@14 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
index 680d7262399c..8df7ec35d17d 100644
--- a/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
@@ -41,13 +41,13 @@
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
- gpio-key,wakeup;
+ wakeup-source;
};
button1@14 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
index 087aedf5b902..0ea2c451c809 100644
--- a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
@@ -41,13 +41,13 @@
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
- gpio-key,wakeup;
+ wakeup-source;
};
button1@14 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/omap3-pandora-common.dtsi b/arch/arm/boot/dts/omap3-pandora-common.dtsi
index cfe140c657e7..13e9d1f987af 100644
--- a/arch/arm/boot/dts/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/omap3-pandora-common.dtsi
@@ -84,112 +84,112 @@
label = "up";
linux,code = <KEY_UP>;
gpios = <&gpio4 14 GPIO_ACTIVE_LOW>; /* GPIO_110 */
- gpio-key,wakeup;
+ wakeup-source;
};
down-button {
label = "down";
linux,code = <KEY_DOWN>;
gpios = <&gpio4 7 GPIO_ACTIVE_LOW>; /* GPIO_103 */
- gpio-key,wakeup;
+ wakeup-source;
};
left-button {
label = "left";
linux,code = <KEY_LEFT>;
gpios = <&gpio4 0 GPIO_ACTIVE_LOW>; /* GPIO_96 */
- gpio-key,wakeup;
+ wakeup-source;
};
right-button {
label = "right";
linux,code = <KEY_RIGHT>;
gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; /* GPIO_98 */
- gpio-key,wakeup;
+ wakeup-source;
};
pageup-button {
label = "game 1";
linux,code = <KEY_PAGEUP>;
gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; /* GPIO_109 */
- gpio-key,wakeup;
+ wakeup-source;
};
pagedown-button {
label = "game 3";
linux,code = <KEY_PAGEDOWN>;
gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; /* GPIO_106 */
- gpio-key,wakeup;
+ wakeup-source;
};
home-button {
label = "game 4";
linux,code = <KEY_HOME>;
gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* GPIO_101 */
- gpio-key,wakeup;
+ wakeup-source;
};
end-button {
label = "game 2";
linux,code = <KEY_END>;
gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; /* GPIO_111 */
- gpio-key,wakeup;
+ wakeup-source;
};
right-shift {
label = "l";
linux,code = <KEY_RIGHTSHIFT>;
gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* GPIO_102 */
- gpio-key,wakeup;
+ wakeup-source;
};
kp-plus {
label = "l2";
linux,code = <KEY_KPPLUS>;
gpios = <&gpio4 1 GPIO_ACTIVE_LOW>; /* GPIO_97 */
- gpio-key,wakeup;
+ wakeup-source;
};
right-ctrl {
label = "r";
linux,code = <KEY_RIGHTCTRL>;
gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; /* GPIO_105 */
- gpio-key,wakeup;
+ wakeup-source;
};
kp-minus {
label = "r2";
linux,code = <KEY_KPMINUS>;
gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; /* GPIO_107 */
- gpio-key,wakeup;
+ wakeup-source;
};
left-ctrl {
label = "ctrl";
linux,code = <KEY_LEFTCTRL>;
gpios = <&gpio4 8 GPIO_ACTIVE_LOW>; /* GPIO_104 */
- gpio-key,wakeup;
+ wakeup-source;
};
menu {
label = "menu";
linux,code = <KEY_MENU>;
gpios = <&gpio4 3 GPIO_ACTIVE_LOW>; /* GPIO_99 */
- gpio-key,wakeup;
+ wakeup-source;
};
hold {
label = "hold";
linux,code = <KEY_COFFEE>;
gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; /* GPIO_176 */
- gpio-key,wakeup;
+ wakeup-source;
};
left-alt {
label = "alt";
linux,code = <KEY_LEFTALT>;
gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>; /* GPIO_100 */
- gpio-key,wakeup;
+ wakeup-source;
};
lid {
@@ -617,7 +617,7 @@
ti,x-plate-ohms = /bits/ 16 <40>;
ti,pressure-max = /bits/ 16 <255>;
- linux,wakeup;
+ wakeup-source;
};
lcd: lcd@1 {
diff --git a/arch/arm/boot/dts/omap3-panel-sharp-ls037v7dw01.dtsi b/arch/arm/boot/dts/omap3-panel-sharp-ls037v7dw01.dtsi
index f4b1a61853e3..157345bb8e79 100644
--- a/arch/arm/boot/dts/omap3-panel-sharp-ls037v7dw01.dtsi
+++ b/arch/arm/boot/dts/omap3-panel-sharp-ls037v7dw01.dtsi
@@ -66,6 +66,6 @@
ti,x-plate-ohms = /bits/ 16 <40>;
ti,pressure-max = /bits/ 16 <255>;
ti,swap-xy;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap3-zoom3.dts b/arch/arm/boot/dts/omap3-zoom3.dts
index 7bc5fdd6981e..f19170bdcc1f 100644
--- a/arch/arm/boot/dts/omap3-zoom3.dts
+++ b/arch/arm/boot/dts/omap3-zoom3.dts
@@ -54,27 +54,27 @@
/* REVISIT: twl gpio0 is mmc0_cd */
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x114 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
- 0x116 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
- 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
- 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
- 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
+ OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_OUTPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
>;
};
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
- 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
- 0x12c (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
- 0x12e (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
- 0x130 (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
- 0x132 (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
- 0x134 (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat4.sdmmc2_dat4 */
- 0x136 (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat5.sdmmc2_dat5 */
- 0x138 (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat6.sdmmc2_dat6 */
- 0x13a (PIN_INPUT | MUX_MODE0) /* sdmmc2_dat7.sdmmc2_dat7 */
+ OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
+ OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
+ OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
+ OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
+ OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
+ OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
+ OMAP3_CORE1_IOPAD(0x2164, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat4.sdmmc2_dat4 */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat5.sdmmc2_dat5 */
+ OMAP3_CORE1_IOPAD(0x2168, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat6.sdmmc2_dat6 */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT | MUX_MODE0) /* sdmmc2_dat7.sdmmc2_dat7 */
>;
};
@@ -87,35 +87,35 @@
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x150 (PIN_INPUT | MUX_MODE0) /* uart1_cts.uart1_cts */
- 0x14e (PIN_OUTPUT | MUX_MODE0) /* uart1_rts.uart1_rts */
- 0x152 (WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
- 0x14c (PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
+ OMAP3_CORE1_IOPAD(0x2180, PIN_INPUT | MUX_MODE0) /* uart1_cts.uart1_cts */
+ OMAP3_CORE1_IOPAD(0x217e, PIN_OUTPUT | MUX_MODE0) /* uart1_rts.uart1_rts */
+ OMAP3_CORE1_IOPAD(0x2182, WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
+ OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
>;
};
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0x144 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts.uart2_cts */
- 0x146 (PIN_OUTPUT | MUX_MODE0) /* uart2_rts.uart2_rts */
- 0x14a (WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
- 0x148 (PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts.uart2_cts */
+ OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts.uart2_rts */
+ OMAP3_CORE1_IOPAD(0x217a, WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16a (PIN_INPUT_PULLDOWN | MUX_MODE0) /* uart3_cts_rctx.uart3_cts_rctx */
- 0x16c (PIN_OUTPUT | MUX_MODE0) /* uart3_rts_sd.uart3_rts_sd */
- 0x16e (WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
+ OMAP3_CORE1_IOPAD(0x219a, PIN_INPUT_PULLDOWN | MUX_MODE0) /* uart3_cts_rctx.uart3_cts_rctx */
+ OMAP3_CORE1_IOPAD(0x219c, PIN_OUTPUT | MUX_MODE0) /* uart3_rts_sd.uart3_rts_sd */
+ OMAP3_CORE1_IOPAD(0x219e, WAKEUP_EN | PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
>;
};
/* wl12xx GPIO output for WLAN_EN */
wl12xx_gpio: pinmux_wl12xx_gpio {
pinctrl-single,pins = <
- 0xea (PIN_OUTPUT| MUX_MODE4) /* cam_d2.gpio_101 */
+ OMAP3_CORE1_IOPAD(0x211a, PIN_OUTPUT| MUX_MODE4) /* cam_d2.gpio_101 */
>;
};
};
@@ -135,7 +135,7 @@
&omap3_pmx_wkup {
wlan_host_wkup: pinmux_wlan_host_wkup_pins {
pinctrl-single,pins = <
- 0x1a (PIN_INPUT_PULLUP | MUX_MODE4) /* sys_clkout1.gpio_10 WLAN_HOST_WKUP */
+ OMAP3_WKUP_IOPAD(0x2a1a, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_clkout1.gpio_10 WLAN_HOST_WKUP */
>;
};
};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 8a2b25332b8c..d1ffabb7c74f 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -717,6 +717,8 @@
ti,hwmods = "gpmc";
reg = <0x6e000000 0x02d0>;
interrupts = <20>;
+ dmas = <&sdma 4>;
+ dma-names = "rxtx";
gpmc,num-cs = <8>;
gpmc,num-waitpins = <4>;
#address-cells = <2>;
diff --git a/arch/arm/boot/dts/omap4-duovero-parlor.dts b/arch/arm/boot/dts/omap4-duovero-parlor.dts
index b75f7b2b7c4a..06c54822ddc2 100644
--- a/arch/arm/boot/dts/omap4-duovero-parlor.dts
+++ b/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -36,7 +36,7 @@
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; /* gpio_121 */
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap4-panda-a4.dts b/arch/arm/boot/dts/omap4-panda-a4.dts
index 133f1b74e8ae..78d363177762 100644
--- a/arch/arm/boot/dts/omap4-panda-a4.dts
+++ b/arch/arm/boot/dts/omap4-panda-a4.dts
@@ -13,8 +13,8 @@
/* Pandaboard Rev A4+ have external pullups on SCL & SDA */
&dss_hdmi_pins {
pinctrl-single,pins = <
- 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x5c (PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
- 0x5e (PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
+ OMAP4_IOPAD(0x09a, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ OMAP4_IOPAD(0x09c, PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
+ OMAP4_IOPAD(0x09e, PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
>;
};
diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
index 18d096696fc0..df2e356ec089 100644
--- a/arch/arm/boot/dts/omap4-panda-common.dtsi
+++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
@@ -199,129 +199,129 @@
twl6040_pins: pinmux_twl6040_pins {
pinctrl-single,pins = <
- 0xe0 (PIN_OUTPUT | MUX_MODE3) /* hdq_sio.gpio_127 */
- 0x160 (PIN_INPUT | MUX_MODE0) /* sys_nirq2.sys_nirq2 */
+ OMAP4_IOPAD(0x120, PIN_OUTPUT | MUX_MODE3) /* hdq_sio.gpio_127 */
+ OMAP4_IOPAD(0x1a0, PIN_INPUT | MUX_MODE0) /* sys_nirq2.sys_nirq2 */
>;
};
mcpdm_pins: pinmux_mcpdm_pins {
pinctrl-single,pins = <
- 0xc6 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_ul_data.abe_pdm_ul_data */
- 0xc8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_dl_data.abe_pdm_dl_data */
- 0xca (PIN_INPUT_PULLUP | MUX_MODE0) /* abe_pdm_frame.abe_pdm_frame */
- 0xcc (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_lb_clk.abe_pdm_lb_clk */
- 0xce (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
+ OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_ul_data.abe_pdm_ul_data */
+ OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_dl_data.abe_pdm_dl_data */
+ OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP | MUX_MODE0) /* abe_pdm_frame.abe_pdm_frame */
+ OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_lb_clk.abe_pdm_lb_clk */
+ OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
>;
};
mcbsp1_pins: pinmux_mcbsp1_pins {
pinctrl-single,pins = <
- 0xbe (PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
- 0xc0 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dr.abe_mcbsp1_dr */
- 0xc2 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dx.abe_mcbsp1_dx */
- 0xc4 (PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_fsx.abe_mcbsp1_fsx */
+ OMAP4_IOPAD(0x0fe, PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
+ OMAP4_IOPAD(0x100, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dr.abe_mcbsp1_dr */
+ OMAP4_IOPAD(0x102, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dx.abe_mcbsp1_dx */
+ OMAP4_IOPAD(0x104, PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_fsx.abe_mcbsp1_fsx */
>;
};
dss_dpi_pins: pinmux_dss_dpi_pins {
pinctrl-single,pins = <
- 0x122 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data23 */
- 0x124 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data22 */
- 0x126 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data21 */
- 0x128 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data20 */
- 0x12a (PIN_OUTPUT | MUX_MODE5) /* dispc2_data19 */
- 0x12c (PIN_OUTPUT | MUX_MODE5) /* dispc2_data18 */
- 0x12e (PIN_OUTPUT | MUX_MODE5) /* dispc2_data15 */
- 0x130 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data14 */
- 0x132 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data13 */
- 0x134 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data12 */
- 0x136 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data11 */
-
- 0x174 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data10 */
- 0x176 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data9 */
- 0x178 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data16 */
- 0x17a (PIN_OUTPUT | MUX_MODE5) /* dispc2_data17 */
- 0x17c (PIN_OUTPUT | MUX_MODE5) /* dispc2_hsync */
- 0x17e (PIN_OUTPUT | MUX_MODE5) /* dispc2_pclk */
- 0x180 (PIN_OUTPUT | MUX_MODE5) /* dispc2_vsync */
- 0x182 (PIN_OUTPUT | MUX_MODE5) /* dispc2_de */
- 0x184 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data8 */
- 0x186 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data7 */
- 0x188 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data6 */
- 0x18a (PIN_OUTPUT | MUX_MODE5) /* dispc2_data5 */
- 0x18c (PIN_OUTPUT | MUX_MODE5) /* dispc2_data4 */
- 0x18e (PIN_OUTPUT | MUX_MODE5) /* dispc2_data3 */
-
- 0x190 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data2 */
- 0x192 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data1 */
- 0x194 (PIN_OUTPUT | MUX_MODE5) /* dispc2_data0 */
+ OMAP4_IOPAD(0x162, PIN_OUTPUT | MUX_MODE5) /* dispc2_data23 */
+ OMAP4_IOPAD(0x164, PIN_OUTPUT | MUX_MODE5) /* dispc2_data22 */
+ OMAP4_IOPAD(0x166, PIN_OUTPUT | MUX_MODE5) /* dispc2_data21 */
+ OMAP4_IOPAD(0x168, PIN_OUTPUT | MUX_MODE5) /* dispc2_data20 */
+ OMAP4_IOPAD(0x16a, PIN_OUTPUT | MUX_MODE5) /* dispc2_data19 */
+ OMAP4_IOPAD(0x16c, PIN_OUTPUT | MUX_MODE5) /* dispc2_data18 */
+ OMAP4_IOPAD(0x16e, PIN_OUTPUT | MUX_MODE5) /* dispc2_data15 */
+ OMAP4_IOPAD(0x170, PIN_OUTPUT | MUX_MODE5) /* dispc2_data14 */
+ OMAP4_IOPAD(0x172, PIN_OUTPUT | MUX_MODE5) /* dispc2_data13 */
+ OMAP4_IOPAD(0x174, PIN_OUTPUT | MUX_MODE5) /* dispc2_data12 */
+ OMAP4_IOPAD(0x176, PIN_OUTPUT | MUX_MODE5) /* dispc2_data11 */
+
+ OMAP4_IOPAD(0x1b4, PIN_OUTPUT | MUX_MODE5) /* dispc2_data10 */
+ OMAP4_IOPAD(0x1b6, PIN_OUTPUT | MUX_MODE5) /* dispc2_data9 */
+ OMAP4_IOPAD(0x1b8, PIN_OUTPUT | MUX_MODE5) /* dispc2_data16 */
+ OMAP4_IOPAD(0x1ba, PIN_OUTPUT | MUX_MODE5) /* dispc2_data17 */
+ OMAP4_IOPAD(0x1bc, PIN_OUTPUT | MUX_MODE5) /* dispc2_hsync */
+ OMAP4_IOPAD(0x1be, PIN_OUTPUT | MUX_MODE5) /* dispc2_pclk */
+ OMAP4_IOPAD(0x1c0, PIN_OUTPUT | MUX_MODE5) /* dispc2_vsync */
+ OMAP4_IOPAD(0x1c2, PIN_OUTPUT | MUX_MODE5) /* dispc2_de */
+ OMAP4_IOPAD(0x1c4, PIN_OUTPUT | MUX_MODE5) /* dispc2_data8 */
+ OMAP4_IOPAD(0x1c6, PIN_OUTPUT | MUX_MODE5) /* dispc2_data7 */
+ OMAP4_IOPAD(0x1c8, PIN_OUTPUT | MUX_MODE5) /* dispc2_data6 */
+ OMAP4_IOPAD(0x1ca, PIN_OUTPUT | MUX_MODE5) /* dispc2_data5 */
+ OMAP4_IOPAD(0x1cc, PIN_OUTPUT | MUX_MODE5) /* dispc2_data4 */
+ OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE5) /* dispc2_data3 */
+
+ OMAP4_IOPAD(0x1d0, PIN_OUTPUT | MUX_MODE5) /* dispc2_data2 */
+ OMAP4_IOPAD(0x1d2, PIN_OUTPUT | MUX_MODE5) /* dispc2_data1 */
+ OMAP4_IOPAD(0x1d4, PIN_OUTPUT | MUX_MODE5) /* dispc2_data0 */
>;
};
tfp410_pins: pinmux_tfp410_pins {
pinctrl-single,pins = <
- 0x144 (PIN_OUTPUT | MUX_MODE3) /* gpio_0 */
+ OMAP4_IOPAD(0x184, PIN_OUTPUT | MUX_MODE3) /* gpio_0 */
>;
};
dss_hdmi_pins: pinmux_dss_hdmi_pins {
pinctrl-single,pins = <
- 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x5c (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_scl.hdmi_scl */
- 0x5e (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_sda.hdmi_sda */
+ OMAP4_IOPAD(0x09a, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ OMAP4_IOPAD(0x09c, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_scl.hdmi_scl */
+ OMAP4_IOPAD(0x09e, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_sda.hdmi_sda */
>;
};
tpd12s015_pins: pinmux_tpd12s015_pins {
pinctrl-single,pins = <
- 0x22 (PIN_OUTPUT | MUX_MODE3) /* gpmc_a17.gpio_41 */
- 0x48 (PIN_OUTPUT | MUX_MODE3) /* gpmc_nbe1.gpio_60 */
- 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* hdmi_hpd.gpio_63 */
+ OMAP4_IOPAD(0x062, PIN_OUTPUT | MUX_MODE3) /* gpmc_a17.gpio_41 */
+ OMAP4_IOPAD(0x088, PIN_OUTPUT | MUX_MODE3) /* gpmc_nbe1.gpio_60 */
+ OMAP4_IOPAD(0x098, PIN_INPUT_PULLDOWN | MUX_MODE3) /* hdmi_hpd.gpio_63 */
>;
};
hsusbb1_pins: pinmux_hsusbb1_pins {
pinctrl-single,pins = <
- 0x82 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_clk.usbb1_ulpiphy_clk */
- 0x84 (PIN_OUTPUT | MUX_MODE4) /* usbb1_ulpitll_stp.usbb1_ulpiphy_stp */
- 0x86 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dir.usbb1_ulpiphy_dir */
- 0x88 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_nxt.usbb1_ulpiphy_nxt */
- 0x8a (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat0.usbb1_ulpiphy_dat0 */
- 0x8c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat1.usbb1_ulpiphy_dat1 */
- 0x8e (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat2.usbb1_ulpiphy_dat2 */
- 0x90 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat3.usbb1_ulpiphy_dat3 */
- 0x92 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat4.usbb1_ulpiphy_dat4 */
- 0x94 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat5.usbb1_ulpiphy_dat5 */
- 0x96 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat6.usbb1_ulpiphy_dat6 */
- 0x98 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat7.usbb1_ulpiphy_dat7 */
+ OMAP4_IOPAD(0x0c2, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_clk.usbb1_ulpiphy_clk */
+ OMAP4_IOPAD(0x0c4, PIN_OUTPUT | MUX_MODE4) /* usbb1_ulpitll_stp.usbb1_ulpiphy_stp */
+ OMAP4_IOPAD(0x0c6, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dir.usbb1_ulpiphy_dir */
+ OMAP4_IOPAD(0x0c8, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_nxt.usbb1_ulpiphy_nxt */
+ OMAP4_IOPAD(0x0ca, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat0.usbb1_ulpiphy_dat0 */
+ OMAP4_IOPAD(0x0cc, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat1.usbb1_ulpiphy_dat1 */
+ OMAP4_IOPAD(0x0ce, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat2.usbb1_ulpiphy_dat2 */
+ OMAP4_IOPAD(0x0d0, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat3.usbb1_ulpiphy_dat3 */
+ OMAP4_IOPAD(0x0d2, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat4.usbb1_ulpiphy_dat4 */
+ OMAP4_IOPAD(0x0d4, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat5.usbb1_ulpiphy_dat5 */
+ OMAP4_IOPAD(0x0d6, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat6.usbb1_ulpiphy_dat6 */
+ OMAP4_IOPAD(0x0d8, PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat7.usbb1_ulpiphy_dat7 */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0xe2 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
- 0xe4 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ OMAP4_IOPAD(0x122, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ OMAP4_IOPAD(0x124, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
- 0xe6 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_scl */
- 0xe8 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_sda */
+ OMAP4_IOPAD(0x126, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_scl */
+ OMAP4_IOPAD(0x128, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_sda */
>;
};
i2c3_pins: pinmux_i2c3_pins {
pinctrl-single,pins = <
- 0xea (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_scl */
- 0xec (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */
+ OMAP4_IOPAD(0x12a, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_scl */
+ OMAP4_IOPAD(0x12c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */
>;
};
i2c4_pins: pinmux_i2c4_pins {
pinctrl-single,pins = <
- 0xee (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_scl */
- 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_sda */
+ OMAP4_IOPAD(0x12e, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_scl */
+ OMAP4_IOPAD(0x130, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_sda */
>;
};
@@ -331,24 +331,24 @@
*/
wl12xx_gpio: pinmux_wl12xx_gpio {
pinctrl-single,pins = <
- 0x26 (PIN_OUTPUT | MUX_MODE3) /* gpmc_a19.gpio_43 */
- 0x2c (PIN_OUTPUT | MUX_MODE3) /* gpmc_a22.gpio_46 */
- 0x30 (PIN_OUTPUT_PULLUP | MUX_MODE3) /* gpmc_a24.gpio_48 */
- 0x32 (PIN_OUTPUT_PULLUP | MUX_MODE3) /* gpmc_a25.gpio_49 */
+ OMAP4_IOPAD(0x066, PIN_OUTPUT | MUX_MODE3) /* gpmc_a19.gpio_43 */
+ OMAP4_IOPAD(0x06c, PIN_OUTPUT | MUX_MODE3) /* gpmc_a22.gpio_46 */
+ OMAP4_IOPAD(0x070, PIN_OUTPUT_PULLUP | MUX_MODE3) /* gpmc_a24.gpio_48 */
+ OMAP4_IOPAD(0x072, PIN_OUTPUT_PULLUP | MUX_MODE3) /* gpmc_a25.gpio_49 */
>;
};
/* wl12xx GPIO inputs and SDIO pins */
wl12xx_pins: pinmux_wl12xx_pins {
pinctrl-single,pins = <
- 0x38 (PIN_INPUT | MUX_MODE3) /* gpmc_ncs2.gpio_52 */
- 0x3a (PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */
- 0x108 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */
- 0x10a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_cmd.sdmmc5_cmd */
- 0x10c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat0.sdmmc5_dat0 */
- 0x10e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1.sdmmc5_dat1 */
- 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat2.sdmmc5_dat2 */
- 0x112 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat3.sdmmc5_dat3 */
+ OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) /* gpmc_ncs2.gpio_52 */
+ OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */
+ OMAP4_IOPAD(0x148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */
+ OMAP4_IOPAD(0x14a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_cmd.sdmmc5_cmd */
+ OMAP4_IOPAD(0x14c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat0.sdmmc5_dat0 */
+ OMAP4_IOPAD(0x14e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1.sdmmc5_dat1 */
+ OMAP4_IOPAD(0x150, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat2.sdmmc5_dat2 */
+ OMAP4_IOPAD(0x152, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat3.sdmmc5_dat3 */
>;
};
};
@@ -356,8 +356,8 @@
&omap4_pmx_wkup {
led_wkgpio_pins: pinmux_leds_wkpins {
pinctrl-single,pins = <
- 0x1a (PIN_OUTPUT | MUX_MODE3) /* gpio_wk7 */
- 0x1c (PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */
+ OMAP4_IOPAD(0x05a, PIN_OUTPUT | MUX_MODE3) /* gpio_wk7 */
+ OMAP4_IOPAD(0x05c, PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */
>;
};
};
diff --git a/arch/arm/boot/dts/omap4-panda-es.dts b/arch/arm/boot/dts/omap4-panda-es.dts
index 2f1dabcc6adf..119f8e657edc 100644
--- a/arch/arm/boot/dts/omap4-panda-es.dts
+++ b/arch/arm/boot/dts/omap4-panda-es.dts
@@ -34,23 +34,23 @@
/* PandaboardES has external pullups on SCL & SDA */
&dss_hdmi_pins {
pinctrl-single,pins = <
- 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x5c (PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
- 0x5e (PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
+ OMAP4_IOPAD(0x09a, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ OMAP4_IOPAD(0x09c, PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
+ OMAP4_IOPAD(0x09e, PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
>;
};
&omap4_pmx_core {
led_gpio_pins: gpio_led_pmx {
pinctrl-single,pins = <
- 0xb6 (PIN_OUTPUT | MUX_MODE3) /* gpio_110 */
+ OMAP4_IOPAD(0x0f6, PIN_OUTPUT | MUX_MODE3) /* gpio_110 */
>;
};
};
&led_wkgpio_pins {
pinctrl-single,pins = <
- 0x1c (PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */
+ OMAP4_IOPAD(0x05c, PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */
>;
};
diff --git a/arch/arm/boot/dts/omap4-sdp-es23plus.dts b/arch/arm/boot/dts/omap4-sdp-es23plus.dts
index aad5dda0f469..b4d19a7ae393 100644
--- a/arch/arm/boot/dts/omap4-sdp-es23plus.dts
+++ b/arch/arm/boot/dts/omap4-sdp-es23plus.dts
@@ -10,8 +10,8 @@
/* SDP boards with 4430 ES2.3+ or 4460 have external pullups on SCL & SDA */
&dss_hdmi_pins {
pinctrl-single,pins = <
- 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x5c (PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
- 0x5e (PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
+ OMAP4_IOPAD(0x09a, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ OMAP4_IOPAD(0x09c, PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
+ OMAP4_IOPAD(0x09e, PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
>;
};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index f0bdc41f8eff..aae513265dc2 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -212,143 +212,143 @@
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0xd8 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts.uart2_cts */
- 0xda (PIN_OUTPUT | MUX_MODE0) /* uart2_rts.uart2_rts */
- 0xdc (PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_rx.uart2_rx */
- 0xde (PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP4_IOPAD(0x118, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_cts.uart2_cts */
+ OMAP4_IOPAD(0x11a, PIN_OUTPUT | MUX_MODE0) /* uart2_rts.uart2_rts */
+ OMAP4_IOPAD(0x11c, PIN_INPUT_PULLUP | MUX_MODE0) /* uart2_rx.uart2_rx */
+ OMAP4_IOPAD(0x11e, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_cts_rctx.uart3_cts_rctx */
- 0x102 (PIN_OUTPUT | MUX_MODE0) /* uart3_rts_sd.uart3_rts_sd */
- 0x104 (PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
- 0x106 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
+ OMAP4_IOPAD(0x140, PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_cts_rctx.uart3_cts_rctx */
+ OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE0) /* uart3_rts_sd.uart3_rts_sd */
+ OMAP4_IOPAD(0x144, PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ OMAP4_IOPAD(0x146, PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
>;
};
uart4_pins: pinmux_uart4_pins {
pinctrl-single,pins = <
- 0x11c (PIN_INPUT | MUX_MODE0) /* uart4_rx.uart4_rx */
- 0x11e (PIN_OUTPUT | MUX_MODE0) /* uart4_tx.uart4_tx */
+ OMAP4_IOPAD(0x15c, PIN_INPUT | MUX_MODE0) /* uart4_rx.uart4_rx */
+ OMAP4_IOPAD(0x15e, PIN_OUTPUT | MUX_MODE0) /* uart4_tx.uart4_tx */
>;
};
twl6040_pins: pinmux_twl6040_pins {
pinctrl-single,pins = <
- 0xe0 (PIN_OUTPUT | MUX_MODE3) /* hdq_sio.gpio_127 */
- 0x160 (PIN_INPUT | MUX_MODE0) /* sys_nirq2.sys_nirq2 */
+ OMAP4_IOPAD(0x120, PIN_OUTPUT | MUX_MODE3) /* hdq_sio.gpio_127 */
+ OMAP4_IOPAD(0x1a0, PIN_INPUT | MUX_MODE0) /* sys_nirq2.sys_nirq2 */
>;
};
mcpdm_pins: pinmux_mcpdm_pins {
pinctrl-single,pins = <
- 0xc6 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_ul_data.abe_pdm_ul_data */
- 0xc8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_dl_data.abe_pdm_dl_data */
- 0xca (PIN_INPUT_PULLUP | MUX_MODE0) /* abe_pdm_frame.abe_pdm_frame */
- 0xcc (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_lb_clk.abe_pdm_lb_clk */
- 0xce (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
+ OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_ul_data.abe_pdm_ul_data */
+ OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_dl_data.abe_pdm_dl_data */
+ OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP | MUX_MODE0) /* abe_pdm_frame.abe_pdm_frame */
+ OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_lb_clk.abe_pdm_lb_clk */
+ OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
>;
};
dmic_pins: pinmux_dmic_pins {
pinctrl-single,pins = <
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* abe_dmic_clk1.abe_dmic_clk1 */
- 0xd2 (PIN_INPUT | MUX_MODE0) /* abe_dmic_din1.abe_dmic_din1 */
- 0xd4 (PIN_INPUT | MUX_MODE0) /* abe_dmic_din2.abe_dmic_din2 */
- 0xd6 (PIN_INPUT | MUX_MODE0) /* abe_dmic_din3.abe_dmic_din3 */
+ OMAP4_IOPAD(0x110, PIN_OUTPUT | MUX_MODE0) /* abe_dmic_clk1.abe_dmic_clk1 */
+ OMAP4_IOPAD(0x112, PIN_INPUT | MUX_MODE0) /* abe_dmic_din1.abe_dmic_din1 */
+ OMAP4_IOPAD(0x114, PIN_INPUT | MUX_MODE0) /* abe_dmic_din2.abe_dmic_din2 */
+ OMAP4_IOPAD(0x116, PIN_INPUT | MUX_MODE0) /* abe_dmic_din3.abe_dmic_din3 */
>;
};
mcbsp1_pins: pinmux_mcbsp1_pins {
pinctrl-single,pins = <
- 0xbe (PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
- 0xc0 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dr.abe_mcbsp1_dr */
- 0xc2 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dx.abe_mcbsp1_dx */
- 0xc4 (PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_fsx.abe_mcbsp1_fsx */
+ OMAP4_IOPAD(0x0fe, PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
+ OMAP4_IOPAD(0x100, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dr.abe_mcbsp1_dr */
+ OMAP4_IOPAD(0x102, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dx.abe_mcbsp1_dx */
+ OMAP4_IOPAD(0x104, PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_fsx.abe_mcbsp1_fsx */
>;
};
mcbsp2_pins: pinmux_mcbsp2_pins {
pinctrl-single,pins = <
- 0xb6 (PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_clkx.abe_mcbsp2_clkx */
- 0xb8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp2_dr.abe_mcbsp2_dr */
- 0xba (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp2_dx.abe_mcbsp2_dx */
- 0xbc (PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_fsx.abe_mcbsp2_fsx */
+ OMAP4_IOPAD(0x0f6, PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_clkx.abe_mcbsp2_clkx */
+ OMAP4_IOPAD(0x0f8, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp2_dr.abe_mcbsp2_dr */
+ OMAP4_IOPAD(0x0fa, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp2_dx.abe_mcbsp2_dx */
+ OMAP4_IOPAD(0x0fc, PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_fsx.abe_mcbsp2_fsx */
>;
};
mcspi1_pins: pinmux_mcspi1_pins {
pinctrl-single,pins = <
- 0xf2 (PIN_INPUT | MUX_MODE0) /* mcspi1_clk.mcspi1_clk */
- 0xf4 (PIN_INPUT | MUX_MODE0) /* mcspi1_somi.mcspi1_somi */
- 0xf6 (PIN_INPUT | MUX_MODE0) /* mcspi1_simo.mcspi1_simo */
- 0xf8 (PIN_INPUT | MUX_MODE0) /* mcspi1_cs0.mcspi1_cs0 */
+ OMAP4_IOPAD(0x132, PIN_INPUT | MUX_MODE0) /* mcspi1_clk.mcspi1_clk */
+ OMAP4_IOPAD(0x134, PIN_INPUT | MUX_MODE0) /* mcspi1_somi.mcspi1_somi */
+ OMAP4_IOPAD(0x136, PIN_INPUT | MUX_MODE0) /* mcspi1_simo.mcspi1_simo */
+ OMAP4_IOPAD(0x138, PIN_INPUT | MUX_MODE0) /* mcspi1_cs0.mcspi1_cs0 */
>;
};
dss_hdmi_pins: pinmux_dss_hdmi_pins {
pinctrl-single,pins = <
- 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x5c (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_scl.hdmi_scl */
- 0x5e (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_sda.hdmi_sda */
+ OMAP4_IOPAD(0x09a, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ OMAP4_IOPAD(0x09c, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_scl.hdmi_scl */
+ OMAP4_IOPAD(0x09e, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_sda.hdmi_sda */
>;
};
tpd12s015_pins: pinmux_tpd12s015_pins {
pinctrl-single,pins = <
- 0x22 (PIN_OUTPUT | MUX_MODE3) /* gpmc_a17.gpio_41 */
- 0x48 (PIN_OUTPUT | MUX_MODE3) /* gpmc_nbe1.gpio_60 */
- 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* hdmi_hpd.gpio_63 */
+ OMAP4_IOPAD(0x062, PIN_OUTPUT | MUX_MODE3) /* gpmc_a17.gpio_41 */
+ OMAP4_IOPAD(0x088, PIN_OUTPUT | MUX_MODE3) /* gpmc_nbe1.gpio_60 */
+ OMAP4_IOPAD(0x098, PIN_INPUT_PULLDOWN | MUX_MODE3) /* hdmi_hpd.gpio_63 */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0xe2 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
- 0xe4 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ OMAP4_IOPAD(0x122, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ OMAP4_IOPAD(0x124, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
>;
};
i2c2_pins: pinmux_i2c2_pins {
pinctrl-single,pins = <
- 0xe6 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_scl */
- 0xe8 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_sda */
+ OMAP4_IOPAD(0x126, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_scl */
+ OMAP4_IOPAD(0x128, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_sda */
>;
};
i2c3_pins: pinmux_i2c3_pins {
pinctrl-single,pins = <
- 0xea (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_scl */
- 0xec (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */
+ OMAP4_IOPAD(0x12a, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_scl */
+ OMAP4_IOPAD(0x12c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */
>;
};
i2c4_pins: pinmux_i2c4_pins {
pinctrl-single,pins = <
- 0xee (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_scl */
- 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_sda */
+ OMAP4_IOPAD(0x12e, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_scl */
+ OMAP4_IOPAD(0x130, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_sda */
>;
};
/* wl12xx GPIO output for WLAN_EN */
wl12xx_gpio: pinmux_wl12xx_gpio {
pinctrl-single,pins = <
- 0x3c (PIN_OUTPUT | MUX_MODE3) /* gpmc_nwp.gpio_54 */
+ OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) /* gpmc_nwp.gpio_54 */
>;
};
/* wl12xx GPIO inputs and SDIO pins */
wl12xx_pins: pinmux_wl12xx_pins {
pinctrl-single,pins = <
- 0x3a (PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */
- 0x108 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */
- 0x10a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_cmd.sdmmc5_cmd */
- 0x10c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat0.sdmmc5_dat0 */
- 0x10e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1.sdmmc5_dat1 */
- 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat2.sdmmc5_dat2 */
- 0x112 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat3.sdmmc5_dat3 */
+ OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */
+ OMAP4_IOPAD(0x148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk.sdmmc5_clk */
+ OMAP4_IOPAD(0x14a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_cmd.sdmmc5_cmd */
+ OMAP4_IOPAD(0x14c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat0.sdmmc5_dat0 */
+ OMAP4_IOPAD(0x14e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1.sdmmc5_dat1 */
+ OMAP4_IOPAD(0x150, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat2.sdmmc5_dat2 */
+ OMAP4_IOPAD(0x152, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat3.sdmmc5_dat3 */
>;
};
};
diff --git a/arch/arm/boot/dts/omap4-var-om44customboard.dtsi b/arch/arm/boot/dts/omap4-var-om44customboard.dtsi
index f2d2fdb75628..6e278d7716a5 100644
--- a/arch/arm/boot/dts/omap4-var-om44customboard.dtsi
+++ b/arch/arm/boot/dts/omap4-var-om44customboard.dtsi
@@ -41,7 +41,7 @@
label = "user";
gpios = <&gpio6 24 GPIO_ACTIVE_HIGH>; /* gpio 184 */
linux,code = <BTN_EXTRA>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 5a206c100ce2..2bd9c83300b2 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -348,12 +348,22 @@
#interrupt-cells = <2>;
};
+ elm: elm@48078000 {
+ compatible = "ti,am3352-elm";
+ reg = <0x48078000 0x2000>;
+ interrupts = <4>;
+ ti,hwmods = "elm";
+ status = "disabled";
+ };
+
gpmc: gpmc@50000000 {
compatible = "ti,omap4430-gpmc";
reg = <0x50000000 0x1000>;
#address-cells = <2>;
#size-cells = <1>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&sdma 4>;
+ dma-names = "rxtx";
gpmc,num-cs = <8>;
gpmc,num-waitpins = <4>;
ti,hwmods = "gpmc";
diff --git a/arch/arm/boot/dts/omap5-board-common.dtsi b/arch/arm/boot/dts/omap5-board-common.dtsi
index 5cf76a1c5c75..888412c63f97 100644
--- a/arch/arm/boot/dts/omap5-board-common.dtsi
+++ b/arch/arm/boot/dts/omap5-board-common.dtsi
@@ -139,60 +139,60 @@
twl6040_pins: pinmux_twl6040_pins {
pinctrl-single,pins = <
- 0x17e (PIN_OUTPUT | MUX_MODE6) /* mcspi1_somi.gpio5_141 */
+ OMAP5_IOPAD(0x1be, PIN_OUTPUT | MUX_MODE6) /* mcspi1_somi.gpio5_141 */
>;
};
mcpdm_pins: pinmux_mcpdm_pins {
pinctrl-single,pins = <
- 0x142 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
- 0x15c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_ul_data.abemcpdm_ul_data */
- 0x15e (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_dl_data.abemcpdm_dl_data */
- 0x160 (PIN_INPUT_PULLUP | MUX_MODE0) /* abemcpdm_frame.abemcpdm_frame */
- 0x162 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_lb_clk.abemcpdm_lb_clk */
+ OMAP5_IOPAD(0x182, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
+ OMAP5_IOPAD(0x19c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_ul_data.abemcpdm_ul_data */
+ OMAP5_IOPAD(0x19e, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_dl_data.abemcpdm_dl_data */
+ OMAP5_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE0) /* abemcpdm_frame.abemcpdm_frame */
+ OMAP5_IOPAD(0x1a2, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_lb_clk.abemcpdm_lb_clk */
>;
};
mcbsp1_pins: pinmux_mcbsp1_pins {
pinctrl-single,pins = <
- 0x14c (PIN_INPUT | MUX_MODE1) /* abedmic_clk2.abemcbsp1_fsx */
- 0x14e (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* abedmic_clk3.abemcbsp1_dx */
- 0x150 (PIN_INPUT | MUX_MODE1) /* abeslimbus1_clock.abemcbsp1_clkx */
- 0x152 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* abeslimbus1_data.abemcbsp1_dr */
+ OMAP5_IOPAD(0x18c, PIN_INPUT | MUX_MODE1) /* abedmic_clk2.abemcbsp1_fsx */
+ OMAP5_IOPAD(0x18e, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* abedmic_clk3.abemcbsp1_dx */
+ OMAP5_IOPAD(0x190, PIN_INPUT | MUX_MODE1) /* abeslimbus1_clock.abemcbsp1_clkx */
+ OMAP5_IOPAD(0x192, PIN_INPUT_PULLDOWN | MUX_MODE1) /* abeslimbus1_data.abemcbsp1_dr */
>;
};
mcbsp2_pins: pinmux_mcbsp2_pins {
pinctrl-single,pins = <
- 0x154 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dr.abemcbsp2_dr */
- 0x156 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dx.abemcbsp2_dx */
- 0x158 (PIN_INPUT | MUX_MODE0) /* abemcbsp2_fsx.abemcbsp2_fsx */
- 0x15a (PIN_INPUT | MUX_MODE0) /* abemcbsp2_clkx.abemcbsp2_clkx */
+ OMAP5_IOPAD(0x194, PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dr.abemcbsp2_dr */
+ OMAP5_IOPAD(0x196, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dx.abemcbsp2_dx */
+ OMAP5_IOPAD(0x198, PIN_INPUT | MUX_MODE0) /* abemcbsp2_fsx.abemcbsp2_fsx */
+ OMAP5_IOPAD(0x19a, PIN_INPUT | MUX_MODE0) /* abemcbsp2_clkx.abemcbsp2_clkx */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x1b2 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
- 0x1b4 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ OMAP5_IOPAD(0x1f2, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ OMAP5_IOPAD(0x1f4, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
>;
};
mcspi2_pins: pinmux_mcspi2_pins {
pinctrl-single,pins = <
- 0xbc (PIN_INPUT | MUX_MODE0) /* mcspi2_clk */
- 0xbe (PIN_INPUT | MUX_MODE0) /* mcspi2_simo */
- 0xc0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mcspi2_somi */
- 0xc2 (PIN_OUTPUT | MUX_MODE0) /* mcspi2_cs0 */
+ OMAP5_IOPAD(0x0fc, PIN_INPUT | MUX_MODE0) /* mcspi2_clk */
+ OMAP5_IOPAD(0x0fe, PIN_INPUT | MUX_MODE0) /* mcspi2_simo */
+ OMAP5_IOPAD(0x100, PIN_INPUT_PULLUP | MUX_MODE0) /* mcspi2_somi */
+ OMAP5_IOPAD(0x102, PIN_OUTPUT | MUX_MODE0) /* mcspi2_cs0 */
>;
};
mcspi3_pins: pinmux_mcspi3_pins {
pinctrl-single,pins = <
- 0x78 (PIN_INPUT | MUX_MODE1) /* mcspi3_somi */
- 0x7a (PIN_INPUT | MUX_MODE1) /* mcspi3_cs0 */
- 0x7c (PIN_INPUT | MUX_MODE1) /* mcspi3_simo */
- 0x7e (PIN_INPUT | MUX_MODE1) /* mcspi3_clk */
+ OMAP5_IOPAD(0x0b8, PIN_INPUT | MUX_MODE1) /* mcspi3_somi */
+ OMAP5_IOPAD(0x0ba, PIN_INPUT | MUX_MODE1) /* mcspi3_cs0 */
+ OMAP5_IOPAD(0x0bc, PIN_INPUT | MUX_MODE1) /* mcspi3_simo */
+ OMAP5_IOPAD(0x0be, PIN_INPUT | MUX_MODE1) /* mcspi3_clk */
>;
};
@@ -215,59 +215,59 @@
usbhost_pins: pinmux_usbhost_pins {
pinctrl-single,pins = <
- 0x84 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_strobe */
- 0x86 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_data */
+ OMAP5_IOPAD(0x0c4, PIN_INPUT | MUX_MODE0) /* usbb2_hsic_strobe */
+ OMAP5_IOPAD(0x0c6, PIN_INPUT | MUX_MODE0) /* usbb2_hsic_data */
- 0x19e (PIN_INPUT | MUX_MODE0) /* usbb3_hsic_strobe */
- 0x1a0 (PIN_INPUT | MUX_MODE0) /* usbb3_hsic_data */
+ OMAP5_IOPAD(0x1de, PIN_INPUT | MUX_MODE0) /* usbb3_hsic_strobe */
+ OMAP5_IOPAD(0x1e0, PIN_INPUT | MUX_MODE0) /* usbb3_hsic_data */
- 0x70 (PIN_OUTPUT | MUX_MODE6) /* gpio3_80 HUB_NRESET */
- 0x6e (PIN_OUTPUT | MUX_MODE6) /* gpio3_79 ETH_NRESET */
+ OMAP5_IOPAD(0x0b0, PIN_OUTPUT | MUX_MODE6) /* gpio3_80 HUB_NRESET */
+ OMAP5_IOPAD(0x0ae, PIN_OUTPUT | MUX_MODE6) /* gpio3_79 ETH_NRESET */
>;
};
led_gpio_pins: pinmux_led_gpio_pins {
pinctrl-single,pins = <
- 0x196 (PIN_OUTPUT | MUX_MODE6) /* uart3_cts_rctx.gpio5_153 */
+ OMAP5_IOPAD(0x1d6, PIN_OUTPUT | MUX_MODE6) /* uart3_cts_rctx.gpio5_153 */
>;
};
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x60 (PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_cts */
- 0x62 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_tx.uart1_cts */
- 0x64 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rx.uart1_rts */
- 0x66 (PIN_OUTPUT | MUX_MODE0) /* uart1_rx.uart1_rts */
+ OMAP5_IOPAD(0x0a0, PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_cts */
+ OMAP5_IOPAD(0x0a2, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_tx.uart1_cts */
+ OMAP5_IOPAD(0x0a4, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rx.uart1_rts */
+ OMAP5_IOPAD(0x0a6, PIN_OUTPUT | MUX_MODE0) /* uart1_rx.uart1_rts */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x19a (PIN_OUTPUT | MUX_MODE0) /* uart3_rts_irsd.uart3_tx_irtx */
- 0x19c (PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_rx_irrx.uart3_usbb3_hsic */
+ OMAP5_IOPAD(0x1da, PIN_OUTPUT | MUX_MODE0) /* uart3_rts_irsd.uart3_tx_irtx */
+ OMAP5_IOPAD(0x1dc, PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_rx_irrx.uart3_usbb3_hsic */
>;
};
uart5_pins: pinmux_uart5_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_rx.uart5_rx */
- 0x172 (PIN_OUTPUT | MUX_MODE0) /* uart5_tx.uart5_tx */
- 0x174 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_cts.uart5_rts */
- 0x176 (PIN_OUTPUT | MUX_MODE0) /* uart5_cts.uart5_rts */
+ OMAP5_IOPAD(0x1b0, PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_rx.uart5_rx */
+ OMAP5_IOPAD(0x1b2, PIN_OUTPUT | MUX_MODE0) /* uart5_tx.uart5_tx */
+ OMAP5_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_cts.uart5_rts */
+ OMAP5_IOPAD(0x1b6, PIN_OUTPUT | MUX_MODE0) /* uart5_cts.uart5_rts */
>;
};
dss_hdmi_pins: pinmux_dss_hdmi_pins {
pinctrl-single,pins = <
- 0x0fc (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x100 (PIN_INPUT | MUX_MODE0) /* hdmi_ddc_scl.hdmi_ddc_scl */
- 0x102 (PIN_INPUT | MUX_MODE0) /* hdmi_ddc_sda.hdmi_ddc_sda */
+ OMAP5_IOPAD(0x13c, PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ OMAP5_IOPAD(0x140, PIN_INPUT | MUX_MODE0) /* hdmi_ddc_scl.hdmi_ddc_scl */
+ OMAP5_IOPAD(0x142, PIN_INPUT | MUX_MODE0) /* hdmi_ddc_sda.hdmi_ddc_sda */
>;
};
tpd12s015_pins: pinmux_tpd12s015_pins {
pinctrl-single,pins = <
- 0x0fe (PIN_INPUT_PULLDOWN | MUX_MODE6) /* hdmi_hpd.gpio7_193 */
+ OMAP5_IOPAD(0x13e, PIN_INPUT_PULLDOWN | MUX_MODE6) /* hdmi_hpd.gpio7_193 */
>;
};
};
@@ -280,13 +280,13 @@
usbhost_wkup_pins: pinmux_usbhost_wkup_pins {
pinctrl-single,pins = <
- 0x1A (PIN_OUTPUT | MUX_MODE0) /* fref_clk1_out, USB hub clk */
+ OMAP5_IOPAD(0x05a, PIN_OUTPUT | MUX_MODE0) /* fref_clk1_out, USB hub clk */
>;
};
wlcore_irq_pin: pinmux_wlcore_irq_pin {
pinctrl-single,pins = <
- OMAP5_IOPAD(0x040, WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE6) /* llia_wakereqin.gpio1_wk14 */
+ OMAP5_IOPAD(0x40, WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE6) /* llia_wakereqin.gpio1_wk14 */
>;
};
};
diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts
index 3774b37be6c8..ecc591dc0778 100644
--- a/arch/arm/boot/dts/omap5-cm-t54.dts
+++ b/arch/arm/boot/dts/omap5-cm-t54.dts
@@ -175,7 +175,7 @@
ads7846_pins: pinmux_ads7846_pins {
pinctrl-single,pins = <
- 0x02 (PIN_INPUT_PULLDOWN | MUX_MODE6) /* llib_wakereqin.gpio1_wk15 */
+ OMAP5_IOPAD(0x0042, PIN_INPUT_PULLDOWN | MUX_MODE6) /* llib_wakereqin.gpio1_wk15 */
>;
};
};
@@ -359,7 +359,7 @@
ti,debounce-tol = /bits/ 16 <10>;
ti,debounce-rep = /bits/ 16 <1>;
- linux,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts
index 05b1c1ebded8..60b3fbb3bf07 100644
--- a/arch/arm/boot/dts/omap5-uevm.dts
+++ b/arch/arm/boot/dts/omap5-uevm.dts
@@ -40,8 +40,8 @@
&omap5_pmx_core {
i2c5_pins: pinmux_i2c5_pins {
pinctrl-single,pins = <
- 0x186 (PIN_INPUT | MUX_MODE0) /* i2c5_scl */
- 0x188 (PIN_INPUT | MUX_MODE0) /* i2c5_sda */
+ OMAP5_IOPAD(0x1c6, PIN_INPUT | MUX_MODE0) /* i2c5_scl */
+ OMAP5_IOPAD(0x1c8, PIN_INPUT | MUX_MODE0) /* i2c5_sda */
>;
};
};
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 4c04389dab32..ca3c17fde5a0 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -391,6 +391,8 @@
#address-cells = <2>;
#size-cells = <1>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&sdma 4>;
+ dma-names = "rxtx";
gpmc,num-cs = <8>;
gpmc,num-waitpins = <4>;
ti,hwmods = "gpmc";
diff --git a/arch/arm/boot/dts/phy3250.dts b/arch/arm/boot/dts/phy3250.dts
index 90fdbd77f274..7d253bb6265a 100644
--- a/arch/arm/boot/dts/phy3250.dts
+++ b/arch/arm/boot/dts/phy3250.dts
@@ -12,7 +12,7 @@
*/
/dts-v1/;
-/include/ "lpc32xx.dtsi"
+#include "lpc32xx.dtsi"
/ {
model = "PHYTEC phyCORE-LPC3250 board based on NXP LPC3250";
@@ -22,7 +22,7 @@
memory {
device_type = "memory";
- reg = <0 0x4000000>;
+ reg = <0x80000000 0x4000000>;
};
ahb {
@@ -31,19 +31,6 @@
use-iram;
};
- /* Here, choose exactly one from: ohci, usbd */
- ohci@31020000 {
- transceiver = <&isp1301>;
- status = "okay";
- };
-
-/*
- usbd@31020000 {
- transceiver = <&isp1301>;
- status = "okay";
- };
-*/
-
clcd@31040000 {
status = "okay";
};
@@ -123,15 +110,6 @@
clock-frequency = <100000>;
};
- i2cusb: i2c@31020300 {
- clock-frequency = <100000>;
-
- isp1301: usb-transceiver@2c {
- compatible = "nxp,isp1301";
- reg = <0x2c>;
- };
- };
-
ssp0: ssp@20084000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -200,3 +178,18 @@
};
};
};
+
+/* Here, choose exactly one from: ohci, usbd */
+&ohci /* &usbd */ {
+ transceiver = <&isp1301>;
+ status = "okay";
+};
+
+&i2cusb {
+ clock-frequency = <100000>;
+
+ isp1301: usb-transceiver@2c {
+ compatible = "nxp,isp1301";
+ reg = <0x2c>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
index 03784f1366e5..21095dad7741 100644
--- a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
@@ -54,7 +54,7 @@
/* Buck SMPS */
- pm8921_s1: s1 {
+ s1 {
regulator-always-on;
regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1225000>;
@@ -62,43 +62,43 @@
bias-pull-down;
};
- pm8921_s3: s3 {
+ s3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1400000>;
qcom,switch-mode-frequency = <4800000>;
};
- pm8921_s4: s4 {
+ s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,switch-mode-frequency = <3200000>;
};
- pm8921_s7: s7 {
+ s7 {
regulator-min-microvolt = <1300000>;
regulator-max-microvolt = <1300000>;
qcom,switch-mode-frequency = <3200000>;
};
- pm8921_l3: l3 {
+ l3 {
regulator-min-microvolt = <3050000>;
regulator-max-microvolt = <3300000>;
bias-pull-down;
};
- pm8921_l4: l4 {
+ l4 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1800000>;
bias-pull-down;
};
- pm8921_l5: l5 {
+ l5 {
regulator-min-microvolt = <2750000>;
regulator-max-microvolt = <3000000>;
bias-pull-down;
};
- pm8921_l23: l23 {
+ l23 {
regulator-min-microvolt = <1700000>;
regulator-max-microvolt = <1900000>;
bias-pull-down;
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index 11ac608b6d50..aa9303b84d67 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -64,7 +64,7 @@
/* Buck SMPS */
- pm8921_s1: s1 {
+ s1 {
regulator-always-on;
regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1225000>;
@@ -72,55 +72,55 @@
bias-pull-down;
};
- pm8921_s3: s3 {
+ s3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1400000>;
qcom,switch-mode-frequency = <4800000>;
};
- pm8921_s4: s4 {
+ s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,switch-mode-frequency = <3200000>;
};
- pm8921_s7: s7 {
+ s7 {
regulator-min-microvolt = <1300000>;
regulator-max-microvolt = <1300000>;
qcom,switch-mode-frequency = <3200000>;
};
- pm8921_l3: l3 {
+ l3 {
regulator-min-microvolt = <3050000>;
regulator-max-microvolt = <3300000>;
bias-pull-down;
};
- pm8921_l4: l4 {
+ l4 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1800000>;
bias-pull-down;
};
- pm8921_l5: l5 {
+ l5 {
regulator-min-microvolt = <2750000>;
regulator-max-microvolt = <3000000>;
bias-pull-down;
};
- pm8921_l6: l6 {
+ l6 {
regulator-min-microvolt = <2950000>;
regulator-max-microvolt = <2950000>;
bias-pull-down;
};
- pm8921_l23: l23 {
+ l23 {
regulator-min-microvolt = <1700000>;
regulator-max-microvolt = <1900000>;
bias-pull-down;
};
- pm8921_lvs1: lvs1 {
+ lvs1 {
bias-pull-down;
};
};
@@ -164,7 +164,7 @@
gsbi@16500000 {
status = "ok";
- qcom,mode = <GSBI_PROT_I2C_UART>;
+ qcom,mode = <GSBI_PROT_UART_W_FC>;
serial@16540000 {
status = "ok";
diff --git a/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts b/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts
new file mode 100644
index 000000000000..06b3c76c3e41
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts
@@ -0,0 +1,436 @@
+#include "qcom-apq8064-v2.0.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+/ {
+ model = "Sony Xperia Z";
+ compatible = "sony,xperia-yuga", "qcom,apq8064";
+
+ aliases {
+ serial0 = &gsbi5_serial;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_keys_pin_a>;
+
+ camera-focus {
+ label = "camera_focus";
+ gpios = <&pm8921_gpio 3 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_CAMERA_FOCUS>;
+ };
+
+ camera-snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8921_gpio 4 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_CAMERA>;
+ };
+
+ volume-down {
+ label = "volume_down";
+ gpios = <&pm8921_gpio 29 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ };
+
+ volume-up {
+ label = "volume_up";
+ gpios = <&pm8921_gpio 35 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEUP>;
+ };
+ };
+
+ soc {
+ pinctrl@800000 {
+ gsbi5_uart_pin_a: gsbi5-uart-pin-active {
+ rx {
+ pins = "gpio52";
+ function = "gsbi5";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ tx {
+ pins = "gpio51";
+ function = "gsbi5";
+ drive-strength = <4>;
+ bias-disable;
+ };
+ };
+
+ sdcc1_pin_a: sdcc1-pin-active {
+ clk {
+ pins = "sdc1_clk";
+ drive-strengh = <16>;
+ bias-disable;
+ };
+
+ cmd {
+ pins = "sdc1_cmd";
+ drive-strengh = <10>;
+ bias-pull-up;
+ };
+
+ data {
+ pins = "sdc1_data";
+ drive-strengh = <10>;
+ bias-pull-up;
+ };
+ };
+
+ sdcc3_pin_a: sdcc3-pin-active {
+ clk {
+ pins = "sdc3_clk";
+ drive-strengh = <8>;
+ bias-disable;
+ };
+
+ cmd {
+ pins = "sdc3_cmd";
+ drive-strengh = <8>;
+ bias-pull-up;
+ };
+
+ data {
+ pins = "sdc3_data";
+ drive-strengh = <8>;
+ bias-pull-up;
+ };
+ };
+
+ sdcc3_cd_pin_a: sdcc3-cd-pin-active {
+ pins = "gpio26";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+
+ rpm@108000 {
+ regulators {
+ vin_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vin_lvs_1_3_6-supply = <&pm8921_s4>;
+ vin_lvs_4_5_7-supply = <&pm8921_s4>;
+ vin_ncp-supply = <&pm8921_l6>;
+ vin_lvs2-supply = <&pm8921_s4>;
+ vin_l24-supply = <&pm8921_s1>;
+ vin_l25-supply = <&pm8921_s1>;
+ vin_l27-supply = <&pm8921_s7>;
+ vin_l28-supply = <&pm8921_s7>;
+
+ /* Buck SMPS */
+ s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
+ };
+
+ s2 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+
+ s3 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,switch-mode-frequency = <4800000>;
+ bias-pull-down;
+ };
+
+ s4 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ qcom,force-mode = <QCOM_RPM_FORCE_MODE_AUTO>;
+ };
+
+ s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ s8 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ qcom,switch-mode-frequency = <1600000>;
+ };
+
+ /* PMOS LDO */
+ l1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ bias-pull-down;
+ };
+
+ l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+
+ l3 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ bias-pull-down;
+ };
+
+ l4 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l5 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l6 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l7 {
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l8 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ bias-pull-down;
+ };
+
+ l9 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
+ };
+
+ l10 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ bias-pull-down;
+ };
+
+ l11 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
+ };
+
+ l12 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+
+ l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l16 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ bias-pull-down;
+ };
+
+ l17 {
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ bias-pull-down;
+ };
+
+ l18 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+
+ l21 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ bias-pull-down;
+ };
+
+ l22 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+
+ l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l24 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1150000>;
+ bias-pull-down;
+ };
+
+ l25 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ bias-pull-down;
+ };
+
+ l27 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ l28 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ bias-pull-down;
+ };
+
+ l29 {
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ bias-pull-down;
+ };
+
+ /* Low Voltage Switch */
+ lvs1 {
+ bias-pull-down;
+ };
+
+ lvs2 {
+ bias-pull-down;
+ };
+
+ lvs3 {
+ bias-pull-down;
+ };
+
+ lvs4 {
+ bias-pull-down;
+ };
+
+ lvs5 {
+ bias-pull-down;
+ };
+
+ lvs6 {
+ bias-pull-down;
+ };
+
+ lvs7 {
+ bias-pull-down;
+ };
+
+ usb-switch {};
+
+ hdmi-switch {};
+
+ ncp {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ };
+ };
+ };
+
+ qcom,ssbi@500000 {
+ pmic@0 {
+ gpio@150 {
+ gpio_keys_pin_a: gpio-keys-pin-active {
+ pins = "gpio3", "gpio4", "gpio29", "gpio35";
+ function = "normal";
+
+ bias-pull-up;
+ drive-push-pull;
+ input-enable;
+ power-source = <2>;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+ qcom,pull-up-strength = <0>;
+ };
+ };
+ };
+ };
+
+ phy@12500000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+ };
+
+ gadget@12500000 {
+ status = "okay";
+ };
+
+ gsbi@1a200000 {
+ status = "ok";
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+
+ serial@1a240000 {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi5_uart_pin_a>;
+ };
+ };
+
+ amba {
+ sdcc1: sdcc@12400000 {
+ status = "okay";
+
+ vmmc-supply = <&pm8921_l5>;
+ vqmmc-supply = <&pm8921_s4>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdcc1_pin_a>;
+ };
+
+ sdcc3: sdcc@12180000 {
+ status = "okay";
+
+ vmmc-supply = <&pm8921_l6>;
+ cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdcc3_pin_a>, <&sdcc3_cd_pin_a>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index a4c1762b53ea..edfc6ee56ea1 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -11,6 +11,17 @@
compatible = "qcom,apq8064";
interrupt-parent = <&intc>;
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ smem_region: smem@80000000 {
+ reg = <0x80000000 0x200000>;
+ no-map;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -80,6 +91,39 @@
interrupts = <1 10 0x304>;
};
+ clocks {
+ cxo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ };
+
+ pxo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+
+ sleep_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+ };
+
+ sfpb_mutex: hwmutex {
+ compatible = "qcom,sfpb-mutex";
+ syscon = <&sfpb_wrapper_mutex 0x604 0x4>;
+ #hwlock-cells = <1>;
+ };
+
+ smem {
+ compatible = "qcom,smem";
+ memory-region = <&smem_region>;
+
+ hwlocks = <&sfpb_mutex 3>;
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -156,6 +200,11 @@
};
};
+ sfpb_wrapper_mutex: syscon@1200000 {
+ compatible = "syscon";
+ reg = <0x01200000 0x8000>;
+ };
+
intc: interrupt-controller@2000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -291,6 +340,28 @@
};
};
+ gsbi5: gsbi@1a200000 {
+ status = "disabled";
+ compatible = "qcom,gsbi-v1.0.0";
+ cell-index = <5>;
+ reg = <0x1a200000 0x03>;
+ clocks = <&gcc GSBI5_H_CLK>;
+ clock-names = "iface";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gsbi5_serial: serial@1a240000 {
+ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+ reg = <0x1a240000 0x100>,
+ <0x1a200000 0x03>;
+ interrupts = <0 154 0x0>;
+ clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+ };
+
gsbi6: gsbi@16500000 {
status = "disabled";
compatible = "qcom,gsbi-v1.0.0";
@@ -336,6 +407,13 @@
};
};
+ rng@1a500000 {
+ compatible = "qcom,prng";
+ reg = <0x1a500000 0x200>;
+ clocks = <&gcc PRNG_CLK>;
+ clock-names = "core";
+ };
+
qcom,ssbi@500000 {
compatible = "qcom,ssbi";
reg = <0x00500000 0x1000>;
@@ -352,7 +430,8 @@
pm8921_gpio: gpio@150 {
- compatible = "qcom,pm8921-gpio";
+ compatible = "qcom,pm8921-gpio",
+ "qcom,ssbi-gpio";
reg = <0x150>;
interrupts = <192 1>, <193 1>, <194 1>,
<195 1>, <196 1>, <197 1>,
@@ -376,7 +455,8 @@
};
pm8921_mpps: mpps@50 {
- compatible = "qcom,pm8921-mpp";
+ compatible = "qcom,pm8921-mpp",
+ "qcom,ssbi-mpp";
reg = <0x50>;
gpio-controller;
#gpio-cells = <2>;
@@ -444,9 +524,55 @@
regulators {
compatible = "qcom,rpm-pm8921-regulators";
+ pm8921_s1: s1 {};
+ pm8921_s2: s2 {};
+ pm8921_s3: s3 {};
+ pm8921_s4: s4 {};
+ pm8921_s7: s7 {};
+ pm8921_s8: s8 {};
+
+ pm8921_l1: l1 {};
+ pm8921_l2: l2 {};
+ pm8921_l3: l3 {};
+ pm8921_l4: l4 {};
+ pm8921_l5: l5 {};
+ pm8921_l6: l6 {};
+ pm8921_l7: l7 {};
+ pm8921_l8: l8 {};
+ pm8921_l9: l9 {};
+ pm8921_l10: l10 {};
+ pm8921_l11: l11 {};
+ pm8921_l12: l12 {};
+ pm8921_l14: l14 {};
+ pm8921_l15: l15 {};
+ pm8921_l16: l16 {};
+ pm8921_l17: l17 {};
+ pm8921_l18: l18 {};
+ pm8921_l21: l21 {};
+ pm8921_l22: l22 {};
+ pm8921_l23: l23 {};
+ pm8921_l24: l24 {};
+ pm8921_l25: l25 {};
+ pm8921_l26: l26 {};
+ pm8921_l27: l27 {};
+ pm8921_l28: l28 {};
+ pm8921_l29: l29 {};
+
+ pm8921_lvs1: lvs1 {};
+ pm8921_lvs2: lvs2 {};
+ pm8921_lvs3: lvs3 {};
+ pm8921_lvs4: lvs4 {};
+ pm8921_lvs5: lvs5 {};
+ pm8921_lvs6: lvs6 {};
+ pm8921_lvs7: lvs7 {};
+
+ pm8921_usb_switch: usb-switch {};
+
pm8921_hdmi_switch: hdmi-switch {
bias-pull-down;
};
+
+ pm8921_ncp: ncp {};
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts
index 835bdc71c5ba..c0e205315042 100644
--- a/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts
+++ b/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts
@@ -8,6 +8,8 @@
aliases {
serial0 = &blsp1_uart2;
+ usid0 = &pm8941_0;
+ usid4 = &pm8841_0;
};
chosen {
diff --git a/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts b/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts
index c9c2b769554f..2052b84a77c6 100644
--- a/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts
+++ b/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts
@@ -3,10 +3,11 @@
/ {
model = "Qualcomm APQ8084/IFC6540";
- compatible = "qcom,apq8084-ifc6540", "qcom,apq8084";
+ compatible = "qcom,apq8084-sbc", "qcom,apq8084";
aliases {
serial0 = &blsp2_uart2;
+ usid0 = &pma8084_0;
};
chosen {
diff --git a/arch/arm/boot/dts/qcom-apq8084-mtp.dts b/arch/arm/boot/dts/qcom-apq8084-mtp.dts
index 3016c7048d44..d174d15bcf70 100644
--- a/arch/arm/boot/dts/qcom-apq8084-mtp.dts
+++ b/arch/arm/boot/dts/qcom-apq8084-mtp.dts
@@ -7,6 +7,7 @@
aliases {
serial0 = &blsp2_uart2;
+ usid0 = &pma8084_0;
};
chosen {
diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi
index fcffecae3e67..08214cbae16d 100644
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -10,6 +10,17 @@
compatible = "qcom,apq8084";
interrupt-parent = <&intc>;
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ smem_mem: smem_region@fa00000 {
+ reg = <0xfa00000 0x200000>;
+ no-map;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -89,6 +100,15 @@
clock-frequency = <19200000>;
};
+ smem {
+ compatible = "qcom,smem";
+
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+ memory-region = <&smem_mem>;
+
+ hwlocks = <&tcsr_mutex 3>;
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -103,6 +123,11 @@
<0xf9002000 0x1000>;
};
+ apcs: syscon@f9011000 {
+ compatible = "syscon";
+ reg = <0xf9011000 0x1000>;
+ };
+
timer@f9020000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -225,6 +250,22 @@
reg = <0xfc400000 0x4000>;
};
+ tcsr_mutex_regs: syscon@fd484000 {
+ compatible = "syscon";
+ reg = <0xfd484000 0x2000>;
+ };
+
+ tcsr_mutex: hwlock {
+ compatible = "qcom,tcsr-mutex";
+ syscon = <&tcsr_mutex_regs 0 0x80>;
+ #hwlock-cells = <1>;
+ };
+
+ rpm_msg_ram: memory@fc428000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0xfc428000 0x4000>;
+ };
+
tlmm: pinctrl@fd510000 {
compatible = "qcom,apq8084-pinctrl";
reg = <0xfd510000 0x4000>;
@@ -282,4 +323,71 @@
#interrupt-cells = <4>;
};
};
+
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <0 168 1>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-apq8084";
+ qcom,smd-channels = "rpm_requests";
+
+ pma8084-regulators {
+ compatible = "qcom,rpm-pma8084-regulators";
+
+ pma8084_s1: s1 {};
+ pma8084_s2: s2 {};
+ pma8084_s3: s3 {};
+ pma8084_s4: s4 {};
+ pma8084_s5: s5 {};
+ pma8084_s6: s6 {};
+ pma8084_s7: s7 {};
+ pma8084_s8: s8 {};
+ pma8084_s9: s9 {};
+ pma8084_s10: s10 {};
+ pma8084_s11: s11 {};
+ pma8084_s12: s12 {};
+
+ pma8084_l1: l1 {};
+ pma8084_l2: l2 {};
+ pma8084_l3: l3 {};
+ pma8084_l4: l4 {};
+ pma8084_l5: l5 {};
+ pma8084_l6: l6 {};
+ pma8084_l7: l7 {};
+ pma8084_l8: l8 {};
+ pma8084_l9: l9 {};
+ pma8084_l10: l10 {};
+ pma8084_l11: l11 {};
+ pma8084_l12: l12 {};
+ pma8084_l13: l13 {};
+ pma8084_l14: l14 {};
+ pma8084_l15: l15 {};
+ pma8084_l16: l16 {};
+ pma8084_l17: l17 {};
+ pma8084_l18: l18 {};
+ pma8084_l19: l19 {};
+ pma8084_l20: l20 {};
+ pma8084_l21: l21 {};
+ pma8084_l22: l22 {};
+ pma8084_l23: l23 {};
+ pma8084_l24: l24 {};
+ pma8084_l25: l25 {};
+ pma8084_l26: l26 {};
+ pma8084_l27: l27 {};
+
+ pma8084_lvs1: lvs1 {};
+ pma8084_lvs2: lvs2 {};
+ pma8084_lvs3: lvs3 {};
+ pma8084_lvs4: lvs4 {};
+
+ pma8084_5vs1: 5vs1 {};
+ };
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi
index 134cd91d68ec..51a40d84145c 100644
--- a/arch/arm/boot/dts/qcom-msm8960.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8960.dtsi
@@ -49,6 +49,29 @@
qcom,no-pc-write;
};
+ clocks {
+ cxo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ clock-output-names = "cxo_board";
+ };
+
+ pxo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ clock-output-names = "pxo_board";
+ };
+
+ sleep_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "sleep_clk";
+ };
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts
index 016f9ad9392a..a0398b69f4f2 100644
--- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts
@@ -1,6 +1,9 @@
#include "qcom-msm8974.dtsi"
#include "qcom-pm8841.dtsi"
#include "qcom-pm8941.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
/ {
model = "Sony Xperia Z1";
@@ -14,24 +17,403 @@
stdout-path = "serial0:115200n8";
};
+ gpio-keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_keys_pin_a>;
+
+ volume-down {
+ label = "volume_down";
+ gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ };
+
+ camera-snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_CAMERA>;
+ };
+
+ camera-focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_CAMERA_FOCUS>;
+ };
+
+ volume-up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEUP>;
+ };
+ };
+
memory@0 {
reg = <0 0x40000000>, <0x40000000 0x40000000>;
device_type = "memory";
};
+
+ smd {
+ rpm {
+ rpm_requests {
+ pm8841-regulators {
+ s1 {
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ s2 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ s3 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ s4 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ };
+ };
+
+ pm8941-regulators {
+ vdd_l1_l3-supply = <&pm8941_s1>;
+ vdd_l2_lvs1_2_3-supply = <&pm8941_s3>;
+ vdd_l4_l11-supply = <&pm8941_s1>;
+ vdd_l5_l7-supply = <&pm8941_s2>;
+ vdd_l6_l12_l14_l15-supply = <&pm8941_s2>;
+ vdd_l9_l10_l17_l22-supply = <&vreg_boost>;
+ vdd_l13_l20_l23_l24-supply = <&vreg_boost>;
+ vdd_l21-supply = <&vreg_boost>;
+ vin_5vs-supply = <&pm8941_5v>;
+
+ s1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ s2 {
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ regulator-boot-on;
+ };
+
+ s3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ s4 {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ l3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ l4 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-boot-on;
+ };
+
+ l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-boot-on;
+ };
+
+ l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ l11 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ l15 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ l16 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ l17 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ l18 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ l19 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ l20 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-allow-set-load;
+ regulator-boot-on;
+ regulator-system-load = <200000>;
+ };
+
+ l21 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ l22 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ l23 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ l24 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+
+ regulator-boot-on;
+ };
+ };
+ };
+ };
+ };
+
+ vreg_boost: vreg-boost {
+ compatible = "regulator-fixed";
+
+ regulator-name = "vreg-boost";
+ regulator-min-microvolt = <3150000>;
+ regulator-max-microvolt = <3150000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+
+ gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&boost_bypass_n_pin>;
+ };
};
&soc {
+ sdhci@f9824900 {
+ status = "ok";
+
+ vmmc-supply = <&pm8941_l20>;
+ vqmmc-supply = <&pm8941_s3>;
+
+ bus-width = <8>;
+ non-removable;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdhc1_pin_a>;
+ };
+
+ sdhci@f98a4900 {
+ status = "ok";
+
+ bus-width = <4>;
+
+ vmmc-supply = <&pm8941_l21>;
+ vqmmc-supply = <&pm8941_l13>;
+
+ cd-gpios = <&msmgpio 62 GPIO_ACTIVE_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdhc2_pin_a>, <&sdhc2_cd_pin_a>;
+ };
+
serial@f991e000 {
status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&blsp1_uart2_pin_a>;
+ };
+
+ pinctrl@fd510000 {
+ blsp1_uart2_pin_a: blsp1-uart2-pin-active {
+ rx {
+ pins = "gpio5";
+ function = "blsp_uart2";
+
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ tx {
+ pins = "gpio4";
+ function = "blsp_uart2";
+
+ drive-strength = <4>;
+ bias-disable;
+ };
+ };
+
+ sdhc1_pin_a: sdhc1-pin-active {
+ clk {
+ pins = "sdc1_clk";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ cmd-data {
+ pins = "sdc1_cmd", "sdc1_data";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ };
+
+ sdhc2_cd_pin_a: sdhc2-cd-pin-active {
+ pins = "gpio62";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ sdhc2_pin_a: sdhc2-pin-active {
+ clk {
+ pins = "sdc2_clk";
+ drive-strength = <10>;
+ bias-disable;
+ };
+
+ cmd-data {
+ pins = "sdc2_cmd", "sdc2_data";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+ };
+
};
};
&spmi_bus {
pm8941@0 {
+ charger@1000 {
+ qcom,fast-charge-safe-current = <1500000>;
+ qcom,fast-charge-current-limit = <1500000>;
+ qcom,dc-current-limit = <1800000>;
+ qcom,fast-charge-safe-voltage = <4400000>;
+ qcom,fast-charge-high-threshold-voltage = <4350000>;
+ qcom,fast-charge-low-threshold-voltage = <3400000>;
+ qcom,auto-recharge-threshold-voltage = <4200000>;
+ qcom,minimum-input-voltage = <4300000>;
+ };
+
+ gpios@c000 {
+ boost_bypass_n_pin: boost-bypass {
+ pins = "gpio21";
+ function = "normal";
+ };
+
+ gpio_keys_pin_a: gpio-keys-active {
+ pins = "gpio2", "gpio3", "gpio4", "gpio5";
+ function = "normal";
+
+ bias-pull-up;
+ power-source = <PM8941_GPIO_S3>;
+ };
+ };
+
coincell@2800 {
status = "ok";
qcom,rset-ohms = <2100>;
qcom,vset-millivolts = <3000>;
};
};
+
+ pm8941@1 {
+ wled@d800 {
+ status = "ok";
+
+ qcom,cs-out;
+ qcom,current-limit = <20>;
+ qcom,current-boost-limit = <805>;
+ qcom,switching-freq = <1600>;
+ qcom,ovp = <29>;
+ qcom,num-strings = <2>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 753bdfddd46e..dfdafdcb8aae 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -319,6 +319,17 @@
interrupts = <0 208 0>;
};
+ blsp_i2c8: i2c@f9964000 {
+ status = "disabled";
+ compatible = "qcom,i2c-qup-v2.1.1";
+ reg = <0xf9964000 0x1000>;
+ interrupts = <0 102 IRQ_TYPE_NONE>;
+ clocks = <&gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
blsp_i2c11: i2c@f9967000 {
status = "disabled";
compatible = "qcom,i2c-qup-v2.1.1";
diff --git a/arch/arm/boot/dts/qcom-pm8841.dtsi b/arch/arm/boot/dts/qcom-pm8841.dtsi
index 8f1a0b162017..9f357f68713c 100644
--- a/arch/arm/boot/dts/qcom-pm8841.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8841.dtsi
@@ -3,14 +3,14 @@
&spmi_bus {
- usid4: pm8841@4 {
- compatible = "qcom,spmi-pmic";
+ pm8841_0: pm8841@4 {
+ compatible = "qcom,pm8841", "qcom,spmi-pmic";
reg = <0x4 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
pm8841_mpps: mpps@a000 {
- compatible = "qcom,pm8841-mpp";
+ compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp";
reg = <0xa000 0x400>;
gpio-controller;
#gpio-cells = <2>;
@@ -27,8 +27,8 @@
};
};
- usid5: pm8841@5 {
- compatible = "qcom,spmi-pmic";
+ pm8841_1: pm8841@5 {
+ compatible = "qcom,pm8841", "qcom,spmi-pmic";
reg = <0x5 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi
index b0d443999fcc..ca53a5947437 100644
--- a/arch/arm/boot/dts/qcom-pm8941.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8941.dtsi
@@ -4,8 +4,8 @@
&spmi_bus {
- usid0: pm8941@0 {
- compatible ="qcom,spmi-pmic";
+ pm8941_0: pm8941@0 {
+ compatible = "qcom,pm8941", "qcom,spmi-pmic";
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
@@ -48,7 +48,7 @@
};
pm8941_gpios: gpios@c000 {
- compatible = "qcom,pm8941-gpio";
+ compatible = "qcom,pm8941-gpio", "qcom,spmi-gpio";
reg = <0xc000 0x2400>;
gpio-controller;
#gpio-cells = <2>;
@@ -91,7 +91,7 @@
};
pm8941_mpps: mpps@a000 {
- compatible = "qcom,pm8941-mpp";
+ compatible = "qcom,pm8941-mpp", "qcom,spmi-mpp";
reg = <0xa000 0x800>;
gpio-controller;
#gpio-cells = <2>;
@@ -153,23 +153,18 @@
};
};
- usid1: pm8941@1 {
- compatible = "qcom,spmi-pmic";
+ pm8941_1: pm8941@1 {
+ compatible = "qcom,pm8941", "qcom,spmi-pmic";
reg = <0x1 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
- wled@d800 {
+ pm8941_wled: wled@d800 {
compatible = "qcom,pm8941-wled";
reg = <0xd800 0x100>;
label = "backlight";
- qcom,cs-out;
- qcom,current-limit = <20>;
- qcom,current-boost-limit = <805>;
- qcom,switching-freq = <1600>;
- qcom,ovp = <29>;
- qcom,num-strings = <2>;
+ status = "disabled";
};
};
};
diff --git a/arch/arm/boot/dts/qcom-pma8084.dtsi b/arch/arm/boot/dts/qcom-pma8084.dtsi
index 5e240ccc08b7..4e9bd3f88473 100644
--- a/arch/arm/boot/dts/qcom-pma8084.dtsi
+++ b/arch/arm/boot/dts/qcom-pma8084.dtsi
@@ -4,8 +4,8 @@
&spmi_bus {
- usid0: pma8084@0 {
- compatible = "qcom,spmi-pmic";
+ pma8084_0: pma8084@0 {
+ compatible = "qcom,pma8084", "qcom,spmi-pmic";
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
@@ -19,7 +19,7 @@
};
pma8084_gpios: gpios@c000 {
- compatible = "qcom,pma8084-gpio";
+ compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio";
reg = <0xc000 0x1600>;
gpio-controller;
#gpio-cells = <2>;
@@ -48,7 +48,7 @@
};
pma8084_mpps: mpps@a000 {
- compatible = "qcom,pma8084-mpp";
+ compatible = "qcom,pma8084-mpp", "qcom,spmi-mpp";
reg = <0xa000 0x800>;
gpio-controller;
#gpio-cells = <2>;
@@ -101,8 +101,8 @@
};
};
- usid1: pma8084@1 {
- compatible = "qcom,spmi-pmic";
+ pma8084_1: pma8084@1 {
+ compatible = "qcom,pma8084", "qcom,spmi-pmic";
reg = <0x1 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
index 060c32cbd669..4657d7fb5bce 100644
--- a/arch/arm/boot/dts/r7s72100.dtsi
+++ b/arch/arm/boot/dts/r7s72100.dtsi
@@ -329,7 +329,7 @@
};
gic: interrupt-controller@e8201000 {
- compatible = "arm,cortex-a9-gic";
+ compatible = "arm,pl390";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm.dts b/arch/arm/boot/dts/r8a73a4-ape6evm.dts
index a4c425923c05..590257095700 100644
--- a/arch/arm/boot/dts/r8a73a4-ape6evm.dts
+++ b/arch/arm/boot/dts/r8a73a4-ape6evm.dts
@@ -23,7 +23,7 @@
chosen {
bootargs = "ignore_loglevel root=/dev/nfs ip=dhcp rw";
- stdout-path = &scifa0;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -110,7 +110,7 @@
gpios = <&pfc 324 GPIO_ACTIVE_LOW>;
linux,code = <KEY_0>;
label = "S16";
- gpio-key,wakeup;
+ wakeup-source;
};
menu-key {
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index 105d9c95de4a..78a21f2828df 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -85,7 +85,7 @@
gpios = <&pfc 99 GPIO_ACTIVE_LOW>;
linux,code = <KEY_POWER>;
label = "SW3";
- gpio-key,wakeup;
+ wakeup-source;
};
back-key {
diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
index e14cb1438216..6ef954766eef 100644
--- a/arch/arm/boot/dts/r8a7740.dtsi
+++ b/arch/arm/boot/dts/r8a7740.dtsi
@@ -26,17 +26,30 @@
reg = <0x0>;
clock-frequency = <800000000>;
power-domains = <&pd_a3sm>;
+ next-level-cache = <&L2>;
};
};
gic: interrupt-controller@c2800000 {
- compatible = "arm,cortex-a9-gic";
+ compatible = "arm,pl390";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xc2800000 0x1000>,
<0xc2000000 0x1000>;
};
+ L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xf0100000 0x1000>;
+ interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&pd_a3sm>;
+ arm,data-latency = <3 3 3>;
+ arm,tag-latency = <2 2 2>;
+ arm,shared-override;
+ cache-unified;
+ cache-level = <2>;
+ };
+
dbsc3: memory-controller@fe400000 {
compatible = "renesas,dbsc3-r8a7740";
reg = <0xfe400000 0x400>;
diff --git a/arch/arm/boot/dts/r8a7778-bockw.dts b/arch/arm/boot/dts/r8a7778-bockw.dts
index 90543b12d7e2..a52b359e2ae2 100644
--- a/arch/arm/boot/dts/r8a7778-bockw.dts
+++ b/arch/arm/boot/dts/r8a7778-bockw.dts
@@ -28,8 +28,8 @@
};
chosen {
- bootargs = "console=ttySC0,115200 ignore_loglevel ip=dhcp root=/dev/nfs rw";
- stdout-path = &scif0;
+ bootargs = "ignore_loglevel ip=dhcp root=/dev/nfs rw";
+ stdout-path = "serial0:115200n8";
};
memory {
@@ -137,10 +137,14 @@
};
sdhi0_pins: sd0 {
- renesas,groups = "sdhi0_data4", "sdhi0_ctrl",
- "sdhi0_cd";
+ renesas,groups = "sdhi0_data4", "sdhi0_ctrl";
renesas,function = "sdhi0";
};
+ sdhi0_pup_pins: sd0_pup {
+ renesas,groups = "sdhi0_cd", "sdhi0_wp";
+ renesas,function = "sdhi0";
+ bias-pull-up;
+ };
hspi0_pins: hspi0 {
renesas,groups = "hspi0_a";
@@ -168,8 +172,13 @@
};
};
+&rcar_sound {
+ /* Single DAI */
+ #sound-dai-cells = <0>;
+};
+
&sdhi0 {
- pinctrl-0 = <&sdhi0_pins>;
+ pinctrl-0 = <&sdhi0_pins>, <&sdhi0_pup_pins>;
pinctrl-names = "default";
vmmc-supply = <&fixedregulator3v3>;
@@ -184,16 +193,20 @@
status = "okay";
flash: flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
compatible = "spansion,s25fl008k", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <104000000>;
m25p,fast-read;
- partition@0 {
- label = "data(spi)";
- reg = <0x00000000 0x00100000>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "data(spi)";
+ reg = <0x00000000 0x00100000>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi
index 4f8e07811746..791aafd310a5 100644
--- a/arch/arm/boot/dts/r8a7778.dtsi
+++ b/arch/arm/boot/dts/r8a7778.dtsi
@@ -61,7 +61,7 @@
};
gic: interrupt-controller@fe438000 {
- compatible = "arm,cortex-a9-gic";
+ compatible = "arm,pl390";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xfe438000 0x1000>,
@@ -236,7 +236,12 @@
};
rcar_sound: sound@ffd90000 {
- #sound-dai-cells = <1>;
+ /*
+ * #sound-dai-cells is required
+ *
+ * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
+ * Multi DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
+ */
compatible = "renesas,rcar_sound-r8a7778", "renesas,rcar_sound-gen1";
reg = <0xffd90000 0x1000>, /* SRU */
<0xffd91000 0x240>, /* SSI */
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index c553abd711ee..052dcee4790d 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -47,13 +47,13 @@
compatible = "renesas,lager", "renesas,r8a7790";
aliases {
- serial0 = &scifa0;
+ serial0 = &scif0;
serial1 = &scifa1;
};
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scifa0;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -77,28 +77,28 @@
button@1 {
linux,code = <KEY_1>;
label = "SW2-1";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
};
button@2 {
linux,code = <KEY_2>;
label = "SW2-2";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
};
button@3 {
linux,code = <KEY_3>;
label = "SW2-3";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
gpios = <&gpio1 26 GPIO_ACTIVE_LOW>;
};
button@4 {
linux,code = <KEY_4>;
label = "SW2-4";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
};
@@ -296,9 +296,9 @@
renesas,function = "du";
};
- scifa0_pins: serial0 {
- renesas,groups = "scifa0_data";
- renesas,function = "scifa0";
+ scif0_pins: serial0 {
+ renesas,groups = "scif0_data";
+ renesas,function = "scif0";
};
ether_pins: ether {
@@ -439,8 +439,6 @@
status = "okay";
flash: flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
@@ -450,25 +448,31 @@
spi-cpol;
m25p,fast-read;
- partition@0 {
- label = "loader";
- reg = <0x00000000 0x00040000>;
- read-only;
- };
- partition@40000 {
- label = "user";
- reg = <0x00040000 0x00400000>;
- read-only;
- };
- partition@440000 {
- label = "flash";
- reg = <0x00440000 0x03bc0000>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "loader";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash";
+ reg = <0x00440000 0x03bc0000>;
+ };
};
};
};
-&scifa0 {
- pinctrl-0 = <&scifa0_pins>;
+&scif0 {
+ pinctrl-0 = <&scif0_pins>;
pinctrl-names = "default";
status = "okay";
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index e07ae5d45e19..7dfd393bfc7e 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -143,7 +143,7 @@
interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>;
gpio-controller;
- gpio-ranges = <&pfc 0 32 32>;
+ gpio-ranges = <&pfc 0 32 30>;
#interrupt-cells = <2>;
interrupt-controller;
clocks = <&mstp9_clks R8A7790_CLK_GPIO1>;
@@ -156,7 +156,7 @@
interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>;
gpio-controller;
- gpio-ranges = <&pfc 0 64 32>;
+ gpio-ranges = <&pfc 0 64 30>;
#interrupt-cells = <2>;
interrupt-controller;
clocks = <&mstp9_clks R8A7790_CLK_GPIO2>;
@@ -266,7 +266,7 @@
};
dmac0: dma-controller@e6700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xe6700000 0 0x20000>;
interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH
0 200 IRQ_TYPE_LEVEL_HIGH
@@ -297,7 +297,7 @@
};
dmac1: dma-controller@e6720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xe6720000 0 0x20000>;
interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
0 216 IRQ_TYPE_LEVEL_HIGH
@@ -328,7 +328,7 @@
};
audma0: dma-controller@ec700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xec700000 0 0x10000>;
interrupts = <0 346 IRQ_TYPE_LEVEL_HIGH
0 320 IRQ_TYPE_LEVEL_HIGH
@@ -357,7 +357,7 @@
};
audma1: dma-controller@ec720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xec720000 0 0x10000>;
interrupts = <0 347 IRQ_TYPE_LEVEL_HIGH
0 333 IRQ_TYPE_LEVEL_HIGH
@@ -386,7 +386,7 @@
};
usb_dmac0: dma-controller@e65a0000 {
- compatible = "renesas,usb-dmac";
+ compatible = "renesas,r8a7790-usb-dmac", "renesas,usb-dmac";
reg = <0 0xe65a0000 0 0x100>;
interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH
0 109 IRQ_TYPE_LEVEL_HIGH>;
@@ -398,7 +398,7 @@
};
usb_dmac1: dma-controller@e65b0000 {
- compatible = "renesas,usb-dmac";
+ compatible = "renesas,r8a7790-usb-dmac", "renesas,usb-dmac";
reg = <0 0xe65b0000 0 0x100>;
interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH
0 110 IRQ_TYPE_LEVEL_HIGH>;
@@ -417,6 +417,7 @@
interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7790_CLK_I2C0>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <110>;
status = "disabled";
};
@@ -428,6 +429,7 @@
interrupts = <0 288 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7790_CLK_I2C1>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -439,6 +441,7 @@
interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7790_CLK_I2C2>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -450,6 +453,7 @@
interrupts = <0 290 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7790_CLK_I2C3>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <110>;
status = "disabled";
};
@@ -1766,7 +1770,7 @@
};
ipmmu_sy0: mmu@e6280000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
reg = <0 0xe6280000 0 0x1000>;
interrupts = <0 223 IRQ_TYPE_LEVEL_HIGH>,
<0 224 IRQ_TYPE_LEVEL_HIGH>;
@@ -1775,7 +1779,7 @@
};
ipmmu_sy1: mmu@e6290000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
reg = <0 0xe6290000 0 0x1000>;
interrupts = <0 225 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1783,7 +1787,7 @@
};
ipmmu_ds: mmu@e6740000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
reg = <0 0xe6740000 0 0x1000>;
interrupts = <0 198 IRQ_TYPE_LEVEL_HIGH>,
<0 199 IRQ_TYPE_LEVEL_HIGH>;
@@ -1792,7 +1796,7 @@
};
ipmmu_mp: mmu@ec680000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
reg = <0 0xec680000 0 0x1000>;
interrupts = <0 226 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1800,7 +1804,7 @@
};
ipmmu_mx: mmu@fe951000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
reg = <0 0xfe951000 0 0x1000>;
interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
<0 221 IRQ_TYPE_LEVEL_HIGH>;
@@ -1809,7 +1813,7 @@
};
ipmmu_rt: mmu@ffc80000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
reg = <0 0xffc80000 0 0x1000>;
interrupts = <0 307 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts
deleted file mode 100644
index 655d1804e5e9..000000000000
--- a/arch/arm/boot/dts/r8a7791-henninger.dts
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Device Tree Source for the Henninger board
- *
- * Copyright (C) 2014 Renesas Solutions Corp.
- * Copyright (C) 2014 Cogent Embedded, Inc.
- *
- * 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.
- */
-
-/dts-v1/;
-#include "r8a7791.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
- model = "Henninger";
- compatible = "renesas,henninger", "renesas,r8a7791";
-
- aliases {
- serial0 = &scif0;
- };
-
- chosen {
- bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scif0;
- };
-
- memory@40000000 {
- device_type = "memory";
- reg = <0 0x40000000 0 0x40000000>;
- };
-
- memory@200000000 {
- device_type = "memory";
- reg = <2 0x00000000 0 0x40000000>;
- };
-
- vcc_sdhi0: regulator@0 {
- compatible = "regulator-fixed";
-
- regulator-name = "SDHI0 Vcc";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- vccq_sdhi0: regulator@1 {
- compatible = "regulator-gpio";
-
- regulator-name = "SDHI0 VccQ";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
-
- gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
- gpios-states = <1>;
- states = <3300000 1
- 1800000 0>;
- };
-
- vcc_sdhi2: regulator@2 {
- compatible = "regulator-fixed";
-
- regulator-name = "SDHI2 Vcc";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- vccq_sdhi2: regulator@3 {
- compatible = "regulator-gpio";
-
- regulator-name = "SDHI2 VccQ";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
-
- gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
- gpios-states = <1>;
- states = <3300000 1
- 1800000 0>;
- };
-};
-
-&extal_clk {
- clock-frequency = <20000000>;
-};
-
-&pfc {
- scif0_pins: serial0 {
- renesas,groups = "scif0_data_d";
- renesas,function = "scif0";
- };
-
- ether_pins: ether {
- renesas,groups = "eth_link", "eth_mdio", "eth_rmii";
- renesas,function = "eth";
- };
-
- phy1_pins: phy1 {
- renesas,groups = "intc_irq0";
- renesas,function = "intc";
- };
-
- sdhi0_pins: sd0 {
- renesas,groups = "sdhi0_data4", "sdhi0_ctrl";
- renesas,function = "sdhi0";
- };
-
- sdhi2_pins: sd2 {
- renesas,groups = "sdhi2_data4", "sdhi2_ctrl";
- renesas,function = "sdhi2";
- };
-
- i2c2_pins: i2c2 {
- renesas,groups = "i2c2";
- renesas,function = "i2c2";
- };
-
- qspi_pins: spi0 {
- renesas,groups = "qspi_ctrl", "qspi_data4";
- renesas,function = "qspi";
- };
-
- msiof0_pins: spi1 {
- renesas,groups = "msiof0_clk", "msiof0_sync", "msiof0_rx",
- "msiof0_tx";
- renesas,function = "msiof0";
- };
-
- usb0_pins: usb0 {
- renesas,groups = "usb0";
- renesas,function = "usb0";
- };
-
- usb1_pins: usb1 {
- renesas,groups = "usb1";
- renesas,function = "usb1";
- };
-
- vin0_pins: vin0 {
- renesas,groups = "vin0_data8", "vin0_clk";
- renesas,function = "vin0";
- };
-
- can0_pins: can0 {
- renesas,groups = "can0_data";
- renesas,function = "can0";
- };
-};
-
-&scif0 {
- pinctrl-0 = <&scif0_pins>;
- pinctrl-names = "default";
-
- status = "okay";
-};
-
-&ether {
- pinctrl-0 = <&ether_pins &phy1_pins>;
- pinctrl-names = "default";
-
- phy-handle = <&phy1>;
- renesas,ether-link-active-low;
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- interrupt-parent = <&irqc0>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- micrel,led-mode = <1>;
- };
-};
-
-&sata0 {
- status = "okay";
-};
-
-&sdhi0 {
- pinctrl-0 = <&sdhi0_pins>;
- pinctrl-names = "default";
-
- vmmc-supply = <&vcc_sdhi0>;
- vqmmc-supply = <&vccq_sdhi0>;
- cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>;
- wp-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>;
- status = "okay";
-};
-
-&sdhi2 {
- pinctrl-0 = <&sdhi2_pins>;
- pinctrl-names = "default";
-
- vmmc-supply = <&vcc_sdhi2>;
- vqmmc-supply = <&vccq_sdhi2>;
- cd-gpios = <&gpio6 22 GPIO_ACTIVE_LOW>;
- status = "okay";
-};
-
-&i2c2 {
- pinctrl-0 = <&i2c2_pins>;
- pinctrl-names = "default";
-
- status = "okay";
- clock-frequency = <400000>;
-
- composite-in@20 {
- compatible = "adi,adv7180";
- reg = <0x20>;
- remote = <&vin0>;
-
- port {
- adv7180: endpoint {
- bus-width = <8>;
- remote-endpoint = <&vin0ep>;
- };
- };
- };
-};
-
-&qspi {
- pinctrl-0 = <&qspi_pins>;
- pinctrl-names = "default";
-
- status = "okay";
-
- flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "spansion,s25fl512s", "jedec,spi-nor";
- reg = <0>;
- spi-max-frequency = <30000000>;
- spi-tx-bus-width = <4>;
- spi-rx-bus-width = <4>;
- m25p,fast-read;
-
- partition@0 {
- label = "loader_prg";
- reg = <0x00000000 0x00040000>;
- read-only;
- };
- partition@40000 {
- label = "user_prg";
- reg = <0x00040000 0x00400000>;
- read-only;
- };
- partition@440000 {
- label = "flash_fs";
- reg = <0x00440000 0x03bc0000>;
- };
- };
-};
-
-&msiof0 {
- pinctrl-0 = <&msiof0_pins>;
- pinctrl-names = "default";
-
- status = "okay";
-
- pmic@0 {
- compatible = "renesas,r2a11302ft";
- reg = <0>;
- spi-max-frequency = <6000000>;
- spi-cpol;
- spi-cpha;
- };
-};
-
-&pci0 {
- status = "okay";
- pinctrl-0 = <&usb0_pins>;
- pinctrl-names = "default";
-};
-
-&pci1 {
- status = "okay";
- pinctrl-0 = <&usb1_pins>;
- pinctrl-names = "default";
-};
-
-&hsusb {
- status = "okay";
- pinctrl-0 = <&usb0_pins>;
- pinctrl-names = "default";
- renesas,enable-gpio = <&gpio5 31 GPIO_ACTIVE_HIGH>;
-};
-
-&usbphy {
- status = "okay";
-};
-
-&pcie_bus_clk {
- status = "okay";
-};
-
-&pciec {
- status = "okay";
-};
-
-/* composite video input */
-&vin0 {
- status = "okay";
- pinctrl-0 = <&vin0_pins>;
- pinctrl-names = "default";
-
- port {
- #address-cells = <1>;
- #size-cells = <0>;
-
- vin0ep: endpoint {
- remote-endpoint = <&adv7180>;
- bus-width = <8>;
- };
- };
-};
-
-&can0 {
- pinctrl-0 = <&can0_pins>;
- pinctrl-names = "default";
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index fc44ea361a4b..45256f3cc835 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -54,7 +54,7 @@
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scif0;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -79,77 +79,77 @@
gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_1>;
label = "SW2-1";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-2 {
gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_2>;
label = "SW2-2";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-3 {
gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
linux,code = <KEY_3>;
label = "SW2-3";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-4 {
gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
linux,code = <KEY_4>;
label = "SW2-4";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-a {
gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_A>;
label = "SW30";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-b {
gpios = <&gpio7 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_B>;
label = "SW31";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-c {
gpios = <&gpio7 2 GPIO_ACTIVE_LOW>;
linux,code = <KEY_C>;
label = "SW32";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-d {
gpios = <&gpio7 3 GPIO_ACTIVE_LOW>;
linux,code = <KEY_D>;
label = "SW33";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-e {
gpios = <&gpio7 4 GPIO_ACTIVE_LOW>;
linux,code = <KEY_E>;
label = "SW34";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-f {
gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
linux,code = <KEY_F>;
label = "SW35";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
key-g {
gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
linux,code = <KEY_G>;
label = "SW36";
- gpio-key,wakeup;
+ wakeup-source;
debounce-interval = <20>;
};
};
@@ -326,7 +326,7 @@
};
du_pins: du {
- renesas,groups = "du_rgb666", "du_sync", "du_disp", "du_clk_out_0";
+ renesas,groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
renesas,function = "du";
};
@@ -479,8 +479,6 @@
status = "okay";
flash: flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
@@ -490,19 +488,25 @@
spi-cpol;
m25p,fast-read;
- partition@0 {
- label = "loader";
- reg = <0x00000000 0x00080000>;
- read-only;
- };
- partition@80000 {
- label = "user";
- reg = <0x00080000 0x00580000>;
- read-only;
- };
- partition@600000 {
- label = "flash";
- reg = <0x00600000 0x03a00000>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "loader";
+ reg = <0x00000000 0x00080000>;
+ read-only;
+ };
+ partition@80000 {
+ label = "user";
+ reg = <0x00080000 0x00580000>;
+ read-only;
+ };
+ partition@600000 {
+ label = "flash";
+ reg = <0x00600000 0x03a00000>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts
index fe0f12fc02a1..6713b1ea732b 100644
--- a/arch/arm/boot/dts/r8a7791-porter.dts
+++ b/arch/arm/boot/dts/r8a7791-porter.dts
@@ -22,7 +22,7 @@
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scif0;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -134,6 +134,11 @@
renesas,groups = "vin0_data8", "vin0_clk";
renesas,function = "vin0";
};
+
+ can0_pins: can0 {
+ renesas,groups = "can0_data";
+ renesas,function = "can0";
+ };
};
&scif0 {
@@ -187,8 +192,6 @@
status = "okay";
flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
@@ -196,19 +199,25 @@
spi-rx-bus-width = <4>;
m25p,fast-read;
- partition@0 {
- label = "loader_prg";
- reg = <0x00000000 0x00040000>;
- read-only;
- };
- partition@40000 {
- label = "user_prg";
- reg = <0x00040000 0x00400000>;
- read-only;
- };
- partition@440000 {
- label = "flash_fs";
- reg = <0x00440000 0x03bc0000>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "loader_prg";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user_prg";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash_fs";
+ reg = <0x00440000 0x03bc0000>;
+ };
};
};
};
@@ -269,6 +278,14 @@
status = "okay";
};
+&hsusb {
+ pinctrl-0 = <&usb0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+ renesas,enable-gpio = <&gpio5 31 GPIO_ACTIVE_HIGH>;
+};
+
&usbphy {
status = "okay";
};
@@ -280,3 +297,10 @@
&pciec {
status = "okay";
};
+
+&can0 {
+ pinctrl-0 = <&can0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 328f48bd15e7..2a369ddcb6fd 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -100,7 +100,7 @@
interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>;
gpio-controller;
- gpio-ranges = <&pfc 0 32 32>;
+ gpio-ranges = <&pfc 0 32 26>;
#interrupt-cells = <2>;
interrupt-controller;
clocks = <&mstp9_clks R8A7791_CLK_GPIO1>;
@@ -255,7 +255,7 @@
};
dmac0: dma-controller@e6700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
reg = <0 0xe6700000 0 0x20000>;
interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH
0 200 IRQ_TYPE_LEVEL_HIGH
@@ -286,7 +286,7 @@
};
dmac1: dma-controller@e6720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
reg = <0 0xe6720000 0 0x20000>;
interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
0 216 IRQ_TYPE_LEVEL_HIGH
@@ -317,7 +317,7 @@
};
audma0: dma-controller@ec700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
reg = <0 0xec700000 0 0x10000>;
interrupts = <0 346 IRQ_TYPE_LEVEL_HIGH
0 320 IRQ_TYPE_LEVEL_HIGH
@@ -346,7 +346,7 @@
};
audma1: dma-controller@ec720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
reg = <0 0xec720000 0 0x10000>;
interrupts = <0 347 IRQ_TYPE_LEVEL_HIGH
0 333 IRQ_TYPE_LEVEL_HIGH
@@ -375,7 +375,7 @@
};
usb_dmac0: dma-controller@e65a0000 {
- compatible = "renesas,usb-dmac";
+ compatible = "renesas,r8a7791-usb-dmac", "renesas,usb-dmac";
reg = <0 0xe65a0000 0 0x100>;
interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH
0 109 IRQ_TYPE_LEVEL_HIGH>;
@@ -387,7 +387,7 @@
};
usb_dmac1: dma-controller@e65b0000 {
- compatible = "renesas,usb-dmac";
+ compatible = "renesas,r8a7791-usb-dmac", "renesas,usb-dmac";
reg = <0 0xe65b0000 0 0x100>;
interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH
0 110 IRQ_TYPE_LEVEL_HIGH>;
@@ -407,6 +407,7 @@
interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C0>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -418,6 +419,7 @@
interrupts = <0 288 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C1>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -429,6 +431,7 @@
interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C2>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -440,6 +443,7 @@
interrupts = <0 290 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C3>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -451,6 +455,7 @@
interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C4>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -463,6 +468,7 @@
interrupts = <0 20 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C5>;
power-domains = <&cpg_clocks>;
+ i2c-scl-internal-delay-ns = <110>;
status = "disabled";
};
@@ -509,7 +515,6 @@
pfc: pfc@e6060000 {
compatible = "renesas,pfc-r8a7791";
reg = <0 0xe6060000 0 0x250>;
- #gpio-range-cells = <3>;
};
mmcif0: mmc@ee200000 {
@@ -786,6 +791,18 @@
status = "disabled";
};
+ avb: ethernet@e6800000 {
+ compatible = "renesas,etheravb-r8a7791",
+ "renesas,etheravb-rcar-gen2";
+ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+ interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7791_CLK_ETHERAVB>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
sata0: sata@ee300000 {
compatible = "renesas,sata-r8a7791";
reg = <0 0xee300000 0 0x2000>;
@@ -1163,14 +1180,6 @@
clock-mult = <1>;
clock-output-names = "m2";
};
- imp_clk: imp_clk {
- compatible = "fixed-factor-clock";
- clocks = <&cpg_clocks R8A7791_CLK_PLL1>;
- #clock-cells = <0>;
- clock-div = <4>;
- clock-mult = <1>;
- clock-output-names = "imp";
- };
rclk_clk: rclk_clk {
compatible = "fixed-factor-clock";
clocks = <&cpg_clocks R8A7791_CLK_PLL1>;
@@ -1338,16 +1347,18 @@
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>;
clocks = <&zx_clk>, <&hp_clk>, <&zg_clk>, <&zg_clk>,
- <&zg_clk>, <&p_clk>, <&zs_clk>, <&zs_clk>;
+ <&zg_clk>, <&hp_clk>, <&p_clk>, <&zs_clk>,
+ <&zs_clk>;
#clock-cells = <1>;
clock-indices = <
R8A7791_CLK_IPMMU_SGX R8A7791_CLK_MLB
R8A7791_CLK_VIN2 R8A7791_CLK_VIN1 R8A7791_CLK_VIN0
- R8A7791_CLK_ETHER R8A7791_CLK_SATA1 R8A7791_CLK_SATA0
+ R8A7791_CLK_ETHERAVB R8A7791_CLK_ETHER
+ R8A7791_CLK_SATA1 R8A7791_CLK_SATA0
>;
clock-output-names =
- "ipmmu_sgx", "mlb", "vin2", "vin1", "vin0", "ether",
- "sata1", "sata0";
+ "ipmmu_sgx", "mlb", "vin2", "vin1", "vin0",
+ "etheravb", "ether", "sata1", "sata0";
};
mstp9_clks: mstp9_clks@e6150994 {
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -1579,7 +1590,7 @@
};
ipmmu_sy0: mmu@e6280000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xe6280000 0 0x1000>;
interrupts = <0 223 IRQ_TYPE_LEVEL_HIGH>,
<0 224 IRQ_TYPE_LEVEL_HIGH>;
@@ -1588,7 +1599,7 @@
};
ipmmu_sy1: mmu@e6290000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xe6290000 0 0x1000>;
interrupts = <0 225 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1596,7 +1607,7 @@
};
ipmmu_ds: mmu@e6740000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xe6740000 0 0x1000>;
interrupts = <0 198 IRQ_TYPE_LEVEL_HIGH>,
<0 199 IRQ_TYPE_LEVEL_HIGH>;
@@ -1605,7 +1616,7 @@
};
ipmmu_mp: mmu@ec680000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xec680000 0 0x1000>;
interrupts = <0 226 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1613,7 +1624,7 @@
};
ipmmu_mx: mmu@fe951000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xfe951000 0 0x1000>;
interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
<0 221 IRQ_TYPE_LEVEL_HIGH>;
@@ -1622,7 +1633,7 @@
};
ipmmu_rt: mmu@ffc80000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xffc80000 0 0x1000>;
interrupts = <0 307 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1630,7 +1641,7 @@
};
ipmmu_gp: mmu@e62a0000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
reg = <0 0xe62a0000 0 0x1000>;
interrupts = <0 260 IRQ_TYPE_LEVEL_HIGH>,
<0 261 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts
index 96443ec5f6ab..baa59fe84298 100644
--- a/arch/arm/boot/dts/r8a7793-gose.dts
+++ b/arch/arm/boot/dts/r8a7793-gose.dts
@@ -24,7 +24,7 @@
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scif0;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -37,7 +37,37 @@
clock-frequency = <20000000>;
};
+&pfc {
+ scif0_pins: serial0 {
+ renesas,groups = "scif0_data_d";
+ renesas,function = "scif0";
+ };
+
+ scif1_pins: serial1 {
+ renesas,groups = "scif1_data_d";
+ renesas,function = "scif1";
+ };
+
+ ether_pins: ether {
+ renesas,groups = "eth_link", "eth_mdio", "eth_rmii";
+ renesas,function = "eth";
+ };
+
+ phy1_pins: phy1 {
+ renesas,groups = "intc_irq0";
+ renesas,function = "intc";
+ };
+
+ qspi_pins: spi0 {
+ renesas,groups = "qspi_ctrl", "qspi_data4";
+ renesas,function = "qspi";
+ };
+};
+
&ether {
+ pinctrl-0 = <&ether_pins &phy1_pins>;
+ pinctrl-names = "default";
+
phy-handle = <&phy1>;
renesas,ether-link-active-low;
status = "okay";
@@ -55,9 +85,54 @@
};
&scif0 {
+ pinctrl-0 = <&scif0_pins>;
+ pinctrl-names = "default";
+
status = "okay";
};
&scif1 {
+ pinctrl-0 = <&scif1_pins>;
+ pinctrl-names = "default";
+
status = "okay";
};
+
+&qspi {
+ pinctrl-0 = <&qspi_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ flash@0 {
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <30000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ spi-cpol;
+ spi-cpha;
+ m25p,fast-read;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "loader";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash";
+ reg = <0x00440000 0x03bc0000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi
index c4654047e684..aef9e69d6c26 100644
--- a/arch/arm/boot/dts/r8a7793.dtsi
+++ b/arch/arm/boot/dts/r8a7793.dtsi
@@ -18,6 +18,10 @@
#address-cells = <2>;
#size-cells = <2>;
+ aliases {
+ spi0 = &qspi;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -53,6 +57,118 @@
interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ gpio0: gpio@e6050000 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6050000 0 0x50>;
+ interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 0 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO0>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio1: gpio@e6051000 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6051000 0 0x50>;
+ interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 32 26>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO1>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio2: gpio@e6052000 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6052000 0 0x50>;
+ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 64 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO2>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio3: gpio@e6053000 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6053000 0 0x50>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 96 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO3>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio4: gpio@e6054000 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6054000 0 0x50>;
+ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 128 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO4>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio5: gpio@e6055000 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6055000 0 0x50>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 160 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO5>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio6: gpio@e6055400 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6055400 0 0x50>;
+ interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 192 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO6>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio7: gpio@e6055800 {
+ compatible = "renesas,gpio-r8a7793", "renesas,gpio-rcar";
+ reg = <0 0xe6055800 0 0x50>;
+ interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 224 26>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7793_CLK_GPIO7>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ thermal@e61f0000 {
+ compatible = "renesas,thermal-r8a7793", "renesas,rcar-thermal";
+ reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>;
+ interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp5_clks R8A7793_CLK_THERMAL>;
+ power-domains = <&cpg_clocks>;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
@@ -114,12 +230,189 @@
power-domains = <&cpg_clocks>;
};
+ pfc: pfc@e6060000 {
+ compatible = "renesas,pfc-r8a7793";
+ reg = <0 0xe6060000 0 0x250>;
+ };
+
+ dmac0: dma-controller@e6700000 {
+ compatible = "renesas,dmac-r8a7793", "renesas,rcar-dmac";
+ reg = <0 0xe6700000 0 0x20000>;
+ interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH
+ 0 200 IRQ_TYPE_LEVEL_HIGH
+ 0 201 IRQ_TYPE_LEVEL_HIGH
+ 0 202 IRQ_TYPE_LEVEL_HIGH
+ 0 203 IRQ_TYPE_LEVEL_HIGH
+ 0 204 IRQ_TYPE_LEVEL_HIGH
+ 0 205 IRQ_TYPE_LEVEL_HIGH
+ 0 206 IRQ_TYPE_LEVEL_HIGH
+ 0 207 IRQ_TYPE_LEVEL_HIGH
+ 0 208 IRQ_TYPE_LEVEL_HIGH
+ 0 209 IRQ_TYPE_LEVEL_HIGH
+ 0 210 IRQ_TYPE_LEVEL_HIGH
+ 0 211 IRQ_TYPE_LEVEL_HIGH
+ 0 212 IRQ_TYPE_LEVEL_HIGH
+ 0 213 IRQ_TYPE_LEVEL_HIGH
+ 0 214 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14";
+ clocks = <&mstp2_clks R8A7793_CLK_SYS_DMAC0>;
+ clock-names = "fck";
+ power-domains = <&cpg_clocks>;
+ #dma-cells = <1>;
+ dma-channels = <15>;
+ };
+
+ dmac1: dma-controller@e6720000 {
+ compatible = "renesas,dmac-r8a7793", "renesas,rcar-dmac";
+ reg = <0 0xe6720000 0 0x20000>;
+ interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
+ 0 216 IRQ_TYPE_LEVEL_HIGH
+ 0 217 IRQ_TYPE_LEVEL_HIGH
+ 0 218 IRQ_TYPE_LEVEL_HIGH
+ 0 219 IRQ_TYPE_LEVEL_HIGH
+ 0 308 IRQ_TYPE_LEVEL_HIGH
+ 0 309 IRQ_TYPE_LEVEL_HIGH
+ 0 310 IRQ_TYPE_LEVEL_HIGH
+ 0 311 IRQ_TYPE_LEVEL_HIGH
+ 0 312 IRQ_TYPE_LEVEL_HIGH
+ 0 313 IRQ_TYPE_LEVEL_HIGH
+ 0 314 IRQ_TYPE_LEVEL_HIGH
+ 0 315 IRQ_TYPE_LEVEL_HIGH
+ 0 316 IRQ_TYPE_LEVEL_HIGH
+ 0 317 IRQ_TYPE_LEVEL_HIGH
+ 0 318 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14";
+ clocks = <&mstp2_clks R8A7793_CLK_SYS_DMAC1>;
+ clock-names = "fck";
+ power-domains = <&cpg_clocks>;
+ #dma-cells = <1>;
+ dma-channels = <15>;
+ };
+
+ scifa0: serial@e6c40000 {
+ compatible = "renesas,scifa-r8a7793", "renesas,scifa";
+ reg = <0 0xe6c40000 0 64>;
+ interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7793_CLK_SCIFA0>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x21>, <&dmac0 0x22>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifa1: serial@e6c50000 {
+ compatible = "renesas,scifa-r8a7793", "renesas,scifa";
+ reg = <0 0xe6c50000 0 64>;
+ interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7793_CLK_SCIFA1>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x25>, <&dmac0 0x26>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifa2: serial@e6c60000 {
+ compatible = "renesas,scifa-r8a7793", "renesas,scifa";
+ reg = <0 0xe6c60000 0 64>;
+ interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7793_CLK_SCIFA2>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x27>, <&dmac0 0x28>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifa3: serial@e6c70000 {
+ compatible = "renesas,scifa-r8a7793", "renesas,scifa";
+ reg = <0 0xe6c70000 0 64>;
+ interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp11_clks R8A7793_CLK_SCIFA3>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x1b>, <&dmac0 0x1c>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifa4: serial@e6c78000 {
+ compatible = "renesas,scifa-r8a7793", "renesas,scifa";
+ reg = <0 0xe6c78000 0 64>;
+ interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp11_clks R8A7793_CLK_SCIFA4>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x1f>, <&dmac0 0x20>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifa5: serial@e6c80000 {
+ compatible = "renesas,scifa-r8a7793", "renesas,scifa";
+ reg = <0 0xe6c80000 0 64>;
+ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp11_clks R8A7793_CLK_SCIFA5>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x23>, <&dmac0 0x24>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifb0: serial@e6c20000 {
+ compatible = "renesas,scifb-r8a7793", "renesas,scifb";
+ reg = <0 0xe6c20000 0 64>;
+ interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7793_CLK_SCIFB0>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x3d>, <&dmac0 0x3e>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifb1: serial@e6c30000 {
+ compatible = "renesas,scifb-r8a7793", "renesas,scifb";
+ reg = <0 0xe6c30000 0 64>;
+ interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7793_CLK_SCIFB1>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x19>, <&dmac0 0x1a>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scifb2: serial@e6ce0000 {
+ compatible = "renesas,scifb-r8a7793", "renesas,scifb";
+ reg = <0 0xe6ce0000 0 64>;
+ interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7793_CLK_SCIFB2>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x1d>, <&dmac0 0x1e>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
scif0: serial@e6e60000 {
compatible = "renesas,scif-r8a7793", "renesas,scif";
reg = <0 0xe6e60000 0 64>;
interrupts = <0 152 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7793_CLK_SCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x29>, <&dmac0 0x2a>;
+ dma-names = "tx", "rx";
power-domains = <&cpg_clocks>;
status = "disabled";
};
@@ -130,6 +423,92 @@
interrupts = <0 153 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7793_CLK_SCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2d>, <&dmac0 0x2e>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scif2: serial@e6e58000 {
+ compatible = "renesas,scif-r8a7793", "renesas,scif";
+ reg = <0 0xe6e58000 0 64>;
+ interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_SCIF2>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x2b>, <&dmac0 0x2c>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scif3: serial@e6ea8000 {
+ compatible = "renesas,scif-r8a7793", "renesas,scif";
+ reg = <0 0xe6ea8000 0 64>;
+ interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_SCIF3>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x2f>, <&dmac0 0x30>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scif4: serial@e6ee0000 {
+ compatible = "renesas,scif-r8a7793", "renesas,scif";
+ reg = <0 0xe6ee0000 0 64>;
+ interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_SCIF4>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0xfb>, <&dmac0 0xfc>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ scif5: serial@e6ee8000 {
+ compatible = "renesas,scif-r8a7793", "renesas,scif";
+ reg = <0 0xe6ee8000 0 64>;
+ interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_SCIF5>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0xfd>, <&dmac0 0xfe>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ hscif0: serial@e62c0000 {
+ compatible = "renesas,hscif-r8a7793", "renesas,hscif";
+ reg = <0 0xe62c0000 0 96>;
+ interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_HSCIF0>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x39>, <&dmac0 0x3a>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ hscif1: serial@e62c8000 {
+ compatible = "renesas,hscif-r8a7793", "renesas,hscif";
+ reg = <0 0xe62c8000 0 96>;
+ interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_HSCIF1>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x4d>, <&dmac0 0x4e>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ hscif2: serial@e62d0000 {
+ compatible = "renesas,hscif-r8a7793", "renesas,hscif";
+ reg = <0 0xe62d0000 0 96>;
+ interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_HSCIF2>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x3b>, <&dmac0 0x3c>;
+ dma-names = "tx", "rx";
power-domains = <&cpg_clocks>;
status = "disabled";
};
@@ -146,6 +525,50 @@
status = "disabled";
};
+ qspi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7793", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7793_CLK_QSPI_MOD>;
+ dmas = <&dmac0 0x17>, <&dmac0 0x18>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ du: display@feb00000 {
+ compatible = "renesas,du-r8a7793";
+ reg = <0 0xfeb00000 0 0x40000>,
+ <0 0xfeb90000 0 0x1c>;
+ reg-names = "du", "lvds.0";
+ interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+ <0 268 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7793_CLK_DU0>,
+ <&mstp7_clks R8A7793_CLK_DU1>,
+ <&mstp7_clks R8A7793_CLK_LVDS0>;
+ clock-names = "du.0", "du.1", "lvds.0";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_lvds0: endpoint {
+ };
+ };
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -299,6 +722,21 @@
"tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1",
"vsp1-du0", "vsps";
};
+ mstp2_clks: mstp2_clks@e6150138 {
+ compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150138 0 4>, <0 0xe6150040 0 4>;
+ clocks = <&mp_clk>, <&mp_clk>, <&mp_clk>, <&mp_clk>,
+ <&mp_clk>, <&mp_clk>, <&zs_clk>, <&zs_clk>;
+ #clock-cells = <1>;
+ clock-indices = <
+ R8A7793_CLK_SCIFA2 R8A7793_CLK_SCIFA1 R8A7793_CLK_SCIFA0
+ R8A7793_CLK_SCIFB0 R8A7793_CLK_SCIFB1 R8A7793_CLK_SCIFB2
+ R8A7793_CLK_SYS_DMAC1 R8A7793_CLK_SYS_DMAC0
+ >;
+ clock-output-names =
+ "scifa2", "scifa1", "scifa0", "scifb0",
+ "scifb1", "scifb2", "sys-dmac1", "sys-dmac0";
+ };
mstp3_clks: mstp3_clks@e615013c {
compatible = "renesas,r8a7793-mstp-clocks",
"renesas,cpg-mstp-clocks";
@@ -329,6 +767,14 @@
clock-indices = <R8A7793_CLK_IRQC>;
clock-output-names = "irqc";
};
+ mstp5_clks: mstp5_clks@e6150144 {
+ compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
+ clocks = <&extal_clk>;
+ #clock-cells = <1>;
+ clock-indices = <R8A7793_CLK_THERMAL>;
+ clock-output-names = "thermal";
+ };
mstp7_clks: mstp7_clks@e615014c {
compatible = "renesas,r8a7793-mstp-clocks",
"renesas,cpg-mstp-clocks";
@@ -369,6 +815,94 @@
"ipmmu_sgx", "vin2", "vin1", "vin0", "ether",
"sata1", "sata0";
};
+ mstp9_clks: mstp9_clks@e6150994 {
+ compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>;
+ clocks = <&cp_clk>, <&cp_clk>, <&cp_clk>, <&cp_clk>,
+ <&cp_clk>, <&cp_clk>, <&cp_clk>, <&cp_clk>,
+ <&cpg_clocks R8A7793_CLK_QSPI>;
+ #clock-cells = <1>;
+ clock-indices = <
+ R8A7793_CLK_GPIO7 R8A7793_CLK_GPIO6
+ R8A7793_CLK_GPIO5 R8A7793_CLK_GPIO4
+ R8A7793_CLK_GPIO3 R8A7793_CLK_GPIO2
+ R8A7793_CLK_GPIO1 R8A7793_CLK_GPIO0
+ R8A7793_CLK_QSPI_MOD
+ >;
+ clock-output-names =
+ "gpio7", "gpio6", "gpio5", "gpio4",
+ "gpio3", "gpio2", "gpio1", "gpio0",
+ "qspi_mod";
+ };
+ mstp11_clks: mstp11_clks@e615099c {
+ compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe615099c 0 4>, <0 0xe61509ac 0 4>;
+ clocks = <&mp_clk>, <&mp_clk>, <&mp_clk>;
+ #clock-cells = <1>;
+ clock-indices = <
+ R8A7793_CLK_SCIFA3 R8A7793_CLK_SCIFA4 R8A7793_CLK_SCIFA5
+ >;
+ clock-output-names = "scifa3", "scifa4", "scifa5";
+ };
+ };
+
+ ipmmu_sy0: mmu@e6280000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xe6280000 0 0x1000>;
+ interrupts = <0 223 IRQ_TYPE_LEVEL_HIGH>,
+ <0 224 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
+ };
+
+ ipmmu_sy1: mmu@e6290000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xe6290000 0 0x1000>;
+ interrupts = <0 225 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
+ };
+
+ ipmmu_ds: mmu@e6740000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xe6740000 0 0x1000>;
+ interrupts = <0 198 IRQ_TYPE_LEVEL_HIGH>,
+ <0 199 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
+ };
+
+ ipmmu_mp: mmu@ec680000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xec680000 0 0x1000>;
+ interrupts = <0 226 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
+ };
+
+ ipmmu_mx: mmu@fe951000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xfe951000 0 0x1000>;
+ interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
+ <0 221 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
+ };
+
+ ipmmu_rt: mmu@ffc80000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xffc80000 0 0x1000>;
+ interrupts = <0 307 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
};
+ ipmmu_gp: mmu@e62a0000 {
+ compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
+ reg = <0 0xe62a0000 0 0x1000>;
+ interrupts = <0 260 IRQ_TYPE_LEVEL_HIGH>,
+ <0 261 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index 928cfa641475..2394e4883786 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -21,7 +21,7 @@
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scif2;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -33,17 +33,115 @@
#address-cells = <1>;
#size-cells = <1>;
};
+
+ vga-encoder {
+ compatible = "adi,adv7123";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7123_in: endpoint {
+ remote-endpoint = <&du_out_rgb1>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ adv7123_out: endpoint {
+ remote-endpoint = <&vga_in>;
+ };
+ };
+ };
+ };
+
+ vga {
+ compatible = "vga-connector";
+
+ port {
+ vga_in: endpoint {
+ remote-endpoint = <&adv7123_out>;
+ };
+ };
+ };
+
+ x2_clk: x2-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <74250000>;
+ };
+
+ x13_clk: x13-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <148500000>;
+ };
+};
+
+&du {
+ pinctrl-0 = <&du_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ clocks = <&mstp7_clks R8A7794_CLK_DU0>,
+ <&mstp7_clks R8A7794_CLK_DU0>,
+ <&x13_clk>, <&x2_clk>;
+ clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1";
+
+ ports {
+ port@1 {
+ endpoint {
+ remote-endpoint = <&adv7123_in>;
+ };
+ };
+ };
};
&extal_clk {
clock-frequency = <20000000>;
};
+&pfc {
+ du_pins: du {
+ renesas,groups = "du1_rgb666", "du1_sync", "du1_disp", "du1_dotclkout0";
+ renesas,function = "du";
+ };
+
+ scif2_pins: serial2 {
+ renesas,groups = "scif2_data";
+ renesas,function = "scif2";
+ };
+
+ ether_pins: ether {
+ renesas,groups = "eth_link", "eth_mdio", "eth_rmii";
+ renesas,function = "eth";
+ };
+
+ phy1_pins: phy1 {
+ renesas,groups = "intc_irq8";
+ renesas,function = "intc";
+ };
+
+ i2c1_pins: i2c1 {
+ renesas,groups = "i2c1";
+ renesas,function = "i2c1";
+ };
+
+ vin0_pins: vin0 {
+ renesas,groups = "vin0_data8", "vin0_clk";
+ renesas,function = "vin0";
+ };
+};
+
&cmt0 {
status = "okay";
};
&ether {
+ pinctrl-0 = <&ether_pins &phy1_pins>;
+ pinctrl-names = "default";
+
phy-handle = <&phy1>;
renesas,ether-link-active-low;
status = "okay";
@@ -56,6 +154,46 @@
};
};
+&i2c1 {
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+ clock-frequency = <400000>;
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin0>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin0ep>;
+ };
+ };
+ };
+};
+
+&vin0 {
+ status = "okay";
+ pinctrl-0 = <&vin0_pins>;
+ pinctrl-names = "default";
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vin0ep: endpoint {
+ remote-endpoint = <&adv7180>;
+ bus-width = <8>;
+ };
+ };
+};
+
&scif2 {
+ pinctrl-0 = <&scif2_pins>;
+ pinctrl-names = "default";
+
status = "okay";
};
diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts
index 48ff3e2958ae..5153e3af25d9 100644
--- a/arch/arm/boot/dts/r8a7794-silk.dts
+++ b/arch/arm/boot/dts/r8a7794-silk.dts
@@ -12,6 +12,7 @@
/dts-v1/;
#include "r8a7794.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "SILK";
@@ -23,7 +24,7 @@
chosen {
bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
- stdout-path = &scif2;
+ stdout-path = "serial0:115200n8";
};
memory@40000000 {
@@ -39,6 +40,30 @@
regulator-boot-on;
regulator-always-on;
};
+
+ vcc_sdhi1: regulator@3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI1 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&gpio4 26 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vccq_sdhi1: regulator@4 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI1 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
};
&extal_clk {
@@ -71,6 +96,11 @@
renesas,function = "mmc";
};
+ sdhi1_pins: sd1 {
+ renesas,groups = "sdhi1_data4", "sdhi1_ctrl";
+ renesas,function = "sdhi1";
+ };
+
qspi_pins: spi0 {
renesas,groups = "qspi_ctrl", "qspi_data4";
renesas,function = "qspi";
@@ -147,6 +177,16 @@
status = "okay";
};
+&sdhi1 {
+ pinctrl-0 = <&sdhi1_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi1>;
+ vqmmc-supply = <&vccq_sdhi1>;
+ cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
&qspi {
pinctrl-0 = <&qspi_pins>;
pinctrl-names = "default";
@@ -154,8 +194,6 @@
status = "okay";
flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
@@ -165,19 +203,25 @@
spi-cpha;
m25p,fast-read;
- partition@0 {
- label = "loader";
- reg = <0x00000000 0x00040000>;
- read-only;
- };
- partition@40000 {
- label = "user";
- reg = <0x00040000 0x00400000>;
- read-only;
- };
- partition@440000 {
- label = "flash";
- reg = <0x00440000 0x03bc0000>;
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "loader";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash";
+ reg = <0x00440000 0x03bc0000>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index a9977d6ee81a..6c78f1fae90f 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -217,11 +217,10 @@
pfc: pin-controller@e6060000 {
compatible = "renesas,pfc-r8a7794";
reg = <0 0xe6060000 0 0x11c>;
- #gpio-range-cells = <3>;
};
dmac0: dma-controller@e6700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7794", "renesas,rcar-dmac";
reg = <0 0xe6700000 0 0x20000>;
interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH
0 200 IRQ_TYPE_LEVEL_HIGH
@@ -252,7 +251,7 @@
};
dmac1: dma-controller@e6720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7794", "renesas,rcar-dmac";
reg = <0 0xe6720000 0 0x20000>;
interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
0 216 IRQ_TYPE_LEVEL_HIGH
@@ -519,6 +518,7 @@
power-domains = <&cpg_clocks>;
#address-cells = <1>;
#size-cells = <0>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -530,6 +530,7 @@
power-domains = <&cpg_clocks>;
#address-cells = <1>;
#size-cells = <0>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -541,6 +542,7 @@
power-domains = <&cpg_clocks>;
#address-cells = <1>;
#size-cells = <0>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -552,6 +554,7 @@
power-domains = <&cpg_clocks>;
#address-cells = <1>;
#size-cells = <0>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -563,6 +566,7 @@
power-domains = <&cpg_clocks>;
#address-cells = <1>;
#size-cells = <0>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -574,6 +578,7 @@
power-domains = <&cpg_clocks>;
#address-cells = <1>;
#size-cells = <0>;
+ i2c-scl-internal-delay-ns = <6>;
status = "disabled";
};
@@ -750,6 +755,34 @@
};
};
+ du: display@feb00000 {
+ compatible = "renesas,du-r8a7794";
+ reg = <0 0xfeb00000 0 0x40000>;
+ reg-names = "du";
+ interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+ <0 268 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7794_CLK_DU0>,
+ <&mstp7_clks R8A7794_CLK_DU0>;
+ clock-names = "du.0", "du.1";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb0: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_rgb1: endpoint {
+ };
+ };
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -879,14 +912,6 @@
clock-mult = <1>;
clock-output-names = "m2";
};
- imp_clk: imp_clk {
- compatible = "fixed-factor-clock";
- clocks = <&cpg_clocks R8A7794_CLK_PLL1>;
- #clock-cells = <0>;
- clock-div = <4>;
- clock-mult = <1>;
- clock-output-names = "imp";
- };
rclk_clk: rclk_clk {
compatible = "fixed-factor-clock";
clocks = <&cpg_clocks R8A7794_CLK_PLL1>;
@@ -1025,19 +1050,20 @@
reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
clocks = <&mp_clk>, <&mp_clk>,
<&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>,
- <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>;
+ <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
+ <&zx_clk>;
#clock-cells = <1>;
clock-indices = <
R8A7794_CLK_EHCI R8A7794_CLK_HSUSB
R8A7794_CLK_HSCIF2 R8A7794_CLK_SCIF5
R8A7794_CLK_SCIF4 R8A7794_CLK_HSCIF1 R8A7794_CLK_HSCIF0
R8A7794_CLK_SCIF3 R8A7794_CLK_SCIF2 R8A7794_CLK_SCIF1
- R8A7794_CLK_SCIF0
+ R8A7794_CLK_SCIF0 R8A7794_CLK_DU0
>;
clock-output-names =
"ehci", "hsusb",
"hscif2", "scif5", "scif4", "hscif1", "hscif0",
- "scif3", "scif2", "scif1", "scif0";
+ "scif3", "scif2", "scif1", "scif0", "du0";
};
mstp8_clks: mstp8_clks@e6150990 {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -1083,7 +1109,7 @@
};
ipmmu_sy0: mmu@e6280000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
reg = <0 0xe6280000 0 0x1000>;
interrupts = <0 223 IRQ_TYPE_LEVEL_HIGH>,
<0 224 IRQ_TYPE_LEVEL_HIGH>;
@@ -1092,7 +1118,7 @@
};
ipmmu_sy1: mmu@e6290000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
reg = <0 0xe6290000 0 0x1000>;
interrupts = <0 225 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1100,15 +1126,16 @@
};
ipmmu_ds: mmu@e6740000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
reg = <0 0xe6740000 0 0x1000>;
interrupts = <0 198 IRQ_TYPE_LEVEL_HIGH>,
<0 199 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
+ status = "disabled";
};
ipmmu_mp: mmu@ec680000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
reg = <0 0xec680000 0 0x1000>;
interrupts = <0 226 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
@@ -1116,15 +1143,16 @@
};
ipmmu_mx: mmu@fe951000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
reg = <0 0xfe951000 0 0x1000>;
interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>,
<0 221 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <1>;
+ status = "disabled";
};
ipmmu_gp: mmu@e62a0000 {
- compatible = "renesas,ipmmu-vmsa";
+ compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
reg = <0 0xe62a0000 0 0x1000>;
interrupts = <0 260 IRQ_TYPE_LEVEL_HIGH>,
<0 261 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/rk3036-evb.dts b/arch/arm/boot/dts/rk3036-evb.dts
new file mode 100644
index 000000000000..28a033666017
--- /dev/null
+++ b/arch/arm/boot/dts/rk3036-evb.dts
@@ -0,0 +1,64 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "rk3036.dtsi"
+
+/ {
+ model = "Rockchip RK3036 Evaluation board";
+ compatible = "rockchip,rk3036-evb", "rockchip,rk3036";
+};
+
+&i2c1 {
+ status = "okay";
+
+ hym8563: hym8563@51 {
+ compatible = "haoyu,hym8563";
+ reg = <0x51>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "xin32k";
+ };
+};
+
+&uart2 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3036-kylin.dts b/arch/arm/boot/dts/rk3036-kylin.dts
new file mode 100644
index 000000000000..992f9cadbc04
--- /dev/null
+++ b/arch/arm/boot/dts/rk3036-kylin.dts
@@ -0,0 +1,300 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "rk3036.dtsi"
+
+/ {
+ model = "Rockchip RK3036 KylinBoard";
+ compatible = "rockchip,rk3036-kylin", "rockchip,rk3036";
+
+ vcc_sys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&acodec {
+ status = "okay";
+};
+
+&emmc {
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ rk808: pmic@1b {
+ compatible = "rockchip,rk808";
+ reg = <0x1b>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int &global_pwroff>;
+ rockchip,system-power-controller;
+ wakeup-source;
+ #clock-cells = <1>;
+ clock-output-names = "xin32k", "rk808-clkout2";
+
+ vcc1-supply = <&vcc_sys>;
+ vcc2-supply = <&vcc_sys>;
+ vcc3-supply = <&vcc_sys>;
+ vcc4-supply = <&vcc_sys>;
+ vcc6-supply = <&vcc_sys>;
+ vcc7-supply = <&vcc_sys>;
+ vcc8-supply = <&vcc_18>;
+ vcc9-supply = <&vcc_io>;
+ vcc10-supply = <&vcc_io>;
+ vcc11-supply = <&vcc_sys>;
+ vcc12-supply = <&vcc_io>;
+ vddio-supply = <&vccio_pmu>;
+
+ regulators {
+ vdd_cpu: DCDC_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-name = "vdd_arm";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_gpu: DCDC_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd_gpu";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_ddr";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_io: DCDC_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_io";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vccio_pmu: LDO_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vccio_pmu";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_tp: LDO_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_tp";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_10: LDO_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd_10";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc18_lcd: LDO_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc18_lcd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vccio_sd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vout5: LDO_REG6 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-name = "vout5";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc_18: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc_18";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcca_codec: LDO_REG8 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcca_codec";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc_wl: SWITCH_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_wl";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_lcd: SWITCH_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_lcd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+ };
+ };
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&sdio {
+ status = "okay";
+
+ broken-cd;
+ bus-width = <4>;
+ cap-sdio-irq;
+ default-sample-phase = <90>;
+ keep-power-in-suspend;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>;
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usb_host {
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&pinctrl {
+ pmic {
+ pmic_int: pmic-int {
+ rockchip,pins = <2 2 RK_FUNC_GPIO &pcfg_pull_default>;
+ };
+ };
+
+ sleep {
+ global_pwroff: global-pwroff {
+ rockchip,pins = <2 7 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
new file mode 100644
index 000000000000..b9567c1e0687
--- /dev/null
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -0,0 +1,622 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/clock/rk3036-cru.h>
+#include "skeleton.dtsi"
+
+/ {
+ compatible = "rockchip,rk3036";
+
+ interrupt-parent = <&gic>;
+
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ mshc0 = &emmc;
+ mshc1 = &sdmmc;
+ mshc2 = &sdio;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x40000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "rockchip,rk3036-smp";
+
+ cpu0: cpu@f00 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf00>;
+ resets = <&cru SRST_CORE0>;
+ operating-points = <
+ /* KHz uV */
+ 816000 1000000
+ >;
+ clock-latency = <40000>;
+ clocks = <&cru ARMCLK>;
+ };
+
+ cpu1: cpu@f01 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf01>;
+ resets = <&cru SRST_CORE1>;
+ };
+ };
+
+ amba {
+ compatible = "arm,amba-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pdma: pdma@20078000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x20078000 0x4000>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ clocks = <&cru ACLK_DMAC2>;
+ clock-names = "apb_pclk";
+ };
+ };
+
+ arm-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ arm,cpu-registers-not-fw-configured;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+ clock-frequency = <24000000>;
+ };
+
+ xin24m: oscillator {
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "xin24m";
+ #clock-cells = <0>;
+ };
+
+ bus_intmem@10080000 {
+ compatible = "mmio-sram";
+ reg = <0x10080000 0x2000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x10080000 0x2000>;
+
+ smp-sram@0 {
+ compatible = "rockchip,rk3066-smp-sram";
+ reg = <0x00 0x10>;
+ };
+ };
+
+ gic: interrupt-controller@10139000 {
+ compatible = "arm,gic-400";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+
+ reg = <0x10139000 0x1000>,
+ <0x1013a000 0x1000>,
+ <0x1013c000 0x2000>,
+ <0x1013e000 0x2000>;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ usb_otg: usb@10180000 {
+ compatible = "rockchip,rk3288-usb", "rockchip,rk3066-usb",
+ "snps,dwc2";
+ reg = <0x10180000 0x40000>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_OTG0>;
+ clock-names = "otg";
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <16>;
+ g-rx-fifo-size = <275>;
+ g-tx-fifo-size = <256 128 128 64 64 32>;
+ g-use-dma;
+ status = "disabled";
+ };
+
+ usb_host: usb@101c0000 {
+ compatible = "rockchip,rk3288-usb", "rockchip,rk3066-usb",
+ "snps,dwc2";
+ reg = <0x101c0000 0x40000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_OTG1>;
+ clock-names = "otg";
+ dr_mode = "host";
+ status = "disabled";
+ };
+
+ sdmmc: dwmmc@10214000 {
+ compatible = "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc";
+ reg = <0x10214000 0x4000>;
+ clock-frequency = <37500000>;
+ clock-freq-min-max = <400000 37500000>;
+ clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>;
+ clock-names = "biu", "ciu";
+ fifo-depth = <0x100>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ sdio: dwmmc@10218000 {
+ compatible = "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc";
+ reg = <0x10218000 0x4000>;
+ clock-freq-min-max = <400000 37500000>;
+ clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
+ <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+ fifo-depth = <0x100>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ emmc: dwmmc@1021c000 {
+ compatible = "rockchip,rk3288-dw-mshc";
+ reg = <0x1021c000 0x4000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ broken-cd;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ clock-frequency = <37500000>;
+ clock-freq-min-max = <400000 37500000>;
+ clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
+ <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+ default-sample-phase = <158>;
+ disable-wp;
+ dmas = <&pdma 12>;
+ dma-names = "rx-tx";
+ fifo-depth = <0x100>;
+ mmc-ddr-1_8v;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+ status = "disabled";
+ };
+
+ i2s: i2s@10220000 {
+ compatible = "rockchip,rk3036-i2s", "rockchip,rk3066-i2s";
+ reg = <0x10220000 0x4000>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "i2s_hclk", "i2s_clk";
+ clocks = <&cru HCLK_I2S>, <&cru SCLK_I2S>;
+ dmas = <&pdma 0>, <&pdma 1>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s_bus>;
+ status = "disabled";
+ };
+
+ cru: clock-controller@20000000 {
+ compatible = "rockchip,rk3036-cru";
+ reg = <0x20000000 0x1000>;
+ rockchip,grf = <&grf>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ assigned-clocks = <&cru PLL_GPLL>;
+ assigned-clock-rates = <594000000>;
+ };
+
+ grf: syscon@20008000 {
+ compatible = "rockchip,rk3036-grf", "syscon";
+ reg = <0x20008000 0x1000>;
+ };
+
+ acodec: acodec-ana@20030000 {
+ compatible = "rk3036-codec";
+ reg = <0x20030000 0x4000>;
+ rockchip,grf = <&grf>;
+ clock-names = "acodec_pclk";
+ clocks = <&cru PCLK_ACODEC>;
+ status = "disabled";
+ };
+
+ timer: timer@20044000 {
+ compatible = "rockchip,rk3036-timer", "rockchip,rk3288-timer";
+ reg = <0x20044000 0x20>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&xin24m>, <&cru PCLK_TIMER>;
+ clock-names = "timer", "pclk";
+ };
+
+ pwm0: pwm@20050000 {
+ compatible = "rockchip,rk3036-pwm", "rockchip,rk2928-pwm";
+ reg = <0x20050000 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pin>;
+ status = "disabled";
+ };
+
+ pwm1: pwm@20050010 {
+ compatible = "rockchip,rk3036-pwm", "rockchip,rk2928-pwm";
+ reg = <0x20050010 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm1_pin>;
+ status = "disabled";
+ };
+
+ pwm2: pwm@20050020 {
+ compatible = "rockchip,rk3036-pwm", "rockchip,rk2928-pwm";
+ reg = <0x20050020 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm2_pin>;
+ status = "disabled";
+ };
+
+ pwm3: pwm@20050030 {
+ compatible = "rockchip,rk3036-pwm", "rockchip,rk2928-pwm";
+ reg = <0x20050030 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm3_pin>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@20056000 {
+ compatible = "rockchip,rk3288-i2c";
+ reg = <0x20056000 0x1000>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "i2c";
+ clocks = <&cru PCLK_I2C1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_xfer>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@2005a000 {
+ compatible = "rockchip,rk3288-i2c";
+ reg = <0x2005a000 0x1000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "i2c";
+ clocks = <&cru PCLK_I2C2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_xfer>;
+ status = "disabled";
+ };
+
+ uart0: serial@20060000 {
+ compatible = "rockchip,rk3036-uart", "snps,dw-apb-uart";
+ reg = <0x20060000 0x100>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clock-frequency = <24000000>;
+ clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
+ clock-names = "baudclk", "apb_pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+ status = "disabled";
+ };
+
+ uart1: serial@20064000 {
+ compatible = "rockchip,rk3036-uart", "snps,dw-apb-uart";
+ reg = <0x20064000 0x100>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clock-frequency = <24000000>;
+ clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
+ clock-names = "baudclk", "apb_pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_xfer>;
+ status = "disabled";
+ };
+
+ uart2: serial@20068000 {
+ compatible = "rockchip,rk3036-uart", "snps,dw-apb-uart";
+ reg = <0x20068000 0x100>;
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clock-frequency = <24000000>;
+ clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
+ clock-names = "baudclk", "apb_pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_xfer>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@20072000 {
+ compatible = "rockchip,rk3288-i2c";
+ reg = <0x20072000 0x1000>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "i2c";
+ clocks = <&cru PCLK_I2C0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_xfer>;
+ status = "disabled";
+ };
+
+ pinctrl: pinctrl {
+ compatible = "rockchip,rk3036-pinctrl";
+ rockchip,grf = <&grf>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio0: gpio0@2007c000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x2007c000 0x100>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio1: gpio1@20080000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x20080000 0x100>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO1>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio2: gpio2@20084000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x20084000 0x100>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO2>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pcfg_pull_default: pcfg_pull_default {
+ bias-pull-pin-default;
+ };
+
+ pcfg_pull_none: pcfg-pull-none {
+ bias-disable;
+ };
+
+ pwm0 {
+ pwm0_pin: pwm0-pin {
+ rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm1 {
+ pwm1_pin: pwm1-pin {
+ rockchip,pins = <0 1 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm2 {
+ pwm2_pin: pwm2-pin {
+ rockchip,pins = <0 1 2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm3 {
+ pwm3_pin: pwm3-pin {
+ rockchip,pins = <0 27 1 &pcfg_pull_none>;
+ };
+ };
+
+ sdmmc {
+ sdmmc_clk: sdmmc-clk {
+ rockchip,pins = <1 16 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ sdmmc_cmd: sdmmc-cmd {
+ rockchip,pins = <1 15 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ sdmmc_cd: sdmcc-cd {
+ rockchip,pins = <1 17 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ sdmmc_bus1: sdmmc-bus1 {
+ rockchip,pins = <1 18 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ sdmmc_bus4: sdmmc-bus4 {
+ rockchip,pins = <1 18 RK_FUNC_1 &pcfg_pull_default>,
+ <1 19 RK_FUNC_1 &pcfg_pull_default>,
+ <1 20 RK_FUNC_1 &pcfg_pull_default>,
+ <1 21 RK_FUNC_1 &pcfg_pull_default>;
+ };
+ };
+
+ sdio {
+ sdio_bus1: sdio-bus1 {
+ rockchip,pins = <0 11 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ sdio_bus4: sdio-bus4 {
+ rockchip,pins = <0 11 RK_FUNC_1 &pcfg_pull_default>,
+ <0 12 RK_FUNC_1 &pcfg_pull_default>,
+ <0 13 RK_FUNC_1 &pcfg_pull_default>,
+ <0 14 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ sdio_cmd: sdio-cmd {
+ rockchip,pins = <0 8 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ sdio_clk: sdio-clk {
+ rockchip,pins = <0 9 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ emmc {
+ /*
+ * We run eMMC at max speed; bump up drive strength.
+ * We also have external pulls, so disable the internal ones.
+ */
+ emmc_clk: emmc-clk {
+ rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ emmc_cmd: emmc-cmd {
+ rockchip,pins = <2 1 RK_FUNC_2 &pcfg_pull_default>;
+ };
+
+ emmc_bus8: emmc-bus8 {
+ rockchip,pins = <1 24 RK_FUNC_2 &pcfg_pull_default>,
+ <1 25 RK_FUNC_2 &pcfg_pull_default>,
+ <1 26 RK_FUNC_2 &pcfg_pull_default>,
+ <1 27 RK_FUNC_2 &pcfg_pull_default>,
+ <1 28 RK_FUNC_2 &pcfg_pull_default>,
+ <1 29 RK_FUNC_2 &pcfg_pull_default>,
+ <1 30 RK_FUNC_2 &pcfg_pull_default>,
+ <1 31 RK_FUNC_2 &pcfg_pull_default>;
+ };
+ };
+
+ i2c0 {
+ i2c0_xfer: i2c0-xfer {
+ rockchip,pins = <0 0 RK_FUNC_1 &pcfg_pull_none>,
+ <0 1 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2c1 {
+ i2c1_xfer: i2c1-xfer {
+ rockchip,pins = <0 2 RK_FUNC_1 &pcfg_pull_none>,
+ <0 3 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2c2 {
+ i2c2_xfer: i2c2-xfer {
+ rockchip,pins = <2 20 RK_FUNC_1 &pcfg_pull_none>,
+ <2 21 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2s {
+ i2s_bus: i2s-bus {
+ rockchip,pins = <1 0 RK_FUNC_1 &pcfg_pull_none>,
+ <1 1 RK_FUNC_1 &pcfg_pull_none>,
+ <1 2 RK_FUNC_1 &pcfg_pull_none>,
+ <1 3 RK_FUNC_1 &pcfg_pull_none>,
+ <1 4 RK_FUNC_1 &pcfg_pull_none>,
+ <1 5 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uart0 {
+ uart0_xfer: uart0-xfer {
+ rockchip,pins = <0 16 RK_FUNC_1 &pcfg_pull_default>,
+ <0 17 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart0_cts: uart0-cts {
+ rockchip,pins = <0 18 RK_FUNC_1 &pcfg_pull_default>;
+ };
+
+ uart0_rts: uart0-rts {
+ rockchip,pins = <0 19 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uart1 {
+ uart1_xfer: uart1-xfer {
+ rockchip,pins = <2 22 RK_FUNC_1 &pcfg_pull_default>,
+ <2 23 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ /* no rts / cts for uart1 */
+ };
+
+ uart2 {
+ uart2_xfer: uart2-xfer {
+ rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_default>,
+ <1 19 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ /* no rts / cts for uart2 */
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index 946f18705e96..58bac5053858 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -103,6 +103,8 @@
dma-names = "tx", "rx";
clock-names = "i2s_hclk", "i2s_clk";
clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+ rockchip,playback-channels = <8>;
+ rockchip,capture-channels = <2>;
status = "disabled";
};
@@ -118,6 +120,8 @@
dma-names = "tx", "rx";
clock-names = "i2s_hclk", "i2s_clk";
clocks = <&cru HCLK_I2S1>, <&cru SCLK_I2S1>;
+ rockchip,playback-channels = <2>;
+ rockchip,capture-channels = <2>;
status = "disabled";
};
@@ -133,6 +137,8 @@
dma-names = "tx", "rx";
clock-names = "i2s_hclk", "i2s_clk";
clocks = <&cru HCLK_I2S2>, <&cru SCLK_I2S2>;
+ rockchip,playback-channels = <2>;
+ rockchip,capture-channels = <2>;
status = "disabled";
};
@@ -153,6 +159,19 @@
clock-names = "timer", "pclk";
};
+ efuse: efuse@20010000 {
+ compatible = "rockchip,rockchip-efuse";
+ reg = <0x20010000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&cru PCLK_EFUSE>;
+ clock-names = "pclk_efuse";
+
+ cpu_leakage: cpu_leakage {
+ reg = <0x17 0x1>;
+ };
+ };
+
timer@20038000 {
compatible = "snps,dw-apb-timer-osc";
reg = <0x20038000 0x100>;
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 6399942f1840..348d46b7ada5 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -118,6 +118,8 @@
dma-names = "tx", "rx";
clock-names = "i2s_hclk", "i2s_clk";
clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+ rockchip,playback-channels = <2>;
+ rockchip,capture-channels = <2>;
status = "disabled";
};
@@ -144,6 +146,19 @@
#reset-cells = <1>;
};
+ efuse: efuse@20010000 {
+ compatible = "rockchip,rockchip-efuse";
+ reg = <0x20010000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&cru PCLK_EFUSE>;
+ clock-names = "pclk_efuse";
+
+ cpu_leakage: cpu_leakage {
+ reg = <0x17 0x1>;
+ };
+ };
+
usbphy: phy {
compatible = "rockchip,rk3188-usb-phy", "rockchip,rk3288-usb-phy";
rockchip,grf = <&grf>;
diff --git a/arch/arm/boot/dts/rk3228-evb.dts b/arch/arm/boot/dts/rk3228-evb.dts
new file mode 100644
index 000000000000..e3898b810150
--- /dev/null
+++ b/arch/arm/boot/dts/rk3228-evb.dts
@@ -0,0 +1,66 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "rk3228.dtsi"
+
+/ {
+ model = "Rockchip RK3228 Evaluation board";
+ compatible = "rockchip,rk3228-evb", "rockchip,rk3228";
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x40000000>;
+ };
+};
+
+&emmc {
+ broken-cd;
+ cap-mmc-highspeed;
+ mmc-ddr-1_8v;
+ disable-wp;
+ non-removable;
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3228.dtsi b/arch/arm/boot/dts/rk3228.dtsi
new file mode 100644
index 000000000000..119ff12ab440
--- /dev/null
+++ b/arch/arm/boot/dts/rk3228.dtsi
@@ -0,0 +1,442 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/clock/rk3228-cru.h>
+#include "skeleton.dtsi"
+
+/ {
+ compatible = "rockchip,rk3228";
+
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@f00 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf00>;
+ resets = <&cru SRST_CORE0>;
+ operating-points = <
+ /* KHz uV */
+ 816000 1000000
+ >;
+ clock-latency = <40000>;
+ clocks = <&cru ARMCLK>;
+ };
+
+ cpu1: cpu@f01 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf01>;
+ resets = <&cru SRST_CORE1>;
+ };
+
+ cpu2: cpu@f02 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf02>;
+ resets = <&cru SRST_CORE2>;
+ };
+
+ cpu3: cpu@f03 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0xf03>;
+ resets = <&cru SRST_CORE3>;
+ };
+ };
+
+ amba {
+ compatible = "arm,amba-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pdma: pdma@110f0000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x110f0000 0x4000>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ clocks = <&cru ACLK_DMAC>;
+ clock-names = "apb_pclk";
+ };
+ };
+
+ arm-pmu {
+ compatible = "arm,cortex-a7-pmu";
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ arm,cpu-registers-not-fw-configured;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ clock-frequency = <24000000>;
+ };
+
+ xin24m: oscillator {
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "xin24m";
+ #clock-cells = <0>;
+ };
+
+ grf: syscon@11000000 {
+ compatible = "syscon";
+ reg = <0x11000000 0x1000>;
+ };
+
+ uart0: serial@11010000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x11010000 0x100>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <24000000>;
+ clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
+ clock-names = "baudclk", "apb_pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ uart1: serial@11020000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x11020000 0x100>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <24000000>;
+ clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
+ clock-names = "baudclk", "apb_pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_xfer>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ uart2: serial@11030000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x11030000 0x100>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <24000000>;
+ clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
+ clock-names = "baudclk", "apb_pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_xfer>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ pwm0: pwm@110b0000 {
+ compatible = "rockchip,rk3288-pwm";
+ reg = <0x110b0000 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pin>;
+ status = "disabled";
+ };
+
+ pwm1: pwm@110b0010 {
+ compatible = "rockchip,rk3288-pwm";
+ reg = <0x110b0010 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm1_pin>;
+ status = "disabled";
+ };
+
+ pwm2: pwm@110b0020 {
+ compatible = "rockchip,rk3288-pwm";
+ reg = <0x110b0020 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm2_pin>;
+ status = "disabled";
+ };
+
+ pwm3: pwm@110b0030 {
+ compatible = "rockchip,rk3288-pwm";
+ reg = <0x110b0030 0x10>;
+ #pwm-cells = <2>;
+ clocks = <&cru PCLK_PWM>;
+ clock-names = "pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm3_pin>;
+ status = "disabled";
+ };
+
+ timer: timer@110c0000 {
+ compatible = "rockchip,rk3288-timer";
+ reg = <0x110c0000 0x20>;
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&xin24m>, <&cru PCLK_TIMER>;
+ clock-names = "timer", "pclk";
+ };
+
+ cru: clock-controller@110e0000 {
+ compatible = "rockchip,rk3228-cru";
+ reg = <0x110e0000 0x1000>;
+ rockchip,grf = <&grf>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ assigned-clocks = <&cru PLL_GPLL>;
+ assigned-clock-rates = <594000000>;
+ };
+
+ emmc: dwmmc@30020000 {
+ compatible = "rockchip,rk3288-dw-mshc";
+ reg = <0x30020000 0x4000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <37500000>;
+ clock-freq-min-max = <400000 37500000>;
+ clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
+ <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+ bus-width = <8>;
+ default-sample-phase = <158>;
+ num-slots = <1>;
+ fifo-depth = <0x100>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+ status = "disabled";
+ };
+
+ gic: interrupt-controller@32010000 {
+ compatible = "arm,gic-400";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+
+ reg = <0x32011000 0x1000>,
+ <0x32012000 0x1000>,
+ <0x32014000 0x2000>,
+ <0x32016000 0x2000>;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ pinctrl: pinctrl {
+ compatible = "rockchip,rk3228-pinctrl";
+ rockchip,grf = <&grf>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio0: gpio0@11110000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x11110000 0x100>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio1: gpio1@11120000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x11120000 0x100>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO1>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio2: gpio2@11130000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x11130000 0x100>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO2>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio3: gpio3@11140000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x11140000 0x100>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_GPIO3>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pcfg_pull_up: pcfg-pull-up {
+ bias-pull-up;
+ };
+
+ pcfg_pull_down: pcfg-pull-down {
+ bias-pull-down;
+ };
+
+ pcfg_pull_none: pcfg-pull-none {
+ bias-disable;
+ };
+
+ emmc {
+ emmc_clk: emmc-clk {
+ rockchip,pins = <2 7 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ emmc_cmd: emmc-cmd {
+ rockchip,pins = <1 22 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ emmc_bus8: emmc-bus8 {
+ rockchip,pins = <1 24 RK_FUNC_2 &pcfg_pull_none>,
+ <1 25 RK_FUNC_2 &pcfg_pull_none>,
+ <1 26 RK_FUNC_2 &pcfg_pull_none>,
+ <1 27 RK_FUNC_2 &pcfg_pull_none>,
+ <1 28 RK_FUNC_2 &pcfg_pull_none>,
+ <1 29 RK_FUNC_2 &pcfg_pull_none>,
+ <1 30 RK_FUNC_2 &pcfg_pull_none>,
+ <1 31 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm0 {
+ pwm0_pin: pwm0-pin {
+ rockchip,pins = <3 21 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ pwm1 {
+ pwm1_pin: pwm1-pin {
+ rockchip,pins = <0 30 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm2 {
+ pwm2_pin: pwm2-pin {
+ rockchip,pins = <1 12 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm3 {
+ pwm3_pin: pwm3-pin {
+ rockchip,pins = <1 11 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ uart0 {
+ uart0_xfer: uart0-xfer {
+ rockchip,pins = <2 26 RK_FUNC_1 &pcfg_pull_none>,
+ <2 27 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart0_cts: uart0-cts {
+ rockchip,pins = <2 29 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart0_rts: uart0-rts {
+ rockchip,pins = <0 17 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uart1 {
+ uart1_xfer: uart1-xfer {
+ rockchip,pins = <1 9 RK_FUNC_1 &pcfg_pull_none>,
+ <1 10 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart1_cts: uart1-cts {
+ rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart1_rts: uart1-rts {
+ rockchip,pins = <1 11 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uart2 {
+ uart2_xfer: uart2-xfer {
+ rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_none>,
+ <1 19 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ uart2_cts: uart2-cts {
+ rockchip,pins = <0 25 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart2_rts: uart2-rts {
+ rockchip,pins = <0 24 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3288-evb-act8846.dts b/arch/arm/boot/dts/rk3288-evb-act8846.dts
index 43949a6771f0..452ca2441e84 100644
--- a/arch/arm/boot/dts/rk3288-evb-act8846.dts
+++ b/arch/arm/boot/dts/rk3288-evb-act8846.dts
@@ -43,10 +43,26 @@
/ {
compatible = "rockchip,rk3288-evb-act8846", "rockchip,rk3288";
-};
-&cpu0 {
- cpu0-supply = <&vdd_cpu>;
+ vcc_lcd: vcc-lcd {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio7 3 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_en>;
+ regulator-name = "vcc_lcd";
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_wl: vcc-wl {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio7 9 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_pwr>;
+ regulator-name = "vcc_wl";
+ vin-supply = <&vcc_18>;
+ };
};
&i2c0 {
@@ -119,8 +135,8 @@
vdd_log: REG3 {
regulator-name = "VDD_LOG";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1500000>;
regulator-always-on;
};
@@ -133,7 +149,7 @@
vccio_sd: REG5 {
regulator-name = "VCCIO_SD";
- regulator-min-microvolt = <3300000>;
+ regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
@@ -152,7 +168,7 @@
regulator-always-on;
};
- vcca_tp: REG8 {
+ vcc_tp: REG8 {
regulator-name = "VCCA_TP";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
@@ -189,3 +205,17 @@
};
};
};
+
+&pinctrl {
+ lcd {
+ lcd_en: lcd-en {
+ rockchip,pins = <7 3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ wifi {
+ wifi_pwr: wifi-pwr {
+ rockchip,pins = <7 9 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
index 18eb6cb495f4..736b08b0bfdd 100644
--- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
+++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
@@ -43,17 +43,6 @@
/ {
compatible = "rockchip,rk3288-evb-rk808", "rockchip,rk3288";
-
- ext_gmac: external-gmac-clock {
- compatible = "fixed-clock";
- clock-frequency = <125000000>;
- clock-output-names = "ext_gmac";
- #clock-cells = <0>;
- };
-};
-
-&cpu0 {
- cpu0-supply = <&vdd_cpu>;
};
&i2c0 {
@@ -244,19 +233,3 @@
};
};
};
-
-&gmac {
- phy-supply = <&vcc_phy>;
- phy-mode = "rgmii";
- clock_in_out = "input";
- snps,reset-gpio = <&gpio4 7 0>;
- snps,reset-active-low;
- snps,reset-delays-us = <0 10000 1000000>;
- assigned-clocks = <&cru SCLK_MAC>;
- assigned-clock-parents = <&ext_gmac>;
- pinctrl-names = "default";
- pinctrl-0 = <&rgmii_pins>;
- tx_delay = <0x30>;
- rx_delay = <0x10>;
- status = "ok";
-};
diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index f6d2e7894b05..4faabdb65868 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -89,6 +89,13 @@
pwms = <&pwm0 0 1000000 PWM_POLARITY_INVERTED>;
};
+ ext_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "ext_gmac";
+ #clock-cells = <0>;
+ };
+
gpio-keys {
compatible = "gpio-keys";
#address-cells = <1>;
@@ -160,6 +167,10 @@
};
};
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
&emmc {
broken-cd;
bus-width = <8>;
@@ -172,11 +183,6 @@
status = "okay";
};
-&hdmi {
- ddc-i2c-bus = <&i2c5>;
- status = "okay";
-};
-
&sdmmc {
bus-width = <4>;
cap-mmc-highspeed;
@@ -191,6 +197,27 @@
vqmmc-supply = <&vccio_sd>;
};
+&gmac {
+ phy-supply = <&vcc_phy>;
+ phy-mode = "rgmii";
+ clock_in_out = "input";
+ snps,reset-gpio = <&gpio4 7 0>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 1000000>;
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&ext_gmac>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins>;
+ tx_delay = <0x30>;
+ rx_delay = <0x10>;
+ status = "ok";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c5>;
+ status = "okay";
+};
+
&i2c0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/rk3288-r89.dts b/arch/arm/boot/dts/rk3288-r89.dts
index 14b9fc73c8a4..17f13c73fe5e 100644
--- a/arch/arm/boot/dts/rk3288-r89.dts
+++ b/arch/arm/boot/dts/rk3288-r89.dts
@@ -78,6 +78,13 @@
};
};
+ ir: ir-receiver {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_int>;
+ };
+
vcc_host: vcc-host-regulator {
compatible = "regulator-fixed";
enable-active-high;
@@ -310,6 +317,12 @@
};
};
+ ir {
+ ir_int: ir-int {
+ rockchip,pins = <7 0 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
pmic {
pmic_int: pmic-int {
rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
diff --git a/arch/arm/boot/dts/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
index 1813b7c36556..1ece66f3e162 100644
--- a/arch/arm/boot/dts/rk3288-rock2-som.dtsi
+++ b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
@@ -109,6 +109,7 @@
act8846: act8846@5a {
compatible = "active-semi,act8846";
reg = <0x5a>;
+ system-power-controller;
inl1-supply = <&vcc_io>;
inl2-supply = <&vcc_sys>;
inl3-supply = <&vcc_20>;
diff --git a/arch/arm/boot/dts/rk3288-rock2-square.dts b/arch/arm/boot/dts/rk3288-rock2-square.dts
index 8af35c867a80..c5453a0b07fc 100644
--- a/arch/arm/boot/dts/rk3288-rock2-square.dts
+++ b/arch/arm/boot/dts/rk3288-rock2-square.dts
@@ -49,6 +49,13 @@
stdout-path = "serial2:115200n8";
};
+ ir: ir-receiver {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio8 1 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_int>;
+ };
+
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "SPDIF";
@@ -131,6 +138,12 @@
};
&pinctrl {
+ ir {
+ ir_int: ir-int {
+ rockchip,pins = <8 1 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
pmic {
pmic_int: pmic-int {
rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_up>;
diff --git a/arch/arm/boot/dts/rk3288-thermal.dtsi b/arch/arm/boot/dts/rk3288-thermal.dtsi
index 340406652186..651b962e3d53 100644
--- a/arch/arm/boot/dts/rk3288-thermal.dtsi
+++ b/arch/arm/boot/dts/rk3288-thermal.dtsi
@@ -52,7 +52,7 @@ reserve_thermal: reserve_thermal {
};
cpu_thermal: cpu_thermal {
- polling-delay-passive = <1000>; /* milliseconds */
+ polling-delay-passive = <100>; /* milliseconds */
polling-delay = <5000>; /* milliseconds */
thermal-sensors = <&tsadc 1>;
@@ -63,6 +63,11 @@ cpu_thermal: cpu_thermal {
hysteresis = <2000>; /* millicelsius */
type = "passive";
};
+ cpu_alert1: cpu_alert1 {
+ temperature = <75000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
cpu_crit: cpu_crit {
temperature = <90000>; /* millicelsius */
hysteresis = <2000>; /* millicelsius */
@@ -74,13 +79,18 @@ cpu_thermal: cpu_thermal {
map0 {
trip = <&cpu_alert0>;
cooling-device =
+ <&cpu0 THERMAL_NO_LIMIT 6>;
+ };
+ map1 {
+ trip = <&cpu_alert1>;
+ cooling-device =
<&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
};
};
gpu_thermal: gpu_thermal {
- polling-delay-passive = <1000>; /* milliseconds */
+ polling-delay-passive = <100>; /* milliseconds */
polling-delay = <5000>; /* milliseconds */
thermal-sensors = <&tsadc 2>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-brain.dts b/arch/arm/boot/dts/rk3288-veyron-brain.dts
new file mode 100644
index 000000000000..cf5311d2617c
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-brain.dts
@@ -0,0 +1,139 @@
+/*
+ * Google Veyron Brain Rev 0 board device tree source
+ *
+ * Copyright 2014 Google, Inc
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3288-veyron.dtsi"
+
+/ {
+ model = "Google Brain";
+ compatible = "google,veyron-brain-rev0", "google,veyron-brain",
+ "google,veyron", "rockchip,rk3288";
+
+ vcc33_sys: vcc33-sys {
+ vin-supply = <&vcc_5v>;
+ };
+
+ vcc33_io: vcc33_io {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc33_io";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc33_sys>;
+ /* This is gated by vcc_18 too */
+ };
+
+ /* This turns on vbus for host2 and otg (dwc2) */
+ vcc5_host2: vcc5-host2-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_pwr_en>;
+ regulator-name = "vcc5_host2";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&pinctrl {
+ hdmi {
+ vcc50_hdmi_en: vcc50-hdmi-en {
+ rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ dvs_1: dvs-1 {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ dvs_2: dvs-2 {
+ rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ usb-host {
+ usb2_pwr_en: usb2-pwr-en {
+ rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&rk808 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>;
+ dvs-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>,
+ <&gpio7 15 GPIO_ACTIVE_HIGH>;
+
+ /delete-property/ vcc6-supply;
+
+ regulators {
+ /* vcc33_io is sourced directly from vcc33_sys */
+ /delete-node/ LDO_REG1;
+
+ /* This is not a pwren anymore, but the real power supply */
+ vdd10_lcd: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd10_lcd";
+ regulator-suspend-mem-disabled;
+ };
+
+ vcc18_hdmi: SWITCH_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc18_hdmi";
+ regulator-suspend-mem-disabled;
+ };
+ };
+};
+
+&vcc50_hdmi {
+ enable-active-high;
+ gpio = <&gpio7 2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc50_hdmi_en>;
+};
diff --git a/arch/arm/boot/dts/rk3288-veyron-mickey.dts b/arch/arm/boot/dts/rk3288-veyron-mickey.dts
new file mode 100644
index 000000000000..f36f6f459225
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-mickey.dts
@@ -0,0 +1,250 @@
+/*
+ * Google Veyron Mickey Rev 0 board device tree source
+ *
+ * Copyright 2015 Google, Inc
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3288-veyron.dtsi"
+
+/ {
+ model = "Google Mickey";
+ compatible = "google,veyron-mickey-rev8", "google,veyron-mickey-rev7",
+ "google,veyron-mickey-rev6", "google,veyron-mickey-rev5",
+ "google,veyron-mickey-rev4", "google,veyron-mickey-rev3",
+ "google,veyron-mickey-rev2", "google,veyron-mickey-rev1",
+ "google,veyron-mickey-rev0", "google,veyron-mickey",
+ "google,veyron", "rockchip,rk3288";
+
+ vcc_5v: vcc-5v {
+ vin-supply = <&vcc33_sys>;
+ };
+
+ vcc33_io: vcc33_io {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc33_io";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc33_sys>;
+ };
+};
+
+&cpu_thermal {
+ /delete-node/ trips;
+ /delete-node/ cooling-maps;
+
+ trips {
+ cpu_alert_almost_warm: cpu_alert_almost_warm {
+ temperature = <63000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_alert_warm: cpu_alert_warm {
+ temperature = <65000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_alert_almost_hot: cpu_alert_almost_hot {
+ temperature = <80000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_alert_hot: cpu_alert_hot {
+ temperature = <82000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_alert_hotter: cpu_alert_hotter {
+ temperature = <84000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_alert_very_hot: cpu_alert_very_hot {
+ temperature = <85000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_crit: cpu_crit {
+ temperature = <90000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ /*
+ * After 1st level, throttle the CPU down to as low as 1.4 GHz
+ * and don't let the GPU go faster than 400 MHz. Note that we
+ * won't throttle the GPU lower than 400 MHz due to CPU
+ * heat--we'll let the GPU do the rest itself.
+ */
+ cpu_warm_limit_cpu {
+ trip = <&cpu_alert_warm>;
+ cooling-device =
+ <&cpu0 THERMAL_NO_LIMIT 4>;
+ };
+
+ /*
+ * Add some discrete steps to help throttling system deal
+ * with the fact that there are two passive cooling devices:
+ * the CPU and the GPU.
+ *
+ * - 1.2 GHz - 1.0 GHz (almost hot)
+ * - 800 MHz (hot)
+ * - 800 MHz - 696 MHz (hotter)
+ * - 696 MHz - min (very hot)
+ *
+ * Note:
+ * - 800 MHz appears to be a "sweet spot" for me. I can run
+ * some pretty serious workload here and be happy.
+ * - After 696 MHz we stop lowering voltage, so throttling
+ * past there is less effective.
+ */
+ cpu_almost_hot_limit_cpu {
+ trip = <&cpu_alert_almost_hot>;
+ cooling-device =
+ <&cpu0 5 6>;
+ };
+ cpu_hot_limit_cpu {
+ trip = <&cpu_alert_hot>;
+ cooling-device =
+ <&cpu0 7 7>;
+ };
+ cpu_hotter_limit_cpu {
+ trip = <&cpu_alert_hotter>;
+ cooling-device =
+ <&cpu0 7 8>;
+ };
+ cpu_very_hot_limit_cpu {
+ trip = <&cpu_alert_very_hot>;
+ cooling-device =
+ <&cpu0 8 THERMAL_NO_LIMIT>;
+ };
+ };
+};
+
+&emmc {
+ /delete-property/mmc-hs200-1_8v;
+};
+
+&i2c2 {
+ status = "disabled";
+};
+
+&i2c4 {
+ status = "disabled";
+};
+
+&i2s {
+ status = "okay";
+ clock-names = "i2s_hclk", "i2s_clk", "i2s_clk_out";
+ clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>, <&cru SCLK_I2S0_OUT>;
+};
+
+&rk808 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>;
+ dvs-gpios = <&gpio7 12 GPIO_ACTIVE_HIGH>,
+ <&gpio7 15 GPIO_ACTIVE_HIGH>;
+
+ /delete-property/ vcc6-supply;
+ /delete-property/ vcc12-supply;
+
+ vcc11-supply = <&vcc33_sys>;
+
+ regulators {
+ /* vcc33_io is sourced directly from vcc33_sys */
+ /delete-node/ LDO_REG1;
+ /delete-node/ LDO_REG7;
+
+ /* This is not a pwren anymore, but the real power supply */
+ vdd10_lcd: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd10_lcd";
+ regulator-suspend-mem-disabled;
+ };
+
+ vcc18_lcd: LDO_REG8 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc18_lcd";
+ regulator-suspend-mem-disabled;
+ };
+ };
+};
+
+&pinctrl {
+ hdmi {
+ power_hdmi_on: power-hdmi-on {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ dvs_1: dvs-1 {
+ rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ dvs_2: dvs-2 {
+ rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+};
+
+&usb_host0_ehci {
+ status = "disabled";
+};
+
+&usb_host1 {
+ status = "disabled";
+};
+
+&vcc50_hdmi {
+ enable-active-high;
+ gpio = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&power_hdmi_on>;
+};
diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
index 85f0373df498..699beb0a9481 100644
--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
@@ -121,6 +121,18 @@
clock-frequency = <400000>;
i2c-scl-falling-time-ns = <50>;
i2c-scl-rising-time-ns = <300>;
+
+ touchscreen@10 {
+ compatible = "elan,ekth3500";
+ reg = <0x10>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_int &touch_rst>;
+ reset-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;
+ vcc33-supply = <&vcc33_touch>;
+ vccio-supply = <&vcc33_touch>;
+ };
};
&rk808 {
diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts
index a7ea7d06cf7f..b34a7b5b3f62 100644
--- a/arch/arm/boot/dts/rk3288-veyron-speedy.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts
@@ -88,6 +88,14 @@
};
};
+&cpu_alert0 {
+ temperature = <65000>;
+};
+
+&cpu_alert1 {
+ temperature = <70000>;
+};
+
&rk808 {
pinctrl-names = "default";
pinctrl-0 = <&pmic_int_l>;
diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi
index 5e61f07724d4..9fce91ffff6f 100644
--- a/arch/arm/boot/dts/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi
@@ -340,6 +340,11 @@
i2c-scl-rising-time-ns = <1000>;
};
+&power {
+ assigned-clocks = <&cru SCLK_EDP_24M>;
+ assigned-clock-parents = <&xin24m>;
+};
+
&pwm1 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 04ea209f1737..8ac49f3efc17 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -53,6 +53,7 @@
interrupt-parent = <&gic>;
aliases {
+ ethernet0 = &gmac;
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
@@ -777,9 +778,23 @@
clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>;
+ rockchip,playback-channels = <8>;
+ rockchip,capture-channels = <2>;
status = "disabled";
};
+ crypto: cypto-controller@ff8a0000 {
+ compatible = "rockchip,rk3288-crypto";
+ reg = <0xff8a0000 0x4000>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>,
+ <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC1>;
+ clock-names = "aclk", "hclk", "sclk", "apb_pclk";
+ resets = <&cru SRST_CRYPTO>;
+ reset-names = "crypto-rst";
+ status = "okay";
+ };
+
vopb: vop@ff930000 {
compatible = "rockchip,rk3288-vop";
reg = <0xff930000 0x19c>;
@@ -886,6 +901,19 @@
interrupts = <GIC_PPI 9 0xf04>;
};
+ efuse: efuse@ffb40000 {
+ compatible = "rockchip,rockchip-efuse";
+ reg = <0xffb40000 0x20>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&cru PCLK_EFUSE256>;
+ clock-names = "pclk_efuse";
+
+ cpu_leakage: cpu_leakage@17 {
+ reg = <0x17 0x1>;
+ };
+ };
+
usbphy: phy {
compatible = "rockchip,rk3288-usb-phy";
rockchip,grf = <&grf>;
@@ -1144,7 +1172,7 @@
rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up>;
};
- sdmmc_cd: sdmcc-cd {
+ sdmmc_cd: sdmmc-cd {
rockchip,pins = <6 22 RK_FUNC_1 &pcfg_pull_up>;
};
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 4497d288a7cb..99eeea70223b 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -49,6 +49,7 @@
interrupt-parent = <&gic>;
aliases {
+ ethernet0 = &emac;
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 4dfca8fc49b3..3f750f6170f2 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -637,6 +637,12 @@
atmel,clk-output-range = <0 83000000>;
};
+ pdmic_clk: pdmic_clk {
+ #clock-cells = <0>;
+ reg = <48>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
i2s0_clk: i2s0_clk {
#clock-cells = <0>;
reg = <54>;
@@ -763,6 +769,11 @@
atmel,clk-output-range = <0 83000000>;
};
+ pdmic_gclk: pdmic_gclk {
+ #clock-cells = <0>;
+ reg = <48>;
+ };
+
i2s0_gclk: i2s0_gclk {
#clock-cells = <0>;
reg = <54>;
@@ -852,6 +863,19 @@
clock-names = "t0_clk", "slow_clk";
};
+ pdmic: pdmic@f8018000 {
+ compatible = "atmel,sama5d2-pdmic";
+ reg = <0xf8018000 0x124>;
+ interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(50))>;
+ dma-names = "rx";
+ clocks = <&pdmic_clk>, <&pdmic_gclk>;
+ clock-names = "pclk", "gclk";
+ status = "disabled";
+ };
+
uart0: serial@f801c000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xf801c000 0x100>;
@@ -929,6 +953,13 @@
clocks = <&h32ck>;
};
+ watchdog@f8048040 {
+ compatible = "atmel,sama5d4-wdt";
+ reg = <0xf8048040 0x10>;
+ interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>;
+ status = "disabled";
+ };
+
sckc@f8048050 {
compatible = "atmel,at91sam9x5-sckc";
reg = <0xf8048050 0x4>;
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 2193637b9cd2..b8032bca4621 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -451,7 +451,7 @@
interrupt-parent = <&pmc>;
interrupts = <AT91_PMC_MCKRDY>;
clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>;
- atmel,clk-output-range = <125000000 177000000>;
+ atmel,clk-output-range = <125000000 200000000>;
atmel,clk-divisors = <1 2 4 3>;
};
@@ -916,7 +916,7 @@
};
i2c0: i2c@f8014000 {
- compatible = "atmel,at91sam9x5-i2c";
+ compatible = "atmel,sama5d4-i2c";
reg = <0xf8014000 0x4000>;
interrupts = <32 IRQ_TYPE_LEVEL_HIGH 6>;
dmas = <&dma1
@@ -935,7 +935,7 @@
};
i2c1: i2c@f8018000 {
- compatible = "atmel,at91sam9x5-i2c";
+ compatible = "atmel,sama5d4-i2c";
reg = <0xf8018000 0x4000>;
interrupts = <33 IRQ_TYPE_LEVEL_HIGH 6>;
dmas = <&dma1
@@ -975,7 +975,7 @@
};
i2c2: i2c@f8024000 {
- compatible = "atmel,at91sam9x5-i2c";
+ compatible = "atmel,sama5d4-i2c";
reg = <0xf8024000 0x4000>;
interrupts = <34 IRQ_TYPE_LEVEL_HIGH 6>;
dmas = <&dma1
@@ -1669,15 +1669,23 @@
pinctrl_mmc0_clk_cmd_dat0: mmc0_clk_cmd_dat0 {
atmel,pins =
<AT91_PIOC 4 AT91_PERIPH_B AT91_PINCTRL_NONE /* MCI0_CK, conflict with PCK1(ISI_MCK) */
- AT91_PIOC 5 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_CDB, conflict with NAND_D0 */
- AT91_PIOC 6 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DB0, conflict with NAND_D1 */
+ AT91_PIOC 5 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_CDA, conflict with NAND_D0 */
+ AT91_PIOC 6 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA0, conflict with NAND_D1 */
>;
};
pinctrl_mmc0_dat1_3: mmc0_dat1_3 {
atmel,pins =
- <AT91_PIOC 7 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DB1, conflict with NAND_D2 */
- AT91_PIOC 8 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DB2, conflict with NAND_D3 */
- AT91_PIOC 9 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DB3, conflict with NAND_D4 */
+ <AT91_PIOC 7 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA1, conflict with NAND_D2 */
+ AT91_PIOC 8 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA2, conflict with NAND_D3 */
+ AT91_PIOC 9 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA3, conflict with NAND_D4 */
+ >;
+ };
+ pinctrl_mmc0_dat4_7: mmc0_dat4_7 {
+ atmel,pins =
+ <AT91_PIOC 10 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA4, conflict with NAND_D5 */
+ AT91_PIOC 11 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA5, conflict with NAND_D6 */
+ AT91_PIOC 12 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA6, conflict with NAND_D7 */
+ AT91_PIOC 13 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* MCI0_DA7, conflict with NAND_OE */
>;
};
};
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g.dts b/arch/arm/boot/dts/sh73a0-kzm9g.dts
index 7fc5602810ad..aa8bae3b8fcf 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g.dts
@@ -147,7 +147,7 @@
gpios = <&pcf8575 14 GPIO_ACTIVE_LOW>;
linux,code = <KEY_HOME>;
label = "SW1";
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi
index ff7c8f298f30..3a6056f9f0d2 100644
--- a/arch/arm/boot/dts/sh73a0.dtsi
+++ b/arch/arm/boot/dts/sh73a0.dtsi
@@ -28,6 +28,7 @@
reg = <0>;
clock-frequency = <1196000000>;
power-domains = <&pd_a2sl>;
+ next-level-cache = <&L2>;
};
cpu@1 {
device_type = "cpu";
@@ -35,6 +36,7 @@
reg = <1>;
clock-frequency = <1196000000>;
power-domains = <&pd_a2sl>;
+ next-level-cache = <&L2>;
};
};
@@ -53,6 +55,18 @@
<0xf0000100 0x100>;
};
+ L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xf0100000 0x1000>;
+ interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&pd_a3sm>;
+ arm,data-latency = <3 3 3>;
+ arm,tag-latency = <2 2 2>;
+ arm,shared-override;
+ cache-unified;
+ cache-level = <2>;
+ };
+
sbsc2: memory-controller@fb400000 {
compatible = "renesas,sbsc-sh73a0";
reg = <0xfb400000 0x400>;
@@ -259,6 +273,50 @@
status = "disabled";
};
+ msiof0: spi@e6e20000 {
+ compatible = "renesas,msiof-sh73a0", "renesas,sh-mobile-msiof";
+ reg = <0xe6e20000 0x0064>;
+ interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp0_clks SH73A0_CLK_MSIOF0>;
+ power-domains = <&pd_a3sp>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof1: spi@e6e10000 {
+ compatible = "renesas,msiof-sh73a0", "renesas,sh-mobile-msiof";
+ reg = <0xe6e10000 0x0064>;
+ interrupts = <0 77 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks SH73A0_CLK_MSIOF1>;
+ power-domains = <&pd_a3sp>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof2: spi@e6e00000 {
+ compatible = "renesas,msiof-sh73a0", "renesas,sh-mobile-msiof";
+ reg = <0xe6e00000 0x0064>;
+ interrupts = <0 76 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks SH73A0_CLK_MSIOF2>;
+ power-domains = <&pd_a3sp>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ msiof3: spi@e6c90000 {
+ compatible = "renesas,msiof-sh73a0", "renesas,sh-mobile-msiof";
+ reg = <0xe6c90000 0x0064>;
+ interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks SH73A0_CLK_MSIOF3>;
+ power-domains = <&pd_a3sp>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
sdhi0: sd@ee100000 {
compatible = "renesas,sdhi-sh73a0";
reg = <0xee100000 0x100>;
@@ -798,13 +856,13 @@
mstp0_clks: mstp0_clks@e6150130 {
compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0xe6150130 4>, <0xe6150030 4>;
- clocks = <&cpg_clocks SH73A0_CLK_HP>;
+ clocks = <&cpg_clocks SH73A0_CLK_HP>, <&sub_clk>;
#clock-cells = <1>;
clock-indices = <
- SH73A0_CLK_IIC2
+ SH73A0_CLK_IIC2 SH73A0_CLK_MSIOF0
>;
clock-output-names =
- "iic2";
+ "iic2", "msiof0";
};
mstp1_clks: mstp1_clks@e6150134 {
compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -834,20 +892,24 @@
reg = <0xe6150138 4>, <0xe6150040 4>;
clocks = <&sub_clk>, <&cpg_clocks SH73A0_CLK_HP>,
<&cpg_clocks SH73A0_CLK_HP>, <&sub_clk>,
- <&sub_clk>, <&sub_clk>, <&sub_clk>, <&sub_clk>,
- <&sub_clk>, <&sub_clk>;
+ <&sub_clk>, <&sub_clk>, <&sub_clk>,
+ <&sub_clk>, <&sub_clk>, <&sub_clk>,
+ <&sub_clk>, <&sub_clk>, <&sub_clk>;
#clock-cells = <1>;
clock-indices = <
SH73A0_CLK_SCIFA7 SH73A0_CLK_SY_DMAC
- SH73A0_CLK_MP_DMAC SH73A0_CLK_SCIFA5
- SH73A0_CLK_SCIFB SH73A0_CLK_SCIFA0
- SH73A0_CLK_SCIFA1 SH73A0_CLK_SCIFA2
- SH73A0_CLK_SCIFA3 SH73A0_CLK_SCIFA4
+ SH73A0_CLK_MP_DMAC SH73A0_CLK_MSIOF3
+ SH73A0_CLK_MSIOF1 SH73A0_CLK_SCIFA5
+ SH73A0_CLK_SCIFB SH73A0_CLK_MSIOF2
+ SH73A0_CLK_SCIFA0 SH73A0_CLK_SCIFA1
+ SH73A0_CLK_SCIFA2 SH73A0_CLK_SCIFA3
+ SH73A0_CLK_SCIFA4
>;
clock-output-names =
- "scifa7", "sy_dmac", "mp_dmac", "scifa5",
- "scifb", "scifa0", "scifa1", "scifa2",
- "scifa3", "scifa4";
+ "scifa7", "sy_dmac", "mp_dmac", "msiof3",
+ "msiof1", "scifa5", "scifb", "msiof2",
+ "scifa0", "scifa1", "scifa2", "scifa3",
+ "scifa4";
};
mstp3_clks: mstp3_clks@e615013c {
compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 39c470e291f9..3ed4abdaaa9c 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -677,6 +677,7 @@
#size-cells = <0>;
clocks = <&l4_mp_clk>, <&sdmmc_clk_divided>;
clock-names = "biu", "ciu";
+ status = "disabled";
};
ocram: sram@ffff0000 {
diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts
index a75a666032b2..3c8867862b0d 100644
--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts
@@ -79,6 +79,7 @@
&mmc0 {
vmmc-supply = <&regulator_3_3v>;
vqmmc-supply = <&regulator_3_3v>;
+ status = "okay";
};
&usb1 {
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts
index 555e9caf21e1..afea3645ada4 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts
@@ -100,6 +100,7 @@
&mmc0 {
vmmc-supply = <&regulator_3_3v>;
vqmmc-supply = <&regulator_3_3v>;
+ status = "okay";
};
&uart0 {
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi
new file mode 100644
index 000000000000..f86f9c060d7a
--- /dev/null
+++ b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "socfpga_cyclone5.dtsi"
+
+/ {
+ model = "DENX MCV";
+ compatible = "altr,socfpga-cyclone5", "altr,socfpga";
+
+ memory {
+ name = "memory";
+ device_type = "memory";
+ reg = <0x0 0x40000000>; /* 1 GiB */
+ };
+};
+
+&mmc0 { /* On-SoM eMMC */
+ bus-width = <8>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts b/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts
new file mode 100644
index 000000000000..7186a29b8b86
--- /dev/null
+++ b/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "socfpga_cyclone5_mcv.dtsi"
+
+/ {
+ model = "DENX MCV EVK";
+ compatible = "altr,socfpga-cyclone5", "altr,socfpga";
+
+ aliases {
+ ethernet0 = &gmac0;
+ stmpe-i2c0 = &stmpe1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&can0 {
+ status = "okay";
+};
+
+&can1 {
+ status = "okay";
+};
+
+&gmac0 {
+ phy-mode = "rgmii";
+ status = "okay";
+};
+
+&gpio0 { /* GPIO 0 ... 28 */
+ status = "okay";
+};
+
+&gpio1 { /* GPIO 29 ... 57 */
+ status = "okay";
+};
+
+&gpio2 { /* GPIO 58..66 (HLGPI 0..13 at offset 13) */
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+ speed-mode = <0>;
+
+ stmpe1: stmpe811@41 {
+ compatible = "st,stmpe811";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x41>;
+ id = <0>;
+ blocks = <0x5>;
+ irq-gpio = <&portb 28 0x4>; /* GPIO 57, trig. level HI */
+
+ stmpe_touchscreen {
+ compatible = "st,stmpe-ts";
+ reg = <0>;
+ ts,sample-time = <4>;
+ ts,mod-12b = <1>;
+ ts,ref-sel = <0>;
+ ts,adc-freq = <1>;
+ ts,ave-ctrl = <1>;
+ ts,touch-det-delay = <3>;
+ ts,settling = <4>;
+ ts,fraction-z = <7>;
+ ts,i-drive = <1>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
index d4d0a28fb331..15e43f43f244 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
@@ -84,6 +84,7 @@
cd-gpios = <&portb 18 0>;
vmmc-supply = <&regulator_3_3v>;
vqmmc-supply = <&regulator_3_3v>;
+ status = "okay";
};
&usb1 {
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
index 48bf651bd762..b61f22f9ac9f 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
@@ -80,6 +80,7 @@
&mmc0 {
vmmc-supply = <&regulator_3_3v>;
vqmmc-supply = <&regulator_3_3v>;
+ status = "okay";
};
&usb1 {
diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi
index 50f5e9d09203..341f5b7ed242 100644
--- a/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -512,63 +512,51 @@
// DB8500_REGULATOR_VAPE
db8500_vape_reg: db8500_vape {
- regulator-compatible = "db8500_vape";
regulator-always-on;
};
// DB8500_REGULATOR_VARM
db8500_varm_reg: db8500_varm {
- regulator-compatible = "db8500_varm";
};
// DB8500_REGULATOR_VMODEM
db8500_vmodem_reg: db8500_vmodem {
- regulator-compatible = "db8500_vmodem";
};
// DB8500_REGULATOR_VPLL
db8500_vpll_reg: db8500_vpll {
- regulator-compatible = "db8500_vpll";
};
// DB8500_REGULATOR_VSMPS1
db8500_vsmps1_reg: db8500_vsmps1 {
- regulator-compatible = "db8500_vsmps1";
};
// DB8500_REGULATOR_VSMPS2
db8500_vsmps2_reg: db8500_vsmps2 {
- regulator-compatible = "db8500_vsmps2";
};
// DB8500_REGULATOR_VSMPS3
db8500_vsmps3_reg: db8500_vsmps3 {
- regulator-compatible = "db8500_vsmps3";
};
// DB8500_REGULATOR_VRF1
db8500_vrf1_reg: db8500_vrf1 {
- regulator-compatible = "db8500_vrf1";
};
// DB8500_REGULATOR_SWITCH_SVAMMDSP
db8500_sva_mmdsp_reg: db8500_sva_mmdsp {
- regulator-compatible = "db8500_sva_mmdsp";
};
// DB8500_REGULATOR_SWITCH_SVAMMDSPRET
db8500_sva_mmdsp_ret_reg: db8500_sva_mmdsp_ret {
- regulator-compatible = "db8500_sva_mmdsp_ret";
};
// DB8500_REGULATOR_SWITCH_SVAPIPE
db8500_sva_pipe_reg: db8500_sva_pipe {
- regulator-compatible = "db8500_sva_pipe";
};
// DB8500_REGULATOR_SWITCH_SIAMMDSP
db8500_sia_mmdsp_reg: db8500_sia_mmdsp {
- regulator-compatible = "db8500_sia_mmdsp";
};
// DB8500_REGULATOR_SWITCH_SIAMMDSPRET
@@ -577,39 +565,32 @@
// DB8500_REGULATOR_SWITCH_SIAPIPE
db8500_sia_pipe_reg: db8500_sia_pipe {
- regulator-compatible = "db8500_sia_pipe";
};
// DB8500_REGULATOR_SWITCH_SGA
db8500_sga_reg: db8500_sga {
- regulator-compatible = "db8500_sga";
vin-supply = <&db8500_vape_reg>;
};
// DB8500_REGULATOR_SWITCH_B2R2_MCDE
db8500_b2r2_mcde_reg: db8500_b2r2_mcde {
- regulator-compatible = "db8500_b2r2_mcde";
vin-supply = <&db8500_vape_reg>;
};
// DB8500_REGULATOR_SWITCH_ESRAM12
db8500_esram12_reg: db8500_esram12 {
- regulator-compatible = "db8500_esram12";
};
// DB8500_REGULATOR_SWITCH_ESRAM12RET
db8500_esram12_ret_reg: db8500_esram12_ret {
- regulator-compatible = "db8500_esram12_ret";
};
// DB8500_REGULATOR_SWITCH_ESRAM34
db8500_esram34_reg: db8500_esram34 {
- regulator-compatible = "db8500_esram34";
};
// DB8500_REGULATOR_SWITCH_ESRAM34RET
db8500_esram34_ret_reg: db8500_esram34_ret {
- regulator-compatible = "db8500_esram34_ret";
};
};
@@ -721,7 +702,6 @@
compatible = "stericsson,ab8500-ext-regulator";
ab8500_ext1_reg: ab8500_ext1 {
- regulator-compatible = "ab8500_ext1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
@@ -729,7 +709,6 @@
};
ab8500_ext2_reg: ab8500_ext2 {
- regulator-compatible = "ab8500_ext2";
regulator-min-microvolt = <1360000>;
regulator-max-microvolt = <1360000>;
regulator-boot-on;
@@ -737,7 +716,6 @@
};
ab8500_ext3_reg: ab8500_ext3 {
- regulator-compatible = "ab8500_ext3";
regulator-min-microvolt = <3400000>;
regulator-max-microvolt = <3400000>;
regulator-boot-on;
@@ -750,7 +728,6 @@
// supplies to the display/camera
ab8500_ldo_aux1_reg: ab8500_ldo_aux1 {
- regulator-compatible = "ab8500_ldo_aux1";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <2900000>;
regulator-boot-on;
@@ -760,56 +737,46 @@
// supplies to the on-board eMMC
ab8500_ldo_aux2_reg: ab8500_ldo_aux2 {
- regulator-compatible = "ab8500_ldo_aux2";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <3300000>;
};
// supply for VAUX3; SDcard slots
ab8500_ldo_aux3_reg: ab8500_ldo_aux3 {
- regulator-compatible = "ab8500_ldo_aux3";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <3300000>;
};
// supply for v-intcore12; VINTCORE12 LDO
ab8500_ldo_intcore_reg: ab8500_ldo_intcore {
- regulator-compatible = "ab8500_ldo_intcore";
};
// supply for tvout; gpadc; TVOUT LDO
ab8500_ldo_tvout_reg: ab8500_ldo_tvout {
- regulator-compatible = "ab8500_ldo_tvout";
};
// supply for ab8500-usb; USB LDO
ab8500_ldo_usb_reg: ab8500_ldo_usb {
- regulator-compatible = "ab8500_ldo_usb";
};
// supply for ab8500-vaudio; VAUDIO LDO
ab8500_ldo_audio_reg: ab8500_ldo_audio {
- regulator-compatible = "ab8500_ldo_audio";
};
// supply for v-anamic1 VAMIC1 LDO
ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 {
- regulator-compatible = "ab8500_ldo_anamic1";
};
// supply for v-amic2; VAMIC2 LDO; reuse constants for AMIC1
ab8500_ldo_anamic2_reg: ab8500_ldo_anamic2 {
- regulator-compatible = "ab8500_ldo_anamic2";
};
// supply for v-dmic; VDMIC LDO
ab8500_ldo_dmic_reg: ab8500_ldo_dmic {
- regulator-compatible = "ab8500_ldo_dmic";
};
// supply for U8500 CSI/DSI; VANA LDO
ab8500_ldo_ana_reg: ab8500_ldo_ana {
- regulator-compatible = "ab8500_ldo_ana";
};
};
};
diff --git a/arch/arm/boot/dts/ste-href-stuib.dtsi b/arch/arm/boot/dts/ste-href-stuib.dtsi
index 78b75256c638..c3987ad06d79 100644
--- a/arch/arm/boot/dts/ste-href-stuib.dtsi
+++ b/arch/arm/boot/dts/ste-href-stuib.dtsi
@@ -114,6 +114,8 @@
rohm,touch-max-x = <384>;
rohm,touch-max-y = <704>;
rohm,flip-y;
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_rohm_mode>;
};
bu21013_tp@5d {
@@ -124,6 +126,8 @@
rohm,touch-max-x = <384>;
rohm,touch-max-y = <704>;
rohm,flip-y;
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_rohm_mode>;
};
};
@@ -166,6 +170,25 @@
};
};
};
+ touch {
+ touch_rohm_mode: touch_rohm {
+ /*
+ * ROHM touch screen uses GPIO 143 for
+ * RST1, GPIO 146 for RST2 and
+ * GPIO 67 for interrupts. Pull-up
+ * the IRQ line and drive both
+ * reset signals low.
+ */
+ stuib_cfg1 {
+ pins = "GPIO143_D12", "GPIO146_D13";
+ ste,config = <&gpio_out_lo>;
+ };
+ stuib_cfg2 {
+ pins = "GPIO67_G2";
+ ste,config = <&gpio_in_pu>;
+ };
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
index 0e1c96943d47..b7b4211c5353 100644
--- a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
+++ b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
@@ -66,7 +66,7 @@
keypad,num-columns = <8>;
keypad,num-rows = <8>;
linux,no-autorepeat;
- linux,wakeup;
+ wakeup-source;
linux,keymap = <0x0301006b
0x04010066
0x06040072
@@ -104,13 +104,40 @@
<19 IRQ_TYPE_EDGE_RISING>;
};
lsm303dlh@1e {
- /* Magnetometer */
+ /*
+ * This magnetometer is packaged with
+ * the accelerometer, and has a DRDY line,
+ * however it is not connected on this
+ * board so it can not generate interrupts.
+ */
compatible = "st,lsm303dlh-magn";
reg = <0x1e>;
vdd-supply = <&ab8500_ldo_aux1_reg>;
vddio-supply = <&db8500_vsmps2_reg>;
+ };
+ lis331dl@1c {
+ /* Accelerometer */
+ compatible = "st,lis331dl-accel";
+ st,drdy-int-pin = <1>;
+ reg = <0x1c>;
+ vdd-supply = <&ab8500_ldo_aux1_reg>;
+ vddio-supply = <&db8500_vsmps2_reg>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&accel_tvk_mode>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <18 IRQ_TYPE_EDGE_RISING>,
+ <19 IRQ_TYPE_EDGE_RISING>;
+ };
+ ak8974@0f {
+ /* Magnetometer */
+ compatible = "asahi-kasei,ak8974";
+ reg = <0x0f>;
+ vdd-supply = <&ab8500_ldo_aux1_reg>;
+ vddio-supply = <&db8500_vsmps2_reg>;
pinctrl-names = "default";
- pinctrl-0 = <&magneto_tvk_mode>;
+ pinctrl-0 = <&gyro_magn_tvk_mode>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
l3g4200d@68 {
/* Gyroscope */
@@ -119,6 +146,10 @@
reg = <0x68>;
vdd-supply = <&ab8500_ldo_aux1_reg>;
vddio-supply = <&db8500_vsmps2_reg>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&gyro_magn_tvk_mode>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
lsp001wm@5c {
/* Barometer/pressure sensor */
@@ -159,17 +190,22 @@
/* Accelerometer interrupt lines 1 & 2 */
tvk_cfg {
pins = "GPIO82_C1", "GPIO83_D3";
- ste,config = <&gpio_in_pu>;
+ ste,config = <&gpio_in_pd>;
};
};
};
- magnetometer {
- magneto_tvk_mode: magneto_tvk {
- /* Magnetometer uses GPIO 31 and 32, pull these up/down respectively */
+ gyroscope {
+ /*
+ * These lines are shared between Gyroscope l3g400dh
+ * and AK8974 magnetometer.
+ */
+ gyro_magn_tvk_mode: gyro_magn_tvk {
+ /* GPIO 31 used for INT pull down the line */
tvk_cfg1 {
pins = "GPIO31_V3";
- ste,config = <&gpio_in_pu>;
+ ste,config = <&gpio_in_pd>;
};
+ /* GPIO 32 used for DRDY, pull this down */
tvk_cfg2 {
pins = "GPIO32_V2";
ste,config = <&gpio_in_pd>;
diff --git a/arch/arm/boot/dts/ste-hrefv60plus.dtsi b/arch/arm/boot/dts/ste-hrefv60plus.dtsi
index 9c2387b34d0c..149a72e7e37a 100644
--- a/arch/arm/boot/dts/ste-hrefv60plus.dtsi
+++ b/arch/arm/boot/dts/ste-hrefv60plus.dtsi
@@ -43,7 +43,6 @@
<&vaudio_hf_hrefv60_mode>,
<&gbf_hrefv60_mode>,
<&hdtv_hrefv60_mode>,
- <&touch_hrefv60_mode>,
<&gpios_hrefv60_mode>;
sdi0 {
@@ -190,23 +189,6 @@
};
};
};
- touch {
- touch_hrefv60_mode: touch_hrefv60 {
- /*
- * Touch screen uses GPIO 143 for RST1, GPIO 146 for RST2 and
- * GPIO 67 for interrupts. Pull-up the IRQ line and drive both
- * reset signals low.
- */
- hrefv60_cfg1 {
- pins = "GPIO143_D12", "GPIO146_D13";
- ste,config = <&gpio_out_lo>;
- };
- hrefv60_cfg2 {
- pins = "GPIO67_G2";
- ste,config = <&gpio_in_pu>;
- };
- };
- };
mcde {
lcd_hrefv60_mode: lcd_hrefv60 {
/*
diff --git a/arch/arm/boot/dts/ste-nomadik-s8815.dts b/arch/arm/boot/dts/ste-nomadik-s8815.dts
index 35282c0105c6..789329030658 100644
--- a/arch/arm/boot/dts/ste-nomadik-s8815.dts
+++ b/arch/arm/boot/dts/ste-nomadik-s8815.dts
@@ -163,7 +163,7 @@
label = "user_button";
gpios = <&gpio0 3 0x1>;
linux,code = <1>; /* KEY_ESC */
- gpio-key,wakeup;
+ wakeup-source;
pinctrl-names = "default";
pinctrl-0 = <&user_button_default_mode>;
};
diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts
index e80e42163883..08f82077b64d 100644
--- a/arch/arm/boot/dts/ste-snowball.dts
+++ b/arch/arm/boot/dts/ste-snowball.dts
@@ -281,7 +281,8 @@
vddio-supply = <&db8500_vsmps2_reg>;
pinctrl-names = "default";
pinctrl-0 = <&magneto_snowball_mode>;
- gpios = <&gpio5 5 0x4>; /* DRDY line */
+ interrupt-parent = <&gpio5>;
+ interrupts = <5 IRQ_TYPE_EDGE_RISING>; /* DRDY line */
};
l3g4200d@68 {
/* Gyroscope */
@@ -292,9 +293,9 @@
vddio-supply = <&db8500_vsmps2_reg>;
pinctrl-names = "default";
pinctrl-0 = <&gyro_snowball_mode>;
- gpios = <&gpio5 6 0x4>; /* DRDY line */
interrupt-parent = <&gpio5>;
- interrupts = <9 IRQ_TYPE_EDGE_RISING>; /* INT1 */
+ interrupts = <6 IRQ_TYPE_EDGE_RISING>, /* DRDY line */
+ <9 IRQ_TYPE_EDGE_RISING>; /* INT1 */
};
lsp001wm@5c {
/* Barometer/pressure sensor */
diff --git a/arch/arm/boot/dts/ste-u300.dts b/arch/arm/boot/dts/ste-u300.dts
index 82a661677e97..9c73ac2842ad 100644
--- a/arch/arm/boot/dts/ste-u300.dts
+++ b/arch/arm/boot/dts/ste-u300.dts
@@ -315,21 +315,17 @@
ab3100-regulators {
compatible = "stericsson,ab3100-regulators";
ab3100_ldo_a_reg: ab3100_ldo_a {
- regulator-compatible = "ab3100_ldo_a";
startup-delay-us = <200>;
regulator-always-on;
regulator-boot-on;
};
ab3100_ldo_c_reg: ab3100_ldo_c {
- regulator-compatible = "ab3100_ldo_c";
startup-delay-us = <200>;
};
ab3100_ldo_d_reg: ab3100_ldo_d {
- regulator-compatible = "ab3100_ldo_d";
startup-delay-us = <200>;
};
ab3100_ldo_e_reg: ab3100_ldo_e {
- regulator-compatible = "ab3100_ldo_e";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
startup-delay-us = <200>;
@@ -337,7 +333,6 @@
regulator-boot-on;
};
ab3100_ldo_f_reg: ab3100_ldo_f {
- regulator-compatible = "ab3100_ldo_f";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <2500000>;
startup-delay-us = <600>;
@@ -345,28 +340,23 @@
regulator-boot-on;
};
ab3100_ldo_g_reg: ab3100_ldo_g {
- regulator-compatible = "ab3100_ldo_g";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <2850000>;
startup-delay-us = <400>;
};
ab3100_ldo_h_reg: ab3100_ldo_h {
- regulator-compatible = "ab3100_ldo_h";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <2750000>;
startup-delay-us = <200>;
};
ab3100_ldo_k_reg: ab3100_ldo_k {
- regulator-compatible = "ab3100_ldo_k";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2750000>;
startup-delay-us = <200>;
};
ab3100_ext_reg: ab3100_ext {
- regulator-compatible = "ab3100_ext";
};
ab3100_buck_reg: ab3100_buck {
- regulator-compatible = "ab3100_buck";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1800000>;
startup-delay-us = <1000>;
diff --git a/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
index 3f0aeb8288cd..ac64781a0a9c 100644
--- a/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
+++ b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
@@ -65,12 +65,22 @@
/*
* TODO:
* 2x cameras via CSI
- * audio
* AXP battery management
* NAND
* OTG
* Touchscreen - gt801_2plus1 @ i2c adapter 2 @ 0x48
*/
+&codec {
+ /* PH15 controls power to external amplifier (ft2012q) */
+ pinctrl-names = "default";
+ pinctrl-0 = <&codec_pa_pin>;
+ allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
&ehci0 {
status = "okay";
@@ -86,15 +96,13 @@
status = "okay";
axp209: pmic@34 {
- compatible = "x-powers,axp209";
reg = <0x34>;
interrupts = <0>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
};
};
+#include "axp209.dtsi"
+
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_a>;
@@ -110,7 +118,7 @@
};
&lradc {
- vref-supply = <&reg_vcc3v0>;
+ vref-supply = <&reg_ldo2>;
status = "okay";
@@ -146,6 +154,40 @@
status = "okay";
};
+&pio {
+ codec_pa_pin: codec_pa_pin@0 {
+ allwinner,pins = "PH15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
&reg_usb1_vbus {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun4i-a10-inet1.dts b/arch/arm/boot/dts/sun4i-a10-inet1.dts
index 487ce63519dc..e09053bf5e1f 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet1.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet1.dts
@@ -47,6 +47,7 @@
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/pwm/pwm.h>
/ {
model = "iNet-1";
@@ -56,11 +57,25 @@
serial0 = &uart0;
};
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_en_pin_inet>;
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
+ };
+
chosen {
stdout-path = "serial0:115200n8";
};
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
@@ -104,6 +119,19 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c2_pins_a>;
status = "okay";
+
+ ft5x: touchscreen@38 {
+ compatible = "edt,edt-ft5406";
+ reg = <0x38>;
+ interrupt-parent = <&pio>;
+ interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&touchscreen_wake_pin>;
+ wake-gpios = <&pio 1 13 GPIO_ACTIVE_HIGH>; /* PB13 */
+ touchscreen-size-x = <600>;
+ touchscreen-size-y = <1024>;
+ touchscreen-swapped-x-y;
+ };
};
&lradc {
@@ -151,6 +179,20 @@
};
&pio {
+ bl_en_pin_inet: bl_en_pin@0 {
+ allwinner,pins = "PH7";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ touchscreen_wake_pin: touchscreen_wake_pin@0 {
+ allwinner,pins = "PB13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
usb0_id_detect_pin: usb0_id_detect_pin@0 {
allwinner,pins = "PH4";
allwinner,function = "gpio_in";
@@ -166,6 +208,12 @@
};
};
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>;
+ status = "okay";
+};
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
diff --git a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
index 2fffc0434075..ca49b0d0ce1e 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
@@ -59,6 +59,159 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ gpio_keys {
+ compatible = "gpio-keys-polled";
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_pins_inet9f>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+
+ button@0 {
+ label = "Left Joystick Left";
+ linux,code = <ABS_X>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <0xffffffff>; /* -1 */
+ gpios = <&pio 0 6 GPIO_ACTIVE_LOW>; /* PA6 */
+ };
+
+ button@1 {
+ label = "Left Joystick Right";
+ linux,code = <ABS_X>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <1>;
+ gpios = <&pio 0 5 GPIO_ACTIVE_LOW>; /* PA5 */
+ };
+
+ button@2 {
+ label = "Left Joystick Up";
+ linux,code = <ABS_Y>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <0xffffffff>; /* -1 */
+ gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
+ };
+
+ button@3 {
+ label = "Left Joystick Down";
+ linux,code = <ABS_Y>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <1>;
+ gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
+ };
+
+ button@4 {
+ label = "Right Joystick Left";
+ linux,code = <ABS_Z>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <0xffffffff>; /* -1 */
+ gpios = <&pio 0 1 GPIO_ACTIVE_LOW>; /* PA1 */
+ };
+
+ button@5 {
+ label = "Right Joystick Right";
+ linux,code = <ABS_Z>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <1>;
+ gpios = <&pio 0 0 GPIO_ACTIVE_LOW>; /* PA0 */
+ };
+
+ button@6 {
+ label = "Right Joystick Up";
+ linux,code = <ABS_RZ>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <0xffffffff>; /* -1 */
+ gpios = <&pio 0 3 GPIO_ACTIVE_LOW>; /* PA3 */
+ };
+
+ button@7 {
+ label = "Right Joystick Down";
+ linux,code = <ABS_RZ>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <1>;
+ gpios = <&pio 0 4 GPIO_ACTIVE_LOW>; /* PA4 */
+ };
+
+ button@8 {
+ label = "DPad Left";
+ linux,code = <ABS_HAT0X>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <0xffffffff>; /* -1 */
+ gpios = <&pio 7 23 GPIO_ACTIVE_LOW>; /* PH23 */
+ };
+
+ button@9 {
+ label = "DPad Right";
+ linux,code = <ABS_HAT0X>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <1>;
+ gpios = <&pio 7 24 GPIO_ACTIVE_LOW>; /* PH24 */
+ };
+
+ button@10 {
+ label = "DPad Up";
+ linux,code = <ABS_HAT0Y>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <0xffffffff>; /* -1 */
+ gpios = <&pio 7 25 GPIO_ACTIVE_LOW>; /* PH25 */
+ };
+
+ button@11 {
+ label = "DPad Down";
+ linux,code = <ABS_HAT0Y>;
+ linux,input-type = <EV_ABS>;
+ linux,input-value = <1>;
+ gpios = <&pio 7 26 GPIO_ACTIVE_LOW>; /* PH26 */
+ };
+
+ button@12 {
+ label = "Button X";
+ linux,code = <BTN_X>;
+ gpios = <&pio 0 16 GPIO_ACTIVE_LOW>; /* PA16 */
+ };
+
+ button@13 {
+ label = "Button Y";
+ linux,code = <BTN_Y>;
+ gpios = <&pio 0 14 GPIO_ACTIVE_LOW>; /* PA14 */
+ };
+
+ button@14 {
+ label = "Button A";
+ linux,code = <BTN_A>;
+ gpios = <&pio 0 17 GPIO_ACTIVE_LOW>; /* PA17 */
+ };
+
+ button@15 {
+ label = "Button B";
+ linux,code = <BTN_B>;
+ gpios = <&pio 0 15 GPIO_ACTIVE_LOW>; /* PA15 */
+ };
+
+ button@16 {
+ label = "Select Button";
+ linux,code = <BTN_SELECT>;
+ gpios = <&pio 0 11 GPIO_ACTIVE_LOW>; /* PA11 */
+ };
+
+ button@17 {
+ label = "Start Button";
+ linux,code = <BTN_START>;
+ gpios = <&pio 0 12 GPIO_ACTIVE_LOW>; /* PA12 */
+ };
+
+ button@18 {
+ label = "Top Left Button";
+ linux,code = <BTN_TL>;
+ gpios = <&pio 7 22 GPIO_ACTIVE_LOW>; /* PH22 */
+ };
+
+ button@19 {
+ label = "Top Right Button";
+ linux,code = <BTN_TR>;
+ gpios = <&pio 0 13 GPIO_ACTIVE_LOW>; /* PA13 */
+ };
+ };
};
&cpu0 {
@@ -157,6 +310,17 @@
};
&pio {
+ key_pins_inet9f: key_pins@0 {
+ allwinner,pins = "PA0", "PA1", "PA3", "PA4",
+ "PA5", "PA6", "PA8", "PA9",
+ "PA11", "PA12", "PA13",
+ "PA14", "PA15", "PA16", "PA17",
+ "PH22", "PH23", "PH24", "PH25", "PH26";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
usb0_id_detect_pin: usb0_id_detect_pin@0 {
allwinner,pins = "PH4";
allwinner,function = "gpio_in";
diff --git a/arch/arm/boot/dts/sun4i-a10-mk802.dts b/arch/arm/boot/dts/sun4i-a10-mk802.dts
index 3c7eebe17088..ddf0683cbc6a 100644
--- a/arch/arm/boot/dts/sun4i-a10-mk802.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mk802.dts
@@ -58,6 +58,10 @@
};
};
+&codec {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
index 82e69c3820a2..918f97294b33 100644
--- a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
@@ -47,6 +47,7 @@
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/pwm/pwm.h>
/ {
model = "Point of View Protab2-IPS9";
@@ -56,11 +57,28 @@
serial0 = &uart0;
};
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_en_pin_protab>;
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
+ };
+
chosen {
stdout-path = "serial0:115200n8";
};
};
+&codec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&codec_pa_pin>;
+ allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
@@ -93,6 +111,22 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c2_pins_a>;
status = "okay";
+
+ pixcir_ts@5c {
+ pinctrl-names = "default";
+ pinctrl-0 = <&touchscreen_pins>;
+ compatible = "pixcir,pixcir_tangoc";
+ reg = <0x5c>;
+ interrupt-parent = <&pio>;
+ interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>; /* EINT21 (PH21) */
+ attb-gpio = <&pio 7 21 GPIO_ACTIVE_HIGH>; /* PH21 */
+ enable-gpios = <&pio 0 5 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&pio 1 13 GPIO_ACTIVE_LOW>;
+ touchscreen-size-x = <1024>;
+ touchscreen-size-y = <768>;
+ touchscreen-inverted-x;
+ touchscreen-inverted-y;
+ };
};
&lradc {
@@ -129,6 +163,27 @@
};
&pio {
+ bl_en_pin_protab: bl_en_pin@0 {
+ allwinner,pins = "PH7";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ codec_pa_pin: codec_pa_pin@0 {
+ allwinner,pins = "PH15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ touchscreen_pins: touchscreen_pins@0 {
+ allwinner,pins = "PA5", "PB13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
usb0_id_detect_pin: usb0_id_detect_pin@0 {
allwinner,pins = "PH4";
allwinner,function = "gpio_in";
@@ -144,6 +199,12 @@
};
};
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>;
+ status = "okay";
+};
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index aa90f319309b..2c8f5e6ad905 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -66,7 +66,7 @@
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
- <&ahb_gates 44>;
+ <&ahb_gates 44>, <&dram_gates 26>;
status = "disabled";
};
@@ -75,7 +75,8 @@
"simple-framebuffer";
allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
- <&ahb_gates 44>, <&ahb_gates 46>;
+ <&ahb_gates 44>, <&ahb_gates 46>,
+ <&dram_gates 25>, <&dram_gates 26>;
status = "disabled";
};
@@ -84,7 +85,8 @@
"simple-framebuffer";
allwinner,pipeline = "de_fe0-de_be0-lcd0";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
- <&ahb_gates 46>;
+ <&ahb_gates 46>, <&dram_gates 25>,
+ <&dram_gates 26>;
status = "disabled";
};
@@ -93,7 +95,8 @@
"simple-framebuffer";
allwinner,pipeline = "de_fe0-de_be0-lcd0-tve0";
clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
- <&ahb_gates 44>, <&ahb_gates 46>;
+ <&ahb_gates 44>, <&ahb_gates 46>,
+ <&dram_gates 25>, <&dram_gates 26>;
status = "disabled";
};
};
@@ -492,6 +495,40 @@
clock-output-names = "spi3";
};
+ dram_gates: clk@01c20100 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-dram-gates-clk";
+ reg = <0x01c20100 0x4>;
+ clocks = <&pll5 0>;
+ clock-indices = <0>,
+ <1>, <2>,
+ <3>,
+ <4>,
+ <5>, <6>,
+ <15>,
+ <24>, <25>,
+ <26>, <27>,
+ <28>, <29>;
+ clock-output-names = "dram_ve",
+ "dram_csi0", "dram_csi1",
+ "dram_ts",
+ "dram_tvd",
+ "dram_tve0", "dram_tve1",
+ "dram_output",
+ "dram_de_fe1", "dram_de_fe0",
+ "dram_de_be0", "dram_de_be1",
+ "dram_de_mp", "dram_ace";
+ };
+
+ ve_clk: clk@01c2013c {
+ #clock-cells = <0>;
+ #reset-cells = <0>;
+ compatible = "allwinner,sun4i-a10-ve-clk";
+ reg = <0x01c2013c 0x4>;
+ clocks = <&pll4>;
+ clock-output-names = "ve";
+ };
+
codec_clk: clk@01c20140 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-codec-clk";
diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
index 2b3511ea2e5d..a790ec8adb75 100644
--- a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
@@ -86,6 +86,20 @@
status = "okay";
};
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp152: pmic@30 {
+ compatible = "x-powers,axp152";
+ reg = <0x30>;
+ interrupts = <0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_t004>;
diff --git a/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts b/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts
new file mode 100644
index 000000000000..7fbb0b0558a9
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-a13.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "Empire Electronix D709 tablet";
+ compatible = "empire-electronix,d709", "allwinner,sun5i-a13";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ /* TODO: backlight uses axp gpio1 as enable pin */
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ pcf8563: rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@400 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <400000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_inet98fv2>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+
+ mmccard: mmccard@0 {
+ reg = <0>;
+ compatible = "mmc-card";
+ broken-hpi;
+ };
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_inet98fv2: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PG2";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins>;
+ status = "okay";
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-pll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_ldo3 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&reg_usb0_vbus {
+ gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb0_vbus_pin_a {
+ allwinner,pins = "PG12";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+ usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_ldo3>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts
index eb793d5a2bd6..fa9ddfdcfe96 100644
--- a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts
+++ b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts
@@ -47,11 +47,21 @@
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/pwm/pwm.h>
/ {
model = "Utoo P66";
compatible = "utoo,p66", "allwinner,sun5i-a13";
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ /* Note levels of 10 / 20% result in backlight off */
+ brightness-levels = <0 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <6>;
+ /* TODO: backlight uses axp gpio1 as enable pin */
+ };
+
i2c_lcd: i2c@0 {
/* The lcd panel i2c interface is hooked up via gpios */
compatible = "i2c-gpio";
@@ -63,6 +73,13 @@
};
};
+&codec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&codec_pa_pin>;
+ allwinner,pa-gpios = <&pio 6 3 GPIO_ACTIVE_HIGH>; /* PG3 */
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
@@ -158,6 +175,13 @@
};
&pio {
+ codec_pa_pin: codec_pa_pin@0 {
+ allwinner,pins = "PG3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc0_cd_pin_p66: mmc0_cd_pin@0 {
allwinner,pins = "PG0";
allwinner,function = "gpio_in";
@@ -201,6 +225,12 @@
};
};
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins>;
+ status = "okay";
+};
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
index b199020733d3..360adfb1e9ca 100644
--- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -113,18 +113,83 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
-&reg_usb1_vbus {
- gpio = <&pio 7 27 GPIO_ACTIVE_HIGH>;
+&p2wi {
status = "okay";
+
+ axp22x: pmic@68 {
+ compatible = "x-powers,axp221";
+ reg = <0x68>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
};
-&usb1_vbus_pin_a {
- allwinner,pins = "PH27";
+#include "axp22x.dtsi"
+
+&reg_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
};
-&usbphy {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
+&reg_dc1sw {
+ regulator-name = "vcc-lcd-usb2";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+};
+
+&reg_dc5ldo {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpus";
+};
+
+&reg_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc4 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-sys-dll";
+};
+
+&reg_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+&reg_dldo1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+/* Voltage source for I2C pullup resistors for I2C Bus 0 */
+&reg_dldo3 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-name = "vddio-csi";
};
&uart0 {
@@ -132,3 +197,9 @@
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_dldo1>;
+ usb2_vbus-supply = <&reg_dc1sw>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index fd7594ff90d5..67c8a7644b99 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -92,6 +92,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
operating-points = <
diff --git a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts
new file mode 100644
index 000000000000..f5b5325a70e2
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2015 Stefan Roese <sr@denx.de>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "ICnova-A20 SWAC";
+ compatible = "swac,icnova-a20-swac", "incircuit,icnova-a20", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 8 5 GPIO_ACTIVE_HIGH>; /* PI5 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-mk808c.dts b/arch/arm/boot/dts/sun7i-a20-mk808c.dts
index 4f432f8ade77..c9e648d17a1e 100644
--- a/arch/arm/boot/dts/sun7i-a20-mk808c.dts
+++ b/arch/arm/boot/dts/sun7i-a20-mk808c.dts
@@ -68,6 +68,10 @@
};
};
+&codec {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
index b7fe102475e7..c3c626b2cfa2 100644
--- a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
@@ -1,5 +1,6 @@
/*
* Copyright 2015 - Marcus Cooper <codekipper@gmail.com>
+ * Copyright 2015 - Karsten Merker <merker@debian.org>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,6 +46,7 @@
#include "sunxi-common-regulators.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
@@ -86,6 +88,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&gmac {
pinctrl-names = "default";
pinctrl-0 = <&gmac_pins_rgmii_a>;
@@ -110,6 +116,60 @@
};
};
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@190 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <190000>;
+ };
+
+ button@390 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <390000>;
+ };
+
+ button@600 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+
+ button@800 {
+ label = "Search";
+ linux,code = <KEY_SEARCH>;
+ channel = <0>;
+ voltage = <800000>;
+ };
+
+ button@980 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <980000>;
+ };
+
+ button@1180 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1180000>;
+ };
+
+ button@1400 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <1400000>;
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
@@ -120,6 +180,16 @@
status = "okay";
};
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olimex_som_evb>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 0 GPIO_ACTIVE_HIGH>; /* PH0 */
+ cd-inverted;
+ status = "okay";
+};
+
&ohci0 {
status = "okay";
};
@@ -142,6 +212,13 @@
allwinner,drive = <SUN4I_PINCTRL_20_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ mmc3_cd_pin_olimex_som_evb: mmc3_cd_pin@0 {
+ allwinner,pins = "PH0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
};
&reg_ahci_5v {
diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
index 4f65664e5dfe..2be04c438b1e 100644
--- a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
@@ -95,6 +95,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
index 1757a6ad74e9..ddac7328b852 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
@@ -82,6 +82,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
index 861a4a66fb19..1a8b39be1d61 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -111,6 +111,10 @@
allwinner,pins = "PH2";
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
diff --git a/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
index 78239ad988e7..2f6b21adddd9 100644
--- a/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
+++ b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
@@ -48,6 +48,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
/ {
model = "Wexler TAB7200";
@@ -57,11 +58,28 @@
serial0 = &uart0;
};
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_enable_pin>;
+ enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
+ };
+
chosen {
stdout-path = "serial0:115200n8";
};
};
+&codec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&codec_pa_pin>;
+ allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
@@ -98,6 +116,18 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c2_pins_a>;
status = "okay";
+
+ gt911: touchscreen@5d {
+ compatible = "goodix,gt911";
+ reg = <0x5d>;
+ interrupt-parent = <&pio>;
+ interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>; /* EINT21 (PH21) */
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_reset_pin>;
+ irq-gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>; /* INT (PH21) */
+ reset-gpios = <&pio 1 13 GPIO_ACTIVE_HIGH>; /* RST (PB13) */
+ touchscreen-swapped-x-y;
+ };
};
&lradc {
@@ -142,6 +172,27 @@
};
&pio {
+ bl_enable_pin: bl_enable_pin@0 {
+ allwinner,pins = "PH7";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ codec_pa_pin: codec_pa_pin@0 {
+ allwinner,pins = "PH15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ts_reset_pin: ts_reset_pin@0 {
+ allwinner,pins = "PB13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
usb0_id_detect_pin: usb0_id_detect_pin@0 {
allwinner,pins = "PH4";
allwinner,function = "gpio_in";
@@ -150,6 +201,12 @@
};
};
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>;
+ status = "okay";
+};
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
diff --git a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
index 85b500d8cc4c..dc31d476ef81 100644
--- a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
+++ b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
@@ -80,6 +80,18 @@
status = "okay";
};
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
&i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index e02eb720c4fc..0940a788f824 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -68,7 +68,7 @@
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
- <&ahb_gates 44>;
+ <&ahb_gates 44>, <&dram_gates 26>;
status = "disabled";
};
@@ -76,7 +76,8 @@
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
- clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+ clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
+ <&dram_gates 26>;
status = "disabled";
};
@@ -85,7 +86,7 @@
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-tve0";
clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
- <&ahb_gates 44>;
+ <&ahb_gates 44>, <&dram_gates 26>;
status = "disabled";
};
};
@@ -501,6 +502,40 @@
clock-output-names = "spi3";
};
+ dram_gates: clk@01c20100 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-dram-gates-clk";
+ reg = <0x01c20100 0x4>;
+ clocks = <&pll5 0>;
+ clock-indices = <0>,
+ <1>, <2>,
+ <3>,
+ <4>,
+ <5>, <6>,
+ <15>,
+ <24>, <25>,
+ <26>, <27>,
+ <28>, <29>;
+ clock-output-names = "dram_ve",
+ "dram_csi0", "dram_csi1",
+ "dram_ts",
+ "dram_tvd",
+ "dram_tve0", "dram_tve1",
+ "dram_output",
+ "dram_de_fe1", "dram_de_fe0",
+ "dram_de_be0", "dram_de_be1",
+ "dram_de_mp", "dram_ace";
+ };
+
+ ve_clk: clk@01c2013c {
+ #clock-cells = <0>;
+ #reset-cells = <0>;
+ compatible = "allwinner,sun4i-a10-ve-clk";
+ reg = <0x01c2013c 0x4>;
+ clocks = <&pll4>;
+ clock-output-names = "ve";
+ };
+
codec_clk: clk@01c20140 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-codec-clk";
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index 0c0964d4fa1f..6f88fb0ddbc7 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -56,7 +56,7 @@
#size-cells = <1>;
ranges;
- framebuffer@0 {
+ simplefb_lcd: framebuffer@0 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
new file mode 100644
index 000000000000..e67df590535f
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Xunlong Orange Pi Plus";
+ compatible = "xunlong,orangepi-plus", "allwinner,sun8i-h3";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+ cd-inverted;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
new file mode 100644
index 000000000000..1524130e43c9
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "skeleton.dtsi"
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <1>;
+ };
+
+ cpu@2 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <2>;
+ };
+
+ cpu@3 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <3>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ osc24M: osc24M_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc32k: osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+ };
+
+ /* dummy clock until actually implemented */
+ pll5: pll5_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ clock-output-names = "pll5";
+ };
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun6i-a31-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6", "pll6x2";
+ };
+
+ pll6d2: pll6d2_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <2>;
+ clock-mult = <1>;
+ clocks = <&pll6 0>;
+ clock-output-names = "pll6d2";
+ };
+
+ /* dummy clock until pll6 can be reused */
+ pll8: pll8_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <1>;
+ clock-output-names = "pll8";
+ };
+
+ cpu: cpu_clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
+ clock-output-names = "cpu";
+ };
+
+ axi: axi_clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+ };
+
+ ahb1: ahb1_clk@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-ahb1-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
+ clock-output-names = "ahb1";
+ };
+
+ ahb2: ahb2_clk@01c2005c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ahb2-clk";
+ reg = <0x01c2005c 0x4>;
+ clocks = <&ahb1>, <&pll6d2>;
+ clock-output-names = "ahb2";
+ };
+
+ apb1: apb1_clk@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1>;
+ clock-output-names = "apb1";
+ };
+
+ apb2: apb2_clk@01c20058 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
+ clock-output-names = "apb2";
+ };
+
+ bus_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-h3-bus-gates-clk";
+ reg = <0x01c20060 0x14>;
+ clocks = <&ahb1>, <&ahb2>, <&apb1>, <&apb2>;
+ clock-names = "ahb1", "ahb2", "apb1", "apb2";
+ clock-indices = <5>, <6>, <8>,
+ <9>, <10>, <13>,
+ <14>, <17>, <18>,
+ <19>, <20>,
+ <21>, <23>,
+ <24>, <25>,
+ <26>, <27>,
+ <28>, <29>,
+ <30>, <31>, <32>,
+ <35>, <36>, <37>,
+ <40>, <41>, <43>,
+ <44>, <52>, <53>,
+ <54>, <64>,
+ <65>, <69>, <72>,
+ <76>, <77>, <78>,
+ <96>, <97>, <98>,
+ <112>, <113>,
+ <114>, <115>,
+ <116>, <128>, <135>;
+ clock-output-names = "bus_ce", "bus_dma", "bus_mmc0",
+ "bus_mmc1", "bus_mmc2", "bus_nand",
+ "bus_sdram", "bus_gmac", "bus_ts",
+ "bus_hstimer", "bus_spi0",
+ "bus_spi1", "bus_otg",
+ "bus_otg_ehci0", "bus_ehci1",
+ "bus_ehci2", "bus_ehci3",
+ "bus_otg_ohci0", "bus_ohci1",
+ "bus_ohci2", "bus_ohci3", "bus_ve",
+ "bus_lcd0", "bus_lcd1", "bus_deint",
+ "bus_csi", "bus_tve", "bus_hdmi",
+ "bus_de", "bus_gpu", "bus_msgbox",
+ "bus_spinlock", "bus_codec",
+ "bus_spdif", "bus_pio", "bus_ths",
+ "bus_i2s0", "bus_i2s1", "bus_i2s2",
+ "bus_i2c0", "bus_i2c1", "bus_i2c2",
+ "bus_uart0", "bus_uart1",
+ "bus_uart2", "bus_uart3",
+ "bus_scr", "bus_ephy", "bus_dbg";
+ };
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 0>, <&pll8>;
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
+ };
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6 0>, <&pll8>;
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
+ };
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6 0>, <&pll8>;
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
+ };
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-mbus-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5>;
+ clock-output-names = "mbus";
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun8i-h3-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bus_gates 6>;
+ resets = <&ahb_rst 6>;
+ #dma-cells = <1>;
+ };
+
+ mmc0: mmc@01c0f000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c0f000 0x1000>;
+ clocks = <&bus_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ resets = <&ahb_rst 8>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc1: mmc@01c10000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c10000 0x1000>;
+ clocks = <&bus_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ resets = <&ahb_rst 9>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc2: mmc@01c11000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c11000 0x1000>;
+ clocks = <&bus_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ resets = <&ahb_rst 10>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ pio: pinctrl@01c20800 {
+ compatible = "allwinner,sun8i-h3-pinctrl";
+ reg = <0x01c20800 0x400>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bus_gates 69>;
+ gpio-controller;
+ #gpio-cells = <3>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PA4", "PA5";
+ allwinner,function = "uart0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_pins_a: mmc0@0 {
+ allwinner,pins = "PF0", "PF1", "PF2", "PF3",
+ "PF4", "PF5";
+ allwinner,function = "mmc0";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin: mmc0_cd_pin@0 {
+ allwinner,pins = "PF6";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ mmc1_pins_a: mmc1@0 {
+ allwinner,pins = "PG0", "PG1", "PG2", "PG3",
+ "PG4", "PG5";
+ allwinner,function = "mmc1";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+ };
+
+ ahb_rst: reset@01c202c0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-ahb1-reset";
+ reg = <0x01c202c0 0xc>;
+ };
+
+ apb1_rst: reset@01c202d0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x01c202d0 0x4>;
+ };
+
+ apb2_rst: reset@01c202d8 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x01c202d8 0x4>;
+ };
+
+ timer@01c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0xa0>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
+ };
+
+ wdt0: watchdog@01c20ca0 {
+ compatible = "allwinner,sun6i-a31-wdt";
+ reg = <0x01c20ca0 0x20>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ uart0: serial@01c28000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28000 0x400>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&bus_gates 112>;
+ resets = <&apb2_rst 16>;
+ dmas = <&dma 6>, <&dma 6>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart1: serial@01c28400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28400 0x400>;
+ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&bus_gates 113>;
+ resets = <&apb2_rst 17>;
+ dmas = <&dma 7>, <&dma 7>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart2: serial@01c28800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28800 0x400>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&bus_gates 114>;
+ resets = <&apb2_rst 18>;
+ dmas = <&dma 8>, <&dma 8>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart3: serial@01c28c00 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28c00 0x400>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&bus_gates 115>;
+ resets = <&apb2_rst 19>;
+ dmas = <&dma 9>, <&dma 9>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ gic: interrupt-controller@01c81000 {
+ compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+ reg = <0x01c81000 0x1000>,
+ <0x01c82000 0x1000>,
+ <0x01c84000 0x2000>,
+ <0x01c86000 0x2000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ rtc: rtc@01f00000 {
+ compatible = "allwinner,sun6i-a31-rtc";
+ reg = <0x01f00000 0x54>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
index 6484dcf69873..382bd9fc5647 100644
--- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -62,9 +62,31 @@
stdout-path = "serial0:115200n8";
};
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_cubieboard4>;
+
+ green {
+ label = "cubieboard4:green:usr";
+ gpios = <&pio 7 17 GPIO_ACTIVE_HIGH>; /* PH17 */
+ };
+
+ red {
+ label = "cubieboard4:red:usr";
+ gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
+ };
+ };
};
&pio {
+ led_pins_cubieboard4: led-pins@0 {
+ allwinner,pins = "PH6", "PH17";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc0_cd_pin_cubieboard4: mmc0_cd_pin@0 {
allwinner,pins = "PH18";
allwinner,function = "gpio_in";
@@ -92,6 +114,14 @@
status = "okay";
};
+&r_ir {
+ status = "okay";
+};
+
+&r_rsb {
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 6ce4b5e8b615..c0060e4f7379 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -65,7 +65,7 @@
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
- pinctrl-0 = <&led_pins_optimus>;
+ pinctrl-0 = <&led_pins_optimus>, <&led_r_pins_optimus>;
/* The LED names match those found on the board */
@@ -74,7 +74,10 @@
gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>;
};
- /* led3 is on PM15, in R_PIO */
+ led3 {
+ label = "optimus:led3:usr";
+ gpios = <&r_pio 1 15 GPIO_ACTIVE_HIGH>; /* PM15 */
+ };
led4 {
label = "optimus:led4:usr";
@@ -180,6 +183,23 @@
status = "okay";
};
+&r_ir {
+ status = "okay";
+};
+
+&r_pio {
+ led_r_pins_optimus: led-pins@1 {
+ allwinner,pins = "PM15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&r_rsb {
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 1118bf5cc4fb..e838f206f2a0 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -128,6 +128,17 @@
*/
ranges = <0 0 0 0x20000000>;
+ /*
+ * This clock is actually configurable from the PRCM address
+ * space. The external 24M oscillator can be turned off, and
+ * the clock switched to an internal 16M RC oscillator. Under
+ * normal operation there's no reason to do this, and the
+ * default is to use the external good one, so just model this
+ * as a fixed clock. Also it is not entirely clear if the
+ * osc24M mux in the PRCM affects the entire clock tree, which
+ * would also throw all the PLL clock rates off, or just the
+ * downstream clocks in the PRCM.
+ */
osc24M: osc24M_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -135,6 +146,13 @@
clock-output-names = "osc24M";
};
+ /*
+ * The 32k clock is from an external source, normally the
+ * AC100 codec/RTC chip. This clock is by default enabled
+ * and clocked at 32768 Hz, from the oscillator connected
+ * to the AC100. It is configurable, but no such driver or
+ * bindings exist yet.
+ */
osc32k: osc32k_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -164,6 +182,14 @@
"usb_phy2", "usb_hsic_12M";
};
+ pll3: clk@06000008 {
+ /* placeholder until implemented */
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-rate = <0>;
+ clock-output-names = "pll3";
+ };
+
pll4: clk@0600000c {
#clock-cells = <0>;
compatible = "allwinner,sun9i-a80-pll4-clk";
@@ -350,6 +376,68 @@
"apb1_uart2", "apb1_uart3",
"apb1_uart4", "apb1_uart5";
};
+
+ cpus_clk: clk@08001410 {
+ compatible = "allwinner,sun9i-a80-cpus-clk";
+ reg = <0x08001410 0x4>;
+ #clock-cells = <0>;
+ clocks = <&osc32k>, <&osc24M>, <&pll4>, <&pll3>;
+ clock-output-names = "cpus";
+ };
+
+ ahbs: ahbs_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&cpus_clk>;
+ clock-output-names = "ahbs";
+ };
+
+ apbs: clk@0800141c {
+ compatible = "allwinner,sun8i-a23-apb0-clk";
+ reg = <0x0800141c 0x4>;
+ #clock-cells = <0>;
+ clocks = <&ahbs>;
+ clock-output-names = "apbs";
+ };
+
+ apbs_gates: clk@08001428 {
+ compatible = "allwinner,sun9i-a80-apbs-gates-clk";
+ reg = <0x08001428 0x4>;
+ #clock-cells = <1>;
+ clocks = <&apbs>;
+ clock-indices = <0>, <1>,
+ <2>, <3>,
+ <4>, <5>,
+ <6>, <7>,
+ <12>, <13>,
+ <16>, <17>,
+ <18>, <20>;
+ clock-output-names = "apbs_pio", "apbs_ir",
+ "apbs_timer", "apbs_rsb",
+ "apbs_uart", "apbs_1wire",
+ "apbs_i2c0", "apbs_i2c1",
+ "apbs_ps2_0", "apbs_ps2_1",
+ "apbs_dma", "apbs_i2s0",
+ "apbs_i2s1", "apbs_twd";
+ };
+
+ r_1wire_clk: clk@08001450 {
+ reg = <0x08001450 0x4>;
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ clocks = <&osc32k>, <&osc24M>;
+ clock-output-names = "r_1wire";
+ };
+
+ r_ir_clk: clk@08001454 {
+ reg = <0x08001454 0x4>;
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ clocks = <&osc32k>, <&osc24M>;
+ clock-output-names = "r_ir";
+ };
};
soc {
@@ -764,14 +852,83 @@
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
};
+ apbs_rst: reset@080014b0 {
+ reg = <0x080014b0 0x4>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ #reset-cells = <1>;
+ };
+
+ nmi_intc: interrupt-controller@080015a0 {
+ compatible = "allwinner,sun9i-a80-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x080015a0 0xc>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ r_ir: ir@08002000 {
+ compatible = "allwinner,sun5i-a13-ir";
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_pins>;
+ clocks = <&apbs_gates 1>, <&r_ir_clk>;
+ clock-names = "apb", "ir";
+ resets = <&apbs_rst 1>;
+ reg = <0x08002000 0x40>;
+ status = "disabled";
+ };
+
r_uart: serial@08002800 {
compatible = "snps,dw-apb-uart";
reg = <0x08002800 0x400>;
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&osc24M>;
+ clocks = <&apbs_gates 4>;
+ resets = <&apbs_rst 4>;
+ status = "disabled";
+ };
+
+ r_pio: pinctrl@08002c00 {
+ compatible = "allwinner,sun9i-a80-r-pinctrl";
+ reg = <0x08002c00 0x400>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apbs_gates 0>;
+ resets = <&apbs_rst 0>;
+ gpio-controller;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ r_ir_pins: r_ir {
+ allwinner,pins = "PL6";
+ allwinner,function = "s_cir_rx";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ r_rsb_pins: r_rsb {
+ allwinner,pins = "PN0", "PN1";
+ allwinner,function = "s_rsb";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+ };
+
+ r_rsb: i2c@08003400 {
+ compatible = "allwinner,sun8i-a23-rsb";
+ reg = <0x08003400 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apbs_gates 3>;
+ clock-frequency = <3000000>;
+ resets = <&apbs_rst 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_rsb_pins>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
};
};
diff --git a/arch/arm/boot/dts/tango4-common.dtsi b/arch/arm/boot/dts/tango4-common.dtsi
new file mode 100644
index 000000000000..ef665d21d317
--- /dev/null
+++ b/arch/arm/boot/dts/tango4-common.dtsi
@@ -0,0 +1,130 @@
+/*
+ * Based on Mans Rullgard's Tango3 DT
+ * https://github.com/mansr/linux-tangox
+ */
+
+#define CPU_CLK 0
+#define SYS_CLK 1
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ periph_clk: periph_clk {
+ compatible = "fixed-factor-clock";
+ clocks = <&clkgen CPU_CLK>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ #clock-cells = <0>;
+ };
+
+ mpcore {
+ compatible = "simple-bus";
+ ranges = <0x00000000 0x20000000 0x2000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ scu@0 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0x0 0x100>;
+ };
+
+ twd@600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x600 0x10>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&periph_clk>;
+ always-on;
+ };
+
+ gic: interrupt-controller@1000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x1000 0x1000>, <0x100 0x100>;
+ };
+ };
+
+ l2cc: l2-cache-controller@20100000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x20100000 0x1000>;
+ cache-level = <2>;
+ cache-unified;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ interrupt-parent = <&irq0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ xtal: xtal {
+ compatible = "fixed-clock";
+ clock-frequency = <27000000>;
+ #clock-cells = <0>;
+ };
+
+ clkgen: clkgen@10000 {
+ compatible = "sigma,tango4-clkgen";
+ reg = <0x10000 0x40>;
+ clocks = <&xtal>;
+ #clock-cells = <1>;
+ };
+
+ tick-counter@10048 {
+ compatible = "sigma,tick-counter";
+ reg = <0x10048 0x4>;
+ clocks = <&xtal>;
+ };
+
+ uart: serial@10700 {
+ compatible = "ralink,rt2880-uart";
+ reg = <0x10700 0x30>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <7372800>;
+ reg-shift = <2>;
+ };
+
+ eth0: ethernet@26000 {
+ compatible = "sigma,smp8734-ethernet";
+ reg = <0x26000 0x800>;
+ interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkgen SYS_CLK>;
+ };
+
+ intc: interrupt-controller@6e000 {
+ compatible = "sigma,smp8642-intc";
+ reg = <0x6e000 0x400>;
+ ranges = <0 0x6e000 0x400>;
+ interrupt-parent = <&gic>;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ irq0: irq0@000 {
+ reg = <0x000 0x100>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ irq1: irq1@100 {
+ reg = <0x100 0x100>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ irq2: irq2@300 {
+ reg = <0x300 0x100>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/tango4-smp8758.dtsi b/arch/arm/boot/dts/tango4-smp8758.dtsi
new file mode 100644
index 000000000000..7ed88ee629fb
--- /dev/null
+++ b/arch/arm/boot/dts/tango4-smp8758.dtsi
@@ -0,0 +1,31 @@
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "sigma,tango4-smp";
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&l2cc>;
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&l2cc>;
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupt-affinity = <&cpu0>, <&cpu1>;
+ interrupts =
+ <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
diff --git a/arch/arm/boot/dts/tango4-vantage-1172.dts b/arch/arm/boot/dts/tango4-vantage-1172.dts
new file mode 100644
index 000000000000..3e5b9c81a51c
--- /dev/null
+++ b/arch/arm/boot/dts/tango4-vantage-1172.dts
@@ -0,0 +1,37 @@
+/dts-v1/;
+
+#include "tango4-smp8758.dtsi"
+#include "tango4-common.dtsi"
+
+/ {
+ model = "Sigma Designs SMP8758 Vantage-1172 Rev E1";
+ compatible = "sigma,vantage-1172", "sigma,smp8758", "sigma,tango4";
+
+ aliases {
+ serial = &uart;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x80000000>; /* 2 GB */
+ };
+
+ chosen {
+ stdout-path = "serial:115200n8";
+ };
+};
+
+&eth0 {
+ phy-connection-type = "rgmii";
+ phy-handle = <&eth0_phy>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Atheros AR8035 */
+ eth0_phy: ethernet-phy@4 {
+ compatible = "ethernet-phy-id004d.d072",
+ "ethernet-phy-ieee802.3-c22";
+ interrupts = <37 IRQ_TYPE_EDGE_RISING>;
+ reg = <4>;
+ };
+};
diff --git a/arch/arm/boot/dts/tps65217.dtsi b/arch/arm/boot/dts/tps65217.dtsi
deleted file mode 100644
index a63272422d76..000000000000
--- a/arch/arm/boot/dts/tps65217.dtsi
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.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.
- */
-
-/*
- * Integrated Power Management Chip
- * http://www.ti.com/lit/ds/symlink/tps65217.pdf
- */
-
-&tps {
- compatible = "ti,tps65217";
-
- regulators {
- #address-cells = <1>;
- #size-cells = <0>;
-
- dcdc1_reg: regulator@0 {
- reg = <0>;
- regulator-compatible = "dcdc1";
- };
-
- dcdc2_reg: regulator@1 {
- reg = <1>;
- regulator-compatible = "dcdc2";
- };
-
- dcdc3_reg: regulator@2 {
- reg = <2>;
- regulator-compatible = "dcdc3";
- };
-
- ldo1_reg: regulator@3 {
- reg = <3>;
- regulator-compatible = "ldo1";
- };
-
- ldo2_reg: regulator@4 {
- reg = <4>;
- regulator-compatible = "ldo2";
- };
-
- ldo3_reg: regulator@5 {
- reg = <5>;
- regulator-compatible = "ldo3";
- };
-
- ldo4_reg: regulator@6 {
- reg = <6>;
- regulator-compatible = "ldo4";
- };
- };
-};
diff --git a/arch/arm/boot/dts/twl4030_omap3.dtsi b/arch/arm/boot/dts/twl4030_omap3.dtsi
index 3537ae5b2146..5288e6dffef7 100644
--- a/arch/arm/boot/dts/twl4030_omap3.dtsi
+++ b/arch/arm/boot/dts/twl4030_omap3.dtsi
@@ -19,7 +19,7 @@
*/
twl4030_pins: pinmux_twl4030_pins {
pinctrl-single,pins = <
- 0x1b0 (PIN_INPUT_PULLUP | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* sys_nirq.sys_nirq */
+ OMAP3_CORE1_IOPAD(0x21e0, PIN_INPUT_PULLUP | PIN_OFF_WAKEUPENABLE | MUX_MODE0) /* sys_nirq.sys_nirq */
>;
};
};
diff --git a/arch/arm/boot/dts/twl6030_omap4.dtsi b/arch/arm/boot/dts/twl6030_omap4.dtsi
index a4fa5703c42b..e373f59cea9c 100644
--- a/arch/arm/boot/dts/twl6030_omap4.dtsi
+++ b/arch/arm/boot/dts/twl6030_omap4.dtsi
@@ -24,7 +24,7 @@
&omap4_pmx_wkup {
twl6030_wkup_pins: pinmux_twl6030_wkup_pins {
pinctrl-single,pins = <
- 0x14 (PIN_OUTPUT | MUX_MODE2) /* fref_clk0_out.sys_drm_msecure */
+ OMAP4_IOPAD(0x054, PIN_OUTPUT | MUX_MODE2) /* fref_clk0_out.sys_drm_msecure */
>;
};
};
@@ -32,7 +32,7 @@
&omap4_pmx_core {
twl6030_pins: pinmux_twl6030_pins {
pinctrl-single,pins = <
- 0x15e (WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq1.sys_nirq1 */
+ OMAP4_IOPAD(0x19e, WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq1.sys_nirq1 */
>;
};
};
diff --git a/arch/arm/boot/dts/uniphier-common32.dtsi b/arch/arm/boot/dts/uniphier-common32.dtsi
new file mode 100644
index 000000000000..ea9301aaa461
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-common32.dtsi
@@ -0,0 +1,135 @@
+/*
+ * Device Tree Source commonly used by UniPhier ARM SoCs
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ soc: soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ interrupt-parent = <&intc>;
+
+ extbus: extbus {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ };
+
+ serial0: serial@54006800 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006800 0x40>;
+ interrupts = <0 33 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ clocks = <&uart_clk>;
+ };
+
+ serial1: serial@54006900 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006900 0x40>;
+ interrupts = <0 35 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ clocks = <&uart_clk>;
+ };
+
+ serial2: serial@54006a00 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006a00 0x40>;
+ interrupts = <0 37 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ clocks = <&uart_clk>;
+ };
+
+ serial3: serial@54006b00 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006b00 0x40>;
+ interrupts = <0 177 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ clocks = <&uart_clk>;
+ };
+
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
+ };
+
+ timer@60000200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x60000200 0x20>;
+ interrupts = <1 11 0x104>;
+ clocks = <&arm_timer_clk>;
+ };
+
+ timer@60000600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x60000600 0x20>;
+ interrupts = <1 13 0x104>;
+ clocks = <&arm_timer_clk>;
+ };
+
+ intc: interrupt-controller@60001000 {
+ compatible = "arm,cortex-a9-gic";
+ reg = <0x60001000 0x1000>,
+ <0x60000100 0x100>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ };
+
+ pinctrl: pinctrl@5f801000 {
+ /* specify compatible in each SoC DTSI */
+ reg = <0x5f801000 0xe00>;
+ };
+ };
+};
+
+/include/ "uniphier-pinctrl.dtsi"
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi b/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
index af493819548d..34f0d8dcd814 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
@@ -42,7 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-/include/ "skeleton.dtsi"
+/include/ "uniphier-common32.dtsi"
/ {
compatible = "socionext,ph1-ld4";
@@ -78,188 +78,105 @@
clock-frequency = <100000000>;
};
};
+};
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- interrupt-parent = <&intc>;
-
- extbus: extbus {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- };
-
- l2: l2-cache@500c0000 {
- compatible = "socionext,uniphier-system-cache";
- reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
- <0x506c0000 0x400>;
- interrupts = <0 174 4>, <0 175 4>;
- cache-unified;
- cache-size = <(512 * 1024)>;
- cache-sets = <256>;
- cache-line-size = <128>;
- cache-level = <2>;
- };
-
- serial0: serial@54006800 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006800 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
- interrupts = <0 33 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial1: serial@54006900 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006900 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
- interrupts = <0 35 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial2: serial@54006a00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006a00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- interrupts = <0 37 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial3: serial@54006b00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006b00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart3>;
- interrupts = <0 29 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- i2c0: i2c@58400000 {
- compatible = "socionext,uniphier-i2c";
- status = "disabled";
- reg = <0x58400000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c0>;
- interrupts = <0 41 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <100000>;
- };
-
- i2c1: i2c@58480000 {
- compatible = "socionext,uniphier-i2c";
- status = "disabled";
- reg = <0x58480000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- interrupts = <0 42 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <100000>;
- };
-
- /* chip-internal connection for DMD */
- i2c2: i2c@58500000 {
- compatible = "socionext,uniphier-i2c";
- reg = <0x58500000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- interrupts = <0 43 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <400000>;
- };
+&soc {
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>, <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(512 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
- i2c3: i2c@58580000 {
- compatible = "socionext,uniphier-i2c";
- status = "disabled";
- reg = <0x58580000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- interrupts = <0 44 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <100000>;
- };
+ i2c0: i2c@58400000 {
+ compatible = "socionext,uniphier-i2c";
+ status = "disabled";
+ reg = <0x58400000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <100000>;
+ };
- system-bus-controller@58c00000 {
- compatible = "socionext,uniphier-system-bus-controller";
- reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
- };
+ i2c1: i2c@58480000 {
+ compatible = "socionext,uniphier-i2c";
+ status = "disabled";
+ reg = <0x58480000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <100000>;
+ };
- usb0: usb@5a800100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a800100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb0>;
- interrupts = <0 80 4>;
- };
+ /* chip-internal connection for DMD */
+ i2c2: i2c@58500000 {
+ compatible = "socionext,uniphier-i2c";
+ reg = <0x58500000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 43 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <400000>;
+ };
- usb1: usb@5a810100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a810100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb1>;
- interrupts = <0 81 4>;
- };
+ i2c3: i2c@58580000 {
+ compatible = "socionext,uniphier-i2c";
+ status = "disabled";
+ reg = <0x58580000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <100000>;
+ };
- usb2: usb@5a820100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a820100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb2>;
- interrupts = <0 82 4>;
- };
+ usb0: usb@5a800100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a800100 0x100>;
+ interrupts = <0 80 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb0>;
+ };
- pinctrl: pinctrl@5f801000 {
- compatible = "socionext,ph1-ld4-pinctrl",
- "syscon";
- reg = <0x5f801000 0xe00>;
- };
+ usb1: usb@5a810100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a810100 0x100>;
+ interrupts = <0 81 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb1>;
+ };
- timer@60000200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x60000200 0x20>;
- interrupts = <1 11 0x104>;
- clocks = <&arm_timer_clk>;
- };
+ usb2: usb@5a820100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a820100 0x100>;
+ interrupts = <0 82 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2>;
+ };
- timer@60000600 {
- compatible = "arm,cortex-a9-twd-timer";
- reg = <0x60000600 0x20>;
- interrupts = <1 13 0x104>;
- clocks = <&arm_timer_clk>;
- };
+};
- intc: interrupt-controller@60001000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x60001000 0x1000>,
- <0x60000100 0x100>;
- };
- };
+&serial3 {
+ interrupts = <0 29 4>;
};
-/include/ "uniphier-pinctrl.dtsi"
+&pinctrl {
+ compatible = "socionext,ph1-ld4-pinctrl", "syscon";
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi b/arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi
index c6499ee65bc6..532115234025 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi
@@ -53,7 +53,7 @@
compatible = "socionext,ph1-ld6b";
};
-/* UART3 unavilable: the pads are not wired to the package balls */
+/* UART3 unavailable: the pads are not wired to the package balls */
&serial3 {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi b/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
index 254642fe0e71..d78142fb35c4 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
@@ -42,7 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-/include/ "skeleton.dtsi"
+/include/ "uniphier-common32.dtsi"
/ {
compatible = "socionext,ph1-pro4";
@@ -86,203 +86,115 @@
clock-frequency = <50000000>;
};
};
+};
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- interrupt-parent = <&intc>;
-
- extbus: extbus {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- };
-
- l2: l2-cache@500c0000 {
- compatible = "socionext,uniphier-system-cache";
- reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
- <0x506c0000 0x400>;
- interrupts = <0 174 4>, <0 175 4>;
- cache-unified;
- cache-size = <(768 * 1024)>;
- cache-sets = <256>;
- cache-line-size = <128>;
- cache-level = <2>;
- };
-
- serial0: serial@54006800 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006800 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
- interrupts = <0 33 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial1: serial@54006900 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006900 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
- interrupts = <0 35 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial2: serial@54006a00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006a00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- interrupts = <0 37 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial3: serial@54006b00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006b00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart3>;
- interrupts = <0 29 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- i2c0: i2c@58780000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58780000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c0>;
- interrupts = <0 41 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c1: i2c@58781000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58781000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- interrupts = <0 42 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c2: i2c@58782000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58782000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- interrupts = <0 43 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c3: i2c@58783000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58783000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- interrupts = <0 44 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- /* i2c4 does not exist */
+&soc {
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>, <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(768 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
- /* chip-internal connection for DMD */
- i2c5: i2c@58785000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58785000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+ i2c0: i2c@58780000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58780000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- /* chip-internal connection for HDMI */
- i2c6: i2c@58786000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58786000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 26 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+ i2c1: i2c@58781000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58781000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- system-bus-controller@58c00000 {
- compatible = "socionext,uniphier-system-bus-controller";
- reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
- };
+ i2c2: i2c@58782000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58782000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 43 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- usb2: usb@5a800100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a800100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb2>;
- interrupts = <0 80 4>;
- };
+ i2c3: i2c@58783000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58783000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- usb3: usb@5a810100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a810100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb3>;
- interrupts = <0 81 4>;
- };
+ /* i2c4 does not exist */
- pinctrl: pinctrl@5f801000 {
- compatible = "socionext,ph1-pro4-pinctrl",
- "syscon";
- reg = <0x5f801000 0xe00>;
- };
+ /* chip-internal connection for DMD */
+ i2c5: i2c@58785000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58785000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 25 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
- timer@60000200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x60000200 0x20>;
- interrupts = <1 11 0x304>;
- clocks = <&arm_timer_clk>;
- };
+ /* chip-internal connection for HDMI */
+ i2c6: i2c@58786000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58786000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 26 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
- timer@60000600 {
- compatible = "arm,cortex-a9-twd-timer";
- reg = <0x60000600 0x20>;
- interrupts = <1 13 0x304>;
- clocks = <&arm_timer_clk>;
- };
+ usb2: usb@5a800100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a800100 0x100>;
+ interrupts = <0 80 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2>;
+ };
- intc: interrupt-controller@60001000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x60001000 0x1000>,
- <0x60000100 0x100>;
- };
+ usb3: usb@5a810100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a810100 0x100>;
+ interrupts = <0 81 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb3>;
};
};
-/include/ "uniphier-pinctrl.dtsi"
+&pinctrl {
+ compatible = "socionext,ph1-pro4-pinctrl", "syscon";
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi b/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
index 11eb76239feb..2f389ea75e01 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
@@ -42,7 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-/include/ "skeleton.dtsi"
+/include/ "uniphier-common32.dtsi"
/ {
compatible = "socionext,ph1-pro5";
@@ -86,193 +86,109 @@
clock-frequency = <50000000>;
};
};
+};
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- interrupt-parent = <&intc>;
-
- extbus: extbus {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- };
-
- l2: l2-cache@500c0000 {
- compatible = "socionext,uniphier-system-cache";
- reg = <0x500c0000 0x2000>, <0x503c0100 0x8>,
- <0x506c0000 0x400>;
- interrupts = <0 190 4>, <0 191 4>;
- cache-unified;
- cache-size = <(2 * 1024 * 1024)>;
- cache-sets = <512>;
- cache-line-size = <128>;
- cache-level = <2>;
- next-level-cache = <&l3>;
- };
-
- l3: l3-cache@500c8000 {
- compatible = "socionext,uniphier-system-cache";
- reg = <0x500c8000 0x2000>, <0x503c8100 0x8>,
- <0x506c8000 0x400>;
- interrupts = <0 174 4>, <0 175 4>;
- cache-unified;
- cache-size = <(2 * 1024 * 1024)>;
- cache-sets = <512>;
- cache-line-size = <256>;
- cache-level = <3>;
- };
-
- serial0: serial@54006800 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006800 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
- interrupts = <0 33 4>;
- clocks = <&uart_clk>;
- };
-
- serial1: serial@54006900 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006900 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
- interrupts = <0 35 4>;
- clocks = <&uart_clk>;
- };
-
- serial2: serial@54006a00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006a00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- interrupts = <0 37 4>;
- clocks = <&uart_clk>;
- };
-
- serial3: serial@54006b00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006b00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart3>;
- interrupts = <0 177 4>;
- clocks = <&uart_clk>;
- };
-
- i2c0: i2c@58780000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58780000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c0>;
- interrupts = <0 41 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c1: i2c@58781000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58781000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- interrupts = <0 42 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c2: i2c@58782000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58782000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- interrupts = <0 43 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c3: i2c@58783000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58783000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- interrupts = <0 44 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
+&soc {
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x8>, <0x506c0000 0x400>;
+ interrupts = <0 190 4>, <0 191 4>;
+ cache-unified;
+ cache-size = <(2 * 1024 * 1024)>;
+ cache-sets = <512>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ next-level-cache = <&l3>;
+ };
- /* i2c4 does not exist */
+ l3: l3-cache@500c8000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c8000 0x2000>, <0x503c8100 0x8>, <0x506c8000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(2 * 1024 * 1024)>;
+ cache-sets = <512>;
+ cache-line-size = <256>;
+ cache-level = <3>;
+ };
- /* chip-internal connection for DMD */
- i2c5: i2c@58785000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58785000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+ i2c0: i2c@58780000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58780000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- /* chip-internal connection for HDMI */
- i2c6: i2c@58786000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58786000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 26 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+ i2c1: i2c@58781000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58781000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- system-bus-controller@58c00000 {
- compatible = "socionext,uniphier-system-bus-controller";
- reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
- };
+ i2c2: i2c@58782000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58782000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 43 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- pinctrl: pinctrl@5f801000 {
- compatible = "socionext,ph1-pro5-pinctrl", "syscon";
- reg = <0x5f801000 0xe00>;
- };
+ i2c3: i2c@58783000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58783000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- timer@60000200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x60000200 0x20>;
- interrupts = <1 11 0x304>;
- clocks = <&arm_timer_clk>;
- };
+ /* i2c4 does not exist */
- timer@60000600 {
- compatible = "arm,cortex-a9-twd-timer";
- reg = <0x60000600 0x20>;
- interrupts = <1 13 0x304>;
- clocks = <&arm_timer_clk>;
- };
+ /* chip-internal connection for DMD */
+ i2c5: i2c@58785000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58785000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 25 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
- intc: interrupt-controller@60001000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x60001000 0x1000>,
- <0x60000100 0x100>;
- };
+ /* chip-internal connection for HDMI */
+ i2c6: i2c@58786000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58786000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 26 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
};
};
-/include/ "uniphier-pinctrl.dtsi"
+&pinctrl {
+ compatible = "socionext,ph1-pro5-pinctrl", "syscon";
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi b/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
index e88559b66be7..7d06a1c487d8 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
@@ -42,7 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-/include/ "skeleton.dtsi"
+/include/ "uniphier-common32.dtsi"
/ {
compatible = "socionext,ph1-sld8";
@@ -78,188 +78,104 @@
clock-frequency = <100000000>;
};
};
+};
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- interrupt-parent = <&intc>;
-
- extbus: extbus {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- };
-
- l2: l2-cache@500c0000 {
- compatible = "socionext,uniphier-system-cache";
- reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
- <0x506c0000 0x400>;
- interrupts = <0 174 4>, <0 175 4>;
- cache-unified;
- cache-size = <(256 * 1024)>;
- cache-sets = <256>;
- cache-line-size = <128>;
- cache-level = <2>;
- };
-
- serial0: serial@54006800 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006800 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
- interrupts = <0 33 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial1: serial@54006900 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006900 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
- interrupts = <0 35 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial2: serial@54006a00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006a00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- interrupts = <0 37 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- serial3: serial@54006b00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006b00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart3>;
- interrupts = <0 29 4>;
- clocks = <&uart_clk>;
- fifo-size = <64>;
- };
-
- i2c0: i2c@58400000 {
- compatible = "socionext,uniphier-i2c";
- status = "disabled";
- reg = <0x58400000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c0>;
- interrupts = <0 41 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <100000>;
- };
-
- i2c1: i2c@58480000 {
- compatible = "socionext,uniphier-i2c";
- status = "disabled";
- reg = <0x58480000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- interrupts = <0 42 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <100000>;
- };
-
- /* chip-internal connection for DMD */
- i2c2: i2c@58500000 {
- compatible = "socionext,uniphier-i2c";
- reg = <0x58500000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- interrupts = <0 43 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <400000>;
- };
-
- i2c3: i2c@58580000 {
- compatible = "socionext,uniphier-i2c";
- status = "disabled";
- reg = <0x58580000 0x40>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- interrupts = <0 44 1>;
- clocks = <&iobus_clk>;
- clock-frequency = <100000>;
- };
-
- system-bus-controller@58c00000 {
- compatible = "socionext,uniphier-system-bus-controller";
- reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
- };
+&soc {
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>, <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(256 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
- usb0: usb@5a800100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a800100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb0>;
- interrupts = <0 80 4>;
- };
+ i2c0: i2c@58400000 {
+ compatible = "socionext,uniphier-i2c";
+ status = "disabled";
+ reg = <0x58400000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <100000>;
+ };
- usb1: usb@5a810100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a810100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb1>;
- interrupts = <0 81 4>;
- };
+ i2c1: i2c@58480000 {
+ compatible = "socionext,uniphier-i2c";
+ status = "disabled";
+ reg = <0x58480000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <100000>;
+ };
- usb2: usb@5a820100 {
- compatible = "socionext,uniphier-ehci", "generic-ehci";
- status = "disabled";
- reg = <0x5a820100 0x100>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usb2>;
- interrupts = <0 82 4>;
- };
+ /* chip-internal connection for DMD */
+ i2c2: i2c@58500000 {
+ compatible = "socionext,uniphier-i2c";
+ reg = <0x58500000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 43 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <400000>;
+ };
- pinctrl: pinctrl@5f801000 {
- compatible = "socionext,ph1-sld8-pinctrl",
- "syscon";
- reg = <0x5f801000 0xe00>;
- };
+ i2c3: i2c@58580000 {
+ compatible = "socionext,uniphier-i2c";
+ status = "disabled";
+ reg = <0x58580000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&iobus_clk>;
+ clock-frequency = <100000>;
+ };
- timer@60000200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x60000200 0x20>;
- interrupts = <1 11 0x104>;
- clocks = <&arm_timer_clk>;
- };
+ usb0: usb@5a800100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a800100 0x100>;
+ interrupts = <0 80 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb0>;
+ };
- timer@60000600 {
- compatible = "arm,cortex-a9-twd-timer";
- reg = <0x60000600 0x20>;
- interrupts = <1 13 0x104>;
- clocks = <&arm_timer_clk>;
- };
+ usb1: usb@5a810100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a810100 0x100>;
+ interrupts = <0 81 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb1>;
+ };
- intc: interrupt-controller@60001000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x60001000 0x1000>,
- <0x60000100 0x100>;
- };
+ usb2: usb@5a820100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a820100 0x100>;
+ interrupts = <0 82 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2>;
};
};
-/include/ "uniphier-pinctrl.dtsi"
+&serial3 {
+ interrupts = <0 29 4>;
+};
+
+&pinctrl {
+ compatible = "socionext,ph1-sld8-pinctrl", "syscon";
+};
diff --git a/arch/arm/boot/dts/uniphier-proxstream2.dtsi b/arch/arm/boot/dts/uniphier-proxstream2.dtsi
index 259f1a909e24..6bd353f2d77e 100644
--- a/arch/arm/boot/dts/uniphier-proxstream2.dtsi
+++ b/arch/arm/boot/dts/uniphier-proxstream2.dtsi
@@ -42,7 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-/include/ "skeleton.dtsi"
+/include/ "uniphier-common32.dtsi"
/ {
compatible = "socionext,proxstream2";
@@ -100,189 +100,106 @@
clock-frequency = <50000000>;
};
};
+};
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
- interrupt-parent = <&intc>;
-
- extbus: extbus {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- };
-
- l2: l2-cache@500c0000 {
- compatible = "socionext,uniphier-system-cache";
- reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
- <0x506c0000 0x400>;
- interrupts = <0 174 4>, <0 175 4>, <0 190 4>, <0 191 4>;
- cache-unified;
- cache-size = <(1280 * 1024)>;
- cache-sets = <512>;
- cache-line-size = <128>;
- cache-level = <2>;
- };
-
- serial0: serial@54006800 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006800 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
- interrupts = <0 33 4>;
- clocks = <&uart_clk>;
- };
-
- serial1: serial@54006900 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006900 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
- interrupts = <0 35 4>;
- clocks = <&uart_clk>;
- };
-
- serial2: serial@54006a00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006a00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- interrupts = <0 37 4>;
- clocks = <&uart_clk>;
- };
-
- serial3: serial@54006b00 {
- compatible = "socionext,uniphier-uart";
- status = "disabled";
- reg = <0x54006b00 0x40>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart3>;
- interrupts = <0 177 4>;
- clocks = <&uart_clk>;
- };
-
- i2c0: i2c@58780000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58780000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c0>;
- interrupts = <0 41 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c1: i2c@58781000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58781000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- interrupts = <0 42 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c2: i2c@58782000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58782000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- interrupts = <0 43 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- i2c3: i2c@58783000 {
- compatible = "socionext,uniphier-fi2c";
- status = "disabled";
- reg = <0x58783000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- interrupts = <0 44 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <100000>;
- };
-
- /* chip-internal connection for DMD */
- i2c4: i2c@58784000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58784000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 45 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+&soc {
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>, <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>, <0 190 4>, <0 191 4>;
+ cache-unified;
+ cache-size = <(1280 * 1024)>;
+ cache-sets = <512>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
- /* chip-internal connection for STM */
- i2c5: i2c@58785000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58785000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+ i2c0: i2c@58780000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58780000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- /* chip-internal connection for HDMI */
- i2c6: i2c@58786000 {
- compatible = "socionext,uniphier-fi2c";
- reg = <0x58786000 0x80>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <0 26 4>;
- clocks = <&i2c_clk>;
- clock-frequency = <400000>;
- };
+ i2c1: i2c@58781000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58781000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- system-bus-controller@58c00000 {
- compatible = "socionext,uniphier-system-bus-controller";
- reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
- };
+ i2c2: i2c@58782000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58782000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ interrupts = <0 43 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- pinctrl: pinctrl@5f801000 {
- compatible = "socionext,proxstream2-pinctrl", "syscon";
- reg = <0x5f801000 0xe00>;
- };
+ i2c3: i2c@58783000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58783000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
- timer@60000200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x60000200 0x20>;
- interrupts = <1 11 0xf04>;
- clocks = <&arm_timer_clk>;
- };
+ /* chip-internal connection for DMD */
+ i2c4: i2c@58784000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58784000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 45 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
- timer@60000600 {
- compatible = "arm,cortex-a9-twd-timer";
- reg = <0x60000600 0x20>;
- interrupts = <1 13 0xf04>;
- clocks = <&arm_timer_clk>;
- };
+ /* chip-internal connection for STM */
+ i2c5: i2c@58785000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58785000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 25 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
- intc: interrupt-controller@60001000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x60001000 0x1000>,
- <0x60000100 0x100>;
- };
+ /* chip-internal connection for HDMI */
+ i2c6: i2c@58786000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58786000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 26 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
};
};
-/include/ "uniphier-pinctrl.dtsi"
+&pinctrl {
+ compatible = "socionext,proxstream2-pinctrl", "syscon";
+};
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
index 3279bf1a17a1..6fd7efbead34 100644
--- a/arch/arm/boot/dts/versatile-ab.dts
+++ b/arch/arm/boot/dts/versatile-ab.dts
@@ -30,9 +30,69 @@
};
core-module@10000000 {
- compatible = "arm,core-module-versatile", "syscon";
+ compatible = "arm,core-module-versatile", "syscon", "simple-mfd";
reg = <0x10000000 0x200>;
+ led@08.0 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x01>;
+ label = "versatile:0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ led@08.1 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x02>;
+ label = "versatile:1";
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+ led@08.2 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x04>;
+ label = "versatile:2";
+ linux,default-trigger = "cpu0";
+ default-state = "off";
+ };
+ led@08.3 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x08>;
+ label = "versatile:3";
+ default-state = "off";
+ };
+ led@08.4 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x10>;
+ label = "versatile:4";
+ default-state = "off";
+ };
+ led@08.5 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x20>;
+ label = "versatile:5";
+ default-state = "off";
+ };
+ led@08.6 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x40>;
+ label = "versatile:6";
+ default-state = "off";
+ };
+ led@08.7 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x80>;
+ label = "versatile:7";
+ default-state = "off";
+ };
+
/* OSC1 on AB, OSC4 on PB */
osc1: cm_aux_osc@24M {
#clock-cells = <0>;
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index e5949b934945..6e556be42ccd 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -23,6 +23,18 @@
status = "okay";
};
+&can0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan0>;
+ status = "disabled";
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "disabled";
+};
+
&dspi1 {
bus-num = <1>;
pinctrl-names = "default";
@@ -125,6 +137,20 @@
&iomuxc {
vf610-colibri {
+ pinctrl_flexcan0: can0grp {
+ fsl,pins = <
+ VF610_PAD_PTB14__CAN0_RX 0x31F1
+ VF610_PAD_PTB15__CAN0_TX 0x31F2
+ >;
+ };
+
+ pinctrl_flexcan1: can1grp {
+ fsl,pins = <
+ VF610_PAD_PTB16__CAN1_RX 0x31F1
+ VF610_PAD_PTB17__CAN1_TX 0x31F2
+ >;
+ };
+
pinctrl_gpio_ext: gpio_ext {
fsl,pins = <
VF610_PAD_PTD10__GPIO_89 0x22ed /* EXT_IO_0 */
diff --git a/arch/arm/boot/dts/vf610m4-cosmic.dts b/arch/arm/boot/dts/vf610m4-cosmic.dts
new file mode 100644
index 000000000000..8944a2d2054c
--- /dev/null
+++ b/arch/arm/boot/dts/vf610m4-cosmic.dts
@@ -0,0 +1,90 @@
+/*
+ * Device tree for Cosmic+ VF6xx Cortex-M4 support
+ *
+ * Copyright (C) 2015
+ *
+ * Based on vf610m4 Colibri
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 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 , 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.
+ */
+
+/dts-v1/;
+#include "vf610m4.dtsi"
+
+/ {
+ model = "VF610 Cortex-M4";
+ compatible = "fsl,vf610m4";
+};
+
+&gpio0 {
+ status = "disabled";
+};
+
+&gpio1 {
+ status = "disabled";
+};
+
+&gpio2 {
+ status = "disabled";
+};
+
+&gpio3 {
+ status = "disabled";
+};
+
+&gpio4 {
+ status = "disabled";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&iomuxc {
+ vf610-cosmic {
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ VF610_PAD_PTA20__UART3_TX 0x21a2
+ VF610_PAD_PTA21__UART3_RX 0x21a1
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index 3cd1b27f2697..a9ceb5bac40e 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -455,6 +455,30 @@
status = "disabled";
};
+ dspi2: dspi2@400ac000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-dspi";
+ reg = <0x400ac000 0x1000>;
+ interrupts = <69 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_DSPI2>;
+ clock-names = "dspi";
+ spi-num-chipselects = <2>;
+ status = "disabled";
+ };
+
+ dspi3: dspi3@400ad000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-dspi";
+ reg = <0x400ad000 0x1000>;
+ interrupts = <70 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_DSPI3>;
+ clock-names = "dspi";
+ spi-num-chipselects = <2>;
+ status = "disabled";
+ };
+
adc1: adc@400bb000 {
compatible = "fsl,vf610-adc";
reg = <0x400bb000 0x1000>;
diff --git a/arch/arm/boot/dts/wm8505.dtsi b/arch/arm/boot/dts/wm8505.dtsi
index a1a854b8a454..e9ef539e13d3 100644
--- a/arch/arm/boot/dts/wm8505.dtsi
+++ b/arch/arm/boot/dts/wm8505.dtsi
@@ -281,8 +281,8 @@
sdhc@d800a000 {
compatible = "wm,wm8505-sdhc";
- reg = <0xd800a000 0x1000>;
- interrupts = <20 21>;
+ reg = <0xd800a000 0x400>;
+ interrupts = <20>, <21>;
clocks = <&clksdhc>;
bus-width = <4>;
};
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index 1a5220e05109..f283ff08381c 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -19,7 +19,7 @@
#address-cells = <1>;
#size-cells = <0>;
- cpu@0 {
+ cpu0: cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0>;
@@ -33,7 +33,7 @@
>;
};
- cpu@1 {
+ cpu1: cpu@1 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <1>;
@@ -101,6 +101,8 @@
#gpio-cells = <2>;
clocks = <&clkc 42>;
gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <0 20 4>;
reg = <0xe000a000 0x1000>;
@@ -238,7 +240,7 @@
slcr: slcr@f8000000 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "xlnx,zynq-slcr", "syscon", "simple-bus";
+ compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
reg = <0xF8000000 0x1000>;
ranges;
clkc: clkc@100 {
diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts
index 5df8f81f4217..cb64209bca08 100644
--- a/arch/arm/boot/dts/zynq-zc702.dts
+++ b/arch/arm/boot/dts/zynq-zc702.dts
@@ -43,14 +43,14 @@
label = "sw14";
gpios = <&gpio0 12 0>;
linux,code = <108>; /* down */
- gpio-key,wakeup;
+ wakeup-source;
autorepeat;
};
sw13 {
label = "sw13";
gpios = <&gpio0 14 0>;
linux,code = <103>; /* up */
- gpio-key,wakeup;
+ wakeup-source;
autorepeat;
};
};
diff --git a/arch/arm/common/mcpm_platsmp.c b/arch/arm/common/mcpm_platsmp.c
index 2b25b6038f66..c773157646d3 100644
--- a/arch/arm/common/mcpm_platsmp.c
+++ b/arch/arm/common/mcpm_platsmp.c
@@ -83,7 +83,7 @@ static void mcpm_cpu_die(unsigned int cpu)
#endif
-static struct smp_operations __initdata mcpm_smp_ops = {
+static const struct smp_operations mcpm_smp_ops __initconst = {
.smp_boot_secondary = mcpm_boot_secondary,
.smp_secondary_init = mcpm_secondary_init,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 45f4c21e393c..e0df333202b8 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -84,7 +84,7 @@ static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
/* XXX: I'm unsure, but it seems so */
- return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1));
+ return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
}
static int scoop_gpio_direction_input(struct gpio_chip *chip,
diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig
index 31cb07388885..72def201c4fd 100644
--- a/arch/arm/configs/bcm2835_defconfig
+++ b/arch/arm/configs/bcm2835_defconfig
@@ -10,7 +10,6 @@ CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_PERF=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_RT_GROUP_SCHED=y
@@ -18,10 +17,6 @@ CONFIG_NAMESPACES=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
-CONFIG_RD_XZ=y
-CONFIG_RD_LZO=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
@@ -29,6 +24,7 @@ CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_JUMP_LABEL=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
CONFIG_ARCH_MULTI_V6=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_BCM=y
@@ -38,7 +34,6 @@ CONFIG_AEABI=y
CONFIG_KSM=y
CONFIG_CLEANCACHE=y
CONFIG_SECCOMP=y
-CONFIG_CC_STACKPROTECTOR=y
CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y
CONFIG_VFP=y
@@ -57,7 +52,6 @@ CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_NETDEVICES=y
@@ -75,19 +69,30 @@ CONFIG_I2C_CHARDEV=y
CONFIG_I2C_BCM2835=y
CONFIG_SPI=y
CONFIG_SPI_BCM2835=y
+CONFIG_SPI_BCM2835AUX=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_BCM2835_WDT=y
CONFIG_FB=y
CONFIG_FB_SIMPLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BCM2835_SOC_I2S=y
CONFIG_USB=y
CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC2=y
CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_BCM2835=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
@@ -96,17 +101,19 @@ CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_LEDS_TRIGGER_TRANSIENT=y
CONFIG_LEDS_TRIGGER_CAMERA=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2835=y
CONFIG_STAGING=y
-CONFIG_USB_DWC2=y
-CONFIG_USB_DWC2_HOST=y
+CONFIG_MAILBOX=y
+CONFIG_BCM2835_MBOX=y
# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_PWM=y
+CONFIG_PWM_BCM2835=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_FANOTIFY=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
index a7846d64b396..158dde87f5d0 100644
--- a/arch/arm/configs/ep93xx_defconfig
+++ b/arch/arm/configs/ep93xx_defconfig
@@ -132,6 +132,5 @@ CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_LL_UART_PL01X=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index e0841a58ff9d..24dcd2bb1215 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -7,7 +7,6 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_EXYNOS=y
CONFIG_ARCH_EXYNOS3=y
@@ -44,7 +43,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
CONFIG_CFG80211=y
CONFIG_RFKILL_REGULATOR=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
@@ -74,6 +72,9 @@ CONFIG_KEYBOARD_CROS_EC=y
CONFIG_MOUSE_CYAPA=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MAX77693_HAPTIC=y
+CONFIG_INPUT_MAX8997_HAPTIC=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_SAMSUNG=y
CONFIG_SERIAL_SAMSUNG_CONSOLE=y
@@ -87,6 +88,7 @@ CONFIG_I2C_ARB_GPIO_CHALLENGE=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SPI=y
+CONFIG_SPI_GPIO=y
CONFIG_SPI_S3C64XX=y
CONFIG_DEBUG_GPIO=y
CONFIG_POWER_SUPPLY=y
@@ -95,6 +97,7 @@ CONFIG_BATTERY_MAX17040=y
CONFIG_BATTERY_MAX17042=y
CONFIG_CHARGER_MAX14577=y
CONFIG_CHARGER_MAX77693=y
+CONFIG_CHARGER_MAX8997=y
CONFIG_CHARGER_TPS65090=y
CONFIG_SENSORS_LM90=y
CONFIG_SENSORS_NTC_THERMISTOR=y
@@ -113,6 +116,7 @@ CONFIG_MFD_MAX14577=y
CONFIG_MFD_MAX77686=y
CONFIG_MFD_MAX77693=y
CONFIG_MFD_MAX8997=y
+CONFIG_MFD_MAX8998=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_TPS65090=y
CONFIG_REGULATOR=y
@@ -120,6 +124,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MAX14577=y
CONFIG_REGULATOR_MAX8997=y
+CONFIG_REGULATOR_MAX8998=y
CONFIG_REGULATOR_MAX77686=y
CONFIG_REGULATOR_MAX77693=y
CONFIG_REGULATOR_MAX77802=y
@@ -138,8 +143,10 @@ CONFIG_DRM_EXYNOS=y
CONFIG_DRM_EXYNOS_FIMD=y
CONFIG_DRM_EXYNOS_DSI=y
CONFIG_DRM_EXYNOS_MIXER=y
+CONFIG_DRM_EXYNOS_DPI=y
CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_PANEL_SIMPLE=y
+CONFIG_DRM_PANEL_SAMSUNG_LD9040=y
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y
CONFIG_EXYNOS_VIDEO=y
CONFIG_EXYNOS_MIPI_DSI=y
@@ -176,11 +183,15 @@ CONFIG_MMC_DW=y
CONFIG_MMC_DW_EXYNOS=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_PWM=y
+CONFIG_LEDS_MAX77693=y
+CONFIG_LEDS_MAX8997=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_MAX8997=y
CONFIG_RTC_DRV_MAX77686=y
CONFIG_RTC_DRV_MAX77802=y
CONFIG_RTC_DRV_S5M=y
@@ -195,6 +206,7 @@ CONFIG_COMMON_CLK_S2MPS11=y
CONFIG_EXTCON=y
CONFIG_EXTCON_MAX14577=y
CONFIG_EXTCON_MAX77693=y
+CONFIG_EXTCON_MAX8997=y
CONFIG_IIO=y
CONFIG_EXYNOS_ADC=y
CONFIG_PWM=y
@@ -203,6 +215,7 @@ CONFIG_PHY_EXYNOS5250_SATA=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y
+CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
@@ -210,6 +223,7 @@ CONFIG_TMPFS_POSIX_ACL=y
CONFIG_CRAMFS=y
CONFIG_ROMFS_FS=y
CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 4187f69f6630..2d5253dcc226 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -42,9 +42,9 @@ CONFIG_SOC_IMX6SL=y
CONFIG_SOC_IMX6SX=y
CONFIG_SOC_IMX6UL=y
CONFIG_SOC_IMX7D=y
-CONFIG_SOC_LS1021A=y
CONFIG_SOC_VF610=y
CONFIG_PCI=y
+CONFIG_PCI_MSI=y
CONFIG_PCI_IMX6=y
CONFIG_SMP=y
CONFIG_PREEMPT_VOLUNTARY=y
@@ -224,6 +224,7 @@ CONFIG_SOC_CAMERA_OV2640=y
CONFIG_IMX_IPUV3_CORE=y
CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y
+CONFIG_DRM_DW_HDMI_AHB_AUDIO=m
CONFIG_DRM_IMX=y
CONFIG_DRM_IMX_FB_HELPER=y
CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
@@ -315,6 +316,8 @@ CONFIG_MXS_DMA=y
CONFIG_FSL_EDMA=y
CONFIG_STAGING=y
# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_IIO=y
+CONFIG_VF610_ADC=y
CONFIG_PWM=y
CONFIG_PWM_IMX=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/lpc18xx_defconfig b/arch/arm/configs/lpc18xx_defconfig
index 03c155f5b811..2ae00b09cfc2 100644
--- a/arch/arm/configs/lpc18xx_defconfig
+++ b/arch/arm/configs/lpc18xx_defconfig
@@ -147,7 +147,12 @@ CONFIG_MEMORY=y
CONFIG_ARM_PL172_MPMC=y
CONFIG_PWM=y
CONFIG_PWM_LPC18XX_SCT=y
+CONFIG_IIO=y
+CONFIG_MMA7455_I2C=y
+CONFIG_IIO_SYSFS_TRIGGER=y
CONFIG_PHY_LPC18XX_USB_OTG=y
+CONFIG_NVMEM=y
+CONFIG_NVMEM_LPC18XX_EEPROM=y
CONFIG_EXT2_FS=y
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
index c100b7df5441..9f56ca3985ae 100644
--- a/arch/arm/configs/lpc32xx_defconfig
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -204,7 +204,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_FTRACE is not set
# CONFIG_ARM_UNWIND is not set
CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_LL_UART_8250=y
CONFIG_EARLY_PRINTK=y
CONFIG_CRYPTO_ANSI_CPRNG=y
# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig
index f69a459f4f92..1f9ca4737ef6 100644
--- a/arch/arm/configs/multi_v5_defconfig
+++ b/arch/arm/configs/multi_v5_defconfig
@@ -11,10 +11,32 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_MVEBU=y
CONFIG_MACH_KIRKWOOD=y
-CONFIG_MACH_NETXBIG=y
CONFIG_ARCH_MXC=y
-CONFIG_SOC_IMX25=y
CONFIG_MACH_IMX27_DT=y
+CONFIG_SOC_IMX25=y
+CONFIG_ARCH_ORION5X=y
+CONFIG_MACH_DB88F5281=y
+CONFIG_MACH_RD88F5182=y
+CONFIG_MACH_RD88F5182_DT=y
+CONFIG_MACH_KUROBOX_PRO=y
+CONFIG_MACH_DNS323=y
+CONFIG_MACH_TS209=y
+CONFIG_MACH_TERASTATION_PRO2=y
+CONFIG_MACH_LINKSTATION_PRO=y
+CONFIG_MACH_LINKSTATION_LSCHL=y
+CONFIG_MACH_LINKSTATION_MINI=y
+CONFIG_MACH_LINKSTATION_LS_HGL=y
+CONFIG_MACH_TS409=y
+CONFIG_MACH_WRT350N_V2=y
+CONFIG_MACH_TS78XX=y
+CONFIG_MACH_MV2120=y
+CONFIG_MACH_D2NET_DT=y
+CONFIG_MACH_NET2BIG=y
+CONFIG_MACH_MSS2_DT=y
+CONFIG_MACH_WNR854T=y
+CONFIG_MACH_RD88F5181L_GE=y
+CONFIG_MACH_RD88F5181L_FXO=y
+CONFIG_MACH_RD88F6183AP_GE=y
CONFIG_ARCH_U300=y
CONFIG_PCI_MVEBU=y
CONFIG_PREEMPT=y
@@ -38,6 +60,8 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IPV6 is not set
+CONFIG_NET_DSA=y
+CONFIG_NET_SWITCHDEV=y
CONFIG_NET_PKTGEN=m
CONFIG_CFG80211=y
CONFIG_MAC80211=y
@@ -53,7 +77,6 @@ CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ORION=y
CONFIG_BLK_DEV_LOOP=y
@@ -66,8 +89,11 @@ CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6131=y
CONFIG_NET_DSA_MV88E6123_61_65=y
CONFIG_NET_DSA_MV88E6171=y
+CONFIG_NET_DSA_MV88E6352=y
CONFIG_MV643XX_ETH=y
CONFIG_R8169=y
CONFIG_MARVELL_PHY=y
@@ -92,7 +118,6 @@ CONFIG_I2C_NOMADIK=y
CONFIG_SPI=y
CONFIG_SPI_ORION=y
CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO=y
CONFIG_POWER_RESET_QNAP=y
@@ -105,17 +130,16 @@ CONFIG_THERMAL=y
CONFIG_KIRKWOOD_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_ORION_WATCHDOG=y
+# CONFIG_ABX500_CORE is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_FB=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_KIRKWOOD_SOC=y
-CONFIG_SND_KIRKWOOD_SOC_T5325=y
CONFIG_SND_SOC_ALC5623=y
CONFIG_SND_SIMPLE_CARD=y
-# CONFIG_ABX500_CORE is not set
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_HID_DRAGONRISE=y
CONFIG_HID_GYRATION=y
CONFIG_HID_TWINHAN=y
@@ -162,8 +186,6 @@ CONFIG_STAGING=y
CONFIG_FB_XGI=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_EXT4_FS=y
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_UDF_FS=m
@@ -189,7 +211,6 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_DEV_MV_CESA=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index cd7b198fc79e..314f6be2dca2 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -11,6 +11,9 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_CMDLINE_PARTITION=y
+CONFIG_ARCH_MULTI_V7=y
+# CONFIG_ARCH_MULTI_V5 is not set
+# CONFIG_ARCH_MULTI_V4 is not set
CONFIG_ARCH_VIRT=y
CONFIG_ARCH_ALPINE=y
CONFIG_ARCH_MVEBU=y
@@ -75,7 +78,7 @@ CONFIG_MACH_SPEAR1340=y
CONFIG_ARCH_STI=y
CONFIG_ARCH_EXYNOS=y
CONFIG_EXYNOS5420_MCPM=y
-CONFIG_ARCH_SHMOBILE_MULTI=y
+CONFIG_ARCH_RENESAS=y
CONFIG_ARCH_EMEV2=y
CONFIG_ARCH_R7S72100=y
CONFIG_ARCH_R8A73A4=y
@@ -125,6 +128,7 @@ CONFIG_KEXEC=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_QORIQ_CPUFREQ=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_CPUIDLE=y
CONFIG_NEON=y
@@ -152,6 +156,7 @@ CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_CAN_DEV=y
CONFIG_CAN_AT91=m
+CONFIG_CAN_RCAR=m
CONFIG_CAN_XILINXCAN=y
CONFIG_CAN_MCP251X=y
CONFIG_CAN_SUN4I=y
@@ -169,6 +174,7 @@ CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_OMAP_OCP2SCP=y
CONFIG_SIMPLE_PM_BUS=y
+CONFIG_SUNXI_RSB=m
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
@@ -178,17 +184,21 @@ CONFIG_MTD_NAND_ATMEL=y
CONFIG_MTD_NAND_BRCMNAND=y
CONFIG_MTD_NAND_DAVINCI=y
CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_FSL_QUADSPI=m
CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_VIRTIO_BLK=y
CONFIG_AD525X_DPOT=y
CONFIG_AD525X_DPOT_I2C=y
CONFIG_ATMEL_TCLIB=y
CONFIG_ICS932S401=y
CONFIG_ATMEL_SSC=m
+CONFIG_QCOM_COINCELL=m
CONFIG_APDS9802ALS=y
CONFIG_ISL29003=y
CONFIG_EEPROM_AT24=y
-CONFIG_EEPROM_SUNXI_SID=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_SCSI_MULTI_LUN=y
@@ -202,10 +212,12 @@ CONFIG_SATA_HIGHBANK=y
CONFIG_SATA_MV=y
CONFIG_SATA_RCAR=y
CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
CONFIG_HIX5HD2_GMAC=y
CONFIG_SUN4I_EMAC=y
CONFIG_MACB=y
CONFIG_NET_CALXEDA_XGMAC=y
+CONFIG_GIANFAR=y
CONFIG_IGB=y
CONFIG_MV643XX_ETH=y
CONFIG_MVNETA=y
@@ -222,6 +234,7 @@ CONFIG_MARVELL_PHY=y
CONFIG_SMSC_PHY=y
CONFIG_BROADCOM_PHY=y
CONFIG_ICPLUS_PHY=y
+CONFIG_REALTEK_PHY=y
CONFIG_MICREL_PHY=y
CONFIG_FIXED_PHY=y
CONFIG_USB_PEGASUS=y
@@ -241,7 +254,7 @@ CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_TEGRA=y
CONFIG_KEYBOARD_SPEAR=y
CONFIG_KEYBOARD_ST_KEYSCAN=y
-CONFIG_KEYBOARD_CROS_EC=y
+CONFIG_KEYBOARD_CROS_EC=m
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_MOUSE_CYAPA=m
CONFIG_MOUSE_ELAN_I2C=y
@@ -252,8 +265,10 @@ CONFIG_TOUCHSCREEN_STMPE=y
CONFIG_TOUCHSCREEN_SUN4I=y
CONFIG_TOUCHSCREEN_WM97XX=m
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MAX77693_HAPTIC=m
+CONFIG_INPUT_MAX8997_HAPTIC=m
CONFIG_INPUT_MPU3050=y
-CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_AXP20X_PEK=m
CONFIG_INPUT_ADXL34X=m
CONFIG_SERIO_AMBAKMI=y
CONFIG_SERIAL_8250=y
@@ -294,6 +309,8 @@ CONFIG_SERIAL_CONEXANT_DIGICOLOR=y
CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE=y
CONFIG_SERIAL_ST_ASC=y
CONFIG_SERIAL_ST_ASC_CONSOLE=y
+CONFIG_HVC_DRIVER=y
+CONFIG_VIRTIO_CONSOLE=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DAVINCI=y
CONFIG_I2C_MUX=y
@@ -304,8 +321,10 @@ CONFIG_I2C_AT91=m
CONFIG_I2C_CADENCE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_DIGICOLOR=m
+CONFIG_I2C_EMEV2=m
CONFIG_I2C_GPIO=m
CONFIG_I2C_EXYNOS5=y
+CONFIG_I2C_IMX=m
CONFIG_I2C_MV64XXX=y
CONFIG_I2C_RIIC=y
CONFIG_I2C_RK3X=y
@@ -324,6 +343,7 @@ CONFIG_SPI=y
CONFIG_SPI_ATMEL=m
CONFIG_SPI_CADENCE=y
CONFIG_SPI_DAVINCI=y
+CONFIG_SPI_FSL_DSPI=m
CONFIG_SPI_OMAP24XX=y
CONFIG_SPI_ORION=y
CONFIG_SPI_PL022=y
@@ -340,10 +360,18 @@ CONFIG_SPI_TEGRA20_SFLASH=y
CONFIG_SPI_TEGRA20_SLINK=y
CONFIG_SPI_XILINX=y
CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
CONFIG_PINCTRL_AS3722=y
CONFIG_PINCTRL_PALMAS=y
CONFIG_PINCTRL_APQ8064=y
CONFIG_PINCTRL_APQ8084=y
+CONFIG_PINCTRL_IPQ8064=y
+CONFIG_PINCTRL_MSM8660=y
+CONFIG_PINCTRL_MSM8960=y
+CONFIG_PINCTRL_MSM8X74=y
+CONFIG_PINCTRL_MSM8916=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_PINCTRL_QCOM_SSBI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_GENERIC_PLATFORM=y
CONFIG_GPIO_DAVINCI=y
@@ -365,6 +393,7 @@ CONFIG_BATTERY_MAX17040=m
CONFIG_BATTERY_MAX17042=m
CONFIG_CHARGER_MAX14577=m
CONFIG_CHARGER_MAX77693=m
+CONFIG_CHARGER_MAX8997=m
CONFIG_CHARGER_TPS65090=y
CONFIG_AXP20X_POWER=m
CONFIG_POWER_RESET_AS3722=y
@@ -372,10 +401,13 @@ CONFIG_POWER_RESET_GPIO=y
CONFIG_POWER_RESET_GPIO_RESTART=y
CONFIG_POWER_RESET_KEYSTONE=y
CONFIG_POWER_RESET_RMOBILE=y
+CONFIG_POWER_AVS=y
+CONFIG_ROCKCHIP_IODOMAIN=y
CONFIG_SENSORS_LM90=y
CONFIG_SENSORS_LM95245=y
CONFIG_SENSORS_NTC_THERMISTOR=m
-CONFIG_THERMAL=y
+CONFIG_SENSORS_PWM_FAN=m
+CONFIG_SENSORS_INA2XX=m
CONFIG_CPU_THERMAL=y
CONFIG_ROCKCHIP_THERMAL=y
CONFIG_RCAR_THERMAL=y
@@ -385,11 +417,13 @@ CONFIG_EXYNOS_THERMAL=m
CONFIG_ST_THERMAL_SYSCFG=y
CONFIG_ST_THERMAL_MEMMAP=y
CONFIG_WATCHDOG=y
+CONFIG_DA9063_WATCHDOG=m
CONFIG_XILINX_WATCHDOG=y
CONFIG_ARM_SP805_WATCHDOG=y
CONFIG_ORION_WATCHDOG=y
CONFIG_ST_LPC_WATCHDOG=y
CONFIG_SUNXI_WATCHDOG=y
+CONFIG_IMX2_WDT=y
CONFIG_TEGRA_WATCHDOG=m
CONFIG_MESON_WATCHDOG=y
CONFIG_DIGICOLOR_WATCHDOG=y
@@ -398,27 +432,34 @@ CONFIG_MFD_AS3722=y
CONFIG_MFD_ATMEL_FLEXCOM=y
CONFIG_MFD_BCM590XX=y
CONFIG_MFD_AXP20X=y
-CONFIG_MFD_CROS_EC=y
+CONFIG_MFD_AXP20X_I2C=m
+CONFIG_MFD_AXP20X_RSB=m
+CONFIG_MFD_CROS_EC=m
CONFIG_MFD_CROS_EC_I2C=m
-CONFIG_MFD_CROS_EC_SPI=y
+CONFIG_MFD_CROS_EC_SPI=m
+CONFIG_MFD_DA9063=m
CONFIG_MFD_MAX14577=y
CONFIG_MFD_MAX77686=y
CONFIG_MFD_MAX77693=y
CONFIG_MFD_MAX8907=y
+CONFIG_MFD_MAX8997=y
CONFIG_MFD_RK808=y
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_STMPE=y
CONFIG_MFD_PALMAS=y
CONFIG_MFD_TPS65090=y
+CONFIG_MFD_TPS65217=y
+CONFIG_MFD_TPS65218=y
CONFIG_MFD_TPS6586X=y
CONFIG_MFD_TPS65910=y
CONFIG_REGULATOR_AB8500=y
CONFIG_REGULATOR_ACT8865=y
CONFIG_REGULATOR_AS3711=y
CONFIG_REGULATOR_AS3722=y
-CONFIG_REGULATOR_AXP20X=y
+CONFIG_REGULATOR_AXP20X=m
CONFIG_REGULATOR_BCM590XX=y
CONFIG_REGULATOR_DA9210=y
CONFIG_REGULATOR_FAN53555=y
@@ -429,6 +470,7 @@ CONFIG_POWER_RESET_SYSCON=y
CONFIG_REGULATOR_MAX14577=m
CONFIG_REGULATOR_MAX8907=y
CONFIG_REGULATOR_MAX8973=y
+CONFIG_REGULATOR_MAX8997=m
CONFIG_REGULATOR_MAX77686=y
CONFIG_REGULATOR_MAX77693=m
CONFIG_REGULATOR_MAX77802=m
@@ -439,9 +481,12 @@ CONFIG_REGULATOR_QCOM_RPM=y
CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
+CONFIG_REGULATOR_TI_ABB=y
CONFIG_REGULATOR_TPS51632=y
CONFIG_REGULATOR_TPS62360=y
CONFIG_REGULATOR_TPS65090=y
+CONFIG_REGULATOR_TPS65217=y
+CONFIG_REGULATOR_TPS65218=y
CONFIG_REGULATOR_TPS6586X=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TWL4030=y
@@ -458,6 +503,7 @@ CONFIG_SOC_CAMERA=m
CONFIG_SOC_CAMERA_PLATFORM=m
CONFIG_VIDEO_RCAR_VIN=m
CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_JPU=m
CONFIG_VIDEO_RENESAS_VSP1=m
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
CONFIG_VIDEO_ADV7180=m
@@ -501,13 +547,21 @@ CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=m
CONFIG_SND_HDA_CODEC_HDMI=m
-CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=m
CONFIG_SND_ATMEL_SOC=m
CONFIG_SND_ATMEL_SOC_WM8904=m
+CONFIG_SND_SOC_FSL_SAI=m
+CONFIG_SND_SOC_ROCKCHIP=m
+CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
+CONFIG_SND_SOC_ROCKCHIP_MAX98090=m
+CONFIG_SND_SOC_ROCKCHIP_RT5645=m
CONFIG_SND_SOC_SH4_FSI=m
CONFIG_SND_SOC_RCAR=m
CONFIG_SND_SOC_RSRC_CARD=m
+CONFIG_SND_SOC_SAMSUNG=m
+CONFIG_SND_SOC_SNOW=m
+CONFIG_SND_SOC_ODROIDX2=m
CONFIG_SND_SOC_TEGRA=m
CONFIG_SND_SOC_TEGRA_RT5640=m
CONFIG_SND_SOC_TEGRA_WM8753=m
@@ -517,6 +571,8 @@ CONFIG_SND_SOC_TEGRA_TRIMSLICE=m
CONFIG_SND_SOC_TEGRA_ALC5632=m
CONFIG_SND_SOC_TEGRA_MAX98090=m
CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_SOC_SPDIF=m
CONFIG_SND_SOC_WM8978=m
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
@@ -546,7 +602,6 @@ CONFIG_USB_GPIO_VBUS=y
CONFIG_USB_ISP1301=y
CONFIG_USB_MSM_OTG=m
CONFIG_USB_MXS_PHY=y
-CONFIG_USB_RCAR_PHY=m
CONFIG_USB_GADGET=y
CONFIG_USB_RENESAS_USBHS_UDC=m
CONFIG_USB_ETH=m
@@ -557,6 +612,7 @@ CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_OF_ARASAN=y
CONFIG_MMC_SDHCI_OF_AT91=y
+CONFIG_MMC_SDHCI_OF_ESDHC=m
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_DOVE=y
CONFIG_MMC_SDHCI_TEGRA=y
@@ -569,6 +625,7 @@ CONFIG_MMC_SDHCI_ST=y
CONFIG_MMC_OMAP=y
CONFIG_MMC_OMAP_HS=y
CONFIG_MMC_ATMELMCI=y
+CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_MVSDIO=y
CONFIG_MMC_SDHI=y
CONFIG_MMC_DW=y
@@ -580,8 +637,11 @@ CONFIG_MMC_SH_MMCIF=y
CONFIG_MMC_SUNXI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_PWM=y
+CONFIG_LEDS_MAX77693=m
+CONFIG_LEDS_MAX8997=m
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
@@ -601,6 +661,7 @@ CONFIG_RTC_DRV_AS3722=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_HYM8563=m
CONFIG_RTC_DRV_MAX8907=y
+CONFIG_RTC_DRV_MAX8997=m
CONFIG_RTC_DRV_MAX77686=y
CONFIG_RTC_DRV_RK808=m
CONFIG_RTC_DRV_MAX77802=m
@@ -613,6 +674,7 @@ CONFIG_RTC_DRV_TPS65910=y
CONFIG_RTC_DRV_S35390A=m
CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_EM3027=y
+CONFIG_RTC_DRV_DA9063=m
CONFIG_RTC_DRV_DIGICOLOR=m
CONFIG_RTC_DRV_S5M=m
CONFIG_RTC_DRV_S3C=m
@@ -628,10 +690,12 @@ CONFIG_DMADEVICES=y
CONFIG_DW_DMAC=y
CONFIG_AT_HDMAC=y
CONFIG_AT_XDMAC=y
+CONFIG_FSL_EDMA=m
CONFIG_MV_XOR=y
CONFIG_TEGRA20_APB_DMA=y
CONFIG_SH_DMAE=y
CONFIG_RCAR_DMAC=y
+CONFIG_RENESAS_USB_DMAC=m
CONFIG_STE_DMA40=y
CONFIG_SIRF_DMA=y
CONFIG_TI_EDMA=y
@@ -653,14 +717,20 @@ CONFIG_NVEC_POWER=y
CONFIG_NVEC_PAZ00=y
CONFIG_QCOM_GSBI=y
CONFIG_QCOM_PM=y
+CONFIG_QCOM_SMEM=y
CONFIG_QCOM_SMD=y
CONFIG_QCOM_SMD_RPM=y
-CONFIG_QCOM_SMEM=y
+CONFIG_QCOM_SMP2P=y
+CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_WCNSS_CTRL=m
+CONFIG_ROCKCHIP_PM_DOMAINS=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_CHROME_PLATFORMS=y
+CONFIG_STAGING_BOARD=y
CONFIG_CROS_EC_CHARDEV=m
CONFIG_COMMON_CLK_MAX77686=y
CONFIG_COMMON_CLK_MAX77802=m
+CONFIG_COMMON_CLK_RK808=m
CONFIG_COMMON_CLK_S2MPS11=m
CONFIG_APQ_MMCC_8084=y
CONFIG_MSM_GCC_8660=y
@@ -684,6 +754,7 @@ CONFIG_AK8975=y
CONFIG_PWM=y
CONFIG_PWM_ATMEL=m
CONFIG_PWM_ATMEL_TCB=m
+CONFIG_PWM_FSL_FTM=m
CONFIG_PWM_RENESAS_TPU=y
CONFIG_PWM_ROCKCHIP=m
CONFIG_PWM_SAMSUNG=m
@@ -706,6 +777,8 @@ CONFIG_PHY_STIH407_USB=y
CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_SUN9I_USB=y
CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SUNXI_SID=y
CONFIG_EXT4_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
@@ -732,6 +805,7 @@ CONFIG_CRYPTO_DEV_TEGRA_AES=y
CONFIG_CPUFREQ_DT=y
CONFIG_KEYSTONE_IRQ=y
CONFIG_CRYPTO_DEV_SUN4I_SS=m
+CONFIG_CRYPTO_DEV_ROCKCHIP=m
CONFIG_ARM_CRYPTO=y
CONFIG_CRYPTO_SHA1_ARM=m
CONFIG_CRYPTO_SHA1_ARM_NEON=m
@@ -746,3 +820,7 @@ CONFIG_CRYPTO_GHASH_ARM_CE=m
CONFIG_CRYPTO_DEV_ATMEL_AES=m
CONFIG_CRYPTO_DEV_ATMEL_TDES=m
CONFIG_CRYPTO_DEV_ATMEL_SHA=m
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTIO_MMIO=y
diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig
index 85d10d2e3d66..a0345e1ce172 100644
--- a/arch/arm/configs/mv78xx0_defconfig
+++ b/arch/arm/configs/mv78xx0_defconfig
@@ -11,6 +11,9 @@ CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_MULTI_V5=y
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_MV78XX0=y
CONFIG_MACH_DB78X00_BP=y
CONFIG_MACH_RD78X00_MASA=y
@@ -132,7 +135,6 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_LL_UART_8250=y
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig
index 824de499237b..af29780accdc 100644
--- a/arch/arm/configs/mvebu_v5_defconfig
+++ b/arch/arm/configs/mvebu_v5_defconfig
@@ -12,8 +12,29 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_MVEBU=y
CONFIG_MACH_KIRKWOOD=y
-CONFIG_MACH_NETXBIG=y
-# CONFIG_CPU_FEROCEON_OLD_ID is not set
+CONFIG_ARCH_ORION5X=y
+CONFIG_MACH_DB88F5281=y
+CONFIG_MACH_RD88F5182=y
+CONFIG_MACH_RD88F5182_DT=y
+CONFIG_MACH_KUROBOX_PRO=y
+CONFIG_MACH_DNS323=y
+CONFIG_MACH_TS209=y
+CONFIG_MACH_TERASTATION_PRO2=y
+CONFIG_MACH_LINKSTATION_PRO=y
+CONFIG_MACH_LINKSTATION_LSCHL=y
+CONFIG_MACH_LINKSTATION_MINI=y
+CONFIG_MACH_LINKSTATION_LS_HGL=y
+CONFIG_MACH_TS409=y
+CONFIG_MACH_WRT350N_V2=y
+CONFIG_MACH_TS78XX=y
+CONFIG_MACH_MV2120=y
+CONFIG_MACH_D2NET_DT=y
+CONFIG_MACH_NET2BIG=y
+CONFIG_MACH_MSS2_DT=y
+CONFIG_MACH_WNR854T=y
+CONFIG_MACH_RD88F5181L_GE=y
+CONFIG_MACH_RD88F5181L_FXO=y
+CONFIG_MACH_RD88F6183AP_GE=y
CONFIG_PCI_MVEBU=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
@@ -26,6 +47,7 @@ CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
+CONFIG_ARM_KIRKWOOD_CPUIDLE=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -35,6 +57,8 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IPV6 is not set
+CONFIG_NET_DSA=y
+CONFIG_NET_SWITCHDEV=y
CONFIG_NET_PKTGEN=m
CONFIG_CFG80211=y
CONFIG_MAC80211=y
@@ -66,8 +90,11 @@ CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6131=y
CONFIG_NET_DSA_MV88E6123_61_65=y
CONFIG_NET_DSA_MV88E6171=y
+CONFIG_NET_DSA_MV88E6352=y
CONFIG_MV643XX_ETH=y
CONFIG_R8169=y
CONFIG_MARVELL_PHY=y
@@ -91,7 +118,6 @@ CONFIG_I2C_MV64XXX=y
CONFIG_SPI=y
CONFIG_SPI_ORION=y
CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO=y
CONFIG_POWER_RESET_QNAP=y
@@ -103,16 +129,15 @@ CONFIG_SENSORS_LM85=y
CONFIG_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_ORION_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_FB=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_KIRKWOOD_SOC=y
-CONFIG_SND_KIRKWOOD_SOC_T5325=y
CONFIG_SND_SOC_ALC5623=y
CONFIG_SND_SIMPLE_CARD=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_HID_DRAGONRISE=y
CONFIG_HID_GYRATION=y
CONFIG_HID_TWINHAN=y
@@ -159,8 +184,6 @@ CONFIG_STAGING=y
CONFIG_FB_XGI=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_EXT4_FS=y
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_UDF_FS=m
@@ -186,7 +209,6 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_DEV_MV_CESA=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/netwinder_defconfig b/arch/arm/configs/netwinder_defconfig
index 25ed772dfb2f..4f3dfb21772b 100644
--- a/arch/arm/configs/netwinder_defconfig
+++ b/arch/arm/configs/netwinder_defconfig
@@ -5,6 +5,7 @@ CONFIG_ARCH_FOOTBRIDGE=y
CONFIG_ARCH_NETWINDER=y
CONFIG_LEDS=y
CONFIG_LEDS_CPU=y
+CONFIG_DEPRECATED_PARAM_STRUCT=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE="root=0x301"
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig
index 8099417a9466..5876ce7af130 100644
--- a/arch/arm/configs/orion5x_defconfig
+++ b/arch/arm/configs/orion5x_defconfig
@@ -13,6 +13,9 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y
CONFIG_BSD_DISKLABEL=y
+CONFIG_ARCH_MULTI_V5=y
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_ORION5X=y
CONFIG_ARCH_ORION5X_DT=y
CONFIG_MACH_DB88F5281=y
@@ -159,7 +162,6 @@ CONFIG_LATENCYTOP=y
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_LL_UART_8250=y
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig
new file mode 100644
index 000000000000..0cb724b5c639
--- /dev/null
+++ b/arch/arm/configs/pxa_defconfig
@@ -0,0 +1,783 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=13
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLOB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_LDM_PARTITION=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_ARCH_PXA=y
+CONFIG_MACH_PXA27X_DT=y
+CONFIG_MACH_PXA3XX_DT=y
+CONFIG_ARCH_LUBBOCK=y
+CONFIG_MACH_MAINSTONE=y
+CONFIG_MACH_ZYLONITE300=y
+CONFIG_MACH_ZYLONITE320=y
+CONFIG_MACH_LITTLETON=y
+CONFIG_MACH_TAVOREVB=y
+CONFIG_MACH_SAAR=y
+CONFIG_ARCH_PXA_IDP=y
+CONFIG_ARCH_VIPER=y
+CONFIG_MACH_ARCOM_ZEUS=y
+CONFIG_MACH_BALLOON3=y
+CONFIG_MACH_CSB726=y
+CONFIG_CSB726_CSB701=y
+CONFIG_MACH_ARMCORE=y
+CONFIG_MACH_EM_X270=y
+CONFIG_MACH_EXEDA=y
+CONFIG_MACH_CM_X300=y
+CONFIG_MACH_CAPC7117=y
+CONFIG_ARCH_GUMSTIX=y
+CONFIG_MACH_INTELMOTE2=y
+CONFIG_MACH_STARGATE2=y
+CONFIG_MACH_XCEP=y
+CONFIG_TRIZEPS_PXA=y
+CONFIG_MACH_TRIZEPS4WL=y
+CONFIG_MACH_LOGICPD_PXA270=y
+CONFIG_MACH_PCM027=y
+CONFIG_MACH_PCM990_BASEBOARD=y
+CONFIG_MACH_COLIBRI=y
+CONFIG_MACH_COLIBRI_PXA270_INCOME=y
+CONFIG_MACH_COLIBRI300=y
+CONFIG_MACH_COLIBRI320=y
+CONFIG_MACH_COLIBRI_EVALBOARD=y
+CONFIG_MACH_VPAC270=y
+CONFIG_MACH_H4700=y
+CONFIG_MACH_H5000=y
+CONFIG_MACH_HIMALAYA=y
+CONFIG_MACH_MAGICIAN=y
+CONFIG_MACH_MIOA701=y
+CONFIG_PXA_EZX=y
+CONFIG_MACH_MP900C=y
+CONFIG_ARCH_PXA_PALM=y
+CONFIG_MACH_RAUMFELD_RC=y
+CONFIG_MACH_RAUMFELD_CONNECTOR=y
+CONFIG_MACH_RAUMFELD_SPEAKER=y
+CONFIG_PXA_SHARPSL=y
+CONFIG_MACH_POODLE=y
+CONFIG_MACH_CORGI=y
+CONFIG_MACH_SHEPHERD=y
+CONFIG_MACH_HUSKY=y
+CONFIG_MACH_AKITA=y
+CONFIG_MACH_BORZOI=y
+CONFIG_MACH_TOSA=y
+CONFIG_TOSA_BT=m
+CONFIG_TOSA_USE_EXT_KEYCODES=y
+CONFIG_MACH_ICONTROL=y
+CONFIG_ARCH_PXA_ESERIES=y
+CONFIG_MACH_ZIPIT2=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCCARD=m
+CONFIG_YENTA=m
+CONFIG_PCMCIA_PXA2XX=m
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_COMPACTION is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 ro"
+CONFIG_KEXEC=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPUFREQ_DT=m
+CONFIG_ARM_PXA2xx_CPUFREQ=m
+CONFIG_CPU_IDLE=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_IEEE802154=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+CONFIG_IRTTY_SIR=m
+CONFIG_PXA_FICP=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_REG_DEBUG=y
+CONFIG_MAC80211=m
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_GPIO=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=0
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_AFS_PARTS=m
+CONFIG_MTD_OF_PARTS=m
+CONFIG_MTD_AR7_PARTS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_LE_BYTE_SWAP=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_OTP=y
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PXA2XX=m
+CONFIG_MTD_M25P80=m
+CONFIG_MTD_BLOCK2MTD=y
+CONFIG_MTD_DOCG3=m
+CONFIG_MTD_NAND=m
+CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_NAND_GPIO=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
+CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
+CONFIG_MTD_NAND_SHARPSL=m
+CONFIG_MTD_NAND_PXA3xx=m
+CONFIG_MTD_NAND_CM_X270=m
+CONFIG_MTD_NAND_TMIO=m
+CONFIG_MTD_NAND_BRCMNAND=m
+CONFIG_MTD_NAND_PLATFORM=m
+CONFIG_MTD_ONENAND=m
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_GENERIC=m
+CONFIG_MTD_SPI_NOR=m
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=8
+CONFIG_AD525X_DPOT=m
+CONFIG_AD525X_DPOT_I2C=m
+CONFIG_ICS932S401=m
+CONFIG_APDS9802ALS=m
+CONFIG_ISL29003=m
+CONFIG_TI_DAC7512=m
+CONFIG_EEPROM_AT24=m
+CONFIG_SENSORS_LIS3_SPI=m
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=y
+CONFIG_ATA=m
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_SATA_MV=m
+CONFIG_PATA_PXA=m
+CONFIG_PATA_PCMCIA=m
+CONFIG_PATA_PLATFORM=m
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_MACB=m
+CONFIG_DM9000=m
+CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+CONFIG_IGB=m
+CONFIG_KS8851=y
+CONFIG_AX88796=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_8139TOO=m
+CONFIG_R8169=m
+CONFIG_SMC91X=m
+CONFIG_SMSC911X=m
+CONFIG_STMMAC_ETH=m
+CONFIG_PHYLIB=y
+CONFIG_AT803X_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_BROADCOM_PHY=y
+CONFIG_ICPLUS_PHY=m
+CONFIG_MICREL_PHY=m
+CONFIG_FIXED_PHY=m
+CONFIG_MDIO_BITBANG=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_BRCMFMAC=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_CS=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_HERMES=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_PCMCIA_SPECTRUM=m
+CONFIG_RT2X00=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_INPUT_FF_MEMLESS=m
+CONFIG_INPUT_POLLDEV=y
+CONFIG_INPUT_MATRIXKMAP=y
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_APMPOWER=m
+CONFIG_KEYBOARD_ATKBD=m
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_PXA27x=m
+CONFIG_KEYBOARD_PXA930_ROTARY=m
+CONFIG_KEYBOARD_CROS_EC=m
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_CYAPA=m
+CONFIG_MOUSE_ELAN_I2C=m
+CONFIG_MOUSE_PXA930_TRKBALL=m
+CONFIG_MOUSE_NAVPOINT_PXA27x=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_DA9034=m
+CONFIG_TOUCHSCREEN_EETI=m
+CONFIG_TOUCHSCREEN_FUJITSU=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+CONFIG_TOUCHSCREEN_HTCPEN=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+CONFIG_TOUCHSCREEN_UCB1400=m
+CONFIG_TOUCHSCREEN_WM97XX=m
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+CONFIG_TOUCHSCREEN_PCAP=m
+CONFIG_TOUCHSCREEN_ST1232=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MPU3050=m
+CONFIG_INPUT_AXP20X_PEK=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_PCAP=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_SERIO=m
+CONFIG_SERIO_SA1111=m
+CONFIG_LEGACY_PTY_COUNT=8
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=7
+CONFIG_SERIAL_8250_RUNTIME_UARTS=7
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_DESIGNWARE_PLATFORM=m
+CONFIG_I2C_PXA_SLAVE=y
+CONFIG_I2C_XILINX=m
+CONFIG_I2C_CROS_EC_TUNNEL=m
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_CADENCE=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_PXA2XX=m
+CONFIG_SPI_ROCKCHIP=m
+CONFIG_SPI_XILINX=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_PPS=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_DWAPB=m
+CONFIG_GPIO_GENERIC_PLATFORM=m
+CONFIG_GPIO_MAX732X=m
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_PALMAS=y
+CONFIG_GPIO_TPS6586X=y
+CONFIG_GPIO_TPS65910=y
+CONFIG_GPIO_MAX7301=m
+CONFIG_POWER_SUPPLY_DEBUG=y
+CONFIG_PDA_POWER=m
+CONFIG_BATTERY_SBS=m
+CONFIG_BATTERY_DA9030=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_MAX17042=m
+CONFIG_CHARGER_MAX14577=m
+CONFIG_CHARGER_MAX77693=m
+CONFIG_CHARGER_TPS65090=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_MAX6650=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM95245=m
+CONFIG_SENSORS_NTC_THERMISTOR=m
+CONFIG_THERMAL=m
+CONFIG_WATCHDOG=y
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_SA1100_WATCHDOG=m
+CONFIG_MFD_AS3711=y
+CONFIG_MFD_BCM590XX=m
+CONFIG_MFD_AXP20X=y
+CONFIG_MFD_CROS_EC=m
+CONFIG_MFD_CROS_EC_I2C=m
+CONFIG_MFD_CROS_EC_SPI=m
+CONFIG_MFD_ASIC3=y
+CONFIG_PMIC_DA903X=y
+CONFIG_HTC_EGPIO=y
+CONFIG_HTC_PASIC3=m
+CONFIG_MFD_MAX14577=y
+CONFIG_MFD_MAX77693=y
+CONFIG_MFD_MAX8907=m
+CONFIG_EZX_PCAP=y
+CONFIG_UCB1400_CORE=m
+CONFIG_MFD_PM8921_CORE=m
+CONFIG_MFD_SEC_CORE=y
+CONFIG_MFD_PALMAS=y
+CONFIG_MFD_TPS65090=y
+CONFIG_MFD_TPS6586X=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_T7L66XB=y
+CONFIG_MFD_TC6387XB=y
+CONFIG_MFD_TC6393XB=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_REGULATOR_ACT8865=m
+CONFIG_REGULATOR_AS3711=m
+CONFIG_REGULATOR_AXP20X=m
+CONFIG_REGULATOR_BCM590XX=m
+CONFIG_REGULATOR_DA903X=m
+CONFIG_REGULATOR_DA9210=m
+CONFIG_REGULATOR_FAN53555=m
+CONFIG_REGULATOR_GPIO=m
+CONFIG_REGULATOR_MAX14577=m
+CONFIG_REGULATOR_MAX8660=m
+CONFIG_REGULATOR_MAX8907=m
+CONFIG_REGULATOR_MAX8973=m
+CONFIG_REGULATOR_MAX77693=m
+CONFIG_REGULATOR_PALMAS=m
+CONFIG_REGULATOR_PCAP=m
+CONFIG_REGULATOR_PWM=m
+CONFIG_REGULATOR_S2MPS11=m
+CONFIG_REGULATOR_S5M8767=m
+CONFIG_REGULATOR_TPS51632=m
+CONFIG_REGULATOR_TPS62360=m
+CONFIG_REGULATOR_TPS65090=m
+CONFIG_REGULATOR_TPS6586X=m
+CONFIG_REGULATOR_TPS65910=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_PLATFORM=m
+CONFIG_VIDEO_PXA27x=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_SOC_CAMERA_MT9M111=m
+CONFIG_DRM=m
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_PXA_OVERLAY=y
+CONFIG_FB_PXA_PARAMETERS=y
+CONFIG_PXA3XX_GCU=m
+CONFIG_FB_MBX=m
+CONFIG_FB_VIRTUAL=m
+CONFIG_FB_SIMPLE=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CORGI=m
+CONFIG_LCD_PLATFORM=m
+CONFIG_LCD_TOSA=m
+CONFIG_BACKLIGHT_PWM=m
+CONFIG_BACKLIGHT_TOSA=m
+CONFIG_FRAMEBUFFER_CONSOLE=m
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_PXA2XX_AC97=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=m
+CONFIG_SND_ATMEL_SOC=m
+CONFIG_SND_PXA2XX_SOC=m
+CONFIG_SND_PXA2XX_SOC_CORGI=m
+CONFIG_SND_PXA2XX_SOC_SPITZ=m
+CONFIG_SND_PXA2XX_SOC_Z2=m
+CONFIG_SND_PXA2XX_SOC_POODLE=m
+CONFIG_SND_PXA2XX_SOC_TOSA=m
+CONFIG_SND_PXA2XX_SOC_E740=m
+CONFIG_SND_PXA2XX_SOC_E750=m
+CONFIG_SND_PXA2XX_SOC_E800=m
+CONFIG_SND_PXA2XX_SOC_EM_X270=m
+CONFIG_SND_PXA2XX_SOC_PALM27X=y
+CONFIG_SND_SOC_ZYLONITE=m
+CONFIG_SND_SOC_RAUMFELD=m
+CONFIG_SND_PXA2XX_SOC_HX4700=m
+CONFIG_SND_PXA2XX_SOC_MAGICIAN=m
+CONFIG_SND_PXA2XX_SOC_MIOA701=m
+CONFIG_SND_PXA2XX_SOC_IMOTE2=m
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_WM8978=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SOUND_PRIME=m
+CONFIG_HID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB=m
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=m
+CONFIG_USB_XHCI_HCD=m
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_HCD_PLATFORM=m
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_PLATFORM=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_CS=m
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_DWC3=m
+CONFIG_USB_DWC2=m
+CONFIG_USB_CHIPIDEA=m
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_ISP1760=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_GPIO_VBUS=y
+CONFIG_USB_ISP1301=m
+CONFIG_USB_GADGET=m
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_PXA25X=m
+CONFIG_USB_PXA27X=m
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+# CONFIG_USB_ETH_RNDIS is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_MMC=m
+CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_SDIO_UART=m
+CONFIG_MMC_PXA=m
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+CONFIG_MMC_TMIO=m
+CONFIG_MMC_DW=m
+CONFIG_MMC_DW_EXYNOS=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_DA903X=m
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_LT3593=m
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DEBUG=y
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_MAX8907=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_PALMAS=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_TPS6586X=m
+CONFIG_RTC_DRV_TPS65910=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_S5M=m
+CONFIG_RTC_DRV_V3020=m
+CONFIG_RTC_DRV_PXA=m
+CONFIG_RTC_DRV_PCAP=m
+CONFIG_DMADEVICES=y
+CONFIG_PXA_DMA=y
+CONFIG_DW_DMAC=m
+CONFIG_UIO=y
+CONFIG_CROS_EC_CHARDEV=m
+CONFIG_COMMON_CLK_S2MPS11=m
+CONFIG_PM_DEVFREQ=y
+CONFIG_EXTCON=y
+CONFIG_MEMORY=y
+CONFIG_PWM=y
+CONFIG_PWM_PXA=m
+CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_XFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_CACHEFILES=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-15"
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=1
+CONFIG_JFFS2_FS_WBUF_VERIFY=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_UBIFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_ROMFS_FS=m
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_UTF8=m
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=0
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_TIMER_STATS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_DEBUG_USER=y
+CONFIG_SECURITY=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM=m
+CONFIG_CRYPTO_SHA256_ARM=m
+CONFIG_CRYPTO_SHA512_ARM=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=m
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_6x11=y
+CONFIG_FONT_MINI_4x6=y
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index ee54a706e8a3..7bff7bf24a85 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -1,8 +1,10 @@
CONFIG_SYSVIPC=y
+CONFIG_FHANDLE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS_ALL=y
@@ -22,10 +24,10 @@ CONFIG_ARCH_MSM8X60=y
CONFIG_ARCH_MSM8960=y
CONFIG_ARCH_MSM8974=y
CONFIG_SMP=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
-CONFIG_HIGHPTE=y
CONFIG_CLEANCACHE=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
@@ -78,10 +80,14 @@ CONFIG_USB_USBNET=y
# CONFIG_USB_NET_ZAURUS is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_PMIC8XXX=y
# CONFIG_MOUSE_PS2 is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PM8XXX_VIBRATOR=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
CONFIG_INPUT_UINPUT=y
CONFIG_SERIO_LIBPS2=y
# CONFIG_LEGACY_PTYS is not set
@@ -99,13 +105,18 @@ CONFIG_PINCTRL_APQ8084=y
CONFIG_PINCTRL_IPQ8064=y
CONFIG_PINCTRL_MSM8960=y
CONFIG_PINCTRL_MSM8X74=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_PINCTRL_QCOM_SSBI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
+CONFIG_CHARGER_QCOM_SMBB=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_MSM=y
CONFIG_THERMAL=y
+CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_QCOM_RPM=y
+CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_QCOM_RPM=y
@@ -136,6 +147,7 @@ CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PM8XXX=y
CONFIG_DMADEVICES=y
CONFIG_QCOM_BAM_DMA=y
CONFIG_STAGING=y
@@ -149,9 +161,9 @@ CONFIG_MSM_MMCC_8974=y
CONFIG_HWSPINLOCK_QCOM=y
CONFIG_QCOM_GSBI=y
CONFIG_QCOM_PM=y
+CONFIG_QCOM_SMEM=y
CONFIG_QCOM_SMD=y
CONFIG_QCOM_SMD_RPM=y
-CONFIG_QCOM_SMEM=y
CONFIG_PHY_QCOM_APQ8064_SATA=y
CONFIG_PHY_QCOM_IPQ806X_SATA=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/realview-smp_defconfig b/arch/arm/configs/realview-smp_defconfig
index 1da5d9e48224..93efdcfcf98f 100644
--- a/arch/arm/configs/realview-smp_defconfig
+++ b/arch/arm/configs/realview-smp_defconfig
@@ -1,19 +1,29 @@
-CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_PERF_EVENTS=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MULTI_V6=y
CONFIG_ARCH_REALVIEW=y
+CONFIG_REALVIEW_DT=y
CONFIG_MACH_REALVIEW_EB=y
+CONFIG_REALVIEW_EB_ARM1136=y
+CONFIG_REALVIEW_EB_ARM1176=y
+CONFIG_REALVIEW_EB_A9MP=y
CONFIG_REALVIEW_EB_ARM11MP=y
+CONFIG_REALVIEW_EB_ARM11MP_REVB=y
CONFIG_MACH_REALVIEW_PB11MP=y
+CONFIG_MACH_REALVIEW_PB1176=y
+CONFIG_MACH_REALVIEW_PBA8=y
+CONFIG_MACH_REALVIEW_PBX=y
CONFIG_SMP=y
-CONFIG_HOTPLUG_CPU=y
CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
@@ -30,28 +40,24 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_IPV6 is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
+CONFIG_MTD_AFS_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_ROM=y
CONFIG_MTD_PHYSMAP=y
CONFIG_ARM_CHARLCD=y
CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_SMSC_PHY=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_AMBAKMI=y
+CONFIG_LEGACY_PTY_COUNT=16
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_VERSATILE=y
@@ -70,8 +76,8 @@ CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
# CONFIG_SND_DRIVERS is not set
CONFIG_SND_ARMAACI=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_ISP1760=y
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
@@ -87,17 +93,13 @@ CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_CRAMFS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig
index d02e9d911bb7..8f56fb3ff51d 100644
--- a/arch/arm/configs/realview_defconfig
+++ b/arch/arm/configs/realview_defconfig
@@ -1,18 +1,26 @@
-CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_PERF_EVENTS=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MULTI_V6=y
CONFIG_ARCH_REALVIEW=y
+CONFIG_REALVIEW_DT=y
CONFIG_MACH_REALVIEW_EB=y
+CONFIG_REALVIEW_EB_ARM1136=y
+CONFIG_REALVIEW_EB_ARM1176=y
+CONFIG_REALVIEW_EB_A9MP=y
CONFIG_REALVIEW_EB_ARM11MP=y
+CONFIG_REALVIEW_EB_ARM11MP_REVB=y
CONFIG_MACH_REALVIEW_PB11MP=y
CONFIG_MACH_REALVIEW_PB1176=y
+CONFIG_MACH_REALVIEW_PBA8=y
+CONFIG_MACH_REALVIEW_PBX=y
CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
@@ -29,28 +37,24 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_IPV6 is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
+CONFIG_MTD_AFS_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_ROM=y
CONFIG_MTD_PHYSMAP=y
CONFIG_ARM_CHARLCD=y
CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_SMSC_PHY=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_AMBAKMI=y
+CONFIG_LEGACY_PTY_COUNT=16
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_VERSATILE=y
@@ -69,8 +73,8 @@ CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
# CONFIG_SND_DRIVERS is not set
CONFIG_SND_ARMAACI=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_ISP1760=y
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
@@ -86,17 +90,13 @@ CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_CRAMFS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arm/configs/s3c6400_defconfig b/arch/arm/configs/s3c6400_defconfig
index e2f9fa5bb54b..e0f66936ae02 100644
--- a/arch/arm/configs/s3c6400_defconfig
+++ b/arch/arm/configs/s3c6400_defconfig
@@ -5,6 +5,8 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_MULTI_V6=y
+# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_S3C64XX=y
CONFIG_S3C_BOOT_ERROR_RESET=y
CONFIG_MACH_SMDK6400=y
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index 63f7e6ce649a..c11bab735125 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -129,6 +129,9 @@ CONFIG_GPIO_SYSFS=y
CONFIG_POWER_SUPPLY=y
CONFIG_POWER_RESET=y
# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
+CONFIG_SAMA5D4_WATCHDOG=y
CONFIG_MFD_ATMEL_FLEXCOM=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index 3aef019c0de7..969738324a5d 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -2,14 +2,13 @@ CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
CONFIG_SLAB=y
-CONFIG_ARCH_SHMOBILE_MULTI=y
+CONFIG_ARCH_RENESAS=y
CONFIG_ARCH_EMEV2=y
CONFIG_ARCH_R7S72100=y
CONFIG_ARCH_R8A73A4=y
@@ -53,6 +52,8 @@ CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
+CONFIG_CAN=y
+CONFIG_CAN_RCAR=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -99,6 +100,7 @@ CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_NR_UARTS=20
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_EMEV2=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_RIIC=y
CONFIG_I2C_SH_MOBILE=y
@@ -135,6 +137,7 @@ CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_VIDEO_RCAR_VIN=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_JPU=y
CONFIG_VIDEO_RENESAS_VSP1=y
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
CONFIG_VIDEO_ADV7180=y
@@ -150,6 +153,7 @@ CONFIG_FB_SH_MOBILE_MERAM=y
# CONFIG_BACKLIGHT_GENERIC is not set
CONFIG_BACKLIGHT_PWM=y
CONFIG_BACKLIGHT_AS3711=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
@@ -163,7 +167,6 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_R8A66597_HCD=y
CONFIG_USB_RENESAS_USBHS=y
-CONFIG_USB_RCAR_PHY=y
CONFIG_USB_GADGET=y
CONFIG_USB_RENESAS_USBHS_UDC=y
CONFIG_USB_ETH=y
@@ -177,9 +180,13 @@ CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_RS5C372=y
CONFIG_RTC_DRV_S35390A=y
CONFIG_RTC_DRV_RX8581=y
+CONFIG_RTC_DRV_DA9063=y
CONFIG_DMADEVICES=y
CONFIG_SH_DMAE=y
CONFIG_RCAR_DMAC=y
+CONFIG_RENESAS_USB_DMAC=y
+CONFIG_STAGING=y
+CONFIG_STAGING_BOARD=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_IIO=y
CONFIG_AK8975=y
@@ -199,6 +206,7 @@ CONFIG_NFS_V4_1=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_ARM_UNWIND is not set
diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig
index 8128b93ed72c..f7f4e2e3cc33 100644
--- a/arch/arm/configs/socfpga_defconfig
+++ b/arch/arm/configs/socfpga_defconfig
@@ -36,7 +36,6 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
-CONFIG_IPV6=y
CONFIG_NETWORK_PHY_TIMESTAMPING=y
CONFIG_VLAN_8021Q=y
CONFIG_VLAN_8021Q_GVRP=y
@@ -57,7 +56,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
CONFIG_STMMAC_ETH=y
-CONFIG_DWMAC_SOCFPGA=y
CONFIG_MICREL_PHY=y
CONFIG_INPUT_EVDEV=y
# CONFIG_SERIO_SERPORT is not set
@@ -83,7 +81,8 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_USB=y
CONFIG_USB_DWC2=y
-CONFIG_USB_DWC2_HOST=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_GADGET=y
CONFIG_MMC=y
CONFIG_MMC_DW=y
CONFIG_FPGA=y
@@ -92,7 +91,6 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT3_FS=y
-CONFIG_EXT4_FS=y
CONFIG_VFAT_FS=y
CONFIG_NTFS_FS=y
CONFIG_NTFS_RW=y
diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
index 4725fab562cb..ec5250547d14 100644
--- a/arch/arm/configs/stm32_defconfig
+++ b/arch/arm/configs/stm32_defconfig
@@ -54,6 +54,8 @@ CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_DMADEVICES=y
+CONFIG_STM32_DMA=y
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index b503a89441bf..a9a81a714be4 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -11,14 +11,12 @@ CONFIG_SMP=y
CONFIG_NR_CPUS=8
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
-CONFIG_HIGHPTE=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CPU_FREQ=y
CONFIG_CPUFREQ_DT=y
CONFIG_VFP=y
CONFIG_NEON=y
-CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -37,7 +35,6 @@ CONFIG_CAN_SUN4I=y
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_EEPROM_SUNXI_SID=y
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
CONFIG_AHCI_SUNXI=y
@@ -61,13 +58,12 @@ CONFIG_STMMAC_ETH=y
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
+CONFIG_KEYBOARD_SUN4I_LRADC=y
# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_AXP20X_PEK=y
CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_KEYBOARD_SUN4I_LRADC=y
CONFIG_TOUCHSCREEN_SUN4I=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AXP20X_PEK=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=8
@@ -90,6 +86,8 @@ CONFIG_CPU_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_SUNXI_WATCHDOG=y
CONFIG_MFD_AXP20X=y
+CONFIG_MFD_AXP20X_I2C=y
+CONFIG_MFD_AXP20X_RSB=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_AXP20X=y
@@ -124,6 +122,8 @@ CONFIG_PWM=y
CONFIG_PWM_SUN4I=y
CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_SUN9I_USB=y
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SUNXI_SID=y
CONFIG_EXT4_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig
index ea49d37564da..295408ea9dc7 100644
--- a/arch/arm/configs/versatile_defconfig
+++ b/arch/arm/configs/versatile_defconfig
@@ -1,13 +1,15 @@
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_VERSATILE=y
-CONFIG_MACH_VERSATILE_AB=y
CONFIG_AEABI=y
CONFIG_OABI_COMPAT=y
CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -47,9 +49,12 @@ CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_PL061=y
# CONFIG_HWMON is not set
+CONFIG_MFD_SYSCON=y
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -59,13 +64,15 @@ CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
CONFIG_SND_ARMAACI=m
CONFIG_MMC=y
-CONFIG_MMC_ARMMMCI=m
+CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_VERSATILE=y
+CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
CONFIG_EXT2_FS=y
CONFIG_VFAT_FS=m
CONFIG_JFFS2_FS=y
@@ -82,6 +89,5 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_LL_UART_PL01X=y
CONFIG_FONTS=y
CONFIG_FONT_ACORN_8x8=y
diff --git a/arch/arm/configs/zx_defconfig b/arch/arm/configs/zx_defconfig
index b200bb0fecdd..ab683fbbb954 100644
--- a/arch/arm/configs/zx_defconfig
+++ b/arch/arm/configs/zx_defconfig
@@ -83,7 +83,6 @@ CONFIG_MMC=y
CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_DW=y
-CONFIG_MMC_DW_IDMAC=y
CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h
index 3ff5642d9788..112cc1a5d47f 100644
--- a/arch/arm/include/asm/barrier.h
+++ b/arch/arm/include/asm/barrier.h
@@ -60,38 +60,11 @@ extern void arm_heavy_mb(void);
#define dma_wmb() barrier()
#endif
-#ifndef CONFIG_SMP
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#else
-#define smp_mb() dmb(ish)
-#define smp_rmb() smp_mb()
-#define smp_wmb() dmb(ishst)
-#endif
-
-#define smp_store_release(p, v) \
-do { \
- compiletime_assert_atomic_type(*p); \
- smp_mb(); \
- WRITE_ONCE(*p, v); \
-} while (0)
-
-#define smp_load_acquire(p) \
-({ \
- typeof(*p) ___p1 = READ_ONCE(*p); \
- compiletime_assert_atomic_type(*p); \
- smp_mb(); \
- ___p1; \
-})
-
-#define read_barrier_depends() do { } while(0)
-#define smp_read_barrier_depends() do { } while(0)
-
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
+#define __smp_mb() dmb(ish)
+#define __smp_rmb() __smp_mb()
+#define __smp_wmb() dmb(ishst)
-#define smp_mb__before_atomic() smp_mb()
-#define smp_mb__after_atomic() smp_mb()
+#include <asm-generic/barrier.h>
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_BARRIER_H */
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 85e374f873ac..b23c6c81c9ad 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -228,10 +228,26 @@ static inline int cpu_is_xsc3(void)
}
#endif
-#if !defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_CPU_XSC3)
-#define cpu_is_xscale() 0
+#if !defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_CPU_XSC3) && \
+ !defined(CONFIG_CPU_MOHAWK)
+#define cpu_is_xscale_family() 0
#else
-#define cpu_is_xscale() 1
+static inline int cpu_is_xscale_family(void)
+{
+ unsigned int id;
+ id = read_cpuid_id() & 0xffffe000;
+
+ switch (id) {
+ case 0x69052000: /* Intel XScale 1 */
+ case 0x69054000: /* Intel XScale 2 */
+ case 0x69056000: /* Intel XScale 3 */
+ case 0x56056000: /* Marvell XScale 3 */
+ case 0x56158000: /* Marvell Mohawk */
+ return 1;
+ }
+
+ return 0;
+}
#endif
/*
diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h
index 662c7bd06108..e1f07764b0d6 100644
--- a/arch/arm/include/asm/div64.h
+++ b/arch/arm/include/asm/div64.h
@@ -5,9 +5,9 @@
#include <asm/compiler.h>
/*
- * The semantics of do_div() are:
+ * The semantics of __div64_32() are:
*
- * uint32_t do_div(uint64_t *n, uint32_t base)
+ * uint32_t __div64_32(uint64_t *n, uint32_t base)
* {
* uint32_t remainder = *n % base;
* *n = *n / base;
@@ -16,8 +16,9 @@
*
* In other words, a 64-bit dividend with a 32-bit divisor producing
* a 64-bit result and a 32-bit remainder. To accomplish this optimally
- * we call a special __do_div64 helper with completely non standard
- * calling convention for arguments and results (beware).
+ * we override the generic version in lib/div64.c to call our __do_div64
+ * assembly implementation with completely non standard calling convention
+ * for arguments and results (beware).
*/
#ifdef __ARMEB__
@@ -28,199 +29,101 @@
#define __xh "r1"
#endif
-#define __do_div_asm(n, base) \
-({ \
- register unsigned int __base asm("r4") = base; \
- register unsigned long long __n asm("r0") = n; \
- register unsigned long long __res asm("r2"); \
- register unsigned int __rem asm(__xh); \
- asm( __asmeq("%0", __xh) \
- __asmeq("%1", "r2") \
- __asmeq("%2", "r0") \
- __asmeq("%3", "r4") \
- "bl __do_div64" \
- : "=r" (__rem), "=r" (__res) \
- : "r" (__n), "r" (__base) \
- : "ip", "lr", "cc"); \
- n = __res; \
- __rem; \
-})
-
-#if __GNUC__ < 4 || !defined(CONFIG_AEABI)
+static inline uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+ register unsigned int __base asm("r4") = base;
+ register unsigned long long __n asm("r0") = *n;
+ register unsigned long long __res asm("r2");
+ register unsigned int __rem asm(__xh);
+ asm( __asmeq("%0", __xh)
+ __asmeq("%1", "r2")
+ __asmeq("%2", "r0")
+ __asmeq("%3", "r4")
+ "bl __do_div64"
+ : "=r" (__rem), "=r" (__res)
+ : "r" (__n), "r" (__base)
+ : "ip", "lr", "cc");
+ *n = __res;
+ return __rem;
+}
+#define __div64_32 __div64_32
+
+#if !defined(CONFIG_AEABI)
/*
- * gcc versions earlier than 4.0 are simply too problematic for the
- * optimized implementation below. First there is gcc PR 15089 that
- * tend to trig on more complex constructs, spurious .global __udivsi3
- * are inserted even if none of those symbols are referenced in the
- * generated code, and those gcc versions are not able to do constant
- * propagation on long long values anyway.
+ * In OABI configurations, some uses of the do_div function
+ * cause gcc to run out of registers. To work around that,
+ * we can force the use of the out-of-line version for
+ * configurations that build a OABI kernel.
*/
-#define do_div(n, base) __do_div_asm(n, base)
-
-#elif __GNUC__ >= 4
+#define do_div(n, base) __div64_32(&(n), base)
-#include <asm/bug.h>
+#else
/*
- * If the divisor happens to be constant, we determine the appropriate
- * inverse at compile time to turn the division into a few inline
- * multiplications instead which is much faster. And yet only if compiling
- * for ARMv4 or higher (we need umull/umlal) and if the gcc version is
- * sufficiently recent to perform proper long long constant propagation.
- * (It is unfortunate that gcc doesn't perform all this internally.)
+ * gcc versions earlier than 4.0 are simply too problematic for the
+ * __div64_const32() code in asm-generic/div64.h. First there is
+ * gcc PR 15089 that tend to trig on more complex constructs, spurious
+ * .global __udivsi3 are inserted even if none of those symbols are
+ * referenced in the generated code, and those gcc versions are not able
+ * to do constant propagation on long long values anyway.
*/
-#define do_div(n, base) \
-({ \
- unsigned int __r, __b = (base); \
- if (!__builtin_constant_p(__b) || __b == 0 || \
- (__LINUX_ARM_ARCH__ < 4 && (__b & (__b - 1)) != 0)) { \
- /* non-constant divisor (or zero): slow path */ \
- __r = __do_div_asm(n, __b); \
- } else if ((__b & (__b - 1)) == 0) { \
- /* Trivial: __b is constant and a power of 2 */ \
- /* gcc does the right thing with this code. */ \
- __r = n; \
- __r &= (__b - 1); \
- n /= __b; \
- } else { \
- /* Multiply by inverse of __b: n/b = n*(p/b)/p */ \
- /* We rely on the fact that most of this code gets */ \
- /* optimized away at compile time due to constant */ \
- /* propagation and only a couple inline assembly */ \
- /* instructions should remain. Better avoid any */ \
- /* code construct that might prevent that. */ \
- unsigned long long __res, __x, __t, __m, __n = n; \
- unsigned int __c, __p, __z = 0; \
- /* preserve low part of n for reminder computation */ \
- __r = __n; \
- /* determine number of bits to represent __b */ \
- __p = 1 << __div64_fls(__b); \
- /* compute __m = ((__p << 64) + __b - 1) / __b */ \
- __m = (~0ULL / __b) * __p; \
- __m += (((~0ULL % __b + 1) * __p) + __b - 1) / __b; \
- /* compute __res = __m*(~0ULL/__b*__b-1)/(__p << 64) */ \
- __x = ~0ULL / __b * __b - 1; \
- __res = (__m & 0xffffffff) * (__x & 0xffffffff); \
- __res >>= 32; \
- __res += (__m & 0xffffffff) * (__x >> 32); \
- __t = __res; \
- __res += (__x & 0xffffffff) * (__m >> 32); \
- __t = (__res < __t) ? (1ULL << 32) : 0; \
- __res = (__res >> 32) + __t; \
- __res += (__m >> 32) * (__x >> 32); \
- __res /= __p; \
- /* Now sanitize and optimize what we've got. */ \
- if (~0ULL % (__b / (__b & -__b)) == 0) { \
- /* those cases can be simplified with: */ \
- __n /= (__b & -__b); \
- __m = ~0ULL / (__b / (__b & -__b)); \
- __p = 1; \
- __c = 1; \
- } else if (__res != __x / __b) { \
- /* We can't get away without a correction */ \
- /* to compensate for bit truncation errors. */ \
- /* To avoid it we'd need an additional bit */ \
- /* to represent __m which would overflow it. */ \
- /* Instead we do m=p/b and n/b=(n*m+m)/p. */ \
- __c = 1; \
- /* Compute __m = (__p << 64) / __b */ \
- __m = (~0ULL / __b) * __p; \
- __m += ((~0ULL % __b + 1) * __p) / __b; \
- } else { \
- /* Reduce __m/__p, and try to clear bit 31 */ \
- /* of __m when possible otherwise that'll */ \
- /* need extra overflow handling later. */ \
- unsigned int __bits = -(__m & -__m); \
- __bits |= __m >> 32; \
- __bits = (~__bits) << 1; \
- /* If __bits == 0 then setting bit 31 is */ \
- /* unavoidable. Simply apply the maximum */ \
- /* possible reduction in that case. */ \
- /* Otherwise the MSB of __bits indicates the */ \
- /* best reduction we should apply. */ \
- if (!__bits) { \
- __p /= (__m & -__m); \
- __m /= (__m & -__m); \
- } else { \
- __p >>= __div64_fls(__bits); \
- __m >>= __div64_fls(__bits); \
- } \
- /* No correction needed. */ \
- __c = 0; \
- } \
- /* Now we have a combination of 2 conditions: */ \
- /* 1) whether or not we need a correction (__c), and */ \
- /* 2) whether or not there might be an overflow in */ \
- /* the cross product (__m & ((1<<63) | (1<<31))) */ \
- /* Select the best insn combination to perform the */ \
- /* actual __m * __n / (__p << 64) operation. */ \
- if (!__c) { \
- asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" \
- "mov %Q0, #0" \
- : "=&r" (__res) \
- : "r" (__m), "r" (__n) \
- : "cc" ); \
- } else if (!(__m & ((1ULL << 63) | (1ULL << 31)))) { \
- __res = __m; \
- asm ( "umlal %Q0, %R0, %Q1, %Q2\n\t" \
- "mov %Q0, #0" \
- : "+&r" (__res) \
- : "r" (__m), "r" (__n) \
- : "cc" ); \
- } else { \
- asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" \
- "cmn %Q0, %Q1\n\t" \
- "adcs %R0, %R0, %R1\n\t" \
- "adc %Q0, %3, #0" \
- : "=&r" (__res) \
- : "r" (__m), "r" (__n), "r" (__z) \
- : "cc" ); \
- } \
- if (!(__m & ((1ULL << 63) | (1ULL << 31)))) { \
- asm ( "umlal %R0, %Q0, %R1, %Q2\n\t" \
- "umlal %R0, %Q0, %Q1, %R2\n\t" \
- "mov %R0, #0\n\t" \
- "umlal %Q0, %R0, %R1, %R2" \
- : "+&r" (__res) \
- : "r" (__m), "r" (__n) \
- : "cc" ); \
- } else { \
- asm ( "umlal %R0, %Q0, %R2, %Q3\n\t" \
- "umlal %R0, %1, %Q2, %R3\n\t" \
- "mov %R0, #0\n\t" \
- "adds %Q0, %1, %Q0\n\t" \
- "adc %R0, %R0, #0\n\t" \
- "umlal %Q0, %R0, %R2, %R3" \
- : "+&r" (__res), "+&r" (__z) \
- : "r" (__m), "r" (__n) \
- : "cc" ); \
- } \
- __res /= __p; \
- /* The reminder can be computed with 32-bit regs */ \
- /* only, and gcc is good at that. */ \
- { \
- unsigned int __res0 = __res; \
- unsigned int __b0 = __b; \
- __r -= __res0 * __b0; \
- } \
- /* BUG_ON(__r >= __b || __res * __b + __r != n); */ \
- n = __res; \
- } \
- __r; \
-})
-
-/* our own fls implementation to make sure constant propagation is fine */
-#define __div64_fls(bits) \
-({ \
- unsigned int __left = (bits), __nr = 0; \
- if (__left & 0xffff0000) __nr += 16, __left >>= 16; \
- if (__left & 0x0000ff00) __nr += 8, __left >>= 8; \
- if (__left & 0x000000f0) __nr += 4, __left >>= 4; \
- if (__left & 0x0000000c) __nr += 2, __left >>= 2; \
- if (__left & 0x00000002) __nr += 1; \
- __nr; \
-})
+
+#define __div64_const32_is_OK (__GNUC__ >= 4)
+
+static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias)
+{
+ unsigned long long res;
+ unsigned int tmp = 0;
+
+ if (!bias) {
+ asm ( "umull %Q0, %R0, %Q1, %Q2\n\t"
+ "mov %Q0, #0"
+ : "=&r" (res)
+ : "r" (m), "r" (n)
+ : "cc");
+ } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
+ res = m;
+ asm ( "umlal %Q0, %R0, %Q1, %Q2\n\t"
+ "mov %Q0, #0"
+ : "+&r" (res)
+ : "r" (m), "r" (n)
+ : "cc");
+ } else {
+ asm ( "umull %Q0, %R0, %Q1, %Q2\n\t"
+ "cmn %Q0, %Q1\n\t"
+ "adcs %R0, %R0, %R1\n\t"
+ "adc %Q0, %3, #0"
+ : "=&r" (res)
+ : "r" (m), "r" (n), "r" (tmp)
+ : "cc");
+ }
+
+ if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
+ asm ( "umlal %R0, %Q0, %R1, %Q2\n\t"
+ "umlal %R0, %Q0, %Q1, %R2\n\t"
+ "mov %R0, #0\n\t"
+ "umlal %Q0, %R0, %R1, %R2"
+ : "+&r" (res)
+ : "r" (m), "r" (n)
+ : "cc");
+ } else {
+ asm ( "umlal %R0, %Q0, %R2, %Q3\n\t"
+ "umlal %R0, %1, %Q2, %R3\n\t"
+ "mov %R0, #0\n\t"
+ "adds %Q0, %1, %Q0\n\t"
+ "adc %R0, %R0, #0\n\t"
+ "umlal %Q0, %R0, %R2, %R3"
+ : "+&r" (res), "+&r" (tmp)
+ : "r" (m), "r" (n)
+ : "cc");
+ }
+
+ return res;
+}
+#define __arch_xprod_64 __arch_xprod_64
+
+#include <asm-generic/div64.h>
#endif
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 9203c21b4673..a520b7987a29 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -182,7 +182,8 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
}
-static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
+ kvm_pfn_t pfn,
unsigned long size,
bool ipa_uncached)
{
@@ -246,7 +247,7 @@ static inline void __kvm_flush_dcache_pte(pte_t pte)
static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
{
unsigned long size = PMD_SIZE;
- pfn_t pfn = pmd_pfn(pmd);
+ kvm_pfn_t pfn = pmd_pfn(pmd);
while (size) {
void *va = kmap_atomic_pfn(pfn);
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index a745a2a53853..dc46398bc3a5 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -88,7 +88,6 @@
#define L_PMD_SECT_VALID (_AT(pmdval_t, 1) << 0)
#define L_PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
-#define L_PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 56)
#define L_PMD_SECT_NONE (_AT(pmdval_t, 1) << 57)
#define L_PMD_SECT_RDONLY (_AT(pteval_t, 1) << 58)
@@ -232,13 +231,6 @@ static inline pte_t pte_mkspecial(pte_t pte)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !pmd_table(pmd))
-#define pmd_trans_splitting(pmd) (pmd_isset((pmd), L_PMD_SECT_SPLITTING))
-
-#ifdef CONFIG_HAVE_RCU_TABLE_FREE
-#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp);
-#endif
#endif
#define PMD_BIT_FUNC(fn,op) \
@@ -246,9 +238,9 @@ static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
PMD_BIT_FUNC(wrprotect, |= L_PMD_SECT_RDONLY);
PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
-PMD_BIT_FUNC(mksplitting, |= L_PMD_SECT_SPLITTING);
PMD_BIT_FUNC(mkwrite, &= ~L_PMD_SECT_RDONLY);
PMD_BIT_FUNC(mkdirty, |= L_PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkclean, &= ~L_PMD_SECT_DIRTY);
PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
index b4c6d99364f1..e1b825dfab23 100644
--- a/arch/arm/include/asm/psci.h
+++ b/arch/arm/include/asm/psci.h
@@ -14,7 +14,7 @@
#ifndef __ASM_ARM_PSCI_H
#define __ASM_ARM_PSCI_H
-extern struct smp_operations psci_smp_ops;
+extern const struct smp_operations psci_smp_ops;
#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
bool psci_smp_available(void);
diff --git a/arch/arm/mach-footbridge/include/mach/debug-macro.S b/arch/arm/include/debug/dc21285.S
index 02247f313e94..02247f313e94 100644
--- a/arch/arm/mach-footbridge/include/mach/debug-macro.S
+++ b/arch/arm/include/debug/dc21285.S
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 65addcbf5b30..2e26016a91a5 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -211,7 +211,7 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
{
const struct machine_desc *mdesc, *mdesc_best = NULL;
-#ifdef CONFIG_ARCH_MULTIPLATFORM
+#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
MACHINE_END
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c
index 097e2e201b9f..0c7efc3446c0 100644
--- a/arch/arm/kernel/module-plts.c
+++ b/arch/arm/kernel/module-plts.c
@@ -32,7 +32,7 @@ struct plt_entries {
static bool in_init(const struct module *mod, u32 addr)
{
- return addr - (u32)mod->module_init < mod->init_size;
+ return addr - (u32)mod->init_layout.base < mod->init_layout.size;
}
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c
index 9d479b2ea40d..cb3fcaeb2233 100644
--- a/arch/arm/kernel/psci_smp.c
+++ b/arch/arm/kernel/psci_smp.c
@@ -120,7 +120,7 @@ bool __init psci_smp_available(void)
return (psci_ops.cpu_on != NULL);
}
-struct smp_operations __initdata psci_smp_ops = {
+const struct smp_operations psci_smp_ops __initconst = {
.smp_boot_secondary = psci_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_disable = psci_cpu_disable,
diff --git a/arch/arm/kernel/xscale-cp0.c b/arch/arm/kernel/xscale-cp0.c
index bdbb8853a19b..77a2eef72115 100644
--- a/arch/arm/kernel/xscale-cp0.c
+++ b/arch/arm/kernel/xscale-cp0.c
@@ -15,6 +15,9 @@
#include <linux/init.h>
#include <linux/io.h>
#include <asm/thread_notify.h>
+#include <asm/cputype.h>
+
+asm(" .arch armv5te\n");
static inline void dsp_save_state(u32 *state)
{
@@ -152,6 +155,10 @@ static int __init xscale_cp0_init(void)
{
u32 cp_access;
+ /* do not attempt to probe iwmmxt on non-xscale family CPUs */
+ if (!cpu_is_xscale_family())
+ return 0;
+
cp_access = xscale_cp_access_read() & ~3;
xscale_cp_access_write(cp_access | 1);
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 22f7fa0124ec..aba61fd3697a 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -992,9 +992,9 @@ out:
return ret;
}
-static bool transparent_hugepage_adjust(pfn_t *pfnp, phys_addr_t *ipap)
+static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap)
{
- pfn_t pfn = *pfnp;
+ kvm_pfn_t pfn = *pfnp;
gfn_t gfn = *ipap >> PAGE_SHIFT;
if (PageTransCompound(pfn_to_page(pfn))) {
@@ -1201,7 +1201,7 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
kvm_mmu_write_protect_pt_masked(kvm, slot, gfn_offset, mask);
}
-static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, kvm_pfn_t pfn,
unsigned long size, bool uncached)
{
__coherent_cache_guest_page(vcpu, pfn, size, uncached);
@@ -1218,7 +1218,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
struct kvm *kvm = vcpu->kvm;
struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
struct vm_area_struct *vma;
- pfn_t pfn;
+ kvm_pfn_t pfn;
pgprot_t mem_type = PAGE_S2;
bool fault_ipa_uncached;
bool logging_active = memslot_is_logging(memslot);
@@ -1346,7 +1346,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
{
pmd_t *pmd;
pte_t *pte;
- pfn_t pfn;
+ kvm_pfn_t pfn;
bool pfn_valid = false;
trace_kvm_access_fault(fault_ipa);
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index 588bbc288396..6bd1089b07e0 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -52,14 +52,13 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
*
* Lock the page table for the destination and check
* to see that it's still huge and whether or not we will
- * need to fault on write, or if we have a splitting THP.
+ * need to fault on write.
*/
if (unlikely(pmd_thp_or_huge(*pmd))) {
ptl = &current->mm->page_table_lock;
spin_lock(ptl);
if (unlikely(!pmd_thp_or_huge(*pmd)
- || pmd_hugewillfault(*pmd)
- || pmd_trans_splitting(*pmd))) {
+ || pmd_hugewillfault(*pmd))) {
spin_unlock(ptl);
return 0;
}
diff --git a/arch/arm/mach-alpine/Kconfig b/arch/arm/mach-alpine/Kconfig
index 2c44b930505a..5c2d54f59f53 100644
--- a/arch/arm/mach-alpine/Kconfig
+++ b/arch/arm/mach-alpine/Kconfig
@@ -1,5 +1,6 @@
config ARCH_ALPINE
- bool "Annapurna Labs Alpine platform" if ARCH_MULTI_V7
+ bool "Annapurna Labs Alpine platform"
+ depends on ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
select GENERIC_IRQ_CHIP
diff --git a/arch/arm/mach-alpine/platsmp.c b/arch/arm/mach-alpine/platsmp.c
index f78429f48bd6..dd77ea25e7ca 100644
--- a/arch/arm/mach-alpine/platsmp.c
+++ b/arch/arm/mach-alpine/platsmp.c
@@ -42,7 +42,7 @@ static void __init alpine_smp_prepare_cpus(unsigned int max_cpus)
alpine_cpu_pm_init();
}
-static struct smp_operations alpine_smp_ops __initdata = {
+static const struct smp_operations alpine_smp_ops __initconst = {
.smp_prepare_cpus = alpine_smp_prepare_cpus,
.smp_boot_secondary = alpine_boot_secondary,
};
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 28656c2b54a0..23be2e433097 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -8,7 +8,8 @@ menuconfig ARCH_AT91
if ARCH_AT91
config SOC_SAMA5D2
- bool "SAMA5D2 family" if ARCH_MULTI_V7
+ bool "SAMA5D2 family"
+ depends on ARCH_MULTI_V7
select SOC_SAMA5
select CACHE_L2X0
select HAVE_FB_ATMEL
@@ -21,7 +22,8 @@ config SOC_SAMA5D2
Select this if ou are using one of Atmel's SAMA5D2 family SoC.
config SOC_SAMA5D3
- bool "SAMA5D3 family" if ARCH_MULTI_V7
+ bool "SAMA5D3 family"
+ depends on ARCH_MULTI_V7
select SOC_SAMA5
select HAVE_FB_ATMEL
select HAVE_AT91_UTMI
@@ -33,7 +35,8 @@ config SOC_SAMA5D3
This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35, SAMA5D36.
config SOC_SAMA5D4
- bool "SAMA5D4 family" if ARCH_MULTI_V7
+ bool "SAMA5D4 family"
+ depends on ARCH_MULTI_V7
select SOC_SAMA5
select CACHE_L2X0
select HAVE_FB_ATMEL
@@ -46,7 +49,8 @@ config SOC_SAMA5D4
Select this if you are using one of Atmel's SAMA5D4 family SoC.
config SOC_AT91RM9200
- bool "AT91RM9200" if ARCH_MULTI_V4T
+ bool "AT91RM9200"
+ depends on ARCH_MULTI_V4T
select ATMEL_AIC_IRQ
select ATMEL_ST
select CPU_ARM920T
@@ -59,7 +63,8 @@ config SOC_AT91RM9200
Select this if you are using Atmel's AT91RM9200 SoC.
config SOC_AT91SAM9
- bool "AT91SAM9" if ARCH_MULTI_V5
+ bool "AT91SAM9"
+ depends on ARCH_MULTI_V5
select ATMEL_AIC_IRQ
select ATMEL_SDRAMC
select CPU_ARM926T
diff --git a/arch/arm/mach-axxia/Kconfig b/arch/arm/mach-axxia/Kconfig
index 8be7e0ae1922..6c6d5e76565b 100644
--- a/arch/arm/mach-axxia/Kconfig
+++ b/arch/arm/mach-axxia/Kconfig
@@ -1,5 +1,6 @@
config ARCH_AXXIA
- bool "LSI Axxia platforms" if (ARCH_MULTI_V7 && ARM_LPAE)
+ bool "LSI Axxia platforms"
+ depends on ARCH_MULTI_V7 && ARM_LPAE
select ARCH_DMA_ADDR_T_64BIT
select ARM_AMBA
select ARM_GIC
diff --git a/arch/arm/mach-axxia/platsmp.c b/arch/arm/mach-axxia/platsmp.c
index 959d4df3d2b6..ffbd71d45008 100644
--- a/arch/arm/mach-axxia/platsmp.c
+++ b/arch/arm/mach-axxia/platsmp.c
@@ -82,7 +82,7 @@ static void __init axxia_smp_prepare_cpus(unsigned int max_cpus)
}
}
-static struct smp_operations axxia_smp_ops __initdata = {
+static const struct smp_operations axxia_smp_ops __initconst = {
.smp_prepare_cpus = axxia_smp_prepare_cpus,
.smp_boot_secondary = axxia_boot_secondary,
};
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 8c53c55be1fe..7ef121472cdd 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_BCM
- bool "Broadcom SoC Support" if ARCH_MULTI_V6_V7
+ bool "Broadcom SoC Support"
+ depends on ARCH_MULTI_V6_V7
help
This enables support for Broadcom ARM based SoC chips
@@ -27,7 +28,8 @@ config ARCH_BCM_IPROC
Currently supported SoCs are Cygnus.
config ARCH_BCM_CYGNUS
- bool "Broadcom Cygnus Support" if ARCH_MULTI_V7
+ bool "Broadcom Cygnus Support"
+ depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
help
Enable support for the Cygnus family,
@@ -36,10 +38,13 @@ config ARCH_BCM_CYGNUS
BCM58300, BCM58302, BCM58303, BCM58305.
config ARCH_BCM_NSP
- bool "Broadcom Northstar Plus SoC Support" if ARCH_MULTI_V7
+ bool "Broadcom Northstar Plus SoC Support"
+ depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
select ARM_ERRATA_754322
select ARM_ERRATA_775420
+ select ARM_ERRATA_764369 if SMP
+ select HAVE_SMP
help
Support for Broadcom Northstar Plus SoC.
Broadcom Northstar Plus family of SoCs are used for switching control
@@ -50,8 +55,14 @@ config ARCH_BCM_NSP
NAND flash, SATA and several other IO controllers.
config ARCH_BCM_5301X
- bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
+ bool "Broadcom BCM470X / BCM5301X ARM SoC"
+ depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
+ select ARM_ERRATA_754322
+ select ARM_ERRATA_775420
+ select ARM_ERRATA_764369 if SMP
+ select HAVE_SMP
+
help
Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
@@ -82,7 +93,8 @@ config ARCH_BCM_MOBILE
This enables support for systems based on Broadcom mobile SoCs.
config ARCH_BCM_281XX
- bool "Broadcom BCM281XX SoC family" if ARCH_MULTI_V7
+ bool "Broadcom BCM281XX SoC family"
+ depends on ARCH_MULTI_V7
select ARCH_BCM_MOBILE
select HAVE_SMP
help
@@ -91,7 +103,8 @@ config ARCH_BCM_281XX
variants.
config ARCH_BCM_21664
- bool "Broadcom BCM21664 SoC family" if ARCH_MULTI_V7
+ bool "Broadcom BCM21664 SoC family"
+ depends on ARCH_MULTI_V7
select ARCH_BCM_MOBILE
select HAVE_SMP
help
@@ -122,20 +135,23 @@ config ARCH_BCM_MOBILE_SMP
comment "Other Architectures"
config ARCH_BCM2835
- bool "Broadcom BCM2835 family" if ARCH_MULTI_V6
+ bool "Broadcom BCM2835 family"
+ depends on ARCH_MULTI_V6 || ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
- select ARM_ERRATA_411920
+ select ARM_ERRATA_411920 if ARCH_MULTI_V6
select ARM_TIMER_SP804
+ select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
select CLKSRC_OF
select PINCTRL
select PINCTRL_BCM2835
help
- This enables support for the Broadcom BCM2835 SoC. This SoC is
- used in the Raspberry Pi and Roku 2 devices.
+ This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
+ This SoC is used in the Raspberry Pi and Roku 2 devices.
config ARCH_BCM_63XX
- bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7
+ bool "Broadcom BCM63xx DSL SoC"
+ depends on ARCH_MULTI_V7
depends on MMU
select ARM_ERRATA_754322
select ARM_ERRATA_764369 if SMP
@@ -152,7 +168,8 @@ config ARCH_BCM_63XX
the BCM63138 variant.
config ARCH_BRCMSTB
- bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7
+ bool "Broadcom BCM7XXX based boards"
+ depends on ARCH_MULTI_V7
select ARM_GIC
select ARM_ERRATA_798181 if SMP
select HAVE_ARM_ARCH_TIMER
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 892261fec0ae..7d665151c772 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -14,7 +14,11 @@
obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
# Northstar Plus
-obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
+obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
+
+ifeq ($(CONFIG_ARCH_BCM_NSP),y)
+obj-$(CONFIG_SMP) += platsmp.o
+endif
# BCM281XX
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
@@ -23,7 +27,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
# BCM281XX and BCM21664 SMP support
-obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
+obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
# BCM281XX and BCM21664 L2 cache control
obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
@@ -39,6 +43,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2835.o
# BCM5301X
obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
+ifeq ($(CONFIG_ARCH_BCM_5301X),y)
+obj-$(CONFIG_SMP) += platsmp.o
+endif
# BCM63XXx
ifeq ($(CONFIG_ARCH_BCM_63XX),y)
diff --git a/arch/arm/mach-bcm/bcm63xx_smp.c b/arch/arm/mach-bcm/bcm63xx_smp.c
index 19be90421f4d..9b6727ed68cd 100644
--- a/arch/arm/mach-bcm/bcm63xx_smp.c
+++ b/arch/arm/mach-bcm/bcm63xx_smp.c
@@ -161,7 +161,7 @@ static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
}
}
-struct smp_operations bcm63138_smp_ops __initdata = {
+static const struct smp_operations bcm63138_smp_ops __initconst = {
.smp_prepare_cpus = bcm63138_smp_prepare_cpus,
.smp_boot_secondary = bcm63138_smp_boot_secondary,
};
diff --git a/arch/arm/mach-bcm/bcm_5301x.c b/arch/arm/mach-bcm/bcm_5301x.c
index 5478fe6bcce6..c8830a2b0d60 100644
--- a/arch/arm/mach-bcm/bcm_5301x.c
+++ b/arch/arm/mach-bcm/bcm_5301x.c
@@ -9,40 +9,6 @@
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
-#include <asm/siginfo.h>
-#include <asm/signal.h>
-
-
-static bool first_fault = true;
-
-static int bcm5301x_abort_handler(unsigned long addr, unsigned int fsr,
- struct pt_regs *regs)
-{
- if ((fsr == 0x1406 || fsr == 0x1c06) && first_fault) {
- first_fault = false;
-
- /*
- * These faults with codes 0x1406 (BCM4709) or 0x1c06 happens
- * for no good reason, possibly left over from the CFE boot
- * loader.
- */
- pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n",
- addr, fsr);
-
- /* Returning non-zero causes fault display and panic */
- return 0;
- }
-
- /* Others should cause a fault */
- return 1;
-}
-
-static void __init bcm5301x_init_early(void)
-{
- /* Install our hook */
- hook_fault_code(16 + 6, bcm5301x_abort_handler, SIGBUS, BUS_OBJERR,
- "imprecise external abort");
-}
static const char *const bcm5301x_dt_compat[] __initconst = {
"brcm,bcm4708",
@@ -52,6 +18,5 @@ static const char *const bcm5301x_dt_compat[] __initconst = {
DT_MACHINE_START(BCM5301X, "BCM5301X")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
- .init_early = bcm5301x_init_early,
.dt_compat = bcm5301x_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-bcm/board_bcm2835.c b/arch/arm/mach-bcm/board_bcm2835.c
index 0f7b9eac3d15..834d67684e20 100644
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -36,7 +36,12 @@ static void __init bcm2835_init(void)
}
static const char * const bcm2835_compat[] = {
+#ifdef CONFIG_ARCH_MULTI_V6
"brcm,bcm2835",
+#endif
+#ifdef CONFIG_ARCH_MULTI_V7
+ "brcm,bcm2836",
+#endif
NULL
};
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c
index 44d6bddf7a4e..40dc8448445e 100644
--- a/arch/arm/mach-bcm/platsmp-brcmstb.c
+++ b/arch/arm/mach-bcm/platsmp-brcmstb.c
@@ -356,7 +356,7 @@ static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
return 0;
}
-static struct smp_operations brcmstb_smp_ops __initdata = {
+static const struct smp_operations brcmstb_smp_ops __initconst = {
.smp_prepare_cpus = brcmstb_cpu_ctrl_setup,
.smp_boot_secondary = brcmstb_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-bcm/kona_smp.c b/arch/arm/mach-bcm/platsmp.c
index 66a0465528a5..575defcc53f9 100644
--- a/arch/arm/mach-bcm/kona_smp.c
+++ b/arch/arm/mach-bcm/platsmp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2015 Broadcom Corporation
* Copyright 2014 Linaro Limited
*
* This program is free software; you can redistribute it and/or
@@ -12,12 +12,17 @@
* GNU General Public License for more details.
*/
-#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/io.h>
+#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/sched.h>
+#include <linux/smp.h>
+#include <asm/cacheflush.h>
#include <asm/smp.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
@@ -30,9 +35,10 @@
/* Name of device node property defining secondary boot register location */
#define OF_SECONDARY_BOOT "secondary-boot-reg"
+#define MPIDR_CPUID_BITMASK 0x3
/* I/O address of register used to coordinate secondary core startup */
-static u32 secondary_boot;
+static u32 secondary_boot_addr;
/*
* Enable the Cortex A9 Snoop Control Unit
@@ -75,47 +81,101 @@ static int __init scu_a9_enable(void)
return 0;
}
+static int nsp_write_lut(void)
+{
+ void __iomem *sku_rom_lut;
+ phys_addr_t secondary_startup_phy;
+
+ if (!secondary_boot_addr) {
+ pr_warn("required secondary boot register not specified\n");
+ return -EINVAL;
+ }
+
+ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr,
+ sizeof(secondary_boot_addr));
+ if (!sku_rom_lut) {
+ pr_warn("unable to ioremap SKU-ROM LUT register\n");
+ return -ENOMEM;
+ }
+
+ secondary_startup_phy = virt_to_phys(secondary_startup);
+ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
+
+ writel_relaxed(secondary_startup_phy, sku_rom_lut);
+
+ /* Ensure the write is visible to the secondary core */
+ smp_wmb();
+
+ iounmap(sku_rom_lut);
+
+ return 0;
+}
+
static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
{
static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
- struct device_node *node;
+ struct device_node *cpus_node = NULL;
+ struct device_node *cpu_node = NULL;
int ret;
- BUG_ON(secondary_boot); /* We're called only once */
-
/*
* This function is only called via smp_ops->smp_prepare_cpu().
* That only happens if a "/cpus" device tree node exists
* and has an "enable-method" property that selects the SMP
* operations defined herein.
*/
- node = of_find_node_by_path("/cpus");
- BUG_ON(!node);
+ cpus_node = of_find_node_by_path("/cpus");
+ if (!cpus_node)
+ return;
- /*
- * Our secondary enable method requires a "secondary-boot-reg"
- * property to specify a register address used to request the
- * ROM code boot a secondary code. If we have any trouble
- * getting this we fall back to uniprocessor mode.
- */
- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
- node->name);
- ret = -ENOENT; /* Arrange to disable SMP */
- goto out;
+ for_each_child_of_node(cpus_node, cpu_node) {
+ u32 cpuid;
+
+ if (of_node_cmp(cpu_node->type, "cpu"))
+ continue;
+
+ if (of_property_read_u32(cpu_node, "reg", &cpuid)) {
+ pr_debug("%s: missing reg property\n",
+ cpu_node->full_name);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /*
+ * "secondary-boot-reg" property should be defined only
+ * for secondary cpu
+ */
+ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) {
+ /*
+ * Our secondary enable method requires a
+ * "secondary-boot-reg" property to specify a register
+ * address used to request the ROM code boot a secondary
+ * core. If we have any trouble getting this we fall
+ * back to uniprocessor mode.
+ */
+ if (of_property_read_u32(cpu_node,
+ OF_SECONDARY_BOOT,
+ &secondary_boot_addr)) {
+ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n",
+ cpu_node->name);
+ ret = -ENOENT;
+ goto out;
+ }
+ }
}
/*
- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
+ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
* returned, the SoC reported a uniprocessor configuration.
* We bail on any other error.
*/
ret = scu_a9_enable();
out:
- of_node_put(node);
+ of_node_put(cpu_node);
+ of_node_put(cpus_node);
+
if (ret) {
/* Update the CPU present map to reflect uniprocessor mode */
- BUG_ON(ret != -ENOENT);
pr_warn("disabling SMP\n");
init_cpu_present(&only_cpu_0);
}
@@ -139,7 +199,7 @@ out:
* - Wait for the secondary boot register to be re-written, which
* indicates the secondary core has started.
*/
-static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
+static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
void __iomem *boot_reg;
phys_addr_t boot_func;
@@ -154,15 +214,16 @@ static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
return -EINVAL;
}
- if (!secondary_boot) {
+ if (!secondary_boot_addr) {
pr_err("required secondary boot register not specified\n");
return -EINVAL;
}
- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
+ boot_reg = ioremap_nocache(
+ (phys_addr_t)secondary_boot_addr, sizeof(u32));
if (!boot_reg) {
pr_err("unable to map boot register for cpu %u\n", cpu_id);
- return -ENOSYS;
+ return -ENOMEM;
}
/*
@@ -191,12 +252,39 @@ static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
pr_err("timeout waiting for cpu %u to start\n", cpu_id);
- return -ENOSYS;
+ return -ENXIO;
}
-static struct smp_operations bcm_smp_ops __initdata = {
+static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ int ret;
+
+ /*
+ * After wake up, secondary core branches to the startup
+ * address programmed at SKU ROM LUT location.
+ */
+ ret = nsp_write_lut();
+ if (ret) {
+ pr_err("unable to write startup addr to SKU ROM LUT\n");
+ goto out;
+ }
+
+ /* Send a CPU wakeup interrupt to the secondary core */
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+out:
+ return ret;
+}
+
+static const struct smp_operations bcm_smp_ops __initconst = {
.smp_prepare_cpus = bcm_smp_prepare_cpus,
- .smp_boot_secondary = bcm_boot_secondary,
+ .smp_boot_secondary = kona_boot_secondary,
};
CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
&bcm_smp_ops);
+
+struct smp_operations nsp_smp_ops __initdata = {
+ .smp_prepare_cpus = bcm_smp_prepare_cpus,
+ .smp_boot_secondary = nsp_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);
diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig
index 742d53a5f7f9..ffbfa0bd091b 100644
--- a/arch/arm/mach-berlin/Kconfig
+++ b/arch/arm/mach-berlin/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_BERLIN
- bool "Marvell Berlin SoCs" if ARCH_MULTI_V7
+ bool "Marvell Berlin SoCs"
+ depends on ARCH_MULTI_V7
select ARCH_HAS_RESET_CONTROLLER
select ARCH_REQUIRE_GPIOLIB
select ARM_GIC
diff --git a/arch/arm/mach-berlin/platsmp.c b/arch/arm/mach-berlin/platsmp.c
index 405cd37e4fba..93f90688db18 100644
--- a/arch/arm/mach-berlin/platsmp.c
+++ b/arch/arm/mach-berlin/platsmp.c
@@ -119,7 +119,7 @@ static int berlin_cpu_kill(unsigned int cpu)
}
#endif
-static struct smp_operations berlin_smp_ops __initdata = {
+static const struct smp_operations berlin_smp_ops __initconst = {
.smp_prepare_cpus = berlin_smp_prepare_cpus,
.smp_boot_secondary = berlin_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-clps711x/board-autcpu12.c b/arch/arm/mach-clps711x/board-autcpu12.c
index c3d964221767..ba3d7d1b28f8 100644
--- a/arch/arm/mach-clps711x/board-autcpu12.c
+++ b/arch/arm/mach-clps711x/board-autcpu12.c
@@ -31,7 +31,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand-gpio.h>
#include <linux/platform_device.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <mach/hardware.h>
#include <asm/sizes.h>
diff --git a/arch/arm/mach-clps711x/board-p720t.c b/arch/arm/mach-clps711x/board-p720t.c
index e68dd629bda2..80a16a8b3776 100644
--- a/arch/arm/mach-clps711x/board-p720t.c
+++ b/arch/arm/mach-clps711x/board-p720t.c
@@ -28,7 +28,7 @@
#include <linux/leds.h>
#include <linux/sizes.h>
#include <linux/backlight.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand-gpio.h>
diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig
index 3c22a1990ecd..eb14a0ff0093 100644
--- a/arch/arm/mach-cns3xxx/Kconfig
+++ b/arch/arm/mach-cns3xxx/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_CNS3XXX
- bool "Cavium Networks CNS3XXX family" if ARCH_MULTI_V6
+ bool "Cavium Networks CNS3XXX family"
+ depends on ARCH_MULTI_V6
select ARM_GIC
select PCI_DOMAINS if PCI
help
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index dd8f5312b2c0..bcaf1d025505 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -34,7 +34,8 @@ config ARCH_DAVINCI_DA830
bool "DA830/OMAP-L137/AM17x based system"
depends on !ARCH_DAVINCI_DMx || AUTO_ZRELADDR
select ARCH_DAVINCI_DA8XX
- select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
+ # needed on silicon revs 1.0, 1.1:
+ select CPU_DCACHE_WRITETHROUGH if !CPU_DCACHE_DISABLE
select CP_INTC
config ARCH_DAVINCI_DA850
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index f8f62fbaa915..3d8cf8cbd98a 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -32,7 +32,7 @@
#include <asm/mach/arch.h>
#include <mach/common.h>
-#include <mach/cp_intc.h>
+#include "cp_intc.h"
#include <mach/mux.h>
#include <mach/da8xx.h>
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 9cc7b818fbf6..8e4539f69fdc 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -40,10 +40,10 @@
#include <linux/spi/flash.h>
#include <mach/common.h>
-#include <mach/cp_intc.h>
+#include "cp_intc.h"
#include <mach/da8xx.h>
#include <mach/mux.h>
-#include <mach/sram.h>
+#include "sram.h"
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index c71dd9982f03..1844076f6403 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -384,9 +384,7 @@ static __init void dm355_evm_init(void)
dm355evm_dm9000_rsrc[2].start = gpio_to_irq(1);
aemif = clk_get(&dm355evm_dm9000.dev, "aemif");
- if (IS_ERR(aemif))
- WARN("%s: unable to get AEMIF clock\n", __func__);
- else
+ if (!WARN(IS_ERR(aemif), "unable to get AEMIF clock\n"))
clk_prepare_enable(aemif);
platform_add_devices(davinci_evm_devices,
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index 680a7a2d9102..284ff27c1b32 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -242,9 +242,7 @@ static __init void dm355_leopard_init(void)
dm355leopard_dm9000_rsrc[2].start = gpio_to_irq(9);
aemif = clk_get(&dm355leopard_dm9000.dev, "aemif");
- if (IS_ERR(aemif))
- WARN("%s: unable to get AEMIF clock\n", __func__);
- else
+ if (!WARN(IS_ERR(aemif), "unable to get AEMIF clock\n"))
clk_prepare_enable(aemif);
platform_add_devices(davinci_leopard_devices,
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
index 8cfbfe084535..de1316bf643a 100644
--- a/arch/arm/mach-davinci/board-mityomapl138.c
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -26,7 +26,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/common.h>
-#include <mach/cp_intc.h>
+#include "cp_intc.h"
#include <mach/da8xx.h>
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 2aac51d0e853..ee624861ca66 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -19,7 +19,7 @@
#include <asm/mach/arch.h>
#include <mach/common.h>
-#include <mach/cp_intc.h>
+#include "cp_intc.h"
#include <mach/da8xx.h>
#include <mach/mux.h>
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 3caff9637a82..3424eac6b588 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -23,7 +23,7 @@
#include <mach/hardware.h>
#include <mach/clock.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/cputype.h>
#include "clock.h"
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
index 507aad4b8dd9..1a68d2477de6 100644
--- a/arch/arm/mach-davinci/cp_intc.c
+++ b/arch/arm/mach-davinci/cp_intc.c
@@ -19,7 +19,7 @@
#include <linux/of_irq.h>
#include <mach/common.h>
-#include <mach/cp_intc.h>
+#include "cp_intc.h"
static inline unsigned int cp_intc_read(unsigned offset)
{
diff --git a/arch/arm/mach-davinci/include/mach/cp_intc.h b/arch/arm/mach-davinci/cp_intc.h
index 827bbe9baed4..827bbe9baed4 100644
--- a/arch/arm/mach-davinci/include/mach/cp_intc.h
+++ b/arch/arm/mach-davinci/cp_intc.h
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 306ebc51599a..1b8f08532455 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -19,8 +19,8 @@
#include <linux/export.h>
#include <asm/cpuidle.h>
-#include <mach/cpuidle.h>
-#include <mach/ddr2.h>
+#include "cpuidle.h"
+#include "ddr2.h"
#define DAVINCI_CPUIDLE_MAX_STATES 2
diff --git a/arch/arm/mach-davinci/include/mach/cpuidle.h b/arch/arm/mach-davinci/cpuidle.h
index 74f088b0edfb..74f088b0edfb 100644
--- a/arch/arm/mach-davinci/include/mach/cpuidle.h
+++ b/arch/arm/mach-davinci/cpuidle.h
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index 115d5736da80..7187e7fc2822 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -15,7 +15,7 @@
#include <asm/mach/map.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/irqs.h>
#include <mach/cputype.h>
#include <mach/common.h>
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 676997895e13..97d8779a9a65 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -22,7 +22,7 @@
#include <asm/mach/map.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/irqs.h>
#include <mach/cputype.h>
#include <mach/common.h>
diff --git a/arch/arm/mach-davinci/da8xx-dt.c b/arch/arm/mach-davinci/da8xx-dt.c
index 06b6451225c1..c4b5808ca7c1 100644
--- a/arch/arm/mach-davinci/da8xx-dt.c
+++ b/arch/arm/mach-davinci/da8xx-dt.c
@@ -15,7 +15,7 @@
#include <asm/mach/arch.h>
#include <mach/common.h>
-#include <mach/cp_intc.h>
+#include "cp_intc.h"
#include <mach/da8xx.h>
#define DA8XX_NUM_UARTS 3
diff --git a/arch/arm/mach-davinci/include/mach/ddr2.h b/arch/arm/mach-davinci/ddr2.h
index c19e047d0e6a..c19e047d0e6a 100644
--- a/arch/arm/mach-davinci/include/mach/ddr2.h
+++ b/arch/arm/mach-davinci/ddr2.h
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 28c90bc372bd..e88b7a5cde99 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -22,8 +22,8 @@
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
-#include <mach/cpuidle.h>
-#include <mach/sram.h>
+#include "cpuidle.h"
+#include "sram.h"
#include "clock.h"
#include "asp.h"
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 609950b8c191..c7c1458df23c 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -21,7 +21,7 @@
#include <asm/mach/map.h>
#include <mach/cputype.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/mux.h>
#include <mach/irqs.h>
#include <mach/time.h>
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 2068cbeaeb03..01843fbcc9ea 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -26,7 +26,7 @@
#include <asm/mach/map.h>
#include <mach/cputype.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/mux.h>
#include <mach/irqs.h>
#include <mach/time.h>
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index d38f5049d56e..b28071ae3a57 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -19,7 +19,7 @@
#include <mach/cputype.h>
#include <mach/irqs.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/mux.h>
#include <mach/time.h>
#include <mach/serial.h>
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 70eb42725eec..cf80786e2471 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -20,7 +20,7 @@
#include <mach/cputype.h>
#include <mach/irqs.h>
-#include <mach/psc.h>
+#include "psc.h"
#include <mach/mux.h>
#include <mach/time.h>
#include <mach/serial.h>
diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c
index 07e23ba61f3a..8929569b1f8a 100644
--- a/arch/arm/mach-davinci/pm.c
+++ b/arch/arm/mach-davinci/pm.c
@@ -21,7 +21,7 @@
#include <mach/common.h>
#include <mach/da8xx.h>
-#include <mach/sram.h>
+#include "sram.h"
#include <mach/pm.h>
#include "clock.h"
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index 82fdc69d5728..e5dc6bfde5f3 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -23,7 +23,7 @@
#include <linux/io.h>
#include <mach/cputype.h>
-#include <mach/psc.h>
+#include "psc.h"
#include "clock.h"
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/psc.h
index 99d47cfa301f..99d47cfa301f 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/psc.h
diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S
index a5336a5e2739..cd350dee4df3 100644
--- a/arch/arm/mach-davinci/sleep.S
+++ b/arch/arm/mach-davinci/sleep.S
@@ -21,8 +21,8 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
-#include <mach/psc.h>
-#include <mach/ddr2.h>
+#include "psc.h"
+#include "ddr2.h"
#include "clock.h"
diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c
index 8540dddf1fbd..668b6e749768 100644
--- a/arch/arm/mach-davinci/sram.c
+++ b/arch/arm/mach-davinci/sram.c
@@ -14,7 +14,7 @@
#include <linux/genalloc.h>
#include <mach/common.h>
-#include <mach/sram.h>
+#include "sram.h"
static struct gen_pool *sram_pool;
diff --git a/arch/arm/mach-davinci/include/mach/sram.h b/arch/arm/mach-davinci/sram.h
index 4e5db56218b8..4e5db56218b8 100644
--- a/arch/arm/mach-davinci/include/mach/sram.h
+++ b/arch/arm/mach-davinci/sram.h
diff --git a/arch/arm/mach-dove/cm-a510.c b/arch/arm/mach-dove/cm-a510.c
index 0dc39cf30fdd..b9a7c33db29a 100644
--- a/arch/arm/mach-dove/cm-a510.c
+++ b/arch/arm/mach-dove/cm-a510.c
@@ -88,6 +88,7 @@ static void __init cm_a510_init(void)
MACHINE_START(CM_A510, "Compulab CM-A510 Board")
.atag_offset = 0x100,
+ .nr_irqs = DOVE_NR_IRQS,
.init_machine = cm_a510_init,
.map_io = dove_map_io,
.init_early = dove_init_early,
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 0d1a89298ece..0cdaa3851d2e 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -16,6 +16,7 @@
#include <linux/platform_data/dma-mv_xor.h>
#include <linux/platform_data/usb-ehci-orion.h>
#include <linux/platform_device.h>
+#include <linux/soc/dove/pmu.h>
#include <asm/hardware/cache-tauros2.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -375,6 +376,47 @@ void __init dove_setup_cpu_wins(void)
DOVE_SCRATCHPAD_SIZE);
}
+static struct resource orion_wdt_resource[] = {
+ DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+ DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
+
+static struct platform_device orion_wdt_device = {
+ .name = "orion_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(orion_wdt_resource),
+ .resource = orion_wdt_resource,
+};
+
+static void __init __maybe_unused orion_wdt_init(void)
+{
+ platform_device_register(&orion_wdt_device);
+}
+
+static const struct dove_pmu_domain_initdata pmu_domains[] __initconst = {
+ {
+ .pwr_mask = PMU_PWR_VPU_PWR_DWN_MASK,
+ .rst_mask = PMU_SW_RST_VIDEO_MASK,
+ .iso_mask = PMU_ISO_VIDEO_MASK,
+ .name = "vpu-domain",
+ }, {
+ .pwr_mask = PMU_PWR_GPU_PWR_DWN_MASK,
+ .rst_mask = PMU_SW_RST_GPU_MASK,
+ .iso_mask = PMU_ISO_GPU_MASK,
+ .name = "gpu-domain",
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct dove_pmu_initdata pmu_data __initconst = {
+ .pmc_base = DOVE_PMU_VIRT_BASE,
+ .pmu_base = DOVE_PMU_VIRT_BASE + 0x8000,
+ .irq = IRQ_DOVE_PMU,
+ .irq_domain_start = IRQ_DOVE_PMU_START,
+ .domains = pmu_domains,
+};
+
void __init dove_init(void)
{
pr_info("Dove 88AP510 SoC, TCLK = %d MHz.\n",
@@ -389,6 +431,7 @@ void __init dove_init(void)
dove_clk_init();
/* internal devices that every board has */
+ dove_init_pmu_legacy(&pmu_data);
dove_rtc_init();
dove_xor0_init();
dove_xor1_init();
diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c
index 76e26f949c27..bcb678fd2415 100644
--- a/arch/arm/mach-dove/dove-db-setup.c
+++ b/arch/arm/mach-dove/dove-db-setup.c
@@ -94,6 +94,7 @@ static void __init dove_db_init(void)
MACHINE_START(DOVE_DB, "Marvell DB-MV88AP510-BP Development Board")
.atag_offset = 0x100,
+ .nr_irqs = DOVE_NR_IRQS,
.init_machine = dove_db_init,
.map_io = dove_map_io,
.init_early = dove_init_early,
diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h
index 0c4b35f4ee5b..00f45458b3ec 100644
--- a/arch/arm/mach-dove/include/mach/dove.h
+++ b/arch/arm/mach-dove/include/mach/dove.h
@@ -11,6 +11,8 @@
#ifndef __ASM_ARCH_DOVE_H
#define __ASM_ARCH_DOVE_H
+#include <mach/irqs.h>
+
/*
* Marvell Dove address maps.
*
diff --git a/arch/arm/mach-dove/include/mach/entry-macro.S b/arch/arm/mach-dove/include/mach/entry-macro.S
deleted file mode 100644
index df1d44bdc375..000000000000
--- a/arch/arm/mach-dove/include/mach/entry-macro.S
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Marvell Dove platforms
- *
- * 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 <mach/bridge-regs.h>
-
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =IRQ_VIRT_BASE
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- @ check low interrupts
- ldr \irqstat, [\base, #IRQ_CAUSE_LOW_OFF]
- ldr \tmp, [\base, #IRQ_MASK_LOW_OFF]
- mov \irqnr, #32
- ands \irqstat, \irqstat, \tmp
-
- @ if no low interrupts set, check high interrupts
- ldreq \irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
- ldreq \tmp, [\base, #IRQ_MASK_HIGH_OFF]
- moveq \irqnr, #64
- andeqs \irqstat, \irqstat, \tmp
-
- @ find first active interrupt source
- clzne \irqstat, \irqstat
- subne \irqnr, \irqnr, \irqstat
- .endm
diff --git a/arch/arm/mach-dove/include/mach/irqs.h b/arch/arm/mach-dove/include/mach/irqs.h
index 3f29e6bca058..8ff0fa8b4fcd 100644
--- a/arch/arm/mach-dove/include/mach/irqs.h
+++ b/arch/arm/mach-dove/include/mach/irqs.h
@@ -90,7 +90,7 @@
#define NR_PMU_IRQS 7
#define IRQ_DOVE_RTC (IRQ_DOVE_PMU_START + 5)
-#define NR_IRQS (IRQ_DOVE_PMU_START + NR_PMU_IRQS)
+#define DOVE_NR_IRQS (IRQ_DOVE_PMU_START + NR_PMU_IRQS)
#endif
diff --git a/arch/arm/mach-dove/include/mach/pm.h b/arch/arm/mach-dove/include/mach/pm.h
index b47f75038686..d22b9b174007 100644
--- a/arch/arm/mach-dove/include/mach/pm.h
+++ b/arch/arm/mach-dove/include/mach/pm.h
@@ -51,22 +51,14 @@
#define CLOCK_GATING_GIGA_PHY_MASK (1 << CLOCK_GATING_BIT_GIGA_PHY)
#define PMU_INTERRUPT_CAUSE (DOVE_PMU_VIRT_BASE + 0x50)
-#define PMU_INTERRUPT_MASK (DOVE_PMU_VIRT_BASE + 0x54)
-static inline int pmu_to_irq(int pin)
-{
- if (pin < NR_PMU_IRQS)
- return pin + IRQ_DOVE_PMU_START;
+#define PMU_SW_RST_VIDEO_MASK BIT(16)
+#define PMU_SW_RST_GPU_MASK BIT(18)
- return -EINVAL;
-}
+#define PMU_PWR_GPU_PWR_DWN_MASK BIT(2)
+#define PMU_PWR_VPU_PWR_DWN_MASK BIT(3)
-static inline int irq_to_pmu(int irq)
-{
- if (IRQ_DOVE_PMU_START <= irq && irq < NR_IRQS)
- return irq - IRQ_DOVE_PMU_START;
-
- return -EINVAL;
-}
+#define PMU_ISO_VIDEO_MASK BIT(0)
+#define PMU_ISO_GPU_MASK BIT(1)
#endif
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c
index bfb3703357c5..d6627c1f7f30 100644
--- a/arch/arm/mach-dove/irq.c
+++ b/arch/arm/mach-dove/irq.c
@@ -7,87 +7,15 @@
* 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/init.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/io.h>
-#include <asm/mach/arch.h>
+#include <asm/exception.h>
#include <plat/irq.h>
-#include <asm/mach/irq.h>
-#include <mach/pm.h>
#include <mach/bridge-regs.h>
#include <plat/orion-gpio.h>
#include "common.h"
-static void pmu_irq_mask(struct irq_data *d)
-{
- int pin = irq_to_pmu(d->irq);
- u32 u;
-
- u = readl(PMU_INTERRUPT_MASK);
- u &= ~(1 << (pin & 31));
- writel(u, PMU_INTERRUPT_MASK);
-}
-
-static void pmu_irq_unmask(struct irq_data *d)
-{
- int pin = irq_to_pmu(d->irq);
- u32 u;
-
- u = readl(PMU_INTERRUPT_MASK);
- u |= 1 << (pin & 31);
- writel(u, PMU_INTERRUPT_MASK);
-}
-
-static void pmu_irq_ack(struct irq_data *d)
-{
- int pin = irq_to_pmu(d->irq);
- u32 u;
-
- /*
- * The PMU mask register is not RW0C: it is RW. This means that
- * the bits take whatever value is written to them; if you write
- * a '1', you will set the interrupt.
- *
- * Unfortunately this means there is NO race free way to clear
- * these interrupts.
- *
- * So, let's structure the code so that the window is as small as
- * possible.
- */
- u = ~(1 << (pin & 31));
- u &= readl_relaxed(PMU_INTERRUPT_CAUSE);
- writel_relaxed(u, PMU_INTERRUPT_CAUSE);
-}
-
-static struct irq_chip pmu_irq_chip = {
- .name = "pmu_irq",
- .irq_mask = pmu_irq_mask,
- .irq_unmask = pmu_irq_unmask,
- .irq_ack = pmu_irq_ack,
-};
-
-static void pmu_irq_handler(struct irq_desc *desc)
-{
- unsigned long cause = readl(PMU_INTERRUPT_CAUSE);
- unsigned int irq;
-
- cause &= readl(PMU_INTERRUPT_MASK);
- if (cause == 0) {
- do_bad_IRQ(desc);
- return;
- }
-
- for (irq = 0; irq < NR_PMU_IRQS; irq++) {
- if (!(cause & (1 << irq)))
- continue;
- irq = pmu_to_irq(irq);
- generic_handle_irq(irq);
- }
-}
-
static int __initdata gpio0_irqs[4] = {
IRQ_DOVE_GPIO_0_7,
IRQ_DOVE_GPIO_8_15,
@@ -109,14 +37,6 @@ static int __initdata gpio2_irqs[4] = {
0,
};
-#ifdef CONFIG_MULTI_IRQ_HANDLER
-/*
- * Compiling with both non-DT and DT support enabled, will
- * break asm irq handler used by non-DT boards. Therefore,
- * we provide a C-style irq handler even for non-DT boards,
- * if MULTI_IRQ_HANDLER is set.
- */
-
static void __iomem *dove_irq_base = IRQ_VIRT_BASE;
static asmlinkage void
@@ -139,18 +59,13 @@ __exception_irq_entry dove_legacy_handle_irq(struct pt_regs *regs)
return;
}
}
-#endif
void __init dove_init_irq(void)
{
- int i;
-
orion_irq_init(1, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF);
orion_irq_init(33, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF);
-#ifdef CONFIG_MULTI_IRQ_HANDLER
set_handle_irq(dove_legacy_handle_irq);
-#endif
/*
* Initialize gpiolib for GPIOs 0-71.
@@ -163,17 +78,4 @@ void __init dove_init_irq(void)
orion_gpio_init(NULL, 64, 8, DOVE_GPIO2_VIRT_BASE, 0,
IRQ_DOVE_GPIO_START + 64, gpio2_irqs);
-
- /*
- * Mask and clear PMU interrupts
- */
- writel(0, PMU_INTERRUPT_MASK);
- writel(0, PMU_INTERRUPT_CAUSE);
-
- for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) {
- irq_set_chip_and_handler(i, &pmu_irq_chip, handle_level_irq);
- irq_set_status_flags(i, IRQ_LEVEL);
- irq_clear_status_flags(i, IRQ_NOREQUEST);
- }
- irq_set_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler);
}
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index c4904264256a..b2db791b3b38 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -49,7 +49,7 @@
static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
static u16 nand_state = SNAPPERCL15_NAND_WPN;
u16 set;
@@ -76,7 +76,7 @@ static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
static int snappercl15_nand_dev_ready(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY);
}
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 61f4b5dc4d7d..45b81a2bcd4b 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -74,7 +74,7 @@ static void __init ts72xx_map_io(void)
static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (ctrl & NAND_CTRL_CHANGE) {
void __iomem *addr = chip->IO_ADDR_R;
@@ -96,7 +96,7 @@ static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
static int ts72xx_nand_device_ready(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
void __iomem *addr = chip->IO_ADDR_R;
addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE);
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index ff105399aae4..652a0bb11578 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -8,7 +8,8 @@
# Configuration options for the EXYNOS4
menuconfig ARCH_EXYNOS
- bool "Samsung EXYNOS" if ARCH_MULTI_V7
+ bool "Samsung EXYNOS"
+ depends on ARCH_MULTI_V7
select ARCH_HAS_BANDGAP
select ARCH_HAS_HOLES_MEMORYMODEL
select ARCH_REQUIRE_GPIOLIB
@@ -28,6 +29,9 @@ menuconfig ARCH_EXYNOS
select THERMAL
select MFD_SYSCON
select CLKSRC_EXYNOS_MCT
+ select POWER_RESET
+ select POWER_RESET_SYSCON
+ select POWER_RESET_SYSCON_POWEROFF
help
Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 153492513c40..e349a038976d 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -149,7 +149,7 @@ static inline void exynos_pm_init(void) {}
extern void exynos_cpu_resume(void);
extern void exynos_cpu_resume_ns(void);
-extern struct smp_operations exynos_smp_ops;
+extern const struct smp_operations exynos_smp_ops;
extern void exynos_cpu_power_down(int cpu);
extern void exynos_cpu_power_up(int cpu);
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 98a2c0cbb833..5bd9559786ba 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -479,7 +479,7 @@ static void exynos_cpu_die(unsigned int cpu)
}
#endif /* CONFIG_HOTPLUG_CPU */
-struct smp_operations exynos_smp_ops __initdata = {
+const struct smp_operations exynos_smp_ops __initconst = {
.smp_init_cpus = exynos_smp_init_cpus,
.smp_prepare_cpus = exynos_smp_prepare_cpus,
.smp_secondary_init = exynos_secondary_init,
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
index c21e41dad19c..dbf9fe98d479 100644
--- a/arch/arm/mach-exynos/pmu.c
+++ b/arch/arm/mach-exynos/pmu.c
@@ -14,9 +14,8 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
+#include <asm/cputype.h>
#include "exynos-pmu.h"
#include "regs-pmu.h"
@@ -681,23 +680,6 @@ static unsigned int const exynos5420_list_disable_pmu_reg[] = {
EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG,
};
-static void exynos_power_off(void)
-{
- unsigned int tmp;
-
- pr_info("Power down.\n");
- tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL);
- tmp ^= (1 << 8);
- pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL);
-
- /* Wait a little so we don't give a false warning below */
- mdelay(100);
-
- pr_err("Power down failed, please power off system manually.\n");
- while (1)
- ;
-}
-
static void exynos5420_powerdown_conf(enum sys_powerdown mode)
{
u32 this_cluster;
@@ -879,14 +861,6 @@ static void exynos5420_pmu_init(void)
pr_info("EXYNOS5420 PMU initialized\n");
}
-static int pmu_restart_notify(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- pmu_raw_writel(0x1, EXYNOS_SWRESET);
-
- return NOTIFY_DONE;
-}
-
static const struct exynos_pmu_data exynos3250_pmu_data = {
.pmu_config = exynos3250_pmu_config,
.pmu_init = exynos3250_pmu_init,
@@ -912,7 +886,7 @@ static const struct exynos_pmu_data exynos5250_pmu_data = {
.powerdown_conf = exynos5_powerdown_conf,
};
-static struct exynos_pmu_data exynos5420_pmu_data = {
+static const struct exynos_pmu_data exynos5420_pmu_data = {
.pmu_config = exynos5420_pmu_config,
.pmu_init = exynos5420_pmu_init,
.powerdown_conf = exynos5420_powerdown_conf,
@@ -944,20 +918,11 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
{ /*sentinel*/ },
};
-/*
- * Exynos PMU restart notifier, handles restart functionality
- */
-static struct notifier_block pmu_restart_handler = {
- .notifier_call = pmu_restart_notify,
- .priority = 128,
-};
-
static int exynos_pmu_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct resource *res;
- int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pmu_base_addr = devm_ioremap_resource(dev, res);
@@ -982,12 +947,6 @@ static int exynos_pmu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pmu_context);
- ret = register_restart_handler(&pmu_restart_handler);
- if (ret)
- dev_warn(dev, "can't register restart handler err=%d\n", ret);
-
- pm_power_off = exynos_power_off;
-
dev_dbg(dev, "Exynos PMU Driver probe done\n");
return 0;
}
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index fba9068ed260..5e4f4c23b06a 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -484,15 +484,6 @@
#define EXYNOS5420_SWRESET_KFC_SEL 0x3
-#include <asm/cputype.h>
-#define MAX_CPUS_IN_CLUSTER 4
-
-static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr)
-{
- return ((MPIDR_AFFINITY_LEVEL(mpidr, 1) * MAX_CPUS_IN_CLUSTER)
- + MPIDR_AFFINITY_LEVEL(mpidr, 0));
-}
-
/* Only for EXYNOS5420 */
#define EXYNOS5420_ISP_ARM_OPTION 0x2488
#define EXYNOS5420_L2RSTDISABLE_VALUE BIT(3)
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 31aa866c3317..81110ec34226 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,6 @@
config ARCH_HIGHBANK
- bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+ bool "Calxeda ECX-1000/2000 (Highbank/Midway)"
+ depends on ARCH_MULTI_V7
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_HAS_HOLES_MEMORYMODEL
select ARCH_SUPPORTS_BIG_ENDIAN
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index 83061ad0e282..a3b091a4d344 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -13,7 +13,8 @@ if ARCH_HISI
menu "Hisilicon platform type"
config ARCH_HI3xxx
- bool "Hisilicon Hi36xx family" if ARCH_MULTI_V7
+ bool "Hisilicon Hi36xx family"
+ depends on ARCH_MULTI_V7
select CACHE_L2X0
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
@@ -23,7 +24,8 @@ config ARCH_HI3xxx
Support for Hisilicon Hi36xx SoC family
config ARCH_HIP01
- bool "Hisilicon HIP01 family" if ARCH_MULTI_V7
+ bool "Hisilicon HIP01 family"
+ depends on ARCH_MULTI_V7
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select ARM_GLOBAL_TIMER
@@ -31,7 +33,8 @@ config ARCH_HIP01
Support for Hisilicon HIP01 SoC family
config ARCH_HIP04
- bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7
+ bool "Hisilicon HiP04 Cortex A15 family"
+ depends on ARCH_MULTI_V7
select ARM_ERRATA_798181 if SMP
select HAVE_ARM_ARCH_TIMER
select MCPM if SMP
@@ -40,7 +43,8 @@ config ARCH_HIP04
Support for Hisilicon HiP04 SoC family
config ARCH_HIX5HD2
- bool "Hisilicon X5HD2 family" if ARCH_MULTI_V7
+ bool "Hisilicon X5HD2 family"
+ depends on ARCH_MULTI_V7
select CACHE_L2X0
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h
index c7648ef1825c..e883583a23f1 100644
--- a/arch/arm/mach-hisi/core.h
+++ b/arch/arm/mach-hisi/core.h
@@ -6,17 +6,14 @@
extern void hi3xxx_set_cpu_jump(int cpu, void *jump_addr);
extern int hi3xxx_get_cpu_jump(int cpu);
extern void secondary_startup(void);
-extern struct smp_operations hi3xxx_smp_ops;
extern void hi3xxx_cpu_die(unsigned int cpu);
extern int hi3xxx_cpu_kill(unsigned int cpu);
extern void hi3xxx_set_cpu(int cpu, bool enable);
-extern struct smp_operations hix5hd2_smp_ops;
extern void hix5hd2_set_cpu(int cpu, bool enable);
extern void hix5hd2_cpu_die(unsigned int cpu);
-extern struct smp_operations hip01_smp_ops;
extern void hip01_set_cpu(int cpu, bool enable);
extern void hip01_cpu_die(unsigned int cpu);
#endif
diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c
index b5f8f5ffda79..4b653a8cb75c 100644
--- a/arch/arm/mach-hisi/platmcpm.c
+++ b/arch/arm/mach-hisi/platmcpm.c
@@ -239,7 +239,7 @@ err:
}
#endif
-static struct smp_operations __initdata hip04_smp_ops = {
+static const struct smp_operations hip04_smp_ops __initconst = {
.smp_boot_secondary = hip04_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = hip04_cpu_die,
diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c
index 51744127db66..47ed32cf57cc 100644
--- a/arch/arm/mach-hisi/platsmp.c
+++ b/arch/arm/mach-hisi/platsmp.c
@@ -89,7 +89,7 @@ static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
return 0;
}
-struct smp_operations hi3xxx_smp_ops __initdata = {
+static const struct smp_operations hi3xxx_smp_ops __initconst = {
.smp_prepare_cpus = hi3xxx_smp_prepare_cpus,
.smp_boot_secondary = hi3xxx_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
@@ -126,7 +126,7 @@ static int hix5hd2_boot_secondary(unsigned int cpu, struct task_struct *idle)
}
-struct smp_operations hix5hd2_smp_ops __initdata = {
+static const struct smp_operations hix5hd2_smp_ops __initconst = {
.smp_prepare_cpus = hisi_common_smp_prepare_cpus,
.smp_boot_secondary = hix5hd2_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
@@ -176,7 +176,7 @@ static int hip01_boot_secondary(unsigned int cpu, struct task_struct *idle)
return 0;
}
-struct smp_operations hip01_smp_ops __initdata = {
+static const struct smp_operations hip01_smp_ops __initconst = {
.smp_prepare_cpus = hisi_common_smp_prepare_cpus,
.smp_boot_secondary = hip01_boot_secondary,
};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 8ceda2844c4f..15df34fbdf44 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_MXC
- bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 || ARM_SINGLE_ARMV7M
+ bool "Freescale i.MX family"
+ depends on ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 || ARM_SINGLE_ARMV7M
select ARCH_REQUIRE_GPIOLIB
select ARM_CPU_SUSPEND if PM
select CLKSRC_IMX_GPT
@@ -562,6 +563,7 @@ config SOC_IMX7D
select ARM_GIC
select HAVE_IMX_ANATOP
select HAVE_IMX_MMDC
+ select HAVE_IMX_SRC
help
This enables support for Freescale i.MX7 Dual processor.
@@ -596,7 +598,8 @@ choice
default VF_USE_ARM_GLOBAL_TIMER
config VF_USE_ARM_GLOBAL_TIMER
- bool "Use ARM Global Timer" if ARCH_MULTI_V7
+ bool "Use ARM Global Timer"
+ depends on ARCH_MULTI_V7
select ARM_GLOBAL_TIMER
select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
help
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index e2d53839fceb..32b83f09da18 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -153,7 +153,7 @@ void imx_init_l2cache(void);
static inline void imx_init_l2cache(void) {}
#endif
-extern struct smp_operations imx_smp_ops;
-extern struct smp_operations ls1021a_smp_ops;
+extern const struct smp_operations imx_smp_ops;
+extern const struct smp_operations ls1021a_smp_ops;
#endif
diff --git a/arch/arm/mach-imx/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c
index 6dd22cabf4d3..0b5ba4bf572a 100644
--- a/arch/arm/mach-imx/iomux-imx31.c
+++ b/arch/arm/mach-imx/iomux-imx31.c
@@ -100,7 +100,7 @@ int mxc_iomux_alloc_pin(unsigned int pin, const char *label)
unsigned pad = pin & IOMUX_PADNUM_MASK;
if (pad >= (PIN_MAX + 1)) {
- printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n",
+ printk(KERN_ERR "mxc_iomux: Attempt to request nonexistent pin %u for \"%s\"\n",
pad, label ? label : "?");
return -EINVAL;
}
diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c
index acaf7056efa5..a38b16b69923 100644
--- a/arch/arm/mach-imx/mach-imx6ul.c
+++ b/arch/arm/mach-imx/mach-imx6ul.c
@@ -84,7 +84,7 @@ static void __init imx6ul_init_late(void)
platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
}
-static const char *imx6ul_dt_compat[] __initconst = {
+static const char * const imx6ul_dt_compat[] __initconst = {
"fsl,imx6ul",
NULL,
};
diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c
index b450f525a670..5a27f20c9a82 100644
--- a/arch/arm/mach-imx/mach-imx7d.c
+++ b/arch/arm/mach-imx/mach-imx7d.c
@@ -105,6 +105,11 @@ static void __init imx7d_init_irq(void)
irqchip_init();
}
+static void __init imx7d_init_late(void)
+{
+ platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+}
+
static const char *const imx7d_dt_compat[] __initconst = {
"fsl,imx7d",
NULL,
@@ -112,6 +117,7 @@ static const char *const imx7d_dt_compat[] __initconst = {
DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
.init_irq = imx7d_init_irq,
+ .init_late = imx7d_init_late,
.init_machine = imx7d_init_machine,
.dt_compat = imx7d_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 703ce31d7379..9986f9a697c8 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/physmap.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c
index a213e7b9cb1c..5c2764604727 100644
--- a/arch/arm/mach-imx/mach-qong.c
+++ b/arch/arm/mach-imx/mach-qong.c
@@ -131,7 +131,7 @@ static void qong_init_nor_mtd(void)
*/
static void qong_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
if (cmd == NAND_CMD_NONE)
return;
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 7f270015fe58..711dbbd5badd 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -88,7 +88,7 @@ static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
sync_cache_w(&g_diag_reg);
}
-struct smp_operations imx_smp_ops __initdata = {
+const struct smp_operations imx_smp_ops __initconst = {
.smp_init_cpus = imx_smp_init_cpus,
.smp_prepare_cpus = imx_smp_prepare_cpus,
.smp_boot_secondary = imx_boot_secondary,
@@ -123,7 +123,7 @@ static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
iounmap(dcfg_base);
}
-struct smp_operations ls1021a_smp_ops __initdata = {
+const struct smp_operations ls1021a_smp_ops __initconst = {
.smp_prepare_cpus = ls1021a_smp_prepare_cpus,
.smp_boot_secondary = ls1021a_boot_secondary,
};
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index 02d083489a26..b01bdc9baf89 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -1,5 +1,6 @@
-config ARCH_INTEGRATOR
- bool "ARM Ltd. Integrator family" if (ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6)
+menuconfig ARCH_INTEGRATOR
+ bool "ARM Ltd. Integrator family"
+ depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6
select ARM_AMBA
select ARM_PATCH_PHYS_VIRT if MMU
select AUTO_ZRELADDR
@@ -23,8 +24,6 @@ config ARCH_INTEGRATOR
if ARCH_INTEGRATOR
-menu "Integrator Options"
-
config ARCH_INTEGRATOR_AP
bool "Support Integrator/AP and Integrator/PP2 platforms"
select CLKSRC_MMIO
@@ -36,19 +35,6 @@ config ARCH_INTEGRATOR_AP
Include support for the ARM(R) Integrator/AP and
Integrator/PP2 platforms.
-config ARCH_INTEGRATOR_CP
- bool "Support Integrator/CP platform"
- select ARCH_CINTEGRATOR
- select ARM_TIMER_SP804
- select SERIAL_AMBA_PL011 if TTY
- select SERIAL_AMBA_PL011_CONSOLE if TTY
- select SOC_BUS
- help
- Include support for the ARM(R) Integrator CP platform.
-
-config ARCH_CINTEGRATOR
- bool
-
config INTEGRATOR_IMPD1
bool "Include support for Integrator/IM-PD1"
depends on ARCH_INTEGRATOR_AP
@@ -63,6 +49,119 @@ config INTEGRATOR_IMPD1
To compile this driver as a module, choose M here: the
module will be called impd1.
-endmenu
+config INTEGRATOR_CM7TDMI
+ bool "Integrator/CM7TDMI core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V4 && !MMU
+ select CPU_ARM7TDMI
+
+config INTEGRATOR_CM720T
+ bool "Integrator/CM720T core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V4T
+ select CPU_ARM720T
+
+config INTEGRATOR_CM740T
+ bool "Integrator/CM740T core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V4T && !MMU
+ select CPU_ARM740T
+
+config INTEGRATOR_CM920T
+ bool "Integrator/CM920T core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V4T
+ select CPU_ARM920T
+
+config INTEGRATOR_CM922T_XA10
+ bool "Integrator/CM922T-XA10 core module"
+ depends on ARCH_MULTI_V4T
+ depends on ARCH_INTEGRATOR_AP
+ select CPU_ARM922T
+
+config INTEGRATOR_CM926EJS
+ bool "Integrator/CM926EJ-S core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V5
+ select CPU_ARM926T
+
+config INTEGRATOR_CM940T
+ bool "Integrator/CM940T core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V4T && !MMU
+ select CPU_ARM940T
+
+config INTEGRATOR_CM946ES
+ bool "Integrator/CM946E-S core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V5 && !MMU
+ select CPU_ARM946E
+
+config INTEGRATOR_CM966ES
+ bool "Integrator/CM966E-S core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on BROKEN # no kernel support
+
+config INTEGRATOR_CM10200E_REV0
+ bool "Integrator/CM10200E rev.0 core module"
+ depends on ARCH_INTEGRATOR_AP && n
+ depends on ARCH_MULTI_V5
+ select CPU_ARM1020
+
+config INTEGRATOR_CM10200E
+ bool "Integrator/CM10200E core module"
+ depends on ARCH_INTEGRATOR_AP && n
+ depends on ARCH_MULTI_V5
+ select CPU_ARM1020E
+
+config INTEGRATOR_CM10220E
+ bool "Integrator/CM10220E core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V5
+ select CPU_ARM1022
+
+config INTEGRATOR_CM1026EJS
+ bool "Integrator/CM1026EJ-S core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V5
+ select CPU_ARM1026
+
+config INTEGRATOR_CM1136JFS
+ bool "Integrator/CM1136JF-S core module"
+ depends on ARCH_INTEGRATOR_AP
+ depends on ARCH_MULTI_V6
+ select CPU_V6
+
+config ARCH_INTEGRATOR_CP
+ bool "Support Integrator/CP platform"
+ depends on (!MMU || ARCH_MULTI_V5 || ARCH_MULTI_V6)
+ select ARM_TIMER_SP804
+ select SERIAL_AMBA_PL011 if TTY
+ select SERIAL_AMBA_PL011_CONSOLE if TTY
+ select SOC_BUS
+ help
+ Include support for the ARM(R) Integrator CP platform.
+
+config INTEGRATOR_CT7T
+ bool "Integrator/CT7TD (ARM7TDMI) core tile"
+ depends on ARCH_INTEGRATOR_CP
+ depends on ARCH_MULTI_V4T && !MMU
+ select CPU_ARM7TDMI
+
+config INTEGRATOR_CT926
+ bool "Integrator/CT926 (ARM926EJ-S) core tile"
+ depends on ARCH_INTEGRATOR_CP
+ depends on ARCH_MULTI_V5
+ select CPU_ARM926T
+
+config INTEGRATOR_CTB36
+ bool "Integrator/CTB36 (ARM1136JF-S) core tile"
+ depends on ARCH_INTEGRATOR_CP
+ depends on ARCH_MULTI_V6
+ select CPU_V6
+
+config ARCH_CINTEGRATOR
+ depends on ARCH_INTEGRATOR_CP
+ def_bool y
endif
diff --git a/arch/arm/mach-iop13xx/include/mach/pci.h b/arch/arm/mach-iop13xx/include/mach/pci.h
deleted file mode 100644
index 59f42b535572..000000000000
--- a/arch/arm/mach-iop13xx/include/mach/pci.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _IOP13XX_PCI_H_
-#define _IOP13XX_PCI_H_
-#include <linux/io.h>
-#include <mach/irqs.h>
-
-struct pci_sys_data;
-struct hw_pci;
-int iop13xx_pci_setup(int nr, struct pci_sys_data *sys);
-struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *);
-void iop13xx_atu_select(struct hw_pci *plat_pci);
-void iop13xx_pci_init(void);
-void iop13xx_map_pci_memory(void);
-
-#define IOP_PCI_STATUS_ERROR (PCI_STATUS_PARITY | \
- PCI_STATUS_SIG_TARGET_ABORT | \
- PCI_STATUS_REC_TARGET_ABORT | \
- PCI_STATUS_REC_TARGET_ABORT | \
- PCI_STATUS_REC_MASTER_ABORT | \
- PCI_STATUS_SIG_SYSTEM_ERROR | \
- PCI_STATUS_DETECTED_PARITY)
-
-#define IOP13XX_ATUE_ATUISR_ERROR (IOP13XX_ATUE_STAT_HALT_ON_ERROR | \
- IOP13XX_ATUE_STAT_ROOT_SYS_ERR | \
- IOP13XX_ATUE_STAT_PCI_IFACE_ERR | \
- IOP13XX_ATUE_STAT_ERR_COR | \
- IOP13XX_ATUE_STAT_ERR_UNCOR | \
- IOP13XX_ATUE_STAT_CRS | \
- IOP13XX_ATUE_STAT_DET_PAR_ERR | \
- IOP13XX_ATUE_STAT_EXT_REC_MABORT | \
- IOP13XX_ATUE_STAT_SIG_TABORT | \
- IOP13XX_ATUE_STAT_EXT_REC_TABORT | \
- IOP13XX_ATUE_STAT_MASTER_DATA_PAR)
-
-#define IOP13XX_ATUX_ATUISR_ERROR (IOP13XX_ATUX_STAT_TX_SCEM | \
- IOP13XX_ATUX_STAT_REC_SCEM | \
- IOP13XX_ATUX_STAT_TX_SERR | \
- IOP13XX_ATUX_STAT_DET_PAR_ERR | \
- IOP13XX_ATUX_STAT_INT_REC_MABORT | \
- IOP13XX_ATUX_STAT_REC_SERR | \
- IOP13XX_ATUX_STAT_EXT_REC_MABORT | \
- IOP13XX_ATUX_STAT_EXT_REC_TABORT | \
- IOP13XX_ATUX_STAT_EXT_SIG_TABORT | \
- IOP13XX_ATUX_STAT_MASTER_DATA_PAR)
-
-/* PCI interrupts
- */
-#define ATUX_INTA IRQ_IOP13XX_XINT0
-#define ATUX_INTB IRQ_IOP13XX_XINT1
-#define ATUX_INTC IRQ_IOP13XX_XINT2
-#define ATUX_INTD IRQ_IOP13XX_XINT3
-
-#define ATUE_INTA IRQ_IOP13XX_ATUE_IMA
-#define ATUE_INTB IRQ_IOP13XX_ATUE_IMB
-#define ATUE_INTC IRQ_IOP13XX_ATUE_IMC
-#define ATUE_INTD IRQ_IOP13XX_ATUE_IMD
-
-#endif /* _IOP13XX_PCI_H_ */
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c
index 9cd07d396093..d255ab5ad1a5 100644
--- a/arch/arm/mach-iop13xx/iq81340mc.c
+++ b/arch/arm/mach-iop13xx/iq81340mc.c
@@ -23,7 +23,7 @@
#include <asm/mach/pci.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pci.h>
+#include "pci.h"
#include <asm/mach/time.h>
#include <mach/time.h>
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index b3ec11cb707e..33eeaf1fa11d 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -23,7 +23,7 @@
#include <asm/mach/pci.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pci.h>
+#include "pci.h"
#include <asm/mach/time.h>
#include <mach/time.h>
diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c
index 623d85a4af2d..c702cc4092de 100644
--- a/arch/arm/mach-iop13xx/irq.c
+++ b/arch/arm/mach-iop13xx/irq.c
@@ -25,7 +25,7 @@
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
-#include <mach/msi.h>
+#include "msi.h"
/* INTCTL0 CP6 R0 Page 4
*/
diff --git a/arch/arm/mach-iop13xx/include/mach/msi.h b/arch/arm/mach-iop13xx/msi.h
index b80c5ae17e99..b80c5ae17e99 100644
--- a/arch/arm/mach-iop13xx/include/mach/msi.h
+++ b/arch/arm/mach-iop13xx/msi.h
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 9082b84aeebb..204eb4460271 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -27,7 +27,7 @@
#include <asm/sizes.h>
#include <asm/signal.h>
#include <asm/mach/pci.h>
-#include <mach/pci.h>
+#include "pci.h"
#define IOP13XX_PCI_DEBUG 0
#define PRINTK(x...) ((void)(IOP13XX_PCI_DEBUG && printk(x)))
diff --git a/arch/arm/mach-iop13xx/pci.h b/arch/arm/mach-iop13xx/pci.h
index d45a80b3080e..71b9c57e1fde 100644
--- a/arch/arm/mach-iop13xx/pci.h
+++ b/arch/arm/mach-iop13xx/pci.h
@@ -1,6 +1,64 @@
+#ifndef _IOP13XX_PCI_H_
+#define _IOP13XX_PCI_H_
+#include <linux/io.h>
+#include <mach/irqs.h>
+
#include <linux/types.h>
extern void __iomem *iop13xx_atue_mem_base;
extern void __iomem *iop13xx_atux_mem_base;
extern size_t iop13xx_atue_mem_size;
extern size_t iop13xx_atux_mem_size;
+
+struct pci_sys_data;
+struct hw_pci;
+int iop13xx_pci_setup(int nr, struct pci_sys_data *sys);
+struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *);
+void iop13xx_atu_select(struct hw_pci *plat_pci);
+void iop13xx_pci_init(void);
+void iop13xx_map_pci_memory(void);
+
+#define IOP_PCI_STATUS_ERROR (PCI_STATUS_PARITY | \
+ PCI_STATUS_SIG_TARGET_ABORT | \
+ PCI_STATUS_REC_TARGET_ABORT | \
+ PCI_STATUS_REC_TARGET_ABORT | \
+ PCI_STATUS_REC_MASTER_ABORT | \
+ PCI_STATUS_SIG_SYSTEM_ERROR | \
+ PCI_STATUS_DETECTED_PARITY)
+
+#define IOP13XX_ATUE_ATUISR_ERROR (IOP13XX_ATUE_STAT_HALT_ON_ERROR | \
+ IOP13XX_ATUE_STAT_ROOT_SYS_ERR | \
+ IOP13XX_ATUE_STAT_PCI_IFACE_ERR | \
+ IOP13XX_ATUE_STAT_ERR_COR | \
+ IOP13XX_ATUE_STAT_ERR_UNCOR | \
+ IOP13XX_ATUE_STAT_CRS | \
+ IOP13XX_ATUE_STAT_DET_PAR_ERR | \
+ IOP13XX_ATUE_STAT_EXT_REC_MABORT | \
+ IOP13XX_ATUE_STAT_SIG_TABORT | \
+ IOP13XX_ATUE_STAT_EXT_REC_TABORT | \
+ IOP13XX_ATUE_STAT_MASTER_DATA_PAR)
+
+#define IOP13XX_ATUX_ATUISR_ERROR (IOP13XX_ATUX_STAT_TX_SCEM | \
+ IOP13XX_ATUX_STAT_REC_SCEM | \
+ IOP13XX_ATUX_STAT_TX_SERR | \
+ IOP13XX_ATUX_STAT_DET_PAR_ERR | \
+ IOP13XX_ATUX_STAT_INT_REC_MABORT | \
+ IOP13XX_ATUX_STAT_REC_SERR | \
+ IOP13XX_ATUX_STAT_EXT_REC_MABORT | \
+ IOP13XX_ATUX_STAT_EXT_REC_TABORT | \
+ IOP13XX_ATUX_STAT_EXT_SIG_TABORT | \
+ IOP13XX_ATUX_STAT_MASTER_DATA_PAR)
+
+/* PCI interrupts
+ */
+#define ATUX_INTA IRQ_IOP13XX_XINT0
+#define ATUX_INTB IRQ_IOP13XX_XINT1
+#define ATUX_INTC IRQ_IOP13XX_XINT2
+#define ATUX_INTD IRQ_IOP13XX_XINT3
+
+#define ATUE_INTA IRQ_IOP13XX_ATUE_IMA
+#define ATUE_INTB IRQ_IOP13XX_ATUE_IMB
+#define ATUE_INTC IRQ_IOP13XX_ATUE_IMC
+#define ATUE_INTD IRQ_IOP13XX_ATUE_IMD
+
+#endif /* _IOP13XX_PCI_H_ */
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index e7b8befa8729..508c2d7786e2 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -76,8 +76,8 @@ static struct mtd_partition ixdp425_partitions[] = {
static void
ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
- int offset = (int)this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ int offset = (int)nand_get_controller_data(this);
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE) {
@@ -88,7 +88,7 @@ ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
offset = (ctrl & NAND_CLE) ? IXDP425_NAND_CMD_BYTE : 0;
offset |= (ctrl & NAND_ALE) ? IXDP425_NAND_ADDR_BYTE : 0;
- this->priv = (void *)offset;
+ nand_set_controller_data(this, (void *)offset);
}
if (cmd != NAND_CMD_NONE)
diff --git a/arch/arm/mach-keystone/keystone.h b/arch/arm/mach-keystone/keystone.h
index cd04a1c14de8..33eaa037af5a 100644
--- a/arch/arm/mach-keystone/keystone.h
+++ b/arch/arm/mach-keystone/keystone.h
@@ -15,7 +15,7 @@
#ifndef __ASSEMBLER__
-extern struct smp_operations keystone_smp_ops;
+extern const struct smp_operations keystone_smp_ops;
extern void secondary_startup(void);
extern u32 keystone_cpu_smc(u32 command, u32 cpu, u32 addr);
extern int keystone_pm_runtime_init(void);
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c
index 4bbb18463bfd..5665276972ec 100644
--- a/arch/arm/mach-keystone/platsmp.c
+++ b/arch/arm/mach-keystone/platsmp.c
@@ -39,6 +39,6 @@ static int keystone_smp_boot_secondary(unsigned int cpu,
return error;
}
-struct smp_operations keystone_smp_ops __initdata = {
+const struct smp_operations keystone_smp_ops __initconst = {
.smp_boot_secondary = keystone_smp_boot_secondary,
};
diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c
index 9f9c0441a917..e4d709c8ed32 100644
--- a/arch/arm/mach-ks8695/board-acs5k.c
+++ b/arch/arm/mach-ks8695/board-acs5k.c
@@ -33,7 +33,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/devices.h>
+#include "devices.h"
#include <mach/gpio-ks8695.h>
#include "generic.h"
diff --git a/arch/arm/mach-ks8695/board-dsm320.c b/arch/arm/mach-ks8695/board-dsm320.c
index d37c218c3584..13537e9c5485 100644
--- a/arch/arm/mach-ks8695/board-dsm320.c
+++ b/arch/arm/mach-ks8695/board-dsm320.c
@@ -28,7 +28,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/devices.h>
+#include "devices.h"
#include <mach/gpio-ks8695.h>
#include "generic.h"
diff --git a/arch/arm/mach-ks8695/board-micrel.c b/arch/arm/mach-ks8695/board-micrel.c
index 3acbdfd31391..69cfb9935fc1 100644
--- a/arch/arm/mach-ks8695/board-micrel.c
+++ b/arch/arm/mach-ks8695/board-micrel.c
@@ -19,7 +19,7 @@
#include <asm/mach/irq.h>
#include <mach/gpio-ks8695.h>
-#include <mach/devices.h>
+#include "devices.h"
#include "generic.h"
diff --git a/arch/arm/mach-ks8695/board-og.c b/arch/arm/mach-ks8695/board-og.c
index f2658168eeff..1f4f2f4f25bb 100644
--- a/arch/arm/mach-ks8695/board-og.c
+++ b/arch/arm/mach-ks8695/board-og.c
@@ -18,7 +18,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/devices.h>
+#include "devices.h"
#include <mach/regs-gpio.h>
#include <mach/gpio-ks8695.h>
#include "generic.h"
diff --git a/arch/arm/mach-ks8695/board-sg.c b/arch/arm/mach-ks8695/board-sg.c
index fdf2352d2cf8..46e455c3821b 100644
--- a/arch/arm/mach-ks8695/board-sg.c
+++ b/arch/arm/mach-ks8695/board-sg.c
@@ -16,7 +16,7 @@
#include <linux/mtd/partitions.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/devices.h>
+#include "devices.h"
#include "generic.h"
/*
diff --git a/arch/arm/mach-ks8695/cpu.c b/arch/arm/mach-ks8695/cpu.c
index ddb24222918e..474a050da85b 100644
--- a/arch/arm/mach-ks8695/cpu.c
+++ b/arch/arm/mach-ks8695/cpu.c
@@ -30,7 +30,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/regs-sys.h>
+#include "regs-sys.h"
#include <mach/regs-misc.h>
diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c
index 47399bc3c024..61cf20beb45f 100644
--- a/arch/arm/mach-ks8695/devices.c
+++ b/arch/arm/mach-ks8695/devices.c
@@ -24,9 +24,9 @@
#include <linux/platform_device.h>
#include <mach/irqs.h>
-#include <mach/regs-wan.h>
-#include <mach/regs-lan.h>
-#include <mach/regs-hpna.h>
+#include "regs-wan.h"
+#include "regs-lan.h"
+#include "regs-hpna.h"
#include <mach/regs-switch.h>
#include <mach/regs-misc.h>
diff --git a/arch/arm/mach-ks8695/include/mach/devices.h b/arch/arm/mach-ks8695/devices.h
index 1e6594a0f297..1e6594a0f297 100644
--- a/arch/arm/mach-ks8695/include/mach/devices.h
+++ b/arch/arm/mach-ks8695/devices.h
diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
index c1bc4c3716ed..577a35f75c8a 100644
--- a/arch/arm/mach-ks8695/pci.c
+++ b/arch/arm/mach-ks8695/pci.c
@@ -33,8 +33,8 @@
#include <asm/mach/pci.h>
#include <mach/hardware.h>
-#include <mach/devices.h>
-#include <mach/regs-pci.h>
+#include "devices.h"
+#include "regs-pci.h"
static int pci_dbg;
diff --git a/arch/arm/mach-ks8695/include/mach/regs-hpna.h b/arch/arm/mach-ks8695/regs-hpna.h
index 815ce5c2e3b9..815ce5c2e3b9 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-hpna.h
+++ b/arch/arm/mach-ks8695/regs-hpna.h
diff --git a/arch/arm/mach-ks8695/include/mach/regs-lan.h b/arch/arm/mach-ks8695/regs-lan.h
index 82c5f3791afb..82c5f3791afb 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-lan.h
+++ b/arch/arm/mach-ks8695/regs-lan.h
diff --git a/arch/arm/mach-ks8695/include/mach/regs-mem.h b/arch/arm/mach-ks8695/regs-mem.h
index 55806bc68ce3..55806bc68ce3 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-mem.h
+++ b/arch/arm/mach-ks8695/regs-mem.h
diff --git a/arch/arm/mach-ks8695/include/mach/regs-pci.h b/arch/arm/mach-ks8695/regs-pci.h
index 75a9db6edbd9..75a9db6edbd9 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-pci.h
+++ b/arch/arm/mach-ks8695/regs-pci.h
diff --git a/arch/arm/mach-ks8695/include/mach/regs-sys.h b/arch/arm/mach-ks8695/regs-sys.h
index 57c20be0c129..57c20be0c129 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-sys.h
+++ b/arch/arm/mach-ks8695/regs-sys.h
diff --git a/arch/arm/mach-ks8695/include/mach/regs-wan.h b/arch/arm/mach-ks8695/regs-wan.h
index c475bed22b8e..c475bed22b8e 100644
--- a/arch/arm/mach-ks8695/include/mach/regs-wan.h
+++ b/arch/arm/mach-ks8695/regs-wan.h
diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
index aeece17e5cea..0abcc51afff5 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_MEDIATEK
- bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7
+ bool "Mediatek MT65xx & MT81xx SoC"
+ depends on ARCH_MULTI_V7
select ARM_GIC
select PINCTRL
select MTK_TIMER
diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c
index d019a080a559..2f9f09ac51bd 100644
--- a/arch/arm/mach-mediatek/mediatek.c
+++ b/arch/arm/mach-mediatek/mediatek.c
@@ -44,6 +44,7 @@ static void __init mediatek_timer_init(void)
};
static const char * const mediatek_board_dt_compat[] = {
+ "mediatek,mt2701",
"mediatek,mt6589",
"mediatek,mt6592",
"mediatek,mt8127",
diff --git a/arch/arm/mach-mediatek/platsmp.c b/arch/arm/mach-mediatek/platsmp.c
index 8141f3f8afed..a1b07eeaaf5b 100644
--- a/arch/arm/mach-mediatek/platsmp.c
+++ b/arch/arm/mach-mediatek/platsmp.c
@@ -128,13 +128,13 @@ static void __init mtk_smp_prepare_cpus(unsigned int max_cpus)
__mtk_smp_prepare_cpus(max_cpus, 0);
}
-static struct smp_operations mt81xx_tz_smp_ops __initdata = {
+static const struct smp_operations mt81xx_tz_smp_ops __initconst = {
.smp_prepare_cpus = mtk_tz_smp_prepare_cpus,
.smp_boot_secondary = mtk_boot_secondary,
};
CPU_METHOD_OF_DECLARE(mt81xx_tz_smp, "mediatek,mt81xx-tz-smp", &mt81xx_tz_smp_ops);
-static struct smp_operations mt6589_smp_ops __initdata = {
+static const struct smp_operations mt6589_smp_ops __initconst = {
.smp_prepare_cpus = mtk_smp_prepare_cpus,
.smp_boot_secondary = mtk_boot_secondary,
};
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index 5d56f86ae1a4..31bdd91098b6 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_MESON
- bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
+ bool "Amlogic Meson SoCs"
+ depends on ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select GENERIC_IRQ_CHIP
select ARM_GIC
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index fdbfadf00c84..01c57d369462 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -1,9 +1,22 @@
+menuconfig ARCH_MMP
+ bool "Marvell PXA168/910/MMP2"
+ depends on ARCH_MULTI_V5 || ARCH_MULTI_V7
+ select ARCH_REQUIRE_GPIOLIB
+ select GPIO_PXA
+ select PINCTRL
+ select PLAT_PXA
+ help
+ Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
+
if ARCH_MMP
-menu "Marvell PXA168/910/MMP2 Implmentations"
+menu "Marvell PXA168/910/MMP2 Implementations"
+
+if ATAGS
config MACH_ASPENITE
bool "Marvell's PXA168 Aspenite Development Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
@@ -11,6 +24,7 @@ config MACH_ASPENITE
config MACH_ZYLONITE2
bool "Marvell's PXA168 Zylonite2 Development Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
@@ -18,6 +32,7 @@ config MACH_ZYLONITE2
config MACH_AVENGERS_LITE
bool "Marvell's PXA168 Avengers Lite Development Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
@@ -25,6 +40,7 @@ config MACH_AVENGERS_LITE
config MACH_TAVOREVB
bool "Marvell's PXA910 TavorEVB Development Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA910
help
Say 'Y' here if you want to support the Marvell PXA910-based
@@ -32,6 +48,7 @@ config MACH_TAVOREVB
config MACH_TTC_DKB
bool "Marvell's PXA910 TavorEVB Development Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA910
help
Say 'Y' here if you want to support the Marvell PXA910-based
@@ -39,7 +56,7 @@ config MACH_TTC_DKB
config MACH_BROWNSTONE
bool "Marvell's Brownstone Development Platform"
- depends on !CPU_MOHAWK
+ depends on ARCH_MULTI_V7
select CPU_MMP2
help
Say 'Y' here if you want to support the Marvell MMP2-based
@@ -50,7 +67,7 @@ config MACH_BROWNSTONE
config MACH_FLINT
bool "Marvell's Flint Development Platform"
- depends on !CPU_MOHAWK
+ depends on ARCH_MULTI_V7
select CPU_MMP2
help
Say 'Y' here if you want to support the Marvell MMP2-based
@@ -61,7 +78,7 @@ config MACH_FLINT
config MACH_MARVELL_JASPER
bool "Marvell's Jasper Development Platform"
- depends on !CPU_MOHAWK
+ depends on ARCH_MULTI_V7
select CPU_MMP2
help
Say 'Y' here if you want to support the Marvell MMP2-base
@@ -72,6 +89,7 @@ config MACH_MARVELL_JASPER
config MACH_TETON_BGA
bool "Marvell's PXA168 Teton BGA Development Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
@@ -79,14 +97,16 @@ config MACH_TETON_BGA
config MACH_GPLUGD
bool "Marvell's PXA168 GuruPlug Display (gplugD) Board"
+ depends on ARCH_MULTI_V5
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
GuruPlug Display (gplugD) Board
+endif
config MACH_MMP_DT
bool "Support MMP (ARMv5) platforms from device tree"
- select USE_OF
+ depends on ARCH_MULTI_V5
select PINCTRL
select PINCTRL_SINGLE
select COMMON_CLK
@@ -99,11 +119,9 @@ config MACH_MMP_DT
config MACH_MMP2_DT
bool "Support MMP2 (ARMv7) platforms from device tree"
- depends on !CPU_MOHAWK
- select USE_OF
+ depends on ARCH_MULTI_V7
select PINCTRL
select PINCTRL_SINGLE
- select COMMON_CLK
select ARCH_HAS_RESET_CONTROLLER
select CPU_PJ4
help
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 98f0f6388e44..7677ad5414e9 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -1,6 +1,7 @@
#
# Makefile for Marvell's PXA168 processors line
#
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-pxa/include
obj-y += common.o devices.o time.o
diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/addr-map.h
index f88a44c0ef91..2739d27bc89d 100644
--- a/arch/arm/mach-mmp/include/mach/addr-map.h
+++ b/arch/arm/mach-mmp/addr-map.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/include/mach/addr-map.h
- *
* Common address map definitions
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 7e0248582efd..5db0edf716dd 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -22,14 +22,14 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-pxa168.h>
-#include <mach/pxa168.h>
-#include <mach/irqs.h>
#include <video/pxa168fb.h>
#include <linux/input.h>
#include <linux/platform_data/keypad-pxa27x.h>
+#include "addr-map.h"
+#include "mfp-pxa168.h"
+#include "pxa168.h"
+#include "irqs.h"
#include "common.h"
static unsigned long common_pin_config[] __initdata = {
diff --git a/arch/arm/mach-mmp/avengers_lite.c b/arch/arm/mach-mmp/avengers_lite.c
index a451a0f4d512..3d2aea830ef7 100644
--- a/arch/arm/mach-mmp/avengers_lite.c
+++ b/arch/arm/mach-mmp/avengers_lite.c
@@ -17,10 +17,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-pxa168.h>
-#include <mach/pxa168.h>
-#include <mach/irqs.h>
+#include "addr-map.h"
+#include "mfp-pxa168.h"
+#include "pxa168.h"
+#include "irqs.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index ac25544b8cdb..d1613b954926 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -22,10 +22,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-mmp2.h>
-#include <mach/mmp2.h>
-#include <mach/irqs.h>
+#include "addr-map.h"
+#include "mfp-mmp2.h"
+#include "mmp2.h"
+#include "irqs.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/clock-mmp2.c b/arch/arm/mach-mmp/clock-mmp2.c
index 53d77cbd6000..835c3e7cc67e 100644
--- a/arch/arm/mach-mmp/clock-mmp2.c
+++ b/arch/arm/mach-mmp/clock-mmp2.c
@@ -4,8 +4,9 @@
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clk/mmp.h>
-#include <mach/addr-map.h>
+#include "addr-map.h"
#include "common.h"
#include "clock.h"
@@ -105,7 +106,8 @@ static struct clk_lookup mmp2_clkregs[] = {
INIT_CLKREG(&clk_sdh3, "sdhci-pxav3.3", "PXA-SDHCLK"),
};
-void __init mmp2_clk_init(void)
+void __init mmp2_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys)
{
clkdev_add_table(ARRAY_AND_SIZE(mmp2_clkregs));
}
diff --git a/arch/arm/mach-mmp/clock-pxa168.c b/arch/arm/mach-mmp/clock-pxa168.c
index c572f219ae26..f726a3692431 100644
--- a/arch/arm/mach-mmp/clock-pxa168.c
+++ b/arch/arm/mach-mmp/clock-pxa168.c
@@ -4,8 +4,9 @@
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clk/mmp.h>
-#include <mach/addr-map.h>
+#include "addr-map.h"
#include "common.h"
#include "clock.h"
@@ -85,7 +86,8 @@ static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
};
-void __init pxa168_clk_init(void)
+void __init pxa168_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys)
{
clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs));
}
diff --git a/arch/arm/mach-mmp/clock-pxa910.c b/arch/arm/mach-mmp/clock-pxa910.c
index 379e1df61c70..bca60a224e07 100644
--- a/arch/arm/mach-mmp/clock-pxa910.c
+++ b/arch/arm/mach-mmp/clock-pxa910.c
@@ -4,8 +4,9 @@
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clk/mmp.h>
-#include <mach/addr-map.h>
+#include "addr-map.h"
#include "common.h"
#include "clock.h"
@@ -61,7 +62,8 @@ static struct clk_lookup pxa910_clkregs[] = {
INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
};
-void __init pxa910_clk_init(void)
+void __init pxa910_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys, phys_addr_t apbcp_phys)
{
clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs));
}
diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c
index 7c6f95f29142..ac6633d0b69b 100644
--- a/arch/arm/mach-mmp/clock.c
+++ b/arch/arm/mach-mmp/clock.c
@@ -13,7 +13,7 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <mach/regs-apbc.h>
+#include "regs-apbc.h"
#include "clock.h"
static void apbc_clk_enable(struct clk *clk)
diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h
index 149b30cd1469..8194445183fe 100644
--- a/arch/arm/mach-mmp/clock.h
+++ b/arch/arm/mach-mmp/clock.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/clock.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.
diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c
index c03b4ab582db..685a0993cff6 100644
--- a/arch/arm/mach-mmp/common.c
+++ b/arch/arm/mach-mmp/common.c
@@ -15,8 +15,8 @@
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/system_misc.h>
-#include <mach/addr-map.h>
-#include <mach/cputype.h>
+#include "addr-map.h"
+#include "cputype.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index cf445bae6d77..7453a90c34bd 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -5,6 +5,3 @@ extern void timer_init(int irq);
extern void __init mmp_map_io(void);
extern void mmp_restart(enum reboot_mode, const char *);
-extern void __init pxa168_clk_init(void);
-extern void __init pxa910_clk_init(void);
-extern void __init mmp2_clk_init(void);
diff --git a/arch/arm/mach-mmp/include/mach/cputype.h b/arch/arm/mach-mmp/cputype.h
index 8a3b56dfd35d..8a3b56dfd35d 100644
--- a/arch/arm/mach-mmp/include/mach/cputype.h
+++ b/arch/arm/mach-mmp/cputype.h
diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c
index 2bcb766af05d..3330ac7cfbef 100644
--- a/arch/arm/mach-mmp/devices.c
+++ b/arch/arm/mach-mmp/devices.c
@@ -12,10 +12,10 @@
#include <linux/delay.h>
#include <asm/irq.h>
-#include <mach/irqs.h>
-#include <mach/devices.h>
-#include <mach/cputype.h>
-#include <mach/regs-usb.h>
+#include "irqs.h"
+#include "devices.h"
+#include "cputype.h"
+#include "regs-usb.h"
int __init pxa_register_device(struct pxa_device_desc *desc,
void *data, size_t size)
@@ -73,6 +73,8 @@ int __init pxa_register_device(struct pxa_device_desc *desc,
}
#if IS_ENABLED(CONFIG_USB) || IS_ENABLED(CONFIG_USB_GADGET)
+#if IS_ENABLED(CONFIG_USB_MV_UDC) || IS_ENABLED(CONFIG_USB_EHCI_MV)
+#if IS_ENABLED(CONFIG_CPU_PXA910) || IS_ENABLED(CONFIG_CPU_PXA168)
/*****************************************************************************
* The registers read/write routines
@@ -112,9 +114,6 @@ static void u2o_write(void __iomem *base, unsigned int offset,
readl_relaxed(base + offset);
}
-#if IS_ENABLED(CONFIG_USB_MV_UDC) || IS_ENABLED(CONFIG_USB_EHCI_MV)
-
-#if IS_ENABLED(CONFIG_CPU_PXA910) || IS_ENABLED(CONFIG_CPU_PXA168)
static DEFINE_MUTEX(phy_lock);
static int phy_init_cnt;
diff --git a/arch/arm/mach-mmp/include/mach/devices.h b/arch/arm/mach-mmp/devices.h
index 21217ef11b64..21217ef11b64 100644
--- a/arch/arm/mach-mmp/include/mach/devices.h
+++ b/arch/arm/mach-mmp/devices.h
diff --git a/arch/arm/mach-mmp/flint.c b/arch/arm/mach-mmp/flint.c
index 6291c33d83e2..078b98034960 100644
--- a/arch/arm/mach-mmp/flint.c
+++ b/arch/arm/mach-mmp/flint.c
@@ -21,10 +21,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-mmp2.h>
-#include <mach/mmp2.h>
-#include <mach/irqs.h>
+#include "addr-map.h"
+#include "mfp-mmp2.h"
+#include "mmp2.h"
+#include "irqs.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/gplugd.c b/arch/arm/mach-mmp/gplugd.c
index 22762a1f9f72..c224119dc0f4 100644
--- a/arch/arm/mach-mmp/gplugd.c
+++ b/arch/arm/mach-mmp/gplugd.c
@@ -16,9 +16,9 @@
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
-#include <mach/irqs.h>
-#include <mach/pxa168.h>
-#include <mach/mfp-pxa168.h>
+#include "irqs.h"
+#include "pxa168.h"
+#include "mfp-pxa168.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/include/mach/dma.h b/arch/arm/mach-mmp/include/mach/dma.h
deleted file mode 100644
index 1d6914544da4..000000000000
--- a/arch/arm/mach-mmp/include/mach/dma.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/dma.h
- */
-
-#ifndef __ASM_MACH_DMA_H
-#define __ASM_MACH_DMA_H
-
-#include <mach/addr-map.h>
-
-#define DMAC_REGS_VIRT (APB_VIRT_BASE + 0x00000)
-
-#include <plat/dma.h>
-#endif /* __ASM_MACH_DMA_H */
diff --git a/arch/arm/mach-mmp/include/mach/hardware.h b/arch/arm/mach-mmp/include/mach/hardware.h
deleted file mode 100644
index 99264a5ce5e4..000000000000
--- a/arch/arm/mach-mmp/include/mach/hardware.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __ASM_MACH_HARDWARE_H
-#define __ASM_MACH_HARDWARE_H
-
-#endif /* __ASM_MACH_HARDWARE_H */
diff --git a/arch/arm/mach-mmp/include/mach/regs-smc.h b/arch/arm/mach-mmp/include/mach/regs-smc.h
deleted file mode 100644
index e484d40d71bd..000000000000
--- a/arch/arm/mach-mmp/include/mach/regs-smc.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/regs-smc.h
- *
- * Static Memory Controller Registers
- *
- * 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 __ASM_MACH_REGS_SMC_H
-#define __ASM_MACH_REGS_SMC_H
-
-#include <mach/addr-map.h>
-
-#define SMC_VIRT_BASE (AXI_VIRT_BASE + 0x83800)
-#define SMC_REG(x) (SMC_VIRT_BASE + (x))
-
-#define SMC_MSC0 SMC_REG(0x0020)
-#define SMC_MSC1 SMC_REG(0x0024)
-#define SMC_SXCNFG0 SMC_REG(0x0030)
-#define SMC_SXCNFG1 SMC_REG(0x0034)
-#define SMC_MEMCLKCFG SMC_REG(0x0068)
-#define SMC_CSDFICFG0 SMC_REG(0x0090)
-#define SMC_CSDFICFG1 SMC_REG(0x0094)
-#define SMC_CLK_RET_DEL SMC_REG(0x00b0)
-#define SMC_ADV_RET_DEL SMC_REG(0x00b4)
-#define SMC_CSADRMAP0 SMC_REG(0x00c0)
-#define SMC_CSADRMAP1 SMC_REG(0x00c4)
-#define SMC_WE_AP0 SMC_REG(0x00e0)
-#define SMC_WE_AP1 SMC_REG(0x00e4)
-#define SMC_OE_AP0 SMC_REG(0x00f0)
-#define SMC_OE_AP1 SMC_REG(0x00f4)
-#define SMC_ADV_AP0 SMC_REG(0x0100)
-#define SMC_ADV_AP1 SMC_REG(0x0104)
-
-#endif /* __ASM_MACH_REGS_SMC_H */
diff --git a/arch/arm/mach-mmp/include/mach/uncompress.h b/arch/arm/mach-mmp/include/mach/uncompress.h
deleted file mode 100644
index 8890fa8fa771..000000000000
--- a/arch/arm/mach-mmp/include/mach/uncompress.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * arch/arm/mach-mmp/include/mach/uncompress.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.
- */
-
-#include <linux/serial_reg.h>
-#include <mach/addr-map.h>
-#include <asm/mach-types.h>
-
-#define UART1_BASE (APB_PHYS_BASE + 0x36000)
-#define UART2_BASE (APB_PHYS_BASE + 0x17000)
-#define UART3_BASE (APB_PHYS_BASE + 0x18000)
-
-volatile unsigned long *UART;
-
-static inline void putc(char c)
-{
- /* UART enabled? */
- if (!(UART[UART_IER] & UART_IER_UUE))
- return;
-
- while (!(UART[UART_LSR] & UART_LSR_THRE))
- barrier();
-
- UART[UART_TX] = c;
-}
-
-/*
- * This does not append a newline
- */
-static inline void flush(void)
-{
-}
-
-static inline void arch_decomp_setup(void)
-{
- /* default to UART2 */
- UART = (unsigned long *)UART2_BASE;
-
- if (machine_is_avengers_lite())
- UART = (unsigned long *)UART3_BASE;
-}
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/irqs.h
index fb492a50a817..fb492a50a817 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/irqs.h
diff --git a/arch/arm/mach-mmp/jasper.c b/arch/arm/mach-mmp/jasper.c
index 0e9e5c05b37c..5dbb753a77ac 100644
--- a/arch/arm/mach-mmp/jasper.c
+++ b/arch/arm/mach-mmp/jasper.c
@@ -20,12 +20,12 @@
#include <linux/mfd/max8925.h>
#include <linux/interrupt.h>
-#include <mach/irqs.h>
+#include "irqs.h"
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-mmp2.h>
-#include <mach/mmp2.h>
+#include "addr-map.h"
+#include "mfp-mmp2.h"
+#include "mmp2.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/include/mach/mfp-mmp2.h b/arch/arm/mach-mmp/mfp-mmp2.h
index 4ad38629c3f6..b2744349725d 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
+++ b/arch/arm/mach-mmp/mfp-mmp2.h
@@ -1,7 +1,7 @@
#ifndef __ASM_MACH_MFP_MMP2_H
#define __ASM_MACH_MFP_MMP2_H
-#include <mach/mfp.h>
+#include "mfp.h"
#define MFP_DRIVE_VERY_SLOW (0x0 << 13)
#define MFP_DRIVE_SLOW (0x2 << 13)
diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa168.h b/arch/arm/mach-mmp/mfp-pxa168.h
index 92aaa3c19d61..9050d032377e 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-pxa168.h
+++ b/arch/arm/mach-mmp/mfp-pxa168.h
@@ -1,7 +1,7 @@
#ifndef __ASM_MACH_MFP_PXA168_H
#define __ASM_MACH_MFP_PXA168_H
-#include <mach/mfp.h>
+#include "mfp.h"
#define MFP_DRIVE_VERY_SLOW (0x0 << 13)
#define MFP_DRIVE_SLOW (0x1 << 13)
diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h b/arch/arm/mach-mmp/mfp-pxa910.h
index 8c78f2b16452..f06db5cd3ad3 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
+++ b/arch/arm/mach-mmp/mfp-pxa910.h
@@ -1,7 +1,7 @@
#ifndef __ASM_MACH_MFP_PXA910_H
#define __ASM_MACH_MFP_PXA910_H
-#include <mach/mfp.h>
+#include "mfp.h"
#define MFP_DRIVE_VERY_SLOW (0x0 << 13)
#define MFP_DRIVE_SLOW (0x2 << 13)
diff --git a/arch/arm/mach-mmp/include/mach/mfp.h b/arch/arm/mach-mmp/mfp.h
index 62e510e80a58..62e510e80a58 100644
--- a/arch/arm/mach-mmp/include/mach/mfp.h
+++ b/arch/arm/mach-mmp/mfp.h
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index a70b5530bd42..afba5460cdaf 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -9,6 +9,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/clk/mmp.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -20,15 +21,14 @@
#include <asm/hardware/cache-tauros2.h>
#include <asm/mach/time.h>
-#include <mach/addr-map.h>
-#include <mach/regs-apbc.h>
-#include <mach/cputype.h>
-#include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/mfp.h>
-#include <mach/devices.h>
-#include <mach/mmp2.h>
-#include <mach/pm-mmp2.h>
+#include "addr-map.h"
+#include "regs-apbc.h"
+#include "cputype.h"
+#include "irqs.h"
+#include "mfp.h"
+#include "devices.h"
+#include "mmp2.h"
+#include "pm-mmp2.h"
#include "common.h"
@@ -110,8 +110,9 @@ static int __init mmp2_init(void)
#endif
mfp_init_base(MFPR_VIRT_BASE);
mfp_init_addr(mmp2_addr_map);
- pxa_init_dma(IRQ_MMP2_DMA_RIQ, 16);
- mmp2_clk_init();
+ mmp2_clk_init(APB_PHYS_BASE + 0x50000,
+ AXI_PHYS_BASE + 0x82800,
+ APB_PHYS_BASE + 0x15000);
}
return 0;
diff --git a/arch/arm/mach-mmp/include/mach/mmp2.h b/arch/arm/mach-mmp/mmp2.h
index 0764f4ecec82..9b5e75ee9e4d 100644
--- a/arch/arm/mach-mmp/include/mach/mmp2.h
+++ b/arch/arm/mach-mmp/mmp2.h
@@ -10,9 +10,10 @@ extern void mmp2_clear_pmic_int(void);
#include <linux/i2c.h>
#include <linux/i2c/pxa-i2c.h>
-#include <mach/devices.h>
#include <linux/platform_data/dma-mmp_tdma.h>
+#include "devices.h"
+
extern struct pxa_device_desc mmp2_device_uart1;
extern struct pxa_device_desc mmp2_device_uart2;
extern struct pxa_device_desc mmp2_device_uart3;
diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c
index 43b1a516957f..17699be3bc3d 100644
--- a/arch/arm/mach-mmp/pm-mmp2.c
+++ b/arch/arm/mach-mmp/pm-mmp2.c
@@ -18,12 +18,12 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/cputype.h>
-#include <mach/addr-map.h>
-#include <mach/pm-mmp2.h>
-#include <mach/regs-icu.h>
-#include <mach/irqs.h>
+
+#include "cputype.h"
+#include "addr-map.h"
+#include "pm-mmp2.h"
+#include "regs-icu.h"
+#include "irqs.h"
int mmp2_set_wake(struct irq_data *d, unsigned int on)
{
diff --git a/arch/arm/mach-mmp/include/mach/pm-mmp2.h b/arch/arm/mach-mmp/pm-mmp2.h
index 98bd66ce8006..486e0590cd8d 100644
--- a/arch/arm/mach-mmp/include/mach/pm-mmp2.h
+++ b/arch/arm/mach-mmp/pm-mmp2.h
@@ -11,7 +11,7 @@
#ifndef __MMP2_PM_H__
#define __MMP2_PM_H__
-#include <mach/addr-map.h>
+#include "addr-map.h"
#define APMU_PJ_IDLE_CFG APMU_REG(0x018)
#define APMU_PJ_IDLE_CFG_PJ_IDLE (1 << 1)
diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c
index 7db5870d127f..8b47600b3cdf 100644
--- a/arch/arm/mach-mmp/pm-pxa910.c
+++ b/arch/arm/mach-mmp/pm-pxa910.c
@@ -19,12 +19,12 @@
#include <linux/irq.h>
#include <asm/mach-types.h>
#include <asm/outercache.h>
-#include <mach/hardware.h>
-#include <mach/cputype.h>
-#include <mach/addr-map.h>
-#include <mach/pm-pxa910.h>
-#include <mach/regs-icu.h>
-#include <mach/irqs.h>
+
+#include "cputype.h"
+#include "addr-map.h"
+#include "pm-pxa910.h"
+#include "regs-icu.h"
+#include "irqs.h"
int pxa910_set_wake(struct irq_data *data, unsigned int on)
{
diff --git a/arch/arm/mach-mmp/include/mach/pm-pxa910.h b/arch/arm/mach-mmp/pm-pxa910.h
index 8cac8ab5253d..8cac8ab5253d 100644
--- a/arch/arm/mach-mmp/include/mach/pm-pxa910.h
+++ b/arch/arm/mach-mmp/pm-pxa910.h
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 144e997624c0..0f5f16fb8c66 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -13,25 +13,25 @@
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clk/mmp.h>
#include <linux/platform_device.h>
#include <linux/platform_data/mv_usb.h>
+#include <linux/dma-mapping.h>
#include <asm/mach/time.h>
#include <asm/system_misc.h>
-#include <mach/cputype.h>
-#include <mach/addr-map.h>
-#include <mach/regs-apbc.h>
-#include <mach/regs-apmu.h>
-#include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/devices.h>
-#include <mach/mfp.h>
-#include <linux/dma-mapping.h>
-#include <mach/pxa168.h>
-#include <mach/regs-usb.h>
-#include "common.h"
+#include "addr-map.h"
#include "clock.h"
+#include "common.h"
+#include "cputype.h"
+#include "devices.h"
+#include "irqs.h"
+#include "mfp.h"
+#include "pxa168.h"
+#include "regs-apbc.h"
+#include "regs-apmu.h"
+#include "regs-usb.h"
#define MFPR_VIRT_BASE (APB_VIRT_BASE + 0x1e000)
@@ -55,8 +55,9 @@ static int __init pxa168_init(void)
if (cpu_is_pxa168()) {
mfp_init_base(MFPR_VIRT_BASE);
mfp_init_addr(pxa168_mfp_addr_map);
- pxa_init_dma(IRQ_PXA168_DMA_INT0, 32);
- pxa168_clk_init();
+ pxa168_clk_init(APB_PHYS_BASE + 0x50000,
+ AXI_PHYS_BASE + 0x82800,
+ APB_PHYS_BASE + 0x15000);
}
return 0;
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/pxa168.h
index a83ba7cb525d..75841e9ccd73 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/pxa168.h
@@ -11,14 +11,15 @@ extern void pxa168_clear_keypad_wakeup(void);
#include <linux/i2c.h>
#include <linux/i2c/pxa-i2c.h>
-#include <mach/devices.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>
#include <video/pxa168fb.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/cputype.h>
#include <linux/pxa168_eth.h>
#include <linux/platform_data/mv_usb.h>
+#include "devices.h"
+#include "cputype.h"
+
extern struct pxa_device_desc pxa168_device_uart1;
extern struct pxa_device_desc pxa168_device_uart2;
extern struct pxa_device_desc pxa168_device_uart3;
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index eb57ee196842..1ccbba9ac495 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -7,6 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/clk/mmp.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -18,15 +19,14 @@
#include <asm/hardware/cache-tauros2.h>
#include <asm/mach/time.h>
-#include <mach/addr-map.h>
-#include <mach/regs-apbc.h>
-#include <mach/cputype.h>
-#include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/mfp.h>
-#include <mach/devices.h>
-#include <mach/pm-pxa910.h>
-#include <mach/pxa910.h>
+#include "addr-map.h"
+#include "regs-apbc.h"
+#include "cputype.h"
+#include "irqs.h"
+#include "mfp.h"
+#include "devices.h"
+#include "pm-pxa910.h"
+#include "pxa910.h"
#include "common.h"
@@ -96,8 +96,10 @@ static int __init pxa910_init(void)
#endif
mfp_init_base(MFPR_VIRT_BASE);
mfp_init_addr(pxa910_mfp_addr_map);
- pxa_init_dma(IRQ_PXA910_DMA_INT0, 32);
- pxa910_clk_init();
+ pxa910_clk_init(APB_PHYS_BASE + 0x50000,
+ AXI_PHYS_BASE + 0x82800,
+ APB_PHYS_BASE + 0x15000,
+ APB_PHYS_BASE + 0x3b000);
}
return 0;
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/pxa910.h
index 92253203f5b4..a211e81e5a08 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/pxa910.h
@@ -7,10 +7,11 @@ extern void __init pxa910_init_irq(void);
#include <linux/i2c.h>
#include <linux/i2c/pxa-i2c.h>
-#include <mach/devices.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>
#include <video/mmp_disp.h>
+#include "devices.h"
+
extern struct pxa_device_desc pxa910_device_uart1;
extern struct pxa_device_desc pxa910_device_uart2;
extern struct pxa_device_desc pxa910_device_twsi0;
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/regs-apbc.h
index ddc812f40341..704bcae3fc26 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/regs-apbc.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/include/mach/regs-apbc.h
- *
* Application Peripheral Bus Clock Unit
*
* This program is free software; you can redistribute it and/or modify
@@ -11,7 +9,7 @@
#ifndef __ASM_MACH_REGS_APBC_H
#define __ASM_MACH_REGS_APBC_H
-#include <mach/addr-map.h>
+#include "addr-map.h"
/* Common APB clock register bit definitions */
#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/regs-apmu.h
index 93c8d0e29bb9..23f6209b65aa 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apmu.h
+++ b/arch/arm/mach-mmp/regs-apmu.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/include/mach/regs-apmu.h
- *
* Application Subsystem Power Management Unit
*
* This program is free software; you can redistribute it and/or modify
@@ -11,7 +9,7 @@
#ifndef __ASM_MACH_REGS_APMU_H
#define __ASM_MACH_REGS_APMU_H
-#include <mach/addr-map.h>
+#include "addr-map.h"
#define APMU_FNCLK_EN (1 << 4)
#define APMU_AXICLK_EN (1 << 3)
diff --git a/arch/arm/mach-mmp/include/mach/regs-icu.h b/arch/arm/mach-mmp/regs-icu.h
index f882d91894be..0328abe340a4 100644
--- a/arch/arm/mach-mmp/include/mach/regs-icu.h
+++ b/arch/arm/mach-mmp/regs-icu.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/include/mach/regs-icu.h
- *
* Interrupt Control Unit
*
* This program is free software; you can redistribute it and/or modify
@@ -11,7 +9,7 @@
#ifndef __ASM_MACH_ICU_H
#define __ASM_MACH_ICU_H
-#include <mach/addr-map.h>
+#include "addr-map.h"
#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000)
#define ICU_REG(x) (ICU_VIRT_BASE + (x))
diff --git a/arch/arm/mach-mmp/include/mach/regs-timers.h b/arch/arm/mach-mmp/regs-timers.h
index 45589fec9fc7..d3611c0becf0 100644
--- a/arch/arm/mach-mmp/include/mach/regs-timers.h
+++ b/arch/arm/mach-mmp/regs-timers.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/include/mach/regs-timers.h
- *
* Timers Module
*
* This program is free software; you can redistribute it and/or modify
@@ -11,7 +9,7 @@
#ifndef __ASM_MACH_REGS_TIMERS_H
#define __ASM_MACH_REGS_TIMERS_H
-#include <mach/addr-map.h>
+#include "addr-map.h"
#define TIMERS1_VIRT_BASE (APB_VIRT_BASE + 0x14000)
#define TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x16000)
diff --git a/arch/arm/mach-mmp/include/mach/regs-usb.h b/arch/arm/mach-mmp/regs-usb.h
index b047bf487506..b047bf487506 100644
--- a/arch/arm/mach-mmp/include/mach/regs-usb.h
+++ b/arch/arm/mach-mmp/regs-usb.h
diff --git a/arch/arm/mach-mmp/tavorevb.c b/arch/arm/mach-mmp/tavorevb.c
index cdfc9bfee1a4..efe35fadeb60 100644
--- a/arch/arm/mach-mmp/tavorevb.c
+++ b/arch/arm/mach-mmp/tavorevb.c
@@ -16,10 +16,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-pxa910.h>
-#include <mach/pxa910.h>
-#include <mach/irqs.h>
+#include "addr-map.h"
+#include "mfp-pxa910.h"
+#include "pxa910.h"
+#include "irqs.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/teton_bga.c b/arch/arm/mach-mmp/teton_bga.c
index 6aa53fb29d26..cf038eb3bb4b 100644
--- a/arch/arm/mach-mmp/teton_bga.c
+++ b/arch/arm/mach-mmp/teton_bga.c
@@ -23,11 +23,11 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-pxa168.h>
-#include <mach/pxa168.h>
-#include <mach/teton_bga.h>
-#include <mach/irqs.h>
+#include "addr-map.h"
+#include "mfp-pxa168.h"
+#include "pxa168.h"
+#include "teton_bga.h"
+#include "irqs.h"
#include "common.h"
diff --git a/arch/arm/mach-mmp/include/mach/teton_bga.h b/arch/arm/mach-mmp/teton_bga.h
index 61a539b2cc98..019730f5aa56 100644
--- a/arch/arm/mach-mmp/include/mach/teton_bga.h
+++ b/arch/arm/mach-mmp/teton_bga.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-mmp/include/mach/teton_bga.h
- *
* Support for the Marvell PXA168 Teton BGA Development Platform.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index dbc697b2fda1..3c2c92aaa0ae 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -29,14 +29,13 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
-
-#include <mach/addr-map.h>
-#include <mach/regs-timers.h>
-#include <mach/regs-apbc.h>
-#include <mach/irqs.h>
-#include <mach/cputype.h>
#include <asm/mach/time.h>
+#include "addr-map.h"
+#include "regs-timers.h"
+#include "regs-apbc.h"
+#include "irqs.h"
+#include "cputype.h"
#include "clock.h"
#ifdef CONFIG_CPU_MMP2
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index ac4af81de3ea..d90c74fa614d 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -26,11 +26,11 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
-#include <mach/addr-map.h>
-#include <mach/mfp-pxa910.h>
-#include <mach/pxa910.h>
-#include <mach/irqs.h>
-#include <mach/regs-usb.h>
+#include "addr-map.h"
+#include "mfp-pxa910.h"
+#include "pxa910.h"
+#include "irqs.h"
+#include "regs-usb.h"
#include "common.h"
diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig
index f49328c39bef..180d9d216719 100644
--- a/arch/arm/mach-moxart/Kconfig
+++ b/arch/arm/mach-moxart/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_MOXART
- bool "MOXA ART SoC" if ARCH_MULTI_V4
+ bool "MOXA ART SoC"
+ depends on ARCH_MULTI_V4
select CPU_FA526
select ARM_DMA_MEM_BUFFERABLE
select CLKSRC_MMIO
diff --git a/arch/arm/mach-mv78xx0/Kconfig b/arch/arm/mach-mv78xx0/Kconfig
index f2d309d0619e..a32575fa3fba 100644
--- a/arch/arm/mach-mv78xx0/Kconfig
+++ b/arch/arm/mach-mv78xx0/Kconfig
@@ -1,6 +1,15 @@
-if ARCH_MV78XX0
+menuconfig ARCH_MV78XX0
+ bool "Marvell MV78xx0" if ARCH_MULTI_V5
+ select ARCH_REQUIRE_GPIOLIB
+ select CPU_FEROCEON
+ select MVEBU_MBUS
+ select PCI
+ select PLAT_ORION_LEGACY
+ help
+ Support for the following Marvell MV78xx0 series SoCs:
+ MV781x0, MV782x0.
-menu "Marvell MV78xx0 Implementations"
+if ARCH_MV78XX0
config MACH_DB78X00_BP
bool "Marvell DB-78x00-BP Development Board"
@@ -20,6 +29,4 @@ config MACH_TERASTATION_WXL
Say 'Y' here if you want your kernel to support the
Buffalo WXL Nas.
-endmenu
-
endif
diff --git a/arch/arm/mach-mv78xx0/Makefile b/arch/arm/mach-mv78xx0/Makefile
index 7cd04634d302..ddb3aa98a3c7 100644
--- a/arch/arm/mach-mv78xx0/Makefile
+++ b/arch/arm/mach-mv78xx0/Makefile
@@ -1,3 +1,5 @@
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-orion/include
+
obj-y += common.o mpp.o irq.o pcie.o
obj-$(CONFIG_MACH_DB78X00_BP) += db78x00-bp-setup.o
obj-$(CONFIG_MACH_RD78X00_MASA) += rd78x00-masa-setup.o
diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/bridge-regs.h
index e20d6da234a6..2f54e1753d45 100644
--- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
+++ b/arch/arm/mach-mv78xx0/bridge-regs.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
- *
* 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.
@@ -9,7 +7,7 @@
#ifndef __ASM_ARCH_BRIDGE_REGS_H
#define __ASM_ARCH_BRIDGE_REGS_H
-#include <mach/mv78xx0.h>
+#include "mv78xx0.h"
#define CPU_CONTROL (BRIDGE_VIRT_BASE + 0x0104)
#define L2_WRITETHROUGH 0x00020000
diff --git a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
index 1f2ef98b37c6..e112f2e7cc9a 100644
--- a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
+++ b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
@@ -17,9 +17,9 @@
#include <linux/mv643xx_eth.h>
#include <linux/ethtool.h>
#include <linux/i2c.h>
-#include <mach/mv78xx0.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include "mv78xx0.h"
#include "common.h"
#include "mpp.h"
@@ -146,6 +146,7 @@ subsys_initcall(wxl_pci_init);
MACHINE_START(TERASTATION_WXL, "Buffalo Nas WXL")
/* Maintainer: Sebastien Requiem <sebastien@requiem.fr> */
.atag_offset = 0x100,
+ .nr_irqs = MV78XX0_NR_IRQS,
.init_machine = wxl_init,
.map_io = mv78xx0_map_io,
.init_early = mv78xx0_init_early,
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index e6ac679bece9..a1a04df9c05c 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -18,13 +18,13 @@
#include <asm/hardware/cache-feroceon-l2.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <mach/mv78xx0.h>
-#include <mach/bridge-regs.h>
#include <linux/platform_data/usb-ehci-orion.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include <plat/time.h>
#include <plat/common.h>
#include <plat/addr-map.h>
+#include "mv78xx0.h"
+#include "bridge-regs.h"
#include "common.h"
static int get_tclk(void);
diff --git a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
index 4e0f22b30bc8..cf16e08d4cf5 100644
--- a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
+++ b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
@@ -15,9 +15,9 @@
#include <linux/mv643xx_eth.h>
#include <linux/ethtool.h>
#include <linux/i2c.h>
-#include <mach/mv78xx0.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include "mv78xx0.h"
#include "common.h"
static struct mv643xx_eth_platform_data db78x00_ge00_data = {
@@ -94,6 +94,7 @@ subsys_initcall(db78x00_pci_init);
MACHINE_START(DB78X00_BP, "Marvell DB-78x00-BP Development Board")
/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = MV78XX0_NR_IRQS,
.init_machine = db78x00_init,
.map_io = mv78xx0_map_io,
.init_early = mv78xx0_init_early,
diff --git a/arch/arm/mach-mv78xx0/include/mach/entry-macro.S b/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
deleted file mode 100644
index 6b1f088e0597..000000000000
--- a/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Marvell MV78xx0 platforms
- *
- * 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 <mach/bridge-regs.h>
-
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =IRQ_VIRT_BASE
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- @ check low interrupts
- ldr \irqstat, [\base, #IRQ_CAUSE_LOW_OFF]
- ldr \tmp, [\base, #IRQ_MASK_LOW_OFF]
- mov \irqnr, #31
- ands \irqstat, \irqstat, \tmp
- bne 1001f
-
- @ if no low interrupts set, check high interrupts
- ldr \irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
- ldr \tmp, [\base, #IRQ_MASK_HIGH_OFF]
- mov \irqnr, #63
- ands \irqstat, \irqstat, \tmp
- bne 1001f
-
- @ if no high interrupts set, check error interrupts
- ldr \irqstat, [\base, #IRQ_CAUSE_ERR_OFF]
- ldr \tmp, [\base, #IRQ_MASK_ERR_OFF]
- mov \irqnr, #95
- ands \irqstat, \irqstat, \tmp
-
- @ find first active interrupt source
-1001: clzne \irqstat, \irqstat
- subne \irqnr, \irqnr, \irqstat
- .endm
diff --git a/arch/arm/mach-mv78xx0/include/mach/hardware.h b/arch/arm/mach-mv78xx0/include/mach/hardware.h
deleted file mode 100644
index 67cab0a08e07..000000000000
--- a/arch/arm/mach-mv78xx0/include/mach/hardware.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/hardware.h
- *
- * 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.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include "mv78xx0.h"
-
-#endif
diff --git a/arch/arm/mach-mv78xx0/include/mach/uncompress.h b/arch/arm/mach-mv78xx0/include/mach/uncompress.h
deleted file mode 100644
index 6a761c44a296..000000000000
--- a/arch/arm/mach-mv78xx0/include/mach/uncompress.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/uncompress.h
- *
- * 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/serial_reg.h>
-#include <mach/mv78xx0.h>
-
-#define SERIAL_BASE ((unsigned char *)UART0_PHYS_BASE)
-
-static void putc(const char c)
-{
- unsigned char *base = SERIAL_BASE;
- int i;
-
- for (i = 0; i < 0x1000; i++) {
- if (base[UART_LSR << 2] & UART_LSR_THRE)
- break;
- barrier();
- }
-
- base[UART_TX << 2] = c;
-}
-
-static void flush(void)
-{
- unsigned char *base = SERIAL_BASE;
- unsigned char mask;
- int i;
-
- mask = UART_LSR_TEMT | UART_LSR_THRE;
-
- for (i = 0; i < 0x1000; i++) {
- if ((base[UART_LSR << 2] & mask) == mask)
- break;
- barrier();
- }
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c
index 32073444024b..788569e960e1 100644
--- a/arch/arm/mach-mv78xx0/irq.c
+++ b/arch/arm/mach-mv78xx0/irq.c
@@ -11,9 +11,10 @@
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <mach/bridge-regs.h>
+#include <asm/exception.h>
#include <plat/orion-gpio.h>
#include <plat/irq.h>
+#include "bridge-regs.h"
#include "common.h"
static int __initdata gpio0_irqs[4] = {
@@ -23,12 +24,44 @@ static int __initdata gpio0_irqs[4] = {
IRQ_MV78XX0_GPIO_24_31,
};
+static void __iomem *mv78xx0_irq_base = IRQ_VIRT_BASE;
+
+static asmlinkage void
+__exception_irq_entry mv78xx0_legacy_handle_irq(struct pt_regs *regs)
+{
+ u32 stat;
+
+ stat = readl_relaxed(mv78xx0_irq_base + IRQ_CAUSE_LOW_OFF);
+ stat &= readl_relaxed(mv78xx0_irq_base + IRQ_MASK_LOW_OFF);
+ if (stat) {
+ unsigned int hwirq = __fls(stat);
+ handle_IRQ(hwirq, regs);
+ return;
+ }
+ stat = readl_relaxed(mv78xx0_irq_base + IRQ_CAUSE_HIGH_OFF);
+ stat &= readl_relaxed(mv78xx0_irq_base + IRQ_MASK_HIGH_OFF);
+ if (stat) {
+ unsigned int hwirq = 32 + __fls(stat);
+ handle_IRQ(hwirq, regs);
+ return;
+ }
+ stat = readl_relaxed(mv78xx0_irq_base + IRQ_CAUSE_ERR_OFF);
+ stat &= readl_relaxed(mv78xx0_irq_base + IRQ_MASK_ERR_OFF);
+ if (stat) {
+ unsigned int hwirq = 64 + __fls(stat);
+ handle_IRQ(hwirq, regs);
+ return;
+ }
+}
+
void __init mv78xx0_init_irq(void)
{
orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF);
orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF);
orion_irq_init(64, IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF);
+ set_handle_irq(mv78xx0_legacy_handle_irq);
+
/*
* Initialize gpiolib for GPIOs 0-31. (The GPIO interrupt mask
* registers for core #1 are at an offset of 0x18 from those of
diff --git a/arch/arm/mach-mv78xx0/include/mach/irqs.h b/arch/arm/mach-mv78xx0/irqs.h
index fa1d422196c2..67e0fe730a13 100644
--- a/arch/arm/mach-mv78xx0/include/mach/irqs.h
+++ b/arch/arm/mach-mv78xx0/irqs.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-mv78xx0/include/mach/irqs.h
- *
* IRQ definitions for Marvell MV78xx0 SoCs
*
* This file is licensed under the terms of the GNU General Public
@@ -88,7 +86,7 @@
#define IRQ_MV78XX0_GPIO_START 96
#define NR_GPIO_IRQS 32
-#define NR_IRQS (IRQ_MV78XX0_GPIO_START + NR_GPIO_IRQS)
+#define MV78XX0_NR_IRQS (IRQ_MV78XX0_GPIO_START + NR_GPIO_IRQS)
#endif
diff --git a/arch/arm/mach-mv78xx0/mpp.c b/arch/arm/mach-mv78xx0/mpp.c
index df50342179e2..72843c02e95a 100644
--- a/arch/arm/mach-mv78xx0/mpp.c
+++ b/arch/arm/mach-mv78xx0/mpp.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <plat/mpp.h>
-#include <mach/hardware.h>
+#include "mv78xx0.h"
#include "common.h"
#include "mpp.h"
diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/mv78xx0.h
index 723748d8ba7d..2db1265ec121 100644
--- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
+++ b/arch/arm/mach-mv78xx0/mv78xx0.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
- *
* Generic definitions for Marvell MV78xx0 SoC flavors:
* MV781x0 and MV782x0.
*
@@ -12,6 +10,8 @@
#ifndef __ASM_ARCH_MV78XX0_H
#define __ASM_ARCH_MV78XX0_H
+#include "irqs.h"
+
/*
* Marvell MV78xx0 address maps.
*
diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
index 097ea4cb1136..13a7d72ee0c4 100644
--- a/arch/arm/mach-mv78xx0/pcie.c
+++ b/arch/arm/mach-mv78xx0/pcie.c
@@ -15,7 +15,7 @@
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <plat/pcie.h>
-#include <mach/mv78xx0.h>
+#include "mv78xx0.h"
#include "common.h"
#define MV78XX0_MBUS_PCIE_MEM_TARGET(port, lane) ((port) ? 8 : 4)
diff --git a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
index d2d06f3957f3..308ab71ec822 100644
--- a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
+++ b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
@@ -14,9 +14,9 @@
#include <linux/ata_platform.h>
#include <linux/mv643xx_eth.h>
#include <linux/ethtool.h>
-#include <mach/mv78xx0.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include "mv78xx0.h"
#include "common.h"
static struct mv643xx_eth_platform_data rd78x00_masa_ge00_data = {
@@ -79,6 +79,7 @@ subsys_initcall(rd78x00_pci_init);
MACHINE_START(RD78X00_MASA, "Marvell RD-78x00-MASA Development Board")
/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = MV78XX0_NR_IRQS,
.init_machine = rd78x00_masa_init,
.map_io = mv78xx0_map_io,
.init_early = mv78xx0_init_early,
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index e20fc4178b15..64e3d2ce9a07 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_MVEBU
- bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V5)
+ bool "Marvell Engineering Business Unit (MVEBU) SoCs"
+ depends on ARCH_MULTI_V7 || ARCH_MULTI_V5
select ARCH_SUPPORTS_BIG_ENDIAN
select CLKSRC_MMIO
select GENERIC_IRQ_CHIP
@@ -25,7 +26,8 @@ config MACH_MVEBU_V7
select MACH_MVEBU_ANY
config MACH_ARMADA_370
- bool "Marvell Armada 370 boards" if ARCH_MULTI_V7
+ bool "Marvell Armada 370 boards"
+ depends on ARCH_MULTI_V7
select ARMADA_370_CLK
select CPU_PJ4B
select MACH_MVEBU_V7
@@ -35,7 +37,8 @@ config MACH_ARMADA_370
on the Marvell Armada 370 SoC with device tree.
config MACH_ARMADA_375
- bool "Marvell Armada 375 boards" if ARCH_MULTI_V7
+ bool "Marvell Armada 375 boards"
+ depends on ARCH_MULTI_V7
select ARM_ERRATA_720789
select ARM_ERRATA_753970
select ARM_GIC
@@ -50,7 +53,8 @@ config MACH_ARMADA_375
on the Marvell Armada 375 SoC with device tree.
config MACH_ARMADA_38X
- bool "Marvell Armada 380/385 boards" if ARCH_MULTI_V7
+ bool "Marvell Armada 380/385 boards"
+ depends on ARCH_MULTI_V7
select ARM_ERRATA_720789
select ARM_ERRATA_753970
select ARM_GIC
@@ -65,7 +69,8 @@ config MACH_ARMADA_38X
on the Marvell Armada 380/385 SoC with device tree.
config MACH_ARMADA_39X
- bool "Marvell Armada 39x boards" if ARCH_MULTI_V7
+ bool "Marvell Armada 39x boards"
+ depends on ARCH_MULTI_V7
select ARM_GIC
select ARMADA_39X_CLK
select CACHE_L2X0
@@ -79,7 +84,8 @@ config MACH_ARMADA_39X
on the Marvell Armada 39x SoC with device tree.
config MACH_ARMADA_XP
- bool "Marvell Armada XP boards" if ARCH_MULTI_V7
+ bool "Marvell Armada XP boards"
+ depends on ARCH_MULTI_V7
select ARMADA_XP_CLK
select CPU_PJ4B
select MACH_MVEBU_V7
@@ -89,7 +95,8 @@ config MACH_ARMADA_XP
on the Marvell Armada XP SoC with device tree.
config MACH_DOVE
- bool "Marvell Dove boards" if ARCH_MULTI_V7
+ bool "Marvell Dove boards"
+ depends on ARCH_MULTI_V7
select CACHE_L2X0
select CPU_PJ4
select DOVE_CLK
@@ -103,7 +110,8 @@ config MACH_DOVE
Marvell Dove using flattened device tree.
config MACH_KIRKWOOD
- bool "Marvell Kirkwood boards" if ARCH_MULTI_V5
+ bool "Marvell Kirkwood boards"
+ depends on ARCH_MULTI_V5
select ARCH_REQUIRE_GPIOLIB
select CPU_FEROCEON
select KIRKWOOD_CLK
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
index c55bbf81de0e..09413b678409 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -17,7 +17,7 @@
#ifdef CONFIG_SMP
void armada_xp_secondary_startup(void);
-extern struct smp_operations armada_xp_smp_ops;
+extern const struct smp_operations armada_xp_smp_ops;
#endif
#endif /* __MACH_ARMADA_370_XP_H */
diff --git a/arch/arm/mach-mvebu/include/mach/gpio.h b/arch/arm/mach-mvebu/include/mach/gpio.h
deleted file mode 100644
index 40a8c178f10d..000000000000
--- a/arch/arm/mach-mvebu/include/mach/gpio.h
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c
index 3d5000481c11..d715dec1c197 100644
--- a/arch/arm/mach-mvebu/platsmp-a9.c
+++ b/arch/arm/mach-mvebu/platsmp-a9.c
@@ -93,11 +93,11 @@ static int armada_38x_cpu_kill(unsigned int cpu)
}
#endif
-static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
+static const struct smp_operations mvebu_cortex_a9_smp_ops __initconst = {
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
};
-static struct smp_operations armada_38x_smp_ops __initdata = {
+static const struct smp_operations armada_38x_smp_ops __initconst = {
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
.smp_secondary_init = armada_38x_secondary_init,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index 58cc8c1575eb..f9597b701028 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -170,7 +170,7 @@ static int armada_xp_cpu_kill(unsigned int cpu)
}
#endif
-struct smp_operations armada_xp_smp_ops __initdata = {
+const struct smp_operations armada_xp_smp_ops __initconst = {
.smp_init_cpus = armada_xp_smp_init_cpus,
.smp_prepare_cpus = armada_xp_smp_prepare_cpus,
.smp_boot_secondary = armada_xp_boot_secondary,
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index a95499ea8706..6613a6ff5dbc 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -11,7 +11,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -41,7 +41,7 @@
#include <mach/hardware.h>
#include <mach/ams-delta-fiq.h>
-#include <mach/camera.h>
+#include "camera.h"
#include <mach/usb.h>
#include "iomap.h"
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 0fb51d22c8b5..fad95b74bb65 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -29,7 +29,7 @@
#include <mach/tc.h>
#include <mach/mux.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <linux/platform_data/keypad-omap.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 8340d684d8b6..cd146ed0538d 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -42,7 +42,7 @@
#include <linux/omap-dma.h>
#include <mach/tc.h>
#include <linux/platform_data/keypad-omap.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/hardware.h>
#include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 086ff34e072b..f7c8c63dd532 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -44,7 +44,7 @@
#include <mach/tc.h>
#include <linux/platform_data/keypad-omap.h>
#include <linux/omap-dma.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/hardware.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index ed4e045c2ad8..ae90bd02b3bf 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -32,7 +32,7 @@
#include <asm/mach/map.h>
#include <mach/mux.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/tc.h>
#include <linux/platform_data/keypad-omap.h>
diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c
index 4d0835327d20..7684f9203474 100644
--- a/arch/arm/mach-omap1/board-nand.c
+++ b/arch/arm/mach-omap1/board-nand.c
@@ -22,7 +22,7 @@
void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long mask;
if (cmd == NAND_CMD_NONE)
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 0efd165b8227..209aecb0df68 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -46,7 +46,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/mux.h>
#include <mach/tc.h>
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 1142ae431fe0..e5288cda1a6a 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -34,7 +34,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/mux.h>
#include <mach/tc.h>
#include <linux/omap-dma.h>
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index 54a547a96950..d672495f7441 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -34,7 +34,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/mux.h>
#include <linux/omap-dma.h>
#include <mach/tc.h>
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index 87ec04ae40dd..aaf741b0aff6 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -36,7 +36,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/mux.h>
#include <linux/omap-dma.h>
#include <mach/tc.h>
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 3d76f05407f0..150b57ba42bf 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -30,7 +30,7 @@
#include <mach/tc.h>
#include <mach/mux.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/hardware.h>
diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c
index 4fcf19c78a08..a9373570bbb1 100644
--- a/arch/arm/mach-omap1/board-sx1-mmc.c
+++ b/arch/arm/mach-omap1/board-sx1-mmc.c
@@ -16,7 +16,7 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
-#include <mach/board-sx1.h>
+#include "board-sx1.h"
#include "mmc.h"
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 939991ea33d5..6c482254b37c 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -34,11 +34,11 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/mux.h>
#include <linux/omap-dma.h>
#include <mach/tc.h>
-#include <mach/board-sx1.h>
+#include "board-sx1.h"
#include <mach/hardware.h>
#include <mach/usb.h>
diff --git a/arch/arm/mach-omap1/include/mach/board-sx1.h b/arch/arm/mach-omap1/board-sx1.h
index 355adbdaae33..355adbdaae33 100644
--- a/arch/arm/mach-omap1/include/mach/board-sx1.h
+++ b/arch/arm/mach-omap1/board-sx1.h
diff --git a/arch/arm/mach-omap1/include/mach/camera.h b/arch/arm/mach-omap1/camera.h
index caa6c0d6f0ac..caa6c0d6f0ac 100644
--- a/arch/arm/mach-omap1/include/mach/camera.h
+++ b/arch/arm/mach-omap1/camera.h
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 325e6030095e..8c8be861fff2 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -25,7 +25,7 @@
#include <mach/mux.h>
#include <mach/omap7xx.h>
-#include <mach/camera.h>
+#include "camera.h"
#include <mach/hardware.h>
#include "common.h"
@@ -33,24 +33,6 @@
#include "mmc.h"
#include "sram.h"
-#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
-
-static struct platform_device omap_pcm = {
- .name = "omap-pcm-audio",
- .id = -1,
-};
-
-static void omap_init_audio(void)
-{
- platform_device_register(&omap_pcm);
-}
-
-#else
-static inline void omap_init_audio(void) {}
-#endif
-
-/*-------------------------------------------------------------------------*/
-
#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
#define OMAP_RTC_BASE 0xfffb4800
@@ -425,7 +407,6 @@ static int __init omap1_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
- omap_init_audio();
omap_init_mbox();
omap_init_rtc();
omap_init_spi100k();
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c
index b3fb531af94e..99cda402e1e2 100644
--- a/arch/arm/mach-omap1/flash.c
+++ b/arch/arm/mach-omap1/flash.c
@@ -11,7 +11,7 @@
#include <linux/mtd/map.h>
#include <mach/tc.h>
-#include <mach/flash.h>
+#include "flash.h"
#include <mach/hardware.h>
diff --git a/arch/arm/mach-omap1/include/mach/flash.h b/arch/arm/mach-omap1/flash.h
index 0d88499b79e9..0d88499b79e9 100644
--- a/arch/arm/mach-omap1/include/mach/flash.h
+++ b/arch/arm/mach-omap1/flash.h
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index ceefcee6bb85..0ba6a0e6fa19 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -223,8 +223,6 @@ obj-$(CONFIG_SOC_DRA7XX) += omap_hwmod_7xx_data.o
# EMU peripherals
obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
-obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
-
# OMAP2420 MSDI controller integration support ("MMC")
obj-$(CONFIG_SOC_OMAP2420) += msdi.o
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 0a0567f8e8a0..da174c0d603b 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -1257,7 +1257,7 @@ static struct platform_device omap3_rom_rng_device = {
static void __init rx51_init_omap3_rom_rng(void)
{
if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
- pr_info("RX-51: Registring OMAP3 HWRNG device\n");
+ pr_info("RX-51: Registering OMAP3 HWRNG device\n");
platform_device_register(&omap3_rom_rng_device);
}
}
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index acb60ed17273..d058125876d8 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -225,5 +225,9 @@ void __init ti_clk_init_features(void)
if (omap_rev() == OMAP3430_REV_ES1_0)
features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
+ /* Errata I810 for omap5 / dra7 */
+ if (soc_is_omap54xx() || soc_is_dra7xx())
+ features.flags |= TI_CLK_ERRATA_I810;
+
ti_clk_setup_features(&features);
}
diff --git a/arch/arm/mach-omap2/clockdomains81xx_data.c b/arch/arm/mach-omap2/clockdomains81xx_data.c
index 53442c86a820..3b5fb05ae701 100644
--- a/arch/arm/mach-omap2/clockdomains81xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains81xx_data.c
@@ -83,6 +83,14 @@ static struct clockdomain mmu_cfg_81xx_clkdm = {
.flags = CLKDM_CAN_SWSUP,
};
+static struct clockdomain default_l3_slow_81xx_clkdm = {
+ .name = "default_l3_slow_clkdm",
+ .pwrdm = { .name = "default_pwrdm" },
+ .cm_inst = TI81XX_CM_DEFAULT_MOD,
+ .clkdm_offs = TI816X_CM_DEFAULT_L3_SLOW_CLKDM,
+ .flags = CLKDM_CAN_SWSUP,
+};
+
/* 816x only */
static struct clockdomain alwon_mpu_816x_clkdm = {
@@ -96,7 +104,7 @@ static struct clockdomain alwon_mpu_816x_clkdm = {
static struct clockdomain active_gem_816x_clkdm = {
.name = "active_gem_clkdm",
.pwrdm = { .name = "active_pwrdm" },
- .cm_inst = TI816X_CM_ACTIVE_MOD,
+ .cm_inst = TI81XX_CM_ACTIVE_MOD,
.clkdm_offs = TI816X_CM_ACTIVE_GEM_CLKDM,
.flags = CLKDM_CAN_SWSUP,
};
@@ -128,7 +136,7 @@ static struct clockdomain ivahd2_816x_clkdm = {
static struct clockdomain sgx_816x_clkdm = {
.name = "sgx_clkdm",
.pwrdm = { .name = "sgx_pwrdm" },
- .cm_inst = TI816X_CM_SGX_MOD,
+ .cm_inst = TI81XX_CM_SGX_MOD,
.clkdm_offs = TI816X_CM_SGX_CLKDM,
.flags = CLKDM_CAN_SWSUP,
};
@@ -136,7 +144,7 @@ static struct clockdomain sgx_816x_clkdm = {
static struct clockdomain default_l3_med_816x_clkdm = {
.name = "default_l3_med_clkdm",
.pwrdm = { .name = "default_pwrdm" },
- .cm_inst = TI816X_CM_DEFAULT_MOD,
+ .cm_inst = TI81XX_CM_DEFAULT_MOD,
.clkdm_offs = TI816X_CM_DEFAULT_L3_MED_CLKDM,
.flags = CLKDM_CAN_SWSUP,
};
@@ -144,7 +152,7 @@ static struct clockdomain default_l3_med_816x_clkdm = {
static struct clockdomain default_ducati_816x_clkdm = {
.name = "default_ducati_clkdm",
.pwrdm = { .name = "default_pwrdm" },
- .cm_inst = TI816X_CM_DEFAULT_MOD,
+ .cm_inst = TI81XX_CM_DEFAULT_MOD,
.clkdm_offs = TI816X_CM_DEFAULT_DUCATI_CLKDM,
.flags = CLKDM_CAN_SWSUP,
};
@@ -152,19 +160,11 @@ static struct clockdomain default_ducati_816x_clkdm = {
static struct clockdomain default_pci_816x_clkdm = {
.name = "default_pci_clkdm",
.pwrdm = { .name = "default_pwrdm" },
- .cm_inst = TI816X_CM_DEFAULT_MOD,
+ .cm_inst = TI81XX_CM_DEFAULT_MOD,
.clkdm_offs = TI816X_CM_DEFAULT_PCI_CLKDM,
.flags = CLKDM_CAN_SWSUP,
};
-static struct clockdomain default_l3_slow_816x_clkdm = {
- .name = "default_l3_slow_clkdm",
- .pwrdm = { .name = "default_pwrdm" },
- .cm_inst = TI816X_CM_DEFAULT_MOD,
- .clkdm_offs = TI816X_CM_DEFAULT_L3_SLOW_CLKDM,
- .flags = CLKDM_CAN_SWSUP,
-};
-
static struct clockdomain *clockdomains_ti814x[] __initdata = {
&alwon_l3_slow_81xx_clkdm,
&alwon_l3_med_81xx_clkdm,
@@ -172,6 +172,7 @@ static struct clockdomain *clockdomains_ti814x[] __initdata = {
&alwon_ethernet_81xx_clkdm,
&mmu_81xx_clkdm,
&mmu_cfg_81xx_clkdm,
+ &default_l3_slow_81xx_clkdm,
NULL,
};
@@ -198,7 +199,7 @@ static struct clockdomain *clockdomains_ti816x[] __initdata = {
&default_l3_med_816x_clkdm,
&default_ducati_816x_clkdm,
&default_pci_816x_clkdm,
- &default_l3_slow_816x_clkdm,
+ &default_l3_slow_81xx_clkdm,
NULL,
};
diff --git a/arch/arm/mach-omap2/cm81xx.h b/arch/arm/mach-omap2/cm81xx.h
index 45cb407da222..3a0ccf07c76f 100644
--- a/arch/arm/mach-omap2/cm81xx.h
+++ b/arch/arm/mach-omap2/cm81xx.h
@@ -18,15 +18,15 @@
#define __ARCH_ARM_MACH_OMAP2_CM_TI81XX_H
/* TI81XX common CM module offsets */
+#define TI81XX_CM_ACTIVE_MOD 0x0400 /* 256B */
+#define TI81XX_CM_DEFAULT_MOD 0x0500 /* 256B */
#define TI81XX_CM_ALWON_MOD 0x1400 /* 1KB */
+#define TI81XX_CM_SGX_MOD 0x0900 /* 256B */
/* TI816X CM module offsets */
-#define TI816X_CM_ACTIVE_MOD 0x0400 /* 256B */
-#define TI816X_CM_DEFAULT_MOD 0x0500 /* 256B */
#define TI816X_CM_IVAHD0_MOD 0x0600 /* 256B */
#define TI816X_CM_IVAHD1_MOD 0x0700 /* 256B */
#define TI816X_CM_IVAHD2_MOD 0x0800 /* 256B */
-#define TI816X_CM_SGX_MOD 0x0900 /* 256B */
/* ALWON */
#define TI81XX_CM_ALWON_L3_SLOW_CLKDM 0x0000
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 0cba9575d2ca..f7666b9f3b21 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -270,7 +270,7 @@ extern u32 omap_read_auxcoreboot0(void);
extern void omap4_cpu_die(unsigned int cpu);
-extern struct smp_operations omap4_smp_ops;
+extern const struct smp_operations omap4_smp_ops;
extern void omap5_secondary_startup(void);
extern void omap5_secondary_hyp_startup(void);
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 9374da313e8e..9cda974a3009 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -94,22 +94,6 @@ static inline void omap_init_mbox(void) { }
static inline void omap_init_sti(void) {}
-#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
-
-static struct platform_device omap_pcm = {
- .name = "omap-pcm-audio",
- .id = -1,
-};
-
-static void omap_init_audio(void)
-{
- platform_device_register(&omap_pcm);
-}
-
-#else
-static inline void omap_init_audio(void) {}
-#endif
-
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -239,13 +223,12 @@ static int __init omap2_init_devices(void)
if (!of_have_populated_dt())
pinctrl_provide_dummies();
- /*
- * please keep these calls, and their implementations above,
- * in alphabetical order so they're easier to sort through.
- */
- omap_init_audio();
/* If dtb is there, the devices will be created dynamically */
if (!of_have_populated_dt()) {
+ /*
+ * please keep these calls, and their implementations above,
+ * in alphabetical order so they're easier to sort through.
+ */
omap_init_mbox();
omap_init_mcspi();
omap_init_sham();
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 8a2ae82cb227..d85c24918c17 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -488,6 +488,7 @@ void __init omap3xxx_check_revision(void)
}
break;
case 0xb8f2:
+ case 0xb968:
switch (rev) {
case 0:
/* FALLTHROUGH */
@@ -511,7 +512,8 @@ void __init omap3xxx_check_revision(void)
/* Unknown default to latest silicon rev as default */
omap_revision = OMAP3630_REV_ES1_2;
cpu_rev = "1.2";
- pr_warn("Warning: unknown chip type; assuming OMAP3630ES1.2\n");
+ pr_warn("Warning: unknown chip type: hawkeye %04x, assuming OMAP3630ES1.2\n",
+ hawkeye);
}
sprintf(soc_rev, "ES%s", cpu_rev);
}
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 3eaeaca5da05..3c87e40650cf 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -612,8 +612,7 @@ void __init ti814x_init_early(void)
ti814x_clockdomains_init();
dm814x_hwmod_init();
omap_hwmod_init_postsetup();
- if (of_have_populated_dt())
- omap_clk_soc_init = dm814x_dt_clk_init;
+ omap_clk_soc_init = dm814x_dt_clk_init;
}
void __init ti816x_init_early(void)
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
deleted file mode 100644
index 8867eb4025bf..000000000000
--- a/arch/arm/mach-omap2/omap-iommu.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * omap iommu: omap device registration
- *
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.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/of.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-
-#include <linux/platform_data/iommu-omap.h>
-#include "soc.h"
-#include "omap_hwmod.h"
-#include "omap_device.h"
-
-static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused)
-{
- struct platform_device *pdev;
- struct iommu_platform_data *pdata;
- struct omap_mmu_dev_attr *a = (struct omap_mmu_dev_attr *)oh->dev_attr;
- static int i;
-
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- pdata->name = oh->name;
- pdata->nr_tlb_entries = a->nr_tlb_entries;
-
- if (oh->rst_lines_cnt == 1) {
- pdata->reset_name = oh->rst_lines->name;
- pdata->assert_reset = omap_device_assert_hardreset;
- pdata->deassert_reset = omap_device_deassert_hardreset;
- }
-
- pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata));
-
- kfree(pdata);
-
- if (IS_ERR(pdev)) {
- pr_err("%s: device build err: %ld\n", __func__, PTR_ERR(pdev));
- return PTR_ERR(pdev);
- }
-
- i++;
-
- return 0;
-}
-
-static int __init omap_iommu_init(void)
-{
- /* If dtb is there, the devices will be created dynamically */
- if (of_have_populated_dt())
- return -ENODEV;
-
- return omap_hwmod_for_each_by_class("mmu", omap_iommu_dev_init, NULL);
-}
-omap_subsys_initcall(omap_iommu_init);
-/* must be ready before omap3isp is probed */
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 79e1f876d1c9..c625cc10d9f9 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -241,7 +241,7 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
}
-struct smp_operations omap4_smp_ops __initdata = {
+const struct smp_operations omap4_smp_ops __initconst = {
.smp_init_cpus = omap4_smp_init_cpus,
.smp_prepare_cpus = omap4_smp_prepare_cpus,
.smp_secondary_init = omap4_secondary_init,
diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c
index d937b2e4040b..497269db882b 100644
--- a/arch/arm/mach-omap2/omap2-restart.c
+++ b/arch/arm/mach-omap2/omap2-restart.c
@@ -62,4 +62,4 @@ static int __init omap2xxx_common_look_up_clks_for_reset(void)
return 0;
}
-omap_core_initcall(omap2xxx_common_look_up_clks_for_reset);
+omap_postcore_initcall(omap2xxx_common_look_up_clks_for_reset);
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index 220822bcfe3f..0437537751bc 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -870,7 +870,7 @@ static int __init omap_device_init(void)
bus_register_notifier(&platform_bus_type, &platform_nb);
return 0;
}
-omap_core_initcall(omap_device_init);
+omap_postcore_initcall(omap_device_init);
/**
* omap_device_late_idle - idle devices without drivers
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 48495ad82aba..e9f65fec55c0 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -3313,7 +3313,7 @@ static int __init omap_hwmod_setup_all(void)
return 0;
}
-omap_core_initcall(omap_hwmod_setup_all);
+omap_postcore_initcall(omap_hwmod_setup_all);
/**
* omap_hwmod_enable - enable an omap_hwmod
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index aff78d5198d2..0a985325cd64 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -25,7 +25,6 @@
#include "l4_3xxx.h"
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/iommu-omap.h>
#include <plat/dmtimer.h>
#include "soc.h"
@@ -2957,80 +2956,40 @@ static struct omap_hwmod_class omap3xxx_mmu_hwmod_class = {
};
/* mmu isp */
-
-static struct omap_mmu_dev_attr mmu_isp_dev_attr = {
- .nr_tlb_entries = 8,
-};
-
static struct omap_hwmod omap3xxx_mmu_isp_hwmod;
-static struct omap_hwmod_irq_info omap3xxx_mmu_isp_irqs[] = {
- { .irq = 24 + OMAP_INTC_START, },
- { .irq = -1 }
-};
-
-static struct omap_hwmod_addr_space omap3xxx_mmu_isp_addrs[] = {
- {
- .pa_start = 0x480bd400,
- .pa_end = 0x480bd47f,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
/* l4_core -> mmu isp */
static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmu_isp = {
.master = &omap3xxx_l4_core_hwmod,
.slave = &omap3xxx_mmu_isp_hwmod,
- .addr = omap3xxx_mmu_isp_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
static struct omap_hwmod omap3xxx_mmu_isp_hwmod = {
.name = "mmu_isp",
.class = &omap3xxx_mmu_hwmod_class,
- .mpu_irqs = omap3xxx_mmu_isp_irqs,
.main_clk = "cam_ick",
- .dev_attr = &mmu_isp_dev_attr,
.flags = HWMOD_NO_IDLEST,
};
/* mmu iva */
-static struct omap_mmu_dev_attr mmu_iva_dev_attr = {
- .nr_tlb_entries = 32,
-};
-
static struct omap_hwmod omap3xxx_mmu_iva_hwmod;
-static struct omap_hwmod_irq_info omap3xxx_mmu_iva_irqs[] = {
- { .irq = 28 + OMAP_INTC_START, },
- { .irq = -1 }
-};
static struct omap_hwmod_rst_info omap3xxx_mmu_iva_resets[] = {
{ .name = "mmu", .rst_shift = 1, .st_shift = 9 },
};
-static struct omap_hwmod_addr_space omap3xxx_mmu_iva_addrs[] = {
- {
- .pa_start = 0x5d000000,
- .pa_end = 0x5d00007f,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
/* l3_main -> iva mmu */
static struct omap_hwmod_ocp_if omap3xxx_l3_main__mmu_iva = {
.master = &omap3xxx_l3_main_hwmod,
.slave = &omap3xxx_mmu_iva_hwmod,
- .addr = omap3xxx_mmu_iva_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
static struct omap_hwmod omap3xxx_mmu_iva_hwmod = {
.name = "mmu_iva",
.class = &omap3xxx_mmu_hwmod_class,
- .mpu_irqs = omap3xxx_mmu_iva_irqs,
.clkdm_name = "iva2_clkdm",
.rst_lines = omap3xxx_mmu_iva_resets,
.rst_lines_cnt = ARRAY_SIZE(omap3xxx_mmu_iva_resets),
@@ -3043,7 +3002,6 @@ static struct omap_hwmod omap3xxx_mmu_iva_hwmod = {
.idlest_idle_bit = OMAP3430_ST_IVA2_SHIFT,
},
},
- .dev_attr = &mmu_iva_dev_attr,
.flags = HWMOD_NO_IDLEST,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index a5e444b1e57a..dad871a4cd96 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -30,7 +30,6 @@
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <linux/platform_data/iommu-omap.h>
#include <plat/dmtimer.h>
#include "omap_hwmod.h"
@@ -2088,30 +2087,16 @@ static struct omap_hwmod_class omap44xx_mmu_hwmod_class = {
/* mmu ipu */
-static struct omap_mmu_dev_attr mmu_ipu_dev_attr = {
- .nr_tlb_entries = 32,
-};
-
static struct omap_hwmod omap44xx_mmu_ipu_hwmod;
static struct omap_hwmod_rst_info omap44xx_mmu_ipu_resets[] = {
{ .name = "mmu_cache", .rst_shift = 2 },
};
-static struct omap_hwmod_addr_space omap44xx_mmu_ipu_addrs[] = {
- {
- .pa_start = 0x55082000,
- .pa_end = 0x550820ff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
/* l3_main_2 -> mmu_ipu */
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__mmu_ipu = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_mmu_ipu_hwmod,
.clk = "l3_div_ck",
- .addr = omap44xx_mmu_ipu_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -2130,35 +2115,20 @@ static struct omap_hwmod omap44xx_mmu_ipu_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .dev_attr = &mmu_ipu_dev_attr,
};
/* mmu dsp */
-static struct omap_mmu_dev_attr mmu_dsp_dev_attr = {
- .nr_tlb_entries = 32,
-};
-
static struct omap_hwmod omap44xx_mmu_dsp_hwmod;
static struct omap_hwmod_rst_info omap44xx_mmu_dsp_resets[] = {
{ .name = "mmu_cache", .rst_shift = 1 },
};
-static struct omap_hwmod_addr_space omap44xx_mmu_dsp_addrs[] = {
- {
- .pa_start = 0x4a066000,
- .pa_end = 0x4a0660ff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
/* l4_cfg -> dsp */
static struct omap_hwmod_ocp_if omap44xx_l4_cfg__mmu_dsp = {
.master = &omap44xx_l4_cfg_hwmod,
.slave = &omap44xx_mmu_dsp_hwmod,
.clk = "l4_div_ck",
- .addr = omap44xx_mmu_dsp_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -2177,7 +2147,6 @@ static struct omap_hwmod omap44xx_mmu_dsp_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .dev_attr = &mmu_dsp_dev_attr,
};
/*
@@ -3915,21 +3884,11 @@ static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_venc = {
.user = OCP_USER_MPU,
};
-static struct omap_hwmod_addr_space omap44xx_elm_addrs[] = {
- {
- .pa_start = 0x48078000,
- .pa_end = 0x48078fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
/* l4_per -> elm */
static struct omap_hwmod_ocp_if omap44xx_l4_per__elm = {
.master = &omap44xx_l4_per_hwmod,
.slave = &omap44xx_elm_hwmod,
.clk = "l4_div_ck",
- .addr = omap44xx_elm_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index ee4e04434a94..848356e38b74 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -2103,7 +2103,7 @@ static struct omap_hwmod dra7xx_uart4_hwmod = {
.class = &dra7xx_uart_hwmod_class,
.clkdm_name = "l4per_clkdm",
.main_clk = "uart4_gfclk_mux",
- .flags = HWMOD_SWSUP_SIDLE_ACT,
+ .flags = HWMOD_SWSUP_SIDLE_ACT | DEBUG_OMAP4UART4_FLAGS,
.prcm = {
.omap4 = {
.clkctrl_offs = DRA7XX_CM_L4PER_UART4_CLKCTRL_OFFSET,
diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
index 6256052893ec..e493ae372910 100644
--- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
@@ -104,8 +104,8 @@
* The default .clkctrl_offs field is offset from CM_DEFAULT, that's
* TRM 18.7.6 CM_DEFAULT device register values minus 0x500
*/
-#define DM816X_CM_DEFAULT_OFFSET 0x500
-#define DM816X_CM_DEFAULT_USB_CLKCTRL (0x558 - DM816X_CM_DEFAULT_OFFSET)
+#define DM81XX_CM_DEFAULT_OFFSET 0x500
+#define DM81XX_CM_DEFAULT_USB_CLKCTRL (0x558 - DM81XX_CM_DEFAULT_OFFSET)
/* L3 Interconnect entries clocked at 125, 250 and 500MHz */
static struct omap_hwmod dm81xx_alwon_l3_slow_hwmod = {
@@ -557,22 +557,42 @@ static struct omap_hwmod_class dm81xx_usbotg_class = {
.sysc = &dm81xx_usbhsotg_sysc,
};
-static struct omap_hwmod dm81xx_usbss_hwmod = {
+static struct omap_hwmod dm814x_usbss_hwmod = {
+ .name = "usb_otg_hs",
+ .clkdm_name = "default_l3_slow_clkdm",
+ .main_clk = "pll260dcoclkldo", /* 481c5260.adpll.dcoclkldo */
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DM81XX_CM_DEFAULT_USB_CLKCTRL,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .class = &dm81xx_usbotg_class,
+};
+
+static struct omap_hwmod_ocp_if dm814x_default_l3_slow__usbss = {
+ .master = &dm81xx_default_l3_slow_hwmod,
+ .slave = &dm814x_usbss_hwmod,
+ .clk = "sysclk6_ck",
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_usbss_hwmod = {
.name = "usb_otg_hs",
.clkdm_name = "default_l3_slow_clkdm",
.main_clk = "sysclk6_ck",
.prcm = {
.omap4 = {
- .clkctrl_offs = DM816X_CM_DEFAULT_USB_CLKCTRL,
+ .clkctrl_offs = DM81XX_CM_DEFAULT_USB_CLKCTRL,
.modulemode = MODULEMODE_SWCTRL,
},
},
.class = &dm81xx_usbotg_class,
};
-static struct omap_hwmod_ocp_if dm81xx_default_l3_slow__usbss = {
+static struct omap_hwmod_ocp_if dm816x_default_l3_slow__usbss = {
.master = &dm81xx_default_l3_slow_hwmod,
- .slave = &dm81xx_usbss_hwmod,
+ .slave = &dm816x_usbss_hwmod,
.clk = "sysclk6_ck",
.user = OCP_USER_MPU,
};
@@ -599,7 +619,7 @@ static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
static struct omap_hwmod dm814x_timer1_hwmod = {
.name = "timer1",
.clkdm_name = "alwon_l3s_clkdm",
- .main_clk = "timer_sys_ck",
+ .main_clk = "timer1_fck",
.dev_attr = &capability_alwon_dev_attr,
.class = &dm816x_timer_hwmod_class,
.flags = HWMOD_NO_IDLEST,
@@ -608,7 +628,7 @@ static struct omap_hwmod dm814x_timer1_hwmod = {
static struct omap_hwmod_ocp_if dm814x_l4_ls__timer1 = {
.master = &dm81xx_l4_ls_hwmod,
.slave = &dm814x_timer1_hwmod,
- .clk = "timer_sys_ck",
+ .clk = "timer1_fck",
.user = OCP_USER_MPU,
};
@@ -636,7 +656,7 @@ static struct omap_hwmod_ocp_if dm816x_l4_ls__timer1 = {
static struct omap_hwmod dm814x_timer2_hwmod = {
.name = "timer2",
.clkdm_name = "alwon_l3s_clkdm",
- .main_clk = "timer_sys_ck",
+ .main_clk = "timer2_fck",
.dev_attr = &capability_alwon_dev_attr,
.class = &dm816x_timer_hwmod_class,
.flags = HWMOD_NO_IDLEST,
@@ -645,7 +665,7 @@ static struct omap_hwmod dm814x_timer2_hwmod = {
static struct omap_hwmod_ocp_if dm814x_l4_ls__timer2 = {
.master = &dm81xx_l4_ls_hwmod,
.slave = &dm814x_timer2_hwmod,
- .clk = "timer_sys_ck",
+ .clk = "timer2_fck",
.user = OCP_USER_MPU,
};
@@ -912,7 +932,7 @@ static struct omap_hwmod_ocp_if dm816x_l4_hs__emac1 = {
.user = OCP_USER_MPU,
};
-static struct omap_hwmod_class_sysconfig dm816x_mmc_sysc = {
+static struct omap_hwmod_class_sysconfig dm81xx_mmc_sysc = {
.rev_offs = 0x0,
.sysc_offs = 0x110,
.syss_offs = 0x114,
@@ -923,24 +943,94 @@ static struct omap_hwmod_class_sysconfig dm816x_mmc_sysc = {
.sysc_fields = &omap_hwmod_sysc_type1,
};
-static struct omap_hwmod_class dm816x_mmc_class = {
+static struct omap_hwmod_class dm81xx_mmc_class = {
.name = "mmc",
- .sysc = &dm816x_mmc_sysc,
+ .sysc = &dm81xx_mmc_sysc,
};
-static struct omap_hwmod_opt_clk dm816x_mmc1_opt_clks[] = {
+static struct omap_hwmod_opt_clk dm81xx_mmc_opt_clks[] = {
{ .role = "dbck", .clk = "sysclk18_ck", },
};
-static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
- .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+static struct omap_hsmmc_dev_attr mmc_dev_attr = {
+};
+
+static struct omap_hwmod dm814x_mmc1_hwmod = {
+ .name = "mmc1",
+ .clkdm_name = "alwon_l3s_clkdm",
+ .opt_clks = dm81xx_mmc_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dm81xx_mmc_opt_clks),
+ .main_clk = "sysclk8_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DM814X_CM_ALWON_MMCHS_0_CLKCTRL,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .dev_attr = &mmc_dev_attr,
+ .class = &dm81xx_mmc_class,
+};
+
+static struct omap_hwmod_ocp_if dm814x_l4_ls__mmc1 = {
+ .master = &dm81xx_l4_ls_hwmod,
+ .slave = &dm814x_mmc1_hwmod,
+ .clk = "sysclk6_ck",
+ .user = OCP_USER_MPU,
+ .flags = OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod dm814x_mmc2_hwmod = {
+ .name = "mmc2",
+ .clkdm_name = "alwon_l3s_clkdm",
+ .opt_clks = dm81xx_mmc_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dm81xx_mmc_opt_clks),
+ .main_clk = "sysclk8_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DM814X_CM_ALWON_MMCHS_1_CLKCTRL,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .dev_attr = &mmc_dev_attr,
+ .class = &dm81xx_mmc_class,
+};
+
+static struct omap_hwmod_ocp_if dm814x_l4_ls__mmc2 = {
+ .master = &dm81xx_l4_ls_hwmod,
+ .slave = &dm814x_mmc2_hwmod,
+ .clk = "sysclk6_ck",
+ .user = OCP_USER_MPU,
+ .flags = OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod dm814x_mmc3_hwmod = {
+ .name = "mmc3",
+ .clkdm_name = "alwon_l3_med_clkdm",
+ .opt_clks = dm81xx_mmc_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dm81xx_mmc_opt_clks),
+ .main_clk = "sysclk8_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DM814X_CM_ALWON_MMCHS_2_CLKCTRL,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .dev_attr = &mmc_dev_attr,
+ .class = &dm81xx_mmc_class,
+};
+
+static struct omap_hwmod_ocp_if dm814x_alwon_l3_med__mmc3 = {
+ .master = &dm81xx_alwon_l3_med_hwmod,
+ .slave = &dm814x_mmc3_hwmod,
+ .clk = "sysclk4_ck",
+ .user = OCP_USER_MPU,
};
static struct omap_hwmod dm816x_mmc1_hwmod = {
.name = "mmc1",
.clkdm_name = "alwon_l3s_clkdm",
- .opt_clks = dm816x_mmc1_opt_clks,
- .opt_clks_cnt = ARRAY_SIZE(dm816x_mmc1_opt_clks),
+ .opt_clks = dm81xx_mmc_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dm81xx_mmc_opt_clks),
.main_clk = "sysclk10_ck",
.prcm = {
.omap4 = {
@@ -948,8 +1038,8 @@ static struct omap_hwmod dm816x_mmc1_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .dev_attr = &mmc1_dev_attr,
- .class = &dm816x_mmc_class,
+ .dev_attr = &mmc_dev_attr,
+ .class = &dm81xx_mmc_class,
};
static struct omap_hwmod_ocp_if dm816x_l4_ls__mmc1 = {
@@ -1036,6 +1126,40 @@ static struct omap_hwmod_ocp_if dm81xx_l4_ls__mailbox = {
.user = OCP_USER_MPU,
};
+static struct omap_hwmod_class_sysconfig dm81xx_spinbox_sysc = {
+ .rev_offs = 0x000,
+ .sysc_offs = 0x010,
+ .syss_offs = 0x014,
+ .sysc_flags = SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE,
+ .idlemodes = SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dm81xx_spinbox_hwmod_class = {
+ .name = "spinbox",
+ .sysc = &dm81xx_spinbox_sysc,
+};
+
+static struct omap_hwmod dm81xx_spinbox_hwmod = {
+ .name = "spinbox",
+ .clkdm_name = "alwon_l3s_clkdm",
+ .class = &dm81xx_spinbox_hwmod_class,
+ .main_clk = "sysclk6_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DM81XX_CM_ALWON_SPINBOX_CLKCTRL,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+static struct omap_hwmod_ocp_if dm81xx_l4_ls__spinbox = {
+ .master = &dm81xx_l4_ls_hwmod,
+ .slave = &dm81xx_spinbox_hwmod,
+ .user = OCP_USER_MPU,
+};
+
static struct omap_hwmod_class dm81xx_tpcc_hwmod_class = {
.name = "tpcc",
};
@@ -1230,11 +1354,7 @@ static struct omap_hwmod_ocp_if dm81xx_tptc3__alwon_l3_fast = {
/*
* REVISIT: Test and enable the following once clocks work:
- * dm81xx_l4_ls__gpio1
- * dm81xx_l4_ls__gpio2
* dm81xx_l4_ls__mailbox
- * dm81xx_alwon_l3_slow__gpmc
- * dm81xx_default_l3_slow__usbss
*
* Also note that some devices share a single clkctrl_offs..
* For example, i2c1 and 3 share one, and i2c2 and 4 share one.
@@ -1250,8 +1370,12 @@ static struct omap_hwmod_ocp_if *dm814x_hwmod_ocp_ifs[] __initdata = {
&dm81xx_l4_ls__wd_timer1,
&dm81xx_l4_ls__i2c1,
&dm81xx_l4_ls__i2c2,
+ &dm81xx_l4_ls__gpio1,
+ &dm81xx_l4_ls__gpio2,
&dm81xx_l4_ls__elm,
&dm81xx_l4_ls__mcspi1,
+ &dm814x_l4_ls__mmc1,
+ &dm814x_l4_ls__mmc2,
&dm81xx_alwon_l3_fast__tpcc,
&dm81xx_alwon_l3_fast__tptc0,
&dm81xx_alwon_l3_fast__tptc1,
@@ -1265,6 +1389,9 @@ static struct omap_hwmod_ocp_if *dm814x_hwmod_ocp_ifs[] __initdata = {
&dm814x_l4_ls__timer2,
&dm814x_l4_hs__cpgmac0,
&dm814x_cpgmac0__mdio,
+ &dm81xx_alwon_l3_slow__gpmc,
+ &dm814x_default_l3_slow__usbss,
+ &dm814x_alwon_l3_med__mmc3,
NULL,
};
@@ -1298,6 +1425,7 @@ static struct omap_hwmod_ocp_if *dm816x_hwmod_ocp_ifs[] __initdata = {
&dm816x_l4_ls__timer7,
&dm81xx_l4_ls__mcspi1,
&dm81xx_l4_ls__mailbox,
+ &dm81xx_l4_ls__spinbox,
&dm81xx_l4_hs__emac0,
&dm81xx_emac0__mdio,
&dm816x_l4_hs__emac1,
@@ -1311,7 +1439,7 @@ static struct omap_hwmod_ocp_if *dm816x_hwmod_ocp_ifs[] __initdata = {
&dm81xx_tptc2__alwon_l3_fast,
&dm81xx_tptc3__alwon_l3_fast,
&dm81xx_alwon_l3_slow__gpmc,
- &dm81xx_default_l3_slow__usbss,
+ &dm816x_default_l3_slow__usbss,
NULL,
};
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 58144779dec4..e781e4fae13a 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -150,6 +150,21 @@ static struct platform_device wl18xx_device = {
}
};
+static struct ti_st_plat_data wilink7_pdata = {
+ .nshutdown_gpio = 162,
+ .dev_name = "/dev/ttyO1",
+ .flow_cntrl = 1,
+ .baud_rate = 300000,
+};
+
+static struct platform_device wl128x_device = {
+ .name = "kim",
+ .id = -1,
+ .dev = {
+ .platform_data = &wilink7_pdata,
+ }
+};
+
static struct platform_device btwilink_device = {
.name = "btwilink",
.id = -1,
@@ -265,7 +280,7 @@ static void __init nokia_n900_legacy_init(void)
pr_warn("Thumb binaries may crash randomly without this workaround\n");
}
- pr_info("RX-51: Registring OMAP3 HWRNG device\n");
+ pr_info("RX-51: Registering OMAP3 HWRNG device\n");
platform_device_register(&omap3_rom_rng_device);
}
@@ -276,6 +291,13 @@ static void __init omap3_tao3530_legacy_init(void)
hsmmc2_internal_input_clk();
}
+static void __init omap3_logicpd_torpedo_init(void)
+{
+ omap3_gpio126_127_129();
+ platform_device_register(&wl128x_device);
+ platform_device_register(&btwilink_device);
+}
+
/* omap3pandora legacy devices */
#define PANDORA_WIFI_IRQ_GPIO 21
#define PANDORA_WIFI_NRESET_GPIO 23
@@ -503,7 +525,7 @@ static struct pdata_init pdata_quirks[] __initdata = {
{ "nokia,omap3-n950", hsmmc2_internal_input_clk, },
{ "isee,omap3-igep0020-rev-f", omap3_igep0020_rev_f_legacy_init, },
{ "isee,omap3-igep0030-rev-g", omap3_igep0030_rev_g_legacy_init, },
- { "logicpd,dm3730-torpedo-devkit", omap3_gpio126_127_129, },
+ { "logicpd,dm3730-torpedo-devkit", omap3_logicpd_torpedo_init, },
{ "ti,omap3-evm-37xx", omap3_evm_legacy_init, },
{ "ti,am3517-evm", am3517_evm_legacy_init, },
{ "technexion,omap3-tao3530", omap3_tao3530_legacy_init, },
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 2e00c7f1f471..eb27ae066292 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -384,14 +384,14 @@ static struct powerdomain isp_814x_pwrdm = {
.voltdm = { .name = "core" },
};
-static struct powerdomain active_816x_pwrdm = {
+static struct powerdomain active_81xx_pwrdm = {
.name = "active_pwrdm",
.prcm_offs = TI816X_PRM_ACTIVE_MOD,
.pwrsts = PWRSTS_OFF_ON,
.voltdm = { .name = "core" },
};
-static struct powerdomain default_816x_pwrdm = {
+static struct powerdomain default_81xx_pwrdm = {
.name = "default_pwrdm",
.prcm_offs = TI81XX_PRM_DEFAULT_MOD,
.pwrsts = PWRSTS_OFF_ON,
@@ -486,6 +486,8 @@ static struct powerdomain *powerdomains_am35x[] __initdata = {
static struct powerdomain *powerdomains_ti814x[] __initdata = {
&alwon_81xx_pwrdm,
&device_81xx_pwrdm,
+ &active_81xx_pwrdm,
+ &default_81xx_pwrdm,
&gem_814x_pwrdm,
&ivahd_814x_pwrdm,
&hdvpss_814x_pwrdm,
@@ -497,8 +499,8 @@ static struct powerdomain *powerdomains_ti814x[] __initdata = {
static struct powerdomain *powerdomains_ti816x[] __initdata = {
&alwon_81xx_pwrdm,
&device_81xx_pwrdm,
- &active_816x_pwrdm,
- &default_816x_pwrdm,
+ &active_81xx_pwrdm,
+ &default_81xx_pwrdm,
&ivahd0_816x_pwrdm,
&ivahd1_816x_pwrdm,
&ivahd2_816x_pwrdm,
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 3fc2cbe52113..5b2f5138d938 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -664,6 +664,13 @@ static struct omap_prcm_init_data am3_prm_data __initdata = {
};
#endif
+#ifdef CONFIG_SOC_TI81XX
+static struct omap_prcm_init_data dm814_pllss_data __initdata = {
+ .index = TI_CLKM_PLLSS,
+ .init = am33xx_prm_init,
+};
+#endif
+
#ifdef CONFIG_ARCH_OMAP4
static struct omap_prcm_init_data omap4_prm_data __initdata = {
.index = TI_CLKM_PRM,
@@ -715,6 +722,7 @@ static const struct of_device_id const omap_prcm_dt_match_table[] __initconst =
#endif
#ifdef CONFIG_SOC_TI81XX
{ .compatible = "ti,dm814-prcm", .data = &am3_prm_data },
+ { .compatible = "ti,dm814-pllss", .data = &dm814_pllss_data },
{ .compatible = "ti,dm816-prcm", .data = &am3_prm_data },
#endif
#ifdef CONFIG_ARCH_OMAP2
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 5fb50fe54153..f164c6b32ce2 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -213,7 +213,7 @@ static int __init omap_serial_early_init(void)
return 0;
}
-omap_core_initcall(omap_serial_early_init);
+omap_postcore_initcall(omap_serial_early_init);
/**
* omap_serial_init_port() - initialize single serial port
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index f86692dbcfd5..5b385bb8aff9 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -194,8 +194,8 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id *
/**
* omap_dmtimer_init - initialisation function when device tree is used
*
- * For secure OMAP3 devices, timers with device type "timer-secure" cannot
- * be used by the kernel as they are reserved. Therefore, to prevent the
+ * For secure OMAP3/DRA7xx devices, timers with device type "timer-secure"
+ * cannot be used by the kernel as they are reserved. Therefore, to prevent the
* kernel registering these devices remove them dynamically from the device
* tree on boot.
*/
@@ -203,7 +203,7 @@ static void __init omap_dmtimer_init(void)
{
struct device_node *np;
- if (!cpu_is_omap34xx())
+ if (!cpu_is_omap34xx() && !soc_is_dra7xx())
return;
/* If we are a secure device, remove any secure timer nodes */
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index 66f1c952c048..a9ad95f000a1 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -1,6 +1,18 @@
-if ARCH_ORION5X
+menuconfig ARCH_ORION5X
+ bool "Marvell Orion"
+ depends on MMU && ARCH_MULTI_V5
+ select ARCH_REQUIRE_GPIOLIB
+ select CPU_FEROCEON
+ select GENERIC_CLOCKEVENTS
+ select MVEBU_MBUS
+ select PCI
+ select PLAT_ORION_LEGACY
+ help
+ Support for the following Marvell Orion 5x series SoCs:
+ Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
+ Orion-2 (5281), Orion-1-90 (6183).
-menu "Orion Implementations"
+if ARCH_ORION5X
config ARCH_ORION5X_DT
bool "Marvell Orion5x Flattened Device Tree"
@@ -163,6 +175,4 @@ config MACH_RD88F6183AP_GE
Say 'Y' here if you want your kernel to support the
Marvell Orion-1-90 (88F6183) AP GE RD.
-endmenu
-
endif
diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile
index a1e0fbe6a7a1..4b2502b4ca0d 100644
--- a/arch/arm/mach-orion5x/Makefile
+++ b/arch/arm/mach-orion5x/Makefile
@@ -1,3 +1,5 @@
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-orion/include
+
obj-y += common.o pci.o irq.o mpp.o
obj-$(CONFIG_MACH_DB88F5281) += db88f5281-setup.o
obj-$(CONFIG_MACH_RD88F5182) += rd88f5182-setup.o
diff --git a/arch/arm/mach-orion5x/board-d2net.c b/arch/arm/mach-orion5x/board-d2net.c
index 8a7284124153..a89376a5cd92 100644
--- a/arch/arm/mach-orion5x/board-d2net.c
+++ b/arch/arm/mach-orion5x/board-d2net.c
@@ -20,9 +20,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include <plat/orion-gpio.h>
#include "common.h"
+#include "orion5x.h"
/*****************************************************************************
* LaCie d2 Network Info
diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c
index d0871786dd8a..6f4c2c4ae2a5 100644
--- a/arch/arm/mach-orion5x/board-dt.c
+++ b/arch/arm/mach-orion5x/board-dt.c
@@ -20,10 +20,10 @@
#include <asm/system_misc.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/orion5x.h>
-#include <mach/bridge-regs.h>
#include <plat/irq.h>
#include <plat/time.h>
+#include "orion5x.h"
+#include "bridge-regs.h"
#include "common.h"
static struct of_dev_auxdata orion5x_auxdata_lookup[] __initdata = {
diff --git a/arch/arm/mach-orion5x/board-mss2.c b/arch/arm/mach-orion5x/board-mss2.c
index 66f9c3ba86cc..79202fd626df 100644
--- a/arch/arm/mach-orion5x/board-mss2.c
+++ b/arch/arm/mach-orion5x/board-mss2.c
@@ -17,8 +17,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
-#include <mach/bridge-regs.h>
+#include "orion5x.h"
+#include "bridge-regs.h"
#include "common.h"
/*****************************************************************************
diff --git a/arch/arm/mach-orion5x/board-rd88f5182.c b/arch/arm/mach-orion5x/board-rd88f5182.c
index 270824b0e50f..b7b0f52f4c0a 100644
--- a/arch/arm/mach-orion5x/board-rd88f5182.c
+++ b/arch/arm/mach-orion5x/board-rd88f5182.c
@@ -18,8 +18,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
+#include "orion5x.h"
/*****************************************************************************
* RD-88F5182 Info
diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/bridge-regs.h
index 5766e3fbff69..305598eaaee1 100644
--- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h
+++ b/arch/arm/mach-orion5x/bridge-regs.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-orion5x/include/mach/bridge-regs.h
- *
* Orion CPU Bridge Registers
*
* This file is licensed under the terms of the GNU General Public
@@ -11,7 +9,7 @@
#ifndef __ASM_ARCH_BRIDGE_REGS_H
#define __ASM_ARCH_BRIDGE_REGS_H
-#include <mach/orion5x.h>
+#include "orion5x.h"
#define CPU_CONF (ORION5X_BRIDGE_VIRT_BASE + 0x100)
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 6bbb7b55c6d1..70c3366c8d03 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -27,14 +27,14 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <mach/bridge-regs.h>
-#include <mach/hardware.h>
-#include <mach/orion5x.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include <linux/platform_data/usb-ehci-orion.h>
#include <plat/time.h>
#include <plat/common.h>
+
+#include "bridge-regs.h"
#include "common.h"
+#include "orion5x.h"
/*****************************************************************************
* I/O Address Mapping
@@ -184,9 +184,21 @@ static void __init orion5x_crypto_init(void)
/*****************************************************************************
* Watchdog
****************************************************************************/
+static struct resource orion_wdt_resource[] = {
+ DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+ DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
+
+static struct platform_device orion_wdt_device = {
+ .name = "orion_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(orion_wdt_resource),
+ .resource = orion_wdt_resource,
+};
+
static void __init orion5x_wdt_init(void)
{
- orion_wdt_init();
+ platform_device_register(&orion_wdt_device);
}
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index dc01c4ffc9a8..12f74b46e2ff 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -23,10 +23,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* DB-88F5281 on board devices
@@ -369,6 +369,7 @@ static void __init db88f5281_init(void)
MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
/* Maintainer: Tzachi Perelstein <tzachi@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = db88f5281_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index bc279a853075..cd483bfb5ca8 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -33,8 +33,8 @@
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
#include <asm/system_info.h>
-#include <mach/orion5x.h>
#include <plat/orion-gpio.h>
+#include "orion5x.h"
#include "common.h"
#include "mpp.h"
@@ -666,6 +666,7 @@ static void __init dns323_init(void)
MACHINE_START(DNS323, "D-Link DNS-323")
/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = dns323_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/include/mach/entry-macro.S b/arch/arm/mach-orion5x/include/mach/entry-macro.S
deleted file mode 100644
index 73919a36b577..000000000000
--- a/arch/arm/mach-orion5x/include/mach/entry-macro.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Orion platforms
- *
- * 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 <mach/bridge-regs.h>
-
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =MAIN_IRQ_CAUSE
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \irqstat, [\base, #0] @ main cause
- ldr \tmp, [\base, #(MAIN_IRQ_MASK - MAIN_IRQ_CAUSE)] @ main mask
- mov \irqnr, #0 @ default irqnr
- @ find cause bits that are unmasked
- ands \irqstat, \irqstat, \tmp @ clear Z flag if any
- clzne \irqnr, \irqstat @ calc irqnr
- rsbne \irqnr, \irqnr, #32
- .endm
diff --git a/arch/arm/mach-orion5x/include/mach/uncompress.h b/arch/arm/mach-orion5x/include/mach/uncompress.h
deleted file mode 100644
index abd26b542c3c..000000000000
--- a/arch/arm/mach-orion5x/include/mach/uncompress.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/uncompress.h
- *
- * Tzachi Perelstein <tzachi@marvell.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/serial_reg.h>
-#include <mach/orion5x.h>
-
-#define SERIAL_BASE ((unsigned char *)UART0_PHYS_BASE)
-
-static void putc(const char c)
-{
- unsigned char *base = SERIAL_BASE;
- int i;
-
- for (i = 0; i < 0x1000; i++) {
- if (base[UART_LSR << 2] & UART_LSR_THRE)
- break;
- barrier();
- }
-
- base[UART_TX << 2] = c;
-}
-
-static void flush(void)
-{
- unsigned char *base = SERIAL_BASE;
- unsigned char mask;
- int i;
-
- mask = UART_LSR_TEMT | UART_LSR_THRE;
-
- for (i = 0; i < 0x1000; i++) {
- if ((base[UART_LSR << 2] & mask) == mask)
- break;
- barrier();
- }
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c
index 086ecb87d885..de980ef9cda1 100644
--- a/arch/arm/mach-orion5x/irq.c
+++ b/arch/arm/mach-orion5x/irq.c
@@ -13,10 +13,10 @@
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <mach/bridge-regs.h>
#include <plat/orion-gpio.h>
#include <plat/irq.h>
#include <asm/exception.h>
+#include "bridge-regs.h"
#include "common.h"
static int __initdata gpio0_irqs[4] = {
@@ -26,14 +26,6 @@ static int __initdata gpio0_irqs[4] = {
IRQ_ORION5X_GPIO_24_31,
};
-#ifdef CONFIG_MULTI_IRQ_HANDLER
-/*
- * Compiling with both non-DT and DT support enabled, will
- * break asm irq handler used by non-DT boards. Therefore,
- * we provide a C-style irq handler even for non-DT boards,
- * if MULTI_IRQ_HANDLER is set.
- */
-
asmlinkage void
__exception_irq_entry orion5x_legacy_handle_irq(struct pt_regs *regs)
{
@@ -47,15 +39,12 @@ __exception_irq_entry orion5x_legacy_handle_irq(struct pt_regs *regs)
return;
}
}
-#endif
void __init orion5x_init_irq(void)
{
orion_irq_init(1, MAIN_IRQ_MASK);
-#ifdef CONFIG_MULTI_IRQ_HANDLER
set_handle_irq(orion5x_legacy_handle_irq);
-#endif
/*
* Initialize gpiolib for GPIOs 0-31.
diff --git a/arch/arm/mach-orion5x/include/mach/irqs.h b/arch/arm/mach-orion5x/irqs.h
index 2431d9923427..506c8e0b30c4 100644
--- a/arch/arm/mach-orion5x/include/mach/irqs.h
+++ b/arch/arm/mach-orion5x/irqs.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-orion5x/include/mach/irqs.h
- *
* IRQ definitions for Orion SoC
*
* Maintainer: Tzachi Perelstein <tzachi@marvell.com>
@@ -54,7 +52,7 @@
#define IRQ_ORION5X_GPIO_START 33
#define NR_GPIO_IRQS 32
-#define NR_IRQS (IRQ_ORION5X_GPIO_START + NR_GPIO_IRQS)
+#define ORION5X_NR_IRQS (IRQ_ORION5X_GPIO_START + NR_GPIO_IRQS)
#endif
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index fe6a48a325e8..9dc3f59bed9c 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -23,10 +23,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* KUROBOX-PRO Info
@@ -383,6 +383,7 @@ static void __init kurobox_pro_init(void)
MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
/* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = kurobox_pro_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
@@ -397,6 +398,7 @@ MACHINE_END
MACHINE_START(LINKSTATION_PRO, "Buffalo Linkstation Pro/Live")
/* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = kurobox_pro_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c
index 028ea038d404..dfdaa8a498a4 100644
--- a/arch/arm/mach-orion5x/ls-chl-setup.c
+++ b/arch/arm/mach-orion5x/ls-chl-setup.c
@@ -22,9 +22,9 @@
#include <linux/gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* Linkstation LS-CHL Info
@@ -320,6 +320,7 @@ static void __init lschl_init(void)
MACHINE_START(LINKSTATION_LSCHL, "Buffalo Linkstation LiveV3 (LS-CHL)")
/* Maintainer: Ash Hughes <ashley.hughes@blueyonder.co.uk> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = lschl_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c
index 32b7129b767d..47ba6e0502f5 100644
--- a/arch/arm/mach-orion5x/ls_hgl-setup.c
+++ b/arch/arm/mach-orion5x/ls_hgl-setup.c
@@ -21,9 +21,9 @@
#include <linux/gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* Linkstation LS-HGL Info
@@ -267,6 +267,7 @@ static void __init ls_hgl_init(void)
MACHINE_START(LINKSTATION_LS_HGL, "Buffalo Linkstation LS-HGL")
/* Maintainer: Zhu Qingsen <zhuqs@cn.fujistu.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = ls_hgl_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c
index 5b70026f478c..19ef18594415 100644
--- a/arch/arm/mach-orion5x/mpp.c
+++ b/arch/arm/mach-orion5x/mpp.c
@@ -11,8 +11,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <mach/hardware.h>
#include <plat/mpp.h>
+#include "orion5x.h"
#include "mpp.h"
#include "common.h"
diff --git a/arch/arm/mach-orion5x/mv2120-setup.c b/arch/arm/mach-orion5x/mv2120-setup.c
index e032f01da49e..2bf8ec75e908 100644
--- a/arch/arm/mach-orion5x/mv2120-setup.c
+++ b/arch/arm/mach-orion5x/mv2120-setup.c
@@ -21,9 +21,9 @@
#include <linux/ata_platform.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
#define MV2120_NOR_BOOT_BASE 0xf4000000
#define MV2120_NOR_BOOT_SIZE SZ_512K
@@ -232,6 +232,7 @@ static void __init mv2120_init(void)
MACHINE_START(MV2120, "HP Media Vault mv2120")
/* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = mv2120_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/net2big-setup.c b/arch/arm/mach-orion5x/net2big-setup.c
index ba73dc7ffb9e..bf6be4cfd238 100644
--- a/arch/arm/mach-orion5x/net2big-setup.c
+++ b/arch/arm/mach-orion5x/net2big-setup.c
@@ -24,10 +24,10 @@
#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/orion5x.h>
#include <plat/orion-gpio.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* LaCie 2Big Network Info
@@ -423,6 +423,7 @@ static void __init net2big_init(void)
/* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
MACHINE_START(NET2BIG, "LaCie 2Big Network")
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = net2big_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/orion5x.h
index b78ff3248868..3364df331f01 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/orion5x.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-orion5x/include/mach/orion5x.h
- *
* Generic definitions of Orion SoC flavors:
* Orion-1, Orion-VoIP, Orion-NAS, Orion-2, and Orion-1-90.
*
@@ -14,6 +12,8 @@
#ifndef __ASM_ARCH_ORION5X_H
#define __ASM_ARCH_ORION5X_H
+#include "irqs.h"
+
/*****************************************************************************
* Orion Address Maps
*
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index b02f3947be51..ecb998e7f8dc 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -19,8 +19,8 @@
#include <asm/mach/pci.h>
#include <plat/pcie.h>
#include <plat/addr-map.h>
-#include <mach/orion5x.h>
#include "common.h"
+#include "orion5x.h"
/*****************************************************************************
* Orion has one PCIe controller and one PCI controller.
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 213b3e143c57..c742e7b40b0d 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -20,9 +20,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* RD-88F5181L FXO Info
@@ -169,6 +169,7 @@ subsys_initcall(rd88f5181l_fxo_pci_init);
MACHINE_START(RD88F5181L_FXO, "Marvell Orion-VoIP FXO Reference Design")
/* Maintainer: Nicolas Pitre <nico@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = rd88f5181l_fxo_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 594800e1d691..7e977b794b0c 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -21,9 +21,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* RD-88F5181L GE Info
@@ -181,6 +181,7 @@ subsys_initcall(rd88f5181l_ge_pci_init);
MACHINE_START(RD88F5181L_GE, "Marvell Orion-VoIP GE Reference Design")
/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = rd88f5181l_ge_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index b576ef5f18a1..fe3e67c81fb8 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -23,9 +23,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* RD-88F5182 Info
@@ -281,6 +281,7 @@ static void __init rd88f5182_init(void)
MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design")
/* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = rd88f5182_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 78a1e6ab1b9d..4bf80dd5478c 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -22,8 +22,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
+#include "orion5x.h"
static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
.phy_addr = -1,
@@ -119,6 +119,7 @@ subsys_initcall(rd88f6183ap_ge_pci_init);
MACHINE_START(RD88F6183AP_GE, "Marvell Orion-1-90 AP GE Reference Design")
/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = rd88f6183ap_ge_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c
index 12086745c9fd..deb5e29ac669 100644
--- a/arch/arm/mach-orion5x/terastation_pro2-setup.c
+++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c
@@ -22,9 +22,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
/*****************************************************************************
* Terastation Pro 2/Live Info
@@ -359,6 +359,7 @@ static void __init tsp2_init(void)
MACHINE_START(TERASTATION_PRO2, "Buffalo Terastation Pro II/Live")
/* Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = tsp2_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index c725b7cb9875..7bd671b2854c 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -25,9 +25,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
#include "tsx09-common.h"
#define QNAP_TS209_NOR_BOOT_BASE 0xf4000000
@@ -324,6 +324,7 @@ static void __init qnap_ts209_init(void)
MACHINE_START(TS209, "QNAP TS-109/TS-209")
/* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = qnap_ts209_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/ts409-setup.c b/arch/arm/mach-orion5x/ts409-setup.c
index cf2ab531cabc..a77613b14db5 100644
--- a/arch/arm/mach-orion5x/ts409-setup.c
+++ b/arch/arm/mach-orion5x/ts409-setup.c
@@ -27,9 +27,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
#include "tsx09-common.h"
/*****************************************************************************
@@ -313,6 +313,7 @@ static void __init qnap_ts409_init(void)
MACHINE_START(TS409, "QNAP TS-409")
/* Maintainer: Sylver Bruneau <sylver.bruneau@gmail.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = qnap_ts409_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index 1b704d35cf5b..3a58a5d4a28a 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -23,9 +23,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/orion5x.h>
#include "common.h"
#include "mpp.h"
+#include "orion5x.h"
#include "ts78xx-fpga.h"
/*****************************************************************************
@@ -176,7 +176,7 @@ static void ts78xx_ts_rtc_unload(void)
static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char bits;
@@ -200,7 +200,7 @@ static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
void __iomem *io_base = chip->IO_ADDR_W;
unsigned long off = ((unsigned long)buf & 3);
int sz;
@@ -227,7 +227,7 @@ static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
void __iomem *io_base = chip->IO_ADDR_R;
unsigned long off = ((unsigned long)buf & 3);
int sz;
@@ -615,6 +615,7 @@ static void __init ts78xx_init(void)
MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
/* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = ts78xx_init,
.map_io = ts78xx_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c
index d42e006597c7..89774985d380 100644
--- a/arch/arm/mach-orion5x/tsx09-common.c
+++ b/arch/arm/mach-orion5x/tsx09-common.c
@@ -15,7 +15,7 @@
#include <linux/mv643xx_eth.h>
#include <linux/timex.h>
#include <linux/serial_reg.h>
-#include <mach/orion5x.h>
+#include "orion5x.h"
#include "tsx09-common.h"
#include "common.h"
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 80a56ee245b3..4e1e5c8f6111 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -19,7 +19,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
+#include "orion5x.h"
#include "common.h"
#include "mpp.h"
@@ -174,6 +174,7 @@ subsys_initcall(wnr854t_pci_init);
MACHINE_START(WNR854T, "Netgear WNR854T")
/* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = wnr854t_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index 670e30dc0d1b..61e9027ef224 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -22,7 +22,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
-#include <mach/orion5x.h>
+#include "orion5x.h"
#include "common.h"
#include "mpp.h"
@@ -262,6 +262,7 @@ subsys_initcall(wrt350n_v2_pci_init);
MACHINE_START(WRT350N_V2, "Linksys WRT350N v2")
/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
.atag_offset = 0x100,
+ .nr_irqs = ORION5X_NR_IRQS,
.init_machine = wrt350n_v2_init,
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
diff --git a/arch/arm/mach-picoxcell/Kconfig b/arch/arm/mach-picoxcell/Kconfig
index 62240f69b4ee..aef92ba0eacd 100644
--- a/arch/arm/mach-picoxcell/Kconfig
+++ b/arch/arm/mach-picoxcell/Kconfig
@@ -1,5 +1,6 @@
config ARCH_PICOXCELL
- bool "Picochip PicoXcell" if ARCH_MULTI_V6
+ bool "Picochip PicoXcell"
+ depends on ARCH_MULTI_V6
select ARCH_REQUIRE_GPIOLIB
select ARM_VIC
select DW_APB_TIMER_OF
diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig
index 9ab8932403e5..f998eb1c698e 100644
--- a/arch/arm/mach-prima2/Kconfig
+++ b/arch/arm/mach-prima2/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_SIRF
- bool "CSR SiRF" if ARCH_MULTI_V7
+ bool "CSR SiRF"
+ depends on ARCH_MULTI_V7
select ARCH_HAS_RESET_CONTROLLER
select ARCH_REQUIRE_GPIOLIB
select GENERIC_IRQ_CHIP
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index 3916a6665100..6d77b622d168 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -15,7 +15,7 @@
#include <asm/mach/time.h>
#include <asm/exception.h>
-extern struct smp_operations sirfsoc_smp_ops;
+extern const struct smp_operations sirfsoc_smp_ops;
extern void sirfsoc_secondary_startup(void);
extern void sirfsoc_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c
index e46c91094dde..0875b99add18 100644
--- a/arch/arm/mach-prima2/platsmp.c
+++ b/arch/arm/mach-prima2/platsmp.c
@@ -112,7 +112,7 @@ static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
return pen_release != -1 ? -ENOSYS : 0;
}
-struct smp_operations sirfsoc_smp_ops __initdata = {
+const struct smp_operations sirfsoc_smp_ops __initconst = {
.smp_secondary_init = sirfsoc_secondary_init,
.smp_boot_secondary = sirfsoc_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-pxa/am200epd.c b/arch/arm/mach-pxa/am200epd.c
index 12fb0f4ae359..50e18ed37fa6 100644
--- a/arch/arm/mach-pxa/am200epd.c
+++ b/arch/arm/mach-pxa/am200epd.c
@@ -30,8 +30,8 @@
#include <linux/irq.h>
#include <linux/gpio.h>
-#include <mach/pxa25x.h>
-#include <mach/gumstix.h>
+#include "pxa25x.h"
+#include "gumstix.h"
#include <linux/platform_data/video-pxafb.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c
index 8b90c4f2d430..17d08abeeb17 100644
--- a/arch/arm/mach-pxa/am300epd.c
+++ b/arch/arm/mach-pxa/am300epd.c
@@ -28,8 +28,8 @@
#include <linux/irq.h>
#include <linux/gpio.h>
-#include <mach/gumstix.h>
-#include <mach/mfp-pxa25x.h>
+#include "gumstix.h"
+#include "mfp-pxa25x.h"
#include <mach/irqs.h>
#include <linux/platform_data/video-pxafb.h>
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index a727282bfa99..8a3c409294bf 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -42,13 +42,13 @@
#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/balloon3.h>
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
-#include <mach/pxa27x-udc.h>
+#include "udc.h"
+#include "pxa27x-udc.h"
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
@@ -572,7 +572,7 @@ static inline void balloon3_i2c_init(void) {}
#if defined(CONFIG_MTD_NAND_PLATFORM)||defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
uint8_t balloon3_ctl_set = 0, balloon3_ctl_clr = 0;
if (ctrl & NAND_CTRL_CHANGE) {
diff --git a/arch/arm/mach-pxa/capc7117.c b/arch/arm/mach-pxa/capc7117.c
index bf366b39fa61..1c3cbfca9f40 100644
--- a/arch/arm/mach-pxa/capc7117.c
+++ b/arch/arm/mach-pxa/capc7117.c
@@ -29,8 +29,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa320.h>
-#include <mach/mxm8x10.h>
+#include "pxa320.h"
+#include "mxm8x10.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/cm-x255.c b/arch/arm/mach-pxa/cm-x255.c
index be751470d37b..b592f79a1742 100644
--- a/arch/arm/mach-pxa/cm-x255.c
+++ b/arch/arm/mach-pxa/cm-x255.c
@@ -22,7 +22,7 @@
#include <asm/mach-types.h>
#include <asm/mach/map.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
index 2503db9e3253..fa5f51d633a3 100644
--- a/arch/arm/mach-pxa/cm-x270.c
+++ b/arch/arm/mach-pxa/cm-x270.c
@@ -21,7 +21,7 @@
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/libertas_spi.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/mmc-pxamci.h>
diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c
index a17a91eb8e9a..7202022ee243 100644
--- a/arch/arm/mach-pxa/cm-x2xx.c
+++ b/arch/arm/mach-pxa/cm-x2xx.c
@@ -22,9 +22,18 @@
#include <asm/mach-types.h>
#include <asm/mach/map.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#undef GPIO24_SSP1_SFRM
-#include <mach/pxa27x.h>
+#undef GPIO86_GPIO
+#undef GPIO87_GPIO
+#undef GPIO88_GPIO
+#undef GPIO89_GPIO
+#include "pxa27x.h"
+#undef GPIO24_SSP1_SFRM
+#undef GPIO86_GPIO
+#undef GPIO87_GPIO
+#undef GPIO88_GPIO
+#undef GPIO89_GPIO
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
#include <mach/smemc.h>
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index a7dae60810e8..5f5ac7c8faf0 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -47,8 +47,8 @@
#include <asm/setup.h>
#include <asm/system_info.h>
-#include <mach/pxa300.h>
-#include <mach/pxa27x-udc.h>
+#include "pxa300.h"
+#include "pxa27x-udc.h"
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c
index 638b0bb88426..dc44fbbe5073 100644
--- a/arch/arm/mach-pxa/colibri-evalboard.c
+++ b/arch/arm/mach-pxa/colibri-evalboard.c
@@ -22,11 +22,11 @@
#include <linux/i2c/pxa-i2c.h>
#include <asm/io.h>
-#include <mach/pxa27x.h>
-#include <mach/colibri.h>
+#include "pxa27x.h"
+#include "colibri.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pxa27x-udc.h>
+#include "pxa27x-udc.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c
index db20d25daaab..8cff770e6a00 100644
--- a/arch/arm/mach-pxa/colibri-pxa270-income.c
+++ b/arch/arm/mach-pxa/colibri-pxa270-income.c
@@ -30,8 +30,8 @@
#include <mach/hardware.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pxa27x.h>
-#include <mach/pxa27x-udc.h>
+#include "pxa27x.h"
+#include "pxa27x-udc.h"
#include <linux/platform_data/video-pxafb.h>
#include "devices.h"
diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c
index 3503826333c7..e68acdd0cdbb 100644
--- a/arch/arm/mach-pxa/colibri-pxa270.c
+++ b/arch/arm/mach-pxa/colibri-pxa270.c
@@ -27,8 +27,8 @@
#include <asm/sizes.h>
#include <mach/audio.h>
-#include <mach/colibri.h>
-#include <mach/pxa27x.h>
+#include "colibri.h"
+#include "pxa27x.h"
#include "devices.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c
index f1a1ac1fbd85..6a5558d95d4e 100644
--- a/arch/arm/mach-pxa/colibri-pxa300.c
+++ b/arch/arm/mach-pxa/colibri-pxa300.c
@@ -22,8 +22,8 @@
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
-#include <mach/pxa300.h>
-#include <mach/colibri.h>
+#include "pxa300.h"
+#include "colibri.h"
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/video-pxafb.h>
#include <mach/audio.h>
diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c
index f6cc8b0ab82f..17067a3039a8 100644
--- a/arch/arm/mach-pxa/colibri-pxa320.c
+++ b/arch/arm/mach-pxa/colibri-pxa320.c
@@ -23,13 +23,13 @@
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
-#include <mach/pxa320.h>
-#include <mach/colibri.h>
+#include "pxa320.h"
+#include "colibri.h"
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <mach/audio.h>
-#include <mach/pxa27x-udc.h>
-#include <mach/udc.h>
+#include "pxa27x-udc.h"
+#include "udc.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
index 8240291ab8cf..b04431bb4ba7 100644
--- a/arch/arm/mach-pxa/colibri-pxa3xx.c
+++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
@@ -22,8 +22,8 @@
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
#include <mach/pxa3xx-regs.h>
-#include <mach/mfp-pxa300.h>
-#include <mach/colibri.h>
+#include "mfp-pxa300.h"
+#include "colibri.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>
diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/colibri.h
index cb4236e98a0f..cb4236e98a0f 100644
--- a/arch/arm/mach-pxa/include/mach/colibri.h
+++ b/arch/arm/mach-pxa/colibri.h
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 89f790dda93e..dc109dc3a622 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -48,12 +48,12 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <mach/corgi.h>
-#include <mach/sharpsl_pm.h>
+#include "sharpsl_pm.h"
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/scoop.h>
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index 7a39efc50865..d9206811be9b 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -27,7 +27,7 @@
#include <mach/corgi.h>
#include <mach/pxa2xx-regs.h>
-#include <mach/sharpsl_pm.h>
+#include "sharpsl_pm.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c
index fadfff8feaef..bf19b8426d2c 100644
--- a/arch/arm/mach-pxa/csb726.c
+++ b/arch/arm/mach-pxa/csb726.c
@@ -21,8 +21,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/csb726.h>
-#include <mach/pxa27x.h>
+#include "csb726.h"
+#include "pxa27x.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <mach/audio.h>
diff --git a/arch/arm/mach-pxa/include/mach/csb726.h b/arch/arm/mach-pxa/csb726.h
index 00cfbbbf73f7..f1f2a78cfd16 100644
--- a/arch/arm/mach-pxa/include/mach/csb726.h
+++ b/arch/arm/mach-pxa/csb726.h
@@ -11,7 +11,7 @@
#ifndef CSB726_H
#define CSB726_H
-#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */
#define CSB726_GPIO_IRQ_LAN 52
#define CSB726_GPIO_IRQ_SM501 53
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index d1211a40f400..37d8d85662f0 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -6,7 +6,7 @@
#include <linux/spi/pxa2xx_spi.h>
#include <linux/i2c/pxa-i2c.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/usb-pxa3xx-ulpi.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 8b1f89e096c6..6e0268deec43 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -39,8 +39,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
-#include <mach/pxa27x-udc.h>
+#include "pxa27x.h"
+#include "pxa27x-udc.h"
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
@@ -289,7 +289,7 @@ static void nand_cs_off(void)
static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
dsb();
diff --git a/arch/arm/mach-pxa/include/mach/eseries-irq.h b/arch/arm/mach-pxa/eseries-irq.h
index de292b269c63..de292b269c63 100644
--- a/arch/arm/mach-pxa/include/mach/eseries-irq.h
+++ b/arch/arm/mach-pxa/eseries-irq.h
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index 16dc95f68125..0b00b226f54b 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -31,12 +31,12 @@
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/eseries-gpio.h>
-#include <mach/eseries-irq.h>
+#include "eseries-irq.h"
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/irda-pxaficp.h>
#include "devices.h"
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index cd6224032109..34ad0a89d4a9 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -29,7 +29,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <mach/hardware.h>
@@ -50,7 +50,7 @@
#define GPIO19_GEN1_CAM_RST 19
#define GPIO28_GEN2_CAM_RST 28
-static struct pwm_lookup ezx_pwm_lookup[] = {
+static struct pwm_lookup ezx_pwm_lookup[] __maybe_unused = {
PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 78700,
PWM_POLARITY_NORMAL),
};
@@ -83,7 +83,7 @@ static struct pxafb_mode_info mode_ezx_old = {
.sync = 0,
};
-static struct pxafb_mach_info ezx_fb_info_1 = {
+static struct pxafb_mach_info ezx_fb_info_1 __maybe_unused = {
.modes = &mode_ezx_old,
.num_modes = 1,
.lcd_conn = LCD_COLOR_TFT_16BPP,
@@ -104,17 +104,17 @@ static struct pxafb_mode_info mode_72r89803y01 = {
.sync = 0,
};
-static struct pxafb_mach_info ezx_fb_info_2 = {
+static struct pxafb_mach_info ezx_fb_info_2 __maybe_unused = {
.modes = &mode_72r89803y01,
.num_modes = 1,
.lcd_conn = LCD_COLOR_TFT_18BPP,
};
-static struct platform_device *ezx_devices[] __initdata = {
+static struct platform_device *ezx_devices[] __initdata __maybe_unused = {
&ezx_backlight_device,
};
-static unsigned long ezx_pin_config[] __initdata = {
+static unsigned long ezx_pin_config[] __initdata __maybe_unused = {
/* PWM backlight */
GPIO16_PWM0_OUT,
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index f6c76a3ee3b2..6815a9357774 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -40,10 +40,10 @@
#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
-#include <mach/gumstix.h>
+#include "udc.h"
+#include "gumstix.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/gumstix.h b/arch/arm/mach-pxa/gumstix.h
index f7df27bbb42e..825f2d1260ae 100644
--- a/arch/arm/mach-pxa/include/mach/gumstix.h
+++ b/arch/arm/mach-pxa/gumstix.h
@@ -6,7 +6,7 @@
* published by the Free Software Foundation.
*/
-#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */
/* BTRESET - Reset line to Bluetooth module, active low signal. */
#define GPIO_GUMSTIX_BTRESET 7
diff --git a/arch/arm/mach-pxa/h5000.c b/arch/arm/mach-pxa/h5000.c
index 875ec3351499..be2a9c3fd55b 100644
--- a/arch/arm/mach-pxa/h5000.c
+++ b/arch/arm/mach-pxa/h5000.c
@@ -30,9 +30,9 @@
#include <asm/mach/map.h>
#include <asm/irq.h>
-#include <mach/pxa25x.h>
-#include <mach/h5000.h>
-#include <mach/udc.h>
+#include "pxa25x.h"
+#include "h5000.h"
+#include "udc.h"
#include <mach/smemc.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/h5000.h b/arch/arm/mach-pxa/h5000.h
index 2a5ae3802787..252461fd2ac8 100644
--- a/arch/arm/mach-pxa/include/mach/h5000.h
+++ b/arch/arm/mach-pxa/h5000.h
@@ -18,7 +18,7 @@
#ifndef __ASM_ARCH_H5000_H
#define __ASM_ARCH_H5000_H
-#include <mach/mfp-pxa25x.h>
+#include "mfp-pxa25x.h"
/*
* CPU GPIOs
diff --git a/arch/arm/mach-pxa/himalaya.c b/arch/arm/mach-pxa/himalaya.c
index 7a8d749a07b8..70e9c06595f6 100644
--- a/arch/arm/mach-pxa/himalaya.c
+++ b/arch/arm/mach-pxa/himalaya.c
@@ -24,7 +24,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index b076a835eb21..4a2f9aba93ea 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -44,7 +44,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/hx4700.h>
#include <linux/platform_data/irda-pxaficp.h>
diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c
index a1869f9b6219..cbaf4f6edcda 100644
--- a/arch/arm/mach-pxa/icontrol.c
+++ b/arch/arm/mach-pxa/icontrol.c
@@ -20,8 +20,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa320.h>
-#include <mach/mxm8x10.h>
+#include "pxa320.h"
+#include "mxm8x10.h"
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index f6d02e4cbcda..c410d84b243d 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -31,8 +31,8 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa25x.h>
-#include <mach/idp.h>
+#include "pxa25x.h"
+#include "idp.h"
#include <linux/platform_data/video-pxafb.h>
#include <mach/bitfield.h>
#include <linux/platform_data/mmc-pxamci.h>
diff --git a/arch/arm/mach-pxa/include/mach/idp.h b/arch/arm/mach-pxa/idp.h
index 7e63f4680271..7182ff92b732 100644
--- a/arch/arm/mach-pxa/include/mach/idp.h
+++ b/arch/arm/mach-pxa/idp.h
@@ -23,7 +23,7 @@
* IDP hardware.
*/
-#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */
#define IDP_FLASH_PHYS (PXA_CS0_PHYS)
#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS)
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 5d665588c7eb..051c554776a6 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -41,11 +41,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/pxa300.h>
+#include "pxa300.h"
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/littleton.h>
+#include "littleton.h"
#include <linux/platform_data/mtd-nand-pxa3xx.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/littleton.h b/arch/arm/mach-pxa/littleton.h
index 8066be54e9f5..8066be54e9f5 100644
--- a/arch/arm/mach-pxa/include/mach/littleton.h
+++ b/arch/arm/mach-pxa/littleton.h
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 5fcd4f094900..e9f401b0a432 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -40,8 +40,8 @@
#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
-#include <mach/pxa27x.h>
-#include <mach/lpd270.h>
+#include "pxa27x.h"
+#include "lpd270.h"
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
diff --git a/arch/arm/mach-pxa/include/mach/lpd270.h b/arch/arm/mach-pxa/lpd270.h
index 4edc712a2de8..4edc712a2de8 100644
--- a/arch/arm/mach-pxa/include/mach/lpd270.h
+++ b/arch/arm/mach-pxa/lpd270.h
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6de32fa0e251..7245f3359564 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -47,14 +47,14 @@
#include <asm/hardware/sa1111.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/audio.h>
#include <mach/lubbock.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/pm.h>
+#include "pm.h"
#include <mach/smemc.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 896b268c3ab7..abc918169367 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -38,7 +38,7 @@
#include <asm/mach/arch.h>
#include <asm/system_info.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/magician.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
@@ -48,9 +48,9 @@
#include <linux/regulator/max1586.h>
#include <linux/platform_data/pxa2xx_udc.h>
-#include <mach/udc.h>
-#include <mach/pxa27x-udc.h>
+#include "udc.h"
+#include "pxa27x-udc.h"
#include "devices.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index c3a87c176d72..40964069a17c 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -46,7 +46,7 @@
#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/mainstone.h>
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h b/arch/arm/mach-pxa/mfp-pxa25x.h
index cafadc33dfd8..1c59d4b3b19b 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
+++ b/arch/arm/mach-pxa/mfp-pxa25x.h
@@ -1,7 +1,7 @@
#ifndef __ASM_ARCH_MFP_PXA25X_H
#define __ASM_ARCH_MFP_PXA25X_H
-#include <mach/mfp-pxa2xx.h>
+#include "mfp-pxa2xx.h"
/* GPIO */
#define GPIO2_GPIO MFP_CFG_IN(GPIO2, AF0)
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/mfp-pxa27x.h
index b6132aa95dc0..9fe5601ce668 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
+++ b/arch/arm/mach-pxa/mfp-pxa27x.h
@@ -8,7 +8,7 @@
* specific controller, and this should work in most cases.
*/
-#include <mach/mfp-pxa2xx.h>
+#include "mfp-pxa2xx.h"
/* Note: GPIO3/GPIO4 will be driven by Power I2C when PCFR/PI2C_EN
* bit is set, regardless of the GPIO configuration
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index 666b78972c40..3732aec76750 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -21,7 +21,7 @@
#include <linux/syscore_ops.h>
#include <mach/pxa2xx-regs.h>
-#include <mach/mfp-pxa2xx.h>
+#include "mfp-pxa2xx.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h b/arch/arm/mach-pxa/mfp-pxa2xx.h
index cbf51ae81855..cbf51ae81855 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.h
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h b/arch/arm/mach-pxa/mfp-pxa300.h
index 4e1287070d21..5ee51e28304d 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h
+++ b/arch/arm/mach-pxa/mfp-pxa300.h
@@ -15,7 +15,7 @@
#ifndef __ASM_ARCH_MFP_PXA300_H
#define __ASM_ARCH_MFP_PXA300_H
-#include <mach/mfp-pxa3xx.h>
+#include "mfp-pxa3xx.h"
/* GPIO */
#define GPIO46_GPIO MFP_CFG(GPIO46, AF1)
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h b/arch/arm/mach-pxa/mfp-pxa320.h
index 3ce4682eabb6..e8797cfc72e0 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h
+++ b/arch/arm/mach-pxa/mfp-pxa320.h
@@ -15,7 +15,7 @@
#ifndef __ASM_ARCH_MFP_PXA320_H
#define __ASM_ARCH_MFP_PXA320_H
-#include <mach/mfp-pxa3xx.h>
+#include "mfp-pxa3xx.h"
/* GPIO */
#define GPIO46_GPIO MFP_CFG(GPIO46, AF0)
diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c
index 89863a01ecd7..994edc0158d4 100644
--- a/arch/arm/mach-pxa/mfp-pxa3xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa3xx.c
@@ -20,7 +20,7 @@
#include <linux/syscore_ops.h>
#include <mach/hardware.h>
-#include <mach/mfp-pxa3xx.h>
+#include "mfp-pxa3xx.h"
#include <mach/pxa3xx-regs.h>
#ifdef CONFIG_PM
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h b/arch/arm/mach-pxa/mfp-pxa3xx.h
index d375195d982b..d375195d982b 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h
+++ b/arch/arm/mach-pxa/mfp-pxa3xx.h
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa930.h b/arch/arm/mach-pxa/mfp-pxa930.h
index 04f7c97044f3..113967beeb67 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa930.h
+++ b/arch/arm/mach-pxa/mfp-pxa930.h
@@ -13,7 +13,7 @@
#ifndef __ASM_ARCH_MFP_PXA9xx_H
#define __ASM_ARCH_MFP_PXA9xx_H
-#include <mach/mfp-pxa3xx.h>
+#include "mfp-pxa3xx.h"
/* GPIO */
#define GPIO46_GPIO MFP_CFG(GPIO46, AF0)
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index ccfd2b63c6a4..38a96a193dc4 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -47,19 +47,19 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
-#include <mach/regs-rtc.h>
+#include "pxa27x.h"
+#include "regs-rtc.h"
#include <linux/platform_data/keypad-pxa27x.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
-#include <mach/pxa27x-udc.h>
+#include "udc.h"
+#include "pxa27x-udc.h"
#include <linux/platform_data/media/camera-pxa.h>
#include <mach/audio.h>
#include <mach/smemc.h>
#include <media/soc_camera.h>
-#include <mach/mioa701.h>
+#include "mioa701.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/mioa701.h b/arch/arm/mach-pxa/mioa701.h
index e57f5c724e8a..e57f5c724e8a 100644
--- a/arch/arm/mach-pxa/include/mach/mioa701.h
+++ b/arch/arm/mach-pxa/mioa701.h
diff --git a/arch/arm/mach-pxa/mp900.c b/arch/arm/mach-pxa/mp900.c
index 14f6aaf8fcc9..4d89029e5401 100644
--- a/arch/arm/mach-pxa/mp900.c
+++ b/arch/arm/mach-pxa/mp900.c
@@ -22,7 +22,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include "generic.h"
static void isp116x_pfm_delay(struct device *dev, int delay)
diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c
index d04ed4961e60..9a22ae0ad8c9 100644
--- a/arch/arm/mach-pxa/mxm8x10.c
+++ b/arch/arm/mach-pxa/mxm8x10.c
@@ -29,9 +29,9 @@
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pxa320.h>
+#include "pxa320.h"
-#include <mach/mxm8x10.h>
+#include "mxm8x10.h"
#include "devices.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/mxm8x10.h b/arch/arm/mach-pxa/mxm8x10.h
index ffa15665a418..ffa15665a418 100644
--- a/arch/arm/mach-pxa/include/mach/mxm8x10.h
+++ b/arch/arm/mach-pxa/mxm8x10.h
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index 8fbfb10047ec..e5ae99db1de4 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -28,14 +28,14 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/asoc-palm27x.h>
-#include <mach/palm27x.h>
+#include "palm27x.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/palm27x.h b/arch/arm/mach-pxa/palm27x.h
index d4eac3d6ffb5..d4eac3d6ffb5 100644
--- a/arch/arm/mach-pxa/include/mach/palm27x.h
+++ b/arch/arm/mach-pxa/palm27x.h
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index cf210b11ffcc..980f2847f5b5 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -32,7 +32,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
#include <mach/palmld.h>
#include <linux/platform_data/mmc-pxamci.h>
@@ -40,7 +40,7 @@
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/keypad-pxa27x.h>
#include <linux/platform_data/asoc-palm27x.h>
-#include <mach/palm27x.h>
+#include "palm27x.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index 3ed9b029428b..876144aa3564 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -33,16 +33,16 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
-#include <mach/palmt5.h>
+#include "palmt5.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/asoc-palm27x.h>
-#include <mach/palm27x.h>
+#include "palm27x.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/palmt5.h b/arch/arm/mach-pxa/palmt5.h
index e342c5921405..f850cc9de1b4 100644
--- a/arch/arm/mach-pxa/include/mach/palmt5.h
+++ b/arch/arm/mach-pxa/palmt5.h
@@ -15,7 +15,7 @@
#ifndef _INCLUDE_PALMT5_H_
#define _INCLUDE_PALMT5_H_
-#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */
/** HERE ARE GPIOs **/
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index 0b5c3876720c..18946594a7c8 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -32,13 +32,13 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/audio.h>
#include <mach/palmtc.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
-#include <mach/udc.h>
+#include "udc.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index e64bb4326e69..36b46141a28b 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -32,13 +32,13 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/audio.h>
-#include <mach/palmte2.h>
+#include "palmte2.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/asoc-palm27x.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/palmte2.h b/arch/arm/mach-pxa/palmte2.h
index f89e989a7637..f89e989a7637 100644
--- a/arch/arm/mach-pxa/include/mach/palmte2.h
+++ b/arch/arm/mach-pxa/palmte2.h
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index 2dc56062fb7e..4cc05ecce618 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -31,20 +31,20 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
-#include <mach/pxa27x-udc.h>
+#include "pxa27x.h"
+#include "pxa27x-udc.h"
#include <mach/audio.h>
-#include <mach/palmtreo.h>
+#include "palmtreo.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <mach/pxa2xx-regs.h>
#include <linux/platform_data/asoc-palm27x.h>
#include <linux/platform_data/media/camera-pxa.h>
-#include <mach/palm27x.h>
+#include "palm27x.h"
#include <sound/pxa2xx-lib.h>
diff --git a/arch/arm/mach-pxa/include/mach/palmtreo.h b/arch/arm/mach-pxa/palmtreo.h
index 714b6574393e..714b6574393e 100644
--- a/arch/arm/mach-pxa/include/mach/palmtreo.h
+++ b/arch/arm/mach-pxa/palmtreo.h
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 83f830dd8ad8..36646975b5d2 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -37,16 +37,16 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
#include <mach/palmtx.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/asoc-palm27x.h>
-#include <mach/palm27x.h>
+#include "palm27x.h"
#include "generic.h"
#include "devices.h"
@@ -250,7 +250,7 @@ static inline void palmtx_keys_init(void) {}
static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
char __iomem *nandaddr = this->IO_ADDR_W;
if (cmd == NAND_CMD_NONE)
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index e3df17a7e8d4..9c308de158c6 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -37,18 +37,18 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
-#include <mach/palmz72.h>
+#include "palmz72.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/asoc-palm27x.h>
-#include <mach/palm27x.h>
+#include "palm27x.h"
-#include <mach/pm.h>
+#include "pm.h"
#include <linux/platform_data/media/camera-pxa.h>
#include <media/soc_camera.h>
diff --git a/arch/arm/mach-pxa/include/mach/palmz72.h b/arch/arm/mach-pxa/palmz72.h
index 0d4700a79612..0d4700a79612 100644
--- a/arch/arm/mach-pxa/include/mach/palmz72.h
+++ b/arch/arm/mach-pxa/palmz72.h
diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c
index 69918c7e3f1f..ccca9f7575c3 100644
--- a/arch/arm/mach-pxa/pcm027.c
+++ b/arch/arm/mach-pxa/pcm027.c
@@ -30,8 +30,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
-#include <mach/pcm027.h>
+#include "pxa27x.h"
+#include "pcm027.h"
#include "generic.h"
/*
diff --git a/arch/arm/mach-pxa/include/mach/pcm027.h b/arch/arm/mach-pxa/pcm027.h
index 86ebd7b6c960..047cdf234f25 100644
--- a/arch/arm/mach-pxa/include/mach/pcm027.h
+++ b/arch/arm/mach-pxa/pcm027.h
@@ -23,7 +23,7 @@
* Definitions of CPU card resources only
*/
-#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */
/* phyCORE-PXA270 (PCM027) Interrupts */
#define PCM027_IRQ(x) (IRQ_BOARD_START + (x))
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 8459239a093c..0bd5959ef7d5 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -32,11 +32,11 @@
#include <linux/platform_data/media/camera-pxa.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pcm990_baseboard.h>
+#include "pcm990_baseboard.h"
#include <linux/platform_data/video-pxafb.h>
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h b/arch/arm/mach-pxa/pcm990_baseboard.h
index 7e544c14967e..79d35adfa786 100644
--- a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
+++ b/arch/arm/mach-pxa/pcm990_baseboard.h
@@ -19,8 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <mach/pcm027.h>
-#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+#include "pcm027.h"
+#include <mach/irqs.h> /* PXA_GPIO_TO_IRQ */
/*
* definitions relevant only when the PCM-990
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 37178a8559b1..388463b99090 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -16,7 +16,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
-#include <mach/pm.h>
+#include "pm.h"
struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
static unsigned long *sleep_save;
diff --git a/arch/arm/mach-pxa/include/mach/pm.h b/arch/arm/mach-pxa/pm.h
index 51558bcee999..51558bcee999 100644
--- a/arch/arm/mach-pxa/include/mach/pm.h
+++ b/arch/arm/mach-pxa/pm.h
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 195b1121c8f1..62a119137be7 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -41,9 +41,9 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
+#include "udc.h"
#include <linux/platform_data/irda-pxaficp.h>
#include <mach/poodle.h>
#include <linux/platform_data/video-pxafb.h>
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 1dc85ffc3e20..a177bf45feef 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -30,9 +30,9 @@
#include <asm/suspend.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/reset.h>
-#include <mach/pm.h>
+#include "pm.h"
#include <mach/dma.h>
#include <mach/smemc.h>
diff --git a/arch/arm/mach-pxa/include/mach/pxa25x.h b/arch/arm/mach-pxa/pxa25x.h
index 5a341752e32c..2011e8da0592 100644
--- a/arch/arm/mach-pxa/include/mach/pxa25x.h
+++ b/arch/arm/mach-pxa/pxa25x.h
@@ -3,7 +3,7 @@
#include <mach/hardware.h>
#include <mach/pxa2xx-regs.h>
-#include <mach/mfp-pxa25x.h>
+#include "mfp-pxa25x.h"
#include <mach/irqs.h>
#endif /* __MACH_PXA25x_H */
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x-udc.h b/arch/arm/mach-pxa/pxa27x-udc.h
index 4cf28f670706..4cf28f670706 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x-udc.h
+++ b/arch/arm/mach-pxa/pxa27x-udc.h
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index ffc424028557..8dfd1755c659 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -28,10 +28,10 @@
#include <asm/irq.h>
#include <asm/suspend.h>
#include <mach/irqs.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/reset.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pm.h>
+#include "pm.h"
#include <mach/dma.h>
#include <mach/smemc.h>
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/pxa27x.h
index 1a4291936c58..075131d83eab 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x.h
+++ b/arch/arm/mach-pxa/pxa27x.h
@@ -4,7 +4,7 @@
#include <linux/suspend.h>
#include <mach/hardware.h>
#include <mach/pxa2xx-regs.h>
-#include <mach/mfp-pxa27x.h>
+#include "mfp-pxa27x.h"
#include <mach/irqs.h>
#define ARB_CNTRL __REG(0x48000048) /* Arbiter Control Register */
diff --git a/arch/arm/mach-pxa/pxa2xx.c b/arch/arm/mach-pxa/pxa2xx.c
index 447dcbb22f6f..6b5e566f52c8 100644
--- a/arch/arm/mach-pxa/pxa2xx.c
+++ b/arch/arm/mach-pxa/pxa2xx.c
@@ -17,7 +17,7 @@
#include <mach/hardware.h>
#include <mach/pxa2xx-regs.h>
-#include <mach/mfp-pxa25x.h>
+#include "mfp-pxa25x.h"
#include <mach/reset.h>
#include <linux/platform_data/irda-pxaficp.h>
diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c
index 28c5b5686638..df83b1bddf34 100644
--- a/arch/arm/mach-pxa/pxa300.c
+++ b/arch/arm/mach-pxa/pxa300.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/pxa300.h>
+#include "pxa300.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/pxa300.h b/arch/arm/mach-pxa/pxa300.h
index 733b6412c3df..59fa41025c80 100644
--- a/arch/arm/mach-pxa/include/mach/pxa300.h
+++ b/arch/arm/mach-pxa/pxa300.h
@@ -1,7 +1,7 @@
#ifndef __MACH_PXA300_H
#define __MACH_PXA300_H
-#include <mach/pxa3xx.h>
-#include <mach/mfp-pxa300.h>
+#include "pxa3xx.h"
+#include "mfp-pxa300.h"
#endif /* __MACH_PXA300_H */
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
index 2f55bb4b9087..a26eec57eec6 100644
--- a/arch/arm/mach-pxa/pxa320.c
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/pxa320.h>
+#include "pxa320.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/pxa320.h b/arch/arm/mach-pxa/pxa320.h
index b6204e470d89..b9e5115a1c30 100644
--- a/arch/arm/mach-pxa/include/mach/pxa320.h
+++ b/arch/arm/mach-pxa/pxa320.h
@@ -1,8 +1,8 @@
#ifndef __MACH_PXA320_H
#define __MACH_PXA320_H
-#include <mach/pxa3xx.h>
-#include <mach/mfp-pxa320.h>
+#include "pxa3xx.h"
+#include "mfp-pxa320.h"
#endif /* __MACH_PXA320_H */
diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c
index 1c85275cb768..eba595fac8ca 100644
--- a/arch/arm/mach-pxa/pxa3xx-ulpi.c
+++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c
@@ -26,7 +26,7 @@
#include <linux/usb/otg.h>
#include <mach/hardware.h>
-#include <mach/regs-u2d.h>
+#include "regs-u2d.h"
#include <linux/platform_data/usb-pxa3xx-ulpi.h>
struct pxa3xx_u2d_ulpi {
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 20ce2d386f17..a1c4c888f246 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -30,7 +30,7 @@
#include <mach/pxa3xx-regs.h>
#include <mach/reset.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pm.h>
+#include "pm.h"
#include <mach/dma.h>
#include <mach/smemc.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx.h b/arch/arm/mach-pxa/pxa3xx.h
index b4143fb6631f..b4143fb6631f 100644
--- a/arch/arm/mach-pxa/include/mach/pxa3xx.h
+++ b/arch/arm/mach-pxa/pxa3xx.h
diff --git a/arch/arm/mach-pxa/pxa930.c b/arch/arm/mach-pxa/pxa930.c
index ab624487cf39..da912be6eae7 100644
--- a/arch/arm/mach-pxa/pxa930.c
+++ b/arch/arm/mach-pxa/pxa930.c
@@ -17,7 +17,7 @@
#include <linux/gpio-pxa.h>
#include <linux/platform_device.h>
-#include <mach/pxa930.h>
+#include "pxa930.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/include/mach/pxa930.h b/arch/arm/mach-pxa/pxa930.h
index 190363b98d01..4eceb02978e8 100644
--- a/arch/arm/mach-pxa/include/mach/pxa930.h
+++ b/arch/arm/mach-pxa/pxa930.h
@@ -1,7 +1,7 @@
#ifndef __MACH_PXA930_H
#define __MACH_PXA930_H
-#include <mach/pxa3xx.h>
-#include <mach/mfp-pxa930.h>
+#include "pxa3xx.h"
+#include "mfp-pxa930.h"
#endif /* __MACH_PXA930_H */
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 36571a9a44fe..8347d87a713d 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -49,7 +49,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa300.h>
+#include "pxa300.h"
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
@@ -1046,7 +1046,7 @@ static void __init raumfeld_common_init(void)
i2c_register_board_info(1, &raumfeld_pwri2c_board_info, 1);
}
-static void __init raumfeld_controller_init(void)
+static void __init __maybe_unused raumfeld_controller_init(void)
{
int ret;
@@ -1067,7 +1067,7 @@ static void __init raumfeld_controller_init(void)
raumfeld_w1_init();
}
-static void __init raumfeld_connector_init(void)
+static void __init __maybe_unused raumfeld_connector_init(void)
{
pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_connector_pin_config));
spi_register_board_info(ARRAY_AND_SIZE(connector_spi_devices));
@@ -1079,7 +1079,7 @@ static void __init raumfeld_connector_init(void)
raumfeld_common_init();
}
-static void __init raumfeld_speaker_init(void)
+static void __init __maybe_unused raumfeld_speaker_init(void)
{
pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_speaker_pin_config));
spi_register_board_info(ARRAY_AND_SIZE(speaker_spi_devices));
diff --git a/arch/arm/mach-pxa/include/mach/regs-rtc.h b/arch/arm/mach-pxa/regs-rtc.h
index f0e4a589bbe1..f0e4a589bbe1 100644
--- a/arch/arm/mach-pxa/include/mach/regs-rtc.h
+++ b/arch/arm/mach-pxa/regs-rtc.h
diff --git a/arch/arm/mach-pxa/include/mach/regs-u2d.h b/arch/arm/mach-pxa/regs-u2d.h
index c15c0c57de08..c15c0c57de08 100644
--- a/arch/arm/mach-pxa/include/mach/regs-u2d.h
+++ b/arch/arm/mach-pxa/regs-u2d.h
diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c
index 710c493eac89..1414b5f29114 100644
--- a/arch/arm/mach-pxa/saar.c
+++ b/arch/arm/mach-pxa/saar.c
@@ -31,7 +31,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
-#include <mach/pxa930.h>
+#include "pxa930.h"
#include <linux/platform_data/video-pxafb.h>
#include "devices.h"
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index bdc0c41bc4fd..b80eab9993c5 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -27,10 +27,10 @@
#include <linux/io.h>
#include <asm/mach-types.h>
-#include <mach/pm.h>
+#include "pm.h"
#include <mach/pxa2xx-regs.h>
-#include <mach/regs-rtc.h>
-#include <mach/sharpsl_pm.h>
+#include "regs-rtc.h"
+#include "sharpsl_pm.h"
/*
* Constants
diff --git a/arch/arm/mach-pxa/include/mach/sharpsl_pm.h b/arch/arm/mach-pxa/sharpsl_pm.h
index 905be6755f04..905be6755f04 100644
--- a/arch/arm/mach-pxa/include/mach/sharpsl_pm.h
+++ b/arch/arm/mach-pxa/sharpsl_pm.h
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index f4e2e2719580..825f903ab77e 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -40,15 +40,15 @@
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/scoop.h>
-#include <mach/pxa27x.h>
-#include <mach/pxa27x-udc.h>
+#include "pxa27x.h"
+#include "pxa27x-udc.h"
#include <mach/reset.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/video-pxafb.h>
#include <mach/spitz.h>
-#include <mach/sharpsl_pm.h>
+#include "sharpsl_pm.h"
#include <mach/smemc.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index e191f9996b26..ea9f9034cb54 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -25,8 +25,8 @@
#include <mach/hardware.h>
#include <mach/spitz.h>
-#include <mach/pxa27x.h>
-#include <mach/sharpsl_pm.h>
+#include "pxa27x.h"
+#include "sharpsl_pm.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
index 01de542432a6..702f4f14b708 100644
--- a/arch/arm/mach-pxa/stargate2.c
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -43,10 +43,10 @@
#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
-#include <mach/pxa27x-udc.h>
+#include "udc.h"
+#include "pxa27x-udc.h"
#include <mach/smemc.h>
#include <linux/spi/spi.h>
diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c
index 349a13a76215..4b38e821ac9c 100644
--- a/arch/arm/mach-pxa/tavorevb.c
+++ b/arch/arm/mach-pxa/tavorevb.c
@@ -24,7 +24,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa930.h>
+#include "pxa930.h"
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/keypad-pxa27x.h>
diff --git a/arch/arm/mach-pxa/tosa-bt.c b/arch/arm/mach-pxa/tosa-bt.c
index e0a53208880a..107f37210fb9 100644
--- a/arch/arm/mach-pxa/tosa-bt.c
+++ b/arch/arm/mach-pxa/tosa-bt.c
@@ -16,7 +16,7 @@
#include <linux/delay.h>
#include <linux/rfkill.h>
-#include <mach/tosa_bt.h>
+#include "tosa_bt.h"
static void tosa_bt_on(struct tosa_bt_data *data)
{
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index e6e27c0468e4..13de6602966f 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -43,12 +43,12 @@
#include <asm/setup.h>
#include <asm/mach-types.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/reset.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/udc.h>
-#include <mach/tosa_bt.h>
+#include "udc.h"
+#include "tosa_bt.h"
#include <mach/audio.h>
#include <mach/smemc.h>
diff --git a/arch/arm/mach-pxa/include/mach/tosa_bt.h b/arch/arm/mach-pxa/tosa_bt.h
index efc3c3d3b75d..efc3c3d3b75d 100644
--- a/arch/arm/mach-pxa/include/mach/tosa_bt.h
+++ b/arch/arm/mach-pxa/tosa_bt.h
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 066e3a250ee0..ea78bc5c4198 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -41,7 +41,7 @@
#include <asm/mach/irq.h>
#include <asm/mach/flash.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/trizeps4.h>
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
diff --git a/arch/arm/mach-pxa/include/mach/udc.h b/arch/arm/mach-pxa/udc.h
index 9a827e32db98..9a827e32db98 100644
--- a/arch/arm/mach-pxa/include/mach/udc.h
+++ b/arch/arm/mach-pxa/udc.h
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 7ecc61ad2bed..8e89d91b206b 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -47,12 +47,12 @@
#include <linux/mtd/physmap.h>
#include <linux/syscore_ops.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
#include <mach/regs-uart.h>
#include <linux/platform_data/pcmcia-pxa2xx_viper.h>
-#include <mach/viper.h>
+#include "viper.h"
#include <asm/setup.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/include/mach/viper.h b/arch/arm/mach-pxa/viper.h
index 5f5fbf1f6489..5f5fbf1f6489 100644
--- a/arch/arm/mach-pxa/include/mach/viper.h
+++ b/arch/arm/mach-pxa/viper.h
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index 54122a983ae3..c006ee902a8f 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -31,14 +31,14 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/audio.h>
#include <mach/vpac270.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
-#include <mach/pxa27x-udc.h>
-#include <mach/udc.h>
+#include "pxa27x-udc.h"
+#include "udc.h"
#include <linux/platform_data/ata-pxa.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/xcep.c b/arch/arm/mach-pxa/xcep.c
index 13b1d4586d7d..3f06cd90567a 100644
--- a/arch/arm/mach-pxa/xcep.c
+++ b/arch/arm/mach-pxa/xcep.c
@@ -28,7 +28,7 @@
#include <asm/mach/map.h>
#include <mach/hardware.h>
-#include <mach/pxa25x.h>
+#include "pxa25x.h"
#include <mach/smemc.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index d9899d73e46b..510e533871f3 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -35,13 +35,13 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa27x.h>
-#include <mach/mfp-pxa27x.h>
+#include "pxa27x.h"
+#include "mfp-pxa27x.h"
#include <mach/z2.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <mach/pm.h>
+#include "pm.h"
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index 30e62a3f0701..515b7ddda8aa 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -38,17 +38,17 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/pxa27x.h>
+#include "pxa27x.h"
#include <mach/regs-uart.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/mmc-pxamci.h>
-#include <mach/pxa27x-udc.h>
-#include <mach/udc.h>
+#include "pxa27x-udc.h"
+#include "udc.h"
#include <linux/platform_data/video-pxafb.h>
-#include <mach/pm.h>
+#include "pm.h"
#include <mach/audio.h>
#include <linux/platform_data/pcmcia-pxa2xx_viper.h>
-#include <mach/zeus.h>
+#include "zeus.h"
#include <mach/smemc.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/zeus.h b/arch/arm/mach-pxa/zeus.h
index 56024f81d57e..56024f81d57e 100644
--- a/arch/arm/mach-pxa/include/mach/zeus.h
+++ b/arch/arm/mach-pxa/zeus.h
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index e20359a7433c..3642389b301a 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -25,10 +25,10 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/pxa3xx.h>
+#include "pxa3xx.h"
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
-#include <mach/zylonite.h>
+#include "zylonite.h"
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/keypad-pxa27x.h>
diff --git a/arch/arm/mach-pxa/include/mach/zylonite.h b/arch/arm/mach-pxa/zylonite.h
index ecca976f03d2..ecca976f03d2 100644
--- a/arch/arm/mach-pxa/include/mach/zylonite.h
+++ b/arch/arm/mach-pxa/zylonite.h
diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c
index 869bce7c3f24..e247acf1400a 100644
--- a/arch/arm/mach-pxa/zylonite_pxa300.c
+++ b/arch/arm/mach-pxa/zylonite_pxa300.c
@@ -21,8 +21,8 @@
#include <linux/platform_data/pca953x.h>
#include <linux/gpio.h>
-#include <mach/pxa300.h>
-#include <mach/zylonite.h>
+#include "pxa300.h"
+#include "zylonite.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c
index 9942bac4cf7d..47961ae0c448 100644
--- a/arch/arm/mach-pxa/zylonite_pxa320.c
+++ b/arch/arm/mach-pxa/zylonite_pxa320.c
@@ -18,8 +18,8 @@
#include <linux/init.h>
#include <linux/gpio.h>
-#include <mach/pxa320.h>
-#include <mach/zylonite.h>
+#include "pxa320.h"
+#include "zylonite.h"
#include "generic.h"
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 2256cd1e25d1..73494500b51c 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_QCOM
- bool "Qualcomm Support" if ARCH_MULTI_V7
+ bool "Qualcomm Support"
+ depends on ARCH_MULTI_V7
select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_GIC
select ARM_AMBA
diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c
index 9b00123a315d..5494c9e0c909 100644
--- a/arch/arm/mach-qcom/platsmp.c
+++ b/arch/arm/mach-qcom/platsmp.c
@@ -332,7 +332,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
}
}
-static struct smp_operations smp_msm8660_ops __initdata = {
+static const struct smp_operations smp_msm8660_ops __initconst = {
.smp_prepare_cpus = qcom_smp_prepare_cpus,
.smp_secondary_init = qcom_secondary_init,
.smp_boot_secondary = msm8660_boot_secondary,
@@ -342,7 +342,7 @@ static struct smp_operations smp_msm8660_ops __initdata = {
};
CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
-static struct smp_operations qcom_smp_kpssv1_ops __initdata = {
+static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
.smp_prepare_cpus = qcom_smp_prepare_cpus,
.smp_secondary_init = qcom_secondary_init,
.smp_boot_secondary = kpssv1_boot_secondary,
@@ -352,7 +352,7 @@ static struct smp_operations qcom_smp_kpssv1_ops __initdata = {
};
CPU_METHOD_OF_DECLARE(qcom_smp_kpssv1, "qcom,kpss-acc-v1", &qcom_smp_kpssv1_ops);
-static struct smp_operations qcom_smp_kpssv2_ops __initdata = {
+static const struct smp_operations qcom_smp_kpssv2_ops __initconst = {
.smp_prepare_cpus = qcom_smp_prepare_cpus,
.smp_secondary_init = qcom_secondary_init,
.smp_boot_secondary = kpssv2_boot_secondary,
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 565925f37dc5..def40a0dd60c 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -1,13 +1,29 @@
-menu "RealView platform type"
- depends on ARCH_REALVIEW
+menuconfig ARCH_REALVIEW
+ bool "ARM Ltd. RealView family" if ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7
+ select ARM_AMBA
+ select ARM_TIMER_SP804
+ select COMMON_CLK_VERSATILE
+ select GPIO_PL061 if GPIOLIB
+ select ICST
+ select PLAT_VERSATILE
+ select PLAT_VERSATILE_SCHED_CLOCK
+ help
+ This enables support for ARM Ltd RealView boards.
+
+if ARCH_REALVIEW
config REALVIEW_DT
bool "Support RealView(R) Device Tree based boot"
select ARM_GIC
+ select CLK_SP810
+ select HAVE_SMP
+ select ICST
+ select MACH_REALVIEW_EB if ARCH_MULTI_V5
select MFD_SYSCON
select POWER_RESET
select POWER_RESET_VERSATILE
select POWER_SUPPLY
+ select SMP_ON_UP if SMP
select SOC_REALVIEW
select USE_OF
help
@@ -17,14 +33,32 @@ config REALVIEW_DT
config MACH_REALVIEW_EB
bool "Support RealView(R) Emulation Baseboard"
select ARM_GIC
+ select CPU_ARM926T if ARCH_MULTI_V5
help
Include support for the ARM(R) RealView(R) Emulation Baseboard
- platform.
+ platform. On an ARMv5 kernel, this will include support for
+ the ARM926EJ-S core tile, while on an ARMv6/v7 kernel, at least
+ one of the ARM1136, ARM1176, ARM11MPCore or Cortex-A9MPCore
+ core tile options should be enabled.
+
+config REALVIEW_EB_ARM1136
+ bool "Support ARM1136J(F)-S Tile"
+ depends on MACH_REALVIEW_EB && ARCH_MULTI_V6
+ select CPU_V6
+ help
+ Enable support for the ARM1136 tile fitted to the
+ Realview(R) Emulation Baseboard platform.
+
+config REALVIEW_EB_ARM1176
+ bool "Support ARM1176JZ(F)-S Tile"
+ depends on MACH_REALVIEW_EB && ARCH_MULTI_V6
+ help
+ Enable support for the ARM1176 tile fitted to the
+ Realview(R) Emulation Baseboard platform.
config REALVIEW_EB_A9MP
bool "Support Multicore Cortex-A9 Tile"
- depends on MACH_REALVIEW_EB
- select CPU_V7
+ depends on MACH_REALVIEW_EB && ARCH_MULTI_V7
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select HAVE_SMP
@@ -35,9 +69,7 @@ config REALVIEW_EB_A9MP
config REALVIEW_EB_ARM11MP
bool "Support ARM11MPCore Tile"
- depends on MACH_REALVIEW_EB
- select ARCH_HAS_BARRIERS if SMP
- select CPU_V6K
+ depends on MACH_REALVIEW_EB && ARCH_MULTI_V6
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select HAVE_SMP
@@ -48,7 +80,7 @@ config REALVIEW_EB_ARM11MP
config REALVIEW_EB_ARM11MP_REVB
bool "Support ARM11MPCore RevB Tile"
- depends on REALVIEW_EB_ARM11MP
+ depends on REALVIEW_EB_ARM11MP && ARCH_MULTI_V6
help
Enable support for the ARM11MPCore Revision B tile on the
Realview(R) Emulation Baseboard platform. Since there are device
@@ -57,9 +89,8 @@ config REALVIEW_EB_ARM11MP_REVB
config MACH_REALVIEW_PB11MP
bool "Support RealView(R) Platform Baseboard for ARM11MPCore"
- select ARCH_HAS_BARRIERS if SMP
+ depends on ARCH_MULTI_V6
select ARM_GIC
- select CPU_V6K
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select HAVE_PATA_PLATFORM
@@ -73,6 +104,7 @@ config MACH_REALVIEW_PB11MP
# ARMv6 CPU without K extensions, but does have the new exclusive ops
config MACH_REALVIEW_PB1176
bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S"
+ depends on ARCH_MULTI_V6
select ARM_GIC
select CPU_V6
select HAVE_TCM
@@ -92,8 +124,8 @@ config REALVIEW_PB1176_SECURE_FLASH
config MACH_REALVIEW_PBA8
bool "Support RealView(R) Platform Baseboard for Cortex(tm)-A8 platform"
+ depends on ARCH_MULTI_V7
select ARM_GIC
- select CPU_V7
select HAVE_PATA_PLATFORM
help
Include support for the ARM(R) RealView Platform Baseboard for
@@ -101,15 +133,15 @@ config MACH_REALVIEW_PBA8
support for PCI-E and Compact Flash.
config MACH_REALVIEW_PBX
- bool "Support RealView(R) Platform Baseboard Explore"
- select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
+ bool "Support RealView(R) Platform Baseboard Explore for Cortex-A9"
+ depends on ARCH_MULTI_V7
select ARM_GIC
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select HAVE_PATA_PLATFORM
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
- select ZONE_DMA if SPARSEMEM
+ select ZONE_DMA
help
Include support for the ARM(R) RealView(R) Platform Baseboard
Explore.
@@ -124,6 +156,6 @@ config REALVIEW_HIGH_PHYS_OFFSET
the board supports 512MB of RAM, this option allows the
memory to be accessed contiguously at the high physical
offset. On the PBX board, disabling this option allows 1GB of
- RAM to be used with SPARSEMEM.
+ RAM to be used with HIGHMEM.
-endmenu
+endif
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index e07fdf7ae8a7..8be6632407d8 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -1,13 +1,20 @@
#
# Makefile for the linux kernel.
#
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
+ -I$(srctree)/arch/arm/plat-versatile/include
+
-obj-y := core.o
obj-$(CONFIG_REALVIEW_DT) += realview-dt.o
+obj-$(CONFIG_SMP) += platsmp-dt.o
+obj-y := core.o
+
+ifdef CONFIG_ATAGS
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o
obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o
obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o
obj-$(CONFIG_MACH_REALVIEW_PBX) += realview_pbx.o
obj-$(CONFIG_SMP) += platsmp.o
+endif
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-realview/include/mach/board-eb.h b/arch/arm/mach-realview/board-eb.h
index a301e61a5554..a850ae6945b0 100644
--- a/arch/arm/mach-realview/include/mach/board-eb.h
+++ b/arch/arm/mach-realview/board-eb.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/board-eb.h
- *
* Copyright (C) 2007 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +19,7 @@
#ifndef __ASM_ARCH_BOARD_EB_H
#define __ASM_ARCH_BOARD_EB_H
-#include <mach/platform.h>
+#include "platform.h"
/*
* RealView EB + ARM11MPCore peripheral addresses
diff --git a/arch/arm/mach-realview/include/mach/board-pb1176.h b/arch/arm/mach-realview/board-pb1176.h
index 2a15fef94730..29c04a9e1344 100644
--- a/arch/arm/mach-realview/include/mach/board-pb1176.h
+++ b/arch/arm/mach-realview/board-pb1176.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/board-pb1176.h
- *
* Copyright (C) 2008 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +19,7 @@
#ifndef __ASM_ARCH_BOARD_PB1176_H
#define __ASM_ARCH_BOARD_PB1176_H
-#include <mach/platform.h>
+#include "platform.h"
/*
* Peripheral addresses
diff --git a/arch/arm/mach-realview/include/mach/board-pb11mp.h b/arch/arm/mach-realview/board-pb11mp.h
index aa2d4e02ea2c..b16e6e85e92d 100644
--- a/arch/arm/mach-realview/include/mach/board-pb11mp.h
+++ b/arch/arm/mach-realview/board-pb11mp.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/board-pb11mp.h
- *
* Copyright (C) 2008 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +19,7 @@
#ifndef __ASM_ARCH_BOARD_PB11MP_H
#define __ASM_ARCH_BOARD_PB11MP_H
-#include <mach/platform.h>
+#include "platform.h"
/*
* Peripheral addresses
diff --git a/arch/arm/mach-realview/include/mach/board-pba8.h b/arch/arm/mach-realview/board-pba8.h
index 4dfc67a4f45f..6a1391f50373 100644
--- a/arch/arm/mach-realview/include/mach/board-pba8.h
+++ b/arch/arm/mach-realview/board-pba8.h
@@ -1,6 +1,4 @@
/*
- * include/asm-arm/arch-realview/board-pba8.h
- *
* Copyright (C) 2008 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +19,7 @@
#ifndef __ASM_ARCH_BOARD_PBA8_H
#define __ASM_ARCH_BOARD_PBA8_H
-#include <mach/platform.h>
+#include "platform.h"
/*
* Peripheral addresses
diff --git a/arch/arm/mach-realview/include/mach/board-pbx.h b/arch/arm/mach-realview/board-pbx.h
index 848bfff6d8f1..5cda480b12bb 100644
--- a/arch/arm/mach-realview/include/mach/board-pbx.h
+++ b/arch/arm/mach-realview/board-pbx.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/board-pbx.h
- *
* Copyright (C) 2009 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +18,7 @@
#ifndef __ASM_ARCH_BOARD_PBX_H
#define __ASM_ARCH_BOARD_PBX_H
-#include <mach/platform.h>
+#include "platform.h"
/*
* Peripheral addresses
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 44575edc44b1..baf174542e36 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -36,8 +36,7 @@
#include <linux/memblock.h>
#include <clocksource/timer-sp804.h>
-
-#include <mach/hardware.h>
+#include "hardware.h"
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/hardware/icst.h>
@@ -46,8 +45,7 @@
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
-#include <mach/platform.h>
-#include <mach/irqs.h>
+#include "platform.h"
#include <plat/sched_clock.h>
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 868ece221978..05a995ea16d3 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-realview/core.h
- *
* Copyright (C) 2004 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
@@ -54,7 +52,7 @@ extern int realview_usb_register(struct resource *res);
extern void realview_init_early(void);
extern void realview_fixup(struct tag *tags, char **from);
-extern struct smp_operations realview_smp_ops;
+extern const struct smp_operations realview_smp_ops;
extern void realview_cpu_die(unsigned int cpu);
#endif
diff --git a/arch/arm/mach-realview/include/mach/hardware.h b/arch/arm/mach-realview/hardware.h
index 281e71c97525..957a230aadf4 100644
--- a/arch/arm/mach-realview/include/mach/hardware.h
+++ b/arch/arm/mach-realview/hardware.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/hardware.h
- *
* This file contains the hardware definitions of the RealView boards.
*
* Copyright (C) 2003 ARM Limited.
diff --git a/arch/arm/mach-realview/include/mach/barriers.h b/arch/arm/mach-realview/include/mach/barriers.h
deleted file mode 100644
index 9a732195aa1c..000000000000
--- a/arch/arm/mach-realview/include/mach/barriers.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Barriers redefined for RealView ARM11MPCore platforms with L220 cache
- * controller to work around hardware errata causing the outer_sync()
- * operation to deadlock the system.
- */
-#define mb() dsb()
-#define rmb() dsb()
-#define wmb() mb()
diff --git a/arch/arm/mach-realview/include/mach/irqs.h b/arch/arm/mach-realview/include/mach/irqs.h
deleted file mode 100644
index 78854f2fa323..000000000000
--- a/arch/arm/mach-realview/include/mach/irqs.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * arch/arm/mach-realview/include/mach/irqs.h
- *
- * Copyright (C) 2003 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H
-
-#include <mach/irqs-eb.h>
-#include <mach/irqs-pb11mp.h>
-#include <mach/irqs-pb1176.h>
-#include <mach/irqs-pba8.h>
-#include <mach/irqs-pbx.h>
-
-#define IRQ_LOCALTIMER 29
-#define IRQ_LOCALWDOG 30
-
-#define IRQ_GIC_START 32
-
-#ifndef NR_IRQS
-#error "NR_IRQS not defined by the board-specific files"
-#endif
-
-#endif
diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h
deleted file mode 100644
index 23e7a313f75d..000000000000
--- a/arch/arm/mach-realview/include/mach/memory.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * arch/arm/mach-realview/include/mach/memory.h
- *
- * Copyright (C) 2003 ARM Limited
- *
- * 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 __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#ifdef CONFIG_SPARSEMEM
-
-/*
- * Sparsemem definitions for RealView PBX.
- *
- * The RealView PBX board has another block of 512MB of RAM at 0x20000000,
- * however only the block at 0x70000000 (or the 256MB mirror at 0x00000000)
- * may be used for DMA.
- *
- * The macros below define a section size of 256MB and a non-linear virtual to
- * physical mapping:
- *
- * 256MB @ 0x00000000 -> PAGE_OFFSET
- * 512MB @ 0x20000000 -> PAGE_OFFSET + 0x10000000
- * 256MB @ 0x80000000 -> PAGE_OFFSET + 0x30000000
- */
-#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
-#error "SPARSEMEM not available with REALVIEW_HIGH_PHYS_OFFSET"
-#endif
-
-#define MAX_PHYSMEM_BITS 32
-#define SECTION_SIZE_BITS 28
-
-/* bank page offsets */
-#define PAGE_OFFSET1 (PAGE_OFFSET + 0x10000000)
-#define PAGE_OFFSET2 (PAGE_OFFSET + 0x30000000)
-
-#define PHYS_OFFSET PLAT_PHYS_OFFSET
-
-#define __phys_to_virt(phys) \
- ((phys) >= 0x80000000 ? (phys) - 0x80000000 + PAGE_OFFSET2 : \
- (phys) >= 0x20000000 ? (phys) - 0x20000000 + PAGE_OFFSET1 : \
- (phys) + PAGE_OFFSET)
-
-#define __virt_to_phys(virt) \
- ((virt) >= PAGE_OFFSET2 ? (virt) - PAGE_OFFSET2 + 0x80000000 : \
- (virt) >= PAGE_OFFSET1 ? (virt) - PAGE_OFFSET1 + 0x20000000 : \
- (virt) - PAGE_OFFSET)
-
-#endif /* CONFIG_SPARSEMEM */
-
-#endif
diff --git a/arch/arm/mach-realview/include/mach/uncompress.h b/arch/arm/mach-realview/include/mach/uncompress.h
deleted file mode 100644
index cfa30d21783b..000000000000
--- a/arch/arm/mach-realview/include/mach/uncompress.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * arch/arm/mach-realview/include/mach/uncompress.h
- *
- * Copyright (C) 2003 ARM Limited
- *
- * 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 <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <mach/board-eb.h>
-#include <mach/board-pb11mp.h>
-#include <mach/board-pb1176.h>
-#include <mach/board-pba8.h>
-#include <mach/board-pbx.h>
-
-#define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00))
-#define AMBA_UART_LCRH(base) (*(volatile unsigned char *)((base) + 0x2c))
-#define AMBA_UART_CR(base) (*(volatile unsigned char *)((base) + 0x30))
-#define AMBA_UART_FR(base) (*(volatile unsigned char *)((base) + 0x18))
-
-/*
- * Return the UART base address
- */
-static inline unsigned long get_uart_base(void)
-{
- if (machine_is_realview_eb())
- return REALVIEW_EB_UART0_BASE;
- else if (machine_is_realview_pb11mp())
- return REALVIEW_PB11MP_UART0_BASE;
- else if (machine_is_realview_pb1176())
- return REALVIEW_PB1176_UART0_BASE;
- else if (machine_is_realview_pba8())
- return REALVIEW_PBA8_UART0_BASE;
- else if (machine_is_realview_pbx())
- return REALVIEW_PBX_UART0_BASE;
- else
- return 0;
-}
-
-/*
- * This does not append a newline
- */
-static inline void putc(int c)
-{
- unsigned long base = get_uart_base();
-
- while (AMBA_UART_FR(base) & (1 << 5))
- barrier();
-
- AMBA_UART_DR(base) = c;
-}
-
-static inline void flush(void)
-{
- unsigned long base = get_uart_base();
-
- while (AMBA_UART_FR(base) & (1 << 3))
- barrier();
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
diff --git a/arch/arm/mach-realview/include/mach/irqs-eb.h b/arch/arm/mach-realview/irqs-eb.h
index 44754230fdcc..61e31680a749 100644
--- a/arch/arm/mach-realview/include/mach/irqs-eb.h
+++ b/arch/arm/mach-realview/irqs-eb.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/irqs-eb.h
- *
* Copyright (C) 2007 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +19,7 @@
#ifndef __MACH_IRQS_EB_H
#define __MACH_IRQS_EB_H
+#define IRQ_LOCALTIMER 29
#define IRQ_EB_GIC_START 32
/*
@@ -112,21 +111,4 @@
#define NR_GIC_EB11MP 2
-/*
- * Only define NR_IRQS if less than NR_IRQS_EB
- */
-#define NR_IRQS_EB (IRQ_EB_GIC_START + 128)
-
-#if defined(CONFIG_MACH_REALVIEW_EB) \
- && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
-#undef NR_IRQS
-#define NR_IRQS NR_IRQS_EB
-#endif
-
-#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_REALVIEW_EB_A9MP) \
- && (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
-#undef MAX_GIC_NR
-#define MAX_GIC_NR NR_GIC_EB11MP
-#endif
-
#endif /* __MACH_IRQS_EB_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb1176.h b/arch/arm/mach-realview/irqs-pb1176.h
index 708f84156f2c..778edfd430e7 100644
--- a/arch/arm/mach-realview/include/mach/irqs-pb1176.h
+++ b/arch/arm/mach-realview/irqs-pb1176.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/irqs-pb1176.h
- *
* Copyright (C) 2008 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -76,25 +74,4 @@
#define IRQ_PB1176_SCTL -1
-#define NR_GIC_PB1176 2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PB1176
- */
-#define NR_IRQS_PB1176 (IRQ_DC1176_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PB1176)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB1176)
-#undef NR_IRQS
-#define NR_IRQS NR_IRQS_PB1176
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB1176)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR NR_GIC_PB1176
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PB1176 */
-
#endif /* __MACH_IRQS_PB1176_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb11mp.h b/arch/arm/mach-realview/irqs-pb11mp.h
index 34e255add21e..938898a3df9f 100644
--- a/arch/arm/mach-realview/include/mach/irqs-pb11mp.h
+++ b/arch/arm/mach-realview/irqs-pb11mp.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/irqs-pb11mp.h
- *
* Copyright (C) 2008 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +19,7 @@
#ifndef __MACH_IRQS_PB11MP_H
#define __MACH_IRQS_PB11MP_H
+#define IRQ_LOCALTIMER 29
#define IRQ_TC11MP_GIC_START 32
#define IRQ_PB11MP_GIC_START 64
@@ -95,28 +94,4 @@
#define IRQ_PB11MP_TSPEN (IRQ_PB11MP_GIC_START + 30) /* Touchscreen pen */
#define IRQ_PB11MP_TSKPAD (IRQ_PB11MP_GIC_START + 31) /* Touchscreen keypad */
-#define IRQ_PB11MP_SMC -1
-#define IRQ_PB11MP_SCTL -1
-
-#define NR_GIC_PB11MP 2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PB11MP
- */
-#define NR_IRQS_PB11MP (IRQ_TC11MP_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PB11MP)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB11MP)
-#undef NR_IRQS
-#define NR_IRQS NR_IRQS_PB11MP
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB11MP)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR NR_GIC_PB11MP
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PB11MP */
-
#endif /* __MACH_IRQS_PB11MP_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pba8.h b/arch/arm/mach-realview/irqs-pba8.h
index 4a88a4edb651..262e321938b8 100644
--- a/arch/arm/mach-realview/include/mach/irqs-pba8.h
+++ b/arch/arm/mach-realview/irqs-pba8.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/irqs-pba8.h
- *
* Copyright (C) 2008 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -70,25 +68,4 @@
#define IRQ_PBA8_SMC -1
#define IRQ_PBA8_SCTL -1
-#define NR_GIC_PBA8 1
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PBA8
- */
-#define NR_IRQS_PBA8 (IRQ_PBA8_GIC_START + 64)
-
-#if defined(CONFIG_MACH_REALVIEW_PBA8)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBA8)
-#undef NR_IRQS
-#define NR_IRQS NR_IRQS_PBA8
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBA8)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR NR_GIC_PBA8
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PBA8 */
-
#endif /* __MACH_IRQS_PBA8_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pbx.h b/arch/arm/mach-realview/irqs-pbx.h
index 206a3001f46b..4ef0567dec32 100644
--- a/arch/arm/mach-realview/include/mach/irqs-pbx.h
+++ b/arch/arm/mach-realview/irqs-pbx.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/irqs-pbx.h
- *
* Copyright (C) 2009 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +18,7 @@
#ifndef __MACH_IRQS_PBX_H
#define __MACH_IRQS_PBX_H
+#define IRQ_LOCALTIMER 29
#define IRQ_PBX_GIC_START 32
/*
@@ -85,25 +84,4 @@
#define IRQ_PBX_SMC -1
#define IRQ_PBX_SCTL -1
-#define NR_GIC_PBX 1
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PBX
- */
-#define NR_IRQS_PBX (IRQ_PBX_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PBX)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBX)
-#undef NR_IRQS
-#define NR_IRQS NR_IRQS_PBX
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBX)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR NR_GIC_PBX
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PBX */
-
#endif /* __MACH_IRQS_PBX_H */
diff --git a/arch/arm/mach-realview/include/mach/platform.h b/arch/arm/mach-realview/platform.h
index 1b77a27badaf..11121739d371 100644
--- a/arch/arm/mach-realview/include/mach/platform.h
+++ b/arch/arm/mach-realview/platform.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-realview/include/mach/platform.h
- *
* Copyright (c) ARM Limited 2003. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/mach-realview/platsmp-dt.c b/arch/arm/mach-realview/platsmp-dt.c
new file mode 100644
index 000000000000..65585392655b
--- /dev/null
+++ b/arch/arm/mach-realview/platsmp-dt.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 Linus Walleij
+ *
+ * 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/smp.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include <plat/platsmp.h>
+
+#include "core.h"
+
+#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30
+
+static const struct of_device_id realview_scu_match[] = {
+ { .compatible = "arm,arm11mp-scu", },
+ { .compatible = "arm,cortex-a9-scu", },
+ { .compatible = "arm,cortex-a5-scu", },
+ { }
+};
+
+static const struct of_device_id realview_syscon_match[] = {
+ { .compatible = "arm,core-module-integrator", },
+ { .compatible = "arm,realview-eb-syscon", },
+ { .compatible = "arm,realview-pb11mp-syscon", },
+ { .compatible = "arm,realview-pbx-syscon", },
+ { },
+};
+
+static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *np;
+ void __iomem *scu_base;
+ struct regmap *map;
+ unsigned int ncores;
+ int i;
+
+ np = of_find_matching_node(NULL, realview_scu_match);
+ if (!np) {
+ pr_err("PLATSMP: No SCU base address\n");
+ return;
+ }
+ scu_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!scu_base) {
+ pr_err("PLATSMP: No SCU remap\n");
+ return;
+ }
+
+ scu_enable(scu_base);
+ ncores = scu_get_core_count(scu_base);
+ pr_info("SCU: %d cores detected\n", ncores);
+ for (i = 0; i < ncores; i++)
+ set_cpu_possible(i, true);
+ iounmap(scu_base);
+
+ /* The syscon contains the magic SMP start address registers */
+ np = of_find_matching_node(NULL, realview_syscon_match);
+ if (!np) {
+ pr_err("PLATSMP: No syscon match\n");
+ return;
+ }
+ map = syscon_node_to_regmap(np);
+ if (IS_ERR(map)) {
+ pr_err("PLATSMP: No syscon regmap\n");
+ return;
+ }
+ /* Put the boot address in this magic register */
+ regmap_write(map, REALVIEW_SYS_FLAGSSET_OFFSET,
+ virt_to_phys(versatile_secondary_startup));
+}
+
+struct smp_operations realview_dt_smp_ops __initdata = {
+ .smp_prepare_cpus = realview_smp_prepare_cpus,
+ .smp_secondary_init = versatile_secondary_init,
+ .smp_boot_secondary = versatile_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = realview_cpu_die,
+#endif
+};
+CPU_METHOD_OF_DECLARE(realview_smp, "arm,realview-smp", &realview_dt_smp_ops);
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 98e3052b7933..e8ab69c7abfb 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -13,13 +13,13 @@
#include <linux/smp.h>
#include <linux/io.h>
-#include <mach/hardware.h>
+#include "hardware.h"
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
-#include <mach/board-eb.h>
-#include <mach/board-pb11mp.h>
-#include <mach/board-pbx.h>
+#include "board-eb.h"
+#include "board-pb11mp.h"
+#include "board-pbx.h"
#include <plat/platsmp.h>
@@ -75,7 +75,7 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
__io_address(REALVIEW_SYS_FLAGSSET));
}
-struct smp_operations realview_smp_ops __initdata = {
+const struct smp_operations realview_smp_ops __initconst = {
.smp_init_cpus = realview_smp_init_cpus,
.smp_prepare_cpus = realview_smp_prepare_cpus,
.smp_secondary_init = versatile_secondary_init,
diff --git a/arch/arm/mach-realview/realview-dt.c b/arch/arm/mach-realview/realview-dt.c
index 382cc1b90519..88b67247945e 100644
--- a/arch/arm/mach-realview/realview-dt.c
+++ b/arch/arm/mach-realview/realview-dt.c
@@ -11,7 +11,6 @@
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
#include <asm/hardware/cache-l2x0.h>
-#include "core.h"
static const char *const realview_dt_platform_compat[] __initconst = {
"arm,realview-eb",
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index b3869cbbcc68..b442fa61e943 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -31,20 +31,21 @@
#include <linux/platform_data/clk-realview.h>
#include <linux/reboot.h>
-#include <mach/hardware.h>
+#include "hardware.h"
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/smp_twd.h>
#include <asm/system_info.h>
+#include <asm/outercache.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <mach/board-eb.h>
-#include <mach/irqs.h>
+#include "board-eb.h"
+#include "irqs-eb.h"
#include "core.h"
@@ -450,6 +451,12 @@ static void __init realview_eb_init(void)
* Bits: .... ...0 0111 1001 0000 .... .... ....
*/
l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff);
+
+ /*
+ * due to a bug in the l220 cache controller, we must not call
+ * the sync function. stub it out here instead!
+ */
+ outer_cache.sync = NULL;
#endif
pmu_device.name = core_tile_a9mp() ? "armv7-pmu" : "armv6-pmu";
platform_device_register(&pmu_device);
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index ce92c1823494..537f3878d501 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -34,7 +34,7 @@
#include <linux/reboot.h>
#include <linux/memblock.h>
-#include <mach/hardware.h>
+#include "hardware.h"
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
@@ -45,8 +45,8 @@
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <mach/board-pb1176.h>
-#include <mach/irqs.h>
+#include "board-pb1176.h"
+#include "irqs-pb1176.h"
#include "core.h"
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 15c45e25095f..a90a0752f157 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -31,7 +31,7 @@
#include <linux/platform_data/clk-realview.h>
#include <linux/reboot.h>
-#include <mach/hardware.h>
+#include "hardware.h"
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
@@ -42,9 +42,10 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
+#include <asm/outercache.h>
-#include <mach/board-pb11mp.h>
-#include <mach/irqs.h>
+#include "board-pb11mp.h"
+#include "irqs-pb11mp.h"
#include "core.h"
@@ -345,6 +346,11 @@ static void __init realview_pb11mp_init(void)
* Bits: .... ...0 0111 1001 0000 .... .... ....
*/
l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff);
+ /*
+ * due to a bug in the l220 cache controller, we must not call
+ * the sync function. stub it out here instead!
+ */
+ outer_cache.sync = NULL;
#endif
realview_flash_register(realview_pb11mp_flash_resource,
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 4c64662f5437..ddafb67c2b6f 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -39,9 +39,9 @@
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <mach/hardware.h>
-#include <mach/board-pba8.h>
-#include <mach/irqs.h>
+#include "hardware.h"
+#include "board-pba8.h"
+#include "irqs-pba8.h"
#include "core.h"
@@ -77,14 +77,6 @@ static struct map_desc realview_pba8_io_desc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE,
},
-#ifdef CONFIG_PCI
- {
- .virtual = PCIX_UNIT_BASE,
- .pfn = __phys_to_pfn(REALVIEW_PBA8_PCI_BASE),
- .length = REALVIEW_PBA8_PCI_BASE_SIZE,
- .type = MT_DEVICE
- },
-#endif
#ifdef CONFIG_DEBUG_LL
{
.virtual = IO_ADDRESS(REALVIEW_PBA8_UART0_BASE),
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 9a22b864219f..b9f0757787ac 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -41,9 +41,9 @@
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <mach/hardware.h>
-#include <mach/board-pbx.h>
-#include <mach/irqs.h>
+#include "hardware.h"
+#include "board-pbx.h"
+#include "irqs-pbx.h"
#include "core.h"
@@ -79,14 +79,6 @@ static struct map_desc realview_pbx_io_desc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE,
},
-#ifdef CONFIG_PCI
- {
- .virtual = PCIX_UNIT_BASE,
- .pfn = __phys_to_pfn(REALVIEW_PBX_PCI_BASE),
- .length = REALVIEW_PBX_PCI_BASE_SIZE,
- .type = MT_DEVICE,
- },
-#endif
#ifdef CONFIG_DEBUG_LL
{
.virtual = IO_ADDRESS(REALVIEW_PBX_UART0_BASE),
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index ae4eb7cc4bcc..cef42fd886d1 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -1,5 +1,6 @@
config ARCH_ROCKCHIP
- bool "Rockchip RK2928 and RK3xxx SOCs" if ARCH_MULTI_V7
+ bool "Rockchip RK2928 and RK3xxx SOCs"
+ depends on ARCH_MULTI_V7
select PINCTRL
select PINCTRL_ROCKCHIP
select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
index 3e7a4b761a95..d42a07e33482 100644
--- a/arch/arm/mach-rockchip/platsmp.c
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -42,6 +42,7 @@ static int ncores;
#define PMU_PWRDN_SCU 4
static struct regmap *pmu;
+static int has_pmu = true;
static int pmu_power_domain_is_on(int pd)
{
@@ -89,20 +90,23 @@ static int pmu_set_power_domain(int pd, bool on)
if (!IS_ERR(rstc) && !on)
reset_control_assert(rstc);
- ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val);
- if (ret < 0) {
- pr_err("%s: could not update power domain\n", __func__);
- return ret;
- }
-
- ret = -1;
- while (ret != on) {
- ret = pmu_power_domain_is_on(pd);
+ if (has_pmu) {
+ ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val);
if (ret < 0) {
- pr_err("%s: could not read power domain state\n",
+ pr_err("%s: could not update power domain\n",
__func__);
return ret;
}
+
+ ret = -1;
+ while (ret != on) {
+ ret = pmu_power_domain_is_on(pd);
+ if (ret < 0) {
+ pr_err("%s: could not read power domain state\n",
+ __func__);
+ return ret;
+ }
+ }
}
if (!IS_ERR(rstc)) {
@@ -122,7 +126,7 @@ static int rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
int ret;
- if (!sram_base_addr || !pmu) {
+ if (!sram_base_addr || (has_pmu && !pmu)) {
pr_err("%s: sram or pmu missing for cpu boot\n", __func__);
return -ENXIO;
}
@@ -275,7 +279,7 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
return;
}
- if (rockchip_smp_prepare_pmu())
+ if (has_pmu && rockchip_smp_prepare_pmu())
return;
if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
@@ -318,6 +322,13 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
pmu_set_power_domain(0 + i, false);
}
+static void __init rk3036_smp_prepare_cpus(unsigned int max_cpus)
+{
+ has_pmu = false;
+
+ rockchip_smp_prepare_cpus(max_cpus);
+}
+
#ifdef CONFIG_HOTPLUG_CPU
static int rockchip_cpu_kill(unsigned int cpu)
{
@@ -340,7 +351,16 @@ static void rockchip_cpu_die(unsigned int cpu)
}
#endif
-static struct smp_operations rockchip_smp_ops __initdata = {
+static const struct smp_operations rk3036_smp_ops __initconst = {
+ .smp_prepare_cpus = rk3036_smp_prepare_cpus,
+ .smp_boot_secondary = rockchip_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_kill = rockchip_cpu_kill,
+ .cpu_die = rockchip_cpu_die,
+#endif
+};
+
+static const struct smp_operations rockchip_smp_ops __initconst = {
.smp_prepare_cpus = rockchip_smp_prepare_cpus,
.smp_boot_secondary = rockchip_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
@@ -349,4 +369,5 @@ static struct smp_operations rockchip_smp_ops __initdata = {
#endif
};
+CPU_METHOD_OF_DECLARE(rk3036_smp, "rockchip,rk3036-smp", &rk3036_smp_ops);
CPU_METHOD_OF_DECLARE(rk3066_smp, "rockchip,rk3066-smp", &rockchip_smp_ops);
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index 251c7b9c5f9b..3f07cc5dfe5f 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -82,6 +82,7 @@ static const char * const rockchip_board_dt_compat[] = {
"rockchip,rk3066a",
"rockchip,rk3066b",
"rockchip,rk3188",
+ "rockchip,rk3228",
"rockchip,rk3288",
NULL,
};
diff --git a/arch/arm/mach-s3c24xx/include/mach/pm-core.h b/arch/arm/mach-s3c24xx/include/mach/pm-core.h
index 69459dbbdcad..712333fec589 100644
--- a/arch/arm/mach-s3c24xx/include/mach/pm-core.h
+++ b/arch/arm/mach-s3c24xx/include/mach/pm-core.h
@@ -85,3 +85,17 @@ static inline void s3c_pm_arch_update_uart(void __iomem *regs,
static inline void s3c_pm_restored_gpios(void) { }
static inline void samsung_pm_saved_gpios(void) { }
+
+/* state for IRQs over sleep */
+
+/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
+ *
+ * set bit to 1 in allow bitfield to enable the wakeup settings on it
+*/
+#ifdef CONFIG_PM_SLEEP
+#define s3c_irqwake_intallow (1L << 30 | 0xfL)
+#define s3c_irqwake_eintallow (0x0000fff0L)
+#else
+#define s3c_irqwake_eintallow 0
+#define s3c_irqwake_intallow 0
+#endif
diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c
index b91341ef2b2e..417b7a20c2d1 100644
--- a/arch/arm/mach-s3c24xx/irq-pm.c
+++ b/arch/arm/mach-s3c24xx/irq-pm.c
@@ -25,19 +25,10 @@
#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>
+#include <mach/pm-core.h>
#include <asm/irq.h>
-/* state for IRQs over sleep */
-
-/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
- *
- * set bit to 1 in allow bitfield to enable the wakeup settings on it
-*/
-
-unsigned long s3c_irqwake_intallow = 1L << 30 | 0xfL;
-unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
-
int s3c_irq_wake(struct irq_data *data, unsigned int state)
{
unsigned long irqbit = 1 << data->hwirq;
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 28c7097e8506..7c0c420c3016 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -2,6 +2,26 @@
# Simtec Electronics, Ben Dooks <ben@simtec.co.uk>
#
# Licensed under GPLv2
+menuconfig ARCH_S3C64XX
+ bool "Samsung S3C64XX" if ARCH_MULTI_V6
+ select ARCH_REQUIRE_GPIOLIB
+ select ARM_AMBA
+ select ARM_VIC
+ select CLKSRC_SAMSUNG_PWM
+ select COMMON_CLK_SAMSUNG
+ select GPIO_SAMSUNG if ATAGS
+ select HAVE_S3C2410_I2C if I2C
+ select HAVE_S3C2410_WATCHDOG if WATCHDOG
+ select HAVE_TCM
+ select PLAT_SAMSUNG
+ select PM_GENERIC_DOMAINS if PM
+ select S3C_DEV_NAND if ATAGS
+ select S3C_GPIO_TRACK if ATAGS
+ select SAMSUNG_ATAGS if ATAGS
+ select SAMSUNG_WAKEMASK if PM
+ select SAMSUNG_WDT_RESET
+ help
+ Samsung S3C64XX series based systems
if ARCH_S3C64XX
@@ -90,6 +110,7 @@ config S3C64XX_SETUP_USB_PHY
config MACH_SMDK6400
bool "SMDK6400"
+ depends on ATAGS
select CPU_S3C6400
select S3C64XX_SETUP_SDHCI
select S3C_DEV_HSMMC1
@@ -100,6 +121,7 @@ config MACH_SMDK6400
config MACH_ANW6410
bool "A&W6410"
+ depends on ATAGS
select CPU_S3C6410
select S3C64XX_SETUP_FB_24BPP
select S3C_DEV_FB
@@ -108,6 +130,7 @@ config MACH_ANW6410
config MACH_MINI6410
bool "MINI6410"
+ depends on ATAGS
select CPU_S3C6410
select S3C64XX_SETUP_FB_24BPP
select S3C64XX_SETUP_SDHCI
@@ -123,6 +146,7 @@ config MACH_MINI6410
config MACH_REAL6410
bool "REAL6410"
+ depends on ATAGS
select CPU_S3C6410
select S3C64XX_SETUP_FB_24BPP
select S3C64XX_SETUP_SDHCI
@@ -138,6 +162,7 @@ config MACH_REAL6410
config MACH_SMDK6410
bool "SMDK6410"
+ depends on ATAGS
select CPU_S3C6410
select HAVE_S3C2410_WATCHDOG if WATCHDOG
select S3C64XX_SETUP_FB_24BPP
@@ -225,6 +250,7 @@ config SMDK6410_WM1192_EV1
config MACH_NCP
bool "NCP"
+ depends on ATAGS
select CPU_S3C6410
select S3C64XX_SETUP_I2C1
select S3C_DEV_HSMMC1
@@ -234,6 +260,7 @@ config MACH_NCP
config MACH_HMT
bool "Airgoo HMT"
+ depends on ATAGS
select CPU_S3C6410
select S3C64XX_SETUP_FB_24BPP
select S3C_DEV_FB
@@ -265,18 +292,21 @@ config MACH_SMARTQ
config MACH_SMARTQ5
bool "SmartQ 5"
+ depends on ATAGS
select MACH_SMARTQ
help
Machine support for the SmartQ 5
config MACH_SMARTQ7
bool "SmartQ 7"
+ depends on ATAGS
select MACH_SMARTQ
help
Machine support for the SmartQ 7
config MACH_WLF_CRAGG_6410
bool "Wolfson Cragganmore 6410"
+ depends on ATAGS
depends on I2C=y
select CPU_S3C6410
select LEDS_GPIO_REGISTER
@@ -310,7 +340,6 @@ config MACH_S3C64XX_DT
select CPU_S3C6410
select PINCTRL
select PINCTRL_S3C64XX
- select USE_OF
help
Machine support for Samsung S3C6400/S3C6410 machines with Device Tree
enabled.
diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile
index bb233f342f31..256cd5b40c60 100644
--- a/arch/arm/mach-s3c64xx/Makefile
+++ b/arch/arm/mach-s3c64xx/Makefile
@@ -5,21 +5,25 @@
#
# Licensed under GPLv2
-# Core
-
-obj-y += common.o
-
-# Core support
-
-obj-$(CONFIG_CPU_S3C6400) += s3c6400.o
-obj-$(CONFIG_CPU_S3C6410) += s3c6410.o
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include -I$(srctree)/arch/arm/plat-samsung/include
+asflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include -I$(srctree)/arch/arm/plat-samsung/include
# PM
obj-$(CONFIG_PM) += pm.o
-obj-$(CONFIG_PM_SLEEP) += irq-pm.o sleep.o
+obj-$(CONFIG_PM_SLEEP) += sleep.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+ifdef CONFIG_SAMSUNG_ATAGS
+
+obj-$(CONFIG_PM_SLEEP) += irq-pm.o
+
+# Core
+
+obj-y += common.o
+obj-$(CONFIG_CPU_S3C6400) += s3c6400.o
+obj-$(CONFIG_CPU_S3C6410) += s3c6410.o
+
# DMA support
obj-$(CONFIG_S3C64XX_PL080) += pl080.o
@@ -55,4 +59,6 @@ obj-$(CONFIG_MACH_SMARTQ7) += mach-smartq7.o
obj-$(CONFIG_MACH_SMDK6400) += mach-smdk6400.o
obj-$(CONFIG_MACH_SMDK6410) += mach-smdk6410.o
obj-$(CONFIG_MACH_WLF_CRAGG_6410) += mach-crag6410.o mach-crag6410-module.o
+endif
+
obj-$(CONFIG_MACH_S3C64XX_DT) += mach-s3c64xx-dt.o
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index ddb30b8434c5..7c66ce1a6bb6 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -39,6 +39,7 @@
#include <asm/system_misc.h>
#include <mach/map.h>
+#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
@@ -208,7 +209,7 @@ void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
static __init int s3c64xx_dev_init(void)
{
/* Not applicable when using DT. */
- if (of_have_populated_dt())
+ if (of_have_populated_dt() || !soc_is_s3c64xx())
return 0;
subsys_system_register(&s3c64xx_subsys, NULL);
@@ -413,7 +414,7 @@ static int __init s3c64xx_init_irq_eint(void)
int irq;
/* On DT-enabled systems EINTs are handled by pinctrl-s3c64xx driver. */
- if (of_have_populated_dt())
+ if (of_have_populated_dt() || !soc_is_s3c64xx())
return -ENODEV;
for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
index 93aa8cb70195..5322db51150e 100644
--- a/arch/arm/mach-s3c64xx/cpuidle.c
+++ b/arch/arm/mach-s3c64xx/cpuidle.c
@@ -18,6 +18,7 @@
#include <asm/cpuidle.h>
+#include <plat/cpu.h>
#include <mach/map.h>
#include "regs-sys.h"
@@ -57,6 +58,8 @@ static struct cpuidle_driver s3c64xx_cpuidle_driver = {
static int __init s3c64xx_init_cpuidle(void)
{
- return cpuidle_register(&s3c64xx_cpuidle_driver, NULL);
+ if (soc_is_s3c64xx())
+ return cpuidle_register(&s3c64xx_cpuidle_driver, NULL);
+ return 0;
}
device_initcall(s3c64xx_init_cpuidle);
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index ff780a8d8366..b57783371d52 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -54,12 +54,13 @@ static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
static struct resource s3c64xx_iis0_resource[] = {
[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
- [2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
};
-static struct s3c_audio_pdata i2sv3_pdata = {
+static struct s3c_audio_pdata i2s0_pdata = {
.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+ .dma_filter = pl08x_filter_id,
+ .dma_playback = DMACH_I2S0_OUT,
+ .dma_capture = DMACH_I2S0_IN,
};
struct platform_device s3c64xx_device_iis0 = {
@@ -68,15 +69,20 @@ struct platform_device s3c64xx_device_iis0 = {
.num_resources = ARRAY_SIZE(s3c64xx_iis0_resource),
.resource = s3c64xx_iis0_resource,
.dev = {
- .platform_data = &i2sv3_pdata,
+ .platform_data = &i2s0_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iis0);
static struct resource s3c64xx_iis1_resource[] = {
[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
- [2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
+};
+
+static struct s3c_audio_pdata i2s1_pdata = {
+ .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+ .dma_filter = pl08x_filter_id,
+ .dma_playback = DMACH_I2S1_OUT,
+ .dma_capture = DMACH_I2S1_IN,
};
struct platform_device s3c64xx_device_iis1 = {
@@ -85,19 +91,20 @@ struct platform_device s3c64xx_device_iis1 = {
.num_resources = ARRAY_SIZE(s3c64xx_iis1_resource),
.resource = s3c64xx_iis1_resource,
.dev = {
- .platform_data = &i2sv3_pdata,
+ .platform_data = &i2s1_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iis1);
static struct resource s3c64xx_iisv4_resource[] = {
[0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
- [2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
};
static struct s3c_audio_pdata i2sv4_pdata = {
.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+ .dma_filter = pl08x_filter_id,
+ .dma_playback = DMACH_HSI_I2SV40_TX,
+ .dma_capture = DMACH_HSI_I2SV40_RX,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN,
@@ -142,12 +149,13 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
static struct resource s3c64xx_pcm0_resource[] = {
[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
- [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
static struct s3c_audio_pdata s3c_pcm0_pdata = {
.cfg_gpio = s3c64xx_pcm_cfg_gpio,
+ .dma_filter = pl08x_filter_id,
+ .dma_capture = DMACH_PCM0_RX,
+ .dma_playback = DMACH_PCM0_TX,
};
struct platform_device s3c64xx_device_pcm0 = {
@@ -163,12 +171,13 @@ EXPORT_SYMBOL(s3c64xx_device_pcm0);
static struct resource s3c64xx_pcm1_resource[] = {
[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
- [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
};
static struct s3c_audio_pdata s3c_pcm1_pdata = {
.cfg_gpio = s3c64xx_pcm_cfg_gpio,
+ .dma_filter = pl08x_filter_id,
+ .dma_playback = DMACH_PCM1_TX,
+ .dma_capture = DMACH_PCM1_RX,
};
struct platform_device s3c64xx_device_pcm1 = {
@@ -196,13 +205,15 @@ static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev)
static struct resource s3c64xx_ac97_resource[] = {
[0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
- [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
- [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
- [4] = DEFINE_RES_IRQ(IRQ_AC97),
+ [1] = DEFINE_RES_IRQ(IRQ_AC97),
};
-static struct s3c_audio_pdata s3c_ac97_pdata;
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+ .dma_playback = DMACH_AC97_PCMOUT,
+ .dma_filter = pl08x_filter_id,
+ .dma_capture = DMACH_AC97_PCMIN,
+ .dma_capture_mic = DMACH_AC97_MICIN,
+};
static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-s3c64xx/dev-uart.c b/arch/arm/mach-s3c64xx/dev-uart.c
index 46e18d77ea93..a0b4f0329811 100644
--- a/arch/arm/mach-s3c64xx/dev-uart.c
+++ b/arch/arm/mach-s3c64xx/dev-uart.c
@@ -23,6 +23,7 @@
#include <asm/mach/irq.h>
#include <mach/hardware.h>
#include <mach/map.h>
+#include <mach/irqs.h>
#include <plat/devs.h>
diff --git a/arch/arm/mach-s3c64xx/include/mach/debug-macro.S b/arch/arm/mach-s3c64xx/include/mach/debug-macro.S
deleted file mode 100644
index c9b95325b672..000000000000
--- a/arch/arm/mach-s3c64xx/include/mach/debug-macro.S
+++ /dev/null
@@ -1,38 +0,0 @@
-/* arch/arm/mach-s3c6400/include/mach/debug-macro.S
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
-*/
-
-/* pull in the relevant register and map files. */
-
-#include <linux/serial_s3c.h>
-#include <mach/map.h>
-
- /* note, for the boot process to work we have to keep the UART
- * virtual address aligned to an 1MiB boundary for the L1
- * mapping the head code makes. We keep the UART virtual address
- * aligned and add in the offset when we load the value here.
- */
-
- .macro addruart, rp, rv, tmp
- ldr \rp, = S3C_PA_UART
- ldr \rv, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
-#if CONFIG_DEBUG_S3C_UART != 0
- add \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
- add \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
-#endif
- .endm
-
-/* include the reset of the code which will do the work, we're only
- * compiling for a single cpu processor type so the default of s3c2440
- * will be fine with us.
- */
-
-#include <debug/samsung.S>
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h
index 096e14073bd9..9c739eafe95c 100644
--- a/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -14,38 +14,38 @@
#define S3C64XX_DMA_CHAN(name) ((unsigned long)(name))
/* DMA0/SDMA0 */
-#define DMACH_UART0 S3C64XX_DMA_CHAN("uart0_tx")
-#define DMACH_UART0_SRC2 S3C64XX_DMA_CHAN("uart0_rx")
-#define DMACH_UART1 S3C64XX_DMA_CHAN("uart1_tx")
-#define DMACH_UART1_SRC2 S3C64XX_DMA_CHAN("uart1_rx")
-#define DMACH_UART2 S3C64XX_DMA_CHAN("uart2_tx")
-#define DMACH_UART2_SRC2 S3C64XX_DMA_CHAN("uart2_rx")
-#define DMACH_UART3 S3C64XX_DMA_CHAN("uart3_tx")
-#define DMACH_UART3_SRC2 S3C64XX_DMA_CHAN("uart3_rx")
-#define DMACH_PCM0_TX S3C64XX_DMA_CHAN("pcm0_tx")
-#define DMACH_PCM0_RX S3C64XX_DMA_CHAN("pcm0_rx")
-#define DMACH_I2S0_OUT S3C64XX_DMA_CHAN("i2s0_tx")
-#define DMACH_I2S0_IN S3C64XX_DMA_CHAN("i2s0_rx")
+#define DMACH_UART0 "uart0_tx"
+#define DMACH_UART0_SRC2 "uart0_rx"
+#define DMACH_UART1 "uart1_tx"
+#define DMACH_UART1_SRC2 "uart1_rx"
+#define DMACH_UART2 "uart2_tx"
+#define DMACH_UART2_SRC2 "uart2_rx"
+#define DMACH_UART3 "uart3_tx"
+#define DMACH_UART3_SRC2 "uart3_rx"
+#define DMACH_PCM0_TX "pcm0_tx"
+#define DMACH_PCM0_RX "pcm0_rx"
+#define DMACH_I2S0_OUT "i2s0_tx"
+#define DMACH_I2S0_IN "i2s0_rx"
#define DMACH_SPI0_TX S3C64XX_DMA_CHAN("spi0_tx")
#define DMACH_SPI0_RX S3C64XX_DMA_CHAN("spi0_rx")
-#define DMACH_HSI_I2SV40_TX S3C64XX_DMA_CHAN("i2s2_tx")
-#define DMACH_HSI_I2SV40_RX S3C64XX_DMA_CHAN("i2s2_rx")
+#define DMACH_HSI_I2SV40_TX "i2s2_tx"
+#define DMACH_HSI_I2SV40_RX "i2s2_rx"
/* DMA1/SDMA1 */
-#define DMACH_PCM1_TX S3C64XX_DMA_CHAN("pcm1_tx")
-#define DMACH_PCM1_RX S3C64XX_DMA_CHAN("pcm1_rx")
-#define DMACH_I2S1_OUT S3C64XX_DMA_CHAN("i2s1_tx")
-#define DMACH_I2S1_IN S3C64XX_DMA_CHAN("i2s1_rx")
+#define DMACH_PCM1_TX "pcm1_tx"
+#define DMACH_PCM1_RX "pcm1_rx"
+#define DMACH_I2S1_OUT "i2s1_tx"
+#define DMACH_I2S1_IN "i2s1_rx"
#define DMACH_SPI1_TX S3C64XX_DMA_CHAN("spi1_tx")
#define DMACH_SPI1_RX S3C64XX_DMA_CHAN("spi1_rx")
-#define DMACH_AC97_PCMOUT S3C64XX_DMA_CHAN("ac97_out")
-#define DMACH_AC97_PCMIN S3C64XX_DMA_CHAN("ac97_in")
-#define DMACH_AC97_MICIN S3C64XX_DMA_CHAN("ac97_mic")
-#define DMACH_PWM S3C64XX_DMA_CHAN("pwm")
-#define DMACH_IRDA S3C64XX_DMA_CHAN("irda")
-#define DMACH_EXTERNAL S3C64XX_DMA_CHAN("external")
-#define DMACH_SECURITY_RX S3C64XX_DMA_CHAN("sec_rx")
-#define DMACH_SECURITY_TX S3C64XX_DMA_CHAN("sec_tx")
+#define DMACH_AC97_PCMOUT "ac97_out"
+#define DMACH_AC97_PCMIN "ac97_in"
+#define DMACH_AC97_MICIN "ac97_mic"
+#define DMACH_PWM "pwm"
+#define DMACH_IRDA "irda"
+#define DMACH_EXTERNAL "external"
+#define DMACH_SECURITY_RX "sec_rx"
+#define DMACH_SECURITY_TX "sec_tx"
enum dma_ch {
DMACH_MAX = 32
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-samsung.h b/arch/arm/mach-s3c64xx/include/mach/gpio-samsung.h
index 9c81fac3b2d5..1d3636512e33 100644
--- a/arch/arm/mach-s3c64xx/include/mach/gpio-samsung.h
+++ b/arch/arm/mach-s3c64xx/include/mach/gpio-samsung.h
@@ -14,6 +14,8 @@
#ifndef GPIO_SAMSUNG_S3C64XX_H
#define GPIO_SAMSUNG_S3C64XX_H
+#ifdef CONFIG_GPIO_SAMSUNG
+
/* GPIO bank sizes */
#define S3C64XX_GPIO_A_NR (8)
#define S3C64XX_GPIO_B_NR (7)
@@ -90,5 +92,6 @@ enum s3c_gpio_number {
/* define the number of gpios we need to the one after the GPQ() range */
#define GPIO_BOARD_START (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1)
+#endif /* GPIO_SAMSUNG */
#endif /* GPIO_SAMSUNG_S3C64XX_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/irqs.h b/arch/arm/mach-s3c64xx/include/mach/irqs.h
index 67bbd1dd04c2..3ceb00b5de07 100644
--- a/arch/arm/mach-s3c64xx/include/mach/irqs.h
+++ b/arch/arm/mach-s3c64xx/include/mach/irqs.h
@@ -156,25 +156,11 @@
#define IRQ_EINT_GROUP(group, no) (IRQ_EINT_GROUP##group##_BASE + (no))
-/* Define a group of interrupts for board-specific use (eg, for MFD
- * interrupt controllers). */
+/* Some boards have their own IRQs behind this */
#define IRQ_BOARD_START (IRQ_EINT_GROUP9_BASE + IRQ_EINT_GROUP9_NR + 1)
-#ifdef CONFIG_MACH_WLF_CRAGG_6410
-#define IRQ_BOARD_NR 160
-#elif defined(CONFIG_SMDK6410_WM1190_EV1)
-#define IRQ_BOARD_NR 64
-#elif defined(CONFIG_SMDK6410_WM1192_EV1)
-#define IRQ_BOARD_NR 64
-#else
-#define IRQ_BOARD_NR 16
-#endif
-
-#define IRQ_BOARD_END (IRQ_BOARD_START + IRQ_BOARD_NR)
-
-/* Set the default NR_IRQS */
-
-#define NR_IRQS (IRQ_BOARD_END + 1)
+/* Set the default nr_irqs, boards can override if necessary */
+#define S3C64XX_NR_IRQS IRQ_BOARD_START
/* Compatibility */
diff --git a/arch/arm/mach-s3c64xx/include/mach/pm-core.h b/arch/arm/mach-s3c64xx/include/mach/pm-core.h
index a30a1e3ffc6a..4a285e97afff 100644
--- a/arch/arm/mach-s3c64xx/include/mach/pm-core.h
+++ b/arch/arm/mach-s3c64xx/include/mach/pm-core.h
@@ -16,8 +16,11 @@
#define __MACH_S3C64XX_PM_CORE_H __FILE__
#include <linux/serial_s3c.h>
+#include <linux/delay.h>
#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <mach/map.h>
static inline void s3c_pm_debug_init_uart(void)
{
@@ -56,9 +59,13 @@ static inline void s3c_pm_arch_show_resume_irqs(void)
/* make these defines, we currently do not have any need to change
* the IRQ wake controls depending on the CPU we are running on */
-
+#ifdef CONFIG_PM_SLEEP
#define s3c_irqwake_eintallow ((1 << 28) - 1)
#define s3c_irqwake_intallow (~0)
+#else
+#define s3c_irqwake_eintallow 0
+#define s3c_irqwake_intallow 0
+#endif
static inline void s3c_pm_arch_update_uart(void __iomem *regs,
struct pm_uart_save *save)
diff --git a/arch/arm/mach-s3c64xx/irq-pm.c b/arch/arm/mach-s3c64xx/irq-pm.c
index ae4ea7601f60..0bbf1faaee42 100644
--- a/arch/arm/mach-s3c64xx/irq-pm.c
+++ b/arch/arm/mach-s3c64xx/irq-pm.c
@@ -113,7 +113,7 @@ static struct syscore_ops s3c64xx_irq_syscore_ops = {
static __init int s3c64xx_syscore_init(void)
{
/* Appropriate drivers (pinctrl, uart) handle this when using DT. */
- if (of_have_populated_dt())
+ if (of_have_populated_dt() || !soc_is_s3c64xx())
return 0;
register_syscore_ops(&s3c64xx_irq_syscore_ops);
diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
index 6224c67f5061..347ce6009a8c 100644
--- a/arch/arm/mach-s3c64xx/mach-anw6410.c
+++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
@@ -47,6 +47,7 @@
#include <plat/devs.h>
#include <plat/cpu.h>
+#include <mach/irqs.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
#include <plat/samsung-time.h>
@@ -229,7 +230,7 @@ static void __init anw6410_machine_init(void)
MACHINE_START(ANW6410, "A&W6410")
/* Maintainer: Kwangwoo Lee <kwangwoo.lee@gmail.com> */
.atag_offset = 0x100,
-
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = anw6410_map_io,
.init_machine = anw6410_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index 9c00d83f7151..571f95cc5a53 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -29,6 +29,9 @@
#include <linux/platform_data/spi-s3c64xx.h>
+#include <plat/cpu.h>
+#include <mach/irqs.h>
+
#include "crag6410.h"
static struct s3c64xx_spi_csinfo wm0010_spi_csinfo = {
@@ -399,6 +402,9 @@ static struct i2c_driver wlf_gf_module_driver = {
static int __init wlf_gf_module_register(void)
{
+ if (!soc_is_s3c64xx())
+ return 0;
+
return i2c_add_driver(&wlf_gf_module_driver);
}
device_initcall(wlf_gf_module_register);
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index f776adcdaee8..d9d0440aed78 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -29,7 +29,7 @@
#include <linux/pwm_backlight.h>
#include <linux/dm9000.h>
#include <linux/gpio_keys.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/pca953x.h>
@@ -52,6 +52,7 @@
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
+#include <mach/irqs.h>
#include <plat/fb.h>
#include <plat/sdhci.h>
@@ -860,6 +861,7 @@ static void __init crag6410_machine_init(void)
MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410")
/* Maintainer: Mark Brown <broonie@opensource.wolfsonmicro.com> */
.atag_offset = 0x100,
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = crag6410_map_io,
.init_machine = crag6410_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index 816b39d1e6d1..bc7dc1fcbf7d 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -31,6 +31,7 @@
#include <video/samsung_fimd.h>
#include <mach/hardware.h>
#include <mach/map.h>
+#include <mach/irqs.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -279,6 +280,7 @@ static void __init hmt_machine_init(void)
MACHINE_START(HMT, "Airgoo-HMT")
/* Maintainer: Peter Korsgaard <jacmet@sunsite.dk> */
.atag_offset = 0x100,
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = hmt_map_io,
.init_machine = hmt_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index ab61af50bfb9..ae999fb3fe6d 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -41,6 +41,7 @@
#include <linux/platform_data/mmc-sdhci-s3c.h>
#include <plat/sdhci.h>
#include <linux/platform_data/touchscreen-s3c2410.h>
+#include <mach/irqs.h>
#include <video/platform_lcd.h>
#include <video/samsung_fimd.h>
@@ -233,7 +234,6 @@ static struct platform_device *mini6410_devices[] __initdata = {
&s3c_device_fb,
&mini6410_lcd_powerdev,
&s3c_device_adc,
- &s3c_device_ts,
};
static void __init mini6410_map_io(void)
@@ -332,7 +332,7 @@ static void __init mini6410_machine_init(void)
s3c_nand_set_platdata(&mini6410_nand_info);
s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]);
s3c_sdhci1_set_platdata(&mini6410_hsmmc1_pdata);
- s3c24xx_ts_set_platdata(NULL);
+ s3c64xx_ts_set_platdata(NULL);
/* configure nCS1 width to 16 bits */
@@ -363,6 +363,7 @@ static void __init mini6410_machine_init(void)
MACHINE_START(MINI6410, "MINI6410")
/* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
.atag_offset = 0x100,
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = mini6410_map_io,
.init_machine = mini6410_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c
index 80cb1446f69f..23baaa04318c 100644
--- a/arch/arm/mach-s3c64xx/mach-ncp.c
+++ b/arch/arm/mach-s3c64xx/mach-ncp.c
@@ -31,6 +31,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/map.h>
@@ -100,6 +101,7 @@ static void __init ncp_machine_init(void)
MACHINE_START(NCP, "NCP")
/* Maintainer: Samsung Electronics */
.atag_offset = 0x100,
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = ncp_map_io,
.init_machine = ncp_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 85fa9598b980..4e240ffa7ac7 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -33,6 +33,7 @@
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
+#include <mach/irqs.h>
#include <plat/adc.h>
#include <plat/cpu.h>
@@ -202,7 +203,6 @@ static struct platform_device *real6410_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_nand,
&s3c_device_adc,
- &s3c_device_ts,
&s3c_device_ohci,
};
@@ -301,7 +301,7 @@ static void __init real6410_machine_init(void)
s3c_fb_set_platdata(&real6410_lcd_pdata[features.lcd_index]);
s3c_nand_set_platdata(&real6410_nand_info);
- s3c24xx_ts_set_platdata(NULL);
+ s3c64xx_ts_set_platdata(NULL);
/* configure nCS1 width to 16 bits */
@@ -331,7 +331,7 @@ static void __init real6410_machine_init(void)
MACHINE_START(REAL6410, "REAL6410")
/* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
.atag_offset = 0x100,
-
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = real6410_map_io,
.init_machine = real6410_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index acdfb5fac40f..936a63fc68d5 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
@@ -252,7 +253,6 @@ static struct platform_device *smartq_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_rtc,
&samsung_device_pwm,
- &s3c_device_ts,
&s3c_device_usb_hsotg,
&s3c64xx_device_iis0,
&smartq_backlight_device,
@@ -383,6 +383,15 @@ void __init smartq_map_io(void)
smartq_lcd_mode_set();
}
+static struct gpiod_lookup_table smartq_audio_gpios = {
+ .dev_id = "smartq-audio",
+ .table = {
+ GPIO_LOOKUP("GPL", 12, "headphone detect", 0),
+ GPIO_LOOKUP("GPK", 12, "amplifiers shutdown", 0),
+ { },
+ },
+};
+
void __init smartq_machine_init(void)
{
s3c_i2c0_set_platdata(NULL);
@@ -390,7 +399,7 @@ void __init smartq_machine_init(void)
s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
- s3c24xx_ts_set_platdata(&smartq_touchscreen_pdata);
+ s3c64xx_ts_set_platdata(&smartq_touchscreen_pdata);
i2c_register_board_info(0, smartq_i2c_devs,
ARRAY_SIZE(smartq_i2c_devs));
@@ -402,4 +411,7 @@ void __init smartq_machine_init(void)
pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
+
+ gpiod_add_lookup_table(&smartq_audio_gpios);
+ platform_device_register_simple("smartq-audio", -1, NULL, 0);
}
diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c
index 33224ab36fac..0972b6ce0ef6 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq5.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq5.c
@@ -21,6 +21,7 @@
#include <asm/mach/arch.h>
#include <video/samsung_fimd.h>
+#include <mach/irqs.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
@@ -153,6 +154,7 @@ static void __init smartq5_machine_init(void)
MACHINE_START(SMARTQ5, "SmartQ 5")
/* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
.atag_offset = 0x100,
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = smartq_map_io,
.init_machine = smartq5_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c
index fc7fece22fb0..51ac1c6c654a 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq7.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq7.c
@@ -21,6 +21,7 @@
#include <asm/mach/arch.h>
#include <video/samsung_fimd.h>
+#include <mach/irqs.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
@@ -169,6 +170,7 @@ static void __init smartq7_machine_init(void)
MACHINE_START(SMARTQ7, "SmartQ 7")
/* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
.atag_offset = 0x100,
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = smartq_map_io,
.init_machine = smartq7_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6400.c b/arch/arm/mach-s3c64xx/mach-smdk6400.c
index 6f425126a735..7d8a74fd8915 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6400.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6400.c
@@ -27,6 +27,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/map.h>
@@ -88,7 +89,7 @@ static void __init smdk6400_machine_init(void)
MACHINE_START(SMDK6400, "SMDK6400")
/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
.atag_offset = 0x100,
-
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6400_init_irq,
.map_io = smdk6400_map_io,
.init_machine = smdk6400_machine_init,
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index 30fd27853072..8a894ee3ee76 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -52,6 +52,7 @@
#include <asm/mach/irq.h>
#include <mach/hardware.h>
+#include <mach/irqs.h>
#include <mach/map.h>
#include <asm/irq.h>
@@ -289,7 +290,6 @@ static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_adc,
&s3c_device_cfcon,
&s3c_device_rtc,
- &s3c_device_ts,
&s3c_device_wdt,
};
@@ -668,7 +668,7 @@ static void __init smdk6410_machine_init(void)
samsung_keypad_set_platdata(&smdk6410_keypad_data);
- s3c24xx_ts_set_platdata(NULL);
+ s3c64xx_ts_set_platdata(NULL);
/* configure nCS1 width to 16 bits */
@@ -707,7 +707,7 @@ static void __init smdk6410_machine_init(void)
MACHINE_START(SMDK6410, "SMDK6410")
/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
.atag_offset = 0x100,
-
+ .nr_irqs = S3C64XX_NR_IRQS,
.init_irq = s3c6410_init_irq,
.map_io = smdk6410_map_io,
.init_machine = smdk6410_machine_init,
diff --git a/arch/arm/mach-s3c64xx/pl080.c b/arch/arm/mach-s3c64xx/pl080.c
index 901a984bddc2..89c5a62830a7 100644
--- a/arch/arm/mach-s3c64xx/pl080.c
+++ b/arch/arm/mach-s3c64xx/pl080.c
@@ -14,6 +14,7 @@
#include <linux/amba/pl08x.h>
#include <linux/of.h>
+#include <plat/cpu.h>
#include <mach/irqs.h>
#include <mach/map.h>
@@ -230,6 +231,9 @@ static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0,
static int __init s3c64xx_pl080_init(void)
{
+ if (!soc_is_s3c64xx())
+ return 0;
+
/* Set all DMA configuration to be DMA, not SDMA */
writel(0xffffff, S3C64XX_SDMA_SEL);
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index 75b14e756383..59d91b83b03d 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -22,6 +22,7 @@
#include <mach/map.h>
#include <mach/irqs.h>
+#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/pm.h>
#include <plat/wakeup-mask.h>
@@ -332,6 +333,9 @@ int __init s3c64xx_pm_init(void)
static __init int s3c64xx_pm_initcall(void)
{
+ if (!soc_is_s3c64xx())
+ return 0;
+
pm_cpu_prep = s3c64xx_pm_prepare;
pm_cpu_sleep = s3c64xx_cpu_suspend;
diff --git a/arch/arm/mach-s3c64xx/s3c6400.c b/arch/arm/mach-s3c64xx/s3c6400.c
index 33273abef669..5ea82accc773 100644
--- a/arch/arm/mach-s3c64xx/s3c6400.c
+++ b/arch/arm/mach-s3c64xx/s3c6400.c
@@ -81,7 +81,7 @@ static struct device s3c6400_dev = {
static int __init s3c6400_core_init(void)
{
/* Not applicable when using DT. */
- if (of_have_populated_dt())
+ if (of_have_populated_dt() || soc_is_s3c64xx())
return 0;
return subsys_system_register(&s3c6400_subsys, NULL);
diff --git a/arch/arm/mach-s3c64xx/s3c6410.c b/arch/arm/mach-s3c64xx/s3c6410.c
index eadc48dee0e4..92bb927c4478 100644
--- a/arch/arm/mach-s3c64xx/s3c6410.c
+++ b/arch/arm/mach-s3c64xx/s3c6410.c
@@ -84,7 +84,7 @@ static struct device s3c6410_dev = {
static int __init s3c6410_core_init(void)
{
/* Not applicable when using DT. */
- if (of_have_populated_dt())
+ if (of_have_populated_dt() || !soc_is_s3c64xx())
return 0;
return subsys_system_register(&s3c6410_subsys, NULL);
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 330bfc8fcd52..13bc9820ff22 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -8,7 +8,8 @@
# Configuration options for the S5PV210/S5PC110
config ARCH_S5PV210
- bool "Samsung S5PV210/S5PC110" if ARCH_MULTI_V7
+ bool "Samsung S5PV210/S5PC110"
+ depends on ARCH_MULTI_V7
select ARCH_HAS_HOLES_MEMORYMODEL
select ARCH_REQUIRE_GPIOLIB
select ARM_VIC
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 41e476e571d7..d8965c682d2f 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -98,8 +98,8 @@ static void cs3_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int cs3_gpio_get(struct gpio_chip *chip, unsigned offset)
{
if (offset > 15)
- return simpad_get_cs3_ro() & (1 << (offset - 16));
- return simpad_get_cs3_shadow() & (1 << offset);
+ return !!(simpad_get_cs3_ro() & (1 << (offset - 16)));
+ return !!(simpad_get_cs3_shadow() & (1 << offset));
};
static int cs3_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 88734a5e10ca..cd5f171f83ce 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -1,6 +1,8 @@
config ARCH_SHMOBILE
bool
- select ZONE_DMA if ARM_LPAE
+
+config ARCH_SHMOBILE_MULTI
+ bool
config PM_RCAR
bool
@@ -29,10 +31,11 @@ config ARCH_RMOBILE
select SYS_SUPPORTS_SH_CMT
select SYS_SUPPORTS_SH_TMU
-menuconfig ARCH_SHMOBILE_MULTI
- bool "Renesas ARM SoCs" if ARCH_MULTI_V7
- depends on MMU
+menuconfig ARCH_RENESAS
+ bool "Renesas ARM SoCs"
+ depends on ARCH_MULTI_V7 && MMU
select ARCH_SHMOBILE
+ select ARCH_SHMOBILE_MULTI
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select ARM_GIC
@@ -40,8 +43,9 @@ menuconfig ARCH_SHMOBILE_MULTI
select NO_IOPORT_MAP
select PINCTRL
select ARCH_REQUIRE_GPIOLIB
+ select ZONE_DMA if ARM_LPAE
-if ARCH_SHMOBILE_MULTI
+if ARCH_RENESAS
#comment "Renesas ARM SoCs System Type"
diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h
deleted file mode 100644
index 5aee83f079e2..000000000000
--- a/arch/arm/mach-shmobile/include/mach/irqs.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_MACH_IRQS_H
-#define __ASM_MACH_IRQS_H
-
-/* Stuck here until drivers/pinctl/sh-pfc gets rid of legacy code */
-
-/* External IRQ pins */
-#define IRQPIN_BASE 2000
-#define irq_pin(nr) ((nr) + IRQPIN_BASE)
-
-#endif /* __ASM_MACH_IRQS_H */
diff --git a/arch/arm/mach-shmobile/irqs.h b/arch/arm/mach-shmobile/irqs.h
deleted file mode 100644
index 3070f6d887eb..000000000000
--- a/arch/arm/mach-shmobile/irqs.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __SHMOBILE_IRQS_H
-#define __SHMOBILE_IRQS_H
-
-#include "include/mach/irqs.h"
-
-/* GIC */
-#define gic_spi(nr) ((nr) + 32)
-#define gic_iid(nr) (nr) /* ICCIAR / interrupt ID */
-
-/* GPIO IRQ */
-#define _GPIO_IRQ_BASE 2500
-#define GPIO_IRQ_BASE(x) (_GPIO_IRQ_BASE + (32 * x))
-#define GPIO_IRQ(x, y) (_GPIO_IRQ_BASE + (32 * x) + y)
-
-#endif /* __SHMOBILE_IRQS_H */
diff --git a/arch/arm/mach-shmobile/r8a7779.h b/arch/arm/mach-shmobile/r8a7779.h
index e1aaa2ef9376..2a5f7730a03c 100644
--- a/arch/arm/mach-shmobile/r8a7779.h
+++ b/arch/arm/mach-shmobile/r8a7779.h
@@ -3,6 +3,6 @@
extern void r8a7779_pm_init(void);
-extern struct smp_operations r8a7779_smp_ops;
+extern const struct smp_operations r8a7779_smp_ops;
#endif /* __ASM_R8A7779_H__ */
diff --git a/arch/arm/mach-shmobile/r8a7790.h b/arch/arm/mach-shmobile/r8a7790.h
index 1a46d026052c..136f3455e9c7 100644
--- a/arch/arm/mach-shmobile/r8a7790.h
+++ b/arch/arm/mach-shmobile/r8a7790.h
@@ -1,6 +1,6 @@
#ifndef __ASM_R8A7790_H__
#define __ASM_R8A7790_H__
-extern struct smp_operations r8a7790_smp_ops;
+extern const struct smp_operations r8a7790_smp_ops;
#endif /* __ASM_R8A7790_H__ */
diff --git a/arch/arm/mach-shmobile/r8a7791.h b/arch/arm/mach-shmobile/r8a7791.h
index 7ca0b7d0f59b..cf7a8405bd7f 100644
--- a/arch/arm/mach-shmobile/r8a7791.h
+++ b/arch/arm/mach-shmobile/r8a7791.h
@@ -1,6 +1,6 @@
#ifndef __ASM_R8A7791_H__
#define __ASM_R8A7791_H__
-extern struct smp_operations r8a7791_smp_ops;
+extern const struct smp_operations r8a7791_smp_ops;
#endif /* __ASM_R8A7791_H__ */
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
index 37f7b15c01bc..10b7cb5dcb3a 100644
--- a/arch/arm/mach-shmobile/setup-emev2.c
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -42,7 +42,7 @@ static const char *const emev2_boards_compat_dt[] __initconst = {
NULL,
};
-extern struct smp_operations emev2_smp_ops;
+extern const struct smp_operations emev2_smp_ops;
DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
.smp = smp_ops(emev2_smp_ops),
diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c
index 0ab9d3272875..fab95d1271bc 100644
--- a/arch/arm/mach-shmobile/setup-r8a7778.c
+++ b/arch/arm/mach-shmobile/setup-r8a7778.c
@@ -22,7 +22,6 @@
#include <asm/mach/arch.h>
#include "common.h"
-#include "irqs.h"
#define MODEMR 0xffcc0020
diff --git a/arch/arm/mach-shmobile/sh73a0.h b/arch/arm/mach-shmobile/sh73a0.h
index 39646806cf64..50ef24f780b3 100644
--- a/arch/arm/mach-shmobile/sh73a0.h
+++ b/arch/arm/mach-shmobile/sh73a0.h
@@ -1,6 +1,6 @@
#ifndef __ASM_SH73A0_H__
#define __ASM_SH73A0_H__
-extern struct smp_operations sh73a0_smp_ops;
+extern const struct smp_operations sh73a0_smp_ops;
#endif /* __ASM_SH73A0_H__ */
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
index baff3b5efed8..adbac6963f2b 100644
--- a/arch/arm/mach-shmobile/smp-emev2.c
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -49,7 +49,7 @@ static void __init emev2_smp_prepare_cpus(unsigned int max_cpus)
shmobile_smp_scu_prepare_cpus(max_cpus);
}
-struct smp_operations emev2_smp_ops __initdata = {
+const struct smp_operations emev2_smp_ops __initconst = {
.smp_prepare_cpus = emev2_smp_prepare_cpus,
.smp_boot_secondary = emev2_boot_secondary,
};
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
index 353562b8a5ee..b854fe2095ad 100644
--- a/arch/arm/mach-shmobile/smp-r8a7779.c
+++ b/arch/arm/mach-shmobile/smp-r8a7779.c
@@ -117,7 +117,7 @@ static int r8a7779_cpu_kill(unsigned int cpu)
}
#endif /* CONFIG_HOTPLUG_CPU */
-struct smp_operations r8a7779_smp_ops __initdata = {
+const struct smp_operations r8a7779_smp_ops __initconst = {
.smp_prepare_cpus = r8a7779_smp_prepare_cpus,
.smp_boot_secondary = r8a7779_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c
index 4b33d432a364..f6426c6fdefc 100644
--- a/arch/arm/mach-shmobile/smp-r8a7790.c
+++ b/arch/arm/mach-shmobile/smp-r8a7790.c
@@ -60,7 +60,7 @@ static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus)
rcar_sysc_power_up(&r8a7790_ca7_scu);
}
-struct smp_operations r8a7790_smp_ops __initdata = {
+const struct smp_operations r8a7790_smp_ops __initconst = {
.smp_prepare_cpus = r8a7790_smp_prepare_cpus,
.smp_boot_secondary = shmobile_smp_apmu_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c
index b2508c0d276b..2d6417af73b5 100644
--- a/arch/arm/mach-shmobile/smp-r8a7791.c
+++ b/arch/arm/mach-shmobile/smp-r8a7791.c
@@ -54,7 +54,7 @@ static int r8a7791_smp_boot_secondary(unsigned int cpu,
return shmobile_smp_apmu_boot_secondary(cpu, idle);
}
-struct smp_operations r8a7791_smp_ops __initdata = {
+const struct smp_operations r8a7791_smp_ops __initconst = {
.smp_prepare_cpus = r8a7791_smp_prepare_cpus,
.smp_boot_secondary = r8a7791_smp_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index bc2824a036e1..ee1a4b70604b 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -56,7 +56,7 @@ static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus)
shmobile_smp_scu_prepare_cpus(max_cpus);
}
-struct smp_operations sh73a0_smp_ops __initdata = {
+const struct smp_operations sh73a0_smp_ops __initconst = {
.smp_prepare_cpus = sh73a0_smp_prepare_cpus,
.smp_boot_secondary = sh73a0_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 90efdeb56be5..d0f62eacf59d 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_SOCFPGA
- bool "Altera SOCFPGA family" if ARCH_MULTI_V7
+ bool "Altera SOCFPGA family"
+ depends on ARCH_MULTI_V7
select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
select ARM_GIC
diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c
index 15c8ce8965f4..cbb0a54df80a 100644
--- a/arch/arm/mach-socfpga/platsmp.c
+++ b/arch/arm/mach-socfpga/platsmp.c
@@ -117,7 +117,7 @@ static int socfpga_cpu_kill(unsigned int cpu)
return 1;
}
-static struct smp_operations socfpga_smp_ops __initdata = {
+static const struct smp_operations socfpga_smp_ops __initconst = {
.smp_prepare_cpus = socfpga_smp_prepare_cpus,
.smp_boot_secondary = socfpga_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
@@ -126,7 +126,7 @@ static struct smp_operations socfpga_smp_ops __initdata = {
#endif
};
-static struct smp_operations socfpga_a10_smp_ops __initdata = {
+static const struct smp_operations socfpga_a10_smp_ops __initconst = {
.smp_prepare_cpus = socfpga_smp_prepare_cpus,
.smp_boot_secondary = socfpga_a10_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig
index b6f4bda273b3..ea9ea95630bd 100644
--- a/arch/arm/mach-spear/Kconfig
+++ b/arch/arm/mach-spear/Kconfig
@@ -3,7 +3,8 @@
#
menuconfig PLAT_SPEAR
- bool "ST SPEAr Family" if ARCH_MULTI_V7 || ARCH_MULTI_V5
+ bool "ST SPEAr Family"
+ depends on ARCH_MULTI_V7 || ARCH_MULTI_V5
select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
select CLKSRC_MMIO
diff --git a/arch/arm/mach-spear/generic.h b/arch/arm/mach-spear/generic.h
index 06640914d9a0..909b97c0b237 100644
--- a/arch/arm/mach-spear/generic.h
+++ b/arch/arm/mach-spear/generic.h
@@ -39,7 +39,7 @@ void spear_restart(enum reboot_mode, const char *);
void spear13xx_secondary_startup(void);
void spear13xx_cpu_die(unsigned int cpu);
-extern struct smp_operations spear13xx_smp_ops;
+extern const struct smp_operations spear13xx_smp_ops;
#ifdef CONFIG_MACH_SPEAR1310
void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base);
diff --git a/arch/arm/mach-spear/platsmp.c b/arch/arm/mach-spear/platsmp.c
index fd4297713d67..8d1e2d551786 100644
--- a/arch/arm/mach-spear/platsmp.c
+++ b/arch/arm/mach-spear/platsmp.c
@@ -120,7 +120,7 @@ static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
__raw_writel(virt_to_phys(spear13xx_secondary_startup), SYS_LOCATION);
}
-struct smp_operations spear13xx_smp_ops __initdata = {
+const struct smp_operations spear13xx_smp_ops __initconst = {
.smp_init_cpus = spear13xx_smp_init_cpus,
.smp_prepare_cpus = spear13xx_smp_prepare_cpus,
.smp_secondary_init = spear13xx_secondary_init,
diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig
index 12dd1dc0a041..a196d14f65f5 100644
--- a/arch/arm/mach-sti/Kconfig
+++ b/arch/arm/mach-sti/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_STI
- bool "STMicroelectronics Consumer Electronics SOCs" if ARCH_MULTI_V7
+ bool "STMicroelectronics Consumer Electronics SOCs"
+ depends on ARCH_MULTI_V7
select ARM_GIC
select ST_IRQCHIP
select ARM_GLOBAL_TIMER
diff --git a/arch/arm/mach-sti/platsmp.c b/arch/arm/mach-sti/platsmp.c
index c4ad6eae67fa..ea5a2277ee46 100644
--- a/arch/arm/mach-sti/platsmp.c
+++ b/arch/arm/mach-sti/platsmp.c
@@ -156,7 +156,7 @@ static void __init sti_smp_prepare_cpus(unsigned int max_cpus)
}
}
-struct smp_operations __initdata sti_smp_ops = {
+const struct smp_operations sti_smp_ops __initconst = {
.smp_prepare_cpus = sti_smp_prepare_cpus,
.smp_secondary_init = sti_secondary_init,
.smp_boot_secondary = sti_boot_secondary,
diff --git a/arch/arm/mach-sti/smp.h b/arch/arm/mach-sti/smp.h
index ae22707d301f..d8a2f8758490 100644
--- a/arch/arm/mach-sti/smp.h
+++ b/arch/arm/mach-sti/smp.h
@@ -12,7 +12,7 @@
#ifndef __MACH_STI_SMP_H
#define __MACH_STI_SMP_H
-extern struct smp_operations sti_smp_ops;
+extern const struct smp_operations sti_smp_ops;
void sti_secondary_startup(void);
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 4efe2d43a126..c124d658b350 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_SUNXI
- bool "Allwinner SoCs" if ARCH_MULTI_V7
+ bool "Allwinner SoCs"
+ depends on ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select ARCH_HAS_RESET_CONTROLLER
select CLKSRC_MMIO
diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c
index e8483ec79d67..6642267812c9 100644
--- a/arch/arm/mach-sunxi/platsmp.c
+++ b/arch/arm/mach-sunxi/platsmp.c
@@ -116,7 +116,7 @@ static int sun6i_smp_boot_secondary(unsigned int cpu,
return 0;
}
-static struct smp_operations sun6i_smp_ops __initdata = {
+static const struct smp_operations sun6i_smp_ops __initconst = {
.smp_prepare_cpus = sun6i_smp_prepare_cpus,
.smp_boot_secondary = sun6i_smp_boot_secondary,
};
@@ -185,7 +185,7 @@ static int sun8i_smp_boot_secondary(unsigned int cpu,
return 0;
}
-struct smp_operations sun8i_smp_ops __initdata = {
+static const struct smp_operations sun8i_smp_ops __initconst = {
.smp_prepare_cpus = sun8i_smp_prepare_cpus,
.smp_boot_secondary = sun8i_smp_boot_secondary,
};
diff --git a/arch/arm/mach-tango/Kconfig b/arch/arm/mach-tango/Kconfig
new file mode 100644
index 000000000000..d6a3714b096e
--- /dev/null
+++ b/arch/arm/mach-tango/Kconfig
@@ -0,0 +1,12 @@
+config ARCH_TANGO
+ bool "Sigma Designs Tango4 (SMP87xx)" if ARCH_MULTI_V7
+ # Cortex-A9 MPCore r3p0, PL310 r3p2
+ select ARCH_HAS_HOLES_MEMORYMODEL
+ select ARM_ERRATA_754322
+ select ARM_ERRATA_764369 if SMP
+ select ARM_ERRATA_775420
+ select ARM_GIC
+ select CLKSRC_TANGO_XTAL
+ select HAVE_ARM_SCU
+ select HAVE_ARM_TWD
+ select TANGO_IRQ
diff --git a/arch/arm/mach-tango/Makefile b/arch/arm/mach-tango/Makefile
new file mode 100644
index 000000000000..f33935e42e77
--- /dev/null
+++ b/arch/arm/mach-tango/Makefile
@@ -0,0 +1,5 @@
+plus_sec := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_smc.o := -Wa,-march=armv7-a$(plus_sec)
+
+obj-y += setup.o smc.o
+obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-tango/platsmp.c b/arch/arm/mach-tango/platsmp.c
new file mode 100644
index 000000000000..a18d5a34e2f5
--- /dev/null
+++ b/arch/arm/mach-tango/platsmp.c
@@ -0,0 +1,16 @@
+#include <linux/init.h>
+#include <linux/smp.h>
+#include "smc.h"
+
+static int tango_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ tango_set_aux_boot_addr(virt_to_phys(secondary_startup));
+ tango_start_aux_core(cpu);
+ return 0;
+}
+
+static struct smp_operations tango_smp_ops __initdata = {
+ .smp_boot_secondary = tango_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(tango4_smp, "sigma,tango4-smp", &tango_smp_ops);
diff --git a/arch/arm/mach-tango/setup.c b/arch/arm/mach-tango/setup.c
new file mode 100644
index 000000000000..f14b6c7d255b
--- /dev/null
+++ b/arch/arm/mach-tango/setup.c
@@ -0,0 +1,17 @@
+#include <asm/mach/arch.h>
+#include <asm/hardware/cache-l2x0.h>
+#include "smc.h"
+
+static void tango_l2c_write(unsigned long val, unsigned int reg)
+{
+ if (reg == L2X0_CTRL)
+ tango_set_l2_control(val);
+}
+
+static const char *const tango_dt_compat[] = { "sigma,tango4", NULL };
+
+DT_MACHINE_START(TANGO_DT, "Sigma Tango DT")
+ .dt_compat = tango_dt_compat,
+ .l2c_aux_mask = ~0,
+ .l2c_write_sec = tango_l2c_write,
+MACHINE_END
diff --git a/arch/arm/mach-tango/smc.S b/arch/arm/mach-tango/smc.S
new file mode 100644
index 000000000000..5d932ce3c1bd
--- /dev/null
+++ b/arch/arm/mach-tango/smc.S
@@ -0,0 +1,9 @@
+#include <linux/linkage.h>
+
+ENTRY(tango_smc)
+ push {lr}
+ mov ip, r1
+ dsb /* This barrier is probably unnecessary */
+ smc #0
+ pop {pc}
+ENDPROC(tango_smc)
diff --git a/arch/arm/mach-tango/smc.h b/arch/arm/mach-tango/smc.h
new file mode 100644
index 000000000000..7a4af35cc390
--- /dev/null
+++ b/arch/arm/mach-tango/smc.h
@@ -0,0 +1,5 @@
+extern int tango_smc(unsigned int val, unsigned int service);
+
+#define tango_set_l2_control(val) tango_smc(val, 0x102)
+#define tango_start_aux_core(val) tango_smc(val, 0x104)
+#define tango_set_aux_boot_addr(val) tango_smc((unsigned int)val, 0x105)
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0fa4c5f8b1be..a90f3556017f 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_TEGRA
- bool "NVIDIA Tegra" if ARCH_MULTI_V7
+ bool "NVIDIA Tegra"
+ depends on ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
select ARM_AMBA
diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h
index 5900cc44f780..1f6fb808e236 100644
--- a/arch/arm/mach-tegra/common.h
+++ b/arch/arm/mach-tegra/common.h
@@ -1,4 +1,4 @@
-extern struct smp_operations tegra_smp_ops;
+extern const struct smp_operations tegra_smp_ops;
extern int tegra_cpu_kill(unsigned int cpu);
extern void tegra_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index b45086666648..f3f61dbbda97 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -192,7 +192,7 @@ static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
scu_enable(IO_ADDRESS(scu_a9_get_base()));
}
-struct smp_operations tegra_smp_ops __initdata = {
+const struct smp_operations tegra_smp_ops __initconst = {
.smp_prepare_cpus = tegra_smp_prepare_cpus,
.smp_secondary_init = tegra_secondary_init,
.smp_boot_secondary = tegra_boot_secondary,
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
index bc51a71394af..301a98498453 100644
--- a/arch/arm/mach-u300/Kconfig
+++ b/arch/arm/mach-u300/Kconfig
@@ -1,6 +1,6 @@
menuconfig ARCH_U300
- bool "ST-Ericsson U300 Series" if ARCH_MULTI_V5
- depends on MMU
+ bool "ST-Ericsson U300 Series"
+ depends on ARCH_MULTI_V5 && MMU
select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
select ARM_VIC
diff --git a/arch/arm/mach-uniphier/Kconfig b/arch/arm/mach-uniphier/Kconfig
index b640458fd757..82dddee3a469 100644
--- a/arch/arm/mach-uniphier/Kconfig
+++ b/arch/arm/mach-uniphier/Kconfig
@@ -6,6 +6,7 @@ config ARCH_UNIPHIER
select ARM_GIC
select HAVE_ARM_SCU
select HAVE_ARM_TWD if SMP
+ select PINCTRL
help
Support for UniPhier SoC family developed by Socionext Inc.
(formerly, System LSI Business Division of Panasonic Corporation)
diff --git a/arch/arm/mach-uniphier/platsmp.c b/arch/arm/mach-uniphier/platsmp.c
index f0577664611c..e1cfc1d6e2f4 100644
--- a/arch/arm/mach-uniphier/platsmp.c
+++ b/arch/arm/mach-uniphier/platsmp.c
@@ -201,7 +201,7 @@ static int __init uniphier_smp_boot_secondary(unsigned int cpu,
return 0;
}
-static struct smp_operations uniphier_smp_ops __initdata = {
+static const struct smp_operations uniphier_smp_ops __initconst = {
.smp_prepare_cpus = uniphier_smp_prepare_cpus,
.smp_boot_secondary = uniphier_smp_boot_secondary,
};
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 5eacdd61e61c..3185081bdb2c 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -1,6 +1,6 @@
menuconfig ARCH_U8500
- bool "ST-Ericsson U8500 Series" if ARCH_MULTI_V7
- depends on MMU
+ bool "ST-Ericsson U8500 Series"
+ depends on ARCH_MULTI_V7 && MMU
select AB8500_CORE
select ABX500_CORE
select ARCH_REQUIRE_GPIOLIB
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index c8643ac5db71..edfff1ae1f8d 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel, U8500 machine.
#
-obj-y := cpu.o id.o timer.o pm.o
+obj-y := cpu.o id.o pm.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o
obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index f80560318c58..a0ffaad1fb61 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -156,8 +156,6 @@ static const char * stericsson_dt_platform_compat[] = {
DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)")
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
- /* we re-use nomadik timer here */
- .init_time = ux500_timer_init,
.init_machine = u8500_init_machine,
.init_late = NULL,
.dt_compat = stericsson_dt_platform_compat,
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 41b81c4fbe63..82156cbc22ce 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -9,7 +9,6 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/clksrc-dbx500-prcmu.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
#include <linux/slab.h>
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index 70766b963758..88b8ab4f300c 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -98,7 +98,7 @@ static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle)
return 0;
}
-struct smp_operations ux500_smp_ops __initdata = {
+static const struct smp_operations ux500_smp_ops __initconst = {
.smp_prepare_cpus = ux500_smp_prepare_cpus,
.smp_boot_secondary = ux500_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-ux500/setup.h b/arch/arm/mach-ux500/setup.h
index 65876eac0761..c704254ab67c 100644
--- a/arch/arm/mach-ux500/setup.h
+++ b/arch/arm/mach-ux500/setup.h
@@ -12,7 +12,6 @@
#define __ASM_ARCH_SETUP_H
#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
#include <linux/init.h>
#include <linux/mfd/abx500/ab8500.h>
@@ -24,8 +23,6 @@ extern void __init ux500_init_irq(void);
extern struct device *ux500_soc_device_init(const char *soc_id);
-extern void ux500_timer_init(void);
-
extern void ux500_cpu_die(unsigned int cpu);
#endif /* __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
deleted file mode 100644
index 8d2d233f8e6c..000000000000
--- a/arch/arm/mach-ux500/timer.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * License Terms: GNU General Public License v2
- * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
- */
-#include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/clksrc-dbx500-prcmu.h>
-#include <linux/clocksource.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include "setup.h"
-
-#include "db8500-regs.h"
-#include "id.h"
-
-static const struct of_device_id prcmu_timer_of_match[] __initconst = {
- { .compatible = "stericsson,db8500-prcmu-timer-4", },
- { },
-};
-
-void __init ux500_timer_init(void)
-{
- void __iomem *prcmu_timer_base;
- void __iomem *tmp_base;
- struct device_node *np;
-
- if (cpu_is_u8500_family() || cpu_is_ux540_family())
- prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
- else
- ux500_unknown_soc();
-
- np = of_find_matching_node(NULL, prcmu_timer_of_match);
- if (!np)
- goto dt_fail;
-
- tmp_base = of_iomap(np, 0);
- if (!tmp_base)
- goto dt_fail;
-
- prcmu_timer_base = tmp_base;
-
-dt_fail:
- clksrc_dbx500_prcmu_init(prcmu_timer_base);
- clocksource_probe();
-}
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig
index 1dba3688275f..e40f777ccf7d 100644
--- a/arch/arm/mach-versatile/Kconfig
+++ b/arch/arm/mach-versatile/Kconfig
@@ -1,33 +1,16 @@
-menu "Versatile platform type"
- depends on ARCH_VERSATILE
-
-config ARCH_VERSATILE_PB
- bool "Support Versatile Platform Baseboard for ARM926EJ-S"
- default y
+config ARCH_VERSATILE
+ bool "ARM Ltd. Versatile family"
+ depends on ARCH_MULTI_V5
+ select ARM_AMBA
+ select ARM_TIMER_SP804
+ select ARM_VIC
+ select CLKSRC_VERSATILE
+ select COMMON_CLK_VERSATILE
select CPU_ARM926T
+ select ICST
select MIGHT_HAVE_PCI
+ select PLAT_VERSATILE
+ select VERSATILE_FPGA_IRQ
help
- Include support for the ARM(R) Versatile Platform Baseboard
- for the ARM926EJ-S.
-
-config MACH_VERSATILE_AB
- bool "Support Versatile Application Baseboard for ARM926EJ-S"
- select CPU_ARM926T
- help
- Include support for the ARM(R) Versatile Application Baseboard
- for the ARM926EJ-S.
-
-config MACH_VERSATILE_DT
- bool "Support Versatile platform from device tree"
- select CPU_ARM926T
- select USE_OF
- help
- Include support for the ARM(R) Versatile/PB platform,
- using the device tree for discovery
-
-config MACH_VERSATILE_AUTO
- def_bool y
- depends on !ARCH_VERSATILE_PB && !MACH_VERSATILE_AB
- select MACH_VERSATILE_DT
+ This enables support for ARM Ltd Versatile board.
-endmenu
diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile
index 81fa3fe25e1a..41b124b5107b 100644
--- a/arch/arm/mach-versatile/Makefile
+++ b/arch/arm/mach-versatile/Makefile
@@ -2,8 +2,4 @@
# Makefile for the linux kernel.
#
-obj-y := core.o
-obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o
-obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o
-obj-$(CONFIG_MACH_VERSATILE_DT) += versatile_dt.o
-obj-$(CONFIG_PCI) += pci.o
+obj-y := versatile_dt.o
diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot
deleted file mode 100644
index ff0a4b5b0a82..000000000000
--- a/arch/arm/mach-versatile/Makefile.boot
+++ /dev/null
@@ -1,4 +0,0 @@
- zreladdr-y += 0x00008000
-params_phys-y := 0x00000100
-initrd_phys-y := 0x00800000
-
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
deleted file mode 100644
index 23a04fe5d2ad..000000000000
--- a/arch/arm/mach-versatile/core.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * linux/arch/arm/mach-versatile/core.c
- *
- * Copyright (C) 1999 - 2003 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/platform_data/video-clcd-versatile.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/amba/pl022.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-vic.h>
-#include <linux/irqchip/versatile-fpga.h>
-#include <linux/gfp.h>
-#include <linux/clkdev.h>
-#include <linux/mtd/physmap.h>
-#include <linux/bitops.h>
-#include <linux/reboot.h>
-
-#include <clocksource/timer-sp804.h>
-
-#include <asm/irq.h>
-#include <asm/hardware/icst.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
-#include <mach/hardware.h>
-#include <mach/platform.h>
-
-#include <plat/sched_clock.h>
-
-#include "core.h"
-
-/*
- * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
- * is the (PA >> 12).
- *
- * Setup a VA for the Versatile Vectored Interrupt Controller.
- */
-#define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE)
-#define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE)
-
-/* These PIC IRQs are valid in each configuration */
-#define PIC_VALID_ALL BIT(SIC_INT_KMI0) | BIT(SIC_INT_KMI1) | \
- BIT(SIC_INT_SCI3) | BIT(SIC_INT_UART3) | \
- BIT(SIC_INT_CLCD) | BIT(SIC_INT_TOUCH) | \
- BIT(SIC_INT_KEYPAD) | BIT(SIC_INT_DoC) | \
- BIT(SIC_INT_USB) | BIT(SIC_INT_PCI0) | \
- BIT(SIC_INT_PCI1) | BIT(SIC_INT_PCI2) | \
- BIT(SIC_INT_PCI3)
-#if 1
-#define IRQ_MMCI0A IRQ_VICSOURCE22
-#define IRQ_AACI IRQ_VICSOURCE24
-#define IRQ_ETH IRQ_VICSOURCE25
-#define PIC_MASK 0xFFD00000
-#define PIC_VALID PIC_VALID_ALL
-#else
-#define IRQ_MMCI0A IRQ_SIC_MMCI0A
-#define IRQ_AACI IRQ_SIC_AACI
-#define IRQ_ETH IRQ_SIC_ETH
-#define PIC_MASK 0
-#define PIC_VALID PIC_VALID_ALL | BIT(SIC_INT_MMCI0A) | \
- BIT(SIC_INT_MMCI1A) | BIT(SIC_INT_AACI) | \
- BIT(SIC_INT_ETH)
-#endif
-
-/* Lookup table for finding a DT node that represents the vic instance */
-static const struct of_device_id vic_of_match[] __initconst = {
- { .compatible = "arm,versatile-vic", },
- {}
-};
-
-static const struct of_device_id sic_of_match[] __initconst = {
- { .compatible = "arm,versatile-sic", },
- {}
-};
-
-void __init versatile_init_irq(void)
-{
- struct device_node *np;
-
- np = of_find_matching_node_by_address(NULL, vic_of_match,
- VERSATILE_VIC_BASE);
- __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
-
- writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
-
- np = of_find_matching_node_by_address(NULL, sic_of_match,
- VERSATILE_SIC_BASE);
-
- fpga_irq_init(VA_SIC_BASE, "SIC", IRQ_SIC_START,
- IRQ_VICSOURCE31, PIC_VALID, np);
-
- /*
- * Interrupts on secondary controller from 0 to 8 are routed to
- * source 31 on PIC.
- * Interrupts from 21 to 31 are routed directly to the VIC on
- * the corresponding number on primary controller. This is controlled
- * by setting PIC_ENABLEx.
- */
- writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE);
-}
-
-static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
- {
- .virtual = IO_ADDRESS(VERSATILE_SYS_BASE),
- .pfn = __phys_to_pfn(VERSATILE_SYS_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(VERSATILE_SIC_BASE),
- .pfn = __phys_to_pfn(VERSATILE_SIC_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(VERSATILE_VIC_BASE),
- .pfn = __phys_to_pfn(VERSATILE_VIC_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE),
- .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE),
- .length = SZ_4K * 9,
- .type = MT_DEVICE
- },
-#ifdef CONFIG_MACH_VERSATILE_AB
- {
- .virtual = IO_ADDRESS(VERSATILE_IB2_BASE),
- .pfn = __phys_to_pfn(VERSATILE_IB2_BASE),
- .length = SZ_64M,
- .type = MT_DEVICE
- },
-#endif
-#ifdef CONFIG_DEBUG_LL
- {
- .virtual = IO_ADDRESS(VERSATILE_UART0_BASE),
- .pfn = __phys_to_pfn(VERSATILE_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- },
-#endif
-#ifdef CONFIG_PCI
- {
- .virtual = IO_ADDRESS(VERSATILE_PCI_CORE_BASE),
- .pfn = __phys_to_pfn(VERSATILE_PCI_CORE_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = (unsigned long)VERSATILE_PCI_VIRT_BASE,
- .pfn = __phys_to_pfn(VERSATILE_PCI_BASE),
- .length = VERSATILE_PCI_BASE_SIZE,
- .type = MT_DEVICE
- }, {
- .virtual = (unsigned long)VERSATILE_PCI_CFG_VIRT_BASE,
- .pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
- .length = VERSATILE_PCI_CFG_BASE_SIZE,
- .type = MT_DEVICE
- },
-#endif
-};
-
-void __init versatile_map_io(void)
-{
- iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
-}
-
-
-#define VERSATILE_FLASHCTRL (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET)
-
-static void versatile_flash_set_vpp(struct platform_device *pdev, int on)
-{
- u32 val;
-
- val = __raw_readl(VERSATILE_FLASHCTRL);
- if (on)
- val |= VERSATILE_FLASHPROG_FLVPPEN;
- else
- val &= ~VERSATILE_FLASHPROG_FLVPPEN;
- __raw_writel(val, VERSATILE_FLASHCTRL);
-}
-
-static struct physmap_flash_data versatile_flash_data = {
- .width = 4,
- .set_vpp = versatile_flash_set_vpp,
-};
-
-static struct resource versatile_flash_resource = {
- .start = VERSATILE_FLASH_BASE,
- .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device versatile_flash_device = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &versatile_flash_data,
- },
- .num_resources = 1,
- .resource = &versatile_flash_resource,
-};
-
-static struct resource smc91x_resources[] = {
- [0] = {
- .start = VERSATILE_ETH_BASE,
- .end = VERSATILE_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_ETH,
- .end = IRQ_ETH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device smc91x_device = {
- .name = "smc91x",
- .id = 0,
- .num_resources = ARRAY_SIZE(smc91x_resources),
- .resource = smc91x_resources,
-};
-
-static struct resource versatile_i2c_resource = {
- .start = VERSATILE_I2C_BASE,
- .end = VERSATILE_I2C_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device versatile_i2c_device = {
- .name = "versatile-i2c",
- .id = 0,
- .num_resources = 1,
- .resource = &versatile_i2c_resource,
-};
-
-static struct i2c_board_info versatile_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("ds1338", 0xd0 >> 1),
- },
-};
-
-static int __init versatile_i2c_init(void)
-{
- return i2c_register_board_info(0, versatile_i2c_board_info,
- ARRAY_SIZE(versatile_i2c_board_info));
-}
-arch_initcall(versatile_i2c_init);
-
-#define VERSATILE_SYSMCI (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET)
-
-unsigned int mmc_status(struct device *dev)
-{
- struct amba_device *adev = container_of(dev, struct amba_device, dev);
- u32 mask;
-
- if (adev->res.start == VERSATILE_MMCI0_BASE)
- mask = 1;
- else
- mask = 2;
-
- return readl(VERSATILE_SYSMCI) & mask;
-}
-
-static struct mmci_platform_data mmc0_plat_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .status = mmc_status,
- .gpio_wp = -1,
- .gpio_cd = -1,
-};
-
-static struct resource char_lcd_resources[] = {
- {
- .start = VERSATILE_CHAR_LCD_BASE,
- .end = (VERSATILE_CHAR_LCD_BASE + SZ_4K - 1),
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device char_lcd_device = {
- .name = "arm-charlcd",
- .id = -1,
- .num_resources = ARRAY_SIZE(char_lcd_resources),
- .resource = char_lcd_resources,
-};
-
-static struct resource leds_resources[] = {
- {
- .start = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET,
- .end = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET + 4,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device leds_device = {
- .name = "versatile-leds",
- .id = -1,
- .num_resources = ARRAY_SIZE(leds_resources),
- .resource = leds_resources,
-};
-
-/*
- * Clock handling
- */
-static const struct icst_params versatile_oscvco_params = {
- .ref = 24000000,
- .vco_max = ICST307_VCO_MAX,
- .vco_min = ICST307_VCO_MIN,
- .vd_min = 4 + 8,
- .vd_max = 511 + 8,
- .rd_min = 1 + 2,
- .rd_max = 127 + 2,
- .s2div = icst307_s2div,
- .idx2s = icst307_idx2s,
-};
-
-static void versatile_oscvco_set(struct clk *clk, struct icst_vco vco)
-{
- void __iomem *sys_lock = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET;
- u32 val;
-
- val = readl(clk->vcoreg) & ~0x7ffff;
- val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
- writel(0xa05f, sys_lock);
- writel(val, clk->vcoreg);
- writel(0, sys_lock);
-}
-
-static const struct clk_ops osc4_clk_ops = {
- .round = icst_clk_round,
- .set = icst_clk_set,
- .setvco = versatile_oscvco_set,
-};
-
-static struct clk osc4_clk = {
- .ops = &osc4_clk_ops,
- .params = &versatile_oscvco_params,
-};
-
-/*
- * These are fixed clocks.
- */
-static struct clk ref24_clk = {
- .rate = 24000000,
-};
-
-static struct clk sp804_clk = {
- .rate = 1000000,
-};
-
-static struct clk dummy_apb_pclk;
-
-static struct clk_lookup lookups[] = {
- { /* AMBA bus clock */
- .con_id = "apb_pclk",
- .clk = &dummy_apb_pclk,
- }, { /* UART0 */
- .dev_id = "dev:f1",
- .clk = &ref24_clk,
- }, { /* UART1 */
- .dev_id = "dev:f2",
- .clk = &ref24_clk,
- }, { /* UART2 */
- .dev_id = "dev:f3",
- .clk = &ref24_clk,
- }, { /* UART3 */
- .dev_id = "fpga:09",
- .clk = &ref24_clk,
- }, { /* KMI0 */
- .dev_id = "fpga:06",
- .clk = &ref24_clk,
- }, { /* KMI1 */
- .dev_id = "fpga:07",
- .clk = &ref24_clk,
- }, { /* MMC0 */
- .dev_id = "fpga:05",
- .clk = &ref24_clk,
- }, { /* MMC1 */
- .dev_id = "fpga:0b",
- .clk = &ref24_clk,
- }, { /* SSP */
- .dev_id = "dev:f4",
- .clk = &ref24_clk,
- }, { /* CLCD */
- .dev_id = "dev:20",
- .clk = &osc4_clk,
- }, { /* SP804 timers */
- .dev_id = "sp804",
- .clk = &sp804_clk,
- },
-};
-
-/*
- * CLCD support.
- */
-#define SYS_CLCD_MODE_MASK (3 << 0)
-#define SYS_CLCD_MODE_888 (0 << 0)
-#define SYS_CLCD_MODE_5551 (1 << 0)
-#define SYS_CLCD_MODE_565_RLSB (2 << 0)
-#define SYS_CLCD_MODE_565_BLSB (3 << 0)
-#define SYS_CLCD_NLCDIOON (1 << 2)
-#define SYS_CLCD_VDDPOSSWITCH (1 << 3)
-#define SYS_CLCD_PWR3V5SWITCH (1 << 4)
-#define SYS_CLCD_ID_MASK (0x1f << 8)
-#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
-#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
-#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
-#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
-#define SYS_CLCD_ID_VGA (0x1f << 8)
-
-static bool is_sanyo_2_5_lcd;
-
-/*
- * Disable all display connectors on the interface module.
- */
-static void versatile_clcd_disable(struct clcd_fb *fb)
-{
- void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
- u32 val;
-
- val = readl(sys_clcd);
- val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
- writel(val, sys_clcd);
-
-#ifdef CONFIG_MACH_VERSATILE_AB
- /*
- * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
- */
- if (machine_is_versatile_ab() && is_sanyo_2_5_lcd) {
- void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
- unsigned long ctrl;
-
- ctrl = readl(versatile_ib2_ctrl);
- ctrl &= ~0x01;
- writel(ctrl, versatile_ib2_ctrl);
- }
-#endif
-}
-
-/*
- * Enable the relevant connector on the interface module.
- */
-static void versatile_clcd_enable(struct clcd_fb *fb)
-{
- struct fb_var_screeninfo *var = &fb->fb.var;
- void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
- u32 val;
-
- val = readl(sys_clcd);
- val &= ~SYS_CLCD_MODE_MASK;
-
- switch (var->green.length) {
- case 5:
- val |= SYS_CLCD_MODE_5551;
- break;
- case 6:
- if (var->red.offset == 0)
- val |= SYS_CLCD_MODE_565_RLSB;
- else
- val |= SYS_CLCD_MODE_565_BLSB;
- break;
- case 8:
- val |= SYS_CLCD_MODE_888;
- break;
- }
-
- /*
- * Set the MUX
- */
- writel(val, sys_clcd);
-
- /*
- * And now enable the PSUs
- */
- val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
- writel(val, sys_clcd);
-
-#ifdef CONFIG_MACH_VERSATILE_AB
- /*
- * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
- */
- if (machine_is_versatile_ab() && is_sanyo_2_5_lcd) {
- void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
- unsigned long ctrl;
-
- ctrl = readl(versatile_ib2_ctrl);
- ctrl |= 0x01;
- writel(ctrl, versatile_ib2_ctrl);
- }
-#endif
-}
-
-/*
- * Detect which LCD panel is connected, and return the appropriate
- * clcd_panel structure. Note: we do not have any information on
- * the required timings for the 8.4in panel, so we presently assume
- * VGA timings.
- */
-static int versatile_clcd_setup(struct clcd_fb *fb)
-{
- void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
- const char *panel_name;
- u32 val;
-
- is_sanyo_2_5_lcd = false;
-
- val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
- if (val == SYS_CLCD_ID_SANYO_3_8)
- panel_name = "Sanyo TM38QV67A02A";
- else if (val == SYS_CLCD_ID_SANYO_2_5) {
- panel_name = "Sanyo QVGA Portrait";
- is_sanyo_2_5_lcd = true;
- } else if (val == SYS_CLCD_ID_EPSON_2_2)
- panel_name = "Epson L2F50113T00";
- else if (val == SYS_CLCD_ID_VGA)
- panel_name = "VGA";
- else {
- printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
- val);
- panel_name = "VGA";
- }
-
- fb->panel = versatile_clcd_get_panel(panel_name);
- if (!fb->panel)
- return -EINVAL;
-
- return versatile_clcd_setup_dma(fb, SZ_1M);
-}
-
-static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
-{
- clcdfb_decode(fb, regs);
-
- /* Always clear BGR for RGB565: we do the routing externally */
- if (fb->fb.var.green.length == 6)
- regs->cntl &= ~CNTL_BGR;
-}
-
-static struct clcd_board clcd_plat_data = {
- .name = "Versatile",
- .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
- .check = clcdfb_check,
- .decode = versatile_clcd_decode,
- .disable = versatile_clcd_disable,
- .enable = versatile_clcd_enable,
- .setup = versatile_clcd_setup,
- .mmap = versatile_clcd_mmap_dma,
- .remove = versatile_clcd_remove_dma,
-};
-
-static struct pl061_platform_data gpio0_plat_data = {
- .gpio_base = 0,
- .irq_base = IRQ_GPIO0_START,
-};
-
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
- .irq_base = IRQ_GPIO1_START,
-};
-
-static struct pl061_platform_data gpio2_plat_data = {
- .gpio_base = 16,
- .irq_base = IRQ_GPIO2_START,
-};
-
-static struct pl061_platform_data gpio3_plat_data = {
- .gpio_base = 24,
- .irq_base = IRQ_GPIO3_START,
-};
-
-static struct pl022_ssp_controller ssp0_plat_data = {
- .bus_id = 0,
- .enable_dma = 0,
- .num_chipselect = 1,
-};
-
-#define AACI_IRQ { IRQ_AACI }
-#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
-#define KMI0_IRQ { IRQ_SIC_KMI0 }
-#define KMI1_IRQ { IRQ_SIC_KMI1 }
-
-/*
- * These devices are connected directly to the multi-layer AHB switch
- */
-#define SMC_IRQ { }
-#define MPMC_IRQ { }
-#define CLCD_IRQ { IRQ_CLCDINT }
-#define DMAC_IRQ { IRQ_DMAINT }
-
-/*
- * These devices are connected via the core APB bridge
- */
-#define SCTL_IRQ { }
-#define WATCHDOG_IRQ { IRQ_WDOGINT }
-#define GPIO0_IRQ { IRQ_GPIOINT0 }
-#define GPIO1_IRQ { IRQ_GPIOINT1 }
-#define GPIO2_IRQ { IRQ_GPIOINT2 }
-#define GPIO3_IRQ { IRQ_GPIOINT3 }
-#define RTC_IRQ { IRQ_RTCINT }
-
-/*
- * These devices are connected via the DMA APB bridge
- */
-#define SCI_IRQ { IRQ_SCIINT }
-#define UART0_IRQ { IRQ_UARTINT0 }
-#define UART1_IRQ { IRQ_UARTINT1 }
-#define UART2_IRQ { IRQ_UARTINT2 }
-#define SSP_IRQ { IRQ_SSPINT }
-
-/* FPGA Primecells */
-APB_DEVICE(aaci, "fpga:04", AACI, NULL);
-APB_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data);
-APB_DEVICE(kmi0, "fpga:06", KMI0, NULL);
-APB_DEVICE(kmi1, "fpga:07", KMI1, NULL);
-
-/* DevChip Primecells */
-AHB_DEVICE(smc, "dev:00", SMC, NULL);
-AHB_DEVICE(mpmc, "dev:10", MPMC, NULL);
-AHB_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data);
-AHB_DEVICE(dmac, "dev:30", DMAC, NULL);
-APB_DEVICE(sctl, "dev:e0", SCTL, NULL);
-APB_DEVICE(wdog, "dev:e1", WATCHDOG, NULL);
-APB_DEVICE(gpio0, "dev:e4", GPIO0, &gpio0_plat_data);
-APB_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
-APB_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
-APB_DEVICE(gpio3, "dev:e7", GPIO3, &gpio3_plat_data);
-APB_DEVICE(rtc, "dev:e8", RTC, NULL);
-APB_DEVICE(sci0, "dev:f0", SCI, NULL);
-APB_DEVICE(uart0, "dev:f1", UART0, NULL);
-APB_DEVICE(uart1, "dev:f2", UART1, NULL);
-APB_DEVICE(uart2, "dev:f3", UART2, NULL);
-APB_DEVICE(ssp0, "dev:f4", SSP, &ssp0_plat_data);
-
-static struct amba_device *amba_devs[] __initdata = {
- &dmac_device,
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &smc_device,
- &mpmc_device,
- &clcd_device,
- &sctl_device,
- &wdog_device,
- &gpio0_device,
- &gpio1_device,
- &gpio2_device,
- &gpio3_device,
- &rtc_device,
- &sci0_device,
- &ssp0_device,
- &aaci_device,
- &mmc0_device,
- &kmi0_device,
- &kmi1_device,
-};
-
-#ifdef CONFIG_OF
-/*
- * Lookup table for attaching a specific name and platform_data pointer to
- * devices as they get created by of_platform_populate(). Ideally this table
- * would not exist, but the current clock implementation depends on some devices
- * having a specific name.
- */
-struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI0_BASE, "fpga:06", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI1_BASE, "fpga:07", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART3_BASE, "fpga:09", NULL),
- /* FIXME: this is buggy, the platform data is needed for this MMC instance too */
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", NULL),
-
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART0_BASE, "dev:f1", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART1_BASE, "dev:f2", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART2_BASE, "dev:f3", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_SSP_BASE, "dev:f4", &ssp0_plat_data),
-
-#if 0
- /*
- * These entries are unnecessary because no clocks referencing
- * them. I've left them in for now as place holders in case
- * any of them need to be added back, but they should be
- * removed before actually committing this patch. --gcl
- */
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_AACI_BASE, "fpga:04", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI1_BASE, "fpga:0a", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_SMC_BASE, "dev:00", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_MPMC_BASE, "dev:10", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_DMAC_BASE, "dev:30", NULL),
-
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCTL_BASE, "dev:e0", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_WATCHDOG_BASE, "dev:e1", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO0_BASE, "dev:e4", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO1_BASE, "dev:e5", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO2_BASE, "dev:e6", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO3_BASE, "dev:e7", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_RTC_BASE, "dev:e8", NULL),
- OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI_BASE, "dev:f0", NULL),
-#endif
- {}
-};
-#endif
-
-void versatile_restart(enum reboot_mode mode, const char *cmd)
-{
- void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
- u32 val;
-
- val = __raw_readl(sys + VERSATILE_SYS_RESETCTL_OFFSET);
- val |= 0x105;
-
- __raw_writel(0xa05f, sys + VERSATILE_SYS_LOCK_OFFSET);
- __raw_writel(val, sys + VERSATILE_SYS_RESETCTL_OFFSET);
- __raw_writel(0, sys + VERSATILE_SYS_LOCK_OFFSET);
-}
-
-/* Early initializations */
-void __init versatile_init_early(void)
-{
- u32 val;
- void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
-
- osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET;
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
- versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000);
-
- /*
- * set clock frequency:
- * VERSATILE_REFCLK is 32KHz
- * VERSATILE_TIMCLK is 1MHz
- */
- val = readl(__io_address(VERSATILE_SCTL_BASE));
- writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
- __io_address(VERSATILE_SCTL_BASE));
-}
-
-void __init versatile_init(void)
-{
- int i;
-
- platform_device_register(&versatile_flash_device);
- platform_device_register(&versatile_i2c_device);
- platform_device_register(&smc91x_device);
- platform_device_register(&char_lcd_device);
- platform_device_register(&leds_device);
-
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-/*
- * Where is the timer (VA)?
- */
-#define TIMER0_VA_BASE __io_address(VERSATILE_TIMER0_1_BASE)
-#define TIMER1_VA_BASE (__io_address(VERSATILE_TIMER0_1_BASE) + 0x20)
-#define TIMER2_VA_BASE __io_address(VERSATILE_TIMER2_3_BASE)
-#define TIMER3_VA_BASE (__io_address(VERSATILE_TIMER2_3_BASE) + 0x20)
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-void __init versatile_timer_init(void)
-{
-
- /*
- * Initialise to a known state (all timers off)
- */
- sp804_timer_disable(TIMER0_VA_BASE);
- sp804_timer_disable(TIMER1_VA_BASE);
- sp804_timer_disable(TIMER2_VA_BASE);
- sp804_timer_disable(TIMER3_VA_BASE);
-
- sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
- sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0");
-}
diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h
deleted file mode 100644
index f06d5768e428..000000000000
--- a/arch/arm/mach-versatile/core.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * linux/arch/arm/mach-versatile/core.h
- *
- * Copyright (C) 2004 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 __ASM_ARCH_VERSATILE_H
-#define __ASM_ARCH_VERSATILE_H
-
-#include <linux/amba/bus.h>
-#include <linux/of_platform.h>
-#include <linux/reboot.h>
-
-extern void __init versatile_init(void);
-extern void __init versatile_init_early(void);
-extern void __init versatile_init_irq(void);
-extern void __init versatile_map_io(void);
-extern void versatile_timer_init(void);
-extern void versatile_restart(enum reboot_mode, const char *);
-extern unsigned int mmc_status(struct device *dev);
-#ifdef CONFIG_OF
-extern struct of_dev_auxdata versatile_auxdata_lookup[];
-#endif
-
-#define APB_DEVICE(name, busid, base, plat) \
-static AMBA_APB_DEVICE(name, busid, 0, VERSATILE_##base##_BASE, base##_IRQ, plat)
-
-#define AHB_DEVICE(name, busid, base, plat) \
-static AMBA_AHB_DEVICE(name, busid, 0, VERSATILE_##base##_BASE, base##_IRQ, plat)
-
-#endif
diff --git a/arch/arm/mach-versatile/include/mach/clkdev.h b/arch/arm/mach-versatile/include/mach/clkdev.h
deleted file mode 100644
index e58d0771b64e..000000000000
--- a/arch/arm/mach-versatile/include/mach/clkdev.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __ASM_MACH_CLKDEV_H
-#define __ASM_MACH_CLKDEV_H
-
-#include <plat/clock.h>
-
-struct clk {
- unsigned long rate;
- const struct clk_ops *ops;
- const struct icst_params *params;
- void __iomem *vcoreg;
-};
-
-#define __clk_get(clk) ({ 1; })
-#define __clk_put(clk) do { } while (0)
-
-#endif
diff --git a/arch/arm/mach-versatile/include/mach/hardware.h b/arch/arm/mach-versatile/include/mach/hardware.h
deleted file mode 100644
index 3e5d425e2a92..000000000000
--- a/arch/arm/mach-versatile/include/mach/hardware.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * arch/arm/mach-versatile/include/mach/hardware.h
- *
- * This file contains the hardware definitions of the Versatile boards.
- *
- * Copyright (C) 2003 ARM Limited.
- *
- * 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 __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <asm/sizes.h>
-
-/*
- * PCI space virtual addresses
- */
-#define VERSATILE_PCI_VIRT_BASE (void __iomem *)0xe8000000ul
-#define VERSATILE_PCI_CFG_VIRT_BASE (void __iomem *)0xe9000000ul
-
-/* macro to get at MMIO space when running virtually */
-#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
-
-#define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n))
-
-#endif
diff --git a/arch/arm/mach-versatile/include/mach/irqs.h b/arch/arm/mach-versatile/include/mach/irqs.h
deleted file mode 100644
index 0fd771ca617b..000000000000
--- a/arch/arm/mach-versatile/include/mach/irqs.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * arch/arm/mach-versatile/include/mach/irqs.h
- *
- * Copyright (C) 2003 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 <mach/platform.h>
-
-/*
- * IRQ interrupts definitions are the same as the INT definitions
- * held within platform.h
- */
-#define IRQ_VIC_START 32
-#define IRQ_WDOGINT (IRQ_VIC_START + INT_WDOGINT)
-#define IRQ_SOFTINT (IRQ_VIC_START + INT_SOFTINT)
-#define IRQ_COMMRx (IRQ_VIC_START + INT_COMMRx)
-#define IRQ_COMMTx (IRQ_VIC_START + INT_COMMTx)
-#define IRQ_TIMERINT0_1 (IRQ_VIC_START + INT_TIMERINT0_1)
-#define IRQ_TIMERINT2_3 (IRQ_VIC_START + INT_TIMERINT2_3)
-#define IRQ_GPIOINT0 (IRQ_VIC_START + INT_GPIOINT0)
-#define IRQ_GPIOINT1 (IRQ_VIC_START + INT_GPIOINT1)
-#define IRQ_GPIOINT2 (IRQ_VIC_START + INT_GPIOINT2)
-#define IRQ_GPIOINT3 (IRQ_VIC_START + INT_GPIOINT3)
-#define IRQ_RTCINT (IRQ_VIC_START + INT_RTCINT)
-#define IRQ_SSPINT (IRQ_VIC_START + INT_SSPINT)
-#define IRQ_UARTINT0 (IRQ_VIC_START + INT_UARTINT0)
-#define IRQ_UARTINT1 (IRQ_VIC_START + INT_UARTINT1)
-#define IRQ_UARTINT2 (IRQ_VIC_START + INT_UARTINT2)
-#define IRQ_SCIINT (IRQ_VIC_START + INT_SCIINT)
-#define IRQ_CLCDINT (IRQ_VIC_START + INT_CLCDINT)
-#define IRQ_DMAINT (IRQ_VIC_START + INT_DMAINT)
-#define IRQ_PWRFAILINT (IRQ_VIC_START + INT_PWRFAILINT)
-#define IRQ_MBXINT (IRQ_VIC_START + INT_MBXINT)
-#define IRQ_GNDINT (IRQ_VIC_START + INT_GNDINT)
-#define IRQ_VICSOURCE21 (IRQ_VIC_START + INT_VICSOURCE21)
-#define IRQ_VICSOURCE22 (IRQ_VIC_START + INT_VICSOURCE22)
-#define IRQ_VICSOURCE23 (IRQ_VIC_START + INT_VICSOURCE23)
-#define IRQ_VICSOURCE24 (IRQ_VIC_START + INT_VICSOURCE24)
-#define IRQ_VICSOURCE25 (IRQ_VIC_START + INT_VICSOURCE25)
-#define IRQ_VICSOURCE26 (IRQ_VIC_START + INT_VICSOURCE26)
-#define IRQ_VICSOURCE27 (IRQ_VIC_START + INT_VICSOURCE27)
-#define IRQ_VICSOURCE28 (IRQ_VIC_START + INT_VICSOURCE28)
-#define IRQ_VICSOURCE29 (IRQ_VIC_START + INT_VICSOURCE29)
-#define IRQ_VICSOURCE30 (IRQ_VIC_START + INT_VICSOURCE30)
-#define IRQ_VICSOURCE31 (IRQ_VIC_START + INT_VICSOURCE31)
-#define IRQ_VIC_END (IRQ_VIC_START + 31)
-
-/*
- * FIQ interrupts definitions are the same as the INT definitions.
- */
-#define FIQ_WDOGINT INT_WDOGINT
-#define FIQ_SOFTINT INT_SOFTINT
-#define FIQ_COMMRx INT_COMMRx
-#define FIQ_COMMTx INT_COMMTx
-#define FIQ_TIMERINT0_1 INT_TIMERINT0_1
-#define FIQ_TIMERINT2_3 INT_TIMERINT2_3
-#define FIQ_GPIOINT0 INT_GPIOINT0
-#define FIQ_GPIOINT1 INT_GPIOINT1
-#define FIQ_GPIOINT2 INT_GPIOINT2
-#define FIQ_GPIOINT3 INT_GPIOINT3
-#define FIQ_RTCINT INT_RTCINT
-#define FIQ_SSPINT INT_SSPINT
-#define FIQ_UARTINT0 INT_UARTINT0
-#define FIQ_UARTINT1 INT_UARTINT1
-#define FIQ_UARTINT2 INT_UARTINT2
-#define FIQ_SCIINT INT_SCIINT
-#define FIQ_CLCDINT INT_CLCDINT
-#define FIQ_DMAINT INT_DMAINT
-#define FIQ_PWRFAILINT INT_PWRFAILINT
-#define FIQ_MBXINT INT_MBXINT
-#define FIQ_GNDINT INT_GNDINT
-#define FIQ_VICSOURCE21 INT_VICSOURCE21
-#define FIQ_VICSOURCE22 INT_VICSOURCE22
-#define FIQ_VICSOURCE23 INT_VICSOURCE23
-#define FIQ_VICSOURCE24 INT_VICSOURCE24
-#define FIQ_VICSOURCE25 INT_VICSOURCE25
-#define FIQ_VICSOURCE26 INT_VICSOURCE26
-#define FIQ_VICSOURCE27 INT_VICSOURCE27
-#define FIQ_VICSOURCE28 INT_VICSOURCE28
-#define FIQ_VICSOURCE29 INT_VICSOURCE29
-#define FIQ_VICSOURCE30 INT_VICSOURCE30
-#define FIQ_VICSOURCE31 INT_VICSOURCE31
-
-
-/*
- * Secondary interrupt controller
- */
-#define IRQ_SIC_START 64
-#define IRQ_SIC_MMCI0B (IRQ_SIC_START + SIC_INT_MMCI0B)
-#define IRQ_SIC_MMCI1B (IRQ_SIC_START + SIC_INT_MMCI1B)
-#define IRQ_SIC_KMI0 (IRQ_SIC_START + SIC_INT_KMI0)
-#define IRQ_SIC_KMI1 (IRQ_SIC_START + SIC_INT_KMI1)
-#define IRQ_SIC_SCI3 (IRQ_SIC_START + SIC_INT_SCI3)
-#define IRQ_SIC_UART3 (IRQ_SIC_START + SIC_INT_UART3)
-#define IRQ_SIC_CLCD (IRQ_SIC_START + SIC_INT_CLCD)
-#define IRQ_SIC_TOUCH (IRQ_SIC_START + SIC_INT_TOUCH)
-#define IRQ_SIC_KEYPAD (IRQ_SIC_START + SIC_INT_KEYPAD)
-#define IRQ_SIC_DoC (IRQ_SIC_START + SIC_INT_DoC)
-#define IRQ_SIC_MMCI0A (IRQ_SIC_START + SIC_INT_MMCI0A)
-#define IRQ_SIC_MMCI1A (IRQ_SIC_START + SIC_INT_MMCI1A)
-#define IRQ_SIC_AACI (IRQ_SIC_START + SIC_INT_AACI)
-#define IRQ_SIC_ETH (IRQ_SIC_START + SIC_INT_ETH)
-#define IRQ_SIC_USB (IRQ_SIC_START + SIC_INT_USB)
-#define IRQ_SIC_PCI0 (IRQ_SIC_START + SIC_INT_PCI0)
-#define IRQ_SIC_PCI1 (IRQ_SIC_START + SIC_INT_PCI1)
-#define IRQ_SIC_PCI2 (IRQ_SIC_START + SIC_INT_PCI2)
-#define IRQ_SIC_PCI3 (IRQ_SIC_START + SIC_INT_PCI3)
-#define IRQ_SIC_END 95
-
-#define IRQ_GPIO0_START (IRQ_SIC_END + 1)
-#define IRQ_GPIO0_END (IRQ_GPIO0_START + 31)
-#define IRQ_GPIO1_START (IRQ_GPIO0_END + 1)
-#define IRQ_GPIO1_END (IRQ_GPIO1_START + 31)
-#define IRQ_GPIO2_START (IRQ_GPIO1_END + 1)
-#define IRQ_GPIO2_END (IRQ_GPIO2_START + 31)
-#define IRQ_GPIO3_START (IRQ_GPIO2_END + 1)
-#define IRQ_GPIO3_END (IRQ_GPIO3_START + 31)
-
-#define NR_IRQS (IRQ_GPIO3_END + 1)
diff --git a/arch/arm/mach-versatile/include/mach/platform.h b/arch/arm/mach-versatile/include/mach/platform.h
deleted file mode 100644
index 6f938ccb0c54..000000000000
--- a/arch/arm/mach-versatile/include/mach/platform.h
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * arch/arm/mach-versatile/include/mach/platform.h
- *
- * Copyright (c) ARM Limited 2003. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __address_h
-#define __address_h 1
-
-/*
- * Memory definitions
- */
-#define VERSATILE_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)...*/
-#define VERSATILE_BOOT_ROM_HI 0x30000000
-#define VERSATILE_BOOT_ROM_BASE VERSATILE_BOOT_ROM_HI /* Normal position */
-#define VERSATILE_BOOT_ROM_SIZE SZ_64M
-
-#define VERSATILE_SSRAM_BASE /* VERSATILE_SSMC_BASE ? */
-#define VERSATILE_SSRAM_SIZE SZ_2M
-
-#define VERSATILE_FLASH_BASE 0x34000000
-#define VERSATILE_FLASH_SIZE SZ_64M
-
-/*
- * SDRAM
- */
-#define VERSATILE_SDRAM_BASE 0x00000000
-
-/*
- * Logic expansion modules
- *
- */
-
-
-/* ------------------------------------------------------------------------
- * Versatile Registers
- * ------------------------------------------------------------------------
- *
- */
-#define VERSATILE_SYS_ID_OFFSET 0x00
-#define VERSATILE_SYS_SW_OFFSET 0x04
-#define VERSATILE_SYS_LED_OFFSET 0x08
-#define VERSATILE_SYS_OSC0_OFFSET 0x0C
-
-#if defined(CONFIG_ARCH_VERSATILE_PB)
-#define VERSATILE_SYS_OSC1_OFFSET 0x10
-#define VERSATILE_SYS_OSC2_OFFSET 0x14
-#define VERSATILE_SYS_OSC3_OFFSET 0x18
-#define VERSATILE_SYS_OSC4_OFFSET 0x1C
-#elif defined(CONFIG_MACH_VERSATILE_AB)
-#define VERSATILE_SYS_OSC1_OFFSET 0x1C
-#endif
-
-#define VERSATILE_SYS_OSCCLCD_OFFSET 0x1c
-
-#define VERSATILE_SYS_LOCK_OFFSET 0x20
-#define VERSATILE_SYS_100HZ_OFFSET 0x24
-#define VERSATILE_SYS_CFGDATA1_OFFSET 0x28
-#define VERSATILE_SYS_CFGDATA2_OFFSET 0x2C
-#define VERSATILE_SYS_FLAGS_OFFSET 0x30
-#define VERSATILE_SYS_FLAGSSET_OFFSET 0x30
-#define VERSATILE_SYS_FLAGSCLR_OFFSET 0x34
-#define VERSATILE_SYS_NVFLAGS_OFFSET 0x38
-#define VERSATILE_SYS_NVFLAGSSET_OFFSET 0x38
-#define VERSATILE_SYS_NVFLAGSCLR_OFFSET 0x3C
-#define VERSATILE_SYS_RESETCTL_OFFSET 0x40
-#define VERSATILE_SYS_PCICTL_OFFSET 0x44
-#define VERSATILE_SYS_MCI_OFFSET 0x48
-#define VERSATILE_SYS_FLASH_OFFSET 0x4C
-#define VERSATILE_SYS_CLCD_OFFSET 0x50
-#define VERSATILE_SYS_CLCDSER_OFFSET 0x54
-#define VERSATILE_SYS_BOOTCS_OFFSET 0x58
-#define VERSATILE_SYS_24MHz_OFFSET 0x5C
-#define VERSATILE_SYS_MISC_OFFSET 0x60
-#define VERSATILE_SYS_TEST_OSC0_OFFSET 0x80
-#define VERSATILE_SYS_TEST_OSC1_OFFSET 0x84
-#define VERSATILE_SYS_TEST_OSC2_OFFSET 0x88
-#define VERSATILE_SYS_TEST_OSC3_OFFSET 0x8C
-#define VERSATILE_SYS_TEST_OSC4_OFFSET 0x90
-
-#define VERSATILE_SYS_BASE 0x10000000
-#define VERSATILE_SYS_ID (VERSATILE_SYS_BASE + VERSATILE_SYS_ID_OFFSET)
-#define VERSATILE_SYS_SW (VERSATILE_SYS_BASE + VERSATILE_SYS_SW_OFFSET)
-#define VERSATILE_SYS_LED (VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET)
-#define VERSATILE_SYS_OSC0 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC0_OFFSET)
-#define VERSATILE_SYS_OSC1 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC1_OFFSET)
-
-#if defined(CONFIG_ARCH_VERSATILE_PB)
-#define VERSATILE_SYS_OSC2 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC2_OFFSET)
-#define VERSATILE_SYS_OSC3 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC3_OFFSET)
-#define VERSATILE_SYS_OSC4 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC4_OFFSET)
-#endif
-
-#define VERSATILE_SYS_LOCK (VERSATILE_SYS_BASE + VERSATILE_SYS_LOCK_OFFSET)
-#define VERSATILE_SYS_100HZ (VERSATILE_SYS_BASE + VERSATILE_SYS_100HZ_OFFSET)
-#define VERSATILE_SYS_CFGDATA1 (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA1_OFFSET)
-#define VERSATILE_SYS_CFGDATA2 (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA2_OFFSET)
-#define VERSATILE_SYS_FLAGS (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGS_OFFSET)
-#define VERSATILE_SYS_FLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGSSET_OFFSET)
-#define VERSATILE_SYS_FLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGSCLR_OFFSET)
-#define VERSATILE_SYS_NVFLAGS (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGS_OFFSET)
-#define VERSATILE_SYS_NVFLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSSET_OFFSET)
-#define VERSATILE_SYS_NVFLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSCLR_OFFSET)
-#define VERSATILE_SYS_RESETCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_RESETCTL_OFFSET)
-#define VERSATILE_SYS_PCICTL (VERSATILE_SYS_BASE + VERSATILE_SYS_PCICTL_OFFSET)
-#define VERSATILE_SYS_MCI (VERSATILE_SYS_BASE + VERSATILE_SYS_MCI_OFFSET)
-#define VERSATILE_SYS_FLASH (VERSATILE_SYS_BASE + VERSATILE_SYS_FLASH_OFFSET)
-#define VERSATILE_SYS_CLCD (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCD_OFFSET)
-#define VERSATILE_SYS_CLCDSER (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCDSER_OFFSET)
-#define VERSATILE_SYS_BOOTCS (VERSATILE_SYS_BASE + VERSATILE_SYS_BOOTCS_OFFSET)
-#define VERSATILE_SYS_24MHz (VERSATILE_SYS_BASE + VERSATILE_SYS_24MHz_OFFSET)
-#define VERSATILE_SYS_MISC (VERSATILE_SYS_BASE + VERSATILE_SYS_MISC_OFFSET)
-#define VERSATILE_SYS_TEST_OSC0 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC0_OFFSET)
-#define VERSATILE_SYS_TEST_OSC1 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC1_OFFSET)
-#define VERSATILE_SYS_TEST_OSC2 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC2_OFFSET)
-#define VERSATILE_SYS_TEST_OSC3 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC3_OFFSET)
-#define VERSATILE_SYS_TEST_OSC4 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC4_OFFSET)
-
-/*
- * Values for VERSATILE_SYS_RESET_CTRL
- */
-#define VERSATILE_SYS_CTRL_RESET_CONFIGCLR 0x01
-#define VERSATILE_SYS_CTRL_RESET_CONFIGINIT 0x02
-#define VERSATILE_SYS_CTRL_RESET_DLLRESET 0x03
-#define VERSATILE_SYS_CTRL_RESET_PLLRESET 0x04
-#define VERSATILE_SYS_CTRL_RESET_POR 0x05
-#define VERSATILE_SYS_CTRL_RESET_DoC 0x06
-
-#define VERSATILE_SYS_CTRL_LED (1 << 0)
-
-
-/* ------------------------------------------------------------------------
- * Versatile control registers
- * ------------------------------------------------------------------------
- */
-
-/*
- * VERSATILE_IDFIELD
- *
- * 31:24 = manufacturer (0x41 = ARM)
- * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus)
- * 15:12 = FPGA (0x3 = XVC600 or XVC600E)
- * 11:4 = build value
- * 3:0 = revision number (0x1 = rev B (AHB))
- */
-
-/*
- * VERSATILE_SYS_LOCK
- * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL,
- * SYS_CLD, SYS_BOOTCS
- */
-#define VERSATILE_SYS_LOCK_LOCKED (1 << 16)
-#define VERSATILE_SYS_LOCKVAL_MASK 0xFFFF /* write 0xA05F to enable write access */
-
-/*
- * VERSATILE_SYS_FLASH
- */
-#define VERSATILE_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */
-
-/*
- * VERSATILE_INTREG
- * - used to acknowledge and control MMCI and UART interrupts
- */
-#define VERSATILE_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */
-#define VERSATILE_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */
-#define VERSATILE_INTREG_CARDIN 0x08 /* MMCI card in detect */
- /* write 1 to acknowledge and clear */
-#define VERSATILE_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */
-#define VERSATILE_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */
-
-/*
- * VERSATILE peripheral addresses
- */
-#define VERSATILE_PCI_CORE_BASE 0x10001000 /* PCI core control */
-#define VERSATILE_I2C_BASE 0x10002000 /* I2C control */
-#define VERSATILE_SIC_BASE 0x10003000 /* Secondary interrupt controller */
-#define VERSATILE_AACI_BASE 0x10004000 /* Audio */
-#define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */
-#define VERSATILE_KMI0_BASE 0x10006000 /* KMI interface */
-#define VERSATILE_KMI1_BASE 0x10007000 /* KMI 2nd interface */
-#define VERSATILE_CHAR_LCD_BASE 0x10008000 /* Character LCD */
-#define VERSATILE_UART3_BASE 0x10009000 /* UART 3 */
-#define VERSATILE_SCI1_BASE 0x1000A000
-#define VERSATILE_MMCI1_BASE 0x1000B000 /* MMC Interface */
- /* 0x1000C000 - 0x1000CFFF = reserved */
-#define VERSATILE_ETH_BASE 0x10010000 /* Ethernet */
-#define VERSATILE_USB_BASE 0x10020000 /* USB */
- /* 0x10030000 - 0x100FFFFF = reserved */
-#define VERSATILE_SMC_BASE 0x10100000 /* SMC */
-#define VERSATILE_MPMC_BASE 0x10110000 /* MPMC */
-#define VERSATILE_CLCD_BASE 0x10120000 /* CLCD */
-#define VERSATILE_DMAC_BASE 0x10130000 /* DMA controller */
-#define VERSATILE_VIC_BASE 0x10140000 /* Vectored interrupt controller */
-#define VERSATILE_PERIPH_BASE 0x10150000 /* off-chip peripherals alias from */
- /* 0x10000000 - 0x100FFFFF */
-#define VERSATILE_AHBM_BASE 0x101D0000 /* AHB monitor */
-#define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */
-#define VERSATILE_WATCHDOG_BASE 0x101E1000 /* Watchdog */
-#define VERSATILE_TIMER0_1_BASE 0x101E2000 /* Timer 0 and 1 */
-#define VERSATILE_TIMER2_3_BASE 0x101E3000 /* Timer 2 and 3 */
-#define VERSATILE_GPIO0_BASE 0x101E4000 /* GPIO port 0 */
-#define VERSATILE_GPIO1_BASE 0x101E5000 /* GPIO port 1 */
-#define VERSATILE_GPIO2_BASE 0x101E6000 /* GPIO port 2 */
-#define VERSATILE_GPIO3_BASE 0x101E7000 /* GPIO port 3 */
-#define VERSATILE_RTC_BASE 0x101E8000 /* Real Time Clock */
- /* 0x101E9000 - reserved */
-#define VERSATILE_SCI_BASE 0x101F0000 /* Smart card controller */
-#define VERSATILE_UART0_BASE 0x101F1000 /* Uart 0 */
-#define VERSATILE_UART1_BASE 0x101F2000 /* Uart 1 */
-#define VERSATILE_UART2_BASE 0x101F3000 /* Uart 2 */
-#define VERSATILE_SSP_BASE 0x101F4000 /* Synchronous Serial Port */
-
-#define VERSATILE_SSMC_BASE 0x20000000 /* SSMC */
-#define VERSATILE_IB2_BASE 0x24000000 /* IB2 module */
-#define VERSATILE_MBX_BASE 0x40000000 /* MBX */
-
-/* PCI space */
-#define VERSATILE_PCI_BASE 0x41000000 /* PCI Interface */
-#define VERSATILE_PCI_CFG_BASE 0x42000000
-#define VERSATILE_PCI_IO_BASE 0x43000000
-#define VERSATILE_PCI_MEM_BASE0 0x44000000
-#define VERSATILE_PCI_MEM_BASE1 0x50000000
-#define VERSATILE_PCI_MEM_BASE2 0x60000000
-/* Sizes of above maps */
-#define VERSATILE_PCI_BASE_SIZE 0x01000000
-#define VERSATILE_PCI_CFG_BASE_SIZE 0x02000000
-#define VERSATILE_PCI_IO_BASE_SIZE 0x01000000
-#define VERSATILE_PCI_MEM_BASE0_SIZE 0x0c000000 /* 32Mb */
-#define VERSATILE_PCI_MEM_BASE1_SIZE 0x10000000 /* 256Mb */
-#define VERSATILE_PCI_MEM_BASE2_SIZE 0x10000000 /* 256Mb */
-
-#define VERSATILE_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */
-#define VERSATILE_LT_BASE 0x80000000 /* Logic Tile expansion */
-
-/*
- * Disk on Chip
- */
-#define VERSATILE_DOC_BASE 0x2C000000
-#define VERSATILE_DOC_SIZE (16 << 20)
-#define VERSATILE_DOC_PAGE_SIZE 512
-#define VERSATILE_DOC_TOTAL_PAGES (DOC_SIZE / PAGE_SIZE)
-
-#define ERASE_UNIT_PAGES 32
-#define START_PAGE 0x80
-
-/*
- * LED settings, bits [7:0]
- */
-#define VERSATILE_SYS_LED0 (1 << 0)
-#define VERSATILE_SYS_LED1 (1 << 1)
-#define VERSATILE_SYS_LED2 (1 << 2)
-#define VERSATILE_SYS_LED3 (1 << 3)
-#define VERSATILE_SYS_LED4 (1 << 4)
-#define VERSATILE_SYS_LED5 (1 << 5)
-#define VERSATILE_SYS_LED6 (1 << 6)
-#define VERSATILE_SYS_LED7 (1 << 7)
-
-#define ALL_LEDS 0xFF
-
-#define LED_BANK VERSATILE_SYS_LED
-
-/*
- * Control registers
- */
-#define VERSATILE_IDFIELD_OFFSET 0x0 /* Versatile build information */
-#define VERSATILE_FLASHPROG_OFFSET 0x4 /* Flash devices */
-#define VERSATILE_INTREG_OFFSET 0x8 /* Interrupt control */
-#define VERSATILE_DECODE_OFFSET 0xC /* Fitted logic modules */
-
-
-/* ------------------------------------------------------------------------
- * Versatile Interrupt Controller - control registers
- * ------------------------------------------------------------------------
- *
- * Offsets from interrupt controller base
- *
- * System Controller interrupt controller base is
- *
- * VERSATILE_IC_BASE
- *
- * Core Module interrupt controller base is
- *
- * VERSATILE_SYS_IC
- *
- */
-/* VIC definitions in include/asm-arm/hardware/vic.h */
-
-#define SIC_IRQ_STATUS 0
-#define SIC_IRQ_RAW_STATUS 0x04
-#define SIC_IRQ_ENABLE 0x08
-#define SIC_IRQ_ENABLE_SET 0x08
-#define SIC_IRQ_ENABLE_CLEAR 0x0C
-#define SIC_INT_SOFT_SET 0x10
-#define SIC_INT_SOFT_CLEAR 0x14
-#define SIC_INT_PIC_ENABLE 0x20 /* read status of pass through mask */
-#define SIC_INT_PIC_ENABLES 0x20 /* set interrupt pass through bits */
-#define SIC_INT_PIC_ENABLEC 0x24 /* Clear interrupt pass through bits */
-
-/* ------------------------------------------------------------------------
- * Interrupts - bit assignment (primary)
- * ------------------------------------------------------------------------
- */
-
-#define INT_WDOGINT 0 /* Watchdog timer */
-#define INT_SOFTINT 1 /* Software interrupt */
-#define INT_COMMRx 2 /* Debug Comm Rx interrupt */
-#define INT_COMMTx 3 /* Debug Comm Tx interrupt */
-#define INT_TIMERINT0_1 4 /* Timer 0 and 1 */
-#define INT_TIMERINT2_3 5 /* Timer 2 and 3 */
-#define INT_GPIOINT0 6 /* GPIO 0 */
-#define INT_GPIOINT1 7 /* GPIO 1 */
-#define INT_GPIOINT2 8 /* GPIO 2 */
-#define INT_GPIOINT3 9 /* GPIO 3 */
-#define INT_RTCINT 10 /* Real Time Clock */
-#define INT_SSPINT 11 /* Synchronous Serial Port */
-#define INT_UARTINT0 12 /* UART 0 on development chip */
-#define INT_UARTINT1 13 /* UART 1 on development chip */
-#define INT_UARTINT2 14 /* UART 2 on development chip */
-#define INT_SCIINT 15 /* Smart Card Interface */
-#define INT_CLCDINT 16 /* CLCD controller */
-#define INT_DMAINT 17 /* DMA controller */
-#define INT_PWRFAILINT 18 /* Power failure */
-#define INT_MBXINT 19 /* Graphics processor */
-#define INT_GNDINT 20 /* Reserved */
- /* External interrupt signals from logic tiles or secondary controller */
-#define INT_VICSOURCE21 21 /* Disk on Chip */
-#define INT_VICSOURCE22 22 /* MCI0A */
-#define INT_VICSOURCE23 23 /* MCI1A */
-#define INT_VICSOURCE24 24 /* AACI */
-#define INT_VICSOURCE25 25 /* Ethernet */
-#define INT_VICSOURCE26 26 /* USB */
-#define INT_VICSOURCE27 27 /* PCI 0 */
-#define INT_VICSOURCE28 28 /* PCI 1 */
-#define INT_VICSOURCE29 29 /* PCI 2 */
-#define INT_VICSOURCE30 30 /* PCI 3 */
-#define INT_VICSOURCE31 31 /* SIC source */
-
-#define VERSATILE_SC_VALID_INT 0x003FFFFF
-
-#define MAXIRQNUM 31
-#define MAXFIQNUM 31
-#define MAXSWINUM 31
-
-/* ------------------------------------------------------------------------
- * Interrupts - bit assignment (secondary)
- * ------------------------------------------------------------------------
- */
-#define SIC_INT_MMCI0B 1 /* Multimedia Card 0B */
-#define SIC_INT_MMCI1B 2 /* Multimedia Card 1B */
-#define SIC_INT_KMI0 3 /* Keyboard/Mouse port 0 */
-#define SIC_INT_KMI1 4 /* Keyboard/Mouse port 1 */
-#define SIC_INT_SCI3 5 /* Smart Card interface */
-#define SIC_INT_UART3 6 /* UART 3 empty or data available */
-#define SIC_INT_CLCD 7 /* Character LCD */
-#define SIC_INT_TOUCH 8 /* Touchscreen */
-#define SIC_INT_KEYPAD 9 /* Key pressed on display keypad */
- /* 10:20 - reserved */
-#define SIC_INT_DoC 21 /* Disk on Chip memory controller */
-#define SIC_INT_MMCI0A 22 /* MMC 0A */
-#define SIC_INT_MMCI1A 23 /* MMC 1A */
-#define SIC_INT_AACI 24 /* Audio Codec */
-#define SIC_INT_ETH 25 /* Ethernet controller */
-#define SIC_INT_USB 26 /* USB controller */
-#define SIC_INT_PCI0 27
-#define SIC_INT_PCI1 28
-#define SIC_INT_PCI2 29
-#define SIC_INT_PCI3 30
-
-
-/*
- * System controller bit assignment
- */
-#define VERSATILE_REFCLK 0
-#define VERSATILE_TIMCLK 1
-
-#define VERSATILE_TIMER1_EnSel 15
-#define VERSATILE_TIMER2_EnSel 17
-#define VERSATILE_TIMER3_EnSel 19
-#define VERSATILE_TIMER4_EnSel 21
-
-
-#define VERSATILE_CSR_BASE 0x10000000
-#define VERSATILE_CSR_SIZE 0x10000000
-
-#ifdef CONFIG_MACH_VERSATILE_AB
-/*
- * IB2 Versatile/AB expansion board definitions
- */
-#define VERSATILE_IB2_CAMERA_BANK VERSATILE_IB2_BASE
-#define VERSATILE_IB2_KBD_DATAREG (VERSATILE_IB2_BASE + 0x01000000)
-
-/* VICINTSOURCE27 */
-#define VERSATILE_IB2_INT_BASE (VERSATILE_IB2_BASE + 0x02000000)
-#define VERSATILE_IB2_IER (VERSATILE_IB2_INT_BASE + 0)
-#define VERSATILE_IB2_ISR (VERSATILE_IB2_INT_BASE + 4)
-
-#define VERSATILE_IB2_CTL_BASE (VERSATILE_IB2_BASE + 0x03000000)
-#define VERSATILE_IB2_CTRL (VERSATILE_IB2_CTL_BASE + 0)
-#define VERSATILE_IB2_STAT (VERSATILE_IB2_CTL_BASE + 4)
-#endif
-
-#endif
diff --git a/arch/arm/mach-versatile/include/mach/uncompress.h b/arch/arm/mach-versatile/include/mach/uncompress.h
deleted file mode 100644
index 986e3d303f3c..000000000000
--- a/arch/arm/mach-versatile/include/mach/uncompress.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * arch/arm/mach-versatile/include/mach/uncompress.h
- *
- * Copyright (C) 2003 ARM Limited
- *
- * 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
- */
-#define AMBA_UART_DR (*(volatile unsigned char *)0x101F1000)
-#define AMBA_UART_LCRH (*(volatile unsigned char *)0x101F102C)
-#define AMBA_UART_CR (*(volatile unsigned char *)0x101F1030)
-#define AMBA_UART_FR (*(volatile unsigned char *)0x101F1018)
-
-/*
- * This does not append a newline
- */
-static inline void putc(int c)
-{
- while (AMBA_UART_FR & (1 << 5))
- barrier();
-
- AMBA_UART_DR = c;
-}
-
-static inline void flush(void)
-{
- while (AMBA_UART_FR & (1 << 3))
- barrier();
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
deleted file mode 100644
index c97be4ea76d2..000000000000
--- a/arch/arm/mach-versatile/pci.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * linux/arch/arm/mach-versatile/pci.c
- *
- * (C) Copyright Koninklijke Philips Electronics NV 2004. All rights reserved.
- * You can redistribute and/or modify this software under the terms of version 2
- * of the GNU General Public License as published by the Free Software Foundation.
- * THIS SOFTWARE IS PROVIDED "AS IS" 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.
- * Koninklijke Philips Electronics nor its subsidiaries is obligated to provide any support for this software.
- *
- * ARM Versatile PCI driver.
- *
- * 14/04/2005 Initial version, colin.king@philips.com
- *
- */
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <asm/irq.h>
-#include <asm/mach/pci.h>
-
-/*
- * these spaces are mapped using the following base registers:
- *
- * Usage Local Bus Memory Base/Map registers used
- *
- * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0, non prefetch
- * Mem 60000000 - 6FFFFFFF LB_BASE1/LB_MAP1, prefetch
- * IO 44000000 - 4FFFFFFF LB_BASE2/LB_MAP2, IO
- * Cfg 42000000 - 42FFFFFF PCI config
- *
- */
-#define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n))
-#define SYS_PCICTL __IO_ADDRESS(VERSATILE_SYS_PCICTL)
-#define PCI_IMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
-#define PCI_IMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
-#define PCI_IMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
-#define PCI_SMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
-#define PCI_SMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
-#define PCI_SMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x1c)
-#define PCI_SELFID __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
-
-#define DEVICE_ID_OFFSET 0x00
-#define CSR_OFFSET 0x04
-#define CLASS_ID_OFFSET 0x08
-
-#define VP_PCI_DEVICE_ID 0x030010ee
-#define VP_PCI_CLASS_ID 0x0b400000
-
-static unsigned long pci_slot_ignore = 0;
-
-static int __init versatile_pci_slot_ignore(char *str)
-{
- int retval;
- int slot;
-
- while ((retval = get_option(&str,&slot))) {
- if ((slot < 0) || (slot > 31)) {
- printk("Illegal slot value: %d\n",slot);
- } else {
- pci_slot_ignore |= (1 << slot);
- }
- }
- return 1;
-}
-
-__setup("pci_slot_ignore=", versatile_pci_slot_ignore);
-
-
-static void __iomem *__pci_addr(struct pci_bus *bus,
- unsigned int devfn, int offset)
-{
- unsigned int busnr = bus->number;
-
- /*
- * Trap out illegal values
- */
- if (offset > 255)
- BUG();
- if (busnr > 255)
- BUG();
- if (devfn > 255)
- BUG();
-
- return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) |
- (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset);
-}
-
-static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 *val)
-{
- void __iomem *addr = __pci_addr(bus, devfn, where & ~3);
- u32 v;
- int slot = PCI_SLOT(devfn);
-
- if (pci_slot_ignore & (1 << slot)) {
- /* Ignore this slot */
- switch (size) {
- case 1:
- v = 0xff;
- break;
- case 2:
- v = 0xffff;
- break;
- default:
- v = 0xffffffff;
- }
- } else {
- switch (size) {
- case 1:
- v = __raw_readl(addr);
- if (where & 2) v >>= 16;
- if (where & 1) v >>= 8;
- v &= 0xff;
- break;
-
- case 2:
- v = __raw_readl(addr);
- if (where & 2) v >>= 16;
- v &= 0xffff;
- break;
-
- default:
- v = __raw_readl(addr);
- break;
- }
- }
-
- *val = v;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 val)
-{
- void __iomem *addr = __pci_addr(bus, devfn, where);
- int slot = PCI_SLOT(devfn);
-
- if (pci_slot_ignore & (1 << slot)) {
- return PCIBIOS_SUCCESSFUL;
- }
-
- switch (size) {
- case 1:
- __raw_writeb((u8)val, addr);
- break;
-
- case 2:
- __raw_writew((u16)val, addr);
- break;
-
- case 4:
- __raw_writel(val, addr);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_versatile_ops = {
- .read = versatile_read_config,
- .write = versatile_write_config,
-};
-
-static struct resource unused_mem = {
- .name = "PCI unused",
- .start = VERSATILE_PCI_MEM_BASE0,
- .end = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct resource non_mem = {
- .name = "PCI non-prefetchable",
- .start = VERSATILE_PCI_MEM_BASE1,
- .end = VERSATILE_PCI_MEM_BASE1+VERSATILE_PCI_MEM_BASE1_SIZE-1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct resource pre_mem = {
- .name = "PCI prefetchable",
- .start = VERSATILE_PCI_MEM_BASE2,
- .end = VERSATILE_PCI_MEM_BASE2+VERSATILE_PCI_MEM_BASE2_SIZE-1,
- .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
-};
-
-static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
-{
- int ret = 0;
-
- ret = request_resource(&iomem_resource, &unused_mem);
- if (ret) {
- printk(KERN_ERR "PCI: unable to allocate unused "
- "memory region (%d)\n", ret);
- goto out;
- }
- ret = request_resource(&iomem_resource, &non_mem);
- if (ret) {
- printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
- "memory region (%d)\n", ret);
- goto release_unused_mem;
- }
- ret = request_resource(&iomem_resource, &pre_mem);
- if (ret) {
- printk(KERN_ERR "PCI: unable to allocate prefetchable "
- "memory region (%d)\n", ret);
- goto release_non_mem;
- }
-
- /*
- * the mem resource for this bus
- * the prefetch mem resource for this bus
- */
- pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
- pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
-
- goto out;
-
- release_non_mem:
- release_resource(&non_mem);
- release_unused_mem:
- release_resource(&unused_mem);
- out:
- return ret;
-}
-
-int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
-{
- int ret = 0;
- int i;
- int myslot = -1;
- unsigned long val;
- void __iomem *local_pci_cfg_base;
-
- val = __raw_readl(SYS_PCICTL);
- if (!(val & 1)) {
- printk("Not plugged into PCI backplane!\n");
- ret = -EIO;
- goto out;
- }
-
- ret = pci_ioremap_io(0, VERSATILE_PCI_IO_BASE);
- if (ret)
- goto out;
-
- if (nr == 0) {
- ret = pci_versatile_setup_resources(sys);
- if (ret < 0) {
- printk("pci_versatile_setup: resources... oops?\n");
- goto out;
- }
- } else {
- printk("pci_versatile_setup: resources... nr == 0??\n");
- goto out;
- }
-
- /*
- * We need to discover the PCI core first to configure itself
- * before the main PCI probing is performed
- */
- for (i=0; i<32; i++)
- if ((__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+DEVICE_ID_OFFSET) == VP_PCI_DEVICE_ID) &&
- (__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+CLASS_ID_OFFSET) == VP_PCI_CLASS_ID)) {
- myslot = i;
- break;
- }
-
- if (myslot == -1) {
- printk("Cannot find PCI core!\n");
- ret = -EIO;
- goto out;
- }
-
- printk("PCI core found (slot %d)\n",myslot);
-
- __raw_writel(myslot, PCI_SELFID);
- local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
-
- val = __raw_readl(local_pci_cfg_base + CSR_OFFSET);
- val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
- __raw_writel(val, local_pci_cfg_base + CSR_OFFSET);
-
- /*
- * Configure the PCI inbound memory windows to be 1:1 mapped to SDRAM
- */
- __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_0);
- __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
- __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
-
- /*
- * For many years the kernel and QEMU were symbiotically buggy
- * in that they both assumed the same broken IRQ mapping.
- * QEMU therefore attempts to auto-detect old broken kernels
- * so that they still work on newer QEMU as they did on old
- * QEMU. Since we now use the correct (ie matching-hardware)
- * IRQ mapping we write a definitely different value to a
- * PCI_INTERRUPT_LINE register to tell QEMU that we expect
- * real hardware behaviour and it need not be backwards
- * compatible for us. This write is harmless on real hardware.
- */
- __raw_writel(0, VERSATILE_PCI_VIRT_BASE+PCI_INTERRUPT_LINE);
-
- /*
- * Do not to map Versatile FPGA PCI device into memory space
- */
- pci_slot_ignore |= (1 << myslot);
- ret = 1;
-
- out:
- return ret;
-}
-
-
-void __init pci_versatile_preinit(void)
-{
- pcibios_min_mem = 0x50000000;
-
- __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28, PCI_IMAP0);
- __raw_writel(VERSATILE_PCI_MEM_BASE1 >> 28, PCI_IMAP1);
- __raw_writel(VERSATILE_PCI_MEM_BASE2 >> 28, PCI_IMAP2);
-
- __raw_writel(PHYS_OFFSET >> 28, PCI_SMAP0);
- __raw_writel(PHYS_OFFSET >> 28, PCI_SMAP1);
- __raw_writel(PHYS_OFFSET >> 28, PCI_SMAP2);
-
- __raw_writel(1, SYS_PCICTL);
-}
-
-/*
- * map the specified device/slot/pin to an IRQ. Different backplanes may need to modify this.
- */
-static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- int irq;
-
- /*
- * Slot INTA INTB INTC INTD
- * 31 PCI1 PCI2 PCI3 PCI0
- * 30 PCI0 PCI1 PCI2 PCI3
- * 29 PCI3 PCI0 PCI1 PCI2
- */
- irq = IRQ_SIC_PCI0 + ((slot + 2 + pin - 1) & 3);
-
- return irq;
-}
-
-static struct hw_pci versatile_pci __initdata = {
- .map_irq = versatile_map_irq,
- .nr_controllers = 1,
- .ops = &pci_versatile_ops,
- .setup = pci_versatile_setup,
- .preinit = pci_versatile_preinit,
-};
-
-static int __init versatile_pci_init(void)
-{
- pci_common_init(&versatile_pci);
- return 0;
-}
-
-subsys_initcall(versatile_pci_init);
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c
deleted file mode 100644
index 1caef1093793..000000000000
--- a/arch/arm/mach-versatile/versatile_ab.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * linux/arch/arm/mach-versatile/versatile_ab.c
- *
- * Copyright (C) 2004 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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/device.h>
-#include <linux/amba/bus.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-
-#include "core.h"
-
-MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .map_io = versatile_map_io,
- .init_early = versatile_init_early,
- .init_irq = versatile_init_irq,
- .init_time = versatile_timer_init,
- .init_machine = versatile_init,
- .restart = versatile_restart,
-MACHINE_END
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c
index 7de3e92a13b0..c44871851255 100644
--- a/arch/arm/mach-versatile/versatile_dt.c
+++ b/arch/arm/mach-versatile/versatile_dt.c
@@ -22,15 +22,389 @@
*/
#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/platform_data/video-clcd-versatile.h>
+#include <linux/amba/mmci.h>
+#include <linux/mtd/physmap.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
-#include "core.h"
+/* macro to get at MMIO space when running virtually */
+#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
+#define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n))
+
+/*
+ * Memory definitions
+ */
+#define VERSATILE_FLASH_BASE 0x34000000
+#define VERSATILE_FLASH_SIZE SZ_64M
+
+/*
+ * ------------------------------------------------------------------------
+ * Versatile Registers
+ * ------------------------------------------------------------------------
+ */
+#define VERSATILE_SYS_LOCK_OFFSET 0x20
+#define VERSATILE_SYS_RESETCTL_OFFSET 0x40
+#define VERSATILE_SYS_PCICTL_OFFSET 0x44
+#define VERSATILE_SYS_MCI_OFFSET 0x48
+#define VERSATILE_SYS_FLASH_OFFSET 0x4C
+#define VERSATILE_SYS_CLCD_OFFSET 0x50
+
+/*
+ * VERSATILE_SYS_FLASH
+ */
+#define VERSATILE_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */
+
+/*
+ * VERSATILE peripheral addresses
+ */
+#define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */
+#define VERSATILE_MMCI1_BASE 0x1000B000 /* MMC Interface */
+#define VERSATILE_CLCD_BASE 0x10120000 /* CLCD */
+#define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */
+#define VERSATILE_IB2_BASE 0x24000000 /* IB2 module */
+#define VERSATILE_IB2_CTL_BASE (VERSATILE_IB2_BASE + 0x03000000)
+
+/*
+ * System controller bit assignment
+ */
+#define VERSATILE_REFCLK 0
+#define VERSATILE_TIMCLK 1
+
+#define VERSATILE_TIMER1_EnSel 15
+#define VERSATILE_TIMER2_EnSel 17
+#define VERSATILE_TIMER3_EnSel 19
+#define VERSATILE_TIMER4_EnSel 21
+
+static void __iomem *versatile_sys_base;
+static void __iomem *versatile_ib2_ctrl;
+
+static void versatile_flash_set_vpp(struct platform_device *pdev, int on)
+{
+ u32 val;
+
+ val = readl(versatile_sys_base + VERSATILE_SYS_FLASH_OFFSET);
+ if (on)
+ val |= VERSATILE_FLASHPROG_FLVPPEN;
+ else
+ val &= ~VERSATILE_FLASHPROG_FLVPPEN;
+ writel(val, versatile_sys_base + VERSATILE_SYS_FLASH_OFFSET);
+}
+
+static struct physmap_flash_data versatile_flash_data = {
+ .width = 4,
+ .set_vpp = versatile_flash_set_vpp,
+};
+
+static struct resource versatile_flash_resource = {
+ .start = VERSATILE_FLASH_BASE,
+ .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct platform_device versatile_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &versatile_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &versatile_flash_resource,
+};
+
+unsigned int mmc_status(struct device *dev)
+{
+ struct amba_device *adev = container_of(dev, struct amba_device, dev);
+ u32 mask;
+
+ if (adev->res.start == VERSATILE_MMCI0_BASE)
+ mask = 1;
+ else
+ mask = 2;
+
+ return readl(versatile_sys_base + VERSATILE_SYS_MCI_OFFSET) & mask;
+}
+
+static struct mmci_platform_data mmc0_plat_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .status = mmc_status,
+ .gpio_wp = -1,
+ .gpio_cd = -1,
+};
+
+static struct mmci_platform_data mmc1_plat_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .status = mmc_status,
+ .gpio_wp = -1,
+ .gpio_cd = -1,
+};
+
+/*
+ * CLCD support.
+ */
+#define SYS_CLCD_MODE_MASK (3 << 0)
+#define SYS_CLCD_MODE_888 (0 << 0)
+#define SYS_CLCD_MODE_5551 (1 << 0)
+#define SYS_CLCD_MODE_565_RLSB (2 << 0)
+#define SYS_CLCD_MODE_565_BLSB (3 << 0)
+#define SYS_CLCD_NLCDIOON (1 << 2)
+#define SYS_CLCD_VDDPOSSWITCH (1 << 3)
+#define SYS_CLCD_PWR3V5SWITCH (1 << 4)
+#define SYS_CLCD_ID_MASK (0x1f << 8)
+#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
+#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
+#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
+#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
+#define SYS_CLCD_ID_VGA (0x1f << 8)
+
+static bool is_sanyo_2_5_lcd;
+
+/*
+ * Disable all display connectors on the interface module.
+ */
+static void versatile_clcd_disable(struct clcd_fb *fb)
+{
+ void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
+ u32 val;
+
+ val = readl(sys_clcd);
+ val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
+ writel(val, sys_clcd);
+
+ /*
+ * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
+ */
+ if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
+ unsigned long ctrl;
+
+ ctrl = readl(versatile_ib2_ctrl);
+ ctrl &= ~0x01;
+ writel(ctrl, versatile_ib2_ctrl);
+ }
+}
+
+/*
+ * Enable the relevant connector on the interface module.
+ */
+static void versatile_clcd_enable(struct clcd_fb *fb)
+{
+ struct fb_var_screeninfo *var = &fb->fb.var;
+ void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
+ u32 val;
+
+ val = readl(sys_clcd);
+ val &= ~SYS_CLCD_MODE_MASK;
+
+ switch (var->green.length) {
+ case 5:
+ val |= SYS_CLCD_MODE_5551;
+ break;
+ case 6:
+ if (var->red.offset == 0)
+ val |= SYS_CLCD_MODE_565_RLSB;
+ else
+ val |= SYS_CLCD_MODE_565_BLSB;
+ break;
+ case 8:
+ val |= SYS_CLCD_MODE_888;
+ break;
+ }
+
+ /*
+ * Set the MUX
+ */
+ writel(val, sys_clcd);
+
+ /*
+ * And now enable the PSUs
+ */
+ val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
+ writel(val, sys_clcd);
+
+ /*
+ * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
+ */
+ if (of_machine_is_compatible("arm,versatile-ab") && is_sanyo_2_5_lcd) {
+ unsigned long ctrl;
+
+ ctrl = readl(versatile_ib2_ctrl);
+ ctrl |= 0x01;
+ writel(ctrl, versatile_ib2_ctrl);
+ }
+}
+
+/*
+ * Detect which LCD panel is connected, and return the appropriate
+ * clcd_panel structure. Note: we do not have any information on
+ * the required timings for the 8.4in panel, so we presently assume
+ * VGA timings.
+ */
+static int versatile_clcd_setup(struct clcd_fb *fb)
+{
+ void __iomem *sys_clcd = versatile_sys_base + VERSATILE_SYS_CLCD_OFFSET;
+ const char *panel_name;
+ u32 val;
+
+ is_sanyo_2_5_lcd = false;
+
+ val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
+ if (val == SYS_CLCD_ID_SANYO_3_8)
+ panel_name = "Sanyo TM38QV67A02A";
+ else if (val == SYS_CLCD_ID_SANYO_2_5) {
+ panel_name = "Sanyo QVGA Portrait";
+ is_sanyo_2_5_lcd = true;
+ } else if (val == SYS_CLCD_ID_EPSON_2_2)
+ panel_name = "Epson L2F50113T00";
+ else if (val == SYS_CLCD_ID_VGA)
+ panel_name = "VGA";
+ else {
+ printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
+ val);
+ panel_name = "VGA";
+ }
+
+ fb->panel = versatile_clcd_get_panel(panel_name);
+ if (!fb->panel)
+ return -EINVAL;
+
+ return versatile_clcd_setup_dma(fb, SZ_1M);
+}
+
+static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
+{
+ clcdfb_decode(fb, regs);
+
+ /* Always clear BGR for RGB565: we do the routing externally */
+ if (fb->fb.var.green.length == 6)
+ regs->cntl &= ~CNTL_BGR;
+}
+
+static struct clcd_board clcd_plat_data = {
+ .name = "Versatile",
+ .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
+ .check = clcdfb_check,
+ .decode = versatile_clcd_decode,
+ .disable = versatile_clcd_disable,
+ .enable = versatile_clcd_enable,
+ .setup = versatile_clcd_setup,
+ .mmap = versatile_clcd_mmap_dma,
+ .remove = versatile_clcd_remove_dma,
+};
+
+/*
+ * Lookup table for attaching a specific name and platform_data pointer to
+ * devices as they get created by of_platform_populate(). Ideally this table
+ * would not exist, but the current clock implementation depends on some devices
+ * having a specific name.
+ */
+struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
+ {}
+};
+
+static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
+ {
+ .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE),
+ .length = SZ_4K * 9,
+ .type = MT_DEVICE
+ }
+};
+
+static void __init versatile_map_io(void)
+{
+ debug_ll_io_init();
+ iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
+}
+
+static void __init versatile_init_early(void)
+{
+ u32 val;
+
+ /*
+ * set clock frequency:
+ * VERSATILE_REFCLK is 32KHz
+ * VERSATILE_TIMCLK is 1MHz
+ */
+ val = readl(__io_address(VERSATILE_SCTL_BASE));
+ writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
+ __io_address(VERSATILE_SCTL_BASE));
+}
+
+static void versatile_restart(enum reboot_mode mode, const char *cmd)
+{
+ u32 val;
+
+ val = readl(versatile_sys_base + VERSATILE_SYS_RESETCTL_OFFSET);
+ val |= 0x105;
+
+ writel(0xa05f, versatile_sys_base + VERSATILE_SYS_LOCK_OFFSET);
+ writel(val, versatile_sys_base + VERSATILE_SYS_RESETCTL_OFFSET);
+ writel(0, versatile_sys_base + VERSATILE_SYS_LOCK_OFFSET);
+}
+
+static void __init versatile_dt_pci_init(void)
+{
+ u32 val;
+ struct device_node *np;
+ struct property *newprop;
+
+ np = of_find_compatible_node(NULL, NULL, "arm,versatile-pci");
+ if (!np)
+ return;
+
+ /* Check if PCI backplane is detected */
+ val = readl(versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
+ if (val & 1) {
+ /*
+ * Enable PCI accesses. Note that the documentaton is
+ * inconsistent whether or not this is needed, but the old
+ * driver had it so we will keep it.
+ */
+ writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
+ return;
+ }
+
+ newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
+ if (!newprop)
+ return;
+
+ newprop->name = kstrdup("status", GFP_KERNEL);
+ newprop->value = kstrdup("disabled", GFP_KERNEL);
+ newprop->length = sizeof("disabled");
+ of_update_property(np, newprop);
+
+ pr_info("Not plugged into PCI backplane!\n");
+}
static void __init versatile_dt_init(void)
{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "arm,core-module-versatile");
+ if (np)
+ versatile_sys_base = of_iomap(np, 0);
+ WARN_ON(!versatile_sys_base);
+
+ versatile_ib2_ctrl = ioremap(VERSATILE_IB2_CTL_BASE, SZ_4K);
+
+ versatile_dt_pci_init();
+
+ platform_device_register(&versatile_flash_device);
of_platform_populate(NULL, of_default_bus_match_table,
versatile_auxdata_lookup, NULL);
}
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
deleted file mode 100644
index 9a53d0bd9144..000000000000
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * linux/arch/arm/mach-versatile/versatile_pb.c
- *
- * Copyright (C) 2004 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-
-#include "core.h"
-
-#if 1
-#define IRQ_MMCI1A IRQ_VICSOURCE23
-#else
-#define IRQ_MMCI1A IRQ_SIC_MMCI1A
-#endif
-
-static struct mmci_platform_data mmc1_plat_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .status = mmc_status,
- .gpio_wp = -1,
- .gpio_cd = -1,
-};
-
-#define UART3_IRQ { IRQ_SIC_UART3 }
-#define SCI1_IRQ { IRQ_SIC_SCI3 }
-#define MMCI1_IRQ { IRQ_MMCI1A, IRQ_SIC_MMCI1B }
-
-/*
- * These devices are connected via the DMA APB bridge
- */
-
-/* FPGA Primecells */
-APB_DEVICE(uart3, "fpga:09", UART3, NULL);
-APB_DEVICE(sci1, "fpga:0a", SCI1, NULL);
-APB_DEVICE(mmc1, "fpga:0b", MMCI1, &mmc1_plat_data);
-
-
-static struct amba_device *amba_devs[] __initdata = {
- &uart3_device,
- &sci1_device,
- &mmc1_device,
-};
-
-static void __init versatile_pb_init(void)
-{
- int i;
-
- versatile_init();
-
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .map_io = versatile_map_io,
- .init_early = versatile_init_early,
- .init_irq = versatile_init_irq,
- .init_time = versatile_timer_init,
- .init_machine = versatile_pb_init,
- .restart = versatile_restart,
-MACHINE_END
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 10f9389572da..398a297b7e09 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_VEXPRESS
- bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7
+ bool "ARM Ltd. Versatile Express family"
+ depends on ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h
index 2a11d3ac8c68..a162ab46ee02 100644
--- a/arch/arm/mach-vexpress/core.h
+++ b/arch/arm/mach-vexpress/core.h
@@ -1,5 +1,5 @@
bool vexpress_smp_init_ops(void);
-extern struct smp_operations vexpress_smp_dt_ops;
+extern const struct smp_operations vexpress_smp_dt_ops;
extern void vexpress_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 83188cf1875d..8b8d0724f6c6 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -64,7 +64,7 @@ static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus)
vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
}
-struct smp_operations __initdata vexpress_smp_dt_ops = {
+const struct smp_operations vexpress_smp_dt_ops __initconst = {
.smp_prepare_cpus = vexpress_smp_dt_prepare_cpus,
.smp_secondary_init = versatile_secondary_init,
.smp_boot_secondary = versatile_boot_secondary,
diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c
index 213230ee57d1..ca763251ffe0 100644
--- a/arch/arm/mach-w90x900/cpu.c
+++ b/arch/arm/mach-w90x900/cpu.c
@@ -33,8 +33,8 @@
#include <mach/hardware.h>
#include <mach/regs-serial.h>
#include <mach/regs-clock.h>
-#include <mach/regs-ebi.h>
-#include <mach/regs-timer.h>
+#include "regs-ebi.h"
+#include "regs-timer.h"
#include "cpu.h"
#include "clock.h"
diff --git a/arch/arm/mach-w90x900/include/mach/regs-ebi.h b/arch/arm/mach-w90x900/regs-ebi.h
index b68455e7f88b..b68455e7f88b 100644
--- a/arch/arm/mach-w90x900/include/mach/regs-ebi.h
+++ b/arch/arm/mach-w90x900/regs-ebi.h
diff --git a/arch/arm/mach-w90x900/include/mach/regs-gcr.h b/arch/arm/mach-w90x900/regs-gcr.h
index 6087abd93ef5..6087abd93ef5 100644
--- a/arch/arm/mach-w90x900/include/mach/regs-gcr.h
+++ b/arch/arm/mach-w90x900/regs-gcr.h
diff --git a/arch/arm/mach-w90x900/include/mach/regs-timer.h b/arch/arm/mach-w90x900/regs-timer.h
index 8f390620c0e4..8f390620c0e4 100644
--- a/arch/arm/mach-w90x900/include/mach/regs-timer.h
+++ b/arch/arm/mach-w90x900/regs-timer.h
diff --git a/arch/arm/mach-w90x900/include/mach/regs-usb.h b/arch/arm/mach-w90x900/regs-usb.h
index ab74b0c2480b..ab74b0c2480b 100644
--- a/arch/arm/mach-w90x900/include/mach/regs-usb.h
+++ b/arch/arm/mach-w90x900/regs-usb.h
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
index cd1966ec9143..cda085245e34 100644
--- a/arch/arm/mach-w90x900/time.c
+++ b/arch/arm/mach-w90x900/time.c
@@ -31,7 +31,7 @@
#include <asm/mach/time.h>
#include <mach/map.h>
-#include <mach/regs-timer.h>
+#include "regs-timer.h"
#include "nuc9xx.h"
diff --git a/arch/arm/mach-zx/Kconfig b/arch/arm/mach-zx/Kconfig
index 446334a25cf5..209c97944de2 100644
--- a/arch/arm/mach-zx/Kconfig
+++ b/arch/arm/mach-zx/Kconfig
@@ -1,5 +1,6 @@
menuconfig ARCH_ZX
- bool "ZTE ZX family" if ARCH_MULTI_V7
+ bool "ZTE ZX family"
+ depends on ARCH_MULTI_V7
help
Support for ZTE ZX-based family of processors. TV
set-top-box processor is supported. More will be
diff --git a/arch/arm/mach-zx/platsmp.c b/arch/arm/mach-zx/platsmp.c
index a3693982d65d..0297f92084e0 100644
--- a/arch/arm/mach-zx/platsmp.c
+++ b/arch/arm/mach-zx/platsmp.c
@@ -176,7 +176,7 @@ static void zx_secondary_init(unsigned int cpu)
scu_power_mode(scu_base, SCU_PM_NORMAL);
}
-struct smp_operations zx_smp_ops __initdata = {
+static const struct smp_operations zx_smp_ops __initconst = {
.smp_prepare_cpus = zx_smp_prepare_cpus,
.smp_secondary_init = zx_secondary_init,
.smp_boot_secondary = zx_boot_secondary,
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
index 78e5e007f52d..fd0aeeb09881 100644
--- a/arch/arm/mach-zynq/Kconfig
+++ b/arch/arm/mach-zynq/Kconfig
@@ -1,5 +1,7 @@
config ARCH_ZYNQ
- bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7
+ bool "Xilinx Zynq ARM Cortex A9 Platform"
+ depends on ARCH_MULTI_V7
+ select ARCH_HAS_RESET_CONTROLLER
select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
select ARM_GIC
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index 79cda2e5fa4e..e771933db7e8 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -30,7 +30,7 @@ extern char zynq_secondary_trampoline;
extern char zynq_secondary_trampoline_jump;
extern char zynq_secondary_trampoline_end;
extern int zynq_cpun_start(u32 address, int cpu);
-extern struct smp_operations zynq_smp_ops __initdata;
+extern const struct smp_operations zynq_smp_ops;
#endif
extern void __iomem *zynq_scu_base;
diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c
index f66816c49186..7cd9865bdeb7 100644
--- a/arch/arm/mach-zynq/platsmp.c
+++ b/arch/arm/mach-zynq/platsmp.c
@@ -157,7 +157,7 @@ static void zynq_cpu_die(unsigned int cpu)
}
#endif
-struct smp_operations zynq_smp_ops __initdata = {
+const struct smp_operations zynq_smp_ops __initconst = {
.smp_init_cpus = zynq_smp_init_cpus,
.smp_prepare_cpus = zynq_smp_prepare_cpus,
.smp_boot_secondary = zynq_boot_secondary,
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 41218867a9a6..549f6d3aec5b 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -21,7 +21,7 @@ config CPU_ARM7TDMI
# ARM720T
config CPU_ARM720T
- bool "Support ARM720T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
+ bool
select CPU_32v4T
select CPU_ABRT_LV4T
select CPU_CACHE_V4
@@ -39,7 +39,7 @@ config CPU_ARM720T
# ARM740T
config CPU_ARM740T
- bool "Support ARM740T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
+ bool
depends on !MMU
select CPU_32v4T
select CPU_ABRT_LV4T
@@ -71,7 +71,7 @@ config CPU_ARM9TDMI
# ARM920T
config CPU_ARM920T
- bool "Support ARM920T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
+ bool
select CPU_32v4T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -89,7 +89,7 @@ config CPU_ARM920T
# ARM922T
config CPU_ARM922T
- bool "Support ARM922T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
+ bool
select CPU_32v4T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -108,7 +108,7 @@ config CPU_ARM922T
# ARM925T
config CPU_ARM925T
- bool "Support ARM925T processor" if ARCH_OMAP1
+ bool
select CPU_32v4T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -127,7 +127,7 @@ config CPU_ARM925T
# ARM926T
config CPU_ARM926T
- bool "Support ARM926T processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V5) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB)
+ bool
select CPU_32v5
select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT
@@ -163,7 +163,7 @@ config CPU_FA526
# ARM940T
config CPU_ARM940T
- bool "Support ARM940T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
+ bool
depends on !MMU
select CPU_32v4T
select CPU_ABRT_NOMMU
@@ -181,7 +181,7 @@ config CPU_ARM940T
# ARM946E-S
config CPU_ARM946E
- bool "Support ARM946E-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
+ bool
depends on !MMU
select CPU_32v5
select CPU_ABRT_NOMMU
@@ -198,7 +198,7 @@ config CPU_ARM946E
# ARM1020 - needs validating
config CPU_ARM1020
- bool "Support ARM1020T (rev 0) processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
+ bool
select CPU_32v5
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -216,7 +216,7 @@ config CPU_ARM1020
# ARM1020E - needs validating
config CPU_ARM1020E
- bool "Support ARM1020E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
+ bool
depends on n
select CPU_32v5
select CPU_ABRT_EV4T
@@ -229,7 +229,7 @@ config CPU_ARM1020E
# ARM1022E
config CPU_ARM1022
- bool "Support ARM1022E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
+ bool
select CPU_32v5
select CPU_ABRT_EV4T
select CPU_CACHE_VIVT
@@ -247,7 +247,7 @@ config CPU_ARM1022
# ARM1026EJ-S
config CPU_ARM1026
- bool "Support ARM1026EJ-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
+ bool
select CPU_32v5
select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
select CPU_CACHE_VIVT
@@ -358,7 +358,7 @@ config CPU_PJ4B
# ARMv6
config CPU_V6
- bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
+ bool
select CPU_32v6
select CPU_ABRT_EV6
select CPU_CACHE_V6
@@ -371,7 +371,7 @@ config CPU_V6
# ARMv6k
config CPU_V6K
- bool "Support ARM V6K processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
+ bool
select CPU_32v6
select CPU_32v6K
select CPU_ABRT_EV6
@@ -385,7 +385,7 @@ config CPU_V6K
# ARMv7
config CPU_V7
- bool "Support ARM V7 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V7) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
+ bool
select CPU_32v6K
select CPU_32v7
select CPU_ABRT_EV7
@@ -1005,8 +1005,6 @@ config ARM_L1_CACHE_SHIFT
config ARM_DMA_MEM_BUFFERABLE
bool "Use non-cacheable memory for DMA" if (CPU_V6 || CPU_V6K) && !CPU_V7
- depends on !(MACH_REALVIEW_PB1176 || REALVIEW_EB_ARM11MP || \
- MACH_REALVIEW_PB11MP)
default y if CPU_V6 || CPU_V6K || CPU_V7
help
Historically, the kernel has used strongly ordered mappings to
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 1ec8e7590fc6..d0ba3551d49a 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -330,7 +330,7 @@ void flush_dcache_page(struct page *page)
mapping = page_mapping(page);
if (!cache_ops_need_broadcast() &&
- mapping && !page_mapped(page))
+ mapping && !page_mapcount(page))
clear_bit(PG_dcache_clean, &page->flags);
else {
__flush_dcache_page(mapping, page);
@@ -415,18 +415,3 @@ void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned l
*/
__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
}
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-#ifdef CONFIG_HAVE_RCU_TABLE_FREE
-void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp)
-{
- pmd_t pmd = pmd_mksplitting(*pmdp);
- VM_BUG_ON(address & ~PMD_MASK);
- set_pmd_at(vma->vm_mm, address, pmdp, pmd);
-
- /* dummy IPI to serialise against fast_gup */
- kick_all_cpus_sync();
-}
-#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index e7a81cebbb2e..d65909697165 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -86,7 +86,7 @@ static void identity_mapping_add(pgd_t *pgd, const char *text_start,
prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
- if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
+ if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale_family())
prot |= PMD_BIT4;
pgd += pgd_index(addr);
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 407dc786583a..4b4058db0781 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -173,8 +173,7 @@ unsigned long arch_mmap_rnd(void)
{
unsigned long rnd;
- /* 8 bits of randomness in 20 address space bits */
- rnd = (unsigned long)get_random_int() % (1 << 8);
+ rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
return rnd << PAGE_SHIFT;
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index a87f6cc3fa2b..434d76f0b363 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -477,7 +477,7 @@ static void __init build_mem_type_table(void)
* "update-able on write" bit on ARM610). However, Xscale and
* Xscale3 require this bit to be cleared.
*/
- if (cpu_is_xscale() || cpu_is_xsc3()) {
+ if (cpu_is_xscale_family()) {
for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
mem_types[i].prot_sect &= ~PMD_BIT4;
mem_types[i].prot_l1 &= ~PMD_BIT4;
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index d65edf717bf7..6f07d2ef4ff2 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -342,11 +342,13 @@ ENTRY(cpu_mohawk_switch_mm)
*/
.align 5
ENTRY(cpu_mohawk_set_pte_ext)
+#ifdef CONFIG_MMU
armv3_set_pte_ext
mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c10, 4 @ drain WB
ret lr
+#endif
.globl cpu_mohawk_suspend_size
.equ cpu_mohawk_suspend_size, 4 * 6
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 8ca94d379bc3..7a327bd32521 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -36,6 +36,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/device.h>
@@ -137,6 +138,31 @@ static int omap_dm_timer_reset(struct omap_dm_timer *timer)
return 0;
}
+static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)
+{
+ int ret;
+ struct clk *parent;
+
+ /*
+ * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
+ * do not call clk_get() for these devices.
+ */
+ if (!timer->fclk)
+ return -ENODEV;
+
+ parent = clk_get(&timer->pdev->dev, NULL);
+ if (IS_ERR(parent))
+ return -ENODEV;
+
+ ret = clk_set_parent(timer->fclk, parent);
+ if (ret < 0)
+ pr_err("%s: failed to set parent\n", __func__);
+
+ clk_put(parent);
+
+ return ret;
+}
+
static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
{
int rc;
@@ -166,7 +192,11 @@ static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
__omap_dm_timer_enable_posted(timer);
omap_dm_timer_disable(timer);
- return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+ rc = omap_dm_timer_of_set_source(timer);
+ if (rc == -ENODEV)
+ return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+
+ return rc;
}
static inline u32 omap_dm_timer_reserved_systimer(int id)
@@ -504,6 +534,12 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
if (IS_ERR(timer->fclk))
return -EINVAL;
+#if defined(CONFIG_COMMON_CLK)
+ /* Check if the clock has configurable parents */
+ if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2)
+ return 0;
+#endif
+
switch (source) {
case OMAP_TIMER_SRC_SYS_CLK:
parent_name = "timer_sys_ck";
@@ -943,6 +979,10 @@ static const struct of_device_id omap_timer_match[] = {
.compatible = "ti,am335x-timer-1ms",
.data = &omap3plus_pdata,
},
+ {
+ .compatible = "ti,dm816-timer",
+ .data = &omap3plus_pdata,
+ },
{},
};
MODULE_DEVICE_TABLE(of, omap_timer_match);
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index 8861c367d061..78c8bf4043c0 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -21,7 +21,6 @@
#include <net/dsa.h>
#include <linux/platform_data/dma-mv_xor.h>
#include <linux/platform_data/usb-ehci-orion.h>
-#include <mach/bridge-regs.h>
#include <plat/common.h>
/* Create a clkdev entry for a given device/clk */
@@ -589,26 +588,6 @@ void __init orion_spi_1_init(unsigned long mapbase)
}
/*****************************************************************************
- * Watchdog
- ****************************************************************************/
-static struct resource orion_wdt_resource[] = {
- DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
- DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
-};
-
-static struct platform_device orion_wdt_device = {
- .name = "orion_wdt",
- .id = -1,
- .num_resources = ARRAY_SIZE(orion_wdt_resource),
- .resource = orion_wdt_resource,
-};
-
-void __init orion_wdt_init(void)
-{
- platform_device_register(&orion_wdt_device);
-}
-
-/*****************************************************************************
* XOR
****************************************************************************/
static u64 orion_xor_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h
index d9a24f605a2b..9e6d76ad48a9 100644
--- a/arch/arm/plat-orion/include/plat/common.h
+++ b/arch/arm/plat-orion/include/plat/common.h
@@ -75,8 +75,6 @@ void __init orion_spi_init(unsigned long mapbase);
void __init orion_spi_1_init(unsigned long mapbase);
-void __init orion_wdt_init(void);
-
void __init orion_xor0_init(unsigned long mapbase_low,
unsigned long mapbase_high,
unsigned long irq_0,
diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c
index 8c1fc06007c0..5b63b28b00ac 100644
--- a/arch/arm/plat-orion/irq.c
+++ b/arch/arm/plat-orion/irq.c
@@ -18,7 +18,6 @@
#include <asm/exception.h>
#include <plat/irq.h>
#include <plat/orion-gpio.h>
-#include <mach/bridge-regs.h>
void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
{
diff --git a/arch/arm/plat-orion/mpp.c b/arch/arm/plat-orion/mpp.c
index 7310bcfb299f..5b4ff9373c89 100644
--- a/arch/arm/plat-orion/mpp.c
+++ b/arch/arm/plat-orion/mpp.c
@@ -13,7 +13,6 @@
#include <linux/mbus.h>
#include <linux/io.h>
#include <linux/gpio.h>
-#include <mach/hardware.h>
#include <plat/orion-gpio.h>
#include <plat/mpp.h>
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 1fc941944912..557b134db772 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -1,8 +1,9 @@
#
# Makefile for code common across different PXA processor families
#
+ccflags-$(CONFIG_ARCH_MMP) := -I$(srctree)/$(src)/include
-obj-y := dma.o
+obj-$(CONFIG_ARCH_PXA) := dma.o
obj-$(CONFIG_PXA3xx) += mfp.o
obj-$(CONFIG_ARCH_MMP) += mfp.o
diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c
index daa1a65f2eb7..ba13f793fbce 100644
--- a/arch/arm/plat-pxa/ssp.c
+++ b/arch/arm/plat-pxa/ssp.c
@@ -34,7 +34,6 @@
#include <linux/of_device.h>
#include <asm/irq.h>
-#include <mach/hardware.h>
static DEFINE_MUTEX(ssp_lock);
static LIST_HEAD(ssp_list);
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 57729b915003..e8229b9fee4a 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -39,7 +39,6 @@ config S3C_LOWLEVEL_UART_PORT
config SAMSUNG_ATAGS
def_bool n
- depends on !ARCH_MULTIPLATFORM
depends on ATAGS
help
This option enables ATAGS based boot support code for
@@ -70,6 +69,7 @@ config S3C_GPIO_TRACK
config S3C_ADC
bool "ADC common driver support"
+ depends on !ARCH_MULTIPLATFORM
help
Core support for the ADC block found in the Samsung SoC systems
for drivers such as the touchscreen and hwmon to use to share
@@ -225,6 +225,9 @@ config S3C24XX_PWM
Support for exporting the PWM timer blocks via the pwm device
system
+config GPIO_SAMSUNG
+ def_bool y
+
config SAMSUNG_PM_GPIO
bool
default y if GPIO_SAMSUNG && PM
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 8c911760f55f..be172efec15c 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -4,7 +4,8 @@
#
# Licensed under GPLv2
-ccflags-$(CONFIG_ARCH_MULTI_V7) += -I$(srctree)/$(src)/include
+ccflags-$(CONFIG_ARCH_S3C64XX) := -I$(srctree)/arch/arm/mach-s3c64xx/include
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include
# Objects we always build independent of SoC choice
@@ -21,6 +22,8 @@ obj-$(CONFIG_SAMSUNG_ATAGS) += platformdata.o
obj-$(CONFIG_SAMSUNG_ATAGS) += devs.o
obj-$(CONFIG_SAMSUNG_ATAGS) += dev-uart.o
+obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o
+
# PM support
obj-$(CONFIG_PM_SLEEP) += pm-common.o
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 74ef8891254e..b53d4ff3befb 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -65,6 +65,7 @@
#include <linux/platform_data/usb-ohci-s3c2410.h>
#include <plat/usb-phy.h>
#include <plat/regs-spi.h>
+#include <linux/platform_data/asoc-s3c.h>
#include <linux/platform_data/spi-s3c64xx.h>
static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -74,9 +75,15 @@ static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
static struct resource s3c_ac97_resource[] = {
[0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97),
[1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97),
- [2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"),
- [3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"),
- [4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"),
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+#ifdef CONFIG_S3C24XX_DMAC
+ .dma_filter = s3c24xx_dma_filter,
+#endif
+ .dma_playback = (void *)DMACH_PCM_OUT,
+ .dma_capture = (void *)DMACH_PCM_IN,
+ .dma_capture_mic = (void *)DMACH_MIC_IN,
};
struct platform_device s3c_device_ac97 = {
@@ -87,6 +94,7 @@ struct platform_device s3c_device_ac97 = {
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &s3c_ac97_pdata,
}
};
#endif /* CONFIG_CPU_S3C2440 */
@@ -111,12 +119,12 @@ struct platform_device s3c_device_adc = {
#if defined(CONFIG_SAMSUNG_DEV_ADC)
static struct resource s3c_adc_resource[] = {
[0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256),
- [1] = DEFINE_RES_IRQ(IRQ_TC),
- [2] = DEFINE_RES_IRQ(IRQ_ADC),
+ [1] = DEFINE_RES_IRQ(IRQ_ADC),
+ [2] = DEFINE_RES_IRQ(IRQ_TC),
};
struct platform_device s3c_device_adc = {
- .name = "samsung-adc",
+ .name = "exynos-adc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_adc_resource),
.resource = s3c_adc_resource,
@@ -566,6 +574,14 @@ static struct resource s3c_iis_resource[] = {
[0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS),
};
+static struct s3c_audio_pdata s3c_iis_platdata = {
+#ifdef CONFIG_S3C24XX_DMAC
+ .dma_filter = s3c24xx_dma_filter,
+#endif
+ .dma_playback = (void *)DMACH_I2S_OUT,
+ .dma_capture = (void *)DMACH_I2S_IN,
+};
+
struct platform_device s3c_device_iis = {
.name = "s3c24xx-iis",
.id = -1,
@@ -574,6 +590,7 @@ struct platform_device s3c_device_iis = {
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &s3c_iis_platdata,
}
};
#endif /* CONFIG_PLAT_S3C24XX */
@@ -939,31 +956,19 @@ void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *hard_s3c2410ts_
#endif /* CONFIG_PLAT_S3C24XX */
#ifdef CONFIG_SAMSUNG_DEV_TS
-static struct resource s3c_ts_resource[] = {
- [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256),
- [1] = DEFINE_RES_IRQ(IRQ_TC),
-};
-
static struct s3c2410_ts_mach_info default_ts_data __initdata = {
.delay = 10000,
.presc = 49,
.oversampling_shift = 2,
};
-struct platform_device s3c_device_ts = {
- .name = "s3c64xx-ts",
- .id = -1,
- .num_resources = ARRAY_SIZE(s3c_ts_resource),
- .resource = s3c_ts_resource,
-};
-
-void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)
+void __init s3c64xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)
{
if (!pd)
pd = &default_ts_data;
s3c_set_platdata(pd, sizeof(struct s3c2410_ts_mach_info),
- &s3c_device_ts);
+ &s3c_device_adc);
}
#endif /* CONFIG_SAMSUNG_DEV_TS */
@@ -1100,9 +1105,7 @@ struct platform_device s3c_device_wdt = {
#ifdef CONFIG_S3C64XX_DEV_SPI0
static struct resource s3c64xx_spi0_resource[] = {
[0] = DEFINE_RES_MEM(S3C_PA_SPI0, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_SPI0_TX),
- [2] = DEFINE_RES_DMA(DMACH_SPI0_RX),
- [3] = DEFINE_RES_IRQ(IRQ_SPI0),
+ [1] = DEFINE_RES_IRQ(IRQ_SPI0),
};
struct platform_device s3c64xx_device_spi0 = {
@@ -1130,6 +1133,8 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
+ pd.dma_tx = (void *)DMACH_SPI0_TX;
+ pd.dma_rx = (void *)DMACH_SPI0_RX;
#if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
@@ -1145,9 +1150,7 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
#ifdef CONFIG_S3C64XX_DEV_SPI1
static struct resource s3c64xx_spi1_resource[] = {
[0] = DEFINE_RES_MEM(S3C_PA_SPI1, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_SPI1_TX),
- [2] = DEFINE_RES_DMA(DMACH_SPI1_RX),
- [3] = DEFINE_RES_IRQ(IRQ_SPI1),
+ [1] = DEFINE_RES_IRQ(IRQ_SPI1),
};
struct platform_device s3c64xx_device_spi1 = {
@@ -1175,12 +1178,15 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
+ pd.dma_tx = (void *)DMACH_SPI1_TX;
+ pd.dma_rx = (void *)DMACH_SPI1_RX;
#if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#endif
+
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
}
#endif /* CONFIG_S3C64XX_DEV_SPI1 */
@@ -1188,9 +1194,7 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
#ifdef CONFIG_S3C64XX_DEV_SPI2
static struct resource s3c64xx_spi2_resource[] = {
[0] = DEFINE_RES_MEM(S3C_PA_SPI2, SZ_256),
- [1] = DEFINE_RES_DMA(DMACH_SPI2_TX),
- [2] = DEFINE_RES_DMA(DMACH_SPI2_RX),
- [3] = DEFINE_RES_IRQ(IRQ_SPI2),
+ [1] = DEFINE_RES_IRQ(IRQ_SPI2),
};
struct platform_device s3c64xx_device_spi2 = {
@@ -1218,6 +1222,8 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
+ pd.dma_tx = (void *)DMACH_SPI2_TX;
+ pd.dma_rx = (void *)DMACH_SPI2_RX;
#if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
diff --git a/drivers/gpio/gpio-samsung.c b/arch/arm/plat-samsung/gpio-samsung.c
index 7c288ba4dc87..7861488f7ca0 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/arch/arm/plat-samsung/gpio-samsung.c
@@ -30,6 +30,7 @@
#include <asm/irq.h>
+#include <mach/irqs.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-samsung.h>
@@ -753,7 +754,7 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip)
#endif
/* gpiochip_add() prints own failure message on error. */
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, chip);
if (ret >= 0)
s3c_gpiolib_track(chip);
}
@@ -862,7 +863,7 @@ static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chi
int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
{
- struct samsung_gpio_chip *samsung_chip = container_of(chip, struct samsung_gpio_chip, chip);
+ struct samsung_gpio_chip *samsung_chip = gpiochip_get_data(chip);
return samsung_chip->irq_base + offset;
}
@@ -1176,14 +1177,16 @@ static __init int samsung_gpiolib_init(void)
* interfaces. For legacy (non-DT) platforms this driver is used.
*/
if (of_have_populated_dt())
- return -ENODEV;
-
- samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
+ return 0;
if (soc_is_s3c24xx()) {
+ samsung_gpiolib_set_cfg(samsung_gpio_cfgs,
+ ARRAY_SIZE(samsung_gpio_cfgs));
s3c24xx_gpiolib_add_chips(s3c24xx_gpios,
ARRAY_SIZE(s3c24xx_gpios), S3C24XX_VA_GPIO);
} else if (soc_is_s3c64xx()) {
+ samsung_gpiolib_set_cfg(samsung_gpio_cfgs,
+ ARRAY_SIZE(samsung_gpio_cfgs));
samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit,
ARRAY_SIZE(s3c64xx_gpios_2bit),
S3C64XX_VA_GPIO + 0xE0, 0x20);
@@ -1192,9 +1195,6 @@ static __init int samsung_gpiolib_init(void)
S3C64XX_VA_GPIO);
samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2,
ARRAY_SIZE(s3c64xx_gpios_4bit2));
- } else {
- WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
- return -ENODEV;
}
return 0;
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 7f415ce74591..9dd562ab0841 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -41,14 +41,6 @@ static inline int s3c64xx_pm_init(void)
extern unsigned long s3c_irqwake_intmask;
extern unsigned long s3c_irqwake_eintmask;
-/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */
-extern unsigned long s3c_irqwake_intallow;
-#ifdef CONFIG_PM_SLEEP
-extern unsigned long s3c_irqwake_eintallow;
-#else
-#define s3c_irqwake_eintallow 0
-#endif
-
/* per-cpu sleep functions */
extern void (*pm_cpu_prep)(void);
diff --git a/arch/arm/plat-samsung/init.c b/arch/arm/plat-samsung/init.c
index 11fbbc26e49f..3776f7e752f0 100644
--- a/arch/arm/plat-samsung/init.c
+++ b/arch/arm/plat-samsung/init.c
@@ -152,6 +152,11 @@ static int __init s3c_arch_init(void)
{
int ret;
+ /* init is only needed for ATAGS based platforms */
+ if (!IS_ENABLED(CONFIG_ATAGS) ||
+ (!soc_is_s3c24xx() && !soc_is_s3c64xx()))
+ return 0;
+
// do the correct init for cpu
if (cpu == NULL) {
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 82777c649774..d7803b434732 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -23,14 +23,10 @@
#include <asm/cacheflush.h>
#include <asm/suspend.h>
-#ifdef CONFIG_SAMSUNG_ATAGS
#include <mach/map.h>
-#ifndef CONFIG_ARCH_EXYNOS
#include <mach/regs-clock.h>
#include <mach/regs-irq.h>
-#endif
#include <mach/irqs.h>
-#endif
#include <asm/irq.h>
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index d6ebffdc6bb1..6be3fa2310ee 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -3,6 +3,7 @@ config ARM64
select ACPI_CCA_REQUIRED if ACPI
select ACPI_GENERIC_GSI if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
@@ -51,6 +52,8 @@ config ARM64
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48)
select HAVE_ARCH_KGDB
+ select HAVE_ARCH_MMAP_RND_BITS
+ select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_BPF_JIT
@@ -106,6 +109,33 @@ config ARCH_PHYS_ADDR_T_64BIT
config MMU
def_bool y
+config ARCH_MMAP_RND_BITS_MIN
+ default 14 if ARM64_64K_PAGES
+ default 16 if ARM64_16K_PAGES
+ default 18
+
+# max bits determined by the following formula:
+# VA_BITS - PAGE_SHIFT - 3
+config ARCH_MMAP_RND_BITS_MAX
+ default 19 if ARM64_VA_BITS=36
+ default 24 if ARM64_VA_BITS=39
+ default 27 if ARM64_VA_BITS=42
+ default 30 if ARM64_VA_BITS=47
+ default 29 if ARM64_VA_BITS=48 && ARM64_64K_PAGES
+ default 31 if ARM64_VA_BITS=48 && ARM64_16K_PAGES
+ default 33 if ARM64_VA_BITS=48
+ default 14 if ARM64_64K_PAGES
+ default 16 if ARM64_16K_PAGES
+ default 18
+
+config ARCH_MMAP_RND_COMPAT_BITS_MIN
+ default 7 if ARM64_64K_PAGES
+ default 9 if ARM64_16K_PAGES
+ default 11
+
+config ARCH_MMAP_RND_COMPAT_BITS_MAX
+ default 16
+
config NO_IOPORT_MAP
def_bool y if !PCI
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index 04fb73b973f1..e13c4bf84d9e 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -14,20 +14,6 @@ config ARM64_PTDUMP
kernel.
If in doubt, say "N"
-config STRICT_DEVMEM
- bool "Filter access to /dev/mem"
- depends on MMU
- help
- If this option is disabled, you allow userspace (root) access to all
- of memory, including kernel and userspace memory. Accidental
- access to this is obviously disastrous, but specific access can
- be used by people debugging the kernel.
-
- If this option is switched on, the /dev/mem file only allows
- userspace access to memory mapped peripherals.
-
- If in doubt, say Y.
-
config PID_IN_CONTEXTIDR
bool "Write the current PID to the CONTEXTIDR register"
help
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 4043c35962cc..2c400412b3bc 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -9,6 +9,7 @@ config ARCH_BERLIN
bool "Marvell Berlin SoC Family"
select ARCH_REQUIRE_GPIOLIB
select DW_APB_ICTL
+ select PINCTRL
help
This enables support for Marvell Berlin SoC Family
@@ -43,6 +44,7 @@ config ARCH_MEDIATEK
bool "Mediatek MT65xx & MT81xx ARMv8 SoC"
select ARM_GIC
select PINCTRL
+ select MTK_TIMER
help
Support for Mediatek MT65xx & MT81xx ARMv8 SoCs
@@ -67,6 +69,23 @@ config ARCH_SEATTLE
help
This enables support for AMD Seattle SOC Family
+config ARCH_SHMOBILE
+ bool
+
+config ARCH_RENESAS
+ bool "Renesas SoC Platforms"
+ select ARCH_SHMOBILE
+ select PINCTRL
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the ARMv8 based Renesas SoCs.
+
+config ARCH_R8A7795
+ bool "Renesas R-Car H3 SoC Platform"
+ depends on ARCH_RENESAS
+ help
+ This enables support for the Renesas R-Car H3 SoC.
+
config ARCH_STRATIX10
bool "Altera's Stratix 10 SoCFPGA Family"
help
@@ -108,6 +127,12 @@ config ARCH_THUNDER
help
This enables support for Cavium's Thunder Family of SoCs.
+config ARCH_UNIPHIER
+ bool "Socionext UniPhier SoC Family"
+ select PINCTRL
+ help
+ This enables support for Socionext UniPhier SoC family.
+
config ARCH_VEXPRESS
bool "ARMv8 software model (Versatile Express)"
select ARCH_REQUIRE_GPIOLIB
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index eb3c42d97175..76e7510835b2 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -10,7 +10,9 @@ dts-dirs += hisilicon
dts-dirs += marvell
dts-dirs += mediatek
dts-dirs += qcom
+dts-dirs += renesas
dts-dirs += rockchip
+dts-dirs += socionext
dts-dirs += sprd
dts-dirs += xilinx
diff --git a/arch/arm64/boot/dts/apm/apm-merlin.dts b/arch/arm64/boot/dts/apm/apm-merlin.dts
index 119a469bd189..e5ba8d5d0cae 100644
--- a/arch/arm64/boot/dts/apm/apm-merlin.dts
+++ b/arch/arm64/boot/dts/apm/apm-merlin.dts
@@ -70,3 +70,15 @@
&xgenet1 {
status = "ok";
};
+
+&mmc0 {
+ status = "ok";
+};
+
+&i2c4 {
+ rtc68: rtc@68 {
+ compatible = "dallas,ds1337";
+ reg = <0x68>;
+ status = "ok";
+ };
+};
diff --git a/arch/arm64/boot/dts/apm/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts
index 01cdeda93c3a..178aef2cdd09 100644
--- a/arch/arm64/boot/dts/apm/apm-mustang.dts
+++ b/arch/arm64/boot/dts/apm/apm-mustang.dts
@@ -74,3 +74,7 @@
&xgenet {
status = "ok";
};
+
+&mmc0 {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
index c804f8f1f38c..5d87a3dc44b8 100644
--- a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
@@ -25,6 +25,7 @@
reg = <0x0 0x000>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_0>;
};
cpu@001 {
device_type = "cpu";
@@ -32,6 +33,7 @@
reg = <0x0 0x001>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_0>;
};
cpu@100 {
device_type = "cpu";
@@ -39,6 +41,7 @@
reg = <0x0 0x100>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_1>;
};
cpu@101 {
device_type = "cpu";
@@ -46,6 +49,7 @@
reg = <0x0 0x101>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_1>;
};
cpu@200 {
device_type = "cpu";
@@ -53,6 +57,7 @@
reg = <0x0 0x200>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_2>;
};
cpu@201 {
device_type = "cpu";
@@ -60,6 +65,7 @@
reg = <0x0 0x201>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_2>;
};
cpu@300 {
device_type = "cpu";
@@ -67,6 +73,7 @@
reg = <0x0 0x300>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_3>;
};
cpu@301 {
device_type = "cpu";
@@ -74,6 +81,19 @@
reg = <0x0 0x301>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_3>;
+ };
+ xgene_L2_0: l2-cache-0 {
+ compatible = "cache";
+ };
+ xgene_L2_1: l2-cache-1 {
+ compatible = "cache";
+ };
+ xgene_L2_2: l2-cache-2 {
+ compatible = "cache";
+ };
+ xgene_L2_3: l2-cache-3 {
+ compatible = "cache";
};
};
@@ -89,6 +109,86 @@
<0x0 0x780A0000 0x0 0x20000>, /* GIC CPU */
<0x0 0x780C0000 0x0 0x10000>, /* GIC VCPU Control */
<0x0 0x780E0000 0x0 0x20000>; /* GIC VCPU */
+ v2m0: v2m@0x00000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x0 0x0 0x1000>;
+ };
+ v2m1: v2m@0x10000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x10000 0x0 0x1000>;
+ };
+ v2m2: v2m@0x20000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x20000 0x0 0x1000>;
+ };
+ v2m3: v2m@0x30000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x30000 0x0 0x1000>;
+ };
+ v2m4: v2m@0x40000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x40000 0x0 0x1000>;
+ };
+ v2m5: v2m@0x50000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x50000 0x0 0x1000>;
+ };
+ v2m6: v2m@0x60000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x60000 0x0 0x1000>;
+ };
+ v2m7: v2m@0x70000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x70000 0x0 0x1000>;
+ };
+ v2m8: v2m@0x80000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x80000 0x0 0x1000>;
+ };
+ v2m9: v2m@0x90000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x90000 0x0 0x1000>;
+ };
+ v2m10: v2m@0xA0000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0xA0000 0x0 0x1000>;
+ };
+ v2m11: v2m@0xB0000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0xB0000 0x0 0x1000>;
+ };
+ v2m12: v2m@0xC0000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0xC0000 0x0 0x1000>;
+ };
+ v2m13: v2m@0xD0000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0xD0000 0x0 0x1000>;
+ };
+ v2m14: v2m@0xE0000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0xE0000 0x0 0x1000>;
+ };
+ v2m15: v2m@0xF0000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0xF0000 0x0 0x1000>;
+ };
};
pmu {
@@ -140,6 +240,47 @@
clock-output-names = "socplldiv2";
};
+ ahbclk: ahbclk@17000000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x17000000 0x0 0x2000>;
+ reg-names = "div-reg";
+ divider-offset = <0x164>;
+ divider-width = <0x5>;
+ divider-shift = <0x0>;
+ clock-output-names = "ahbclk";
+ };
+
+ sbapbclk: sbapbclk@1704c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&ahbclk 0>;
+ reg = <0x0 0x1704c000 0x0 0x2000>;
+ reg-names = "div-reg";
+ divider-offset = <0x10>;
+ divider-width = <0x2>;
+ divider-shift = <0x0>;
+ clock-output-names = "sbapbclk";
+ };
+
+ sdioclk: sdioclk@1f2ac000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f2ac000 0x0 0x1000
+ 0x0 0x17000000 0x0 0x2000>;
+ reg-names = "csr-reg", "div-reg";
+ csr-offset = <0x0>;
+ csr-mask = <0x2>;
+ enable-offset = <0x8>;
+ enable-mask = <0x2>;
+ divider-offset = <0x178>;
+ divider-width = <0x8>;
+ divider-shift = <0x0>;
+ clock-output-names = "sdioclk";
+ };
+
pcie0clk: pcie0clk@1f2bc000 {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
@@ -149,6 +290,15 @@
clock-output-names = "pcie0clk";
};
+ pcie1clk: pcie1clk@1f2cc000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f2cc000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "pcie1clk";
+ };
+
xge0clk: xge0clk@1f61c000 {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
@@ -170,6 +320,32 @@
csr-mask = <0x3>;
clock-output-names = "xge1clk";
};
+
+ rngpkaclk: rngpkaclk@17000000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x17000000 0x0 0x2000>;
+ reg-names = "csr-reg";
+ csr-offset = <0xc>;
+ csr-mask = <0x10>;
+ enable-offset = <0x10>;
+ enable-mask = <0x10>;
+ clock-output-names = "rngpkaclk";
+ };
+
+ i2c4clk: i2c4clk@1704c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&sbapbclk 0>;
+ reg = <0x0 0x1704c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ csr-offset = <0x0>;
+ csr-mask = <0x40>;
+ enable-offset = <0x8>;
+ enable-mask = <0x40>;
+ clock-output-names = "i2c4clk";
+ };
};
scu: system-clk-controller@17000000 {
@@ -184,6 +360,99 @@
mask = <0x1>;
};
+ csw: csw@7e200000 {
+ compatible = "apm,xgene-csw", "syscon";
+ reg = <0x0 0x7e200000 0x0 0x1000>;
+ };
+
+ mcba: mcba@7e700000 {
+ compatible = "apm,xgene-mcb", "syscon";
+ reg = <0x0 0x7e700000 0x0 0x1000>;
+ };
+
+ mcbb: mcbb@7e720000 {
+ compatible = "apm,xgene-mcb", "syscon";
+ reg = <0x0 0x7e720000 0x0 0x1000>;
+ };
+
+ efuse: efuse@1054a000 {
+ compatible = "apm,xgene-efuse", "syscon";
+ reg = <0x0 0x1054a000 0x0 0x20>;
+ };
+
+ edac@78800000 {
+ compatible = "apm,xgene-edac";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ regmap-csw = <&csw>;
+ regmap-mcba = <&mcba>;
+ regmap-mcbb = <&mcbb>;
+ regmap-efuse = <&efuse>;
+ reg = <0x0 0x78800000 0x0 0x100>;
+ interrupts = <0x0 0x20 0x4>,
+ <0x0 0x21 0x4>,
+ <0x0 0x27 0x4>;
+
+ edacmc@7e800000 {
+ compatible = "apm,xgene-edac-mc";
+ reg = <0x0 0x7e800000 0x0 0x1000>;
+ memory-controller = <0>;
+ };
+
+ edacmc@7e840000 {
+ compatible = "apm,xgene-edac-mc";
+ reg = <0x0 0x7e840000 0x0 0x1000>;
+ memory-controller = <1>;
+ };
+
+ edacmc@7e880000 {
+ compatible = "apm,xgene-edac-mc";
+ reg = <0x0 0x7e880000 0x0 0x1000>;
+ memory-controller = <2>;
+ };
+
+ edacmc@7e8c0000 {
+ compatible = "apm,xgene-edac-mc";
+ reg = <0x0 0x7e8c0000 0x0 0x1000>;
+ memory-controller = <3>;
+ };
+
+ edacpmd@7c000000 {
+ compatible = "apm,xgene-edac-pmd";
+ reg = <0x0 0x7c000000 0x0 0x200000>;
+ pmd-controller = <0>;
+ };
+
+ edacpmd@7c200000 {
+ compatible = "apm,xgene-edac-pmd";
+ reg = <0x0 0x7c200000 0x0 0x200000>;
+ pmd-controller = <1>;
+ };
+
+ edacpmd@7c400000 {
+ compatible = "apm,xgene-edac-pmd";
+ reg = <0x0 0x7c400000 0x0 0x200000>;
+ pmd-controller = <2>;
+ };
+
+ edacpmd@7c600000 {
+ compatible = "apm,xgene-edac-pmd";
+ reg = <0x0 0x7c600000 0x0 0x200000>;
+ pmd-controller = <3>;
+ };
+
+ edacl3@7e600000 {
+ compatible = "apm,xgene-edac-l3-v2";
+ reg = <0x0 0x7e600000 0x0 0x1000>;
+ };
+
+ edacsoc@7e930000 {
+ compatible = "apm,xgene-edac-soc";
+ reg = <0x0 0x7e930000 0x0 0x1000>;
+ };
+ };
+
serial0: serial@10600000 {
device_type = "serial";
compatible = "ns16550";
@@ -194,6 +463,66 @@
interrupts = <0x0 0x4c 0x4>;
};
+ /* Do not change dwusb name, coded for backward compatibility */
+ usb0: dwusb@19000000 {
+ status = "disabled";
+ compatible = "snps,dwc3";
+ reg = <0x0 0x19000000 0x0 0x100000>;
+ interrupts = <0x0 0x5d 0x4>;
+ dma-coherent;
+ dr_mode = "host";
+ };
+
+ pcie0: pcie@1f2b0000 {
+ status = "disabled";
+ device_type = "pci";
+ compatible = "apm,xgene-pcie", "apm,xgene2-pcie";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
+ 0xc0 0xd0000000 0x0 0x00040000>; /* PCI config space */
+ reg-names = "csr", "cfg";
+ ranges = <0x01000000 0x00 0x00000000 0xc0 0x10000000 0x00 0x00010000 /* io */
+ 0x02000000 0x00 0x20000000 0xc1 0x20000000 0x00 0x20000000 /* mem */
+ 0x43000000 0xe0 0x00000000 0xe0 0x00000000 0x20 0x00000000>; /* mem */
+ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x10 0x1
+ 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x11 0x1
+ 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x12 0x1
+ 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x13 0x1>;
+ dma-coherent;
+ clocks = <&pcie0clk 0>;
+ msi-parent = <&v2m0>;
+ };
+
+ pcie1: pcie@1f2c0000 {
+ status = "disabled";
+ device_type = "pci";
+ compatible = "apm,xgene-pcie", "apm,xgene2-pcie";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = < 0x00 0x1f2c0000 0x0 0x00010000 /* Controller registers */
+ 0xa0 0xd0000000 0x0 0x00040000>; /* PCI config space */
+ reg-names = "csr", "cfg";
+ ranges = <0x01000000 0x00 0x00000000 0xa0 0x10000000 0x00 0x00010000 /* io */
+ 0x02000000 0x00 0x20000000 0xa1 0x20000000 0x00 0x20000000 /* mem */
+ 0x43000000 0xb0 0x00000000 0xb0 0x00000000 0x10 0x00000000>; /* mem */
+ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
+ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x16 0x1
+ 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x17 0x1
+ 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x18 0x1
+ 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x19 0x1>;
+ dma-coherent;
+ clocks = <&pcie1clk 0>;
+ msi-parent = <&v2m0>;
+ };
+
sata1: sata@1a000000 {
compatible = "apm,xgene-ahci";
reg = <0x0 0x1a000000 0x0 0x1000>,
@@ -224,7 +553,39 @@
dma-coherent;
};
- sbgpio: sbgpio@17001000{
+ mmc0: mmc@1c000000 {
+ compatible = "arasan,sdhci-4.9a";
+ reg = <0x0 0x1c000000 0x0 0x100>;
+ interrupts = <0x0 0x49 0x4>;
+ dma-coherent;
+ no-1-8-v;
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <&sdioclk 0>, <&ahbclk 0>;
+ };
+
+ gfcgpio: gpio@1f63c000 {
+ compatible = "apm,xgene-gpio";
+ reg = <0x0 0x1f63c000 0x0 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ dwgpio: gpio@1c024000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x0 0x1c024000 0x0 0x1000>;
+ reg-io-width = <4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ porta: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ };
+ };
+
+ sbgpio: gpio@17001000{
compatible = "apm,xgene-gpio-sb";
reg = <0x0 0x17001000 0x0 0x400>;
#gpio-cells = <2>;
@@ -267,5 +628,33 @@
local-mac-address = [00 01 73 00 00 02];
phy-connection-type = "xgmii";
};
+
+ rng: rng@10520000 {
+ compatible = "apm,xgene-rng";
+ reg = <0x0 0x10520000 0x0 0x100>;
+ interrupts = <0x0 0x41 0x4>;
+ clocks = <&rngpkaclk 0>;
+ };
+
+ i2c1: i2c@10511000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0x0 0x10511000 0x0 0x1000>;
+ interrupts = <0 0x45 0x4>;
+ #clock-cells = <1>;
+ clocks = <&sbapbclk 0>;
+ bus_num = <1>;
+ };
+
+ i2c4: i2c@10640000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0x0 0x10640000 0x0 0x1000>;
+ interrupts = <0 0x3A 0x4>;
+ clocks = <&i2c4clk 0>;
+ bus_num = <4>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi
index 6c5ed119934f..fe30f7671ea3 100644
--- a/arch/arm64/boot/dts/apm/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi
@@ -25,6 +25,7 @@
reg = <0x0 0x000>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_0>;
};
cpu@001 {
device_type = "cpu";
@@ -32,6 +33,7 @@
reg = <0x0 0x001>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_0>;
};
cpu@100 {
device_type = "cpu";
@@ -39,6 +41,7 @@
reg = <0x0 0x100>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_1>;
};
cpu@101 {
device_type = "cpu";
@@ -46,6 +49,7 @@
reg = <0x0 0x101>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_1>;
};
cpu@200 {
device_type = "cpu";
@@ -53,6 +57,7 @@
reg = <0x0 0x200>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_2>;
};
cpu@201 {
device_type = "cpu";
@@ -60,6 +65,7 @@
reg = <0x0 0x201>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_2>;
};
cpu@300 {
device_type = "cpu";
@@ -67,6 +73,7 @@
reg = <0x0 0x300>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_3>;
};
cpu@301 {
device_type = "cpu";
@@ -74,6 +81,19 @@
reg = <0x0 0x301>;
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
+ next-level-cache = <&xgene_L2_3>;
+ };
+ xgene_L2_0: l2-cache-0 {
+ compatible = "cache";
+ };
+ xgene_L2_1: l2-cache-1 {
+ compatible = "cache";
+ };
+ xgene_L2_2: l2-cache-2 {
+ compatible = "cache";
+ };
+ xgene_L2_3: l2-cache-3 {
+ compatible = "cache";
};
};
@@ -150,6 +170,35 @@
clock-output-names = "socplldiv2";
};
+ ahbclk: ahbclk@17000000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x17000000 0x0 0x2000>;
+ reg-names = "div-reg";
+ divider-offset = <0x164>;
+ divider-width = <0x5>;
+ divider-shift = <0x0>;
+ clock-output-names = "ahbclk";
+ };
+
+ sdioclk: sdioclk@1f2ac000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f2ac000 0x0 0x1000
+ 0x0 0x17000000 0x0 0x2000>;
+ reg-names = "csr-reg", "div-reg";
+ csr-offset = <0x0>;
+ csr-mask = <0x2>;
+ enable-offset = <0x8>;
+ enable-mask = <0x2>;
+ divider-offset = <0x178>;
+ divider-width = <0x8>;
+ divider-shift = <0x0>;
+ clock-output-names = "sdioclk";
+ };
+
qmlclk: qmlclk {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
@@ -686,6 +735,50 @@
interrupts = <0x0 0x4f 0x4>;
};
+ mmc0: mmc@1c000000 {
+ compatible = "arasan,sdhci-4.9a";
+ reg = <0x0 0x1c000000 0x0 0x100>;
+ interrupts = <0x0 0x49 0x4>;
+ dma-coherent;
+ no-1-8-v;
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <&sdioclk 0>, <&ahbclk 0>;
+ };
+
+ gfcgpio: gpio0@1701c000 {
+ compatible = "apm,xgene-gpio";
+ reg = <0x0 0x1701c000 0x0 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ dwgpio: gpio@1c024000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x0 0x1c024000 0x0 0x1000>;
+ reg-io-width = <4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ porta: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ };
+ };
+
+ i2c0: i2c@10512000 {
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0x0 0x10512000 0x0 0x1000>;
+ interrupts = <0 0x44 0x4>;
+ #clock-cells = <1>;
+ clocks = <&ahbclk 0>;
+ bus_num = <0>;
+ };
+
phy1: phy@1f21a000 {
compatible = "apm,xgene-phy";
reg = <0x0 0x1f21a000 0x0 0x100>;
@@ -760,7 +853,26 @@
phy-names = "sata-phy";
};
- sbgpio: sbgpio@17001000{
+ /* Do not change dwusb name, coded for backward compatibility */
+ usb0: dwusb@19000000 {
+ status = "disabled";
+ compatible = "snps,dwc3";
+ reg = <0x0 0x19000000 0x0 0x100000>;
+ interrupts = <0x0 0x89 0x4>;
+ dma-coherent;
+ dr_mode = "host";
+ };
+
+ usb1: dwusb@19800000 {
+ status = "disabled";
+ compatible = "snps,dwc3";
+ reg = <0x0 0x19800000 0x0 0x100000>;
+ interrupts = <0x0 0x8a 0x4>;
+ dma-coherent;
+ dr_mode = "host";
+ };
+
+ sbgpio: gpio@17001000{
compatible = "apm,xgene-gpio-sb";
reg = <0x0 0x17001000 0x0 0x400>;
#gpio-cells = <2>;
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts
index 93bc3d7d51c0..8826f834f54f 100644
--- a/arch/arm64/boot/dts/arm/juno-r1.dts
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -60,6 +60,28 @@
};
};
+ idle-states {
+ entry-method = "arm,psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2000>;
+ };
+
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x1010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2500>;
+ };
+ };
+
A57_0: cpu@0 {
compatible = "arm,cortex-a57","arm,armv8";
reg = <0x0 0x0>;
@@ -67,6 +89,7 @@
enable-method = "psci";
next-level-cache = <&A57_L2>;
clocks = <&scpi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A57_1: cpu@1 {
@@ -76,6 +99,7 @@
enable-method = "psci";
next-level-cache = <&A57_L2>;
clocks = <&scpi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_0: cpu@100 {
@@ -85,6 +109,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_1: cpu@101 {
@@ -94,6 +119,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_2: cpu@102 {
@@ -103,6 +129,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_3: cpu@103 {
@@ -112,6 +139,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A57_L2: l2-cache0 {
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index 53442b5ee4ff..dcfcf15a17f5 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -60,6 +60,28 @@
};
};
+ idle-states {
+ entry-method = "arm,psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2000>;
+ };
+
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x1010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2500>;
+ };
+ };
+
A57_0: cpu@0 {
compatible = "arm,cortex-a57","arm,armv8";
reg = <0x0 0x0>;
@@ -67,6 +89,7 @@
enable-method = "psci";
next-level-cache = <&A57_L2>;
clocks = <&scpi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A57_1: cpu@1 {
@@ -76,6 +99,7 @@
enable-method = "psci";
next-level-cache = <&A57_L2>;
clocks = <&scpi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_0: cpu@100 {
@@ -85,6 +109,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_1: cpu@101 {
@@ -94,6 +119,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_2: cpu@102 {
@@ -103,6 +129,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A53_3: cpu@103 {
@@ -112,6 +139,7 @@
enable-method = "psci";
next-level-cache = <&A53_L2>;
clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
};
A57_L2: l2-cache0 {
diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
index 244baf879dc9..6bb3d4d9efa9 100644
--- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts
+++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
@@ -50,10 +50,28 @@
device_type = "memory";
reg = <0x000000000 0x80000000 0x00000000 0x40000000>;
};
+};
+
+&i2c0 {
+ status = "ok";
+};
+
+&i2c1 {
+ status = "ok";
+};
+
+&uart3 {
+ status = "ok";
+};
- soc: soc {
- uart3: serial@66130000 {
- status = "ok";
- };
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-ecc-mode = "hw";
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+ #address-cells = <1>;
+ #size-cells = <1>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi
index 3c92d92278e5..a510d3a8e647 100644
--- a/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@ -31,6 +31,7 @@
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/bcm-ns2.h>
/memreserve/ 0x84b00000 0x00000008;
@@ -44,36 +45,44 @@
#address-cells = <2>;
#size-cells = <0>;
- cpu@0 {
+ A57_0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a57", "arm,armv8";
reg = <0 0>;
enable-method = "spin-table";
cpu-release-addr = <0 0x84b00000>;
+ next-level-cache = <&CLUSTER0_L2>;
};
- cpu@1 {
+ A57_1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a57", "arm,armv8";
reg = <0 1>;
enable-method = "spin-table";
cpu-release-addr = <0 0x84b00000>;
+ next-level-cache = <&CLUSTER0_L2>;
};
- cpu@2 {
+ A57_2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a57", "arm,armv8";
reg = <0 2>;
enable-method = "spin-table";
cpu-release-addr = <0 0x84b00000>;
+ next-level-cache = <&CLUSTER0_L2>;
};
- cpu@3 {
+ A57_3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a57", "arm,armv8";
reg = <0 3>;
enable-method = "spin-table";
cpu-release-addr = <0 0x84b00000>;
+ next-level-cache = <&CLUSTER0_L2>;
+ };
+
+ CLUSTER0_L2: l2-cache@000 {
+ compatible = "cache";
};
};
@@ -89,12 +98,154 @@
IRQ_TYPE_EDGE_RISING)>;
};
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&A57_0>,
+ <&A57_1>,
+ <&A57_2>,
+ <&A57_3>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ osc: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ iprocmed: iprocmed {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&genpll_scr BCM_NS2_GENPLL_SCR_SCR_CLK>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ iprocslow: iprocslow {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&genpll_scr BCM_NS2_GENPLL_SCR_SCR_CLK>;
+ clock-div = <4>;
+ clock-mult = <1>;
+ };
+ };
+
soc: soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0 0 0xffffffff>;
+ smmu: mmu@64000000 {
+ compatible = "arm,mmu-500";
+ reg = <0x64000000 0x40000>;
+ #global-interrupts = <2>;
+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 235 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 236 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 237 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
+ mmu-masters;
+ };
+
+ lcpll_ddr: lcpll_ddr@6501d058 {
+ #clock-cells = <1>;
+ compatible = "brcm,ns2-lcpll-ddr";
+ reg = <0x6501d058 0x20>,
+ <0x6501c020 0x4>,
+ <0x6501d04c 0x4>;
+ clocks = <&osc>;
+ clock-output-names = "lcpll_ddr", "pcie_sata_usb",
+ "ddr", "ddr_ch2_unused",
+ "ddr_ch3_unused", "ddr_ch4_unused",
+ "ddr_ch5_unused";
+ };
+
+ lcpll_ports: lcpll_ports@6501d078 {
+ #clock-cells = <1>;
+ compatible = "brcm,ns2-lcpll-ports";
+ reg = <0x6501d078 0x20>,
+ <0x6501c020 0x4>,
+ <0x6501d054 0x4>;
+ clocks = <&osc>;
+ clock-output-names = "lcpll_ports", "wan", "rgmii",
+ "ports_ch2_unused",
+ "ports_ch3_unused",
+ "ports_ch4_unused",
+ "ports_ch5_unused";
+ };
+
+ genpll_scr: genpll_scr@6501d098 {
+ #clock-cells = <1>;
+ compatible = "brcm,ns2-genpll-scr";
+ reg = <0x6501d098 0x32>,
+ <0x6501c020 0x4>,
+ <0x6501d044 0x4>;
+ clocks = <&osc>;
+ clock-output-names = "genpll_scr", "scr", "fs",
+ "audio_ref", "scr_ch3_unused",
+ "scr_ch4_unused", "scr_ch5_unused";
+ };
+
+ genpll_sw: genpll_sw@6501d0c4 {
+ #clock-cells = <1>;
+ compatible = "brcm,ns2-genpll-sw";
+ reg = <0x6501d0c4 0x32>,
+ <0x6501c020 0x4>,
+ <0x6501d044 0x4>;
+ clocks = <&osc>;
+ clock-output-names = "genpll_sw", "rpe", "250", "nic",
+ "chimp", "port", "sdio";
+ };
+
+ crmu: crmu@65024000 {
+ compatible = "syscon";
+ reg = <0x65024000 0x100>;
+ };
+
+ reboot@65024000 {
+ compatible ="syscon-reboot";
+ regmap = <&crmu>;
+ offset = <0x90>;
+ mask = <0xfffffffd>;
+ };
+
gic: interrupt-controller@65210000 {
compatible = "arm,gic-400";
#interrupt-cells = <3>;
@@ -105,14 +256,53 @@
<0x65260000 0x1000>;
};
+ i2c0: i2c@66080000 {
+ compatible = "brcm,iproc-i2c";
+ reg = <0x66080000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 394 IRQ_TYPE_NONE>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@660b0000 {
+ compatible = "brcm,iproc-i2c";
+ reg = <0x660b0000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 395 IRQ_TYPE_NONE>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
+
uart3: serial@66130000 {
compatible = "snps,dw-apb-uart";
reg = <0x66130000 0x100>;
interrupts = <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clock-frequency = <23961600>;
+ clocks = <&osc>;
status = "disabled";
};
+
+ hwrng: hwrng@66220000 {
+ compatible = "brcm,iproc-rng200";
+ reg = <0x66220000 0x28>;
+ };
+
+ nand: nand@66460000 {
+ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
+ reg = <0x66460000 0x600>,
+ <0x67015408 0x600>,
+ <0x66460f00 0x20>;
+ reg-names = "nand", "iproc-idm", "iproc-ext";
+ interrupts = <GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ brcm,nand-has-wp;
+ };
};
};
diff --git a/arch/arm64/boot/dts/exynos/exynos7-espresso.dts b/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
index 5424cc450f72..d8767b00862e 100644
--- a/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
+++ b/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
@@ -11,6 +11,7 @@
/dts-v1/;
#include "exynos7.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "Samsung Exynos7 Espresso board based on EXYNOS7";
@@ -52,11 +53,288 @@
status = "okay";
};
+&hsi2c_4 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <200000>;
+ status = "okay";
+
+ s2mps15_pmic@66 {
+ compatible = "samsung,s2mps15-pmic";
+ reg = <0x66>;
+ interrupts = <2 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpa0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_irq>;
+ wakeup-source;
+
+ s2mps15_osc: clocks {
+ compatible = "samsung,s2mps13-clk";
+ #clock-cells = <1>;
+ clock-output-names = "s2mps13_ap", "s2mps13_cp",
+ "s2mps13_bt";
+ };
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "vdd_ldo1";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <900000>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "vqmmc-sdcard";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "vdd_ldo3";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "vdd_ldo4";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1110000>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "vdd_ldo5";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "vdd_ldo6";
+ regulator-min-microvolt = <2250000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "vdd_ldo7";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "vdd_ldo8";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "vdd_ldo9";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "vdd_ldo10";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "vdd_ldo11";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "vdd_ldo12";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "vdd_ldo13";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "vdd_ldo14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3375000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "vmmc-sdcard";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3375000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "vdd_ldo18";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "vdd_ldo19";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3375000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo21_reg: LDO21 {
+ regulator-name = "vdd_ldo21";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3375000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo23_reg: LDO23 {
+ regulator-name = "vdd_ldo23";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "vdd_ldo25";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3375000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo26_reg: LDO26 {
+ regulator-name = "vdd_ldo26";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1470000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ ldo27_reg: LDO27 {
+ regulator-name = "vdd_ldo27";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-enable-ramp-delay = <125>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <25000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_atlas";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <12500>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <12500>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "vdd_buck5";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-ramp-delay = <25000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-ramp-delay = <12500>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "vdd_buck7";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-ramp-delay = <25000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "vdd_buck8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-ramp-delay = <25000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "vdd_buck9";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2100000>;
+ regulator-always-on;
+ regulator-ramp-delay = <25000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+
+ buck10_reg: BUCK10 {
+ regulator-name = "vdd_buck10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-ramp-delay = <25000>;
+ regulator-enable-ramp-delay = <250>;
+ };
+ };
+ };
+};
+
+&pinctrl_alive {
+ pmic_irq: pmic-irq {
+ samsung,pins = "gpa0-2";
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+};
+
&mmc_0 {
status = "okay";
num-slots = <1>;
- broken-cd;
cap-mmc-highspeed;
+ mmc-hs200-1_8v;
non-removable;
card-detect-delay = <200>;
clock-frequency = <800000000>;
@@ -80,5 +358,7 @@
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
bus-width = <4>;
+ vmmc-supply = <&ldo17_reg>;
+ vqmmc-supply = <&ldo2_reg>;
disable-wp;
};
diff --git a/arch/arm64/boot/dts/exynos/exynos7.dtsi b/arch/arm64/boot/dts/exynos/exynos7.dtsi
index f9c5a549c2c0..93108f1a90f9 100644
--- a/arch/arm64/boot/dts/exynos/exynos7.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos7.dtsi
@@ -454,6 +454,13 @@
reg = <0x105c0000 0x5000>;
};
+ reboot: syscon-reboot {
+ compatible = "syscon-reboot";
+ regmap = <&pmu_system_controller>;
+ offset = <0x0400>;
+ mask = <0x1>;
+ };
+
rtc: rtc@10590000 {
compatible = "samsung,s3c6410-rtc";
reg = <0x10590000 0x100>;
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index c4957a4aa5aa..f3c25165dad3 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -1,6 +1,7 @@
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-rdb.dtb
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-simu.dtb
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
new file mode 100644
index 000000000000..ce235577e90f
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
@@ -0,0 +1,116 @@
+/*
+ * Device Tree Include file for Freescale Layerscape-1043A family SoC.
+ *
+ * Copyright 2014-2015, Freescale Semiconductor
+ *
+ * Mingkai Hu <Mingkai.hu@freescale.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "fsl-ls1043a.dtsi"
+
+/ {
+ model = "LS1043A RDB Board";
+};
+
+&i2c0 {
+ status = "okay";
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <1000>;
+ };
+ adt7461a@4c {
+ compatible = "adi,adt7461";
+ reg = <0x4c>;
+ };
+ eeprom@52 {
+ compatible = "at24,24c512";
+ reg = <0x52>;
+ };
+ eeprom@53 {
+ compatible = "at24,24c512";
+ reg = <0x53>;
+ };
+ rtc@68 {
+ compatible = "pericom,pt7c4338";
+ reg = <0x68>;
+ };
+};
+
+&ifc {
+ status = "okay";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ /* NOR, NAND Flashes and FPGA on board */
+ ranges = <0x0 0x0 0x0 0x60000000 0x08000000
+ 0x1 0x0 0x0 0x7e800000 0x00010000
+ 0x2 0x0 0x0 0x7fb00000 0x00000100>;
+
+ nor@0,0 {
+ compatible = "cfi-flash";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ nand@1,0 {
+ compatible = "fsl,ifc-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1 0x0 0x10000>;
+ };
+
+ cpld: board-control@2,0 {
+ compatible = "fsl,ls1043ardb-cpld";
+ reg = <0x2 0x0 0x0000100>;
+ };
+};
+
+&duart0 {
+ status = "okay";
+};
+
+&duart1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
new file mode 100644
index 000000000000..42a61549afd4
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -0,0 +1,527 @@
+/*
+ * Device Tree Include file for Freescale Layerscape-1043A family SoC.
+ *
+ * Copyright 2014-2015, Freescale Semiconductor
+ *
+ * Mingkai Hu <Mingkai.hu@freescale.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/ {
+ compatible = "fsl,ls1043a";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ /*
+ * We expect the enable-method for cpu's to be "psci", but this
+ * is dependent on the SoC FW, which will fill this in.
+ *
+ * Currently supported enable-method is psci v0.2
+ */
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x0 0x0>;
+ clocks = <&clockgen 1 0>;
+ };
+
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x0 0x1>;
+ clocks = <&clockgen 1 0>;
+ };
+
+ cpu2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x0 0x2>;
+ clocks = <&clockgen 1 0>;
+ };
+
+ cpu3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ reg = <0x0 0x3>;
+ clocks = <&clockgen 1 0>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0 0x80000000>;
+ /* DRAM space 1, size: 2GiB DRAM */
+ };
+
+ sysclk: sysclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "sysclk";
+ };
+
+ reboot {
+ compatible ="syscon-reboot";
+ regmap = <&dcfg>;
+ offset = <0xb0>;
+ mask = <0x02>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0x1>, /* Physical Secure PPI */
+ <1 14 0x1>, /* Physical Non-Secure PPI */
+ <1 11 0x1>, /* Virtual PPI */
+ <1 10 0x1>; /* Hypervisor PPI */
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <0 106 0x4>,
+ <0 107 0x4>,
+ <0 95 0x4>,
+ <0 97 0x4>;
+ interrupt-affinity = <&cpu0>,
+ <&cpu1>,
+ <&cpu2>,
+ <&cpu3>;
+ };
+
+ gic: interrupt-controller@1400000 {
+ compatible = "arm,gic-400";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x0 0x1401000 0 0x1000>, /* GICD */
+ <0x0 0x1402000 0 0x2000>, /* GICC */
+ <0x0 0x1404000 0 0x2000>, /* GICH */
+ <0x0 0x1406000 0 0x2000>; /* GICV */
+ interrupts = <1 9 0xf08>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ clockgen: clocking@1ee1000 {
+ compatible = "fsl,ls1043a-clockgen";
+ reg = <0x0 0x1ee1000 0x0 0x1000>;
+ #clock-cells = <2>;
+ clocks = <&sysclk>;
+ };
+
+ scfg: scfg@1570000 {
+ compatible = "fsl,ls1043a-scfg", "syscon";
+ reg = <0x0 0x1570000 0x0 0x10000>;
+ big-endian;
+ };
+
+ dcfg: dcfg@1ee0000 {
+ compatible = "fsl,ls1043a-dcfg", "syscon";
+ reg = <0x0 0x1ee0000 0x0 0x10000>;
+ big-endian;
+ };
+
+ ifc: ifc@1530000 {
+ compatible = "fsl,ifc", "simple-bus";
+ reg = <0x0 0x1530000 0x0 0x10000>;
+ interrupts = <0 43 0x4>;
+ };
+
+ esdhc: esdhc@1560000 {
+ compatible = "fsl,ls1043a-esdhc", "fsl,esdhc";
+ reg = <0x0 0x1560000 0x0 0x10000>;
+ interrupts = <0 62 0x4>;
+ clock-frequency = <0>;
+ voltage-ranges = <1800 1800 3300 3300>;
+ sdhci,auto-cmd12;
+ big-endian;
+ bus-width = <4>;
+ };
+
+ dspi0: dspi@2100000 {
+ compatible = "fsl,ls1043a-dspi", "fsl,ls1021a-v1.0-dspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2100000 0x0 0x10000>;
+ interrupts = <0 64 0x4>;
+ clock-names = "dspi";
+ clocks = <&clockgen 4 0>;
+ spi-num-chipselects = <5>;
+ big-endian;
+ status = "disabled";
+ };
+
+ dspi1: dspi@2110000 {
+ compatible = "fsl,ls1043a-dspi", "fsl,ls1021a-v1.0-dspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2110000 0x0 0x10000>;
+ interrupts = <0 65 0x4>;
+ clock-names = "dspi";
+ clocks = <&clockgen 4 0>;
+ spi-num-chipselects = <5>;
+ big-endian;
+ status = "disabled";
+ };
+
+ i2c0: i2c@2180000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2180000 0x0 0x10000>;
+ interrupts = <0 56 0x4>;
+ clock-names = "i2c";
+ clocks = <&clockgen 4 0>;
+ dmas = <&edma0 1 39>,
+ <&edma0 1 38>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c1: i2c@2190000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2190000 0x0 0x10000>;
+ interrupts = <0 57 0x4>;
+ clock-names = "i2c";
+ clocks = <&clockgen 4 0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@21a0000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x21a0000 0x0 0x10000>;
+ interrupts = <0 58 0x4>;
+ clock-names = "i2c";
+ clocks = <&clockgen 4 0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@21b0000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x21b0000 0x0 0x10000>;
+ interrupts = <0 59 0x4>;
+ clock-names = "i2c";
+ clocks = <&clockgen 4 0>;
+ status = "disabled";
+ };
+
+ duart0: serial@21c0500 {
+ compatible = "fsl,ns16550", "ns16550a";
+ reg = <0x00 0x21c0500 0x0 0x100>;
+ interrupts = <0 54 0x4>;
+ clocks = <&clockgen 4 0>;
+ };
+
+ duart1: serial@21c0600 {
+ compatible = "fsl,ns16550", "ns16550a";
+ reg = <0x00 0x21c0600 0x0 0x100>;
+ interrupts = <0 54 0x4>;
+ clocks = <&clockgen 4 0>;
+ };
+
+ duart2: serial@21d0500 {
+ compatible = "fsl,ns16550", "ns16550a";
+ reg = <0x0 0x21d0500 0x0 0x100>;
+ interrupts = <0 55 0x4>;
+ clocks = <&clockgen 4 0>;
+ };
+
+ duart3: serial@21d0600 {
+ compatible = "fsl,ns16550", "ns16550a";
+ reg = <0x0 0x21d0600 0x0 0x100>;
+ interrupts = <0 55 0x4>;
+ clocks = <&clockgen 4 0>;
+ };
+
+ gpio1: gpio@2300000 {
+ compatible = "fsl,ls1043a-gpio";
+ reg = <0x0 0x2300000 0x0 0x10000>;
+ interrupts = <0 66 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio2: gpio@2310000 {
+ compatible = "fsl,ls1043a-gpio";
+ reg = <0x0 0x2310000 0x0 0x10000>;
+ interrupts = <0 67 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio3: gpio@2320000 {
+ compatible = "fsl,ls1043a-gpio";
+ reg = <0x0 0x2320000 0x0 0x10000>;
+ interrupts = <0 68 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio4: gpio@2330000 {
+ compatible = "fsl,ls1043a-gpio";
+ reg = <0x0 0x2330000 0x0 0x10000>;
+ interrupts = <0 134 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ lpuart0: serial@2950000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2950000 0x0 0x1000>;
+ interrupts = <0 48 0x4>;
+ clocks = <&clockgen 0 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart1: serial@2960000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2960000 0x0 0x1000>;
+ interrupts = <0 49 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart2: serial@2970000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2970000 0x0 0x1000>;
+ interrupts = <0 50 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart3: serial@2980000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2980000 0x0 0x1000>;
+ interrupts = <0 51 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart4: serial@2990000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2990000 0x0 0x1000>;
+ interrupts = <0 52 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart5: serial@29a0000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x29a0000 0x0 0x1000>;
+ interrupts = <0 53 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ wdog0: wdog@2ad0000 {
+ compatible = "fsl,ls1043a-wdt", "fsl,imx21-wdt";
+ reg = <0x0 0x2ad0000 0x0 0x10000>;
+ interrupts = <0 83 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "wdog";
+ big-endian;
+ };
+
+ edma0: edma@2c00000 {
+ #dma-cells = <2>;
+ compatible = "fsl,vf610-edma";
+ reg = <0x0 0x2c00000 0x0 0x10000>,
+ <0x0 0x2c10000 0x0 0x10000>,
+ <0x0 0x2c20000 0x0 0x10000>;
+ interrupts = <0 103 0x4>,
+ <0 103 0x4>;
+ interrupt-names = "edma-tx", "edma-err";
+ dma-channels = <32>;
+ big-endian;
+ clock-names = "dmamux0", "dmamux1";
+ clocks = <&clockgen 4 0>,
+ <&clockgen 4 0>;
+ };
+
+ usb0: usb3@2f00000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0x2f00000 0x0 0x10000>;
+ interrupts = <0 60 0x4>;
+ dr_mode = "host";
+ };
+
+ usb1: usb3@3000000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0x3000000 0x0 0x10000>;
+ interrupts = <0 61 0x4>;
+ dr_mode = "host";
+ };
+
+ usb2: usb3@3100000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0x3100000 0x0 0x10000>;
+ interrupts = <0 63 0x4>;
+ dr_mode = "host";
+ };
+
+ sata: sata@3200000 {
+ compatible = "fsl,ls1043a-ahci", "fsl,ls1021a-ahci";
+ reg = <0x0 0x3200000 0x0 0x10000>;
+ interrupts = <0 69 0x4>;
+ clocks = <&clockgen 4 0>;
+ };
+
+ msi1: msi-controller1@1571000 {
+ compatible = "fsl,1s1043a-msi";
+ reg = <0x0 0x1571000 0x0 0x8>;
+ msi-controller;
+ interrupts = <0 116 0x4>;
+ };
+
+ msi2: msi-controller2@1572000 {
+ compatible = "fsl,1s1043a-msi";
+ reg = <0x0 0x1572000 0x0 0x8>;
+ msi-controller;
+ interrupts = <0 126 0x4>;
+ };
+
+ msi3: msi-controller3@1573000 {
+ compatible = "fsl,1s1043a-msi";
+ reg = <0x0 0x1573000 0x0 0x8>;
+ msi-controller;
+ interrupts = <0 160 0x4>;
+ };
+
+ pcie@3400000 {
+ compatible = "fsl,ls1043a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */
+ 0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 118 0x4>, /* controller interrupt */
+ <0 117 0x4>; /* PME interrupt */
+ interrupt-names = "intr", "pme";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <4>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&msi1>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 110 0x4>,
+ <0000 0 0 2 &gic 0 111 0x4>,
+ <0000 0 0 3 &gic 0 112 0x4>,
+ <0000 0 0 4 &gic 0 113 0x4>;
+ };
+
+ pcie@3500000 {
+ compatible = "fsl,ls1043a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */
+ 0x48 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 128 0x4>,
+ <0 127 0x4>;
+ interrupt-names = "intr", "pme";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <2>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&msi2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 120 0x4>,
+ <0000 0 0 2 &gic 0 121 0x4>,
+ <0000 0 0 3 &gic 0 122 0x4>,
+ <0000 0 0 4 &gic 0 123 0x4>;
+ };
+
+ pcie@3600000 {
+ compatible = "fsl,ls1043a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */
+ 0x50 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 162 0x4>,
+ <0 161 0x4>;
+ interrupt-names = "intr", "pme";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <2>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&msi3>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 154 0x4>,
+ <0000 0 0 2 &gic 0 155 0x4>,
+ <0000 0 0 3 &gic 0 156 0x4>,
+ <0000 0 0 4 &gic 0 157 0x4>;
+ };
+ };
+
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
index 925552e7b4f3..2b23d0360683 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
@@ -153,6 +153,18 @@
};
};
+ rstcr: syscon@1e60000 {
+ compatible = "fsl,ls2080a-rstcr", "syscon";
+ reg = <0x0 0x1e60000 0x0 0x4>;
+ };
+
+ reboot {
+ compatible ="syscon-reboot";
+ regmap = <&rstcr>;
+ offset = <0x0>;
+ mask = <0x2>;
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <1 13 0x8>, /* Physical Secure PPI, active-low */
@@ -193,6 +205,62 @@
interrupts = <0 32 0x4>; /* Level high type */
};
+ cluster1_core0_watchdog: wdt@c000000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc000000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster1_core1_watchdog: wdt@c010000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc010000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster2_core0_watchdog: wdt@c100000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc100000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster2_core1_watchdog: wdt@c110000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc110000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster3_core0_watchdog: wdt@c200000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc200000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster3_core1_watchdog: wdt@c210000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc210000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster4_core0_watchdog: wdt@c300000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc300000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
+ cluster4_core1_watchdog: wdt@c310000 {
+ compatible = "arm,sp805-wdt", "arm,primecell";
+ reg = <0x0 0xc310000 0x0 0x1000>;
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "apb_pclk", "wdog_clk";
+ };
+
fsl_mc: fsl-mc@80c000000 {
compatible = "fsl,qoriq-mc";
reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
index 8d43a0fce522..818525197508 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -32,3 +32,10 @@
reg = <0x0 0x0 0x0 0x40000000>;
};
};
+
+&uart2 {
+ label = "LS-UART0";
+};
+&uart3 {
+ label = "LS-UART1";
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 82d2488a0e86..ad1f1ebcb05c 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -147,6 +147,7 @@
compatible = "hisilicon,hi6220-sysctrl", "syscon";
reg = <0x0 0xf7030000 0x0 0x2000>;
#clock-cells = <1>;
+ #reset-cells = <1>;
};
media_ctrl: media_ctrl@f4410000 {
diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
index 4ff16d016e34..c1ea999c7be1 100644
--- a/arch/arm64/boot/dts/hisilicon/hip05.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
@@ -246,6 +246,11 @@
clock-frequency = <200000000>;
};
+ peri_c_subctrl: syscon@80000000 {
+ compatible = "hisilicon,hip05-perisubc", "syscon";
+ reg = < 0x0 0x80000000 0x0 0x10000>;
+ };
+
uart0: uart@80300000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x80300000 0x0 0x10000>;
diff --git a/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi b/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi
index 606dd5a05c2d..da7b6e613257 100644
--- a/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi
@@ -10,8 +10,8 @@ soc0: soc@000000000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "hisilicon,hns-mdio";
- reg = <0x0 0x803c0000 0x0 0x10000
- 0x0 0x80000000 0x0 0x10000>;
+ reg = <0x0 0x803c0000 0x0 0x10000>;
+ subctrl-vbase = <&peri_c_subctrl>;
soc0_phy0: ethernet-phy@0 {
reg = <0x0>;
diff --git a/arch/arm64/boot/dts/marvell/berlin4ct.dtsi b/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
index a3b5f1d4a240..099ad93bb49b 100644
--- a/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
+++ b/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
@@ -55,7 +55,7 @@
};
psci {
- compatible = "arm,psci-0.2";
+ compatible = "arm,psci-1.0", "arm,psci-0.2";
method = "smc";
};
@@ -68,6 +68,7 @@
device_type = "cpu";
reg = <0x0>;
enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
};
cpu1: cpu@1 {
@@ -75,6 +76,7 @@
device_type = "cpu";
reg = <0x1>;
enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
};
cpu2: cpu@2 {
@@ -82,6 +84,7 @@
device_type = "cpu";
reg = <0x2>;
enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
};
cpu3: cpu@3 {
@@ -89,6 +92,19 @@
device_type = "cpu";
reg = <0x3>;
enable-method = "psci";
+ cpu-idle-states = <&CPU_SLEEP_0>;
+ };
+
+ idle-states {
+ entry-method = "psci";
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ arm,psci-suspend-param = <0x0010000>;
+ entry-latency-us = <75>;
+ exit-latency-us = <155>;
+ min-residency-us = <1000>;
+ };
};
};
@@ -225,6 +241,16 @@
};
};
+ soc_pinctrl: pin-controller@ea8000 {
+ compatible = "marvell,berlin4ct-soc-pinctrl";
+ reg = <0xea8000 0x14>;
+ };
+
+ avio_pinctrl: pin-controller@ea8400 {
+ compatible = "marvell,berlin4ct-avio-pinctrl";
+ reg = <0xea8400 0x8>;
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
@@ -241,6 +267,29 @@
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
+ wdt0: watchdog@3000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x3000 0x100>;
+ clocks = <&osc>;
+ interrupts = <0>;
+ };
+
+ wdt1: watchdog@4000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x4000 0x100>;
+ clocks = <&osc>;
+ interrupts = <1>;
+ status = "disabled";
+ };
+
+ wdt2: watchdog@5000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x5000 0x100>;
+ clocks = <&osc>;
+ interrupts = <2>;
+ status = "disabled";
+ };
+
sm_gpio0: gpio@8000 {
compatible = "snps,dw-apb-gpio";
reg = <0x8000 0x400>;
@@ -278,6 +327,18 @@
clocks = <&osc>;
reg-shift = <2>;
status = "disabled";
+ pinctrl-0 = <&uart0_pmux>;
+ pinctrl-names = "default";
+ };
+ };
+
+ system_pinctrl: pin-controller@fe2200 {
+ compatible = "marvell,berlin4ct-system-pinctrl";
+ reg = <0xfe2200 0xc>;
+
+ uart0_pmux: uart0-pmux {
+ groups = "SM_URT0_TXD", "SM_URT0_RXD";
+ function = "uart0";
};
};
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 811cb760ba49..e427f04a9f45 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -13,6 +13,7 @@
*/
/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
#include "mt8173.dtsi"
/ {
@@ -32,6 +33,15 @@
};
chosen { };
+
+ usb_p1_vbus: regulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
&i2c1 {
@@ -92,6 +102,13 @@
};
&pio {
+ disp_pwm0_pins: disp_pwm0_pins {
+ pins1 {
+ pinmux = <MT8173_PIN_87_DISP_PWM0__FUNC_DISP_PWM0>;
+ output-low;
+ };
+ };
+
mmc0_pins_default: mmc0default {
pins_cmd_dat {
pinmux = <MT8173_PIN_57_MSDC0_DAT0__FUNC_MSDC0_DAT0>,
@@ -190,6 +207,12 @@
};
};
+&pwm0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&disp_pwm0_pins>;
+ status = "okay";
+};
+
&pwrap {
pmic: mt6397 {
compatible = "mediatek,mt6397";
@@ -408,3 +431,9 @@
&uart0 {
status = "okay";
};
+
+&usb30 {
+ vusb33-supply = <&mt6397_vusb_reg>;
+ vbus-supply = <&usb_p1_vbus>;
+ mediatek,wakeup-src = <1>;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 4dd5f93d0303..ec135eae31f5 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -14,8 +14,9 @@
#include <dt-bindings/clock/mt8173-clk.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
#include <dt-bindings/power/mt8173-power.h>
-#include <dt-bindings/reset-controller/mt8173-resets.h>
+#include <dt-bindings/reset/mt8173-resets.h>
#include "mt8173-pinfunc.h"
/ {
@@ -95,7 +96,7 @@
};
psci {
- compatible = "arm,psci";
+ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
method = "smc";
cpu_suspend = <0x84000001>;
cpu_off = <0x84000002>;
@@ -247,6 +248,15 @@
reg = <0 0x10007000 0 0x100>;
};
+ timer: timer@10008000 {
+ compatible = "mediatek,mt8173-timer",
+ "mediatek,mt6577-timer";
+ reg = <0 0x10008000 0 0x1000>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_CLK_13M>,
+ <&topckgen CLK_TOP_RTC_SEL>;
+ };
+
pwrap: pwrap@1000d000 {
compatible = "mediatek,mt8173-pwrap";
reg = <0 0x1000d000 0 0x1000>;
@@ -510,12 +520,75 @@
status = "disabled";
};
+ usb30: usb@11270000 {
+ compatible = "mediatek,mt8173-xhci";
+ reg = <0 0x11270000 0 0x1000>,
+ <0 0x11280700 0 0x0100>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+ clocks = <&topckgen CLK_TOP_USB30_SEL>,
+ <&pericfg CLK_PERI_USB0>,
+ <&pericfg CLK_PERI_USB1>;
+ clock-names = "sys_ck",
+ "wakeup_deb_p0",
+ "wakeup_deb_p1";
+ phys = <&phy_port0 PHY_TYPE_USB3>,
+ <&phy_port1 PHY_TYPE_USB2>;
+ mediatek,syscon-wakeup = <&pericfg>;
+ status = "okay";
+ };
+
+ u3phy: usb-phy@11290000 {
+ compatible = "mediatek,mt8173-u3phy";
+ reg = <0 0x11290000 0 0x800>;
+ clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
+ clock-names = "u3phya_ref";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "okay";
+
+ phy_port0: port@11290800 {
+ reg = <0 0x11290800 0 0x800>;
+ #phy-cells = <1>;
+ status = "okay";
+ };
+
+ phy_port1: port@11291000 {
+ reg = <0 0x11291000 0 0x800>;
+ #phy-cells = <1>;
+ status = "okay";
+ };
+ };
+
mmsys: clock-controller@14000000 {
compatible = "mediatek,mt8173-mmsys", "syscon";
reg = <0 0x14000000 0 0x1000>;
#clock-cells = <1>;
};
+ pwm0: pwm@1401e000 {
+ compatible = "mediatek,mt8173-disp-pwm",
+ "mediatek,mt6595-disp-pwm";
+ reg = <0 0x1401e000 0 0x1000>;
+ #pwm-cells = <2>;
+ clocks = <&mmsys CLK_MM_DISP_PWM026M>,
+ <&mmsys CLK_MM_DISP_PWM0MM>;
+ clock-names = "main", "mm";
+ status = "disabled";
+ };
+
+ pwm1: pwm@1401f000 {
+ compatible = "mediatek,mt8173-disp-pwm",
+ "mediatek,mt6595-disp-pwm";
+ reg = <0 0x1401f000 0 0x1000>;
+ #pwm-cells = <2>;
+ clocks = <&mmsys CLK_MM_DISP_PWM126M>,
+ <&mmsys CLK_MM_DISP_PWM1MM>;
+ clock-names = "main", "mm";
+ status = "disabled";
+ };
+
imgsys: clock-controller@15000000 {
compatible = "mediatek,mt8173-imgsys", "syscon";
reg = <0 0x15000000 0 0x1000>;
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
index 6b8abbe68746..db17c5d5689c 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -20,6 +20,10 @@
aliases {
serial0 = &blsp1_uart2;
serial1 = &blsp1_uart1;
+ usid0 = &pm8916_0;
+ i2c0 = &blsp_i2c2;
+ i2c1 = &blsp_i2c6;
+ i2c3 = &blsp_i2c4;
};
chosen {
@@ -27,7 +31,16 @@
};
soc {
+ serial@78af000 {
+ label = "LS-UART0";
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp1_uart1_default>;
+ pinctrl-1 = <&blsp1_uart1_sleep>;
+ };
+
serial@78b0000 {
+ label = "LS-UART1";
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&blsp1_uart2_default>;
@@ -36,26 +49,31 @@
i2c@78b6000 {
/* On Low speed expansion */
+ label = "LS-I2C0";
status = "okay";
};
i2c@78b8000 {
/* On High speed expansion */
+ label = "HS-I2C2";
status = "okay";
};
i2c@78ba000 {
/* On Low speed expansion */
+ label = "LS-I2C1";
status = "okay";
};
spi@78b7000 {
/* On High speed expansion */
+ label = "HS-SPI1";
status = "okay";
};
spi@78b9000 {
/* On Low speed expansion */
+ label = "LS-SPI0";
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
index fced77f0fd3a..b0a064d3806b 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
@@ -17,6 +17,6 @@
/ {
model = "Qualcomm Technologies, Inc. MSM 8916 MTP";
- compatible = "qcom,msm8916-mtp", "qcom,msm8916-mtp-smb1360",
+ compatible = "qcom,msm8916-mtp", "qcom,msm8916-mtp/1",
"qcom,msm8916", "qcom,mtp";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
index a1aa0b201e92..ceeb8a6feed6 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
@@ -17,6 +17,7 @@
/ {
aliases {
serial0 = &blsp1_uart2;
+ usid0 = &pm8916_0;
};
chosen {
diff --git a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
index 49ec55a37614..955c6f174d4c 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
@@ -16,10 +16,13 @@
blsp1_uart1_default: blsp1_uart1_default {
pinmux {
function = "blsp_uart1";
- pins = "gpio0", "gpio1";
+ // TX, RX, CTS_N, RTS_N
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
};
pinconf {
- pins = "gpio0", "gpio1";
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
drive-strength = <16>;
bias-disable;
};
@@ -28,10 +31,12 @@
blsp1_uart1_sleep: blsp1_uart1_sleep {
pinmux {
function = "gpio";
- pins = "gpio0", "gpio1";
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
};
pinconf {
- pins = "gpio0", "gpio1";
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
drive-strength = <2>;
bias-pull-down;
};
@@ -272,7 +277,7 @@
};
pinconf {
pins = "gpio6", "gpio7";
- drive-strength = <2>;
+ drive-strength = <16>;
bias-disable = <0>;
};
};
@@ -296,7 +301,7 @@
};
pinconf {
pins = "gpio14", "gpio15";
- drive-strength = <2>;
+ drive-strength = <16>;
bias-disable = <0>;
};
};
@@ -320,7 +325,7 @@
};
pinconf {
pins = "gpio22", "gpio23";
- drive-strength = <2>;
+ drive-strength = <16>;
bias-disable = <0>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 8d184ff19642..915321479998 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -37,6 +37,22 @@
reg = <0 0 0 0>;
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ reserve_aligned@86000000 {
+ reg = <0x0 0x86000000 0x0 0x0300000>;
+ no-map;
+ };
+
+ smem_mem: smem_region@86300000 {
+ reg = <0x0 0x86300000 0x0 0x0100000>;
+ no-map;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -74,6 +90,29 @@
<GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
+ clocks {
+ xo_board: xo_board {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ };
+
+ sleep_clk: sleep_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+ };
+
+ smem {
+ compatible = "qcom,smem";
+
+ memory-region = <&smem_mem>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+
+ hwlocks = <&tcsr_mutex 3>;
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -103,21 +142,46 @@
reg = <0x1800000 0x80000>;
};
+ tcsr_mutex_regs: syscon@1905000 {
+ compatible = "syscon";
+ reg = <0x1905000 0x20000>;
+ };
+
+ tcsr_mutex: hwlock {
+ compatible = "qcom,tcsr-mutex";
+ syscon = <&tcsr_mutex_regs 0 0x1000>;
+ #hwlock-cells = <1>;
+ };
+
+ rpm_msg_ram: memory@60000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x60000 0x8000>;
+ };
+
blsp1_uart1: serial@78af000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78af000 0x200>;
interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
+ dmas = <&blsp_dma 1>, <&blsp_dma 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
+ apcs: syscon@b011000 {
+ compatible = "syscon";
+ reg = <0x0b011000 0x1000>;
+ };
+
blsp1_uart2: serial@78b0000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78b0000 0x200>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
+ dmas = <&blsp_dma 3>, <&blsp_dma 2>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -438,6 +502,49 @@
clock-names = "core";
};
};
+
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-msm8916";
+ qcom,smd-channels = "rpm_requests";
+
+ pm8916-regulators {
+ compatible = "qcom,rpm-pm8916-regulators";
+
+ pm8916_s1: s1 {};
+ pm8916_s2: s2 {};
+ pm8916_s3: s3 {};
+ pm8916_s4: s4 {};
+
+ pm8916_l1: l1 {};
+ pm8916_l2: l2 {};
+ pm8916_l3: l3 {};
+ pm8916_l4: l4 {};
+ pm8916_l5: l5 {};
+ pm8916_l6: l6 {};
+ pm8916_l7: l7 {};
+ pm8916_l8: l8 {};
+ pm8916_l9: l9 {};
+ pm8916_l10: l10 {};
+ pm8916_l11: l11 {};
+ pm8916_l12: l12 {};
+ pm8916_l13: l13 {};
+ pm8916_l14: l14 {};
+ pm8916_l15: l15 {};
+ pm8916_l16: l16 {};
+ pm8916_l17: l17 {};
+ pm8916_l18: l18 {};
+ };
+ };
+ };
+ };
};
#include "msm8916-pins.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
index b222ece7e3d2..37432451ee4c 100644
--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -4,8 +4,8 @@
&spmi_bus {
- usid0: pm8916@0 {
- compatible = "qcom,spmi-pmic";
+ pm8916_0: pm8916@0 {
+ compatible = "qcom,pm8916", "qcom,spmi-pmic";
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
@@ -90,7 +90,7 @@
};
};
- usid1: pm8916@1 {
+ pm8916_1: pm8916@1 {
compatible = "qcom,spmi-pmic";
reg = <0x1 SPMI_USID>;
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
new file mode 100644
index 000000000000..9ce1890a650e
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/Makefile
@@ -0,0 +1,4 @@
+dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x.dtb
+
+always := $(dtb-y)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
new file mode 100644
index 000000000000..265d12ff6022
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
@@ -0,0 +1,251 @@
+/*
+ * Device Tree Source for the Salvator-X board
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/*
+ * SSI-AK4613
+ *
+ * This command is required when Playback/Capture
+ *
+ * amixer set "DVC Out" 100%
+ * amixer set "DVC In" 100%
+ *
+ * You can use Mute
+ *
+ * amixer set "DVC Out Mute" on
+ * amixer set "DVC In Mute" on
+ *
+ * You can use Volume Ramp
+ *
+ * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps"
+ * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
+ * amixer set "DVC Out Ramp" on
+ * aplay xxx.wav &
+ * amixer set "DVC Out" 80% // Volume Down
+ * amixer set "DVC Out" 100% // Volume Up
+ */
+
+/dts-v1/;
+#include "r8a7795.dtsi"
+
+/ {
+ model = "Renesas Salvator-X board based on r8a7795";
+ compatible = "renesas,salvator-x", "renesas,r8a7795";
+
+ aliases {
+ serial0 = &scif2;
+ serial1 = &scif1;
+ ethernet0 = &avb;
+ };
+
+ chosen {
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@48000000 {
+ device_type = "memory";
+ /* first 128MB is reserved for secure area. */
+ reg = <0x0 0x48000000 0x0 0x38000000>;
+ };
+
+ x12_clk: x12_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
+
+ audio_clkout: audio_clkout {
+ /*
+ * This is same as <&rcar_sound 0>
+ * but needed to avoid cs2000/rcar_sound probe dead-lock
+ */
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <11289600>;
+ };
+
+ rsnd_ak4613: sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcpu>;
+ simple-audio-card,frame-master = <&sndcpu>;
+
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4613>;
+ };
+ };
+};
+
+&extal_clk {
+ clock-frequency = <16666666>;
+};
+
+&pfc {
+ scif1_pins: scif1 {
+ renesas,groups = "scif1_data_a", "scif1_ctrl";
+ renesas,function = "scif1";
+ };
+ scif2_pins: scif2 {
+ renesas,groups = "scif2_data_a";
+ renesas,function = "scif2";
+ };
+
+ i2c2_pins: i2c2 {
+ renesas,groups = "i2c2_a";
+ renesas,function = "i2c2";
+ };
+
+ avb_pins: avb {
+ renesas,groups = "avb_mdc";
+ renesas,function = "avb";
+ };
+
+ sound_pins: sound {
+ renesas,groups = "ssi01239_ctrl", "ssi0_data", "ssi1_data_a";
+ renesas,function = "ssi";
+ };
+
+ sound_clk_pins: sound_clk {
+ renesas,groups = "audio_clk_a_a", "audio_clk_b_a", "audio_clk_c_a",
+ "audio_clkout_a", "audio_clkout3_a";
+ renesas,function = "audio_clk";
+ };
+};
+
+&scif1 {
+ pinctrl-0 = <&scif1_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&scif2 {
+ pinctrl-0 = <&scif2_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ clock-frequency = <100000>;
+
+ ak4613: codec@10 {
+ compatible = "asahi-kasei,ak4613";
+ #sound-dai-cells = <0>;
+ reg = <0x10>;
+ clocks = <&rcar_sound 3>;
+
+ asahi-kasei,in1-single-end;
+ asahi-kasei,in2-single-end;
+ asahi-kasei,out1-single-end;
+ asahi-kasei,out2-single-end;
+ asahi-kasei,out3-single-end;
+ asahi-kasei,out4-single-end;
+ asahi-kasei,out5-single-end;
+ asahi-kasei,out6-single-end;
+ };
+
+ cs2000: clk_multiplier@4f {
+ #clock-cells = <0>;
+ compatible = "cirrus,cs2000-cp";
+ reg = <0x4f>;
+ clocks = <&audio_clkout>, <&x12_clk>;
+ clock-names = "clk_in", "ref_clk";
+
+ assigned-clocks = <&cs2000>;
+ assigned-clock-rates = <24576000>; /* 1/1 divide */
+ };
+};
+
+&rcar_sound {
+ pinctrl-0 = <&sound_pins &sound_clk_pins>;
+ pinctrl-names = "default";
+
+ /* Single DAI */
+ #sound-dai-cells = <0>;
+
+ /* audio_clkout0/1/2/3 */
+ #clock-cells = <1>;
+ clock-frequency = <11289600>;
+
+ status = "okay";
+
+ /* update <audio_clk_b> to <cs2000> */
+ clocks = <&cpg CPG_MOD 1005>,
+ <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+ <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+ <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+ <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+ <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+ <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+ <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+ <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+ <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+ <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+ <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+ <&audio_clk_a>, <&cs2000>,
+ <&audio_clk_c>,
+ <&cpg CPG_CORE R8A7795_CLK_S0D4>;
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0 &src0 &dvc0>;
+ capture = <&ssi1 &src1 &dvc1>;
+ };
+ };
+};
+
+&sata {
+ status = "okay";
+};
+
+&ssi1 {
+ shared-pin;
+};
+
+&audio_clk_a {
+ clock-frequency = <22579200>;
+};
+
+&avb {
+ pinctrl-0 = <&avb_pins>;
+ pinctrl-names = "default";
+ renesas,no-ether-link;
+ phy-handle = <&phy0>;
+ status = "okay";
+
+ phy0: ethernet-phy@0 {
+ rxc-skew-ps = <900>;
+ rxdv-skew-ps = <0>;
+ rxd0-skew-ps = <0>;
+ rxd1-skew-ps = <0>;
+ rxd2-skew-ps = <0>;
+ rxd3-skew-ps = <0>;
+ txc-skew-ps = <900>;
+ txen-skew-ps = <0>;
+ txd0-skew-ps = <0>;
+ txd1-skew-ps = <0>;
+ txd2-skew-ps = <0>;
+ txd3-skew-ps = <0>;
+ reg = <0>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
new file mode 100644
index 000000000000..bb353cde1253
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -0,0 +1,779 @@
+/*
+ * Device Tree Source for the r8a7795 SoC
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "renesas,r8a7795";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ a57_0: cpu@0 {
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ a57_1: cpu@1 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x1>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+ a57_2: cpu@2 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x2>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+ a57_3: cpu@3 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x3>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+ };
+
+ extal_clk: extal {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ /* This value must be overridden by the board */
+ clock-frequency = <0>;
+ };
+
+ extalr_clk: extalr {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ /* This value must be overridden by the board */
+ clock-frequency = <0>;
+ };
+
+ /*
+ * The external audio clocks are configured as 0 Hz fixed frequency
+ * clocks by default.
+ * Boards that provide audio clocks should override them.
+ */
+ audio_clk_a: audio_clk_a {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ };
+
+ audio_clk_b: audio_clk_b {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ };
+
+ audio_clk_c: audio_clk_c {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ interrupt-parent = <&gic>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ gic: interrupt-controller@0xf1010000 {
+ compatible = "arm,gic-400";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x0 0xf1010000 0 0x1000>,
+ <0x0 0xf1020000 0 0x2000>;
+ interrupts = <GIC_PPI 9
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ gpio0: gpio@e6050000 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6050000 0 0x50>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 0 16>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 912>;
+ power-domains = <&cpg>;
+ };
+
+ gpio1: gpio@e6051000 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6051000 0 0x50>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 32 28>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 911>;
+ power-domains = <&cpg>;
+ };
+
+ gpio2: gpio@e6052000 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6052000 0 0x50>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 64 15>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 910>;
+ power-domains = <&cpg>;
+ };
+
+ gpio3: gpio@e6053000 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6053000 0 0x50>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 96 16>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 909>;
+ power-domains = <&cpg>;
+ };
+
+ gpio4: gpio@e6054000 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6054000 0 0x50>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 128 18>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 908>;
+ power-domains = <&cpg>;
+ };
+
+ gpio5: gpio@e6055000 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055000 0 0x50>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 160 26>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 907>;
+ power-domains = <&cpg>;
+ };
+
+ gpio6: gpio@e6055400 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055400 0 0x50>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 192 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 906>;
+ power-domains = <&cpg>;
+ };
+
+ gpio7: gpio@e6055800 {
+ compatible = "renesas,gpio-r8a7795",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055800 0 0x50>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 224 4>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 905>;
+ power-domains = <&cpg>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&a57_0>,
+ <&a57_1>,
+ <&a57_2>,
+ <&a57_3>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ cpg: clock-controller@e6150000 {
+ compatible = "renesas,r8a7795-cpg-mssr";
+ reg = <0 0xe6150000 0 0x1000>;
+ clocks = <&extal_clk>, <&extalr_clk>;
+ clock-names = "extal", "extalr";
+ #clock-cells = <2>;
+ #power-domain-cells = <0>;
+ };
+
+ audma0: dma-controller@ec700000 {
+ compatible = "renesas,rcar-dmac";
+ reg = <0 0xec700000 0 0x10000>;
+ interrupts = <0 350 IRQ_TYPE_LEVEL_HIGH
+ 0 320 IRQ_TYPE_LEVEL_HIGH
+ 0 321 IRQ_TYPE_LEVEL_HIGH
+ 0 322 IRQ_TYPE_LEVEL_HIGH
+ 0 323 IRQ_TYPE_LEVEL_HIGH
+ 0 324 IRQ_TYPE_LEVEL_HIGH
+ 0 325 IRQ_TYPE_LEVEL_HIGH
+ 0 326 IRQ_TYPE_LEVEL_HIGH
+ 0 327 IRQ_TYPE_LEVEL_HIGH
+ 0 328 IRQ_TYPE_LEVEL_HIGH
+ 0 329 IRQ_TYPE_LEVEL_HIGH
+ 0 330 IRQ_TYPE_LEVEL_HIGH
+ 0 331 IRQ_TYPE_LEVEL_HIGH
+ 0 332 IRQ_TYPE_LEVEL_HIGH
+ 0 333 IRQ_TYPE_LEVEL_HIGH
+ 0 334 IRQ_TYPE_LEVEL_HIGH
+ 0 335 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15";
+ clocks = <&cpg CPG_MOD 502>;
+ clock-names = "fck";
+ power-domains = <&cpg>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ };
+
+ audma1: dma-controller@ec720000 {
+ compatible = "renesas,rcar-dmac";
+ reg = <0 0xec720000 0 0x10000>;
+ interrupts = <0 351 IRQ_TYPE_LEVEL_HIGH
+ 0 336 IRQ_TYPE_LEVEL_HIGH
+ 0 337 IRQ_TYPE_LEVEL_HIGH
+ 0 338 IRQ_TYPE_LEVEL_HIGH
+ 0 339 IRQ_TYPE_LEVEL_HIGH
+ 0 340 IRQ_TYPE_LEVEL_HIGH
+ 0 341 IRQ_TYPE_LEVEL_HIGH
+ 0 342 IRQ_TYPE_LEVEL_HIGH
+ 0 343 IRQ_TYPE_LEVEL_HIGH
+ 0 344 IRQ_TYPE_LEVEL_HIGH
+ 0 345 IRQ_TYPE_LEVEL_HIGH
+ 0 346 IRQ_TYPE_LEVEL_HIGH
+ 0 347 IRQ_TYPE_LEVEL_HIGH
+ 0 348 IRQ_TYPE_LEVEL_HIGH
+ 0 349 IRQ_TYPE_LEVEL_HIGH
+ 0 382 IRQ_TYPE_LEVEL_HIGH
+ 0 383 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15";
+ clocks = <&cpg CPG_MOD 501>;
+ clock-names = "fck";
+ power-domains = <&cpg>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ };
+
+ pfc: pfc@e6060000 {
+ compatible = "renesas,pfc-r8a7795";
+ reg = <0 0xe6060000 0 0x50c>;
+ };
+
+ dmac0: dma-controller@e6700000 {
+ /* Empty node for now */
+ };
+
+ dmac1: dma-controller@e7300000 {
+ /* Empty node for now */
+ };
+
+ dmac2: dma-controller@e7310000 {
+ /* Empty node for now */
+ };
+
+ avb: ethernet@e6800000 {
+ compatible = "renesas,etheravb-r8a7795";
+ reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15",
+ "ch16", "ch17", "ch18", "ch19",
+ "ch20", "ch21", "ch22", "ch23",
+ "ch24";
+ clocks = <&cpg CPG_MOD 812>;
+ power-domains = <&cpg>;
+ phy-mode = "rgmii-id";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ hscif0: serial@e6540000 {
+ compatible = "renesas,hscif-r8a7795", "renesas,hscif";
+ reg = <0 0xe6540000 0 96>;
+ interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 520>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x31>, <&dmac1 0x30>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ hscif1: serial@e6550000 {
+ compatible = "renesas,hscif-r8a7795", "renesas,hscif";
+ reg = <0 0xe6550000 0 96>;
+ interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 519>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x33>, <&dmac1 0x32>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ hscif2: serial@e6560000 {
+ compatible = "renesas,hscif-r8a7795", "renesas,hscif";
+ reg = <0 0xe6560000 0 96>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 518>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x35>, <&dmac1 0x34>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ hscif3: serial@e66a0000 {
+ compatible = "renesas,hscif-r8a7795", "renesas,hscif";
+ reg = <0 0xe66a0000 0 96>;
+ interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 517>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x37>, <&dmac0 0x36>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ hscif4: serial@e66b0000 {
+ compatible = "renesas,hscif-r8a7795", "renesas,hscif";
+ reg = <0 0xe66b0000 0 96>;
+ interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 516>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x39>, <&dmac0 0x38>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ scif0: serial@e6e60000 {
+ compatible = "renesas,scif-r8a7795", "renesas,scif";
+ reg = <0 0xe6e60000 0 64>;
+ interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 207>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x51>, <&dmac1 0x50>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ scif1: serial@e6e68000 {
+ compatible = "renesas,scif-r8a7795", "renesas,scif";
+ reg = <0 0xe6e68000 0 64>;
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 206>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x53>, <&dmac1 0x52>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ scif2: serial@e6e88000 {
+ compatible = "renesas,scif-r8a7795", "renesas,scif";
+ reg = <0 0xe6e88000 0 64>;
+ interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 310>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x13>, <&dmac1 0x12>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ scif3: serial@e6c50000 {
+ compatible = "renesas,scif-r8a7795", "renesas,scif";
+ reg = <0 0xe6c50000 0 64>;
+ interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 204>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x57>, <&dmac0 0x56>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ scif4: serial@e6c40000 {
+ compatible = "renesas,scif-r8a7795", "renesas,scif";
+ reg = <0 0xe6c40000 0 64>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 203>;
+ clock-names = "sci_ick";
+ dmas = <&dmac0 0x59>, <&dmac0 0x58>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ scif5: serial@e6f30000 {
+ compatible = "renesas,scif-r8a7795", "renesas,scif";
+ reg = <0 0xe6f30000 0 64>;
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 202>;
+ clock-names = "sci_ick";
+ dmas = <&dmac1 0x5b>, <&dmac1 0x5a>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@e6500000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe6500000 0 0x40>;
+ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 931>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <110>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@e6508000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe6508000 0 0x40>;
+ interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 930>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <6>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@e6510000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe6510000 0 0x40>;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 929>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <6>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@e66d0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe66d0000 0 0x40>;
+ interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 928>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <110>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@e66d8000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe66d8000 0 0x40>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 927>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <110>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@e66e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe66e0000 0 0x40>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 919>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <110>;
+ status = "disabled";
+ };
+
+ i2c6: i2c@e66e8000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,i2c-r8a7795";
+ reg = <0 0xe66e8000 0 0x40>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 918>;
+ power-domains = <&cpg>;
+ i2c-scl-internal-delay-ns = <6>;
+ status = "disabled";
+ };
+
+ rcar_sound: sound@ec500000 {
+ /*
+ * #sound-dai-cells is required
+ *
+ * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
+ * Multi DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
+ */
+ /*
+ * #clock-cells is required for audio_clkout0/1/2/3
+ *
+ * clkout : #clock-cells = <0>; <&rcar_sound>;
+ * clkout0/1/2/3: #clock-cells = <1>; <&rcar_sound N>;
+ */
+ compatible = "renesas,rcar_sound-r8a7795", "renesas,rcar_sound-gen3";
+ reg = <0 0xec500000 0 0x1000>, /* SCU */
+ <0 0xec5a0000 0 0x100>, /* ADG */
+ <0 0xec540000 0 0x1000>, /* SSIU */
+ <0 0xec541000 0 0x280>, /* SSI */
+ <0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/
+ reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+ clocks = <&cpg CPG_MOD 1005>,
+ <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+ <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+ <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+ <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+ <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+ <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+ <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+ <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+ <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+ <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+ <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+ <&audio_clk_a>, <&audio_clk_b>,
+ <&audio_clk_c>,
+ <&cpg CPG_CORE R8A7795_CLK_S0D4>;
+ clock-names = "ssi-all",
+ "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+ "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+ "ssi.1", "ssi.0",
+ "src.9", "src.8", "src.7", "src.6",
+ "src.5", "src.4", "src.3", "src.2",
+ "src.1", "src.0",
+ "dvc.0", "dvc.1",
+ "clk_a", "clk_b", "clk_c", "clk_i";
+ power-domains = <&cpg>;
+ status = "disabled";
+
+ rcar_sound,dvc {
+ dvc0: dvc@0 {
+ dmas = <&audma0 0xbc>;
+ dma-names = "tx";
+ };
+ dvc1: dvc@1 {
+ dmas = <&audma0 0xbe>;
+ dma-names = "tx";
+ };
+ };
+
+ rcar_sound,src {
+ src0: src@0 {
+ interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x85>, <&audma1 0x9a>;
+ dma-names = "rx", "tx";
+ };
+ src1: src@1 {
+ interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x87>, <&audma1 0x9c>;
+ dma-names = "rx", "tx";
+ };
+ src2: src@2 {
+ interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x89>, <&audma1 0x9e>;
+ dma-names = "rx", "tx";
+ };
+ src3: src@3 {
+ interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+ dma-names = "rx", "tx";
+ };
+ src4: src@4 {
+ interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+ dma-names = "rx", "tx";
+ };
+ src5: src@5 {
+ interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+ dma-names = "rx", "tx";
+ };
+ src6: src@6 {
+ interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x91>, <&audma1 0xb4>;
+ dma-names = "rx", "tx";
+ };
+ src7: src@7 {
+ interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x93>, <&audma1 0xb6>;
+ dma-names = "rx", "tx";
+ };
+ src8: src@8 {
+ interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x95>, <&audma1 0xb8>;
+ dma-names = "rx", "tx";
+ };
+ src9: src@9 {
+ interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x97>, <&audma1 0xba>;
+ 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";
+ };
+ 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";
+ };
+ 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";
+ };
+ 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";
+ };
+ };
+ };
+
+ sata: sata@ee300000 {
+ compatible = "renesas,sata-r8a7795";
+ reg = <0 0xee300000 0 0x1fff>;
+ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 815>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 601e6a236c1d..e3f0b5f4ba4e 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -1,3 +1,4 @@
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-evb-act8846.dts b/arch/arm64/boot/dts/rockchip/rk3368-evb-act8846.dts
new file mode 100644
index 000000000000..8a5275f0539b
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-evb-act8846.dts
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015 Caesar Wang <wxt@rock-chips.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3368-evb.dtsi"
+
+/ {
+ model = "Rockchip RK3368 EVB with ACT8846 pmic";
+ compatible = "rockchip,rk3368-evb-act8846", "rockchip,rk3368";
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+
+ vdd_cpu: syr827@40 {
+ compatible = "silergy,syr827";
+ reg = <0x40>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-name = "vdd_cpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vdd_gpu: syr828@41 {
+ compatible = "silergy,syr828";
+ reg = <0x41>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-name = "vdd_gpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ act8846: act8846@5a {
+ compatible = "active-semi,act8846";
+ reg = <0x5a>;
+ status = "okay";
+
+ vp1-supply = <&vcc_sys>;
+ vp2-supply = <&vcc_sys>;
+ vp3-supply = <&vcc_sys>;
+ vp4-supply = <&vcc_sys>;
+ inl1-supply = <&vcc_io>;
+ inl2-supply = <&vcc_sys>;
+ inl3-supply = <&vcc_20>;
+
+ regulators {
+ vcc_ddr: REG1 {
+ regulator-name = "VCC_DDR";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vcc_io: REG2 {
+ regulator-name = "VCC_IO";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_log: REG3 {
+ regulator-name = "VDD_LOG";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ };
+
+ vcc_20: REG4 {
+ regulator-name = "VCC_20";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ vccio_sd: REG5 {
+ regulator-name = "VCCIO_SD";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd10_lcd: REG6 {
+ regulator-name = "VDD10_LCD";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcca_codec: REG7 {
+ regulator-name = "VCCA_CODEC";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vcca_tp: REG8 {
+ regulator-name = "VCCA_TP";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vccio_pmu: REG9 {
+ regulator-name = "VCCIO_PMU";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_10: REG10 {
+ regulator-name = "VDD_10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcc_18: REG11 {
+ regulator-name = "VCC_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vcc18_lcd: REG12 {
+ regulator-name = "VCC18_LCD";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
new file mode 100644
index 000000000000..8c219ccf67a3
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2015 Caesar Wang <wxt@rock-chips.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3368.dtsi"
+
+/ {
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x40000000>;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <
+ 0 1 2 3 4 5 6 7
+ 8 9 10 11 12 13 14 15
+ 16 17 18 19 20 21 22 23
+ 24 25 26 27 28 29 30 31
+ 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47
+ 48 49 50 51 52 53 54 55
+ 56 57 58 59 60 61 62 63
+ 64 65 66 67 68 69 70 71
+ 72 73 74 75 76 77 78 79
+ 80 81 82 83 84 85 86 87
+ 88 89 90 91 92 93 94 95
+ 96 97 98 99 100 101 102 103
+ 104 105 106 107 108 109 110 111
+ 112 113 114 115 116 117 118 119
+ 120 121 122 123 124 125 126 127
+ 128 129 130 131 132 133 134 135
+ 136 137 138 139 140 141 142 143
+ 144 145 146 147 148 149 150 151
+ 152 153 154 155 156 157 158 159
+ 160 161 162 163 164 165 166 167
+ 168 169 170 171 172 173 174 175
+ 176 177 178 179 180 181 182 183
+ 184 185 186 187 188 189 190 191
+ 192 193 194 195 196 197 198 199
+ 200 201 202 203 204 205 206 207
+ 208 209 210 211 212 213 214 215
+ 216 217 218 219 220 221 222 223
+ 224 225 226 227 228 229 230 231
+ 232 233 234 235 236 237 238 239
+ 240 241 242 243 244 245 246 247
+ 248 249 250 251 252 253 254 255>;
+ default-brightness-level = <128>;
+ enable-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_en>;
+ pwms = <&pwm0 0 1000000 PWM_POLARITY_INVERTED>;
+ pwm-delay-us = <10000>;
+ };
+
+ emmc_pwrseq: emmc-pwrseq {
+ compatible = "mmc-pwrseq-emmc";
+ pinctrl-0 = <&emmc_reset>;
+ pinctrl-names = "default";
+ reset-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+ };
+
+ keys: gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_key>;
+
+ button@0 {
+ gpio-key,wakeup = <1>;
+ gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+ label = "GPIO Power";
+ linux,code = <116>;
+ };
+ };
+
+ /* supplies both host and otg */
+ vcc_host: vcc-host-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&host_vbus_drv>;
+ regulator-name = "vcc_host";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vcc_lan: vcc-lan-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_lan";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_sys: vcc-sys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&emmc {
+ broken-cd;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ mmc-pwrseq = <&emmc_pwrseq>;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+ status = "okay";
+};
+
+&gmac {
+ phy-supply = <&vcc_lan>;
+ phy-mode = "rmii";
+ clock_in_out = "output";
+ snps,reset-gpio = <&gpio3 12 0>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 1000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rmii_pins>;
+ tx_delay = <0x30>;
+ rx_delay = <0x10>;
+ status = "ok";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&pinctrl {
+ pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
+ bias-disable;
+ drive-strength = <8>;
+ };
+
+ pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma {
+ bias-pull-up;
+ drive-strength = <8>;
+ };
+
+ backlight {
+ bl_en: bl-en {
+ rockchip,pins = <0 20 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ emmc {
+ emmc_bus8: emmc-bus8 {
+ rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 19 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 20 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 21 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 22 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 23 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 24 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 25 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+ };
+
+ emmc-clk {
+ rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+ };
+
+ emmc-cmd {
+ rockchip,pins = <1 26 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+ };
+
+ emmc_reset: emmc-reset {
+ rockchip,pins = <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ keys {
+ pwr_key: pwr-key {
+ rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ pmic {
+ pmic_int: pmic-int {
+ rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ sdio {
+ wifi_reg_on: wifi-reg-on {
+ rockchip,pins = <3 4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_rst: bt-rst {
+ rockchip,pins = <3 5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb {
+ host_vbus_drv: host-vbus-drv {
+ rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&tsadc {
+ rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
index 401a81231eb9..104cbee762bb 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
@@ -336,6 +336,12 @@
status = "okay";
};
+&tsadc {
+ rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */
+ status = "okay";
+};
+
&uart2 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-thermal.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-thermal.dtsi
new file mode 100644
index 000000000000..a10010f92f96
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-thermal.dtsi
@@ -0,0 +1,112 @@
+/*
+ * Device Tree Source for RK3368 SoC thermal
+ *
+ * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
+ * Caesar Wang <wxt@rock-chips.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+cpu_thermal: cpu_thermal {
+ polling-delay-passive = <100>; /* milliseconds */
+ polling-delay = <5000>; /* milliseconds */
+
+ thermal-sensors = <&tsadc 0>;
+
+ trips {
+ cpu_alert0: cpu_alert0 {
+ temperature = <75000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_alert1: cpu_alert1 {
+ temperature = <80000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_crit: cpu_crit {
+ temperature = <95000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device =
+ <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ map1 {
+ trip = <&cpu_alert1>;
+ cooling-device =
+ <&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+};
+
+gpu_thermal: gpu_thermal {
+ polling-delay-passive = <100>; /* milliseconds */
+ polling-delay = <5000>; /* milliseconds */
+
+ thermal-sensors = <&tsadc 1>;
+
+ trips {
+ gpu_alert0: gpu_alert0 {
+ temperature = <80000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ gpu_crit: gpu_crit {
+ temperature = <1150000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&gpu_alert0>;
+ cooling-device =
+ <&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index cc093a482aa4..122777b1441e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -45,6 +45,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
compatible = "rockchip,rk3368";
@@ -53,6 +54,7 @@
#size-cells = <2>;
aliases {
+ ethernet0 = &gmac;
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
@@ -123,6 +125,8 @@
reg = <0x0 0x0>;
cpu-idle-states = <&cpu_sleep>;
enable-method = "psci";
+
+ #cooling-cells = <2>; /* min followed by max */
};
cpu_l1: cpu@1 {
@@ -155,6 +159,8 @@
reg = <0x0 0x100>;
cpu-idle-states = <&cpu_sleep>;
enable-method = "psci";
+
+ #cooling-cells = <2>; /* min followed by max */
};
cpu_b1: cpu@101 {
@@ -404,6 +410,27 @@
status = "disabled";
};
+ thermal-zones {
+ #include "rk3368-thermal.dtsi"
+ };
+
+ tsadc: tsadc@ff280000 {
+ compatible = "rockchip,rk3368-tsadc";
+ reg = <0x0 0xff280000 0x0 0x100>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+ clock-names = "tsadc", "apb_pclk";
+ resets = <&cru SRST_TSADC>;
+ reset-names = "tsadc-apb";
+ pinctrl-names = "init", "default", "sleep";
+ pinctrl-0 = <&otp_gpio>;
+ pinctrl-1 = <&otp_out>;
+ pinctrl-2 = <&otp_gpio>;
+ #thermal-sensor-cells = <1>;
+ rockchip,hw-tshut-temp = <95000>;
+ status = "disabled";
+ };
+
gmac: ethernet@ff290000 {
compatible = "rockchip,rk3368-gmac";
reg = <0x0 0xff290000 0x0 0x10000>;
@@ -471,6 +498,48 @@
status = "disabled";
};
+ pwm0: pwm@ff680000 {
+ compatible = "rockchip,rk3368-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff680000 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pin>;
+ clocks = <&cru PCLK_PWM1>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pwm1: pwm@ff680010 {
+ compatible = "rockchip,rk3368-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff680010 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm1_pin>;
+ clocks = <&cru PCLK_PWM1>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pwm2: pwm@ff680020 {
+ compatible = "rockchip,rk3368-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff680020 0x0 0x10>;
+ #pwm-cells = <3>;
+ clocks = <&cru PCLK_PWM1>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pwm3: pwm@ff680030 {
+ compatible = "rockchip,rk3368-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff680030 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm3_pin>;
+ clocks = <&cru PCLK_PWM1>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
uart2: serial@ff690000 {
compatible = "rockchip,rk3368-uart", "snps,dw-apb-uart";
reg = <0x0 0xff690000 0x0 0x100>;
@@ -510,6 +579,12 @@
status = "disabled";
};
+ timer@ff810000 {
+ compatible = "rockchip,rk3368-timer", "rockchip,rk3288-timer";
+ reg = <0x0 0xff810000 0x0 0x20>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
gic: interrupt-controller@ffb71000 {
compatible = "arm,gic-400";
interrupt-controller;
@@ -712,6 +787,24 @@
};
};
+ pwm0 {
+ pwm0_pin: pwm0-pin {
+ rockchip,pins = <3 8 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm1 {
+ pwm1_pin: pwm1-pin {
+ rockchip,pins = <0 8 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm3 {
+ pwm3_pin: pwm3-pin {
+ rockchip,pins = <3 29 RK_FUNC_3 &pcfg_pull_none>;
+ };
+ };
+
sdio0 {
sdio0_bus1: sdio0-bus1 {
rockchip,pins = <2 28 RK_FUNC_1 &pcfg_pull_up>;
@@ -762,7 +855,7 @@
rockchip,pins = <2 10 RK_FUNC_1 &pcfg_pull_up>;
};
- sdmmc_cd: sdmcc-cd {
+ sdmmc_cd: sdmmc-cd {
rockchip,pins = <2 11 RK_FUNC_1 &pcfg_pull_up>;
};
@@ -829,6 +922,16 @@
};
};
+ tsadc {
+ otp_gpio: otp-gpio {
+ rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ otp_out: otp-out {
+ rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
uart0 {
uart0_xfer: uart0-xfer {
rockchip,pins = <2 24 RK_FUNC_1 &pcfg_pull_up>,
diff --git a/arch/arm64/boot/dts/socionext/Makefile b/arch/arm64/boot/dts/socionext/Makefile
new file mode 100644
index 000000000000..8d727717c24e
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/Makefile
@@ -0,0 +1,4 @@
+dtb-$(CONFIG_ARCH_UNIPHIER) += uniphier-ph1-ld10-ref.dtb
+
+always := $(dtb-y)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts
new file mode 100644
index 000000000000..3e533178ba2f
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10-ref.dts
@@ -0,0 +1,95 @@
+/*
+ * Device Tree Source for UniPhier PH1-LD10 Reference Board
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "uniphier-ph1-ld10.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier PH1-LD10 Reference Board";
+ compatible = "socionext,ph1-ld10-ref", "socionext,ph1-ld10";
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x80000000 0 0xc0000000>;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ serial3 = &serial3;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
+ };
+};
+
+&extbus {
+ ranges = <1 0x00000000 0x42000000 0x02000000>;
+};
+
+&support_card {
+ ranges = <0x00000000 1 0x01f00000 0x00100000>;
+};
+
+&ethsc {
+ interrupts = <0 48 4>;
+};
+
+&serial0 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi
new file mode 100644
index 000000000000..0296af9cbbdb
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/uniphier-ph1-ld10.dtsi
@@ -0,0 +1,280 @@
+/*
+ * Device Tree Source for UniPhier PH1-LD10 SoC
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 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.
+ *
+ * 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 hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/ {
+ compatible = "socionext,ph1-ld10";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu2>;
+ };
+ core1 {
+ cpu = <&cpu3>;
+ };
+ };
+ };
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0 0x000>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0x80000100>;
+ };
+
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0 0x001>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0x80000100>;
+ };
+
+ cpu2: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0 0x100>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0x80000100>;
+ };
+
+ cpu3: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0 0x101>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0x80000100>;
+ };
+ };
+
+ clocks {
+ uart_clk: uart_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <58820000>;
+ };
+
+ i2c_clk: i2c_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <50000000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xf01>,
+ <1 14 0xf01>,
+ <1 11 0xf01>,
+ <1 10 0xf01>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+
+ extbus: extbus {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ };
+
+ serial0: serial@54006800 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006800 0x40>;
+ interrupts = <0 33 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ clocks = <&uart_clk>;
+ };
+
+ serial1: serial@54006900 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006900 0x40>;
+ interrupts = <0 35 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ clocks = <&uart_clk>;
+ };
+
+ serial2: serial@54006a00 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006a00 0x40>;
+ interrupts = <0 37 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ clocks = <&uart_clk>;
+ };
+
+ serial3: serial@54006b00 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006b00 0x40>;
+ interrupts = <0 177 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ clocks = <&uart_clk>;
+ };
+
+ i2c0: i2c@58780000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58780000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
+
+ i2c1: i2c@58781000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58781000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
+
+ i2c2: i2c@58782000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58782000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 43 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
+
+ i2c3: i2c@58783000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58783000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
+
+ i2c4: i2c@58784000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58784000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 45 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
+
+ i2c5: i2c@58785000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58785000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 25 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
+
+ i2c6: i2c@58786000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58786000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 26 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <400000>;
+ };
+
+ pinctrl: pinctrl@5f801000 {
+ compatible = "socionext,ph1-ld10-pinctrl", "syscon";
+ reg = <0x5f801000 0xe00>;
+ };
+
+ gic: interrupt-controller@5fe00000 {
+ compatible = "arm,gic-v3";
+ reg = <0x5fe00000 0x10000>, /* GICD */
+ <0x5fe80000 0x80000>; /* GICR */
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupts = <1 9 4>;
+ };
+ };
+};
+
+/include/ "uniphier-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi b/arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi
new file mode 120000
index 000000000000..f42fb6f38bd3
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi
@@ -0,0 +1 @@
+../../../../arm/boot/dts/uniphier-pinctrl.dtsi \ No newline at end of file
diff --git a/arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi b/arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi
new file mode 120000
index 000000000000..1246db9be2a1
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi
@@ -0,0 +1 @@
+../../../../arm/boot/dts/uniphier-support-card.dtsi \ No newline at end of file
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
index 857eda5c7217..200fb588d0f5 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
@@ -133,6 +133,8 @@
clocks = <&misc_clk>;
interrupt-parent = <&gic>;
interrupts = <0 16 4>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
reg = <0x0 0xff0a0000 0x1000>;
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index bdd7aa358d2a..18ca9fb9e65f 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -39,12 +39,16 @@ CONFIG_ARCH_HISI=y
CONFIG_ARCH_MEDIATEK=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ARCH_SEATTLE=y
+CONFIG_ARCH_RENESAS=y
+CONFIG_ARCH_R8A7795=y
CONFIG_ARCH_STRATIX10=y
CONFIG_ARCH_TEGRA=y
CONFIG_ARCH_TEGRA_132_SOC=y
+CONFIG_ARCH_TEGRA_210_SOC=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_SPRD=y
CONFIG_ARCH_THUNDER=y
+CONFIG_ARCH_UNIPHIER=y
CONFIG_ARCH_VEXPRESS=y
CONFIG_ARCH_XGENE=y
CONFIG_ARCH_ZYNQMP=y
@@ -76,7 +80,6 @@ CONFIG_BPF_JIT=y
# CONFIG_WIRELESS is not set
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
-# CONFIG_TEGRA_AHB is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -91,6 +94,7 @@ CONFIG_SATA_AHCI=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_CEVA=y
CONFIG_AHCI_XGENE=y
+CONFIG_SATA_RCAR=y
CONFIG_PATA_PLATFORM=y
CONFIG_PATA_OF_PLATFORM=y
CONFIG_NETDEVICES=y
@@ -98,8 +102,10 @@ CONFIG_TUN=y
CONFIG_VIRTIO_NET=y
CONFIG_NET_XGENE=y
CONFIG_SKY2=y
+CONFIG_RAVB=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
+CONFIG_MICREL_PHY=y
# CONFIG_WLAN is not set
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
@@ -110,12 +116,17 @@ CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_8250_MT6577=y
+CONFIG_SERIAL_8250_UNIPHIER=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_SAMSUNG=y
CONFIG_SERIAL_SAMSUNG_UARTS_4=y
CONFIG_SERIAL_SAMSUNG_UARTS=4
CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=11
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
@@ -125,11 +136,13 @@ CONFIG_VIRTIO_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_QUP=y
+CONFIG_I2C_RCAR=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
CONFIG_SPI_QUP=y
CONFIG_PINCTRL_MSM8916=y
CONFIG_GPIO_PL061=y
+CONFIG_GPIO_RCAR=y
CONFIG_GPIO_XGENE=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
@@ -143,6 +156,11 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_RCAR=y
+CONFIG_SND_SOC_AK4613=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
@@ -155,6 +173,7 @@ CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
CONFIG_MMC_SPI=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
@@ -170,10 +189,13 @@ CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_EFI=y
CONFIG_RTC_DRV_XGENE=y
CONFIG_DMADEVICES=y
+CONFIG_RCAR_DMAC=y
CONFIG_QCOM_BAM_DMA=y
+CONFIG_TEGRA20_APB_DMA=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_MMIO=y
+CONFIG_COMMON_CLK_CS2000_CP=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_MSM_GCC_8916=y
CONFIG_HWSPINLOCK_QCOM=y
@@ -197,7 +219,7 @@ CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_HUGETLBFS=y
CONFIG_EFIVAR_FS=y
-# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_SQUASHFS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
@@ -206,6 +228,7 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
+CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 9622eb48f894..dae5c49618db 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -35,11 +35,11 @@
#define dma_rmb() dmb(oshld)
#define dma_wmb() dmb(oshst)
-#define smp_mb() dmb(ish)
-#define smp_rmb() dmb(ishld)
-#define smp_wmb() dmb(ishst)
+#define __smp_mb() dmb(ish)
+#define __smp_rmb() dmb(ishld)
+#define __smp_wmb() dmb(ishst)
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
switch (sizeof(*p)) { \
@@ -62,7 +62,7 @@ do { \
} \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
union { typeof(*p) __val; char __c[1]; } __u; \
compiletime_assert_atomic_type(*p); \
@@ -91,14 +91,7 @@ do { \
__u.__val; \
})
-#define read_barrier_depends() do { } while(0)
-#define smp_read_barrier_depends() do { } while(0)
-
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
-#define nop() asm volatile("nop");
-
-#define smp_mb__before_atomic() smp_mb()
-#define smp_mb__after_atomic() smp_mb()
+#include <asm-generic/barrier.h>
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 0bf8b4320a91..736433912a1e 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -230,7 +230,8 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
}
-static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
+ kvm_pfn_t pfn,
unsigned long size,
bool ipa_uncached)
{
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 69d2e2f86bce..2d545d7aa80b 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -353,21 +353,14 @@ static inline pgprot_t mk_sect_prot(pgprot_t prot)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
-#define pmd_trans_splitting(pmd) pte_special(pmd_pte(pmd))
-#ifdef CONFIG_HAVE_RCU_TABLE_FREE
-#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-struct vm_area_struct;
-void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp);
-#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
-#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index c08b9ad6f429..7371455160e5 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -2,7 +2,7 @@
* Copyright (C) 2013 Huawei Ltd.
* Author: Jiang Liu <liuj97@gmail.com>
*
- * Copyright (C) 2014 Zi Shen Lim <zlim.lnx@gmail.com>
+ * Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@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
@@ -363,6 +363,9 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
u32 immlo, immhi, mask;
int shift;
+ if (insn == AARCH64_BREAK_FAULT)
+ return AARCH64_BREAK_FAULT;
+
switch (type) {
case AARCH64_INSN_IMM_ADR:
shift = 0;
@@ -377,7 +380,7 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n",
type);
- return 0;
+ return AARCH64_BREAK_FAULT;
}
}
@@ -394,9 +397,12 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
{
int shift;
+ if (insn == AARCH64_BREAK_FAULT)
+ return AARCH64_BREAK_FAULT;
+
if (reg < AARCH64_INSN_REG_0 || reg > AARCH64_INSN_REG_SP) {
pr_err("%s: unknown register encoding %d\n", __func__, reg);
- return 0;
+ return AARCH64_BREAK_FAULT;
}
switch (type) {
@@ -417,7 +423,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
default:
pr_err("%s: unknown register type encoding %d\n", __func__,
type);
- return 0;
+ return AARCH64_BREAK_FAULT;
}
insn &= ~(GENMASK(4, 0) << shift);
@@ -446,7 +452,7 @@ static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type,
break;
default:
pr_err("%s: unknown size encoding %d\n", __func__, type);
- return 0;
+ return AARCH64_BREAK_FAULT;
}
insn &= ~GENMASK(31, 30);
@@ -460,14 +466,17 @@ static inline long branch_imm_common(unsigned long pc, unsigned long addr,
{
long offset;
- /*
- * PC: A 64-bit Program Counter holding the address of the current
- * instruction. A64 instructions must be word-aligned.
- */
- BUG_ON((pc & 0x3) || (addr & 0x3));
+ if ((pc & 0x3) || (addr & 0x3)) {
+ pr_err("%s: A64 instructions must be word aligned\n", __func__);
+ return range;
+ }
offset = ((long)addr - (long)pc);
- BUG_ON(offset < -range || offset >= range);
+
+ if (offset < -range || offset >= range) {
+ pr_err("%s: offset out of range\n", __func__);
+ return range;
+ }
return offset;
}
@@ -484,6 +493,8 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
* texts are within +/-128M.
*/
offset = branch_imm_common(pc, addr, SZ_128M);
+ if (offset >= SZ_128M)
+ return AARCH64_BREAK_FAULT;
switch (type) {
case AARCH64_INSN_BRANCH_LINK:
@@ -493,7 +504,7 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
insn = aarch64_insn_get_b_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown branch encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -510,6 +521,8 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
long offset;
offset = branch_imm_common(pc, addr, SZ_1M);
+ if (offset >= SZ_1M)
+ return AARCH64_BREAK_FAULT;
switch (type) {
case AARCH64_INSN_BRANCH_COMP_ZERO:
@@ -519,7 +532,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
insn = aarch64_insn_get_cbnz_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown branch encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -530,7 +543,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
insn |= AARCH64_INSN_SF_BIT;
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -550,7 +563,10 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
insn = aarch64_insn_get_bcond_value();
- BUG_ON(cond < AARCH64_INSN_COND_EQ || cond > AARCH64_INSN_COND_AL);
+ if (cond < AARCH64_INSN_COND_EQ || cond > AARCH64_INSN_COND_AL) {
+ pr_err("%s: unknown condition encoding %d\n", __func__, cond);
+ return AARCH64_BREAK_FAULT;
+ }
insn |= cond;
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
@@ -583,7 +599,7 @@ u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
insn = aarch64_insn_get_ret_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown branch encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -606,7 +622,7 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
insn = aarch64_insn_get_str_reg_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown load/store encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -645,26 +661,30 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
insn = aarch64_insn_get_stp_post_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown load/store encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
switch (variant) {
case AARCH64_INSN_VARIANT_32BIT:
- /* offset must be multiples of 4 in the range [-256, 252] */
- BUG_ON(offset & 0x3);
- BUG_ON(offset < -256 || offset > 252);
+ if ((offset & 0x3) || (offset < -256) || (offset > 252)) {
+ pr_err("%s: offset must be multiples of 4 in the range of [-256, 252] %d\n",
+ __func__, offset);
+ return AARCH64_BREAK_FAULT;
+ }
shift = 2;
break;
case AARCH64_INSN_VARIANT_64BIT:
- /* offset must be multiples of 8 in the range [-512, 504] */
- BUG_ON(offset & 0x7);
- BUG_ON(offset < -512 || offset > 504);
+ if ((offset & 0x7) || (offset < -512) || (offset > 504)) {
+ pr_err("%s: offset must be multiples of 8 in the range of [-512, 504] %d\n",
+ __func__, offset);
+ return AARCH64_BREAK_FAULT;
+ }
shift = 3;
insn |= AARCH64_INSN_SF_BIT;
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -702,7 +722,7 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
insn = aarch64_insn_get_subs_imm_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown add/sub encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -713,11 +733,14 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT;
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
- BUG_ON(imm & ~(SZ_4K - 1));
+ if (imm & ~(SZ_4K - 1)) {
+ pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
+ return AARCH64_BREAK_FAULT;
+ }
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
@@ -746,7 +769,7 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
insn = aarch64_insn_get_sbfm_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown bitfield encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -759,12 +782,18 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
mask = GENMASK(5, 0);
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
- BUG_ON(immr & ~mask);
- BUG_ON(imms & ~mask);
+ if (immr & ~mask) {
+ pr_err("%s: invalid immr encoding %d\n", __func__, immr);
+ return AARCH64_BREAK_FAULT;
+ }
+ if (imms & ~mask) {
+ pr_err("%s: invalid imms encoding %d\n", __func__, imms);
+ return AARCH64_BREAK_FAULT;
+ }
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
@@ -793,23 +822,33 @@ u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst,
insn = aarch64_insn_get_movn_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown movewide encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
- BUG_ON(imm & ~(SZ_64K - 1));
+ if (imm & ~(SZ_64K - 1)) {
+ pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
+ return AARCH64_BREAK_FAULT;
+ }
switch (variant) {
case AARCH64_INSN_VARIANT_32BIT:
- BUG_ON(shift != 0 && shift != 16);
+ if (shift != 0 && shift != 16) {
+ pr_err("%s: invalid shift encoding %d\n", __func__,
+ shift);
+ return AARCH64_BREAK_FAULT;
+ }
break;
case AARCH64_INSN_VARIANT_64BIT:
insn |= AARCH64_INSN_SF_BIT;
- BUG_ON(shift != 0 && shift != 16 && shift != 32 &&
- shift != 48);
+ if (shift != 0 && shift != 16 && shift != 32 && shift != 48) {
+ pr_err("%s: invalid shift encoding %d\n", __func__,
+ shift);
+ return AARCH64_BREAK_FAULT;
+ }
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -843,20 +882,28 @@ u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst,
insn = aarch64_insn_get_subs_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown add/sub encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
switch (variant) {
case AARCH64_INSN_VARIANT_32BIT:
- BUG_ON(shift & ~(SZ_32 - 1));
+ if (shift & ~(SZ_32 - 1)) {
+ pr_err("%s: invalid shift encoding %d\n", __func__,
+ shift);
+ return AARCH64_BREAK_FAULT;
+ }
break;
case AARCH64_INSN_VARIANT_64BIT:
insn |= AARCH64_INSN_SF_BIT;
- BUG_ON(shift & ~(SZ_64 - 1));
+ if (shift & ~(SZ_64 - 1)) {
+ pr_err("%s: invalid shift encoding %d\n", __func__,
+ shift);
+ return AARCH64_BREAK_FAULT;
+ }
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -885,11 +932,15 @@ u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst,
insn = aarch64_insn_get_rev32_value();
break;
case AARCH64_INSN_DATA1_REVERSE_64:
- BUG_ON(variant != AARCH64_INSN_VARIANT_64BIT);
+ if (variant != AARCH64_INSN_VARIANT_64BIT) {
+ pr_err("%s: invalid variant for reverse64 %d\n",
+ __func__, variant);
+ return AARCH64_BREAK_FAULT;
+ }
insn = aarch64_insn_get_rev64_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown data1 encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -900,7 +951,7 @@ u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT;
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -937,7 +988,7 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst,
insn = aarch64_insn_get_rorv_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown data2 encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -948,7 +999,7 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT;
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -976,7 +1027,7 @@ u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst,
insn = aarch64_insn_get_msub_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown data3 encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
@@ -987,7 +1038,7 @@ u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT;
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
@@ -1037,20 +1088,28 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
insn = aarch64_insn_get_bics_value();
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown logical encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT;
}
switch (variant) {
case AARCH64_INSN_VARIANT_32BIT:
- BUG_ON(shift & ~(SZ_32 - 1));
+ if (shift & ~(SZ_32 - 1)) {
+ pr_err("%s: invalid shift encoding %d\n", __func__,
+ shift);
+ return AARCH64_BREAK_FAULT;
+ }
break;
case AARCH64_INSN_VARIANT_64BIT:
insn |= AARCH64_INSN_SF_BIT;
- BUG_ON(shift & ~(SZ_64 - 1));
+ if (shift & ~(SZ_64 - 1)) {
+ pr_err("%s: invalid shift encoding %d\n", __func__,
+ shift);
+ return AARCH64_BREAK_FAULT;
+ }
break;
default:
- BUG_ON(1);
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT;
}
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
index 46649d6e6c5a..60585bde1264 100644
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -102,19 +102,3 @@ EXPORT_SYMBOL(flush_dcache_page);
* Additional functions defined in assembly.
*/
EXPORT_SYMBOL(flush_icache_range);
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-#ifdef CONFIG_HAVE_RCU_TABLE_FREE
-void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp)
-{
- pmd_t pmd = pmd_mksplitting(*pmdp);
-
- VM_BUG_ON(address & ~PMD_MASK);
- set_pmd_at(vma->vm_mm, address, pmdp, pmd);
-
- /* dummy IPI to serialise against fast_gup */
- kick_all_cpus_sync();
-}
-#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index ed177475dd8c..4c893b5189dd 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -51,8 +51,12 @@ unsigned long arch_mmap_rnd(void)
{
unsigned long rnd;
- rnd = (unsigned long)get_random_int() & STACK_RND_MASK;
-
+#ifdef CONFIG_COMPAT
+ if (test_thread_flag(TIF_32BIT))
+ rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_compat_bits) - 1);
+ else
+#endif
+ rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
return rnd << PAGE_SHIFT;
}
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 7658612d915c..a34420a5df9a 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1,7 +1,7 @@
/*
* BPF JIT compiler for ARM64
*
- * Copyright (C) 2014-2015 Zi Shen Lim <zlim.lnx@gmail.com>
+ * Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@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
@@ -737,6 +737,20 @@ static int build_body(struct jit_ctx *ctx)
return 0;
}
+static int validate_code(struct jit_ctx *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->idx; i++) {
+ u32 a64_insn = le32_to_cpu(ctx->image[i]);
+
+ if (a64_insn == AARCH64_BREAK_FAULT)
+ return -1;
+ }
+
+ return 0;
+}
+
static inline void bpf_flush_icache(void *start, void *end)
{
flush_icache_range((unsigned long)start, (unsigned long)end);
@@ -799,6 +813,12 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
build_epilogue(&ctx);
+ /* 3. Extra pass to validate JITed code. */
+ if (validate_code(&ctx)) {
+ bpf_jit_binary_free(header);
+ goto out;
+ }
+
/* And we're done. */
if (bpf_jit_enable > 1)
bpf_jit_dump(prog->len, image_size, 2, ctx.image);
diff --git a/arch/avr32/include/asm/page.h b/arch/avr32/include/asm/page.h
index f805d1cb11bc..c5d2a3e2c62f 100644
--- a/arch/avr32/include/asm/page.h
+++ b/arch/avr32/include/asm/page.h
@@ -83,11 +83,9 @@ static inline int get_order(unsigned long size)
#ifndef CONFIG_NEED_MULTIPLE_NODES
-#define PHYS_PFN_OFFSET (CONFIG_PHYS_OFFSET >> PAGE_SHIFT)
+#define ARCH_PFN_OFFSET (CONFIG_PHYS_OFFSET >> PAGE_SHIFT)
-#define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET))
-#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET)
-#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
+#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && (pfn) < (ARCH_PFN_OFFSET + max_mapnr))
#endif /* CONFIG_NEED_MULTIPLE_NODES */
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
@@ -101,4 +99,6 @@ static inline int get_order(unsigned long size)
*/
#define HIGHMEM_START 0x20000000UL
+#include <asm-generic/memory_model.h>
+
#endif /* __ASM_AVR32_PAGE_H */
diff --git a/arch/avr32/include/uapi/asm/unistd.h b/arch/avr32/include/uapi/asm/unistd.h
index bbe2fba565cd..b60132bb27ea 100644
--- a/arch/avr32/include/uapi/asm/unistd.h
+++ b/arch/avr32/include/uapi/asm/unistd.h
@@ -333,5 +333,9 @@
#define __NR_memfd_create 318
#define __NR_bpf 319
#define __NR_execveat 320
+#define __NR_accept4 321
+#define __NR_userfaultfd 322
+#define __NR_membarrier 323
+#define __NR_mlock2 324
#endif /* _UAPI__ASM_AVR32_UNISTD_H */
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index 164efa009e5b..2b4c54c04cb6 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -118,9 +118,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
* Increase core size to make room for GOT and set start
* offset for GOT.
*/
- module->core_size = ALIGN(module->core_size, 4);
- module->arch.got_offset = module->core_size;
- module->core_size += module->arch.got_size;
+ module->core_layout.size = ALIGN(module->core_layout.size, 4);
+ module->arch.got_offset = module->core_layout.size;
+ module->core_layout.size += module->arch.got_size;
return 0;
@@ -177,7 +177,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
if (!info->got_initialized) {
Elf32_Addr *gotent;
- gotent = (module->module_core
+ gotent = (module->core_layout.base
+ module->arch.got_offset
+ info->got_offset);
*gotent = relocation;
@@ -255,8 +255,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
*/
pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n",
relocation, module->arch.got_offset,
- module->module_core);
- relocation -= ((unsigned long)module->module_core
+ module->core_layout.base);
+ relocation -= ((unsigned long)module->core_layout.base
+ module->arch.got_offset);
*location = relocation;
break;
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index c3b593bfc3b3..1915a443b491 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -334,4 +334,8 @@ sys_call_table:
.long sys_memfd_create
.long sys_bpf
.long sys_execveat /* 320 */
+ .long sys_accept4
+ .long sys_userfaultfd
+ .long sys_membarrier
+ .long sys_mlock2
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index b4cb3bd89d8a..bf445aa48282 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -17,7 +17,6 @@
#include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.h>
-#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/atmel-mci.h>
#include <asm/io.h>
@@ -1321,11 +1320,26 @@ static struct clk atmel_mci0_pclk = {
.index = 9,
};
+static bool at32_mci_dma_filter(struct dma_chan *chan, void *pdata)
+{
+ struct dw_dma_slave *sl = pdata;
+
+ if (!sl)
+ return false;
+
+ if (sl->dma_dev == chan->device->dev) {
+ chan->private = sl;
+ return true;
+ }
+
+ return false;
+}
+
struct platform_device *__init
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
{
struct platform_device *pdev;
- struct mci_dma_data *slave;
+ struct dw_dma_slave *slave;
u32 pioa_mask;
u32 piob_mask;
@@ -1344,17 +1358,18 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
ARRAY_SIZE(atmel_mci0_resource)))
goto fail;
- slave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
+ slave = kzalloc(sizeof(*slave), GFP_KERNEL);
if (!slave)
goto fail;
- slave->sdata.dma_dev = &dw_dmac0_device.dev;
- slave->sdata.src_id = 0;
- slave->sdata.dst_id = 1;
- slave->sdata.src_master = 1;
- slave->sdata.dst_master = 0;
+ slave->dma_dev = &dw_dmac0_device.dev;
+ slave->src_id = 0;
+ slave->dst_id = 1;
+ slave->src_master = 1;
+ slave->dst_master = 0;
data->dma_slave = slave;
+ data->dma_filter = at32_mci_dma_filter;
if (platform_device_add_data(pdev, data,
sizeof(struct mci_platform_data)))
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 4f61378c3453..5020057ac7a2 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -203,7 +203,7 @@ fail:
static int direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ struct pio_device *pio = gpiochip_get_data(chip);
u32 mask = 1 << offset;
if (!(pio_readl(pio, PSR) & mask))
@@ -215,7 +215,7 @@ static int direction_input(struct gpio_chip *chip, unsigned offset)
static int gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ struct pio_device *pio = gpiochip_get_data(chip);
return (pio_readl(pio, PDSR) >> offset) & 1;
}
@@ -224,7 +224,7 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value);
static int direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ struct pio_device *pio = gpiochip_get_data(chip);
u32 mask = 1 << offset;
if (!(pio_readl(pio, PSR) & mask))
@@ -237,7 +237,7 @@ static int direction_output(struct gpio_chip *chip, unsigned offset, int value)
static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ struct pio_device *pio = gpiochip_get_data(chip);
u32 mask = 1 << offset;
if (value)
@@ -335,7 +335,7 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
*/
static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ struct pio_device *pio = gpiochip_get_data(chip);
u32 psr, osr, imr, pdsr, pusr, ifsr, mdsr;
unsigned i;
u32 mask;
@@ -397,7 +397,7 @@ static int __init pio_probe(struct platform_device *pdev)
pio->chip.label = pio->name;
pio->chip.base = pdev->id * 32;
pio->chip.ngpio = 32;
- pio->chip.dev = &pdev->dev;
+ pio->chip.parent = &pdev->dev;
pio->chip.owner = THIS_MODULE;
pio->chip.direction_input = direction_input;
@@ -406,7 +406,7 @@ static int __init pio_probe(struct platform_device *pdev)
pio->chip.set = gpio_set;
pio->chip.dbg_show = pio_bank_show;
- gpiochip_add(&pio->chip);
+ gpiochip_add_data(&pio->chip, pio);
gpio_irq_setup(pio, irq, gpio_irq_base);
diff --git a/arch/blackfin/include/asm/barrier.h b/arch/blackfin/include/asm/barrier.h
index dfb66fe88b34..7cca51cae5ff 100644
--- a/arch/blackfin/include/asm/barrier.h
+++ b/arch/blackfin/include/asm/barrier.h
@@ -78,8 +78,8 @@
#endif /* !CONFIG_SMP */
-#define smp_mb__before_atomic() barrier()
-#define smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
#include <asm-generic/barrier.h>
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 88a19fc9844d..c181543a399a 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -404,7 +404,7 @@ static struct mtd_partition bfin_plat_nand_partitions[] = {
#define BFIN_NAND_PLAT_ALE 1
static void bfin_plat_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
if (cmd == NAND_CMD_NONE)
return;
diff --git a/arch/blackfin/mach-bf561/boards/acvilon.c b/arch/blackfin/mach-bf561/boards/acvilon.c
index 6ab951534d79..37f8f25a1347 100644
--- a/arch/blackfin/mach-bf561/boards/acvilon.c
+++ b/arch/blackfin/mach-bf561/boards/acvilon.c
@@ -267,7 +267,7 @@ static struct mtd_partition bfin_plat_nand_partitions[] = {
static void bfin_plat_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
if (cmd == NAND_CMD_NONE)
return;
diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
index 7fb52128ddc9..5aa3f5162310 100644
--- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
@@ -36,7 +36,6 @@
#define CE_BIT 12
struct mtd_info_wrapper {
- struct mtd_info info;
struct nand_chip chip;
};
@@ -52,7 +51,7 @@ static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
{
unsigned long flags;
reg_pio_rw_dout dout;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
local_irq_save(flags);
@@ -148,10 +147,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
/* Get pointer to private data */
this = &wrapper->chip;
- crisv32_mtd = &wrapper->info;
-
- /* Link the private data with the MTD structure */
- crisv32_mtd->priv = this;
+ crisv32_mtd = nand_to_mtd(this);
/* Set address of NAND IO lines */
this->IO_ADDR_R = read_cs;
diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
index e03238454b0e..a7c17b0f172a 100644
--- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
@@ -31,7 +31,6 @@
#define BY_BIT 7
struct mtd_info_wrapper {
- struct mtd_info info;
struct nand_chip chip;
};
@@ -51,7 +50,7 @@ static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
{
unsigned long flags;
reg_gio_rw_pa_dout dout;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
local_irq_save(flags);
@@ -129,7 +128,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
/* Get pointer to private data */
this = &wrapper->chip;
- crisv32_mtd = &wrapper->info;
+ crisv32_mtd = nand_to_mtd(this);
pa_oe.oe |= 1 << CE_BIT;
pa_oe.oe |= 1 << ALE_BIT;
@@ -141,9 +140,6 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
bif_cfg.gated_csp1 = regk_bif_core_wr;
REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg);
- /* Link the private data with the MTD structure */
- crisv32_mtd->priv = this;
-
/* Set address of NAND IO lines */
this->IO_ADDR_R = read_cs;
this->IO_ADDR_W = write_cs;
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 34aa19352dc1..03bfd6bf03e7 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -10,6 +10,7 @@ config FRV
select HAVE_DEBUG_BUGVERBOSE
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CPU_DEVICES
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_WANT_IPC_PARSE_VERSION
select OLD_SIGSUSPEND3
select OLD_SIGACTION
diff --git a/arch/frv/include/asm/page.h b/arch/frv/include/asm/page.h
index 8c97068ac8fc..688d8076a43a 100644
--- a/arch/frv/include/asm/page.h
+++ b/arch/frv/include/asm/page.h
@@ -34,7 +34,7 @@ typedef struct page *pgtable_t;
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } )
-#define __pmd(x) ((pmd_t) { (x) } )
+#define __pmd(x) ((pmd_t) { { (x) } } )
#define __pud(x) ((pud_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
diff --git a/arch/ia64/include/asm/barrier.h b/arch/ia64/include/asm/barrier.h
index 209c4b817c95..588f1614cafc 100644
--- a/arch/ia64/include/asm/barrier.h
+++ b/arch/ia64/include/asm/barrier.h
@@ -42,34 +42,24 @@
#define dma_rmb() mb()
#define dma_wmb() mb()
-#ifdef CONFIG_SMP
-# define smp_mb() mb()
-#else
-# define smp_mb() barrier()
-#endif
+# define __smp_mb() mb()
-#define smp_rmb() smp_mb()
-#define smp_wmb() smp_mb()
-
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
-
-#define smp_mb__before_atomic() barrier()
-#define smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
/*
* IA64 GCC turns volatile stores into st.rel and volatile loads into ld.acq no
* need for asm trickery!
*/
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
WRITE_ONCE(*p, v); \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
@@ -77,12 +67,12 @@ do { \
___p1; \
})
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
-
/*
* The group barrier in front of the rsm & ssm are necessary to ensure
* that none of the previous instructions in the same group are
* affected by the rsm/ssm.
*/
+#include <asm-generic/barrier.h>
+
#endif /* _ASM_IA64_BARRIER_H */
diff --git a/arch/ia64/include/asm/early_ioremap.h b/arch/ia64/include/asm/early_ioremap.h
new file mode 100644
index 000000000000..eec9e1d1b833
--- /dev/null
+++ b/arch/ia64/include/asm/early_ioremap.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_IA64_EARLY_IOREMAP_H
+#define _ASM_IA64_EARLY_IOREMAP_H
+
+extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
+#define early_memremap(phys_addr, size) early_ioremap(phys_addr, size)
+
+extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
+#define early_memunmap(addr, size) early_iounmap(addr, size)
+
+#endif
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h
index 9041bbe2b7b4..a865d2a04f75 100644
--- a/arch/ia64/include/asm/io.h
+++ b/arch/ia64/include/asm/io.h
@@ -20,6 +20,7 @@
*/
#include <asm/unaligned.h>
+#include <asm/early_ioremap.h>
/* We don't use IO slowdowns on the ia64, but.. */
#define __SLOW_DOWN_IO do { } while (0)
@@ -427,10 +428,6 @@ __writeq (unsigned long val, volatile void __iomem *addr)
extern void __iomem * ioremap(unsigned long offset, unsigned long size);
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap (volatile void __iomem *addr);
-extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
-#define early_memremap(phys_addr, size) early_ioremap(phys_addr, size)
-extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
-#define early_memunmap(addr, size) early_iounmap(addr, size)
static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size)
{
return ioremap(phys_addr, size);
diff --git a/arch/ia64/include/asm/page.h b/arch/ia64/include/asm/page.h
index ec48bb9f95e1..e8c486ef0d76 100644
--- a/arch/ia64/include/asm/page.h
+++ b/arch/ia64/include/asm/page.h
@@ -105,6 +105,7 @@ extern struct page *vmem_map;
#ifdef CONFIG_DISCONTIGMEM
# define page_to_pfn(page) ((unsigned long) (page - vmem_map))
# define pfn_to_page(pfn) (vmem_map + (pfn))
+# define __pfn_to_phys(pfn) PFN_PHYS(pfn)
#else
# include <asm-generic/memory_model.h>
#endif
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index d2fae054d988..90fde5b8669d 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -256,7 +256,7 @@ set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask)
}
static void
-nop (struct irq_data *data)
+iosapic_nop (struct irq_data *data)
{
/* do nothing... */
}
@@ -415,7 +415,7 @@ iosapic_unmask_level_irq (struct irq_data *data)
#define iosapic_shutdown_level_irq mask_irq
#define iosapic_enable_level_irq unmask_irq
#define iosapic_disable_level_irq mask_irq
-#define iosapic_ack_level_irq nop
+#define iosapic_ack_level_irq iosapic_nop
static struct irq_chip irq_type_iosapic_level = {
.name = "IO-SAPIC-level",
@@ -453,7 +453,7 @@ iosapic_ack_edge_irq (struct irq_data *data)
}
#define iosapic_enable_edge_irq unmask_irq
-#define iosapic_disable_edge_irq nop
+#define iosapic_disable_edge_irq iosapic_nop
static struct irq_chip irq_type_iosapic_edge = {
.name = "IO-SAPIC-edge",
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
index b15933c31b2f..6ab0ae7d6535 100644
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -486,13 +486,13 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
static inline int
in_init (const struct module *mod, uint64_t addr)
{
- return addr - (uint64_t) mod->module_init < mod->init_size;
+ return addr - (uint64_t) mod->init_layout.base < mod->init_layout.size;
}
static inline int
in_core (const struct module *mod, uint64_t addr)
{
- return addr - (uint64_t) mod->module_core < mod->core_size;
+ return addr - (uint64_t) mod->core_layout.base < mod->core_layout.size;
}
static inline int
@@ -675,7 +675,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
break;
case RV_BDREL:
- val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core);
+ val -= (uint64_t) (in_init(mod, val) ? mod->init_layout.base : mod->core_layout.base);
break;
case RV_LTV:
@@ -810,15 +810,15 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind
* addresses have been selected...
*/
uint64_t gp;
- if (mod->core_size > MAX_LTOFF)
+ if (mod->core_layout.size > MAX_LTOFF)
/*
* This takes advantage of fact that SHF_ARCH_SMALL gets allocated
* at the end of the module.
*/
- gp = mod->core_size - MAX_LTOFF / 2;
+ gp = mod->core_layout.size - MAX_LTOFF / 2;
else
- gp = mod->core_size / 2;
- gp = (uint64_t) mod->module_core + ((gp + 7) & -8);
+ gp = mod->core_layout.size / 2;
+ gp = (uint64_t) mod->core_layout.base + ((gp + 7) & -8);
mod->arch.gp = gp;
DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp);
}
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 60e02f7747ff..9cd607b06964 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2332,8 +2332,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
*/
insert_vm_struct(mm, vma);
- vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file,
- vma_pages(vma));
+ vm_stat_account(vma->vm_mm, vma->vm_flags, vma_pages(vma));
up_write(&task->mm->mmap_sem);
/*
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 9e44bbd8051e..836ac5a963c8 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -13,6 +13,7 @@ config M32R
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select GENERIC_ATOMIC64
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_USES_GETTIMEOFFSET
select MODULES_USE_ELF_RELA
select HAVE_DEBUG_STACKOVERFLOW
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c
index 0392112a5d70..a5ecef7188ba 100644
--- a/arch/m32r/kernel/setup.c
+++ b/arch/m32r/kernel/setup.c
@@ -81,7 +81,10 @@ static struct resource code_resource = {
};
unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
void __init setup_arch(char **);
int get_cpuinfo(char *);
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index 0b389a81c43a..a0fa88da3e31 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -36,9 +36,6 @@ config STACKTRACE_SUPPORT
config LOCKDEP_SUPPORT
def_bool y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config RWSEM_GENERIC_SPINLOCK
def_bool y
diff --git a/arch/metag/include/asm/barrier.h b/arch/metag/include/asm/barrier.h
index 172b7e5efc53..5418517aa5eb 100644
--- a/arch/metag/include/asm/barrier.h
+++ b/arch/metag/include/asm/barrier.h
@@ -44,16 +44,6 @@ static inline void wr_fence(void)
#define rmb() barrier()
#define wmb() mb()
-#define dma_rmb() rmb()
-#define dma_wmb() wmb()
-
-#ifndef CONFIG_SMP
-#define fence() do { } while (0)
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#else
-
#ifdef CONFIG_METAG_SMP_WRITE_REORDERING
/*
* Write to the atomic memory unlock system event register (command 0). This is
@@ -63,45 +53,32 @@ static inline void wr_fence(void)
* incoherence). It is therefore ineffective if used after and on the same
* thread as a write.
*/
-static inline void fence(void)
+static inline void metag_fence(void)
{
volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_ATOMIC_UNLOCK;
barrier();
*flushptr = 0;
barrier();
}
-#define smp_mb() fence()
-#define smp_rmb() fence()
-#define smp_wmb() barrier()
+#define __smp_mb() metag_fence()
+#define __smp_rmb() metag_fence()
+#define __smp_wmb() barrier()
#else
-#define fence() do { } while (0)
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#endif
+#define metag_fence() do { } while (0)
+#define __smp_mb() barrier()
+#define __smp_rmb() barrier()
+#define __smp_wmb() barrier()
#endif
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
-
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
-
-#define smp_store_release(p, v) \
-do { \
- compiletime_assert_atomic_type(*p); \
- smp_mb(); \
- WRITE_ONCE(*p, v); \
-} while (0)
+#ifdef CONFIG_SMP
+#define fence() metag_fence()
+#else
+#define fence() do { } while (0)
+#endif
-#define smp_load_acquire(p) \
-({ \
- typeof(*p) ___p1 = READ_ONCE(*p); \
- compiletime_assert_atomic_type(*p); \
- smp_mb(); \
- ___p1; \
-})
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
-#define smp_mb__before_atomic() barrier()
-#define smp_mb__after_atomic() barrier()
+#include <asm-generic/barrier.h>
#endif /* _ASM_METAG_BARRIER_H */
diff --git a/arch/metag/kernel/module.c b/arch/metag/kernel/module.c
index 986331cd0a52..bb8dfba9a763 100644
--- a/arch/metag/kernel/module.c
+++ b/arch/metag/kernel/module.c
@@ -176,8 +176,8 @@ static uint32_t do_plt_call(void *location, Elf32_Addr val,
tramp[1] = 0xac000001 | ((val & 0x0000ffff) << 3);
/* Init, or core PLT? */
- if (location >= mod->module_core
- && location < mod->module_core + mod->core_size)
+ if (location >= mod->core_layout.base
+ && location < mod->core_layout.base + mod->core_layout.size)
entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
else
entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 0bce820428fc..5ecd0287a874 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -67,9 +67,6 @@ config STACKTRACE_SUPPORT
config LOCKDEP_SUPPORT
def_bool y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index 8c13675a12e7..992442a03d8b 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -200,7 +200,7 @@ static struct i2c_board_info db1200_i2c_devs[] __initdata = {
static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
ioaddr &= 0xffffff00;
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index b58077008a53..d3c087f59f1a 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -150,7 +150,7 @@ static void __init db1300_gpio_config(void)
static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
ioaddr &= 0xffffff00;
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index 5740bcfdfc7f..b518f029f5e7 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -128,7 +128,7 @@ static struct i2c_board_info db1550_i2c_devs[] __initdata = {
static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
ioaddr &= 0xffffff00;
diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h
index 752e0b86c171..d296633d890e 100644
--- a/arch/mips/include/asm/barrier.h
+++ b/arch/mips/include/asm/barrier.h
@@ -10,9 +10,6 @@
#include <asm/addrspace.h>
-#define read_barrier_depends() do { } while(0)
-#define smp_read_barrier_depends() do { } while(0)
-
#ifdef CONFIG_CPU_HAS_SYNC
#define __sync() \
__asm__ __volatile__( \
@@ -87,23 +84,21 @@
#define wmb() fast_wmb()
#define rmb() fast_rmb()
-#define dma_wmb() fast_wmb()
-#define dma_rmb() fast_rmb()
-#if defined(CONFIG_WEAK_ORDERING) && defined(CONFIG_SMP)
+#if defined(CONFIG_WEAK_ORDERING)
# ifdef CONFIG_CPU_CAVIUM_OCTEON
-# define smp_mb() __sync()
-# define smp_rmb() barrier()
-# define smp_wmb() __syncw()
+# define __smp_mb() __sync()
+# define __smp_rmb() barrier()
+# define __smp_wmb() __syncw()
# else
-# define smp_mb() __asm__ __volatile__("sync" : : :"memory")
-# define smp_rmb() __asm__ __volatile__("sync" : : :"memory")
-# define smp_wmb() __asm__ __volatile__("sync" : : :"memory")
+# define __smp_mb() __asm__ __volatile__("sync" : : :"memory")
+# define __smp_rmb() __asm__ __volatile__("sync" : : :"memory")
+# define __smp_wmb() __asm__ __volatile__("sync" : : :"memory")
# endif
#else
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
+#define __smp_mb() barrier()
+#define __smp_rmb() barrier()
+#define __smp_wmb() barrier()
#endif
#if defined(CONFIG_WEAK_REORDERING_BEYOND_LLSC) && defined(CONFIG_SMP)
@@ -112,13 +107,11 @@
#define __WEAK_LLSC_MB " \n"
#endif
-#define smp_store_mb(var, value) \
- do { WRITE_ONCE(var, value); smp_mb(); } while (0)
-
#define smp_llsc_mb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
#ifdef CONFIG_CPU_CAVIUM_OCTEON
#define smp_mb__before_llsc() smp_wmb()
+#define __smp_mb__before_llsc() __smp_wmb()
/* Cause previous writes to become visible on all CPUs as soon as possible */
#define nudge_writes() __asm__ __volatile__(".set push\n\t" \
".set arch=octeon\n\t" \
@@ -126,25 +119,13 @@
".set pop" : : : "memory")
#else
#define smp_mb__before_llsc() smp_llsc_mb()
+#define __smp_mb__before_llsc() smp_llsc_mb()
#define nudge_writes() mb()
#endif
-#define smp_store_release(p, v) \
-do { \
- compiletime_assert_atomic_type(*p); \
- smp_mb(); \
- WRITE_ONCE(*p, v); \
-} while (0)
-
-#define smp_load_acquire(p) \
-({ \
- typeof(*p) ___p1 = READ_ONCE(*p); \
- compiletime_assert_atomic_type(*p); \
- smp_mb(); \
- ___p1; \
-})
-
-#define smp_mb__before_atomic() smp_mb__before_llsc()
-#define smp_mb__after_atomic() smp_llsc_mb()
+#define __smp_mb__before_atomic() __smp_mb__before_llsc()
+#define __smp_mb__after_atomic() smp_llsc_mb()
+
+#include <asm-generic/barrier.h>
#endif /* __ASM_BARRIER_H */
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 6ded8d347af9..7c191443c7ea 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -101,9 +101,9 @@
#define CAUSEF_DC (_ULCAST_(1) << 27)
extern atomic_t kvm_mips_instance;
-extern pfn_t(*kvm_mips_gfn_to_pfn) (struct kvm *kvm, gfn_t gfn);
-extern void (*kvm_mips_release_pfn_clean) (pfn_t pfn);
-extern bool(*kvm_mips_is_error_pfn) (pfn_t pfn);
+extern kvm_pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
+extern void (*kvm_mips_release_pfn_clean)(kvm_pfn_t pfn);
+extern bool (*kvm_mips_is_error_pfn)(kvm_pfn_t pfn);
struct kvm_vm_stat {
u32 remote_tlb_flush;
diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h
index ff7ad91c85db..97b313882678 100644
--- a/arch/mips/include/asm/pgtable-bits.h
+++ b/arch/mips/include/asm/pgtable-bits.h
@@ -131,14 +131,12 @@
/* Huge TLB page */
#define _PAGE_HUGE_SHIFT (_PAGE_MODIFIED_SHIFT + 1)
#define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT)
-#define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1)
-#define _PAGE_SPLITTING (1 << _PAGE_SPLITTING_SHIFT)
#endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
/* XI - page cannot be executed */
-#ifdef _PAGE_SPLITTING_SHIFT
-#define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1)
+#ifdef _PAGE_HUGE_SHIFT
+#define _PAGE_NO_EXEC_SHIFT (_PAGE_HUGE_SHIFT + 1)
#else
#define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1)
#endif
@@ -153,8 +151,8 @@
#if defined(_PAGE_NO_READ_SHIFT)
#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1)
-#elif defined(_PAGE_SPLITTING_SHIFT)
-#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1)
+#elif defined(_PAGE_HUGE_SHIFT)
+#define _PAGE_GLOBAL_SHIFT (_PAGE_HUGE_SHIFT + 1)
#else
#define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1)
#endif
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 8957f15e21ec..6995b4a02e23 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -482,27 +482,9 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd)
return pmd;
}
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- return !!(pmd_val(pmd) & _PAGE_SPLITTING);
-}
-
-static inline pmd_t pmd_mksplitting(pmd_t pmd)
-{
- pmd_val(pmd) |= _PAGE_SPLITTING;
-
- return pmd;
-}
-
extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd);
-#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-/* Extern to avoid header file madness */
-extern void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long address,
- pmd_t *pmdp);
-
#define __HAVE_ARCH_PMD_WRITE
static inline int pmd_write(pmd_t pmd)
{
diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h
index 97c03f468924..b0ebe59f73fd 100644
--- a/arch/mips/include/uapi/asm/mman.h
+++ b/arch/mips/include/uapi/asm/mman.h
@@ -73,8 +73,10 @@
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
#define MADV_WILLNEED 3 /* will need these pages */
#define MADV_DONTNEED 4 /* don't need these pages */
+#define MADV_FREE 5 /* free pages only if memory pressure */
/* common parameters: try to keep these consistent across architectures */
+#define MADV_FREE 8 /* free pages only if memory pressure */
#define MADV_REMOVE 9 /* remove these pages & resources */
#define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 9067b651c7a2..544ea21bfef9 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -205,11 +205,11 @@ static void layout_sections(struct module *mod, const Elf_Ehdr *hdr,
|| s->sh_entsize != ~0UL)
continue;
s->sh_entsize =
- get_offset((unsigned long *)&mod->core_size, s);
+ get_offset((unsigned long *)&mod->core_layout.size, s);
}
if (m == 0)
- mod->core_text_size = mod->core_size;
+ mod->core_layout.text_size = mod->core_layout.size;
}
}
@@ -641,7 +641,7 @@ static int vpe_elfload(struct vpe *v)
layout_sections(&mod, hdr, sechdrs, secstrings);
}
- v->load_addr = alloc_progmem(mod.core_size);
+ v->load_addr = alloc_progmem(mod.core_layout.size);
if (!v->load_addr)
return -ENOMEM;
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 41b1b090f56f..1b675c7ce89f 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1525,7 +1525,7 @@ int kvm_mips_sync_icache(unsigned long va, struct kvm_vcpu *vcpu)
struct kvm *kvm = vcpu->kvm;
unsigned long pa;
gfn_t gfn;
- pfn_t pfn;
+ kvm_pfn_t pfn;
gfn = va >> PAGE_SHIFT;
diff --git a/arch/mips/kvm/tlb.c b/arch/mips/kvm/tlb.c
index aed0ac2a4972..570479c03bdc 100644
--- a/arch/mips/kvm/tlb.c
+++ b/arch/mips/kvm/tlb.c
@@ -38,13 +38,13 @@ atomic_t kvm_mips_instance;
EXPORT_SYMBOL(kvm_mips_instance);
/* These function pointers are initialized once the KVM module is loaded */
-pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
+kvm_pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
EXPORT_SYMBOL(kvm_mips_gfn_to_pfn);
-void (*kvm_mips_release_pfn_clean)(pfn_t pfn);
+void (*kvm_mips_release_pfn_clean)(kvm_pfn_t pfn);
EXPORT_SYMBOL(kvm_mips_release_pfn_clean);
-bool (*kvm_mips_is_error_pfn)(pfn_t pfn);
+bool (*kvm_mips_is_error_pfn)(kvm_pfn_t pfn);
EXPORT_SYMBOL(kvm_mips_is_error_pfn);
uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
@@ -144,7 +144,7 @@ EXPORT_SYMBOL(kvm_mips_dump_guest_tlbs);
static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn)
{
int srcu_idx, err = 0;
- pfn_t pfn;
+ kvm_pfn_t pfn;
if (kvm->arch.guest_pmap[gfn] != KVM_INVALID_PAGE)
return 0;
@@ -262,7 +262,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
struct kvm_vcpu *vcpu)
{
gfn_t gfn;
- pfn_t pfn0, pfn1;
+ kvm_pfn_t pfn0, pfn1;
unsigned long vaddr = 0;
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
int even;
@@ -313,7 +313,7 @@ EXPORT_SYMBOL(kvm_mips_handle_kseg0_tlb_fault);
int kvm_mips_handle_commpage_tlb_fault(unsigned long badvaddr,
struct kvm_vcpu *vcpu)
{
- pfn_t pfn0, pfn1;
+ kvm_pfn_t pfn0, pfn1;
unsigned long flags, old_entryhi = 0, vaddr = 0;
unsigned long entrylo0 = 0, entrylo1 = 0;
@@ -360,7 +360,7 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
{
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
struct kvm *kvm = vcpu->kvm;
- pfn_t pfn0, pfn1;
+ kvm_pfn_t pfn0, pfn1;
if ((tlb->tlb_hi & VPN2_MASK) == 0) {
pfn0 = 0;
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 5d3a25e1cfae..caac3d747a90 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -587,7 +587,8 @@ static inline void local_r4k_flush_cache_page(void *args)
* another ASID than the current one.
*/
map_coherent = (cpu_has_dc_aliases &&
- page_mapped(page) && !Page_dcache_dirty(page));
+ page_mapcount(page) &&
+ !Page_dcache_dirty(page));
if (map_coherent)
vaddr = kmap_coherent(page, addr);
else
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index aab218c36e0d..3f159caf6dbc 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -106,7 +106,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
unsigned long addr = (unsigned long) page_address(page);
if (pages_do_alias(addr, vmaddr)) {
- if (page_mapped(page) && !Page_dcache_dirty(page)) {
+ if (page_mapcount(page) && !Page_dcache_dirty(page)) {
void *kaddr;
kaddr = kmap_coherent(page, vmaddr);
diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
index 349995d19c7f..1afd87c999b0 100644
--- a/arch/mips/mm/gup.c
+++ b/arch/mips/mm/gup.c
@@ -87,8 +87,6 @@ static int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end,
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
- if (PageTail(page))
- get_huge_page_tail(page);
(*nr)++;
page++;
refs++;
@@ -109,18 +107,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmd_t pmd = *pmdp;
next = pmd_addr_end(addr, end);
- /*
- * The pmd_trans_splitting() check below explains why
- * pmdp_splitting_flush has to flush the tlb, to stop
- * this gup-fast code from running while we set the
- * splitting bit in the pmd. Returning zero will take
- * the slow path that will call wait_split_huge_page()
- * if the pmd is still in splitting state. gup-fast
- * can't because it has irq disabled and
- * wait_split_huge_page() would never return as the
- * tlb flush IPI wouldn't run.
- */
- if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+ if (pmd_none(pmd))
return 0;
if (unlikely(pmd_huge(pmd))) {
if (!gup_huge_pmd(pmd, addr, next, write, pages,nr))
@@ -153,8 +140,6 @@ static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end,
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
- if (PageTail(page))
- get_huge_page_tail(page);
(*nr)++;
page++;
refs++;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 8770e619185e..7e5fa0938c21 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -165,7 +165,7 @@ void copy_user_highpage(struct page *to, struct page *from,
vto = kmap_atomic(to);
if (cpu_has_dc_aliases &&
- page_mapped(from) && !Page_dcache_dirty(from)) {
+ page_mapcount(from) && !Page_dcache_dirty(from)) {
vfrom = kmap_coherent(from, vaddr);
copy_page(vto, vfrom);
kunmap_coherent();
@@ -187,7 +187,7 @@ void copy_to_user_page(struct vm_area_struct *vma,
unsigned long len)
{
if (cpu_has_dc_aliases &&
- page_mapped(page) && !Page_dcache_dirty(page)) {
+ page_mapcount(page) && !Page_dcache_dirty(page)) {
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(vto, src, len);
kunmap_coherent();
@@ -205,7 +205,7 @@ void copy_from_user_page(struct vm_area_struct *vma,
unsigned long len)
{
if (cpu_has_dc_aliases &&
- page_mapped(page) && !Page_dcache_dirty(page)) {
+ page_mapcount(page) && !Page_dcache_dirty(page)) {
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(dst, vfrom, len);
kunmap_coherent();
diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c
index e8adc0069d66..ce4473e7c0d2 100644
--- a/arch/mips/mm/pgtable-64.c
+++ b/arch/mips/mm/pgtable-64.c
@@ -62,20 +62,6 @@ void pmd_init(unsigned long addr, unsigned long pagetable)
}
#endif
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-
-void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long address,
- pmd_t *pmdp)
-{
- if (!pmd_trans_splitting(*pmdp)) {
- pmd_t pmd = pmd_mksplitting(*pmdp);
- set_pmd_at(vma->vm_mm, address, pmdp, pmd);
- }
-}
-
-#endif
-
pmd_t mk_pmd(struct page *page, pgprot_t prot)
{
pmd_t pmd;
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 32e0be27673f..482192cc8f2b 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -240,7 +240,6 @@ static void output_pgtable_bits_defines(void)
pr_define("_PAGE_MODIFIED_SHIFT %d\n", _PAGE_MODIFIED_SHIFT);
#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT);
- pr_define("_PAGE_SPLITTING_SHIFT %d\n", _PAGE_SPLITTING_SHIFT);
#endif
#ifdef CONFIG_CPU_MIPSR2
if (cpu_has_rixi) {
diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c
index b4b774bc3178..3cd357737a26 100644
--- a/arch/mips/pnx833x/common/platform.c
+++ b/arch/mips/pnx833x/common/platform.c
@@ -180,7 +180,7 @@ static struct platform_device pnx833x_sata_device = {
static void
pnx833x_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
if (cmd == NAND_CMD_NONE)
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
index 9bd7a2de0765..0966adccf520 100644
--- a/arch/mips/rb532/devices.c
+++ b/arch/mips/rb532/devices.c
@@ -148,7 +148,7 @@ static int rb532_dev_ready(struct mtd_info *mtd)
static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
unsigned char orbits, nandbits;
if (ctrl & NAND_CTRL_CHANGE) {
diff --git a/arch/mn10300/include/asm/page.h b/arch/mn10300/include/asm/page.h
index 8288e124165b..3810a6f740fd 100644
--- a/arch/mn10300/include/asm/page.h
+++ b/arch/mn10300/include/asm/page.h
@@ -107,6 +107,7 @@ static inline int get_order(unsigned long size)
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define pfn_to_page(pfn) (mem_map + ((pfn) - __pfn_disp))
#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + __pfn_disp)
+#define __pfn_to_phys(pfn) PFN_PHYS(pfn)
#define pfn_valid(pfn) \
({ \
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 729f89163bc3..7c34cafdf301 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -79,9 +79,6 @@ config TIME_LOW_RES
depends on SMP
default y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
# unless you want to implement ACPI on PA-RISC ... ;-)
config PM
bool
diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h
index 7d56a9ccb752..a65d888716c4 100644
--- a/arch/parisc/include/asm/hugetlb.h
+++ b/arch/parisc/include/asm/hugetlb.h
@@ -54,24 +54,12 @@ static inline pte_t huge_pte_wrprotect(pte_t pte)
return pte_wrprotect(pte);
}
-static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- pte_t old_pte = *ptep;
- set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
-}
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep);
-static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep,
- pte_t pte, int dirty)
-{
- int changed = !pte_same(*ptep, pte);
- if (changed) {
- set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
- flush_tlb_page(vma, addr);
- }
- return changed;
-}
+ pte_t pte, int dirty);
static inline pte_t huge_ptep_get(pte_t *ptep)
{
diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index 71889ea72740..89c53bfff055 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -167,6 +167,7 @@ static inline void pcibios_register_hba(struct pci_hba_data *x)
{
}
#endif
+extern void pcibios_init_bridge(struct pci_dev *);
/*
* pcibios_assign_all_busses() is used in drivers/pci/pci.c:pci_do_scan_bus()
diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h
index 7eb616e4bf8a..451906d78136 100644
--- a/arch/parisc/include/asm/pdc.h
+++ b/arch/parisc/include/asm/pdc.h
@@ -63,7 +63,7 @@ struct pdc_tlb_cf { /* for PDC_CACHE (I/D-TLB's) */
tc_page : 1, /* 0 = 2K page-size-machine, 1 = 4k page size */
tc_cst : 3, /* 0 = incoherent operations, else coherent operations */
tc_aid : 5, /* ITLB: width of access ids of processor (encoded!) */
- tc_pad1 : 8; /* ITLB: width of space-registers (encoded) */
+ tc_sr : 8; /* ITLB: width of space-registers (encoded) */
};
struct pdc_cache_info { /* main-PDC_CACHE-structure (caches & TLB's) */
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index 7e759ecb1343..2e674e13e005 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -311,18 +311,17 @@ extern unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
#define cpu_relax_lowlatency() cpu_relax()
-/* Used as a macro to identify the combined VIPT/PIPT cached
- * CPUs which require a guarantee of coherency (no inequivalent
- * aliases with different data, whether clean or not) to operate */
-static inline int parisc_requires_coherency(void)
-{
+/*
+ * parisc_requires_coherency() is used to identify the combined VIPT/PIPT
+ * cached CPUs which require a guarantee of coherency (no inequivalent aliases
+ * with different data, whether clean or not) to operate
+ */
#ifdef CONFIG_PA8X00
- return (boot_cpu_data.cpu_type == mako) ||
- (boot_cpu_data.cpu_type == mako2);
+extern int _parisc_requires_coherency;
+#define parisc_requires_coherency() _parisc_requires_coherency
#else
- return 0;
+#define parisc_requires_coherency() (0)
#endif
-}
#endif /* __ASSEMBLY__ */
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
index dd4d1876a020..cf830d465f75 100644
--- a/arch/parisc/include/uapi/asm/mman.h
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -43,8 +43,10 @@
#define MADV_SPACEAVAIL 5 /* insure that resources are reserved */
#define MADV_VPS_PURGE 6 /* Purge pages from VM page cache */
#define MADV_VPS_INHERIT 7 /* Inherit parents page size */
+#define MADV_FREE 8 /* free pages only if memory pressure */
/* common/generic parameters */
+#define MADV_FREE 8 /* free pages only if memory pressure */
#define MADV_REMOVE 9 /* remove these pages & resources */
#define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */
diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h
index d7034728f377..8fd10f85c50e 100644
--- a/arch/parisc/include/uapi/asm/siginfo.h
+++ b/arch/parisc/include/uapi/asm/siginfo.h
@@ -1,9 +1,10 @@
#ifndef _PARISC_SIGINFO_H
#define _PARISC_SIGINFO_H
-#include <asm-generic/siginfo.h>
+#if defined(__LP64__)
+#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#endif
-#undef NSIGTRAP
-#define NSIGTRAP 4
+#include <asm-generic/siginfo.h>
#endif
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index cda6dbbe9842..91c2a39cd5aa 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -172,6 +172,24 @@ parisc_cache_init(void)
cache_info.ic_count,
cache_info.ic_loop);
+ printk("IT base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx off_base 0x%lx off_stride 0x%lx off_count 0x%lx\n",
+ cache_info.it_sp_base,
+ cache_info.it_sp_stride,
+ cache_info.it_sp_count,
+ cache_info.it_loop,
+ cache_info.it_off_base,
+ cache_info.it_off_stride,
+ cache_info.it_off_count);
+
+ printk("DT base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx off_base 0x%lx off_stride 0x%lx off_count 0x%lx\n",
+ cache_info.dt_sp_base,
+ cache_info.dt_sp_stride,
+ cache_info.dt_sp_count,
+ cache_info.dt_loop,
+ cache_info.dt_off_base,
+ cache_info.dt_off_stride,
+ cache_info.dt_off_count);
+
printk("ic_conf = 0x%lx alias %d blk %d line %d shift %d\n",
*(unsigned long *) (&cache_info.ic_conf),
cache_info.ic_conf.cc_alias,
@@ -184,19 +202,19 @@ parisc_cache_init(void)
cache_info.ic_conf.cc_cst,
cache_info.ic_conf.cc_hv);
- printk("D-TLB conf: sh %d page %d cst %d aid %d pad1 %d\n",
+ printk("D-TLB conf: sh %d page %d cst %d aid %d sr %d\n",
cache_info.dt_conf.tc_sh,
cache_info.dt_conf.tc_page,
cache_info.dt_conf.tc_cst,
cache_info.dt_conf.tc_aid,
- cache_info.dt_conf.tc_pad1);
+ cache_info.dt_conf.tc_sr);
- printk("I-TLB conf: sh %d page %d cst %d aid %d pad1 %d\n",
+ printk("I-TLB conf: sh %d page %d cst %d aid %d sr %d\n",
cache_info.it_conf.tc_sh,
cache_info.it_conf.tc_page,
cache_info.it_conf.tc_cst,
cache_info.it_conf.tc_aid,
- cache_info.it_conf.tc_pad1);
+ cache_info.it_conf.tc_sr);
#endif
split_tlb = 0;
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index 3c63a820fcda..b9d75d9fa9ac 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -42,9 +42,9 @@
* We are not doing SEGREL32 handling correctly. According to the ABI, we
* should do a value offset, like this:
* if (in_init(me, (void *)val))
- * val -= (uint32_t)me->module_init;
+ * val -= (uint32_t)me->init_layout.base;
* else
- * val -= (uint32_t)me->module_core;
+ * val -= (uint32_t)me->core_layout.base;
* However, SEGREL32 is used only for PARISC unwind entries, and we want
* those entries to have an absolute address, and not just an offset.
*
@@ -100,14 +100,14 @@
* or init pieces the location is */
static inline int in_init(struct module *me, void *loc)
{
- return (loc >= me->module_init &&
- loc <= (me->module_init + me->init_size));
+ return (loc >= me->init_layout.base &&
+ loc <= (me->init_layout.base + me->init_layout.size));
}
static inline int in_core(struct module *me, void *loc)
{
- return (loc >= me->module_core &&
- loc <= (me->module_core + me->core_size));
+ return (loc >= me->core_layout.base &&
+ loc <= (me->core_layout.base + me->core_layout.size));
}
static inline int in_local(struct module *me, void *loc)
@@ -367,13 +367,13 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
}
/* align things a bit */
- me->core_size = ALIGN(me->core_size, 16);
- me->arch.got_offset = me->core_size;
- me->core_size += gots * sizeof(struct got_entry);
+ me->core_layout.size = ALIGN(me->core_layout.size, 16);
+ me->arch.got_offset = me->core_layout.size;
+ me->core_layout.size += gots * sizeof(struct got_entry);
- me->core_size = ALIGN(me->core_size, 16);
- me->arch.fdesc_offset = me->core_size;
- me->core_size += fdescs * sizeof(Elf_Fdesc);
+ me->core_layout.size = ALIGN(me->core_layout.size, 16);
+ me->arch.fdesc_offset = me->core_layout.size;
+ me->core_layout.size += fdescs * sizeof(Elf_Fdesc);
me->arch.got_max = gots;
me->arch.fdesc_max = fdescs;
@@ -391,7 +391,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
BUG_ON(value == 0);
- got = me->module_core + me->arch.got_offset;
+ got = me->core_layout.base + me->arch.got_offset;
for (i = 0; got[i].addr; i++)
if (got[i].addr == value)
goto out;
@@ -409,7 +409,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
#ifdef CONFIG_64BIT
static Elf_Addr get_fdesc(struct module *me, unsigned long value)
{
- Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset;
+ Elf_Fdesc *fdesc = me->core_layout.base + me->arch.fdesc_offset;
if (!value) {
printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
@@ -427,7 +427,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
/* Create new one */
fdesc->addr = value;
- fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset;
+ fdesc->gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
return (Elf_Addr)fdesc;
}
#endif /* CONFIG_64BIT */
@@ -839,7 +839,7 @@ register_unwind_table(struct module *me,
table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
end = table + sechdrs[me->arch.unwind_section].sh_size;
- gp = (Elf_Addr)me->module_core + me->arch.got_offset;
+ gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
me->arch.unwind_section, table, end, gp);
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index c99f3dde455c..0903c6abd7a4 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -170,6 +170,32 @@ void pcibios_set_master(struct pci_dev *dev)
(0x80 << 8) | pci_cache_line_size);
}
+/*
+ * pcibios_init_bridge() initializes cache line and default latency
+ * for pci controllers and pci-pci bridges
+ */
+void __init pcibios_init_bridge(struct pci_dev *dev)
+{
+ unsigned short bridge_ctl, bridge_ctl_new;
+
+ /* We deal only with pci controllers and pci-pci bridges. */
+ if (!dev || (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+
+ /* PCI-PCI bridge - set the cache line and default latency
+ * (32) for primary and secondary buses.
+ */
+ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
+
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bridge_ctl);
+
+ bridge_ctl_new = bridge_ctl | PCI_BRIDGE_CTL_PARITY |
+ PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_MASTER_ABORT;
+ dev_info(&dev->dev, "Changing bridge control from 0x%08x to 0x%08x\n",
+ bridge_ctl, bridge_ctl_new);
+
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl_new);
+}
/*
* pcibios align resources() is called every time generic PCI code
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
index b68d977ce30f..e81ccf1716e9 100644
--- a/arch/parisc/kernel/processor.c
+++ b/arch/parisc/kernel/processor.c
@@ -44,6 +44,10 @@
struct system_cpuinfo_parisc boot_cpu_data __read_mostly;
EXPORT_SYMBOL(boot_cpu_data);
+#ifdef CONFIG_PA8X00
+int _parisc_requires_coherency __read_mostly;
+EXPORT_SYMBOL(_parisc_requires_coherency);
+#endif
DEFINE_PER_CPU(struct cpuinfo_parisc, cpu_data);
@@ -277,8 +281,12 @@ void __init collect_boot_cpu_data(void)
boot_cpu_data.cpu_type = parisc_get_cpu_type(boot_cpu_data.hversion);
boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
-}
+#ifdef CONFIG_PA8X00
+ _parisc_requires_coherency = (boot_cpu_data.cpu_type == mako) ||
+ (boot_cpu_data.cpu_type == mako2);
+#endif
+}
/**
diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c
index f6fdc77a72bd..54ba39262b82 100644
--- a/arch/parisc/mm/hugetlbpage.c
+++ b/arch/parisc/mm/hugetlbpage.c
@@ -105,15 +105,13 @@ static inline void purge_tlb_entries_huge(struct mm_struct *mm, unsigned long ad
addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT;
for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) {
- mtsp(mm->context, 1);
- pdtlb(addr);
- if (unlikely(split_tlb))
- pitlb(addr);
+ purge_tlb_entries(mm, addr);
addr += (1UL << REAL_HPAGE_SHIFT);
}
}
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+/* __set_huge_pte_at() must be called holding the pa_tlb_lock. */
+static void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t entry)
{
unsigned long addr_start;
@@ -123,14 +121,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
addr_start = addr;
for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- /* Directly write pte entry. We could call set_pte_at(mm, addr, ptep, entry)
- * instead, but then we get double locking on pa_tlb_lock. */
- *ptep = entry;
+ set_pte(ptep, entry);
ptep++;
- /* Drop the PAGE_SIZE/non-huge tlb entry */
- purge_tlb_entries(mm, addr);
-
addr += PAGE_SIZE;
pte_val(entry) += PAGE_SIZE;
}
@@ -138,18 +131,61 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
purge_tlb_entries_huge(mm, addr_start);
}
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry)
+{
+ unsigned long flags;
+
+ purge_tlb_start(flags);
+ __set_huge_pte_at(mm, addr, ptep, entry);
+ purge_tlb_end(flags);
+}
+
pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
+ unsigned long flags;
pte_t entry;
+ purge_tlb_start(flags);
entry = *ptep;
- set_huge_pte_at(mm, addr, ptep, __pte(0));
+ __set_huge_pte_at(mm, addr, ptep, __pte(0));
+ purge_tlb_end(flags);
return entry;
}
+
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ unsigned long flags;
+ pte_t old_pte;
+
+ purge_tlb_start(flags);
+ old_pte = *ptep;
+ __set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+ purge_tlb_end(flags);
+}
+
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ unsigned long flags;
+ int changed;
+
+ purge_tlb_start(flags);
+ changed = !pte_same(*ptep, pte);
+ if (changed) {
+ __set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+ }
+ purge_tlb_end(flags);
+ return changed;
+}
+
+
int pmd_huge(pmd_t pmd)
{
return 0;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index db49e0d796b1..94f6c5089e0c 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -47,9 +47,6 @@ config STACKTRACE_SUPPORT
bool
default y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config TRACE_IRQFLAGS_SUPPORT
bool
default y
@@ -159,6 +156,7 @@ config PPC
select EDAC_SUPPORT
select EDAC_ATOMIC_SCRUB
select ARCH_HAS_DMA_SET_COHERENT_MASK
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select HAVE_ARCH_SECCOMP_FILTER
config GENERIC_CSUM
@@ -559,6 +557,7 @@ choice
config PPC_4K_PAGES
bool "4k page size"
+ select HAVE_ARCH_SOFT_DIRTY if CHECKPOINT_RESTORE && PPC_BOOK3S
config PPC_16K_PAGES
bool "16k page size"
@@ -567,6 +566,7 @@ config PPC_16K_PAGES
config PPC_64K_PAGES
bool "64k page size"
depends on !PPC_FSL_BOOK3E && (44x || PPC_STD_MMU_64 || PPC_BOOK3E_64)
+ select HAVE_ARCH_SOFT_DIRTY if CHECKPOINT_RESTORE && PPC_BOOK3S
config PPC_256K_PAGES
bool "256k page size"
@@ -1074,8 +1074,6 @@ source "drivers/Kconfig"
source "fs/Kconfig"
-source "arch/powerpc/sysdev/qe_lib/Kconfig"
-
source "lib/Kconfig"
source "arch/powerpc/Kconfig.debug"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 3a510f4a6b68..638f9ce740f5 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -64,17 +64,17 @@ config PPC_EMULATED_STATS
emulated.
config CODE_PATCHING_SELFTEST
- bool "Run self-tests of the code-patching code."
+ bool "Run self-tests of the code-patching code"
depends on DEBUG_KERNEL
default n
config FTR_FIXUP_SELFTEST
- bool "Run self-tests of the feature-fixup code."
+ bool "Run self-tests of the feature-fixup code"
depends on DEBUG_KERNEL
default n
config MSI_BITMAP_SELFTEST
- bool "Run self-tests of the MSI bitmap code."
+ bool "Run self-tests of the MSI bitmap code"
depends on DEBUG_KERNEL
default n
@@ -335,18 +335,6 @@ config PPC_EARLY_DEBUG_CPM_ADDR
platform probing is done, all platforms selected must
share the same address.
-config STRICT_DEVMEM
- def_bool y
- prompt "Filter access to /dev/mem"
- help
- This option restricts access to /dev/mem. If this option is
- disabled, you allow userspace access to all memory, including
- kernel and userspace memory. Accidental memory access is likely
- to be disastrous.
- Memory access is required for experts who want to debug the kernel.
-
- If you are unsure, say Y.
-
config FAIL_IOMMU
bool "Fault-injection capability for IOMMU"
depends on FAULT_INJECTION
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 99e4487248ff..61165101342c 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -113,7 +113,6 @@ src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c
src-plat-$(CONFIG_PPC_PSERIES) += pseries-head.S
src-plat-$(CONFIG_PPC_POWERNV) += pseries-head.S
src-plat-$(CONFIG_PPC_IBM_CELL_BLADE) += pseries-head.S
-src-plat-$(CONFIG_PPC_CELL_QPACE) += pseries-head.S
src-wlib := $(sort $(src-wlib-y))
src-plat := $(sort $(src-plat-y))
@@ -217,7 +216,6 @@ image-$(CONFIG_PPC_POWERNV) += zImage.pseries
image-$(CONFIG_PPC_MAPLE) += zImage.maple
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
image-$(CONFIG_PPC_PS3) += dtbImage.ps3
-image-$(CONFIG_PPC_CELL_QPACE) += zImage.pseries
image-$(CONFIG_PPC_CHRP) += zImage.chrp
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
image-$(CONFIG_PPC_PMAC) += zImage.pmac
diff --git a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
index 74866ac52f39..1b33f5157c8a 100644
--- a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
@@ -474,6 +474,11 @@
fman@400000 {
interrupts = <96 2 0 0>, <16 2 1 30>;
+ muram@0 {
+ compatible = "fsl,fman-muram";
+ reg = <0x0 0x80000>;
+ };
+
enet0: ethernet@e0000 {
};
diff --git a/arch/powerpc/boot/dts/fsl/bsc9132qds.dts b/arch/powerpc/boot/dts/fsl/bsc9132qds.dts
index 70882ade606d..56e6f1337e96 100644
--- a/arch/powerpc/boot/dts/fsl/bsc9132qds.dts
+++ b/arch/powerpc/boot/dts/fsl/bsc9132qds.dts
@@ -29,6 +29,21 @@
soc: soc@ff700000 {
ranges = <0x0 0x0 0xff700000 0x100000>;
};
+
+ pci0: pcie@ff70a000 {
+ reg = <0 0xff70a000 0 0x1000>;
+ ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xc0010000 0x0 0x10000>;
+ pcie@0 {
+ ranges = <0x2000000 0x0 0x90000000
+ 0x2000000 0x0 0x90000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
};
/include/ "bsc9132qds.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/bsc9132si-post.dtsi b/arch/powerpc/boot/dts/fsl/bsc9132si-post.dtsi
index c72307198140..b5f071574e83 100644
--- a/arch/powerpc/boot/dts/fsl/bsc9132si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/bsc9132si-post.dtsi
@@ -40,6 +40,34 @@
interrupts = <16 2 0 0 20 2 0 0>;
};
+/* controller at 0xa000 */
+&pci0 {
+ compatible = "fsl,bsc9132-pcie", "fsl,qoriq-pcie-v2.2";
+ device_type = "pci";
+ #size-cells = <2>;
+ #address-cells = <3>;
+ bus-range = <0 255>;
+ interrupts = <16 2 0 0>;
+
+ pcie@0 {
+ reg = <0 0 0 0 0>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ interrupts = <16 2 0 0>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x0 0x2 0x0 0x0
+ 0000 0x0 0x0 0x2 &mpic 0x1 0x2 0x0 0x0
+ 0000 0x0 0x0 0x3 &mpic 0x2 0x2 0x0 0x0
+ 0000 0x0 0x0 0x4 &mpic 0x3 0x2 0x0 0x0
+ >;
+ };
+};
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/bsc9132si-pre.dtsi b/arch/powerpc/boot/dts/fsl/bsc9132si-pre.dtsi
index 301a9dba5790..90f7949fe312 100644
--- a/arch/powerpc/boot/dts/fsl/bsc9132si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/bsc9132si-pre.dtsi
@@ -45,6 +45,7 @@
serial0 = &serial0;
ethernet0 = &enet0;
ethernet1 = &enet1;
+ pci0 = &pci0;
};
cpus {
diff --git a/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi b/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi
index 0f0ced69835a..14b629505038 100644
--- a/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010rdb.dtsi
@@ -215,3 +215,19 @@
phy-connection-type = "sgmii";
};
};
+
+&pci0 {
+ pcie@0 {
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ /*
+ *irq[4:5] are active-high
+ *irq[6:7] are active-low
+ */
+ 0000 0x0 0x0 0x1 &mpic 0x4 0x2 0x0 0x0
+ 0000 0x0 0x0 0x2 &mpic 0x5 0x2 0x0 0x0
+ 0000 0x0 0x0 0x3 &mpic 0x6 0x1 0x0 0x0
+ 0000 0x0 0x0 0x4 &mpic 0x7 0x1 0x0 0x0
+ >;
+ };
+};
diff --git a/arch/powerpc/boot/dts/fsl/t1023rdb.dts b/arch/powerpc/boot/dts/fsl/t1023rdb.dts
index 2b2fff4a12a2..6bd842beb1dc 100644
--- a/arch/powerpc/boot/dts/fsl/t1023rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1023rdb.dts
@@ -159,4 +159,4 @@
};
};
-/include/ "t1023si-post.dtsi"
+#include "t1023si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
index 518ddaa8da2d..99e421df79d4 100644
--- a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
@@ -32,6 +32,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <dt-bindings/thermal/thermal.h>
+
&ifc {
#address-cells = <2>;
#size-cells = <1>;
@@ -275,6 +277,90 @@
reg = <0xea000 0x4000>;
};
+ tmu: tmu@f0000 {
+ compatible = "fsl,qoriq-tmu";
+ reg = <0xf0000 0x1000>;
+ interrupts = <18 2 0 0>;
+ fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x30061>;
+ fsl,tmu-calibration = <0x00000000 0x0000000f
+ 0x00000001 0x00000017
+ 0x00000002 0x0000001e
+ 0x00000003 0x00000026
+ 0x00000004 0x0000002e
+ 0x00000005 0x00000035
+ 0x00000006 0x0000003d
+ 0x00000007 0x00000044
+ 0x00000008 0x0000004c
+ 0x00000009 0x00000053
+ 0x0000000a 0x0000005b
+ 0x0000000b 0x00000064
+
+ 0x00010000 0x00000011
+ 0x00010001 0x0000001c
+ 0x00010002 0x00000024
+ 0x00010003 0x0000002b
+ 0x00010004 0x00000034
+ 0x00010005 0x00000039
+ 0x00010006 0x00000042
+ 0x00010007 0x0000004c
+ 0x00010008 0x00000051
+ 0x00010009 0x0000005a
+ 0x0001000a 0x00000063
+
+ 0x00020000 0x00000013
+ 0x00020001 0x00000019
+ 0x00020002 0x00000024
+ 0x00020003 0x0000002c
+ 0x00020004 0x00000035
+ 0x00020005 0x0000003d
+ 0x00020006 0x00000046
+ 0x00020007 0x00000050
+ 0x00020008 0x00000059
+
+ 0x00030000 0x00000002
+ 0x00030001 0x0000000d
+ 0x00030002 0x00000019
+ 0x00030003 0x00000024>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+
+ thermal-sensors = <&tmu>;
+
+ trips {
+ cpu_alert: cpu-alert {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit: cpu-crit {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert>;
+ cooling-device =
+ <&cpu0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ map1 {
+ trip = <&cpu_alert>;
+ cooling-device =
+ <&cpu1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+ };
+
scfg: global-utilities@fc000 {
compatible = "fsl,t1023-scfg";
reg = <0xfc000 0x1000>;
diff --git a/arch/powerpc/boot/dts/fsl/t1024qds.dts b/arch/powerpc/boot/dts/fsl/t1024qds.dts
index 43cd5b50cd0a..6a3581b8e1f8 100644
--- a/arch/powerpc/boot/dts/fsl/t1024qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024qds.dts
@@ -248,4 +248,4 @@
};
};
-/include/ "t1024si-post.dtsi"
+#include "t1024si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1024rdb.dts b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
index 429d8c73650a..0ccc7d03335e 100644
--- a/arch/powerpc/boot/dts/fsl/t1024rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
@@ -188,4 +188,4 @@
};
};
-/include/ "t1024si-post.dtsi"
+#include "t1024si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi
index 95e3af8d768e..bb480346a58d 100644
--- a/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi
@@ -32,7 +32,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/include/ "t1023si-post.dtsi"
+#include "t1023si-post.dtsi"
/ {
aliases {
diff --git a/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi b/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi
index 3e1528abf3f4..9d08a363bab3 100644
--- a/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi
@@ -76,6 +76,7 @@
reg = <0>;
clocks = <&mux0>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
};
@@ -85,6 +86,7 @@
reg = <1>;
clocks = <&mux1>;
next-level-cache = <&L2_2>;
+ #cooling-cells = <2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
};
diff --git a/arch/powerpc/boot/dts/fsl/t1040d4rdb.dts b/arch/powerpc/boot/dts/fsl/t1040d4rdb.dts
index 681746efd31d..fb6bc02ebb60 100644
--- a/arch/powerpc/boot/dts/fsl/t1040d4rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1040d4rdb.dts
@@ -43,4 +43,4 @@
interrupt-parent = <&mpic>;
};
-/include/ "t1040si-post.dtsi"
+#include "t1040si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1040qds.dts b/arch/powerpc/boot/dts/fsl/t1040qds.dts
index 4d298659468c..5f76edc7838c 100644
--- a/arch/powerpc/boot/dts/fsl/t1040qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t1040qds.dts
@@ -43,4 +43,4 @@
interrupt-parent = <&mpic>;
};
-/include/ "t1040si-post.dtsi"
+#include "t1040si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
index 8f9e65b47515..cf194154bbdc 100644
--- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
@@ -45,4 +45,4 @@
};
};
-/include/ "t1040si-post.dtsi"
+#include "t1040si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
index d30b3de1cfc5..e0f4da554774 100644
--- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
@@ -32,6 +32,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <dt-bindings/thermal/thermal.h>
+
&bman_fbpr {
compatible = "fsl,bman-fbpr";
alloc-ranges = <0 0 0x10000 0>;
@@ -484,6 +486,98 @@
reg = <0xea000 0x4000>;
};
+ tmu: tmu@f0000 {
+ compatible = "fsl,qoriq-tmu";
+ reg = <0xf0000 0x1000>;
+ interrupts = <18 2 0 0>;
+ fsl,tmu-range = <0xa0000 0x90026 0x8004a 0x1006a>;
+ fsl,tmu-calibration = <0x00000000 0x00000025
+ 0x00000001 0x00000028
+ 0x00000002 0x0000002d
+ 0x00000003 0x00000031
+ 0x00000004 0x00000036
+ 0x00000005 0x0000003a
+ 0x00000006 0x00000040
+ 0x00000007 0x00000044
+ 0x00000008 0x0000004a
+ 0x00000009 0x0000004f
+ 0x0000000a 0x00000054
+
+ 0x00010000 0x0000000d
+ 0x00010001 0x00000013
+ 0x00010002 0x00000019
+ 0x00010003 0x0000001f
+ 0x00010004 0x00000025
+ 0x00010005 0x0000002d
+ 0x00010006 0x00000033
+ 0x00010007 0x00000043
+ 0x00010008 0x0000004b
+ 0x00010009 0x00000053
+
+ 0x00020000 0x00000010
+ 0x00020001 0x00000017
+ 0x00020002 0x0000001f
+ 0x00020003 0x00000029
+ 0x00020004 0x00000031
+ 0x00020005 0x0000003c
+ 0x00020006 0x00000042
+ 0x00020007 0x0000004d
+ 0x00020008 0x00000056
+
+ 0x00030000 0x00000012
+ 0x00030001 0x0000001d>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+
+ thermal-sensors = <&tmu>;
+
+ trips {
+ cpu_alert: cpu-alert {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit: cpu-crit {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert>;
+ cooling-device =
+ <&cpu0 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ map1 {
+ trip = <&cpu_alert>;
+ cooling-device =
+ <&cpu1 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ map2 {
+ trip = <&cpu_alert>;
+ cooling-device =
+ <&cpu2 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ map3 {
+ trip = <&cpu_alert>;
+ cooling-device =
+ <&cpu3 THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+ };
+
scfg: global-utilities@fc000 {
compatible = "fsl,t1040-scfg";
reg = <0xfc000 0x1000>;
diff --git a/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts b/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts
index b245b31b8279..2a5a90dd272e 100644
--- a/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts
@@ -50,4 +50,4 @@
};
};
-/include/ "t1040si-post.dtsi"
+#include "t1042si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1042qds.dts b/arch/powerpc/boot/dts/fsl/t1042qds.dts
index 4ab9bbe7c5c5..90a4a73bb905 100644
--- a/arch/powerpc/boot/dts/fsl/t1042qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042qds.dts
@@ -43,4 +43,4 @@
interrupt-parent = <&mpic>;
};
-/include/ "t1042si-post.dtsi"
+#include "t1042si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1042rdb.dts b/arch/powerpc/boot/dts/fsl/t1042rdb.dts
index 67af56bc5ee9..8d908e795e4d 100644
--- a/arch/powerpc/boot/dts/fsl/t1042rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042rdb.dts
@@ -45,4 +45,4 @@
};
};
-/include/ "t1042si-post.dtsi"
+#include "t1042si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts b/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts
index 2f67677530a4..98c001019d6a 100644
--- a/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042rdb_pi.dts
@@ -54,4 +54,4 @@
};
};
-/include/ "t1042si-post.dtsi"
+#include "t1042si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/t1042si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1042si-post.dtsi
index 319b74f29724..a5544f93689c 100644
--- a/arch/powerpc/boot/dts/fsl/t1042si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1042si-post.dtsi
@@ -32,6 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/include/ "t1040si-post.dtsi"
+#include "t1040si-post.dtsi"
/* Place holder for ethernet related device tree nodes */
diff --git a/arch/powerpc/boot/dts/fsl/t104xsi-pre.dtsi b/arch/powerpc/boot/dts/fsl/t104xsi-pre.dtsi
index fcfa38ae5e02..6db0ee8b1384 100644
--- a/arch/powerpc/boot/dts/fsl/t104xsi-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t104xsi-pre.dtsi
@@ -76,6 +76,7 @@
reg = <0>;
clocks = <&mux0>;
next-level-cache = <&L2_1>;
+ #cooling-cells = <2>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
};
@@ -85,6 +86,7 @@
reg = <1>;
clocks = <&mux1>;
next-level-cache = <&L2_2>;
+ #cooling-cells = <2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
};
@@ -94,6 +96,7 @@
reg = <2>;
clocks = <&mux2>;
next-level-cache = <&L2_3>;
+ #cooling-cells = <2>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
};
@@ -103,6 +106,7 @@
reg = <3>;
clocks = <&mux3>;
next-level-cache = <&L2_4>;
+ #cooling-cells = <2>;
L2_4: l2-cache {
next-level-cache = <&cpc>;
};
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index ceaa75d5a684..6a19fcef5596 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -154,7 +154,7 @@ if [ -z "$kernel" ]; then
kernel=vmlinux
fi
-elfformat="`${CROSS}objdump -p "$kernel" | grep 'file format' | awk '{print $4}'`"
+LANG=C elfformat="`${CROSS}objdump -p "$kernel" | grep 'file format' | awk '{print $4}'`"
case "$elfformat" in
elf64-powerpcle) format=elf64lppc ;;
elf64-powerpc) format=elf32ppc ;;
diff --git a/arch/powerpc/configs/mpc85xx_basic_defconfig b/arch/powerpc/configs/mpc85xx_basic_defconfig
index 850bd195d0e8..b1593fe6f70b 100644
--- a/arch/powerpc/configs/mpc85xx_basic_defconfig
+++ b/arch/powerpc/configs/mpc85xx_basic_defconfig
@@ -12,6 +12,7 @@ CONFIG_P1010_RDB=y
CONFIG_P1022_DS=y
CONFIG_P1022_RDK=y
CONFIG_P1023_RDB=y
+CONFIG_TWR_P102x=y
CONFIG_SBC8548=y
CONFIG_SOCRATES=y
CONFIG_STX_GP3=y
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 2c041b535a64..b041fb607376 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -36,7 +36,6 @@ CONFIG_PS3_ROM=m
CONFIG_PS3_FLASH=m
CONFIG_PS3_LPM=m
CONFIG_PPC_IBM_CELL_BLADE=y
-CONFIG_PPC_CELL_QPACE=y
CONFIG_RTAS_FLASH=m
CONFIG_IBMEBUS=y
CONFIG_CPU_FREQ_PMAC64=y
diff --git a/arch/powerpc/crypto/aes-spe-glue.c b/arch/powerpc/crypto/aes-spe-glue.c
index bd5e63f72ad4..93ee046d12cd 100644
--- a/arch/powerpc/crypto/aes-spe-glue.c
+++ b/arch/powerpc/crypto/aes-spe-glue.c
@@ -85,6 +85,7 @@ static void spe_begin(void)
static void spe_end(void)
{
+ disable_kernel_spe();
/* reenable preemption */
preempt_enable();
}
diff --git a/arch/powerpc/crypto/sha1-spe-glue.c b/arch/powerpc/crypto/sha1-spe-glue.c
index 3e1d22212521..f9ebc38d3fe7 100644
--- a/arch/powerpc/crypto/sha1-spe-glue.c
+++ b/arch/powerpc/crypto/sha1-spe-glue.c
@@ -46,6 +46,7 @@ static void spe_begin(void)
static void spe_end(void)
{
+ disable_kernel_spe();
/* reenable preemption */
preempt_enable();
}
diff --git a/arch/powerpc/crypto/sha256-spe-glue.c b/arch/powerpc/crypto/sha256-spe-glue.c
index f4a616fe1a82..718a079dcdbf 100644
--- a/arch/powerpc/crypto/sha256-spe-glue.c
+++ b/arch/powerpc/crypto/sha256-spe-glue.c
@@ -47,6 +47,7 @@ static void spe_begin(void)
static void spe_end(void)
{
+ disable_kernel_spe();
/* reenable preemption */
preempt_enable();
}
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
index a7af5fb7b914..c0deafc212b8 100644
--- a/arch/powerpc/include/asm/barrier.h
+++ b/arch/powerpc/include/asm/barrier.h
@@ -34,8 +34,6 @@
#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
-
#ifdef __SUBARCH_HAS_LWSYNC
# define SMPWMB LWSYNC
#else
@@ -46,22 +44,11 @@
#define dma_rmb() __lwsync()
#define dma_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
-#ifdef CONFIG_SMP
-#define smp_lwsync() __lwsync()
-
-#define smp_mb() mb()
-#define smp_rmb() __lwsync()
-#define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
-#else
-#define smp_lwsync() barrier()
+#define __smp_lwsync() __lwsync()
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#endif /* CONFIG_SMP */
-
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
+#define __smp_mb() mb()
+#define __smp_rmb() __lwsync()
+#define __smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
/*
* This is a barrier which prevents following instructions from being
@@ -72,23 +59,23 @@
#define data_barrier(x) \
asm volatile("twi 0,%0,0; isync" : : "r" (x) : "memory");
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
- smp_lwsync(); \
+ __smp_lwsync(); \
WRITE_ONCE(*p, v); \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
- smp_lwsync(); \
+ __smp_lwsync(); \
___p1; \
})
-#define smp_mb__before_atomic() smp_mb()
-#define smp_mb__after_atomic() smp_mb()
#define smp_mb__before_spinlock() smp_mb()
+#include <asm-generic/barrier.h>
+
#endif /* _ASM_POWERPC_BARRIER_H */
diff --git a/arch/powerpc/include/asm/pte-hash32.h b/arch/powerpc/include/asm/book3s/32/hash.h
index 62cfb0c663bb..264b754d65b0 100644
--- a/arch/powerpc/include/asm/pte-hash32.h
+++ b/arch/powerpc/include/asm/book3s/32/hash.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PTE_HASH32_H
-#define _ASM_POWERPC_PTE_HASH32_H
+#ifndef _ASM_POWERPC_BOOK3S_32_HASH_H
+#define _ASM_POWERPC_BOOK3S_32_HASH_H
#ifdef __KERNEL__
/*
@@ -43,4 +43,4 @@
#define PTE_ATOMIC_UPDATES 1
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_HASH32_H */
+#endif /* _ASM_POWERPC_BOOK3S_32_HASH_H */
diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
new file mode 100644
index 000000000000..38b33dcfcc9d
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -0,0 +1,482 @@
+#ifndef _ASM_POWERPC_BOOK3S_32_PGTABLE_H
+#define _ASM_POWERPC_BOOK3S_32_PGTABLE_H
+
+#include <asm-generic/pgtable-nopmd.h>
+
+#include <asm/book3s/32/hash.h>
+
+/* And here we include common definitions */
+#include <asm/pte-common.h>
+
+/*
+ * The normal case is that PTEs are 32-bits and we have a 1-page
+ * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages. -- paulus
+ *
+ * For any >32-bit physical address platform, we can use the following
+ * two level page table layout where the pgdir is 8KB and the MS 13 bits
+ * are an index to the second level table. The combined pgdir/pmd first
+ * level has 2048 entries and the second level has 512 64-bit PTE entries.
+ * -Matt
+ */
+/* PGDIR_SHIFT determines what a top-level page table entry can map */
+#define PGDIR_SHIFT (PAGE_SHIFT + PTE_SHIFT)
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+#define PTRS_PER_PTE (1 << PTE_SHIFT)
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT))
+
+#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
+/*
+ * This is the bottom of the PKMAP area with HIGHMEM or an arbitrary
+ * value (for now) on others, from where we can start layout kernel
+ * virtual space that goes below PKMAP and FIXMAP
+ */
+#ifdef CONFIG_HIGHMEM
+#define KVIRT_TOP PKMAP_BASE
+#else
+#define KVIRT_TOP (0xfe000000UL) /* for now, could be FIXMAP_BASE ? */
+#endif
+
+/*
+ * ioremap_bot starts at that address. Early ioremaps move down from there,
+ * until mem_init() at which point this becomes the top of the vmalloc
+ * and ioremap space
+ */
+#ifdef CONFIG_NOT_COHERENT_CACHE
+#define IOREMAP_TOP ((KVIRT_TOP - CONFIG_CONSISTENT_SIZE) & PAGE_MASK)
+#else
+#define IOREMAP_TOP KVIRT_TOP
+#endif
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 16MB value just means that there will be a 64MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ *
+ * We no longer map larger than phys RAM with the BATs so we don't have
+ * to worry about the VMALLOC_OFFSET causing problems. We do have to worry
+ * about clashes between our early calls to ioremap() that start growing down
+ * from ioremap_base being run into the VM area allocations (growing upwards
+ * from VMALLOC_START). For this reason we have ioremap_bot to check when
+ * we actually run into our mappings setup in the early boot with the VM
+ * system. This really does become a problem for machines with good amounts
+ * of RAM. -- Cort
+ */
+#define VMALLOC_OFFSET (0x1000000) /* 16M */
+#ifdef PPC_PIN_SIZE
+#define VMALLOC_START (((_ALIGN((long)high_memory, PPC_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#else
+#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#endif
+#define VMALLOC_END ioremap_bot
+
+#ifndef __ASSEMBLY__
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/io.h> /* For sub-arch specific PPC_PIN_SIZE */
+
+extern unsigned long ioremap_bot;
+
+/*
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
+ */
+#define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_SHIFT)
+#define PGD_TABLE_SIZE (sizeof(pgd_t) << (32 - PGDIR_SHIFT))
+
+#define pte_ERROR(e) \
+ pr_err("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
+ (unsigned long long)pte_val(e))
+#define pgd_ERROR(e) \
+ pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+/*
+ * Bits in a linux-style PTE. These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+
+#define pte_clear(mm, addr, ptep) \
+ do { pte_update(ptep, ~_PAGE_HASHPTE, 0); } while (0)
+
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
+#define pmd_present(pmd) (pmd_val(pmd) & _PMD_PRESENT_MASK)
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ *pmdp = __pmd(0);
+}
+
+
+/*
+ * When flushing the tlb entry for a page, we also need to flush the hash
+ * table entry. flush_hash_pages is assembler (for speed) in hashtable.S.
+ */
+extern int flush_hash_pages(unsigned context, unsigned long va,
+ unsigned long pmdval, int count);
+
+/* Add an HPTE to the hash table */
+extern void add_hash_page(unsigned context, unsigned long va,
+ unsigned long pmdval);
+
+/* Flush an entry from the TLB/hash table */
+extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep,
+ unsigned long address);
+
+/*
+ * PTE updates. This function is called whenever an existing
+ * valid PTE is updated. This does -not- include set_pte_at()
+ * which nowadays only sets a new PTE.
+ *
+ * Depending on the type of MMU, we may need to use atomic updates
+ * and the PTE may be either 32 or 64 bit wide. In the later case,
+ * when using atomic updates, only the low part of the PTE is
+ * accessed atomically.
+ *
+ * In addition, on 44x, we also maintain a global flag indicating
+ * that an executable user mapping was modified, which is needed
+ * to properly flush the virtually tagged instruction cache of
+ * those implementations.
+ */
+#ifndef CONFIG_PTE_64BIT
+static inline unsigned long pte_update(pte_t *p,
+ unsigned long clr,
+ unsigned long set)
+{
+ unsigned long old, tmp;
+
+ __asm__ __volatile__("\
+1: lwarx %0,0,%3\n\
+ andc %1,%0,%4\n\
+ or %1,%1,%5\n"
+ PPC405_ERR77(0,%3)
+" stwcx. %1,0,%3\n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*p)
+ : "r" (p), "r" (clr), "r" (set), "m" (*p)
+ : "cc" );
+
+ return old;
+}
+#else /* CONFIG_PTE_64BIT */
+static inline unsigned long long pte_update(pte_t *p,
+ unsigned long clr,
+ unsigned long set)
+{
+ unsigned long long old;
+ unsigned long tmp;
+
+ __asm__ __volatile__("\
+1: lwarx %L0,0,%4\n\
+ lwzx %0,0,%3\n\
+ andc %1,%L0,%5\n\
+ or %1,%1,%6\n"
+ PPC405_ERR77(0,%3)
+" stwcx. %1,0,%4\n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*p)
+ : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p)
+ : "cc" );
+
+ return old;
+}
+#endif /* CONFIG_PTE_64BIT */
+
+/*
+ * 2.6 calls this without flushing the TLB entry; this is wrong
+ * for our hash-based implementation, we fix that up here.
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int __ptep_test_and_clear_young(unsigned int context, unsigned long addr, pte_t *ptep)
+{
+ unsigned long old;
+ old = pte_update(ptep, _PAGE_ACCESSED, 0);
+ if (old & _PAGE_HASHPTE) {
+ unsigned long ptephys = __pa(ptep) & PAGE_MASK;
+ flush_hash_pages(context, addr, ptephys, 1);
+ }
+ return (old & _PAGE_ACCESSED) != 0;
+}
+#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
+ __ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0));
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), _PAGE_RO);
+}
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
+{
+ unsigned long set = pte_val(entry) &
+ (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
+ unsigned long clr = ~pte_val(entry) & _PAGE_RO;
+
+ pte_update(ptep, clr, set);
+}
+
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
+
+/*
+ * Note that on Book E processors, the pmd contains the kernel virtual
+ * (lowmem) address of the pte page. The physical address is less useful
+ * because everything runs with translation enabled (even the TLB miss
+ * handler). On everything else the pmd contains the physical address
+ * of the pte page. -- paulus
+ */
+#ifndef CONFIG_BOOKE
+#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) \
+ pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
+#else
+#define pmd_page_vaddr(pmd) \
+ ((unsigned long) (pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) \
+ pfn_to_page((__pa(pmd_val(pmd)) >> PAGE_SHIFT))
+#endif
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+
+/* Find an entry in the third-level page table.. */
+#define pte_index(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, addr) \
+ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
+#define pte_offset_map(dir, addr) \
+ ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
+#define pte_unmap(pte) kunmap_atomic(pte)
+
+/*
+ * Encode and decode a swap entry.
+ * Note that the bits we use in a PTE for representing a swap entry
+ * must not include the _PAGE_PRESENT bit or the _PAGE_HASHPTE bit (if used).
+ * -- paulus
+ */
+#define __swp_type(entry) ((entry).val & 0x1f)
+#define __swp_offset(entry) ((entry).val >> 5)
+#define __swp_entry(type, offset) ((swp_entry_t) { (type) | ((offset) << 5) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 3 })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val << 3 })
+
+#ifndef CONFIG_PPC_4K_PAGES
+void pgtable_cache_init(void);
+#else
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init() do { } while (0)
+#endif
+
+extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep,
+ pmd_t **pmdp);
+
+/* Generic accessors to PTE bits */
+static inline int pte_write(pte_t pte) { return !!(pte_val(pte) & _PAGE_RW);}
+static inline int pte_dirty(pte_t pte) { return !!(pte_val(pte) & _PAGE_DIRTY); }
+static inline int pte_young(pte_t pte) { return !!(pte_val(pte) & _PAGE_ACCESSED); }
+static inline int pte_special(pte_t pte) { return !!(pte_val(pte) & _PAGE_SPECIAL); }
+static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
+static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
+
+static inline int pte_present(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_PRESENT;
+}
+
+/* Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * Even if PTEs can be unsigned long long, a PFN is always an unsigned
+ * long for now.
+ */
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+ return __pte(((pte_basic_t)(pfn) << PTE_RPN_SHIFT) |
+ pgprot_val(pgprot));
+}
+
+static inline unsigned long pte_pfn(pte_t pte)
+{
+ return pte_val(pte) >> PTE_RPN_SHIFT;
+}
+
+/* Generic modifiers for PTE bits */
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_RW);
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_DIRTY);
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_RW);
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_DIRTY);
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_SPECIAL);
+}
+
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+ return pte;
+}
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
+}
+
+
+
+/* This low level function performs the actual PTE insertion
+ * Setting the PTE depends on the MMU type and other factors. It's
+ * an horrible mess that I'm not going to try to clean up now but
+ * I'm keeping it in one place rather than spread around
+ */
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, int percpu)
+{
+#if defined(CONFIG_PPC_STD_MMU_32) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
+ /* First case is 32-bit Hash MMU in SMP mode with 32-bit PTEs. We use the
+ * helper pte_update() which does an atomic update. We need to do that
+ * because a concurrent invalidation can clear _PAGE_HASHPTE. If it's a
+ * per-CPU PTE such as a kmap_atomic, we do a simple update preserving
+ * the hash bits instead (ie, same as the non-SMP case)
+ */
+ if (percpu)
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+ else
+ pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte));
+
+#elif defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
+ /* Second case is 32-bit with 64-bit PTE. In this case, we
+ * can just store as long as we do the two halves in the right order
+ * with a barrier in between. This is possible because we take care,
+ * in the hash code, to pre-invalidate if the PTE was already hashed,
+ * which synchronizes us with any concurrent invalidation.
+ * In the percpu case, we also fallback to the simple update preserving
+ * the hash bits
+ */
+ if (percpu) {
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+ return;
+ }
+ if (pte_val(*ptep) & _PAGE_HASHPTE)
+ flush_hash_entry(mm, ptep, addr);
+ __asm__ __volatile__("\
+ stw%U0%X0 %2,%0\n\
+ eieio\n\
+ stw%U0%X0 %L2,%1"
+ : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
+ : "r" (pte) : "memory");
+
+#elif defined(CONFIG_PPC_STD_MMU_32)
+ /* Third case is 32-bit hash table in UP mode, we need to preserve
+ * the _PAGE_HASHPTE bit since we may not have invalidated the previous
+ * translation in the hash yet (done in a subsequent flush_tlb_xxx())
+ * and see we need to keep track that this PTE needs invalidating
+ */
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+
+#else
+#error "Not supported "
+#endif
+}
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+
+#define _PAGE_CACHE_CTL (_PAGE_COHERENT | _PAGE_GUARDED | _PAGE_NO_CACHE | \
+ _PAGE_WRITETHRU)
+
+#define pgprot_noncached pgprot_noncached
+static inline pgprot_t pgprot_noncached(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_NO_CACHE | _PAGE_GUARDED);
+}
+
+#define pgprot_noncached_wc pgprot_noncached_wc
+static inline pgprot_t pgprot_noncached_wc(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_NO_CACHE);
+}
+
+#define pgprot_cached pgprot_cached
+static inline pgprot_t pgprot_cached(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_COHERENT);
+}
+
+#define pgprot_cached_wthru pgprot_cached_wthru
+static inline pgprot_t pgprot_cached_wthru(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_COHERENT | _PAGE_WRITETHRU);
+}
+
+#define pgprot_cached_noncoherent pgprot_cached_noncoherent
+static inline pgprot_t pgprot_cached_noncoherent(pgprot_t prot)
+{
+ return __pgprot(pgprot_val(prot) & ~_PAGE_CACHE_CTL);
+}
+
+#define pgprot_writecombine pgprot_writecombine
+static inline pgprot_t pgprot_writecombine(pgprot_t prot)
+{
+ return pgprot_noncached_wc(prot);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_BOOK3S_32_PGTABLE_H */
diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h
new file mode 100644
index 000000000000..ea0414d6659e
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h
@@ -0,0 +1,132 @@
+#ifndef _ASM_POWERPC_BOOK3S_64_HASH_4K_H
+#define _ASM_POWERPC_BOOK3S_64_HASH_4K_H
+/*
+ * Entries per page directory level. The PTE level must use a 64b record
+ * for each page table entry. The PMD and PGD level use a 32b record for
+ * each entry by assuming that each entry is page aligned.
+ */
+#define PTE_INDEX_SIZE 9
+#define PMD_INDEX_SIZE 7
+#define PUD_INDEX_SIZE 9
+#define PGD_INDEX_SIZE 9
+
+#ifndef __ASSEMBLY__
+#define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_INDEX_SIZE)
+#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
+#define PUD_TABLE_SIZE (sizeof(pud_t) << PUD_INDEX_SIZE)
+#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
+#endif /* __ASSEMBLY__ */
+
+#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE)
+#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE)
+#define PTRS_PER_PUD (1 << PUD_INDEX_SIZE)
+#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE)
+
+/* PMD_SHIFT determines what a second-level page table entry can map */
+#define PMD_SHIFT (PAGE_SHIFT + PTE_INDEX_SIZE)
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+
+/* With 4k base page size, hugepage PTEs go at the PMD level */
+#define MIN_HUGEPTE_SHIFT PMD_SHIFT
+
+/* PUD_SHIFT determines what a third-level page table entry can map */
+#define PUD_SHIFT (PMD_SHIFT + PMD_INDEX_SIZE)
+#define PUD_SIZE (1UL << PUD_SHIFT)
+#define PUD_MASK (~(PUD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a fourth-level page table entry can map */
+#define PGDIR_SHIFT (PUD_SHIFT + PUD_INDEX_SIZE)
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/* Bits to mask out from a PMD to get to the PTE page */
+#define PMD_MASKED_BITS 0
+/* Bits to mask out from a PUD to get to the PMD page */
+#define PUD_MASKED_BITS 0
+/* Bits to mask out from a PGD to get to the PUD page */
+#define PGD_MASKED_BITS 0
+
+/* PTE flags to conserve for HPTE identification */
+#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | \
+ _PAGE_F_SECOND | _PAGE_F_GIX)
+
+/* shift to put page number into pte */
+#define PTE_RPN_SHIFT (18)
+
+#define _PAGE_4K_PFN 0
+#ifndef __ASSEMBLY__
+/*
+ * 4-level page tables related bits
+ */
+
+#define pgd_none(pgd) (!pgd_val(pgd))
+#define pgd_bad(pgd) (pgd_val(pgd) == 0)
+#define pgd_present(pgd) (pgd_val(pgd) != 0)
+#define pgd_page_vaddr(pgd) (pgd_val(pgd) & ~PGD_MASKED_BITS)
+
+static inline void pgd_clear(pgd_t *pgdp)
+{
+ *pgdp = __pgd(0);
+}
+
+static inline pte_t pgd_pte(pgd_t pgd)
+{
+ return __pte(pgd_val(pgd));
+}
+
+static inline pgd_t pte_pgd(pte_t pte)
+{
+ return __pgd(pte_val(pte));
+}
+extern struct page *pgd_page(pgd_t pgd);
+
+#define pud_offset(pgdp, addr) \
+ (((pud_t *) pgd_page_vaddr(*(pgdp))) + \
+ (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))
+
+#define pud_ERROR(e) \
+ pr_err("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
+
+/*
+ * On all 4K setups, remap_4k_pfn() equates to remap_pfn_range() */
+#define remap_4k_pfn(vma, addr, pfn, prot) \
+ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot))
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * For 4k page size, we support explicit hugepage via hugepd
+ */
+static inline int pmd_huge(pmd_t pmd)
+{
+ return 0;
+}
+
+static inline int pud_huge(pud_t pud)
+{
+ return 0;
+}
+
+static inline int pgd_huge(pgd_t pgd)
+{
+ return 0;
+}
+#define pgd_huge pgd_huge
+
+static inline int hugepd_ok(hugepd_t hpd)
+{
+ /*
+ * if it is not a pte and have hugepd shift mask
+ * set, then it is a hugepd directory pointer
+ */
+ if (!(hpd.pd & _PAGE_PTE) &&
+ ((hpd.pd & HUGEPD_SHIFT_MASK) != 0))
+ return true;
+ return false;
+}
+#define is_hugepd(hpd) (hugepd_ok(hpd))
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_BOOK3S_64_HASH_4K_H */
diff --git a/arch/powerpc/include/asm/book3s/64/hash-64k.h b/arch/powerpc/include/asm/book3s/64/hash-64k.h
new file mode 100644
index 000000000000..849bbec80f7b
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/64/hash-64k.h
@@ -0,0 +1,300 @@
+#ifndef _ASM_POWERPC_BOOK3S_64_HASH_64K_H
+#define _ASM_POWERPC_BOOK3S_64_HASH_64K_H
+
+#include <asm-generic/pgtable-nopud.h>
+
+#define PTE_INDEX_SIZE 8
+#define PMD_INDEX_SIZE 10
+#define PUD_INDEX_SIZE 0
+#define PGD_INDEX_SIZE 12
+
+#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE)
+#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE)
+#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE)
+
+/* With 4k base page size, hugepage PTEs go at the PMD level */
+#define MIN_HUGEPTE_SHIFT PAGE_SHIFT
+
+/* PMD_SHIFT determines what a second-level page table entry can map */
+#define PMD_SHIFT (PAGE_SHIFT + PTE_INDEX_SIZE)
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT (PMD_SHIFT + PMD_INDEX_SIZE)
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+#define _PAGE_COMBO 0x00040000 /* this is a combo 4k page */
+#define _PAGE_4K_PFN 0x00080000 /* PFN is for a single 4k page */
+/*
+ * Used to track subpage group valid if _PAGE_COMBO is set
+ * This overloads _PAGE_F_GIX and _PAGE_F_SECOND
+ */
+#define _PAGE_COMBO_VALID (_PAGE_F_GIX | _PAGE_F_SECOND)
+
+/* PTE flags to conserve for HPTE identification */
+#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_F_SECOND | \
+ _PAGE_F_GIX | _PAGE_HASHPTE | _PAGE_COMBO)
+
+/* Shift to put page number into pte.
+ *
+ * That gives us a max RPN of 34 bits, which means a max of 50 bits
+ * of addressable physical space, or 46 bits for the special 4k PFNs.
+ */
+#define PTE_RPN_SHIFT (30)
+/*
+ * we support 16 fragments per PTE page of 64K size.
+ */
+#define PTE_FRAG_NR 16
+/*
+ * We use a 2K PTE page fragment and another 2K for storing
+ * real_pte_t hash index
+ */
+#define PTE_FRAG_SIZE_SHIFT 12
+#define PTE_FRAG_SIZE (1UL << PTE_FRAG_SIZE_SHIFT)
+
+/*
+ * Bits to mask out from a PMD to get to the PTE page
+ * PMDs point to PTE table fragments which are PTE_FRAG_SIZE aligned.
+ */
+#define PMD_MASKED_BITS (PTE_FRAG_SIZE - 1)
+/* Bits to mask out from a PGD/PUD to get to the PMD page */
+#define PUD_MASKED_BITS 0x1ff
+
+#ifndef __ASSEMBLY__
+
+/*
+ * With 64K pages on hash table, we have a special PTE format that
+ * uses a second "half" of the page table to encode sub-page information
+ * in order to deal with 64K made of 4K HW pages. Thus we override the
+ * generic accessors and iterators here
+ */
+#define __real_pte __real_pte
+static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep)
+{
+ real_pte_t rpte;
+ unsigned long *hidxp;
+
+ rpte.pte = pte;
+ rpte.hidx = 0;
+ if (pte_val(pte) & _PAGE_COMBO) {
+ /*
+ * Make sure we order the hidx load against the _PAGE_COMBO
+ * check. The store side ordering is done in __hash_page_4K
+ */
+ smp_rmb();
+ hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+ rpte.hidx = *hidxp;
+ }
+ return rpte;
+}
+
+static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
+{
+ if ((pte_val(rpte.pte) & _PAGE_COMBO))
+ return (rpte.hidx >> (index<<2)) & 0xf;
+ return (pte_val(rpte.pte) >> _PAGE_F_GIX_SHIFT) & 0xf;
+}
+
+#define __rpte_to_pte(r) ((r).pte)
+extern bool __rpte_sub_valid(real_pte_t rpte, unsigned long index);
+/*
+ * Trick: we set __end to va + 64k, which happens works for
+ * a 16M page as well as we want only one iteration
+ */
+#define pte_iterate_hashed_subpages(rpte, psize, vpn, index, shift) \
+ do { \
+ unsigned long __end = vpn + (1UL << (PAGE_SHIFT - VPN_SHIFT)); \
+ unsigned __split = (psize == MMU_PAGE_4K || \
+ psize == MMU_PAGE_64K_AP); \
+ shift = mmu_psize_defs[psize].shift; \
+ for (index = 0; vpn < __end; index++, \
+ vpn += (1L << (shift - VPN_SHIFT))) { \
+ if (!__split || __rpte_sub_valid(rpte, index)) \
+ do {
+
+#define pte_iterate_hashed_end() } while(0); } } while(0)
+
+#define pte_pagesize_index(mm, addr, pte) \
+ (((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
+
+#define remap_4k_pfn(vma, addr, pfn, prot) \
+ (WARN_ON(((pfn) >= (1UL << (64 - PTE_RPN_SHIFT)))) ? -EINVAL : \
+ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
+ __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))
+
+#define PTE_TABLE_SIZE PTE_FRAG_SIZE
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define PMD_TABLE_SIZE ((sizeof(pmd_t) << PMD_INDEX_SIZE) + (sizeof(unsigned long) << PMD_INDEX_SIZE))
+#else
+#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
+#endif
+#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
+
+#define pgd_pte(pgd) (pud_pte(((pud_t){ pgd })))
+#define pte_pgd(pte) ((pgd_t)pte_pud(pte))
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * We have PGD_INDEX_SIZ = 12 and PTE_INDEX_SIZE = 8, so that we can have
+ * 16GB hugepage pte in PGD and 16MB hugepage pte at PMD;
+ *
+ * Defined in such a way that we can optimize away code block at build time
+ * if CONFIG_HUGETLB_PAGE=n.
+ */
+static inline int pmd_huge(pmd_t pmd)
+{
+ /*
+ * leaf pte for huge page
+ */
+ return !!(pmd_val(pmd) & _PAGE_PTE);
+}
+
+static inline int pud_huge(pud_t pud)
+{
+ /*
+ * leaf pte for huge page
+ */
+ return !!(pud_val(pud) & _PAGE_PTE);
+}
+
+static inline int pgd_huge(pgd_t pgd)
+{
+ /*
+ * leaf pte for huge page
+ */
+ return !!(pgd_val(pgd) & _PAGE_PTE);
+}
+#define pgd_huge pgd_huge
+
+#ifdef CONFIG_DEBUG_VM
+extern int hugepd_ok(hugepd_t hpd);
+#define is_hugepd(hpd) (hugepd_ok(hpd))
+#else
+/*
+ * With 64k page size, we have hugepage ptes in the pgd and pmd entries. We don't
+ * need to setup hugepage directory for them. Our pte and page directory format
+ * enable us to have this enabled.
+ */
+static inline int hugepd_ok(hugepd_t hpd)
+{
+ return 0;
+}
+#define is_hugepd(pdep) 0
+#endif /* CONFIG_DEBUG_VM */
+
+#endif /* CONFIG_HUGETLB_PAGE */
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
+ unsigned long addr,
+ pmd_t *pmdp,
+ unsigned long clr,
+ unsigned long set);
+static inline char *get_hpte_slot_array(pmd_t *pmdp)
+{
+ /*
+ * The hpte hindex is stored in the pgtable whose address is in the
+ * second half of the PMD
+ *
+ * Order this load with the test for pmd_trans_huge in the caller
+ */
+ smp_rmb();
+ return *(char **)(pmdp + PTRS_PER_PMD);
+
+
+}
+/*
+ * The linux hugepage PMD now include the pmd entries followed by the address
+ * to the stashed pgtable_t. The stashed pgtable_t contains the hpte bits.
+ * [ 1 bit secondary | 3 bit hidx | 1 bit valid | 000]. We use one byte per
+ * each HPTE entry. With 16MB hugepage and 64K HPTE we need 256 entries and
+ * with 4K HPTE we need 4096 entries. Both will fit in a 4K pgtable_t.
+ *
+ * The last three bits are intentionally left to zero. This memory location
+ * are also used as normal page PTE pointers. So if we have any pointers
+ * left around while we collapse a hugepage, we need to make sure
+ * _PAGE_PRESENT bit of that is zero when we look at them
+ */
+static inline unsigned int hpte_valid(unsigned char *hpte_slot_array, int index)
+{
+ return (hpte_slot_array[index] >> 3) & 0x1;
+}
+
+static inline unsigned int hpte_hash_index(unsigned char *hpte_slot_array,
+ int index)
+{
+ return hpte_slot_array[index] >> 4;
+}
+
+static inline void mark_hpte_slot_valid(unsigned char *hpte_slot_array,
+ unsigned int index, unsigned int hidx)
+{
+ hpte_slot_array[index] = hidx << 4 | 0x1 << 3;
+}
+
+/*
+ *
+ * For core kernel code by design pmd_trans_huge is never run on any hugetlbfs
+ * page. The hugetlbfs page table walking and mangling paths are totally
+ * separated form the core VM paths and they're differentiated by
+ * VM_HUGETLB being set on vm_flags well before any pmd_trans_huge could run.
+ *
+ * pmd_trans_huge() is defined as false at build time if
+ * CONFIG_TRANSPARENT_HUGEPAGE=n to optimize away code blocks at build
+ * time in such case.
+ *
+ * For ppc64 we need to differntiate from explicit hugepages from THP, because
+ * for THP we also track the subpage details at the pmd level. We don't do
+ * that for explicit huge pages.
+ *
+ */
+static inline int pmd_trans_huge(pmd_t pmd)
+{
+ return !!((pmd_val(pmd) & (_PAGE_PTE | _PAGE_THP_HUGE)) ==
+ (_PAGE_PTE | _PAGE_THP_HUGE));
+}
+
+static inline int pmd_large(pmd_t pmd)
+{
+ return !!(pmd_val(pmd) & _PAGE_PTE);
+}
+
+static inline pmd_t pmd_mknotpresent(pmd_t pmd)
+{
+ return __pmd(pmd_val(pmd) & ~_PAGE_PRESENT);
+}
+
+#define __HAVE_ARCH_PMD_SAME
+static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
+{
+ return (((pmd_val(pmd_a) ^ pmd_val(pmd_b)) & ~_PAGE_HPTEFLAGS) == 0);
+}
+
+static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
+ unsigned long addr, pmd_t *pmdp)
+{
+ unsigned long old;
+
+ if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+ return 0;
+ old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0);
+ return ((old & _PAGE_ACCESSED) != 0);
+}
+
+#define __HAVE_ARCH_PMDP_SET_WRPROTECT
+static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+
+ if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
+ return;
+
+ pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
+}
+
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_BOOK3S_64_HASH_64K_H */
diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h
new file mode 100644
index 000000000000..06f17e778c27
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/64/hash.h
@@ -0,0 +1,545 @@
+#ifndef _ASM_POWERPC_BOOK3S_64_HASH_H
+#define _ASM_POWERPC_BOOK3S_64_HASH_H
+#ifdef __KERNEL__
+
+/*
+ * Common bits between 4K and 64K pages in a linux-style PTE.
+ * These match the bits in the (hardware-defined) PowerPC PTE as closely
+ * as possible. Additional bits may be defined in pgtable-hash64-*.h
+ *
+ * Note: We only support user read/write permissions. Supervisor always
+ * have full read/write to pages above PAGE_OFFSET (pages below that
+ * always use the user access permissions).
+ *
+ * We could create separate kernel read-only if we used the 3 PP bits
+ * combinations that newer processors provide but we currently don't.
+ */
+#define _PAGE_PTE 0x00001
+#define _PAGE_PRESENT 0x00002 /* software: pte contains a translation */
+#define _PAGE_BIT_SWAP_TYPE 2
+#define _PAGE_USER 0x00004 /* matches one of the PP bits */
+#define _PAGE_EXEC 0x00008 /* No execute on POWER4 and newer (we invert) */
+#define _PAGE_GUARDED 0x00010
+/* We can derive Memory coherence from _PAGE_NO_CACHE */
+#define _PAGE_COHERENT 0x0
+#define _PAGE_NO_CACHE 0x00020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU 0x00040 /* W: cache write-through */
+#define _PAGE_DIRTY 0x00080 /* C: page changed */
+#define _PAGE_ACCESSED 0x00100 /* R: page referenced */
+#define _PAGE_RW 0x00200 /* software: user write access allowed */
+#define _PAGE_HASHPTE 0x00400 /* software: pte has an associated HPTE */
+#define _PAGE_BUSY 0x00800 /* software: PTE & hash are busy */
+#define _PAGE_F_GIX 0x07000 /* full page: hidx bits */
+#define _PAGE_F_GIX_SHIFT 12
+#define _PAGE_F_SECOND 0x08000 /* Whether to use secondary hash or not */
+#define _PAGE_SPECIAL 0x10000 /* software: special page */
+
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define _PAGE_SOFT_DIRTY 0x20000 /* software: software dirty tracking */
+#else
+#define _PAGE_SOFT_DIRTY 0x00000
+#endif
+
+/*
+ * We need to differentiate between explicit huge page and THP huge
+ * page, since THP huge page also need to track real subpage details
+ */
+#define _PAGE_THP_HUGE _PAGE_4K_PFN
+
+/*
+ * set of bits not changed in pmd_modify.
+ */
+#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
+ _PAGE_ACCESSED | _PAGE_THP_HUGE)
+
+#ifdef CONFIG_PPC_64K_PAGES
+#include <asm/book3s/64/hash-64k.h>
+#else
+#include <asm/book3s/64/hash-4k.h>
+#endif
+
+/*
+ * Size of EA range mapped by our pagetables.
+ */
+#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
+ PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
+#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define PMD_CACHE_INDEX (PMD_INDEX_SIZE + 1)
+#else
+#define PMD_CACHE_INDEX PMD_INDEX_SIZE
+#endif
+/*
+ * Define the address range of the kernel non-linear virtual area
+ */
+#define KERN_VIRT_START ASM_CONST(0xD000000000000000)
+#define KERN_VIRT_SIZE ASM_CONST(0x0000100000000000)
+
+/*
+ * The vmalloc space starts at the beginning of that region, and
+ * occupies half of it on hash CPUs and a quarter of it on Book3E
+ * (we keep a quarter for the virtual memmap)
+ */
+#define VMALLOC_START KERN_VIRT_START
+#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
+#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
+
+/*
+ * Region IDs
+ */
+#define REGION_SHIFT 60UL
+#define REGION_MASK (0xfUL << REGION_SHIFT)
+#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
+
+#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
+#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
+#define VMEMMAP_REGION_ID (0xfUL) /* Server only */
+#define USER_REGION_ID (0UL)
+
+/*
+ * Defines the address of the vmemap area, in its own region on
+ * hash table CPUs.
+ */
+#define VMEMMAP_BASE (VMEMMAP_REGION_ID << REGION_SHIFT)
+
+#ifdef CONFIG_PPC_MM_SLICES
+#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+#endif /* CONFIG_PPC_MM_SLICES */
+
+/* No separate kernel read-only */
+#define _PAGE_KERNEL_RW (_PAGE_RW | _PAGE_DIRTY) /* user access blocked by key */
+#define _PAGE_KERNEL_RO _PAGE_KERNEL_RW
+#define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC)
+
+/* Strong Access Ordering */
+#define _PAGE_SAO (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT)
+
+/* No page size encoding in the linux PTE */
+#define _PAGE_PSIZE 0
+
+/* PTEIDX nibble */
+#define _PTEIDX_SECONDARY 0x8
+#define _PTEIDX_GROUP_IX 0x7
+
+/* Hash table based platforms need atomic updates of the linux PTE */
+#define PTE_ATOMIC_UPDATES 1
+#define _PTE_NONE_MASK _PAGE_HPTEFLAGS
+/*
+ * The mask convered by the RPN must be a ULL on 32-bit platforms with
+ * 64-bit PTEs
+ */
+#define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1))
+/*
+ * _PAGE_CHG_MASK masks of bits that are to be preserved across
+ * pgprot changes
+ */
+#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
+ _PAGE_ACCESSED | _PAGE_SPECIAL | _PAGE_PTE | \
+ _PAGE_SOFT_DIRTY)
+/*
+ * Mask of bits returned by pte_pgprot()
+ */
+#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
+ _PAGE_WRITETHRU | _PAGE_4K_PFN | \
+ _PAGE_USER | _PAGE_ACCESSED | \
+ _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC | \
+ _PAGE_SOFT_DIRTY)
+/*
+ * We define 2 sets of base prot bits, one for basic pages (ie,
+ * cacheable kernel and user pages) and one for non cacheable
+ * pages. We always set _PAGE_COHERENT when SMP is enabled or
+ * the processor might need it for DMA coherency.
+ */
+#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE)
+#define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT)
+
+/* Permission masks used to generate the __P and __S table,
+ *
+ * Note:__pgprot is defined in arch/powerpc/include/asm/page.h
+ *
+ * Write permissions imply read permissions for now (we could make write-only
+ * pages on BookE but we don't bother for now). Execute permission control is
+ * possible on platforms that define _PAGE_EXEC
+ *
+ * Note due to the way vm flags are laid out, the bits are XWR
+ */
+#define PAGE_NONE __pgprot(_PAGE_BASE)
+#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | \
+ _PAGE_EXEC)
+#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER )
+#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER )
+#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY_X
+#define __P101 PAGE_READONLY_X
+#define __P110 PAGE_COPY_X
+#define __P111 PAGE_COPY_X
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY_X
+#define __S101 PAGE_READONLY_X
+#define __S110 PAGE_SHARED_X
+#define __S111 PAGE_SHARED_X
+
+/* Permission masks used for kernel mappings */
+#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
+#define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \
+ _PAGE_NO_CACHE)
+#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \
+ _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO)
+#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX)
+
+/* Protection used for kernel text. We want the debuggers to be able to
+ * set breakpoints anywhere, so don't write protect the kernel text
+ * on platforms where such control is possible.
+ */
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\
+ defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE)
+#define PAGE_KERNEL_TEXT PAGE_KERNEL_X
+#else
+#define PAGE_KERNEL_TEXT PAGE_KERNEL_ROX
+#endif
+
+/* Make modules code happy. We don't set RO yet */
+#define PAGE_KERNEL_EXEC PAGE_KERNEL_X
+#define PAGE_AGP (PAGE_KERNEL_NC)
+
+#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
+#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
+
+#ifndef __ASSEMBLY__
+#define pmd_bad(pmd) (!is_kernel_addr(pmd_val(pmd)) \
+ || (pmd_val(pmd) & PMD_BAD_BITS))
+#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
+
+#define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \
+ || (pud_val(pud) & PUD_BAD_BITS))
+#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
+
+#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
+#define pmd_index(address) (((address) >> (PMD_SHIFT)) & (PTRS_PER_PMD - 1))
+#define pte_index(address) (((address) >> (PAGE_SHIFT)) & (PTRS_PER_PTE - 1))
+
+extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, unsigned long pte, int huge);
+extern unsigned long htab_convert_pte_flags(unsigned long pteflags);
+/* Atomic PTE updates */
+static inline unsigned long pte_update(struct mm_struct *mm,
+ unsigned long addr,
+ pte_t *ptep, unsigned long clr,
+ unsigned long set,
+ int huge)
+{
+ unsigned long old, tmp;
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%3 # pte_update\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ andc %1,%0,%4 \n\
+ or %1,%1,%7\n\
+ stdcx. %1,0,%3 \n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*ptep)
+ : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set)
+ : "cc" );
+ /* huge pages use the old page table lock */
+ if (!huge)
+ assert_pte_locked(mm, addr);
+
+ if (old & _PAGE_HASHPTE)
+ hpte_need_flush(mm, addr, ptep, old, huge);
+
+ return old;
+}
+
+static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ unsigned long old;
+
+ if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+ return 0;
+ old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
+ return (old & _PAGE_ACCESSED) != 0;
+}
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
+({ \
+ int __r; \
+ __r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
+ __r; \
+})
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+
+ if ((pte_val(*ptep) & _PAGE_RW) == 0)
+ return;
+
+ pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ if ((pte_val(*ptep) & _PAGE_RW) == 0)
+ return;
+
+ pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
+}
+
+/*
+ * We currently remove entries from the hashtable regardless of whether
+ * the entry was young or dirty. The generic routines only flush if the
+ * entry was young or dirty which is not good enough.
+ *
+ * We should be more intelligent about this but for the moment we override
+ * these functions and force a tlb flush unconditionally
+ */
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+#define ptep_clear_flush_young(__vma, __address, __ptep) \
+({ \
+ int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
+ __ptep); \
+ __young; \
+})
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
+ return __pte(old);
+}
+
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t * ptep)
+{
+ pte_update(mm, addr, ptep, ~0UL, 0, 0);
+}
+
+
+/* Set the dirty and/or accessed bits atomically in a linux PTE, this
+ * function doesn't need to flush the hash entry
+ */
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
+{
+ unsigned long bits = pte_val(entry) &
+ (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC |
+ _PAGE_SOFT_DIRTY);
+
+ unsigned long old, tmp;
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%4\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ or %0,%3,%0\n\
+ stdcx. %0,0,%4\n\
+ bne- 1b"
+ :"=&r" (old), "=&r" (tmp), "=m" (*ptep)
+ :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
+ :"cc");
+}
+
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
+
+/* Generic accessors to PTE bits */
+static inline int pte_write(pte_t pte) { return !!(pte_val(pte) & _PAGE_RW);}
+static inline int pte_dirty(pte_t pte) { return !!(pte_val(pte) & _PAGE_DIRTY); }
+static inline int pte_young(pte_t pte) { return !!(pte_val(pte) & _PAGE_ACCESSED); }
+static inline int pte_special(pte_t pte) { return !!(pte_val(pte) & _PAGE_SPECIAL); }
+static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
+static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
+
+#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
+static inline bool pte_soft_dirty(pte_t pte)
+{
+ return !!(pte_val(pte) & _PAGE_SOFT_DIRTY);
+}
+static inline pte_t pte_mksoft_dirty(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_SOFT_DIRTY);
+}
+
+static inline pte_t pte_clear_soft_dirty(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_SOFT_DIRTY);
+}
+#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
+
+#ifdef CONFIG_NUMA_BALANCING
+/*
+ * These work without NUMA balancing but the kernel does not care. See the
+ * comment in include/asm-generic/pgtable.h . On powerpc, this will only
+ * work for user pages and always return true for kernel pages.
+ */
+static inline int pte_protnone(pte_t pte)
+{
+ return (pte_val(pte) &
+ (_PAGE_PRESENT | _PAGE_USER)) == _PAGE_PRESENT;
+}
+#endif /* CONFIG_NUMA_BALANCING */
+
+static inline int pte_present(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_PRESENT;
+}
+
+/* Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * Even if PTEs can be unsigned long long, a PFN is always an unsigned
+ * long for now.
+ */
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+ return __pte(((pte_basic_t)(pfn) << PTE_RPN_SHIFT) |
+ pgprot_val(pgprot));
+}
+
+static inline unsigned long pte_pfn(pte_t pte)
+{
+ return pte_val(pte) >> PTE_RPN_SHIFT;
+}
+
+/* Generic modifiers for PTE bits */
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_RW);
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_DIRTY);
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_RW);
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_SPECIAL);
+}
+
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+ return pte;
+}
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
+}
+
+/* This low level function performs the actual PTE insertion
+ * Setting the PTE depends on the MMU type and other factors. It's
+ * an horrible mess that I'm not going to try to clean up now but
+ * I'm keeping it in one place rather than spread around
+ */
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, int percpu)
+{
+ /*
+ * Anything else just stores the PTE normally. That covers all 64-bit
+ * cases, and 32-bit non-hash with 32-bit PTEs.
+ */
+ *ptep = pte;
+}
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+
+#define _PAGE_CACHE_CTL (_PAGE_COHERENT | _PAGE_GUARDED | _PAGE_NO_CACHE | \
+ _PAGE_WRITETHRU)
+
+#define pgprot_noncached pgprot_noncached
+static inline pgprot_t pgprot_noncached(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_NO_CACHE | _PAGE_GUARDED);
+}
+
+#define pgprot_noncached_wc pgprot_noncached_wc
+static inline pgprot_t pgprot_noncached_wc(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_NO_CACHE);
+}
+
+#define pgprot_cached pgprot_cached
+static inline pgprot_t pgprot_cached(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_COHERENT);
+}
+
+#define pgprot_cached_wthru pgprot_cached_wthru
+static inline pgprot_t pgprot_cached_wthru(pgprot_t prot)
+{
+ return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) |
+ _PAGE_COHERENT | _PAGE_WRITETHRU);
+}
+
+#define pgprot_cached_noncoherent pgprot_cached_noncoherent
+static inline pgprot_t pgprot_cached_noncoherent(pgprot_t prot)
+{
+ return __pgprot(pgprot_val(prot) & ~_PAGE_CACHE_CTL);
+}
+
+#define pgprot_writecombine pgprot_writecombine
+static inline pgprot_t pgprot_writecombine(pgprot_t prot)
+{
+ return pgprot_noncached_wc(prot);
+}
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, unsigned long old_pmd);
+#else
+static inline void hpte_do_hugepage_flush(struct mm_struct *mm,
+ unsigned long addr, pmd_t *pmdp,
+ unsigned long old_pmd)
+{
+ WARN(1, "%s called with THP disabled\n", __func__);
+}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_BOOK3S_64_HASH_H */
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
new file mode 100644
index 000000000000..8204b0c393aa
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -0,0 +1,298 @@
+#ifndef _ASM_POWERPC_BOOK3S_64_PGTABLE_H_
+#define _ASM_POWERPC_BOOK3S_64_PGTABLE_H_
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the ppc64 hashed page table.
+ */
+
+#include <asm/book3s/64/hash.h>
+#include <asm/barrier.h>
+
+/*
+ * The second half of the kernel virtual space is used for IO mappings,
+ * it's itself carved into the PIO region (ISA and PHB IO space) and
+ * the ioremap space
+ *
+ * ISA_IO_BASE = KERN_IO_START, 64K reserved area
+ * PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
+ * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
+ */
+#define KERN_IO_START (KERN_VIRT_START + (KERN_VIRT_SIZE >> 1))
+#define FULL_IO_SIZE 0x80000000ul
+#define ISA_IO_BASE (KERN_IO_START)
+#define ISA_IO_END (KERN_IO_START + 0x10000ul)
+#define PHB_IO_BASE (ISA_IO_END)
+#define PHB_IO_END (KERN_IO_START + FULL_IO_SIZE)
+#define IOREMAP_BASE (PHB_IO_END)
+#define IOREMAP_END (KERN_VIRT_START + KERN_VIRT_SIZE)
+
+#define vmemmap ((struct page *)VMEMMAP_BASE)
+
+/* Advertise special mapping type for AGP */
+#define HAVE_PAGE_AGP
+
+/* Advertise support for _PAGE_SPECIAL */
+#define __HAVE_ARCH_PTE_SPECIAL
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This is the default implementation of various PTE accessors, it's
+ * used in all cases except Book3S with 64K pages where we have a
+ * concept of sub-pages
+ */
+#ifndef __real_pte
+
+#ifdef CONFIG_STRICT_MM_TYPECHECKS
+#define __real_pte(e,p) ((real_pte_t){(e)})
+#define __rpte_to_pte(r) ((r).pte)
+#else
+#define __real_pte(e,p) (e)
+#define __rpte_to_pte(r) (__pte(r))
+#endif
+#define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >>_PAGE_F_GIX_SHIFT)
+
+#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
+ do { \
+ index = 0; \
+ shift = mmu_psize_defs[psize].shift; \
+
+#define pte_iterate_hashed_end() } while(0)
+
+/*
+ * We expect this to be called only for user addresses or kernel virtual
+ * addresses other than the linear mapping.
+ */
+#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
+
+#endif /* __real_pte */
+
+static inline void pmd_set(pmd_t *pmdp, unsigned long val)
+{
+ *pmdp = __pmd(val);
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ *pmdp = __pmd(0);
+}
+
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_present(pmd) (!pmd_none(pmd))
+
+static inline void pud_set(pud_t *pudp, unsigned long val)
+{
+ *pudp = __pud(val);
+}
+
+static inline void pud_clear(pud_t *pudp)
+{
+ *pudp = __pud(0);
+}
+
+#define pud_none(pud) (!pud_val(pud))
+#define pud_present(pud) (pud_val(pud) != 0)
+
+extern struct page *pud_page(pud_t pud);
+extern struct page *pmd_page(pmd_t pmd);
+static inline pte_t pud_pte(pud_t pud)
+{
+ return __pte(pud_val(pud));
+}
+
+static inline pud_t pte_pud(pte_t pte)
+{
+ return __pud(pte_val(pte));
+}
+#define pud_write(pud) pte_write(pud_pte(pud))
+#define pgd_write(pgd) pte_write(pgd_pte(pgd))
+static inline void pgd_set(pgd_t *pgdp, unsigned long val)
+{
+ *pgdp = __pgd(val);
+}
+
+/*
+ * Find an entry in a page-table-directory. We combine the address region
+ * (the high order N bits) and the pgd portion of the address.
+ */
+
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+
+#define pmd_offset(pudp,addr) \
+ (((pmd_t *) pud_page_vaddr(*(pudp))) + pmd_index(addr))
+
+#define pte_offset_kernel(dir,addr) \
+ (((pte_t *) pmd_page_vaddr(*(dir))) + pte_index(addr))
+
+#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
+#define pte_unmap(pte) do { } while(0)
+
+/* to find an entry in a kernel page-table-directory */
+/* This now only contains the vmalloc pages */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+#define pte_ERROR(e) \
+ pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+ pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/* Encode and de-code a swap entry */
+#define MAX_SWAPFILES_CHECK() do { \
+ BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS); \
+ /* \
+ * Don't have overlapping bits with _PAGE_HPTEFLAGS \
+ * We filter HPTEFLAGS on set_pte. \
+ */ \
+ BUILD_BUG_ON(_PAGE_HPTEFLAGS & (0x1f << _PAGE_BIT_SWAP_TYPE)); \
+ BUILD_BUG_ON(_PAGE_HPTEFLAGS & _PAGE_SWP_SOFT_DIRTY); \
+ } while (0)
+/*
+ * on pte we don't need handle RADIX_TREE_EXCEPTIONAL_SHIFT;
+ */
+#define SWP_TYPE_BITS 5
+#define __swp_type(x) (((x).val >> _PAGE_BIT_SWAP_TYPE) \
+ & ((1UL << SWP_TYPE_BITS) - 1))
+#define __swp_offset(x) ((x).val >> PTE_RPN_SHIFT)
+#define __swp_entry(type, offset) ((swp_entry_t) { \
+ ((type) << _PAGE_BIT_SWAP_TYPE) \
+ | ((offset) << PTE_RPN_SHIFT) })
+/*
+ * swp_entry_t must be independent of pte bits. We build a swp_entry_t from
+ * swap type and offset we get from swap and convert that to pte to find a
+ * matching pte in linux page table.
+ * Clear bits not found in swap entries here.
+ */
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) & ~_PAGE_PTE })
+#define __swp_entry_to_pte(x) __pte((x).val | _PAGE_PTE)
+
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define _PAGE_SWP_SOFT_DIRTY (1UL << (SWP_TYPE_BITS + _PAGE_BIT_SWAP_TYPE))
+#else
+#define _PAGE_SWP_SOFT_DIRTY 0UL
+#endif /* CONFIG_MEM_SOFT_DIRTY */
+
+#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
+static inline pte_t pte_swp_mksoft_dirty(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_SWP_SOFT_DIRTY);
+}
+static inline bool pte_swp_soft_dirty(pte_t pte)
+{
+ return !!(pte_val(pte) & _PAGE_SWP_SOFT_DIRTY);
+}
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_SWP_SOFT_DIRTY);
+}
+#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
+
+void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
+void pgtable_cache_init(void);
+
+struct page *realmode_pfn_to_page(unsigned long pfn);
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot);
+extern pmd_t mk_pmd(struct page *page, pgprot_t pgprot);
+extern pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot);
+extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, pmd_t pmd);
+extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd);
+extern int has_transparent_hugepage(void);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+
+static inline pte_t pmd_pte(pmd_t pmd)
+{
+ return __pte(pmd_val(pmd));
+}
+
+static inline pmd_t pte_pmd(pte_t pte)
+{
+ return __pmd(pte_val(pte));
+}
+
+static inline pte_t *pmdp_ptep(pmd_t *pmd)
+{
+ return (pte_t *)pmd;
+}
+
+#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
+#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
+#define pmd_young(pmd) pte_young(pmd_pte(pmd))
+#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
+#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
+#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
+#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
+#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
+#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
+#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+
+#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
+#define pmd_soft_dirty(pmd) pte_soft_dirty(pmd_pte(pmd))
+#define pmd_mksoft_dirty(pmd) pte_pmd(pte_mksoft_dirty(pmd_pte(pmd)))
+#define pmd_clear_soft_dirty(pmd) pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd)))
+#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
+
+#ifdef CONFIG_NUMA_BALANCING
+static inline int pmd_protnone(pmd_t pmd)
+{
+ return pte_protnone(pmd_pte(pmd));
+}
+#endif /* CONFIG_NUMA_BALANCING */
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd) pte_write(pmd_pte(pmd))
+
+static inline pmd_t pmd_mkhuge(pmd_t pmd)
+{
+ return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_THP_HUGE));
+}
+
+#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
+extern int pmdp_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp,
+ pmd_t entry, int dirty);
+
+#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
+extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp);
+#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
+extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp);
+
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+extern pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pmd_t *pmdp);
+
+extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp);
+#define pmdp_collapse_flush pmdp_collapse_flush
+
+#define __HAVE_ARCH_PGTABLE_DEPOSIT
+extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable);
+#define __HAVE_ARCH_PGTABLE_WITHDRAW
+extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
+
+#define __HAVE_ARCH_PMDP_INVALIDATE
+extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
+ pmd_t *pmdp);
+
+#define pmd_move_must_withdraw pmd_move_must_withdraw
+struct spinlock;
+static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
+ struct spinlock *old_pmd_ptl)
+{
+ /*
+ * Archs like ppc64 use pgtable to store per pmd
+ * specific information. So when we switch the pmd,
+ * we should also withdraw and deposit the pgtable
+ */
+ return true;
+}
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
diff --git a/arch/powerpc/include/asm/book3s/pgtable.h b/arch/powerpc/include/asm/book3s/pgtable.h
new file mode 100644
index 000000000000..8b0f4a29259a
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/pgtable.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_POWERPC_BOOK3S_PGTABLE_H
+#define _ASM_POWERPC_BOOK3S_PGTABLE_H
+
+#ifdef CONFIG_PPC64
+#include <asm/book3s/64/pgtable.h>
+#else
+#include <asm/book3s/32/pgtable.h>
+#endif
+
+#define FIRST_USER_ADDRESS 0UL
+#ifndef __ASSEMBLY__
+/* Insert a PTE, top-level function is out of line. It uses an inline
+ * low level function in the respective pgtable-* files
+ */
+extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+ pte_t pte);
+
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+ pte_t *ptep, pte_t entry, int dirty);
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h
index ad6263cffb0f..d1a8d93cccfd 100644
--- a/arch/powerpc/include/asm/cmpxchg.h
+++ b/arch/powerpc/include/asm/cmpxchg.h
@@ -18,12 +18,12 @@ __xchg_u32(volatile void *p, unsigned long val)
unsigned long prev;
__asm__ __volatile__(
- PPC_RELEASE_BARRIER
+ PPC_ATOMIC_ENTRY_BARRIER
"1: lwarx %0,0,%2 \n"
PPC405_ERR77(0,%2)
" stwcx. %3,0,%2 \n\
bne- 1b"
- PPC_ACQUIRE_BARRIER
+ PPC_ATOMIC_EXIT_BARRIER
: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
: "r" (p), "r" (val)
: "cc", "memory");
@@ -61,12 +61,12 @@ __xchg_u64(volatile void *p, unsigned long val)
unsigned long prev;
__asm__ __volatile__(
- PPC_RELEASE_BARRIER
+ PPC_ATOMIC_ENTRY_BARRIER
"1: ldarx %0,0,%2 \n"
PPC405_ERR77(0,%2)
" stdcx. %3,0,%2 \n\
bne- 1b"
- PPC_ACQUIRE_BARRIER
+ PPC_ATOMIC_EXIT_BARRIER
: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
: "r" (p), "r" (val)
: "cc", "memory");
@@ -151,14 +151,14 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
unsigned int prev;
__asm__ __volatile__ (
- PPC_RELEASE_BARRIER
+ PPC_ATOMIC_ENTRY_BARRIER
"1: lwarx %0,0,%2 # __cmpxchg_u32\n\
cmpw 0,%0,%3\n\
bne- 2f\n"
PPC405_ERR77(0,%2)
" stwcx. %4,0,%2\n\
bne- 1b"
- PPC_ACQUIRE_BARRIER
+ PPC_ATOMIC_EXIT_BARRIER
"\n\
2:"
: "=&r" (prev), "+m" (*p)
@@ -197,13 +197,13 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
unsigned long prev;
__asm__ __volatile__ (
- PPC_RELEASE_BARRIER
+ PPC_ATOMIC_ENTRY_BARRIER
"1: ldarx %0,0,%2 # __cmpxchg_u64\n\
cmpd 0,%0,%3\n\
bne- 2f\n\
stdcx. %4,0,%2\n\
bne- 1b"
- PPC_ACQUIRE_BARRIER
+ PPC_ATOMIC_EXIT_BARRIER
"\n\
2:"
: "=&r" (prev), "+m" (*p)
diff --git a/arch/powerpc/include/asm/cpm.h b/arch/powerpc/include/asm/cpm.h
index 4398a6cdcf53..2c5c5b476804 100644
--- a/arch/powerpc/include/asm/cpm.h
+++ b/arch/powerpc/include/asm/cpm.h
@@ -5,6 +5,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/of.h>
+#include <soc/fsl/qe/qe.h>
/*
* SPI Parameter RAM common to QE and CPM.
@@ -155,49 +156,6 @@ typedef struct cpm_buf_desc {
*/
#define BD_I2C_START (0x0400)
-int cpm_muram_init(void);
-
-#if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE)
-unsigned long cpm_muram_alloc(unsigned long size, unsigned long align);
-int cpm_muram_free(unsigned long offset);
-unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size);
-void __iomem *cpm_muram_addr(unsigned long offset);
-unsigned long cpm_muram_offset(void __iomem *addr);
-dma_addr_t cpm_muram_dma(void __iomem *addr);
-#else
-static inline unsigned long cpm_muram_alloc(unsigned long size,
- unsigned long align)
-{
- return -ENOSYS;
-}
-
-static inline int cpm_muram_free(unsigned long offset)
-{
- return -ENOSYS;
-}
-
-static inline unsigned long cpm_muram_alloc_fixed(unsigned long offset,
- unsigned long size)
-{
- return -ENOSYS;
-}
-
-static inline void __iomem *cpm_muram_addr(unsigned long offset)
-{
- return NULL;
-}
-
-static inline unsigned long cpm_muram_offset(void __iomem *addr)
-{
- return -ENOSYS;
-}
-
-static inline dma_addr_t cpm_muram_dma(void __iomem *addr)
-{
- return 0;
-}
-#endif /* defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) */
-
#ifdef CONFIG_CPM
int cpm_command(u32 command, u8 opcode);
#else
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 77f52b26dad6..93ae809fe5ea 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -130,15 +130,6 @@ BEGIN_FTR_SECTION_NESTED(941) \
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,941)
/*
- * Increase the priority on systems where PPR save/restore is not
- * implemented/ supported.
- */
-#define HMT_MEDIUM_PPR_DISCARD \
-BEGIN_FTR_SECTION_NESTED(942) \
- HMT_MEDIUM; \
-END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942) /*non P7*/
-
-/*
* Get an SPR into a register if the CPU has the given feature
*/
#define OPT_GET_SPR(ra, spr, ftr) \
@@ -263,17 +254,6 @@ do_kvm_##n: \
#define KVM_HANDLER_SKIP(area, h, n)
#endif
-#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
-#define KVMTEST_PR(n) __KVMTEST(n)
-#define KVM_HANDLER_PR(area, h, n) __KVM_HANDLER(area, h, n)
-#define KVM_HANDLER_PR_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n)
-
-#else
-#define KVMTEST_PR(n)
-#define KVM_HANDLER_PR(area, h, n)
-#define KVM_HANDLER_PR_SKIP(area, h, n)
-#endif
-
#define NOTEST(n)
/*
@@ -353,27 +333,25 @@ do_kvm_##n: \
/*
* Exception vectors.
*/
-#define STD_EXCEPTION_PSERIES(loc, vec, label) \
- . = loc; \
+#define STD_EXCEPTION_PSERIES(vec, label) \
+ . = vec; \
.globl label##_pSeries; \
label##_pSeries: \
- HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_STD, KVMTEST_PR, vec)
+ EXC_STD, KVMTEST, vec)
/* Version of above for when we have to branch out-of-line */
#define STD_EXCEPTION_PSERIES_OOL(vec, label) \
.globl label##_pSeries; \
label##_pSeries: \
- EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD)
#define STD_EXCEPTION_HV(loc, vec, label) \
. = loc; \
.globl label##_hv; \
label##_hv: \
- HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
EXC_HV, KVMTEST, vec)
@@ -389,7 +367,6 @@ label##_hv: \
. = loc; \
.globl label##_relon_pSeries; \
label##_relon_pSeries: \
- HMT_MEDIUM_PPR_DISCARD; \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
@@ -405,7 +382,6 @@ label##_relon_pSeries: \
. = loc; \
.globl label##_relon_hv; \
label##_relon_hv: \
- HMT_MEDIUM_PPR_DISCARD; \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
@@ -436,17 +412,13 @@ label##_relon_hv: \
#define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec)
#define SOFTEN_TEST_PR(vec) \
- KVMTEST_PR(vec); \
+ KVMTEST(vec); \
_SOFTEN_TEST(EXC_STD, vec)
#define SOFTEN_TEST_HV(vec) \
KVMTEST(vec); \
_SOFTEN_TEST(EXC_HV, vec)
-#define SOFTEN_TEST_HV_201(vec) \
- KVMTEST(vec); \
- _SOFTEN_TEST(EXC_STD, vec)
-
#define SOFTEN_NOTEST_PR(vec) _SOFTEN_TEST(EXC_STD, vec)
#define SOFTEN_NOTEST_HV(vec) _SOFTEN_TEST(EXC_HV, vec)
@@ -463,7 +435,6 @@ label##_relon_hv: \
. = loc; \
.globl label##_pSeries; \
label##_pSeries: \
- HMT_MEDIUM_PPR_DISCARD; \
_MASKABLE_EXCEPTION_PSERIES(vec, label, \
EXC_STD, SOFTEN_TEST_PR)
@@ -481,7 +452,6 @@ label##_hv: \
EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
#define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \
- HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_0(PACA_EXGEN); \
__EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h
index e05808a328db..b0629249778b 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -47,12 +47,10 @@
#define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000)
#define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000)
#define FW_FEATURE_OPAL ASM_CONST(0x0000000010000000)
-#define FW_FEATURE_OPALv2 ASM_CONST(0x0000000020000000)
#define FW_FEATURE_SET_MODE ASM_CONST(0x0000000040000000)
#define FW_FEATURE_BEST_ENERGY ASM_CONST(0x0000000080000000)
#define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)
#define FW_FEATURE_PRRN ASM_CONST(0x0000000200000000)
-#define FW_FEATURE_OPALv3 ASM_CONST(0x0000000400000000)
#ifndef __ASSEMBLY__
@@ -70,8 +68,7 @@ enum {
FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY |
FW_FEATURE_TYPE1_AFFINITY | FW_FEATURE_PRRN,
FW_FEATURE_PSERIES_ALWAYS = 0,
- FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2 |
- FW_FEATURE_OPALv3,
+ FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL,
FW_FEATURE_POWERNV_ALWAYS = 0,
FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
FW_FEATURE_PS3_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 5879fde56f3c..6c1297ec374c 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -385,6 +385,17 @@ static inline void __raw_writeq(unsigned long v, volatile void __iomem *addr)
{
*(volatile unsigned long __force *)PCI_FIX_ADDR(addr) = v;
}
+
+/*
+ * Real mode version of the above. stdcix is only supposed to be used
+ * in hypervisor real mode as per the architecture spec.
+ */
+static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
+{
+ __asm__ __volatile__("stdcix %0,0,%1"
+ : : "r" (val), "r" (paddr) : "memory");
+}
+
#endif /* __powerpc64__ */
/*
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 9fac01cb89c1..8f39796c9da8 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -154,8 +154,8 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
bool upper, u32 val);
extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
-extern pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
- bool *writable);
+extern kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa,
+ bool writing, bool *writable);
extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
unsigned long *rmap, long pte_index, int realmode);
extern void kvmppc_update_rmap_change(unsigned long *rmap, unsigned long psize);
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index c6ef05bd0765..2241d5357129 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -515,7 +515,7 @@ void kvmppc_claim_lpid(long lpid);
void kvmppc_free_lpid(long lpid);
void kvmppc_init_lpid(unsigned long nr_lpids);
-static inline void kvmppc_mmu_flush_icache(pfn_t pfn)
+static inline void kvmppc_mmu_flush_icache(kvm_pfn_t pfn)
{
struct page *page;
/*
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index ba3342bbdbda..7352d3f212df 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -21,7 +21,7 @@
* need for various slices related matters. Note that this isn't the
* complete pgtable.h but only a portion of it.
*/
-#include <asm/pgtable-ppc64.h>
+#include <asm/book3s/64/pgtable.h>
#include <asm/bug.h>
#include <asm/processor.h>
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 9c326565d498..c82cbf52d19e 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PGTABLE_PPC32_H
-#define _ASM_POWERPC_PGTABLE_PPC32_H
+#ifndef _ASM_POWERPC_NOHASH_32_PGTABLE_H
+#define _ASM_POWERPC_NOHASH_32_PGTABLE_H
#include <asm-generic/pgtable-nopmd.h>
@@ -106,17 +106,15 @@ extern int icache_44x_need_flush;
*/
#if defined(CONFIG_40x)
-#include <asm/pte-40x.h>
+#include <asm/nohash/32/pte-40x.h>
#elif defined(CONFIG_44x)
-#include <asm/pte-44x.h>
+#include <asm/nohash/32/pte-44x.h>
#elif defined(CONFIG_FSL_BOOKE) && defined(CONFIG_PTE_64BIT)
-#include <asm/pte-book3e.h>
+#include <asm/nohash/pte-book3e.h>
#elif defined(CONFIG_FSL_BOOKE)
-#include <asm/pte-fsl-booke.h>
+#include <asm/nohash/32/pte-fsl-booke.h>
#elif defined(CONFIG_8xx)
-#include <asm/pte-8xx.h>
-#else /* CONFIG_6xx */
-#include <asm/pte-hash32.h>
+#include <asm/nohash/32/pte-8xx.h>
#endif
/* And here we include common definitions */
@@ -130,7 +128,12 @@ extern int icache_44x_need_flush;
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
#define pmd_present(pmd) (pmd_val(pmd) & _PMD_PRESENT_MASK)
-#define pmd_clear(pmdp) do { pmd_val(*(pmdp)) = 0; } while (0)
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ *pmdp = __pmd(0);
+}
+
+
/*
* When flushing the tlb entry for a page, we also need to flush the hash
@@ -337,4 +340,4 @@ extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep,
#endif /* !__ASSEMBLY__ */
-#endif /* _ASM_POWERPC_PGTABLE_PPC32_H */
+#endif /* __ASM_POWERPC_NOHASH_32_PGTABLE_H */
diff --git a/arch/powerpc/include/asm/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h
index 486b1ef81338..9624ebdacc47 100644
--- a/arch/powerpc/include/asm/pte-40x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PTE_40x_H
-#define _ASM_POWERPC_PTE_40x_H
+#ifndef _ASM_POWERPC_NOHASH_32_PTE_40x_H
+#define _ASM_POWERPC_NOHASH_32_PTE_40x_H
#ifdef __KERNEL__
/*
@@ -61,4 +61,4 @@
#define PTE_ATOMIC_UPDATES 1
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_40x_H */
+#endif /* _ASM_POWERPC_NOHASH_32_PTE_40x_H */
diff --git a/arch/powerpc/include/asm/pte-44x.h b/arch/powerpc/include/asm/nohash/32/pte-44x.h
index 36f75fab23f5..fdab41c654ef 100644
--- a/arch/powerpc/include/asm/pte-44x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-44x.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PTE_44x_H
-#define _ASM_POWERPC_PTE_44x_H
+#ifndef _ASM_POWERPC_NOHASH_32_PTE_44x_H
+#define _ASM_POWERPC_NOHASH_32_PTE_44x_H
#ifdef __KERNEL__
/*
@@ -94,4 +94,4 @@
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_44x_H */
+#endif /* _ASM_POWERPC_NOHASH_32_PTE_44x_H */
diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index a0e2ba960976..3742b1919661 100644
--- a/arch/powerpc/include/asm/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PTE_8xx_H
-#define _ASM_POWERPC_PTE_8xx_H
+#ifndef _ASM_POWERPC_NOHASH_32_PTE_8xx_H
+#define _ASM_POWERPC_NOHASH_32_PTE_8xx_H
#ifdef __KERNEL__
/*
@@ -62,4 +62,4 @@
_PAGE_HWWRITE | _PAGE_EXEC)
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_8xx_H */
+#endif /* _ASM_POWERPC_NOHASH_32_PTE_8xx_H */
diff --git a/arch/powerpc/include/asm/pte-fsl-booke.h b/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h
index 9f5c3d04a1a3..5422d00c6145 100644
--- a/arch/powerpc/include/asm/pte-fsl-booke.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PTE_FSL_BOOKE_H
-#define _ASM_POWERPC_PTE_FSL_BOOKE_H
+#ifndef _ASM_POWERPC_NOHASH_32_PTE_FSL_BOOKE_H
+#define _ASM_POWERPC_NOHASH_32_PTE_FSL_BOOKE_H
#ifdef __KERNEL__
/* PTE bit definitions for Freescale BookE SW loaded TLB MMU based
@@ -37,4 +37,4 @@
#define PTE_WIMGE_SHIFT (6)
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_FSL_BOOKE_H */
+#endif /* _ASM_POWERPC_NOHASH_32_PTE_FSL_BOOKE_H */
diff --git a/arch/powerpc/include/asm/pgtable-ppc64-4k.h b/arch/powerpc/include/asm/nohash/64/pgtable-4k.h
index 132ee1d482c2..fc7d51753f81 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64-4k.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable-4k.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PGTABLE_PPC64_4K_H
-#define _ASM_POWERPC_PGTABLE_PPC64_4K_H
+#ifndef _ASM_POWERPC_NOHASH_64_PGTABLE_4K_H
+#define _ASM_POWERPC_NOHASH_64_PGTABLE_4K_H
/*
* Entries per page directory level. The PTE level must use a 64b record
* for each page table entry. The PMD and PGD level use a 32b record for
@@ -55,11 +55,15 @@
#define pgd_none(pgd) (!pgd_val(pgd))
#define pgd_bad(pgd) (pgd_val(pgd) == 0)
#define pgd_present(pgd) (pgd_val(pgd) != 0)
-#define pgd_clear(pgdp) (pgd_val(*(pgdp)) = 0)
#define pgd_page_vaddr(pgd) (pgd_val(pgd) & ~PGD_MASKED_BITS)
#ifndef __ASSEMBLY__
+static inline void pgd_clear(pgd_t *pgdp)
+{
+ *pgdp = __pgd(0);
+}
+
static inline pte_t pgd_pte(pgd_t pgd)
{
return __pte(pgd_val(pgd));
@@ -85,4 +89,4 @@ extern struct page *pgd_page(pgd_t pgd);
#define remap_4k_pfn(vma, addr, pfn, prot) \
remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot))
-#endif /* _ASM_POWERPC_PGTABLE_PPC64_4K_H */
+#endif /* _ _ASM_POWERPC_NOHASH_64_PGTABLE_4K_H */
diff --git a/arch/powerpc/include/asm/pgtable-ppc64-64k.h b/arch/powerpc/include/asm/nohash/64/pgtable-64k.h
index 1de35bbd02a6..570fb30be21c 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64-64k.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable-64k.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PGTABLE_PPC64_64K_H
-#define _ASM_POWERPC_PGTABLE_PPC64_64K_H
+#ifndef _ASM_POWERPC_NOHASH_64_PGTABLE_64K_H
+#define _ASM_POWERPC_NOHASH_64_PGTABLE_64K_H
#include <asm-generic/pgtable-nopud.h>
@@ -9,8 +9,19 @@
#define PUD_INDEX_SIZE 0
#define PGD_INDEX_SIZE 12
+/*
+ * we support 32 fragments per PTE page of 64K size
+ */
+#define PTE_FRAG_NR 32
+/*
+ * We use a 2K PTE page fragment and another 2K for storing
+ * real_pte_t hash index
+ */
+#define PTE_FRAG_SIZE_SHIFT 11
+#define PTE_FRAG_SIZE (1UL << PTE_FRAG_SIZE_SHIFT)
+
#ifndef __ASSEMBLY__
-#define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE)
+#define PTE_TABLE_SIZE PTE_FRAG_SIZE
#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
#endif /* __ASSEMBLY__ */
@@ -32,13 +43,15 @@
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
-/* Bits to mask out from a PMD to get to the PTE page */
-/* PMDs point to PTE table fragments which are 4K aligned. */
-#define PMD_MASKED_BITS 0xfff
+/*
+ * Bits to mask out from a PMD to get to the PTE page
+ * PMDs point to PTE table fragments which are PTE_FRAG_SIZE aligned.
+ */
+#define PMD_MASKED_BITS (PTE_FRAG_SIZE - 1)
/* Bits to mask out from a PGD/PUD to get to the PMD page */
#define PUD_MASKED_BITS 0x1ff
#define pgd_pte(pgd) (pud_pte(((pud_t){ pgd })))
#define pte_pgd(pte) ((pgd_t)pte_pud(pte))
-#endif /* _ASM_POWERPC_PGTABLE_PPC64_64K_H */
+#endif /* _ASM_POWERPC_NOHASH_64_PGTABLE_64K_H */
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index 3245f2d96d4f..b9f734dd5b81 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -1,14 +1,14 @@
-#ifndef _ASM_POWERPC_PGTABLE_PPC64_H_
-#define _ASM_POWERPC_PGTABLE_PPC64_H_
+#ifndef _ASM_POWERPC_NOHASH_64_PGTABLE_H
+#define _ASM_POWERPC_NOHASH_64_PGTABLE_H
/*
* This file contains the functions and defines necessary to modify and use
* the ppc64 hashed page table.
*/
#ifdef CONFIG_PPC_64K_PAGES
-#include <asm/pgtable-ppc64-64k.h>
+#include <asm/nohash/64/pgtable-64k.h>
#else
-#include <asm/pgtable-ppc64-4k.h>
+#include <asm/nohash/64/pgtable-4k.h>
#endif
#include <asm/barrier.h>
@@ -18,7 +18,7 @@
* Size of EA range mapped by our pagetables.
*/
#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
- PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
+ PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -97,11 +97,7 @@
/*
* Include the PTE bits definitions
*/
-#ifdef CONFIG_PPC_BOOK3S
-#include <asm/pte-hash64.h>
-#else
-#include <asm/pte-book3e.h>
-#endif
+#include <asm/nohash/pte-book3e.h>
#include <asm/pte-common.h>
#ifdef CONFIG_PPC_MM_SLICES
@@ -110,59 +106,47 @@
#endif /* CONFIG_PPC_MM_SLICES */
#ifndef __ASSEMBLY__
-
-/*
- * This is the default implementation of various PTE accessors, it's
- * used in all cases except Book3S with 64K pages where we have a
- * concept of sub-pages
- */
-#ifndef __real_pte
-
-#ifdef CONFIG_STRICT_MM_TYPECHECKS
-#define __real_pte(e,p) ((real_pte_t){(e)})
-#define __rpte_to_pte(r) ((r).pte)
-#else
-#define __real_pte(e,p) (e)
-#define __rpte_to_pte(r) (__pte(r))
-#endif
-#define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >> 12)
-
-#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
- do { \
- index = 0; \
- shift = mmu_psize_defs[psize].shift; \
-
-#define pte_iterate_hashed_end() } while(0)
-
-/*
- * We expect this to be called only for user addresses or kernel virtual
- * addresses other than the linear mapping.
- */
-#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
-
-#endif /* __real_pte */
-
-
/* pte_clear moved to later in this file */
#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
-#define pmd_set(pmdp, pmdval) (pmd_val(*(pmdp)) = (pmdval))
+static inline void pmd_set(pmd_t *pmdp, unsigned long val)
+{
+ *pmdp = __pmd(val);
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ *pmdp = __pmd(0);
+}
+
+static inline pte_t pmd_pte(pmd_t pmd)
+{
+ return __pte(pmd_val(pmd));
+}
+
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (!is_kernel_addr(pmd_val(pmd)) \
|| (pmd_val(pmd) & PMD_BAD_BITS))
#define pmd_present(pmd) (!pmd_none(pmd))
-#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
extern struct page *pmd_page(pmd_t pmd);
-#define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
+static inline void pud_set(pud_t *pudp, unsigned long val)
+{
+ *pudp = __pud(val);
+}
+
+static inline void pud_clear(pud_t *pudp)
+{
+ *pudp = __pud(0);
+}
+
#define pud_none(pud) (!pud_val(pud))
#define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \
|| (pud_val(pud) & PUD_BAD_BITS))
#define pud_present(pud) (pud_val(pud) != 0)
-#define pud_clear(pudp) (pud_val(*(pudp)) = 0)
#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
extern struct page *pud_page(pud_t pud);
@@ -177,9 +161,13 @@ static inline pud_t pte_pud(pte_t pte)
return __pud(pte_val(pte));
}
#define pud_write(pud) pte_write(pud_pte(pud))
-#define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
#define pgd_write(pgd) pte_write(pgd_pte(pgd))
+static inline void pgd_set(pgd_t *pgdp, unsigned long val)
+{
+ *pgdp = __pgd(val);
+}
+
/*
* Find an entry in a page-table-directory. We combine the address region
* (the high order N bits) and the pgd portion of the address.
@@ -373,254 +361,4 @@ void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
void pgtable_cache_init(void);
#endif /* __ASSEMBLY__ */
-/*
- * THP pages can't be special. So use the _PAGE_SPECIAL
- */
-#define _PAGE_SPLITTING _PAGE_SPECIAL
-
-/*
- * We need to differentiate between explicit huge page and THP huge
- * page, since THP huge page also need to track real subpage details
- */
-#define _PAGE_THP_HUGE _PAGE_4K_PFN
-
-/*
- * set of bits not changed in pmd_modify.
- */
-#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | \
- _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPLITTING | \
- _PAGE_THP_HUGE)
-
-#ifndef __ASSEMBLY__
-/*
- * The linux hugepage PMD now include the pmd entries followed by the address
- * to the stashed pgtable_t. The stashed pgtable_t contains the hpte bits.
- * [ 1 bit secondary | 3 bit hidx | 1 bit valid | 000]. We use one byte per
- * each HPTE entry. With 16MB hugepage and 64K HPTE we need 256 entries and
- * with 4K HPTE we need 4096 entries. Both will fit in a 4K pgtable_t.
- *
- * The last three bits are intentionally left to zero. This memory location
- * are also used as normal page PTE pointers. So if we have any pointers
- * left around while we collapse a hugepage, we need to make sure
- * _PAGE_PRESENT bit of that is zero when we look at them
- */
-static inline unsigned int hpte_valid(unsigned char *hpte_slot_array, int index)
-{
- return (hpte_slot_array[index] >> 3) & 0x1;
-}
-
-static inline unsigned int hpte_hash_index(unsigned char *hpte_slot_array,
- int index)
-{
- return hpte_slot_array[index] >> 4;
-}
-
-static inline void mark_hpte_slot_valid(unsigned char *hpte_slot_array,
- unsigned int index, unsigned int hidx)
-{
- hpte_slot_array[index] = hidx << 4 | 0x1 << 3;
-}
-
-struct page *realmode_pfn_to_page(unsigned long pfn);
-
-static inline char *get_hpte_slot_array(pmd_t *pmdp)
-{
- /*
- * The hpte hindex is stored in the pgtable whose address is in the
- * second half of the PMD
- *
- * Order this load with the test for pmd_trans_huge in the caller
- */
- smp_rmb();
- return *(char **)(pmdp + PTRS_PER_PMD);
-
-
-}
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-extern void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp, unsigned long old_pmd);
-extern pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot);
-extern pmd_t mk_pmd(struct page *page, pgprot_t pgprot);
-extern pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot);
-extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp, pmd_t pmd);
-extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
- pmd_t *pmd);
-/*
- *
- * For core kernel code by design pmd_trans_huge is never run on any hugetlbfs
- * page. The hugetlbfs page table walking and mangling paths are totally
- * separated form the core VM paths and they're differentiated by
- * VM_HUGETLB being set on vm_flags well before any pmd_trans_huge could run.
- *
- * pmd_trans_huge() is defined as false at build time if
- * CONFIG_TRANSPARENT_HUGEPAGE=n to optimize away code blocks at build
- * time in such case.
- *
- * For ppc64 we need to differntiate from explicit hugepages from THP, because
- * for THP we also track the subpage details at the pmd level. We don't do
- * that for explicit huge pages.
- *
- */
-static inline int pmd_trans_huge(pmd_t pmd)
-{
- /*
- * leaf pte for huge page, bottom two bits != 00
- */
- return (pmd_val(pmd) & 0x3) && (pmd_val(pmd) & _PAGE_THP_HUGE);
-}
-
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- if (pmd_trans_huge(pmd))
- return pmd_val(pmd) & _PAGE_SPLITTING;
- return 0;
-}
-
-extern int has_transparent_hugepage(void);
-#else
-static inline void hpte_do_hugepage_flush(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmdp,
- unsigned long old_pmd)
-{
-
- WARN(1, "%s called with THP disabled\n", __func__);
-}
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-
-static inline int pmd_large(pmd_t pmd)
-{
- /*
- * leaf pte for huge page, bottom two bits != 00
- */
- return ((pmd_val(pmd) & 0x3) != 0x0);
-}
-
-static inline pte_t pmd_pte(pmd_t pmd)
-{
- return __pte(pmd_val(pmd));
-}
-
-static inline pmd_t pte_pmd(pte_t pte)
-{
- return __pmd(pte_val(pte));
-}
-
-static inline pte_t *pmdp_ptep(pmd_t *pmd)
-{
- return (pte_t *)pmd;
-}
-
-#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
-#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
-#define pmd_young(pmd) pte_young(pmd_pte(pmd))
-#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
-#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
-#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
-#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
-#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
-
-#define __HAVE_ARCH_PMD_WRITE
-#define pmd_write(pmd) pte_write(pmd_pte(pmd))
-
-static inline pmd_t pmd_mkhuge(pmd_t pmd)
-{
- /* Do nothing, mk_pmd() does this part. */
- return pmd;
-}
-
-static inline pmd_t pmd_mknotpresent(pmd_t pmd)
-{
- pmd_val(pmd) &= ~_PAGE_PRESENT;
- return pmd;
-}
-
-static inline pmd_t pmd_mksplitting(pmd_t pmd)
-{
- pmd_val(pmd) |= _PAGE_SPLITTING;
- return pmd;
-}
-
-#define __HAVE_ARCH_PMD_SAME
-static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
-{
- return (((pmd_val(pmd_a) ^ pmd_val(pmd_b)) & ~_PAGE_HPTEFLAGS) == 0);
-}
-
-#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
-extern int pmdp_set_access_flags(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp,
- pmd_t entry, int dirty);
-
-extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
- unsigned long addr,
- pmd_t *pmdp,
- unsigned long clr,
- unsigned long set);
-
-static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmdp)
-{
- unsigned long old;
-
- if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
- return 0;
- old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0);
- return ((old & _PAGE_ACCESSED) != 0);
-}
-
-#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
-extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp);
-#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
-extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp);
-
-#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
-extern pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmdp);
-
-#define __HAVE_ARCH_PMDP_SET_WRPROTECT
-static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp)
-{
-
- if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
- return;
-
- pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
-}
-
-#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-extern void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp);
-
-extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp);
-#define pmdp_collapse_flush pmdp_collapse_flush
-
-#define __HAVE_ARCH_PGTABLE_DEPOSIT
-extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
- pgtable_t pgtable);
-#define __HAVE_ARCH_PGTABLE_WITHDRAW
-extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
-
-#define __HAVE_ARCH_PMDP_INVALIDATE
-extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp);
-
-#define pmd_move_must_withdraw pmd_move_must_withdraw
-struct spinlock;
-static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
- struct spinlock *old_pmd_ptl)
-{
- /*
- * Archs like ppc64 use pgtable to store per pmd
- * specific information. So when we switch the pmd,
- * we should also withdraw and deposit the pgtable
- */
- return true;
-}
-#endif /* __ASSEMBLY__ */
-#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
+#endif /* _ASM_POWERPC_NOHASH_64_PGTABLE_H */
diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h
new file mode 100644
index 000000000000..1263c22d60d8
--- /dev/null
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -0,0 +1,252 @@
+#ifndef _ASM_POWERPC_NOHASH_PGTABLE_H
+#define _ASM_POWERPC_NOHASH_PGTABLE_H
+
+#if defined(CONFIG_PPC64)
+#include <asm/nohash/64/pgtable.h>
+#else
+#include <asm/nohash/32/pgtable.h>
+#endif
+
+#ifndef __ASSEMBLY__
+
+/* Generic accessors to PTE bits */
+static inline int pte_write(pte_t pte)
+{
+ return (pte_val(pte) & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO;
+}
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
+static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
+static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
+
+#ifdef CONFIG_NUMA_BALANCING
+/*
+ * These work without NUMA balancing but the kernel does not care. See the
+ * comment in include/asm-generic/pgtable.h . On powerpc, this will only
+ * work for user pages and always return true for kernel pages.
+ */
+static inline int pte_protnone(pte_t pte)
+{
+ return (pte_val(pte) &
+ (_PAGE_PRESENT | _PAGE_USER)) == _PAGE_PRESENT;
+}
+
+static inline int pmd_protnone(pmd_t pmd)
+{
+ return pte_protnone(pmd_pte(pmd));
+}
+#endif /* CONFIG_NUMA_BALANCING */
+
+static inline int pte_present(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_PRESENT;
+}
+
+/* Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * Even if PTEs can be unsigned long long, a PFN is always an unsigned
+ * long for now.
+ */
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) {
+ return __pte(((pte_basic_t)(pfn) << PTE_RPN_SHIFT) |
+ pgprot_val(pgprot)); }
+static inline unsigned long pte_pfn(pte_t pte) {
+ return pte_val(pte) >> PTE_RPN_SHIFT; }
+
+/* Generic modifiers for PTE bits */
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+ pte_basic_t ptev;
+
+ ptev = pte_val(pte) & ~(_PAGE_RW | _PAGE_HWWRITE);
+ ptev |= _PAGE_RO;
+ return __pte(ptev);
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~(_PAGE_DIRTY | _PAGE_HWWRITE));
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+ return __pte(pte_val(pte) & ~_PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+ pte_basic_t ptev;
+
+ ptev = pte_val(pte) & ~_PAGE_RO;
+ ptev |= _PAGE_RW;
+ return __pte(ptev);
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_DIRTY);
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_ACCESSED);
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return __pte(pte_val(pte) | _PAGE_SPECIAL);
+}
+
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+ return pte;
+}
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
+}
+
+/* Insert a PTE, top-level function is out of line. It uses an inline
+ * low level function in the respective pgtable-* files
+ */
+extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+ pte_t pte);
+
+/* This low level function performs the actual PTE insertion
+ * Setting the PTE depends on the MMU type and other factors. It's
+ * an horrible mess that I'm not going to try to clean up now but
+ * I'm keeping it in one place rather than spread around
+ */
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, int percpu)
+{
+#if defined(CONFIG_PPC_STD_MMU_32) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
+ /* First case is 32-bit Hash MMU in SMP mode with 32-bit PTEs. We use the
+ * helper pte_update() which does an atomic update. We need to do that
+ * because a concurrent invalidation can clear _PAGE_HASHPTE. If it's a
+ * per-CPU PTE such as a kmap_atomic, we do a simple update preserving
+ * the hash bits instead (ie, same as the non-SMP case)
+ */
+ if (percpu)
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+ else
+ pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte));
+
+#elif defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
+ /* Second case is 32-bit with 64-bit PTE. In this case, we
+ * can just store as long as we do the two halves in the right order
+ * with a barrier in between. This is possible because we take care,
+ * in the hash code, to pre-invalidate if the PTE was already hashed,
+ * which synchronizes us with any concurrent invalidation.
+ * In the percpu case, we also fallback to the simple update preserving
+ * the hash bits
+ */
+ if (percpu) {
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+ return;
+ }
+#if _PAGE_HASHPTE != 0
+ if (pte_val(*ptep) & _PAGE_HASHPTE)
+ flush_hash_entry(mm, ptep, addr);
+#endif
+ __asm__ __volatile__("\
+ stw%U0%X0 %2,%0\n\
+ eieio\n\
+ stw%U0%X0 %L2,%1"
+ : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
+ : "r" (pte) : "memory");
+
+#elif defined(CONFIG_PPC_STD_MMU_32)
+ /* Third case is 32-bit hash table in UP mode, we need to preserve
+ * the _PAGE_HASHPTE bit since we may not have invalidated the previous
+ * translation in the hash yet (done in a subsequent flush_tlb_xxx())
+ * and see we need to keep track that this PTE needs invalidating
+ */
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+
+#else
+ /* Anything else just stores the PTE normally. That covers all 64-bit
+ * cases, and 32-bit non-hash with 32-bit PTEs.
+ */
+ *ptep = pte;
+
+#ifdef CONFIG_PPC_BOOK3E_64
+ /*
+ * With hardware tablewalk, a sync is needed to ensure that
+ * subsequent accesses see the PTE we just wrote. Unlike userspace
+ * mappings, we can't tolerate spurious faults, so make sure
+ * the new PTE will be seen the first time.
+ */
+ if (is_kernel_addr(addr))
+ mb();
+#endif
+#endif
+}
+
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+ pte_t *ptep, pte_t entry, int dirty);
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+
+#define _PAGE_CACHE_CTL (_PAGE_COHERENT | _PAGE_GUARDED | _PAGE_NO_CACHE | \
+ _PAGE_WRITETHRU)
+
+#define pgprot_noncached(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+ _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+#define pgprot_noncached_wc(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+ _PAGE_NO_CACHE))
+
+#define pgprot_cached(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+ _PAGE_COHERENT))
+
+#define pgprot_cached_wthru(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+ _PAGE_COHERENT | _PAGE_WRITETHRU))
+
+#define pgprot_cached_noncoherent(prot) \
+ (__pgprot(pgprot_val(prot) & ~_PAGE_CACHE_CTL))
+
+#define pgprot_writecombine pgprot_noncached_wc
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#ifdef CONFIG_HUGETLB_PAGE
+static inline int hugepd_ok(hugepd_t hpd)
+{
+ return (hpd.pd > 0);
+}
+
+static inline int pmd_huge(pmd_t pmd)
+{
+ return 0;
+}
+
+static inline int pud_huge(pud_t pud)
+{
+ return 0;
+}
+
+static inline int pgd_huge(pgd_t pgd)
+{
+ return 0;
+}
+#define pgd_huge pgd_huge
+
+#define is_hugepd(hpd) (hugepd_ok(hpd))
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/nohash/pte-book3e.h
index 8d8473278d91..e16807b78edf 100644
--- a/arch/powerpc/include/asm/pte-book3e.h
+++ b/arch/powerpc/include/asm/nohash/pte-book3e.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_PTE_BOOK3E_H
-#define _ASM_POWERPC_PTE_BOOK3E_H
+#ifndef _ASM_POWERPC_NOHASH_PTE_BOOK3E_H
+#define _ASM_POWERPC_NOHASH_PTE_BOOK3E_H
#ifdef __KERNEL__
/* PTE bit definitions for processors compliant to the Book3E
@@ -84,4 +84,4 @@
#endif
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_FSL_BOOKE_H */
+#endif /* _ASM_POWERPC_NOHASH_PTE_BOOK3E_H */
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 8374afed9d0a..f8faaaeeca1e 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -157,7 +157,8 @@
#define OPAL_LEDS_GET_INDICATOR 114
#define OPAL_LEDS_SET_INDICATOR 115
#define OPAL_CEC_REBOOT2 116
-#define OPAL_LAST 116
+#define OPAL_CONSOLE_FLUSH 117
+#define OPAL_LAST 117
/* Device tree flags */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 800115910e43..07a99e638449 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -35,6 +35,7 @@ int64_t opal_console_read(int64_t term_number, __be64 *length,
uint8_t *buffer);
int64_t opal_console_write_buffer_space(int64_t term_number,
__be64 *length);
+int64_t opal_console_flush(int64_t term_number);
int64_t opal_rtc_read(__be32 *year_month_day,
__be64 *hour_minute_second_millisecond);
int64_t opal_rtc_write(uint32_t year_month_day,
@@ -262,6 +263,8 @@ extern int opal_resync_timebase(void);
extern void opal_lpc_init(void);
+extern void opal_kmsg_init(void);
+
extern int opal_event_request(unsigned int opal_event_nr);
struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 70bd4381f8e6..546540b91095 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -16,6 +16,7 @@
#ifdef CONFIG_PPC64
+#include <linux/string.h>
#include <asm/types.h>
#include <asm/lppaca.h>
#include <asm/mmu.h>
@@ -131,7 +132,16 @@ struct paca_struct {
struct tlb_core_data tcd;
#endif /* CONFIG_PPC_BOOK3E */
- mm_context_t context;
+#ifdef CONFIG_PPC_BOOK3S
+ mm_context_id_t mm_ctx_id;
+#ifdef CONFIG_PPC_MM_SLICES
+ u64 mm_ctx_low_slices_psize;
+ unsigned char mm_ctx_high_slices_psize[SLICE_ARRAY_SIZE];
+#else
+ u16 mm_ctx_user_psize;
+ u16 mm_ctx_sllp;
+#endif
+#endif
/*
* then miscellaneous read-write fields
@@ -194,6 +204,23 @@ struct paca_struct {
#endif
};
+#ifdef CONFIG_PPC_BOOK3S
+static inline void copy_mm_to_paca(mm_context_t *context)
+{
+ get_paca()->mm_ctx_id = context->id;
+#ifdef CONFIG_PPC_MM_SLICES
+ get_paca()->mm_ctx_low_slices_psize = context->low_slices_psize;
+ memcpy(&get_paca()->mm_ctx_high_slices_psize,
+ &context->high_slices_psize, SLICE_ARRAY_SIZE);
+#else
+ get_paca()->mm_ctx_user_psize = context->user_psize;
+ get_paca()->mm_ctx_sllp = context->sllp;
+#endif
+}
+#else
+static inline void copy_mm_to_paca(mm_context_t *context){}
+#endif
+
extern struct paca_struct *paca;
extern void initialise_paca(struct paca_struct *new_paca, int cpu);
extern void setup_paca(struct paca_struct *new_paca);
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 3140c19c448c..e34124f6fbf2 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -286,8 +286,11 @@ extern long long virt_phys_offset;
/* PTE level */
typedef struct { pte_basic_t pte; } pte_t;
-#define pte_val(x) ((x).pte)
#define __pte(x) ((pte_t) { (x) })
+static inline pte_basic_t pte_val(pte_t x)
+{
+ return x.pte;
+}
/* 64k pages additionally define a bigger "real PTE" type that gathers
* the "second half" part of the PTE for pseudo 64k pages
@@ -301,21 +304,30 @@ typedef struct { pte_t pte; } real_pte_t;
/* PMD level */
#ifdef CONFIG_PPC64
typedef struct { unsigned long pmd; } pmd_t;
-#define pmd_val(x) ((x).pmd)
#define __pmd(x) ((pmd_t) { (x) })
+static inline unsigned long pmd_val(pmd_t x)
+{
+ return x.pmd;
+}
/* PUD level exusts only on 4k pages */
#ifndef CONFIG_PPC_64K_PAGES
typedef struct { unsigned long pud; } pud_t;
-#define pud_val(x) ((x).pud)
#define __pud(x) ((pud_t) { (x) })
+static inline unsigned long pud_val(pud_t x)
+{
+ return x.pud;
+}
#endif /* !CONFIG_PPC_64K_PAGES */
#endif /* CONFIG_PPC64 */
/* PGD level */
typedef struct { unsigned long pgd; } pgd_t;
-#define pgd_val(x) ((x).pgd)
#define __pgd(x) ((pgd_t) { (x) })
+static inline unsigned long pgd_val(pgd_t x)
+{
+ return x.pgd;
+}
/* Page protection bits */
typedef struct { unsigned long pgprot; } pgprot_t;
@@ -329,8 +341,11 @@ typedef struct { unsigned long pgprot; } pgprot_t;
*/
typedef pte_basic_t pte_t;
-#define pte_val(x) (x)
#define __pte(x) (x)
+static inline pte_basic_t pte_val(pte_t pte)
+{
+ return pte;
+}
#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64)
typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
@@ -341,67 +356,42 @@ typedef pte_t real_pte_t;
#ifdef CONFIG_PPC64
typedef unsigned long pmd_t;
-#define pmd_val(x) (x)
#define __pmd(x) (x)
+static inline unsigned long pmd_val(pmd_t pmd)
+{
+ return pmd;
+}
#ifndef CONFIG_PPC_64K_PAGES
typedef unsigned long pud_t;
-#define pud_val(x) (x)
#define __pud(x) (x)
+static inline unsigned long pud_val(pud_t pud)
+{
+ return pud;
+}
#endif /* !CONFIG_PPC_64K_PAGES */
#endif /* CONFIG_PPC64 */
typedef unsigned long pgd_t;
-#define pgd_val(x) (x)
-#define pgprot_val(x) (x)
+#define __pgd(x) (x)
+static inline unsigned long pgd_val(pgd_t pgd)
+{
+ return pgd;
+}
typedef unsigned long pgprot_t;
-#define __pgd(x) (x)
+#define pgprot_val(x) (x)
#define __pgprot(x) (x)
#endif
typedef struct { signed long pd; } hugepd_t;
-#ifdef CONFIG_HUGETLB_PAGE
-#ifdef CONFIG_PPC_BOOK3S_64
-#ifdef CONFIG_PPC_64K_PAGES
-/*
- * With 64k page size, we have hugepage ptes in the pgd and pmd entries. We don't
- * need to setup hugepage directory for them. Our pte and page directory format
- * enable us to have this enabled. But to avoid errors when implementing new
- * features disable hugepd for 64K. We enable a debug version here, So we catch
- * wrong usage.
- */
-#ifdef CONFIG_DEBUG_VM
-extern int hugepd_ok(hugepd_t hpd);
-#else
-#define hugepd_ok(x) (0)
-#endif
-#else
-static inline int hugepd_ok(hugepd_t hpd)
-{
- /*
- * hugepd pointer, bottom two bits == 00 and next 4 bits
- * indicate size of table
- */
- return (((hpd.pd & 0x3) == 0x0) && ((hpd.pd & HUGEPD_SHIFT_MASK) != 0));
-}
-#endif
-#else
-static inline int hugepd_ok(hugepd_t hpd)
-{
- return (hpd.pd > 0);
-}
-#endif
-
-#define is_hugepd(hpd) (hugepd_ok(hpd))
-#define pgd_huge pgd_huge
-int pgd_huge(pgd_t pgd);
-#else /* CONFIG_HUGETLB_PAGE */
-#define is_hugepd(pdep) 0
-#define pgd_huge(pgd) 0
+#ifndef CONFIG_HUGETLB_PAGE
+#define is_hugepd(pdep) (0)
+#define pgd_huge(pgd) (0)
#endif /* CONFIG_HUGETLB_PAGE */
+
#define __hugepd(x) ((hugepd_t) { (x) })
struct page;
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 37fc53587bb4..54843ca5fa2b 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -205,6 +205,7 @@ struct pci_dn {
int pci_ext_config_space; /* for pci devices */
+ struct pci_dev *pcidev; /* back-pointer to the pci device */
#ifdef CONFIG_EEH
struct eeh_dev *edev; /* eeh device */
#endif
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 3453bd8dc18f..6f8065a7d487 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -149,4 +149,8 @@ extern void pcibios_setup_phb_io_space(struct pci_controller *hose);
extern void pcibios_scan_phb(struct pci_controller *hose);
#endif /* __KERNEL__ */
+
+extern struct pci_dev *pnv_pci_get_gpu_dev(struct pci_dev *npdev);
+extern struct pci_dev *pnv_pci_get_npu_dev(struct pci_dev *gpdev, int index);
+
#endif /* __ASM_POWERPC_PCI_H */
diff --git a/arch/powerpc/include/asm/pgalloc-32.h b/arch/powerpc/include/asm/pgalloc-32.h
index 842846c1b711..76d6b9e0c8a9 100644
--- a/arch/powerpc/include/asm/pgalloc-32.h
+++ b/arch/powerpc/include/asm/pgalloc-32.h
@@ -21,16 +21,34 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
/* #define pgd_populate(mm, pmd, pte) BUG() */
#ifndef CONFIG_BOOKE
-#define pmd_populate_kernel(mm, pmd, pte) \
- (pmd_val(*(pmd)) = __pa(pte) | _PMD_PRESENT)
-#define pmd_populate(mm, pmd, pte) \
- (pmd_val(*(pmd)) = (page_to_pfn(pte) << PAGE_SHIFT) | _PMD_PRESENT)
+
+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp,
+ pte_t *pte)
+{
+ *pmdp = __pmd(__pa(pte) | _PMD_PRESENT);
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pte_page)
+{
+ *pmdp = __pmd((page_to_pfn(pte_page) << PAGE_SHIFT) | _PMD_PRESENT);
+}
+
#define pmd_pgtable(pmd) pmd_page(pmd)
#else
-#define pmd_populate_kernel(mm, pmd, pte) \
- (pmd_val(*(pmd)) = (unsigned long)pte | _PMD_PRESENT)
-#define pmd_populate(mm, pmd, pte) \
- (pmd_val(*(pmd)) = (unsigned long)lowmem_page_address(pte) | _PMD_PRESENT)
+
+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp,
+ pte_t *pte)
+{
+ *pmdp = __pmd((unsigned long)pte | _PMD_PRESENT);
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pte_page)
+{
+ *pmdp = __pmd((unsigned long)lowmem_page_address(pte_page) | _PMD_PRESENT);
+}
+
#define pmd_pgtable(pmd) pmd_page(pmd)
#endif
diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
index 4b0be20fcbfd..69ef28a81733 100644
--- a/arch/powerpc/include/asm/pgalloc-64.h
+++ b/arch/powerpc/include/asm/pgalloc-64.h
@@ -53,7 +53,7 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
#ifndef CONFIG_PPC_64K_PAGES
-#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD)
+#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, (unsigned long)PUD)
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
@@ -71,9 +71,18 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
pud_set(pud, (unsigned long)pmd);
}
-#define pmd_populate(mm, pmd, pte_page) \
- pmd_populate_kernel(mm, pmd, page_address(pte_page))
-#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte))
+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
+ pte_t *pte)
+{
+ pmd_set(pmd, (unsigned long)pte);
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+ pgtable_t pte_page)
+{
+ pmd_set(pmd, (unsigned long)page_address(pte_page));
+}
+
#define pmd_pgtable(pmd) pmd_page(pmd)
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
@@ -154,16 +163,6 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
}
#else /* if CONFIG_PPC_64K_PAGES */
-/*
- * we support 16 fragments per PTE page.
- */
-#define PTE_FRAG_NR 16
-/*
- * We use a 2K PTE page fragment and another 2K for storing
- * real_pte_t hash index
- */
-#define PTE_FRAG_SIZE_SHIFT 12
-#define PTE_FRAG_SIZE (2 * PTRS_PER_PTE * sizeof(pte_t))
extern pte_t *page_table_alloc(struct mm_struct *, unsigned long, int);
extern void page_table_free(struct mm_struct *, unsigned long *, int);
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index b64b4212b71f..ac9fb114e25d 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -1,6 +1,5 @@
#ifndef _ASM_POWERPC_PGTABLE_H
#define _ASM_POWERPC_PGTABLE_H
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#include <linux/mmdebug.h>
@@ -13,210 +12,20 @@ struct mm_struct;
#endif /* !__ASSEMBLY__ */
-#if defined(CONFIG_PPC64)
-# include <asm/pgtable-ppc64.h>
+#ifdef CONFIG_PPC_BOOK3S
+#include <asm/book3s/pgtable.h>
#else
-# include <asm/pgtable-ppc32.h>
-#endif
-
-/*
- * We save the slot number & secondary bit in the second half of the
- * PTE page. We use the 8 bytes per each pte entry.
- */
-#define PTE_PAGE_HIDX_OFFSET (PTRS_PER_PTE * 8)
+#include <asm/nohash/pgtable.h>
+#endif /* !CONFIG_PPC_BOOK3S */
#ifndef __ASSEMBLY__
#include <asm/tlbflush.h>
-/* Generic accessors to PTE bits */
-static inline int pte_write(pte_t pte)
-{ return (pte_val(pte) & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO; }
-static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
-static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
-static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
-static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
-
-#ifdef CONFIG_NUMA_BALANCING
-/*
- * These work without NUMA balancing but the kernel does not care. See the
- * comment in include/asm-generic/pgtable.h . On powerpc, this will only
- * work for user pages and always return true for kernel pages.
- */
-static inline int pte_protnone(pte_t pte)
-{
- return (pte_val(pte) &
- (_PAGE_PRESENT | _PAGE_USER)) == _PAGE_PRESENT;
-}
-
-static inline int pmd_protnone(pmd_t pmd)
-{
- return pte_protnone(pmd_pte(pmd));
-}
-#endif /* CONFIG_NUMA_BALANCING */
-
-static inline int pte_present(pte_t pte)
-{
- return pte_val(pte) & _PAGE_PRESENT;
-}
-
-/* Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- *
- * Even if PTEs can be unsigned long long, a PFN is always an unsigned
- * long for now.
- */
-static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) {
- return __pte(((pte_basic_t)(pfn) << PTE_RPN_SHIFT) |
- pgprot_val(pgprot)); }
-static inline unsigned long pte_pfn(pte_t pte) {
- return pte_val(pte) >> PTE_RPN_SHIFT; }
-
/* Keep these as a macros to avoid include dependency mess */
#define pte_page(x) pfn_to_page(pte_pfn(x))
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
-/* Generic modifiers for PTE bits */
-static inline pte_t pte_wrprotect(pte_t pte) {
- pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE);
- pte_val(pte) |= _PAGE_RO; return pte; }
-static inline pte_t pte_mkclean(pte_t pte) {
- pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
-static inline pte_t pte_mkold(pte_t pte) {
- pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkwrite(pte_t pte) {
- pte_val(pte) &= ~_PAGE_RO;
- pte_val(pte) |= _PAGE_RW; return pte; }
-static inline pte_t pte_mkdirty(pte_t pte) {
- pte_val(pte) |= _PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkyoung(pte_t pte) {
- pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkspecial(pte_t pte) {
- pte_val(pte) |= _PAGE_SPECIAL; return pte; }
-static inline pte_t pte_mkhuge(pte_t pte) {
- return pte; }
-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
- pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
- return pte;
-}
-
-
-/* Insert a PTE, top-level function is out of line. It uses an inline
- * low level function in the respective pgtable-* files
- */
-extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
- pte_t pte);
-
-/* This low level function performs the actual PTE insertion
- * Setting the PTE depends on the MMU type and other factors. It's
- * an horrible mess that I'm not going to try to clean up now but
- * I'm keeping it in one place rather than spread around
- */
-static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pte, int percpu)
-{
-#if defined(CONFIG_PPC_STD_MMU_32) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
- /* First case is 32-bit Hash MMU in SMP mode with 32-bit PTEs. We use the
- * helper pte_update() which does an atomic update. We need to do that
- * because a concurrent invalidation can clear _PAGE_HASHPTE. If it's a
- * per-CPU PTE such as a kmap_atomic, we do a simple update preserving
- * the hash bits instead (ie, same as the non-SMP case)
- */
- if (percpu)
- *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
- | (pte_val(pte) & ~_PAGE_HASHPTE));
- else
- pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte));
-
-#elif defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
- /* Second case is 32-bit with 64-bit PTE. In this case, we
- * can just store as long as we do the two halves in the right order
- * with a barrier in between. This is possible because we take care,
- * in the hash code, to pre-invalidate if the PTE was already hashed,
- * which synchronizes us with any concurrent invalidation.
- * In the percpu case, we also fallback to the simple update preserving
- * the hash bits
- */
- if (percpu) {
- *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
- | (pte_val(pte) & ~_PAGE_HASHPTE));
- return;
- }
-#if _PAGE_HASHPTE != 0
- if (pte_val(*ptep) & _PAGE_HASHPTE)
- flush_hash_entry(mm, ptep, addr);
-#endif
- __asm__ __volatile__("\
- stw%U0%X0 %2,%0\n\
- eieio\n\
- stw%U0%X0 %L2,%1"
- : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
- : "r" (pte) : "memory");
-
-#elif defined(CONFIG_PPC_STD_MMU_32)
- /* Third case is 32-bit hash table in UP mode, we need to preserve
- * the _PAGE_HASHPTE bit since we may not have invalidated the previous
- * translation in the hash yet (done in a subsequent flush_tlb_xxx())
- * and see we need to keep track that this PTE needs invalidating
- */
- *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
- | (pte_val(pte) & ~_PAGE_HASHPTE));
-
-#else
- /* Anything else just stores the PTE normally. That covers all 64-bit
- * cases, and 32-bit non-hash with 32-bit PTEs.
- */
- *ptep = pte;
-
-#ifdef CONFIG_PPC_BOOK3E_64
- /*
- * With hardware tablewalk, a sync is needed to ensure that
- * subsequent accesses see the PTE we just wrote. Unlike userspace
- * mappings, we can't tolerate spurious faults, so make sure
- * the new PTE will be seen the first time.
- */
- if (is_kernel_addr(addr))
- mb();
-#endif
-#endif
-}
-
-
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
- pte_t *ptep, pte_t entry, int dirty);
-
-/*
- * Macro to mark a page protection value as "uncacheable".
- */
-
-#define _PAGE_CACHE_CTL (_PAGE_COHERENT | _PAGE_GUARDED | _PAGE_NO_CACHE | \
- _PAGE_WRITETHRU)
-
-#define pgprot_noncached(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
- _PAGE_NO_CACHE | _PAGE_GUARDED))
-
-#define pgprot_noncached_wc(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
- _PAGE_NO_CACHE))
-
-#define pgprot_cached(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
- _PAGE_COHERENT))
-
-#define pgprot_cached_wthru(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
- _PAGE_COHERENT | _PAGE_WRITETHRU))
-
-#define pgprot_cached_noncoherent(prot) \
- (__pgprot(pgprot_val(prot) & ~_PAGE_CACHE_CTL))
-
-#define pgprot_writecombine pgprot_noncached_wc
-
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
- unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
@@ -271,5 +80,4 @@ static inline pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
}
#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
index 67859edbf8fd..1b394247afc2 100644
--- a/arch/powerpc/include/asm/plpar_wrappers.h
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -202,6 +202,23 @@ static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
}
/*
+ * ptes must be 8*sizeof(unsigned long)
+ */
+static inline long plpar_pte_read_4(unsigned long flags, unsigned long ptex,
+ unsigned long *ptes)
+
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+ rc = plpar_hcall9(H_READ, retbuf, flags | H_READ_4, ptex);
+
+ memcpy(ptes, retbuf, 8*sizeof(unsigned long));
+
+ return rc;
+}
+
+/*
* plpar_pte_read_4_raw can be called in real mode.
* ptes must be 8*sizeof(unsigned long)
*/
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index dd0fc18d8103..499d9f89435a 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -413,24 +413,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
FTR_SECTION_ELSE_NESTED(848); \
mtocrf (FXM), RS; \
ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
-
-/*
- * PPR restore macros used in entry_64.S
- * Used for P7 or later processors
- */
-#define HMT_MEDIUM_LOW_HAS_PPR \
-BEGIN_FTR_SECTION_NESTED(944) \
- HMT_MEDIUM_LOW; \
-END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,944)
-
-#define SET_DEFAULT_THREAD_PPR(ra, rb) \
-BEGIN_FTR_SECTION_NESTED(945) \
- lis ra,INIT_PPR@highest; /* default ppr=3 */ \
- ld rb,PACACURRENT(r13); \
- sldi ra,ra,32; /* 11- 13 bits are used for ppr */ \
- std ra,TASKTHREADPPR(rb); \
-END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945)
-
#endif
/*
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 5afea361beaa..ac2330820b9a 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -88,12 +88,6 @@ struct task_struct;
void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
void release_thread(struct task_struct *);
-/* Lazy FPU handling on uni-processor */
-extern struct task_struct *last_task_used_math;
-extern struct task_struct *last_task_used_altivec;
-extern struct task_struct *last_task_used_vsx;
-extern struct task_struct *last_task_used_spe;
-
#ifdef CONFIG_PPC32
#if CONFIG_TASK_SIZE > CONFIG_KERNEL_START
@@ -294,6 +288,7 @@ struct thread_struct {
#endif
#ifdef CONFIG_PPC64
unsigned long dscr;
+ unsigned long fscr;
/*
* This member element dscr_inherit indicates that the process
* has explicitly attempted and changed the DSCR register value
@@ -385,8 +380,6 @@ extern int set_endian(struct task_struct *tsk, unsigned int val);
extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr);
extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
-extern void fp_enable(void);
-extern void vec_enable(void);
extern void load_fp_state(struct thread_fp_state *fp);
extern void store_fp_state(struct thread_fp_state *fp);
extern void load_vr_state(struct thread_vr_state *vr);
diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h
index 71537a319fc8..1ec67b043065 100644
--- a/arch/powerpc/include/asm/pte-common.h
+++ b/arch/powerpc/include/asm/pte-common.h
@@ -40,6 +40,11 @@
#else
#define _PAGE_RW 0
#endif
+
+#ifndef _PAGE_PTE
+#define _PAGE_PTE 0
+#endif
+
#ifndef _PMD_PRESENT_MASK
#define _PMD_PRESENT_MASK _PMD_PRESENT
#endif
diff --git a/arch/powerpc/include/asm/pte-hash64-4k.h b/arch/powerpc/include/asm/pte-hash64-4k.h
deleted file mode 100644
index c134e809aac3..000000000000
--- a/arch/powerpc/include/asm/pte-hash64-4k.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* To be include by pgtable-hash64.h only */
-
-/* PTE bits */
-#define _PAGE_HASHPTE 0x0400 /* software: pte has an associated HPTE */
-#define _PAGE_SECONDARY 0x8000 /* software: HPTE is in secondary group */
-#define _PAGE_GROUP_IX 0x7000 /* software: HPTE index within group */
-#define _PAGE_F_SECOND _PAGE_SECONDARY
-#define _PAGE_F_GIX _PAGE_GROUP_IX
-#define _PAGE_SPECIAL 0x10000 /* software: special page */
-
-/* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | \
- _PAGE_SECONDARY | _PAGE_GROUP_IX)
-
-/* shift to put page number into pte */
-#define PTE_RPN_SHIFT (17)
-
diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h
deleted file mode 100644
index 4f4ec2ab45c9..000000000000
--- a/arch/powerpc/include/asm/pte-hash64-64k.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* To be include by pgtable-hash64.h only */
-
-/* Additional PTE bits (don't change without checking asm in hash_low.S) */
-#define _PAGE_SPECIAL 0x00000400 /* software: special page */
-#define _PAGE_HPTE_SUB 0x0ffff000 /* combo only: sub pages HPTE bits */
-#define _PAGE_HPTE_SUB0 0x08000000 /* combo only: first sub page */
-#define _PAGE_COMBO 0x10000000 /* this is a combo 4k page */
-#define _PAGE_4K_PFN 0x20000000 /* PFN is for a single 4k page */
-
-/* For 64K page, we don't have a separate _PAGE_HASHPTE bit. Instead,
- * we set that to be the whole sub-bits mask. The C code will only
- * test this, so a multi-bit mask will work. For combo pages, this
- * is equivalent as effectively, the old _PAGE_HASHPTE was an OR of
- * all the sub bits. For real 64k pages, we now have the assembly set
- * _PAGE_HPTE_SUB0 in addition to setting the HIDX bits which overlap
- * that mask. This is fine as long as the HIDX bits are never set on
- * a PTE that isn't hashed, which is the case today.
- *
- * A little nit is for the huge page C code, which does the hashing
- * in C, we need to provide which bit to use.
- */
-#define _PAGE_HASHPTE _PAGE_HPTE_SUB
-
-/* Note the full page bits must be in the same location as for normal
- * 4k pages as the same assembly will be used to insert 64K pages
- * whether the kernel has CONFIG_PPC_64K_PAGES or not
- */
-#define _PAGE_F_SECOND 0x00008000 /* full page: hidx bits */
-#define _PAGE_F_GIX 0x00007000 /* full page: hidx bits */
-
-/* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | _PAGE_COMBO)
-
-/* Shift to put page number into pte.
- *
- * That gives us a max RPN of 34 bits, which means a max of 50 bits
- * of addressable physical space, or 46 bits for the special 4k PFNs.
- */
-#define PTE_RPN_SHIFT (30)
-
-#ifndef __ASSEMBLY__
-
-/*
- * With 64K pages on hash table, we have a special PTE format that
- * uses a second "half" of the page table to encode sub-page information
- * in order to deal with 64K made of 4K HW pages. Thus we override the
- * generic accessors and iterators here
- */
-#define __real_pte __real_pte
-static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep)
-{
- real_pte_t rpte;
-
- rpte.pte = pte;
- rpte.hidx = 0;
- if (pte_val(pte) & _PAGE_COMBO) {
- /*
- * Make sure we order the hidx load against the _PAGE_COMBO
- * check. The store side ordering is done in __hash_page_4K
- */
- smp_rmb();
- rpte.hidx = pte_val(*((ptep) + PTRS_PER_PTE));
- }
- return rpte;
-}
-
-static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
-{
- if ((pte_val(rpte.pte) & _PAGE_COMBO))
- return (rpte.hidx >> (index<<2)) & 0xf;
- return (pte_val(rpte.pte) >> 12) & 0xf;
-}
-
-#define __rpte_to_pte(r) ((r).pte)
-#define __rpte_sub_valid(rpte, index) \
- (pte_val(rpte.pte) & (_PAGE_HPTE_SUB0 >> (index)))
-
-/* Trick: we set __end to va + 64k, which happens works for
- * a 16M page as well as we want only one iteration
- */
-#define pte_iterate_hashed_subpages(rpte, psize, vpn, index, shift) \
- do { \
- unsigned long __end = vpn + (1UL << (PAGE_SHIFT - VPN_SHIFT)); \
- unsigned __split = (psize == MMU_PAGE_4K || \
- psize == MMU_PAGE_64K_AP); \
- shift = mmu_psize_defs[psize].shift; \
- for (index = 0; vpn < __end; index++, \
- vpn += (1L << (shift - VPN_SHIFT))) { \
- if (!__split || __rpte_sub_valid(rpte, index)) \
- do {
-
-#define pte_iterate_hashed_end() } while(0); } } while(0)
-
-#define pte_pagesize_index(mm, addr, pte) \
- (((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
-
-#define remap_4k_pfn(vma, addr, pfn, prot) \
- (WARN_ON(((pfn) >= (1UL << (64 - PTE_RPN_SHIFT)))) ? -EINVAL : \
- remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
- __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))
-
-#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/pte-hash64.h b/arch/powerpc/include/asm/pte-hash64.h
deleted file mode 100644
index ef612c160da7..000000000000
--- a/arch/powerpc/include/asm/pte-hash64.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _ASM_POWERPC_PTE_HASH64_H
-#define _ASM_POWERPC_PTE_HASH64_H
-#ifdef __KERNEL__
-
-/*
- * Common bits between 4K and 64K pages in a linux-style PTE.
- * These match the bits in the (hardware-defined) PowerPC PTE as closely
- * as possible. Additional bits may be defined in pgtable-hash64-*.h
- *
- * Note: We only support user read/write permissions. Supervisor always
- * have full read/write to pages above PAGE_OFFSET (pages below that
- * always use the user access permissions).
- *
- * We could create separate kernel read-only if we used the 3 PP bits
- * combinations that newer processors provide but we currently don't.
- */
-#define _PAGE_PRESENT 0x0001 /* software: pte contains a translation */
-#define _PAGE_USER 0x0002 /* matches one of the PP bits */
-#define _PAGE_BIT_SWAP_TYPE 2
-#define _PAGE_EXEC 0x0004 /* No execute on POWER4 and newer (we invert) */
-#define _PAGE_GUARDED 0x0008
-/* We can derive Memory coherence from _PAGE_NO_CACHE */
-#define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */
-#define _PAGE_WRITETHRU 0x0040 /* W: cache write-through */
-#define _PAGE_DIRTY 0x0080 /* C: page changed */
-#define _PAGE_ACCESSED 0x0100 /* R: page referenced */
-#define _PAGE_RW 0x0200 /* software: user write access allowed */
-#define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */
-
-/* No separate kernel read-only */
-#define _PAGE_KERNEL_RW (_PAGE_RW | _PAGE_DIRTY) /* user access blocked by key */
-#define _PAGE_KERNEL_RO _PAGE_KERNEL_RW
-
-/* Strong Access Ordering */
-#define _PAGE_SAO (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT)
-
-/* No page size encoding in the linux PTE */
-#define _PAGE_PSIZE 0
-
-/* PTEIDX nibble */
-#define _PTEIDX_SECONDARY 0x8
-#define _PTEIDX_GROUP_IX 0x7
-
-/* Hash table based platforms need atomic updates of the linux PTE */
-#define PTE_ATOMIC_UPDATES 1
-
-#ifdef CONFIG_PPC_64K_PAGES
-#include <asm/pte-hash64-64k.h>
-#else
-#include <asm/pte-hash64-4k.h>
-#endif
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_PTE_HASH64_H */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 2220f7a60def..c4cb2ffc624e 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1194,12 +1194,20 @@
#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
: : "r" (v) : "memory")
#define mtmsr(v) __mtmsrd((v), 0)
+#define __MTMSR "mtmsrd"
#else
#define mtmsr(v) asm volatile("mtmsr %0" : \
: "r" ((unsigned long)(v)) \
: "memory")
+#define __MTMSR "mtmsr"
#endif
+static inline void mtmsr_isync(unsigned long val)
+{
+ asm volatile(__MTMSR " %0; " ASM_FTR_IFCLR("isync", "nop", %1) : :
+ "r" (val), "i" (CPU_FTR_ARCH_206) : "memory");
+}
+
#define mfspr(rn) ({unsigned long rval; \
asm volatile("mfspr %0," __stringify(rn) \
: "=r" (rval)); rval;})
@@ -1207,6 +1215,15 @@
: "r" ((unsigned long)(v)) \
: "memory")
+extern void msr_check_and_set(unsigned long bits);
+extern bool strict_msr_control;
+extern void __msr_check_and_clear(unsigned long bits);
+static inline void msr_check_and_clear(unsigned long bits)
+{
+ if (strict_msr_control)
+ __msr_check_and_clear(bits);
+}
+
static inline unsigned long mfvtb (void)
{
#ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index b77ef369c0f0..51400baa8d48 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -334,10 +334,11 @@ extern void (*rtas_flash_term_hook)(int);
extern struct rtas_t rtas;
-extern void enter_rtas(unsigned long);
extern int rtas_token(const char *service);
extern int rtas_service_present(const char *service);
extern int rtas_call(int token, int, int, int *, ...);
+void rtas_call_unlocked(struct rtas_args *args, int token, int nargs,
+ int nret, ...);
extern void rtas_restart(char *cmd);
extern void rtas_power_off(void);
extern void rtas_halt(void);
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 15cca17cba4b..5b268b6be74c 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -4,6 +4,8 @@
#ifndef _ASM_POWERPC_SWITCH_TO_H
#define _ASM_POWERPC_SWITCH_TO_H
+#include <asm/reg.h>
+
struct thread_struct;
struct task_struct;
struct pt_regs;
@@ -12,74 +14,59 @@ extern struct task_struct *__switch_to(struct task_struct *,
struct task_struct *);
#define switch_to(prev, next, last) ((last) = __switch_to((prev), (next)))
-struct thread_struct;
extern struct task_struct *_switch(struct thread_struct *prev,
struct thread_struct *next);
-#ifdef CONFIG_PPC_BOOK3S_64
-static inline void save_early_sprs(struct thread_struct *prev)
-{
- if (cpu_has_feature(CPU_FTR_ARCH_207S))
- prev->tar = mfspr(SPRN_TAR);
- if (cpu_has_feature(CPU_FTR_DSCR))
- prev->dscr = mfspr(SPRN_DSCR);
-}
-#else
-static inline void save_early_sprs(struct thread_struct *prev) {}
-#endif
-extern void enable_kernel_fp(void);
-extern void enable_kernel_altivec(void);
-extern void enable_kernel_vsx(void);
-extern int emulate_altivec(struct pt_regs *);
-extern void __giveup_vsx(struct task_struct *);
-extern void giveup_vsx(struct task_struct *);
-extern void enable_kernel_spe(void);
-extern void giveup_spe(struct task_struct *);
-extern void load_up_spe(struct task_struct *);
extern void switch_booke_debug_regs(struct debug_reg *new_debug);
-#ifndef CONFIG_SMP
-extern void discard_lazy_cpu_state(void);
-#else
-static inline void discard_lazy_cpu_state(void)
-{
-}
-#endif
+extern int emulate_altivec(struct pt_regs *);
+
+extern void flush_all_to_thread(struct task_struct *);
+extern void giveup_all(struct task_struct *);
#ifdef CONFIG_PPC_FPU
+extern void enable_kernel_fp(void);
extern void flush_fp_to_thread(struct task_struct *);
extern void giveup_fpu(struct task_struct *);
+extern void __giveup_fpu(struct task_struct *);
+static inline void disable_kernel_fp(void)
+{
+ msr_check_and_clear(MSR_FP);
+}
#else
static inline void flush_fp_to_thread(struct task_struct *t) { }
-static inline void giveup_fpu(struct task_struct *t) { }
#endif
#ifdef CONFIG_ALTIVEC
+extern void enable_kernel_altivec(void);
extern void flush_altivec_to_thread(struct task_struct *);
extern void giveup_altivec(struct task_struct *);
-extern void giveup_altivec_notask(void);
-#else
-static inline void flush_altivec_to_thread(struct task_struct *t)
-{
-}
-static inline void giveup_altivec(struct task_struct *t)
+extern void __giveup_altivec(struct task_struct *);
+static inline void disable_kernel_altivec(void)
{
+ msr_check_and_clear(MSR_VEC);
}
#endif
#ifdef CONFIG_VSX
+extern void enable_kernel_vsx(void);
extern void flush_vsx_to_thread(struct task_struct *);
-#else
-static inline void flush_vsx_to_thread(struct task_struct *t)
+extern void giveup_vsx(struct task_struct *);
+extern void __giveup_vsx(struct task_struct *);
+static inline void disable_kernel_vsx(void)
{
+ msr_check_and_clear(MSR_FP|MSR_VEC|MSR_VSX);
}
#endif
#ifdef CONFIG_SPE
+extern void enable_kernel_spe(void);
extern void flush_spe_to_thread(struct task_struct *);
-#else
-static inline void flush_spe_to_thread(struct task_struct *t)
+extern void giveup_spe(struct task_struct *);
+extern void __giveup_spe(struct task_struct *);
+static inline void disable_kernel_spe(void)
{
+ msr_check_and_clear(MSR_SPE);
}
#endif
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index e682a7143edb..c50868681f9e 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -44,7 +44,7 @@ static inline void isync(void)
MAKE_LWSYNC_SECTION_ENTRY(97, __lwsync_fixup);
#define PPC_ACQUIRE_BARRIER "\n" stringify_in_c(__PPC_ACQUIRE_BARRIER)
#define PPC_RELEASE_BARRIER stringify_in_c(LWSYNC) "\n"
-#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(LWSYNC) "\n"
+#define PPC_ATOMIC_ENTRY_BARRIER "\n" stringify_in_c(sync) "\n"
#define PPC_ATOMIC_EXIT_BARRIER "\n" stringify_in_c(sync) "\n"
#else
#define PPC_ACQUIRE_BARRIER
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 10fc784a2ad4..2d7109a8d296 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -27,7 +27,6 @@ extern struct clock_event_device decrementer_clockevent;
struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm);
-extern void GregorianDay(struct rtc_time *tm);
extern void tick_broadcast_ipi_handler(void);
extern void generic_calibrate_decr(void);
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index 4b6b8ace18e0..6a5ace5fa0c8 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -12,10 +12,9 @@
#include <uapi/asm/unistd.h>
-#define __NR_syscalls 379
+#define NR_syscalls 379
#define __NR__exit __NR_exit
-#define NR_syscalls __NR_syscalls
#ifndef __ASSEMBLY__
diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h
index b73a8199f161..1afe90ade595 100644
--- a/arch/powerpc/include/asm/vdso_datapage.h
+++ b/arch/powerpc/include/asm/vdso_datapage.h
@@ -41,7 +41,7 @@
#include <linux/unistd.h>
#include <linux/time.h>
-#define SYSCALL_MAP_SIZE ((__NR_syscalls + 31) / 32)
+#define SYSCALL_MAP_SIZE ((NR_syscalls + 31) / 32)
/*
* So here is the ppc64 backward compatible version
diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h
index 43686043e297..8dde19962a5b 100644
--- a/arch/powerpc/include/uapi/asm/cputable.h
+++ b/arch/powerpc/include/uapi/asm/cputable.h
@@ -43,5 +43,7 @@
#define PPC_FEATURE2_TAR 0x04000000
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
#define PPC_FEATURE2_HTM_NOSC 0x01000000
+#define PPC_FEATURE2_ARCH_3_00 0x00800000 /* ISA 3.00 */
+#define PPC_FEATURE2_HAS_IEEE128 0x00400000 /* VSX IEEE Binary Float 128-bit */
#endif /* _UAPI__ASM_POWERPC_CPUTABLE_H */
diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h
index 59dad113897b..c2d21d11c2d2 100644
--- a/arch/powerpc/include/uapi/asm/elf.h
+++ b/arch/powerpc/include/uapi/asm/elf.h
@@ -295,6 +295,8 @@ do { \
#define R_PPC64_TLSLD 108
#define R_PPC64_TOCSAVE 109
+#define R_PPC64_ENTRY 118
+
#define R_PPC64_REL16 249
#define R_PPC64_REL16_LO 250
#define R_PPC64_REL16_HI 251
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 86150fbb42c3..8e7cb8e2b21a 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -960,6 +960,7 @@ int fix_alignment(struct pt_regs *regs)
preempt_disable();
enable_kernel_fp();
cvt_df(&data.dd, (float *)&data.x32.low32);
+ disable_kernel_fp();
preempt_enable();
#else
return 0;
@@ -1000,6 +1001,7 @@ int fix_alignment(struct pt_regs *regs)
preempt_disable();
enable_kernel_fp();
cvt_fd((float *)&data.x32.low32, &data.dd);
+ disable_kernel_fp();
preempt_enable();
#else
return 0;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 221d584d089f..07cebc3514f3 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -185,14 +185,16 @@ int main(void)
DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened));
- DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
+#ifdef CONFIG_PPC_BOOK3S
+ DEFINE(PACACONTEXTID, offsetof(struct paca_struct, mm_ctx_id));
#ifdef CONFIG_PPC_MM_SLICES
DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
- context.low_slices_psize));
+ mm_ctx_low_slices_psize));
DEFINE(PACAHIGHSLICEPSIZE, offsetof(struct paca_struct,
- context.high_slices_psize));
+ mm_ctx_high_slices_psize));
DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
#endif /* CONFIG_PPC_MM_SLICES */
+#endif
#ifdef CONFIG_PPC_BOOK3E
DEFINE(PACAPGD, offsetof(struct paca_struct, pgd));
@@ -222,7 +224,7 @@ int main(void)
#ifdef CONFIG_PPC_MM_SLICES
DEFINE(MMUPSIZESLLP, offsetof(struct mmu_psize_def, sllp));
#else
- DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
+ DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, mm_ctx_sllp));
#endif /* CONFIG_PPC_MM_SLICES */
DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index a94f155db78e..0d525ce3717f 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -223,7 +223,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
beq- 1f
ACCOUNT_CPU_USER_EXIT(r11, r12)
- HMT_MEDIUM_LOW_HAS_PPR
+
+BEGIN_FTR_SECTION
+ HMT_MEDIUM_LOW
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
1: ld r2,GPR2(r1)
ld r1,GPR1(r1)
@@ -312,7 +316,13 @@ syscall_exit_work:
subi r12,r12,TI_FLAGS
4: /* Anything else left to do? */
- SET_DEFAULT_THREAD_PPR(r3, r10) /* Set thread.ppr = 3 */
+BEGIN_FTR_SECTION
+ lis r3,INIT_PPR@highest /* Set thread.ppr = 3 */
+ ld r10,PACACURRENT(r13)
+ sldi r3,r3,32 /* bits 11-13 are used for ppr */
+ std r3,TASKTHREADPPR(r10)
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+
andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP)
beq ret_from_except_lite
@@ -452,43 +462,11 @@ _GLOBAL(_switch)
/* r3-r13 are caller saved -- Cort */
SAVE_8GPRS(14, r1)
SAVE_10GPRS(22, r1)
- mflr r20 /* Return to switch caller */
- mfmsr r22
- li r0, MSR_FP
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
- oris r0,r0,MSR_VSX@h /* Disable VSX */
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif /* CONFIG_VSX */
-#ifdef CONFIG_ALTIVEC
-BEGIN_FTR_SECTION
- oris r0,r0,MSR_VEC@h /* Disable altivec */
- mfspr r24,SPRN_VRSAVE /* save vrsave register value */
- std r24,THREAD_VRSAVE(r3)
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-#endif /* CONFIG_ALTIVEC */
- and. r0,r0,r22
- beq+ 1f
- andc r22,r22,r0
- MTMSRD(r22)
- isync
-1: std r20,_NIP(r1)
+ std r0,_NIP(r1) /* Return to switch caller */
mfcr r23
std r23,_CCR(r1)
std r1,KSP(r3) /* Set old stack pointer */
-#ifdef CONFIG_PPC_BOOK3S_64
-BEGIN_FTR_SECTION
- /* Event based branch registers */
- mfspr r0, SPRN_BESCR
- std r0, THREAD_BESCR(r3)
- mfspr r0, SPRN_EBBHR
- std r0, THREAD_EBBHR(r3)
- mfspr r0, SPRN_EBBRR
- std r0, THREAD_EBBRR(r3)
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
-#endif
-
#ifdef CONFIG_SMP
/* We need a sync somewhere here to make sure that if the
* previous task gets rescheduled on another CPU, it sees all
@@ -576,47 +554,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
mr r1,r8 /* start using new stack pointer */
std r7,PACAKSAVE(r13)
-#ifdef CONFIG_PPC_BOOK3S_64
-BEGIN_FTR_SECTION
- /* Event based branch registers */
- ld r0, THREAD_BESCR(r4)
- mtspr SPRN_BESCR, r0
- ld r0, THREAD_EBBHR(r4)
- mtspr SPRN_EBBHR, r0
- ld r0, THREAD_EBBRR(r4)
- mtspr SPRN_EBBRR, r0
-
- ld r0,THREAD_TAR(r4)
- mtspr SPRN_TAR,r0
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
-#endif
-
-#ifdef CONFIG_ALTIVEC
-BEGIN_FTR_SECTION
- ld r0,THREAD_VRSAVE(r4)
- mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-#endif /* CONFIG_ALTIVEC */
-#ifdef CONFIG_PPC64
-BEGIN_FTR_SECTION
- lwz r6,THREAD_DSCR_INHERIT(r4)
- ld r0,THREAD_DSCR(r4)
- cmpwi r6,0
- bne 1f
- ld r0,PACA_DSCR_DEFAULT(r13)
-1:
-BEGIN_FTR_SECTION_NESTED(70)
- mfspr r8, SPRN_FSCR
- rldimi r8, r6, FSCR_DSCR_LG, (63 - FSCR_DSCR_LG)
- mtspr SPRN_FSCR, r8
-END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70)
- cmpd r0,r25
- beq 2f
- mtspr SPRN_DSCR,r0
-2:
-END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
-#endif
-
ld r6,_CCR(r1)
mtcrf 0xFF,r6
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 0a0399c2af11..7716cebf4b8e 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -96,7 +96,6 @@ __start_interrupts:
.globl system_reset_pSeries;
system_reset_pSeries:
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
#ifdef CONFIG_PPC_P7_NAP
BEGIN_FTR_SECTION
@@ -164,7 +163,6 @@ machine_check_pSeries_1:
* some code path might still want to branch into the original
* vector
*/
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13) /* save r13 */
#ifdef CONFIG_PPC_P7_NAP
BEGIN_FTR_SECTION
@@ -199,7 +197,6 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
. = 0x300
.globl data_access_pSeries
data_access_pSeries:
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
KVMTEST, 0x300)
@@ -207,7 +204,6 @@ data_access_pSeries:
. = 0x380
.globl data_access_slb_pSeries
data_access_slb_pSeries:
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
EXCEPTION_PROLOG_0(PACA_EXSLB)
EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
@@ -234,15 +230,14 @@ data_access_slb_pSeries:
bctr
#endif
- STD_EXCEPTION_PSERIES(0x400, 0x400, instruction_access)
+ STD_EXCEPTION_PSERIES(0x400, instruction_access)
. = 0x480
.globl instruction_access_slb_pSeries
instruction_access_slb_pSeries:
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
EXCEPTION_PROLOG_0(PACA_EXSLB)
- EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
+ EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x480)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
#ifdef __DISABLED__
@@ -269,25 +264,24 @@ instruction_access_slb_pSeries:
.globl hardware_interrupt_hv;
hardware_interrupt_pSeries:
hardware_interrupt_hv:
- HMT_MEDIUM_PPR_DISCARD
BEGIN_FTR_SECTION
_MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt,
EXC_HV, SOFTEN_TEST_HV)
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502)
FTR_SECTION_ELSE
_MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt,
- EXC_STD, SOFTEN_TEST_HV_201)
+ EXC_STD, SOFTEN_TEST_PR)
KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500)
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
- STD_EXCEPTION_PSERIES(0x600, 0x600, alignment)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x600)
+ STD_EXCEPTION_PSERIES(0x600, alignment)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x600)
- STD_EXCEPTION_PSERIES(0x700, 0x700, program_check)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x700)
+ STD_EXCEPTION_PSERIES(0x700, program_check)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x700)
- STD_EXCEPTION_PSERIES(0x800, 0x800, fp_unavailable)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x800)
+ STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x800)
. = 0x900
.globl decrementer_pSeries
@@ -297,10 +291,10 @@ decrementer_pSeries:
STD_EXCEPTION_HV(0x980, 0x982, hdecrementer)
MASKABLE_EXCEPTION_PSERIES(0xa00, 0xa00, doorbell_super)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xa00)
- STD_EXCEPTION_PSERIES(0xb00, 0xb00, trap_0b)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xb00)
+ STD_EXCEPTION_PSERIES(0xb00, trap_0b)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xb00)
. = 0xc00
.globl system_call_pSeries
@@ -331,8 +325,8 @@ system_call_pSeries:
SYSCALL_PSERIES_3
KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00)
- STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xd00)
+ STD_EXCEPTION_PSERIES(0xd00, single_step)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xd00)
/* At 0xe??? we have a bunch of hypervisor exceptions, we branch
* out of line to handle them
@@ -407,13 +401,12 @@ hv_facility_unavailable_trampoline:
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
#endif /* CONFIG_CBE_RAS */
- STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint)
- KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300)
+ STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
+ KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1300)
. = 0x1500
.global denorm_exception_hv
denorm_exception_hv:
- HMT_MEDIUM_PPR_DISCARD
mtspr SPRN_SPRG_HSCRATCH0,r13
EXCEPTION_PROLOG_0(PACA_EXGEN)
EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0x1500)
@@ -435,8 +428,8 @@ denorm_exception_hv:
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602)
#endif /* CONFIG_CBE_RAS */
- STD_EXCEPTION_PSERIES(0x1700, 0x1700, altivec_assist)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x1700)
+ STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x1700)
#ifdef CONFIG_CBE_RAS
STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal)
@@ -527,7 +520,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
machine_check_pSeries:
.globl machine_check_fwnmi
machine_check_fwnmi:
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13) /* save r13 */
EXCEPTION_PROLOG_0(PACA_EXMC)
machine_check_pSeries_0:
@@ -536,9 +528,9 @@ machine_check_pSeries_0:
KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x400)
- KVM_HANDLER_PR(PACA_EXSLB, EXC_STD, 0x480)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x400)
+ KVM_HANDLER(PACA_EXSLB, EXC_STD, 0x480)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x900)
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982)
#ifdef CONFIG_PPC_DENORMALISATION
@@ -621,13 +613,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
/* moved from 0xf00 */
STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf00)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf00)
STD_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf20)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf20)
STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf40)
STD_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
- KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf60)
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf60)
STD_EXCEPTION_HV_OOL(0xf82, facility_unavailable)
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xf82)
@@ -711,7 +703,6 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
.globl system_reset_fwnmi
.align 7
system_reset_fwnmi:
- HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13) /* save r13 */
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
NOTEST, 0x100)
@@ -1556,29 +1547,19 @@ do_hash_page:
lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */
andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */
bne 77f /* then don't call hash_page now */
- /*
- * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
- * accessing a userspace segment (even from the kernel). We assume
- * kernel addresses always have the high bit set.
- */
- rlwinm r4,r4,32-25+9,31-9,31-9 /* DSISR_STORE -> _PAGE_RW */
- rotldi r0,r3,15 /* Move high bit into MSR_PR posn */
- orc r0,r12,r0 /* MSR_PR | ~high_bit */
- rlwimi r4,r0,32-13,30,30 /* becomes _PAGE_USER access bit */
- ori r4,r4,1 /* add _PAGE_PRESENT */
- rlwimi r4,r5,22+2,31-2,31-2 /* Set _PAGE_EXEC if trap is 0x400 */
/*
* r3 contains the faulting address
- * r4 contains the required access permissions
+ * r4 msr
* r5 contains the trap number
* r6 contains dsisr
*
* at return r3 = 0 for success, 1 for page fault, negative for error
*/
+ mr r4,r12
ld r6,_DSISR(r1)
- bl hash_page /* build HPTE if possible */
- cmpdi r3,0 /* see if hash_page succeeded */
+ bl __hash_page /* build HPTE if possible */
+ cmpdi r3,0 /* see if __hash_page succeeded */
/* Success */
beq fast_exc_return_irq /* Return from exception on success */
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 9ad236e5d2c9..2117eaca3d28 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -73,30 +73,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
MTFSF_L(fr0)
REST_32FPVSRS(0, R4, R7)
- /* FP/VSX off again */
- MTMSRD(r6)
- SYNC
-
blr
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
/*
- * Enable use of the FPU, and VSX if possible, for the caller.
- */
-_GLOBAL(fp_enable)
- mfmsr r3
- ori r3,r3,MSR_FP
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
- oris r3,r3,MSR_VSX@h
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
- SYNC
- MTMSRD(r3)
- isync /* (not necessary for arch 2.02 and later) */
- blr
-
-/*
* Load state from memory into FP registers including FPSCR.
* Assumes the caller has enabled FP in the MSR.
*/
@@ -136,31 +116,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
SYNC
MTMSRD(r5) /* enable use of fpu now */
isync
-/*
- * For SMP, we don't do lazy FPU switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_fpu in switch_to.
- */
-#ifndef CONFIG_SMP
- LOAD_REG_ADDRBASE(r3, last_task_used_math)
- toreal(r3)
- PPC_LL r4,ADDROFF(last_task_used_math)(r3)
- PPC_LCMPI 0,r4,0
- beq 1f
- toreal(r4)
- addi r4,r4,THREAD /* want last_task_used_math->thread */
- addi r10,r4,THREAD_FPSTATE
- SAVE_32FPVSRS(0, R5, R10)
- mffs fr0
- stfd fr0,FPSTATE_FPSCR(r10)
- PPC_LL r5,PT_REGS(r4)
- toreal(r5)
- PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r10,MSR_FP|MSR_FE0|MSR_FE1
- andc r4,r4,r10 /* disable FP for previous task */
- PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
/* enable use of FP after return */
#ifdef CONFIG_PPC32
mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
@@ -179,36 +134,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
lfd fr0,FPSTATE_FPSCR(r10)
MTFSF_L(fr0)
REST_32FPVSRS(0, R4, R10)
-#ifndef CONFIG_SMP
- subi r4,r5,THREAD
- fromreal(r4)
- PPC_STL r4,ADDROFF(last_task_used_math)(r3)
-#endif /* CONFIG_SMP */
/* restore registers and return */
/* we haven't used ctr or xer or lr */
blr
/*
- * giveup_fpu(tsk)
+ * __giveup_fpu(tsk)
* Disable FP for the task given as the argument,
* and save the floating-point registers in its thread_struct.
* Enables the FPU for use in the kernel on return.
*/
-_GLOBAL(giveup_fpu)
- mfmsr r5
- ori r5,r5,MSR_FP
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
- oris r5,r5,MSR_VSX@h
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
- SYNC_601
- ISYNC_601
- MTMSRD(r5) /* enable use of fpu now */
- SYNC_601
- isync
- PPC_LCMPI 0,r3,0
- beqlr- /* if no previous owner, done */
+_GLOBAL(__giveup_fpu)
addi r3,r3,THREAD /* want THREAD of task */
PPC_LL r6,THREAD_FPSAVEAREA(r3)
PPC_LL r5,PT_REGS(r3)
@@ -230,11 +166,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
andc r4,r4,r3 /* disable FP for previous task */
PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
1:
-#ifndef CONFIG_SMP
- li r5,0
- LOAD_REG_ADDRBASE(r4,last_task_used_math)
- PPC_STL r5,ADDROFF(last_task_used_math)(r4)
-#endif /* CONFIG_SMP */
blr
/*
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index fffd1f96bb1d..f705171b924b 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -857,29 +857,6 @@ _GLOBAL(load_up_spe)
oris r5,r5,MSR_SPE@h
mtmsr r5 /* enable use of SPE now */
isync
-/*
- * For SMP, we don't do lazy SPE switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_spe in switch_to.
- */
-#ifndef CONFIG_SMP
- lis r3,last_task_used_spe@ha
- lwz r4,last_task_used_spe@l(r3)
- cmpi 0,r4,0
- beq 1f
- addi r4,r4,THREAD /* want THREAD of last_task_used_spe */
- SAVE_32EVRS(0,r10,r4,THREAD_EVR0)
- evxor evr10, evr10, evr10 /* clear out evr10 */
- evmwumiaa evr10, evr10, evr10 /* evr10 <- ACC = 0 * 0 + ACC */
- li r5,THREAD_ACC
- evstddx evr10, r4, r5 /* save off accumulator */
- lwz r5,PT_REGS(r4)
- lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r10,MSR_SPE@h
- andc r4,r4,r10 /* disable SPE for previous task */
- stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* !CONFIG_SMP */
/* enable use of SPE after return */
oris r9,r9,MSR_SPE@h
mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
@@ -889,10 +866,6 @@ _GLOBAL(load_up_spe)
evlddx evr4,r10,r5
evmra evr4,evr4
REST_32EVRS(0,r10,r5,THREAD_EVR0)
-#ifndef CONFIG_SMP
- subi r4,r5,THREAD
- stw r4,last_task_used_spe@l(r3)
-#endif /* !CONFIG_SMP */
blr
/*
@@ -1011,16 +984,10 @@ _GLOBAL(__setup_ehv_ivors)
#ifdef CONFIG_SPE
/*
- * extern void giveup_spe(struct task_struct *prev)
+ * extern void __giveup_spe(struct task_struct *prev)
*
*/
-_GLOBAL(giveup_spe)
- mfmsr r5
- oris r5,r5,MSR_SPE@h
- mtmsr r5 /* enable use of SPE now */
- isync
- cmpi 0,r3,0
- beqlr- /* if no previous owner, done */
+_GLOBAL(__giveup_spe)
addi r3,r3,THREAD /* want THREAD of task */
lwz r5,PT_REGS(r3)
cmpi 0,r5,0
@@ -1035,11 +1002,6 @@ _GLOBAL(giveup_spe)
andc r4,r4,r3 /* disable SPE for previous task */
stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
1:
-#ifndef CONFIG_SMP
- li r5,0
- lis r4,last_task_used_spe@ha
- stw r5,last_task_used_spe@l(r4)
-#endif /* !CONFIG_SMP */
blr
#endif /* CONFIG_SPE */
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 112ccf497562..cf4fb5429cf1 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -89,13 +89,6 @@ _GLOBAL(power7_powersave_common)
std r0,_LINK(r1)
std r0,_NIP(r1)
-#ifndef CONFIG_SMP
- /* Make sure FPU, VSX etc... are flushed as we may lose
- * state when going to nap mode
- */
- bl discard_lazy_cpu_state
-#endif /* CONFIG_SMP */
-
/* Hard disable interrupts */
mfmsr r9
rldicl r9,r9,48,1
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index ed3ab509faca..be8edd67f05b 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -743,6 +743,8 @@ relocate_new_kernel:
/* Check for 47x cores */
mfspr r3,SPRN_PVR
srwi r3,r3,16
+ cmplwi cr0,r3,PVR_476FPE@h
+ beq setup_map_47x
cmplwi cr0,r3,PVR_476@h
beq setup_map_47x
cmplwi cr0,r3,PVR_476_ISS@h
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
index c94d2e018d84..2c01665eb410 100644
--- a/arch/powerpc/kernel/module_32.c
+++ b/arch/powerpc/kernel/module_32.c
@@ -188,8 +188,8 @@ static uint32_t do_plt_call(void *location,
pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
/* Init, or core PLT? */
- if (location >= mod->module_core
- && location < mod->module_core + mod->core_size)
+ if (location >= mod->core_layout.base
+ && location < mod->core_layout.base + mod->core_layout.size)
entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
else
entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
@@ -296,7 +296,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
}
#ifdef CONFIG_DYNAMIC_FTRACE
module->arch.tramp =
- do_plt_call(module->module_core,
+ do_plt_call(module->core_layout.base,
(unsigned long)ftrace_caller,
sechdrs, module);
#endif
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 68384514506b..59663af9315f 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -635,6 +635,33 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
*/
break;
+ case R_PPC64_ENTRY:
+ /*
+ * Optimize ELFv2 large code model entry point if
+ * the TOC is within 2GB range of current location.
+ */
+ value = my_r2(sechdrs, me) - (unsigned long)location;
+ if (value + 0x80008000 > 0xffffffff)
+ break;
+ /*
+ * Check for the large code model prolog sequence:
+ * ld r2, ...(r12)
+ * add r2, r2, r12
+ */
+ if ((((uint32_t *)location)[0] & ~0xfffc)
+ != 0xe84c0000)
+ break;
+ if (((uint32_t *)location)[1] != 0x7c426214)
+ break;
+ /*
+ * If found, replace it with:
+ * addis r2, r12, (.TOC.-func)@ha
+ * addi r2, r12, (.TOC.-func)@l
+ */
+ ((uint32_t *)location)[0] = 0x3c4c0000 + PPC_HA(value);
+ ((uint32_t *)location)[1] = 0x38420000 + PPC_LO(value);
+ break;
+
case R_PPC64_REL16_HA:
/* Subtract location pointer */
value -= (unsigned long)location;
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 202963ee013a..41e1607e800c 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -19,13 +19,11 @@ EXPORT_SYMBOL(_mcount);
#endif
#ifdef CONFIG_PPC_FPU
-EXPORT_SYMBOL(giveup_fpu);
EXPORT_SYMBOL(load_fp_state);
EXPORT_SYMBOL(store_fp_state);
#endif
#ifdef CONFIG_ALTIVEC
-EXPORT_SYMBOL(giveup_altivec);
EXPORT_SYMBOL(load_vr_state);
EXPORT_SYMBOL(store_vr_state);
#endif
@@ -34,10 +32,6 @@ EXPORT_SYMBOL(store_vr_state);
EXPORT_SYMBOL_GPL(__giveup_vsx);
#endif
-#ifdef CONFIG_SPE
-EXPORT_SYMBOL(giveup_spe);
-#endif
-
#ifdef CONFIG_EPAPR_PARAVIRT
EXPORT_SYMBOL(epapr_hypercall_start);
#endif
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 646bf4d222c1..dccc87e8fee5 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -67,15 +67,8 @@
extern unsigned long _get_SP(void);
-#ifndef CONFIG_SMP
-struct task_struct *last_task_used_math = NULL;
-struct task_struct *last_task_used_altivec = NULL;
-struct task_struct *last_task_used_vsx = NULL;
-struct task_struct *last_task_used_spe = NULL;
-#endif
-
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-void giveup_fpu_maybe_transactional(struct task_struct *tsk)
+static void check_if_tm_restore_required(struct task_struct *tsk)
{
/*
* If we are saving the current thread's registers, and the
@@ -89,34 +82,67 @@ void giveup_fpu_maybe_transactional(struct task_struct *tsk)
tsk->thread.ckpt_regs.msr = tsk->thread.regs->msr;
set_thread_flag(TIF_RESTORE_TM);
}
+}
+#else
+static inline void check_if_tm_restore_required(struct task_struct *tsk) { }
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
+bool strict_msr_control;
+EXPORT_SYMBOL(strict_msr_control);
+
+static int __init enable_strict_msr_control(char *str)
+{
+ strict_msr_control = true;
+ pr_info("Enabling strict facility control\n");
- giveup_fpu(tsk);
+ return 0;
}
+early_param("ppc_strict_facility_enable", enable_strict_msr_control);
-void giveup_altivec_maybe_transactional(struct task_struct *tsk)
+void msr_check_and_set(unsigned long bits)
{
- /*
- * If we are saving the current thread's registers, and the
- * thread is in a transactional state, set the TIF_RESTORE_TM
- * bit so that we know to restore the registers before
- * returning to userspace.
- */
- if (tsk == current && tsk->thread.regs &&
- MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
- !test_thread_flag(TIF_RESTORE_TM)) {
- tsk->thread.ckpt_regs.msr = tsk->thread.regs->msr;
- set_thread_flag(TIF_RESTORE_TM);
- }
+ unsigned long oldmsr = mfmsr();
+ unsigned long newmsr;
- giveup_altivec(tsk);
+ newmsr = oldmsr | bits;
+
+#ifdef CONFIG_VSX
+ if (cpu_has_feature(CPU_FTR_VSX) && (bits & MSR_FP))
+ newmsr |= MSR_VSX;
+#endif
+
+ if (oldmsr != newmsr)
+ mtmsr_isync(newmsr);
}
-#else
-#define giveup_fpu_maybe_transactional(tsk) giveup_fpu(tsk)
-#define giveup_altivec_maybe_transactional(tsk) giveup_altivec(tsk)
-#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+void __msr_check_and_clear(unsigned long bits)
+{
+ unsigned long oldmsr = mfmsr();
+ unsigned long newmsr;
+
+ newmsr = oldmsr & ~bits;
+
+#ifdef CONFIG_VSX
+ if (cpu_has_feature(CPU_FTR_VSX) && (bits & MSR_FP))
+ newmsr &= ~MSR_VSX;
+#endif
+
+ if (oldmsr != newmsr)
+ mtmsr_isync(newmsr);
+}
+EXPORT_SYMBOL(__msr_check_and_clear);
#ifdef CONFIG_PPC_FPU
+void giveup_fpu(struct task_struct *tsk)
+{
+ check_if_tm_restore_required(tsk);
+
+ msr_check_and_set(MSR_FP);
+ __giveup_fpu(tsk);
+ msr_check_and_clear(MSR_FP);
+}
+EXPORT_SYMBOL(giveup_fpu);
+
/*
* Make sure the floating-point register state in the
* the thread_struct is up to date for task tsk.
@@ -134,52 +160,56 @@ void flush_fp_to_thread(struct task_struct *tsk)
*/
preempt_disable();
if (tsk->thread.regs->msr & MSR_FP) {
-#ifdef CONFIG_SMP
/*
* This should only ever be called for current or
* for a stopped child process. Since we save away
- * the FP register state on context switch on SMP,
+ * the FP register state on context switch,
* there is something wrong if a stopped child appears
* to still have its FP state in the CPU registers.
*/
BUG_ON(tsk != current);
-#endif
- giveup_fpu_maybe_transactional(tsk);
+ giveup_fpu(tsk);
}
preempt_enable();
}
}
EXPORT_SYMBOL_GPL(flush_fp_to_thread);
-#endif /* CONFIG_PPC_FPU */
void enable_kernel_fp(void)
{
WARN_ON(preemptible());
-#ifdef CONFIG_SMP
- if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
- giveup_fpu_maybe_transactional(current);
- else
- giveup_fpu(NULL); /* just enables FP for kernel */
-#else
- giveup_fpu_maybe_transactional(last_task_used_math);
-#endif /* CONFIG_SMP */
+ msr_check_and_set(MSR_FP);
+
+ if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) {
+ check_if_tm_restore_required(current);
+ __giveup_fpu(current);
+ }
}
EXPORT_SYMBOL(enable_kernel_fp);
+#endif /* CONFIG_PPC_FPU */
#ifdef CONFIG_ALTIVEC
+void giveup_altivec(struct task_struct *tsk)
+{
+ check_if_tm_restore_required(tsk);
+
+ msr_check_and_set(MSR_VEC);
+ __giveup_altivec(tsk);
+ msr_check_and_clear(MSR_VEC);
+}
+EXPORT_SYMBOL(giveup_altivec);
+
void enable_kernel_altivec(void)
{
WARN_ON(preemptible());
-#ifdef CONFIG_SMP
- if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
- giveup_altivec_maybe_transactional(current);
- else
- giveup_altivec_notask();
-#else
- giveup_altivec_maybe_transactional(last_task_used_altivec);
-#endif /* CONFIG_SMP */
+ msr_check_and_set(MSR_VEC);
+
+ if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) {
+ check_if_tm_restore_required(current);
+ __giveup_altivec(current);
+ }
}
EXPORT_SYMBOL(enable_kernel_altivec);
@@ -192,10 +222,8 @@ void flush_altivec_to_thread(struct task_struct *tsk)
if (tsk->thread.regs) {
preempt_disable();
if (tsk->thread.regs->msr & MSR_VEC) {
-#ifdef CONFIG_SMP
BUG_ON(tsk != current);
-#endif
- giveup_altivec_maybe_transactional(tsk);
+ giveup_altivec(tsk);
}
preempt_enable();
}
@@ -204,37 +232,43 @@ EXPORT_SYMBOL_GPL(flush_altivec_to_thread);
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_VSX
-void enable_kernel_vsx(void)
+void giveup_vsx(struct task_struct *tsk)
{
- WARN_ON(preemptible());
+ check_if_tm_restore_required(tsk);
-#ifdef CONFIG_SMP
- if (current->thread.regs && (current->thread.regs->msr & MSR_VSX))
- giveup_vsx(current);
- else
- giveup_vsx(NULL); /* just enable vsx for kernel - force */
-#else
- giveup_vsx(last_task_used_vsx);
-#endif /* CONFIG_SMP */
+ msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
+ if (tsk->thread.regs->msr & MSR_FP)
+ __giveup_fpu(tsk);
+ if (tsk->thread.regs->msr & MSR_VEC)
+ __giveup_altivec(tsk);
+ __giveup_vsx(tsk);
+ msr_check_and_clear(MSR_FP|MSR_VEC|MSR_VSX);
}
-EXPORT_SYMBOL(enable_kernel_vsx);
+EXPORT_SYMBOL(giveup_vsx);
-void giveup_vsx(struct task_struct *tsk)
+void enable_kernel_vsx(void)
{
- giveup_fpu_maybe_transactional(tsk);
- giveup_altivec_maybe_transactional(tsk);
- __giveup_vsx(tsk);
+ WARN_ON(preemptible());
+
+ msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
+
+ if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) {
+ check_if_tm_restore_required(current);
+ if (current->thread.regs->msr & MSR_FP)
+ __giveup_fpu(current);
+ if (current->thread.regs->msr & MSR_VEC)
+ __giveup_altivec(current);
+ __giveup_vsx(current);
+ }
}
-EXPORT_SYMBOL(giveup_vsx);
+EXPORT_SYMBOL(enable_kernel_vsx);
void flush_vsx_to_thread(struct task_struct *tsk)
{
if (tsk->thread.regs) {
preempt_disable();
if (tsk->thread.regs->msr & MSR_VSX) {
-#ifdef CONFIG_SMP
BUG_ON(tsk != current);
-#endif
giveup_vsx(tsk);
}
preempt_enable();
@@ -244,19 +278,26 @@ EXPORT_SYMBOL_GPL(flush_vsx_to_thread);
#endif /* CONFIG_VSX */
#ifdef CONFIG_SPE
+void giveup_spe(struct task_struct *tsk)
+{
+ check_if_tm_restore_required(tsk);
+
+ msr_check_and_set(MSR_SPE);
+ __giveup_spe(tsk);
+ msr_check_and_clear(MSR_SPE);
+}
+EXPORT_SYMBOL(giveup_spe);
void enable_kernel_spe(void)
{
WARN_ON(preemptible());
-#ifdef CONFIG_SMP
- if (current->thread.regs && (current->thread.regs->msr & MSR_SPE))
- giveup_spe(current);
- else
- giveup_spe(NULL); /* just enable SPE for kernel - force */
-#else
- giveup_spe(last_task_used_spe);
-#endif /* __SMP __ */
+ msr_check_and_set(MSR_SPE);
+
+ if (current->thread.regs && (current->thread.regs->msr & MSR_SPE)) {
+ check_if_tm_restore_required(current);
+ __giveup_spe(current);
+ }
}
EXPORT_SYMBOL(enable_kernel_spe);
@@ -265,9 +306,7 @@ void flush_spe_to_thread(struct task_struct *tsk)
if (tsk->thread.regs) {
preempt_disable();
if (tsk->thread.regs->msr & MSR_SPE) {
-#ifdef CONFIG_SMP
BUG_ON(tsk != current);
-#endif
tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
giveup_spe(tsk);
}
@@ -276,31 +315,81 @@ void flush_spe_to_thread(struct task_struct *tsk)
}
#endif /* CONFIG_SPE */
-#ifndef CONFIG_SMP
-/*
- * If we are doing lazy switching of CPU state (FP, altivec or SPE),
- * and the current task has some state, discard it.
- */
-void discard_lazy_cpu_state(void)
+static unsigned long msr_all_available;
+
+static int __init init_msr_all_available(void)
{
- preempt_disable();
- if (last_task_used_math == current)
- last_task_used_math = NULL;
+#ifdef CONFIG_PPC_FPU
+ msr_all_available |= MSR_FP;
+#endif
#ifdef CONFIG_ALTIVEC
- if (last_task_used_altivec == current)
- last_task_used_altivec = NULL;
-#endif /* CONFIG_ALTIVEC */
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ msr_all_available |= MSR_VEC;
+#endif
#ifdef CONFIG_VSX
- if (last_task_used_vsx == current)
- last_task_used_vsx = NULL;
-#endif /* CONFIG_VSX */
+ if (cpu_has_feature(CPU_FTR_VSX))
+ msr_all_available |= MSR_VSX;
+#endif
#ifdef CONFIG_SPE
- if (last_task_used_spe == current)
- last_task_used_spe = NULL;
+ if (cpu_has_feature(CPU_FTR_SPE))
+ msr_all_available |= MSR_SPE;
#endif
- preempt_enable();
+
+ return 0;
+}
+early_initcall(init_msr_all_available);
+
+void giveup_all(struct task_struct *tsk)
+{
+ unsigned long usermsr;
+
+ if (!tsk->thread.regs)
+ return;
+
+ usermsr = tsk->thread.regs->msr;
+
+ if ((usermsr & msr_all_available) == 0)
+ return;
+
+ msr_check_and_set(msr_all_available);
+
+#ifdef CONFIG_PPC_FPU
+ if (usermsr & MSR_FP)
+ __giveup_fpu(tsk);
+#endif
+#ifdef CONFIG_ALTIVEC
+ if (usermsr & MSR_VEC)
+ __giveup_altivec(tsk);
+#endif
+#ifdef CONFIG_VSX
+ if (usermsr & MSR_VSX)
+ __giveup_vsx(tsk);
+#endif
+#ifdef CONFIG_SPE
+ if (usermsr & MSR_SPE)
+ __giveup_spe(tsk);
+#endif
+
+ msr_check_and_clear(msr_all_available);
+}
+EXPORT_SYMBOL(giveup_all);
+
+void flush_all_to_thread(struct task_struct *tsk)
+{
+ if (tsk->thread.regs) {
+ preempt_disable();
+ BUG_ON(tsk != current);
+ giveup_all(tsk);
+
+#ifdef CONFIG_SPE
+ if (tsk->thread.regs->msr & MSR_SPE)
+ tsk->thread.spefscr = mfspr(SPRN_SPEFSCR);
+#endif
+
+ preempt_enable();
+ }
}
-#endif /* CONFIG_SMP */
+EXPORT_SYMBOL(flush_all_to_thread);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
void do_send_trap(struct pt_regs *regs, unsigned long address,
@@ -744,13 +833,15 @@ void restore_tm_state(struct pt_regs *regs)
msr_diff = current->thread.ckpt_regs.msr & ~regs->msr;
msr_diff &= MSR_FP | MSR_VEC | MSR_VSX;
if (msr_diff & MSR_FP) {
- fp_enable();
+ msr_check_and_set(MSR_FP);
load_fp_state(&current->thread.fp_state);
+ msr_check_and_clear(MSR_FP);
regs->msr |= current->thread.fpexc_mode;
}
if (msr_diff & MSR_VEC) {
- vec_enable();
+ msr_check_and_set(MSR_VEC);
load_vr_state(&current->thread.vr_state);
+ msr_check_and_clear(MSR_VEC);
}
regs->msr |= msr_diff;
}
@@ -760,112 +851,87 @@ void restore_tm_state(struct pt_regs *regs)
#define __switch_to_tm(prev)
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
-struct task_struct *__switch_to(struct task_struct *prev,
- struct task_struct *new)
+static inline void save_sprs(struct thread_struct *t)
{
- struct thread_struct *new_thread, *old_thread;
- struct task_struct *last;
-#ifdef CONFIG_PPC_BOOK3S_64
- struct ppc64_tlb_batch *batch;
+#ifdef CONFIG_ALTIVEC
+ if (cpu_has_feature(cpu_has_feature(CPU_FTR_ALTIVEC)))
+ t->vrsave = mfspr(SPRN_VRSAVE);
#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+ if (cpu_has_feature(CPU_FTR_DSCR))
+ t->dscr = mfspr(SPRN_DSCR);
- WARN_ON(!irqs_disabled());
+ if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+ t->bescr = mfspr(SPRN_BESCR);
+ t->ebbhr = mfspr(SPRN_EBBHR);
+ t->ebbrr = mfspr(SPRN_EBBRR);
- /* Back up the TAR and DSCR across context switches.
- * Note that the TAR is not available for use in the kernel. (To
- * provide this, the TAR should be backed up/restored on exception
- * entry/exit instead, and be in pt_regs. FIXME, this should be in
- * pt_regs anyway (for debug).)
- * Save the TAR and DSCR here before we do treclaim/trecheckpoint as
- * these will change them.
- */
- save_early_sprs(&prev->thread);
+ t->fscr = mfspr(SPRN_FSCR);
- __switch_to_tm(prev);
+ /*
+ * Note that the TAR is not available for use in the kernel.
+ * (To provide this, the TAR should be backed up/restored on
+ * exception entry/exit instead, and be in pt_regs. FIXME,
+ * this should be in pt_regs anyway (for debug).)
+ */
+ t->tar = mfspr(SPRN_TAR);
+ }
+#endif
+}
-#ifdef CONFIG_SMP
- /* avoid complexity of lazy save/restore of fpu
- * by just saving it every time we switch out if
- * this task used the fpu during the last quantum.
- *
- * If it tries to use the fpu again, it'll trap and
- * reload its fp regs. So we don't have to do a restore
- * every switch, just a save.
- * -- Cort
- */
- if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP))
- giveup_fpu(prev);
+static inline void restore_sprs(struct thread_struct *old_thread,
+ struct thread_struct *new_thread)
+{
#ifdef CONFIG_ALTIVEC
- /*
- * If the previous thread used altivec in the last quantum
- * (thus changing altivec regs) then save them.
- * We used to check the VRSAVE register but not all apps
- * set it, so we don't rely on it now (and in fact we need
- * to save & restore VSCR even if VRSAVE == 0). -- paulus
- *
- * On SMP we always save/restore altivec regs just to avoid the
- * complexity of changing processors.
- * -- Cort
- */
- if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC))
- giveup_altivec(prev);
-#endif /* CONFIG_ALTIVEC */
-#ifdef CONFIG_VSX
- if (prev->thread.regs && (prev->thread.regs->msr & MSR_VSX))
- /* VMX and FPU registers are already save here */
- __giveup_vsx(prev);
-#endif /* CONFIG_VSX */
-#ifdef CONFIG_SPE
- /*
- * If the previous thread used spe in the last quantum
- * (thus changing spe regs) then save them.
- *
- * On SMP we always save/restore spe regs just to avoid the
- * complexity of changing processors.
- */
- if ((prev->thread.regs && (prev->thread.regs->msr & MSR_SPE)))
- giveup_spe(prev);
-#endif /* CONFIG_SPE */
+ if (cpu_has_feature(CPU_FTR_ALTIVEC) &&
+ old_thread->vrsave != new_thread->vrsave)
+ mtspr(SPRN_VRSAVE, new_thread->vrsave);
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+ if (cpu_has_feature(CPU_FTR_DSCR)) {
+ u64 dscr = get_paca()->dscr_default;
+ u64 fscr = old_thread->fscr & ~FSCR_DSCR;
-#else /* CONFIG_SMP */
-#ifdef CONFIG_ALTIVEC
- /* Avoid the trap. On smp this this never happens since
- * we don't set last_task_used_altivec -- Cort
- */
- if (new->thread.regs && last_task_used_altivec == new)
- new->thread.regs->msr |= MSR_VEC;
-#endif /* CONFIG_ALTIVEC */
-#ifdef CONFIG_VSX
- if (new->thread.regs && last_task_used_vsx == new)
- new->thread.regs->msr |= MSR_VSX;
-#endif /* CONFIG_VSX */
-#ifdef CONFIG_SPE
- /* Avoid the trap. On smp this this never happens since
- * we don't set last_task_used_spe
- */
- if (new->thread.regs && last_task_used_spe == new)
- new->thread.regs->msr |= MSR_SPE;
-#endif /* CONFIG_SPE */
+ if (new_thread->dscr_inherit) {
+ dscr = new_thread->dscr;
+ fscr |= FSCR_DSCR;
+ }
-#endif /* CONFIG_SMP */
+ if (old_thread->dscr != dscr)
+ mtspr(SPRN_DSCR, dscr);
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
- switch_booke_debug_regs(&new->thread.debug);
-#else
-/*
- * For PPC_BOOK3S_64, we use the hw-breakpoint interfaces that would
- * schedule DABR
- */
-#ifndef CONFIG_HAVE_HW_BREAKPOINT
- if (unlikely(!hw_brk_match(this_cpu_ptr(&current_brk), &new->thread.hw_brk)))
- __set_breakpoint(&new->thread.hw_brk);
-#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+ if (old_thread->fscr != fscr)
+ mtspr(SPRN_FSCR, fscr);
+ }
+
+ if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+ if (old_thread->bescr != new_thread->bescr)
+ mtspr(SPRN_BESCR, new_thread->bescr);
+ if (old_thread->ebbhr != new_thread->ebbhr)
+ mtspr(SPRN_EBBHR, new_thread->ebbhr);
+ if (old_thread->ebbrr != new_thread->ebbrr)
+ mtspr(SPRN_EBBRR, new_thread->ebbrr);
+
+ if (old_thread->tar != new_thread->tar)
+ mtspr(SPRN_TAR, new_thread->tar);
+ }
#endif
+}
+struct task_struct *__switch_to(struct task_struct *prev,
+ struct task_struct *new)
+{
+ struct thread_struct *new_thread, *old_thread;
+ struct task_struct *last;
+#ifdef CONFIG_PPC_BOOK3S_64
+ struct ppc64_tlb_batch *batch;
+#endif
new_thread = &new->thread;
old_thread = &current->thread;
+ WARN_ON(!irqs_disabled());
+
#ifdef CONFIG_PPC64
/*
* Collect processor utilization data per process
@@ -890,6 +956,30 @@ struct task_struct *__switch_to(struct task_struct *prev,
}
#endif /* CONFIG_PPC_BOOK3S_64 */
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ switch_booke_debug_regs(&new->thread.debug);
+#else
+/*
+ * For PPC_BOOK3S_64, we use the hw-breakpoint interfaces that would
+ * schedule DABR
+ */
+#ifndef CONFIG_HAVE_HW_BREAKPOINT
+ if (unlikely(!hw_brk_match(this_cpu_ptr(&current_brk), &new->thread.hw_brk)))
+ __set_breakpoint(&new->thread.hw_brk);
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#endif
+
+ /*
+ * We need to save SPRs before treclaim/trecheckpoint as these will
+ * change a number of them.
+ */
+ save_sprs(&prev->thread);
+
+ __switch_to_tm(prev);
+
+ /* Save FPU, Altivec, VSX and SPE state */
+ giveup_all(prev);
+
/*
* We can't take a PMU exception inside _switch() since there is a
* window where the kernel stack SLB and the kernel stack are out
@@ -899,6 +989,15 @@ struct task_struct *__switch_to(struct task_struct *prev,
tm_recheckpoint_new_task(new);
+ /*
+ * Call restore_sprs() before calling _switch(). If we move it after
+ * _switch() then we miss out on calling it for new tasks. The reason
+ * for this is we manually create a stack frame for new tasks that
+ * directly returns through ret_from_fork() or
+ * ret_from_kernel_thread(). See copy_thread() for details.
+ */
+ restore_sprs(old_thread, new_thread);
+
last = _switch(old_thread, new_thread);
#ifdef CONFIG_PPC_BOOK3S_64
@@ -952,10 +1051,12 @@ static void show_instructions(struct pt_regs *regs)
printk("\n");
}
-static struct regbit {
+struct regbit {
unsigned long bit;
const char *name;
-} msr_bits[] = {
+};
+
+static struct regbit msr_bits[] = {
#if defined(CONFIG_PPC64) && !defined(CONFIG_BOOKE)
{MSR_SF, "SF"},
{MSR_HV, "HV"},
@@ -985,16 +1086,49 @@ static struct regbit {
{0, NULL}
};
-static void printbits(unsigned long val, struct regbit *bits)
+static void print_bits(unsigned long val, struct regbit *bits, const char *sep)
{
- const char *sep = "";
+ const char *s = "";
- printk("<");
for (; bits->bit; ++bits)
if (val & bits->bit) {
- printk("%s%s", sep, bits->name);
- sep = ",";
+ printk("%s%s", s, bits->name);
+ s = sep;
}
+}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static struct regbit msr_tm_bits[] = {
+ {MSR_TS_T, "T"},
+ {MSR_TS_S, "S"},
+ {MSR_TM, "E"},
+ {0, NULL}
+};
+
+static void print_tm_bits(unsigned long val)
+{
+/*
+ * This only prints something if at least one of the TM bit is set.
+ * Inside the TM[], the output means:
+ * E: Enabled (bit 32)
+ * S: Suspended (bit 33)
+ * T: Transactional (bit 34)
+ */
+ if (val & (MSR_TM | MSR_TS_S | MSR_TS_T)) {
+ printk(",TM[");
+ print_bits(val, msr_tm_bits, "");
+ printk("]");
+ }
+}
+#else
+static void print_tm_bits(unsigned long val) {}
+#endif
+
+static void print_msr_bits(unsigned long val)
+{
+ printk("<");
+ print_bits(val, msr_bits, ",");
+ print_tm_bits(val);
printk(">");
}
@@ -1019,7 +1153,7 @@ void show_regs(struct pt_regs * regs)
printk("REGS: %p TRAP: %04lx %s (%s)\n",
regs, regs->trap, print_tainted(), init_utsname()->release);
printk("MSR: "REG" ", regs->msr);
- printbits(regs->msr, msr_bits);
+ print_msr_bits(regs->msr);
printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer);
trap = TRAP(regs);
if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR))
@@ -1061,13 +1195,10 @@ void show_regs(struct pt_regs * regs)
void exit_thread(void)
{
- discard_lazy_cpu_state();
}
void flush_thread(void)
{
- discard_lazy_cpu_state();
-
#ifdef CONFIG_HAVE_HW_BREAKPOINT
flush_ptrace_hw_breakpoint(current);
#else /* CONFIG_HAVE_HW_BREAKPOINT */
@@ -1086,10 +1217,7 @@ release_thread(struct task_struct *t)
*/
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- flush_fp_to_thread(src);
- flush_altivec_to_thread(src);
- flush_vsx_to_thread(src);
- flush_spe_to_thread(src);
+ flush_all_to_thread(src);
/*
* Flush TM state out so we can copy it. __switch_to_tm() does this
* flush but it removes the checkpointed state from the current CPU and
@@ -1212,7 +1340,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
#ifdef CONFIG_PPC64
if (cpu_has_feature(CPU_FTR_DSCR)) {
p->thread.dscr_inherit = current->thread.dscr_inherit;
- p->thread.dscr = current->thread.dscr;
+ p->thread.dscr = mfspr(SPRN_DSCR);
}
if (cpu_has_feature(CPU_FTR_HAS_PPR))
p->thread.ppr = INIT_PPR;
@@ -1305,7 +1433,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
regs->msr = MSR_USER32;
}
#endif
- discard_lazy_cpu_state();
#ifdef CONFIG_VSX
current->thread.used_vsr = 0;
#endif
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 92dea8df6b26..da5192590c44 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -389,6 +389,7 @@ static void __init prom_printf(const char *format, ...)
break;
}
}
+ va_end(args);
}
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 737c0d0b53ac..30a03c03fe73 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -60,6 +60,7 @@ struct pt_regs_offset {
#define STR(s) #s /* convert to string */
#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
#define GPR_OFFSET_NAME(num) \
+ {.name = STR(r##num), .offset = offsetof(struct pt_regs, gpr[num])}, \
{.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])}
#define REG_OFFSET_END {.name = NULL, .offset = 0}
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 5a753fae8265..28736ff27fea 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -44,6 +44,9 @@
#include <asm/mmu.h>
#include <asm/topology.h>
+/* This is here deliberately so it's only used in this file */
+void enter_rtas(unsigned long);
+
struct rtas_t rtas = {
.lock = __ARCH_SPIN_LOCK_UNLOCKED
};
@@ -93,21 +96,13 @@ static void unlock_rtas(unsigned long flags)
*/
static void call_rtas_display_status(unsigned char c)
{
- struct rtas_args *args = &rtas.args;
unsigned long s;
if (!rtas.base)
return;
- s = lock_rtas();
-
- args->token = cpu_to_be32(10);
- args->nargs = cpu_to_be32(1);
- args->nret = cpu_to_be32(1);
- args->rets = &(args->args[1]);
- args->args[0] = cpu_to_be32(c);
-
- enter_rtas(__pa(args));
+ s = lock_rtas();
+ rtas_call_unlocked(&rtas.args, 10, 1, 1, NULL, c);
unlock_rtas(s);
}
@@ -418,6 +413,36 @@ static char *__fetch_rtas_last_error(char *altbuf)
#define get_errorlog_buffer() NULL
#endif
+
+static void
+va_rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret,
+ va_list list)
+{
+ int i;
+
+ args->token = cpu_to_be32(token);
+ args->nargs = cpu_to_be32(nargs);
+ args->nret = cpu_to_be32(nret);
+ args->rets = &(args->args[nargs]);
+
+ for (i = 0; i < nargs; ++i)
+ args->args[i] = cpu_to_be32(va_arg(list, __u32));
+
+ for (i = 0; i < nret; ++i)
+ args->rets[i] = 0;
+
+ enter_rtas(__pa(args));
+}
+
+void rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, ...)
+{
+ va_list list;
+
+ va_start(list, nret);
+ va_rtas_call_unlocked(args, token, nargs, nret, list);
+ va_end(list);
+}
+
int rtas_call(int token, int nargs, int nret, int *outputs, ...)
{
va_list list;
@@ -431,22 +456,14 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
return -1;
s = lock_rtas();
+
+ /* We use the global rtas args buffer */
rtas_args = &rtas.args;
- rtas_args->token = cpu_to_be32(token);
- rtas_args->nargs = cpu_to_be32(nargs);
- rtas_args->nret = cpu_to_be32(nret);
- rtas_args->rets = &(rtas_args->args[nargs]);
va_start(list, outputs);
- for (i = 0; i < nargs; ++i)
- rtas_args->args[i] = cpu_to_be32(va_arg(list, __u32));
+ va_rtas_call_unlocked(rtas_args, token, nargs, nret, list);
va_end(list);
- for (i = 0; i < nret; ++i)
- rtas_args->rets[i] = 0;
-
- enter_rtas(__pa(rtas_args));
-
/* A -1 return code indicates that the last command couldn't
be completed due to a hardware error. */
if (be32_to_cpu(rtas_args->rets[0]) == -1)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index ef7c24e84a62..b6aa378aff63 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -458,7 +458,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
* contains valid data
*/
if (current->thread.used_vsr && ctx_has_vsx_region) {
- __giveup_vsx(current);
+ flush_vsx_to_thread(current);
if (copy_vsx_to_user(&frame->mc_vsregs, current))
return 1;
msr |= MSR_VSX;
@@ -606,7 +606,7 @@ static int save_tm_user_regs(struct pt_regs *regs,
* contains valid data
*/
if (current->thread.used_vsr) {
- __giveup_vsx(current);
+ flush_vsx_to_thread(current);
if (copy_vsx_to_user(&frame->mc_vsregs, current))
return 1;
if (msr & MSR_VSX) {
@@ -687,15 +687,6 @@ static long restore_user_regs(struct pt_regs *regs,
if (sig)
regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
- /*
- * Do this before updating the thread state in
- * current->thread.fpr/vr/evr. That way, if we get preempted
- * and another task grabs the FPU/Altivec/SPE, it won't be
- * tempted to save the current CPU state into the thread_struct
- * and corrupt what we are writing there.
- */
- discard_lazy_cpu_state();
-
#ifdef CONFIG_ALTIVEC
/*
* Force the process to reload the altivec registers from
@@ -798,15 +789,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
/* Restore the previous little-endian mode */
regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
- /*
- * Do this before updating the thread state in
- * current->thread.fpr/vr/evr. That way, if we get preempted
- * and another task grabs the FPU/Altivec/SPE, it won't be
- * tempted to save the current CPU state into the thread_struct
- * and corrupt what we are writing there.
- */
- discard_lazy_cpu_state();
-
#ifdef CONFIG_ALTIVEC
regs->msr &= ~MSR_VEC;
if (msr & MSR_VEC) {
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index c676ecec0869..25520794aa37 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -147,7 +147,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
* VMX data.
*/
if (current->thread.used_vsr && ctx_has_vsx_region) {
- __giveup_vsx(current);
+ flush_vsx_to_thread(current);
v_regs += ELF_NVRREG;
err |= copy_vsx_to_user(v_regs, current);
/* set MSR_VSX in the MSR value in the frame to
@@ -270,7 +270,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
* VMX data.
*/
if (current->thread.used_vsr) {
- __giveup_vsx(current);
+ flush_vsx_to_thread(current);
v_regs += ELF_NVRREG;
tm_v_regs += ELF_NVRREG;
@@ -350,15 +350,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
err |= __get_user(set->sig[0], &sc->oldmask);
/*
- * Do this before updating the thread state in
- * current->thread.fpr/vr. That way, if we get preempted
- * and another task grabs the FPU/Altivec, it won't be
- * tempted to save the current CPU state into the thread_struct
- * and corrupt what we are writing there.
- */
- discard_lazy_cpu_state();
-
- /*
* Force reload of FP/VEC.
* This has to be done before copying stuff into current->thread.fpr/vr
* for the reasons explained in the previous comment.
@@ -469,15 +460,6 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);
/*
- * Do this before updating the thread state in
- * current->thread.fpr/vr. That way, if we get preempted
- * and another task grabs the FPU/Altivec, it won't be
- * tempted to save the current CPU state into the thread_struct
- * and corrupt what we are writing there.
- */
- discard_lazy_cpu_state();
-
- /*
* Force reload of FP/VEC.
* This has to be done before copying stuff into current->thread.fpr/vr
* for the reasons explained in the previous comment.
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c
index ea43a347a104..4f24606afc3f 100644
--- a/arch/powerpc/kernel/stacktrace.c
+++ b/arch/powerpc/kernel/stacktrace.c
@@ -61,3 +61,10 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
save_context_stack(trace, tsk->thread.ksp, tsk, 0);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+
+void
+save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
+{
+ save_context_stack(trace, regs->gpr[1], current, 0);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_regs);
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
index eae33e10b65f..6669b1752512 100644
--- a/arch/powerpc/kernel/swsusp.c
+++ b/arch/powerpc/kernel/swsusp.c
@@ -20,9 +20,7 @@ void save_processor_state(void)
* flush out all the special registers so we don't need
* to save them in the snapshot
*/
- flush_fp_to_thread(current);
- flush_altivec_to_thread(current);
- flush_spe_to_thread(current);
+ flush_all_to_thread(current);
#ifdef CONFIG_PPC64
hard_irq_disable();
diff --git a/arch/powerpc/kernel/systbl_chk.c b/arch/powerpc/kernel/systbl_chk.c
index 2384129f5893..55323a620cfe 100644
--- a/arch/powerpc/kernel/systbl_chk.c
+++ b/arch/powerpc/kernel/systbl_chk.c
@@ -57,4 +57,4 @@
START_TABLE
#include <asm/systbl.h>
-END_TABLE __NR_syscalls
+END_TABLE NR_syscalls
diff --git a/arch/powerpc/kernel/systbl_chk.sh b/arch/powerpc/kernel/systbl_chk.sh
index 19415e7674a5..31b6e7c358ca 100644
--- a/arch/powerpc/kernel/systbl_chk.sh
+++ b/arch/powerpc/kernel/systbl_chk.sh
@@ -16,7 +16,7 @@ awk 'BEGIN { num = -1; } # Ignore the beginning of the file
/^START_TABLE/ { num = 0; next; }
/^END_TABLE/ {
if (num != $2) {
- printf "__NR_syscalls (%s) is not one more than the last syscall (%s)\n",
+ printf "NR_syscalls (%s) is not one more than the last syscall (%s)\n",
$2, num - 1;
exit(1);
}
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 1be1092c7204..81b0900a39ee 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -1002,38 +1002,6 @@ static int month_days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
-/*
- * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
- */
-void GregorianDay(struct rtc_time * tm)
-{
- int leapsToDate;
- int lastYear;
- int day;
- int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
- lastYear = tm->tm_year - 1;
-
- /*
- * Number of leap corrections to apply up to end of last year
- */
- leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
-
- /*
- * This year is a leap year if it is divisible by 4 except when it is
- * divisible by 100 unless it is divisible by 400
- *
- * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
- */
- day = tm->tm_mon > 2 && leapyear(tm->tm_year);
-
- day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
- tm->tm_mday;
-
- tm->tm_wday = day % 7;
-}
-EXPORT_SYMBOL_GPL(GregorianDay);
-
void to_tm(int tim, struct rtc_time * tm)
{
register int i;
@@ -1064,9 +1032,9 @@ void to_tm(int tim, struct rtc_time * tm)
tm->tm_mday = day + 1;
/*
- * Determine the day of week
+ * No-one uses the day of the week.
*/
- GregorianDay(tm);
+ tm->tm_wday = -1;
}
EXPORT_SYMBOL(to_tm);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 37de90f8a845..b6becc795bb5 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1313,13 +1313,6 @@ void nonrecoverable_exception(struct pt_regs *regs)
die("nonrecoverable exception", regs, SIGKILL);
}
-void trace_syscall(struct pt_regs *regs)
-{
- printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n",
- current, task_pid_nr(current), regs->nip, regs->link, regs->gpr[0],
- regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted());
-}
-
void kernel_fp_unavailable_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index b457bfa28436..def1b8b5e6c1 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -671,7 +671,7 @@ static void __init vdso_setup_syscall_map(void)
extern unsigned long sys_ni_syscall;
- for (i = 0; i < __NR_syscalls; i++) {
+ for (i = 0; i < NR_syscalls; i++) {
#ifdef CONFIG_PPC64
if (sys_call_table[i*2] != sys_ni_syscall)
vdso_data->syscall_map_64[i >> 5] |=
diff --git a/arch/powerpc/kernel/vdso32/datapage.S b/arch/powerpc/kernel/vdso32/datapage.S
index 59cf5f452879..3745113fcc65 100644
--- a/arch/powerpc/kernel/vdso32/datapage.S
+++ b/arch/powerpc/kernel/vdso32/datapage.S
@@ -61,7 +61,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map)
addi r3,r3,CFG_SYSCALL_MAP32
cmpli cr0,r4,0
beqlr
- li r0,__NR_syscalls
+ li r0,NR_syscalls
stw r0,0(r4)
crclr cr0*4+so
blr
diff --git a/arch/powerpc/kernel/vdso64/datapage.S b/arch/powerpc/kernel/vdso64/datapage.S
index 2f01c4a0d8a0..184a6ba7f283 100644
--- a/arch/powerpc/kernel/vdso64/datapage.S
+++ b/arch/powerpc/kernel/vdso64/datapage.S
@@ -62,7 +62,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map)
cmpli cr0,r4,0
crclr cr0*4+so
beqlr
- li r0,__NR_syscalls
+ li r0,NR_syscalls
stw r0,0(r4)
blr
.cfi_endproc
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index f5c80d567d8d..162d0f714941 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -29,24 +29,10 @@ _GLOBAL(do_load_up_transact_altivec)
addi r10,r3,THREAD_TRANSACT_VRSTATE
REST_32VRS(0,r4,r10)
- /* Disable VEC again. */
- MTMSRD(r6)
- isync
-
blr
#endif
/*
- * Enable use of VMX/Altivec for the caller.
- */
-_GLOBAL(vec_enable)
- mfmsr r3
- oris r3,r3,MSR_VEC@h
- MTMSRD(r3)
- isync
- blr
-
-/*
* Load state from memory into VMX registers including VSCR.
* Assumes the caller has enabled VMX in the MSR.
*/
@@ -84,39 +70,6 @@ _GLOBAL(load_up_altivec)
MTMSRD(r5) /* enable use of AltiVec now */
isync
-/*
- * For SMP, we don't do lazy VMX switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_altvec in switch_to.
- * VRSAVE isn't dealt with here, that is done in the normal context
- * switch code. Note that we could rely on vrsave value to eventually
- * avoid saving all of the VREGs here...
- */
-#ifndef CONFIG_SMP
- LOAD_REG_ADDRBASE(r3, last_task_used_altivec)
- toreal(r3)
- PPC_LL r4,ADDROFF(last_task_used_altivec)(r3)
- PPC_LCMPI 0,r4,0
- beq 1f
-
- /* Save VMX state to last_task_used_altivec's THREAD struct */
- toreal(r4)
- addi r4,r4,THREAD
- addi r6,r4,THREAD_VRSTATE
- SAVE_32VRS(0,r5,r6)
- mfvscr v0
- li r10,VRSTATE_VSCR
- stvx v0,r10,r6
- /* Disable VMX for last_task_used_altivec */
- PPC_LL r5,PT_REGS(r4)
- toreal(r5)
- PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r10,MSR_VEC@h
- andc r4,r4,r10
- PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
-
/* Hack: if we get an altivec unavailable trap with VRSAVE
* set to all zeros, we assume this is a broken application
* that fails to set it properly, and thus we switch it to
@@ -145,39 +98,15 @@ _GLOBAL(load_up_altivec)
lvx v0,r10,r6
mtvscr v0
REST_32VRS(0,r4,r6)
-#ifndef CONFIG_SMP
- /* Update last_task_used_altivec to 'current' */
- subi r4,r5,THREAD /* Back to 'current' */
- fromreal(r4)
- PPC_STL r4,ADDROFF(last_task_used_altivec)(r3)
-#endif /* CONFIG_SMP */
/* restore registers and return */
blr
-_GLOBAL(giveup_altivec_notask)
- mfmsr r3
- andis. r4,r3,MSR_VEC@h
- bnelr /* Already enabled? */
- oris r3,r3,MSR_VEC@h
- SYNC
- MTMSRD(r3) /* enable use of VMX now */
- isync
- blr
-
/*
- * giveup_altivec(tsk)
+ * __giveup_altivec(tsk)
* Disable VMX for the task given as the argument,
* and save the vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
*/
-_GLOBAL(giveup_altivec)
- mfmsr r5
- oris r5,r5,MSR_VEC@h
- SYNC
- MTMSRD(r5) /* enable use of VMX now */
- isync
- PPC_LCMPI 0,r3,0
- beqlr /* if no previous owner, done */
+_GLOBAL(__giveup_altivec)
addi r3,r3,THREAD /* want THREAD of task */
PPC_LL r7,THREAD_VRSAVEAREA(r3)
PPC_LL r5,PT_REGS(r3)
@@ -203,11 +132,6 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
andc r4,r4,r3 /* disable FP for previous task */
PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
1:
-#ifndef CONFIG_SMP
- li r5,0
- LOAD_REG_ADDRBASE(r4,last_task_used_altivec)
- PPC_STL r5,ADDROFF(last_task_used_altivec)(r4)
-#endif /* CONFIG_SMP */
blr
#ifdef CONFIG_VSX
@@ -230,20 +154,6 @@ _GLOBAL(load_up_vsx)
andis. r5,r12,MSR_VEC@h
beql+ load_up_altivec /* skip if already loaded */
-#ifndef CONFIG_SMP
- ld r3,last_task_used_vsx@got(r2)
- ld r4,0(r3)
- cmpdi 0,r4,0
- beq 1f
- /* Disable VSX for last_task_used_vsx */
- addi r4,r4,THREAD
- ld r5,PT_REGS(r4)
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r6,MSR_VSX@h
- andc r6,r4,r6
- std r6,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
ld r4,PACACURRENT(r13)
addi r4,r4,THREAD /* Get THREAD */
li r6,1
@@ -251,27 +161,14 @@ _GLOBAL(load_up_vsx)
/* enable use of VSX after return */
oris r12,r12,MSR_VSX@h
std r12,_MSR(r1)
-#ifndef CONFIG_SMP
- /* Update last_task_used_vsx to 'current' */
- ld r4,PACACURRENT(r13)
- std r4,0(r3)
-#endif /* CONFIG_SMP */
b fast_exception_return
/*
* __giveup_vsx(tsk)
* Disable VSX for the task given as the argument.
* Does NOT save vsx registers.
- * Enables the VSX for use in the kernel on return.
*/
_GLOBAL(__giveup_vsx)
- mfmsr r5
- oris r5,r5,MSR_VSX@h
- mtmsrd r5 /* enable use of VSX now */
- isync
-
- cmpdi 0,r3,0
- beqlr- /* if no previous owner, done */
addi r3,r3,THREAD /* want THREAD of task */
ld r5,PT_REGS(r3)
cmpdi 0,r5,0
@@ -281,11 +178,6 @@ _GLOBAL(__giveup_vsx)
andc r4,r4,r3 /* disable VSX for previous task */
std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
1:
-#ifndef CONFIG_SMP
- li r5,0
- ld r4,last_task_used_vsx@got(r2)
- std r5,0(r4)
-#endif /* CONFIG_SMP */
blr
#endif /* CONFIG_VSX */
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 099c79d8c160..638c6d9be9e0 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -366,7 +366,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvmppc_core_prepare_to_enter);
-pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
+kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
bool *writable)
{
ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM;
@@ -379,9 +379,9 @@ pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
gpa &= ~0xFFFULL;
if (unlikely(mp_pa) && unlikely((gpa & KVM_PAM) == mp_pa)) {
ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
- pfn_t pfn;
+ kvm_pfn_t pfn;
- pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
+ pfn = (kvm_pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
get_page(pfn_to_page(pfn));
if (writable)
*writable = true;
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index d5c9bfeb0c9c..55c4d51ea3e2 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -142,7 +142,7 @@ extern char etext[];
int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
bool iswrite)
{
- pfn_t hpaddr;
+ kvm_pfn_t hpaddr;
u64 vpn;
u64 vsid;
struct kvmppc_sid_map *map;
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index 79ad35abd196..913cd2198fa6 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -83,7 +83,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
bool iswrite)
{
unsigned long vpn;
- pfn_t hpaddr;
+ kvm_pfn_t hpaddr;
ulong hash, hpteg;
u64 vsid;
int ret;
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 6b352691b8c9..cff207b72c46 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2700,9 +2700,8 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
goto out;
}
- flush_fp_to_thread(current);
- flush_altivec_to_thread(current);
- flush_vsx_to_thread(current);
+ flush_all_to_thread(current);
+
vcpu->arch.wqp = &vcpu->arch.vcore->wq;
vcpu->arch.pgdir = current->mm->pgd;
vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index a759d9adb0b6..eab96cfe82fa 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -1265,6 +1265,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
if (rcomp)
kvmppc_set_cr(vcpu, cr);
+ disable_kernel_fp();
preempt_enable();
return emulated;
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 70fb08da416d..95bceca8f40e 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -751,6 +751,7 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
preempt_disable();
enable_kernel_fp();
load_fp_state(&vcpu->arch.fp);
+ disable_kernel_fp();
t->fp_save_area = &vcpu->arch.fp;
preempt_enable();
}
@@ -760,6 +761,7 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
preempt_disable();
enable_kernel_altivec();
load_vr_state(&vcpu->arch.vr);
+ disable_kernel_altivec();
t->vr_save_area = &vcpu->arch.vr;
preempt_enable();
#endif
@@ -788,6 +790,7 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
preempt_disable();
enable_kernel_fp();
load_fp_state(&vcpu->arch.fp);
+ disable_kernel_fp();
preempt_enable();
}
#ifdef CONFIG_ALTIVEC
@@ -795,6 +798,7 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
preempt_disable();
enable_kernel_altivec();
load_vr_state(&vcpu->arch.vr);
+ disable_kernel_altivec();
preempt_enable();
}
#endif
@@ -1486,21 +1490,8 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
goto out;
/* interrupts now hard-disabled */
- /* Save FPU state in thread_struct */
- if (current->thread.regs->msr & MSR_FP)
- giveup_fpu(current);
-
-#ifdef CONFIG_ALTIVEC
- /* Save Altivec state in thread_struct */
- if (current->thread.regs->msr & MSR_VEC)
- giveup_altivec(current);
-#endif
-
-#ifdef CONFIG_VSX
- /* Save VSX state in thread_struct */
- if (current->thread.regs->msr & MSR_VSX)
- __giveup_vsx(current);
-#endif
+ /* Save FPU, Altivec and VSX state */
+ giveup_all(current);
/* Preload FPU if it's enabled */
if (kvmppc_get_msr(vcpu) & MSR_FP)
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index fd5875179e5c..778ef86e187e 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -98,6 +98,7 @@ void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu)
preempt_disable();
enable_kernel_spe();
kvmppc_save_guest_spe(vcpu);
+ disable_kernel_spe();
vcpu->arch.shadow_msr &= ~MSR_SPE;
preempt_enable();
}
@@ -107,6 +108,7 @@ static void kvmppc_vcpu_enable_spe(struct kvm_vcpu *vcpu)
preempt_disable();
enable_kernel_spe();
kvmppc_load_guest_spe(vcpu);
+ disable_kernel_spe();
vcpu->arch.shadow_msr |= MSR_SPE;
preempt_enable();
}
@@ -141,6 +143,7 @@ static inline void kvmppc_load_guest_fp(struct kvm_vcpu *vcpu)
if (!(current->thread.regs->msr & MSR_FP)) {
enable_kernel_fp();
load_fp_state(&vcpu->arch.fp);
+ disable_kernel_fp();
current->thread.fp_save_area = &vcpu->arch.fp;
current->thread.regs->msr |= MSR_FP;
}
@@ -182,6 +185,7 @@ static inline void kvmppc_load_guest_altivec(struct kvm_vcpu *vcpu)
if (!(current->thread.regs->msr & MSR_VEC)) {
enable_kernel_altivec();
load_vr_state(&vcpu->arch.vr);
+ disable_kernel_altivec();
current->thread.vr_save_area = &vcpu->arch.vr;
current->thread.regs->msr |= MSR_VEC;
}
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h
index 72920bed3ac6..94f04fcb373e 100644
--- a/arch/powerpc/kvm/e500.h
+++ b/arch/powerpc/kvm/e500.h
@@ -41,7 +41,7 @@ enum vcpu_ftr {
#define E500_TLB_MAS2_ATTR (0x7f)
struct tlbe_ref {
- pfn_t pfn; /* valid only for TLB0, except briefly */
+ kvm_pfn_t pfn; /* valid only for TLB0, except briefly */
unsigned int flags; /* E500_TLB_* */
};
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
index 34c43fff4adb..b0333cc737dd 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -163,9 +163,9 @@ void kvmppc_map_magic(struct kvm_vcpu *vcpu)
struct kvm_book3e_206_tlb_entry magic;
ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
unsigned int stid;
- pfn_t pfn;
+ kvm_pfn_t pfn;
- pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
+ pfn = (kvm_pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
get_page(pfn_to_page(pfn));
preempt_disable();
@@ -246,7 +246,7 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
struct kvm_book3e_206_tlb_entry *gtlbe,
- pfn_t pfn, unsigned int wimg)
+ kvm_pfn_t pfn, unsigned int wimg)
{
ref->pfn = pfn;
ref->flags = E500_TLB_VALID;
@@ -309,7 +309,7 @@ static void kvmppc_e500_setup_stlbe(
int tsize, struct tlbe_ref *ref, u64 gvaddr,
struct kvm_book3e_206_tlb_entry *stlbe)
{
- pfn_t pfn = ref->pfn;
+ kvm_pfn_t pfn = ref->pfn;
u32 pr = vcpu->arch.shared->msr & MSR_PR;
BUG_ON(!(ref->flags & E500_TLB_VALID));
diff --git a/arch/powerpc/kvm/trace_pr.h b/arch/powerpc/kvm/trace_pr.h
index 810507cb688a..d44f324184fb 100644
--- a/arch/powerpc/kvm/trace_pr.h
+++ b/arch/powerpc/kvm/trace_pr.h
@@ -30,7 +30,7 @@ TRACE_EVENT(kvm_book3s_reenter,
#ifdef CONFIG_PPC_BOOK3S_64
TRACE_EVENT(kvm_book3s_64_mmu_map,
- TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr,
+ TP_PROTO(int rflags, ulong hpteg, ulong va, kvm_pfn_t hpaddr,
struct kvmppc_pte *orig_pte),
TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte),
diff --git a/arch/powerpc/lib/vmx-helper.c b/arch/powerpc/lib/vmx-helper.c
index ac93a3bd2730..b27e030fc9f8 100644
--- a/arch/powerpc/lib/vmx-helper.c
+++ b/arch/powerpc/lib/vmx-helper.c
@@ -46,6 +46,7 @@ int enter_vmx_usercopy(void)
*/
int exit_vmx_usercopy(void)
{
+ disable_kernel_altivec();
pagefault_enable();
preempt_enable();
return 0;
@@ -70,6 +71,7 @@ int enter_vmx_copy(void)
*/
void *exit_vmx_copy(void *dest)
{
+ disable_kernel_altivec();
preempt_enable();
return dest;
}
diff --git a/arch/powerpc/lib/xor_vmx.c b/arch/powerpc/lib/xor_vmx.c
index e905f7c2ea7b..07f49f1568e5 100644
--- a/arch/powerpc/lib/xor_vmx.c
+++ b/arch/powerpc/lib/xor_vmx.c
@@ -74,6 +74,7 @@ void xor_altivec_2(unsigned long bytes, unsigned long *v1_in,
v2 += 4;
} while (--lines > 0);
+ disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_2);
@@ -102,6 +103,7 @@ void xor_altivec_3(unsigned long bytes, unsigned long *v1_in,
v3 += 4;
} while (--lines > 0);
+ disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_3);
@@ -135,6 +137,7 @@ void xor_altivec_4(unsigned long bytes, unsigned long *v1_in,
v4 += 4;
} while (--lines > 0);
+ disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_4);
@@ -172,6 +175,7 @@ void xor_altivec_5(unsigned long bytes, unsigned long *v1_in,
v5 += 4;
} while (--lines > 0);
+ disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_5);
diff --git a/arch/powerpc/mm/40x_mmu.c b/arch/powerpc/mm/40x_mmu.c
index 5810967511d4..31a5d42df8c9 100644
--- a/arch/powerpc/mm/40x_mmu.c
+++ b/arch/powerpc/mm/40x_mmu.c
@@ -110,10 +110,10 @@ unsigned long __init mmu_mapin_ram(unsigned long top)
unsigned long val = p | _PMD_SIZE_16M | _PAGE_EXEC | _PAGE_HWWRITE;
pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v);
- pmd_val(*pmdp++) = val;
- pmd_val(*pmdp++) = val;
- pmd_val(*pmdp++) = val;
- pmd_val(*pmdp++) = val;
+ *pmdp++ = __pmd(val);
+ *pmdp++ = __pmd(val);
+ *pmdp++ = __pmd(val);
+ *pmdp++ = __pmd(val);
v += LARGE_PAGE_SIZE_16M;
p += LARGE_PAGE_SIZE_16M;
@@ -125,7 +125,7 @@ unsigned long __init mmu_mapin_ram(unsigned long top)
unsigned long val = p | _PMD_SIZE_4M | _PAGE_EXEC | _PAGE_HWWRITE;
pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v);
- pmd_val(*pmdp) = val;
+ *pmdp = __pmd(val);
v += LARGE_PAGE_SIZE_4M;
p += LARGE_PAGE_SIZE_4M;
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 3eb73a38220d..1ffeda85c086 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -14,10 +14,13 @@ obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \
obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(CONFIG_WORD_SIZE)e.o
hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC_STD_MMU_64) += hash_utils_64.o slb_low.o slb.o $(hash64-y)
-obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
-obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
- tlb_hash$(CONFIG_WORD_SIZE).o \
+obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o
+obj-$(CONFIG_PPC_STD_MMU) += tlb_hash$(CONFIG_WORD_SIZE).o \
mmu_context_hash$(CONFIG_WORD_SIZE).o
+ifeq ($(CONFIG_PPC_STD_MMU_64),y)
+obj-$(CONFIG_PPC_4K_PAGES) += hash64_4k.o
+obj-$(CONFIG_PPC_64K_PAGES) += hash64_64k.o
+endif
obj-$(CONFIG_PPC_ICSWX) += icswx.o
obj-$(CONFIG_PPC_ICSWX_PID) += icswx_pid.o
obj-$(CONFIG_40x) += 40x_mmu.o
diff --git a/arch/powerpc/mm/hash64_4k.c b/arch/powerpc/mm/hash64_4k.c
new file mode 100644
index 000000000000..e7c04542ba62
--- /dev/null
+++ b/arch/powerpc/mm/hash64_4k.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright IBM Corporation, 2015
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/mm.h>
+#include <asm/machdep.h>
+#include <asm/mmu.h>
+
+int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
+ pte_t *ptep, unsigned long trap, unsigned long flags,
+ int ssize, int subpg_prot)
+{
+ unsigned long hpte_group;
+ unsigned long rflags, pa;
+ unsigned long old_pte, new_pte;
+ unsigned long vpn, hash, slot;
+ unsigned long shift = mmu_psize_defs[MMU_PAGE_4K].shift;
+
+ /*
+ * atomically mark the linux large page PTE busy and dirty
+ */
+ do {
+ pte_t pte = READ_ONCE(*ptep);
+
+ old_pte = pte_val(pte);
+ /* If PTE busy, retry the access */
+ if (unlikely(old_pte & _PAGE_BUSY))
+ return 0;
+ /* If PTE permissions don't match, take page fault */
+ if (unlikely(access & ~old_pte))
+ return 1;
+ /*
+ * Try to lock the PTE, add ACCESSED and DIRTY if it was
+ * a write access. Since this is 4K insert of 64K page size
+ * also add _PAGE_COMBO
+ */
+ new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE;
+ if (access & _PAGE_RW)
+ new_pte |= _PAGE_DIRTY;
+ } while (old_pte != __cmpxchg_u64((unsigned long *)ptep,
+ old_pte, new_pte));
+ /*
+ * PP bits. _PAGE_USER is already PP bit 0x2, so we only
+ * need to add in 0x1 if it's a read-only user page
+ */
+ rflags = htab_convert_pte_flags(new_pte);
+
+ if (!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
+ !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
+ rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
+
+ vpn = hpt_vpn(ea, vsid, ssize);
+ if (unlikely(old_pte & _PAGE_HASHPTE)) {
+ /*
+ * There MIGHT be an HPTE for this pte
+ */
+ hash = hpt_hash(vpn, shift, ssize);
+ if (old_pte & _PAGE_F_SECOND)
+ hash = ~hash;
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += (old_pte & _PAGE_F_GIX) >> _PAGE_F_GIX_SHIFT;
+
+ if (ppc_md.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_4K,
+ MMU_PAGE_4K, ssize, flags) == -1)
+ old_pte &= ~_PAGE_HPTEFLAGS;
+ }
+
+ if (likely(!(old_pte & _PAGE_HASHPTE))) {
+
+ pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
+ hash = hpt_hash(vpn, shift, ssize);
+
+repeat:
+ hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+
+ /* Insert into the hash table, primary slot */
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
+ MMU_PAGE_4K, MMU_PAGE_4K, ssize);
+ /*
+ * Primary is full, try the secondary
+ */
+ if (unlikely(slot == -1)) {
+ hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa,
+ rflags, HPTE_V_SECONDARY,
+ MMU_PAGE_4K, MMU_PAGE_4K, ssize);
+ if (slot == -1) {
+ if (mftb() & 0x1)
+ hpte_group = ((hash & htab_hash_mask) *
+ HPTES_PER_GROUP) & ~0x7UL;
+ ppc_md.hpte_remove(hpte_group);
+ /*
+ * FIXME!! Should be try the group from which we removed ?
+ */
+ goto repeat;
+ }
+ }
+ /*
+ * Hypervisor failure. Restore old pmd and return -1
+ * similar to __hash_page_*
+ */
+ if (unlikely(slot == -2)) {
+ *ptep = __pte(old_pte);
+ hash_failure_debug(ea, access, vsid, trap, ssize,
+ MMU_PAGE_4K, MMU_PAGE_4K, old_pte);
+ return -1;
+ }
+ new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE;
+ new_pte |= (slot << _PAGE_F_GIX_SHIFT) & (_PAGE_F_SECOND | _PAGE_F_GIX);
+ }
+ *ptep = __pte(new_pte & ~_PAGE_BUSY);
+ return 0;
+}
diff --git a/arch/powerpc/mm/hash64_64k.c b/arch/powerpc/mm/hash64_64k.c
new file mode 100644
index 000000000000..0762c1e08c88
--- /dev/null
+++ b/arch/powerpc/mm/hash64_64k.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright IBM Corporation, 2015
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/mm.h>
+#include <asm/machdep.h>
+#include <asm/mmu.h>
+/*
+ * index from 0 - 15
+ */
+bool __rpte_sub_valid(real_pte_t rpte, unsigned long index)
+{
+ unsigned long g_idx;
+ unsigned long ptev = pte_val(rpte.pte);
+
+ g_idx = (ptev & _PAGE_COMBO_VALID) >> _PAGE_F_GIX_SHIFT;
+ index = index >> 2;
+ if (g_idx & (0x1 << index))
+ return true;
+ else
+ return false;
+}
+/*
+ * index from 0 - 15
+ */
+static unsigned long mark_subptegroup_valid(unsigned long ptev, unsigned long index)
+{
+ unsigned long g_idx;
+
+ if (!(ptev & _PAGE_COMBO))
+ return ptev;
+ index = index >> 2;
+ g_idx = 0x1 << index;
+
+ return ptev | (g_idx << _PAGE_F_GIX_SHIFT);
+}
+
+int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
+ pte_t *ptep, unsigned long trap, unsigned long flags,
+ int ssize, int subpg_prot)
+{
+ real_pte_t rpte;
+ unsigned long *hidxp;
+ unsigned long hpte_group;
+ unsigned int subpg_index;
+ unsigned long rflags, pa, hidx;
+ unsigned long old_pte, new_pte, subpg_pte;
+ unsigned long vpn, hash, slot;
+ unsigned long shift = mmu_psize_defs[MMU_PAGE_4K].shift;
+
+ /*
+ * atomically mark the linux large page PTE busy and dirty
+ */
+ do {
+ pte_t pte = READ_ONCE(*ptep);
+
+ old_pte = pte_val(pte);
+ /* If PTE busy, retry the access */
+ if (unlikely(old_pte & _PAGE_BUSY))
+ return 0;
+ /* If PTE permissions don't match, take page fault */
+ if (unlikely(access & ~old_pte))
+ return 1;
+ /*
+ * Try to lock the PTE, add ACCESSED and DIRTY if it was
+ * a write access. Since this is 4K insert of 64K page size
+ * also add _PAGE_COMBO
+ */
+ new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED | _PAGE_COMBO;
+ if (access & _PAGE_RW)
+ new_pte |= _PAGE_DIRTY;
+ } while (old_pte != __cmpxchg_u64((unsigned long *)ptep,
+ old_pte, new_pte));
+ /*
+ * Handle the subpage protection bits
+ */
+ subpg_pte = new_pte & ~subpg_prot;
+ rflags = htab_convert_pte_flags(subpg_pte);
+
+ if (!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
+ !cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
+
+ /*
+ * No CPU has hugepages but lacks no execute, so we
+ * don't need to worry about that case
+ */
+ rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
+ }
+
+ subpg_index = (ea & (PAGE_SIZE - 1)) >> shift;
+ vpn = hpt_vpn(ea, vsid, ssize);
+ rpte = __real_pte(__pte(old_pte), ptep);
+ /*
+ *None of the sub 4k page is hashed
+ */
+ if (!(old_pte & _PAGE_HASHPTE))
+ goto htab_insert_hpte;
+ /*
+ * Check if the pte was already inserted into the hash table
+ * as a 64k HW page, and invalidate the 64k HPTE if so.
+ */
+ if (!(old_pte & _PAGE_COMBO)) {
+ flush_hash_page(vpn, rpte, MMU_PAGE_64K, ssize, flags);
+ old_pte &= ~_PAGE_HASHPTE | _PAGE_F_GIX | _PAGE_F_SECOND;
+ goto htab_insert_hpte;
+ }
+ /*
+ * Check for sub page valid and update
+ */
+ if (__rpte_sub_valid(rpte, subpg_index)) {
+ int ret;
+
+ hash = hpt_hash(vpn, shift, ssize);
+ hidx = __rpte_to_hidx(rpte, subpg_index);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+
+ ret = ppc_md.hpte_updatepp(slot, rflags, vpn,
+ MMU_PAGE_4K, MMU_PAGE_4K,
+ ssize, flags);
+ /*
+ *if we failed because typically the HPTE wasn't really here
+ * we try an insertion.
+ */
+ if (ret == -1)
+ goto htab_insert_hpte;
+
+ *ptep = __pte(new_pte & ~_PAGE_BUSY);
+ return 0;
+ }
+
+htab_insert_hpte:
+ /*
+ * handle _PAGE_4K_PFN case
+ */
+ if (old_pte & _PAGE_4K_PFN) {
+ /*
+ * All the sub 4k page have the same
+ * physical address.
+ */
+ pa = pte_pfn(__pte(old_pte)) << HW_PAGE_SHIFT;
+ } else {
+ pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
+ pa += (subpg_index << shift);
+ }
+ hash = hpt_hash(vpn, shift, ssize);
+repeat:
+ hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+
+ /* Insert into the hash table, primary slot */
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
+ MMU_PAGE_4K, MMU_PAGE_4K, ssize);
+ /*
+ * Primary is full, try the secondary
+ */
+ if (unlikely(slot == -1)) {
+ hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa,
+ rflags, HPTE_V_SECONDARY,
+ MMU_PAGE_4K, MMU_PAGE_4K, ssize);
+ if (slot == -1) {
+ if (mftb() & 0x1)
+ hpte_group = ((hash & htab_hash_mask) *
+ HPTES_PER_GROUP) & ~0x7UL;
+ ppc_md.hpte_remove(hpte_group);
+ /*
+ * FIXME!! Should be try the group from which we removed ?
+ */
+ goto repeat;
+ }
+ }
+ /*
+ * Hypervisor failure. Restore old pmd and return -1
+ * similar to __hash_page_*
+ */
+ if (unlikely(slot == -2)) {
+ *ptep = __pte(old_pte);
+ hash_failure_debug(ea, access, vsid, trap, ssize,
+ MMU_PAGE_4K, MMU_PAGE_4K, old_pte);
+ return -1;
+ }
+ /*
+ * Insert slot number & secondary bit in PTE second half,
+ * clear _PAGE_BUSY and set appropriate HPTE slot bit
+ * Since we have _PAGE_BUSY set on ptep, we can be sure
+ * nobody is undating hidx.
+ */
+ hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+ rpte.hidx &= ~(0xfUL << (subpg_index << 2));
+ *hidxp = rpte.hidx | (slot << (subpg_index << 2));
+ new_pte = mark_subptegroup_valid(new_pte, subpg_index);
+ new_pte |= _PAGE_HASHPTE;
+ /*
+ * check __real_pte for details on matching smp_rmb()
+ */
+ smp_wmb();
+ *ptep = __pte(new_pte & ~_PAGE_BUSY);
+ return 0;
+}
+
+int __hash_page_64K(unsigned long ea, unsigned long access,
+ unsigned long vsid, pte_t *ptep, unsigned long trap,
+ unsigned long flags, int ssize)
+{
+
+ unsigned long hpte_group;
+ unsigned long rflags, pa;
+ unsigned long old_pte, new_pte;
+ unsigned long vpn, hash, slot;
+ unsigned long shift = mmu_psize_defs[MMU_PAGE_64K].shift;
+
+ /*
+ * atomically mark the linux large page PTE busy and dirty
+ */
+ do {
+ pte_t pte = READ_ONCE(*ptep);
+
+ old_pte = pte_val(pte);
+ /* If PTE busy, retry the access */
+ if (unlikely(old_pte & _PAGE_BUSY))
+ return 0;
+ /* If PTE permissions don't match, take page fault */
+ if (unlikely(access & ~old_pte))
+ return 1;
+ /*
+ * Check if PTE has the cache-inhibit bit set
+ * If so, bail out and refault as a 4k page
+ */
+ if (!mmu_has_feature(MMU_FTR_CI_LARGE_PAGE) &&
+ unlikely(old_pte & _PAGE_NO_CACHE))
+ return 0;
+ /*
+ * Try to lock the PTE, add ACCESSED and DIRTY if it was
+ * a write access. Since this is 4K insert of 64K page size
+ * also add _PAGE_COMBO
+ */
+ new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED;
+ if (access & _PAGE_RW)
+ new_pte |= _PAGE_DIRTY;
+ } while (old_pte != __cmpxchg_u64((unsigned long *)ptep,
+ old_pte, new_pte));
+
+ rflags = htab_convert_pte_flags(new_pte);
+
+ if (!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
+ !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
+ rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
+
+ vpn = hpt_vpn(ea, vsid, ssize);
+ if (unlikely(old_pte & _PAGE_HASHPTE)) {
+ /*
+ * There MIGHT be an HPTE for this pte
+ */
+ hash = hpt_hash(vpn, shift, ssize);
+ if (old_pte & _PAGE_F_SECOND)
+ hash = ~hash;
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += (old_pte & _PAGE_F_GIX) >> _PAGE_F_GIX_SHIFT;
+
+ if (ppc_md.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_64K,
+ MMU_PAGE_64K, ssize, flags) == -1)
+ old_pte &= ~_PAGE_HPTEFLAGS;
+ }
+
+ if (likely(!(old_pte & _PAGE_HASHPTE))) {
+
+ pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
+ hash = hpt_hash(vpn, shift, ssize);
+
+repeat:
+ hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+
+ /* Insert into the hash table, primary slot */
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
+ MMU_PAGE_64K, MMU_PAGE_64K, ssize);
+ /*
+ * Primary is full, try the secondary
+ */
+ if (unlikely(slot == -1)) {
+ hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa,
+ rflags, HPTE_V_SECONDARY,
+ MMU_PAGE_64K, MMU_PAGE_64K, ssize);
+ if (slot == -1) {
+ if (mftb() & 0x1)
+ hpte_group = ((hash & htab_hash_mask) *
+ HPTES_PER_GROUP) & ~0x7UL;
+ ppc_md.hpte_remove(hpte_group);
+ /*
+ * FIXME!! Should be try the group from which we removed ?
+ */
+ goto repeat;
+ }
+ }
+ /*
+ * Hypervisor failure. Restore old pmd and return -1
+ * similar to __hash_page_*
+ */
+ if (unlikely(slot == -2)) {
+ *ptep = __pte(old_pte);
+ hash_failure_debug(ea, access, vsid, trap, ssize,
+ MMU_PAGE_64K, MMU_PAGE_64K, old_pte);
+ return -1;
+ }
+ new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE;
+ new_pte |= (slot << _PAGE_F_GIX_SHIFT) & (_PAGE_F_SECOND | _PAGE_F_GIX);
+ }
+ *ptep = __pte(new_pte & ~_PAGE_BUSY);
+ return 0;
+}
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
deleted file mode 100644
index 3b49e3295901..000000000000
--- a/arch/powerpc/mm/hash_low_64.S
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * ppc64 MMU hashtable management routines
- *
- * (c) Copyright IBM Corp. 2003, 2005
- *
- * Maintained by: Benjamin Herrenschmidt
- * <benh@kernel.crashing.org>
- *
- * This file is covered by the GNU Public Licence v2 as
- * described in the kernel's COPYING file.
- */
-
-#include <asm/reg.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/page.h>
-#include <asm/types.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/cputable.h>
-
- .text
-
-/*
- * Stackframe:
- *
- * +-> Back chain (SP + 256)
- * | General register save area (SP + 112)
- * | Parameter save area (SP + 48)
- * | TOC save area (SP + 40)
- * | link editor doubleword (SP + 32)
- * | compiler doubleword (SP + 24)
- * | LR save area (SP + 16)
- * | CR save area (SP + 8)
- * SP ---> +-- Back chain (SP + 0)
- */
-
-#ifndef CONFIG_PPC_64K_PAGES
-
-/*****************************************************************************
- * *
- * 4K SW & 4K HW pages implementation *
- * *
- *****************************************************************************/
-
-
-/*
- * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
- * pte_t *ptep, unsigned long trap, unsigned long flags,
- * int ssize)
- *
- * Adds a 4K page to the hash table in a segment of 4K pages only
- */
-
-_GLOBAL(__hash_page_4K)
- mflr r0
- std r0,16(r1)
- stdu r1,-STACKFRAMESIZE(r1)
- /* Save all params that we need after a function call */
- std r6,STK_PARAM(R6)(r1)
- std r8,STK_PARAM(R8)(r1)
- std r9,STK_PARAM(R9)(r1)
-
- /* Save non-volatile registers.
- * r31 will hold "old PTE"
- * r30 is "new PTE"
- * r29 is vpn
- * r28 is a hash value
- * r27 is hashtab mask (maybe dynamic patched instead ?)
- */
- std r27,STK_REG(R27)(r1)
- std r28,STK_REG(R28)(r1)
- std r29,STK_REG(R29)(r1)
- std r30,STK_REG(R30)(r1)
- std r31,STK_REG(R31)(r1)
-
- /* Step 1:
- *
- * Check permissions, atomically mark the linux PTE busy
- * and hashed.
- */
-1:
- ldarx r31,0,r6
- /* Check access rights (access & ~(pte_val(*ptep))) */
- andc. r0,r4,r31
- bne- htab_wrong_access
- /* Check if PTE is busy */
- andi. r0,r31,_PAGE_BUSY
- /* If so, just bail out and refault if needed. Someone else
- * is changing this PTE anyway and might hash it.
- */
- bne- htab_bail_ok
-
- /* Prepare new PTE value (turn access RW into DIRTY, then
- * add BUSY,HASHPTE and ACCESSED)
- */
- rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
- or r30,r30,r31
- ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
- /* Write the linux PTE atomically (setting busy) */
- stdcx. r30,0,r6
- bne- 1b
- isync
-
- /* Step 2:
- *
- * Insert/Update the HPTE in the hash table. At this point,
- * r4 (access) is re-useable, we use it for the new HPTE flags
- */
-
-BEGIN_FTR_SECTION
- cmpdi r9,0 /* check segment size */
- bne 3f
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
- /* Calc vpn and put it in r29 */
- sldi r29,r5,SID_SHIFT - VPN_SHIFT
- rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
- or r29,r28,r29
- /*
- * Calculate hash value for primary slot and store it in r28
- * r3 = va, r5 = vsid
- * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
- */
- rldicl r0,r3,64-12,48
- xor r28,r5,r0 /* hash */
- b 4f
-
-3: /* Calc vpn and put it in r29 */
- sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT
- rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
- or r29,r28,r29
-
- /*
- * calculate hash value for primary slot and
- * store it in r28 for 1T segment
- * r3 = va, r5 = vsid
- */
- sldi r28,r5,25 /* vsid << 25 */
- /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
- rldicl r0,r3,64-12,36
- xor r28,r28,r5 /* vsid ^ ( vsid << 25) */
- xor r28,r28,r0 /* hash */
-
- /* Convert linux PTE bits into HW equivalents */
-4: andi. r3,r30,0x1fe /* Get basic set of flags */
- xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
- rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
- rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
- and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
- andc r0,r30,r0 /* r0 = pte & ~r0 */
- rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
- /*
- * Always add "C" bit for perf. Memory coherence is always enabled
- */
- ori r3,r3,HPTE_R_C | HPTE_R_M
-
- /* We eventually do the icache sync here (maybe inline that
- * code rather than call a C function...)
- */
-BEGIN_FTR_SECTION
- mr r4,r30
- mr r5,r7
- bl hash_page_do_lazy_icache
-END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
-
- /* At this point, r3 contains new PP bits, save them in
- * place of "access" in the param area (sic)
- */
- std r3,STK_PARAM(R4)(r1)
-
- /* Get htab_hash_mask */
- ld r4,htab_hash_mask@got(2)
- ld r27,0(r4) /* htab_hash_mask -> r27 */
-
- /* Check if we may already be in the hashtable, in this case, we
- * go to out-of-line code to try to modify the HPTE
- */
- andi. r0,r31,_PAGE_HASHPTE
- bne htab_modify_pte
-
-htab_insert_pte:
- /* Clear hpte bits in new pte (we also clear BUSY btw) and
- * add _PAGE_HASHPTE
- */
- lis r0,_PAGE_HPTEFLAGS@h
- ori r0,r0,_PAGE_HPTEFLAGS@l
- andc r30,r30,r0
- ori r30,r30,_PAGE_HASHPTE
-
- /* physical address r5 */
- rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
- sldi r5,r5,PAGE_SHIFT
-
- /* Calculate primary group hash */
- and r0,r28,r27
- rldicr r3,r0,3,63-3 /* r3 = (hash & mask) << 3 */
-
- /* Call ppc_md.hpte_insert */
- ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */
- mr r4,r29 /* Retrieve vpn */
- li r7,0 /* !bolted, !secondary */
- li r8,MMU_PAGE_4K /* page size */
- li r9,MMU_PAGE_4K /* actual page size */
- ld r10,STK_PARAM(R9)(r1) /* segment size */
-.globl htab_call_hpte_insert1
-htab_call_hpte_insert1:
- bl . /* Patched by htab_finish_init() */
- cmpdi 0,r3,0
- bge htab_pte_insert_ok /* Insertion successful */
- cmpdi 0,r3,-2 /* Critical failure */
- beq- htab_pte_insert_failure
-
- /* Now try secondary slot */
-
- /* physical address r5 */
- rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
- sldi r5,r5,PAGE_SHIFT
-
- /* Calculate secondary group hash */
- andc r0,r27,r28
- rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */
-
- /* Call ppc_md.hpte_insert */
- ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */
- mr r4,r29 /* Retrieve vpn */
- li r7,HPTE_V_SECONDARY /* !bolted, secondary */
- li r8,MMU_PAGE_4K /* page size */
- li r9,MMU_PAGE_4K /* actual page size */
- ld r10,STK_PARAM(R9)(r1) /* segment size */
-.globl htab_call_hpte_insert2
-htab_call_hpte_insert2:
- bl . /* Patched by htab_finish_init() */
- cmpdi 0,r3,0
- bge+ htab_pte_insert_ok /* Insertion successful */
- cmpdi 0,r3,-2 /* Critical failure */
- beq- htab_pte_insert_failure
-
- /* Both are full, we need to evict something */
- mftb r0
- /* Pick a random group based on TB */
- andi. r0,r0,1
- mr r5,r28
- bne 2f
- not r5,r5
-2: and r0,r5,r27
- rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
- /* Call ppc_md.hpte_remove */
-.globl htab_call_hpte_remove
-htab_call_hpte_remove:
- bl . /* Patched by htab_finish_init() */
-
- /* Try all again */
- b htab_insert_pte
-
-htab_bail_ok:
- li r3,0
- b htab_bail
-
-htab_pte_insert_ok:
- /* Insert slot number & secondary bit in PTE */
- rldimi r30,r3,12,63-15
-
- /* Write out the PTE with a normal write
- * (maybe add eieio may be good still ?)
- */
-htab_write_out_pte:
- ld r6,STK_PARAM(R6)(r1)
- std r30,0(r6)
- li r3, 0
-htab_bail:
- ld r27,STK_REG(R27)(r1)
- ld r28,STK_REG(R28)(r1)
- ld r29,STK_REG(R29)(r1)
- ld r30,STK_REG(R30)(r1)
- ld r31,STK_REG(R31)(r1)
- addi r1,r1,STACKFRAMESIZE
- ld r0,16(r1)
- mtlr r0
- blr
-
-htab_modify_pte:
- /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
- mr r4,r3
- rlwinm r3,r31,32-12,29,31
-
- /* Secondary group ? if yes, get a inverted hash value */
- mr r5,r28
- andi. r0,r31,_PAGE_SECONDARY
- beq 1f
- not r5,r5
-1:
- /* Calculate proper slot value for ppc_md.hpte_updatepp */
- and r0,r5,r27
- rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */
- add r3,r0,r3 /* add slot idx */
-
- /* Call ppc_md.hpte_updatepp */
- mr r5,r29 /* vpn */
- li r6,MMU_PAGE_4K /* base page size */
- li r7,MMU_PAGE_4K /* actual page size */
- ld r8,STK_PARAM(R9)(r1) /* segment size */
- ld r9,STK_PARAM(R8)(r1) /* get "flags" param */
-.globl htab_call_hpte_updatepp
-htab_call_hpte_updatepp:
- bl . /* Patched by htab_finish_init() */
-
- /* if we failed because typically the HPTE wasn't really here
- * we try an insertion.
- */
- cmpdi 0,r3,-1
- beq- htab_insert_pte
-
- /* Clear the BUSY bit and Write out the PTE */
- li r0,_PAGE_BUSY
- andc r30,r30,r0
- b htab_write_out_pte
-
-htab_wrong_access:
- /* Bail out clearing reservation */
- stdcx. r31,0,r6
- li r3,1
- b htab_bail
-
-htab_pte_insert_failure:
- /* Bail out restoring old PTE */
- ld r6,STK_PARAM(R6)(r1)
- std r31,0(r6)
- li r3,-1
- b htab_bail
-
-
-#else /* CONFIG_PPC_64K_PAGES */
-
-
-/*****************************************************************************
- * *
- * 64K SW & 4K or 64K HW in a 4K segment pages implementation *
- * *
- *****************************************************************************/
-
-/* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
- * pte_t *ptep, unsigned long trap, unsigned local flags,
- * int ssize, int subpg_prot)
- */
-
-/*
- * For now, we do NOT implement Admixed pages
- */
-_GLOBAL(__hash_page_4K)
- mflr r0
- std r0,16(r1)
- stdu r1,-STACKFRAMESIZE(r1)
- /* Save all params that we need after a function call */
- std r6,STK_PARAM(R6)(r1)
- std r8,STK_PARAM(R8)(r1)
- std r9,STK_PARAM(R9)(r1)
-
- /* Save non-volatile registers.
- * r31 will hold "old PTE"
- * r30 is "new PTE"
- * r29 is vpn
- * r28 is a hash value
- * r27 is hashtab mask (maybe dynamic patched instead ?)
- * r26 is the hidx mask
- * r25 is the index in combo page
- */
- std r25,STK_REG(R25)(r1)
- std r26,STK_REG(R26)(r1)
- std r27,STK_REG(R27)(r1)
- std r28,STK_REG(R28)(r1)
- std r29,STK_REG(R29)(r1)
- std r30,STK_REG(R30)(r1)
- std r31,STK_REG(R31)(r1)
-
- /* Step 1:
- *
- * Check permissions, atomically mark the linux PTE busy
- * and hashed.
- */
-1:
- ldarx r31,0,r6
- /* Check access rights (access & ~(pte_val(*ptep))) */
- andc. r0,r4,r31
- bne- htab_wrong_access
- /* Check if PTE is busy */
- andi. r0,r31,_PAGE_BUSY
- /* If so, just bail out and refault if needed. Someone else
- * is changing this PTE anyway and might hash it.
- */
- bne- htab_bail_ok
- /* Prepare new PTE value (turn access RW into DIRTY, then
- * add BUSY and ACCESSED)
- */
- rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
- or r30,r30,r31
- ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
- oris r30,r30,_PAGE_COMBO@h
- /* Write the linux PTE atomically (setting busy) */
- stdcx. r30,0,r6
- bne- 1b
- isync
-
- /* Step 2:
- *
- * Insert/Update the HPTE in the hash table. At this point,
- * r4 (access) is re-useable, we use it for the new HPTE flags
- */
-
- /* Load the hidx index */
- rldicl r25,r3,64-12,60
-
-BEGIN_FTR_SECTION
- cmpdi r9,0 /* check segment size */
- bne 3f
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
- /* Calc vpn and put it in r29 */
- sldi r29,r5,SID_SHIFT - VPN_SHIFT
- /*
- * clrldi r3,r3,64 - SID_SHIFT --> ea & 0xfffffff
- * srdi r28,r3,VPN_SHIFT
- */
- rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
- or r29,r28,r29
- /*
- * Calculate hash value for primary slot and store it in r28
- * r3 = va, r5 = vsid
- * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
- */
- rldicl r0,r3,64-12,48
- xor r28,r5,r0 /* hash */
- b 4f
-
-3: /* Calc vpn and put it in r29 */
- sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT
- /*
- * clrldi r3,r3,64 - SID_SHIFT_1T --> ea & 0xffffffffff
- * srdi r28,r3,VPN_SHIFT
- */
- rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
- or r29,r28,r29
-
- /*
- * Calculate hash value for primary slot and
- * store it in r28 for 1T segment
- * r3 = va, r5 = vsid
- */
- sldi r28,r5,25 /* vsid << 25 */
- /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
- rldicl r0,r3,64-12,36
- xor r28,r28,r5 /* vsid ^ ( vsid << 25) */
- xor r28,r28,r0 /* hash */
-
- /* Convert linux PTE bits into HW equivalents */
-4:
-#ifdef CONFIG_PPC_SUBPAGE_PROT
- andc r10,r30,r10
- andi. r3,r10,0x1fe /* Get basic set of flags */
- rlwinm r0,r10,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
-#else
- andi. r3,r30,0x1fe /* Get basic set of flags */
- rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
-#endif
- xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
- rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
- and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
- andc r0,r3,r0 /* r0 = pte & ~r0 */
- rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
- /*
- * Always add "C" bit for perf. Memory coherence is always enabled
- */
- ori r3,r3,HPTE_R_C | HPTE_R_M
-
- /* We eventually do the icache sync here (maybe inline that
- * code rather than call a C function...)
- */
-BEGIN_FTR_SECTION
- mr r4,r30
- mr r5,r7
- bl hash_page_do_lazy_icache
-END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
-
- /* At this point, r3 contains new PP bits, save them in
- * place of "access" in the param area (sic)
- */
- std r3,STK_PARAM(R4)(r1)
-
- /* Get htab_hash_mask */
- ld r4,htab_hash_mask@got(2)
- ld r27,0(r4) /* htab_hash_mask -> r27 */
-
- /* Check if we may already be in the hashtable, in this case, we
- * go to out-of-line code to try to modify the HPTE. We look for
- * the bit at (1 >> (index + 32))
- */
- rldicl. r0,r31,64-12,48
- li r26,0 /* Default hidx */
- beq htab_insert_pte
-
- /*
- * Check if the pte was already inserted into the hash table
- * as a 64k HW page, and invalidate the 64k HPTE if so.
- */
- andis. r0,r31,_PAGE_COMBO@h
- beq htab_inval_old_hpte
-
- ld r6,STK_PARAM(R6)(r1)
- ori r26,r6,PTE_PAGE_HIDX_OFFSET /* Load the hidx mask. */
- ld r26,0(r26)
- addi r5,r25,36 /* Check actual HPTE_SUB bit, this */
- rldcr. r0,r31,r5,0 /* must match pgtable.h definition */
- bne htab_modify_pte
-
-htab_insert_pte:
- /* real page number in r5, PTE RPN value + index */
- andis. r0,r31,_PAGE_4K_PFN@h
- srdi r5,r31,PTE_RPN_SHIFT
- bne- htab_special_pfn
- sldi r5,r5,PAGE_FACTOR
- add r5,r5,r25
-htab_special_pfn:
- sldi r5,r5,HW_PAGE_SHIFT
-
- /* Calculate primary group hash */
- and r0,r28,r27
- rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
-
- /* Call ppc_md.hpte_insert */
- ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */
- mr r4,r29 /* Retrieve vpn */
- li r7,0 /* !bolted, !secondary */
- li r8,MMU_PAGE_4K /* page size */
- li r9,MMU_PAGE_4K /* actual page size */
- ld r10,STK_PARAM(R9)(r1) /* segment size */
-.globl htab_call_hpte_insert1
-htab_call_hpte_insert1:
- bl . /* patched by htab_finish_init() */
- cmpdi 0,r3,0
- bge htab_pte_insert_ok /* Insertion successful */
- cmpdi 0,r3,-2 /* Critical failure */
- beq- htab_pte_insert_failure
-
- /* Now try secondary slot */
-
- /* real page number in r5, PTE RPN value + index */
- andis. r0,r31,_PAGE_4K_PFN@h
- srdi r5,r31,PTE_RPN_SHIFT
- bne- 3f
- sldi r5,r5,PAGE_FACTOR
- add r5,r5,r25
-3: sldi r5,r5,HW_PAGE_SHIFT
-
- /* Calculate secondary group hash */
- andc r0,r27,r28
- rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */
-
- /* Call ppc_md.hpte_insert */
- ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */
- mr r4,r29 /* Retrieve vpn */
- li r7,HPTE_V_SECONDARY /* !bolted, secondary */
- li r8,MMU_PAGE_4K /* page size */
- li r9,MMU_PAGE_4K /* actual page size */
- ld r10,STK_PARAM(R9)(r1) /* segment size */
-.globl htab_call_hpte_insert2
-htab_call_hpte_insert2:
- bl . /* patched by htab_finish_init() */
- cmpdi 0,r3,0
- bge+ htab_pte_insert_ok /* Insertion successful */
- cmpdi 0,r3,-2 /* Critical failure */
- beq- htab_pte_insert_failure
-
- /* Both are full, we need to evict something */
- mftb r0
- /* Pick a random group based on TB */
- andi. r0,r0,1
- mr r5,r28
- bne 2f
- not r5,r5
-2: and r0,r5,r27
- rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
- /* Call ppc_md.hpte_remove */
-.globl htab_call_hpte_remove
-htab_call_hpte_remove:
- bl . /* patched by htab_finish_init() */
-
- /* Try all again */
- b htab_insert_pte
-
- /*
- * Call out to C code to invalidate an 64k HW HPTE that is
- * useless now that the segment has been switched to 4k pages.
- */
-htab_inval_old_hpte:
- mr r3,r29 /* vpn */
- mr r4,r31 /* PTE.pte */
- li r5,0 /* PTE.hidx */
- li r6,MMU_PAGE_64K /* psize */
- ld r7,STK_PARAM(R9)(r1) /* ssize */
- ld r8,STK_PARAM(R8)(r1) /* flags */
- bl flush_hash_page
- /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */
- lis r0,_PAGE_HPTE_SUB@h
- ori r0,r0,_PAGE_HPTE_SUB@l
- andc r30,r30,r0
- b htab_insert_pte
-
-htab_bail_ok:
- li r3,0
- b htab_bail
-
-htab_pte_insert_ok:
- /* Insert slot number & secondary bit in PTE second half,
- * clear _PAGE_BUSY and set approriate HPTE slot bit
- */
- ld r6,STK_PARAM(R6)(r1)
- li r0,_PAGE_BUSY
- andc r30,r30,r0
- /* HPTE SUB bit */
- li r0,1
- subfic r5,r25,27 /* Must match bit position in */
- sld r0,r0,r5 /* pgtable.h */
- or r30,r30,r0
- /* hindx */
- sldi r5,r25,2
- sld r3,r3,r5
- li r4,0xf
- sld r4,r4,r5
- andc r26,r26,r4
- or r26,r26,r3
- ori r5,r6,PTE_PAGE_HIDX_OFFSET
- std r26,0(r5)
- lwsync
- std r30,0(r6)
- li r3, 0
-htab_bail:
- ld r25,STK_REG(R25)(r1)
- ld r26,STK_REG(R26)(r1)
- ld r27,STK_REG(R27)(r1)
- ld r28,STK_REG(R28)(r1)
- ld r29,STK_REG(R29)(r1)
- ld r30,STK_REG(R30)(r1)
- ld r31,STK_REG(R31)(r1)
- addi r1,r1,STACKFRAMESIZE
- ld r0,16(r1)
- mtlr r0
- blr
-
-htab_modify_pte:
- /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
- mr r4,r3
- sldi r5,r25,2
- srd r3,r26,r5
-
- /* Secondary group ? if yes, get a inverted hash value */
- mr r5,r28
- andi. r0,r3,0x8 /* page secondary ? */
- beq 1f
- not r5,r5
-1: andi. r3,r3,0x7 /* extract idx alone */
-
- /* Calculate proper slot value for ppc_md.hpte_updatepp */
- and r0,r5,r27
- rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */
- add r3,r0,r3 /* add slot idx */
-
- /* Call ppc_md.hpte_updatepp */
- mr r5,r29 /* vpn */
- li r6,MMU_PAGE_4K /* base page size */
- li r7,MMU_PAGE_4K /* actual page size */
- ld r8,STK_PARAM(R9)(r1) /* segment size */
- ld r9,STK_PARAM(R8)(r1) /* get "flags" param */
-.globl htab_call_hpte_updatepp
-htab_call_hpte_updatepp:
- bl . /* patched by htab_finish_init() */
-
- /* if we failed because typically the HPTE wasn't really here
- * we try an insertion.
- */
- cmpdi 0,r3,-1
- beq- htab_insert_pte
-
- /* Clear the BUSY bit and Write out the PTE */
- li r0,_PAGE_BUSY
- andc r30,r30,r0
- ld r6,STK_PARAM(R6)(r1)
- std r30,0(r6)
- li r3,0
- b htab_bail
-
-htab_wrong_access:
- /* Bail out clearing reservation */
- stdcx. r31,0,r6
- li r3,1
- b htab_bail
-
-htab_pte_insert_failure:
- /* Bail out restoring old PTE */
- ld r6,STK_PARAM(R6)(r1)
- std r31,0(r6)
- li r3,-1
- b htab_bail
-
-#endif /* CONFIG_PPC_64K_PAGES */
-
-#ifdef CONFIG_PPC_64K_PAGES
-
-/*****************************************************************************
- * *
- * 64K SW & 64K HW in a 64K segment pages implementation *
- * *
- *****************************************************************************/
-
-_GLOBAL(__hash_page_64K)
- mflr r0
- std r0,16(r1)
- stdu r1,-STACKFRAMESIZE(r1)
- /* Save all params that we need after a function call */
- std r6,STK_PARAM(R6)(r1)
- std r8,STK_PARAM(R8)(r1)
- std r9,STK_PARAM(R9)(r1)
-
- /* Save non-volatile registers.
- * r31 will hold "old PTE"
- * r30 is "new PTE"
- * r29 is vpn
- * r28 is a hash value
- * r27 is hashtab mask (maybe dynamic patched instead ?)
- */
- std r27,STK_REG(R27)(r1)
- std r28,STK_REG(R28)(r1)
- std r29,STK_REG(R29)(r1)
- std r30,STK_REG(R30)(r1)
- std r31,STK_REG(R31)(r1)
-
- /* Step 1:
- *
- * Check permissions, atomically mark the linux PTE busy
- * and hashed.
- */
-1:
- ldarx r31,0,r6
- /* Check access rights (access & ~(pte_val(*ptep))) */
- andc. r0,r4,r31
- bne- ht64_wrong_access
- /* Check if PTE is busy */
- andi. r0,r31,_PAGE_BUSY
- /* If so, just bail out and refault if needed. Someone else
- * is changing this PTE anyway and might hash it.
- */
- bne- ht64_bail_ok
-BEGIN_FTR_SECTION
- /* Check if PTE has the cache-inhibit bit set */
- andi. r0,r31,_PAGE_NO_CACHE
- /* If so, bail out and refault as a 4k page */
- bne- ht64_bail_ok
-END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
- /* Prepare new PTE value (turn access RW into DIRTY, then
- * add BUSY and ACCESSED)
- */
- rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
- or r30,r30,r31
- ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
- /* Write the linux PTE atomically (setting busy) */
- stdcx. r30,0,r6
- bne- 1b
- isync
-
- /* Step 2:
- *
- * Insert/Update the HPTE in the hash table. At this point,
- * r4 (access) is re-useable, we use it for the new HPTE flags
- */
-
-BEGIN_FTR_SECTION
- cmpdi r9,0 /* check segment size */
- bne 3f
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
- /* Calc vpn and put it in r29 */
- sldi r29,r5,SID_SHIFT - VPN_SHIFT
- rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
- or r29,r28,r29
-
- /* Calculate hash value for primary slot and store it in r28
- * r3 = va, r5 = vsid
- * r0 = (va >> 16) & ((1ul << (28 - 16)) -1)
- */
- rldicl r0,r3,64-16,52
- xor r28,r5,r0 /* hash */
- b 4f
-
-3: /* Calc vpn and put it in r29 */
- sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT
- rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
- or r29,r28,r29
- /*
- * calculate hash value for primary slot and
- * store it in r28 for 1T segment
- * r3 = va, r5 = vsid
- */
- sldi r28,r5,25 /* vsid << 25 */
- /* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */
- rldicl r0,r3,64-16,40
- xor r28,r28,r5 /* vsid ^ ( vsid << 25) */
- xor r28,r28,r0 /* hash */
-
- /* Convert linux PTE bits into HW equivalents */
-4: andi. r3,r30,0x1fe /* Get basic set of flags */
- xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
- rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
- rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
- and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
- andc r0,r30,r0 /* r0 = pte & ~r0 */
- rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
- /*
- * Always add "C" bit for perf. Memory coherence is always enabled
- */
- ori r3,r3,HPTE_R_C | HPTE_R_M
-
- /* We eventually do the icache sync here (maybe inline that
- * code rather than call a C function...)
- */
-BEGIN_FTR_SECTION
- mr r4,r30
- mr r5,r7
- bl hash_page_do_lazy_icache
-END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
-
- /* At this point, r3 contains new PP bits, save them in
- * place of "access" in the param area (sic)
- */
- std r3,STK_PARAM(R4)(r1)
-
- /* Get htab_hash_mask */
- ld r4,htab_hash_mask@got(2)
- ld r27,0(r4) /* htab_hash_mask -> r27 */
-
- /* Check if we may already be in the hashtable, in this case, we
- * go to out-of-line code to try to modify the HPTE
- */
- rldicl. r0,r31,64-12,48
- bne ht64_modify_pte
-
-ht64_insert_pte:
- /* Clear hpte bits in new pte (we also clear BUSY btw) and
- * add _PAGE_HPTE_SUB0
- */
- lis r0,_PAGE_HPTEFLAGS@h
- ori r0,r0,_PAGE_HPTEFLAGS@l
- andc r30,r30,r0
-#ifdef CONFIG_PPC_64K_PAGES
- oris r30,r30,_PAGE_HPTE_SUB0@h
-#else
- ori r30,r30,_PAGE_HASHPTE
-#endif
- /* Phyical address in r5 */
- rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
- sldi r5,r5,PAGE_SHIFT
-
- /* Calculate primary group hash */
- and r0,r28,r27
- rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
-
- /* Call ppc_md.hpte_insert */
- ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */
- mr r4,r29 /* Retrieve vpn */
- li r7,0 /* !bolted, !secondary */
- li r8,MMU_PAGE_64K
- li r9,MMU_PAGE_64K /* actual page size */
- ld r10,STK_PARAM(R9)(r1) /* segment size */
-.globl ht64_call_hpte_insert1
-ht64_call_hpte_insert1:
- bl . /* patched by htab_finish_init() */
- cmpdi 0,r3,0
- bge ht64_pte_insert_ok /* Insertion successful */
- cmpdi 0,r3,-2 /* Critical failure */
- beq- ht64_pte_insert_failure
-
- /* Now try secondary slot */
-
- /* Phyical address in r5 */
- rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
- sldi r5,r5,PAGE_SHIFT
-
- /* Calculate secondary group hash */
- andc r0,r27,r28
- rldicr r3,r0,3,63-3 /* r0 = (~hash & mask) << 3 */
-
- /* Call ppc_md.hpte_insert */
- ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */
- mr r4,r29 /* Retrieve vpn */
- li r7,HPTE_V_SECONDARY /* !bolted, secondary */
- li r8,MMU_PAGE_64K
- li r9,MMU_PAGE_64K /* actual page size */
- ld r10,STK_PARAM(R9)(r1) /* segment size */
-.globl ht64_call_hpte_insert2
-ht64_call_hpte_insert2:
- bl . /* patched by htab_finish_init() */
- cmpdi 0,r3,0
- bge+ ht64_pte_insert_ok /* Insertion successful */
- cmpdi 0,r3,-2 /* Critical failure */
- beq- ht64_pte_insert_failure
-
- /* Both are full, we need to evict something */
- mftb r0
- /* Pick a random group based on TB */
- andi. r0,r0,1
- mr r5,r28
- bne 2f
- not r5,r5
-2: and r0,r5,r27
- rldicr r3,r0,3,63-3 /* r0 = (hash & mask) << 3 */
- /* Call ppc_md.hpte_remove */
-.globl ht64_call_hpte_remove
-ht64_call_hpte_remove:
- bl . /* patched by htab_finish_init() */
-
- /* Try all again */
- b ht64_insert_pte
-
-ht64_bail_ok:
- li r3,0
- b ht64_bail
-
-ht64_pte_insert_ok:
- /* Insert slot number & secondary bit in PTE */
- rldimi r30,r3,12,63-15
-
- /* Write out the PTE with a normal write
- * (maybe add eieio may be good still ?)
- */
-ht64_write_out_pte:
- ld r6,STK_PARAM(R6)(r1)
- std r30,0(r6)
- li r3, 0
-ht64_bail:
- ld r27,STK_REG(R27)(r1)
- ld r28,STK_REG(R28)(r1)
- ld r29,STK_REG(R29)(r1)
- ld r30,STK_REG(R30)(r1)
- ld r31,STK_REG(R31)(r1)
- addi r1,r1,STACKFRAMESIZE
- ld r0,16(r1)
- mtlr r0
- blr
-
-ht64_modify_pte:
- /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
- mr r4,r3
- rlwinm r3,r31,32-12,29,31
-
- /* Secondary group ? if yes, get a inverted hash value */
- mr r5,r28
- andi. r0,r31,_PAGE_F_SECOND
- beq 1f
- not r5,r5
-1:
- /* Calculate proper slot value for ppc_md.hpte_updatepp */
- and r0,r5,r27
- rldicr r0,r0,3,63-3 /* r0 = (hash & mask) << 3 */
- add r3,r0,r3 /* add slot idx */
-
- /* Call ppc_md.hpte_updatepp */
- mr r5,r29 /* vpn */
- li r6,MMU_PAGE_64K /* base page size */
- li r7,MMU_PAGE_64K /* actual page size */
- ld r8,STK_PARAM(R9)(r1) /* segment size */
- ld r9,STK_PARAM(R8)(r1) /* get "flags" param */
-.globl ht64_call_hpte_updatepp
-ht64_call_hpte_updatepp:
- bl . /* patched by htab_finish_init() */
-
- /* if we failed because typically the HPTE wasn't really here
- * we try an insertion.
- */
- cmpdi 0,r3,-1
- beq- ht64_insert_pte
-
- /* Clear the BUSY bit and Write out the PTE */
- li r0,_PAGE_BUSY
- andc r30,r30,r0
- b ht64_write_out_pte
-
-ht64_wrong_access:
- /* Bail out clearing reservation */
- stdcx. r31,0,r6
- li r3,1
- b ht64_bail
-
-ht64_pte_insert_failure:
- /* Bail out restoring old PTE */
- ld r6,STK_PARAM(R6)(r1)
- std r31,0(r6)
- li r3,-1
- b ht64_bail
-
-
-#endif /* CONFIG_PPC_64K_PAGES */
-
-
-/*****************************************************************************
- * *
- * Huge pages implementation is in hugetlbpage.c *
- * *
- *****************************************************************************/
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index c8822af10a58..8eaac81347fd 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -429,6 +429,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
local_irq_restore(flags);
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static void native_hugepage_invalidate(unsigned long vsid,
unsigned long addr,
unsigned char *hpte_slot_array,
@@ -482,6 +483,15 @@ static void native_hugepage_invalidate(unsigned long vsid,
}
local_irq_restore(flags);
}
+#else
+static void native_hugepage_invalidate(unsigned long vsid,
+ unsigned long addr,
+ unsigned char *hpte_slot_array,
+ int psize, int ssize, int local)
+{
+ WARN(1, "%s called without THP support\n", __func__);
+}
+#endif
static inline int __hpte_actual_psize(unsigned int lp, int psize)
{
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 7f9616f7c479..ba59d5977f34 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -159,24 +159,41 @@ static struct mmu_psize_def mmu_psize_defaults_gp[] = {
},
};
-static unsigned long htab_convert_pte_flags(unsigned long pteflags)
+unsigned long htab_convert_pte_flags(unsigned long pteflags)
{
- unsigned long rflags = pteflags & 0x1fa;
+ unsigned long rflags = 0;
/* _PAGE_EXEC -> NOEXEC */
if ((pteflags & _PAGE_EXEC) == 0)
rflags |= HPTE_R_N;
-
- /* PP bits. PAGE_USER is already PP bit 0x2, so we only
- * need to add in 0x1 if it's a read-only user page
+ /*
+ * PP bits:
+ * Linux use slb key 0 for kernel and 1 for user.
+ * kernel areas are mapped by PP bits 00
+ * and and there is no kernel RO (_PAGE_KERNEL_RO).
+ * User area mapped by 0x2 and read only use by
+ * 0x3.
*/
- if ((pteflags & _PAGE_USER) && !((pteflags & _PAGE_RW) &&
- (pteflags & _PAGE_DIRTY)))
- rflags |= 1;
+ if (pteflags & _PAGE_USER) {
+ rflags |= 0x2;
+ if (!((pteflags & _PAGE_RW) && (pteflags & _PAGE_DIRTY)))
+ rflags |= 0x1;
+ }
/*
* Always add "C" bit for perf. Memory coherence is always enabled
*/
- return rflags | HPTE_R_C | HPTE_R_M;
+ rflags |= HPTE_R_C | HPTE_R_M;
+ /*
+ * Add in WIG bits
+ */
+ if (pteflags & _PAGE_WRITETHRU)
+ rflags |= HPTE_R_W;
+ if (pteflags & _PAGE_NO_CACHE)
+ rflags |= HPTE_R_I;
+ if (pteflags & _PAGE_GUARDED)
+ rflags |= HPTE_R_G;
+
+ return rflags;
}
int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
@@ -629,46 +646,6 @@ int remove_section_mapping(unsigned long start, unsigned long end)
}
#endif /* CONFIG_MEMORY_HOTPLUG */
-extern u32 htab_call_hpte_insert1[];
-extern u32 htab_call_hpte_insert2[];
-extern u32 htab_call_hpte_remove[];
-extern u32 htab_call_hpte_updatepp[];
-extern u32 ht64_call_hpte_insert1[];
-extern u32 ht64_call_hpte_insert2[];
-extern u32 ht64_call_hpte_remove[];
-extern u32 ht64_call_hpte_updatepp[];
-
-static void __init htab_finish_init(void)
-{
-#ifdef CONFIG_PPC_64K_PAGES
- patch_branch(ht64_call_hpte_insert1,
- ppc_function_entry(ppc_md.hpte_insert),
- BRANCH_SET_LINK);
- patch_branch(ht64_call_hpte_insert2,
- ppc_function_entry(ppc_md.hpte_insert),
- BRANCH_SET_LINK);
- patch_branch(ht64_call_hpte_remove,
- ppc_function_entry(ppc_md.hpte_remove),
- BRANCH_SET_LINK);
- patch_branch(ht64_call_hpte_updatepp,
- ppc_function_entry(ppc_md.hpte_updatepp),
- BRANCH_SET_LINK);
-#endif /* CONFIG_PPC_64K_PAGES */
-
- patch_branch(htab_call_hpte_insert1,
- ppc_function_entry(ppc_md.hpte_insert),
- BRANCH_SET_LINK);
- patch_branch(htab_call_hpte_insert2,
- ppc_function_entry(ppc_md.hpte_insert),
- BRANCH_SET_LINK);
- patch_branch(htab_call_hpte_remove,
- ppc_function_entry(ppc_md.hpte_remove),
- BRANCH_SET_LINK);
- patch_branch(htab_call_hpte_updatepp,
- ppc_function_entry(ppc_md.hpte_updatepp),
- BRANCH_SET_LINK);
-}
-
static void __init htab_initialize(void)
{
unsigned long table;
@@ -815,7 +792,6 @@ static void __init htab_initialize(void)
mmu_linear_psize, mmu_kernel_ssize));
}
- htab_finish_init();
DBG(" <- htab_initialize()\n");
}
@@ -877,11 +853,11 @@ static unsigned int get_paca_psize(unsigned long addr)
unsigned long index, mask_index;
if (addr < SLICE_LOW_TOP) {
- lpsizes = get_paca()->context.low_slices_psize;
+ lpsizes = get_paca()->mm_ctx_low_slices_psize;
index = GET_LOW_SLICE_INDEX(addr);
return (lpsizes >> (index * 4)) & 0xF;
}
- hpsizes = get_paca()->context.high_slices_psize;
+ hpsizes = get_paca()->mm_ctx_high_slices_psize;
index = GET_HIGH_SLICE_INDEX(addr);
mask_index = index & 0x1;
return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xF;
@@ -890,7 +866,7 @@ static unsigned int get_paca_psize(unsigned long addr)
#else
unsigned int get_paca_psize(unsigned long addr)
{
- return get_paca()->context.user_psize;
+ return get_paca()->mm_ctx_user_psize;
}
#endif
@@ -906,7 +882,8 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K);
copro_flush_all_slbs(mm);
if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) {
- get_paca()->context = mm->context;
+
+ copy_mm_to_paca(&mm->context);
slb_flush_and_rebolt();
}
}
@@ -973,7 +950,7 @@ static void check_paca_psize(unsigned long ea, struct mm_struct *mm,
{
if (user_region) {
if (psize != get_paca_psize(ea)) {
- get_paca()->context = mm->context;
+ copy_mm_to_paca(&mm->context);
slb_flush_and_rebolt();
}
} else if (get_paca()->vmalloc_sllp !=
@@ -1148,9 +1125,10 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea,
}
}
+#endif /* CONFIG_PPC_64K_PAGES */
+
if (current->mm == mm)
check_paca_psize(ea, mm, psize, user_region);
-#endif /* CONFIG_PPC_64K_PAGES */
#ifdef CONFIG_PPC_64K_PAGES
if (psize == MMU_PAGE_64K)
@@ -1203,6 +1181,35 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap,
}
EXPORT_SYMBOL_GPL(hash_page);
+int __hash_page(unsigned long ea, unsigned long msr, unsigned long trap,
+ unsigned long dsisr)
+{
+ unsigned long access = _PAGE_PRESENT;
+ unsigned long flags = 0;
+ struct mm_struct *mm = current->mm;
+
+ if (REGION_ID(ea) == VMALLOC_REGION_ID)
+ mm = &init_mm;
+
+ if (dsisr & DSISR_NOHPTE)
+ flags |= HPTE_NOHPTE_UPDATE;
+
+ if (dsisr & DSISR_ISSTORE)
+ access |= _PAGE_RW;
+ /*
+ * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
+ * accessing a userspace segment (even from the kernel). We assume
+ * kernel addresses always have the high bit set.
+ */
+ if ((msr & MSR_PR) || (REGION_ID(ea) == USER_REGION_ID))
+ access |= _PAGE_USER;
+
+ if (trap == 0x400)
+ access |= _PAGE_EXEC;
+
+ return hash_page_mm(mm, ea, access, trap, flags);
+}
+
void hash_preload(struct mm_struct *mm, unsigned long ea,
unsigned long access, unsigned long trap)
{
diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c
index 4d87122cf6a7..49b152b0f926 100644
--- a/arch/powerpc/mm/hugepage-hash64.c
+++ b/arch/powerpc/mm/hugepage-hash64.c
@@ -39,9 +39,6 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
/* If PMD busy, retry the access */
if (unlikely(old_pmd & _PAGE_BUSY))
return 0;
- /* If PMD is trans splitting retry the access */
- if (unlikely(old_pmd & _PAGE_SPLITTING))
- return 0;
/* If PMD permissions don't match, take page fault */
if (unlikely(access & ~old_pmd))
return 1;
@@ -54,18 +51,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
new_pmd |= _PAGE_DIRTY;
} while (old_pmd != __cmpxchg_u64((unsigned long *)pmdp,
old_pmd, new_pmd));
- /*
- * PP bits. _PAGE_USER is already PP bit 0x2, so we only
- * need to add in 0x1 if it's a read-only user page
- */
- rflags = new_pmd & _PAGE_USER;
- if ((new_pmd & _PAGE_USER) && !((new_pmd & _PAGE_RW) &&
- (new_pmd & _PAGE_DIRTY)))
- rflags |= 0x1;
- /*
- * _PAGE_EXEC -> HW_NO_EXEC since it's inverted
- */
- rflags |= ((new_pmd & _PAGE_EXEC) ? 0 : HPTE_R_N);
+ rflags = htab_convert_pte_flags(new_pmd);
#if 0
if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
@@ -82,7 +68,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
*/
shift = mmu_psize_defs[psize].shift;
index = (ea & ~HPAGE_PMD_MASK) >> shift;
- BUG_ON(index >= 4096);
+ BUG_ON(index >= PTE_FRAG_SIZE);
vpn = hpt_vpn(ea, vsid, ssize);
hpte_slot_array = get_hpte_slot_array(pmdp);
@@ -131,13 +117,6 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
pa = pmd_pfn(__pmd(old_pmd)) << PAGE_SHIFT;
new_pmd |= _PAGE_HASHPTE;
- /* Add in WIMG bits */
- rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
- _PAGE_GUARDED));
- /*
- * enable the memory coherence always
- */
- rflags |= HPTE_R_M;
repeat:
hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c
index ba47aaf33a4b..7e6d0880813f 100644
--- a/arch/powerpc/mm/hugetlbpage-book3e.c
+++ b/arch/powerpc/mm/hugetlbpage-book3e.c
@@ -51,6 +51,48 @@ static inline int mmu_get_tsize(int psize)
return mmu_psize_defs[psize].enc;
}
+#if defined(CONFIG_PPC_FSL_BOOK3E) && defined(CONFIG_PPC64)
+#include <asm/paca.h>
+
+static inline void book3e_tlb_lock(void)
+{
+ struct paca_struct *paca = get_paca();
+ unsigned long tmp;
+ int token = smp_processor_id() + 1;
+
+ asm volatile("1: lbarx %0, 0, %1;"
+ "cmpwi %0, 0;"
+ "bne 2f;"
+ "stbcx. %2, 0, %1;"
+ "bne 1b;"
+ "b 3f;"
+ "2: lbzx %0, 0, %1;"
+ "cmpwi %0, 0;"
+ "bne 2b;"
+ "b 1b;"
+ "3:"
+ : "=&r" (tmp)
+ : "r" (&paca->tcd_ptr->lock), "r" (token)
+ : "memory");
+}
+
+static inline void book3e_tlb_unlock(void)
+{
+ struct paca_struct *paca = get_paca();
+
+ isync();
+ paca->tcd_ptr->lock = 0;
+}
+#else
+static inline void book3e_tlb_lock(void)
+{
+}
+
+static inline void book3e_tlb_unlock(void)
+{
+}
+#endif
+
static inline int book3e_tlb_exists(unsigned long ea, unsigned long pid)
{
int found = 0;
@@ -109,7 +151,10 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
*/
local_irq_save(flags);
+ book3e_tlb_lock();
+
if (unlikely(book3e_tlb_exists(ea, mm->context.id))) {
+ book3e_tlb_unlock();
local_irq_restore(flags);
return;
}
@@ -141,6 +186,7 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
asm volatile ("tlbwe");
+ book3e_tlb_unlock();
local_irq_restore(flags);
}
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c
index d94b1af53a93..e2138c7ae70f 100644
--- a/arch/powerpc/mm/hugetlbpage-hash64.c
+++ b/arch/powerpc/mm/hugetlbpage-hash64.c
@@ -59,10 +59,8 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
new_pte |= _PAGE_DIRTY;
} while(old_pte != __cmpxchg_u64((unsigned long *)ptep,
old_pte, new_pte));
+ rflags = htab_convert_pte_flags(new_pte);
- rflags = 0x2 | (!(new_pte & _PAGE_RW));
- /* _PAGE_EXEC -> HW_NO_EXEC since it's inverted */
- rflags |= ((new_pte & _PAGE_EXEC) ? 0 : HPTE_R_N);
sz = ((1UL) << shift);
if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
/* No CPU has hugepages but lacks no execute, so we
@@ -91,18 +89,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
/* clear HPTE slot informations in new PTE */
-#ifdef CONFIG_PPC_64K_PAGES
- new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HPTE_SUB0;
-#else
new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE;
-#endif
- /* Add in WIMG bits */
- rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
- _PAGE_COHERENT | _PAGE_GUARDED));
- /*
- * enable the memory coherence always
- */
- rflags |= HPTE_R_M;
slot = hpte_insert_repeating(hash, vpn, pa, rflags, 0,
mmu_psize, ssize);
@@ -127,3 +114,21 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
*ptep = __pte(new_pte & ~_PAGE_BUSY);
return 0;
}
+
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_DEBUG_VM)
+/*
+ * This enables us to catch the wrong page directory format
+ * Moved here so that we can use WARN() in the call.
+ */
+int hugepd_ok(hugepd_t hpd)
+{
+ bool is_hugepd;
+
+ /*
+ * We should not find this format in page directory, warn otherwise.
+ */
+ is_hugepd = (((hpd.pd & 0x3) == 0x0) && ((hpd.pd & HUGEPD_SHIFT_MASK) != 0));
+ WARN(is_hugepd, "Found wrong page directory format\n");
+ return 0;
+}
+#endif
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 9833fee493ec..744e24bcb85c 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -53,78 +53,6 @@ static unsigned nr_gpages;
#define hugepd_none(hpd) ((hpd).pd == 0)
-#ifdef CONFIG_PPC_BOOK3S_64
-/*
- * At this point we do the placement change only for BOOK3S 64. This would
- * possibly work on other subarchs.
- */
-
-/*
- * We have PGD_INDEX_SIZ = 12 and PTE_INDEX_SIZE = 8, so that we can have
- * 16GB hugepage pte in PGD and 16MB hugepage pte at PMD;
- *
- * Defined in such a way that we can optimize away code block at build time
- * if CONFIG_HUGETLB_PAGE=n.
- */
-int pmd_huge(pmd_t pmd)
-{
- /*
- * leaf pte for huge page, bottom two bits != 00
- */
- return ((pmd_val(pmd) & 0x3) != 0x0);
-}
-
-int pud_huge(pud_t pud)
-{
- /*
- * leaf pte for huge page, bottom two bits != 00
- */
- return ((pud_val(pud) & 0x3) != 0x0);
-}
-
-int pgd_huge(pgd_t pgd)
-{
- /*
- * leaf pte for huge page, bottom two bits != 00
- */
- return ((pgd_val(pgd) & 0x3) != 0x0);
-}
-
-#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_DEBUG_VM)
-/*
- * This enables us to catch the wrong page directory format
- * Moved here so that we can use WARN() in the call.
- */
-int hugepd_ok(hugepd_t hpd)
-{
- bool is_hugepd;
-
- /*
- * We should not find this format in page directory, warn otherwise.
- */
- is_hugepd = (((hpd.pd & 0x3) == 0x0) && ((hpd.pd & HUGEPD_SHIFT_MASK) != 0));
- WARN(is_hugepd, "Found wrong page directory format\n");
- return 0;
-}
-#endif
-
-#else
-int pmd_huge(pmd_t pmd)
-{
- return 0;
-}
-
-int pud_huge(pud_t pud)
-{
- return 0;
-}
-
-int pgd_huge(pgd_t pgd)
-{
- return 0;
-}
-#endif
-
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
/* Only called for hugetlbfs pages, hence can ignore THP */
@@ -966,8 +894,8 @@ void flush_dcache_icache_hugepage(struct page *page)
* We have 4 cases for pgds and pmds:
* (1) invalid (all zeroes)
* (2) pointer to next table, as normal; bottom 6 bits == 0
- * (3) leaf pte for huge page, bottom two bits != 00
- * (4) hugepd pointer, bottom two bits == 00, next 4 bits indicate size of table
+ * (3) leaf pte for huge page _PAGE_PTE set
+ * (4) hugepd pointer, _PAGE_PTE = 0 and bits [2..6] indicate size of table
*
* So long as we atomically load page table pointers we are safe against teardown,
* we can follow the address down to the the page and take a ref on it.
@@ -1030,10 +958,6 @@ pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
/*
* A hugepage collapse is captured by pmd_none, because
* it mark the pmd none and do a hpte invalidate.
- *
- * We don't worry about pmd_trans_splitting here, The
- * caller if it needs to handle the splitting case
- * should check for that.
*/
if (pmd_none(pmd))
return NULL;
@@ -1071,7 +995,7 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
{
unsigned long mask;
unsigned long pte_end;
- struct page *head, *page, *tail;
+ struct page *head, *page;
pte_t pte;
int refs;
@@ -1094,7 +1018,6 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
head = pte_page(pte);
page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
- tail = page;
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
@@ -1116,15 +1039,5 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
return 0;
}
- /*
- * Any tail page need their mapcount reference taken before we
- * return.
- */
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
return 1;
}
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index d747dd7bc90b..379a6a90644b 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -87,11 +87,7 @@ static void pgd_ctor(void *addr)
static void pmd_ctor(void *addr)
{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- memset(addr, 0, PMD_TABLE_SIZE * 2);
-#else
memset(addr, 0, PMD_TABLE_SIZE);
-#endif
}
struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE];
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 83dfcb55ffef..83dfd7925c72 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -179,6 +179,10 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
*/
VM_WARN_ON((pte_val(*ptep) & (_PAGE_PRESENT | _PAGE_USER)) ==
(_PAGE_PRESENT | _PAGE_USER));
+ /*
+ * Add the pte bit when tryint set a pte
+ */
+ pte = __pte(pte_val(pte) | _PAGE_PTE);
/* Note: mm->context.id might not yet have been assigned as
* this context might not have been activated yet when this
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index e92cb2146b18..3124a20d0fab 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -359,7 +359,7 @@ struct page *pud_page(pud_t pud)
struct page *pmd_page(pmd_t pmd)
{
if (pmd_trans_huge(pmd) || pmd_huge(pmd))
- return pfn_to_page(pmd_pfn(pmd));
+ return pte_page(pmd_pte(pmd));
return virt_to_page(pmd_page_vaddr(pmd));
}
@@ -604,55 +604,6 @@ int pmdp_clear_flush_young(struct vm_area_struct *vma,
}
/*
- * We mark the pmd splitting and invalidate all the hpte
- * entries for this hugepage.
- */
-void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp)
-{
- unsigned long old, tmp;
-
- VM_BUG_ON(address & ~HPAGE_PMD_MASK);
-
-#ifdef CONFIG_DEBUG_VM
- WARN_ON(!pmd_trans_huge(*pmdp));
- assert_spin_locked(&vma->vm_mm->page_table_lock);
-#endif
-
-#ifdef PTE_ATOMIC_UPDATES
-
- __asm__ __volatile__(
- "1: ldarx %0,0,%3\n\
- andi. %1,%0,%6\n\
- bne- 1b \n\
- ori %1,%0,%4 \n\
- stdcx. %1,0,%3 \n\
- bne- 1b"
- : "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
- : "r" (pmdp), "i" (_PAGE_SPLITTING), "m" (*pmdp), "i" (_PAGE_BUSY)
- : "cc" );
-#else
- old = pmd_val(*pmdp);
- *pmdp = __pmd(old | _PAGE_SPLITTING);
-#endif
- /*
- * If we didn't had the splitting flag set, go and flush the
- * HPTE entries.
- */
- trace_hugepage_splitting(address, old);
- if (!(old & _PAGE_SPLITTING)) {
- /* We need to flush the hpte */
- if (old & _PAGE_HASHPTE)
- hpte_do_hugepage_flush(vma->vm_mm, address, pmdp, old);
- }
- /*
- * This ensures that generic code that rely on IRQ disabling
- * to prevent a parallel THP split work as expected.
- */
- kick_all_cpus_sync();
-}
-
-/*
* We want to put the pgtable in pmd and use pgtable for tracking
* the base page size hptes
*/
@@ -759,22 +710,15 @@ void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot)
{
- pmd_val(pmd) |= pgprot_val(pgprot);
- return pmd;
+ return __pmd(pmd_val(pmd) | pgprot_val(pgprot));
}
pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot)
{
- pmd_t pmd;
- /*
- * For a valid pte, we would have _PAGE_PRESENT always
- * set. We use this to check THP page at pmd level.
- * leaf pte for huge page, bottom two bits != 00
- */
- pmd_val(pmd) = pfn << PTE_RPN_SHIFT;
- pmd_val(pmd) |= _PAGE_THP_HUGE;
- pmd = pmd_set_protbits(pmd, pgprot);
- return pmd;
+ unsigned long pmdv;
+
+ pmdv = pfn << PTE_RPN_SHIFT;
+ return pmd_set_protbits(__pmd(pmdv), pgprot);
}
pmd_t mk_pmd(struct page *page, pgprot_t pgprot)
@@ -784,10 +728,11 @@ pmd_t mk_pmd(struct page *page, pgprot_t pgprot)
pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
{
+ unsigned long pmdv;
- pmd_val(pmd) &= _HPAGE_CHG_MASK;
- pmd = pmd_set_protbits(pmd, newprot);
- return pmd;
+ pmdv = pmd_val(pmd);
+ pmdv &= _HPAGE_CHG_MASK;
+ return pmd_set_protbits(__pmd(pmdv), newprot);
}
/*
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 515730e499fe..825b6873391f 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -228,7 +228,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
asm volatile("slbie %0" : : "r" (slbie_data));
get_paca()->slb_cache_ptr = 0;
- get_paca()->context = mm->context;
+ copy_mm_to_paca(&mm->context);
/*
* preload some userspace segments into the SLB.
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
index 0f432a702870..42954f0b47ac 100644
--- a/arch/powerpc/mm/slice.c
+++ b/arch/powerpc/mm/slice.c
@@ -185,8 +185,7 @@ static void slice_flush_segments(void *parm)
if (mm != current->active_mm)
return;
- /* update the paca copy of the context struct */
- get_paca()->context = current->active_mm->context;
+ copy_mm_to_paca(&current->active_mm->context);
local_irq_save(flags);
slb_flush_and_rebolt();
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
index fa9fb5b4c66c..d5543514c1df 100644
--- a/arch/powerpc/mm/subpage-prot.c
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -135,7 +135,7 @@ static int subpage_walk_pmd_entry(pmd_t *pmd, unsigned long addr,
unsigned long end, struct mm_walk *walk)
{
struct vm_area_struct *vma = walk->vma;
- split_huge_page_pmd(vma, addr, pmd);
+ split_huge_pmd(vma, pmd, addr);
return 0;
}
diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index bf4c4473abb9..4bc6bbbe9ada 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -37,8 +37,8 @@
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include "mpc83xx.h"
@@ -136,8 +136,6 @@ static void __init mpc83xx_km_setup_arch(void)
mpc83xx_setup_pci();
#ifdef CONFIG_QUICC_ENGINE
- qe_reset();
-
np = of_find_node_by_name(NULL, "par_io");
if (np != NULL) {
par_io_init(np);
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c
index ef9d01a049c1..7e923cad56cf 100644
--- a/arch/powerpc/platforms/83xx/misc.c
+++ b/arch/powerpc/platforms/83xx/misc.c
@@ -17,7 +17,7 @@
#include <asm/io.h>
#include <asm/hw_irq.h>
#include <asm/ipic.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 8d762203eeff..a973b2ae5df6 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -36,8 +36,8 @@
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include "mpc83xx.h"
@@ -74,8 +74,6 @@ static void __init mpc832x_sys_setup_arch(void)
mpc83xx_setup_pci();
#ifdef CONFIG_QUICC_ENGINE
- qe_reset();
-
if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index eff5baabc3fb..ea2b87d202ca 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -25,8 +25,8 @@
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@@ -203,8 +203,6 @@ static void __init mpc832x_rdb_setup_arch(void)
mpc83xx_setup_pci();
#ifdef CONFIG_QUICC_ENGINE
- qe_reset();
-
if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index 1a26d2f83401..dd70b85f56d4 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -44,8 +44,8 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <sysdev/simple_gpio.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include "mpc83xx.h"
@@ -82,8 +82,6 @@ static void __init mpc836x_mds_setup_arch(void)
mpc83xx_setup_pci();
#ifdef CONFIG_QUICC_ENGINE
- qe_reset();
-
if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c
index b63b42d11d6c..4cd7153a6c88 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c
@@ -20,8 +20,8 @@
#include <asm/time.h>
#include <asm/ipic.h>
#include <asm/udbg.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@@ -35,9 +35,6 @@ static void __init mpc836x_rdk_setup_arch(void)
ppc_md.progress("mpc836x_rdk_setup_arch()", 0);
mpc83xx_setup_pci();
-#ifdef CONFIG_QUICC_ENGINE
- qe_reset();
-#endif
}
/*
diff --git a/arch/powerpc/platforms/85xx/bsc913x_qds.c b/arch/powerpc/platforms/85xx/bsc913x_qds.c
index f0927e58af25..dcfafd6b91ee 100644
--- a/arch/powerpc/platforms/85xx/bsc913x_qds.c
+++ b/arch/powerpc/platforms/85xx/bsc913x_qds.c
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <asm/mpic.h>
#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
#include <asm/udbg.h>
#include "mpc85xx.h"
@@ -46,10 +47,12 @@ static void __init bsc913x_qds_setup_arch(void)
mpc85xx_smp_init();
#endif
+ fsl_pci_assign_primary();
+
pr_info("bsc913x board from Freescale Semiconductor\n");
}
-machine_device_initcall(bsc9132_qds, mpc85xx_common_publish_devices);
+machine_arch_initcall(bsc9132_qds, mpc85xx_common_publish_devices);
/*
* Called very early, device-tree isn't unflattened
@@ -67,6 +70,9 @@ define_machine(bsc9132_qds) {
.probe = bsc9132_qds_probe,
.setup_arch = bsc913x_qds_setup_arch,
.init_IRQ = bsc913x_qds_pic_init,
+#ifdef CONFIG_PCI
+ .pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
index 23791de7b688..949f22c86e61 100644
--- a/arch/powerpc/platforms/85xx/common.c
+++ b/arch/powerpc/platforms/85xx/common.c
@@ -9,7 +9,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include <sysdev/cpm2_pic.h>
#include "mpc85xx.h"
@@ -105,7 +105,6 @@ void __init mpc85xx_qe_init(void)
return;
}
- qe_reset();
of_node_put(np);
}
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index 46d05c94add6..a2b0bc859de0 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -27,7 +27,7 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/ehv_pic.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 7d12a19aa7ee..de72a5f464b1 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -36,17 +36,6 @@
#include "mpc85xx.h"
-#ifdef CONFIG_PCI
-static int mpc85xx_exclude_device(struct pci_controller *hose,
- u_char bus, u_char devfn)
-{
- if (bus == 0 && PCI_SLOT(devfn) == 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
- else
- return PCIBIOS_SUCCESSFUL;
-}
-#endif /* CONFIG_PCI */
-
static void __init mpc85xx_ads_pic_init(void)
{
struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
@@ -145,10 +134,6 @@ static void __init mpc85xx_ads_setup_arch(void)
init_ioports();
#endif
-#ifdef CONFIG_PCI
- ppc_md.pci_exclude_device = mpc85xx_exclude_device;
-#endif
-
fsl_pci_assign_primary();
}
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index f0be439ceaaa..f61cbe235581 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -48,8 +48,8 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <sysdev/simple_gpio.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <asm/mpic.h>
#include <asm/swiotlb.h>
#include "smp.h"
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index 50dcc00a0f5a..3f4dad133338 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -26,8 +26,8 @@
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/mpic.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c
index 892e613519cc..71bc255b4324 100644
--- a/arch/powerpc/platforms/85xx/twr_p102x.c
+++ b/arch/powerpc/platforms/85xx/twr_p102x.c
@@ -22,8 +22,8 @@
#include <asm/pci-bridge.h>
#include <asm/udbg.h>
#include <asm/mpic.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index b7f9c408bf24..46a3533d3acb 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -272,17 +272,6 @@ config TAU_AVERAGE
If in doubt, say N here.
-config QUICC_ENGINE
- bool "Freescale QUICC Engine (QE) Support"
- depends on FSL_SOC && PPC32
- select PPC_LIB_RHEAP
- select CRC32
- help
- The QUICC Engine (QE) is a new generation of communications
- coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
- Selecting this option means that you wish to build a kernel
- for a machine with a QE coprocessor.
-
config QE_GPIO
bool "QE GPIO support"
depends on QUICC_ENGINE
@@ -295,7 +284,6 @@ config CPM2
bool "Enable support for the CPM2 (Communications Processor Module)"
depends on (FSL_SOC_BOOKE && PPC32) || 8260
select CPM
- select PPC_LIB_RHEAP
select PPC_PCI_CHOICE
select ARCH_REQUIRE_GPIOLIB
help
@@ -325,6 +313,7 @@ config FSL_ULI1575
config CPM
bool
+ select GENERIC_ALLOCATOR
config OF_RTC
bool
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 429fc59d2a47..d9088f0b8fcc 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -33,11 +33,6 @@ config PPC_IBM_CELL_BLADE
select PPC_UDBG_16550
select UDBG_RTAS_CONSOLE
-config PPC_CELL_QPACE
- bool "IBM Cell - QPACE"
- depends on PPC64 && PPC_BOOK3S && CPU_BIG_ENDIAN
- select PPC_CELL_COMMON
-
config AXON_MSI
bool
depends on PPC_IBM_CELL_BLADE && PCI_MSI
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 34699bddfddd..00464305763d 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_PPC_IBM_CELL_POWERBUTTON) += cbe_powerbutton.o
ifeq ($(CONFIG_SMP),y)
obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
-obj-$(CONFIG_PPC_CELL_QPACE) += smp.o
endif
# needed only when building loadable spufs.ko
@@ -26,6 +25,3 @@ obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
spufs/
obj-$(CONFIG_AXON_MSI) += axon_msi.o
-
-# qpace setup
-obj-$(CONFIG_PPC_CELL_QPACE) += qpace_setup.o
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
deleted file mode 100644
index d328140dc6f5..000000000000
--- a/arch/powerpc/platforms/cell/qpace_setup.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * linux/arch/powerpc/platforms/cell/qpace_setup.c
- *
- * Copyright (C) 1995 Linus Torvalds
- * Adapted from 'alpha' version by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- * Modified by PPC64 Team, IBM Corp
- * Modified by Cell Team, IBM Deutschland Entwicklung GmbH
- * Modified by Benjamin Krill <ben@codiert.org>, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/export.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/console.h>
-#include <linux/of_platform.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/kexec.h>
-#include <asm/pgtable.h>
-#include <asm/prom.h>
-#include <asm/rtas.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/cputable.h>
-#include <asm/irq.h>
-#include <asm/spu.h>
-#include <asm/spu_priv1.h>
-#include <asm/udbg.h>
-#include <asm/cell-regs.h>
-
-#include "interrupt.h"
-#include "pervasive.h"
-#include "ras.h"
-
-static void qpace_show_cpuinfo(struct seq_file *m)
-{
- struct device_node *root;
- const char *model = "";
-
- root = of_find_node_by_path("/");
- if (root)
- model = of_get_property(root, "model", NULL);
- seq_printf(m, "machine\t\t: CHRP %s\n", model);
- of_node_put(root);
-}
-
-static void qpace_progress(char *s, unsigned short hex)
-{
- printk("*** %04x : %s\n", hex, s ? s : "");
-}
-
-static const struct of_device_id qpace_bus_ids[] __initconst = {
- { .type = "soc", },
- { .compatible = "soc", },
- { .type = "spider", },
- { .type = "axon", },
- { .type = "plb5", },
- { .type = "plb4", },
- { .type = "opb", },
- { .type = "ebc", },
- {},
-};
-
-static int __init qpace_publish_devices(void)
-{
- int node;
-
- /* Publish OF platform devices for southbridge IOs */
- of_platform_bus_probe(NULL, qpace_bus_ids, NULL);
-
- /* There is no device for the MIC memory controller, thus we create
- * a platform device for it to attach the EDAC driver to.
- */
- for_each_online_node(node) {
- if (cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(node)) == NULL)
- continue;
- platform_device_register_simple("cbe-mic", node, NULL, 0);
- }
-
- return 0;
-}
-machine_subsys_initcall(qpace, qpace_publish_devices);
-
-static void __init qpace_setup_arch(void)
-{
-#ifdef CONFIG_SPU_BASE
- spu_priv1_ops = &spu_priv1_mmio_ops;
- spu_management_ops = &spu_management_of_ops;
-#endif
-
- cbe_regs_init();
-
-#ifdef CONFIG_CBE_RAS
- cbe_ras_init();
-#endif
-
-#ifdef CONFIG_SMP
- smp_init_cell();
-#endif
-
- /* init to some ~sane value until calibrate_delay() runs */
- loops_per_jiffy = 50000000;
-
- cbe_pervasive_init();
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-}
-
-static int __init qpace_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "IBM,QPACE"))
- return 0;
-
- hpte_init_native();
- pm_power_off = rtas_power_off;
-
- return 1;
-}
-
-define_machine(qpace) {
- .name = "QPACE",
- .probe = qpace_probe,
- .setup_arch = qpace_setup_arch,
- .show_cpuinfo = qpace_show_cpuinfo,
- .restart = rtas_restart,
- .halt = rtas_halt,
- .get_boot_time = rtas_get_boot_time,
- .get_rtc_time = rtas_get_rtc_time,
- .set_rtc_time = rtas_set_rtc_time,
- .calibrate_decr = generic_calibrate_decr,
- .progress = qpace_progress,
- .init_IRQ = iic_init_IRQ,
-};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 11634fa7ab3c..ad4840f86be1 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -767,7 +767,7 @@ static int __init spufs_init(void)
ret = -ENOMEM;
spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
sizeof(struct spufs_inode_info), 0,
- SLAB_HWCACHE_ALIGN, spufs_init_once);
+ SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, spufs_init_once);
if (!spufs_inode_cache)
goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 4ddf769a64e5..9f79004e6d6f 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -326,7 +326,7 @@ static int spu_process_callback(struct spu_context *ctx)
spu_ret = -ENOSYS;
npc += 4;
- if (s.nr_ret < __NR_syscalls) {
+ if (s.nr_ret < NR_syscalls) {
spu_release(ctx);
/* do actual system call from here */
spu_ret = spu_sys_callback(&s);
diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c
index b4a369dac3a8..81799d70a1ee 100644
--- a/arch/powerpc/platforms/maple/time.c
+++ b/arch/powerpc/platforms/maple/time.c
@@ -77,7 +77,7 @@ void maple_get_rtc_time(struct rtc_time *tm)
if ((tm->tm_year + 1900) < 1970)
tm->tm_year += 100;
- GregorianDay(tm);
+ tm->tm_wday = -1;
}
int maple_set_rtc_time(struct rtc_time *tm)
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index 76f5013c35e5..c3c9bbb3573a 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -84,6 +84,7 @@ static void __init bootx_printf(const char *format, ...)
break;
}
}
+ va_end(args);
}
#else /* CONFIG_BOOTX_TEXT */
static void __init bootx_printf(const char *format, ...) {}
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 6f4f8b060def..981546345033 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -258,13 +258,14 @@ static unsigned int pmac_pic_get_irq(void)
#ifdef CONFIG_XMON
static struct irqaction xmon_action = {
.handler = xmon_irq,
- .flags = 0,
+ .flags = IRQF_NO_THREAD,
.name = "NMI - XMON"
};
#endif
static struct irqaction gatwick_cascade_action = {
.handler = gatwick_action,
+ .flags = IRQF_NO_THREAD,
.name = "cascade",
};
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 1c8cdb6250e7..f1516b5ecec9 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,9 +2,10 @@ obj-y += setup.o opal-wrappers.o opal.o opal-async.o idle.o
obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
+obj-y += opal-kmsg.o
obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o
-obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
+obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o npu-dma.o
obj-$(CONFIG_EEH) += eeh-powernv.o
obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index e1c90725522a..5f152b95ca0c 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -48,8 +48,8 @@ static int pnv_eeh_init(void)
struct pci_controller *hose;
struct pnv_phb *phb;
- if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
- pr_warn("%s: OPALv3 is required !\n",
+ if (!firmware_has_feature(FW_FEATURE_OPAL)) {
+ pr_warn("%s: OPAL is required !\n",
__func__);
return -EINVAL;
}
diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
index 59d735d2e5c0..15bfbcd5debc 100644
--- a/arch/powerpc/platforms/powernv/idle.c
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -242,7 +242,7 @@ static int __init pnv_init_idle_states(void)
if (cpuidle_disable != IDLE_NO_OVERRIDE)
goto out;
- if (!firmware_has_feature(FW_FEATURE_OPALv3))
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
goto out;
power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
new file mode 100644
index 000000000000..e85aa900f5c0
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -0,0 +1,348 @@
+/*
+ * This file implements the DMA operations for NVLink devices. The NPU
+ * devices all point to the same iommu table as the parent PCI device.
+ *
+ * Copyright Alistair Popple, IBM Corporation 2015.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+#include <linux/pci.h>
+#include <linux/memblock.h>
+
+#include <asm/iommu.h>
+#include <asm/pnv-pci.h>
+#include <asm/msi_bitmap.h>
+#include <asm/opal.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+/*
+ * Other types of TCE cache invalidation are not functional in the
+ * hardware.
+ */
+#define TCE_KILL_INVAL_ALL PPC_BIT(0)
+
+static struct pci_dev *get_pci_dev(struct device_node *dn)
+{
+ return PCI_DN(dn)->pcidev;
+}
+
+/* Given a NPU device get the associated PCI device. */
+struct pci_dev *pnv_pci_get_gpu_dev(struct pci_dev *npdev)
+{
+ struct device_node *dn;
+ struct pci_dev *gpdev;
+
+ /* Get assoicated PCI device */
+ dn = of_parse_phandle(npdev->dev.of_node, "ibm,gpu", 0);
+ if (!dn)
+ return NULL;
+
+ gpdev = get_pci_dev(dn);
+ of_node_put(dn);
+
+ return gpdev;
+}
+EXPORT_SYMBOL(pnv_pci_get_gpu_dev);
+
+/* Given the real PCI device get a linked NPU device. */
+struct pci_dev *pnv_pci_get_npu_dev(struct pci_dev *gpdev, int index)
+{
+ struct device_node *dn;
+ struct pci_dev *npdev;
+
+ /* Get assoicated PCI device */
+ dn = of_parse_phandle(gpdev->dev.of_node, "ibm,npu", index);
+ if (!dn)
+ return NULL;
+
+ npdev = get_pci_dev(dn);
+ of_node_put(dn);
+
+ return npdev;
+}
+EXPORT_SYMBOL(pnv_pci_get_npu_dev);
+
+#define NPU_DMA_OP_UNSUPPORTED() \
+ dev_err_once(dev, "%s operation unsupported for NVLink devices\n", \
+ __func__)
+
+static void *dma_npu_alloc(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
+{
+ NPU_DMA_OP_UNSUPPORTED();
+ return NULL;
+}
+
+static void dma_npu_free(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ NPU_DMA_OP_UNSUPPORTED();
+}
+
+static dma_addr_t dma_npu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ NPU_DMA_OP_UNSUPPORTED();
+ return 0;
+}
+
+static int dma_npu_map_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ NPU_DMA_OP_UNSUPPORTED();
+ return 0;
+}
+
+static int dma_npu_dma_supported(struct device *dev, u64 mask)
+{
+ NPU_DMA_OP_UNSUPPORTED();
+ return 0;
+}
+
+static u64 dma_npu_get_required_mask(struct device *dev)
+{
+ NPU_DMA_OP_UNSUPPORTED();
+ return 0;
+}
+
+struct dma_map_ops dma_npu_ops = {
+ .map_page = dma_npu_map_page,
+ .map_sg = dma_npu_map_sg,
+ .alloc = dma_npu_alloc,
+ .free = dma_npu_free,
+ .dma_supported = dma_npu_dma_supported,
+ .get_required_mask = dma_npu_get_required_mask,
+};
+
+/*
+ * Returns the PE assoicated with the PCI device of the given
+ * NPU. Returns the linked pci device if pci_dev != NULL.
+ */
+static struct pnv_ioda_pe *get_gpu_pci_dev_and_pe(struct pnv_ioda_pe *npe,
+ struct pci_dev **gpdev)
+{
+ struct pnv_phb *phb;
+ struct pci_controller *hose;
+ struct pci_dev *pdev;
+ struct pnv_ioda_pe *pe;
+ struct pci_dn *pdn;
+
+ if (npe->flags & PNV_IODA_PE_PEER) {
+ pe = npe->peers[0];
+ pdev = pe->pdev;
+ } else {
+ pdev = pnv_pci_get_gpu_dev(npe->pdev);
+ if (!pdev)
+ return NULL;
+
+ pdn = pci_get_pdn(pdev);
+ if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+ return NULL;
+
+ hose = pci_bus_to_host(pdev->bus);
+ phb = hose->private_data;
+ pe = &phb->ioda.pe_array[pdn->pe_number];
+ }
+
+ if (gpdev)
+ *gpdev = pdev;
+
+ return pe;
+}
+
+void pnv_npu_tce_invalidate_entire(struct pnv_ioda_pe *npe)
+{
+ struct pnv_phb *phb = npe->phb;
+
+ if (WARN_ON(phb->type != PNV_PHB_NPU ||
+ !phb->ioda.tce_inval_reg ||
+ !(npe->flags & PNV_IODA_PE_DEV)))
+ return;
+
+ mb(); /* Ensure previous TCE table stores are visible */
+ __raw_writeq(cpu_to_be64(TCE_KILL_INVAL_ALL),
+ phb->ioda.tce_inval_reg);
+}
+
+void pnv_npu_tce_invalidate(struct pnv_ioda_pe *npe,
+ struct iommu_table *tbl,
+ unsigned long index,
+ unsigned long npages,
+ bool rm)
+{
+ struct pnv_phb *phb = npe->phb;
+
+ /* We can only invalidate the whole cache on NPU */
+ unsigned long val = TCE_KILL_INVAL_ALL;
+
+ if (WARN_ON(phb->type != PNV_PHB_NPU ||
+ !phb->ioda.tce_inval_reg ||
+ !(npe->flags & PNV_IODA_PE_DEV)))
+ return;
+
+ mb(); /* Ensure previous TCE table stores are visible */
+ if (rm)
+ __raw_rm_writeq(cpu_to_be64(val),
+ (__be64 __iomem *) phb->ioda.tce_inval_reg_phys);
+ else
+ __raw_writeq(cpu_to_be64(val),
+ phb->ioda.tce_inval_reg);
+}
+
+void pnv_npu_init_dma_pe(struct pnv_ioda_pe *npe)
+{
+ struct pnv_ioda_pe *gpe;
+ struct pci_dev *gpdev;
+ int i, avail = -1;
+
+ if (!npe->pdev || !(npe->flags & PNV_IODA_PE_DEV))
+ return;
+
+ gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
+ if (!gpe)
+ return;
+
+ for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+ /* Nothing to do if the PE is already connected. */
+ if (gpe->peers[i] == npe)
+ return;
+
+ if (!gpe->peers[i])
+ avail = i;
+ }
+
+ if (WARN_ON(avail < 0))
+ return;
+
+ gpe->peers[avail] = npe;
+ gpe->flags |= PNV_IODA_PE_PEER;
+
+ /*
+ * We assume that the NPU devices only have a single peer PE
+ * (the GPU PCIe device PE).
+ */
+ npe->peers[0] = gpe;
+ npe->flags |= PNV_IODA_PE_PEER;
+}
+
+/*
+ * For the NPU we want to point the TCE table at the same table as the
+ * real PCI device.
+ */
+static void pnv_npu_disable_bypass(struct pnv_ioda_pe *npe)
+{
+ struct pnv_phb *phb = npe->phb;
+ struct pci_dev *gpdev;
+ struct pnv_ioda_pe *gpe;
+ void *addr;
+ unsigned int size;
+ int64_t rc;
+
+ /*
+ * Find the assoicated PCI devices and get the dma window
+ * information from there.
+ */
+ if (!npe->pdev || !(npe->flags & PNV_IODA_PE_DEV))
+ return;
+
+ gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
+ if (!gpe)
+ return;
+
+ addr = (void *)gpe->table_group.tables[0]->it_base;
+ size = gpe->table_group.tables[0]->it_size << 3;
+ rc = opal_pci_map_pe_dma_window(phb->opal_id, npe->pe_number,
+ npe->pe_number, 1, __pa(addr),
+ size, 0x1000);
+ if (rc != OPAL_SUCCESS)
+ pr_warn("%s: Error %lld setting DMA window on PHB#%d-PE#%d\n",
+ __func__, rc, phb->hose->global_number, npe->pe_number);
+
+ /*
+ * We don't initialise npu_pe->tce32_table as we always use
+ * dma_npu_ops which are nops.
+ */
+ set_dma_ops(&npe->pdev->dev, &dma_npu_ops);
+}
+
+/*
+ * Enable/disable bypass mode on the NPU. The NPU only supports one
+ * window per link, so bypass needs to be explicity enabled or
+ * disabled. Unlike for a PHB3 bypass and non-bypass modes can't be
+ * active at the same time.
+ */
+int pnv_npu_dma_set_bypass(struct pnv_ioda_pe *npe, bool enable)
+{
+ struct pnv_phb *phb = npe->phb;
+ int64_t rc = 0;
+
+ if (phb->type != PNV_PHB_NPU || !npe->pdev)
+ return -EINVAL;
+
+ if (enable) {
+ /* Enable the bypass window */
+ phys_addr_t top = memblock_end_of_DRAM();
+
+ npe->tce_bypass_base = 0;
+ top = roundup_pow_of_two(top);
+ dev_info(&npe->pdev->dev, "Enabling bypass for PE %d\n",
+ npe->pe_number);
+ rc = opal_pci_map_pe_dma_window_real(phb->opal_id,
+ npe->pe_number, npe->pe_number,
+ npe->tce_bypass_base, top);
+ } else {
+ /*
+ * Disable the bypass window by replacing it with the
+ * TCE32 window.
+ */
+ pnv_npu_disable_bypass(npe);
+ }
+
+ return rc;
+}
+
+int pnv_npu_dma_set_mask(struct pci_dev *npdev, u64 dma_mask)
+{
+ struct pci_controller *hose = pci_bus_to_host(npdev->bus);
+ struct pnv_phb *phb = hose->private_data;
+ struct pci_dn *pdn = pci_get_pdn(npdev);
+ struct pnv_ioda_pe *npe, *gpe;
+ struct pci_dev *gpdev;
+ uint64_t top;
+ bool bypass = false;
+
+ if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+ return -ENXIO;
+
+ /* We only do bypass if it's enabled on the linked device */
+ npe = &phb->ioda.pe_array[pdn->pe_number];
+ gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
+ if (!gpe)
+ return -ENODEV;
+
+ if (gpe->tce_bypass_enabled) {
+ top = gpe->tce_bypass_base + memblock_end_of_DRAM() - 1;
+ bypass = (dma_mask >= top);
+ }
+
+ if (bypass)
+ dev_info(&npdev->dev, "Using 64-bit DMA iommu bypass\n");
+ else
+ dev_info(&npdev->dev, "Using 32-bit DMA via iommu\n");
+
+ pnv_npu_dma_set_bypass(npe, bypass);
+ *npdev->dev.dma_mask = dma_mask;
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/powernv/opal-kmsg.c b/arch/powerpc/platforms/powernv/opal-kmsg.c
new file mode 100644
index 000000000000..6f1214d4de92
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-kmsg.c
@@ -0,0 +1,75 @@
+/*
+ * kmsg dumper that ensures the OPAL console fully flushes panic messages
+ *
+ * Author: Russell Currey <ruscur@russell.cc>
+ *
+ * Copyright 2015 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/kmsg_dump.h>
+
+#include <asm/opal.h>
+#include <asm/opal-api.h>
+
+/*
+ * Console output is controlled by OPAL firmware. The kernel regularly calls
+ * OPAL_POLL_EVENTS, which flushes some console output. In a panic state,
+ * however, the kernel no longer calls OPAL_POLL_EVENTS and the panic message
+ * may not be completely printed. This function does not actually dump the
+ * message, it just ensures that OPAL completely flushes the console buffer.
+ */
+static void force_opal_console_flush(struct kmsg_dumper *dumper,
+ enum kmsg_dump_reason reason)
+{
+ int i;
+ int64_t ret;
+
+ /*
+ * Outside of a panic context the pollers will continue to run,
+ * so we don't need to do any special flushing.
+ */
+ if (reason != KMSG_DUMP_PANIC)
+ return;
+
+ if (opal_check_token(OPAL_CONSOLE_FLUSH)) {
+ ret = opal_console_flush(0);
+
+ if (ret == OPAL_UNSUPPORTED || ret == OPAL_PARAMETER)
+ return;
+
+ /* Incrementally flush until there's nothing left */
+ while (opal_console_flush(0) != OPAL_SUCCESS);
+ } else {
+ /*
+ * If OPAL_CONSOLE_FLUSH is not implemented in the firmware,
+ * the console can still be flushed by calling the polling
+ * function enough times to flush the buffer. We don't know
+ * how much output still needs to be flushed, but we can be
+ * generous since the kernel is in panic and doesn't need
+ * to do much else.
+ */
+ printk(KERN_NOTICE "opal: OPAL_CONSOLE_FLUSH missing.\n");
+ for (i = 0; i < 1024; i++) {
+ opal_poll_events(NULL);
+ }
+ }
+}
+
+static struct kmsg_dumper opal_kmsg_dumper = {
+ .dump = force_opal_console_flush
+};
+
+void __init opal_kmsg_init(void)
+{
+ int rc;
+
+ /* Add our dumper to the list */
+ rc = kmsg_dump_register(&opal_kmsg_dumper);
+ if (rc != 0)
+ pr_err("opal: kmsg_dump_register failed; returned %d\n", rc);
+}
diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c
index 4ece8e40dd54..e315e704cca7 100644
--- a/arch/powerpc/platforms/powernv/opal-prd.c
+++ b/arch/powerpc/platforms/powernv/opal-prd.c
@@ -434,7 +434,6 @@ static const struct of_device_id opal_prd_match[] = {
static struct platform_driver opal_prd_driver = {
.driver = {
.name = "opal-prd",
- .owner = THIS_MODULE,
.of_match_table = opal_prd_match,
},
.probe = opal_prd_probe,
diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c
index 37dbee15769f..f8868864f373 100644
--- a/arch/powerpc/platforms/powernv/opal-rtc.c
+++ b/arch/powerpc/platforms/powernv/opal-rtc.c
@@ -31,8 +31,7 @@ static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm)
tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff);
tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff);
tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff);
-
- GregorianDay(tm);
+ tm->tm_wday = -1;
}
unsigned long __init opal_get_boot_time(void)
@@ -51,7 +50,7 @@ unsigned long __init opal_get_boot_time(void)
rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
if (rc == OPAL_BUSY_EVENT)
opal_poll_events(NULL);
- else
+ else if (rc == OPAL_BUSY)
mdelay(10);
}
if (rc != OPAL_SUCCESS)
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index b7a464fef7a7..e45b88a5d7e0 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -301,3 +301,4 @@ OPAL_CALL(opal_flash_erase, OPAL_FLASH_ERASE);
OPAL_CALL(opal_prd_msg, OPAL_PRD_MSG);
OPAL_CALL(opal_leds_get_ind, OPAL_LEDS_GET_INDICATOR);
OPAL_CALL(opal_leds_set_ind, OPAL_LEDS_SET_INDICATOR);
+OPAL_CALL(opal_console_flush, OPAL_CONSOLE_FLUSH);
diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c
index 7634d1c62299..d0ac535cf5d7 100644
--- a/arch/powerpc/platforms/powernv/opal-xscom.c
+++ b/arch/powerpc/platforms/powernv/opal-xscom.c
@@ -126,7 +126,7 @@ static const struct scom_controller opal_scom_controller = {
static int opal_xscom_init(void)
{
- if (firmware_has_feature(FW_FEATURE_OPALv3))
+ if (firmware_has_feature(FW_FEATURE_OPAL))
scom_init(&opal_scom_controller);
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 57cffb80bc36..4e0da5af94a1 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -98,16 +98,11 @@ int __init early_init_dt_scan_opal(unsigned long node,
pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n",
opal.size, sizep, runtimesz);
- powerpc_firmware_features |= FW_FEATURE_OPAL;
if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
- powerpc_firmware_features |= FW_FEATURE_OPALv2;
- powerpc_firmware_features |= FW_FEATURE_OPALv3;
- pr_info("OPAL V3 detected !\n");
- } else if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) {
- powerpc_firmware_features |= FW_FEATURE_OPALv2;
- pr_info("OPAL V2 detected !\n");
+ powerpc_firmware_features |= FW_FEATURE_OPAL;
+ pr_info("OPAL detected !\n");
} else {
- pr_info("OPAL V1 detected !\n");
+ panic("OPAL != V3 detected, no longer supported.\n");
}
/* Reinit all cores with the right endian */
@@ -352,17 +347,15 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
* enough room and be done with it
*/
spin_lock_irqsave(&opal_write_lock, flags);
- if (firmware_has_feature(FW_FEATURE_OPALv2)) {
- rc = opal_console_write_buffer_space(vtermno, &olen);
- len = be64_to_cpu(olen);
- if (rc || len < total_len) {
- spin_unlock_irqrestore(&opal_write_lock, flags);
- /* Closed -> drop characters */
- if (rc)
- return total_len;
- opal_poll_events(NULL);
- return -EAGAIN;
- }
+ rc = opal_console_write_buffer_space(vtermno, &olen);
+ len = be64_to_cpu(olen);
+ if (rc || len < total_len) {
+ spin_unlock_irqrestore(&opal_write_lock, flags);
+ /* Closed -> drop characters */
+ if (rc)
+ return total_len;
+ opal_poll_events(NULL);
+ return -EAGAIN;
}
/* We still try to handle partial completions, though they
@@ -555,7 +548,7 @@ bool opal_mce_check_early_recovery(struct pt_regs *regs)
goto out;
if ((regs->nip >= opal.base) &&
- (regs->nip <= (opal.base + opal.size)))
+ (regs->nip < (opal.base + opal.size)))
recover_addr = find_recovery_address(regs->nip);
/*
@@ -696,10 +689,7 @@ static int __init opal_init(void)
}
/* Register OPAL consoles if any ports */
- if (firmware_has_feature(FW_FEATURE_OPALv2))
- consoles = of_find_node_by_path("/ibm,opal/consoles");
- else
- consoles = of_node_get(opal_node);
+ consoles = of_find_node_by_path("/ibm,opal/consoles");
if (consoles) {
for_each_child_of_node(consoles, np) {
if (strcmp(np->name, "serial"))
@@ -758,6 +748,9 @@ static int __init opal_init(void)
opal_pdev_init(opal_node, "ibm,opal-flash");
opal_pdev_init(opal_node, "ibm,opal-prd");
+ /* Initialise OPAL kmsg dumper for flushing console on panic */
+ opal_kmsg_init();
+
return 0;
}
machine_subsys_initcall(powernv, opal_init);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 414fd1a00fda..573ae1994097 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -116,16 +116,6 @@ static int __init iommu_setup(char *str)
}
early_param("iommu", iommu_setup);
-/*
- * stdcix is only supposed to be used in hypervisor real mode as per
- * the architecture spec
- */
-static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
-{
- __asm__ __volatile__("stdcix %0,0,%1"
- : : "r" (val), "r" (paddr) : "memory");
-}
-
static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)
{
return ((flags & (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) ==
@@ -344,7 +334,7 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
return;
}
- if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
+ if (!firmware_has_feature(FW_FEATURE_OPAL)) {
pr_info(" Firmware too old to support M64 window\n");
return;
}
@@ -357,6 +347,7 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
}
res = &hose->mem_resources[1];
+ res->name = dn->full_name;
res->start = of_translate_address(dn, r + 2);
res->end = res->start + of_read_number(r + 4, 2) - 1;
res->flags = (IORESOURCE_MEM | IORESOURCE_MEM_64 | IORESOURCE_PREFETCH);
@@ -780,8 +771,12 @@ static int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
return -ENXIO;
}
- /* Configure PELTV */
- pnv_ioda_set_peltv(phb, pe, true);
+ /*
+ * Configure PELTV. NPUs don't have a PELTV table so skip
+ * configuration on them.
+ */
+ if (phb->type != PNV_PHB_NPU)
+ pnv_ioda_set_peltv(phb, pe, true);
/* Setup reverse map */
for (rid = pe->rid; rid < rid_end; rid++)
@@ -924,7 +919,6 @@ static int pnv_pci_vf_resource_shift(struct pci_dev *dev, int offset)
}
#endif /* CONFIG_PCI_IOV */
-#if 0
static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -941,11 +935,7 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
if (pdn->pe_number != IODA_INVALID_PE)
return NULL;
- /* PE#0 has been pre-set */
- if (dev->bus->number == 0)
- pe_num = 0;
- else
- pe_num = pnv_ioda_alloc_pe(phb);
+ pe_num = pnv_ioda_alloc_pe(phb);
if (pe_num == IODA_INVALID_PE) {
pr_warning("%s: Not enough PE# available, disabling device\n",
pci_name(dev));
@@ -963,6 +953,7 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
pci_dev_get(dev);
pdn->pcidev = dev;
pdn->pe_number = pe_num;
+ pe->flags = PNV_IODA_PE_DEV;
pe->pdev = dev;
pe->pbus = NULL;
pe->tce32_seg = -1;
@@ -993,7 +984,6 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
return pe;
}
-#endif /* Useful for SRIOV case */
static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
{
@@ -1007,6 +997,7 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
pci_name(dev));
continue;
}
+ pdn->pcidev = dev;
pdn->pe_number = pe->pe_number;
pe->dma_weight += pnv_ioda_dma_weight(dev);
if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
@@ -1083,6 +1074,77 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)
pnv_ioda_link_pe_by_weight(phb, pe);
}
+static struct pnv_ioda_pe *pnv_ioda_setup_npu_PE(struct pci_dev *npu_pdev)
+{
+ int pe_num, found_pe = false, rc;
+ long rid;
+ struct pnv_ioda_pe *pe;
+ struct pci_dev *gpu_pdev;
+ struct pci_dn *npu_pdn;
+ struct pci_controller *hose = pci_bus_to_host(npu_pdev->bus);
+ struct pnv_phb *phb = hose->private_data;
+
+ /*
+ * Due to a hardware errata PE#0 on the NPU is reserved for
+ * error handling. This means we only have three PEs remaining
+ * which need to be assigned to four links, implying some
+ * links must share PEs.
+ *
+ * To achieve this we assign PEs such that NPUs linking the
+ * same GPU get assigned the same PE.
+ */
+ gpu_pdev = pnv_pci_get_gpu_dev(npu_pdev);
+ for (pe_num = 0; pe_num < phb->ioda.total_pe; pe_num++) {
+ pe = &phb->ioda.pe_array[pe_num];
+ if (!pe->pdev)
+ continue;
+
+ if (pnv_pci_get_gpu_dev(pe->pdev) == gpu_pdev) {
+ /*
+ * This device has the same peer GPU so should
+ * be assigned the same PE as the existing
+ * peer NPU.
+ */
+ dev_info(&npu_pdev->dev,
+ "Associating to existing PE %d\n", pe_num);
+ pci_dev_get(npu_pdev);
+ npu_pdn = pci_get_pdn(npu_pdev);
+ rid = npu_pdev->bus->number << 8 | npu_pdn->devfn;
+ npu_pdn->pcidev = npu_pdev;
+ npu_pdn->pe_number = pe_num;
+ pe->dma_weight += pnv_ioda_dma_weight(npu_pdev);
+ phb->ioda.pe_rmap[rid] = pe->pe_number;
+
+ /* Map the PE to this link */
+ rc = opal_pci_set_pe(phb->opal_id, pe_num, rid,
+ OpalPciBusAll,
+ OPAL_COMPARE_RID_DEVICE_NUMBER,
+ OPAL_COMPARE_RID_FUNCTION_NUMBER,
+ OPAL_MAP_PE);
+ WARN_ON(rc != OPAL_SUCCESS);
+ found_pe = true;
+ break;
+ }
+ }
+
+ if (!found_pe)
+ /*
+ * Could not find an existing PE so allocate a new
+ * one.
+ */
+ return pnv_ioda_setup_dev_PE(npu_pdev);
+ else
+ return pe;
+}
+
+static void pnv_ioda_setup_npu_PEs(struct pci_bus *bus)
+{
+ struct pci_dev *pdev;
+
+ list_for_each_entry(pdev, &bus->devices, bus_list)
+ pnv_ioda_setup_npu_PE(pdev);
+}
+
static void pnv_ioda_setup_PEs(struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -1119,7 +1181,17 @@ static void pnv_pci_ioda_setup_PEs(void)
if (phb->reserve_m64_pe)
phb->reserve_m64_pe(hose->bus, NULL, true);
- pnv_ioda_setup_PEs(hose->bus);
+ /*
+ * On NPU PHB, we expect separate PEs for individual PCI
+ * functions. PCI bus dependent PEs are required for the
+ * remaining types of PHBs.
+ */
+ if (phb->type == PNV_PHB_NPU) {
+ /* PE#0 is needed for error reporting */
+ pnv_ioda_reserve_pe(phb, 0);
+ pnv_ioda_setup_npu_PEs(hose->bus);
+ } else
+ pnv_ioda_setup_PEs(hose->bus);
}
}
@@ -1578,6 +1650,8 @@ static int pnv_pci_ioda_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
struct pnv_ioda_pe *pe;
uint64_t top;
bool bypass = false;
+ struct pci_dev *linked_npu_dev;
+ int i;
if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
return -ENODEV;;
@@ -1596,6 +1670,18 @@ static int pnv_pci_ioda_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
set_dma_ops(&pdev->dev, &dma_iommu_ops);
}
*pdev->dev.dma_mask = dma_mask;
+
+ /* Update peer npu devices */
+ if (pe->flags & PNV_IODA_PE_PEER)
+ for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+ if (!pe->peers[i])
+ continue;
+
+ linked_npu_dev = pe->peers[i]->pdev;
+ if (dma_get_mask(&linked_npu_dev->dev) != dma_mask)
+ dma_set_mask(&linked_npu_dev->dev, dma_mask);
+ }
+
return 0;
}
@@ -1740,12 +1826,23 @@ static inline void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_ioda_pe *pe)
/* 01xb - invalidate TCEs that match the specified PE# */
unsigned long val = (0x4ull << 60) | (pe->pe_number & 0xFF);
struct pnv_phb *phb = pe->phb;
+ struct pnv_ioda_pe *npe;
+ int i;
if (!phb->ioda.tce_inval_reg)
return;
mb(); /* Ensure above stores are visible */
__raw_writeq(cpu_to_be64(val), phb->ioda.tce_inval_reg);
+
+ if (pe->flags & PNV_IODA_PE_PEER)
+ for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+ npe = pe->peers[i];
+ if (!npe || npe->phb->type != PNV_PHB_NPU)
+ continue;
+
+ pnv_npu_tce_invalidate_entire(npe);
+ }
}
static void pnv_pci_ioda2_do_tce_invalidate(unsigned pe_number, bool rm,
@@ -1780,15 +1877,28 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
struct iommu_table_group_link *tgl;
list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
+ struct pnv_ioda_pe *npe;
struct pnv_ioda_pe *pe = container_of(tgl->table_group,
struct pnv_ioda_pe, table_group);
__be64 __iomem *invalidate = rm ?
(__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
pe->phb->ioda.tce_inval_reg;
+ int i;
pnv_pci_ioda2_do_tce_invalidate(pe->pe_number, rm,
invalidate, tbl->it_page_shift,
index, npages);
+
+ if (pe->flags & PNV_IODA_PE_PEER)
+ /* Invalidate PEs using the same TCE table */
+ for (i = 0; i < PNV_IODA_MAX_PEER_PES; i++) {
+ npe = pe->peers[i];
+ if (!npe || npe->phb->type != PNV_PHB_NPU)
+ continue;
+
+ pnv_npu_tce_invalidate(npe, tbl, index,
+ npages, rm);
+ }
}
}
@@ -2436,10 +2546,17 @@ static void pnv_ioda_setup_dma(struct pnv_phb *phb)
pe_info(pe, "DMA weight %d, assigned %d DMA32 segments\n",
pe->dma_weight, segs);
pnv_pci_ioda_setup_dma_pe(phb, pe, base, segs);
- } else {
+ } else if (phb->type == PNV_PHB_IODA2) {
pe_info(pe, "Assign DMA32 space\n");
segs = 0;
pnv_pci_ioda2_setup_dma_pe(phb, pe);
+ } else if (phb->type == PNV_PHB_NPU) {
+ /*
+ * We initialise the DMA space for an NPU PHB
+ * after setup of the PHB is complete as we
+ * point the NPU TVT to the the same location
+ * as the PHB3 TVT.
+ */
}
remaining -= segs;
@@ -2881,6 +2998,11 @@ static void pnv_pci_ioda_setup_seg(void)
list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
phb = hose->private_data;
+
+ /* NPU PHB does not support IO or MMIO segmentation */
+ if (phb->type == PNV_PHB_NPU)
+ continue;
+
list_for_each_entry(pe, &phb->ioda.pe_list, list) {
pnv_ioda_setup_pe_seg(hose, pe);
}
@@ -2920,6 +3042,27 @@ static void pnv_pci_ioda_create_dbgfs(void)
#endif /* CONFIG_DEBUG_FS */
}
+static void pnv_npu_ioda_fixup(void)
+{
+ bool enable_bypass;
+ struct pci_controller *hose, *tmp;
+ struct pnv_phb *phb;
+ struct pnv_ioda_pe *pe;
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+ phb = hose->private_data;
+ if (phb->type != PNV_PHB_NPU)
+ continue;
+
+ list_for_each_entry(pe, &phb->ioda.pe_dma_list, dma_link) {
+ enable_bypass = dma_get_mask(&pe->pdev->dev) ==
+ DMA_BIT_MASK(64);
+ pnv_npu_init_dma_pe(pe);
+ pnv_npu_dma_set_bypass(pe, enable_bypass);
+ }
+ }
+}
+
static void pnv_pci_ioda_fixup(void)
{
pnv_pci_ioda_setup_PEs();
@@ -2932,6 +3075,9 @@ static void pnv_pci_ioda_fixup(void)
eeh_init();
eeh_addr_cache_build();
#endif
+
+ /* Link NPU IODA tables to their PCI devices. */
+ pnv_npu_ioda_fixup();
}
/*
@@ -3046,6 +3192,19 @@ static const struct pci_controller_ops pnv_pci_ioda_controller_ops = {
.shutdown = pnv_pci_ioda_shutdown,
};
+static const struct pci_controller_ops pnv_npu_ioda_controller_ops = {
+ .dma_dev_setup = pnv_pci_dma_dev_setup,
+#ifdef CONFIG_PCI_MSI
+ .setup_msi_irqs = pnv_setup_msi_irqs,
+ .teardown_msi_irqs = pnv_teardown_msi_irqs,
+#endif
+ .enable_device_hook = pnv_pci_enable_device_hook,
+ .window_alignment = pnv_pci_window_alignment,
+ .reset_secondary_bus = pnv_pci_reset_secondary_bus,
+ .dma_set_mask = pnv_npu_dma_set_mask,
+ .shutdown = pnv_pci_ioda_shutdown,
+};
+
static void __init pnv_pci_init_ioda_phb(struct device_node *np,
u64 hub_id, int ioda_type)
{
@@ -3101,6 +3260,8 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
phb->model = PNV_PHB_MODEL_P7IOC;
else if (of_device_is_compatible(np, "ibm,power8-pciex"))
phb->model = PNV_PHB_MODEL_PHB3;
+ else if (of_device_is_compatible(np, "ibm,power8-npu-pciex"))
+ phb->model = PNV_PHB_MODEL_NPU;
else
phb->model = PNV_PHB_MODEL_UNKNOWN;
@@ -3201,7 +3362,11 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
* the child P2P bridges) can form individual PE.
*/
ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
- hose->controller_ops = pnv_pci_ioda_controller_ops;
+
+ if (phb->type == PNV_PHB_NPU)
+ hose->controller_ops = pnv_npu_ioda_controller_ops;
+ else
+ hose->controller_ops = pnv_pci_ioda_controller_ops;
#ifdef CONFIG_PCI_IOV
ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;
@@ -3236,6 +3401,11 @@ void __init pnv_pci_init_ioda2_phb(struct device_node *np)
pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2);
}
+void __init pnv_pci_init_npu_phb(struct device_node *np)
+{
+ pnv_pci_init_ioda_phb(np, 0, PNV_PHB_NPU);
+}
+
void __init pnv_pci_init_ioda_hub(struct device_node *np)
{
struct device_node *phbn;
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index f2dd77234240..2f55c86df703 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -1,8 +1,6 @@
/*
* Support PCI/PCIe on PowerNV platforms
*
- * Currently supports only P5IOC2
- *
* Copyright 2011 Benjamin Herrenschmidt, IBM Corp.
*
* This program is free software; you can redistribute it and/or
@@ -807,6 +805,10 @@ void __init pnv_pci_init(void)
for_each_compatible_node(np, NULL, "ibm,ioda2-phb")
pnv_pci_init_ioda2_phb(np);
+ /* Look for NPU PHBs */
+ for_each_compatible_node(np, NULL, "ibm,ioda2-npu-phb")
+ pnv_pci_init_npu_phb(np);
+
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index c8ff50e90766..7f56313e8d72 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -7,6 +7,7 @@ enum pnv_phb_type {
PNV_PHB_P5IOC2 = 0,
PNV_PHB_IODA1 = 1,
PNV_PHB_IODA2 = 2,
+ PNV_PHB_NPU = 3,
};
/* Precise PHB model for error management */
@@ -15,6 +16,7 @@ enum pnv_phb_model {
PNV_PHB_MODEL_P5IOC2,
PNV_PHB_MODEL_P7IOC,
PNV_PHB_MODEL_PHB3,
+ PNV_PHB_MODEL_NPU,
};
#define PNV_PCI_DIAG_BUF_SIZE 8192
@@ -24,6 +26,7 @@ enum pnv_phb_model {
#define PNV_IODA_PE_MASTER (1 << 3) /* Master PE in compound case */
#define PNV_IODA_PE_SLAVE (1 << 4) /* Slave PE in compound case */
#define PNV_IODA_PE_VF (1 << 5) /* PE for one VF */
+#define PNV_IODA_PE_PEER (1 << 6) /* PE has peers */
/* Data associated with a PE, including IOMMU tracking etc.. */
struct pnv_phb;
@@ -31,6 +34,9 @@ struct pnv_ioda_pe {
unsigned long flags;
struct pnv_phb *phb;
+#define PNV_IODA_MAX_PEER_PES 8
+ struct pnv_ioda_pe *peers[PNV_IODA_MAX_PEER_PES];
+
/* A PE can be associated with a single device or an
* entire bus (& children). In the former case, pdev
* is populated, in the later case, pbus is.
@@ -229,6 +235,7 @@ extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
extern void pnv_pci_init_p5ioc2_hub(struct device_node *np);
extern void pnv_pci_init_ioda_hub(struct device_node *np);
extern void pnv_pci_init_ioda2_phb(struct device_node *np);
+extern void pnv_pci_init_npu_phb(struct device_node *np);
extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
__be64 *startp, __be64 *endp, bool rm);
extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
@@ -238,4 +245,16 @@ extern void pnv_pci_dma_dev_setup(struct pci_dev *pdev);
extern int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type);
extern void pnv_teardown_msi_irqs(struct pci_dev *pdev);
+/* Nvlink functions */
+extern void pnv_npu_tce_invalidate_entire(struct pnv_ioda_pe *npe);
+extern void pnv_npu_tce_invalidate(struct pnv_ioda_pe *npe,
+ struct iommu_table *tbl,
+ unsigned long index,
+ unsigned long npages,
+ bool rm);
+extern void pnv_npu_init_dma_pe(struct pnv_ioda_pe *npe);
+extern void pnv_npu_setup_dma_pe(struct pnv_ioda_pe *npe);
+extern int pnv_npu_dma_set_bypass(struct pnv_ioda_pe *npe, bool enabled);
+extern int pnv_npu_dma_set_mask(struct pci_dev *npdev, u64 dma_mask);
+
#endif /* __POWERNV_PCI_H */
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index a9a8fa37a555..1acb0c72d923 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -90,12 +90,8 @@ static void pnv_show_cpuinfo(struct seq_file *m)
if (root)
model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: PowerNV %s\n", model);
- if (firmware_has_feature(FW_FEATURE_OPALv3))
- seq_printf(m, "firmware\t: OPAL v3\n");
- else if (firmware_has_feature(FW_FEATURE_OPALv2))
- seq_printf(m, "firmware\t: OPAL v2\n");
- else if (firmware_has_feature(FW_FEATURE_OPAL))
- seq_printf(m, "firmware\t: OPAL v1\n");
+ if (firmware_has_feature(FW_FEATURE_OPAL))
+ seq_printf(m, "firmware\t: OPAL\n");
else
seq_printf(m, "firmware\t: BML\n");
of_node_put(root);
@@ -224,9 +220,9 @@ static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
{
xics_kexec_teardown_cpu(secondary);
- /* On OPAL v3, we return all CPUs to firmware */
+ /* On OPAL, we return all CPUs to firmware */
- if (!firmware_has_feature(FW_FEATURE_OPALv3))
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
return;
if (secondary) {
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index ca264833ee64..ad7b1a3dbed0 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -61,14 +61,15 @@ static int pnv_smp_kick_cpu(int nr)
unsigned long start_here =
__pa(ppc_function_entry(generic_secondary_smp_init));
long rc;
+ uint8_t status;
BUG_ON(nr < 0 || nr >= NR_CPUS);
/*
- * If we already started or OPALv2 is not supported, we just
+ * If we already started or OPAL is not supported, we just
* kick the CPU via the PACA
*/
- if (paca[nr].cpu_start || !firmware_has_feature(FW_FEATURE_OPALv2))
+ if (paca[nr].cpu_start || !firmware_has_feature(FW_FEATURE_OPAL))
goto kick;
/*
@@ -77,55 +78,42 @@ static int pnv_smp_kick_cpu(int nr)
* first time. OPAL v3 allows us to query OPAL to know if it
* has the CPUs, so we do that
*/
- if (firmware_has_feature(FW_FEATURE_OPALv3)) {
- uint8_t status;
-
- rc = opal_query_cpu_status(pcpu, &status);
- if (rc != OPAL_SUCCESS) {
- pr_warn("OPAL Error %ld querying CPU %d state\n",
- rc, nr);
- return -ENODEV;
- }
+ rc = opal_query_cpu_status(pcpu, &status);
+ if (rc != OPAL_SUCCESS) {
+ pr_warn("OPAL Error %ld querying CPU %d state\n", rc, nr);
+ return -ENODEV;
+ }
- /*
- * Already started, just kick it, probably coming from
- * kexec and spinning
- */
- if (status == OPAL_THREAD_STARTED)
- goto kick;
+ /*
+ * Already started, just kick it, probably coming from
+ * kexec and spinning
+ */
+ if (status == OPAL_THREAD_STARTED)
+ goto kick;
- /*
- * Available/inactive, let's kick it
- */
- if (status == OPAL_THREAD_INACTIVE) {
- pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n",
- nr, pcpu);
- rc = opal_start_cpu(pcpu, start_here);
- if (rc != OPAL_SUCCESS) {
- pr_warn("OPAL Error %ld starting CPU %d\n",
- rc, nr);
- return -ENODEV;
- }
- } else {
- /*
- * An unavailable CPU (or any other unknown status)
- * shouldn't be started. It should also
- * not be in the possible map but currently it can
- * happen
- */
- pr_devel("OPAL: CPU %d (HW 0x%x) is unavailable"
- " (status %d)...\n", nr, pcpu, status);
+ /*
+ * Available/inactive, let's kick it
+ */
+ if (status == OPAL_THREAD_INACTIVE) {
+ pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n", nr, pcpu);
+ rc = opal_start_cpu(pcpu, start_here);
+ if (rc != OPAL_SUCCESS) {
+ pr_warn("OPAL Error %ld starting CPU %d\n", rc, nr);
return -ENODEV;
}
} else {
/*
- * On OPAL v2, we just kick it and hope for the best,
- * we must not test the error from opal_start_cpu() or
- * we would fail to get CPUs from kexec.
+ * An unavailable CPU (or any other unknown status)
+ * shouldn't be started. It should also
+ * not be in the possible map but currently it can
+ * happen
*/
- opal_start_cpu(pcpu, start_here);
+ pr_devel("OPAL: CPU %d (HW 0x%x) is unavailable"
+ " (status %d)...\n", nr, pcpu, status);
+ return -ENODEV;
}
- kick:
+
+kick:
return smp_generic_kick_cpu(nr);
}
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index f244dcb4f2cf..2b93ae8d557a 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -20,7 +20,6 @@
#include <linux/of.h>
#include "of_helpers.h"
-#include "offline_states.h"
#include "pseries.h"
#include <asm/prom.h>
@@ -338,185 +337,6 @@ int dlpar_release_drc(u32 drc_index)
return 0;
}
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-
-static int dlpar_online_cpu(struct device_node *dn)
-{
- int rc = 0;
- unsigned int cpu;
- int len, nthreads, i;
- const __be32 *intserv;
- u32 thread;
-
- intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
- if (!intserv)
- return -EINVAL;
-
- nthreads = len / sizeof(u32);
-
- cpu_maps_update_begin();
- for (i = 0; i < nthreads; i++) {
- thread = be32_to_cpu(intserv[i]);
- for_each_present_cpu(cpu) {
- if (get_hard_smp_processor_id(cpu) != thread)
- continue;
- BUG_ON(get_cpu_current_state(cpu)
- != CPU_STATE_OFFLINE);
- cpu_maps_update_done();
- rc = device_online(get_cpu_device(cpu));
- if (rc)
- goto out;
- cpu_maps_update_begin();
-
- break;
- }
- if (cpu == num_possible_cpus())
- printk(KERN_WARNING "Could not find cpu to online "
- "with physical id 0x%x\n", thread);
- }
- cpu_maps_update_done();
-
-out:
- return rc;
-
-}
-
-static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
-{
- struct device_node *dn, *parent;
- u32 drc_index;
- int rc;
-
- rc = kstrtou32(buf, 0, &drc_index);
- if (rc)
- return -EINVAL;
-
- rc = dlpar_acquire_drc(drc_index);
- if (rc)
- return -EINVAL;
-
- parent = of_find_node_by_path("/cpus");
- if (!parent)
- return -ENODEV;
-
- dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
- of_node_put(parent);
- if (!dn) {
- dlpar_release_drc(drc_index);
- return -EINVAL;
- }
-
- rc = dlpar_attach_node(dn);
- if (rc) {
- dlpar_release_drc(drc_index);
- dlpar_free_cc_nodes(dn);
- return rc;
- }
-
- rc = dlpar_online_cpu(dn);
- if (rc)
- return rc;
-
- return count;
-}
-
-static int dlpar_offline_cpu(struct device_node *dn)
-{
- int rc = 0;
- unsigned int cpu;
- int len, nthreads, i;
- const __be32 *intserv;
- u32 thread;
-
- intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
- if (!intserv)
- return -EINVAL;
-
- nthreads = len / sizeof(u32);
-
- cpu_maps_update_begin();
- for (i = 0; i < nthreads; i++) {
- thread = be32_to_cpu(intserv[i]);
- for_each_present_cpu(cpu) {
- if (get_hard_smp_processor_id(cpu) != thread)
- continue;
-
- if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
- break;
-
- if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
- set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
- cpu_maps_update_done();
- rc = device_offline(get_cpu_device(cpu));
- if (rc)
- goto out;
- cpu_maps_update_begin();
- break;
-
- }
-
- /*
- * The cpu is in CPU_STATE_INACTIVE.
- * Upgrade it's state to CPU_STATE_OFFLINE.
- */
- set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
- BUG_ON(plpar_hcall_norets(H_PROD, thread)
- != H_SUCCESS);
- __cpu_die(cpu);
- break;
- }
- if (cpu == num_possible_cpus())
- printk(KERN_WARNING "Could not find cpu to offline "
- "with physical id 0x%x\n", thread);
- }
- cpu_maps_update_done();
-
-out:
- return rc;
-
-}
-
-static ssize_t dlpar_cpu_release(const char *buf, size_t count)
-{
- struct device_node *dn;
- u32 drc_index;
- int rc;
-
- dn = of_find_node_by_path(buf);
- if (!dn)
- return -EINVAL;
-
- rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
- if (rc) {
- of_node_put(dn);
- return -EINVAL;
- }
-
- rc = dlpar_offline_cpu(dn);
- if (rc) {
- of_node_put(dn);
- return -EINVAL;
- }
-
- rc = dlpar_release_drc(drc_index);
- if (rc) {
- of_node_put(dn);
- return rc;
- }
-
- rc = dlpar_detach_node(dn);
- if (rc) {
- dlpar_acquire_drc(drc_index);
- return rc;
- }
-
- of_node_put(dn);
-
- return count;
-}
-
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
-
static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
{
int rc;
@@ -536,6 +356,9 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
case PSERIES_HP_ELOG_RESOURCE_MEM:
rc = dlpar_memory(hp_elog);
break;
+ case PSERIES_HP_ELOG_RESOURCE_CPU:
+ rc = dlpar_cpu(hp_elog);
+ break;
default:
pr_warn_ratelimited("Invalid resource (%d) specified\n",
hp_elog->resource);
@@ -565,6 +388,9 @@ static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
if (!strncmp(arg, "memory", 6)) {
hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
arg += strlen("memory ");
+ } else if (!strncmp(arg, "cpu", 3)) {
+ hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
+ arg += strlen("cpu ");
} else {
pr_err("Invalid resource specified: \"%s\"\n", buf);
rc = -EINVAL;
@@ -624,16 +450,7 @@ static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
static int __init pseries_dlpar_init(void)
{
- int rc;
-
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
- ppc_md.cpu_probe = dlpar_cpu_probe;
- ppc_md.cpu_release = dlpar_cpu_release;
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
-
- rc = sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
-
- return rc;
+ return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
}
machine_device_initcall(pseries, pseries_dlpar_init);
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 62475440fd45..32274f72fe3f 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -18,12 +18,15 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) "pseries-hotplug-cpu: " fmt
+
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/sched.h> /* for idle_task_exit */
#include <linux/cpu.h>
#include <linux/of.h>
+#include <linux/slab.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/firmware.h>
@@ -32,6 +35,7 @@
#include <asm/xics.h>
#include <asm/plpar_wrappers.h>
+#include "pseries.h"
#include "offline_states.h"
/* This version can't take the spinlock, because it never returns */
@@ -88,13 +92,7 @@ void set_default_offline_state(int cpu)
static void rtas_stop_self(void)
{
- static struct rtas_args args = {
- .nargs = 0,
- .nret = cpu_to_be32(1),
- .rets = &args.args[0],
- };
-
- args.token = cpu_to_be32(rtas_stop_self_token);
+ static struct rtas_args args;
local_irq_disable();
@@ -102,7 +100,8 @@ static void rtas_stop_self(void)
printk("cpu %u (hwid %u) Ready to die...\n",
smp_processor_id(), hard_smp_processor_id());
- enter_rtas(__pa(&args));
+
+ rtas_call_unlocked(&args, rtas_stop_self_token, 0, 1, NULL);
panic("Alas, I survived.\n");
}
@@ -339,6 +338,536 @@ static void pseries_remove_processor(struct device_node *np)
cpu_maps_update_done();
}
+static int dlpar_online_cpu(struct device_node *dn)
+{
+ int rc = 0;
+ unsigned int cpu;
+ int len, nthreads, i;
+ const __be32 *intserv;
+ u32 thread;
+
+ intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+ if (!intserv)
+ return -EINVAL;
+
+ nthreads = len / sizeof(u32);
+
+ cpu_maps_update_begin();
+ for (i = 0; i < nthreads; i++) {
+ thread = be32_to_cpu(intserv[i]);
+ for_each_present_cpu(cpu) {
+ if (get_hard_smp_processor_id(cpu) != thread)
+ continue;
+ BUG_ON(get_cpu_current_state(cpu)
+ != CPU_STATE_OFFLINE);
+ cpu_maps_update_done();
+ rc = device_online(get_cpu_device(cpu));
+ if (rc)
+ goto out;
+ cpu_maps_update_begin();
+
+ break;
+ }
+ if (cpu == num_possible_cpus())
+ printk(KERN_WARNING "Could not find cpu to online "
+ "with physical id 0x%x\n", thread);
+ }
+ cpu_maps_update_done();
+
+out:
+ return rc;
+
+}
+
+static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
+{
+ struct device_node *child = NULL;
+ u32 my_drc_index;
+ bool found;
+ int rc;
+
+ /* Assume cpu doesn't exist */
+ found = false;
+
+ for_each_child_of_node(parent, child) {
+ rc = of_property_read_u32(child, "ibm,my-drc-index",
+ &my_drc_index);
+ if (rc)
+ continue;
+
+ if (my_drc_index == drc_index) {
+ of_node_put(child);
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
+{
+ bool found = false;
+ int rc, index;
+
+ index = 0;
+ while (!found) {
+ u32 drc;
+
+ rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
+ index++, &drc);
+ if (rc)
+ break;
+
+ if (drc == drc_index)
+ found = true;
+ }
+
+ return found;
+}
+
+static ssize_t dlpar_cpu_add(u32 drc_index)
+{
+ struct device_node *dn, *parent;
+ int rc, saved_rc;
+
+ pr_debug("Attempting to add CPU, drc index: %x\n", drc_index);
+
+ parent = of_find_node_by_path("/cpus");
+ if (!parent) {
+ pr_warn("Failed to find CPU root node \"/cpus\"\n");
+ return -ENODEV;
+ }
+
+ if (dlpar_cpu_exists(parent, drc_index)) {
+ of_node_put(parent);
+ pr_warn("CPU with drc index %x already exists\n", drc_index);
+ return -EINVAL;
+ }
+
+ if (!valid_cpu_drc_index(parent, drc_index)) {
+ of_node_put(parent);
+ pr_warn("Cannot find CPU (drc index %x) to add.\n", drc_index);
+ return -EINVAL;
+ }
+
+ rc = dlpar_acquire_drc(drc_index);
+ if (rc) {
+ pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n",
+ rc, drc_index);
+ of_node_put(parent);
+ return -EINVAL;
+ }
+
+ dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
+ of_node_put(parent);
+ if (!dn) {
+ pr_warn("Failed call to configure-connector, drc index: %x\n",
+ drc_index);
+ dlpar_release_drc(drc_index);
+ return -EINVAL;
+ }
+
+ rc = dlpar_attach_node(dn);
+ if (rc) {
+ saved_rc = rc;
+ pr_warn("Failed to attach node %s, rc: %d, drc index: %x\n",
+ dn->name, rc, drc_index);
+
+ rc = dlpar_release_drc(drc_index);
+ if (!rc)
+ dlpar_free_cc_nodes(dn);
+
+ return saved_rc;
+ }
+
+ rc = dlpar_online_cpu(dn);
+ if (rc) {
+ saved_rc = rc;
+ pr_warn("Failed to online cpu %s, rc: %d, drc index: %x\n",
+ dn->name, rc, drc_index);
+
+ rc = dlpar_detach_node(dn);
+ if (!rc)
+ dlpar_release_drc(drc_index);
+
+ return saved_rc;
+ }
+
+ pr_debug("Successfully added CPU %s, drc index: %x\n", dn->name,
+ drc_index);
+ return rc;
+}
+
+static int dlpar_offline_cpu(struct device_node *dn)
+{
+ int rc = 0;
+ unsigned int cpu;
+ int len, nthreads, i;
+ const __be32 *intserv;
+ u32 thread;
+
+ intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+ if (!intserv)
+ return -EINVAL;
+
+ nthreads = len / sizeof(u32);
+
+ cpu_maps_update_begin();
+ for (i = 0; i < nthreads; i++) {
+ thread = be32_to_cpu(intserv[i]);
+ for_each_present_cpu(cpu) {
+ if (get_hard_smp_processor_id(cpu) != thread)
+ continue;
+
+ if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
+ break;
+
+ if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
+ set_preferred_offline_state(cpu,
+ CPU_STATE_OFFLINE);
+ cpu_maps_update_done();
+ rc = device_offline(get_cpu_device(cpu));
+ if (rc)
+ goto out;
+ cpu_maps_update_begin();
+ break;
+
+ }
+
+ /*
+ * The cpu is in CPU_STATE_INACTIVE.
+ * Upgrade it's state to CPU_STATE_OFFLINE.
+ */
+ set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
+ BUG_ON(plpar_hcall_norets(H_PROD, thread)
+ != H_SUCCESS);
+ __cpu_die(cpu);
+ break;
+ }
+ if (cpu == num_possible_cpus())
+ printk(KERN_WARNING "Could not find cpu to offline with physical id 0x%x\n", thread);
+ }
+ cpu_maps_update_done();
+
+out:
+ return rc;
+
+}
+
+static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
+{
+ int rc;
+
+ pr_debug("Attemping to remove CPU %s, drc index: %x\n",
+ dn->name, drc_index);
+
+ rc = dlpar_offline_cpu(dn);
+ if (rc) {
+ pr_warn("Failed to offline CPU %s, rc: %d\n", dn->name, rc);
+ return -EINVAL;
+ }
+
+ rc = dlpar_release_drc(drc_index);
+ if (rc) {
+ pr_warn("Failed to release drc (%x) for CPU %s, rc: %d\n",
+ drc_index, dn->name, rc);
+ dlpar_online_cpu(dn);
+ return rc;
+ }
+
+ rc = dlpar_detach_node(dn);
+ if (rc) {
+ int saved_rc = rc;
+
+ pr_warn("Failed to detach CPU %s, rc: %d", dn->name, rc);
+
+ rc = dlpar_acquire_drc(drc_index);
+ if (!rc)
+ dlpar_online_cpu(dn);
+
+ return saved_rc;
+ }
+
+ pr_debug("Successfully removed CPU, drc index: %x\n", drc_index);
+ return 0;
+}
+
+static struct device_node *cpu_drc_index_to_dn(u32 drc_index)
+{
+ struct device_node *dn;
+ u32 my_index;
+ int rc;
+
+ for_each_node_by_type(dn, "cpu") {
+ rc = of_property_read_u32(dn, "ibm,my-drc-index", &my_index);
+ if (rc)
+ continue;
+
+ if (my_index == drc_index)
+ break;
+ }
+
+ return dn;
+}
+
+static int dlpar_cpu_remove_by_index(u32 drc_index)
+{
+ struct device_node *dn;
+ int rc;
+
+ dn = cpu_drc_index_to_dn(drc_index);
+ if (!dn) {
+ pr_warn("Cannot find CPU (drc index %x) to remove\n",
+ drc_index);
+ return -ENODEV;
+ }
+
+ rc = dlpar_cpu_remove(dn, drc_index);
+ of_node_put(dn);
+ return rc;
+}
+
+static int find_dlpar_cpus_to_remove(u32 *cpu_drcs, int cpus_to_remove)
+{
+ struct device_node *dn;
+ int cpus_found = 0;
+ int rc;
+
+ /* We want to find cpus_to_remove + 1 CPUs to ensure we do not
+ * remove the last CPU.
+ */
+ for_each_node_by_type(dn, "cpu") {
+ cpus_found++;
+
+ if (cpus_found > cpus_to_remove) {
+ of_node_put(dn);
+ break;
+ }
+
+ /* Note that cpus_found is always 1 ahead of the index
+ * into the cpu_drcs array, so we use cpus_found - 1
+ */
+ rc = of_property_read_u32(dn, "ibm,my-drc-index",
+ &cpu_drcs[cpus_found - 1]);
+ if (rc) {
+ pr_warn("Error occurred getting drc-index for %s\n",
+ dn->name);
+ of_node_put(dn);
+ return -1;
+ }
+ }
+
+ if (cpus_found < cpus_to_remove) {
+ pr_warn("Failed to find enough CPUs (%d of %d) to remove\n",
+ cpus_found, cpus_to_remove);
+ } else if (cpus_found == cpus_to_remove) {
+ pr_warn("Cannot remove all CPUs\n");
+ }
+
+ return cpus_found;
+}
+
+static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
+{
+ u32 *cpu_drcs;
+ int cpus_found;
+ int cpus_removed = 0;
+ int i, rc;
+
+ pr_debug("Attempting to hot-remove %d CPUs\n", cpus_to_remove);
+
+ cpu_drcs = kcalloc(cpus_to_remove, sizeof(*cpu_drcs), GFP_KERNEL);
+ if (!cpu_drcs)
+ return -EINVAL;
+
+ cpus_found = find_dlpar_cpus_to_remove(cpu_drcs, cpus_to_remove);
+ if (cpus_found <= cpus_to_remove) {
+ kfree(cpu_drcs);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < cpus_to_remove; i++) {
+ rc = dlpar_cpu_remove_by_index(cpu_drcs[i]);
+ if (rc)
+ break;
+
+ cpus_removed++;
+ }
+
+ if (cpus_removed != cpus_to_remove) {
+ pr_warn("CPU hot-remove failed, adding back removed CPUs\n");
+
+ for (i = 0; i < cpus_removed; i++)
+ dlpar_cpu_add(cpu_drcs[i]);
+
+ rc = -EINVAL;
+ } else {
+ rc = 0;
+ }
+
+ kfree(cpu_drcs);
+ return rc;
+}
+
+static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
+{
+ struct device_node *parent;
+ int cpus_found = 0;
+ int index, rc;
+
+ parent = of_find_node_by_path("/cpus");
+ if (!parent) {
+ pr_warn("Could not find CPU root node in device tree\n");
+ kfree(cpu_drcs);
+ return -1;
+ }
+
+ /* Search the ibm,drc-indexes array for possible CPU drcs to
+ * add. Note that the format of the ibm,drc-indexes array is
+ * the number of entries in the array followed by the array
+ * of drc values so we start looking at index = 1.
+ */
+ index = 1;
+ while (cpus_found < cpus_to_add) {
+ u32 drc;
+
+ rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
+ index++, &drc);
+ if (rc)
+ break;
+
+ if (dlpar_cpu_exists(parent, drc))
+ continue;
+
+ cpu_drcs[cpus_found++] = drc;
+ }
+
+ of_node_put(parent);
+ return cpus_found;
+}
+
+static int dlpar_cpu_add_by_count(u32 cpus_to_add)
+{
+ u32 *cpu_drcs;
+ int cpus_added = 0;
+ int cpus_found;
+ int i, rc;
+
+ pr_debug("Attempting to hot-add %d CPUs\n", cpus_to_add);
+
+ cpu_drcs = kcalloc(cpus_to_add, sizeof(*cpu_drcs), GFP_KERNEL);
+ if (!cpu_drcs)
+ return -EINVAL;
+
+ cpus_found = find_dlpar_cpus_to_add(cpu_drcs, cpus_to_add);
+ if (cpus_found < cpus_to_add) {
+ pr_warn("Failed to find enough CPUs (%d of %d) to add\n",
+ cpus_found, cpus_to_add);
+ kfree(cpu_drcs);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < cpus_to_add; i++) {
+ rc = dlpar_cpu_add(cpu_drcs[i]);
+ if (rc)
+ break;
+
+ cpus_added++;
+ }
+
+ if (cpus_added < cpus_to_add) {
+ pr_warn("CPU hot-add failed, removing any added CPUs\n");
+
+ for (i = 0; i < cpus_added; i++)
+ dlpar_cpu_remove_by_index(cpu_drcs[i]);
+
+ rc = -EINVAL;
+ } else {
+ rc = 0;
+ }
+
+ kfree(cpu_drcs);
+ return rc;
+}
+
+int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
+{
+ u32 count, drc_index;
+ int rc;
+
+ count = hp_elog->_drc_u.drc_count;
+ drc_index = hp_elog->_drc_u.drc_index;
+
+ lock_device_hotplug();
+
+ switch (hp_elog->action) {
+ case PSERIES_HP_ELOG_ACTION_REMOVE:
+ if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
+ rc = dlpar_cpu_remove_by_count(count);
+ else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
+ rc = dlpar_cpu_remove_by_index(drc_index);
+ else
+ rc = -EINVAL;
+ break;
+ case PSERIES_HP_ELOG_ACTION_ADD:
+ if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
+ rc = dlpar_cpu_add_by_count(count);
+ else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
+ rc = dlpar_cpu_add(drc_index);
+ else
+ rc = -EINVAL;
+ break;
+ default:
+ pr_err("Invalid action (%d) specified\n", hp_elog->action);
+ rc = -EINVAL;
+ break;
+ }
+
+ unlock_device_hotplug();
+ return rc;
+}
+
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+
+static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
+{
+ u32 drc_index;
+ int rc;
+
+ rc = kstrtou32(buf, 0, &drc_index);
+ if (rc)
+ return -EINVAL;
+
+ rc = dlpar_cpu_add(drc_index);
+
+ return rc ? rc : count;
+}
+
+static ssize_t dlpar_cpu_release(const char *buf, size_t count)
+{
+ struct device_node *dn;
+ u32 drc_index;
+ int rc;
+
+ dn = of_find_node_by_path(buf);
+ if (!dn)
+ return -EINVAL;
+
+ rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
+ if (rc) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+
+ rc = dlpar_cpu_remove(dn, drc_index);
+ of_node_put(dn);
+
+ return rc ? rc : count;
+}
+
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
static int pseries_smp_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -385,6 +914,11 @@ static int __init pseries_cpu_hotplug_init(void)
int cpu;
int qcss_tok;
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+ ppc_md.cpu_probe = dlpar_cpu_probe;
+ ppc_md.cpu_release = dlpar_cpu_release;
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
for_each_node_by_name(np, "interrupt-controller") {
typep = of_get_property(np, "compatible", NULL);
if (strstr(typep, "open-pic")) {
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index b7a67e3d2201..477290ad855e 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -315,48 +315,48 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot,
return 0;
}
-static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot)
+static long __pSeries_lpar_hpte_find(unsigned long want_v, unsigned long hpte_group)
{
- unsigned long dword0;
- unsigned long lpar_rc;
- unsigned long dummy_word1;
- unsigned long flags;
+ long lpar_rc;
+ unsigned long i, j;
+ struct {
+ unsigned long pteh;
+ unsigned long ptel;
+ } ptes[4];
- /* Read 1 pte at a time */
- /* Do not need RPN to logical page translation */
- /* No cross CEC PFT access */
- flags = 0;
+ for (i = 0; i < HPTES_PER_GROUP; i += 4, hpte_group += 4) {
- lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
+ lpar_rc = plpar_pte_read_4(0, hpte_group, (void *)ptes);
+ if (lpar_rc != H_SUCCESS)
+ continue;
- BUG_ON(lpar_rc != H_SUCCESS);
+ for (j = 0; j < 4; j++) {
+ if (HPTE_V_COMPARE(ptes[j].pteh, want_v) &&
+ (ptes[j].pteh & HPTE_V_VALID))
+ return i + j;
+ }
+ }
- return dword0;
+ return -1;
}
static long pSeries_lpar_hpte_find(unsigned long vpn, int psize, int ssize)
{
- unsigned long hash;
- unsigned long i;
long slot;
- unsigned long want_v, hpte_v;
+ unsigned long hash;
+ unsigned long want_v;
+ unsigned long hpte_group;
hash = hpt_hash(vpn, mmu_psize_defs[psize].shift, ssize);
want_v = hpte_encode_avpn(vpn, psize, ssize);
/* Bolted entries are always in the primary group */
- slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
- for (i = 0; i < HPTES_PER_GROUP; i++) {
- hpte_v = pSeries_lpar_hpte_getword0(slot);
-
- if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID))
- /* HPTE matches */
- return slot;
- ++slot;
- }
-
- return -1;
-}
+ hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot = __pSeries_lpar_hpte_find(want_v, hpte_group);
+ if (slot < 0)
+ return -1;
+ return hpte_group + slot;
+}
static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
unsigned long ea,
@@ -396,6 +396,7 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
BUG_ON(lpar_rc != H_SUCCESS);
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
/*
* Limit iterations holding pSeries_lpar_tlbie_lock to 3. We also need
* to make sure that we avoid bouncing the hypervisor tlbie lock.
@@ -494,6 +495,15 @@ static void pSeries_lpar_hugepage_invalidate(unsigned long vsid,
__pSeries_lpar_hugepage_invalidate(slot_array, vpn_array,
index, psize, ssize);
}
+#else
+static void pSeries_lpar_hugepage_invalidate(unsigned long vsid,
+ unsigned long addr,
+ unsigned char *hpte_slot_array,
+ int psize, int ssize, int local)
+{
+ WARN(1, "%s called without THP support\n", __func__);
+}
+#endif
static void pSeries_lpar_hpte_removebolted(unsigned long ea,
int psize, int ssize)
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 8411c27293e4..7aa83f00ac62 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -73,6 +73,15 @@ static inline int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
}
#endif
+#ifdef CONFIG_HOTPLUG_CPU
+int dlpar_cpu(struct pseries_hp_errorlog *hp_elog);
+#else
+static inline int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
/* PCI root bridge prepare function override for pseries */
struct pci_host_bridge;
int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 3b6647e574b6..9a3e27b863ce 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -40,6 +40,9 @@ static int ras_check_exception_token;
#define EPOW_SENSOR_TOKEN 9
#define EPOW_SENSOR_INDEX 0
+/* EPOW events counter variable */
+static int num_epow_events;
+
static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
@@ -82,32 +85,30 @@ static void handle_system_shutdown(char event_modifier)
{
switch (event_modifier) {
case EPOW_SHUTDOWN_NORMAL:
- pr_emerg("Firmware initiated power off");
+ pr_emerg("Power off requested\n");
orderly_poweroff(true);
break;
case EPOW_SHUTDOWN_ON_UPS:
- pr_emerg("Loss of power reported by firmware, system is "
- "running on UPS/battery");
- pr_emerg("Check RTAS error log for details");
+ pr_emerg("Loss of system power detected. System is running on"
+ " UPS/battery. Check RTAS error log for details\n");
orderly_poweroff(true);
break;
case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
- pr_emerg("Loss of system critical functions reported by "
- "firmware");
- pr_emerg("Check RTAS error log for details");
+ pr_emerg("Loss of system critical functions detected. Check"
+ " RTAS error log for details\n");
orderly_poweroff(true);
break;
case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
- pr_emerg("Ambient temperature too high reported by firmware");
- pr_emerg("Check RTAS error log for details");
+ pr_emerg("High ambient temperature detected. Check RTAS"
+ " error log for details\n");
orderly_poweroff(true);
break;
default:
- pr_err("Unknown power/cooling shutdown event (modifier %d)",
+ pr_err("Unknown power/cooling shutdown event (modifier = %d)\n",
event_modifier);
}
}
@@ -145,17 +146,20 @@ static void rtas_parse_epow_errlog(struct rtas_error_log *log)
switch (action_code) {
case EPOW_RESET:
- pr_err("Non critical power or cooling issue cleared");
+ if (num_epow_events) {
+ pr_info("Non critical power/cooling issue cleared\n");
+ num_epow_events--;
+ }
break;
case EPOW_WARN_COOLING:
- pr_err("Non critical cooling issue reported by firmware");
- pr_err("Check RTAS error log for details");
+ pr_info("Non-critical cooling issue detected. Check RTAS error"
+ " log for details\n");
break;
case EPOW_WARN_POWER:
- pr_err("Non critical power issue reported by firmware");
- pr_err("Check RTAS error log for details");
+ pr_info("Non-critical power issue detected. Check RTAS error"
+ " log for details\n");
break;
case EPOW_SYSTEM_SHUTDOWN:
@@ -163,23 +167,27 @@ static void rtas_parse_epow_errlog(struct rtas_error_log *log)
break;
case EPOW_SYSTEM_HALT:
- pr_emerg("Firmware initiated power off");
+ pr_emerg("Critical power/cooling issue detected. Check RTAS"
+ " error log for details. Powering off.\n");
orderly_poweroff(true);
break;
case EPOW_MAIN_ENCLOSURE:
case EPOW_POWER_OFF:
- pr_emerg("Critical power/cooling issue reported by firmware");
- pr_emerg("Check RTAS error log for details");
- pr_emerg("Immediate power off");
+ pr_emerg("System about to lose power. Check RTAS error log "
+ " for details. Powering off immediately.\n");
emergency_sync();
kernel_power_off();
break;
default:
- pr_err("Unknown power/cooling event (action code %d)",
+ pr_err("Unknown power/cooling event (action code = %d)\n",
action_code);
}
+
+ /* Increment epow events counter variable */
+ if (action_code != EPOW_RESET)
+ num_epow_events++;
}
/* Handle environmental and power warning (EPOW) interrupts. */
@@ -249,13 +257,12 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);
if (fatal) {
- pr_emerg("Fatal hardware error reported by firmware");
- pr_emerg("Check RTAS error log for details");
- pr_emerg("Immediate power off");
+ pr_emerg("Fatal hardware error detected. Check RTAS error"
+ " log for details. Powering off immediately\n");
emergency_sync();
kernel_power_off();
} else {
- pr_err("Recoverable hardware error reported by firmware");
+ pr_err("Recoverable hardware error detected\n");
}
spin_unlock(&ras_log_buf_lock);
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5b492a6438ff..bd6bd729969c 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -26,7 +26,6 @@ obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
obj-$(CONFIG_FSL_RIO) += fsl_rio.o fsl_rmu.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
-obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
mv64x60_udbg.o
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 7a399b4d60a0..0d112b94d91d 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -43,6 +43,7 @@
#include <linux/types.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/pfn_t.h>
#include <asm/page.h>
#include <asm/prom.h>
@@ -142,15 +143,13 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
*/
static long
axon_ram_direct_access(struct block_device *device, sector_t sector,
- void __pmem **kaddr, unsigned long *pfn)
+ void __pmem **kaddr, pfn_t *pfn)
{
struct axon_ram_bank *bank = device->bd_disk->private_data;
loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;
- void *addr = (void *)(bank->ph_addr + offset);
-
- *kaddr = (void __pmem *)addr;
- *pfn = virt_to_phys(addr) >> PAGE_SHIFT;
+ *kaddr = (void __pmem __force *) bank->io_addr + offset;
+ *pfn = phys_to_pfn_t(bank->ph_addr + offset, PFN_DEV);
return bank->size - offset;
}
@@ -313,6 +312,7 @@ static const struct of_device_id axon_ram_device_id[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, axon_ram_device_id);
static struct platform_driver axon_ram_driver = {
.probe = axon_ram_probe,
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index e00a5ee58fd7..9d32465eddb1 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -27,8 +27,8 @@
#include <asm/udbg.h>
#include <asm/io.h>
-#include <asm/rheap.h>
#include <asm/cpm.h>
+#include <soc/fsl/qe/qe.h>
#include <mm/mmu_decl.h>
@@ -65,162 +65,6 @@ void __init udbg_init_cpm(void)
}
#endif
-static spinlock_t cpm_muram_lock;
-static rh_block_t cpm_boot_muram_rh_block[16];
-static rh_info_t cpm_muram_info;
-static u8 __iomem *muram_vbase;
-static phys_addr_t muram_pbase;
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS 4
-
-int cpm_muram_init(void)
-{
- struct device_node *np;
- struct resource r;
- u32 zero[OF_MAX_ADDR_CELLS] = {};
- resource_size_t max = 0;
- int i = 0;
- int ret = 0;
-
- if (muram_pbase)
- return 0;
-
- spin_lock_init(&cpm_muram_lock);
- /* initialize the info header */
- rh_init(&cpm_muram_info, 1,
- sizeof(cpm_boot_muram_rh_block) /
- sizeof(cpm_boot_muram_rh_block[0]),
- cpm_boot_muram_rh_block);
-
- np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data");
- if (!np) {
- /* try legacy bindings */
- np = of_find_node_by_name(NULL, "data-only");
- if (!np) {
- printk(KERN_ERR "Cannot find CPM muram data node");
- ret = -ENODEV;
- goto out;
- }
- }
-
- muram_pbase = of_translate_address(np, zero);
- if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) {
- printk(KERN_ERR "Cannot translate zero through CPM muram node");
- ret = -ENODEV;
- goto out;
- }
-
- while (of_address_to_resource(np, i++, &r) == 0) {
- if (r.end > max)
- max = r.end;
-
- rh_attach_region(&cpm_muram_info, r.start - muram_pbase,
- resource_size(&r));
- }
-
- muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1);
- if (!muram_vbase) {
- printk(KERN_ERR "Cannot map CPM muram");
- ret = -ENOMEM;
- }
-
-out:
- of_node_put(np);
- return ret;
-}
-
-/**
- * cpm_muram_alloc - allocate the requested size worth of multi-user ram
- * @size: number of bytes to allocate
- * @align: requested alignment, in bytes
- *
- * This function returns an offset into the muram area.
- * Use cpm_dpram_addr() to get the virtual address of the area.
- * Use cpm_muram_free() to free the allocation.
- */
-unsigned long cpm_muram_alloc(unsigned long size, unsigned long align)
-{
- unsigned long start;
- unsigned long flags;
-
- spin_lock_irqsave(&cpm_muram_lock, flags);
- cpm_muram_info.alignment = align;
- start = rh_alloc(&cpm_muram_info, size, "commproc");
- if (!IS_ERR_VALUE(start))
- memset_io(cpm_muram_addr(start), 0, size);
- spin_unlock_irqrestore(&cpm_muram_lock, flags);
-
- return start;
-}
-EXPORT_SYMBOL(cpm_muram_alloc);
-
-/**
- * cpm_muram_free - free a chunk of multi-user ram
- * @offset: The beginning of the chunk as returned by cpm_muram_alloc().
- */
-int cpm_muram_free(unsigned long offset)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&cpm_muram_lock, flags);
- ret = rh_free(&cpm_muram_info, offset);
- spin_unlock_irqrestore(&cpm_muram_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(cpm_muram_free);
-
-/**
- * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram
- * @offset: the offset into the muram area to reserve
- * @size: the number of bytes to reserve
- *
- * This function returns "start" on success, -ENOMEM on failure.
- * Use cpm_dpram_addr() to get the virtual address of the area.
- * Use cpm_muram_free() to free the allocation.
- */
-unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size)
-{
- unsigned long start;
- unsigned long flags;
-
- spin_lock_irqsave(&cpm_muram_lock, flags);
- cpm_muram_info.alignment = 1;
- start = rh_alloc_fixed(&cpm_muram_info, offset, size, "commproc");
- spin_unlock_irqrestore(&cpm_muram_lock, flags);
-
- return start;
-}
-EXPORT_SYMBOL(cpm_muram_alloc_fixed);
-
-/**
- * cpm_muram_addr - turn a muram offset into a virtual address
- * @offset: muram offset to convert
- */
-void __iomem *cpm_muram_addr(unsigned long offset)
-{
- return muram_vbase + offset;
-}
-EXPORT_SYMBOL(cpm_muram_addr);
-
-unsigned long cpm_muram_offset(void __iomem *addr)
-{
- return addr - (void __iomem *)muram_vbase;
-}
-EXPORT_SYMBOL(cpm_muram_offset);
-
-/**
- * cpm_muram_dma - turn a muram virtual address into a DMA address
- * @offset: virtual address from cpm_muram_addr() to convert
- */
-dma_addr_t cpm_muram_dma(void __iomem *addr)
-{
- return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
-}
-EXPORT_SYMBOL(cpm_muram_dma);
-
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
struct cpm2_ioports {
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 38138cf8d33e..47f781059eeb 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -243,8 +243,6 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
if (status & LTESR_CS)
dev_err(ctrl->dev, "Chip select error: "
"LTESR 0x%08X\n", status);
- if (status & LTESR_UPM)
- ;
if (status & LTESR_FCT) {
dev_err(ctrl->dev, "FCM command time-out: "
"LTESR 0x%08X\n", status);
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index a1ac80b3041a..c69e88e91459 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -218,6 +218,19 @@ static void setup_pci_atmu(struct pci_controller *hose)
*/
setup_inbound = !is_kdump();
+ if (of_device_is_compatible(hose->dn, "fsl,bsc9132-pcie")) {
+ /*
+ * BSC9132 Rev1.0 has an issue where all the PEX inbound
+ * windows have implemented the default target value as 0xf
+ * for CCSR space.In all Freescale legacy devices the target
+ * of 0xf is reserved for local memory space. 9132 Rev1.0
+ * now has local mempry space mapped to target 0x0 instead of
+ * 0xf. Hence adding a workaround to remove the target 0xf
+ * defined for memory space from Inbound window attributes.
+ */
+ piwar &= ~PIWAR_TGI_LOCAL;
+ }
+
if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
win_idx = 2;
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 786bf01691c9..07a8508cb7fa 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -320,6 +320,7 @@ static inline void disable_surveillance(void)
#ifdef CONFIG_PPC_PSERIES
/* Since this can't be a module, args should end up below 4GB. */
static struct rtas_args args;
+ int token;
/*
* At this point we have got all the cpus we can into
@@ -328,17 +329,12 @@ static inline void disable_surveillance(void)
* If we did try to take rtas.lock there would be a
* real possibility of deadlock.
*/
- args.token = rtas_token("set-indicator");
- if (args.token == RTAS_UNKNOWN_SERVICE)
+ token = rtas_token("set-indicator");
+ if (token == RTAS_UNKNOWN_SERVICE)
return;
- args.token = cpu_to_be32(args.token);
- args.nargs = cpu_to_be32(3);
- args.nret = cpu_to_be32(1);
- args.rets = &args.args[3];
- args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN);
- args.args[1] = 0;
- args.args[2] = 0;
- enter_rtas(__pa(&args));
+
+ rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
+
#endif /* CONFIG_PPC_PSERIES */
}
@@ -1522,6 +1518,8 @@ static void excprint(struct pt_regs *fp)
if (trap == 0x700)
print_bug_trap(fp);
+
+ printf(linux_banner);
}
static void prregs(struct pt_regs *fp)
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 3a55f493c7da..dbeeb3a049f2 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -10,9 +10,6 @@ config LOCKDEP_SUPPORT
config STACKTRACE_SUPPORT
def_bool y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config RWSEM_GENERIC_SPINLOCK
bool
@@ -66,6 +63,7 @@ config S390
def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SG_CHAIN
@@ -166,8 +164,7 @@ config SCHED_OMIT_FRAME_POINTER
config PGTABLE_LEVELS
int
- default 4 if 64BIT
- default 2
+ default 4
source "init/Kconfig"
@@ -390,9 +387,6 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.
-config SCHED_SMT
- def_bool n
-
# Some NUMA nodes have memory ranges that span
# other nodes. Even though a pfn is valid and
# between a node's start and end pfns, it may not
@@ -403,7 +397,7 @@ config NODES_SPAN_OTHER_NODES
config NUMA
bool "NUMA support"
- depends on SMP && 64BIT && SCHED_TOPOLOGY
+ depends on SMP && SCHED_TOPOLOGY
default n
help
Enable NUMA support
@@ -463,6 +457,9 @@ config EMU_SIZE
endmenu
+config SCHED_SMT
+ def_bool n
+
config SCHED_MC
def_bool n
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
index c56878e1245f..26c5d5beb4be 100644
--- a/arch/s390/Kconfig.debug
+++ b/arch/s390/Kconfig.debug
@@ -5,18 +5,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-config STRICT_DEVMEM
- def_bool y
- prompt "Filter access to /dev/mem"
- ---help---
- This option restricts access to /dev/mem. If this option is
- disabled, you allow userspace access to all memory, including
- kernel and userspace memory. Accidental memory access is likely
- to be disastrous.
- Memory access is required for experts who want to debug the kernel.
-
- If you are unsure, say Y.
-
config S390_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index e8d4423e4f85..224b42734f0d 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -106,6 +106,7 @@ drivers-y += drivers/s390/
drivers-$(CONFIG_OPROFILE) += arch/s390/oprofile/
boot := arch/s390/boot
+tools := arch/s390/tools
all: image bzImage
@@ -124,9 +125,17 @@ vdso_install:
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
+ $(Q)$(MAKE) $(clean)=$(tools)
+
+archprepare:
+ $(Q)$(MAKE) $(build)=$(tools) include/generated/facilities.h
# Don't use tabs in echo arguments
define archhelp
echo '* image - Kernel image for IPL ($(boot)/image)'
echo '* bzImage - Compressed kernel image for IPL ($(boot)/bzImage)'
+ echo ' install - Install kernel using'
+ echo ' (your) ~/bin/$(INSTALLKERNEL) or'
+ echo ' (distribution) /sbin/$(INSTALLKERNEL) or'
+ echo ' install to $$(INSTALL_PATH)'
endef
diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig
index ed7da281df66..0ac42cc4f880 100644
--- a/arch/s390/configs/default_defconfig
+++ b/arch/s390/configs/default_defconfig
@@ -10,28 +10,35 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_NUMA_BALANCING=y
CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_BLK_CGROUP=y
CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
+CONFIG_STATIC_KEYS_SELFTEST=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
@@ -64,7 +71,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
CONFIG_NET=y
@@ -106,7 +112,6 @@ CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
-CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -457,19 +462,9 @@ CONFIG_INFINIBAND=m
CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_MLX4_INFINIBAND=m
CONFIG_VIRTIO_BALLOON=m
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-CONFIG_JBD_DEBUG=y
CONFIG_JBD2_DEBUG=y
CONFIG_JFS_FS=m
CONFIG_JFS_POSIX_ACL=y
@@ -490,7 +485,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V1=m
CONFIG_QFMT_V2=m
CONFIG_AUTOFS4_FS=m
-CONFIG_FUSE_FS=m
+CONFIG_FUSE_FS=y
CONFIG_CUSE=m
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
@@ -542,10 +537,11 @@ CONFIG_DLM=m
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO=y
-# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_FRAME_WARN=1024
CONFIG_READABLE_ASM=y
CONFIG_UNUSED_SYMBOLS=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_DEBUG_OBJECTS=y
@@ -588,6 +584,7 @@ CONFIG_FAILSLAB=y
CONFIG_FAIL_PAGE_ALLOC=y
CONFIG_FAIL_MAKE_REQUEST=y
CONFIG_FAIL_IO_TIMEOUT=y
+CONFIG_FAIL_FUTEX=y
CONFIG_FAULT_INJECTION_DEBUG_FS=y
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_LATENCYTOP=y
diff --git a/arch/s390/configs/gcov_defconfig b/arch/s390/configs/gcov_defconfig
index 9858b14cde1e..a31dcd56f7c0 100644
--- a/arch/s390/configs/gcov_defconfig
+++ b/arch/s390/configs/gcov_defconfig
@@ -10,21 +10,27 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_NUMA_BALANCING=y
CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_BLK_CGROUP=y
CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
@@ -61,7 +67,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
CONFIG_NET=y
@@ -103,7 +108,6 @@ CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
-CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -453,19 +457,9 @@ CONFIG_INFINIBAND=m
CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_MLX4_INFINIBAND=m
CONFIG_VIRTIO_BALLOON=m
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-CONFIG_JBD_DEBUG=y
CONFIG_JBD2_DEBUG=y
CONFIG_JFS_FS=m
CONFIG_JFS_POSIX_ACL=y
@@ -485,7 +479,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V1=m
CONFIG_QFMT_V2=m
CONFIG_AUTOFS4_FS=m
-CONFIG_FUSE_FS=m
+CONFIG_FUSE_FS=y
CONFIG_CUSE=m
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
@@ -550,6 +544,7 @@ CONFIG_NOTIFIER_ERROR_INJECTION=m
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
CONFIG_PM_NOTIFIER_ERROR_INJECT=m
CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
CONFIG_BLK_DEV_IO_TRACE=y
# CONFIG_KPROBE_EVENT is not set
CONFIG_LKDTM=m
@@ -557,6 +552,7 @@ CONFIG_RBTREE_TEST=m
CONFIG_INTERVAL_TREE_TEST=m
CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_TEST_BPF=m
# CONFIG_STRICT_DEVMEM is not set
CONFIG_S390_PTDUMP=y
CONFIG_ENCRYPTED_KEYS=m
diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig
index 7f14f80717d4..7b73bf353345 100644
--- a/arch/s390/configs/performance_defconfig
+++ b/arch/s390/configs/performance_defconfig
@@ -10,22 +10,28 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_NUMA_BALANCING=y
# CONFIG_NUMA_BALANCING_DEFAULT_ENABLED is not set
CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_BLK_CGROUP=y
CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
@@ -61,7 +67,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
CONFIG_NET=y
@@ -103,7 +108,6 @@ CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
-CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -453,19 +457,9 @@ CONFIG_INFINIBAND=m
CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_MLX4_INFINIBAND=m
CONFIG_VIRTIO_BALLOON=m
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-CONFIG_JBD_DEBUG=y
CONFIG_JBD2_DEBUG=y
CONFIG_JFS_FS=m
CONFIG_JFS_POSIX_ACL=y
@@ -485,7 +479,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V1=m
CONFIG_QFMT_V2=m
CONFIG_AUTOFS4_FS=m
-CONFIG_FUSE_FS=m
+CONFIG_FUSE_FS=y
CONFIG_CUSE=m
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
@@ -546,6 +540,7 @@ CONFIG_TIMER_STATS=y
CONFIG_RCU_TORTURE_TEST=m
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
CONFIG_SCHED_TRACER=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_STACK_TRACER=y
@@ -554,6 +549,7 @@ CONFIG_UPROBE_EVENT=y
CONFIG_LKDTM=m
CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_TEST_BPF=m
# CONFIG_STRICT_DEVMEM is not set
CONFIG_S390_PTDUMP=y
CONFIG_ENCRYPTED_KEYS=m
diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig
index 92805d604173..1719843a55a2 100644
--- a/arch/s390/configs/zfcpdump_defconfig
+++ b/arch/s390/configs/zfcpdump_defconfig
@@ -23,8 +23,6 @@ CONFIG_CRASH_DUMP=y
# CONFIG_SECCOMP is not set
CONFIG_NET=y
# CONFIG_IUCV is not set
-CONFIG_ATM=y
-CONFIG_ATM_LANE=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -54,14 +52,10 @@ CONFIG_RAW_DRIVER=y
# CONFIG_S390_VMUR is not set
# CONFIG_HID is not set
# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_FS=y
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 9256b48e7e43..e24f2af4c73b 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -11,22 +11,31 @@ CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_BLK_CGROUP=y
CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
+CONFIG_STATIC_KEYS_SELFTEST=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
@@ -37,6 +46,7 @@ CONFIG_DEFAULT_DEADLINE=y
CONFIG_LIVEPATCH=y
CONFIG_MARCH_Z196=y
CONFIG_NR_CPUS=256
+CONFIG_NUMA=y
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -52,7 +62,6 @@ CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
CONFIG_L2TP=m
CONFIG_L2TP_DEBUGFS=m
CONFIG_VLAN_8021Q=y
@@ -89,10 +98,26 @@ CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_ZFCP=y
CONFIG_SCSI_VIRTIO=y
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=m
+CONFIG_DM_SWITCH=m
CONFIG_NETDEVICES=y
CONFIG_BONDING=m
CONFIG_DUMMY=m
@@ -137,7 +162,6 @@ CONFIG_DEBUG_PI_LIST=y
CONFIG_DEBUG_SG=y
CONFIG_DEBUG_NOTIFIERS=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
-# CONFIG_RCU_CPU_STALL_INFO is not set
CONFIG_RCU_TRACE=y
CONFIG_LATENCYTOP=y
CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h
index 7ffd0b19135c..5c8db3ce61c8 100644
--- a/arch/s390/include/asm/barrier.h
+++ b/arch/s390/include/asm/barrier.h
@@ -26,26 +26,18 @@
#define wmb() barrier()
#define dma_rmb() mb()
#define dma_wmb() mb()
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
+#define __smp_mb() mb()
+#define __smp_rmb() rmb()
+#define __smp_wmb() wmb()
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
-
-#define smp_mb__before_atomic() smp_mb()
-#define smp_mb__after_atomic() smp_mb()
-
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
-
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
WRITE_ONCE(*p, v); \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
@@ -53,4 +45,9 @@ do { \
___p1; \
})
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
+
+#include <asm-generic/barrier.h>
+
#endif /* __ASM_BARRIER_H */
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index d350ed9d0fbb..352f7bdaf11f 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -284,7 +284,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
static inline int is_compat_task(void)
{
- return is_32bit_task();
+ return test_thread_flag(TIF_31BIT);
}
static inline void __user *arch_compat_alloc_user_space(long len)
diff --git a/arch/s390/include/asm/crw.h b/arch/s390/include/asm/crw.h
index 7c31d3e25cd1..bcb9cd2a730a 100644
--- a/arch/s390/include/asm/crw.h
+++ b/arch/s390/include/asm/crw.h
@@ -52,18 +52,4 @@ void crw_wait_for_channel_report(void);
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
-static inline int stcrw(struct crw *pcrw)
-{
- int ccode;
-
- asm volatile(
- " stcrw 0(%2)\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode), "=m" (*pcrw)
- : "a" (pcrw)
- : "cc" );
- return ccode;
-}
-
#endif /* _ASM_S390_CRW_H */
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 08e34a5dc909..563ab9f44874 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -129,6 +129,7 @@ typedef s390_regs elf_gregset_t;
typedef s390_fp_regs compat_elf_fpregset_t;
typedef s390_compat_regs compat_elf_gregset_t;
+#include <linux/compat.h>
#include <linux/sched.h> /* for task_struct */
#include <asm/mmu_context.h>
@@ -162,7 +163,7 @@ extern unsigned int vdso_enabled;
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. 64-bit
tasks are aligned to 4GB. */
-#define ELF_ET_DYN_BASE (is_32bit_task() ? \
+#define ELF_ET_DYN_BASE (is_compat_task() ? \
(STACK_TOP / 3 * 2) : \
(STACK_TOP / 3 * 2) & ~((1UL << 32) - 1))
@@ -219,9 +220,9 @@ do { \
* of up to 1GB. For 31-bit processes the virtual address space is limited,
* use no alignment and limit the randomization to 8MB.
*/
-#define BRK_RND_MASK (is_32bit_task() ? 0x7ffUL : 0x3ffffUL)
-#define MMAP_RND_MASK (is_32bit_task() ? 0x7ffUL : 0x3ff80UL)
-#define MMAP_ALIGN_MASK (is_32bit_task() ? 0 : 0x7fUL)
+#define BRK_RND_MASK (is_compat_task() ? 0x7ffUL : 0x3ffffUL)
+#define MMAP_RND_MASK (is_compat_task() ? 0x7ffUL : 0x3ff80UL)
+#define MMAP_ALIGN_MASK (is_compat_task() ? 0 : 0x7fUL)
#define STACK_RND_MASK MMAP_RND_MASK
#define ARCH_DLINFO \
@@ -236,6 +237,4 @@ struct linux_binprm;
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
int arch_setup_additional_pages(struct linux_binprm *, int);
-void *fill_cpu_elf_notes(void *ptr, struct save_area *sa, __vector128 *vxrs);
-
#endif
diff --git a/arch/s390/include/asm/facilities_src.h b/arch/s390/include/asm/facilities_src.h
new file mode 100644
index 000000000000..4917728e5828
--- /dev/null
+++ b/arch/s390/include/asm/facilities_src.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright IBM Corp. 2015
+ */
+
+#ifndef S390_GEN_FACILITIES_C
+#error "This file can only be included by gen_facilities.c"
+#endif
+
+#include <linux/kconfig.h>
+
+struct facility_def {
+ char *name;
+ int *bits;
+};
+
+static struct facility_def facility_defs[] = {
+ {
+ /*
+ * FACILITIES_ALS contains the list of facilities that are
+ * required to run a kernel that is compiled e.g. with
+ * -march=<machine>.
+ */
+ .name = "FACILITIES_ALS",
+ .bits = (int[]){
+#ifdef CONFIG_HAVE_MARCH_Z900_FEATURES
+ 0, /* N3 instructions */
+ 1, /* z/Arch mode installed */
+#endif
+#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
+ 18, /* long displacement facility */
+#endif
+#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
+ 7, /* stfle */
+ 17, /* message security assist */
+ 21, /* extended-immediate facility */
+ 25, /* store clock fast */
+#endif
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+ 27, /* mvcos */
+ 32, /* compare and swap and store */
+ 33, /* compare and swap and store 2 */
+ 34, /* general extension facility */
+ 35, /* execute extensions */
+#endif
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+ 45, /* fast-BCR, etc. */
+#endif
+#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
+ 49, /* misc-instruction-extensions */
+ 52, /* interlocked facility 2 */
+#endif
+#ifdef CONFIG_HAVE_MARCH_Z13_FEATURES
+ 53, /* load-and-zero-rightmost-byte, etc. */
+#endif
+ -1 /* END */
+ }
+ },
+};
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h
index 0aa6a7ed95a3..09b406db7529 100644
--- a/arch/s390/include/asm/facility.h
+++ b/arch/s390/include/asm/facility.h
@@ -7,6 +7,10 @@
#ifndef __ASM_FACILITY_H
#define __ASM_FACILITY_H
+#include <generated/facilities.h>
+
+#ifndef __ASSEMBLY__
+
#include <linux/string.h>
#include <linux/preempt.h>
#include <asm/lowcore.h>
@@ -30,6 +34,12 @@ static inline int __test_facility(unsigned long nr, void *facilities)
*/
static inline int test_facility(unsigned long nr)
{
+ unsigned long facilities_als[] = { FACILITIES_ALS };
+
+ if (__builtin_constant_p(nr) && nr < sizeof(facilities_als) * 8) {
+ if (__test_facility(nr, &facilities_als))
+ return 1;
+ }
return __test_facility(nr, &S390_lowcore.stfle_fac_list);
}
@@ -44,10 +54,8 @@ static inline void stfle(u64 *stfle_fac_list, int size)
preempt_disable();
asm volatile(
- " .insn s,0xb2b10000,0(0)\n" /* stfl */
- "0:\n"
- EX_TABLE(0b, 0b)
- : "+m" (S390_lowcore.stfl_fac_list));
+ " stfl 0(0)\n"
+ : "=m" (S390_lowcore.stfl_fac_list));
nr = 4; /* bytes stored by stfl */
memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
if (S390_lowcore.stfl_fac_list & 0x01000000) {
@@ -64,4 +72,5 @@ static inline void stfle(u64 *stfle_fac_list, int size)
preempt_enable();
}
+#endif /* __ASSEMBLY__ */
#endif /* __ASM_FACILITY_H */
diff --git a/arch/s390/include/asm/fpu/internal.h b/arch/s390/include/asm/fpu/internal.h
index 2559b16da525..ea91ddfe54eb 100644
--- a/arch/s390/include/asm/fpu/internal.h
+++ b/arch/s390/include/asm/fpu/internal.h
@@ -12,21 +12,13 @@
#include <asm/ctl_reg.h>
#include <asm/fpu/types.h>
-static inline void save_vx_regs_safe(__vector128 *vxrs)
+static inline void save_vx_regs(__vector128 *vxrs)
{
- unsigned long cr0, flags;
-
- flags = arch_local_irq_save();
- __ctl_store(cr0, 0, 0);
- __ctl_set_bit(0, 17);
- __ctl_set_bit(0, 18);
asm volatile(
" la 1,%0\n"
" .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */
" .word 0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */
: "=Q" (*(struct vx_array *) vxrs) : : "1");
- __ctl_load(cr0, 0, 0);
- arch_local_irq_restore(flags);
}
static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs)
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index 86634e71b69f..6fc44dca193e 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -87,14 +87,12 @@ struct ipl_parameter_block {
* IPL validity flags
*/
extern u32 ipl_flags;
-extern u32 dump_prefix_page;
-struct dump_save_areas {
- struct save_area_ext **areas;
- int count;
-};
-
-extern struct dump_save_areas dump_save_areas;
+struct save_area;
+struct save_area * __init save_area_alloc(bool is_boot_cpu);
+struct save_area * __init save_area_boot_cpu(void);
+void __init save_area_add_regs(struct save_area *, void *regs);
+void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs);
extern void do_reipl(void);
extern void do_halt(void);
@@ -176,7 +174,7 @@ enum diag308_rc {
extern int diag308(unsigned long subcode, void *addr);
extern void diag308_reset(void);
-extern void store_status(void);
+extern void store_status(void (*fn)(void *), void *data);
extern void lgr_info_log(void);
#endif /* _ASM_S390_IPL_H */
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index afe1cfebf1a4..d79ba7cf75b0 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -16,28 +16,7 @@
#define LC_ORDER 1
#define LC_PAGES 2
-struct save_area {
- u64 fp_regs[16];
- u64 gp_regs[16];
- u8 psw[16];
- u8 pad1[8];
- u32 pref_reg;
- u32 fp_ctrl_reg;
- u8 pad2[4];
- u32 tod_reg;
- u64 timer;
- u64 clk_cmp;
- u8 pad3[8];
- u32 acc_regs[16];
- u64 ctrl_regs[16];
-} __packed;
-
-struct save_area_ext {
- struct save_area sa;
- __vector128 vx_regs[32];
-};
-
-struct _lowcore {
+struct lowcore {
__u8 pad_0x0000[0x0014-0x0000]; /* 0x0000 */
__u32 ipl_parmblock_ptr; /* 0x0014 */
__u8 pad_0x0018[0x0080-0x0018]; /* 0x0018 */
@@ -204,9 +183,9 @@ struct _lowcore {
__u8 vector_save_area[1024]; /* 0x1c00 */
} __packed;
-#define S390_lowcore (*((struct _lowcore *) 0))
+#define S390_lowcore (*((struct lowcore *) 0))
-extern struct _lowcore *lowcore_ptr[];
+extern struct lowcore *lowcore_ptr[];
static inline void set_prefix(__u32 address)
{
diff --git a/arch/s390/include/asm/os_info.h b/arch/s390/include/asm/os_info.h
index 295f2c4f1c96..943475382d51 100644
--- a/arch/s390/include/asm/os_info.h
+++ b/arch/s390/include/asm/os_info.h
@@ -38,7 +38,7 @@ u32 os_info_csum(struct os_info *os_info);
#ifdef CONFIG_CRASH_DUMP
void *os_info_old_entry(int nr, unsigned long *size);
-int copy_from_oldmem(void *dest, void *src, size_t count);
+int copy_oldmem_kernel(void *dst, void *src, size_t count);
#else
static inline void *os_info_old_entry(int nr, unsigned long *size)
{
diff --git a/arch/s390/include/asm/pci_dma.h b/arch/s390/include/asm/pci_dma.h
index 1aac41e83ea1..92df3eb8d14e 100644
--- a/arch/s390/include/asm/pci_dma.h
+++ b/arch/s390/include/asm/pci_dma.h
@@ -23,6 +23,8 @@ enum zpci_ioat_dtype {
#define ZPCI_IOTA_FS_2G 2
#define ZPCI_KEY (PAGE_DEFAULT_KEY << 5)
+#define ZPCI_TABLE_SIZE_RT (1UL << 42)
+
#define ZPCI_IOTA_STO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)
#define ZPCI_IOTA_RTTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
#define ZPCI_IOTA_RSTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 024f85f947ae..64ead8091248 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -286,7 +286,6 @@ static inline int is_module_addr(void *addr)
#define _SEGMENT_ENTRY_DIRTY 0x2000 /* SW segment dirty bit */
#define _SEGMENT_ENTRY_YOUNG 0x1000 /* SW segment young bit */
-#define _SEGMENT_ENTRY_SPLIT 0x0800 /* THP splitting bit */
#define _SEGMENT_ENTRY_LARGE 0x0400 /* STE-format control, large page */
#define _SEGMENT_ENTRY_READ 0x0002 /* SW segment read bit */
#define _SEGMENT_ENTRY_WRITE 0x0001 /* SW segment write bit */
@@ -318,8 +317,6 @@ static inline int is_module_addr(void *addr)
* SW-bits: y young, d dirty, r read, w write
*/
-#define _SEGMENT_ENTRY_SPLIT_BIT 11 /* THP splitting bit number */
-
/* Page status table bits for virtualization */
#define PGSTE_ACC_BITS 0xf000000000000000UL
#define PGSTE_FP_BIT 0x0800000000000000UL
@@ -523,10 +520,6 @@ static inline int pmd_bad(pmd_t pmd)
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0;
}
-#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-extern void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long addr, pmd_t *pmdp);
-
#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
extern int pmdp_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp,
@@ -1424,8 +1417,7 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
if (pmd_large(pmd)) {
pmd_val(pmd) &= _SEGMENT_ENTRY_ORIGIN_LARGE |
_SEGMENT_ENTRY_DIRTY | _SEGMENT_ENTRY_YOUNG |
- _SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_SPLIT |
- _SEGMENT_ENTRY_SOFT_DIRTY;
+ _SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_SOFT_DIRTY;
pmd_val(pmd) |= massage_pgprot_pmd(newprot);
if (!(pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY))
pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
@@ -1533,12 +1525,6 @@ extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
#define __HAVE_ARCH_PGTABLE_WITHDRAW
extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) &&
- (pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT);
-}
-
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t entry)
{
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index b16c3d0a1b9f..f16debf6a612 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -18,12 +18,14 @@
#define CIF_NOHZ_DELAY 2 /* delay HZ disable for a tick */
#define CIF_FPU 3 /* restore FPU registers */
#define CIF_IGNORE_IRQ 4 /* ignore interrupt (for udelay) */
+#define CIF_ENABLED_WAIT 5 /* in enabled wait state */
#define _CIF_MCCK_PENDING _BITUL(CIF_MCCK_PENDING)
#define _CIF_ASCE _BITUL(CIF_ASCE)
#define _CIF_NOHZ_DELAY _BITUL(CIF_NOHZ_DELAY)
#define _CIF_FPU _BITUL(CIF_FPU)
#define _CIF_IGNORE_IRQ _BITUL(CIF_IGNORE_IRQ)
+#define _CIF_ENABLED_WAIT _BITUL(CIF_ENABLED_WAIT)
#ifndef __ASSEMBLY__
@@ -52,6 +54,16 @@ static inline int test_cpu_flag(int flag)
return !!(S390_lowcore.cpu_flags & (1UL << flag));
}
+/*
+ * Test CIF flag of another CPU. The caller needs to ensure that
+ * CPU hotplug can not happen, e.g. by disabling preemption.
+ */
+static inline int test_cpu_flag_of(int flag, int cpu)
+{
+ struct lowcore *lc = lowcore_ptr[cpu];
+ return !!(lc->cpu_flags & (1UL << flag));
+}
+
#define arch_needs_cpu() test_cpu_flag(CIF_NOHZ_DELAY)
/*
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 37cbc50947f2..f00cd35c8ac4 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -24,25 +24,25 @@
PSW_MASK_PSTATE | PSW_ASC_PRIMARY)
struct psw_bits {
- unsigned long long : 1;
- unsigned long long r : 1; /* PER-Mask */
- unsigned long long : 3;
- unsigned long long t : 1; /* DAT Mode */
- unsigned long long i : 1; /* Input/Output Mask */
- unsigned long long e : 1; /* External Mask */
- unsigned long long key : 4; /* PSW Key */
- unsigned long long : 1;
- unsigned long long m : 1; /* Machine-Check Mask */
- unsigned long long w : 1; /* Wait State */
- unsigned long long p : 1; /* Problem State */
- unsigned long long as : 2; /* Address Space Control */
- unsigned long long cc : 2; /* Condition Code */
- unsigned long long pm : 4; /* Program Mask */
- unsigned long long ri : 1; /* Runtime Instrumentation */
- unsigned long long : 6;
- unsigned long long eaba : 2; /* Addressing Mode */
- unsigned long long : 31;
- unsigned long long ia : 64;/* Instruction Address */
+ unsigned long : 1;
+ unsigned long r : 1; /* PER-Mask */
+ unsigned long : 3;
+ unsigned long t : 1; /* DAT Mode */
+ unsigned long i : 1; /* Input/Output Mask */
+ unsigned long e : 1; /* External Mask */
+ unsigned long key : 4; /* PSW Key */
+ unsigned long : 1;
+ unsigned long m : 1; /* Machine-Check Mask */
+ unsigned long w : 1; /* Wait State */
+ unsigned long p : 1; /* Problem State */
+ unsigned long as : 2; /* Address Space Control */
+ unsigned long cc : 2; /* Condition Code */
+ unsigned long pm : 4; /* Program Mask */
+ unsigned long ri : 1; /* Runtime Instrumentation */
+ unsigned long : 6;
+ unsigned long eaba : 2; /* Addressing Mode */
+ unsigned long : 31;
+ unsigned long ia : 64; /* Instruction Address */
};
enum {
diff --git a/arch/s390/include/asm/reset.h b/arch/s390/include/asm/reset.h
index 72786067b300..fe11fa88a0e0 100644
--- a/arch/s390/include/asm/reset.h
+++ b/arch/s390/include/asm/reset.h
@@ -15,6 +15,5 @@ struct reset_call {
extern void register_reset_call(struct reset_call *reset);
extern void unregister_reset_call(struct reset_call *reset);
-extern void s390_reset_system(void (*fn_pre)(void),
- void (*fn_post)(void *), void *data);
+extern void s390_reset_system(void);
#endif /* _ASM_S390_RESET_H */
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index dea883f85d66..bab456be9a4f 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -63,12 +63,12 @@ struct sclp_info {
unsigned int mtid;
unsigned int mtid_cp;
unsigned int mtid_prev;
- unsigned long long rzm;
- unsigned long long rnmax;
- unsigned long long hamax;
+ unsigned long rzm;
+ unsigned long rnmax;
+ unsigned long hamax;
unsigned int max_cores;
unsigned long hsa_size;
- unsigned long long facilities;
+ unsigned long facilities;
};
extern struct sclp_info sclp;
@@ -83,8 +83,9 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
void sclp_get_ipl_info(struct sclp_ipl_info *info);
int sclp_pci_configure(u32 fid);
int sclp_pci_deconfigure(u32 fid);
-int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
+int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
+int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
void sclp_early_detect(void);
-int _sclp_print_early(const char *);
+void _sclp_print_early(const char *);
#endif /* _ASM_S390_SCLP_H */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 23537661da0e..69837225119e 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -12,27 +12,24 @@
#define PARMAREA 0x10400
/*
- * Machine features detected in head.S
+ * Machine features detected in early.c
*/
#define MACHINE_FLAG_VM _BITUL(0)
-#define MACHINE_FLAG_IEEE _BITUL(1)
-#define MACHINE_FLAG_CSP _BITUL(2)
-#define MACHINE_FLAG_MVPG _BITUL(3)
-#define MACHINE_FLAG_DIAG44 _BITUL(4)
+#define MACHINE_FLAG_KVM _BITUL(1)
+#define MACHINE_FLAG_LPAR _BITUL(2)
+#define MACHINE_FLAG_DIAG9C _BITUL(3)
+#define MACHINE_FLAG_ESOP _BITUL(4)
#define MACHINE_FLAG_IDTE _BITUL(5)
-#define MACHINE_FLAG_DIAG9C _BITUL(6)
-#define MACHINE_FLAG_KVM _BITUL(8)
-#define MACHINE_FLAG_ESOP _BITUL(9)
-#define MACHINE_FLAG_EDAT1 _BITUL(10)
-#define MACHINE_FLAG_EDAT2 _BITUL(11)
-#define MACHINE_FLAG_LPAR _BITUL(12)
-#define MACHINE_FLAG_LPP _BITUL(13)
-#define MACHINE_FLAG_TOPOLOGY _BITUL(14)
-#define MACHINE_FLAG_TE _BITUL(15)
-#define MACHINE_FLAG_TLB_LC _BITUL(17)
-#define MACHINE_FLAG_VX _BITUL(18)
-#define MACHINE_FLAG_CAD _BITUL(19)
+#define MACHINE_FLAG_DIAG44 _BITUL(6)
+#define MACHINE_FLAG_EDAT1 _BITUL(7)
+#define MACHINE_FLAG_EDAT2 _BITUL(8)
+#define MACHINE_FLAG_LPP _BITUL(9)
+#define MACHINE_FLAG_TOPOLOGY _BITUL(10)
+#define MACHINE_FLAG_TE _BITUL(11)
+#define MACHINE_FLAG_TLB_LC _BITUL(12)
+#define MACHINE_FLAG_VX _BITUL(13)
+#define MACHINE_FLAG_CAD _BITUL(14)
#define LPP_MAGIC _BITUL(31)
#define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL)
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index 5df26b11cf47..0cc383b9be7f 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -18,6 +18,7 @@
extern struct mutex smp_cpu_state_mutex;
extern unsigned int smp_cpu_mt_shift;
extern unsigned int smp_cpu_mtid;
+extern __vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS];
extern int __cpu_up(unsigned int cpu, struct task_struct *tidle);
@@ -55,7 +56,6 @@ static inline int smp_store_status(int cpu) { return 0; }
static inline int smp_vcpu_scheduled(int cpu) { return 1; }
static inline void smp_yield_cpu(int cpu) { }
static inline void smp_fill_possible_mask(void) { }
-static inline void smp_save_dump_cpus(void) { }
#endif /* CONFIG_SMP */
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h
index f7054a892d9e..2728114d5484 100644
--- a/arch/s390/include/asm/sysinfo.h
+++ b/arch/s390/include/asm/sysinfo.h
@@ -56,7 +56,12 @@ struct sysinfo_1_2_2 {
char format;
char reserved_0[1];
unsigned short acc_offset;
- char reserved_1[20];
+ unsigned char mt_installed :1;
+ unsigned char :2;
+ unsigned char mt_stid :5;
+ unsigned char :3;
+ unsigned char mt_gtid :5;
+ char reserved_1[18];
unsigned int nominal_cap;
unsigned int secondary_cap;
unsigned int capability;
@@ -92,9 +97,13 @@ struct sysinfo_2_2_2 {
char name[8];
unsigned int caf;
char reserved_2[8];
- unsigned char mt_installed;
- unsigned char mt_general;
- unsigned char mt_psmtid;
+ unsigned char mt_installed :1;
+ unsigned char :2;
+ unsigned char mt_stid :5;
+ unsigned char :3;
+ unsigned char mt_gtid :5;
+ unsigned char :3;
+ unsigned char mt_psmtid :5;
char reserved_3[5];
unsigned short cpus_dedicated;
unsigned short cpus_shared;
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 692b9247c019..2fffc2c27581 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -96,6 +96,4 @@ void arch_release_task_struct(struct task_struct *tsk);
#define _TIF_31BIT _BITUL(TIF_31BIT)
#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP)
-#define is_32bit_task() (test_thread_flag(TIF_31BIT))
-
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index 94fc55fc72ce..6b53962e807e 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -7,7 +7,7 @@
struct sysinfo_15_1_x;
struct cpu;
-#ifdef CONFIG_SCHED_BOOK
+#ifdef CONFIG_SCHED_TOPOLOGY
struct cpu_topology_s390 {
unsigned short thread_id;
@@ -40,13 +40,13 @@ void store_topology(struct sysinfo_15_1_x *info);
void topology_expect_change(void);
const struct cpumask *cpu_coregroup_mask(int cpu);
-#else /* CONFIG_SCHED_BOOK */
+#else /* CONFIG_SCHED_TOPOLOGY */
static inline void topology_schedule_update(void) { }
static inline int topology_cpu_init(struct cpu *cpu) { return 0; }
static inline void topology_expect_change(void) { }
-#endif /* CONFIG_SCHED_BOOK */
+#endif /* CONFIG_SCHED_TOPOLOGY */
#define POLARIZATION_UNKNOWN (-1)
#define POLARIZATION_HRZ (0)
diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h
index 787acd4f9668..d0a2dbf2433d 100644
--- a/arch/s390/include/asm/vdso.h
+++ b/arch/s390/include/asm/vdso.h
@@ -38,12 +38,14 @@ struct vdso_data {
struct vdso_per_cpu_data {
__u64 ectg_timer_base;
__u64 ectg_user_time;
+ __u32 cpu_nr;
+ __u32 node_id;
};
extern struct vdso_data *vdso_data;
-int vdso_alloc_per_cpu(struct _lowcore *lowcore);
-void vdso_free_per_cpu(struct _lowcore *lowcore);
+int vdso_alloc_per_cpu(struct lowcore *lowcore);
+void vdso_free_per_cpu(struct lowcore *lowcore);
#endif /* __ASSEMBLY__ */
#endif /* __S390_VDSO_H__ */
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index dc167a23b920..2f5586ab8a6a 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -34,8 +34,10 @@ CFLAGS_sysinfo.o += -w
#
CFLAGS_REMOVE_sclp.o = $(CC_FLAGS_FTRACE)
ifneq ($(CC_FLAGS_MARCH),-march=z900)
-CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH)
-CFLAGS_sclp.o += -march=z900
+CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH)
+CFLAGS_sclp.o += -march=z900
+AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH)
+AFLAGS_head.o += -march=z900
endif
GCOV_PROFILE_sclp.o := n
@@ -50,7 +52,7 @@ extra-y += head.o head64.o vmlinux.lds
obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_SCHED_BOOK) += topology.o
+obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o
obj-$(CONFIG_HIBERNATION) += suspend.o swsusp.o
obj-$(CONFIG_AUDIT) += audit.o
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 9cd248f637c7..53bbc9e8b281 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -80,6 +80,8 @@ int main(void)
OFFSET(__VDSO_TK_SHIFT, vdso_data, tk_shift);
OFFSET(__VDSO_ECTG_BASE, vdso_per_cpu_data, ectg_timer_base);
OFFSET(__VDSO_ECTG_USER, vdso_per_cpu_data, ectg_user_time);
+ OFFSET(__VDSO_CPU_NR, vdso_per_cpu_data, cpu_nr);
+ OFFSET(__VDSO_NODE_ID, vdso_per_cpu_data, node_id);
BLANK();
/* constants used by the vdso */
DEFINE(__CLOCK_REALTIME, CLOCK_REALTIME);
@@ -97,95 +99,96 @@ int main(void)
OFFSET(__TIMER_IDLE_EXIT, s390_idle_data, timer_idle_exit);
BLANK();
/* hardware defined lowcore locations 0x000 - 0x1ff */
- OFFSET(__LC_EXT_PARAMS, _lowcore, ext_params);
- OFFSET(__LC_EXT_CPU_ADDR, _lowcore, ext_cpu_addr);
- OFFSET(__LC_EXT_INT_CODE, _lowcore, ext_int_code);
- OFFSET(__LC_SVC_ILC, _lowcore, svc_ilc);
- OFFSET(__LC_SVC_INT_CODE, _lowcore, svc_code);
- OFFSET(__LC_PGM_ILC, _lowcore, pgm_ilc);
- OFFSET(__LC_PGM_INT_CODE, _lowcore, pgm_code);
- OFFSET(__LC_DATA_EXC_CODE, _lowcore, data_exc_code);
- OFFSET(__LC_MON_CLASS_NR, _lowcore, mon_class_num);
- OFFSET(__LC_PER_CODE, _lowcore, per_code);
- OFFSET(__LC_PER_ATMID, _lowcore, per_atmid);
- OFFSET(__LC_PER_ADDRESS, _lowcore, per_address);
- OFFSET(__LC_EXC_ACCESS_ID, _lowcore, exc_access_id);
- OFFSET(__LC_PER_ACCESS_ID, _lowcore, per_access_id);
- OFFSET(__LC_OP_ACCESS_ID, _lowcore, op_access_id);
- OFFSET(__LC_AR_MODE_ID, _lowcore, ar_mode_id);
- OFFSET(__LC_TRANS_EXC_CODE, _lowcore, trans_exc_code);
- OFFSET(__LC_MON_CODE, _lowcore, monitor_code);
- OFFSET(__LC_SUBCHANNEL_ID, _lowcore, subchannel_id);
- OFFSET(__LC_SUBCHANNEL_NR, _lowcore, subchannel_nr);
- OFFSET(__LC_IO_INT_PARM, _lowcore, io_int_parm);
- OFFSET(__LC_IO_INT_WORD, _lowcore, io_int_word);
- OFFSET(__LC_STFL_FAC_LIST, _lowcore, stfl_fac_list);
- OFFSET(__LC_MCCK_CODE, _lowcore, mcck_interruption_code);
- OFFSET(__LC_MCCK_FAIL_STOR_ADDR, _lowcore, failing_storage_address);
- OFFSET(__LC_LAST_BREAK, _lowcore, breaking_event_addr);
- OFFSET(__LC_RST_OLD_PSW, _lowcore, restart_old_psw);
- OFFSET(__LC_EXT_OLD_PSW, _lowcore, external_old_psw);
- OFFSET(__LC_SVC_OLD_PSW, _lowcore, svc_old_psw);
- OFFSET(__LC_PGM_OLD_PSW, _lowcore, program_old_psw);
- OFFSET(__LC_MCK_OLD_PSW, _lowcore, mcck_old_psw);
- OFFSET(__LC_IO_OLD_PSW, _lowcore, io_old_psw);
- OFFSET(__LC_RST_NEW_PSW, _lowcore, restart_psw);
- OFFSET(__LC_EXT_NEW_PSW, _lowcore, external_new_psw);
- OFFSET(__LC_SVC_NEW_PSW, _lowcore, svc_new_psw);
- OFFSET(__LC_PGM_NEW_PSW, _lowcore, program_new_psw);
- OFFSET(__LC_MCK_NEW_PSW, _lowcore, mcck_new_psw);
- OFFSET(__LC_IO_NEW_PSW, _lowcore, io_new_psw);
+ OFFSET(__LC_EXT_PARAMS, lowcore, ext_params);
+ OFFSET(__LC_EXT_CPU_ADDR, lowcore, ext_cpu_addr);
+ OFFSET(__LC_EXT_INT_CODE, lowcore, ext_int_code);
+ OFFSET(__LC_SVC_ILC, lowcore, svc_ilc);
+ OFFSET(__LC_SVC_INT_CODE, lowcore, svc_code);
+ OFFSET(__LC_PGM_ILC, lowcore, pgm_ilc);
+ OFFSET(__LC_PGM_INT_CODE, lowcore, pgm_code);
+ OFFSET(__LC_DATA_EXC_CODE, lowcore, data_exc_code);
+ OFFSET(__LC_MON_CLASS_NR, lowcore, mon_class_num);
+ OFFSET(__LC_PER_CODE, lowcore, per_code);
+ OFFSET(__LC_PER_ATMID, lowcore, per_atmid);
+ OFFSET(__LC_PER_ADDRESS, lowcore, per_address);
+ OFFSET(__LC_EXC_ACCESS_ID, lowcore, exc_access_id);
+ OFFSET(__LC_PER_ACCESS_ID, lowcore, per_access_id);
+ OFFSET(__LC_OP_ACCESS_ID, lowcore, op_access_id);
+ OFFSET(__LC_AR_MODE_ID, lowcore, ar_mode_id);
+ OFFSET(__LC_TRANS_EXC_CODE, lowcore, trans_exc_code);
+ OFFSET(__LC_MON_CODE, lowcore, monitor_code);
+ OFFSET(__LC_SUBCHANNEL_ID, lowcore, subchannel_id);
+ OFFSET(__LC_SUBCHANNEL_NR, lowcore, subchannel_nr);
+ OFFSET(__LC_IO_INT_PARM, lowcore, io_int_parm);
+ OFFSET(__LC_IO_INT_WORD, lowcore, io_int_word);
+ OFFSET(__LC_STFL_FAC_LIST, lowcore, stfl_fac_list);
+ OFFSET(__LC_STFLE_FAC_LIST, lowcore, stfle_fac_list);
+ OFFSET(__LC_MCCK_CODE, lowcore, mcck_interruption_code);
+ OFFSET(__LC_MCCK_FAIL_STOR_ADDR, lowcore, failing_storage_address);
+ OFFSET(__LC_LAST_BREAK, lowcore, breaking_event_addr);
+ OFFSET(__LC_RST_OLD_PSW, lowcore, restart_old_psw);
+ OFFSET(__LC_EXT_OLD_PSW, lowcore, external_old_psw);
+ OFFSET(__LC_SVC_OLD_PSW, lowcore, svc_old_psw);
+ OFFSET(__LC_PGM_OLD_PSW, lowcore, program_old_psw);
+ OFFSET(__LC_MCK_OLD_PSW, lowcore, mcck_old_psw);
+ OFFSET(__LC_IO_OLD_PSW, lowcore, io_old_psw);
+ OFFSET(__LC_RST_NEW_PSW, lowcore, restart_psw);
+ OFFSET(__LC_EXT_NEW_PSW, lowcore, external_new_psw);
+ OFFSET(__LC_SVC_NEW_PSW, lowcore, svc_new_psw);
+ OFFSET(__LC_PGM_NEW_PSW, lowcore, program_new_psw);
+ OFFSET(__LC_MCK_NEW_PSW, lowcore, mcck_new_psw);
+ OFFSET(__LC_IO_NEW_PSW, lowcore, io_new_psw);
/* software defined lowcore locations 0x200 - 0xdff*/
- OFFSET(__LC_SAVE_AREA_SYNC, _lowcore, save_area_sync);
- OFFSET(__LC_SAVE_AREA_ASYNC, _lowcore, save_area_async);
- OFFSET(__LC_SAVE_AREA_RESTART, _lowcore, save_area_restart);
- OFFSET(__LC_CPU_FLAGS, _lowcore, cpu_flags);
- OFFSET(__LC_RETURN_PSW, _lowcore, return_psw);
- OFFSET(__LC_RETURN_MCCK_PSW, _lowcore, return_mcck_psw);
- OFFSET(__LC_SYNC_ENTER_TIMER, _lowcore, sync_enter_timer);
- OFFSET(__LC_ASYNC_ENTER_TIMER, _lowcore, async_enter_timer);
- OFFSET(__LC_MCCK_ENTER_TIMER, _lowcore, mcck_enter_timer);
- OFFSET(__LC_EXIT_TIMER, _lowcore, exit_timer);
- OFFSET(__LC_USER_TIMER, _lowcore, user_timer);
- OFFSET(__LC_SYSTEM_TIMER, _lowcore, system_timer);
- OFFSET(__LC_STEAL_TIMER, _lowcore, steal_timer);
- OFFSET(__LC_LAST_UPDATE_TIMER, _lowcore, last_update_timer);
- OFFSET(__LC_LAST_UPDATE_CLOCK, _lowcore, last_update_clock);
- OFFSET(__LC_INT_CLOCK, _lowcore, int_clock);
- OFFSET(__LC_MCCK_CLOCK, _lowcore, mcck_clock);
- OFFSET(__LC_CURRENT, _lowcore, current_task);
- OFFSET(__LC_THREAD_INFO, _lowcore, thread_info);
- OFFSET(__LC_KERNEL_STACK, _lowcore, kernel_stack);
- OFFSET(__LC_ASYNC_STACK, _lowcore, async_stack);
- OFFSET(__LC_PANIC_STACK, _lowcore, panic_stack);
- OFFSET(__LC_RESTART_STACK, _lowcore, restart_stack);
- OFFSET(__LC_RESTART_FN, _lowcore, restart_fn);
- OFFSET(__LC_RESTART_DATA, _lowcore, restart_data);
- OFFSET(__LC_RESTART_SOURCE, _lowcore, restart_source);
- OFFSET(__LC_USER_ASCE, _lowcore, user_asce);
- OFFSET(__LC_LPP, _lowcore, lpp);
- OFFSET(__LC_CURRENT_PID, _lowcore, current_pid);
- OFFSET(__LC_PERCPU_OFFSET, _lowcore, percpu_offset);
- OFFSET(__LC_VDSO_PER_CPU, _lowcore, vdso_per_cpu_data);
- OFFSET(__LC_MACHINE_FLAGS, _lowcore, machine_flags);
- OFFSET(__LC_GMAP, _lowcore, gmap);
- OFFSET(__LC_PASTE, _lowcore, paste);
+ OFFSET(__LC_SAVE_AREA_SYNC, lowcore, save_area_sync);
+ OFFSET(__LC_SAVE_AREA_ASYNC, lowcore, save_area_async);
+ OFFSET(__LC_SAVE_AREA_RESTART, lowcore, save_area_restart);
+ OFFSET(__LC_CPU_FLAGS, lowcore, cpu_flags);
+ OFFSET(__LC_RETURN_PSW, lowcore, return_psw);
+ OFFSET(__LC_RETURN_MCCK_PSW, lowcore, return_mcck_psw);
+ OFFSET(__LC_SYNC_ENTER_TIMER, lowcore, sync_enter_timer);
+ OFFSET(__LC_ASYNC_ENTER_TIMER, lowcore, async_enter_timer);
+ OFFSET(__LC_MCCK_ENTER_TIMER, lowcore, mcck_enter_timer);
+ OFFSET(__LC_EXIT_TIMER, lowcore, exit_timer);
+ OFFSET(__LC_USER_TIMER, lowcore, user_timer);
+ OFFSET(__LC_SYSTEM_TIMER, lowcore, system_timer);
+ OFFSET(__LC_STEAL_TIMER, lowcore, steal_timer);
+ OFFSET(__LC_LAST_UPDATE_TIMER, lowcore, last_update_timer);
+ OFFSET(__LC_LAST_UPDATE_CLOCK, lowcore, last_update_clock);
+ OFFSET(__LC_INT_CLOCK, lowcore, int_clock);
+ OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock);
+ OFFSET(__LC_CURRENT, lowcore, current_task);
+ OFFSET(__LC_THREAD_INFO, lowcore, thread_info);
+ OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack);
+ OFFSET(__LC_ASYNC_STACK, lowcore, async_stack);
+ OFFSET(__LC_PANIC_STACK, lowcore, panic_stack);
+ OFFSET(__LC_RESTART_STACK, lowcore, restart_stack);
+ OFFSET(__LC_RESTART_FN, lowcore, restart_fn);
+ OFFSET(__LC_RESTART_DATA, lowcore, restart_data);
+ OFFSET(__LC_RESTART_SOURCE, lowcore, restart_source);
+ OFFSET(__LC_USER_ASCE, lowcore, user_asce);
+ OFFSET(__LC_LPP, lowcore, lpp);
+ OFFSET(__LC_CURRENT_PID, lowcore, current_pid);
+ OFFSET(__LC_PERCPU_OFFSET, lowcore, percpu_offset);
+ OFFSET(__LC_VDSO_PER_CPU, lowcore, vdso_per_cpu_data);
+ OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags);
+ OFFSET(__LC_GMAP, lowcore, gmap);
+ OFFSET(__LC_PASTE, lowcore, paste);
/* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
- OFFSET(__LC_DUMP_REIPL, _lowcore, ipib);
+ OFFSET(__LC_DUMP_REIPL, lowcore, ipib);
/* hardware defined lowcore locations 0x1000 - 0x18ff */
- OFFSET(__LC_VX_SAVE_AREA_ADDR, _lowcore, vector_save_area_addr);
- OFFSET(__LC_EXT_PARAMS2, _lowcore, ext_params2);
- OFFSET(SAVE_AREA_BASE, _lowcore, floating_pt_save_area);
- OFFSET(__LC_FPREGS_SAVE_AREA, _lowcore, floating_pt_save_area);
- OFFSET(__LC_GPREGS_SAVE_AREA, _lowcore, gpregs_save_area);
- OFFSET(__LC_PSW_SAVE_AREA, _lowcore, psw_save_area);
- OFFSET(__LC_PREFIX_SAVE_AREA, _lowcore, prefixreg_save_area);
- OFFSET(__LC_FP_CREG_SAVE_AREA, _lowcore, fpt_creg_save_area);
- OFFSET(__LC_CPU_TIMER_SAVE_AREA, _lowcore, cpu_timer_save_area);
- OFFSET(__LC_CLOCK_COMP_SAVE_AREA, _lowcore, clock_comp_save_area);
- OFFSET(__LC_AREGS_SAVE_AREA, _lowcore, access_regs_save_area);
- OFFSET(__LC_CREGS_SAVE_AREA, _lowcore, cregs_save_area);
- OFFSET(__LC_PGM_TDB, _lowcore, pgm_tdb);
+ OFFSET(__LC_VX_SAVE_AREA_ADDR, lowcore, vector_save_area_addr);
+ OFFSET(__LC_EXT_PARAMS2, lowcore, ext_params2);
+ OFFSET(__LC_FPREGS_SAVE_AREA, lowcore, floating_pt_save_area);
+ OFFSET(__LC_GPREGS_SAVE_AREA, lowcore, gpregs_save_area);
+ OFFSET(__LC_PSW_SAVE_AREA, lowcore, psw_save_area);
+ OFFSET(__LC_PREFIX_SAVE_AREA, lowcore, prefixreg_save_area);
+ OFFSET(__LC_FP_CREG_SAVE_AREA, lowcore, fpt_creg_save_area);
+ OFFSET(__LC_TOD_PROGREG_SAVE_AREA, lowcore, tod_progreg_save_area);
+ OFFSET(__LC_CPU_TIMER_SAVE_AREA, lowcore, cpu_timer_save_area);
+ OFFSET(__LC_CLOCK_COMP_SAVE_AREA, lowcore, clock_comp_save_area);
+ OFFSET(__LC_AREGS_SAVE_AREA, lowcore, access_regs_save_area);
+ OFFSET(__LC_CREGS_SAVE_AREA, lowcore, cregs_save_area);
+ OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
BLANK();
/* gmap/sie offsets */
OFFSET(__GMAP_ASCE, gmap, asce);
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index 171e09bb8ea2..a92b39fd0e63 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/bootmem.h>
#include <linux/elf.h>
+#include <asm/asm-offsets.h>
#include <linux/memblock.h>
#include <asm/os_info.h>
#include <asm/elf.h>
@@ -32,7 +33,84 @@ static struct memblock_type oldmem_type = {
.regions = &oldmem_region,
};
-struct dump_save_areas dump_save_areas;
+struct save_area {
+ struct list_head list;
+ u64 psw[2];
+ u64 ctrs[16];
+ u64 gprs[16];
+ u32 acrs[16];
+ u64 fprs[16];
+ u32 fpc;
+ u32 prefix;
+ u64 todpreg;
+ u64 timer;
+ u64 todcmp;
+ u64 vxrs_low[16];
+ __vector128 vxrs_high[16];
+};
+
+static LIST_HEAD(dump_save_areas);
+
+/*
+ * Allocate a save area
+ */
+struct save_area * __init save_area_alloc(bool is_boot_cpu)
+{
+ struct save_area *sa;
+
+ sa = (void *) memblock_alloc(sizeof(*sa), 8);
+ if (!sa)
+ return NULL;
+ if (is_boot_cpu)
+ list_add(&sa->list, &dump_save_areas);
+ else
+ list_add_tail(&sa->list, &dump_save_areas);
+ return sa;
+}
+
+/*
+ * Return the address of the save area for the boot CPU
+ */
+struct save_area * __init save_area_boot_cpu(void)
+{
+ if (list_empty(&dump_save_areas))
+ return NULL;
+ return list_first_entry(&dump_save_areas, struct save_area, list);
+}
+
+/*
+ * Copy CPU registers into the save area
+ */
+void __init save_area_add_regs(struct save_area *sa, void *regs)
+{
+ struct lowcore *lc;
+
+ lc = (struct lowcore *)(regs - __LC_FPREGS_SAVE_AREA);
+ memcpy(&sa->psw, &lc->psw_save_area, sizeof(sa->psw));
+ memcpy(&sa->ctrs, &lc->cregs_save_area, sizeof(sa->ctrs));
+ memcpy(&sa->gprs, &lc->gpregs_save_area, sizeof(sa->gprs));
+ memcpy(&sa->acrs, &lc->access_regs_save_area, sizeof(sa->acrs));
+ memcpy(&sa->fprs, &lc->floating_pt_save_area, sizeof(sa->fprs));
+ memcpy(&sa->fpc, &lc->fpt_creg_save_area, sizeof(sa->fpc));
+ memcpy(&sa->prefix, &lc->prefixreg_save_area, sizeof(sa->prefix));
+ memcpy(&sa->todpreg, &lc->tod_progreg_save_area, sizeof(sa->todpreg));
+ memcpy(&sa->timer, &lc->cpu_timer_save_area, sizeof(sa->timer));
+ memcpy(&sa->todcmp, &lc->clock_comp_save_area, sizeof(sa->todcmp));
+}
+
+/*
+ * Copy vector registers into the save area
+ */
+void __init save_area_add_vxrs(struct save_area *sa, __vector128 *vxrs)
+{
+ int i;
+
+ /* Copy lower halves of vector registers 0-15 */
+ for (i = 0; i < 16; i++)
+ memcpy(&sa->vxrs_low[i], &vxrs[i].u[2], 8);
+ /* Copy vector registers 16-31 */
+ memcpy(sa->vxrs_high, vxrs + 16, 16 * sizeof(__vector128));
+}
/*
* Return physical address for virtual address
@@ -51,79 +129,85 @@ static inline void *load_real_addr(void *addr)
}
/*
- * Copy real to virtual or real memory
- */
-static int copy_from_realmem(void *dest, void *src, size_t count)
-{
- unsigned long size;
-
- if (!count)
- return 0;
- if (!is_vmalloc_or_module_addr(dest))
- return memcpy_real(dest, src, count);
- do {
- size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK));
- if (memcpy_real(load_real_addr(dest), src, size))
- return -EFAULT;
- count -= size;
- dest += size;
- src += size;
- } while (count);
- return 0;
-}
-
-/*
- * Pointer to ELF header in new kernel
- */
-static void *elfcorehdr_newmem;
-
-/*
- * Copy one page from zfcpdump "oldmem"
- *
- * For pages below HSA size memory from the HSA is copied. Otherwise
- * real memory copy is used.
+ * Copy memory of the old, dumped system to a kernel space virtual address
*/
-static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
- unsigned long src, int userbuf)
+int copy_oldmem_kernel(void *dst, void *src, size_t count)
{
+ unsigned long from, len;
+ void *ra;
int rc;
- if (src < sclp.hsa_size) {
- rc = memcpy_hsa(buf, src, csize, userbuf);
- } else {
- if (userbuf)
- rc = copy_to_user_real((void __force __user *) buf,
- (void *) src, csize);
- else
- rc = memcpy_real(buf, (void *) src, csize);
+ while (count) {
+ from = __pa(src);
+ if (!OLDMEM_BASE && from < sclp.hsa_size) {
+ /* Copy from zfcpdump HSA area */
+ len = min(count, sclp.hsa_size - from);
+ rc = memcpy_hsa_kernel(dst, from, len);
+ if (rc)
+ return rc;
+ } else {
+ /* Check for swapped kdump oldmem areas */
+ if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) {
+ from -= OLDMEM_BASE;
+ len = min(count, OLDMEM_SIZE - from);
+ } else if (OLDMEM_BASE && from < OLDMEM_SIZE) {
+ len = min(count, OLDMEM_SIZE - from);
+ from += OLDMEM_BASE;
+ } else {
+ len = count;
+ }
+ if (is_vmalloc_or_module_addr(dst)) {
+ ra = load_real_addr(dst);
+ len = min(PAGE_SIZE - offset_in_page(ra), len);
+ } else {
+ ra = dst;
+ }
+ if (memcpy_real(ra, (void *) from, len))
+ return -EFAULT;
+ }
+ dst += len;
+ src += len;
+ count -= len;
}
- return rc ? rc : csize;
+ return 0;
}
/*
- * Copy one page from kdump "oldmem"
- *
- * For the kdump reserved memory this functions performs a swap operation:
- * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
- * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
+ * Copy memory of the old, dumped system to a user space virtual address
*/
-static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
- unsigned long src, int userbuf)
-
+int copy_oldmem_user(void __user *dst, void *src, size_t count)
{
+ unsigned long from, len;
int rc;
- if (src < OLDMEM_SIZE)
- src += OLDMEM_BASE;
- else if (src > OLDMEM_BASE &&
- src < OLDMEM_BASE + OLDMEM_SIZE)
- src -= OLDMEM_BASE;
- if (userbuf)
- rc = copy_to_user_real((void __force __user *) buf,
- (void *) src, csize);
- else
- rc = copy_from_realmem(buf, (void *) src, csize);
- return (rc == 0) ? rc : csize;
+ while (count) {
+ from = __pa(src);
+ if (!OLDMEM_BASE && from < sclp.hsa_size) {
+ /* Copy from zfcpdump HSA area */
+ len = min(count, sclp.hsa_size - from);
+ rc = memcpy_hsa_user(dst, from, len);
+ if (rc)
+ return rc;
+ } else {
+ /* Check for swapped kdump oldmem areas */
+ if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) {
+ from -= OLDMEM_BASE;
+ len = min(count, OLDMEM_SIZE - from);
+ } else if (OLDMEM_BASE && from < OLDMEM_SIZE) {
+ len = min(count, OLDMEM_SIZE - from);
+ from += OLDMEM_BASE;
+ } else {
+ len = count;
+ }
+ rc = copy_to_user_real(dst, (void *) from, count);
+ if (rc)
+ return rc;
+ }
+ dst += len;
+ src += len;
+ count -= len;
+ }
+ return 0;
}
/*
@@ -132,15 +216,17 @@ static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
unsigned long offset, int userbuf)
{
- unsigned long src;
+ void *src;
+ int rc;
if (!csize)
return 0;
- src = (pfn << PAGE_SHIFT) + offset;
- if (OLDMEM_BASE)
- return copy_oldmem_page_kdump(buf, csize, src, userbuf);
+ src = (void *) (pfn << PAGE_SHIFT) + offset;
+ if (userbuf)
+ rc = copy_oldmem_user((void __force __user *) buf, src, csize);
else
- return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf);
+ rc = copy_oldmem_kernel((void *) buf, src, csize);
+ return rc;
}
/*
@@ -209,33 +295,6 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
}
/*
- * Copy memory from old kernel
- */
-int copy_from_oldmem(void *dest, void *src, size_t count)
-{
- unsigned long copied = 0;
- int rc;
-
- if (OLDMEM_BASE) {
- if ((unsigned long) src < OLDMEM_SIZE) {
- copied = min(count, OLDMEM_SIZE - (unsigned long) src);
- rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied);
- if (rc)
- return rc;
- }
- } else {
- unsigned long hsa_end = sclp.hsa_size;
- if ((unsigned long) src < hsa_end) {
- copied = min(count, hsa_end - (unsigned long) src);
- rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
- if (rc)
- return rc;
- }
- }
- return copy_from_realmem(dest + copied, src + copied, count - copied);
-}
-
-/*
* Alloc memory and panic in case of ENOMEM
*/
static void *kzalloc_panic(int len)
@@ -251,8 +310,8 @@ static void *kzalloc_panic(int len)
/*
* Initialize ELF note
*/
-static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
- const char *name)
+static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len,
+ const char *name)
{
Elf64_Nhdr *note;
u64 len;
@@ -272,136 +331,42 @@ static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
return PTR_ADD(buf, len);
}
-/*
- * Initialize prstatus note
- */
-static void *nt_prstatus(void *ptr, struct save_area *sa)
+static inline void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len)
{
- struct elf_prstatus nt_prstatus;
- static int cpu_nr = 1;
-
- memset(&nt_prstatus, 0, sizeof(nt_prstatus));
- memcpy(&nt_prstatus.pr_reg.gprs, sa->gp_regs, sizeof(sa->gp_regs));
- memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw));
- memcpy(&nt_prstatus.pr_reg.acrs, sa->acc_regs, sizeof(sa->acc_regs));
- nt_prstatus.pr_pid = cpu_nr;
- cpu_nr++;
-
- return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
- "CORE");
+ return nt_init_name(buf, type, desc, d_len, KEXEC_CORE_NOTE_NAME);
}
/*
- * Initialize fpregset (floating point) note
+ * Fill ELF notes for one CPU with save area registers
*/
-static void *nt_fpregset(void *ptr, struct save_area *sa)
+static void *fill_cpu_elf_notes(void *ptr, int cpu, struct save_area *sa)
{
+ struct elf_prstatus nt_prstatus;
elf_fpregset_t nt_fpregset;
+ /* Prepare prstatus note */
+ memset(&nt_prstatus, 0, sizeof(nt_prstatus));
+ memcpy(&nt_prstatus.pr_reg.gprs, sa->gprs, sizeof(sa->gprs));
+ memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw));
+ memcpy(&nt_prstatus.pr_reg.acrs, sa->acrs, sizeof(sa->acrs));
+ nt_prstatus.pr_pid = cpu;
+ /* Prepare fpregset (floating point) note */
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
- memcpy(&nt_fpregset.fpc, &sa->fp_ctrl_reg, sizeof(sa->fp_ctrl_reg));
- memcpy(&nt_fpregset.fprs, &sa->fp_regs, sizeof(sa->fp_regs));
-
- return nt_init(ptr, NT_PRFPREG, &nt_fpregset, sizeof(nt_fpregset),
- "CORE");
-}
-
-/*
- * Initialize timer note
- */
-static void *nt_s390_timer(void *ptr, struct save_area *sa)
-{
- return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer),
- KEXEC_CORE_NOTE_NAME);
-}
-
-/*
- * Initialize TOD clock comparator note
- */
-static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
-{
- return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp,
- sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME);
-}
-
-/*
- * Initialize TOD programmable register note
- */
-static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
-{
- return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg,
- sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME);
-}
-
-/*
- * Initialize control register note
- */
-static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
-{
- return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs,
- sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME);
-}
-
-/*
- * Initialize prefix register note
- */
-static void *nt_s390_prefix(void *ptr, struct save_area *sa)
-{
- return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg,
- sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
-}
-
-/*
- * Initialize vxrs high note (full 128 bit VX registers 16-31)
- */
-static void *nt_s390_vx_high(void *ptr, __vector128 *vx_regs)
-{
- return nt_init(ptr, NT_S390_VXRS_HIGH, &vx_regs[16],
- 16 * sizeof(__vector128), KEXEC_CORE_NOTE_NAME);
-}
-
-/*
- * Initialize vxrs low note (lower halves of VX registers 0-15)
- */
-static void *nt_s390_vx_low(void *ptr, __vector128 *vx_regs)
-{
- Elf64_Nhdr *note;
- u64 len;
- int i;
-
- note = (Elf64_Nhdr *)ptr;
- note->n_namesz = strlen(KEXEC_CORE_NOTE_NAME) + 1;
- note->n_descsz = 16 * 8;
- note->n_type = NT_S390_VXRS_LOW;
- len = sizeof(Elf64_Nhdr);
-
- memcpy(ptr + len, KEXEC_CORE_NOTE_NAME, note->n_namesz);
- len = roundup(len + note->n_namesz, 4);
-
- ptr += len;
- /* Copy lower halves of SIMD registers 0-15 */
- for (i = 0; i < 16; i++) {
- memcpy(ptr, &vx_regs[i].u[2], 8);
- ptr += 8;
- }
- return ptr;
-}
-
-/*
- * Fill ELF notes for one CPU with save area registers
- */
-void *fill_cpu_elf_notes(void *ptr, struct save_area *sa, __vector128 *vx_regs)
-{
- ptr = nt_prstatus(ptr, sa);
- ptr = nt_fpregset(ptr, sa);
- ptr = nt_s390_timer(ptr, sa);
- ptr = nt_s390_tod_cmp(ptr, sa);
- ptr = nt_s390_tod_preg(ptr, sa);
- ptr = nt_s390_ctrs(ptr, sa);
- ptr = nt_s390_prefix(ptr, sa);
- if (MACHINE_HAS_VX && vx_regs) {
- ptr = nt_s390_vx_low(ptr, vx_regs);
- ptr = nt_s390_vx_high(ptr, vx_regs);
+ memcpy(&nt_fpregset.fpc, &sa->fpc, sizeof(sa->fpc));
+ memcpy(&nt_fpregset.fprs, &sa->fprs, sizeof(sa->fprs));
+ /* Create ELF notes for the CPU */
+ ptr = nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus));
+ ptr = nt_init(ptr, NT_PRFPREG, &nt_fpregset, sizeof(nt_fpregset));
+ ptr = nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer));
+ ptr = nt_init(ptr, NT_S390_TODCMP, &sa->todcmp, sizeof(sa->todcmp));
+ ptr = nt_init(ptr, NT_S390_TODPREG, &sa->todpreg, sizeof(sa->todpreg));
+ ptr = nt_init(ptr, NT_S390_CTRS, &sa->ctrs, sizeof(sa->ctrs));
+ ptr = nt_init(ptr, NT_S390_PREFIX, &sa->prefix, sizeof(sa->prefix));
+ if (MACHINE_HAS_VX) {
+ ptr = nt_init(ptr, NT_S390_VXRS_HIGH,
+ &sa->vxrs_high, sizeof(sa->vxrs_high));
+ ptr = nt_init(ptr, NT_S390_VXRS_LOW,
+ &sa->vxrs_low, sizeof(sa->vxrs_low));
}
return ptr;
}
@@ -416,8 +381,7 @@ static void *nt_prpsinfo(void *ptr)
memset(&prpsinfo, 0, sizeof(prpsinfo));
prpsinfo.pr_sname = 'R';
strcpy(prpsinfo.pr_fname, "vmlinux");
- return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo),
- KEXEC_CORE_NOTE_NAME);
+ return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo));
}
/*
@@ -429,17 +393,18 @@ static void *get_vmcoreinfo_old(unsigned long *size)
Elf64_Nhdr note;
void *addr;
- if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
+ if (copy_oldmem_kernel(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
return NULL;
memset(nt_name, 0, sizeof(nt_name));
- if (copy_from_oldmem(&note, addr, sizeof(note)))
+ if (copy_oldmem_kernel(&note, addr, sizeof(note)))
return NULL;
- if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1))
+ if (copy_oldmem_kernel(nt_name, addr + sizeof(note),
+ sizeof(nt_name) - 1))
return NULL;
if (strcmp(nt_name, "VMCOREINFO") != 0)
return NULL;
vmcoreinfo = kzalloc_panic(note.n_descsz);
- if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz))
+ if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz))
return NULL;
*size = note.n_descsz;
return vmcoreinfo;
@@ -458,7 +423,7 @@ static void *nt_vmcoreinfo(void *ptr)
vmcoreinfo = get_vmcoreinfo_old(&size);
if (!vmcoreinfo)
return ptr;
- return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
+ return nt_init_name(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
}
/*
@@ -487,13 +452,12 @@ static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
*/
static int get_cpu_cnt(void)
{
- int i, cpus = 0;
+ struct save_area *sa;
+ int cpus = 0;
- for (i = 0; i < dump_save_areas.count; i++) {
- if (dump_save_areas.areas[i]->sa.pref_reg == 0)
- continue;
- cpus++;
- }
+ list_for_each_entry(sa, &dump_save_areas, list)
+ if (sa->prefix != 0)
+ cpus++;
return cpus;
}
@@ -538,18 +502,16 @@ static void loads_init(Elf64_Phdr *phdr, u64 loads_offset)
*/
static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
{
- struct save_area_ext *sa_ext;
+ struct save_area *sa;
void *ptr_start = ptr;
- int i;
+ int cpu;
ptr = nt_prpsinfo(ptr);
- for (i = 0; i < dump_save_areas.count; i++) {
- sa_ext = dump_save_areas.areas[i];
- if (sa_ext->sa.pref_reg == 0)
- continue;
- ptr = fill_cpu_elf_notes(ptr, &sa_ext->sa, sa_ext->vx_regs);
- }
+ cpu = 1;
+ list_for_each_entry(sa, &dump_save_areas, list)
+ if (sa->prefix != 0)
+ ptr = fill_cpu_elf_notes(ptr, cpu++, sa);
ptr = nt_vmcoreinfo(ptr);
memset(phdr, 0, sizeof(*phdr));
phdr->p_type = PT_NOTE;
@@ -573,9 +535,6 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
/* If we are not in kdump or zfcpdump mode return */
if (!OLDMEM_BASE && ipl_info.type != IPL_TYPE_FCP_DUMP)
return 0;
- /* If elfcorehdr= has been passed via cmdline, we use that one */
- if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
- return 0;
/* If we cannot get HSA size for zfcpdump return error */
if (ipl_info.type == IPL_TYPE_FCP_DUMP && !sclp.hsa_size)
return -ENODEV;
@@ -606,7 +565,6 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
hdr_off = PTR_DIFF(ptr, hdr);
loads_init(phdr_loads, hdr_off);
*addr = (unsigned long long) hdr;
- elfcorehdr_newmem = hdr;
*size = (unsigned long long) hdr_off;
BUG_ON(elfcorehdr_size > alloc_size);
return 0;
@@ -617,8 +575,6 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
*/
void elfcorehdr_free(unsigned long long addr)
{
- if (!elfcorehdr_newmem)
- return;
kfree((void *)(unsigned long)addr);
}
@@ -629,7 +585,6 @@ ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
{
void *src = (void *)(unsigned long)*ppos;
- src = elfcorehdr_newmem ? src : src - OLDMEM_BASE;
memcpy(buf, src, count);
*ppos += count;
return count;
@@ -641,15 +596,8 @@ ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
{
void *src = (void *)(unsigned long)*ppos;
- int rc;
- if (elfcorehdr_newmem) {
- memcpy(buf, src, count);
- } else {
- rc = copy_from_oldmem(buf, src, count);
- if (rc)
- return rc;
- }
+ memcpy(buf, src, count);
*ppos += count;
return count;
}
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 6e72961608f0..62973efd214a 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -2022,7 +2022,7 @@ void show_code(struct pt_regs *regs)
*ptr++ = '\t';
ptr += print_insn(ptr, code + start, addr);
start += opsize;
- printk(buffer);
+ printk("%s", buffer);
ptr = buffer;
ptr += sprintf(ptr, "\n ");
hops++;
@@ -2049,7 +2049,7 @@ void print_fn_code(unsigned char *code, unsigned long len)
ptr += print_insn(ptr, code, (unsigned long) code);
*ptr++ = '\n';
*ptr++ = 0;
- printk(buffer);
+ printk("%s", buffer);
code += opsize;
len -= opsize;
}
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 3c31609df959..20a5caf6d981 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -335,6 +335,14 @@ static __init void detect_machine_facilities(void)
}
}
+static inline void save_vector_registers(void)
+{
+#ifdef CONFIG_CRASH_DUMP
+ if (test_facility(129))
+ save_vx_regs(boot_cpu_vector_save_area);
+#endif
+}
+
static int __init disable_vector_extension(char *str)
{
S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
@@ -451,6 +459,7 @@ void __init startup_init(void)
detect_diag9c();
detect_diag44();
detect_machine_facilities();
+ save_vector_registers();
setup_topology();
sclp_early_detect();
lockdep_on();
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 857b6526d298..cd5a191381b9 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -764,6 +764,7 @@ ENTRY(psw_idle)
.insn rsy,0xeb0000000017,%r1,5,__SF_EMPTY+16(%r15)
.Lpsw_idle_stcctm:
#endif
+ oi __LC_CPU_FLAGS+7,_CIF_ENABLED_WAIT
STCK __CLOCK_IDLE_ENTER(%r2)
stpt __TIMER_IDLE_ENTER(%r2)
.Lpsw_idle_lpsw:
@@ -1146,6 +1147,7 @@ cleanup_critical:
.quad .Lio_done - 4
.Lcleanup_idle:
+ ni __LC_CPU_FLAGS+7,255-_CIF_ENABLED_WAIT
# copy interrupt clock & cpu timer
mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK
mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 301ee9c70688..fcaefb041364 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -25,6 +25,7 @@
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
+#include <asm/facility.h>
#include <asm/page.h>
#include <asm/ptrace.h>
@@ -300,27 +301,27 @@ ENTRY(startup_kdump)
xc 0x200(256),0x200 # partially clear lowcore
xc 0x300(256),0x300
xc 0xe00(256),0xe00
+ xc 0xf00(256),0xf00
lctlg %c0,%c15,0x200(%r0) # initialize control registers
stck __LC_LAST_UPDATE_CLOCK
spt 6f-.LPG0(%r13)
mvc __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13)
- xc __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST
- # check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10}
- .insn s,0xb2b10000,0 # store facilities @ __LC_STFL_FAC_LIST
- tm __LC_STFL_FAC_LIST,0x01 # stfle available ?
+ stfl 0(%r0) # store facilities @ __LC_STFL_FAC_LIST
+ mvc __LC_STFLE_FAC_LIST(4),__LC_STFL_FAC_LIST
+ tm __LC_STFLE_FAC_LIST,0x01 # stfle available ?
jz 0f
- la %r0,1
- .insn s,0xb2b00000,__LC_STFL_FAC_LIST # store facility list extended
+ lghi %r0,FACILITIES_ALS_DWORDS-1
+ .insn s,0xb2b00000,__LC_STFLE_FAC_LIST # store facility list extended
# verify if all required facilities are supported by the machine
-0: la %r1,__LC_STFL_FAC_LIST
+0: la %r1,__LC_STFLE_FAC_LIST
la %r2,3f+8-.LPG0(%r13)
- l %r3,0(%r2)
-1: l %r0,0(%r1)
- n %r0,4(%r2)
- cl %r0,4(%r2)
+ lhi %r3,FACILITIES_ALS_DWORDS
+1: lg %r0,0(%r1)
+ ng %r0,0(%r2)
+ clg %r0,0(%r2)
jne 2f
- la %r1,4(%r1)
- la %r2,4(%r2)
+ la %r1,8(%r1)
+ la %r2,8(%r2)
ahi %r3,-1
jnz 1b
j 4f
@@ -340,24 +341,10 @@ ENTRY(startup_kdump)
3: .long 0x000a0000,0x8badcccc
# List of facilities that are required. If not all facilities are present
-# the kernel will crash. Format is number of facility words with bits set,
-# followed by the facility words.
+# the kernel will crash.
+
+ .quad FACILITIES_ALS
-#if defined(CONFIG_MARCH_Z13)
- .long 2, 0xc100eff2, 0xf46cc800
-#elif defined(CONFIG_MARCH_ZEC12)
- .long 2, 0xc100eff2, 0xf46cc800
-#elif defined(CONFIG_MARCH_Z196)
- .long 2, 0xc100eff2, 0xf46c0000
-#elif defined(CONFIG_MARCH_Z10)
- .long 2, 0xc100eff2, 0xf0680000
-#elif defined(CONFIG_MARCH_Z9_109)
- .long 1, 0xc100efc2
-#elif defined(CONFIG_MARCH_Z990)
- .long 1, 0xc0002000
-#elif defined(CONFIG_MARCH_Z900)
- .long 1, 0xc0000000
-#endif
4:
/* Continue with startup code in head64.S */
jg startup_continue
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 58b719fa8067..c5febe84eba6 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -16,7 +16,7 @@
__HEAD
ENTRY(startup_continue)
- tm __LC_STFL_FAC_LIST+6,0x80 # LPP available ?
+ tm __LC_STFLE_FAC_LIST+6,0x80 # LPP available ?
jz 0f
xc __LC_LPP+1(7,0),__LC_LPP+1 # clear lpp and current_pid
mvi __LC_LPP,0x80 # and set LPP_MAGIC
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index b1f0a90f933b..0a5a6b661b93 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -2039,21 +2039,15 @@ static void do_reset_calls(void)
reset->fn();
}
-u32 dump_prefix_page;
-
-void s390_reset_system(void (*fn_pre)(void),
- void (*fn_post)(void *), void *data)
+void s390_reset_system(void)
{
- struct _lowcore *lc;
+ struct lowcore *lc;
- lc = (struct _lowcore *)(unsigned long) store_prefix();
+ lc = (struct lowcore *)(unsigned long) store_prefix();
/* Stack for interrupt/machine check handler */
lc->panic_stack = S390_lowcore.panic_stack;
- /* Save prefix page address for dump case */
- dump_prefix_page = (u32)(unsigned long) lc;
-
/* Disable prefixing */
set_prefix(0);
@@ -2077,14 +2071,5 @@ void s390_reset_system(void (*fn_pre)(void),
S390_lowcore.subchannel_id = 0;
S390_lowcore.subchannel_nr = 0;
- /* Store status at absolute zero */
- store_status();
-
- /* Call function before reset */
- if (fn_pre)
- fn_pre();
do_reset_calls();
- /* Call function after reset */
- if (fn_post)
- fn_post(data);
}
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index fb0901ec4306..2f1b7217c25c 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -35,46 +35,6 @@ extern const unsigned long long relocate_kernel_len;
#ifdef CONFIG_CRASH_DUMP
/*
- * Create ELF notes for one CPU
- */
-static void add_elf_notes(int cpu)
-{
- struct save_area *sa = (void *) 4608 + store_prefix();
- void *ptr;
-
- memcpy((void *) (4608UL + sa->pref_reg), sa, sizeof(*sa));
- ptr = (u64 *) per_cpu_ptr(crash_notes, cpu);
- ptr = fill_cpu_elf_notes(ptr, sa, NULL);
- memset(ptr, 0, sizeof(struct elf_note));
-}
-
-/*
- * Initialize CPU ELF notes
- */
-static void setup_regs(void)
-{
- unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE;
- struct _lowcore *lc;
- int cpu, this_cpu;
-
- /* Get lowcore pointer from store status of this CPU (absolute zero) */
- lc = (struct _lowcore *)(unsigned long)S390_lowcore.prefixreg_save_area;
- this_cpu = smp_find_processor_id(stap());
- add_elf_notes(this_cpu);
- for_each_online_cpu(cpu) {
- if (cpu == this_cpu)
- continue;
- if (smp_store_status(cpu))
- continue;
- add_elf_notes(cpu);
- }
- if (MACHINE_HAS_VX)
- save_vx_regs_safe((void *) lc->vector_save_area_addr);
- /* Copy dump CPU store status info to absolute zero */
- memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area));
-}
-
-/*
* PM notifier callback for kdump
*/
static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action,
@@ -105,14 +65,66 @@ static int __init machine_kdump_pm_init(void)
arch_initcall(machine_kdump_pm_init);
/*
- * Start kdump: We expect here that a store status has been done on our CPU
+ * Reset the system, copy boot CPU registers to absolute zero,
+ * and jump to the kdump image
*/
static void __do_machine_kdump(void *image)
{
- int (*start_kdump)(int) = (void *)((struct kimage *) image)->start;
+ int (*start_kdump)(int);
+ unsigned long prefix;
+
+ /* store_status() saved the prefix register to lowcore */
+ prefix = (unsigned long) S390_lowcore.prefixreg_save_area;
+
+ /* Now do the reset */
+ s390_reset_system();
+
+ /*
+ * Copy dump CPU store status info to absolute zero.
+ * This need to be done *after* s390_reset_system set the
+ * prefix register of this CPU to zero
+ */
+ memcpy((void *) __LC_FPREGS_SAVE_AREA,
+ (void *)(prefix + __LC_FPREGS_SAVE_AREA), 512);
__load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA);
+ start_kdump = (void *)((struct kimage *) image)->start;
start_kdump(1);
+
+ /* Die if start_kdump returns */
+ disabled_wait((unsigned long) __builtin_return_address(0));
+}
+
+/*
+ * Start kdump: create a LGR log entry, store status of all CPUs and
+ * branch to __do_machine_kdump.
+ */
+static noinline void __machine_kdump(void *image)
+{
+ int this_cpu, cpu;
+
+ lgr_info_log();
+ /* Get status of the other CPUs */
+ this_cpu = smp_find_processor_id(stap());
+ for_each_online_cpu(cpu) {
+ if (cpu == this_cpu)
+ continue;
+ if (smp_store_status(cpu))
+ continue;
+ }
+ /* Store status of the boot CPU */
+ if (MACHINE_HAS_VX)
+ save_vx_regs((void *) &S390_lowcore.vector_save_area);
+ /*
+ * To create a good backchain for this CPU in the dump store_status
+ * is passed the address of a function. The address is saved into
+ * the PSW save area of the boot CPU and the function is invoked as
+ * a tail call of store_status. The backchain in the dump will look
+ * like this:
+ * restart_int_handler -> __machine_kexec -> __do_machine_kdump
+ * The call to store_status() will not return.
+ */
+ store_status(__do_machine_kdump, image);
}
#endif
@@ -235,10 +247,14 @@ static void __do_machine_kexec(void *data)
relocate_kernel_t data_mover;
struct kimage *image = data;
+ s390_reset_system();
data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page);
/* Call the moving routine */
(*data_mover)(&image->head, image->start);
+
+ /* Die if kexec returns */
+ disabled_wait((unsigned long) __builtin_return_address(0));
}
/*
@@ -251,14 +267,10 @@ static void __machine_kexec(void *data)
tracing_off();
debug_locks_off();
#ifdef CONFIG_CRASH_DUMP
- if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) {
-
- lgr_info_log();
- s390_reset_system(setup_regs, __do_machine_kdump, data);
- } else
+ if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH)
+ __machine_kdump(data);
#endif
- s390_reset_system(NULL, __do_machine_kexec, data);
- disabled_wait((unsigned long) __builtin_return_address(0));
+ __do_machine_kexec(data);
}
/*
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 0c1a679314dd..7873e171457c 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -159,11 +159,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
/* Increase core size by size of got & plt and set start
offsets for got and plt. */
- me->core_size = ALIGN(me->core_size, 4);
- me->arch.got_offset = me->core_size;
- me->core_size += me->arch.got_size;
- me->arch.plt_offset = me->core_size;
- me->core_size += me->arch.plt_size;
+ me->core_layout.size = ALIGN(me->core_layout.size, 4);
+ me->arch.got_offset = me->core_layout.size;
+ me->core_layout.size += me->arch.got_size;
+ me->arch.plt_offset = me->core_layout.size;
+ me->core_layout.size += me->arch.plt_size;
return 0;
}
@@ -279,7 +279,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
if (info->got_initialized == 0) {
Elf_Addr *gotent;
- gotent = me->module_core + me->arch.got_offset +
+ gotent = me->core_layout.base + me->arch.got_offset +
info->got_offset;
*gotent = val;
info->got_initialized = 1;
@@ -302,7 +302,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
rc = apply_rela_bits(loc, val, 0, 64, 0);
else if (r_type == R_390_GOTENT ||
r_type == R_390_GOTPLTENT) {
- val += (Elf_Addr) me->module_core - loc;
+ val += (Elf_Addr) me->core_layout.base - loc;
rc = apply_rela_bits(loc, val, 1, 32, 1);
}
break;
@@ -315,7 +315,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
if (info->plt_initialized == 0) {
unsigned int *ip;
- ip = me->module_core + me->arch.plt_offset +
+ ip = me->core_layout.base + me->arch.plt_offset +
info->plt_offset;
ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
ip[1] = 0x100a0004;
@@ -334,7 +334,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val - loc + 0xffffUL < 0x1ffffeUL) ||
(r_type == R_390_PLT32DBL &&
val - loc + 0xffffffffULL < 0x1fffffffeULL)))
- val = (Elf_Addr) me->module_core +
+ val = (Elf_Addr) me->core_layout.base +
me->arch.plt_offset +
info->plt_offset;
val += rela->r_addend - loc;
@@ -356,7 +356,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_GOTOFF32: /* 32 bit offset to GOT. */
case R_390_GOTOFF64: /* 64 bit offset to GOT. */
val = val + rela->r_addend -
- ((Elf_Addr) me->module_core + me->arch.got_offset);
+ ((Elf_Addr) me->core_layout.base + me->arch.got_offset);
if (r_type == R_390_GOTOFF16)
rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_GOTOFF32)
@@ -366,7 +366,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
- val = (Elf_Addr) me->module_core + me->arch.got_offset +
+ val = (Elf_Addr) me->core_layout.base + me->arch.got_offset +
rela->r_addend - loc;
if (r_type == R_390_GOTPC)
rc = apply_rela_bits(loc, val, 1, 32, 0);
diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c
index d112fc66f993..87f05e475ae8 100644
--- a/arch/s390/kernel/os_info.c
+++ b/arch/s390/kernel/os_info.c
@@ -89,7 +89,7 @@ static void os_info_old_alloc(int nr, int align)
goto fail;
}
buf_align = PTR_ALIGN(buf, align);
- if (copy_from_oldmem(buf_align, (void *) addr, size)) {
+ if (copy_oldmem_kernel(buf_align, (void *) addr, size)) {
msg = "copy failed";
goto fail_free;
}
@@ -122,14 +122,15 @@ static void os_info_old_init(void)
return;
if (!OLDMEM_BASE)
goto fail;
- if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr)))
+ if (copy_oldmem_kernel(&addr, &S390_lowcore.os_info, sizeof(addr)))
goto fail;
if (addr == 0 || addr % PAGE_SIZE)
goto fail;
os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
if (!os_info_old)
goto fail;
- if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old)))
+ if (copy_oldmem_kernel(os_info_old, (void *) addr,
+ sizeof(*os_info_old)))
goto fail_free;
if (os_info_old->magic != OS_INFO_MAGIC)
goto fail_free;
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index 52aab0bd84f8..89ea8c213d82 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -9,60 +9,66 @@
#include <asm/sigp.h>
#
-# store_status
+# Issue "store status" for the current CPU to its prefix page
+# and call passed function afterwards
#
-# Prerequisites to run this function:
-# - Prefix register is set to zero
-# - Original prefix register is stored in "dump_prefix_page"
-# - Lowcore protection is off
+# r2 = Function to be called after store status
+# r3 = Parameter for function
#
ENTRY(store_status)
/* Save register one and load save area base */
stg %r1,__LC_SAVE_AREA_RESTART
- lghi %r1,SAVE_AREA_BASE
/* General purpose registers */
- stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- lg %r2,__LC_SAVE_AREA_RESTART
- stg %r2,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE+8(%r1)
+ lghi %r1,__LC_GPREGS_SAVE_AREA
+ stmg %r0,%r15,0(%r1)
+ mvc 8(8,%r1),__LC_SAVE_AREA_RESTART
/* Control registers */
- stctg %c0,%c15,__LC_CREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+ lghi %r1,__LC_CREGS_SAVE_AREA
+ stctg %c0,%c15,0(%r1)
/* Access registers */
- stam %a0,%a15,__LC_AREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+ lghi %r1,__LC_AREGS_SAVE_AREA
+ stam %a0,%a15,0(%r1)
/* Floating point registers */
- std %f0, 0x00 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f1, 0x08 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f2, 0x10 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f3, 0x18 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f4, 0x20 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f5, 0x28 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f6, 0x30 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f7, 0x38 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f8, 0x40 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f9, 0x48 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f10,0x50 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f11,0x58 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f12,0x60 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f13,0x68 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f14,0x70 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
- std %f15,0x78 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
+ lghi %r1,__LC_FPREGS_SAVE_AREA
+ std %f0, 0x00(%r1)
+ std %f1, 0x08(%r1)
+ std %f2, 0x10(%r1)
+ std %f3, 0x18(%r1)
+ std %f4, 0x20(%r1)
+ std %f5, 0x28(%r1)
+ std %f6, 0x30(%r1)
+ std %f7, 0x38(%r1)
+ std %f8, 0x40(%r1)
+ std %f9, 0x48(%r1)
+ std %f10,0x50(%r1)
+ std %f11,0x58(%r1)
+ std %f12,0x60(%r1)
+ std %f13,0x68(%r1)
+ std %f14,0x70(%r1)
+ std %f15,0x78(%r1)
/* Floating point control register */
- stfpc __LC_FP_CREG_SAVE_AREA-SAVE_AREA_BASE(%r1)
+ lghi %r1,__LC_FP_CREG_SAVE_AREA
+ stfpc 0(%r1)
/* CPU timer */
- stpt __LC_CPU_TIMER_SAVE_AREA-SAVE_AREA_BASE(%r1)
- /* Saved prefix register */
- larl %r2,dump_prefix_page
- mvc __LC_PREFIX_SAVE_AREA-SAVE_AREA_BASE(4,%r1),0(%r2)
+ lghi %r1,__LC_CPU_TIMER_SAVE_AREA
+ stpt 0(%r1)
+ /* Store prefix register */
+ lghi %r1,__LC_PREFIX_SAVE_AREA
+ stpx 0(%r1)
/* Clock comparator - seven bytes */
- larl %r2,.Lclkcmp
- stckc 0(%r2)
- mvc __LC_CLOCK_COMP_SAVE_AREA-SAVE_AREA_BASE + 1(7,%r1),1(%r2)
+ lghi %r1,__LC_CLOCK_COMP_SAVE_AREA
+ larl %r4,.Lclkcmp
+ stckc 0(%r4)
+ mvc 1(7,%r1),1(%r4)
/* Program status word */
- epsw %r2,%r3
- st %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 0(%r1)
- st %r3,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 4(%r1)
- larl %r2,store_status
- stg %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 8(%r1)
- br %r14
+ lghi %r1,__LC_PSW_SAVE_AREA
+ epsw %r4,%r5
+ st %r4,0(%r1)
+ st %r5,4(%r1)
+ stg %r2,8(%r1)
+ lgr %r1,%r2
+ lgr %r2,%r3
+ br %r1
.section .bss
.align 8
@@ -77,9 +83,11 @@ ENTRY(store_status)
ENTRY(do_reipl_asm)
basr %r13,0
.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
-.Lpg1: brasl %r14,store_status
+.Lpg1: lgr %r3,%r2
+ larl %r2,.Lstatus
+ brasl %r14,store_status
- lctlg %c6,%c6,.Lall-.Lpg0(%r13)
+.Lstatus: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
lgr %r1,%r2
mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
stsch .Lschib-.Lpg0(%r13)
diff --git a/arch/s390/kernel/sclp.c b/arch/s390/kernel/sclp.c
index 9fe7781a45cd..d88db40bdf15 100644
--- a/arch/s390/kernel/sclp.c
+++ b/arch/s390/kernel/sclp.c
@@ -9,7 +9,11 @@
#include <asm/processor.h>
#include <asm/sclp.h>
+#define EVTYP_VT220MSG_MASK 0x00000040
+#define EVTYP_MSG_MASK 0x40000000
+
static char _sclp_work_area[4096] __aligned(PAGE_SIZE);
+static bool have_vt220, have_linemode;
static void _sclp_wait_int(void)
{
@@ -68,7 +72,7 @@ static int _sclp_setup(int disable)
0x00, 0x1c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04,
- 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int *masks;
@@ -82,13 +86,13 @@ static int _sclp_setup(int disable)
rc = _sclp_servc(0x00780005, _sclp_work_area);
if (rc)
return rc;
- if ((masks[0] & masks[3]) != masks[0] ||
- (masks[1] & masks[2]) != masks[1])
- return -EIO;
+ have_vt220 = masks[2] & EVTYP_VT220MSG_MASK;
+ have_linemode = masks[2] & EVTYP_MSG_MASK;
return 0;
}
-static int _sclp_print(const char *str)
+/* Output multi-line text using SCLP Message interface. */
+static void _sclp_print_lm(const char *str)
{
static unsigned char write_head[] = {
/* sccb header */
@@ -143,18 +147,49 @@ static int _sclp_print(const char *str)
} while (ch != 0);
/* SCLP write data */
- return _sclp_servc(0x00760005, _sclp_work_area);
+ _sclp_servc(0x00760005, _sclp_work_area);
}
-int _sclp_print_early(const char *str)
+/* Output multi-line text (plus a newline) using SCLP VT220
+ * interface.
+ */
+static void _sclp_print_vt220(const char *str)
{
- int rc;
+ static unsigned char const write_head[] = {
+ /* sccb header */
+ 0x00, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* evbuf header */
+ 0x00, 0x06,
+ 0x1a, 0x00, 0x00, 0x00,
+ };
+ size_t len = strlen(str);
- rc = _sclp_setup(0);
- if (rc)
- return rc;
- rc = _sclp_print(str);
- if (rc)
- return rc;
- return _sclp_setup(1);
+ if (sizeof(write_head) + len >= sizeof(_sclp_work_area))
+ len = sizeof(_sclp_work_area) - sizeof(write_head) - 1;
+
+ memcpy(_sclp_work_area, write_head, sizeof(write_head));
+ memcpy(_sclp_work_area + sizeof(write_head), str, len);
+ _sclp_work_area[sizeof(write_head) + len] = '\n';
+
+ /* Update length fields in evbuf and sccb headers */
+ *(unsigned short *)(_sclp_work_area + 8) += len + 1;
+ *(unsigned short *)(_sclp_work_area + 0) += len + 1;
+
+ /* SCLP write data */
+ (void)_sclp_servc(0x00760005, _sclp_work_area);
+}
+
+/* Output one or more lines of text on the SCLP console (VT220 and /
+ * or line-mode). All lines get terminated; no need for a trailing LF.
+ */
+void _sclp_print_early(const char *str)
+{
+ if (_sclp_setup(0) != 0)
+ return;
+ if (have_linemode)
+ _sclp_print_lm(str);
+ if (have_vt220)
+ _sclp_print_vt220(str);
+ _sclp_setup(1);
}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index dc83ae66a730..c6878fbbcf13 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -99,7 +99,7 @@ unsigned long MODULES_VADDR;
unsigned long MODULES_END;
/* An array with a pointer to the lowcore of every CPU. */
-struct _lowcore *lowcore_ptr[NR_CPUS];
+struct lowcore *lowcore_ptr[NR_CPUS];
EXPORT_SYMBOL(lowcore_ptr);
/*
@@ -293,12 +293,12 @@ void *restart_stack __attribute__((__section__(".data")));
static void __init setup_lowcore(void)
{
- struct _lowcore *lc;
+ struct lowcore *lc;
/*
* Setup lowcore for boot cpu
*/
- BUILD_BUG_ON(sizeof(struct _lowcore) != LC_PAGES * 4096);
+ BUILD_BUG_ON(sizeof(struct lowcore) != LC_PAGES * 4096);
lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0);
lc->restart_psw.mask = PSW_KERNEL_BITS;
lc->restart_psw.addr =
@@ -663,15 +663,6 @@ static void __init reserve_kernel(void)
#endif
}
-static void __init reserve_elfcorehdr(void)
-{
-#ifdef CONFIG_CRASH_DUMP
- if (is_kdump_kernel())
- memblock_reserve(elfcorehdr_addr - OLDMEM_BASE,
- PAGE_ALIGN(elfcorehdr_size));
-#endif
-}
-
static void __init setup_memory(void)
{
struct memblock_region *reg;
@@ -850,6 +841,11 @@ void __init setup_arch(char **cmdline_p)
init_mm.brk = (unsigned long) &_end;
parse_early_param();
+#ifdef CONFIG_CRASH_DUMP
+ /* Deactivate elfcorehdr= kernel parameter */
+ elfcorehdr_addr = ELFCORE_ADDR_MAX;
+#endif
+
os_info_init();
setup_ipl();
@@ -858,7 +854,6 @@ void __init setup_arch(char **cmdline_p)
reserve_oldmem();
reserve_kernel();
reserve_initrd();
- reserve_elfcorehdr();
memblock_allow_resize();
/* Get information about *all* installed memory */
@@ -879,11 +874,13 @@ void __init setup_arch(char **cmdline_p)
check_initrd();
reserve_crashkernel();
+#ifdef CONFIG_CRASH_DUMP
/*
* Be aware that smp_save_dump_cpus() triggers a system reset.
* Therefore CPU and device initialization should be done afterwards.
*/
smp_save_dump_cpus();
+#endif
setup_resources();
setup_vmcoreinfo();
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 9062df575afe..a13468b9a913 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -64,8 +64,9 @@ enum {
static DEFINE_PER_CPU(struct cpu *, cpu_device);
struct pcpu {
- struct _lowcore *lowcore; /* lowcore page(s) for the cpu */
+ struct lowcore *lowcore; /* lowcore page(s) for the cpu */
unsigned long ec_mask; /* bit mask for ec_xxx functions */
+ unsigned long ec_clk; /* sigp timestamp for ec_xxx */
signed char state; /* physical cpu state */
signed char polarization; /* physical polarization */
u16 address; /* physical cpu address */
@@ -80,6 +81,10 @@ EXPORT_SYMBOL(smp_cpu_mt_shift);
unsigned int smp_cpu_mtid;
EXPORT_SYMBOL(smp_cpu_mtid);
+#ifdef CONFIG_CRASH_DUMP
+__vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS];
+#endif
+
static unsigned int smp_max_threads __initdata = -1U;
static int __init early_nosmt(char *s)
@@ -105,8 +110,7 @@ DEFINE_MUTEX(smp_cpu_state_mutex);
/*
* Signal processor helper functions.
*/
-static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm,
- u32 *status)
+static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm)
{
int cc;
@@ -171,6 +175,7 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
if (test_and_set_bit(ec_bit, &pcpu->ec_mask))
return;
order = pcpu_running(pcpu) ? SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL;
+ pcpu->ec_clk = get_tod_clock_fast();
pcpu_sigp_retry(pcpu, order, 0);
}
@@ -180,10 +185,10 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
{
unsigned long async_stack, panic_stack;
- struct _lowcore *lc;
+ struct lowcore *lc;
if (pcpu != &pcpu_devices[0]) {
- pcpu->lowcore = (struct _lowcore *)
+ pcpu->lowcore = (struct lowcore *)
__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
panic_stack = __get_free_page(GFP_KERNEL);
@@ -235,7 +240,7 @@ static void pcpu_free_lowcore(struct pcpu *pcpu)
static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
{
- struct _lowcore *lc = pcpu->lowcore;
+ struct lowcore *lc = pcpu->lowcore;
if (MACHINE_HAS_TLB_LC)
cpumask_set_cpu(cpu, &init_mm.context.cpu_attach_mask);
@@ -255,7 +260,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
{
- struct _lowcore *lc = pcpu->lowcore;
+ struct lowcore *lc = pcpu->lowcore;
struct thread_info *ti = task_thread_info(tsk);
lc->kernel_stack = (unsigned long) task_stack_page(tsk)
@@ -271,7 +276,7 @@ static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
{
- struct _lowcore *lc = pcpu->lowcore;
+ struct lowcore *lc = pcpu->lowcore;
lc->restart_stack = lc->kernel_stack;
lc->restart_fn = (unsigned long) func;
@@ -286,7 +291,7 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
void *data, unsigned long stack)
{
- struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
+ struct lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
unsigned long source_cpu = stap();
__load_psw_mask(PSW_KERNEL_BITS);
@@ -538,53 +543,24 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
#ifdef CONFIG_CRASH_DUMP
-static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext,
- u16 address, int is_boot_cpu)
-{
- void *lc = (void *)(unsigned long) store_prefix();
- unsigned long vx_sa;
-
- if (is_boot_cpu) {
- /* Copy the registers of the boot CPU. */
- copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
- SAVE_AREA_BASE - PAGE_SIZE, 0);
- if (MACHINE_HAS_VX)
- save_vx_regs_safe(sa_ext->vx_regs);
- return;
- }
- /* Get the registers of a non-boot cpu. */
- __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
- memcpy_real(&sa_ext->sa, lc + SAVE_AREA_BASE, sizeof(sa_ext->sa));
- if (!MACHINE_HAS_VX)
- return;
- /* Get the VX registers */
- vx_sa = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
- if (!vx_sa)
- panic("could not allocate memory for VX save area\n");
- __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL);
- memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs));
- memblock_free(vx_sa, PAGE_SIZE);
-}
-
int smp_store_status(int cpu)
{
- unsigned long vx_sa;
- struct pcpu *pcpu;
+ struct pcpu *pcpu = pcpu_devices + cpu;
+ unsigned long pa;
- pcpu = pcpu_devices + cpu;
- if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
- 0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
+ pa = __pa(&pcpu->lowcore->floating_pt_save_area);
+ if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS,
+ pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
return -EIO;
if (!MACHINE_HAS_VX)
return 0;
- vx_sa = __pa(pcpu->lowcore->vector_save_area_addr);
- __pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
- vx_sa, NULL);
+ pa = __pa(pcpu->lowcore->vector_save_area_addr);
+ if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
+ pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
+ return -EIO;
return 0;
}
-#endif /* CONFIG_CRASH_DUMP */
-
/*
* Collect CPU state of the previous, crashed system.
* There are four cases:
@@ -593,7 +569,7 @@ int smp_store_status(int cpu)
* The state for all CPUs except the boot CPU needs to be collected
* with sigp stop-and-store-status. The boot CPU state is located in
* the absolute lowcore of the memory stored in the HSA. The zcore code
- * will allocate the save area and copy the boot CPU state from the HSA.
+ * will copy the boot CPU state from the HSA.
* 2) stand-alone kdump for SCSI (zfcp dump with swapped memory)
* condition: OLDMEM_BASE != NULL && ipl_info.type == IPL_TYPE_FCP_DUMP
* The state for all CPUs except the boot CPU needs to be collected
@@ -608,55 +584,78 @@ int smp_store_status(int cpu)
* stored the registers of the boot CPU in the memory of the old system.
* 4) kdump and the old kernel stored the CPU state
* condition: OLDMEM_BASE != NULL && is_kdump_kernel()
- * The state of all CPUs is stored in ELF sections in the memory of the
- * old system. The ELF sections are picked up by the crash_dump code
- * via elfcorehdr_addr.
+ * This case does not exist for s390 anymore, setup_arch explicitly
+ * deactivates the elfcorehdr= kernel parameter
*/
+static __init void smp_save_cpu_vxrs(struct save_area *sa, u16 addr,
+ bool is_boot_cpu, unsigned long page)
+{
+ __vector128 *vxrs = (__vector128 *) page;
+
+ if (is_boot_cpu)
+ vxrs = boot_cpu_vector_save_area;
+ else
+ __pcpu_sigp_relax(addr, SIGP_STORE_ADDITIONAL_STATUS, page);
+ save_area_add_vxrs(sa, vxrs);
+}
+
+static __init void smp_save_cpu_regs(struct save_area *sa, u16 addr,
+ bool is_boot_cpu, unsigned long page)
+{
+ void *regs = (void *) page;
+
+ if (is_boot_cpu)
+ copy_oldmem_kernel(regs, (void *) __LC_FPREGS_SAVE_AREA, 512);
+ else
+ __pcpu_sigp_relax(addr, SIGP_STORE_STATUS_AT_ADDRESS, page);
+ save_area_add_regs(sa, regs);
+}
+
void __init smp_save_dump_cpus(void)
{
-#ifdef CONFIG_CRASH_DUMP
- int addr, cpu, boot_cpu_addr, max_cpu_addr;
- struct save_area_ext *sa_ext;
+ int addr, boot_cpu_addr, max_cpu_addr;
+ struct save_area *sa;
+ unsigned long page;
bool is_boot_cpu;
- if (is_kdump_kernel())
- /* Previous system stored the CPU states. Nothing to do. */
- return;
if (!(OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP))
/* No previous system present, normal boot. */
return;
+ /* Allocate a page as dumping area for the store status sigps */
+ page = memblock_alloc_base(PAGE_SIZE, PAGE_SIZE, 1UL << 31);
+ if (!page)
+ panic("could not allocate memory for save area\n");
/* Set multi-threading state to the previous system. */
pcpu_set_smt(sclp.mtid_prev);
- max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev;
- for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) {
- if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) ==
- SIGP_CC_NOT_OPERATIONAL)
- continue;
- cpu += 1;
- }
- dump_save_areas.areas = (void *)memblock_alloc(sizeof(void *) * cpu, 8);
- dump_save_areas.count = cpu;
boot_cpu_addr = stap();
- for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) {
- if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) ==
+ max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev;
+ for (addr = 0; addr <= max_cpu_addr; addr++) {
+ if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0) ==
SIGP_CC_NOT_OPERATIONAL)
continue;
- sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8);
- dump_save_areas.areas[cpu] = sa_ext;
- if (!sa_ext)
- panic("could not allocate memory for save area\n");
is_boot_cpu = (addr == boot_cpu_addr);
- cpu += 1;
- if (is_boot_cpu && !OLDMEM_BASE)
- /* Skip boot CPU for standard zfcp dump. */
- continue;
- /* Get state for this CPU. */
- __smp_store_cpu_state(sa_ext, addr, is_boot_cpu);
+ /* Allocate save area */
+ sa = save_area_alloc(is_boot_cpu);
+ if (!sa)
+ panic("could not allocate memory for save area\n");
+ if (MACHINE_HAS_VX)
+ /* Get the vector registers */
+ smp_save_cpu_vxrs(sa, addr, is_boot_cpu, page);
+ /*
+ * For a zfcp dump OLDMEM_BASE == NULL and the registers
+ * of the boot CPU are stored in the HSA. To retrieve
+ * these registers an SCLP request is required which is
+ * done by drivers/s390/char/zcore.c:init_cpu_info()
+ */
+ if (!is_boot_cpu || OLDMEM_BASE)
+ /* Get the CPU registers */
+ smp_save_cpu_regs(sa, addr, is_boot_cpu, page);
}
+ memblock_free(page, PAGE_SIZE);
diag308_reset();
pcpu_set_smt(0);
-#endif /* CONFIG_CRASH_DUMP */
}
+#endif /* CONFIG_CRASH_DUMP */
void smp_cpu_set_polarization(int cpu, int val)
{
@@ -680,7 +679,7 @@ static struct sclp_core_info *smp_get_core_info(void)
for (address = 0;
address < (SCLP_MAX_CORES << smp_cpu_mt_shift);
address += (1U << smp_cpu_mt_shift)) {
- if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==
+ if (__pcpu_sigp_relax(address, SIGP_SENSE, 0) ==
SIGP_CC_NOT_OPERATIONAL)
continue;
info->core[info->configured].core_id =
@@ -924,7 +923,7 @@ void __init smp_prepare_boot_cpu(void)
pcpu->state = CPU_STATE_CONFIGURED;
pcpu->address = stap();
- pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
+ pcpu->lowcore = (struct lowcore *)(unsigned long) store_prefix();
S390_lowcore.percpu_offset = __per_cpu_offset[0];
smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
set_cpu_present(0, true);
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c
index 99babea026ca..f7dba3887a54 100644
--- a/arch/s390/kernel/sysinfo.c
+++ b/arch/s390/kernel/sysinfo.c
@@ -111,8 +111,7 @@ static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
{
- static int max_mnest;
- int i, rc;
+ int i;
seq_putc(m, '\n');
if (!MACHINE_HAS_TOPOLOGY)
@@ -123,7 +122,7 @@ static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
for (i = 0; i < TOPOLOGY_NR_MAG; i++)
seq_printf(m, " %d", info->mag[i]);
seq_putc(m, '\n');
-#ifdef CONFIG_SCHED_MC
+#ifdef CONFIG_SCHED_TOPOLOGY
store_topology(info);
seq_printf(m, "CPU Topology SW: ");
for (i = 0; i < TOPOLOGY_NR_MAG; i++)
@@ -145,6 +144,10 @@ static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info)
seq_printf(m, "CPUs Configured: %d\n", info->cpus_configured);
seq_printf(m, "CPUs Standby: %d\n", info->cpus_standby);
seq_printf(m, "CPUs Reserved: %d\n", info->cpus_reserved);
+ if (info->mt_installed) {
+ seq_printf(m, "CPUs G-MTID: %d\n", info->mt_gtid);
+ seq_printf(m, "CPUs S-MTID: %d\n", info->mt_stid);
+ }
/*
* Sigh 2. According to the specification the alternate
* capability field is a 32 bit floating point number
@@ -194,13 +197,10 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved);
seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated);
seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared);
- if (info->mt_installed & 0x80) {
- seq_printf(m, "LPAR CPUs G-MTID: %d\n",
- info->mt_general & 0x1f);
- seq_printf(m, "LPAR CPUs S-MTID: %d\n",
- info->mt_installed & 0x1f);
- seq_printf(m, "LPAR CPUs PS-MTID: %d\n",
- info->mt_psmtid & 0x1f);
+ if (info->mt_installed) {
+ seq_printf(m, "LPAR CPUs G-MTID: %d\n", info->mt_gtid);
+ seq_printf(m, "LPAR CPUs S-MTID: %d\n", info->mt_stid);
+ seq_printf(m, "LPAR CPUs PS-MTID: %d\n", info->mt_psmtid);
}
}
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 1b18118bbc06..d69d648759c9 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -260,11 +260,8 @@ void vector_exception(struct pt_regs *regs)
void data_exception(struct pt_regs *regs)
{
- __u16 __user *location;
int signal = 0;
- location = get_trap_ip(regs);
-
save_fpu_regs();
if (current->thread.fpu.fpc & FPC_DXC_MASK)
signal = SIGFPE;
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 59eddb0e1a3e..94495cac8be3 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -80,7 +80,7 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
/*
* Setup vdso data page.
*/
-static void vdso_init_data(struct vdso_data *vd)
+static void __init vdso_init_data(struct vdso_data *vd)
{
vd->ectg_available = test_facility(31);
}
@@ -90,9 +90,10 @@ static void vdso_init_data(struct vdso_data *vd)
*/
#define SEGMENT_ORDER 2
-int vdso_alloc_per_cpu(struct _lowcore *lowcore)
+int vdso_alloc_per_cpu(struct lowcore *lowcore)
{
unsigned long segment_table, page_table, page_frame;
+ struct vdso_per_cpu_data *vd;
u32 *psal, *aste;
int i;
@@ -107,6 +108,12 @@ int vdso_alloc_per_cpu(struct _lowcore *lowcore)
if (!segment_table || !page_table || !page_frame)
goto out;
+ /* Initialize per-cpu vdso data page */
+ vd = (struct vdso_per_cpu_data *) page_frame;
+ vd->cpu_nr = lowcore->cpu_nr;
+ vd->node_id = cpu_to_node(vd->cpu_nr);
+
+ /* Set up access register mode page table */
clear_table((unsigned long *) segment_table, _SEGMENT_ENTRY_EMPTY,
PAGE_SIZE << SEGMENT_ORDER);
clear_table((unsigned long *) page_table, _PAGE_INVALID,
@@ -138,7 +145,7 @@ out:
return -ENOMEM;
}
-void vdso_free_per_cpu(struct _lowcore *lowcore)
+void vdso_free_per_cpu(struct lowcore *lowcore)
{
unsigned long segment_table, page_table, page_frame;
u32 *psal, *aste;
@@ -163,7 +170,7 @@ static void vdso_init_cr5(void)
if (!vdso_enabled)
return;
- cr5 = offsetof(struct _lowcore, paste);
+ cr5 = offsetof(struct lowcore, paste);
__ctl_load(cr5, 5, 5);
}
@@ -299,8 +306,6 @@ static int __init vdso_init(void)
get_page(virt_to_page(vdso_data));
- smp_mb();
-
return 0;
}
early_initcall(vdso_init);
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile
index ee8a18e50a25..f9c459586649 100644
--- a/arch/s390/kernel/vdso32/Makefile
+++ b/arch/s390/kernel/vdso32/Makefile
@@ -1,6 +1,6 @@
# List of files in the vdso, has to be asm only for now
-obj-vdso32 = gettimeofday.o clock_getres.o clock_gettime.o note.o
+obj-vdso32 = gettimeofday.o clock_getres.o clock_gettime.o note.o getcpu.o
# Build rules
diff --git a/arch/s390/kernel/vdso32/getcpu.S b/arch/s390/kernel/vdso32/getcpu.S
new file mode 100644
index 000000000000..c1ed0b72030f
--- /dev/null
+++ b/arch/s390/kernel/vdso32/getcpu.S
@@ -0,0 +1,43 @@
+/*
+ * Userland implementation of getcpu() for 32 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ * Copyright IBM Corp. 2016
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+
+ .text
+ .align 4
+ .globl __kernel_getcpu
+ .type __kernel_getcpu,@function
+__kernel_getcpu:
+ .cfi_startproc
+ ear %r1,%a4
+ lhi %r4,1
+ sll %r4,24
+ sar %a4,%r4
+ la %r4,0
+ epsw %r0,0
+ sacf 512
+ l %r5,__VDSO_CPU_NR(%r4)
+ l %r4,__VDSO_NODE_ID(%r4)
+ tml %r0,0x4000
+ jo 1f
+ tml %r0,0x8000
+ jno 0f
+ sacf 256
+ j 1f
+0: sacf 0
+1: sar %a4,%r1
+ ltr %r2,%r2
+ jz 2f
+ st %r5,0(%r2)
+2: ltr %r3,%r3
+ jz 3f
+ st %r4,0(%r3)
+3: lhi %r2,0
+ br %r14
+ .cfi_endproc
+ .size __kernel_getcpu,.-__kernel_getcpu
diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S
index a8c379fa1247..8f048c2d6d13 100644
--- a/arch/s390/kernel/vdso32/vdso32.lds.S
+++ b/arch/s390/kernel/vdso32/vdso32.lds.S
@@ -132,6 +132,7 @@ VERSION
__kernel_gettimeofday;
__kernel_clock_gettime;
__kernel_clock_getres;
+ __kernel_getcpu;
local: *;
};
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
index c4b03f9ed228..058659c1b8cf 100644
--- a/arch/s390/kernel/vdso64/Makefile
+++ b/arch/s390/kernel/vdso64/Makefile
@@ -1,6 +1,6 @@
# List of files in the vdso, has to be asm only for now
-obj-vdso64 = gettimeofday.o clock_getres.o clock_gettime.o note.o
+obj-vdso64 = gettimeofday.o clock_getres.o clock_gettime.o note.o getcpu.o
# Build rules
diff --git a/arch/s390/kernel/vdso64/getcpu.S b/arch/s390/kernel/vdso64/getcpu.S
new file mode 100644
index 000000000000..4cbe98291931
--- /dev/null
+++ b/arch/s390/kernel/vdso64/getcpu.S
@@ -0,0 +1,42 @@
+/*
+ * Userland implementation of getcpu() for 64 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ * Copyright IBM Corp. 2016
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+
+ .text
+ .align 4
+ .globl __kernel_getcpu
+ .type __kernel_getcpu,@function
+__kernel_getcpu:
+ .cfi_startproc
+ ear %r1,%a4
+ llilh %r4,0x0100
+ sar %a4,%r4
+ la %r4,0
+ epsw %r0,0
+ sacf 512
+ l %r5,__VDSO_CPU_NR(%r4)
+ l %r4,__VDSO_NODE_ID(%r4)
+ tml %r0,0x4000
+ jo 1f
+ tml %r0,0x8000
+ jno 0f
+ sacf 256
+ j 1f
+0: sacf 0
+1: sar %a4,%r1
+ ltgr %r2,%r2
+ jz 2f
+ st %r5,0(%r2)
+2: ltgr %r3,%r3
+ jz 3f
+ st %r4,0(%r3)
+3: lghi %r2,0
+ br %r14
+ .cfi_endproc
+ .size __kernel_getcpu,.-__kernel_getcpu
diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S
index 9f5979d102a9..f35455d497fe 100644
--- a/arch/s390/kernel/vdso64/vdso64.lds.S
+++ b/arch/s390/kernel/vdso64/vdso64.lds.S
@@ -132,6 +132,7 @@ VERSION
__kernel_gettimeofday;
__kernel_clock_gettime;
__kernel_clock_getres;
+ __kernel_getcpu;
local: *;
};
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 62ec925aa196..f88ca72c3a77 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -499,9 +499,9 @@ static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0);
rc = write_guest_lc(vcpu,
- offsetof(struct _lowcore, restart_old_psw),
+ offsetof(struct lowcore, restart_old_psw),
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= read_guest_lc(vcpu, offsetof(struct _lowcore, restart_psw),
+ rc |= read_guest_lc(vcpu, offsetof(struct lowcore, restart_psw),
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
clear_bit(IRQ_PEND_RESTART, &li->pending_irqs);
return rc ? -EFAULT : 0;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 5927c61d322a..835d60bedb54 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -2400,37 +2400,37 @@ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa)
u64 clkcomp;
int rc;
+ px = kvm_s390_get_prefix(vcpu);
if (gpa == KVM_S390_STORE_STATUS_NOADDR) {
if (write_guest_abs(vcpu, 163, &archmode, 1))
return -EFAULT;
- gpa = SAVE_AREA_BASE;
+ gpa = 0;
} else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) {
if (write_guest_real(vcpu, 163, &archmode, 1))
return -EFAULT;
- gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE);
- }
- rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs),
+ gpa = px;
+ } else
+ gpa -= __LC_FPREGS_SAVE_AREA;
+ rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
vcpu->arch.guest_fpregs.fprs, 128);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs),
+ rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA,
vcpu->run->s.regs.gprs, 128);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw),
+ rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA,
&vcpu->arch.sie_block->gpsw, 16);
- px = kvm_s390_get_prefix(vcpu);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg),
+ rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA,
&px, 4);
- rc |= write_guest_abs(vcpu,
- gpa + offsetof(struct save_area, fp_ctrl_reg),
+ rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA,
&vcpu->arch.guest_fpregs.fpc, 4);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg),
+ rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA,
&vcpu->arch.sie_block->todpr, 4);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer),
+ rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA,
&vcpu->arch.sie_block->cputm, 8);
clkcomp = vcpu->arch.sie_block->ckc >> 8;
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp),
+ rc |= write_guest_abs(vcpu, gpa + __LC_CLOCK_COMP_SAVE_AREA,
&clkcomp, 8);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs),
+ rc |= write_guest_abs(vcpu, gpa + __LC_AREGS_SAVE_AREA,
&vcpu->run->s.regs.acrs, 64);
- rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs),
+ rc |= write_guest_abs(vcpu, gpa + __LC_CREGS_SAVE_AREA,
&vcpu->arch.sie_block->gcr, 128);
return rc ? -EFAULT : 0;
}
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index d76b51cb4b62..ed74e86d9b9e 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -355,7 +355,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
* into a u32 memory representation. They will remain bits 0-31.
*/
fac = *vcpu->kvm->arch.model.fac->list >> 32;
- rc = write_guest_lc(vcpu, offsetof(struct _lowcore, stfl_fac_list),
+ rc = write_guest_lc(vcpu, offsetof(struct lowcore, stfl_fac_list),
&fac, sizeof(fac));
if (rc)
return rc;
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index 427aa44b3505..d4549c964589 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -37,12 +37,22 @@ static inline void _raw_compare_and_delay(unsigned int *lock, unsigned int old)
asm(".insn rsy,0xeb0000000022,%0,0,%1" : : "d" (old), "Q" (*lock));
}
+static inline int cpu_is_preempted(int cpu)
+{
+ if (test_cpu_flag_of(CIF_ENABLED_WAIT, cpu))
+ return 0;
+ if (smp_vcpu_scheduled(cpu))
+ return 0;
+ return 1;
+}
+
void arch_spin_lock_wait(arch_spinlock_t *lp)
{
unsigned int cpu = SPINLOCK_LOCKVAL;
unsigned int owner;
- int count;
+ int count, first_diag;
+ first_diag = 1;
while (1) {
owner = ACCESS_ONCE(lp->lock);
/* Try to get the lock if it is free. */
@@ -51,9 +61,10 @@ void arch_spin_lock_wait(arch_spinlock_t *lp)
return;
continue;
}
- /* Check if the lock owner is running. */
- if (!smp_vcpu_scheduled(~owner)) {
+ /* First iteration: check if the lock owner is running. */
+ if (first_diag && cpu_is_preempted(~owner)) {
smp_yield_cpu(~owner);
+ first_diag = 0;
continue;
}
/* Loop for a while on the lock value. */
@@ -67,10 +78,13 @@ void arch_spin_lock_wait(arch_spinlock_t *lp)
continue;
/*
* For multiple layers of hypervisors, e.g. z/VM + LPAR
- * yield the CPU if the lock is still unavailable.
+ * yield the CPU unconditionally. For LPAR rely on the
+ * sense running status.
*/
- if (!MACHINE_IS_LPAR)
+ if (!MACHINE_IS_LPAR || cpu_is_preempted(~owner)) {
smp_yield_cpu(~owner);
+ first_diag = 0;
+ }
}
}
EXPORT_SYMBOL(arch_spin_lock_wait);
@@ -79,9 +93,10 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
{
unsigned int cpu = SPINLOCK_LOCKVAL;
unsigned int owner;
- int count;
+ int count, first_diag;
local_irq_restore(flags);
+ first_diag = 1;
while (1) {
owner = ACCESS_ONCE(lp->lock);
/* Try to get the lock if it is free. */
@@ -92,8 +107,9 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
local_irq_restore(flags);
}
/* Check if the lock owner is running. */
- if (!smp_vcpu_scheduled(~owner)) {
+ if (first_diag && cpu_is_preempted(~owner)) {
smp_yield_cpu(~owner);
+ first_diag = 0;
continue;
}
/* Loop for a while on the lock value. */
@@ -107,10 +123,13 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
continue;
/*
* For multiple layers of hypervisors, e.g. z/VM + LPAR
- * yield the CPU if the lock is still unavailable.
+ * yield the CPU unconditionally. For LPAR rely on the
+ * sense running status.
*/
- if (!MACHINE_IS_LPAR)
+ if (!MACHINE_IS_LPAR || cpu_is_preempted(~owner)) {
smp_yield_cpu(~owner);
+ first_diag = 0;
+ }
}
}
EXPORT_SYMBOL(arch_spin_lock_wait_flags);
@@ -145,7 +164,7 @@ void _raw_read_lock_wait(arch_rwlock_t *rw)
owner = 0;
while (1) {
if (count-- <= 0) {
- if (owner && !smp_vcpu_scheduled(~owner))
+ if (owner && cpu_is_preempted(~owner))
smp_yield_cpu(~owner);
count = spin_retry;
}
@@ -191,7 +210,7 @@ void _raw_write_lock_wait(arch_rwlock_t *rw, unsigned int prev)
owner = 0;
while (1) {
if (count-- <= 0) {
- if (owner && !smp_vcpu_scheduled(~owner))
+ if (owner && cpu_is_preempted(~owner))
smp_yield_cpu(~owner);
count = spin_retry;
}
@@ -221,7 +240,7 @@ void _raw_write_lock_wait(arch_rwlock_t *rw)
owner = 0;
while (1) {
if (count-- <= 0) {
- if (owner && !smp_vcpu_scheduled(~owner))
+ if (owner && cpu_is_preempted(~owner))
smp_yield_cpu(~owner);
count = spin_retry;
}
@@ -265,7 +284,7 @@ void arch_lock_relax(unsigned int cpu)
{
if (!cpu)
return;
- if (MACHINE_IS_LPAR && smp_vcpu_scheduled(~cpu))
+ if (MACHINE_IS_LPAR && !cpu_is_preempted(~cpu))
return;
smp_yield_cpu(~cpu);
}
diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c
index 4d1ee88864e8..18c8b819b0aa 100644
--- a/arch/s390/mm/extable.c
+++ b/arch/s390/mm/extable.c
@@ -52,12 +52,16 @@ void sort_extable(struct exception_table_entry *start,
int i;
/* Normalize entries to being relative to the start of the section */
- for (p = start, i = 0; p < finish; p++, i += 8)
+ for (p = start, i = 0; p < finish; p++, i += 8) {
p->insn += i;
+ p->fixup += i + 4;
+ }
sort(start, finish - start, sizeof(*start), cmp_ex, NULL);
/* Denormalize all entries */
- for (p = start, i = 0; p < finish; p++, i += 8)
+ for (p = start, i = 0; p < finish; p++, i += 8) {
p->insn -= i;
+ p->fixup -= i + 4;
+ }
}
#ifdef CONFIG_MODULES
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 18fccc303db7..a1bf4ad8925d 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -94,7 +94,7 @@ static DEFINE_MUTEX(dcss_lock);
static LIST_HEAD(dcss_list);
static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
"EW/EN-MIXED" };
-static int loadshr_scode, loadnsr_scode, findseg_scode;
+static int loadshr_scode, loadnsr_scode;
static int segext_scode, purgeseg_scode;
static int scode_set;
@@ -130,7 +130,6 @@ dcss_set_subcodes(void)
loadshr_scode = DCSS_LOADSHRX;
loadnsr_scode = DCSS_LOADNSRX;
purgeseg_scode = DCSS_PURGESEG;
- findseg_scode = DCSS_FINDSEGX;
segext_scode = DCSS_SEGEXTX;
return 0;
}
@@ -138,7 +137,6 @@ dcss_set_subcodes(void)
loadshr_scode = DCSS_LOADNOLY;
loadnsr_scode = DCSS_LOADNSR;
purgeseg_scode = DCSS_PURGESEG;
- findseg_scode = DCSS_FINDSEG;
segext_scode = DCSS_SEGEXT;
return 0;
}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index ec1a30d0d11a..1b903f6ad54a 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -254,7 +254,6 @@ static noinline void do_sigsegv(struct pt_regs *regs, int si_code)
static noinline void do_no_context(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
- unsigned long address;
/* Are we prepared to handle this kernel fault? */
fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -267,7 +266,6 @@ static noinline void do_no_context(struct pt_regs *regs)
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
- address = regs->int_parm_long & __FAIL_ADDR_MASK;
if (!user_space_fault(regs))
printk(KERN_ALERT "Unable to handle kernel pointer dereference"
" in virtual kernel address space\n");
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 12bbf0e8478f..13dab0c1645c 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -55,7 +55,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
unsigned long mask, result;
- struct page *head, *page, *tail;
+ struct page *head, *page;
int refs;
result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
@@ -67,7 +67,6 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
refs = 0;
head = pmd_page(pmd);
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
- tail = page;
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
@@ -88,16 +87,6 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
return 0;
}
- /*
- * Any tail page need their mapcount reference taken before we
- * return.
- */
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
return 1;
}
@@ -116,16 +105,7 @@ static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
pmd = *pmdp;
barrier();
next = pmd_addr_end(addr, end);
- /*
- * The pmd_trans_splitting() check below explains why
- * pmdp_splitting_flush() has to serialize with
- * smp_call_function() against our disabled IRQs, to stop
- * this gup-fast code from running while we set the
- * splitting bit in the pmd. Returning zero will take
- * the slow path that will call wait_split_huge_page()
- * if the pmd is still in splitting state.
- */
- if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+ if (pmd_none(pmd))
return 0;
if (unlikely(pmd_large(pmd))) {
/*
@@ -233,6 +213,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct mm_struct *mm = current->mm;
int nr, ret;
+ might_sleep();
start &= PAGE_MASK;
nr = __get_user_pages_fast(start, nr_pages, write, pages);
if (nr == nr_pages)
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index 8a993a53fcd6..fec59c067d0d 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -163,11 +163,11 @@ static int is_swapped(unsigned long addr)
unsigned long lc;
int cpu;
- if (addr < sizeof(struct _lowcore))
+ if (addr < sizeof(struct lowcore))
return 1;
for_each_online_cpu(cpu) {
lc = (unsigned long) lowcore_ptr[cpu];
- if (addr > lc + sizeof(struct _lowcore) - 1 || addr < lc)
+ if (addr > lc + sizeof(struct lowcore) - 1 || addr < lc)
continue;
return 1;
}
diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c
index e00f0d5d296d..d612cc3eec6a 100644
--- a/arch/s390/mm/mem_detect.c
+++ b/arch/s390/mm/mem_detect.c
@@ -14,8 +14,6 @@
#include <asm/sclp.h>
#include <asm/setup.h>
-#define ADDR2G (1ULL << 31)
-
#define CHUNK_READ_WRITE 0
#define CHUNK_READ_ONLY 1
@@ -27,15 +25,14 @@ static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size)
void __init detect_memory_memblock(void)
{
- unsigned long long memsize, rnmax, rzm;
- unsigned long addr, size;
+ unsigned long memsize, rnmax, rzm, addr, size;
int type;
rzm = sclp.rzm;
rnmax = sclp.rnmax;
memsize = rzm * rnmax;
if (!rzm)
- rzm = 1ULL << 17;
+ rzm = 1UL << 17;
max_physmem_end = memsize;
addr = 0;
/* keep memblock lists close to the kernel */
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 63b039899a5e..a809fa8e6f8b 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -578,17 +578,29 @@ int gmap_fault(struct gmap *gmap, unsigned long gaddr,
{
unsigned long vmaddr;
int rc;
+ bool unlocked;
down_read(&gmap->mm->mmap_sem);
+
+retry:
+ unlocked = false;
vmaddr = __gmap_translate(gmap, gaddr);
if (IS_ERR_VALUE(vmaddr)) {
rc = vmaddr;
goto out_up;
}
- if (fixup_user_fault(current, gmap->mm, vmaddr, fault_flags)) {
+ if (fixup_user_fault(current, gmap->mm, vmaddr, fault_flags,
+ &unlocked)) {
rc = -EFAULT;
goto out_up;
}
+ /*
+ * In the case that fixup_user_fault unlocked the mmap_sem during
+ * faultin redo __gmap_translate to not race with a map/unmap_segment.
+ */
+ if (unlocked)
+ goto retry;
+
rc = __gmap_link(gmap, gaddr, vmaddr);
out_up:
up_read(&gmap->mm->mmap_sem);
@@ -603,10 +615,7 @@ static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm)
else if (is_migration_entry(entry)) {
struct page *page = migration_entry_to_page(entry);
- if (PageAnon(page))
- dec_mm_counter(mm, MM_ANONPAGES);
- else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter(page));
}
free_swap_and_cache(entry);
}
@@ -717,12 +726,14 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len)
spinlock_t *ptl;
pte_t *ptep, entry;
pgste_t pgste;
+ bool unlocked;
int rc = 0;
if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK))
return -EINVAL;
down_read(&gmap->mm->mmap_sem);
while (len) {
+ unlocked = false;
/* Convert gmap address and connect the page tables */
addr = __gmap_translate(gmap, gaddr);
if (IS_ERR_VALUE(addr)) {
@@ -730,10 +741,14 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len)
break;
}
/* Get the page mapped */
- if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE)) {
+ if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE,
+ &unlocked)) {
rc = -EFAULT;
break;
}
+ /* While trying to map mmap_sem got unlocked. Let us retry */
+ if (unlocked)
+ continue;
rc = __gmap_link(gmap, gaddr, addr);
if (rc)
break;
@@ -794,9 +809,11 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
spinlock_t *ptl;
pgste_t old, new;
pte_t *ptep;
+ bool unlocked;
down_read(&mm->mmap_sem);
retry:
+ unlocked = false;
ptep = get_locked_pte(mm, addr, &ptl);
if (unlikely(!ptep)) {
up_read(&mm->mmap_sem);
@@ -805,7 +822,12 @@ retry:
if (!(pte_val(*ptep) & _PAGE_INVALID) &&
(pte_val(*ptep) & _PAGE_PROTECT)) {
pte_unmap_unlock(ptep, ptl);
- if (fixup_user_fault(current, mm, addr, FAULT_FLAG_WRITE)) {
+ /*
+ * We do not really care about unlocked. We will retry either
+ * way. But this allows fixup_user_fault to enable userfaultfd.
+ */
+ if (fixup_user_fault(current, mm, addr, FAULT_FLAG_WRITE,
+ &unlocked)) {
up_read(&mm->mmap_sem);
return -EFAULT;
}
@@ -1308,22 +1330,6 @@ int pmdp_set_access_flags(struct vm_area_struct *vma,
return 1;
}
-static void pmdp_splitting_flush_sync(void *arg)
-{
- /* Simply deliver the interrupt */
-}
-
-void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp)
-{
- VM_BUG_ON(address & ~HPAGE_PMD_MASK);
- if (!test_and_set_bit(_SEGMENT_ENTRY_SPLIT_BIT,
- (unsigned long *) pmdp)) {
- /* need to serialize against gup-fast (IRQ disabled) */
- smp_call_function(pmdp_splitting_flush_sync, NULL, 1);
- }
-}
-
void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
pgtable_t pgtable)
{
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 7ef12a3ace3a..11d4f277e9f6 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -701,8 +701,7 @@ static int zpci_restore(struct device *dev)
goto out;
zpci_map_resources(pdev);
- zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
- zdev->start_dma + zdev->iommu_size - 1,
+ zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
(u64) zdev->dma_table);
out:
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index 32da0a6ecec2..4638b93c7632 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -457,7 +457,19 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
goto out_clean;
}
- zdev->iommu_size = (unsigned long) high_memory - PAGE_OFFSET;
+ /*
+ * Restrict the iommu bitmap size to the minimum of the following:
+ * - main memory size
+ * - 3-level pagetable address limit minus start_dma offset
+ * - DMA address range allowed by the hardware (clp query pci fn)
+ *
+ * Also set zdev->end_dma to the actual end address of the usable
+ * range, instead of the theoretical maximum as reported by hardware.
+ */
+ zdev->iommu_size = min3((u64) high_memory,
+ ZPCI_TABLE_SIZE_RT - zdev->start_dma,
+ zdev->end_dma - zdev->start_dma + 1);
+ zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
if (!zdev->iommu_bitmap) {
@@ -465,10 +477,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
goto out_reg;
}
- rc = zpci_register_ioat(zdev,
- 0,
- zdev->start_dma + PAGE_OFFSET,
- zdev->start_dma + zdev->iommu_size - 1,
+ rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
(u64) zdev->dma_table);
if (rc)
goto out_reg;
diff --git a/arch/s390/tools/.gitignore b/arch/s390/tools/.gitignore
new file mode 100644
index 000000000000..72a4b2cf1365
--- /dev/null
+++ b/arch/s390/tools/.gitignore
@@ -0,0 +1 @@
+gen_facilities
diff --git a/arch/s390/tools/Makefile b/arch/s390/tools/Makefile
new file mode 100644
index 000000000000..6d9814c9df2b
--- /dev/null
+++ b/arch/s390/tools/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for s390 specific build tools
+#
+
+hostprogs-y += gen_facilities
+HOSTCFLAGS_gen_facilities.o += -Wall $(LINUXINCLUDE)
+
+define filechk_facilities.h
+ $(obj)/gen_facilities
+endef
+
+$(obj)/gen_facilities.o: $(srctree)/arch/s390/tools/gen_facilities.c
+
+include/generated/facilities.h: $(obj)/gen_facilities FORCE
+ $(call filechk,facilities.h)
diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c
new file mode 100644
index 000000000000..e2660d27889b
--- /dev/null
+++ b/arch/s390/tools/gen_facilities.c
@@ -0,0 +1,67 @@
+/*
+ * Simple program to generate defines out of facility lists that use the bit
+ * numbering scheme from the Princples of Operations: most significant bit
+ * has bit number 0.
+ *
+ * Copyright IBM Corp. 2015
+ *
+ */
+
+#define S390_GEN_FACILITIES_C
+
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <asm/facilities_src.h>
+
+static void print_facility_list(struct facility_def *def)
+{
+ unsigned int high, bit, dword, i;
+ unsigned long long *array;
+
+ array = calloc(1, 8);
+ if (!array)
+ exit(EXIT_FAILURE);
+ high = 0;
+ for (i = 0; def->bits[i] != -1; i++) {
+ bit = 63 - (def->bits[i] & 63);
+ dword = def->bits[i] / 64;
+ if (dword > high) {
+ array = realloc(array, (dword + 1) * 8);
+ if (!array)
+ exit(EXIT_FAILURE);
+ memset(array + high + 1, 0, (dword - high) * 8);
+ high = dword;
+ }
+ array[dword] |= 1ULL << bit;
+ }
+ printf("#define %s ", def->name);
+ for (i = 0; i <= high; i++)
+ printf("_AC(0x%016llx,UL)%c", array[i], i < high ? ',' : '\n');
+ printf("#define %s_DWORDS %d\n", def->name, high + 1);
+ free(array);
+}
+
+static void print_facility_lists(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(facility_defs) / sizeof(facility_defs[0]); i++)
+ print_facility_list(&facility_defs[i]);
+}
+
+int main(int argc, char **argv)
+{
+ printf("#ifndef __ASM_S390_FACILITIES__\n");
+ printf("#define __ASM_S390_FACILITIES__\n");
+ printf("/*\n");
+ printf(" * DO NOT MODIFY.\n");
+ printf(" *\n");
+ printf(" * This file was generated by %s\n", __FILE__);
+ printf(" */\n\n");
+ printf("#include <linux/const.h>\n\n");
+ print_facility_lists();
+ printf("\n#endif\n");
+ return 0;
+}
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d514df7e04dd..6c391a5d3e5c 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -130,9 +130,6 @@ config STACKTRACE_SUPPORT
config LOCKDEP_SUPPORT
def_bool y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config ARCH_HAS_ILOG2_U32
def_bool n
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 8f237a5bd9aa..7a04da3efce4 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -167,7 +167,7 @@ static struct mtd_partition migor_nand_flash_partitions[] = {
static void migor_nand_flash_cmd_ctl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (cmd == NAND_CMD_NONE)
return;
diff --git a/arch/sh/include/asm/barrier.h b/arch/sh/include/asm/barrier.h
index bf91037db4e0..f887c6465a82 100644
--- a/arch/sh/include/asm/barrier.h
+++ b/arch/sh/include/asm/barrier.h
@@ -32,7 +32,8 @@
#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
#endif
-#define smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#define __smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#define smp_store_mb(var, value) __smp_store_mb(var, value)
#include <asm-generic/barrier.h>
diff --git a/arch/sh/include/asm/cmpxchg-grb.h b/arch/sh/include/asm/cmpxchg-grb.h
index f848dec9e483..2ed557b31bd9 100644
--- a/arch/sh/include/asm/cmpxchg-grb.h
+++ b/arch/sh/include/asm/cmpxchg-grb.h
@@ -23,6 +23,28 @@ static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
return retval;
}
+static inline unsigned long xchg_u16(volatile u16 *m, unsigned long val)
+{
+ unsigned long retval;
+
+ __asm__ __volatile__ (
+ " .align 2 \n\t"
+ " mova 1f, r0 \n\t" /* r0 = end point */
+ " mov r15, r1 \n\t" /* r1 = saved sp */
+ " mov #-6, r15 \n\t" /* LOGIN */
+ " mov.w @%1, %0 \n\t" /* load old value */
+ " extu.w %0, %0 \n\t" /* extend as unsigned */
+ " mov.w %2, @%1 \n\t" /* store new value */
+ "1: mov r1, r15 \n\t" /* LOGOUT */
+ : "=&r" (retval),
+ "+r" (m),
+ "+r" (val) /* inhibit r15 overloading */
+ :
+ : "memory" , "r0", "r1");
+
+ return retval;
+}
+
static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
{
unsigned long retval;
diff --git a/arch/sh/include/asm/cmpxchg-irq.h b/arch/sh/include/asm/cmpxchg-irq.h
index bd11f630414a..f88877257171 100644
--- a/arch/sh/include/asm/cmpxchg-irq.h
+++ b/arch/sh/include/asm/cmpxchg-irq.h
@@ -14,6 +14,17 @@ static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
return retval;
}
+static inline unsigned long xchg_u16(volatile u16 *m, unsigned long val)
+{
+ unsigned long flags, retval;
+
+ local_irq_save(flags);
+ retval = *m;
+ *m = val;
+ local_irq_restore(flags);
+ return retval;
+}
+
static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
{
unsigned long flags, retval;
diff --git a/arch/sh/include/asm/cmpxchg-llsc.h b/arch/sh/include/asm/cmpxchg-llsc.h
index 47136661a203..fcfd32271bff 100644
--- a/arch/sh/include/asm/cmpxchg-llsc.h
+++ b/arch/sh/include/asm/cmpxchg-llsc.h
@@ -22,29 +22,8 @@ static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
return retval;
}
-static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
-{
- unsigned long retval;
- unsigned long tmp;
-
- __asm__ __volatile__ (
- "1: \n\t"
- "movli.l @%2, %0 ! xchg_u8 \n\t"
- "mov %0, %1 \n\t"
- "mov %3, %0 \n\t"
- "movco.l %0, @%2 \n\t"
- "bf 1b \n\t"
- "synco \n\t"
- : "=&z"(tmp), "=&r" (retval)
- : "r" (m), "r" (val & 0xff)
- : "t", "memory"
- );
-
- return retval;
-}
-
static inline unsigned long
-__cmpxchg_u32(volatile int *m, unsigned long old, unsigned long new)
+__cmpxchg_u32(volatile u32 *m, unsigned long old, unsigned long new)
{
unsigned long retval;
unsigned long tmp;
@@ -68,4 +47,6 @@ __cmpxchg_u32(volatile int *m, unsigned long old, unsigned long new)
return retval;
}
+#include <asm/cmpxchg-xchg.h>
+
#endif /* __ASM_SH_CMPXCHG_LLSC_H */
diff --git a/arch/sh/include/asm/cmpxchg-xchg.h b/arch/sh/include/asm/cmpxchg-xchg.h
new file mode 100644
index 000000000000..7219719c23a3
--- /dev/null
+++ b/arch/sh/include/asm/cmpxchg-xchg.h
@@ -0,0 +1,51 @@
+#ifndef __ASM_SH_CMPXCHG_XCHG_H
+#define __ASM_SH_CMPXCHG_XCHG_H
+
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See the
+ * file "COPYING" in the main directory of this archive for more details.
+ */
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+
+/*
+ * Portable implementations of 1 and 2 byte xchg using a 4 byte cmpxchg.
+ * Note: this header isn't self-contained: before including it, __cmpxchg_u32
+ * must be defined first.
+ */
+static inline u32 __xchg_cmpxchg(volatile void *ptr, u32 x, int size)
+{
+ int off = (unsigned long)ptr % sizeof(u32);
+ volatile u32 *p = ptr - off;
+#ifdef __BIG_ENDIAN
+ int bitoff = (sizeof(u32) - 1 - off) * BITS_PER_BYTE;
+#else
+ int bitoff = off * BITS_PER_BYTE;
+#endif
+ u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
+ u32 oldv, newv;
+ u32 ret;
+
+ do {
+ oldv = READ_ONCE(*p);
+ ret = (oldv & bitmask) >> bitoff;
+ newv = (oldv & ~bitmask) | (x << bitoff);
+ } while (__cmpxchg_u32(p, oldv, newv) != oldv);
+
+ return ret;
+}
+
+static inline unsigned long xchg_u16(volatile u16 *m, unsigned long val)
+{
+ return __xchg_cmpxchg(m, val, sizeof *m);
+}
+
+static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
+{
+ return __xchg_cmpxchg(m, val, sizeof *m);
+}
+
+#endif /* __ASM_SH_CMPXCHG_XCHG_H */
diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h
index 85c97b188d71..5225916c1057 100644
--- a/arch/sh/include/asm/cmpxchg.h
+++ b/arch/sh/include/asm/cmpxchg.h
@@ -27,6 +27,9 @@ extern void __xchg_called_with_bad_pointer(void);
case 4: \
__xchg__res = xchg_u32(__xchg_ptr, x); \
break; \
+ case 2: \
+ __xchg__res = xchg_u16(__xchg_ptr, x); \
+ break; \
case 1: \
__xchg__res = xchg_u8(__xchg_ptr, x); \
break; \
diff --git a/arch/sh/kernel/cpu/clock-cpg.c b/arch/sh/kernel/cpu/clock-cpg.c
index 8525a671266f..786c0769b4c3 100644
--- a/arch/sh/kernel/cpu/clock-cpg.c
+++ b/arch/sh/kernel/cpu/clock-cpg.c
@@ -63,7 +63,6 @@ int __init __deprecated cpg_clk_init(void)
clk_add_alias("fck", "sh-mtu2", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-cmt-16.0", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-cmt-32.0", "peripheral_clk", NULL);
- clk_add_alias("sci_ick", NULL, "peripheral_clk", NULL);
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7264.c b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
index 8638fba6cd7f..7e06e39b0958 100644
--- a/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
@@ -115,7 +115,14 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
/* MSTP clocks */
- CLKDEV_CON_ID("sci_ick", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.6", &mstp_clks[MSTP77]),
+ CLKDEV_ICK_ID("fck", "sh-sci.7", &mstp_clks[MSTP77]),
CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7269.c b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
index f8a5c2abdfb3..663a97bed554 100644
--- a/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
@@ -150,14 +150,14 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
/* MSTP clocks */
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP47]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP46]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP45]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP44]),
+ CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP43]),
+ CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP42]),
+ CLKDEV_ICK_ID("fck", "sh-sci.6", &mstp_clks[MSTP41]),
+ CLKDEV_ICK_ID("fck", "sh-sci.7", &mstp_clks[MSTP40]),
CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
index 9edc06c02dcf..a907ee2388bf 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
@@ -232,10 +232,10 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP004]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP004]),
CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
index 955b9add7810..ac9854179dee 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
@@ -230,9 +230,9 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
index ccbcab550df2..fe844222f3f6 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
@@ -267,12 +267,12 @@ static struct clk_lookup lookups[] = {
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[HWBLK_TMU0]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[HWBLK_TMU1]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+ CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+ CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
index 7f54bf2f453d..354dcac5e4cd 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
@@ -194,12 +194,12 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP026]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP024]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP023]),
+ CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP022]),
+ CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP016]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP015]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index e40ec2c97ad1..b10af2ae9f35 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -125,9 +125,9 @@ static struct clk_lookup lookups[] = {
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP113]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP114]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP112]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP111]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP112]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP111]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP110]),
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
index 8eb6e62340c9..1aafd5496752 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -132,12 +132,12 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
- CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+ CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP029]),
+ CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP028]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
index 5e50e7ebeff0..ac3dcfe5d303 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
@@ -139,12 +139,12 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
- CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+ CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP029]),
+ CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP028]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]),
CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
index 605221d1448a..b1bdbc3cbc21 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -114,10 +114,10 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
- CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
- CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+ CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP027]),
+ CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP026]),
+ CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP025]),
+ CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
index f617bcb734df..69b8a50310d9 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
@@ -28,7 +28,7 @@ static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
};
static struct resource scif0_resources[] = {
@@ -50,7 +50,7 @@ static struct plat_sci_port scif1_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
};
static struct resource scif1_resources[] = {
@@ -72,7 +72,7 @@ static struct plat_sci_port scif2_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
};
static struct resource scif2_resources[] = {
@@ -94,7 +94,7 @@ static struct plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
};
static struct resource scif3_resources[] = {
@@ -116,7 +116,7 @@ static struct plat_sci_port scif4_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
};
static struct resource scif4_resources[] = {
@@ -138,7 +138,7 @@ static struct plat_sci_port scif5_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
};
static struct resource scif5_resources[] = {
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 51d8f7f31d1d..58aaa4f33b81 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -241,7 +241,7 @@ static void sh4_flush_cache_page(void *args)
*/
map_coherent = (current_cpu_data.dcache.n_aliases &&
test_bit(PG_dcache_clean, &page->flags) &&
- page_mapped(page));
+ page_mapcount(page));
if (map_coherent)
vaddr = kmap_coherent(page, address);
else
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index f770e3992620..e58cfbf45150 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -59,7 +59,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
unsigned long len)
{
- if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
+ if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) &&
test_bit(PG_dcache_clean, &page->flags)) {
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(vto, src, len);
@@ -78,7 +78,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
unsigned long len)
{
- if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
+ if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) &&
test_bit(PG_dcache_clean, &page->flags)) {
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(dst, vfrom, len);
@@ -97,7 +97,7 @@ void copy_user_highpage(struct page *to, struct page *from,
vto = kmap_atomic(to);
- if (boot_cpu_data.dcache.n_aliases && page_mapped(from) &&
+ if (boot_cpu_data.dcache.n_aliases && page_mapcount(from) &&
test_bit(PG_dcache_clean, &from->flags)) {
vfrom = kmap_coherent(from, vaddr);
copy_page(vto, vfrom);
@@ -153,7 +153,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
unsigned long addr = (unsigned long) page_address(page);
if (pages_do_alias(addr, vmaddr)) {
- if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
+ if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) &&
test_bit(PG_dcache_clean, &page->flags)) {
void *kaddr;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 56442d2d7bbc..3203e42190dd 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -101,10 +101,6 @@ config LOCKDEP_SUPPORT
bool
default y if SPARC64
-config HAVE_LATENCYTOP_SUPPORT
- bool
- default y if SPARC64
-
config ARCH_HIBERNATION_POSSIBLE
def_bool y if SPARC64
diff --git a/arch/sparc/include/asm/barrier_32.h b/arch/sparc/include/asm/barrier_32.h
index ae69eda288f4..8059130a6cee 100644
--- a/arch/sparc/include/asm/barrier_32.h
+++ b/arch/sparc/include/asm/barrier_32.h
@@ -1,7 +1,6 @@
#ifndef __SPARC_BARRIER_H
#define __SPARC_BARRIER_H
-#include <asm/processor.h> /* for nop() */
#include <asm-generic/barrier.h>
#endif /* !(__SPARC_BARRIER_H) */
diff --git a/arch/sparc/include/asm/barrier_64.h b/arch/sparc/include/asm/barrier_64.h
index 14a928601657..c9f6ee64f41d 100644
--- a/arch/sparc/include/asm/barrier_64.h
+++ b/arch/sparc/include/asm/barrier_64.h
@@ -37,33 +37,14 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#define rmb() __asm__ __volatile__("":::"memory")
#define wmb() __asm__ __volatile__("":::"memory")
-#define dma_rmb() rmb()
-#define dma_wmb() wmb()
-
-#define smp_store_mb(__var, __value) \
- do { WRITE_ONCE(__var, __value); membar_safe("#StoreLoad"); } while(0)
-
-#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
-#else
-#define smp_mb() __asm__ __volatile__("":::"memory")
-#define smp_rmb() __asm__ __volatile__("":::"memory")
-#define smp_wmb() __asm__ __volatile__("":::"memory")
-#endif
-
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
-
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
WRITE_ONCE(*p, v); \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
@@ -71,7 +52,9 @@ do { \
___p1; \
})
-#define smp_mb__before_atomic() barrier()
-#define smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
+
+#include <asm-generic/barrier.h>
#endif /* !(__SPARC64_BARRIER_H) */
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 131d36fcd07a..7a38d6a576c5 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -681,13 +681,6 @@ static inline unsigned long pmd_trans_huge(pmd_t pmd)
return pte_val(pte) & _PAGE_PMD_HUGE;
}
-static inline unsigned long pmd_trans_splitting(pmd_t pmd)
-{
- pte_t pte = __pte(pmd_val(pmd));
-
- return pmd_trans_huge(pmd) && pte_special(pte);
-}
-
#define has_transparent_hugepage() 1
static inline pmd_t pmd_mkold(pmd_t pmd)
@@ -717,29 +710,29 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)
return __pmd(pte_val(pte));
}
-static inline pmd_t pmd_mkyoung(pmd_t pmd)
+static inline pmd_t pmd_mkclean(pmd_t pmd)
{
pte_t pte = __pte(pmd_val(pmd));
- pte = pte_mkyoung(pte);
+ pte = pte_mkclean(pte);
return __pmd(pte_val(pte));
}
-static inline pmd_t pmd_mkwrite(pmd_t pmd)
+static inline pmd_t pmd_mkyoung(pmd_t pmd)
{
pte_t pte = __pte(pmd_val(pmd));
- pte = pte_mkwrite(pte);
+ pte = pte_mkyoung(pte);
return __pmd(pte_val(pte));
}
-static inline pmd_t pmd_mksplitting(pmd_t pmd)
+static inline pmd_t pmd_mkwrite(pmd_t pmd)
{
pte_t pte = __pte(pmd_val(pmd));
- pte = pte_mkspecial(pte);
+ pte = pte_mkwrite(pte);
return __pmd(pte_val(pte));
}
diff --git a/arch/sparc/include/asm/processor.h b/arch/sparc/include/asm/processor.h
index 2fe99e66e760..9da9646bf6c6 100644
--- a/arch/sparc/include/asm/processor.h
+++ b/arch/sparc/include/asm/processor.h
@@ -5,7 +5,4 @@
#else
#include <asm/processor_32.h>
#endif
-
-#define nop() __asm__ __volatile__ ("nop")
-
#endif
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
index 30e7ddb27a3a..c690c8e16a96 100644
--- a/arch/sparc/kernel/sys_sparc_64.c
+++ b/arch/sparc/kernel/sys_sparc_64.c
@@ -413,7 +413,7 @@ out:
SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality)
{
- int ret;
+ long ret;
if (personality(current->personality) == PER_LINUX32 &&
personality(personality) == PER_LINUX)
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index dbabe5713a15..cb841a33da59 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -113,9 +113,6 @@ static unsigned int get_user_insn(unsigned long tpc)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
if (pmd_trans_huge(*pmdp)) {
- if (pmd_trans_splitting(*pmdp))
- goto out_irq_enable;
-
pa = pmd_pfn(*pmdp) << PAGE_SHIFT;
pa += tpc & ~HPAGE_MASK;
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c
index 2e5c4fc2daa9..eb3d8e8ebc6b 100644
--- a/arch/sparc/mm/gup.c
+++ b/arch/sparc/mm/gup.c
@@ -56,8 +56,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
put_page(head);
return 0;
}
- if (head != page)
- get_huge_page_tail(page);
pages[*nr] = page;
(*nr)++;
@@ -70,7 +68,7 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages,
int *nr)
{
- struct page *head, *page, *tail;
+ struct page *head, *page;
int refs;
if (!(pmd_val(pmd) & _PAGE_VALID))
@@ -82,7 +80,6 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
refs = 0;
head = pmd_page(pmd);
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
- tail = page;
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
@@ -103,15 +100,6 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
return 0;
}
- /* Any tail page need their mapcount reference taken before we
- * return.
- */
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
return 1;
}
@@ -126,7 +114,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmd_t pmd = *pmdp;
next = pmd_addr_end(addr, end);
- if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+ if (pmd_none(pmd))
return 0;
if (unlikely(pmd_large(pmd))) {
if (!gup_huge_pmd(pmdp, pmd, addr, next,
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 3025bd57f7ab..6f216853f272 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -1267,13 +1267,6 @@ static int __init numa_parse_mdesc(void)
int i, j, err, count;
u64 node;
- /* Some sane defaults for numa latency values */
- for (i = 0; i < MAX_NUMNODES; i++) {
- for (j = 0; j < MAX_NUMNODES; j++)
- numa_latency[i][j] = (i == j) ?
- LOCAL_DISTANCE : REMOTE_DISTANCE;
- }
-
node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups");
if (node == MDESC_NODE_NULL) {
mdesc_release(md);
@@ -1369,10 +1362,18 @@ static int __init numa_parse_sun4u(void)
static int __init bootmem_init_numa(void)
{
+ int i, j;
int err = -1;
numadbg("bootmem_init_numa()\n");
+ /* Some sane defaults for numa latency values */
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ for (j = 0; j < MAX_NUMNODES; j++)
+ numa_latency[i][j] = (i == j) ?
+ LOCAL_DISTANCE : REMOTE_DISTANCE;
+ }
+
if (numa_enabled) {
if (tlb_type == hypervisor)
err = numa_parse_mdesc();
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 8ec7a4599c08..6bfbe8b71e7e 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -19,6 +19,7 @@ config TILE
select VIRT_TO_BUS
select SYS_HYPERVISOR
select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA
@@ -116,9 +117,6 @@ config ARCH_DISCONTIGMEM_DEFAULT
config TRACE_IRQFLAGS_SUPPORT
def_bool y
-config STRICT_DEVMEM
- def_bool y
-
# SMP is required for Tilera Linux.
config SMP
def_bool y
@@ -143,6 +141,7 @@ config TILEGX
select HAVE_KRETPROBES
select HAVE_ARCH_KGDB
select ARCH_SUPPORTS_ATOMIC_RMW
+ select HAVE_ARCH_JUMP_LABEL
config TILEPRO
def_bool !TILEGX
diff --git a/arch/tile/include/asm/barrier.h b/arch/tile/include/asm/barrier.h
index 96a42ae79f4d..d55222806c2f 100644
--- a/arch/tile/include/asm/barrier.h
+++ b/arch/tile/include/asm/barrier.h
@@ -79,11 +79,12 @@ mb_incoherent(void)
* But after the word is updated, the routine issues an "mf" before returning,
* and since it's a function call, we don't even need a compiler barrier.
*/
-#define smp_mb__before_atomic() smp_mb()
-#define smp_mb__after_atomic() do { } while (0)
+#define __smp_mb__before_atomic() __smp_mb()
+#define __smp_mb__after_atomic() do { } while (0)
+#define smp_mb__after_atomic() __smp_mb__after_atomic()
#else /* 64 bit */
-#define smp_mb__before_atomic() smp_mb()
-#define smp_mb__after_atomic() smp_mb()
+#define __smp_mb__before_atomic() __smp_mb()
+#define __smp_mb__after_atomic() __smp_mb()
#endif
#include <asm-generic/barrier.h>
diff --git a/arch/tile/include/asm/insn.h b/arch/tile/include/asm/insn.h
new file mode 100644
index 000000000000..f78ba5c16722
--- /dev/null
+++ b/arch/tile/include/asm/insn.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+#ifndef __ASM_TILE_INSN_H
+#define __ASM_TILE_INSN_H
+
+#include <arch/opcode.h>
+
+static inline tilegx_bundle_bits NOP(void)
+{
+ return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) |
+ create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) |
+ create_Opcode_X0(RRR_0_OPCODE_X0) |
+ create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) |
+ create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) |
+ create_Opcode_X1(RRR_0_OPCODE_X1);
+}
+
+static inline tilegx_bundle_bits tilegx_gen_branch(unsigned long pc,
+ unsigned long addr,
+ bool link)
+{
+ tilegx_bundle_bits opcode_x0, opcode_x1;
+ long pcrel_by_instr = (addr - pc) >> TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES;
+
+ if (link) {
+ /* opcode: jal addr */
+ opcode_x1 =
+ create_Opcode_X1(JUMP_OPCODE_X1) |
+ create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) |
+ create_JumpOff_X1(pcrel_by_instr);
+ } else {
+ /* opcode: j addr */
+ opcode_x1 =
+ create_Opcode_X1(JUMP_OPCODE_X1) |
+ create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) |
+ create_JumpOff_X1(pcrel_by_instr);
+ }
+
+ /* opcode: fnop */
+ opcode_x0 =
+ create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) |
+ create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) |
+ create_Opcode_X0(RRR_0_OPCODE_X0);
+
+ return opcode_x1 | opcode_x0;
+}
+
+#endif /* __ASM_TILE_INSN_H */
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index 322b5fe94781..30f4a210d148 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -161,14 +161,14 @@ extern void _tile_writew(u16 val, unsigned long addr);
extern void _tile_writel(u32 val, unsigned long addr);
extern void _tile_writeq(u64 val, unsigned long addr);
-#define __raw_readb(addr) _tile_readb((unsigned long)addr)
-#define __raw_readw(addr) _tile_readw((unsigned long)addr)
-#define __raw_readl(addr) _tile_readl((unsigned long)addr)
-#define __raw_readq(addr) _tile_readq((unsigned long)addr)
-#define __raw_writeb(val, addr) _tile_writeb(val, (unsigned long)addr)
-#define __raw_writew(val, addr) _tile_writew(val, (unsigned long)addr)
-#define __raw_writel(val, addr) _tile_writel(val, (unsigned long)addr)
-#define __raw_writeq(val, addr) _tile_writeq(val, (unsigned long)addr)
+#define __raw_readb(addr) _tile_readb((unsigned long)(addr))
+#define __raw_readw(addr) _tile_readw((unsigned long)(addr))
+#define __raw_readl(addr) _tile_readl((unsigned long)(addr))
+#define __raw_readq(addr) _tile_readq((unsigned long)(addr))
+#define __raw_writeb(val, addr) _tile_writeb(val, (unsigned long)(addr))
+#define __raw_writew(val, addr) _tile_writew(val, (unsigned long)(addr))
+#define __raw_writel(val, addr) _tile_writel(val, (unsigned long)(addr))
+#define __raw_writeq(val, addr) _tile_writeq(val, (unsigned long)(addr))
#else /* CONFIG_PCI */
diff --git a/arch/tile/include/asm/jump_label.h b/arch/tile/include/asm/jump_label.h
new file mode 100644
index 000000000000..cde7573f397b
--- /dev/null
+++ b/arch/tile/include/asm/jump_label.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_JUMP_LABEL_H
+#define _ASM_TILE_JUMP_LABEL_H
+
+#include <arch/opcode.h>
+
+#define JUMP_LABEL_NOP_SIZE TILE_BUNDLE_SIZE_IN_BYTES
+
+static __always_inline bool arch_static_branch(struct static_key *key,
+ bool branch)
+{
+ asm_volatile_goto("1:\n\t"
+ "nop" "\n\t"
+ ".pushsection __jump_table, \"aw\"\n\t"
+ ".quad 1b, %l[l_yes], %0 + %1 \n\t"
+ ".popsection\n\t"
+ : : "i" (key), "i" (branch) : : l_yes);
+ return false;
+l_yes:
+ return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key *key,
+ bool branch)
+{
+ asm_volatile_goto("1:\n\t"
+ "j %l[l_yes]" "\n\t"
+ ".pushsection __jump_table, \"aw\"\n\t"
+ ".quad 1b, %l[l_yes], %0 + %1 \n\t"
+ ".popsection\n\t"
+ : : "i" (key), "i" (branch) : : l_yes);
+ return false;
+l_yes:
+ return true;
+}
+
+typedef u64 jump_label_t;
+
+struct jump_entry {
+ jump_label_t code;
+ jump_label_t target;
+ jump_label_t key;
+};
+
+#endif /* _ASM_TILE_JUMP_LABEL_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index 8eca6a0e1762..498a5f71245d 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -321,6 +321,16 @@ static inline int pfn_valid(unsigned long pfn)
#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn((void *)(kaddr)))
#define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page))
+/*
+ * The kernel text is mapped at MEM_SV_START as read-only. To allow
+ * modifying kernel text, it is also mapped at PAGE_OFFSET as read-write.
+ * This macro converts a kernel address to its writable kernel text mapping,
+ * which is used to modify the text code on a running kernel by kgdb,
+ * ftrace, kprobe, jump label, etc.
+ */
+#define ktext_writable_addr(kaddr) \
+ ((unsigned long)(kaddr) - MEM_SV_START + PAGE_OFFSET)
+
struct mm_struct;
extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
extern pte_t *virt_to_kpte(unsigned long kaddr);
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index 2b05ccbebed9..96cecf55522e 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
@@ -489,16 +489,6 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define has_transparent_hugepage() 1
#define pmd_trans_huge pmd_huge_page
-
-static inline pmd_t pmd_mksplitting(pmd_t pmd)
-{
- return pte_pmd(hv_pte_set_client2(pmd_pte(pmd)));
-}
-
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- return hv_pte_get_client2(pmd_pte(pmd));
-}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
/*
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index 139dfdee0134..0684e88aacd8 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -212,7 +212,7 @@ static inline void release_thread(struct task_struct *dead_task)
/* Nothing for now */
}
-extern int do_work_pending(struct pt_regs *regs, u32 flags);
+extern void prepare_exit_to_usermode(struct pt_regs *regs, u32 flags);
/*
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h
index dc1fb28d9636..4b7cef9e94e0 100644
--- a/arch/tile/include/asm/thread_info.h
+++ b/arch/tile/include/asm/thread_info.h
@@ -140,10 +140,14 @@ extern void _cpu_idle(void);
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_NOHZ (1<<TIF_NOHZ)
+/* Work to do as we loop to exit to user space. */
+#define _TIF_WORK_MASK \
+ (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+ _TIF_ASYNC_TLB | _TIF_NOTIFY_RESUME)
+
/* Work to do on any return to user space. */
#define _TIF_ALLWORK_MASK \
- (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP | \
- _TIF_ASYNC_TLB | _TIF_NOTIFY_RESUME | _TIF_NOHZ)
+ (_TIF_WORK_MASK | _TIF_SINGLESTEP | _TIF_NOHZ)
/* Work to do at syscall entry. */
#define _TIF_SYSCALL_ENTRY_WORK \
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index 76b0d0ebb244..b11d5fcd2c41 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -44,9 +44,6 @@ static inline const struct cpumask *cpumask_of_node(int node)
/* For now, use numa node -1 for global allocation. */
#define pcibus_to_node(bus) ((void)(bus), -1)
-/* By definition, we create nodes based on online memory. */
-#define node_has_online_mem(nid) 1
-
#endif /* CONFIG_NUMA */
#include <asm-generic/topology.h>
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile
index 21f77bf68c69..09936d0bcb42 100644
--- a/arch/tile/kernel/Makefile
+++ b/arch/tile/kernel/Makefile
@@ -32,5 +32,6 @@ obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-y += vdso/
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c
index 0c0996175b1e..4a572088b270 100644
--- a/arch/tile/kernel/ftrace.c
+++ b/arch/tile/kernel/ftrace.c
@@ -20,21 +20,12 @@
#include <asm/cacheflush.h>
#include <asm/ftrace.h>
#include <asm/sections.h>
+#include <asm/insn.h>
#include <arch/opcode.h>
#ifdef CONFIG_DYNAMIC_FTRACE
-static inline tilegx_bundle_bits NOP(void)
-{
- return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) |
- create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) |
- create_Opcode_X0(RRR_0_OPCODE_X0) |
- create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) |
- create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) |
- create_Opcode_X1(RRR_0_OPCODE_X1);
-}
-
static int machine_stopped __read_mostly;
int ftrace_arch_code_modify_prepare(void)
@@ -117,7 +108,7 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
return -EINVAL;
/* Operate on writable kernel text mapping. */
- pc_wr = pc - MEM_SV_START + PAGE_OFFSET;
+ pc_wr = ktext_writable_addr(pc);
if (probe_kernel_write((void *)pc_wr, &new, MCOUNT_INSN_SIZE))
return -EPERM;
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index fbbe2ea882ea..9ff75e3a318a 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -572,7 +572,7 @@ intvec_\vecname:
}
wh64 r52
-#ifdef CONFIG_TRACE_IRQFLAGS
+#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
.ifnc \function,handle_nmi
/*
* We finally have enough state set up to notify the irq
@@ -588,6 +588,9 @@ intvec_\vecname:
{ move r32, r2; move r33, r3 }
.endif
TRACE_IRQS_OFF
+#ifdef CONFIG_CONTEXT_TRACKING
+ jal context_tracking_user_exit
+#endif
.ifnc \function,handle_syscall
{ move r0, r30; move r1, r31 }
{ move r2, r32; move r3, r33 }
@@ -846,18 +849,6 @@ STD_ENTRY(interrupt_return)
FEEDBACK_REENTER(interrupt_return)
/*
- * Use r33 to hold whether we have already loaded the callee-saves
- * into ptregs. We don't want to do it twice in this loop, since
- * then we'd clobber whatever changes are made by ptrace, etc.
- * Get base of stack in r32.
- */
- {
- GET_THREAD_INFO(r32)
- movei r33, 0
- }
-
-.Lretry_work_pending:
- /*
* Disable interrupts so as to make sure we don't
* miss an interrupt that sets any of the thread flags (like
* need_resched or sigpending) between sampling and the iret.
@@ -867,33 +858,27 @@ STD_ENTRY(interrupt_return)
IRQ_DISABLE(r20, r21)
TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */
-
- /* Check to see if there is any work to do before returning to user. */
+ /*
+ * See if there are any work items (including single-shot items)
+ * to do. If so, save the callee-save registers to pt_regs
+ * and then dispatch to C code.
+ */
+ GET_THREAD_INFO(r21)
{
- addi r29, r32, THREAD_INFO_FLAGS_OFFSET
- moveli r1, lo16(_TIF_ALLWORK_MASK)
+ addi r22, r21, THREAD_INFO_FLAGS_OFFSET
+ moveli r20, lo16(_TIF_ALLWORK_MASK)
}
{
- lw r29, r29
- auli r1, r1, ha16(_TIF_ALLWORK_MASK)
+ lw r22, r22
+ auli r20, r20, ha16(_TIF_ALLWORK_MASK)
}
- and r1, r29, r1
- bzt r1, .Lrestore_all
-
- /*
- * Make sure we have all the registers saved for signal
- * handling, notify-resume, or single-step. Call out to C
- * code to figure out exactly what we need to do for each flag bit,
- * then if necessary, reload the flags and recheck.
- */
+ and r1, r22, r20
{
PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
- bnz r33, 1f
+ bzt r1, .Lrestore_all
}
push_extra_callee_saves r0
- movei r33, 1
-1: jal do_work_pending
- bnz r0, .Lretry_work_pending
+ jal prepare_exit_to_usermode
/*
* In the NMI case we
@@ -1327,7 +1312,7 @@ STD_ENTRY(ret_from_kernel_thread)
FEEDBACK_REENTER(ret_from_kernel_thread)
{
movei r30, 0 /* not an NMI */
- j .Lresume_userspace /* jump into middle of interrupt_return */
+ j interrupt_return
}
STD_ENDPROC(ret_from_kernel_thread)
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 58964d209d4d..3b51bdf37d11 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -658,7 +658,7 @@ intvec_\vecname:
*/
mfspr r32, SPR_EX_CONTEXT_K_1
{
- IS_KERNEL_EX1(r22, r22)
+ IS_KERNEL_EX1(r32, r32)
PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
}
beqzt r32, 1f /* zero if from user space */
@@ -753,7 +753,7 @@ intvec_\vecname:
}
wh64 r52
-#ifdef CONFIG_TRACE_IRQFLAGS
+#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
.ifnc \function,handle_nmi
/*
* We finally have enough state set up to notify the irq
@@ -769,6 +769,9 @@ intvec_\vecname:
{ move r32, r2; move r33, r3 }
.endif
TRACE_IRQS_OFF
+#ifdef CONFIG_CONTEXT_TRACKING
+ jal context_tracking_user_exit
+#endif
.ifnc \function,handle_syscall
{ move r0, r30; move r1, r31 }
{ move r2, r32; move r3, r33 }
@@ -879,20 +882,6 @@ STD_ENTRY(interrupt_return)
FEEDBACK_REENTER(interrupt_return)
/*
- * Use r33 to hold whether we have already loaded the callee-saves
- * into ptregs. We don't want to do it twice in this loop, since
- * then we'd clobber whatever changes are made by ptrace, etc.
- */
- {
- movei r33, 0
- move r32, sp
- }
-
- /* Get base of stack in r32. */
- EXTRACT_THREAD_INFO(r32)
-
-.Lretry_work_pending:
- /*
* Disable interrupts so as to make sure we don't
* miss an interrupt that sets any of the thread flags (like
* need_resched or sigpending) between sampling and the iret.
@@ -902,33 +891,28 @@ STD_ENTRY(interrupt_return)
IRQ_DISABLE(r20, r21)
TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */
-
- /* Check to see if there is any work to do before returning to user. */
+ /*
+ * See if there are any work items (including single-shot items)
+ * to do. If so, save the callee-save registers to pt_regs
+ * and then dispatch to C code.
+ */
+ move r21, sp
+ EXTRACT_THREAD_INFO(r21)
{
- addi r29, r32, THREAD_INFO_FLAGS_OFFSET
- moveli r1, hw1_last(_TIF_ALLWORK_MASK)
+ addi r22, r21, THREAD_INFO_FLAGS_OFFSET
+ moveli r20, hw1_last(_TIF_ALLWORK_MASK)
}
{
- ld r29, r29
- shl16insli r1, r1, hw0(_TIF_ALLWORK_MASK)
+ ld r22, r22
+ shl16insli r20, r20, hw0(_TIF_ALLWORK_MASK)
}
- and r1, r29, r1
- beqzt r1, .Lrestore_all
-
- /*
- * Make sure we have all the registers saved for signal
- * handling or notify-resume. Call out to C code to figure out
- * exactly what we need to do for each flag bit, then if
- * necessary, reload the flags and recheck.
- */
+ and r1, r22, r20
{
PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
- bnez r33, 1f
+ beqzt r1, .Lrestore_all
}
push_extra_callee_saves r0
- movei r33, 1
-1: jal do_work_pending
- bnez r0, .Lretry_work_pending
+ jal prepare_exit_to_usermode
/*
* In the NMI case we
@@ -1411,7 +1395,7 @@ STD_ENTRY(ret_from_kernel_thread)
FEEDBACK_REENTER(ret_from_kernel_thread)
{
movei r30, 0 /* not an NMI */
- j .Lresume_userspace /* jump into middle of interrupt_return */
+ j interrupt_return
}
STD_ENDPROC(ret_from_kernel_thread)
diff --git a/arch/tile/kernel/jump_label.c b/arch/tile/kernel/jump_label.c
new file mode 100644
index 000000000000..07802d586988
--- /dev/null
+++ b/arch/tile/kernel/jump_label.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * jump label TILE-Gx support
+ */
+
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/insn.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+static void __jump_label_transform(struct jump_entry *e,
+ enum jump_label_type type)
+{
+ tilegx_bundle_bits opcode;
+ /* Operate on writable kernel text mapping. */
+ unsigned long pc_wr = ktext_writable_addr(e->code);
+
+ if (type == JUMP_LABEL_JMP)
+ opcode = tilegx_gen_branch(e->code, e->target, false);
+ else
+ opcode = NOP();
+
+ *(tilegx_bundle_bits *)pc_wr = opcode;
+ /* Make sure that above mem writes were issued towards the memory. */
+ smp_wmb();
+}
+
+void arch_jump_label_transform(struct jump_entry *e,
+ enum jump_label_type type)
+{
+ get_online_cpus();
+ mutex_lock(&text_mutex);
+
+ __jump_label_transform(e, type);
+ flush_icache_range(e->code, e->code + sizeof(tilegx_bundle_bits));
+
+ mutex_unlock(&text_mutex);
+ put_online_cpus();
+}
+
+__init_or_module void arch_jump_label_transform_static(struct jump_entry *e,
+ enum jump_label_type type)
+{
+ __jump_label_transform(e, type);
+}
+
+#endif /* HAVE_JUMP_LABEL */
diff --git a/arch/tile/kernel/kgdb.c b/arch/tile/kernel/kgdb.c
index ff5335ae050d..a506c2c28943 100644
--- a/arch/tile/kernel/kgdb.c
+++ b/arch/tile/kernel/kgdb.c
@@ -164,7 +164,7 @@ static unsigned long writable_address(unsigned long addr)
unsigned long ret = 0;
if (core_kernel_text(addr))
- ret = addr - MEM_SV_START + PAGE_OFFSET;
+ ret = ktext_writable_addr(addr);
else if (is_module_text_address(addr))
ret = addr;
else
diff --git a/arch/tile/kernel/kprobes.c b/arch/tile/kernel/kprobes.c
index f8a45c51e9e4..c68694bb1ad2 100644
--- a/arch/tile/kernel/kprobes.c
+++ b/arch/tile/kernel/kprobes.c
@@ -116,7 +116,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
unsigned long addr_wr;
/* Operate on writable kernel text mapping. */
- addr_wr = (unsigned long)p->addr - MEM_SV_START + PAGE_OFFSET;
+ addr_wr = ktext_writable_addr(p->addr);
if (probe_kernel_write((void *)addr_wr, &breakpoint_insn,
sizeof(breakpoint_insn)))
@@ -131,7 +131,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *kp)
unsigned long addr_wr;
/* Operate on writable kernel text mapping. */
- addr_wr = (unsigned long)kp->addr - MEM_SV_START + PAGE_OFFSET;
+ addr_wr = ktext_writable_addr(kp->addr);
if (probe_kernel_write((void *)addr_wr, &kp->opcode,
sizeof(kp->opcode)))
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 7d5769310bef..b5f30d376ce1 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -462,54 +462,57 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
/*
* This routine is called on return from interrupt if any of the
- * TIF_WORK_MASK flags are set in thread_info->flags. It is
- * entered with interrupts disabled so we don't miss an event
- * that modified the thread_info flags. If any flag is set, we
- * handle it and return, and the calling assembly code will
- * re-disable interrupts, reload the thread flags, and call back
- * if more flags need to be handled.
- *
- * We return whether we need to check the thread_info flags again
- * or not. Note that we don't clear TIF_SINGLESTEP here, so it's
- * important that it be tested last, and then claim that we don't
- * need to recheck the flags.
+ * TIF_ALLWORK_MASK flags are set in thread_info->flags. It is
+ * entered with interrupts disabled so we don't miss an event that
+ * modified the thread_info flags. We loop until all the tested flags
+ * are clear. Note that the function is called on certain conditions
+ * that are not listed in the loop condition here (e.g. SINGLESTEP)
+ * which guarantees we will do those things once, and redo them if any
+ * of the other work items is re-done, but won't continue looping if
+ * all the other work is done.
*/
-int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
+void prepare_exit_to_usermode(struct pt_regs *regs, u32 thread_info_flags)
{
- /* If we enter in kernel mode, do nothing and exit the caller loop. */
- if (!user_mode(regs))
- return 0;
+ if (WARN_ON(!user_mode(regs)))
+ return;
- user_exit();
+ do {
+ local_irq_enable();
- /* Enable interrupts; they are disabled again on return to caller. */
- local_irq_enable();
+ if (thread_info_flags & _TIF_NEED_RESCHED)
+ schedule();
- if (thread_info_flags & _TIF_NEED_RESCHED) {
- schedule();
- return 1;
- }
#if CHIP_HAS_TILE_DMA()
- if (thread_info_flags & _TIF_ASYNC_TLB) {
- do_async_page_fault(regs);
- return 1;
- }
+ if (thread_info_flags & _TIF_ASYNC_TLB)
+ do_async_page_fault(regs);
#endif
- if (thread_info_flags & _TIF_SIGPENDING) {
- do_signal(regs);
- return 1;
- }
- if (thread_info_flags & _TIF_NOTIFY_RESUME) {
- clear_thread_flag(TIF_NOTIFY_RESUME);
- tracehook_notify_resume(regs);
- return 1;
- }
- if (thread_info_flags & _TIF_SINGLESTEP)
+
+ if (thread_info_flags & _TIF_SIGPENDING)
+ do_signal(regs);
+
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ }
+
+ local_irq_disable();
+ thread_info_flags = READ_ONCE(current_thread_info()->flags);
+
+ } while (thread_info_flags & _TIF_WORK_MASK);
+
+ if (thread_info_flags & _TIF_SINGLESTEP) {
single_step_once(regs);
+#ifndef __tilegx__
+ /*
+ * FIXME: on tilepro, since we enable interrupts in
+ * this routine, it's possible that we miss a signal
+ * or other asynchronous event.
+ */
+ local_irq_disable();
+#endif
+ }
user_enter();
-
- return 0;
}
unsigned long get_wchan(struct task_struct *p)
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index bdc126faf741..54e7b723db99 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -255,13 +255,6 @@ int do_syscall_trace_enter(struct pt_regs *regs)
{
u32 work = ACCESS_ONCE(current_thread_info()->flags);
- /*
- * If TIF_NOHZ is set, we are required to call user_exit() before
- * doing anything that could touch RCU.
- */
- if (work & _TIF_NOHZ)
- user_exit();
-
if (secure_computing() == -1)
return -1;
@@ -281,12 +274,6 @@ void do_syscall_trace_exit(struct pt_regs *regs)
long errno;
/*
- * We may come here right after calling schedule_user()
- * in which case we can be in RCU user mode.
- */
- user_exit();
-
- /*
* The standard tile calling convention returns the value (or negative
* errno) in r0, and zero (or positive errno) in r1.
* It saves a couple of cycles on the hot path to do this work in
@@ -322,7 +309,5 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs)
/* Handle synthetic interrupt delivered only by the simulator. */
void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
{
- enum ctx_state prev_state = exception_enter();
send_sigtrap(current, regs);
- exception_exit(prev_state);
}
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 6b755d125783..bbb855de6569 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -882,7 +882,7 @@ static int __init node_neighbors(int node, int cpu,
static void __init setup_numa_mapping(void)
{
- int distance[MAX_NUMNODES][NR_CPUS];
+ u8 distance[MAX_NUMNODES][NR_CPUS];
HV_Coord coord;
int cpu, node, cpus, i, x, y;
int num_nodes = num_online_nodes();
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 53f7b9def07b..862973074bf9 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -23,7 +23,6 @@
#include <linux/types.h>
#include <linux/err.h>
#include <linux/prctl.h>
-#include <linux/context_tracking.h>
#include <asm/cacheflush.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
@@ -739,7 +738,6 @@ static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
{
- enum ctx_state prev_state = exception_enter();
unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc);
struct thread_info *info = (void *)current_thread_info();
int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
@@ -756,7 +754,6 @@ void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
send_sigtrap(current, regs);
}
- exception_exit(prev_state);
}
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index 402b9c85a894..22bbbd3ff4a3 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -78,8 +78,7 @@ static bool read_memory_func(void *result, unsigned long address,
/* Return a pt_regs pointer for a valid fault handler frame */
static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
{
- const char *fault = NULL; /* happy compiler */
- char fault_buf[64];
+ char fault[64];
unsigned long sp = kbt->it.sp;
struct pt_regs *p;
@@ -90,14 +89,14 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
if (!in_kernel_stack(kbt, sp + C_ABI_SAVE_AREA_SIZE + PTREGS_SIZE-1))
return NULL;
p = (struct pt_regs *)(sp + C_ABI_SAVE_AREA_SIZE);
- if (p->faultnum == INT_SWINT_1 || p->faultnum == INT_SWINT_1_SIGRETURN)
- fault = "syscall";
- else {
- if (kbt->verbose) { /* else we aren't going to use it */
- snprintf(fault_buf, sizeof(fault_buf),
+ if (kbt->verbose) { /* else we aren't going to use it */
+ if (p->faultnum == INT_SWINT_1 ||
+ p->faultnum == INT_SWINT_1_SIGRETURN)
+ snprintf(fault, sizeof(fault),
+ "syscall %ld", p->regs[TREG_SYSCALL_NR]);
+ else
+ snprintf(fault, sizeof(fault),
"interrupt %ld", p->faultnum);
- fault = fault_buf;
- }
}
if (EX1_PL(p->ex1) == KERNEL_PL &&
__kernel_text_address(p->pc) &&
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 0011a9ff0525..4d9651c5b1ad 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -20,7 +20,6 @@
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <linux/ptrace.h>
-#include <linux/context_tracking.h>
#include <asm/stack.h>
#include <asm/traps.h>
#include <asm/setup.h>
@@ -254,7 +253,6 @@ static int do_bpt(struct pt_regs *regs)
void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason)
{
- enum ctx_state prev_state = exception_enter();
siginfo_t info = { 0 };
int signo, code;
unsigned long address = 0;
@@ -263,7 +261,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
/* Handle breakpoints, etc. */
if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
- goto done;
+ return;
/* Re-enable interrupts, if they were previously enabled. */
if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
@@ -277,7 +275,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
const char *name;
char buf[100];
if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */
- goto done;
+ return;
if (fault_num >= 0 &&
fault_num < ARRAY_SIZE(int_name) &&
int_name[fault_num] != NULL)
@@ -319,7 +317,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
case INT_GPV:
#if CHIP_HAS_TILE_DMA()
if (retry_gpv(reason))
- goto done;
+ return;
#endif
/*FALLTHROUGH*/
case INT_UDN_ACCESS:
@@ -346,7 +344,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
if (!state ||
(void __user *)(regs->pc) != state->buffer) {
single_step_once(regs);
- goto done;
+ return;
}
}
#endif
@@ -390,9 +388,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
if (signo != SIGTRAP)
trace_unhandled_signal("trap", regs, address, signo);
force_sig_info(signo, &info, current);
-
-done:
- exception_exit(prev_state);
}
void do_nmi(struct pt_regs *regs, int fault_num, unsigned long reason)
diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c
index d075f92ccee0..0db5f7c9d9e5 100644
--- a/arch/tile/kernel/unaligned.c
+++ b/arch/tile/kernel/unaligned.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/compat.h>
#include <linux/prctl.h>
-#include <linux/context_tracking.h>
#include <asm/cacheflush.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
@@ -1449,7 +1448,6 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle,
void do_unaligned(struct pt_regs *regs, int vecnum)
{
- enum ctx_state prev_state = exception_enter();
tilegx_bundle_bits __user *pc;
tilegx_bundle_bits bundle;
struct thread_info *info = current_thread_info();
@@ -1503,7 +1501,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
*((tilegx_bundle_bits *)(regs->pc)));
jit_bundle_gen(regs, bundle, align_ctl);
}
- goto done;
+ return;
}
/*
@@ -1527,7 +1525,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS);
force_sig_info(info.si_signo, &info, current);
- goto done;
+ return;
}
@@ -1544,7 +1542,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
trace_unhandled_signal("segfault in unalign fixup", regs,
(unsigned long)info.si_addr, SIGSEGV);
force_sig_info(info.si_signo, &info, current);
- goto done;
+ return;
}
if (!info->unalign_jit_base) {
@@ -1579,7 +1577,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
if (IS_ERR((void __force *)user_page)) {
pr_err("Out of kernel pages trying do_mmap\n");
- goto done;
+ return;
}
/* Save the address in the thread_info struct */
@@ -1592,9 +1590,6 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
/* Generate unalign JIT */
jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl);
-
-done:
- exception_exit(prev_state);
}
#endif /* __tilegx__ */
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 13eac59bf16a..26734214818c 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -35,7 +35,6 @@
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
-#include <linux/context_tracking.h>
#include <asm/pgalloc.h>
#include <asm/sections.h>
@@ -845,9 +844,7 @@ static inline void __do_page_fault(struct pt_regs *regs, int fault_num,
void do_page_fault(struct pt_regs *regs, int fault_num,
unsigned long address, unsigned long write)
{
- enum ctx_state prev_state = exception_enter();
__do_page_fault(regs, fault_num, address, write);
- exception_exit(prev_state);
}
#if CHIP_HAS_TILE_DMA()
diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
index 71c5d132062a..e13d41c392ae 100644
--- a/arch/um/include/asm/page.h
+++ b/arch/um/include/asm/page.h
@@ -18,6 +18,7 @@
struct page;
+#include <linux/pfn.h>
#include <linux/types.h>
#include <asm/vm-flags.h>
@@ -52,7 +53,6 @@ typedef struct { unsigned long pgd; } pgd_t;
#define pmd_val(x) ((x).pmd)
#define __pmd(x) ((pmd_t) { (x) } )
-typedef unsigned long long pfn_t;
typedef unsigned long long phys_t;
#else
@@ -76,7 +76,6 @@ typedef struct { unsigned long pmd; } pmd_t;
#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE))
#define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot))
-typedef unsigned long pfn_t;
typedef unsigned long phys_t;
#endif
@@ -109,8 +108,8 @@ extern unsigned long uml_physmem;
#define __pa(virt) to_phys((void *) (unsigned long) (virt))
#define __va(phys) to_virt((unsigned long) (phys))
-#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT))
-#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT))
+#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
+#define pfn_to_phys(pfn) PFN_PHYS(pfn)
#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h
index 2b4274e7c095..bae8523a162f 100644
--- a/arch/um/include/asm/pgtable-3level.h
+++ b/arch/um/include/asm/pgtable-3level.h
@@ -98,7 +98,7 @@ static inline unsigned long pte_pfn(pte_t pte)
return phys_to_pfn(pte_val(pte));
}
-static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot)
+static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
pte_t pte;
phys_t phys = pfn_to_phys(page_nr);
@@ -107,7 +107,7 @@ static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot)
return pte;
}
-static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot)
+static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
{
return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
}
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 18eb9924dda3..7485398d0737 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -271,7 +271,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)
#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys))
#define __virt_to_page(virt) phys_to_page(__pa(virt))
-#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page))
+#define page_to_phys(page) pfn_to_phys(page_to_pfn(page))
#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
#define mk_pte(page, pgprot) \
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index c9faddc61100..877342640b6e 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -1,5 +1,6 @@
config UNICORE32
def_bool y
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_MIGHT_HAVE_PC_SERIO
select HAVE_MEMBLOCK
@@ -33,9 +34,6 @@ config NO_IOPORT_MAP
config STACKTRACE_SUPPORT
def_bool y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config LOCKDEP_SUPPORT
def_bool y
diff --git a/arch/unicore32/Kconfig.debug b/arch/unicore32/Kconfig.debug
index 1a3626239843..f075bbe1d46f 100644
--- a/arch/unicore32/Kconfig.debug
+++ b/arch/unicore32/Kconfig.debug
@@ -2,20 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config STRICT_DEVMEM
- bool "Filter access to /dev/mem"
- depends on MMU
- ---help---
- If this option is disabled, you allow userspace (root) access to all
- of memory, including kernel and userspace memory. Accidental
- access to this is obviously disastrous, but specific access can
- be used by people debugging the kernel.
-
- If this option is switched on, the /dev/mem file only allows
- userspace access to memory mapped peripherals.
-
- If in doubt, say Y.
-
config EARLY_PRINTK
def_bool DEBUG_OCD
help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ccfededfe470..4a10ba9e95da 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -24,6 +24,7 @@ config X86
select ARCH_DISCARD_MEMBLOCK
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FAST_MULTIPLIER
select ARCH_HAS_GCOV_PROFILE_ALL
@@ -82,6 +83,8 @@ config X86
select HAVE_ARCH_KASAN if X86_64 && SPARSEMEM_VMEMMAP
select HAVE_ARCH_KGDB
select HAVE_ARCH_KMEMCHECK
+ select HAVE_ARCH_MMAP_RND_BITS if MMU
+ select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_SOFT_DIRTY if X86_64
select HAVE_ARCH_TRACEHOOK
@@ -177,12 +180,23 @@ config LOCKDEP_SUPPORT
config STACKTRACE_SUPPORT
def_bool y
-config HAVE_LATENCYTOP_SUPPORT
- def_bool y
-
config MMU
def_bool y
+config ARCH_MMAP_RND_BITS_MIN
+ default 28 if 64BIT
+ default 8
+
+config ARCH_MMAP_RND_BITS_MAX
+ default 32 if 64BIT
+ default 16
+
+config ARCH_MMAP_RND_COMPAT_BITS_MIN
+ default 8
+
+config ARCH_MMAP_RND_COMPAT_BITS_MAX
+ default 16
+
config SBUS
bool
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 110253ce83af..9b18ed97a8a2 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -5,23 +5,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-config STRICT_DEVMEM
- bool "Filter access to /dev/mem"
- ---help---
- If this option is disabled, you allow userspace (root) access to all
- of memory, including kernel and userspace memory. Accidental
- access to this is obviously disastrous, but specific access can
- be used by people debugging the kernel. Note that with PAT support
- enabled, even in this case there are restrictions on /dev/mem
- use due to the cache aliasing requirements.
-
- If this option is switched on, the /dev/mem file only allows
- userspace access to PCI space and the BIOS code and data regions.
- This is sufficient for dosemu and X and all common users of
- /dev/mem.
-
- If in doubt, say Y.
-
config X86_VERBOSE_BOOTUP
bool "Enable verbose x86 bootup info messages"
default y
diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index 8602f06c759f..1a50e09c945b 100644
--- a/arch/x86/entry/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
@@ -126,23 +126,23 @@ static notrace cycle_t vread_pvclock(int *mode)
*
* On Xen, we don't appear to have that guarantee, but Xen still
* supplies a valid seqlock using the version field.
-
+ *
* We only do pvclock vdso timing at all if
* PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
* mean that all vCPUs have matching pvti and that the TSC is
* synced, so we can just look at vCPU 0's pvti.
*/
- if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
- *mode = VCLOCK_NONE;
- return 0;
- }
-
do {
version = pvti->version;
smp_rmb();
+ if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
+ *mode = VCLOCK_NONE;
+ return 0;
+ }
+
tsc = rdtsc_ordered();
pvti_tsc_to_system_mul = pvti->tsc_to_system_mul;
pvti_tsc_shift = pvti->tsc_shift;
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index 0681d2532527..a584e1c50918 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -31,20 +31,10 @@
#endif
#define dma_wmb() barrier()
-#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() dma_rmb()
-#define smp_wmb() barrier()
-#define smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
-#else /* !SMP */
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
-#endif /* SMP */
-
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
+#define __smp_mb() mb()
+#define __smp_rmb() dma_rmb()
+#define __smp_wmb() barrier()
+#define __smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
#if defined(CONFIG_X86_PPRO_FENCE)
@@ -53,31 +43,31 @@
* model and we should fall back to full barriers.
*/
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
- smp_mb(); \
+ __smp_mb(); \
WRITE_ONCE(*p, v); \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
- smp_mb(); \
+ __smp_mb(); \
___p1; \
})
#else /* regular x86 TSO memory ordering */
-#define smp_store_release(p, v) \
+#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
WRITE_ONCE(*p, v); \
} while (0)
-#define smp_load_acquire(p) \
+#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
@@ -88,7 +78,9 @@ do { \
#endif
/* Atomic operations are already serializing on x86 */
-#define smp_mb__before_atomic() barrier()
-#define smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
+
+#include <asm-generic/barrier.h>
#endif /* _ASM_X86_BARRIER_H */
diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h
index 4fa687a47a62..6b8d6e8cd449 100644
--- a/arch/x86/include/asm/boot.h
+++ b/arch/x86/include/asm/boot.h
@@ -27,7 +27,7 @@
#define BOOT_HEAP_SIZE 0x400000
#else /* !CONFIG_KERNEL_BZIP2 */
-#define BOOT_HEAP_SIZE 0x8000
+#define BOOT_HEAP_SIZE 0x10000
#endif /* !CONFIG_KERNEL_BZIP2 */
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index eadcdd5bb946..0fd440df63f1 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -42,6 +42,7 @@ extern void fpu__init_cpu_xstate(void);
extern void fpu__init_system(struct cpuinfo_x86 *c);
extern void fpu__init_check_bugs(void);
extern void fpu__resume_cpu(void);
+extern u64 fpu__get_supported_xfeatures_mask(void);
/*
* Debugging facility:
diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h
index 3a6c89b70307..af30fdeb140d 100644
--- a/arch/x86/include/asm/fpu/xstate.h
+++ b/arch/x86/include/asm/fpu/xstate.h
@@ -20,15 +20,16 @@
/* Supported features which support lazy state saving */
#define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \
- XFEATURE_MASK_SSE | \
+ XFEATURE_MASK_SSE)
+
+/* Supported features which require eager state saving */
+#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | \
+ XFEATURE_MASK_BNDCSR | \
XFEATURE_MASK_YMM | \
- XFEATURE_MASK_OPMASK | \
+ XFEATURE_MASK_OPMASK | \
XFEATURE_MASK_ZMM_Hi256 | \
XFEATURE_MASK_Hi16_ZMM)
-/* Supported features which require eager state saving */
-#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)
-
/* All currently supported features */
#define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER)
diff --git a/arch/x86/include/asm/intel_punit_ipc.h b/arch/x86/include/asm/intel_punit_ipc.h
new file mode 100644
index 000000000000..201eb9dce595
--- /dev/null
+++ b/arch/x86/include/asm/intel_punit_ipc.h
@@ -0,0 +1,101 @@
+#ifndef _ASM_X86_INTEL_PUNIT_IPC_H_
+#define _ASM_X86_INTEL_PUNIT_IPC_H_
+
+/*
+ * Three types of 8bit P-Unit IPC commands are supported,
+ * bit[7:6]: [00]: BIOS; [01]: GTD; [10]: ISPD.
+ */
+typedef enum {
+ BIOS_IPC = 0,
+ GTDRIVER_IPC,
+ ISPDRIVER_IPC,
+ RESERVED_IPC,
+} IPC_TYPE;
+
+#define IPC_TYPE_OFFSET 6
+#define IPC_PUNIT_BIOS_CMD_BASE (BIOS_IPC << IPC_TYPE_OFFSET)
+#define IPC_PUNIT_GTD_CMD_BASE (GTDDRIVER_IPC << IPC_TYPE_OFFSET)
+#define IPC_PUNIT_ISPD_CMD_BASE (ISPDRIVER_IPC << IPC_TYPE_OFFSET)
+#define IPC_PUNIT_CMD_TYPE_MASK (RESERVED_IPC << IPC_TYPE_OFFSET)
+
+/* BIOS => Pcode commands */
+#define IPC_PUNIT_BIOS_ZERO (IPC_PUNIT_BIOS_CMD_BASE | 0x00)
+#define IPC_PUNIT_BIOS_VR_INTERFACE (IPC_PUNIT_BIOS_CMD_BASE | 0x01)
+#define IPC_PUNIT_BIOS_READ_PCS (IPC_PUNIT_BIOS_CMD_BASE | 0x02)
+#define IPC_PUNIT_BIOS_WRITE_PCS (IPC_PUNIT_BIOS_CMD_BASE | 0x03)
+#define IPC_PUNIT_BIOS_READ_PCU_CONFIG (IPC_PUNIT_BIOS_CMD_BASE | 0x04)
+#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG (IPC_PUNIT_BIOS_CMD_BASE | 0x05)
+#define IPC_PUNIT_BIOS_READ_PL1_SETTING (IPC_PUNIT_BIOS_CMD_BASE | 0x06)
+#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING (IPC_PUNIT_BIOS_CMD_BASE | 0x07)
+#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM (IPC_PUNIT_BIOS_CMD_BASE | 0x08)
+#define IPC_PUNIT_BIOS_READ_TELE_INFO (IPC_PUNIT_BIOS_CMD_BASE | 0x09)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0a)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0b)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0c)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x0d)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE (IPC_PUNIT_BIOS_CMD_BASE | 0x0e)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE (IPC_PUNIT_BIOS_CMD_BASE | 0x0f)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT (IPC_PUNIT_BIOS_CMD_BASE | 0x10)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT (IPC_PUNIT_BIOS_CMD_BASE | 0x11)
+#define IPC_PUNIT_BIOS_READ_MODULE_TEMP (IPC_PUNIT_BIOS_CMD_BASE | 0x12)
+#define IPC_PUNIT_BIOS_RESERVED (IPC_PUNIT_BIOS_CMD_BASE | 0x13)
+#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x14)
+#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x15)
+#define IPC_PUNIT_BIOS_READ_RATIO_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x16)
+#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER (IPC_PUNIT_BIOS_CMD_BASE | 0x17)
+#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x18)
+#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL (IPC_PUNIT_BIOS_CMD_BASE | 0x19)
+#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH (IPC_PUNIT_BIOS_CMD_BASE | 0x1a)
+#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH (IPC_PUNIT_BIOS_CMD_BASE | 0x1b)
+
+/* GT Driver => Pcode commands */
+#define IPC_PUNIT_GTD_ZERO (IPC_PUNIT_GTD_CMD_BASE | 0x00)
+#define IPC_PUNIT_GTD_CONFIG (IPC_PUNIT_GTD_CMD_BASE | 0x01)
+#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL (IPC_PUNIT_GTD_CMD_BASE | 0x02)
+#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL (IPC_PUNIT_GTD_CMD_BASE | 0x03)
+#define IPC_PUNIT_GTD_GET_WM_VAL (IPC_PUNIT_GTD_CMD_BASE | 0x06)
+#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ (IPC_PUNIT_GTD_CMD_BASE | 0x07)
+#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE (IPC_PUNIT_GTD_CMD_BASE | 0x16)
+#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST (IPC_PUNIT_GTD_CMD_BASE | 0x17)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL (IPC_PUNIT_GTD_CMD_BASE | 0x1a)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING (IPC_PUNIT_GTD_CMD_BASE | 0x1c)
+
+/* ISP Driver => Pcode commands */
+#define IPC_PUNIT_ISPD_ZERO (IPC_PUNIT_ISPD_CMD_BASE | 0x00)
+#define IPC_PUNIT_ISPD_CONFIG (IPC_PUNIT_ISPD_CMD_BASE | 0x01)
+#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL (IPC_PUNIT_ISPD_CMD_BASE | 0x02)
+#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS (IPC_PUNIT_ISPD_CMD_BASE | 0x03)
+#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL (IPC_PUNIT_ISPD_CMD_BASE | 0x04)
+#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL (IPC_PUNIT_ISPD_CMD_BASE | 0x05)
+
+/* Error codes */
+#define IPC_PUNIT_ERR_SUCCESS 0
+#define IPC_PUNIT_ERR_INVALID_CMD 1
+#define IPC_PUNIT_ERR_INVALID_PARAMETER 2
+#define IPC_PUNIT_ERR_CMD_TIMEOUT 3
+#define IPC_PUNIT_ERR_CMD_LOCKED 4
+#define IPC_PUNIT_ERR_INVALID_VR_ID 5
+#define IPC_PUNIT_ERR_VR_ERR 6
+
+#if IS_ENABLED(CONFIG_INTEL_PUNIT_IPC)
+
+int intel_punit_ipc_simple_command(int cmd, int para1, int para2);
+int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out);
+
+#else
+
+static inline int intel_punit_ipc_simple_command(int cmd,
+ int para1, int para2)
+{
+ return -ENODEV;
+}
+
+static inline int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2,
+ u32 *in, u32 *out)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_INTEL_PUNIT_IPC */
+
+#endif
diff --git a/arch/x86/include/asm/intel_telemetry.h b/arch/x86/include/asm/intel_telemetry.h
new file mode 100644
index 000000000000..ed65fe701de5
--- /dev/null
+++ b/arch/x86/include/asm/intel_telemetry.h
@@ -0,0 +1,147 @@
+/*
+ * Intel SOC Telemetry Driver Header File
+ * Copyright (C) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#ifndef INTEL_TELEMETRY_H
+#define INTEL_TELEMETRY_H
+
+#define TELEM_MAX_EVENTS_SRAM 28
+#define TELEM_MAX_OS_ALLOCATED_EVENTS 20
+
+enum telemetry_unit {
+ TELEM_PSS = 0,
+ TELEM_IOSS,
+ TELEM_UNIT_NONE
+};
+
+struct telemetry_evtlog {
+ u32 telem_evtid;
+ u64 telem_evtlog;
+};
+
+struct telemetry_evtconfig {
+ /* Array of Event-IDs to Enable */
+ u32 *evtmap;
+
+ /* Number of Events (<29) in evtmap */
+ u8 num_evts;
+
+ /* Sampling period */
+ u8 period;
+};
+
+struct telemetry_evtmap {
+ const char *name;
+ u32 evt_id;
+};
+
+struct telemetry_unit_config {
+ struct telemetry_evtmap *telem_evts;
+ void __iomem *regmap;
+ u32 ssram_base_addr;
+ u8 ssram_evts_used;
+ u8 curr_period;
+ u8 max_period;
+ u8 min_period;
+ u32 ssram_size;
+
+};
+
+struct telemetry_plt_config {
+ struct telemetry_unit_config pss_config;
+ struct telemetry_unit_config ioss_config;
+ struct mutex telem_trace_lock;
+ struct mutex telem_lock;
+ bool telem_in_use;
+};
+
+struct telemetry_core_ops {
+ int (*get_sampling_period)(u8 *pss_min_period, u8 *pss_max_period,
+ u8 *ioss_min_period, u8 *ioss_max_period);
+
+ int (*get_eventconfig)(struct telemetry_evtconfig *pss_evtconfig,
+ struct telemetry_evtconfig *ioss_evtconfig,
+ int pss_len, int ioss_len);
+
+ int (*update_events)(struct telemetry_evtconfig pss_evtconfig,
+ struct telemetry_evtconfig ioss_evtconfig);
+
+ int (*set_sampling_period)(u8 pss_period, u8 ioss_period);
+
+ int (*get_trace_verbosity)(enum telemetry_unit telem_unit,
+ u32 *verbosity);
+
+ int (*set_trace_verbosity)(enum telemetry_unit telem_unit,
+ u32 verbosity);
+
+ int (*raw_read_eventlog)(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog,
+ int len, int log_all_evts);
+
+ int (*read_eventlog)(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog,
+ int len, int log_all_evts);
+
+ int (*add_events)(u8 num_pss_evts, u8 num_ioss_evts,
+ u32 *pss_evtmap, u32 *ioss_evtmap);
+
+ int (*reset_events)(void);
+};
+
+int telemetry_set_pltdata(struct telemetry_core_ops *ops,
+ struct telemetry_plt_config *pltconfig);
+
+int telemetry_clear_pltdata(void);
+
+int telemetry_pltconfig_valid(void);
+
+int telemetry_get_evtname(enum telemetry_unit telem_unit,
+ const char **name, int len);
+
+int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig,
+ struct telemetry_evtconfig ioss_evtconfig);
+
+int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+ u32 *pss_evtmap, u32 *ioss_evtmap);
+
+int telemetry_reset_events(void);
+
+int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_config,
+ struct telemetry_evtconfig *ioss_config,
+ int pss_len, int ioss_len);
+
+int telemetry_read_events(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_raw_read_events(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len);
+
+int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period,
+ u8 *ioss_min_period, u8 *ioss_max_period);
+
+int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period);
+
+int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 verbosity);
+
+int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 *verbosity);
+
+#endif /* INTEL_TELEMETRY_H */
diff --git a/arch/x86/include/asm/lguest.h b/arch/x86/include/asm/lguest.h
index 3bbc07a57a31..73d0c9b92087 100644
--- a/arch/x86/include/asm/lguest.h
+++ b/arch/x86/include/asm/lguest.h
@@ -12,7 +12,9 @@
#define GUEST_PL 1
/* Page for Switcher text itself, then two pages per cpu */
-#define TOTAL_SWITCHER_PAGES (1 + 2 * nr_cpu_ids)
+#define SWITCHER_TEXT_PAGES (1)
+#define SWITCHER_STACK_PAGES (2 * nr_cpu_ids)
+#define TOTAL_SWITCHER_PAGES (SWITCHER_TEXT_PAGES + SWITCHER_STACK_PAGES)
/* Where we map the Switcher, in both Host and Guest. */
extern unsigned long switcher_addr;
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 379cd3658799..bfd9b2a35a0b 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -116,8 +116,36 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
#endif
cpumask_set_cpu(cpu, mm_cpumask(next));
- /* Re-load page tables */
+ /*
+ * Re-load page tables.
+ *
+ * This logic has an ordering constraint:
+ *
+ * CPU 0: Write to a PTE for 'next'
+ * CPU 0: load bit 1 in mm_cpumask. if nonzero, send IPI.
+ * CPU 1: set bit 1 in next's mm_cpumask
+ * CPU 1: load from the PTE that CPU 0 writes (implicit)
+ *
+ * We need to prevent an outcome in which CPU 1 observes
+ * the new PTE value and CPU 0 observes bit 1 clear in
+ * mm_cpumask. (If that occurs, then the IPI will never
+ * be sent, and CPU 0's TLB will contain a stale entry.)
+ *
+ * The bad outcome can occur if either CPU's load is
+ * reordered before that CPU's store, so both CPUs must
+ * execute full barriers to prevent this from happening.
+ *
+ * Thus, switch_mm needs a full barrier between the
+ * store to mm_cpumask and any operation that could load
+ * from next->pgd. TLB fills are special and can happen
+ * due to instruction fetches or for no reason at all,
+ * and neither LOCK nor MFENCE orders them.
+ * Fortunately, load_cr3() is serializing and gives the
+ * ordering guarantee we need.
+ *
+ */
load_cr3(next->pgd);
+
trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
/* Stop flush ipis for the previous mm */
@@ -156,10 +184,14 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* schedule, protecting us from simultaneous changes.
*/
cpumask_set_cpu(cpu, mm_cpumask(next));
+
/*
* We were in lazy tlb mode and leave_mm disabled
* tlb flush IPI delivery. We must reload CR3
* to make sure to use no freed page tables.
+ *
+ * As above, load_cr3() is serializing and orders TLB
+ * fills with respect to the mm_cpumask write.
*/
load_cr3(next->pgd);
trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index d3eee663c41f..0687c4748b8f 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -162,20 +162,22 @@ static inline int pmd_large(pmd_t pte)
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- return pmd_val(pmd) & _PAGE_SPLITTING;
-}
-
static inline int pmd_trans_huge(pmd_t pmd)
{
- return pmd_val(pmd) & _PAGE_PSE;
+ return (pmd_val(pmd) & (_PAGE_PSE|_PAGE_DEVMAP)) == _PAGE_PSE;
}
static inline int has_transparent_hugepage(void)
{
return cpu_has_pse;
}
+
+#ifdef __HAVE_ARCH_PTE_DEVMAP
+static inline int pmd_devmap(pmd_t pmd)
+{
+ return !!(pmd_val(pmd) & _PAGE_DEVMAP);
+}
+#endif
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
static inline pte_t pte_set_flags(pte_t pte, pteval_t set)
@@ -252,6 +254,11 @@ static inline pte_t pte_mkspecial(pte_t pte)
return pte_set_flags(pte, _PAGE_SPECIAL);
}
+static inline pte_t pte_mkdevmap(pte_t pte)
+{
+ return pte_set_flags(pte, _PAGE_SPECIAL|_PAGE_DEVMAP);
+}
+
static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
{
pmdval_t v = native_pmd_val(pmd);
@@ -271,6 +278,11 @@ static inline pmd_t pmd_mkold(pmd_t pmd)
return pmd_clear_flags(pmd, _PAGE_ACCESSED);
}
+static inline pmd_t pmd_mkclean(pmd_t pmd)
+{
+ return pmd_clear_flags(pmd, _PAGE_DIRTY);
+}
+
static inline pmd_t pmd_wrprotect(pmd_t pmd)
{
return pmd_clear_flags(pmd, _PAGE_RW);
@@ -281,6 +293,11 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)
return pmd_set_flags(pmd, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
}
+static inline pmd_t pmd_mkdevmap(pmd_t pmd)
+{
+ return pmd_set_flags(pmd, _PAGE_DEVMAP);
+}
+
static inline pmd_t pmd_mkhuge(pmd_t pmd)
{
return pmd_set_flags(pmd, _PAGE_PSE);
@@ -462,6 +479,13 @@ static inline int pte_present(pte_t a)
return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
}
+#ifdef __HAVE_ARCH_PTE_DEVMAP
+static inline int pte_devmap(pte_t a)
+{
+ return (pte_flags(a) & _PAGE_DEVMAP) == _PAGE_DEVMAP;
+}
+#endif
+
#define pte_accessible pte_accessible
static inline bool pte_accessible(struct mm_struct *mm, pte_t a)
{
@@ -808,10 +832,6 @@ extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp);
-#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-extern void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long addr, pmd_t *pmdp);
-
#define __HAVE_ARCH_PMD_WRITE
static inline int pmd_write(pmd_t pmd)
{
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index a471cadb9630..04c27a013165 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -22,10 +22,11 @@
#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
#define _PAGE_BIT_SPECIAL _PAGE_BIT_SOFTW1
#define _PAGE_BIT_CPA_TEST _PAGE_BIT_SOFTW1
-#define _PAGE_BIT_SPLITTING _PAGE_BIT_SOFTW2 /* only valid on a PSE pmd */
#define _PAGE_BIT_HIDDEN _PAGE_BIT_SOFTW3 /* hidden by kmemcheck */
#define _PAGE_BIT_SOFT_DIRTY _PAGE_BIT_SOFTW3 /* software dirty tracking */
-#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
+#define _PAGE_BIT_SOFTW4 58 /* available for programmer */
+#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4
+#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
/* If _PAGE_BIT_PRESENT is clear, we use these: */
/* - if the user mapped it with PROT_NONE; pte_present gives true */
@@ -46,7 +47,6 @@
#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
#define _PAGE_SPECIAL (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
#define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
-#define _PAGE_SPLITTING (_AT(pteval_t, 1) << _PAGE_BIT_SPLITTING)
#define __HAVE_ARCH_PTE_SPECIAL
#ifdef CONFIG_KMEMCHECK
@@ -85,8 +85,11 @@
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX)
+#define _PAGE_DEVMAP (_AT(u64, 1) << _PAGE_BIT_DEVMAP)
+#define __HAVE_ARCH_PTE_DEVMAP
#else
#define _PAGE_NX (_AT(pteval_t, 0))
+#define _PAGE_DEVMAP (_AT(pteval_t, 0))
#endif
#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h
index 7249e6d0902d..5973a2f3db3d 100644
--- a/arch/x86/include/asm/platform_sst_audio.h
+++ b/arch/x86/include/asm/platform_sst_audio.h
@@ -55,6 +55,7 @@ enum sst_audio_device_id_mrfld {
PIPE_MEDIA0_IN = 0x8F,
PIPE_MEDIA1_IN = 0x90,
PIPE_MEDIA2_IN = 0x91,
+ PIPE_MEDIA3_IN = 0x9C,
PIPE_RSVD = 0xFF,
};
diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h
index d8ce3ec816ab..1544fabcd7f9 100644
--- a/arch/x86/include/asm/pmem.h
+++ b/arch/x86/include/asm/pmem.h
@@ -132,12 +132,7 @@ static inline void arch_clear_pmem(void __pmem *addr, size_t size)
{
void *vaddr = (void __force *)addr;
- /* TODO: implement the zeroing via non-temporal writes */
- if (size == PAGE_SIZE && ((unsigned long)vaddr & ~PAGE_MASK) == 0)
- clear_page(vaddr);
- else
- memset(vaddr, 0, size);
-
+ memset(vaddr, 0, size);
__arch_wb_cache_pmem(vaddr, size);
}
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index e678ddeed030..a07956a08936 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -434,8 +434,7 @@ static void srat_detect_node(struct cpuinfo_x86 *c)
*/
int ht_nodeid = c->initial_apicid;
- if (ht_nodeid >= 0 &&
- __apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
+ if (__apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
node = __apicid_to_node[ht_nodeid];
/* Pick a nearby node */
if (!node_online(node))
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index db9a675e751b..bca14c899137 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -547,6 +547,7 @@ static const struct pci_device_id intel_stolen_ids[] __initconst = {
INTEL_CHV_IDS(&chv_stolen_funcs),
INTEL_SKL_IDS(&gen9_stolen_funcs),
INTEL_BXT_IDS(&gen9_stolen_funcs),
+ INTEL_KBL_IDS(&gen9_stolen_funcs),
};
static void __init intel_graphics_stolen(int num, int slot, int func)
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index 7b2978ab30df..6d9f0a7ef4c8 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -3,8 +3,11 @@
*/
#include <asm/fpu/internal.h>
#include <asm/tlbflush.h>
+#include <asm/setup.h>
+#include <asm/cmdline.h>
#include <linux/sched.h>
+#include <linux/init.h>
/*
* Initialize the TS bit in CR0 according to the style of context-switches
@@ -270,20 +273,52 @@ static void __init fpu__init_system_xstate_size_legacy(void)
*/
static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
-static int __init eager_fpu_setup(char *s)
+/*
+ * Find supported xfeatures based on cpu features and command-line input.
+ * This must be called after fpu__init_parse_early_param() is called and
+ * xfeatures_mask is enumerated.
+ */
+u64 __init fpu__get_supported_xfeatures_mask(void)
{
- if (!strcmp(s, "on"))
- eagerfpu = ENABLE;
- else if (!strcmp(s, "off"))
- eagerfpu = DISABLE;
- else if (!strcmp(s, "auto"))
- eagerfpu = AUTO;
- return 1;
+ /* Support all xfeatures known to us */
+ if (eagerfpu != DISABLE)
+ return XCNTXT_MASK;
+
+ /* Warning of xfeatures being disabled for no eagerfpu mode */
+ if (xfeatures_mask & XFEATURE_MASK_EAGER) {
+ pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n",
+ xfeatures_mask & XFEATURE_MASK_EAGER);
+ }
+
+ /* Return a mask that masks out all features requiring eagerfpu mode */
+ return ~XFEATURE_MASK_EAGER;
+}
+
+/*
+ * Disable features dependent on eagerfpu.
+ */
+static void __init fpu__clear_eager_fpu_features(void)
+{
+ setup_clear_cpu_cap(X86_FEATURE_MPX);
+ setup_clear_cpu_cap(X86_FEATURE_AVX);
+ setup_clear_cpu_cap(X86_FEATURE_AVX2);
+ setup_clear_cpu_cap(X86_FEATURE_AVX512F);
+ setup_clear_cpu_cap(X86_FEATURE_AVX512PF);
+ setup_clear_cpu_cap(X86_FEATURE_AVX512ER);
+ setup_clear_cpu_cap(X86_FEATURE_AVX512CD);
}
-__setup("eagerfpu=", eager_fpu_setup);
/*
* Pick the FPU context switching strategy:
+ *
+ * When eagerfpu is AUTO or ENABLE, we ensure it is ENABLE if either of
+ * the following is true:
+ *
+ * (1) the cpu has xsaveopt, as it has the optimization and doing eager
+ * FPU switching has a relatively low cost compared to a plain xsave;
+ * (2) the cpu has xsave features (e.g. MPX) that depend on eager FPU
+ * switching. Should the kernel boot with noxsaveopt, we support MPX
+ * with eager FPU switching at a higher cost.
*/
static void __init fpu__init_system_ctx_switch(void)
{
@@ -295,19 +330,11 @@ static void __init fpu__init_system_ctx_switch(void)
WARN_ON_FPU(current->thread.fpu.fpstate_active);
current_thread_info()->status = 0;
- /* Auto enable eagerfpu for xsaveopt */
if (boot_cpu_has(X86_FEATURE_XSAVEOPT) && eagerfpu != DISABLE)
eagerfpu = ENABLE;
- if (xfeatures_mask & XFEATURE_MASK_EAGER) {
- if (eagerfpu == DISABLE) {
- pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n",
- xfeatures_mask & XFEATURE_MASK_EAGER);
- xfeatures_mask &= ~XFEATURE_MASK_EAGER;
- } else {
- eagerfpu = ENABLE;
- }
- }
+ if (xfeatures_mask & XFEATURE_MASK_EAGER)
+ eagerfpu = ENABLE;
if (eagerfpu == ENABLE)
setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
@@ -316,11 +343,48 @@ static void __init fpu__init_system_ctx_switch(void)
}
/*
+ * We parse fpu parameters early because fpu__init_system() is executed
+ * before parse_early_param().
+ */
+static void __init fpu__init_parse_early_param(void)
+{
+ /*
+ * No need to check "eagerfpu=auto" again, since it is the
+ * initial default.
+ */
+ if (cmdline_find_option_bool(boot_command_line, "eagerfpu=off")) {
+ eagerfpu = DISABLE;
+ fpu__clear_eager_fpu_features();
+ } else if (cmdline_find_option_bool(boot_command_line, "eagerfpu=on")) {
+ eagerfpu = ENABLE;
+ }
+
+ if (cmdline_find_option_bool(boot_command_line, "no387"))
+ setup_clear_cpu_cap(X86_FEATURE_FPU);
+
+ if (cmdline_find_option_bool(boot_command_line, "nofxsr")) {
+ setup_clear_cpu_cap(X86_FEATURE_FXSR);
+ setup_clear_cpu_cap(X86_FEATURE_FXSR_OPT);
+ setup_clear_cpu_cap(X86_FEATURE_XMM);
+ }
+
+ if (cmdline_find_option_bool(boot_command_line, "noxsave"))
+ fpu__xstate_clear_all_cpu_caps();
+
+ if (cmdline_find_option_bool(boot_command_line, "noxsaveopt"))
+ setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+
+ if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
+ setup_clear_cpu_cap(X86_FEATURE_XSAVES);
+}
+
+/*
* Called on the boot CPU once per system bootup, to set up the initial
* FPU state that is later cloned into all processes:
*/
void __init fpu__init_system(struct cpuinfo_x86 *c)
{
+ fpu__init_parse_early_param();
fpu__init_system_early_generic(c);
/*
@@ -344,62 +408,3 @@ void __init fpu__init_system(struct cpuinfo_x86 *c)
fpu__init_system_ctx_switch();
}
-
-/*
- * Boot parameter to turn off FPU support and fall back to math-emu:
- */
-static int __init no_387(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_FPU);
- return 1;
-}
-__setup("no387", no_387);
-
-/*
- * Disable all xstate CPU features:
- */
-static int __init x86_noxsave_setup(char *s)
-{
- if (strlen(s))
- return 0;
-
- fpu__xstate_clear_all_cpu_caps();
-
- return 1;
-}
-__setup("noxsave", x86_noxsave_setup);
-
-/*
- * Disable the XSAVEOPT instruction specifically:
- */
-static int __init x86_noxsaveopt_setup(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
-
- return 1;
-}
-__setup("noxsaveopt", x86_noxsaveopt_setup);
-
-/*
- * Disable the XSAVES instruction:
- */
-static int __init x86_noxsaves_setup(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_XSAVES);
-
- return 1;
-}
-__setup("noxsaves", x86_noxsaves_setup);
-
-/*
- * Disable FX save/restore and SSE support:
- */
-static int __init x86_nofxsr_setup(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_FXSR);
- setup_clear_cpu_cap(X86_FEATURE_FXSR_OPT);
- setup_clear_cpu_cap(X86_FEATURE_XMM);
-
- return 1;
-}
-__setup("nofxsr", x86_nofxsr_setup);
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 40f100285984..d425cda5ae6d 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -52,6 +52,7 @@ void fpu__xstate_clear_all_cpu_caps(void)
setup_clear_cpu_cap(X86_FEATURE_AVX512ER);
setup_clear_cpu_cap(X86_FEATURE_AVX512CD);
setup_clear_cpu_cap(X86_FEATURE_MPX);
+ setup_clear_cpu_cap(X86_FEATURE_XGETBV1);
}
/*
@@ -632,8 +633,7 @@ void __init fpu__init_system_xstate(void)
BUG();
}
- /* Support only the state known to the OS: */
- xfeatures_mask = xfeatures_mask & XCNTXT_MASK;
+ xfeatures_mask &= fpu__get_supported_xfeatures_mask();
/* Enable xstate instructions to be able to continue with initialization: */
fpu__init_cpu_xstate();
diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c
index d1d35ccffed3..92fc1a51f994 100644
--- a/arch/x86/kernel/livepatch.c
+++ b/arch/x86/kernel/livepatch.c
@@ -20,8 +20,6 @@
#include <linux/module.h>
#include <linux/uaccess.h>
-#include <asm/cacheflush.h>
-#include <asm/page_types.h>
#include <asm/elf.h>
#include <asm/livepatch.h>
@@ -38,11 +36,10 @@
int klp_write_module_reloc(struct module *mod, unsigned long type,
unsigned long loc, unsigned long value)
{
- int ret, numpages, size = 4;
- bool readonly;
+ size_t size = 4;
unsigned long val;
- unsigned long core = (unsigned long)mod->module_core;
- unsigned long core_size = mod->core_size;
+ unsigned long core = (unsigned long)mod->core_layout.base;
+ unsigned long core_size = mod->core_layout.size;
switch (type) {
case R_X86_64_NONE:
@@ -69,23 +66,5 @@ int klp_write_module_reloc(struct module *mod, unsigned long type,
/* loc does not point to any symbol inside the module */
return -EINVAL;
- readonly = false;
-
-#ifdef CONFIG_DEBUG_SET_MODULE_RONX
- if (loc < core + mod->core_ro_size)
- readonly = true;
-#endif
-
- /* determine if the relocation spans a page boundary */
- numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2;
-
- if (readonly)
- set_memory_rw(loc & PAGE_MASK, numpages);
-
- ret = probe_kernel_write((void *)loc, &val, size);
-
- if (readonly)
- set_memory_ro(loc & PAGE_MASK, numpages);
-
- return ret;
+ return probe_kernel_write((void *)loc, &val, size);
}
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d64889aa2d46..ab0adc0fa5db 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -182,6 +182,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
},
},
+ { /* Handle problems with rebooting on the iMac10,1. */
+ .callback = set_pci_reboot,
+ .ident = "Apple iMac10,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac10,1"),
+ },
+ },
/* ASRock */
{ /* Handle problems with rebooting on ASRock Q1900DC-ITX */
diff --git a/arch/x86/kernel/verify_cpu.S b/arch/x86/kernel/verify_cpu.S
index 4cf401f581e7..07efb35ee4bc 100644
--- a/arch/x86/kernel/verify_cpu.S
+++ b/arch/x86/kernel/verify_cpu.S
@@ -48,31 +48,31 @@ verify_cpu:
pushfl
popl %eax
cmpl %eax,%ebx
- jz verify_cpu_no_longmode # cpu has no cpuid
+ jz .Lverify_cpu_no_longmode # cpu has no cpuid
#endif
movl $0x0,%eax # See if cpuid 1 is implemented
cpuid
cmpl $0x1,%eax
- jb verify_cpu_no_longmode # no cpuid 1
+ jb .Lverify_cpu_no_longmode # no cpuid 1
xor %di,%di
cmpl $0x68747541,%ebx # AuthenticAMD
- jnz verify_cpu_noamd
+ jnz .Lverify_cpu_noamd
cmpl $0x69746e65,%edx
- jnz verify_cpu_noamd
+ jnz .Lverify_cpu_noamd
cmpl $0x444d4163,%ecx
- jnz verify_cpu_noamd
+ jnz .Lverify_cpu_noamd
mov $1,%di # cpu is from AMD
- jmp verify_cpu_check
+ jmp .Lverify_cpu_check
-verify_cpu_noamd:
+.Lverify_cpu_noamd:
cmpl $0x756e6547,%ebx # GenuineIntel?
- jnz verify_cpu_check
+ jnz .Lverify_cpu_check
cmpl $0x49656e69,%edx
- jnz verify_cpu_check
+ jnz .Lverify_cpu_check
cmpl $0x6c65746e,%ecx
- jnz verify_cpu_check
+ jnz .Lverify_cpu_check
# only call IA32_MISC_ENABLE when:
# family > 6 || (family == 6 && model >= 0xd)
@@ -83,59 +83,59 @@ verify_cpu_noamd:
andl $0x0ff00f00, %eax # mask family and extended family
shrl $8, %eax
cmpl $6, %eax
- ja verify_cpu_clear_xd # family > 6, ok
- jb verify_cpu_check # family < 6, skip
+ ja .Lverify_cpu_clear_xd # family > 6, ok
+ jb .Lverify_cpu_check # family < 6, skip
andl $0x000f00f0, %ecx # mask model and extended model
shrl $4, %ecx
cmpl $0xd, %ecx
- jb verify_cpu_check # family == 6, model < 0xd, skip
+ jb .Lverify_cpu_check # family == 6, model < 0xd, skip
-verify_cpu_clear_xd:
+.Lverify_cpu_clear_xd:
movl $MSR_IA32_MISC_ENABLE, %ecx
rdmsr
btrl $2, %edx # clear MSR_IA32_MISC_ENABLE_XD_DISABLE
- jnc verify_cpu_check # only write MSR if bit was changed
+ jnc .Lverify_cpu_check # only write MSR if bit was changed
wrmsr
-verify_cpu_check:
+.Lverify_cpu_check:
movl $0x1,%eax # Does the cpu have what it takes
cpuid
andl $REQUIRED_MASK0,%edx
xorl $REQUIRED_MASK0,%edx
- jnz verify_cpu_no_longmode
+ jnz .Lverify_cpu_no_longmode
movl $0x80000000,%eax # See if extended cpuid is implemented
cpuid
cmpl $0x80000001,%eax
- jb verify_cpu_no_longmode # no extended cpuid
+ jb .Lverify_cpu_no_longmode # no extended cpuid
movl $0x80000001,%eax # Does the cpu have what it takes
cpuid
andl $REQUIRED_MASK1,%edx
xorl $REQUIRED_MASK1,%edx
- jnz verify_cpu_no_longmode
+ jnz .Lverify_cpu_no_longmode
-verify_cpu_sse_test:
+.Lverify_cpu_sse_test:
movl $1,%eax
cpuid
andl $SSE_MASK,%edx
cmpl $SSE_MASK,%edx
- je verify_cpu_sse_ok
+ je .Lverify_cpu_sse_ok
test %di,%di
- jz verify_cpu_no_longmode # only try to force SSE on AMD
+ jz .Lverify_cpu_no_longmode # only try to force SSE on AMD
movl $MSR_K7_HWCR,%ecx
rdmsr
btr $15,%eax # enable SSE
wrmsr
xor %di,%di # don't loop
- jmp verify_cpu_sse_test # try again
+ jmp .Lverify_cpu_sse_test # try again
-verify_cpu_no_longmode:
+.Lverify_cpu_no_longmode:
popf # Restore caller passed flags
movl $1,%eax
ret
-verify_cpu_sse_ok:
+.Lverify_cpu_sse_ok:
popf # Restore caller passed flags
xorl %eax, %eax
ret
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 483231ebbb0b..e574b8546518 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -175,7 +175,11 @@ static void mark_screen_rdonly(struct mm_struct *mm)
if (pud_none_or_clear_bad(pud))
goto out;
pmd = pmd_offset(pud, 0xA0000);
- split_huge_page_pmd_mm(mm, 0xA0000, pmd);
+
+ if (pmd_trans_huge(*pmd)) {
+ struct vm_area_struct *vma = find_vma(mm, 0xA0000);
+ split_huge_pmd(vma, pmd, 0xA0000);
+ }
if (pmd_none_or_clear_bad(pmd))
goto out;
pte = pte_offset_map_lock(mm, pmd, 0xA0000, &ptl);
diff --git a/arch/x86/kvm/iommu.c b/arch/x86/kvm/iommu.c
index 5c520ebf6343..a22a488b4622 100644
--- a/arch/x86/kvm/iommu.c
+++ b/arch/x86/kvm/iommu.c
@@ -43,11 +43,11 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm);
static void kvm_iommu_put_pages(struct kvm *kvm,
gfn_t base_gfn, unsigned long npages);
-static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
+static kvm_pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
unsigned long npages)
{
gfn_t end_gfn;
- pfn_t pfn;
+ kvm_pfn_t pfn;
pfn = gfn_to_pfn_memslot(slot, gfn);
end_gfn = gfn + npages;
@@ -62,7 +62,8 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
return pfn;
}
-static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
+static void kvm_unpin_pages(struct kvm *kvm, kvm_pfn_t pfn,
+ unsigned long npages)
{
unsigned long i;
@@ -73,7 +74,7 @@ static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
{
gfn_t gfn, end_gfn;
- pfn_t pfn;
+ kvm_pfn_t pfn;
int r = 0;
struct iommu_domain *domain = kvm->arch.iommu_domain;
int flags;
@@ -275,7 +276,7 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
{
struct iommu_domain *domain;
gfn_t end_gfn, gfn;
- pfn_t pfn;
+ kvm_pfn_t pfn;
u64 phys;
domain = kvm->arch.iommu_domain;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 420a5ca3c0ee..95a955de5964 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -259,7 +259,7 @@ static unsigned get_mmio_spte_access(u64 spte)
}
static bool set_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
- pfn_t pfn, unsigned access)
+ kvm_pfn_t pfn, unsigned access)
{
if (unlikely(is_noslot_pfn(pfn))) {
mark_mmio_spte(vcpu, sptep, gfn, access);
@@ -320,7 +320,7 @@ static int is_last_spte(u64 pte, int level)
return 0;
}
-static pfn_t spte_to_pfn(u64 pte)
+static kvm_pfn_t spte_to_pfn(u64 pte)
{
return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
}
@@ -582,7 +582,7 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte)
*/
static int mmu_spte_clear_track_bits(u64 *sptep)
{
- pfn_t pfn;
+ kvm_pfn_t pfn;
u64 old_spte = *sptep;
if (!spte_has_volatile_bits(old_spte))
@@ -1372,7 +1372,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
int need_flush = 0;
u64 new_spte;
pte_t *ptep = (pte_t *)data;
- pfn_t new_pfn;
+ kvm_pfn_t new_pfn;
WARN_ON(pte_huge(*ptep));
new_pfn = pte_pfn(*ptep);
@@ -2450,7 +2450,7 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
return 0;
}
-static bool kvm_is_mmio_pfn(pfn_t pfn)
+static bool kvm_is_mmio_pfn(kvm_pfn_t pfn)
{
if (pfn_valid(pfn))
return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn));
@@ -2460,7 +2460,7 @@ static bool kvm_is_mmio_pfn(pfn_t pfn)
static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
unsigned pte_access, int level,
- gfn_t gfn, pfn_t pfn, bool speculative,
+ gfn_t gfn, kvm_pfn_t pfn, bool speculative,
bool can_unsync, bool host_writable)
{
u64 spte;
@@ -2539,7 +2539,7 @@ done:
}
static bool mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
- int write_fault, int level, gfn_t gfn, pfn_t pfn,
+ int write_fault, int level, gfn_t gfn, kvm_pfn_t pfn,
bool speculative, bool host_writable)
{
int was_rmapped = 0;
@@ -2602,7 +2602,7 @@ static bool mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
return emulate;
}
-static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
+static kvm_pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
bool no_dirty_log)
{
struct kvm_memory_slot *slot;
@@ -2684,7 +2684,7 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
}
static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable,
- int level, gfn_t gfn, pfn_t pfn, bool prefault)
+ int level, gfn_t gfn, kvm_pfn_t pfn, bool prefault)
{
struct kvm_shadow_walk_iterator iterator;
struct kvm_mmu_page *sp;
@@ -2732,7 +2732,7 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *
send_sig_info(SIGBUS, &info, tsk);
}
-static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
+static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
{
/*
* Do not cache the mmio info caused by writing the readonly gfn
@@ -2752,9 +2752,10 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
}
static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
- gfn_t *gfnp, pfn_t *pfnp, int *levelp)
+ gfn_t *gfnp, kvm_pfn_t *pfnp,
+ int *levelp)
{
- pfn_t pfn = *pfnp;
+ kvm_pfn_t pfn = *pfnp;
gfn_t gfn = *gfnp;
int level = *levelp;
@@ -2793,7 +2794,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
}
static bool handle_abnormal_pfn(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
- pfn_t pfn, unsigned access, int *ret_val)
+ kvm_pfn_t pfn, unsigned access, int *ret_val)
{
bool ret = true;
@@ -2947,7 +2948,7 @@ exit:
}
static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
- gva_t gva, pfn_t *pfn, bool write, bool *writable);
+ gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable);
static void make_mmu_pages_available(struct kvm_vcpu *vcpu);
static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
@@ -2956,7 +2957,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
int r;
int level;
bool force_pt_level = false;
- pfn_t pfn;
+ kvm_pfn_t pfn;
unsigned long mmu_seq;
bool map_writable, write = error_code & PFERR_WRITE_MASK;
@@ -3410,7 +3411,7 @@ static bool can_do_async_pf(struct kvm_vcpu *vcpu)
}
static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
- gva_t gva, pfn_t *pfn, bool write, bool *writable)
+ gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable)
{
struct kvm_memory_slot *slot;
bool async;
@@ -3448,7 +3449,7 @@ check_hugepage_cache_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, int level)
static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
bool prefault)
{
- pfn_t pfn;
+ kvm_pfn_t pfn;
int r;
int level;
bool force_pt_level;
@@ -4601,7 +4602,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
u64 *sptep;
struct rmap_iterator iter;
int need_tlb_flush = 0;
- pfn_t pfn;
+ kvm_pfn_t pfn;
struct kvm_mmu_page *sp;
restart:
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index 1cee3ec20dd2..dcce533d420c 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -97,7 +97,7 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
{
struct kvm_mmu_page *sp;
gfn_t gfn;
- pfn_t pfn;
+ kvm_pfn_t pfn;
hpa_t hpa;
sp = page_header(__pa(sptep));
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 91e939b486d1..6c9fed957cce 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -456,7 +456,7 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
{
unsigned pte_access;
gfn_t gfn;
- pfn_t pfn;
+ kvm_pfn_t pfn;
if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte))
return false;
@@ -551,7 +551,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
struct guest_walker *gw,
int write_fault, int hlevel,
- pfn_t pfn, bool map_writable, bool prefault)
+ kvm_pfn_t pfn, bool map_writable, bool prefault)
{
struct kvm_mmu_page *sp = NULL;
struct kvm_shadow_walk_iterator it;
@@ -694,7 +694,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
int user_fault = error_code & PFERR_USER_MASK;
struct guest_walker walker;
int r;
- pfn_t pfn;
+ kvm_pfn_t pfn;
int level = PT_PAGE_TABLE_LEVEL;
bool force_pt_level = false;
unsigned long mmu_seq;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 04d61d496b14..e2951b6edbbc 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4251,7 +4251,7 @@ out:
static int init_rmode_identity_map(struct kvm *kvm)
{
int i, idx, r = 0;
- pfn_t identity_map_pfn;
+ kvm_pfn_t identity_map_pfn;
u32 tmp;
if (!enable_ept)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f53f5b13c677..4244c2baf57d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5148,7 +5148,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2,
int emulation_type)
{
gpa_t gpa = cr2;
- pfn_t pfn;
+ kvm_pfn_t pfn;
if (emulation_type & EMULTYPE_NO_REEXECUTE)
return false;
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index ae9a37bf1371..6d5eb5900372 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -9,6 +9,7 @@
#include <linux/vmstat.h>
#include <linux/highmem.h>
#include <linux/swap.h>
+#include <linux/memremap.h>
#include <asm/pgtable.h>
@@ -63,6 +64,16 @@ retry:
#endif
}
+static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages)
+{
+ while ((*nr) - nr_start) {
+ struct page *page = pages[--(*nr)];
+
+ ClearPageReferenced(page);
+ put_page(page);
+ }
+}
+
/*
* The performance critical leaf functions are made noinline otherwise gcc
* inlines everything into a single function which results in too much
@@ -71,7 +82,9 @@ retry:
static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
+ struct dev_pagemap *pgmap = NULL;
unsigned long mask;
+ int nr_start = *nr;
pte_t *ptep;
mask = _PAGE_PRESENT|_PAGE_USER;
@@ -89,13 +102,21 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
return 0;
}
- if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
+ page = pte_page(pte);
+ if (pte_devmap(pte)) {
+ pgmap = get_dev_pagemap(pte_pfn(pte), pgmap);
+ if (unlikely(!pgmap)) {
+ undo_dev_pagemap(nr, nr_start, pages);
+ pte_unmap(ptep);
+ return 0;
+ }
+ } else if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
pte_unmap(ptep);
return 0;
}
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
- page = pte_page(pte);
get_page(page);
+ put_dev_pagemap(pgmap);
SetPageReferenced(page);
pages[*nr] = page;
(*nr)++;
@@ -114,6 +135,32 @@ static inline void get_head_page_multiple(struct page *page, int nr)
SetPageReferenced(page);
}
+static int __gup_device_huge_pmd(pmd_t pmd, unsigned long addr,
+ unsigned long end, struct page **pages, int *nr)
+{
+ int nr_start = *nr;
+ unsigned long pfn = pmd_pfn(pmd);
+ struct dev_pagemap *pgmap = NULL;
+
+ pfn += (addr & ~PMD_MASK) >> PAGE_SHIFT;
+ do {
+ struct page *page = pfn_to_page(pfn);
+
+ pgmap = get_dev_pagemap(pfn, pgmap);
+ if (unlikely(!pgmap)) {
+ undo_dev_pagemap(nr, nr_start, pages);
+ return 0;
+ }
+ SetPageReferenced(page);
+ pages[*nr] = page;
+ get_page(page);
+ put_dev_pagemap(pgmap);
+ (*nr)++;
+ pfn++;
+ } while (addr += PAGE_SIZE, addr != end);
+ return 1;
+}
+
static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
@@ -126,9 +173,13 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
mask |= _PAGE_RW;
if ((pmd_flags(pmd) & mask) != mask)
return 0;
+
+ VM_BUG_ON(!pfn_valid(pmd_pfn(pmd)));
+ if (pmd_devmap(pmd))
+ return __gup_device_huge_pmd(pmd, addr, end, pages, nr);
+
/* hugepages are never "special" */
VM_BUG_ON(pmd_flags(pmd) & _PAGE_SPECIAL);
- VM_BUG_ON(!pfn_valid(pmd_pfn(pmd)));
refs = 0;
head = pmd_page(pmd);
@@ -136,8 +187,6 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
do {
VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
- if (PageTail(page))
- get_huge_page_tail(page);
(*nr)++;
page++;
refs++;
@@ -158,18 +207,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmd_t pmd = *pmdp;
next = pmd_addr_end(addr, end);
- /*
- * The pmd_trans_splitting() check below explains why
- * pmdp_splitting_flush has to flush the tlb, to stop
- * this gup-fast code from running while we set the
- * splitting bit in the pmd. Returning zero will take
- * the slow path that will call wait_split_huge_page()
- * if the pmd is still in splitting state. gup-fast
- * can't because it has irq disabled and
- * wait_split_huge_page() would never return as the
- * tlb flush IPI wouldn't run.
- */
- if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+ if (pmd_none(pmd))
return 0;
if (unlikely(pmd_large(pmd) || !pmd_present(pmd))) {
/*
@@ -212,8 +250,6 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
do {
VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
- if (PageTail(page))
- get_huge_page_tail(page);
(*nr)++;
page++;
refs++;
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index ec081fe0ce2c..5488d21123bd 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/memory.h>
#include <linux/memory_hotplug.h>
+#include <linux/memremap.h>
#include <linux/nmi.h>
#include <linux/gfp.h>
#include <linux/kcore.h>
@@ -714,6 +715,12 @@ static void __meminit free_pagetable(struct page *page, int order)
{
unsigned long magic;
unsigned int nr_pages = 1 << order;
+ struct vmem_altmap *altmap = to_vmem_altmap((unsigned long) page);
+
+ if (altmap) {
+ vmem_altmap_free(altmap, nr_pages);
+ return;
+ }
/* bootmem page has reserved flag */
if (PageReserved(page)) {
@@ -814,8 +821,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
if (phys_addr < (phys_addr_t)0x40000000)
return;
- if (IS_ALIGNED(addr, PAGE_SIZE) &&
- IS_ALIGNED(next, PAGE_SIZE)) {
+ if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) {
/*
* Do not free direct mapping pages since they were
* freed when offlining, or simplely not in use.
@@ -1018,13 +1024,19 @@ int __ref arch_remove_memory(u64 start, u64 size)
{
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
+ struct page *page = pfn_to_page(start_pfn);
+ struct vmem_altmap *altmap;
struct zone *zone;
int ret;
- zone = page_zone(pfn_to_page(start_pfn));
- kernel_physical_mapping_remove(start, start + size);
+ /* With altmap the first mapped page is offset from @start */
+ altmap = to_vmem_altmap((unsigned long) page);
+ if (altmap)
+ page += vmem_altmap_offset(altmap);
+ zone = page_zone(page);
ret = __remove_pages(zone, start_pfn, nr_pages);
WARN_ON_ONCE(ret);
+ kernel_physical_mapping_remove(start, start + size);
return ret;
}
@@ -1236,7 +1248,7 @@ static void __meminitdata *p_start, *p_end;
static int __meminitdata node_start;
static int __meminit vmemmap_populate_hugepages(unsigned long start,
- unsigned long end, int node)
+ unsigned long end, int node, struct vmem_altmap *altmap)
{
unsigned long addr;
unsigned long next;
@@ -1259,7 +1271,7 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
if (pmd_none(*pmd)) {
void *p;
- p = vmemmap_alloc_block_buf(PMD_SIZE, node);
+ p = __vmemmap_alloc_block_buf(PMD_SIZE, node, altmap);
if (p) {
pte_t entry;
@@ -1280,7 +1292,8 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
addr_end = addr + PMD_SIZE;
p_end = p + PMD_SIZE;
continue;
- }
+ } else if (altmap)
+ return -ENOMEM; /* no fallback */
} else if (pmd_large(*pmd)) {
vmemmap_verify((pte_t *)pmd, node, addr, next);
continue;
@@ -1294,11 +1307,16 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{
+ struct vmem_altmap *altmap = to_vmem_altmap(start);
int err;
if (cpu_has_pse)
- err = vmemmap_populate_hugepages(start, end, node);
- else
+ err = vmemmap_populate_hugepages(start, end, node, altmap);
+ else if (altmap) {
+ pr_err_once("%s: no cpu support for altmap allocations\n",
+ __func__);
+ err = -ENOMEM;
+ } else
err = vmemmap_populate_basepages(start, end, node);
if (!err)
sync_global_pgds(start, end - 1, 0);
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 844b06d67df4..96bd1e2bffaf 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -69,14 +69,14 @@ unsigned long arch_mmap_rnd(void)
{
unsigned long rnd;
- /*
- * 8 bits of randomness in 32bit mmaps, 20 address space bits
- * 28 bits of randomness in 64bit mmaps, 40 address space bits
- */
if (mmap_is_ia32())
- rnd = (unsigned long)get_random_int() % (1<<8);
+#ifdef CONFIG_COMPAT
+ rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_compat_bits) - 1);
+#else
+ rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+#endif
else
- rnd = (unsigned long)get_random_int() % (1<<28);
+ rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
return rnd << PAGE_SHIFT;
}
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 6000ad7f560c..fc6a4c8f6e2a 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -66,6 +66,9 @@ void update_page_count(int level, unsigned long pages)
static void split_page_count(int level)
{
+ if (direct_pages_count[level] == 0)
+ return;
+
direct_pages_count[level]--;
direct_pages_count[level - 1] += PTRS_PER_PTE;
}
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 031782e74231..f4ae536b0914 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -12,6 +12,7 @@
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/pfn_t.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/fs.h>
@@ -949,7 +950,7 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
}
int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
- unsigned long pfn)
+ pfn_t pfn)
{
enum page_cache_mode pcm;
@@ -957,7 +958,7 @@ int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
return 0;
/* Set prot based on lookup */
- pcm = lookup_memtype((resource_size_t)pfn << PAGE_SHIFT);
+ pcm = lookup_memtype(pfn_t_to_phys(pfn));
*prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
cachemode2protval(pcm));
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index ee9c2e3a7199..4eb287e25043 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -505,19 +505,6 @@ int pmdp_clear_flush_young(struct vm_area_struct *vma,
return young;
}
-
-void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp)
-{
- int set;
- VM_BUG_ON(address & ~HPAGE_PMD_MASK);
- set = !test_and_set_bit(_PAGE_BIT_SPLITTING,
- (unsigned long *)pmdp);
- if (set) {
- /* need tlb flush only to serialize against gup-fast */
- flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
- }
-}
#endif
/**
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 8ddb5d0d66fb..8f4cc3dfac32 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -161,7 +161,10 @@ void flush_tlb_current_task(void)
preempt_disable();
count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
+
+ /* This is an implicit full barrier that synchronizes with switch_mm. */
local_flush_tlb();
+
trace_tlb_flush(TLB_LOCAL_SHOOTDOWN, TLB_FLUSH_ALL);
if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL);
@@ -188,17 +191,29 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
unsigned long base_pages_to_flush = TLB_FLUSH_ALL;
preempt_disable();
- if (current->active_mm != mm)
+ if (current->active_mm != mm) {
+ /* Synchronize with switch_mm. */
+ smp_mb();
+
goto out;
+ }
if (!current->mm) {
leave_mm(smp_processor_id());
+
+ /* Synchronize with switch_mm. */
+ smp_mb();
+
goto out;
}
if ((end != TLB_FLUSH_ALL) && !(vmflag & VM_HUGETLB))
base_pages_to_flush = (end - start) >> PAGE_SHIFT;
+ /*
+ * Both branches below are implicit full barriers (MOV to CR or
+ * INVLPG) that synchronize with switch_mm.
+ */
if (base_pages_to_flush > tlb_single_page_flush_ceiling) {
base_pages_to_flush = TLB_FLUSH_ALL;
count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
@@ -228,10 +243,18 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start)
preempt_disable();
if (current->active_mm == mm) {
- if (current->mm)
+ if (current->mm) {
+ /*
+ * Implicit full barrier (INVLPG) that synchronizes
+ * with switch_mm.
+ */
__flush_tlb_one(start);
- else
+ } else {
leave_mm(smp_processor_id());
+
+ /* Synchronize with switch_mm. */
+ smp_mb();
+ }
}
if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h
index 755481f14d90..174781a404ff 100644
--- a/arch/x86/um/asm/barrier.h
+++ b/arch/x86/um/asm/barrier.h
@@ -36,13 +36,6 @@
#endif /* CONFIG_X86_PPRO_FENCE */
#define dma_wmb() barrier()
-#define smp_mb() barrier()
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
-
-#define read_barrier_depends() do { } while (0)
-#define smp_read_barrier_depends() do { } while (0)
+#include <asm-generic/barrier.h>
#endif
diff --git a/arch/xtensa/include/asm/barrier.h b/arch/xtensa/include/asm/barrier.h
index 5b88774c75ab..956596e4d437 100644
--- a/arch/xtensa/include/asm/barrier.h
+++ b/arch/xtensa/include/asm/barrier.h
@@ -13,8 +13,8 @@
#define rmb() barrier()
#define wmb() mb()
-#define smp_mb__before_atomic() barrier()
-#define smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() barrier()
+#define __smp_mb__after_atomic() barrier()
#include <asm-generic/barrier.h>
diff --git a/arch/xtensa/include/uapi/asm/mman.h b/arch/xtensa/include/uapi/asm/mman.h
index 360944e1da52..d030594ed22b 100644
--- a/arch/xtensa/include/uapi/asm/mman.h
+++ b/arch/xtensa/include/uapi/asm/mman.h
@@ -86,8 +86,10 @@
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
#define MADV_WILLNEED 3 /* will need these pages */
#define MADV_DONTNEED 4 /* don't need these pages */
+#define MADV_FREE 5 /* free pages only if memory pressure */
/* common parameters: try to keep these consistent across architectures */
+#define MADV_FREE 8 /* free pages only if memory pressure */
#define MADV_REMOVE 9 /* remove these pages & resources */
#define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
index 5ece856c5725..35c822286bbe 100644
--- a/arch/xtensa/mm/tlb.c
+++ b/arch/xtensa/mm/tlb.c
@@ -245,7 +245,7 @@ static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
page_mapcount(p));
if (!page_count(p))
rc |= TLB_INSANE;
- else if (page_mapped(p))
+ else if (page_mapcount(p))
rc |= TLB_SUSPICIOUS;
} else {
rc |= TLB_INSANE;
diff --git a/block/Makefile b/block/Makefile
index 00ecc97629db..db5f622c9d67 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \
blk-iopoll.o blk-lib.o blk-mq.o blk-mq-tag.o \
blk-mq-sysfs.o blk-mq-cpu.o blk-mq-cpumap.o ioctl.o \
genhd.o scsi_ioctl.o partition-generic.o ioprio.o \
- partitions/
+ badblocks.o partitions/
obj-$(CONFIG_BOUNCE) += bounce.o
obj-$(CONFIG_BLK_DEV_BSG) += bsg.o
diff --git a/block/badblocks.c b/block/badblocks.c
new file mode 100644
index 000000000000..7be53cb1cc3c
--- /dev/null
+++ b/block/badblocks.c
@@ -0,0 +1,585 @@
+/*
+ * Bad block management
+ *
+ * - Heavily based on MD badblocks code from Neil Brown
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/badblocks.h>
+#include <linux/seqlock.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+/**
+ * badblocks_check() - check a given range for bad sectors
+ * @bb: the badblocks structure that holds all badblock information
+ * @s: sector (start) at which to check for badblocks
+ * @sectors: number of sectors to check for badblocks
+ * @first_bad: pointer to store location of the first badblock
+ * @bad_sectors: pointer to store number of badblocks after @first_bad
+ *
+ * We can record which blocks on each device are 'bad' and so just
+ * fail those blocks, or that stripe, rather than the whole device.
+ * Entries in the bad-block table are 64bits wide. This comprises:
+ * Length of bad-range, in sectors: 0-511 for lengths 1-512
+ * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
+ * A 'shift' can be set so that larger blocks are tracked and
+ * consequently larger devices can be covered.
+ * 'Acknowledged' flag - 1 bit. - the most significant bit.
+ *
+ * Locking of the bad-block table uses a seqlock so badblocks_check
+ * might need to retry if it is very unlucky.
+ * We will sometimes want to check for bad blocks in a bi_end_io function,
+ * so we use the write_seqlock_irq variant.
+ *
+ * When looking for a bad block we specify a range and want to
+ * know if any block in the range is bad. So we binary-search
+ * to the last range that starts at-or-before the given endpoint,
+ * (or "before the sector after the target range")
+ * then see if it ends after the given start.
+ *
+ * Return:
+ * 0: there are no known bad blocks in the range
+ * 1: there are known bad block which are all acknowledged
+ * -1: there are bad blocks which have not yet been acknowledged in metadata.
+ * plus the start/length of the first bad section we overlap.
+ */
+int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
+ sector_t *first_bad, int *bad_sectors)
+{
+ int hi;
+ int lo;
+ u64 *p = bb->page;
+ int rv;
+ sector_t target = s + sectors;
+ unsigned seq;
+
+ if (bb->shift > 0) {
+ /* round the start down, and the end up */
+ s >>= bb->shift;
+ target += (1<<bb->shift) - 1;
+ target >>= bb->shift;
+ sectors = target - s;
+ }
+ /* 'target' is now the first block after the bad range */
+
+retry:
+ seq = read_seqbegin(&bb->lock);
+ lo = 0;
+ rv = 0;
+ hi = bb->count;
+
+ /* Binary search between lo and hi for 'target'
+ * i.e. for the last range that starts before 'target'
+ */
+ /* INVARIANT: ranges before 'lo' and at-or-after 'hi'
+ * are known not to be the last range before target.
+ * VARIANT: hi-lo is the number of possible
+ * ranges, and decreases until it reaches 1
+ */
+ while (hi - lo > 1) {
+ int mid = (lo + hi) / 2;
+ sector_t a = BB_OFFSET(p[mid]);
+
+ if (a < target)
+ /* This could still be the one, earlier ranges
+ * could not.
+ */
+ lo = mid;
+ else
+ /* This and later ranges are definitely out. */
+ hi = mid;
+ }
+ /* 'lo' might be the last that started before target, but 'hi' isn't */
+ if (hi > lo) {
+ /* need to check all range that end after 's' to see if
+ * any are unacknowledged.
+ */
+ while (lo >= 0 &&
+ BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
+ if (BB_OFFSET(p[lo]) < target) {
+ /* starts before the end, and finishes after
+ * the start, so they must overlap
+ */
+ if (rv != -1 && BB_ACK(p[lo]))
+ rv = 1;
+ else
+ rv = -1;
+ *first_bad = BB_OFFSET(p[lo]);
+ *bad_sectors = BB_LEN(p[lo]);
+ }
+ lo--;
+ }
+ }
+
+ if (read_seqretry(&bb->lock, seq))
+ goto retry;
+
+ return rv;
+}
+EXPORT_SYMBOL_GPL(badblocks_check);
+
+/**
+ * badblocks_set() - Add a range of bad blocks to the table.
+ * @bb: the badblocks structure that holds all badblock information
+ * @s: first sector to mark as bad
+ * @sectors: number of sectors to mark as bad
+ * @acknowledged: weather to mark the bad sectors as acknowledged
+ *
+ * This might extend the table, or might contract it if two adjacent ranges
+ * can be merged. We binary-search to find the 'insertion' point, then
+ * decide how best to handle it.
+ *
+ * Return:
+ * 0: success
+ * 1: failed to set badblocks (out of space)
+ */
+int badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+ int acknowledged)
+{
+ u64 *p;
+ int lo, hi;
+ int rv = 0;
+ unsigned long flags;
+
+ if (bb->shift < 0)
+ /* badblocks are disabled */
+ return 0;
+
+ if (bb->shift) {
+ /* round the start down, and the end up */
+ sector_t next = s + sectors;
+
+ s >>= bb->shift;
+ next += (1<<bb->shift) - 1;
+ next >>= bb->shift;
+ sectors = next - s;
+ }
+
+ write_seqlock_irqsave(&bb->lock, flags);
+
+ p = bb->page;
+ lo = 0;
+ hi = bb->count;
+ /* Find the last range that starts at-or-before 's' */
+ while (hi - lo > 1) {
+ int mid = (lo + hi) / 2;
+ sector_t a = BB_OFFSET(p[mid]);
+
+ if (a <= s)
+ lo = mid;
+ else
+ hi = mid;
+ }
+ if (hi > lo && BB_OFFSET(p[lo]) > s)
+ hi = lo;
+
+ if (hi > lo) {
+ /* we found a range that might merge with the start
+ * of our new range
+ */
+ sector_t a = BB_OFFSET(p[lo]);
+ sector_t e = a + BB_LEN(p[lo]);
+ int ack = BB_ACK(p[lo]);
+
+ if (e >= s) {
+ /* Yes, we can merge with a previous range */
+ if (s == a && s + sectors >= e)
+ /* new range covers old */
+ ack = acknowledged;
+ else
+ ack = ack && acknowledged;
+
+ if (e < s + sectors)
+ e = s + sectors;
+ if (e - a <= BB_MAX_LEN) {
+ p[lo] = BB_MAKE(a, e-a, ack);
+ s = e;
+ } else {
+ /* does not all fit in one range,
+ * make p[lo] maximal
+ */
+ if (BB_LEN(p[lo]) != BB_MAX_LEN)
+ p[lo] = BB_MAKE(a, BB_MAX_LEN, ack);
+ s = a + BB_MAX_LEN;
+ }
+ sectors = e - s;
+ }
+ }
+ if (sectors && hi < bb->count) {
+ /* 'hi' points to the first range that starts after 's'.
+ * Maybe we can merge with the start of that range
+ */
+ sector_t a = BB_OFFSET(p[hi]);
+ sector_t e = a + BB_LEN(p[hi]);
+ int ack = BB_ACK(p[hi]);
+
+ if (a <= s + sectors) {
+ /* merging is possible */
+ if (e <= s + sectors) {
+ /* full overlap */
+ e = s + sectors;
+ ack = acknowledged;
+ } else
+ ack = ack && acknowledged;
+
+ a = s;
+ if (e - a <= BB_MAX_LEN) {
+ p[hi] = BB_MAKE(a, e-a, ack);
+ s = e;
+ } else {
+ p[hi] = BB_MAKE(a, BB_MAX_LEN, ack);
+ s = a + BB_MAX_LEN;
+ }
+ sectors = e - s;
+ lo = hi;
+ hi++;
+ }
+ }
+ if (sectors == 0 && hi < bb->count) {
+ /* we might be able to combine lo and hi */
+ /* Note: 's' is at the end of 'lo' */
+ sector_t a = BB_OFFSET(p[hi]);
+ int lolen = BB_LEN(p[lo]);
+ int hilen = BB_LEN(p[hi]);
+ int newlen = lolen + hilen - (s - a);
+
+ if (s >= a && newlen < BB_MAX_LEN) {
+ /* yes, we can combine them */
+ int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]);
+
+ p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack);
+ memmove(p + hi, p + hi + 1,
+ (bb->count - hi - 1) * 8);
+ bb->count--;
+ }
+ }
+ while (sectors) {
+ /* didn't merge (it all).
+ * Need to add a range just before 'hi'
+ */
+ if (bb->count >= MAX_BADBLOCKS) {
+ /* No room for more */
+ rv = 1;
+ break;
+ } else {
+ int this_sectors = sectors;
+
+ memmove(p + hi + 1, p + hi,
+ (bb->count - hi) * 8);
+ bb->count++;
+
+ if (this_sectors > BB_MAX_LEN)
+ this_sectors = BB_MAX_LEN;
+ p[hi] = BB_MAKE(s, this_sectors, acknowledged);
+ sectors -= this_sectors;
+ s += this_sectors;
+ }
+ }
+
+ bb->changed = 1;
+ if (!acknowledged)
+ bb->unacked_exist = 1;
+ write_sequnlock_irqrestore(&bb->lock, flags);
+
+ return rv;
+}
+EXPORT_SYMBOL_GPL(badblocks_set);
+
+/**
+ * badblocks_clear() - Remove a range of bad blocks to the table.
+ * @bb: the badblocks structure that holds all badblock information
+ * @s: first sector to mark as bad
+ * @sectors: number of sectors to mark as bad
+ *
+ * This may involve extending the table if we spilt a region,
+ * but it must not fail. So if the table becomes full, we just
+ * drop the remove request.
+ *
+ * Return:
+ * 0: success
+ * 1: failed to clear badblocks
+ */
+int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
+{
+ u64 *p;
+ int lo, hi;
+ sector_t target = s + sectors;
+ int rv = 0;
+
+ if (bb->shift > 0) {
+ /* When clearing we round the start up and the end down.
+ * This should not matter as the shift should align with
+ * the block size and no rounding should ever be needed.
+ * However it is better the think a block is bad when it
+ * isn't than to think a block is not bad when it is.
+ */
+ s += (1<<bb->shift) - 1;
+ s >>= bb->shift;
+ target >>= bb->shift;
+ sectors = target - s;
+ }
+
+ write_seqlock_irq(&bb->lock);
+
+ p = bb->page;
+ lo = 0;
+ hi = bb->count;
+ /* Find the last range that starts before 'target' */
+ while (hi - lo > 1) {
+ int mid = (lo + hi) / 2;
+ sector_t a = BB_OFFSET(p[mid]);
+
+ if (a < target)
+ lo = mid;
+ else
+ hi = mid;
+ }
+ if (hi > lo) {
+ /* p[lo] is the last range that could overlap the
+ * current range. Earlier ranges could also overlap,
+ * but only this one can overlap the end of the range.
+ */
+ if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) {
+ /* Partial overlap, leave the tail of this range */
+ int ack = BB_ACK(p[lo]);
+ sector_t a = BB_OFFSET(p[lo]);
+ sector_t end = a + BB_LEN(p[lo]);
+
+ if (a < s) {
+ /* we need to split this range */
+ if (bb->count >= MAX_BADBLOCKS) {
+ rv = -ENOSPC;
+ goto out;
+ }
+ memmove(p+lo+1, p+lo, (bb->count - lo) * 8);
+ bb->count++;
+ p[lo] = BB_MAKE(a, s-a, ack);
+ lo++;
+ }
+ p[lo] = BB_MAKE(target, end - target, ack);
+ /* there is no longer an overlap */
+ hi = lo;
+ lo--;
+ }
+ while (lo >= 0 &&
+ BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
+ /* This range does overlap */
+ if (BB_OFFSET(p[lo]) < s) {
+ /* Keep the early parts of this range. */
+ int ack = BB_ACK(p[lo]);
+ sector_t start = BB_OFFSET(p[lo]);
+
+ p[lo] = BB_MAKE(start, s - start, ack);
+ /* now low doesn't overlap, so.. */
+ break;
+ }
+ lo--;
+ }
+ /* 'lo' is strictly before, 'hi' is strictly after,
+ * anything between needs to be discarded
+ */
+ if (hi - lo > 1) {
+ memmove(p+lo+1, p+hi, (bb->count - hi) * 8);
+ bb->count -= (hi - lo - 1);
+ }
+ }
+
+ bb->changed = 1;
+out:
+ write_sequnlock_irq(&bb->lock);
+ return rv;
+}
+EXPORT_SYMBOL_GPL(badblocks_clear);
+
+/**
+ * ack_all_badblocks() - Acknowledge all bad blocks in a list.
+ * @bb: the badblocks structure that holds all badblock information
+ *
+ * This only succeeds if ->changed is clear. It is used by
+ * in-kernel metadata updates
+ */
+void ack_all_badblocks(struct badblocks *bb)
+{
+ if (bb->page == NULL || bb->changed)
+ /* no point even trying */
+ return;
+ write_seqlock_irq(&bb->lock);
+
+ if (bb->changed == 0 && bb->unacked_exist) {
+ u64 *p = bb->page;
+ int i;
+
+ for (i = 0; i < bb->count ; i++) {
+ if (!BB_ACK(p[i])) {
+ sector_t start = BB_OFFSET(p[i]);
+ int len = BB_LEN(p[i]);
+
+ p[i] = BB_MAKE(start, len, 1);
+ }
+ }
+ bb->unacked_exist = 0;
+ }
+ write_sequnlock_irq(&bb->lock);
+}
+EXPORT_SYMBOL_GPL(ack_all_badblocks);
+
+/**
+ * badblocks_show() - sysfs access to bad-blocks list
+ * @bb: the badblocks structure that holds all badblock information
+ * @page: buffer received from sysfs
+ * @unack: weather to show unacknowledged badblocks
+ *
+ * Return:
+ * Length of returned data
+ */
+ssize_t badblocks_show(struct badblocks *bb, char *page, int unack)
+{
+ size_t len;
+ int i;
+ u64 *p = bb->page;
+ unsigned seq;
+
+ if (bb->shift < 0)
+ return 0;
+
+retry:
+ seq = read_seqbegin(&bb->lock);
+
+ len = 0;
+ i = 0;
+
+ while (len < PAGE_SIZE && i < bb->count) {
+ sector_t s = BB_OFFSET(p[i]);
+ unsigned int length = BB_LEN(p[i]);
+ int ack = BB_ACK(p[i]);
+
+ i++;
+
+ if (unack && ack)
+ continue;
+
+ len += snprintf(page+len, PAGE_SIZE-len, "%llu %u\n",
+ (unsigned long long)s << bb->shift,
+ length << bb->shift);
+ }
+ if (unack && len == 0)
+ bb->unacked_exist = 0;
+
+ if (read_seqretry(&bb->lock, seq))
+ goto retry;
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(badblocks_show);
+
+/**
+ * badblocks_store() - sysfs access to bad-blocks list
+ * @bb: the badblocks structure that holds all badblock information
+ * @page: buffer received from sysfs
+ * @len: length of data received from sysfs
+ * @unack: weather to show unacknowledged badblocks
+ *
+ * Return:
+ * Length of the buffer processed or -ve error.
+ */
+ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
+ int unack)
+{
+ unsigned long long sector;
+ int length;
+ char newline;
+
+ switch (sscanf(page, "%llu %d%c", &sector, &length, &newline)) {
+ case 3:
+ if (newline != '\n')
+ return -EINVAL;
+ case 2:
+ if (length <= 0)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (badblocks_set(bb, sector, length, !unack))
+ return -ENOSPC;
+ else
+ return len;
+}
+EXPORT_SYMBOL_GPL(badblocks_store);
+
+static int __badblocks_init(struct device *dev, struct badblocks *bb,
+ int enable)
+{
+ bb->dev = dev;
+ bb->count = 0;
+ if (enable)
+ bb->shift = 0;
+ else
+ bb->shift = -1;
+ if (dev)
+ bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
+ else
+ bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!bb->page) {
+ bb->shift = -1;
+ return -ENOMEM;
+ }
+ seqlock_init(&bb->lock);
+
+ return 0;
+}
+
+/**
+ * badblocks_init() - initialize the badblocks structure
+ * @bb: the badblocks structure that holds all badblock information
+ * @enable: weather to enable badblocks accounting
+ *
+ * Return:
+ * 0: success
+ * -ve errno: on error
+ */
+int badblocks_init(struct badblocks *bb, int enable)
+{
+ return __badblocks_init(NULL, bb, enable);
+}
+EXPORT_SYMBOL_GPL(badblocks_init);
+
+int devm_init_badblocks(struct device *dev, struct badblocks *bb)
+{
+ if (!bb)
+ return -EINVAL;
+ return __badblocks_init(dev, bb, 1);
+}
+EXPORT_SYMBOL_GPL(devm_init_badblocks);
+
+/**
+ * badblocks_exit() - free the badblocks structure
+ * @bb: the badblocks structure that holds all badblock information
+ */
+void badblocks_exit(struct badblocks *bb)
+{
+ if (!bb)
+ return;
+ if (bb->dev)
+ devm_kfree(bb->dev, bb->page);
+ else
+ kfree(bb->page);
+ bb->page = NULL;
+}
+EXPORT_SYMBOL_GPL(badblocks_exit);
diff --git a/block/bio.c b/block/bio.c
index 4f184d938942..dbabd48b1934 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1125,7 +1125,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
int i, ret;
int nr_pages = 0;
unsigned int len = iter->count;
- unsigned int offset = map_data ? map_data->offset & ~PAGE_MASK : 0;
+ unsigned int offset = map_data ? offset_in_page(map_data->offset) : 0;
for (i = 0; i < iter->nr_segs; i++) {
unsigned long uaddr;
@@ -1304,7 +1304,7 @@ struct bio *bio_map_user_iov(struct request_queue *q,
goto out_unmap;
}
- offset = uaddr & ~PAGE_MASK;
+ offset = offset_in_page(uaddr);
for (j = cur_page; j < page_limit; j++) {
unsigned int bytes = PAGE_SIZE - offset;
diff --git a/block/blk-core.c b/block/blk-core.c
index 33e2f62d5062..476244d59309 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -51,7 +51,7 @@ DEFINE_IDA(blk_queue_ida);
/*
* For the allocated request tables
*/
-struct kmem_cache *request_cachep = NULL;
+struct kmem_cache *request_cachep;
/*
* For queue allocation
@@ -646,7 +646,7 @@ struct request_queue *blk_alloc_queue(gfp_t gfp_mask)
}
EXPORT_SYMBOL(blk_alloc_queue);
-int blk_queue_enter(struct request_queue *q, gfp_t gfp)
+int blk_queue_enter(struct request_queue *q, bool nowait)
{
while (true) {
int ret;
@@ -654,7 +654,7 @@ int blk_queue_enter(struct request_queue *q, gfp_t gfp)
if (percpu_ref_tryget_live(&q->q_usage_counter))
return 0;
- if (!gfpflags_allow_blocking(gfp))
+ if (nowait)
return -EBUSY;
ret = wait_event_interruptible(q->mq_freeze_wq,
@@ -1292,7 +1292,9 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw,
struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
{
if (q->mq_ops)
- return blk_mq_alloc_request(q, rw, gfp_mask, false);
+ return blk_mq_alloc_request(q, rw,
+ (gfp_mask & __GFP_DIRECT_RECLAIM) ?
+ 0 : BLK_MQ_REQ_NOWAIT);
else
return blk_old_get_request(q, rw, gfp_mask);
}
@@ -2060,8 +2062,7 @@ blk_qc_t generic_make_request(struct bio *bio)
do {
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
- if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) {
-
+ if (likely(blk_queue_enter(q, false) == 0)) {
ret = q->make_request_fn(q, bio);
blk_queue_exit(q);
@@ -3534,7 +3535,7 @@ int __init blk_dev_init(void)
request_cachep = kmem_cache_create("blkdev_requests",
sizeof(struct request), 0, SLAB_PANIC, NULL);
- blk_requestq_cachep = kmem_cache_create("blkdev_queue",
+ blk_requestq_cachep = kmem_cache_create("request_queue",
sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
return 0;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index e01405a3e8b3..1699df5b0493 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -7,6 +7,8 @@
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
+#include <trace/events/block.h>
+
#include "blk.h"
static struct bio *blk_bio_discard_split(struct request_queue *q,
@@ -81,9 +83,6 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
struct bio *new = NULL;
bio_for_each_segment(bv, bio, iter) {
- if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q))
- goto split;
-
/*
* If the queue doesn't support SG gaps and adding this
* offset would create a gap, disallow it.
@@ -91,6 +90,22 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset))
goto split;
+ if (sectors + (bv.bv_len >> 9) >
+ blk_max_size_offset(q, bio->bi_iter.bi_sector)) {
+ /*
+ * Consider this a new segment if we're splitting in
+ * the middle of this vector.
+ */
+ if (nsegs < queue_max_segments(q) &&
+ sectors < blk_max_size_offset(q,
+ bio->bi_iter.bi_sector)) {
+ nsegs++;
+ sectors = blk_max_size_offset(q,
+ bio->bi_iter.bi_sector);
+ }
+ goto split;
+ }
+
if (bvprvp && blk_queue_cluster(q)) {
if (seg_size + bv.bv_len > queue_max_segment_size(q))
goto new_segment;
@@ -162,6 +177,7 @@ void blk_queue_split(struct request_queue *q, struct bio **bio,
split->bi_rw |= REQ_NOMERGE;
bio_chain(split, *bio);
+ trace_block_split(q, split, (*bio)->bi_iter.bi_sector);
generic_make_request(*bio);
*bio = split;
}
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index 8764c241e5bb..d0634bcf322f 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -113,7 +113,7 @@ int blk_mq_hw_queue_to_node(unsigned int *mq_map, unsigned int index)
for_each_possible_cpu(i) {
if (index == mq_map[i])
- return cpu_to_node(i);
+ return local_memory_node(cpu_to_node(i));
}
return NUMA_NO_NODE;
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index a07ca3488d96..abdbb47405cb 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -268,7 +268,7 @@ static int bt_get(struct blk_mq_alloc_data *data,
if (tag != -1)
return tag;
- if (!gfpflags_allow_blocking(data->gfp))
+ if (data->flags & BLK_MQ_REQ_NOWAIT)
return -1;
bs = bt_wait_ptr(bt, hctx);
@@ -303,7 +303,7 @@ static int bt_get(struct blk_mq_alloc_data *data,
data->ctx = blk_mq_get_ctx(data->q);
data->hctx = data->q->mq_ops->map_queue(data->q,
data->ctx->cpu);
- if (data->reserved) {
+ if (data->flags & BLK_MQ_REQ_RESERVED) {
bt = &data->hctx->tags->breserved_tags;
} else {
last_tag = &data->ctx->last_tag;
@@ -349,10 +349,9 @@ static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_alloc_data *data)
unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data)
{
- if (!data->reserved)
- return __blk_mq_get_tag(data);
-
- return __blk_mq_get_reserved_tag(data);
+ if (data->flags & BLK_MQ_REQ_RESERVED)
+ return __blk_mq_get_reserved_tag(data);
+ return __blk_mq_get_tag(data);
}
static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 6d6f8feb48c0..6889d7183a2a 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -229,8 +229,8 @@ __blk_mq_alloc_request(struct blk_mq_alloc_data *data, int rw)
return NULL;
}
-struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp,
- bool reserved)
+struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
+ unsigned int flags)
{
struct blk_mq_ctx *ctx;
struct blk_mq_hw_ctx *hctx;
@@ -238,24 +238,22 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp,
struct blk_mq_alloc_data alloc_data;
int ret;
- ret = blk_queue_enter(q, gfp);
+ ret = blk_queue_enter(q, flags & BLK_MQ_REQ_NOWAIT);
if (ret)
return ERR_PTR(ret);
ctx = blk_mq_get_ctx(q);
hctx = q->mq_ops->map_queue(q, ctx->cpu);
- blk_mq_set_alloc_data(&alloc_data, q, gfp & ~__GFP_DIRECT_RECLAIM,
- reserved, ctx, hctx);
+ blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
rq = __blk_mq_alloc_request(&alloc_data, rw);
- if (!rq && (gfp & __GFP_DIRECT_RECLAIM)) {
+ if (!rq && !(flags & BLK_MQ_REQ_NOWAIT)) {
__blk_mq_run_hw_queue(hctx);
blk_mq_put_ctx(ctx);
ctx = blk_mq_get_ctx(q);
hctx = q->mq_ops->map_queue(q, ctx->cpu);
- blk_mq_set_alloc_data(&alloc_data, q, gfp, reserved, ctx,
- hctx);
+ blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
rq = __blk_mq_alloc_request(&alloc_data, rw);
ctx = alloc_data.ctx;
}
@@ -1175,8 +1173,7 @@ static struct request *blk_mq_map_request(struct request_queue *q,
rw |= REQ_SYNC;
trace_block_getrq(q, bio, rw);
- blk_mq_set_alloc_data(&alloc_data, q, GFP_ATOMIC, false, ctx,
- hctx);
+ blk_mq_set_alloc_data(&alloc_data, q, BLK_MQ_REQ_NOWAIT, ctx, hctx);
rq = __blk_mq_alloc_request(&alloc_data, rw);
if (unlikely(!rq)) {
__blk_mq_run_hw_queue(hctx);
@@ -1185,8 +1182,7 @@ static struct request *blk_mq_map_request(struct request_queue *q,
ctx = blk_mq_get_ctx(q);
hctx = q->mq_ops->map_queue(q, ctx->cpu);
- blk_mq_set_alloc_data(&alloc_data, q,
- __GFP_RECLAIM|__GFP_HIGH, false, ctx, hctx);
+ blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx);
rq = __blk_mq_alloc_request(&alloc_data, rw);
ctx = alloc_data.ctx;
hctx = alloc_data.hctx;
@@ -1794,7 +1790,7 @@ static void blk_mq_init_cpu_queues(struct request_queue *q,
* not, we remain on the home node of the device
*/
if (nr_hw_queues > 1 && hctx->numa_node == NUMA_NO_NODE)
- hctx->numa_node = cpu_to_node(i);
+ hctx->numa_node = local_memory_node(cpu_to_node(i));
}
}
@@ -1854,6 +1850,7 @@ static void blk_mq_map_swqueue(struct request_queue *q,
hctx->tags = set->tags[i];
WARN_ON(!hctx->tags);
+ cpumask_copy(hctx->tags->cpumask, hctx->cpumask);
/*
* Set the map size to the number of mapped software queues.
* This is more accurate and more efficient than looping
@@ -1867,14 +1864,6 @@ static void blk_mq_map_swqueue(struct request_queue *q,
hctx->next_cpu = cpumask_first(hctx->cpumask);
hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
}
-
- queue_for_each_ctx(q, ctx, i) {
- if (!cpumask_test_cpu(i, online_mask))
- continue;
-
- hctx = q->mq_ops->map_queue(q, i);
- cpumask_set_cpu(i, hctx->tags->cpumask);
- }
}
static void queue_set_hctx_shared(struct request_queue *q, bool shared)
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 713820b47b31..eaede8e45c9c 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -96,8 +96,7 @@ static inline void blk_mq_put_ctx(struct blk_mq_ctx *ctx)
struct blk_mq_alloc_data {
/* input parameter */
struct request_queue *q;
- gfp_t gfp;
- bool reserved;
+ unsigned int flags;
/* input & output parameter */
struct blk_mq_ctx *ctx;
@@ -105,13 +104,11 @@ struct blk_mq_alloc_data {
};
static inline void blk_mq_set_alloc_data(struct blk_mq_alloc_data *data,
- struct request_queue *q, gfp_t gfp, bool reserved,
- struct blk_mq_ctx *ctx,
- struct blk_mq_hw_ctx *hctx)
+ struct request_queue *q, unsigned int flags,
+ struct blk_mq_ctx *ctx, struct blk_mq_hw_ctx *hctx)
{
data->q = q;
- data->gfp = gfp;
- data->reserved = reserved;
+ data->flags = flags;
data->ctx = ctx;
data->hctx = hctx;
}
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index aa40aa93381b..3610af561748 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -186,6 +186,7 @@ unsigned long blk_rq_timeout(unsigned long timeout)
* Notes:
* Each request has its own timer, and as it is added to the queue, we
* set up the timer. When the request completes, we cancel the timer.
+ * Queue lock must be held for the non-mq case, mq case doesn't care.
*/
void blk_add_timer(struct request *req)
{
@@ -209,6 +210,11 @@ void blk_add_timer(struct request *req)
req->timeout = q->rq_timeout;
req->deadline = jiffies + req->timeout;
+
+ /*
+ * Only the non-mq case needs to add the request to a protected list.
+ * For the mq case we simply scan the tag map.
+ */
if (!q->mq_ops)
list_add_tail(&req->timeout_list, &req->q->timeout_list);
diff --git a/block/genhd.c b/block/genhd.c
index e5cafa51567c..9f42526b4d62 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -20,6 +20,7 @@
#include <linux/idr.h>
#include <linux/log2.h>
#include <linux/pm_runtime.h>
+#include <linux/badblocks.h>
#include "blk.h"
@@ -664,7 +665,6 @@ void del_gendisk(struct gendisk *disk)
kobject_put(disk->part0.holder_dir);
kobject_put(disk->slave_dir);
- disk->driverfs_dev = NULL;
if (!sysfs_deprecated)
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
@@ -672,6 +672,31 @@ void del_gendisk(struct gendisk *disk)
}
EXPORT_SYMBOL(del_gendisk);
+/* sysfs access to bad-blocks list. */
+static ssize_t disk_badblocks_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+
+ if (!disk->bb)
+ return sprintf(page, "\n");
+
+ return badblocks_show(disk->bb, page, 0);
+}
+
+static ssize_t disk_badblocks_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *page, size_t len)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+
+ if (!disk->bb)
+ return -ENXIO;
+
+ return badblocks_store(disk->bb, page, len, 0);
+}
+
/**
* get_gendisk - get partitioning information for a given device
* @devt: device to get partitioning information for
@@ -990,6 +1015,8 @@ static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show,
static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
+static DEVICE_ATTR(badblocks, S_IRUGO | S_IWUSR, disk_badblocks_show,
+ disk_badblocks_store);
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -1011,6 +1038,7 @@ static struct attribute *disk_attrs[] = {
&dev_attr_capability.attr,
&dev_attr_stat.attr,
&dev_attr_inflight.attr,
+ &dev_attr_badblocks.attr,
#ifdef CONFIG_FAIL_MAKE_REQUEST
&dev_attr_fail.attr,
#endif
@@ -1421,7 +1449,7 @@ static DEFINE_MUTEX(disk_events_mutex);
static LIST_HEAD(disk_events);
/* disable in-kernel polling by default */
-static unsigned long disk_events_dfl_poll_msecs = 0;
+static unsigned long disk_events_dfl_poll_msecs;
static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
{
diff --git a/block/ioctl.c b/block/ioctl.c
index 0918aed2d847..2c84683aada5 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -4,6 +4,7 @@
#include <linux/gfp.h>
#include <linux/blkpg.h>
#include <linux/hdreg.h>
+#include <linux/badblocks.h>
#include <linux/backing-dev.h>
#include <linux/fs.h>
#include <linux/blktrace_api.h>
@@ -406,6 +407,71 @@ static inline int is_unrecognized_ioctl(int ret)
ret == -ENOIOCTLCMD;
}
+#ifdef CONFIG_FS_DAX
+bool blkdev_dax_capable(struct block_device *bdev)
+{
+ struct gendisk *disk = bdev->bd_disk;
+
+ if (!disk->fops->direct_access)
+ return false;
+
+ /*
+ * If the partition is not aligned on a page boundary, we can't
+ * do dax I/O to it.
+ */
+ if ((bdev->bd_part->start_sect % (PAGE_SIZE / 512))
+ || (bdev->bd_part->nr_sects % (PAGE_SIZE / 512)))
+ return false;
+
+ /*
+ * If the device has known bad blocks, force all I/O through the
+ * driver / page cache.
+ *
+ * TODO: support finer grained dax error handling
+ */
+ if (disk->bb && disk->bb->count)
+ return false;
+
+ return true;
+}
+
+static int blkdev_daxset(struct block_device *bdev, unsigned long argp)
+{
+ unsigned long arg;
+ int rc = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (get_user(arg, (int __user *)(argp)))
+ return -EFAULT;
+ arg = !!arg;
+ if (arg == !!(bdev->bd_inode->i_flags & S_DAX))
+ return 0;
+
+ if (arg)
+ arg = S_DAX;
+
+ if (arg && !blkdev_dax_capable(bdev))
+ return -ENOTTY;
+
+ mutex_lock(&bdev->bd_inode->i_mutex);
+ if (bdev->bd_map_count == 0)
+ inode_set_flags(bdev->bd_inode, arg, S_DAX);
+ else
+ rc = -EBUSY;
+ mutex_unlock(&bdev->bd_inode->i_mutex);
+ return rc;
+}
+#else
+static int blkdev_daxset(struct block_device *bdev, int arg)
+{
+ if (arg)
+ return -ENOTTY;
+ return 0;
+}
+#endif
+
static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
@@ -568,6 +634,11 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
case BLKTRACESETUP:
case BLKTRACETEARDOWN:
return blk_trace_ioctl(bdev, cmd, argp);
+ case BLKDAXSET:
+ return blkdev_daxset(bdev, arg);
+ case BLKDAXGET:
+ return put_int(arg, !!(bdev->bd_inode->i_flags & S_DAX));
+ break;
case IOC_PR_REGISTER:
return blkdev_pr_register(bdev, argp);
case IOC_PR_RESERVE:
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 2a44b3752471..9e9e5a6a9ed6 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -321,6 +321,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
goto error_free_cert;
} else if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
+ if (ret)
+ ret = x509_validate_trust(cert, get_ima_mok_keyring());
if (!ret)
prep->trusted = 1;
}
diff --git a/crypto/hash_info.c b/crypto/hash_info.c
index 3e7ff46f26e8..7b1e0b188ce6 100644
--- a/crypto/hash_info.c
+++ b/crypto/hash_info.c
@@ -31,6 +31,7 @@ const char *const hash_algo_name[HASH_ALGO__LAST] = {
[HASH_ALGO_TGR_128] = "tgr128",
[HASH_ALGO_TGR_160] = "tgr160",
[HASH_ALGO_TGR_192] = "tgr192",
+ [HASH_ALGO_SM3_256] = "sm3-256",
};
EXPORT_SYMBOL_GPL(hash_algo_name);
@@ -52,5 +53,6 @@ const int hash_digest_size[HASH_ALGO__LAST] = {
[HASH_ALGO_TGR_128] = TGR128_DIGEST_SIZE,
[HASH_ALGO_TGR_160] = TGR160_DIGEST_SIZE,
[HASH_ALGO_TGR_192] = TGR192_DIGEST_SIZE,
+ [HASH_ALGO_SM3_256] = SM3256_DIGEST_SIZE,
};
EXPORT_SYMBOL_GPL(hash_digest_size);
diff --git a/drivers/Makefile b/drivers/Makefile
index 795d0ca714bf..8f5d076baeb0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -106,7 +106,7 @@ obj-y += i2c/ media/
obj-$(CONFIG_PPS) += pps/
obj-$(CONFIG_PTP_1588_CLOCK) += ptp/
obj-$(CONFIG_W1) += w1/
-obj-$(CONFIG_POWER_SUPPLY) += power/
+obj-y += power/
obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_THERMAL) += thermal/
obj-$(CONFIG_WATCHDOG) += watchdog/
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index aa45d4802707..ad6d8c6b777e 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/ndctl.h>
+#include <linux/delay.h>
#include <linux/list.h>
#include <linux/acpi.h>
#include <linux/sort.h>
@@ -1473,6 +1474,201 @@ static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus,
/* devm will free nfit_blk */
}
+static int ars_get_cap(struct nvdimm_bus_descriptor *nd_desc,
+ struct nd_cmd_ars_cap *cmd, u64 addr, u64 length)
+{
+ cmd->address = addr;
+ cmd->length = length;
+
+ return nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
+ sizeof(*cmd));
+}
+
+static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
+ struct nd_cmd_ars_start *cmd, u64 addr, u64 length)
+{
+ int rc;
+
+ cmd->address = addr;
+ cmd->length = length;
+ cmd->type = ND_ARS_PERSISTENT;
+
+ while (1) {
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, cmd,
+ sizeof(*cmd));
+ if (rc)
+ return rc;
+ switch (cmd->status) {
+ case 0:
+ return 0;
+ case 1:
+ /* ARS unsupported, but we should never get here */
+ return 0;
+ case 2:
+ return -EINVAL;
+ case 3:
+ /* ARS is in progress */
+ msleep(1000);
+ break;
+ default:
+ return -ENXIO;
+ }
+ }
+}
+
+static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc,
+ struct nd_cmd_ars_status *cmd)
+{
+ int rc;
+
+ while (1) {
+ rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, cmd,
+ sizeof(*cmd));
+ if (rc || cmd->status & 0xffff)
+ return -ENXIO;
+
+ /* Check extended status (Upper two bytes) */
+ switch (cmd->status >> 16) {
+ case 0:
+ return 0;
+ case 1:
+ /* ARS is in progress */
+ msleep(1000);
+ break;
+ case 2:
+ /* No ARS performed for the current boot */
+ return 0;
+ default:
+ return -ENXIO;
+ }
+ }
+}
+
+static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
+ struct nd_cmd_ars_status *ars_status, u64 start)
+{
+ int rc;
+ u32 i;
+
+ /*
+ * The address field returned by ars_status should be either
+ * less than or equal to the address we last started ARS for.
+ * The (start, length) returned by ars_status should also have
+ * non-zero overlap with the range we started ARS for.
+ * If this is not the case, bail.
+ */
+ if (ars_status->address > start ||
+ (ars_status->address + ars_status->length < start))
+ return -ENXIO;
+
+ for (i = 0; i < ars_status->num_records; i++) {
+ rc = nvdimm_bus_add_poison(nvdimm_bus,
+ ars_status->records[i].err_address,
+ ars_status->records[i].length);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
+ struct nd_region_desc *ndr_desc)
+{
+ struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
+ struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
+ struct nd_cmd_ars_status *ars_status = NULL;
+ struct nd_cmd_ars_start *ars_start = NULL;
+ struct nd_cmd_ars_cap *ars_cap = NULL;
+ u64 start, len, cur, remaining;
+ int rc;
+
+ ars_cap = kzalloc(sizeof(*ars_cap), GFP_KERNEL);
+ if (!ars_cap)
+ return -ENOMEM;
+
+ start = ndr_desc->res->start;
+ len = ndr_desc->res->end - ndr_desc->res->start + 1;
+
+ rc = ars_get_cap(nd_desc, ars_cap, start, len);
+ if (rc)
+ goto out;
+
+ /*
+ * If ARS is unsupported, or if the 'Persistent Memory Scrub' flag in
+ * extended status is not set, skip this but continue initialization
+ */
+ if ((ars_cap->status & 0xffff) ||
+ !(ars_cap->status >> 16 & ND_ARS_PERSISTENT)) {
+ dev_warn(acpi_desc->dev,
+ "ARS unsupported (status: 0x%x), won't create an error list\n",
+ ars_cap->status);
+ goto out;
+ }
+
+ /*
+ * Check if a full-range ARS has been run. If so, use those results
+ * without having to start a new ARS.
+ */
+ ars_status = kzalloc(ars_cap->max_ars_out + sizeof(*ars_status),
+ GFP_KERNEL);
+ if (!ars_status) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = ars_get_status(nd_desc, ars_status);
+ if (rc)
+ goto out;
+
+ if (ars_status->address <= start &&
+ (ars_status->address + ars_status->length >= start + len)) {
+ rc = ars_status_process_records(nvdimm_bus, ars_status, start);
+ goto out;
+ }
+
+ /*
+ * ARS_STATUS can overflow if the number of poison entries found is
+ * greater than the maximum buffer size (ars_cap->max_ars_out)
+ * To detect overflow, check if the length field of ars_status
+ * is less than the length we supplied. If so, process the
+ * error entries we got, adjust the start point, and start again
+ */
+ ars_start = kzalloc(sizeof(*ars_start), GFP_KERNEL);
+ if (!ars_start)
+ return -ENOMEM;
+
+ cur = start;
+ remaining = len;
+ do {
+ u64 done, end;
+
+ rc = ars_do_start(nd_desc, ars_start, cur, remaining);
+ if (rc)
+ goto out;
+
+ rc = ars_get_status(nd_desc, ars_status);
+ if (rc)
+ goto out;
+
+ rc = ars_status_process_records(nvdimm_bus, ars_status, cur);
+ if (rc)
+ goto out;
+
+ end = min(cur + remaining,
+ ars_status->address + ars_status->length);
+ done = end - cur;
+ cur += done;
+ remaining -= done;
+ } while (remaining);
+
+ out:
+ kfree(ars_cap);
+ kfree(ars_start);
+ kfree(ars_status);
+ return rc;
+}
+
static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
struct acpi_nfit_memory_map *memdev,
@@ -1585,6 +1781,13 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
nvdimm_bus = acpi_desc->nvdimm_bus;
if (nfit_spa_type(spa) == NFIT_SPA_PM) {
+ rc = acpi_nfit_find_poison(acpi_desc, ndr_desc);
+ if (rc) {
+ dev_err(acpi_desc->dev,
+ "error while performing ARS to find poison: %d\n",
+ rc);
+ return rc;
+ }
if (!nvdimm_pmem_region_create(nvdimm_bus, ndr_desc))
return -ENOMEM;
} else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8524450e75bd..b9250e564ebf 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1118,15 +1118,17 @@ static int
_request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device, unsigned int opt_flags)
{
- struct firmware *fw;
+ struct firmware *fw = NULL;
long timeout;
int ret;
if (!firmware_p)
return -EINVAL;
- if (!name || name[0] == '\0')
- return -EINVAL;
+ if (!name || name[0] == '\0') {
+ ret = -EINVAL;
+ goto out;
+ }
ret = _request_firmware_prepare(&fw, name, device);
if (ret <= 0) /* error or already assigned */
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 25425d3f2575..213456c2b123 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -450,8 +450,7 @@ memory_probe_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
u64 phys_addr;
- int nid;
- int i, ret;
+ int nid, ret;
unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
ret = kstrtoull(buf, 0, &phys_addr);
@@ -461,15 +460,12 @@ memory_probe_store(struct device *dev, struct device_attribute *attr,
if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
return -EINVAL;
- for (i = 0; i < sections_per_block; i++) {
- nid = memory_add_physaddr_to_nid(phys_addr);
- ret = add_memory(nid, phys_addr,
- PAGES_PER_SECTION << PAGE_SHIFT);
- if (ret)
- goto out;
+ nid = memory_add_physaddr_to_nid(phys_addr);
+ ret = add_memory(nid, phys_addr,
+ MIN_MEMORY_BLOCK_SIZE * sections_per_block);
- phys_addr += MIN_MEMORY_BLOCK_SIZE;
- }
+ if (ret)
+ goto out;
ret = count;
out:
@@ -618,7 +614,6 @@ static int init_memory_block(struct memory_block **memory,
base_memory_block_id(scn_nr) * sections_per_block;
mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
mem->state = state;
- mem->section_count++;
start_pfn = section_nr_to_pfn(mem->start_section_nr);
mem->phys_device = arch_get_memory_phys_device(start_pfn);
@@ -652,6 +647,13 @@ static int add_memory_block(int base_section_nr)
return 0;
}
+static bool is_zone_device_section(struct mem_section *ms)
+{
+ struct page *page;
+
+ page = sparse_decode_mem_map(ms->section_mem_map, __section_nr(ms));
+ return is_zone_device_page(page);
+}
/*
* need an interface for the VM to add new memory regions,
@@ -662,6 +664,9 @@ int register_new_memory(int nid, struct mem_section *section)
int ret = 0;
struct memory_block *mem;
+ if (is_zone_device_section(section))
+ return 0;
+
mutex_lock(&mem_sysfs_mutex);
mem = find_memory_block(section);
@@ -672,6 +677,7 @@ int register_new_memory(int nid, struct mem_section *section)
ret = init_memory_block(&mem, section, MEM_OFFLINE);
if (ret)
goto out;
+ mem->section_count++;
}
if (mem->section_count == sections_per_block)
@@ -692,11 +698,14 @@ unregister_memory(struct memory_block *memory)
device_unregister(&memory->dev);
}
-static int remove_memory_block(unsigned long node_id,
+static int remove_memory_section(unsigned long node_id,
struct mem_section *section, int phys_device)
{
struct memory_block *mem;
+ if (is_zone_device_section(section))
+ return 0;
+
mutex_lock(&mem_sysfs_mutex);
mem = find_memory_block(section);
unregister_mem_sect_under_nodes(mem, __section_nr(section));
@@ -716,7 +725,7 @@ int unregister_memory_section(struct mem_section *section)
if (!present_section(section))
return -EINVAL;
- return remove_memory_block(0, section, 0);
+ return remove_memory_section(0, section, 0);
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 504899a72966..98067f757fb0 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -17,14 +17,9 @@
#define BCMA_GPIO_MAX_PINS 32
-static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
-{
- return container_of(chip, struct bcma_drv_cc, gpio);
-}
-
static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
return !!bcma_chipco_gpio_in(cc, 1 << gpio);
}
@@ -32,14 +27,14 @@ static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
}
static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_outen(cc, 1 << gpio, 0);
return 0;
@@ -48,7 +43,7 @@ static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio);
bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
@@ -57,7 +52,7 @@ static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_control(cc, 1 << gpio, 0);
/* clear pulldown */
@@ -70,7 +65,7 @@ static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
/* clear pullup */
bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
@@ -81,7 +76,7 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
static void bcma_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(gc);
+ struct bcma_drv_cc *cc = gpiochip_get_data(gc);
int gpio = irqd_to_hwirq(d);
u32 val = bcma_chipco_gpio_in(cc, BIT(gpio));
@@ -92,7 +87,7 @@ static void bcma_gpio_irq_unmask(struct irq_data *d)
static void bcma_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(gc);
+ struct bcma_drv_cc *cc = gpiochip_get_data(gc);
int gpio = irqd_to_hwirq(d);
bcma_chipco_gpio_intmask(cc, BIT(gpio), 0);
@@ -188,7 +183,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
chip->direction_input = bcma_gpio_direction_input;
chip->direction_output = bcma_gpio_direction_output;
chip->owner = THIS_MODULE;
- chip->dev = bcma_bus_get_host_dev(bus);
+ chip->parent = bcma_bus_get_host_dev(bus);
#if IS_BUILTIN(CONFIG_OF)
if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
chip->of_node = cc->core->dev.of_node;
@@ -216,7 +211,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
else
chip->base = -1;
- err = gpiochip_add(chip);
+ err = gpiochip_add_data(chip, cc);
if (err)
return err;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index a5880f4ab40e..cb27190e9f39 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -19,6 +19,9 @@
#include <linux/radix-tree.h>
#include <linux/fs.h>
#include <linux/slab.h>
+#ifdef CONFIG_BLK_DEV_RAM_DAX
+#include <linux/pfn_t.h>
+#endif
#include <asm/uaccess.h>
@@ -378,7 +381,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
#ifdef CONFIG_BLK_DEV_RAM_DAX
static long brd_direct_access(struct block_device *bdev, sector_t sector,
- void __pmem **kaddr, unsigned long *pfn)
+ void __pmem **kaddr, pfn_t *pfn)
{
struct brd_device *brd = bdev->bd_disk->private_data;
struct page *page;
@@ -389,7 +392,7 @@ static long brd_direct_access(struct block_device *bdev, sector_t sector,
if (!page)
return -ENOSPC;
*kaddr = (void __pmem *)page_address(page);
- *pfn = page_to_pfn(page);
+ *pfn = page_to_pfn_t(page);
return PAGE_SIZE;
}
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index b38bd06d564c..63c2064689f8 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -3848,7 +3848,7 @@ static void print_cfg_table(ctlr_info_t *h)
readl(&(tb->HostWrite.CoalIntDelay)));
dev_dbg(&h->pdev->dev, " Coalesce Interrupt Count = 0x%x\n",
readl(&(tb->HostWrite.CoalIntCount)));
- dev_dbg(&h->pdev->dev, " Max outstanding commands = 0x%d\n",
+ dev_dbg(&h->pdev->dev, " Max outstanding commands = 0x%x\n",
readl(&(tb->CmdsOutMax)));
dev_dbg(&h->pdev->dev, " Bus Types = 0x%x\n",
readl(&(tb->BusTypes)));
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 331363e7de0f..9e251201dd48 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3585,7 +3585,7 @@ static void __init config_types(void)
unsigned int type = UDP->cmos;
struct floppy_drive_params *params;
const char *name = NULL;
- static char temparea[32];
+ char temparea[32];
if (type < ARRAY_SIZE(default_drive_params)) {
params = &default_drive_params[type].params;
@@ -3596,7 +3596,8 @@ static void __init config_types(void)
allowed_drive_mask &= ~(1 << drive);
} else {
params = &default_drive_params[0].params;
- sprintf(temparea, "unknown type %d (usb?)", type);
+ snprintf(temparea, sizeof(temparea),
+ "unknown type %d (usb?)", type);
name = temparea;
}
if (name) {
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 34997d8ecd64..15bec407ac37 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -173,7 +173,7 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
{
struct request *rq;
- rq = blk_mq_alloc_request(dd->queue, 0, __GFP_RECLAIM, true);
+ rq = blk_mq_alloc_request(dd->queue, 0, BLK_MQ_REQ_RESERVED);
return blk_mq_rq_to_pdu(rq);
}
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 09e3c0d87ecc..95dff91135ad 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -449,7 +449,7 @@ static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
struct request *rq;
struct bio *bio = rqd->bio;
- rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0);
+ rq = blk_mq_alloc_request(q, bio_rw(bio), 0);
if (IS_ERR(rq))
return -ENOMEM;
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 5cb13ca3a3ac..3ef42e563bb5 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -74,18 +74,18 @@ static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
* allocate new zcomp_strm structure with ->private initialized by
* backend, return NULL on error
*/
-static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
+static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp, gfp_t flags)
{
- struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL);
+ struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), flags);
if (!zstrm)
return NULL;
- zstrm->private = comp->backend->create();
+ zstrm->private = comp->backend->create(flags);
/*
* allocate 2 pages. 1 for compressed data, plus 1 extra for the
* case when compressed size is larger than the original one
*/
- zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+ zstrm->buffer = (void *)__get_free_pages(flags | __GFP_ZERO, 1);
if (!zstrm->private || !zstrm->buffer) {
zcomp_strm_free(comp, zstrm);
zstrm = NULL;
@@ -120,8 +120,16 @@ static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp)
/* allocate new zstrm stream */
zs->avail_strm++;
spin_unlock(&zs->strm_lock);
-
- zstrm = zcomp_strm_alloc(comp);
+ /*
+ * This function can be called in swapout/fs write path
+ * so we can't use GFP_FS|IO. And it assumes we already
+ * have at least one stream in zram initialization so we
+ * don't do best effort to allocate more stream in here.
+ * A default stream will work well without further multiple
+ * streams. That's why we use NORETRY | NOWARN.
+ */
+ zstrm = zcomp_strm_alloc(comp, GFP_NOIO | __GFP_NORETRY |
+ __GFP_NOWARN);
if (!zstrm) {
spin_lock(&zs->strm_lock);
zs->avail_strm--;
@@ -209,7 +217,7 @@ static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm)
zs->max_strm = max_strm;
zs->avail_strm = 1;
- zstrm = zcomp_strm_alloc(comp);
+ zstrm = zcomp_strm_alloc(comp, GFP_KERNEL);
if (!zstrm) {
kfree(zs);
return -ENOMEM;
@@ -259,7 +267,7 @@ static int zcomp_strm_single_create(struct zcomp *comp)
comp->stream = zs;
mutex_init(&zs->strm_lock);
- zs->zstrm = zcomp_strm_alloc(comp);
+ zs->zstrm = zcomp_strm_alloc(comp, GFP_KERNEL);
if (!zs->zstrm) {
kfree(zs);
return -ENOMEM;
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 46e2b9f8f1f0..b7d2a4bcae54 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -33,7 +33,7 @@ struct zcomp_backend {
int (*decompress)(const unsigned char *src, size_t src_len,
unsigned char *dst);
- void *(*create)(void);
+ void *(*create)(gfp_t flags);
void (*destroy)(void *private);
const char *name;
diff --git a/drivers/block/zram/zcomp_lz4.c b/drivers/block/zram/zcomp_lz4.c
index f2afb7e988c3..0110086accba 100644
--- a/drivers/block/zram/zcomp_lz4.c
+++ b/drivers/block/zram/zcomp_lz4.c
@@ -10,17 +10,26 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/lz4.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
#include "zcomp_lz4.h"
-static void *zcomp_lz4_create(void)
+static void *zcomp_lz4_create(gfp_t flags)
{
- return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
+ void *ret;
+
+ ret = kmalloc(LZ4_MEM_COMPRESS, flags);
+ if (!ret)
+ ret = __vmalloc(LZ4_MEM_COMPRESS,
+ flags | __GFP_HIGHMEM,
+ PAGE_KERNEL);
+ return ret;
}
static void zcomp_lz4_destroy(void *private)
{
- kfree(private);
+ kvfree(private);
}
static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst,
diff --git a/drivers/block/zram/zcomp_lzo.c b/drivers/block/zram/zcomp_lzo.c
index da1bc47d588e..ed7a1f0549ec 100644
--- a/drivers/block/zram/zcomp_lzo.c
+++ b/drivers/block/zram/zcomp_lzo.c
@@ -10,17 +10,26 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/lzo.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
#include "zcomp_lzo.h"
-static void *lzo_create(void)
+static void *lzo_create(gfp_t flags)
{
- return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ void *ret;
+
+ ret = kmalloc(LZO1X_MEM_COMPRESS, flags);
+ if (!ret)
+ ret = __vmalloc(LZO1X_MEM_COMPRESS,
+ flags | __GFP_HIGHMEM,
+ PAGE_KERNEL);
+ return ret;
}
static void lzo_destroy(void *private)
{
- kfree(private);
+ kvfree(private);
}
static int lzo_compress(const unsigned char *src, unsigned char *dst,
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 47915d736f8d..370c2f76016d 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1325,7 +1325,6 @@ static int zram_remove(struct zram *zram)
pr_info("Removed device: %s\n", zram->disk->disk_name);
- idr_remove(&zram_index_idr, zram->disk->first_minor);
blk_cleanup_queue(zram->disk->queue);
del_gendisk(zram->disk);
put_disk(zram->disk);
@@ -1367,10 +1366,12 @@ static ssize_t hot_remove_store(struct class *class,
mutex_lock(&zram_index_mutex);
zram = idr_find(&zram_index_idr, dev_id);
- if (zram)
+ if (zram) {
ret = zram_remove(zram);
- else
+ idr_remove(&zram_index_idr, dev_id);
+ } else {
ret = -ENODEV;
+ }
mutex_unlock(&zram_index_mutex);
return ret ? ret : count;
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 116b363b7987..129d47bcc5fc 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -131,6 +131,14 @@ config SUNXI_RSB
with various RSB based devices, such as AXP223, AXP8XX PMICs,
and AC100/AC200 ICs.
+config UNIPHIER_SYSTEM_BUS
+ bool "UniPhier System Bus driver"
+ depends on ARCH_UNIPHIER && OF
+ default y
+ help
+ Support for UniPhier System Bus, a simple external bus. This is
+ needed to use on-board devices connected to UniPhier SoCs.
+
config VEXPRESS_CONFIG
bool "Versatile Express configuration bus"
default y if ARCH_VEXPRESS
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index fcb9f9794a1f..ccff007ee7e8 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
+obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
diff --git a/drivers/bus/uniphier-system-bus.c b/drivers/bus/uniphier-system-bus.c
new file mode 100644
index 000000000000..834a2aeaf27a
--- /dev/null
+++ b/drivers/bus/uniphier-system-bus.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+/* System Bus Controller registers */
+#define UNIPHIER_SBC_BASE 0x100 /* base address of bank0 space */
+#define UNIPHIER_SBC_BASE_BE BIT(0) /* bank_enable */
+#define UNIPHIER_SBC_CTRL0 0x200 /* timing parameter 0 of bank0 */
+#define UNIPHIER_SBC_CTRL1 0x204 /* timing parameter 1 of bank0 */
+#define UNIPHIER_SBC_CTRL2 0x208 /* timing parameter 2 of bank0 */
+#define UNIPHIER_SBC_CTRL3 0x20c /* timing parameter 3 of bank0 */
+#define UNIPHIER_SBC_CTRL4 0x300 /* timing parameter 4 of bank0 */
+
+#define UNIPHIER_SBC_STRIDE 0x10 /* register stride to next bank */
+#define UNIPHIER_SBC_NR_BANKS 8 /* number of banks (chip select) */
+#define UNIPHIER_SBC_BASE_DUMMY 0xffffffff /* data to squash bank 0, 1 */
+
+struct uniphier_system_bus_bank {
+ u32 base;
+ u32 end;
+};
+
+struct uniphier_system_bus_priv {
+ struct device *dev;
+ void __iomem *membase;
+ struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];
+};
+
+static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,
+ int bank, u32 addr, u64 paddr, u32 size)
+{
+ u64 end, mask;
+
+ dev_dbg(priv->dev,
+ "range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
+ bank, addr, paddr, size);
+
+ if (bank >= ARRAY_SIZE(priv->bank)) {
+ dev_err(priv->dev, "unsupported bank number %d\n", bank);
+ return -EINVAL;
+ }
+
+ if (priv->bank[bank].base || priv->bank[bank].end) {
+ dev_err(priv->dev,
+ "range for bank %d has already been specified\n", bank);
+ return -EINVAL;
+ }
+
+ if (paddr > U32_MAX) {
+ dev_err(priv->dev, "base address %llx is too high\n", paddr);
+ return -EINVAL;
+ }
+
+ end = paddr + size;
+
+ if (addr > paddr) {
+ dev_err(priv->dev,
+ "base %08x cannot be mapped to %08llx of parent\n",
+ addr, paddr);
+ return -EINVAL;
+ }
+ paddr -= addr;
+
+ paddr = round_down(paddr, 0x00020000);
+ end = round_up(end, 0x00020000);
+
+ if (end > U32_MAX) {
+ dev_err(priv->dev, "end address %08llx is too high\n", end);
+ return -EINVAL;
+ }
+ mask = paddr ^ (end - 1);
+ mask = roundup_pow_of_two(mask);
+
+ paddr = round_down(paddr, mask);
+ end = round_up(end, mask);
+
+ priv->bank[bank].base = paddr;
+ priv->bank[bank].end = end;
+
+ dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n",
+ bank, priv->bank[bank].base, priv->bank[bank].end);
+
+ return 0;
+}
+
+static int uniphier_system_bus_check_overlap(
+ const struct uniphier_system_bus_priv *priv)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
+ for (j = i + 1; j < ARRAY_SIZE(priv->bank); j++) {
+ if (priv->bank[i].end > priv->bank[j].base ||
+ priv->bank[i].base < priv->bank[j].end) {
+ dev_err(priv->dev,
+ "region overlap between bank%d and bank%d\n",
+ i, j);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void uniphier_system_bus_check_boot_swap(
+ struct uniphier_system_bus_priv *priv)
+{
+ void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
+ int is_swapped;
+
+ is_swapped = !(readl(base_reg) & UNIPHIER_SBC_BASE_BE);
+
+ dev_dbg(priv->dev, "Boot Swap: %s\n", is_swapped ? "on" : "off");
+
+ /*
+ * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are
+ * swapped. In this case, bank0 and bank1 should be swapped as well.
+ */
+ if (is_swapped)
+ swap(priv->bank[0], priv->bank[1]);
+}
+
+static void uniphier_system_bus_set_reg(
+ const struct uniphier_system_bus_priv *priv)
+{
+ void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
+ u32 base, end, mask, val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
+ base = priv->bank[i].base;
+ end = priv->bank[i].end;
+
+ if (base == end) {
+ /*
+ * If SBC_BASE0 or SBC_BASE1 is set to zero, the access
+ * to anywhere in the system bus space is routed to
+ * bank 0 (if boot swap if off) or bank 1 (if boot swap
+ * if on). It means that CPUs cannot get access to
+ * bank 2 or later. In other words, bank 0/1 cannot
+ * be disabled even if its bank_enable bits is cleared.
+ * This seems odd, but it is how this hardware goes.
+ * As a workaround, dummy data (0xffffffff) should be
+ * set when the bank 0/1 is unused. As for bank 2 and
+ * later, they can be simply disable by clearing the
+ * bank_enable bit.
+ */
+ if (i < 2)
+ val = UNIPHIER_SBC_BASE_DUMMY;
+ else
+ val = 0;
+ } else {
+ mask = base ^ (end - 1);
+
+ val = base & 0xfffe0000;
+ val |= (~mask >> 16) & 0xfffe;
+ val |= UNIPHIER_SBC_BASE_BE;
+ }
+ dev_dbg(priv->dev, "SBC_BASE[%d] = 0x%08x\n", i, val);
+
+ writel(val, base_reg + UNIPHIER_SBC_STRIDE * i);
+ }
+}
+
+static int uniphier_system_bus_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_system_bus_priv *priv;
+ struct resource *regs;
+ const __be32 *ranges;
+ u32 cells, addr, size;
+ u64 paddr;
+ int pna, bank, rlen, rone, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->membase = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
+
+ priv->dev = dev;
+
+ pna = of_n_addr_cells(dev->of_node);
+
+ ret = of_property_read_u32(dev->of_node, "#address-cells", &cells);
+ if (ret) {
+ dev_err(dev, "failed to get #address-cells\n");
+ return ret;
+ }
+ if (cells != 2) {
+ dev_err(dev, "#address-cells must be 2\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "#size-cells", &cells);
+ if (ret) {
+ dev_err(dev, "failed to get #size-cells\n");
+ return ret;
+ }
+ if (cells != 1) {
+ dev_err(dev, "#size-cells must be 1\n");
+ return -EINVAL;
+ }
+
+ ranges = of_get_property(dev->of_node, "ranges", &rlen);
+ if (!ranges) {
+ dev_err(dev, "failed to get ranges property\n");
+ return -ENOENT;
+ }
+
+ rlen /= sizeof(*ranges);
+ rone = pna + 2;
+
+ for (; rlen >= rone; rlen -= rone) {
+ bank = be32_to_cpup(ranges++);
+ addr = be32_to_cpup(ranges++);
+ paddr = of_translate_address(dev->of_node, ranges);
+ if (paddr == OF_BAD_ADDR)
+ return -EINVAL;
+ ranges += pna;
+ size = be32_to_cpup(ranges++);
+
+ ret = uniphier_system_bus_add_bank(priv, bank, addr,
+ paddr, size);
+ if (ret)
+ return ret;
+ }
+
+ ret = uniphier_system_bus_check_overlap(priv);
+ if (ret)
+ return ret;
+
+ uniphier_system_bus_check_boot_swap(priv);
+
+ uniphier_system_bus_set_reg(priv);
+
+ /* Now, the bus is configured. Populate platform_devices below it */
+ return of_platform_populate(dev->of_node, of_default_bus_match_table,
+ NULL, dev);
+}
+
+static const struct of_device_id uniphier_system_bus_match[] = {
+ { .compatible = "socionext,uniphier-system-bus" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_system_bus_match);
+
+static struct platform_driver uniphier_system_bus_driver = {
+ .probe = uniphier_system_bus_probe,
+ .driver = {
+ .name = "uniphier-system-bus",
+ .of_match_table = uniphier_system_bus_match,
+ },
+};
+module_platform_driver(uniphier_system_bus_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier System Bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index e3536da05c88..94fb407d8561 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -472,9 +472,10 @@ static DEFINE_MUTEX(smi_watchers_mutex);
#define ipmi_get_stat(intf, stat) \
((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat]))
-static char *addr_src_to_str[] = { "invalid", "hotmod", "hardcoded", "SPMI",
- "ACPI", "SMBIOS", "PCI",
- "device-tree", "default" };
+static const char * const addr_src_to_str[] = {
+ "invalid", "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI",
+ "device-tree", "default"
+};
const char *ipmi_addr_src_to_str(enum ipmi_addr_src src)
{
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 4cc72fa017c7..9fda22e3387e 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -105,7 +105,8 @@ enum si_intf_state {
enum si_type {
SI_KCS, SI_SMIC, SI_BT
};
-static char *si_to_str[] = { "kcs", "smic", "bt" };
+
+static const char * const si_to_str[] = { "kcs", "smic", "bt" };
#define DEVICE_NAME "ipmi_si"
@@ -1341,7 +1342,7 @@ static unsigned int num_slave_addrs;
#define IPMI_IO_ADDR_SPACE 0
#define IPMI_MEM_ADDR_SPACE 1
-static char *addr_space_to_str[] = { "i/o", "mem" };
+static const char * const addr_space_to_str[] = { "i/o", "mem" };
static int hotmod_handler(const char *val, struct kernel_param *kp);
@@ -1723,27 +1724,31 @@ static int mem_setup(struct smi_info *info)
*/
enum hotmod_op { HM_ADD, HM_REMOVE };
struct hotmod_vals {
- char *name;
- int val;
+ const char *name;
+ const int val;
};
-static struct hotmod_vals hotmod_ops[] = {
+
+static const struct hotmod_vals hotmod_ops[] = {
{ "add", HM_ADD },
{ "remove", HM_REMOVE },
{ NULL }
};
-static struct hotmod_vals hotmod_si[] = {
+
+static const struct hotmod_vals hotmod_si[] = {
{ "kcs", SI_KCS },
{ "smic", SI_SMIC },
{ "bt", SI_BT },
{ NULL }
};
-static struct hotmod_vals hotmod_as[] = {
+
+static const struct hotmod_vals hotmod_as[] = {
{ "mem", IPMI_MEM_ADDR_SPACE },
{ "i/o", IPMI_IO_ADDR_SPACE },
{ NULL }
};
-static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
+static int parse_str(const struct hotmod_vals *v, int *val, char *name,
+ char **curr)
{
char *s;
int i;
@@ -2554,7 +2559,6 @@ static void ipmi_pci_remove(struct pci_dev *pdev)
{
struct smi_info *info = pci_get_drvdata(pdev);
cleanup_one_si(info);
- pci_disable_device(pdev);
}
static const struct pci_device_id ipmi_pci_devices[] = {
@@ -2870,7 +2874,7 @@ static int ipmi_parisc_remove(struct parisc_device *dev)
return 0;
}
-static struct parisc_device_id ipmi_parisc_tbl[] = {
+static const struct parisc_device_id ipmi_parisc_tbl[] = {
{ HPHW_MC, HVERSION_REV_ANY_ID, 0x004, 0xC0 },
{ 0, }
};
@@ -3444,8 +3448,8 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
static const struct ipmi_default_vals
{
- int type;
- int port;
+ const int type;
+ const int port;
} ipmi_defaults[] =
{
{ .type = SI_KCS, .port = 0xca2 },
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 90e624662257..5f1c3d08ba65 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -1959,7 +1959,6 @@ MODULE_DEVICE_TABLE(i2c, ssif_id);
static struct i2c_driver ssif_i2c_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
- .owner = THIS_MODULE,
.name = DEVICE_NAME
},
.probe = ssif_probe,
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 60316fbaf295..9b9809b709a5 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -71,7 +71,7 @@ static int raw_open(struct inode *inode, struct file *filp)
err = -ENODEV;
if (!bdev)
goto out;
- igrab(bdev->bd_inode);
+ bdgrab(bdev);
err = blkdev_get(bdev, filp->f_mode | FMODE_EXCL, raw_open);
if (err)
goto out;
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index c50637db3a8a..e2fa89c88304 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -310,10 +310,12 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
{
int duration_idx = TPM_UNDEFINED;
int duration = 0;
- u8 category = (ordinal >> 24) & 0xFF;
- if ((category == TPM_PROTECTED_COMMAND && ordinal < TPM_MAX_ORDINAL) ||
- (category == TPM_CONNECTION_COMMAND && ordinal < TSC_MAX_ORDINAL))
+ /*
+ * We only have a duration table for protected commands, where the upper
+ * 16 bits are 0. For the few other ordinals the fallback will be used.
+ */
+ if (ordinal < TPM_MAX_ORDINAL)
duration_idx = tpm_ordinal_duration[ordinal];
if (duration_idx != TPM_UNDEFINED)
@@ -501,6 +503,21 @@ int tpm_get_timeouts(struct tpm_chip *chip)
struct duration_t *duration_cap;
ssize_t rc;
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ /* Fixed timeouts for TPM2 */
+ chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
+ chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
+ chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
+ chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
+ chip->vendor.duration[TPM_SHORT] =
+ msecs_to_jiffies(TPM2_DURATION_SHORT);
+ chip->vendor.duration[TPM_MEDIUM] =
+ msecs_to_jiffies(TPM2_DURATION_MEDIUM);
+ chip->vendor.duration[TPM_LONG] =
+ msecs_to_jiffies(TPM2_DURATION_LONG);
+ return 0;
+ }
+
tpm_cmd.header.in = tpm_getcap_header;
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index a4257a32964f..542a80cbfd9c 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -83,16 +83,20 @@ enum tpm2_structures {
};
enum tpm2_return_codes {
- TPM2_RC_INITIALIZE = 0x0100,
- TPM2_RC_TESTING = 0x090A,
+ TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
+ TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
TPM2_RC_DISABLED = 0x0120,
+ TPM2_RC_TESTING = 0x090A, /* RC_WARN */
};
enum tpm2_algorithms {
TPM2_ALG_SHA1 = 0x0004,
TPM2_ALG_KEYEDHASH = 0x0008,
TPM2_ALG_SHA256 = 0x000B,
- TPM2_ALG_NULL = 0x0010
+ TPM2_ALG_SHA384 = 0x000C,
+ TPM2_ALG_SHA512 = 0x000D,
+ TPM2_ALG_NULL = 0x0010,
+ TPM2_ALG_SM3_256 = 0x0012,
};
enum tpm2_command_codes {
@@ -138,7 +142,6 @@ struct tpm_vendor_specific {
unsigned long base; /* TPM base address */
int irq;
- int probed_irq;
int region_size;
int have_region;
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index c12130485fc1..45a634016f95 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -16,6 +16,7 @@
*/
#include "tpm.h"
+#include <crypto/hash_info.h>
#include <keys/trusted-type.h>
enum tpm2_object_attributes {
@@ -104,6 +105,19 @@ struct tpm2_cmd {
union tpm2_cmd_params params;
} __packed;
+struct tpm2_hash {
+ unsigned int crypto_id;
+ unsigned int tpm_id;
+};
+
+static struct tpm2_hash tpm2_hash_map[] = {
+ {HASH_ALGO_SHA1, TPM2_ALG_SHA1},
+ {HASH_ALGO_SHA256, TPM2_ALG_SHA256},
+ {HASH_ALGO_SHA384, TPM2_ALG_SHA384},
+ {HASH_ALGO_SHA512, TPM2_ALG_SHA512},
+ {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
+};
+
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The values
@@ -429,8 +443,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
{
unsigned int blob_len;
struct tpm_buf buf;
+ u32 hash;
+ int i;
int rc;
+ for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+ if (options->hash == tpm2_hash_map[i].crypto_id) {
+ hash = tpm2_hash_map[i].tpm_id;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(tpm2_hash_map))
+ return -EINVAL;
+
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
if (rc)
return rc;
@@ -452,12 +478,26 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
tpm_buf_append_u8(&buf, payload->migratable);
/* public */
- tpm_buf_append_u16(&buf, 14);
+ if (options->policydigest)
+ tpm_buf_append_u16(&buf, 14 + options->digest_len);
+ else
+ tpm_buf_append_u16(&buf, 14);
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
- tpm_buf_append_u16(&buf, TPM2_ALG_SHA256);
- tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
- tpm_buf_append_u16(&buf, 0); /* policy digest size */
+ tpm_buf_append_u16(&buf, hash);
+
+ /* policy */
+ if (options->policydigest) {
+ tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u16(&buf, options->digest_len);
+ tpm_buf_append(&buf, options->policydigest,
+ options->digest_len);
+ } else {
+ tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
+ tpm_buf_append_u16(&buf, 0);
+ }
+
+ /* public parameters */
tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
tpm_buf_append_u16(&buf, 0);
@@ -488,8 +528,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
out:
tpm_buf_destroy(&buf);
- if (rc > 0)
- rc = -EPERM;
+ if (rc > 0) {
+ if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH)
+ rc = -EINVAL;
+ else
+ rc = -EPERM;
+ }
return rc;
}
@@ -583,7 +627,9 @@ static int tpm2_unseal(struct tpm_chip *chip,
return rc;
tpm_buf_append_u32(&buf, blob_handle);
- tpm2_buf_append_auth(&buf, TPM2_RS_PW,
+ tpm2_buf_append_auth(&buf,
+ options->policyhandle ?
+ options->policyhandle : TPM2_RS_PW,
NULL /* nonce */, 0,
0 /* session_attributes */,
options->blobauth /* hmac */,
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 4bb9727c1047..8342cf51ffdc 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -284,17 +284,9 @@ static int crb_acpi_add(struct acpi_device *device)
chip->vendor.priv = priv;
- /* Default timeouts and durations */
- chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
- chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
- chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
- chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
- chip->vendor.duration[TPM_SHORT] =
- msecs_to_jiffies(TPM2_DURATION_SHORT);
- chip->vendor.duration[TPM_MEDIUM] =
- msecs_to_jiffies(TPM2_DURATION_MEDIUM);
- chip->vendor.duration[TPM_LONG] =
- msecs_to_jiffies(TPM2_DURATION_LONG);
+ rc = tpm_get_timeouts(chip);
+ if (rc)
+ return rc;
chip->acpi_dev_handle = device->handle;
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index 3e6a22658b63..b0a9a9e34241 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -90,7 +90,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return 0;
}
- sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
+ sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
if (sig)
return -EINTR;
@@ -125,7 +125,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
struct ibmvtpm_dev *ibmvtpm;
struct ibmvtpm_crq crq;
__be64 *word = (__be64 *)&crq;
- int rc;
+ int rc, sig;
ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
@@ -141,18 +141,35 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
return -EIO;
}
+ if (ibmvtpm->tpm_processing_cmd) {
+ dev_info(ibmvtpm->dev,
+ "Need to wait for TPM to finish\n");
+ /* wait for previous command to finish */
+ sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
+ if (sig)
+ return -EINTR;
+ }
+
spin_lock(&ibmvtpm->rtce_lock);
+ ibmvtpm->res_len = 0;
memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_TPM_COMMAND;
crq.len = cpu_to_be16(count);
crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
+ /*
+ * set the processing flag before the Hcall, since we may get the
+ * result (interrupt) before even being able to check rc.
+ */
+ ibmvtpm->tpm_processing_cmd = true;
+
rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
be64_to_cpu(word[1]));
if (rc != H_SUCCESS) {
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
rc = 0;
+ ibmvtpm->tpm_processing_cmd = false;
} else
rc = count;
@@ -515,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
case VTPM_TPM_COMMAND_RES:
/* len of the data in rtce buffer */
ibmvtpm->res_len = be16_to_cpu(crq->len);
+ ibmvtpm->tpm_processing_cmd = false;
wake_up_interruptible(&ibmvtpm->wq);
return;
default:
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
index 6af92890518f..91dfe766d080 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.h
+++ b/drivers/char/tpm/tpm_ibmvtpm.h
@@ -45,6 +45,7 @@ struct ibmvtpm_dev {
wait_queue_head_t wq;
u16 res_len;
u32 vtpm_version;
+ bool tpm_processing_cmd;
};
#define CRQ_RES_BUF_SIZE PAGE_SIZE
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 65f7eecc45b0..8a3509cb10da 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -401,7 +401,7 @@ static void disable_interrupts(struct tpm_chip *chip)
iowrite32(intmask,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
- free_irq(chip->vendor.irq, chip);
+ devm_free_irq(chip->pdev, chip->vendor.irq, chip);
chip->vendor.irq = 0;
}
@@ -461,11 +461,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
chip->vendor.irq = irq;
if (!priv->irq_tested)
msleep(1);
- if (!priv->irq_tested) {
+ if (!priv->irq_tested)
disable_interrupts(chip);
- dev_err(chip->pdev,
- FW_BUG "TPM interrupt not working, polling instead\n");
- }
priv->irq_tested = true;
return rc;
}
@@ -570,26 +567,6 @@ static const struct tpm_class_ops tpm_tis = {
.req_canceled = tpm_tis_req_canceled,
};
-static irqreturn_t tis_int_probe(int irq, void *dev_id)
-{
- struct tpm_chip *chip = dev_id;
- u32 interrupt;
-
- interrupt = ioread32(chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality));
-
- if (interrupt == 0)
- return IRQ_NONE;
-
- chip->vendor.probed_irq = irq;
-
- /* Clear interrupts handled with TPM_EOI */
- iowrite32(interrupt,
- chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality));
- return IRQ_HANDLED;
-}
-
static irqreturn_t tis_int_handler(int dummy, void *dev_id)
{
struct tpm_chip *chip = dev_id;
@@ -622,6 +599,84 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
return IRQ_HANDLED;
}
+/* Register the IRQ and issue a command that will cause an interrupt. If an
+ * irq is seen then leave the chip setup for IRQ operation, otherwise reverse
+ * everything and leave in polling mode. Returns 0 on success.
+ */
+static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
+ int flags, int irq)
+{
+ struct priv_data *priv = chip->vendor.priv;
+ u8 original_int_vec;
+
+ if (devm_request_irq(chip->pdev, irq, tis_int_handler, flags,
+ chip->devname, chip) != 0) {
+ dev_info(chip->pdev, "Unable to request irq: %d for probe\n",
+ irq);
+ return -1;
+ }
+ chip->vendor.irq = irq;
+
+ original_int_vec = ioread8(chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
+ iowrite8(irq,
+ chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality));
+
+ /* Clear all existing */
+ iowrite32(ioread32(chip->vendor.iobase +
+ TPM_INT_STATUS(chip->vendor.locality)),
+ chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
+
+ /* Turn on */
+ iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
+ chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+
+ priv->irq_tested = false;
+
+ /* Generate an interrupt by having the core call through to
+ * tpm_tis_send
+ */
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ tpm2_gen_interrupt(chip);
+ else
+ tpm_gen_interrupt(chip);
+
+ /* tpm_tis_send will either confirm the interrupt is working or it
+ * will call disable_irq which undoes all of the above.
+ */
+ if (!chip->vendor.irq) {
+ iowrite8(original_int_vec,
+ chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
+ * do not have ACPI/etc. We typically expect the interrupt to be declared if
+ * present.
+ */
+static void tpm_tis_probe_irq(struct tpm_chip *chip, u32 intmask)
+{
+ u8 original_int_vec;
+ int i;
+
+ original_int_vec = ioread8(chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
+
+ if (!original_int_vec) {
+ if (IS_ENABLED(CONFIG_X86))
+ for (i = 3; i <= 15; i++)
+ if (!tpm_tis_probe_irq_single(chip, intmask, 0,
+ i))
+ return;
+ } else if (!tpm_tis_probe_irq_single(chip, intmask, 0,
+ original_int_vec))
+ return;
+}
+
static bool interrupts = true;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
@@ -644,8 +699,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
acpi_handle acpi_dev_handle)
{
u32 vendor, intfcaps, intmask;
- int rc, i, irq_s, irq_e, probe;
- int irq_r = -1;
+ int rc, probe;
struct tpm_chip *chip;
struct priv_data *priv;
@@ -677,6 +731,15 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
goto out_err;
}
+ /* Take control of the TPM's interrupt hardware and shut it off */
+ intmask = ioread32(chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
+ TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
+ intmask &= ~TPM_GLOBAL_INT_ENABLE;
+ iowrite32(intmask,
+ chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+
if (request_locality(chip, 0) != 0) {
rc = -ENODEV;
goto out_err;
@@ -731,126 +794,31 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
dev_dbg(dev, "\tData Avail Int Support\n");
+ /* Very early on issue a command to the TPM in polling mode to make
+ * sure it works. May as well use that command to set the proper
+ * timeouts for the driver.
+ */
+ if (tpm_get_timeouts(chip)) {
+ dev_err(dev, "Could not get TPM timeouts and durations\n");
+ rc = -ENODEV;
+ goto out_err;
+ }
+
/* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
-
- intmask =
- ioread32(chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.locality));
-
- intmask |= TPM_INTF_CMD_READY_INT
- | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
- | TPM_INTF_STS_VALID_INT;
-
- iowrite32(intmask,
- chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.locality));
- if (interrupts)
- chip->vendor.irq = tpm_info->irq;
- if (interrupts && !chip->vendor.irq) {
- irq_s =
- ioread8(chip->vendor.iobase +
- TPM_INT_VECTOR(chip->vendor.locality));
- irq_r = irq_s;
- if (irq_s) {
- irq_e = irq_s;
- } else {
- irq_s = 3;
- irq_e = 15;
- }
-
- for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
- iowrite8(i, chip->vendor.iobase +
- TPM_INT_VECTOR(chip->vendor.locality));
- if (devm_request_irq
- (dev, i, tis_int_probe, IRQF_SHARED,
- chip->devname, chip) != 0) {
- dev_info(chip->pdev,
- "Unable to request irq: %d for probe\n",
- i);
- continue;
- }
-
- /* Clear all existing */
- iowrite32(ioread32
- (chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality)),
- chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality));
-
- /* Turn on */
- iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
- chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.locality));
-
- chip->vendor.probed_irq = 0;
-
- /* Generate Interrupts */
- if (chip->flags & TPM_CHIP_FLAG_TPM2)
- tpm2_gen_interrupt(chip);
- else
- tpm_gen_interrupt(chip);
-
- chip->vendor.irq = chip->vendor.probed_irq;
-
- /* free_irq will call into tis_int_probe;
- clear all irqs we haven't seen while doing
- tpm_gen_interrupt */
- iowrite32(ioread32
- (chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality)),
- chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality));
-
- /* Turn off */
- iowrite32(intmask,
- chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.locality));
-
- devm_free_irq(dev, i, chip);
- }
+ if (interrupts) {
+ if (tpm_info->irq) {
+ tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
+ tpm_info->irq);
+ if (!chip->vendor.irq)
+ dev_err(chip->pdev, FW_BUG
+ "TPM interrupt not working, polling instead\n");
+ } else
+ tpm_tis_probe_irq(chip, intmask);
}
- if (chip->vendor.irq) {
- iowrite8(chip->vendor.irq,
- chip->vendor.iobase +
- TPM_INT_VECTOR(chip->vendor.locality));
- if (devm_request_irq
- (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
- chip->devname, chip) != 0) {
- dev_info(chip->pdev,
- "Unable to request irq: %d for use\n",
- chip->vendor.irq);
- chip->vendor.irq = 0;
- } else {
- /* Clear all existing */
- iowrite32(ioread32
- (chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality)),
- chip->vendor.iobase +
- TPM_INT_STATUS(chip->vendor.locality));
-
- /* Turn on */
- iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
- chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.locality));
- }
- } else if (irq_r != -1)
- iowrite8(irq_r, chip->vendor.iobase +
- TPM_INT_VECTOR(chip->vendor.locality));
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
- chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
- chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
- chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
- chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
- chip->vendor.duration[TPM_SHORT] =
- msecs_to_jiffies(TPM2_DURATION_SHORT);
- chip->vendor.duration[TPM_MEDIUM] =
- msecs_to_jiffies(TPM2_DURATION_MEDIUM);
- chip->vendor.duration[TPM_LONG] =
- msecs_to_jiffies(TPM2_DURATION_LONG);
-
rc = tpm2_do_selftest(chip);
if (rc == TPM2_RC_INITIALIZE) {
dev_warn(dev, "Firmware has not started TPM\n");
@@ -866,12 +834,6 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
goto out_err;
}
} else {
- if (tpm_get_timeouts(chip)) {
- dev_err(dev, "Could not get TPM timeouts and durations\n");
- rc = -ENODEV;
- goto out_err;
- }
-
if (tpm_do_selftest(chip)) {
dev_err(dev, "TPM self test failed\n");
rc = -ENODEV;
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c3e3a02f7f1f..eca8e019e005 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -116,6 +116,12 @@ config COMMON_CLK_CDCE925
Given a target output frequency, the driver will set the PLL and
divider to best approximate the desired output.
+config COMMON_CLK_CS2000_CP
+ tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier"
+ depends on I2C
+ help
+ If you say yes here you get support for the CS2000 clock multiplier.
+
config COMMON_CLK_S2MPS11
tristate "Clock driver for S2MPS1X/S5M8767 MFD"
depends on MFD_SEC_CORE
@@ -161,6 +167,12 @@ config COMMON_CLK_KEYSTONE
Supports clock drivers for Keystone based SOCs. These SOCs have local
a power sleep control module that gate the clock to the IPs and PLLs.
+config COMMON_CLK_NXP
+ def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX)
+ select REGMAP_MMIO if ARCH_LPC32XX
+ ---help---
+ Support for clock providers on NXP platforms.
+
config COMMON_CLK_PALMAS
tristate "Clock driver for TI Palmas devices"
depends on MFD_PALMAS
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 820714c72d36..b038e3666058 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
+obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
+obj-$(CONFIG_ARCH_TANGOX) += clk-tango4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
@@ -62,13 +64,14 @@ endif
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_ARCH_MXS) += mxs/
-obj-$(CONFIG_ARCH_LPC18XX) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
+obj-$(CONFIG_COMMON_CLK_NXP) += nxp/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/
+obj-$(CONFIG_ARCH_RENESAS) += shmobile/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
index d0d5076a9b94..6f99a530ead6 100644
--- a/drivers/clk/at91/clk-slow.c
+++ b/drivers/clk/at91/clk-slow.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/slab.h>
@@ -72,8 +71,6 @@ struct clk_sam9x5_slow {
#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
-static struct clk *slow_clk;
-
static int clk_slow_osc_prepare(struct clk_hw *hw)
{
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
@@ -360,8 +357,6 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
clk = clk_register(NULL, &slowck->hw);
if (IS_ERR(clk))
kfree(slowck);
- else
- slow_clk = clk;
return clk;
}
@@ -433,8 +428,6 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
clk = clk_register(NULL, &slowck->hw);
if (IS_ERR(clk))
kfree(slowck);
- else
- slow_clk = clk;
return clk;
}
@@ -462,25 +455,3 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
-
-/*
- * FIXME: All slow clk users are not properly claiming it (get + prepare +
- * enable) before using it.
- * If all users properly claiming this clock decide that they don't need it
- * anymore (or are removed), it is disabled while faulty users are still
- * requiring it, and the system hangs.
- * Prevent this clock from being disabled until all users are properly
- * requesting it.
- * Once this is done we should remove this function and the slow_clk variable.
- */
-static int __init of_at91_clk_slow_retain(void)
-{
- if (!slow_clk)
- return 0;
-
- __clk_get(slow_clk);
- clk_prepare_enable(slow_clk);
-
- return 0;
-}
-arch_initcall(of_at91_clk_slow_retain);
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index 85260fb96b36..f2878459199a 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -1,3 +1,13 @@
+config CLK_BCM_63XX
+ bool "Broadcom BCM63xx clock support"
+ depends on ARCH_BCM_63XX || COMPILE_TEST
+ depends on COMMON_CLK
+ select COMMON_CLK_IPROC
+ default ARCH_BCM_63XX
+ help
+ Enable common clock framework support for Broadcom BCM63xx DSL SoCs
+ based on the ARM architecture
+
config CLK_BCM_KONA
bool "Broadcom Kona CCU clock support"
depends on ARCH_BCM_MOBILE || COMPILE_TEST
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 3fc95060d875..1d79bd2c36f0 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -1,9 +1,11 @@
+obj-$(CONFIG_CLK_BCM_63XX) += clk-bcm63xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
+obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
diff --git a/drivers/clk/bcm/clk-bcm2835-aux.c b/drivers/clk/bcm/clk-bcm2835-aux.c
new file mode 100644
index 000000000000..e4f89e28b5ec
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm2835-aux.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 Broadcom
+ *
+ * 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>
+#include <linux/clk-provider.h>
+#include <linux/clk/bcm2835.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/bcm2835-aux.h>
+
+#define BCM2835_AUXIRQ 0x00
+#define BCM2835_AUXENB 0x04
+
+static int bcm2835_aux_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk_onecell_data *onecell;
+ const char *parent;
+ struct clk *parent_clk;
+ struct resource *res;
+ void __iomem *reg, *gate;
+
+ parent_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(parent_clk))
+ return PTR_ERR(parent_clk);
+ parent = __clk_get_name(parent_clk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(dev, res);
+ if (!reg)
+ return -ENODEV;
+
+ onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
+ if (!onecell)
+ return -ENOMEM;
+ onecell->clk_num = BCM2835_AUX_CLOCK_COUNT;
+ onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT,
+ sizeof(*onecell->clks), GFP_KERNEL);
+ if (!onecell->clks)
+ return -ENOMEM;
+
+ gate = reg + BCM2835_AUXENB;
+ onecell->clks[BCM2835_AUX_CLOCK_UART] =
+ clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
+
+ onecell->clks[BCM2835_AUX_CLOCK_SPI1] =
+ clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
+
+ onecell->clks[BCM2835_AUX_CLOCK_SPI2] =
+ clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
+
+ of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_aux_clk_of_match[] = {
+ { .compatible = "brcm,bcm2835-aux", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
+
+static struct platform_driver bcm2835_aux_clk_driver = {
+ .driver = {
+ .name = "bcm2835-aux-clk",
+ .of_match_table = bcm2835_aux_clk_of_match,
+ },
+ .probe = bcm2835_aux_clk_probe,
+};
+builtin_platform_driver(bcm2835_aux_clk_driver);
+
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39bf5820297e..015e687ffabe 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -807,6 +807,16 @@ static const struct bcm2835_clock_data bcm2835_clock_emmc_data = {
.frac_bits = 8,
};
+static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+ .name = "pwm",
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+ .parents = bcm2835_clock_per_parents,
+ .ctl_reg = CM_PWMCTL,
+ .div_reg = CM_PWMDIV,
+ .int_bits = 12,
+ .frac_bits = 12,
+};
+
struct bcm2835_pll {
struct clk_hw hw;
struct bcm2835_cprman *cprman;
@@ -1148,22 +1158,24 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
- unsigned long parent_rate)
+ unsigned long parent_rate,
+ bool round_up)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
- u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
+ u32 unused_frac_mask =
+ GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+ u64 rem;
u32 div;
- do_div(temp, rate);
+ rem = do_div(temp, rate);
div = temp;
- /* Round and mask off the unused bits */
- if (unused_frac_mask != 0) {
- div += unused_frac_mask >> 1;
- div &= ~unused_frac_mask;
- }
+ /* Round up and mask off the unused bits */
+ if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
+ div += unused_frac_mask + 1;
+ div &= ~unused_frac_mask;
/* Clamp to the limits. */
div = max(div, unused_frac_mask + 1);
@@ -1197,16 +1209,6 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
return temp;
}
-static long bcm2835_clock_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *parent_rate)
-{
- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
- u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
-
- return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
-}
-
static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -1271,20 +1273,82 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
- u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
+ u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
cprman_write(cprman, data->div_reg, div);
return 0;
}
+static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct clk_hw *parent, *best_parent = NULL;
+ unsigned long rate, best_rate = 0;
+ unsigned long prate, best_prate = 0;
+ size_t i;
+ u32 div;
+
+ /*
+ * Select parent clock that results in the closest but lower rate
+ */
+ for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
+ parent = clk_hw_get_parent_by_index(hw, i);
+ if (!parent)
+ continue;
+ prate = clk_hw_get_rate(parent);
+ div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+ rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+ if (rate > best_rate && rate <= req->rate) {
+ best_parent = parent;
+ best_prate = prate;
+ best_rate = rate;
+ }
+ }
+
+ if (!best_parent)
+ return -EINVAL;
+
+ req->best_parent_hw = best_parent;
+ req->best_parent_rate = best_prate;
+
+ req->rate = best_rate;
+
+ return 0;
+}
+
+static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+ const struct bcm2835_clock_data *data = clock->data;
+ u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
+
+ cprman_write(cprman, data->ctl_reg, src);
+ return 0;
+}
+
+static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
+{
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+ const struct bcm2835_clock_data *data = clock->data;
+ u32 src = cprman_read(cprman, data->ctl_reg);
+
+ return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+}
+
+
static const struct clk_ops bcm2835_clock_clk_ops = {
.is_prepared = bcm2835_clock_is_on,
.prepare = bcm2835_clock_on,
.unprepare = bcm2835_clock_off,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
- .round_rate = bcm2835_clock_round_rate,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
};
static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@@ -1300,7 +1364,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.is_prepared = bcm2835_vpu_clock_is_on,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
- .round_rate = bcm2835_clock_round_rate,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
};
static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@@ -1394,45 +1460,23 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
{
struct bcm2835_clock *clock;
struct clk_init_data init;
- const char *parent;
+ const char *parents[1 << CM_SRC_BITS];
+ size_t i;
/*
- * Most of the clock generators have a mux field, so we
- * instantiate a generic mux as our parent to handle it.
+ * Replace our "xosc" references with the oscillator's
+ * actual name.
*/
- if (data->num_mux_parents) {
- const char *parents[1 << CM_SRC_BITS];
- int i;
-
- parent = devm_kasprintf(cprman->dev, GFP_KERNEL,
- "mux_%s", data->name);
- if (!parent)
- return NULL;
-
- /*
- * Replace our "xosc" references with the oscillator's
- * actual name.
- */
- for (i = 0; i < data->num_mux_parents; i++) {
- if (strcmp(data->parents[i], "xosc") == 0)
- parents[i] = cprman->osc_name;
- else
- parents[i] = data->parents[i];
- }
-
- clk_register_mux(cprman->dev, parent,
- parents, data->num_mux_parents,
- CLK_SET_RATE_PARENT,
- cprman->regs + data->ctl_reg,
- CM_SRC_SHIFT, CM_SRC_BITS,
- 0, &cprman->regs_lock);
- } else {
- parent = data->parents[0];
+ for (i = 0; i < data->num_mux_parents; i++) {
+ if (strcmp(data->parents[i], "xosc") == 0)
+ parents[i] = cprman->osc_name;
+ else
+ parents[i] = data->parents[i];
}
memset(&init, 0, sizeof(init));
- init.parent_names = &parent;
- init.num_parents = 1;
+ init.parent_names = parents;
+ init.num_parents = data->num_mux_parents;
init.name = data->name;
init.flags = CLK_IGNORE_UNUSED;
@@ -1550,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
cprman->regs + CM_PERIICTL, CM_GATE_BIT,
0, &cprman->regs_lock);
+ clks[BCM2835_CLOCK_PWM] =
+ bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
+
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
&cprman->onecell);
}
diff --git a/drivers/clk/bcm/clk-bcm63xx.c b/drivers/clk/bcm/clk-bcm63xx.c
new file mode 100644
index 000000000000..fbc17ae5ff2b
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm63xx.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include "clk-iproc.h"
+
+static void __init bcm63138_armpll_init(struct device_node *node)
+{
+ iproc_armpll_setup(node);
+}
+CLK_OF_DECLARE(bcm63138_armpll, "brcm,bcm63138-armpll", bcm63138_armpll_init);
diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c
new file mode 100644
index 000000000000..7379de8dc894
--- /dev/null
+++ b/drivers/clk/clk-cs2000-cp.c
@@ -0,0 +1,510 @@
+/*
+ * CS2000 -- CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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-provider.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+
+#define CH_MAX 4
+#define RATIO_REG_SIZE 4
+
+#define DEVICE_ID 0x1
+#define DEVICE_CTRL 0x2
+#define DEVICE_CFG1 0x3
+#define DEVICE_CFG2 0x4
+#define GLOBAL_CFG 0x5
+#define Ratio_Add(x, nth) (6 + (x * 4) + (nth))
+#define Ratio_Val(x, nth) ((x >> (24 - (8 * nth))) & 0xFF)
+#define Val_Ratio(x, nth) ((x & 0xFF) << (24 - (8 * nth)))
+#define FUNC_CFG1 0x16
+#define FUNC_CFG2 0x17
+
+/* DEVICE_ID */
+#define REVISION_MASK (0x7)
+#define REVISION_B2_B3 (0x4)
+#define REVISION_C1 (0x6)
+
+/* DEVICE_CTRL */
+#define PLL_UNLOCK (1 << 7)
+
+/* DEVICE_CFG1 */
+#define RSEL(x) (((x) & 0x3) << 3)
+#define RSEL_MASK RSEL(0x3)
+#define ENDEV1 (0x1)
+
+/* GLOBAL_CFG */
+#define ENDEV2 (0x1)
+
+#define CH_SIZE_ERR(ch) ((ch < 0) || (ch >= CH_MAX))
+#define hw_to_priv(_hw) container_of(_hw, struct cs2000_priv, hw)
+#define priv_to_client(priv) (priv->client)
+#define priv_to_dev(priv) (&(priv_to_client(priv)->dev))
+
+#define CLK_IN 0
+#define REF_CLK 1
+#define CLK_MAX 2
+
+struct cs2000_priv {
+ struct clk_hw hw;
+ struct i2c_client *client;
+ struct clk *clk_in;
+ struct clk *ref_clk;
+ struct clk *clk_out;
+};
+
+static const struct of_device_id cs2000_of_match[] = {
+ { .compatible = "cirrus,cs2000-cp", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs2000_of_match);
+
+static const struct i2c_device_id cs2000_id[] = {
+ { "cs2000-cp", },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs2000_id);
+
+#define cs2000_read(priv, addr) \
+ i2c_smbus_read_byte_data(priv_to_client(priv), addr)
+#define cs2000_write(priv, addr, val) \
+ i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
+
+static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
+{
+ s32 data;
+
+ data = cs2000_read(priv, addr);
+ if (data < 0)
+ return data;
+
+ data &= ~mask;
+ data |= (val & mask);
+
+ return cs2000_write(priv, addr, data);
+}
+
+static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
+{
+ int ret;
+
+ ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
+ enable ? ENDEV1 : 0);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_bset(priv, GLOBAL_CFG, ENDEV2,
+ enable ? ENDEV2 : 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
+ u32 rate_in)
+{
+ u32 val;
+
+ if (rate_in >= 32000000 && rate_in < 56000000)
+ val = 0x0;
+ else if (rate_in >= 16000000 && rate_in < 28000000)
+ val = 0x1;
+ else if (rate_in >= 8000000 && rate_in < 14000000)
+ val = 0x2;
+ else
+ return -EINVAL;
+
+ return cs2000_bset(priv, FUNC_CFG1, 0x3 << 3, val << 3);
+}
+
+static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
+{
+ struct device *dev = priv_to_dev(priv);
+ s32 val;
+ unsigned int i;
+
+ for (i = 0; i < 256; i++) {
+ val = cs2000_read(priv, DEVICE_CTRL);
+ if (val < 0)
+ return val;
+ if (!(val & PLL_UNLOCK))
+ return 0;
+ udelay(1);
+ }
+
+ dev_err(dev, "pll lock failed\n");
+
+ return -ETIMEDOUT;
+}
+
+static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
+{
+ /* enable both AUX_OUT, CLK_OUT */
+ return cs2000_write(priv, DEVICE_CTRL, enable ? 0 : 0x3);
+}
+
+static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
+{
+ u64 ratio;
+
+ /*
+ * ratio = rate_out / rate_in * 2^20
+ *
+ * To avoid over flow, rate_out is u64.
+ * The result should be u32.
+ */
+ ratio = (u64)rate_out << 20;
+ do_div(ratio, rate_in);
+
+ return ratio;
+}
+
+static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in)
+{
+ u64 rate_out;
+
+ /*
+ * ratio = rate_out / rate_in * 2^20
+ *
+ * To avoid over flow, rate_out is u64.
+ * The result should be u32 or unsigned long.
+ */
+
+ rate_out = (u64)ratio * rate_in;
+ return rate_out >> 20;
+}
+
+static int cs2000_ratio_set(struct cs2000_priv *priv,
+ int ch, u32 rate_in, u32 rate_out)
+{
+ u32 val;
+ unsigned int i;
+ int ret;
+
+ if (CH_SIZE_ERR(ch))
+ return -EINVAL;
+
+ val = cs2000_rate_to_ratio(rate_in, rate_out);
+ for (i = 0; i < RATIO_REG_SIZE; i++) {
+ ret = cs2000_write(priv,
+ Ratio_Add(ch, i),
+ Ratio_Val(val, i));
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
+{
+ s32 tmp;
+ u32 val;
+ unsigned int i;
+
+ val = 0;
+ for (i = 0; i < RATIO_REG_SIZE; i++) {
+ tmp = cs2000_read(priv, Ratio_Add(ch, i));
+ if (tmp < 0)
+ return 0;
+
+ val |= Val_Ratio(tmp, i);
+ }
+
+ return val;
+}
+
+static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
+{
+ int ret;
+
+ if (CH_SIZE_ERR(ch))
+ return -EINVAL;
+
+ /*
+ * FIXME
+ *
+ * this driver supports static ratio mode only at this point.
+ */
+ ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_write(priv, DEVICE_CFG2, 0x0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cs2000_priv *priv = hw_to_priv(hw);
+ int ch = 0; /* it uses ch0 only at this point */
+ u32 ratio;
+
+ ratio = cs2000_ratio_get(priv, ch);
+
+ return cs2000_ratio_to_rate(ratio, parent_rate);
+}
+
+static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ u32 ratio;
+
+ ratio = cs2000_rate_to_ratio(*parent_rate, rate);
+
+ return cs2000_ratio_to_rate(ratio, *parent_rate);
+}
+
+static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
+ unsigned long rate, unsigned long parent_rate)
+
+{
+ int ret;
+
+ ret = cs2000_clk_in_bound_rate(priv, parent_rate);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_ratio_set(priv, ch, parent_rate, rate);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_ratio_select(priv, ch);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cs2000_set_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct cs2000_priv *priv = hw_to_priv(hw);
+ int ch = 0; /* it uses ch0 only at this point */
+
+ return __cs2000_set_rate(priv, ch, rate, parent_rate);
+}
+
+static int cs2000_enable(struct clk_hw *hw)
+{
+ struct cs2000_priv *priv = hw_to_priv(hw);
+ int ret;
+
+ ret = cs2000_enable_dev_config(priv, true);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_clk_out_enable(priv, true);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_wait_pll_lock(priv);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static void cs2000_disable(struct clk_hw *hw)
+{
+ struct cs2000_priv *priv = hw_to_priv(hw);
+
+ cs2000_enable_dev_config(priv, false);
+
+ cs2000_clk_out_enable(priv, false);
+}
+
+static u8 cs2000_get_parent(struct clk_hw *hw)
+{
+ /* always return REF_CLK */
+ return REF_CLK;
+}
+
+static const struct clk_ops cs2000_ops = {
+ .get_parent = cs2000_get_parent,
+ .recalc_rate = cs2000_recalc_rate,
+ .round_rate = cs2000_round_rate,
+ .set_rate = cs2000_set_rate,
+ .prepare = cs2000_enable,
+ .unprepare = cs2000_disable,
+};
+
+static int cs2000_clk_get(struct cs2000_priv *priv)
+{
+ struct i2c_client *client = priv_to_client(priv);
+ struct device *dev = &client->dev;
+ struct clk *clk_in, *ref_clk;
+
+ clk_in = devm_clk_get(dev, "clk_in");
+ /* not yet provided */
+ if (IS_ERR(clk_in))
+ return -EPROBE_DEFER;
+
+ ref_clk = devm_clk_get(dev, "ref_clk");
+ /* not yet provided */
+ if (IS_ERR(ref_clk))
+ return -EPROBE_DEFER;
+
+ priv->clk_in = clk_in;
+ priv->ref_clk = ref_clk;
+
+ return 0;
+}
+
+static int cs2000_clk_register(struct cs2000_priv *priv)
+{
+ struct device *dev = priv_to_dev(priv);
+ struct device_node *np = dev->of_node;
+ struct clk_init_data init;
+ const char *name = np->name;
+ struct clk *clk;
+ static const char *parent_names[CLK_MAX];
+ int ch = 0; /* it uses ch0 only at this point */
+ int rate;
+ int ret;
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ /*
+ * set default rate as 1/1.
+ * otherwise .set_rate which setup ratio
+ * is never called if user requests 1/1 rate
+ */
+ rate = clk_get_rate(priv->ref_clk);
+ ret = __cs2000_set_rate(priv, ch, rate, rate);
+ if (ret < 0)
+ return ret;
+
+ parent_names[CLK_IN] = __clk_get_name(priv->clk_in);
+ parent_names[REF_CLK] = __clk_get_name(priv->ref_clk);
+
+ init.name = name;
+ init.ops = &cs2000_ops;
+ init.flags = CLK_SET_RATE_GATE;
+ init.parent_names = parent_names;
+ init.num_parents = ARRAY_SIZE(parent_names);
+
+ priv->hw.init = &init;
+
+ clk = clk_register(dev, &priv->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (ret < 0) {
+ clk_unregister(clk);
+ return ret;
+ }
+
+ priv->clk_out = clk;
+
+ return 0;
+}
+
+static int cs2000_version_print(struct cs2000_priv *priv)
+{
+ struct i2c_client *client = priv_to_client(priv);
+ struct device *dev = &client->dev;
+ s32 val;
+ const char *revision;
+
+ val = cs2000_read(priv, DEVICE_ID);
+ if (val < 0)
+ return val;
+
+ /* CS2000 should be 0x0 */
+ if (val >> 3)
+ return -EIO;
+
+ switch (val & REVISION_MASK) {
+ case REVISION_B2_B3:
+ revision = "B2 / B3";
+ break;
+ case REVISION_C1:
+ revision = "C1";
+ break;
+ default:
+ return -EIO;
+ }
+
+ dev_info(dev, "revision - %s\n", revision);
+
+ return 0;
+}
+
+static int cs2000_remove(struct i2c_client *client)
+{
+ struct cs2000_priv *priv = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+ struct device_node *np = dev->of_node;
+
+ of_clk_del_provider(np);
+
+ clk_unregister(priv->clk_out);
+
+ return 0;
+}
+
+static int cs2000_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cs2000_priv *priv;
+ struct device *dev = &client->dev;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+ i2c_set_clientdata(client, priv);
+
+ ret = cs2000_clk_get(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_clk_register(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = cs2000_version_print(priv);
+ if (ret < 0)
+ goto probe_err;
+
+ return 0;
+
+probe_err:
+ cs2000_remove(client);
+
+ return ret;
+}
+
+static struct i2c_driver cs2000_driver = {
+ .driver = {
+ .name = "cs2000-cp",
+ .of_match_table = cs2000_of_match,
+ },
+ .probe = cs2000_probe,
+ .remove = cs2000_remove,
+ .id_table = cs2000_id,
+};
+
+module_i2c_driver(cs2000_driver);
+
+MODULE_DESCRIPTION("CS2000-CP driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 3ace102a2a0a..ded3ff4b91b9 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -32,13 +32,14 @@
#define div_mask(width) ((1 << (width)) - 1)
-static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
+static unsigned int _get_table_maxdiv(const struct clk_div_table *table,
+ u8 width)
{
- unsigned int maxdiv = 0;
+ unsigned int maxdiv = 0, mask = div_mask(width);
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
- if (clkt->div > maxdiv)
+ if (clkt->div > maxdiv && clkt->val <= mask)
maxdiv = clkt->div;
return maxdiv;
}
@@ -62,7 +63,7 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask(width);
if (table)
- return _get_table_maxdiv(table);
+ return _get_table_maxdiv(table, width);
return div_mask(width) + 1;
}
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 335322dc403f..19fed65587e8 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -264,8 +264,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
const char * const *parent_names, u8 num_parents,
unsigned gpio, bool active_low)
{
- return clk_register_gpio_gate(NULL, name, parent_names[0],
- gpio, active_low, 0);
+ return clk_register_gpio_gate(NULL, name, parent_names ?
+ parent_names[0] : NULL, gpio, active_low, 0);
}
static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
@@ -287,18 +287,26 @@ static void __init of_gpio_clk_setup(struct device_node *node,
const char **parent_names;
int i, num_parents;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
- return;
-
num_parents = of_clk_get_parent_count(node);
+ if (num_parents < 0)
+ return;
- parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
- if (!parent_names)
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
return;
- for (i = 0; i < num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(node, i);
+ if (num_parents) {
+ parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
+ if (!parent_names) {
+ kfree(data);
+ return;
+ }
+
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(node, i);
+ } else {
+ parent_names = NULL;
+ }
data->num_parents = num_parents;
data->parent_names = parent_names;
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 7129c86a79db..5ed03c8a8df9 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -71,10 +71,9 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
u32 val;
unsigned long flags = 0;
- if (mux->table)
+ if (mux->table) {
index = mux->table[index];
-
- else {
+ } else {
if (mux->flags & CLK_MUX_INDEX_BIT)
index = 1 << index;
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index e346b223199d..850316ac8831 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -1091,6 +1091,13 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
SI5351_CLK_POWERDOWN, 0);
+ /*
+ * Do a pll soft reset on both plls, needed in some cases to get
+ * all outputs running.
+ */
+ si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
+ SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
+
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
__func__, clk_hw_get_name(hw), (1 << rdiv),
diff --git a/drivers/clk/clk-tango4.c b/drivers/clk/clk-tango4.c
new file mode 100644
index 000000000000..004ab7dfcfe3
--- /dev/null
+++ b/drivers/clk/clk-tango4.c
@@ -0,0 +1,61 @@
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+static struct clk *out[2];
+static struct clk_onecell_data clk_data = { out, 2 };
+
+#define SYSCLK_CTRL 0x20
+#define CPUCLK_CTRL 0x24
+#define LEGACY_DIV 0x3c
+
+#define PLL_N(val) (((val) >> 0) & 0x7f)
+#define PLL_K(val) (((val) >> 13) & 0x7)
+#define PLL_M(val) (((val) >> 16) & 0x7)
+#define DIV_INDEX(val) (((val) >> 8) & 0xf)
+
+static void __init make_pll(int idx, const char *parent, void __iomem *base)
+{
+ char name[8];
+ u32 val, mul, div;
+
+ sprintf(name, "pll%d", idx);
+ val = readl_relaxed(base + idx*8);
+ mul = PLL_N(val) + 1;
+ div = (PLL_M(val) + 1) << PLL_K(val);
+ clk_register_fixed_factor(NULL, name, parent, 0, mul, div);
+}
+
+static int __init get_div(void __iomem *base)
+{
+ u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
+ int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV));
+
+ return sysclk_tab[idx];
+}
+
+static void __init tango4_clkgen_setup(struct device_node *np)
+{
+ int div, ret;
+ void __iomem *base = of_iomap(np, 0);
+ const char *parent = of_clk_get_parent_name(np, 0);
+
+ if (!base)
+ panic("%s: invalid address\n", np->full_name);
+
+ make_pll(0, parent, base);
+ make_pll(1, parent, base);
+
+ out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0,
+ base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL);
+
+ div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4;
+ out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div);
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0)
+ panic("%s: clk registration failed\n", np->full_name);
+}
+CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index 27c0da29eca3..10224b01b97c 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -351,7 +351,8 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
/* Set new divider */
data = xgene_clk_read(pclk->param.divider_reg +
pclk->param.reg_divider_offset);
- data &= ~((1 << pclk->param.reg_divider_width) - 1);
+ data &= ~((1 << pclk->param.reg_divider_width) - 1)
+ << pclk->param.reg_divider_shift;
data |= divider;
xgene_clk_write(data, pclk->param.divider_reg +
pclk->param.reg_divider_offset);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index f13c3f4228d4..b4db67a446c8 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1443,6 +1443,15 @@ static void clk_change_rate(struct clk_core *core)
else if (core->parent)
best_parent_rate = core->parent->rate;
+ if (core->flags & CLK_SET_RATE_UNGATE) {
+ unsigned long flags;
+
+ clk_core_prepare(core);
+ flags = clk_enable_lock();
+ clk_core_enable(core);
+ clk_enable_unlock(flags);
+ }
+
if (core->new_parent && core->new_parent != core->parent) {
old_parent = __clk_set_parent_before(core, core->new_parent);
trace_clk_set_parent(core, core->new_parent);
@@ -1469,6 +1478,15 @@ static void clk_change_rate(struct clk_core *core)
core->rate = clk_recalc(core, best_parent_rate);
+ if (core->flags & CLK_SET_RATE_UNGATE) {
+ unsigned long flags;
+
+ flags = clk_enable_lock();
+ clk_core_disable(core);
+ clk_enable_unlock(flags);
+ clk_core_unprepare(core);
+ }
+
if (core->notifier_count && old_rate != core->rate)
__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
@@ -1944,7 +1962,7 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
if (p == q)
return true;
- /* true if clk->core pointers match. Avoid derefing garbage */
+ /* true if clk->core pointers match. Avoid dereferencing garbage */
if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
if (p->core == q->core)
return true;
@@ -2482,7 +2500,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
struct clk *clk;
/* This is to allow this function to be chained to others */
- if (!hw || IS_ERR(hw))
+ if (IS_ERR_OR_NULL(hw))
return (struct clk *) hw;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
@@ -2806,10 +2824,9 @@ void __clk_put(struct clk *clk)
* re-enter into the clk framework by calling any top-level clk APIs;
* this will cause a nested prepare_lock mutex.
*
- * In all notification cases cases (pre, post and abort rate change) the
- * original clock rate is passed to the callback via struct
- * clk_notifier_data.old_rate and the new frequency is passed via struct
- * clk_notifier_data.new_rate.
+ * In all notification cases (pre, post and abort rate change) the original
+ * clock rate is passed to the callback via struct clk_notifier_data.old_rate
+ * and the new frequency is passed via struct clk_notifier_data.new_rate.
*
* clk_notifier_register() must be called from non-atomic context.
* Returns -EINVAL if called with null arguments, -ENOMEM upon
@@ -3062,9 +3079,6 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
int count;
struct clk *clk;
- if (index < 0)
- return NULL;
-
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
&clkspec);
if (rc)
@@ -3083,6 +3097,9 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
}
count++;
}
+ /* We went off the end of 'clock-indices' without finding it */
+ if (prop && !vp)
+ return NULL;
if (of_property_read_string_index(clkspec.np, "clock-output-names",
index,
diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
index c4c141cab444..23686f756b5e 100644
--- a/drivers/clk/imx/clk-imx25.c
+++ b/drivers/clk/imx/clk-imx25.c
@@ -96,13 +96,11 @@ static struct clk ** const uart_clks[] __initconst = {
NULL
};
-static int __init __mx25_clocks_init(unsigned long osc_rate,
- void __iomem *ccm_base)
+static int __init __mx25_clocks_init(void __iomem *ccm_base)
{
BUG_ON(!ccm_base);
clk[dummy] = imx_clk_fixed("dummy", 0);
- clk[osc] = imx_clk_fixed("osc", osc_rate);
clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX25, "mpll", "osc", ccm(CCM_MPCTL));
clk[upll] = imx_clk_pllv1(IMX_PLLV1_IMX25, "upll", "osc", ccm(CCM_UPCTL));
clk[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4);
@@ -250,22 +248,10 @@ static int __init __mx25_clocks_init(unsigned long osc_rate,
static void __init mx25_clocks_init_dt(struct device_node *np)
{
- struct device_node *refnp;
- unsigned long osc_rate = 24000000;
void __iomem *ccm;
- /* retrieve the freqency of fixed clocks from device tree */
- for_each_compatible_node(refnp, NULL, "fixed-clock") {
- u32 rate;
- if (of_property_read_u32(refnp, "clock-frequency", &rate))
- continue;
-
- if (of_device_is_compatible(refnp, "fsl,imx-osc"))
- osc_rate = rate;
- }
-
ccm = of_iomap(np, 0);
- __mx25_clocks_init(osc_rate, ccm);
+ __mx25_clocks_init(ccm);
clk_data.clks = clk;
clk_data.clk_num = ARRAY_SIZE(clk);
diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c
index c6770348d2ab..29d4c44ef356 100644
--- a/drivers/clk/imx/clk-imx51-imx53.c
+++ b/drivers/clk/imx/clk-imx51-imx53.c
@@ -519,10 +519,10 @@ static void __init mx53_clocks_init(struct device_node *np)
mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel), CLK_SET_RATE_PARENT);
clk[IMX5_CLK_LDB_DI0_GATE] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28);
clk[IMX5_CLK_LDB_DI1_GATE] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30);
- clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
- mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));
- clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
- mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel));
+ clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
+ mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel), CLK_SET_RATE_PARENT);
+ clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_flags("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
+ mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel), CLK_SET_RATE_PARENT);
clk[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);
clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index c1935081d34a..f0efc6feeec2 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -70,7 +70,8 @@ static const char *cko_sels[] = { "cko1", "cko2", };
static const char *lvds_sels[] = {
"dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
"pll4_audio", "pll5_video", "pll8_mlb", "enet_ref",
- "pcie_ref_125m", "sata_ref_100m",
+ "pcie_ref_125m", "sata_ref_100m", "usbphy1", "usbphy2",
+ "dummy", "dummy", "dummy", "dummy", "osc",
};
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 01718d05e952..08692d74b884 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -399,9 +399,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
/* mask handshake of mmdc */
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
- for (i = 0; i < ARRAY_SIZE(clks); i++)
- if (IS_ERR(clks[i]))
- pr_err("i.MX6UL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i]));
+ imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 448ef321948b..fbb6a8c8653d 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -833,10 +833,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
- for (i = 0; i < ARRAY_SIZE(clks); i++)
- if (IS_ERR(clks[i]))
- pr_err("i.MX7D clk %d: register failed with %ld\n",
- i, PTR_ERR(clks[i]));
+ clks[IMX7D_CLK_ARM] = imx_clk_cpu("arm", "arm_a7_root_clk",
+ clks[IMX7D_ARM_A7_ROOT_CLK],
+ clks[IMX7D_ARM_A7_ROOT_SRC],
+ clks[IMX7D_PLL_ARM_MAIN_CLK],
+ clks[IMX7D_PLL_SYS_MAIN_CLK]);
+
+ imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index 6addf8f58b97..c05c43d56a94 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -97,6 +97,16 @@ static void clk_pllv3_unprepare(struct clk_hw *hw)
writel_relaxed(val, pll->base);
}
+static int clk_pllv3_is_prepared(struct clk_hw *hw)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(hw);
+
+ if (readl_relaxed(pll->base) & BM_PLL_LOCK)
+ return 1;
+
+ return 0;
+}
+
static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -139,6 +149,7 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_pllv3_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
+ .is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_recalc_rate,
.round_rate = clk_pllv3_round_rate,
.set_rate = clk_pllv3_set_rate,
@@ -193,6 +204,7 @@ static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_pllv3_sys_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
+ .is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_sys_recalc_rate,
.round_rate = clk_pllv3_sys_round_rate,
.set_rate = clk_pllv3_sys_set_rate,
@@ -265,6 +277,7 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_pllv3_av_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
+ .is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_av_recalc_rate,
.round_rate = clk_pllv3_av_round_rate,
.set_rate = clk_pllv3_av_set_rate,
@@ -279,6 +292,7 @@ static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw,
static const struct clk_ops clk_pllv3_enet_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
+ .is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_enet_recalc_rate,
};
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
index 71fd29348f28..38931dbd1eff 100644
--- a/drivers/clk/mmp/clk-mmp2.c
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -17,8 +17,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <mach/addr-map.h>
-
#include "clk.h"
#define APBC_RTC 0x0
@@ -74,7 +72,8 @@ static const char *sdh_parent[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
static const char *disp_parent[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
static const char *ccic_parent[] = {"pll1_2", "pll1_16", "vctcxo"};
-void __init mmp2_clk_init(void)
+void __init mmp2_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys)
{
struct clk *clk;
struct clk *vctcxo;
@@ -82,19 +81,19 @@ void __init mmp2_clk_init(void)
void __iomem *apmu_base;
void __iomem *apbc_base;
- mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+ mpmu_base = ioremap(mpmu_phys, SZ_4K);
if (mpmu_base == NULL) {
pr_err("error to ioremap MPMU base\n");
return;
}
- apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+ apmu_base = ioremap(apmu_phys, SZ_4K);
if (apmu_base == NULL) {
pr_err("error to ioremap APMU base\n");
return;
}
- apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+ apbc_base = ioremap(apbc_phys, SZ_4K);
if (apbc_base == NULL) {
pr_err("error to ioremap APBC base\n");
return;
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
index 75244915df05..0dd83fb950c9 100644
--- a/drivers/clk/mmp/clk-pxa168.c
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -17,8 +17,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <mach/addr-map.h>
-
#include "clk.h"
#define APBC_RTC 0x28
@@ -67,7 +65,8 @@ static const char *disp_parent[] = {"pll1_2", "pll1_12"};
static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
-void __init pxa168_clk_init(void)
+void __init pxa168_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys)
{
struct clk *clk;
struct clk *uart_pll;
@@ -75,19 +74,19 @@ void __init pxa168_clk_init(void)
void __iomem *apmu_base;
void __iomem *apbc_base;
- mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+ mpmu_base = ioremap(mpmu_phys, SZ_4K);
if (mpmu_base == NULL) {
pr_err("error to ioremap MPMU base\n");
return;
}
- apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+ apmu_base = ioremap(apmu_phys, SZ_4K);
if (apmu_base == NULL) {
pr_err("error to ioremap APMU base\n");
return;
}
- apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+ apbc_base = ioremap(apbc_phys, SZ_4K);
if (apbc_base == NULL) {
pr_err("error to ioremap APBC base\n");
return;
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
index 37ba04ba1368..e1d2ce22cdf1 100644
--- a/drivers/clk/mmp/clk-pxa910.c
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -17,8 +17,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <mach/addr-map.h>
-
#include "clk.h"
#define APBC_RTC 0x28
@@ -65,7 +63,8 @@ static const char *disp_parent[] = {"pll1_2", "pll1_12"};
static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
-void __init pxa910_clk_init(void)
+void __init pxa910_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys, phys_addr_t apbcp_phys)
{
struct clk *clk;
struct clk *uart_pll;
@@ -74,25 +73,25 @@ void __init pxa910_clk_init(void)
void __iomem *apbcp_base;
void __iomem *apbc_base;
- mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+ mpmu_base = ioremap(mpmu_phys, SZ_4K);
if (mpmu_base == NULL) {
pr_err("error to ioremap MPMU base\n");
return;
}
- apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+ apmu_base = ioremap(apmu_phys, SZ_4K);
if (apmu_base == NULL) {
pr_err("error to ioremap APMU base\n");
return;
}
- apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K);
+ apbcp_base = ioremap(apbcp_phys, SZ_4K);
if (apbcp_base == NULL) {
pr_err("error to ioremap APBC extension base\n");
return;
}
- apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+ apbc_base = ioremap(apbc_phys, SZ_4K);
if (apbc_base == NULL) {
pr_err("error to ioremap APBC base\n");
return;
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 645ac7ea3565..8866115486f7 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -7,6 +7,6 @@ obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o
obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o
obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
-obj-$(CONFIG_DOVE_CLK) += dove.o
+obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
obj-$(CONFIG_ORION_CLK) += orion.o
diff --git a/drivers/clk/mvebu/dove-divider.c b/drivers/clk/mvebu/dove-divider.c
new file mode 100644
index 000000000000..d5c5bfa35a5a
--- /dev/null
+++ b/drivers/clk/mvebu/dove-divider.c
@@ -0,0 +1,262 @@
+/*
+ * Marvell Dove PMU Core PLL divider driver
+ *
+ * Cleaned up by substantially rewriting, and converted to DT by
+ * Russell King. Origin is not known.
+ */
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "dove-divider.h"
+
+struct dove_clk {
+ const char *name;
+ struct clk_hw hw;
+ void __iomem *base;
+ spinlock_t *lock;
+ u8 div_bit_start;
+ u8 div_bit_end;
+ u8 div_bit_load;
+ u8 div_bit_size;
+ u32 *divider_table;
+};
+
+enum {
+ DIV_CTRL0 = 0,
+ DIV_CTRL1 = 4,
+ DIV_CTRL1_N_RESET_MASK = BIT(10),
+};
+
+#define to_dove_clk(hw) container_of(hw, struct dove_clk, hw)
+
+static void dove_load_divider(void __iomem *base, u32 val, u32 mask, u32 load)
+{
+ u32 v;
+
+ v = readl_relaxed(base + DIV_CTRL1) | DIV_CTRL1_N_RESET_MASK;
+ writel_relaxed(v, base + DIV_CTRL1);
+
+ v = (readl_relaxed(base + DIV_CTRL0) & ~(mask | load)) | val;
+ writel_relaxed(v, base + DIV_CTRL0);
+ writel_relaxed(v | load, base + DIV_CTRL0);
+ ndelay(250);
+ writel_relaxed(v, base + DIV_CTRL0);
+}
+
+static unsigned int dove_get_divider(struct dove_clk *dc)
+{
+ unsigned int divider;
+ u32 val;
+
+ val = readl_relaxed(dc->base + DIV_CTRL0);
+ val >>= dc->div_bit_start;
+
+ divider = val & ~(~0 << dc->div_bit_size);
+
+ if (dc->divider_table)
+ divider = dc->divider_table[divider];
+
+ return divider;
+}
+
+static int dove_calc_divider(const struct dove_clk *dc, unsigned long rate,
+ unsigned long parent_rate, bool set)
+{
+ unsigned int divider, max;
+
+ divider = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+ if (dc->divider_table) {
+ unsigned int i;
+
+ for (i = 0; dc->divider_table[i]; i++)
+ if (divider == dc->divider_table[i]) {
+ divider = i;
+ break;
+ }
+
+ if (!dc->divider_table[i])
+ return -EINVAL;
+ } else {
+ max = 1 << dc->div_bit_size;
+
+ if (set && (divider == 0 || divider >= max))
+ return -EINVAL;
+ if (divider >= max)
+ divider = max - 1;
+ else if (divider == 0)
+ divider = 1;
+ }
+
+ return divider;
+}
+
+static unsigned long dove_recalc_rate(struct clk_hw *hw, unsigned long parent)
+{
+ struct dove_clk *dc = to_dove_clk(hw);
+ unsigned int divider = dove_get_divider(dc);
+ unsigned long rate = DIV_ROUND_CLOSEST(parent, divider);
+
+ pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
+ __func__, dc->name, divider, parent, rate);
+
+ return rate;
+}
+
+static long dove_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent)
+{
+ struct dove_clk *dc = to_dove_clk(hw);
+ unsigned long parent_rate = *parent;
+ int divider;
+
+ divider = dove_calc_divider(dc, rate, parent_rate, false);
+ if (divider < 0)
+ return divider;
+
+ rate = DIV_ROUND_CLOSEST(parent_rate, divider);
+
+ pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
+ __func__, dc->name, divider, parent_rate, rate);
+
+ return rate;
+}
+
+static int dove_set_clock(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dove_clk *dc = to_dove_clk(hw);
+ u32 mask, load, div;
+ int divider;
+
+ divider = dove_calc_divider(dc, rate, parent_rate, true);
+ if (divider < 0)
+ return divider;
+
+ pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
+ __func__, dc->name, divider, parent_rate, rate);
+
+ div = (u32)divider << dc->div_bit_start;
+ mask = ~(~0 << dc->div_bit_size) << dc->div_bit_start;
+ load = BIT(dc->div_bit_load);
+
+ spin_lock(dc->lock);
+ dove_load_divider(dc->base, div, mask, load);
+ spin_unlock(dc->lock);
+
+ return 0;
+}
+
+static const struct clk_ops dove_divider_ops = {
+ .set_rate = dove_set_clock,
+ .round_rate = dove_round_rate,
+ .recalc_rate = dove_recalc_rate,
+};
+
+static struct clk *clk_register_dove_divider(struct device *dev,
+ struct dove_clk *dc, const char **parent_names, size_t num_parents,
+ void __iomem *base)
+{
+ char name[32];
+ struct clk_init_data init = {
+ .name = name,
+ .ops = &dove_divider_ops,
+ .parent_names = parent_names,
+ .num_parents = num_parents,
+ };
+
+ strlcpy(name, dc->name, sizeof(name));
+
+ dc->hw.init = &init;
+ dc->base = base;
+ dc->div_bit_size = dc->div_bit_end - dc->div_bit_start + 1;
+
+ return clk_register(dev, &dc->hw);
+}
+
+static DEFINE_SPINLOCK(dove_divider_lock);
+
+static u32 axi_divider[] = {-1, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 0};
+
+static struct dove_clk dove_hw_clocks[4] = {
+ {
+ .name = "axi",
+ .lock = &dove_divider_lock,
+ .div_bit_start = 1,
+ .div_bit_end = 6,
+ .div_bit_load = 7,
+ .divider_table = axi_divider,
+ }, {
+ .name = "gpu",
+ .lock = &dove_divider_lock,
+ .div_bit_start = 8,
+ .div_bit_end = 13,
+ .div_bit_load = 14,
+ }, {
+ .name = "vmeta",
+ .lock = &dove_divider_lock,
+ .div_bit_start = 15,
+ .div_bit_end = 20,
+ .div_bit_load = 21,
+ }, {
+ .name = "lcd",
+ .lock = &dove_divider_lock,
+ .div_bit_start = 22,
+ .div_bit_end = 27,
+ .div_bit_load = 28,
+ },
+};
+
+static const char *core_pll[] = {
+ "core-pll",
+};
+
+static int dove_divider_init(struct device *dev, void __iomem *base,
+ struct clk **clks)
+{
+ struct clk *clk;
+ int i;
+
+ /*
+ * Create the core PLL clock. We treat this as a fixed rate
+ * clock as we don't know any better, and documentation is sparse.
+ */
+ clk = clk_register_fixed_rate(dev, core_pll[0], NULL, CLK_IS_ROOT,
+ 2000000000UL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ for (i = 0; i < ARRAY_SIZE(dove_hw_clocks); i++)
+ clks[i] = clk_register_dove_divider(dev, &dove_hw_clocks[i],
+ core_pll,
+ ARRAY_SIZE(core_pll), base);
+
+ return 0;
+}
+
+static struct clk *dove_divider_clocks[4];
+
+static struct clk_onecell_data dove_divider_data = {
+ .clks = dove_divider_clocks,
+ .clk_num = ARRAY_SIZE(dove_divider_clocks),
+};
+
+void __init dove_divider_clk_init(struct device_node *np)
+{
+ void *base;
+
+ base = of_iomap(np, 0);
+ if (WARN_ON(!base))
+ return;
+
+ if (WARN_ON(dove_divider_init(NULL, base, dove_divider_clocks))) {
+ iounmap(base);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &dove_divider_data);
+}
diff --git a/drivers/clk/mvebu/dove-divider.h b/drivers/clk/mvebu/dove-divider.h
new file mode 100644
index 000000000000..4f2f718deb8e
--- /dev/null
+++ b/drivers/clk/mvebu/dove-divider.h
@@ -0,0 +1,6 @@
+#ifndef DOVE_DIVIDER_H
+#define DOVE_DIVIDER_H
+
+void __init dove_divider_clk_init(struct device_node *np);
+
+#endif
diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c
index b8c2424ac926..59fad9546c84 100644
--- a/drivers/clk/mvebu/dove.c
+++ b/drivers/clk/mvebu/dove.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include "common.h"
+#include "dove-divider.h"
/*
* Core Clocks
@@ -184,9 +185,14 @@ static void __init dove_clk_init(struct device_node *np)
{
struct device_node *cgnp =
of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+ struct device_node *ddnp =
+ of_find_compatible_node(NULL, NULL, "marvell,dove-divider-clock");
mvebu_coreclk_setup(np, &dove_coreclks);
+ if (ddnp)
+ dove_divider_clk_init(ddnp);
+
if (cgnp)
mvebu_clk_gating_setup(cgnp, dove_gating_desc);
}
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
index 7f608b0ad7b4..607bd48c6563 100644
--- a/drivers/clk/nxp/Makefile
+++ b/drivers/clk/nxp/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-ccu.o
+obj-$(CONFIG_ARCH_LPC32XX) += clk-lpc32xx.o
diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c
new file mode 100644
index 000000000000..10dd0fdaa474
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc32xx.c
@@ -0,0 +1,1569 @@
+/*
+ * Copyright 2015 Vladimir Zapolskiy <vz@mleia.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/lpc32xx-clock.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+/* Common bitfield definitions for x397 PLL (lock), USB PLL and HCLK PLL */
+#define PLL_CTRL_ENABLE BIT(16)
+#define PLL_CTRL_BYPASS BIT(15)
+#define PLL_CTRL_DIRECT BIT(14)
+#define PLL_CTRL_FEEDBACK BIT(13)
+#define PLL_CTRL_POSTDIV (BIT(12)|BIT(11))
+#define PLL_CTRL_PREDIV (BIT(10)|BIT(9))
+#define PLL_CTRL_FEEDDIV (0xFF << 1)
+#define PLL_CTRL_LOCK BIT(0)
+
+/* Clock registers on System Control Block */
+#define LPC32XX_CLKPWR_DEBUG_CTRL 0x00
+#define LPC32XX_CLKPWR_USB_DIV 0x1C
+#define LPC32XX_CLKPWR_HCLKDIV_CTRL 0x40
+#define LPC32XX_CLKPWR_PWR_CTRL 0x44
+#define LPC32XX_CLKPWR_PLL397_CTRL 0x48
+#define LPC32XX_CLKPWR_OSC_CTRL 0x4C
+#define LPC32XX_CLKPWR_SYSCLK_CTRL 0x50
+#define LPC32XX_CLKPWR_LCDCLK_CTRL 0x54
+#define LPC32XX_CLKPWR_HCLKPLL_CTRL 0x58
+#define LPC32XX_CLKPWR_ADCCLK_CTRL1 0x60
+#define LPC32XX_CLKPWR_USB_CTRL 0x64
+#define LPC32XX_CLKPWR_SSP_CTRL 0x78
+#define LPC32XX_CLKPWR_I2S_CTRL 0x7C
+#define LPC32XX_CLKPWR_MS_CTRL 0x80
+#define LPC32XX_CLKPWR_MACCLK_CTRL 0x90
+#define LPC32XX_CLKPWR_TEST_CLK_CTRL 0xA4
+#define LPC32XX_CLKPWR_I2CCLK_CTRL 0xAC
+#define LPC32XX_CLKPWR_KEYCLK_CTRL 0xB0
+#define LPC32XX_CLKPWR_ADCCLK_CTRL 0xB4
+#define LPC32XX_CLKPWR_PWMCLK_CTRL 0xB8
+#define LPC32XX_CLKPWR_TIMCLK_CTRL 0xBC
+#define LPC32XX_CLKPWR_TIMCLK_CTRL1 0xC0
+#define LPC32XX_CLKPWR_SPI_CTRL 0xC4
+#define LPC32XX_CLKPWR_FLASHCLK_CTRL 0xC8
+#define LPC32XX_CLKPWR_UART3_CLK_CTRL 0xD0
+#define LPC32XX_CLKPWR_UART4_CLK_CTRL 0xD4
+#define LPC32XX_CLKPWR_UART5_CLK_CTRL 0xD8
+#define LPC32XX_CLKPWR_UART6_CLK_CTRL 0xDC
+#define LPC32XX_CLKPWR_IRDA_CLK_CTRL 0xE0
+#define LPC32XX_CLKPWR_UART_CLK_CTRL 0xE4
+#define LPC32XX_CLKPWR_DMA_CLK_CTRL 0xE8
+
+/* Clock registers on USB controller */
+#define LPC32XX_USB_CLK_CTRL 0xF4
+#define LPC32XX_USB_CLK_STS 0xF8
+
+static struct regmap_config lpc32xx_scb_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+ .max_register = 0x114,
+ .fast_io = true,
+};
+
+static struct regmap *clk_regmap;
+static void __iomem *usb_clk_vbase;
+
+enum {
+ LPC32XX_USB_CLK_OTG = LPC32XX_USB_CLK_HOST + 1,
+ LPC32XX_USB_CLK_AHB,
+
+ LPC32XX_USB_CLK_MAX = LPC32XX_USB_CLK_AHB + 1,
+};
+
+enum {
+ /* Start from the last defined clock in dt bindings */
+ LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_ADC + 1,
+ LPC32XX_CLK_ADC_RTC,
+ LPC32XX_CLK_TEST1,
+ LPC32XX_CLK_TEST2,
+
+ /* System clocks, PLL 397x and HCLK PLL clocks */
+ LPC32XX_CLK_OSC,
+ LPC32XX_CLK_SYS,
+ LPC32XX_CLK_PLL397X,
+ LPC32XX_CLK_HCLK_PLL,
+ LPC32XX_CLK_HCLK_DIV_PERIPH,
+ LPC32XX_CLK_HCLK_DIV,
+ LPC32XX_CLK_HCLK,
+ LPC32XX_CLK_PERIPH,
+ LPC32XX_CLK_ARM,
+ LPC32XX_CLK_ARM_VFP,
+
+ /* USB clocks */
+ LPC32XX_CLK_USB_PLL,
+ LPC32XX_CLK_USB_DIV,
+ LPC32XX_CLK_USB,
+
+ /* Only one control PWR_CTRL[10] for both muxes */
+ LPC32XX_CLK_PERIPH_HCLK_MUX,
+ LPC32XX_CLK_PERIPH_ARM_MUX,
+
+ /* Only one control PWR_CTRL[2] for all three muxes */
+ LPC32XX_CLK_SYSCLK_PERIPH_MUX,
+ LPC32XX_CLK_SYSCLK_HCLK_MUX,
+ LPC32XX_CLK_SYSCLK_ARM_MUX,
+
+ /* Two clock sources external to the driver */
+ LPC32XX_CLK_XTAL_32K,
+ LPC32XX_CLK_XTAL,
+
+ /* Renumbered USB clocks, may have a parent from SCB table */
+ LPC32XX_CLK_USB_OFFSET,
+ LPC32XX_CLK_USB_I2C = LPC32XX_USB_CLK_I2C + LPC32XX_CLK_USB_OFFSET,
+ LPC32XX_CLK_USB_DEV = LPC32XX_USB_CLK_DEVICE + LPC32XX_CLK_USB_OFFSET,
+ LPC32XX_CLK_USB_HOST = LPC32XX_USB_CLK_HOST + LPC32XX_CLK_USB_OFFSET,
+ LPC32XX_CLK_USB_OTG = LPC32XX_USB_CLK_OTG + LPC32XX_CLK_USB_OFFSET,
+ LPC32XX_CLK_USB_AHB = LPC32XX_USB_CLK_AHB + LPC32XX_CLK_USB_OFFSET,
+
+ /* Stub for composite clocks */
+ LPC32XX_CLK__NULL,
+
+ /* Subclocks of composite clocks, clocks above are for CCF */
+ LPC32XX_CLK_PWM1_MUX,
+ LPC32XX_CLK_PWM1_DIV,
+ LPC32XX_CLK_PWM1_GATE,
+ LPC32XX_CLK_PWM2_MUX,
+ LPC32XX_CLK_PWM2_DIV,
+ LPC32XX_CLK_PWM2_GATE,
+ LPC32XX_CLK_UART3_MUX,
+ LPC32XX_CLK_UART3_DIV,
+ LPC32XX_CLK_UART3_GATE,
+ LPC32XX_CLK_UART4_MUX,
+ LPC32XX_CLK_UART4_DIV,
+ LPC32XX_CLK_UART4_GATE,
+ LPC32XX_CLK_UART5_MUX,
+ LPC32XX_CLK_UART5_DIV,
+ LPC32XX_CLK_UART5_GATE,
+ LPC32XX_CLK_UART6_MUX,
+ LPC32XX_CLK_UART6_DIV,
+ LPC32XX_CLK_UART6_GATE,
+ LPC32XX_CLK_TEST1_MUX,
+ LPC32XX_CLK_TEST1_GATE,
+ LPC32XX_CLK_TEST2_MUX,
+ LPC32XX_CLK_TEST2_GATE,
+ LPC32XX_CLK_USB_DIV_DIV,
+ LPC32XX_CLK_USB_DIV_GATE,
+ LPC32XX_CLK_SD_DIV,
+ LPC32XX_CLK_SD_GATE,
+ LPC32XX_CLK_LCD_DIV,
+ LPC32XX_CLK_LCD_GATE,
+
+ LPC32XX_CLK_HW_MAX,
+ LPC32XX_CLK_MAX = LPC32XX_CLK_SYSCLK_ARM_MUX + 1,
+ LPC32XX_CLK_CCF_MAX = LPC32XX_CLK_USB_AHB + 1,
+};
+
+static struct clk *clk[LPC32XX_CLK_MAX];
+static struct clk_onecell_data clk_data = {
+ .clks = clk,
+ .clk_num = LPC32XX_CLK_MAX,
+};
+
+static struct clk *usb_clk[LPC32XX_USB_CLK_MAX];
+static struct clk_onecell_data usb_clk_data = {
+ .clks = usb_clk,
+ .clk_num = LPC32XX_USB_CLK_MAX,
+};
+
+#define LPC32XX_CLK_PARENTS_MAX 5
+
+struct clk_proto_t {
+ const char *name;
+ const u8 parents[LPC32XX_CLK_PARENTS_MAX];
+ u8 num_parents;
+ unsigned long flags;
+};
+
+#define CLK_PREFIX(LITERAL) LPC32XX_CLK_ ## LITERAL
+#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+
+#define LPC32XX_CLK_DEFINE(_idx, _name, _flags, ...) \
+ [CLK_PREFIX(_idx)] = { \
+ .name = _name, \
+ .flags = _flags, \
+ .parents = { __VA_ARGS__ }, \
+ .num_parents = NUMARGS(__VA_ARGS__), \
+ }
+
+static const struct clk_proto_t clk_proto[LPC32XX_CLK_CCF_MAX] __initconst = {
+ LPC32XX_CLK_DEFINE(XTAL, "xtal", 0x0),
+ LPC32XX_CLK_DEFINE(XTAL_32K, "xtal_32k", 0x0),
+
+ LPC32XX_CLK_DEFINE(RTC, "rtc", 0x0, LPC32XX_CLK_XTAL_32K),
+ LPC32XX_CLK_DEFINE(OSC, "osc", CLK_IGNORE_UNUSED, LPC32XX_CLK_XTAL),
+ LPC32XX_CLK_DEFINE(SYS, "sys", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_OSC, LPC32XX_CLK_PLL397X),
+ LPC32XX_CLK_DEFINE(PLL397X, "pll_397x", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_RTC),
+ LPC32XX_CLK_DEFINE(HCLK_PLL, "hclk_pll", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYS),
+ LPC32XX_CLK_DEFINE(HCLK_DIV_PERIPH, "hclk_div_periph",
+ CLK_IGNORE_UNUSED, LPC32XX_CLK_HCLK_PLL),
+ LPC32XX_CLK_DEFINE(HCLK_DIV, "hclk_div", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_HCLK_PLL),
+ LPC32XX_CLK_DEFINE(HCLK, "hclk", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_PERIPH_HCLK_MUX),
+ LPC32XX_CLK_DEFINE(PERIPH, "pclk", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYSCLK_PERIPH_MUX),
+ LPC32XX_CLK_DEFINE(ARM, "arm", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_PERIPH_ARM_MUX),
+
+ LPC32XX_CLK_DEFINE(PERIPH_HCLK_MUX, "periph_hclk_mux",
+ CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYSCLK_HCLK_MUX, LPC32XX_CLK_SYSCLK_PERIPH_MUX),
+ LPC32XX_CLK_DEFINE(PERIPH_ARM_MUX, "periph_arm_mux", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYSCLK_ARM_MUX, LPC32XX_CLK_SYSCLK_PERIPH_MUX),
+ LPC32XX_CLK_DEFINE(SYSCLK_PERIPH_MUX, "sysclk_periph_mux",
+ CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYS, LPC32XX_CLK_HCLK_DIV_PERIPH),
+ LPC32XX_CLK_DEFINE(SYSCLK_HCLK_MUX, "sysclk_hclk_mux",
+ CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYS, LPC32XX_CLK_HCLK_DIV),
+ LPC32XX_CLK_DEFINE(SYSCLK_ARM_MUX, "sysclk_arm_mux", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_SYS, LPC32XX_CLK_HCLK_PLL),
+
+ LPC32XX_CLK_DEFINE(ARM_VFP, "vfp9", CLK_IGNORE_UNUSED,
+ LPC32XX_CLK_ARM),
+ LPC32XX_CLK_DEFINE(USB_PLL, "usb_pll",
+ CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, LPC32XX_CLK_USB_DIV),
+ LPC32XX_CLK_DEFINE(USB_DIV, "usb_div", 0x0, LPC32XX_CLK_OSC),
+ LPC32XX_CLK_DEFINE(USB, "usb", 0x0, LPC32XX_CLK_USB_PLL),
+ LPC32XX_CLK_DEFINE(DMA, "dma", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(MLC, "mlc", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(SLC, "slc", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(LCD, "lcd", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(MAC, "mac", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(SD, "sd", 0x0, LPC32XX_CLK_ARM),
+ LPC32XX_CLK_DEFINE(DDRAM, "ddram", CLK_GET_RATE_NOCACHE,
+ LPC32XX_CLK_SYSCLK_ARM_MUX),
+ LPC32XX_CLK_DEFINE(SSP0, "ssp0", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(SSP1, "ssp1", 0x0, LPC32XX_CLK_HCLK),
+
+ /*
+ * CLK_GET_RATE_NOCACHE is needed, if UART clock is disabled, its
+ * divider register does not contain information about selected rate.
+ */
+ LPC32XX_CLK_DEFINE(UART3, "uart3", CLK_GET_RATE_NOCACHE,
+ LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(UART4, "uart4", CLK_GET_RATE_NOCACHE,
+ LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(UART5, "uart5", CLK_GET_RATE_NOCACHE,
+ LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(UART6, "uart6", CLK_GET_RATE_NOCACHE,
+ LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(IRDA, "irda", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(I2C1, "i2c1", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(I2C2, "i2c2", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(TIMER0, "timer0", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(TIMER1, "timer1", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(TIMER2, "timer2", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(TIMER3, "timer3", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(TIMER4, "timer4", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(TIMER5, "timer5", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(WDOG, "watchdog", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(I2S0, "i2s0", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(I2S1, "i2s1", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(SPI1, "spi1", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(SPI2, "spi2", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(MCPWM, "mcpwm", 0x0, LPC32XX_CLK_HCLK),
+ LPC32XX_CLK_DEFINE(HSTIMER, "hstimer", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(KEY, "key", 0x0, LPC32XX_CLK_RTC),
+ LPC32XX_CLK_DEFINE(PWM1, "pwm1", 0x0,
+ LPC32XX_CLK_RTC, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(PWM2, "pwm2", 0x0,
+ LPC32XX_CLK_RTC, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(ADC, "adc", 0x0,
+ LPC32XX_CLK_ADC_RTC, LPC32XX_CLK_ADC_DIV),
+ LPC32XX_CLK_DEFINE(ADC_DIV, "adc_div", 0x0, LPC32XX_CLK_PERIPH),
+ LPC32XX_CLK_DEFINE(ADC_RTC, "adc_rtc", 0x0, LPC32XX_CLK_RTC),
+ LPC32XX_CLK_DEFINE(TEST1, "test1", 0x0,
+ LPC32XX_CLK_PERIPH, LPC32XX_CLK_RTC, LPC32XX_CLK_OSC),
+ LPC32XX_CLK_DEFINE(TEST2, "test2", 0x0,
+ LPC32XX_CLK_HCLK, LPC32XX_CLK_PERIPH, LPC32XX_CLK_USB,
+ LPC32XX_CLK_OSC, LPC32XX_CLK_PLL397X),
+
+ /* USB controller clocks */
+ LPC32XX_CLK_DEFINE(USB_AHB, "usb_ahb", 0x0, LPC32XX_CLK_USB),
+ LPC32XX_CLK_DEFINE(USB_OTG, "usb_otg", 0x0, LPC32XX_CLK_USB_AHB),
+ LPC32XX_CLK_DEFINE(USB_I2C, "usb_i2c", 0x0, LPC32XX_CLK_USB_AHB),
+ LPC32XX_CLK_DEFINE(USB_DEV, "usb_dev", 0x0, LPC32XX_CLK_USB_OTG),
+ LPC32XX_CLK_DEFINE(USB_HOST, "usb_host", 0x0, LPC32XX_CLK_USB_OTG),
+};
+
+struct lpc32xx_clk {
+ struct clk_hw hw;
+ u32 reg;
+ u32 enable;
+ u32 enable_mask;
+ u32 disable;
+ u32 disable_mask;
+ u32 busy;
+ u32 busy_mask;
+};
+
+enum clk_pll_mode {
+ PLL_UNKNOWN,
+ PLL_DIRECT,
+ PLL_BYPASS,
+ PLL_DIRECT_BYPASS,
+ PLL_INTEGER,
+ PLL_NON_INTEGER,
+};
+
+struct lpc32xx_pll_clk {
+ struct clk_hw hw;
+ u32 reg;
+ u32 enable;
+ unsigned long m_div;
+ unsigned long n_div;
+ unsigned long p_div;
+ enum clk_pll_mode mode;
+};
+
+struct lpc32xx_usb_clk {
+ struct clk_hw hw;
+ u32 ctrl_enable;
+ u32 ctrl_disable;
+ u32 ctrl_mask;
+ u32 enable;
+ u32 busy;
+};
+
+struct lpc32xx_clk_mux {
+ struct clk_hw hw;
+ u32 reg;
+ u32 mask;
+ u8 shift;
+ u32 *table;
+ u8 flags;
+};
+
+struct lpc32xx_clk_div {
+ struct clk_hw hw;
+ u32 reg;
+ u8 shift;
+ u8 width;
+ const struct clk_div_table *table;
+ u8 flags;
+};
+
+struct lpc32xx_clk_gate {
+ struct clk_hw hw;
+ u32 reg;
+ u8 bit_idx;
+ u8 flags;
+};
+
+#define to_lpc32xx_clk(_hw) container_of(_hw, struct lpc32xx_clk, hw)
+#define to_lpc32xx_pll_clk(_hw) container_of(_hw, struct lpc32xx_pll_clk, hw)
+#define to_lpc32xx_usb_clk(_hw) container_of(_hw, struct lpc32xx_usb_clk, hw)
+#define to_lpc32xx_mux(_hw) container_of(_hw, struct lpc32xx_clk_mux, hw)
+#define to_lpc32xx_div(_hw) container_of(_hw, struct lpc32xx_clk_div, hw)
+#define to_lpc32xx_gate(_hw) container_of(_hw, struct lpc32xx_clk_gate, hw)
+
+static inline bool pll_is_valid(u64 val0, u64 val1, u64 min, u64 max)
+{
+ return (val0 >= (val1 * min) && val0 <= (val1 * max));
+}
+
+static inline u32 lpc32xx_usb_clk_read(struct lpc32xx_usb_clk *clk)
+{
+ return readl(usb_clk_vbase + LPC32XX_USB_CLK_STS);
+}
+
+static inline void lpc32xx_usb_clk_write(struct lpc32xx_usb_clk *clk, u32 val)
+{
+ writel(val, usb_clk_vbase + LPC32XX_USB_CLK_CTRL);
+}
+
+static int clk_mask_enable(struct clk_hw *hw)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+ u32 val;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+
+ if (clk->busy_mask && (val & clk->busy_mask) == clk->busy)
+ return -EBUSY;
+
+ return regmap_update_bits(clk_regmap, clk->reg,
+ clk->enable_mask, clk->enable);
+}
+
+static void clk_mask_disable(struct clk_hw *hw)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+
+ regmap_update_bits(clk_regmap, clk->reg,
+ clk->disable_mask, clk->disable);
+}
+
+static int clk_mask_is_enabled(struct clk_hw *hw)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+ u32 val;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+
+ return ((val & clk->enable_mask) == clk->enable);
+}
+
+static const struct clk_ops clk_mask_ops = {
+ .enable = clk_mask_enable,
+ .disable = clk_mask_disable,
+ .is_enabled = clk_mask_is_enabled,
+};
+
+static int clk_pll_enable(struct clk_hw *hw)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+ u32 val, count;
+
+ regmap_update_bits(clk_regmap, clk->reg, clk->enable, clk->enable);
+
+ for (count = 0; count < 1000; count++) {
+ regmap_read(clk_regmap, clk->reg, &val);
+ if (val & PLL_CTRL_LOCK)
+ break;
+ }
+
+ if (val & PLL_CTRL_LOCK)
+ return 0;
+
+ return -ETIMEDOUT;
+}
+
+static void clk_pll_disable(struct clk_hw *hw)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+
+ regmap_update_bits(clk_regmap, clk->reg, clk->enable, 0x0);
+}
+
+static int clk_pll_is_enabled(struct clk_hw *hw)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+ u32 val;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+
+ val &= clk->enable | PLL_CTRL_LOCK;
+ if (val == (clk->enable | PLL_CTRL_LOCK))
+ return 1;
+
+ return 0;
+}
+
+static unsigned long clk_pll_397x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate * 397;
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+ bool is_direct, is_bypass, is_feedback;
+ unsigned long rate, cco_rate, ref_rate;
+ u32 val;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+ is_direct = val & PLL_CTRL_DIRECT;
+ is_bypass = val & PLL_CTRL_BYPASS;
+ is_feedback = val & PLL_CTRL_FEEDBACK;
+
+ clk->m_div = ((val & PLL_CTRL_FEEDDIV) >> 1) + 1;
+ clk->n_div = ((val & PLL_CTRL_PREDIV) >> 9) + 1;
+ clk->p_div = ((val & PLL_CTRL_POSTDIV) >> 11) + 1;
+
+ if (is_direct && is_bypass) {
+ clk->p_div = 0;
+ clk->mode = PLL_DIRECT_BYPASS;
+ return parent_rate;
+ }
+ if (is_bypass) {
+ clk->mode = PLL_BYPASS;
+ return parent_rate / (1 << clk->p_div);
+ }
+ if (is_direct) {
+ clk->p_div = 0;
+ clk->mode = PLL_DIRECT;
+ }
+
+ ref_rate = parent_rate / clk->n_div;
+ rate = cco_rate = ref_rate * clk->m_div;
+
+ if (!is_direct) {
+ if (is_feedback) {
+ cco_rate *= (1 << clk->p_div);
+ clk->mode = PLL_INTEGER;
+ } else {
+ rate /= (1 << clk->p_div);
+ clk->mode = PLL_NON_INTEGER;
+ }
+ }
+
+ pr_debug("%s: %lu: 0x%x: %d/%d/%d, %lu/%lu/%d => %lu\n",
+ clk_hw_get_name(hw),
+ parent_rate, val, is_direct, is_bypass, is_feedback,
+ clk->n_div, clk->m_div, (1 << clk->p_div), rate);
+
+ if (clk_pll_is_enabled(hw) &&
+ !(pll_is_valid(parent_rate, 1, 1000000, 20000000)
+ && pll_is_valid(cco_rate, 1, 156000000, 320000000)
+ && pll_is_valid(ref_rate, 1, 1000000, 27000000)))
+ pr_err("%s: PLL clocks are not in valid ranges: %lu/%lu/%lu",
+ clk_hw_get_name(hw),
+ parent_rate, cco_rate, ref_rate);
+
+ return rate;
+}
+
+static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+ u32 val;
+ unsigned long new_rate;
+
+ /* Validate PLL clock parameters computed on round rate stage */
+ switch (clk->mode) {
+ case PLL_DIRECT:
+ val = PLL_CTRL_DIRECT;
+ val |= (clk->m_div - 1) << 1;
+ val |= (clk->n_div - 1) << 9;
+ new_rate = (parent_rate * clk->m_div) / clk->n_div;
+ break;
+ case PLL_BYPASS:
+ val = PLL_CTRL_BYPASS;
+ val |= (clk->p_div - 1) << 11;
+ new_rate = parent_rate / (1 << (clk->p_div));
+ break;
+ case PLL_DIRECT_BYPASS:
+ val = PLL_CTRL_DIRECT | PLL_CTRL_BYPASS;
+ new_rate = parent_rate;
+ break;
+ case PLL_INTEGER:
+ val = PLL_CTRL_FEEDBACK;
+ val |= (clk->m_div - 1) << 1;
+ val |= (clk->n_div - 1) << 9;
+ val |= (clk->p_div - 1) << 11;
+ new_rate = (parent_rate * clk->m_div) / clk->n_div;
+ break;
+ case PLL_NON_INTEGER:
+ val = 0x0;
+ val |= (clk->m_div - 1) << 1;
+ val |= (clk->n_div - 1) << 9;
+ val |= (clk->p_div - 1) << 11;
+ new_rate = (parent_rate * clk->m_div) /
+ (clk->n_div * (1 << clk->p_div));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Sanity check that round rate is equal to the requested one */
+ if (new_rate != rate)
+ return -EINVAL;
+
+ return regmap_update_bits(clk_regmap, clk->reg, 0x1FFFF, val);
+}
+
+static long clk_hclk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+ u64 m_i, m, n, p, o = rate, i = *parent_rate, d = (u64)rate << 6;
+ int p_i, n_i;
+
+ pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), *parent_rate, rate);
+
+ if (rate > 266500000)
+ return -EINVAL;
+
+ /* Have to check all 20 possibilities to find the minimal M */
+ for (p_i = 4; p_i >= 0; p_i--) {
+ for (n_i = 4; n_i > 0; n_i--) {
+ m_i = div64_u64(o * n_i * (1 << p_i), i);
+
+ /* Check for valid PLL parameter constraints */
+ if (!(m_i && m_i <= 256
+ && pll_is_valid(i, n_i, 1000000, 27000000)
+ && pll_is_valid(i * m_i * (1 << p_i), n_i,
+ 156000000, 320000000)))
+ continue;
+
+ /* Store some intermediate valid parameters */
+ if (o * n_i * (1 << p_i) - i * m_i <= d) {
+ m = m_i;
+ n = n_i;
+ p = p_i;
+ d = o * n_i * (1 << p_i) - i * m_i;
+ }
+ }
+ }
+
+ if (d == (u64)rate << 6) {
+ pr_err("%s: %lu: no valid PLL parameters are found\n",
+ clk_hw_get_name(hw), rate);
+ return -EINVAL;
+ }
+
+ clk->m_div = m;
+ clk->n_div = n;
+ clk->p_div = p;
+
+ /* Set only direct or non-integer mode of PLL */
+ if (!p)
+ clk->mode = PLL_DIRECT;
+ else
+ clk->mode = PLL_NON_INTEGER;
+
+ o = div64_u64(i * m, n * (1 << p));
+
+ if (!d)
+ pr_debug("%s: %lu: found exact match: %llu/%llu/%llu\n",
+ clk_hw_get_name(hw), rate, m, n, p);
+ else
+ pr_debug("%s: %lu: found closest: %llu/%llu/%llu - %llu\n",
+ clk_hw_get_name(hw), rate, m, n, p, o);
+
+ return o;
+}
+
+static long clk_usb_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+ struct clk_hw *usb_div_hw, *osc_hw;
+ u64 d_i, n_i, m, o;
+
+ pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), *parent_rate, rate);
+
+ /*
+ * The only supported USB clock is 48MHz, with PLL internal constraints
+ * on Fclkin, Fcco and Fref this implies that Fcco must be 192MHz
+ * and post-divider must be 4, this slightly simplifies calculation of
+ * USB divider, USB PLL N and M parameters.
+ */
+ if (rate != 48000000)
+ return -EINVAL;
+
+ /* USB divider clock */
+ usb_div_hw = clk_hw_get_parent_by_index(hw, 0);
+ if (!usb_div_hw)
+ return -EINVAL;
+
+ /* Main oscillator clock */
+ osc_hw = clk_hw_get_parent_by_index(usb_div_hw, 0);
+ if (!osc_hw)
+ return -EINVAL;
+ o = clk_hw_get_rate(osc_hw); /* must be in range 1..20 MHz */
+
+ /* Check if valid USB divider and USB PLL parameters exists */
+ for (d_i = 16; d_i >= 1; d_i--) {
+ for (n_i = 1; n_i <= 4; n_i++) {
+ m = div64_u64(192000000 * d_i * n_i, o);
+ if (!(m && m <= 256
+ && m * o == 192000000 * d_i * n_i
+ && pll_is_valid(o, d_i, 1000000, 20000000)
+ && pll_is_valid(o, d_i * n_i, 1000000, 27000000)))
+ continue;
+
+ clk->n_div = n_i;
+ clk->m_div = m;
+ clk->p_div = 2;
+ clk->mode = PLL_NON_INTEGER;
+ *parent_rate = div64_u64(o, d_i);
+
+ return rate;
+ }
+ }
+
+ return -EINVAL;
+}
+
+#define LPC32XX_DEFINE_PLL_OPS(_name, _rc, _sr, _rr) \
+ static const struct clk_ops clk_ ##_name ## _ops = { \
+ .enable = clk_pll_enable, \
+ .disable = clk_pll_disable, \
+ .is_enabled = clk_pll_is_enabled, \
+ .recalc_rate = _rc, \
+ .set_rate = _sr, \
+ .round_rate = _rr, \
+ }
+
+LPC32XX_DEFINE_PLL_OPS(pll_397x, clk_pll_397x_recalc_rate, NULL, NULL);
+LPC32XX_DEFINE_PLL_OPS(hclk_pll, clk_pll_recalc_rate,
+ clk_pll_set_rate, clk_hclk_pll_round_rate);
+LPC32XX_DEFINE_PLL_OPS(usb_pll, clk_pll_recalc_rate,
+ clk_pll_set_rate, clk_usb_pll_round_rate);
+
+static int clk_ddram_is_enabled(struct clk_hw *hw)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+ u32 val;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+ val &= clk->enable_mask | clk->busy_mask;
+
+ return (val == (BIT(7) | BIT(0)) ||
+ val == (BIT(8) | BIT(1)));
+}
+
+static int clk_ddram_enable(struct clk_hw *hw)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+ u32 val, hclk_div;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+ hclk_div = val & clk->busy_mask;
+
+ /*
+ * DDRAM clock must be 2 times higher than HCLK,
+ * this implies DDRAM clock can not be enabled,
+ * if HCLK clock rate is equal to ARM clock rate
+ */
+ if (hclk_div == 0x0 || hclk_div == (BIT(1) | BIT(0)))
+ return -EINVAL;
+
+ return regmap_update_bits(clk_regmap, clk->reg,
+ clk->enable_mask, hclk_div << 7);
+}
+
+static unsigned long clk_ddram_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+ u32 val;
+
+ if (!clk_ddram_is_enabled(hw))
+ return 0;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+ val &= clk->enable_mask;
+
+ return parent_rate / (val >> 7);
+}
+
+static const struct clk_ops clk_ddram_ops = {
+ .enable = clk_ddram_enable,
+ .disable = clk_mask_disable,
+ .is_enabled = clk_ddram_is_enabled,
+ .recalc_rate = clk_ddram_recalc_rate,
+};
+
+static unsigned long lpc32xx_clk_uart_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+ u32 val, x, y;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+ x = (val & 0xFF00) >> 8;
+ y = val & 0xFF;
+
+ if (x && y)
+ return (parent_rate * x) / y;
+ else
+ return 0;
+}
+
+static const struct clk_ops lpc32xx_uart_div_ops = {
+ .recalc_rate = lpc32xx_clk_uart_recalc_rate,
+};
+
+static const struct clk_div_table clk_hclk_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 4 },
+ { },
+};
+
+static u32 test1_mux_table[] = { 0, 1, 2, };
+static u32 test2_mux_table[] = { 0, 1, 2, 5, 7, };
+
+static int clk_usb_enable(struct clk_hw *hw)
+{
+ struct lpc32xx_usb_clk *clk = to_lpc32xx_usb_clk(hw);
+ u32 val, ctrl_val, count;
+
+ pr_debug("%s: 0x%x\n", clk_hw_get_name(hw), clk->enable);
+
+ if (clk->ctrl_mask) {
+ regmap_read(clk_regmap, LPC32XX_CLKPWR_USB_CTRL, &ctrl_val);
+ regmap_update_bits(clk_regmap, LPC32XX_CLKPWR_USB_CTRL,
+ clk->ctrl_mask, clk->ctrl_enable);
+ }
+
+ val = lpc32xx_usb_clk_read(clk);
+ if (clk->busy && (val & clk->busy) == clk->busy) {
+ if (clk->ctrl_mask)
+ regmap_write(clk_regmap, LPC32XX_CLKPWR_USB_CTRL,
+ ctrl_val);
+ return -EBUSY;
+ }
+
+ val |= clk->enable;
+ lpc32xx_usb_clk_write(clk, val);
+
+ for (count = 0; count < 1000; count++) {
+ val = lpc32xx_usb_clk_read(clk);
+ if ((val & clk->enable) == clk->enable)
+ break;
+ }
+
+ if ((val & clk->enable) == clk->enable)
+ return 0;
+
+ if (clk->ctrl_mask)
+ regmap_write(clk_regmap, LPC32XX_CLKPWR_USB_CTRL, ctrl_val);
+
+ return -ETIMEDOUT;
+}
+
+static void clk_usb_disable(struct clk_hw *hw)
+{
+ struct lpc32xx_usb_clk *clk = to_lpc32xx_usb_clk(hw);
+ u32 val = lpc32xx_usb_clk_read(clk);
+
+ val &= ~clk->enable;
+ lpc32xx_usb_clk_write(clk, val);
+
+ if (clk->ctrl_mask)
+ regmap_update_bits(clk_regmap, LPC32XX_CLKPWR_USB_CTRL,
+ clk->ctrl_mask, clk->ctrl_disable);
+}
+
+static int clk_usb_is_enabled(struct clk_hw *hw)
+{
+ struct lpc32xx_usb_clk *clk = to_lpc32xx_usb_clk(hw);
+ u32 ctrl_val, val;
+
+ if (clk->ctrl_mask) {
+ regmap_read(clk_regmap, LPC32XX_CLKPWR_USB_CTRL, &ctrl_val);
+ if ((ctrl_val & clk->ctrl_mask) != clk->ctrl_enable)
+ return 0;
+ }
+
+ val = lpc32xx_usb_clk_read(clk);
+
+ return ((val & clk->enable) == clk->enable);
+}
+
+static unsigned long clk_usb_i2c_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return clk_get_rate(clk[LPC32XX_CLK_PERIPH]);
+}
+
+static const struct clk_ops clk_usb_ops = {
+ .enable = clk_usb_enable,
+ .disable = clk_usb_disable,
+ .is_enabled = clk_usb_is_enabled,
+};
+
+static const struct clk_ops clk_usb_i2c_ops = {
+ .enable = clk_usb_enable,
+ .disable = clk_usb_disable,
+ .is_enabled = clk_usb_is_enabled,
+ .recalc_rate = clk_usb_i2c_recalc_rate,
+};
+
+static int clk_gate_enable(struct clk_hw *hw)
+{
+ struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
+ u32 mask = BIT(clk->bit_idx);
+ u32 val = (clk->flags & CLK_GATE_SET_TO_DISABLE ? 0x0 : mask);
+
+ return regmap_update_bits(clk_regmap, clk->reg, mask, val);
+}
+
+static void clk_gate_disable(struct clk_hw *hw)
+{
+ struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
+ u32 mask = BIT(clk->bit_idx);
+ u32 val = (clk->flags & CLK_GATE_SET_TO_DISABLE ? mask : 0x0);
+
+ regmap_update_bits(clk_regmap, clk->reg, mask, val);
+}
+
+static int clk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
+ u32 val;
+ bool is_set;
+
+ regmap_read(clk_regmap, clk->reg, &val);
+ is_set = val & BIT(clk->bit_idx);
+
+ return (clk->flags & CLK_GATE_SET_TO_DISABLE ? !is_set : is_set);
+}
+
+static const struct clk_ops lpc32xx_clk_gate_ops = {
+ .enable = clk_gate_enable,
+ .disable = clk_gate_disable,
+ .is_enabled = clk_gate_is_enabled,
+};
+
+#define div_mask(width) ((1 << (width)) - 1)
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->val == val)
+ return clkt->div;
+ return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags, u8 width)
+{
+ if (flags & CLK_DIVIDER_ONE_BASED)
+ return val;
+ if (table)
+ return _get_table_div(table, val);
+ return val + 1;
+}
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw);
+ unsigned int val;
+
+ regmap_read(clk_regmap, divider->reg, &val);
+
+ val >>= divider->shift;
+ val &= div_mask(divider->width);
+
+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
+ divider->flags);
+}
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw);
+ unsigned int bestdiv;
+
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ regmap_read(clk_regmap, divider->reg, &bestdiv);
+ bestdiv >>= divider->shift;
+ bestdiv &= div_mask(divider->width);
+ bestdiv = _get_div(divider->table, bestdiv, divider->flags,
+ divider->width);
+ return DIV_ROUND_UP(*prate, bestdiv);
+ }
+
+ return divider_round_rate(hw, rate, prate, divider->table,
+ divider->width, divider->flags);
+}
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw);
+ unsigned int value;
+
+ value = divider_get_val(rate, parent_rate, divider->table,
+ divider->width, divider->flags);
+
+ return regmap_update_bits(clk_regmap, divider->reg,
+ div_mask(divider->width) << divider->shift,
+ value << divider->shift);
+}
+
+static const struct clk_ops lpc32xx_clk_divider_ops = {
+ .recalc_rate = clk_divider_recalc_rate,
+ .round_rate = clk_divider_round_rate,
+ .set_rate = clk_divider_set_rate,
+};
+
+static u8 clk_mux_get_parent(struct clk_hw *hw)
+{
+ struct lpc32xx_clk_mux *mux = to_lpc32xx_mux(hw);
+ u32 num_parents = clk_hw_get_num_parents(hw);
+ u32 val;
+
+ regmap_read(clk_regmap, mux->reg, &val);
+ val >>= mux->shift;
+ val &= mux->mask;
+
+ if (mux->table) {
+ u32 i;
+
+ for (i = 0; i < num_parents; i++)
+ if (mux->table[i] == val)
+ return i;
+ return -EINVAL;
+ }
+
+ if (val >= num_parents)
+ return -EINVAL;
+
+ return val;
+}
+
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct lpc32xx_clk_mux *mux = to_lpc32xx_mux(hw);
+
+ if (mux->table)
+ index = mux->table[index];
+
+ return regmap_update_bits(clk_regmap, mux->reg,
+ mux->mask << mux->shift, index << mux->shift);
+}
+
+static const struct clk_ops lpc32xx_clk_mux_ro_ops = {
+ .get_parent = clk_mux_get_parent,
+};
+
+static const struct clk_ops lpc32xx_clk_mux_ops = {
+ .get_parent = clk_mux_get_parent,
+ .set_parent = clk_mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
+
+enum lpc32xx_clk_type {
+ CLK_FIXED,
+ CLK_MUX,
+ CLK_DIV,
+ CLK_GATE,
+ CLK_COMPOSITE,
+ CLK_LPC32XX,
+ CLK_LPC32XX_PLL,
+ CLK_LPC32XX_USB,
+};
+
+struct clk_hw_proto0 {
+ const struct clk_ops *ops;
+ union {
+ struct lpc32xx_pll_clk pll;
+ struct lpc32xx_clk clk;
+ struct lpc32xx_usb_clk usb_clk;
+ struct lpc32xx_clk_mux mux;
+ struct lpc32xx_clk_div div;
+ struct lpc32xx_clk_gate gate;
+ };
+};
+
+struct clk_hw_proto1 {
+ struct clk_hw_proto0 *mux;
+ struct clk_hw_proto0 *div;
+ struct clk_hw_proto0 *gate;
+};
+
+struct clk_hw_proto {
+ enum lpc32xx_clk_type type;
+
+ union {
+ struct clk_fixed_rate f;
+ struct clk_hw_proto0 hw0;
+ struct clk_hw_proto1 hw1;
+ };
+};
+
+#define LPC32XX_DEFINE_FIXED(_idx, _rate, _flags) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_FIXED, \
+ { \
+ .f = { \
+ .fixed_rate = (_rate), \
+ .flags = (_flags), \
+ }, \
+ }, \
+}
+
+#define LPC32XX_DEFINE_PLL(_idx, _name, _reg, _enable) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_LPC32XX_PLL, \
+ { \
+ .hw0 = { \
+ .ops = &clk_ ##_name ## _ops, \
+ { \
+ .pll = { \
+ .reg = LPC32XX_CLKPWR_ ## _reg, \
+ .enable = (_enable), \
+ }, \
+ }, \
+ }, \
+ }, \
+}
+
+#define LPC32XX_DEFINE_MUX(_idx, _reg, _shift, _mask, _table, _flags) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_MUX, \
+ { \
+ .hw0 = { \
+ .ops = (_flags & CLK_MUX_READ_ONLY ? \
+ &lpc32xx_clk_mux_ro_ops : \
+ &lpc32xx_clk_mux_ops), \
+ { \
+ .mux = { \
+ .reg = LPC32XX_CLKPWR_ ## _reg, \
+ .mask = (_mask), \
+ .shift = (_shift), \
+ .table = (_table), \
+ .flags = (_flags), \
+ }, \
+ }, \
+ }, \
+ }, \
+}
+
+#define LPC32XX_DEFINE_DIV(_idx, _reg, _shift, _width, _table, _flags) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_DIV, \
+ { \
+ .hw0 = { \
+ .ops = &lpc32xx_clk_divider_ops, \
+ { \
+ .div = { \
+ .reg = LPC32XX_CLKPWR_ ## _reg, \
+ .shift = (_shift), \
+ .width = (_width), \
+ .table = (_table), \
+ .flags = (_flags), \
+ }, \
+ }, \
+ }, \
+ }, \
+}
+
+#define LPC32XX_DEFINE_GATE(_idx, _reg, _bit, _flags) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_GATE, \
+ { \
+ .hw0 = { \
+ .ops = &lpc32xx_clk_gate_ops, \
+ { \
+ .gate = { \
+ .reg = LPC32XX_CLKPWR_ ## _reg, \
+ .bit_idx = (_bit), \
+ .flags = (_flags), \
+ }, \
+ }, \
+ }, \
+ }, \
+}
+
+#define LPC32XX_DEFINE_CLK(_idx, _reg, _e, _em, _d, _dm, _b, _bm, _ops) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_LPC32XX, \
+ { \
+ .hw0 = { \
+ .ops = &(_ops), \
+ { \
+ .clk = { \
+ .reg = LPC32XX_CLKPWR_ ## _reg, \
+ .enable = (_e), \
+ .enable_mask = (_em), \
+ .disable = (_d), \
+ .disable_mask = (_dm), \
+ .busy = (_b), \
+ .busy_mask = (_bm), \
+ }, \
+ }, \
+ }, \
+ }, \
+}
+
+#define LPC32XX_DEFINE_USB(_idx, _ce, _cd, _cm, _e, _b, _ops) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_LPC32XX_USB, \
+ { \
+ .hw0 = { \
+ .ops = &(_ops), \
+ { \
+ .usb_clk = { \
+ .ctrl_enable = (_ce), \
+ .ctrl_disable = (_cd), \
+ .ctrl_mask = (_cm), \
+ .enable = (_e), \
+ .busy = (_b), \
+ } \
+ }, \
+ } \
+ }, \
+}
+
+#define LPC32XX_DEFINE_COMPOSITE(_idx, _mux, _div, _gate) \
+[CLK_PREFIX(_idx)] = { \
+ .type = CLK_COMPOSITE, \
+ { \
+ .hw1 = { \
+ .mux = (CLK_PREFIX(_mux) == LPC32XX_CLK__NULL ? NULL : \
+ &clk_hw_proto[CLK_PREFIX(_mux)].hw0), \
+ .div = (CLK_PREFIX(_div) == LPC32XX_CLK__NULL ? NULL : \
+ &clk_hw_proto[CLK_PREFIX(_div)].hw0), \
+ .gate = (CLK_PREFIX(_gate) == LPC32XX_CLK__NULL ? NULL :\
+ &clk_hw_proto[CLK_PREFIX(_gate)].hw0), \
+ }, \
+ }, \
+}
+
+static struct clk_hw_proto clk_hw_proto[LPC32XX_CLK_HW_MAX] = {
+ LPC32XX_DEFINE_FIXED(RTC, 32768, 0),
+ LPC32XX_DEFINE_PLL(PLL397X, pll_397x, HCLKPLL_CTRL, BIT(1)),
+ LPC32XX_DEFINE_PLL(HCLK_PLL, hclk_pll, HCLKPLL_CTRL, PLL_CTRL_ENABLE),
+ LPC32XX_DEFINE_PLL(USB_PLL, usb_pll, USB_CTRL, PLL_CTRL_ENABLE),
+ LPC32XX_DEFINE_GATE(OSC, OSC_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+ LPC32XX_DEFINE_GATE(USB, USB_CTRL, 18, 0),
+
+ LPC32XX_DEFINE_DIV(HCLK_DIV_PERIPH, HCLKDIV_CTRL, 2, 5, NULL,
+ CLK_DIVIDER_READ_ONLY),
+ LPC32XX_DEFINE_DIV(HCLK_DIV, HCLKDIV_CTRL, 0, 2, clk_hclk_div_table,
+ CLK_DIVIDER_READ_ONLY),
+
+ /* Register 3 read-only muxes with a single control PWR_CTRL[2] */
+ LPC32XX_DEFINE_MUX(SYSCLK_PERIPH_MUX, PWR_CTRL, 2, 0x1, NULL,
+ CLK_MUX_READ_ONLY),
+ LPC32XX_DEFINE_MUX(SYSCLK_HCLK_MUX, PWR_CTRL, 2, 0x1, NULL,
+ CLK_MUX_READ_ONLY),
+ LPC32XX_DEFINE_MUX(SYSCLK_ARM_MUX, PWR_CTRL, 2, 0x1, NULL,
+ CLK_MUX_READ_ONLY),
+ /* Register 2 read-only muxes with a single control PWR_CTRL[10] */
+ LPC32XX_DEFINE_MUX(PERIPH_HCLK_MUX, PWR_CTRL, 10, 0x1, NULL,
+ CLK_MUX_READ_ONLY),
+ LPC32XX_DEFINE_MUX(PERIPH_ARM_MUX, PWR_CTRL, 10, 0x1, NULL,
+ CLK_MUX_READ_ONLY),
+
+ /* 3 always on gates with a single control PWR_CTRL[0] same as OSC */
+ LPC32XX_DEFINE_GATE(PERIPH, PWR_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+ LPC32XX_DEFINE_GATE(HCLK, PWR_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+ LPC32XX_DEFINE_GATE(ARM, PWR_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+
+ LPC32XX_DEFINE_GATE(ARM_VFP, DEBUG_CTRL, 4, 0),
+ LPC32XX_DEFINE_GATE(DMA, DMA_CLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_CLK(DDRAM, HCLKDIV_CTRL, 0x0, BIT(8) | BIT(7),
+ 0x0, BIT(8) | BIT(7), 0x0, BIT(1) | BIT(0), clk_ddram_ops),
+
+ LPC32XX_DEFINE_GATE(TIMER0, TIMCLK_CTRL1, 2, 0),
+ LPC32XX_DEFINE_GATE(TIMER1, TIMCLK_CTRL1, 3, 0),
+ LPC32XX_DEFINE_GATE(TIMER2, TIMCLK_CTRL1, 4, 0),
+ LPC32XX_DEFINE_GATE(TIMER3, TIMCLK_CTRL1, 5, 0),
+ LPC32XX_DEFINE_GATE(TIMER4, TIMCLK_CTRL1, 0, 0),
+ LPC32XX_DEFINE_GATE(TIMER5, TIMCLK_CTRL1, 1, 0),
+
+ LPC32XX_DEFINE_GATE(SSP0, SSP_CTRL, 0, 0),
+ LPC32XX_DEFINE_GATE(SSP1, SSP_CTRL, 1, 0),
+ LPC32XX_DEFINE_GATE(SPI1, SPI_CTRL, 0, 0),
+ LPC32XX_DEFINE_GATE(SPI2, SPI_CTRL, 4, 0),
+ LPC32XX_DEFINE_GATE(I2S0, I2S_CTRL, 0, 0),
+ LPC32XX_DEFINE_GATE(I2S1, I2S_CTRL, 1, 0),
+ LPC32XX_DEFINE_GATE(I2C1, I2CCLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_GATE(I2C2, I2CCLK_CTRL, 1, 0),
+ LPC32XX_DEFINE_GATE(WDOG, TIMCLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_GATE(HSTIMER, TIMCLK_CTRL, 1, 0),
+
+ LPC32XX_DEFINE_GATE(KEY, KEYCLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_GATE(MCPWM, TIMCLK_CTRL1, 6, 0),
+
+ LPC32XX_DEFINE_MUX(PWM1_MUX, PWMCLK_CTRL, 1, 0x1, NULL, 0),
+ LPC32XX_DEFINE_DIV(PWM1_DIV, PWMCLK_CTRL, 4, 4, NULL,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+ LPC32XX_DEFINE_GATE(PWM1_GATE, PWMCLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_COMPOSITE(PWM1, PWM1_MUX, PWM1_DIV, PWM1_GATE),
+
+ LPC32XX_DEFINE_MUX(PWM2_MUX, PWMCLK_CTRL, 3, 0x1, NULL, 0),
+ LPC32XX_DEFINE_DIV(PWM2_DIV, PWMCLK_CTRL, 8, 4, NULL,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+ LPC32XX_DEFINE_GATE(PWM2_GATE, PWMCLK_CTRL, 2, 0),
+ LPC32XX_DEFINE_COMPOSITE(PWM2, PWM2_MUX, PWM2_DIV, PWM2_GATE),
+
+ LPC32XX_DEFINE_MUX(UART3_MUX, UART3_CLK_CTRL, 16, 0x1, NULL, 0),
+ LPC32XX_DEFINE_CLK(UART3_DIV, UART3_CLK_CTRL,
+ 0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+ LPC32XX_DEFINE_GATE(UART3_GATE, UART_CLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_COMPOSITE(UART3, UART3_MUX, UART3_DIV, UART3_GATE),
+
+ LPC32XX_DEFINE_MUX(UART4_MUX, UART4_CLK_CTRL, 16, 0x1, NULL, 0),
+ LPC32XX_DEFINE_CLK(UART4_DIV, UART4_CLK_CTRL,
+ 0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+ LPC32XX_DEFINE_GATE(UART4_GATE, UART_CLK_CTRL, 1, 0),
+ LPC32XX_DEFINE_COMPOSITE(UART4, UART4_MUX, UART4_DIV, UART4_GATE),
+
+ LPC32XX_DEFINE_MUX(UART5_MUX, UART5_CLK_CTRL, 16, 0x1, NULL, 0),
+ LPC32XX_DEFINE_CLK(UART5_DIV, UART5_CLK_CTRL,
+ 0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+ LPC32XX_DEFINE_GATE(UART5_GATE, UART_CLK_CTRL, 2, 0),
+ LPC32XX_DEFINE_COMPOSITE(UART5, UART5_MUX, UART5_DIV, UART5_GATE),
+
+ LPC32XX_DEFINE_MUX(UART6_MUX, UART6_CLK_CTRL, 16, 0x1, NULL, 0),
+ LPC32XX_DEFINE_CLK(UART6_DIV, UART6_CLK_CTRL,
+ 0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+ LPC32XX_DEFINE_GATE(UART6_GATE, UART_CLK_CTRL, 3, 0),
+ LPC32XX_DEFINE_COMPOSITE(UART6, UART6_MUX, UART6_DIV, UART6_GATE),
+
+ LPC32XX_DEFINE_CLK(IRDA, IRDA_CLK_CTRL,
+ 0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+
+ LPC32XX_DEFINE_MUX(TEST1_MUX, TEST_CLK_CTRL, 5, 0x3,
+ test1_mux_table, 0),
+ LPC32XX_DEFINE_GATE(TEST1_GATE, TEST_CLK_CTRL, 4, 0),
+ LPC32XX_DEFINE_COMPOSITE(TEST1, TEST1_MUX, _NULL, TEST1_GATE),
+
+ LPC32XX_DEFINE_MUX(TEST2_MUX, TEST_CLK_CTRL, 1, 0x7,
+ test2_mux_table, 0),
+ LPC32XX_DEFINE_GATE(TEST2_GATE, TEST_CLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_COMPOSITE(TEST2, TEST2_MUX, _NULL, TEST2_GATE),
+
+ LPC32XX_DEFINE_MUX(SYS, SYSCLK_CTRL, 0, 0x1, NULL, CLK_MUX_READ_ONLY),
+
+ LPC32XX_DEFINE_DIV(USB_DIV_DIV, USB_DIV, 0, 4, NULL, 0),
+ LPC32XX_DEFINE_GATE(USB_DIV_GATE, USB_CTRL, 17, 0),
+ LPC32XX_DEFINE_COMPOSITE(USB_DIV, _NULL, USB_DIV_DIV, USB_DIV_GATE),
+
+ LPC32XX_DEFINE_DIV(SD_DIV, MS_CTRL, 0, 4, NULL,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+ LPC32XX_DEFINE_CLK(SD_GATE, MS_CTRL, BIT(5) | BIT(9), BIT(5) | BIT(9),
+ 0x0, BIT(5) | BIT(9), 0x0, 0x0, clk_mask_ops),
+ LPC32XX_DEFINE_COMPOSITE(SD, _NULL, SD_DIV, SD_GATE),
+
+ LPC32XX_DEFINE_DIV(LCD_DIV, LCDCLK_CTRL, 0, 5, NULL, 0),
+ LPC32XX_DEFINE_GATE(LCD_GATE, LCDCLK_CTRL, 5, 0),
+ LPC32XX_DEFINE_COMPOSITE(LCD, _NULL, LCD_DIV, LCD_GATE),
+
+ LPC32XX_DEFINE_CLK(MAC, MACCLK_CTRL,
+ BIT(2) | BIT(1) | BIT(0), BIT(2) | BIT(1) | BIT(0),
+ BIT(2) | BIT(1) | BIT(0), BIT(2) | BIT(1) | BIT(0),
+ 0x0, 0x0, clk_mask_ops),
+ LPC32XX_DEFINE_CLK(SLC, FLASHCLK_CTRL,
+ BIT(2) | BIT(0), BIT(2) | BIT(0), 0x0,
+ BIT(0), BIT(1), BIT(2) | BIT(1), clk_mask_ops),
+ LPC32XX_DEFINE_CLK(MLC, FLASHCLK_CTRL,
+ BIT(1), BIT(2) | BIT(1), 0x0, BIT(1),
+ BIT(2) | BIT(0), BIT(2) | BIT(0), clk_mask_ops),
+ /*
+ * ADC/TS clock unfortunately cannot be registered as a composite one
+ * due to a different connection of gate, div and mux, e.g. gating it
+ * won't mean that the clock is off, if peripheral clock is its parent:
+ *
+ * rtc-->[gate]-->| |
+ * | mux |--> adc/ts
+ * pclk-->[div]-->| |
+ *
+ * Constraints:
+ * ADC --- resulting clock must be <= 4.5 MHz
+ * TS --- resulting clock must be <= 400 KHz
+ */
+ LPC32XX_DEFINE_DIV(ADC_DIV, ADCCLK_CTRL1, 0, 8, NULL, 0),
+ LPC32XX_DEFINE_GATE(ADC_RTC, ADCCLK_CTRL, 0, 0),
+ LPC32XX_DEFINE_MUX(ADC, ADCCLK_CTRL1, 8, 0x1, NULL, 0),
+
+ /* USB controller clocks */
+ LPC32XX_DEFINE_USB(USB_AHB,
+ BIT(24), 0x0, BIT(24), BIT(4), 0, clk_usb_ops),
+ LPC32XX_DEFINE_USB(USB_OTG,
+ 0x0, 0x0, 0x0, BIT(3), 0, clk_usb_ops),
+ LPC32XX_DEFINE_USB(USB_I2C,
+ 0x0, BIT(23), BIT(23), BIT(2), 0, clk_usb_i2c_ops),
+ LPC32XX_DEFINE_USB(USB_DEV,
+ BIT(22), 0x0, BIT(22), BIT(1), BIT(0), clk_usb_ops),
+ LPC32XX_DEFINE_USB(USB_HOST,
+ BIT(21), 0x0, BIT(21), BIT(0), BIT(1), clk_usb_ops),
+};
+
+static struct clk * __init lpc32xx_clk_register(u32 id)
+{
+ const struct clk_proto_t *lpc32xx_clk = &clk_proto[id];
+ struct clk_hw_proto *clk_hw = &clk_hw_proto[id];
+ const char *parents[LPC32XX_CLK_PARENTS_MAX];
+ struct clk *clk;
+ unsigned int i;
+
+ for (i = 0; i < lpc32xx_clk->num_parents; i++)
+ parents[i] = clk_proto[lpc32xx_clk->parents[i]].name;
+
+ pr_debug("%s: derived from '%s', clock type %d\n", lpc32xx_clk->name,
+ parents[0], clk_hw->type);
+
+ switch (clk_hw->type) {
+ case CLK_LPC32XX:
+ case CLK_LPC32XX_PLL:
+ case CLK_LPC32XX_USB:
+ case CLK_MUX:
+ case CLK_DIV:
+ case CLK_GATE:
+ {
+ struct clk_init_data clk_init = {
+ .name = lpc32xx_clk->name,
+ .parent_names = parents,
+ .num_parents = lpc32xx_clk->num_parents,
+ .flags = lpc32xx_clk->flags,
+ .ops = clk_hw->hw0.ops,
+ };
+ struct clk_hw *hw;
+
+ if (clk_hw->type == CLK_LPC32XX)
+ hw = &clk_hw->hw0.clk.hw;
+ else if (clk_hw->type == CLK_LPC32XX_PLL)
+ hw = &clk_hw->hw0.pll.hw;
+ else if (clk_hw->type == CLK_LPC32XX_USB)
+ hw = &clk_hw->hw0.usb_clk.hw;
+ else if (clk_hw->type == CLK_MUX)
+ hw = &clk_hw->hw0.mux.hw;
+ else if (clk_hw->type == CLK_DIV)
+ hw = &clk_hw->hw0.div.hw;
+ else if (clk_hw->type == CLK_GATE)
+ hw = &clk_hw->hw0.gate.hw;
+
+ hw->init = &clk_init;
+ clk = clk_register(NULL, hw);
+ break;
+ }
+ case CLK_COMPOSITE:
+ {
+ struct clk_hw *mux_hw = NULL, *div_hw = NULL, *gate_hw = NULL;
+ const struct clk_ops *mops = NULL, *dops = NULL, *gops = NULL;
+ struct clk_hw_proto0 *mux0, *div0, *gate0;
+
+ mux0 = clk_hw->hw1.mux;
+ div0 = clk_hw->hw1.div;
+ gate0 = clk_hw->hw1.gate;
+ if (mux0) {
+ mops = mux0->ops;
+ mux_hw = &mux0->clk.hw;
+ }
+ if (div0) {
+ dops = div0->ops;
+ div_hw = &div0->clk.hw;
+ }
+ if (gate0) {
+ gops = gate0->ops;
+ gate_hw = &gate0->clk.hw;
+ }
+
+ clk = clk_register_composite(NULL, lpc32xx_clk->name,
+ parents, lpc32xx_clk->num_parents,
+ mux_hw, mops, div_hw, dops,
+ gate_hw, gops, lpc32xx_clk->flags);
+ break;
+ }
+ case CLK_FIXED:
+ {
+ struct clk_fixed_rate *fixed = &clk_hw->f;
+
+ clk = clk_register_fixed_rate(NULL, lpc32xx_clk->name,
+ parents[0], fixed->flags, fixed->fixed_rate);
+ break;
+ }
+ default:
+ clk = ERR_PTR(-EINVAL);
+ }
+
+ return clk;
+}
+
+static void __init lpc32xx_clk_init(struct device_node *np)
+{
+ unsigned int i;
+ struct clk *clk_osc, *clk_32k;
+ void __iomem *base = NULL;
+
+ /* Ensure that parent clocks are available and valid */
+ clk_32k = of_clk_get_by_name(np, clk_proto[LPC32XX_CLK_XTAL_32K].name);
+ if (IS_ERR(clk_32k)) {
+ pr_err("failed to find external 32KHz clock: %ld\n",
+ PTR_ERR(clk_32k));
+ return;
+ }
+ if (clk_get_rate(clk_32k) != 32768) {
+ pr_err("invalid clock rate of external 32KHz oscillator");
+ return;
+ }
+
+ clk_osc = of_clk_get_by_name(np, clk_proto[LPC32XX_CLK_XTAL].name);
+ if (IS_ERR(clk_osc)) {
+ pr_err("failed to find external main oscillator clock: %ld\n",
+ PTR_ERR(clk_osc));
+ return;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("failed to map system control block registers\n");
+ return;
+ }
+
+ clk_regmap = regmap_init_mmio(NULL, base, &lpc32xx_scb_regmap_config);
+ if (IS_ERR(clk_regmap)) {
+ pr_err("failed to regmap system control block: %ld\n",
+ PTR_ERR(clk_regmap));
+ return;
+ }
+
+ for (i = 0; i < LPC32XX_CLK_MAX; i++) {
+ clk[i] = lpc32xx_clk_register(i);
+ if (IS_ERR(clk[i])) {
+ pr_err("failed to register %s clock: %ld\n",
+ clk_proto[i].name, PTR_ERR(clk[i]));
+ clk[i] = NULL;
+ }
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ /* For 13MHz osc valid output range of PLL is from 156MHz to 266.5MHz */
+ clk_set_rate(clk[LPC32XX_CLK_HCLK_PLL], 208000000);
+
+ /* Set 48MHz rate of USB PLL clock */
+ clk_set_rate(clk[LPC32XX_CLK_USB_PLL], 48000000);
+
+ /* These two clocks must be always on independently on consumers */
+ clk_prepare_enable(clk[LPC32XX_CLK_ARM]);
+ clk_prepare_enable(clk[LPC32XX_CLK_HCLK]);
+
+ /* Enable ARM VFP by default */
+ clk_prepare_enable(clk[LPC32XX_CLK_ARM_VFP]);
+
+ /* Disable enabled by default clocks for NAND MLC and SLC */
+ clk_mask_disable(&clk_hw_proto[LPC32XX_CLK_SLC].hw0.clk.hw);
+ clk_mask_disable(&clk_hw_proto[LPC32XX_CLK_MLC].hw0.clk.hw);
+}
+CLK_OF_DECLARE(lpc32xx_clk, "nxp,lpc3220-clk", lpc32xx_clk_init);
+
+static void __init lpc32xx_usb_clk_init(struct device_node *np)
+{
+ unsigned int i;
+
+ usb_clk_vbase = of_iomap(np, 0);
+ if (!usb_clk_vbase) {
+ pr_err("failed to map address range\n");
+ return;
+ }
+
+ for (i = 0; i < LPC32XX_USB_CLK_MAX; i++) {
+ usb_clk[i] = lpc32xx_clk_register(i + LPC32XX_CLK_USB_OFFSET);
+ if (IS_ERR(usb_clk[i])) {
+ pr_err("failed to register %s clock: %ld\n",
+ clk_proto[i].name, PTR_ERR(usb_clk[i]));
+ usb_clk[i] = NULL;
+ }
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &usb_clk_data);
+}
+CLK_OF_DECLARE(lpc32xx_usb_clk, "nxp,lpc3220-usb-clk", lpc32xx_usb_clk_init);
diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c
index 542e45ef5087..b7747229db9a 100644
--- a/drivers/clk/pxa/clk-pxa25x.c
+++ b/drivers/clk/pxa/clk-pxa25x.c
@@ -17,7 +17,6 @@
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <mach/pxa25x.h>
#include <mach/pxa2xx-regs.h>
#include <dt-bindings/clock/pxa-clock.h>
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index ee4c83aab4f4..b552eceec2be 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -106,3 +106,20 @@ config MSM_MMCC_8974
Support for the multimedia clock controller on msm8974 devices.
Say Y if you want to support multimedia devices such as display,
graphics, video encode/decode, camera, etc.
+
+config MSM_GCC_8996
+ tristate "MSM8996 Global Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the global clock controller on msm8996 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ i2c, USB, UFS, SD/eMMC, PCIe, etc.
+
+config MSM_MMCC_8996
+ tristate "MSM8996 Multimedia Clock Controller"
+ select MSM_GCC_8996
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the multimedia clock controller on msm8996 devices.
+ Say Y if you want to support multimedia devices such as display,
+ graphics, video encode/decode, camera, etc.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index fe6252349e55..dc4280b85db1 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o
clk-qcom-y += common.o
clk-qcom-y += clk-regmap.o
+clk-qcom-y += clk-alpha-pll.o
clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o
clk-qcom-y += clk-rcg2.o
@@ -20,5 +21,7 @@ obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
+obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
+obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
new file mode 100644
index 000000000000..e6a03eaf7a93
--- /dev/null
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include "clk-alpha-pll.h"
+
+#define PLL_MODE 0x00
+# define PLL_OUTCTRL BIT(0)
+# define PLL_BYPASSNL BIT(1)
+# define PLL_RESET_N BIT(2)
+# define PLL_LOCK_COUNT_SHIFT 8
+# define PLL_LOCK_COUNT_MASK 0x3f
+# define PLL_BIAS_COUNT_SHIFT 14
+# define PLL_BIAS_COUNT_MASK 0x3f
+# define PLL_VOTE_FSM_ENA BIT(20)
+# define PLL_VOTE_FSM_RESET BIT(21)
+# define PLL_ACTIVE_FLAG BIT(30)
+# define PLL_LOCK_DET BIT(31)
+
+#define PLL_L_VAL 0x04
+#define PLL_ALPHA_VAL 0x08
+#define PLL_ALPHA_VAL_U 0x0c
+
+#define PLL_USER_CTL 0x10
+# define PLL_POST_DIV_SHIFT 8
+# define PLL_POST_DIV_MASK 0xf
+# define PLL_ALPHA_EN BIT(24)
+# define PLL_VCO_SHIFT 20
+# define PLL_VCO_MASK 0x3
+
+#define PLL_USER_CTL_U 0x14
+
+#define PLL_CONFIG_CTL 0x18
+#define PLL_TEST_CTL 0x1c
+#define PLL_TEST_CTL_U 0x20
+#define PLL_STATUS 0x24
+
+/*
+ * Even though 40 bits are present, use only 32 for ease of calculation.
+ */
+#define ALPHA_REG_BITWIDTH 40
+#define ALPHA_BITWIDTH 32
+
+#define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \
+ struct clk_alpha_pll, clkr)
+
+#define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \
+ struct clk_alpha_pll_postdiv, clkr)
+
+static int wait_for_pll(struct clk_alpha_pll *pll)
+{
+ u32 val, mask, off;
+ int count;
+ int ret;
+ const char *name = clk_hw_get_name(&pll->clkr.hw);
+
+ off = pll->offset;
+ ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+ if (ret)
+ return ret;
+
+ if (val & PLL_VOTE_FSM_ENA)
+ mask = PLL_ACTIVE_FLAG;
+ else
+ mask = PLL_LOCK_DET;
+
+ /* Wait for pll to enable. */
+ for (count = 100; count > 0; count--) {
+ ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+ if (ret)
+ return ret;
+ if ((val & mask) == mask)
+ return 0;
+
+ udelay(1);
+ }
+
+ WARN(1, "%s didn't enable after voting for it!\n", name);
+ return -ETIMEDOUT;
+}
+
+static int clk_alpha_pll_enable(struct clk_hw *hw)
+{
+ int ret;
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 val, mask, off;
+
+ off = pll->offset;
+
+ mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
+ ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+ if (ret)
+ return ret;
+
+ /* If in FSM mode, just vote for it */
+ if (val & PLL_VOTE_FSM_ENA) {
+ ret = clk_enable_regmap(hw);
+ if (ret)
+ return ret;
+ return wait_for_pll(pll);
+ }
+
+ /* Skip if already enabled */
+ if ((val & mask) == mask)
+ return 0;
+
+ ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+ PLL_BYPASSNL, PLL_BYPASSNL);
+ if (ret)
+ return ret;
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset.
+ */
+ mb();
+ udelay(5);
+
+ ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+ PLL_RESET_N, PLL_RESET_N);
+ if (ret)
+ return ret;
+
+ ret = wait_for_pll(pll);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+ PLL_OUTCTRL, PLL_OUTCTRL);
+
+ /* Ensure that the write above goes through before returning. */
+ mb();
+ return ret;
+}
+
+static void clk_alpha_pll_disable(struct clk_hw *hw)
+{
+ int ret;
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 val, mask, off;
+
+ off = pll->offset;
+
+ ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+ if (ret)
+ return;
+
+ /* If in FSM mode, just unvote it */
+ if (val & PLL_VOTE_FSM_ENA) {
+ clk_disable_regmap(hw);
+ return;
+ }
+
+ mask = PLL_OUTCTRL;
+ regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0);
+
+ /* Delay of 2 output clock ticks required until output is disabled */
+ mb();
+ udelay(1);
+
+ mask = PLL_RESET_N | PLL_BYPASSNL;
+ regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0);
+}
+
+static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)
+{
+ return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH);
+}
+
+static unsigned long
+alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a)
+{
+ u64 remainder;
+ u64 quotient;
+
+ quotient = rate;
+ remainder = do_div(quotient, prate);
+ *l = quotient;
+
+ if (!remainder) {
+ *a = 0;
+ return rate;
+ }
+
+ /* Upper ALPHA_BITWIDTH bits of Alpha */
+ quotient = remainder << ALPHA_BITWIDTH;
+ remainder = do_div(quotient, prate);
+
+ if (remainder)
+ quotient++;
+
+ *a = quotient;
+ return alpha_pll_calc_rate(prate, *l, *a);
+}
+
+static const struct pll_vco *
+alpha_pll_find_vco(const struct clk_alpha_pll *pll, unsigned long rate)
+{
+ const struct pll_vco *v = pll->vco_table;
+ const struct pll_vco *end = v + pll->num_vco;
+
+ for (; v < end; v++)
+ if (rate >= v->min_freq && rate <= v->max_freq)
+ return v;
+
+ return NULL;
+}
+
+static unsigned long
+clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ u32 l, low, high, ctl;
+ u64 a = 0, prate = parent_rate;
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 off = pll->offset;
+
+ regmap_read(pll->clkr.regmap, off + PLL_L_VAL, &l);
+
+ regmap_read(pll->clkr.regmap, off + PLL_USER_CTL, &ctl);
+ if (ctl & PLL_ALPHA_EN) {
+ regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL, &low);
+ regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, &high);
+ a = (u64)high << 32 | low;
+ a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH;
+ }
+
+ return alpha_pll_calc_rate(prate, l, a);
+}
+
+static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ const struct pll_vco *vco;
+ u32 l, off = pll->offset;
+ u64 a;
+
+ rate = alpha_pll_round_rate(rate, prate, &l, &a);
+ vco = alpha_pll_find_vco(pll, rate);
+ if (!vco) {
+ pr_err("alpha pll not in a valid vco range\n");
+ return -EINVAL;
+ }
+
+ a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH);
+
+ regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
+ regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, a);
+ regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32);
+
+ regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL,
+ PLL_VCO_MASK << PLL_VCO_SHIFT,
+ vco->val << PLL_VCO_SHIFT);
+
+ regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_ALPHA_EN,
+ PLL_ALPHA_EN);
+
+ return 0;
+}
+
+static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 l;
+ u64 a;
+ unsigned long min_freq, max_freq;
+
+ rate = alpha_pll_round_rate(rate, *prate, &l, &a);
+ if (alpha_pll_find_vco(pll, rate))
+ return rate;
+
+ min_freq = pll->vco_table[0].min_freq;
+ max_freq = pll->vco_table[pll->num_vco - 1].max_freq;
+
+ return clamp(rate, min_freq, max_freq);
+}
+
+const struct clk_ops clk_alpha_pll_ops = {
+ .enable = clk_alpha_pll_enable,
+ .disable = clk_alpha_pll_disable,
+ .recalc_rate = clk_alpha_pll_recalc_rate,
+ .round_rate = clk_alpha_pll_round_rate,
+ .set_rate = clk_alpha_pll_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);
+
+static unsigned long
+clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+ u32 ctl;
+
+ regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl);
+
+ ctl >>= PLL_POST_DIV_SHIFT;
+ ctl &= PLL_POST_DIV_MASK;
+
+ return parent_rate >> fls(ctl);
+}
+
+static const struct clk_div_table clk_alpha_div_table[] = {
+ { 0x0, 1 },
+ { 0x1, 2 },
+ { 0x3, 4 },
+ { 0x7, 8 },
+ { 0xf, 16 },
+ { }
+};
+
+static long
+clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+
+ return divider_round_rate(hw, rate, prate, clk_alpha_div_table,
+ pll->width, CLK_DIVIDER_POWER_OF_TWO);
+}
+
+static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+ int div;
+
+ /* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */
+ div = DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
+
+ return regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL,
+ PLL_POST_DIV_MASK << PLL_POST_DIV_SHIFT,
+ div << PLL_POST_DIV_SHIFT);
+}
+
+const struct clk_ops clk_alpha_pll_postdiv_ops = {
+ .recalc_rate = clk_alpha_pll_postdiv_recalc_rate,
+ .round_rate = clk_alpha_pll_postdiv_round_rate,
+ .set_rate = clk_alpha_pll_postdiv_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops);
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
new file mode 100644
index 000000000000..90ce2016e1a0
--- /dev/null
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __QCOM_CLK_ALPHA_PLL_H__
+#define __QCOM_CLK_ALPHA_PLL_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct pll_vco {
+ unsigned long min_freq;
+ unsigned long max_freq;
+ u32 val;
+};
+
+/**
+ * struct clk_alpha_pll - phase locked loop (PLL)
+ * @offset: base address of registers
+ * @vco_table: array of VCO settings
+ * @clkr: regmap clock handle
+ */
+struct clk_alpha_pll {
+ u32 offset;
+
+ const struct pll_vco *vco_table;
+ size_t num_vco;
+
+ struct clk_regmap clkr;
+};
+
+/**
+ * struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider
+ * @offset: base address of registers
+ * @width: width of post-divider
+ * @clkr: regmap clock handle
+ */
+struct clk_alpha_pll_postdiv {
+ u32 offset;
+ u8 width;
+
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_alpha_pll_ops;
+extern const struct clk_ops clk_alpha_pll_postdiv_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 4b1e94bdf29e..b904c335cda4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -178,5 +178,6 @@ extern const struct clk_ops clk_edp_pixel_ops;
extern const struct clk_ops clk_byte_ops;
extern const struct clk_ops clk_byte2_ops;
extern const struct clk_ops clk_pixel_ops;
+extern const struct clk_ops clk_gfx3d_ops;
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index b544bb302f79..a071bba8018c 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -723,3 +723,90 @@ const struct clk_ops clk_pixel_ops = {
.determine_rate = clk_pixel_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_pixel_ops);
+
+static int clk_gfx3d_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_rate_request parent_req = { };
+ struct clk_hw *p2, *p8, *p9, *xo;
+ unsigned long p9_rate;
+ int ret;
+
+ xo = clk_hw_get_parent_by_index(hw, 0);
+ if (req->rate == clk_hw_get_rate(xo)) {
+ req->best_parent_hw = xo;
+ return 0;
+ }
+
+ p9 = clk_hw_get_parent_by_index(hw, 2);
+ p2 = clk_hw_get_parent_by_index(hw, 3);
+ p8 = clk_hw_get_parent_by_index(hw, 4);
+
+ /* PLL9 is a fixed rate PLL */
+ p9_rate = clk_hw_get_rate(p9);
+
+ parent_req.rate = req->rate = min(req->rate, p9_rate);
+ if (req->rate == p9_rate) {
+ req->rate = req->best_parent_rate = p9_rate;
+ req->best_parent_hw = p9;
+ return 0;
+ }
+
+ if (req->best_parent_hw == p9) {
+ /* Are we going back to a previously used rate? */
+ if (clk_hw_get_rate(p8) == req->rate)
+ req->best_parent_hw = p8;
+ else
+ req->best_parent_hw = p2;
+ } else if (req->best_parent_hw == p8) {
+ req->best_parent_hw = p2;
+ } else {
+ req->best_parent_hw = p8;
+ }
+
+ ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
+ if (ret)
+ return ret;
+
+ req->rate = req->best_parent_rate = parent_req.rate;
+
+ return 0;
+}
+
+static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ u32 cfg;
+ int ret;
+
+ /* Just mux it, we don't use the division or m/n hardware */
+ cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
+ ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
+ if (ret)
+ return ret;
+
+ return update_config(rcg);
+}
+
+static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ /*
+ * We should never get here; clk_gfx3d_determine_rate() should always
+ * make us use a different parent than what we're currently using, so
+ * clk_gfx3d_set_rate_and_parent() should always be called.
+ */
+ return 0;
+}
+
+const struct clk_ops clk_gfx3d_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .set_rate = clk_gfx3d_set_rate,
+ .set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
+ .determine_rate = clk_gfx3d_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index 8fa477293ae0..c112ebaba70d 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/reset-controller.h>
+#include <linux/of.h>
#include "common.h"
#include "clk-rcg.h"
@@ -88,6 +89,92 @@ static void qcom_cc_gdsc_unregister(void *data)
gdsc_unregister(data);
}
+/*
+ * Backwards compatibility with old DTs. Register a pass-through factor 1/1
+ * clock to translate 'path' clk into 'name' clk and regsiter the 'path'
+ * clk as a fixed rate clock if it isn't present.
+ */
+static int _qcom_cc_register_board_clk(struct device *dev, const char *path,
+ const char *name, unsigned long rate,
+ bool add_factor)
+{
+ struct device_node *node = NULL;
+ struct device_node *clocks_node;
+ struct clk_fixed_factor *factor;
+ struct clk_fixed_rate *fixed;
+ struct clk *clk;
+ struct clk_init_data init_data = { };
+
+ clocks_node = of_find_node_by_path("/clocks");
+ if (clocks_node)
+ node = of_find_node_by_name(clocks_node, path);
+ of_node_put(clocks_node);
+
+ if (!node) {
+ fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return -EINVAL;
+
+ fixed->fixed_rate = rate;
+ fixed->hw.init = &init_data;
+
+ init_data.name = path;
+ init_data.flags = CLK_IS_ROOT;
+ init_data.ops = &clk_fixed_rate_ops;
+
+ clk = devm_clk_register(dev, &fixed->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+ of_node_put(node);
+
+ if (add_factor) {
+ factor = devm_kzalloc(dev, sizeof(*factor), GFP_KERNEL);
+ if (!factor)
+ return -EINVAL;
+
+ factor->mult = factor->div = 1;
+ factor->hw.init = &init_data;
+
+ init_data.name = name;
+ init_data.parent_names = &path;
+ init_data.num_parents = 1;
+ init_data.flags = 0;
+ init_data.ops = &clk_fixed_factor_ops;
+
+ clk = devm_clk_register(dev, &factor->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
+ return 0;
+}
+
+int qcom_cc_register_board_clk(struct device *dev, const char *path,
+ const char *name, unsigned long rate)
+{
+ bool add_factor = true;
+ struct device_node *node;
+
+ /* The RPM clock driver will add the factor clock if present */
+ if (IS_ENABLED(CONFIG_QCOM_RPMCC)) {
+ node = of_find_compatible_node(NULL, NULL, "qcom,rpmcc");
+ if (of_device_is_available(node))
+ add_factor = false;
+ of_node_put(node);
+ }
+
+ return _qcom_cc_register_board_clk(dev, path, name, rate, add_factor);
+}
+EXPORT_SYMBOL_GPL(qcom_cc_register_board_clk);
+
+int qcom_cc_register_sleep_clk(struct device *dev)
+{
+ return _qcom_cc_register_board_clk(dev, "sleep_clk", "sleep_clk_src",
+ 32768, true);
+}
+EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
+
int qcom_cc_really_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc, struct regmap *regmap)
{
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 7c1fba3ebc03..ae9bdeb21f29 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -37,6 +37,10 @@ extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
u8 src);
+extern int qcom_cc_register_board_clk(struct device *dev, const char *path,
+ const char *name, unsigned long rate);
+extern int qcom_cc_register_sleep_clk(struct device *dev);
+
extern struct regmap *qcom_cc_map(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
extern int qcom_cc_really_probe(struct platform_device *pdev,
diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c
index 1567c3a79534..cf73e539e9f6 100644
--- a/drivers/clk/qcom/gcc-apq8084.c
+++ b/drivers/clk/qcom/gcc-apq8084.c
@@ -3587,6 +3587,7 @@ static const struct regmap_config gcc_apq8084_regmap_config = {
.val_bits = 32,
.max_register = 0x1fc0,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_apq8084_desc = {
@@ -3607,18 +3608,16 @@ MODULE_DEVICE_TABLE(of, gcc_apq8084_match_table);
static int gcc_apq8084_probe(struct platform_device *pdev)
{
- struct clk *clk;
+ int ret;
struct device *dev = &pdev->dev;
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
+ if (ret)
+ return ret;
- clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
- CLK_IS_ROOT, 32768);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_sleep_clk(dev);
+ if (ret)
+ return ret;
return qcom_cc_probe(pdev, &gcc_apq8084_desc);
}
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index 16fc64c082a5..b692ae881d6a 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -3005,6 +3005,7 @@ static const struct regmap_config gcc_ipq806x_regmap_config = {
.val_bits = 32,
.max_register = 0x3e40,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_ipq806x_desc = {
@@ -3023,19 +3024,17 @@ MODULE_DEVICE_TABLE(of, gcc_ipq806x_match_table);
static int gcc_ipq806x_probe(struct platform_device *pdev)
{
- struct clk *clk;
struct device *dev = &pdev->dev;
struct regmap *regmap;
int ret;
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
+ if (ret)
+ return ret;
- clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 25000000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
+ if (ret)
+ return ret;
ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
if (ret)
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
index f110bb5a1df3..f6a2b14dfec4 100644
--- a/drivers/clk/qcom/gcc-msm8660.c
+++ b/drivers/clk/qcom/gcc-msm8660.c
@@ -2702,6 +2702,7 @@ static const struct regmap_config gcc_msm8660_regmap_config = {
.val_bits = 32,
.max_register = 0x363c,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8660_desc = {
@@ -2720,17 +2721,16 @@ MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table);
static int gcc_msm8660_probe(struct platform_device *pdev)
{
- struct clk *clk;
+ int ret;
struct device *dev = &pdev->dev;
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
+ if (ret)
+ return ret;
- clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
+ if (ret)
+ return ret;
return qcom_cc_probe(pdev, &gcc_msm8660_desc);
}
diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c
index d0a0313d6bef..e3bf09d7d0ef 100644
--- a/drivers/clk/qcom/gcc-msm8916.c
+++ b/drivers/clk/qcom/gcc-msm8916.c
@@ -3336,6 +3336,7 @@ static const struct regmap_config gcc_msm8916_regmap_config = {
.val_bits = 32,
.max_register = 0x80000,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8916_desc = {
@@ -3356,18 +3357,16 @@ MODULE_DEVICE_TABLE(of, gcc_msm8916_match_table);
static int gcc_msm8916_probe(struct platform_device *pdev)
{
- struct clk *clk;
+ int ret;
struct device *dev = &pdev->dev;
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
+ if (ret)
+ return ret;
- clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
- CLK_IS_ROOT, 32768);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_sleep_clk(dev);
+ if (ret)
+ return ret;
return qcom_cc_probe(pdev, &gcc_msm8916_desc);
}
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index 66c18bc97857..f31111e32d44 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -3468,6 +3468,7 @@ static const struct regmap_config gcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0x3660,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct regmap_config gcc_apq8064_regmap_config = {
@@ -3476,6 +3477,7 @@ static const struct regmap_config gcc_apq8064_regmap_config = {
.val_bits = 32,
.max_register = 0x3880,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8960_desc = {
@@ -3503,7 +3505,6 @@ MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table);
static int gcc_msm8960_probe(struct platform_device *pdev)
{
- struct clk *clk;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct platform_device *tsens;
@@ -3513,14 +3514,13 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
if (!match)
return -EINVAL;
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
+ if (ret)
+ return ret;
- clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
+ if (ret)
+ return ret;
ret = qcom_cc_probe(pdev, match->data);
if (ret)
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 28abb8f8f293..df164d618e34 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -2680,6 +2680,7 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
.val_bits = 32,
.max_register = 0x1fc0,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8974_desc = {
@@ -2717,7 +2718,7 @@ static void msm8974_pro_clock_override(void)
static int gcc_msm8974_probe(struct platform_device *pdev)
{
- struct clk *clk;
+ int ret;
struct device *dev = &pdev->dev;
bool pro;
const struct of_device_id *id;
@@ -2730,16 +2731,13 @@ static int gcc_msm8974_probe(struct platform_device *pdev)
if (pro)
msm8974_pro_clock_override();
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
+ if (ret)
+ return ret;
- /* Should move to DT node? */
- clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
- CLK_IS_ROOT, 32768);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = qcom_cc_register_sleep_clk(dev);
+ if (ret)
+ return ret;
return qcom_cc_probe(pdev, &gcc_msm8974_desc);
}
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
new file mode 100644
index 000000000000..16d7c323db49
--- /dev/null
+++ b/drivers/clk/qcom/gcc-msm8996.c
@@ -0,0 +1,3422 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,gcc-msm8996.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+ P_XO,
+ P_GPLL0,
+ P_GPLL2,
+ P_GPLL3,
+ P_GPLL1,
+ P_GPLL2_EARLY,
+ P_GPLL0_EARLY_DIV,
+ P_SLEEP_CLK,
+ P_GPLL4,
+ P_AUD_REF_CLK,
+ P_GPLL1_EARLY_DIV
+};
+
+static const struct parent_map gcc_sleep_clk_map[] = {
+ { P_SLEEP_CLK, 5 }
+};
+
+static const char * const gcc_sleep_clk[] = {
+ "sleep_clk"
+};
+
+static const struct parent_map gcc_xo_gpll0_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 }
+};
+
+static const char * const gcc_xo_gpll0[] = {
+ "xo",
+ "gpll0"
+};
+
+static const struct parent_map gcc_xo_sleep_clk_map[] = {
+ { P_XO, 0 },
+ { P_SLEEP_CLK, 5 }
+};
+
+static const char * const gcc_xo_sleep_clk[] = {
+ "xo",
+ "sleep_clk"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL4, 5 }
+};
+
+static const char * const gcc_xo_gpll0_gpll4[] = {
+ "xo",
+ "gpll0",
+ "gpll4"
+};
+
+static const struct parent_map gcc_xo_gpll0_aud_ref_clk_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_AUD_REF_CLK, 2 }
+};
+
+static const char * const gcc_xo_gpll0_aud_ref_clk[] = {
+ "xo",
+ "gpll0",
+ "aud_ref_clk"
+};
+
+static const struct parent_map gcc_xo_gpll0_sleep_clk_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "sleep_clk",
+ "gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll4_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL4, 5 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll4",
+ "gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL2, 2 },
+ { P_GPLL3, 3 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll2",
+ "gpll3",
+ "gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL1_EARLY_DIV, 3 },
+ { P_GPLL1, 4 },
+ { P_GPLL4, 5 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll1_early_div",
+ "gpll1",
+ "gpll4",
+ "gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL2, 2 },
+ { P_GPLL3, 3 },
+ { P_GPLL1, 4 },
+ { P_GPLL2_EARLY, 5 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll2",
+ "gpll3",
+ "gpll1",
+ "gpll2_early",
+ "gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL2, 2 },
+ { P_GPLL3, 3 },
+ { P_GPLL1, 4 },
+ { P_GPLL4, 5 },
+ { P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll2",
+ "gpll3",
+ "gpll1",
+ "gpll4",
+ "gpll0_early_div"
+};
+
+static struct clk_fixed_factor xo = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "xo",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll0_early = {
+ .offset = 0x00000,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll0_early_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_early_div",
+ .parent_names = (const char *[]){ "gpll0_early" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+ .offset = 0x00000,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll0",
+ .parent_names = (const char *[]){ "gpll0_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll4_early = {
+ .offset = 0x77000,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll4 = {
+ .offset = 0x77000,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll4",
+ .parent_names = (const char *[]){ "gpll4_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_system_noc_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(240000000, P_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 system_noc_clk_src = {
+ .cmd_rcgr = 0x0401c,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div_map,
+ .freq_tbl = ftbl_system_noc_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "system_noc_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_config_noc_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(37500000, P_GPLL0, 16, 0, 0),
+ F(75000000, P_GPLL0, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 config_noc_clk_src = {
+ .cmd_rcgr = 0x0500c,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_config_noc_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "config_noc_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_periph_noc_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(37500000, P_GPLL0, 16, 0, 0),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(75000000, P_GPLL0, 8, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 periph_noc_clk_src = {
+ .cmd_rcgr = 0x06014,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_periph_noc_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "periph_noc_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(120000000, P_GPLL0, 5, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+ .cmd_rcgr = 0x0f014,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+ .freq_tbl = ftbl_usb30_master_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_master_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x0f028,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+ .freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_mock_utmi_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
+ F(1200000, P_XO, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+ .cmd_rcgr = 0x5000c,
+ .hid_width = 5,
+ .parent_map = gcc_xo_sleep_clk_map,
+ .freq_tbl = ftbl_usb3_phy_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb3_phy_aux_clk_src",
+ .parent_names = gcc_xo_sleep_clk,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
+ F(120000000, P_GPLL0, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb20_master_clk_src = {
+ .cmd_rcgr = 0x12010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+ .freq_tbl = ftbl_usb20_master_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb20_master_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x12024,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+ .freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb20_mock_utmi_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0, 15, 1, 2),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(96000000, P_GPLL4, 4, 0, 0),
+ F(192000000, P_GPLL4, 2, 0, 0),
+ F(384000000, P_GPLL4, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x13010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll4_gpll0_early_div_map,
+ .freq_tbl = ftbl_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_apps_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x13024,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll4_gpll0_early_div_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_ice_core_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0, 15, 1, 2),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x14010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll4_map,
+ .freq_tbl = ftbl_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc2_apps_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll4,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 sdcc3_apps_clk_src = {
+ .cmd_rcgr = 0x15010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll4_map,
+ .freq_tbl = ftbl_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc3_apps_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll4,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc4_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0, 15, 1, 2),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc4_apps_clk_src = {
+ .cmd_rcgr = 0x16010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_sdcc4_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc4_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+ F(960000, P_XO, 10, 1, 2),
+ F(4800000, P_XO, 4, 0, 0),
+ F(9600000, P_XO, 2, 0, 0),
+ F(15000000, P_GPLL0, 10, 1, 4),
+ F(19200000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1900c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x19020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
+ F(3686400, P_GPLL0, 1, 96, 15625),
+ F(7372800, P_GPLL0, 1, 192, 15625),
+ F(14745600, P_GPLL0, 1, 384, 15625),
+ F(16000000, P_GPLL0, 5, 2, 15),
+ F(19200000, P_XO, 1, 0, 0),
+ F(24000000, P_GPLL0, 5, 1, 5),
+ F(32000000, P_GPLL0, 1, 4, 75),
+ F(40000000, P_GPLL0, 15, 0, 0),
+ F(46400000, P_GPLL0, 1, 29, 375),
+ F(48000000, P_GPLL0, 12.5, 0, 0),
+ F(51200000, P_GPLL0, 1, 32, 375),
+ F(56000000, P_GPLL0, 1, 7, 75),
+ F(58982400, P_GPLL0, 1, 1536, 15625),
+ F(60000000, P_GPLL0, 10, 0, 0),
+ F(63157895, P_GPLL0, 9.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr = 0x1a00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart1_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1b00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x1b020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr = 0x1c00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart2_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1d00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x1d020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr = 0x1e00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart3_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1f00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x1f020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart4_apps_clk_src = {
+ .cmd_rcgr = 0x2000c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart4_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2100c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup5_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x21020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup5_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart5_apps_clk_src = {
+ .cmd_rcgr = 0x2200c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart5_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2300c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup6_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x23020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup6_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart6_apps_clk_src = {
+ .cmd_rcgr = 0x2400c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart6_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2600c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup1_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x26020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup1_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
+ .cmd_rcgr = 0x2700c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart1_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2800c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup2_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x28020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup2_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
+ .cmd_rcgr = 0x2900c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart2_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2a00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup3_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x2a020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup3_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart3_apps_clk_src = {
+ .cmd_rcgr = 0x2b00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart3_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2c00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup4_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x2c020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup4_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart4_apps_clk_src = {
+ .cmd_rcgr = 0x2d00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart4_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup5_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2e00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup5_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x2e020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup5_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart5_apps_clk_src = {
+ .cmd_rcgr = 0x2f00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart5_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup6_spi_apps_clk_src = {
+ .cmd_rcgr = 0x3000c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup6_spi_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x30020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup6_i2c_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart6_apps_clk_src = {
+ .cmd_rcgr = 0x3100c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart6_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+ F(60000000, P_GPLL0, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+ .cmd_rcgr = 0x33010,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_pdm2_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pdm2_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_tsif_ref_clk_src[] = {
+ F(105495, P_XO, 1, 1, 182),
+ { }
+};
+
+static struct clk_rcg2 tsif_ref_clk_src = {
+ .cmd_rcgr = 0x36010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_aud_ref_clk_map,
+ .freq_tbl = ftbl_tsif_ref_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "tsif_ref_clk_src",
+ .parent_names = gcc_xo_gpll0_aud_ref_clk,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_sleep_clk_src = {
+ .cmd_rcgr = 0x43014,
+ .hid_width = 5,
+ .parent_map = gcc_sleep_clk_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sleep_clk_src",
+ .parent_names = gcc_sleep_clk,
+ .num_parents = 1,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 hmss_rbcpr_clk_src = {
+ .cmd_rcgr = 0x48040,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hmss_rbcpr_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 hmss_gpll0_clk_src = {
+ .cmd_rcgr = 0x48058,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hmss_gpll0_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+ .cmd_rcgr = 0x64004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_sleep_clk_gpll0_early_div_map,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp1_clk_src",
+ .parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+ .cmd_rcgr = 0x65004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_sleep_clk_gpll0_early_div_map,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp2_clk_src",
+ .parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+ .cmd_rcgr = 0x66004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_sleep_clk_gpll0_early_div_map,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp3_clk_src",
+ .parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_pcie_aux_clk_src[] = {
+ F(1010526, P_XO, 1, 1, 19),
+ { }
+};
+
+static struct clk_rcg2 pcie_aux_clk_src = {
+ .cmd_rcgr = 0x6c000,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_sleep_clk_map,
+ .freq_tbl = ftbl_pcie_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pcie_aux_clk_src",
+ .parent_names = gcc_xo_sleep_clk,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(240000000, P_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ufs_axi_clk_src = {
+ .cmd_rcgr = 0x75024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_ufs_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ufs_axi_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 ufs_ice_core_clk_src = {
+ .cmd_rcgr = 0x76014,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ufs_ice_core_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 qspi_ser_clk_src = {
+ .cmd_rcgr = 0x8b00c,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "qspi_ser_clk_src",
+ .parent_names = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div,
+ .num_parents = 6,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb3_axi_clk = {
+ .halt_reg = 0x0f03c,
+ .clkr = {
+ .enable_reg = 0x0f03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_usb3_axi_clk",
+ .parent_names = (const char *[]){ "usb30_master_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_ufs_axi_clk = {
+ .halt_reg = 0x75038,
+ .clkr = {
+ .enable_reg = 0x75038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_ufs_axi_clk",
+ .parent_names = (const char *[]){ "ufs_axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_periph_noc_usb20_ahb_clk = {
+ .halt_reg = 0x6010,
+ .clkr = {
+ .enable_reg = 0x6010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_periph_noc_usb20_ahb_clk",
+ .parent_names = (const char *[]){ "usb20_master_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
+ .halt_reg = 0x9008,
+ .clkr = {
+ .enable_reg = 0x9008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_noc_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmss_bimc_gfx_clk = {
+ .halt_reg = 0x9010,
+ .clkr = {
+ .enable_reg = 0x9010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_bimc_gfx_clk",
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_ROOT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+ .halt_reg = 0x0f008,
+ .clkr = {
+ .enable_reg = 0x0f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_master_clk",
+ .parent_names = (const char *[]){ "usb30_master_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+ .halt_reg = 0x0f00c,
+ .clkr = {
+ .enable_reg = 0x0f00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_sleep_clk",
+ .parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+ .halt_reg = 0x0f010,
+ .clkr = {
+ .enable_reg = 0x0f010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_mock_utmi_clk",
+ .parent_names = (const char *[]){ "usb30_mock_utmi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+ .halt_reg = 0x50000,
+ .clkr = {
+ .enable_reg = 0x50000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_phy_aux_clk",
+ .parent_names = (const char *[]){ "usb3_phy_aux_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+ .halt_reg = 0x50004,
+ .clkr = {
+ .enable_reg = 0x50004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_phy_pipe_clk",
+ .parent_names = (const char *[]){ "usb3_phy_pipe_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+ .halt_reg = 0x12004,
+ .clkr = {
+ .enable_reg = 0x12004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_master_clk",
+ .parent_names = (const char *[]){ "usb20_master_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+ .halt_reg = 0x12008,
+ .clkr = {
+ .enable_reg = 0x12008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_sleep_clk",
+ .parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+ .halt_reg = 0x1200c,
+ .clkr = {
+ .enable_reg = 0x1200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_mock_utmi_clk",
+ .parent_names = (const char *[]){ "usb20_mock_utmi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+ .halt_reg = 0x6a004,
+ .clkr = {
+ .enable_reg = 0x6a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_phy_cfg_ahb2phy_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x13004,
+ .clkr = {
+ .enable_reg = 0x13004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_names = (const char *[]){ "sdcc1_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x13008,
+ .clkr = {
+ .enable_reg = 0x13008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x13038,
+ .clkr = {
+ .enable_reg = 0x13038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_names = (const char *[]){ "sdcc1_ice_core_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x14004,
+ .clkr = {
+ .enable_reg = 0x14004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_names = (const char *[]){ "sdcc2_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x14008,
+ .clkr = {
+ .enable_reg = 0x14008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc3_apps_clk = {
+ .halt_reg = 0x15004,
+ .clkr = {
+ .enable_reg = 0x15004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc3_apps_clk",
+ .parent_names = (const char *[]){ "sdcc3_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc3_ahb_clk = {
+ .halt_reg = 0x15008,
+ .clkr = {
+ .enable_reg = 0x15008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc3_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_apps_clk = {
+ .halt_reg = 0x16004,
+ .clkr = {
+ .enable_reg = 0x16004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc4_apps_clk",
+ .parent_names = (const char *[]){ "sdcc4_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_ahb_clk = {
+ .halt_reg = 0x16008,
+ .clkr = {
+ .enable_reg = 0x16008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc4_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+ .halt_reg = 0x17004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_sleep_clk = {
+ .halt_reg = 0x17008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(16),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_sleep_clk",
+ .parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+ .halt_reg = 0x19004,
+ .clkr = {
+ .enable_reg = 0x19004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup1_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+ .halt_reg = 0x19008,
+ .clkr = {
+ .enable_reg = 0x19008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup1_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+ .halt_reg = 0x1a004,
+ .clkr = {
+ .enable_reg = 0x1a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart1_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_uart1_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+ .halt_reg = 0x1b004,
+ .clkr = {
+ .enable_reg = 0x1b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup2_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+ .halt_reg = 0x1b008,
+ .clkr = {
+ .enable_reg = 0x1b008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup2_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+ .halt_reg = 0x1c004,
+ .clkr = {
+ .enable_reg = 0x1c004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart2_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_uart2_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+ .halt_reg = 0x1d004,
+ .clkr = {
+ .enable_reg = 0x1d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup3_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+ .halt_reg = 0x1d008,
+ .clkr = {
+ .enable_reg = 0x1d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup3_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart3_apps_clk = {
+ .halt_reg = 0x1e004,
+ .clkr = {
+ .enable_reg = 0x1e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart3_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_uart3_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+ .halt_reg = 0x1f004,
+ .clkr = {
+ .enable_reg = 0x1f004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup4_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+ .halt_reg = 0x1f008,
+ .clkr = {
+ .enable_reg = 0x1f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup4_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart4_apps_clk = {
+ .halt_reg = 0x20004,
+ .clkr = {
+ .enable_reg = 0x20004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart4_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_uart4_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = {
+ .halt_reg = 0x21004,
+ .clkr = {
+ .enable_reg = 0x21004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup5_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup5_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = {
+ .halt_reg = 0x21008,
+ .clkr = {
+ .enable_reg = 0x21008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup5_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup5_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart5_apps_clk = {
+ .halt_reg = 0x22004,
+ .clkr = {
+ .enable_reg = 0x22004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart5_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_uart5_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = {
+ .halt_reg = 0x23004,
+ .clkr = {
+ .enable_reg = 0x23004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup6_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup6_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = {
+ .halt_reg = 0x23008,
+ .clkr = {
+ .enable_reg = 0x23008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup6_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_qup6_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart6_apps_clk = {
+ .halt_reg = 0x24004,
+ .clkr = {
+ .enable_reg = 0x24004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart6_apps_clk",
+ .parent_names = (const char *[]){ "blsp1_uart6_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+ .halt_reg = 0x25004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_sleep_clk = {
+ .halt_reg = 0x25008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(14),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_sleep_clk",
+ .parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
+ .halt_reg = 0x26004,
+ .clkr = {
+ .enable_reg = 0x26004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup1_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup1_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
+ .halt_reg = 0x26008,
+ .clkr = {
+ .enable_reg = 0x26008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup1_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup1_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart1_apps_clk = {
+ .halt_reg = 0x27004,
+ .clkr = {
+ .enable_reg = 0x27004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart1_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_uart1_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
+ .halt_reg = 0x28004,
+ .clkr = {
+ .enable_reg = 0x28004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup2_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup2_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
+ .halt_reg = 0x28008,
+ .clkr = {
+ .enable_reg = 0x28008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup2_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup2_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart2_apps_clk = {
+ .halt_reg = 0x29004,
+ .clkr = {
+ .enable_reg = 0x29004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart2_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_uart2_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
+ .halt_reg = 0x2a004,
+ .clkr = {
+ .enable_reg = 0x2a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup3_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup3_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
+ .halt_reg = 0x2a008,
+ .clkr = {
+ .enable_reg = 0x2a008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup3_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup3_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart3_apps_clk = {
+ .halt_reg = 0x2b004,
+ .clkr = {
+ .enable_reg = 0x2b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart3_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_uart3_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
+ .halt_reg = 0x2c004,
+ .clkr = {
+ .enable_reg = 0x2c004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup4_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup4_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
+ .halt_reg = 0x2c008,
+ .clkr = {
+ .enable_reg = 0x2c008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup4_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup4_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart4_apps_clk = {
+ .halt_reg = 0x2d004,
+ .clkr = {
+ .enable_reg = 0x2d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart4_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_uart4_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup5_spi_apps_clk = {
+ .halt_reg = 0x2e004,
+ .clkr = {
+ .enable_reg = 0x2e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup5_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup5_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup5_i2c_apps_clk = {
+ .halt_reg = 0x2e008,
+ .clkr = {
+ .enable_reg = 0x2e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup5_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup5_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart5_apps_clk = {
+ .halt_reg = 0x2f004,
+ .clkr = {
+ .enable_reg = 0x2f004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart5_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_uart5_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup6_spi_apps_clk = {
+ .halt_reg = 0x30004,
+ .clkr = {
+ .enable_reg = 0x30004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup6_spi_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup6_spi_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup6_i2c_apps_clk = {
+ .halt_reg = 0x30008,
+ .clkr = {
+ .enable_reg = 0x30008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup6_i2c_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_qup6_i2c_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart6_apps_clk = {
+ .halt_reg = 0x31004,
+ .clkr = {
+ .enable_reg = 0x31004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart6_apps_clk",
+ .parent_names = (const char *[]){ "blsp2_uart6_apps_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x33004,
+ .clkr = {
+ .enable_reg = 0x33004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x3300c,
+ .clkr = {
+ .enable_reg = 0x3300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_names = (const char *[]){ "pdm2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+ .halt_reg = 0x34004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_prng_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tsif_ahb_clk = {
+ .halt_reg = 0x36004,
+ .clkr = {
+ .enable_reg = 0x36004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_tsif_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tsif_ref_clk = {
+ .halt_reg = 0x36008,
+ .clkr = {
+ .enable_reg = 0x36008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_tsif_ref_clk",
+ .parent_names = (const char *[]){ "tsif_ref_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tsif_inactivity_timers_clk = {
+ .halt_reg = 0x3600c,
+ .clkr = {
+ .enable_reg = 0x3600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_tsif_inactivity_timers_clk",
+ .parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_boot_rom_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+ .halt_reg = 0x46018,
+ .clkr = {
+ .enable_reg = 0x46018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_gfx_clk",
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_ROOT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_hmss_rbcpr_clk = {
+ .halt_reg = 0x4800c,
+ .clkr = {
+ .enable_reg = 0x4800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_hmss_rbcpr_clk",
+ .parent_names = (const char *[]){ "hmss_rbcpr_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x64000,
+ .clkr = {
+ .enable_reg = 0x64000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_names = (const char *[]){ "gp1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x65000,
+ .clkr = {
+ .enable_reg = 0x65000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_names = (const char *[]){ "gp2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x66000,
+ .clkr = {
+ .enable_reg = 0x66000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_names = (const char *[]){ "gp3_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0x6b008,
+ .clkr = {
+ .enable_reg = 0x6b008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0x6b00c,
+ .clkr = {
+ .enable_reg = 0x6b00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0x6b010,
+ .clkr = {
+ .enable_reg = 0x6b010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0x6b014,
+ .clkr = {
+ .enable_reg = 0x6b014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_names = (const char *[]){ "pcie_aux_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0x6b018,
+ .clkr = {
+ .enable_reg = 0x6b018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_pipe_clk",
+ .parent_names = (const char *[]){ "pcie_0_pipe_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_axi_clk = {
+ .halt_reg = 0x6d008,
+ .clkr = {
+ .enable_reg = 0x6d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_1_slv_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
+ .halt_reg = 0x6d00c,
+ .clkr = {
+ .enable_reg = 0x6d00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_1_mstr_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
+ .halt_reg = 0x6d010,
+ .clkr = {
+ .enable_reg = 0x6d010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_1_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_aux_clk = {
+ .halt_reg = 0x6d014,
+ .clkr = {
+ .enable_reg = 0x6d014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_1_aux_clk",
+ .parent_names = (const char *[]){ "pcie_aux_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+ .halt_reg = 0x6d018,
+ .clkr = {
+ .enable_reg = 0x6d018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_1_pipe_clk",
+ .parent_names = (const char *[]){ "pcie_1_pipe_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_slv_axi_clk = {
+ .halt_reg = 0x6e008,
+ .clkr = {
+ .enable_reg = 0x6e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_2_slv_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_mstr_axi_clk = {
+ .halt_reg = 0x6e00c,
+ .clkr = {
+ .enable_reg = 0x6e00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_2_mstr_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_cfg_ahb_clk = {
+ .halt_reg = 0x6e010,
+ .clkr = {
+ .enable_reg = 0x6e010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_2_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_aux_clk = {
+ .halt_reg = 0x6e014,
+ .clkr = {
+ .enable_reg = 0x6e014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_2_aux_clk",
+ .parent_names = (const char *[]){ "pcie_aux_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_pipe_clk = {
+ .halt_reg = 0x6e108,
+ .clkr = {
+ .enable_reg = 0x6e108,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_2_pipe_clk",
+ .parent_names = (const char *[]){ "pcie_2_pipe_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_phy_cfg_ahb_clk = {
+ .halt_reg = 0x6f004,
+ .clkr = {
+ .enable_reg = 0x6f004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_phy_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_phy_aux_clk = {
+ .halt_reg = 0x6f008,
+ .clkr = {
+ .enable_reg = 0x6f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_phy_aux_clk",
+ .parent_names = (const char *[]){ "pcie_aux_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_axi_clk = {
+ .halt_reg = 0x75008,
+ .clkr = {
+ .enable_reg = 0x75008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_axi_clk",
+ .parent_names = (const char *[]){ "ufs_axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_ahb_clk = {
+ .halt_reg = 0x7500c,
+ .clkr = {
+ .enable_reg = 0x7500c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor ufs_tx_cfg_clk_src = {
+ .mult = 1,
+ .div = 16,
+ .hw.init = &(struct clk_init_data){
+ .name = "ufs_tx_cfg_clk_src",
+ .parent_names = (const char *[]){ "ufs_axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_branch gcc_ufs_tx_cfg_clk = {
+ .halt_reg = 0x75010,
+ .clkr = {
+ .enable_reg = 0x75010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_tx_cfg_clk",
+ .parent_names = (const char *[]){ "ufs_tx_cfg_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor ufs_rx_cfg_clk_src = {
+ .mult = 1,
+ .div = 16,
+ .hw.init = &(struct clk_init_data){
+ .name = "ufs_rx_cfg_clk_src",
+ .parent_names = (const char *[]){ "ufs_axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_branch gcc_ufs_rx_cfg_clk = {
+ .halt_reg = 0x75014,
+ .clkr = {
+ .enable_reg = 0x75014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_rx_cfg_clk",
+ .parent_names = (const char *[]){ "ufs_rx_cfg_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
+ .halt_reg = 0x75018,
+ .clkr = {
+ .enable_reg = 0x75018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_tx_symbol_0_clk",
+ .parent_names = (const char *[]){ "ufs_tx_symbol_0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
+ .halt_reg = 0x7501c,
+ .clkr = {
+ .enable_reg = 0x7501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_rx_symbol_0_clk",
+ .parent_names = (const char *[]){ "ufs_rx_symbol_0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
+ .halt_reg = 0x75020,
+ .clkr = {
+ .enable_reg = 0x75020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_rx_symbol_1_clk",
+ .parent_names = (const char *[]){ "ufs_rx_symbol_1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor ufs_ice_core_postdiv_clk_src = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "ufs_ice_core_postdiv_clk_src",
+ .parent_names = (const char *[]){ "ufs_ice_core_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_branch gcc_ufs_unipro_core_clk = {
+ .halt_reg = 0x7600c,
+ .clkr = {
+ .enable_reg = 0x7600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_unipro_core_clk",
+ .parent_names = (const char *[]){ "ufs_ice_core_postdiv_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_ice_core_clk = {
+ .halt_reg = 0x76010,
+ .clkr = {
+ .enable_reg = 0x76010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_ice_core_clk",
+ .parent_names = (const char *[]){ "ufs_ice_core_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_sys_clk_core_clk = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x76030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_sys_clk_core_clk",
+ .ops = &clk_branch2_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_clk_core_clk = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x76034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_tx_symbol_clk_core_clk",
+ .ops = &clk_branch2_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre0_snoc_axi_clk = {
+ .halt_reg = 0x81008,
+ .clkr = {
+ .enable_reg = 0x81008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre0_snoc_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre0_cnoc_ahb_clk = {
+ .halt_reg = 0x8100c,
+ .clkr = {
+ .enable_reg = 0x8100c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre0_cnoc_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_smmu_aggre0_axi_clk = {
+ .halt_reg = 0x81014,
+ .clkr = {
+ .enable_reg = 0x81014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_smmu_aggre0_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
+ .halt_reg = 0x81018,
+ .clkr = {
+ .enable_reg = 0x81018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_smmu_aggre0_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
+ .halt_reg = 0x82014,
+ .clkr = {
+ .enable_reg = 0x82014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre1_pnoc_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
+ .halt_reg = 0x83014,
+ .clkr = {
+ .enable_reg = 0x83014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre2_ufs_axi_clk",
+ .parent_names = (const char *[]){ "ufs_axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
+ .halt_reg = 0x83018,
+ .clkr = {
+ .enable_reg = 0x83018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre2_usb3_axi_clk",
+ .parent_names = (const char *[]){ "usb30_master_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qspi_ahb_clk = {
+ .halt_reg = 0x8b004,
+ .clkr = {
+ .enable_reg = 0x8b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qspi_ser_clk = {
+ .halt_reg = 0x8b008,
+ .clkr = {
+ .enable_reg = 0x8b008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_ser_clk",
+ .parent_names = (const char *[]){ "qspi_ser_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_clkref_clk = {
+ .halt_reg = 0x8800C,
+ .clkr = {
+ .enable_reg = 0x8800C,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_hdmi_clkref_clk = {
+ .halt_reg = 0x88000,
+ .clkr = {
+ .enable_reg = 0x88000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_hdmi_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_clkref_clk = {
+ .halt_reg = 0x88008,
+ .clkr = {
+ .enable_reg = 0x88008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_clkref_clk = {
+ .halt_reg = 0x88010,
+ .clkr = {
+ .enable_reg = 0x88010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_rx2_usb2_clkref_clk = {
+ .halt_reg = 0x88014,
+ .clkr = {
+ .enable_reg = 0x88014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_rx2_usb2_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_rx1_usb2_clkref_clk = {
+ .halt_reg = 0x88018,
+ .clkr = {
+ .enable_reg = 0x88018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_rx1_usb2_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_hw *gcc_msm8996_hws[] = {
+ &xo.hw,
+ &gpll0_early_div.hw,
+ &ufs_tx_cfg_clk_src.hw,
+ &ufs_rx_cfg_clk_src.hw,
+ &ufs_ice_core_postdiv_clk_src.hw,
+};
+
+static struct clk_regmap *gcc_msm8996_clocks[] = {
+ [GPLL0_EARLY] = &gpll0_early.clkr,
+ [GPLL0] = &gpll0.clkr,
+ [GPLL4_EARLY] = &gpll4_early.clkr,
+ [GPLL4] = &gpll4.clkr,
+ [SYSTEM_NOC_CLK_SRC] = &system_noc_clk_src.clkr,
+ [CONFIG_NOC_CLK_SRC] = &config_noc_clk_src.clkr,
+ [PERIPH_NOC_CLK_SRC] = &periph_noc_clk_src.clkr,
+ [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+ [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+ [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+ [USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
+ [USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+ [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+ [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+ [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+ [SDCC3_APPS_CLK_SRC] = &sdcc3_apps_clk_src.clkr,
+ [SDCC4_APPS_CLK_SRC] = &sdcc4_apps_clk_src.clkr,
+ [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+ [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+ [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+ [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+ [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+ [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+ [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+ [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+ [BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr,
+ [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+ [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+ [BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr,
+ [BLSP1_QUP5_SPI_APPS_CLK_SRC] = &blsp1_qup5_spi_apps_clk_src.clkr,
+ [BLSP1_QUP5_I2C_APPS_CLK_SRC] = &blsp1_qup5_i2c_apps_clk_src.clkr,
+ [BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr,
+ [BLSP1_QUP6_SPI_APPS_CLK_SRC] = &blsp1_qup6_spi_apps_clk_src.clkr,
+ [BLSP1_QUP6_I2C_APPS_CLK_SRC] = &blsp1_qup6_i2c_apps_clk_src.clkr,
+ [BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr,
+ [BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
+ [BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
+ [BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
+ [BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
+ [BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
+ [BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
+ [BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
+ [BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
+ [BLSP2_UART3_APPS_CLK_SRC] = &blsp2_uart3_apps_clk_src.clkr,
+ [BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
+ [BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
+ [BLSP2_UART4_APPS_CLK_SRC] = &blsp2_uart4_apps_clk_src.clkr,
+ [BLSP2_QUP5_SPI_APPS_CLK_SRC] = &blsp2_qup5_spi_apps_clk_src.clkr,
+ [BLSP2_QUP5_I2C_APPS_CLK_SRC] = &blsp2_qup5_i2c_apps_clk_src.clkr,
+ [BLSP2_UART5_APPS_CLK_SRC] = &blsp2_uart5_apps_clk_src.clkr,
+ [BLSP2_QUP6_SPI_APPS_CLK_SRC] = &blsp2_qup6_spi_apps_clk_src.clkr,
+ [BLSP2_QUP6_I2C_APPS_CLK_SRC] = &blsp2_qup6_i2c_apps_clk_src.clkr,
+ [BLSP2_UART6_APPS_CLK_SRC] = &blsp2_uart6_apps_clk_src.clkr,
+ [PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+ [TSIF_REF_CLK_SRC] = &tsif_ref_clk_src.clkr,
+ [GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.clkr,
+ [HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
+ [HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
+ [GP1_CLK_SRC] = &gp1_clk_src.clkr,
+ [GP2_CLK_SRC] = &gp2_clk_src.clkr,
+ [GP3_CLK_SRC] = &gp3_clk_src.clkr,
+ [PCIE_AUX_CLK_SRC] = &pcie_aux_clk_src.clkr,
+ [UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
+ [UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
+ [QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
+ [GCC_SYS_NOC_USB3_AXI_CLK] = &gcc_sys_noc_usb3_axi_clk.clkr,
+ [GCC_SYS_NOC_UFS_AXI_CLK] = &gcc_sys_noc_ufs_axi_clk.clkr,
+ [GCC_PERIPH_NOC_USB20_AHB_CLK] = &gcc_periph_noc_usb20_ahb_clk.clkr,
+ [GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
+ [GCC_MMSS_BIMC_GFX_CLK] = &gcc_mmss_bimc_gfx_clk.clkr,
+ [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+ [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+ [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+ [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+ [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+ [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+ [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+ [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC3_APPS_CLK] = &gcc_sdcc3_apps_clk.clkr,
+ [GCC_SDCC3_AHB_CLK] = &gcc_sdcc3_ahb_clk.clkr,
+ [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr,
+ [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr,
+ [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+ [GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr,
+ [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+ [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+ [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+ [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+ [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+ [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr,
+ [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+ [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr,
+ [GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr,
+ [GCC_BLSP1_UART5_APPS_CLK] = &gcc_blsp1_uart5_apps_clk.clkr,
+ [GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr,
+ [GCC_BLSP1_UART6_APPS_CLK] = &gcc_blsp1_uart6_apps_clk.clkr,
+ [GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+ [GCC_BLSP2_SLEEP_CLK] = &gcc_blsp2_sleep_clk.clkr,
+ [GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
+ [GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
+ [GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
+ [GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
+ [GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
+ [GCC_BLSP2_UART3_APPS_CLK] = &gcc_blsp2_uart3_apps_clk.clkr,
+ [GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
+ [GCC_BLSP2_UART4_APPS_CLK] = &gcc_blsp2_uart4_apps_clk.clkr,
+ [GCC_BLSP2_QUP5_SPI_APPS_CLK] = &gcc_blsp2_qup5_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP5_I2C_APPS_CLK] = &gcc_blsp2_qup5_i2c_apps_clk.clkr,
+ [GCC_BLSP2_UART5_APPS_CLK] = &gcc_blsp2_uart5_apps_clk.clkr,
+ [GCC_BLSP2_QUP6_SPI_APPS_CLK] = &gcc_blsp2_qup6_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP6_I2C_APPS_CLK] = &gcc_blsp2_qup6_i2c_apps_clk.clkr,
+ [GCC_BLSP2_UART6_APPS_CLK] = &gcc_blsp2_uart6_apps_clk.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+ [GCC_TSIF_AHB_CLK] = &gcc_tsif_ahb_clk.clkr,
+ [GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr,
+ [GCC_TSIF_INACTIVITY_TIMERS_CLK] = &gcc_tsif_inactivity_timers_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+ [GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr,
+ [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr,
+ [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr,
+ [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr,
+ [GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr,
+ [GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr,
+ [GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr,
+ [GCC_PCIE_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr,
+ [GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr,
+ [GCC_PCIE_PHY_CFG_AHB_CLK] = &gcc_pcie_phy_cfg_ahb_clk.clkr,
+ [GCC_PCIE_PHY_AUX_CLK] = &gcc_pcie_phy_aux_clk.clkr,
+ [GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
+ [GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
+ [GCC_UFS_TX_CFG_CLK] = &gcc_ufs_tx_cfg_clk.clkr,
+ [GCC_UFS_RX_CFG_CLK] = &gcc_ufs_rx_cfg_clk.clkr,
+ [GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
+ [GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
+ [GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
+ [GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
+ [GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
+ [GCC_UFS_SYS_CLK_CORE_CLK] = &gcc_ufs_sys_clk_core_clk.clkr,
+ [GCC_UFS_TX_SYMBOL_CLK_CORE_CLK] = &gcc_ufs_tx_symbol_clk_core_clk.clkr,
+ [GCC_AGGRE0_SNOC_AXI_CLK] = &gcc_aggre0_snoc_axi_clk.clkr,
+ [GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
+ [GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
+ [GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
+ [GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
+ [GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
+ [GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
+ [GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
+ [GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
+ [GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
+ [GCC_HDMI_CLKREF_CLK] = &gcc_hdmi_clkref_clk.clkr,
+ [GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
+ [GCC_PCIE_CLKREF_CLK] = &gcc_pcie_clkref_clk.clkr,
+ [GCC_RX2_USB2_CLKREF_CLK] = &gcc_rx2_usb2_clkref_clk.clkr,
+ [GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+};
+
+static const struct qcom_reset_map gcc_msm8996_resets[] = {
+ [GCC_SYSTEM_NOC_BCR] = { 0x4000 },
+ [GCC_CONFIG_NOC_BCR] = { 0x5000 },
+ [GCC_PERIPH_NOC_BCR] = { 0x6000 },
+ [GCC_IMEM_BCR] = { 0x8000 },
+ [GCC_MMSS_BCR] = { 0x9000 },
+ [GCC_PIMEM_BCR] = { 0x0a000 },
+ [GCC_QDSS_BCR] = { 0x0c000 },
+ [GCC_USB_30_BCR] = { 0x0f000 },
+ [GCC_USB_20_BCR] = { 0x12000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12038 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x1203c },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+ [GCC_SDCC1_BCR] = { 0x13000 },
+ [GCC_SDCC2_BCR] = { 0x14000 },
+ [GCC_SDCC3_BCR] = { 0x15000 },
+ [GCC_SDCC4_BCR] = { 0x16000 },
+ [GCC_BLSP1_BCR] = { 0x17000 },
+ [GCC_BLSP1_QUP1_BCR] = { 0x19000 },
+ [GCC_BLSP1_UART1_BCR] = { 0x1a000 },
+ [GCC_BLSP1_QUP2_BCR] = { 0x1b000 },
+ [GCC_BLSP1_UART2_BCR] = { 0x1c000 },
+ [GCC_BLSP1_QUP3_BCR] = { 0x1d000 },
+ [GCC_BLSP1_UART3_BCR] = { 0x1e000 },
+ [GCC_BLSP1_QUP4_BCR] = { 0x1f000 },
+ [GCC_BLSP1_UART4_BCR] = { 0x20000 },
+ [GCC_BLSP1_QUP5_BCR] = { 0x21000 },
+ [GCC_BLSP1_UART5_BCR] = { 0x22000 },
+ [GCC_BLSP1_QUP6_BCR] = { 0x23000 },
+ [GCC_BLSP1_UART6_BCR] = { 0x24000 },
+ [GCC_BLSP2_BCR] = { 0x25000 },
+ [GCC_BLSP2_QUP1_BCR] = { 0x26000 },
+ [GCC_BLSP2_UART1_BCR] = { 0x27000 },
+ [GCC_BLSP2_QUP2_BCR] = { 0x28000 },
+ [GCC_BLSP2_UART2_BCR] = { 0x29000 },
+ [GCC_BLSP2_QUP3_BCR] = { 0x2a000 },
+ [GCC_BLSP2_UART3_BCR] = { 0x2b000 },
+ [GCC_BLSP2_QUP4_BCR] = { 0x2c000 },
+ [GCC_BLSP2_UART4_BCR] = { 0x2d000 },
+ [GCC_BLSP2_QUP5_BCR] = { 0x2e000 },
+ [GCC_BLSP2_UART5_BCR] = { 0x2f000 },
+ [GCC_BLSP2_QUP6_BCR] = { 0x30000 },
+ [GCC_BLSP2_UART6_BCR] = { 0x31000 },
+ [GCC_PDM_BCR] = { 0x33000 },
+ [GCC_PRNG_BCR] = { 0x34000 },
+ [GCC_TSIF_BCR] = { 0x36000 },
+ [GCC_TCSR_BCR] = { 0x37000 },
+ [GCC_BOOT_ROM_BCR] = { 0x38000 },
+ [GCC_MSG_RAM_BCR] = { 0x39000 },
+ [GCC_TLMM_BCR] = { 0x3a000 },
+ [GCC_MPM_BCR] = { 0x3b000 },
+ [GCC_SEC_CTRL_BCR] = { 0x3d000 },
+ [GCC_SPMI_BCR] = { 0x3f000 },
+ [GCC_SPDM_BCR] = { 0x40000 },
+ [GCC_CE1_BCR] = { 0x41000 },
+ [GCC_BIMC_BCR] = { 0x44000 },
+ [GCC_SNOC_BUS_TIMEOUT0_BCR] = { 0x49000 },
+ [GCC_SNOC_BUS_TIMEOUT2_BCR] = { 0x49008 },
+ [GCC_SNOC_BUS_TIMEOUT1_BCR] = { 0x49010 },
+ [GCC_SNOC_BUS_TIMEOUT3_BCR] = { 0x49018 },
+ [GCC_SNOC_BUS_TIMEOUT_EXTREF_BCR] = { 0x49020 },
+ [GCC_PNOC_BUS_TIMEOUT0_BCR] = { 0x4a000 },
+ [GCC_PNOC_BUS_TIMEOUT1_BCR] = { 0x4a008 },
+ [GCC_PNOC_BUS_TIMEOUT2_BCR] = { 0x4a010 },
+ [GCC_PNOC_BUS_TIMEOUT3_BCR] = { 0x4a018 },
+ [GCC_PNOC_BUS_TIMEOUT4_BCR] = { 0x4a020 },
+ [GCC_CNOC_BUS_TIMEOUT0_BCR] = { 0x4b000 },
+ [GCC_CNOC_BUS_TIMEOUT1_BCR] = { 0x4b008 },
+ [GCC_CNOC_BUS_TIMEOUT2_BCR] = { 0x4b010 },
+ [GCC_CNOC_BUS_TIMEOUT3_BCR] = { 0x4b018 },
+ [GCC_CNOC_BUS_TIMEOUT4_BCR] = { 0x4b020 },
+ [GCC_CNOC_BUS_TIMEOUT5_BCR] = { 0x4b028 },
+ [GCC_CNOC_BUS_TIMEOUT6_BCR] = { 0x4b030 },
+ [GCC_CNOC_BUS_TIMEOUT7_BCR] = { 0x4b038 },
+ [GCC_CNOC_BUS_TIMEOUT8_BCR] = { 0x80000 },
+ [GCC_CNOC_BUS_TIMEOUT9_BCR] = { 0x80008 },
+ [GCC_CNOC_BUS_TIMEOUT_EXTREF_BCR] = { 0x80010 },
+ [GCC_APB2JTAG_BCR] = { 0x4c000 },
+ [GCC_RBCPR_CX_BCR] = { 0x4e000 },
+ [GCC_RBCPR_MX_BCR] = { 0x4f000 },
+ [GCC_PCIE_0_BCR] = { 0x6b000 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+ [GCC_PCIE_1_BCR] = { 0x6d000 },
+ [GCC_PCIE_1_PHY_BCR] = { 0x6d038 },
+ [GCC_PCIE_2_BCR] = { 0x6e000 },
+ [GCC_PCIE_2_PHY_BCR] = { 0x6e038 },
+ [GCC_PCIE_PHY_BCR] = { 0x6f000 },
+ [GCC_DCD_BCR] = { 0x70000 },
+ [GCC_OBT_ODT_BCR] = { 0x73000 },
+ [GCC_UFS_BCR] = { 0x75000 },
+ [GCC_SSC_BCR] = { 0x63000 },
+ [GCC_VS_BCR] = { 0x7a000 },
+ [GCC_AGGRE0_NOC_BCR] = { 0x81000 },
+ [GCC_AGGRE1_NOC_BCR] = { 0x82000 },
+ [GCC_AGGRE2_NOC_BCR] = { 0x83000 },
+ [GCC_DCC_BCR] = { 0x84000 },
+ [GCC_IPA_BCR] = { 0x89000 },
+ [GCC_QSPI_BCR] = { 0x8b000 },
+ [GCC_SKL_BCR] = { 0x8c000 },
+ [GCC_MSMPU_BCR] = { 0x8d000 },
+ [GCC_MSS_Q6_BCR] = { 0x8e000 },
+ [GCC_QREFS_VBG_CAL_BCR] = { 0x88020 },
+};
+
+static const struct regmap_config gcc_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x8f010,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_msm8996_desc = {
+ .config = &gcc_msm8996_regmap_config,
+ .clks = gcc_msm8996_clocks,
+ .num_clks = ARRAY_SIZE(gcc_msm8996_clocks),
+ .resets = gcc_msm8996_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8996_resets),
+};
+
+static const struct of_device_id gcc_msm8996_match_table[] = {
+ { .compatible = "qcom,gcc-msm8996" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_msm8996_match_table);
+
+static int gcc_msm8996_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ struct device *dev = &pdev->dev;
+ int i;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &gcc_msm8996_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /*
+ * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
+ * turned off by hardware during certain apps low power modes.
+ */
+ regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
+
+ for (i = 0; i < ARRAY_SIZE(gcc_msm8996_hws); i++) {
+ clk = devm_clk_register(dev, gcc_msm8996_hws[i]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
+ return qcom_cc_really_probe(pdev, &gcc_msm8996_desc, regmap);
+}
+
+static struct platform_driver gcc_msm8996_driver = {
+ .probe = gcc_msm8996_probe,
+ .driver = {
+ .name = "gcc-msm8996",
+ .of_match_table = gcc_msm8996_match_table,
+ },
+};
+
+static int __init gcc_msm8996_init(void)
+{
+ return platform_driver_register(&gcc_msm8996_driver);
+}
+core_initcall(gcc_msm8996_init);
+
+static void __exit gcc_msm8996_exit(void)
+{
+ platform_driver_unregister(&gcc_msm8996_driver);
+}
+module_exit(gcc_msm8996_exit);
+
+MODULE_DESCRIPTION("QCOM GCC MSM8996 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:gcc-msm8996");
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
index db3998e5e2d8..62e79fadd5f7 100644
--- a/drivers/clk/qcom/lcc-ipq806x.c
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -419,6 +419,7 @@ static const struct regmap_config lcc_ipq806x_regmap_config = {
.val_bits = 32,
.max_register = 0xfc,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc lcc_ipq806x_desc = {
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
index 4fcf9d1d233c..bf95bb0ea1b8 100644
--- a/drivers/clk/qcom/lcc-msm8960.c
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -524,6 +524,7 @@ static const struct regmap_config lcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0xfc,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc lcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c
index 30777f9f1a43..1e703fda8a0f 100644
--- a/drivers/clk/qcom/mmcc-apq8084.c
+++ b/drivers/clk/qcom/mmcc-apq8084.c
@@ -3368,6 +3368,7 @@ static const struct regmap_config mmcc_apq8084_regmap_config = {
.val_bits = 32,
.max_register = 0x5104,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_apq8084_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c
index 00e36192a1de..d73a048d3b9d 100644
--- a/drivers/clk/qcom/mmcc-msm8960.c
+++ b/drivers/clk/qcom/mmcc-msm8960.c
@@ -3029,6 +3029,7 @@ static const struct regmap_config mmcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0x334,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct regmap_config mmcc_apq8064_regmap_config = {
@@ -3037,6 +3038,7 @@ static const struct regmap_config mmcc_apq8064_regmap_config = {
.val_bits = 32,
.max_register = 0x350,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c
index 9d790bcadf25..bbe28ed93669 100644
--- a/drivers/clk/qcom/mmcc-msm8974.c
+++ b/drivers/clk/qcom/mmcc-msm8974.c
@@ -2594,6 +2594,7 @@ static const struct regmap_config mmcc_msm8974_regmap_config = {
.val_bits = 32,
.max_register = 0x5104,
.fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_msm8974_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c
new file mode 100644
index 000000000000..064f3eaa39d0
--- /dev/null
+++ b/drivers/clk/qcom/mmcc-msm8996.c
@@ -0,0 +1,3217 @@
+/*x
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+ P_XO,
+ P_MMPLL0,
+ P_GPLL0,
+ P_GPLL0_DIV,
+ P_MMPLL1,
+ P_MMPLL9,
+ P_MMPLL2,
+ P_MMPLL8,
+ P_MMPLL3,
+ P_DSI0PLL,
+ P_DSI1PLL,
+ P_MMPLL5,
+ P_HDMIPLL,
+ P_DSI0PLL_BYTE,
+ P_DSI1PLL_BYTE,
+ P_MMPLL4,
+};
+
+static const struct parent_map mmss_xo_hdmi_map[] = {
+ { P_XO, 0 },
+ { P_HDMIPLL, 1 }
+};
+
+static const char * const mmss_xo_hdmi[] = {
+ "xo",
+ "hdmipll"
+};
+
+static const struct parent_map mmss_xo_dsi0pll_dsi1pll_map[] = {
+ { P_XO, 0 },
+ { P_DSI0PLL, 1 },
+ { P_DSI1PLL, 2 }
+};
+
+static const char * const mmss_xo_dsi0pll_dsi1pll[] = {
+ "xo",
+ "dsi0pll",
+ "dsi1pll"
+};
+
+static const struct parent_map mmss_xo_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_gpll0_gpll0_div[] = {
+ "xo",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_dsibyte_map[] = {
+ { P_XO, 0 },
+ { P_DSI0PLL_BYTE, 1 },
+ { P_DSI1PLL_BYTE, 2 }
+};
+
+static const char * const mmss_xo_dsibyte[] = {
+ "xo",
+ "dsi0pllbyte",
+ "dsi1pllbyte"
+};
+
+static const struct parent_map mmss_xo_mmpll0_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL1, 2 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "mmpll1",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL3, 3 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "mmpll3",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL5, 2 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "mmpll5",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL4, 3 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "mmpll4",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL9, 2 },
+ { P_MMPLL2, 3 },
+ { P_MMPLL8, 4 },
+ { P_GPLL0, 5 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0[] = {
+ "xo",
+ "mmpll0",
+ "mmpll9",
+ "mmpll2",
+ "mmpll8",
+ "gpll0"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL9, 2 },
+ { P_MMPLL2, 3 },
+ { P_MMPLL8, 4 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "mmpll9",
+ "mmpll2",
+ "mmpll8",
+ "gpll0",
+ "gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map[] = {
+ { P_XO, 0 },
+ { P_MMPLL0, 1 },
+ { P_MMPLL1, 2 },
+ { P_MMPLL4, 3 },
+ { P_MMPLL3, 4 },
+ { P_GPLL0, 5 },
+ { P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div[] = {
+ "xo",
+ "mmpll0",
+ "mmpll1",
+ "mmpll4",
+ "mmpll3",
+ "gpll0",
+ "gpll0_div"
+};
+
+static struct clk_fixed_factor gpll0_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_div",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct pll_vco mmpll_p_vco[] = {
+ { 250000000, 500000000, 3 },
+ { 500000000, 1000000000, 2 },
+ { 1000000000, 1500000000, 1 },
+ { 1500000000, 2000000000, 0 },
+};
+
+static struct pll_vco mmpll_gfx_vco[] = {
+ { 400000000, 1000000000, 2 },
+ { 1000000000, 1500000000, 1 },
+ { 1500000000, 2000000000, 0 },
+};
+
+static struct pll_vco mmpll_t_vco[] = {
+ { 500000000, 1500000000, 0 },
+};
+
+static struct clk_alpha_pll mmpll0_early = {
+ .offset = 0x0,
+ .vco_table = mmpll_p_vco,
+ .num_vco = ARRAY_SIZE(mmpll_p_vco),
+ .clkr = {
+ .enable_reg = 0x100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll0_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll0 = {
+ .offset = 0x0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll0",
+ .parent_names = (const char *[]){ "mmpll0_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll1_early = {
+ .offset = 0x30,
+ .vco_table = mmpll_p_vco,
+ .num_vco = ARRAY_SIZE(mmpll_p_vco),
+ .clkr = {
+ .enable_reg = 0x100,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll1_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ }
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll1 = {
+ .offset = 0x30,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll1",
+ .parent_names = (const char *[]){ "mmpll1_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll2_early = {
+ .offset = 0x4100,
+ .vco_table = mmpll_gfx_vco,
+ .num_vco = ARRAY_SIZE(mmpll_gfx_vco),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll2_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll2 = {
+ .offset = 0x4100,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll2",
+ .parent_names = (const char *[]){ "mmpll2_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll3_early = {
+ .offset = 0x60,
+ .vco_table = mmpll_p_vco,
+ .num_vco = ARRAY_SIZE(mmpll_p_vco),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll3_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll3 = {
+ .offset = 0x60,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll3",
+ .parent_names = (const char *[]){ "mmpll3_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll4_early = {
+ .offset = 0x90,
+ .vco_table = mmpll_t_vco,
+ .num_vco = ARRAY_SIZE(mmpll_t_vco),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll4_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll4 = {
+ .offset = 0x90,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll4",
+ .parent_names = (const char *[]){ "mmpll4_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll5_early = {
+ .offset = 0xc0,
+ .vco_table = mmpll_p_vco,
+ .num_vco = ARRAY_SIZE(mmpll_p_vco),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll5_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll5 = {
+ .offset = 0xc0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll5",
+ .parent_names = (const char *[]){ "mmpll5_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll8_early = {
+ .offset = 0x4130,
+ .vco_table = mmpll_gfx_vco,
+ .num_vco = ARRAY_SIZE(mmpll_gfx_vco),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll8_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll8 = {
+ .offset = 0x4130,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll8",
+ .parent_names = (const char *[]){ "mmpll8_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_alpha_pll mmpll9_early = {
+ .offset = 0x4200,
+ .vco_table = mmpll_t_vco,
+ .num_vco = ARRAY_SIZE(mmpll_t_vco),
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll9_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv mmpll9 = {
+ .offset = 0x4200,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll9",
+ .parent_names = (const char *[]){ "mmpll9_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct freq_tbl ftbl_ahb_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(40000000, P_GPLL0_DIV, 7.5, 0, 0),
+ F(80000000, P_MMPLL0, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ahb_clk_src = {
+ .cmd_rcgr = 0x5000,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ahb_clk_src",
+ .parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_axi_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(75000000, P_GPLL0_DIV, 4, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(171430000, P_GPLL0, 3.5, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(320000000, P_MMPLL0, 2.5, 0, 0),
+ F(400000000, P_MMPLL0, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 axi_clk_src = {
+ .cmd_rcgr = 0x5040,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "axi_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 maxi_clk_src = {
+ .cmd_rcgr = 0x5090,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "maxi_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gfx3d_clk_src = {
+ .cmd_rcgr = 0x4000,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gfx3d_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0,
+ .num_parents = 6,
+ .ops = &clk_gfx3d_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct freq_tbl ftbl_rbbmtimer_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 rbbmtimer_clk_src = {
+ .cmd_rcgr = 0x4090,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_rbbmtimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "rbbmtimer_clk_src",
+ .parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 isense_clk_src = {
+ .cmd_rcgr = 0x4010,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "isense_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 rbcpr_clk_src = {
+ .cmd_rcgr = 0x4060,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_rbcpr_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "rbcpr_clk_src",
+ .parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_video_core_clk_src[] = {
+ F(75000000, P_GPLL0_DIV, 4, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(346666667, P_MMPLL3, 3, 0, 0),
+ F(520000000, P_MMPLL3, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_core_clk_src = {
+ .cmd_rcgr = 0x1000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_video_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "video_core_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 video_subcore0_clk_src = {
+ .cmd_rcgr = 0x1060,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_video_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "video_subcore0_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 video_subcore1_clk_src = {
+ .cmd_rcgr = 0x1080,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_video_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "video_subcore1_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 pclk0_clk_src = {
+ .cmd_rcgr = 0x2000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_dsi0pll_dsi1pll_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk0_clk_src",
+ .parent_names = mmss_xo_dsi0pll_dsi1pll,
+ .num_parents = 3,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_rcg2 pclk1_clk_src = {
+ .cmd_rcgr = 0x2020,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_dsi0pll_dsi1pll_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk1_clk_src",
+ .parent_names = mmss_xo_dsi0pll_dsi1pll,
+ .num_parents = 3,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct freq_tbl ftbl_mdp_clk_src[] = {
+ F(85714286, P_GPLL0, 7, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(171428571, P_GPLL0, 3.5, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(275000000, P_MMPLL5, 3, 0, 0),
+ F(300000000, P_GPLL0, 2, 0, 0),
+ F(330000000, P_MMPLL5, 2.5, 0, 0),
+ F(412500000, P_MMPLL5, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 mdp_clk_src = {
+ .cmd_rcgr = 0x2040,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mdp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mdp_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct freq_tbl extpclk_freq_tbl[] = {
+ { .src = P_HDMIPLL },
+ { }
+};
+
+static struct clk_rcg2 extpclk_clk_src = {
+ .cmd_rcgr = 0x2060,
+ .hid_width = 5,
+ .parent_map = mmss_xo_hdmi_map,
+ .freq_tbl = extpclk_freq_tbl,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "extpclk_clk_src",
+ .parent_names = mmss_xo_hdmi,
+ .num_parents = 2,
+ .ops = &clk_byte_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct freq_tbl ftbl_mdss_vsync_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 vsync_clk_src = {
+ .cmd_rcgr = 0x2080,
+ .hid_width = 5,
+ .parent_map = mmss_xo_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mdss_vsync_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vsync_clk_src",
+ .parent_names = mmss_xo_gpll0_gpll0_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct freq_tbl ftbl_mdss_hdmi_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 hdmi_clk_src = {
+ .cmd_rcgr = 0x2100,
+ .hid_width = 5,
+ .parent_map = mmss_xo_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mdss_hdmi_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hdmi_clk_src",
+ .parent_names = mmss_xo_gpll0_gpll0_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 byte0_clk_src = {
+ .cmd_rcgr = 0x2120,
+ .hid_width = 5,
+ .parent_map = mmss_xo_dsibyte_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte0_clk_src",
+ .parent_names = mmss_xo_dsibyte,
+ .num_parents = 3,
+ .ops = &clk_byte2_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_rcg2 byte1_clk_src = {
+ .cmd_rcgr = 0x2140,
+ .hid_width = 5,
+ .parent_map = mmss_xo_dsibyte_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte1_clk_src",
+ .parent_names = mmss_xo_dsibyte,
+ .num_parents = 3,
+ .ops = &clk_byte2_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct freq_tbl ftbl_mdss_esc0_1_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 esc0_clk_src = {
+ .cmd_rcgr = 0x2160,
+ .hid_width = 5,
+ .parent_map = mmss_xo_dsibyte_map,
+ .freq_tbl = ftbl_mdss_esc0_1_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc0_clk_src",
+ .parent_names = mmss_xo_dsibyte,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 esc1_clk_src = {
+ .cmd_rcgr = 0x2180,
+ .hid_width = 5,
+ .parent_map = mmss_xo_dsibyte_map,
+ .freq_tbl = ftbl_mdss_esc0_1_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc1_clk_src",
+ .parent_names = mmss_xo_dsibyte,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camss_gp0_clk_src[] = {
+ F(10000, P_XO, 16, 1, 120),
+ F(24000, P_XO, 16, 1, 50),
+ F(6000000, P_GPLL0_DIV, 10, 1, 5),
+ F(12000000, P_GPLL0_DIV, 1, 1, 25),
+ F(13000000, P_GPLL0_DIV, 2, 13, 150),
+ F(24000000, P_GPLL0_DIV, 1, 2, 25),
+ { }
+};
+
+static struct clk_rcg2 camss_gp0_clk_src = {
+ .cmd_rcgr = 0x3420,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camss_gp0_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camss_gp1_clk_src = {
+ .cmd_rcgr = 0x3450,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camss_gp1_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_mclk0_clk_src[] = {
+ F(4800000, P_XO, 4, 0, 0),
+ F(6000000, P_GPLL0_DIV, 10, 1, 5),
+ F(8000000, P_GPLL0_DIV, 1, 2, 75),
+ F(9600000, P_XO, 2, 0, 0),
+ F(16666667, P_GPLL0_DIV, 2, 1, 9),
+ F(19200000, P_XO, 1, 0, 0),
+ F(24000000, P_GPLL0_DIV, 1, 2, 25),
+ F(33333333, P_GPLL0_DIV, 1, 1, 9),
+ F(48000000, P_GPLL0, 1, 2, 25),
+ F(66666667, P_GPLL0, 1, 1, 9),
+ { }
+};
+
+static struct clk_rcg2 mclk0_clk_src = {
+ .cmd_rcgr = 0x3360,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk0_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 mclk1_clk_src = {
+ .cmd_rcgr = 0x3390,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk1_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 mclk2_clk_src = {
+ .cmd_rcgr = 0x33c0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk2_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 mclk3_clk_src = {
+ .cmd_rcgr = 0x33f0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk3_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cci_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(37500000, P_GPLL0, 16, 0, 0),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cci_clk_src = {
+ .cmd_rcgr = 0x3300,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_cci_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cci_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_csi0phytimer_clk_src[] = {
+ F(100000000, P_GPLL0_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(266666667, P_MMPLL0, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x3000,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi0phytimer_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x3030,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi1phytimer_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x3060,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2phytimer_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_csiphy0_3p_clk_src[] = {
+ F(100000000, P_GPLL0_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(320000000, P_MMPLL4, 3, 0, 0),
+ F(384000000, P_MMPLL4, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csiphy0_3p_clk_src = {
+ .cmd_rcgr = 0x3240,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csiphy0_3p_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csiphy0_3p_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csiphy1_3p_clk_src = {
+ .cmd_rcgr = 0x3260,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csiphy0_3p_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csiphy1_3p_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csiphy2_3p_clk_src = {
+ .cmd_rcgr = 0x3280,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csiphy0_3p_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csiphy2_3p_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_jpeg0_clk_src[] = {
+ F(75000000, P_GPLL0_DIV, 4, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(228571429, P_MMPLL0, 3.5, 0, 0),
+ F(266666667, P_MMPLL0, 3, 0, 0),
+ F(320000000, P_MMPLL0, 2.5, 0, 0),
+ F(480000000, P_MMPLL4, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 jpeg0_clk_src = {
+ .cmd_rcgr = 0x3500,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_jpeg0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "jpeg0_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_jpeg2_clk_src[] = {
+ F(75000000, P_GPLL0_DIV, 4, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(228571429, P_MMPLL0, 3.5, 0, 0),
+ F(266666667, P_MMPLL0, 3, 0, 0),
+ F(320000000, P_MMPLL0, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 jpeg2_clk_src = {
+ .cmd_rcgr = 0x3540,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_jpeg2_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "jpeg2_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 jpeg_dma_clk_src = {
+ .cmd_rcgr = 0x3560,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_jpeg0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "jpeg_dma_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_vfe0_clk_src[] = {
+ F(75000000, P_GPLL0_DIV, 4, 0, 0),
+ F(100000000, P_GPLL0_DIV, 3, 0, 0),
+ F(300000000, P_GPLL0, 2, 0, 0),
+ F(320000000, P_MMPLL0, 2.5, 0, 0),
+ F(480000000, P_MMPLL4, 2, 0, 0),
+ F(600000000, P_GPLL0, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 vfe0_clk_src = {
+ .cmd_rcgr = 0x3600,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vfe0_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 vfe1_clk_src = {
+ .cmd_rcgr = 0x3620,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vfe1_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cpp_clk_src[] = {
+ F(100000000, P_GPLL0_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(320000000, P_MMPLL0, 2.5, 0, 0),
+ F(480000000, P_MMPLL4, 2, 0, 0),
+ F(640000000, P_MMPLL4, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cpp_clk_src = {
+ .cmd_rcgr = 0x3640,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_cpp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cpp_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_csi0_clk_src[] = {
+ F(100000000, P_GPLL0_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(266666667, P_MMPLL0, 3, 0, 0),
+ F(480000000, P_MMPLL4, 2, 0, 0),
+ F(600000000, P_GPLL0, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csi0_clk_src = {
+ .cmd_rcgr = 0x3090,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi0_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csi1_clk_src = {
+ .cmd_rcgr = 0x3100,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi1_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csi2_clk_src = {
+ .cmd_rcgr = 0x3160,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 csi3_clk_src = {
+ .cmd_rcgr = 0x31c0,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi3_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_fd_core_clk_src[] = {
+ F(100000000, P_GPLL0_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(400000000, P_MMPLL0, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 fd_core_clk_src = {
+ .cmd_rcgr = 0x3b00,
+ .hid_width = 5,
+ .parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+ .freq_tbl = ftbl_fd_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "fd_core_clk_src",
+ .parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch mmss_mmagic_ahb_clk = {
+ .halt_reg = 0x5024,
+ .clkr = {
+ .enable_reg = 0x5024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mmagic_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mmagic_cfg_ahb_clk = {
+ .halt_reg = 0x5054,
+ .clkr = {
+ .enable_reg = 0x5054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mmagic_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_misc_ahb_clk = {
+ .halt_reg = 0x5018,
+ .clkr = {
+ .enable_reg = 0x5018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_misc_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_misc_cxo_clk = {
+ .halt_reg = 0x5014,
+ .clkr = {
+ .enable_reg = 0x5014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_misc_cxo_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mmagic_axi_clk = {
+ .halt_reg = 0x506c,
+ .clkr = {
+ .enable_reg = 0x506c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mmagic_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mmagic_maxi_clk = {
+ .halt_reg = 0x5074,
+ .clkr = {
+ .enable_reg = 0x5074,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mmagic_maxi_clk",
+ .parent_names = (const char *[]){ "maxi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_camss_axi_clk = {
+ .halt_reg = 0x3c44,
+ .clkr = {
+ .enable_reg = 0x3c44,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_camss_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_camss_noc_cfg_ahb_clk = {
+ .halt_reg = 0x3c48,
+ .clkr = {
+ .enable_reg = 0x3c48,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_camss_noc_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_vfe_ahb_clk = {
+ .halt_reg = 0x3c04,
+ .clkr = {
+ .enable_reg = 0x3c04,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_vfe_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_vfe_axi_clk = {
+ .halt_reg = 0x3c08,
+ .clkr = {
+ .enable_reg = 0x3c08,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_vfe_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_cpp_ahb_clk = {
+ .halt_reg = 0x3c14,
+ .clkr = {
+ .enable_reg = 0x3c14,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_cpp_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_cpp_axi_clk = {
+ .halt_reg = 0x3c18,
+ .clkr = {
+ .enable_reg = 0x3c18,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_cpp_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_jpeg_ahb_clk = {
+ .halt_reg = 0x3c24,
+ .clkr = {
+ .enable_reg = 0x3c24,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_jpeg_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_jpeg_axi_clk = {
+ .halt_reg = 0x3c28,
+ .clkr = {
+ .enable_reg = 0x3c28,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_jpeg_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_mdss_axi_clk = {
+ .halt_reg = 0x2474,
+ .clkr = {
+ .enable_reg = 0x2474,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_mdss_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_mdss_noc_cfg_ahb_clk = {
+ .halt_reg = 0x2478,
+ .clkr = {
+ .enable_reg = 0x2478,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_mdss_noc_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_rot_ahb_clk = {
+ .halt_reg = 0x2444,
+ .clkr = {
+ .enable_reg = 0x2444,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_rot_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_rot_axi_clk = {
+ .halt_reg = 0x2448,
+ .clkr = {
+ .enable_reg = 0x2448,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_rot_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_mdp_ahb_clk = {
+ .halt_reg = 0x2454,
+ .clkr = {
+ .enable_reg = 0x2454,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_mdp_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_mdp_axi_clk = {
+ .halt_reg = 0x2458,
+ .clkr = {
+ .enable_reg = 0x2458,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_mdp_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_video_axi_clk = {
+ .halt_reg = 0x1194,
+ .clkr = {
+ .enable_reg = 0x1194,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_video_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_video_noc_cfg_ahb_clk = {
+ .halt_reg = 0x1198,
+ .clkr = {
+ .enable_reg = 0x1198,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_video_noc_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_video_ahb_clk = {
+ .halt_reg = 0x1174,
+ .clkr = {
+ .enable_reg = 0x1174,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_video_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch smmu_video_axi_clk = {
+ .halt_reg = 0x1178,
+ .clkr = {
+ .enable_reg = 0x1178,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "smmu_video_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_bimc_axi_clk = {
+ .halt_reg = 0x5294,
+ .clkr = {
+ .enable_reg = 0x5294,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_bimc_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmagic_bimc_noc_cfg_ahb_clk = {
+ .halt_reg = 0x5298,
+ .clkr = {
+ .enable_reg = 0x5298,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmagic_bimc_noc_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_gx_gfx3d_clk = {
+ .halt_reg = 0x4028,
+ .clkr = {
+ .enable_reg = 0x4028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_gx_gfx3d_clk",
+ .parent_names = (const char *[]){ "gfx3d_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_gx_rbbmtimer_clk = {
+ .halt_reg = 0x40b0,
+ .clkr = {
+ .enable_reg = 0x40b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_gx_rbbmtimer_clk",
+ .parent_names = (const char *[]){ "rbbmtimer_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_ahb_clk = {
+ .halt_reg = 0x403c,
+ .clkr = {
+ .enable_reg = 0x403c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_aon_isense_clk = {
+ .halt_reg = 0x4044,
+ .clkr = {
+ .enable_reg = 0x4044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_aon_isense_clk",
+ .parent_names = (const char *[]){ "isense_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch vmem_maxi_clk = {
+ .halt_reg = 0x1204,
+ .clkr = {
+ .enable_reg = 0x1204,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "vmem_maxi_clk",
+ .parent_names = (const char *[]){ "maxi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch vmem_ahb_clk = {
+ .halt_reg = 0x1208,
+ .clkr = {
+ .enable_reg = 0x1208,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "vmem_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_rbcpr_clk = {
+ .halt_reg = 0x4084,
+ .clkr = {
+ .enable_reg = 0x4084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_rbcpr_clk",
+ .parent_names = (const char *[]){ "rbcpr_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_rbcpr_ahb_clk = {
+ .halt_reg = 0x4088,
+ .clkr = {
+ .enable_reg = 0x4088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_rbcpr_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_core_clk = {
+ .halt_reg = 0x1028,
+ .clkr = {
+ .enable_reg = 0x1028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "video_core_clk",
+ .parent_names = (const char *[]){ "video_core_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_axi_clk = {
+ .halt_reg = 0x1034,
+ .clkr = {
+ .enable_reg = 0x1034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "video_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_maxi_clk = {
+ .halt_reg = 0x1038,
+ .clkr = {
+ .enable_reg = 0x1038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "video_maxi_clk",
+ .parent_names = (const char *[]){ "maxi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_ahb_clk = {
+ .halt_reg = 0x1030,
+ .clkr = {
+ .enable_reg = 0x1030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "video_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_subcore0_clk = {
+ .halt_reg = 0x1048,
+ .clkr = {
+ .enable_reg = 0x1048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "video_subcore0_clk",
+ .parent_names = (const char *[]){ "video_subcore0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_subcore1_clk = {
+ .halt_reg = 0x104c,
+ .clkr = {
+ .enable_reg = 0x104c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "video_subcore1_clk",
+ .parent_names = (const char *[]){ "video_subcore1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_ahb_clk = {
+ .halt_reg = 0x2308,
+ .clkr = {
+ .enable_reg = 0x2308,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_hdmi_ahb_clk = {
+ .halt_reg = 0x230c,
+ .clkr = {
+ .enable_reg = 0x230c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_hdmi_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_axi_clk = {
+ .halt_reg = 0x2310,
+ .clkr = {
+ .enable_reg = 0x2310,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_pclk0_clk = {
+ .halt_reg = 0x2314,
+ .clkr = {
+ .enable_reg = 0x2314,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_pclk0_clk",
+ .parent_names = (const char *[]){ "pclk0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_pclk1_clk = {
+ .halt_reg = 0x2318,
+ .clkr = {
+ .enable_reg = 0x2318,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_pclk1_clk",
+ .parent_names = (const char *[]){ "pclk1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_mdp_clk = {
+ .halt_reg = 0x231c,
+ .clkr = {
+ .enable_reg = 0x231c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_mdp_clk",
+ .parent_names = (const char *[]){ "mdp_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_extpclk_clk = {
+ .halt_reg = 0x2324,
+ .clkr = {
+ .enable_reg = 0x2324,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_extpclk_clk",
+ .parent_names = (const char *[]){ "extpclk_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_vsync_clk = {
+ .halt_reg = 0x2328,
+ .clkr = {
+ .enable_reg = 0x2328,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_vsync_clk",
+ .parent_names = (const char *[]){ "vsync_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_hdmi_clk = {
+ .halt_reg = 0x2338,
+ .clkr = {
+ .enable_reg = 0x2338,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_hdmi_clk",
+ .parent_names = (const char *[]){ "hdmi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_byte0_clk = {
+ .halt_reg = 0x233c,
+ .clkr = {
+ .enable_reg = 0x233c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_byte0_clk",
+ .parent_names = (const char *[]){ "byte0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_byte1_clk = {
+ .halt_reg = 0x2340,
+ .clkr = {
+ .enable_reg = 0x2340,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_byte1_clk",
+ .parent_names = (const char *[]){ "byte1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_esc0_clk = {
+ .halt_reg = 0x2344,
+ .clkr = {
+ .enable_reg = 0x2344,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_esc0_clk",
+ .parent_names = (const char *[]){ "esc0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mdss_esc1_clk = {
+ .halt_reg = 0x2348,
+ .clkr = {
+ .enable_reg = 0x2348,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mdss_esc1_clk",
+ .parent_names = (const char *[]){ "esc1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_top_ahb_clk = {
+ .halt_reg = 0x3484,
+ .clkr = {
+ .enable_reg = 0x3484,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_top_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_ahb_clk = {
+ .halt_reg = 0x348c,
+ .clkr = {
+ .enable_reg = 0x348c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_micro_ahb_clk = {
+ .halt_reg = 0x3494,
+ .clkr = {
+ .enable_reg = 0x3494,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_micro_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_gp0_clk = {
+ .halt_reg = 0x3444,
+ .clkr = {
+ .enable_reg = 0x3444,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_gp0_clk",
+ .parent_names = (const char *[]){ "camss_gp0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_gp1_clk = {
+ .halt_reg = 0x3474,
+ .clkr = {
+ .enable_reg = 0x3474,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_gp1_clk",
+ .parent_names = (const char *[]){ "camss_gp1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_mclk0_clk = {
+ .halt_reg = 0x3384,
+ .clkr = {
+ .enable_reg = 0x3384,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_mclk0_clk",
+ .parent_names = (const char *[]){ "mclk0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_mclk1_clk = {
+ .halt_reg = 0x33b4,
+ .clkr = {
+ .enable_reg = 0x33b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_mclk1_clk",
+ .parent_names = (const char *[]){ "mclk1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_mclk2_clk = {
+ .halt_reg = 0x33e4,
+ .clkr = {
+ .enable_reg = 0x33e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_mclk2_clk",
+ .parent_names = (const char *[]){ "mclk2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_mclk3_clk = {
+ .halt_reg = 0x3414,
+ .clkr = {
+ .enable_reg = 0x3414,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_mclk3_clk",
+ .parent_names = (const char *[]){ "mclk3_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_cci_clk = {
+ .halt_reg = 0x3344,
+ .clkr = {
+ .enable_reg = 0x3344,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_cci_clk",
+ .parent_names = (const char *[]){ "cci_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_cci_ahb_clk = {
+ .halt_reg = 0x3348,
+ .clkr = {
+ .enable_reg = 0x3348,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_cci_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi0phytimer_clk = {
+ .halt_reg = 0x3024,
+ .clkr = {
+ .enable_reg = 0x3024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi0phytimer_clk",
+ .parent_names = (const char *[]){ "csi0phytimer_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi1phytimer_clk = {
+ .halt_reg = 0x3054,
+ .clkr = {
+ .enable_reg = 0x3054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi1phytimer_clk",
+ .parent_names = (const char *[]){ "csi1phytimer_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi2phytimer_clk = {
+ .halt_reg = 0x3084,
+ .clkr = {
+ .enable_reg = 0x3084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi2phytimer_clk",
+ .parent_names = (const char *[]){ "csi2phytimer_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csiphy0_3p_clk = {
+ .halt_reg = 0x3234,
+ .clkr = {
+ .enable_reg = 0x3234,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csiphy0_3p_clk",
+ .parent_names = (const char *[]){ "csiphy0_3p_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csiphy1_3p_clk = {
+ .halt_reg = 0x3254,
+ .clkr = {
+ .enable_reg = 0x3254,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csiphy1_3p_clk",
+ .parent_names = (const char *[]){ "csiphy1_3p_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csiphy2_3p_clk = {
+ .halt_reg = 0x3274,
+ .clkr = {
+ .enable_reg = 0x3274,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csiphy2_3p_clk",
+ .parent_names = (const char *[]){ "csiphy2_3p_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_jpeg0_clk = {
+ .halt_reg = 0x35a8,
+ .clkr = {
+ .enable_reg = 0x35a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_jpeg0_clk",
+ .parent_names = (const char *[]){ "jpeg0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_jpeg2_clk = {
+ .halt_reg = 0x35b0,
+ .clkr = {
+ .enable_reg = 0x35b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_jpeg2_clk",
+ .parent_names = (const char *[]){ "jpeg2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_jpeg_dma_clk = {
+ .halt_reg = 0x35c0,
+ .clkr = {
+ .enable_reg = 0x35c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_jpeg_dma_clk",
+ .parent_names = (const char *[]){ "jpeg_dma_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_jpeg_ahb_clk = {
+ .halt_reg = 0x35b4,
+ .clkr = {
+ .enable_reg = 0x35b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_jpeg_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_jpeg_axi_clk = {
+ .halt_reg = 0x35b8,
+ .clkr = {
+ .enable_reg = 0x35b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_jpeg_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe_ahb_clk = {
+ .halt_reg = 0x36b8,
+ .clkr = {
+ .enable_reg = 0x36b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe_axi_clk = {
+ .halt_reg = 0x36bc,
+ .clkr = {
+ .enable_reg = 0x36bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe0_clk = {
+ .halt_reg = 0x36a8,
+ .clkr = {
+ .enable_reg = 0x36a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe0_clk",
+ .parent_names = (const char *[]){ "vfe0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe0_stream_clk = {
+ .halt_reg = 0x3720,
+ .clkr = {
+ .enable_reg = 0x3720,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe0_stream_clk",
+ .parent_names = (const char *[]){ "vfe0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe0_ahb_clk = {
+ .halt_reg = 0x3668,
+ .clkr = {
+ .enable_reg = 0x3668,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe0_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe1_clk = {
+ .halt_reg = 0x36ac,
+ .clkr = {
+ .enable_reg = 0x36ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe1_clk",
+ .parent_names = (const char *[]){ "vfe1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe1_stream_clk = {
+ .halt_reg = 0x3724,
+ .clkr = {
+ .enable_reg = 0x3724,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe1_stream_clk",
+ .parent_names = (const char *[]){ "vfe1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_vfe1_ahb_clk = {
+ .halt_reg = 0x3678,
+ .clkr = {
+ .enable_reg = 0x3678,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_vfe1_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi_vfe0_clk = {
+ .halt_reg = 0x3704,
+ .clkr = {
+ .enable_reg = 0x3704,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi_vfe0_clk",
+ .parent_names = (const char *[]){ "vfe0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi_vfe1_clk = {
+ .halt_reg = 0x3714,
+ .clkr = {
+ .enable_reg = 0x3714,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi_vfe1_clk",
+ .parent_names = (const char *[]){ "vfe1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_cpp_vbif_ahb_clk = {
+ .halt_reg = 0x36c8,
+ .clkr = {
+ .enable_reg = 0x36c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_cpp_vbif_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_cpp_axi_clk = {
+ .halt_reg = 0x36c4,
+ .clkr = {
+ .enable_reg = 0x36c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_cpp_axi_clk",
+ .parent_names = (const char *[]){ "axi_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_cpp_clk = {
+ .halt_reg = 0x36b0,
+ .clkr = {
+ .enable_reg = 0x36b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_cpp_clk",
+ .parent_names = (const char *[]){ "cpp_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_cpp_ahb_clk = {
+ .halt_reg = 0x36b4,
+ .clkr = {
+ .enable_reg = 0x36b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_cpp_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi0_clk = {
+ .halt_reg = 0x30b4,
+ .clkr = {
+ .enable_reg = 0x30b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi0_clk",
+ .parent_names = (const char *[]){ "csi0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi0_ahb_clk = {
+ .halt_reg = 0x30bc,
+ .clkr = {
+ .enable_reg = 0x30bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi0_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi0phy_clk = {
+ .halt_reg = 0x30c4,
+ .clkr = {
+ .enable_reg = 0x30c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi0phy_clk",
+ .parent_names = (const char *[]){ "csi0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi0rdi_clk = {
+ .halt_reg = 0x30d4,
+ .clkr = {
+ .enable_reg = 0x30d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi0rdi_clk",
+ .parent_names = (const char *[]){ "csi0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi0pix_clk = {
+ .halt_reg = 0x30e4,
+ .clkr = {
+ .enable_reg = 0x30e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi0pix_clk",
+ .parent_names = (const char *[]){ "csi0_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi1_clk = {
+ .halt_reg = 0x3124,
+ .clkr = {
+ .enable_reg = 0x3124,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi1_clk",
+ .parent_names = (const char *[]){ "csi1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi1_ahb_clk = {
+ .halt_reg = 0x3128,
+ .clkr = {
+ .enable_reg = 0x3128,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi1_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi1phy_clk = {
+ .halt_reg = 0x3134,
+ .clkr = {
+ .enable_reg = 0x3134,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi1phy_clk",
+ .parent_names = (const char *[]){ "csi1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi1rdi_clk = {
+ .halt_reg = 0x3144,
+ .clkr = {
+ .enable_reg = 0x3144,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi1rdi_clk",
+ .parent_names = (const char *[]){ "csi1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi1pix_clk = {
+ .halt_reg = 0x3154,
+ .clkr = {
+ .enable_reg = 0x3154,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi1pix_clk",
+ .parent_names = (const char *[]){ "csi1_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi2_clk = {
+ .halt_reg = 0x3184,
+ .clkr = {
+ .enable_reg = 0x3184,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi2_clk",
+ .parent_names = (const char *[]){ "csi2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi2_ahb_clk = {
+ .halt_reg = 0x3188,
+ .clkr = {
+ .enable_reg = 0x3188,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi2_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi2phy_clk = {
+ .halt_reg = 0x3194,
+ .clkr = {
+ .enable_reg = 0x3194,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi2phy_clk",
+ .parent_names = (const char *[]){ "csi2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi2rdi_clk = {
+ .halt_reg = 0x31a4,
+ .clkr = {
+ .enable_reg = 0x31a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi2rdi_clk",
+ .parent_names = (const char *[]){ "csi2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi2pix_clk = {
+ .halt_reg = 0x31b4,
+ .clkr = {
+ .enable_reg = 0x31b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi2pix_clk",
+ .parent_names = (const char *[]){ "csi2_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi3_clk = {
+ .halt_reg = 0x31e4,
+ .clkr = {
+ .enable_reg = 0x31e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi3_clk",
+ .parent_names = (const char *[]){ "csi3_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi3_ahb_clk = {
+ .halt_reg = 0x31e8,
+ .clkr = {
+ .enable_reg = 0x31e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi3_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi3phy_clk = {
+ .halt_reg = 0x31f4,
+ .clkr = {
+ .enable_reg = 0x31f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi3phy_clk",
+ .parent_names = (const char *[]){ "csi3_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi3rdi_clk = {
+ .halt_reg = 0x3204,
+ .clkr = {
+ .enable_reg = 0x3204,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi3rdi_clk",
+ .parent_names = (const char *[]){ "csi3_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_csi3pix_clk = {
+ .halt_reg = 0x3214,
+ .clkr = {
+ .enable_reg = 0x3214,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_csi3pix_clk",
+ .parent_names = (const char *[]){ "csi3_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camss_ispif_ahb_clk = {
+ .halt_reg = 0x3224,
+ .clkr = {
+ .enable_reg = 0x3224,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camss_ispif_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch fd_core_clk = {
+ .halt_reg = 0x3b68,
+ .clkr = {
+ .enable_reg = 0x3b68,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "fd_core_clk",
+ .parent_names = (const char *[]){ "fd_core_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch fd_core_uar_clk = {
+ .halt_reg = 0x3b6c,
+ .clkr = {
+ .enable_reg = 0x3b6c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "fd_core_uar_clk",
+ .parent_names = (const char *[]){ "fd_core_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch fd_ahb_clk = {
+ .halt_reg = 0x3ba74,
+ .clkr = {
+ .enable_reg = 0x3ba74,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "fd_ahb_clk",
+ .parent_names = (const char *[]){ "ahb_clk_src" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_hw *mmcc_msm8996_hws[] = {
+ &gpll0_div.hw,
+};
+
+static struct clk_regmap *mmcc_msm8996_clocks[] = {
+ [MMPLL0_EARLY] = &mmpll0_early.clkr,
+ [MMPLL0_PLL] = &mmpll0.clkr,
+ [MMPLL1_EARLY] = &mmpll1_early.clkr,
+ [MMPLL1_PLL] = &mmpll1.clkr,
+ [MMPLL2_EARLY] = &mmpll2_early.clkr,
+ [MMPLL2_PLL] = &mmpll2.clkr,
+ [MMPLL3_EARLY] = &mmpll3_early.clkr,
+ [MMPLL3_PLL] = &mmpll3.clkr,
+ [MMPLL4_EARLY] = &mmpll4_early.clkr,
+ [MMPLL4_PLL] = &mmpll4.clkr,
+ [MMPLL5_EARLY] = &mmpll5_early.clkr,
+ [MMPLL5_PLL] = &mmpll5.clkr,
+ [MMPLL8_EARLY] = &mmpll8_early.clkr,
+ [MMPLL8_PLL] = &mmpll8.clkr,
+ [MMPLL9_EARLY] = &mmpll9_early.clkr,
+ [MMPLL9_PLL] = &mmpll9.clkr,
+ [AHB_CLK_SRC] = &ahb_clk_src.clkr,
+ [AXI_CLK_SRC] = &axi_clk_src.clkr,
+ [MAXI_CLK_SRC] = &maxi_clk_src.clkr,
+ [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
+ [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
+ [ISENSE_CLK_SRC] = &isense_clk_src.clkr,
+ [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
+ [VIDEO_CORE_CLK_SRC] = &video_core_clk_src.clkr,
+ [VIDEO_SUBCORE0_CLK_SRC] = &video_subcore0_clk_src.clkr,
+ [VIDEO_SUBCORE1_CLK_SRC] = &video_subcore1_clk_src.clkr,
+ [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr,
+ [PCLK1_CLK_SRC] = &pclk1_clk_src.clkr,
+ [MDP_CLK_SRC] = &mdp_clk_src.clkr,
+ [EXTPCLK_CLK_SRC] = &extpclk_clk_src.clkr,
+ [VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
+ [HDMI_CLK_SRC] = &hdmi_clk_src.clkr,
+ [BYTE0_CLK_SRC] = &byte0_clk_src.clkr,
+ [BYTE1_CLK_SRC] = &byte1_clk_src.clkr,
+ [ESC0_CLK_SRC] = &esc0_clk_src.clkr,
+ [ESC1_CLK_SRC] = &esc1_clk_src.clkr,
+ [CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr,
+ [CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr,
+ [MCLK0_CLK_SRC] = &mclk0_clk_src.clkr,
+ [MCLK1_CLK_SRC] = &mclk1_clk_src.clkr,
+ [MCLK2_CLK_SRC] = &mclk2_clk_src.clkr,
+ [MCLK3_CLK_SRC] = &mclk3_clk_src.clkr,
+ [CCI_CLK_SRC] = &cci_clk_src.clkr,
+ [CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr,
+ [CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr,
+ [CSI2PHYTIMER_CLK_SRC] = &csi2phytimer_clk_src.clkr,
+ [CSIPHY0_3P_CLK_SRC] = &csiphy0_3p_clk_src.clkr,
+ [CSIPHY1_3P_CLK_SRC] = &csiphy1_3p_clk_src.clkr,
+ [CSIPHY2_3P_CLK_SRC] = &csiphy2_3p_clk_src.clkr,
+ [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr,
+ [JPEG2_CLK_SRC] = &jpeg2_clk_src.clkr,
+ [JPEG_DMA_CLK_SRC] = &jpeg_dma_clk_src.clkr,
+ [VFE0_CLK_SRC] = &vfe0_clk_src.clkr,
+ [VFE1_CLK_SRC] = &vfe1_clk_src.clkr,
+ [CPP_CLK_SRC] = &cpp_clk_src.clkr,
+ [CSI0_CLK_SRC] = &csi0_clk_src.clkr,
+ [CSI1_CLK_SRC] = &csi1_clk_src.clkr,
+ [CSI2_CLK_SRC] = &csi2_clk_src.clkr,
+ [CSI3_CLK_SRC] = &csi3_clk_src.clkr,
+ [FD_CORE_CLK_SRC] = &fd_core_clk_src.clkr,
+ [MMSS_MMAGIC_AHB_CLK] = &mmss_mmagic_ahb_clk.clkr,
+ [MMSS_MMAGIC_CFG_AHB_CLK] = &mmss_mmagic_cfg_ahb_clk.clkr,
+ [MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr,
+ [MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr,
+ [MMSS_MMAGIC_AXI_CLK] = &mmss_mmagic_axi_clk.clkr,
+ [MMSS_MMAGIC_MAXI_CLK] = &mmss_mmagic_maxi_clk.clkr,
+ [MMAGIC_CAMSS_AXI_CLK] = &mmagic_camss_axi_clk.clkr,
+ [MMAGIC_CAMSS_NOC_CFG_AHB_CLK] = &mmagic_camss_noc_cfg_ahb_clk.clkr,
+ [SMMU_VFE_AHB_CLK] = &smmu_vfe_ahb_clk.clkr,
+ [SMMU_VFE_AXI_CLK] = &smmu_vfe_axi_clk.clkr,
+ [SMMU_CPP_AHB_CLK] = &smmu_cpp_ahb_clk.clkr,
+ [SMMU_CPP_AXI_CLK] = &smmu_cpp_axi_clk.clkr,
+ [SMMU_JPEG_AHB_CLK] = &smmu_jpeg_ahb_clk.clkr,
+ [SMMU_JPEG_AXI_CLK] = &smmu_jpeg_axi_clk.clkr,
+ [MMAGIC_MDSS_AXI_CLK] = &mmagic_mdss_axi_clk.clkr,
+ [MMAGIC_MDSS_NOC_CFG_AHB_CLK] = &mmagic_mdss_noc_cfg_ahb_clk.clkr,
+ [SMMU_ROT_AHB_CLK] = &smmu_rot_ahb_clk.clkr,
+ [SMMU_ROT_AXI_CLK] = &smmu_rot_axi_clk.clkr,
+ [SMMU_MDP_AHB_CLK] = &smmu_mdp_ahb_clk.clkr,
+ [SMMU_MDP_AXI_CLK] = &smmu_mdp_axi_clk.clkr,
+ [MMAGIC_VIDEO_AXI_CLK] = &mmagic_video_axi_clk.clkr,
+ [MMAGIC_VIDEO_NOC_CFG_AHB_CLK] = &mmagic_video_noc_cfg_ahb_clk.clkr,
+ [SMMU_VIDEO_AHB_CLK] = &smmu_video_ahb_clk.clkr,
+ [SMMU_VIDEO_AXI_CLK] = &smmu_video_axi_clk.clkr,
+ [MMAGIC_BIMC_AXI_CLK] = &mmagic_bimc_axi_clk.clkr,
+ [MMAGIC_BIMC_NOC_CFG_AHB_CLK] = &mmagic_bimc_noc_cfg_ahb_clk.clkr,
+ [GPU_GX_GFX3D_CLK] = &gpu_gx_gfx3d_clk.clkr,
+ [GPU_GX_RBBMTIMER_CLK] = &gpu_gx_rbbmtimer_clk.clkr,
+ [GPU_AHB_CLK] = &gpu_ahb_clk.clkr,
+ [GPU_AON_ISENSE_CLK] = &gpu_aon_isense_clk.clkr,
+ [VMEM_MAXI_CLK] = &vmem_maxi_clk.clkr,
+ [VMEM_AHB_CLK] = &vmem_ahb_clk.clkr,
+ [MMSS_RBCPR_CLK] = &mmss_rbcpr_clk.clkr,
+ [MMSS_RBCPR_AHB_CLK] = &mmss_rbcpr_ahb_clk.clkr,
+ [VIDEO_CORE_CLK] = &video_core_clk.clkr,
+ [VIDEO_AXI_CLK] = &video_axi_clk.clkr,
+ [VIDEO_MAXI_CLK] = &video_maxi_clk.clkr,
+ [VIDEO_AHB_CLK] = &video_ahb_clk.clkr,
+ [VIDEO_SUBCORE0_CLK] = &video_subcore0_clk.clkr,
+ [VIDEO_SUBCORE1_CLK] = &video_subcore1_clk.clkr,
+ [MDSS_AHB_CLK] = &mdss_ahb_clk.clkr,
+ [MDSS_HDMI_AHB_CLK] = &mdss_hdmi_ahb_clk.clkr,
+ [MDSS_AXI_CLK] = &mdss_axi_clk.clkr,
+ [MDSS_PCLK0_CLK] = &mdss_pclk0_clk.clkr,
+ [MDSS_PCLK1_CLK] = &mdss_pclk1_clk.clkr,
+ [MDSS_MDP_CLK] = &mdss_mdp_clk.clkr,
+ [MDSS_EXTPCLK_CLK] = &mdss_extpclk_clk.clkr,
+ [MDSS_VSYNC_CLK] = &mdss_vsync_clk.clkr,
+ [MDSS_HDMI_CLK] = &mdss_hdmi_clk.clkr,
+ [MDSS_BYTE0_CLK] = &mdss_byte0_clk.clkr,
+ [MDSS_BYTE1_CLK] = &mdss_byte1_clk.clkr,
+ [MDSS_ESC0_CLK] = &mdss_esc0_clk.clkr,
+ [MDSS_ESC1_CLK] = &mdss_esc1_clk.clkr,
+ [CAMSS_TOP_AHB_CLK] = &camss_top_ahb_clk.clkr,
+ [CAMSS_AHB_CLK] = &camss_ahb_clk.clkr,
+ [CAMSS_MICRO_AHB_CLK] = &camss_micro_ahb_clk.clkr,
+ [CAMSS_GP0_CLK] = &camss_gp0_clk.clkr,
+ [CAMSS_GP1_CLK] = &camss_gp1_clk.clkr,
+ [CAMSS_MCLK0_CLK] = &camss_mclk0_clk.clkr,
+ [CAMSS_MCLK1_CLK] = &camss_mclk1_clk.clkr,
+ [CAMSS_MCLK2_CLK] = &camss_mclk2_clk.clkr,
+ [CAMSS_MCLK3_CLK] = &camss_mclk3_clk.clkr,
+ [CAMSS_CCI_CLK] = &camss_cci_clk.clkr,
+ [CAMSS_CCI_AHB_CLK] = &camss_cci_ahb_clk.clkr,
+ [CAMSS_CSI0PHYTIMER_CLK] = &camss_csi0phytimer_clk.clkr,
+ [CAMSS_CSI1PHYTIMER_CLK] = &camss_csi1phytimer_clk.clkr,
+ [CAMSS_CSI2PHYTIMER_CLK] = &camss_csi2phytimer_clk.clkr,
+ [CAMSS_CSIPHY0_3P_CLK] = &camss_csiphy0_3p_clk.clkr,
+ [CAMSS_CSIPHY1_3P_CLK] = &camss_csiphy1_3p_clk.clkr,
+ [CAMSS_CSIPHY2_3P_CLK] = &camss_csiphy2_3p_clk.clkr,
+ [CAMSS_JPEG0_CLK] = &camss_jpeg0_clk.clkr,
+ [CAMSS_JPEG2_CLK] = &camss_jpeg2_clk.clkr,
+ [CAMSS_JPEG_DMA_CLK] = &camss_jpeg_dma_clk.clkr,
+ [CAMSS_JPEG_AHB_CLK] = &camss_jpeg_ahb_clk.clkr,
+ [CAMSS_JPEG_AXI_CLK] = &camss_jpeg_axi_clk.clkr,
+ [CAMSS_VFE_AHB_CLK] = &camss_vfe_ahb_clk.clkr,
+ [CAMSS_VFE_AXI_CLK] = &camss_vfe_axi_clk.clkr,
+ [CAMSS_VFE0_CLK] = &camss_vfe0_clk.clkr,
+ [CAMSS_VFE0_STREAM_CLK] = &camss_vfe0_stream_clk.clkr,
+ [CAMSS_VFE0_AHB_CLK] = &camss_vfe0_ahb_clk.clkr,
+ [CAMSS_VFE1_CLK] = &camss_vfe1_clk.clkr,
+ [CAMSS_VFE1_STREAM_CLK] = &camss_vfe1_stream_clk.clkr,
+ [CAMSS_VFE1_AHB_CLK] = &camss_vfe1_ahb_clk.clkr,
+ [CAMSS_CSI_VFE0_CLK] = &camss_csi_vfe0_clk.clkr,
+ [CAMSS_CSI_VFE1_CLK] = &camss_csi_vfe1_clk.clkr,
+ [CAMSS_CPP_VBIF_AHB_CLK] = &camss_cpp_vbif_ahb_clk.clkr,
+ [CAMSS_CPP_AXI_CLK] = &camss_cpp_axi_clk.clkr,
+ [CAMSS_CPP_CLK] = &camss_cpp_clk.clkr,
+ [CAMSS_CPP_AHB_CLK] = &camss_cpp_ahb_clk.clkr,
+ [CAMSS_CSI0_CLK] = &camss_csi0_clk.clkr,
+ [CAMSS_CSI0_AHB_CLK] = &camss_csi0_ahb_clk.clkr,
+ [CAMSS_CSI0PHY_CLK] = &camss_csi0phy_clk.clkr,
+ [CAMSS_CSI0RDI_CLK] = &camss_csi0rdi_clk.clkr,
+ [CAMSS_CSI0PIX_CLK] = &camss_csi0pix_clk.clkr,
+ [CAMSS_CSI1_CLK] = &camss_csi1_clk.clkr,
+ [CAMSS_CSI1_AHB_CLK] = &camss_csi1_ahb_clk.clkr,
+ [CAMSS_CSI1PHY_CLK] = &camss_csi1phy_clk.clkr,
+ [CAMSS_CSI1RDI_CLK] = &camss_csi1rdi_clk.clkr,
+ [CAMSS_CSI1PIX_CLK] = &camss_csi1pix_clk.clkr,
+ [CAMSS_CSI2_CLK] = &camss_csi2_clk.clkr,
+ [CAMSS_CSI2_AHB_CLK] = &camss_csi2_ahb_clk.clkr,
+ [CAMSS_CSI2PHY_CLK] = &camss_csi2phy_clk.clkr,
+ [CAMSS_CSI2RDI_CLK] = &camss_csi2rdi_clk.clkr,
+ [CAMSS_CSI2PIX_CLK] = &camss_csi2pix_clk.clkr,
+ [CAMSS_CSI3_CLK] = &camss_csi3_clk.clkr,
+ [CAMSS_CSI3_AHB_CLK] = &camss_csi3_ahb_clk.clkr,
+ [CAMSS_CSI3PHY_CLK] = &camss_csi3phy_clk.clkr,
+ [CAMSS_CSI3RDI_CLK] = &camss_csi3rdi_clk.clkr,
+ [CAMSS_CSI3PIX_CLK] = &camss_csi3pix_clk.clkr,
+ [CAMSS_ISPIF_AHB_CLK] = &camss_ispif_ahb_clk.clkr,
+ [FD_CORE_CLK] = &fd_core_clk.clkr,
+ [FD_CORE_UAR_CLK] = &fd_core_uar_clk.clkr,
+ [FD_AHB_CLK] = &fd_ahb_clk.clkr,
+};
+
+static const struct qcom_reset_map mmcc_msm8996_resets[] = {
+ [MMAGICAHB_BCR] = { 0x5020 },
+ [MMAGIC_CFG_BCR] = { 0x5050 },
+ [MISC_BCR] = { 0x5010 },
+ [BTO_BCR] = { 0x5030 },
+ [MMAGICAXI_BCR] = { 0x5060 },
+ [MMAGICMAXI_BCR] = { 0x5070 },
+ [DSA_BCR] = { 0x50a0 },
+ [MMAGIC_CAMSS_BCR] = { 0x3c40 },
+ [THROTTLE_CAMSS_BCR] = { 0x3c30 },
+ [SMMU_VFE_BCR] = { 0x3c00 },
+ [SMMU_CPP_BCR] = { 0x3c10 },
+ [SMMU_JPEG_BCR] = { 0x3c20 },
+ [MMAGIC_MDSS_BCR] = { 0x2470 },
+ [THROTTLE_MDSS_BCR] = { 0x2460 },
+ [SMMU_ROT_BCR] = { 0x2440 },
+ [SMMU_MDP_BCR] = { 0x2450 },
+ [MMAGIC_VIDEO_BCR] = { 0x1190 },
+ [THROTTLE_VIDEO_BCR] = { 0x1180 },
+ [SMMU_VIDEO_BCR] = { 0x1170 },
+ [MMAGIC_BIMC_BCR] = { 0x5290 },
+ [GPU_GX_BCR] = { 0x4020 },
+ [GPU_BCR] = { 0x4030 },
+ [GPU_AON_BCR] = { 0x4040 },
+ [VMEM_BCR] = { 0x1200 },
+ [MMSS_RBCPR_BCR] = { 0x4080 },
+ [VIDEO_BCR] = { 0x1020 },
+ [MDSS_BCR] = { 0x2300 },
+ [CAMSS_TOP_BCR] = { 0x3480 },
+ [CAMSS_AHB_BCR] = { 0x3488 },
+ [CAMSS_MICRO_BCR] = { 0x3490 },
+ [CAMSS_CCI_BCR] = { 0x3340 },
+ [CAMSS_PHY0_BCR] = { 0x3020 },
+ [CAMSS_PHY1_BCR] = { 0x3050 },
+ [CAMSS_PHY2_BCR] = { 0x3080 },
+ [CAMSS_CSIPHY0_3P_BCR] = { 0x3230 },
+ [CAMSS_CSIPHY1_3P_BCR] = { 0x3250 },
+ [CAMSS_CSIPHY2_3P_BCR] = { 0x3270 },
+ [CAMSS_JPEG_BCR] = { 0x35a0 },
+ [CAMSS_VFE_BCR] = { 0x36a0 },
+ [CAMSS_VFE0_BCR] = { 0x3660 },
+ [CAMSS_VFE1_BCR] = { 0x3670 },
+ [CAMSS_CSI_VFE0_BCR] = { 0x3700 },
+ [CAMSS_CSI_VFE1_BCR] = { 0x3710 },
+ [CAMSS_CPP_TOP_BCR] = { 0x36c0 },
+ [CAMSS_CPP_BCR] = { 0x36d0 },
+ [CAMSS_CSI0_BCR] = { 0x30b0 },
+ [CAMSS_CSI0RDI_BCR] = { 0x30d0 },
+ [CAMSS_CSI0PIX_BCR] = { 0x30e0 },
+ [CAMSS_CSI1_BCR] = { 0x3120 },
+ [CAMSS_CSI1RDI_BCR] = { 0x3140 },
+ [CAMSS_CSI1PIX_BCR] = { 0x3150 },
+ [CAMSS_CSI2_BCR] = { 0x3180 },
+ [CAMSS_CSI2RDI_BCR] = { 0x31a0 },
+ [CAMSS_CSI2PIX_BCR] = { 0x31b0 },
+ [CAMSS_CSI3_BCR] = { 0x31e0 },
+ [CAMSS_CSI3RDI_BCR] = { 0x3200 },
+ [CAMSS_CSI3PIX_BCR] = { 0x3210 },
+ [CAMSS_ISPIF_BCR] = { 0x3220 },
+ [FD_BCR] = { 0x3b60 },
+ [MMSS_SPDM_RM_BCR] = { 0x300 },
+};
+
+static const struct regmap_config mmcc_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xb008,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc mmcc_msm8996_desc = {
+ .config = &mmcc_msm8996_regmap_config,
+ .clks = mmcc_msm8996_clocks,
+ .num_clks = ARRAY_SIZE(mmcc_msm8996_clocks),
+ .resets = mmcc_msm8996_resets,
+ .num_resets = ARRAY_SIZE(mmcc_msm8996_resets),
+};
+
+static const struct of_device_id mmcc_msm8996_match_table[] = {
+ { .compatible = "qcom,mmcc-msm8996" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mmcc_msm8996_match_table);
+
+static int mmcc_msm8996_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ struct device *dev = &pdev->dev;
+ int i;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &mmcc_msm8996_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Disable the AHB DCD */
+ regmap_update_bits(regmap, 0x50d8, BIT(31), 0);
+ /* Disable the NoC FSM for mmss_mmagic_cfg_ahb_clk */
+ regmap_update_bits(regmap, 0x5054, BIT(15), 0);
+
+ for (i = 0; i < ARRAY_SIZE(mmcc_msm8996_hws); i++) {
+ clk = devm_clk_register(dev, mmcc_msm8996_hws[i]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
+ return qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap);
+}
+
+static struct platform_driver mmcc_msm8996_driver = {
+ .probe = mmcc_msm8996_probe,
+ .driver = {
+ .name = "mmcc-msm8996",
+ .of_match_table = mmcc_msm8996_match_table,
+ },
+};
+module_platform_driver(mmcc_msm8996_driver);
+
+MODULE_DESCRIPTION("QCOM MMCC MSM8996 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mmcc-msm8996");
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index b27edd6c8183..80b9a379beb4 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -10,6 +10,8 @@ obj-y += clk-inverter.o
obj-y += clk-mmc-phase.o
obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
+obj-y += clk-rk3036.o
obj-y += clk-rk3188.o
+obj-y += clk-rk3228.o
obj-y += clk-rk3288.o
obj-y += clk-rk3368.o
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index 330870a6d8bf..d07374f48caf 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -242,8 +242,8 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
struct clk *clk, *cclk;
int ret;
- if (num_parents != 2) {
- pr_err("%s: needs two parent clocks\n", __func__);
+ if (num_parents < 2) {
+ pr_err("%s: needs at least two parent clocks\n", __func__);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 4881eb8a1576..b7e66c9dd9f2 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -2,6 +2,9 @@
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.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
@@ -19,6 +22,7 @@
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
+#include <linux/clk.h>
#include "clk.h"
#define PLL_MODE_MASK 0x3
@@ -108,6 +112,252 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
}
/**
+ * PLL used in RK3036
+ */
+
+#define RK3036_PLLCON(i) (i * 0x4)
+#define RK3036_PLLCON0_FBDIV_MASK 0xfff
+#define RK3036_PLLCON0_FBDIV_SHIFT 0
+#define RK3036_PLLCON0_POSTDIV1_MASK 0x7
+#define RK3036_PLLCON0_POSTDIV1_SHIFT 12
+#define RK3036_PLLCON1_REFDIV_MASK 0x3f
+#define RK3036_PLLCON1_REFDIV_SHIFT 0
+#define RK3036_PLLCON1_POSTDIV2_MASK 0x7
+#define RK3036_PLLCON1_POSTDIV2_SHIFT 6
+#define RK3036_PLLCON1_DSMPD_MASK 0x1
+#define RK3036_PLLCON1_DSMPD_SHIFT 12
+#define RK3036_PLLCON2_FRAC_MASK 0xffffff
+#define RK3036_PLLCON2_FRAC_SHIFT 0
+
+#define RK3036_PLLCON1_PWRDOWN (1 << 13)
+
+static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll,
+ struct rockchip_pll_rate_table *rate)
+{
+ u32 pllcon;
+
+ pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(0));
+ rate->fbdiv = ((pllcon >> RK3036_PLLCON0_FBDIV_SHIFT)
+ & RK3036_PLLCON0_FBDIV_MASK);
+ rate->postdiv1 = ((pllcon >> RK3036_PLLCON0_POSTDIV1_SHIFT)
+ & RK3036_PLLCON0_POSTDIV1_MASK);
+
+ pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(1));
+ rate->refdiv = ((pllcon >> RK3036_PLLCON1_REFDIV_SHIFT)
+ & RK3036_PLLCON1_REFDIV_MASK);
+ rate->postdiv2 = ((pllcon >> RK3036_PLLCON1_POSTDIV2_SHIFT)
+ & RK3036_PLLCON1_POSTDIV2_MASK);
+ rate->dsmpd = ((pllcon >> RK3036_PLLCON1_DSMPD_SHIFT)
+ & RK3036_PLLCON1_DSMPD_MASK);
+
+ pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
+ rate->frac = ((pllcon >> RK3036_PLLCON2_FRAC_SHIFT)
+ & RK3036_PLLCON2_FRAC_MASK);
+}
+
+static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ struct rockchip_pll_rate_table cur;
+ u64 rate64 = prate;
+
+ rockchip_rk3036_pll_get_params(pll, &cur);
+
+ rate64 *= cur.fbdiv;
+ do_div(rate64, cur.refdiv);
+
+ if (cur.dsmpd == 0) {
+ /* fractional mode */
+ u64 frac_rate64 = prate * cur.frac;
+
+ do_div(frac_rate64, cur.refdiv);
+ rate64 += frac_rate64 >> 24;
+ }
+
+ do_div(rate64, cur.postdiv1);
+ do_div(rate64, cur.postdiv2);
+
+ return (unsigned long)rate64;
+}
+
+static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
+ const struct rockchip_pll_rate_table *rate)
+{
+ const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+ struct clk_mux *pll_mux = &pll->pll_mux;
+ struct rockchip_pll_rate_table cur;
+ u32 pllcon;
+ int rate_change_remuxed = 0;
+ int cur_parent;
+ int ret;
+
+ pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+ __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
+ rate->postdiv2, rate->dsmpd, rate->frac);
+
+ rockchip_rk3036_pll_get_params(pll, &cur);
+ cur.rate = 0;
+
+ cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
+ if (cur_parent == PLL_MODE_NORM) {
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
+ rate_change_remuxed = 1;
+ }
+
+ /* update pll values */
+ writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
+ RK3036_PLLCON0_FBDIV_SHIFT) |
+ HIWORD_UPDATE(rate->postdiv1, RK3036_PLLCON0_POSTDIV1_MASK,
+ RK3036_PLLCON0_POSTDIV1_SHIFT),
+ pll->reg_base + RK3036_PLLCON(0));
+
+ writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3036_PLLCON1_REFDIV_MASK,
+ RK3036_PLLCON1_REFDIV_SHIFT) |
+ HIWORD_UPDATE(rate->postdiv2, RK3036_PLLCON1_POSTDIV2_MASK,
+ RK3036_PLLCON1_POSTDIV2_SHIFT) |
+ HIWORD_UPDATE(rate->dsmpd, RK3036_PLLCON1_DSMPD_MASK,
+ RK3036_PLLCON1_DSMPD_SHIFT),
+ pll->reg_base + RK3036_PLLCON(1));
+
+ /* GPLL CON2 is not HIWORD_MASK */
+ pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
+ pllcon &= ~(RK3036_PLLCON2_FRAC_MASK << RK3036_PLLCON2_FRAC_SHIFT);
+ pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
+ writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
+
+ /* wait for the pll to lock */
+ ret = rockchip_pll_wait_lock(pll);
+ if (ret) {
+ pr_warn("%s: pll update unsucessful, trying to restore old params\n",
+ __func__);
+ rockchip_rk3036_pll_set_params(pll, &cur);
+ }
+
+ if (rate_change_remuxed)
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
+
+ return ret;
+}
+
+static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct rockchip_pll_rate_table *rate;
+ unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate);
+ struct regmap *grf = rockchip_clk_get_grf();
+
+ if (IS_ERR(grf)) {
+ pr_debug("%s: grf regmap not available, aborting rate change\n",
+ __func__);
+ return PTR_ERR(grf);
+ }
+
+ pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
+ __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
+
+ /* Get required rate settings from table */
+ rate = rockchip_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
+ }
+
+ return rockchip_rk3036_pll_set_params(pll, rate);
+}
+
+static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+ writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3036_PLLCON(1));
+
+ return 0;
+}
+
+static void rockchip_rk3036_pll_disable(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+ writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
+ RK3036_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3036_PLLCON(1));
+}
+
+static int rockchip_rk3036_pll_is_enabled(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ u32 pllcon = readl(pll->reg_base + RK3036_PLLCON(1));
+
+ return !(pllcon & RK3036_PLLCON1_PWRDOWN);
+}
+
+static void rockchip_rk3036_pll_init(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct rockchip_pll_rate_table *rate;
+ struct rockchip_pll_rate_table cur;
+ unsigned long drate;
+
+ if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
+ return;
+
+ drate = clk_hw_get_rate(hw);
+ rate = rockchip_get_pll_settings(pll, drate);
+
+ /* when no rate setting for the current rate, rely on clk_set_rate */
+ if (!rate)
+ return;
+
+ rockchip_rk3036_pll_get_params(pll, &cur);
+
+ pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
+ drate);
+ pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+ cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
+ cur.dsmpd, cur.frac);
+ pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+ rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
+ rate->dsmpd, rate->frac);
+
+ if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
+ rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
+ rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) {
+ struct clk *parent = clk_get_parent(hw->clk);
+
+ if (!parent) {
+ pr_warn("%s: parent of %s not available\n",
+ __func__, __clk_get_name(hw->clk));
+ return;
+ }
+
+ pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
+ __func__, __clk_get_name(hw->clk));
+ rockchip_rk3036_pll_set_params(pll, rate);
+ }
+}
+
+static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
+ .recalc_rate = rockchip_rk3036_pll_recalc_rate,
+ .enable = rockchip_rk3036_pll_enable,
+ .disable = rockchip_rk3036_pll_disable,
+ .is_enabled = rockchip_rk3036_pll_is_enabled,
+};
+
+static const struct clk_ops rockchip_rk3036_pll_clk_ops = {
+ .recalc_rate = rockchip_rk3036_pll_recalc_rate,
+ .round_rate = rockchip_pll_round_rate,
+ .set_rate = rockchip_rk3036_pll_set_rate,
+ .enable = rockchip_rk3036_pll_enable,
+ .disable = rockchip_rk3036_pll_disable,
+ .is_enabled = rockchip_rk3036_pll_is_enabled,
+ .init = rockchip_rk3036_pll_init,
+};
+
+/**
* PLL used in RK3066, RK3188 and RK3288
*/
@@ -376,7 +626,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
pll_mux->lock = lock;
pll_mux->hw.init = &init;
- if (pll_type == pll_rk3066)
+ if (pll_type == pll_rk3036 || pll_type == pll_rk3066)
pll_mux->flags |= CLK_MUX_HIWORD_MASK;
/* the actual muxing is xin24m, pll-output, xin32k */
@@ -421,6 +671,12 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
}
switch (pll_type) {
+ case pll_rk3036:
+ if (!pll->rate_table)
+ init.ops = &rockchip_rk3036_pll_clk_norate_ops;
+ else
+ init.ops = &rockchip_rk3036_pll_clk_ops;
+ break;
case pll_rk3066:
if (!pll->rate_table)
init.ops = &rockchip_rk3066_pll_clk_norate_ops;
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
new file mode 100644
index 000000000000..ebce98033fbb
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3036-cru.h>
+#include "clk.h"
+
+#define RK3036_GRF_SOC_STATUS0 0x14c
+
+enum rk3036_plls {
+ apll, dpll, gpll,
+};
+
+static struct rockchip_pll_rate_table rk3036_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+ RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+ RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+ RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+ RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+ RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
+ { /* sentinel */ },
+};
+
+#define RK3036_DIV_CPU_MASK 0x1f
+#define RK3036_DIV_CPU_SHIFT 8
+
+#define RK3036_DIV_PERI_MASK 0xf
+#define RK3036_DIV_PERI_SHIFT 0
+#define RK3036_DIV_ACLK_MASK 0x7
+#define RK3036_DIV_ACLK_SHIFT 4
+#define RK3036_DIV_HCLK_MASK 0x3
+#define RK3036_DIV_HCLK_SHIFT 8
+#define RK3036_DIV_PCLK_MASK 0x7
+#define RK3036_DIV_PCLK_SHIFT 12
+
+#define RK3036_CLKSEL1(_core_periph_div) \
+ { \
+ .reg = RK2928_CLKSEL_CON(1), \
+ .val = HIWORD_UPDATE(_core_periph_div, RK3036_DIV_PERI_MASK, \
+ RK3036_DIV_PERI_SHIFT) \
+ }
+
+#define RK3036_CPUCLK_RATE(_prate, _core_periph_div) \
+ { \
+ .prate = _prate, \
+ .divs = { \
+ RK3036_CLKSEL1(_core_periph_div), \
+ }, \
+ }
+
+static struct rockchip_cpuclk_rate_table rk3036_cpuclk_rates[] __initdata = {
+ RK3036_CPUCLK_RATE(816000000, 4),
+ RK3036_CPUCLK_RATE(600000000, 4),
+ RK3036_CPUCLK_RATE(312000000, 4),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = {
+ .core_reg = RK2928_CLKSEL_CON(0),
+ .div_core_shift = 0,
+ .div_core_mask = 0x1f,
+ .mux_core_shift = 7,
+};
+
+PNAME(mux_pll_p) = { "xin24m", "xin24m" };
+
+PNAME(mux_armclk_p) = { "apll", "gpll_armclk" };
+PNAME(mux_busclk_p) = { "apll", "dpll_cpu", "gpll_cpu" };
+PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" };
+PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" };
+PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" };
+
+PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll" "usb480m" };
+
+PNAME(mux_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" };
+PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
+PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" };
+PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" };
+PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" };
+PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
+PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
+PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" };
+PNAME(mux_dclk_p) = { "dclk_lcdc", "dclk_cru" };
+
+static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = {
+ [apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
+ RK2928_MODE_CON, 0, 5, 0, rk3036_pll_rates),
+ [dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
+ RK2928_MODE_CON, 4, 4, 0, NULL),
+ [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
+ RK2928_MODE_CON, 12, 6, ROCKCHIP_PLL_SYNC_RATE, rk3036_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3036_uart0_fracmux __initdata =
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_uart1_fracmux __initdata =
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_uart2_fracmux __initdata =
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_i2s_fracmux __initdata =
+ MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_spdif_fracmux __initdata =
+ MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
+ RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
+ /*
+ * Clock-Architecture Diagram 1
+ */
+
+ GATE(0, "gpll_armclk", "gpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 6, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 2
+ */
+
+ GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 2, GFLAGS),
+ GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 8, GFLAGS),
+ COMPOSITE_NOGATE(0, "ddrphy2x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
+
+ COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK2928_CLKGATE_CON(0), 7, GFLAGS),
+ COMPOSITE_NOMUX(0, "aclk_core_pre", "armclk", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK2928_CLKGATE_CON(0), 7, GFLAGS),
+
+ GATE(0, "dpll_cpu", "dpll", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
+ GATE(0, "gpll_cpu", "gpll", 0, RK2928_CLKGATE_CON(0), 1, GFLAGS),
+ COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_busclk_p, 0,
+ RK2928_CLKSEL_CON(0), 14, 2, MFLAGS, 8, 5, DFLAGS),
+ GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 3, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(1), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK2928_CLKGATE_CON(0), 5, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_CPU, "hclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK2928_CLKGATE_CON(0), 4, GFLAGS),
+
+ COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(2), 0, GFLAGS),
+
+ GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
+ RK2928_CLKGATE_CON(2), 1, GFLAGS),
+ DIV(0, "pclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
+ GATE(PCLK_PERI, "pclk_peri", "pclk_peri_src", 0,
+ RK2928_CLKGATE_CON(2), 3, GFLAGS),
+ DIV(0, "hclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
+ GATE(HCLK_PERI, "hclk_peri", "hclk_peri_src", 0,
+ RK2928_CLKGATE_CON(2), 2, GFLAGS),
+
+ COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(2), 4, 1, DFLAGS,
+ RK2928_CLKGATE_CON(1), 0, GFLAGS),
+ COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(2), 5, 1, DFLAGS,
+ RK2928_CLKGATE_CON(1), 1, GFLAGS),
+ COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(2), 6, 1, DFLAGS,
+ RK2928_CLKGATE_CON(2), 4, GFLAGS),
+ COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(2), 7, 1, DFLAGS,
+ RK2928_CLKGATE_CON(2), 5, GFLAGS),
+
+ MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
+ RK2928_CLKSEL_CON(13), 10, 2, MFLAGS),
+ COMPOSITE_NOMUX(0, "uart0_src", "uart_pll_clk", 0,
+ RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 8, GFLAGS),
+ COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0,
+ RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 8, GFLAGS),
+ COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0,
+ RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 8, GFLAGS),
+ COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(17), 0,
+ RK2928_CLKGATE_CON(1), 9, GFLAGS,
+ &rk3036_uart0_fracmux),
+ COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(18), 0,
+ RK2928_CLKGATE_CON(1), 11, GFLAGS,
+ &rk3036_uart1_fracmux),
+ COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(19), 0,
+ RK2928_CLKGATE_CON(1), 13, GFLAGS,
+ &rk3036_uart2_fracmux),
+
+ COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 11, GFLAGS),
+
+ COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS,
+ RK2928_CLKGATE_CON(10), 6, GFLAGS),
+
+ COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(1), 4, GFLAGS),
+ COMPOSITE(0, "hclk_disp_pre", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(0), 11, GFLAGS),
+ COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(28), 0, 2, MFLAGS, 8, 8, DFLAGS,
+ RK2928_CLKGATE_CON(3), 2, GFLAGS),
+
+ COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0,
+ RK2928_CLKSEL_CON(12), 8, 2, DFLAGS,
+ RK2928_CLKGATE_CON(2), 11, GFLAGS),
+ DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0,
+ RK2928_CLKSEL_CON(11), 0, 7, DFLAGS),
+
+ COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
+ RK2928_CLKSEL_CON(12), 10, 2, DFLAGS,
+ RK2928_CLKGATE_CON(2), 13, GFLAGS),
+ DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
+ RK2928_CLKSEL_CON(11), 8, 7, DFLAGS),
+
+ COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0,
+ RK2928_CLKSEL_CON(12), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(2), 14, GFLAGS),
+
+ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3036_SDMMC_CON0, 1),
+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3036_SDMMC_CON1, 0),
+
+ MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3036_SDIO_CON0, 1),
+ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3036_SDIO_CON1, 0),
+
+ MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3036_EMMC_CON0, 1),
+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3036_EMMC_CON1, 0),
+
+ COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(0), 9, GFLAGS),
+ COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(7), 0,
+ RK2928_CLKGATE_CON(0), 10, GFLAGS,
+ &rk3036_i2s_fracmux),
+ COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0,
+ RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
+ RK2928_CLKGATE_CON(0), 13, GFLAGS),
+ GATE(SCLK_I2S, "sclk_i2s", "i2s_pre", CLK_SET_RATE_PARENT,
+ RK2928_CLKGATE_CON(0), 14, GFLAGS),
+
+ COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(2), 10, GFLAGS),
+ COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0,
+ RK2928_CLKSEL_CON(9), 0,
+ RK2928_CLKGATE_CON(2), 12, GFLAGS,
+ &rk3036_spdif_fracmux),
+
+ GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(1), 5, GFLAGS),
+
+ COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(34), 8, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 13, GFLAGS),
+
+ COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(2), 9, GFLAGS),
+
+ COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS,
+ RK2928_CLKGATE_CON(10), 4, GFLAGS),
+
+ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
+ RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS,
+ RK2928_CLKGATE_CON(10), 5, GFLAGS),
+
+ COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS),
+ MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(21), 3, 1, MFLAGS),
+
+ COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0,
+ RK2928_CLKSEL_CON(21), 9, 5, DFLAGS,
+ RK2928_CLKGATE_CON(2), 6, GFLAGS),
+
+ MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0,
+ RK2928_CLKSEL_CON(31), 0, 1, MFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 3
+ */
+
+ /* aclk_cpu gates */
+ GATE(0, "sclk_intmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 12, GFLAGS),
+ GATE(0, "aclk_strc_sys", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 10, GFLAGS),
+
+ /* hclk_cpu gates */
+ GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 6, GFLAGS),
+
+ /* pclk_cpu gates */
+ GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS),
+ GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS),
+ GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
+ GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS),
+
+ /* aclk_vio gates */
+ GATE(ACLK_VIO, "aclk_vio", "aclk_disp1_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(6), 13, GFLAGS),
+ GATE(ACLK_LCDC, "aclk_lcdc", "aclk_disp1_pre", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
+
+ GATE(HCLK_VIO_BUS, "hclk_vio_bus", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS),
+ GATE(HCLK_LCDC, "hclk_lcdc", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
+
+ /* hclk_video gates */
+ GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS),
+
+ /* xin24m gates */
+ GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK2928_CLKGATE_CON(10), 0, GFLAGS),
+ GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK2928_CLKGATE_CON(10), 1, GFLAGS),
+
+ /* aclk_peri gates */
+ GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 3, GFLAGS),
+ GATE(0, "aclk_cpu_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS),
+ GATE(ACLK_DMAC2, "aclk_dmac2", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS),
+ GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 15, GFLAGS),
+
+ /* hclk_peri gates */
+ GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
+ GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 13, GFLAGS),
+ GATE(0, "hclk_peri_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 14, GFLAGS),
+ GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS),
+ GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS),
+ GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 11, GFLAGS),
+ GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS),
+ GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
+ GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS),
+ GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
+ GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS),
+ GATE(0, "hclk_mac", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 15, GFLAGS),
+
+ /* pclk_peri gates */
+ GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS),
+ GATE(0, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS),
+ GATE(PCLK_TIMER, "pclk_timer", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS),
+ GATE(PCLK_PWM, "pclk_pwm", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS),
+ GATE(PCLK_SPI, "pclk_spi", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS),
+ GATE(PCLK_WDT, "pclk_wdt", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS),
+ GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
+ GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
+ GATE(PCLK_UART2, "pclk_uart2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
+ GATE(PCLK_I2C0, "pclk_i2c0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
+ GATE(PCLK_I2C1, "pclk_i2c1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 5, GFLAGS),
+ GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
+ GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
+ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
+ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
+};
+
+static const char *const rk3036_critical_clocks[] __initconst = {
+ "aclk_cpu",
+ "aclk_peri",
+ "hclk_peri",
+ "pclk_peri",
+};
+
+static void __init rk3036_clk_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+ struct clk *clk;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru region\n", __func__);
+ return;
+ }
+
+ rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+
+ /* xin12m is created by an cru-internal divider */
+ clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock xin12m: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock usb480m: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "ddrphy", "ddrphy2x", 0, 1, 2);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock ddrphy: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre",
+ "aclk_vcodec", 0, 1, 4);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "sclk_macref_out",
+ "hclk_peri_src", 0, 1, 2);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock sclk_macref_out: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ rockchip_clk_register_plls(rk3036_pll_clks,
+ ARRAY_SIZE(rk3036_pll_clks),
+ RK3036_GRF_SOC_STATUS0);
+ rockchip_clk_register_branches(rk3036_clk_branches,
+ ARRAY_SIZE(rk3036_clk_branches));
+ rockchip_clk_protect_critical(rk3036_critical_clocks,
+ ARRAY_SIZE(rk3036_critical_clocks));
+
+ rockchip_clk_register_armclk(ARMCLK, "armclk",
+ mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+ &rk3036_cpuclk_data, rk3036_cpuclk_rates,
+ ARRAY_SIZE(rk3036_cpuclk_rates));
+
+ rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
+ ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+ rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
+}
+CLK_OF_DECLARE(rk3036_cru, "rockchip,rk3036-cru", rk3036_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index abb47608713b..7f7444cbf6fc 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -247,6 +247,30 @@ static struct clk_div_table div_core_peri_t[] = {
{ /* sentinel */ },
};
+static struct rockchip_clk_branch common_hsadc_out_fracmux __initdata =
+ MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
+ RK2928_CLKSEL_CON(22), 4, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_spdif_fracmux __initdata =
+ MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart0_fracmux __initdata =
+ MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
+ RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart1_fracmux __initdata =
+ MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
+ RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart2_fracmux __initdata =
+ MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
+ RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart3_fracmux __initdata =
+ MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
+ RK2928_CLKSEL_CON(16), 8, 2, MFLAGS);
+
static struct rockchip_clk_branch common_clk_branches[] __initdata = {
/*
* Clock-Architecture Diagram 2
@@ -335,11 +359,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0,
RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS,
RK2928_CLKGATE_CON(2), 6, GFLAGS),
- COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0,
+ COMPOSITE_FRACMUX(0, "hsadc_frac", "hsadc_src", 0,
RK2928_CLKSEL_CON(23), 0,
- RK2928_CLKGATE_CON(2), 7, GFLAGS),
- MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
- RK2928_CLKSEL_CON(22), 4, 2, MFLAGS),
+ RK2928_CLKGATE_CON(2), 7, GFLAGS,
+ &common_hsadc_out_fracmux),
INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
RK2928_CLKSEL_CON(22), 7, IFLAGS),
@@ -350,11 +373,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(5), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 13, GFLAGS),
- COMPOSITE_FRAC(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_pll", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(9), 0,
- RK2928_CLKGATE_CON(0), 14, GFLAGS),
- MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
- RK2928_CLKSEL_CON(5), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(0), 14, GFLAGS,
+ &common_spdif_fracmux),
/*
* Clock-Architecture Diagram 4
@@ -385,35 +407,31 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0,
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
- COMPOSITE_FRAC(0, "uart0_frac", "uart0_pre", 0,
+ COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
RK2928_CLKSEL_CON(17), 0,
- RK2928_CLKGATE_CON(1), 9, GFLAGS),
- MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
- RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(1), 9, GFLAGS,
+ &common_uart0_fracmux),
COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 10, GFLAGS),
- COMPOSITE_FRAC(0, "uart1_frac", "uart1_pre", 0,
+ COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0,
RK2928_CLKSEL_CON(18), 0,
- RK2928_CLKGATE_CON(1), 11, GFLAGS),
- MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
- RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(1), 11, GFLAGS,
+ &common_uart1_fracmux),
COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart2_frac", "uart2_pre", 0,
+ COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0,
RK2928_CLKSEL_CON(19), 0,
- RK2928_CLKGATE_CON(1), 13, GFLAGS),
- MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
- RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(1), 13, GFLAGS,
+ &common_uart2_fracmux),
COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 14, GFLAGS),
- COMPOSITE_FRAC(0, "uart3_frac", "uart3_pre", 0,
+ COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0,
RK2928_CLKSEL_CON(20), 0,
- RK2928_CLKGATE_CON(1), 15, GFLAGS),
- MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
- RK2928_CLKSEL_CON(16), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(1), 15, GFLAGS,
+ &common_uart3_fracmux),
GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS),
@@ -523,6 +541,18 @@ static struct clk_div_table div_aclk_cpu_t[] = {
{ /* sentinel */ },
};
+static struct rockchip_clk_branch rk3066a_i2s0_fracmux __initdata =
+ MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
+ RK2928_CLKSEL_CON(2), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3066a_i2s1_fracmux __initdata =
+ MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
+ RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3066a_i2s2_fracmux __initdata =
+ MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
+ RK2928_CLKSEL_CON(4), 8, 2, MFLAGS);
+
static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
DIVTBL(0, "aclk_cpu_pre", "armclk", 0,
RK2928_CLKSEL_CON(1), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_cpu_t),
@@ -584,27 +614,24 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(2), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 7, GFLAGS),
- COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0,
+ COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
RK2928_CLKSEL_CON(6), 0,
- RK2928_CLKGATE_CON(0), 8, GFLAGS),
- MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
- RK2928_CLKSEL_CON(2), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(0), 8, GFLAGS,
+ &rk3066a_i2s0_fracmux),
COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
- COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_pre", 0,
+ COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0,
RK2928_CLKSEL_CON(7), 0,
- RK2928_CLKGATE_CON(0), 10, GFLAGS),
- MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
- RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(0), 10, GFLAGS,
+ &rk3066a_i2s1_fracmux),
COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 11, GFLAGS),
- COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_pre", 0,
+ COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0,
RK2928_CLKSEL_CON(8), 0,
- RK2928_CLKGATE_CON(0), 12, GFLAGS),
- MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
- RK2928_CLKSEL_CON(4), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(0), 12, GFLAGS,
+ &rk3066a_i2s2_fracmux),
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
@@ -638,6 +665,10 @@ static struct clk_div_table div_rk3188_aclk_core_t[] = {
PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1",
"gpll", "cpll" };
+static struct rockchip_clk_branch rk3188_i2s0_fracmux __initdata =
+ MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
+ RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
+
static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
@@ -691,11 +722,10 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
- COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0,
+ COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
RK2928_CLKSEL_CON(7), 0,
- RK2928_CLKGATE_CON(0), 10, GFLAGS),
- MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
- RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
+ RK2928_CLKGATE_CON(0), 10, GFLAGS,
+ &rk3188_i2s0_fracmux),
GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
@@ -750,7 +780,7 @@ static void __init rk3188_common_clk_init(struct device_node *np)
rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
- rockchip_register_restart_notifier(RK2928_GLB_SRST_FST);
+ rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
}
static void __init rk3066a_clk_init(struct device_node *np)
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
new file mode 100644
index 000000000000..981a50205339
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ * Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3228-cru.h>
+#include "clk.h"
+
+#define RK3228_GRF_SOC_STATUS0 0x480
+
+enum rk3228_plls {
+ apll, dpll, cpll, gpll,
+};
+
+static struct rockchip_pll_rate_table rk3228_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+ RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+ RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+ RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+ RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+ RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+ RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
+ { /* sentinel */ },
+};
+
+#define RK3228_DIV_CPU_MASK 0x1f
+#define RK3228_DIV_CPU_SHIFT 8
+
+#define RK3228_DIV_PERI_MASK 0xf
+#define RK3228_DIV_PERI_SHIFT 0
+#define RK3228_DIV_ACLK_MASK 0x7
+#define RK3228_DIV_ACLK_SHIFT 4
+#define RK3228_DIV_HCLK_MASK 0x3
+#define RK3228_DIV_HCLK_SHIFT 8
+#define RK3228_DIV_PCLK_MASK 0x7
+#define RK3228_DIV_PCLK_SHIFT 12
+
+#define RK3228_CLKSEL1(_core_peri_div) \
+ { \
+ .reg = RK2928_CLKSEL_CON(1), \
+ .val = HIWORD_UPDATE(_core_peri_div, RK3228_DIV_PERI_MASK, \
+ RK3228_DIV_PERI_SHIFT) \
+ }
+
+#define RK3228_CPUCLK_RATE(_prate, _core_peri_div) \
+ { \
+ .prate = _prate, \
+ .divs = { \
+ RK3228_CLKSEL1(_core_peri_div), \
+ }, \
+ }
+
+static struct rockchip_cpuclk_rate_table rk3228_cpuclk_rates[] __initdata = {
+ RK3228_CPUCLK_RATE(816000000, 4),
+ RK3228_CPUCLK_RATE(600000000, 4),
+ RK3228_CPUCLK_RATE(312000000, 4),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = {
+ .core_reg = RK2928_CLKSEL_CON(0),
+ .div_core_shift = 0,
+ .div_core_mask = 0x1f,
+ .mux_core_shift = 6,
+};
+
+PNAME(mux_pll_p) = { "clk_24m", "xin24m" };
+
+PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr", "apll_ddr" };
+PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" };
+PNAME(mux_usb480m_phy_p) = { "usb480m_phy0", "usb480m_phy1" };
+PNAME(mux_usb480m_p) = { "usb480m_phy", "xin24m" };
+PNAME(mux_hdmiphy_p) = { "hdmiphy_phy", "xin24m" };
+PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" };
+
+PNAME(mux_pll_src_4plls_p) = { "cpll", "gpll", "hdmiphy" "usb480m" };
+PNAME(mux_pll_src_3plls_p) = { "cpll", "gpll", "hdmiphy" };
+PNAME(mux_pll_src_2plls_p) = { "cpll", "gpll" };
+PNAME(mux_sclk_hdmi_cec_p) = { "cpll", "gpll", "xin24m" };
+PNAME(mux_aclk_peri_src_p) = { "cpll_peri", "gpll_peri", "hdmiphy_peri" };
+PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "usb480m" };
+PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usb480m" };
+
+PNAME(mux_sclk_rga_p) = { "gpll", "cpll", "sclk_rga_src" };
+
+PNAME(mux_sclk_vop_src_p) = { "gpll_vop", "cpll_vop" };
+PNAME(mux_dclk_vop_p) = { "hdmiphy", "sclk_vop_pre" };
+
+PNAME(mux_i2s0_p) = { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" };
+PNAME(mux_i2s1_pre_p) = { "i2s1_src", "i2s1_frac", "ext_i2s", "xin12m" };
+PNAME(mux_i2s_out_p) = { "i2s1_pre", "xin12m" };
+PNAME(mux_i2s2_p) = { "i2s2_src", "i2s2_frac", "xin12m" };
+PNAME(mux_sclk_spdif_p) = { "sclk_spdif_src", "spdif_frac", "xin12m" };
+
+PNAME(mux_aclk_gpu_pre_p) = { "cpll_gpu", "gpll_gpu", "hdmiphy_gpu", "usb480m_gpu" };
+
+PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" };
+PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
+PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
+
+PNAME(mux_sclk_macphy_50m_p) = { "ext_gmac", "phy_50m_out" };
+PNAME(mux_sclk_gmac_pre_p) = { "sclk_gmac_src", "sclk_macphy_50m" };
+PNAME(mux_sclk_macphy_p) = { "sclk_gmac_src", "ext_gmac" };
+
+static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = {
+ [apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
+ RK2928_MODE_CON, 0, 7, 0, rk3228_pll_rates),
+ [dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(3),
+ RK2928_MODE_CON, 4, 6, 0, NULL),
+ [cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6),
+ RK2928_MODE_CON, 8, 8, 0, NULL),
+ [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9),
+ RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
+ /*
+ * Clock-Architecture Diagram 1
+ */
+
+ DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(4), 8, 5, DFLAGS),
+
+ /* PD_DDR */
+ GATE(0, "apll_ddr", "apll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 2, GFLAGS),
+ GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 2, GFLAGS),
+ GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 2, GFLAGS),
+ COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+ RK2928_CLKGATE_CON(7), 1, GFLAGS),
+ GATE(0, "ddrc", "ddrphy_pre", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(8), 5, GFLAGS),
+ GATE(0, "ddrphy", "ddrphy_pre", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(7), 0, GFLAGS),
+
+ /* PD_CORE */
+ GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 6, GFLAGS),
+ GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 6, GFLAGS),
+ GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 6, GFLAGS),
+ COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK2928_CLKGATE_CON(4), 1, GFLAGS),
+ COMPOSITE_NOMUX(0, "armcore", "armclk", CLK_IGNORE_UNUSED,
+ RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK2928_CLKGATE_CON(4), 0, GFLAGS),
+
+ /* PD_MISC */
+ MUX(0, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+ RK2928_MISC_CON, 13, 1, MFLAGS),
+ MUX(0, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
+ RK2928_MISC_CON, 14, 1, MFLAGS),
+ MUX(0, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
+ RK2928_MISC_CON, 15, 1, MFLAGS),
+
+ /* PD_BUS */
+ GATE(0, "hdmiphy_aclk_cpu", "hdmiphy", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 1, GFLAGS),
+ GATE(0, "gpll_aclk_cpu", "gpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 1, GFLAGS),
+ GATE(0, "cpll_aclk_cpu", "cpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(0), 1, GFLAGS),
+ COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0,
+ RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS),
+ GATE(ARMCLK, "aclk_cpu", "aclk_cpu_src", 0,
+ RK2928_CLKGATE_CON(6), 0, GFLAGS),
+ COMPOSITE_NOMUX(0, "hclk_cpu", "aclk_cpu_src", 0,
+ RK2928_CLKSEL_CON(1), 8, 2, DFLAGS,
+ RK2928_CLKGATE_CON(6), 1, GFLAGS),
+ COMPOSITE_NOMUX(0, "pclk_bus_src", "aclk_cpu_src", 0,
+ RK2928_CLKSEL_CON(1), 12, 3, DFLAGS,
+ RK2928_CLKGATE_CON(6), 2, GFLAGS),
+ GATE(0, "pclk_cpu", "pclk_bus_src", 0,
+ RK2928_CLKGATE_CON(6), 3, GFLAGS),
+ GATE(0, "pclk_phy_pre", "pclk_bus_src", 0,
+ RK2928_CLKGATE_CON(6), 4, GFLAGS),
+ GATE(0, "pclk_ddr_pre", "pclk_bus_src", 0,
+ RK2928_CLKGATE_CON(6), 13, GFLAGS),
+
+ /* PD_VIDEO */
+ COMPOSITE(0, "aclk_vpu_pre", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(32), 5, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 11, GFLAGS),
+ GATE(0, "hclk_vpu_src", "aclk_vpu_pre", 0,
+ RK2928_CLKGATE_CON(4), 4, GFLAGS),
+
+ COMPOSITE(0, "aclk_rkvdec_pre", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 2, GFLAGS),
+ GATE(0, "hclk_rkvdec_src", "aclk_rkvdec_pre", 0,
+ RK2928_CLKGATE_CON(4), 5, GFLAGS),
+
+ COMPOSITE(0, "sclk_vdec_cabac", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(28), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 3, GFLAGS),
+
+ COMPOSITE(0, "sclk_vdec_core", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(34), 13, 2, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 4, GFLAGS),
+
+ /* PD_VIO */
+ COMPOSITE(0, "aclk_iep_pre", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(31), 5, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 0, GFLAGS),
+ DIV(0, "hclk_vio_pre", "aclk_iep_pre", 0,
+ RK2928_CLKSEL_CON(2), 0, 5, DFLAGS),
+
+ COMPOSITE(0, "aclk_hdcp_pre", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(31), 13, 2, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(1), 4, GFLAGS),
+
+ MUX(0, "sclk_rga_src", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(33), 13, 2, MFLAGS),
+ COMPOSITE_NOMUX(0, "aclk_rga_pre", "sclk_rga_src", 0,
+ RK2928_CLKSEL_CON(33), 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(1), 2, GFLAGS),
+ COMPOSITE(0, "sclk_rga", mux_sclk_rga_p, 0,
+ RK2928_CLKSEL_CON(22), 5, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(3), 6, GFLAGS),
+
+ COMPOSITE(0, "aclk_vop_pre", mux_pll_src_4plls_p, 0,
+ RK2928_CLKSEL_CON(33), 5, 2, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(1), 1, GFLAGS),
+
+ COMPOSITE(0, "sclk_hdcp", mux_pll_src_3plls_p, 0,
+ RK2928_CLKSEL_CON(23), 14, 2, MFLAGS, 8, 6, DFLAGS,
+ RK2928_CLKGATE_CON(3), 5, GFLAGS),
+
+ GATE(0, "sclk_hdmi_hdcp", "xin24m", 0,
+ RK2928_CLKGATE_CON(3), 7, GFLAGS),
+
+ COMPOSITE(0, "sclk_hdmi_cec", mux_sclk_hdmi_cec_p, 0,
+ RK2928_CLKSEL_CON(21), 14, 2, MFLAGS, 0, 14, DFLAGS,
+ RK2928_CLKGATE_CON(3), 8, GFLAGS),
+
+ /* PD_PERI */
+ GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(2), 0, GFLAGS),
+ GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(2), 0, GFLAGS),
+ GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED,
+ RK2928_CLKGATE_CON(2), 0, GFLAGS),
+ COMPOSITE_NOGATE(0, "aclk_peri_src", mux_aclk_peri_src_p, 0,
+ RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS),
+ COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0,
+ RK2928_CLKSEL_CON(10), 12, 3, DFLAGS,
+ RK2928_CLKGATE_CON(5), 2, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0,
+ RK2928_CLKSEL_CON(10), 8, 2, DFLAGS,
+ RK2928_CLKGATE_CON(5), 1, GFLAGS),
+ GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
+ RK2928_CLKGATE_CON(5), 0, GFLAGS),
+
+ GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0,
+ RK2928_CLKGATE_CON(6), 5, GFLAGS),
+ GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0,
+ RK2928_CLKGATE_CON(6), 6, GFLAGS),
+ GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0,
+ RK2928_CLKGATE_CON(6), 7, GFLAGS),
+ GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0,
+ RK2928_CLKGATE_CON(6), 8, GFLAGS),
+ GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0,
+ RK2928_CLKGATE_CON(6), 9, GFLAGS),
+ GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0,
+ RK2928_CLKGATE_CON(6), 10, GFLAGS),
+
+ COMPOSITE(0, "sclk_crypto", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(24), 5, 1, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(2), 7, GFLAGS),
+
+ COMPOSITE(0, "sclk_tsp", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(22), 15, 1, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(2), 6, GFLAGS),
+
+ GATE(0, "sclk_hsadc", "ext_hsadc", 0,
+ RK3288_CLKGATE_CON(10), 12, GFLAGS),
+
+ COMPOSITE(0, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0,
+ RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS,
+ RK2928_CLKGATE_CON(2), 15, GFLAGS),
+
+ COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0,
+ RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK2928_CLKGATE_CON(2), 11, GFLAGS),
+
+ COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
+ RK2928_CLKSEL_CON(11), 10, 2, MFLAGS,
+ RK2928_CLKGATE_CON(2), 13, GFLAGS),
+ DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
+ RK2928_CLKSEL_CON(12), 0, 8, DFLAGS),
+
+ COMPOSITE_NODIV(0, "sclk_emmc_src", mux_mmc_src_p, 0,
+ RK2928_CLKSEL_CON(11), 12, 2, MFLAGS,
+ RK2928_CLKGATE_CON(2), 14, GFLAGS),
+ DIV(SCLK_EMMC, "sclk_emmc", "sclk_emmc_src", 0,
+ RK2928_CLKSEL_CON(12), 8, 8, DFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 2
+ */
+
+ GATE(0, "gpll_vop", "gpll", 0,
+ RK2928_CLKGATE_CON(3), 1, GFLAGS),
+ GATE(0, "cpll_vop", "cpll", 0,
+ RK2928_CLKGATE_CON(3), 1, GFLAGS),
+ MUX(0, "sclk_vop_src", mux_sclk_vop_src_p, 0,
+ RK2928_CLKSEL_CON(27), 0, 1, MFLAGS),
+ DIV(0, "dclk_hdmiphy", "sclk_vop_src", 0,
+ RK2928_CLKSEL_CON(29), 0, 3, DFLAGS),
+ DIV(0, "sclk_vop_pre", "sclk_vop_src", 0,
+ RK2928_CLKSEL_CON(27), 8, 8, DFLAGS),
+ MUX(0, "dclk_vop", mux_dclk_vop_p, 0,
+ RK2928_CLKSEL_CON(27), 1, 1, MFLAGS),
+
+ COMPOSITE(0, "i2s0_src", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(9), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(0), 3, GFLAGS),
+ COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(8), 0,
+ RK3288_CLKGATE_CON(0), 4, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S0, "sclk_i2s0", mux_i2s0_p, 0,
+ RK2928_CLKSEL_CON(9), 8, 2, MFLAGS,
+ RK2928_CLKGATE_CON(0), 5, GFLAGS),
+
+ COMPOSITE(0, "i2s1_src", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(3), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(0), 10, GFLAGS),
+ COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(7), 0,
+ RK3288_CLKGATE_CON(0), 11, GFLAGS),
+ MUX(0, "i2s1_pre", mux_i2s1_pre_p, 0,
+ RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
+ GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", 0,
+ RK2928_CLKGATE_CON(0), 14, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
+ RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
+ RK2928_CLKGATE_CON(0), 13, GFLAGS),
+
+ COMPOSITE(0, "i2s2_src", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(16), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(0), 7, GFLAGS),
+ COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(30), 0,
+ RK3288_CLKGATE_CON(0), 8, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S2, "sclk_i2s2", mux_i2s2_p, 0,
+ RK2928_CLKSEL_CON(16), 8, 2, MFLAGS,
+ RK2928_CLKGATE_CON(0), 9, GFLAGS),
+
+ COMPOSITE(0, "sclk_spdif_src", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(2), 10, GFLAGS),
+ COMPOSITE_FRAC(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(20), 0,
+ RK3288_CLKGATE_CON(2), 12, GFLAGS),
+ MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0,
+ RK2928_CLKSEL_CON(6), 8, 2, MFLAGS),
+
+ GATE(0, "jtag", "ext_jtag", 0,
+ RK2928_CLKGATE_CON(1), 3, GFLAGS),
+
+ GATE(0, "sclk_otgphy0", "xin24m", 0,
+ RK2928_CLKGATE_CON(1), 5, GFLAGS),
+ GATE(0, "sclk_otgphy1", "xin24m", 0,
+ RK2928_CLKGATE_CON(1), 6, GFLAGS),
+
+ COMPOSITE_NOMUX(0, "sclk_tsadc", "xin24m", 0,
+ RK2928_CLKSEL_CON(24), 6, 10, DFLAGS,
+ RK2928_CLKGATE_CON(2), 8, GFLAGS),
+
+ GATE(0, "cpll_gpu", "cpll", 0,
+ RK2928_CLKGATE_CON(3), 13, GFLAGS),
+ GATE(0, "gpll_gpu", "gpll", 0,
+ RK2928_CLKGATE_CON(3), 13, GFLAGS),
+ GATE(0, "hdmiphy_gpu", "hdmiphy", 0,
+ RK2928_CLKGATE_CON(3), 13, GFLAGS),
+ GATE(0, "usb480m_gpu", "usb480m", 0,
+ RK2928_CLKGATE_CON(3), 13, GFLAGS),
+ COMPOSITE_NOGATE(0, "aclk_gpu_pre", mux_aclk_gpu_pre_p, 0,
+ RK2928_CLKSEL_CON(34), 5, 2, MFLAGS, 0, 5, DFLAGS),
+
+ COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(25), 8, 1, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(2), 9, GFLAGS),
+
+ /* PD_UART */
+ COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gpll_usb480m_p, 0,
+ RK2928_CLKSEL_CON(13), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 8, GFLAGS),
+ COMPOSITE(0, "uart1_src", mux_pll_src_cpll_gpll_usb480m_p, 0,
+ RK2928_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK2928_CLKGATE_CON(1), 10, GFLAGS),
+ COMPOSITE(0, "uart2_src", mux_pll_src_cpll_gpll_usb480m_p,
+ 0, RK2928_CLKSEL_CON(15), 12, 2,
+ MFLAGS, 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 12, GFLAGS),
+ COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(17), 0,
+ RK2928_CLKGATE_CON(1), 9, GFLAGS),
+ COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(18), 0,
+ RK2928_CLKGATE_CON(1), 11, GFLAGS),
+ COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(19), 0,
+ RK2928_CLKGATE_CON(1), 13, GFLAGS),
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+ RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
+
+ COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(2), 14, 1, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(1), 0, GFLAGS),
+
+ COMPOSITE(0, "sclk_gmac_src", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(5), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK2928_CLKGATE_CON(1), 7, GFLAGS),
+ MUX(0, "sclk_macphy_50m", mux_sclk_macphy_50m_p, 0,
+ RK2928_CLKSEL_CON(29), 10, 1, MFLAGS),
+ MUX(0, "sclk_gmac_pre", mux_sclk_gmac_pre_p, 0,
+ RK2928_CLKSEL_CON(5), 5, 1, MFLAGS),
+ GATE(0, "sclk_mac_refout", "sclk_gmac_pre", 0,
+ RK2928_CLKGATE_CON(5), 4, GFLAGS),
+ GATE(0, "sclk_mac_ref", "sclk_gmac_pre", 0,
+ RK2928_CLKGATE_CON(5), 3, GFLAGS),
+ GATE(0, "sclk_mac_rx", "sclk_gmac_pre", 0,
+ RK2928_CLKGATE_CON(5), 5, GFLAGS),
+ GATE(0, "sclk_mac_tx", "sclk_gmac_pre", 0,
+ RK2928_CLKGATE_CON(5), 6, GFLAGS),
+ COMPOSITE(0, "sclk_macphy", mux_sclk_macphy_p, 0,
+ RK2928_CLKSEL_CON(29), 12, 1, MFLAGS, 8, 2, DFLAGS,
+ RK2928_CLKGATE_CON(5), 7, GFLAGS),
+ COMPOSITE(0, "sclk_gmac_out", mux_pll_src_2plls_p, 0,
+ RK2928_CLKSEL_CON(5), 15, 1, MFLAGS, 8, 5, DFLAGS,
+ RK2928_CLKGATE_CON(2), 2, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 3
+ */
+
+ /* PD_VOP */
+ GATE(0, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS),
+ GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS),
+ GATE(0, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS),
+ GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS),
+
+ GATE(0, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS),
+ GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS),
+
+ GATE(0, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS),
+ GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS),
+
+ GATE(0, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS),
+ GATE(0, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS),
+ GATE(0, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS),
+ GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS),
+ GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS),
+ GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS),
+ GATE(0, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS),
+ GATE(0, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS),
+ GATE(0, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS),
+ GATE(0, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS),
+ GATE(0, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS),
+
+ /* PD_PERI */
+ GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 0, GFLAGS),
+ GATE(0, "aclk_gmac", "aclk_peri", 0, RK2928_CLKGATE_CON(11), 4, GFLAGS),
+
+ GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 0, GFLAGS),
+ GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 1, GFLAGS),
+ GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS),
+ GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS),
+ GATE(0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS),
+ GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS),
+ GATE(0, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS),
+ GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS),
+ GATE(0, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS),
+ GATE(0, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS),
+ GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS),
+ GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS),
+ GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS),
+
+ GATE(0, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS),
+ GATE(0, "pclk_peri_noc", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 2, GFLAGS),
+
+ /* PD_GPU */
+ GATE(0, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 14, GFLAGS),
+ GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 15, GFLAGS),
+
+ /* PD_BUS */
+ GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
+ GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
+ GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
+ GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS),
+
+ GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS),
+ GATE(0, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS),
+ GATE(0, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS),
+ GATE(0, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
+ GATE(0, "hclk_spdif_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
+ GATE(0, "hclk_tsp", "hclk_cpu", 0, RK2928_CLKGATE_CON(10), 11, GFLAGS),
+ GATE(0, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
+ GATE(0, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS),
+
+ GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
+ GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
+ GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS),
+
+ GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS),
+ GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS),
+ GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 15, GFLAGS),
+ GATE(PCLK_I2C1, "pclk_i2c1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 0, GFLAGS),
+ GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS),
+ GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS),
+ GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS),
+ GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
+ GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
+ GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS),
+ GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS),
+ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 9, GFLAGS),
+ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 10, GFLAGS),
+ GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 11, GFLAGS),
+ GATE(PCLK_UART0, "pclk_uart0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 12, GFLAGS),
+ GATE(PCLK_UART1, "pclk_uart1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 13, GFLAGS),
+ GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 14, GFLAGS),
+ GATE(0, "pclk_tsadc", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 15, GFLAGS),
+ GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS),
+ GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS),
+ GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS),
+ GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS),
+
+ GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS),
+ GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS),
+ GATE(0, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS),
+ GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
+ GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS),
+
+ GATE(0, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS),
+ GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS),
+ GATE(0, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS),
+ GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS),
+ GATE(0, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS),
+ GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS),
+ GATE(0, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS),
+ GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS),
+
+ /* PD_MMC */
+ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1),
+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1),
+
+ MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1),
+ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1),
+
+ MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1),
+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1),
+};
+
+static const char *const rk3228_critical_clocks[] __initconst = {
+ "aclk_cpu",
+ "aclk_peri",
+ "hclk_peri",
+ "pclk_peri",
+};
+
+static void __init rk3228_clk_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+ struct clk *clk;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru region\n", __func__);
+ return;
+ }
+
+ rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+
+ /* xin12m is created by an cru-internal divider */
+ clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock xin12m: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "ddrphy_pre", "ddrphy4x", 0, 1, 4);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock ddrphy_pre: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "hclk_vpu_pre",
+ "hclk_vpu_src", 0, 1, 4);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock hclk_vpu_pre: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ clk = clk_register_fixed_factor(NULL, "hclk_rkvdec_pre",
+ "hclk_rkvdec_src", 0, 1, 4);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock hclk_rkvdec_pre: %ld\n",
+ __func__, PTR_ERR(clk));
+
+ rockchip_clk_register_plls(rk3228_pll_clks,
+ ARRAY_SIZE(rk3228_pll_clks),
+ RK3228_GRF_SOC_STATUS0);
+ rockchip_clk_register_branches(rk3228_clk_branches,
+ ARRAY_SIZE(rk3228_clk_branches));
+ rockchip_clk_protect_critical(rk3228_critical_clocks,
+ ARRAY_SIZE(rk3228_critical_clocks));
+
+ rockchip_clk_register_armclk(ARMCLK, "armclk",
+ mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+ &rk3228_cpuclk_data, rk3228_cpuclk_rates,
+ ARRAY_SIZE(rk3228_cpuclk_rates));
+
+ rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
+ ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+ rockchip_register_restart_notifier(RK3228_GLB_SRST_FST, NULL);
+}
+CLK_OF_DECLARE(rk3228_cru, "rockchip,rk3228-cru", rk3228_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 9040878e3e2b..984fc187d12e 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -225,6 +225,38 @@ static struct clk_div_table div_hclk_cpu_t[] = {
#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
+static struct rockchip_clk_branch rk3288_i2s_fracmux __initdata =
+ MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(4), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_spdif_fracmux __initdata =
+ MUX(0, "spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_spdif_8ch_fracmux __initdata =
+ MUX(0, "spdif_8ch_mux", mux_spdif_8ch_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(40), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart0_fracmux __initdata =
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(13), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart1_fracmux __initdata =
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart2_fracmux __initdata =
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(15), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart3_fracmux __initdata =
+ MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(16), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart4_fracmux __initdata =
+ MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
+ RK3288_CLKSEL_CON(3), 8, 2, MFLAGS);
+
static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
/*
* Clock-Architecture Diagram 1
@@ -295,7 +327,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
RK3288_CLKGATE_CON(0), 4, GFLAGS),
GATE(0, "c2c_host", "aclk_cpu_src", 0,
RK3288_CLKGATE_CON(13), 8, GFLAGS),
- COMPOSITE_NOMUX(0, "crypto", "aclk_cpu_pre", 0,
+ COMPOSITE_NOMUX(SCLK_CRYPTO, "crypto", "aclk_cpu_pre", 0,
RK3288_CLKSEL_CON(26), 6, 2, DFLAGS,
RK3288_CLKGATE_CON(5), 4, GFLAGS),
GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED,
@@ -304,11 +336,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(4), 1, GFLAGS),
- COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(8), 0,
- RK3288_CLKGATE_CON(4), 2, GFLAGS),
- MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
- RK3288_CLKSEL_CON(4), 8, 2, MFLAGS),
+ RK3288_CLKGATE_CON(4), 2, GFLAGS,
+ &rk3288_i2s_fracmux),
COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0,
RK3288_CLKSEL_CON(4), 12, 1, MFLAGS,
RK3288_CLKGATE_CON(4), 0, GFLAGS),
@@ -317,23 +348,23 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(5), 15, 1, MFLAGS),
- COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", 0,
+ COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(5), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(4), 4, GFLAGS),
- COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0,
+ COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(9), 0,
- RK3288_CLKGATE_CON(4), 5, GFLAGS),
- COMPOSITE_NODIV(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
- RK3288_CLKSEL_CON(5), 8, 2, MFLAGS,
+ RK3288_CLKGATE_CON(4), 5, GFLAGS,
+ &rk3288_spdif_fracmux),
+ GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", CLK_SET_RATE_PARENT,
RK3288_CLKGATE_CON(4), 6, GFLAGS),
- COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0,
+ COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(40), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(4), 7, GFLAGS),
- COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_pre", 0,
+ COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(41), 0,
- RK3288_CLKGATE_CON(4), 8, GFLAGS),
- COMPOSITE_NODIV(SCLK_SPDIF8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0,
- RK3288_CLKSEL_CON(40), 8, 2, MFLAGS,
+ RK3288_CLKGATE_CON(4), 8, GFLAGS,
+ &rk3288_spdif_8ch_fracmux),
+ GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", CLK_SET_RATE_PARENT,
RK3288_CLKGATE_CON(4), 9, GFLAGS),
GATE(0, "sclk_acc_efuse", "xin24m", 0,
@@ -536,45 +567,40 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 8, GFLAGS),
- COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(17), 0,
- RK3288_CLKGATE_CON(1), 9, GFLAGS),
- MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
- RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
+ RK3288_CLKGATE_CON(1), 9, GFLAGS,
+ &rk3288_uart0_fracmux),
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 10, GFLAGS),
- COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(18), 0,
- RK3288_CLKGATE_CON(1), 11, GFLAGS),
- MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
- RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
+ RK3288_CLKGATE_CON(1), 11, GFLAGS,
+ &rk3288_uart1_fracmux),
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(19), 0,
- RK3288_CLKGATE_CON(1), 13, GFLAGS),
- MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
- RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
+ RK3288_CLKGATE_CON(1), 13, GFLAGS,
+ &rk3288_uart2_fracmux),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 14, GFLAGS),
- COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
- RK3288_CLKGATE_CON(1), 15, GFLAGS),
- MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
- RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
+ RK3288_CLKGATE_CON(1), 15, GFLAGS,
+ &rk3288_uart3_fracmux),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
+ COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
- RK3288_CLKGATE_CON(2), 13, GFLAGS),
- MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
- RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
+ RK3288_CLKGATE_CON(2), 13, GFLAGS,
+ &rk3288_uart4_fracmux),
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
@@ -644,10 +670,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(PCLK_PUBL0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS),
GATE(PCLK_DDRUPCTL1, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS),
GATE(PCLK_PUBL1, "pclk_publ1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 1, GFLAGS),
- GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
+ GATE(PCLK_EFUSE1024, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS),
GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS),
- GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
+ GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
/* ddrctrl [DDR Controller PHY clock] gates */
@@ -709,7 +735,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
- GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
+ GATE(SCLK_MIPIDSI_24M, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
/* sclk_gpu gates */
GATE(ACLK_GPU, "aclk_gpu", "sclk_gpu", 0, RK3288_CLKGATE_CON(18), 0, GFLAGS),
@@ -783,10 +809,10 @@ static const char *const rk3288_critical_clocks[] __initconst = {
"pclk_pd_pmu",
};
-#ifdef CONFIG_PM_SLEEP
static void __iomem *rk3288_cru_base;
-/* Some CRU registers will be reset in maskrom when the system
+/*
+ * Some CRU registers will be reset in maskrom when the system
* wakes up from fastboot.
* So save them before suspend, restore them after resume.
*/
@@ -840,33 +866,27 @@ static void rk3288_clk_resume(void)
}
}
+static void rk3288_clk_shutdown(void)
+{
+ writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
+}
+
static struct syscore_ops rk3288_clk_syscore_ops = {
.suspend = rk3288_clk_suspend,
.resume = rk3288_clk_resume,
};
-static void rk3288_clk_sleep_init(void __iomem *reg_base)
-{
- rk3288_cru_base = reg_base;
- register_syscore_ops(&rk3288_clk_syscore_ops);
-}
-
-#else /* CONFIG_PM_SLEEP */
-static void rk3288_clk_sleep_init(void __iomem *reg_base) {}
-#endif
-
static void __init rk3288_clk_init(struct device_node *np)
{
- void __iomem *reg_base;
struct clk *clk;
- reg_base = of_iomap(np, 0);
- if (!reg_base) {
+ rk3288_cru_base = of_iomap(np, 0);
+ if (!rk3288_cru_base) {
pr_err("%s: could not map cru region\n", __func__);
return;
}
- rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+ rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
/* xin12m is created by an cru-internal divider */
clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
@@ -907,10 +927,12 @@ static void __init rk3288_clk_init(struct device_node *np)
&rk3288_cpuclk_data, rk3288_cpuclk_rates,
ARRAY_SIZE(rk3288_cpuclk_rates));
- rockchip_register_softrst(np, 12, reg_base + RK3288_SOFTRST_CON(0),
+ rockchip_register_softrst(np, 12,
+ rk3288_cru_base + RK3288_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
- rockchip_register_restart_notifier(RK3288_GLB_SRST_FST);
- rk3288_clk_sleep_init(reg_base);
+ rockchip_register_restart_notifier(RK3288_GLB_SRST_FST,
+ rk3288_clk_shutdown);
+ register_syscore_ops(&rk3288_clk_syscore_ops);
}
CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index 7e6b783e6eee..be0ede522269 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -184,13 +184,13 @@ static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = {
#define RK3368_CLKSEL0(_offs, _aclkm) \
{ \
- .reg = RK3288_CLKSEL_CON(0 + _offs), \
+ .reg = RK3368_CLKSEL_CON(0 + _offs), \
.val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \
RK3368_DIV_ACLKM_SHIFT), \
}
#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \
{ \
- .reg = RK3288_CLKSEL_CON(1 + _offs), \
+ .reg = RK3368_CLKSEL_CON(1 + _offs), \
.val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \
RK3368_DIV_ATCLK_SHIFT) | \
HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \
@@ -819,6 +819,13 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
};
static const char *const rk3368_critical_clocks[] __initconst = {
+ "aclk_bus",
+ "aclk_peri",
+ /*
+ * pwm1 supplies vdd_logic on a lot of boards, is currently unhandled
+ * but needs to stay enabled there (including its parents) at all times.
+ */
+ "pclk_pwm1",
"pclk_pd_pmu",
};
@@ -882,6 +889,6 @@ static void __init rk3368_clk_init(struct device_node *np)
rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
- rockchip_register_restart_notifier(RK3368_GLB_SRST_FST);
+ rockchip_register_restart_notifier(RK3368_GLB_SRST_FST, NULL);
}
CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init);
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index be6c7fd8315d..d9a0b5d4d47f 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -102,22 +102,82 @@ static struct clk *rockchip_clk_register_branch(const char *name,
return clk;
}
+struct rockchip_clk_frac {
+ struct notifier_block clk_nb;
+ struct clk_fractional_divider div;
+ struct clk_gate gate;
+
+ struct clk_mux mux;
+ const struct clk_ops *mux_ops;
+ int mux_frac_idx;
+
+ bool rate_change_remuxed;
+ int rate_change_idx;
+};
+
+#define to_rockchip_clk_frac_nb(nb) \
+ container_of(nb, struct rockchip_clk_frac, clk_nb)
+
+static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct rockchip_clk_frac *frac = to_rockchip_clk_frac_nb(nb);
+ struct clk_mux *frac_mux = &frac->mux;
+ int ret = 0;
+
+ pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n",
+ __func__, event, ndata->old_rate, ndata->new_rate);
+ if (event == PRE_RATE_CHANGE) {
+ frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw);
+ if (frac->rate_change_idx != frac->mux_frac_idx) {
+ frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx);
+ frac->rate_change_remuxed = 1;
+ }
+ } else if (event == POST_RATE_CHANGE) {
+ /*
+ * The POST_RATE_CHANGE notifier runs directly after the
+ * divider clock is set in clk_change_rate, so we'll have
+ * remuxed back to the original parent before clk_change_rate
+ * reaches the mux itself.
+ */
+ if (frac->rate_change_remuxed) {
+ frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx);
+ frac->rate_change_remuxed = 0;
+ }
+ }
+
+ return notifier_from_errno(ret);
+}
+
static struct clk *rockchip_clk_register_frac_branch(const char *name,
const char *const *parent_names, u8 num_parents,
void __iomem *base, int muxdiv_offset, u8 div_flags,
int gate_offset, u8 gate_shift, u8 gate_flags,
- unsigned long flags, spinlock_t *lock)
+ unsigned long flags, struct rockchip_clk_branch *child,
+ spinlock_t *lock)
{
+ struct rockchip_clk_frac *frac;
struct clk *clk;
struct clk_gate *gate = NULL;
struct clk_fractional_divider *div = NULL;
const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
- if (gate_offset >= 0) {
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate)
- return ERR_PTR(-ENOMEM);
+ if (muxdiv_offset < 0)
+ return ERR_PTR(-EINVAL);
+
+ if (child && child->branch_type != branch_mux) {
+ pr_err("%s: fractional child clock for %s can only be a mux\n",
+ __func__, name);
+ return ERR_PTR(-EINVAL);
+ }
+ frac = kzalloc(sizeof(*frac), GFP_KERNEL);
+ if (!frac)
+ return ERR_PTR(-ENOMEM);
+
+ if (gate_offset >= 0) {
+ gate = &frac->gate;
gate->flags = gate_flags;
gate->reg = base + gate_offset;
gate->bit_idx = gate_shift;
@@ -125,13 +185,7 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name,
gate_ops = &clk_gate_ops;
}
- if (muxdiv_offset < 0)
- return ERR_PTR(-EINVAL);
-
- div = kzalloc(sizeof(*div), GFP_KERNEL);
- if (!div)
- return ERR_PTR(-ENOMEM);
-
+ div = &frac->div;
div->flags = div_flags;
div->reg = base + muxdiv_offset;
div->mshift = 16;
@@ -147,7 +201,61 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name,
NULL, NULL,
&div->hw, div_ops,
gate ? &gate->hw : NULL, gate_ops,
- flags);
+ flags | CLK_SET_RATE_UNGATE);
+ if (IS_ERR(clk)) {
+ kfree(frac);
+ return clk;
+ }
+
+ if (child) {
+ struct clk_mux *frac_mux = &frac->mux;
+ struct clk_init_data init;
+ struct clk *mux_clk;
+ int i, ret;
+
+ frac->mux_frac_idx = -1;
+ for (i = 0; i < child->num_parents; i++) {
+ if (!strcmp(name, child->parent_names[i])) {
+ pr_debug("%s: found fractional parent in mux at pos %d\n",
+ __func__, i);
+ frac->mux_frac_idx = i;
+ break;
+ }
+ }
+
+ frac->mux_ops = &clk_mux_ops;
+ frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb;
+
+ frac_mux->reg = base + child->muxdiv_offset;
+ frac_mux->shift = child->mux_shift;
+ frac_mux->mask = BIT(child->mux_width) - 1;
+ frac_mux->flags = child->mux_flags;
+ frac_mux->lock = lock;
+ frac_mux->hw.init = &init;
+
+ init.name = child->name;
+ init.flags = child->flags | CLK_SET_RATE_PARENT;
+ init.ops = frac->mux_ops;
+ init.parent_names = child->parent_names;
+ init.num_parents = child->num_parents;
+
+ mux_clk = clk_register(NULL, &frac_mux->hw);
+ if (IS_ERR(mux_clk))
+ return clk;
+
+ rockchip_clk_add_lookup(mux_clk, child->id);
+
+ /* notifier on the fraction divider to catch rate changes */
+ if (frac->mux_frac_idx >= 0) {
+ ret = clk_notifier_register(clk, &frac->clk_nb);
+ if (ret)
+ pr_err("%s: failed to register clock notifier for %s\n",
+ __func__, name);
+ } else {
+ pr_warn("%s: could not find %s as parent of %s, rate changes may not work\n",
+ __func__, name, child->name);
+ }
+ }
return clk;
}
@@ -251,7 +359,8 @@ void __init rockchip_clk_register_branches(
list->parent_names, list->num_parents,
reg_base, list->muxdiv_offset, list->div_flags,
list->gate_offset, list->gate_shift,
- list->gate_flags, flags, &clk_lock);
+ list->gate_flags, flags, list->child,
+ &clk_lock);
break;
case branch_gate:
flags |= CLK_SET_RATE_PARENT;
@@ -341,9 +450,13 @@ void __init rockchip_clk_protect_critical(const char *const clocks[],
}
static unsigned int reg_restart;
+static void (*cb_restart)(void);
static int rockchip_restart_notify(struct notifier_block *this,
unsigned long mode, void *cmd)
{
+ if (cb_restart)
+ cb_restart();
+
writel(0xfdb9, reg_base + reg_restart);
return NOTIFY_DONE;
}
@@ -353,11 +466,12 @@ static struct notifier_block rockchip_restart_handler = {
.priority = 128,
};
-void __init rockchip_register_restart_notifier(unsigned int reg)
+void __init rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void))
{
int ret;
reg_restart = reg;
+ cb_restart = cb;
ret = register_restart_handler(&rockchip_restart_handler);
if (ret)
pr_err("%s: cannot register restart handler, %d\n",
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index dc8ecb2673b7..ff8bd23a93ec 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -2,6 +2,9 @@
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
* based on
*
* samsung/clk.h
@@ -30,7 +33,7 @@ struct clk;
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
-/* register positions shared by RK2928, RK3066 and RK3188 */
+/* register positions shared by RK2928, RK3036, RK3066, RK3188 and RK3228 */
#define RK2928_PLL_CON(x) ((x) * 0x4)
#define RK2928_MODE_CON 0x40
#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44)
@@ -40,6 +43,22 @@ struct clk;
#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110)
#define RK2928_MISC_CON 0x134
+#define RK3036_SDMMC_CON0 0x144
+#define RK3036_SDMMC_CON1 0x148
+#define RK3036_SDIO_CON0 0x14c
+#define RK3036_SDIO_CON1 0x150
+#define RK3036_EMMC_CON0 0x154
+#define RK3036_EMMC_CON1 0x158
+
+#define RK3228_GLB_SRST_FST 0x1f0
+#define RK3228_GLB_SRST_SND 0x1f4
+#define RK3228_SDMMC_CON0 0x1c0
+#define RK3228_SDMMC_CON1 0x1c4
+#define RK3228_SDIO_CON0 0x1c8
+#define RK3228_SDIO_CON1 0x1cc
+#define RK3228_EMMC_CON0 0x1d8
+#define RK3228_EMMC_CON1 0x1dc
+
#define RK3288_PLL_CON(x) RK2928_PLL_CON(x)
#define RK3288_MODE_CON 0x50
#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
@@ -74,9 +93,22 @@ struct clk;
#define RK3368_EMMC_CON1 0x41c
enum rockchip_pll_type {
+ pll_rk3036,
pll_rk3066,
};
+#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
+ _postdiv2, _dsmpd, _frac) \
+{ \
+ .rate = _rate##U, \
+ .fbdiv = _fbdiv, \
+ .postdiv1 = _postdiv1, \
+ .refdiv = _refdiv, \
+ .postdiv2 = _postdiv2, \
+ .dsmpd = _dsmpd, \
+ .frac = _frac, \
+}
+
#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \
{ \
.rate = _rate##U, \
@@ -101,6 +133,13 @@ struct rockchip_pll_rate_table {
unsigned int nf;
unsigned int no;
unsigned int nb;
+ /* for RK3036 */
+ unsigned int fbdiv;
+ unsigned int postdiv1;
+ unsigned int refdiv;
+ unsigned int postdiv2;
+ unsigned int dsmpd;
+ unsigned int frac;
};
/**
@@ -235,6 +274,7 @@ struct rockchip_clk_branch {
int gate_offset;
u8 gate_shift;
u8 gate_flags;
+ struct rockchip_clk_branch *child;
};
#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
@@ -369,6 +409,24 @@ struct rockchip_clk_branch {
.gate_flags = gf, \
}
+#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
+ { \
+ .id = _id, \
+ .branch_type = branch_fraction_divider, \
+ .name = cname, \
+ .parent_names = (const char *[]){ pname }, \
+ .num_parents = 1, \
+ .flags = f, \
+ .muxdiv_offset = mo, \
+ .div_shift = 16, \
+ .div_width = 16, \
+ .div_flags = df, \
+ .gate_offset = go, \
+ .gate_shift = gs, \
+ .gate_flags = gf, \
+ .child = ch, \
+ }
+
#define MUX(_id, cname, pnames, f, o, s, w, mf) \
{ \
.id = _id, \
@@ -464,7 +522,7 @@ void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name,
const struct rockchip_cpuclk_rate_table *rates,
int nrates);
void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
-void rockchip_register_restart_notifier(unsigned int reg);
+void rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void));
#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0)
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
index 2fe37f708dc7..813003d6ce09 100644
--- a/drivers/clk/samsung/clk-cpu.c
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -148,6 +148,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
unsigned long div0, div1 = 0, mux_reg;
+ unsigned long flags;
/* find out the divider values to use for clock data */
while ((cfg_data->prate * 1000) != ndata->new_rate) {
@@ -156,7 +157,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
cfg_data++;
}
- spin_lock(cpuclk->lock);
+ spin_lock_irqsave(cpuclk->lock, flags);
/*
* For the selected PLL clock frequency, get the pre-defined divider
@@ -212,7 +213,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
DIV_MASK_ALL);
}
- spin_unlock(cpuclk->lock);
+ spin_unlock_irqrestore(cpuclk->lock, flags);
return 0;
}
@@ -223,6 +224,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
unsigned long div = 0, div_mask = DIV_MASK;
unsigned long mux_reg;
+ unsigned long flags;
/* find out the divider values to use for clock data */
if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
@@ -233,7 +235,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
}
}
- spin_lock(cpuclk->lock);
+ spin_lock_irqsave(cpuclk->lock, flags);
/* select mout_apll as the alternate parent */
mux_reg = readl(base + E4210_SRC_CPU);
@@ -246,7 +248,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
}
exynos_set_safe_div(base, div, div_mask);
- spin_unlock(cpuclk->lock);
+ spin_unlock_irqrestore(cpuclk->lock, flags);
return 0;
}
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 7f370d3e0983..ac03e4fe2871 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -1024,6 +1024,7 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = {
0, 0),
GATE(CLK_AC97, "ac97", "aclk100", GATE_IP_PERIL, 27,
0, 0),
+ GATE(CLK_SSS, "sss", "aclk133", GATE_IP_DMC, 4, 0, 0),
GATE(CLK_PPMUDMC0, "ppmudmc0", "aclk133", GATE_IP_DMC, 8, 0, 0),
GATE(CLK_PPMUDMC1, "ppmudmc1", "aclk133", GATE_IP_DMC, 9, 0, 0),
GATE(CLK_PPMUCPU, "ppmucpu", "aclk133", GATE_IP_DMC, 10, 0, 0),
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 389af3c15ec4..d048dedd8b72 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -18,6 +18,7 @@
#include <linux/syscore_ops.h>
#include "clk.h"
+#include "clk-cpu.h"
#define APLL_LOCK 0x0
#define APLL_CON0 0x100
@@ -616,9 +617,11 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(0, "mout_mspll_kfc", mout_mspll_cpu_p, SRC_TOP7, 8, 2),
MUX(0, "mout_mspll_cpu", mout_mspll_cpu_p, SRC_TOP7, 12, 2),
- MUX(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
+ MUX_F(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
+ CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1),
- MUX(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1),
+ MUX_F(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1,
+ CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
MUX(0, "mout_kfc", mout_kfc_p, SRC_KFC, 16, 1),
MUX(0, "mout_aclk200", mout_group1_p, SRC_TOP0, 8, 2),
@@ -677,8 +680,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP5, 20, 1),
MUX(CLK_MOUT_USER_ACLK300_DISP1, "mout_user_aclk300_disp1",
mout_user_aclk300_disp1_p, SRC_TOP5, 24, 1),
- MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
- SRC_TOP5, 28, 1),
+ MUX(CLK_MOUT_USER_ACLK300_GSCL, "mout_user_aclk300_gscl",
+ mout_user_aclk300_gscl_p, SRC_TOP5, 28, 1),
MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
@@ -729,8 +732,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP12, 20, 1),
MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1",
mout_sw_aclk300_disp1_p, SRC_TOP12, 24, 1),
- MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
- SRC_TOP12, 28, 1),
+ MUX(CLK_MOUT_SW_ACLK300_GSCL, "mout_sw_aclk300_gscl",
+ mout_sw_aclk300_gscl_p, SRC_TOP12, 28, 1),
/* DISP1 Block */
MUX(0, "mout_mipi1", mout_group2_p, SRC_DISP10, 16, 3),
@@ -926,7 +929,7 @@ static struct samsung_gate_clock exynos5x_gate_clks[] __initdata = {
GATE_BUS_TOP, 13, 0, 0),
GATE(0, "aclk166", "mout_user_aclk166",
GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
- GATE(0, "aclk333", "mout_aclk333",
+ GATE(0, "aclk333", "mout_user_aclk333",
GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
GATE_BUS_TOP, 16, 0, 0),
@@ -1246,6 +1249,74 @@ static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = {
KPLL_CON0, NULL),
};
+#define E5420_EGL_DIV0(apll, pclk_dbg, atb, cpud) \
+ ((((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) | \
+ ((cpud) << 4)))
+
+static const struct exynos_cpuclk_cfg_data exynos5420_eglclk_d[] __initconst = {
+ { 1800000, E5420_EGL_DIV0(3, 7, 7, 4), },
+ { 1700000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1600000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1500000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1400000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1300000, E5420_EGL_DIV0(3, 7, 7, 2), },
+ { 1200000, E5420_EGL_DIV0(3, 7, 7, 2), },
+ { 1100000, E5420_EGL_DIV0(3, 7, 7, 2), },
+ { 1000000, E5420_EGL_DIV0(3, 6, 6, 2), },
+ { 900000, E5420_EGL_DIV0(3, 6, 6, 2), },
+ { 800000, E5420_EGL_DIV0(3, 5, 5, 2), },
+ { 700000, E5420_EGL_DIV0(3, 5, 5, 2), },
+ { 600000, E5420_EGL_DIV0(3, 4, 4, 2), },
+ { 500000, E5420_EGL_DIV0(3, 3, 3, 2), },
+ { 400000, E5420_EGL_DIV0(3, 3, 3, 2), },
+ { 300000, E5420_EGL_DIV0(3, 3, 3, 2), },
+ { 200000, E5420_EGL_DIV0(3, 3, 3, 2), },
+ { 0 },
+};
+
+static const struct exynos_cpuclk_cfg_data exynos5800_eglclk_d[] __initconst = {
+ { 2000000, E5420_EGL_DIV0(3, 7, 7, 4), },
+ { 1900000, E5420_EGL_DIV0(3, 7, 7, 4), },
+ { 1800000, E5420_EGL_DIV0(3, 7, 7, 4), },
+ { 1700000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1600000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1500000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1400000, E5420_EGL_DIV0(3, 7, 7, 3), },
+ { 1300000, E5420_EGL_DIV0(3, 7, 7, 2), },
+ { 1200000, E5420_EGL_DIV0(3, 7, 7, 2), },
+ { 1100000, E5420_EGL_DIV0(3, 7, 7, 2), },
+ { 1000000, E5420_EGL_DIV0(3, 7, 6, 2), },
+ { 900000, E5420_EGL_DIV0(3, 7, 6, 2), },
+ { 800000, E5420_EGL_DIV0(3, 7, 5, 2), },
+ { 700000, E5420_EGL_DIV0(3, 7, 5, 2), },
+ { 600000, E5420_EGL_DIV0(3, 7, 4, 2), },
+ { 500000, E5420_EGL_DIV0(3, 7, 3, 2), },
+ { 400000, E5420_EGL_DIV0(3, 7, 3, 2), },
+ { 300000, E5420_EGL_DIV0(3, 7, 3, 2), },
+ { 200000, E5420_EGL_DIV0(3, 7, 3, 2), },
+ { 0 },
+};
+
+#define E5420_KFC_DIV(kpll, pclk, aclk) \
+ ((((kpll) << 24) | ((pclk) << 20) | ((aclk) << 4)))
+
+static const struct exynos_cpuclk_cfg_data exynos5420_kfcclk_d[] __initconst = {
+ { 1400000, E5420_KFC_DIV(3, 5, 3), }, /* for Exynos5800 */
+ { 1300000, E5420_KFC_DIV(3, 5, 2), },
+ { 1200000, E5420_KFC_DIV(3, 5, 2), },
+ { 1100000, E5420_KFC_DIV(3, 5, 2), },
+ { 1000000, E5420_KFC_DIV(3, 5, 2), },
+ { 900000, E5420_KFC_DIV(3, 5, 2), },
+ { 800000, E5420_KFC_DIV(3, 5, 2), },
+ { 700000, E5420_KFC_DIV(3, 4, 2), },
+ { 600000, E5420_KFC_DIV(3, 4, 2), },
+ { 500000, E5420_KFC_DIV(3, 4, 2), },
+ { 400000, E5420_KFC_DIV(3, 3, 2), },
+ { 300000, E5420_KFC_DIV(3, 3, 2), },
+ { 200000, E5420_KFC_DIV(3, 3, 2), },
+ { 0 },
+};
+
static const struct of_device_id ext_clk_match[] __initconst = {
{ .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, },
{ },
@@ -1310,6 +1381,19 @@ static void __init exynos5x_clk_init(struct device_node *np,
ARRAY_SIZE(exynos5800_gate_clks));
}
+ if (soc == EXYNOS5420) {
+ exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+ mout_cpu_p[0], mout_cpu_p[1], 0x200,
+ exynos5420_eglclk_d, ARRAY_SIZE(exynos5420_eglclk_d), 0);
+ } else {
+ exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+ mout_cpu_p[0], mout_cpu_p[1], 0x200,
+ exynos5800_eglclk_d, ARRAY_SIZE(exynos5800_eglclk_d), 0);
+ }
+ exynos_register_cpu_clock(ctx, CLK_KFC_CLK, "kfcclk",
+ mout_kfc_p[0], mout_kfc_p[1], 0x28200,
+ exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0);
+
exynos5420_clk_sleep_init();
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c
index e9eb935d7616..ec6fb14d951c 100644
--- a/drivers/clk/samsung/clk-s3c2410-dclk.c
+++ b/drivers/clk/samsung/clk-s3c2410-dclk.c
@@ -77,12 +77,11 @@ static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw)
static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index)
{
struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
- int ret = 0;
s3c2410_modify_misccr((clkout->mask << clkout->shift),
(index << clkout->shift));
- return ret;
+ return 0;
}
static const struct clk_ops s3c24xx_clkout_ops = {
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 97c71c885e4f..7e2579b30326 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,13 +1,13 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
-obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
-obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
-obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
-obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o
-obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
-obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o
-obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
-obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o
+obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7795) += renesas-cpg-mssr.o \
+ r8a7795-cpg-mssr.o clk-div6.o
+obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-mstp.o clk-div6.o
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index b4c8d6746f68..999994769450 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -18,6 +18,8 @@
#include <linux/of_address.h>
#include <linux/slab.h>
+#include "clk-div6.h"
+
#define CPG_DIV6_CKSTP BIT(8)
#define CPG_DIV6_DIV(d) ((d) & 0x3f)
#define CPG_DIV6_DIV_MASK 0x3f
@@ -172,67 +174,44 @@ static const struct clk_ops cpg_div6_clock_ops = {
.set_rate = cpg_div6_clock_set_rate,
};
-static void __init cpg_div6_clock_init(struct device_node *np)
+
+/**
+ * cpg_div6_register - Register a DIV6 clock
+ * @name: Name of the DIV6 clock
+ * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
+ * @parent_names: Array containing the names of the parent clocks
+ * @reg: Mapped register used to control the DIV6 clock
+ */
+struct clk * __init cpg_div6_register(const char *name,
+ unsigned int num_parents,
+ const char **parent_names,
+ void __iomem *reg)
{
- unsigned int num_parents, valid_parents;
- const char **parent_names;
+ unsigned int valid_parents;
struct clk_init_data init;
struct div6_clock *clock;
- const char *name;
struct clk *clk;
unsigned int i;
- int ret;
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
if (!clock)
- return;
+ return ERR_PTR(-ENOMEM);
- num_parents = of_clk_get_parent_count(np);
- if (num_parents < 1) {
- pr_err("%s: no parent found for %s DIV6 clock\n",
- __func__, np->name);
- return;
+ clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
+ GFP_KERNEL);
+ if (!clock->parents) {
+ clk = ERR_PTR(-ENOMEM);
+ goto free_clock;
}
- clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
- GFP_KERNEL);
- parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
- GFP_KERNEL);
- if (!parent_names)
- return;
+ clock->reg = reg;
- /* Remap the clock register and read the divisor. Disabling the
- * clock overwrites the divisor, so we need to cache its value for the
- * enable operation.
+ /*
+ * Read the divisor. Disabling the clock overwrites the divisor, so we
+ * need to cache its value for the enable operation.
*/
- clock->reg = of_iomap(np, 0);
- if (clock->reg == NULL) {
- pr_err("%s: failed to map %s DIV6 clock register\n",
- __func__, np->name);
- goto error;
- }
-
clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
- /* Parse the DT properties. */
- ret = of_property_read_string(np, "clock-output-names", &name);
- if (ret < 0) {
- pr_err("%s: failed to get %s DIV6 clock output name\n",
- __func__, np->name);
- goto error;
- }
-
-
- for (i = 0, valid_parents = 0; i < num_parents; i++) {
- const char *name = of_clk_get_parent_name(np, i);
-
- if (name) {
- parent_names[valid_parents] = name;
- clock->parents[valid_parents] = i;
- valid_parents++;
- }
- }
-
switch (num_parents) {
case 1:
/* fixed parent clock */
@@ -250,8 +229,18 @@ static void __init cpg_div6_clock_init(struct device_node *np)
break;
default:
pr_err("%s: invalid number of parents for DIV6 clock %s\n",
- __func__, np->name);
- goto error;
+ __func__, name);
+ clk = ERR_PTR(-EINVAL);
+ goto free_parents;
+ }
+
+ /* Filter out invalid parents */
+ for (i = 0, valid_parents = 0; i < num_parents; i++) {
+ if (parent_names[i]) {
+ parent_names[valid_parents] = parent_names[i];
+ clock->parents[valid_parents] = i;
+ valid_parents++;
+ }
}
/* Register the clock. */
@@ -264,6 +253,53 @@ static void __init cpg_div6_clock_init(struct device_node *np)
clock->hw.init = &init;
clk = clk_register(NULL, &clock->hw);
+ if (IS_ERR(clk))
+ goto free_parents;
+
+ return clk;
+
+free_parents:
+ kfree(clock->parents);
+free_clock:
+ kfree(clock);
+ return clk;
+}
+
+static void __init cpg_div6_clock_init(struct device_node *np)
+{
+ unsigned int num_parents;
+ const char **parent_names;
+ const char *clk_name = np->name;
+ void __iomem *reg;
+ struct clk *clk;
+ unsigned int i;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents < 1) {
+ pr_err("%s: no parent found for %s DIV6 clock\n",
+ __func__, np->name);
+ return;
+ }
+
+ parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
+ GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ reg = of_iomap(np, 0);
+ if (reg == NULL) {
+ pr_err("%s: failed to map %s DIV6 clock register\n",
+ __func__, np->name);
+ goto error;
+ }
+
+ /* Parse the DT properties. */
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
if (IS_ERR(clk)) {
pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
__func__, np->name, PTR_ERR(clk));
@@ -276,9 +312,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
return;
error:
- if (clock->reg)
- iounmap(clock->reg);
+ if (reg)
+ iounmap(reg);
kfree(parent_names);
- kfree(clock);
}
CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);
diff --git a/drivers/clk/shmobile/clk-div6.h b/drivers/clk/shmobile/clk-div6.h
new file mode 100644
index 000000000000..9a85a95188da
--- /dev/null
+++ b/drivers/clk/shmobile/clk-div6.h
@@ -0,0 +1,7 @@
+#ifndef __SHMOBILE_CLK_DIV6_H__
+#define __SHMOBILE_CLK_DIV6_H__
+
+struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
+ const char **parent_names, void __iomem *reg);
+
+#endif
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index 745496f7ee9c..841977240305 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -115,7 +115,7 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
*
* Using experimental measurements, it seems that no more than
* ~10 iterations are needed, independently of the CPU rate.
- * Since this value might be dependant of external xtal rate, pll1
+ * Since this value might be dependent on external xtal rate, pll1
* rate or even the other emulation clocks rate, use 1000 as a
* "super" safe value.
*/
@@ -262,7 +262,7 @@ static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
* 1 1 0 30 / 2 x172/2 x208/2 x106
* 1 1 1 30 / 2 x172/2 x208/2 x88
*
- * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2)
+ * *1 : Table 7.6 indicates VCO output (PLLx = VCO/2)
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
(((md) & BIT(13)) >> 12) | \
diff --git a/drivers/clk/shmobile/r8a7795-cpg-mssr.c b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
new file mode 100644
index 000000000000..13e994772dfd
--- /dev/null
+++ b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
@@ -0,0 +1,383 @@
+/*
+ * r8a7795 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-rcar-gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics 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.
+ */
+
+#include <linux/bug.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R8A7795_CLK_OSC,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+ CLK_EXTALR,
+
+ /* Internal Core Clocks */
+ CLK_MAIN,
+ CLK_PLL0,
+ CLK_PLL1,
+ CLK_PLL2,
+ CLK_PLL3,
+ CLK_PLL4,
+ CLK_PLL1_DIV2,
+ CLK_PLL1_DIV4,
+ CLK_S0,
+ CLK_S1,
+ CLK_S2,
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_SSPSRC,
+
+ /* Module Clocks */
+ MOD_CLK_BASE
+};
+
+enum r8a7795_clk_types {
+ CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
+ CLK_TYPE_GEN3_PLL0,
+ CLK_TYPE_GEN3_PLL1,
+ CLK_TYPE_GEN3_PLL2,
+ CLK_TYPE_GEN3_PLL3,
+ CLK_TYPE_GEN3_PLL4,
+};
+
+static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+ DEF_INPUT("extalr", CLK_EXTALR),
+
+ /* Internal Core Clocks */
+ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+ DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+ DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+ DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
+ DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+ DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+ DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
+ DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1),
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
+
+ /* Core Clock Outputs */
+ DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+ DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED("zx", R8A7795_CLK_ZX, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED("s0d1", R8A7795_CLK_S0D1, CLK_S0, 1, 1),
+ DEF_FIXED("s0d4", R8A7795_CLK_S0D4, CLK_S0, 4, 1),
+ DEF_FIXED("s1d1", R8A7795_CLK_S1D1, CLK_S1, 1, 1),
+ DEF_FIXED("s1d2", R8A7795_CLK_S1D2, CLK_S1, 2, 1),
+ DEF_FIXED("s1d4", R8A7795_CLK_S1D4, CLK_S1, 4, 1),
+ DEF_FIXED("s2d1", R8A7795_CLK_S2D1, CLK_S2, 1, 1),
+ DEF_FIXED("s2d2", R8A7795_CLK_S2D2, CLK_S2, 2, 1),
+ DEF_FIXED("s2d4", R8A7795_CLK_S2D4, CLK_S2, 4, 1),
+ DEF_FIXED("s3d1", R8A7795_CLK_S3D1, CLK_S3, 1, 1),
+ DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1),
+ DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1),
+ DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1),
+ DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1),
+
+ DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014),
+ DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250),
+};
+
+static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
+ DEF_MOD("scif5", 202, R8A7795_CLK_S3D4),
+ DEF_MOD("scif4", 203, R8A7795_CLK_S3D4),
+ DEF_MOD("scif3", 204, R8A7795_CLK_S3D4),
+ DEF_MOD("scif1", 206, R8A7795_CLK_S3D4),
+ DEF_MOD("scif0", 207, R8A7795_CLK_S3D4),
+ DEF_MOD("msiof3", 208, R8A7795_CLK_MSO),
+ DEF_MOD("msiof2", 209, R8A7795_CLK_MSO),
+ DEF_MOD("msiof1", 210, R8A7795_CLK_MSO),
+ DEF_MOD("msiof0", 211, R8A7795_CLK_MSO),
+ DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1),
+ DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1),
+ DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1),
+ DEF_MOD("scif2", 310, R8A7795_CLK_S3D4),
+ DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1),
+ DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1),
+ DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1),
+ DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4),
+ DEF_MOD("audmac1", 501, R8A7795_CLK_S3D4),
+ DEF_MOD("hscif4", 516, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif3", 517, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1),
+ DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1),
+ DEF_MOD("vspd3", 620, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd2", 621, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd1", 622, R8A7795_CLK_S2D1),
+ DEF_MOD("vspd0", 623, R8A7795_CLK_S2D1),
+ DEF_MOD("vspbc", 624, R8A7795_CLK_S2D1),
+ DEF_MOD("vspbd", 626, R8A7795_CLK_S2D1),
+ DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1),
+ DEF_MOD("vspi1", 630, R8A7795_CLK_S2D1),
+ DEF_MOD("vspi0", 631, R8A7795_CLK_S2D1),
+ DEF_MOD("ehci2", 701, R8A7795_CLK_S3D4),
+ DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4),
+ DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4),
+ DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4),
+ DEF_MOD("du3", 721, R8A7795_CLK_S2D1),
+ DEF_MOD("du2", 722, R8A7795_CLK_S2D1),
+ DEF_MOD("du1", 723, R8A7795_CLK_S2D1),
+ DEF_MOD("du0", 724, R8A7795_CLK_S2D1),
+ DEF_MOD("hdmi1", 728, R8A7795_CLK_HDMI),
+ DEF_MOD("hdmi0", 729, R8A7795_CLK_HDMI),
+ DEF_MOD("etheravb", 812, R8A7795_CLK_S3D2),
+ DEF_MOD("sata0", 815, R8A7795_CLK_S3D2),
+ DEF_MOD("gpio7", 905, R8A7795_CLK_CP),
+ DEF_MOD("gpio6", 906, R8A7795_CLK_CP),
+ DEF_MOD("gpio5", 907, R8A7795_CLK_CP),
+ DEF_MOD("gpio4", 908, R8A7795_CLK_CP),
+ DEF_MOD("gpio3", 909, R8A7795_CLK_CP),
+ DEF_MOD("gpio2", 910, R8A7795_CLK_CP),
+ DEF_MOD("gpio1", 911, R8A7795_CLK_CP),
+ DEF_MOD("gpio0", 912, R8A7795_CLK_CP),
+ DEF_MOD("i2c6", 918, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c5", 919, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c4", 927, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c3", 928, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c2", 929, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c1", 930, R8A7795_CLK_S3D2),
+ DEF_MOD("i2c0", 931, R8A7795_CLK_S3D2),
+ DEF_MOD("ssi-all", 1005, R8A7795_CLK_S3D4),
+ DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)),
+ DEF_MOD("scu-all", 1017, R8A7795_CLK_S3D4),
+ DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
+ MOD_CLK_ID(408), /* INTC-AP (GIC) */
+};
+
+
+#define CPG_PLL0CR 0x00d8
+#define CPG_PLL2CR 0x002c
+#define CPG_PLL4CR 0x01f4
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
+ * 14 13 19 17 (MHz)
+ *-------------------------------------------------------------------
+ * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
+ * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
+ * 0 0 1 0 Prohibited setting
+ * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
+ * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
+ * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
+ * 0 1 1 0 Prohibited setting
+ * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
+ * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
+ * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
+ * 1 0 1 0 Prohibited setting
+ * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
+ * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
+ * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
+ * 1 1 1 0 Prohibited setting
+ * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
+ */
+#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
+ (((md) & BIT(13)) >> 11) | \
+ (((md) & BIT(19)) >> 18) | \
+ (((md) & BIT(17)) >> 17))
+
+struct cpg_pll_config {
+ unsigned int extal_div;
+ unsigned int pll1_mult;
+ unsigned int pll3_mult;
+};
+
+static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
+ /* EXTAL div PLL1 mult PLL3 mult */
+ { 1, 192, 192, },
+ { 1, 192, 128, },
+ { 0, /* Prohibited setting */ },
+ { 1, 192, 192, },
+ { 1, 160, 160, },
+ { 1, 160, 106, },
+ { 0, /* Prohibited setting */ },
+ { 1, 160, 160, },
+ { 1, 128, 128, },
+ { 1, 128, 84, },
+ { 0, /* Prohibited setting */ },
+ { 1, 128, 128, },
+ { 2, 192, 192, },
+ { 2, 192, 128, },
+ { 0, /* Prohibited setting */ },
+ { 2, 192, 192, },
+};
+
+static const struct cpg_pll_config *cpg_pll_config __initdata;
+
+static
+struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
+ const struct cpg_core_clk *core,
+ const struct cpg_mssr_info *info,
+ struct clk **clks,
+ void __iomem *base)
+{
+ const struct clk *parent;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+ u32 value;
+
+ parent = clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ switch (core->type) {
+ case CLK_TYPE_GEN3_MAIN:
+ div = cpg_pll_config->extal_div;
+ break;
+
+ case CLK_TYPE_GEN3_PLL0:
+ /*
+ * PLL0 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ value = readl(base + CPG_PLL0CR);
+ mult = (((value >> 24) & 0x7f) + 1) * 2;
+ break;
+
+ case CLK_TYPE_GEN3_PLL1:
+ mult = cpg_pll_config->pll1_mult;
+ break;
+
+ case CLK_TYPE_GEN3_PLL2:
+ /*
+ * PLL2 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ value = readl(base + CPG_PLL2CR);
+ mult = (((value >> 24) & 0x7f) + 1) * 2;
+ break;
+
+ case CLK_TYPE_GEN3_PLL3:
+ mult = cpg_pll_config->pll3_mult;
+ break;
+
+ case CLK_TYPE_GEN3_PLL4:
+ /*
+ * PLL4 is a configurable multiplier clock. Register it as a
+ * fixed factor clock for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ value = readl(base + CPG_PLL4CR);
+ mult = (((value >> 24) & 0x7f) + 1) * 2;
+ break;
+
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, core->name,
+ __clk_get_name(parent), 0, mult, div);
+}
+
+/*
+ * Reset register definitions.
+ */
+#define MODEMR 0xe6160060
+
+static u32 rcar_gen3_read_mode_pins(void)
+{
+ void __iomem *modemr = ioremap_nocache(MODEMR, 4);
+ u32 mode;
+
+ BUG_ON(!modemr);
+ mode = ioread32(modemr);
+ iounmap(modemr);
+
+ return mode;
+}
+
+static int __init r8a7795_cpg_mssr_init(struct device *dev)
+{
+ u32 cpg_mode = rcar_gen3_read_mode_pins();
+
+ cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+ if (!cpg_pll_config->extal_div) {
+ dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
+ /* Core Clocks */
+ .core_clks = r8a7795_core_clks,
+ .num_core_clks = ARRAY_SIZE(r8a7795_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Module Clocks */
+ .mod_clks = r8a7795_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks),
+ .num_hw_mod_clks = 12 * 32,
+
+ /* Critical Module Clocks */
+ .crit_mod_clks = r8a7795_crit_mod_clks,
+ .num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks),
+
+ /* Callbacks */
+ .init = r8a7795_cpg_mssr_init,
+ .cpg_clk_register = r8a7795_cpg_clk_register,
+};
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c
new file mode 100644
index 000000000000..9a4d888164bb
--- /dev/null
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.c
@@ -0,0 +1,596 @@
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Renesas Electronics 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "clk-div6.h"
+
+#ifdef DEBUG
+#define WARN_DEBUG(x) do { } while (0)
+#else
+#define WARN_DEBUG(x) WARN_ON(x)
+#endif
+
+
+/*
+ * Module Standby and Software Reset register offets.
+ *
+ * If the registers exist, these are valid for SH-Mobile, R-Mobile,
+ * R-Car Gen 2, and R-Car Gen 3.
+ * These are NOT valid for R-Car Gen1 and RZ/A1!
+ */
+
+/*
+ * Module Stop Status Register offsets
+ */
+
+static const u16 mstpsr[] = {
+ 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4,
+ 0x9A0, 0x9A4, 0x9A8, 0x9AC,
+};
+
+#define MSTPSR(i) mstpsr[i]
+
+
+/*
+ * System Module Stop Control Register offsets
+ */
+
+static const u16 smstpcr[] = {
+ 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C,
+ 0x990, 0x994, 0x998, 0x99C,
+};
+
+#define SMSTPCR(i) smstpcr[i]
+
+
+/*
+ * Software Reset Register offsets
+ */
+
+static const u16 srcr[] = {
+ 0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC,
+ 0x920, 0x924, 0x928, 0x92C,
+};
+
+#define SRCR(i) srcr[i]
+
+
+/* Realtime Module Stop Control Register offsets */
+#define RMSTPCR(i) (smstpcr[i] - 0x20)
+
+/* Modem Module Stop Control Register offsets (r8a73a4) */
+#define MMSTPCR(i) (smstpcr[i] + 0x20)
+
+/* Software Reset Clearing Register offsets */
+#define SRSTCLR(i) (0x940 + (i) * 4)
+
+
+/**
+ * Clock Pulse Generator / Module Standby and Software Reset Private Data
+ *
+ * @dev: CPG/MSSR device
+ * @base: CPG/MSSR register block base address
+ * @mstp_lock: protects writes to SMSTPCR
+ * @clks: Array containing all Core and Module Clocks
+ * @num_core_clks: Number of Core Clocks in clks[]
+ * @num_mod_clks: Number of Module Clocks in clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ */
+struct cpg_mssr_priv {
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t mstp_lock;
+
+ struct clk **clks;
+ unsigned int num_core_clks;
+ unsigned int num_mod_clks;
+ unsigned int last_dt_core_clk;
+};
+
+
+/**
+ * struct mstp_clock - MSTP gating clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @index: MSTP clock number
+ * @priv: CPG/MSSR private data
+ */
+struct mstp_clock {
+ struct clk_hw hw;
+ u32 index;
+ struct cpg_mssr_priv *priv;
+};
+
+#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
+
+static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
+{
+ struct mstp_clock *clock = to_mstp_clock(hw);
+ struct cpg_mssr_priv *priv = clock->priv;
+ unsigned int reg = clock->index / 32;
+ unsigned int bit = clock->index % 32;
+ struct device *dev = priv->dev;
+ u32 bitmask = BIT(bit);
+ unsigned long flags;
+ unsigned int i;
+ u32 value;
+
+ dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
+ enable ? "ON" : "OFF");
+ spin_lock_irqsave(&priv->mstp_lock, flags);
+
+ value = clk_readl(priv->base + SMSTPCR(reg));
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ clk_writel(value, priv->base + SMSTPCR(reg));
+
+ spin_unlock_irqrestore(&priv->mstp_lock, flags);
+
+ if (!enable)
+ return 0;
+
+ for (i = 1000; i > 0; --i) {
+ if (!(clk_readl(priv->base + MSTPSR(reg)) &
+ bitmask))
+ break;
+ cpu_relax();
+ }
+
+ if (!i) {
+ dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
+ priv->base + SMSTPCR(reg), bit);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int cpg_mstp_clock_enable(struct clk_hw *hw)
+{
+ return cpg_mstp_clock_endisable(hw, true);
+}
+
+static void cpg_mstp_clock_disable(struct clk_hw *hw)
+{
+ cpg_mstp_clock_endisable(hw, false);
+}
+
+static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
+{
+ struct mstp_clock *clock = to_mstp_clock(hw);
+ struct cpg_mssr_priv *priv = clock->priv;
+ u32 value;
+
+ value = clk_readl(priv->base + MSTPSR(clock->index / 32));
+
+ return !(value & BIT(clock->index % 32));
+}
+
+static const struct clk_ops cpg_mstp_clock_ops = {
+ .enable = cpg_mstp_clock_enable,
+ .disable = cpg_mstp_clock_disable,
+ .is_enabled = cpg_mstp_clock_is_enabled,
+};
+
+static
+struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ unsigned int clkidx = clkspec->args[1];
+ struct cpg_mssr_priv *priv = data;
+ struct device *dev = priv->dev;
+ unsigned int idx;
+ const char *type;
+ struct clk *clk;
+
+ switch (clkspec->args[0]) {
+ case CPG_CORE:
+ type = "core";
+ if (clkidx > priv->last_dt_core_clk) {
+ dev_err(dev, "Invalid %s clock index %u\n", type,
+ clkidx);
+ return ERR_PTR(-EINVAL);
+ }
+ clk = priv->clks[clkidx];
+ break;
+
+ case CPG_MOD:
+ type = "module";
+ idx = MOD_CLK_PACK(clkidx);
+ if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
+ dev_err(dev, "Invalid %s clock index %u\n", type,
+ clkidx);
+ return ERR_PTR(-EINVAL);
+ }
+ clk = priv->clks[priv->num_core_clks + idx];
+ break;
+
+ default:
+ dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (IS_ERR(clk))
+ dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
+ PTR_ERR(clk));
+ else
+ dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n",
+ clkspec->args[0], clkspec->args[1], clk, clk);
+ return clk;
+}
+
+static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
+ const struct cpg_mssr_info *info,
+ struct cpg_mssr_priv *priv)
+{
+ struct clk *clk = NULL, *parent;
+ struct device *dev = priv->dev;
+ unsigned int id = core->id;
+ const char *parent_name;
+
+ WARN_DEBUG(id >= priv->num_core_clks);
+ WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+ switch (core->type) {
+ case CLK_TYPE_IN:
+ clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+ break;
+
+ case CLK_TYPE_FF:
+ case CLK_TYPE_DIV6P1:
+ WARN_DEBUG(core->parent >= priv->num_core_clks);
+ parent = priv->clks[core->parent];
+ if (IS_ERR(parent)) {
+ clk = parent;
+ goto fail;
+ }
+
+ parent_name = __clk_get_name(parent);
+ if (core->type == CLK_TYPE_FF) {
+ clk = clk_register_fixed_factor(NULL, core->name,
+ parent_name, 0,
+ core->mult, core->div);
+ } else {
+ clk = cpg_div6_register(core->name, 1, &parent_name,
+ priv->base + core->offset);
+ }
+ break;
+
+ default:
+ if (info->cpg_clk_register)
+ clk = info->cpg_clk_register(dev, core, info,
+ priv->clks, priv->base);
+ else
+ dev_err(dev, "%s has unsupported core clock type %u\n",
+ core->name, core->type);
+ break;
+ }
+
+ if (IS_ERR_OR_NULL(clk))
+ goto fail;
+
+ dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk);
+ priv->clks[id] = clk;
+ return;
+
+fail:
+ dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,",
+ core->name, PTR_ERR(clk));
+}
+
+static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
+ const struct cpg_mssr_info *info,
+ struct cpg_mssr_priv *priv)
+{
+ struct mstp_clock *clock = NULL;
+ struct device *dev = priv->dev;
+ unsigned int id = mod->id;
+ struct clk_init_data init;
+ struct clk *parent, *clk;
+ const char *parent_name;
+ unsigned int i;
+
+ WARN_DEBUG(id < priv->num_core_clks);
+ WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
+ WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
+ WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+ parent = priv->clks[mod->parent];
+ if (IS_ERR(parent)) {
+ clk = parent;
+ goto fail;
+ }
+
+ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ if (!clock) {
+ clk = ERR_PTR(-ENOMEM);
+ goto fail;
+ }
+
+ init.name = mod->name;
+ init.ops = &cpg_mstp_clock_ops;
+ init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+ for (i = 0; i < info->num_crit_mod_clks; i++)
+ if (id == info->crit_mod_clks[i]) {
+#ifdef CLK_ENABLE_HAND_OFF
+ dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n",
+ mod->name);
+ init.flags |= CLK_ENABLE_HAND_OFF;
+ break;
+#else
+ dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n",
+ mod->name);
+ return;
+#endif
+ }
+
+ parent_name = __clk_get_name(parent);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clock->index = id - priv->num_core_clks;
+ clock->priv = priv;
+ clock->hw.init = &init;
+
+ clk = clk_register(NULL, &clock->hw);
+ if (IS_ERR(clk))
+ goto fail;
+
+ dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk);
+ priv->clks[id] = clk;
+ return;
+
+fail:
+ dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,",
+ mod->name, PTR_ERR(clk));
+ kfree(clock);
+}
+
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+struct cpg_mssr_clk_domain {
+ struct generic_pm_domain genpd;
+ struct device_node *np;
+ unsigned int num_core_pm_clks;
+ unsigned int core_pm_clks[0];
+};
+
+static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
+ struct cpg_mssr_clk_domain *pd)
+{
+ unsigned int i;
+
+ if (clkspec->np != pd->np || clkspec->args_count != 2)
+ return false;
+
+ switch (clkspec->args[0]) {
+ case CPG_CORE:
+ for (i = 0; i < pd->num_core_pm_clks; i++)
+ if (clkspec->args[1] == pd->core_pm_clks[i])
+ return true;
+ return false;
+
+ case CPG_MOD:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ struct cpg_mssr_clk_domain *pd =
+ container_of(genpd, struct cpg_mssr_clk_domain, genpd);
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ struct clk *clk;
+ int i = 0;
+ int error;
+
+ while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+ &clkspec)) {
+ if (cpg_mssr_is_pm_clk(&clkspec, pd))
+ goto found;
+
+ of_node_put(clkspec.np);
+ i++;
+ }
+
+ return 0;
+
+found:
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ error = pm_clk_create(dev);
+ if (error) {
+ dev_err(dev, "pm_clk_create failed %d\n", error);
+ goto fail_put;
+ }
+
+ error = pm_clk_add_clk(dev, clk);
+ if (error) {
+ dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+ goto fail_destroy;
+ }
+
+ return 0;
+
+fail_destroy:
+ pm_clk_destroy(dev);
+fail_put:
+ clk_put(clk);
+ return error;
+}
+
+static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ if (!list_empty(&dev->power.subsys_data->clock_list))
+ pm_clk_destroy(dev);
+}
+
+static int __init cpg_mssr_add_clk_domain(struct device *dev,
+ const unsigned int *core_pm_clks,
+ unsigned int num_core_pm_clks)
+{
+ struct device_node *np = dev->of_node;
+ struct generic_pm_domain *genpd;
+ struct cpg_mssr_clk_domain *pd;
+ size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
+
+ pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pd->np = np;
+ pd->num_core_pm_clks = num_core_pm_clks;
+ memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
+
+ genpd = &pd->genpd;
+ genpd->name = np->name;
+ genpd->flags = GENPD_FLAG_PM_CLK;
+ pm_genpd_init(genpd, &simple_qos_governor, false);
+ genpd->attach_dev = cpg_mssr_attach_dev;
+ genpd->detach_dev = cpg_mssr_detach_dev;
+
+ of_genpd_add_provider_simple(np, genpd);
+ return 0;
+}
+#else
+static inline int cpg_mssr_add_clk_domain(struct device *dev,
+ const unsigned int *core_pm_clks,
+ unsigned int num_core_pm_clks)
+{
+ return 0;
+}
+#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
+
+
+static const struct of_device_id cpg_mssr_match[] = {
+#ifdef CONFIG_ARCH_R8A7795
+ {
+ .compatible = "renesas,r8a7795-cpg-mssr",
+ .data = &r8a7795_cpg_mssr_info,
+ },
+#endif
+ { /* sentinel */ }
+};
+
+static void cpg_mssr_del_clk_provider(void *data)
+{
+ of_clk_del_provider(data);
+}
+
+static int __init cpg_mssr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct cpg_mssr_info *info;
+ struct cpg_mssr_priv *priv;
+ unsigned int nclks, i;
+ struct resource *res;
+ struct clk **clks;
+ int error;
+
+ info = of_match_node(cpg_mssr_match, np)->data;
+ if (info->init) {
+ error = info->init(dev);
+ if (error)
+ return error;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ spin_lock_init(&priv->mstp_lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+ clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ priv->clks = clks;
+ priv->num_core_clks = info->num_total_core_clks;
+ priv->num_mod_clks = info->num_hw_mod_clks;
+ priv->last_dt_core_clk = info->last_dt_core_clk;
+
+ for (i = 0; i < nclks; i++)
+ clks[i] = ERR_PTR(-ENOENT);
+
+ for (i = 0; i < info->num_core_clks; i++)
+ cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
+
+ for (i = 0; i < info->num_mod_clks; i++)
+ cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
+
+ error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
+ if (error)
+ return error;
+
+ devm_add_action(dev, cpg_mssr_del_clk_provider, np);
+
+ error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks,
+ info->num_core_pm_clks);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static struct platform_driver cpg_mssr_driver = {
+ .driver = {
+ .name = "renesas-cpg-mssr",
+ .of_match_table = cpg_mssr_match,
+ },
+};
+
+static int __init cpg_mssr_init(void)
+{
+ return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe);
+}
+
+subsys_initcall(cpg_mssr_init);
+
+MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.h b/drivers/clk/shmobile/renesas-cpg-mssr.h
new file mode 100644
index 000000000000..e09f03cbf086
--- /dev/null
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.h
@@ -0,0 +1,132 @@
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * 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.
+ */
+
+#ifndef __CLK_RENESAS_CPG_MSSR_H__
+#define __CLK_RENESAS_CPG_MSSR_H__
+
+ /*
+ * Definitions of CPG Core Clocks
+ *
+ * These include:
+ * - Clock outputs exported to DT
+ * - External input clocks
+ * - Internal CPG clocks
+ */
+
+struct cpg_core_clk {
+ /* Common */
+ const char *name;
+ unsigned int id;
+ unsigned int type;
+ /* Depending on type */
+ unsigned int parent; /* Core Clocks only */
+ unsigned int div;
+ unsigned int mult;
+ unsigned int offset;
+};
+
+enum clk_types {
+ /* Generic */
+ CLK_TYPE_IN, /* External Clock Input */
+ CLK_TYPE_FF, /* Fixed Factor Clock */
+ CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */
+
+ /* Custom definitions start here */
+ CLK_TYPE_CUSTOM,
+};
+
+#define DEF_TYPE(_name, _id, _type...) \
+ { .name = _name, .id = _id, .type = _type }
+#define DEF_BASE(_name, _id, _type, _parent...) \
+ DEF_TYPE(_name, _id, _type, .parent = _parent)
+
+#define DEF_INPUT(_name, _id) \
+ DEF_TYPE(_name, _id, CLK_TYPE_IN)
+#define DEF_FIXED(_name, _id, _parent, _div, _mult) \
+ DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_DIV6P1(_name, _id, _parent, _offset) \
+ DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
+
+
+ /*
+ * Definitions of Module Clocks
+ */
+
+struct mssr_mod_clk {
+ const char *name;
+ unsigned int id;
+ unsigned int parent; /* Add MOD_CLK_BASE for Module Clocks */
+};
+
+/* Convert from sparse base-100 to packed index space */
+#define MOD_CLK_PACK(x) ((x) - ((x) / 100) * (100 - 32))
+
+#define MOD_CLK_ID(x) (MOD_CLK_BASE + MOD_CLK_PACK(x))
+
+#define DEF_MOD(_name, _mod, _parent...) \
+ { .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
+
+
+struct device_node;
+
+ /**
+ * SoC-specific CPG/MSSR Description
+ *
+ * @core_clks: Array of Core Clock definitions
+ * @num_core_clks: Number of entries in core_clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @num_total_core_clks: Total number of Core Clocks (exported + internal)
+ *
+ * @mod_clks: Array of Module Clock definitions
+ * @num_mod_clks: Number of entries in mod_clks[]
+ * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
+ *
+ * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
+ * should not be disabled without a knowledgeable driver
+ * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
+ *
+ * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
+ * Management, in addition to Module Clocks
+ * @num_core_pm_clks: Number of entries in core_pm_clks[]
+ *
+ * @init: Optional callback to perform SoC-specific initialization
+ * @cpg_clk_register: Optional callback to handle special Core Clock types
+ */
+
+struct cpg_mssr_info {
+ /* Core Clocks */
+ const struct cpg_core_clk *core_clks;
+ unsigned int num_core_clks;
+ unsigned int last_dt_core_clk;
+ unsigned int num_total_core_clks;
+
+ /* Module Clocks */
+ const struct mssr_mod_clk *mod_clks;
+ unsigned int num_mod_clks;
+ unsigned int num_hw_mod_clks;
+
+ /* Critical Module Clocks that should not be disabled */
+ const unsigned int *crit_mod_clks;
+ unsigned int num_crit_mod_clks;
+
+ /* Core Clocks suitable for PM, in addition to the Module Clocks */
+ const unsigned int *core_pm_clks;
+ unsigned int num_core_pm_clks;
+
+ /* Callbacks */
+ int (*init)(struct device *dev);
+ struct clk *(*cpg_clk_register)(struct device *dev,
+ const struct cpg_core_clk *core,
+ const struct cpg_mssr_info *info,
+ struct clk **clks, void __iomem *base);
+};
+
+extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
+#endif
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index 576cd0354d48..ccb324d97160 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -549,19 +549,20 @@ static int clk_fs660c32_vco_get_params(unsigned long input,
return 0;
}
-static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate
- , unsigned long *prate)
+static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *prate)
{
struct stm_fs params;
- if (!clk_fs660c32_vco_get_params(*prate, rate, &params))
- clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+ if (clk_fs660c32_vco_get_params(*prate, rate, &params))
+ return rate;
- pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
+ clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+
+ pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
__func__, clk_hw_get_name(hw),
- rate, (unsigned int)params.sdiv,
- (unsigned int)params.mdiv,
- (unsigned int)params.pe, (unsigned int)params.nsdiv);
+ rate, (unsigned int)params.ndiv);
return rate;
}
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index cb4c299214ce..3fd7901d48e4 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -7,14 +7,19 @@ obj-y += clk-a10-codec.o
obj-y += clk-a10-hosc.o
obj-y += clk-a10-mod1.o
obj-y += clk-a10-pll2.o
+obj-y += clk-a10-ve.o
obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
obj-y += clk-simple-gates.o
+obj-y += clk-sun8i-bus-gates.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
obj-y += clk-sun9i-mmc.o
obj-y += clk-usb.o
+obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
+obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
+
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
clk-sun8i-apb0.o
diff --git a/drivers/clk/sunxi/clk-a10-ve.c b/drivers/clk/sunxi/clk-a10-ve.c
new file mode 100644
index 000000000000..044c1717b762
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-ve.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(ve_lock);
+
+#define SUN4I_VE_ENABLE 31
+#define SUN4I_VE_DIVIDER_SHIFT 16
+#define SUN4I_VE_DIVIDER_WIDTH 3
+#define SUN4I_VE_RESET 0
+
+/**
+ * sunxi_ve_reset... - reset bit in ve clk registers handling
+ */
+
+struct ve_reset_data {
+ void __iomem *reg;
+ spinlock_t *lock;
+ struct reset_controller_dev rcdev;
+};
+
+static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct ve_reset_data *data = container_of(rcdev,
+ struct ve_reset_data,
+ rcdev);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(data->lock, flags);
+
+ reg = readl(data->reg);
+ writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
+
+ spin_unlock_irqrestore(data->lock, flags);
+
+ return 0;
+}
+
+static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct ve_reset_data *data = container_of(rcdev,
+ struct ve_reset_data,
+ rcdev);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(data->lock, flags);
+
+ reg = readl(data->reg);
+ writel(reg | BIT(SUN4I_VE_RESET), data->reg);
+
+ spin_unlock_irqrestore(data->lock, flags);
+
+ return 0;
+}
+
+static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ if (WARN_ON(reset_spec->args_count != 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct reset_control_ops sunxi_ve_reset_ops = {
+ .assert = sunxi_ve_reset_assert,
+ .deassert = sunxi_ve_reset_deassert,
+};
+
+static void __init sun4i_ve_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_divider *div;
+ struct clk_gate *gate;
+ struct ve_reset_data *reset_data;
+ const char *parent;
+ const char *clk_name = node->name;
+ void __iomem *reg;
+ int err;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg))
+ return;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ goto err_unmap;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto err_free_div;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent = of_clk_get_parent_name(node, 0);
+
+ gate->reg = reg;
+ gate->bit_idx = SUN4I_VE_ENABLE;
+ gate->lock = &ve_lock;
+
+ div->reg = reg;
+ div->shift = SUN4I_VE_DIVIDER_SHIFT;
+ div->width = SUN4I_VE_DIVIDER_WIDTH;
+ div->lock = &ve_lock;
+
+ clk = clk_register_composite(NULL, clk_name, &parent, 1,
+ NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops,
+ CLK_SET_RATE_PARENT);
+ if (IS_ERR(clk))
+ goto err_free_gate;
+
+ err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (err)
+ goto err_unregister_clk;
+
+ reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+ if (!reset_data)
+ goto err_del_provider;
+
+ reset_data->reg = reg;
+ reset_data->lock = &ve_lock;
+ reset_data->rcdev.nr_resets = 1;
+ reset_data->rcdev.ops = &sunxi_ve_reset_ops;
+ reset_data->rcdev.of_node = node;
+ reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
+ reset_data->rcdev.of_reset_n_cells = 0;
+ err = reset_controller_register(&reset_data->rcdev);
+ if (err)
+ goto err_free_reset;
+
+ return;
+
+err_free_reset:
+ kfree(reset_data);
+err_del_provider:
+ of_clk_del_provider(node);
+err_unregister_clk:
+ clk_unregister(clk);
+err_free_gate:
+ kfree(gate);
+err_free_div:
+ kfree(div);
+err_unmap:
+ iounmap(reg);
+}
+CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
+ sun4i_ve_clk_setup);
diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
index 0214c6548afd..f4da52b5ca0e 100644
--- a/drivers/clk/sunxi/clk-simple-gates.c
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -140,6 +140,8 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
sunxi_simple_gates_init);
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
+ sunxi_simple_gates_init);
static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
14, /* ahb_sdram */
@@ -158,3 +160,15 @@ CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
sun4i_a10_ahb_init);
CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
sun4i_a10_ahb_init);
+
+static const int sun4i_a10_dram_critical_clocks[] __initconst = {
+ 15, /* dram_output */
+};
+
+static void __init sun4i_a10_dram_init(struct device_node *node)
+{
+ sunxi_simple_gates_setup(node, sun4i_a10_dram_critical_clocks,
+ ARRAY_SIZE(sun4i_a10_dram_critical_clocks));
+}
+CLK_OF_DECLARE(sun4i_a10_dram, "allwinner,sun4i-a10-dram-gates-clk",
+ sun4i_a10_dram_init);
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
index 7ae5d2c2cde1..7ba61103a6f5 100644
--- a/drivers/clk/sunxi/clk-sun8i-apb0.c
+++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
@@ -17,13 +17,77 @@
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
+static struct clk *sun8i_a23_apb0_register(struct device_node *node,
+ void __iomem *reg)
+{
+ const char *clk_name = node->name;
+ const char *clk_parent;
+ struct clk *clk;
+ int ret;
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+ if (!clk_parent)
+ return ERR_PTR(-EINVAL);
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ /* The A23 APB0 clock is a standard 2 bit wide divider clock */
+ clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
+ 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+ if (IS_ERR(clk))
+ return clk;
+
+ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (ret)
+ goto err_unregister;
+
+ return clk;
+
+err_unregister:
+ clk_unregister_divider(clk);
+
+ return ERR_PTR(ret);
+}
+
+static void sun8i_a23_apb0_setup(struct device_node *node)
+{
+ void __iomem *reg;
+ struct resource res;
+ struct clk *clk;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ /*
+ * This happens with clk nodes instantiated through mfd,
+ * as those do not have their resources assigned in the
+ * device tree. Do not print an error in this case.
+ */
+ if (PTR_ERR(reg) != -EINVAL)
+ pr_err("Could not get registers for a23-apb0-clk\n");
+
+ return;
+ }
+
+ clk = sun8i_a23_apb0_register(node, reg);
+ if (IS_ERR(clk))
+ goto err_unmap;
+
+ return;
+
+err_unmap:
+ iounmap(reg);
+ of_address_to_resource(node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+}
+CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
+ sun8i_a23_apb0_setup);
+
static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const char *clk_name = np->name;
- const char *clk_parent;
struct resource *r;
void __iomem *reg;
struct clk *clk;
@@ -33,19 +97,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
if (IS_ERR(reg))
return PTR_ERR(reg);
- clk_parent = of_clk_get_parent_name(np, 0);
- if (!clk_parent)
- return -EINVAL;
-
- of_property_read_string(np, "clock-output-names", &clk_name);
-
- /* The A23 APB0 clock is a standard 2 bit wide divider clock */
- clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
- 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+ clk = sun8i_a23_apb0_register(np, reg);
if (IS_ERR(clk))
return PTR_ERR(clk);
- return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return 0;
}
static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
diff --git a/drivers/clk/sunxi/clk-sun8i-bus-gates.c b/drivers/clk/sunxi/clk-sun8i-bus-gates.c
new file mode 100644
index 000000000000..e32d18ba252b
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun8i-bus-gates.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * Based on clk-simple-gates.c, which is:
+ * Copyright 2015 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(gates_lock);
+
+static void __init sun8i_h3_bus_gates_init(struct device_node *node)
+{
+ static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" };
+ enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent;
+ const char *parents[PARENT_MAX];
+ struct clk_onecell_data *clk_data;
+ const char *clk_name;
+ struct property *prop;
+ struct resource res;
+ void __iomem *clk_reg;
+ void __iomem *reg;
+ const __be32 *p;
+ int number, i;
+ u8 clk_bit;
+ int index;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ int idx = of_property_match_string(node, "clock-names",
+ names[i]);
+ if (idx < 0)
+ return;
+
+ parents[i] = of_clk_get_parent_name(node, idx);
+ }
+
+ clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!clk_data)
+ goto err_unmap;
+
+ number = of_property_count_u32_elems(node, "clock-indices");
+ of_property_read_u32_index(node, "clock-indices", number - 1, &number);
+
+ clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
+ if (!clk_data->clks)
+ goto err_free_data;
+
+ i = 0;
+ of_property_for_each_u32(node, "clock-indices", prop, p, index) {
+ of_property_read_string_index(node, "clock-output-names",
+ i, &clk_name);
+
+ if (index == 17 || (index >= 29 && index <= 31))
+ clk_parent = AHB2;
+ else if (index <= 63 || index >= 128)
+ clk_parent = AHB1;
+ else if (index >= 64 && index <= 95)
+ clk_parent = APB1;
+ else if (index >= 96 && index <= 127)
+ clk_parent = APB2;
+
+ clk_reg = reg + 4 * (index / 32);
+ clk_bit = index % 32;
+
+ clk_data->clks[index] = clk_register_gate(NULL, clk_name,
+ parents[clk_parent],
+ 0, clk_reg, clk_bit,
+ 0, &gates_lock);
+ i++;
+
+ if (IS_ERR(clk_data->clks[index])) {
+ WARN_ON(true);
+ continue;
+ }
+ }
+
+ clk_data->clk_num = number + 1;
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+ return;
+
+err_free_data:
+ kfree(clk_data);
+err_unmap:
+ iounmap(reg);
+ of_address_to_resource(node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+}
+
+CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk",
+ sun8i_h3_bus_gates_init);
diff --git a/drivers/clk/sunxi/clk-sun9i-cpus.c b/drivers/clk/sunxi/clk-sun9i-cpus.c
new file mode 100644
index 000000000000..7626d2194b96
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-cpus.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * Allwinner A80 CPUS clock driver
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
+
+/**
+ * sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
+ */
+
+#define SUN9I_CPUS_MAX_PARENTS 4
+#define SUN9I_CPUS_MUX_PARENT_PLL4 3
+#define SUN9I_CPUS_MUX_SHIFT 16
+#define SUN9I_CPUS_MUX_MASK GENMASK(17, 16)
+#define SUN9I_CPUS_MUX_GET_PARENT(reg) ((reg & SUN9I_CPUS_MUX_MASK) >> \
+ SUN9I_CPUS_MUX_SHIFT)
+
+#define SUN9I_CPUS_DIV_SHIFT 4
+#define SUN9I_CPUS_DIV_MASK GENMASK(5, 4)
+#define SUN9I_CPUS_DIV_GET(reg) ((reg & SUN9I_CPUS_DIV_MASK) >> \
+ SUN9I_CPUS_DIV_SHIFT)
+#define SUN9I_CPUS_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_DIV_MASK) | \
+ (div << SUN9I_CPUS_DIV_SHIFT))
+#define SUN9I_CPUS_PLL4_DIV_SHIFT 8
+#define SUN9I_CPUS_PLL4_DIV_MASK GENMASK(12, 8)
+#define SUN9I_CPUS_PLL4_DIV_GET(reg) ((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
+ SUN9I_CPUS_PLL4_DIV_SHIFT)
+#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
+ (div << SUN9I_CPUS_PLL4_DIV_SHIFT))
+
+struct sun9i_a80_cpus_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
+
+static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+ unsigned long rate;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(cpus->reg);
+
+ /* apply pre-divider first if parent is pll4 */
+ if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
+ parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
+
+ /* clk divider */
+ rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
+
+ return rate;
+}
+
+static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+ u8 parent, unsigned long parent_rate)
+{
+ u8 div, pre_div = 1;
+
+ /*
+ * clock can only divide, so we will never be able to achieve
+ * frequencies higher than the parent frequency
+ */
+ if (parent_rate && rate > parent_rate)
+ rate = parent_rate;
+
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /* calculate pre-divider if parent is pll4 */
+ if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
+ /* pre-divider is 1 ~ 32 */
+ if (div < 32) {
+ pre_div = div;
+ div = 1;
+ } else if (div < 64) {
+ pre_div = DIV_ROUND_UP(div, 2);
+ div = 2;
+ } else if (div < 96) {
+ pre_div = DIV_ROUND_UP(div, 3);
+ div = 3;
+ } else {
+ pre_div = DIV_ROUND_UP(div, 4);
+ div = 4;
+ }
+ }
+
+ /* we were asked to pass back divider values */
+ if (divp) {
+ *divp = div - 1;
+ *pre_divp = pre_div - 1;
+ }
+
+ return parent_rate / pre_div / div;
+}
+
+static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
+ struct clk_rate_request *req)
+{
+ struct clk_hw *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+ unsigned long rate = req->rate;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = clk_hw_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_hw_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = clk_hw_round_rate(parent, rate);
+ else
+ parent_rate = clk_hw_get_rate(parent);
+
+ child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
+ parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (!best_parent)
+ return -EINVAL;
+
+ req->best_parent_hw = best_parent;
+ req->best_parent_rate = best;
+ req->rate = best_child_rate;
+
+ return 0;
+}
+
+static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+ unsigned long flags;
+ u8 div, pre_div, parent;
+ u32 reg;
+
+ spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
+
+ reg = readl(cpus->reg);
+
+ /* need to know which parent is used to apply pre-divider */
+ parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
+ sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+ reg = SUN9I_CPUS_DIV_SET(reg, div);
+ reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
+ writel(reg, cpus->reg);
+
+ spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops sun9i_a80_cpus_clk_ops = {
+ .determine_rate = sun9i_a80_cpus_clk_determine_rate,
+ .recalc_rate = sun9i_a80_cpus_clk_recalc_rate,
+ .set_rate = sun9i_a80_cpus_clk_set_rate,
+};
+
+static void sun9i_a80_cpus_setup(struct device_node *node)
+{
+ const char *clk_name = node->name;
+ const char *parents[SUN9I_CPUS_MAX_PARENTS];
+ struct resource res;
+ struct sun9i_a80_cpus_clk *cpus;
+ struct clk_mux *mux;
+ struct clk *clk;
+ int ret;
+
+ cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
+ if (!cpus)
+ return;
+
+ cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(cpus->reg))
+ goto err_free_cpus;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ /* we have a mux, we will have >1 parents */
+ ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ goto err_unmap;
+
+ /* set up clock properties */
+ mux->reg = cpus->reg;
+ mux->shift = SUN9I_CPUS_MUX_SHIFT;
+ /* un-shifted mask is what mux_clk expects */
+ mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
+ mux->lock = &sun9i_a80_cpus_lock;
+
+ clk = clk_register_composite(NULL, clk_name, parents, ret,
+ &mux->hw, &clk_mux_ops,
+ &cpus->hw, &sun9i_a80_cpus_clk_ops,
+ NULL, NULL, 0);
+ if (IS_ERR(clk))
+ goto err_free_mux;
+
+ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (ret)
+ goto err_unregister;
+
+ return;
+
+err_unregister:
+ clk_unregister(clk);
+err_free_mux:
+ kfree(mux);
+err_unmap:
+ iounmap(cpus->reg);
+ of_address_to_resource(node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+err_free_cpus:
+ kfree(cpus);
+}
+CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
+ sun9i_a80_cpus_setup);
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 9c79af0c03b2..5ba2188ee99c 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -778,6 +778,10 @@ static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = {
.shift = 12,
};
+static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = {
+ .shift = 0,
+};
+
static void __init sunxi_mux_clk_setup(struct device_node *node,
struct mux_data *data)
{
@@ -1130,6 +1134,7 @@ static const struct of_device_id clk_divs_match[] __initconst = {
static const struct of_device_id clk_mux_match[] __initconst = {
{.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
{.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
+ {.compatible = "allwinner,sun8i-h3-ahb2-clk", .data = &sun8i_h3_ahb2_mux_data,},
{}
};
@@ -1212,6 +1217,7 @@ CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks);
+CLK_OF_DECLARE(sun8i_h3_clk_init, "allwinner,sun8i-h3", sun6i_init_clocks);
static void __init sun9i_init_clocks(struct device_node *node)
{
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
index 1a72cd672839..67b8e38f4ee9 100644
--- a/drivers/clk/sunxi/clk-usb.c
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -243,3 +243,15 @@ static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
}
CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
+
+static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
+ .clk_mask = BIT(19) | BIT(18) | BIT(17) | BIT(16) |
+ BIT(11) | BIT(10) | BIT(9) | BIT(8),
+ .reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+};
+
+static void __init sun8i_h3_usb_setup(struct device_node *node)
+{
+ sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
+}
+CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index 826c325dc2e8..97984c503bbb 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124-dfll-fcpu.o
obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
obj-y += cvb.o
+obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 48c83efda4cf..16e0aee14773 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -32,7 +32,7 @@
static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
unsigned long parent_rate)
{
- s64 divider_ux1 = parent_rate;
+ u64 divider_ux1 = parent_rate;
u8 flags = divider->flags;
int mul;
@@ -54,7 +54,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
divider_ux1 -= mul;
- if (divider_ux1 < 0)
+ if ((s64)divider_ux1 < 0)
return 0;
if (divider_ux1 > get_max_div(divider))
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 60738cc954cb..19ce0738ee76 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -13,6 +13,7 @@ enum clk_id {
tegra_clk_amx1,
tegra_clk_apbdma,
tegra_clk_apbif,
+ tegra_clk_ape,
tegra_clk_audio0,
tegra_clk_audio0_2x,
tegra_clk_audio0_mux,
@@ -38,6 +39,7 @@ enum clk_id {
tegra_clk_cile,
tegra_clk_clk_32k,
tegra_clk_clk72Mhz,
+ tegra_clk_clk72Mhz_8,
tegra_clk_clk_m,
tegra_clk_clk_m_div2,
tegra_clk_clk_m_div4,
@@ -51,17 +53,21 @@ enum clk_id {
tegra_clk_cml1,
tegra_clk_csi,
tegra_clk_csite,
+ tegra_clk_csite_8,
tegra_clk_csus,
tegra_clk_cve,
tegra_clk_dam0,
tegra_clk_dam1,
tegra_clk_dam2,
tegra_clk_d_audio,
+ tegra_clk_dbgapb,
tegra_clk_dds,
tegra_clk_dfll_ref,
tegra_clk_dfll_soc,
tegra_clk_disp1,
+ tegra_clk_disp1_8,
tegra_clk_disp2,
+ tegra_clk_disp2_8,
tegra_clk_dp2,
tegra_clk_dpaux,
tegra_clk_dsialp,
@@ -71,6 +77,7 @@ enum clk_id {
tegra_clk_dtv,
tegra_clk_emc,
tegra_clk_entropy,
+ tegra_clk_entropy_8,
tegra_clk_epp,
tegra_clk_epp_8,
tegra_clk_extern1,
@@ -85,12 +92,16 @@ enum clk_id {
tegra_clk_gr3d_8,
tegra_clk_hclk,
tegra_clk_hda,
+ tegra_clk_hda_8,
tegra_clk_hda2codec_2x,
+ tegra_clk_hda2codec_2x_8,
tegra_clk_hda2hdmi,
tegra_clk_hdmi,
tegra_clk_hdmi_audio,
tegra_clk_host1x,
tegra_clk_host1x_8,
+ tegra_clk_host1x_9,
+ tegra_clk_hsic_trk,
tegra_clk_i2c1,
tegra_clk_i2c2,
tegra_clk_i2c3,
@@ -110,11 +121,14 @@ enum clk_id {
tegra_clk_i2s4_sync,
tegra_clk_isp,
tegra_clk_isp_8,
+ tegra_clk_isp_9,
tegra_clk_ispb,
tegra_clk_kbc,
tegra_clk_kfuse,
tegra_clk_la,
+ tegra_clk_maud,
tegra_clk_mipi,
+ tegra_clk_mipibif,
tegra_clk_mipi_cal,
tegra_clk_mpe,
tegra_clk_mselect,
@@ -124,15 +138,24 @@ enum clk_id {
tegra_clk_ndspeed,
tegra_clk_ndspeed_8,
tegra_clk_nor,
+ tegra_clk_nvdec,
+ tegra_clk_nvenc,
+ tegra_clk_nvjpg,
tegra_clk_owr,
+ tegra_clk_owr_8,
tegra_clk_pcie,
tegra_clk_pclk,
tegra_clk_pll_a,
tegra_clk_pll_a_out0,
+ tegra_clk_pll_a1,
tegra_clk_pll_c,
tegra_clk_pll_c2,
tegra_clk_pll_c3,
tegra_clk_pll_c4,
+ tegra_clk_pll_c4_out0,
+ tegra_clk_pll_c4_out1,
+ tegra_clk_pll_c4_out2,
+ tegra_clk_pll_c4_out3,
tegra_clk_pll_c_out1,
tegra_clk_pll_d,
tegra_clk_pll_d2,
@@ -140,19 +163,29 @@ enum clk_id {
tegra_clk_pll_d_out0,
tegra_clk_pll_dp,
tegra_clk_pll_e_out0,
+ tegra_clk_pll_g_ref,
tegra_clk_pll_m,
tegra_clk_pll_m_out1,
+ tegra_clk_pll_mb,
tegra_clk_pll_p,
tegra_clk_pll_p_out1,
tegra_clk_pll_p_out2,
tegra_clk_pll_p_out2_int,
tegra_clk_pll_p_out3,
tegra_clk_pll_p_out4,
+ tegra_clk_pll_p_out4_cpu,
tegra_clk_pll_p_out5,
+ tegra_clk_pll_p_out_hsio,
+ tegra_clk_pll_p_out_xusb,
+ tegra_clk_pll_p_out_cpu,
+ tegra_clk_pll_p_out_adsp,
tegra_clk_pll_ref,
tegra_clk_pll_re_out,
tegra_clk_pll_re_vco,
tegra_clk_pll_u,
+ tegra_clk_pll_u_out,
+ tegra_clk_pll_u_out1,
+ tegra_clk_pll_u_out2,
tegra_clk_pll_u_12m,
tegra_clk_pll_u_480m,
tegra_clk_pll_u_48m,
@@ -160,53 +193,80 @@ enum clk_id {
tegra_clk_pll_x,
tegra_clk_pll_x_out0,
tegra_clk_pwm,
+ tegra_clk_qspi,
tegra_clk_rtc,
tegra_clk_sata,
+ tegra_clk_sata_8,
tegra_clk_sata_cold,
tegra_clk_sata_oob,
+ tegra_clk_sata_oob_8,
tegra_clk_sbc1,
tegra_clk_sbc1_8,
+ tegra_clk_sbc1_9,
tegra_clk_sbc2,
tegra_clk_sbc2_8,
+ tegra_clk_sbc2_9,
tegra_clk_sbc3,
tegra_clk_sbc3_8,
+ tegra_clk_sbc3_9,
tegra_clk_sbc4,
tegra_clk_sbc4_8,
+ tegra_clk_sbc4_9,
tegra_clk_sbc5,
tegra_clk_sbc5_8,
tegra_clk_sbc6,
tegra_clk_sbc6_8,
tegra_clk_sclk,
+ tegra_clk_sdmmc_legacy,
tegra_clk_sdmmc1,
tegra_clk_sdmmc1_8,
+ tegra_clk_sdmmc1_9,
tegra_clk_sdmmc2,
tegra_clk_sdmmc2_8,
+ tegra_clk_sdmmc2_9,
tegra_clk_sdmmc3,
tegra_clk_sdmmc3_8,
+ tegra_clk_sdmmc3_9,
tegra_clk_sdmmc4,
tegra_clk_sdmmc4_8,
+ tegra_clk_sdmmc4_9,
tegra_clk_se,
tegra_clk_soc_therm,
+ tegra_clk_soc_therm_8,
tegra_clk_sor0,
tegra_clk_sor0_lvds,
+ tegra_clk_sor1,
+ tegra_clk_sor1_brick,
+ tegra_clk_sor1_src,
tegra_clk_spdif,
tegra_clk_spdif_2x,
tegra_clk_spdif_in,
+ tegra_clk_spdif_in_8,
tegra_clk_spdif_in_sync,
tegra_clk_spdif_mux,
tegra_clk_spdif_out,
tegra_clk_timer,
tegra_clk_trace,
tegra_clk_tsec,
+ tegra_clk_tsec_8,
+ tegra_clk_tsecb,
tegra_clk_tsensor,
tegra_clk_tvdac,
tegra_clk_tvo,
tegra_clk_uarta,
+ tegra_clk_uarta_8,
tegra_clk_uartb,
+ tegra_clk_uartb_8,
tegra_clk_uartc,
+ tegra_clk_uartc_8,
tegra_clk_uartd,
+ tegra_clk_uartd_8,
tegra_clk_uarte,
+ tegra_clk_uarte_8,
+ tegra_clk_uartape,
tegra_clk_usb2,
+ tegra_clk_usb2_hsic_trk,
+ tegra_clk_usb2_trk,
tegra_clk_usb3,
tegra_clk_usbd,
tegra_clk_vcp,
@@ -216,22 +276,35 @@ enum clk_id {
tegra_clk_vi,
tegra_clk_vi_8,
tegra_clk_vi_9,
+ tegra_clk_vi_10,
+ tegra_clk_vi_i2c,
tegra_clk_vic03,
+ tegra_clk_vic03_8,
tegra_clk_vim2_clk,
tegra_clk_vimclk_sync,
tegra_clk_vi_sensor,
- tegra_clk_vi_sensor2,
tegra_clk_vi_sensor_8,
+ tegra_clk_vi_sensor_9,
+ tegra_clk_vi_sensor2,
+ tegra_clk_vi_sensor2_8,
tegra_clk_xusb_dev,
tegra_clk_xusb_dev_src,
+ tegra_clk_xusb_dev_src_8,
tegra_clk_xusb_falcon_src,
+ tegra_clk_xusb_falcon_src_8,
tegra_clk_xusb_fs_src,
+ tegra_clk_xusb_gate,
tegra_clk_xusb_host,
tegra_clk_xusb_host_src,
+ tegra_clk_xusb_host_src_8,
tegra_clk_xusb_hs_src,
+ tegra_clk_xusb_hs_src_4,
tegra_clk_xusb_ss,
tegra_clk_xusb_ss_src,
+ tegra_clk_xusb_ss_src_8,
tegra_clk_xusb_ss_div2,
+ tegra_clk_xusb_ssp_src,
+ tegra_clk_sclk_mux,
tegra_clk_max,
};
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index d6d4ecb88e94..a534bfab30b3 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -65,6 +65,7 @@
#define PLLE_BASE_DIVN_WIDTH 8
#define PLLE_BASE_DIVM_SHIFT 0
#define PLLE_BASE_DIVM_WIDTH 8
+#define PLLE_BASE_ENABLE BIT(31)
#define PLLE_MISC_SETUP_BASE_SHIFT 16
#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
@@ -102,6 +103,7 @@
#define PLLE_AUX_SEQ_ENABLE BIT(24)
#define PLLE_AUX_SEQ_START_STATE BIT(25)
#define PLLE_AUX_PLLRE_SEL BIT(28)
+#define PLLE_AUX_SS_SEQ_INCLUDE BIT(31)
#define XUSBIO_PLL_CFG0 0x51c
#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0)
@@ -187,17 +189,23 @@
#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
+#define pll_readl_sdm_din(p) pll_readl(p->params->sdm_din_reg, p)
+#define pll_readl_sdm_ctrl(p) pll_readl(p->params->sdm_ctrl_reg, p)
#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
+#define pll_writel_sdm_din(val, p) pll_writel(val, p->params->sdm_din_reg, p)
+#define pll_writel_sdm_ctrl(val, p) pll_writel(val, p->params->sdm_ctrl_reg, p)
#define mask(w) ((1 << (w)) - 1)
#define divm_mask(p) mask(p->params->div_nmp->divm_width)
#define divn_mask(p) mask(p->params->div_nmp->divn_width)
#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
mask(p->params->div_nmp->divp_width))
+#define sdm_din_mask(p) p->params->sdm_din_mask
+#define sdm_en_mask(p) p->params->sdm_ctrl_en_mask
#define divm_shift(p) (p)->params->div_nmp->divm_shift
#define divn_shift(p) (p)->params->div_nmp->divn_shift
@@ -211,6 +219,9 @@
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))
+#define sdin_din_to_data(din) ((u16)((din) ? : 0xFFFFU))
+#define sdin_data_to_din(dat) (((dat) == 0xFFFFU) ? 0 : (s16)dat)
+
static struct div_nmp default_nmp = {
.divn_shift = PLL_BASE_DIVN_SHIFT,
.divn_width = PLL_BASE_DIVN_WIDTH,
@@ -269,6 +280,11 @@ static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll)
return -1;
}
+int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll)
+{
+ return clk_pll_wait_for_lock(pll);
+}
+
static int clk_pll_is_enabled(struct clk_hw *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
@@ -290,6 +306,19 @@ static void _clk_pll_enable(struct clk_hw *hw)
struct tegra_clk_pll *pll = to_clk_pll(hw);
u32 val;
+ if (pll->params->iddq_reg) {
+ val = pll_readl(pll->params->iddq_reg, pll);
+ val &= ~BIT(pll->params->iddq_bit_idx);
+ pll_writel(val, pll->params->iddq_reg, pll);
+ udelay(2);
+ }
+
+ if (pll->params->reset_reg) {
+ val = pll_readl(pll->params->reset_reg, pll);
+ val &= ~BIT(pll->params->reset_bit_idx);
+ pll_writel(val, pll->params->reset_reg, pll);
+ }
+
clk_pll_enable_lock(pll);
val = pll_readl_base(pll);
@@ -321,6 +350,19 @@ static void _clk_pll_disable(struct clk_hw *hw)
val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
}
+
+ if (pll->params->reset_reg) {
+ val = pll_readl(pll->params->reset_reg, pll);
+ val |= BIT(pll->params->reset_bit_idx);
+ pll_writel(val, pll->params->reset_reg, pll);
+ }
+
+ if (pll->params->iddq_reg) {
+ val = pll_readl(pll->params->iddq_reg, pll);
+ val |= BIT(pll->params->iddq_bit_idx);
+ pll_writel(val, pll->params->iddq_reg, pll);
+ udelay(2);
+ }
}
static int clk_pll_enable(struct clk_hw *hw)
@@ -359,7 +401,7 @@ static void clk_pll_disable(struct clk_hw *hw)
static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+ const struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
if (p_tohw) {
while (p_tohw->pdiv) {
@@ -372,10 +414,15 @@ static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
return -EINVAL;
}
+int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div)
+{
+ return _p_div_to_hw(&pll->hw, p_div);
+}
+
static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+ const struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
if (p_tohw) {
while (p_tohw->pdiv) {
@@ -395,6 +442,7 @@ static int _get_table_rate(struct clk_hw *hw,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table *sel;
+ int p;
for (sel = pll->params->freq_table; sel->input_rate != 0; sel++)
if (sel->input_rate == parent_rate &&
@@ -404,12 +452,21 @@ static int _get_table_rate(struct clk_hw *hw,
if (sel->input_rate == 0)
return -EINVAL;
+ if (pll->params->pdiv_tohw) {
+ p = _p_div_to_hw(hw, sel->p);
+ if (p < 0)
+ return p;
+ } else {
+ p = ilog2(sel->p);
+ }
+
cfg->input_rate = sel->input_rate;
cfg->output_rate = sel->output_rate;
cfg->m = sel->m;
cfg->n = sel->n;
- cfg->p = sel->p;
+ cfg->p = p;
cfg->cpcon = sel->cpcon;
+ cfg->sdm_data = sel->sdm_data;
return 0;
}
@@ -439,7 +496,7 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
/*
* PLL_P_OUT1 rate is not listed in PLLA table
*/
- cfreq = parent_rate/(parent_rate/1000000);
+ cfreq = parent_rate / (parent_rate / 1000000);
break;
default:
pr_err("%s Unexpected reference rate %lu\n",
@@ -476,6 +533,42 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
return 0;
}
+/*
+ * SDM (Sigma Delta Modulator) divisor is 16-bit 2's complement signed number
+ * within (-2^12 ... 2^12-1) range. Represented in PLL data structure as
+ * unsigned 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used
+ * to indicate that SDM is disabled.
+ *
+ * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13
+ */
+static void clk_pll_set_sdm_data(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+ bool enabled;
+
+ if (!pll->params->sdm_din_reg)
+ return;
+
+ if (cfg->sdm_data) {
+ val = pll_readl_sdm_din(pll) & (~sdm_din_mask(pll));
+ val |= sdin_data_to_din(cfg->sdm_data) & sdm_din_mask(pll);
+ pll_writel_sdm_din(val, pll);
+ }
+
+ val = pll_readl_sdm_ctrl(pll);
+ enabled = (val & sdm_en_mask(pll));
+
+ if (cfg->sdm_data == 0 && enabled)
+ val &= ~pll->params->sdm_ctrl_en_mask;
+
+ if (cfg->sdm_data != 0 && !enabled)
+ val |= pll->params->sdm_ctrl_en_mask;
+
+ pll_writel_sdm_ctrl(val, pll);
+}
+
static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
@@ -483,7 +576,7 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_params *params = pll->params;
struct div_nmp *div_nmp = params->div_nmp;
- if ((params->flags & TEGRA_PLLM) &&
+ if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
val = pll_override_readl(params->pmc_divp_reg, pll);
@@ -508,6 +601,8 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
(cfg->p << divp_shift(pll));
pll_writel_base(val, pll);
+
+ clk_pll_set_sdm_data(&pll->hw, cfg);
}
}
@@ -518,7 +613,7 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_params *params = pll->params;
struct div_nmp *div_nmp = params->div_nmp;
- if ((params->flags & TEGRA_PLLM) &&
+ if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
val = pll_override_readl(params->pmc_divp_reg, pll);
@@ -533,6 +628,14 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll,
cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
+
+ if (pll->params->sdm_din_reg) {
+ if (sdm_en_mask(pll) & pll_readl_sdm_ctrl(pll)) {
+ val = pll_readl_sdm_din(pll);
+ val &= sdm_din_mask(pll);
+ cfg->sdm_data = sdin_din_to_data(val);
+ }
+ }
}
}
@@ -560,16 +663,51 @@ static void _update_pll_cpcon(struct tegra_clk_pll *pll,
pll_writel_misc(val, pll);
}
+static void pll_clk_start_ss(struct tegra_clk_pll *pll)
+{
+ if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) {
+ u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
+
+ val |= pll->params->ssc_ctrl_en_mask;
+ pll_writel(val, pll->params->ssc_ctrl_reg, pll);
+ }
+}
+
+static void pll_clk_stop_ss(struct tegra_clk_pll *pll)
+{
+ if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) {
+ u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
+
+ val &= ~pll->params->ssc_ctrl_en_mask;
+ pll_writel(val, pll->params->ssc_ctrl_reg, pll);
+ }
+}
+
static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
unsigned long rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table old_cfg;
int state, ret = 0;
state = clk_pll_is_enabled(hw);
- if (state)
+ _get_pll_mnp(pll, &old_cfg);
+
+ if (state && pll->params->defaults_set && pll->params->dyn_ramp &&
+ (cfg->m == old_cfg.m) && (cfg->p == old_cfg.p)) {
+ ret = pll->params->dyn_ramp(pll, cfg);
+ if (!ret)
+ return 0;
+ }
+
+ if (state) {
+ pll_clk_stop_ss(pll);
_clk_pll_disable(hw);
+ }
+
+ if (!pll->params->defaults_set && pll->params->set_defaults)
+ pll->params->set_defaults(pll);
_update_pll_mnp(pll, cfg);
@@ -579,6 +717,7 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
if (state) {
_clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll);
+ pll_clk_start_ss(pll);
}
return ret;
@@ -603,7 +742,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}
if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
- _calc_rate(hw, &cfg, rate, parent_rate)) {
+ pll->params->calc_rate(hw, &cfg, rate, parent_rate)) {
pr_err("%s: Failed to set %s rate %lu\n", __func__,
clk_hw_get_name(hw), rate);
WARN_ON(1);
@@ -613,8 +752,11 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
spin_lock_irqsave(pll->lock, flags);
_get_pll_mnp(pll, &old_cfg);
+ if (pll->params->flags & TEGRA_PLL_VCO_OUT)
+ cfg.p = old_cfg.p;
- if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
+ if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p ||
+ old_cfg.sdm_data != cfg.sdm_data)
ret = _program_pll(hw, &cfg, rate);
if (pll->lock)
@@ -629,15 +771,15 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
- if (pll->params->flags & TEGRA_PLL_FIXED)
+ if (pll->params->flags & TEGRA_PLL_FIXED) {
+ /* PLLM/MB are used for memory; we do not change rate */
+ if (pll->params->flags & (TEGRA_PLLM | TEGRA_PLLMB))
+ return clk_hw_get_rate(hw);
return pll->params->fixed_rate;
-
- /* PLLM is used for memory; we do not change rate */
- if (pll->params->flags & TEGRA_PLLM)
- return clk_hw_get_rate(hw);
+ }
if (_get_table_rate(hw, &cfg, rate, *prate) &&
- _calc_rate(hw, &cfg, rate, *prate))
+ pll->params->calc_rate(hw, &cfg, rate, *prate))
return -EINVAL;
return cfg.output_rate;
@@ -658,6 +800,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
return parent_rate;
if ((pll->params->flags & TEGRA_PLL_FIXED) &&
+ !(pll->params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
!(val & PLL_BASE_OVERRIDE)) {
struct tegra_clk_pll_freq_table sel;
if (_get_table_rate(hw, &sel, pll->params->fixed_rate,
@@ -671,12 +814,20 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
_get_pll_mnp(pll, &cfg);
- pdiv = _hw_to_p_div(hw, cfg.p);
- if (pdiv < 0) {
- WARN_ON(1);
+ if (pll->params->flags & TEGRA_PLL_VCO_OUT) {
pdiv = 1;
+ } else {
+ pdiv = _hw_to_p_div(hw, cfg.p);
+ if (pdiv < 0) {
+ WARN(1, "Clock %s has invalid pdiv value : 0x%x\n",
+ clk_hw_get_name(hw), cfg.p);
+ pdiv = 1;
+ }
}
+ if (pll->params->set_gain)
+ pll->params->set_gain(&cfg);
+
cfg.m *= pdiv;
rate *= cfg.n;
@@ -816,19 +967,65 @@ const struct clk_ops tegra_clk_plle_ops = {
.enable = clk_plle_enable,
};
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
- defined(CONFIG_ARCH_TEGRA_124_SOC) || \
- defined(CONFIG_ARCH_TEGRA_132_SOC)
-
static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
{
+ u16 mdiv = parent_rate / pll_params->cf_min;
+
+ if (pll_params->flags & TEGRA_MDIV_NEW)
+ return (!pll_params->mdiv_default ? mdiv :
+ min(mdiv, pll_params->mdiv_default));
+
+ if (pll_params->mdiv_default)
+ return pll_params->mdiv_default;
+
if (parent_rate > pll_params->cf_max)
return 2;
else
return 1;
}
+static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned int p;
+ int p_div;
+
+ if (!rate)
+ return -EINVAL;
+
+ p = DIV_ROUND_UP(pll->params->vco_min, rate);
+ cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
+ cfg->output_rate = rate * p;
+ cfg->n = cfg->output_rate * cfg->m / parent_rate;
+ cfg->input_rate = parent_rate;
+
+ p_div = _p_div_to_hw(hw, p);
+ if (p_div < 0)
+ return p_div;
+
+ cfg->p = p_div;
+
+ if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
+ return -EINVAL;
+
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)
+
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+ return (u16)_pll_fixed_mdiv(pll->params, input_rate);
+}
+
static unsigned long _clip_vco_min(unsigned long vco_min,
unsigned long parent_rate)
{
@@ -871,86 +1068,12 @@ static int _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params,
return 0;
}
-static int clk_pll_iddq_enable(struct clk_hw *hw)
-{
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long flags = 0;
-
- u32 val;
- int ret;
-
- if (pll->lock)
- spin_lock_irqsave(pll->lock, flags);
-
- val = pll_readl(pll->params->iddq_reg, pll);
- val &= ~BIT(pll->params->iddq_bit_idx);
- pll_writel(val, pll->params->iddq_reg, pll);
- udelay(2);
-
- _clk_pll_enable(hw);
-
- ret = clk_pll_wait_for_lock(pll);
-
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
-
- return 0;
-}
-
-static void clk_pll_iddq_disable(struct clk_hw *hw)
-{
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long flags = 0;
- u32 val;
-
- if (pll->lock)
- spin_lock_irqsave(pll->lock, flags);
-
- _clk_pll_disable(hw);
-
- val = pll_readl(pll->params->iddq_reg, pll);
- val |= BIT(pll->params->iddq_bit_idx);
- pll_writel(val, pll->params->iddq_reg, pll);
- udelay(2);
-
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
-}
-
-static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
- struct tegra_clk_pll_freq_table *cfg,
- unsigned long rate, unsigned long parent_rate)
-{
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned int p;
- int p_div;
-
- if (!rate)
- return -EINVAL;
-
- p = DIV_ROUND_UP(pll->params->vco_min, rate);
- cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
- cfg->output_rate = rate * p;
- cfg->n = cfg->output_rate * cfg->m / parent_rate;
-
- p_div = _p_div_to_hw(hw, p);
- if (p_div < 0)
- return p_div;
- else
- cfg->p = p_div;
-
- if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
- return -EINVAL;
-
- return 0;
-}
-
static int _pll_ramp_calc_pll(struct clk_hw *hw,
struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- int err = 0, p_div;
+ int err = 0;
err = _get_table_rate(hw, cfg, rate, parent_rate);
if (err < 0)
@@ -961,11 +1084,6 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,
err = -EINVAL;
goto out;
}
- p_div = _p_div_to_hw(hw, cfg->p);
- if (p_div < 0)
- return p_div;
- else
- cfg->p = p_div;
}
if (cfg->p > pll->params->max_p)
@@ -991,6 +1109,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
spin_lock_irqsave(pll->lock, flags);
_get_pll_mnp(pll, &old_cfg);
+ if (pll->params->flags & TEGRA_PLL_VCO_OUT)
+ cfg.p = old_cfg.p;
if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
ret = _program_pll(hw, &cfg, rate);
@@ -1004,6 +1124,7 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
int ret, p_div;
u64 output_rate = *prate;
@@ -1016,46 +1137,15 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
if (p_div < 0)
return p_div;
+ if (pll->params->set_gain)
+ pll->params->set_gain(&cfg);
+
output_rate *= cfg.n;
do_div(output_rate, cfg.m * p_div);
return output_rate;
}
-static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct tegra_clk_pll_freq_table cfg;
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long flags = 0;
- int state, ret = 0;
-
- if (pll->lock)
- spin_lock_irqsave(pll->lock, flags);
-
- state = clk_pll_is_enabled(hw);
- if (state) {
- if (rate != clk_get_rate(hw->clk)) {
- pr_err("%s: Cannot change active PLLM\n", __func__);
- ret = -EINVAL;
- goto out;
- }
- goto out;
- }
-
- ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
- if (ret < 0)
- goto out;
-
- _update_pll_mnp(pll, &cfg);
-
-out:
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
-
- return ret;
-}
-
static void _pllcx_strobe(struct tegra_clk_pll *pll)
{
u32 val;
@@ -1445,6 +1535,17 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
+ /* Default to _calc_rate if unspecified */
+ if (!pll->params->calc_rate) {
+ if (pll->params->flags & TEGRA_PLLM)
+ pll->params->calc_rate = _calc_dynamic_ramp_rate;
+ else
+ pll->params->calc_rate = _calc_rate;
+ }
+
+ if (pll->params->set_defaults)
+ pll->params->set_defaults(pll);
+
/* Data in .init is copied by clk_register(), so stack variable OK */
pll->hw.init = &init;
@@ -1460,7 +1561,7 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
struct clk *clk;
pll_params->flags |= TEGRA_PLL_BYPASS;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1490,8 +1591,7 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk;
- pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll_params->flags |= TEGRA_PLL_BYPASS;
if (!pll_params->div_nmp)
pll_params->div_nmp = &pll_e_nmp;
@@ -1510,25 +1610,17 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
- defined(CONFIG_ARCH_TEGRA_132_SOC)
+ defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)
static const struct clk_ops tegra_clk_pllxc_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllxc_set_rate,
};
-static const struct clk_ops tegra_clk_pllm_ops = {
- .is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
- .recalc_rate = clk_pll_recalc_rate,
- .round_rate = clk_pll_ramp_round_rate,
- .set_rate = clk_pllm_set_rate,
-};
-
static const struct clk_ops tegra_clk_pllc_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pllc_enable,
@@ -1540,8 +1632,8 @@ static const struct clk_ops tegra_clk_pllc_ops = {
static const struct clk_ops tegra_clk_pllre_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pllre_recalc_rate,
.round_rate = clk_pllre_round_rate,
.set_rate = clk_pllre_set_rate,
@@ -1564,7 +1656,6 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk, *parent;
unsigned long parent_rate;
- int err;
u32 val, val_iddq;
parent = __clk_lookup(parent_name);
@@ -1581,21 +1672,33 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
- err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
- if (err)
- return ERR_PTR(err);
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
- val = readl_relaxed(clk_base + pll_params->base_reg);
- val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+ /*
+ * If the pll has a set_defaults callback, it will take care of
+ * configuring dynamic ramping and setting IDDQ in that path.
+ */
+ if (!pll_params->set_defaults) {
+ int err;
- if (val & PLL_BASE_ENABLE)
- WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
- else {
- val_iddq |= BIT(pll_params->iddq_bit_idx);
- writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
+ err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
+ if (err)
+ return ERR_PTR(err);
+
+ val = readl_relaxed(clk_base + pll_params->base_reg);
+ val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+
+ if (val & PLL_BASE_ENABLE)
+ WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
+ else {
+ val_iddq |= BIT(pll_params->iddq_bit_idx);
+ writel_relaxed(val_iddq,
+ clk_base + pll_params->iddq_reg);
+ }
}
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1618,10 +1721,12 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;
-
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1630,7 +1735,8 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
val = pll_readl_base(pll);
if (val & PLL_BASE_ENABLE)
- WARN_ON(val & pll_params->iddq_bit_idx);
+ WARN_ON(readl_relaxed(clk_base + pll_params->iddq_reg) &
+ BIT(pll_params->iddq_bit_idx));
else {
int m;
@@ -1678,15 +1784,18 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll_params->flags |= TEGRA_PLL_BYPASS;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll_params->flags |= TEGRA_PLLM;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
- &tegra_clk_pllm_ops);
+ &tegra_clk_pll_ops);
if (IS_ERR(clk))
kfree(pll);
@@ -1700,7 +1809,7 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
spinlock_t *lock)
{
struct clk *parent, *clk;
- struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
+ const struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
struct tegra_clk_pll *pll;
struct tegra_clk_pll_freq_table cfg;
unsigned long parent_rate;
@@ -1777,7 +1886,6 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
struct clk *clk;
u32 val, val_aux;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1810,8 +1918,8 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllss_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllxc_set_rate,
@@ -1826,7 +1934,7 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
struct clk *clk, *parent;
struct tegra_clk_pll_freq_table cfg;
unsigned long parent_rate;
- u32 val;
+ u32 val, val_iddq;
int i;
if (!pll_params->div_nmp)
@@ -1839,7 +1947,6 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
return ERR_PTR(-EINVAL);
}
- pll_params->flags = TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_USE_LOCK;
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1874,6 +1981,337 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
pll_writel(PLLSS_CTRL1_DEFAULT, pll_params->ext_misc_reg[2], pll);
val = pll_readl_base(pll);
+ val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+ if (val & PLL_BASE_ENABLE) {
+ if (val_iddq & BIT(pll_params->iddq_bit_idx)) {
+ WARN(1, "%s is on but IDDQ set\n", name);
+ kfree(pll);
+ return ERR_PTR(-EINVAL);
+ }
+ } else {
+ val_iddq |= BIT(pll_params->iddq_bit_idx);
+ writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
+ }
+
+ val &= ~PLLSS_LOCK_OVERRIDE;
+ pll_writel_base(val, pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pllss_ops);
+
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_210_SOC)
+static int clk_plle_tegra210_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table sel;
+ u32 val;
+ int ret;
+ unsigned long flags = 0;
+ unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+
+ if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
+ return -EINVAL;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ val = pll_readl_base(pll);
+ val &= ~BIT(30); /* Disable lock override */
+ pll_writel_base(val, pll);
+
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= PLLE_AUX_ENABLE_SWCTL;
+ val &= ~PLLE_AUX_SEQ_ENABLE;
+ pll_writel(val, pll->params->aux_reg, pll);
+ udelay(1);
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_LOCK_ENABLE;
+ val |= PLLE_MISC_IDDQ_SW_CTRL;
+ val &= ~PLLE_MISC_IDDQ_SW_VALUE;
+ val |= PLLE_MISC_PLLE_PTS;
+ val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+ pll_writel_misc(val, pll);
+ udelay(5);
+
+ val = pll_readl(PLLE_SS_CTRL, pll);
+ val |= PLLE_SS_DISABLE;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+
+ val = pll_readl_base(pll);
+ val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) |
+ divm_mask_shifted(pll));
+ val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT);
+ val |= sel.m << divm_shift(pll);
+ val |= sel.n << divn_shift(pll);
+ val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
+ pll_writel_base(val, pll);
+ udelay(1);
+
+ val = pll_readl_base(pll);
+ val |= PLLE_BASE_ENABLE;
+ pll_writel_base(val, pll);
+
+ ret = clk_pll_wait_for_lock(pll);
+
+ if (ret < 0)
+ goto out;
+
+ val = pll_readl(PLLE_SS_CTRL, pll);
+ val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
+ val &= ~PLLE_SS_COEFFICIENTS_MASK;
+ val |= PLLE_SS_COEFFICIENTS_VAL;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+ val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
+ pll_writel(val, PLLE_SS_CTRL, pll);
+ udelay(1);
+ val &= ~PLLE_SS_CNTL_INTERP_RESET;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+ udelay(1);
+
+ val = pll_readl_misc(pll);
+ val &= ~PLLE_MISC_IDDQ_SW_CTRL;
+ pll_writel_misc(val, pll);
+
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE);
+ val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
+ pll_writel(val, pll->params->aux_reg, pll);
+ udelay(1);
+ val |= PLLE_AUX_SEQ_ENABLE;
+ pll_writel(val, pll->params->aux_reg, pll);
+
+out:
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static void clk_plle_tegra210_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ val = pll_readl_base(pll);
+ val &= ~PLLE_BASE_ENABLE;
+ pll_writel_base(val, pll);
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
+ pll_writel_misc(val, pll);
+ udelay(1);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+
+ val = pll_readl_base(pll);
+
+ return val & PLLE_BASE_ENABLE ? 1 : 0;
+}
+
+static const struct clk_ops tegra_clk_plle_tegra210_ops = {
+ .is_enabled = clk_plle_tegra210_is_enabled,
+ .enable = clk_plle_tegra210_enable,
+ .disable = clk_plle_tegra210_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+};
+
+struct clk *tegra_clk_register_plle_tegra210(const char *name,
+ const char *parent_name,
+ void __iomem *clk_base, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+ u32 val, val_aux;
+
+ pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ /* ensure parent is set to pll_re_vco */
+
+ val = pll_readl_base(pll);
+ val_aux = pll_readl(pll_params->aux_reg, pll);
+
+ if (val & PLLE_BASE_ENABLE) {
+ if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
+ (val_aux & PLLE_AUX_PLLP_SEL))
+ WARN(1, "pll_e enabled with unsupported parent %s\n",
+ (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
+ "pll_re_vco");
+ } else {
+ val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
+ pll_writel(val_aux, pll_params->aux_reg, pll);
+ }
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_plle_tegra210_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct clk *parent, *clk;
+ const struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
+ struct tegra_clk_pll *pll;
+ unsigned long parent_rate;
+
+ if (!p_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ parent_rate = clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
+ pll_params->flags |= TEGRA_PLL_BYPASS;
+ pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk, *parent;
+ unsigned long parent_rate;
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!pll_params->pdiv_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent_rate = clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
+ pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllss_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk, *parent;
+ struct tegra_clk_pll_freq_table cfg;
+ unsigned long parent_rate;
+ u32 val;
+ int i;
+
+ if (!pll_params->div_nmp)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ val = pll_readl_base(pll);
+ val &= ~PLLSS_REF_SRC_SEL_MASK;
+ pll_writel_base(val, pll);
+
+ parent_rate = clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
+ /* initialize PLL to minimum rate */
+
+ cfg.m = _pll_fixed_mdiv(pll_params, parent_rate);
+ cfg.n = cfg.m * pll_params->vco_min / parent_rate;
+
+ for (i = 0; pll_params->pdiv_tohw[i].pdiv; i++)
+ ;
+ if (!i) {
+ kfree(pll);
+ return ERR_PTR(-EINVAL);
+ }
+
+ cfg.p = pll_params->pdiv_tohw[i-1].hw_val;
+
+ _update_pll_mnp(pll, &cfg);
+
+ pll_writel_misc(PLLSS_MISC_DEFAULT, pll);
+
+ val = pll_readl_base(pll);
if (val & PLL_BASE_ENABLE) {
if (val & BIT(pll_params->iddq_bit_idx)) {
WARN(1, "%s is on but IDDQ set\n", name);
@@ -1887,8 +2325,50 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
pll_writel_base(val, pll);
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
- &tegra_clk_pllss_ops);
+ &tegra_clk_pll_ops);
+
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk, *parent;
+ unsigned long parent_rate;
+ if (!pll_params->pdiv_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ parent_name, name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ parent_rate = clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
+ pll_params->flags |= TEGRA_PLL_BYPASS;
+ pll_params->flags |= TEGRA_PLLMB;
+ pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
if (IS_ERR(clk))
kfree(pll);
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index cb6ab830941d..6ad381a888a6 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -124,6 +124,20 @@
#define CLK_SOURCE_HDMI_AUDIO 0x668
#define CLK_SOURCE_VIC03 0x678
#define CLK_SOURCE_CLK72MHZ 0x66c
+#define CLK_SOURCE_DBGAPB 0x718
+#define CLK_SOURCE_NVENC 0x6a0
+#define CLK_SOURCE_NVDEC 0x698
+#define CLK_SOURCE_NVJPG 0x69c
+#define CLK_SOURCE_APE 0x6c0
+#define CLK_SOURCE_SOR1 0x410
+#define CLK_SOURCE_SDMMC_LEGACY 0x694
+#define CLK_SOURCE_QSPI 0x6c4
+#define CLK_SOURCE_VI_I2C 0x6c8
+#define CLK_SOURCE_MIPIBIF 0x660
+#define CLK_SOURCE_UARTAPE 0x710
+#define CLK_SOURCE_TSECB 0x6d8
+#define CLK_SOURCE_MAUD 0x6d4
+#define CLK_SOURCE_USB2_HSIC_TRK 0x6cc
#define MASK(x) (BIT(x) - 1)
@@ -182,6 +196,13 @@
TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
_parents##_idx, 0, NULL)
+#define UART8(_name, _parents, _offset,\
+ _clk_num, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
+ 29, MASK(3), 0, 0, 16, 1, TEGRA_DIVIDER_UART| \
+ TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
+ _parents##_idx, 0, NULL)
+
#define I2C(_name, _parents, _offset,\
_clk_num, _clk_id) \
TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
@@ -221,8 +242,21 @@
.flags = _flags \
}
+#define DIV8(_name, _parent_name, _offset, _clk_id, _flags) \
+ { \
+ .name = _name, \
+ .clk_id = _clk_id, \
+ .p.parent_name = _parent_name, \
+ .periph = TEGRA_CLK_PERIPH(0, 0, 0, 0, 8, 1, \
+ TEGRA_DIVIDER_ROUND_UP, 0, 0, \
+ NULL, NULL), \
+ .offset = _offset, \
+ .flags = _flags, \
+ }
+
#define PLLP_BASE 0xa0
#define PLLP_MISC 0xac
+#define PLLP_MISC1 0x680
#define PLLP_OUTA 0xa4
#define PLLP_OUTB 0xa8
#define PLLP_OUTC 0x67c
@@ -234,6 +268,7 @@ static DEFINE_SPINLOCK(PLLP_OUTA_lock);
static DEFINE_SPINLOCK(PLLP_OUTB_lock);
static DEFINE_SPINLOCK(PLLP_OUTC_lock);
static DEFINE_SPINLOCK(sor0_lock);
+static DEFINE_SPINLOCK(sor1_lock);
#define MUX_I2S_SPDIF(_id) \
static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \
@@ -285,6 +320,68 @@ static u32 mux_pllp_clkm_idx[] = {
[0] = 0, [1] = 3,
};
+static const char *mux_pllp_clkm_2[] = {
+ "pll_p", "clk_m"
+};
+static u32 mux_pllp_clkm_2_idx[] = {
+ [0] = 2, [1] = 6,
+};
+
+static const char *mux_pllc2_c_c3_pllp_plla1_clkm[] = {
+ "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a1", "clk_m"
+};
+static u32 mux_pllc2_c_c3_pllp_plla1_clkm_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 6, [5] = 7,
+};
+
+static const char *
+mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0[] = {
+ "pll_c4_out1", "pll_c", "pll_c4_out2", "pll_p", "clk_m",
+ "pll_a_out0", "pll_c4_out0"
+};
+static u32 mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0_idx[] = {
+ [0] = 0, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllc_pllp_plla[] = {
+ "pll_c", "pll_p", "pll_a_out0"
+};
+static u32 mux_pllc_pllp_plla_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3,
+};
+
+static const char *mux_clkm_pllc_pllp_plla[] = {
+ "clk_m", "pll_c", "pll_p", "pll_a_out0"
+};
+#define mux_clkm_pllc_pllp_plla_idx NULL
+
+static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm[] = {
+ "pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m"
+};
+static u32 mux_pllc_pllp_plla1_pllc2_c3_clkm_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6,
+};
+
+static const char *mux_pllc2_c_c3_pllp_clkm_plla1_pllc4[] = {
+ "pll_c2", "pll_c", "pll_c3", "pll_p", "clk_m", "pll_a1", "pll_c4_out0",
+};
+static u32 mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4[] = {
+ "pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m", "pll_c4_out0",
+};
+#define mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4_idx \
+ mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx
+
+static const char *
+mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm[] = {
+ "pll_a_out0", "pll_c4_out0", "pll_c", "pll_c4_out1", "pll_p",
+ "pll_c4_out2", "clk_m"
+};
+#define mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm_idx NULL
+
static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = {
"pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0"
};
@@ -302,12 +399,93 @@ static const char *mux_pllm_pllc_pllp_plla[] = {
#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx
static const char *mux_pllp_pllc_clkm[] = {
- "pll_p", "pll_c", "pll_m"
+ "pll_p", "pll_c", "clk_m"
};
static u32 mux_pllp_pllc_clkm_idx[] = {
[0] = 0, [1] = 1, [2] = 3,
};
+static const char *mux_pllp_pllc_clkm_1[] = {
+ "pll_p", "pll_c", "clk_m"
+};
+static u32 mux_pllp_pllc_clkm_1_idx[] = {
+ [0] = 0, [1] = 2, [2] = 5,
+};
+
+static const char *mux_pllp_pllc_plla_clkm[] = {
+ "pll_p", "pll_c", "pll_a_out0", "clk_m"
+};
+static u32 mux_pllp_pllc_plla_clkm_idx[] = {
+ [0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
+
+static const char *mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2[] = {
+ "pll_p", "pll_c", "pll_c4_out0", "pll_c4_out1", "clk_m", "pll_c4_out2"
+};
+static u32 mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2_idx[] = {
+ [0] = 0, [1] = 2, [2] = 3, [3] = 5, [4] = 6, [5] = 7,
+};
+
+static const char *
+mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
+ "pll_p", "pll_c_out1", "pll_c", "pll_c4_out2", "pll_c4_out1",
+ "clk_m", "pll_c4_out0"
+};
+static u32
+mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
+ "pll_p", "pll_c4_out2", "pll_c4_out1", "clk_m", "pll_c4_out0"
+};
+static u32 mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
+ [0] = 0, [1] = 3, [2] = 4, [3] = 6, [4] = 7,
+};
+
+static const char *mux_pllp_clkm_pllc4_out2_out1_out0_lj[] = {
+ "pll_p",
+ "pll_c4_out2", "pll_c4_out0", /* LJ input */
+ "pll_c4_out2", "pll_c4_out1",
+ "pll_c4_out1", /* LJ input */
+ "clk_m", "pll_c4_out0"
+};
+#define mux_pllp_clkm_pllc4_out2_out1_out0_lj_idx NULL
+
+static const char *mux_pllp_pllc2_c_c3_clkm[] = {
+ "pll_p", "pll_c2", "pll_c", "pll_c3", "clk_m"
+};
+static u32 mux_pllp_pllc2_c_c3_clkm_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 6,
+};
+
+static const char *mux_pllp_clkm_clk32_plle[] = {
+ "pll_p", "clk_m", "clk_32k", "pll_e"
+};
+static u32 mux_pllp_clkm_clk32_plle_idx[] = {
+ [0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
+
+static const char *mux_pllp_pllp_out3_clkm_clk32k_plla[] = {
+ "pll_p", "pll_p_out3", "clk_m", "clk_32k", "pll_a_out0"
+};
+#define mux_pllp_pllp_out3_clkm_clk32k_plla_idx NULL
+
+static const char *mux_pllp_out3_clkm_pllp_pllc4[] = {
+ "pll_p_out3", "clk_m", "pll_p", "pll_c4_out0", "pll_c4_out1",
+ "pll_c4_out2"
+};
+static u32 mux_pllp_out3_clkm_pllp_pllc4_idx[] = {
+ [0] = 0, [1] = 3, [2] = 4, [3] = 5, [4] = 6, [5] = 7,
+};
+
+static const char *mux_clkm_pllp_pllre[] = {
+ "clk_m", "pll_p_out_xusb", "pll_re_out"
+};
+static u32 mux_clkm_pllp_pllre_idx[] = {
+ [0] = 0, [1] = 1, [2] = 5,
+};
+
static const char *mux_pllp_pllc_clkm_clk32[] = {
"pll_p", "pll_c", "clk_m", "clk_32k"
};
@@ -332,6 +510,11 @@ static u32 mux_clkm_48M_pllp_480M_idx[] = {
[0] = 0, [1] = 2, [2] = 4, [3] = 6,
};
+static const char *mux_clkm_pllre_clk32_480M[] = {
+ "clk_m", "pll_re_out", "clk_32k", "pll_u_480M"
+};
+#define mux_clkm_pllre_clk32_480M_idx NULL
+
static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
};
@@ -339,10 +522,27 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
};
-static const char *mux_ss_60M[] = {
+static const char *mux_pllp_out3_pllp_pllc_clkm[] = {
+ "pll_p_out3", "pll_p", "pll_c", "clk_m"
+};
+static u32 mux_pllp_out3_pllp_pllc_clkm_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 6,
+};
+
+static const char *mux_ss_div2_60M[] = {
"xusb_ss_div2", "pll_u_60M"
};
-#define mux_ss_60M_idx NULL
+#define mux_ss_div2_60M_idx NULL
+
+static const char *mux_ss_div2_60M_ss[] = {
+ "xusb_ss_div2", "pll_u_60M", "xusb_ss_src"
+};
+#define mux_ss_div2_60M_ss_idx NULL
+
+static const char *mux_ss_clkm[] = {
+ "xusb_ss_src", "clk_m"
+};
+#define mux_ss_clkm_idx NULL
static const char *mux_d_audio_clk[] = {
"pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
@@ -386,6 +586,32 @@ static u32 mux_pllm_pllc2_c_c3_pllp_plla_pllc4_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, [6] = 7,
};
+/* SOR1 mux'es */
+static const char *mux_pllp_plld_plld2_clkm[] = {
+ "pll_p", "pll_d_out0", "pll_d2_out0", "clk_m"
+};
+static u32 mux_pllp_plld_plld2_clkm_idx[] = {
+ [0] = 0, [1] = 2, [2] = 5, [3] = 6
+};
+
+static const char *mux_plldp_sor1_src[] = {
+ "pll_dp", "clk_sor1_src"
+};
+#define mux_plldp_sor1_src_idx NULL
+
+static const char *mux_clkm_sor1_brick_sor1_src[] = {
+ "clk_m", "sor1_brick", "sor1_src", "sor1_brick"
+};
+#define mux_clkm_sor1_brick_sor1_src_idx NULL
+
+static const char *mux_pllp_pllre_clkm[] = {
+ "pll_p", "pll_re_out1", "clk_m"
+};
+
+static u32 mux_pllp_pllre_clkm_idx[] = {
+ [0] = 0, [1] = 2, [2] = 3,
+};
+
static const char *mux_clkm_plldp_sor0lvds[] = {
"clk_m", "pll_dp", "sor0_lvds",
};
@@ -401,6 +627,7 @@ static struct tegra_periph_init_data periph_clks[] = {
I2C("i2c3", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, tegra_clk_i2c3),
I2C("i2c4", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, tegra_clk_i2c4),
I2C("i2c5", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, tegra_clk_i2c5),
+ I2C("i2c6", mux_pllp_clkm, CLK_SOURCE_I2C6, 166, tegra_clk_i2c6),
INT("vde", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde),
INT("vi", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi),
INT("epp", mux_pllm_pllc_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp),
@@ -411,14 +638,19 @@ static struct tegra_periph_init_data periph_clks[] = {
INT8("vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde_8),
INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_8),
INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_9),
+ INT8("vi", mux_pllc2_c_c3_pllp_clkm_plla1_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_10),
INT8("epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp_8),
INT8("msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, TEGRA_PERIPH_WAR_1005168, tegra_clk_msenc),
INT8("tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec),
+ INT("tsec", mux_pllp_pllc_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec_8),
INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8),
+ INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9),
INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
+ INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8),
INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8),
INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03),
+ INT8("vic03", mux_pllc_pllp_plla1_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03_8),
INT_FLAGS("mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, 0, tegra_clk_mselect, CLK_IGNORE_UNUSED),
MUX("i2s0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, TEGRA_PERIPH_ON_APB, tegra_clk_i2s0),
MUX("i2s1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, tegra_clk_i2s1),
@@ -427,22 +659,31 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("i2s4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, TEGRA_PERIPH_ON_APB, tegra_clk_i2s4),
MUX("spdif_out", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_out),
MUX("spdif_in", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in),
+ MUX8("spdif_in", mux_pllp_pllc_clkm_1, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in_8),
MUX("pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, TEGRA_PERIPH_ON_APB, tegra_clk_pwm),
MUX("adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, TEGRA_PERIPH_ON_APB, tegra_clk_adx),
MUX("amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, TEGRA_PERIPH_ON_APB, tegra_clk_amx),
MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
+ MUX("hda", mux_pllp_pllc_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda_8),
MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
+ MUX8("hda2codec_2x", mux_pllp_pllc_plla_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x_8),
MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
+ MUX8("sdmmc1", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_9),
+ MUX8("sdmmc2", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_9),
+ MUX8("sdmmc3", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_9),
+ MUX8("sdmmc4", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_9),
MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
+ MUX("owr", mux_pllp_pllc_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr_8),
MUX("nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, 0, tegra_clk_nor),
MUX("mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, TEGRA_PERIPH_ON_APB, tegra_clk_mipi),
MUX("vi_sensor", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor),
+ MUX("vi_sensor", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_9),
MUX("cilab", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, 0, tegra_clk_cilab),
MUX("cilcd", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, 0, tegra_clk_cilcd),
MUX("cile", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, 0, tegra_clk_cile),
@@ -465,10 +706,13 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("ndflash", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash),
MUX("ndspeed", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed),
MUX("sata_oob", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob),
+ MUX("sata_oob", mux_pllp_pllc_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob_8),
MUX("sata", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata),
+ MUX("sata", mux_pllp_pllc_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata_8),
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+ MUX("vi_sensor2", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2_8),
MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
@@ -479,6 +723,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("sbc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_8),
MUX8("sbc5", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC5, 104, TEGRA_PERIPH_ON_APB, tegra_clk_sbc5_8),
MUX8("sbc6", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC6, 105, TEGRA_PERIPH_ON_APB, tegra_clk_sbc6_8),
+ MUX("sbc1", mux_pllp_pllc_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_9),
+ MUX("sbc2", mux_pllp_pllc_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_9),
+ MUX("sbc3", mux_pllp_pllc_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_9),
+ MUX("sbc4", mux_pllp_pllc_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_9),
MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
@@ -486,27 +734,59 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
+ MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
MUX8("isp", mux_pllm_pllc_pllp_plla_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_8),
+ MUX8("isp", mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_9),
MUX8("entropy", mux_pllp_clkm1, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy),
+ MUX8("entropy", mux_pllp_clkm_clk32_plle, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy_8),
MUX8("hdmi_audio", mux_pllp3_pllc_clkm, CLK_SOURCE_HDMI_AUDIO, 176, TEGRA_PERIPH_NO_RESET, tegra_clk_hdmi_audio),
MUX8("clk72mhz", mux_pllp3_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz),
+ MUX8("clk72mhz", mux_pllp_out3_pllp_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz_8),
MUX8_NOGATE_LOCK("sor0_lvds", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_SOR0, tegra_clk_sor0_lvds, &sor0_lock),
MUX_FLAGS("csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite, CLK_IGNORE_UNUSED),
+ MUX_FLAGS("csite", mux_pllp_pllre_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite_8, CLK_IGNORE_UNUSED),
NODIV("disp1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1, NULL),
+ NODIV("disp1", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1_8, NULL),
NODIV("disp2", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2, NULL),
+ NODIV("disp2", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2_8, NULL),
NODIV("sor0", mux_clkm_plldp_sor0lvds, CLK_SOURCE_SOR0, 14, 3, 182, 0, tegra_clk_sor0, &sor0_lock),
UART("uarta", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, tegra_clk_uarta),
UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
+ UART8("uarta", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTA, 6, tegra_clk_uarta_8),
+ UART8("uartb", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTB, 7, tegra_clk_uartb_8),
+ UART8("uartc", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTC, 55, tegra_clk_uartc_8),
+ UART8("uartd", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTD, 65, tegra_clk_uartd_8),
XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
+ XUSB("xusb_host_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src_8),
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
+ XUSB("xusb_falcon_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src_8),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
- NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
+ XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src_8),
+ NODIV("xusb_hs_src", mux_ss_div2_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
+ NODIV("xusb_hs_src", mux_ss_div2_60M_ss, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(2), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src_4, NULL),
+ NODIV("xusb_ssp_src", mux_ss_clkm, CLK_SOURCE_XUSB_SS_SRC, 24, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ssp_src, NULL),
XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
+ XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8),
+ MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb),
+ MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
+ MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec),
+ MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg),
+ MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape),
+ MUX8_NOGATE_LOCK("sor1_src", mux_pllp_plld_plld2_clkm, CLK_SOURCE_SOR1, tegra_clk_sor1_src, &sor1_lock),
+ NODIV("sor1_brick", mux_plldp_sor1_src, CLK_SOURCE_SOR1, 14, MASK(1), 183, 0, tegra_clk_sor1_brick, &sor1_lock),
+ NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock),
+ MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy),
+ MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi),
+ MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c),
+ MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif),
+ MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape),
+ MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb),
+ MUX8("maud", mux_pllp_pllp_out3_clkm_clk32k_plla, CLK_SOURCE_MAUD, 202, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_maud),
};
static struct tegra_periph_init_data gate_clks[] = {
@@ -543,6 +823,16 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0),
GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0),
GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0),
+ GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0),
+ GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0),
+ GATE("usb2_trk", "usb2_hsic_trk", 210, TEGRA_PERIPH_NO_RESET, tegra_clk_usb2_trk, 0),
+ GATE("xusb_gate", "osc", 143, 0, tegra_clk_xusb_gate, 0),
+ GATE("pll_p_out_cpu", "pll_p", 223, 0, tegra_clk_pll_p_out_cpu, 0),
+ GATE("pll_p_out_adsp", "pll_p", 187, 0, tegra_clk_pll_p_out_adsp, 0),
+};
+
+static struct tegra_periph_init_data div_clks[] = {
+ DIV8("usb2_hsic_trk", "osc", CLK_SOURCE_USB2_HSIC_TRK, tegra_clk_usb2_hsic_trk, 0),
};
struct pll_out_data {
@@ -633,6 +923,33 @@ static void __init gate_clk_init(void __iomem *clk_base,
}
}
+static void __init div_clk_init(void __iomem *clk_base,
+ struct tegra_clk *tegra_clks)
+{
+ int i;
+ struct clk *clk;
+ struct clk **dt_clk;
+
+ for (i = 0; i < ARRAY_SIZE(div_clks); i++) {
+ struct tegra_periph_init_data *data;
+
+ data = div_clks + i;
+
+ dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
+ if (!dt_clk)
+ continue;
+
+ clk = tegra_clk_register_divider(data->name,
+ data->p.parent_name, clk_base + data->offset,
+ data->flags, data->periph.divider.flags,
+ data->periph.divider.shift,
+ data->periph.divider.width,
+ data->periph.divider.frac_width,
+ data->periph.divider.lock);
+ *dt_clk = clk;
+ }
+}
+
static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *pll_params)
@@ -669,6 +986,51 @@ static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
data->lock);
*dt_clk = clk;
}
+
+ dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_cpu,
+ tegra_clks);
+ if (dt_clk) {
+ /*
+ * Tegra210 has control on enabling/disabling PLLP branches to
+ * CPU, register a gate clock "pll_p_out_cpu" for this gating
+ * function and parent "pll_p_out4" to it, so when we are
+ * re-parenting CPU off from "pll_p_out4" the PLLP branching to
+ * CPU can be disabled automatically.
+ */
+ clk = tegra_clk_register_divider("pll_p_out4_div",
+ "pll_p_out_cpu", clk_base + PLLP_OUTB, 0, 0, 24,
+ 8, 1, &PLLP_OUTB_lock);
+
+ dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out4_cpu, tegra_clks);
+ if (dt_clk) {
+ clk = tegra_clk_register_pll_out("pll_p_out4",
+ "pll_p_out4_div", clk_base + PLLP_OUTB,
+ 17, 16, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0,
+ &PLLP_OUTB_lock);
+ *dt_clk = clk;
+ }
+ }
+
+ dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_hsio, tegra_clks);
+ if (dt_clk) {
+ /* PLLP_OUT_HSIO */
+ clk = clk_register_gate(NULL, "pll_p_out_hsio", "pll_p",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ clk_base + PLLP_MISC1, 29, 0, NULL);
+ *dt_clk = clk;
+ }
+
+ dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_xusb, tegra_clks);
+ if (dt_clk) {
+ /* PLLP_OUT_XUSB */
+ clk = clk_register_gate(NULL, "pll_p_out_xusb",
+ "pll_p_out_hsio", CLK_SET_RATE_PARENT |
+ CLK_IGNORE_UNUSED, clk_base + PLLP_MISC1, 28, 0,
+ NULL);
+ clk_register_clkdev(clk, "pll_p_out_xusb", NULL);
+ *dt_clk = clk;
+ }
}
void __init tegra_periph_clk_init(void __iomem *clk_base,
@@ -678,4 +1040,5 @@ void __init tegra_periph_clk_init(void __iomem *clk_base,
init_pllp(clk_base, pmc_base, tegra_clks, pll_params);
periph_clk_init(clk_base, tegra_clks);
gate_clk_init(clk_base, tegra_clks);
+ div_clk_init(clk_base, tegra_clks);
}
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index 5b1d723932c5..4559a20e3af6 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -34,9 +34,25 @@
#define CCLKLP_BURST_POLICY 0x370
#define SCLK_BURST_POLICY 0x028
#define SYSTEM_CLK_RATE 0x030
+#define SCLK_DIVIDER 0x2c
static DEFINE_SPINLOCK(sysrate_lock);
+enum tegra_super_gen {
+ gen4 = 4,
+ gen5,
+};
+
+struct tegra_super_gen_info {
+ enum tegra_super_gen gen;
+ const char **sclk_parents;
+ const char **cclk_g_parents;
+ const char **cclk_lp_parents;
+ int num_sclk_parents;
+ int num_cclk_g_parents;
+ int num_cclk_lp_parents;
+};
+
static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
"pll_p", "pll_p_out2", "unused",
"clk_32k", "pll_m_out1" };
@@ -51,21 +67,81 @@ static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
"pll_p", "pll_p_out4", "unused",
"unused", "pll_x", "pll_x_out0" };
+const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
+ .gen = gen4,
+ .sclk_parents = sclk_parents,
+ .cclk_g_parents = cclk_g_parents,
+ .cclk_lp_parents = cclk_lp_parents,
+ .num_sclk_parents = ARRAY_SIZE(sclk_parents),
+ .num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents),
+ .num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents),
+};
+
+static const char *sclk_parents_gen5[] = { "clk_m", "pll_c_out1", "pll_c4_out3",
+ "pll_p", "pll_p_out2", "pll_c4_out1",
+ "clk_32k", "pll_c4_out2" };
+
+static const char *cclk_g_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
+ "pll_p", "pll_p_out4", "unused",
+ "unused", "pll_x", "unused", "unused",
+ "unused", "unused", "unused", "unused",
+ "dfllCPU_out" };
+
+static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
+ "pll_p", "pll_p_out4", "unused",
+ "unused", "pll_x", "unused", "unused",
+ "unused", "unused", "unused", "unused",
+ "dfllCPU_out" };
+
+const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
+ .gen = gen5,
+ .sclk_parents = sclk_parents_gen5,
+ .cclk_g_parents = cclk_g_parents_gen5,
+ .cclk_lp_parents = cclk_lp_parents_gen5,
+ .num_sclk_parents = ARRAY_SIZE(sclk_parents_gen5),
+ .num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents_gen5),
+ .num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents_gen5),
+};
+
static void __init tegra_sclk_init(void __iomem *clk_base,
- struct tegra_clk *tegra_clks)
+ struct tegra_clk *tegra_clks,
+ const struct tegra_super_gen_info *gen_info)
{
struct clk *clk;
struct clk **dt_clk;
- /* SCLK */
- dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+ /* SCLK_MUX */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk_mux, tegra_clks);
if (dt_clk) {
- clk = tegra_clk_register_super_mux("sclk", sclk_parents,
- ARRAY_SIZE(sclk_parents),
+ clk = tegra_clk_register_super_mux("sclk_mux",
+ gen_info->sclk_parents,
+ gen_info->num_sclk_parents,
CLK_SET_RATE_PARENT,
clk_base + SCLK_BURST_POLICY,
0, 4, 0, 0, NULL);
*dt_clk = clk;
+
+
+ /* SCLK */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+ if (dt_clk) {
+ clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0,
+ clk_base + SCLK_DIVIDER, 0, 8,
+ 0, &sysrate_lock);
+ *dt_clk = clk;
+ }
+ } else {
+ /* SCLK */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+ if (dt_clk) {
+ clk = tegra_clk_register_super_mux("sclk",
+ gen_info->sclk_parents,
+ gen_info->num_sclk_parents,
+ CLK_SET_RATE_PARENT,
+ clk_base + SCLK_BURST_POLICY,
+ 0, 4, 0, 0, NULL);
+ *dt_clk = clk;
+ }
}
/* HCLK */
@@ -95,10 +171,11 @@ static void __init tegra_sclk_init(void __iomem *clk_base,
*dt_clk = clk;
}
-void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
+void __init tegra_super_clk_init(void __iomem *clk_base,
void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
- struct tegra_clk_pll_params *params)
+ struct tegra_clk_pll_params *params,
+ const struct tegra_super_gen_info *gen_info)
{
struct clk *clk;
struct clk **dt_clk;
@@ -106,28 +183,50 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
/* CCLKG */
dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
if (dt_clk) {
- clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
- ARRAY_SIZE(cclk_g_parents),
+ if (gen_info->gen == gen5) {
+ clk = tegra_clk_register_super_mux("cclk_g",
+ gen_info->cclk_g_parents,
+ gen_info->num_cclk_g_parents,
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKG_BURST_POLICY,
+ 0, 4, 8, 0, NULL);
+ } else {
+ clk = tegra_clk_register_super_mux("cclk_g",
+ gen_info->cclk_g_parents,
+ gen_info->num_cclk_g_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKG_BURST_POLICY,
0, 4, 0, 0, NULL);
+ }
*dt_clk = clk;
}
/* CCLKLP */
dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
if (dt_clk) {
- clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
- ARRAY_SIZE(cclk_lp_parents),
+ if (gen_info->gen == gen5) {
+ clk = tegra_clk_register_super_mux("cclk_lp",
+ gen_info->cclk_lp_parents,
+ gen_info->num_cclk_lp_parents,
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKLP_BURST_POLICY,
+ 0, 4, 8, 0, NULL);
+ } else {
+ clk = tegra_clk_register_super_mux("cclk_lp",
+ gen_info->cclk_lp_parents,
+ gen_info->num_cclk_lp_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKLP_BURST_POLICY,
TEGRA_DIVIDER_2, 4, 8, 9, NULL);
+ }
*dt_clk = clk;
}
- tegra_sclk_init(clk_base, tegra_clks);
+ tegra_sclk_init(clk_base, tegra_clks, gen_info);
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)
/* PLLX */
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
if (!dt_clk)
@@ -148,3 +247,20 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
#endif
}
+void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
+ void __iomem *pmc_base,
+ struct tegra_clk *tegra_clks,
+ struct tegra_clk_pll_params *params)
+{
+ tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
+ &tegra_super_gen_info_gen4);
+}
+
+void __init tegra_super_clk_gen5_init(void __iomem *clk_base,
+ void __iomem *pmc_base,
+ struct tegra_clk *tegra_clks,
+ struct tegra_clk_pll_params *params)
+{
+ tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
+ &tegra_super_gen_info_gen5);
+}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index b7d03e9add97..4a24aa4bbdea 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -182,40 +182,40 @@ static struct div_nmp pllxc_nmp = {
.divp_width = 4,
};
-static struct pdiv_map pllxc_p[] = {
- { .pdiv = 1, .hw_val = 0 },
- { .pdiv = 2, .hw_val = 1 },
- { .pdiv = 3, .hw_val = 2 },
- { .pdiv = 4, .hw_val = 3 },
- { .pdiv = 5, .hw_val = 4 },
- { .pdiv = 6, .hw_val = 5 },
- { .pdiv = 8, .hw_val = 6 },
- { .pdiv = 10, .hw_val = 7 },
- { .pdiv = 12, .hw_val = 8 },
- { .pdiv = 16, .hw_val = 9 },
+static const struct pdiv_map pllxc_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
- { .pdiv = 0, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
- { 12000000, 624000000, 104, 0, 2},
- { 12000000, 600000000, 100, 0, 2},
- { 13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */
- { 16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */
- { 19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */
- { 26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 624000000, 104, 1, 2, 0 },
+ { 12000000, 600000000, 100, 1, 2, 0 },
+ { 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c_params = {
.input_min = 12000000,
.input_max = 800000000,
.cf_min = 12000000,
- .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 600000000,
.vco_max = 1400000000,
.base_reg = PLLC_BASE,
@@ -232,7 +232,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp pllcx_nmp = {
@@ -244,22 +244,22 @@ static struct div_nmp pllcx_nmp = {
.divp_width = 3,
};
-static struct pdiv_map pllc_p[] = {
- { .pdiv = 1, .hw_val = 0 },
- { .pdiv = 2, .hw_val = 1 },
- { .pdiv = 4, .hw_val = 3 },
- { .pdiv = 8, .hw_val = 5 },
+static const struct pdiv_map pllc_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 8, .hw_val = 5 },
{ .pdiv = 16, .hw_val = 7 },
- { .pdiv = 0, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
- {12000000, 600000000, 100, 0, 2},
- {13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */
- {16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */
- {19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */
- {26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 600000000, 100, 1, 2, 0 },
+ { 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c2_params = {
@@ -318,26 +318,26 @@ static struct div_nmp pllm_nmp = {
.override_divp_shift = 27,
};
-static struct pdiv_map pllm_p[] = {
+static const struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
- {12000000, 800000000, 66, 0, 1}, /* actual: 792.0 MHz */
- {13000000, 800000000, 61, 0, 1}, /* actual: 793.0 MHz */
- {16800000, 800000000, 47, 0, 1}, /* actual: 789.6 MHz */
- {19200000, 800000000, 41, 0, 1}, /* actual: 787.2 MHz */
- {26000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 800000000, 66, 1, 1, 0 }, /* actual: 792.0 MHz */
+ { 13000000, 800000000, 61, 1, 1, 0 }, /* actual: 793.0 MHz */
+ { 16800000, 800000000, 47, 1, 1, 0 }, /* actual: 789.6 MHz */
+ { 19200000, 800000000, 41, 1, 1, 0 }, /* actual: 787.2 MHz */
+ { 26000000, 800000000, 61, 2, 1, 0 }, /* actual: 793.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_m_params = {
.input_min = 12000000,
.input_max = 500000000,
.cf_min = 12000000,
- .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 400000000,
.vco_max = 1066000000,
.base_reg = PLLM_BASE,
@@ -351,7 +351,8 @@ static struct tegra_clk_pll_params pll_m_params = {
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_FIXED,
};
static struct div_nmp pllp_nmp = {
@@ -364,12 +365,12 @@ static struct div_nmp pllp_nmp = {
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- {12000000, 216000000, 432, 12, 1, 8},
- {13000000, 216000000, 432, 13, 1, 8},
- {16800000, 216000000, 360, 14, 1, 8},
- {19200000, 216000000, 360, 16, 1, 8},
- {26000000, 216000000, 432, 26, 1, 8},
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 216000000, 432, 12, 2, 8 },
+ { 13000000, 216000000, 432, 13, 2, 8 },
+ { 16800000, 216000000, 360, 14, 2, 8 },
+ { 19200000, 216000000, 360, 16, 2, 8 },
+ { 26000000, 216000000, 432, 26, 2, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_p_params = {
@@ -386,19 +387,19 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 408000000,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
- {9600000, 282240000, 147, 5, 0, 4},
- {9600000, 368640000, 192, 5, 0, 4},
- {9600000, 240000000, 200, 8, 0, 8},
-
- {28800000, 282240000, 245, 25, 0, 8},
- {28800000, 368640000, 320, 25, 0, 8},
- {28800000, 240000000, 200, 24, 0, 8},
- {0, 0, 0, 0, 0, 0},
+ { 9600000, 282240000, 147, 5, 1, 4 },
+ { 9600000, 368640000, 192, 5, 1, 4 },
+ { 9600000, 240000000, 200, 8, 1, 8 },
+ { 28800000, 282240000, 245, 25, 1, 8 },
+ { 28800000, 368640000, 320, 25, 1, 8 },
+ { 28800000, 240000000, 200, 24, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
@@ -416,28 +417,26 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
- {12000000, 216000000, 864, 12, 2, 12},
- {13000000, 216000000, 864, 13, 2, 12},
- {16800000, 216000000, 720, 14, 2, 12},
- {19200000, 216000000, 720, 16, 2, 12},
- {26000000, 216000000, 864, 26, 2, 12},
-
- {12000000, 594000000, 594, 12, 0, 12},
- {13000000, 594000000, 594, 13, 0, 12},
- {16800000, 594000000, 495, 14, 0, 12},
- {19200000, 594000000, 495, 16, 0, 12},
- {26000000, 594000000, 594, 26, 0, 12},
-
- {12000000, 1000000000, 1000, 12, 0, 12},
- {13000000, 1000000000, 1000, 13, 0, 12},
- {19200000, 1000000000, 625, 12, 0, 12},
- {26000000, 1000000000, 1000, 26, 0, 12},
-
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 216000000, 864, 12, 4, 12 },
+ { 13000000, 216000000, 864, 13, 4, 12 },
+ { 16800000, 216000000, 720, 14, 4, 12 },
+ { 19200000, 216000000, 720, 16, 4, 12 },
+ { 26000000, 216000000, 864, 26, 4, 12 },
+ { 12000000, 594000000, 594, 12, 1, 12 },
+ { 13000000, 594000000, 594, 13, 1, 12 },
+ { 16800000, 594000000, 495, 14, 1, 12 },
+ { 19200000, 594000000, 495, 16, 1, 12 },
+ { 26000000, 594000000, 594, 26, 1, 12 },
+ { 12000000, 1000000000, 1000, 12, 1, 12 },
+ { 13000000, 1000000000, 1000, 13, 1, 12 },
+ { 19200000, 1000000000, 625, 12, 1, 12 },
+ { 26000000, 1000000000, 1000, 26, 1, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_d_params = {
@@ -455,7 +454,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_d2_params = {
@@ -473,10 +472,10 @@ static struct tegra_clk_pll_params pll_d2_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
@@ -492,12 +491,12 @@ static struct div_nmp pllu_nmp = {
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- {12000000, 480000000, 960, 12, 0, 12},
- {13000000, 480000000, 960, 13, 0, 12},
- {16800000, 480000000, 400, 7, 0, 5},
- {19200000, 480000000, 200, 4, 0, 3},
- {26000000, 480000000, 960, 26, 0, 12},
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 480000000, 960, 12, 2, 12 },
+ { 13000000, 480000000, 960, 13, 2, 12 },
+ { 16800000, 480000000, 400, 7, 2, 5 },
+ { 19200000, 480000000, 200, 4, 2, 3 },
+ { 26000000, 480000000, 960, 26, 2, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_u_params = {
@@ -516,25 +515,24 @@ static struct tegra_clk_pll_params pll_u_params = {
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
- {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */
- {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */
- {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */
- {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */
- {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */
-
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 1000000000, 83, 1, 1, 0 }, /* actual: 996.0 MHz */
+ { 13000000, 1000000000, 76, 1, 1, 0 }, /* actual: 988.0 MHz */
+ { 16800000, 1000000000, 59, 1, 1, 0 }, /* actual: 991.2 MHz */
+ { 19200000, 1000000000, 52, 1, 1, 0 }, /* actual: 998.4 MHz */
+ { 26000000, 1000000000, 76, 2, 1, 0 }, /* actual: 988.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_x_params = {
.input_min = 12000000,
.input_max = 800000000,
.cf_min = 12000000,
- .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 700000000,
.vco_max = 2400000000U,
.base_reg = PLLX_BASE,
@@ -551,15 +549,34 @@ static struct tegra_clk_pll_params pll_x_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_x_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
- {336000000, 100000000, 100, 21, 16, 11},
- {312000000, 100000000, 200, 26, 24, 13},
- {12000000, 100000000, 200, 1, 24, 13},
- {0, 0, 0, 0, 0, 0},
+ { 336000000, 100000000, 100, 21, 16, 11 },
+ { 312000000, 100000000, 200, 26, 24, 13 },
+ { 12000000, 100000000, 200, 1, 24, 13 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static const struct pdiv_map plle_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
+ { .pdiv = 12, .hw_val = 10 },
+ { .pdiv = 16, .hw_val = 11 },
+ { .pdiv = 20, .hw_val = 12 },
+ { .pdiv = 24, .hw_val = 13 },
+ { .pdiv = 32, .hw_val = 14 },
+ { .pdiv = 0, .hw_val = 0 }
};
static struct div_nmp plle_nmp = {
@@ -584,9 +601,10 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .pdiv_tohw = plle_p,
.div_nmp = &plle_nmp,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};
@@ -614,18 +632,19 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_LOCK_MISC,
};
/* possible OSC frequencies in Hz */
static unsigned long tegra114_input_freq[] = {
- [0] = 13000000,
- [1] = 16800000,
- [4] = 19200000,
- [5] = 38400000,
- [8] = 12000000,
- [9] = 48000000,
- [12] = 260000000,
+ [ 0] = 13000000,
+ [ 1] = 16800000,
+ [ 4] = 19200000,
+ [ 5] = 38400000,
+ [ 8] = 12000000,
+ [ 9] = 48000000,
+ [12] = 26000000,
};
#define MASK(x) (BIT(x) - 1)
@@ -644,21 +663,27 @@ struct utmi_clk_param {
};
static const struct utmi_clk_param utmi_parameters[] = {
- {.osc_frequency = 13000000, .enable_delay_count = 0x02,
- .stable_count = 0x33, .active_delay_count = 0x05,
- .xtal_freq_count = 0x7F},
- {.osc_frequency = 19200000, .enable_delay_count = 0x03,
- .stable_count = 0x4B, .active_delay_count = 0x06,
- .xtal_freq_count = 0xBB},
- {.osc_frequency = 12000000, .enable_delay_count = 0x02,
- .stable_count = 0x2F, .active_delay_count = 0x04,
- .xtal_freq_count = 0x76},
- {.osc_frequency = 26000000, .enable_delay_count = 0x04,
- .stable_count = 0x66, .active_delay_count = 0x09,
- .xtal_freq_count = 0xFE},
- {.osc_frequency = 16800000, .enable_delay_count = 0x03,
- .stable_count = 0x41, .active_delay_count = 0x0A,
- .xtal_freq_count = 0xA4},
+ {
+ .osc_frequency = 13000000, .enable_delay_count = 0x02,
+ .stable_count = 0x33, .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7f
+ }, {
+ .osc_frequency = 19200000, .enable_delay_count = 0x03,
+ .stable_count = 0x4b, .active_delay_count = 0x06,
+ .xtal_freq_count = 0xbb
+ }, {
+ .osc_frequency = 12000000, .enable_delay_count = 0x02,
+ .stable_count = 0x2f, .active_delay_count = 0x04,
+ .xtal_freq_count = 0x76
+ }, {
+ .osc_frequency = 26000000, .enable_delay_count = 0x04,
+ .stable_count = 0x66, .active_delay_count = 0x09,
+ .xtal_freq_count = 0xfe
+ }, {
+ .osc_frequency = 16800000, .enable_delay_count = 0x03,
+ .stable_count = 0x41, .active_delay_count = 0x0a,
+ .xtal_freq_count = 0xa4
+ },
};
/* peripheral mux definitions */
@@ -965,8 +990,8 @@ static void __init tegra114_fixed_clk_init(void __iomem *clk_base)
static __init void tegra114_utmi_param_configure(void __iomem *clk_base)
{
+ unsigned int i;
u32 reg;
- int i;
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (osc_freq == utmi_parameters[i].osc_frequency)
@@ -1173,7 +1198,7 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
{
struct clk *clk;
struct tegra_periph_init_data *data;
- int i;
+ unsigned int i;
/* xusb_ss_div2 */
clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
@@ -1278,7 +1303,7 @@ static struct tegra_cpu_car_ops tegra114_cpu_car_ops = {
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra114-pmc" },
- {},
+ { },
};
/*
@@ -1286,37 +1311,37 @@ static const struct of_device_id pmc_match[] __initconst = {
* breaks
*/
static struct tegra_clk_init_table init_table[] __initdata = {
- {TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0},
- {TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0},
- {TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0},
- {TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0},
- {TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1},
- {TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1},
- {TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1},
- {TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1},
- {TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1},
- {TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0},
- {TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1},
- {TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1},
- {TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0},
- {TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0},
- {TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0},
- {TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0},
- {TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0},
- {TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0},
- {TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0},
- {TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0},
- {TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0},
- {TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0},
- {TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0},
- {TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0},
- /* This MUST be the last entry. */
- {TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0},
+ { TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0 },
+ { TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0 },
+ { TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0 },
+ { TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0 },
+ { TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1 },
+ { TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1 },
+ { TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1 },
+ { TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1 },
+ { TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1 },
+ { TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0 },
+ { TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1 },
+ { TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1 },
+ { TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0 },
+ { TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0 },
+ { TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0 },
+ { TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0 },
+ { TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0 },
+ { TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0 },
+ { TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0 },
+ { TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0 },
+ { TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0 },
+ { TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0 },
+ { TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0 },
+ { TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0 },
+ /* must be the last entry */
+ { TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0 },
};
static void __init tegra114_clock_apply_init_table(void)
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 87975f7adddc..1627258292d2 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -150,13 +150,13 @@ static DEFINE_SPINLOCK(emc_lock);
/* possible OSC frequencies in Hz */
static unsigned long tegra124_input_freq[] = {
- [0] = 13000000,
- [1] = 16800000,
- [4] = 19200000,
- [5] = 38400000,
- [8] = 12000000,
- [9] = 48000000,
- [12] = 260000000,
+ [ 0] = 13000000,
+ [ 1] = 16800000,
+ [ 4] = 19200000,
+ [ 5] = 38400000,
+ [ 8] = 12000000,
+ [ 9] = 48000000,
+ [12] = 26000000,
};
static struct div_nmp pllxc_nmp = {
@@ -168,33 +168,33 @@ static struct div_nmp pllxc_nmp = {
.divp_width = 4,
};
-static struct pdiv_map pllxc_p[] = {
- { .pdiv = 1, .hw_val = 0 },
- { .pdiv = 2, .hw_val = 1 },
- { .pdiv = 3, .hw_val = 2 },
- { .pdiv = 4, .hw_val = 3 },
- { .pdiv = 5, .hw_val = 4 },
- { .pdiv = 6, .hw_val = 5 },
- { .pdiv = 8, .hw_val = 6 },
- { .pdiv = 10, .hw_val = 7 },
- { .pdiv = 12, .hw_val = 8 },
- { .pdiv = 16, .hw_val = 9 },
+static const struct pdiv_map pllxc_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
- { .pdiv = 0, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
- {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */
- {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */
- {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */
- {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */
- {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 1000000000, 83, 1, 1, 0 }, /* actual: 996.0 MHz */
+ { 13000000, 1000000000, 76, 1, 1, 0 }, /* actual: 988.0 MHz */
+ { 16800000, 1000000000, 59, 1, 1, 0 }, /* actual: 991.2 MHz */
+ { 19200000, 1000000000, 52, 1, 1, 0 }, /* actual: 998.4 MHz */
+ { 26000000, 1000000000, 76, 2, 1, 0 }, /* actual: 988.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_x_params = {
@@ -218,24 +218,24 @@ static struct tegra_clk_pll_params pll_x_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_x_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
- { 12000000, 624000000, 104, 1, 2},
- { 12000000, 600000000, 100, 1, 2},
- { 13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
- { 16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */
- { 19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */
- { 26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 624000000, 104, 1, 2, 0 },
+ { 12000000, 600000000, 100, 1, 2, 0 },
+ { 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c_params = {
.input_min = 12000000,
.input_max = 800000000,
.cf_min = 12000000,
- .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 600000000,
.vco_max = 1400000000,
.base_reg = PLLC_BASE,
@@ -252,7 +252,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp pllcx_nmp = {
@@ -264,25 +264,25 @@ static struct div_nmp pllcx_nmp = {
.divp_width = 3,
};
-static struct pdiv_map pllc_p[] = {
- { .pdiv = 1, .hw_val = 0 },
- { .pdiv = 2, .hw_val = 1 },
- { .pdiv = 3, .hw_val = 2 },
- { .pdiv = 4, .hw_val = 3 },
- { .pdiv = 6, .hw_val = 4 },
- { .pdiv = 8, .hw_val = 5 },
+static const struct pdiv_map pllc_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 6, .hw_val = 4 },
+ { .pdiv = 8, .hw_val = 5 },
{ .pdiv = 12, .hw_val = 6 },
{ .pdiv = 16, .hw_val = 7 },
- { .pdiv = 0, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
- {12000000, 600000000, 100, 1, 2},
- {13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
- {16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */
- {19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */
- {26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 600000000, 100, 1, 2, 0 },
+ { 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c2_params = {
@@ -338,32 +338,32 @@ static struct div_nmp pllss_nmp = {
.divp_width = 4,
};
-static struct pdiv_map pll12g_ssd_esd_p[] = {
- { .pdiv = 1, .hw_val = 0 },
- { .pdiv = 2, .hw_val = 1 },
- { .pdiv = 3, .hw_val = 2 },
- { .pdiv = 4, .hw_val = 3 },
- { .pdiv = 5, .hw_val = 4 },
- { .pdiv = 6, .hw_val = 5 },
- { .pdiv = 8, .hw_val = 6 },
- { .pdiv = 10, .hw_val = 7 },
- { .pdiv = 12, .hw_val = 8 },
- { .pdiv = 16, .hw_val = 9 },
+static const struct pdiv_map pll12g_ssd_esd_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
- { .pdiv = 0, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_c4_freq_table[] = {
- { 12000000, 600000000, 100, 1, 1},
- { 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */
- { 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */
- { 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */
- { 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 600000000, 100, 1, 2, 0 },
+ { 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c4_params = {
@@ -386,21 +386,35 @@ static struct tegra_clk_pll_params pll_c4_params = {
.ext_misc_reg[1] = 0x5b0,
.ext_misc_reg[2] = 0x5b4,
.freq_table = pll_c4_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
-static struct pdiv_map pllm_p[] = {
- { .pdiv = 1, .hw_val = 0 },
- { .pdiv = 2, .hw_val = 1 },
- { .pdiv = 0, .hw_val = 0 },
+static const struct pdiv_map pllm_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
+ { .pdiv = 12, .hw_val = 10 },
+ { .pdiv = 16, .hw_val = 11 },
+ { .pdiv = 20, .hw_val = 12 },
+ { .pdiv = 24, .hw_val = 13 },
+ { .pdiv = 32, .hw_val = 14 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
- {12000000, 800000000, 66, 1, 1}, /* actual: 792.0 MHz */
- {13000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */
- {16800000, 800000000, 47, 1, 1}, /* actual: 789.6 MHz */
- {19200000, 800000000, 41, 1, 1}, /* actual: 787.2 MHz */
- {26000000, 800000000, 61, 2, 1}, /* actual: 793.0 MHz */
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 800000000, 66, 1, 1, 0 }, /* actual: 792.0 MHz */
+ { 13000000, 800000000, 61, 1, 1, 0 }, /* actual: 793.0 MHz */
+ { 16800000, 800000000, 47, 1, 1, 0 }, /* actual: 789.6 MHz */
+ { 19200000, 800000000, 41, 1, 1, 0 }, /* actual: 787.2 MHz */
+ { 26000000, 800000000, 61, 2, 1, 0 }, /* actual: 793.0 MHz */
+ { 0, 0, 0, 0, 0, 0},
};
static struct div_nmp pllm_nmp = {
@@ -427,22 +441,41 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
- .max_p = 2,
+ .max_p = 5,
.pdiv_tohw = pllm_p,
.div_nmp = &pllm_nmp,
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
- {336000000, 100000000, 100, 21, 16, 11},
- {312000000, 100000000, 200, 26, 24, 13},
- {13000000, 100000000, 200, 1, 26, 13},
- {12000000, 100000000, 200, 1, 24, 13},
- {0, 0, 0, 0, 0, 0},
+ { 336000000, 100000000, 100, 21, 16, 11 },
+ { 312000000, 100000000, 200, 26, 24, 13 },
+ { 13000000, 100000000, 200, 1, 26, 13 },
+ { 12000000, 100000000, 200, 1, 24, 13 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static const struct pdiv_map plle_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
+ { .pdiv = 12, .hw_val = 10 },
+ { .pdiv = 16, .hw_val = 11 },
+ { .pdiv = 20, .hw_val = 12 },
+ { .pdiv = 24, .hw_val = 13 },
+ { .pdiv = 32, .hw_val = 14 },
+ { .pdiv = 1, .hw_val = 0 },
};
static struct div_nmp plle_nmp = {
@@ -467,9 +500,10 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .pdiv_tohw = plle_p,
.div_nmp = &plle_nmp,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};
@@ -507,7 +541,8 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_LOCK_MISC,
};
static struct div_nmp pllp_nmp = {
@@ -520,12 +555,12 @@ static struct div_nmp pllp_nmp = {
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- {12000000, 408000000, 408, 12, 0, 8},
- {13000000, 408000000, 408, 13, 0, 8},
- {16800000, 408000000, 340, 14, 0, 8},
- {19200000, 408000000, 340, 16, 0, 8},
- {26000000, 408000000, 408, 26, 0, 8},
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 408000000, 408, 12, 1, 8 },
+ { 13000000, 408000000, 408, 13, 1, 8 },
+ { 16800000, 408000000, 340, 14, 1, 8 },
+ { 19200000, 408000000, 340, 16, 1, 8 },
+ { 26000000, 408000000, 408, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_p_params = {
@@ -543,18 +578,18 @@ static struct tegra_clk_pll_params pll_p_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
.fixed_rate = 408000000,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
- {9600000, 282240000, 147, 5, 0, 4},
- {9600000, 368640000, 192, 5, 0, 4},
- {9600000, 240000000, 200, 8, 0, 8},
-
- {28800000, 282240000, 245, 25, 0, 8},
- {28800000, 368640000, 320, 25, 0, 8},
- {28800000, 240000000, 200, 24, 0, 8},
- {0, 0, 0, 0, 0, 0},
+ { 9600000, 282240000, 147, 5, 1, 4 },
+ { 9600000, 368640000, 192, 5, 1, 4 },
+ { 9600000, 240000000, 200, 8, 1, 8 },
+ { 28800000, 282240000, 245, 25, 1, 8 },
+ { 28800000, 368640000, 320, 25, 1, 8 },
+ { 28800000, 240000000, 200, 24, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_a_params = {
@@ -571,7 +606,8 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp plld_nmp = {
@@ -584,24 +620,21 @@ static struct div_nmp plld_nmp = {
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
- {12000000, 216000000, 864, 12, 4, 12},
- {13000000, 216000000, 864, 13, 4, 12},
- {16800000, 216000000, 720, 14, 4, 12},
- {19200000, 216000000, 720, 16, 4, 12},
- {26000000, 216000000, 864, 26, 4, 12},
-
- {12000000, 594000000, 594, 12, 1, 12},
- {13000000, 594000000, 594, 13, 1, 12},
- {16800000, 594000000, 495, 14, 1, 12},
- {19200000, 594000000, 495, 16, 1, 12},
- {26000000, 594000000, 594, 26, 1, 12},
-
- {12000000, 1000000000, 1000, 12, 1, 12},
- {13000000, 1000000000, 1000, 13, 1, 12},
- {19200000, 1000000000, 625, 12, 1, 12},
- {26000000, 1000000000, 1000, 26, 1, 12},
-
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 216000000, 864, 12, 4, 12 },
+ { 13000000, 216000000, 864, 13, 4, 12 },
+ { 16800000, 216000000, 720, 14, 4, 12 },
+ { 19200000, 216000000, 720, 16, 4, 12 },
+ { 26000000, 216000000, 864, 26, 4, 12 },
+ { 12000000, 594000000, 594, 12, 1, 12 },
+ { 13000000, 594000000, 594, 13, 1, 12 },
+ { 16800000, 594000000, 495, 14, 1, 12 },
+ { 19200000, 594000000, 495, 16, 1, 12 },
+ { 26000000, 594000000, 594, 26, 1, 12 },
+ { 12000000, 1000000000, 1000, 12, 1, 12 },
+ { 13000000, 1000000000, 1000, 13, 1, 12 },
+ { 19200000, 1000000000, 625, 12, 1, 12 },
+ { 26000000, 1000000000, 1000, 26, 1, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_d_params = {
@@ -619,16 +652,16 @@ static struct tegra_clk_pll_params pll_d_params = {
.div_nmp = &plld_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
- { 12000000, 594000000, 99, 1, 2},
- { 13000000, 594000000, 91, 1, 2}, /* actual: 591.5 MHz */
- { 16800000, 594000000, 71, 1, 2}, /* actual: 596.4 MHz */
- { 19200000, 594000000, 62, 1, 2}, /* actual: 595.2 MHz */
- { 26000000, 594000000, 91, 2, 2}, /* actual: 591.5 MHz */
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 594000000, 99, 1, 2, 0 },
+ { 13000000, 594000000, 91, 1, 2, 0 }, /* actual: 591.5 MHz */
+ { 16800000, 594000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 594000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 594000000, 91, 2, 2, 0 }, /* actual: 591.5 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params tegra124_pll_d2_params = {
@@ -652,15 +685,16 @@ static struct tegra_clk_pll_params tegra124_pll_d2_params = {
.ext_misc_reg[2] = 0x578,
.max_p = 15,
.freq_table = tegra124_pll_d2_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
- { 12000000, 600000000, 100, 1, 1},
- { 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */
- { 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */
- { 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */
- { 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 600000000, 100, 1, 2, 0 },
+ { 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_dp_params = {
@@ -684,9 +718,10 @@ static struct tegra_clk_pll_params pll_dp_params = {
.ext_misc_reg[2] = 0x5a0,
.max_p = 5,
.freq_table = pll_dp_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
@@ -702,12 +737,12 @@ static struct div_nmp pllu_nmp = {
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- {12000000, 480000000, 960, 12, 2, 12},
- {13000000, 480000000, 960, 13, 2, 12},
- {16800000, 480000000, 400, 7, 2, 5},
- {19200000, 480000000, 200, 4, 2, 3},
- {26000000, 480000000, 960, 26, 2, 12},
- {0, 0, 0, 0, 0, 0},
+ { 12000000, 480000000, 960, 12, 2, 12 },
+ { 13000000, 480000000, 960, 13, 2, 12 },
+ { 16800000, 480000000, 400, 7, 2, 5 },
+ { 19200000, 480000000, 200, 4, 2, 3 },
+ { 26000000, 480000000, 960, 26, 2, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_u_params = {
@@ -726,7 +761,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
struct utmi_clk_param {
@@ -743,21 +778,27 @@ struct utmi_clk_param {
};
static const struct utmi_clk_param utmi_parameters[] = {
- {.osc_frequency = 13000000, .enable_delay_count = 0x02,
- .stable_count = 0x33, .active_delay_count = 0x05,
- .xtal_freq_count = 0x7F},
- {.osc_frequency = 19200000, .enable_delay_count = 0x03,
- .stable_count = 0x4B, .active_delay_count = 0x06,
- .xtal_freq_count = 0xBB},
- {.osc_frequency = 12000000, .enable_delay_count = 0x02,
- .stable_count = 0x2F, .active_delay_count = 0x04,
- .xtal_freq_count = 0x76},
- {.osc_frequency = 26000000, .enable_delay_count = 0x04,
- .stable_count = 0x66, .active_delay_count = 0x09,
- .xtal_freq_count = 0xFE},
- {.osc_frequency = 16800000, .enable_delay_count = 0x03,
- .stable_count = 0x41, .active_delay_count = 0x0A,
- .xtal_freq_count = 0xA4},
+ {
+ .osc_frequency = 13000000, .enable_delay_count = 0x02,
+ .stable_count = 0x33, .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7f
+ }, {
+ .osc_frequency = 19200000, .enable_delay_count = 0x03,
+ .stable_count = 0x4b, .active_delay_count = 0x06,
+ .xtal_freq_count = 0xbb
+ }, {
+ .osc_frequency = 12000000, .enable_delay_count = 0x02,
+ .stable_count = 0x2f, .active_delay_count = 0x04,
+ .xtal_freq_count = 0x76
+ }, {
+ .osc_frequency = 26000000, .enable_delay_count = 0x04,
+ .stable_count = 0x66, .active_delay_count = 0x09,
+ .xtal_freq_count = 0xfe
+ }, {
+ .osc_frequency = 16800000, .enable_delay_count = 0x03,
+ .stable_count = 0x41, .active_delay_count = 0x0a,
+ .xtal_freq_count = 0xa4
+ },
};
static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
@@ -1024,8 +1065,8 @@ static struct clk **clks;
static void tegra124_utmi_param_configure(void __iomem *clk_base)
{
+ unsigned int i;
u32 reg;
- int i;
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (osc_freq == utmi_parameters[i].osc_frequency)
@@ -1356,65 +1397,65 @@ static struct tegra_cpu_car_ops tegra124_cpu_car_ops = {
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra124-pmc" },
- {},
+ { },
};
static struct tegra_clk_init_table common_init_table[] __initdata = {
- {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0},
- {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0},
- {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0},
- {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0},
- {TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1},
- {TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1},
- {TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1},
- {TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1},
- {TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0},
- {TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1},
- {TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0},
- {TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0},
- {TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1},
- {TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1},
- {TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1},
- {TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0},
- {TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0},
- {TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1},
- {TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0},
- {TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0},
- {TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0},
- {TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0},
- {TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0},
- {TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0},
- {TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0},
- {TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
- {TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
- {TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
- {TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
- /* This MUST be the last entry. */
- {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+ { TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0 },
+ { TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0 },
+ { TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0 },
+ { TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0 },
+ { TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1 },
+ { TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1 },
+ { TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1 },
+ { TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1 },
+ { TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1 },
+ { TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0 },
+ { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 },
+ { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 },
+ { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 },
+ { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1 },
+ { TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1 },
+ { TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1 },
+ { TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0 },
+ { TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0 },
+ { TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1 },
+ { TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0 },
+ { TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0 },
+ { TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0 },
+ { TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0 },
+ { TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0 },
+ { TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0 },
+ { TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0 },
+ { TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0 },
+ { TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0 },
+ { TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0 },
+ { TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1 },
+ { TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1 },
+ { TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0 },
+ /* must be the last entry */
+ { TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
};
static struct tegra_clk_init_table tegra124_init_table[] __initdata = {
- {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
- {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_HDA, TEGRA124_CLK_PLL_P, 102000000, 0},
- {TEGRA124_CLK_HDA2CODEC_2X, TEGRA124_CLK_PLL_P, 48000000, 0},
- /* This MUST be the last entry. */
- {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+ { TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0 },
+ { TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1 },
+ { TEGRA124_CLK_HDA, TEGRA124_CLK_PLL_P, 102000000, 0 },
+ { TEGRA124_CLK_HDA2CODEC_2X, TEGRA124_CLK_PLL_P, 48000000, 0 },
+ /* must be the last entry */
+ { TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
};
/* Tegra132 requires the SOC_THERM clock to remain active */
static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
- {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1},
- /* This MUST be the last entry. */
- {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+ { TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1 },
+ /* must be the last entry */
+ { TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
};
static struct tegra_audio_clk_info tegra124_audio_plls[] = {
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index bf004f0e4f65..7a48e986c4c9 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -166,126 +166,120 @@ static DEFINE_SPINLOCK(emc_lock);
static struct clk **clks;
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
- { 12000000, 600000000, 600, 12, 0, 8 },
- { 13000000, 600000000, 600, 13, 0, 8 },
- { 19200000, 600000000, 500, 16, 0, 6 },
- { 26000000, 600000000, 600, 26, 0, 8 },
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 600000000, 600, 12, 1, 8 },
+ { 13000000, 600000000, 600, 13, 1, 8 },
+ { 19200000, 600000000, 500, 16, 1, 6 },
+ { 26000000, 600000000, 600, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 0, 8},
- { 13000000, 666000000, 666, 13, 0, 8},
- { 19200000, 666000000, 555, 16, 0, 8},
- { 26000000, 666000000, 666, 26, 0, 8},
- { 12000000, 600000000, 600, 12, 0, 8},
- { 13000000, 600000000, 600, 13, 0, 8},
- { 19200000, 600000000, 375, 12, 0, 6},
- { 26000000, 600000000, 600, 26, 0, 8},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 666000000, 666, 12, 1, 8 },
+ { 13000000, 666000000, 666, 13, 1, 8 },
+ { 19200000, 666000000, 555, 16, 1, 8 },
+ { 26000000, 666000000, 666, 26, 1, 8 },
+ { 12000000, 600000000, 600, 12, 1, 8 },
+ { 13000000, 600000000, 600, 13, 1, 8 },
+ { 19200000, 600000000, 375, 12, 1, 6 },
+ { 26000000, 600000000, 600, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 1, 8},
- { 13000000, 216000000, 432, 13, 1, 8},
- { 19200000, 216000000, 90, 4, 1, 1},
- { 26000000, 216000000, 432, 26, 1, 8},
- { 12000000, 432000000, 432, 12, 0, 8},
- { 13000000, 432000000, 432, 13, 0, 8},
- { 19200000, 432000000, 90, 4, 0, 1},
- { 26000000, 432000000, 432, 26, 0, 8},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 216000000, 432, 12, 2, 8 },
+ { 13000000, 216000000, 432, 13, 2, 8 },
+ { 19200000, 216000000, 90, 4, 2, 1 },
+ { 26000000, 216000000, 432, 26, 2, 8 },
+ { 12000000, 432000000, 432, 12, 1, 8 },
+ { 13000000, 432000000, 432, 13, 1, 8 },
+ { 19200000, 432000000, 90, 4, 1, 1 },
+ { 26000000, 432000000, 432, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
- { 28800000, 56448000, 49, 25, 0, 1},
- { 28800000, 73728000, 64, 25, 0, 1},
- { 28800000, 24000000, 5, 6, 0, 1},
- { 0, 0, 0, 0, 0, 0 },
+ { 28800000, 56448000, 49, 25, 1, 1 },
+ { 28800000, 73728000, 64, 25, 1, 1 },
+ { 28800000, 24000000, 5, 6, 1, 1 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 0, 4},
- { 13000000, 216000000, 216, 13, 0, 4},
- { 19200000, 216000000, 135, 12, 0, 3},
- { 26000000, 216000000, 216, 26, 0, 4},
-
- { 12000000, 594000000, 594, 12, 0, 8},
- { 13000000, 594000000, 594, 13, 0, 8},
- { 19200000, 594000000, 495, 16, 0, 8},
- { 26000000, 594000000, 594, 26, 0, 8},
-
- { 12000000, 1000000000, 1000, 12, 0, 12},
- { 13000000, 1000000000, 1000, 13, 0, 12},
- { 19200000, 1000000000, 625, 12, 0, 8},
- { 26000000, 1000000000, 1000, 26, 0, 12},
-
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 216000000, 216, 12, 1, 4 },
+ { 13000000, 216000000, 216, 13, 1, 4 },
+ { 19200000, 216000000, 135, 12, 1, 3 },
+ { 26000000, 216000000, 216, 26, 1, 4 },
+ { 12000000, 594000000, 594, 12, 1, 8 },
+ { 13000000, 594000000, 594, 13, 1, 8 },
+ { 19200000, 594000000, 495, 16, 1, 8 },
+ { 26000000, 594000000, 594, 26, 1, 8 },
+ { 12000000, 1000000000, 1000, 12, 1, 12 },
+ { 13000000, 1000000000, 1000, 13, 1, 12 },
+ { 19200000, 1000000000, 625, 12, 1, 8 },
+ { 26000000, 1000000000, 1000, 26, 1, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 0, 0},
- { 13000000, 480000000, 960, 13, 0, 0},
- { 19200000, 480000000, 200, 4, 0, 0},
- { 26000000, 480000000, 960, 26, 0, 0},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 480000000, 960, 12, 1, 0 },
+ { 13000000, 480000000, 960, 13, 1, 0 },
+ { 19200000, 480000000, 200, 4, 1, 0 },
+ { 26000000, 480000000, 960, 26, 1, 0 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 0, 12},
- { 13000000, 1000000000, 1000, 13, 0, 12},
- { 19200000, 1000000000, 625, 12, 0, 8},
- { 26000000, 1000000000, 1000, 26, 0, 12},
-
+ { 12000000, 1000000000, 1000, 12, 1, 12 },
+ { 13000000, 1000000000, 1000, 13, 1, 12 },
+ { 19200000, 1000000000, 625, 12, 1, 8 },
+ { 26000000, 1000000000, 1000, 26, 1, 12 },
/* 912 MHz */
- { 12000000, 912000000, 912, 12, 0, 12},
- { 13000000, 912000000, 912, 13, 0, 12},
- { 19200000, 912000000, 760, 16, 0, 8},
- { 26000000, 912000000, 912, 26, 0, 12},
-
+ { 12000000, 912000000, 912, 12, 1, 12 },
+ { 13000000, 912000000, 912, 13, 1, 12 },
+ { 19200000, 912000000, 760, 16, 1, 8 },
+ { 26000000, 912000000, 912, 26, 1, 12 },
/* 816 MHz */
- { 12000000, 816000000, 816, 12, 0, 12},
- { 13000000, 816000000, 816, 13, 0, 12},
- { 19200000, 816000000, 680, 16, 0, 8},
- { 26000000, 816000000, 816, 26, 0, 12},
-
+ { 12000000, 816000000, 816, 12, 1, 12 },
+ { 13000000, 816000000, 816, 13, 1, 12 },
+ { 19200000, 816000000, 680, 16, 1, 8 },
+ { 26000000, 816000000, 816, 26, 1, 12 },
/* 760 MHz */
- { 12000000, 760000000, 760, 12, 0, 12},
- { 13000000, 760000000, 760, 13, 0, 12},
- { 19200000, 760000000, 950, 24, 0, 8},
- { 26000000, 760000000, 760, 26, 0, 12},
-
+ { 12000000, 760000000, 760, 12, 1, 12 },
+ { 13000000, 760000000, 760, 13, 1, 12 },
+ { 19200000, 760000000, 950, 24, 1, 8 },
+ { 26000000, 760000000, 760, 26, 1, 12 },
/* 750 MHz */
- { 12000000, 750000000, 750, 12, 0, 12},
- { 13000000, 750000000, 750, 13, 0, 12},
- { 19200000, 750000000, 625, 16, 0, 8},
- { 26000000, 750000000, 750, 26, 0, 12},
-
+ { 12000000, 750000000, 750, 12, 1, 12 },
+ { 13000000, 750000000, 750, 13, 1, 12 },
+ { 19200000, 750000000, 625, 16, 1, 8 },
+ { 26000000, 750000000, 750, 26, 1, 12 },
/* 608 MHz */
- { 12000000, 608000000, 608, 12, 0, 12},
- { 13000000, 608000000, 608, 13, 0, 12},
- { 19200000, 608000000, 380, 12, 0, 8},
- { 26000000, 608000000, 608, 26, 0, 12},
-
+ { 12000000, 608000000, 608, 12, 1, 12 },
+ { 13000000, 608000000, 608, 13, 1, 12 },
+ { 19200000, 608000000, 380, 12, 1, 8 },
+ { 26000000, 608000000, 608, 26, 1, 12 },
/* 456 MHz */
- { 12000000, 456000000, 456, 12, 0, 12},
- { 13000000, 456000000, 456, 13, 0, 12},
- { 19200000, 456000000, 380, 16, 0, 8},
- { 26000000, 456000000, 456, 26, 0, 12},
-
+ { 12000000, 456000000, 456, 12, 1, 12 },
+ { 13000000, 456000000, 456, 13, 1, 12 },
+ { 19200000, 456000000, 380, 16, 1, 8 },
+ { 26000000, 456000000, 456, 26, 1, 12 },
/* 312 MHz */
- { 12000000, 312000000, 312, 12, 0, 12},
- { 13000000, 312000000, 312, 13, 0, 12},
- { 19200000, 312000000, 260, 16, 0, 8},
- { 26000000, 312000000, 312, 26, 0, 12},
+ { 12000000, 312000000, 312, 12, 1, 12 },
+ { 13000000, 312000000, 312, 13, 1, 12 },
+ { 19200000, 312000000, 260, 16, 1, 8 },
+ { 26000000, 312000000, 312, 26, 1, 12 },
+ { 0, 0, 0, 0, 0, 0 },
+};
- { 0, 0, 0, 0, 0, 0 },
+static const struct pdiv_map plle_p[] = {
+ { .pdiv = 1, .hw_val = 1 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
- { 12000000, 100000000, 200, 24, 0, 0 },
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 100000000, 200, 24, 1, 0 },
+ { 0, 0, 0, 0, 0, 0 },
};
/* PLL parameters */
@@ -302,7 +296,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_m_params = {
@@ -318,7 +312,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_p_params = {
@@ -334,7 +328,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_p_freq_table,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 216000000,
};
@@ -351,7 +346,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_d_params = {
@@ -367,10 +362,10 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
@@ -390,7 +385,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
.freq_table = pll_u_freq_table,
- .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_x_params = {
@@ -406,7 +401,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_x_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_e_params = {
@@ -421,8 +416,10 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 0,
+ .pdiv_tohw = plle_p,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};
@@ -733,9 +730,9 @@ static void tegra20_super_clk_init(void)
clks[TEGRA20_CLK_TWD] = clk;
}
-static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused",
- "pll_a_out0", "unused", "unused",
- "unused"};
+static const char *audio_parents[] = { "spdif_in", "i2s1", "i2s2", "unused",
+ "pll_a_out0", "unused", "unused",
+ "unused" };
static void __init tegra20_audio_clk_init(void)
{
@@ -759,19 +756,18 @@ static void __init tegra20_audio_clk_init(void)
CLK_SET_RATE_PARENT, 89,
periph_clk_enb_refcnt);
clks[TEGRA20_CLK_AUDIO_2X] = clk;
-
}
-static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
- "clk_m"};
-static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
- "clk_m"};
-static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m",
- "clk_32k"};
-static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"};
-static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c",
- "clk_m"};
-static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"};
+static const char *i2s1_parents[] = { "pll_a_out0", "audio_2x", "pll_p",
+ "clk_m" };
+static const char *i2s2_parents[] = { "pll_a_out0", "audio_2x", "pll_p",
+ "clk_m" };
+static const char *pwm_parents[] = { "pll_p", "pll_c", "audio", "clk_m",
+ "clk_32k" };
+static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" };
+static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c",
+ "clk_m" };
+static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" };
static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("i2s1", i2s1_parents, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S1),
@@ -802,7 +798,7 @@ static void __init tegra20_periph_clk_init(void)
{
struct tegra_periph_init_data *data;
struct clk *clk;
- int i;
+ unsigned int i;
/* ac97 */
clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0",
@@ -1025,44 +1021,45 @@ static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
};
static struct tegra_clk_init_table init_table[] __initdata = {
- {TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1},
- {TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1},
- {TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1},
- {TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1},
- {TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1},
- {TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1},
- {TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1},
- {TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1},
- {TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1},
- {TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1},
- {TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1},
- {TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1},
- {TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1},
- {TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0},
- {TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0},
- {TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0},
- {TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0},
- {TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0},
- {TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1},
- {TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1},
- {TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1},
- {TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1},
- {TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0},
- {TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0},
- {TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0},
- {TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0},
- {TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0},
- {TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0},
- {TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0},
- {TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0},
- {TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0},
- {TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0},
- {TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0},
- {TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0},
- {TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0},
- {TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry */
+ { TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1 },
+ { TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1 },
+ { TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1 },
+ { TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 },
+ { TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 },
+ { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 },
+ { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1 },
+ { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 },
+ { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
+ { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 },
+ { TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 },
+ { TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1 },
+ { TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
+ { TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0 },
+ { TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0 },
+ { TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0 },
+ { TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0 },
+ { TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0 },
+ { TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 },
+ { TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 },
+ { TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 },
+ { TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1 },
+ { TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 },
+ { TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0 },
+ { TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0 },
+ { TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0 },
+ { TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0 },
+ { TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0 },
+ { TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0 },
+ { TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0 },
+ { TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0 },
+ { TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0 },
+ { TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 },
+ { TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 },
+ { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
+ /* must be the last entry */
+ { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
};
static void __init tegra20_clock_apply_init_table(void)
@@ -1076,16 +1073,17 @@ static void __init tegra20_clock_apply_init_table(void)
* table under two names.
*/
static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
- TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "utmip-pad", NULL),
- TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-ehci.0", NULL),
- TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-otg", NULL),
- TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK, NULL, "cpu"),
- TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL, NULL), /* Must be the last entry */
+ TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "utmip-pad", NULL),
+ TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-ehci.0", NULL),
+ TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-otg", NULL),
+ TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK, NULL, "cpu"),
+ /* must be the last entry */
+ TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL, NULL),
};
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-pmc" },
- {},
+ { },
};
static void __init tegra20_clock_init(struct device_node *np)
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
new file mode 100644
index 000000000000..58514c44ea83
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -0,0 +1,2852 @@
+/*
+ * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/clk/tegra.h>
+#include <dt-bindings/clock/tegra210-car.h>
+
+#include "clk.h"
+#include "clk-id.h"
+
+/*
+ * TEGRA210_CAR_BANK_COUNT: the number of peripheral clock register
+ * banks present in the Tegra210 CAR IP block. The banks are
+ * identified by single letters, e.g.: L, H, U, V, W, X, Y. See
+ * periph_regs[] in drivers/clk/tegra/clk.c
+ */
+#define TEGRA210_CAR_BANK_COUNT 7
+
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_EMC 0x19c
+
+#define PLLC_BASE 0x80
+#define PLLC_OUT 0x84
+#define PLLC_MISC0 0x88
+#define PLLC_MISC1 0x8c
+#define PLLC_MISC2 0x5d0
+#define PLLC_MISC3 0x5d4
+
+#define PLLC2_BASE 0x4e8
+#define PLLC2_MISC0 0x4ec
+#define PLLC2_MISC1 0x4f0
+#define PLLC2_MISC2 0x4f4
+#define PLLC2_MISC3 0x4f8
+
+#define PLLC3_BASE 0x4fc
+#define PLLC3_MISC0 0x500
+#define PLLC3_MISC1 0x504
+#define PLLC3_MISC2 0x508
+#define PLLC3_MISC3 0x50c
+
+#define PLLM_BASE 0x90
+#define PLLM_MISC0 0x9c
+#define PLLM_MISC1 0x98
+#define PLLP_BASE 0xa0
+#define PLLP_MISC0 0xac
+#define PLLP_MISC1 0x680
+#define PLLA_BASE 0xb0
+#define PLLA_MISC0 0xbc
+#define PLLA_MISC1 0xb8
+#define PLLA_MISC2 0x5d8
+#define PLLD_BASE 0xd0
+#define PLLD_MISC0 0xdc
+#define PLLD_MISC1 0xd8
+#define PLLU_BASE 0xc0
+#define PLLU_OUTA 0xc4
+#define PLLU_MISC0 0xcc
+#define PLLU_MISC1 0xc8
+#define PLLX_BASE 0xe0
+#define PLLX_MISC0 0xe4
+#define PLLX_MISC1 0x510
+#define PLLX_MISC2 0x514
+#define PLLX_MISC3 0x518
+#define PLLX_MISC4 0x5f0
+#define PLLX_MISC5 0x5f4
+#define PLLE_BASE 0xe8
+#define PLLE_MISC0 0xec
+#define PLLD2_BASE 0x4b8
+#define PLLD2_MISC0 0x4bc
+#define PLLD2_MISC1 0x570
+#define PLLD2_MISC2 0x574
+#define PLLD2_MISC3 0x578
+#define PLLE_AUX 0x48c
+#define PLLRE_BASE 0x4c4
+#define PLLRE_MISC0 0x4c8
+#define PLLDP_BASE 0x590
+#define PLLDP_MISC 0x594
+
+#define PLLC4_BASE 0x5a4
+#define PLLC4_MISC0 0x5a8
+#define PLLC4_OUT 0x5e4
+#define PLLMB_BASE 0x5e8
+#define PLLMB_MISC0 0x5ec
+#define PLLA1_BASE 0x6a4
+#define PLLA1_MISC0 0x6a8
+#define PLLA1_MISC1 0x6ac
+#define PLLA1_MISC2 0x6b0
+#define PLLA1_MISC3 0x6b4
+
+#define PLLU_IDDQ_BIT 31
+#define PLLCX_IDDQ_BIT 27
+#define PLLRE_IDDQ_BIT 24
+#define PLLA_IDDQ_BIT 25
+#define PLLD_IDDQ_BIT 20
+#define PLLSS_IDDQ_BIT 18
+#define PLLM_IDDQ_BIT 5
+#define PLLMB_IDDQ_BIT 17
+#define PLLXP_IDDQ_BIT 3
+
+#define PLLCX_RESET_BIT 30
+
+#define PLL_BASE_LOCK BIT(27)
+#define PLLCX_BASE_LOCK BIT(26)
+#define PLLE_MISC_LOCK BIT(11)
+#define PLLRE_MISC_LOCK BIT(27)
+
+#define PLL_MISC_LOCK_ENABLE 18
+#define PLLC_MISC_LOCK_ENABLE 24
+#define PLLDU_MISC_LOCK_ENABLE 22
+#define PLLU_MISC_LOCK_ENABLE 29
+#define PLLE_MISC_LOCK_ENABLE 9
+#define PLLRE_MISC_LOCK_ENABLE 30
+#define PLLSS_MISC_LOCK_ENABLE 30
+#define PLLP_MISC_LOCK_ENABLE 18
+#define PLLM_MISC_LOCK_ENABLE 4
+#define PLLMB_MISC_LOCK_ENABLE 16
+#define PLLA_MISC_LOCK_ENABLE 28
+#define PLLU_MISC_LOCK_ENABLE 29
+#define PLLD_MISC_LOCK_ENABLE 18
+
+#define PLLA_SDM_DIN_MASK 0xffff
+#define PLLA_SDM_EN_MASK BIT(26)
+
+#define PLLD_SDM_EN_MASK BIT(16)
+
+#define PLLD2_SDM_EN_MASK BIT(31)
+#define PLLD2_SSC_EN_MASK BIT(30)
+
+#define PLLDP_SS_CFG 0x598
+#define PLLDP_SDM_EN_MASK BIT(31)
+#define PLLDP_SSC_EN_MASK BIT(30)
+#define PLLDP_SS_CTRL1 0x59c
+#define PLLDP_SS_CTRL2 0x5a0
+
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP BIT(1)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP BIT(3)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERUP BIT(5)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN BIT(24)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP BIT(25)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
+
+#define UTMIPLL_HW_PWRDN_CFG0 0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK BIT(31)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE BIT(7)
+#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4)
+#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0)
+
+#define PLLU_HW_PWRDN_CFG0 0x530
+#define PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE BIT(28)
+#define PLLU_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24)
+#define PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT BIT(7)
+#define PLLU_HW_PWRDN_CFG0_USE_LOCKDET BIT(6)
+#define PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL BIT(0)
+
+#define XUSB_PLL_CFG0 0x534
+#define XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY 0x3ff
+#define XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK (0x3ff << 14)
+
+#define SPARE_REG0 0x55c
+#define CLK_M_DIVISOR_SHIFT 2
+#define CLK_M_DIVISOR_MASK 0x3
+
+/*
+ * SDM fractional divisor is 16-bit 2's complement signed number within
+ * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned
+ * 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used to
+ * indicate that SDM is disabled.
+ *
+ * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13
+ */
+#define PLL_SDM_COEFF BIT(13)
+#define sdin_din_to_data(din) ((u16)((din) ? : 0xFFFFU))
+#define sdin_data_to_din(dat) (((dat) == 0xFFFFU) ? 0 : (s16)dat)
+
+/* Tegra CPU clock and reset control regs */
+#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
+
+#ifdef CONFIG_PM_SLEEP
+static struct cpu_clk_suspend_context {
+ u32 clk_csite_src;
+} tegra210_cpu_clk_sctx;
+#endif
+
+static void __iomem *clk_base;
+static void __iomem *pmc_base;
+
+static unsigned long osc_freq;
+static unsigned long pll_ref_freq;
+
+static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(pll_e_lock);
+static DEFINE_SPINLOCK(pll_re_lock);
+static DEFINE_SPINLOCK(pll_u_lock);
+static DEFINE_SPINLOCK(emc_lock);
+
+/* possible OSC frequencies in Hz */
+static unsigned long tegra210_input_freq[] = {
+ [5] = 38400000,
+ [8] = 12000000,
+};
+
+static const char *mux_pllmcp_clkm[] = {
+ "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
+};
+#define mux_pllmcp_clkm_idx NULL
+
+#define PLL_ENABLE (1 << 30)
+
+#define PLLCX_MISC1_IDDQ (1 << 27)
+#define PLLCX_MISC0_RESET (1 << 30)
+
+#define PLLCX_MISC0_DEFAULT_VALUE 0x40080000
+#define PLLCX_MISC0_WRITE_MASK 0x400ffffb
+#define PLLCX_MISC1_DEFAULT_VALUE 0x08000000
+#define PLLCX_MISC1_WRITE_MASK 0x08003cff
+#define PLLCX_MISC2_DEFAULT_VALUE 0x1f720f05
+#define PLLCX_MISC2_WRITE_MASK 0xffffff17
+#define PLLCX_MISC3_DEFAULT_VALUE 0x000000c4
+#define PLLCX_MISC3_WRITE_MASK 0x00ffffff
+
+/* PLLA */
+#define PLLA_BASE_IDDQ (1 << 25)
+#define PLLA_BASE_LOCK (1 << 27)
+
+#define PLLA_MISC0_LOCK_ENABLE (1 << 28)
+#define PLLA_MISC0_LOCK_OVERRIDE (1 << 27)
+
+#define PLLA_MISC2_EN_SDM (1 << 26)
+#define PLLA_MISC2_EN_DYNRAMP (1 << 25)
+
+#define PLLA_MISC0_DEFAULT_VALUE 0x12000020
+#define PLLA_MISC0_WRITE_MASK 0x7fffffff
+#define PLLA_MISC2_DEFAULT_VALUE 0x0
+#define PLLA_MISC2_WRITE_MASK 0x06ffffff
+
+/* PLLD */
+#define PLLD_MISC0_EN_SDM (1 << 16)
+#define PLLD_MISC0_LOCK_OVERRIDE (1 << 17)
+#define PLLD_MISC0_LOCK_ENABLE (1 << 18)
+#define PLLD_MISC0_IDDQ (1 << 20)
+#define PLLD_MISC0_DSI_CLKENABLE (1 << 21)
+
+#define PLLD_MISC0_DEFAULT_VALUE 0x00140000
+#define PLLD_MISC0_WRITE_MASK 0x3ff7ffff
+#define PLLD_MISC1_DEFAULT_VALUE 0x20
+#define PLLD_MISC1_WRITE_MASK 0x00ffffff
+
+/* PLLD2 and PLLDP and PLLC4 */
+#define PLLDSS_BASE_LOCK (1 << 27)
+#define PLLDSS_BASE_LOCK_OVERRIDE (1 << 24)
+#define PLLDSS_BASE_IDDQ (1 << 18)
+#define PLLDSS_BASE_REF_SEL_SHIFT 25
+#define PLLDSS_BASE_REF_SEL_MASK (0x3 << PLLDSS_BASE_REF_SEL_SHIFT)
+
+#define PLLDSS_MISC0_LOCK_ENABLE (1 << 30)
+
+#define PLLDSS_MISC1_CFG_EN_SDM (1 << 31)
+#define PLLDSS_MISC1_CFG_EN_SSC (1 << 30)
+
+#define PLLD2_MISC0_DEFAULT_VALUE 0x40000020
+#define PLLD2_MISC1_CFG_DEFAULT_VALUE 0x10000000
+#define PLLD2_MISC2_CTRL1_DEFAULT_VALUE 0x0
+#define PLLD2_MISC3_CTRL2_DEFAULT_VALUE 0x0
+
+#define PLLDP_MISC0_DEFAULT_VALUE 0x40000020
+#define PLLDP_MISC1_CFG_DEFAULT_VALUE 0xc0000000
+#define PLLDP_MISC2_CTRL1_DEFAULT_VALUE 0xf400f0da
+#define PLLDP_MISC3_CTRL2_DEFAULT_VALUE 0x2004f400
+
+#define PLLDSS_MISC0_WRITE_MASK 0x47ffffff
+#define PLLDSS_MISC1_CFG_WRITE_MASK 0xf8000000
+#define PLLDSS_MISC2_CTRL1_WRITE_MASK 0xffffffff
+#define PLLDSS_MISC3_CTRL2_WRITE_MASK 0xffffffff
+
+#define PLLC4_MISC0_DEFAULT_VALUE 0x40000000
+
+/* PLLRE */
+#define PLLRE_MISC0_LOCK_ENABLE (1 << 30)
+#define PLLRE_MISC0_LOCK_OVERRIDE (1 << 29)
+#define PLLRE_MISC0_LOCK (1 << 27)
+#define PLLRE_MISC0_IDDQ (1 << 24)
+
+#define PLLRE_BASE_DEFAULT_VALUE 0x0
+#define PLLRE_MISC0_DEFAULT_VALUE 0x41000000
+
+#define PLLRE_BASE_DEFAULT_MASK 0x1c000000
+#define PLLRE_MISC0_WRITE_MASK 0x67ffffff
+
+/* PLLX */
+#define PLLX_USE_DYN_RAMP 1
+#define PLLX_BASE_LOCK (1 << 27)
+
+#define PLLX_MISC0_FO_G_DISABLE (0x1 << 28)
+#define PLLX_MISC0_LOCK_ENABLE (0x1 << 18)
+
+#define PLLX_MISC2_DYNRAMP_STEPB_SHIFT 24
+#define PLLX_MISC2_DYNRAMP_STEPB_MASK (0xFF << PLLX_MISC2_DYNRAMP_STEPB_SHIFT)
+#define PLLX_MISC2_DYNRAMP_STEPA_SHIFT 16
+#define PLLX_MISC2_DYNRAMP_STEPA_MASK (0xFF << PLLX_MISC2_DYNRAMP_STEPA_SHIFT)
+#define PLLX_MISC2_NDIV_NEW_SHIFT 8
+#define PLLX_MISC2_NDIV_NEW_MASK (0xFF << PLLX_MISC2_NDIV_NEW_SHIFT)
+#define PLLX_MISC2_LOCK_OVERRIDE (0x1 << 4)
+#define PLLX_MISC2_DYNRAMP_DONE (0x1 << 2)
+#define PLLX_MISC2_EN_DYNRAMP (0x1 << 0)
+
+#define PLLX_MISC3_IDDQ (0x1 << 3)
+
+#define PLLX_MISC0_DEFAULT_VALUE PLLX_MISC0_LOCK_ENABLE
+#define PLLX_MISC0_WRITE_MASK 0x10c40000
+#define PLLX_MISC1_DEFAULT_VALUE 0x20
+#define PLLX_MISC1_WRITE_MASK 0x00ffffff
+#define PLLX_MISC2_DEFAULT_VALUE 0x0
+#define PLLX_MISC2_WRITE_MASK 0xffffff11
+#define PLLX_MISC3_DEFAULT_VALUE PLLX_MISC3_IDDQ
+#define PLLX_MISC3_WRITE_MASK 0x01ff0f0f
+#define PLLX_MISC4_DEFAULT_VALUE 0x0
+#define PLLX_MISC4_WRITE_MASK 0x8000ffff
+#define PLLX_MISC5_DEFAULT_VALUE 0x0
+#define PLLX_MISC5_WRITE_MASK 0x0000ffff
+
+#define PLLX_HW_CTRL_CFG 0x548
+#define PLLX_HW_CTRL_CFG_SWCTRL (0x1 << 0)
+
+/* PLLMB */
+#define PLLMB_BASE_LOCK (1 << 27)
+
+#define PLLMB_MISC0_LOCK_OVERRIDE (1 << 18)
+#define PLLMB_MISC0_IDDQ (1 << 17)
+#define PLLMB_MISC0_LOCK_ENABLE (1 << 16)
+
+#define PLLMB_MISC0_DEFAULT_VALUE 0x00030000
+#define PLLMB_MISC0_WRITE_MASK 0x0007ffff
+
+/* PLLP */
+#define PLLP_BASE_OVERRIDE (1 << 28)
+#define PLLP_BASE_LOCK (1 << 27)
+
+#define PLLP_MISC0_LOCK_ENABLE (1 << 18)
+#define PLLP_MISC0_LOCK_OVERRIDE (1 << 17)
+#define PLLP_MISC0_IDDQ (1 << 3)
+
+#define PLLP_MISC1_HSIO_EN_SHIFT 29
+#define PLLP_MISC1_HSIO_EN (1 << PLLP_MISC1_HSIO_EN_SHIFT)
+#define PLLP_MISC1_XUSB_EN_SHIFT 28
+#define PLLP_MISC1_XUSB_EN (1 << PLLP_MISC1_XUSB_EN_SHIFT)
+
+#define PLLP_MISC0_DEFAULT_VALUE 0x00040008
+#define PLLP_MISC1_DEFAULT_VALUE 0x0
+
+#define PLLP_MISC0_WRITE_MASK 0xdc6000f
+#define PLLP_MISC1_WRITE_MASK 0x70ffffff
+
+/* PLLU */
+#define PLLU_BASE_LOCK (1 << 27)
+#define PLLU_BASE_OVERRIDE (1 << 24)
+#define PLLU_BASE_CLKENABLE_USB (1 << 21)
+#define PLLU_BASE_CLKENABLE_HSIC (1 << 22)
+#define PLLU_BASE_CLKENABLE_ICUSB (1 << 23)
+#define PLLU_BASE_CLKENABLE_48M (1 << 25)
+#define PLLU_BASE_CLKENABLE_ALL (PLLU_BASE_CLKENABLE_USB |\
+ PLLU_BASE_CLKENABLE_HSIC |\
+ PLLU_BASE_CLKENABLE_ICUSB |\
+ PLLU_BASE_CLKENABLE_48M)
+
+#define PLLU_MISC0_IDDQ (1 << 31)
+#define PLLU_MISC0_LOCK_ENABLE (1 << 29)
+#define PLLU_MISC1_LOCK_OVERRIDE (1 << 0)
+
+#define PLLU_MISC0_DEFAULT_VALUE 0xa0000000
+#define PLLU_MISC1_DEFAULT_VALUE 0x0
+
+#define PLLU_MISC0_WRITE_MASK 0xbfffffff
+#define PLLU_MISC1_WRITE_MASK 0x00000007
+
+static inline void _pll_misc_chk_default(void __iomem *base,
+ struct tegra_clk_pll_params *params,
+ u8 misc_num, u32 default_val, u32 mask)
+{
+ u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]);
+
+ boot_val &= mask;
+ default_val &= mask;
+ if (boot_val != default_val) {
+ pr_warn("boot misc%d 0x%x: expected 0x%x\n",
+ misc_num, boot_val, default_val);
+ pr_warn(" (comparison mask = 0x%x)\n", mask);
+ params->defaults_set = false;
+ }
+}
+
+/*
+ * PLLCX: PLLC, PLLC2, PLLC3, PLLA1
+ * Hybrid PLLs with dynamic ramp. Dynamic ramp is allowed for any transition
+ * that changes NDIV only, while PLL is already locked.
+ */
+static void pllcx_check_defaults(struct tegra_clk_pll_params *params)
+{
+ u32 default_val;
+
+ default_val = PLLCX_MISC0_DEFAULT_VALUE & (~PLLCX_MISC0_RESET);
+ _pll_misc_chk_default(clk_base, params, 0, default_val,
+ PLLCX_MISC0_WRITE_MASK);
+
+ default_val = PLLCX_MISC1_DEFAULT_VALUE & (~PLLCX_MISC1_IDDQ);
+ _pll_misc_chk_default(clk_base, params, 1, default_val,
+ PLLCX_MISC1_WRITE_MASK);
+
+ default_val = PLLCX_MISC2_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, params, 2, default_val,
+ PLLCX_MISC2_WRITE_MASK);
+
+ default_val = PLLCX_MISC3_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, params, 3, default_val,
+ PLLCX_MISC3_WRITE_MASK);
+}
+
+void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx)
+{
+ pllcx->params->defaults_set = true;
+
+ if (readl_relaxed(clk_base + pllcx->params->base_reg) &
+ PLL_ENABLE) {
+ /* PLL is ON: only check if defaults already set */
+ pllcx_check_defaults(pllcx->params);
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ name);
+ return;
+ }
+
+ /* Defaults assert PLL reset, and set IDDQ */
+ writel_relaxed(PLLCX_MISC0_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[0]);
+ writel_relaxed(PLLCX_MISC1_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[1]);
+ writel_relaxed(PLLCX_MISC2_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[2]);
+ writel_relaxed(PLLCX_MISC3_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[3]);
+ udelay(1);
+}
+
+void _pllc_set_defaults(struct tegra_clk_pll *pllcx)
+{
+ tegra210_pllcx_set_defaults("PLL_C", pllcx);
+}
+
+void _pllc2_set_defaults(struct tegra_clk_pll *pllcx)
+{
+ tegra210_pllcx_set_defaults("PLL_C2", pllcx);
+}
+
+void _pllc3_set_defaults(struct tegra_clk_pll *pllcx)
+{
+ tegra210_pllcx_set_defaults("PLL_C3", pllcx);
+}
+
+void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
+{
+ tegra210_pllcx_set_defaults("PLL_A1", pllcx);
+}
+
+/*
+ * PLLA
+ * PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used.
+ * Fractional SDM is allowed to provide exact audio rates.
+ */
+void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
+{
+ u32 mask;
+ u32 val = readl_relaxed(clk_base + plla->params->base_reg);
+
+ plla->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ if (val & PLLA_BASE_IDDQ) {
+ pr_warn("PLL_A boot enabled with IDDQ set\n");
+ plla->params->defaults_set = false;
+ }
+
+ pr_warn("PLL_A already enabled. Postponing set full defaults\n");
+
+ val = PLLA_MISC0_DEFAULT_VALUE; /* ignore lock enable */
+ mask = PLLA_MISC0_LOCK_ENABLE | PLLA_MISC0_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, plla->params, 0, val,
+ ~mask & PLLA_MISC0_WRITE_MASK);
+
+ val = PLLA_MISC2_DEFAULT_VALUE; /* ignore all but control bit */
+ _pll_misc_chk_default(clk_base, plla->params, 2, val,
+ PLLA_MISC2_EN_DYNRAMP);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLA_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect, disable dynamic ramp and SDM */
+ val |= PLLA_BASE_IDDQ;
+ writel_relaxed(val, clk_base + plla->params->base_reg);
+ writel_relaxed(PLLA_MISC0_DEFAULT_VALUE,
+ clk_base + plla->params->ext_misc_reg[0]);
+ writel_relaxed(PLLA_MISC2_DEFAULT_VALUE,
+ clk_base + plla->params->ext_misc_reg[2]);
+ udelay(1);
+}
+
+/*
+ * PLLD
+ * PLL with fractional SDM.
+ */
+void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
+{
+ u32 val;
+ u32 mask = 0xffff;
+
+ plld->params->defaults_set = true;
+
+ if (readl_relaxed(clk_base + plld->params->base_reg) &
+ PLL_ENABLE) {
+ pr_warn("PLL_D already enabled. Postponing set full defaults\n");
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ val = PLLD_MISC1_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, plld->params, 1,
+ val, PLLD_MISC1_WRITE_MASK);
+
+ /* ignore lock, DSI and SDM controls, make sure IDDQ not set */
+ val = PLLD_MISC0_DEFAULT_VALUE & (~PLLD_MISC0_IDDQ);
+ mask |= PLLD_MISC0_DSI_CLKENABLE | PLLD_MISC0_LOCK_ENABLE |
+ PLLD_MISC0_LOCK_OVERRIDE | PLLD_MISC0_EN_SDM;
+ _pll_misc_chk_default(clk_base, plld->params, 0, val,
+ ~mask & PLLD_MISC0_WRITE_MASK);
+
+ /* Enable lock detect */
+ mask = PLLD_MISC0_LOCK_ENABLE | PLLD_MISC0_LOCK_OVERRIDE;
+ val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLD_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
+ val &= PLLD_MISC0_DSI_CLKENABLE;
+ val |= PLLD_MISC0_DEFAULT_VALUE;
+ /* set IDDQ, enable lock detect, disable SDM */
+ writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
+ writel_relaxed(PLLD_MISC1_DEFAULT_VALUE, clk_base +
+ plld->params->ext_misc_reg[1]);
+ udelay(1);
+}
+
+/*
+ * PLLD2, PLLDP
+ * PLL with fractional SDM and Spread Spectrum (SDM is a must if SSC is used).
+ */
+static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss,
+ u32 misc0_val, u32 misc1_val, u32 misc2_val, u32 misc3_val)
+{
+ u32 default_val;
+ u32 val = readl_relaxed(clk_base + plldss->params->base_reg);
+
+ plldss->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ pll_name);
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ if (val & PLLDSS_BASE_IDDQ) {
+ pr_warn("plldss boot enabled with IDDQ set\n");
+ plldss->params->defaults_set = false;
+ }
+
+ /* ignore lock enable */
+ default_val = misc0_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 0, default_val,
+ PLLDSS_MISC0_WRITE_MASK &
+ (~PLLDSS_MISC0_LOCK_ENABLE));
+
+ /*
+ * If SSC is used, check all settings, otherwise just confirm
+ * that SSC is not used on boot as well. Do nothing when using
+ * this function for PLLC4 that has only MISC0.
+ */
+ if (plldss->params->ssc_ctrl_en_mask) {
+ default_val = misc1_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 1,
+ default_val, PLLDSS_MISC1_CFG_WRITE_MASK);
+ default_val = misc2_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 2,
+ default_val, PLLDSS_MISC2_CTRL1_WRITE_MASK);
+ default_val = misc3_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 3,
+ default_val, PLLDSS_MISC3_CTRL2_WRITE_MASK);
+ } else if (plldss->params->ext_misc_reg[1]) {
+ default_val = misc1_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 1,
+ default_val, PLLDSS_MISC1_CFG_WRITE_MASK &
+ (~PLLDSS_MISC1_CFG_EN_SDM));
+ }
+
+ /* Enable lock detect */
+ if (val & PLLDSS_BASE_LOCK_OVERRIDE) {
+ val &= ~PLLDSS_BASE_LOCK_OVERRIDE;
+ writel_relaxed(val, clk_base +
+ plldss->params->base_reg);
+ }
+
+ val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]);
+ val &= ~PLLDSS_MISC0_LOCK_ENABLE;
+ val |= misc0_val & PLLDSS_MISC0_LOCK_ENABLE;
+ writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect, configure SDM/SSC */
+ val |= PLLDSS_BASE_IDDQ;
+ val &= ~PLLDSS_BASE_LOCK_OVERRIDE;
+ writel_relaxed(val, clk_base + plldss->params->base_reg);
+
+ /* When using this function for PLLC4 exit here */
+ if (!plldss->params->ext_misc_reg[1]) {
+ writel_relaxed(misc0_val, clk_base +
+ plldss->params->ext_misc_reg[0]);
+ udelay(1);
+ return;
+ }
+
+ writel_relaxed(misc0_val, clk_base +
+ plldss->params->ext_misc_reg[0]);
+ /* if SSC used set by 1st enable */
+ writel_relaxed(misc1_val & (~PLLDSS_MISC1_CFG_EN_SSC),
+ clk_base + plldss->params->ext_misc_reg[1]);
+ writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]);
+ writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]);
+ udelay(1);
+}
+
+void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
+{
+ plldss_defaults("PLL_D2", plld2, PLLD2_MISC0_DEFAULT_VALUE,
+ PLLD2_MISC1_CFG_DEFAULT_VALUE,
+ PLLD2_MISC2_CTRL1_DEFAULT_VALUE,
+ PLLD2_MISC3_CTRL2_DEFAULT_VALUE);
+}
+
+void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
+{
+ plldss_defaults("PLL_DP", plldp, PLLDP_MISC0_DEFAULT_VALUE,
+ PLLDP_MISC1_CFG_DEFAULT_VALUE,
+ PLLDP_MISC2_CTRL1_DEFAULT_VALUE,
+ PLLDP_MISC3_CTRL2_DEFAULT_VALUE);
+}
+
+/*
+ * PLLC4
+ * Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support.
+ * VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers.
+ */
+void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
+{
+ plldss_defaults("PLL_C4", pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0);
+}
+
+/*
+ * PLLRE
+ * VCO is exposed to the clock tree directly along with post-divider output
+ */
+void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
+{
+ u32 mask;
+ u32 val = readl_relaxed(clk_base + pllre->params->base_reg);
+
+ pllre->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ val &= PLLRE_BASE_DEFAULT_MASK;
+ if (val != PLLRE_BASE_DEFAULT_VALUE) {
+ pr_warn("pllre boot base 0x%x : expected 0x%x\n",
+ val, PLLRE_BASE_DEFAULT_VALUE);
+ pr_warn("(comparison mask = 0x%x)\n",
+ PLLRE_BASE_DEFAULT_MASK);
+ pllre->params->defaults_set = false;
+ }
+
+ /* Ignore lock enable */
+ val = PLLRE_MISC0_DEFAULT_VALUE & (~PLLRE_MISC0_IDDQ);
+ mask = PLLRE_MISC0_LOCK_ENABLE | PLLRE_MISC0_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, pllre->params, 0, val,
+ ~mask & PLLRE_MISC0_WRITE_MASK);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLRE_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ val &= ~PLLRE_BASE_DEFAULT_MASK;
+ val |= PLLRE_BASE_DEFAULT_VALUE & PLLRE_BASE_DEFAULT_MASK;
+ writel_relaxed(val, clk_base + pllre->params->base_reg);
+ writel_relaxed(PLLRE_MISC0_DEFAULT_VALUE,
+ clk_base + pllre->params->ext_misc_reg[0]);
+ udelay(1);
+}
+
+static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b)
+{
+ unsigned long input_rate;
+
+ if (!IS_ERR_OR_NULL(hw->clk)) {
+ input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
+ /* cf rate */
+ input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
+ } else {
+ input_rate = 38400000;
+ }
+
+ switch (input_rate) {
+ case 12000000:
+ case 12800000:
+ case 13000000:
+ *step_a = 0x2B;
+ *step_b = 0x0B;
+ return;
+ case 19200000:
+ *step_a = 0x12;
+ *step_b = 0x08;
+ return;
+ case 38400000:
+ *step_a = 0x04;
+ *step_b = 0x05;
+ return;
+ default:
+ pr_err("%s: Unexpected reference rate %lu\n",
+ __func__, input_rate);
+ BUG();
+ }
+}
+
+static void pllx_check_defaults(struct tegra_clk_pll *pll)
+{
+ u32 default_val;
+
+ default_val = PLLX_MISC0_DEFAULT_VALUE;
+ /* ignore lock enable */
+ _pll_misc_chk_default(clk_base, pll->params, 0, default_val,
+ PLLX_MISC0_WRITE_MASK & (~PLLX_MISC0_LOCK_ENABLE));
+
+ default_val = PLLX_MISC1_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 1, default_val,
+ PLLX_MISC1_WRITE_MASK);
+
+ /* ignore all but control bit */
+ default_val = PLLX_MISC2_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 2,
+ default_val, PLLX_MISC2_EN_DYNRAMP);
+
+ default_val = PLLX_MISC3_DEFAULT_VALUE & (~PLLX_MISC3_IDDQ);
+ _pll_misc_chk_default(clk_base, pll->params, 3, default_val,
+ PLLX_MISC3_WRITE_MASK);
+
+ default_val = PLLX_MISC4_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 4, default_val,
+ PLLX_MISC4_WRITE_MASK);
+
+ default_val = PLLX_MISC5_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 5, default_val,
+ PLLX_MISC5_WRITE_MASK);
+}
+
+void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
+{
+ u32 val;
+ u32 step_a, step_b;
+
+ pllx->params->defaults_set = true;
+
+ /* Get ready dyn ramp state machine settings */
+ pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b);
+ val = PLLX_MISC2_DEFAULT_VALUE & (~PLLX_MISC2_DYNRAMP_STEPA_MASK) &
+ (~PLLX_MISC2_DYNRAMP_STEPB_MASK);
+ val |= step_a << PLLX_MISC2_DYNRAMP_STEPA_SHIFT;
+ val |= step_b << PLLX_MISC2_DYNRAMP_STEPB_SHIFT;
+
+ if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) {
+ pr_warn("PLL_X already enabled. Postponing set full defaults\n");
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ pllx_check_defaults(pllx);
+
+ /* Configure dyn ramp, disable lock override */
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]);
+ val &= ~PLLX_MISC0_LOCK_ENABLE;
+ val |= PLLX_MISC0_DEFAULT_VALUE & PLLX_MISC0_LOCK_ENABLE;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* Enable lock detect and CPU output */
+ writel_relaxed(PLLX_MISC0_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[0]);
+
+ /* Setup */
+ writel_relaxed(PLLX_MISC1_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[1]);
+
+ /* Configure dyn ramp state machine, disable lock override */
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+
+ /* Set IDDQ */
+ writel_relaxed(PLLX_MISC3_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[3]);
+
+ /* Disable SDM */
+ writel_relaxed(PLLX_MISC4_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[4]);
+ writel_relaxed(PLLX_MISC5_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[5]);
+ udelay(1);
+}
+
+/* PLLMB */
+void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
+{
+ u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg);
+
+ pllmb->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("PLL_MB already enabled. Postponing set full defaults\n");
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ);
+ mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, pllmb->params, 0, val,
+ ~mask & PLLMB_MISC0_WRITE_MASK);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLMB_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE,
+ clk_base + pllmb->params->ext_misc_reg[0]);
+ udelay(1);
+}
+
+/*
+ * PLLP
+ * VCO is exposed to the clock tree directly along with post-divider output.
+ * Both VCO and post-divider output rates are fixed at 408MHz and 204MHz,
+ * respectively.
+ */
+static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled)
+{
+ u32 val, mask;
+
+ /* Ignore lock enable (will be set), make sure not in IDDQ if enabled */
+ val = PLLP_MISC0_DEFAULT_VALUE & (~PLLP_MISC0_IDDQ);
+ mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE;
+ if (!enabled)
+ mask |= PLLP_MISC0_IDDQ;
+ _pll_misc_chk_default(clk_base, pll->params, 0, val,
+ ~mask & PLLP_MISC0_WRITE_MASK);
+
+ /* Ignore branch controls */
+ val = PLLP_MISC1_DEFAULT_VALUE;
+ mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN;
+ _pll_misc_chk_default(clk_base, pll->params, 1, val,
+ ~mask & PLLP_MISC1_WRITE_MASK);
+}
+
+void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
+{
+ u32 mask;
+ u32 val = readl_relaxed(clk_base + pllp->params->base_reg);
+
+ pllp->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("PLL_P already enabled. Postponing set full defaults\n");
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ pllp_check_defaults(pllp, true);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]);
+ mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE;
+ val &= ~mask;
+ val |= PLLP_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ writel_relaxed(PLLP_MISC0_DEFAULT_VALUE,
+ clk_base + pllp->params->ext_misc_reg[0]);
+
+ /* Preserve branch control */
+ val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]);
+ mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN;
+ val &= mask;
+ val |= ~mask & PLLP_MISC1_DEFAULT_VALUE;
+ writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]);
+ udelay(1);
+}
+
+/*
+ * PLLU
+ * VCO is exposed to the clock tree directly along with post-divider output.
+ * Both VCO and post-divider output rates are fixed at 480MHz and 240MHz,
+ * respectively.
+ */
+static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control)
+{
+ u32 val, mask;
+
+ /* Ignore lock enable (will be set) and IDDQ if under h/w control */
+ val = PLLU_MISC0_DEFAULT_VALUE & (~PLLU_MISC0_IDDQ);
+ mask = PLLU_MISC0_LOCK_ENABLE | (hw_control ? PLLU_MISC0_IDDQ : 0);
+ _pll_misc_chk_default(clk_base, pll->params, 0, val,
+ ~mask & PLLU_MISC0_WRITE_MASK);
+
+ val = PLLU_MISC1_DEFAULT_VALUE;
+ mask = PLLU_MISC1_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, pll->params, 1, val,
+ ~mask & PLLU_MISC1_WRITE_MASK);
+}
+
+void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
+{
+ u32 val = readl_relaxed(clk_base + pllu->params->base_reg);
+
+ pllu->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("PLL_U already enabled. Postponing set full defaults\n");
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ pllu_check_defaults(pllu, false);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[0]);
+ val &= ~PLLU_MISC0_LOCK_ENABLE;
+ val |= PLLU_MISC0_DEFAULT_VALUE & PLLU_MISC0_LOCK_ENABLE;
+ writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[0]);
+
+ val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[1]);
+ val &= ~PLLU_MISC1_LOCK_OVERRIDE;
+ val |= PLLU_MISC1_DEFAULT_VALUE & PLLU_MISC1_LOCK_OVERRIDE;
+ writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[1]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ writel_relaxed(PLLU_MISC0_DEFAULT_VALUE,
+ clk_base + pllu->params->ext_misc_reg[0]);
+ writel_relaxed(PLLU_MISC1_DEFAULT_VALUE,
+ clk_base + pllu->params->ext_misc_reg[1]);
+ udelay(1);
+}
+
+#define mask(w) ((1 << (w)) - 1)
+#define divm_mask(p) mask(p->params->div_nmp->divm_width)
+#define divn_mask(p) mask(p->params->div_nmp->divn_width)
+#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
+ mask(p->params->div_nmp->divp_width))
+
+#define divm_shift(p) ((p)->params->div_nmp->divm_shift)
+#define divn_shift(p) ((p)->params->div_nmp->divn_shift)
+#define divp_shift(p) ((p)->params->div_nmp->divp_shift)
+
+#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p))
+#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p))
+#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p))
+
+#define PLL_LOCKDET_DELAY 2 /* Lock detection safety delays */
+static int tegra210_wait_for_mask(struct tegra_clk_pll *pll,
+ u32 reg, u32 mask)
+{
+ int i;
+ u32 val = 0;
+
+ for (i = 0; i < pll->params->lock_delay / PLL_LOCKDET_DELAY + 1; i++) {
+ udelay(PLL_LOCKDET_DELAY);
+ val = readl_relaxed(clk_base + reg);
+ if ((val & mask) == mask) {
+ udelay(PLL_LOCKDET_DELAY);
+ return 0;
+ }
+ }
+ return -ETIMEDOUT;
+}
+
+static int tegra210_pllx_dyn_ramp(struct tegra_clk_pll *pllx,
+ struct tegra_clk_pll_freq_table *cfg)
+{
+ u32 val, base, ndiv_new_mask;
+
+ ndiv_new_mask = (divn_mask(pllx) >> pllx->params->div_nmp->divn_shift)
+ << PLLX_MISC2_NDIV_NEW_SHIFT;
+
+ val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
+ val &= (~ndiv_new_mask);
+ val |= cfg->n << PLLX_MISC2_NDIV_NEW_SHIFT;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+ udelay(1);
+
+ val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
+ val |= PLLX_MISC2_EN_DYNRAMP;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+ udelay(1);
+
+ tegra210_wait_for_mask(pllx, pllx->params->ext_misc_reg[2],
+ PLLX_MISC2_DYNRAMP_DONE);
+
+ base = readl_relaxed(clk_base + pllx->params->base_reg) &
+ (~divn_mask_shifted(pllx));
+ base |= cfg->n << pllx->params->div_nmp->divn_shift;
+ writel_relaxed(base, clk_base + pllx->params->base_reg);
+ udelay(1);
+
+ val &= ~PLLX_MISC2_EN_DYNRAMP;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+ udelay(1);
+
+ pr_debug("%s: dynamic ramp to m = %u n = %u p = %u, Fout = %lu kHz\n",
+ __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p,
+ cfg->input_rate / cfg->m * cfg->n /
+ pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);
+
+ return 0;
+}
+
+/*
+ * Common configuration for PLLs with fixed input divider policy:
+ * - always set fixed M-value based on the reference rate
+ * - always set P-value value 1:1 for output rates above VCO minimum, and
+ * choose minimum necessary P-value for output rates below VCO maximum
+ * - calculate N-value based on selected M and P
+ * - calculate SDM_DIN fractional part
+ */
+static int tegra210_pll_fixed_mdiv_cfg(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long input_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_params *params = pll->params;
+ int p;
+ unsigned long cf, p_rate;
+ u32 pdiv;
+
+ if (!rate)
+ return -EINVAL;
+
+ if (!(params->flags & TEGRA_PLL_VCO_OUT)) {
+ p = DIV_ROUND_UP(params->vco_min, rate);
+ p = params->round_p_to_pdiv(p, &pdiv);
+ } else {
+ p = rate >= params->vco_min ? 1 : -EINVAL;
+ }
+
+ if (IS_ERR_VALUE(p))
+ return -EINVAL;
+
+ cfg->m = tegra_pll_get_fixed_mdiv(hw, input_rate);
+ cfg->p = p;
+
+ /* Store P as HW value, as that is what is expected */
+ cfg->p = tegra_pll_p_div_to_hw(pll, cfg->p);
+
+ p_rate = rate * p;
+ if (p_rate > params->vco_max)
+ p_rate = params->vco_max;
+ cf = input_rate / cfg->m;
+ cfg->n = p_rate / cf;
+
+ cfg->sdm_data = 0;
+ if (params->sdm_ctrl_reg) {
+ unsigned long rem = p_rate - cf * cfg->n;
+ /* If ssc is enabled SDM enabled as well, even for integer n */
+ if (rem || params->ssc_ctrl_reg) {
+ u64 s = rem * PLL_SDM_COEFF;
+
+ do_div(s, cf);
+ s -= PLL_SDM_COEFF / 2;
+ cfg->sdm_data = sdin_din_to_data(s);
+ }
+ }
+
+ cfg->input_rate = input_rate;
+ cfg->output_rate = rate;
+
+ return 0;
+}
+
+/*
+ * clk_pll_set_gain - set gain to m, n to calculate correct VCO rate
+ *
+ * @cfg: struct tegra_clk_pll_freq_table * cfg
+ *
+ * For Normal mode:
+ * Fvco = Fref * NDIV / MDIV
+ *
+ * For fractional mode:
+ * Fvco = Fref * (NDIV + 0.5 + SDM_DIN / PLL_SDM_COEFF) / MDIV
+ */
+static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg)
+{
+ cfg->n = cfg->n * PLL_SDM_COEFF + PLL_SDM_COEFF/2 +
+ sdin_data_to_din(cfg->sdm_data);
+ cfg->m *= PLL_SDM_COEFF;
+}
+
+unsigned long tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
+ unsigned long parent_rate)
+{
+ unsigned long vco_min = params->vco_min;
+
+ params->vco_min += DIV_ROUND_UP(parent_rate, PLL_SDM_COEFF);
+ vco_min = min(vco_min, params->vco_min);
+
+ return vco_min;
+}
+
+static struct div_nmp pllx_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+/*
+ * PLL post divider maps - two types: quasi-linear and exponential
+ * post divider.
+ */
+#define PLL_QLIN_PDIV_MAX 16
+static const struct pdiv_map pll_qlin_pdiv_to_hw[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 9, .hw_val = 7 },
+ { .pdiv = 10, .hw_val = 8 },
+ { .pdiv = 12, .hw_val = 9 },
+ { .pdiv = 15, .hw_val = 10 },
+ { .pdiv = 16, .hw_val = 11 },
+ { .pdiv = 18, .hw_val = 12 },
+ { .pdiv = 20, .hw_val = 13 },
+ { .pdiv = 24, .hw_val = 14 },
+ { .pdiv = 30, .hw_val = 15 },
+ { .pdiv = 32, .hw_val = 16 },
+};
+
+static u32 pll_qlin_p_to_pdiv(u32 p, u32 *pdiv)
+{
+ int i;
+
+ if (p) {
+ for (i = 0; i <= PLL_QLIN_PDIV_MAX; i++) {
+ if (p <= pll_qlin_pdiv_to_hw[i].pdiv) {
+ if (pdiv)
+ *pdiv = i;
+ return pll_qlin_pdiv_to_hw[i].pdiv;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+#define PLL_EXPO_PDIV_MAX 7
+static const struct pdiv_map pll_expo_pdiv_to_hw[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 4, .hw_val = 2 },
+ { .pdiv = 8, .hw_val = 3 },
+ { .pdiv = 16, .hw_val = 4 },
+ { .pdiv = 32, .hw_val = 5 },
+ { .pdiv = 64, .hw_val = 6 },
+ { .pdiv = 128, .hw_val = 7 },
+};
+
+static u32 pll_expo_p_to_pdiv(u32 p, u32 *pdiv)
+{
+ if (p) {
+ u32 i = fls(p);
+
+ if (i == ffs(p))
+ i--;
+
+ if (i <= PLL_EXPO_PDIV_MAX) {
+ if (pdiv)
+ *pdiv = i;
+ return 1 << i;
+ }
+ }
+ return -EINVAL;
+}
+
+static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
+ /* 1 GHz */
+ { 12000000, 1000000000, 166, 1, 1, 0 }, /* actual: 996.0 MHz */
+ { 13000000, 1000000000, 153, 1, 1, 0 }, /* actual: 994.0 MHz */
+ { 38400000, 1000000000, 156, 3, 1, 0 }, /* actual: 998.4 MHz */
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_x_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 1350000000,
+ .vco_max = 3000000000UL,
+ .base_reg = PLLX_BASE,
+ .misc_reg = PLLX_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .ext_misc_reg[0] = PLLX_MISC0,
+ .ext_misc_reg[1] = PLLX_MISC1,
+ .ext_misc_reg[2] = PLLX_MISC2,
+ .ext_misc_reg[3] = PLLX_MISC3,
+ .ext_misc_reg[4] = PLLX_MISC4,
+ .ext_misc_reg[5] = PLLX_MISC5,
+ .iddq_reg = PLLX_MISC3,
+ .iddq_bit_idx = PLLXP_IDDQ_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .mdiv_default = 2,
+ .dyn_ramp_reg = PLLX_MISC2,
+ .stepa_shift = 16,
+ .stepb_shift = 24,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllx_nmp,
+ .freq_table = pll_x_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .dyn_ramp = tegra210_pllx_dyn_ramp,
+ .set_defaults = tegra210_pllx_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllc_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 10,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
+ { 12000000, 510000000, 85, 1, 1, 0 },
+ { 13000000, 510000000, 78, 1, 1, 0 }, /* actual: 507.0 MHz */
+ { 38400000, 510000000, 79, 3, 1, 0 }, /* actual: 505.6 MHz */
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_c_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC_BASE,
+ .misc_reg = PLLC_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_delay = 300,
+ .iddq_reg = PLLC_MISC1,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLC_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC_MISC0,
+ .ext_misc_reg[1] = PLLC_MISC1,
+ .ext_misc_reg[2] = PLLC_MISC2,
+ .ext_misc_reg[3] = PLLC_MISC3,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllc_nmp,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = _pllc_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllcx_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 10,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_c2_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC2_BASE,
+ .misc_reg = PLLC2_MISC0,
+ .iddq_reg = PLLC2_MISC1,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLC2_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .lock_mask = PLLCX_BASE_LOCK,
+ .lock_delay = 300,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllcx_nmp,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC2_MISC0,
+ .ext_misc_reg[1] = PLLC2_MISC1,
+ .ext_misc_reg[2] = PLLC2_MISC2,
+ .ext_misc_reg[3] = PLLC2_MISC3,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = _pllc2_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_c3_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC3_BASE,
+ .misc_reg = PLLC3_MISC0,
+ .lock_mask = PLLCX_BASE_LOCK,
+ .lock_delay = 300,
+ .iddq_reg = PLLC3_MISC1,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLC3_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllcx_nmp,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC3_MISC0,
+ .ext_misc_reg[1] = PLLC3_MISC1,
+ .ext_misc_reg[2] = PLLC3_MISC2,
+ .ext_misc_reg[3] = PLLC3_MISC3,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = _pllc3_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllss_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 19,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_c4_vco_freq_table[] = {
+ { 12000000, 600000000, 50, 1, 0, 0 },
+ { 13000000, 600000000, 46, 1, 0, 0 }, /* actual: 598.0 MHz */
+ { 38400000, 600000000, 62, 4, 0, 0 }, /* actual: 595.2 MHz */
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static const struct clk_div_table pll_vco_post_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 3 },
+ { .val = 3, .div = 4 },
+ { .val = 4, .div = 5 },
+ { .val = 5, .div = 6 },
+ { .val = 6, .div = 8 },
+ { .val = 7, .div = 10 },
+ { .val = 8, .div = 12 },
+ { .val = 9, .div = 16 },
+ { .val = 10, .div = 12 },
+ { .val = 11, .div = 16 },
+ { .val = 12, .div = 20 },
+ { .val = 13, .div = 24 },
+ { .val = 14, .div = 32 },
+ { .val = 0, .div = 0 },
+};
+
+static struct tegra_clk_pll_params pll_c4_vco_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 500000000,
+ .vco_max = 1080000000,
+ .base_reg = PLLC4_BASE,
+ .misc_reg = PLLC4_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC4_MISC0,
+ .iddq_reg = PLLC4_BASE,
+ .iddq_bit_idx = PLLSS_IDDQ_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllss_nmp,
+ .freq_table = pll_c4_vco_freq_table,
+ .set_defaults = tegra210_pllc4_set_defaults,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_VCO_OUT,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
+ { 12000000, 800000000, 66, 1, 0, 0 }, /* actual: 792.0 MHz */
+ { 13000000, 800000000, 61, 1, 0, 0 }, /* actual: 793.0 MHz */
+ { 38400000, 297600000, 93, 4, 2, 0 },
+ { 38400000, 400000000, 125, 4, 2, 0 },
+ { 38400000, 532800000, 111, 4, 1, 0 },
+ { 38400000, 665600000, 104, 3, 1, 0 },
+ { 38400000, 800000000, 125, 3, 1, 0 },
+ { 38400000, 931200000, 97, 4, 0, 0 },
+ { 38400000, 1065600000, 111, 4, 0, 0 },
+ { 38400000, 1200000000, 125, 4, 0, 0 },
+ { 38400000, 1331200000, 104, 3, 0, 0 },
+ { 38400000, 1459200000, 76, 2, 0, 0 },
+ { 38400000, 1600000000, 125, 3, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct div_nmp pllm_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .override_divm_shift = 0,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .override_divn_shift = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+ .override_divp_shift = 27,
+};
+
+static struct tegra_clk_pll_params pll_m_params = {
+ .input_min = 9600000,
+ .input_max = 500000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 800000000,
+ .vco_max = 1866000000,
+ .base_reg = PLLM_BASE,
+ .misc_reg = PLLM_MISC1,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLM_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLM_MISC0,
+ .iddq_bit_idx = PLLM_IDDQ_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLM_MISC0,
+ .ext_misc_reg[0] = PLLM_MISC1,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllm_nmp,
+ .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+ .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
+ .freq_table = pll_m_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_mb_params = {
+ .input_min = 9600000,
+ .input_max = 500000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 800000000,
+ .vco_max = 1866000000,
+ .base_reg = PLLMB_BASE,
+ .misc_reg = PLLMB_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLMB_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLMB_MISC0,
+ .iddq_bit_idx = PLLMB_IDDQ_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLMB_MISC0,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllm_nmp,
+ .freq_table = pll_m_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_pllmb_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+
+static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
+ /* PLLE special case: use cpcon field to store cml divider value */
+ { 672000000, 100000000, 125, 42, 0, 13 },
+ { 624000000, 100000000, 125, 39, 0, 13 },
+ { 336000000, 100000000, 125, 21, 0, 13 },
+ { 312000000, 100000000, 200, 26, 0, 14 },
+ { 38400000, 100000000, 125, 2, 0, 14 },
+ { 12000000, 100000000, 200, 1, 0, 14 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct div_nmp plle_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 24,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_e_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 1600000000,
+ .vco_max = 2500000000U,
+ .base_reg = PLLE_BASE,
+ .misc_reg = PLLE_MISC0,
+ .aux_reg = PLLE_AUX,
+ .lock_mask = PLLE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .div_nmp = &plle_nmp,
+ .freq_table = pll_e_freq_table,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
+ .fixed_rate = 100000000,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_freq_table pll_re_vco_freq_table[] = {
+ { 12000000, 672000000, 56, 1, 0, 0 },
+ { 13000000, 672000000, 51, 1, 0, 0 }, /* actual: 663.0 MHz */
+ { 38400000, 672000000, 70, 4, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct div_nmp pllre_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 16,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_re_vco_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 350000000,
+ .vco_max = 700000000,
+ .base_reg = PLLRE_BASE,
+ .misc_reg = PLLRE_MISC0,
+ .lock_mask = PLLRE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLRE_MISC0,
+ .iddq_reg = PLLRE_MISC0,
+ .iddq_bit_idx = PLLRE_IDDQ_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllre_nmp,
+ .freq_table = pll_re_vco_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+ .set_defaults = tegra210_pllre_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllp_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 10,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
+ { 12000000, 408000000, 34, 1, 0, 0 },
+ { 38400000, 408000000, 85, 8, 0, 0 }, /* cf = 4.8MHz, allowed exception */
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_p_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 350000000,
+ .vco_max = 700000000,
+ .base_reg = PLLP_BASE,
+ .misc_reg = PLLP_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLP_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLP_MISC0,
+ .iddq_bit_idx = PLLXP_IDDQ_BIT,
+ .ext_misc_reg[0] = PLLP_MISC0,
+ .ext_misc_reg[1] = PLLP_MISC1,
+ .div_nmp = &pllp_nmp,
+ .freq_table = pll_p_freq_table,
+ .fixed_rate = 408000000,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+ .set_defaults = tegra210_pllp_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_a1_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLA1_BASE,
+ .misc_reg = PLLA1_MISC0,
+ .lock_mask = PLLCX_BASE_LOCK,
+ .lock_delay = 300,
+ .iddq_reg = PLLA1_MISC0,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLA1_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllc_nmp,
+ .ext_misc_reg[0] = PLLA1_MISC0,
+ .ext_misc_reg[1] = PLLA1_MISC1,
+ .ext_misc_reg[2] = PLLA1_MISC2,
+ .ext_misc_reg[3] = PLLA1_MISC3,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = _plla1_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp plla_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
+ { 12000000, 282240000, 47, 1, 1, 1, 0xf148 }, /* actual: 282240234 */
+ { 12000000, 368640000, 61, 1, 1, 1, 0xfe15 }, /* actual: 368640381 */
+ { 12000000, 240000000, 60, 1, 2, 1, 0 },
+ { 13000000, 282240000, 43, 1, 1, 1, 0xfd7d }, /* actual: 282239807 */
+ { 13000000, 368640000, 56, 1, 1, 1, 0x06d8 }, /* actual: 368640137 */
+ { 13000000, 240000000, 55, 1, 2, 1, 0 }, /* actual: 238.3 MHz */
+ { 38400000, 282240000, 44, 3, 1, 1, 0xf333 }, /* actual: 282239844 */
+ { 38400000, 368640000, 57, 3, 1, 1, 0x0333 }, /* actual: 368639844 */
+ { 38400000, 240000000, 75, 3, 3, 1, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_a_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000,
+ .vco_min = 500000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLA_BASE,
+ .misc_reg = PLLA_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLA_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .iddq_reg = PLLA_BASE,
+ .iddq_bit_idx = PLLA_IDDQ_BIT,
+ .div_nmp = &plla_nmp,
+ .sdm_din_reg = PLLA_MISC1,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLA_MISC2,
+ .sdm_ctrl_en_mask = PLLA_SDM_EN_MASK,
+ .ext_misc_reg[0] = PLLA_MISC0,
+ .ext_misc_reg[1] = PLLA_MISC1,
+ .ext_misc_reg[2] = PLLA_MISC2,
+ .freq_table = pll_a_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_plla_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct div_nmp plld_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 11,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 3,
+};
+
+static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
+ { 12000000, 594000000, 99, 1, 1, 0, 0 },
+ { 13000000, 594000000, 91, 1, 1, 0, 0xfc4f }, /* actual: 594000183 */
+ { 38400000, 594000000, 30, 1, 1, 0, 0x0e00 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_d_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 750000000,
+ .vco_max = 1500000000,
+ .base_reg = PLLD_BASE,
+ .misc_reg = PLLD_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLD_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+ .iddq_reg = PLLD_MISC0,
+ .iddq_bit_idx = PLLD_IDDQ_BIT,
+ .round_p_to_pdiv = pll_expo_p_to_pdiv,
+ .pdiv_tohw = pll_expo_pdiv_to_hw,
+ .div_nmp = &plld_nmp,
+ .sdm_din_reg = PLLD_MISC0,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLD_MISC0,
+ .sdm_ctrl_en_mask = PLLD_SDM_EN_MASK,
+ .ext_misc_reg[0] = PLLD_MISC0,
+ .ext_misc_reg[1] = PLLD_MISC1,
+ .freq_table = pll_d_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .mdiv_default = 1,
+ .set_defaults = tegra210_plld_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct tegra_clk_pll_freq_table tegra210_pll_d2_freq_table[] = {
+ { 12000000, 594000000, 99, 1, 1, 0, 0xf000 },
+ { 13000000, 594000000, 91, 1, 1, 0, 0xfc4f }, /* actual: 594000183 */
+ { 38400000, 594000000, 30, 1, 1, 0, 0x0e00 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+};
+
+/* s/w policy, always tegra_pll_ref */
+static struct tegra_clk_pll_params pll_d2_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 750000000,
+ .vco_max = 1500000000,
+ .base_reg = PLLD2_BASE,
+ .misc_reg = PLLD2_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLD2_BASE,
+ .iddq_bit_idx = PLLSS_IDDQ_BIT,
+ .sdm_din_reg = PLLD2_MISC3,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLD2_MISC1,
+ .sdm_ctrl_en_mask = PLLD2_SDM_EN_MASK,
+ .ssc_ctrl_reg = PLLD2_MISC1,
+ .ssc_ctrl_en_mask = PLLD2_SSC_EN_MASK,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllss_nmp,
+ .ext_misc_reg[0] = PLLD2_MISC0,
+ .ext_misc_reg[1] = PLLD2_MISC1,
+ .ext_misc_reg[2] = PLLD2_MISC2,
+ .ext_misc_reg[3] = PLLD2_MISC3,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .mdiv_default = 1,
+ .freq_table = tegra210_pll_d2_freq_table,
+ .set_defaults = tegra210_plld2_set_defaults,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
+ { 12000000, 270000000, 90, 1, 3, 0, 0xf000 },
+ { 13000000, 270000000, 83, 1, 3, 0, 0xf000 }, /* actual: 269.8 MHz */
+ { 38400000, 270000000, 28, 1, 3, 0, 0xf400 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_dp_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 750000000,
+ .vco_max = 1500000000,
+ .base_reg = PLLDP_BASE,
+ .misc_reg = PLLDP_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLDP_BASE,
+ .iddq_bit_idx = PLLSS_IDDQ_BIT,
+ .sdm_din_reg = PLLDP_SS_CTRL2,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLDP_SS_CFG,
+ .sdm_ctrl_en_mask = PLLDP_SDM_EN_MASK,
+ .ssc_ctrl_reg = PLLDP_SS_CFG,
+ .ssc_ctrl_en_mask = PLLDP_SSC_EN_MASK,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllss_nmp,
+ .ext_misc_reg[0] = PLLDP_MISC,
+ .ext_misc_reg[1] = PLLDP_SS_CFG,
+ .ext_misc_reg[2] = PLLDP_SS_CTRL1,
+ .ext_misc_reg[3] = PLLDP_SS_CTRL2,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .mdiv_default = 1,
+ .freq_table = pll_dp_freq_table,
+ .set_defaults = tegra210_plldp_set_defaults,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct div_nmp pllu_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 16,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
+ { 12000000, 480000000, 40, 1, 0, 0 },
+ { 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */
+ { 38400000, 480000000, 25, 2, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_u_vco_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 350000000,
+ .vco_max = 700000000,
+ .base_reg = PLLU_BASE,
+ .misc_reg = PLLU_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+ .iddq_reg = PLLU_MISC0,
+ .iddq_bit_idx = PLLU_IDDQ_BIT,
+ .ext_misc_reg[0] = PLLU_MISC0,
+ .ext_misc_reg[1] = PLLU_MISC1,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllu_nmp,
+ .freq_table = pll_u_freq_table,
+ .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_VCO_OUT,
+ .set_defaults = tegra210_pllu_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+struct utmi_clk_param {
+ /* Oscillator Frequency in KHz */
+ u32 osc_frequency;
+ /* UTMIP PLL Enable Delay Count */
+ u8 enable_delay_count;
+ /* UTMIP PLL Stable count */
+ u16 stable_count;
+ /* UTMIP PLL Active delay count */
+ u8 active_delay_count;
+ /* UTMIP PLL Xtal frequency count */
+ u16 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+ {
+ .osc_frequency = 38400000, .enable_delay_count = 0x0,
+ .stable_count = 0x0, .active_delay_count = 0x6,
+ .xtal_freq_count = 0x80
+ }, {
+ .osc_frequency = 13000000, .enable_delay_count = 0x02,
+ .stable_count = 0x33, .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7f
+ }, {
+ .osc_frequency = 19200000, .enable_delay_count = 0x03,
+ .stable_count = 0x4b, .active_delay_count = 0x06,
+ .xtal_freq_count = 0xbb
+ }, {
+ .osc_frequency = 12000000, .enable_delay_count = 0x02,
+ .stable_count = 0x2f, .active_delay_count = 0x08,
+ .xtal_freq_count = 0x76
+ }, {
+ .osc_frequency = 26000000, .enable_delay_count = 0x04,
+ .stable_count = 0x66, .active_delay_count = 0x09,
+ .xtal_freq_count = 0xfe
+ }, {
+ .osc_frequency = 16800000, .enable_delay_count = 0x03,
+ .stable_count = 0x41, .active_delay_count = 0x0a,
+ .xtal_freq_count = 0xa4
+ },
+};
+
+static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
+ [tegra_clk_ispb] = { .dt_id = TEGRA210_CLK_ISPB, .present = true },
+ [tegra_clk_rtc] = { .dt_id = TEGRA210_CLK_RTC, .present = true },
+ [tegra_clk_timer] = { .dt_id = TEGRA210_CLK_TIMER, .present = true },
+ [tegra_clk_uarta_8] = { .dt_id = TEGRA210_CLK_UARTA, .present = true },
+ [tegra_clk_sdmmc2_9] = { .dt_id = TEGRA210_CLK_SDMMC2, .present = true },
+ [tegra_clk_i2s1] = { .dt_id = TEGRA210_CLK_I2S1, .present = true },
+ [tegra_clk_i2c1] = { .dt_id = TEGRA210_CLK_I2C1, .present = true },
+ [tegra_clk_sdmmc1_9] = { .dt_id = TEGRA210_CLK_SDMMC1, .present = true },
+ [tegra_clk_sdmmc4_9] = { .dt_id = TEGRA210_CLK_SDMMC4, .present = true },
+ [tegra_clk_pwm] = { .dt_id = TEGRA210_CLK_PWM, .present = true },
+ [tegra_clk_i2s2] = { .dt_id = TEGRA210_CLK_I2S2, .present = true },
+ [tegra_clk_usbd] = { .dt_id = TEGRA210_CLK_USBD, .present = true },
+ [tegra_clk_isp_9] = { .dt_id = TEGRA210_CLK_ISP, .present = true },
+ [tegra_clk_disp2_8] = { .dt_id = TEGRA210_CLK_DISP2, .present = true },
+ [tegra_clk_disp1_8] = { .dt_id = TEGRA210_CLK_DISP1, .present = true },
+ [tegra_clk_host1x_9] = { .dt_id = TEGRA210_CLK_HOST1X, .present = true },
+ [tegra_clk_i2s0] = { .dt_id = TEGRA210_CLK_I2S0, .present = true },
+ [tegra_clk_apbdma] = { .dt_id = TEGRA210_CLK_APBDMA, .present = true },
+ [tegra_clk_kfuse] = { .dt_id = TEGRA210_CLK_KFUSE, .present = true },
+ [tegra_clk_sbc1_9] = { .dt_id = TEGRA210_CLK_SBC1, .present = true },
+ [tegra_clk_sbc2_9] = { .dt_id = TEGRA210_CLK_SBC2, .present = true },
+ [tegra_clk_sbc3_9] = { .dt_id = TEGRA210_CLK_SBC3, .present = true },
+ [tegra_clk_i2c5] = { .dt_id = TEGRA210_CLK_I2C5, .present = true },
+ [tegra_clk_csi] = { .dt_id = TEGRA210_CLK_CSI, .present = true },
+ [tegra_clk_i2c2] = { .dt_id = TEGRA210_CLK_I2C2, .present = true },
+ [tegra_clk_uartc_8] = { .dt_id = TEGRA210_CLK_UARTC, .present = true },
+ [tegra_clk_mipi_cal] = { .dt_id = TEGRA210_CLK_MIPI_CAL, .present = true },
+ [tegra_clk_emc] = { .dt_id = TEGRA210_CLK_EMC, .present = true },
+ [tegra_clk_usb2] = { .dt_id = TEGRA210_CLK_USB2, .present = true },
+ [tegra_clk_bsev] = { .dt_id = TEGRA210_CLK_BSEV, .present = true },
+ [tegra_clk_uartd_8] = { .dt_id = TEGRA210_CLK_UARTD, .present = true },
+ [tegra_clk_i2c3] = { .dt_id = TEGRA210_CLK_I2C3, .present = true },
+ [tegra_clk_sbc4_9] = { .dt_id = TEGRA210_CLK_SBC4, .present = true },
+ [tegra_clk_sdmmc3_9] = { .dt_id = TEGRA210_CLK_SDMMC3, .present = true },
+ [tegra_clk_pcie] = { .dt_id = TEGRA210_CLK_PCIE, .present = true },
+ [tegra_clk_owr_8] = { .dt_id = TEGRA210_CLK_OWR, .present = true },
+ [tegra_clk_afi] = { .dt_id = TEGRA210_CLK_AFI, .present = true },
+ [tegra_clk_csite_8] = { .dt_id = TEGRA210_CLK_CSITE, .present = true },
+ [tegra_clk_soc_therm_8] = { .dt_id = TEGRA210_CLK_SOC_THERM, .present = true },
+ [tegra_clk_dtv] = { .dt_id = TEGRA210_CLK_DTV, .present = true },
+ [tegra_clk_i2cslow] = { .dt_id = TEGRA210_CLK_I2CSLOW, .present = true },
+ [tegra_clk_tsec_8] = { .dt_id = TEGRA210_CLK_TSEC, .present = true },
+ [tegra_clk_xusb_host] = { .dt_id = TEGRA210_CLK_XUSB_HOST, .present = true },
+ [tegra_clk_csus] = { .dt_id = TEGRA210_CLK_CSUS, .present = true },
+ [tegra_clk_mselect] = { .dt_id = TEGRA210_CLK_MSELECT, .present = true },
+ [tegra_clk_tsensor] = { .dt_id = TEGRA210_CLK_TSENSOR, .present = true },
+ [tegra_clk_i2s3] = { .dt_id = TEGRA210_CLK_I2S3, .present = true },
+ [tegra_clk_i2s4] = { .dt_id = TEGRA210_CLK_I2S4, .present = true },
+ [tegra_clk_i2c4] = { .dt_id = TEGRA210_CLK_I2C4, .present = true },
+ [tegra_clk_d_audio] = { .dt_id = TEGRA210_CLK_D_AUDIO, .present = true },
+ [tegra_clk_hda2codec_2x_8] = { .dt_id = TEGRA210_CLK_HDA2CODEC_2X, .present = true },
+ [tegra_clk_spdif_2x] = { .dt_id = TEGRA210_CLK_SPDIF_2X, .present = true },
+ [tegra_clk_actmon] = { .dt_id = TEGRA210_CLK_ACTMON, .present = true },
+ [tegra_clk_extern1] = { .dt_id = TEGRA210_CLK_EXTERN1, .present = true },
+ [tegra_clk_extern2] = { .dt_id = TEGRA210_CLK_EXTERN2, .present = true },
+ [tegra_clk_extern3] = { .dt_id = TEGRA210_CLK_EXTERN3, .present = true },
+ [tegra_clk_sata_oob_8] = { .dt_id = TEGRA210_CLK_SATA_OOB, .present = true },
+ [tegra_clk_sata_8] = { .dt_id = TEGRA210_CLK_SATA, .present = true },
+ [tegra_clk_hda_8] = { .dt_id = TEGRA210_CLK_HDA, .present = true },
+ [tegra_clk_hda2hdmi] = { .dt_id = TEGRA210_CLK_HDA2HDMI, .present = true },
+ [tegra_clk_cilab] = { .dt_id = TEGRA210_CLK_CILAB, .present = true },
+ [tegra_clk_cilcd] = { .dt_id = TEGRA210_CLK_CILCD, .present = true },
+ [tegra_clk_cile] = { .dt_id = TEGRA210_CLK_CILE, .present = true },
+ [tegra_clk_dsialp] = { .dt_id = TEGRA210_CLK_DSIALP, .present = true },
+ [tegra_clk_dsiblp] = { .dt_id = TEGRA210_CLK_DSIBLP, .present = true },
+ [tegra_clk_entropy_8] = { .dt_id = TEGRA210_CLK_ENTROPY, .present = true },
+ [tegra_clk_xusb_ss] = { .dt_id = TEGRA210_CLK_XUSB_SS, .present = true },
+ [tegra_clk_i2c6] = { .dt_id = TEGRA210_CLK_I2C6, .present = true },
+ [tegra_clk_vim2_clk] = { .dt_id = TEGRA210_CLK_VIM2_CLK, .present = true },
+ [tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true },
+ [tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true },
+ [tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true },
+ [tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true },
+ [tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true },
+ [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true },
+ [tegra_clk_pll_g_ref] = { .dt_id = TEGRA210_CLK_PLL_G_REF, .present = true, },
+ [tegra_clk_uartb_8] = { .dt_id = TEGRA210_CLK_UARTB, .present = true },
+ [tegra_clk_vfir] = { .dt_id = TEGRA210_CLK_VFIR, .present = true },
+ [tegra_clk_spdif_in_8] = { .dt_id = TEGRA210_CLK_SPDIF_IN, .present = true },
+ [tegra_clk_spdif_out] = { .dt_id = TEGRA210_CLK_SPDIF_OUT, .present = true },
+ [tegra_clk_vi_10] = { .dt_id = TEGRA210_CLK_VI, .present = true },
+ [tegra_clk_vi_sensor_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR, .present = true },
+ [tegra_clk_fuse] = { .dt_id = TEGRA210_CLK_FUSE, .present = true },
+ [tegra_clk_fuse_burn] = { .dt_id = TEGRA210_CLK_FUSE_BURN, .present = true },
+ [tegra_clk_clk_32k] = { .dt_id = TEGRA210_CLK_CLK_32K, .present = true },
+ [tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true },
+ [tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true },
+ [tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true },
+ [tegra_clk_pll_ref] = { .dt_id = TEGRA210_CLK_PLL_REF, .present = true },
+ [tegra_clk_pll_c] = { .dt_id = TEGRA210_CLK_PLL_C, .present = true },
+ [tegra_clk_pll_c_out1] = { .dt_id = TEGRA210_CLK_PLL_C_OUT1, .present = true },
+ [tegra_clk_pll_c2] = { .dt_id = TEGRA210_CLK_PLL_C2, .present = true },
+ [tegra_clk_pll_c3] = { .dt_id = TEGRA210_CLK_PLL_C3, .present = true },
+ [tegra_clk_pll_m] = { .dt_id = TEGRA210_CLK_PLL_M, .present = true },
+ [tegra_clk_pll_m_out1] = { .dt_id = TEGRA210_CLK_PLL_M_OUT1, .present = true },
+ [tegra_clk_pll_p] = { .dt_id = TEGRA210_CLK_PLL_P, .present = true },
+ [tegra_clk_pll_p_out1] = { .dt_id = TEGRA210_CLK_PLL_P_OUT1, .present = true },
+ [tegra_clk_pll_p_out3] = { .dt_id = TEGRA210_CLK_PLL_P_OUT3, .present = true },
+ [tegra_clk_pll_p_out4_cpu] = { .dt_id = TEGRA210_CLK_PLL_P_OUT4, .present = true },
+ [tegra_clk_pll_p_out_hsio] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_HSIO, .present = true },
+ [tegra_clk_pll_p_out_xusb] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_XUSB, .present = true },
+ [tegra_clk_pll_p_out_cpu] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_CPU, .present = true },
+ [tegra_clk_pll_p_out_adsp] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_ADSP, .present = true },
+ [tegra_clk_pll_a] = { .dt_id = TEGRA210_CLK_PLL_A, .present = true },
+ [tegra_clk_pll_a_out0] = { .dt_id = TEGRA210_CLK_PLL_A_OUT0, .present = true },
+ [tegra_clk_pll_d] = { .dt_id = TEGRA210_CLK_PLL_D, .present = true },
+ [tegra_clk_pll_d_out0] = { .dt_id = TEGRA210_CLK_PLL_D_OUT0, .present = true },
+ [tegra_clk_pll_d2] = { .dt_id = TEGRA210_CLK_PLL_D2, .present = true },
+ [tegra_clk_pll_d2_out0] = { .dt_id = TEGRA210_CLK_PLL_D2_OUT0, .present = true },
+ [tegra_clk_pll_u] = { .dt_id = TEGRA210_CLK_PLL_U, .present = true },
+ [tegra_clk_pll_u_out] = { .dt_id = TEGRA210_CLK_PLL_U_OUT, .present = true },
+ [tegra_clk_pll_u_out1] = { .dt_id = TEGRA210_CLK_PLL_U_OUT1, .present = true },
+ [tegra_clk_pll_u_out2] = { .dt_id = TEGRA210_CLK_PLL_U_OUT2, .present = true },
+ [tegra_clk_pll_u_480m] = { .dt_id = TEGRA210_CLK_PLL_U_480M, .present = true },
+ [tegra_clk_pll_u_60m] = { .dt_id = TEGRA210_CLK_PLL_U_60M, .present = true },
+ [tegra_clk_pll_u_48m] = { .dt_id = TEGRA210_CLK_PLL_U_48M, .present = true },
+ [tegra_clk_pll_x] = { .dt_id = TEGRA210_CLK_PLL_X, .present = true },
+ [tegra_clk_pll_x_out0] = { .dt_id = TEGRA210_CLK_PLL_X_OUT0, .present = true },
+ [tegra_clk_pll_re_vco] = { .dt_id = TEGRA210_CLK_PLL_RE_VCO, .present = true },
+ [tegra_clk_pll_re_out] = { .dt_id = TEGRA210_CLK_PLL_RE_OUT, .present = true },
+ [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC, .present = true },
+ [tegra_clk_i2s0_sync] = { .dt_id = TEGRA210_CLK_I2S0_SYNC, .present = true },
+ [tegra_clk_i2s1_sync] = { .dt_id = TEGRA210_CLK_I2S1_SYNC, .present = true },
+ [tegra_clk_i2s2_sync] = { .dt_id = TEGRA210_CLK_I2S2_SYNC, .present = true },
+ [tegra_clk_i2s3_sync] = { .dt_id = TEGRA210_CLK_I2S3_SYNC, .present = true },
+ [tegra_clk_i2s4_sync] = { .dt_id = TEGRA210_CLK_I2S4_SYNC, .present = true },
+ [tegra_clk_vimclk_sync] = { .dt_id = TEGRA210_CLK_VIMCLK_SYNC, .present = true },
+ [tegra_clk_audio0] = { .dt_id = TEGRA210_CLK_AUDIO0, .present = true },
+ [tegra_clk_audio1] = { .dt_id = TEGRA210_CLK_AUDIO1, .present = true },
+ [tegra_clk_audio2] = { .dt_id = TEGRA210_CLK_AUDIO2, .present = true },
+ [tegra_clk_audio3] = { .dt_id = TEGRA210_CLK_AUDIO3, .present = true },
+ [tegra_clk_audio4] = { .dt_id = TEGRA210_CLK_AUDIO4, .present = true },
+ [tegra_clk_spdif] = { .dt_id = TEGRA210_CLK_SPDIF, .present = true },
+ [tegra_clk_clk_out_1] = { .dt_id = TEGRA210_CLK_CLK_OUT_1, .present = true },
+ [tegra_clk_clk_out_2] = { .dt_id = TEGRA210_CLK_CLK_OUT_2, .present = true },
+ [tegra_clk_clk_out_3] = { .dt_id = TEGRA210_CLK_CLK_OUT_3, .present = true },
+ [tegra_clk_blink] = { .dt_id = TEGRA210_CLK_BLINK, .present = true },
+ [tegra_clk_xusb_gate] = { .dt_id = TEGRA210_CLK_XUSB_GATE, .present = true },
+ [tegra_clk_xusb_host_src_8] = { .dt_id = TEGRA210_CLK_XUSB_HOST_SRC, .present = true },
+ [tegra_clk_xusb_falcon_src_8] = { .dt_id = TEGRA210_CLK_XUSB_FALCON_SRC, .present = true },
+ [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA210_CLK_XUSB_FS_SRC, .present = true },
+ [tegra_clk_xusb_ss_src_8] = { .dt_id = TEGRA210_CLK_XUSB_SS_SRC, .present = true },
+ [tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA210_CLK_XUSB_SS_DIV2, .present = true },
+ [tegra_clk_xusb_dev_src_8] = { .dt_id = TEGRA210_CLK_XUSB_DEV_SRC, .present = true },
+ [tegra_clk_xusb_dev] = { .dt_id = TEGRA210_CLK_XUSB_DEV, .present = true },
+ [tegra_clk_xusb_hs_src_4] = { .dt_id = TEGRA210_CLK_XUSB_HS_SRC, .present = true },
+ [tegra_clk_xusb_ssp_src] = { .dt_id = TEGRA210_CLK_XUSB_SSP_SRC, .present = true },
+ [tegra_clk_usb2_hsic_trk] = { .dt_id = TEGRA210_CLK_USB2_HSIC_TRK, .present = true },
+ [tegra_clk_hsic_trk] = { .dt_id = TEGRA210_CLK_HSIC_TRK, .present = true },
+ [tegra_clk_usb2_trk] = { .dt_id = TEGRA210_CLK_USB2_TRK, .present = true },
+ [tegra_clk_sclk] = { .dt_id = TEGRA210_CLK_SCLK, .present = true },
+ [tegra_clk_sclk_mux] = { .dt_id = TEGRA210_CLK_SCLK_MUX, .present = true },
+ [tegra_clk_hclk] = { .dt_id = TEGRA210_CLK_HCLK, .present = true },
+ [tegra_clk_pclk] = { .dt_id = TEGRA210_CLK_PCLK, .present = true },
+ [tegra_clk_cclk_g] = { .dt_id = TEGRA210_CLK_CCLK_G, .present = true },
+ [tegra_clk_cclk_lp] = { .dt_id = TEGRA210_CLK_CCLK_LP, .present = true },
+ [tegra_clk_dfll_ref] = { .dt_id = TEGRA210_CLK_DFLL_REF, .present = true },
+ [tegra_clk_dfll_soc] = { .dt_id = TEGRA210_CLK_DFLL_SOC, .present = true },
+ [tegra_clk_vi_sensor2_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR2, .present = true },
+ [tegra_clk_pll_p_out5] = { .dt_id = TEGRA210_CLK_PLL_P_OUT5, .present = true },
+ [tegra_clk_pll_c4] = { .dt_id = TEGRA210_CLK_PLL_C4, .present = true },
+ [tegra_clk_pll_dp] = { .dt_id = TEGRA210_CLK_PLL_DP, .present = true },
+ [tegra_clk_audio0_mux] = { .dt_id = TEGRA210_CLK_AUDIO0_MUX, .present = true },
+ [tegra_clk_audio1_mux] = { .dt_id = TEGRA210_CLK_AUDIO1_MUX, .present = true },
+ [tegra_clk_audio2_mux] = { .dt_id = TEGRA210_CLK_AUDIO2_MUX, .present = true },
+ [tegra_clk_audio3_mux] = { .dt_id = TEGRA210_CLK_AUDIO3_MUX, .present = true },
+ [tegra_clk_audio4_mux] = { .dt_id = TEGRA210_CLK_AUDIO4_MUX, .present = true },
+ [tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true },
+ [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_1_MUX, .present = true },
+ [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_2_MUX, .present = true },
+ [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_3_MUX, .present = true },
+ [tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true },
+ [tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true },
+ [tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true },
+ [tegra_clk_sdmmc_legacy] = { .dt_id = TEGRA210_CLK_SDMMC_LEGACY, .present = true },
+ [tegra_clk_tsecb] = { .dt_id = TEGRA210_CLK_TSECB, .present = true },
+ [tegra_clk_uartape] = { .dt_id = TEGRA210_CLK_UARTAPE, .present = true },
+ [tegra_clk_vi_i2c] = { .dt_id = TEGRA210_CLK_VI_I2C, .present = true },
+ [tegra_clk_ape] = { .dt_id = TEGRA210_CLK_APE, .present = true },
+ [tegra_clk_dbgapb] = { .dt_id = TEGRA210_CLK_DBGAPB, .present = true },
+ [tegra_clk_nvdec] = { .dt_id = TEGRA210_CLK_NVDEC, .present = true },
+ [tegra_clk_nvenc] = { .dt_id = TEGRA210_CLK_NVENC, .present = true },
+ [tegra_clk_nvjpg] = { .dt_id = TEGRA210_CLK_NVJPG, .present = true },
+ [tegra_clk_pll_c4_out0] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT0, .present = true },
+ [tegra_clk_pll_c4_out1] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT1, .present = true },
+ [tegra_clk_pll_c4_out2] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT2, .present = true },
+ [tegra_clk_pll_c4_out3] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT3, .present = true },
+};
+
+static struct tegra_devclk devclks[] __initdata = {
+ { .con_id = "clk_m", .dt_id = TEGRA210_CLK_CLK_M },
+ { .con_id = "pll_ref", .dt_id = TEGRA210_CLK_PLL_REF },
+ { .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K },
+ { .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 },
+ { .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 },
+ { .con_id = "pll_c", .dt_id = TEGRA210_CLK_PLL_C },
+ { .con_id = "pll_c_out1", .dt_id = TEGRA210_CLK_PLL_C_OUT1 },
+ { .con_id = "pll_c2", .dt_id = TEGRA210_CLK_PLL_C2 },
+ { .con_id = "pll_c3", .dt_id = TEGRA210_CLK_PLL_C3 },
+ { .con_id = "pll_p", .dt_id = TEGRA210_CLK_PLL_P },
+ { .con_id = "pll_p_out1", .dt_id = TEGRA210_CLK_PLL_P_OUT1 },
+ { .con_id = "pll_p_out2", .dt_id = TEGRA210_CLK_PLL_P_OUT2 },
+ { .con_id = "pll_p_out3", .dt_id = TEGRA210_CLK_PLL_P_OUT3 },
+ { .con_id = "pll_p_out4", .dt_id = TEGRA210_CLK_PLL_P_OUT4 },
+ { .con_id = "pll_m", .dt_id = TEGRA210_CLK_PLL_M },
+ { .con_id = "pll_m_out1", .dt_id = TEGRA210_CLK_PLL_M_OUT1 },
+ { .con_id = "pll_x", .dt_id = TEGRA210_CLK_PLL_X },
+ { .con_id = "pll_x_out0", .dt_id = TEGRA210_CLK_PLL_X_OUT0 },
+ { .con_id = "pll_u", .dt_id = TEGRA210_CLK_PLL_U },
+ { .con_id = "pll_u_out", .dt_id = TEGRA210_CLK_PLL_U_OUT },
+ { .con_id = "pll_u_out1", .dt_id = TEGRA210_CLK_PLL_U_OUT1 },
+ { .con_id = "pll_u_out2", .dt_id = TEGRA210_CLK_PLL_U_OUT2 },
+ { .con_id = "pll_u_480M", .dt_id = TEGRA210_CLK_PLL_U_480M },
+ { .con_id = "pll_u_60M", .dt_id = TEGRA210_CLK_PLL_U_60M },
+ { .con_id = "pll_u_48M", .dt_id = TEGRA210_CLK_PLL_U_48M },
+ { .con_id = "pll_d", .dt_id = TEGRA210_CLK_PLL_D },
+ { .con_id = "pll_d_out0", .dt_id = TEGRA210_CLK_PLL_D_OUT0 },
+ { .con_id = "pll_d2", .dt_id = TEGRA210_CLK_PLL_D2 },
+ { .con_id = "pll_d2_out0", .dt_id = TEGRA210_CLK_PLL_D2_OUT0 },
+ { .con_id = "pll_a", .dt_id = TEGRA210_CLK_PLL_A },
+ { .con_id = "pll_a_out0", .dt_id = TEGRA210_CLK_PLL_A_OUT0 },
+ { .con_id = "pll_re_vco", .dt_id = TEGRA210_CLK_PLL_RE_VCO },
+ { .con_id = "pll_re_out", .dt_id = TEGRA210_CLK_PLL_RE_OUT },
+ { .con_id = "spdif_in_sync", .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC },
+ { .con_id = "i2s0_sync", .dt_id = TEGRA210_CLK_I2S0_SYNC },
+ { .con_id = "i2s1_sync", .dt_id = TEGRA210_CLK_I2S1_SYNC },
+ { .con_id = "i2s2_sync", .dt_id = TEGRA210_CLK_I2S2_SYNC },
+ { .con_id = "i2s3_sync", .dt_id = TEGRA210_CLK_I2S3_SYNC },
+ { .con_id = "i2s4_sync", .dt_id = TEGRA210_CLK_I2S4_SYNC },
+ { .con_id = "vimclk_sync", .dt_id = TEGRA210_CLK_VIMCLK_SYNC },
+ { .con_id = "audio0", .dt_id = TEGRA210_CLK_AUDIO0 },
+ { .con_id = "audio1", .dt_id = TEGRA210_CLK_AUDIO1 },
+ { .con_id = "audio2", .dt_id = TEGRA210_CLK_AUDIO2 },
+ { .con_id = "audio3", .dt_id = TEGRA210_CLK_AUDIO3 },
+ { .con_id = "audio4", .dt_id = TEGRA210_CLK_AUDIO4 },
+ { .con_id = "spdif", .dt_id = TEGRA210_CLK_SPDIF },
+ { .con_id = "spdif_2x", .dt_id = TEGRA210_CLK_SPDIF_2X },
+ { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA210_CLK_EXTERN1 },
+ { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA210_CLK_EXTERN2 },
+ { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA210_CLK_EXTERN3 },
+ { .con_id = "blink", .dt_id = TEGRA210_CLK_BLINK },
+ { .con_id = "cclk_g", .dt_id = TEGRA210_CLK_CCLK_G },
+ { .con_id = "cclk_lp", .dt_id = TEGRA210_CLK_CCLK_LP },
+ { .con_id = "sclk", .dt_id = TEGRA210_CLK_SCLK },
+ { .con_id = "hclk", .dt_id = TEGRA210_CLK_HCLK },
+ { .con_id = "pclk", .dt_id = TEGRA210_CLK_PCLK },
+ { .con_id = "fuse", .dt_id = TEGRA210_CLK_FUSE },
+ { .dev_id = "rtc-tegra", .dt_id = TEGRA210_CLK_RTC },
+ { .dev_id = "timer", .dt_id = TEGRA210_CLK_TIMER },
+ { .con_id = "pll_c4_out0", .dt_id = TEGRA210_CLK_PLL_C4_OUT0 },
+ { .con_id = "pll_c4_out1", .dt_id = TEGRA210_CLK_PLL_C4_OUT1 },
+ { .con_id = "pll_c4_out2", .dt_id = TEGRA210_CLK_PLL_C4_OUT2 },
+ { .con_id = "pll_c4_out3", .dt_id = TEGRA210_CLK_PLL_C4_OUT3 },
+ { .con_id = "dpaux", .dt_id = TEGRA210_CLK_DPAUX },
+ { .con_id = "sor0", .dt_id = TEGRA210_CLK_SOR0 },
+};
+
+static struct tegra_audio_clk_info tegra210_audio_plls[] = {
+ { "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_ref" },
+ { "pll_a1", &pll_a1_params, tegra_clk_pll_a1, "pll_ref" },
+};
+
+static struct clk **clks;
+
+static void tegra210_utmi_param_configure(void __iomem *clk_base)
+{
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+ if (osc_freq == utmi_parameters[i].osc_frequency)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(utmi_parameters)) {
+ pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
+ osc_freq);
+ return;
+ }
+
+ reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
+ reg |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
+ PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
+ PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
+ reg &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
+ PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
+ writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
+
+ reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
+ reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
+ udelay(1);
+
+ reg = readl_relaxed(clk_base + PLLU_BASE);
+ reg &= ~PLLU_BASE_CLKENABLE_USB;
+ writel_relaxed(reg, clk_base + PLLU_BASE);
+
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ udelay(10);
+
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL stable and active counts */
+ /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
+ active_delay_count);
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
+ enable_delay_count);
+
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
+ xtal_freq_count);
+
+ reg |= UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+ udelay(1);
+
+ /* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+ reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP;
+ reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP;
+ reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+ /* Setup HW control of UTMIPLL */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ udelay(1);
+
+ reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
+ reg &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY;
+ writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
+
+ udelay(1);
+
+ /* Enable HW control UTMIPLL */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+}
+
+static __init void tegra210_periph_clk_init(void __iomem *clk_base,
+ void __iomem *pmc_base)
+{
+ struct clk *clk;
+
+ /* xusb_ss_div2 */
+ clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+ 1, 2);
+ clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk;
+
+ /* pll_d_dsi_out */
+ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0,
+ clk_base + PLLD_MISC0, 21, 0, &pll_d_lock);
+ clks[TEGRA210_CLK_PLL_D_DSI_OUT] = clk;
+
+ /* dsia */
+ clk = tegra_clk_register_periph_gate("dsia", "pll_d_dsi_out", 0,
+ clk_base, 0, 48,
+ periph_clk_enb_refcnt);
+ clks[TEGRA210_CLK_DSIA] = clk;
+
+ /* dsib */
+ clk = tegra_clk_register_periph_gate("dsib", "pll_d_dsi_out", 0,
+ clk_base, 0, 82,
+ periph_clk_enb_refcnt);
+ clks[TEGRA210_CLK_DSIB] = clk;
+
+ /* emc mux */
+ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
+ ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ clk_base + CLK_SOURCE_EMC,
+ 29, 3, 0, &emc_lock);
+
+ clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+ &emc_lock);
+ clks[TEGRA210_CLK_MC] = clk;
+
+ /* cml0 */
+ clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
+ 0, 0, &pll_e_lock);
+ clk_register_clkdev(clk, "cml0", NULL);
+ clks[TEGRA210_CLK_CML0] = clk;
+
+ /* cml1 */
+ clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX,
+ 1, 0, &pll_e_lock);
+ clk_register_clkdev(clk, "cml1", NULL);
+ clks[TEGRA210_CLK_CML1] = clk;
+
+ tegra_periph_clk_init(clk_base, pmc_base, tegra210_clks, &pll_p_params);
+}
+
+static void __init tegra210_pll_init(void __iomem *clk_base,
+ void __iomem *pmc)
+{
+ u32 val;
+ struct clk *clk;
+
+ /* PLLC */
+ clk = tegra_clk_register_pllxc_tegra210("pll_c", "pll_ref", clk_base,
+ pmc, 0, &pll_c_params, NULL);
+ if (!WARN_ON(IS_ERR(clk)))
+ clk_register_clkdev(clk, "pll_c", NULL);
+ clks[TEGRA210_CLK_PLL_C] = clk;
+
+ /* PLLC_OUT1 */
+ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c",
+ clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div",
+ clk_base + PLLC_OUT, 1, 0,
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_c_out1", NULL);
+ clks[TEGRA210_CLK_PLL_C_OUT1] = clk;
+
+ /* PLLC_UD */
+ clk = clk_register_fixed_factor(NULL, "pll_c_ud", "pll_c",
+ CLK_SET_RATE_PARENT, 1, 1);
+ clk_register_clkdev(clk, "pll_c_ud", NULL);
+ clks[TEGRA210_CLK_PLL_C_UD] = clk;
+
+ /* PLLC2 */
+ clk = tegra_clk_register_pllc_tegra210("pll_c2", "pll_ref", clk_base,
+ pmc, 0, &pll_c2_params, NULL);
+ clk_register_clkdev(clk, "pll_c2", NULL);
+ clks[TEGRA210_CLK_PLL_C2] = clk;
+
+ /* PLLC3 */
+ clk = tegra_clk_register_pllc_tegra210("pll_c3", "pll_ref", clk_base,
+ pmc, 0, &pll_c3_params, NULL);
+ clk_register_clkdev(clk, "pll_c3", NULL);
+ clks[TEGRA210_CLK_PLL_C3] = clk;
+
+ /* PLLM */
+ clk = tegra_clk_register_pllm("pll_m", "osc", clk_base, pmc,
+ CLK_SET_RATE_GATE, &pll_m_params, NULL);
+ clk_register_clkdev(clk, "pll_m", NULL);
+ clks[TEGRA210_CLK_PLL_M] = clk;
+
+ /* PLLMB */
+ clk = tegra_clk_register_pllmb("pll_mb", "osc", clk_base, pmc,
+ CLK_SET_RATE_GATE, &pll_mb_params, NULL);
+ clk_register_clkdev(clk, "pll_mb", NULL);
+ clks[TEGRA210_CLK_PLL_MB] = clk;
+
+ clk_register_clkdev(clk, "pll_m_out1", NULL);
+ clks[TEGRA210_CLK_PLL_M_OUT1] = clk;
+
+ /* PLLM_UD */
+ clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m",
+ CLK_SET_RATE_PARENT, 1, 1);
+ clk_register_clkdev(clk, "pll_m_ud", NULL);
+ clks[TEGRA210_CLK_PLL_M_UD] = clk;
+
+ /* PLLU_VCO */
+ val = readl(clk_base + pll_u_vco_params.base_reg);
+ val &= ~BIT(24); /* disable PLLU_OVERRIDE */
+ writel(val, clk_base + pll_u_vco_params.base_reg);
+
+ clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc,
+ 0, &pll_u_vco_params, &pll_u_lock, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_u_vco", NULL);
+ clks[TEGRA210_CLK_PLL_U] = clk;
+
+ /* PLLU_OUT */
+ clk = clk_register_divider_table(NULL, "pll_u_out", "pll_u_vco", 0,
+ clk_base + PLLU_BASE, 16, 4, 0,
+ pll_vco_post_div_table, NULL);
+ clk_register_clkdev(clk, "pll_u_out", NULL);
+ clks[TEGRA210_CLK_PLL_U_OUT] = clk;
+
+ /* PLLU_OUT1 */
+ clk = tegra_clk_register_divider("pll_u_out1_div", "pll_u_out",
+ clk_base + PLLU_OUTA, 0,
+ TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, &pll_u_lock);
+ clk = tegra_clk_register_pll_out("pll_u_out1", "pll_u_out1_div",
+ clk_base + PLLU_OUTA, 1, 0,
+ CLK_SET_RATE_PARENT, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_out1", NULL);
+ clks[TEGRA210_CLK_PLL_U_OUT1] = clk;
+
+ /* PLLU_OUT2 */
+ clk = tegra_clk_register_divider("pll_u_out2_div", "pll_u_out",
+ clk_base + PLLU_OUTA, 0,
+ TEGRA_DIVIDER_ROUND_UP,
+ 24, 8, 1, &pll_u_lock);
+ clk = tegra_clk_register_pll_out("pll_u_out2", "pll_u_out2_div",
+ clk_base + PLLU_OUTA, 17, 16,
+ CLK_SET_RATE_PARENT, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_out2", NULL);
+ clks[TEGRA210_CLK_PLL_U_OUT2] = clk;
+
+ tegra210_utmi_param_configure(clk_base);
+
+ /* PLLU_480M */
+ clk = clk_register_gate(NULL, "pll_u_480M", "pll_u_vco",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 22, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_480M", NULL);
+ clks[TEGRA210_CLK_PLL_U_480M] = clk;
+
+ /* PLLU_60M */
+ clk = clk_register_gate(NULL, "pll_u_60M", "pll_u_out2",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 23, 0, NULL);
+ clk_register_clkdev(clk, "pll_u_60M", NULL);
+ clks[TEGRA210_CLK_PLL_U_60M] = clk;
+
+ /* PLLU_48M */
+ clk = clk_register_gate(NULL, "pll_u_48M", "pll_u_out1",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 25, 0, NULL);
+ clk_register_clkdev(clk, "pll_u_48M", NULL);
+ clks[TEGRA210_CLK_PLL_U_48M] = clk;
+
+ /* PLLD */
+ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0,
+ &pll_d_params, &pll_d_lock);
+ clk_register_clkdev(clk, "pll_d", NULL);
+ clks[TEGRA210_CLK_PLL_D] = clk;
+
+ /* PLLD_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d_out0", NULL);
+ clks[TEGRA210_CLK_PLL_D_OUT0] = clk;
+
+ /* PLLRE */
+ clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc,
+ 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_re_vco", NULL);
+ clks[TEGRA210_CLK_PLL_RE_VCO] = clk;
+
+ clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0,
+ clk_base + PLLRE_BASE, 16, 5, 0,
+ pll_vco_post_div_table, &pll_re_lock);
+ clk_register_clkdev(clk, "pll_re_out", NULL);
+ clks[TEGRA210_CLK_PLL_RE_OUT] = clk;
+
+ /* PLLE */
+ clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref",
+ clk_base, 0, &pll_e_params, NULL);
+ clk_register_clkdev(clk, "pll_e", NULL);
+ clks[TEGRA210_CLK_PLL_E] = clk;
+
+ /* PLLC4 */
+ clk = tegra_clk_register_pllre("pll_c4_vco", "pll_ref", clk_base, pmc,
+ 0, &pll_c4_vco_params, NULL, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_c4_vco", NULL);
+ clks[TEGRA210_CLK_PLL_C4] = clk;
+
+ /* PLLC4_OUT0 */
+ clk = clk_register_divider_table(NULL, "pll_c4_out0", "pll_c4_vco", 0,
+ clk_base + PLLC4_BASE, 19, 4, 0,
+ pll_vco_post_div_table, NULL);
+ clk_register_clkdev(clk, "pll_c4_out0", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT0] = clk;
+
+ /* PLLC4_OUT1 */
+ clk = clk_register_fixed_factor(NULL, "pll_c4_out1", "pll_c4_vco",
+ CLK_SET_RATE_PARENT, 1, 3);
+ clk_register_clkdev(clk, "pll_c4_out1", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT1] = clk;
+
+ /* PLLC4_OUT2 */
+ clk = clk_register_fixed_factor(NULL, "pll_c4_out2", "pll_c4_vco",
+ CLK_SET_RATE_PARENT, 1, 5);
+ clk_register_clkdev(clk, "pll_c4_out2", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT2] = clk;
+
+ /* PLLC4_OUT3 */
+ clk = tegra_clk_register_divider("pll_c4_out3_div", "pll_c4_out0",
+ clk_base + PLLC4_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c4_out3", "pll_c4_out3_div",
+ clk_base + PLLC4_OUT, 1, 0,
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_c4_out3", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT3] = clk;
+
+ /* PLLDP */
+ clk = tegra_clk_register_pllss_tegra210("pll_dp", "pll_ref", clk_base,
+ 0, &pll_dp_params, NULL);
+ clk_register_clkdev(clk, "pll_dp", NULL);
+ clks[TEGRA210_CLK_PLL_DP] = clk;
+
+ /* PLLD2 */
+ clk = tegra_clk_register_pllss_tegra210("pll_d2", "pll_ref", clk_base,
+ 0, &pll_d2_params, NULL);
+ clk_register_clkdev(clk, "pll_d2", NULL);
+ clks[TEGRA210_CLK_PLL_D2] = clk;
+
+ /* PLLD2_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
+ CLK_SET_RATE_PARENT, 1, 1);
+ clk_register_clkdev(clk, "pll_d2_out0", NULL);
+ clks[TEGRA210_CLK_PLL_D2_OUT0] = clk;
+
+ /* PLLP_OUT2 */
+ clk = clk_register_fixed_factor(NULL, "pll_p_out2", "pll_p",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_p_out2", NULL);
+ clks[TEGRA210_CLK_PLL_P_OUT2] = clk;
+
+}
+
+/* Tegra210 CPU clock and reset control functions */
+static void tegra210_wait_cpu_in_reset(u32 cpu)
+{
+ unsigned int reg;
+
+ do {
+ reg = readl(clk_base + CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+ cpu_relax();
+ } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
+}
+
+static void tegra210_disable_cpu_clock(u32 cpu)
+{
+ /* flow controller would take care in the power sequence. */
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void tegra210_cpu_clock_suspend(void)
+{
+ /* switch coresite to clk_m, save off original source */
+ tegra210_cpu_clk_sctx.clk_csite_src =
+ readl(clk_base + CLK_SOURCE_CSITE);
+ writel(3 << 30, clk_base + CLK_SOURCE_CSITE);
+}
+
+static void tegra210_cpu_clock_resume(void)
+{
+ writel(tegra210_cpu_clk_sctx.clk_csite_src,
+ clk_base + CLK_SOURCE_CSITE);
+}
+#endif
+
+static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
+ .wait_for_reset = tegra210_wait_cpu_in_reset,
+ .disable_clock = tegra210_disable_cpu_clock,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = tegra210_cpu_clock_suspend,
+ .resume = tegra210_cpu_clock_resume,
+#endif
+};
+
+static const struct of_device_id pmc_match[] __initconst = {
+ { .compatible = "nvidia,tegra210-pmc" },
+ { },
+};
+
+static struct tegra_clk_init_table init_table[] __initdata = {
+ { TEGRA210_CLK_UARTA, TEGRA210_CLK_PLL_P, 408000000, 0 },
+ { TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0 },
+ { TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0 },
+ { TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0 },
+ { TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1 },
+ { TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1 },
+ { TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1 },
+ { TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1 },
+ { TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1 },
+ { TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA210_CLK_I2S3, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1 },
+ { TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1 },
+ { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1 },
+ { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 },
+ { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
+ { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
+ { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
+ { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
+ { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
+ { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
+ { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
+ { TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
+ { TEGRA210_CLK_XUSB_HS_SRC, TEGRA210_CLK_XUSB_SS_SRC, 120000000, 0 },
+ { TEGRA210_CLK_XUSB_SSP_SRC, TEGRA210_CLK_XUSB_SS_SRC, 120000000, 0 },
+ { TEGRA210_CLK_XUSB_FALCON_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 204000000, 0 },
+ { TEGRA210_CLK_XUSB_HOST_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 },
+ { TEGRA210_CLK_XUSB_DEV_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 },
+ { TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0 },
+ { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0 },
+ { TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1 },
+ { TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1 },
+ { TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1 },
+ { TEGRA210_CLK_TSENSOR, TEGRA210_CLK_CLK_M, 400000, 0 },
+ { TEGRA210_CLK_I2C1, TEGRA210_CLK_PLL_P, 0, 0 },
+ { TEGRA210_CLK_I2C2, TEGRA210_CLK_PLL_P, 0, 0 },
+ { TEGRA210_CLK_I2C3, TEGRA210_CLK_PLL_P, 0, 0 },
+ { TEGRA210_CLK_I2C4, TEGRA210_CLK_PLL_P, 0, 0 },
+ { TEGRA210_CLK_I2C5, TEGRA210_CLK_PLL_P, 0, 0 },
+ { TEGRA210_CLK_I2C6, TEGRA210_CLK_PLL_P, 0, 0 },
+ { TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 },
+ { TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 },
+ { TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 },
+ /* This MUST be the last entry. */
+ { TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 },
+};
+
+/**
+ * tegra210_clock_apply_init_table - initialize clocks on Tegra210 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra210 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
+static void __init tegra210_clock_apply_init_table(void)
+{
+ tegra_init_from_table(init_table, clks, TEGRA210_CLK_CLK_MAX);
+}
+
+/**
+ * tegra210_clock_init - Tegra210-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra210 system-on-chip. Intended
+ * to be called by the OF init code when a DT node with the
+ * "nvidia,tegra210-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra210_clock_init(struct device_node *np)
+{
+ struct device_node *node;
+ u32 value, clk_m_div;
+
+ clk_base = of_iomap(np, 0);
+ if (!clk_base) {
+ pr_err("ioremap tegra210 CAR failed\n");
+ return;
+ }
+
+ node = of_find_matching_node(NULL, pmc_match);
+ if (!node) {
+ pr_err("Failed to find pmc node\n");
+ WARN_ON(1);
+ return;
+ }
+
+ pmc_base = of_iomap(node, 0);
+ if (!pmc_base) {
+ pr_err("Can't map pmc registers\n");
+ WARN_ON(1);
+ return;
+ }
+
+ clks = tegra_clk_init(clk_base, TEGRA210_CLK_CLK_MAX,
+ TEGRA210_CAR_BANK_COUNT);
+ if (!clks)
+ return;
+
+ value = clk_readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT;
+ clk_m_div = (value & CLK_M_DIVISOR_MASK) + 1;
+
+ if (tegra_osc_clk_init(clk_base, tegra210_clks, tegra210_input_freq,
+ ARRAY_SIZE(tegra210_input_freq), clk_m_div,
+ &osc_freq, &pll_ref_freq) < 0)
+ return;
+
+ tegra_fixed_clk_init(tegra210_clks);
+ tegra210_pll_init(clk_base, pmc_base);
+ tegra210_periph_clk_init(clk_base, pmc_base);
+ tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks,
+ tegra210_audio_plls,
+ ARRAY_SIZE(tegra210_audio_plls));
+ tegra_pmc_clk_init(pmc_base, tegra210_clks);
+
+ /* For Tegra210, PLLD is the only source for DSIA & DSIB */
+ value = clk_readl(clk_base + PLLD_BASE);
+ value &= ~BIT(25);
+ clk_writel(value, clk_base + PLLD_BASE);
+
+ tegra_clk_apply_init_table = tegra210_clock_apply_init_table;
+
+ tegra_super_clk_gen5_init(clk_base, pmc_base, tegra210_clks,
+ &pll_x_params);
+ tegra_add_of_provider(np);
+ tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
+
+ tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+}
+CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index b90db615c29e..0478565cf292 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -224,188 +224,192 @@ struct utmi_clk_param {
};
static const struct utmi_clk_param utmi_parameters[] = {
-/* OSC_FREQUENCY, ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT */
- {13000000, 0x02, 0x33, 0x05, 0x7F},
- {19200000, 0x03, 0x4B, 0x06, 0xBB},
- {12000000, 0x02, 0x2F, 0x04, 0x76},
- {26000000, 0x04, 0x66, 0x09, 0xFE},
- {16800000, 0x03, 0x41, 0x0A, 0xA4},
+ {
+ .osc_frequency = 13000000, .enable_delay_count = 0x02,
+ .stable_count = 0x33, .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7f
+ }, {
+ .osc_frequency = 19200000, .enable_delay_count = 0x03,
+ .stable_count = 0x4b, .active_delay_count = 0x06,
+ .xtal_freq_count = 0xbb
+ }, {
+ .osc_frequency = 12000000, .enable_delay_count = 0x02,
+ .stable_count = 0x2f, .active_delay_count = 0x04,
+ .xtal_freq_count = 0x76
+ }, {
+ .osc_frequency = 26000000, .enable_delay_count = 0x04,
+ .stable_count = 0x66, .active_delay_count = 0x09,
+ .xtal_freq_count = 0xfe
+ }, {
+ .osc_frequency = 16800000, .enable_delay_count = 0x03,
+ .stable_count = 0x41, .active_delay_count = 0x0a,
+ .xtal_freq_count = 0xa4
+ },
};
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
- { 12000000, 1040000000, 520, 6, 0, 8},
- { 13000000, 1040000000, 480, 6, 0, 8},
- { 16800000, 1040000000, 495, 8, 0, 8}, /* actual: 1039.5 MHz */
- { 19200000, 1040000000, 325, 6, 0, 6},
- { 26000000, 1040000000, 520, 13, 0, 8},
-
- { 12000000, 832000000, 416, 6, 0, 8},
- { 13000000, 832000000, 832, 13, 0, 8},
- { 16800000, 832000000, 396, 8, 0, 8}, /* actual: 831.6 MHz */
- { 19200000, 832000000, 260, 6, 0, 8},
- { 26000000, 832000000, 416, 13, 0, 8},
-
- { 12000000, 624000000, 624, 12, 0, 8},
- { 13000000, 624000000, 624, 13, 0, 8},
- { 16800000, 600000000, 520, 14, 0, 8},
- { 19200000, 624000000, 520, 16, 0, 8},
- { 26000000, 624000000, 624, 26, 0, 8},
-
- { 12000000, 600000000, 600, 12, 0, 8},
- { 13000000, 600000000, 600, 13, 0, 8},
- { 16800000, 600000000, 500, 14, 0, 8},
- { 19200000, 600000000, 375, 12, 0, 6},
- { 26000000, 600000000, 600, 26, 0, 8},
-
- { 12000000, 520000000, 520, 12, 0, 8},
- { 13000000, 520000000, 520, 13, 0, 8},
- { 16800000, 520000000, 495, 16, 0, 8}, /* actual: 519.75 MHz */
- { 19200000, 520000000, 325, 12, 0, 6},
- { 26000000, 520000000, 520, 26, 0, 8},
-
- { 12000000, 416000000, 416, 12, 0, 8},
- { 13000000, 416000000, 416, 13, 0, 8},
- { 16800000, 416000000, 396, 16, 0, 8}, /* actual: 415.8 MHz */
- { 19200000, 416000000, 260, 12, 0, 6},
- { 26000000, 416000000, 416, 26, 0, 8},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 1040000000, 520, 6, 1, 8 },
+ { 13000000, 1040000000, 480, 6, 1, 8 },
+ { 16800000, 1040000000, 495, 8, 1, 8 }, /* actual: 1039.5 MHz */
+ { 19200000, 1040000000, 325, 6, 1, 6 },
+ { 26000000, 1040000000, 520, 13, 1, 8 },
+ { 12000000, 832000000, 416, 6, 1, 8 },
+ { 13000000, 832000000, 832, 13, 1, 8 },
+ { 16800000, 832000000, 396, 8, 1, 8 }, /* actual: 831.6 MHz */
+ { 19200000, 832000000, 260, 6, 1, 8 },
+ { 26000000, 832000000, 416, 13, 1, 8 },
+ { 12000000, 624000000, 624, 12, 1, 8 },
+ { 13000000, 624000000, 624, 13, 1, 8 },
+ { 16800000, 600000000, 520, 14, 1, 8 },
+ { 19200000, 624000000, 520, 16, 1, 8 },
+ { 26000000, 624000000, 624, 26, 1, 8 },
+ { 12000000, 600000000, 600, 12, 1, 8 },
+ { 13000000, 600000000, 600, 13, 1, 8 },
+ { 16800000, 600000000, 500, 14, 1, 8 },
+ { 19200000, 600000000, 375, 12, 1, 6 },
+ { 26000000, 600000000, 600, 26, 1, 8 },
+ { 12000000, 520000000, 520, 12, 1, 8 },
+ { 13000000, 520000000, 520, 13, 1, 8 },
+ { 16800000, 520000000, 495, 16, 1, 8 }, /* actual: 519.75 MHz */
+ { 19200000, 520000000, 325, 12, 1, 6 },
+ { 26000000, 520000000, 520, 26, 1, 8 },
+ { 12000000, 416000000, 416, 12, 1, 8 },
+ { 13000000, 416000000, 416, 13, 1, 8 },
+ { 16800000, 416000000, 396, 16, 1, 8 }, /* actual: 415.8 MHz */
+ { 19200000, 416000000, 260, 12, 1, 6 },
+ { 26000000, 416000000, 416, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 0, 8},
- { 13000000, 666000000, 666, 13, 0, 8},
- { 16800000, 666000000, 555, 14, 0, 8},
- { 19200000, 666000000, 555, 16, 0, 8},
- { 26000000, 666000000, 666, 26, 0, 8},
- { 12000000, 600000000, 600, 12, 0, 8},
- { 13000000, 600000000, 600, 13, 0, 8},
- { 16800000, 600000000, 500, 14, 0, 8},
- { 19200000, 600000000, 375, 12, 0, 6},
- { 26000000, 600000000, 600, 26, 0, 8},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 666000000, 666, 12, 1, 8 },
+ { 13000000, 666000000, 666, 13, 1, 8 },
+ { 16800000, 666000000, 555, 14, 1, 8 },
+ { 19200000, 666000000, 555, 16, 1, 8 },
+ { 26000000, 666000000, 666, 26, 1, 8 },
+ { 12000000, 600000000, 600, 12, 1, 8 },
+ { 13000000, 600000000, 600, 13, 1, 8 },
+ { 16800000, 600000000, 500, 14, 1, 8 },
+ { 19200000, 600000000, 375, 12, 1, 6 },
+ { 26000000, 600000000, 600, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 1, 8},
- { 13000000, 216000000, 432, 13, 1, 8},
- { 16800000, 216000000, 360, 14, 1, 8},
- { 19200000, 216000000, 360, 16, 1, 8},
- { 26000000, 216000000, 432, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 216000000, 432, 12, 2, 8 },
+ { 13000000, 216000000, 432, 13, 2, 8 },
+ { 16800000, 216000000, 360, 14, 2, 8 },
+ { 19200000, 216000000, 360, 16, 2, 8 },
+ { 26000000, 216000000, 432, 26, 2, 8 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
- { 9600000, 564480000, 294, 5, 0, 4},
- { 9600000, 552960000, 288, 5, 0, 4},
- { 9600000, 24000000, 5, 2, 0, 1},
-
- { 28800000, 56448000, 49, 25, 0, 1},
- { 28800000, 73728000, 64, 25, 0, 1},
- { 28800000, 24000000, 5, 6, 0, 1},
- { 0, 0, 0, 0, 0, 0 },
+ { 9600000, 564480000, 294, 5, 1, 4 },
+ { 9600000, 552960000, 288, 5, 1, 4 },
+ { 9600000, 24000000, 5, 2, 1, 1 },
+ { 28800000, 56448000, 49, 25, 1, 1 },
+ { 28800000, 73728000, 64, 25, 1, 1 },
+ { 28800000, 24000000, 5, 6, 1, 1 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 0, 4},
- { 13000000, 216000000, 216, 13, 0, 4},
- { 16800000, 216000000, 180, 14, 0, 4},
- { 19200000, 216000000, 180, 16, 0, 4},
- { 26000000, 216000000, 216, 26, 0, 4},
-
- { 12000000, 594000000, 594, 12, 0, 8},
- { 13000000, 594000000, 594, 13, 0, 8},
- { 16800000, 594000000, 495, 14, 0, 8},
- { 19200000, 594000000, 495, 16, 0, 8},
- { 26000000, 594000000, 594, 26, 0, 8},
-
- { 12000000, 1000000000, 1000, 12, 0, 12},
- { 13000000, 1000000000, 1000, 13, 0, 12},
- { 19200000, 1000000000, 625, 12, 0, 8},
- { 26000000, 1000000000, 1000, 26, 0, 12},
-
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 216000000, 216, 12, 1, 4 },
+ { 13000000, 216000000, 216, 13, 1, 4 },
+ { 16800000, 216000000, 180, 14, 1, 4 },
+ { 19200000, 216000000, 180, 16, 1, 4 },
+ { 26000000, 216000000, 216, 26, 1, 4 },
+ { 12000000, 594000000, 594, 12, 1, 8 },
+ { 13000000, 594000000, 594, 13, 1, 8 },
+ { 16800000, 594000000, 495, 14, 1, 8 },
+ { 19200000, 594000000, 495, 16, 1, 8 },
+ { 26000000, 594000000, 594, 26, 1, 8 },
+ { 12000000, 1000000000, 1000, 12, 1, 12 },
+ { 13000000, 1000000000, 1000, 13, 1, 12 },
+ { 19200000, 1000000000, 625, 12, 1, 8 },
+ { 26000000, 1000000000, 1000, 26, 1, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 0, 12},
- { 13000000, 480000000, 960, 13, 0, 12},
- { 16800000, 480000000, 400, 7, 0, 5},
- { 19200000, 480000000, 200, 4, 0, 3},
- { 26000000, 480000000, 960, 26, 0, 12},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 480000000, 960, 12, 1, 12 },
+ { 13000000, 480000000, 960, 13, 1, 12 },
+ { 16800000, 480000000, 400, 7, 1, 5 },
+ { 19200000, 480000000, 200, 4, 1, 3 },
+ { 26000000, 480000000, 960, 26, 1, 12 },
+ { 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1.7 GHz */
- { 12000000, 1700000000, 850, 6, 0, 8},
- { 13000000, 1700000000, 915, 7, 0, 8}, /* actual: 1699.2 MHz */
- { 16800000, 1700000000, 708, 7, 0, 8}, /* actual: 1699.2 MHz */
- { 19200000, 1700000000, 885, 10, 0, 8}, /* actual: 1699.2 MHz */
- { 26000000, 1700000000, 850, 13, 0, 8},
-
+ { 12000000, 1700000000, 850, 6, 1, 8 },
+ { 13000000, 1700000000, 915, 7, 1, 8 }, /* actual: 1699.2 MHz */
+ { 16800000, 1700000000, 708, 7, 1, 8 }, /* actual: 1699.2 MHz */
+ { 19200000, 1700000000, 885, 10, 1, 8 }, /* actual: 1699.2 MHz */
+ { 26000000, 1700000000, 850, 13, 1, 8 },
/* 1.6 GHz */
- { 12000000, 1600000000, 800, 6, 0, 8},
- { 13000000, 1600000000, 738, 6, 0, 8}, /* actual: 1599.0 MHz */
- { 16800000, 1600000000, 857, 9, 0, 8}, /* actual: 1599.7 MHz */
- { 19200000, 1600000000, 500, 6, 0, 8},
- { 26000000, 1600000000, 800, 13, 0, 8},
-
+ { 12000000, 1600000000, 800, 6, 1, 8 },
+ { 13000000, 1600000000, 738, 6, 1, 8 }, /* actual: 1599.0 MHz */
+ { 16800000, 1600000000, 857, 9, 1, 8 }, /* actual: 1599.7 MHz */
+ { 19200000, 1600000000, 500, 6, 1, 8 },
+ { 26000000, 1600000000, 800, 13, 1, 8 },
/* 1.5 GHz */
- { 12000000, 1500000000, 750, 6, 0, 8},
- { 13000000, 1500000000, 923, 8, 0, 8}, /* actual: 1499.8 MHz */
- { 16800000, 1500000000, 625, 7, 0, 8},
- { 19200000, 1500000000, 625, 8, 0, 8},
- { 26000000, 1500000000, 750, 13, 0, 8},
-
+ { 12000000, 1500000000, 750, 6, 1, 8 },
+ { 13000000, 1500000000, 923, 8, 1, 8 }, /* actual: 1499.8 MHz */
+ { 16800000, 1500000000, 625, 7, 1, 8 },
+ { 19200000, 1500000000, 625, 8, 1, 8 },
+ { 26000000, 1500000000, 750, 13, 1, 8 },
/* 1.4 GHz */
- { 12000000, 1400000000, 700, 6, 0, 8},
- { 13000000, 1400000000, 969, 9, 0, 8}, /* actual: 1399.7 MHz */
- { 16800000, 1400000000, 1000, 12, 0, 8},
- { 19200000, 1400000000, 875, 12, 0, 8},
- { 26000000, 1400000000, 700, 13, 0, 8},
-
+ { 12000000, 1400000000, 700, 6, 1, 8 },
+ { 13000000, 1400000000, 969, 9, 1, 8 }, /* actual: 1399.7 MHz */
+ { 16800000, 1400000000, 1000, 12, 1, 8 },
+ { 19200000, 1400000000, 875, 12, 1, 8 },
+ { 26000000, 1400000000, 700, 13, 1, 8 },
/* 1.3 GHz */
- { 12000000, 1300000000, 975, 9, 0, 8},
- { 13000000, 1300000000, 1000, 10, 0, 8},
- { 16800000, 1300000000, 928, 12, 0, 8}, /* actual: 1299.2 MHz */
- { 19200000, 1300000000, 812, 12, 0, 8}, /* actual: 1299.2 MHz */
- { 26000000, 1300000000, 650, 13, 0, 8},
-
+ { 12000000, 1300000000, 975, 9, 1, 8 },
+ { 13000000, 1300000000, 1000, 10, 1, 8 },
+ { 16800000, 1300000000, 928, 12, 1, 8 }, /* actual: 1299.2 MHz */
+ { 19200000, 1300000000, 812, 12, 1, 8 }, /* actual: 1299.2 MHz */
+ { 26000000, 1300000000, 650, 13, 1, 8 },
/* 1.2 GHz */
- { 12000000, 1200000000, 1000, 10, 0, 8},
- { 13000000, 1200000000, 923, 10, 0, 8}, /* actual: 1199.9 MHz */
- { 16800000, 1200000000, 1000, 14, 0, 8},
- { 19200000, 1200000000, 1000, 16, 0, 8},
- { 26000000, 1200000000, 600, 13, 0, 8},
-
+ { 12000000, 1200000000, 1000, 10, 1, 8 },
+ { 13000000, 1200000000, 923, 10, 1, 8 }, /* actual: 1199.9 MHz */
+ { 16800000, 1200000000, 1000, 14, 1, 8 },
+ { 19200000, 1200000000, 1000, 16, 1, 8 },
+ { 26000000, 1200000000, 600, 13, 1, 8 },
/* 1.1 GHz */
- { 12000000, 1100000000, 825, 9, 0, 8},
- { 13000000, 1100000000, 846, 10, 0, 8}, /* actual: 1099.8 MHz */
- { 16800000, 1100000000, 982, 15, 0, 8}, /* actual: 1099.8 MHz */
- { 19200000, 1100000000, 859, 15, 0, 8}, /* actual: 1099.5 MHz */
- { 26000000, 1100000000, 550, 13, 0, 8},
-
+ { 12000000, 1100000000, 825, 9, 1, 8 },
+ { 13000000, 1100000000, 846, 10, 1, 8 }, /* actual: 1099.8 MHz */
+ { 16800000, 1100000000, 982, 15, 1, 8 }, /* actual: 1099.8 MHz */
+ { 19200000, 1100000000, 859, 15, 1, 8 }, /* actual: 1099.5 MHz */
+ { 26000000, 1100000000, 550, 13, 1, 8 },
/* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 0, 8},
- { 13000000, 1000000000, 1000, 13, 0, 8},
- { 16800000, 1000000000, 833, 14, 0, 8}, /* actual: 999.6 MHz */
- { 19200000, 1000000000, 625, 12, 0, 8},
- { 26000000, 1000000000, 1000, 26, 0, 8},
+ { 12000000, 1000000000, 1000, 12, 1, 8 },
+ { 13000000, 1000000000, 1000, 13, 1, 8 },
+ { 16800000, 1000000000, 833, 14, 1, 8 }, /* actual: 999.6 MHz */
+ { 19200000, 1000000000, 625, 12, 1, 8 },
+ { 26000000, 1000000000, 1000, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
+};
- { 0, 0, 0, 0, 0, 0 },
+static const struct pdiv_map plle_p[] = {
+ { .pdiv = 18, .hw_val = 18 },
+ { .pdiv = 24, .hw_val = 24 },
+ { .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
- { 12000000, 100000000, 150, 1, 18, 11},
- { 216000000, 100000000, 200, 18, 24, 13},
- { 0, 0, 0, 0, 0, 0 },
+ { 12000000, 100000000, 150, 1, 18, 11 },
+ { 216000000, 100000000, 200, 18, 24, 13 },
+ { 0, 0, 0, 0, 0, 0 },
};
/* PLL parameters */
@@ -422,7 +426,8 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp pllm_nmp = {
@@ -454,7 +459,8 @@ static struct tegra_clk_pll_params pll_m_params = {
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
.freq_table = pll_m_freq_table,
.flags = TEGRA_PLLM | TEGRA_PLL_HAS_CPCON |
- TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_FIXED,
};
static struct tegra_clk_pll_params pll_p_params = {
@@ -470,7 +476,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_p_freq_table,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 408000000,
};
@@ -487,7 +494,8 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_d_params = {
@@ -504,8 +512,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
-
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_d2_params = {
@@ -522,7 +529,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_u_params = {
@@ -539,7 +546,8 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
.freq_table = pll_u_freq_table,
- .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
+ .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_x_params = {
@@ -556,7 +564,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.lock_delay = 300,
.freq_table = pll_x_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_DCCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_e_params = {
@@ -571,19 +579,21 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .pdiv_tohw = plle_p,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC,
.fixed_rate = 100000000,
};
static unsigned long tegra30_input_freq[] = {
- [0] = 13000000,
- [1] = 16800000,
- [4] = 19200000,
- [5] = 38400000,
- [8] = 12000000,
- [9] = 48000000,
- [12] = 260000000,
+ [ 0] = 13000000,
+ [ 1] = 16800000,
+ [ 4] = 19200000,
+ [ 5] = 38400000,
+ [ 8] = 12000000,
+ [ 9] = 48000000,
+ [12] = 26000000,
};
static struct tegra_devclk devclks[] __initdata = {
@@ -861,13 +871,12 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
[tegra_clk_pll_p_out4] = { .dt_id = TEGRA30_CLK_PLL_P_OUT4, .present = true },
[tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true },
[tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true },
-
};
static void tegra30_utmi_param_configure(void)
{
+ unsigned int i;
u32 reg;
- int i;
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (input_freq == utmi_parameters[i].osc_frequency)
@@ -917,7 +926,7 @@ static void tegra30_utmi_param_configure(void)
writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
}
-static const char *pll_e_parents[] = {"pll_ref", "pll_p"};
+static const char *pll_e_parents[] = { "pll_ref", "pll_p" };
static void __init tegra30_pll_init(void)
{
@@ -925,7 +934,7 @@ static void __init tegra30_pll_init(void)
/* PLLC */
clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0,
- &pll_c_params, NULL);
+ &pll_c_params, NULL);
clks[TEGRA30_CLK_PLL_C] = clk;
/* PLLC_OUT1 */
@@ -1135,7 +1144,7 @@ static void __init tegra30_periph_clk_init(void)
{
struct tegra_periph_init_data *data;
struct clk *clk;
- int i;
+ unsigned int i;
/* dsia */
clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base,
@@ -1224,7 +1233,6 @@ static void tegra30_cpu_out_of_reset(u32 cpu)
wmb();
}
-
static void tegra30_enable_cpu_clock(u32 cpu)
{
unsigned int reg;
@@ -1237,7 +1245,6 @@ static void tegra30_enable_cpu_clock(u32 cpu)
static void tegra30_disable_cpu_clock(u32 cpu)
{
-
unsigned int reg;
reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
@@ -1268,7 +1275,7 @@ static void tegra30_cpu_clock_suspend(void)
/* switch coresite to clk_m, save off original source */
tegra30_cpu_clk_sctx.clk_csite_src =
readl(clk_base + CLK_RESET_SOURCE_CSITE);
- writel(3<<30, clk_base + CLK_RESET_SOURCE_CSITE);
+ writel(3 << 30, clk_base + CLK_RESET_SOURCE_CSITE);
tegra30_cpu_clk_sctx.cpu_burst =
readl(clk_base + CLK_RESET_CCLK_BURST);
@@ -1335,44 +1342,45 @@ static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
};
static struct tegra_clk_init_table init_table[] __initdata = {
- {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 408000000, 0},
- {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 408000000, 0},
- {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0},
- {TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0},
- {TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0},
- {TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1},
- {TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1},
- {TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1},
- {TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0},
- {TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA30_CLK_I2S3, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA30_CLK_I2S4, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
- {TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0},
- {TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0},
- {TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0},
- {TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0},
- {TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0},
- {TEGRA30_CLK_SBC3, TEGRA30_CLK_PLL_P, 100000000, 0},
- {TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0},
- {TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0},
- {TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0},
- {TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0},
- {TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0},
- {TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0},
- {TEGRA30_CLK_TWD, TEGRA30_CLK_CLK_MAX, 0, 1},
- {TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0},
- {TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0},
- {TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0},
- {TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry. */
+ { TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 408000000, 0 },
+ { TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 408000000, 0 },
+ { TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0 },
+ { TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0 },
+ { TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0 },
+ { TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1 },
+ { TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1 },
+ { TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1 },
+ { TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0 },
+ { TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA30_CLK_I2S3, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA30_CLK_I2S4, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+ { TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0 },
+ { TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0 },
+ { TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0 },
+ { TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0 },
+ { TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0 },
+ { TEGRA30_CLK_SBC3, TEGRA30_CLK_PLL_P, 100000000, 0 },
+ { TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0 },
+ { TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0 },
+ { TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 },
+ { TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 },
+ { TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 },
+ { TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 },
+ { TEGRA30_CLK_TWD, TEGRA30_CLK_CLK_MAX, 0, 1 },
+ { TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 },
+ { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 },
+ { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 },
+ /* must be the last entry */
+ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
};
static void __init tegra30_clock_apply_init_table(void)
@@ -1397,12 +1405,13 @@ static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CML1, "tegra_sata_cml", NULL),
TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CML0, "tegra_pcie", "cml"),
TEGRA_CLK_DUPLICATE(TEGRA30_CLK_VCP, "nvavp", "vcp"),
- TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CLK_MAX, NULL, NULL), /* MUST be the last entry */
+ /* must be the last entry */
+ TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CLK_MAX, NULL, NULL),
};
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra30-pmc" },
- {},
+ { },
};
static struct tegra_audio_clk_info tegra30_audio_plls[] = {
@@ -1441,7 +1450,6 @@ static void __init tegra30_clock_init(struct device_node *np)
NULL) < 0)
return;
-
tegra_fixed_clk_init(tegra30_clks);
tegra30_pll_init();
tegra30_super_clk_init();
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 5d2678914160..4dbcfaec576a 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -110,14 +110,16 @@ struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
* @m: input divider
* @p: post divider
* @cpcon: charge pump current
+ * @sdm_data: fraction divider setting (0 = disabled)
*/
struct tegra_clk_pll_freq_table {
unsigned long input_rate;
unsigned long output_rate;
- u16 n;
+ u32 n;
u16 m;
u8 p;
u8 cpcon;
+ u16 sdm_data;
};
/**
@@ -156,6 +158,10 @@ struct div_nmp {
u8 override_divp_shift;
};
+#define MAX_PLL_MISC_REG_COUNT 6
+
+struct tegra_clk_pll;
+
/**
* struct tegra_clk_pll_params - PLL parameters
*
@@ -172,6 +178,14 @@ struct div_nmp {
* @lock_enable_bit_idx: Bit index to enable PLL lock
* @iddq_reg: PLL IDDQ register offset
* @iddq_bit_idx: Bit index to enable PLL IDDQ
+ * @reset_reg: Register offset of where RESET bit is
+ * @reset_bit_idx: Shift of reset bit in reset_reg
+ * @sdm_din_reg: Register offset where SDM settings are
+ * @sdm_din_mask: Mask of SDM divider bits
+ * @sdm_ctrl_reg: Register offset where SDM enable is
+ * @sdm_ctrl_en_mask: Mask of SDM enable bit
+ * @ssc_ctrl_reg: Register offset where SSC settings are
+ * @ssc_ctrl_en_mask: Mask of SSC enable bit
* @aux_reg: AUX register offset
* @dyn_ramp_reg: Dynamic ramp control register offset
* @ext_misc_reg: Miscellaneous control register offsets
@@ -182,10 +196,27 @@ struct div_nmp {
* @stepb_shift: Dynamic ramp step B field shift
* @lock_delay: Delay in us if PLL lock is not used
* @max_p: maximum value for the p divider
+ * @defaults_set: Boolean signaling all reg defaults for PLL set.
* @pdiv_tohw: mapping of p divider to register values
* @div_nmp: offsets and widths on n, m and p fields
* @freq_table: array of frequencies supported by PLL
* @fixed_rate: PLL rate if it is fixed
+ * @mdiv_default: Default value for fixed mdiv for this PLL
+ * @round_p_to_pdiv: Callback used to round p to the closed pdiv
+ * @set_gain: Callback to adjust N div for SDM enabled
+ * PLL's based on fractional divider value.
+ * @calc_rate: Callback used to change how out of table
+ * rates (dividers and multipler) are calculated.
+ * @adjust_vco: Callback to adjust the programming range of the
+ * divider range (if SDM is present)
+ * @set_defaults: Callback which will try to initialize PLL
+ * registers to sane default values. This is first
+ * tried during PLL registration, but if the PLL
+ * is already enabled, it will be done the first
+ * time the rate is changed while the PLL is
+ * disabled.
+ * @dyn_ramp: Callback which can be used to define a custom
+ * dynamic ramp function for a given PLL.
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -207,6 +238,11 @@ struct div_nmp {
* base register.
* TEGRA_PLL_BYPASS - PLL has bypass bit
* TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
+ * TEGRA_MDIV_NEW - Switch to new method for calculating fixed mdiv
+ * it may be more accurate (especially if SDM present)
+ * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
+ * flag indicated that it is PLLMB.
+ * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
*/
struct tegra_clk_pll_params {
unsigned long input_min;
@@ -223,9 +259,17 @@ struct tegra_clk_pll_params {
u32 lock_enable_bit_idx;
u32 iddq_reg;
u32 iddq_bit_idx;
+ u32 reset_reg;
+ u32 reset_bit_idx;
+ u32 sdm_din_reg;
+ u32 sdm_din_mask;
+ u32 sdm_ctrl_reg;
+ u32 sdm_ctrl_en_mask;
+ u32 ssc_ctrl_reg;
+ u32 ssc_ctrl_en_mask;
u32 aux_reg;
u32 dyn_ramp_reg;
- u32 ext_misc_reg[3];
+ u32 ext_misc_reg[MAX_PLL_MISC_REG_COUNT];
u32 pmc_divnm_reg;
u32 pmc_divp_reg;
u32 flags;
@@ -233,10 +277,22 @@ struct tegra_clk_pll_params {
int stepb_shift;
int lock_delay;
int max_p;
- struct pdiv_map *pdiv_tohw;
+ bool defaults_set;
+ const struct pdiv_map *pdiv_tohw;
struct div_nmp *div_nmp;
struct tegra_clk_pll_freq_table *freq_table;
unsigned long fixed_rate;
+ u16 mdiv_default;
+ u32 (*round_p_to_pdiv)(u32 p, u32 *pdiv);
+ void (*set_gain)(struct tegra_clk_pll_freq_table *cfg);
+ int (*calc_rate)(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate);
+ unsigned long (*adjust_vco)(struct tegra_clk_pll_params *pll_params,
+ unsigned long parent_rate);
+ void (*set_defaults)(struct tegra_clk_pll *pll);
+ int (*dyn_ramp)(struct tegra_clk_pll *pll,
+ struct tegra_clk_pll_freq_table *cfg);
};
#define TEGRA_PLL_USE_LOCK BIT(0)
@@ -250,6 +306,9 @@ struct tegra_clk_pll_params {
#define TEGRA_PLL_LOCK_MISC BIT(8)
#define TEGRA_PLL_BYPASS BIT(9)
#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
+#define TEGRA_MDIV_NEW BIT(11)
+#define TEGRA_PLLMB BIT(12)
+#define TEGRA_PLL_VCO_OUT BIT(13)
/**
* struct tegra_clk_pll - Tegra PLL clock
@@ -303,6 +362,12 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock);
+struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
void __iomem *clk_base, void __iomem *pmc,
unsigned long flags,
@@ -327,11 +392,35 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock);
+struct clk *tegra_clk_register_plle_tegra210(const char *name,
+ const char *parent_name,
+ void __iomem *clk_base, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllss_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
void __iomem *clk_base, unsigned long flags,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock);
+struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
/**
* struct tegra_clk_pll_out - PLL divider down clock
*
@@ -653,6 +742,9 @@ int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
void tegra_super_clk_gen4_init(void __iomem *clk_base,
void __iomem *pmc_base, struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *pll_params);
+void tegra_super_clk_gen5_init(void __iomem *clk_base,
+ void __iomem *pmc_base, struct tegra_clk *tegra_clks,
+ struct tegra_clk_pll_params *pll_params);
#ifdef CONFIG_TEGRA_CLK_EMC
struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
@@ -674,5 +766,8 @@ void tegra114_clock_deassert_dfll_dvco_reset(void);
typedef void (*tegra_clk_apply_init_table_func)(void);
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll);
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
+int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
#endif /* TEGRA_CLK_H */
diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c
index f3eab6e79027..b336a8c11e2a 100644
--- a/drivers/clk/ti/apll.c
+++ b/drivers/clk/ti/apll.c
@@ -323,7 +323,7 @@ static void omap2_apll_deny_idle(struct clk_hw_omap *clk)
omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_DISABLE);
}
-static struct clk_hw_omap_ops omap2_apll_hwops = {
+static const struct clk_hw_omap_ops omap2_apll_hwops = {
.allow_idle = &omap2_apll_allow_idle,
.deny_idle = &omap2_apll_deny_idle,
};
diff --git a/drivers/clk/ti/clk-814x.c b/drivers/clk/ti/clk-814x.c
index e172920798ea..9e85fcc74cc9 100644
--- a/drivers/clk/ti/clk-814x.c
+++ b/drivers/clk/ti/clk-814x.c
@@ -14,10 +14,14 @@ static struct ti_dt_clk dm814_clks[] = {
DT_CLK(NULL, "devosc_ck", "devosc_ck"),
DT_CLK(NULL, "mpu_ck", "mpu_ck"),
DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
+ DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"),
DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
+ DT_CLK(NULL, "sysclk8_ck", "sysclk8_ck"),
DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
DT_CLK(NULL, "timer_sys_ck", "devosc_ck"),
+ DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+ DT_CLK(NULL, "timer2_fck", "timer2_fck"),
DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"),
DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"),
{ .node_name = NULL },
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index f4dec00fb684..1c300388782b 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -305,8 +305,9 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
{
struct dpll_data *dd = clk->dpll_data;
- u8 dco, sd_div;
+ u8 dco, sd_div, ai = 0;
u32 v;
+ bool errata_i810;
/* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
_omap3_noncore_dpll_bypass(clk);
@@ -350,6 +351,25 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
v |= sd_div << __ffs(dd->sddiv_mask);
}
+ /*
+ * Errata i810 - DPLL controller can get stuck while transitioning
+ * to a power saving state. Software must ensure the DPLL can not
+ * transition to a low power state while changing M/N values.
+ * Easiest way to accomplish this is to prevent DPLL autoidle
+ * before doing the M/N re-program.
+ */
+ errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810;
+
+ if (errata_i810) {
+ ai = omap3_dpll_autoidle_read(clk);
+ if (ai) {
+ omap3_dpll_deny_idle(clk);
+
+ /* OCP barrier */
+ omap3_dpll_autoidle_read(clk);
+ }
+ }
+
ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg);
/* Set 4X multiplier and low-power mode */
@@ -379,6 +399,9 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
_omap3_noncore_dpll_lock(clk);
+ if (errata_i810 && ai)
+ omap3_dpll_allow_idle(clk);
+
return 0;
}
diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig
index fc50b6264bed..a6da2aa09f83 100644
--- a/drivers/clk/versatile/Kconfig
+++ b/drivers/clk/versatile/Kconfig
@@ -1,6 +1,9 @@
config COMMON_CLK_VERSATILE
bool "Clock driver for ARM Reference designs"
- depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64 || COMPILE_TEST
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \
+ ARCH_VERSATILE || ARCH_VEXPRESS || ARM64 || \
+ COMPILE_TEST
+ select REGMAP_MMIO
---help---
Supports clocking on ARM Reference designs:
- Integrator/AP and Integrator/CP
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index 08c5ee976879..e62f8cb2c9b5 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -3,7 +3,7 @@
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
* clock framework.
*
- * Copyright (C) 2012 Linus Walleij
+ * Copyright (C) 2012-2015 Linus Walleij
*
* 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
@@ -19,9 +19,14 @@
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
#include "clk-icst.h"
+/* Magic unlocking token used on all Versatile boards */
+#define VERSATILE_LOCK_VAL 0xA05F
+
/**
* struct clk_icst - ICST VCO clock wrapper
* @hw: corresponding clock hardware entry
@@ -32,8 +37,9 @@
*/
struct clk_icst {
struct clk_hw hw;
- void __iomem *vcoreg;
- void __iomem *lockreg;
+ struct regmap *map;
+ u32 vcoreg_off;
+ u32 lockreg_off;
struct icst_params *params;
unsigned long rate;
};
@@ -41,53 +47,67 @@ struct clk_icst {
#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
/**
- * vco_get() - get ICST VCO settings from a certain register
- * @vcoreg: register containing the VCO settings
+ * vco_get() - get ICST VCO settings from a certain ICST
+ * @icst: the ICST clock to get
+ * @vco: the VCO struct to return the value in
*/
-static struct icst_vco vco_get(void __iomem *vcoreg)
+static int vco_get(struct clk_icst *icst, struct icst_vco *vco)
{
u32 val;
- struct icst_vco vco;
+ int ret;
- val = readl(vcoreg);
- vco.v = val & 0x1ff;
- vco.r = (val >> 9) & 0x7f;
- vco.s = (val >> 16) & 03;
- return vco;
+ ret = regmap_read(icst->map, icst->vcoreg_off, &val);
+ if (ret)
+ return ret;
+ vco->v = val & 0x1ff;
+ vco->r = (val >> 9) & 0x7f;
+ vco->s = (val >> 16) & 03;
+ return 0;
}
/**
* vco_set() - commit changes to an ICST VCO
- * @locreg: register to poke to unlock the VCO for writing
- * @vcoreg: register containing the VCO settings
- * @vco: ICST VCO parameters to commit
+ * @icst: the ICST clock to set
+ * @vco: the VCO struct to set the changes from
*/
-static void vco_set(void __iomem *lockreg,
- void __iomem *vcoreg,
- struct icst_vco vco)
+static int vco_set(struct clk_icst *icst, struct icst_vco vco)
{
u32 val;
+ int ret;
- val = readl(vcoreg) & ~0x7ffff;
+ ret = regmap_read(icst->map, icst->vcoreg_off, &val);
+ if (ret)
+ return ret;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
/* This magic unlocks the VCO so it can be controlled */
- writel(0xa05f, lockreg);
- writel(val, vcoreg);
+ ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL);
+ if (ret)
+ return ret;
+ ret = regmap_write(icst->map, icst->vcoreg_off, val);
+ if (ret)
+ return ret;
/* This locks the VCO again */
- writel(0, lockreg);
+ ret = regmap_write(icst->map, icst->lockreg_off, 0);
+ if (ret)
+ return ret;
+ return 0;
}
-
static unsigned long icst_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;
+ int ret;
if (parent_rate)
icst->params->ref = parent_rate;
- vco = vco_get(icst->vcoreg);
+ ret = vco_get(icst, &vco);
+ if (ret) {
+ pr_err("ICST: could not get VCO setting\n");
+ return 0;
+ }
icst->rate = icst_hz(icst->params, vco);
return icst->rate;
}
@@ -112,8 +132,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
icst->params->ref = parent_rate;
vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco);
- vco_set(icst->lockreg, icst->vcoreg, vco);
- return 0;
+ return vco_set(icst, vco);
}
static const struct clk_ops icst_ops = {
@@ -122,11 +141,11 @@ static const struct clk_ops icst_ops = {
.set_rate = icst_set_rate,
};
-struct clk *icst_clk_register(struct device *dev,
- const struct clk_icst_desc *desc,
- const char *name,
- const char *parent_name,
- void __iomem *base)
+static struct clk *icst_clk_setup(struct device *dev,
+ const struct clk_icst_desc *desc,
+ const char *name,
+ const char *parent_name,
+ struct regmap *map)
{
struct clk *clk;
struct clk_icst *icst;
@@ -151,10 +170,11 @@ struct clk *icst_clk_register(struct device *dev,
init.flags = CLK_IS_ROOT;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
+ icst->map = map;
icst->hw.init = &init;
icst->params = pclone;
- icst->vcoreg = base + desc->vco_offset;
- icst->lockreg = base + desc->lock_offset;
+ icst->vcoreg_off = desc->vco_offset;
+ icst->lockreg_off = desc->lock_offset;
clk = clk_register(dev, &icst->hw);
if (IS_ERR(clk)) {
@@ -164,4 +184,112 @@ struct clk *icst_clk_register(struct device *dev,
return clk;
}
+
+struct clk *icst_clk_register(struct device *dev,
+ const struct clk_icst_desc *desc,
+ const char *name,
+ const char *parent_name,
+ void __iomem *base)
+{
+ struct regmap_config icst_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ };
+ struct regmap *map;
+
+ map = regmap_init_mmio(dev, base, &icst_regmap_conf);
+ if (IS_ERR(map)) {
+ pr_err("could not initialize ICST regmap\n");
+ return ERR_CAST(map);
+ }
+ return icst_clk_setup(dev, desc, name, parent_name, map);
+}
EXPORT_SYMBOL_GPL(icst_clk_register);
+
+#ifdef CONFIG_OF
+/*
+ * In a device tree, an memory-mapped ICST clock appear as a child
+ * of a syscon node. Assume this and probe it only as a child of a
+ * syscon.
+ */
+
+static const struct icst_params icst525_params = {
+ .vco_max = ICST525_VCO_MAX_5V,
+ .vco_min = ICST525_VCO_MIN,
+ .vd_min = 8,
+ .vd_max = 263,
+ .rd_min = 3,
+ .rd_max = 65,
+ .s2div = icst525_s2div,
+ .idx2s = icst525_idx2s,
+};
+
+static const struct icst_params icst307_params = {
+ .vco_max = ICST307_VCO_MAX,
+ .vco_min = ICST307_VCO_MIN,
+ .vd_min = 4 + 8,
+ .vd_max = 511 + 8,
+ .rd_min = 1 + 2,
+ .rd_max = 127 + 2,
+ .s2div = icst307_s2div,
+ .idx2s = icst307_idx2s,
+};
+
+static void __init of_syscon_icst_setup(struct device_node *np)
+{
+ struct device_node *parent;
+ struct regmap *map;
+ struct clk_icst_desc icst_desc;
+ const char *name = np->name;
+ const char *parent_name;
+ struct clk *regclk;
+
+ /* We do not release this reference, we are using it perpetually */
+ parent = of_get_parent(np);
+ if (!parent) {
+ pr_err("no parent node for syscon ICST clock\n");
+ return;
+ }
+ map = syscon_node_to_regmap(parent);
+ if (IS_ERR(map)) {
+ pr_err("no regmap for syscon ICST clock parent\n");
+ return;
+ }
+
+ if (of_property_read_u32(np, "vco-offset", &icst_desc.vco_offset)) {
+ pr_err("no VCO register offset for ICST clock\n");
+ return;
+ }
+ if (of_property_read_u32(np, "lock-offset", &icst_desc.lock_offset)) {
+ pr_err("no lock register offset for ICST clock\n");
+ return;
+ }
+
+ if (of_device_is_compatible(np, "arm,syscon-icst525"))
+ icst_desc.params = &icst525_params;
+ else if (of_device_is_compatible(np, "arm,syscon-icst307"))
+ icst_desc.params = &icst307_params;
+ else {
+ pr_err("unknown ICST clock %s\n", name);
+ return;
+ }
+
+ /* Parent clock name is not the same as node parent */
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map);
+ if (IS_ERR(regclk)) {
+ pr_err("error setting up syscon ICST clock %s\n", name);
+ return;
+ }
+ of_clk_add_provider(np, of_clk_src_simple_get, regclk);
+ pr_debug("registered syscon ICST clock %s\n", name);
+}
+
+CLK_OF_DECLARE(arm_syscon_icst525_clk,
+ "arm,syscon-icst525", of_syscon_icst_setup);
+CLK_OF_DECLARE(arm_syscon_icst307_clk,
+ "arm,syscon-icst307", of_syscon_icst_setup);
+
+#endif
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
index 86f70997d59d..bd4dd2463e23 100644
--- a/drivers/clk/versatile/clk-realview.c
+++ b/drivers/clk/versatile/clk-realview.c
@@ -11,11 +11,15 @@
#include <linux/io.h>
#include <linux/clk-provider.h>
-#include <mach/hardware.h>
-#include <mach/platform.h>
-
#include "clk-icst.h"
+#define REALVIEW_SYS_OSC0_OFFSET 0x0C
+#define REALVIEW_SYS_OSC1_OFFSET 0x10
+#define REALVIEW_SYS_OSC2_OFFSET 0x14
+#define REALVIEW_SYS_OSC3_OFFSET 0x18
+#define REALVIEW_SYS_OSC4_OFFSET 0x1C /* OSC1 for RealView/AB */
+#define REALVIEW_SYS_LOCK_OFFSET 0x20
+
/*
* Implementation of the ARM RealView clock trees.
*/
diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c
index a1cdef6b0f90..e78755e0ef78 100644
--- a/drivers/clk/versatile/clk-sp810.c
+++ b/drivers/clk/versatile/clk-sp810.c
@@ -95,13 +95,12 @@ static void __init clk_sp810_of_setup(struct device_node *node)
int i;
bool deprecated;
- if (!sp810) {
- pr_err("Failed to allocate memory for SP810!\n");
+ if (!sp810)
return;
- }
if (of_clk_parent_fill(node, parent_names, num) != num) {
pr_warn("Failed to obtain parent clocks for SP810!\n");
+ kfree(sp810);
return;
}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index b251013eef0a..56777f04d2d9 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -152,7 +152,7 @@ config CLKSRC_EFM32
config CLKSRC_LPC32XX
bool "Clocksource for LPC32XX" if COMPILE_TEST
- depends on GENERIC_CLOCKEVENTS
+ depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
select CLKSRC_MMIO
select CLKSRC_OF
help
@@ -160,6 +160,7 @@ config CLKSRC_LPC32XX
config CLKSRC_PISTACHIO
bool "Clocksource for Pistachio SoC" if COMPILE_TEST
+ depends on HAS_IOMEM
select CLKSRC_OF
help
Enables the clocksource for the Pistachio SoC.
@@ -256,6 +257,7 @@ config CLKSRC_SAMSUNG_PWM
config FSL_FTM_TIMER
bool "Freescale FlexTimer Module driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS
+ select CLKSRC_MMIO
help
Support for Freescale FlexTimer Module (FTM) timer.
@@ -269,7 +271,7 @@ config SYS_SUPPORTS_SH_CMT
config MTK_TIMER
bool "Mediatek timer driver" if COMPILE_TEST
- depends on GENERIC_CLOCKEVENTS
+ depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
select CLKSRC_OF
select CLKSRC_MMIO
help
@@ -365,20 +367,20 @@ config CLKSRC_PXA
config H8300_TMR8
bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
- depends on GENERIC_CLOCKEVENTS
+ depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
help
This enables the 8 bits timer for the H8300 platform.
config H8300_TMR16
bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
- depends on GENERIC_CLOCKEVENTS
+ depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
help
This enables the 16 bits timer for the H8300 platform with the
H83069 cpu.
config H8300_TPU
bool "Clocksource for the H8300 platform" if COMPILE_TEST
- depends on GENERIC_CLOCKEVENTS
+ depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
help
This enables the clocksource for the H8300 platform with the
H8S2678 cpu.
@@ -391,6 +393,7 @@ config CLKSRC_IMX_GPT
config CLKSRC_ST_LPC
bool "Low power clocksource found in the LPC" if COMPILE_TEST
select CLKSRC_OF if OF
+ depends on HAS_IOMEM
help
Enable this option to use the Low Power controller timer
as clocksource.
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c
index b375106844d8..dfad6eb99662 100644
--- a/drivers/clocksource/clksrc-dbx500-prcmu.c
+++ b/drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -12,8 +12,9 @@
* power domain. We use the Timer 4 for our always-on clock
* source on DB8500.
*/
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/clockchips.h>
-#include <linux/clksrc-dbx500-prcmu.h>
#include <linux/sched_clock.h>
#define RATE_32K 32768
@@ -63,9 +64,9 @@ static u64 notrace dbx500_prcmu_sched_clock_read(void)
#endif
-void __init clksrc_dbx500_prcmu_init(void __iomem *base)
+static void __init clksrc_dbx500_prcmu_init(struct device_node *node)
{
- clksrc_dbx500_timer_base = base;
+ clksrc_dbx500_timer_base = of_iomap(node, 0);
/*
* The A9 sub system expects the timer to be configured as
@@ -85,3 +86,5 @@ void __init clksrc_dbx500_prcmu_init(void __iomem *base)
#endif
clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
}
+CLOCKSOURCE_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
+ clksrc_dbx500_prcmu_init);
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c
index de49805fbb09..ddb409274f45 100644
--- a/drivers/clocksource/vt8500_timer.c
+++ b/drivers/clocksource/vt8500_timer.c
@@ -49,6 +49,8 @@
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+#define MIN_OSCR_DELTA 16
+
static void __iomem *regbase;
static cycle_t vt8500_timer_read(struct clocksource *cs)
@@ -79,7 +81,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles,
cpu_relax();
writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
- if ((signed)(alarm - clocksource.read(&clocksource)) <= 16)
+ if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA)
return -ETIME;
writel(1, regbase + TIMER_IER_VAL);
@@ -150,7 +152,7 @@ static void __init vt8500_timer_init(struct device_node *np)
pr_err("%s: setup_irq failed for %s\n", __func__,
clockevent.name);
clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
- 4, 0xf0000000);
+ MIN_OSCR_DELTA * 2, 0xf0000000);
}
CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index cb501386eb6e..547890fd9572 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -586,7 +586,7 @@ static int __init powernv_cpufreq_init(void)
int rc = 0;
/* Don't probe on pseries (guest) platforms */
- if (!firmware_has_feature(FW_FEATURE_OPALv3))
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
return -ENODEV;
/* Discover pstates from device tree and init */
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 845bafcfa792..e12dc30d8864 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -264,7 +264,7 @@ static int powernv_idle_probe(void)
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
- if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+ if (firmware_has_feature(FW_FEATURE_OPAL)) {
cpuidle_state_table = powernv_states;
/* Device tree can indicate more idle states */
max_idle_state = powernv_add_idle_states();
diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c
index 263af709e536..022c7ab7351a 100644
--- a/drivers/crypto/vmx/aes.c
+++ b/drivers/crypto/vmx/aes.c
@@ -83,10 +83,10 @@ static int p8_aes_setkey(struct crypto_tfm *tfm, const u8 *key,
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
@@ -103,9 +103,9 @@ static void p8_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
} else {
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
aes_p8_encrypt(src, dst, &ctx->enc_key);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
}
@@ -120,9 +120,9 @@ static void p8_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
} else {
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
aes_p8_decrypt(src, dst, &ctx->dec_key);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
}
diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c
index 78a978613ca8..495577b6d31b 100644
--- a/drivers/crypto/vmx/aes_cbc.c
+++ b/drivers/crypto/vmx/aes_cbc.c
@@ -84,10 +84,10 @@ static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key,
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
@@ -115,7 +115,6 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc,
} else {
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -129,6 +128,7 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc,
ret = blkcipher_walk_done(desc, &walk, nbytes);
}
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
}
@@ -156,7 +156,6 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc,
} else {
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -170,6 +169,7 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc,
ret = blkcipher_walk_done(desc, &walk, nbytes);
}
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
}
diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c
index 1febc4f1d9af..0a3c1b04cf3c 100644
--- a/drivers/crypto/vmx/aes_ctr.c
+++ b/drivers/crypto/vmx/aes_ctr.c
@@ -81,9 +81,9 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key,
struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
+ disable_kernel_vsx();
pagefault_enable();
ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
@@ -100,9 +100,9 @@ static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx,
unsigned int nbytes = walk->nbytes;
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key);
+ disable_kernel_vsx();
pagefault_enable();
crypto_xor(keystream, src, nbytes);
@@ -133,7 +133,6 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr,
walk.dst.virt.addr,
@@ -142,6 +141,7 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
AES_BLOCK_SIZE,
&ctx->enc_key,
walk.iv);
+ disable_kernel_vsx();
pagefault_enable();
/* We need to update IV mostly for last bytes/round */
diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c
index 2183a2e77641..6c999cb01b80 100644
--- a/drivers/crypto/vmx/ghash.c
+++ b/drivers/crypto/vmx/ghash.c
@@ -118,10 +118,9 @@ static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
- enable_kernel_fp();
gcm_init_p8(ctx->htable, (const u64 *) key);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
return crypto_shash_setkey(ctx->fallback, key, keylen);
@@ -149,11 +148,10 @@ static int p8_ghash_update(struct shash_desc *desc,
GHASH_DIGEST_SIZE - dctx->bytes);
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
- enable_kernel_fp();
gcm_ghash_p8(dctx->shash, ctx->htable,
dctx->buffer, GHASH_DIGEST_SIZE);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
src += GHASH_DIGEST_SIZE - dctx->bytes;
@@ -164,10 +162,9 @@ static int p8_ghash_update(struct shash_desc *desc,
if (len) {
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
- enable_kernel_fp();
gcm_ghash_p8(dctx->shash, ctx->htable, src, len);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
src += len;
@@ -195,11 +192,10 @@ static int p8_ghash_final(struct shash_desc *desc, u8 *out)
dctx->buffer[i] = 0;
preempt_disable();
pagefault_disable();
- enable_kernel_altivec();
enable_kernel_vsx();
- enable_kernel_fp();
gcm_ghash_p8(dctx->shash, ctx->htable,
dctx->buffer, GHASH_DIGEST_SIZE);
+ disable_kernel_vsx();
pagefault_enable();
preempt_enable();
dctx->bytes = 0;
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
index 819dfda88236..7afbb28d6a0f 100644
--- a/drivers/dca/dca-core.c
+++ b/drivers/dca/dca-core.c
@@ -321,7 +321,8 @@ EXPORT_SYMBOL_GPL(dca_get_tag);
* @ops - pointer to struct of dca operation function pointers
* @priv_size - size of extra mem to be added for provider's needs
*/
-struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size)
+struct dca_provider *alloc_dca_provider(const struct dca_ops *ops,
+ int priv_size)
{
struct dca_provider *dca;
int alloc_size;
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index e6cd1a32025a..79b1390f2016 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -431,8 +431,20 @@ config STE_DMA40
help
Support for ST-Ericsson DMA40 controller
+config STM32_DMA
+ bool "STMicroelectronics STM32 DMA support"
+ depends on ARCH_STM32
+ select DMA_ENGINE
+ select DMA_OF
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Enable support for the on-chip DMA controller on STMicroelectronics
+ STM32 MCUs.
+ If you have a board based on such a MCU and wish to use DMA say Y or M
+ here.
+
config S3C24XX_DMAC
- tristate "Samsung S3C24XX DMA support"
+ bool "Samsung S3C24XX DMA support"
depends on ARCH_S3C24XX
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index ef9c099bd2b6..2dd0a067a0ca 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o
obj-$(CONFIG_RENESAS_DMA) += sh/
obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
+obj-$(CONFIG_STM32_DMA) += stm32-dma.o
obj-$(CONFIG_S3C24XX_DMAC) += s3c24xx-dma.o
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index 16d0daa058a5..eed6bda01790 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -72,7 +73,9 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
si = (const struct acpi_csrt_shared_info *)&grp[1];
/* Match device by MMIO and IRQ */
- if (si->mmio_base_low != mem || si->gsi_interrupt != irq)
+ if (si->mmio_base_low != lower_32_bits(mem) ||
+ si->mmio_base_high != upper_32_bits(mem) ||
+ si->gsi_interrupt != irq)
return 0;
dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 370c661c7d7b..64f5d1bdbb48 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -863,8 +863,12 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
* access. Hopefully we can access DDR through both ports (at least on
* SAMA5D4x), so we can use the same interface for source and dest,
* that solves the fact we don't know the direction.
+ * ERRATA: Even if useless for memory transfers, the PERID has to not
+ * match the one of another channel. If not, it could lead to spurious
+ * flag status.
*/
- u32 chan_cc = AT_XDMAC_CC_DIF(0)
+ u32 chan_cc = AT_XDMAC_CC_PERID(0x3f)
+ | AT_XDMAC_CC_DIF(0)
| AT_XDMAC_CC_SIF(0)
| AT_XDMAC_CC_MBSIZE_SIXTEEN
| AT_XDMAC_CC_TYPE_MEM_TRAN;
@@ -1041,8 +1045,12 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
* access DDR through both ports (at least on SAMA5D4x), so we can use
* the same interface for source and dest, that solves the fact we
* don't know the direction.
+ * ERRATA: Even if useless for memory transfers, the PERID has to not
+ * match the one of another channel. If not, it could lead to spurious
+ * flag status.
*/
- u32 chan_cc = AT_XDMAC_CC_DAM_INCREMENTED_AM
+ u32 chan_cc = AT_XDMAC_CC_PERID(0x3f)
+ | AT_XDMAC_CC_DAM_INCREMENTED_AM
| AT_XDMAC_CC_SAM_INCREMENTED_AM
| AT_XDMAC_CC_DIF(0)
| AT_XDMAC_CC_SIF(0)
@@ -1143,8 +1151,12 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
* access. Hopefully we can access DDR through both ports (at least on
* SAMA5D4x), so we can use the same interface for source and dest,
* that solves the fact we don't know the direction.
+ * ERRATA: Even if useless for memory transfers, the PERID has to not
+ * match the one of another channel. If not, it could lead to spurious
+ * flag status.
*/
- u32 chan_cc = AT_XDMAC_CC_DAM_UBS_AM
+ u32 chan_cc = AT_XDMAC_CC_PERID(0x3f)
+ | AT_XDMAC_CC_DAM_UBS_AM
| AT_XDMAC_CC_SAM_INCREMENTED_AM
| AT_XDMAC_CC_DIF(0)
| AT_XDMAC_CC_SIF(0)
@@ -1688,6 +1700,7 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
at_xdmac_remove_xfer(atchan, desc);
+ clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1820,6 +1833,8 @@ static int atmel_xdmac_resume(struct device *dev)
atchan = to_at_xdmac_chan(chan);
at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc);
if (at_xdmac_chan_is_cyclic(atchan)) {
+ if (at_xdmac_chan_is_paused(atchan))
+ at_xdmac_device_resume(chan);
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda);
at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc);
at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim);
@@ -1998,8 +2013,6 @@ static int at_xdmac_remove(struct platform_device *pdev)
dma_async_device_unregister(&atxdmac->dma);
clk_disable_unprepare(atxdmac->clk);
- synchronize_irq(atxdmac->irq);
-
free_irq(atxdmac->irq, atxdmac->dma.dev);
for (i = 0; i < atxdmac->dma.chancnt; i++) {
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index 5b2395e7e04d..c3468094393e 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -307,6 +307,13 @@ static int axi_dmac_terminate_all(struct dma_chan *c)
return 0;
}
+static void axi_dmac_synchronize(struct dma_chan *c)
+{
+ struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
+
+ vchan_synchronize(&chan->vchan);
+}
+
static void axi_dmac_issue_pending(struct dma_chan *c)
{
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
@@ -613,6 +620,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic;
dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved;
dma_dev->device_terminate_all = axi_dmac_terminate_all;
+ dma_dev->device_synchronize = axi_dmac_synchronize;
dma_dev->dev = &pdev->dev;
dma_dev->chancnt = 1;
dma_dev->src_addr_widths = BIT(dmac->chan.src_width);
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 3ecec1445adf..c50a247be2e0 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -43,6 +43,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -265,8 +266,11 @@ static void dma_chan_put(struct dma_chan *chan)
module_put(dma_chan_to_owner(chan));
/* This channel is not in use anymore, free it */
- if (!chan->client_count && chan->device->device_free_chan_resources)
+ if (!chan->client_count && chan->device->device_free_chan_resources) {
+ /* Make sure all operations have completed */
+ dmaengine_synchronize(chan);
chan->device->device_free_chan_resources(chan);
+ }
/* If the channel is used via a DMA request router, free the mapping */
if (chan->router && chan->router->route_free) {
@@ -493,6 +497,7 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
caps->dst_addr_widths = device->dst_addr_widths;
caps->directions = device->directions;
caps->residue_granularity = device->residue_granularity;
+ caps->descriptor_reuse = device->descriptor_reuse;
/*
* Some devices implement only pause (e.g. to get residuum) but no
@@ -511,7 +516,7 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
{
struct dma_chan *chan;
- if (!__dma_device_satisfies_mask(dev, mask)) {
+ if (mask && !__dma_device_satisfies_mask(dev, mask)) {
pr_debug("%s: wrong capabilities\n", __func__);
return NULL;
}
@@ -542,6 +547,42 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
return NULL;
}
+static struct dma_chan *find_candidate(struct dma_device *device,
+ const dma_cap_mask_t *mask,
+ dma_filter_fn fn, void *fn_param)
+{
+ struct dma_chan *chan = private_candidate(mask, device, fn, fn_param);
+ int err;
+
+ if (chan) {
+ /* Found a suitable channel, try to grab, prep, and return it.
+ * We first set DMA_PRIVATE to disable balance_ref_count as this
+ * channel will not be published in the general-purpose
+ * allocator
+ */
+ dma_cap_set(DMA_PRIVATE, device->cap_mask);
+ device->privatecnt++;
+ err = dma_chan_get(chan);
+
+ if (err) {
+ if (err == -ENODEV) {
+ pr_debug("%s: %s module removed\n", __func__,
+ dma_chan_name(chan));
+ list_del_rcu(&device->global_node);
+ } else
+ pr_debug("%s: failed to get %s: (%d)\n",
+ __func__, dma_chan_name(chan), err);
+
+ if (--device->privatecnt == 0)
+ dma_cap_clear(DMA_PRIVATE, device->cap_mask);
+
+ chan = ERR_PTR(err);
+ }
+ }
+
+ return chan ? chan : ERR_PTR(-EPROBE_DEFER);
+}
+
/**
* dma_get_slave_channel - try to get specific channel exclusively
* @chan: target channel
@@ -580,7 +621,6 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device)
{
dma_cap_mask_t mask;
struct dma_chan *chan;
- int err;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -588,23 +628,11 @@ struct dma_chan *dma_get_any_slave_channel(struct dma_device *device)
/* lock against __dma_request_channel */
mutex_lock(&dma_list_mutex);
- chan = private_candidate(&mask, device, NULL, NULL);
- if (chan) {
- dma_cap_set(DMA_PRIVATE, device->cap_mask);
- device->privatecnt++;
- err = dma_chan_get(chan);
- if (err) {
- pr_debug("%s: failed to get %s: (%d)\n",
- __func__, dma_chan_name(chan), err);
- chan = NULL;
- if (--device->privatecnt == 0)
- dma_cap_clear(DMA_PRIVATE, device->cap_mask);
- }
- }
+ chan = find_candidate(device, &mask, NULL, NULL);
mutex_unlock(&dma_list_mutex);
- return chan;
+ return IS_ERR(chan) ? NULL : chan;
}
EXPORT_SYMBOL_GPL(dma_get_any_slave_channel);
@@ -621,35 +649,15 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
{
struct dma_device *device, *_d;
struct dma_chan *chan = NULL;
- int err;
/* Find a channel */
mutex_lock(&dma_list_mutex);
list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
- chan = private_candidate(mask, device, fn, fn_param);
- if (chan) {
- /* Found a suitable channel, try to grab, prep, and
- * return it. We first set DMA_PRIVATE to disable
- * balance_ref_count as this channel will not be
- * published in the general-purpose allocator
- */
- dma_cap_set(DMA_PRIVATE, device->cap_mask);
- device->privatecnt++;
- err = dma_chan_get(chan);
+ chan = find_candidate(device, mask, fn, fn_param);
+ if (!IS_ERR(chan))
+ break;
- if (err == -ENODEV) {
- pr_debug("%s: %s module removed\n",
- __func__, dma_chan_name(chan));
- list_del_rcu(&device->global_node);
- } else if (err)
- pr_debug("%s: failed to get %s: (%d)\n",
- __func__, dma_chan_name(chan), err);
- else
- break;
- if (--device->privatecnt == 0)
- dma_cap_clear(DMA_PRIVATE, device->cap_mask);
- chan = NULL;
- }
+ chan = NULL;
}
mutex_unlock(&dma_list_mutex);
@@ -662,27 +670,73 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
}
EXPORT_SYMBOL_GPL(__dma_request_channel);
+static const struct dma_slave_map *dma_filter_match(struct dma_device *device,
+ const char *name,
+ struct device *dev)
+{
+ int i;
+
+ if (!device->filter.mapcnt)
+ return NULL;
+
+ for (i = 0; i < device->filter.mapcnt; i++) {
+ const struct dma_slave_map *map = &device->filter.map[i];
+
+ if (!strcmp(map->devname, dev_name(dev)) &&
+ !strcmp(map->slave, name))
+ return map;
+ }
+
+ return NULL;
+}
+
/**
- * dma_request_slave_channel_reason - try to allocate an exclusive slave channel
+ * dma_request_chan - try to allocate an exclusive slave channel
* @dev: pointer to client device structure
* @name: slave channel name
*
* Returns pointer to appropriate DMA channel on success or an error pointer.
*/
-struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
- const char *name)
+struct dma_chan *dma_request_chan(struct device *dev, const char *name)
{
+ struct dma_device *d, *_d;
+ struct dma_chan *chan = NULL;
+
/* If device-tree is present get slave info from here */
if (dev->of_node)
- return of_dma_request_slave_channel(dev->of_node, name);
+ chan = of_dma_request_slave_channel(dev->of_node, name);
/* If device was enumerated by ACPI get slave info from here */
- if (ACPI_HANDLE(dev))
- return acpi_dma_request_slave_chan_by_name(dev, name);
+ if (has_acpi_companion(dev) && !chan)
+ chan = acpi_dma_request_slave_chan_by_name(dev, name);
+
+ if (chan) {
+ /* Valid channel found or requester need to be deferred */
+ if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
+ return chan;
+ }
- return ERR_PTR(-ENODEV);
+ /* Try to find the channel via the DMA filter map(s) */
+ mutex_lock(&dma_list_mutex);
+ list_for_each_entry_safe(d, _d, &dma_device_list, global_node) {
+ dma_cap_mask_t mask;
+ const struct dma_slave_map *map = dma_filter_match(d, name, dev);
+
+ if (!map)
+ continue;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ chan = find_candidate(d, &mask, d->filter.fn, map->param);
+ if (!IS_ERR(chan))
+ break;
+ }
+ mutex_unlock(&dma_list_mutex);
+
+ return chan ? chan : ERR_PTR(-EPROBE_DEFER);
}
-EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason);
+EXPORT_SYMBOL_GPL(dma_request_chan);
/**
* dma_request_slave_channel - try to allocate an exclusive slave channel
@@ -694,17 +748,35 @@ EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason);
struct dma_chan *dma_request_slave_channel(struct device *dev,
const char *name)
{
- struct dma_chan *ch = dma_request_slave_channel_reason(dev, name);
+ struct dma_chan *ch = dma_request_chan(dev, name);
if (IS_ERR(ch))
return NULL;
- dma_cap_set(DMA_PRIVATE, ch->device->cap_mask);
- ch->device->privatecnt++;
-
return ch;
}
EXPORT_SYMBOL_GPL(dma_request_slave_channel);
+/**
+ * dma_request_chan_by_mask - allocate a channel satisfying certain capabilities
+ * @mask: capabilities that the channel must satisfy
+ *
+ * Returns pointer to appropriate DMA channel on success or an error pointer.
+ */
+struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask)
+{
+ struct dma_chan *chan;
+
+ if (!mask)
+ return ERR_PTR(-ENODEV);
+
+ chan = __dma_request_channel(mask, NULL, NULL);
+ if (!chan)
+ chan = ERR_PTR(-ENODEV);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(dma_request_chan_by_mask);
+
void dma_release_channel(struct dma_chan *chan)
{
mutex_lock(&dma_list_mutex);
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 8b20930ade98..e893318560db 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -156,6 +156,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
/* Enable interrupts */
channel_set_bit(dw, MASK.XFER, dwc->mask);
+ channel_set_bit(dw, MASK.BLOCK, dwc->mask);
channel_set_bit(dw, MASK.ERROR, dwc->mask);
dwc->initialized = true;
@@ -536,16 +537,17 @@ EXPORT_SYMBOL(dw_dma_get_dst_addr);
/* Called with dwc->lock held and all DMAC interrupts disabled */
static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
- u32 status_err, u32 status_xfer)
+ u32 status_block, u32 status_err, u32 status_xfer)
{
unsigned long flags;
- if (dwc->mask) {
+ if (status_block & dwc->mask) {
void (*callback)(void *param);
void *callback_param;
dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n",
channel_readl(dwc, LLP));
+ dma_writel(dw, CLEAR.BLOCK, dwc->mask);
callback = dwc->cdesc->period_callback;
callback_param = dwc->cdesc->period_callback_param;
@@ -577,6 +579,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
channel_writel(dwc, CTL_LO, 0);
channel_writel(dwc, CTL_HI, 0);
+ dma_writel(dw, CLEAR.BLOCK, dwc->mask);
dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
@@ -593,10 +596,12 @@ static void dw_dma_tasklet(unsigned long data)
{
struct dw_dma *dw = (struct dw_dma *)data;
struct dw_dma_chan *dwc;
+ u32 status_block;
u32 status_xfer;
u32 status_err;
int i;
+ status_block = dma_readl(dw, RAW.BLOCK);
status_xfer = dma_readl(dw, RAW.XFER);
status_err = dma_readl(dw, RAW.ERROR);
@@ -605,7 +610,8 @@ static void dw_dma_tasklet(unsigned long data)
for (i = 0; i < dw->dma.chancnt; i++) {
dwc = &dw->chan[i];
if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
- dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
+ dwc_handle_cyclic(dw, dwc, status_block, status_err,
+ status_xfer);
else if (status_err & (1 << i))
dwc_handle_error(dw, dwc);
else if (status_xfer & (1 << i))
@@ -616,6 +622,7 @@ static void dw_dma_tasklet(unsigned long data)
* Re-enable interrupts.
*/
channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
+ channel_set_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
}
@@ -640,6 +647,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
* softirq handler.
*/
channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
+ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
status = dma_readl(dw, STATUS_INT);
@@ -650,6 +658,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
/* Try to recover */
channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1);
+ channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1);
channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1);
channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1);
channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1);
@@ -1116,6 +1125,7 @@ static void dw_dma_off(struct dw_dma *dw)
dma_writel(dw, CFG, 0);
channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
+ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1221,6 +1231,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
/* Disable interrupts */
channel_clear_bit(dw, MASK.XFER, dwc->mask);
+ channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
channel_clear_bit(dw, MASK.ERROR, dwc->mask);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1250,7 +1261,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
int dw_dma_cyclic_start(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
- struct dw_dma *dw = to_dw_dma(dwc->chan.device);
unsigned long flags;
if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
@@ -1259,27 +1269,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
}
spin_lock_irqsave(&dwc->lock, flags);
-
- /* Assert channel is idle */
- if (dma_readl(dw, CH_EN) & dwc->mask) {
- dev_err(chan2dev(&dwc->chan),
- "%s: BUG: Attempted to start non-idle channel\n",
- __func__);
- dwc_dump_chan_regs(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
- return -EBUSY;
- }
-
- dma_writel(dw, CLEAR.ERROR, dwc->mask);
- dma_writel(dw, CLEAR.XFER, dwc->mask);
-
- /* Setup DMAC channel registers */
- channel_writel(dwc, LLP, dwc->cdesc->desc[0]->txd.phys);
- channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
- channel_writel(dwc, CTL_HI, 0);
-
- channel_set_bit(dw, CH_EN, dwc->mask);
-
+ dwc_dostart(dwc, dwc->cdesc->desc[0]);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@@ -1484,6 +1474,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
dwc_chan_disable(dw, dwc);
+ dma_writel(dw, CLEAR.BLOCK, dwc->mask);
dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
@@ -1572,9 +1563,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
/* Force dma off, just in case */
dw_dma_off(dw);
- /* Disable BLOCK interrupts as well */
- channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
-
/* Create a pool of consistent memory blocks for hardware descriptors */
dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev,
sizeof(struct dw_desc), 4, 0);
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index 127093a0c0e8..26edbe3a27ac 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -103,18 +103,21 @@ dw_dma_parse_dt(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct dw_dma_platform_data *pdata;
u32 tmp, arr[DW_DMA_MAX_NR_MASTERS];
+ u32 nr_channels;
if (!np) {
dev_err(&pdev->dev, "Missing DT data\n");
return NULL;
}
+ if (of_property_read_u32(np, "dma-channels", &nr_channels))
+ return NULL;
+
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
- if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
- return NULL;
+ pdata->nr_channels = nr_channels;
if (of_property_read_bool(np, "is_private"))
pdata->is_private = true;
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 16fe773fb846..d92d65549406 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -484,7 +484,7 @@ static void edma_read_slot(struct edma_cc *ecc, unsigned slot,
*/
static int edma_alloc_slot(struct edma_cc *ecc, int slot)
{
- if (slot > 0) {
+ if (slot >= 0) {
slot = EDMA_CHAN_SLOT(slot);
/* Requesting entry paRAM slot for a HW triggered channel. */
if (ecc->chmap_exist && slot < ecc->num_channels)
@@ -2314,6 +2314,10 @@ static int edma_probe(struct platform_device *pdev)
edma_set_chmap(&ecc->slave_chans[i], ecc->dummy_slot);
}
+ ecc->dma_slave.filter.map = info->slave_map;
+ ecc->dma_slave.filter.mapcnt = info->slavecnt;
+ ecc->dma_slave.filter.fn = edma_filter_fn;
+
ret = dma_async_device_register(&ecc->dma_slave);
if (ret) {
dev_err(dev, "slave ddev registration failed (%d)\n", ret);
@@ -2421,7 +2425,13 @@ static struct platform_driver edma_driver = {
},
};
+static int edma_tptc_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
static struct platform_driver edma_tptc_driver = {
+ .probe = edma_tptc_probe,
.driver = {
.name = "edma3-tptc",
.of_match_table = edma_tptc_of_ids,
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3cc279..be2e62b87948 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -116,6 +116,10 @@
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+enum fsl_edma_pm_state {
+ RUNNING = 0,
+ SUSPENDED,
+};
struct fsl_edma_hw_tcd {
__le32 saddr;
@@ -147,6 +151,9 @@ struct fsl_edma_slave_config {
struct fsl_edma_chan {
struct virt_dma_chan vchan;
enum dma_status status;
+ enum fsl_edma_pm_state pm_state;
+ bool idle;
+ u32 slave_id;
struct fsl_edma_engine *edma;
struct fsl_edma_desc *edesc;
struct fsl_edma_slave_config fsc;
@@ -298,6 +305,7 @@ static int fsl_edma_terminate_all(struct dma_chan *chan)
spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
fsl_edma_disable_request(fsl_chan);
fsl_chan->edesc = NULL;
+ fsl_chan->idle = true;
vchan_get_all_descriptors(&fsl_chan->vchan, &head);
spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
@@ -313,6 +321,7 @@ static int fsl_edma_pause(struct dma_chan *chan)
if (fsl_chan->edesc) {
fsl_edma_disable_request(fsl_chan);
fsl_chan->status = DMA_PAUSED;
+ fsl_chan->idle = true;
}
spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
return 0;
@@ -327,6 +336,7 @@ static int fsl_edma_resume(struct dma_chan *chan)
if (fsl_chan->edesc) {
fsl_edma_enable_request(fsl_chan);
fsl_chan->status = DMA_IN_PROGRESS;
+ fsl_chan->idle = false;
}
spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
return 0;
@@ -648,6 +658,7 @@ static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
fsl_edma_enable_request(fsl_chan);
fsl_chan->status = DMA_IN_PROGRESS;
+ fsl_chan->idle = false;
}
static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
@@ -676,6 +687,7 @@ static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
vchan_cookie_complete(&fsl_chan->edesc->vdesc);
fsl_chan->edesc = NULL;
fsl_chan->status = DMA_COMPLETE;
+ fsl_chan->idle = true;
} else {
vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
}
@@ -704,6 +716,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
fsl_edma->membase + EDMA_CERR);
fsl_edma->chans[ch].status = DMA_ERROR;
+ fsl_edma->chans[ch].idle = true;
}
}
return IRQ_HANDLED;
@@ -724,6 +737,12 @@ static void fsl_edma_issue_pending(struct dma_chan *chan)
spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (unlikely(fsl_chan->pm_state != RUNNING)) {
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ /* cannot submit due to suspend */
+ return;
+ }
+
if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
fsl_edma_xfer_desc(fsl_chan);
@@ -735,6 +754,7 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
{
struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
struct dma_chan *chan, *_chan;
+ struct fsl_edma_chan *fsl_chan;
unsigned long chans_per_mux = fsl_edma->n_chans / DMAMUX_NR;
if (dma_spec->args_count != 2)
@@ -748,8 +768,10 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
chan = dma_get_slave_channel(chan);
if (chan) {
chan->device->privatecnt++;
- fsl_edma_chan_mux(to_fsl_edma_chan(chan),
- dma_spec->args[1], true);
+ fsl_chan = to_fsl_edma_chan(chan);
+ fsl_chan->slave_id = dma_spec->args[1];
+ fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id,
+ true);
mutex_unlock(&fsl_edma->fsl_edma_mutex);
return chan;
}
@@ -888,7 +910,9 @@ static int fsl_edma_probe(struct platform_device *pdev)
struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i];
fsl_chan->edma = fsl_edma;
-
+ fsl_chan->pm_state = RUNNING;
+ fsl_chan->slave_id = 0;
+ fsl_chan->idle = true;
fsl_chan->vchan.desc_free = fsl_edma_free_desc;
vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
@@ -959,6 +983,60 @@ static int fsl_edma_remove(struct platform_device *pdev)
return 0;
}
+static int fsl_edma_suspend_late(struct device *dev)
+{
+ struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
+ struct fsl_edma_chan *fsl_chan;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < fsl_edma->n_chans; i++) {
+ fsl_chan = &fsl_edma->chans[i];
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ /* Make sure chan is idle or will force disable. */
+ if (unlikely(!fsl_chan->idle)) {
+ dev_warn(dev, "WARN: There is non-idle channel.");
+ fsl_edma_disable_request(fsl_chan);
+ fsl_edma_chan_mux(fsl_chan, 0, false);
+ }
+
+ fsl_chan->pm_state = SUSPENDED;
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ }
+
+ return 0;
+}
+
+static int fsl_edma_resume_early(struct device *dev)
+{
+ struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
+ struct fsl_edma_chan *fsl_chan;
+ int i;
+
+ for (i = 0; i < fsl_edma->n_chans; i++) {
+ fsl_chan = &fsl_edma->chans[i];
+ fsl_chan->pm_state = RUNNING;
+ edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+ if (fsl_chan->slave_id != 0)
+ fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true);
+ }
+
+ edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA,
+ fsl_edma->membase + EDMA_CR);
+
+ return 0;
+}
+
+/*
+ * eDMA provides the service to others, so it should be suspend late
+ * and resume early. When eDMA suspend, all of the clients should stop
+ * the DMA data transmission and let the channel idle.
+ */
+static const struct dev_pm_ops fsl_edma_pm_ops = {
+ .suspend_late = fsl_edma_suspend_late,
+ .resume_early = fsl_edma_resume_early,
+};
+
static const struct of_device_id fsl_edma_dt_ids[] = {
{ .compatible = "fsl,vf610-edma", },
{ /* sentinel */ }
@@ -969,6 +1047,7 @@ static struct platform_driver fsl_edma_driver = {
.driver = {
.name = "fsl-edma",
.of_match_table = fsl_edma_dt_ids,
+ .pm = &fsl_edma_pm_ops,
},
.probe = fsl_edma_probe,
.remove = fsl_edma_remove,
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c
index 823ad728aecf..eef145edb936 100644
--- a/drivers/dma/hsu/hsu.c
+++ b/drivers/dma/hsu/hsu.c
@@ -228,6 +228,8 @@ static struct dma_async_tx_descriptor *hsu_dma_prep_slave_sg(
for_each_sg(sgl, sg, sg_len, i) {
desc->sg[i].addr = sg_dma_address(sg);
desc->sg[i].len = sg_dma_len(sg);
+
+ desc->length += sg_dma_len(sg);
}
desc->nents = sg_len;
@@ -249,21 +251,10 @@ static void hsu_dma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
}
-static size_t hsu_dma_desc_size(struct hsu_dma_desc *desc)
-{
- size_t bytes = 0;
- unsigned int i;
-
- for (i = desc->active; i < desc->nents; i++)
- bytes += desc->sg[i].len;
-
- return bytes;
-}
-
static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc)
{
struct hsu_dma_desc *desc = hsuc->desc;
- size_t bytes = hsu_dma_desc_size(desc);
+ size_t bytes = desc->length;
int i;
i = desc->active % HSU_DMA_CHAN_NR_DESC;
@@ -294,7 +285,7 @@ static enum dma_status hsu_dma_tx_status(struct dma_chan *chan,
dma_set_residue(state, bytes);
status = hsuc->desc->status;
} else if (vdesc) {
- bytes = hsu_dma_desc_size(to_hsu_dma_desc(vdesc));
+ bytes = to_hsu_dma_desc(vdesc)->length;
dma_set_residue(state, bytes);
}
spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h
index f06579c6d548..578a8ee8cd05 100644
--- a/drivers/dma/hsu/hsu.h
+++ b/drivers/dma/hsu/hsu.h
@@ -65,6 +65,7 @@ struct hsu_dma_desc {
enum dma_transfer_direction direction;
struct hsu_dma_sg *sg;
unsigned int nents;
+ size_t length;
unsigned int active;
enum dma_status status;
};
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 7d56b47e4fcf..3cb7b2c78197 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -178,20 +178,12 @@ static irqreturn_t idma64_irq(int irq, void *dev)
if (!status)
return IRQ_NONE;
- /* Disable interrupts */
- channel_clear_bit(idma64, MASK(XFER), idma64->all_chan_mask);
- channel_clear_bit(idma64, MASK(ERROR), idma64->all_chan_mask);
-
status_xfer = dma_readl(idma64, RAW(XFER));
status_err = dma_readl(idma64, RAW(ERROR));
for (i = 0; i < idma64->dma.chancnt; i++)
idma64_chan_irq(idma64, i, status_err, status_xfer);
- /* Re-enable interrupts */
- channel_set_bit(idma64, MASK(XFER), idma64->all_chan_mask);
- channel_set_bit(idma64, MASK(ERROR), idma64->all_chan_mask);
-
return IRQ_HANDLED;
}
@@ -239,7 +231,7 @@ static void idma64_vdesc_free(struct virt_dma_desc *vdesc)
idma64_desc_free(idma64c, to_idma64_desc(vdesc));
}
-static u64 idma64_hw_desc_fill(struct idma64_hw_desc *hw,
+static void idma64_hw_desc_fill(struct idma64_hw_desc *hw,
struct dma_slave_config *config,
enum dma_transfer_direction direction, u64 llp)
{
@@ -276,26 +268,26 @@ static u64 idma64_hw_desc_fill(struct idma64_hw_desc *hw,
IDMA64C_CTLL_SRC_WIDTH(src_width);
lli->llp = llp;
- return hw->llp;
}
static void idma64_desc_fill(struct idma64_chan *idma64c,
struct idma64_desc *desc)
{
struct dma_slave_config *config = &idma64c->config;
- struct idma64_hw_desc *hw = &desc->hw[desc->ndesc - 1];
+ unsigned int i = desc->ndesc;
+ struct idma64_hw_desc *hw = &desc->hw[i - 1];
struct idma64_lli *lli = hw->lli;
u64 llp = 0;
- unsigned int i = desc->ndesc;
/* Fill the hardware descriptors and link them to a list */
do {
hw = &desc->hw[--i];
- llp = idma64_hw_desc_fill(hw, config, desc->direction, llp);
+ idma64_hw_desc_fill(hw, config, desc->direction, llp);
+ llp = hw->llp;
desc->length += hw->len;
} while (i);
- /* Trigger interrupt after last block */
+ /* Trigger an interrupt after the last block is transfered */
lli->ctllo |= IDMA64C_CTLL_INT_EN;
}
@@ -596,6 +588,8 @@ static int idma64_probe(struct idma64_chip *chip)
idma64->dma.dev = chip->dev;
+ dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK);
+
ret = dma_async_device_register(&idma64->dma);
if (ret)
return ret;
diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h
index f6aeff0af8a5..8423f13ed0da 100644
--- a/drivers/dma/idma64.h
+++ b/drivers/dma/idma64.h
@@ -54,7 +54,8 @@
#define IDMA64C_CTLL_LLP_S_EN (1 << 28) /* src block chain */
/* Bitfields in CTL_HI */
-#define IDMA64C_CTLH_BLOCK_TS(x) ((x) & ((1 << 17) - 1))
+#define IDMA64C_CTLH_BLOCK_TS_MASK ((1 << 17) - 1)
+#define IDMA64C_CTLH_BLOCK_TS(x) ((x) & IDMA64C_CTLH_BLOCK_TS_MASK)
#define IDMA64C_CTLH_DONE (1 << 17)
/* Bitfields in CFG_LO */
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
index 9ca56830cc63..a4c53be482cf 100644
--- a/drivers/dma/img-mdc-dma.c
+++ b/drivers/dma/img-mdc-dma.c
@@ -651,6 +651,48 @@ static enum dma_status mdc_tx_status(struct dma_chan *chan,
return ret;
}
+static unsigned int mdc_get_new_events(struct mdc_chan *mchan)
+{
+ u32 val, processed, done1, done2;
+ unsigned int ret;
+
+ val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
+ processed = (val >> MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK;
+ /*
+ * CMDS_DONE may have incremented between reading CMDS_PROCESSED
+ * and clearing INT_ACTIVE. Re-read CMDS_PROCESSED to ensure we
+ * didn't miss a command completion.
+ */
+ do {
+ val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
+
+ done1 = (val >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
+
+ val &= ~((MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK <<
+ MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) |
+ MDC_CMDS_PROCESSED_INT_ACTIVE);
+
+ val |= done1 << MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT;
+
+ mdc_chan_writel(mchan, val, MDC_CMDS_PROCESSED);
+
+ val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
+
+ done2 = (val >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
+ } while (done1 != done2);
+
+ if (done1 >= processed)
+ ret = done1 - processed;
+ else
+ ret = ((MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK + 1) -
+ processed) + done1;
+
+ return ret;
+}
+
static int mdc_terminate_all(struct dma_chan *chan)
{
struct mdc_chan *mchan = to_mdc_chan(chan);
@@ -667,6 +709,8 @@ static int mdc_terminate_all(struct dma_chan *chan)
mchan->desc = NULL;
vchan_get_all_descriptors(&mchan->vc, &head);
+ mdc_get_new_events(mchan);
+
spin_unlock_irqrestore(&mchan->vc.lock, flags);
if (mdesc)
@@ -703,35 +747,17 @@ static irqreturn_t mdc_chan_irq(int irq, void *dev_id)
{
struct mdc_chan *mchan = (struct mdc_chan *)dev_id;
struct mdc_tx_desc *mdesc;
- u32 val, processed, done1, done2;
- unsigned int i;
+ unsigned int i, new_events;
spin_lock(&mchan->vc.lock);
- val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
- processed = (val >> MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) &
- MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK;
- /*
- * CMDS_DONE may have incremented between reading CMDS_PROCESSED
- * and clearing INT_ACTIVE. Re-read CMDS_PROCESSED to ensure we
- * didn't miss a command completion.
- */
- do {
- val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
- done1 = (val >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
- MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
- val &= ~((MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK <<
- MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) |
- MDC_CMDS_PROCESSED_INT_ACTIVE);
- val |= done1 << MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT;
- mdc_chan_writel(mchan, val, MDC_CMDS_PROCESSED);
- val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
- done2 = (val >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
- MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
- } while (done1 != done2);
-
dev_dbg(mdma2dev(mchan->mdma), "IRQ on channel %d\n", mchan->chan_nr);
+ new_events = mdc_get_new_events(mchan);
+
+ if (!new_events)
+ goto out;
+
mdesc = mchan->desc;
if (!mdesc) {
dev_warn(mdma2dev(mchan->mdma),
@@ -740,8 +766,7 @@ static irqreturn_t mdc_chan_irq(int irq, void *dev_id)
goto out;
}
- for (i = processed; i != done1;
- i = (i + 1) % (MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK + 1)) {
+ for (i = 0; i < new_events; i++) {
/*
* The first interrupt in a transfer indicates that the
* command list has been loaded, not that a command has
@@ -979,7 +1004,6 @@ static int mdc_dma_remove(struct platform_device *pdev)
vc.chan.device_node) {
list_del(&mchan->vc.chan.device_node);
- synchronize_irq(mchan->irq);
devm_free_irq(&pdev->dev, mchan->irq, mchan);
tasklet_kill(&mchan->vc.task);
diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c
index 2cb7c308d5c7..0b9b6b07db9e 100644
--- a/drivers/dma/ioat/dca.c
+++ b/drivers/dma/ioat/dca.c
@@ -224,7 +224,7 @@ static u8 ioat_dca_get_tag(struct dca_provider *dca,
return tag;
}
-static struct dca_ops ioat_dca_ops = {
+static const struct dca_ops ioat_dca_ops = {
.add_requester = ioat_dca_add_requester,
.remove_requester = ioat_dca_remove_requester,
.get_tag = ioat_dca_get_tag,
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index 8f4e607d5817..b8f48074789f 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -235,43 +235,11 @@ ioat_chan_by_index(struct ioatdma_device *ioat_dma, int index)
return ioat_dma->idx[index];
}
-static inline u64 ioat_chansts_32(struct ioatdma_chan *ioat_chan)
-{
- u8 ver = ioat_chan->ioat_dma->version;
- u64 status;
- u32 status_lo;
-
- /* We need to read the low address first as this causes the
- * chipset to latch the upper bits for the subsequent read
- */
- status_lo = readl(ioat_chan->reg_base + IOAT_CHANSTS_OFFSET_LOW(ver));
- status = readl(ioat_chan->reg_base + IOAT_CHANSTS_OFFSET_HIGH(ver));
- status <<= 32;
- status |= status_lo;
-
- return status;
-}
-
-#if BITS_PER_LONG == 64
-
static inline u64 ioat_chansts(struct ioatdma_chan *ioat_chan)
{
- u8 ver = ioat_chan->ioat_dma->version;
- u64 status;
-
- /* With IOAT v3.3 the status register is 64bit. */
- if (ver >= IOAT_VER_3_3)
- status = readq(ioat_chan->reg_base + IOAT_CHANSTS_OFFSET(ver));
- else
- status = ioat_chansts_32(ioat_chan);
-
- return status;
+ return readq(ioat_chan->reg_base + IOAT_CHANSTS_OFFSET);
}
-#else
-#define ioat_chansts ioat_chansts_32
-#endif
-
static inline u64 ioat_chansts_to_addr(u64 status)
{
return status & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h
index 909352f74c89..4994a3623aee 100644
--- a/drivers/dma/ioat/registers.h
+++ b/drivers/dma/ioat/registers.h
@@ -99,19 +99,9 @@
#define IOAT_DMA_COMP_V1 0x0001 /* Compatibility with DMA version 1 */
#define IOAT_DMA_COMP_V2 0x0002 /* Compatibility with DMA version 2 */
-
-#define IOAT1_CHANSTS_OFFSET 0x04 /* 64-bit Channel Status Register */
-#define IOAT2_CHANSTS_OFFSET 0x08 /* 64-bit Channel Status Register */
-#define IOAT_CHANSTS_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
- ? IOAT1_CHANSTS_OFFSET : IOAT2_CHANSTS_OFFSET)
-#define IOAT1_CHANSTS_OFFSET_LOW 0x04
-#define IOAT2_CHANSTS_OFFSET_LOW 0x08
-#define IOAT_CHANSTS_OFFSET_LOW(ver) ((ver) < IOAT_VER_2_0 \
- ? IOAT1_CHANSTS_OFFSET_LOW : IOAT2_CHANSTS_OFFSET_LOW)
-#define IOAT1_CHANSTS_OFFSET_HIGH 0x08
-#define IOAT2_CHANSTS_OFFSET_HIGH 0x0C
-#define IOAT_CHANSTS_OFFSET_HIGH(ver) ((ver) < IOAT_VER_2_0 \
- ? IOAT1_CHANSTS_OFFSET_HIGH : IOAT2_CHANSTS_OFFSET_HIGH)
+/* IOAT1 define left for i7300_idle driver to not fail compiling */
+#define IOAT1_CHANSTS_OFFSET 0x04
+#define IOAT_CHANSTS_OFFSET 0x08 /* 64-bit Channel Status Register */
#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR (~0x3fULL)
#define IOAT_CHANSTS_SOFT_ERR 0x10ULL
#define IOAT_CHANSTS_UNAFFILIATED_ERR 0x8ULL
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 1c2de9a834a9..14091f878f80 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -139,46 +139,10 @@ static void mv_chan_clear_err_status(struct mv_xor_chan *chan)
}
static void mv_chan_set_mode(struct mv_xor_chan *chan,
- enum dma_transaction_type type)
+ u32 op_mode)
{
- u32 op_mode;
u32 config = readl_relaxed(XOR_CONFIG(chan));
- switch (type) {
- case DMA_XOR:
- op_mode = XOR_OPERATION_MODE_XOR;
- break;
- case DMA_MEMCPY:
- op_mode = XOR_OPERATION_MODE_MEMCPY;
- break;
- default:
- dev_err(mv_chan_to_devp(chan),
- "error: unsupported operation %d\n",
- type);
- BUG();
- return;
- }
-
- config &= ~0x7;
- config |= op_mode;
-
-#if defined(__BIG_ENDIAN)
- config |= XOR_DESCRIPTOR_SWAP;
-#else
- config &= ~XOR_DESCRIPTOR_SWAP;
-#endif
-
- writel_relaxed(config, XOR_CONFIG(chan));
- chan->current_type = type;
-}
-
-static void mv_chan_set_mode_to_desc(struct mv_xor_chan *chan)
-{
- u32 op_mode;
- u32 config = readl_relaxed(XOR_CONFIG(chan));
-
- op_mode = XOR_OPERATION_MODE_IN_DESC;
-
config &= ~0x7;
config |= op_mode;
@@ -1043,9 +1007,9 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
mv_chan_unmask_interrupts(mv_chan);
if (mv_chan->op_in_desc == XOR_MODE_IN_DESC)
- mv_chan_set_mode_to_desc(mv_chan);
+ mv_chan_set_mode(mv_chan, XOR_OPERATION_MODE_IN_DESC);
else
- mv_chan_set_mode(mv_chan, DMA_XOR);
+ mv_chan_set_mode(mv_chan, XOR_OPERATION_MODE_XOR);
spin_lock_init(&mv_chan->lock);
INIT_LIST_HEAD(&mv_chan->chain);
@@ -1121,6 +1085,57 @@ mv_xor_conf_mbus_windows(struct mv_xor_device *xordev,
writel(0, base + WINDOW_OVERRIDE_CTRL(1));
}
+/*
+ * Since this XOR driver is basically used only for RAID5, we don't
+ * need to care about synchronizing ->suspend with DMA activity,
+ * because the DMA engine will naturally be quiet due to the block
+ * devices being suspended.
+ */
+static int mv_xor_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mv_xor_device *xordev = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) {
+ struct mv_xor_chan *mv_chan = xordev->channels[i];
+
+ if (!mv_chan)
+ continue;
+
+ mv_chan->saved_config_reg =
+ readl_relaxed(XOR_CONFIG(mv_chan));
+ mv_chan->saved_int_mask_reg =
+ readl_relaxed(XOR_INTR_MASK(mv_chan));
+ }
+
+ return 0;
+}
+
+static int mv_xor_resume(struct platform_device *dev)
+{
+ struct mv_xor_device *xordev = platform_get_drvdata(dev);
+ const struct mbus_dram_target_info *dram;
+ int i;
+
+ for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) {
+ struct mv_xor_chan *mv_chan = xordev->channels[i];
+
+ if (!mv_chan)
+ continue;
+
+ writel_relaxed(mv_chan->saved_config_reg,
+ XOR_CONFIG(mv_chan));
+ writel_relaxed(mv_chan->saved_int_mask_reg,
+ XOR_INTR_MASK(mv_chan));
+ }
+
+ dram = mv_mbus_dram_info();
+ if (dram)
+ mv_xor_conf_mbus_windows(xordev, dram);
+
+ return 0;
+}
+
static const struct of_device_id mv_xor_dt_ids[] = {
{ .compatible = "marvell,orion-xor", .data = (void *)XOR_MODE_IN_REG },
{ .compatible = "marvell,armada-380-xor", .data = (void *)XOR_MODE_IN_DESC },
@@ -1282,6 +1297,8 @@ err_channel_add:
static struct platform_driver mv_xor_driver = {
.probe = mv_xor_probe,
+ .suspend = mv_xor_suspend,
+ .resume = mv_xor_resume,
.driver = {
.name = MV_XOR_NAME,
.of_match_table = of_match_ptr(mv_xor_dt_ids),
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index b7455b42137b..c19fe30e5ae9 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -110,7 +110,6 @@ struct mv_xor_chan {
void __iomem *mmr_high_base;
unsigned int idx;
int irq;
- enum dma_transaction_type current_type;
struct list_head chain;
struct list_head free_slots;
struct list_head allocated_slots;
@@ -126,6 +125,7 @@ struct mv_xor_chan {
char dummy_src[MV_XOR_MIN_BYTE_COUNT];
char dummy_dst[MV_XOR_MIN_BYTE_COUNT];
dma_addr_t dummy_src_addr, dummy_dst_addr;
+ u32 saved_config_reg, saved_int_mask_reg;
};
/**
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index 1dfc71c90123..9794b073d7d7 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -28,8 +28,6 @@
struct omap_dmadev {
struct dma_device ddev;
spinlock_t lock;
- struct tasklet_struct task;
- struct list_head pending;
void __iomem *base;
const struct omap_dma_reg *reg_map;
struct omap_system_dma_plat_info *plat;
@@ -42,7 +40,6 @@ struct omap_dmadev {
struct omap_chan {
struct virt_dma_chan vc;
- struct list_head node;
void __iomem *channel_base;
const struct omap_dma_reg *reg_map;
uint32_t ccr;
@@ -454,33 +451,6 @@ static void omap_dma_callback(int ch, u16 status, void *data)
spin_unlock_irqrestore(&c->vc.lock, flags);
}
-/*
- * This callback schedules all pending channels. We could be more
- * clever here by postponing allocation of the real DMA channels to
- * this point, and freeing them when our virtual channel becomes idle.
- *
- * We would then need to deal with 'all channels in-use'
- */
-static void omap_dma_sched(unsigned long data)
-{
- struct omap_dmadev *d = (struct omap_dmadev *)data;
- LIST_HEAD(head);
-
- spin_lock_irq(&d->lock);
- list_splice_tail_init(&d->pending, &head);
- spin_unlock_irq(&d->lock);
-
- while (!list_empty(&head)) {
- struct omap_chan *c = list_first_entry(&head,
- struct omap_chan, node);
-
- spin_lock_irq(&c->vc.lock);
- list_del_init(&c->node);
- omap_dma_start_desc(c);
- spin_unlock_irq(&c->vc.lock);
- }
-}
-
static irqreturn_t omap_dma_irq(int irq, void *devid)
{
struct omap_dmadev *od = devid;
@@ -703,8 +673,14 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan,
struct omap_chan *c = to_omap_dma_chan(chan);
struct virt_dma_desc *vd;
enum dma_status ret;
+ uint32_t ccr;
unsigned long flags;
+ ccr = omap_dma_chan_read(c, CCR);
+ /* The channel is no longer active, handle the completion right away */
+ if (!(ccr & CCR_ENABLE))
+ omap_dma_callback(c->dma_ch, 0, c);
+
ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_COMPLETE || !txstate)
return ret;
@@ -719,7 +695,7 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan,
if (d->dir == DMA_MEM_TO_DEV)
pos = omap_dma_get_src_pos(c);
- else if (d->dir == DMA_DEV_TO_MEM)
+ else if (d->dir == DMA_DEV_TO_MEM || d->dir == DMA_MEM_TO_MEM)
pos = omap_dma_get_dst_pos(c);
else
pos = 0;
@@ -739,22 +715,8 @@ static void omap_dma_issue_pending(struct dma_chan *chan)
unsigned long flags;
spin_lock_irqsave(&c->vc.lock, flags);
- if (vchan_issue_pending(&c->vc) && !c->desc) {
- /*
- * c->cyclic is used only by audio and in this case the DMA need
- * to be started without delay.
- */
- if (!c->cyclic) {
- struct omap_dmadev *d = to_omap_dma_dev(chan->device);
- spin_lock(&d->lock);
- if (list_empty(&c->node))
- list_add_tail(&c->node, &d->pending);
- spin_unlock(&d->lock);
- tasklet_schedule(&d->task);
- } else {
- omap_dma_start_desc(c);
- }
- }
+ if (vchan_issue_pending(&c->vc) && !c->desc)
+ omap_dma_start_desc(c);
spin_unlock_irqrestore(&c->vc.lock, flags);
}
@@ -768,7 +730,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
struct scatterlist *sgent;
struct omap_desc *d;
dma_addr_t dev_addr;
- unsigned i, j = 0, es, en, frame_bytes;
+ unsigned i, es, en, frame_bytes;
u32 burst;
if (dir == DMA_DEV_TO_MEM) {
@@ -845,13 +807,12 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
en = burst;
frame_bytes = es_bytes[es] * en;
for_each_sg(sgl, sgent, sglen, i) {
- d->sg[j].addr = sg_dma_address(sgent);
- d->sg[j].en = en;
- d->sg[j].fn = sg_dma_len(sgent) / frame_bytes;
- j++;
+ d->sg[i].addr = sg_dma_address(sgent);
+ d->sg[i].en = en;
+ d->sg[i].fn = sg_dma_len(sgent) / frame_bytes;
}
- d->sglen = j;
+ d->sglen = sglen;
return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
}
@@ -1018,17 +979,11 @@ static int omap_dma_slave_config(struct dma_chan *chan, struct dma_slave_config
static int omap_dma_terminate_all(struct dma_chan *chan)
{
struct omap_chan *c = to_omap_dma_chan(chan);
- struct omap_dmadev *d = to_omap_dma_dev(c->vc.chan.device);
unsigned long flags;
LIST_HEAD(head);
spin_lock_irqsave(&c->vc.lock, flags);
- /* Prevent this channel being scheduled */
- spin_lock(&d->lock);
- list_del_init(&c->node);
- spin_unlock(&d->lock);
-
/*
* Stop DMA activity: we assume the callback will not be called
* after omap_dma_stop() returns (even if it does, it will see
@@ -1102,14 +1057,12 @@ static int omap_dma_chan_init(struct omap_dmadev *od)
c->reg_map = od->reg_map;
c->vc.desc_free = omap_dma_desc_free;
vchan_init(&c->vc, &od->ddev);
- INIT_LIST_HEAD(&c->node);
return 0;
}
static void omap_dma_free(struct omap_dmadev *od)
{
- tasklet_kill(&od->task);
while (!list_empty(&od->ddev.channels)) {
struct omap_chan *c = list_first_entry(&od->ddev.channels,
struct omap_chan, vc.chan.device_node);
@@ -1165,12 +1118,9 @@ static int omap_dma_probe(struct platform_device *pdev)
od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
od->ddev.dev = &pdev->dev;
INIT_LIST_HEAD(&od->ddev.channels);
- INIT_LIST_HEAD(&od->pending);
spin_lock_init(&od->lock);
spin_lock_init(&od->irq_lock);
- tasklet_init(&od->task, omap_dma_sched, (unsigned long)od);
-
od->dma_requests = OMAP_SDMA_REQUESTS;
if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
"dma-requests",
@@ -1203,6 +1153,10 @@ static int omap_dma_probe(struct platform_device *pdev)
return rc;
}
+ od->ddev.filter.map = od->plat->slave_map;
+ od->ddev.filter.mapcnt = od->plat->slavecnt;
+ od->ddev.filter.fn = omap_dma_filter_fn;
+
rc = dma_async_device_register(&od->ddev);
if (rc) {
pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n",
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index fc4156afa070..f2a0310ae771 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1414,6 +1414,7 @@ static int pxad_probe(struct platform_device *op)
pdev->slave.dst_addr_widths = widths;
pdev->slave.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
pdev->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+ pdev->slave.descriptor_reuse = true;
pdev->slave.dev = &op->dev;
ret = pxad_init_dmadev(op, pdev, dma_channels);
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 9fda65af841e..f32c430eb16c 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -47,12 +47,6 @@ config RCAR_DMAC
This driver supports the general purpose DMA controller found in the
Renesas R-Car second generation SoCs.
-config RCAR_HPB_DMAE
- tristate "Renesas R-Car HPB DMAC support"
- depends on SH_DMAE_BASE
- help
- Enable support for the Renesas R-Car series DMA controllers.
-
config RENESAS_USB_DMAC
tristate "Renesas USB-DMA Controller"
depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index 0133e4658196..f1e2fd64f279 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -14,6 +14,5 @@ shdma-objs := $(shdma-y)
obj-$(CONFIG_SH_DMAE) += shdma.o
obj-$(CONFIG_RCAR_DMAC) += rcar-dmac.o
-obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
obj-$(CONFIG_RENESAS_USB_DMAC) += usb-dmac.o
obj-$(CONFIG_SUDMAC) += sudmac.o
diff --git a/drivers/dma/sh/rcar-hpbdma.c b/drivers/dma/sh/rcar-hpbdma.c
deleted file mode 100644
index 749f26ecd3b3..000000000000
--- a/drivers/dma/sh/rcar-hpbdma.c
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2011-2013 Renesas Electronics Corporation
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * This file is based on the drivers/dma/sh/shdma.c
- *
- * Renesas SuperH DMA Engine support
- *
- * 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.
- *
- * - DMA of SuperH does not have Hardware DMA chain mode.
- * - max DMA size is 16MB.
- *
- */
-
-#include <linux/dmaengine.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_data/dma-rcar-hpbdma.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/shdma-base.h>
-#include <linux/slab.h>
-
-/* DMA channel registers */
-#define HPB_DMAE_DSAR0 0x00
-#define HPB_DMAE_DDAR0 0x04
-#define HPB_DMAE_DTCR0 0x08
-#define HPB_DMAE_DSAR1 0x0C
-#define HPB_DMAE_DDAR1 0x10
-#define HPB_DMAE_DTCR1 0x14
-#define HPB_DMAE_DSASR 0x18
-#define HPB_DMAE_DDASR 0x1C
-#define HPB_DMAE_DTCSR 0x20
-#define HPB_DMAE_DPTR 0x24
-#define HPB_DMAE_DCR 0x28
-#define HPB_DMAE_DCMDR 0x2C
-#define HPB_DMAE_DSTPR 0x30
-#define HPB_DMAE_DSTSR 0x34
-#define HPB_DMAE_DDBGR 0x38
-#define HPB_DMAE_DDBGR2 0x3C
-#define HPB_DMAE_CHAN(n) (0x40 * (n))
-
-/* DMA command register (DCMDR) bits */
-#define HPB_DMAE_DCMDR_BDOUT BIT(7)
-#define HPB_DMAE_DCMDR_DQSPD BIT(6)
-#define HPB_DMAE_DCMDR_DQSPC BIT(5)
-#define HPB_DMAE_DCMDR_DMSPD BIT(4)
-#define HPB_DMAE_DCMDR_DMSPC BIT(3)
-#define HPB_DMAE_DCMDR_DQEND BIT(2)
-#define HPB_DMAE_DCMDR_DNXT BIT(1)
-#define HPB_DMAE_DCMDR_DMEN BIT(0)
-
-/* DMA forced stop register (DSTPR) bits */
-#define HPB_DMAE_DSTPR_DMSTP BIT(0)
-
-/* DMA status register (DSTSR) bits */
-#define HPB_DMAE_DSTSR_DQSTS BIT(2)
-#define HPB_DMAE_DSTSR_DMSTS BIT(0)
-
-/* DMA common registers */
-#define HPB_DMAE_DTIMR 0x00
-#define HPB_DMAE_DINTSR0 0x0C
-#define HPB_DMAE_DINTSR1 0x10
-#define HPB_DMAE_DINTCR0 0x14
-#define HPB_DMAE_DINTCR1 0x18
-#define HPB_DMAE_DINTMR0 0x1C
-#define HPB_DMAE_DINTMR1 0x20
-#define HPB_DMAE_DACTSR0 0x24
-#define HPB_DMAE_DACTSR1 0x28
-#define HPB_DMAE_HSRSTR(n) (0x40 + (n) * 4)
-#define HPB_DMAE_HPB_DMASPR(n) (0x140 + (n) * 4)
-#define HPB_DMAE_HPB_DMLVLR0 0x160
-#define HPB_DMAE_HPB_DMLVLR1 0x164
-#define HPB_DMAE_HPB_DMSHPT0 0x168
-#define HPB_DMAE_HPB_DMSHPT1 0x16C
-
-#define HPB_DMA_SLAVE_NUMBER 256
-#define HPB_DMA_TCR_MAX 0x01000000 /* 16 MiB */
-
-struct hpb_dmae_chan {
- struct shdma_chan shdma_chan;
- int xfer_mode; /* DMA transfer mode */
-#define XFER_SINGLE 1
-#define XFER_DOUBLE 2
- unsigned plane_idx; /* current DMA information set */
- bool first_desc; /* first/next transfer */
- int xmit_shift; /* log_2(bytes_per_xfer) */
- void __iomem *base;
- const struct hpb_dmae_slave_config *cfg;
- char dev_id[16]; /* unique name per DMAC of channel */
- dma_addr_t slave_addr;
-};
-
-struct hpb_dmae_device {
- struct shdma_dev shdma_dev;
- spinlock_t reg_lock; /* comm_reg operation lock */
- struct hpb_dmae_pdata *pdata;
- void __iomem *chan_reg;
- void __iomem *comm_reg;
- void __iomem *reset_reg;
- void __iomem *mode_reg;
-};
-
-struct hpb_dmae_regs {
- u32 sar; /* SAR / source address */
- u32 dar; /* DAR / destination address */
- u32 tcr; /* TCR / transfer count */
-};
-
-struct hpb_desc {
- struct shdma_desc shdma_desc;
- struct hpb_dmae_regs hw;
- unsigned plane_idx;
-};
-
-#define to_chan(schan) container_of(schan, struct hpb_dmae_chan, shdma_chan)
-#define to_desc(sdesc) container_of(sdesc, struct hpb_desc, shdma_desc)
-#define to_dev(sc) container_of(sc->shdma_chan.dma_chan.device, \
- struct hpb_dmae_device, shdma_dev.dma_dev)
-
-static void ch_reg_write(struct hpb_dmae_chan *hpb_dc, u32 data, u32 reg)
-{
- iowrite32(data, hpb_dc->base + reg);
-}
-
-static u32 ch_reg_read(struct hpb_dmae_chan *hpb_dc, u32 reg)
-{
- return ioread32(hpb_dc->base + reg);
-}
-
-static void dcmdr_write(struct hpb_dmae_device *hpbdev, u32 data)
-{
- iowrite32(data, hpbdev->chan_reg + HPB_DMAE_DCMDR);
-}
-
-static void hsrstr_write(struct hpb_dmae_device *hpbdev, u32 ch)
-{
- iowrite32(0x1, hpbdev->comm_reg + HPB_DMAE_HSRSTR(ch));
-}
-
-static u32 dintsr_read(struct hpb_dmae_device *hpbdev, u32 ch)
-{
- u32 v;
-
- if (ch < 32)
- v = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTSR0) >> ch;
- else
- v = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTSR1) >> (ch - 32);
- return v & 0x1;
-}
-
-static void dintcr_write(struct hpb_dmae_device *hpbdev, u32 ch)
-{
- if (ch < 32)
- iowrite32((0x1 << ch), hpbdev->comm_reg + HPB_DMAE_DINTCR0);
- else
- iowrite32((0x1 << (ch - 32)),
- hpbdev->comm_reg + HPB_DMAE_DINTCR1);
-}
-
-static void asyncmdr_write(struct hpb_dmae_device *hpbdev, u32 data)
-{
- iowrite32(data, hpbdev->mode_reg);
-}
-
-static u32 asyncmdr_read(struct hpb_dmae_device *hpbdev)
-{
- return ioread32(hpbdev->mode_reg);
-}
-
-static void hpb_dmae_enable_int(struct hpb_dmae_device *hpbdev, u32 ch)
-{
- u32 intreg;
-
- spin_lock_irq(&hpbdev->reg_lock);
- if (ch < 32) {
- intreg = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTMR0);
- iowrite32(BIT(ch) | intreg,
- hpbdev->comm_reg + HPB_DMAE_DINTMR0);
- } else {
- intreg = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTMR1);
- iowrite32(BIT(ch - 32) | intreg,
- hpbdev->comm_reg + HPB_DMAE_DINTMR1);
- }
- spin_unlock_irq(&hpbdev->reg_lock);
-}
-
-static void hpb_dmae_async_reset(struct hpb_dmae_device *hpbdev, u32 data)
-{
- u32 rstr;
- int timeout = 10000; /* 100 ms */
-
- spin_lock(&hpbdev->reg_lock);
- rstr = ioread32(hpbdev->reset_reg);
- rstr |= data;
- iowrite32(rstr, hpbdev->reset_reg);
- do {
- rstr = ioread32(hpbdev->reset_reg);
- if ((rstr & data) == data)
- break;
- udelay(10);
- } while (timeout--);
-
- if (timeout < 0)
- dev_err(hpbdev->shdma_dev.dma_dev.dev,
- "%s timeout\n", __func__);
-
- rstr &= ~data;
- iowrite32(rstr, hpbdev->reset_reg);
- spin_unlock(&hpbdev->reg_lock);
-}
-
-static void hpb_dmae_set_async_mode(struct hpb_dmae_device *hpbdev,
- u32 mask, u32 data)
-{
- u32 mode;
-
- spin_lock_irq(&hpbdev->reg_lock);
- mode = asyncmdr_read(hpbdev);
- mode &= ~mask;
- mode |= data;
- asyncmdr_write(hpbdev, mode);
- spin_unlock_irq(&hpbdev->reg_lock);
-}
-
-static void hpb_dmae_ctl_stop(struct hpb_dmae_device *hpbdev)
-{
- dcmdr_write(hpbdev, HPB_DMAE_DCMDR_DQSPD);
-}
-
-static void hpb_dmae_reset(struct hpb_dmae_device *hpbdev)
-{
- u32 ch;
-
- for (ch = 0; ch < hpbdev->pdata->num_hw_channels; ch++)
- hsrstr_write(hpbdev, ch);
-}
-
-static unsigned int calc_xmit_shift(struct hpb_dmae_chan *hpb_chan)
-{
- struct hpb_dmae_device *hpbdev = to_dev(hpb_chan);
- struct hpb_dmae_pdata *pdata = hpbdev->pdata;
- int width = ch_reg_read(hpb_chan, HPB_DMAE_DCR);
- int i;
-
- switch (width & (HPB_DMAE_DCR_SPDS_MASK | HPB_DMAE_DCR_DPDS_MASK)) {
- case HPB_DMAE_DCR_SPDS_8BIT | HPB_DMAE_DCR_DPDS_8BIT:
- default:
- i = XMIT_SZ_8BIT;
- break;
- case HPB_DMAE_DCR_SPDS_16BIT | HPB_DMAE_DCR_DPDS_16BIT:
- i = XMIT_SZ_16BIT;
- break;
- case HPB_DMAE_DCR_SPDS_32BIT | HPB_DMAE_DCR_DPDS_32BIT:
- i = XMIT_SZ_32BIT;
- break;
- }
- return pdata->ts_shift[i];
-}
-
-static void hpb_dmae_set_reg(struct hpb_dmae_chan *hpb_chan,
- struct hpb_dmae_regs *hw, unsigned plane)
-{
- ch_reg_write(hpb_chan, hw->sar,
- plane ? HPB_DMAE_DSAR1 : HPB_DMAE_DSAR0);
- ch_reg_write(hpb_chan, hw->dar,
- plane ? HPB_DMAE_DDAR1 : HPB_DMAE_DDAR0);
- ch_reg_write(hpb_chan, hw->tcr >> hpb_chan->xmit_shift,
- plane ? HPB_DMAE_DTCR1 : HPB_DMAE_DTCR0);
-}
-
-static void hpb_dmae_start(struct hpb_dmae_chan *hpb_chan, bool next)
-{
- ch_reg_write(hpb_chan, (next ? HPB_DMAE_DCMDR_DNXT : 0) |
- HPB_DMAE_DCMDR_DMEN, HPB_DMAE_DCMDR);
-}
-
-static void hpb_dmae_halt(struct shdma_chan *schan)
-{
- struct hpb_dmae_chan *chan = to_chan(schan);
-
- ch_reg_write(chan, HPB_DMAE_DCMDR_DQEND, HPB_DMAE_DCMDR);
- ch_reg_write(chan, HPB_DMAE_DSTPR_DMSTP, HPB_DMAE_DSTPR);
-
- chan->plane_idx = 0;
- chan->first_desc = true;
-}
-
-static const struct hpb_dmae_slave_config *
-hpb_dmae_find_slave(struct hpb_dmae_chan *hpb_chan, int slave_id)
-{
- struct hpb_dmae_device *hpbdev = to_dev(hpb_chan);
- struct hpb_dmae_pdata *pdata = hpbdev->pdata;
- int i;
-
- if (slave_id >= HPB_DMA_SLAVE_NUMBER)
- return NULL;
-
- for (i = 0; i < pdata->num_slaves; i++)
- if (pdata->slaves[i].id == slave_id)
- return pdata->slaves + i;
-
- return NULL;
-}
-
-static void hpb_dmae_start_xfer(struct shdma_chan *schan,
- struct shdma_desc *sdesc)
-{
- struct hpb_dmae_chan *chan = to_chan(schan);
- struct hpb_dmae_device *hpbdev = to_dev(chan);
- struct hpb_desc *desc = to_desc(sdesc);
-
- if (chan->cfg->flags & HPB_DMAE_SET_ASYNC_RESET)
- hpb_dmae_async_reset(hpbdev, chan->cfg->rstr);
-
- desc->plane_idx = chan->plane_idx;
- hpb_dmae_set_reg(chan, &desc->hw, chan->plane_idx);
- hpb_dmae_start(chan, !chan->first_desc);
-
- if (chan->xfer_mode == XFER_DOUBLE) {
- chan->plane_idx ^= 1;
- chan->first_desc = false;
- }
-}
-
-static bool hpb_dmae_desc_completed(struct shdma_chan *schan,
- struct shdma_desc *sdesc)
-{
- /*
- * This is correct since we always have at most single
- * outstanding DMA transfer per channel, and by the time
- * we get completion interrupt the transfer is completed.
- * This will change if we ever use alternating DMA
- * information sets and submit two descriptors at once.
- */
- return true;
-}
-
-static bool hpb_dmae_chan_irq(struct shdma_chan *schan, int irq)
-{
- struct hpb_dmae_chan *chan = to_chan(schan);
- struct hpb_dmae_device *hpbdev = to_dev(chan);
- int ch = chan->cfg->dma_ch;
-
- /* Check Complete DMA Transfer */
- if (dintsr_read(hpbdev, ch)) {
- /* Clear Interrupt status */
- dintcr_write(hpbdev, ch);
- return true;
- }
- return false;
-}
-
-static int hpb_dmae_desc_setup(struct shdma_chan *schan,
- struct shdma_desc *sdesc,
- dma_addr_t src, dma_addr_t dst, size_t *len)
-{
- struct hpb_desc *desc = to_desc(sdesc);
-
- if (*len > (size_t)HPB_DMA_TCR_MAX)
- *len = (size_t)HPB_DMA_TCR_MAX;
-
- desc->hw.sar = src;
- desc->hw.dar = dst;
- desc->hw.tcr = *len;
-
- return 0;
-}
-
-static size_t hpb_dmae_get_partial(struct shdma_chan *schan,
- struct shdma_desc *sdesc)
-{
- struct hpb_desc *desc = to_desc(sdesc);
- struct hpb_dmae_chan *chan = to_chan(schan);
- u32 tcr = ch_reg_read(chan, desc->plane_idx ?
- HPB_DMAE_DTCR1 : HPB_DMAE_DTCR0);
-
- return (desc->hw.tcr - tcr) << chan->xmit_shift;
-}
-
-static bool hpb_dmae_channel_busy(struct shdma_chan *schan)
-{
- struct hpb_dmae_chan *chan = to_chan(schan);
- u32 dstsr = ch_reg_read(chan, HPB_DMAE_DSTSR);
-
- if (chan->xfer_mode == XFER_DOUBLE)
- return dstsr & HPB_DMAE_DSTSR_DQSTS;
- else
- return dstsr & HPB_DMAE_DSTSR_DMSTS;
-}
-
-static int
-hpb_dmae_alloc_chan_resources(struct hpb_dmae_chan *hpb_chan,
- const struct hpb_dmae_slave_config *cfg)
-{
- struct hpb_dmae_device *hpbdev = to_dev(hpb_chan);
- struct hpb_dmae_pdata *pdata = hpbdev->pdata;
- const struct hpb_dmae_channel *channel = pdata->channels;
- int slave_id = cfg->id;
- int i, err;
-
- for (i = 0; i < pdata->num_channels; i++, channel++) {
- if (channel->s_id == slave_id) {
- struct device *dev = hpb_chan->shdma_chan.dev;
-
- hpb_chan->base = hpbdev->chan_reg +
- HPB_DMAE_CHAN(cfg->dma_ch);
-
- dev_dbg(dev, "Detected Slave device\n");
- dev_dbg(dev, " -- slave_id : 0x%x\n", slave_id);
- dev_dbg(dev, " -- cfg->dma_ch : %d\n", cfg->dma_ch);
- dev_dbg(dev, " -- channel->ch_irq: %d\n",
- channel->ch_irq);
- break;
- }
- }
-
- err = shdma_request_irq(&hpb_chan->shdma_chan, channel->ch_irq,
- IRQF_SHARED, hpb_chan->dev_id);
- if (err) {
- dev_err(hpb_chan->shdma_chan.dev,
- "DMA channel request_irq %d failed with error %d\n",
- channel->ch_irq, err);
- return err;
- }
-
- hpb_chan->plane_idx = 0;
- hpb_chan->first_desc = true;
-
- if ((cfg->dcr & (HPB_DMAE_DCR_CT | HPB_DMAE_DCR_DIP)) == 0) {
- hpb_chan->xfer_mode = XFER_SINGLE;
- } else if ((cfg->dcr & (HPB_DMAE_DCR_CT | HPB_DMAE_DCR_DIP)) ==
- (HPB_DMAE_DCR_CT | HPB_DMAE_DCR_DIP)) {
- hpb_chan->xfer_mode = XFER_DOUBLE;
- } else {
- dev_err(hpb_chan->shdma_chan.dev, "DCR setting error");
- return -EINVAL;
- }
-
- if (cfg->flags & HPB_DMAE_SET_ASYNC_MODE)
- hpb_dmae_set_async_mode(hpbdev, cfg->mdm, cfg->mdr);
- ch_reg_write(hpb_chan, cfg->dcr, HPB_DMAE_DCR);
- ch_reg_write(hpb_chan, cfg->port, HPB_DMAE_DPTR);
- hpb_chan->xmit_shift = calc_xmit_shift(hpb_chan);
- hpb_dmae_enable_int(hpbdev, cfg->dma_ch);
-
- return 0;
-}
-
-static int hpb_dmae_set_slave(struct shdma_chan *schan, int slave_id,
- dma_addr_t slave_addr, bool try)
-{
- struct hpb_dmae_chan *chan = to_chan(schan);
- const struct hpb_dmae_slave_config *sc =
- hpb_dmae_find_slave(chan, slave_id);
-
- if (!sc)
- return -ENODEV;
- if (try)
- return 0;
- chan->cfg = sc;
- chan->slave_addr = slave_addr ? : sc->addr;
- return hpb_dmae_alloc_chan_resources(chan, sc);
-}
-
-static void hpb_dmae_setup_xfer(struct shdma_chan *schan, int slave_id)
-{
-}
-
-static dma_addr_t hpb_dmae_slave_addr(struct shdma_chan *schan)
-{
- struct hpb_dmae_chan *chan = to_chan(schan);
-
- return chan->slave_addr;
-}
-
-static struct shdma_desc *hpb_dmae_embedded_desc(void *buf, int i)
-{
- return &((struct hpb_desc *)buf)[i].shdma_desc;
-}
-
-static const struct shdma_ops hpb_dmae_ops = {
- .desc_completed = hpb_dmae_desc_completed,
- .halt_channel = hpb_dmae_halt,
- .channel_busy = hpb_dmae_channel_busy,
- .slave_addr = hpb_dmae_slave_addr,
- .desc_setup = hpb_dmae_desc_setup,
- .set_slave = hpb_dmae_set_slave,
- .setup_xfer = hpb_dmae_setup_xfer,
- .start_xfer = hpb_dmae_start_xfer,
- .embedded_desc = hpb_dmae_embedded_desc,
- .chan_irq = hpb_dmae_chan_irq,
- .get_partial = hpb_dmae_get_partial,
-};
-
-static int hpb_dmae_chan_probe(struct hpb_dmae_device *hpbdev, int id)
-{
- struct shdma_dev *sdev = &hpbdev->shdma_dev;
- struct platform_device *pdev =
- to_platform_device(hpbdev->shdma_dev.dma_dev.dev);
- struct hpb_dmae_chan *new_hpb_chan;
- struct shdma_chan *schan;
-
- /* Alloc channel */
- new_hpb_chan = devm_kzalloc(&pdev->dev,
- sizeof(struct hpb_dmae_chan), GFP_KERNEL);
- if (!new_hpb_chan) {
- dev_err(hpbdev->shdma_dev.dma_dev.dev,
- "No free memory for allocating DMA channels!\n");
- return -ENOMEM;
- }
-
- schan = &new_hpb_chan->shdma_chan;
- schan->max_xfer_len = HPB_DMA_TCR_MAX;
-
- shdma_chan_probe(sdev, schan, id);
-
- if (pdev->id >= 0)
- snprintf(new_hpb_chan->dev_id, sizeof(new_hpb_chan->dev_id),
- "hpb-dmae%d.%d", pdev->id, id);
- else
- snprintf(new_hpb_chan->dev_id, sizeof(new_hpb_chan->dev_id),
- "hpb-dma.%d", id);
-
- return 0;
-}
-
-static int hpb_dmae_probe(struct platform_device *pdev)
-{
- const enum dma_slave_buswidth widths = DMA_SLAVE_BUSWIDTH_1_BYTE |
- DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES;
- struct hpb_dmae_pdata *pdata = pdev->dev.platform_data;
- struct hpb_dmae_device *hpbdev;
- struct dma_device *dma_dev;
- struct resource *chan, *comm, *rest, *mode, *irq_res;
- int err, i;
-
- /* Get platform data */
- if (!pdata || !pdata->num_channels)
- return -ENODEV;
-
- chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- comm = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- rest = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- mode = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res)
- return -ENODEV;
-
- hpbdev = devm_kzalloc(&pdev->dev, sizeof(struct hpb_dmae_device),
- GFP_KERNEL);
- if (!hpbdev) {
- dev_err(&pdev->dev, "Not enough memory\n");
- return -ENOMEM;
- }
-
- hpbdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
- if (IS_ERR(hpbdev->chan_reg))
- return PTR_ERR(hpbdev->chan_reg);
-
- hpbdev->comm_reg = devm_ioremap_resource(&pdev->dev, comm);
- if (IS_ERR(hpbdev->comm_reg))
- return PTR_ERR(hpbdev->comm_reg);
-
- hpbdev->reset_reg = devm_ioremap_resource(&pdev->dev, rest);
- if (IS_ERR(hpbdev->reset_reg))
- return PTR_ERR(hpbdev->reset_reg);
-
- hpbdev->mode_reg = devm_ioremap_resource(&pdev->dev, mode);
- if (IS_ERR(hpbdev->mode_reg))
- return PTR_ERR(hpbdev->mode_reg);
-
- dma_dev = &hpbdev->shdma_dev.dma_dev;
-
- spin_lock_init(&hpbdev->reg_lock);
-
- /* Platform data */
- hpbdev->pdata = pdata;
-
- pm_runtime_enable(&pdev->dev);
- err = pm_runtime_get_sync(&pdev->dev);
- if (err < 0)
- dev_err(&pdev->dev, "%s(): GET = %d\n", __func__, err);
-
- /* Reset DMA controller */
- hpb_dmae_reset(hpbdev);
-
- pm_runtime_put(&pdev->dev);
-
- dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
- dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
- dma_dev->src_addr_widths = widths;
- dma_dev->dst_addr_widths = widths;
- dma_dev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
- dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
-
- hpbdev->shdma_dev.ops = &hpb_dmae_ops;
- hpbdev->shdma_dev.desc_size = sizeof(struct hpb_desc);
- err = shdma_init(&pdev->dev, &hpbdev->shdma_dev, pdata->num_channels);
- if (err < 0)
- goto error;
-
- /* Create DMA channels */
- for (i = 0; i < pdata->num_channels; i++)
- hpb_dmae_chan_probe(hpbdev, i);
-
- platform_set_drvdata(pdev, hpbdev);
- err = dma_async_device_register(dma_dev);
- if (!err)
- return 0;
-
- shdma_cleanup(&hpbdev->shdma_dev);
-error:
- pm_runtime_disable(&pdev->dev);
- return err;
-}
-
-static void hpb_dmae_chan_remove(struct hpb_dmae_device *hpbdev)
-{
- struct shdma_chan *schan;
- int i;
-
- shdma_for_each_chan(schan, &hpbdev->shdma_dev, i) {
- BUG_ON(!schan);
-
- shdma_chan_remove(schan);
- }
-}
-
-static int hpb_dmae_remove(struct platform_device *pdev)
-{
- struct hpb_dmae_device *hpbdev = platform_get_drvdata(pdev);
-
- dma_async_device_unregister(&hpbdev->shdma_dev.dma_dev);
-
- pm_runtime_disable(&pdev->dev);
-
- hpb_dmae_chan_remove(hpbdev);
-
- return 0;
-}
-
-static void hpb_dmae_shutdown(struct platform_device *pdev)
-{
- struct hpb_dmae_device *hpbdev = platform_get_drvdata(pdev);
- hpb_dmae_ctl_stop(hpbdev);
-}
-
-static struct platform_driver hpb_dmae_driver = {
- .probe = hpb_dmae_probe,
- .remove = hpb_dmae_remove,
- .shutdown = hpb_dmae_shutdown,
- .driver = {
- .name = "hpb-dma-engine",
- },
-};
-module_platform_driver(hpb_dmae_driver);
-
-MODULE_AUTHOR("Max Filippov <max.filippov@cogentembedded.com>");
-MODULE_DESCRIPTION("Renesas HPB DMA Engine driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index f1bcc2a163b3..749f1bd5d65d 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -448,7 +448,7 @@ usb_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
static int usb_dmac_chan_terminate_all(struct dma_chan *chan)
{
struct usb_dmac_chan *uchan = to_usb_dmac_chan(chan);
- struct usb_dmac_desc *desc;
+ struct usb_dmac_desc *desc, *_desc;
unsigned long flags;
LIST_HEAD(head);
LIST_HEAD(list);
@@ -459,7 +459,7 @@ static int usb_dmac_chan_terminate_all(struct dma_chan *chan)
if (uchan->desc)
uchan->desc = NULL;
list_splice_init(&uchan->desc_got, &list);
- list_for_each_entry(desc, &list, node)
+ list_for_each_entry_safe(desc, _desc, &list, node)
list_move_tail(&desc->node, &uchan->desc_freed);
spin_unlock_irqrestore(&uchan->vc.lock, flags);
vchan_dma_desc_free_list(&uchan->vc, &head);
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index dd3e7ba273ad..6fb8307468ab 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -3543,8 +3543,8 @@ static int __init d40_probe(struct platform_device *pdev)
struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
int ret = -ENOENT;
- struct d40_base *base = NULL;
- struct resource *res = NULL;
+ struct d40_base *base;
+ struct resource *res;
int num_reserved_chans;
u32 val;
@@ -3552,17 +3552,17 @@ static int __init d40_probe(struct platform_device *pdev)
if (np) {
if (d40_of_probe(pdev, np)) {
ret = -ENOMEM;
- goto failure;
+ goto report_failure;
}
} else {
d40_err(&pdev->dev, "No pdata or Device Tree provided\n");
- goto failure;
+ goto report_failure;
}
}
base = d40_hw_detect_init(pdev);
if (!base)
- goto failure;
+ goto report_failure;
num_reserved_chans = d40_phy_res_init(base);
@@ -3693,51 +3693,48 @@ static int __init d40_probe(struct platform_device *pdev)
return 0;
failure:
- if (base) {
- if (base->desc_slab)
- kmem_cache_destroy(base->desc_slab);
- if (base->virtbase)
- iounmap(base->virtbase);
-
- if (base->lcla_pool.base && base->plat_data->use_esram_lcla) {
- iounmap(base->lcla_pool.base);
- base->lcla_pool.base = NULL;
- }
+ kmem_cache_destroy(base->desc_slab);
+ if (base->virtbase)
+ iounmap(base->virtbase);
- if (base->lcla_pool.dma_addr)
- dma_unmap_single(base->dev, base->lcla_pool.dma_addr,
- SZ_1K * base->num_phy_chans,
- DMA_TO_DEVICE);
-
- if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
- free_pages((unsigned long)base->lcla_pool.base,
- base->lcla_pool.pages);
-
- kfree(base->lcla_pool.base_unaligned);
-
- if (base->phy_lcpa)
- release_mem_region(base->phy_lcpa,
- base->lcpa_size);
- if (base->phy_start)
- release_mem_region(base->phy_start,
- base->phy_size);
- if (base->clk) {
- clk_disable_unprepare(base->clk);
- clk_put(base->clk);
- }
+ if (base->lcla_pool.base && base->plat_data->use_esram_lcla) {
+ iounmap(base->lcla_pool.base);
+ base->lcla_pool.base = NULL;
+ }
- if (base->lcpa_regulator) {
- regulator_disable(base->lcpa_regulator);
- regulator_put(base->lcpa_regulator);
- }
+ if (base->lcla_pool.dma_addr)
+ dma_unmap_single(base->dev, base->lcla_pool.dma_addr,
+ SZ_1K * base->num_phy_chans,
+ DMA_TO_DEVICE);
- kfree(base->lcla_pool.alloc_map);
- kfree(base->lookup_log_chans);
- kfree(base->lookup_phy_chans);
- kfree(base->phy_res);
- kfree(base);
+ if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
+ free_pages((unsigned long)base->lcla_pool.base,
+ base->lcla_pool.pages);
+
+ kfree(base->lcla_pool.base_unaligned);
+
+ if (base->phy_lcpa)
+ release_mem_region(base->phy_lcpa,
+ base->lcpa_size);
+ if (base->phy_start)
+ release_mem_region(base->phy_start,
+ base->phy_size);
+ if (base->clk) {
+ clk_disable_unprepare(base->clk);
+ clk_put(base->clk);
+ }
+
+ if (base->lcpa_regulator) {
+ regulator_disable(base->lcpa_regulator);
+ regulator_put(base->lcpa_regulator);
}
+ kfree(base->lcla_pool.alloc_map);
+ kfree(base->lookup_log_chans);
+ kfree(base->lookup_phy_chans);
+ kfree(base->phy_res);
+ kfree(base);
+report_failure:
d40_err(&pdev->dev, "probe failed\n");
return ret;
}
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
new file mode 100644
index 000000000000..047476a1383d
--- /dev/null
+++ b/drivers/dma/stm32-dma.c
@@ -0,0 +1,1141 @@
+/*
+ * Driver for STM32 DMA controller
+ *
+ * Inspired by dma-jz4740.c and tegra20-apb-dma.c
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2015
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "virt-dma.h"
+
+#define STM32_DMA_LISR 0x0000 /* DMA Low Int Status Reg */
+#define STM32_DMA_HISR 0x0004 /* DMA High Int Status Reg */
+#define STM32_DMA_LIFCR 0x0008 /* DMA Low Int Flag Clear Reg */
+#define STM32_DMA_HIFCR 0x000c /* DMA High Int Flag Clear Reg */
+#define STM32_DMA_TCI BIT(5) /* Transfer Complete Interrupt */
+#define STM32_DMA_TEI BIT(3) /* Transfer Error Interrupt */
+#define STM32_DMA_DMEI BIT(2) /* Direct Mode Error Interrupt */
+#define STM32_DMA_FEI BIT(0) /* FIFO Error Interrupt */
+
+/* DMA Stream x Configuration Register */
+#define STM32_DMA_SCR(x) (0x0010 + 0x18 * (x)) /* x = 0..7 */
+#define STM32_DMA_SCR_REQ(n) ((n & 0x7) << 25)
+#define STM32_DMA_SCR_MBURST_MASK GENMASK(24, 23)
+#define STM32_DMA_SCR_MBURST(n) ((n & 0x3) << 23)
+#define STM32_DMA_SCR_PBURST_MASK GENMASK(22, 21)
+#define STM32_DMA_SCR_PBURST(n) ((n & 0x3) << 21)
+#define STM32_DMA_SCR_PL_MASK GENMASK(17, 16)
+#define STM32_DMA_SCR_PL(n) ((n & 0x3) << 16)
+#define STM32_DMA_SCR_MSIZE_MASK GENMASK(14, 13)
+#define STM32_DMA_SCR_MSIZE(n) ((n & 0x3) << 13)
+#define STM32_DMA_SCR_PSIZE_MASK GENMASK(12, 11)
+#define STM32_DMA_SCR_PSIZE(n) ((n & 0x3) << 11)
+#define STM32_DMA_SCR_PSIZE_GET(n) ((n & STM32_DMA_SCR_PSIZE_MASK) >> 11)
+#define STM32_DMA_SCR_DIR_MASK GENMASK(7, 6)
+#define STM32_DMA_SCR_DIR(n) ((n & 0x3) << 6)
+#define STM32_DMA_SCR_CT BIT(19) /* Target in double buffer */
+#define STM32_DMA_SCR_DBM BIT(18) /* Double Buffer Mode */
+#define STM32_DMA_SCR_PINCOS BIT(15) /* Peripheral inc offset size */
+#define STM32_DMA_SCR_MINC BIT(10) /* Memory increment mode */
+#define STM32_DMA_SCR_PINC BIT(9) /* Peripheral increment mode */
+#define STM32_DMA_SCR_CIRC BIT(8) /* Circular mode */
+#define STM32_DMA_SCR_PFCTRL BIT(5) /* Peripheral Flow Controller */
+#define STM32_DMA_SCR_TCIE BIT(4) /* Transfer Cplete Int Enable*/
+#define STM32_DMA_SCR_TEIE BIT(2) /* Transfer Error Int Enable */
+#define STM32_DMA_SCR_DMEIE BIT(1) /* Direct Mode Err Int Enable */
+#define STM32_DMA_SCR_EN BIT(0) /* Stream Enable */
+#define STM32_DMA_SCR_CFG_MASK (STM32_DMA_SCR_PINC \
+ | STM32_DMA_SCR_MINC \
+ | STM32_DMA_SCR_PINCOS \
+ | STM32_DMA_SCR_PL_MASK)
+#define STM32_DMA_SCR_IRQ_MASK (STM32_DMA_SCR_TCIE \
+ | STM32_DMA_SCR_TEIE \
+ | STM32_DMA_SCR_DMEIE)
+
+/* DMA Stream x number of data register */
+#define STM32_DMA_SNDTR(x) (0x0014 + 0x18 * (x))
+
+/* DMA stream peripheral address register */
+#define STM32_DMA_SPAR(x) (0x0018 + 0x18 * (x))
+
+/* DMA stream x memory 0 address register */
+#define STM32_DMA_SM0AR(x) (0x001c + 0x18 * (x))
+
+/* DMA stream x memory 1 address register */
+#define STM32_DMA_SM1AR(x) (0x0020 + 0x18 * (x))
+
+/* DMA stream x FIFO control register */
+#define STM32_DMA_SFCR(x) (0x0024 + 0x18 * (x))
+#define STM32_DMA_SFCR_FTH_MASK GENMASK(1, 0)
+#define STM32_DMA_SFCR_FTH(n) (n & STM32_DMA_SFCR_FTH_MASK)
+#define STM32_DMA_SFCR_FEIE BIT(7) /* FIFO error interrupt enable */
+#define STM32_DMA_SFCR_DMDIS BIT(2) /* Direct mode disable */
+#define STM32_DMA_SFCR_MASK (STM32_DMA_SFCR_FEIE \
+ | STM32_DMA_SFCR_DMDIS)
+
+/* DMA direction */
+#define STM32_DMA_DEV_TO_MEM 0x00
+#define STM32_DMA_MEM_TO_DEV 0x01
+#define STM32_DMA_MEM_TO_MEM 0x02
+
+/* DMA priority level */
+#define STM32_DMA_PRIORITY_LOW 0x00
+#define STM32_DMA_PRIORITY_MEDIUM 0x01
+#define STM32_DMA_PRIORITY_HIGH 0x02
+#define STM32_DMA_PRIORITY_VERY_HIGH 0x03
+
+/* DMA FIFO threshold selection */
+#define STM32_DMA_FIFO_THRESHOLD_1QUARTERFULL 0x00
+#define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01
+#define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02
+#define STM32_DMA_FIFO_THRESHOLD_FULL 0x03
+
+#define STM32_DMA_MAX_DATA_ITEMS 0xffff
+#define STM32_DMA_MAX_CHANNELS 0x08
+#define STM32_DMA_MAX_REQUEST_ID 0x08
+#define STM32_DMA_MAX_DATA_PARAM 0x03
+
+enum stm32_dma_width {
+ STM32_DMA_BYTE,
+ STM32_DMA_HALF_WORD,
+ STM32_DMA_WORD,
+};
+
+enum stm32_dma_burst_size {
+ STM32_DMA_BURST_SINGLE,
+ STM32_DMA_BURST_INCR4,
+ STM32_DMA_BURST_INCR8,
+ STM32_DMA_BURST_INCR16,
+};
+
+struct stm32_dma_cfg {
+ u32 channel_id;
+ u32 request_line;
+ u32 stream_config;
+ u32 threshold;
+};
+
+struct stm32_dma_chan_reg {
+ u32 dma_lisr;
+ u32 dma_hisr;
+ u32 dma_lifcr;
+ u32 dma_hifcr;
+ u32 dma_scr;
+ u32 dma_sndtr;
+ u32 dma_spar;
+ u32 dma_sm0ar;
+ u32 dma_sm1ar;
+ u32 dma_sfcr;
+};
+
+struct stm32_dma_sg_req {
+ u32 len;
+ struct stm32_dma_chan_reg chan_reg;
+};
+
+struct stm32_dma_desc {
+ struct virt_dma_desc vdesc;
+ bool cyclic;
+ u32 num_sgs;
+ struct stm32_dma_sg_req sg_req[];
+};
+
+struct stm32_dma_chan {
+ struct virt_dma_chan vchan;
+ bool config_init;
+ bool busy;
+ u32 id;
+ u32 irq;
+ struct stm32_dma_desc *desc;
+ u32 next_sg;
+ struct dma_slave_config dma_sconfig;
+ struct stm32_dma_chan_reg chan_reg;
+};
+
+struct stm32_dma_device {
+ struct dma_device ddev;
+ void __iomem *base;
+ struct clk *clk;
+ struct reset_control *rst;
+ bool mem2mem;
+ struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS];
+};
+
+static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan)
+{
+ return container_of(chan->vchan.chan.device, struct stm32_dma_device,
+ ddev);
+}
+
+static struct stm32_dma_chan *to_stm32_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct stm32_dma_chan, vchan.chan);
+}
+
+static struct stm32_dma_desc *to_stm32_dma_desc(struct virt_dma_desc *vdesc)
+{
+ return container_of(vdesc, struct stm32_dma_desc, vdesc);
+}
+
+static struct device *chan2dev(struct stm32_dma_chan *chan)
+{
+ return &chan->vchan.chan.dev->device;
+}
+
+static u32 stm32_dma_read(struct stm32_dma_device *dmadev, u32 reg)
+{
+ return readl_relaxed(dmadev->base + reg);
+}
+
+static void stm32_dma_write(struct stm32_dma_device *dmadev, u32 reg, u32 val)
+{
+ writel_relaxed(val, dmadev->base + reg);
+}
+
+static struct stm32_dma_desc *stm32_dma_alloc_desc(u32 num_sgs)
+{
+ return kzalloc(sizeof(struct stm32_dma_desc) +
+ sizeof(struct stm32_dma_sg_req) * num_sgs, GFP_NOWAIT);
+}
+
+static int stm32_dma_get_width(struct stm32_dma_chan *chan,
+ enum dma_slave_buswidth width)
+{
+ switch (width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ return STM32_DMA_BYTE;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ return STM32_DMA_HALF_WORD;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ return STM32_DMA_WORD;
+ default:
+ dev_err(chan2dev(chan), "Dma bus width not supported\n");
+ return -EINVAL;
+ }
+}
+
+static int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst)
+{
+ switch (maxburst) {
+ case 0:
+ case 1:
+ return STM32_DMA_BURST_SINGLE;
+ case 4:
+ return STM32_DMA_BURST_INCR4;
+ case 8:
+ return STM32_DMA_BURST_INCR8;
+ case 16:
+ return STM32_DMA_BURST_INCR16;
+ default:
+ dev_err(chan2dev(chan), "Dma burst size not supported\n");
+ return -EINVAL;
+ }
+}
+
+static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan,
+ u32 src_maxburst, u32 dst_maxburst)
+{
+ chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_MASK;
+ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_DMEIE;
+
+ if ((!src_maxburst) && (!dst_maxburst)) {
+ /* Using direct mode */
+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_DMEIE;
+ } else {
+ /* Using FIFO mode */
+ chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK;
+ }
+}
+
+static int stm32_dma_slave_config(struct dma_chan *c,
+ struct dma_slave_config *config)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+
+ memcpy(&chan->dma_sconfig, config, sizeof(*config));
+
+ chan->config_init = true;
+
+ return 0;
+}
+
+static u32 stm32_dma_irq_status(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ u32 flags, dma_isr;
+
+ /*
+ * Read "flags" from DMA_xISR register corresponding to the selected
+ * DMA channel at the correct bit offset inside that register.
+ *
+ * If (ch % 4) is 2 or 3, left shift the mask by 16 bits.
+ * If (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits.
+ */
+
+ if (chan->id & 4)
+ dma_isr = stm32_dma_read(dmadev, STM32_DMA_HISR);
+ else
+ dma_isr = stm32_dma_read(dmadev, STM32_DMA_LISR);
+
+ flags = dma_isr >> (((chan->id & 2) << 3) | ((chan->id & 1) * 6));
+
+ return flags;
+}
+
+static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ u32 dma_ifcr;
+
+ /*
+ * Write "flags" to the DMA_xIFCR register corresponding to the selected
+ * DMA channel at the correct bit offset inside that register.
+ *
+ * If (ch % 4) is 2 or 3, left shift the mask by 16 bits.
+ * If (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits.
+ */
+ dma_ifcr = flags << (((chan->id & 2) << 3) | ((chan->id & 1) * 6));
+
+ if (chan->id & 4)
+ stm32_dma_write(dmadev, STM32_DMA_HIFCR, dma_ifcr);
+ else
+ stm32_dma_write(dmadev, STM32_DMA_LIFCR, dma_ifcr);
+}
+
+static int stm32_dma_disable_chan(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+ u32 dma_scr, id;
+
+ id = chan->id;
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
+
+ if (dma_scr & STM32_DMA_SCR_EN) {
+ dma_scr &= ~STM32_DMA_SCR_EN;
+ stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr);
+
+ do {
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
+ dma_scr &= STM32_DMA_SCR_EN;
+ if (!dma_scr)
+ break;
+
+ if (time_after_eq(jiffies, timeout)) {
+ dev_err(chan2dev(chan), "%s: timeout!\n",
+ __func__);
+ return -EBUSY;
+ }
+ cond_resched();
+ } while (1);
+ }
+
+ return 0;
+}
+
+static void stm32_dma_stop(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ u32 dma_scr, dma_sfcr, status;
+ int ret;
+
+ /* Disable interrupts */
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
+ dma_scr &= ~STM32_DMA_SCR_IRQ_MASK;
+ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr);
+ dma_sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
+ dma_sfcr &= ~STM32_DMA_SFCR_FEIE;
+ stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), dma_sfcr);
+
+ /* Disable DMA */
+ ret = stm32_dma_disable_chan(chan);
+ if (ret < 0)
+ return;
+
+ /* Clear interrupt status if it is there */
+ status = stm32_dma_irq_status(chan);
+ if (status) {
+ dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n",
+ __func__, status);
+ stm32_dma_irq_clear(chan, status);
+ }
+
+ chan->busy = false;
+}
+
+static int stm32_dma_terminate_all(struct dma_chan *c)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+
+ if (chan->busy) {
+ stm32_dma_stop(chan);
+ chan->desc = NULL;
+ }
+
+ vchan_get_all_descriptors(&chan->vchan, &head);
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+ vchan_dma_desc_free_list(&chan->vchan, &head);
+
+ return 0;
+}
+
+static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ u32 scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
+ u32 ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
+ u32 spar = stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id));
+ u32 sm0ar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id));
+ u32 sm1ar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id));
+ u32 sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
+
+ dev_dbg(chan2dev(chan), "SCR: 0x%08x\n", scr);
+ dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n", ndtr);
+ dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n", spar);
+ dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n", sm0ar);
+ dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n", sm1ar);
+ dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr);
+}
+
+static int stm32_dma_start_transfer(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ struct virt_dma_desc *vdesc;
+ struct stm32_dma_sg_req *sg_req;
+ struct stm32_dma_chan_reg *reg;
+ u32 status;
+ int ret;
+
+ ret = stm32_dma_disable_chan(chan);
+ if (ret < 0)
+ return ret;
+
+ if (!chan->desc) {
+ vdesc = vchan_next_desc(&chan->vchan);
+ if (!vdesc)
+ return -EPERM;
+
+ chan->desc = to_stm32_dma_desc(vdesc);
+ chan->next_sg = 0;
+ }
+
+ if (chan->next_sg == chan->desc->num_sgs)
+ chan->next_sg = 0;
+
+ sg_req = &chan->desc->sg_req[chan->next_sg];
+ reg = &sg_req->chan_reg;
+
+ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr);
+ stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar);
+ stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar);
+ stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), reg->dma_sfcr);
+ stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar);
+ stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr);
+
+ chan->next_sg++;
+
+ /* Clear interrupt status if it is there */
+ status = stm32_dma_irq_status(chan);
+ if (status)
+ stm32_dma_irq_clear(chan, status);
+
+ stm32_dma_dump_reg(chan);
+
+ /* Start DMA */
+ reg->dma_scr |= STM32_DMA_SCR_EN;
+ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr);
+
+ chan->busy = true;
+
+ return 0;
+}
+
+static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ struct stm32_dma_sg_req *sg_req;
+ u32 dma_scr, dma_sm0ar, dma_sm1ar, id;
+
+ id = chan->id;
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
+
+ if (dma_scr & STM32_DMA_SCR_DBM) {
+ if (chan->next_sg == chan->desc->num_sgs)
+ chan->next_sg = 0;
+
+ sg_req = &chan->desc->sg_req[chan->next_sg];
+
+ if (dma_scr & STM32_DMA_SCR_CT) {
+ dma_sm0ar = sg_req->chan_reg.dma_sm0ar;
+ stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar);
+ dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n",
+ stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)));
+ } else {
+ dma_sm1ar = sg_req->chan_reg.dma_sm1ar;
+ stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar);
+ dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n",
+ stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)));
+ }
+
+ chan->next_sg++;
+ }
+}
+
+static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan)
+{
+ if (chan->desc) {
+ if (chan->desc->cyclic) {
+ vchan_cyclic_callback(&chan->desc->vdesc);
+ stm32_dma_configure_next_sg(chan);
+ } else {
+ chan->busy = false;
+ if (chan->next_sg == chan->desc->num_sgs) {
+ list_del(&chan->desc->vdesc.node);
+ vchan_cookie_complete(&chan->desc->vdesc);
+ chan->desc = NULL;
+ }
+ stm32_dma_start_transfer(chan);
+ }
+ }
+}
+
+static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
+{
+ struct stm32_dma_chan *chan = devid;
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ u32 status, scr, sfcr;
+
+ spin_lock(&chan->vchan.lock);
+
+ status = stm32_dma_irq_status(chan);
+ scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
+ sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
+
+ if ((status & STM32_DMA_TCI) && (scr & STM32_DMA_SCR_TCIE)) {
+ stm32_dma_irq_clear(chan, STM32_DMA_TCI);
+ stm32_dma_handle_chan_done(chan);
+
+ } else {
+ stm32_dma_irq_clear(chan, status);
+ dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);
+ }
+
+ spin_unlock(&chan->vchan.lock);
+
+ return IRQ_HANDLED;
+}
+
+static void stm32_dma_issue_pending(struct dma_chan *c)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ if (!chan->busy) {
+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) {
+ ret = stm32_dma_start_transfer(chan);
+ if ((!ret) && (chan->desc->cyclic))
+ stm32_dma_configure_next_sg(chan);
+ }
+ }
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+}
+
+static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
+ enum dma_transfer_direction direction,
+ enum dma_slave_buswidth *buswidth)
+{
+ enum dma_slave_buswidth src_addr_width, dst_addr_width;
+ int src_bus_width, dst_bus_width;
+ int src_burst_size, dst_burst_size;
+ u32 src_maxburst, dst_maxburst;
+ dma_addr_t src_addr, dst_addr;
+ u32 dma_scr = 0;
+
+ src_addr_width = chan->dma_sconfig.src_addr_width;
+ dst_addr_width = chan->dma_sconfig.dst_addr_width;
+ src_maxburst = chan->dma_sconfig.src_maxburst;
+ dst_maxburst = chan->dma_sconfig.dst_maxburst;
+ src_addr = chan->dma_sconfig.src_addr;
+ dst_addr = chan->dma_sconfig.dst_addr;
+
+ switch (direction) {
+ case DMA_MEM_TO_DEV:
+ dst_bus_width = stm32_dma_get_width(chan, dst_addr_width);
+ if (dst_bus_width < 0)
+ return dst_bus_width;
+
+ dst_burst_size = stm32_dma_get_burst(chan, dst_maxburst);
+ if (dst_burst_size < 0)
+ return dst_burst_size;
+
+ if (!src_addr_width)
+ src_addr_width = dst_addr_width;
+
+ src_bus_width = stm32_dma_get_width(chan, src_addr_width);
+ if (src_bus_width < 0)
+ return src_bus_width;
+
+ src_burst_size = stm32_dma_get_burst(chan, src_maxburst);
+ if (src_burst_size < 0)
+ return src_burst_size;
+
+ dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_DEV) |
+ STM32_DMA_SCR_PSIZE(dst_bus_width) |
+ STM32_DMA_SCR_MSIZE(src_bus_width) |
+ STM32_DMA_SCR_PBURST(dst_burst_size) |
+ STM32_DMA_SCR_MBURST(src_burst_size);
+
+ chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr;
+ *buswidth = dst_addr_width;
+ break;
+
+ case DMA_DEV_TO_MEM:
+ src_bus_width = stm32_dma_get_width(chan, src_addr_width);
+ if (src_bus_width < 0)
+ return src_bus_width;
+
+ src_burst_size = stm32_dma_get_burst(chan, src_maxburst);
+ if (src_burst_size < 0)
+ return src_burst_size;
+
+ if (!dst_addr_width)
+ dst_addr_width = src_addr_width;
+
+ dst_bus_width = stm32_dma_get_width(chan, dst_addr_width);
+ if (dst_bus_width < 0)
+ return dst_bus_width;
+
+ dst_burst_size = stm32_dma_get_burst(chan, dst_maxburst);
+ if (dst_burst_size < 0)
+ return dst_burst_size;
+
+ dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_DEV_TO_MEM) |
+ STM32_DMA_SCR_PSIZE(src_bus_width) |
+ STM32_DMA_SCR_MSIZE(dst_bus_width) |
+ STM32_DMA_SCR_PBURST(src_burst_size) |
+ STM32_DMA_SCR_MBURST(dst_burst_size);
+
+ chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr;
+ *buswidth = chan->dma_sconfig.src_addr_width;
+ break;
+
+ default:
+ dev_err(chan2dev(chan), "Dma direction is not supported\n");
+ return -EINVAL;
+ }
+
+ stm32_dma_set_fifo_config(chan, src_maxburst, dst_maxburst);
+
+ chan->chan_reg.dma_scr &= ~(STM32_DMA_SCR_DIR_MASK |
+ STM32_DMA_SCR_PSIZE_MASK | STM32_DMA_SCR_MSIZE_MASK |
+ STM32_DMA_SCR_PBURST_MASK | STM32_DMA_SCR_MBURST_MASK);
+ chan->chan_reg.dma_scr |= dma_scr;
+
+ return 0;
+}
+
+static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs)
+{
+ memset(regs, 0, sizeof(struct stm32_dma_chan_reg));
+}
+
+static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg(
+ struct dma_chan *c, struct scatterlist *sgl,
+ u32 sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ struct stm32_dma_desc *desc;
+ struct scatterlist *sg;
+ enum dma_slave_buswidth buswidth;
+ u32 nb_data_items;
+ int i, ret;
+
+ if (!chan->config_init) {
+ dev_err(chan2dev(chan), "dma channel is not configured\n");
+ return NULL;
+ }
+
+ if (sg_len < 1) {
+ dev_err(chan2dev(chan), "Invalid segment length %d\n", sg_len);
+ return NULL;
+ }
+
+ desc = stm32_dma_alloc_desc(sg_len);
+ if (!desc)
+ return NULL;
+
+ ret = stm32_dma_set_xfer_param(chan, direction, &buswidth);
+ if (ret < 0)
+ goto err;
+
+ /* Set peripheral flow controller */
+ if (chan->dma_sconfig.device_fc)
+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_PFCTRL;
+ else
+ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ desc->sg_req[i].len = sg_dma_len(sg);
+
+ nb_data_items = desc->sg_req[i].len / buswidth;
+ if (nb_data_items > STM32_DMA_MAX_DATA_ITEMS) {
+ dev_err(chan2dev(chan), "nb items not supported\n");
+ goto err;
+ }
+
+ stm32_dma_clear_reg(&desc->sg_req[i].chan_reg);
+ desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr;
+ desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr;
+ desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar;
+ desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg);
+ desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg);
+ desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items;
+ }
+
+ desc->num_sgs = sg_len;
+ desc->cyclic = false;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+
+err:
+ kfree(desc);
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic(
+ struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ struct stm32_dma_desc *desc;
+ enum dma_slave_buswidth buswidth;
+ u32 num_periods, nb_data_items;
+ int i, ret;
+
+ if (!buf_len || !period_len) {
+ dev_err(chan2dev(chan), "Invalid buffer/period len\n");
+ return NULL;
+ }
+
+ if (!chan->config_init) {
+ dev_err(chan2dev(chan), "dma channel is not configured\n");
+ return NULL;
+ }
+
+ if (buf_len % period_len) {
+ dev_err(chan2dev(chan), "buf_len not multiple of period_len\n");
+ return NULL;
+ }
+
+ /*
+ * We allow to take more number of requests till DMA is
+ * not started. The driver will loop over all requests.
+ * Once DMA is started then new requests can be queued only after
+ * terminating the DMA.
+ */
+ if (chan->busy) {
+ dev_err(chan2dev(chan), "Request not allowed when dma busy\n");
+ return NULL;
+ }
+
+ ret = stm32_dma_set_xfer_param(chan, direction, &buswidth);
+ if (ret < 0)
+ return NULL;
+
+ nb_data_items = period_len / buswidth;
+ if (nb_data_items > STM32_DMA_MAX_DATA_ITEMS) {
+ dev_err(chan2dev(chan), "number of items not supported\n");
+ return NULL;
+ }
+
+ /* Enable Circular mode or double buffer mode */
+ if (buf_len == period_len)
+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC;
+ else
+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM;
+
+ /* Clear periph ctrl if client set it */
+ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL;
+
+ num_periods = buf_len / period_len;
+
+ desc = stm32_dma_alloc_desc(num_periods);
+ if (!desc)
+ return NULL;
+
+ for (i = 0; i < num_periods; i++) {
+ desc->sg_req[i].len = period_len;
+
+ stm32_dma_clear_reg(&desc->sg_req[i].chan_reg);
+ desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr;
+ desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr;
+ desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar;
+ desc->sg_req[i].chan_reg.dma_sm0ar = buf_addr;
+ desc->sg_req[i].chan_reg.dma_sm1ar = buf_addr;
+ desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items;
+ buf_addr += period_len;
+ }
+
+ desc->num_sgs = num_periods;
+ desc->cyclic = true;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy(
+ struct dma_chan *c, dma_addr_t dest,
+ dma_addr_t src, size_t len, unsigned long flags)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ u32 num_sgs;
+ struct stm32_dma_desc *desc;
+ size_t xfer_count, offset;
+ int i;
+
+ num_sgs = DIV_ROUND_UP(len, STM32_DMA_MAX_DATA_ITEMS);
+ desc = stm32_dma_alloc_desc(num_sgs);
+ if (!desc)
+ return NULL;
+
+ for (offset = 0, i = 0; offset < len; offset += xfer_count, i++) {
+ xfer_count = min_t(size_t, len - offset,
+ STM32_DMA_MAX_DATA_ITEMS);
+
+ desc->sg_req[i].len = xfer_count;
+
+ stm32_dma_clear_reg(&desc->sg_req[i].chan_reg);
+ desc->sg_req[i].chan_reg.dma_scr =
+ STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_MEM) |
+ STM32_DMA_SCR_MINC |
+ STM32_DMA_SCR_PINC |
+ STM32_DMA_SCR_TCIE |
+ STM32_DMA_SCR_TEIE;
+ desc->sg_req[i].chan_reg.dma_sfcr = STM32_DMA_SFCR_DMDIS |
+ STM32_DMA_SFCR_FTH(STM32_DMA_FIFO_THRESHOLD_FULL) |
+ STM32_DMA_SFCR_FEIE;
+ desc->sg_req[i].chan_reg.dma_spar = src + offset;
+ desc->sg_req[i].chan_reg.dma_sm0ar = dest + offset;
+ desc->sg_req[i].chan_reg.dma_sndtr = xfer_count;
+ }
+
+ desc->num_sgs = num_sgs;
+ desc->cyclic = false;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
+static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
+ struct stm32_dma_desc *desc,
+ u32 next_sg)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ u32 dma_scr, width, residue, count;
+ int i;
+
+ residue = 0;
+
+ for (i = next_sg; i < desc->num_sgs; i++)
+ residue += desc->sg_req[i].len;
+
+ if (next_sg != 0) {
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
+ width = STM32_DMA_SCR_PSIZE_GET(dma_scr);
+ count = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
+
+ residue += count << width;
+ }
+
+ return residue;
+}
+
+static enum dma_status stm32_dma_tx_status(struct dma_chan *c,
+ dma_cookie_t cookie,
+ struct dma_tx_state *state)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ struct virt_dma_desc *vdesc;
+ enum dma_status status;
+ unsigned long flags;
+ u32 residue;
+
+ status = dma_cookie_status(c, cookie, state);
+ if ((status == DMA_COMPLETE) || (!state))
+ return status;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ vdesc = vchan_find_desc(&chan->vchan, cookie);
+ if (cookie == chan->desc->vdesc.tx.cookie) {
+ residue = stm32_dma_desc_residue(chan, chan->desc,
+ chan->next_sg);
+ } else if (vdesc) {
+ residue = stm32_dma_desc_residue(chan,
+ to_stm32_dma_desc(vdesc), 0);
+ } else {
+ residue = 0;
+ }
+
+ dma_set_residue(state, residue);
+
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+ return status;
+}
+
+static int stm32_dma_alloc_chan_resources(struct dma_chan *c)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ int ret;
+
+ chan->config_init = false;
+ ret = clk_prepare_enable(dmadev->clk);
+ if (ret < 0) {
+ dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = stm32_dma_disable_chan(chan);
+ if (ret < 0)
+ clk_disable_unprepare(dmadev->clk);
+
+ return ret;
+}
+
+static void stm32_dma_free_chan_resources(struct dma_chan *c)
+{
+ struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ unsigned long flags;
+
+ dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id);
+
+ if (chan->busy) {
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ stm32_dma_stop(chan);
+ chan->desc = NULL;
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+ }
+
+ clk_disable_unprepare(dmadev->clk);
+
+ vchan_free_chan_resources(to_virt_chan(c));
+}
+
+static void stm32_dma_desc_free(struct virt_dma_desc *vdesc)
+{
+ kfree(container_of(vdesc, struct stm32_dma_desc, vdesc));
+}
+
+void stm32_dma_set_config(struct stm32_dma_chan *chan,
+ struct stm32_dma_cfg *cfg)
+{
+ stm32_dma_clear_reg(&chan->chan_reg);
+
+ chan->chan_reg.dma_scr = cfg->stream_config & STM32_DMA_SCR_CFG_MASK;
+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_REQ(cfg->request_line);
+
+ /* Enable Interrupts */
+ chan->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE;
+
+ chan->chan_reg.dma_sfcr = cfg->threshold & STM32_DMA_SFCR_FTH_MASK;
+}
+
+static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct stm32_dma_device *dmadev = ofdma->of_dma_data;
+ struct stm32_dma_cfg cfg;
+ struct stm32_dma_chan *chan;
+ struct dma_chan *c;
+
+ if (dma_spec->args_count < 3)
+ return NULL;
+
+ cfg.channel_id = dma_spec->args[0];
+ cfg.request_line = dma_spec->args[1];
+ cfg.stream_config = dma_spec->args[2];
+ cfg.threshold = 0;
+
+ if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >=
+ STM32_DMA_MAX_REQUEST_ID))
+ return NULL;
+
+ if (dma_spec->args_count > 3)
+ cfg.threshold = dma_spec->args[3];
+
+ chan = &dmadev->chan[cfg.channel_id];
+
+ c = dma_get_slave_channel(&chan->vchan.chan);
+ if (c)
+ stm32_dma_set_config(chan, &cfg);
+
+ return c;
+}
+
+static const struct of_device_id stm32_dma_of_match[] = {
+ { .compatible = "st,stm32-dma", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_dma_of_match);
+
+static int stm32_dma_probe(struct platform_device *pdev)
+{
+ struct stm32_dma_chan *chan;
+ struct stm32_dma_device *dmadev;
+ struct dma_device *dd;
+ const struct of_device_id *match;
+ struct resource *res;
+ int i, ret;
+
+ match = of_match_device(stm32_dma_of_match, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+
+ dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
+ if (!dmadev)
+ return -ENOMEM;
+
+ dd = &dmadev->ddev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dmadev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dmadev->base))
+ return PTR_ERR(dmadev->base);
+
+ dmadev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dmadev->clk)) {
+ dev_err(&pdev->dev, "Error: Missing controller clock\n");
+ return PTR_ERR(dmadev->clk);
+ }
+
+ dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node,
+ "st,mem2mem");
+
+ dmadev->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (!IS_ERR(dmadev->rst)) {
+ reset_control_assert(dmadev->rst);
+ udelay(2);
+ reset_control_deassert(dmadev->rst);
+ }
+
+ dma_cap_set(DMA_SLAVE, dd->cap_mask);
+ dma_cap_set(DMA_PRIVATE, dd->cap_mask);
+ dma_cap_set(DMA_CYCLIC, dd->cap_mask);
+ dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources;
+ dd->device_free_chan_resources = stm32_dma_free_chan_resources;
+ dd->device_tx_status = stm32_dma_tx_status;
+ dd->device_issue_pending = stm32_dma_issue_pending;
+ dd->device_prep_slave_sg = stm32_dma_prep_slave_sg;
+ dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic;
+ dd->device_config = stm32_dma_slave_config;
+ dd->device_terminate_all = stm32_dma_terminate_all;
+ dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ dd->dev = &pdev->dev;
+ INIT_LIST_HEAD(&dd->channels);
+
+ if (dmadev->mem2mem) {
+ dma_cap_set(DMA_MEMCPY, dd->cap_mask);
+ dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy;
+ dd->directions |= BIT(DMA_MEM_TO_MEM);
+ }
+
+ for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
+ chan = &dmadev->chan[i];
+ chan->id = i;
+ chan->vchan.desc_free = stm32_dma_desc_free;
+ vchan_init(&chan->vchan, dd);
+ }
+
+ ret = dma_async_device_register(dd);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
+ chan = &dmadev->chan[i];
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ if (!res) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
+ goto err_unregister;
+ }
+ chan->irq = res->start;
+ ret = devm_request_irq(&pdev->dev, chan->irq,
+ stm32_dma_chan_irq, 0,
+ dev_name(chan2dev(chan)), chan);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "request_irq failed with err %d channel %d\n",
+ ret, i);
+ goto err_unregister;
+ }
+ }
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ stm32_dma_of_xlate, dmadev);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "STM32 DMA DMA OF registration failed %d\n", ret);
+ goto err_unregister;
+ }
+
+ platform_set_drvdata(pdev, dmadev);
+
+ dev_info(&pdev->dev, "STM32 DMA driver registered\n");
+
+ return 0;
+
+err_unregister:
+ dma_async_device_unregister(dd);
+
+ return ret;
+}
+
+static struct platform_driver stm32_dma_driver = {
+ .driver = {
+ .name = "stm32-dma",
+ .of_match_table = stm32_dma_of_match,
+ },
+};
+
+static int __init stm32_dma_init(void)
+{
+ return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe);
+}
+subsys_initcall(stm32_dma_init);
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index c8f79dcaaee8..935da8192f59 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -296,7 +296,7 @@ static struct tegra_dma_desc *tegra_dma_desc_get(
spin_unlock_irqrestore(&tdc->lock, flags);
/* Allocate DMA desc */
- dma_desc = kzalloc(sizeof(*dma_desc), GFP_ATOMIC);
+ dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT);
if (!dma_desc) {
dev_err(tdc2dev(tdc), "dma_desc alloc failed\n");
return NULL;
@@ -336,7 +336,7 @@ static struct tegra_dma_sg_req *tegra_dma_sg_req_get(
}
spin_unlock_irqrestore(&tdc->lock, flags);
- sg_req = kzalloc(sizeof(struct tegra_dma_sg_req), GFP_ATOMIC);
+ sg_req = kzalloc(sizeof(struct tegra_dma_sg_req), GFP_NOWAIT);
if (!sg_req)
dev_err(tdc2dev(tdc), "sg_req alloc failed\n");
return sg_req;
@@ -1186,10 +1186,12 @@ static int tegra_dma_alloc_chan_resources(struct dma_chan *dc)
dma_cookie_init(&tdc->dma_chan);
tdc->config_init = false;
- ret = clk_prepare_enable(tdma->dma_clk);
+
+ ret = pm_runtime_get_sync(tdma->dev);
if (ret < 0)
- dev_err(tdc2dev(tdc), "clk_prepare_enable failed: %d\n", ret);
- return ret;
+ return ret;
+
+ return 0;
}
static void tegra_dma_free_chan_resources(struct dma_chan *dc)
@@ -1232,7 +1234,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
list_del(&sg_req->node);
kfree(sg_req);
}
- clk_disable_unprepare(tdma->dma_clk);
+ pm_runtime_put(tdma->dev);
tdc->slave_id = 0;
}
@@ -1356,20 +1358,14 @@ static int tegra_dma_probe(struct platform_device *pdev)
spin_lock_init(&tdma->global_lock);
pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
+ if (!pm_runtime_enabled(&pdev->dev))
ret = tegra_dma_runtime_resume(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "dma_runtime_resume failed %d\n",
- ret);
- goto err_pm_disable;
- }
- }
+ else
+ ret = pm_runtime_get_sync(&pdev->dev);
- /* Enable clock before accessing registers */
- ret = clk_prepare_enable(tdma->dma_clk);
if (ret < 0) {
- dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
- goto err_pm_disable;
+ pm_runtime_disable(&pdev->dev);
+ return ret;
}
/* Reset DMA controller */
@@ -1382,7 +1378,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0);
tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul);
- clk_disable_unprepare(tdma->dma_clk);
+ pm_runtime_put(&pdev->dev);
INIT_LIST_HEAD(&tdma->dma_dev.channels);
for (i = 0; i < cdata->nr_channels; i++) {
@@ -1400,8 +1396,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
}
tdc->irq = res->start;
snprintf(tdc->name, sizeof(tdc->name), "apbdma.%d", i);
- ret = devm_request_irq(&pdev->dev, tdc->irq,
- tegra_dma_isr, 0, tdc->name, tdc);
+ ret = request_irq(tdc->irq, tegra_dma_isr, 0, tdc->name, tdc);
if (ret) {
dev_err(&pdev->dev,
"request_irq failed with err %d channel %d\n",
@@ -1482,10 +1477,11 @@ err_unregister_dma_dev:
err_irq:
while (--i >= 0) {
struct tegra_dma_channel *tdc = &tdma->channels[i];
+
+ free_irq(tdc->irq, tdc);
tasklet_kill(&tdc->tasklet);
}
-err_pm_disable:
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
tegra_dma_runtime_suspend(&pdev->dev);
@@ -1502,6 +1498,7 @@ static int tegra_dma_remove(struct platform_device *pdev)
for (i = 0; i < tdma->chip_data->nr_channels; ++i) {
tdc = &tdma->channels[i];
+ free_irq(tdc->irq, tdc);
tasklet_kill(&tdc->tasklet);
}
@@ -1514,8 +1511,7 @@ static int tegra_dma_remove(struct platform_device *pdev)
static int tegra_dma_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct tegra_dma *tdma = platform_get_drvdata(pdev);
+ struct tegra_dma *tdma = dev_get_drvdata(dev);
clk_disable_unprepare(tdma->dma_clk);
return 0;
@@ -1523,8 +1519,7 @@ static int tegra_dma_runtime_suspend(struct device *dev)
static int tegra_dma_runtime_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct tegra_dma *tdma = platform_get_drvdata(pdev);
+ struct tegra_dma *tdma = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(tdma->dma_clk);
@@ -1543,7 +1538,7 @@ static int tegra_dma_pm_suspend(struct device *dev)
int ret;
/* Enable clock before accessing register */
- ret = tegra_dma_runtime_resume(dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0)
return ret;
@@ -1552,15 +1547,22 @@ static int tegra_dma_pm_suspend(struct device *dev)
struct tegra_dma_channel *tdc = &tdma->channels[i];
struct tegra_dma_channel_regs *ch_reg = &tdc->channel_reg;
+ /* Only save the state of DMA channels that are in use */
+ if (!tdc->config_init)
+ continue;
+
ch_reg->csr = tdc_read(tdc, TEGRA_APBDMA_CHAN_CSR);
ch_reg->ahb_ptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBPTR);
ch_reg->apb_ptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_APBPTR);
ch_reg->ahb_seq = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBSEQ);
ch_reg->apb_seq = tdc_read(tdc, TEGRA_APBDMA_CHAN_APBSEQ);
+ if (tdma->chip_data->support_separate_wcount_reg)
+ ch_reg->wcount = tdc_read(tdc,
+ TEGRA_APBDMA_CHAN_WCOUNT);
}
/* Disable clock */
- tegra_dma_runtime_suspend(dev);
+ pm_runtime_put(dev);
return 0;
}
@@ -1571,7 +1573,7 @@ static int tegra_dma_pm_resume(struct device *dev)
int ret;
/* Enable clock before accessing register */
- ret = tegra_dma_runtime_resume(dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0)
return ret;
@@ -1583,6 +1585,13 @@ static int tegra_dma_pm_resume(struct device *dev)
struct tegra_dma_channel *tdc = &tdma->channels[i];
struct tegra_dma_channel_regs *ch_reg = &tdc->channel_reg;
+ /* Only restore the state of DMA channels that are in use */
+ if (!tdc->config_init)
+ continue;
+
+ if (tdma->chip_data->support_separate_wcount_reg)
+ tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT,
+ ch_reg->wcount);
tdc_write(tdc, TEGRA_APBDMA_CHAN_APBSEQ, ch_reg->apb_seq);
tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_reg->apb_ptr);
tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_reg->ahb_seq);
@@ -1592,16 +1601,14 @@ static int tegra_dma_pm_resume(struct device *dev)
}
/* Disable clock */
- tegra_dma_runtime_suspend(dev);
+ pm_runtime_put(dev);
return 0;
}
#endif
static const struct dev_pm_ops tegra_dma_dev_pm_ops = {
-#ifdef CONFIG_PM
- .runtime_suspend = tegra_dma_runtime_suspend,
- .runtime_resume = tegra_dma_runtime_resume,
-#endif
+ SET_RUNTIME_PM_OPS(tegra_dma_runtime_suspend, tegra_dma_runtime_resume,
+ NULL)
SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume)
};
diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c
index a415edbe61b1..e107779b1a2e 100644
--- a/drivers/dma/ti-dma-crossbar.c
+++ b/drivers/dma/ti-dma-crossbar.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
-#include <linux/idr.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
@@ -198,7 +197,8 @@ struct ti_dra7_xbar_data {
void __iomem *iomem;
struct dma_router dmarouter;
- struct idr map_idr;
+ struct mutex mutex;
+ unsigned long *dma_inuse;
u16 safe_val; /* Value to rest the crossbar lines */
u32 xbar_requests; /* number of DMA requests connected to XBAR */
@@ -225,7 +225,9 @@ static void ti_dra7_xbar_free(struct device *dev, void *route_data)
map->xbar_in, map->xbar_out);
ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
- idr_remove(&xbar->map_idr, map->xbar_out);
+ mutex_lock(&xbar->mutex);
+ clear_bit(map->xbar_out, xbar->dma_inuse);
+ mutex_unlock(&xbar->mutex);
kfree(map);
}
@@ -255,8 +257,17 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
return ERR_PTR(-ENOMEM);
}
- map->xbar_out = idr_alloc(&xbar->map_idr, NULL, 0, xbar->dma_requests,
- GFP_KERNEL);
+ mutex_lock(&xbar->mutex);
+ map->xbar_out = find_first_zero_bit(xbar->dma_inuse,
+ xbar->dma_requests);
+ mutex_unlock(&xbar->mutex);
+ if (map->xbar_out == xbar->dma_requests) {
+ dev_err(&pdev->dev, "Run out of free DMA requests\n");
+ kfree(map);
+ return ERR_PTR(-ENOMEM);
+ }
+ set_bit(map->xbar_out, xbar->dma_inuse);
+
map->xbar_in = (u16)dma_spec->args[0];
dma_spec->args[0] = map->xbar_out + xbar->dma_offset;
@@ -278,17 +289,29 @@ static const struct of_device_id ti_dra7_master_match[] = {
.compatible = "ti,edma3",
.data = (void *)TI_XBAR_EDMA_OFFSET,
},
+ {
+ .compatible = "ti,edma3-tpcc",
+ .data = (void *)TI_XBAR_EDMA_OFFSET,
+ },
{},
};
+static inline void ti_dra7_xbar_reserve(int offset, int len, unsigned long *p)
+{
+ for (; len > 0; len--)
+ clear_bit(offset + (len - 1), p);
+}
+
static int ti_dra7_xbar_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *dma_node;
struct ti_dra7_xbar_data *xbar;
+ struct property *prop;
struct resource *res;
u32 safe_val;
+ size_t sz;
void __iomem *iomem;
int i, ret;
@@ -299,8 +322,6 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
if (!xbar)
return -ENOMEM;
- idr_init(&xbar->map_idr);
-
dma_node = of_parse_phandle(node, "dma-masters", 0);
if (!dma_node) {
dev_err(&pdev->dev, "Can't get DMA master node\n");
@@ -322,6 +343,12 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
}
of_node_put(dma_node);
+ xbar->dma_inuse = devm_kcalloc(&pdev->dev,
+ BITS_TO_LONGS(xbar->dma_requests),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!xbar->dma_inuse)
+ return -ENOMEM;
+
if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
dev_info(&pdev->dev,
"Missing XBAR input information, using %u.\n",
@@ -332,6 +359,33 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
xbar->safe_val = (u16)safe_val;
+
+ prop = of_find_property(node, "ti,reserved-dma-request-ranges", &sz);
+ if (prop) {
+ const char pname[] = "ti,reserved-dma-request-ranges";
+ u32 (*rsv_events)[2];
+ size_t nelm = sz / sizeof(*rsv_events);
+ int i;
+
+ if (!nelm)
+ return -EINVAL;
+
+ rsv_events = kcalloc(nelm, sizeof(*rsv_events), GFP_KERNEL);
+ if (!rsv_events)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(node, pname, (u32 *)rsv_events,
+ nelm * 2);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nelm; i++) {
+ ti_dra7_xbar_reserve(rsv_events[i][0], rsv_events[i][1],
+ xbar->dma_inuse);
+ }
+ kfree(rsv_events);
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iomem = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(iomem))
@@ -343,18 +397,23 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
xbar->dmarouter.route_free = ti_dra7_xbar_free;
xbar->dma_offset = (u32)match->data;
+ mutex_init(&xbar->mutex);
platform_set_drvdata(pdev, xbar);
/* Reset the crossbar */
- for (i = 0; i < xbar->dma_requests; i++)
- ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
+ for (i = 0; i < xbar->dma_requests; i++) {
+ if (!test_bit(i, xbar->dma_inuse))
+ ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
+ }
ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate,
&xbar->dmarouter);
if (ret) {
/* Restore the defaults for the crossbar */
- for (i = 0; i < xbar->dma_requests; i++)
- ti_dra7_xbar_write(xbar->iomem, i, i);
+ for (i = 0; i < xbar->dma_requests; i++) {
+ if (!test_bit(i, xbar->dma_inuse))
+ ti_dra7_xbar_write(xbar->iomem, i, i);
+ }
}
return ret;
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 6f80432a3f0a..a35c211857dd 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -29,7 +29,7 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_irqsave(&vc->lock, flags);
cookie = dma_cookie_assign(tx);
- list_add_tail(&vd->node, &vc->desc_submitted);
+ list_move_tail(&vd->node, &vc->desc_submitted);
spin_unlock_irqrestore(&vc->lock, flags);
dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
@@ -39,6 +39,33 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
}
EXPORT_SYMBOL_GPL(vchan_tx_submit);
+/**
+ * vchan_tx_desc_free - free a reusable descriptor
+ * @tx: the transfer
+ *
+ * This function frees a previously allocated reusable descriptor. The only
+ * other way is to clear the DMA_CTRL_REUSE flag and submit one last time the
+ * transfer.
+ *
+ * Returns 0 upon success
+ */
+int vchan_tx_desc_free(struct dma_async_tx_descriptor *tx)
+{
+ struct virt_dma_chan *vc = to_virt_chan(tx->chan);
+ struct virt_dma_desc *vd = to_virt_desc(tx);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vc->lock, flags);
+ list_del(&vd->node);
+ spin_unlock_irqrestore(&vc->lock, flags);
+
+ dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: freeing\n",
+ vc, vd, vd->tx.cookie);
+ vc->desc_free(vd);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vchan_tx_desc_free);
+
struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
dma_cookie_t cookie)
{
@@ -83,8 +110,10 @@ static void vchan_complete(unsigned long arg)
cb_data = vd->tx.callback_param;
list_del(&vd->node);
-
- vc->desc_free(vd);
+ if (dmaengine_desc_test_reuse(&vd->tx))
+ list_add(&vd->node, &vc->desc_allocated);
+ else
+ vc->desc_free(vd);
if (cb)
cb(cb_data);
@@ -96,9 +125,13 @@ void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
while (!list_empty(head)) {
struct virt_dma_desc *vd = list_first_entry(head,
struct virt_dma_desc, node);
- list_del(&vd->node);
- dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
- vc->desc_free(vd);
+ if (dmaengine_desc_test_reuse(&vd->tx)) {
+ list_move_tail(&vd->node, &vc->desc_allocated);
+ } else {
+ dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
+ list_del(&vd->node);
+ vc->desc_free(vd);
+ }
}
}
EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
@@ -108,6 +141,7 @@ void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
dma_cookie_init(&vc->chan);
spin_lock_init(&vc->lock);
+ INIT_LIST_HEAD(&vc->desc_allocated);
INIT_LIST_HEAD(&vc->desc_submitted);
INIT_LIST_HEAD(&vc->desc_issued);
INIT_LIST_HEAD(&vc->desc_completed);
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 2fa47745a41f..d9731ca5e262 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -29,6 +29,7 @@ struct virt_dma_chan {
spinlock_t lock;
/* protected by vc.lock */
+ struct list_head desc_allocated;
struct list_head desc_submitted;
struct list_head desc_issued;
struct list_head desc_completed;
@@ -55,10 +56,17 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
struct virt_dma_desc *vd, unsigned long tx_flags)
{
extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
+ extern int vchan_tx_desc_free(struct dma_async_tx_descriptor *);
+ unsigned long flags;
dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
vd->tx.flags = tx_flags;
vd->tx.tx_submit = vchan_tx_submit;
+ vd->tx.desc_free = vchan_tx_desc_free;
+
+ spin_lock_irqsave(&vc->lock, flags);
+ list_add_tail(&vd->node, &vc->desc_allocated);
+ spin_unlock_irqrestore(&vc->lock, flags);
return &vd->tx;
}
@@ -134,6 +142,7 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
struct list_head *head)
{
+ list_splice_tail_init(&vc->desc_allocated, head);
list_splice_tail_init(&vc->desc_submitted, head);
list_splice_tail_init(&vc->desc_issued, head);
list_splice_tail_init(&vc->desc_completed, head);
@@ -141,14 +150,30 @@ static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
{
+ struct virt_dma_desc *vd;
unsigned long flags;
LIST_HEAD(head);
spin_lock_irqsave(&vc->lock, flags);
vchan_get_all_descriptors(vc, &head);
+ list_for_each_entry(vd, &head, node)
+ dmaengine_desc_clear_reuse(&vd->tx);
spin_unlock_irqrestore(&vc->lock, flags);
vchan_dma_desc_free_list(vc, &head);
}
+/**
+ * vchan_synchronize() - synchronize callback execution to the current context
+ * @vc: virtual channel to synchronize
+ *
+ * Makes sure that all scheduled or active callbacks have finished running. For
+ * proper operation the caller has to ensure that no new callbacks are scheduled
+ * after the invocation of this function started.
+ */
+static inline void vchan_synchronize(struct virt_dma_chan *vc)
+{
+ tasklet_kill(&vc->task);
+}
+
#endif
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 0cebbf668886..3d89e60a3e71 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -52,6 +52,15 @@ config EXTCON_MAX14577
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
detector and switch.
+config EXTCON_MAX3355
+ tristate "Maxim MAX3355 USB OTG EXTCON Support"
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ If you say yes here you get support for the USB OTG role detection by
+ MAX3355. The MAX3355 chip integrates a charge pump and comparators to
+ enable a system with an integrated USB OTG dual-role transceiver to
+ function as an USB OTG dual-role device.
+
config EXTCON_MAX77693
tristate "Maxim MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index ba787d04295b..2a0e4f45d5b2 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
+obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index e4890dd4fefd..c121d01a5cd6 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -1201,10 +1201,58 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
regmap_update_bits(arizona->regmap, reg, mask, level);
}
-static int arizona_extcon_device_get_pdata(struct arizona *arizona)
+static int arizona_extcon_get_micd_configs(struct device *dev,
+ struct arizona *arizona)
+{
+ const char * const prop = "wlf,micd-configs";
+ const int entries_per_config = 3;
+ struct arizona_micd_config *micd_configs;
+ int nconfs, ret;
+ int i, j;
+ u32 *vals;
+
+ nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
+ if (nconfs <= 0)
+ return 0;
+
+ vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
+ if (ret < 0)
+ goto out;
+
+ nconfs /= entries_per_config;
+
+ micd_configs = devm_kzalloc(dev,
+ nconfs * sizeof(struct arizona_micd_range),
+ GFP_KERNEL);
+ if (!micd_configs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0, j = 0; i < nconfs; ++i) {
+ micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
+ micd_configs[i].bias = vals[j++];
+ micd_configs[i].gpio = vals[j++];
+ }
+
+ arizona->pdata.micd_configs = micd_configs;
+ arizona->pdata.num_micd_configs = nconfs;
+
+out:
+ kfree(vals);
+ return ret;
+}
+
+static int arizona_extcon_device_get_pdata(struct device *dev,
+ struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
unsigned int val = ARIZONA_ACCDET_MODE_HPL;
+ int ret;
device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
switch (val) {
@@ -1230,12 +1278,29 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona)
device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
&pdata->micd_dbtime);
- device_property_read_u32(arizona->dev, "wlf,micd-timeout",
+ device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
&pdata->micd_timeout);
pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
"wlf,micd-force-micbias");
+ pdata->micd_software_compare = device_property_read_bool(arizona->dev,
+ "wlf,micd-software-compare");
+
+ pdata->jd_invert = device_property_read_bool(arizona->dev,
+ "wlf,jd-invert");
+
+ device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
+
+ pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2");
+ pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2-nopull");
+
+ ret = arizona_extcon_get_micd_configs(dev, arizona);
+ if (ret < 0)
+ dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
+
return 0;
}
@@ -1257,7 +1322,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
return -ENOMEM;
if (!dev_get_platdata(arizona->dev))
- arizona_extcon_device_get_pdata(arizona);
+ arizona_extcon_device_get_pdata(&pdev->dev, arizona);
info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
if (IS_ERR(info->micvdd)) {
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 601dbd996487..b30ab97ce75f 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -692,7 +692,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
/* Support irq domain for max14577 MUIC device */
for (i = 0; i < info->muic_irqs_num; i++) {
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
- unsigned int virq = 0;
+ int virq = 0;
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
if (virq <= 0)
diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
new file mode 100644
index 000000000000..c24abec5d06c
--- /dev/null
+++ b/drivers/extcon/extcon-max3355.c
@@ -0,0 +1,146 @@
+/*
+ * Maxim Integrated MAX3355 USB OTG chip extcon driver
+ *
+ * Copyright (C) 2014-2015 Cogent Embedded, Inc.
+ * Author: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+ *
+ * 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.
+ */
+
+#include <linux/extcon.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct max3355_data {
+ struct extcon_dev *edev;
+ struct gpio_desc *id_gpiod;
+ struct gpio_desc *shdn_gpiod;
+};
+
+static const unsigned int max3355_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+static irqreturn_t max3355_id_irq(int irq, void *dev_id)
+{
+ struct max3355_data *data = dev_id;
+ int id = gpiod_get_value_cansleep(data->id_gpiod);
+
+ if (id) {
+ /*
+ * ID = 1 means USB HOST cable detached.
+ * As we don't have event for USB peripheral cable attached,
+ * we simulate USB peripheral attach here.
+ */
+ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false);
+ extcon_set_cable_state_(data->edev, EXTCON_USB, true);
+ } else {
+ /*
+ * ID = 0 means USB HOST cable attached.
+ * As we don't have event for USB peripheral cable detached,
+ * we simulate USB peripheral detach here.
+ */
+ extcon_set_cable_state_(data->edev, EXTCON_USB, false);
+ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int max3355_probe(struct platform_device *pdev)
+{
+ struct max3355_data *data;
+ struct gpio_desc *gpiod;
+ int irq, err;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct max3355_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ dev_err(&pdev->dev, "failed to get ID_OUT GPIO\n");
+ return PTR_ERR(gpiod);
+ }
+ data->id_gpiod = gpiod;
+
+ gpiod = devm_gpiod_get(&pdev->dev, "maxim,shdn", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod)) {
+ dev_err(&pdev->dev, "failed to get SHDN# GPIO\n");
+ return PTR_ERR(gpiod);
+ }
+ data->shdn_gpiod = gpiod;
+
+ data->edev = devm_extcon_dev_allocate(&pdev->dev, max3355_cable);
+ if (IS_ERR(data->edev)) {
+ dev_err(&pdev->dev, "failed to allocate extcon device\n");
+ return PTR_ERR(data->edev);
+ }
+
+ err = devm_extcon_dev_register(&pdev->dev, data->edev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return err;
+ }
+
+ irq = gpiod_to_irq(data->id_gpiod);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to translate ID_OUT GPIO to IRQ\n");
+ return irq;
+ }
+
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL, max3355_id_irq,
+ IRQF_ONESHOT | IRQF_NO_SUSPEND |
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ pdev->name, data);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request ID_OUT IRQ\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ /* Perform initial detection */
+ max3355_id_irq(irq, data);
+
+ return 0;
+}
+
+static int max3355_remove(struct platform_device *pdev)
+{
+ struct max3355_data *data = platform_get_drvdata(pdev);
+
+ gpiod_set_value_cansleep(data->shdn_gpiod, 0);
+
+ return 0;
+}
+
+static const struct of_device_id max3355_match_table[] = {
+ { .compatible = "maxim,max3355", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max3355_match_table);
+
+static struct platform_driver max3355_driver = {
+ .probe = max3355_probe,
+ .remove = max3355_remove,
+ .driver = {
+ .name = "extcon-max3355",
+ .of_match_table = max3355_match_table,
+ },
+};
+
+module_platform_driver(max3355_driver);
+
+MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");
+MODULE_DESCRIPTION("Maxim MAX3355 extcon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 44c499e1beee..fdf8f5d4d4e9 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1127,11 +1127,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
/* Support irq domain for MAX77693 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max77693_muic_irq *muic_irq = &muic_irqs[i];
- unsigned int virq = 0;
+ int virq;
virq = regmap_irq_get_virq(max77693->irq_data_muic,
muic_irq->irq);
- if (!virq)
+ if (virq <= 0)
return -EINVAL;
muic_irq->virq = virq;
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 9f9ea334399c..74dfb7f4f277 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -811,7 +811,7 @@ static int max77843_muic_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i];
- unsigned int virq = 0;
+ int virq = 0;
virq = regmap_irq_get_virq(max77843->irq_data_muic,
muic_irq->irq);
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index 36bf1d63791c..e1bb82809bef 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -603,7 +603,7 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
ret = devm_request_threaded_irq(info->dev, virq, NULL,
rt8973a_muic_irq_handler,
- IRQF_NO_SUSPEND,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
muic_irq->name, info);
if (ret) {
dev_err(info->dev,
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 0e08e665f715..88bebe1968b7 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -321,39 +321,58 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
list_add_tail(&dev->list, &dmi_devices);
}
-static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
- int devfn, const char *name)
+static void __init dmi_save_dev_pciaddr(int instance, int segment, int bus,
+ int devfn, const char *name, int type)
{
- struct dmi_dev_onboard *onboard_dev;
+ struct dmi_dev_onboard *dev;
- onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1);
- if (!onboard_dev)
+ /* Ignore invalid values */
+ if (type == DMI_DEV_TYPE_DEV_SLOT &&
+ segment == 0xFFFF && bus == 0xFF && devfn == 0xFF)
return;
- onboard_dev->instance = instance;
- onboard_dev->segment = segment;
- onboard_dev->bus = bus;
- onboard_dev->devfn = devfn;
+ dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1);
+ if (!dev)
+ return;
- strcpy((char *)&onboard_dev[1], name);
- onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD;
- onboard_dev->dev.name = (char *)&onboard_dev[1];
- onboard_dev->dev.device_data = onboard_dev;
+ dev->instance = instance;
+ dev->segment = segment;
+ dev->bus = bus;
+ dev->devfn = devfn;
- list_add(&onboard_dev->dev.list, &dmi_devices);
+ strcpy((char *)&dev[1], name);
+ dev->dev.type = type;
+ dev->dev.name = (char *)&dev[1];
+ dev->dev.device_data = dev;
+
+ list_add(&dev->dev.list, &dmi_devices);
}
static void __init dmi_save_extended_devices(const struct dmi_header *dm)
{
- const u8 *d = (u8 *) dm + 5;
+ const char *name;
+ const u8 *d = (u8 *)dm;
/* Skip disabled device */
- if ((*d & 0x80) == 0)
+ if ((d[0x5] & 0x80) == 0)
return;
- dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5),
- dmi_string_nosave(dm, *(d-1)));
- dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
+ name = dmi_string_nosave(dm, d[0x4]);
+ dmi_save_dev_pciaddr(d[0x6], *(u16 *)(d + 0x7), d[0x9], d[0xA], name,
+ DMI_DEV_TYPE_DEV_ONBOARD);
+ dmi_save_one_device(d[0x5] & 0x7f, name);
+}
+
+static void __init dmi_save_system_slot(const struct dmi_header *dm)
+{
+ const u8 *d = (u8 *)dm;
+
+ /* Need SMBIOS 2.6+ structure */
+ if (dm->length < 0x11)
+ return;
+ dmi_save_dev_pciaddr(*(u16 *)(d + 0x9), *(u16 *)(d + 0xD), d[0xF],
+ d[0x10], dmi_string_nosave(dm, d[0x4]),
+ DMI_DEV_TYPE_DEV_SLOT);
}
static void __init count_mem_devices(const struct dmi_header *dm, void *v)
@@ -426,6 +445,9 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
break;
+ case 9: /* System Slots */
+ dmi_save_system_slot(dm);
+ break;
case 10: /* Onboard Devices Information */
dmi_save_devices(dm);
break;
@@ -869,7 +891,7 @@ EXPORT_SYMBOL(dmi_name_in_vendors);
* @from: previous device found in search, or %NULL for new search.
*
* Iterates through the list of known onboard devices. If a device is
- * found with a matching @vendor and @device, a pointer to its device
+ * found with a matching @type and @name, a pointer to its device
* structure is returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL as the @from argument.
* If @from is not %NULL, searches continue from next device.
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index cffa89b3317b..2cd37dad67a6 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -25,7 +25,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
-#include <asm/efi.h>
+#include <asm/early_ioremap.h>
struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR,
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index b62e2f5dcab3..cf7b7d46302a 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -253,7 +253,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
sys_table->boottime->free_pool(memory_map);
new_fdt_size += EFI_PAGE_SIZE;
} else {
- pr_efi_err(sys_table, "Unable to constuct new device tree.\n");
+ pr_efi_err(sys_table, "Unable to construct new device tree.\n");
goto fail_free_mmap;
}
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b18bea08ff25..c88dd24a4b1f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -134,8 +134,8 @@ config GPIO_BCM_KONA
config GPIO_BRCMSTB
tristate "BRCMSTB GPIO support"
- default y if ARCH_BRCMSTB
- depends on OF_GPIO && (ARCH_BRCMSTB || COMPILE_TEST)
+ default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
+ depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST)
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
@@ -344,13 +344,6 @@ config GPIO_RCAR
help
Say yes here to support GPIO on Renesas R-Car SoCs.
-config GPIO_SAMSUNG
- bool
- depends on PLAT_SAMSUNG
- help
- Legacy GPIO support. Use only for platforms without support for
- pinctrl.
-
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
@@ -496,8 +489,21 @@ menu "Port-mapped I/O GPIO drivers"
config GPIO_104_IDIO_16
tristate "ACCES 104-IDIO-16 GPIO support"
+ select GPIOLIB_IRQCHIP
help
- Enables GPIO support for the ACCES 104-IDIO-16 family.
+ Enables GPIO support for the ACCES 104-IDIO-16 family. The base port
+ address for the device may be set via the idio_16_base module
+ parameter. The interrupt line number for the device may be set via the
+ idio_16_irq module parameter.
+
+config GPIO_104_IDI_48
+ tristate "ACCES 104-IDI-48 GPIO support"
+ select GPIOLIB_IRQCHIP
+ help
+ Enables GPIO support for the ACCES 104-IDI-48 family. The base port
+ address for the device may be configured via the idi_48_base module
+ parameter. The interrupt line number for the device may be configured
+ via the idi_48_irq module parameter.
config GPIO_F7188X
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
@@ -907,7 +913,6 @@ menu "PCI GPIO expanders"
config GPIO_AMD8111
tristate "AMD 8111 GPIO driver"
- depends on PCI
help
The AMD 8111 south bridge contains 32 GPIO pins which can be used.
@@ -919,7 +924,7 @@ config GPIO_AMD8111
config GPIO_BT8XX
tristate "BT8XX GPIO abuser"
- depends on PCI && VIDEO_BT848=n
+ depends on VIDEO_BT848=n
help
The BT8xx frame grabber chip has 24 GPIO pins that can be abused
as a cheap PCI GPIO card.
@@ -935,14 +940,13 @@ config GPIO_BT8XX
config GPIO_INTEL_MID
bool "Intel Mid GPIO support"
- depends on PCI && X86
+ depends on X86
select GPIOLIB_IRQCHIP
help
Say Y here to support Intel Mid GPIO.
config GPIO_ML_IOH
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
- depends on PCI
select GENERIC_IRQ_CHIP
help
ML7213 is companion chip for Intel Atom E6xx series.
@@ -952,7 +956,7 @@ config GPIO_ML_IOH
config GPIO_PCH
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
- depends on PCI && (X86_32 || COMPILE_TEST)
+ depends on X86_32 || MIPS || COMPILE_TEST
select GENERIC_IRQ_CHIP
help
This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
@@ -968,7 +972,6 @@ config GPIO_PCH
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
- depends on PCI
select MFD_CORE
select MFD_RDC321X
help
@@ -977,7 +980,7 @@ config GPIO_RDC321X
config GPIO_SODAVILLE
bool "Intel Sodaville GPIO support"
- depends on X86 && PCI && OF
+ depends on X86 && OF
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
help
@@ -1028,7 +1031,7 @@ menu "USB GPIO expanders"
config GPIO_VIPERBOARD
tristate "Viperboard GPIO a & b support"
- depends on MFD_VIPERBOARD && USB
+ depends on MFD_VIPERBOARD
help
Say yes here to access the GPIO signals of Nano River
Technologies Viperboard. There are two GPIO chips on the
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 986dbd838cea..ece7d7cbdc80 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
+obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
@@ -79,7 +80,6 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
-obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
new file mode 100644
index 000000000000..52eed328ce99
--- /dev/null
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -0,0 +1,343 @@
+/*
+ * GPIO driver for the ACCES 104-IDI-48 family
+ * Copyright (C) 2015 William Breathitt Gray
+ *
+ * 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/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+static unsigned idi_48_base;
+module_param(idi_48_base, uint, 0);
+MODULE_PARM_DESC(idi_48_base, "ACCES 104-IDI-48 base address");
+static unsigned idi_48_irq;
+module_param(idi_48_irq, uint, 0);
+MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number");
+
+/**
+ * struct idi_48_gpio - GPIO device private data structure
+ * @chip: instance of the gpio_chip
+ * @lock: synchronization lock to prevent I/O race conditions
+ * @ack_lock: synchronization lock to prevent IRQ handler race conditions
+ * @irq_mask: input bits affected by interrupts
+ * @base: base port address of the GPIO device
+ * @extent: extent of port address region of the GPIO device
+ * @irq: Interrupt line number
+ * @cos_enb: Change-Of-State IRQ enable boundaries mask
+ */
+struct idi_48_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ spinlock_t ack_lock;
+ unsigned char irq_mask[6];
+ unsigned base;
+ unsigned extent;
+ unsigned irq;
+ unsigned char cos_enb;
+};
+
+static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ return 1;
+}
+
+static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return 0;
+}
+
+static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+ unsigned i;
+ const unsigned register_offset[6] = { 0, 1, 2, 4, 5, 6 };
+ unsigned base_offset;
+ unsigned mask;
+
+ for (i = 0; i < 48; i += 8)
+ if (offset < i + 8) {
+ base_offset = register_offset[i / 8];
+ mask = BIT(offset - i);
+
+ return !!(inb(idi48gpio->base + base_offset) & mask);
+ }
+
+ /* The following line should never execute since offset < 48 */
+ return 0;
+}
+
+static void idi_48_irq_ack(struct irq_data *data)
+{
+}
+
+static void idi_48_irq_mask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+ const unsigned offset = irqd_to_hwirq(data);
+ unsigned i;
+ unsigned mask;
+ unsigned boundary;
+ unsigned long flags;
+
+ for (i = 0; i < 48; i += 8)
+ if (offset < i + 8) {
+ mask = BIT(offset - i);
+ boundary = i / 8;
+
+ idi48gpio->irq_mask[boundary] &= ~mask;
+
+ if (!idi48gpio->irq_mask[boundary]) {
+ idi48gpio->cos_enb &= ~BIT(boundary);
+
+ spin_lock_irqsave(&idi48gpio->lock, flags);
+
+ outb(idi48gpio->cos_enb, idi48gpio->base + 7);
+
+ spin_unlock_irqrestore(&idi48gpio->lock, flags);
+ }
+
+ return;
+ }
+}
+
+static void idi_48_irq_unmask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+ const unsigned offset = irqd_to_hwirq(data);
+ unsigned i;
+ unsigned mask;
+ unsigned boundary;
+ unsigned prev_irq_mask;
+ unsigned long flags;
+
+ for (i = 0; i < 48; i += 8)
+ if (offset < i + 8) {
+ mask = BIT(offset - i);
+ boundary = i / 8;
+ prev_irq_mask = idi48gpio->irq_mask[boundary];
+
+ idi48gpio->irq_mask[boundary] |= mask;
+
+ if (!prev_irq_mask) {
+ idi48gpio->cos_enb |= BIT(boundary);
+
+ spin_lock_irqsave(&idi48gpio->lock, flags);
+
+ outb(idi48gpio->cos_enb, idi48gpio->base + 7);
+
+ spin_unlock_irqrestore(&idi48gpio->lock, flags);
+ }
+
+ return;
+ }
+}
+
+static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
+{
+ /* The only valid irq types are none and both-edges */
+ if (flow_type != IRQ_TYPE_NONE &&
+ (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct irq_chip idi_48_irqchip = {
+ .name = "104-idi-48",
+ .irq_ack = idi_48_irq_ack,
+ .irq_mask = idi_48_irq_mask,
+ .irq_unmask = idi_48_irq_unmask,
+ .irq_set_type = idi_48_irq_set_type
+};
+
+static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
+{
+ struct idi_48_gpio *const idi48gpio = dev_id;
+ unsigned long cos_status;
+ unsigned long boundary;
+ unsigned long irq_mask;
+ unsigned long bit_num;
+ unsigned long gpio;
+ struct gpio_chip *const chip = &idi48gpio->chip;
+
+ spin_lock(&idi48gpio->ack_lock);
+
+ spin_lock(&idi48gpio->lock);
+
+ cos_status = inb(idi48gpio->base + 7);
+
+ spin_unlock(&idi48gpio->lock);
+
+ /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
+ if (cos_status & BIT(6)) {
+ spin_unlock(&idi48gpio->ack_lock);
+ return IRQ_NONE;
+ }
+
+ /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
+ cos_status &= 0x3F;
+
+ for_each_set_bit(boundary, &cos_status, 6) {
+ irq_mask = idi48gpio->irq_mask[boundary];
+
+ for_each_set_bit(bit_num, &irq_mask, 8) {
+ gpio = bit_num + boundary * 8;
+
+ generic_handle_irq(irq_find_mapping(chip->irqdomain,
+ gpio));
+ }
+ }
+
+ spin_unlock(&idi48gpio->ack_lock);
+
+ return IRQ_HANDLED;
+}
+
+static int __init idi_48_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct idi_48_gpio *idi48gpio;
+ const unsigned base = idi_48_base;
+ const unsigned extent = 8;
+ const char *const name = dev_name(dev);
+ int err;
+ const unsigned irq = idi_48_irq;
+
+ idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
+ if (!idi48gpio)
+ return -ENOMEM;
+
+ if (!request_region(base, extent, name)) {
+ dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
+ name, base, base + extent);
+ err = -EBUSY;
+ goto err_lock_io_port;
+ }
+
+ idi48gpio->chip.label = name;
+ idi48gpio->chip.parent = dev;
+ idi48gpio->chip.owner = THIS_MODULE;
+ idi48gpio->chip.base = -1;
+ idi48gpio->chip.ngpio = 48;
+ idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
+ idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
+ idi48gpio->chip.get = idi_48_gpio_get;
+ idi48gpio->base = base;
+ idi48gpio->extent = extent;
+ idi48gpio->irq = irq;
+
+ spin_lock_init(&idi48gpio->lock);
+
+ dev_set_drvdata(dev, idi48gpio);
+
+ err = gpiochip_add_data(&idi48gpio->chip, idi48gpio);
+ if (err) {
+ dev_err(dev, "GPIO registering failed (%d)\n", err);
+ goto err_gpio_register;
+ }
+
+ /* Disable IRQ by default */
+ outb(0, base + 7);
+ inb(base + 7);
+
+ err = gpiochip_irqchip_add(&idi48gpio->chip, &idi_48_irqchip, 0,
+ handle_edge_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_err(dev, "Could not add irqchip (%d)\n", err);
+ goto err_gpiochip_irqchip_add;
+ }
+
+ err = request_irq(irq, idi_48_irq_handler, 0, name, idi48gpio);
+ if (err) {
+ dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+ goto err_request_irq;
+ }
+
+ return 0;
+
+err_request_irq:
+err_gpiochip_irqchip_add:
+ gpiochip_remove(&idi48gpio->chip);
+err_gpio_register:
+ release_region(base, extent);
+err_lock_io_port:
+ return err;
+}
+
+static int idi_48_remove(struct platform_device *pdev)
+{
+ struct idi_48_gpio *const idi48gpio = platform_get_drvdata(pdev);
+
+ free_irq(idi48gpio->irq, idi48gpio);
+ gpiochip_remove(&idi48gpio->chip);
+ release_region(idi48gpio->base, idi48gpio->extent);
+
+ return 0;
+}
+
+static struct platform_device *idi_48_device;
+
+static struct platform_driver idi_48_driver = {
+ .driver = {
+ .name = "104-idi-48"
+ },
+ .remove = idi_48_remove
+};
+
+static void __exit idi_48_exit(void)
+{
+ platform_device_unregister(idi_48_device);
+ platform_driver_unregister(&idi_48_driver);
+}
+
+static int __init idi_48_init(void)
+{
+ int err;
+
+ idi_48_device = platform_device_alloc(idi_48_driver.driver.name, -1);
+ if (!idi_48_device)
+ return -ENOMEM;
+
+ err = platform_device_add(idi_48_device);
+ if (err)
+ goto err_platform_device;
+
+ err = platform_driver_probe(&idi_48_driver, idi_48_probe);
+ if (err)
+ goto err_platform_driver;
+
+ return 0;
+
+err_platform_driver:
+ platform_device_del(idi_48_device);
+err_platform_device:
+ platform_device_put(idi_48_device);
+ return err;
+}
+
+module_init(idi_48_init);
+module_exit(idi_48_exit);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 5400d7d4d8fd..4d69b50b2d84 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -11,11 +11,14 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -25,20 +28,27 @@
static unsigned idio_16_base;
module_param(idio_16_base, uint, 0);
MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address");
+static unsigned idio_16_irq;
+module_param(idio_16_irq, uint, 0);
+MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number");
/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
- * @lock: synchronization lock to prevent gpio_set race conditions
+ * @lock: synchronization lock to prevent I/O race conditions
+ * @irq_mask: I/O bits affected by interrupts
* @base: base port address of the GPIO device
* @extent: extent of port address region of the GPIO device
+ * @irq: Interrupt line number
* @out_state: output bits state
*/
struct idio_16_gpio {
struct gpio_chip chip;
spinlock_t lock;
+ unsigned long irq_mask;
unsigned base;
unsigned extent;
+ unsigned irq;
unsigned out_state;
};
@@ -62,29 +72,24 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
-static struct idio_16_gpio *to_idio16gpio(struct gpio_chip *gc)
-{
- return container_of(gc, struct idio_16_gpio, chip);
-}
-
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip);
- const unsigned BIT_MASK = 1U << (offset-16);
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ const unsigned mask = BIT(offset-16);
if (offset < 16)
return -EINVAL;
if (offset < 24)
- return !!(inb(idio16gpio->base + 1) & BIT_MASK);
+ return !!(inb(idio16gpio->base + 1) & mask);
- return !!(inb(idio16gpio->base + 5) & (BIT_MASK>>8));
+ return !!(inb(idio16gpio->base + 5) & (mask>>8));
}
static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip);
- const unsigned BIT_MASK = 1U << offset;
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ const unsigned mask = BIT(offset);
unsigned long flags;
if (offset > 15)
@@ -93,9 +98,9 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_lock_irqsave(&idio16gpio->lock, flags);
if (value)
- idio16gpio->out_state |= BIT_MASK;
+ idio16gpio->out_state |= mask;
else
- idio16gpio->out_state &= ~BIT_MASK;
+ idio16gpio->out_state &= ~mask;
if (offset > 7)
outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
@@ -105,29 +110,106 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
+static void idio_16_irq_ack(struct irq_data *data)
+{
+}
+
+static void idio_16_irq_mask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ const unsigned long mask = BIT(irqd_to_hwirq(data));
+ unsigned long flags;
+
+ idio16gpio->irq_mask &= ~mask;
+
+ if (!idio16gpio->irq_mask) {
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ outb(0, idio16gpio->base + 2);
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ }
+}
+
+static void idio_16_irq_unmask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ const unsigned long mask = BIT(irqd_to_hwirq(data));
+ const unsigned long prev_irq_mask = idio16gpio->irq_mask;
+ unsigned long flags;
+
+ idio16gpio->irq_mask |= mask;
+
+ if (!prev_irq_mask) {
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ inb(idio16gpio->base + 2);
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ }
+}
+
+static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
+{
+ /* The only valid irq types are none and both-edges */
+ if (flow_type != IRQ_TYPE_NONE &&
+ (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct irq_chip idio_16_irqchip = {
+ .name = "104-idio-16",
+ .irq_ack = idio_16_irq_ack,
+ .irq_mask = idio_16_irq_mask,
+ .irq_unmask = idio_16_irq_unmask,
+ .irq_set_type = idio_16_irq_set_type
+};
+
+static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
+{
+ struct idio_16_gpio *const idio16gpio = dev_id;
+ struct gpio_chip *const chip = &idio16gpio->chip;
+ int gpio;
+
+ for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
+ generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+
+ spin_lock(&idio16gpio->lock);
+
+ outb(0, idio16gpio->base + 1);
+
+ spin_unlock(&idio16gpio->lock);
+
+ return IRQ_HANDLED;
+}
+
static int __init idio_16_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct idio_16_gpio *idio16gpio;
+ const unsigned base = idio_16_base;
+ const unsigned extent = 8;
+ const char *const name = dev_name(dev);
int err;
-
- const unsigned BASE = idio_16_base;
- const unsigned EXTENT = 8;
- const char *const NAME = dev_name(dev);
+ const unsigned irq = idio_16_irq;
idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
if (!idio16gpio)
return -ENOMEM;
- if (!request_region(BASE, EXTENT, NAME)) {
+ if (!request_region(base, extent, name)) {
dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
- NAME, BASE, BASE + EXTENT);
+ name, base, base + extent);
err = -EBUSY;
goto err_lock_io_port;
}
- idio16gpio->chip.label = NAME;
- idio16gpio->chip.dev = dev;
+ idio16gpio->chip.label = name;
+ idio16gpio->chip.parent = dev;
idio16gpio->chip.owner = THIS_MODULE;
idio16gpio->chip.base = -1;
idio16gpio->chip.ngpio = 32;
@@ -136,24 +218,45 @@ static int __init idio_16_probe(struct platform_device *pdev)
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
idio16gpio->chip.get = idio_16_gpio_get;
idio16gpio->chip.set = idio_16_gpio_set;
- idio16gpio->base = BASE;
- idio16gpio->extent = EXTENT;
+ idio16gpio->base = base;
+ idio16gpio->extent = extent;
+ idio16gpio->irq = irq;
idio16gpio->out_state = 0xFFFF;
spin_lock_init(&idio16gpio->lock);
dev_set_drvdata(dev, idio16gpio);
- err = gpiochip_add(&idio16gpio->chip);
+ err = gpiochip_add_data(&idio16gpio->chip, idio16gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
goto err_gpio_register;
}
+ /* Disable IRQ by default */
+ outb(0, base + 2);
+ outb(0, base + 1);
+
+ err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
+ handle_edge_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_err(dev, "Could not add irqchip (%d)\n", err);
+ goto err_gpiochip_irqchip_add;
+ }
+
+ err = request_irq(irq, idio_16_irq_handler, 0, name, idio16gpio);
+ if (err) {
+ dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+ goto err_request_irq;
+ }
+
return 0;
+err_request_irq:
+err_gpiochip_irqchip_add:
+ gpiochip_remove(&idio16gpio->chip);
err_gpio_register:
- release_region(BASE, EXTENT);
+ release_region(base, extent);
err_lock_io_port:
return err;
}
@@ -162,6 +265,7 @@ static int idio_16_remove(struct platform_device *pdev)
{
struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev);
+ free_irq(idio16gpio->irq, idio16gpio);
gpiochip_remove(&idio16gpio->chip);
release_region(idio16gpio->base, idio16gpio->extent);
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index 60172f835d15..c81224ff2dca 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -20,56 +20,34 @@
#define GEN_74X164_NUMBER_GPIOS 8
struct gen_74x164_chip {
- u8 *buffer;
struct gpio_chip gpio_chip;
struct mutex lock;
u32 registers;
-};
-
-static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc)
-{
- return container_of(gc, struct gen_74x164_chip, gpio_chip);
-}
-
-static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
-{
- struct spi_device *spi = to_spi_device(chip->gpio_chip.dev);
- struct spi_message message;
- struct spi_transfer *msg_buf;
- int i, ret = 0;
-
- msg_buf = kzalloc(chip->registers * sizeof(struct spi_transfer),
- GFP_KERNEL);
- if (!msg_buf)
- return -ENOMEM;
-
- spi_message_init(&message);
-
/*
* Since the registers are chained, every byte sent will make
* the previous byte shift to the next register in the
- * chain. Thus, the first byte send will end up in the last
+ * chain. Thus, the first byte sent will end up in the last
* register at the end of the transfer. So, to have a logical
- * numbering, send the bytes in reverse order so that the last
- * byte of the buffer will end up in the last register.
+ * numbering, store the bytes in reverse order.
*/
- for (i = chip->registers - 1; i >= 0; i--) {
- msg_buf[i].tx_buf = chip->buffer + i;
- msg_buf[i].len = sizeof(u8);
- spi_message_add_tail(msg_buf + i, &message);
- }
-
- ret = spi_sync(spi, &message);
+ u8 buffer[0];
+};
- kfree(msg_buf);
+static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
+{
+ struct spi_transfer xfer = {
+ .tx_buf = chip->buffer,
+ .len = chip->registers,
+ };
- return ret;
+ return spi_sync_transfer(to_spi_device(chip->gpio_chip.parent),
+ &xfer, 1);
}
static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
{
- struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
- u8 bank = offset / 8;
+ struct gen_74x164_chip *chip = gpiochip_get_data(gc);
+ u8 bank = chip->registers - 1 - offset / 8;
u8 pin = offset % 8;
int ret;
@@ -83,8 +61,8 @@ static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
static void gen_74x164_set_value(struct gpio_chip *gc,
unsigned offset, int val)
{
- struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
- u8 bank = offset / 8;
+ struct gen_74x164_chip *chip = gpiochip_get_data(gc);
+ u8 bank = chip->registers - 1 - offset / 8;
u8 pin = offset % 8;
mutex_lock(&chip->lock);
@@ -107,6 +85,7 @@ static int gen_74x164_direction_output(struct gpio_chip *gc,
static int gen_74x164_probe(struct spi_device *spi)
{
struct gen_74x164_chip *chip;
+ u32 nregs;
int ret;
/*
@@ -118,7 +97,14 @@ static int gen_74x164_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
+ if (of_property_read_u32(spi->dev.of_node, "registers-number",
+ &nregs)) {
+ dev_err(&spi->dev,
+ "Missing registers-number property in the DT.\n");
+ return -EINVAL;
+ }
+
+ chip = devm_kzalloc(&spi->dev, sizeof(*chip) + nregs, GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -130,20 +116,11 @@ static int gen_74x164_probe(struct spi_device *spi)
chip->gpio_chip.set = gen_74x164_set_value;
chip->gpio_chip.base = -1;
- if (of_property_read_u32(spi->dev.of_node, "registers-number",
- &chip->registers)) {
- dev_err(&spi->dev,
- "Missing registers-number property in the DT.\n");
- return -EINVAL;
- }
-
+ chip->registers = nregs;
chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
- chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
- if (!chip->buffer)
- return -ENOMEM;
chip->gpio_chip.can_sleep = true;
- chip->gpio_chip.dev = &spi->dev;
+ chip->gpio_chip.parent = &spi->dev;
chip->gpio_chip.owner = THIS_MODULE;
mutex_init(&chip->lock);
@@ -154,7 +131,7 @@ static int gen_74x164_probe(struct spi_device *spi)
goto exit_destroy;
}
- ret = gpiochip_add(&chip->gpio_chip);
+ ret = gpiochip_add_data(&chip->gpio_chip, chip);
if (!ret)
return 0;
diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
index 6b186829087c..372b0e01adc6 100644
--- a/drivers/gpio/gpio-74xx-mmio.c
+++ b/drivers/gpio/gpio-74xx-mmio.c
@@ -10,10 +10,9 @@
*/
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#define MMIO_74XX_DIR_IN (0 << 8)
@@ -21,7 +20,7 @@
#define MMIO_74XX_BIT_CNT(x) ((x) & 0xff)
struct mmio_74xx_gpio_priv {
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
unsigned flags;
};
@@ -78,30 +77,23 @@ static const struct of_device_id mmio_74xx_gpio_ids[] = {
};
MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids);
-static inline struct mmio_74xx_gpio_priv *to_74xx_gpio(struct gpio_chip *gc)
-{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- return container_of(bgc, struct mmio_74xx_gpio_priv, bgc);
-}
-
static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset)
{
- struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc);
+ struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
- return (priv->flags & MMIO_74XX_DIR_OUT) ? GPIOF_DIR_OUT : GPIOF_DIR_IN;
+ return !(priv->flags & MMIO_74XX_DIR_OUT);
}
static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
- struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc);
+ struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0;
}
static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc);
+ struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
if (priv->flags & MMIO_74XX_DIR_OUT) {
gc->set(gc, gpio, val);
@@ -134,28 +126,29 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev)
priv->flags = (uintptr_t) of_id->data;
- err = bgpio_init(&priv->bgc, &pdev->dev,
+ err = bgpio_init(&priv->gc, &pdev->dev,
DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),
dat, NULL, NULL, NULL, NULL, 0);
if (err)
return err;
- priv->bgc.gc.direction_input = mmio_74xx_dir_in;
- priv->bgc.gc.direction_output = mmio_74xx_dir_out;
- priv->bgc.gc.get_direction = mmio_74xx_get_direction;
- priv->bgc.gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags);
- priv->bgc.gc.owner = THIS_MODULE;
+ priv->gc.direction_input = mmio_74xx_dir_in;
+ priv->gc.direction_output = mmio_74xx_dir_out;
+ priv->gc.get_direction = mmio_74xx_get_direction;
+ priv->gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags);
+ priv->gc.owner = THIS_MODULE;
platform_set_drvdata(pdev, priv);
- return gpiochip_add(&priv->bgc.gc);
+ return gpiochip_add_data(&priv->gc, priv);
}
static int mmio_74xx_gpio_remove(struct platform_device *pdev)
{
struct mmio_74xx_gpio_priv *priv = platform_get_drvdata(pdev);
- return bgpio_remove(&priv->bgc);
+ gpiochip_remove(&priv->gc);
+ return 0;
}
static struct platform_driver mmio_74xx_gpio_driver = {
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index d3d0a90fe542..fb5b47b69f14 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -36,18 +36,13 @@ struct adnp {
u8 *irq_low;
};
-static inline struct adnp *to_adnp(struct gpio_chip *chip)
-{
- return container_of(chip, struct adnp, gpio);
-}
-
static int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value)
{
int err;
err = i2c_smbus_read_byte_data(adnp->client, offset);
if (err < 0) {
- dev_err(adnp->gpio.dev, "%s failed: %d\n",
+ dev_err(adnp->gpio.parent, "%s failed: %d\n",
"i2c_smbus_read_byte_data()", err);
return err;
}
@@ -62,7 +57,7 @@ static int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value)
err = i2c_smbus_write_byte_data(adnp->client, offset, value);
if (err < 0) {
- dev_err(adnp->gpio.dev, "%s failed: %d\n",
+ dev_err(adnp->gpio.parent, "%s failed: %d\n",
"i2c_smbus_write_byte_data()", err);
return err;
}
@@ -72,7 +67,7 @@ static int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value)
static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct adnp *adnp = to_adnp(chip);
+ struct adnp *adnp = gpiochip_get_data(chip);
unsigned int reg = offset >> adnp->reg_shift;
unsigned int pos = offset & 7;
u8 value;
@@ -106,7 +101,7 @@ static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value)
static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct adnp *adnp = to_adnp(chip);
+ struct adnp *adnp = gpiochip_get_data(chip);
mutex_lock(&adnp->i2c_lock);
__adnp_gpio_set(adnp, offset, value);
@@ -115,7 +110,7 @@ static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct adnp *adnp = to_adnp(chip);
+ struct adnp *adnp = gpiochip_get_data(chip);
unsigned int reg = offset >> adnp->reg_shift;
unsigned int pos = offset & 7;
u8 value;
@@ -150,7 +145,7 @@ out:
static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct adnp *adnp = to_adnp(chip);
+ struct adnp *adnp = gpiochip_get_data(chip);
unsigned int reg = offset >> adnp->reg_shift;
unsigned int pos = offset & 7;
int err;
@@ -187,7 +182,7 @@ out:
static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct adnp *adnp = to_adnp(chip);
+ struct adnp *adnp = gpiochip_get_data(chip);
unsigned int num_regs = 1 << adnp->reg_shift, i, j;
int err;
@@ -266,11 +261,11 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
chip->base = -1;
chip->ngpio = num_gpios;
chip->label = adnp->client->name;
- chip->dev = &adnp->client->dev;
- chip->of_node = chip->dev->of_node;
+ chip->parent = &adnp->client->dev;
+ chip->of_node = chip->parent->of_node;
chip->owner = THIS_MODULE;
- err = gpiochip_add(chip);
+ err = gpiochip_add_data(chip, adnp);
if (err)
return err;
@@ -340,7 +335,7 @@ static irqreturn_t adnp_irq(int irq, void *data)
static void adnp_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct adnp *adnp = to_adnp(gc);
+ struct adnp *adnp = gpiochip_get_data(gc);
unsigned int reg = d->hwirq >> adnp->reg_shift;
unsigned int pos = d->hwirq & 7;
@@ -350,7 +345,7 @@ static void adnp_irq_mask(struct irq_data *d)
static void adnp_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct adnp *adnp = to_adnp(gc);
+ struct adnp *adnp = gpiochip_get_data(gc);
unsigned int reg = d->hwirq >> adnp->reg_shift;
unsigned int pos = d->hwirq & 7;
@@ -360,7 +355,7 @@ static void adnp_irq_unmask(struct irq_data *d)
static int adnp_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct adnp *adnp = to_adnp(gc);
+ struct adnp *adnp = gpiochip_get_data(gc);
unsigned int reg = d->hwirq >> adnp->reg_shift;
unsigned int pos = d->hwirq & 7;
@@ -390,7 +385,7 @@ static int adnp_irq_set_type(struct irq_data *d, unsigned int type)
static void adnp_irq_bus_lock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct adnp *adnp = to_adnp(gc);
+ struct adnp *adnp = gpiochip_get_data(gc);
mutex_lock(&adnp->irq_lock);
}
@@ -398,7 +393,7 @@ static void adnp_irq_bus_lock(struct irq_data *d)
static void adnp_irq_bus_unlock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct adnp *adnp = to_adnp(gc);
+ struct adnp *adnp = gpiochip_get_data(gc);
unsigned int num_regs = 1 << adnp->reg_shift, i;
mutex_lock(&adnp->i2c_lock);
@@ -435,7 +430,8 @@ static int adnp_irq_setup(struct adnp *adnp)
* is chosen to match the register layout of the hardware in that
* each segment contains the corresponding bits for all interrupts.
*/
- adnp->irq_enable = devm_kzalloc(chip->dev, num_regs * 6, GFP_KERNEL);
+ adnp->irq_enable = devm_kzalloc(chip->parent, num_regs * 6,
+ GFP_KERNEL);
if (!adnp->irq_enable)
return -ENOMEM;
@@ -462,12 +458,12 @@ static int adnp_irq_setup(struct adnp *adnp)
adnp->irq_enable[i] = 0x00;
}
- err = devm_request_threaded_irq(chip->dev, adnp->client->irq,
+ err = devm_request_threaded_irq(chip->parent, adnp->client->irq,
NULL, adnp_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- dev_name(chip->dev), adnp);
+ dev_name(chip->parent), adnp);
if (err != 0) {
- dev_err(chip->dev, "can't request IRQ#%d: %d\n",
+ dev_err(chip->parent, "can't request IRQ#%d: %d\n",
adnp->client->irq, err);
return err;
}
@@ -478,7 +474,7 @@ static int adnp_irq_setup(struct adnp *adnp)
handle_simple_irq,
IRQ_TYPE_NONE);
if (err) {
- dev_err(chip->dev,
+ dev_err(chip->parent,
"could not connect irqchip to gpiochip\n");
return err;
}
@@ -547,7 +543,6 @@ MODULE_DEVICE_TABLE(of, adnp_of_match);
static struct i2c_driver adnp_i2c_driver = {
.driver = {
.name = "gpio-adnp",
- .owner = THIS_MODULE,
.of_match_table = adnp_of_match,
},
.probe = adnp_i2c_probe,
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index caff711ca5a9..4fa7ff1fec9a 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -27,7 +27,7 @@ static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
struct adp5520_gpio *dev;
uint8_t reg_val;
- dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+ dev = gpiochip_get_data(chip);
/*
* There are dedicated registers for GPIO IN/OUT.
@@ -46,7 +46,7 @@ static void adp5520_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
struct adp5520_gpio *dev;
- dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+ dev = gpiochip_get_data(chip);
if (val)
adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
@@ -57,7 +57,7 @@ static void adp5520_gpio_set_value(struct gpio_chip *chip,
static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
struct adp5520_gpio *dev;
- dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+ dev = gpiochip_get_data(chip);
clear_bit(off, &dev->output);
@@ -70,7 +70,7 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip,
{
struct adp5520_gpio *dev;
int ret = 0;
- dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+ dev = gpiochip_get_data(chip);
set_bit(off, &dev->output);
@@ -153,7 +153,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
goto err;
}
- ret = gpiochip_add(&dev->gpio_chip);
+ ret = gpiochip_add_data(&dev->gpio_chip, dev);
if (ret)
goto err;
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index 984186ee58a0..19a0eba1e942 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -65,8 +65,7 @@ static int adp5588_gpio_write(struct i2c_client *client, u8 reg, u8 val)
static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
- struct adp5588_gpio *dev =
- container_of(chip, struct adp5588_gpio, gpio_chip);
+ struct adp5588_gpio *dev = gpiochip_get_data(chip);
unsigned bank = ADP5588_BANK(off);
unsigned bit = ADP5588_BIT(off);
int val;
@@ -87,8 +86,7 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
unsigned bank, bit;
- struct adp5588_gpio *dev =
- container_of(chip, struct adp5588_gpio, gpio_chip);
+ struct adp5588_gpio *dev = gpiochip_get_data(chip);
bank = ADP5588_BANK(off);
bit = ADP5588_BIT(off);
@@ -108,8 +106,7 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
int ret;
unsigned bank;
- struct adp5588_gpio *dev =
- container_of(chip, struct adp5588_gpio, gpio_chip);
+ struct adp5588_gpio *dev = gpiochip_get_data(chip);
bank = ADP5588_BANK(off);
@@ -126,8 +123,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
{
int ret;
unsigned bank, bit;
- struct adp5588_gpio *dev =
- container_of(chip, struct adp5588_gpio, gpio_chip);
+ struct adp5588_gpio *dev = gpiochip_get_data(chip);
bank = ADP5588_BANK(off);
bit = ADP5588_BIT(off);
@@ -152,8 +148,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
#ifdef CONFIG_GPIO_ADP5588_IRQ
static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off)
{
- struct adp5588_gpio *dev =
- container_of(chip, struct adp5588_gpio, gpio_chip);
+ struct adp5588_gpio *dev = gpiochip_get_data(chip);
+
return dev->irq_base + off;
}
@@ -418,7 +414,7 @@ static int adp5588_gpio_probe(struct i2c_client *client,
}
}
- ret = gpiochip_add(&dev->gpio_chip);
+ ret = gpiochip_add_data(&dev->gpio_chip, dev);
if (ret)
goto err_irq;
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 3e6661bab54a..2aeaebd1c6e7 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -42,11 +42,6 @@ struct altera_gpio_chip {
int mapped_irq;
};
-static struct altera_gpio_chip *to_altera(struct gpio_chip *gc)
-{
- return container_of(gc, struct altera_gpio_chip, mmchip.gc);
-}
-
static void altera_gpio_irq_unmask(struct irq_data *d)
{
struct altera_gpio_chip *altera_gc;
@@ -54,7 +49,7 @@ static void altera_gpio_irq_unmask(struct irq_data *d)
unsigned long flags;
u32 intmask;
- altera_gc = to_altera(irq_data_get_irq_chip_data(d));
+ altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
mm_gc = &altera_gc->mmchip;
spin_lock_irqsave(&altera_gc->gpio_lock, flags);
@@ -72,7 +67,7 @@ static void altera_gpio_irq_mask(struct irq_data *d)
unsigned long flags;
u32 intmask;
- altera_gc = to_altera(irq_data_get_irq_chip_data(d));
+ altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
mm_gc = &altera_gc->mmchip;
spin_lock_irqsave(&altera_gc->gpio_lock, flags);
@@ -92,7 +87,7 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
{
struct altera_gpio_chip *altera_gc;
- altera_gc = to_altera(irq_data_get_irq_chip_data(d));
+ altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
if (type == IRQ_TYPE_NONE)
return 0;
@@ -145,7 +140,7 @@ static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
unsigned int data_reg;
mm_gc = to_of_mm_gpio_chip(gc);
- chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+ chip = gpiochip_get_data(gc);
spin_lock_irqsave(&chip->gpio_lock, flags);
data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA);
@@ -165,7 +160,7 @@ static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
unsigned int gpio_ddr;
mm_gc = to_of_mm_gpio_chip(gc);
- chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+ chip = gpiochip_get_data(gc);
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set pin as input, assumes software controlled IP */
@@ -186,7 +181,7 @@ static int altera_gpio_direction_output(struct gpio_chip *gc,
unsigned int data_reg, gpio_ddr;
mm_gc = to_of_mm_gpio_chip(gc);
- chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+ chip = gpiochip_get_data(gc);
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Sets the GPIO value */
@@ -215,7 +210,7 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
unsigned long status;
int i;
- altera_gc = to_altera(irq_desc_get_handler_data(desc));
+ altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
chip = irq_desc_get_chip(desc);
mm_gc = &altera_gc->mmchip;
irqdomain = altera_gc->mmchip.gc.irqdomain;
@@ -244,7 +239,7 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
unsigned long status;
int i;
- altera_gc = to_altera(irq_desc_get_handler_data(desc));
+ altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
chip = irq_desc_get_chip(desc);
mm_gc = &altera_gc->mmchip;
irqdomain = altera_gc->mmchip.gc.irqdomain;
@@ -290,9 +285,9 @@ static int altera_gpio_probe(struct platform_device *pdev)
altera_gc->mmchip.gc.get = altera_gpio_get;
altera_gc->mmchip.gc.set = altera_gpio_set;
altera_gc->mmchip.gc.owner = THIS_MODULE;
- altera_gc->mmchip.gc.dev = &pdev->dev;
+ altera_gc->mmchip.gc.parent = &pdev->dev;
- ret = of_mm_gpiochip_add(node, &altera_gc->mmchip);
+ ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc);
if (ret) {
dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
return ret;
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index d00d81928fe8..c7040fffc5b4 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -75,11 +75,9 @@ struct amd_gpio {
u8 orig[32];
};
-#define to_agp(chip) container_of(chip, struct amd_gpio, chip)
-
static int amd_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct amd_gpio *agp = to_agp(chip);
+ struct amd_gpio *agp = gpiochip_get_data(chip);
agp->orig[offset] = ioread8(agp->pm + AMD_REG_GPIO(offset)) &
(AMD_GPIO_DEBOUNCE | AMD_GPIO_MODE_MASK | AMD_GPIO_X_MASK);
@@ -91,7 +89,7 @@ static int amd_gpio_request(struct gpio_chip *chip, unsigned offset)
static void amd_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct amd_gpio *agp = to_agp(chip);
+ struct amd_gpio *agp = gpiochip_get_data(chip);
dev_dbg(&agp->pdev->dev, "Freed gpio %d, data %x\n", offset, agp->orig[offset]);
@@ -100,7 +98,7 @@ static void amd_gpio_free(struct gpio_chip *chip, unsigned offset)
static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct amd_gpio *agp = to_agp(chip);
+ struct amd_gpio *agp = gpiochip_get_data(chip);
u8 temp;
unsigned long flags;
@@ -115,7 +113,7 @@ static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int amd_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct amd_gpio *agp = to_agp(chip);
+ struct amd_gpio *agp = gpiochip_get_data(chip);
u8 temp;
temp = ioread8(agp->pm + AMD_REG_GPIO(offset));
@@ -127,7 +125,7 @@ static int amd_gpio_get(struct gpio_chip *chip, unsigned offset)
static int amd_gpio_dirout(struct gpio_chip *chip, unsigned offset, int value)
{
- struct amd_gpio *agp = to_agp(chip);
+ struct amd_gpio *agp = gpiochip_get_data(chip);
u8 temp;
unsigned long flags;
@@ -144,7 +142,7 @@ static int amd_gpio_dirout(struct gpio_chip *chip, unsigned offset, int value)
static int amd_gpio_dirin(struct gpio_chip *chip, unsigned offset)
{
- struct amd_gpio *agp = to_agp(chip);
+ struct amd_gpio *agp = gpiochip_get_data(chip);
u8 temp;
unsigned long flags;
@@ -220,12 +218,12 @@ found:
goto out;
}
gp.pdev = pdev;
- gp.chip.dev = &pdev->dev;
+ gp.chip.parent = &pdev->dev;
spin_lock_init(&gp.lock);
printk(KERN_INFO "AMD-8111 GPIO detected\n");
- err = gpiochip_add(&gp.chip);
+ err = gpiochip_add_data(&gp.chip, &gp);
if (err) {
printk(KERN_ERR "GPIO registering failed (%d)\n",
err);
diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c
index cbbb966d4fc0..c2484046e8e9 100644
--- a/drivers/gpio/gpio-amdpt.c
+++ b/drivers/gpio/gpio-amdpt.c
@@ -31,22 +31,20 @@ struct pt_gpio_chip {
spinlock_t lock;
};
-#define to_pt_gpio(c) container_of(c, struct pt_gpio_chip, gc)
-
static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
{
- struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+ struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
unsigned long flags;
u32 using_pins;
- dev_dbg(gc->dev, "pt_gpio_request offset=%x\n", offset);
+ dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset);
spin_lock_irqsave(&pt_gpio->lock, flags);
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
if (using_pins & BIT(offset)) {
- dev_warn(gc->dev, "PT GPIO pin %x reconfigured\n",
- offset);
+ dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n",
+ offset);
spin_unlock_irqrestore(&pt_gpio->lock, flags);
return -EINVAL;
}
@@ -60,7 +58,7 @@ static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
{
- struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+ struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
unsigned long flags;
u32 using_pins;
@@ -72,16 +70,16 @@ static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
spin_unlock_irqrestore(&pt_gpio->lock, flags);
- dev_dbg(gc->dev, "pt_gpio_free offset=%x\n", offset);
+ dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset);
}
static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value)
{
- struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+ struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
unsigned long flags;
u32 data;
- dev_dbg(gc->dev, "pt_gpio_set_value offset=%x, value=%x\n",
+ dev_dbg(gc->parent, "pt_gpio_set_value offset=%x, value=%x\n",
offset, value);
spin_lock_irqsave(&pt_gpio->lock, flags);
@@ -97,7 +95,7 @@ static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value)
static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
{
- struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+ struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
unsigned long flags;
u32 data;
@@ -116,7 +114,7 @@ static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
data >>= offset;
data &= 1;
- dev_dbg(gc->dev, "pt_gpio_get_value offset=%x, value=%x\n",
+ dev_dbg(gc->parent, "pt_gpio_get_value offset=%x, value=%x\n",
offset, data);
return data;
@@ -124,11 +122,11 @@ static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+ struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
unsigned long flags;
u32 data;
- dev_dbg(gc->dev, "pt_gpio_dirction_input offset=%x\n", offset);
+ dev_dbg(gc->parent, "pt_gpio_dirction_input offset=%x\n", offset);
spin_lock_irqsave(&pt_gpio->lock, flags);
@@ -144,11 +142,11 @@ static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
static int pt_gpio_direction_output(struct gpio_chip *gc,
unsigned offset, int value)
{
- struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+ struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
unsigned long flags;
u32 data;
- dev_dbg(gc->dev, "pt_gpio_direction_output offset=%x, value=%x\n",
+ dev_dbg(gc->parent, "pt_gpio_direction_output offset=%x, value=%x\n",
offset, value);
spin_lock_irqsave(&pt_gpio->lock, flags);
@@ -202,7 +200,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->gc.label = pdev->name;
pt_gpio->gc.owner = THIS_MODULE;
- pt_gpio->gc.dev = dev;
+ pt_gpio->gc.parent = dev;
pt_gpio->gc.request = pt_gpio_request;
pt_gpio->gc.free = pt_gpio_free;
pt_gpio->gc.direction_input = pt_gpio_direction_input;
@@ -214,7 +212,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
#if defined(CONFIG_OF_GPIO)
pt_gpio->gc.of_node = pdev->dev.of_node;
#endif
- ret = gpiochip_add(&pt_gpio->gc);
+ ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio);
if (ret) {
dev_err(&pdev->dev, "Failed to register GPIO lib\n");
return ret;
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index ca002739616a..e910c1f41d93 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/drivers/gpio/gpio-arizona.c
@@ -28,14 +28,9 @@ struct arizona_gpio {
struct gpio_chip gpio_chip;
};
-static inline struct arizona_gpio *to_arizona_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct arizona_gpio, gpio_chip);
-}
-
static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+ struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
struct arizona *arizona = arizona_gpio->arizona;
return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
@@ -44,7 +39,7 @@ static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+ struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
struct arizona *arizona = arizona_gpio->arizona;
unsigned int val;
int ret;
@@ -62,7 +57,7 @@ static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
static int arizona_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+ struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
struct arizona *arizona = arizona_gpio->arizona;
if (value)
@@ -74,7 +69,7 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip,
static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+ struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
struct arizona *arizona = arizona_gpio->arizona;
if (value)
@@ -108,7 +103,7 @@ static int arizona_gpio_probe(struct platform_device *pdev)
arizona_gpio->arizona = arizona;
arizona_gpio->gpio_chip = template_chip;
- arizona_gpio->gpio_chip.dev = &pdev->dev;
+ arizona_gpio->gpio_chip.parent = &pdev->dev;
#ifdef CONFIG_OF_GPIO
arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
#endif
@@ -122,6 +117,10 @@ static int arizona_gpio_probe(struct platform_device *pdev)
case WM1814:
arizona_gpio->gpio_chip.ngpio = 5;
break;
+ case WM1831:
+ case CS47L24:
+ arizona_gpio->gpio_chip.ngpio = 2;
+ break;
default:
dev_err(&pdev->dev, "Unknown chip variant %d\n",
arizona->type);
@@ -133,7 +132,7 @@ static int arizona_gpio_probe(struct platform_device *pdev)
else
arizona_gpio->gpio_chip.base = -1;
- ret = gpiochip_add(&arizona_gpio->gpio_chip);
+ ret = gpiochip_add_data(&arizona_gpio->gpio_chip, arizona_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
ret);
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 5eaea8b812cf..d13dd133a907 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -24,12 +24,10 @@ struct ath79_gpio_ctrl {
spinlock_t lock;
};
-#define to_ath79_gpio_ctrl(c) container_of(c, struct ath79_gpio_ctrl, chip)
-
static void ath79_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+ struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
if (value)
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET);
@@ -39,7 +37,7 @@ static void ath79_gpio_set_value(struct gpio_chip *chip,
static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+ struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
}
@@ -47,7 +45,7 @@ static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static int ath79_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+ struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags);
@@ -64,7 +62,7 @@ static int ath79_gpio_direction_input(struct gpio_chip *chip,
static int ath79_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+ struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags);
@@ -85,7 +83,7 @@ static int ath79_gpio_direction_output(struct gpio_chip *chip,
static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+ struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags);
@@ -102,7 +100,7 @@ static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+ struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags);
@@ -138,7 +136,7 @@ static const struct of_device_id ath79_gpio_of_match[] = {
static int ath79_gpio_probe(struct platform_device *pdev)
{
- struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct ath79_gpio_ctrl *ctrl;
struct resource *res;
@@ -177,14 +175,14 @@ static int ath79_gpio_probe(struct platform_device *pdev)
spin_lock_init(&ctrl->lock);
memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip));
- ctrl->chip.dev = &pdev->dev;
+ ctrl->chip.parent = &pdev->dev;
ctrl->chip.ngpio = ath79_gpio_count;
if (oe_inverted) {
ctrl->chip.direction_input = ar934x_gpio_direction_input;
ctrl->chip.direction_output = ar934x_gpio_direction_output;
}
- err = gpiochip_add(&ctrl->chip);
+ err = gpiochip_add_data(&ctrl->chip, ctrl);
if (err) {
dev_err(&pdev->dev,
"cannot add AR71xx GPIO chip, error=%d", err);
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index 33a1f9779b86..b6c5abe85daf 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -78,11 +78,6 @@ struct bcm_kona_gpio_bank {
struct bcm_kona_gpio *kona_gpio;
};
-static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct bcm_kona_gpio, gpio_chip);
-}
-
static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base,
int bank_id, u32 lockcode)
{
@@ -124,7 +119,7 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
{
- struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+ struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
void __iomem *reg_base = kona_gpio->reg_base;
u32 val;
@@ -141,7 +136,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
u32 val, reg_offset;
unsigned long flags;
- kona_gpio = to_kona_gpio(chip);
+ kona_gpio = gpiochip_get_data(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
@@ -168,7 +163,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
u32 val, reg_offset;
unsigned long flags;
- kona_gpio = to_kona_gpio(chip);
+ kona_gpio = gpiochip_get_data(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
@@ -188,7 +183,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio)
{
- struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+ struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
bcm_kona_gpio_unlock_gpio(kona_gpio, gpio);
return 0;
@@ -196,7 +191,7 @@ static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio)
static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio)
{
- struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+ struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
bcm_kona_gpio_lock_gpio(kona_gpio, gpio);
}
@@ -208,7 +203,7 @@ static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
u32 val;
unsigned long flags;
- kona_gpio = to_kona_gpio(chip);
+ kona_gpio = gpiochip_get_data(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
@@ -232,7 +227,7 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
u32 val, reg_offset;
unsigned long flags;
- kona_gpio = to_kona_gpio(chip);
+ kona_gpio = gpiochip_get_data(chip);
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
@@ -255,7 +250,7 @@ static int bcm_kona_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
{
struct bcm_kona_gpio *kona_gpio;
- kona_gpio = to_kona_gpio(chip);
+ kona_gpio = gpiochip_get_data(chip);
if (gpio >= kona_gpio->gpio_chip.ngpio)
return -ENXIO;
return irq_create_mapping(kona_gpio->irq_domain, gpio);
@@ -269,11 +264,11 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
u32 val, res;
unsigned long flags;
- kona_gpio = to_kona_gpio(chip);
+ kona_gpio = gpiochip_get_data(chip);
reg_base = kona_gpio->reg_base;
/* debounce must be 1-128ms (or 0) */
if ((debounce > 0 && debounce < 1000) || debounce > 128000) {
- dev_err(chip->dev, "Debounce value %u not in range\n",
+ dev_err(chip->parent, "Debounce value %u not in range\n",
debounce);
return -EINVAL;
}
@@ -416,7 +411,7 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
case IRQ_TYPE_LEVEL_LOW:
/* BCM GPIO doesn't support level triggering */
default:
- dev_err(kona_gpio->gpio_chip.dev,
+ dev_err(kona_gpio->gpio_chip.parent,
"Invalid BCM GPIO irq type 0x%x\n", type);
return -EINVAL;
}
@@ -477,7 +472,7 @@ static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
if (gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) {
- dev_err(kona_gpio->gpio_chip.dev,
+ dev_err(kona_gpio->gpio_chip.parent,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
return -EINVAL;
@@ -635,7 +630,7 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev)
bcm_kona_gpio_reset(kona_gpio);
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, kona_gpio);
if (ret < 0) {
dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret);
goto err_irq_domain;
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 4c64627c6bb5..d7644251e869 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -16,7 +16,6 @@
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/module.h>
-#include <linux/basic_mmio_gpio.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/interrupt.h>
@@ -35,7 +34,7 @@
struct brcmstb_gpio_bank {
struct list_head node;
int id;
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
struct brcmstb_gpio_priv *parent_priv;
u32 width;
struct irq_chip irq_chip;
@@ -57,37 +56,30 @@ struct brcmstb_gpio_priv {
/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
#define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1))
-static inline struct brcmstb_gpio_bank *
-brcmstb_gpio_gc_to_bank(struct gpio_chip *gc)
-{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- return container_of(bgc, struct brcmstb_gpio_bank, bgc);
-}
-
static inline struct brcmstb_gpio_priv *
brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
{
- struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
return bank->parent_priv;
}
static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
unsigned int offset, bool enable)
{
- struct bgpio_chip *bgc = &bank->bgc;
+ struct gpio_chip *gc = &bank->gc;
struct brcmstb_gpio_priv *priv = bank->parent_priv;
- u32 mask = bgc->pin2mask(bgc, offset);
+ u32 mask = gc->pin2mask(gc, offset);
u32 imask;
unsigned long flags;
- spin_lock_irqsave(&bgc->lock, flags);
- imask = bgc->read_reg(priv->reg_base + GIO_MASK(bank->id));
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+ imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
if (enable)
imask |= mask;
else
imask &= ~mask;
- bgc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
/* -------------------- IRQ chip functions -------------------- */
@@ -95,7 +87,7 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
static void brcmstb_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
brcmstb_gpio_set_imask(bank, d->hwirq, false);
}
@@ -103,7 +95,7 @@ static void brcmstb_gpio_irq_mask(struct irq_data *d)
static void brcmstb_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
brcmstb_gpio_set_imask(bank, d->hwirq, true);
}
@@ -111,7 +103,7 @@ static void brcmstb_gpio_irq_unmask(struct irq_data *d)
static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
struct brcmstb_gpio_priv *priv = bank->parent_priv;
u32 mask = BIT(d->hwirq);
u32 edge_insensitive, iedge_insensitive;
@@ -149,23 +141,23 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
- spin_lock_irqsave(&bank->bgc.lock, flags);
+ spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
- iedge_config = bank->bgc.read_reg(priv->reg_base +
+ iedge_config = bank->gc.read_reg(priv->reg_base +
GIO_EC(bank->id)) & ~mask;
- iedge_insensitive = bank->bgc.read_reg(priv->reg_base +
+ iedge_insensitive = bank->gc.read_reg(priv->reg_base +
GIO_EI(bank->id)) & ~mask;
- ilevel = bank->bgc.read_reg(priv->reg_base +
+ ilevel = bank->gc.read_reg(priv->reg_base +
GIO_LEVEL(bank->id)) & ~mask;
- bank->bgc.write_reg(priv->reg_base + GIO_EC(bank->id),
+ bank->gc.write_reg(priv->reg_base + GIO_EC(bank->id),
iedge_config | edge_config);
- bank->bgc.write_reg(priv->reg_base + GIO_EI(bank->id),
+ bank->gc.write_reg(priv->reg_base + GIO_EI(bank->id),
iedge_insensitive | edge_insensitive);
- bank->bgc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
+ bank->gc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
ilevel | level);
- spin_unlock_irqrestore(&bank->bgc.lock, flags);
+ spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
return 0;
}
@@ -210,29 +202,29 @@ static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data)
static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
{
struct brcmstb_gpio_priv *priv = bank->parent_priv;
- struct irq_domain *irq_domain = bank->bgc.gc.irqdomain;
+ struct irq_domain *irq_domain = bank->gc.irqdomain;
void __iomem *reg_base = priv->reg_base;
unsigned long status;
unsigned long flags;
- spin_lock_irqsave(&bank->bgc.lock, flags);
- while ((status = bank->bgc.read_reg(reg_base + GIO_STAT(bank->id)) &
- bank->bgc.read_reg(reg_base + GIO_MASK(bank->id)))) {
+ spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
+ while ((status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) &
+ bank->gc.read_reg(reg_base + GIO_MASK(bank->id)))) {
int bit;
for_each_set_bit(bit, &status, 32) {
- u32 stat = bank->bgc.read_reg(reg_base +
+ u32 stat = bank->gc.read_reg(reg_base +
GIO_STAT(bank->id));
if (bit >= bank->width)
dev_warn(&priv->pdev->dev,
"IRQ for invalid GPIO (bank=%d, offset=%d)\n",
bank->id, bit);
- bank->bgc.write_reg(reg_base + GIO_STAT(bank->id),
+ bank->gc.write_reg(reg_base + GIO_STAT(bank->id),
stat | BIT(bit));
generic_handle_irq(irq_find_mapping(irq_domain, bit));
}
}
- spin_unlock_irqrestore(&bank->bgc.lock, flags);
+ spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
}
/* Each UPG GIO block has one IRQ for all banks */
@@ -303,9 +295,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
*/
list_for_each(pos, &priv->bank_list) {
bank = list_entry(pos, struct brcmstb_gpio_bank, node);
- ret = bgpio_remove(&bank->bgc);
- if (ret)
- dev_err(&pdev->dev, "gpiochip_remove fail in cleanup\n");
+ gpiochip_remove(&bank->gc);
}
if (priv->reboot_notifier.notifier_call) {
ret = unregister_reboot_notifier(&priv->reboot_notifier);
@@ -320,7 +310,7 @@ static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags)
{
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
- struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+ struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
int offset;
if (gc->of_gpio_n_cells != 2) {
@@ -398,9 +388,9 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev,
if (priv->can_wake)
bank->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake;
- gpiochip_irqchip_add(&bank->bgc.gc, &bank->irq_chip, 0,
+ gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0,
handle_simple_irq, IRQ_TYPE_NONE);
- gpiochip_set_chained_irqchip(&bank->bgc.gc, &bank->irq_chip,
+ gpiochip_set_chained_irqchip(&bank->gc, &bank->irq_chip,
priv->parent_irq, brcmstb_gpio_irq_handler);
return 0;
@@ -419,6 +409,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
int num_banks = 0;
int err;
static int gpio_base;
+ unsigned long flags = 0;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -448,10 +439,21 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
if (brcmstb_gpio_sanity_check_banks(dev, np, res))
return -EINVAL;
+ /*
+ * MIPS endianness is configured by boot strap, which also reverses all
+ * bus endianness (i.e., big-endian CPU + big endian bus ==> native
+ * endian I/O).
+ *
+ * Other architectures (e.g., ARM) either do not support big endian, or
+ * else leave I/O in little endian mode.
+ */
+#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
+ flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+#endif
+
of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
bank_width) {
struct brcmstb_gpio_bank *bank;
- struct bgpio_chip *bgc;
struct gpio_chip *gc;
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
@@ -473,17 +475,16 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
* Regs are 4 bytes wide, have data reg, no set/clear regs,
* and direction bits have 0 = output and 1 = input
*/
- bgc = &bank->bgc;
- err = bgpio_init(bgc, dev, 4,
+ gc = &bank->gc;
+ err = bgpio_init(gc, dev, 4,
reg_base + GIO_DATA(bank->id),
NULL, NULL, NULL,
- reg_base + GIO_IODIR(bank->id), 0);
+ reg_base + GIO_IODIR(bank->id), flags);
if (err) {
dev_err(dev, "bgpio_init() failed\n");
goto fail;
}
- gc = &bgc->gc;
gc->of_node = np;
gc->owner = THIS_MODULE;
gc->label = np->full_name;
@@ -497,9 +498,9 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
* Mask all interrupts by default, since wakeup interrupts may
* be retained from S5 cold boot
*/
- bank->bgc.write_reg(reg_base + GIO_MASK(bank->id), 0);
+ gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
- err = gpiochip_add(gc);
+ err = gpiochip_add_data(gc, bank);
if (err) {
dev_err(dev, "Could not add gpiochip for bank %d\n",
bank->id);
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index 7e4c43c18960..acefb25e8eca 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the
static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
- struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+ struct bt8xxgpio *bg = gpiochip_get_data(gpio);
unsigned long flags;
u32 outen, data;
@@ -101,7 +101,7 @@ static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
- struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+ struct bt8xxgpio *bg = gpiochip_get_data(gpio);
unsigned long flags;
u32 val;
@@ -115,7 +115,7 @@ static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
unsigned nr, int val)
{
- struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+ struct bt8xxgpio *bg = gpiochip_get_data(gpio);
unsigned long flags;
u32 outen, data;
@@ -140,7 +140,7 @@ static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
unsigned nr, int val)
{
- struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+ struct bt8xxgpio *bg = gpiochip_get_data(gpio);
unsigned long flags;
u32 data;
@@ -217,7 +217,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
bgwrite(0, BT848_GPIO_OUT_EN);
bt8xxgpio_gpio_setup(bg);
- err = gpiochip_add(&bg->gpio);
+ err = gpiochip_add_data(&bg->gpio, bg);
if (err) {
printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
goto err_disable;
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index b6908f1ff1ab..c84f9551f108 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -10,24 +10,23 @@
*/
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/module.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
static int clps711x_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
void __iomem *dat, *dir;
- struct bgpio_chip *bgc;
+ struct gpio_chip *gc;
struct resource *res;
int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id;
if ((id < 0) || (id > 4))
return -ENODEV;
- bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
- if (!bgc)
+ gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -43,11 +42,11 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
switch (id) {
case 3:
/* PORTD is inverted logic for direction register */
- err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+ err = bgpio_init(gc, &pdev->dev, 1, dat, NULL, NULL,
NULL, dir, 0);
break;
default:
- err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+ err = bgpio_init(gc, &pdev->dev, 1, dat, NULL, NULL,
dir, NULL, 0);
break;
}
@@ -58,24 +57,25 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
switch (id) {
case 4:
/* PORTE is 3 lines only */
- bgc->gc.ngpio = 3;
+ gc->ngpio = 3;
break;
default:
break;
}
- bgc->gc.base = id * 8;
- bgc->gc.owner = THIS_MODULE;
- platform_set_drvdata(pdev, bgc);
+ gc->base = id * 8;
+ gc->owner = THIS_MODULE;
+ platform_set_drvdata(pdev, gc);
- return gpiochip_add(&bgc->gc);
+ return gpiochip_add_data(gc, NULL);
}
static int clps711x_gpio_remove(struct platform_device *pdev)
{
- struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+ struct gpio_chip *gc = platform_get_drvdata(pdev);
- return bgpio_remove(bgc);
+ gpiochip_remove(gc);
+ return 0;
}
static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = {
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index fddd204dc9b6..7865ef0d3352 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -86,11 +86,6 @@ struct crystalcove_gpio {
bool set_irq_mask;
};
-static inline struct crystalcove_gpio *to_cg(struct gpio_chip *gc)
-{
- return container_of(gc, struct crystalcove_gpio, chip);
-}
-
static inline int to_reg(int gpio, enum ctrl_register reg_type)
{
int reg;
@@ -134,7 +129,7 @@ static void crystalcove_update_irq_ctrl(struct crystalcove_gpio *cg, int gpio)
static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
{
- struct crystalcove_gpio *cg = to_cg(chip);
+ struct crystalcove_gpio *cg = gpiochip_get_data(chip);
if (gpio > CRYSTALCOVE_VGPIO_NUM)
return 0;
@@ -146,7 +141,7 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct crystalcove_gpio *cg = to_cg(chip);
+ struct crystalcove_gpio *cg = gpiochip_get_data(chip);
if (gpio > CRYSTALCOVE_VGPIO_NUM)
return 0;
@@ -157,7 +152,7 @@ static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
- struct crystalcove_gpio *cg = to_cg(chip);
+ struct crystalcove_gpio *cg = gpiochip_get_data(chip);
int ret;
unsigned int val;
@@ -174,7 +169,7 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
static void crystalcove_gpio_set(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct crystalcove_gpio *cg = to_cg(chip);
+ struct crystalcove_gpio *cg = gpiochip_get_data(chip);
if (gpio > CRYSTALCOVE_VGPIO_NUM)
return;
@@ -187,7 +182,8 @@ static void crystalcove_gpio_set(struct gpio_chip *chip,
static int crystalcove_irq_type(struct irq_data *data, unsigned type)
{
- struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg =
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
switch (type) {
case IRQ_TYPE_NONE:
@@ -213,14 +209,16 @@ static int crystalcove_irq_type(struct irq_data *data, unsigned type)
static void crystalcove_bus_lock(struct irq_data *data)
{
- struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg =
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
mutex_lock(&cg->buslock);
}
static void crystalcove_bus_sync_unlock(struct irq_data *data)
{
- struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg =
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
int gpio = data->hwirq;
if (cg->update & UPDATE_IRQ_TYPE)
@@ -234,7 +232,8 @@ static void crystalcove_bus_sync_unlock(struct irq_data *data)
static void crystalcove_irq_unmask(struct irq_data *data)
{
- struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg =
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
cg->set_irq_mask = false;
cg->update |= UPDATE_IRQ_MASK;
@@ -242,7 +241,8 @@ static void crystalcove_irq_unmask(struct irq_data *data)
static void crystalcove_irq_mask(struct irq_data *data)
{
- struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg =
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
cg->set_irq_mask = true;
cg->update |= UPDATE_IRQ_MASK;
@@ -288,7 +288,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
static void crystalcove_gpio_dbg_show(struct seq_file *s,
struct gpio_chip *chip)
{
- struct crystalcove_gpio *cg = to_cg(chip);
+ struct crystalcove_gpio *cg = gpiochip_get_data(chip);
int gpio, offset;
unsigned int ctlo, ctli, mirqs0, mirqsx, irq;
@@ -341,11 +341,11 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
cg->chip.base = -1;
cg->chip.ngpio = CRYSTALCOVE_VGPIO_NUM;
cg->chip.can_sleep = true;
- cg->chip.dev = dev;
+ cg->chip.parent = dev;
cg->chip.dbg_show = crystalcove_gpio_dbg_show;
cg->regmap = pmic->regmap;
- retval = gpiochip_add(&cg->chip);
+ retval = gpiochip_add_data(&cg->chip, cg);
if (retval) {
dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
return retval;
diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c
index 7b0b198a563d..eccb712e09fb 100644
--- a/drivers/gpio/gpio-cs5535.c
+++ b/drivers/gpio/gpio-cs5535.c
@@ -42,6 +42,10 @@ static ulong mask = GPIO_DEFAULT_MASK;
module_param_named(mask, mask, ulong, 0444);
MODULE_PARM_DESC(mask, "GPIO channel mask.");
+/*
+ * FIXME: convert this singleton driver to use the state container
+ * design pattern, see Documentation/driver-model/design-patterns.txt
+ */
static struct cs5535_gpio_chip {
struct gpio_chip chip;
resource_size_t base;
@@ -201,8 +205,7 @@ EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event);
static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
{
- struct cs5535_gpio_chip *chip =
- container_of(c, struct cs5535_gpio_chip, chip);
+ struct cs5535_gpio_chip *chip = gpiochip_get_data(c);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -242,8 +245,7 @@ static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int chip_direction_input(struct gpio_chip *c, unsigned offset)
{
- struct cs5535_gpio_chip *chip =
- container_of(c, struct cs5535_gpio_chip, chip);
+ struct cs5535_gpio_chip *chip = gpiochip_get_data(c);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -256,8 +258,7 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset)
static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
{
- struct cs5535_gpio_chip *chip =
- container_of(c, struct cs5535_gpio_chip, chip);
+ struct cs5535_gpio_chip *chip = gpiochip_get_data(c);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -347,7 +348,7 @@ static int cs5535_gpio_probe(struct platform_device *pdev)
mask_orig, mask);
/* finally, register with the generic GPIO API */
- err = gpiochip_add(&cs5535_gpio_chip.chip);
+ err = gpiochip_add_data(&cs5535_gpio_chip.chip, &cs5535_gpio_chip);
if (err)
goto done;
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c
index 2e9578ec0ca1..f9b3247ad14b 100644
--- a/drivers/gpio/gpio-da9052.c
+++ b/drivers/gpio/gpio-da9052.c
@@ -51,11 +51,6 @@ struct da9052_gpio {
struct gpio_chip gp;
};
-static inline struct da9052_gpio *to_da9052_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct da9052_gpio, gp);
-}
-
static unsigned char da9052_gpio_port_odd(unsigned offset)
{
return offset % 2;
@@ -63,7 +58,7 @@ static unsigned char da9052_gpio_port_odd(unsigned offset)
static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct da9052_gpio *gpio = to_da9052_gpio(gc);
+ struct da9052_gpio *gpio = gpiochip_get_data(gc);
int da9052_port_direction = 0;
int ret;
@@ -89,15 +84,12 @@ static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
DA9052_STATUS_D_REG);
if (ret < 0)
return ret;
- if (ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)))
- return 1;
- else
- return 0;
+ return !!(ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)));
case DA9052_OUTPUT_PUSHPULL:
if (da9052_gpio_port_odd(offset))
- return ret & DA9052_GPIO_ODD_PORT_MODE;
+ return !!(ret & DA9052_GPIO_ODD_PORT_MODE);
else
- return ret & DA9052_GPIO_EVEN_PORT_MODE;
+ return !!(ret & DA9052_GPIO_EVEN_PORT_MODE);
default:
return -EINVAL;
}
@@ -105,7 +97,7 @@ static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
- struct da9052_gpio *gpio = to_da9052_gpio(gc);
+ struct da9052_gpio *gpio = gpiochip_get_data(gc);
int ret;
if (da9052_gpio_port_odd(offset)) {
@@ -131,7 +123,7 @@ static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct da9052_gpio *gpio = to_da9052_gpio(gc);
+ struct da9052_gpio *gpio = gpiochip_get_data(gc);
unsigned char register_value;
int ret;
@@ -157,7 +149,7 @@ static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
static int da9052_gpio_direction_output(struct gpio_chip *gc,
unsigned offset, int value)
{
- struct da9052_gpio *gpio = to_da9052_gpio(gc);
+ struct da9052_gpio *gpio = gpiochip_get_data(gc);
unsigned char register_value;
int ret;
@@ -182,7 +174,7 @@ static int da9052_gpio_direction_output(struct gpio_chip *gc,
static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
{
- struct da9052_gpio *gpio = to_da9052_gpio(gc);
+ struct da9052_gpio *gpio = gpiochip_get_data(gc);
struct da9052 *da9052 = gpio->da9052;
int irq;
@@ -222,7 +214,7 @@ static int da9052_gpio_probe(struct platform_device *pdev)
if (pdata && pdata->gpio_base)
gpio->gp.base = pdata->gpio_base;
- ret = gpiochip_add(&gpio->gp);
+ ret = gpiochip_add_data(&gpio->gp, gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c
index 7227e6ed3cb9..18210fb2cb13 100644
--- a/drivers/gpio/gpio-da9055.c
+++ b/drivers/gpio/gpio-da9055.c
@@ -35,14 +35,9 @@ struct da9055_gpio {
struct gpio_chip gp;
};
-static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct da9055_gpio, gp);
-}
-
static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ struct da9055_gpio *gpio = gpiochip_get_data(gc);
int gpio_direction = 0;
int ret;
@@ -71,7 +66,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
- struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ struct da9055_gpio *gpio = gpiochip_get_data(gc);
da9055_reg_update(gpio->da9055,
DA9055_REG_GPIO_MODE0_2,
@@ -81,7 +76,7 @@ static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ struct da9055_gpio *gpio = gpiochip_get_data(gc);
unsigned char reg_byte;
reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
@@ -97,7 +92,7 @@ static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
static int da9055_gpio_direction_output(struct gpio_chip *gc,
unsigned offset, int value)
{
- struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ struct da9055_gpio *gpio = gpiochip_get_data(gc);
unsigned char reg_byte;
int ret;
@@ -119,7 +114,7 @@ static int da9055_gpio_direction_output(struct gpio_chip *gc,
static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
{
- struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ struct da9055_gpio *gpio = gpiochip_get_data(gc);
struct da9055 *da9055 = gpio->da9055;
return regmap_irq_get_virq(da9055->irq_data,
@@ -156,7 +151,7 @@ static int da9055_gpio_probe(struct platform_device *pdev)
if (pdata && pdata->gpio_base)
gpio->gp.base = pdata->gpio_base;
- ret = gpiochip_add(&gpio->gp);
+ ret = gpiochip_add_data(&gpio->gp, gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
goto err_mem;
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 5e715388803d..ec58f4288649 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -41,9 +41,6 @@ typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
-#define chip2controller(chip) \
- container_of(chip, struct davinci_gpio_controller, chip)
-
static void __iomem *gpio_base;
static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
@@ -82,7 +79,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev);
static inline int __davinci_direction(struct gpio_chip *chip,
unsigned offset, bool out, int value)
{
- struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_controller *d = gpiochip_get_data(chip);
struct davinci_gpio_regs __iomem *g = d->regs;
unsigned long flags;
u32 temp;
@@ -122,10 +119,10 @@ davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
*/
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_controller *d = gpiochip_get_data(chip);
struct davinci_gpio_regs __iomem *g = d->regs;
- return (1 << offset) & readl_relaxed(&g->in_data);
+ return !!((1 << offset) & readl_relaxed(&g->in_data));
}
/*
@@ -134,7 +131,7 @@ static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
static void
davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_controller *d = gpiochip_get_data(chip);
struct davinci_gpio_regs __iomem *g = d->regs;
writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data);
@@ -149,7 +146,7 @@ davinci_gpio_get_pdata(struct platform_device *pdev)
u32 val;
if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
- return pdev->dev.platform_data;
+ return dev_get_platdata(&pdev->dev);
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -179,8 +176,8 @@ static int davinci_gpio_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec,
u32 *flags)
{
- struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev);
- struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev);
+ struct davinci_gpio_controller *chips = dev_get_drvdata(gc->parent);
+ struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->parent);
if (gpiospec->args[0] > pdata->ngpio)
return -EINVAL;
@@ -254,7 +251,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
chips[i].chip.of_gpio_n_cells = 2;
chips[i].chip.of_xlate = davinci_gpio_of_xlate;
- chips[i].chip.dev = dev;
+ chips[i].chip.parent = dev;
chips[i].chip.of_node = dev->of_node;
#endif
spin_lock_init(&chips[i].lock);
@@ -265,7 +262,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips[i].clr_data = &regs->clr_data;
chips[i].in_data = &regs->in_data;
- gpiochip_add(&chips[i].chip);
+ gpiochip_add_data(&chips[i].chip, &chips[i]);
}
platform_set_drvdata(pdev, chips);
@@ -368,7 +365,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
{
- struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_controller *d = gpiochip_get_data(chip);
if (d->irq_domain)
return irq_create_mapping(d->irq_domain, d->chip.base + offset);
@@ -378,7 +375,7 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
{
- struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_controller *d = gpiochip_get_data(chip);
/*
* NOTE: we assume for now that only irqs in the first gpio_chip
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index 6685712c15cf..e11a7d126e74 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -153,7 +153,7 @@ static int dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
static int dln2_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
struct dln2_gpio_pin req = {
.pin = cpu_to_le16(offset),
};
@@ -194,14 +194,14 @@ out_disable:
static void dln2_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_DISABLE, offset);
}
static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
if (test_bit(offset, dln2->output_enabled))
return GPIOF_DIR_OUT;
@@ -211,7 +211,7 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
int dir;
dir = dln2_gpio_get_direction(chip, offset);
@@ -226,7 +226,7 @@ static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
static void dln2_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
dln2_gpio_pin_set_out_val(dln2, offset, value);
}
@@ -234,7 +234,7 @@ static void dln2_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int dln2_gpio_set_direction(struct gpio_chip *chip, unsigned offset,
unsigned dir)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
struct dln2_gpio_pin_val req = {
.pin = cpu_to_le16(offset),
.value = dir,
@@ -262,7 +262,7 @@ static int dln2_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
int ret;
ret = dln2_gpio_pin_set_out_val(dln2, offset, value);
@@ -275,7 +275,7 @@ static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int dln2_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
unsigned debounce)
{
- struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(chip);
__le32 duration = cpu_to_le32(debounce);
return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_SET_DEBOUNCE,
@@ -302,7 +302,7 @@ static int dln2_gpio_set_event_cfg(struct dln2_gpio *dln2, unsigned pin,
static void dln2_irq_unmask(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(gc);
int pin = irqd_to_hwirq(irqd);
set_bit(pin, dln2->unmasked_irqs);
@@ -311,7 +311,7 @@ static void dln2_irq_unmask(struct irq_data *irqd)
static void dln2_irq_mask(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(gc);
int pin = irqd_to_hwirq(irqd);
clear_bit(pin, dln2->unmasked_irqs);
@@ -320,7 +320,7 @@ static void dln2_irq_mask(struct irq_data *irqd)
static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(gc);
int pin = irqd_to_hwirq(irqd);
switch (type) {
@@ -349,7 +349,7 @@ static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
static void dln2_irq_bus_lock(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(gc);
mutex_lock(&dln2->irq_lock);
}
@@ -357,7 +357,7 @@ static void dln2_irq_bus_lock(struct irq_data *irqd)
static void dln2_irq_bus_unlock(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ struct dln2_gpio *dln2 = gpiochip_get_data(gc);
int pin = irqd_to_hwirq(irqd);
int enabled, unmasked;
unsigned type;
@@ -377,7 +377,7 @@ static void dln2_irq_bus_unlock(struct irq_data *irqd)
ret = dln2_gpio_set_event_cfg(dln2, pin, type, 0);
if (ret)
- dev_err(dln2->gpio.dev, "failed to set event\n");
+ dev_err(dln2->gpio.parent, "failed to set event\n");
}
mutex_unlock(&dln2->irq_lock);
@@ -406,19 +406,19 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
if (len < sizeof(*event)) {
- dev_err(dln2->gpio.dev, "short event message\n");
+ dev_err(dln2->gpio.parent, "short event message\n");
return;
}
pin = le16_to_cpu(event->pin);
if (pin >= dln2->gpio.ngpio) {
- dev_err(dln2->gpio.dev, "out of bounds pin %d\n", pin);
+ dev_err(dln2->gpio.parent, "out of bounds pin %d\n", pin);
return;
}
irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
if (!irq) {
- dev_err(dln2->gpio.dev, "pin %d not mapped to IRQ\n", pin);
+ dev_err(dln2->gpio.parent, "pin %d not mapped to IRQ\n", pin);
return;
}
@@ -462,7 +462,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->pdev = pdev;
dln2->gpio.label = "dln2";
- dln2->gpio.dev = dev;
+ dln2->gpio.parent = dev;
dln2->gpio.owner = THIS_MODULE;
dln2->gpio.base = -1;
dln2->gpio.ngpio = pins;
@@ -479,7 +479,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dln2);
- ret = gpiochip_add(&dln2->gpio);
+ ret = gpiochip_add_data(&dln2->gpio, dln2);
if (ret < 0) {
dev_err(dev, "failed to add gpio chip: %d\n", ret);
goto out;
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index fcd5b0acfc72..597de1ef497b 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -7,7 +7,9 @@
*
* All enquiries to support@picochip.com
*/
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: for gpio_get_value(), replace this with direct register read */
+#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -66,7 +68,7 @@ struct dwapb_context {
#endif
struct dwapb_gpio_port {
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
bool is_registered;
struct dwapb_gpio *gpio;
#ifdef CONFIG_PM_SLEEP
@@ -83,33 +85,26 @@ struct dwapb_gpio {
struct irq_domain *domain;
};
-static inline struct dwapb_gpio_port *
-to_dwapb_gpio_port(struct bgpio_chip *bgc)
-{
- return container_of(bgc, struct dwapb_gpio_port, bgc);
-}
-
static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
{
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
void __iomem *reg_base = gpio->regs;
- return bgc->read_reg(reg_base + offset);
+ return gc->read_reg(reg_base + offset);
}
static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
u32 val)
{
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
void __iomem *reg_base = gpio->regs;
- bgc->write_reg(reg_base + offset, val);
+ gc->write_reg(reg_base + offset, val);
}
static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
+ struct dwapb_gpio_port *port = gpiochip_get_data(gc);
struct dwapb_gpio *gpio = port->gpio;
return irq_find_mapping(gpio->domain, offset);
@@ -119,7 +114,7 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
{
u32 v = dwapb_read(gpio, GPIO_INT_POLARITY);
- if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
+ if (gpio_get_value(gpio->ports[0].gc.base + offs))
v &= ~BIT(offs);
else
v |= BIT(offs);
@@ -162,39 +157,39 @@ static void dwapb_irq_enable(struct irq_data *d)
{
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = igc->private;
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
u32 val;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
val = dwapb_read(gpio, GPIO_INTEN);
val |= BIT(d->hwirq);
dwapb_write(gpio, GPIO_INTEN, val);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void dwapb_irq_disable(struct irq_data *d)
{
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = igc->private;
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
u32 val;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
val = dwapb_read(gpio, GPIO_INTEN);
val &= ~BIT(d->hwirq);
dwapb_write(gpio, GPIO_INTEN, val);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int dwapb_irq_reqres(struct irq_data *d)
{
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = igc->private;
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
- if (gpiochip_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) {
+ if (gpiochip_lock_as_irq(gc, irqd_to_hwirq(d))) {
dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
return -EINVAL;
@@ -206,16 +201,16 @@ static void dwapb_irq_relres(struct irq_data *d)
{
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = igc->private;
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
- gpiochip_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d));
+ gpiochip_unlock_as_irq(gc, irqd_to_hwirq(d));
}
static int dwapb_irq_set_type(struct irq_data *d, u32 type)
{
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = igc->private;
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
int bit = d->hwirq;
unsigned long level, polarity, flags;
@@ -223,7 +218,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
return -EINVAL;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
@@ -254,7 +249,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -262,13 +257,12 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
unsigned offset, unsigned debounce)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
+ struct dwapb_gpio_port *port = gpiochip_get_data(gc);
struct dwapb_gpio *gpio = port->gpio;
unsigned long flags, val_deb;
- unsigned long mask = bgc->pin2mask(bgc, offset);
+ unsigned long mask = gc->pin2mask(gc, offset);
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
if (debounce)
@@ -276,7 +270,7 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
else
dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -295,7 +289,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
struct dwapb_gpio_port *port,
struct dwapb_port_property *pp)
{
- struct gpio_chip *gc = &port->bgc.gc;
+ struct gpio_chip *gc = &port->gc;
struct device_node *node = pp->node;
struct irq_chip_generic *irq_gc = NULL;
unsigned int hwirq, ngpio = gc->ngpio;
@@ -369,13 +363,13 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
irq_create_mapping(gpio->domain, hwirq);
- port->bgc.gc.to_irq = dwapb_gpio_to_irq;
+ port->gc.to_irq = dwapb_gpio_to_irq;
}
static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
{
struct dwapb_gpio_port *port = &gpio->ports[0];
- struct gpio_chip *gc = &port->bgc.gc;
+ struct gpio_chip *gc = &port->gc;
unsigned int ngpio = gc->ngpio;
irq_hw_number_t hwirq;
@@ -412,7 +406,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
dirout = gpio->regs + GPIO_SWPORTA_DDR +
(pp->idx * GPIO_SWPORT_DDR_SIZE);
- err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
+ err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
NULL, false);
if (err) {
dev_err(gpio->dev, "failed to init gpio chip for %s\n",
@@ -421,19 +415,19 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
}
#ifdef CONFIG_OF_GPIO
- port->bgc.gc.of_node = pp->node;
+ port->gc.of_node = pp->node;
#endif
- port->bgc.gc.ngpio = pp->ngpio;
- port->bgc.gc.base = pp->gpio_base;
+ port->gc.ngpio = pp->ngpio;
+ port->gc.base = pp->gpio_base;
/* Only port A support debounce */
if (pp->idx == 0)
- port->bgc.gc.set_debounce = dwapb_gpio_set_debounce;
+ port->gc.set_debounce = dwapb_gpio_set_debounce;
if (pp->irq)
dwapb_configure_irqs(gpio, port, pp);
- err = gpiochip_add(&port->bgc.gc);
+ err = gpiochip_add_data(&port->gc, port);
if (err)
dev_err(gpio->dev, "failed to register gpiochip for %s\n",
pp->name);
@@ -449,7 +443,7 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
for (m = 0; m < gpio->nr_ports; ++m)
if (gpio->ports[m].is_registered)
- gpiochip_remove(&gpio->ports[m].bgc.gc);
+ gpiochip_remove(&gpio->ports[m].gc);
}
static struct dwapb_platform_data *
@@ -591,11 +585,11 @@ static int dwapb_gpio_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
int i;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
for (i = 0; i < gpio->nr_ports; i++) {
unsigned int offset;
unsigned int idx = gpio->ports[i].idx;
@@ -624,7 +618,7 @@ static int dwapb_gpio_suspend(struct device *dev)
dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
}
}
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -633,11 +627,11 @@ static int dwapb_gpio_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
- struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
int i;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
for (i = 0; i < gpio->nr_ports; i++) {
unsigned int offset;
unsigned int idx = gpio->ports[i].idx;
@@ -666,7 +660,7 @@ static int dwapb_gpio_resume(struct device *dev)
dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
}
}
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 6bca1e125e12..8d32ccc980d9 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -103,7 +103,7 @@ static int em_gio_irq_reqres(struct irq_data *d)
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
if (gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) {
- dev_err(p->gpio_chip.dev,
+ dev_err(p->gpio_chip.parent,
"unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
return -EINVAL;
@@ -192,7 +192,7 @@ static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
{
- return container_of(chip, struct em_gio_priv, gpio_chip);
+ return gpiochip_get_data(chip);
}
static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -203,7 +203,7 @@ static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
static int em_gio_get(struct gpio_chip *chip, unsigned offset)
{
- return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
+ return !!(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
}
static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
@@ -332,7 +332,7 @@ static int em_gio_probe(struct platform_device *pdev)
gpio_chip->request = em_gio_request;
gpio_chip->free = em_gio_free;
gpio_chip->label = name;
- gpio_chip->dev = &pdev->dev;
+ gpio_chip->parent = &pdev->dev;
gpio_chip->owner = THIS_MODULE;
gpio_chip->base = -1;
gpio_chip->ngpio = ngpios;
@@ -368,7 +368,7 @@ static int em_gio_probe(struct platform_device *pdev)
goto err1;
}
- ret = gpiochip_add(gpio_chip);
+ ret = gpiochip_add_data(gpio_chip, p);
if (ret) {
dev_err(&pdev->dev, "failed to add GPIO controller\n");
goto err1;
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 3e3947b35c83..ad279078fed7 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -16,10 +16,11 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/slab.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: this is here for gpio_to_irq() - get rid of this! */
+#include <linux/gpio.h>
#include <mach/hardware.h>
#include <mach/gpio-ep93xx.h>
@@ -28,7 +29,7 @@
struct ep93xx_gpio {
void __iomem *mmio_base;
- struct bgpio_chip bgc[8];
+ struct gpio_chip gc[8];
};
/*************************************************************************
@@ -319,26 +320,26 @@ static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return 64 + gpio;
}
-static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
+static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
void __iomem *mmio_base, struct ep93xx_gpio_bank *bank)
{
void __iomem *data = mmio_base + bank->data;
void __iomem *dir = mmio_base + bank->dir;
int err;
- err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, 0);
+ err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
if (err)
return err;
- bgc->gc.label = bank->label;
- bgc->gc.base = bank->base;
+ gc->label = bank->label;
+ gc->base = bank->base;
if (bank->has_debounce) {
- bgc->gc.set_debounce = ep93xx_gpio_set_debounce;
- bgc->gc.to_irq = ep93xx_gpio_to_irq;
+ gc->set_debounce = ep93xx_gpio_set_debounce;
+ gc->to_irq = ep93xx_gpio_to_irq;
}
- return gpiochip_add(&bgc->gc);
+ return gpiochip_add_data(gc, NULL);
}
static int ep93xx_gpio_probe(struct platform_device *pdev)
@@ -358,10 +359,10 @@ static int ep93xx_gpio_probe(struct platform_device *pdev)
return PTR_ERR(ep93xx_gpio->mmio_base);
for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
- struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i];
+ struct gpio_chip *gc = &ep93xx_gpio->gc[i];
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
- if (ep93xx_gpio_add_bank(bgc, &pdev->dev,
+ if (ep93xx_gpio_add_bank(gc, &pdev->dev,
ep93xx_gpio->mmio_base, bank))
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
bank->label);
diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c
index 5c15dd12172d..00b022c9acb3 100644
--- a/drivers/gpio/gpio-etraxfs.c
+++ b/drivers/gpio/gpio-etraxfs.c
@@ -1,12 +1,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/basic_mmio_gpio.h>
#define ETRAX_FS_rw_pa_dout 0
#define ETRAX_FS_r_pa_din 4
@@ -67,7 +65,7 @@ struct etraxfs_gpio_block {
};
struct etraxfs_gpio_chip {
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
struct etraxfs_gpio_block *block;
};
@@ -176,11 +174,6 @@ static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = {
.rw_intr_pins = ARTPEC3_rw_intr_pins,
};
-static struct etraxfs_gpio_chip *to_etraxfs(struct gpio_chip *gc)
-{
- return container_of(gc, struct etraxfs_gpio_chip, bgc.gc);
-}
-
static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc)
{
return gc->label[0] - 'A';
@@ -220,13 +213,13 @@ static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio)
static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
unsigned int gpio)
{
- return 4 * etraxfs_gpio_chip_to_port(&chip->bgc.gc) + gpio / 8;
+ return 4 * etraxfs_gpio_chip_to_port(&chip->gc) + gpio / 8;
}
static void etraxfs_gpio_irq_ack(struct irq_data *d)
{
struct etraxfs_gpio_chip *chip =
- to_etraxfs(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
struct etraxfs_gpio_block *block = chip->block;
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
@@ -236,7 +229,7 @@ static void etraxfs_gpio_irq_ack(struct irq_data *d)
static void etraxfs_gpio_irq_mask(struct irq_data *d)
{
struct etraxfs_gpio_chip *chip =
- to_etraxfs(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
struct etraxfs_gpio_block *block = chip->block;
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
@@ -249,7 +242,7 @@ static void etraxfs_gpio_irq_mask(struct irq_data *d)
static void etraxfs_gpio_irq_unmask(struct irq_data *d)
{
struct etraxfs_gpio_chip *chip =
- to_etraxfs(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
struct etraxfs_gpio_block *block = chip->block;
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
@@ -262,7 +255,7 @@ static void etraxfs_gpio_irq_unmask(struct irq_data *d)
static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
{
struct etraxfs_gpio_chip *chip =
- to_etraxfs(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
struct etraxfs_gpio_block *block = chip->block;
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
u32 cfg;
@@ -299,7 +292,7 @@ static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
{
struct etraxfs_gpio_chip *chip =
- to_etraxfs(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
struct etraxfs_gpio_block *block = chip->block;
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
int ret = -EBUSY;
@@ -308,7 +301,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
if (block->group[grpirq])
goto out;
- ret = gpiochip_lock_as_irq(&chip->bgc.gc, d->hwirq);
+ ret = gpiochip_lock_as_irq(&chip->gc, d->hwirq);
if (ret)
goto out;
@@ -330,13 +323,13 @@ out:
static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
{
struct etraxfs_gpio_chip *chip =
- to_etraxfs(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
struct etraxfs_gpio_block *block = chip->block;
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
spin_lock(&block->lock);
block->group[grpirq] = 0;
- gpiochip_unlock_as_irq(&chip->bgc.gc, d->hwirq);
+ gpiochip_unlock_as_irq(&chip->gc, d->hwirq);
spin_unlock(&block->lock);
}
@@ -419,7 +412,7 @@ static int etraxfs_gpio_probe(struct platform_device *pdev)
for (i = 0; i < info->num_ports; i++) {
struct etraxfs_gpio_chip *chip = &chips[i];
- struct bgpio_chip *bgc = &chip->bgc;
+ struct gpio_chip *gc = &chip->gc;
const struct etraxfs_gpio_port *port = &info->ports[i];
unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET;
void __iomem *dat = regs + port->din;
@@ -433,7 +426,7 @@ static int etraxfs_gpio_probe(struct platform_device *pdev)
flags = BGPIOF_NO_OUTPUT;
}
- ret = bgpio_init(bgc, dev, 4,
+ ret = bgpio_init(gc, dev, 4,
dat, set, NULL, dirout, NULL,
flags);
if (ret) {
@@ -442,28 +435,28 @@ static int etraxfs_gpio_probe(struct platform_device *pdev)
continue;
}
- bgc->gc.ngpio = port->ngpio;
- bgc->gc.label = port->label;
+ gc->ngpio = port->ngpio;
+ gc->label = port->label;
- bgc->gc.of_node = dev->of_node;
- bgc->gc.of_gpio_n_cells = 3;
- bgc->gc.of_xlate = etraxfs_gpio_of_xlate;
+ gc->of_node = dev->of_node;
+ gc->of_gpio_n_cells = 3;
+ gc->of_xlate = etraxfs_gpio_of_xlate;
- ret = gpiochip_add(&bgc->gc);
+ ret = gpiochip_add_data(gc, chip);
if (ret) {
dev_err(dev, "Unable to register port %s\n",
- bgc->gc.label);
+ gc->label);
continue;
}
if (i > 0 && !allportsirq)
continue;
- ret = gpiochip_irqchip_add(&bgc->gc, &etraxfs_gpio_irq_chip, 0,
+ ret = gpiochip_irqchip_add(gc, &etraxfs_gpio_irq_chip, 0,
handle_level_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "Unable to add irqchip to port %s\n",
- bgc->gc.label);
+ gc->label);
}
}
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index 5e3c4fa67d82..d62fd6bbaf82 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -193,8 +193,7 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = {
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
int err;
- struct f7188x_gpio_bank *bank =
- container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
struct f7188x_sio *sio = bank->data->sio;
u8 dir;
@@ -215,8 +214,7 @@ static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
int err;
- struct f7188x_gpio_bank *bank =
- container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
struct f7188x_sio *sio = bank->data->sio;
u8 dir, data;
@@ -241,8 +239,7 @@ static int f7188x_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
int err;
- struct f7188x_gpio_bank *bank =
- container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
struct f7188x_sio *sio = bank->data->sio;
u8 dir, data_out;
@@ -270,8 +267,7 @@ static int f7188x_gpio_direction_out(struct gpio_chip *chip,
static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
int err;
- struct f7188x_gpio_bank *bank =
- container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
struct f7188x_sio *sio = bank->data->sio;
u8 data_out;
@@ -298,7 +294,7 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
{
int err;
int i;
- struct f7188x_sio *sio = pdev->dev.platform_data;
+ struct f7188x_sio *sio = dev_get_platdata(&pdev->dev);
struct f7188x_gpio_data *data;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
@@ -333,10 +329,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
for (i = 0; i < data->nr_bank; i++) {
struct f7188x_gpio_bank *bank = &data->bank[i];
- bank->chip.dev = &pdev->dev;
+ bank->chip.parent = &pdev->dev;
bank->data = data;
- err = gpiochip_add(&bank->chip);
+ err = gpiochip_add_data(&bank->chip, bank);
if (err) {
dev_err(&pdev->dev,
"Failed to register gpiochip %d: %d\n",
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index f9ac3f351753..cbbec838a9d1 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -24,7 +24,7 @@
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/module.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#define GEF_GPIO_DIRECT 0x00
#define GEF_GPIO_IN 0x04
@@ -55,19 +55,19 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(gef_gpio_ids, &pdev->dev);
- struct bgpio_chip *bgc;
+ struct gpio_chip *gc;
void __iomem *regs;
int ret;
- bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
- if (!bgc)
+ gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
return -ENOMEM;
regs = of_iomap(pdev->dev.of_node, 0);
if (!regs)
return -ENOMEM;
- ret = bgpio_init(bgc, &pdev->dev, 4, regs + GEF_GPIO_IN,
+ ret = bgpio_init(gc, &pdev->dev, 4, regs + GEF_GPIO_IN,
regs + GEF_GPIO_OUT, NULL, NULL,
regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret) {
@@ -76,20 +76,20 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
}
/* Setup pointers to chip functions */
- bgc->gc.label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name,
+ gc->label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name,
GFP_KERNEL);
- if (!bgc->gc.label) {
+ if (!gc->label) {
ret = -ENOMEM;
goto err0;
}
- bgc->gc.base = -1;
- bgc->gc.ngpio = (u16)(uintptr_t)of_id->data;
- bgc->gc.of_gpio_n_cells = 2;
- bgc->gc.of_node = pdev->dev.of_node;
+ gc->base = -1;
+ gc->ngpio = (u16)(uintptr_t)of_id->data;
+ gc->of_gpio_n_cells = 2;
+ gc->of_node = pdev->dev.of_node;
/* This function adds a memory mapped GPIO chip */
- ret = gpiochip_add(&bgc->gc);
+ ret = gpiochip_add_data(gc, NULL);
if (ret)
goto err0;
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 88ae70ddb127..2a4f2333a50b 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -56,11 +56,11 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/log2.h>
#include <linux/ioport.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
+#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
-#include <linux/basic_mmio_gpio.h>
static void bgpio_write8(void __iomem *reg, unsigned long data)
{
@@ -124,33 +124,30 @@ static unsigned long bgpio_read32be(void __iomem *reg)
return ioread32be(reg);
}
-static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
+static unsigned long bgpio_pin2mask(struct gpio_chip *gc, unsigned int pin)
{
- return 1 << pin;
+ return BIT(pin);
}
-static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
+static unsigned long bgpio_pin2mask_be(struct gpio_chip *gc,
unsigned int pin)
{
- return 1 << (bgc->bits - 1 - pin);
+ return BIT(gc->bgpio_bits - 1 - pin);
}
static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned long pinmask = bgc->pin2mask(bgc, gpio);
+ unsigned long pinmask = gc->pin2mask(gc, gpio);
- if (bgc->dir & pinmask)
- return !!(bgc->read_reg(bgc->reg_set) & pinmask);
+ if (gc->bgpio_dir & pinmask)
+ return !!(gc->read_reg(gc->reg_set) & pinmask);
else
- return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
+ return !!(gc->read_reg(gc->reg_dat) & pinmask);
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
+ return !!(gc->read_reg(gc->reg_dat) & gc->pin2mask(gc, gpio));
}
static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -159,53 +156,50 @@ static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned long mask = bgc->pin2mask(bgc, gpio);
+ unsigned long mask = gc->pin2mask(gc, gpio);
unsigned long flags;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
if (val)
- bgc->data |= mask;
+ gc->bgpio_data |= mask;
else
- bgc->data &= ~mask;
+ gc->bgpio_data &= ~mask;
- bgc->write_reg(bgc->reg_dat, bgc->data);
+ gc->write_reg(gc->reg_dat, gc->bgpio_data);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
int val)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned long mask = bgc->pin2mask(bgc, gpio);
+ unsigned long mask = gc->pin2mask(gc, gpio);
if (val)
- bgc->write_reg(bgc->reg_set, mask);
+ gc->write_reg(gc->reg_set, mask);
else
- bgc->write_reg(bgc->reg_clr, mask);
+ gc->write_reg(gc->reg_clr, mask);
}
static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned long mask = bgc->pin2mask(bgc, gpio);
+ unsigned long mask = gc->pin2mask(gc, gpio);
unsigned long flags;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
if (val)
- bgc->data |= mask;
+ gc->bgpio_data |= mask;
else
- bgc->data &= ~mask;
+ gc->bgpio_data &= ~mask;
- bgc->write_reg(bgc->reg_set, bgc->data);
+ gc->write_reg(gc->reg_set, gc->bgpio_data);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
-static void bgpio_multiple_get_masks(struct bgpio_chip *bgc,
+static void bgpio_multiple_get_masks(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits,
unsigned long *set_mask,
unsigned long *clear_mask)
@@ -215,19 +209,19 @@ static void bgpio_multiple_get_masks(struct bgpio_chip *bgc,
*set_mask = 0;
*clear_mask = 0;
- for (i = 0; i < bgc->bits; i++) {
+ for (i = 0; i < gc->bgpio_bits; i++) {
if (*mask == 0)
break;
if (__test_and_clear_bit(i, mask)) {
if (test_bit(i, bits))
- *set_mask |= bgc->pin2mask(bgc, i);
+ *set_mask |= gc->pin2mask(gc, i);
else
- *clear_mask |= bgc->pin2mask(bgc, i);
+ *clear_mask |= gc->pin2mask(gc, i);
}
}
}
-static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc,
+static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
unsigned long *mask,
unsigned long *bits,
void __iomem *reg)
@@ -235,47 +229,42 @@ static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc,
unsigned long flags;
unsigned long set_mask, clear_mask;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
- bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
+ bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
- bgc->data |= set_mask;
- bgc->data &= ~clear_mask;
+ gc->bgpio_data |= set_mask;
+ gc->bgpio_data &= ~clear_mask;
- bgc->write_reg(reg, bgc->data);
+ gc->write_reg(reg, gc->bgpio_data);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat);
+ bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_dat);
}
static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set);
+ bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_set);
}
static void bgpio_set_multiple_with_clear(struct gpio_chip *gc,
unsigned long *mask,
unsigned long *bits)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long set_mask, clear_mask;
- bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
+ bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
if (set_mask)
- bgc->write_reg(bgc->reg_set, set_mask);
+ gc->write_reg(gc->reg_set, set_mask);
if (clear_mask)
- bgc->write_reg(bgc->reg_clr, clear_mask);
+ gc->write_reg(gc->reg_clr, clear_mask);
}
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
@@ -299,111 +288,103 @@ static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
- bgc->dir &= ~bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
+ gc->write_reg(gc->reg_dir, gc->bgpio_dir);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ?
- GPIOF_DIR_OUT : GPIOF_DIR_IN;
+ /* Return 0 if output, 1 of input */
+ return !(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
}
static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
gc->set(gc, gpio, val);
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
- bgc->dir |= bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ gc->bgpio_dir |= gc->pin2mask(gc, gpio);
+ gc->write_reg(gc->reg_dir, gc->bgpio_dir);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
- bgc->dir |= bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ gc->bgpio_dir |= gc->pin2mask(gc, gpio);
+ gc->write_reg(gc->reg_dir, gc->bgpio_dir);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
gc->set(gc, gpio, val);
- spin_lock_irqsave(&bgc->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
- bgc->dir &= ~bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
+ gc->write_reg(gc->reg_dir, gc->bgpio_dir);
- spin_unlock_irqrestore(&bgc->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ?
- GPIOF_DIR_IN : GPIOF_DIR_OUT;
+ /* Return 0 if output, 1 if input */
+ return !!(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
}
static int bgpio_setup_accessors(struct device *dev,
- struct bgpio_chip *bgc,
+ struct gpio_chip *gc,
bool bit_be,
bool byte_be)
{
- switch (bgc->bits) {
+ switch (gc->bgpio_bits) {
case 8:
- bgc->read_reg = bgpio_read8;
- bgc->write_reg = bgpio_write8;
+ gc->read_reg = bgpio_read8;
+ gc->write_reg = bgpio_write8;
break;
case 16:
if (byte_be) {
- bgc->read_reg = bgpio_read16be;
- bgc->write_reg = bgpio_write16be;
+ gc->read_reg = bgpio_read16be;
+ gc->write_reg = bgpio_write16be;
} else {
- bgc->read_reg = bgpio_read16;
- bgc->write_reg = bgpio_write16;
+ gc->read_reg = bgpio_read16;
+ gc->write_reg = bgpio_write16;
}
break;
case 32:
if (byte_be) {
- bgc->read_reg = bgpio_read32be;
- bgc->write_reg = bgpio_write32be;
+ gc->read_reg = bgpio_read32be;
+ gc->write_reg = bgpio_write32be;
} else {
- bgc->read_reg = bgpio_read32;
- bgc->write_reg = bgpio_write32;
+ gc->read_reg = bgpio_read32;
+ gc->write_reg = bgpio_write32;
}
break;
#if BITS_PER_LONG >= 64
@@ -413,17 +394,17 @@ static int bgpio_setup_accessors(struct device *dev,
"64 bit big endian byte order unsupported\n");
return -EINVAL;
} else {
- bgc->read_reg = bgpio_read64;
- bgc->write_reg = bgpio_write64;
+ gc->read_reg = bgpio_read64;
+ gc->write_reg = bgpio_write64;
}
break;
#endif /* BITS_PER_LONG >= 64 */
default:
- dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
+ dev_err(dev, "unsupported data width %u bits\n", gc->bgpio_bits);
return -EINVAL;
}
- bgc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
+ gc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
return 0;
}
@@ -450,44 +431,44 @@ static int bgpio_setup_accessors(struct device *dev,
* - an input direction register (named "dirin") where a 1 bit indicates
* the GPIO is an input.
*/
-static int bgpio_setup_io(struct bgpio_chip *bgc,
+static int bgpio_setup_io(struct gpio_chip *gc,
void __iomem *dat,
void __iomem *set,
void __iomem *clr,
unsigned long flags)
{
- bgc->reg_dat = dat;
- if (!bgc->reg_dat)
+ gc->reg_dat = dat;
+ if (!gc->reg_dat)
return -EINVAL;
if (set && clr) {
- bgc->reg_set = set;
- bgc->reg_clr = clr;
- bgc->gc.set = bgpio_set_with_clear;
- bgc->gc.set_multiple = bgpio_set_multiple_with_clear;
+ gc->reg_set = set;
+ gc->reg_clr = clr;
+ gc->set = bgpio_set_with_clear;
+ gc->set_multiple = bgpio_set_multiple_with_clear;
} else if (set && !clr) {
- bgc->reg_set = set;
- bgc->gc.set = bgpio_set_set;
- bgc->gc.set_multiple = bgpio_set_multiple_set;
+ gc->reg_set = set;
+ gc->set = bgpio_set_set;
+ gc->set_multiple = bgpio_set_multiple_set;
} else if (flags & BGPIOF_NO_OUTPUT) {
- bgc->gc.set = bgpio_set_none;
- bgc->gc.set_multiple = NULL;
+ gc->set = bgpio_set_none;
+ gc->set_multiple = NULL;
} else {
- bgc->gc.set = bgpio_set;
- bgc->gc.set_multiple = bgpio_set_multiple;
+ gc->set = bgpio_set;
+ gc->set_multiple = bgpio_set_multiple;
}
if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
(flags & BGPIOF_READ_OUTPUT_REG_SET))
- bgc->gc.get = bgpio_get_set;
+ gc->get = bgpio_get_set;
else
- bgc->gc.get = bgpio_get;
+ gc->get = bgpio_get;
return 0;
}
-static int bgpio_setup_direction(struct bgpio_chip *bgc,
+static int bgpio_setup_direction(struct gpio_chip *gc,
void __iomem *dirout,
void __iomem *dirin,
unsigned long flags)
@@ -495,21 +476,21 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
if (dirout && dirin) {
return -EINVAL;
} else if (dirout) {
- bgc->reg_dir = dirout;
- bgc->gc.direction_output = bgpio_dir_out;
- bgc->gc.direction_input = bgpio_dir_in;
- bgc->gc.get_direction = bgpio_get_dir;
+ gc->reg_dir = dirout;
+ gc->direction_output = bgpio_dir_out;
+ gc->direction_input = bgpio_dir_in;
+ gc->get_direction = bgpio_get_dir;
} else if (dirin) {
- bgc->reg_dir = dirin;
- bgc->gc.direction_output = bgpio_dir_out_inv;
- bgc->gc.direction_input = bgpio_dir_in_inv;
- bgc->gc.get_direction = bgpio_get_dir_inv;
+ gc->reg_dir = dirin;
+ gc->direction_output = bgpio_dir_out_inv;
+ gc->direction_input = bgpio_dir_in_inv;
+ gc->get_direction = bgpio_get_dir_inv;
} else {
if (flags & BGPIOF_NO_OUTPUT)
- bgc->gc.direction_output = bgpio_dir_out_err;
+ gc->direction_output = bgpio_dir_out_err;
else
- bgc->gc.direction_output = bgpio_simple_dir_out;
- bgc->gc.direction_input = bgpio_simple_dir_in;
+ gc->direction_output = bgpio_simple_dir_out;
+ gc->direction_input = bgpio_simple_dir_in;
}
return 0;
@@ -523,14 +504,7 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
return -EINVAL;
}
-int bgpio_remove(struct bgpio_chip *bgc)
-{
- gpiochip_remove(&bgc->gc);
- return 0;
-}
-EXPORT_SYMBOL_GPL(bgpio_remove);
-
-int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
+int bgpio_init(struct gpio_chip *gc, struct device *dev,
unsigned long sz, void __iomem *dat, void __iomem *set,
void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
unsigned long flags)
@@ -540,36 +514,36 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
if (!is_power_of_2(sz))
return -EINVAL;
- bgc->bits = sz * 8;
- if (bgc->bits > BITS_PER_LONG)
+ gc->bgpio_bits = sz * 8;
+ if (gc->bgpio_bits > BITS_PER_LONG)
return -EINVAL;
- spin_lock_init(&bgc->lock);
- bgc->gc.dev = dev;
- bgc->gc.label = dev_name(dev);
- bgc->gc.base = -1;
- bgc->gc.ngpio = bgc->bits;
- bgc->gc.request = bgpio_request;
+ spin_lock_init(&gc->bgpio_lock);
+ gc->parent = dev;
+ gc->label = dev_name(dev);
+ gc->base = -1;
+ gc->ngpio = gc->bgpio_bits;
+ gc->request = bgpio_request;
- ret = bgpio_setup_io(bgc, dat, set, clr, flags);
+ ret = bgpio_setup_io(gc, dat, set, clr, flags);
if (ret)
return ret;
- ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN,
+ ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN,
flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
return ret;
- ret = bgpio_setup_direction(bgc, dirout, dirin, flags);
+ ret = bgpio_setup_direction(gc, dirout, dirin, flags);
if (ret)
return ret;
- bgc->data = bgc->read_reg(bgc->reg_dat);
- if (bgc->gc.set == bgpio_set_set &&
+ gc->bgpio_data = gc->read_reg(gc->reg_dat);
+ if (gc->set == bgpio_set_set &&
!(flags & BGPIOF_UNREADABLE_REG_SET))
- bgc->data = bgc->read_reg(bgc->reg_set);
- if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
- bgc->dir = bgc->read_reg(bgc->reg_dir);
+ gc->bgpio_data = gc->read_reg(gc->reg_set);
+ if (gc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
+ gc->bgpio_dir = gc->read_reg(gc->reg_dir);
return ret;
}
@@ -607,7 +581,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
unsigned long sz;
unsigned long flags = pdev->id_entry->driver_data;
int err;
- struct bgpio_chip *bgc;
+ struct gpio_chip *gc;
struct bgpio_pdata *pdata = dev_get_platdata(dev);
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
@@ -636,32 +610,33 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
if (IS_ERR(dirin))
return PTR_ERR(dirin);
- bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
- if (!bgc)
+ gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
return -ENOMEM;
- err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, flags);
+ err = bgpio_init(gc, dev, sz, dat, set, clr, dirout, dirin, flags);
if (err)
return err;
if (pdata) {
if (pdata->label)
- bgc->gc.label = pdata->label;
- bgc->gc.base = pdata->base;
+ gc->label = pdata->label;
+ gc->base = pdata->base;
if (pdata->ngpio > 0)
- bgc->gc.ngpio = pdata->ngpio;
+ gc->ngpio = pdata->ngpio;
}
- platform_set_drvdata(pdev, bgc);
+ platform_set_drvdata(pdev, gc);
- return gpiochip_add(&bgc->gc);
+ return gpiochip_add_data(gc, NULL);
}
static int bgpio_pdev_remove(struct platform_device *pdev)
{
- struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+ struct gpio_chip *gc = platform_get_drvdata(pdev);
- return bgpio_remove(bgc);
+ gpiochip_remove(gc);
+ return 0;
}
static const struct platform_device_id bgpio_id_table[] = {
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 801423fe8143..7847dd34f86f 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -31,7 +31,7 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
@@ -63,7 +63,7 @@ struct grgpio_lirq {
};
struct grgpio_priv {
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
void __iomem *regs;
struct device *dev;
@@ -92,29 +92,22 @@ struct grgpio_priv {
struct grgpio_lirq lirqs[GRGPIO_MAX_NGPIO];
};
-static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc)
-{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- return container_of(bgc, struct grgpio_priv, bgc);
-}
-
static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
int val)
{
- struct bgpio_chip *bgc = &priv->bgc;
- unsigned long mask = bgc->pin2mask(bgc, offset);
+ struct gpio_chip *gc = &priv->gc;
+ unsigned long mask = gc->pin2mask(gc, offset);
if (val)
priv->imask |= mask;
else
priv->imask &= ~mask;
- bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
+ gc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
}
static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
+ struct grgpio_priv *priv = gpiochip_get_data(gc);
if (offset >= gc->ngpio)
return -ENXIO;
@@ -158,15 +151,15 @@ static int grgpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
- ipol = priv->bgc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
- iedge = priv->bgc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
+ ipol = priv->gc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
+ iedge = priv->gc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
- priv->bgc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
- priv->bgc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
+ priv->gc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
+ priv->gc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
return 0;
}
@@ -177,11 +170,11 @@ static void grgpio_irq_mask(struct irq_data *d)
int offset = d->hwirq;
unsigned long flags;
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
grgpio_set_imask(priv, offset, 0);
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}
static void grgpio_irq_unmask(struct irq_data *d)
@@ -190,11 +183,11 @@ static void grgpio_irq_unmask(struct irq_data *d)
int offset = d->hwirq;
unsigned long flags;
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
grgpio_set_imask(priv, offset, 1);
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}
static struct irq_chip grgpio_irq_chip = {
@@ -207,12 +200,12 @@ static struct irq_chip grgpio_irq_chip = {
static irqreturn_t grgpio_irq_handler(int irq, void *dev)
{
struct grgpio_priv *priv = dev;
- int ngpio = priv->bgc.gc.ngpio;
+ int ngpio = priv->gc.ngpio;
unsigned long flags;
int i;
int match = 0;
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
/*
* For each gpio line, call its interrupt handler if it its underlying
@@ -228,7 +221,7 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev)
}
}
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
if (!match)
dev_warn(priv->dev, "No gpio line matched irq %d\n", irq);
@@ -260,7 +253,7 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n",
irq, offset);
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
/* Request underlying irq if not already requested */
lirq->irq = irq;
@@ -273,14 +266,14 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
"Could not request underlying irq %d\n",
uirq->uirq);
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
return ret;
}
}
uirq->refcnt++;
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
/* Setup irq */
irq_set_chip_data(irq, priv);
@@ -298,13 +291,13 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
struct grgpio_lirq *lirq;
struct grgpio_uirq *uirq;
unsigned long flags;
- int ngpio = priv->bgc.gc.ngpio;
+ int ngpio = priv->gc.ngpio;
int i;
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
/* Free underlying irq if last user unmapped */
index = -1;
@@ -326,7 +319,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
free_irq(uirq->uirq, priv);
}
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}
static const struct irq_domain_ops grgpio_irq_domain_ops = {
@@ -341,7 +334,6 @@ static int grgpio_probe(struct platform_device *ofdev)
struct device_node *np = ofdev->dev.of_node;
void __iomem *regs;
struct gpio_chip *gc;
- struct bgpio_chip *bgc;
struct grgpio_priv *priv;
struct resource *res;
int err;
@@ -359,8 +351,8 @@ static int grgpio_probe(struct platform_device *ofdev)
if (IS_ERR(regs))
return PTR_ERR(regs);
- bgc = &priv->bgc;
- err = bgpio_init(bgc, &ofdev->dev, 4, regs + GRGPIO_DATA,
+ gc = &priv->gc;
+ err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA,
regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (err) {
@@ -369,10 +361,9 @@ static int grgpio_probe(struct platform_device *ofdev)
}
priv->regs = regs;
- priv->imask = bgc->read_reg(regs + GRGPIO_IMASK);
+ priv->imask = gc->read_reg(regs + GRGPIO_IMASK);
priv->dev = &ofdev->dev;
- gc = &bgc->gc;
gc->of_node = np;
gc->owner = THIS_MODULE;
gc->to_irq = grgpio_to_irq;
@@ -435,7 +426,7 @@ static int grgpio_probe(struct platform_device *ofdev)
platform_set_drvdata(ofdev, priv);
- err = gpiochip_add(gc);
+ err = gpiochip_add_data(gc, priv);
if (err) {
dev_err(&ofdev->dev, "Could not add gpiochip\n");
if (priv->domain)
@@ -456,7 +447,7 @@ static int grgpio_remove(struct platform_device *ofdev)
int i;
int ret = 0;
- spin_lock_irqsave(&priv->bgc.lock, flags);
+ spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
if (priv->domain) {
for (i = 0; i < GRGPIO_MAX_NGPIO; i++) {
@@ -467,13 +458,13 @@ static int grgpio_remove(struct platform_device *ofdev)
}
}
- gpiochip_remove(&priv->bgc.gc);
+ gpiochip_remove(&priv->gc);
if (priv->domain)
irq_domain_remove(priv->domain);
out:
- spin_unlock_irqrestore(&priv->bgc.lock, flags);
+ spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
return ret;
}
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index 4ba7ed502131..a4893386abbf 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -282,7 +282,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip)
{
chip->owner = THIS_MODULE;
chip->label = DRV_NAME;
- chip->dev = &ichx_priv.dev->dev;
+ chip->parent = &ichx_priv.dev->dev;
/* Allow chip-specific overrides of request()/get() */
chip->request = ichx_priv.desc->request ?
@@ -499,7 +499,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
init:
ichx_gpiolib_setup(&ichx_priv.chip);
- err = gpiochip_add(&ichx_priv.chip);
+ err = gpiochip_add_data(&ichx_priv.chip, NULL);
if (err) {
pr_err("Failed to register GPIOs\n");
goto add_err;
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index 70097472b02c..cdaba13cb8e8 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -78,15 +78,10 @@ struct intel_mid_gpio {
struct pci_dev *pdev;
};
-static inline struct intel_mid_gpio *to_intel_gpio_priv(struct gpio_chip *gc)
-{
- return container_of(gc, struct intel_mid_gpio, chip);
-}
-
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
enum GPIO_REG reg_type)
{
- struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ struct intel_mid_gpio *priv = gpiochip_get_data(chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 32;
@@ -96,7 +91,7 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
enum GPIO_REG reg_type)
{
- struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ struct intel_mid_gpio *priv = gpiochip_get_data(chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 16;
@@ -120,7 +115,7 @@ static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
{
void __iomem *gplr = gpio_reg(chip, offset, GPLR);
- return readl(gplr) & BIT(offset % 32);
+ return !!(readl(gplr) & BIT(offset % 32));
}
static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -138,7 +133,7 @@ static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ struct intel_mid_gpio *priv = gpiochip_get_data(chip);
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
u32 value;
unsigned long flags;
@@ -161,7 +156,7 @@ static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int intel_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ struct intel_mid_gpio *priv = gpiochip_get_data(chip);
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
unsigned long flags;
@@ -185,7 +180,7 @@ static int intel_gpio_direction_output(struct gpio_chip *chip,
static int intel_mid_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
+ struct intel_mid_gpio *priv = gpiochip_get_data(gc);
u32 gpio = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
@@ -304,7 +299,7 @@ MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
static void intel_mid_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
+ struct intel_mid_gpio *priv = gpiochip_get_data(gc);
struct irq_data *data = irq_desc_get_irq_data(desc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, gpio, mask;
@@ -392,7 +387,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,
priv->reg_base = pcim_iomap_table(pdev)[0];
priv->chip.label = dev_name(&pdev->dev);
- priv->chip.dev = &pdev->dev;
+ priv->chip.parent = &pdev->dev;
priv->chip.request = intel_gpio_request;
priv->chip.direction_input = intel_gpio_direction_input;
priv->chip.direction_output = intel_gpio_direction_output;
@@ -406,7 +401,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
pci_set_drvdata(pdev, priv);
- retval = gpiochip_add(&priv->chip);
+ retval = gpiochip_add_data(&priv->chip, priv);
if (retval) {
dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
return retval;
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index 2ed0237a8baf..fb65e5850e0c 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -114,7 +114,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- return gpiochip_add(&iop3xx_chip);
+ return gpiochip_add_data(&iop3xx_chip, NULL);
}
static struct platform_driver iop3xx_gpio_driver = {
diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c
index 21f6f7c0eb34..b219c82414bf 100644
--- a/drivers/gpio/gpio-it87.c
+++ b/drivers/gpio/gpio-it87.c
@@ -77,11 +77,6 @@ static struct it87_gpio it87_gpio_chip = {
.lock = __SPIN_LOCK_UNLOCKED(it87_gpio_chip.lock),
};
-static inline struct it87_gpio *to_it87_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct it87_gpio, chip);
-}
-
/* Superio chip access functions; copied from wdt_it87 */
static inline int superio_enter(void)
@@ -165,7 +160,7 @@ static int it87_gpio_request(struct gpio_chip *chip, unsigned gpio_num)
{
u8 mask, group;
int rc = 0;
- struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+ struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
mask = 1 << (gpio_num % 8);
group = (gpio_num / 8);
@@ -198,7 +193,7 @@ static int it87_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
{
u16 reg;
u8 mask;
- struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+ struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
mask = 1 << (gpio_num % 8);
reg = (gpio_num / 8) + it87_gpio->io_base;
@@ -210,7 +205,7 @@ static int it87_gpio_direction_in(struct gpio_chip *chip, unsigned gpio_num)
{
u8 mask, group;
int rc = 0;
- struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+ struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
mask = 1 << (gpio_num % 8);
group = (gpio_num / 8);
@@ -236,7 +231,7 @@ static void it87_gpio_set(struct gpio_chip *chip,
{
u8 mask, curr_vals;
u16 reg;
- struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+ struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
mask = 1 << (gpio_num % 8);
reg = (gpio_num / 8) + it87_gpio->io_base;
@@ -253,7 +248,7 @@ static int it87_gpio_direction_out(struct gpio_chip *chip,
{
u8 mask, group;
int rc = 0;
- struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+ struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
mask = 1 << (gpio_num % 8);
group = (gpio_num / 8);
@@ -380,7 +375,7 @@ static int __init it87_gpio_init(void)
it87_gpio->chip.names = (const char *const*)labels_table;
- rc = gpiochip_add(&it87_gpio->chip);
+ rc = gpiochip_add_data(&it87_gpio->chip, it87_gpio);
if (rc)
goto labels_free;
diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c
index 3a1664335f5e..482aa0353868 100644
--- a/drivers/gpio/gpio-janz-ttl.c
+++ b/drivers/gpio/gpio-janz-ttl.c
@@ -59,7 +59,7 @@ struct ttl_module {
static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
{
- struct ttl_module *mod = dev_get_drvdata(gpio->dev);
+ struct ttl_module *mod = dev_get_drvdata(gpio->parent);
u8 *shadow;
int ret;
@@ -76,12 +76,12 @@ static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
spin_lock(&mod->lock);
ret = *shadow & (1 << offset);
spin_unlock(&mod->lock);
- return ret;
+ return !!ret;
}
static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
{
- struct ttl_module *mod = dev_get_drvdata(gpio->dev);
+ struct ttl_module *mod = dev_get_drvdata(gpio->parent);
void __iomem *port;
u8 *shadow;
@@ -172,7 +172,7 @@ static int ttl_probe(struct platform_device *pdev)
/* Initialize the GPIO data structures */
gpio = &mod->gpio;
- gpio->dev = &pdev->dev;
+ gpio->parent = &pdev->dev;
gpio->label = pdev->name;
gpio->get = ttl_get_value;
gpio->set = ttl_set_value;
@@ -182,7 +182,7 @@ static int ttl_probe(struct platform_device *pdev)
gpio->base = -1;
gpio->ngpio = 20;
- ret = gpiochip_add(gpio);
+ ret = gpiochip_add_data(gpio, NULL);
if (ret) {
dev_err(dev, "unable to add GPIO chip\n");
return ret;
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
index 83f281dda1e0..01117747b965 100644
--- a/drivers/gpio/gpio-kempld.c
+++ b/drivers/gpio/gpio-kempld.c
@@ -65,17 +65,15 @@ static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit)
static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct kempld_gpio_data *gpio
- = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
struct kempld_device_data *pld = gpio->pld;
- return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
+ return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
}
static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct kempld_gpio_data *gpio
- = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
struct kempld_device_data *pld = gpio->pld;
kempld_get_mutex(pld);
@@ -85,8 +83,7 @@ static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct kempld_gpio_data *gpio
- = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
struct kempld_device_data *pld = gpio->pld;
kempld_get_mutex(pld);
@@ -99,8 +96,7 @@ static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct kempld_gpio_data *gpio
- = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
struct kempld_device_data *pld = gpio->pld;
kempld_get_mutex(pld);
@@ -113,8 +109,7 @@ static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct kempld_gpio_data *gpio
- = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
struct kempld_device_data *pld = gpio->pld;
return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
@@ -166,7 +161,7 @@ static int kempld_gpio_probe(struct platform_device *pdev)
chip = &gpio->chip;
chip->label = "gpio-kempld";
chip->owner = THIS_MODULE;
- chip->dev = dev;
+ chip->parent = dev;
chip->can_sleep = true;
if (pdata && pdata->gpio_base)
chip->base = pdata->gpio_base;
@@ -183,7 +178,7 @@ static int kempld_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, gpio);
if (ret) {
dev_err(dev, "Could not register GPIO chip\n");
return ret;
diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c
index cc09b237e88c..9f86ed9c753b 100644
--- a/drivers/gpio/gpio-ks8695.c
+++ b/drivers/gpio/gpio-ks8695.c
@@ -234,7 +234,7 @@ static struct gpio_chip ks8695_gpio_chip = {
/* Register the GPIOs */
void ks8695_register_gpios(void)
{
- if (gpiochip_add(&ks8695_gpio_chip))
+ if (gpiochip_add_data(&ks8695_gpio_chip, NULL))
printk(KERN_ERR "Unable to register core GPIOs\n");
}
diff --git a/drivers/gpio/gpio-loongson.c b/drivers/gpio/gpio-loongson.c
index ccc65a1aea88..92c4fe7b2677 100644
--- a/drivers/gpio/gpio-loongson.c
+++ b/drivers/gpio/gpio-loongson.c
@@ -110,6 +110,6 @@ static struct gpio_chip loongson_chip = {
static int __init loongson_gpio_setup(void)
{
- return gpiochip_add(&loongson_chip);
+ return gpiochip_add_data(&loongson_chip, NULL);
}
postcore_initcall(loongson_gpio_setup);
diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c
index cfc5b12b43ad..1c8e2ae26938 100644
--- a/drivers/gpio/gpio-lp3943.c
+++ b/drivers/gpio/gpio-lp3943.c
@@ -45,14 +45,9 @@ struct lp3943_gpio {
u16 input_mask; /* 1 = GPIO is input direction, 0 = output */
};
-static inline struct lp3943_gpio *to_lp3943_gpio(struct gpio_chip *_chip)
-{
- return container_of(_chip, struct lp3943_gpio, chip);
-}
-
static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
/* Return an error if the pin is already assigned */
@@ -64,7 +59,7 @@ static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
clear_bit(offset, &lp3943->pin_used);
@@ -82,7 +77,7 @@ static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset,
static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
lp3943_gpio->input_mask |= BIT(offset);
@@ -138,7 +133,7 @@ static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
/*
* Limitation:
@@ -157,7 +152,7 @@ static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
u8 data;
if (value)
@@ -171,7 +166,7 @@ static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
lp3943_gpio_set(chip, offset, value);
lp3943_gpio->input_mask &= ~BIT(offset);
@@ -205,11 +200,11 @@ static int lp3943_gpio_probe(struct platform_device *pdev)
lp3943_gpio->lp3943 = lp3943;
lp3943_gpio->chip = lp3943_gpio_chip;
- lp3943_gpio->chip.dev = &pdev->dev;
+ lp3943_gpio->chip.parent = &pdev->dev;
platform_set_drvdata(pdev, lp3943_gpio);
- return gpiochip_add(&lp3943_gpio->chip);
+ return gpiochip_add_data(&lp3943_gpio->chip, lp3943_gpio);
}
static int lp3943_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c
index e39dcb0af8ae..98832c9f614a 100644
--- a/drivers/gpio/gpio-lpc18xx.c
+++ b/drivers/gpio/gpio-lpc18xx.c
@@ -31,27 +31,22 @@ struct lpc18xx_gpio_chip {
spinlock_t lock;
};
-static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct lpc18xx_gpio_chip, gpio);
-}
-
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
+ struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
writeb(value ? 1 : 0, gc->base + offset);
}
static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
+ struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
return !!readb(gc->base + offset);
}
static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
bool out)
{
- struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
+ struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
unsigned long flags;
u32 port, pin, dir;
@@ -127,9 +122,9 @@ static int lpc18xx_gpio_probe(struct platform_device *pdev)
spin_lock_init(&gc->lock);
- gc->gpio.dev = &pdev->dev;
+ gc->gpio.parent = &pdev->dev;
- ret = gpiochip_add(&gc->gpio);
+ ret = gpiochip_add_data(&gc->gpio, gc);
if (ret) {
dev_err(&pdev->dev, "failed to add gpio chip\n");
clk_disable_unprepare(gc->clk);
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 47e2dde63734..4cecf4ce96c1 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -165,12 +165,6 @@ struct lpc32xx_gpio_chip {
struct gpio_regs *gpio_grp;
};
-static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
- struct gpio_chip *gpc)
-{
- return container_of(gpc, struct lpc32xx_gpio_chip, chip);
-}
-
static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
unsigned pin, int input)
{
@@ -261,7 +255,7 @@ static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
unsigned pin)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpio_dir_p012(group, pin, 1);
@@ -271,7 +265,7 @@ static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
unsigned pin)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpio_dir_p3(group, pin, 1);
@@ -286,29 +280,29 @@ static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip,
static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
- return __get_gpio_state_p012(group, pin);
+ return !!__get_gpio_state_p012(group, pin);
}
static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
- return __get_gpio_state_p3(group, pin);
+ return !!__get_gpio_state_p3(group, pin);
}
static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
- return __get_gpi_state_p3(group, pin);
+ return !!__get_gpi_state_p3(group, pin);
}
static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpio_level_p012(group, pin, value);
__set_gpio_dir_p012(group, pin, 0);
@@ -319,7 +313,7 @@ static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpio_level_p3(group, pin, value);
__set_gpio_dir_p3(group, pin, 0);
@@ -330,7 +324,7 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpo_level_p3(group, pin, value);
return 0;
@@ -339,7 +333,7 @@ static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpio_level_p012(group, pin, value);
}
@@ -347,7 +341,7 @@ static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpio_level_p3(group, pin, value);
}
@@ -355,16 +349,16 @@ static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
__set_gpo_level_p3(group, pin, value);
}
static int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin)
{
- struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
- return __get_gpo_state_p3(group, pin);
+ return !!__get_gpo_state_p3(group, pin);
}
static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
@@ -553,7 +547,8 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev)
lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3;
lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node;
}
- gpiochip_add(&lpc32xx_gpiochip[i].chip);
+ gpiochip_add_data(&lpc32xx_gpiochip[i].chip,
+ &lpc32xx_gpiochip[i]);
}
return 0;
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 127c37b380ae..13107772be4f 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -97,7 +97,7 @@ struct lp_gpio {
static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset,
int reg)
{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(chip);
int reg_offset;
if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
@@ -112,7 +112,7 @@ static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset,
static int lp_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(chip);
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED);
@@ -137,7 +137,7 @@ static int lp_gpio_request(struct gpio_chip *chip, unsigned offset)
static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(chip);
unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
/* disable input sensing */
@@ -149,7 +149,7 @@ static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
static int lp_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(gc);
u32 hwirq = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
@@ -191,7 +191,7 @@ static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(chip);
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
unsigned long flags;
@@ -207,7 +207,7 @@ static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(chip);
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
unsigned long flags;
@@ -221,7 +221,7 @@ static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int lp_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(chip);
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
unsigned long flags;
@@ -238,7 +238,7 @@ static void lp_gpio_irq_handler(struct irq_desc *desc)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(gc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, pin, mask;
unsigned long reg, ena, pending;
@@ -273,7 +273,7 @@ static void lp_irq_mask(struct irq_data *d)
static void lp_irq_enable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(gc);
u32 hwirq = irqd_to_hwirq(d);
unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
unsigned long flags;
@@ -286,7 +286,7 @@ static void lp_irq_enable(struct irq_data *d)
static void lp_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+ struct lp_gpio *lg = gpiochip_get_data(gc);
u32 hwirq = irqd_to_hwirq(d);
unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
unsigned long flags;
@@ -368,9 +368,9 @@ static int lp_gpio_probe(struct platform_device *pdev)
gc->base = -1;
gc->ngpio = LP_NUM_GPIO;
gc->can_sleep = false;
- gc->dev = dev;
+ gc->parent = dev;
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, lg);
if (ret) {
dev_err(dev, "failed adding lp-gpio chip\n");
return ret;
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 0cc2c279ab5c..1ae9ba851c9a 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -65,7 +65,6 @@ MODULE_DEVICE_TABLE(i2c, max7300_id);
static struct i2c_driver max7300_driver = {
.driver = {
.name = "max7300",
- .owner = THIS_MODULE,
},
.probe = max7300_probe,
.remove = max7300_remove,
diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c
index 0f57d2d248ec..08807368f007 100644
--- a/drivers/gpio/gpio-max730x.c
+++ b/drivers/gpio/gpio-max730x.c
@@ -50,7 +50,7 @@
static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
+ struct max7301 *ts = gpiochip_get_data(chip);
u8 *config;
u8 offset_bits, pin_config;
int ret;
@@ -92,7 +92,7 @@ static int __max7301_set(struct max7301 *ts, unsigned offset, int value)
static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
+ struct max7301 *ts = gpiochip_get_data(chip);
u8 *config;
u8 offset_bits;
int ret;
@@ -120,7 +120,7 @@ static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
static int max7301_get(struct gpio_chip *chip, unsigned offset)
{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
+ struct max7301 *ts = gpiochip_get_data(chip);
int config, level = -EINVAL;
/* First 4 pins are unused in the controller */
@@ -148,7 +148,7 @@ static int max7301_get(struct gpio_chip *chip, unsigned offset)
static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
+ struct max7301 *ts = gpiochip_get_data(chip);
/* First 4 pins are unused in the controller */
offset += 4;
@@ -189,7 +189,7 @@ int __max730x_probe(struct max7301 *ts)
ts->chip.ngpio = PIN_NUMBER;
ts->chip.can_sleep = true;
- ts->chip.dev = dev;
+ ts->chip.parent = dev;
ts->chip.owner = THIS_MODULE;
/*
@@ -213,7 +213,7 @@ int __max730x_probe(struct max7301 *ts)
}
}
- ret = gpiochip_add(&ts->chip);
+ ret = gpiochip_add_data(&ts->chip, ts);
if (ret)
goto exit_destroy;
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 8c5252c6c327..a9aaf9d822b4 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -158,11 +158,6 @@ struct max732x_chip {
#endif
};
-static inline struct max732x_chip *to_max732x(struct gpio_chip *gc)
-{
- return container_of(gc, struct max732x_chip, gpio_chip);
-}
-
static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val)
{
struct i2c_client *client;
@@ -201,21 +196,21 @@ static inline int is_group_a(struct max732x_chip *chip, unsigned off)
static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
uint8_t reg_val;
int ret;
ret = max732x_readb(chip, is_group_a(chip, off), &reg_val);
if (ret < 0)
- return 0;
+ return ret;
- return reg_val & (1u << (off & 0x7));
+ return !!(reg_val & (1u << (off & 0x7)));
}
static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask,
int val)
{
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
uint8_t reg_out;
int ret;
@@ -259,7 +254,7 @@ static void max732x_gpio_set_multiple(struct gpio_chip *gc,
static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
unsigned int mask = 1u << off;
if ((mask & chip->dir_input) == 0) {
@@ -281,7 +276,7 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
static int max732x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
unsigned int mask = 1u << off;
if ((mask & chip->dir_output) == 0) {
@@ -356,7 +351,7 @@ static void max732x_irq_update_mask(struct max732x_chip *chip)
static void max732x_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
chip->irq_mask_cur &= ~(1 << d->hwirq);
}
@@ -364,7 +359,7 @@ static void max732x_irq_mask(struct irq_data *d)
static void max732x_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
chip->irq_mask_cur |= 1 << d->hwirq;
}
@@ -372,7 +367,7 @@ static void max732x_irq_unmask(struct irq_data *d)
static void max732x_irq_bus_lock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->irq_lock);
chip->irq_mask_cur = chip->irq_mask;
@@ -381,7 +376,7 @@ static void max732x_irq_bus_lock(struct irq_data *d)
static void max732x_irq_bus_sync_unlock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
uint16_t new_irqs;
uint16_t level;
@@ -400,7 +395,7 @@ static void max732x_irq_bus_sync_unlock(struct irq_data *d)
static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct max732x_chip *chip = to_max732x(gc);
+ struct max732x_chip *chip = gpiochip_get_data(gc);
uint16_t off = d->hwirq;
uint16_t mask = 1 << off;
@@ -603,7 +598,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip,
gc->base = gpio_start;
gc->ngpio = port;
gc->label = chip->client->name;
- gc->dev = &chip->client->dev;
+ gc->parent = &chip->client->dev;
gc->owner = THIS_MODULE;
return port;
@@ -649,7 +644,7 @@ static int max732x_probe(struct i2c_client *client,
chip->client = client;
nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base);
- chip->gpio_chip.dev = &client->dev;
+ chip->gpio_chip.parent = &client->dev;
addr_a = (client->addr & 0x0f) | 0x60;
addr_b = (client->addr & 0x0f) | 0x50;
@@ -694,7 +689,7 @@ static int max732x_probe(struct i2c_client *client,
goto out_failed;
}
- ret = gpiochip_add(&chip->gpio_chip);
+ ret = gpiochip_add_data(&chip->gpio_chip, chip);
if (ret)
goto out_failed;
@@ -749,7 +744,6 @@ static int max732x_remove(struct i2c_client *client)
static struct i2c_driver max732x_driver = {
.driver = {
.name = "max732x",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(max732x_of_table),
},
.probe = max732x_probe,
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index ee93c0ab0a59..7fffc1d6c055 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -44,14 +44,9 @@ struct mb86s70_gpio_chip {
spinlock_t lock;
};
-static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc)
-{
- return container_of(gc, struct mb86s70_gpio_chip, gc);
-}
-
static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
{
- struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
unsigned long flags;
u32 val;
@@ -73,7 +68,7 @@ static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
{
- struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
unsigned long flags;
u32 val;
@@ -88,7 +83,7 @@ static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
{
- struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
unsigned long flags;
unsigned char val;
@@ -106,7 +101,7 @@ static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
unsigned gpio, int value)
{
- struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
unsigned long flags;
unsigned char val;
@@ -130,14 +125,14 @@ static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
- struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
}
static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
{
- struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
unsigned long flags;
unsigned char val;
@@ -187,12 +182,12 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
gchip->gc.label = dev_name(&pdev->dev);
gchip->gc.ngpio = 32;
gchip->gc.owner = THIS_MODULE;
- gchip->gc.dev = &pdev->dev;
+ gchip->gc.parent = &pdev->dev;
gchip->gc.base = -1;
platform_set_drvdata(pdev, gchip);
- ret = gpiochip_add(&gchip->gc);
+ ret = gpiochip_add_data(&gchip->gc, gchip);
if (ret) {
dev_err(&pdev->dev, "couldn't register gpio driver\n");
clk_disable_unprepare(gchip->clk);
diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index 2853731db5bc..0f0df7956264 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/drivers/gpio/gpio-mc33880.c
@@ -71,7 +71,7 @@ static int __mc33880_set(struct mc33880 *mc, unsigned offset, int value)
static void mc33880_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct mc33880 *mc = container_of(chip, struct mc33880, chip);
+ struct mc33880 *mc = gpiochip_get_data(chip);
mutex_lock(&mc->lock);
@@ -116,7 +116,7 @@ static int mc33880_probe(struct spi_device *spi)
mc->chip.base = pdata->base;
mc->chip.ngpio = PIN_NUMBER;
mc->chip.can_sleep = true;
- mc->chip.dev = &spi->dev;
+ mc->chip.parent = &spi->dev;
mc->chip.owner = THIS_MODULE;
mc->port_config = 0x00;
@@ -135,7 +135,7 @@ static int mc33880_probe(struct spi_device *spi)
goto exit_destroy;
}
- ret = gpiochip_add(&mc->chip);
+ ret = gpiochip_add_data(&mc->chip, mc);
if (ret)
goto exit_destroy;
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
index d62b4f8182bf..ba22fb92a6e7 100644
--- a/drivers/gpio/gpio-mc9s08dz60.c
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -29,12 +29,6 @@ struct mc9s08dz60 {
struct gpio_chip chip;
};
-static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc)
-{
- return container_of(gc, struct mc9s08dz60, chip);
-}
-
-
static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
{
*reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
@@ -45,7 +39,7 @@ static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
{
u8 reg, bit;
s32 value;
- struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+ struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
value = i2c_smbus_read_byte_data(mc9s->client, reg);
@@ -75,7 +69,7 @@ static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
{
- struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+ struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
mc9s08dz60_set(mc9s, offset, val);
}
@@ -83,7 +77,7 @@ static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
static int mc9s08dz60_direction_output(struct gpio_chip *gc,
unsigned offset, int val)
{
- struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+ struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
return mc9s08dz60_set(mc9s, offset, val);
}
@@ -99,7 +93,7 @@ static int mc9s08dz60_probe(struct i2c_client *client,
mc9s->chip.label = client->name;
mc9s->chip.base = -1;
- mc9s->chip.dev = &client->dev;
+ mc9s->chip.parent = &client->dev;
mc9s->chip.owner = THIS_MODULE;
mc9s->chip.ngpio = GPIO_NUM;
mc9s->chip.can_sleep = true;
@@ -109,7 +103,7 @@ static int mc9s08dz60_probe(struct i2c_client *client,
mc9s->client = client;
i2c_set_clientdata(client, mc9s);
- return gpiochip_add(&mc9s->chip);
+ return gpiochip_add_data(&mc9s->chip, mc9s);
}
static int mc9s08dz60_remove(struct i2c_client *client)
@@ -131,7 +125,6 @@ MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id);
static struct i2c_driver mc9s08dz60_i2c_driver = {
.driver = {
- .owner = THIS_MODULE,
.name = "mc9s08dz60",
},
.probe = mc9s08dz60_probe,
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 4a41694919da..c767879e4dd9 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -269,7 +269,7 @@ static const struct mcp23s08_ops mcp23s17_ops = {
static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ struct mcp23s08 *mcp = gpiochip_get_data(chip);
int status;
mutex_lock(&mcp->lock);
@@ -281,7 +281,7 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
static int mcp23s08_get(struct gpio_chip *chip, unsigned offset)
{
- struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ struct mcp23s08 *mcp = gpiochip_get_data(chip);
int status;
mutex_lock(&mcp->lock);
@@ -312,7 +312,7 @@ static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value)
static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ struct mcp23s08 *mcp = gpiochip_get_data(chip);
unsigned mask = 1 << offset;
mutex_lock(&mcp->lock);
@@ -323,7 +323,7 @@ static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
static int
mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
- struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ struct mcp23s08 *mcp = gpiochip_get_data(chip);
unsigned mask = 1 << offset;
int status;
@@ -377,7 +377,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ struct mcp23s08 *mcp = gpiochip_get_data(chip);
return irq_find_mapping(mcp->irq_domain, offset);
}
@@ -446,7 +446,7 @@ static int mcp23s08_irq_reqres(struct irq_data *data)
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
if (gpiochip_lock_as_irq(&mcp->chip, data->hwirq)) {
- dev_err(mcp->chip.dev,
+ dev_err(mcp->chip.parent,
"unable to lock HW IRQ %lu for IRQ usage\n",
data->hwirq);
return -EINVAL;
@@ -481,7 +481,8 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
mutex_init(&mcp->irq_lock);
- mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio,
+ mcp->irq_domain = irq_domain_add_linear(chip->parent->of_node,
+ chip->ngpio,
&irq_domain_simple_ops, mcp);
if (!mcp->irq_domain)
return -ENODEV;
@@ -491,10 +492,11 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
else
irqflags |= IRQF_TRIGGER_LOW;
- err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq,
- irqflags, dev_name(chip->dev), mcp);
+ err = devm_request_threaded_irq(chip->parent, mcp->irq, NULL,
+ mcp23s08_irq,
+ irqflags, dev_name(chip->parent), mcp);
if (err != 0) {
- dev_err(chip->dev, "unable to request IRQ#%d: %d\n",
+ dev_err(chip->parent, "unable to request IRQ#%d: %d\n",
mcp->irq, err);
return err;
}
@@ -542,7 +544,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
int t;
unsigned mask;
- mcp = container_of(chip, struct mcp23s08, chip);
+ mcp = gpiochip_get_data(chip);
/* NOTE: we only handle one bank for now ... */
bank = '0' + ((mcp->addr >> 1) & 0x7);
@@ -638,7 +640,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
mcp->chip.base = pdata->base;
mcp->chip.can_sleep = true;
- mcp->chip.dev = dev;
+ mcp->chip.parent = dev;
mcp->chip.owner = THIS_MODULE;
/* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
@@ -652,7 +654,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
mcp->irq_controller = pdata->irq_controller;
if (mcp->irq && mcp->irq_controller) {
mcp->irq_active_high =
- of_property_read_bool(mcp->chip.dev->of_node,
+ of_property_read_bool(mcp->chip.parent->of_node,
"microchip,irq-active-high");
if (type == MCP_TYPE_017)
@@ -702,7 +704,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
goto fail;
}
- status = gpiochip_add(&mcp->chip);
+ status = gpiochip_add_data(&mcp->chip, mcp);
if (status < 0)
goto fail;
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 5536108aa9db..796a5a4bc4f5 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -106,7 +106,7 @@ static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
{
u32 reg_val;
- struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ struct ioh_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
@@ -122,15 +122,15 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
- struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ struct ioh_gpio *chip = gpiochip_get_data(gpio);
- return ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr);
+ return !!(ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr));
}
static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
- struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ struct ioh_gpio *chip = gpiochip_get_data(gpio);
u32 pm;
u32 reg_val;
unsigned long flags;
@@ -155,7 +155,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
- struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ struct ioh_gpio *chip = gpiochip_get_data(gpio);
u32 pm;
unsigned long flags;
@@ -225,7 +225,7 @@ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
- struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ struct ioh_gpio *chip = gpiochip_get_data(gpio);
return chip->irq_base + offset;
}
@@ -450,7 +450,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
chip->ch = i;
spin_lock_init(&chip->spinlock);
ioh_gpio_setup(chip, num_ports[i]);
- ret = gpiochip_add(&chip->gpio);
+ ret = gpiochip_add_data(&chip->gpio, chip);
if (ret) {
dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n");
goto err_gpiochip_add;
diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c
index f67ef2283d64..54e5d8257d34 100644
--- a/drivers/gpio/gpio-mm-lantiq.c
+++ b/drivers/gpio/gpio-mm-lantiq.c
@@ -61,9 +61,7 @@ static void ltq_mm_apply(struct ltq_mm *chip)
*/
static void ltq_mm_set(struct gpio_chip *gc, unsigned offset, int value)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct ltq_mm *chip =
- container_of(mm_gc, struct ltq_mm, mmchip);
+ struct ltq_mm *chip = gpiochip_get_data(gc);
if (value)
chip->shadow |= (1 << offset);
@@ -122,7 +120,7 @@ static int ltq_mm_probe(struct platform_device *pdev)
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
chip->shadow = shadow;
- return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip);
+ return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip);
}
static int ltq_mm_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index d3355a6dc9b1..ca604538ebf7 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -14,7 +14,6 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/of_address.h>
@@ -23,7 +22,7 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/bitops.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#define GPIO_DATA_OUT 0x00
#define GPIO_DATA_IN 0x04
@@ -33,12 +32,12 @@ static int moxart_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
- struct bgpio_chip *bgc;
+ struct gpio_chip *gc;
void __iomem *base;
int ret;
- bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
- if (!bgc)
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -46,7 +45,7 @@ static int moxart_gpio_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
+ ret = bgpio_init(gc, dev, 4, base + GPIO_DATA_IN,
base + GPIO_DATA_OUT, NULL,
base + GPIO_PIN_DIRECTION, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
@@ -55,16 +54,16 @@ static int moxart_gpio_probe(struct platform_device *pdev)
return ret;
}
- bgc->gc.label = "moxart-gpio";
- bgc->gc.request = gpiochip_generic_request;
- bgc->gc.free = gpiochip_generic_free;
- bgc->data = bgc->read_reg(bgc->reg_set);
- bgc->gc.base = 0;
- bgc->gc.ngpio = 32;
- bgc->gc.dev = dev;
- bgc->gc.owner = THIS_MODULE;
+ gc->label = "moxart-gpio";
+ gc->request = gpiochip_generic_request;
+ gc->free = gpiochip_generic_free;
+ gc->bgpio_data = gc->read_reg(gc->reg_set);
+ gc->base = 0;
+ gc->ngpio = 32;
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
- ret = gpiochip_add(&bgc->gc);
+ ret = gpiochip_add_data(gc, NULL);
if (ret) {
dev_err(dev, "%s: gpiochip_add failed\n",
dev->of_node->full_name);
diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c
index 4c542153e923..0e5a6709f27d 100644
--- a/drivers/gpio/gpio-mpc5200.c
+++ b/drivers/gpio/gpio-mpc5200.c
@@ -71,8 +71,7 @@ static inline void
__mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct mpc52xx_gpiochip *chip = container_of(mm_gc,
- struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
if (val)
@@ -100,8 +99,7 @@ mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static int mpc52xx_wkup_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct mpc52xx_gpiochip *chip = container_of(mm_gc,
- struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
unsigned long flags;
@@ -125,8 +123,7 @@ mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
- struct mpc52xx_gpiochip *chip = container_of(mm_gc,
- struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
@@ -169,7 +166,7 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev)
gc->get = mpc52xx_wkup_gpio_get;
gc->set = mpc52xx_wkup_gpio_set;
- ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
+ ret = of_mm_gpiochip_add_data(ofdev->dev.of_node, &chip->mmchip, chip);
if (ret)
return ret;
@@ -236,8 +233,7 @@ static inline void
__mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct mpc52xx_gpiochip *chip = container_of(mm_gc,
- struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
if (val)
@@ -264,8 +260,7 @@ mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static int mpc52xx_simple_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct mpc52xx_gpiochip *chip = container_of(mm_gc,
- struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
unsigned long flags;
@@ -288,8 +283,7 @@ static int
mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct mpc52xx_gpiochip *chip = container_of(mm_gc,
- struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
unsigned long flags;
@@ -334,7 +328,7 @@ static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev)
gc->get = mpc52xx_simple_gpio_get;
gc->set = mpc52xx_simple_gpio_set;
- ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
+ ret = of_mm_gpiochip_add_data(ofdev->dev.of_node, &chip->mmchip, chip);
if (ret)
return ret;
@@ -360,15 +354,14 @@ static struct platform_driver mpc52xx_simple_gpiochip_driver = {
.remove = mpc52xx_gpiochip_remove,
};
+static struct platform_driver * const drivers[] = {
+ &mpc52xx_wkup_gpiochip_driver,
+ &mpc52xx_simple_gpiochip_driver,
+};
+
static int __init mpc52xx_gpio_init(void)
{
- if (platform_driver_register(&mpc52xx_wkup_gpiochip_driver))
- printk(KERN_ERR "Unable to register wakeup GPIO driver\n");
-
- if (platform_driver_register(&mpc52xx_simple_gpiochip_driver))
- printk(KERN_ERR "Unable to register simple GPIO driver\n");
-
- return 0;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
/* Make sure we get initialised before anyone else tries to use us */
@@ -376,9 +369,7 @@ subsys_initcall(mpc52xx_gpio_init);
static void __exit mpc52xx_gpio_exit(void)
{
- platform_driver_unregister(&mpc52xx_wkup_gpiochip_driver);
-
- platform_driver_unregister(&mpc52xx_simple_gpiochip_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(mpc52xx_gpio_exit);
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 48ef368347ab..9d40787e66c0 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -49,15 +49,10 @@ static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
}
-static inline struct mpc8xxx_gpio_chip *
-to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
-{
- return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
-}
-
static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
{
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc =
+ container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
}
@@ -71,7 +66,7 @@ static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
u32 val;
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
u32 out_mask, out_shadow;
out_mask = in_be32(mm->regs + GPIO_DIR);
@@ -79,7 +74,7 @@ static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
val = in_be32(mm->regs + GPIO_DAT) & ~out_mask;
out_shadow = mpc8xxx_gc->data & out_mask;
- return (val | out_shadow) & mpc8xxx_gpio2mask(gpio);
+ return !!((val | out_shadow) & mpc8xxx_gpio2mask(gpio));
}
static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
@@ -92,7 +87,7 @@ static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
@@ -111,7 +106,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
int i;
@@ -136,7 +131,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc,
static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
@@ -151,7 +146,7 @@ static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
mpc8xxx_gpio_set(gc, gpio, val);
@@ -185,8 +180,7 @@ static int mpc5125_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val
static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
return irq_create_mapping(mpc8xxx_gc->irq, offset);
@@ -417,7 +411,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
gc->set_multiple = mpc8xxx_gpio_set_multiple;
gc->to_irq = mpc8xxx_gpio_to_irq;
- ret = of_mm_gpiochip_add(np, mm_gc);
+ ret = of_mm_gpiochip_add_data(np, mm_gc, mpc8xxx_gc);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c
index 22523aae8abe..d75649787e6c 100644
--- a/drivers/gpio/gpio-msic.c
+++ b/drivers/gpio/gpio-msic.c
@@ -143,7 +143,7 @@ static int msic_gpio_get(struct gpio_chip *chip, unsigned offset)
if (ret < 0)
return ret;
- return r & MSIC_GPIO_DIN_MASK;
+ return !!(r & MSIC_GPIO_DIN_MASK);
}
static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -179,7 +179,7 @@ static int msic_irq_type(struct irq_data *data, unsigned type)
static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct msic_gpio *mg = container_of(chip, struct msic_gpio, chip);
+ struct msic_gpio *mg = gpiochip_get_data(chip);
return mg->irq_base + offset;
}
@@ -293,11 +293,11 @@ static int platform_msic_gpio_probe(struct platform_device *pdev)
mg->chip.base = pdata->gpio_base;
mg->chip.ngpio = MSIC_NUM_GPIO;
mg->chip.can_sleep = true;
- mg->chip.dev = dev;
+ mg->chip.parent = dev;
mutex_init(&mg->buslock);
- retval = gpiochip_add(&mg->chip);
+ retval = gpiochip_add_data(&mg->chip, mg);
if (retval) {
dev_err(dev, "Adding MSIC gpio chip failed\n");
goto err;
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index d428b97876c5..a5eacc1dff09 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -187,8 +187,7 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
unsigned long flags;
u32 u;
@@ -204,8 +203,7 @@ static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
u32 u;
if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin)) {
@@ -220,8 +218,7 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
unsigned long flags;
u32 u;
@@ -237,8 +234,7 @@ static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
unsigned long flags;
int ret;
u32 u;
@@ -261,8 +257,7 @@ static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
int value)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
unsigned long flags;
int ret;
u32 u;
@@ -287,8 +282,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
return irq_create_mapping(mvchip->domain, pin);
}
@@ -494,8 +488,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct mvebu_gpio_chip *mvchip =
- container_of(chip, struct mvebu_gpio_chip, chip);
+ struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
int i;
@@ -698,7 +691,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
mvchip->soc_variant = soc_variant;
mvchip->chip.label = dev_name(&pdev->dev);
- mvchip->chip.dev = &pdev->dev;
+ mvchip->chip.parent = &pdev->dev;
mvchip->chip.request = gpiochip_generic_request;
mvchip->chip.free = gpiochip_generic_free;
mvchip->chip.direction_input = mvebu_gpio_direction_input;
@@ -763,7 +756,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
BUG();
}
- gpiochip_add(&mvchip->chip);
+ gpiochip_add_data(&mvchip->chip, mvchip);
/* Some gpio controllers do not provide irq support */
if (!of_irq_count(np))
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 6ea8df6c7397..7fd21cb53c81 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -26,10 +26,11 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: for gpio_get_value() replace this with direct register read */
+#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/module.h>
@@ -64,7 +65,7 @@ struct mxc_gpio_port {
int irq;
int irq_high;
struct irq_domain *domain;
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
u32 both_edges;
};
@@ -172,7 +173,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
struct mxc_gpio_port *port = gc->private;
u32 bit, val;
u32 gpio_idx = d->hwirq;
- u32 gpio = port->bgc.gc.base + gpio_idx;
+ u32 gpio = port->gc.base + gpio_idx;
int edge;
void __iomem *reg = port->base;
@@ -398,9 +399,7 @@ static void mxc_gpio_get_hw(struct platform_device *pdev)
static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- struct mxc_gpio_port *port =
- container_of(bgc, struct mxc_gpio_port, bgc);
+ struct mxc_gpio_port *port = gpiochip_get_data(gc);
return irq_find_mapping(port->domain, offset);
}
@@ -451,7 +450,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
port);
}
- err = bgpio_init(&port->bgc, &pdev->dev, 4,
+ err = bgpio_init(&port->gc, &pdev->dev, 4,
port->base + GPIO_PSR,
port->base + GPIO_DR, NULL,
port->base + GPIO_GDIR, NULL,
@@ -459,13 +458,13 @@ static int mxc_gpio_probe(struct platform_device *pdev)
if (err)
goto out_bgio;
- port->bgc.gc.to_irq = mxc_gpio_to_irq;
- port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
+ port->gc.to_irq = mxc_gpio_to_irq;
+ port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
pdev->id * 32;
- err = gpiochip_add(&port->bgc.gc);
+ err = gpiochip_add_data(&port->gc, port);
if (err)
- goto out_bgpio_remove;
+ goto out_bgio;
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
if (irq_base < 0) {
@@ -494,9 +493,7 @@ out_irqdomain_remove:
out_irqdesc_free:
irq_free_descs(irq_base, 32);
out_gpiochip_remove:
- gpiochip_remove(&port->bgc.gc);
-out_bgpio_remove:
- bgpio_remove(&port->bgc);
+ gpiochip_remove(&port->gc);
out_bgio:
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
return err;
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index a4288f428819..b9daa0bf32a4 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -26,13 +26,14 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
-#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: for gpio_get_value(), replace this by direct register read */
+#include <linux/gpio.h>
#include <linux/module.h>
#define MXS_SET 0x4
@@ -64,7 +65,7 @@ struct mxs_gpio_port {
int id;
int irq;
struct irq_domain *domain;
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
enum mxs_gpio_id devid;
u32 both_edges;
};
@@ -93,7 +94,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
port->both_edges &= ~pin_mask;
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
- val = gpio_get_value(port->bgc.gc.base + d->hwirq);
+ val = gpio_get_value(port->gc.base + d->hwirq);
if (val)
edge = GPIO_INT_FALL_EDGE;
else
@@ -225,18 +226,14 @@ static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- struct mxs_gpio_port *port =
- container_of(bgc, struct mxs_gpio_port, bgc);
+ struct mxs_gpio_port *port = gpiochip_get_data(gc);
return irq_find_mapping(port->domain, offset);
}
static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
- struct mxs_gpio_port *port =
- container_of(bgc, struct mxs_gpio_port, bgc);
+ struct mxs_gpio_port *port = gpiochip_get_data(gc);
u32 mask = 1 << offset;
u32 dir;
@@ -330,26 +327,24 @@ static int mxs_gpio_probe(struct platform_device *pdev)
irq_set_chained_handler_and_data(port->irq, mxs_gpio_irq_handler,
port);
- err = bgpio_init(&port->bgc, &pdev->dev, 4,
+ err = bgpio_init(&port->gc, &pdev->dev, 4,
port->base + PINCTRL_DIN(port),
port->base + PINCTRL_DOUT(port) + MXS_SET,
port->base + PINCTRL_DOUT(port) + MXS_CLR,
port->base + PINCTRL_DOE(port), NULL, 0);
if (err)
- goto out_irqdesc_free;
+ goto out_irqdomain_remove;
- port->bgc.gc.to_irq = mxs_gpio_to_irq;
- port->bgc.gc.get_direction = mxs_gpio_get_direction;
- port->bgc.gc.base = port->id * 32;
+ port->gc.to_irq = mxs_gpio_to_irq;
+ port->gc.get_direction = mxs_gpio_get_direction;
+ port->gc.base = port->id * 32;
- err = gpiochip_add(&port->bgc.gc);
+ err = gpiochip_add_data(&port->gc, port);
if (err)
- goto out_bgpio_remove;
+ goto out_irqdomain_remove;
return 0;
-out_bgpio_remove:
- bgpio_remove(&port->bgc);
out_irqdomain_remove:
irq_domain_remove(port->domain);
out_irqdesc_free:
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c
index 62ae251d4490..7665ebcd0c1d 100644
--- a/drivers/gpio/gpio-octeon.c
+++ b/drivers/gpio/gpio-octeon.c
@@ -41,7 +41,7 @@ struct octeon_gpio {
static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
{
- struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ struct octeon_gpio *gpio = gpiochip_get_data(chip);
cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), 0);
return 0;
@@ -49,7 +49,7 @@ static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ struct octeon_gpio *gpio = gpiochip_get_data(chip);
u64 mask = 1ull << offset;
u64 reg = gpio->register_base + (value ? TX_SET : TX_CLEAR);
cvmx_write_csr(reg, mask);
@@ -58,7 +58,7 @@ static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ struct octeon_gpio *gpio = gpiochip_get_data(chip);
union cvmx_gpio_bit_cfgx cfgx;
octeon_gpio_set(chip, offset, value);
@@ -72,7 +72,7 @@ static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset,
static int octeon_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ struct octeon_gpio *gpio = gpiochip_get_data(chip);
u64 read_bits = cvmx_read_csr(gpio->register_base + RX_DAT);
return ((1ull << offset) & read_bits) != 0;
@@ -108,7 +108,7 @@ static int octeon_gpio_probe(struct platform_device *pdev)
pdev->dev.platform_data = chip;
chip->label = "octeon-gpio";
- chip->dev = &pdev->dev;
+ chip->parent = &pdev->dev;
chip->owner = THIS_MODULE;
chip->base = 0;
chip->can_sleep = false;
@@ -117,7 +117,7 @@ static int octeon_gpio_probe(struct platform_device *pdev)
chip->get = octeon_gpio_get;
chip->direction_output = octeon_gpio_dir_out;
chip->set = octeon_gpio_set;
- err = gpiochip_add(chip);
+ err = gpiochip_add_data(chip, gpio);
if (err)
goto out;
@@ -128,7 +128,7 @@ out:
static int octeon_gpio_remove(struct platform_device *pdev)
{
- struct gpio_chip *chip = pdev->dev.platform_data;
+ struct gpio_chip *chip = dev_get_platdata(&pdev->dev);
gpiochip_remove(chip);
return 0;
}
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index f7fbb46d5d79..189f672bebc1 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -93,7 +93,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d);
static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- return container_of(chip, struct gpio_bank, chip);
+ return gpiochip_get_data(chip);
}
static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
@@ -661,7 +661,7 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+ struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
/*
@@ -681,7 +681,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+ struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
@@ -954,7 +954,7 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
void __iomem *reg;
int dir;
- bank = container_of(chip, struct gpio_bank, chip);
+ bank = gpiochip_get_data(chip);
reg = bank->base + bank->regs->direction;
raw_spin_lock_irqsave(&bank->lock, flags);
dir = !!(readl_relaxed(reg) & BIT(offset));
@@ -967,7 +967,7 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
struct gpio_bank *bank;
unsigned long flags;
- bank = container_of(chip, struct gpio_bank, chip);
+ bank = gpiochip_get_data(chip);
raw_spin_lock_irqsave(&bank->lock, flags);
omap_set_gpio_direction(bank, offset, 1);
raw_spin_unlock_irqrestore(&bank->lock, flags);
@@ -978,7 +978,7 @@ static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
- bank = container_of(chip, struct gpio_bank, chip);
+ bank = gpiochip_get_data(chip);
if (omap_gpio_is_input(bank, offset))
return omap_get_gpio_datain(bank, offset);
@@ -991,7 +991,7 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
struct gpio_bank *bank;
unsigned long flags;
- bank = container_of(chip, struct gpio_bank, chip);
+ bank = gpiochip_get_data(chip);
raw_spin_lock_irqsave(&bank->lock, flags);
bank->set_dataout(bank, offset, value);
omap_set_gpio_direction(bank, offset, 0);
@@ -1005,7 +1005,7 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
struct gpio_bank *bank;
unsigned long flags;
- bank = container_of(chip, struct gpio_bank, chip);
+ bank = gpiochip_get_data(chip);
raw_spin_lock_irqsave(&bank->lock, flags);
omap2_set_gpio_debounce(bank, offset, debounce);
@@ -1019,7 +1019,7 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
struct gpio_bank *bank;
unsigned long flags;
- bank = container_of(chip, struct gpio_bank, chip);
+ bank = gpiochip_get_data(chip);
raw_spin_lock_irqsave(&bank->lock, flags);
bank->set_dataout(bank, offset, value);
raw_spin_unlock_irqrestore(&bank->lock, flags);
@@ -1090,7 +1090,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
if (bank->is_mpuio) {
bank->chip.label = "mpuio";
if (bank->regs->wkup_en)
- bank->chip.dev = &omap_mpuio_device.dev;
+ bank->chip.parent = &omap_mpuio_device.dev;
bank->chip.base = OMAP_MPUIO(0);
} else {
bank->chip.label = "gpio";
@@ -1098,7 +1098,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
}
bank->chip.ngpio = bank->width;
- ret = gpiochip_add(&bank->chip);
+ ret = gpiochip_add_data(&bank->chip, bank);
if (ret) {
dev_err(bank->dev, "Could not register gpio chip %d\n", ret);
return ret;
@@ -1197,7 +1197,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
}
bank->dev = dev;
- bank->chip.dev = dev;
+ bank->chip.parent = dev;
bank->chip.owner = THIS_MODULE;
bank->dbck_flag = pdata->dbck_flag;
bank->stride = pdata->bank_stride;
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index 52b447c071cb..fdfb3b1e0def 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -35,14 +35,9 @@ struct palmas_device_data {
int ngpio;
};
-static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct palmas_gpio, gpio_chip);
-}
-
static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas_gpio *pg = gpiochip_get_data(gc);
struct palmas *palmas = pg->palmas;
unsigned int val;
int ret;
@@ -54,7 +49,7 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
if (ret < 0) {
- dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
+ dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
return ret;
}
@@ -65,7 +60,7 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
if (ret < 0) {
- dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
+ dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
return ret;
}
return !!(val & BIT(offset));
@@ -74,7 +69,7 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas_gpio *pg = gpiochip_get_data(gc);
struct palmas *palmas = pg->palmas;
int ret;
unsigned int reg;
@@ -90,13 +85,13 @@ static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));
if (ret < 0)
- dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret);
+ dev_err(gc->parent, "Reg 0x%02x write failed, %d\n", reg, ret);
}
static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas_gpio *pg = gpiochip_get_data(gc);
struct palmas *palmas = pg->palmas;
int ret;
unsigned int reg;
@@ -111,13 +106,14 @@ static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,
BIT(offset), BIT(offset));
if (ret < 0)
- dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
+ dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
+ ret);
return ret;
}
static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
{
- struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas_gpio *pg = gpiochip_get_data(gc);
struct palmas *palmas = pg->palmas;
int ret;
unsigned int reg;
@@ -128,13 +124,14 @@ static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
if (ret < 0)
- dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
+ dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
+ ret);
return ret;
}
static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas_gpio *pg = gpiochip_get_data(gc);
struct palmas *palmas = pg->palmas;
return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
@@ -188,7 +185,7 @@ static int palmas_gpio_probe(struct platform_device *pdev)
palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
palmas_gpio->gpio_chip.set = palmas_gpio_set;
palmas_gpio->gpio_chip.get = palmas_gpio_get;
- palmas_gpio->gpio_chip.dev = &pdev->dev;
+ palmas_gpio->gpio_chip.parent = &pdev->dev;
#ifdef CONFIG_OF_GPIO
palmas_gpio->gpio_chip.of_node = pdev->dev.of_node;
#endif
@@ -198,7 +195,7 @@ static int palmas_gpio_probe(struct platform_device *pdev)
else
palmas_gpio->gpio_chip.base = -1;
- ret = gpiochip_add(&palmas_gpio->gpio_chip);
+ ret = gpiochip_add_data(&palmas_gpio->gpio_chip, palmas_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 2d4892cc70fb..23196c5fc17c 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -18,9 +18,7 @@
#include <linux/i2c.h>
#include <linux/platform_data/pca953x.h>
#include <linux/slab.h>
-#ifdef CONFIG_OF_GPIO
#include <linux/of_platform.h>
-#endif
#include <linux/acpi.h>
#define PCA953X_INPUT 0
@@ -109,11 +107,6 @@ struct pca953x_chip {
unsigned long driver_data;
};
-static inline struct pca953x_chip *to_pca(struct gpio_chip *gc)
-{
- return container_of(gc, struct pca953x_chip, gpio_chip);
-}
-
static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
int off)
{
@@ -216,7 +209,7 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 reg_val;
int ret, offset = 0;
@@ -245,7 +238,7 @@ exit:
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 reg_val;
int ret, offset = 0;
@@ -295,7 +288,7 @@ exit:
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
u32 reg_val;
int ret, offset = 0;
@@ -323,7 +316,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 reg_val;
int ret, offset = 0;
@@ -352,6 +345,43 @@ exit:
mutex_unlock(&chip->i2c_lock);
}
+
+static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
+ u8 reg_val[MAX_BANK];
+ int ret, offset = 0;
+ int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+ int bank;
+
+ switch (chip->chip_type) {
+ case PCA953X_TYPE:
+ offset = PCA953X_OUTPUT;
+ break;
+ case PCA957X_TYPE:
+ offset = PCA957X_OUT;
+ break;
+ }
+
+ memcpy(reg_val, chip->reg_output, NBANK(chip));
+ mutex_lock(&chip->i2c_lock);
+ for(bank=0; bank<NBANK(chip); bank++) {
+ unsigned bankmask = mask[bank/4] >> ((bank % 4) * 8);
+ if(bankmask) {
+ unsigned bankval = bits[bank/4] >> ((bank % 4) * 8);
+ reg_val[bank] = (reg_val[bank] & ~bankmask) | bankval;
+ }
+ }
+ ret = i2c_smbus_write_i2c_block_data(chip->client, offset << bank_shift, NBANK(chip), reg_val);
+ if (ret)
+ goto exit;
+
+ memcpy(chip->reg_output, reg_val, NBANK(chip));
+exit:
+ mutex_unlock(&chip->i2c_lock);
+}
+
static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
{
struct gpio_chip *gc;
@@ -362,12 +392,13 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->direction_output = pca953x_gpio_direction_output;
gc->get = pca953x_gpio_get_value;
gc->set = pca953x_gpio_set_value;
+ gc->set_multiple = pca953x_gpio_set_multiple;
gc->can_sleep = true;
gc->base = chip->gpio_start;
gc->ngpio = gpios;
gc->label = chip->client->name;
- gc->dev = &chip->client->dev;
+ gc->parent = &chip->client->dev;
gc->owner = THIS_MODULE;
gc->names = chip->names;
}
@@ -376,7 +407,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
static void pca953x_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
}
@@ -384,7 +415,7 @@ static void pca953x_irq_mask(struct irq_data *d)
static void pca953x_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
}
@@ -392,7 +423,7 @@ static void pca953x_irq_unmask(struct irq_data *d)
static void pca953x_irq_bus_lock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->irq_lock);
}
@@ -400,7 +431,7 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 new_irqs;
int level, i;
@@ -423,7 +454,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pca953x_chip *chip = to_pca(gc);
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
int bank_nb = d->hwirq / BANK_SZ;
u8 mask = 1 << (d->hwirq % BANK_SZ);
@@ -660,6 +691,8 @@ out:
return ret;
}
+static const struct of_device_id pca953x_dt_ids[];
+
static int pca953x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -691,12 +724,18 @@ static int pca953x_probe(struct i2c_client *client,
chip->driver_data = id->driver_data;
} else {
const struct acpi_device_id *id;
+ const struct of_device_id *match;
- id = acpi_match_device(pca953x_acpi_ids, &client->dev);
- if (!id)
- return -ENODEV;
+ match = of_match_device(pca953x_dt_ids, &client->dev);
+ if (match) {
+ chip->driver_data = (int)(uintptr_t)match->data;
+ } else {
+ id = acpi_match_device(pca953x_acpi_ids, &client->dev);
+ if (!id)
+ return -ENODEV;
- chip->driver_data = id->driver_data;
+ chip->driver_data = id->driver_data;
+ }
}
chip->chip_type = PCA_CHIP_TYPE(chip->driver_data);
@@ -715,7 +754,7 @@ static int pca953x_probe(struct i2c_client *client,
if (ret)
return ret;
- ret = gpiochip_add(&chip->gpio_chip);
+ ret = gpiochip_add_data(&chip->gpio_chip, chip);
if (ret)
return ret;
@@ -755,33 +794,39 @@ static int pca953x_remove(struct i2c_client *client)
return 0;
}
+/* convenience to stop overlong match-table lines */
+#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
+#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
+
static const struct of_device_id pca953x_dt_ids[] = {
- { .compatible = "nxp,pca9505", },
- { .compatible = "nxp,pca9534", },
- { .compatible = "nxp,pca9535", },
- { .compatible = "nxp,pca9536", },
- { .compatible = "nxp,pca9537", },
- { .compatible = "nxp,pca9538", },
- { .compatible = "nxp,pca9539", },
- { .compatible = "nxp,pca9554", },
- { .compatible = "nxp,pca9555", },
- { .compatible = "nxp,pca9556", },
- { .compatible = "nxp,pca9557", },
- { .compatible = "nxp,pca9574", },
- { .compatible = "nxp,pca9575", },
- { .compatible = "nxp,pca9698", },
-
- { .compatible = "maxim,max7310", },
- { .compatible = "maxim,max7312", },
- { .compatible = "maxim,max7313", },
- { .compatible = "maxim,max7315", },
-
- { .compatible = "ti,pca6107", },
- { .compatible = "ti,tca6408", },
- { .compatible = "ti,tca6416", },
- { .compatible = "ti,tca6424", },
-
- { .compatible = "exar,xra1202", },
+ { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
+ { .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9536", .data = OF_953X( 4, 0), },
+ { .compatible = "nxp,pca9537", .data = OF_953X( 4, PCA_INT), },
+ { .compatible = "nxp,pca9538", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9554", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9556", .data = OF_953X( 8, 0), },
+ { .compatible = "nxp,pca9557", .data = OF_953X( 8, 0), },
+ { .compatible = "nxp,pca9574", .data = OF_957X( 8, PCA_INT), },
+ { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
+ { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+
+ { .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
+ { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), },
+
+ { .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
+
+ { .compatible = "onsemi,pca9654", .data = OF_953X( 8, PCA_INT), },
+
+ { .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
{ }
};
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 1d4d9bc8b69d..709cd3fc2a70 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -137,7 +137,7 @@ static int i2c_read_le16(struct i2c_client *client)
static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
{
- struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ struct pcf857x *gpio = gpiochip_get_data(chip);
int status;
mutex_lock(&gpio->lock);
@@ -150,16 +150,16 @@ static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
static int pcf857x_get(struct gpio_chip *chip, unsigned offset)
{
- struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ struct pcf857x *gpio = gpiochip_get_data(chip);
int value;
value = gpio->read(gpio->client);
- return (value < 0) ? 0 : (value & (1 << offset));
+ return (value < 0) ? value : !!(value & (1 << offset));
}
static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ struct pcf857x *gpio = gpiochip_get_data(chip);
unsigned bit = 1 << offset;
int status;
@@ -293,7 +293,7 @@ static int pcf857x_probe(struct i2c_client *client,
gpio->chip.base = pdata ? pdata->gpio_base : -1;
gpio->chip.can_sleep = true;
- gpio->chip.dev = &client->dev;
+ gpio->chip.parent = &client->dev;
gpio->chip.owner = THIS_MODULE;
gpio->chip.get = pcf857x_get;
gpio->chip.set = pcf857x_set;
@@ -372,7 +372,7 @@ static int pcf857x_probe(struct i2c_client *client,
gpio->out = ~n_latch;
gpio->status = gpio->out;
- status = gpiochip_add(&gpio->chip);
+ status = gpiochip_add_data(&gpio->chip, gpio);
if (status < 0)
goto fail;
@@ -447,7 +447,6 @@ static int pcf857x_remove(struct i2c_client *client)
static struct i2c_driver pcf857x_driver = {
.driver = {
.name = "pcf857x",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcf857x_of_table),
},
.probe = pcf857x_probe,
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 34ed176df15a..7c7135da5d4a 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -109,7 +109,7 @@ struct pch_gpio {
static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
{
u32 reg_val;
- struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ struct pch_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
@@ -125,15 +125,15 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
- struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ struct pch_gpio *chip = gpiochip_get_data(gpio);
- return ioread32(&chip->reg->pi) & (1 << nr);
+ return (ioread32(&chip->reg->pi) >> nr) & 1;
}
static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
- struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ struct pch_gpio *chip = gpiochip_get_data(gpio);
u32 pm;
u32 reg_val;
unsigned long flags;
@@ -158,7 +158,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
- struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ struct pch_gpio *chip = gpiochip_get_data(gpio);
u32 pm;
unsigned long flags;
@@ -211,7 +211,7 @@ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
- struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ struct pch_gpio *chip = gpiochip_get_data(gpio);
return chip->irq_base + offset;
}
@@ -220,7 +220,7 @@ static void pch_gpio_setup(struct pch_gpio *chip)
struct gpio_chip *gpio = &chip->gpio;
gpio->label = dev_name(chip->dev);
- gpio->dev = chip->dev;
+ gpio->parent = chip->dev;
gpio->owner = THIS_MODULE;
gpio->direction_input = pch_gpio_direction_input;
gpio->get = pch_gpio_get;
@@ -394,7 +394,10 @@ static int pch_gpio_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, chip);
spin_lock_init(&chip->spinlock);
pch_gpio_setup(chip);
- ret = gpiochip_add(&chip->gpio);
+#ifdef CONFIG_OF_GPIO
+ chip->gpio.of_node = pdev->dev.of_node;
+#endif
+ ret = gpiochip_add_data(&chip->gpio, chip);
if (ret) {
dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n");
goto err_gpiochip_add;
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 4d4b37676702..5cb38212bbc0 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/bitops.h>
@@ -60,7 +61,7 @@ struct pl061_gpio {
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
unsigned char gpiodir;
@@ -79,7 +80,7 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
unsigned char gpiodir;
@@ -104,14 +105,14 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
{
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
return !!readb(chip->base + (BIT(offset + 2)));
}
static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
{
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
writeb(!!value << offset, chip->base + (BIT(offset + 2)));
}
@@ -119,7 +120,7 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
@@ -131,7 +132,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
(trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
{
- dev_err(gc->dev,
+ dev_err(gc->parent,
"trying to configure line %d for both level and edge "
"detection, choose one!\n",
offset);
@@ -158,7 +159,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
else
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_level_irq);
- dev_dbg(gc->dev, "line %d: IRQ on %s level\n",
+ dev_dbg(gc->parent, "line %d: IRQ on %s level\n",
offset,
polarity ? "HIGH" : "LOW");
} else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
@@ -167,7 +168,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
/* Select both edges, setting this makes GPIOEV be ignored */
gpioibe |= bit;
irq_set_handler_locked(d, handle_edge_irq);
- dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset);
+ dev_dbg(gc->parent, "line %d: IRQ on both edges\n", offset);
} else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
(trigger & IRQ_TYPE_EDGE_FALLING)) {
bool rising = trigger & IRQ_TYPE_EDGE_RISING;
@@ -182,7 +183,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
else
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_edge_irq);
- dev_dbg(gc->dev, "line %d: IRQ on %s edge\n",
+ dev_dbg(gc->parent, "line %d: IRQ on %s edge\n",
offset,
rising ? "RISING" : "FALLING");
} else {
@@ -191,7 +192,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
gpioibe &= ~bit;
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_bad_irq);
- dev_warn(gc->dev, "no trigger selected for line %d\n",
+ dev_warn(gc->parent, "no trigger selected for line %d\n",
offset);
}
@@ -209,7 +210,7 @@ static void pl061_irq_handler(struct irq_desc *desc)
unsigned long pending;
int offset;
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc);
@@ -227,7 +228,7 @@ static void pl061_irq_handler(struct irq_desc *desc)
static void pl061_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
@@ -240,7 +241,7 @@ static void pl061_irq_mask(struct irq_data *d)
static void pl061_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
@@ -261,7 +262,7 @@ static void pl061_irq_unmask(struct irq_data *d)
static void pl061_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
spin_lock(&chip->lock);
@@ -269,12 +270,20 @@ static void pl061_irq_ack(struct irq_data *d)
spin_unlock(&chip->lock);
}
+static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ return irq_set_irq_wake(gc->irq_parent, state);
+}
+
static struct irq_chip pl061_irqchip = {
.name = "pl061",
.irq_ack = pl061_irq_ack,
.irq_mask = pl061_irq_mask,
.irq_unmask = pl061_irq_unmask,
.irq_set_type = pl061_irq_type,
+ .irq_set_wake = pl061_irq_set_wake,
};
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
@@ -316,10 +325,10 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
chip->gc.set = pl061_set_value;
chip->gc.ngpio = PL061_GPIO_NR;
chip->gc.label = dev_name(dev);
- chip->gc.dev = dev;
+ chip->gc.parent = dev;
chip->gc.owner = THIS_MODULE;
- ret = gpiochip_add(&chip->gc);
+ ret = gpiochip_add_data(&chip->gc, chip);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index df2ce550f309..b2b7b78664b8 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <linux/slab.h>
@@ -64,20 +65,11 @@
int pxa_last_gpio;
static int irq_base;
-#ifdef CONFIG_OF
-static struct irq_domain *domain;
-static struct device_node *pxa_gpio_of_node;
-#endif
-
-struct pxa_gpio_chip {
- struct gpio_chip chip;
+struct pxa_gpio_bank {
void __iomem *regbase;
- char label[10];
-
unsigned long irq_mask;
unsigned long irq_edge_rise;
unsigned long irq_edge_fall;
- int (*set_wake)(unsigned int gpio, unsigned int on);
#ifdef CONFIG_PM
unsigned long saved_gplr;
@@ -87,6 +79,17 @@ struct pxa_gpio_chip {
#endif
};
+struct pxa_gpio_chip {
+ struct device *dev;
+ struct gpio_chip chip;
+ struct pxa_gpio_bank *banks;
+ struct irq_domain *irqdomain;
+
+ int irq0;
+ int irq1;
+ int (*set_wake)(unsigned int gpio, unsigned int on);
+};
+
enum pxa_gpio_type {
PXA25X_GPIO = 0,
PXA26X_GPIO,
@@ -104,9 +107,8 @@ struct pxa_gpio_id {
};
static DEFINE_SPINLOCK(gpio_lock);
-static struct pxa_gpio_chip *pxa_gpio_chips;
+static struct pxa_gpio_chip *pxa_gpio_chip;
static enum pxa_gpio_type gpio_type;
-static void __iomem *gpio_reg_base;
static struct pxa_gpio_id pxa25x_id = {
.type = PXA25X_GPIO,
@@ -148,17 +150,28 @@ static struct pxa_gpio_id pxa1928_id = {
.gpio_nums = 224,
};
-#define for_each_gpio_chip(i, c) \
- for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
+#define for_each_gpio_bank(i, b, pc) \
+ for (i = 0, b = pc->banks; i <= pxa_last_gpio; i += 32, b++)
-static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
+static inline struct pxa_gpio_chip *chip_to_pxachip(struct gpio_chip *c)
{
- return container_of(c, struct pxa_gpio_chip, chip)->regbase;
+ struct pxa_gpio_chip *pxa_chip = gpiochip_get_data(c);
+
+ return pxa_chip;
}
-static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
+static inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio)
{
- return &pxa_gpio_chips[gpio_to_bank(gpio)];
+ struct pxa_gpio_chip *p = gpiochip_get_data(c);
+ struct pxa_gpio_bank *bank = p->banks + (gpio / 32);
+
+ return bank->regbase;
+}
+
+static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c,
+ unsigned gpio)
+{
+ return chip_to_pxachip(c)->banks + gpio / 32;
}
static inline int gpio_is_pxa_type(int type)
@@ -187,15 +200,13 @@ static inline int __gpio_is_inverted(int gpio)
* is attributed as "occupied" here (I know this terminology isn't
* accurate, you are welcome to propose a better one :-)
*/
-static inline int __gpio_is_occupied(unsigned gpio)
+static inline int __gpio_is_occupied(struct pxa_gpio_chip *pchip, unsigned gpio)
{
- struct pxa_gpio_chip *pxachip;
void __iomem *base;
unsigned long gafr = 0, gpdr = 0;
int ret, af = 0, dir = 0;
- pxachip = gpio_to_pxachip(gpio);
- base = gpio_chip_base(&pxachip->chip);
+ base = gpio_bank_base(&pchip->chip, gpio);
gpdr = readl_relaxed(base + GPDR_OFFSET);
switch (gpio_type) {
@@ -218,21 +229,35 @@ static inline int __gpio_is_occupied(unsigned gpio)
return ret;
}
-static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+int pxa_irq_to_gpio(int irq)
{
- return chip->base + offset + irq_base;
+ struct pxa_gpio_chip *pchip = pxa_gpio_chip;
+ int irq_gpio0;
+
+ irq_gpio0 = irq_find_mapping(pchip->irqdomain, 0);
+ if (irq_gpio0 > 0)
+ return irq - irq_gpio0;
+
+ return irq_gpio0;
}
-int pxa_irq_to_gpio(int irq)
+static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- return irq - irq_base;
+ struct pxa_gpio_chip *pchip = chip_to_pxachip(chip);
+
+ return irq_find_mapping(pchip->irqdomain, offset);
}
static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- void __iomem *base = gpio_chip_base(chip);
- uint32_t value, mask = 1 << offset;
+ void __iomem *base = gpio_bank_base(chip, offset);
+ uint32_t value, mask = GPIO_bit(offset);
unsigned long flags;
+ int ret;
+
+ ret = pinctrl_gpio_direction_input(chip->base + offset);
+ if (!ret)
+ return 0;
spin_lock_irqsave(&gpio_lock, flags);
@@ -250,12 +275,17 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int pxa_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- void __iomem *base = gpio_chip_base(chip);
- uint32_t tmp, mask = 1 << offset;
+ void __iomem *base = gpio_bank_base(chip, offset);
+ uint32_t tmp, mask = GPIO_bit(offset);
unsigned long flags;
+ int ret;
writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
+ ret = pinctrl_gpio_direction_output(chip->base + offset);
+ if (!ret)
+ return 0;
+
spin_lock_irqsave(&gpio_lock, flags);
tmp = readl_relaxed(base + GPDR_OFFSET);
@@ -271,14 +301,18 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- u32 gplr = readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET);
- return !!(gplr & (1 << offset));
+ void __iomem *base = gpio_bank_base(chip, offset);
+ u32 gplr = readl_relaxed(base + GPLR_OFFSET);
+
+ return !!(gplr & GPIO_bit(offset));
}
static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- writel_relaxed(1 << offset, gpio_chip_base(chip) +
- (value ? GPSR_OFFSET : GPCR_OFFSET));
+ void __iomem *base = gpio_bank_base(chip, offset);
+
+ writel_relaxed(GPIO_bit(offset),
+ base + (value ? GPSR_OFFSET : GPCR_OFFSET));
}
#ifdef CONFIG_OF_GPIO
@@ -289,61 +323,61 @@ static int pxa_gpio_of_xlate(struct gpio_chip *gc,
if (gpiospec->args[0] > pxa_last_gpio)
return -EINVAL;
- if (gc != &pxa_gpio_chips[gpiospec->args[0] / 32].chip)
- return -EINVAL;
-
if (flags)
*flags = gpiospec->args[1];
- return gpiospec->args[0] % 32;
+ return gpiospec->args[0];
}
#endif
-static int pxa_init_gpio_chip(int gpio_end,
- int (*set_wake)(unsigned int, unsigned int))
+static int pxa_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
- int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
- struct pxa_gpio_chip *chips;
-
- chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
- if (chips == NULL) {
- pr_err("%s: failed to allocate GPIO chips\n", __func__);
- return -ENOMEM;
- }
+ return pinctrl_request_gpio(chip->base + offset);
+}
- for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
- struct gpio_chip *c = &chips[i].chip;
+static void pxa_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
- sprintf(chips[i].label, "gpio-%d", i);
- chips[i].regbase = gpio_reg_base + BANK_OFF(i);
- chips[i].set_wake = set_wake;
+static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio,
+ struct device_node *np, void __iomem *regbase)
+{
+ int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32);
+ struct pxa_gpio_bank *bank;
- c->base = gpio;
- c->label = chips[i].label;
+ pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks),
+ GFP_KERNEL);
+ if (!pchip->banks)
+ return -ENOMEM;
- c->direction_input = pxa_gpio_direction_input;
- c->direction_output = pxa_gpio_direction_output;
- c->get = pxa_gpio_get;
- c->set = pxa_gpio_set;
- c->to_irq = pxa_gpio_to_irq;
+ pchip->chip.label = "gpio-pxa";
+ pchip->chip.direction_input = pxa_gpio_direction_input;
+ pchip->chip.direction_output = pxa_gpio_direction_output;
+ pchip->chip.get = pxa_gpio_get;
+ pchip->chip.set = pxa_gpio_set;
+ pchip->chip.to_irq = pxa_gpio_to_irq;
+ pchip->chip.ngpio = ngpio;
+ pchip->chip.request = pxa_gpio_request;
+ pchip->chip.free = pxa_gpio_free;
#ifdef CONFIG_OF_GPIO
- c->of_node = pxa_gpio_of_node;
- c->of_xlate = pxa_gpio_of_xlate;
- c->of_gpio_n_cells = 2;
+ pchip->chip.of_node = np;
+ pchip->chip.of_xlate = pxa_gpio_of_xlate;
+ pchip->chip.of_gpio_n_cells = 2;
#endif
- /* number of GPIOs on last bank may be less than 32 */
- c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
- gpiochip_add(c);
+ for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
+ bank = pchip->banks + i;
+ bank->regbase = regbase + BANK_OFF(i);
}
- pxa_gpio_chips = chips;
- return 0;
+
+ return gpiochip_add_data(&pchip->chip, pchip);
}
/* Update only those GRERx and GFERx edge detection register bits if those
* bits are set in c->irq_mask
*/
-static inline void update_edge_detect(struct pxa_gpio_chip *c)
+static inline void update_edge_detect(struct pxa_gpio_bank *c)
{
uint32_t grer, gfer;
@@ -357,12 +391,11 @@ static inline void update_edge_detect(struct pxa_gpio_chip *c)
static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
{
- struct pxa_gpio_chip *c;
- int gpio = pxa_irq_to_gpio(d->irq);
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irqd_to_hwirq(d);
+ struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
unsigned long gpdr, mask = GPIO_bit(gpio);
- c = gpio_to_pxachip(gpio);
-
if (type == IRQ_TYPE_PROBE) {
/* Don't mess with enabled GPIOs using preconfigured edges or
* GPIOs set to alternate function or to output during probe
@@ -370,7 +403,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
return 0;
- if (__gpio_is_occupied(gpio))
+ if (__gpio_is_occupied(pchip, gpio))
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
@@ -401,20 +434,16 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
return 0;
}
-static void pxa_gpio_demux_handler(struct irq_desc *desc)
+static irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d)
{
- struct pxa_gpio_chip *c;
- int loop, gpio, gpio_base, n;
+ int loop, gpio, n, handled = 0;
unsigned long gedr;
- struct irq_chip *chip = irq_desc_get_chip(desc);
-
- chained_irq_enter(chip, desc);
+ struct pxa_gpio_chip *pchip = d;
+ struct pxa_gpio_bank *c;
do {
loop = 0;
- for_each_gpio_chip(gpio, c) {
- gpio_base = c->chip.base;
-
+ for_each_gpio_bank(gpio, c, pchip) {
gedr = readl_relaxed(c->regbase + GEDR_OFFSET);
gedr = gedr & c->irq_mask;
writel_relaxed(gedr, c->regbase + GEDR_OFFSET);
@@ -422,51 +451,71 @@ static void pxa_gpio_demux_handler(struct irq_desc *desc)
for_each_set_bit(n, &gedr, BITS_PER_LONG) {
loop = 1;
- generic_handle_irq(gpio_to_irq(gpio_base + n));
+ generic_handle_irq(gpio_to_irq(gpio + n));
}
}
+ handled += loop;
} while (loop);
- chained_irq_exit(chip, desc);
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d)
+{
+ struct pxa_gpio_chip *pchip = d;
+
+ if (in_irq == pchip->irq0) {
+ generic_handle_irq(gpio_to_irq(0));
+ } else if (in_irq == pchip->irq1) {
+ generic_handle_irq(gpio_to_irq(1));
+ } else {
+ pr_err("%s() unknown irq %d\n", __func__, in_irq);
+ return IRQ_NONE;
+ }
+ return IRQ_HANDLED;
}
static void pxa_ack_muxed_gpio(struct irq_data *d)
{
- int gpio = pxa_irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irqd_to_hwirq(d);
+ void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
- writel_relaxed(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
+ writel_relaxed(GPIO_bit(gpio), base + GEDR_OFFSET);
}
static void pxa_mask_muxed_gpio(struct irq_data *d)
{
- int gpio = pxa_irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irqd_to_hwirq(d);
+ struct pxa_gpio_bank *b = gpio_to_pxabank(&pchip->chip, gpio);
+ void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
uint32_t grer, gfer;
- c->irq_mask &= ~GPIO_bit(gpio);
+ b->irq_mask &= ~GPIO_bit(gpio);
- grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
- gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
- writel_relaxed(grer, c->regbase + GRER_OFFSET);
- writel_relaxed(gfer, c->regbase + GFER_OFFSET);
+ grer = readl_relaxed(base + GRER_OFFSET) & ~GPIO_bit(gpio);
+ gfer = readl_relaxed(base + GFER_OFFSET) & ~GPIO_bit(gpio);
+ writel_relaxed(grer, base + GRER_OFFSET);
+ writel_relaxed(gfer, base + GFER_OFFSET);
}
static int pxa_gpio_set_wake(struct irq_data *d, unsigned int on)
{
- int gpio = pxa_irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irqd_to_hwirq(d);
- if (c->set_wake)
- return c->set_wake(gpio, on);
+ if (pchip->set_wake)
+ return pchip->set_wake(gpio, on);
else
return 0;
}
static void pxa_unmask_muxed_gpio(struct irq_data *d)
{
- int gpio = pxa_irq_to_gpio(d->irq);
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irqd_to_hwirq(d);
+ struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
c->irq_mask |= GPIO_bit(gpio);
update_edge_detect(c);
@@ -506,24 +555,12 @@ static int pxa_gpio_nums(struct platform_device *pdev)
return count;
}
-#ifdef CONFIG_OF
-static const struct of_device_id pxa_gpio_dt_ids[] = {
- { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
- { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
- { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
- { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, },
- { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
- { .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
- { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
- { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, },
- {}
-};
-
static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
handle_edge_irq);
+ irq_set_chip_data(irq, d->host_data);
irq_set_noprobe(irq);
return 0;
}
@@ -533,10 +570,23 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
-static int pxa_gpio_probe_dt(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_gpio_dt_ids[] = {
+ { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
+ { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
+ { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
+ { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, },
+ { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
+ { .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
+ { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
+ { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, },
+ {}
+};
+
+static int pxa_gpio_probe_dt(struct platform_device *pdev,
+ struct pxa_gpio_chip *pchip)
{
- int ret = 0, nr_gpios;
- struct device_node *np = pdev->dev.of_node;
+ int nr_gpios;
const struct of_device_id *of_id =
of_match_device(pxa_gpio_dt_ids, &pdev->dev);
const struct pxa_gpio_id *gpio_id;
@@ -554,57 +604,64 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev)
irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
- ret = irq_base;
- goto err;
+ return irq_base;
}
- domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
- &pxa_irq_domain_ops, NULL);
- pxa_gpio_of_node = np;
- return 0;
-err:
- iounmap(gpio_reg_base);
- return ret;
+ return irq_base;
}
#else
-#define pxa_gpio_probe_dt(pdev) (-1)
+#define pxa_gpio_probe_dt(pdev, pchip) (-1)
#endif
static int pxa_gpio_probe(struct platform_device *pdev)
{
- struct pxa_gpio_chip *c;
+ struct pxa_gpio_chip *pchip;
+ struct pxa_gpio_bank *c;
struct resource *res;
struct clk *clk;
struct pxa_gpio_platform_data *info;
- int gpio, irq, ret, use_of = 0;
+ void __iomem *gpio_reg_base;
+ int gpio, ret;
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
+ pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL);
+ if (!pchip)
+ return -ENOMEM;
+ pchip->dev = &pdev->dev;
+
info = dev_get_platdata(&pdev->dev);
if (info) {
irq_base = info->irq_base;
if (irq_base <= 0)
return -EINVAL;
pxa_last_gpio = pxa_gpio_nums(pdev);
+ pchip->set_wake = info->gpio_set_wake;
} else {
- irq_base = 0;
- use_of = 1;
- ret = pxa_gpio_probe_dt(pdev);
- if (ret < 0)
+ irq_base = pxa_gpio_probe_dt(pdev, pchip);
+ if (irq_base < 0)
return -EINVAL;
}
if (!pxa_last_gpio)
return -EINVAL;
+ pchip->irqdomain = irq_domain_add_legacy(pdev->dev.of_node,
+ pxa_last_gpio + 1, irq_base,
+ 0, &pxa_irq_domain_ops, pchip);
+ if (!pchip->irqdomain)
+ return -ENOMEM;
+
irq0 = platform_get_irq_byname(pdev, "gpio0");
irq1 = platform_get_irq_byname(pdev, "gpio1");
irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0)
|| (irq_mux <= 0))
return -EINVAL;
+
+ pchip->irq0 = irq0;
+ pchip->irq1 = irq1;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
- gpio_reg_base = ioremap(res->start, resource_size(res));
+ gpio_reg_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
if (!gpio_reg_base)
return -EINVAL;
@@ -615,21 +672,24 @@ static int pxa_gpio_probe(struct platform_device *pdev)
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Error %ld to get gpio clock\n",
PTR_ERR(clk));
- iounmap(gpio_reg_base);
return PTR_ERR(clk);
}
ret = clk_prepare_enable(clk);
if (ret) {
clk_put(clk);
- iounmap(gpio_reg_base);
return ret;
}
/* Initialize GPIO chips */
- pxa_init_gpio_chip(pxa_last_gpio, info ? info->gpio_set_wake : NULL);
+ ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, pdev->dev.of_node,
+ gpio_reg_base);
+ if (ret) {
+ clk_put(clk);
+ return ret;
+ }
/* clear all GPIO edge detects */
- for_each_gpio_chip(gpio, c) {
+ for_each_gpio_bank(gpio, c, pchip) {
writel_relaxed(0, c->regbase + GFER_OFFSET);
writel_relaxed(0, c->regbase + GRER_OFFSET);
writel_relaxed(~0, c->regbase + GEDR_OFFSET);
@@ -638,34 +698,31 @@ static int pxa_gpio_probe(struct platform_device *pdev)
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
}
- if (!use_of) {
- if (irq0 > 0) {
- irq = gpio_to_irq(0);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
- }
- if (irq1 > 0) {
- irq = gpio_to_irq(1);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
- }
-
- for (irq = gpio_to_irq(gpio_offset);
- irq <= gpio_to_irq(pxa_last_gpio); irq++) {
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
- }
+ if (irq0 > 0) {
+ ret = devm_request_irq(&pdev->dev,
+ irq0, pxa_gpio_direct_handler, 0,
+ "gpio-0", pchip);
+ if (ret)
+ dev_err(&pdev->dev, "request of gpio0 irq failed: %d\n",
+ ret);
}
+ if (irq1 > 0) {
+ ret = devm_request_irq(&pdev->dev,
+ irq1, pxa_gpio_direct_handler, 0,
+ "gpio-1", pchip);
+ if (ret)
+ dev_err(&pdev->dev, "request of gpio1 irq failed: %d\n",
+ ret);
+ }
+ ret = devm_request_irq(&pdev->dev,
+ irq_mux, pxa_gpio_demux_handler, 0,
+ "gpio-mux", pchip);
+ if (ret)
+ dev_err(&pdev->dev, "request of gpio-mux irq failed: %d\n",
+ ret);
- if (irq0 > 0)
- irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
- if (irq1 > 0)
- irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
+ pxa_gpio_chip = pchip;
- irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
return 0;
}
@@ -690,19 +747,32 @@ static struct platform_driver pxa_gpio_driver = {
.id_table = gpio_id_table,
};
-static int __init pxa_gpio_init(void)
+static int __init pxa_gpio_legacy_init(void)
{
+ if (of_have_populated_dt())
+ return 0;
+
return platform_driver_register(&pxa_gpio_driver);
}
-postcore_initcall(pxa_gpio_init);
+postcore_initcall(pxa_gpio_legacy_init);
+
+static int __init pxa_gpio_dt_init(void)
+{
+ if (of_have_populated_dt())
+ return platform_driver_register(&pxa_gpio_driver);
+
+ return 0;
+}
+device_initcall(pxa_gpio_dt_init);
#ifdef CONFIG_PM
static int pxa_gpio_suspend(void)
{
- struct pxa_gpio_chip *c;
+ struct pxa_gpio_chip *pchip = pxa_gpio_chip;
+ struct pxa_gpio_bank *c;
int gpio;
- for_each_gpio_chip(gpio, c) {
+ for_each_gpio_bank(gpio, c, pchip) {
c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET);
@@ -716,10 +786,11 @@ static int pxa_gpio_suspend(void)
static void pxa_gpio_resume(void)
{
- struct pxa_gpio_chip *c;
+ struct pxa_gpio_chip *pchip = pxa_gpio_chip;
+ struct pxa_gpio_bank *c;
int gpio;
- for_each_gpio_chip(gpio, c) {
+ for_each_gpio_bank(gpio, c, pchip) {
/* restore level with set/clear */
writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET);
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 6eabf239676b..1e2d210b3369 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -34,14 +34,9 @@ struct rc5t583_gpio {
struct rc5t583 *rc5t583;
};
-static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct rc5t583_gpio, gpio_chip);
-}
-
static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
- struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
uint8_t val = 0;
int ret;
@@ -55,7 +50,7 @@ static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset)
static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
{
- struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
if (val)
rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
@@ -65,7 +60,7 @@ static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
{
- struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
int ret;
@@ -80,7 +75,7 @@ static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
int ret;
@@ -95,7 +90,7 @@ static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset,
static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
if (offset < RC5T583_MAX_GPIO)
return rc5t583_gpio->rc5t583->irq_base +
@@ -105,7 +100,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset)
{
- struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
@@ -132,7 +127,7 @@ static int rc5t583_gpio_probe(struct platform_device *pdev)
rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq,
rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO,
rc5t583_gpio->gpio_chip.can_sleep = true,
- rc5t583_gpio->gpio_chip.dev = &pdev->dev;
+ rc5t583_gpio->gpio_chip.parent = &pdev->dev;
rc5t583_gpio->gpio_chip.base = -1;
rc5t583_gpio->rc5t583 = rc5t583;
@@ -141,7 +136,7 @@ static int rc5t583_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rc5t583_gpio);
- return gpiochip_add(&rc5t583_gpio->gpio_chip);
+ return gpiochip_add_data(&rc5t583_gpio->gpio_chip, rc5t583_gpio);
}
static int rc5t583_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 2a8122444614..cf41440aff91 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/platform_data/gpio-rcar.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
@@ -34,12 +33,13 @@
struct gpio_rcar_priv {
void __iomem *base;
spinlock_t lock;
- struct gpio_rcar_config config;
struct platform_device *pdev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
- unsigned int irq_parent;
struct clk *clk;
+ unsigned int irq_parent;
+ bool has_both_edge_trigger;
+ bool needs_clk;
};
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
@@ -84,8 +84,7 @@ static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs,
static void gpio_rcar_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
- gpio_chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
}
@@ -93,8 +92,7 @@ static void gpio_rcar_irq_disable(struct irq_data *d)
static void gpio_rcar_irq_enable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
- gpio_chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
}
@@ -121,7 +119,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
/* Select one edge or both edges in BOTHEDGE */
- if (p->config.has_both_edge_trigger)
+ if (p->has_both_edge_trigger)
gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
/* Select "Interrupt Input Mode" in IOINTSEL */
@@ -137,8 +135,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
- gpio_chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
unsigned int hwirq = irqd_to_hwirq(d);
dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
@@ -161,7 +158,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
false);
break;
case IRQ_TYPE_EDGE_BOTH:
- if (!p->config.has_both_edge_trigger)
+ if (!p->has_both_edge_trigger)
return -EINVAL;
gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
true);
@@ -175,8 +172,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
- gpio_chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(gc);
int error;
if (p->irq_parent) {
@@ -218,16 +214,11 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
}
-static inline struct gpio_rcar_priv *gpio_to_priv(struct gpio_chip *chip)
-{
- return container_of(chip, struct gpio_rcar_priv, gpio_chip);
-}
-
static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
unsigned int gpio,
bool output)
{
- struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
unsigned long flags;
/* follow steps in the GPIO documentation for
@@ -251,7 +242,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
int error;
error = pm_runtime_get_sync(&p->pdev->dev);
@@ -267,7 +258,7 @@ static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
pinctrl_free_gpio(chip->base + offset);
@@ -291,15 +282,15 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
/* testing on r8a7790 shows that INDT does not show correct pin state
* when configured as output, so use OUTDT in case of output pins */
- if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
- return !!(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+ if (gpio_rcar_read(gpiochip_get_data(chip), INOUTSEL) & bit)
+ return !!(gpio_rcar_read(gpiochip_get_data(chip), OUTDT) & bit);
else
- return !!(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
+ return !!(gpio_rcar_read(gpiochip_get_data(chip), INDT) & bit);
}
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&p->lock, flags);
@@ -318,14 +309,17 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
struct gpio_rcar_info {
bool has_both_edge_trigger;
+ bool needs_clk;
};
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
.has_both_edge_trigger = false,
+ .needs_clk = false,
};
static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
.has_both_edge_trigger = true,
+ .needs_clk = true,
};
static const struct of_device_id gpio_rcar_of_table[] = {
@@ -355,39 +349,30 @@ static const struct of_device_id gpio_rcar_of_table[] = {
MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
-static int gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
+static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
{
- struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev);
struct device_node *np = p->pdev->dev.of_node;
+ const struct of_device_id *match;
+ const struct gpio_rcar_info *info;
struct of_phandle_args args;
int ret;
- if (pdata) {
- p->config = *pdata;
- } else if (IS_ENABLED(CONFIG_OF) && np) {
- const struct of_device_id *match;
- const struct gpio_rcar_info *info;
-
- match = of_match_node(gpio_rcar_of_table, np);
- if (!match)
- return -EINVAL;
+ match = of_match_node(gpio_rcar_of_table, np);
+ if (!match)
+ return -EINVAL;
- info = match->data;
+ info = match->data;
- ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0,
- &args);
- p->config.number_of_pins = ret == 0 ? args.args[2]
- : RCAR_MAX_GPIO_PER_BANK;
- p->config.gpio_base = -1;
- p->config.has_both_edge_trigger = info->has_both_edge_trigger;
- }
+ ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
+ *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
+ p->has_both_edge_trigger = info->has_both_edge_trigger;
+ p->needs_clk = info->needs_clk;
- if (p->config.number_of_pins == 0 ||
- p->config.number_of_pins > RCAR_MAX_GPIO_PER_BANK) {
+ if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
dev_warn(&p->pdev->dev,
- "Invalid number of gpio lines %u, using %u\n",
- p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK);
- p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK;
+ "Invalid number of gpio lines %u, using %u\n", *npins,
+ RCAR_MAX_GPIO_PER_BANK);
+ *npins = RCAR_MAX_GPIO_PER_BANK;
}
return 0;
@@ -401,6 +386,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
struct irq_chip *irq_chip;
struct device *dev = &pdev->dev;
const char *name = dev_name(dev);
+ unsigned int npins;
int ret;
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
@@ -410,8 +396,8 @@ static int gpio_rcar_probe(struct platform_device *pdev)
p->pdev = pdev;
spin_lock_init(&p->lock);
- /* Get device configuration from DT node or platform data. */
- ret = gpio_rcar_parse_pdata(p);
+ /* Get device configuration from DT node */
+ ret = gpio_rcar_parse_dt(p, &npins);
if (ret < 0)
return ret;
@@ -419,7 +405,11 @@ static int gpio_rcar_probe(struct platform_device *pdev)
p->clk = devm_clk_get(dev, NULL);
if (IS_ERR(p->clk)) {
- dev_warn(dev, "unable to get clock\n");
+ if (p->needs_clk) {
+ dev_err(dev, "unable to get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err0;
+ }
p->clk = NULL;
}
@@ -449,10 +439,10 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->direction_output = gpio_rcar_direction_output;
gpio_chip->set = gpio_rcar_set;
gpio_chip->label = name;
- gpio_chip->dev = dev;
+ gpio_chip->parent = dev;
gpio_chip->owner = THIS_MODULE;
- gpio_chip->base = p->config.gpio_base;
- gpio_chip->ngpio = p->config.number_of_pins;
+ gpio_chip->base = -1;
+ gpio_chip->ngpio = npins;
irq_chip = &p->irq_chip;
irq_chip->name = name;
@@ -462,14 +452,14 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
- ret = gpiochip_add(gpio_chip);
+ ret = gpiochip_add_data(gpio_chip, p);
if (ret) {
dev_err(dev, "failed to add GPIO controller\n");
goto err0;
}
- ret = gpiochip_irqchip_add(gpio_chip, irq_chip, p->config.irq_base,
- handle_level_irq, IRQ_TYPE_NONE);
+ ret = gpiochip_irqchip_add(gpio_chip, irq_chip, 0, handle_level_irq,
+ IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "cannot add irqchip\n");
goto err1;
@@ -483,22 +473,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
goto err1;
}
- dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins);
-
- /* warn in case of mismatch if irq base is specified */
- if (p->config.irq_base) {
- ret = irq_find_mapping(gpio_chip->irqdomain, 0);
- if (p->config.irq_base != ret)
- dev_warn(dev, "irq base mismatch (%u/%u)\n",
- p->config.irq_base, ret);
- }
-
- if (p->config.pctl_name) {
- ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
- gpio_chip->base, gpio_chip->ngpio);
- if (ret < 0)
- dev_warn(dev, "failed to add pin range\n");
- }
+ dev_info(dev, "driving %d GPIOs\n", npins);
return 0;
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index d729bc8a554d..96ddee3f464a 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -47,7 +47,7 @@ static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
u32 value = 0;
int reg;
- gpch = container_of(chip, struct rdc321x_gpio, chip);
+ gpch = gpiochip_get_data(chip);
reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base;
spin_lock(&gpch->lock);
@@ -65,7 +65,7 @@ static void rdc_gpio_set_value_impl(struct gpio_chip *chip,
struct rdc321x_gpio *gpch;
int reg = (gpio < 32) ? 0 : 1;
- gpch = container_of(chip, struct rdc321x_gpio, chip);
+ gpch = gpiochip_get_data(chip);
if (value)
gpch->data_reg[reg] |= 1 << (gpio & 0x1f);
@@ -83,7 +83,7 @@ static void rdc_gpio_set_value(struct gpio_chip *chip,
{
struct rdc321x_gpio *gpch;
- gpch = container_of(chip, struct rdc321x_gpio, chip);
+ gpch = gpiochip_get_data(chip);
spin_lock(&gpch->lock);
rdc_gpio_set_value_impl(chip, gpio, value);
spin_unlock(&gpch->lock);
@@ -96,7 +96,7 @@ static int rdc_gpio_config(struct gpio_chip *chip,
int err;
u32 reg;
- gpch = container_of(chip, struct rdc321x_gpio, chip);
+ gpch = gpiochip_get_data(chip);
spin_lock(&gpch->lock);
err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?
@@ -194,7 +194,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio);
- return gpiochip_add(&rdc321x_gpio_dev->chip);
+ return gpiochip_add_data(&rdc321x_gpio_dev->chip, rdc321x_gpio_dev);
}
static int rdc321x_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 990fa9023e22..0c99e8fb9af3 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -17,7 +17,7 @@
static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- return GPLR & GPIO_GPIO(offset);
+ return !!(GPLR & GPIO_GPIO(offset));
}
static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -238,7 +238,7 @@ void __init sa1100_init_gpio(void)
GRER = 0;
GEDR = -1;
- gpiochip_add(&sa1100_gpio_chip);
+ gpiochip_add_data(&sa1100_gpio_chip, NULL);
sa1100_gpio_irqdomain = irq_domain_add_simple(NULL,
28, IRQ_GPIO0,
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index b72906f5b999..5314ee4b947d 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -41,8 +41,6 @@ struct sch_gpio {
unsigned short resume_base;
};
-#define to_sch_gpio(gc) container_of(gc, struct sch_gpio, chip)
-
static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
unsigned reg)
{
@@ -65,7 +63,7 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
{
- struct sch_gpio *sch = to_sch_gpio(gc);
+ struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned short offset, bit;
u8 reg_val;
@@ -80,7 +78,7 @@ static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
int val)
{
- struct sch_gpio *sch = to_sch_gpio(gc);
+ struct sch_gpio *sch = gpiochip_get_data(gc);
unsigned short offset, bit;
u8 reg_val;
@@ -97,7 +95,7 @@ static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
{
- struct sch_gpio *sch = to_sch_gpio(gc);
+ struct sch_gpio *sch = gpiochip_get_data(gc);
spin_lock(&sch->lock);
sch_gpio_reg_set(gc, gpio_num, GIO, 1);
@@ -112,7 +110,7 @@ static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
{
- struct sch_gpio *sch = to_sch_gpio(gc);
+ struct sch_gpio *sch = gpiochip_get_data(gc);
spin_lock(&sch->lock);
sch_gpio_reg_set(gc, gpio_num, GLV, val);
@@ -122,7 +120,7 @@ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
int val)
{
- struct sch_gpio *sch = to_sch_gpio(gc);
+ struct sch_gpio *sch = gpiochip_get_data(gc);
spin_lock(&sch->lock);
sch_gpio_reg_set(gc, gpio_num, GIO, 0);
@@ -171,7 +169,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
sch->iobase = res->start;
sch->chip = sch_gpio_chip;
sch->chip.label = dev_name(&pdev->dev);
- sch->chip.dev = &pdev->dev;
+ sch->chip.parent = &pdev->dev;
switch (pdev->id) {
case PCI_DEVICE_ID_INTEL_SCH_LPC:
@@ -217,7 +215,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sch);
- return gpiochip_add(&sch->chip);
+ return gpiochip_add_data(&sch->chip, sch);
}
static int sch_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
index 0cb11413e814..1cbd77a04e7b 100644
--- a/drivers/gpio/gpio-sch311x.c
+++ b/drivers/gpio/gpio-sch311x.c
@@ -93,13 +93,6 @@ static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = {
},
};
-static inline struct sch311x_gpio_block *
-to_sch311x_gpio_block(struct gpio_chip *chip)
-{
- return container_of(chip, struct sch311x_gpio_block, chip);
-}
-
-
/*
* Super-IO functions
*/
@@ -142,14 +135,14 @@ static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ struct sch311x_gpio_block *block = gpiochip_get_data(chip);
if (block->config_regs[offset] == 0) /* GPIO is not available */
return -ENODEV;
if (!request_region(block->runtime_reg + block->config_regs[offset],
1, DRV_NAME)) {
- dev_err(chip->dev, "Failed to request region 0x%04x.\n",
+ dev_err(chip->parent, "Failed to request region 0x%04x.\n",
block->runtime_reg + block->config_regs[offset]);
return -EBUSY;
}
@@ -158,7 +151,7 @@ static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ struct sch311x_gpio_block *block = gpiochip_get_data(chip);
if (block->config_regs[offset] == 0) /* GPIO is not available */
return;
@@ -168,7 +161,7 @@ static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ struct sch311x_gpio_block *block = gpiochip_get_data(chip);
unsigned char data;
spin_lock(&block->lock);
@@ -192,7 +185,7 @@ static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ struct sch311x_gpio_block *block = gpiochip_get_data(chip);
spin_lock(&block->lock);
__sch311x_gpio_set(block, offset, value);
@@ -201,7 +194,7 @@ static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ struct sch311x_gpio_block *block = gpiochip_get_data(chip);
spin_lock(&block->lock);
outb(SCH311X_GPIO_CONF_IN, block->runtime_reg +
@@ -214,7 +207,7 @@ static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ struct sch311x_gpio_block *block = gpiochip_get_data(chip);
spin_lock(&block->lock);
@@ -229,7 +222,7 @@ static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
static int sch311x_gpio_probe(struct platform_device *pdev)
{
- struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
+ struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
struct sch311x_gpio_priv *priv;
struct sch311x_gpio_block *block;
int err, i;
@@ -261,13 +254,13 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
block->chip.get = sch311x_gpio_get;
block->chip.set = sch311x_gpio_set;
block->chip.ngpio = 8;
- block->chip.dev = &pdev->dev;
+ block->chip.parent = &pdev->dev;
block->chip.base = sch311x_gpio_blocks[i].base;
block->config_regs = sch311x_gpio_blocks[i].config_regs;
block->data_reg = sch311x_gpio_blocks[i].data_reg;
block->runtime_reg = pdata->runtime_reg;
- err = gpiochip_add(&block->chip);
+ err = gpiochip_add_data(&block->chip, block);
if (err < 0) {
dev_err(&pdev->dev,
"Could not register gpiochip, %d\n", err);
@@ -289,7 +282,7 @@ exit_err:
static int sch311x_gpio_remove(struct platform_device *pdev)
{
- struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
+ struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
int i;
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index 34b02b42ab9e..e3cb6772f6ec 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -10,7 +10,6 @@
*/
#include <linux/errno.h>
-#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -20,7 +19,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/of_irq.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#define DRV_NAME "sdv_gpio"
#define SDV_NUM_PUB_GPIOS 12
@@ -43,7 +42,7 @@ struct sdv_gpio_chip_data {
void __iomem *gpio_pub_base;
struct irq_domain *id;
struct irq_chip_generic *gc;
- struct bgpio_chip bgpio;
+ struct gpio_chip chip;
};
static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
@@ -226,14 +225,14 @@ static int sdv_gpio_probe(struct pci_dev *pdev,
writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
}
- ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
+ ret = bgpio_init(&sd->chip, &pdev->dev, 4,
sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
NULL, sd->gpio_pub_base + GPOER, NULL, 0);
if (ret)
goto unmap;
- sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
+ sd->chip.ngpio = SDV_NUM_PUB_GPIOS;
- ret = gpiochip_add(&sd->bgpio.gc);
+ ret = gpiochip_add_data(&sd->chip, sd);
if (ret < 0) {
dev_err(&pdev->dev, "gpiochip_add() failed.\n");
goto unmap;
@@ -265,7 +264,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev)
free_irq(pdev->irq, sd);
irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
- gpiochip_remove(&sd->bgpio.gc);
+ gpiochip_remove(&sd->chip);
pci_release_region(pdev, GPIO_BAR);
iounmap(sd->gpio_pub_base);
pci_disable_device(pdev);
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 69ffca5b073b..50fb09080a6b 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -62,8 +62,7 @@ static int spics_get_value(struct gpio_chip *chip, unsigned offset)
static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value)
{
- struct spear_spics *spics = container_of(chip, struct spear_spics,
- chip);
+ struct spear_spics *spics = gpiochip_get_data(chip);
u32 tmp;
/* select chip select from register */
@@ -94,8 +93,7 @@ static int spics_direction_output(struct gpio_chip *chip, unsigned offset,
static int spics_request(struct gpio_chip *chip, unsigned offset)
{
- struct spear_spics *spics = container_of(chip, struct spear_spics,
- chip);
+ struct spear_spics *spics = gpiochip_get_data(chip);
u32 tmp;
if (!spics->use_count++) {
@@ -110,8 +108,7 @@ static int spics_request(struct gpio_chip *chip, unsigned offset)
static void spics_free(struct gpio_chip *chip, unsigned offset)
{
- struct spear_spics *spics = container_of(chip, struct spear_spics,
- chip);
+ struct spear_spics *spics = gpiochip_get_data(chip);
u32 tmp;
if (!--spics->use_count) {
@@ -164,11 +161,11 @@ static int spics_gpio_probe(struct platform_device *pdev)
spics->chip.get = spics_get_value;
spics->chip.set = spics_set_value;
spics->chip.label = dev_name(&pdev->dev);
- spics->chip.dev = &pdev->dev;
+ spics->chip.parent = &pdev->dev;
spics->chip.owner = THIS_MODULE;
spics->last_off = -1;
- ret = gpiochip_add(&spics->chip);
+ ret = gpiochip_add_data(&spics->chip, spics);
if (ret) {
dev_err(&pdev->dev, "unable to add gpio chip\n");
return ret;
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index 55e47828ddfc..83af1cb36333 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -74,7 +74,7 @@ static inline u32 __bit(int nr)
static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
{
- struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+ struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
@@ -86,17 +86,17 @@ static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
- struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+ struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
- return readl(&regs->dat) & bit;
+ return !!(readl(&regs->dat) & bit);
}
static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
- struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+ struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
@@ -111,7 +111,7 @@ static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
- struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+ struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
@@ -121,7 +121,7 @@ static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int gsta_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
- struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+ struct gsta_gpio *chip = gpiochip_get_data(gpio);
return chip->irq_base + offset;
}
@@ -409,7 +409,7 @@ static int gsta_probe(struct platform_device *dev)
goto err_free_descs;
}
- err = gpiochip_add(&chip->gpio);
+ err = gpiochip_add_data(&chip->gpio, chip);
if (err < 0) {
dev_err(&dev->dev, "sta2x11 gpio: Can't register (%i)\n",
-err);
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index dabfb99dddef..5197edf1acfd 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -36,14 +36,9 @@ struct stmpe_gpio {
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};
-static inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct stmpe_gpio, chip);
-}
-
static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
@@ -58,7 +53,7 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
u8 reg = stmpe->regs[which] - (offset / 8);
@@ -77,7 +72,7 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int stmpe_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
@@ -90,7 +85,7 @@ static int stmpe_gpio_direction_output(struct gpio_chip *chip,
static int stmpe_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
@@ -100,7 +95,7 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip,
static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
if (stmpe_gpio->norequest_mask & (1 << offset))
@@ -123,7 +118,7 @@ static struct gpio_chip template_chip = {
static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -151,7 +146,7 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void stmpe_gpio_irq_lock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
mutex_lock(&stmpe_gpio->irq_lock);
}
@@ -159,7 +154,7 @@ static void stmpe_gpio_irq_lock(struct irq_data *d)
static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
static const u8 regmap[] = {
@@ -193,7 +188,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
static void stmpe_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -204,7 +199,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
static void stmpe_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -216,7 +211,7 @@ static void stmpe_dbg_show_one(struct seq_file *s,
struct gpio_chip *gc,
unsigned offset, unsigned gpio)
{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
struct stmpe *stmpe = stmpe_gpio->stmpe;
const char *label = gpiochip_is_requested(gc, offset);
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
@@ -356,7 +351,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->stmpe = stmpe;
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
- stmpe_gpio->chip.dev = &pdev->dev;
+ stmpe_gpio->chip.parent = &pdev->dev;
stmpe_gpio->chip.of_node = np;
stmpe_gpio->chip.base = -1;
@@ -375,7 +370,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
if (ret)
goto out_free;
- ret = gpiochip_add(&stmpe_gpio->chip);
+ ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
goto out_disable;
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 81bdbe7ba2a4..d11dd48570b2 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -100,8 +100,7 @@ struct xway_stp {
*/
static void xway_stp_set(struct gpio_chip *gc, unsigned gpio, int val)
{
- struct xway_stp *chip =
- container_of(gc, struct xway_stp, gc);
+ struct xway_stp *chip = gpiochip_get_data(gc);
if (val)
chip->shadow |= BIT(gpio);
@@ -135,11 +134,10 @@ static int xway_stp_dir_out(struct gpio_chip *gc, unsigned gpio, int val)
*/
static int xway_stp_request(struct gpio_chip *gc, unsigned gpio)
{
- struct xway_stp *chip =
- container_of(gc, struct xway_stp, gc);
+ struct xway_stp *chip = gpiochip_get_data(gc);
if ((gpio < 8) && (chip->reserved & BIT(gpio))) {
- dev_err(gc->dev, "GPIO %d is driven by hardware\n", gpio);
+ dev_err(gc->parent, "GPIO %d is driven by hardware\n", gpio);
return -ENODEV;
}
@@ -214,7 +212,7 @@ static int xway_stp_probe(struct platform_device *pdev)
if (IS_ERR(chip->virt))
return PTR_ERR(chip->virt);
- chip->gc.dev = &pdev->dev;
+ chip->gc.parent = &pdev->dev;
chip->gc.label = "stp-xway";
chip->gc.direction_output = xway_stp_dir_out;
chip->gc.set = xway_stp_set;
@@ -260,7 +258,7 @@ static int xway_stp_probe(struct platform_device *pdev)
ret = xway_stp_hw_init(chip);
if (!ret)
- ret = gpiochip_add(&chip->gc);
+ ret = gpiochip_add_data(&chip->gc, chip);
if (!ret)
dev_info(&pdev->dev, "Init done\n");
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 76f920173a2f..e6cff1cabd0c 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -32,8 +32,19 @@
#define NO_UPDATE_PENDING -1
/* The chip models of sx150x */
-#define SX150X_456 0
-#define SX150X_789 1
+#define SX150X_123 0
+#define SX150X_456 1
+#define SX150X_789 2
+
+struct sx150x_123_pri {
+ u8 reg_pld_mode;
+ u8 reg_pld_table0;
+ u8 reg_pld_table1;
+ u8 reg_pld_table2;
+ u8 reg_pld_table3;
+ u8 reg_pld_table4;
+ u8 reg_advance;
+};
struct sx150x_456_pri {
u8 reg_pld_mode;
@@ -65,6 +76,7 @@ struct sx150x_device_data {
u8 reg_sense;
u8 ngpios;
union {
+ struct sx150x_123_pri x123;
struct sx150x_456_pri x456;
struct sx150x_789_pri x789;
} pri;
@@ -142,12 +154,33 @@ static const struct sx150x_device_data sx150x_devices[] = {
},
.ngpios = 16
},
+ [3] = { /* sx1502q */
+ .model = SX150X_123,
+ .reg_pullup = 0x02,
+ .reg_pulldn = 0x03,
+ .reg_dir = 0x01,
+ .reg_data = 0x00,
+ .reg_irq_mask = 0x05,
+ .reg_irq_src = 0x08,
+ .reg_sense = 0x07,
+ .pri.x123 = {
+ .reg_pld_mode = 0x10,
+ .reg_pld_table0 = 0x11,
+ .reg_pld_table1 = 0x12,
+ .reg_pld_table2 = 0x13,
+ .reg_pld_table3 = 0x14,
+ .reg_pld_table4 = 0x15,
+ .reg_advance = 0xad,
+ },
+ .ngpios = 8,
+ },
};
static const struct i2c_device_id sx150x_id[] = {
{"sx1508q", 0},
{"sx1509q", 1},
{"sx1506q", 2},
+ {"sx1502q", 3},
{}
};
MODULE_DEVICE_TABLE(i2c, sx150x_id);
@@ -156,15 +189,11 @@ static const struct of_device_id sx150x_of_match[] = {
{ .compatible = "semtech,sx1508q" },
{ .compatible = "semtech,sx1509q" },
{ .compatible = "semtech,sx1506q" },
+ { .compatible = "semtech,sx1502q" },
{},
};
MODULE_DEVICE_TABLE(of, sx150x_of_match);
-struct sx150x_chip *to_sx150x(struct gpio_chip *gc)
-{
- return container_of(gc, struct sx150x_chip, gpio_chip);
-}
-
static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
{
s32 err = i2c_smbus_write_byte_data(client, reg, val);
@@ -301,7 +330,7 @@ static int sx150x_io_output(struct sx150x_chip *chip, unsigned offset, int val)
static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct sx150x_chip *chip = to_sx150x(gc);
+ struct sx150x_chip *chip = gpiochip_get_data(gc);
int status = -EINVAL;
if (!offset_is_oscio(chip, offset)) {
@@ -310,12 +339,12 @@ static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset)
mutex_unlock(&chip->lock);
}
- return status;
+ return (status < 0) ? status : !!status;
}
static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
{
- struct sx150x_chip *chip = to_sx150x(gc);
+ struct sx150x_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock);
if (offset_is_oscio(chip, offset))
@@ -327,7 +356,7 @@ static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct sx150x_chip *chip = to_sx150x(gc);
+ struct sx150x_chip *chip = gpiochip_get_data(gc);
int status = -EINVAL;
if (!offset_is_oscio(chip, offset)) {
@@ -342,7 +371,7 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc,
unsigned offset,
int val)
{
- struct sx150x_chip *chip = to_sx150x(gc);
+ struct sx150x_chip *chip = gpiochip_get_data(gc);
int status = 0;
if (!offset_is_oscio(chip, offset)) {
@@ -355,7 +384,7 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc,
static void sx150x_irq_mask(struct irq_data *d)
{
- struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+ struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n = d->hwirq;
chip->irq_masked |= (1 << n);
@@ -364,7 +393,7 @@ static void sx150x_irq_mask(struct irq_data *d)
static void sx150x_irq_unmask(struct irq_data *d)
{
- struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+ struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n = d->hwirq;
chip->irq_masked &= ~(1 << n);
@@ -373,7 +402,7 @@ static void sx150x_irq_unmask(struct irq_data *d)
static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+ struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n, val = 0;
if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
@@ -428,14 +457,14 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
static void sx150x_irq_bus_lock(struct irq_data *d)
{
- struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+ struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
mutex_lock(&chip->lock);
}
static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+ struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n;
if (chip->irq_update == NO_UPDATE_PENDING)
@@ -473,7 +502,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
chip->client = client;
chip->dev_cfg = &sx150x_devices[driver_data];
- chip->gpio_chip.dev = &client->dev;
+ chip->gpio_chip.parent = &client->dev;
chip->gpio_chip.label = client->name;
chip->gpio_chip.direction_input = sx150x_gpio_direction_input;
chip->gpio_chip.direction_output = sx150x_gpio_direction_output;
@@ -545,10 +574,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
err = sx150x_i2c_write(chip->client,
chip->dev_cfg->pri.x789.reg_misc,
0x01);
- else
+ else if (chip->dev_cfg->model == SX150X_456)
err = sx150x_i2c_write(chip->client,
chip->dev_cfg->pri.x456.reg_advance,
0x04);
+ else
+ err = sx150x_i2c_write(chip->client,
+ chip->dev_cfg->pri.x123.reg_advance,
+ 0x00);
if (err < 0)
return err;
@@ -574,13 +607,20 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
pdata->io_polarity);
if (err < 0)
return err;
- } else {
+ } else if (chip->dev_cfg->model == SX150X_456) {
/* Set all pins to work in normal mode */
err = sx150x_init_io(chip,
chip->dev_cfg->pri.x456.reg_pld_mode,
0);
if (err < 0)
return err;
+ } else {
+ /* Set all pins to work in normal mode */
+ err = sx150x_init_io(chip,
+ chip->dev_cfg->pri.x123.reg_pld_mode,
+ 0);
+ if (err < 0)
+ return err;
}
@@ -647,7 +687,7 @@ static int sx150x_probe(struct i2c_client *client,
if (rc < 0)
return rc;
- rc = gpiochip_add(&chip->gpio_chip);
+ rc = gpiochip_add_data(&chip->gpio_chip, chip);
if (rc)
return rc;
@@ -680,7 +720,6 @@ static int sx150x_remove(struct i2c_client *client)
static struct i2c_driver sx150x_driver = {
.driver = {
.name = "sx150x",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(sx150x_of_match),
},
.probe = sx150x_probe,
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 7b25fdf64802..e5c5b6205886 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -59,14 +59,9 @@ struct syscon_gpio_priv {
u32 dir_reg_offset;
};
-static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct syscon_gpio_priv, chip);
-}
-
static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
unsigned int val, offs;
int ret;
@@ -82,7 +77,7 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
unsigned int offs;
offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
@@ -95,7 +90,7 @@ static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
{
- struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
unsigned int offs;
@@ -113,7 +108,7 @@ static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
{
- struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
unsigned int offs;
@@ -144,7 +139,7 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = {
static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
unsigned int offs;
int ret;
@@ -159,7 +154,7 @@ static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT,
BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT);
if (ret < 0)
- dev_err(chip->dev, "gpio write failed ret(%d)\n", ret);
+ dev_err(chip->parent, "gpio write failed ret(%d)\n", ret);
}
static const struct syscon_gpio_data keystone_dsp_gpio = {
@@ -228,7 +223,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
priv->dir_reg_offset <<= 3;
}
- priv->chip.dev = dev;
+ priv->chip.parent = dev;
priv->chip.owner = THIS_MODULE;
priv->chip.label = dev_name(dev);
priv->chip.base = -1;
@@ -243,7 +238,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- return gpiochip_add(&priv->chip);
+ return gpiochip_add_data(&priv->chip, priv);
}
static int syscon_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 4356e6c20fc5..5eaec20ddbc7 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -87,14 +87,9 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs,
spin_unlock_irqrestore(&gpio->spinlock, flags);
}
-static inline struct tb10x_gpio *to_tb10x_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct tb10x_gpio, gc);
-}
-
static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int mask = BIT(offset);
int val = TB10X_GPIO_DIR_IN << offset;
@@ -105,7 +100,7 @@ static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int val;
val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA);
@@ -118,7 +113,7 @@ static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int mask = BIT(offset);
int val = value << offset;
@@ -128,7 +123,7 @@ static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int tb10x_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
int mask = BIT(offset);
int val = TB10X_GPIO_DIR_OUT << offset;
@@ -140,7 +135,7 @@ static int tb10x_gpio_direction_out(struct gpio_chip *chip,
static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
return irq_create_mapping(tb10x_gpio->domain, offset);
}
@@ -197,7 +192,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
return PTR_ERR(tb10x_gpio->base);
tb10x_gpio->gc.label = of_node_full_name(dn);
- tb10x_gpio->gc.dev = &pdev->dev;
+ tb10x_gpio->gc.parent = &pdev->dev;
tb10x_gpio->gc.owner = THIS_MODULE;
tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in;
tb10x_gpio->gc.get = tb10x_gpio_get;
@@ -210,7 +205,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
tb10x_gpio->gc.can_sleep = false;
- ret = gpiochip_add(&tb10x_gpio->gc);
+ ret = gpiochip_add_data(&tb10x_gpio->gc, tb10x_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not add gpiochip.\n");
goto fail_gpiochip_registration;
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index d1d585ddb9ab..05a27ec55add 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -34,14 +34,9 @@ struct tc3589x_gpio {
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};
-static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct tc3589x_gpio, chip);
-}
-
static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
u8 mask = 1 << (offset % 8);
@@ -51,12 +46,12 @@ static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
if (ret < 0)
return ret;
- return ret & mask;
+ return !!(ret & mask);
}
static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
unsigned pos = offset % 8;
@@ -68,7 +63,7 @@ static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
@@ -81,7 +76,7 @@ static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
@@ -102,7 +97,7 @@ static struct gpio_chip template_chip = {
static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -130,7 +125,7 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void tc3589x_gpio_irq_lock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
mutex_lock(&tc3589x_gpio->irq_lock);
}
@@ -138,7 +133,7 @@ static void tc3589x_gpio_irq_lock(struct irq_data *d)
static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
static const u8 regmap[] = {
[REG_IBE] = TC3589x_GPIOIBE0,
@@ -167,7 +162,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
static void tc3589x_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -178,7 +173,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
static void tc3589x_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -258,7 +253,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
tc3589x_gpio->chip = template_chip;
tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
- tc3589x_gpio->chip.dev = &pdev->dev;
+ tc3589x_gpio->chip.parent = &pdev->dev;
tc3589x_gpio->chip.base = -1;
tc3589x_gpio->chip.of_node = np;
@@ -277,7 +272,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
return ret;
}
- ret = gpiochip_add(&tc3589x_gpio->chip);
+ ret = gpiochip_add_data(&tc3589x_gpio->chip, tc3589x_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 896bf29776b0..9a1a7e2ef388 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -545,7 +545,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
tegra_gpio_chip.of_node = pdev->dev.of_node;
- ret = gpiochip_add(&tegra_gpio_chip);
+ ret = gpiochip_add_data(&tegra_gpio_chip, NULL);
if (ret < 0) {
irq_domain_remove(irq_domain);
return ret;
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 30653e6319e9..a6de10c5275b 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -53,7 +53,7 @@ struct timbgpio {
static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
unsigned offset, bool enabled)
{
- struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+ struct timbgpio *tgpio = gpiochip_get_data(gpio);
u32 reg;
spin_lock(&tgpio->lock);
@@ -77,7 +77,7 @@ static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
- struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+ struct timbgpio *tgpio = gpiochip_get_data(gpio);
u32 value;
value = ioread32(tgpio->membase + TGPIOVAL);
@@ -98,7 +98,7 @@ static void timbgpio_gpio_set(struct gpio_chip *gpio,
static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
- struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+ struct timbgpio *tgpio = gpiochip_get_data(gpio);
if (tgpio->irq_base <= 0)
return -EINVAL;
@@ -268,7 +268,7 @@ static int timbgpio_probe(struct platform_device *pdev)
gc->label = dev_name(&pdev->dev);
gc->owner = THIS_MODULE;
- gc->dev = &pdev->dev;
+ gc->parent = &pdev->dev;
gc->direction_input = timbgpio_gpio_direction_input;
gc->get = timbgpio_gpio_get;
gc->direction_output = timbgpio_gpio_direction_output;
@@ -279,7 +279,7 @@ static int timbgpio_probe(struct platform_device *pdev)
gc->ngpio = pdata->nr_pins;
gc->can_sleep = false;
- err = gpiochip_add(gc);
+ err = gpiochip_add_data(gc, tgpio);
if (err)
return err;
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 9c9238e838a9..87de5486a29e 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -38,14 +38,9 @@ struct tps6586x_gpio {
struct device *parent;
};
-static inline struct tps6586x_gpio *to_tps6586x_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct tps6586x_gpio, gpio_chip);
-}
-
static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+ struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
uint8_t val;
int ret;
@@ -59,7 +54,7 @@ static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+ struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2,
value << offset, 1 << offset);
@@ -68,7 +63,7 @@ static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset,
static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+ struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
uint8_t val, mask;
tps6586x_gpio_set(gc, offset, value);
@@ -82,7 +77,7 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+ struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
return tps6586x_irq_get_virq(tps6586x_gpio->parent,
TPS6586X_INT_PLDO_0 + offset);
@@ -104,7 +99,7 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
tps6586x_gpio->gpio_chip.owner = THIS_MODULE;
tps6586x_gpio->gpio_chip.label = pdev->name;
- tps6586x_gpio->gpio_chip.dev = &pdev->dev;
+ tps6586x_gpio->gpio_chip.parent = &pdev->dev;
tps6586x_gpio->gpio_chip.ngpio = 4;
tps6586x_gpio->gpio_chip.can_sleep = true;
@@ -122,7 +117,7 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
else
tps6586x_gpio->gpio_chip.base = -1;
- ret = gpiochip_add(&tps6586x_gpio->gpio_chip);
+ ret = gpiochip_add_data(&tps6586x_gpio->gpio_chip, tps6586x_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 88f1f5ff4e96..e81eee7627a3 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -27,14 +27,9 @@ struct tps65910_gpio {
struct tps65910 *tps65910;
};
-static inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct tps65910_gpio, gpio_chip);
-}
-
static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
unsigned int val;
@@ -49,7 +44,7 @@ static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
if (value)
@@ -63,7 +58,7 @@ static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
/* Set the initial value */
@@ -75,7 +70,7 @@ static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
{
- struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+ struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
@@ -146,7 +141,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev)
tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output;
tps65910_gpio->gpio_chip.set = tps65910_gpio_set;
tps65910_gpio->gpio_chip.get = tps65910_gpio_get;
- tps65910_gpio->gpio_chip.dev = &pdev->dev;
+ tps65910_gpio->gpio_chip.parent = &pdev->dev;
#ifdef CONFIG_OF_GPIO
tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node;
#endif
@@ -175,7 +170,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev)
}
skip_init:
- ret = gpiochip_add(&tps65910_gpio->gpio_chip);
+ ret = gpiochip_add_data(&tps65910_gpio->gpio_chip, tps65910_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 9cdbc0c9cb2d..4f2029c7da3a 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -26,11 +26,9 @@ struct tps65912_gpio_data {
struct gpio_chip gpio_chip;
};
-#define to_tgd(gc) container_of(gc, struct tps65912_gpio_data, gpio_chip)
-
static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+ struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
struct tps65912 *tps65912 = tps65912_gpio->tps65912;
int val;
@@ -45,7 +43,7 @@ static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+ struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
struct tps65912 *tps65912 = tps65912_gpio->tps65912;
if (value)
@@ -59,7 +57,7 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+ struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
struct tps65912 *tps65912 = tps65912_gpio->tps65912;
/* Set the initial value */
@@ -71,7 +69,7 @@ static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
{
- struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+ struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
struct tps65912 *tps65912 = tps65912_gpio->tps65912;
return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
@@ -104,11 +102,11 @@ static int tps65912_gpio_probe(struct platform_device *pdev)
tps65912_gpio->tps65912 = tps65912;
tps65912_gpio->gpio_chip = template_chip;
- tps65912_gpio->gpio_chip.dev = &pdev->dev;
+ tps65912_gpio->gpio_chip.parent = &pdev->dev;
if (pdata && pdata->gpio_base)
tps65912_gpio->gpio_chip.base = pdata->gpio_base;
- ret = gpiochip_add(&tps65912_gpio->gpio_chip);
+ ret = gpiochip_add_data(&tps65912_gpio->gpio_chip, tps65912_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
index b29a102d136b..5f945083f9d8 100644
--- a/drivers/gpio/gpio-ts5500.c
+++ b/drivers/gpio/gpio-ts5500.c
@@ -185,11 +185,6 @@ static const struct ts5500_dio ts5500_lcd[] = {
TS5500_DIO_IN_IRQ(0x73, 7, 1),
};
-static inline struct ts5500_priv *ts5500_gc_to_priv(struct gpio_chip *chip)
-{
- return container_of(chip, struct ts5500_priv, gpio_chip);
-}
-
static inline void ts5500_set_mask(u8 mask, u8 addr)
{
u8 val = inb(addr);
@@ -206,7 +201,7 @@ static inline void ts5500_clear_mask(u8 mask, u8 addr)
static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
{
- struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ struct ts5500_priv *priv = gpiochip_get_data(chip);
const struct ts5500_dio line = priv->pinout[offset];
unsigned long flags;
@@ -225,7 +220,7 @@ static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ struct ts5500_priv *priv = gpiochip_get_data(chip);
const struct ts5500_dio line = priv->pinout[offset];
return !!(inb(line.value_addr) & line.value_mask);
@@ -233,7 +228,7 @@ static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
{
- struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ struct ts5500_priv *priv = gpiochip_get_data(chip);
const struct ts5500_dio line = priv->pinout[offset];
unsigned long flags;
@@ -255,7 +250,7 @@ static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
static void ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ struct ts5500_priv *priv = gpiochip_get_data(chip);
const struct ts5500_dio line = priv->pinout[offset];
unsigned long flags;
@@ -269,7 +264,7 @@ static void ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ struct ts5500_priv *priv = gpiochip_get_data(chip);
const struct ts5500_dio *block = priv->pinout;
const struct ts5500_dio line = block[offset];
@@ -315,7 +310,8 @@ static void ts5500_disable_irq(struct ts5500_priv *priv)
else if (priv->hwirq == 1)
ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
else
- dev_err(priv->gpio_chip.dev, "invalid hwirq %d\n", priv->hwirq);
+ dev_err(priv->gpio_chip.parent, "invalid hwirq %d\n",
+ priv->hwirq);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -346,7 +342,7 @@ static int ts5500_dio_probe(struct platform_device *pdev)
priv->gpio_chip.owner = THIS_MODULE;
priv->gpio_chip.label = name;
- priv->gpio_chip.dev = dev;
+ priv->gpio_chip.parent = dev;
priv->gpio_chip.direction_input = ts5500_gpio_input;
priv->gpio_chip.direction_output = ts5500_gpio_output;
priv->gpio_chip.get = ts5500_gpio_get;
@@ -413,7 +409,7 @@ static int ts5500_dio_probe(struct platform_device *pdev)
break;
}
- ret = gpiochip_add(&priv->gpio_chip);
+ ret = gpiochip_add_data(&priv->gpio_chip, priv);
if (ret) {
dev_err(dev, "failed to register the gpio chip\n");
return ret;
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 9e1dbb9877c1..4b807b0e0c8e 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -76,11 +76,6 @@ struct gpio_twl4030_priv {
/*----------------------------------------------------------------------*/
-static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip)
-{
- return container_of(chip, struct gpio_twl4030_priv, gpio_chip);
-}
-
/*
* To configure TWL4030 GPIO module registers
*/
@@ -205,7 +200,7 @@ static int twl4030_get_gpio_datain(int gpio)
static int twl_request(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
int status = 0;
mutex_lock(&priv->mutex);
@@ -256,7 +251,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
/* optionally have the first two GPIOs switch vMMC1
* and vMMC2 power supplies based on card presence.
*/
- pdata = dev_get_platdata(chip->dev);
+ pdata = dev_get_platdata(chip->parent);
if (pdata)
value |= pdata->mmc_cd & 0x03;
@@ -273,7 +268,7 @@ done:
static void twl_free(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
mutex_lock(&priv->mutex);
if (offset >= TWL4030_GPIO_MAX) {
@@ -293,7 +288,7 @@ out:
static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
int ret;
mutex_lock(&priv->mutex);
@@ -312,7 +307,7 @@ static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
static int twl_get(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
int ret;
int status = 0;
@@ -327,7 +322,7 @@ static int twl_get(struct gpio_chip *chip, unsigned offset)
else
status = twl4030_get_gpio_datain(offset);
- ret = (status <= 0) ? 0 : 1;
+ ret = (status < 0) ? status : !!status;
out:
mutex_unlock(&priv->mutex);
return ret;
@@ -335,7 +330,7 @@ out:
static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
@@ -353,7 +348,7 @@ static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
int ret = 0;
mutex_lock(&priv->mutex);
@@ -379,7 +374,7 @@ static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
? (priv->irq_base + offset)
@@ -509,7 +504,7 @@ no_irqs:
priv->gpio_chip = template_chip;
priv->gpio_chip.base = -1;
priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
- priv->gpio_chip.dev = &pdev->dev;
+ priv->gpio_chip.parent = &pdev->dev;
mutex_init(&priv->mutex);
@@ -544,7 +539,7 @@ no_irqs:
if (pdata->use_leds)
priv->gpio_chip.ngpio += 2;
- ret = gpiochip_add(&priv->gpio_chip);
+ ret = gpiochip_add_data(&priv->gpio_chip, priv);
if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
priv->gpio_chip.ngpio = 0;
diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c
index c946e7eef3ee..8e9e9853f3bd 100644
--- a/drivers/gpio/gpio-twl6040.c
+++ b/drivers/gpio/gpio-twl6040.c
@@ -36,7 +36,7 @@ static struct gpio_chip twl6040gpo_chip;
static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
{
- struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent);
+ struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
int ret = 0;
ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL);
@@ -55,7 +55,7 @@ static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent);
+ struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
int ret;
u8 gpoctl;
@@ -95,12 +95,12 @@ static int gpo_twl6040_probe(struct platform_device *pdev)
else
twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */
- twl6040gpo_chip.dev = &pdev->dev;
+ twl6040gpo_chip.parent = &pdev->dev;
#ifdef CONFIG_OF_GPIO
twl6040gpo_chip.of_node = twl6040_core_dev->of_node;
#endif
- ret = gpiochip_add(&twl6040gpo_chip);
+ ret = gpiochip_add_data(&twl6040gpo_chip, NULL);
if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
twl6040gpo_chip.ngpio = 0;
diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c
index 3623d009d808..5b7781741ee9 100644
--- a/drivers/gpio/gpio-tz1090-pdc.c
+++ b/drivers/gpio/gpio-tz1090-pdc.c
@@ -49,7 +49,6 @@ struct tz1090_pdc_gpio {
void __iomem *reg;
int irq[GPIO_PDC_NIRQ];
};
-#define to_pdc(c) container_of(c, struct tz1090_pdc_gpio, chip)
/* Register accesses into the PDC MMIO area */
@@ -70,7 +69,7 @@ static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv,
static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
- struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
u32 value;
int lstat;
@@ -87,7 +86,7 @@ static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset,
int output_value)
{
- struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
u32 value;
int lstat;
@@ -112,14 +111,14 @@ static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
- struct tz1090_pdc_gpio *priv = to_pdc(chip);
- return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset);
+ struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
+ return !!(pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset));
}
static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
int output_value)
{
- struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
u32 value;
int lstat;
@@ -139,7 +138,7 @@ static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
{
- struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
int irq;
@@ -188,7 +187,7 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
/* Set up GPIO chip */
priv->chip.label = "tz1090-pdc-gpio";
- priv->chip.dev = &pdev->dev;
+ priv->chip.parent = &pdev->dev;
priv->chip.direction_input = tz1090_pdc_gpio_direction_input;
priv->chip.direction_output = tz1090_pdc_gpio_direction_output;
priv->chip.get = tz1090_pdc_gpio_get;
@@ -207,7 +206,7 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
priv->irq[i] = irq_of_parse_and_map(np, i);
/* Add the GPIO bank */
- gpiochip_add(&priv->chip);
+ gpiochip_add_data(&priv->chip, priv);
return 0;
}
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
index 87bb1b1eee8d..ca958e0f6909 100644
--- a/drivers/gpio/gpio-tz1090.c
+++ b/drivers/gpio/gpio-tz1090.c
@@ -62,7 +62,6 @@ struct tz1090_gpio_bank {
int irq;
char label[16];
};
-#define to_bank(c) container_of(c, struct tz1090_gpio_bank, chip)
/**
* struct tz1090_gpio - Overall GPIO device private data
@@ -187,7 +186,7 @@ static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank,
static int tz1090_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
return 0;
@@ -196,7 +195,7 @@ static int tz1090_gpio_direction_input(struct gpio_chip *chip,
static int tz1090_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int output_value)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
int lstat;
__global_lock2(lstat);
@@ -212,9 +211,9 @@ static int tz1090_gpio_direction_output(struct gpio_chip *chip,
*/
static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
- return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
+ return !!tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
}
/*
@@ -223,14 +222,14 @@ static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset,
int output_value)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
}
static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
int ret;
ret = pinctrl_request_gpio(chip->base + offset);
@@ -245,7 +244,7 @@ static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
pinctrl_free_gpio(chip->base + offset);
@@ -254,7 +253,7 @@ static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
{
- struct tz1090_gpio_bank *bank = to_bank(chip);
+ struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
if (!bank->domain)
return -EINVAL;
@@ -425,7 +424,7 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u",
info->index);
bank->chip.label = bank->label;
- bank->chip.dev = dev;
+ bank->chip.parent = dev;
bank->chip.direction_input = tz1090_gpio_direction_input;
bank->chip.direction_output = tz1090_gpio_direction_output;
bank->chip.get = tz1090_gpio_get;
@@ -440,7 +439,7 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
bank->chip.ngpio = 30;
/* Add the GPIO bank */
- gpiochip_add(&bank->chip);
+ gpiochip_add_data(&bank->chip, bank);
/* Get the GPIO bank IRQ if provided */
bank->irq = irq_of_parse_and_map(np, 0);
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index d502825159b9..2c5cd46bfa6e 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -15,7 +15,7 @@
static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
{
struct ucb1400_gpio *gpio;
- gpio = container_of(gc, struct ucb1400_gpio, gc);
+ gpio = gpiochip_get_data(gc);
ucb1400_gpio_set_direction(gpio->ac97, off, 0);
return 0;
}
@@ -23,7 +23,7 @@ static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
static int ucb1400_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
{
struct ucb1400_gpio *gpio;
- gpio = container_of(gc, struct ucb1400_gpio, gc);
+ gpio = gpiochip_get_data(gc);
ucb1400_gpio_set_direction(gpio->ac97, off, 1);
ucb1400_gpio_set_value(gpio->ac97, off, val);
return 0;
@@ -32,14 +32,15 @@ static int ucb1400_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
static int ucb1400_gpio_get(struct gpio_chip *gc, unsigned off)
{
struct ucb1400_gpio *gpio;
- gpio = container_of(gc, struct ucb1400_gpio, gc);
- return ucb1400_gpio_get_value(gpio->ac97, off);
+
+ gpio = gpiochip_get_data(gc);
+ return !!ucb1400_gpio_get_value(gpio->ac97, off);
}
static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val)
{
struct ucb1400_gpio *gpio;
- gpio = container_of(gc, struct ucb1400_gpio, gc);
+ gpio = gpiochip_get_data(gc);
ucb1400_gpio_set_value(gpio->ac97, off, val);
}
@@ -66,7 +67,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
ucb->gc.set = ucb1400_gpio_set;
ucb->gc.can_sleep = true;
- err = gpiochip_add(&ucb->gc);
+ err = gpiochip_add_data(&ucb->gc, ucb);
if (err)
goto err;
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 87b950cec6ec..6284bdbe1e0c 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -62,11 +62,6 @@ struct vf610_gpio_port {
static struct irq_chip vf610_gpio_irq_chip;
-static struct vf610_gpio_port *to_vf610_gp(struct gpio_chip *gc)
-{
- return container_of(gc, struct vf610_gpio_port, gc);
-}
-
static const struct of_device_id vf610_gpio_dt_ids[] = {
{ .compatible = "fsl,vf610-gpio" },
{ /* sentinel */ }
@@ -84,14 +79,14 @@ static inline u32 vf610_gpio_readl(void __iomem *reg)
static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
- struct vf610_gpio_port *port = to_vf610_gp(gc);
+ struct vf610_gpio_port *port = gpiochip_get_data(gc);
return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
}
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct vf610_gpio_port *port = to_vf610_gp(gc);
+ struct vf610_gpio_port *port = gpiochip_get_data(gc);
unsigned long mask = BIT(gpio);
if (val)
@@ -116,7 +111,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
static void vf610_gpio_irq_handler(struct irq_desc *desc)
{
struct vf610_gpio_port *port =
- to_vf610_gp(irq_desc_get_handler_data(desc));
+ gpiochip_get_data(irq_desc_get_handler_data(desc));
struct irq_chip *chip = irq_desc_get_chip(desc);
int pin;
unsigned long irq_isfr;
@@ -137,7 +132,7 @@ static void vf610_gpio_irq_handler(struct irq_desc *desc)
static void vf610_gpio_irq_ack(struct irq_data *d)
{
struct vf610_gpio_port *port =
- to_vf610_gp(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
int gpio = d->hwirq;
vf610_gpio_writel(BIT(gpio), port->base + PORT_ISFR);
@@ -146,7 +141,7 @@ static void vf610_gpio_irq_ack(struct irq_data *d)
static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
{
struct vf610_gpio_port *port =
- to_vf610_gp(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
u8 irqc;
switch (type) {
@@ -182,7 +177,7 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
static void vf610_gpio_irq_mask(struct irq_data *d)
{
struct vf610_gpio_port *port =
- to_vf610_gp(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
vf610_gpio_writel(0, pcr_base);
@@ -191,7 +186,7 @@ static void vf610_gpio_irq_mask(struct irq_data *d)
static void vf610_gpio_irq_unmask(struct irq_data *d)
{
struct vf610_gpio_port *port =
- to_vf610_gp(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET,
@@ -201,7 +196,7 @@ static void vf610_gpio_irq_unmask(struct irq_data *d)
static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable)
{
struct vf610_gpio_port *port =
- to_vf610_gp(irq_data_get_irq_chip_data(d));
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
if (enable)
enable_irq_wake(port->irq);
@@ -249,7 +244,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
gc = &port->gc;
gc->of_node = np;
- gc->dev = dev;
+ gc->parent = dev;
gc->label = "vf610-gpio";
gc->ngpio = VF610_GPIO_PER_PORT;
gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
@@ -261,7 +256,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
gc->direction_output = vf610_gpio_direction_output;
gc->set = vf610_gpio_set;
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, port);
if (ret < 0)
return ret;
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index e2a11f27807f..1170b035cb92 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -88,14 +88,13 @@ static int vprbrd_gpioa_get(struct gpio_chip *chip,
unsigned offset)
{
int ret, answer, error = 0;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
/* if io is set to output, just return the saved value */
if (gpio->gpioa_out & (1 << offset))
- return gpio->gpioa_val & (1 << offset);
+ return !!(gpio->gpioa_val & (1 << offset));
mutex_lock(&vb->lock);
@@ -139,8 +138,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip,
unsigned offset, int value)
{
int ret;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
@@ -173,7 +171,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip,
mutex_unlock(&vb->lock);
if (ret != sizeof(struct vprbrd_gpioa_msg))
- dev_err(chip->dev, "usb error setting pin value\n");
+ dev_err(chip->parent, "usb error setting pin value\n");
}
}
@@ -181,8 +179,7 @@ static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
unsigned offset)
{
int ret;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
@@ -219,8 +216,7 @@ static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
int ret;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
@@ -287,8 +283,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip,
{
int ret;
u16 val;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
@@ -319,8 +314,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
unsigned offset, int value)
{
int ret;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
@@ -345,7 +339,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
mutex_unlock(&vb->lock);
if (ret != sizeof(struct vprbrd_gpiob_msg))
- dev_err(chip->dev, "usb error setting pin value\n");
+ dev_err(chip->parent, "usb error setting pin value\n");
}
}
@@ -353,8 +347,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
unsigned offset)
{
int ret;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
gpio->gpiob_out &= ~(1 << offset);
@@ -366,7 +359,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
mutex_unlock(&vb->lock);
if (ret)
- dev_err(chip->dev, "usb error setting pin to input\n");
+ dev_err(chip->parent, "usb error setting pin to input\n");
return ret;
}
@@ -375,8 +368,7 @@ static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
int ret;
- struct vprbrd_gpio *gpio =
- container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
struct vprbrd *vb = gpio->vb;
gpio->gpiob_out |= (1 << offset);
@@ -385,7 +377,7 @@ static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
ret = vprbrd_gpiob_setdir(vb, offset, 1);
if (ret)
- dev_err(chip->dev, "usb error setting pin to output\n");
+ dev_err(chip->parent, "usb error setting pin to output\n");
mutex_unlock(&vb->lock);
@@ -409,7 +401,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
vb_gpio->vb = vb;
/* registering gpio a */
vb_gpio->gpioa.label = "viperboard gpio a";
- vb_gpio->gpioa.dev = &pdev->dev;
+ vb_gpio->gpioa.parent = &pdev->dev;
vb_gpio->gpioa.owner = THIS_MODULE;
vb_gpio->gpioa.base = -1;
vb_gpio->gpioa.ngpio = 16;
@@ -418,15 +410,15 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
vb_gpio->gpioa.get = vprbrd_gpioa_get;
vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input;
vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output;
- ret = gpiochip_add(&vb_gpio->gpioa);
+ ret = gpiochip_add_data(&vb_gpio->gpioa, vb_gpio);
if (ret < 0) {
- dev_err(vb_gpio->gpioa.dev, "could not add gpio a");
+ dev_err(vb_gpio->gpioa.parent, "could not add gpio a");
goto err_gpioa;
}
/* registering gpio b */
vb_gpio->gpiob.label = "viperboard gpio b";
- vb_gpio->gpiob.dev = &pdev->dev;
+ vb_gpio->gpiob.parent = &pdev->dev;
vb_gpio->gpiob.owner = THIS_MODULE;
vb_gpio->gpiob.base = -1;
vb_gpio->gpiob.ngpio = 16;
@@ -435,9 +427,9 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
vb_gpio->gpiob.get = vprbrd_gpiob_get;
vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input;
vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output;
- ret = gpiochip_add(&vb_gpio->gpiob);
+ ret = gpiochip_add_data(&vb_gpio->gpiob, vb_gpio);
if (ret < 0) {
- dev_err(vb_gpio->gpiob.dev, "could not add gpio b");
+ dev_err(vb_gpio->gpiob.parent, "could not add gpio b");
goto err_gpiob;
}
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index c1caa459c02d..ac8deb01f6f6 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -139,7 +139,7 @@ static void unmask_giuint_low(struct irq_data *d)
static unsigned int startup_giuint(struct irq_data *data)
{
if (gpiochip_lock_as_irq(&vr41xx_gpio_chip, data->hwirq))
- dev_err(vr41xx_gpio_chip.dev,
+ dev_err(vr41xx_gpio_chip.parent,
"unable to lock HW IRQ %lu for IRQ\n",
data->hwirq);
/* Satisfy the .enable semantics by unmasking the line */
@@ -542,9 +542,9 @@ static int giu_probe(struct platform_device *pdev)
if (!giu_base)
return -ENOMEM;
- vr41xx_gpio_chip.dev = &pdev->dev;
+ vr41xx_gpio_chip.parent = &pdev->dev;
- ret = gpiochip_add(&vr41xx_gpio_chip);
+ ret = gpiochip_add_data(&vr41xx_gpio_chip, NULL);
if (!ret) {
iounmap(giu_base);
return -ENODEV;
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 57b470d5b39e..764999cc0794 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -96,7 +96,7 @@ static inline u_int32_t gpio_o_bit(int i)
static int vx855gpio_direction_input(struct gpio_chip *gpio,
unsigned int nr)
{
- struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+ struct vx855_gpio *vg = gpiochip_get_data(gpio);
unsigned long flags;
u_int32_t reg_out;
@@ -120,7 +120,7 @@ static int vx855gpio_direction_input(struct gpio_chip *gpio,
static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
{
- struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+ struct vx855_gpio *vg = gpiochip_get_data(gpio);
u_int32_t reg_in;
int ret = 0;
@@ -146,7 +146,7 @@ static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr,
int val)
{
- struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+ struct vx855_gpio *vg = gpiochip_get_data(gpio);
unsigned long flags;
u_int32_t reg_out;
@@ -259,7 +259,7 @@ static int vx855gpio_probe(struct platform_device *pdev)
vx855gpio_gpio_setup(vg);
- return gpiochip_add(&vg->gpio);
+ return gpiochip_add_data(&vg->gpio, vg);
}
static int vx855gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 58ce75c188b7..98390070fb64 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -30,14 +30,9 @@ struct wm831x_gpio {
struct gpio_chip gpio_chip;
};
-static inline struct wm831x_gpio *to_wm831x_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm831x_gpio, gpio_chip);
-}
-
static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int val = WM831X_GPN_DIR;
@@ -51,7 +46,7 @@ static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int ret;
@@ -67,7 +62,7 @@ static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
@@ -77,7 +72,7 @@ static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int wm831x_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int val = 0;
int ret;
@@ -99,7 +94,7 @@ static int wm831x_gpio_direction_out(struct gpio_chip *chip,
static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
return irq_create_mapping(wm831x->irq_domain,
@@ -109,7 +104,7 @@ static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
unsigned debounce)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int reg = WM831X_GPIO1_CONTROL + offset;
int ret, fn;
@@ -140,7 +135,7 @@ static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
#ifdef CONFIG_DEBUG_FS
static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int i, tristated;
@@ -258,13 +253,13 @@ static int wm831x_gpio_probe(struct platform_device *pdev)
wm831x_gpio->wm831x = wm831x;
wm831x_gpio->gpio_chip = template_chip;
wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
- wm831x_gpio->gpio_chip.dev = &pdev->dev;
+ wm831x_gpio->gpio_chip.parent = &pdev->dev;
if (pdata && pdata->gpio_base)
wm831x_gpio->gpio_chip.base = pdata->gpio_base;
else
wm831x_gpio->gpio_chip.base = -1;
- ret = gpiochip_add(&wm831x_gpio->gpio_chip);
+ ret = gpiochip_add_data(&wm831x_gpio->gpio_chip, wm831x_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index 060b89303bb6..0a306b4baa73 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -28,14 +28,9 @@ struct wm8350_gpio_data {
struct gpio_chip gpio_chip;
};
-static inline struct wm8350_gpio_data *to_wm8350_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm8350_gpio_data, gpio_chip);
-}
-
static int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
struct wm8350 *wm8350 = wm8350_gpio->wm8350;
return wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O,
@@ -44,7 +39,7 @@ static int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
struct wm8350 *wm8350 = wm8350_gpio->wm8350;
int ret;
@@ -60,7 +55,7 @@ static int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset)
static void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
struct wm8350 *wm8350 = wm8350_gpio->wm8350;
if (value)
@@ -72,7 +67,7 @@ static void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int wm8350_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
struct wm8350 *wm8350 = wm8350_gpio->wm8350;
int ret;
@@ -89,7 +84,7 @@ static int wm8350_gpio_direction_out(struct gpio_chip *chip,
static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
struct wm8350 *wm8350 = wm8350_gpio->wm8350;
if (!wm8350->irq_base)
@@ -124,13 +119,13 @@ static int wm8350_gpio_probe(struct platform_device *pdev)
wm8350_gpio->wm8350 = wm8350;
wm8350_gpio->gpio_chip = template_chip;
wm8350_gpio->gpio_chip.ngpio = 13;
- wm8350_gpio->gpio_chip.dev = &pdev->dev;
+ wm8350_gpio->gpio_chip.parent = &pdev->dev;
if (pdata && pdata->gpio_base)
wm8350_gpio->gpio_chip.base = pdata->gpio_base;
else
wm8350_gpio->gpio_chip.base = -1;
- ret = gpiochip_add(&wm8350_gpio->gpio_chip);
+ ret = gpiochip_add_data(&wm8350_gpio->gpio_chip, wm8350_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 6f5e42db4b9e..3ae4c1597494 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -31,14 +31,9 @@ struct wm8994_gpio {
struct gpio_chip gpio_chip;
};
-static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm8994_gpio, gpio_chip);
-}
-
static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
switch (wm8994->type) {
@@ -61,7 +56,7 @@ static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
@@ -70,7 +65,7 @@ static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
int ret;
@@ -87,7 +82,7 @@ static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset)
static int wm8994_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
if (value)
@@ -99,7 +94,7 @@ static int wm8994_gpio_direction_out(struct gpio_chip *chip,
static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
if (value)
@@ -110,7 +105,7 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
return regmap_irq_get_virq(wm8994->irq_data, offset);
@@ -174,7 +169,7 @@ static const char *wm8994_gpio_fn(u16 fn)
static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
int i;
@@ -260,13 +255,13 @@ static int wm8994_gpio_probe(struct platform_device *pdev)
wm8994_gpio->wm8994 = wm8994;
wm8994_gpio->gpio_chip = template_chip;
wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX;
- wm8994_gpio->gpio_chip.dev = &pdev->dev;
+ wm8994_gpio->gpio_chip.parent = &pdev->dev;
if (pdata && pdata->gpio_base)
wm8994_gpio->gpio_chip.base = pdata->gpio_base;
else
wm8994_gpio->gpio_chip.base = -1;
- ret = gpiochip_add(&wm8994_gpio->gpio_chip);
+ ret = gpiochip_add_data(&wm8994_gpio->gpio_chip, wm8994_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
ret);
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index d57068b9083e..282004deb5d4 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -23,10 +23,8 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/acpi.h>
-#include <linux/basic_mmio_gpio.h>
#include "gpiolib.h"
@@ -43,38 +41,31 @@
/**
* struct xgene_gpio_sb - GPIO-Standby private data structure.
- * @bgc: memory-mapped GPIO controllers.
+ * @gc: memory-mapped GPIO controllers.
* @irq: Mapping GPIO pins and interrupt number
* nirq: Number of GPIO pins that supports interrupt
*/
struct xgene_gpio_sb {
- struct bgpio_chip bgc;
+ struct gpio_chip gc;
u32 *irq;
u32 nirq;
};
-static inline struct xgene_gpio_sb *to_xgene_gpio_sb(struct gpio_chip *gc)
-{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- return container_of(bgc, struct xgene_gpio_sb, bgc);
-}
-
-static void xgene_gpio_set_bit(struct bgpio_chip *bgc, void __iomem *reg, u32 gpio, int val)
+static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio, int val)
{
u32 data;
- data = bgc->read_reg(reg);
+ data = gc->read_reg(reg);
if (val)
data |= GPIO_MASK(gpio);
else
data &= ~GPIO_MASK(gpio);
- bgc->write_reg(reg, data);
+ gc->write_reg(reg, data);
}
static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
{
- struct xgene_gpio_sb *priv = to_xgene_gpio_sb(gc);
+ struct xgene_gpio_sb *priv = gpiochip_get_data(gc);
if (priv->irq[gpio])
return priv->irq[gpio];
@@ -99,15 +90,15 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
if (IS_ERR(regs))
return PTR_ERR(regs);
- ret = bgpio_init(&priv->bgc, &pdev->dev, 4,
+ ret = bgpio_init(&priv->gc, &pdev->dev, 4,
regs + MPA_GPIO_IN_ADDR,
regs + MPA_GPIO_OUT_ADDR, NULL,
regs + MPA_GPIO_OE_ADDR, NULL, 0);
if (ret)
return ret;
- priv->bgc.gc.to_irq = apm_gpio_sb_to_irq;
- priv->bgc.gc.ngpio = XGENE_MAX_GPIO_DS;
+ priv->gc.to_irq = apm_gpio_sb_to_irq;
+ priv->gc.ngpio = XGENE_MAX_GPIO_DS;
priv->nirq = XGENE_MAX_GPIO_DS_IRQ;
@@ -118,14 +109,14 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
for (i = 0; i < priv->nirq; i++) {
priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
- xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_SEL_LO,
+ xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_SEL_LO,
default_lines[i] * 2, 1);
- xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_INT_LVL, i, 1);
+ xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_INT_LVL, i, 1);
}
platform_set_drvdata(pdev, priv);
- ret = gpiochip_add(&priv->bgc.gc);
+ ret = gpiochip_add_data(&priv->gc, priv);
if (ret)
dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n");
else
@@ -133,7 +124,7 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
if (priv->nirq > 0) {
/* Register interrupt handlers for gpio signaled acpi events */
- acpi_gpiochip_request_interrupts(&priv->bgc.gc);
+ acpi_gpiochip_request_interrupts(&priv->gc);
}
return ret;
@@ -144,10 +135,11 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)
struct xgene_gpio_sb *priv = platform_get_drvdata(pdev);
if (priv->nirq > 0) {
- acpi_gpiochip_free_interrupts(&priv->bgc.gc);
+ acpi_gpiochip_free_interrupts(&priv->gc);
}
- return bgpio_remove(&priv->bgc);
+ gpiochip_remove(&priv->gc);
+ return 0;
}
static const struct of_device_id xgene_gpio_sb_of_match[] = {
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
index 18a8182d4fec..592e9cdf9c53 100644
--- a/drivers/gpio/gpio-xgene.c
+++ b/drivers/gpio/gpio-xgene.c
@@ -47,14 +47,9 @@ struct xgene_gpio {
#endif
};
-static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct xgene_gpio, chip);
-}
-
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
- struct xgene_gpio *chip = to_xgene_gpio(gc);
+ struct xgene_gpio *chip = gpiochip_get_data(gc);
unsigned long bank_offset;
u32 bit_offset;
@@ -65,7 +60,7 @@ static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
{
- struct xgene_gpio *chip = to_xgene_gpio(gc);
+ struct xgene_gpio *chip = gpiochip_get_data(gc);
unsigned long bank_offset;
u32 setval, bit_offset;
@@ -82,7 +77,7 @@ static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
{
- struct xgene_gpio *chip = to_xgene_gpio(gc);
+ struct xgene_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -92,7 +87,7 @@ static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
{
- struct xgene_gpio *chip = to_xgene_gpio(gc);
+ struct xgene_gpio *chip = gpiochip_get_data(gc);
unsigned long flags, bank_offset;
u32 dirval, bit_offset;
@@ -113,7 +108,7 @@ static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
static int xgene_gpio_dir_out(struct gpio_chip *gc,
unsigned int offset, int val)
{
- struct xgene_gpio *chip = to_xgene_gpio(gc);
+ struct xgene_gpio *chip = gpiochip_get_data(gc);
unsigned long flags, bank_offset;
u32 dirval, bit_offset;
@@ -188,7 +183,7 @@ static int xgene_gpio_probe(struct platform_device *pdev)
gpio->chip.ngpio = XGENE_MAX_GPIOS;
spin_lock_init(&gpio->lock);
- gpio->chip.dev = &pdev->dev;
+ gpio->chip.parent = &pdev->dev;
gpio->chip.direction_input = xgene_gpio_dir_in;
gpio->chip.direction_output = xgene_gpio_dir_out;
gpio->chip.get = xgene_gpio_get;
@@ -198,7 +193,7 @@ static int xgene_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpio);
- err = gpiochip_add(&gpio->chip);
+ err = gpiochip_add_data(&gpio->chip, gpio);
if (err) {
dev_err(&pdev->dev,
"failed to register gpiochip.\n");
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index d5284dfe01fe..d0fbb7f99523 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -92,8 +92,7 @@ static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct xgpio_instance *chip =
- container_of(mm_gc, struct xgpio_instance, mmchip);
+ struct xgpio_instance *chip = gpiochip_get_data(gc);
u32 val;
val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
@@ -115,8 +114,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct xgpio_instance *chip =
- container_of(mm_gc, struct xgpio_instance, mmchip);
+ struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@@ -147,8 +145,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct xgpio_instance *chip =
- container_of(mm_gc, struct xgpio_instance, mmchip);
+ struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@@ -180,8 +177,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct xgpio_instance *chip =
- container_of(mm_gc, struct xgpio_instance, mmchip);
+ struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@@ -212,7 +208,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct xgpio_instance *chip =
- container_of(mm_gc, struct xgpio_instance, mmchip);
+ container_of(mm_gc, struct xgpio_instance, mmchip);
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
@@ -305,7 +301,7 @@ static int xgpio_probe(struct platform_device *pdev)
}
chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
- chip->mmchip.gc.dev = &pdev->dev;
+ chip->mmchip.gc.parent = &pdev->dev;
chip->mmchip.gc.direction_input = xgpio_dir_in;
chip->mmchip.gc.direction_output = xgpio_dir_out;
chip->mmchip.gc.get = xgpio_get;
@@ -314,7 +310,7 @@ static int xgpio_probe(struct platform_device *pdev)
chip->mmchip.save_regs = xgpio_save_regs;
/* Call the OF gpio helper to setup and register the GPIO device */
- status = of_mm_gpiochip_add(np, &chip->mmchip);
+ status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
if (status) {
pr_err("%s: error in probe function with status %d\n",
np->full_name, status);
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index bc06a2cd2c1d..aa5813d2deb1 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -100,11 +100,6 @@ struct xlp_gpio_priv {
spinlock_t lock;
};
-static struct xlp_gpio_priv *gpio_chip_to_xlp_priv(struct gpio_chip *gc)
-{
- return container_of(gc, struct xlp_gpio_priv, chip);
-}
-
static int xlp_gpio_get_reg(void __iomem *addr, unsigned gpio)
{
u32 pos, regset;
@@ -133,7 +128,7 @@ static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
static void xlp_gpio_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -145,7 +140,7 @@ static void xlp_gpio_irq_disable(struct irq_data *d)
static void xlp_gpio_irq_mask_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -158,7 +153,7 @@ static void xlp_gpio_irq_mask_ack(struct irq_data *d)
static void xlp_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -170,7 +165,7 @@ static void xlp_gpio_irq_unmask(struct irq_data *d)
static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
int pol, irq_type;
switch (type) {
@@ -235,7 +230,7 @@ static void xlp_gpio_generic_handler(struct irq_desc *desc)
static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
{
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
BUG_ON(gpio >= gc->ngpio);
xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1);
@@ -245,7 +240,7 @@ static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
{
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
BUG_ON(gpio >= gc->ngpio);
xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0);
@@ -255,7 +250,7 @@ static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
BUG_ON(gpio >= gc->ngpio);
return xlp_gpio_get_reg(priv->gpio_paddrv, gpio);
@@ -263,7 +258,7 @@ static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state)
{
- struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+ struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
BUG_ON(gpio >= gc->ngpio);
xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state);
@@ -373,7 +368,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
gc->owner = THIS_MODULE;
gc->label = dev_name(&pdev->dev);
gc->base = 0;
- gc->dev = &pdev->dev;
+ gc->parent = &pdev->dev;
gc->ngpio = ngpio;
gc->of_node = pdev->dev.of_node;
gc->direction_output = xlp_gpio_dir_output;
@@ -388,7 +383,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- err = gpiochip_add(gc);
+ err = gpiochip_add_data(gc, priv);
if (err < 0)
goto out_free_desc;
diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c
index 93ec95df67a3..f16c0427952e 100644
--- a/drivers/gpio/gpio-xtensa.c
+++ b/drivers/gpio/gpio-xtensa.c
@@ -148,10 +148,10 @@ static int xtensa_gpio_probe(struct platform_device *pdev)
{
int ret;
- ret = gpiochip_add(&impwire_chip);
+ ret = gpiochip_add_data(&impwire_chip, NULL);
if (ret)
return ret;
- return gpiochip_add(&expstate_chip);
+ return gpiochip_add_data(&expstate_chip, NULL);
}
static struct platform_driver xtensa_gpio_driver = {
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 6f02d7c4cc57..cda6d922be98 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -52,9 +52,6 @@
#define ZEVIO_GPIO_INPUT 0x18
#define ZEVIO_GPIO_INT_STICKY 0x20
-#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \
- struct zevio_gpio, chip)
-
/* Bit number of GPIO in its section */
#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
@@ -80,7 +77,7 @@ static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
/* Functions for struct gpio_chip */
static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
{
- struct zevio_gpio *controller = to_zevio_gpio(chip);
+ struct zevio_gpio *controller = gpiochip_get_data(chip);
u32 val, dir;
spin_lock(&controller->lock);
@@ -96,7 +93,7 @@ static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
{
- struct zevio_gpio *controller = to_zevio_gpio(chip);
+ struct zevio_gpio *controller = gpiochip_get_data(chip);
u32 val;
spin_lock(&controller->lock);
@@ -112,7 +109,7 @@ static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
- struct zevio_gpio *controller = to_zevio_gpio(chip);
+ struct zevio_gpio *controller = gpiochip_get_data(chip);
u32 val;
spin_lock(&controller->lock);
@@ -129,7 +126,7 @@ static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
static int zevio_gpio_direction_output(struct gpio_chip *chip,
unsigned pin, int value)
{
- struct zevio_gpio *controller = to_zevio_gpio(chip);
+ struct zevio_gpio *controller = gpiochip_get_data(chip);
u32 val;
spin_lock(&controller->lock);
@@ -185,9 +182,11 @@ static int zevio_gpio_probe(struct platform_device *pdev)
/* Copy our reference */
controller->chip.gc = zevio_gpio_chip;
- controller->chip.gc.dev = &pdev->dev;
+ controller->chip.gc.parent = &pdev->dev;
- status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip));
+ status = of_mm_gpiochip_add_data(pdev->dev.of_node,
+ &(controller->chip),
+ controller);
if (status) {
dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
return status;
@@ -199,7 +198,7 @@ static int zevio_gpio_probe(struct platform_device *pdev)
for (i = 0; i < controller->chip.gc.ngpio; i += 8)
zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
- dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n");
+ dev_dbg(controller->chip.gc.parent, "ZEVIO GPIO controller set up!\n");
return 0;
}
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index 1dcf7a66dd36..47c79fa65670 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -43,14 +43,9 @@ struct zx_gpio {
struct gpio_chip gc;
};
-static inline struct zx_gpio *to_zx(struct gpio_chip *gc)
-{
- return container_of(gc, struct zx_gpio, gc);
-}
-
static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
u16 gpiodir;
@@ -69,7 +64,7 @@ static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
static int zx_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
u16 gpiodir;
@@ -92,14 +87,14 @@ static int zx_direction_output(struct gpio_chip *gc, unsigned offset,
static int zx_get_value(struct gpio_chip *gc, unsigned offset)
{
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset));
}
static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value)
{
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
if (value)
writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1);
@@ -110,7 +105,7 @@ static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value)
static int zx_irq_type(struct irq_data *d, unsigned trigger)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(d);
unsigned long flags;
u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev;
@@ -162,7 +157,7 @@ static void zx_irq_handler(struct irq_desc *desc)
unsigned long pending;
int offset;
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc);
@@ -181,7 +176,7 @@ static void zx_irq_handler(struct irq_desc *desc)
static void zx_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
u16 gpioie;
@@ -196,7 +191,7 @@ static void zx_irq_mask(struct irq_data *d)
static void zx_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct zx_gpio *chip = to_zx(gc);
+ struct zx_gpio *chip = gpiochip_get_data(gc);
u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
u16 gpioie;
@@ -245,10 +240,10 @@ static int zx_gpio_probe(struct platform_device *pdev)
chip->gc.base = ZX_GPIO_NR * id;
chip->gc.ngpio = ZX_GPIO_NR;
chip->gc.label = dev_name(dev);
- chip->gc.dev = dev;
+ chip->gc.parent = dev;
chip->gc.owner = THIS_MODULE;
- ret = gpiochip_add(&chip->gc);
+ ret = gpiochip_add_data(&chip->gc, chip);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 8abeacac5885..66d3d247d76d 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -131,11 +131,6 @@ struct zynq_platform_data {
static struct irq_chip zynq_gpio_level_irqchip;
static struct irq_chip zynq_gpio_edge_irqchip;
-static struct zynq_gpio *to_zynq_gpio(struct gpio_chip *gc)
-{
- return container_of(gc, struct zynq_gpio, chip);
-}
-
/**
* zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
* for a given pin in the GPIO device
@@ -183,7 +178,7 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
{
u32 data;
unsigned int bank_num, bank_pin_num;
- struct zynq_gpio *gpio = to_zynq_gpio(chip);
+ struct zynq_gpio *gpio = gpiochip_get_data(chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
@@ -207,7 +202,7 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
int state)
{
unsigned int reg_offset, bank_num, bank_pin_num;
- struct zynq_gpio *gpio = to_zynq_gpio(chip);
+ struct zynq_gpio *gpio = gpiochip_get_data(chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
@@ -244,7 +239,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
{
u32 reg;
unsigned int bank_num, bank_pin_num;
- struct zynq_gpio *gpio = to_zynq_gpio(chip);
+ struct zynq_gpio *gpio = gpiochip_get_data(chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
@@ -277,7 +272,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
{
u32 reg;
unsigned int bank_num, bank_pin_num;
- struct zynq_gpio *gpio = to_zynq_gpio(chip);
+ struct zynq_gpio *gpio = gpiochip_get_data(chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
@@ -308,7 +303,7 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio =
- to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+ gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -329,7 +324,7 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio =
- to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+ gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -349,7 +344,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio =
- to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+ gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -400,7 +395,7 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
u32 int_type, int_pol, int_any;
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio =
- to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+ gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -464,7 +459,7 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
{
struct zynq_gpio *gpio =
- to_zynq_gpio(irq_data_get_irq_chip_data(data));
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
irq_set_irq_wake(gpio->irq, on);
@@ -530,7 +525,7 @@ static void zynq_gpio_irqhandler(struct irq_desc *desc)
u32 int_sts, int_enb;
unsigned int bank_num;
struct zynq_gpio *gpio =
- to_zynq_gpio(irq_desc_get_handler_data(desc));
+ gpiochip_get_data(irq_desc_get_handler_data(desc));
struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc);
@@ -592,7 +587,7 @@ static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset)
{
int ret;
- ret = pm_runtime_get_sync(chip->dev);
+ ret = pm_runtime_get_sync(chip->parent);
/*
* If the device is already active pm_runtime_get() will return 1 on
@@ -603,7 +598,7 @@ static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset)
static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- pm_runtime_put(chip->dev);
+ pm_runtime_put(chip->parent);
}
static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
@@ -698,7 +693,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip = &gpio->chip;
chip->label = gpio->p_data->label;
chip->owner = THIS_MODULE;
- chip->dev = &pdev->dev;
+ chip->parent = &pdev->dev;
chip->get = zynq_gpio_get_value;
chip->set = zynq_gpio_set_value;
chip->request = zynq_gpio_request;
@@ -708,23 +703,23 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip->base = -1;
chip->ngpio = gpio->p_data->ngpio;
- /* Enable GPIO clock */
+ /* Retrieve GPIO clock */
gpio->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(gpio->clk)) {
dev_err(&pdev->dev, "input clock not found.\n");
return PTR_ERR(gpio->clk);
}
- ret = clk_prepare_enable(gpio->clk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable clock.\n");
+
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
return ret;
- }
/* report a bug if gpio chip registration fails */
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, gpio);
if (ret) {
dev_err(&pdev->dev, "Failed to add gpio chip\n");
- goto err_disable_clk;
+ goto err_pm_put;
}
/* disable interrupts for all banks */
@@ -742,15 +737,14 @@ static int zynq_gpio_probe(struct platform_device *pdev)
gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
zynq_gpio_irqhandler);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
return 0;
err_rm_gpiochip:
gpiochip_remove(chip);
-err_disable_clk:
- clk_disable_unprepare(gpio->clk);
+err_pm_put:
+ pm_runtime_put(&pdev->dev);
return ret;
}
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index cbbb67a6f1d6..540cbc88c7a2 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -51,10 +51,10 @@ struct acpi_gpio_chip {
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
- if (!gc->dev)
+ if (!gc->parent)
return false;
- return ACPI_HANDLE(gc->dev) == data;
+ return ACPI_HANDLE(gc->parent) == data;
}
#ifdef CONFIG_PINCTRL
@@ -184,7 +184,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
return AE_OK;
- handle = ACPI_HANDLE(chip->dev);
+ handle = ACPI_HANDLE(chip->parent);
pin = agpio->pin_table[0];
if (pin <= 255) {
@@ -208,7 +208,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
if (IS_ERR(desc)) {
- dev_err(chip->dev, "Failed to request GPIO\n");
+ dev_err(chip->parent, "Failed to request GPIO\n");
return AE_ERROR;
}
@@ -216,13 +216,13 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
ret = gpiochip_lock_as_irq(chip, pin);
if (ret) {
- dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
+ dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
goto fail_free_desc;
}
irq = gpiod_to_irq(desc);
if (irq < 0) {
- dev_err(chip->dev, "Failed to translate GPIO to IRQ\n");
+ dev_err(chip->parent, "Failed to translate GPIO to IRQ\n");
goto fail_unlock_irq;
}
@@ -259,7 +259,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
"ACPI:Event", event);
if (ret) {
- dev_err(chip->dev, "Failed to setup interrupt handler for %d\n",
+ dev_err(chip->parent,
+ "Failed to setup interrupt handler for %d\n",
event->irq);
goto fail_free_event;
}
@@ -293,10 +294,10 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
acpi_handle handle;
acpi_status status;
- if (!chip->dev || !chip->to_irq)
+ if (!chip->parent || !chip->to_irq)
return;
- handle = ACPI_HANDLE(chip->dev);
+ handle = ACPI_HANDLE(chip->parent);
if (!handle)
return;
@@ -323,10 +324,10 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
acpi_handle handle;
acpi_status status;
- if (!chip->dev || !chip->to_irq)
+ if (!chip->parent || !chip->to_irq)
return;
- handle = ACPI_HANDLE(chip->dev);
+ handle = ACPI_HANDLE(chip->parent);
if (!handle)
return;
@@ -769,7 +770,7 @@ out:
static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
{
struct gpio_chip *chip = achip->chip;
- acpi_handle handle = ACPI_HANDLE(chip->dev);
+ acpi_handle handle = ACPI_HANDLE(chip->parent);
acpi_status status;
INIT_LIST_HEAD(&achip->conns);
@@ -778,20 +779,22 @@ static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
acpi_gpio_adr_space_handler,
NULL, achip);
if (ACPI_FAILURE(status))
- dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n");
+ dev_err(chip->parent,
+ "Failed to install GPIO OpRegion handler\n");
}
static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
{
struct gpio_chip *chip = achip->chip;
- acpi_handle handle = ACPI_HANDLE(chip->dev);
+ acpi_handle handle = ACPI_HANDLE(chip->parent);
struct acpi_gpio_connection *conn, *tmp;
acpi_status status;
status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
acpi_gpio_adr_space_handler);
if (ACPI_FAILURE(status)) {
- dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n");
+ dev_err(chip->parent,
+ "Failed to remove GPIO OpRegion handler\n");
return;
}
@@ -808,16 +811,16 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
acpi_handle handle;
acpi_status status;
- if (!chip || !chip->dev)
+ if (!chip || !chip->parent)
return;
- handle = ACPI_HANDLE(chip->dev);
+ handle = ACPI_HANDLE(chip->parent);
if (!handle)
return;
acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
if (!acpi_gpio) {
- dev_err(chip->dev,
+ dev_err(chip->parent,
"Failed to allocate memory for ACPI GPIO chip\n");
return;
}
@@ -827,7 +830,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
if (ACPI_FAILURE(status)) {
- dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n");
+ dev_err(chip->parent, "Failed to attach ACPI GPIO chip\n");
kfree(acpi_gpio);
return;
}
@@ -841,16 +844,16 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
acpi_handle handle;
acpi_status status;
- if (!chip || !chip->dev)
+ if (!chip || !chip->parent)
return;
- handle = ACPI_HANDLE(chip->dev);
+ handle = ACPI_HANDLE(chip->parent);
if (!handle)
return;
status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
if (ACPI_FAILURE(status)) {
- dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n");
+ dev_warn(chip->parent, "Failed to retrieve ACPI GPIO chip\n");
return;
}
@@ -943,3 +946,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
}
return count;
}
+
+struct acpi_crs_lookup {
+ struct list_head node;
+ struct acpi_device *adev;
+ const char *con_id;
+};
+
+static DEFINE_MUTEX(acpi_crs_lookup_lock);
+static LIST_HEAD(acpi_crs_lookup_list);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
+{
+ struct acpi_crs_lookup *l, *lookup = NULL;
+
+ /* Never allow fallback if the device has properties */
+ if (adev->data.properties || adev->driver_gpios)
+ return false;
+
+ mutex_lock(&acpi_crs_lookup_lock);
+
+ list_for_each_entry(l, &acpi_crs_lookup_list, node) {
+ if (l->adev == adev) {
+ lookup = l;
+ break;
+ }
+ }
+
+ if (!lookup) {
+ lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
+ if (lookup) {
+ lookup->adev = adev;
+ lookup->con_id = con_id;
+ list_add_tail(&lookup->node, &acpi_crs_lookup_list);
+ }
+ }
+
+ mutex_unlock(&acpi_crs_lookup_lock);
+
+ return lookup &&
+ ((!lookup->con_id && !con_id) ||
+ (lookup->con_id && con_id &&
+ strcmp(lookup->con_id, con_id) == 0));
+}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 5fe34a9df3e6..42a4bb7cf49a 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -262,9 +262,10 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
EXPORT_SYMBOL(of_gpio_simple_xlate);
/**
- * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
+ * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
* @np: device node of the GPIO chip
* @mm_gc: pointer to the of_mm_gpio_chip allocated structure
+ * @data: driver data to store in the struct gpio_chip
*
* To use this function you should allocate and fill mm_gc with:
*
@@ -280,8 +281,9 @@ EXPORT_SYMBOL(of_gpio_simple_xlate);
* do all necessary work for you. Then you'll able to use .regs
* to manage GPIOs from the callbacks.
*/
-int of_mm_gpiochip_add(struct device_node *np,
- struct of_mm_gpio_chip *mm_gc)
+int of_mm_gpiochip_add_data(struct device_node *np,
+ struct of_mm_gpio_chip *mm_gc,
+ void *data)
{
int ret = -ENOMEM;
struct gpio_chip *gc = &mm_gc->gc;
@@ -301,7 +303,7 @@ int of_mm_gpiochip_add(struct device_node *np,
mm_gc->gc.of_node = np;
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, data);
if (ret)
goto err2;
@@ -315,7 +317,7 @@ err0:
np->full_name, ret);
return ret;
}
-EXPORT_SYMBOL(of_mm_gpiochip_add);
+EXPORT_SYMBOL(of_mm_gpiochip_add_data);
/**
* of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
@@ -423,8 +425,8 @@ int of_gpiochip_add(struct gpio_chip *chip)
{
int status;
- if ((!chip->of_node) && (chip->dev))
- chip->of_node = chip->dev->of_node;
+ if ((!chip->of_node) && (chip->parent))
+ chip->of_node = chip->parent->of_node;
if (!chip->of_node)
return 0;
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index b57ed8e55ab5..405dfcaadc4c 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -605,7 +605,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
- dev = device_create_with_groups(&gpio_class, chip->dev,
+ dev = device_create_with_groups(&gpio_class, chip->parent,
MKDEV(0, 0), data, gpio_groups,
ioname ? ioname : "gpio%u",
desc_to_gpio(desc));
@@ -730,7 +730,8 @@ int gpiochip_sysfs_register(struct gpio_chip *chip)
return 0;
/* use chip->base for the ID; it's already known to be unique */
- dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
+ dev = device_create_with_groups(&gpio_class, chip->parent,
+ MKDEV(0, 0),
chip, gpiochip_groups,
"gpiochip%d", chip->base);
if (IS_ERR(dev))
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5d8d7ab96916..5c1ba879f889 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -182,39 +182,62 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction);
/*
* Add a new chip to the global chips list, keeping the list of chips sorted
- * by base order.
+ * by range(means [base, base + ngpio - 1]) order.
*
* Return -EBUSY if the new chip overlaps with some other chip's integer
* space.
*/
static int gpiochip_add_to_list(struct gpio_chip *chip)
{
- struct list_head *pos;
- struct gpio_chip *_chip;
- int err = 0;
+ struct gpio_chip *iterator;
+ struct gpio_chip *previous = NULL;
- /* find where to insert our chip */
- list_for_each(pos, &gpio_chips) {
- _chip = list_entry(pos, struct gpio_chip, list);
- /* shall we insert before _chip? */
- if (_chip->base >= chip->base + chip->ngpio)
- break;
+ if (list_empty(&gpio_chips)) {
+ list_add_tail(&chip->list, &gpio_chips);
+ return 0;
}
- /* are we stepping on the chip right before? */
- if (pos != &gpio_chips && pos->prev != &gpio_chips) {
- _chip = list_entry(pos->prev, struct gpio_chip, list);
- if (_chip->base + _chip->ngpio > chip->base) {
- dev_err(chip->dev,
- "GPIO integer space overlap, cannot add chip\n");
- err = -EBUSY;
+ list_for_each_entry(iterator, &gpio_chips, list) {
+ if (iterator->base >= chip->base + chip->ngpio) {
+ /*
+ * Iterator is the first GPIO chip so there is no
+ * previous one
+ */
+ if (!previous) {
+ goto found;
+ } else {
+ /*
+ * We found a valid range(means
+ * [base, base + ngpio - 1]) between previous
+ * and iterator chip.
+ */
+ if (previous->base + previous->ngpio
+ <= chip->base)
+ goto found;
+ }
}
+ previous = iterator;
}
- if (!err)
- list_add_tail(&chip->list, pos);
+ /*
+ * We are beyond the last chip in the list and iterator now
+ * points to the head.
+ * Let iterator point to the last chip in the list.
+ */
- return err;
+ iterator = list_last_entry(&gpio_chips, struct gpio_chip, list);
+ if (iterator->base + iterator->ngpio <= chip->base) {
+ list_add(&chip->list, &iterator->list);
+ return 0;
+ }
+
+ dev_err(chip->parent,
+ "GPIO integer space overlap, cannot add chip\n");
+ return -EBUSY;
+
+found:
+ list_add_tail(&chip->list, &iterator->list);
+ return 0;
}
/**
@@ -252,7 +275,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
* Takes the names from gc->names and checks if they are all unique. If they
* are, they are assigned to their gpio descriptors.
*
- * Returns -EEXIST if one of the names is already used for a different GPIO.
+ * Warning if one of the names is already used for a different GPIO.
*/
static int gpiochip_set_desc_names(struct gpio_chip *gc)
{
@@ -267,7 +290,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
gpio = gpio_name_to_desc(gc->names[i]);
if (gpio)
- dev_warn(gc->dev, "Detected name collision for "
+ dev_warn(gc->parent, "Detected name collision for "
"GPIO name '%s'\n",
gc->names[i]);
}
@@ -280,7 +303,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
}
/**
- * gpiochip_add() - register a gpio_chip
+ * gpiochip_add_data() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
* Context: potentially before irqs will work
*
@@ -288,15 +311,15 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
* because the chip->base is invalid or already associated with a
* different chip. Otherwise it returns zero as a success code.
*
- * When gpiochip_add() is called very early during boot, so that GPIOs
- * can be freely used, the chip->dev device must be registered before
+ * When gpiochip_add_data() is called very early during boot, so that GPIOs
+ * can be freely used, the chip->parent device must be registered before
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
* for GPIOs will fail rudely.
*
* If chip->base is negative, this requests dynamic assignment of
* a range of valid GPIOs.
*/
-int gpiochip_add(struct gpio_chip *chip)
+int gpiochip_add_data(struct gpio_chip *chip, void *data)
{
unsigned long flags;
int status = 0;
@@ -308,6 +331,13 @@ int gpiochip_add(struct gpio_chip *chip)
if (!descs)
return -ENOMEM;
+ chip->data = data;
+
+ if (chip->ngpio == 0) {
+ chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&gpio_lock, flags);
if (base < 0) {
@@ -348,8 +378,8 @@ int gpiochip_add(struct gpio_chip *chip)
INIT_LIST_HEAD(&chip->pin_ranges);
#endif
- if (!chip->owner && chip->dev && chip->dev->driver)
- chip->owner = chip->dev->driver->owner;
+ if (!chip->owner && chip->parent && chip->parent->driver)
+ chip->owner = chip->parent->driver->owner;
status = gpiochip_set_desc_names(chip);
if (status)
@@ -389,7 +419,7 @@ err_free_descs:
chip->label ? : "generic");
return status;
}
-EXPORT_SYMBOL_GPL(gpiochip_add);
+EXPORT_SYMBOL_GPL(gpiochip_add_data);
/**
* gpiochip_remove() - unregister a gpio_chip
@@ -424,7 +454,8 @@ void gpiochip_remove(struct gpio_chip *chip)
spin_unlock_irqrestore(&gpio_lock, flags);
if (requested)
- dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
+ dev_crit(chip->parent,
+ "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
kfree(chip->desc);
chip->desc = NULL;
@@ -659,7 +690,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
* gpiochip, providing an irq domain to translate the local IRQs to
* global irqs in the gpiolib core, and making sure that the gpiochip
* is passed as chip data to all related functions. Driver callbacks
- * need to use container_of() to get their local state containers back
+ * need to use gpiochip_get_data() to get their local state containers back
* from the gpiochip passed as chip data. An irqdomain will be stored
* in the gpiochip that shall be used by the driver to handle IRQ number
* translation. The gpiochip will need to be initialized and registered
@@ -683,15 +714,16 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
if (!gpiochip || !irqchip)
return -EINVAL;
- if (!gpiochip->dev) {
+ if (!gpiochip->parent) {
pr_err("missing gpiochip .dev parent pointer\n");
return -EINVAL;
}
- of_node = gpiochip->dev->of_node;
+ of_node = gpiochip->parent->of_node;
#ifdef CONFIG_OF_GPIO
/*
* If the gpiochip has an assigned OF node this takes precedence
- * FIXME: get rid of this and use gpiochip->dev->of_node everywhere
+ * FIXME: get rid of this and use gpiochip->parent->of_node
+ * everywhere
*/
if (gpiochip->of_node)
of_node = gpiochip->of_node;
@@ -1279,13 +1311,7 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
chip = desc->chip;
offset = gpio_chip_hwgpio(desc);
value = chip->get ? chip->get(chip, offset) : -EIO;
- /*
- * FIXME: fix all drivers to clamp to [0,1] or return negative,
- * then change this to:
- * value = value < 0 ? value : !!value;
- * so we can properly propagate error codes.
- */
- value = !!value;
+ value = value < 0 ? value : !!value;
trace_gpio_value(desc_to_gpio(desc), 1, value);
return value;
}
@@ -1874,6 +1900,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
+ if (!acpi_can_fallback_to_crs(adev, con_id))
+ return ERR_PTR(-ENOENT);
+
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
@@ -2509,7 +2538,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
chip->base, chip->base + chip->ngpio - 1);
- dev = chip->dev;
+ dev = chip->parent;
if (dev)
seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
dev_name(dev));
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 5ac3b88a2e0a..99ed3b00ffe9 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -16,7 +16,7 @@
#include <linux/device.h>
enum of_gpio_flags;
-
+enum gpiod_flags;
struct acpi_device;
/**
@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
@@ -74,6 +76,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{
return -ENODEV;
}
+
+static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
+ const char *con_id)
+{
+ return false;
+}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c4bf9a1cf4a6..59babd5a5396 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -160,6 +160,7 @@ config DRM_AMDGPU
If M is selected, the module will be called amdgpu.
source "drivers/gpu/drm/amd/amdgpu/Kconfig"
+source "drivers/gpu/drm/amd/powerplay/Kconfig"
source "drivers/gpu/drm/nouveau/Kconfig"
@@ -266,3 +267,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
source "drivers/gpu/drm/imx/Kconfig"
source "drivers/gpu/drm/vc4/Kconfig"
+
+source "drivers/gpu/drm/etnaviv/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1e9ff4c3e3db..61766dec6a8d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -21,8 +21,6 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_AGP) += drm_agpsupport.o
-drm-y += $(drm-m)
-
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
@@ -62,7 +60,7 @@ obj-$(CONFIG_DRM_ARMADA) += armada/
obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
-obj-$(CONFIG_DRM_OMAP) += omapdrm/
+obj-y += omapdrm/
obj-y += tilcdc/
obj-$(CONFIG_DRM_QXL) += qxl/
obj-$(CONFIG_DRM_BOCHS) += bochs/
@@ -75,3 +73,4 @@ obj-y += i2c/
obj-y += panel/
obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
+obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index 04c270757030..66f729eaf00b 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -2,10 +2,13 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/asic_reg \
- -Idrivers/gpu/drm/amd/include \
- -Idrivers/gpu/drm/amd/amdgpu \
- -Idrivers/gpu/drm/amd/scheduler
+FULL_AMD_PATH=$(src)/..
+
+ccflags-y := -Iinclude/drm -I$(FULL_AMD_PATH)/include/asic_reg \
+ -I$(FULL_AMD_PATH)/include \
+ -I$(FULL_AMD_PATH)/amdgpu \
+ -I$(FULL_AMD_PATH)/scheduler \
+ -I$(FULL_AMD_PATH)/powerplay/inc
amdgpu-y := amdgpu_drv.o
@@ -44,6 +47,7 @@ amdgpu-y += \
# add SMC block
amdgpu-y += \
amdgpu_dpm.o \
+ amdgpu_powerplay.o \
cz_smc.o cz_dpm.o \
tonga_smc.o tonga_dpm.o \
fiji_smc.o fiji_dpm.o \
@@ -94,6 +98,14 @@ amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o
amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
amdgpu-$(CONFIG_MMU_NOTIFIER) += amdgpu_mn.o
+ifneq ($(CONFIG_DRM_AMD_POWERPLAY),)
+
+include $(FULL_AMD_PATH)/powerplay/Makefile
+
+amdgpu-y += $(AMD_POWERPLAY_FILES)
+
+endif
+
obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
CFLAGS_amdgpu_trace_points.o := -I$(src)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 048cfe073dae..313b0cc8d676 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -52,6 +52,7 @@
#include "amdgpu_irq.h"
#include "amdgpu_ucode.h"
#include "amdgpu_gds.h"
+#include "amd_powerplay.h"
#include "gpu_scheduler.h"
@@ -85,6 +86,7 @@ extern int amdgpu_enable_scheduler;
extern int amdgpu_sched_jobs;
extern int amdgpu_sched_hw_submission;
extern int amdgpu_enable_semaphores;
+extern int amdgpu_powerplay;
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
#define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
@@ -918,8 +920,8 @@ struct amdgpu_ring {
#define AMDGPU_VM_FAULT_STOP_ALWAYS 2
struct amdgpu_vm_pt {
- struct amdgpu_bo *bo;
- uint64_t addr;
+ struct amdgpu_bo_list_entry entry;
+ uint64_t addr;
};
struct amdgpu_vm_id {
@@ -981,9 +983,12 @@ struct amdgpu_vm_manager {
void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
- struct amdgpu_vm *vm,
- struct list_head *head);
+void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
+ struct list_head *validated,
+ struct amdgpu_bo_list_entry *entry);
+void amdgpu_vm_get_pt_bos(struct amdgpu_vm *vm, struct list_head *duplicates);
+void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm);
int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
struct amdgpu_sync *sync);
void amdgpu_vm_flush(struct amdgpu_ring *ring,
@@ -1024,11 +1029,9 @@ int amdgpu_vm_free_job(struct amdgpu_job *job);
* context related structures
*/
-#define AMDGPU_CTX_MAX_CS_PENDING 16
-
struct amdgpu_ctx_ring {
uint64_t sequence;
- struct fence *fences[AMDGPU_CTX_MAX_CS_PENDING];
+ struct fence **fences;
struct amd_sched_entity entity;
};
@@ -1037,6 +1040,7 @@ struct amdgpu_ctx {
struct amdgpu_device *adev;
unsigned reset_counter;
spinlock_t ring_lock;
+ struct fence **fences;
struct amdgpu_ctx_ring rings[AMDGPU_MAX_RINGS];
};
@@ -1047,7 +1051,7 @@ struct amdgpu_ctx_mgr {
struct idr ctx_handles;
};
-int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
+int amdgpu_ctx_init(struct amdgpu_device *adev, enum amd_sched_priority pri,
struct amdgpu_ctx *ctx);
void amdgpu_ctx_fini(struct amdgpu_ctx *ctx);
@@ -1254,7 +1258,7 @@ struct amdgpu_cs_parser {
unsigned nchunks;
struct amdgpu_cs_chunk *chunks;
/* relocations */
- struct amdgpu_bo_list_entry *vm_bos;
+ struct amdgpu_bo_list_entry vm_pd;
struct list_head validated;
struct fence *fence;
@@ -1301,31 +1305,7 @@ struct amdgpu_wb {
int amdgpu_wb_get(struct amdgpu_device *adev, u32 *wb);
void amdgpu_wb_free(struct amdgpu_device *adev, u32 wb);
-/**
- * struct amdgpu_pm - power management datas
- * It keeps track of various data needed to take powermanagement decision.
- */
-enum amdgpu_pm_state_type {
- /* not used for dpm */
- POWER_STATE_TYPE_DEFAULT,
- POWER_STATE_TYPE_POWERSAVE,
- /* user selectable states */
- POWER_STATE_TYPE_BATTERY,
- POWER_STATE_TYPE_BALANCED,
- POWER_STATE_TYPE_PERFORMANCE,
- /* internal states */
- POWER_STATE_TYPE_INTERNAL_UVD,
- POWER_STATE_TYPE_INTERNAL_UVD_SD,
- POWER_STATE_TYPE_INTERNAL_UVD_HD,
- POWER_STATE_TYPE_INTERNAL_UVD_HD2,
- POWER_STATE_TYPE_INTERNAL_UVD_MVC,
- POWER_STATE_TYPE_INTERNAL_BOOT,
- POWER_STATE_TYPE_INTERNAL_THERMAL,
- POWER_STATE_TYPE_INTERNAL_ACPI,
- POWER_STATE_TYPE_INTERNAL_ULV,
- POWER_STATE_TYPE_INTERNAL_3DPERF,
-};
enum amdgpu_int_thermal_type {
THERMAL_TYPE_NONE,
@@ -1607,8 +1587,8 @@ struct amdgpu_dpm {
/* vce requirements */
struct amdgpu_vce_state vce_states[AMDGPU_MAX_VCE_LEVELS];
enum amdgpu_vce_level vce_level;
- enum amdgpu_pm_state_type state;
- enum amdgpu_pm_state_type user_state;
+ enum amd_pm_state_type state;
+ enum amd_pm_state_type user_state;
u32 platform_caps;
u32 voltage_response_time;
u32 backbias_response_time;
@@ -1661,8 +1641,13 @@ struct amdgpu_pm {
const struct firmware *fw; /* SMC firmware */
uint32_t fw_version;
const struct amdgpu_dpm_funcs *funcs;
+ uint32_t pcie_gen_mask;
+ uint32_t pcie_mlw_mask;
+ struct amd_pp_display_configuration pm_display_cfg;/* set by DAL */
};
+void amdgpu_get_pcie_info(struct amdgpu_device *adev);
+
/*
* UVD
*/
@@ -1830,6 +1815,8 @@ struct amdgpu_cu_info {
*/
struct amdgpu_asic_funcs {
bool (*read_disabled_bios)(struct amdgpu_device *adev);
+ bool (*read_bios_from_rom)(struct amdgpu_device *adev,
+ u8 *bios, u32 length_bytes);
int (*read_register)(struct amdgpu_device *adev, u32 se_num,
u32 sh_num, u32 reg_offset, u32 *value);
void (*set_vga_state)(struct amdgpu_device *adev, bool state);
@@ -2060,6 +2047,10 @@ struct amdgpu_device {
/* interrupts */
struct amdgpu_irq irq;
+ /* powerplay */
+ struct amd_powerplay powerplay;
+ bool pp_enabled;
+
/* dpm */
struct amdgpu_pm pm;
u32 cg_flags;
@@ -2236,6 +2227,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
#define amdgpu_asic_set_vce_clocks(adev, ev, ec) (adev)->asic_funcs->set_vce_clocks((adev), (ev), (ec))
#define amdgpu_asic_get_gpu_clock_counter(adev) (adev)->asic_funcs->get_gpu_clock_counter((adev))
#define amdgpu_asic_read_disabled_bios(adev) (adev)->asic_funcs->read_disabled_bios((adev))
+#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
#define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
#define amdgpu_asic_get_cu_info(adev, info) (adev)->asic_funcs->get_cu_info((adev), (info))
#define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid))
@@ -2277,24 +2269,78 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
#define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s))
#define amdgpu_emit_copy_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((ib), (s), (d), (b))
#define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))
-#define amdgpu_dpm_get_temperature(adev) (adev)->pm.funcs->get_temperature((adev))
#define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev))
#define amdgpu_dpm_set_power_state(adev) (adev)->pm.funcs->set_power_state((adev))
#define amdgpu_dpm_post_set_power_state(adev) (adev)->pm.funcs->post_set_power_state((adev))
#define amdgpu_dpm_display_configuration_changed(adev) (adev)->pm.funcs->display_configuration_changed((adev))
-#define amdgpu_dpm_get_sclk(adev, l) (adev)->pm.funcs->get_sclk((adev), (l))
-#define amdgpu_dpm_get_mclk(adev, l) (adev)->pm.funcs->get_mclk((adev), (l))
#define amdgpu_dpm_print_power_state(adev, ps) (adev)->pm.funcs->print_power_state((adev), (ps))
-#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) (adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m))
-#define amdgpu_dpm_force_performance_level(adev, l) (adev)->pm.funcs->force_performance_level((adev), (l))
#define amdgpu_dpm_vblank_too_short(adev) (adev)->pm.funcs->vblank_too_short((adev))
-#define amdgpu_dpm_powergate_uvd(adev, g) (adev)->pm.funcs->powergate_uvd((adev), (g))
-#define amdgpu_dpm_powergate_vce(adev, g) (adev)->pm.funcs->powergate_vce((adev), (g))
#define amdgpu_dpm_enable_bapm(adev, e) (adev)->pm.funcs->enable_bapm((adev), (e))
-#define amdgpu_dpm_set_fan_control_mode(adev, m) (adev)->pm.funcs->set_fan_control_mode((adev), (m))
-#define amdgpu_dpm_get_fan_control_mode(adev) (adev)->pm.funcs->get_fan_control_mode((adev))
-#define amdgpu_dpm_set_fan_speed_percent(adev, s) (adev)->pm.funcs->set_fan_speed_percent((adev), (s))
-#define amdgpu_dpm_get_fan_speed_percent(adev, s) (adev)->pm.funcs->get_fan_speed_percent((adev), (s))
+
+#define amdgpu_dpm_get_temperature(adev) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->get_temperature((adev)->powerplay.pp_handle) : \
+ (adev)->pm.funcs->get_temperature((adev))
+
+#define amdgpu_dpm_set_fan_control_mode(adev, m) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->set_fan_control_mode((adev)->powerplay.pp_handle, (m)) : \
+ (adev)->pm.funcs->set_fan_control_mode((adev), (m))
+
+#define amdgpu_dpm_get_fan_control_mode(adev) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->get_fan_control_mode((adev)->powerplay.pp_handle) : \
+ (adev)->pm.funcs->get_fan_control_mode((adev))
+
+#define amdgpu_dpm_set_fan_speed_percent(adev, s) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->set_fan_speed_percent((adev)->powerplay.pp_handle, (s)) : \
+ (adev)->pm.funcs->set_fan_speed_percent((adev), (s))
+
+#define amdgpu_dpm_get_fan_speed_percent(adev, s) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->get_fan_speed_percent((adev)->powerplay.pp_handle, (s)) : \
+ (adev)->pm.funcs->get_fan_speed_percent((adev), (s))
+
+#define amdgpu_dpm_get_sclk(adev, l) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->get_sclk((adev)->powerplay.pp_handle, (l)) : \
+ (adev)->pm.funcs->get_sclk((adev), (l))
+
+#define amdgpu_dpm_get_mclk(adev, l) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->get_mclk((adev)->powerplay.pp_handle, (l)) : \
+ (adev)->pm.funcs->get_mclk((adev), (l))
+
+
+#define amdgpu_dpm_force_performance_level(adev, l) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->force_performance_level((adev)->powerplay.pp_handle, (l)) : \
+ (adev)->pm.funcs->force_performance_level((adev), (l))
+
+#define amdgpu_dpm_powergate_uvd(adev, g) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->powergate_uvd((adev)->powerplay.pp_handle, (g)) : \
+ (adev)->pm.funcs->powergate_uvd((adev), (g))
+
+#define amdgpu_dpm_powergate_vce(adev, g) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->powergate_vce((adev)->powerplay.pp_handle, (g)) : \
+ (adev)->pm.funcs->powergate_vce((adev), (g))
+
+#define amdgpu_dpm_debugfs_print_current_performance_level(adev, m) \
+ (adev)->pp_enabled ? \
+ (adev)->powerplay.pp_funcs->print_current_performance_level((adev)->powerplay.pp_handle, (m)) : \
+ (adev)->pm.funcs->debugfs_print_current_performance_level((adev), (m))
+
+#define amdgpu_dpm_get_current_power_state(adev) \
+ (adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)
+
+#define amdgpu_dpm_get_performance_level(adev) \
+ (adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle)
+
+#define amdgpu_dpm_dispatch_task(adev, event_id, input, output) \
+ (adev)->powerplay.pp_funcs->dispatch_tasks((adev)->powerplay.pp_handle, (event_id), (input), (output))
#define amdgpu_gds_switch(adev, r, v, d, w, a) (adev)->gds.funcs->patch_gds_switch((r), (v), (d), (w), (a))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index a142d5ae148d..5cd7b736a9de 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -29,66 +29,10 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "amdgpu.h"
-#include "amdgpu_acpi.h"
+#include "amd_acpi.h"
#include "atom.h"
-#define ACPI_AC_CLASS "ac_adapter"
-
extern void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev);
-
-struct atif_verify_interface {
- u16 size; /* structure size in bytes (includes size field) */
- u16 version; /* version */
- u32 notification_mask; /* supported notifications mask */
- u32 function_bits; /* supported functions bit vector */
-} __packed;
-
-struct atif_system_params {
- u16 size; /* structure size in bytes (includes size field) */
- u32 valid_mask; /* valid flags mask */
- u32 flags; /* flags */
- u8 command_code; /* notify command code */
-} __packed;
-
-struct atif_sbios_requests {
- u16 size; /* structure size in bytes (includes size field) */
- u32 pending; /* pending sbios requests */
- u8 panel_exp_mode; /* panel expansion mode */
- u8 thermal_gfx; /* thermal state: target gfx controller */
- u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */
- u8 forced_power_gfx; /* forced power state: target gfx controller */
- u8 forced_power_state; /* forced power state: state id */
- u8 system_power_src; /* system power source */
- u8 backlight_level; /* panel backlight level (0-255) */
-} __packed;
-
-#define ATIF_NOTIFY_MASK 0x3
-#define ATIF_NOTIFY_NONE 0
-#define ATIF_NOTIFY_81 1
-#define ATIF_NOTIFY_N 2
-
-struct atcs_verify_interface {
- u16 size; /* structure size in bytes (includes size field) */
- u16 version; /* version */
- u32 function_bits; /* supported functions bit vector */
-} __packed;
-
-#define ATCS_VALID_FLAGS_MASK 0x3
-
-struct atcs_pref_req_input {
- u16 size; /* structure size in bytes (includes size field) */
- u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
- u16 valid_flags_mask; /* valid flags mask */
- u16 flags; /* flags */
- u8 req_type; /* request type */
- u8 perf_req; /* performance request */
-} __packed;
-
-struct atcs_pref_req_output {
- u16 size; /* structure size in bytes (includes size field) */
- u8 ret_val; /* return value */
-} __packed;
-
/* Call the ATIF method
*/
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
index 5a8fbadbd27b..3c895863fcf5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -11,7 +11,7 @@
#include <linux/acpi.h>
#include <linux/pci.h>
-#include "amdgpu_acpi.h"
+#include "amd_acpi.h"
struct amdgpu_atpx_functions {
bool px_params;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index c44c0c6afd1b..80add22375ee 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -35,6 +35,13 @@
* BIOS.
*/
+#define AMD_VBIOS_SIGNATURE " 761295520"
+#define AMD_VBIOS_SIGNATURE_OFFSET 0x30
+#define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
+#define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
+#define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
+#define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
+
/* If you boot an IGP board with a discrete card as the primary,
* the IGP rom is not accessible via the rom bar as the IGP rom is
* part of the system bios. On boot, the system bios puts a
@@ -58,7 +65,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
return false;
}
- if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
iounmap(bios);
return false;
}
@@ -74,7 +81,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
bool amdgpu_read_bios(struct amdgpu_device *adev)
{
- uint8_t __iomem *bios, val1, val2;
+ uint8_t __iomem *bios, val[2];
size_t size;
adev->bios = NULL;
@@ -84,10 +91,10 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
return false;
}
- val1 = readb(&bios[0]);
- val2 = readb(&bios[1]);
+ val[0] = readb(&bios[0]);
+ val[1] = readb(&bios[1]);
- if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
+ if (size == 0 || !AMD_IS_VALID_VBIOS(val)) {
pci_unmap_rom(adev->pdev, bios);
return false;
}
@@ -101,6 +108,38 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
return true;
}
+static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
+{
+ u8 header[AMD_VBIOS_SIGNATURE_END+1] = {0};
+ int len;
+
+ if (!adev->asic_funcs->read_bios_from_rom)
+ return false;
+
+ /* validate VBIOS signature */
+ if (amdgpu_asic_read_bios_from_rom(adev, &header[0], sizeof(header)) == false)
+ return false;
+ header[AMD_VBIOS_SIGNATURE_END] = 0;
+
+ if ((!AMD_IS_VALID_VBIOS(header)) ||
+ 0 != memcmp((char *)&header[AMD_VBIOS_SIGNATURE_OFFSET],
+ AMD_VBIOS_SIGNATURE,
+ strlen(AMD_VBIOS_SIGNATURE)))
+ return false;
+
+ /* valid vbios, go on */
+ len = AMD_VBIOS_LENGTH(header);
+ len = ALIGN(len, 4);
+ adev->bios = kmalloc(len, GFP_KERNEL);
+ if (!adev->bios) {
+ DRM_ERROR("no memory to allocate for BIOS\n");
+ return false;
+ }
+
+ /* read complete BIOS */
+ return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
+}
+
static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
{
uint8_t __iomem *bios;
@@ -113,7 +152,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
return false;
}
- if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ if (size == 0 || !AMD_IS_VALID_VBIOS(bios)) {
return false;
}
adev->bios = kmemdup(bios, size, GFP_KERNEL);
@@ -230,7 +269,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
break;
}
- if (i == 0 || adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
+ if (i == 0 || !AMD_IS_VALID_VBIOS(adev->bios)) {
kfree(adev->bios);
return false;
}
@@ -320,6 +359,9 @@ bool amdgpu_get_bios(struct amdgpu_device *adev)
if (r == false)
r = amdgpu_read_bios(adev);
if (r == false) {
+ r = amdgpu_read_bios_from_rom(adev);
+ }
+ if (r == false) {
r = amdgpu_read_disabled_bios(adev);
}
if (r == false) {
@@ -330,7 +372,7 @@ bool amdgpu_get_bios(struct amdgpu_device *adev)
adev->bios = NULL;
return false;
}
- if (adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
+ if (!AMD_IS_VALID_VBIOS(adev->bios)) {
printk("BIOS signature incorrect %x %x\n", adev->bios[0], adev->bios[1]);
goto free_bios;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
index 8e995148f56e..a081dda9fa2f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/acpi.h>
#include <drm/drmP.h>
#include <linux/firmware.h>
#include <drm/amdgpu_drm.h>
@@ -32,7 +33,6 @@
#include "atom.h"
#include "amdgpu_ucode.h"
-
struct amdgpu_cgs_device {
struct cgs_device base;
struct amdgpu_device *adev;
@@ -398,6 +398,41 @@ static void amdgpu_cgs_write_pci_config_dword(void *cgs_device, unsigned addr,
WARN(ret, "pci_write_config_dword error");
}
+
+static int amdgpu_cgs_get_pci_resource(void *cgs_device,
+ enum cgs_resource_type resource_type,
+ uint64_t size,
+ uint64_t offset,
+ uint64_t *resource_base)
+{
+ CGS_FUNC_ADEV;
+
+ if (resource_base == NULL)
+ return -EINVAL;
+
+ switch (resource_type) {
+ case CGS_RESOURCE_TYPE_MMIO:
+ if (adev->rmmio_size == 0)
+ return -ENOENT;
+ if ((offset + size) > adev->rmmio_size)
+ return -EINVAL;
+ *resource_base = adev->rmmio_base;
+ return 0;
+ case CGS_RESOURCE_TYPE_DOORBELL:
+ if (adev->doorbell.size == 0)
+ return -ENOENT;
+ if ((offset + size) > adev->doorbell.size)
+ return -EINVAL;
+ *resource_base = adev->doorbell.base;
+ return 0;
+ case CGS_RESOURCE_TYPE_FB:
+ case CGS_RESOURCE_TYPE_IO:
+ case CGS_RESOURCE_TYPE_ROM:
+ default:
+ return -EINVAL;
+ }
+}
+
static const void *amdgpu_cgs_atom_get_data_table(void *cgs_device,
unsigned table, uint16_t *size,
uint8_t *frev, uint8_t *crev)
@@ -703,6 +738,9 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device,
case CHIP_TONGA:
strcpy(fw_name, "amdgpu/tonga_smc.bin");
break;
+ case CHIP_FIJI:
+ strcpy(fw_name, "amdgpu/fiji_smc.bin");
+ break;
default:
DRM_ERROR("SMC firmware not supported\n");
return -EINVAL;
@@ -736,6 +774,288 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device,
return 0;
}
+static int amdgpu_cgs_query_system_info(void *cgs_device,
+ struct cgs_system_info *sys_info)
+{
+ CGS_FUNC_ADEV;
+
+ if (NULL == sys_info)
+ return -ENODEV;
+
+ if (sizeof(struct cgs_system_info) != sys_info->size)
+ return -ENODEV;
+
+ switch (sys_info->info_id) {
+ case CGS_SYSTEM_INFO_ADAPTER_BDF_ID:
+ sys_info->value = adev->pdev->devfn | (adev->pdev->bus->number << 8);
+ break;
+ case CGS_SYSTEM_INFO_PCIE_GEN_INFO:
+ sys_info->value = adev->pm.pcie_gen_mask;
+ break;
+ case CGS_SYSTEM_INFO_PCIE_MLW:
+ sys_info->value = adev->pm.pcie_mlw_mask;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amdgpu_cgs_get_active_displays_info(void *cgs_device,
+ struct cgs_display_info *info)
+{
+ CGS_FUNC_ADEV;
+ struct amdgpu_crtc *amdgpu_crtc;
+ struct drm_device *ddev = adev->ddev;
+ struct drm_crtc *crtc;
+ uint32_t line_time_us, vblank_lines;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+ list_for_each_entry(crtc,
+ &ddev->mode_config.crtc_list, head) {
+ amdgpu_crtc = to_amdgpu_crtc(crtc);
+ if (crtc->enabled) {
+ info->active_display_mask |= (1 << amdgpu_crtc->crtc_id);
+ info->display_count++;
+ }
+ if (info->mode_info != NULL &&
+ crtc->enabled && amdgpu_crtc->enabled &&
+ amdgpu_crtc->hw_mode.clock) {
+ line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
+ amdgpu_crtc->hw_mode.clock;
+ vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
+ amdgpu_crtc->hw_mode.crtc_vdisplay +
+ (amdgpu_crtc->v_border * 2);
+ info->mode_info->vblank_time_us = vblank_lines * line_time_us;
+ info->mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
+ info->mode_info->ref_clock = adev->clock.spll.reference_freq;
+ info->mode_info++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/** \brief evaluate acpi namespace object, handle or pathname must be valid
+ * \param cgs_device
+ * \param info input/output arguments for the control method
+ * \return status
+ */
+
+#if defined(CONFIG_ACPI)
+static int amdgpu_cgs_acpi_eval_object(void *cgs_device,
+ struct cgs_acpi_method_info *info)
+{
+ CGS_FUNC_ADEV;
+ acpi_handle handle;
+ struct acpi_object_list input;
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *params = NULL;
+ union acpi_object *obj = NULL;
+ uint8_t name[5] = {'\0'};
+ struct cgs_acpi_method_argument *argument = NULL;
+ uint32_t i, count;
+ acpi_status status;
+ int result;
+ uint32_t func_no = 0xFFFFFFFF;
+
+ handle = ACPI_HANDLE(&adev->pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ memset(&input, 0, sizeof(struct acpi_object_list));
+
+ /* validate input info */
+ if (info->size != sizeof(struct cgs_acpi_method_info))
+ return -EINVAL;
+
+ input.count = info->input_count;
+ if (info->input_count > 0) {
+ if (info->pinput_argument == NULL)
+ return -EINVAL;
+ argument = info->pinput_argument;
+ func_no = argument->value;
+ for (i = 0; i < info->input_count; i++) {
+ if (((argument->type == ACPI_TYPE_STRING) ||
+ (argument->type == ACPI_TYPE_BUFFER)) &&
+ (argument->pointer == NULL))
+ return -EINVAL;
+ argument++;
+ }
+ }
+
+ if (info->output_count > 0) {
+ if (info->poutput_argument == NULL)
+ return -EINVAL;
+ argument = info->poutput_argument;
+ for (i = 0; i < info->output_count; i++) {
+ if (((argument->type == ACPI_TYPE_STRING) ||
+ (argument->type == ACPI_TYPE_BUFFER))
+ && (argument->pointer == NULL))
+ return -EINVAL;
+ argument++;
+ }
+ }
+
+ /* The path name passed to acpi_evaluate_object should be null terminated */
+ if ((info->field & CGS_ACPI_FIELD_METHOD_NAME) != 0) {
+ strncpy(name, (char *)&(info->name), sizeof(uint32_t));
+ name[4] = '\0';
+ }
+
+ /* parse input parameters */
+ if (input.count > 0) {
+ input.pointer = params =
+ kzalloc(sizeof(union acpi_object) * input.count, GFP_KERNEL);
+ if (params == NULL)
+ return -EINVAL;
+
+ argument = info->pinput_argument;
+
+ for (i = 0; i < input.count; i++) {
+ params->type = argument->type;
+ switch (params->type) {
+ case ACPI_TYPE_INTEGER:
+ params->integer.value = argument->value;
+ break;
+ case ACPI_TYPE_STRING:
+ params->string.length = argument->method_length;
+ params->string.pointer = argument->pointer;
+ break;
+ case ACPI_TYPE_BUFFER:
+ params->buffer.length = argument->method_length;
+ params->buffer.pointer = argument->pointer;
+ break;
+ default:
+ break;
+ }
+ params++;
+ argument++;
+ }
+ }
+
+ /* parse output info */
+ count = info->output_count;
+ argument = info->poutput_argument;
+
+ /* evaluate the acpi method */
+ status = acpi_evaluate_object(handle, name, &input, &output);
+
+ if (ACPI_FAILURE(status)) {
+ result = -EIO;
+ goto error;
+ }
+
+ /* return the output info */
+ obj = output.pointer;
+
+ if (count > 1) {
+ if ((obj->type != ACPI_TYPE_PACKAGE) ||
+ (obj->package.count != count)) {
+ result = -EIO;
+ goto error;
+ }
+ params = obj->package.elements;
+ } else
+ params = obj;
+
+ if (params == NULL) {
+ result = -EIO;
+ goto error;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (argument->type != params->type) {
+ result = -EIO;
+ goto error;
+ }
+ switch (params->type) {
+ case ACPI_TYPE_INTEGER:
+ argument->value = params->integer.value;
+ break;
+ case ACPI_TYPE_STRING:
+ if ((params->string.length != argument->data_length) ||
+ (params->string.pointer == NULL)) {
+ result = -EIO;
+ goto error;
+ }
+ strncpy(argument->pointer,
+ params->string.pointer,
+ params->string.length);
+ break;
+ case ACPI_TYPE_BUFFER:
+ if (params->buffer.pointer == NULL) {
+ result = -EIO;
+ goto error;
+ }
+ memcpy(argument->pointer,
+ params->buffer.pointer,
+ argument->data_length);
+ break;
+ default:
+ break;
+ }
+ argument++;
+ params++;
+ }
+
+error:
+ if (obj != NULL)
+ kfree(obj);
+ kfree((void *)input.pointer);
+ return result;
+}
+#else
+static int amdgpu_cgs_acpi_eval_object(void *cgs_device,
+ struct cgs_acpi_method_info *info)
+{
+ return -EIO;
+}
+#endif
+
+int amdgpu_cgs_call_acpi_method(void *cgs_device,
+ uint32_t acpi_method,
+ uint32_t acpi_function,
+ void *pinput, void *poutput,
+ uint32_t output_count,
+ uint32_t input_size,
+ uint32_t output_size)
+{
+ struct cgs_acpi_method_argument acpi_input[2] = { {0}, {0} };
+ struct cgs_acpi_method_argument acpi_output = {0};
+ struct cgs_acpi_method_info info = {0};
+
+ acpi_input[0].type = CGS_ACPI_TYPE_INTEGER;
+ acpi_input[0].method_length = sizeof(uint32_t);
+ acpi_input[0].data_length = sizeof(uint32_t);
+ acpi_input[0].value = acpi_function;
+
+ acpi_input[1].type = CGS_ACPI_TYPE_BUFFER;
+ acpi_input[1].method_length = CGS_ACPI_MAX_BUFFER_SIZE;
+ acpi_input[1].data_length = input_size;
+ acpi_input[1].pointer = pinput;
+
+ acpi_output.type = CGS_ACPI_TYPE_BUFFER;
+ acpi_output.method_length = CGS_ACPI_MAX_BUFFER_SIZE;
+ acpi_output.data_length = output_size;
+ acpi_output.pointer = poutput;
+
+ info.size = sizeof(struct cgs_acpi_method_info);
+ info.field = CGS_ACPI_FIELD_METHOD_NAME | CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT;
+ info.input_count = 2;
+ info.name = acpi_method;
+ info.pinput_argument = acpi_input;
+ info.output_count = output_count;
+ info.poutput_argument = &acpi_output;
+
+ return amdgpu_cgs_acpi_eval_object(cgs_device, &info);
+}
+
static const struct cgs_ops amdgpu_cgs_ops = {
amdgpu_cgs_gpu_mem_info,
amdgpu_cgs_gmap_kmem,
@@ -756,6 +1076,7 @@ static const struct cgs_ops amdgpu_cgs_ops = {
amdgpu_cgs_write_pci_config_byte,
amdgpu_cgs_write_pci_config_word,
amdgpu_cgs_write_pci_config_dword,
+ amdgpu_cgs_get_pci_resource,
amdgpu_cgs_atom_get_data_table,
amdgpu_cgs_atom_get_cmd_table_revs,
amdgpu_cgs_atom_exec_cmd_table,
@@ -768,7 +1089,10 @@ static const struct cgs_ops amdgpu_cgs_ops = {
amdgpu_cgs_set_camera_voltages,
amdgpu_cgs_get_firmware_info,
amdgpu_cgs_set_powergating_state,
- amdgpu_cgs_set_clockgating_state
+ amdgpu_cgs_set_clockgating_state,
+ amdgpu_cgs_get_active_displays_info,
+ amdgpu_cgs_call_acpi_method,
+ amdgpu_cgs_query_system_info,
};
static const struct cgs_os_ops amdgpu_cgs_os_ops = {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 25a3e2485cc2..6f89f8e034d0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -406,8 +406,8 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
amdgpu_cs_buckets_get_list(&buckets, &p->validated);
}
- p->vm_bos = amdgpu_vm_get_bos(p->adev, &fpriv->vm,
- &p->validated);
+ INIT_LIST_HEAD(&duplicates);
+ amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd);
if (p->uf.bo)
list_add(&p->uf_entry.tv.head, &p->validated);
@@ -415,20 +415,23 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
if (need_mmap_lock)
down_read(&current->mm->mmap_sem);
- INIT_LIST_HEAD(&duplicates);
r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates);
if (unlikely(r != 0))
goto error_reserve;
- r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated);
+ amdgpu_vm_get_pt_bos(&fpriv->vm, &duplicates);
+
+ r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates);
if (r)
goto error_validate;
- r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates);
+ r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated);
error_validate:
- if (r)
+ if (r) {
+ amdgpu_vm_move_pt_bos_in_lru(p->adev, &fpriv->vm);
ttm_eu_backoff_reservation(&p->ticket, &p->validated);
+ }
error_reserve:
if (need_mmap_lock)
@@ -472,8 +475,11 @@ static int cmp_size_smaller_first(void *priv, struct list_head *a,
**/
static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
{
+ struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
unsigned i;
+ amdgpu_vm_move_pt_bos_in_lru(parser->adev, &fpriv->vm);
+
if (!error) {
/* Sort the buffer list from the smallest to largest buffer,
* which affects the order of buffers in the LRU list.
@@ -501,7 +507,6 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
if (parser->bo_list)
amdgpu_bo_list_put(parser->bo_list);
- drm_free_large(parser->vm_bos);
for (i = 0; i < parser->nchunks; i++)
drm_free_large(parser->chunks[i].kdata);
kfree(parser->chunks);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index fec65f01c031..17d1fb12128a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -25,7 +25,7 @@
#include <drm/drmP.h>
#include "amdgpu.h"
-int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
+int amdgpu_ctx_init(struct amdgpu_device *adev, enum amd_sched_priority pri,
struct amdgpu_ctx *ctx)
{
unsigned i, j;
@@ -35,17 +35,25 @@ int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
ctx->adev = adev;
kref_init(&ctx->refcount);
spin_lock_init(&ctx->ring_lock);
- for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
- ctx->rings[i].sequence = 1;
+ ctx->fences = kzalloc(sizeof(struct fence *) * amdgpu_sched_jobs *
+ AMDGPU_MAX_RINGS, GFP_KERNEL);
+ if (!ctx->fences)
+ return -ENOMEM;
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ ctx->rings[i].sequence = 1;
+ ctx->rings[i].fences = (void *)ctx->fences + sizeof(struct fence *) *
+ amdgpu_sched_jobs * i;
+ }
if (amdgpu_enable_scheduler) {
/* create context entity for each ring */
for (i = 0; i < adev->num_rings; i++) {
struct amd_sched_rq *rq;
- if (kernel)
- rq = &adev->rings[i]->sched.kernel_rq;
- else
- rq = &adev->rings[i]->sched.sched_rq;
+ if (pri >= AMD_SCHED_MAX_PRIORITY) {
+ kfree(ctx->fences);
+ return -EINVAL;
+ }
+ rq = &adev->rings[i]->sched.sched_rq[pri];
r = amd_sched_entity_init(&adev->rings[i]->sched,
&ctx->rings[i].entity,
rq, amdgpu_sched_jobs);
@@ -57,7 +65,7 @@ int amdgpu_ctx_init(struct amdgpu_device *adev, bool kernel,
for (j = 0; j < i; j++)
amd_sched_entity_fini(&adev->rings[j]->sched,
&ctx->rings[j].entity);
- kfree(ctx);
+ kfree(ctx->fences);
return r;
}
}
@@ -73,8 +81,9 @@ void amdgpu_ctx_fini(struct amdgpu_ctx *ctx)
return;
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
- for (j = 0; j < AMDGPU_CTX_MAX_CS_PENDING; ++j)
+ for (j = 0; j < amdgpu_sched_jobs; ++j)
fence_put(ctx->rings[i].fences[j]);
+ kfree(ctx->fences);
if (amdgpu_enable_scheduler) {
for (i = 0; i < adev->num_rings; i++)
@@ -103,9 +112,13 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
return r;
}
*id = (uint32_t)r;
- r = amdgpu_ctx_init(adev, false, ctx);
+ r = amdgpu_ctx_init(adev, AMD_SCHED_PRIORITY_NORMAL, ctx);
+ if (r) {
+ idr_remove(&mgr->ctx_handles, *id);
+ *id = 0;
+ kfree(ctx);
+ }
mutex_unlock(&mgr->lock);
-
return r;
}
@@ -239,7 +252,7 @@ uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring,
unsigned idx = 0;
struct fence *other = NULL;
- idx = seq % AMDGPU_CTX_MAX_CS_PENDING;
+ idx = seq & (amdgpu_sched_jobs - 1);
other = cring->fences[idx];
if (other) {
signed long r;
@@ -274,12 +287,12 @@ struct fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
}
- if (seq + AMDGPU_CTX_MAX_CS_PENDING < cring->sequence) {
+ if (seq + amdgpu_sched_jobs < cring->sequence) {
spin_unlock(&ctx->ring_lock);
return NULL;
}
- fence = fence_get(cring->fences[seq % AMDGPU_CTX_MAX_CS_PENDING]);
+ fence = fence_get(cring->fences[seq & (amdgpu_sched_jobs - 1)]);
spin_unlock(&ctx->ring_lock);
return fence;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index d5b421330145..65531463f88e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -38,6 +38,7 @@
#include "amdgpu_i2c.h"
#include "atom.h"
#include "amdgpu_atombios.h"
+#include "amd_pcie.h"
#ifdef CONFIG_DRM_AMDGPU_CIK
#include "cik.h"
#endif
@@ -949,6 +950,15 @@ static bool amdgpu_check_pot_argument(int arg)
*/
static void amdgpu_check_arguments(struct amdgpu_device *adev)
{
+ if (amdgpu_sched_jobs < 4) {
+ dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n",
+ amdgpu_sched_jobs);
+ amdgpu_sched_jobs = 4;
+ } else if (!amdgpu_check_pot_argument(amdgpu_sched_jobs)){
+ dev_warn(adev->dev, "sched jobs (%d) must be a power of 2\n",
+ amdgpu_sched_jobs);
+ amdgpu_sched_jobs = roundup_pow_of_two(amdgpu_sched_jobs);
+ }
/* vramlimit must be a power of two */
if (!amdgpu_check_pot_argument(amdgpu_vram_limit)) {
dev_warn(adev->dev, "vram limit (%d) must be a power of 2\n",
@@ -1214,12 +1224,14 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
} else {
if (adev->ip_blocks[i].funcs->early_init) {
r = adev->ip_blocks[i].funcs->early_init((void *)adev);
- if (r == -ENOENT)
+ if (r == -ENOENT) {
adev->ip_block_status[i].valid = false;
- else if (r)
+ } else if (r) {
+ DRM_ERROR("early_init %d failed %d\n", i, r);
return r;
- else
+ } else {
adev->ip_block_status[i].valid = true;
+ }
} else {
adev->ip_block_status[i].valid = true;
}
@@ -1237,20 +1249,28 @@ static int amdgpu_init(struct amdgpu_device *adev)
if (!adev->ip_block_status[i].valid)
continue;
r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
- if (r)
+ if (r) {
+ DRM_ERROR("sw_init %d failed %d\n", i, r);
return r;
+ }
adev->ip_block_status[i].sw = true;
/* need to do gmc hw init early so we can allocate gpu mem */
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
r = amdgpu_vram_scratch_init(adev);
- if (r)
+ if (r) {
+ DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r);
return r;
+ }
r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
- if (r)
+ if (r) {
+ DRM_ERROR("hw_init %d failed %d\n", i, r);
return r;
+ }
r = amdgpu_wb_init(adev);
- if (r)
+ if (r) {
+ DRM_ERROR("amdgpu_wb_init failed %d\n", r);
return r;
+ }
adev->ip_block_status[i].hw = true;
}
}
@@ -1262,8 +1282,10 @@ static int amdgpu_init(struct amdgpu_device *adev)
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
continue;
r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
- if (r)
+ if (r) {
+ DRM_ERROR("hw_init %d failed %d\n", i, r);
return r;
+ }
adev->ip_block_status[i].hw = true;
}
@@ -1280,12 +1302,16 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
/* enable clockgating to save power */
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
AMD_CG_STATE_GATE);
- if (r)
+ if (r) {
+ DRM_ERROR("set_clockgating_state(gate) %d failed %d\n", i, r);
return r;
+ }
if (adev->ip_blocks[i].funcs->late_init) {
r = adev->ip_blocks[i].funcs->late_init((void *)adev);
- if (r)
+ if (r) {
+ DRM_ERROR("late_init %d failed %d\n", i, r);
return r;
+ }
}
}
@@ -1306,10 +1332,15 @@ static int amdgpu_fini(struct amdgpu_device *adev)
/* ungate blocks before hw fini so that we can shutdown the blocks safely */
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
AMD_CG_STATE_UNGATE);
- if (r)
+ if (r) {
+ DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r);
return r;
+ }
r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
/* XXX handle errors */
+ if (r) {
+ DRM_DEBUG("hw_fini %d failed %d\n", i, r);
+ }
adev->ip_block_status[i].hw = false;
}
@@ -1318,6 +1349,9 @@ static int amdgpu_fini(struct amdgpu_device *adev)
continue;
r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
/* XXX handle errors */
+ if (r) {
+ DRM_DEBUG("sw_fini %d failed %d\n", i, r);
+ }
adev->ip_block_status[i].sw = false;
adev->ip_block_status[i].valid = false;
}
@@ -1335,9 +1369,15 @@ static int amdgpu_suspend(struct amdgpu_device *adev)
/* ungate blocks so that suspend can properly shut them down */
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
AMD_CG_STATE_UNGATE);
+ if (r) {
+ DRM_ERROR("set_clockgating_state(ungate) %d failed %d\n", i, r);
+ }
/* XXX handle errors */
r = adev->ip_blocks[i].funcs->suspend(adev);
/* XXX handle errors */
+ if (r) {
+ DRM_ERROR("suspend %d failed %d\n", i, r);
+ }
}
return 0;
@@ -1351,8 +1391,10 @@ static int amdgpu_resume(struct amdgpu_device *adev)
if (!adev->ip_block_status[i].valid)
continue;
r = adev->ip_blocks[i].funcs->resume(adev);
- if (r)
+ if (r) {
+ DRM_ERROR("resume %d failed %d\n", i, r);
return r;
+ }
}
return 0;
@@ -1484,8 +1526,10 @@ int amdgpu_device_init(struct amdgpu_device *adev,
return -EINVAL;
}
r = amdgpu_atombios_init(adev);
- if (r)
+ if (r) {
+ dev_err(adev->dev, "amdgpu_atombios_init failed\n");
return r;
+ }
/* Post card if necessary */
if (!amdgpu_card_posted(adev)) {
@@ -1499,21 +1543,26 @@ int amdgpu_device_init(struct amdgpu_device *adev,
/* Initialize clocks */
r = amdgpu_atombios_get_clock_info(adev);
- if (r)
+ if (r) {
+ dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
return r;
+ }
/* init i2c buses */
amdgpu_atombios_i2c_init(adev);
/* Fence driver */
r = amdgpu_fence_driver_init(adev);
- if (r)
+ if (r) {
+ dev_err(adev->dev, "amdgpu_fence_driver_init failed\n");
return r;
+ }
/* init the mode config */
drm_mode_config_init(adev->ddev);
r = amdgpu_init(adev);
if (r) {
+ dev_err(adev->dev, "amdgpu_init failed\n");
amdgpu_fini(adev);
return r;
}
@@ -1528,7 +1577,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
return r;
}
- r = amdgpu_ctx_init(adev, true, &adev->kernel_ctx);
+ r = amdgpu_ctx_init(adev, AMD_SCHED_PRIORITY_KERNEL, &adev->kernel_ctx);
if (r) {
dev_err(adev->dev, "failed to create kernel context (%d).\n", r);
return r;
@@ -1570,8 +1619,10 @@ int amdgpu_device_init(struct amdgpu_device *adev,
* explicit gating rather than handling it automatically.
*/
r = amdgpu_late_init(adev);
- if (r)
+ if (r) {
+ dev_err(adev->dev, "amdgpu_late_init failed\n");
return r;
+ }
return 0;
}
@@ -1788,6 +1839,7 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
}
drm_kms_helper_poll_enable(dev);
+ drm_helper_hpd_irq_event(dev);
if (fbcon) {
amdgpu_fbdev_set_suspend(adev, 0);
@@ -1881,6 +1933,83 @@ retry:
return r;
}
+void amdgpu_get_pcie_info(struct amdgpu_device *adev)
+{
+ u32 mask;
+ int ret;
+
+ if (pci_is_root_bus(adev->pdev->bus))
+ return;
+
+ if (amdgpu_pcie_gen2 == 0)
+ return;
+
+ if (adev->flags & AMD_IS_APU)
+ return;
+
+ ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
+ if (!ret) {
+ adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
+ CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+ CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
+
+ if (mask & DRM_PCIE_SPEED_25)
+ adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1;
+ if (mask & DRM_PCIE_SPEED_50)
+ adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2;
+ if (mask & DRM_PCIE_SPEED_80)
+ adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3;
+ }
+ ret = drm_pcie_get_max_link_width(adev->ddev, &mask);
+ if (!ret) {
+ switch (mask) {
+ case 32:
+ adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+ break;
+ case 16:
+ adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+ break;
+ case 12:
+ adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+ break;
+ case 8:
+ adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+ break;
+ case 4:
+ adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+ break;
+ case 2:
+ adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+ CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+ break;
+ case 1:
+ adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1;
+ break;
+ default:
+ break;
+ }
+ }
+}
/*
* Debugfs
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 5580d3420c3a..acd066d0a805 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -518,7 +518,7 @@ static const struct drm_framebuffer_funcs amdgpu_fb_funcs = {
int
amdgpu_framebuffer_init(struct drm_device *dev,
struct amdgpu_framebuffer *rfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -535,7 +535,7 @@ amdgpu_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
amdgpu_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct amdgpu_framebuffer *amdgpu_fb;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 0508c5cd103a..b5dbbb573491 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -79,9 +79,10 @@ int amdgpu_vm_fault_stop = 0;
int amdgpu_vm_debug = 0;
int amdgpu_exp_hw_support = 0;
int amdgpu_enable_scheduler = 1;
-int amdgpu_sched_jobs = 16;
+int amdgpu_sched_jobs = 32;
int amdgpu_sched_hw_submission = 2;
int amdgpu_enable_semaphores = 0;
+int amdgpu_powerplay = -1;
MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
@@ -155,7 +156,7 @@ module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444);
MODULE_PARM_DESC(enable_scheduler, "enable SW GPU scheduler (1 = enable (default), 0 = disable)");
module_param_named(enable_scheduler, amdgpu_enable_scheduler, int, 0444);
-MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 16)");
+MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 32)");
module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444);
MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)");
@@ -164,6 +165,11 @@ module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444);
MODULE_PARM_DESC(enable_semaphores, "Enable semaphores (1 = enable, 0 = disable (default))");
module_param_named(enable_semaphores, amdgpu_enable_semaphores, int, 0644);
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+MODULE_PARM_DESC(powerplay, "Powerplay component (1 = enable, 0 = disable, -1 = auto (default))");
+module_param_named(powerplay, amdgpu_powerplay, int, 0444);
+#endif
+
static struct pci_device_id pciidlist[] = {
#ifdef CONFIG_DRM_AMDGPU_CIK
/* Kaveri */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
index 093a8c618931..cfb6caad2a73 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -45,7 +45,6 @@
struct amdgpu_fbdev {
struct drm_fb_helper helper;
struct amdgpu_framebuffer rfb;
- struct list_head fbdev_list;
struct amdgpu_device *adev;
};
@@ -264,7 +263,7 @@ out_unref:
}
if (fb && ret) {
- drm_gem_object_unreference(gobj);
+ drm_gem_object_unreference_unlocked(gobj);
drm_framebuffer_unregister_private(fb);
drm_framebuffer_cleanup(fb);
kfree(fb);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 9c253c535d26..7380f782cd14 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -448,7 +448,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va, uint32_t operation)
{
struct ttm_validate_buffer tv, *entry;
- struct amdgpu_bo_list_entry *vm_bos;
+ struct amdgpu_bo_list_entry vm_pd;
struct ww_acquire_ctx ticket;
struct list_head list, duplicates;
unsigned domain;
@@ -461,15 +461,14 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
tv.shared = true;
list_add(&tv.head, &list);
- vm_bos = amdgpu_vm_get_bos(adev, bo_va->vm, &list);
- if (!vm_bos)
- return;
+ amdgpu_vm_get_pd_bo(bo_va->vm, &list, &vm_pd);
/* Provide duplicates to avoid -EALREADY */
r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates);
if (r)
- goto error_free;
+ goto error_print;
+ amdgpu_vm_get_pt_bos(bo_va->vm, &duplicates);
list_for_each_entry(entry, &list, head) {
domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type);
/* if anything is swapped out don't swap it in here,
@@ -499,9 +498,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
error_unreserve:
ttm_eu_backoff_reservation(&ticket, &list);
-error_free:
- drm_free_large(vm_bos);
-
+error_print:
if (r && r != -ERESTARTSYS)
DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 7c42ff670080..f594cfaa97e5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -25,6 +25,7 @@
* Alex Deucher
* Jerome Glisse
*/
+#include <linux/irq.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/amdgpu_drm.h>
@@ -312,6 +313,7 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
}
adev->irq.sources[src_id] = source;
+
return 0;
}
@@ -335,15 +337,19 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
return;
}
- src = adev->irq.sources[src_id];
- if (!src) {
- DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
- return;
- }
+ if (adev->irq.virq[src_id]) {
+ generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
+ } else {
+ src = adev->irq.sources[src_id];
+ if (!src) {
+ DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
+ return;
+ }
- r = src->funcs->process(adev, src, entry);
- if (r)
- DRM_ERROR("error processing interrupt (%d)\n", r);
+ r = src->funcs->process(adev, src, entry);
+ if (r)
+ DRM_ERROR("error processing interrupt (%d)\n", r);
+ }
}
/**
@@ -461,3 +467,90 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
return !!atomic_read(&src->enabled_types[type]);
}
+
+/* gen irq */
+static void amdgpu_irq_mask(struct irq_data *irqd)
+{
+ /* XXX */
+}
+
+static void amdgpu_irq_unmask(struct irq_data *irqd)
+{
+ /* XXX */
+}
+
+static struct irq_chip amdgpu_irq_chip = {
+ .name = "amdgpu-ih",
+ .irq_mask = amdgpu_irq_mask,
+ .irq_unmask = amdgpu_irq_unmask,
+};
+
+static int amdgpu_irqdomain_map(struct irq_domain *d,
+ unsigned int irq, irq_hw_number_t hwirq)
+{
+ if (hwirq >= AMDGPU_MAX_IRQ_SRC_ID)
+ return -EPERM;
+
+ irq_set_chip_and_handler(irq,
+ &amdgpu_irq_chip, handle_simple_irq);
+ return 0;
+}
+
+static struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
+ .map = amdgpu_irqdomain_map,
+};
+
+/**
+ * amdgpu_irq_add_domain - create a linear irq domain
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Create an irq domain for GPU interrupt sources
+ * that may be driven by another driver (e.g., ACP).
+ */
+int amdgpu_irq_add_domain(struct amdgpu_device *adev)
+{
+ adev->irq.domain = irq_domain_add_linear(NULL, AMDGPU_MAX_IRQ_SRC_ID,
+ &amdgpu_hw_irqdomain_ops, adev);
+ if (!adev->irq.domain) {
+ DRM_ERROR("GPU irq add domain failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_irq_remove_domain - remove the irq domain
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Remove the irq domain for GPU interrupt sources
+ * that may be driven by another driver (e.g., ACP).
+ */
+void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
+{
+ if (adev->irq.domain) {
+ irq_domain_remove(adev->irq.domain);
+ adev->irq.domain = NULL;
+ }
+}
+
+/**
+ * amdgpu_irq_create_mapping - create a mapping between a domain irq and a
+ * Linux irq
+ *
+ * @adev: amdgpu device pointer
+ * @src_id: IH source id
+ *
+ * Create a mapping between a domain irq (GPU IH src id) and a Linux irq
+ * Use this for components that generate a GPU interrupt, but are driven
+ * by a different driver (e.g., ACP).
+ * Returns the Linux irq.
+ */
+unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
+{
+ adev->irq.virq[src_id] = irq_create_mapping(adev->irq.domain, src_id);
+
+ return adev->irq.virq[src_id];
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
index 17b01aef4278..e124b59f39c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
@@ -24,6 +24,7 @@
#ifndef __AMDGPU_IRQ_H__
#define __AMDGPU_IRQ_H__
+#include <linux/irqdomain.h>
#include "amdgpu_ih.h"
#define AMDGPU_MAX_IRQ_SRC_ID 0x100
@@ -65,6 +66,10 @@ struct amdgpu_irq {
/* interrupt ring */
struct amdgpu_ih_ring ih;
const struct amdgpu_ih_funcs *ih_funcs;
+
+ /* gen irq stuff */
+ struct irq_domain *domain; /* GPU irq controller domain */
+ unsigned virq[AMDGPU_MAX_IRQ_SRC_ID];
};
void amdgpu_irq_preinstall(struct drm_device *dev);
@@ -90,4 +95,8 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
unsigned type);
+int amdgpu_irq_add_domain(struct amdgpu_device *adev);
+void amdgpu_irq_remove_domain(struct amdgpu_device *adev);
+unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id);
+
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 064ebb347074..fdc1be8550da 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -35,6 +35,7 @@
#include <drm/drm_dp_helper.h>
#include <drm/drm_fixed.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
@@ -556,7 +557,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
int amdgpu_framebuffer_init(struct drm_device *dev,
struct amdgpu_framebuffer *rfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
int amdgpufb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index ea756e77b023..5107fb291bdb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -96,6 +96,7 @@ static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo)
*/
static inline u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
{
+ WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM);
return bo->tbo.offset;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 22a8c7d3a3ab..7d8d84eaea4a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -30,10 +30,16 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include "amd_powerplay.h"
+
static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
{
+ if (adev->pp_enabled)
+ /* TODO */
+ return;
+
if (adev->pm.dpm_enabled) {
mutex_lock(&adev->pm.mutex);
if (power_supply_is_system_supplied() > 0)
@@ -52,7 +58,12 @@ static ssize_t amdgpu_get_dpm_state(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
- enum amdgpu_pm_state_type pm = adev->pm.dpm.user_state;
+ enum amd_pm_state_type pm;
+
+ if (adev->pp_enabled) {
+ pm = amdgpu_dpm_get_current_power_state(adev);
+ } else
+ pm = adev->pm.dpm.user_state;
return snprintf(buf, PAGE_SIZE, "%s\n",
(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
@@ -66,40 +77,57 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
+ enum amd_pm_state_type state;
- mutex_lock(&adev->pm.mutex);
if (strncmp("battery", buf, strlen("battery")) == 0)
- adev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
+ state = POWER_STATE_TYPE_BATTERY;
else if (strncmp("balanced", buf, strlen("balanced")) == 0)
- adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+ state = POWER_STATE_TYPE_BALANCED;
else if (strncmp("performance", buf, strlen("performance")) == 0)
- adev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
+ state = POWER_STATE_TYPE_PERFORMANCE;
else {
- mutex_unlock(&adev->pm.mutex);
count = -EINVAL;
goto fail;
}
- mutex_unlock(&adev->pm.mutex);
- /* Can't set dpm state when the card is off */
- if (!(adev->flags & AMD_IS_PX) ||
- (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
- amdgpu_pm_compute_clocks(adev);
+ if (adev->pp_enabled) {
+ amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_ENABLE_USER_STATE, &state, NULL);
+ } else {
+ mutex_lock(&adev->pm.mutex);
+ adev->pm.dpm.user_state = state;
+ mutex_unlock(&adev->pm.mutex);
+
+ /* Can't set dpm state when the card is off */
+ if (!(adev->flags & AMD_IS_PX) ||
+ (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
+ amdgpu_pm_compute_clocks(adev);
+ }
fail:
return count;
}
static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
- enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
- (level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+ if (adev->pp_enabled) {
+ enum amd_dpm_forced_level level;
+
+ level = amdgpu_dpm_get_performance_level(adev);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+ (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+ } else {
+ enum amdgpu_dpm_forced_level level;
+
+ level = adev->pm.dpm.forced_level;
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+ (level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+ }
}
static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
@@ -112,7 +140,6 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
enum amdgpu_dpm_forced_level level;
int ret = 0;
- mutex_lock(&adev->pm.mutex);
if (strncmp("low", buf, strlen("low")) == 0) {
level = AMDGPU_DPM_FORCED_LEVEL_LOW;
} else if (strncmp("high", buf, strlen("high")) == 0) {
@@ -123,7 +150,11 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
count = -EINVAL;
goto fail;
}
- if (adev->pm.funcs->force_performance_level) {
+
+ if (adev->pp_enabled)
+ amdgpu_dpm_force_performance_level(adev, level);
+ else {
+ mutex_lock(&adev->pm.mutex);
if (adev->pm.dpm.thermal_active) {
count = -EINVAL;
goto fail;
@@ -131,6 +162,9 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
ret = amdgpu_dpm_force_performance_level(adev, level);
if (ret)
count = -EINVAL;
+ else
+ adev->pm.dpm.forced_level = level;
+ mutex_unlock(&adev->pm.mutex);
}
fail:
mutex_unlock(&adev->pm.mutex);
@@ -150,10 +184,10 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
struct amdgpu_device *adev = dev_get_drvdata(dev);
int temp;
- if (adev->pm.funcs->get_temperature)
- temp = amdgpu_dpm_get_temperature(adev);
- else
+ if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
temp = 0;
+ else
+ temp = amdgpu_dpm_get_temperature(adev);
return snprintf(buf, PAGE_SIZE, "%d\n", temp);
}
@@ -181,8 +215,10 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev,
struct amdgpu_device *adev = dev_get_drvdata(dev);
u32 pwm_mode = 0;
- if (adev->pm.funcs->get_fan_control_mode)
- pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
+ if (!adev->pp_enabled && !adev->pm.funcs->get_fan_control_mode)
+ return -EINVAL;
+
+ pwm_mode = amdgpu_dpm_get_fan_control_mode(adev);
/* never 0 (full-speed), fuse or smc-controlled always */
return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
@@ -197,7 +233,7 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
int err;
int value;
- if(!adev->pm.funcs->set_fan_control_mode)
+ if (!adev->pp_enabled && !adev->pm.funcs->set_fan_control_mode)
return -EINVAL;
err = kstrtoint(buf, 10, &value);
@@ -290,11 +326,11 @@ static struct attribute *hwmon_attributes[] = {
static umode_t hwmon_attributes_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct amdgpu_device *adev = dev_get_drvdata(dev);
umode_t effective_mode = attr->mode;
- /* Skip attributes if DPM is not enabled */
+ /* Skip limit attributes if DPM is not enabled */
if (!adev->pm.dpm_enabled &&
(attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr ||
@@ -304,6 +340,9 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
return 0;
+ if (adev->pp_enabled)
+ return effective_mode;
+
/* Skip fan attributes if fan is not present */
if (adev->pm.no_fan &&
(attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
@@ -351,7 +390,7 @@ void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
container_of(work, struct amdgpu_device,
pm.dpm.thermal.work);
/* switch to the thermal state */
- enum amdgpu_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
+ enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
if (!adev->pm.dpm_enabled)
return;
@@ -379,7 +418,7 @@ void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
}
static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
- enum amdgpu_pm_state_type dpm_state)
+ enum amd_pm_state_type dpm_state)
{
int i;
struct amdgpu_ps *ps;
@@ -516,7 +555,7 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
{
int i;
struct amdgpu_ps *ps;
- enum amdgpu_pm_state_type dpm_state;
+ enum amd_pm_state_type dpm_state;
int ret;
/* if dpm init failed */
@@ -635,49 +674,54 @@ done:
void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
{
- if (adev->pm.funcs->powergate_uvd) {
- mutex_lock(&adev->pm.mutex);
- /* enable/disable UVD */
+ if (adev->pp_enabled)
amdgpu_dpm_powergate_uvd(adev, !enable);
- mutex_unlock(&adev->pm.mutex);
- } else {
- if (enable) {
+ else {
+ if (adev->pm.funcs->powergate_uvd) {
mutex_lock(&adev->pm.mutex);
- adev->pm.dpm.uvd_active = true;
- adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
+ /* enable/disable UVD */
+ amdgpu_dpm_powergate_uvd(adev, !enable);
mutex_unlock(&adev->pm.mutex);
} else {
- mutex_lock(&adev->pm.mutex);
- adev->pm.dpm.uvd_active = false;
- mutex_unlock(&adev->pm.mutex);
+ if (enable) {
+ mutex_lock(&adev->pm.mutex);
+ adev->pm.dpm.uvd_active = true;
+ adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
+ mutex_unlock(&adev->pm.mutex);
+ } else {
+ mutex_lock(&adev->pm.mutex);
+ adev->pm.dpm.uvd_active = false;
+ mutex_unlock(&adev->pm.mutex);
+ }
+ amdgpu_pm_compute_clocks(adev);
}
- amdgpu_pm_compute_clocks(adev);
}
}
void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
{
- if (adev->pm.funcs->powergate_vce) {
- mutex_lock(&adev->pm.mutex);
- /* enable/disable VCE */
+ if (adev->pp_enabled)
amdgpu_dpm_powergate_vce(adev, !enable);
-
- mutex_unlock(&adev->pm.mutex);
- } else {
- if (enable) {
+ else {
+ if (adev->pm.funcs->powergate_vce) {
mutex_lock(&adev->pm.mutex);
- adev->pm.dpm.vce_active = true;
- /* XXX select vce level based on ring/task */
- adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
+ amdgpu_dpm_powergate_vce(adev, !enable);
mutex_unlock(&adev->pm.mutex);
} else {
- mutex_lock(&adev->pm.mutex);
- adev->pm.dpm.vce_active = false;
- mutex_unlock(&adev->pm.mutex);
+ if (enable) {
+ mutex_lock(&adev->pm.mutex);
+ adev->pm.dpm.vce_active = true;
+ /* XXX select vce level based on ring/task */
+ adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL;
+ mutex_unlock(&adev->pm.mutex);
+ } else {
+ mutex_lock(&adev->pm.mutex);
+ adev->pm.dpm.vce_active = false;
+ mutex_unlock(&adev->pm.mutex);
+ }
+ amdgpu_pm_compute_clocks(adev);
}
-
- amdgpu_pm_compute_clocks(adev);
}
}
@@ -685,10 +729,13 @@ void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
{
int i;
- for (i = 0; i < adev->pm.dpm.num_ps; i++) {
- printk("== power state %d ==\n", i);
+ if (adev->pp_enabled)
+ /* TO DO */
+ return;
+
+ for (i = 0; i < adev->pm.dpm.num_ps; i++)
amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
- }
+
}
int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
@@ -698,8 +745,11 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
if (adev->pm.sysfs_initialized)
return 0;
- if (adev->pm.funcs->get_temperature == NULL)
- return 0;
+ if (!adev->pp_enabled) {
+ if (adev->pm.funcs->get_temperature == NULL)
+ return 0;
+ }
+
adev->pm.int_hwmon_dev = hwmon_device_register_with_groups(adev->dev,
DRIVER_NAME, adev,
hwmon_groups);
@@ -748,32 +798,43 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
if (!adev->pm.dpm_enabled)
return;
- mutex_lock(&adev->pm.mutex);
+ if (adev->pp_enabled) {
+ int i = 0;
- /* update active crtc counts */
- adev->pm.dpm.new_active_crtcs = 0;
- adev->pm.dpm.new_active_crtc_count = 0;
- if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
- list_for_each_entry(crtc,
- &ddev->mode_config.crtc_list, head) {
- amdgpu_crtc = to_amdgpu_crtc(crtc);
- if (crtc->enabled) {
- adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
- adev->pm.dpm.new_active_crtc_count++;
+ amdgpu_display_bandwidth_update(adev);
+ mutex_lock(&adev->ring_lock);
+ for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (ring && ring->ready)
+ amdgpu_fence_wait_empty(ring);
}
- }
- }
+ mutex_unlock(&adev->ring_lock);
- /* update battery/ac status */
- if (power_supply_is_system_supplied() > 0)
- adev->pm.dpm.ac_power = true;
- else
- adev->pm.dpm.ac_power = false;
-
- amdgpu_dpm_change_power_state_locked(adev);
+ amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE, NULL, NULL);
+ } else {
+ mutex_lock(&adev->pm.mutex);
+ adev->pm.dpm.new_active_crtcs = 0;
+ adev->pm.dpm.new_active_crtc_count = 0;
+ if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+ list_for_each_entry(crtc,
+ &ddev->mode_config.crtc_list, head) {
+ amdgpu_crtc = to_amdgpu_crtc(crtc);
+ if (crtc->enabled) {
+ adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
+ adev->pm.dpm.new_active_crtc_count++;
+ }
+ }
+ }
+ /* update battery/ac status */
+ if (power_supply_is_system_supplied() > 0)
+ adev->pm.dpm.ac_power = true;
+ else
+ adev->pm.dpm.ac_power = false;
- mutex_unlock(&adev->pm.mutex);
+ amdgpu_dpm_change_power_state_locked(adev);
+ mutex_unlock(&adev->pm.mutex);
+ }
}
/*
@@ -787,7 +848,13 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = dev->dev_private;
- if (adev->pm.dpm_enabled) {
+ if (!adev->pm.dpm_enabled) {
+ seq_printf(m, "dpm not enabled\n");
+ return 0;
+ }
+ if (adev->pp_enabled) {
+ amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
+ } else {
mutex_lock(&adev->pm.mutex);
if (adev->pm.funcs->debugfs_print_current_performance_level)
amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
new file mode 100644
index 000000000000..5ee9a0690278
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2015 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 "atom.h"
+#include "amdgpu.h"
+#include "amd_shared.h"
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include "amdgpu_pm.h"
+#include <drm/amdgpu_drm.h>
+#include "amdgpu_powerplay.h"
+#include "cik_dpm.h"
+#include "vi_dpm.h"
+
+static int amdgpu_powerplay_init(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ struct amd_powerplay *amd_pp;
+
+ amd_pp = &(adev->powerplay);
+
+ if (adev->pp_enabled) {
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+ struct amd_pp_init *pp_init;
+
+ pp_init = kzalloc(sizeof(struct amd_pp_init), GFP_KERNEL);
+
+ if (pp_init == NULL)
+ return -ENOMEM;
+
+ pp_init->chip_family = adev->family;
+ pp_init->chip_id = adev->asic_type;
+ pp_init->device = amdgpu_cgs_create_device(adev);
+
+ ret = amd_powerplay_init(pp_init, amd_pp);
+ kfree(pp_init);
+#endif
+ } else {
+ amd_pp->pp_handle = (void *)adev;
+
+ switch (adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+ case CHIP_BONAIRE:
+ case CHIP_HAWAII:
+ amd_pp->ip_funcs = &ci_dpm_ip_funcs;
+ break;
+ case CHIP_KABINI:
+ case CHIP_MULLINS:
+ case CHIP_KAVERI:
+ amd_pp->ip_funcs = &kv_dpm_ip_funcs;
+ break;
+#endif
+ case CHIP_TOPAZ:
+ amd_pp->ip_funcs = &iceland_dpm_ip_funcs;
+ break;
+ case CHIP_TONGA:
+ amd_pp->ip_funcs = &tonga_dpm_ip_funcs;
+ break;
+ case CHIP_FIJI:
+ amd_pp->ip_funcs = &fiji_dpm_ip_funcs;
+ break;
+ case CHIP_CARRIZO:
+ case CHIP_STONEY:
+ amd_pp->ip_funcs = &cz_dpm_ip_funcs;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int amdgpu_pp_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret = 0;
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+ switch (adev->asic_type) {
+ case CHIP_TONGA:
+ case CHIP_FIJI:
+ adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false;
+ break;
+ default:
+ adev->pp_enabled = (amdgpu_powerplay > 0) ? true : false;
+ break;
+ }
+#else
+ adev->pp_enabled = false;
+#endif
+
+ ret = amdgpu_powerplay_init(adev);
+ if (ret)
+ return ret;
+
+ if (adev->powerplay.ip_funcs->early_init)
+ ret = adev->powerplay.ip_funcs->early_init(
+ adev->powerplay.pp_handle);
+ return ret;
+}
+
+
+static int amdgpu_pp_late_init(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->late_init)
+ ret = adev->powerplay.ip_funcs->late_init(
+ adev->powerplay.pp_handle);
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+ if (adev->pp_enabled)
+ amdgpu_pm_sysfs_init(adev);
+#endif
+ return ret;
+}
+
+static int amdgpu_pp_sw_init(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->sw_init)
+ ret = adev->powerplay.ip_funcs->sw_init(
+ adev->powerplay.pp_handle);
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+ if (adev->pp_enabled) {
+ if (amdgpu_dpm == 0)
+ adev->pm.dpm_enabled = false;
+ else
+ adev->pm.dpm_enabled = true;
+ }
+#endif
+
+ return ret;
+}
+
+static int amdgpu_pp_sw_fini(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->sw_fini)
+ ret = adev->powerplay.ip_funcs->sw_fini(
+ adev->powerplay.pp_handle);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_DRM_AMD_POWERPLAY
+ if (adev->pp_enabled) {
+ amdgpu_pm_sysfs_fini(adev);
+ amd_powerplay_fini(adev->powerplay.pp_handle);
+ }
+#endif
+
+ return ret;
+}
+
+static int amdgpu_pp_hw_init(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->pp_enabled && adev->firmware.smu_load)
+ amdgpu_ucode_init_bo(adev);
+
+ if (adev->powerplay.ip_funcs->hw_init)
+ ret = adev->powerplay.ip_funcs->hw_init(
+ adev->powerplay.pp_handle);
+
+ return ret;
+}
+
+static int amdgpu_pp_hw_fini(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->hw_fini)
+ ret = adev->powerplay.ip_funcs->hw_fini(
+ adev->powerplay.pp_handle);
+
+ if (adev->pp_enabled && adev->firmware.smu_load)
+ amdgpu_ucode_fini_bo(adev);
+
+ return ret;
+}
+
+static int amdgpu_pp_suspend(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->suspend)
+ ret = adev->powerplay.ip_funcs->suspend(
+ adev->powerplay.pp_handle);
+ return ret;
+}
+
+static int amdgpu_pp_resume(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->resume)
+ ret = adev->powerplay.ip_funcs->resume(
+ adev->powerplay.pp_handle);
+ return ret;
+}
+
+static int amdgpu_pp_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->set_clockgating_state)
+ ret = adev->powerplay.ip_funcs->set_clockgating_state(
+ adev->powerplay.pp_handle, state);
+ return ret;
+}
+
+static int amdgpu_pp_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->set_powergating_state)
+ ret = adev->powerplay.ip_funcs->set_powergating_state(
+ adev->powerplay.pp_handle, state);
+ return ret;
+}
+
+
+static bool amdgpu_pp_is_idle(void *handle)
+{
+ bool ret = true;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->is_idle)
+ ret = adev->powerplay.ip_funcs->is_idle(
+ adev->powerplay.pp_handle);
+ return ret;
+}
+
+static int amdgpu_pp_wait_for_idle(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->wait_for_idle)
+ ret = adev->powerplay.ip_funcs->wait_for_idle(
+ adev->powerplay.pp_handle);
+ return ret;
+}
+
+static int amdgpu_pp_soft_reset(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->soft_reset)
+ ret = adev->powerplay.ip_funcs->soft_reset(
+ adev->powerplay.pp_handle);
+ return ret;
+}
+
+static void amdgpu_pp_print_status(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->powerplay.ip_funcs->print_status)
+ adev->powerplay.ip_funcs->print_status(
+ adev->powerplay.pp_handle);
+}
+
+const struct amd_ip_funcs amdgpu_pp_ip_funcs = {
+ .early_init = amdgpu_pp_early_init,
+ .late_init = amdgpu_pp_late_init,
+ .sw_init = amdgpu_pp_sw_init,
+ .sw_fini = amdgpu_pp_sw_fini,
+ .hw_init = amdgpu_pp_hw_init,
+ .hw_fini = amdgpu_pp_hw_fini,
+ .suspend = amdgpu_pp_suspend,
+ .resume = amdgpu_pp_resume,
+ .is_idle = amdgpu_pp_is_idle,
+ .wait_for_idle = amdgpu_pp_wait_for_idle,
+ .soft_reset = amdgpu_pp_soft_reset,
+ .print_status = amdgpu_pp_print_status,
+ .set_clockgating_state = amdgpu_pp_set_clockgating_state,
+ .set_powergating_state = amdgpu_pp_set_powergating_state,
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h
new file mode 100644
index 000000000000..da5cf47cfd99
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 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 __AMDGPU_POPWERPLAY_H__
+#define __AMDGPU_POPWERPLAY_H__
+
+#include "amd_shared.h"
+
+extern const struct amd_ip_funcs amdgpu_pp_ip_funcs;
+
+#endif /* __AMDSOC_DM_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
index dd005c336c97..181ce39ef5e5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -293,7 +293,8 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
fence = to_amdgpu_fence(sync->sync_to[i]);
/* check if we really need to sync */
- if (!amdgpu_fence_need_sync(fence, ring))
+ if (!amdgpu_enable_scheduler &&
+ !amdgpu_fence_need_sync(fence, ring))
continue;
/* prevent GPU deadlocks */
@@ -303,7 +304,7 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
}
if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) {
- r = fence_wait(&fence->base, true);
+ r = fence_wait(sync->sync_to[i], true);
if (r)
return r;
continue;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index b53d273eb7a1..aefc668e6b5d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -75,50 +75,77 @@ static unsigned amdgpu_vm_directory_size(struct amdgpu_device *adev)
}
/**
- * amdgpu_vm_get_bos - add the vm BOs to a validation list
+ * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
*
* @vm: vm providing the BOs
- * @head: head of validation list
+ * @validated: head of validation list
+ * @entry: entry to add
*
* Add the page directory to the list of BOs to
- * validate for command submission (cayman+).
+ * validate for command submission.
*/
-struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
- struct amdgpu_vm *vm,
- struct list_head *head)
+void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
+ struct list_head *validated,
+ struct amdgpu_bo_list_entry *entry)
{
- struct amdgpu_bo_list_entry *list;
- unsigned i, idx;
+ entry->robj = vm->page_directory;
+ entry->prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
+ entry->allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
+ entry->priority = 0;
+ entry->tv.bo = &vm->page_directory->tbo;
+ entry->tv.shared = true;
+ list_add(&entry->tv.head, validated);
+}
- list = drm_malloc_ab(vm->max_pde_used + 2,
- sizeof(struct amdgpu_bo_list_entry));
- if (!list) {
- return NULL;
- }
+/**
+ * amdgpu_vm_get_bos - add the vm BOs to a duplicates list
+ *
+ * @vm: vm providing the BOs
+ * @duplicates: head of duplicates list
+ *
+ * Add the page directory to the BO duplicates list
+ * for command submission.
+ */
+void amdgpu_vm_get_pt_bos(struct amdgpu_vm *vm, struct list_head *duplicates)
+{
+ unsigned i;
/* add the vm page table to the list */
- list[0].robj = vm->page_directory;
- list[0].prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
- list[0].allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
- list[0].priority = 0;
- list[0].tv.bo = &vm->page_directory->tbo;
- list[0].tv.shared = true;
- list_add(&list[0].tv.head, head);
-
- for (i = 0, idx = 1; i <= vm->max_pde_used; i++) {
- if (!vm->page_tables[i].bo)
+ for (i = 0; i <= vm->max_pde_used; ++i) {
+ struct amdgpu_bo_list_entry *entry = &vm->page_tables[i].entry;
+
+ if (!entry->robj)
continue;
- list[idx].robj = vm->page_tables[i].bo;
- list[idx].prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
- list[idx].allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
- list[idx].priority = 0;
- list[idx].tv.bo = &list[idx].robj->tbo;
- list[idx].tv.shared = true;
- list_add(&list[idx++].tv.head, head);
+ list_add(&entry->tv.head, duplicates);
}
- return list;
+}
+
+/**
+ * amdgpu_vm_move_pt_bos_in_lru - move the PT BOs to the LRU tail
+ *
+ * @adev: amdgpu device instance
+ * @vm: vm providing the BOs
+ *
+ * Move the PT BOs to the tail of the LRU.
+ */
+void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm)
+{
+ struct ttm_bo_global *glob = adev->mman.bdev.glob;
+ unsigned i;
+
+ spin_lock(&glob->lru_lock);
+ for (i = 0; i <= vm->max_pde_used; ++i) {
+ struct amdgpu_bo_list_entry *entry = &vm->page_tables[i].entry;
+
+ if (!entry->robj)
+ continue;
+
+ ttm_bo_move_to_lru_tail(&entry->robj->tbo);
+ }
+ spin_unlock(&glob->lru_lock);
}
/**
@@ -461,7 +488,7 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
/* walk over the address space and update the page directory */
for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) {
- struct amdgpu_bo *bo = vm->page_tables[pt_idx].bo;
+ struct amdgpu_bo *bo = vm->page_tables[pt_idx].entry.robj;
uint64_t pde, pt;
if (bo == NULL)
@@ -638,7 +665,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev,
/* walk over the address space and update the page tables */
for (addr = start; addr < end; ) {
uint64_t pt_idx = addr >> amdgpu_vm_block_size;
- struct amdgpu_bo *pt = vm->page_tables[pt_idx].bo;
+ struct amdgpu_bo *pt = vm->page_tables[pt_idx].entry.robj;
unsigned nptes;
uint64_t pte;
int r;
@@ -1010,13 +1037,13 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
return -EINVAL;
/* make sure object fit at this offset */
- eaddr = saddr + size;
+ eaddr = saddr + size - 1;
if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo)))
return -EINVAL;
last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE;
- if (last_pfn > adev->vm_manager.max_pfn) {
- dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n",
+ if (last_pfn >= adev->vm_manager.max_pfn) {
+ dev_err(adev->dev, "va above limit (0x%08X >= 0x%08X)\n",
last_pfn, adev->vm_manager.max_pfn);
return -EINVAL;
}
@@ -1025,7 +1052,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
eaddr /= AMDGPU_GPU_PAGE_SIZE;
spin_lock(&vm->it_lock);
- it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
+ it = interval_tree_iter_first(&vm->va, saddr, eaddr);
spin_unlock(&vm->it_lock);
if (it) {
struct amdgpu_bo_va_mapping *tmp;
@@ -1046,7 +1073,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
INIT_LIST_HEAD(&mapping->list);
mapping->it.start = saddr;
- mapping->it.last = eaddr - 1;
+ mapping->it.last = eaddr;
mapping->offset = offset;
mapping->flags = flags;
@@ -1070,9 +1097,11 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
/* walk over the address space and allocate the page tables */
for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
struct reservation_object *resv = vm->page_directory->tbo.resv;
+ struct amdgpu_bo_list_entry *entry;
struct amdgpu_bo *pt;
- if (vm->page_tables[pt_idx].bo)
+ entry = &vm->page_tables[pt_idx].entry;
+ if (entry->robj)
continue;
r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
@@ -1094,8 +1123,13 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
goto error_free;
}
+ entry->robj = pt;
+ entry->prefered_domains = AMDGPU_GEM_DOMAIN_VRAM;
+ entry->allowed_domains = AMDGPU_GEM_DOMAIN_VRAM;
+ entry->priority = 0;
+ entry->tv.bo = &entry->robj->tbo;
+ entry->tv.shared = true;
vm->page_tables[pt_idx].addr = 0;
- vm->page_tables[pt_idx].bo = pt;
}
return 0;
@@ -1326,7 +1360,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
}
for (i = 0; i < amdgpu_vm_num_pdes(adev); i++)
- amdgpu_bo_unref(&vm->page_tables[i].bo);
+ amdgpu_bo_unref(&vm->page_tables[i].entry.robj);
kfree(vm->page_tables);
amdgpu_bo_unref(&vm->page_directory);
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
index 92b6acadfc52..21aacc1f45c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
@@ -243,7 +243,7 @@ static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STA
/* convert bits per color to bits per pixel */
/* get bpc from the EDID */
-static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
+static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
{
if (bpc == 0)
return 24;
@@ -251,64 +251,32 @@ static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
return bpc * 3;
}
-/* get the max pix clock supported by the link rate and lane num */
-static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate,
- int lane_num,
- int bpp)
-{
- return (link_rate * lane_num * 8) / bpp;
-}
-
/***** amdgpu specific DP functions *****/
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector,
+static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
const u8 dpcd[DP_DPCD_SIZE],
- int pix_clock)
-{
- int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
- int max_link_rate = drm_dp_max_link_rate(dpcd);
- int max_lane_num = drm_dp_max_lane_count(dpcd);
- int lane_num;
- int max_dp_pix_clock;
-
- for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
- max_dp_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
- if (pix_clock <= max_dp_pix_clock)
- break;
- }
-
- return lane_num;
-}
-
-static int amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector,
- const u8 dpcd[DP_DPCD_SIZE],
- int pix_clock)
+ unsigned pix_clock,
+ unsigned *dp_lanes, unsigned *dp_rate)
{
- int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
- int lane_num, max_pix_clock;
-
- if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
- ENCODER_OBJECT_ID_NUTMEG)
- return 270000;
-
- lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock);
- max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp);
- if (pix_clock <= max_pix_clock)
- return 162000;
- max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp);
- if (pix_clock <= max_pix_clock)
- return 270000;
- if (amdgpu_connector_is_dp12_capable(connector)) {
- max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp);
- if (pix_clock <= max_pix_clock)
- return 540000;
+ unsigned bpp =
+ amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
+ static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+ unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+ unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+ unsigned lane_num, i, max_pix_clock;
+
+ for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+ for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+ max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+ if (max_pix_clock >= pix_clock) {
+ *dp_lanes = lane_num;
+ *dp_rate = link_rates[i];
+ return 0;
+ }
+ }
}
- return drm_dp_max_link_rate(dpcd);
+ return -EINVAL;
}
static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
@@ -422,6 +390,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
{
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
struct amdgpu_connector_atom_dig *dig_connector;
+ int ret;
if (!amdgpu_connector->con_priv)
return;
@@ -429,10 +398,14 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
- dig_connector->dp_clock =
- amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
- dig_connector->dp_lane_count =
- amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+ ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
+ mode->clock,
+ &dig_connector->dp_lane_count,
+ &dig_connector->dp_clock);
+ if (ret) {
+ dig_connector->dp_clock = 0;
+ dig_connector->dp_lane_count = 0;
+ }
}
}
@@ -441,14 +414,17 @@ int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
{
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
struct amdgpu_connector_atom_dig *dig_connector;
- int dp_clock;
+ unsigned dp_lanes, dp_clock;
+ int ret;
if (!amdgpu_connector->con_priv)
return MODE_CLOCK_HIGH;
dig_connector = amdgpu_connector->con_priv;
- dp_clock =
- amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+ ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
+ mode->clock, &dp_lanes, &dp_clock);
+ if (ret)
+ return MODE_CLOCK_HIGH;
if ((dp_clock == 540000) &&
(!amdgpu_connector_is_dp12_capable(connector)))
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
index 57a2e347f04d..8b4731d4e10e 100644
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -1395,7 +1395,6 @@ static void ci_thermal_stop_thermal_controller(struct amdgpu_device *adev)
ci_fan_ctrl_set_default_mode(adev);
}
-#if 0
static int ci_read_smc_soft_register(struct amdgpu_device *adev,
u16 reg_offset, u32 *value)
{
@@ -1405,7 +1404,6 @@ static int ci_read_smc_soft_register(struct amdgpu_device *adev,
pi->soft_regs_start + reg_offset,
value, pi->sram_end);
}
-#endif
static int ci_write_smc_soft_register(struct amdgpu_device *adev,
u16 reg_offset, u32 value)
@@ -6084,11 +6082,23 @@ ci_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
struct amdgpu_ps *rps = &pi->current_rps;
u32 sclk = ci_get_average_sclk_freq(adev);
u32 mclk = ci_get_average_mclk_freq(adev);
+ u32 activity_percent = 50;
+ int ret;
+
+ ret = ci_read_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, AverageGraphicsA),
+ &activity_percent);
+
+ if (ret == 0) {
+ activity_percent += 0x80;
+ activity_percent >>= 8;
+ activity_percent = activity_percent > 100 ? 100 : activity_percent;
+ }
seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis");
seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
seq_printf(m, "power level avg sclk: %u mclk: %u\n",
sclk, mclk);
+ seq_printf(m, "GPU load: %u %%\n", activity_percent);
}
static void ci_dpm_print_power_state(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
index 484710cfdf82..fd9c9588ef46 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -32,6 +32,7 @@
#include "amdgpu_vce.h"
#include "cikd.h"
#include "atom.h"
+#include "amd_pcie.h"
#include "cik.h"
#include "gmc_v7_0.h"
@@ -65,6 +66,7 @@
#include "oss/oss_2_0_sh_mask.h"
#include "amdgpu_amdkfd.h"
+#include "amdgpu_powerplay.h"
/*
* Indirect registers accessor
@@ -929,6 +931,37 @@ static bool cik_read_disabled_bios(struct amdgpu_device *adev)
return r;
}
+static bool cik_read_bios_from_rom(struct amdgpu_device *adev,
+ u8 *bios, u32 length_bytes)
+{
+ u32 *dw_ptr;
+ unsigned long flags;
+ u32 i, length_dw;
+
+ if (bios == NULL)
+ return false;
+ if (length_bytes == 0)
+ return false;
+ /* APU vbios image is part of sbios image */
+ if (adev->flags & AMD_IS_APU)
+ return false;
+
+ dw_ptr = (u32 *)bios;
+ length_dw = ALIGN(length_bytes, 4) / 4;
+ /* take the smc lock since we are using the smc index */
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ /* set rom index to 0 */
+ WREG32(mmSMC_IND_INDEX_0, ixROM_INDEX);
+ WREG32(mmSMC_IND_DATA_0, 0);
+ /* set index to data for continous read */
+ WREG32(mmSMC_IND_INDEX_0, ixROM_DATA);
+ for (i = 0; i < length_dw; i++)
+ dw_ptr[i] = RREG32(mmSMC_IND_DATA_0);
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+ return true;
+}
+
static struct amdgpu_allowed_register_entry cik_allowed_read_registers[] = {
{mmGRBM_STATUS, false},
{mmGB_ADDR_CONFIG, false},
@@ -1563,8 +1596,8 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
{
struct pci_dev *root = adev->pdev->bus->self;
int bridge_pos, gpu_pos;
- u32 speed_cntl, mask, current_data_rate;
- int ret, i;
+ u32 speed_cntl, current_data_rate;
+ int i;
u16 tmp16;
if (pci_is_root_bus(adev->pdev->bus))
@@ -1576,23 +1609,20 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
if (adev->flags & AMD_IS_APU)
return;
- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
- if (ret != 0)
- return;
-
- if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+ if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+ CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
return;
speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
current_data_rate = (speed_cntl & PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) >>
PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
- if (mask & DRM_PCIE_SPEED_80) {
+ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
if (current_data_rate == 2) {
DRM_INFO("PCIE gen 3 link speeds already enabled\n");
return;
}
DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n");
- } else if (mask & DRM_PCIE_SPEED_50) {
+ } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) {
if (current_data_rate == 1) {
DRM_INFO("PCIE gen 2 link speeds already enabled\n");
return;
@@ -1608,7 +1638,7 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
if (!gpu_pos)
return;
- if (mask & DRM_PCIE_SPEED_80) {
+ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
/* re-try equalization if gen3 is not already enabled */
if (current_data_rate != 2) {
u16 bridge_cfg, gpu_cfg;
@@ -1703,9 +1733,9 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
tmp16 &= ~0xf;
- if (mask & DRM_PCIE_SPEED_80)
+ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
tmp16 |= 3; /* gen3 */
- else if (mask & DRM_PCIE_SPEED_50)
+ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
tmp16 |= 2; /* gen2 */
else
tmp16 |= 1; /* gen1 */
@@ -1922,7 +1952,7 @@ static const struct amdgpu_ip_block_version bonaire_ip_blocks[] =
.major = 7,
.minor = 0,
.rev = 0,
- .funcs = &ci_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1990,7 +2020,7 @@ static const struct amdgpu_ip_block_version hawaii_ip_blocks[] =
.major = 7,
.minor = 0,
.rev = 0,
- .funcs = &ci_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2058,7 +2088,7 @@ static const struct amdgpu_ip_block_version kabini_ip_blocks[] =
.major = 7,
.minor = 0,
.rev = 0,
- .funcs = &kv_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2126,7 +2156,7 @@ static const struct amdgpu_ip_block_version mullins_ip_blocks[] =
.major = 7,
.minor = 0,
.rev = 0,
- .funcs = &kv_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2194,7 +2224,7 @@ static const struct amdgpu_ip_block_version kaveri_ip_blocks[] =
.major = 7,
.minor = 0,
.rev = 0,
- .funcs = &kv_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -2267,6 +2297,7 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
static const struct amdgpu_asic_funcs cik_asic_funcs =
{
.read_disabled_bios = &cik_read_disabled_bios,
+ .read_bios_from_rom = &cik_read_bios_from_rom,
.read_register = &cik_read_register,
.reset = &cik_asic_reset,
.set_vga_state = &cik_vga_set_state,
@@ -2417,6 +2448,8 @@ static int cik_common_early_init(void *handle)
return -EINVAL;
}
+ amdgpu_get_pcie_info(adev);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
index 8993c50cb89f..30c9b3beeef9 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
@@ -274,6 +274,11 @@ static void cik_ih_set_rptr(struct amdgpu_device *adev)
static int cik_ih_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret;
+
+ ret = amdgpu_irq_add_domain(adev);
+ if (ret)
+ return ret;
cik_ih_set_interrupt_funcs(adev);
@@ -300,6 +305,7 @@ static int cik_ih_sw_fini(void *handle)
amdgpu_irq_fini(adev);
amdgpu_ih_ring_fini(adev);
+ amdgpu_irq_remove_domain(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
index 8035d4d6a4f5..4dd17f2dd905 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
@@ -1078,6 +1078,37 @@ static uint32_t cz_get_eclk_level(struct amdgpu_device *adev,
return i;
}
+static uint32_t cz_get_uvd_level(struct amdgpu_device *adev,
+ uint32_t clock, uint16_t msg)
+{
+ int i = 0;
+ struct amdgpu_uvd_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+
+ switch (msg) {
+ case PPSMC_MSG_SetUvdSoftMin:
+ case PPSMC_MSG_SetUvdHardMin:
+ for (i = 0; i < table->count; i++)
+ if (clock <= table->entries[i].vclk)
+ break;
+ if (i == table->count)
+ i = table->count - 1;
+ break;
+ case PPSMC_MSG_SetUvdSoftMax:
+ case PPSMC_MSG_SetUvdHardMax:
+ for (i = table->count - 1; i >= 0; i--)
+ if (clock >= table->entries[i].vclk)
+ break;
+ if (i < 0)
+ i = 0;
+ break;
+ default:
+ break;
+ }
+
+ return i;
+}
+
static int cz_program_bootup_state(struct amdgpu_device *adev)
{
struct cz_power_info *pi = cz_get_pi(adev);
@@ -1739,6 +1770,200 @@ static int cz_dpm_unforce_dpm_levels(struct amdgpu_device *adev)
return 0;
}
+static int cz_dpm_uvd_force_highest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->uvd_dpm.soft_min_clk != pi->uvd_dpm.soft_max_clk) {
+ pi->uvd_dpm.soft_min_clk =
+ pi->uvd_dpm.soft_max_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMin,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_min_clk,
+ PPSMC_MSG_SetUvdSoftMin));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cz_dpm_uvd_force_lowest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->uvd_dpm.soft_max_clk != pi->uvd_dpm.soft_min_clk) {
+ pi->uvd_dpm.soft_max_clk = pi->uvd_dpm.soft_min_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMax,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_max_clk,
+ PPSMC_MSG_SetUvdSoftMax));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static uint32_t cz_dpm_get_max_uvd_level(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ if (!pi->max_uvd_level) {
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
+ pi->max_uvd_level = cz_get_argument(adev) + 1;
+ }
+
+ if (pi->max_uvd_level > CZ_MAX_HARDWARE_POWERLEVELS) {
+ DRM_ERROR("Invalid max uvd level!\n");
+ return -EINVAL;
+ }
+
+ return pi->max_uvd_level;
+}
+
+static int cz_dpm_unforce_uvd_dpm_levels(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_uvd_clock_voltage_dependency_table *dep_table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+ uint32_t level = 0;
+ int ret = 0;
+
+ pi->uvd_dpm.soft_min_clk = dep_table->entries[0].vclk;
+ level = cz_dpm_get_max_uvd_level(adev) - 1;
+ if (level < dep_table->count)
+ pi->uvd_dpm.soft_max_clk = dep_table->entries[level].vclk;
+ else
+ pi->uvd_dpm.soft_max_clk =
+ dep_table->entries[dep_table->count - 1].vclk;
+
+ /* get min/max sclk soft value
+ * notify SMU to execute */
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMin,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_min_clk,
+ PPSMC_MSG_SetUvdSoftMin));
+ if (ret)
+ return ret;
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMax,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_max_clk,
+ PPSMC_MSG_SetUvdSoftMax));
+ if (ret)
+ return ret;
+
+ DRM_DEBUG("DPM uvd unforce state min=%d, max=%d.\n",
+ pi->uvd_dpm.soft_min_clk,
+ pi->uvd_dpm.soft_max_clk);
+
+ return 0;
+}
+
+static int cz_dpm_vce_force_highest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->vce_dpm.soft_min_clk != pi->vce_dpm.soft_max_clk) {
+ pi->vce_dpm.soft_min_clk =
+ pi->vce_dpm.soft_max_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetEclkSoftMin,
+ cz_get_eclk_level(adev,
+ pi->vce_dpm.soft_min_clk,
+ PPSMC_MSG_SetEclkSoftMin));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cz_dpm_vce_force_lowest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->vce_dpm.soft_max_clk != pi->vce_dpm.soft_min_clk) {
+ pi->vce_dpm.soft_max_clk = pi->vce_dpm.soft_min_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetEclkSoftMax,
+ cz_get_uvd_level(adev,
+ pi->vce_dpm.soft_max_clk,
+ PPSMC_MSG_SetEclkSoftMax));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static uint32_t cz_dpm_get_max_vce_level(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ if (!pi->max_vce_level) {
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel);
+ pi->max_vce_level = cz_get_argument(adev) + 1;
+ }
+
+ if (pi->max_vce_level > CZ_MAX_HARDWARE_POWERLEVELS) {
+ DRM_ERROR("Invalid max vce level!\n");
+ return -EINVAL;
+ }
+
+ return pi->max_vce_level;
+}
+
+static int cz_dpm_unforce_vce_dpm_levels(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_vce_clock_voltage_dependency_table *dep_table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+ uint32_t level = 0;
+ int ret = 0;
+
+ pi->vce_dpm.soft_min_clk = dep_table->entries[0].ecclk;
+ level = cz_dpm_get_max_vce_level(adev) - 1;
+ if (level < dep_table->count)
+ pi->vce_dpm.soft_max_clk = dep_table->entries[level].ecclk;
+ else
+ pi->vce_dpm.soft_max_clk =
+ dep_table->entries[dep_table->count - 1].ecclk;
+
+ /* get min/max sclk soft value
+ * notify SMU to execute */
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetEclkSoftMin,
+ cz_get_eclk_level(adev,
+ pi->vce_dpm.soft_min_clk,
+ PPSMC_MSG_SetEclkSoftMin));
+ if (ret)
+ return ret;
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetEclkSoftMax,
+ cz_get_eclk_level(adev,
+ pi->vce_dpm.soft_max_clk,
+ PPSMC_MSG_SetEclkSoftMax));
+ if (ret)
+ return ret;
+
+ DRM_DEBUG("DPM vce unforce state min=%d, max=%d.\n",
+ pi->vce_dpm.soft_min_clk,
+ pi->vce_dpm.soft_max_clk);
+
+ return 0;
+}
+
static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
enum amdgpu_dpm_forced_level level)
{
@@ -1746,25 +1971,70 @@ static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
switch (level) {
case AMDGPU_DPM_FORCED_LEVEL_HIGH:
+ /* sclk */
ret = cz_dpm_unforce_dpm_levels(adev);
if (ret)
return ret;
ret = cz_dpm_force_highest(adev);
if (ret)
return ret;
+
+ /* uvd */
+ ret = cz_dpm_unforce_uvd_dpm_levels(adev);
+ if (ret)
+ return ret;
+ ret = cz_dpm_uvd_force_highest(adev);
+ if (ret)
+ return ret;
+
+ /* vce */
+ ret = cz_dpm_unforce_vce_dpm_levels(adev);
+ if (ret)
+ return ret;
+ ret = cz_dpm_vce_force_highest(adev);
+ if (ret)
+ return ret;
break;
case AMDGPU_DPM_FORCED_LEVEL_LOW:
+ /* sclk */
ret = cz_dpm_unforce_dpm_levels(adev);
if (ret)
return ret;
ret = cz_dpm_force_lowest(adev);
if (ret)
return ret;
+
+ /* uvd */
+ ret = cz_dpm_unforce_uvd_dpm_levels(adev);
+ if (ret)
+ return ret;
+ ret = cz_dpm_uvd_force_lowest(adev);
+ if (ret)
+ return ret;
+
+ /* vce */
+ ret = cz_dpm_unforce_vce_dpm_levels(adev);
+ if (ret)
+ return ret;
+ ret = cz_dpm_vce_force_lowest(adev);
+ if (ret)
+ return ret;
break;
case AMDGPU_DPM_FORCED_LEVEL_AUTO:
+ /* sclk */
ret = cz_dpm_unforce_dpm_levels(adev);
if (ret)
return ret;
+
+ /* uvd */
+ ret = cz_dpm_unforce_uvd_dpm_levels(adev);
+ if (ret)
+ return ret;
+
+ /* vce */
+ ret = cz_dpm_unforce_vce_dpm_levels(adev);
+ if (ret)
+ return ret;
break;
default:
break;
@@ -1905,7 +2175,8 @@ static int cz_update_vce_dpm(struct amdgpu_device *adev)
pi->vce_dpm.hard_min_clk = table->entries[table->count-1].ecclk;
} else { /* non-stable p-state cases. without vce.Arbiter.EcclkHardMin */
- pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;
+ /* leave it as set by user */
+ /*pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;*/
}
cz_send_msg_to_smc_with_parameter(adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
index 99e1afc89629..5df8c1faab51 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
@@ -183,6 +183,8 @@ struct cz_power_info {
uint32_t voltage_drop_threshold;
uint32_t gfx_pg_threshold;
uint32_t max_sclk_level;
+ uint32_t max_uvd_level;
+ uint32_t max_vce_level;
/* flags */
bool didt_enabled;
bool video_start;
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
index bc751bfbcae2..c79638f8e732 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -253,8 +253,14 @@ static void cz_ih_set_rptr(struct amdgpu_device *adev)
static int cz_ih_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret;
+
+ ret = amdgpu_irq_add_domain(adev);
+ if (ret)
+ return ret;
cz_ih_set_interrupt_funcs(adev);
+
return 0;
}
@@ -278,6 +284,7 @@ static int cz_ih_sw_fini(void *handle)
amdgpu_irq_fini(adev);
amdgpu_ih_ring_fini(adev);
+ amdgpu_irq_remove_domain(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 4dcc8fba5792..093599aba64b 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -3729,7 +3729,7 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &dce_v10_0_dac_helper_funcs);
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
@@ -3740,15 +3740,15 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
amdgpu_encoder->rmx_type = RMX_FULL;
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
} else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
} else {
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
}
drm_encoder_helper_add(encoder, &dce_v10_0_dig_helper_funcs);
@@ -3766,13 +3766,13 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
amdgpu_encoder->is_ext_encoder = true;
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
else
drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &dce_v10_0_ext_helper_funcs);
break;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index 8f1e51128b33..8e67249d4367 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -211,9 +211,9 @@ static bool dce_v11_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
*/
static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
{
- unsigned i = 0;
+ unsigned i = 100;
- if (crtc >= adev->mode_info.num_crtc)
+ if (crtc < 0 || crtc >= adev->mode_info.num_crtc)
return;
if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK))
@@ -223,14 +223,16 @@ static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
* wait for another frame.
*/
while (dce_v11_0_is_in_vblank(adev, crtc)) {
- if (i++ % 100 == 0) {
+ if (i++ == 100) {
+ i = 0;
if (!dce_v11_0_is_counter_moving(adev, crtc))
break;
}
}
while (!dce_v11_0_is_in_vblank(adev, crtc)) {
- if (i++ % 100 == 0) {
+ if (i++ == 100) {
+ i = 0;
if (!dce_v11_0_is_counter_moving(adev, crtc))
break;
}
@@ -239,7 +241,7 @@ static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
static u32 dce_v11_0_vblank_get_counter(struct amdgpu_device *adev, int crtc)
{
- if (crtc >= adev->mode_info.num_crtc)
+ if (crtc < 0 || crtc >= adev->mode_info.num_crtc)
return 0;
else
return RREG32(mmCRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
@@ -3384,7 +3386,7 @@ static void dce_v11_0_crtc_vblank_int_ack(struct amdgpu_device *adev,
{
u32 tmp;
- if (crtc >= adev->mode_info.num_crtc) {
+ if (crtc < 0 || crtc >= adev->mode_info.num_crtc) {
DRM_DEBUG("invalid crtc %d\n", crtc);
return;
}
@@ -3399,7 +3401,7 @@ static void dce_v11_0_crtc_vline_int_ack(struct amdgpu_device *adev,
{
u32 tmp;
- if (crtc >= adev->mode_info.num_crtc) {
+ if (crtc < 0 || crtc >= adev->mode_info.num_crtc) {
DRM_DEBUG("invalid crtc %d\n", crtc);
return;
}
@@ -3722,7 +3724,7 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &dce_v11_0_dac_helper_funcs);
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
@@ -3733,15 +3735,15 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
amdgpu_encoder->rmx_type = RMX_FULL;
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
} else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
} else {
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
}
drm_encoder_helper_add(encoder, &dce_v11_0_dig_helper_funcs);
@@ -3759,13 +3761,13 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
amdgpu_encoder->is_ext_encoder = true;
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
else
drm_encoder_init(dev, encoder, &dce_v11_0_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &dce_v11_0_ext_helper_funcs);
break;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index 42d954dc436d..d0e128c24813 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -3659,7 +3659,7 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev,
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &dce_v8_0_dac_helper_funcs);
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
@@ -3670,15 +3670,15 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev,
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
amdgpu_encoder->rmx_type = RMX_FULL;
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);
} else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
} else {
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
}
drm_encoder_helper_add(encoder, &dce_v8_0_dig_helper_funcs);
@@ -3696,13 +3696,13 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev,
amdgpu_encoder->is_ext_encoder = true;
if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
else
drm_encoder_init(dev, encoder, &dce_v8_0_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &dce_v8_0_ext_helper_funcs);
break;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c b/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c
index 8f9845d9a986..4b0e45a27129 100644
--- a/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c
@@ -24,7 +24,7 @@
#include <linux/firmware.h>
#include "drmP.h"
#include "amdgpu.h"
-#include "fiji_smumgr.h"
+#include "fiji_smum.h"
MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_ppsmc.h b/drivers/gpu/drm/amd/amdgpu/fiji_ppsmc.h
deleted file mode 100644
index 3c4824082990..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/fiji_ppsmc.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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 FIJI_PP_SMC_H
-#define FIJI_PP_SMC_H
-
-#pragma pack(push, 1)
-
-#define PPSMC_SWSTATE_FLAG_DC 0x01
-#define PPSMC_SWSTATE_FLAG_UVD 0x02
-#define PPSMC_SWSTATE_FLAG_VCE 0x04
-
-#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
-#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
-#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
-
-#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
-#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
-#define PPSMC_SYSTEMFLAG_GDDR5 0x04
-
-#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
-
-#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
-#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
-
-#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
-#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
-
-#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
-#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
-
-#define PPSMC_DPM2FLAGS_TDPCLMP 0x01
-#define PPSMC_DPM2FLAGS_PWRSHFT 0x02
-#define PPSMC_DPM2FLAGS_OCP 0x04
-
-#define PPSMC_DISPLAY_WATERMARK_LOW 0
-#define PPSMC_DISPLAY_WATERMARK_HIGH 1
-
-#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
-#define PPSMC_STATEFLAG_POWERBOOST 0x02
-#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
-#define PPSMC_STATEFLAG_POWERSHIFT 0x08
-#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10
-#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
-#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
-
-#define FDO_MODE_HARDWARE 0
-#define FDO_MODE_PIECE_WISE_LINEAR 1
-
-enum FAN_CONTROL {
- FAN_CONTROL_FUZZY,
- FAN_CONTROL_TABLE
-};
-
-//Gemini Modes
-#define PPSMC_GeminiModeNone 0 //Single GPU board
-#define PPSMC_GeminiModeMaster 1 //Master GPU on a Gemini board
-#define PPSMC_GeminiModeSlave 2 //Slave GPU on a Gemini board
-
-#define PPSMC_Result_OK ((uint16_t)0x01)
-#define PPSMC_Result_NoMore ((uint16_t)0x02)
-#define PPSMC_Result_NotNow ((uint16_t)0x03)
-#define PPSMC_Result_Failed ((uint16_t)0xFF)
-#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE)
-#define PPSMC_Result_UnknownVT ((uint16_t)0xFD)
-
-typedef uint16_t PPSMC_Result;
-
-#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
-
-#define PPSMC_MSG_Halt ((uint16_t)0x10)
-#define PPSMC_MSG_Resume ((uint16_t)0x11)
-#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12)
-#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13)
-#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14)
-#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15)
-#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16)
-#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17)
-#define PPSMC_MSG_LevelUp ((uint16_t)0x18)
-#define PPSMC_MSG_LevelDown ((uint16_t)0x19)
-#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a)
-#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20)
-#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f)
-#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40)
-#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41)
-#define PPSMC_MSG_ForceHigh ((uint16_t)0x42)
-#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43)
-#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51)
-#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52)
-#define PPSMC_MSG_EnableCac ((uint16_t)0x53)
-#define PPSMC_MSG_DisableCac ((uint16_t)0x54)
-#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55)
-#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56)
-#define PPSMC_CACHistoryStart ((uint16_t)0x57)
-#define PPSMC_CACHistoryStop ((uint16_t)0x58)
-#define PPSMC_TDPClampingActive ((uint16_t)0x59)
-#define PPSMC_TDPClampingInactive ((uint16_t)0x5A)
-#define PPSMC_StartFanControl ((uint16_t)0x5B)
-#define PPSMC_StopFanControl ((uint16_t)0x5C)
-#define PPSMC_NoDisplay ((uint16_t)0x5D)
-#define PPSMC_HasDisplay ((uint16_t)0x5E)
-#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60)
-#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61)
-#define PPSMC_MSG_EnableULV ((uint16_t)0x62)
-#define PPSMC_MSG_DisableULV ((uint16_t)0x63)
-#define PPSMC_MSG_EnterULV ((uint16_t)0x64)
-#define PPSMC_MSG_ExitULV ((uint16_t)0x65)
-#define PPSMC_PowerShiftActive ((uint16_t)0x6A)
-#define PPSMC_PowerShiftInactive ((uint16_t)0x6B)
-#define PPSMC_OCPActive ((uint16_t)0x6C)
-#define PPSMC_OCPInactive ((uint16_t)0x6D)
-#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E)
-#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F)
-#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70)
-#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71)
-#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72)
-#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73)
-#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74)
-#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75)
-#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76)
-#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77)
-#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78)
-#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79)
-#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A)
-#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B)
-#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C)
-#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
-#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E)
-#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F)
-#define PPSMC_FlushDataCache ((uint16_t)0x80)
-#define PPSMC_FlushInstrCache ((uint16_t)0x81)
-#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82)
-#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83)
-#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84)
-#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85)
-#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86)
-#define PPSMC_MSG_EnableDTE ((uint16_t)0x87)
-#define PPSMC_MSG_DisableDTE ((uint16_t)0x88)
-#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89)
-#define PPSMC_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A)
-#define PPSMC_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B)
-#define PPSMC_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C)
-
-#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
-
-#define PPSMC_MSG_Test ((uint16_t)0x100)
-#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t)0x250)
-#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t)0x251)
-#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t)0x252)
-#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t)0x253)
-#define PPSMC_MSG_LoadUcodes ((uint16_t)0x254)
-
-typedef uint16_t PPSMC_Msg;
-
-#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
-#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
-#define PPSMC_EVENT_STATUS_DC 0x00000004
-#define PPSMC_EVENT_STATUS_GPIO17 0x00000008
-
-#pragma pack(pop)
-
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c
index bda1249eb871..e35340afd3db 100644
--- a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c
+++ b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c
@@ -25,7 +25,7 @@
#include "drmP.h"
#include "amdgpu.h"
#include "fiji_ppsmc.h"
-#include "fiji_smumgr.h"
+#include "fiji_smum.h"
#include "smu_ucode_xfer_vi.h"
#include "amdgpu_ucode.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smumgr.h b/drivers/gpu/drm/amd/amdgpu/fiji_smum.h
index 1cef03deeac3..1cef03deeac3 100644
--- a/drivers/gpu/drm/amd/amdgpu/fiji_smumgr.h
+++ b/drivers/gpu/drm/amd/amdgpu/fiji_smum.h
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index e1dcab98e249..13235d84e5a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -66,6 +66,27 @@
#define MACRO_TILE_ASPECT(x) ((x) << GB_MACROTILE_MODE0__MACRO_TILE_ASPECT__SHIFT)
#define NUM_BANKS(x) ((x) << GB_MACROTILE_MODE0__NUM_BANKS__SHIFT)
+#define RLC_CGTT_MGCG_OVERRIDE__CPF_MASK 0x00000001L
+#define RLC_CGTT_MGCG_OVERRIDE__RLC_MASK 0x00000002L
+#define RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK 0x00000004L
+#define RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK 0x00000008L
+#define RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK 0x00000010L
+#define RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK 0x00000020L
+
+/* BPM SERDES CMD */
+#define SET_BPM_SERDES_CMD 1
+#define CLE_BPM_SERDES_CMD 0
+
+/* BPM Register Address*/
+enum {
+ BPM_REG_CGLS_EN = 0, /* Enable/Disable CGLS */
+ BPM_REG_CGLS_ON, /* ON/OFF CGLS: shall be controlled by RLC FW */
+ BPM_REG_CGCG_OVERRIDE, /* Set/Clear CGCG Override */
+ BPM_REG_MGCG_OVERRIDE, /* Set/Clear MGCG Override */
+ BPM_REG_FGCG_OVERRIDE, /* Set/Clear FGCG Override */
+ BPM_REG_FGCG_MAX
+};
+
MODULE_FIRMWARE("amdgpu/carrizo_ce.bin");
MODULE_FIRMWARE("amdgpu/carrizo_pfp.bin");
MODULE_FIRMWARE("amdgpu/carrizo_me.bin");
@@ -964,6 +985,322 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
return 0;
}
+static const u32 vgpr_init_compute_shader[] =
+{
+ 0x7e000209, 0x7e020208,
+ 0x7e040207, 0x7e060206,
+ 0x7e080205, 0x7e0a0204,
+ 0x7e0c0203, 0x7e0e0202,
+ 0x7e100201, 0x7e120200,
+ 0x7e140209, 0x7e160208,
+ 0x7e180207, 0x7e1a0206,
+ 0x7e1c0205, 0x7e1e0204,
+ 0x7e200203, 0x7e220202,
+ 0x7e240201, 0x7e260200,
+ 0x7e280209, 0x7e2a0208,
+ 0x7e2c0207, 0x7e2e0206,
+ 0x7e300205, 0x7e320204,
+ 0x7e340203, 0x7e360202,
+ 0x7e380201, 0x7e3a0200,
+ 0x7e3c0209, 0x7e3e0208,
+ 0x7e400207, 0x7e420206,
+ 0x7e440205, 0x7e460204,
+ 0x7e480203, 0x7e4a0202,
+ 0x7e4c0201, 0x7e4e0200,
+ 0x7e500209, 0x7e520208,
+ 0x7e540207, 0x7e560206,
+ 0x7e580205, 0x7e5a0204,
+ 0x7e5c0203, 0x7e5e0202,
+ 0x7e600201, 0x7e620200,
+ 0x7e640209, 0x7e660208,
+ 0x7e680207, 0x7e6a0206,
+ 0x7e6c0205, 0x7e6e0204,
+ 0x7e700203, 0x7e720202,
+ 0x7e740201, 0x7e760200,
+ 0x7e780209, 0x7e7a0208,
+ 0x7e7c0207, 0x7e7e0206,
+ 0xbf8a0000, 0xbf810000,
+};
+
+static const u32 sgpr_init_compute_shader[] =
+{
+ 0xbe8a0100, 0xbe8c0102,
+ 0xbe8e0104, 0xbe900106,
+ 0xbe920108, 0xbe940100,
+ 0xbe960102, 0xbe980104,
+ 0xbe9a0106, 0xbe9c0108,
+ 0xbe9e0100, 0xbea00102,
+ 0xbea20104, 0xbea40106,
+ 0xbea60108, 0xbea80100,
+ 0xbeaa0102, 0xbeac0104,
+ 0xbeae0106, 0xbeb00108,
+ 0xbeb20100, 0xbeb40102,
+ 0xbeb60104, 0xbeb80106,
+ 0xbeba0108, 0xbebc0100,
+ 0xbebe0102, 0xbec00104,
+ 0xbec20106, 0xbec40108,
+ 0xbec60100, 0xbec80102,
+ 0xbee60004, 0xbee70005,
+ 0xbeea0006, 0xbeeb0007,
+ 0xbee80008, 0xbee90009,
+ 0xbefc0000, 0xbf8a0000,
+ 0xbf810000, 0x00000000,
+};
+
+static const u32 vgpr_init_regs[] =
+{
+ mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xffffffff,
+ mmCOMPUTE_RESOURCE_LIMITS, 0,
+ mmCOMPUTE_NUM_THREAD_X, 256*4,
+ mmCOMPUTE_NUM_THREAD_Y, 1,
+ mmCOMPUTE_NUM_THREAD_Z, 1,
+ mmCOMPUTE_PGM_RSRC2, 20,
+ mmCOMPUTE_USER_DATA_0, 0xedcedc00,
+ mmCOMPUTE_USER_DATA_1, 0xedcedc01,
+ mmCOMPUTE_USER_DATA_2, 0xedcedc02,
+ mmCOMPUTE_USER_DATA_3, 0xedcedc03,
+ mmCOMPUTE_USER_DATA_4, 0xedcedc04,
+ mmCOMPUTE_USER_DATA_5, 0xedcedc05,
+ mmCOMPUTE_USER_DATA_6, 0xedcedc06,
+ mmCOMPUTE_USER_DATA_7, 0xedcedc07,
+ mmCOMPUTE_USER_DATA_8, 0xedcedc08,
+ mmCOMPUTE_USER_DATA_9, 0xedcedc09,
+};
+
+static const u32 sgpr1_init_regs[] =
+{
+ mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0x0f,
+ mmCOMPUTE_RESOURCE_LIMITS, 0x1000000,
+ mmCOMPUTE_NUM_THREAD_X, 256*5,
+ mmCOMPUTE_NUM_THREAD_Y, 1,
+ mmCOMPUTE_NUM_THREAD_Z, 1,
+ mmCOMPUTE_PGM_RSRC2, 20,
+ mmCOMPUTE_USER_DATA_0, 0xedcedc00,
+ mmCOMPUTE_USER_DATA_1, 0xedcedc01,
+ mmCOMPUTE_USER_DATA_2, 0xedcedc02,
+ mmCOMPUTE_USER_DATA_3, 0xedcedc03,
+ mmCOMPUTE_USER_DATA_4, 0xedcedc04,
+ mmCOMPUTE_USER_DATA_5, 0xedcedc05,
+ mmCOMPUTE_USER_DATA_6, 0xedcedc06,
+ mmCOMPUTE_USER_DATA_7, 0xedcedc07,
+ mmCOMPUTE_USER_DATA_8, 0xedcedc08,
+ mmCOMPUTE_USER_DATA_9, 0xedcedc09,
+};
+
+static const u32 sgpr2_init_regs[] =
+{
+ mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xf0,
+ mmCOMPUTE_RESOURCE_LIMITS, 0x1000000,
+ mmCOMPUTE_NUM_THREAD_X, 256*5,
+ mmCOMPUTE_NUM_THREAD_Y, 1,
+ mmCOMPUTE_NUM_THREAD_Z, 1,
+ mmCOMPUTE_PGM_RSRC2, 20,
+ mmCOMPUTE_USER_DATA_0, 0xedcedc00,
+ mmCOMPUTE_USER_DATA_1, 0xedcedc01,
+ mmCOMPUTE_USER_DATA_2, 0xedcedc02,
+ mmCOMPUTE_USER_DATA_3, 0xedcedc03,
+ mmCOMPUTE_USER_DATA_4, 0xedcedc04,
+ mmCOMPUTE_USER_DATA_5, 0xedcedc05,
+ mmCOMPUTE_USER_DATA_6, 0xedcedc06,
+ mmCOMPUTE_USER_DATA_7, 0xedcedc07,
+ mmCOMPUTE_USER_DATA_8, 0xedcedc08,
+ mmCOMPUTE_USER_DATA_9, 0xedcedc09,
+};
+
+static const u32 sec_ded_counter_registers[] =
+{
+ mmCPC_EDC_ATC_CNT,
+ mmCPC_EDC_SCRATCH_CNT,
+ mmCPC_EDC_UCODE_CNT,
+ mmCPF_EDC_ATC_CNT,
+ mmCPF_EDC_ROQ_CNT,
+ mmCPF_EDC_TAG_CNT,
+ mmCPG_EDC_ATC_CNT,
+ mmCPG_EDC_DMA_CNT,
+ mmCPG_EDC_TAG_CNT,
+ mmDC_EDC_CSINVOC_CNT,
+ mmDC_EDC_RESTORE_CNT,
+ mmDC_EDC_STATE_CNT,
+ mmGDS_EDC_CNT,
+ mmGDS_EDC_GRBM_CNT,
+ mmGDS_EDC_OA_DED,
+ mmSPI_EDC_CNT,
+ mmSQC_ATC_EDC_GATCL1_CNT,
+ mmSQC_EDC_CNT,
+ mmSQ_EDC_DED_CNT,
+ mmSQ_EDC_INFO,
+ mmSQ_EDC_SEC_CNT,
+ mmTCC_EDC_CNT,
+ mmTCP_ATC_EDC_GATCL1_CNT,
+ mmTCP_EDC_CNT,
+ mmTD_EDC_CNT
+};
+
+static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *ring = &adev->gfx.compute_ring[0];
+ struct amdgpu_ib ib;
+ struct fence *f = NULL;
+ int r, i;
+ u32 tmp;
+ unsigned total_size, vgpr_offset, sgpr_offset;
+ u64 gpu_addr;
+
+ /* only supported on CZ */
+ if (adev->asic_type != CHIP_CARRIZO)
+ return 0;
+
+ /* bail if the compute ring is not ready */
+ if (!ring->ready)
+ return 0;
+
+ tmp = RREG32(mmGB_EDC_MODE);
+ WREG32(mmGB_EDC_MODE, 0);
+
+ total_size =
+ (((ARRAY_SIZE(vgpr_init_regs) / 2) * 3) + 4 + 5 + 2) * 4;
+ total_size +=
+ (((ARRAY_SIZE(sgpr1_init_regs) / 2) * 3) + 4 + 5 + 2) * 4;
+ total_size +=
+ (((ARRAY_SIZE(sgpr2_init_regs) / 2) * 3) + 4 + 5 + 2) * 4;
+ total_size = ALIGN(total_size, 256);
+ vgpr_offset = total_size;
+ total_size += ALIGN(sizeof(vgpr_init_compute_shader), 256);
+ sgpr_offset = total_size;
+ total_size += sizeof(sgpr_init_compute_shader);
+
+ /* allocate an indirect buffer to put the commands in */
+ memset(&ib, 0, sizeof(ib));
+ r = amdgpu_ib_get(ring, NULL, total_size, &ib);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
+ return r;
+ }
+
+ /* load the compute shaders */
+ for (i = 0; i < ARRAY_SIZE(vgpr_init_compute_shader); i++)
+ ib.ptr[i + (vgpr_offset / 4)] = vgpr_init_compute_shader[i];
+
+ for (i = 0; i < ARRAY_SIZE(sgpr_init_compute_shader); i++)
+ ib.ptr[i + (sgpr_offset / 4)] = sgpr_init_compute_shader[i];
+
+ /* init the ib length to 0 */
+ ib.length_dw = 0;
+
+ /* VGPR */
+ /* write the register state for the compute dispatch */
+ for (i = 0; i < ARRAY_SIZE(vgpr_init_regs); i += 2) {
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1);
+ ib.ptr[ib.length_dw++] = vgpr_init_regs[i] - PACKET3_SET_SH_REG_START;
+ ib.ptr[ib.length_dw++] = vgpr_init_regs[i + 1];
+ }
+ /* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */
+ gpu_addr = (ib.gpu_addr + (u64)vgpr_offset) >> 8;
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2);
+ ib.ptr[ib.length_dw++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+ ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr);
+ ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr);
+
+ /* write dispatch packet */
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+ ib.ptr[ib.length_dw++] = 8; /* x */
+ ib.ptr[ib.length_dw++] = 1; /* y */
+ ib.ptr[ib.length_dw++] = 1; /* z */
+ ib.ptr[ib.length_dw++] =
+ REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1);
+
+ /* write CS partial flush packet */
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0);
+ ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
+
+ /* SGPR1 */
+ /* write the register state for the compute dispatch */
+ for (i = 0; i < ARRAY_SIZE(sgpr1_init_regs); i += 2) {
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1);
+ ib.ptr[ib.length_dw++] = sgpr1_init_regs[i] - PACKET3_SET_SH_REG_START;
+ ib.ptr[ib.length_dw++] = sgpr1_init_regs[i + 1];
+ }
+ /* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */
+ gpu_addr = (ib.gpu_addr + (u64)sgpr_offset) >> 8;
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2);
+ ib.ptr[ib.length_dw++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+ ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr);
+ ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr);
+
+ /* write dispatch packet */
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+ ib.ptr[ib.length_dw++] = 8; /* x */
+ ib.ptr[ib.length_dw++] = 1; /* y */
+ ib.ptr[ib.length_dw++] = 1; /* z */
+ ib.ptr[ib.length_dw++] =
+ REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1);
+
+ /* write CS partial flush packet */
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0);
+ ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
+
+ /* SGPR2 */
+ /* write the register state for the compute dispatch */
+ for (i = 0; i < ARRAY_SIZE(sgpr2_init_regs); i += 2) {
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1);
+ ib.ptr[ib.length_dw++] = sgpr2_init_regs[i] - PACKET3_SET_SH_REG_START;
+ ib.ptr[ib.length_dw++] = sgpr2_init_regs[i + 1];
+ }
+ /* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */
+ gpu_addr = (ib.gpu_addr + (u64)sgpr_offset) >> 8;
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2);
+ ib.ptr[ib.length_dw++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START;
+ ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr);
+ ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr);
+
+ /* write dispatch packet */
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3);
+ ib.ptr[ib.length_dw++] = 8; /* x */
+ ib.ptr[ib.length_dw++] = 1; /* y */
+ ib.ptr[ib.length_dw++] = 1; /* z */
+ ib.ptr[ib.length_dw++] =
+ REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1);
+
+ /* write CS partial flush packet */
+ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0);
+ ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4);
+
+ /* shedule the ib on the ring */
+ r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL,
+ AMDGPU_FENCE_OWNER_UNDEFINED,
+ &f);
+ if (r) {
+ DRM_ERROR("amdgpu: ib submit failed (%d).\n", r);
+ goto fail;
+ }
+
+ /* wait for the GPU to finish processing the IB */
+ r = fence_wait(f, false);
+ if (r) {
+ DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
+ goto fail;
+ }
+
+ tmp = REG_SET_FIELD(tmp, GB_EDC_MODE, DED_MODE, 2);
+ tmp = REG_SET_FIELD(tmp, GB_EDC_MODE, PROP_FED, 1);
+ WREG32(mmGB_EDC_MODE, tmp);
+
+ tmp = RREG32(mmCC_GC_EDC_CONFIG);
+ tmp = REG_SET_FIELD(tmp, CC_GC_EDC_CONFIG, DIS_EDC, 0) | 1;
+ WREG32(mmCC_GC_EDC_CONFIG, tmp);
+
+
+ /* read back registers to clear the counters */
+ for (i = 0; i < ARRAY_SIZE(sec_ded_counter_registers); i++)
+ RREG32(sec_ded_counter_registers[i]);
+
+fail:
+ fence_put(f);
+ amdgpu_ib_free(adev, &ib);
+
+ return r;
+}
+
static void gfx_v8_0_gpu_early_init(struct amdgpu_device *adev)
{
u32 gb_addr_config;
@@ -1323,1418 +1660,923 @@ static int gfx_v8_0_sw_fini(void *handle)
static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
{
- const u32 num_tile_mode_states = 32;
- const u32 num_secondary_tile_mode_states = 16;
- u32 reg_offset, gb_tile_moden, split_equal_to_row_size;
+ uint32_t *modearray, *mod2array;
+ const u32 num_tile_mode_states = ARRAY_SIZE(adev->gfx.config.tile_mode_array);
+ const u32 num_secondary_tile_mode_states = ARRAY_SIZE(adev->gfx.config.macrotile_mode_array);
+ u32 reg_offset;
- switch (adev->gfx.config.mem_row_size_in_kb) {
- case 1:
- split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_1KB;
- break;
- case 2:
- default:
- split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_2KB;
- break;
- case 4:
- split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_4KB;
- break;
- }
+ modearray = adev->gfx.config.tile_mode_array;
+ mod2array = adev->gfx.config.macrotile_mode_array;
+
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
+ modearray[reg_offset] = 0;
+
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++)
+ mod2array[reg_offset] = 0;
switch (adev->asic_type) {
case CHIP_TOPAZ:
- for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 1:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 2:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 3:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 4:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 5:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 6:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 8:
- gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
- PIPE_CONFIG(ADDR_SURF_P2));
- break;
- case 9:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 10:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 11:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 13:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 14:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 15:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 16:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 18:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 19:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 20:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 21:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 22:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 24:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 25:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 26:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 27:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 28:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 29:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 7:
- case 12:
- case 17:
- case 23:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
- }
- for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 1:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 2:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 3:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 4:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 5:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 6:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 8:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 9:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 10:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 11:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 12:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 13:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 14:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 7:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
- }
+ modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[6] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P2));
+ modearray[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[15] = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[18] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[19] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[20] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[21] = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[22] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[24] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[25] = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[26] = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+
+ mod2array[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
+ if (reg_offset != 7 && reg_offset != 12 && reg_offset != 17 &&
+ reg_offset != 23)
+ WREG32(mmGB_TILE_MODE0 + reg_offset, modearray[reg_offset]);
+
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++)
+ if (reg_offset != 7)
+ WREG32(mmGB_MACROTILE_MODE0 + reg_offset, mod2array[reg_offset]);
+
+ break;
case CHIP_FIJI:
- for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 1:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 2:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 3:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 4:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 5:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 6:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 7:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 8:
- gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16));
- break;
- case 9:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 10:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 11:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 12:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 13:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 14:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 15:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 16:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 17:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 18:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 19:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 20:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 21:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 22:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 23:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 24:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 25:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 26:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 27:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 28:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 29:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 30:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- default:
- gb_tile_moden = 0;
- break;
- }
- adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
- }
- for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 1:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 2:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 3:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 4:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 5:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 6:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 8:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 9:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 10:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 11:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 12:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 13:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 14:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_4_BANK));
- break;
- case 7:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- }
- adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
- }
+ modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[6] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[7] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16));
+ modearray[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[12] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[15] = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[17] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[18] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[19] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[20] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[21] = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[22] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[23] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[24] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[25] = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[26] = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[30] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+
+ mod2array[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
+ WREG32(mmGB_TILE_MODE0 + reg_offset, modearray[reg_offset]);
+
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++)
+ if (reg_offset != 7)
+ WREG32(mmGB_MACROTILE_MODE0 + reg_offset, mod2array[reg_offset]);
+
break;
case CHIP_TONGA:
- for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 1:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 2:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 3:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 4:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 5:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 6:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 7:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 8:
- gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16));
- break;
- case 9:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 10:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 11:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 12:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 13:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 14:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 15:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 16:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 17:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 18:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 19:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 20:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 21:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 22:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 23:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 24:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 25:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 26:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 27:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 28:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 29:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 30:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P4_16x16) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
- }
- for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 1:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 2:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 3:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 4:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 5:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 6:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 8:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 9:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 10:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 11:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 12:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 13:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_4_BANK));
- break;
- case 14:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
- NUM_BANKS(ADDR_SURF_4_BANK));
- break;
- case 7:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
- }
+ modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[6] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[7] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16));
+ modearray[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[12] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[15] = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[17] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[18] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[19] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[20] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[21] = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[22] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[23] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[24] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[25] = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[26] = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[30] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+
+ mod2array[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+ mod2array[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
+ WREG32(mmGB_TILE_MODE0 + reg_offset, modearray[reg_offset]);
+
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++)
+ if (reg_offset != 7)
+ WREG32(mmGB_MACROTILE_MODE0 + reg_offset, mod2array[reg_offset]);
+
break;
case CHIP_STONEY:
- for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 1:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 2:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 3:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 4:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 5:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 6:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 8:
- gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
- PIPE_CONFIG(ADDR_SURF_P2));
- break;
- case 9:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 10:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 11:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 13:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 14:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 15:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 16:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 18:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 19:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 20:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 21:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 22:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 24:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 25:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 26:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 27:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 28:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 29:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 7:
- case 12:
- case 17:
- case 23:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
- }
- for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 1:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 2:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 3:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 4:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 5:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 6:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 8:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 9:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 10:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 11:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 12:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 13:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 14:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 7:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
- }
+ modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[6] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P2));
+ modearray[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[15] = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[18] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[19] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[20] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[21] = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[22] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[24] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[25] = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[26] = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+
+ mod2array[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
+ if (reg_offset != 7 && reg_offset != 12 && reg_offset != 17 &&
+ reg_offset != 23)
+ WREG32(mmGB_TILE_MODE0 + reg_offset, modearray[reg_offset]);
+
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++)
+ if (reg_offset != 7)
+ WREG32(mmGB_MACROTILE_MODE0 + reg_offset, mod2array[reg_offset]);
+
break;
- case CHIP_CARRIZO:
default:
- for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 1:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 2:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 3:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 4:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 5:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 6:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
- break;
- case 8:
- gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
- PIPE_CONFIG(ADDR_SURF_P2));
- break;
- case 9:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 10:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 11:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 13:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 14:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 15:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 16:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 18:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 19:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 20:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 21:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 22:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 24:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 25:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 26:
- gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
- break;
- case 27:
- gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 28:
- gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
- break;
- case 29:
- gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
- PIPE_CONFIG(ADDR_SURF_P2) |
- MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
- SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
- break;
- case 7:
- case 12:
- case 17:
- case 23:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
- }
- for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
- switch (reg_offset) {
- case 0:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 1:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 2:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 3:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 4:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 5:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 6:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 8:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 9:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 10:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 11:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 12:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 13:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
- NUM_BANKS(ADDR_SURF_16_BANK));
- break;
- case 14:
- gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
- BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
- MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
- NUM_BANKS(ADDR_SURF_8_BANK));
- break;
- case 7:
- /* unused idx */
- continue;
- default:
- gb_tile_moden = 0;
- break;
- };
- adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
- WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
- }
+ dev_warn(adev->dev,
+ "Unknown chip type (%d) in function gfx_v8_0_tiling_mode_table_init() falling through to CHIP_CARRIZO\n",
+ adev->asic_type);
+
+ case CHIP_CARRIZO:
+ modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[6] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ modearray[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P2));
+ modearray[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[15] = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ modearray[18] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[19] = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[20] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[21] = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[22] = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[24] = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[25] = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[26] = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ modearray[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ modearray[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+
+ mod2array[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ mod2array[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ mod2array[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++)
+ if (reg_offset != 7 && reg_offset != 12 && reg_offset != 17 &&
+ reg_offset != 23)
+ WREG32(mmGB_TILE_MODE0 + reg_offset, modearray[reg_offset]);
+
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++)
+ if (reg_offset != 7)
+ WREG32(mmGB_MACROTILE_MODE0 + reg_offset, mod2array[reg_offset]);
+
+ break;
}
}
static u32 gfx_v8_0_create_bitmask(u32 bit_width)
{
- u32 i, mask = 0;
-
- for (i = 0; i < bit_width; i++) {
- mask <<= 1;
- mask |= 1;
- }
- return mask;
+ return (u32)((1ULL << bit_width) - 1);
}
void gfx_v8_0_select_se_sh(struct amdgpu_device *adev, u32 se_num, u32 sh_num)
@@ -2809,7 +2651,7 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev,
mutex_lock(&adev->grbm_idx_mutex);
for (i = 0; i < se_num; i++) {
gfx_v8_0_select_se_sh(adev, i, 0xffffffff);
- data = 0;
+ data = RREG32(mmPA_SC_RASTER_CONFIG);
for (j = 0; j < sh_per_se; j++) {
switch (enabled_rbs & 3) {
case 0:
@@ -2997,17 +2839,11 @@ static void gfx_v8_0_enable_gui_idle_interrupt(struct amdgpu_device *adev,
{
u32 tmp = RREG32(mmCP_INT_CNTL_RING0);
- if (enable) {
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, 1);
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, 1);
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, 1);
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, 1);
- } else {
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, 0);
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, 0);
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, 0);
- tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, 0);
- }
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, enable ? 1 : 0);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, enable ? 1 : 0);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, enable ? 1 : 0);
+ tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, enable ? 1 : 0);
+
WREG32(mmCP_INT_CNTL_RING0, tmp);
}
@@ -3087,16 +2923,18 @@ static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
gfx_v8_0_rlc_reset(adev);
- if (!adev->firmware.smu_load) {
- /* legacy rlc firmware loading */
- r = gfx_v8_0_rlc_load_microcode(adev);
- if (r)
- return r;
- } else {
- r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
- AMDGPU_UCODE_ID_RLC_G);
- if (r)
- return -EINVAL;
+ if (!adev->pp_enabled) {
+ if (!adev->firmware.smu_load) {
+ /* legacy rlc firmware loading */
+ r = gfx_v8_0_rlc_load_microcode(adev);
+ if (r)
+ return r;
+ } else {
+ r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+ AMDGPU_UCODE_ID_RLC_G);
+ if (r)
+ return -EINVAL;
+ }
}
gfx_v8_0_rlc_start(adev);
@@ -3941,6 +3779,11 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
tmp = REG_SET_FIELD(tmp, CP_HQD_PERSISTENT_STATE, PRELOAD_SIZE, 0x53);
WREG32(mmCP_HQD_PERSISTENT_STATE, tmp);
mqd->cp_hqd_persistent_state = tmp;
+ if (adev->asic_type == CHIP_STONEY) {
+ tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL);
+ tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1);
+ WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp);
+ }
/* activate the queue */
mqd->cp_hqd_active = 1;
@@ -3982,35 +3825,37 @@ static int gfx_v8_0_cp_resume(struct amdgpu_device *adev)
if (!(adev->flags & AMD_IS_APU))
gfx_v8_0_enable_gui_idle_interrupt(adev, false);
- if (!adev->firmware.smu_load) {
- /* legacy firmware loading */
- r = gfx_v8_0_cp_gfx_load_microcode(adev);
- if (r)
- return r;
-
- r = gfx_v8_0_cp_compute_load_microcode(adev);
- if (r)
- return r;
- } else {
- r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
- AMDGPU_UCODE_ID_CP_CE);
- if (r)
- return -EINVAL;
-
- r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
- AMDGPU_UCODE_ID_CP_PFP);
- if (r)
- return -EINVAL;
-
- r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
- AMDGPU_UCODE_ID_CP_ME);
- if (r)
- return -EINVAL;
+ if (!adev->pp_enabled) {
+ if (!adev->firmware.smu_load) {
+ /* legacy firmware loading */
+ r = gfx_v8_0_cp_gfx_load_microcode(adev);
+ if (r)
+ return r;
- r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
- AMDGPU_UCODE_ID_CP_MEC1);
- if (r)
- return -EINVAL;
+ r = gfx_v8_0_cp_compute_load_microcode(adev);
+ if (r)
+ return r;
+ } else {
+ r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+ AMDGPU_UCODE_ID_CP_CE);
+ if (r)
+ return -EINVAL;
+
+ r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+ AMDGPU_UCODE_ID_CP_PFP);
+ if (r)
+ return -EINVAL;
+
+ r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+ AMDGPU_UCODE_ID_CP_ME);
+ if (r)
+ return -EINVAL;
+
+ r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+ AMDGPU_UCODE_ID_CP_MEC1);
+ if (r)
+ return -EINVAL;
+ }
}
r = gfx_v8_0_cp_gfx_resume(adev);
@@ -4458,15 +4303,261 @@ static int gfx_v8_0_early_init(void *handle)
return 0;
}
+static int gfx_v8_0_late_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int r;
+
+ /* requires IBs so do in late init after IB pool is initialized */
+ r = gfx_v8_0_do_edc_gpr_workarounds(adev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
static int gfx_v8_0_set_powergating_state(void *handle,
enum amd_powergating_state state)
{
return 0;
}
+static void fiji_send_serdes_cmd(struct amdgpu_device *adev,
+ uint32_t reg_addr, uint32_t cmd)
+{
+ uint32_t data;
+
+ gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff);
+
+ WREG32(mmRLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
+ WREG32(mmRLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
+
+ data = RREG32(mmRLC_SERDES_WR_CTRL);
+ data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK |
+ RLC_SERDES_WR_CTRL__READ_COMMAND_MASK |
+ RLC_SERDES_WR_CTRL__P1_SELECT_MASK |
+ RLC_SERDES_WR_CTRL__P2_SELECT_MASK |
+ RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK |
+ RLC_SERDES_WR_CTRL__POWER_DOWN_MASK |
+ RLC_SERDES_WR_CTRL__POWER_UP_MASK |
+ RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK |
+ RLC_SERDES_WR_CTRL__BPM_DATA_MASK |
+ RLC_SERDES_WR_CTRL__REG_ADDR_MASK |
+ RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK);
+ data |= (RLC_SERDES_WR_CTRL__RSVD_BPM_ADDR_MASK |
+ (cmd << RLC_SERDES_WR_CTRL__BPM_DATA__SHIFT) |
+ (reg_addr << RLC_SERDES_WR_CTRL__REG_ADDR__SHIFT) |
+ (0xff << RLC_SERDES_WR_CTRL__BPM_ADDR__SHIFT));
+
+ WREG32(mmRLC_SERDES_WR_CTRL, data);
+}
+
+static void fiji_update_medium_grain_clock_gating(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ /* It is disabled by HW by default */
+ if (enable) {
+ /* 1 - RLC memory Light sleep */
+ temp = data = RREG32(mmRLC_MEM_SLP_CNTL);
+ data |= RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
+ if (temp != data)
+ WREG32(mmRLC_MEM_SLP_CNTL, data);
+
+ /* 2 - CP memory Light sleep */
+ temp = data = RREG32(mmCP_MEM_SLP_CNTL);
+ data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
+ if (temp != data)
+ WREG32(mmCP_MEM_SLP_CNTL, data);
+
+ /* 3 - RLC_CGTT_MGCG_OVERRIDE */
+ temp = data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+ data &= ~(RLC_CGTT_MGCG_OVERRIDE__CPF_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__RLC_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK);
+
+ if (temp != data)
+ WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data);
+
+ /* 4 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+
+ /* 5 - clear mgcg override */
+ fiji_send_serdes_cmd(adev, BPM_REG_MGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
+
+ /* 6 - Enable CGTS(Tree Shade) MGCG /MGLS */
+ temp = data = RREG32(mmCGTS_SM_CTRL_REG);
+ data &= ~(CGTS_SM_CTRL_REG__SM_MODE_MASK);
+ data |= (0x2 << CGTS_SM_CTRL_REG__SM_MODE__SHIFT);
+ data |= CGTS_SM_CTRL_REG__SM_MODE_ENABLE_MASK;
+ data &= ~CGTS_SM_CTRL_REG__OVERRIDE_MASK;
+ data &= ~CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK;
+ data |= CGTS_SM_CTRL_REG__ON_MONITOR_ADD_EN_MASK;
+ data |= (0x96 << CGTS_SM_CTRL_REG__ON_MONITOR_ADD__SHIFT);
+ if (temp != data)
+ WREG32(mmCGTS_SM_CTRL_REG, data);
+ udelay(50);
+
+ /* 7 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+ } else {
+ /* 1 - MGCG_OVERRIDE[0] for CP and MGCG_OVERRIDE[1] for RLC */
+ temp = data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+ data |= (RLC_CGTT_MGCG_OVERRIDE__CPF_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__RLC_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK);
+ if (temp != data)
+ WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data);
+
+ /* 2 - disable MGLS in RLC */
+ data = RREG32(mmRLC_MEM_SLP_CNTL);
+ if (data & RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK) {
+ data &= ~RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
+ WREG32(mmRLC_MEM_SLP_CNTL, data);
+ }
+
+ /* 3 - disable MGLS in CP */
+ data = RREG32(mmCP_MEM_SLP_CNTL);
+ if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
+ data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
+ WREG32(mmCP_MEM_SLP_CNTL, data);
+ }
+
+ /* 4 - Disable CGTS(Tree Shade) MGCG and MGLS */
+ temp = data = RREG32(mmCGTS_SM_CTRL_REG);
+ data |= (CGTS_SM_CTRL_REG__OVERRIDE_MASK |
+ CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK);
+ if (temp != data)
+ WREG32(mmCGTS_SM_CTRL_REG, data);
+
+ /* 5 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+
+ /* 6 - set mgcg override */
+ fiji_send_serdes_cmd(adev, BPM_REG_MGCG_OVERRIDE, SET_BPM_SERDES_CMD);
+
+ udelay(50);
+
+ /* 7- wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+ }
+}
+
+static void fiji_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, temp1, data, data1;
+
+ temp = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
+
+ if (enable) {
+ /* 1 enable cntx_empty_int_enable/cntx_busy_int_enable/
+ * Cmp_busy/GFX_Idle interrupts
+ */
+ gfx_v8_0_enable_gui_idle_interrupt(adev, true);
+
+ temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+ data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK;
+ if (temp1 != data1)
+ WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
+
+ /* 2 wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+
+ /* 3 - clear cgcg override */
+ fiji_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
+
+ /* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+
+ /* 4 - write cmd to set CGLS */
+ fiji_send_serdes_cmd(adev, BPM_REG_CGLS_EN, SET_BPM_SERDES_CMD);
+
+ /* 5 - enable cgcg */
+ data |= RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
+
+ /* enable cgls*/
+ data |= RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK;
+
+ temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+ data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK;
+
+ if (temp1 != data1)
+ WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
+
+ if (temp != data)
+ WREG32(mmRLC_CGCG_CGLS_CTRL, data);
+ } else {
+ /* disable cntx_empty_int_enable & GFX Idle interrupt */
+ gfx_v8_0_enable_gui_idle_interrupt(adev, false);
+
+ /* TEST CGCG */
+ temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
+ data1 |= (RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK);
+ if (temp1 != data1)
+ WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
+
+ /* read gfx register to wake up cgcg */
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+ RREG32(mmCB_CGTT_SCLK_CTRL);
+
+ /* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+
+ /* write cmd to Set CGCG Overrride */
+ fiji_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, SET_BPM_SERDES_CMD);
+
+ /* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+ gfx_v8_0_wait_for_rlc_serdes(adev);
+
+ /* write cmd to Clear CGLS */
+ fiji_send_serdes_cmd(adev, BPM_REG_CGLS_EN, CLE_BPM_SERDES_CMD);
+
+ /* disable cgcg, cgls should be disabled too. */
+ data &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK |
+ RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
+ if (temp != data)
+ WREG32(mmRLC_CGCG_CGLS_CTRL, data);
+ }
+}
+static int fiji_update_gfx_clock_gating(struct amdgpu_device *adev,
+ bool enable)
+{
+ if (enable) {
+ /* CGCG/CGLS should be enabled after MGCG/MGLS/TS(CG/LS)
+ * === MGCG + MGLS + TS(CG/LS) ===
+ */
+ fiji_update_medium_grain_clock_gating(adev, enable);
+ fiji_update_coarse_grain_clock_gating(adev, enable);
+ } else {
+ /* CGCG/CGLS should be disabled before MGCG/MGLS/TS(CG/LS)
+ * === CGCG + CGLS ===
+ */
+ fiji_update_coarse_grain_clock_gating(adev, enable);
+ fiji_update_medium_grain_clock_gating(adev, enable);
+ }
+ return 0;
+}
+
static int gfx_v8_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ switch (adev->asic_type) {
+ case CHIP_FIJI:
+ fiji_update_gfx_clock_gating(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ break;
+ default:
+ break;
+ }
return 0;
}
@@ -4627,7 +4718,7 @@ static void gfx_v8_0_ring_emit_fence_gfx(struct amdgpu_ring *ring, u64 addr,
EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
EVENT_INDEX(5)));
amdgpu_ring_write(ring, addr & 0xfffffffc);
- amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
+ amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
DATA_SEL(write64bit ? 2 : 1) | INT_SEL(int_sel ? 2 : 0));
amdgpu_ring_write(ring, lower_32_bits(seq));
amdgpu_ring_write(ring, upper_32_bits(seq));
@@ -4995,7 +5086,7 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev,
const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
.early_init = gfx_v8_0_early_init,
- .late_init = NULL,
+ .late_init = gfx_v8_0_late_init,
.sw_init = gfx_v8_0_sw_init,
.sw_fini = gfx_v8_0_sw_fini,
.hw_init = gfx_v8_0_hw_init,
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index ed8abb58a785..3f956065d069 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -370,6 +370,10 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
adev->mc.visible_vram_size = adev->mc.aper_size;
+ /* In case the PCI BAR is larger than the actual amount of vram */
+ if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
+ adev->mc.visible_vram_size = adev->mc.real_vram_size;
+
/* unless the user had overridden it, set the gart
* size equal to the 1024 or vram, whichever is larger.
*/
@@ -1012,7 +1016,6 @@ static int gmc_v7_0_suspend(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
if (adev->vm_manager.enabled) {
- amdgpu_vm_manager_fini(adev);
gmc_v7_0_vm_fini(adev);
adev->vm_manager.enabled = false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index d39028440814..c0c9a0101eb4 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -476,6 +476,10 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
adev->mc.visible_vram_size = adev->mc.aper_size;
+ /* In case the PCI BAR is larger than the actual amount of vram */
+ if (adev->mc.visible_vram_size > adev->mc.real_vram_size)
+ adev->mc.visible_vram_size = adev->mc.real_vram_size;
+
/* unless the user had overridden it, set the gart
* size equal to the 1024 or vram, whichever is larger.
*/
@@ -1033,7 +1037,6 @@ static int gmc_v8_0_suspend(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
if (adev->vm_manager.enabled) {
- amdgpu_vm_manager_fini(adev);
gmc_v8_0_vm_fini(adev);
adev->vm_manager.enabled = false;
}
@@ -1324,9 +1327,181 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev,
return 0;
}
+static void fiji_update_mc_medium_grain_clock_gating(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t data;
+
+ if (enable) {
+ data = RREG32(mmMC_HUB_MISC_HUB_CG);
+ data |= MC_HUB_MISC_HUB_CG__ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_SIP_CG);
+ data |= MC_HUB_MISC_SIP_CG__ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_VM_CG);
+ data |= MC_HUB_MISC_VM_CG__ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+ data = RREG32(mmMC_XPB_CLK_GAT);
+ data |= MC_XPB_CLK_GAT__ENABLE_MASK;
+ WREG32(mmMC_XPB_CLK_GAT, data);
+
+ data = RREG32(mmATC_MISC_CG);
+ data |= ATC_MISC_CG__ENABLE_MASK;
+ WREG32(mmATC_MISC_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_WR_CG);
+ data |= MC_CITF_MISC_WR_CG__ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_RD_CG);
+ data |= MC_CITF_MISC_RD_CG__ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_VM_CG);
+ data |= MC_CITF_MISC_VM_CG__ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+ data = RREG32(mmVM_L2_CG);
+ data |= VM_L2_CG__ENABLE_MASK;
+ WREG32(mmVM_L2_CG, data);
+ } else {
+ data = RREG32(mmMC_HUB_MISC_HUB_CG);
+ data &= ~MC_HUB_MISC_HUB_CG__ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_SIP_CG);
+ data &= ~MC_HUB_MISC_SIP_CG__ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_VM_CG);
+ data &= ~MC_HUB_MISC_VM_CG__ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+ data = RREG32(mmMC_XPB_CLK_GAT);
+ data &= ~MC_XPB_CLK_GAT__ENABLE_MASK;
+ WREG32(mmMC_XPB_CLK_GAT, data);
+
+ data = RREG32(mmATC_MISC_CG);
+ data &= ~ATC_MISC_CG__ENABLE_MASK;
+ WREG32(mmATC_MISC_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_WR_CG);
+ data &= ~MC_CITF_MISC_WR_CG__ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_RD_CG);
+ data &= ~MC_CITF_MISC_RD_CG__ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_VM_CG);
+ data &= ~MC_CITF_MISC_VM_CG__ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+ data = RREG32(mmVM_L2_CG);
+ data &= ~VM_L2_CG__ENABLE_MASK;
+ WREG32(mmVM_L2_CG, data);
+ }
+}
+
+static void fiji_update_mc_light_sleep(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t data;
+
+ if (enable) {
+ data = RREG32(mmMC_HUB_MISC_HUB_CG);
+ data |= MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_SIP_CG);
+ data |= MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_VM_CG);
+ data |= MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+ data = RREG32(mmMC_XPB_CLK_GAT);
+ data |= MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_XPB_CLK_GAT, data);
+
+ data = RREG32(mmATC_MISC_CG);
+ data |= ATC_MISC_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmATC_MISC_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_WR_CG);
+ data |= MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_RD_CG);
+ data |= MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_VM_CG);
+ data |= MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+ data = RREG32(mmVM_L2_CG);
+ data |= VM_L2_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmVM_L2_CG, data);
+ } else {
+ data = RREG32(mmMC_HUB_MISC_HUB_CG);
+ data &= ~MC_HUB_MISC_HUB_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_HUB_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_SIP_CG);
+ data &= ~MC_HUB_MISC_SIP_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_SIP_CG, data);
+
+ data = RREG32(mmMC_HUB_MISC_VM_CG);
+ data &= ~MC_HUB_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_HUB_MISC_VM_CG, data);
+
+ data = RREG32(mmMC_XPB_CLK_GAT);
+ data &= ~MC_XPB_CLK_GAT__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_XPB_CLK_GAT, data);
+
+ data = RREG32(mmATC_MISC_CG);
+ data &= ~ATC_MISC_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmATC_MISC_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_WR_CG);
+ data &= ~MC_CITF_MISC_WR_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_WR_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_RD_CG);
+ data &= ~MC_CITF_MISC_RD_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_RD_CG, data);
+
+ data = RREG32(mmMC_CITF_MISC_VM_CG);
+ data &= ~MC_CITF_MISC_VM_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmMC_CITF_MISC_VM_CG, data);
+
+ data = RREG32(mmVM_L2_CG);
+ data &= ~VM_L2_CG__MEM_LS_ENABLE_MASK;
+ WREG32(mmVM_L2_CG, data);
+ }
+}
+
static int gmc_v8_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ switch (adev->asic_type) {
+ case CHIP_FIJI:
+ fiji_update_mc_medium_grain_clock_gating(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ fiji_update_mc_light_sleep(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ break;
+ default:
+ break;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
index 779532d350ff..679e7394a495 100644
--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
@@ -253,8 +253,14 @@ static void iceland_ih_set_rptr(struct amdgpu_device *adev)
static int iceland_ih_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret;
+
+ ret = amdgpu_irq_add_domain(adev);
+ if (ret)
+ return ret;
iceland_ih_set_interrupt_funcs(adev);
+
return 0;
}
@@ -278,6 +284,7 @@ static int iceland_ih_sw_fini(void *handle)
amdgpu_irq_fini(adev);
amdgpu_ih_ring_fini(adev);
+ amdgpu_irq_remove_domain(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 7253132f04b8..ad54c46751b0 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -727,18 +727,20 @@ static int sdma_v3_0_start(struct amdgpu_device *adev)
{
int r, i;
- if (!adev->firmware.smu_load) {
- r = sdma_v3_0_load_microcode(adev);
- if (r)
- return r;
- } else {
- for (i = 0; i < adev->sdma.num_instances; i++) {
- r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
- (i == 0) ?
- AMDGPU_UCODE_ID_SDMA0 :
- AMDGPU_UCODE_ID_SDMA1);
+ if (!adev->pp_enabled) {
+ if (!adev->firmware.smu_load) {
+ r = sdma_v3_0_load_microcode(adev);
if (r)
- return -EINVAL;
+ return r;
+ } else {
+ for (i = 0; i < adev->sdma.num_instances; i++) {
+ r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+ (i == 0) ?
+ AMDGPU_UCODE_ID_SDMA0 :
+ AMDGPU_UCODE_ID_SDMA1);
+ if (r)
+ return -EINVAL;
+ }
}
}
@@ -1427,9 +1429,114 @@ static int sdma_v3_0_process_illegal_inst_irq(struct amdgpu_device *adev,
return 0;
}
+static void fiji_update_sdma_medium_grain_clock_gating(
+ struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ if (enable) {
+ temp = data = RREG32(mmSDMA0_CLK_CTRL);
+ data &= ~(SDMA0_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK);
+ if (data != temp)
+ WREG32(mmSDMA0_CLK_CTRL, data);
+
+ temp = data = RREG32(mmSDMA1_CLK_CTRL);
+ data &= ~(SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE0_MASK);
+
+ if (data != temp)
+ WREG32(mmSDMA1_CLK_CTRL, data);
+ } else {
+ temp = data = RREG32(mmSDMA0_CLK_CTRL);
+ data |= SDMA0_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+ SDMA0_CLK_CTRL__SOFT_OVERRIDE0_MASK;
+
+ if (data != temp)
+ WREG32(mmSDMA0_CLK_CTRL, data);
+
+ temp = data = RREG32(mmSDMA1_CLK_CTRL);
+ data |= SDMA1_CLK_CTRL__SOFT_OVERRIDE7_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE6_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE5_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE4_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE3_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE2_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE1_MASK |
+ SDMA1_CLK_CTRL__SOFT_OVERRIDE0_MASK;
+
+ if (data != temp)
+ WREG32(mmSDMA1_CLK_CTRL, data);
+ }
+}
+
+static void fiji_update_sdma_medium_grain_light_sleep(
+ struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ if (enable) {
+ temp = data = RREG32(mmSDMA0_POWER_CNTL);
+ data |= SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+ if (temp != data)
+ WREG32(mmSDMA0_POWER_CNTL, data);
+
+ temp = data = RREG32(mmSDMA1_POWER_CNTL);
+ data |= SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+ if (temp != data)
+ WREG32(mmSDMA1_POWER_CNTL, data);
+ } else {
+ temp = data = RREG32(mmSDMA0_POWER_CNTL);
+ data &= ~SDMA0_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+ if (temp != data)
+ WREG32(mmSDMA0_POWER_CNTL, data);
+
+ temp = data = RREG32(mmSDMA1_POWER_CNTL);
+ data &= ~SDMA1_POWER_CNTL__MEM_POWER_OVERRIDE_MASK;
+
+ if (temp != data)
+ WREG32(mmSDMA1_POWER_CNTL, data);
+ }
+}
+
static int sdma_v3_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ switch (adev->asic_type) {
+ case CHIP_FIJI:
+ fiji_update_sdma_medium_grain_clock_gating(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ fiji_update_sdma_medium_grain_light_sleep(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ break;
+ default:
+ break;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c b/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c
index 204903897b4f..f4a1346525fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c
@@ -24,7 +24,7 @@
#include <linux/firmware.h>
#include "drmP.h"
#include "amdgpu.h"
-#include "tonga_smumgr.h"
+#include "tonga_smum.h"
MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
index 743c372837aa..b6f7d7bff929 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
@@ -273,8 +273,14 @@ static void tonga_ih_set_rptr(struct amdgpu_device *adev)
static int tonga_ih_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret;
+
+ ret = amdgpu_irq_add_domain(adev);
+ if (ret)
+ return ret;
tonga_ih_set_interrupt_funcs(adev);
+
return 0;
}
@@ -301,6 +307,7 @@ static int tonga_ih_sw_fini(void *handle)
amdgpu_irq_fini(adev);
amdgpu_ih_ring_fini(adev);
+ amdgpu_irq_add_domain(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ppsmc.h b/drivers/gpu/drm/amd/amdgpu/tonga_ppsmc.h
deleted file mode 100644
index 811781f69482..000000000000
--- a/drivers/gpu/drm/amd/amdgpu/tonga_ppsmc.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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 TONGA_PP_SMC_H
-#define TONGA_PP_SMC_H
-
-#pragma pack(push, 1)
-
-#define PPSMC_SWSTATE_FLAG_DC 0x01
-#define PPSMC_SWSTATE_FLAG_UVD 0x02
-#define PPSMC_SWSTATE_FLAG_VCE 0x04
-#define PPSMC_SWSTATE_FLAG_PCIE_X1 0x08
-
-#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
-#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
-#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
-
-#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
-#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
-#define PPSMC_SYSTEMFLAG_GDDR5 0x04
-
-#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
-
-#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
-#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
-#define PPSMC_SYSTEMFLAG_12CHANNEL 0x40
-
-#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
-#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
-
-#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
-#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
-
-#define PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH 0x10
-#define PPSMC_EXTRAFLAGS_DRIVER_TO_GPIO17 0x20
-#define PPSMC_EXTRAFLAGS_PCC_TO_GPIO17 0x40
-
-#define PPSMC_DPM2FLAGS_TDPCLMP 0x01
-#define PPSMC_DPM2FLAGS_PWRSHFT 0x02
-#define PPSMC_DPM2FLAGS_OCP 0x04
-
-#define PPSMC_DISPLAY_WATERMARK_LOW 0
-#define PPSMC_DISPLAY_WATERMARK_HIGH 1
-
-#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
-#define PPSMC_STATEFLAG_POWERBOOST 0x02
-#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
-#define PPSMC_STATEFLAG_POWERSHIFT 0x08
-#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10
-#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
-#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
-
-#define FDO_MODE_HARDWARE 0
-#define FDO_MODE_PIECE_WISE_LINEAR 1
-
-enum FAN_CONTROL {
- FAN_CONTROL_FUZZY,
- FAN_CONTROL_TABLE
-};
-
-#define PPSMC_Result_OK ((uint16_t)0x01)
-#define PPSMC_Result_NoMore ((uint16_t)0x02)
-#define PPSMC_Result_NotNow ((uint16_t)0x03)
-#define PPSMC_Result_Failed ((uint16_t)0xFF)
-#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE)
-#define PPSMC_Result_UnknownVT ((uint16_t)0xFD)
-
-typedef uint16_t PPSMC_Result;
-
-#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
-
-#define PPSMC_MSG_Halt ((uint16_t)0x10)
-#define PPSMC_MSG_Resume ((uint16_t)0x11)
-#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12)
-#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13)
-#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14)
-#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15)
-#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16)
-#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17)
-#define PPSMC_MSG_LevelUp ((uint16_t)0x18)
-#define PPSMC_MSG_LevelDown ((uint16_t)0x19)
-#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a)
-#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20)
-#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f)
-#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40)
-#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41)
-#define PPSMC_MSG_ForceHigh ((uint16_t)0x42)
-#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43)
-#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51)
-#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52)
-#define PPSMC_MSG_EnableCac ((uint16_t)0x53)
-#define PPSMC_MSG_DisableCac ((uint16_t)0x54)
-#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55)
-#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56)
-#define PPSMC_CACHistoryStart ((uint16_t)0x57)
-#define PPSMC_CACHistoryStop ((uint16_t)0x58)
-#define PPSMC_TDPClampingActive ((uint16_t)0x59)
-#define PPSMC_TDPClampingInactive ((uint16_t)0x5A)
-#define PPSMC_StartFanControl ((uint16_t)0x5B)
-#define PPSMC_StopFanControl ((uint16_t)0x5C)
-#define PPSMC_NoDisplay ((uint16_t)0x5D)
-#define PPSMC_HasDisplay ((uint16_t)0x5E)
-#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60)
-#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61)
-#define PPSMC_MSG_EnableULV ((uint16_t)0x62)
-#define PPSMC_MSG_DisableULV ((uint16_t)0x63)
-#define PPSMC_MSG_EnterULV ((uint16_t)0x64)
-#define PPSMC_MSG_ExitULV ((uint16_t)0x65)
-#define PPSMC_PowerShiftActive ((uint16_t)0x6A)
-#define PPSMC_PowerShiftInactive ((uint16_t)0x6B)
-#define PPSMC_OCPActive ((uint16_t)0x6C)
-#define PPSMC_OCPInactive ((uint16_t)0x6D)
-#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E)
-#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F)
-#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70)
-#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71)
-#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72)
-#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73)
-#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74)
-#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75)
-#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76)
-#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77)
-#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78)
-#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79)
-#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A)
-#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B)
-#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C)
-#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
-#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E)
-#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F)
-#define PPSMC_FlushDataCache ((uint16_t)0x80)
-#define PPSMC_FlushInstrCache ((uint16_t)0x81)
-#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82)
-#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83)
-#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84)
-#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85)
-#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86)
-#define PPSMC_MSG_EnableDTE ((uint16_t)0x87)
-#define PPSMC_MSG_DisableDTE ((uint16_t)0x88)
-#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89)
-#define PPSMC_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A)
-#define PPSMC_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B)
-#define PPSMC_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C)
-#define PPSMC_MSG_ChangeNearTDPLimit ((uint16_t)0x90)
-#define PPSMC_MSG_ChangeSafePowerLimit ((uint16_t)0x91)
-#define PPSMC_MSG_DPMStateSweepStart ((uint16_t)0x92)
-#define PPSMC_MSG_DPMStateSweepStop ((uint16_t)0x93)
-#define PPSMC_MSG_OVRDDisableSCLKDS ((uint16_t)0x94)
-#define PPSMC_MSG_CancelDisableOVRDSCLKDS ((uint16_t)0x95)
-#define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint16_t)0x96)
-#define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint16_t)0x97)
-#define PPSMC_MSG_GPIO17 ((uint16_t)0x98)
-#define PPSMC_MSG_API_SetSvi2Volt_Vddc ((uint16_t)0x99)
-#define PPSMC_MSG_API_SetSvi2Volt_Vddci ((uint16_t)0x9A)
-#define PPSMC_MSG_API_SetSvi2Volt_Mvdd ((uint16_t)0x9B)
-#define PPSMC_MSG_API_GetSvi2Volt_Vddc ((uint16_t)0x9C)
-#define PPSMC_MSG_API_GetSvi2Volt_Vddci ((uint16_t)0x9D)
-#define PPSMC_MSG_API_GetSvi2Volt_Mvdd ((uint16_t)0x9E)
-
-#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
-
-#define PPSMC_MSG_Test ((uint16_t)0x100)
-#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t)0x250)
-#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t)0x251)
-#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t)0x252)
-#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t)0x253)
-#define PPSMC_MSG_LoadUcodes ((uint16_t)0x254)
-
-typedef uint16_t PPSMC_Msg;
-
-#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
-#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
-#define PPSMC_EVENT_STATUS_DC 0x00000004
-#define PPSMC_EVENT_STATUS_GPIO17 0x00000008
-
-#pragma pack(pop)
-
-#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c
index 5421309c1862..361c49a82323 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c
@@ -25,7 +25,7 @@
#include "drmP.h"
#include "amdgpu.h"
#include "tonga_ppsmc.h"
-#include "tonga_smumgr.h"
+#include "tonga_smum.h"
#include "smu_ucode_xfer_vi.h"
#include "amdgpu_ucode.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smumgr.h b/drivers/gpu/drm/amd/amdgpu/tonga_smum.h
index c031ff99fe3e..c031ff99fe3e 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_smumgr.h
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_smum.h
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index 121915bbc3b6..3d5913926436 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -279,6 +279,234 @@ static void uvd_v6_0_mc_resume(struct amdgpu_device *adev)
WREG32(mmUVD_VCPU_CACHE_SIZE2, size);
}
+static void cz_set_uvd_clock_gating_branches(struct amdgpu_device *adev,
+ bool enable)
+{
+ u32 data, data1;
+
+ data = RREG32(mmUVD_CGC_GATE);
+ data1 = RREG32(mmUVD_SUVD_CGC_GATE);
+ if (enable) {
+ data |= UVD_CGC_GATE__SYS_MASK |
+ UVD_CGC_GATE__UDEC_MASK |
+ UVD_CGC_GATE__MPEG2_MASK |
+ UVD_CGC_GATE__RBC_MASK |
+ UVD_CGC_GATE__LMI_MC_MASK |
+ UVD_CGC_GATE__IDCT_MASK |
+ UVD_CGC_GATE__MPRD_MASK |
+ UVD_CGC_GATE__MPC_MASK |
+ UVD_CGC_GATE__LBSI_MASK |
+ UVD_CGC_GATE__LRBBM_MASK |
+ UVD_CGC_GATE__UDEC_RE_MASK |
+ UVD_CGC_GATE__UDEC_CM_MASK |
+ UVD_CGC_GATE__UDEC_IT_MASK |
+ UVD_CGC_GATE__UDEC_DB_MASK |
+ UVD_CGC_GATE__UDEC_MP_MASK |
+ UVD_CGC_GATE__WCB_MASK |
+ UVD_CGC_GATE__VCPU_MASK |
+ UVD_CGC_GATE__SCPU_MASK;
+ data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
+ UVD_SUVD_CGC_GATE__SIT_MASK |
+ UVD_SUVD_CGC_GATE__SMP_MASK |
+ UVD_SUVD_CGC_GATE__SCM_MASK |
+ UVD_SUVD_CGC_GATE__SDB_MASK |
+ UVD_SUVD_CGC_GATE__SRE_H264_MASK |
+ UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
+ UVD_SUVD_CGC_GATE__SIT_H264_MASK |
+ UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
+ UVD_SUVD_CGC_GATE__SCM_H264_MASK |
+ UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
+ UVD_SUVD_CGC_GATE__SDB_H264_MASK |
+ UVD_SUVD_CGC_GATE__SDB_HEVC_MASK;
+ } else {
+ data &= ~(UVD_CGC_GATE__SYS_MASK |
+ UVD_CGC_GATE__UDEC_MASK |
+ UVD_CGC_GATE__MPEG2_MASK |
+ UVD_CGC_GATE__RBC_MASK |
+ UVD_CGC_GATE__LMI_MC_MASK |
+ UVD_CGC_GATE__LMI_UMC_MASK |
+ UVD_CGC_GATE__IDCT_MASK |
+ UVD_CGC_GATE__MPRD_MASK |
+ UVD_CGC_GATE__MPC_MASK |
+ UVD_CGC_GATE__LBSI_MASK |
+ UVD_CGC_GATE__LRBBM_MASK |
+ UVD_CGC_GATE__UDEC_RE_MASK |
+ UVD_CGC_GATE__UDEC_CM_MASK |
+ UVD_CGC_GATE__UDEC_IT_MASK |
+ UVD_CGC_GATE__UDEC_DB_MASK |
+ UVD_CGC_GATE__UDEC_MP_MASK |
+ UVD_CGC_GATE__WCB_MASK |
+ UVD_CGC_GATE__VCPU_MASK |
+ UVD_CGC_GATE__SCPU_MASK);
+ data1 &= ~(UVD_SUVD_CGC_GATE__SRE_MASK |
+ UVD_SUVD_CGC_GATE__SIT_MASK |
+ UVD_SUVD_CGC_GATE__SMP_MASK |
+ UVD_SUVD_CGC_GATE__SCM_MASK |
+ UVD_SUVD_CGC_GATE__SDB_MASK |
+ UVD_SUVD_CGC_GATE__SRE_H264_MASK |
+ UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
+ UVD_SUVD_CGC_GATE__SIT_H264_MASK |
+ UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
+ UVD_SUVD_CGC_GATE__SCM_H264_MASK |
+ UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
+ UVD_SUVD_CGC_GATE__SDB_H264_MASK |
+ UVD_SUVD_CGC_GATE__SDB_HEVC_MASK);
+ }
+ WREG32(mmUVD_CGC_GATE, data);
+ WREG32(mmUVD_SUVD_CGC_GATE, data1);
+}
+
+static void tonga_set_uvd_clock_gating_branches(struct amdgpu_device *adev,
+ bool enable)
+{
+ u32 data, data1;
+
+ data = RREG32(mmUVD_CGC_GATE);
+ data1 = RREG32(mmUVD_SUVD_CGC_GATE);
+ if (enable) {
+ data |= UVD_CGC_GATE__SYS_MASK |
+ UVD_CGC_GATE__UDEC_MASK |
+ UVD_CGC_GATE__MPEG2_MASK |
+ UVD_CGC_GATE__RBC_MASK |
+ UVD_CGC_GATE__LMI_MC_MASK |
+ UVD_CGC_GATE__IDCT_MASK |
+ UVD_CGC_GATE__MPRD_MASK |
+ UVD_CGC_GATE__MPC_MASK |
+ UVD_CGC_GATE__LBSI_MASK |
+ UVD_CGC_GATE__LRBBM_MASK |
+ UVD_CGC_GATE__UDEC_RE_MASK |
+ UVD_CGC_GATE__UDEC_CM_MASK |
+ UVD_CGC_GATE__UDEC_IT_MASK |
+ UVD_CGC_GATE__UDEC_DB_MASK |
+ UVD_CGC_GATE__UDEC_MP_MASK |
+ UVD_CGC_GATE__WCB_MASK |
+ UVD_CGC_GATE__VCPU_MASK |
+ UVD_CGC_GATE__SCPU_MASK;
+ data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
+ UVD_SUVD_CGC_GATE__SIT_MASK |
+ UVD_SUVD_CGC_GATE__SMP_MASK |
+ UVD_SUVD_CGC_GATE__SCM_MASK |
+ UVD_SUVD_CGC_GATE__SDB_MASK;
+ } else {
+ data &= ~(UVD_CGC_GATE__SYS_MASK |
+ UVD_CGC_GATE__UDEC_MASK |
+ UVD_CGC_GATE__MPEG2_MASK |
+ UVD_CGC_GATE__RBC_MASK |
+ UVD_CGC_GATE__LMI_MC_MASK |
+ UVD_CGC_GATE__LMI_UMC_MASK |
+ UVD_CGC_GATE__IDCT_MASK |
+ UVD_CGC_GATE__MPRD_MASK |
+ UVD_CGC_GATE__MPC_MASK |
+ UVD_CGC_GATE__LBSI_MASK |
+ UVD_CGC_GATE__LRBBM_MASK |
+ UVD_CGC_GATE__UDEC_RE_MASK |
+ UVD_CGC_GATE__UDEC_CM_MASK |
+ UVD_CGC_GATE__UDEC_IT_MASK |
+ UVD_CGC_GATE__UDEC_DB_MASK |
+ UVD_CGC_GATE__UDEC_MP_MASK |
+ UVD_CGC_GATE__WCB_MASK |
+ UVD_CGC_GATE__VCPU_MASK |
+ UVD_CGC_GATE__SCPU_MASK);
+ data1 &= ~(UVD_SUVD_CGC_GATE__SRE_MASK |
+ UVD_SUVD_CGC_GATE__SIT_MASK |
+ UVD_SUVD_CGC_GATE__SMP_MASK |
+ UVD_SUVD_CGC_GATE__SCM_MASK |
+ UVD_SUVD_CGC_GATE__SDB_MASK);
+ }
+ WREG32(mmUVD_CGC_GATE, data);
+ WREG32(mmUVD_SUVD_CGC_GATE, data1);
+}
+
+static void uvd_v6_0_set_uvd_dynamic_clock_mode(struct amdgpu_device *adev,
+ bool swmode)
+{
+ u32 data, data1 = 0, data2;
+
+ /* Always un-gate UVD REGS bit */
+ data = RREG32(mmUVD_CGC_GATE);
+ data &= ~(UVD_CGC_GATE__REGS_MASK);
+ WREG32(mmUVD_CGC_GATE, data);
+
+ data = RREG32(mmUVD_CGC_CTRL);
+ data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |
+ UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
+ data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
+ 1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER) |
+ 4 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_OFF_DELAY);
+
+ data2 = RREG32(mmUVD_SUVD_CGC_CTRL);
+ if (swmode) {
+ data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
+ UVD_CGC_CTRL__SYS_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_MODE_MASK |
+ UVD_CGC_CTRL__MPEG2_MODE_MASK |
+ UVD_CGC_CTRL__REGS_MODE_MASK |
+ UVD_CGC_CTRL__RBC_MODE_MASK |
+ UVD_CGC_CTRL__LMI_MC_MODE_MASK |
+ UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
+ UVD_CGC_CTRL__IDCT_MODE_MASK |
+ UVD_CGC_CTRL__MPRD_MODE_MASK |
+ UVD_CGC_CTRL__MPC_MODE_MASK |
+ UVD_CGC_CTRL__LBSI_MODE_MASK |
+ UVD_CGC_CTRL__LRBBM_MODE_MASK |
+ UVD_CGC_CTRL__WCB_MODE_MASK |
+ UVD_CGC_CTRL__VCPU_MODE_MASK |
+ UVD_CGC_CTRL__JPEG_MODE_MASK |
+ UVD_CGC_CTRL__SCPU_MODE_MASK);
+ data1 |= UVD_CGC_CTRL2__DYN_OCLK_RAMP_EN_MASK |
+ UVD_CGC_CTRL2__DYN_RCLK_RAMP_EN_MASK;
+ data1 &= ~UVD_CGC_CTRL2__GATER_DIV_ID_MASK;
+ data1 |= 7 << REG_FIELD_SHIFT(UVD_CGC_CTRL2, GATER_DIV_ID);
+ data2 &= ~(UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);
+ } else {
+ data |= UVD_CGC_CTRL__UDEC_RE_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_CM_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_IT_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_DB_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_MP_MODE_MASK |
+ UVD_CGC_CTRL__SYS_MODE_MASK |
+ UVD_CGC_CTRL__UDEC_MODE_MASK |
+ UVD_CGC_CTRL__MPEG2_MODE_MASK |
+ UVD_CGC_CTRL__REGS_MODE_MASK |
+ UVD_CGC_CTRL__RBC_MODE_MASK |
+ UVD_CGC_CTRL__LMI_MC_MODE_MASK |
+ UVD_CGC_CTRL__LMI_UMC_MODE_MASK |
+ UVD_CGC_CTRL__IDCT_MODE_MASK |
+ UVD_CGC_CTRL__MPRD_MODE_MASK |
+ UVD_CGC_CTRL__MPC_MODE_MASK |
+ UVD_CGC_CTRL__LBSI_MODE_MASK |
+ UVD_CGC_CTRL__LRBBM_MODE_MASK |
+ UVD_CGC_CTRL__WCB_MODE_MASK |
+ UVD_CGC_CTRL__VCPU_MODE_MASK |
+ UVD_CGC_CTRL__SCPU_MODE_MASK;
+ data2 |= UVD_SUVD_CGC_CTRL__SRE_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SIT_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
+ UVD_SUVD_CGC_CTRL__SDB_MODE_MASK;
+ }
+ WREG32(mmUVD_CGC_CTRL, data);
+ WREG32(mmUVD_SUVD_CGC_CTRL, data2);
+
+ data = RREG32_UVD_CTX(ixUVD_CGC_CTRL2);
+ data &= ~(REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_OCLK_RAMP_EN) |
+ REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_RCLK_RAMP_EN) |
+ REG_FIELD_MASK(UVD_CGC_CTRL2, GATER_DIV_ID));
+ data1 &= (REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_OCLK_RAMP_EN) |
+ REG_FIELD_MASK(UVD_CGC_CTRL2, DYN_RCLK_RAMP_EN) |
+ REG_FIELD_MASK(UVD_CGC_CTRL2, GATER_DIV_ID));
+ data |= data1;
+ WREG32_UVD_CTX(ixUVD_CGC_CTRL2, data);
+}
+
/**
* uvd_v6_0_start - start UVD block
*
@@ -303,8 +531,19 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
uvd_v6_0_mc_resume(adev);
- /* disable clock gating */
- WREG32(mmUVD_CGC_GATE, 0);
+ /* Set dynamic clock gating in S/W control mode */
+ if (adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG) {
+ if (adev->flags & AMD_IS_APU)
+ cz_set_uvd_clock_gating_branches(adev, false);
+ else
+ tonga_set_uvd_clock_gating_branches(adev, false);
+ uvd_v6_0_set_uvd_dynamic_clock_mode(adev, true);
+ } else {
+ /* disable clock gating */
+ uint32_t data = RREG32(mmUVD_CGC_CTRL);
+ data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
+ WREG32(mmUVD_CGC_CTRL, data);
+ }
/* disable interupt */
WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1));
@@ -758,6 +997,24 @@ static int uvd_v6_0_process_interrupt(struct amdgpu_device *adev,
static int uvd_v6_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
+
+ if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG))
+ return 0;
+
+ if (enable) {
+ if (adev->flags & AMD_IS_APU)
+ cz_set_uvd_clock_gating_branches(adev, enable);
+ else
+ tonga_set_uvd_clock_gating_branches(adev, enable);
+ uvd_v6_0_set_uvd_dynamic_clock_mode(adev, true);
+ } else {
+ uint32_t data = RREG32(mmUVD_CGC_CTRL);
+ data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
+ WREG32(mmUVD_CGC_CTRL, data);
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 370c6c9d81c2..e99af81e4aec 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -103,6 +103,108 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
WREG32(mmVCE_RB_WPTR2, ring->wptr);
}
+static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
+{
+ u32 tmp, data;
+
+ tmp = data = RREG32(mmVCE_RB_ARB_CTRL);
+ if (override)
+ data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
+ else
+ data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK;
+
+ if (tmp != data)
+ WREG32(mmVCE_RB_ARB_CTRL, data);
+}
+
+static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
+ bool gated)
+{
+ u32 tmp, data;
+ /* Set Override to disable Clock Gating */
+ vce_v3_0_override_vce_clock_gating(adev, true);
+
+ if (!gated) {
+ /* Force CLOCK ON for VCE_CLOCK_GATING_B,
+ * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
+ * VREG can be FORCE ON or set to Dynamic, but can't be OFF
+ */
+ tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
+ data |= 0x1ff;
+ data &= ~0xef0000;
+ if (tmp != data)
+ WREG32(mmVCE_CLOCK_GATING_B, data);
+
+ /* Force CLOCK ON for VCE_UENC_CLOCK_GATING,
+ * {*_FORCE_ON, *_FORCE_OFF} = {1, 0}
+ */
+ tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
+ data |= 0x3ff000;
+ data &= ~0xffc00000;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_CLOCK_GATING, data);
+
+ /* set VCE_UENC_CLOCK_GATING_2 */
+ tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
+ data |= 0x2;
+ data &= ~0x2;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
+
+ /* Force CLOCK ON for VCE_UENC_REG_CLOCK_GATING */
+ tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
+ data |= 0x37f;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
+
+ /* Force VCE_UENC_DMA_DCLK_CTRL Clock ON */
+ tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
+ data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
+ VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
+ VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK |
+ 0x8;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
+ } else {
+ /* Force CLOCK OFF for VCE_CLOCK_GATING_B,
+ * {*, *_FORCE_OFF} = {*, 1}
+ * set VREG to Dynamic, as it can't be OFF
+ */
+ tmp = data = RREG32(mmVCE_CLOCK_GATING_B);
+ data &= ~0x80010;
+ data |= 0xe70008;
+ if (tmp != data)
+ WREG32(mmVCE_CLOCK_GATING_B, data);
+ /* Force CLOCK OFF for VCE_UENC_CLOCK_GATING,
+ * Force ClOCK OFF takes precedent over Force CLOCK ON setting.
+ * {*_FORCE_ON, *_FORCE_OFF} = {*, 1}
+ */
+ tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING);
+ data |= 0xffc00000;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_CLOCK_GATING, data);
+ /* Set VCE_UENC_CLOCK_GATING_2 */
+ tmp = data = RREG32(mmVCE_UENC_CLOCK_GATING_2);
+ data |= 0x10000;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
+ /* Set VCE_UENC_REG_CLOCK_GATING to dynamic */
+ tmp = data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
+ data &= ~0xffc00000;
+ if (tmp != data)
+ WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
+ /* Set VCE_UENC_DMA_DCLK_CTRL CG always in dynamic mode */
+ tmp = data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
+ data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK |
+ VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK |
+ VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK |
+ 0x8);
+ if (tmp != data)
+ WREG32(mmVCE_UENC_DMA_DCLK_CTRL, data);
+ }
+ vce_v3_0_override_vce_clock_gating(adev, false);
+}
+
/**
* vce_v3_0_start - start VCE block
*
@@ -121,7 +223,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
if (adev->vce.harvest_config & (1 << idx))
continue;
- if(idx == 0)
+ if (idx == 0)
WREG32_P(mmGRBM_GFX_INDEX, 0,
~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
else
@@ -174,6 +276,10 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
/* clear BUSY flag */
WREG32_P(mmVCE_STATUS, 0, ~1);
+ /* Set Clock-Gating off */
+ if (adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG)
+ vce_v3_0_set_vce_sw_clock_gating(adev, false);
+
if (r) {
DRM_ERROR("VCE not responding, giving up!!!\n");
mutex_unlock(&adev->grbm_idx_mutex);
@@ -208,14 +314,11 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
{
u32 tmp;
- unsigned ret;
/* Fiji, Stoney are single pipe */
if ((adev->asic_type == CHIP_FIJI) ||
- (adev->asic_type == CHIP_STONEY)){
- ret = AMDGPU_VCE_HARVEST_VCE1;
- return ret;
- }
+ (adev->asic_type == CHIP_STONEY))
+ return AMDGPU_VCE_HARVEST_VCE1;
/* Tonga and CZ are dual or single pipe */
if (adev->flags & AMD_IS_APU)
@@ -229,19 +332,14 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
switch (tmp) {
case 1:
- ret = AMDGPU_VCE_HARVEST_VCE0;
- break;
+ return AMDGPU_VCE_HARVEST_VCE0;
case 2:
- ret = AMDGPU_VCE_HARVEST_VCE1;
- break;
+ return AMDGPU_VCE_HARVEST_VCE1;
case 3:
- ret = AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
- break;
+ return AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
default:
- ret = 0;
+ return 0;
}
-
- return ret;
}
static int vce_v3_0_early_init(void *handle)
@@ -316,28 +414,22 @@ static int vce_v3_0_sw_fini(void *handle)
static int vce_v3_0_hw_init(void *handle)
{
- struct amdgpu_ring *ring;
- int r;
+ int r, i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
r = vce_v3_0_start(adev);
if (r)
return r;
- ring = &adev->vce.ring[0];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
- return r;
- }
+ adev->vce.ring[0].ready = false;
+ adev->vce.ring[1].ready = false;
- ring = &adev->vce.ring[1];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
- return r;
+ for (i = 0; i < 2; i++) {
+ r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+ if (r)
+ return r;
+ else
+ adev->vce.ring[i].ready = true;
}
DRM_INFO("VCE initialized successfully.\n");
@@ -437,17 +529,9 @@ static bool vce_v3_0_is_idle(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
u32 mask = 0;
- int idx;
-
- for (idx = 0; idx < 2; ++idx) {
- if (adev->vce.harvest_config & (1 << idx))
- continue;
- if (idx == 0)
- mask |= SRBM_STATUS2__VCE0_BUSY_MASK;
- else
- mask |= SRBM_STATUS2__VCE1_BUSY_MASK;
- }
+ mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK;
+ mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK;
return !(RREG32(mmSRBM_STATUS2) & mask);
}
@@ -456,23 +540,11 @@ static int vce_v3_0_wait_for_idle(void *handle)
{
unsigned i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- u32 mask = 0;
- int idx;
-
- for (idx = 0; idx < 2; ++idx) {
- if (adev->vce.harvest_config & (1 << idx))
- continue;
-
- if (idx == 0)
- mask |= SRBM_STATUS2__VCE0_BUSY_MASK;
- else
- mask |= SRBM_STATUS2__VCE1_BUSY_MASK;
- }
- for (i = 0; i < adev->usec_timeout; i++) {
- if (!(RREG32(mmSRBM_STATUS2) & mask))
+ for (i = 0; i < adev->usec_timeout; i++)
+ if (vce_v3_0_is_idle(handle))
return 0;
- }
+
return -ETIMEDOUT;
}
@@ -480,17 +552,10 @@ static int vce_v3_0_soft_reset(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
u32 mask = 0;
- int idx;
- for (idx = 0; idx < 2; ++idx) {
- if (adev->vce.harvest_config & (1 << idx))
- continue;
+ mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK;
+ mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK;
- if (idx == 0)
- mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK;
- else
- mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK;
- }
WREG32_P(mmSRBM_SOFT_RESET, mask,
~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK |
SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK));
@@ -592,10 +657,8 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
switch (entry->src_data) {
case 0:
- amdgpu_fence_process(&adev->vce.ring[0]);
- break;
case 1:
- amdgpu_fence_process(&adev->vce.ring[1]);
+ amdgpu_fence_process(&adev->vce.ring[entry->src_data]);
break;
default:
DRM_ERROR("Unhandled interrupt: %d %d\n",
@@ -609,6 +672,47 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
static int vce_v3_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
+ int i;
+
+ if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG))
+ return 0;
+
+ mutex_lock(&adev->grbm_idx_mutex);
+ for (i = 0; i < 2; i++) {
+ /* Program VCE Instance 0 or 1 if not harvested */
+ if (adev->vce.harvest_config & (1 << i))
+ continue;
+
+ if (i == 0)
+ WREG32_P(mmGRBM_GFX_INDEX, 0,
+ ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+ else
+ WREG32_P(mmGRBM_GFX_INDEX,
+ GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
+ ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+
+ if (enable) {
+ /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
+ uint32_t data = RREG32(mmVCE_CLOCK_GATING_A);
+ data &= ~(0xf | 0xff0);
+ data |= ((0x0 << 0) | (0x04 << 4));
+ WREG32(mmVCE_CLOCK_GATING_A, data);
+
+ /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */
+ data = RREG32(mmVCE_UENC_CLOCK_GATING);
+ data &= ~(0xf | 0xff0);
+ data |= ((0x0 << 0) | (0x04 << 4));
+ WREG32(mmVCE_UENC_CLOCK_GATING, data);
+ }
+
+ vce_v3_0_set_vce_sw_clock_gating(adev, enable);
+ }
+
+ WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
+ mutex_unlock(&adev->grbm_idx_mutex);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
index 2adc1c855e85..652e76644c31 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.c
+++ b/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -31,6 +31,7 @@
#include "amdgpu_vce.h"
#include "amdgpu_ucode.h"
#include "atom.h"
+#include "amd_pcie.h"
#include "gmc/gmc_8_1_d.h"
#include "gmc/gmc_8_1_sh_mask.h"
@@ -71,6 +72,7 @@
#include "uvd_v5_0.h"
#include "uvd_v6_0.h"
#include "vce_v3_0.h"
+#include "amdgpu_powerplay.h"
/*
* Indirect registers accessor
@@ -376,6 +378,38 @@ static bool vi_read_disabled_bios(struct amdgpu_device *adev)
WREG32_SMC(ixROM_CNTL, rom_cntl);
return r;
}
+
+static bool vi_read_bios_from_rom(struct amdgpu_device *adev,
+ u8 *bios, u32 length_bytes)
+{
+ u32 *dw_ptr;
+ unsigned long flags;
+ u32 i, length_dw;
+
+ if (bios == NULL)
+ return false;
+ if (length_bytes == 0)
+ return false;
+ /* APU vbios image is part of sbios image */
+ if (adev->flags & AMD_IS_APU)
+ return false;
+
+ dw_ptr = (u32 *)bios;
+ length_dw = ALIGN(length_bytes, 4) / 4;
+ /* take the smc lock since we are using the smc index */
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ /* set rom index to 0 */
+ WREG32(mmSMC_IND_INDEX_0, ixROM_INDEX);
+ WREG32(mmSMC_IND_DATA_0, 0);
+ /* set index to data for continous read */
+ WREG32(mmSMC_IND_INDEX_0, ixROM_DATA);
+ for (i = 0; i < length_dw; i++)
+ dw_ptr[i] = RREG32(mmSMC_IND_DATA_0);
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+ return true;
+}
+
static struct amdgpu_allowed_register_entry tonga_allowed_read_registers[] = {
{mmGB_MACROTILE_MODE7, true},
};
@@ -1019,9 +1053,6 @@ static int vi_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk)
static void vi_pcie_gen3_enable(struct amdgpu_device *adev)
{
- u32 mask;
- int ret;
-
if (pci_is_root_bus(adev->pdev->bus))
return;
@@ -1031,11 +1062,8 @@ static void vi_pcie_gen3_enable(struct amdgpu_device *adev)
if (adev->flags & AMD_IS_APU)
return;
- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
- if (ret != 0)
- return;
-
- if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+ if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+ CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
return;
/* todo */
@@ -1098,7 +1126,7 @@ static const struct amdgpu_ip_block_version topaz_ip_blocks[] =
.major = 7,
.minor = 1,
.rev = 0,
- .funcs = &iceland_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_GFX,
@@ -1145,7 +1173,7 @@ static const struct amdgpu_ip_block_version tonga_ip_blocks[] =
.major = 7,
.minor = 1,
.rev = 0,
- .funcs = &tonga_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1213,7 +1241,7 @@ static const struct amdgpu_ip_block_version fiji_ip_blocks[] =
.major = 7,
.minor = 1,
.rev = 0,
- .funcs = &fiji_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs,
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1281,7 +1309,7 @@ static const struct amdgpu_ip_block_version cz_ip_blocks[] =
.major = 8,
.minor = 0,
.rev = 0,
- .funcs = &cz_dpm_ip_funcs,
+ .funcs = &amdgpu_pp_ip_funcs
},
{
.type = AMD_IP_BLOCK_TYPE_DCE,
@@ -1354,20 +1382,18 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
static uint32_t vi_get_rev_id(struct amdgpu_device *adev)
{
- if (adev->asic_type == CHIP_TOPAZ)
- return (RREG32(mmPCIE_EFUSE4) & PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID_MASK)
- >> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT;
- else if (adev->flags & AMD_IS_APU)
+ if (adev->flags & AMD_IS_APU)
return (RREG32_SMC(ATI_REV_ID_FUSE_MACRO__ADDRESS) & ATI_REV_ID_FUSE_MACRO__MASK)
>> ATI_REV_ID_FUSE_MACRO__SHIFT;
else
- return (RREG32(mmCC_DRM_ID_STRAPS) & CC_DRM_ID_STRAPS__ATI_REV_ID_MASK)
- >> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
+ return (RREG32(mmPCIE_EFUSE4) & PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID_MASK)
+ >> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT;
}
static const struct amdgpu_asic_funcs vi_asic_funcs =
{
.read_disabled_bios = &vi_read_disabled_bios,
+ .read_bios_from_rom = &vi_read_bios_from_rom,
.read_register = &vi_read_register,
.reset = &vi_asic_reset,
.set_vga_state = &vi_vga_set_state,
@@ -1416,7 +1442,8 @@ static int vi_common_early_init(void *handle)
break;
case CHIP_FIJI:
adev->has_uvd = true;
- adev->cg_flags = 0;
+ adev->cg_flags = AMDGPU_CG_SUPPORT_UVD_MGCG |
+ AMDGPU_CG_SUPPORT_VCE_MGCG;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x3c;
break;
@@ -1442,6 +1469,8 @@ static int vi_common_early_init(void *handle)
if (amdgpu_smc_load_fw && smc_enabled)
adev->firmware.smu_load = true;
+ amdgpu_get_pcie_info(adev);
+
return 0;
}
@@ -1515,9 +1544,95 @@ static int vi_common_soft_reset(void *handle)
return 0;
}
+static void fiji_update_bif_medium_grain_light_sleep(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ temp = data = RREG32_PCIE(ixPCIE_CNTL2);
+
+ if (enable)
+ data |= PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
+ PCIE_CNTL2__MST_MEM_LS_EN_MASK |
+ PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK;
+ else
+ data &= ~(PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
+ PCIE_CNTL2__MST_MEM_LS_EN_MASK |
+ PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK);
+
+ if (temp != data)
+ WREG32_PCIE(ixPCIE_CNTL2, data);
+}
+
+static void fiji_update_hdp_medium_grain_clock_gating(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ temp = data = RREG32(mmHDP_HOST_PATH_CNTL);
+
+ if (enable)
+ data &= ~HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK;
+ else
+ data |= HDP_HOST_PATH_CNTL__CLOCK_GATING_DIS_MASK;
+
+ if (temp != data)
+ WREG32(mmHDP_HOST_PATH_CNTL, data);
+}
+
+static void fiji_update_hdp_light_sleep(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ temp = data = RREG32(mmHDP_MEM_POWER_LS);
+
+ if (enable)
+ data |= HDP_MEM_POWER_LS__LS_ENABLE_MASK;
+ else
+ data &= ~HDP_MEM_POWER_LS__LS_ENABLE_MASK;
+
+ if (temp != data)
+ WREG32(mmHDP_MEM_POWER_LS, data);
+}
+
+static void fiji_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev,
+ bool enable)
+{
+ uint32_t temp, data;
+
+ temp = data = RREG32_SMC(ixCGTT_ROM_CLK_CTRL0);
+
+ if (enable)
+ data &= ~(CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
+ CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK);
+ else
+ data |= CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
+ CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK;
+
+ if (temp != data)
+ WREG32_SMC(ixCGTT_ROM_CLK_CTRL0, data);
+}
+
static int vi_common_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ switch (adev->asic_type) {
+ case CHIP_FIJI:
+ fiji_update_bif_medium_grain_light_sleep(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ fiji_update_hdp_medium_grain_clock_gating(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ fiji_update_hdp_light_sleep(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ fiji_update_rom_medium_grain_clock_gating(adev,
+ state == AMD_CG_STATE_GATE ? true : false);
+ break;
+ default:
+ break;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index d321222fd92e..d2b49c026cf6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -558,8 +558,7 @@ static int kfd_ioctl_dbg_address_watch(struct file *filep,
return -EINVAL;
/* this is the actual buffer to work with */
-
- args_buff = memdup_user(args_buff,
+ args_buff = memdup_user(cmd_from_user,
args->buf_size_in_bytes - sizeof(*args));
if (IS_ERR(args_buff))
return PTR_ERR(args_buff);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h b/drivers/gpu/drm/amd/include/amd_acpi.h
index 01a29c3d7011..496360eb3fba 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
+++ b/drivers/gpu/drm/amd/include/amd_acpi.h
@@ -21,14 +21,63 @@
*
*/
-#ifndef AMDGPU_ACPI_H
-#define AMDGPU_ACPI_H
+#ifndef AMD_ACPI_H
+#define AMD_ACPI_H
-struct amdgpu_device;
-struct acpi_bus_event;
+#define ACPI_AC_CLASS "ac_adapter"
-int amdgpu_atif_handler(struct amdgpu_device *adev,
- struct acpi_bus_event *event);
+struct atif_verify_interface {
+ u16 size; /* structure size in bytes (includes size field) */
+ u16 version; /* version */
+ u32 notification_mask; /* supported notifications mask */
+ u32 function_bits; /* supported functions bit vector */
+} __packed;
+
+struct atif_system_params {
+ u16 size; /* structure size in bytes (includes size field) */
+ u32 valid_mask; /* valid flags mask */
+ u32 flags; /* flags */
+ u8 command_code; /* notify command code */
+} __packed;
+
+struct atif_sbios_requests {
+ u16 size; /* structure size in bytes (includes size field) */
+ u32 pending; /* pending sbios requests */
+ u8 panel_exp_mode; /* panel expansion mode */
+ u8 thermal_gfx; /* thermal state: target gfx controller */
+ u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */
+ u8 forced_power_gfx; /* forced power state: target gfx controller */
+ u8 forced_power_state; /* forced power state: state id */
+ u8 system_power_src; /* system power source */
+ u8 backlight_level; /* panel backlight level (0-255) */
+} __packed;
+
+#define ATIF_NOTIFY_MASK 0x3
+#define ATIF_NOTIFY_NONE 0
+#define ATIF_NOTIFY_81 1
+#define ATIF_NOTIFY_N 2
+
+struct atcs_verify_interface {
+ u16 size; /* structure size in bytes (includes size field) */
+ u16 version; /* version */
+ u32 function_bits; /* supported functions bit vector */
+} __packed;
+
+#define ATCS_VALID_FLAGS_MASK 0x3
+
+struct atcs_pref_req_input {
+ u16 size; /* structure size in bytes (includes size field) */
+ u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
+ u16 valid_flags_mask; /* valid flags mask */
+ u16 flags; /* flags */
+ u8 req_type; /* request type */
+ u8 perf_req; /* performance request */
+} __packed;
+
+struct atcs_pref_req_output {
+ u16 size; /* structure size in bytes (includes size field) */
+ u8 ret_val; /* return value */
+} __packed;
/* AMD hw uses four ACPI control methods:
* 1. ATIF
diff --git a/drivers/gpu/drm/amd/include/amd_pcie.h b/drivers/gpu/drm/amd/include/amd_pcie.h
new file mode 100644
index 000000000000..7c2a916c1e63
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/amd_pcie.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 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 __AMD_PCIE_H__
+#define __AMD_PCIE_H__
+
+/* Following flags shows PCIe link speed supported in driver which are decided by chipset and ASIC */
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00010000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00020000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00040000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_MASK 0xFFFF0000
+#define CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT 16
+
+/* Following flags shows PCIe link speed supported by ASIC H/W.*/
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00000001
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00000002
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00000004
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK 0x0000FFFF
+#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_SHIFT 0
+
+/* Following flags shows PCIe lane width switch supported in driver which are decided by chipset and ASIC */
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X1 0x00010000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 0x00020000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 0x00040000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 0x00080000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 0x00100000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 0x00200000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 0x00400000
+#define CAIL_PCIE_LINK_WIDTH_SUPPORT_SHIFT 16
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/amd_pcie_helpers.h b/drivers/gpu/drm/amd/include/amd_pcie_helpers.h
new file mode 100644
index 000000000000..5725bf85eacc
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/amd_pcie_helpers.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015 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 __AMD_PCIE_HELPERS_H__
+#define __AMD_PCIE_HELPERS_H__
+
+#include "amd_pcie.h"
+
+static inline bool is_pcie_gen3_supported(uint32_t pcie_link_speed_cap)
+{
+ if (pcie_link_speed_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+ return true;
+
+ return false;
+}
+
+static inline bool is_pcie_gen2_supported(uint32_t pcie_link_speed_cap)
+{
+ if (pcie_link_speed_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
+ return true;
+
+ return false;
+}
+
+/* Get the new PCIE speed given the ASIC PCIE Cap and the NewState's requested PCIE speed*/
+static inline uint16_t get_pcie_gen_support(uint32_t pcie_link_speed_cap,
+ uint16_t ns_pcie_gen)
+{
+ uint32_t asic_pcie_link_speed_cap = (pcie_link_speed_cap &
+ CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK);
+ uint32_t sys_pcie_link_speed_cap = (pcie_link_speed_cap &
+ CAIL_PCIE_LINK_SPEED_SUPPORT_MASK);
+
+ switch (asic_pcie_link_speed_cap) {
+ case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1:
+ return PP_PCIEGen1;
+
+ case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2:
+ return PP_PCIEGen2;
+
+ case CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3:
+ return PP_PCIEGen3;
+
+ default:
+ if (is_pcie_gen3_supported(sys_pcie_link_speed_cap) &&
+ (ns_pcie_gen == PP_PCIEGen3)) {
+ return PP_PCIEGen3;
+ } else if (is_pcie_gen2_supported(sys_pcie_link_speed_cap) &&
+ ((ns_pcie_gen == PP_PCIEGen3) || (ns_pcie_gen == PP_PCIEGen2))) {
+ return PP_PCIEGen2;
+ }
+ }
+
+ return PP_PCIEGen1;
+}
+
+static inline uint16_t get_pcie_lane_support(uint32_t pcie_lane_width_cap,
+ uint16_t ns_pcie_lanes)
+{
+ int i, j;
+ uint16_t new_pcie_lanes = ns_pcie_lanes;
+ uint16_t pcie_lanes[7] = {1, 2, 4, 8, 12, 16, 32};
+
+ switch (pcie_lane_width_cap) {
+ case 0:
+ printk(KERN_ERR "No valid PCIE lane width reported");
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X1:
+ new_pcie_lanes = 1;
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X2:
+ new_pcie_lanes = 2;
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X4:
+ new_pcie_lanes = 4;
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X8:
+ new_pcie_lanes = 8;
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X12:
+ new_pcie_lanes = 12;
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X16:
+ new_pcie_lanes = 16;
+ break;
+ case CAIL_PCIE_LINK_WIDTH_SUPPORT_X32:
+ new_pcie_lanes = 32;
+ break;
+ default:
+ for (i = 0; i < 7; i++) {
+ if (ns_pcie_lanes == pcie_lanes[i]) {
+ if (pcie_lane_width_cap & (0x10000 << i)) {
+ break;
+ } else {
+ for (j = i - 1; j >= 0; j--) {
+ if (pcie_lane_width_cap & (0x10000 << j)) {
+ new_pcie_lanes = pcie_lanes[j];
+ break;
+ }
+ }
+
+ if (j < 0) {
+ for (j = i + 1; j < 7; j++) {
+ if (pcie_lane_width_cap & (0x10000 << j)) {
+ new_pcie_lanes = pcie_lanes[j];
+ break;
+ }
+ }
+ if (j > 7)
+ printk(KERN_ERR "Cannot find a valid PCIE lane width!");
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return new_pcie_lanes;
+}
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index fe28fb353fab..1195d06f55bc 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -85,6 +85,27 @@ enum amd_powergating_state {
AMD_PG_STATE_UNGATE,
};
+enum amd_pm_state_type {
+ /* not used for dpm */
+ POWER_STATE_TYPE_DEFAULT,
+ POWER_STATE_TYPE_POWERSAVE,
+ /* user selectable states */
+ POWER_STATE_TYPE_BATTERY,
+ POWER_STATE_TYPE_BALANCED,
+ POWER_STATE_TYPE_PERFORMANCE,
+ /* internal states */
+ POWER_STATE_TYPE_INTERNAL_UVD,
+ POWER_STATE_TYPE_INTERNAL_UVD_SD,
+ POWER_STATE_TYPE_INTERNAL_UVD_HD,
+ POWER_STATE_TYPE_INTERNAL_UVD_HD2,
+ POWER_STATE_TYPE_INTERNAL_UVD_MVC,
+ POWER_STATE_TYPE_INTERNAL_BOOT,
+ POWER_STATE_TYPE_INTERNAL_THERMAL,
+ POWER_STATE_TYPE_INTERNAL_ACPI,
+ POWER_STATE_TYPE_INTERNAL_ULV,
+ POWER_STATE_TYPE_INTERNAL_3DPERF,
+};
+
struct amd_ip_funcs {
/* sets up early driver state (pre sw_init), does not configure hw - Optional */
int (*early_init)(void *handle);
diff --git a/drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h
index 92b6ba0047af..293329719bba 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h
@@ -596,6 +596,7 @@
#define mmSWRST_EP_CONTROL_0 0x14ac
#define mmCPM_CONTROL 0x14b8
#define mmGSKT_CONTROL 0x14bf
+#define ixSWRST_COMMAND_1 0x1400103
#define ixLM_CONTROL 0x1400120
#define ixLM_PCIETXMUX0 0x1400121
#define ixLM_PCIETXMUX1 0x1400122
diff --git a/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h
index daf763ba1a8f..a9b6923192ee 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h
@@ -2807,5 +2807,18 @@
#define ixDIDT_DBR_WEIGHT0_3 0x90
#define ixDIDT_DBR_WEIGHT4_7 0x91
#define ixDIDT_DBR_WEIGHT8_11 0x92
+#define mmTD_EDC_CNT 0x252e
+#define mmCPF_EDC_TAG_CNT 0x3188
+#define mmCPF_EDC_ROQ_CNT 0x3189
+#define mmCPF_EDC_ATC_CNT 0x318a
+#define mmCPG_EDC_TAG_CNT 0x318b
+#define mmCPG_EDC_ATC_CNT 0x318c
+#define mmCPG_EDC_DMA_CNT 0x318d
+#define mmCPC_EDC_SCRATCH_CNT 0x318e
+#define mmCPC_EDC_UCODE_CNT 0x318f
+#define mmCPC_EDC_ATC_CNT 0x3190
+#define mmDC_EDC_STATE_CNT 0x3191
+#define mmDC_EDC_CSINVOC_CNT 0x3192
+#define mmDC_EDC_RESTORE_CNT 0x3193
#endif /* GFX_8_0_D_H */
diff --git a/drivers/gpu/drm/amd/include/atombios.h b/drivers/gpu/drm/amd/include/atombios.h
index 552622675ace..eaf451e26643 100644
--- a/drivers/gpu/drm/amd/include/atombios.h
+++ b/drivers/gpu/drm/amd/include/atombios.h
@@ -550,6 +550,13 @@ typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1
//MPLL_CNTL_FLAG_BYPASS_AD_PLL has a wrong name, should be BYPASS_DQ_PLL
#define MPLL_CNTL_FLAG_BYPASS_AD_PLL 0x04
+// use for ComputeMemoryClockParamTable
+typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2
+{
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 ulClock;
+ ULONG ulReserved;
+}COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2;
+
typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
{
ATOM_COMPUTE_CLOCK_FREQ ulClock;
@@ -4988,6 +4995,78 @@ typedef struct _ATOM_ASIC_PROFILING_INFO_V3_3
ULONG ulSDCMargine;
}ATOM_ASIC_PROFILING_INFO_V3_3;
+// for Fiji speed EVV algorithm
+typedef struct _ATOM_ASIC_PROFILING_INFO_V3_4
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ ULONG ulEvvLkgFactor;
+ ULONG ulBoardCoreTemp;
+ ULONG ulMaxVddc;
+ ULONG ulMinVddc;
+ ULONG ulLoadLineSlop;
+ ULONG ulLeakageTemp;
+ ULONG ulLeakageVoltage;
+ EFUSE_LINEAR_FUNC_PARAM sCACm;
+ EFUSE_LINEAR_FUNC_PARAM sCACb;
+ EFUSE_LOGISTIC_FUNC_PARAM sKt_b;
+ EFUSE_LOGISTIC_FUNC_PARAM sKv_m;
+ EFUSE_LOGISTIC_FUNC_PARAM sKv_b;
+ USHORT usLkgEuseIndex;
+ UCHAR ucLkgEfuseBitLSB;
+ UCHAR ucLkgEfuseLength;
+ ULONG ulLkgEncodeLn_MaxDivMin;
+ ULONG ulLkgEncodeMax;
+ ULONG ulLkgEncodeMin;
+ ULONG ulEfuseLogisticAlpha;
+ USHORT usPowerDpm0;
+ USHORT usPowerDpm1;
+ USHORT usPowerDpm2;
+ USHORT usPowerDpm3;
+ USHORT usPowerDpm4;
+ USHORT usPowerDpm5;
+ USHORT usPowerDpm6;
+ USHORT usPowerDpm7;
+ ULONG ulTdpDerateDPM0;
+ ULONG ulTdpDerateDPM1;
+ ULONG ulTdpDerateDPM2;
+ ULONG ulTdpDerateDPM3;
+ ULONG ulTdpDerateDPM4;
+ ULONG ulTdpDerateDPM5;
+ ULONG ulTdpDerateDPM6;
+ ULONG ulTdpDerateDPM7;
+ EFUSE_LINEAR_FUNC_PARAM sRoFuse;
+ ULONG ulEvvDefaultVddc;
+ ULONG ulEvvNoCalcVddc;
+ USHORT usParamNegFlag;
+ USHORT usSpeed_Model;
+ ULONG ulSM_A0;
+ ULONG ulSM_A1;
+ ULONG ulSM_A2;
+ ULONG ulSM_A3;
+ ULONG ulSM_A4;
+ ULONG ulSM_A5;
+ ULONG ulSM_A6;
+ ULONG ulSM_A7;
+ UCHAR ucSM_A0_sign;
+ UCHAR ucSM_A1_sign;
+ UCHAR ucSM_A2_sign;
+ UCHAR ucSM_A3_sign;
+ UCHAR ucSM_A4_sign;
+ UCHAR ucSM_A5_sign;
+ UCHAR ucSM_A6_sign;
+ UCHAR ucSM_A7_sign;
+ ULONG ulMargin_RO_a;
+ ULONG ulMargin_RO_b;
+ ULONG ulMargin_RO_c;
+ ULONG ulMargin_fixed;
+ ULONG ulMargin_Fmax_mean;
+ ULONG ulMargin_plat_mean;
+ ULONG ulMargin_Fmax_sigma;
+ ULONG ulMargin_plat_sigma;
+ ULONG ulMargin_DC_sigma;
+ ULONG ulReserved[8]; // Reserved for future ASIC
+}ATOM_ASIC_PROFILING_INFO_V3_4;
+
typedef struct _ATOM_POWER_SOURCE_OBJECT
{
UCHAR ucPwrSrcId; // Power source
diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h
index 992dcd8a5c6a..713aec954692 100644
--- a/drivers/gpu/drm/amd/include/cgs_common.h
+++ b/drivers/gpu/drm/amd/include/cgs_common.h
@@ -105,6 +105,34 @@ enum cgs_ucode_id {
CGS_UCODE_ID_MAXIMUM,
};
+enum cgs_system_info_id {
+ CGS_SYSTEM_INFO_ADAPTER_BDF_ID = 1,
+ CGS_SYSTEM_INFO_PCIE_GEN_INFO,
+ CGS_SYSTEM_INFO_PCIE_MLW,
+ CGS_SYSTEM_INFO_ID_MAXIMUM,
+};
+
+struct cgs_system_info {
+ uint64_t size;
+ uint64_t info_id;
+ union {
+ void *ptr;
+ uint64_t value;
+ };
+ uint64_t padding[13];
+};
+
+/*
+ * enum cgs_resource_type - GPU resource type
+ */
+enum cgs_resource_type {
+ CGS_RESOURCE_TYPE_MMIO = 0,
+ CGS_RESOURCE_TYPE_FB,
+ CGS_RESOURCE_TYPE_IO,
+ CGS_RESOURCE_TYPE_DOORBELL,
+ CGS_RESOURCE_TYPE_ROM,
+};
+
/**
* struct cgs_clock_limits - Clock limits
*
@@ -127,8 +155,53 @@ struct cgs_firmware_info {
void *kptr;
};
+struct cgs_mode_info {
+ uint32_t refresh_rate;
+ uint32_t ref_clock;
+ uint32_t vblank_time_us;
+};
+
+struct cgs_display_info {
+ uint32_t display_count;
+ uint32_t active_display_mask;
+ struct cgs_mode_info *mode_info;
+};
+
typedef unsigned long cgs_handle_t;
+#define CGS_ACPI_METHOD_ATCS 0x53435441
+#define CGS_ACPI_METHOD_ATIF 0x46495441
+#define CGS_ACPI_METHOD_ATPX 0x58505441
+#define CGS_ACPI_FIELD_METHOD_NAME 0x00000001
+#define CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT 0x00000002
+#define CGS_ACPI_MAX_BUFFER_SIZE 256
+#define CGS_ACPI_TYPE_ANY 0x00
+#define CGS_ACPI_TYPE_INTEGER 0x01
+#define CGS_ACPI_TYPE_STRING 0x02
+#define CGS_ACPI_TYPE_BUFFER 0x03
+#define CGS_ACPI_TYPE_PACKAGE 0x04
+
+struct cgs_acpi_method_argument {
+ uint32_t type;
+ uint32_t method_length;
+ uint32_t data_length;
+ union{
+ uint32_t value;
+ void *pointer;
+ };
+};
+
+struct cgs_acpi_method_info {
+ uint32_t size;
+ uint32_t field;
+ uint32_t input_count;
+ uint32_t name;
+ struct cgs_acpi_method_argument *pinput_argument;
+ uint32_t output_count;
+ struct cgs_acpi_method_argument *poutput_argument;
+ uint32_t padding[9];
+};
+
/**
* cgs_gpu_mem_info() - Return information about memory heaps
* @cgs_device: opaque device handle
@@ -355,6 +428,23 @@ typedef void (*cgs_write_pci_config_word_t)(void *cgs_device, unsigned addr,
typedef void (*cgs_write_pci_config_dword_t)(void *cgs_device, unsigned addr,
uint32_t value);
+
+/**
+ * cgs_get_pci_resource() - provide access to a device resource (PCI BAR)
+ * @cgs_device: opaque device handle
+ * @resource_type: Type of Resource (MMIO, IO, ROM, FB, DOORBELL)
+ * @size: size of the region
+ * @offset: offset from the start of the region
+ * @resource_base: base address (not including offset) returned
+ *
+ * Return: 0 on success, -errno otherwise
+ */
+typedef int (*cgs_get_pci_resource_t)(void *cgs_device,
+ enum cgs_resource_type resource_type,
+ uint64_t size,
+ uint64_t offset,
+ uint64_t *resource_base);
+
/**
* cgs_atom_get_data_table() - Get a pointer to an ATOM BIOS data table
* @cgs_device: opaque device handle
@@ -493,6 +583,21 @@ typedef int(*cgs_set_clockgating_state)(void *cgs_device,
enum amd_ip_block_type block_type,
enum amd_clockgating_state state);
+typedef int(*cgs_get_active_displays_info)(
+ void *cgs_device,
+ struct cgs_display_info *info);
+
+typedef int (*cgs_call_acpi_method)(void *cgs_device,
+ uint32_t acpi_method,
+ uint32_t acpi_function,
+ void *pinput, void *poutput,
+ uint32_t output_count,
+ uint32_t input_size,
+ uint32_t output_size);
+
+typedef int (*cgs_query_system_info)(void *cgs_device,
+ struct cgs_system_info *sys_info);
+
struct cgs_ops {
/* memory management calls (similar to KFD interface) */
cgs_gpu_mem_info_t gpu_mem_info;
@@ -516,6 +621,8 @@ struct cgs_ops {
cgs_write_pci_config_byte_t write_pci_config_byte;
cgs_write_pci_config_word_t write_pci_config_word;
cgs_write_pci_config_dword_t write_pci_config_dword;
+ /* PCI resources */
+ cgs_get_pci_resource_t get_pci_resource;
/* ATOM BIOS */
cgs_atom_get_data_table_t atom_get_data_table;
cgs_atom_get_cmd_table_revs_t atom_get_cmd_table_revs;
@@ -533,7 +640,12 @@ struct cgs_ops {
/* cg pg interface*/
cgs_set_powergating_state set_powergating_state;
cgs_set_clockgating_state set_clockgating_state;
- /* ACPI (TODO) */
+ /* display manager */
+ cgs_get_active_displays_info get_active_displays_info;
+ /* ACPI */
+ cgs_call_acpi_method call_acpi_method;
+ /* get system info */
+ cgs_query_system_info query_system_info;
};
struct cgs_os_ops; /* To be define in OS-specific CGS header */
@@ -620,5 +732,15 @@ struct cgs_device
CGS_CALL(set_powergating_state, dev, block_type, state)
#define cgs_set_clockgating_state(dev, block_type, state) \
CGS_CALL(set_clockgating_state, dev, block_type, state)
+#define cgs_get_active_displays_info(dev, info) \
+ CGS_CALL(get_active_displays_info, dev, info)
+#define cgs_call_acpi_method(dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size) \
+ CGS_CALL(call_acpi_method, dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size)
+#define cgs_query_system_info(dev, sys_info) \
+ CGS_CALL(query_system_info, dev, sys_info)
+#define cgs_get_pci_resource(cgs_device, resource_type, size, offset, \
+ resource_base) \
+ CGS_CALL(get_pci_resource, cgs_device, resource_type, size, offset, \
+ resource_base)
#endif /* _CGS_COMMON_H */
diff --git a/drivers/gpu/drm/amd/powerplay/Kconfig b/drivers/gpu/drm/amd/powerplay/Kconfig
new file mode 100644
index 000000000000..af380335b425
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/Kconfig
@@ -0,0 +1,6 @@
+config DRM_AMD_POWERPLAY
+ bool "Enable AMD powerplay component"
+ depends on DRM_AMDGPU
+ default n
+ help
+ select this option will enable AMD powerplay component.
diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/powerplay/Makefile
new file mode 100644
index 000000000000..e195bf59da86
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/Makefile
@@ -0,0 +1,22 @@
+
+subdir-ccflags-y += -Iinclude/drm \
+ -Idrivers/gpu/drm/amd/powerplay/inc/ \
+ -Idrivers/gpu/drm/amd/include/asic_reg \
+ -Idrivers/gpu/drm/amd/include \
+ -Idrivers/gpu/drm/amd/powerplay/smumgr\
+ -Idrivers/gpu/drm/amd/powerplay/hwmgr \
+ -Idrivers/gpu/drm/amd/powerplay/eventmgr
+
+AMD_PP_PATH = ../powerplay
+
+PP_LIBS = smumgr hwmgr eventmgr
+
+AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix drivers/gpu/drm/amd/powerplay/,$(PP_LIBS)))
+
+include $(AMD_POWERPLAY)
+
+POWER_MGR = amd_powerplay.o
+
+AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_POWER)
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
new file mode 100644
index 000000000000..8f5d5edcf193
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -0,0 +1,660 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include "amd_shared.h"
+#include "amd_powerplay.h"
+#include "pp_instance.h"
+#include "power_state.h"
+#include "eventmanager.h"
+
+#define PP_CHECK(handle) \
+ do { \
+ if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \
+ return -EINVAL; \
+ } while (0)
+
+static int pp_early_init(void *handle)
+{
+ return 0;
+}
+
+static int pp_sw_init(void *handle)
+{
+ struct pp_instance *pp_handle;
+ struct pp_hwmgr *hwmgr;
+ int ret = 0;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+ hwmgr = pp_handle->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->pptable_func == NULL ||
+ hwmgr->hwmgr_func == NULL ||
+ hwmgr->pptable_func->pptable_init == NULL ||
+ hwmgr->hwmgr_func->backend_init == NULL)
+ return -EINVAL;
+
+ ret = hwmgr->pptable_func->pptable_init(hwmgr);
+
+ if (ret == 0)
+ ret = hwmgr->hwmgr_func->backend_init(hwmgr);
+
+ return ret;
+}
+
+static int pp_sw_fini(void *handle)
+{
+ struct pp_instance *pp_handle;
+ struct pp_hwmgr *hwmgr;
+ int ret = 0;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+ hwmgr = pp_handle->hwmgr;
+
+ if (hwmgr != NULL || hwmgr->hwmgr_func != NULL ||
+ hwmgr->hwmgr_func->backend_fini != NULL)
+ ret = hwmgr->hwmgr_func->backend_fini(hwmgr);
+
+ return ret;
+}
+
+static int pp_hw_init(void *handle)
+{
+ struct pp_instance *pp_handle;
+ struct pp_smumgr *smumgr;
+ struct pp_eventmgr *eventmgr;
+ int ret = 0;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+ smumgr = pp_handle->smu_mgr;
+
+ if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
+ smumgr->smumgr_funcs->smu_init == NULL ||
+ smumgr->smumgr_funcs->start_smu == NULL)
+ return -EINVAL;
+
+ ret = smumgr->smumgr_funcs->smu_init(smumgr);
+ if (ret) {
+ printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
+ return ret;
+ }
+
+ ret = smumgr->smumgr_funcs->start_smu(smumgr);
+ if (ret) {
+ printk(KERN_ERR "[ powerplay ] smc start failed\n");
+ smumgr->smumgr_funcs->smu_fini(smumgr);
+ return ret;
+ }
+
+ hw_init_power_state_table(pp_handle->hwmgr);
+ eventmgr = pp_handle->eventmgr;
+
+ if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
+ return -EINVAL;
+
+ ret = eventmgr->pp_eventmgr_init(eventmgr);
+ return 0;
+}
+
+static int pp_hw_fini(void *handle)
+{
+ struct pp_instance *pp_handle;
+ struct pp_smumgr *smumgr;
+ struct pp_eventmgr *eventmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+ eventmgr = pp_handle->eventmgr;
+
+ if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL)
+ eventmgr->pp_eventmgr_fini(eventmgr);
+
+ smumgr = pp_handle->smu_mgr;
+
+ if (smumgr != NULL || smumgr->smumgr_funcs != NULL ||
+ smumgr->smumgr_funcs->smu_fini != NULL)
+ smumgr->smumgr_funcs->smu_fini(smumgr);
+
+ return 0;
+}
+
+static bool pp_is_idle(void *handle)
+{
+ return 0;
+}
+
+static int pp_wait_for_idle(void *handle)
+{
+ return 0;
+}
+
+static int pp_sw_reset(void *handle)
+{
+ return 0;
+}
+
+static void pp_print_status(void *handle)
+{
+
+}
+
+static int pp_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ return 0;
+}
+
+static int pp_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+static int pp_suspend(void *handle)
+{
+ struct pp_instance *pp_handle;
+ struct pp_eventmgr *eventmgr;
+ struct pem_event_data event_data = { {0} };
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+ eventmgr = pp_handle->eventmgr;
+ pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
+ return 0;
+}
+
+static int pp_resume(void *handle)
+{
+ struct pp_instance *pp_handle;
+ struct pp_eventmgr *eventmgr;
+ struct pem_event_data event_data = { {0} };
+ struct pp_smumgr *smumgr;
+ int ret;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+ smumgr = pp_handle->smu_mgr;
+
+ if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
+ smumgr->smumgr_funcs->start_smu == NULL)
+ return -EINVAL;
+
+ ret = smumgr->smumgr_funcs->start_smu(smumgr);
+ if (ret) {
+ printk(KERN_ERR "[ powerplay ] smc start failed\n");
+ smumgr->smumgr_funcs->smu_fini(smumgr);
+ return ret;
+ }
+
+ eventmgr = pp_handle->eventmgr;
+ pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
+
+ return 0;
+}
+
+const struct amd_ip_funcs pp_ip_funcs = {
+ .early_init = pp_early_init,
+ .late_init = NULL,
+ .sw_init = pp_sw_init,
+ .sw_fini = pp_sw_fini,
+ .hw_init = pp_hw_init,
+ .hw_fini = pp_hw_fini,
+ .suspend = pp_suspend,
+ .resume = pp_resume,
+ .is_idle = pp_is_idle,
+ .wait_for_idle = pp_wait_for_idle,
+ .soft_reset = pp_sw_reset,
+ .print_status = pp_print_status,
+ .set_clockgating_state = pp_set_clockgating_state,
+ .set_powergating_state = pp_set_powergating_state,
+};
+
+static int pp_dpm_load_fw(void *handle)
+{
+ return 0;
+}
+
+static int pp_dpm_fw_loading_complete(void *handle)
+{
+ return 0;
+}
+
+static int pp_dpm_force_performance_level(void *handle,
+ enum amd_dpm_forced_level level)
+{
+ struct pp_instance *pp_handle;
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ pp_handle = (struct pp_instance *)handle;
+
+ hwmgr = pp_handle->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->force_dpm_level == NULL)
+ return -EINVAL;
+
+ hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
+
+ return 0;
+}
+
+static enum amd_dpm_forced_level pp_dpm_get_performance_level(
+ void *handle)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ return (((struct pp_instance *)handle)->hwmgr->dpm_level);
+}
+
+static int pp_dpm_get_sclk(void *handle, bool low)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->get_sclk == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
+}
+
+static int pp_dpm_get_mclk(void *handle, bool low)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->get_mclk == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
+}
+
+static int pp_dpm_powergate_vce(void *handle, bool gate)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->powergate_vce == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
+}
+
+static int pp_dpm_powergate_uvd(void *handle, bool gate)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->powergate_uvd == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
+}
+
+static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type state)
+{
+ switch (state) {
+ case POWER_STATE_TYPE_BATTERY:
+ return PP_StateUILabel_Battery;
+ case POWER_STATE_TYPE_BALANCED:
+ return PP_StateUILabel_Balanced;
+ case POWER_STATE_TYPE_PERFORMANCE:
+ return PP_StateUILabel_Performance;
+ default:
+ return PP_StateUILabel_None;
+ }
+}
+
+int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input, void *output)
+{
+ int ret = 0;
+ struct pp_instance *pp_handle;
+ struct pem_event_data data = { {0} };
+
+ pp_handle = (struct pp_instance *)handle;
+
+ if (pp_handle == NULL)
+ return -EINVAL;
+
+ switch (event_id) {
+ case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
+ ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+ break;
+ case AMD_PP_EVENT_ENABLE_USER_STATE:
+ {
+ enum amd_pm_state_type ps;
+
+ if (input == NULL)
+ return -EINVAL;
+ ps = *(unsigned long *)input;
+
+ data.requested_ui_label = power_state_convert(ps);
+ ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
+{
+ struct pp_hwmgr *hwmgr;
+ struct pp_power_state *state;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->current_ps == NULL)
+ return -EINVAL;
+
+ state = hwmgr->current_ps;
+
+ switch (state->classification.ui_label) {
+ case PP_StateUILabel_Battery:
+ return POWER_STATE_TYPE_BATTERY;
+ case PP_StateUILabel_Balanced:
+ return POWER_STATE_TYPE_BALANCED;
+ case PP_StateUILabel_Performance:
+ return POWER_STATE_TYPE_PERFORMANCE;
+ default:
+ return POWER_STATE_TYPE_DEFAULT;
+ }
+}
+
+static void
+pp_debugfs_print_current_performance_level(void *handle,
+ struct seq_file *m)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->print_current_perforce_level == NULL)
+ return;
+
+ hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m);
+}
+
+static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->set_fan_control_mode == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
+}
+
+static int pp_dpm_get_fan_control_mode(void *handle)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->get_fan_control_mode == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
+}
+
+static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->set_fan_speed_percent == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
+}
+
+static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->get_fan_speed_percent == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
+}
+
+static int pp_dpm_get_temperature(void *handle)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
+ hwmgr->hwmgr_func->get_temperature == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->get_temperature(hwmgr);
+}
+
+const struct amd_powerplay_funcs pp_dpm_funcs = {
+ .get_temperature = pp_dpm_get_temperature,
+ .load_firmware = pp_dpm_load_fw,
+ .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
+ .force_performance_level = pp_dpm_force_performance_level,
+ .get_performance_level = pp_dpm_get_performance_level,
+ .get_current_power_state = pp_dpm_get_current_power_state,
+ .get_sclk = pp_dpm_get_sclk,
+ .get_mclk = pp_dpm_get_mclk,
+ .powergate_vce = pp_dpm_powergate_vce,
+ .powergate_uvd = pp_dpm_powergate_uvd,
+ .dispatch_tasks = pp_dpm_dispatch_tasks,
+ .print_current_performance_level = pp_debugfs_print_current_performance_level,
+ .set_fan_control_mode = pp_dpm_set_fan_control_mode,
+ .get_fan_control_mode = pp_dpm_get_fan_control_mode,
+ .set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
+ .get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
+};
+
+static int amd_pp_instance_init(struct amd_pp_init *pp_init,
+ struct amd_powerplay *amd_pp)
+{
+ int ret;
+ struct pp_instance *handle;
+
+ handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
+ if (handle == NULL)
+ return -ENOMEM;
+
+ handle->pp_valid = PP_VALID;
+
+ ret = smum_init(pp_init, handle);
+ if (ret)
+ goto fail_smum;
+
+ ret = hwmgr_init(pp_init, handle);
+ if (ret)
+ goto fail_hwmgr;
+
+ ret = eventmgr_init(handle);
+ if (ret)
+ goto fail_eventmgr;
+
+ amd_pp->pp_handle = handle;
+ return 0;
+
+fail_eventmgr:
+ hwmgr_fini(handle->hwmgr);
+fail_hwmgr:
+ smum_fini(handle->smu_mgr);
+fail_smum:
+ kfree(handle);
+ return ret;
+}
+
+static int amd_pp_instance_fini(void *handle)
+{
+ struct pp_instance *instance = (struct pp_instance *)handle;
+
+ if (instance == NULL)
+ return -EINVAL;
+
+ eventmgr_fini(instance->eventmgr);
+
+ hwmgr_fini(instance->hwmgr);
+
+ smum_fini(instance->smu_mgr);
+
+ kfree(handle);
+ return 0;
+}
+
+int amd_powerplay_init(struct amd_pp_init *pp_init,
+ struct amd_powerplay *amd_pp)
+{
+ int ret;
+
+ if (pp_init == NULL || amd_pp == NULL)
+ return -EINVAL;
+
+ ret = amd_pp_instance_init(pp_init, amd_pp);
+
+ if (ret)
+ return ret;
+
+ amd_pp->ip_funcs = &pp_ip_funcs;
+ amd_pp->pp_funcs = &pp_dpm_funcs;
+
+ return 0;
+}
+
+int amd_powerplay_fini(void *handle)
+{
+ amd_pp_instance_fini(handle);
+
+ return 0;
+}
+
+/* export this function to DAL */
+
+int amd_powerplay_display_configuration_change(void *handle, const void *input)
+{
+ struct pp_hwmgr *hwmgr;
+ const struct amd_pp_display_configuration *display_config = input;
+
+ PP_CHECK((struct pp_instance *)handle);
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ phm_store_dal_configuration_data(hwmgr, display_config);
+
+ return 0;
+}
+
+int amd_powerplay_get_display_power_level(void *handle,
+ struct amd_pp_dal_clock_info *output)
+{
+ struct pp_hwmgr *hwmgr;
+
+ PP_CHECK((struct pp_instance *)handle);
+
+ if (output == NULL)
+ return -EINVAL;
+
+ hwmgr = ((struct pp_instance *)handle)->hwmgr;
+
+ return phm_get_dal_power_level(hwmgr, output);
+}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/Makefile b/drivers/gpu/drm/amd/powerplay/eventmgr/Makefile
new file mode 100644
index 000000000000..7509e3850087
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the 'event manager' sub-component of powerplay.
+# It provides the event management services for the driver.
+
+EVENT_MGR = eventmgr.o eventinit.o eventmanagement.o \
+ eventactionchains.o eventsubchains.o eventtasks.o psm.o
+
+AMD_PP_EVENT = $(addprefix $(AMD_PP_PATH)/eventmgr/,$(EVENT_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_EVENT)
+
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
new file mode 100644
index 000000000000..83be3cf210e0
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmgr.h"
+#include "eventactionchains.h"
+#include "eventsubchains.h"
+
+static const pem_event_action *initialize_event[] = {
+ block_adjust_power_state_tasks,
+ power_budget_tasks,
+ system_config_tasks,
+ setup_asic_tasks,
+ enable_dynamic_state_management_tasks,
+ enable_clock_power_gatings_tasks,
+ get_2d_performance_state_tasks,
+ set_performance_state_tasks,
+ initialize_thermal_controller_tasks,
+ conditionally_force_3d_performance_state_tasks,
+ process_vbios_eventinfo_tasks,
+ broadcast_power_policy_tasks,
+ NULL
+};
+
+const struct action_chain initialize_action_chain = {
+ "Initialize",
+ initialize_event
+};
+
+static const pem_event_action *uninitialize_event[] = {
+ ungate_all_display_phys_tasks,
+ uninitialize_display_phy_access_tasks,
+ disable_gfx_voltage_island_power_gating_tasks,
+ disable_gfx_clock_gating_tasks,
+ set_boot_state_tasks,
+ adjust_power_state_tasks,
+ disable_dynamic_state_management_tasks,
+ disable_clock_power_gatings_tasks,
+ cleanup_asic_tasks,
+ prepare_for_pnp_stop_tasks,
+ NULL
+};
+
+const struct action_chain uninitialize_action_chain = {
+ "Uninitialize",
+ uninitialize_event
+};
+
+static const pem_event_action *power_source_change_event_pp_enabled[] = {
+ set_power_source_tasks,
+ set_power_saving_state_tasks,
+ adjust_power_state_tasks,
+ enable_disable_fps_tasks,
+ set_nbmcu_state_tasks,
+ broadcast_power_policy_tasks,
+ NULL
+};
+
+const struct action_chain power_source_change_action_chain_pp_enabled = {
+ "Power source change - PowerPlay enabled",
+ power_source_change_event_pp_enabled
+};
+
+static const pem_event_action *power_source_change_event_pp_disabled[] = {
+ set_power_source_tasks,
+ set_nbmcu_state_tasks,
+ NULL
+};
+
+const struct action_chain power_source_changes_action_chain_pp_disabled = {
+ "Power source change - PowerPlay disabled",
+ power_source_change_event_pp_disabled
+};
+
+static const pem_event_action *power_source_change_event_hardware_dc[] = {
+ set_power_source_tasks,
+ set_power_saving_state_tasks,
+ adjust_power_state_tasks,
+ enable_disable_fps_tasks,
+ reset_hardware_dc_notification_tasks,
+ set_nbmcu_state_tasks,
+ broadcast_power_policy_tasks,
+ NULL
+};
+
+const struct action_chain power_source_change_action_chain_hardware_dc = {
+ "Power source change - with Hardware DC switching",
+ power_source_change_event_hardware_dc
+};
+
+static const pem_event_action *suspend_event[] = {
+ reset_display_phy_access_tasks,
+ unregister_interrupt_tasks,
+ disable_gfx_voltage_island_power_gating_tasks,
+ disable_gfx_clock_gating_tasks,
+ notify_smu_suspend_tasks,
+ disable_smc_firmware_ctf_tasks,
+ set_boot_state_tasks,
+ adjust_power_state_tasks,
+ disable_fps_tasks,
+ vari_bright_suspend_tasks,
+ reset_fan_speed_to_default_tasks,
+ power_down_asic_tasks,
+ disable_stutter_mode_tasks,
+ set_connected_standby_tasks,
+ block_hw_access_tasks,
+ NULL
+};
+
+const struct action_chain suspend_action_chain = {
+ "Suspend",
+ suspend_event
+};
+
+static const pem_event_action *resume_event[] = {
+ unblock_hw_access_tasks,
+ resume_connected_standby_tasks,
+ notify_smu_resume_tasks,
+ reset_display_configCounter_tasks,
+ update_dal_configuration_tasks,
+ vari_bright_resume_tasks,
+ block_adjust_power_state_tasks,
+ setup_asic_tasks,
+ enable_stutter_mode_tasks, /*must do this in boot state and before SMC is started */
+ enable_dynamic_state_management_tasks,
+ enable_clock_power_gatings_tasks,
+ enable_disable_bapm_tasks,
+ initialize_thermal_controller_tasks,
+ reset_boot_state_tasks,
+ adjust_power_state_tasks,
+ enable_disable_fps_tasks,
+ notify_hw_power_source_tasks,
+ process_vbios_event_info_tasks,
+ enable_gfx_clock_gating_tasks,
+ enable_gfx_voltage_island_power_gating_tasks,
+ reset_clock_gating_tasks,
+ notify_smu_vpu_recovery_end_tasks,
+ disable_vpu_cap_tasks,
+ execute_escape_sequence_tasks,
+ NULL
+};
+
+
+const struct action_chain resume_action_chain = {
+ "resume",
+ resume_event
+};
+
+static const pem_event_action *complete_init_event[] = {
+ adjust_power_state_tasks,
+ enable_gfx_clock_gating_tasks,
+ enable_gfx_voltage_island_power_gating_tasks,
+ notify_power_state_change_tasks,
+ NULL
+};
+
+const struct action_chain complete_init_action_chain = {
+ "complete init",
+ complete_init_event
+};
+
+static const pem_event_action *enable_gfx_clock_gating_event[] = {
+ enable_gfx_clock_gating_tasks,
+ NULL
+};
+
+const struct action_chain enable_gfx_clock_gating_action_chain = {
+ "enable gfx clock gate",
+ enable_gfx_clock_gating_event
+};
+
+static const pem_event_action *disable_gfx_clock_gating_event[] = {
+ disable_gfx_clock_gating_tasks,
+ NULL
+};
+
+const struct action_chain disable_gfx_clock_gating_action_chain = {
+ "disable gfx clock gate",
+ disable_gfx_clock_gating_event
+};
+
+static const pem_event_action *enable_cgpg_event[] = {
+ enable_cgpg_tasks,
+ NULL
+};
+
+const struct action_chain enable_cgpg_action_chain = {
+ "eable cg pg",
+ enable_cgpg_event
+};
+
+static const pem_event_action *disable_cgpg_event[] = {
+ disable_cgpg_tasks,
+ NULL
+};
+
+const struct action_chain disable_cgpg_action_chain = {
+ "disable cg pg",
+ disable_cgpg_event
+};
+
+
+/* Enable user _2d performance and activate */
+
+static const pem_event_action *enable_user_state_event[] = {
+ create_new_user_performance_state_tasks,
+ adjust_power_state_tasks,
+ NULL
+};
+
+const struct action_chain enable_user_state_action_chain = {
+ "Enable user state",
+ enable_user_state_event
+};
+
+static const pem_event_action *enable_user_2d_performance_event[] = {
+ enable_user_2d_performance_tasks,
+ add_user_2d_performance_state_tasks,
+ set_performance_state_tasks,
+ adjust_power_state_tasks,
+ delete_user_2d_performance_state_tasks,
+ NULL
+};
+
+const struct action_chain enable_user_2d_performance_action_chain = {
+ "enable_user_2d_performance_event_activate",
+ enable_user_2d_performance_event
+};
+
+
+static const pem_event_action *disable_user_2d_performance_event[] = {
+ disable_user_2d_performance_tasks,
+ delete_user_2d_performance_state_tasks,
+ NULL
+};
+
+const struct action_chain disable_user_2d_performance_action_chain = {
+ "disable_user_2d_performance_event",
+ disable_user_2d_performance_event
+};
+
+
+static const pem_event_action *display_config_change_event[] = {
+ /* countDisplayConfigurationChangeEventTasks, */
+ unblock_adjust_power_state_tasks,
+ set_cpu_power_state,
+ notify_hw_power_source_tasks,
+ /* updateDALConfigurationTasks,
+ variBrightDisplayConfigurationChangeTasks, */
+ adjust_power_state_tasks,
+ /*enableDisableFPSTasks,
+ setNBMCUStateTasks,
+ notifyPCIEDeviceReadyTasks,*/
+ NULL
+};
+
+const struct action_chain display_config_change_action_chain = {
+ "Display configuration change",
+ display_config_change_event
+};
+
+static const pem_event_action *readjust_power_state_event[] = {
+ adjust_power_state_tasks,
+ NULL
+};
+
+const struct action_chain readjust_power_state_action_chain = {
+ "re-adjust power state",
+ readjust_power_state_event
+};
+
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h
new file mode 100644
index 000000000000..f181e53cdcda
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 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 _EVENT_ACTION_CHAINS_H_
+#define _EVENT_ACTION_CHAINS_H_
+#include "eventmgr.h"
+
+extern const struct action_chain initialize_action_chain;
+
+extern const struct action_chain uninitialize_action_chain;
+
+extern const struct action_chain power_source_change_action_chain_pp_enabled;
+
+extern const struct action_chain power_source_changes_action_chain_pp_disabled;
+
+extern const struct action_chain power_source_change_action_chain_hardware_dc;
+
+extern const struct action_chain suspend_action_chain;
+
+extern const struct action_chain resume_action_chain;
+
+extern const struct action_chain complete_init_action_chain;
+
+extern const struct action_chain enable_gfx_clock_gating_action_chain;
+
+extern const struct action_chain disable_gfx_clock_gating_action_chain;
+
+extern const struct action_chain enable_cgpg_action_chain;
+
+extern const struct action_chain disable_cgpg_action_chain;
+
+extern const struct action_chain enable_user_2d_performance_action_chain;
+
+extern const struct action_chain disable_user_2d_performance_action_chain;
+
+extern const struct action_chain enable_user_state_action_chain;
+
+extern const struct action_chain readjust_power_state_action_chain;
+
+extern const struct action_chain display_config_change_action_chain;
+
+#endif /*_EVENT_ACTION_CHAINS_H_*/
+
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
new file mode 100644
index 000000000000..d5ec8ccbe97d
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmgr.h"
+#include "eventinit.h"
+#include "ppinterrupt.h"
+#include "hardwaremanager.h"
+
+void pem_init_feature_info(struct pp_eventmgr *eventmgr)
+{
+
+ /* PowerPlay info */
+ eventmgr->ui_state_info[PP_PowerSource_AC].default_ui_lable =
+ PP_StateUILabel_Performance;
+
+ eventmgr->ui_state_info[PP_PowerSource_AC].current_ui_label =
+ PP_StateUILabel_Performance;
+
+ eventmgr->ui_state_info[PP_PowerSource_DC].default_ui_lable =
+ PP_StateUILabel_Battery;
+
+ eventmgr->ui_state_info[PP_PowerSource_DC].current_ui_label =
+ PP_StateUILabel_Battery;
+
+ if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_PowerPlaySupport)) {
+ eventmgr->features[PP_Feature_PowerPlay].supported = true;
+ eventmgr->features[PP_Feature_PowerPlay].version = PEM_CURRENT_POWERPLAY_FEATURE_VERSION;
+ eventmgr->features[PP_Feature_PowerPlay].enabled_default = true;
+ eventmgr->features[PP_Feature_PowerPlay].enabled = true;
+ } else {
+ eventmgr->features[PP_Feature_PowerPlay].supported = false;
+ eventmgr->features[PP_Feature_PowerPlay].enabled = false;
+ eventmgr->features[PP_Feature_PowerPlay].enabled_default = false;
+ }
+
+ eventmgr->features[PP_Feature_Force3DClock].supported = true;
+ eventmgr->features[PP_Feature_Force3DClock].enabled = false;
+ eventmgr->features[PP_Feature_Force3DClock].enabled_default = false;
+ eventmgr->features[PP_Feature_Force3DClock].version = 1;
+
+ /* over drive*/
+ eventmgr->features[PP_Feature_User2DPerformance].version = 4;
+ eventmgr->features[PP_Feature_User3DPerformance].version = 4;
+ eventmgr->features[PP_Feature_OverdriveTest].version = 4;
+
+ eventmgr->features[PP_Feature_OverDrive].version = 4;
+ eventmgr->features[PP_Feature_OverDrive].enabled = false;
+ eventmgr->features[PP_Feature_OverDrive].enabled_default = false;
+
+ eventmgr->features[PP_Feature_User2DPerformance].supported = false;
+ eventmgr->features[PP_Feature_User2DPerformance].enabled = false;
+ eventmgr->features[PP_Feature_User2DPerformance].enabled_default = false;
+
+ eventmgr->features[PP_Feature_User3DPerformance].supported = false;
+ eventmgr->features[PP_Feature_User3DPerformance].enabled = false;
+ eventmgr->features[PP_Feature_User3DPerformance].enabled_default = false;
+
+ eventmgr->features[PP_Feature_OverdriveTest].supported = false;
+ eventmgr->features[PP_Feature_OverdriveTest].enabled = false;
+ eventmgr->features[PP_Feature_OverdriveTest].enabled_default = false;
+
+ eventmgr->features[PP_Feature_OverDrive].supported = false;
+
+ eventmgr->features[PP_Feature_PowerBudgetWaiver].enabled_default = false;
+ eventmgr->features[PP_Feature_PowerBudgetWaiver].version = 1;
+ eventmgr->features[PP_Feature_PowerBudgetWaiver].supported = false;
+ eventmgr->features[PP_Feature_PowerBudgetWaiver].enabled = false;
+
+ /* Multi UVD States support */
+ eventmgr->features[PP_Feature_MultiUVDState].supported = false;
+ eventmgr->features[PP_Feature_MultiUVDState].enabled = false;
+ eventmgr->features[PP_Feature_MultiUVDState].enabled_default = false;
+
+ /* Dynamic UVD States support */
+ eventmgr->features[PP_Feature_DynamicUVDState].supported = false;
+ eventmgr->features[PP_Feature_DynamicUVDState].enabled = false;
+ eventmgr->features[PP_Feature_DynamicUVDState].enabled_default = false;
+
+ /* VCE DPM support */
+ eventmgr->features[PP_Feature_VCEDPM].supported = false;
+ eventmgr->features[PP_Feature_VCEDPM].enabled = false;
+ eventmgr->features[PP_Feature_VCEDPM].enabled_default = false;
+
+ /* ACP PowerGating support */
+ eventmgr->features[PP_Feature_ACP_POWERGATING].supported = false;
+ eventmgr->features[PP_Feature_ACP_POWERGATING].enabled = false;
+ eventmgr->features[PP_Feature_ACP_POWERGATING].enabled_default = false;
+
+ /* PPM support */
+ eventmgr->features[PP_Feature_PPM].version = 1;
+ eventmgr->features[PP_Feature_PPM].supported = false;
+ eventmgr->features[PP_Feature_PPM].enabled = false;
+
+ /* FFC support (enables fan and temp settings, Gemini needs temp settings) */
+ if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport) ||
+ phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_GeminiRegulatorFanControlSupport)) {
+ eventmgr->features[PP_Feature_FFC].version = 1;
+ eventmgr->features[PP_Feature_FFC].supported = true;
+ eventmgr->features[PP_Feature_FFC].enabled = true;
+ eventmgr->features[PP_Feature_FFC].enabled_default = true;
+ } else {
+ eventmgr->features[PP_Feature_FFC].supported = false;
+ eventmgr->features[PP_Feature_FFC].enabled = false;
+ eventmgr->features[PP_Feature_FFC].enabled_default = false;
+ }
+
+ eventmgr->features[PP_Feature_VariBright].supported = false;
+ eventmgr->features[PP_Feature_VariBright].enabled = false;
+ eventmgr->features[PP_Feature_VariBright].enabled_default = false;
+
+ eventmgr->features[PP_Feature_BACO].supported = false;
+ eventmgr->features[PP_Feature_BACO].supported = false;
+ eventmgr->features[PP_Feature_BACO].enabled_default = false;
+
+ /* PowerDown feature support */
+ eventmgr->features[PP_Feature_PowerDown].supported = false;
+ eventmgr->features[PP_Feature_PowerDown].enabled = false;
+ eventmgr->features[PP_Feature_PowerDown].enabled_default = false;
+
+ eventmgr->features[PP_Feature_FPS].version = 1;
+ eventmgr->features[PP_Feature_FPS].supported = false;
+ eventmgr->features[PP_Feature_FPS].enabled_default = false;
+ eventmgr->features[PP_Feature_FPS].enabled = false;
+
+ eventmgr->features[PP_Feature_ViPG].version = 1;
+ eventmgr->features[PP_Feature_ViPG].supported = false;
+ eventmgr->features[PP_Feature_ViPG].enabled_default = false;
+ eventmgr->features[PP_Feature_ViPG].enabled = false;
+}
+
+static int thermal_interrupt_callback(void *private_data,
+ unsigned src_id, const uint32_t *iv_entry)
+{
+ /* TO DO hanle PEM_Event_ThermalNotification (struct pp_eventmgr *)private_data*/
+ printk("current thermal is out of range \n");
+ return 0;
+}
+
+int pem_register_interrupts(struct pp_eventmgr *eventmgr)
+{
+ int result = 0;
+ struct pp_interrupt_registration_info info;
+
+ info.call_back = thermal_interrupt_callback;
+ info.context = eventmgr;
+
+ result = phm_register_thermal_interrupt(eventmgr->hwmgr, &info);
+
+ /* TODO:
+ * 2. Register CTF event interrupt
+ * 3. Register for vbios events interrupt
+ * 4. Register External Throttle Interrupt
+ * 5. Register Smc To Host Interrupt
+ * */
+ return result;
+}
+
+
+int pem_unregister_interrupts(struct pp_eventmgr *eventmgr)
+{
+ return 0;
+}
+
+
+void pem_uninit_featureInfo(struct pp_eventmgr *eventmgr)
+{
+ eventmgr->features[PP_Feature_MultiUVDState].supported = false;
+ eventmgr->features[PP_Feature_VariBright].supported = false;
+ eventmgr->features[PP_Feature_PowerBudgetWaiver].supported = false;
+ eventmgr->features[PP_Feature_OverDrive].supported = false;
+ eventmgr->features[PP_Feature_OverdriveTest].supported = false;
+ eventmgr->features[PP_Feature_User3DPerformance].supported = false;
+ eventmgr->features[PP_Feature_User2DPerformance].supported = false;
+ eventmgr->features[PP_Feature_PowerPlay].supported = false;
+ eventmgr->features[PP_Feature_Force3DClock].supported = false;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h b/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h
new file mode 100644
index 000000000000..9ef96aab3f24
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventinit.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 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 _EVENTINIT_H_
+#define _EVENTINIT_H_
+
+#define PEM_CURRENT_POWERPLAY_FEATURE_VERSION 4
+
+void pem_init_feature_info(struct pp_eventmgr *eventmgr);
+void pem_uninit_featureInfo(struct pp_eventmgr *eventmgr);
+int pem_register_interrupts(struct pp_eventmgr *eventmgr);
+int pem_unregister_interrupts(struct pp_eventmgr *eventmgr);
+
+#endif /* _EVENTINIT_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c
new file mode 100644
index 000000000000..1e2ad5603080
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmanagement.h"
+#include "eventmgr.h"
+#include "eventactionchains.h"
+
+int pem_init_event_action_chains(struct pp_eventmgr *eventmgr)
+{
+ int i;
+
+ for (i = 0; i < AMD_PP_EVENT_MAX; i++)
+ eventmgr->event_chain[i] = NULL;
+
+ eventmgr->event_chain[AMD_PP_EVENT_SUSPEND] = pem_get_suspend_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_INITIALIZE] = pem_get_initialize_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_UNINITIALIZE] = pem_get_uninitialize_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_POWER_SOURCE_CHANGE] = pem_get_power_source_change_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_HIBERNATE] = pem_get_hibernate_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_RESUME] = pem_get_resume_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_THERMAL_NOTIFICATION] = pem_get_thermal_notification_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_VBIOS_NOTIFICATION] = pem_get_vbios_notification_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_ENTER_THERMAL_STATE] = pem_get_enter_thermal_state_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_EXIT_THERMAL_STATE] = pem_get_exit_thermal_state_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_ENABLE_POWER_PLAY] = pem_get_enable_powerplay_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_DISABLE_POWER_PLAY] = pem_get_disable_powerplay_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_ENABLE_OVER_DRIVE_TEST] = pem_get_enable_overdrive_test_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_DISABLE_OVER_DRIVE_TEST] = pem_get_disable_overdrive_test_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_ENABLE_GFX_CLOCK_GATING] = pem_get_enable_gfx_clock_gating_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_DISABLE_GFX_CLOCK_GATING] = pem_get_disable_gfx_clock_gating_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_ENABLE_CGPG] = pem_get_enable_cgpg_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_DISABLE_CGPG] = pem_get_disable_cgpg_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_COMPLETE_INIT] = pem_get_complete_init_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_SCREEN_ON] = pem_get_screen_on_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_SCREEN_OFF] = pem_get_screen_off_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_PRE_SUSPEND] = pem_get_pre_suspend_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_PRE_RESUME] = pem_get_pre_resume_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_ENABLE_USER_STATE] = pem_enable_user_state_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_READJUST_POWER_STATE] = pem_readjust_power_state_action_chain(eventmgr);
+ eventmgr->event_chain[AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE] = pem_display_config_change_action_chain(eventmgr);
+ return 0;
+}
+
+int pem_excute_event_chain(struct pp_eventmgr *eventmgr, const struct action_chain *event_chain, struct pem_event_data *event_data)
+{
+ const pem_event_action **paction_chain;
+ const pem_event_action *psub_chain;
+ int tmp_result = 0;
+ int result = 0;
+
+ if (eventmgr == NULL || event_chain == NULL || event_data == NULL)
+ return -EINVAL;
+
+ for (paction_chain = event_chain->action_chain; NULL != *paction_chain; paction_chain++) {
+ if (0 != result)
+ return result;
+
+ for (psub_chain = *paction_chain; NULL != *psub_chain; psub_chain++) {
+ tmp_result = (*psub_chain)(eventmgr, event_data);
+ if (0 == result)
+ result = tmp_result;
+ }
+ }
+
+ return result;
+}
+
+const struct action_chain *pem_get_suspend_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &suspend_action_chain;
+}
+
+const struct action_chain *pem_get_initialize_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &initialize_action_chain;
+}
+
+const struct action_chain *pem_get_uninitialize_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &uninitialize_action_chain;
+}
+
+const struct action_chain *pem_get_power_source_change_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &power_source_change_action_chain_pp_enabled; /* other case base on feature info*/
+}
+
+const struct action_chain *pem_get_resume_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &resume_action_chain;
+}
+
+const struct action_chain *pem_get_hibernate_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_thermal_notification_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_vbios_notification_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_enter_thermal_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_exit_thermal_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_enable_powerplay_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_disable_powerplay_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_enable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_disable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_enable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &enable_gfx_clock_gating_action_chain;
+}
+
+const struct action_chain *pem_get_disable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &disable_gfx_clock_gating_action_chain;
+}
+
+const struct action_chain *pem_get_enable_cgpg_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &enable_cgpg_action_chain;
+}
+
+const struct action_chain *pem_get_disable_cgpg_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &disable_cgpg_action_chain;
+}
+
+const struct action_chain *pem_get_complete_init_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &complete_init_action_chain;
+}
+
+const struct action_chain *pem_get_screen_on_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_screen_off_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_pre_suspend_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_get_pre_resume_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return NULL;
+}
+
+const struct action_chain *pem_enable_user_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &enable_user_state_action_chain;
+}
+
+const struct action_chain *pem_readjust_power_state_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &readjust_power_state_action_chain;
+}
+
+const struct action_chain *pem_display_config_change_action_chain(struct pp_eventmgr *eventmgr)
+{
+ return &display_config_change_action_chain;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h
new file mode 100644
index 000000000000..383d4b295aa9
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmanagement.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 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 _EVENT_MANAGEMENT_H_
+#define _EVENT_MANAGEMENT_H_
+
+#include "eventmgr.h"
+
+int pem_init_event_action_chains(struct pp_eventmgr *eventmgr);
+int pem_excute_event_chain(struct pp_eventmgr *eventmgr, const struct action_chain *event_chain, struct pem_event_data *event_data);
+const struct action_chain *pem_get_suspend_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_initialize_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_uninitialize_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_power_source_change_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_resume_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_hibernate_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_thermal_notification_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_vbios_notification_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enter_thermal_state_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_exit_thermal_state_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_powerplay_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_powerplay_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_overdrive_test_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_gfx_clock_gating_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_enable_cgpg_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_disable_cgpg_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_complete_init_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_screen_on_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_screen_off_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_pre_suspend_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_get_pre_resume_action_chain(struct pp_eventmgr *eventmgr);
+
+extern const struct action_chain *pem_enable_user_state_action_chain(struct pp_eventmgr *eventmgr);
+extern const struct action_chain *pem_readjust_power_state_action_chain(struct pp_eventmgr *eventmgr);
+const struct action_chain *pem_display_config_change_action_chain(struct pp_eventmgr *eventmgr);
+
+
+#endif /* _EVENT_MANAGEMENT_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
new file mode 100644
index 000000000000..52a3efc97f05
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "eventmgr.h"
+#include "hwmgr.h"
+#include "eventinit.h"
+#include "eventmanagement.h"
+
+static int pem_init(struct pp_eventmgr *eventmgr)
+{
+ int result = 0;
+ struct pem_event_data event_data;
+
+ /* Initialize PowerPlay feature info */
+ pem_init_feature_info(eventmgr);
+
+ /* Initialize event action chains */
+ pem_init_event_action_chains(eventmgr);
+
+ /* Call initialization event */
+ result = pem_handle_event(eventmgr, AMD_PP_EVENT_INITIALIZE, &event_data);
+
+ if (0 != result)
+ return result;
+
+ /* Register interrupt callback functions */
+ result = pem_register_interrupts(eventmgr);
+ return 0;
+}
+
+static void pem_fini(struct pp_eventmgr *eventmgr)
+{
+ struct pem_event_data event_data;
+
+ pem_uninit_featureInfo(eventmgr);
+ pem_unregister_interrupts(eventmgr);
+
+ pem_handle_event(eventmgr, AMD_PP_EVENT_UNINITIALIZE, &event_data);
+
+ if (eventmgr != NULL)
+ kfree(eventmgr);
+}
+
+int eventmgr_init(struct pp_instance *handle)
+{
+ int result = 0;
+ struct pp_eventmgr *eventmgr;
+
+ if (handle == NULL)
+ return -EINVAL;
+
+ eventmgr = kzalloc(sizeof(struct pp_eventmgr), GFP_KERNEL);
+ if (eventmgr == NULL)
+ return -ENOMEM;
+
+ eventmgr->hwmgr = handle->hwmgr;
+ handle->eventmgr = eventmgr;
+
+ eventmgr->platform_descriptor = &(eventmgr->hwmgr->platform_descriptor);
+ eventmgr->pp_eventmgr_init = pem_init;
+ eventmgr->pp_eventmgr_fini = pem_fini;
+
+ return result;
+}
+
+int eventmgr_fini(struct pp_eventmgr *eventmgr)
+{
+ kfree(eventmgr);
+ return 0;
+}
+
+static int pem_handle_event_unlocked(struct pp_eventmgr *eventmgr, enum amd_pp_event event, struct pem_event_data *data)
+{
+ if (eventmgr == NULL || event >= AMD_PP_EVENT_MAX || data == NULL)
+ return -EINVAL;
+
+ return pem_excute_event_chain(eventmgr, eventmgr->event_chain[event], data);
+}
+
+int pem_handle_event(struct pp_eventmgr *eventmgr, enum amd_pp_event event, struct pem_event_data *event_data)
+{
+ int r = 0;
+
+ r = pem_handle_event_unlocked(eventmgr, event, event_data);
+
+ return r;
+}
+
+bool pem_is_hw_access_blocked(struct pp_eventmgr *eventmgr)
+{
+ return (eventmgr->block_adjust_power_state || phm_is_hw_access_blocked(eventmgr->hwmgr));
+}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c
new file mode 100644
index 000000000000..9ef2d90e2886
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "eventmgr.h"
+#include "eventsubchains.h"
+#include "eventtasks.h"
+#include "hardwaremanager.h"
+
+const pem_event_action reset_display_phy_access_tasks[] = {
+ pem_task_reset_display_phys_access,
+ NULL
+};
+
+const pem_event_action broadcast_power_policy_tasks[] = {
+ /* PEM_Task_BroadcastPowerPolicyChange, */
+ NULL
+};
+
+const pem_event_action unregister_interrupt_tasks[] = {
+ pem_task_unregister_interrupts,
+ NULL
+};
+
+/* Disable GFX Voltage Islands Power Gating */
+const pem_event_action disable_gfx_voltage_island_powergating_tasks[] = {
+ pem_task_disable_voltage_island_power_gating,
+ NULL
+};
+
+const pem_event_action disable_gfx_clockgating_tasks[] = {
+ pem_task_disable_gfx_clock_gating,
+ NULL
+};
+
+const pem_event_action block_adjust_power_state_tasks[] = {
+ pem_task_block_adjust_power_state,
+ NULL
+};
+
+
+const pem_event_action unblock_adjust_power_state_tasks[] = {
+ pem_task_unblock_adjust_power_state,
+ NULL
+};
+
+const pem_event_action set_performance_state_tasks[] = {
+ pem_task_set_performance_state,
+ NULL
+};
+
+const pem_event_action get_2d_performance_state_tasks[] = {
+ pem_task_get_2D_performance_state_id,
+ NULL
+};
+
+const pem_event_action conditionally_force3D_performance_state_tasks[] = {
+ pem_task_conditionally_force_3d_performance_state,
+ NULL
+};
+
+const pem_event_action process_vbios_eventinfo_tasks[] = {
+ /* PEM_Task_ProcessVbiosEventInfo,*/
+ NULL
+};
+
+const pem_event_action enable_dynamic_state_management_tasks[] = {
+ /* PEM_Task_ResetBAPMPolicyChangedFlag,*/
+ pem_task_get_boot_state_id,
+ pem_task_enable_dynamic_state_management,
+ pem_task_register_interrupts,
+ NULL
+};
+
+const pem_event_action enable_clock_power_gatings_tasks[] = {
+ pem_task_enable_clock_power_gatings_tasks,
+ pem_task_powerdown_uvd_tasks,
+ pem_task_powerdown_vce_tasks,
+ NULL
+};
+
+const pem_event_action setup_asic_tasks[] = {
+ pem_task_setup_asic,
+ NULL
+};
+
+const pem_event_action power_budget_tasks[] = {
+ /* TODO
+ * PEM_Task_PowerBudgetWaiverAvailable,
+ * PEM_Task_PowerBudgetWarningMessage,
+ * PEM_Task_PruneStatesBasedOnPowerBudget,
+ */
+ NULL
+};
+
+const pem_event_action system_config_tasks[] = {
+ /* PEM_Task_PruneStatesBasedOnSystemConfig,*/
+ NULL
+};
+
+
+const pem_event_action conditionally_force_3d_performance_state_tasks[] = {
+ pem_task_conditionally_force_3d_performance_state,
+ NULL
+};
+
+const pem_event_action ungate_all_display_phys_tasks[] = {
+ /* PEM_Task_GetDisplayPhyAccessInfo */
+ NULL
+};
+
+const pem_event_action uninitialize_display_phy_access_tasks[] = {
+ /* PEM_Task_UninitializeDisplayPhysAccess, */
+ NULL
+};
+
+const pem_event_action disable_gfx_voltage_island_power_gating_tasks[] = {
+ /* PEM_Task_DisableVoltageIslandPowerGating, */
+ NULL
+};
+
+const pem_event_action disable_gfx_clock_gating_tasks[] = {
+ pem_task_disable_gfx_clock_gating,
+ NULL
+};
+
+const pem_event_action set_boot_state_tasks[] = {
+ pem_task_get_boot_state_id,
+ pem_task_set_boot_state,
+ NULL
+};
+
+const pem_event_action adjust_power_state_tasks[] = {
+ pem_task_notify_hw_mgr_display_configuration_change,
+ pem_task_adjust_power_state,
+ pem_task_notify_smc_display_config_after_power_state_adjustment,
+ pem_task_update_allowed_performance_levels,
+ /* to do pem_task_Enable_disable_bapm, */
+ NULL
+};
+
+const pem_event_action disable_dynamic_state_management_tasks[] = {
+ pem_task_unregister_interrupts,
+ pem_task_get_boot_state_id,
+ pem_task_disable_dynamic_state_management,
+ NULL
+};
+
+const pem_event_action disable_clock_power_gatings_tasks[] = {
+ pem_task_disable_clock_power_gatings_tasks,
+ NULL
+};
+
+const pem_event_action cleanup_asic_tasks[] = {
+ /* PEM_Task_DisableFPS,*/
+ pem_task_cleanup_asic,
+ NULL
+};
+
+const pem_event_action prepare_for_pnp_stop_tasks[] = {
+ /* PEM_Task_PrepareForPnpStop,*/
+ NULL
+};
+
+const pem_event_action set_power_source_tasks[] = {
+ pem_task_set_power_source,
+ pem_task_notify_hw_of_power_source,
+ NULL
+};
+
+const pem_event_action set_power_saving_state_tasks[] = {
+ pem_task_reset_power_saving_state,
+ pem_task_get_power_saving_state,
+ pem_task_set_power_saving_state,
+ /* PEM_Task_ResetODDCState,
+ * PEM_Task_GetODDCState,
+ * PEM_Task_SetODDCState,*/
+ NULL
+};
+
+const pem_event_action enable_disable_fps_tasks[] = {
+ /* PEM_Task_EnableDisableFPS,*/
+ NULL
+};
+
+const pem_event_action set_nbmcu_state_tasks[] = {
+ /* PEM_Task_NBMCUStateChange,*/
+ NULL
+};
+
+const pem_event_action reset_hardware_dc_notification_tasks[] = {
+ /* PEM_Task_ResetHardwareDCNotification,*/
+ NULL
+};
+
+
+const pem_event_action notify_smu_suspend_tasks[] = {
+ /* PEM_Task_NotifySMUSuspend,*/
+ NULL
+};
+
+const pem_event_action disable_smc_firmware_ctf_tasks[] = {
+ /* PEM_Task_DisableSMCFirmwareCTF,*/
+ NULL
+};
+
+const pem_event_action disable_fps_tasks[] = {
+ /* PEM_Task_DisableFPS,*/
+ NULL
+};
+
+const pem_event_action vari_bright_suspend_tasks[] = {
+ /* PEM_Task_VariBright_Suspend,*/
+ NULL
+};
+
+const pem_event_action reset_fan_speed_to_default_tasks[] = {
+ /* PEM_Task_ResetFanSpeedToDefault,*/
+ NULL
+};
+
+const pem_event_action power_down_asic_tasks[] = {
+ /* PEM_Task_DisableFPS,*/
+ pem_task_power_down_asic,
+ NULL
+};
+
+const pem_event_action disable_stutter_mode_tasks[] = {
+ /* PEM_Task_DisableStutterMode,*/
+ NULL
+};
+
+const pem_event_action set_connected_standby_tasks[] = {
+ /* PEM_Task_SetConnectedStandby,*/
+ NULL
+};
+
+const pem_event_action block_hw_access_tasks[] = {
+ pem_task_block_hw_access,
+ NULL
+};
+
+const pem_event_action unblock_hw_access_tasks[] = {
+ pem_task_un_block_hw_access,
+ NULL
+};
+
+const pem_event_action resume_connected_standby_tasks[] = {
+ /* PEM_Task_ResumeConnectedStandby,*/
+ NULL
+};
+
+const pem_event_action notify_smu_resume_tasks[] = {
+ /* PEM_Task_NotifySMUResume,*/
+ NULL
+};
+
+const pem_event_action reset_display_configCounter_tasks[] = {
+ pem_task_reset_display_phys_access,
+ NULL
+};
+
+const pem_event_action update_dal_configuration_tasks[] = {
+ /* PEM_Task_CheckVBlankTime,*/
+ NULL
+};
+
+const pem_event_action vari_bright_resume_tasks[] = {
+ /* PEM_Task_VariBright_Resume,*/
+ NULL
+};
+
+const pem_event_action notify_hw_power_source_tasks[] = {
+ pem_task_notify_hw_of_power_source,
+ NULL
+};
+
+const pem_event_action process_vbios_event_info_tasks[] = {
+ /* PEM_Task_ProcessVbiosEventInfo,*/
+ NULL
+};
+
+const pem_event_action enable_gfx_clock_gating_tasks[] = {
+ pem_task_enable_gfx_clock_gating,
+ NULL
+};
+
+const pem_event_action enable_gfx_voltage_island_power_gating_tasks[] = {
+ pem_task_enable_voltage_island_power_gating,
+ NULL
+};
+
+const pem_event_action reset_clock_gating_tasks[] = {
+ /* PEM_Task_ResetClockGating*/
+ NULL
+};
+
+const pem_event_action notify_smu_vpu_recovery_end_tasks[] = {
+ /* PEM_Task_NotifySmuVPURecoveryEnd,*/
+ NULL
+};
+
+const pem_event_action disable_vpu_cap_tasks[] = {
+ /* PEM_Task_DisableVPUCap,*/
+ NULL
+};
+
+const pem_event_action execute_escape_sequence_tasks[] = {
+ /* PEM_Task_ExecuteEscapesequence,*/
+ NULL
+};
+
+const pem_event_action notify_power_state_change_tasks[] = {
+ pem_task_notify_power_state_change,
+ NULL
+};
+
+const pem_event_action enable_cgpg_tasks[] = {
+ pem_task_enable_cgpg,
+ NULL
+};
+
+const pem_event_action disable_cgpg_tasks[] = {
+ pem_task_disable_cgpg,
+ NULL
+};
+
+const pem_event_action enable_user_2d_performance_tasks[] = {
+ /* PEM_Task_SetUser2DPerformanceFlag,*/
+ /* PEM_Task_UpdateUser2DPerformanceEnableEvents,*/
+ NULL
+};
+
+const pem_event_action add_user_2d_performance_state_tasks[] = {
+ /* PEM_Task_Get2DPerformanceTemplate,*/
+ /* PEM_Task_AllocateNewPowerStateMemory,*/
+ /* PEM_Task_CopyNewPowerStateInfo,*/
+ /* PEM_Task_UpdateNewPowerStateClocks,*/
+ /* PEM_Task_UpdateNewPowerStateUser2DPerformanceFlag,*/
+ /* PEM_Task_AddPowerState,*/
+ /* PEM_Task_ReleaseNewPowerStateMemory,*/
+ NULL
+};
+
+const pem_event_action delete_user_2d_performance_state_tasks[] = {
+ /* PEM_Task_GetCurrentUser2DPerformanceStateID,*/
+ /* PEM_Task_DeletePowerState,*/
+ /* PEM_Task_SetCurrentUser2DPerformanceStateID,*/
+ NULL
+};
+
+const pem_event_action disable_user_2d_performance_tasks[] = {
+ /* PEM_Task_ResetUser2DPerformanceFlag,*/
+ /* PEM_Task_UpdateUser2DPerformanceDisableEvents,*/
+ NULL
+};
+
+const pem_event_action enable_stutter_mode_tasks[] = {
+ pem_task_enable_stutter_mode,
+ NULL
+};
+
+const pem_event_action enable_disable_bapm_tasks[] = {
+ /*PEM_Task_EnableDisableBAPM,*/
+ NULL
+};
+
+const pem_event_action reset_boot_state_tasks[] = {
+ pem_task_reset_boot_state,
+ NULL
+};
+
+const pem_event_action create_new_user_performance_state_tasks[] = {
+ pem_task_create_user_performance_state,
+ NULL
+};
+
+const pem_event_action initialize_thermal_controller_tasks[] = {
+ pem_task_initialize_thermal_controller,
+ NULL
+};
+
+const pem_event_action uninitialize_thermal_controller_tasks[] = {
+ pem_task_uninitialize_thermal_controller,
+ NULL
+};
+
+const pem_event_action set_cpu_power_state[] = {
+ pem_task_set_cpu_power_state,
+ NULL
+}; \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h b/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h
new file mode 100644
index 000000000000..7714cb927428
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventsubchains.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 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 _EVENT_SUB_CHAINS_H_
+#define _EVENT_SUB_CHAINS_H_
+
+#include "eventmgr.h"
+
+extern const pem_event_action reset_display_phy_access_tasks[];
+extern const pem_event_action broadcast_power_policy_tasks[];
+extern const pem_event_action unregister_interrupt_tasks[];
+extern const pem_event_action disable_GFX_voltage_island_powergating_tasks[];
+extern const pem_event_action disable_GFX_clockgating_tasks[];
+extern const pem_event_action block_adjust_power_state_tasks[];
+extern const pem_event_action unblock_adjust_power_state_tasks[];
+extern const pem_event_action set_performance_state_tasks[];
+extern const pem_event_action get_2D_performance_state_tasks[];
+extern const pem_event_action conditionally_force3D_performance_state_tasks[];
+extern const pem_event_action process_vbios_eventinfo_tasks[];
+extern const pem_event_action enable_dynamic_state_management_tasks[];
+extern const pem_event_action enable_clock_power_gatings_tasks[];
+extern const pem_event_action conditionally_force3D_performance_state_tasks[];
+extern const pem_event_action setup_asic_tasks[];
+extern const pem_event_action power_budget_tasks[];
+extern const pem_event_action system_config_tasks[];
+extern const pem_event_action get_2d_performance_state_tasks[];
+extern const pem_event_action conditionally_force_3d_performance_state_tasks[];
+extern const pem_event_action ungate_all_display_phys_tasks[];
+extern const pem_event_action uninitialize_display_phy_access_tasks[];
+extern const pem_event_action disable_gfx_voltage_island_power_gating_tasks[];
+extern const pem_event_action disable_gfx_clock_gating_tasks[];
+extern const pem_event_action set_boot_state_tasks[];
+extern const pem_event_action adjust_power_state_tasks[];
+extern const pem_event_action disable_dynamic_state_management_tasks[];
+extern const pem_event_action disable_clock_power_gatings_tasks[];
+extern const pem_event_action cleanup_asic_tasks[];
+extern const pem_event_action prepare_for_pnp_stop_tasks[];
+extern const pem_event_action set_power_source_tasks[];
+extern const pem_event_action set_power_saving_state_tasks[];
+extern const pem_event_action enable_disable_fps_tasks[];
+extern const pem_event_action set_nbmcu_state_tasks[];
+extern const pem_event_action reset_hardware_dc_notification_tasks[];
+extern const pem_event_action notify_smu_suspend_tasks[];
+extern const pem_event_action disable_smc_firmware_ctf_tasks[];
+extern const pem_event_action disable_fps_tasks[];
+extern const pem_event_action vari_bright_suspend_tasks[];
+extern const pem_event_action reset_fan_speed_to_default_tasks[];
+extern const pem_event_action power_down_asic_tasks[];
+extern const pem_event_action disable_stutter_mode_tasks[];
+extern const pem_event_action set_connected_standby_tasks[];
+extern const pem_event_action block_hw_access_tasks[];
+extern const pem_event_action unblock_hw_access_tasks[];
+extern const pem_event_action resume_connected_standby_tasks[];
+extern const pem_event_action notify_smu_resume_tasks[];
+extern const pem_event_action reset_display_configCounter_tasks[];
+extern const pem_event_action update_dal_configuration_tasks[];
+extern const pem_event_action vari_bright_resume_tasks[];
+extern const pem_event_action notify_hw_power_source_tasks[];
+extern const pem_event_action process_vbios_event_info_tasks[];
+extern const pem_event_action enable_gfx_clock_gating_tasks[];
+extern const pem_event_action enable_gfx_voltage_island_power_gating_tasks[];
+extern const pem_event_action reset_clock_gating_tasks[];
+extern const pem_event_action notify_smu_vpu_recovery_end_tasks[];
+extern const pem_event_action disable_vpu_cap_tasks[];
+extern const pem_event_action execute_escape_sequence_tasks[];
+extern const pem_event_action notify_power_state_change_tasks[];
+extern const pem_event_action enable_cgpg_tasks[];
+extern const pem_event_action disable_cgpg_tasks[];
+extern const pem_event_action enable_user_2d_performance_tasks[];
+extern const pem_event_action add_user_2d_performance_state_tasks[];
+extern const pem_event_action delete_user_2d_performance_state_tasks[];
+extern const pem_event_action disable_user_2d_performance_tasks[];
+extern const pem_event_action enable_stutter_mode_tasks[];
+extern const pem_event_action enable_disable_bapm_tasks[];
+extern const pem_event_action reset_boot_state_tasks[];
+extern const pem_event_action create_new_user_performance_state_tasks[];
+extern const pem_event_action initialize_thermal_controller_tasks[];
+extern const pem_event_action uninitialize_thermal_controller_tasks[];
+extern const pem_event_action set_cpu_power_state[];
+#endif /* _EVENT_SUB_CHAINS_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c b/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
new file mode 100644
index 000000000000..5cd123472db4
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "eventmgr.h"
+#include "eventinit.h"
+#include "eventmanagement.h"
+#include "eventmanager.h"
+#include "hardwaremanager.h"
+#include "eventtasks.h"
+#include "power_state.h"
+#include "hwmgr.h"
+#include "amd_powerplay.h"
+#include "psm.h"
+
+#define TEMP_RANGE_MIN (90 * 1000)
+#define TEMP_RANGE_MAX (120 * 1000)
+
+int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+
+ if (pem_is_hw_access_blocked(eventmgr))
+ return 0;
+
+ phm_force_dpm_levels(eventmgr->hwmgr, AMD_DPM_FORCED_LEVEL_AUTO);
+
+ return 0;
+}
+
+/* eventtasks_generic.c */
+int pem_task_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if (pem_is_hw_access_blocked(eventmgr))
+ return 0;
+
+ hwmgr = eventmgr->hwmgr;
+ if (event_data->pnew_power_state != NULL)
+ hwmgr->request_ps = event_data->pnew_power_state;
+
+ if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
+ psm_adjust_power_state_dynamic(eventmgr, event_data->skip_state_adjust_rules);
+ else
+ psm_adjust_power_state_static(eventmgr, event_data->skip_state_adjust_rules);
+
+ return 0;
+}
+
+int pem_task_power_down_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_power_down_asic(eventmgr->hwmgr);
+}
+
+int pem_task_set_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ if (pem_is_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID))
+ return psm_set_states(eventmgr, &(event_data->requested_state_id));
+
+ return 0;
+}
+
+int pem_task_reset_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_update_new_power_state_clocks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_system_shutdown(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_register_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_unregister_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return pem_unregister_interrupts(eventmgr);
+}
+
+int pem_task_get_boot_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ int result;
+
+ result = psm_get_state_by_classification(eventmgr,
+ PP_StateClassificationFlag_Boot,
+ &(event_data->requested_state_id)
+ );
+
+ if (0 == result)
+ pem_set_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+ else
+ pem_unset_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+
+ return result;
+}
+
+int pem_task_enable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_enable_dynamic_state_management(eventmgr->hwmgr);
+}
+
+int pem_task_disable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_enable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_enable_clock_power_gatings(eventmgr->hwmgr);
+}
+
+int pem_task_powerdown_uvd_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_powerdown_uvd(eventmgr->hwmgr);
+}
+
+int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ phm_powergate_uvd(eventmgr->hwmgr, true);
+ phm_powergate_vce(eventmgr->hwmgr, true);
+ return 0;
+}
+
+int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_start_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_stop_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_setup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_setup_asic(eventmgr->hwmgr);
+}
+
+int pem_task_cleanup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_store_dal_configuration(struct pp_eventmgr *eventmgr, const struct amd_display_configuration *display_config)
+{
+ /* TODO */
+ return 0;
+ /*phm_store_dal_configuration_data(eventmgr->hwmgr, display_config) */
+}
+
+int pem_task_notify_hw_mgr_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ if (pem_is_hw_access_blocked(eventmgr))
+ return 0;
+
+ return phm_display_configuration_changed(eventmgr->hwmgr);
+}
+
+int pem_task_notify_hw_mgr_pre_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return 0;
+}
+
+int pem_task_notify_smc_display_config_after_power_state_adjustment(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ if (pem_is_hw_access_blocked(eventmgr))
+ return 0;
+
+ return phm_notify_smc_display_config_after_ps_adjustment(eventmgr->hwmgr);
+}
+
+int pem_task_block_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ eventmgr->block_adjust_power_state = true;
+ /* to do PHM_ResetIPSCounter(pEventMgr->pHwMgr);*/
+ return 0;
+}
+
+int pem_task_unblock_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ eventmgr->block_adjust_power_state = false;
+ return 0;
+}
+
+int pem_task_notify_power_state_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_un_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_reset_display_phys_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_set_cpu_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_set_cpu_power_state(eventmgr->hwmgr);
+}
+
+/*powersaving*/
+
+int pem_task_set_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_notify_hw_of_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_get_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_reset_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_set_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_set_screen_state_on(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_set_screen_state_off(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_enable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_disable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_enable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_disable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_enable_clock_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+
+int pem_task_enable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_disable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+
+/* performance */
+int pem_task_set_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ if (pem_is_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID))
+ return psm_set_states(eventmgr, &(event_data->requested_state_id));
+
+ return 0;
+}
+
+int pem_task_conditionally_force_3d_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_enable_stutter_mode(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ /* TODO */
+ return 0;
+}
+
+int pem_task_get_2D_performance_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ int result;
+
+ if (eventmgr->features[PP_Feature_PowerPlay].supported &&
+ !(eventmgr->features[PP_Feature_PowerPlay].enabled))
+ result = psm_get_state_by_classification(eventmgr,
+ PP_StateClassificationFlag_Boot,
+ &(event_data->requested_state_id));
+ else if (eventmgr->features[PP_Feature_User2DPerformance].enabled)
+ result = psm_get_state_by_classification(eventmgr,
+ PP_StateClassificationFlag_User2DPerformance,
+ &(event_data->requested_state_id));
+ else
+ result = psm_get_ui_state(eventmgr, PP_StateUILabel_Performance,
+ &(event_data->requested_state_id));
+
+ if (0 == result)
+ pem_set_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+ else
+ pem_unset_event_data_valid(event_data->valid_fields, PEM_EventDataValid_RequestedStateID);
+
+ return result;
+}
+
+int pem_task_create_user_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ struct pp_power_state *state;
+ int table_entries;
+ struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+ int i;
+
+ table_entries = hwmgr->num_ps;
+ state = hwmgr->ps;
+
+restart_search:
+ for (i = 0; i < table_entries; i++) {
+ if (state->classification.ui_label & event_data->requested_ui_label) {
+ event_data->pnew_power_state = state;
+ return 0;
+ }
+ state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+ }
+
+ switch (event_data->requested_ui_label) {
+ case PP_StateUILabel_Battery:
+ case PP_StateUILabel_Balanced:
+ event_data->requested_ui_label = PP_StateUILabel_Performance;
+ goto restart_search;
+ default:
+ break;
+ }
+ return -1;
+}
+
+int pem_task_initialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ struct PP_TemperatureRange range;
+
+ range.max = TEMP_RANGE_MAX;
+ range.min = TEMP_RANGE_MIN;
+
+ if (eventmgr == NULL || eventmgr->platform_descriptor == NULL)
+ return -EINVAL;
+
+ if (phm_cap_enabled(eventmgr->platform_descriptor->platformCaps, PHM_PlatformCaps_ThermalController))
+ return phm_start_thermal_controller(eventmgr->hwmgr, &range);
+
+ return 0;
+}
+
+int pem_task_uninitialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
+{
+ return phm_stop_thermal_controller(eventmgr->hwmgr);
+}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h b/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h
new file mode 100644
index 000000000000..6c6297e3b598
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 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 _EVENT_TASKS_H_
+#define _EVENT_TASKS_H_
+#include "eventmgr.h"
+
+struct amd_display_configuration;
+
+/* eventtasks_generic.c */
+int pem_task_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_power_down_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_get_boot_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_reset_boot_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_update_new_power_state_clocks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_system_shutdown(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_register_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_unregister_interrupts(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_dynamic_state_management(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_powerdown_uvd_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_start_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_stop_asic_block_usage(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_setup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_cleanup_asic(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_store_dal_configuration (struct pp_eventmgr *eventmgr, const struct amd_display_configuration *display_config);
+int pem_task_notify_hw_mgr_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_hw_mgr_pre_display_configuration_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_block_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_unblock_adjust_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_power_state_change(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_un_block_hw_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_reset_display_phys_access(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_cpu_power_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_smc_display_config_after_power_state_adjustment(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+/*powersaving*/
+
+int pem_task_set_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_notify_hw_of_power_source(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_get_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_reset_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_power_saving_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_screen_state_on(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_set_screen_state_off(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_voltage_island_power_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_cgpg(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_disable_gfx_clock_gating(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_enable_stutter_mode(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+
+/* performance */
+int pem_task_set_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_conditionally_force_3d_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_get_2D_performance_state_id(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_create_user_performance_state(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_update_allowed_performance_levels(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+/*thermal */
+int pem_task_initialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+int pem_task_uninitialize_thermal_controller(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data);
+
+#endif /* _EVENT_TASKS_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/psm.c b/drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
new file mode 100644
index 000000000000..a46225c0fc01
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/psm.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "psm.h"
+
+int psm_get_ui_state(struct pp_eventmgr *eventmgr, enum PP_StateUILabel ui_label, unsigned long *state_id)
+{
+ struct pp_power_state *state;
+ int table_entries;
+ struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+ int i;
+
+ table_entries = hwmgr->num_ps;
+ state = hwmgr->ps;
+
+ for (i = 0; i < table_entries; i++) {
+ if (state->classification.ui_label & ui_label) {
+ *state_id = state->id;
+ return 0;
+ }
+ state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+ }
+ return -1;
+}
+
+int psm_get_state_by_classification(struct pp_eventmgr *eventmgr, enum PP_StateClassificationFlag flag, unsigned long *state_id)
+{
+ struct pp_power_state *state;
+ int table_entries;
+ struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+ int i;
+
+ table_entries = hwmgr->num_ps;
+ state = hwmgr->ps;
+
+ for (i = 0; i < table_entries; i++) {
+ if (state->classification.flags & flag) {
+ *state_id = state->id;
+ return 0;
+ }
+ state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+ }
+ return -1;
+}
+
+int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id)
+{
+ struct pp_power_state *state;
+ int table_entries;
+ struct pp_hwmgr *hwmgr = eventmgr->hwmgr;
+ int i;
+
+ table_entries = hwmgr->num_ps;
+ state = hwmgr->ps;
+
+ for (i = 0; i < table_entries; i++) {
+ if (state->id == *state_id) {
+ hwmgr->request_ps = state;
+ return 0;
+ }
+ state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
+ }
+ return -1;
+}
+
+int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip)
+{
+
+ struct pp_power_state *pcurrent;
+ struct pp_power_state *requested;
+ struct pp_hwmgr *hwmgr;
+ bool equal;
+
+ if (skip)
+ return 0;
+
+ hwmgr = eventmgr->hwmgr;
+ pcurrent = hwmgr->current_ps;
+ requested = hwmgr->request_ps;
+
+ if (requested == NULL)
+ return 0;
+
+ if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr, &pcurrent->hardware, &requested->hardware, &equal)))
+ equal = false;
+
+ if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) {
+ phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
+ phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware);
+ hwmgr->current_ps = requested;
+ }
+ return 0;
+}
+
+int psm_adjust_power_state_static(struct pp_eventmgr *eventmgr, bool skip)
+{
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/eventmgr/psm.h b/drivers/gpu/drm/amd/powerplay/eventmgr/psm.h
new file mode 100644
index 000000000000..fbdff3e02aa3
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/eventmgr/psm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "eventmgr.h"
+#include "eventinit.h"
+#include "eventmanagement.h"
+#include "eventmanager.h"
+#include "power_state.h"
+#include "hardwaremanager.h"
+
+int psm_get_ui_state(struct pp_eventmgr *eventmgr, enum PP_StateUILabel ui_label, unsigned long *state_id);
+
+int psm_get_state_by_classification(struct pp_eventmgr *eventmgr, enum PP_StateClassificationFlag flag, unsigned long *state_id);
+
+int psm_set_states(struct pp_eventmgr *eventmgr, unsigned long *state_id);
+
+int psm_adjust_power_state_dynamic(struct pp_eventmgr *eventmgr, bool skip);
+
+int psm_adjust_power_state_static(struct pp_eventmgr *eventmgr, bool skip);
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
new file mode 100644
index 000000000000..b664e34dbcc0
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the 'hw manager' sub-component of powerplay.
+# It provides the hardware management services for the driver.
+
+HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \
+ hardwaremanager.o pp_acpi.o cz_hwmgr.o \
+ cz_clockpowergating.o \
+ tonga_processpptables.o ppatomctrl.o \
+ tonga_hwmgr.o pppcielanes.o tonga_thermal.o\
+ fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \
+ fiji_clockpowergating.o fiji_thermal.o
+
+AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_HWMGR)
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
new file mode 100644
index 000000000000..ad7700822a1c
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "cz_clockpowergating.h"
+#include "cz_ppsmc.h"
+
+/* PhyID -> Status Mapping in DDI_PHY_GEN_STATUS
+ 0 GFX0L (3:0), (27:24),
+ 1 GFX0H (7:4), (31:28),
+ 2 GFX1L (3:0), (19:16),
+ 3 GFX1H (7:4), (23:20),
+ 4 DDIL (3:0), (11: 8),
+ 5 DDIH (7:4), (15:12),
+ 6 DDI2L (3:0), ( 3: 0),
+ 7 DDI2H (7:4), ( 7: 4),
+*/
+#define DDI_PHY_GEN_STATUS_VAL(phyID) (1 << ((3 - ((phyID & 0x07)/2))*8 + (phyID & 0x01)*4))
+#define IS_PHY_ID_USED_BY_PLL(PhyID) (((0xF3 & (1 << PhyID)) & 0xFF) ? true : false)
+
+
+int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
+{
+ int ret = 0;
+
+ switch (block) {
+ case PHM_AsicBlock_UVD_MVC:
+ case PHM_AsicBlock_UVD:
+ case PHM_AsicBlock_UVD_HD:
+ case PHM_AsicBlock_UVD_SD:
+ if (gating == PHM_ClockGateSetting_StaticOff)
+ ret = cz_dpm_powerdown_uvd(hwmgr);
+ else
+ ret = cz_dpm_powerup_uvd(hwmgr);
+ break;
+ case PHM_AsicBlock_GFX:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+bool cz_phm_is_safe_for_asic_block(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, enum PHM_AsicBlock block)
+{
+ return true;
+}
+
+
+int cz_phm_enable_disable_gfx_power_gating(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return 0;
+}
+
+int cz_phm_smu_power_up_down_pcie(struct pp_hwmgr *hwmgr, uint32_t target, bool up, uint32_t args)
+{
+ /* TODO */
+ return 0;
+}
+
+int cz_phm_initialize_display_phy_access(struct pp_hwmgr *hwmgr, bool initialize, bool accesshw)
+{
+ /* TODO */
+ return 0;
+}
+
+int cz_phm_get_display_phy_access_info(struct pp_hwmgr *hwmgr)
+{
+ /* TODO */
+ return 0;
+}
+
+int cz_phm_gate_unused_display_phys(struct pp_hwmgr *hwmgr)
+{
+ /* TODO */
+ return 0;
+}
+
+int cz_phm_ungate_all_display_phys(struct pp_hwmgr *hwmgr)
+{
+ /* TODO */
+ return 0;
+}
+
+static int cz_tf_uvd_power_gating_initialize(struct pp_hwmgr *hwmgr, void *pInput, void *pOutput, void *pStorage, int Result)
+{
+ return 0;
+}
+
+static int cz_tf_vce_power_gating_initialize(struct pp_hwmgr *hwmgr, void *pInput, void *pOutput, void *pStorage, int Result)
+{
+ return 0;
+}
+
+int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ uint32_t dpm_features = 0;
+
+ if (enable &&
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UVDDPM)) {
+ cz_hwmgr->dpm_flags |= DPMFlags_UVD_Enabled;
+ dpm_features |= UVD_DPM_MASK;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
+ } else {
+ dpm_features |= UVD_DPM_MASK;
+ cz_hwmgr->dpm_flags &= ~DPMFlags_UVD_Enabled;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
+ }
+ return 0;
+}
+
+int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ uint32_t dpm_features = 0;
+
+ if (enable && phm_cap_enabled(
+ hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_VCEDPM)) {
+ cz_hwmgr->dpm_flags |= DPMFlags_VCE_Enabled;
+ dpm_features |= VCE_DPM_MASK;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
+ } else {
+ dpm_features |= VCE_DPM_MASK;
+ cz_hwmgr->dpm_flags &= ~DPMFlags_VCE_Enabled;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
+ }
+
+ return 0;
+}
+
+
+int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (cz_hwmgr->uvd_power_gated == bgate)
+ return 0;
+
+ cz_hwmgr->uvd_power_gated = bgate;
+
+ if (bgate) {
+ cgs_set_clockgating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_CG_STATE_UNGATE);
+ cgs_set_powergating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_GATE);
+ cz_dpm_update_uvd_dpm(hwmgr, true);
+ cz_dpm_powerdown_uvd(hwmgr);
+ } else {
+ cz_dpm_powerup_uvd(hwmgr);
+ cgs_set_clockgating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_GATE);
+ cgs_set_powergating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_CG_STATE_UNGATE);
+ cz_dpm_update_uvd_dpm(hwmgr, false);
+ }
+
+ return 0;
+}
+
+int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_VCEPowerGating)) {
+ if (cz_hwmgr->vce_power_gated != bgate) {
+ if (bgate) {
+ cgs_set_clockgating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_UNGATE);
+ cgs_set_powergating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_GATE);
+ cz_enable_disable_vce_dpm(hwmgr, false);
+ /* TODO: to figure out why vce can't be poweroff*/
+ cz_hwmgr->vce_power_gated = true;
+ } else {
+ cz_dpm_powerup_vce(hwmgr);
+ cz_hwmgr->vce_power_gated = false;
+ cgs_set_clockgating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_GATE);
+ cgs_set_powergating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_UNGATE);
+ cz_dpm_update_vce_dpm(hwmgr);
+ cz_enable_disable_vce_dpm(hwmgr, true);
+ return 0;
+ }
+ }
+ } else {
+ cz_dpm_update_vce_dpm(hwmgr);
+ cz_enable_disable_vce_dpm(hwmgr, true);
+ return 0;
+ }
+
+ if (!cz_hwmgr->vce_power_gated)
+ cz_dpm_update_vce_dpm(hwmgr);
+
+ return 0;
+}
+
+
+static struct phm_master_table_item cz_enable_clock_power_gatings_list[] = {
+ /*we don't need an exit table here, because there is only D3 cold on Kv*/
+ { phm_cf_want_uvd_power_gating, cz_tf_uvd_power_gating_initialize },
+ { phm_cf_want_vce_power_gating, cz_tf_vce_power_gating_initialize },
+ /* to do { NULL, cz_tf_xdma_power_gating_enable }, */
+ { NULL, NULL }
+};
+
+struct phm_master_table_header cz_phm_enable_clock_power_gatings_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ cz_enable_clock_power_gatings_list
+};
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h
new file mode 100644
index 000000000000..bbbc0571320e
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 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 _CZ_CLOCK_POWER_GATING_H_
+#define _CZ_CLOCK_POWER_GATING_H_
+
+#include "cz_hwmgr.h"
+#include "pp_asicblocks.h"
+
+extern int cz_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
+extern struct phm_master_table_header cz_phm_enable_clock_power_gatings_master;
+extern struct phm_master_table_header cz_phm_disable_clock_power_gatings_master;
+extern int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+extern int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+extern int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
+extern int cz_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
+#endif /* _CZ_CLOCK_POWER_GATING_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
new file mode 100644
index 000000000000..0874ab42ee95
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
@@ -0,0 +1,1737 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "atom-types.h"
+#include "atombios.h"
+#include "processpptables.h"
+#include "pp_debug.h"
+#include "cgs_common.h"
+#include "smu/smu_8_0_d.h"
+#include "smu8_fusion.h"
+#include "smu/smu_8_0_sh_mask.h"
+#include "smumgr.h"
+#include "hwmgr.h"
+#include "hardwaremanager.h"
+#include "cz_ppsmc.h"
+#include "cz_hwmgr.h"
+#include "power_state.h"
+#include "cz_clockpowergating.h"
+#include "pp_debug.h"
+
+#define ixSMUSVI_NB_CURRENTVID 0xD8230044
+#define CURRENT_NB_VID_MASK 0xff000000
+#define CURRENT_NB_VID__SHIFT 24
+#define ixSMUSVI_GFX_CURRENTVID 0xD8230048
+#define CURRENT_GFX_VID_MASK 0xff000000
+#define CURRENT_GFX_VID__SHIFT 24
+
+static const unsigned long PhwCz_Magic = (unsigned long) PHM_Cz_Magic;
+
+static struct cz_power_state *cast_PhwCzPowerState(struct pp_hw_power_state *hw_ps)
+{
+ if (PhwCz_Magic != hw_ps->magic)
+ return NULL;
+
+ return (struct cz_power_state *)hw_ps;
+}
+
+static const struct cz_power_state *cast_const_PhwCzPowerState(
+ const struct pp_hw_power_state *hw_ps)
+{
+ if (PhwCz_Magic != hw_ps->magic)
+ return NULL;
+
+ return (struct cz_power_state *)hw_ps;
+}
+
+uint32_t cz_get_eclk_level(struct pp_hwmgr *hwmgr,
+ uint32_t clock, uint32_t msg)
+{
+ int i = 0;
+ struct phm_vce_clock_voltage_dependency_table *ptable =
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+ switch (msg) {
+ case PPSMC_MSG_SetEclkSoftMin:
+ case PPSMC_MSG_SetEclkHardMin:
+ for (i = 0; i < (int)ptable->count; i++) {
+ if (clock <= ptable->entries[i].ecclk)
+ break;
+ }
+ break;
+
+ case PPSMC_MSG_SetEclkSoftMax:
+ case PPSMC_MSG_SetEclkHardMax:
+ for (i = ptable->count - 1; i >= 0; i--) {
+ if (clock >= ptable->entries[i].ecclk)
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return i;
+}
+
+static uint32_t cz_get_sclk_level(struct pp_hwmgr *hwmgr,
+ uint32_t clock, uint32_t msg)
+{
+ int i = 0;
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+ switch (msg) {
+ case PPSMC_MSG_SetSclkSoftMin:
+ case PPSMC_MSG_SetSclkHardMin:
+ for (i = 0; i < (int)table->count; i++) {
+ if (clock <= table->entries[i].clk)
+ break;
+ }
+ break;
+
+ case PPSMC_MSG_SetSclkSoftMax:
+ case PPSMC_MSG_SetSclkHardMax:
+ for (i = table->count - 1; i >= 0; i--) {
+ if (clock >= table->entries[i].clk)
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return i;
+}
+
+static uint32_t cz_get_uvd_level(struct pp_hwmgr *hwmgr,
+ uint32_t clock, uint32_t msg)
+{
+ int i = 0;
+ struct phm_uvd_clock_voltage_dependency_table *ptable =
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+ switch (msg) {
+ case PPSMC_MSG_SetUvdSoftMin:
+ case PPSMC_MSG_SetUvdHardMin:
+ for (i = 0; i < (int)ptable->count; i++) {
+ if (clock <= ptable->entries[i].vclk)
+ break;
+ }
+ break;
+
+ case PPSMC_MSG_SetUvdSoftMax:
+ case PPSMC_MSG_SetUvdHardMax:
+ for (i = ptable->count - 1; i >= 0; i--) {
+ if (clock >= ptable->entries[i].vclk)
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return i;
+}
+
+static uint32_t cz_get_max_sclk_level(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (cz_hwmgr->max_sclk_level == 0) {
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxSclkLevel);
+ cz_hwmgr->max_sclk_level = smum_get_argument(hwmgr->smumgr) + 1;
+ }
+
+ return cz_hwmgr->max_sclk_level;
+}
+
+static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ uint32_t i;
+
+ cz_hwmgr->gfx_ramp_step = 256*25/100;
+
+ cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */
+
+ for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++)
+ cz_hwmgr->activity_target[i] = CZ_AT_DFLT;
+
+ cz_hwmgr->mgcg_cgtt_local0 = 0x00000000;
+ cz_hwmgr->mgcg_cgtt_local1 = 0x00000000;
+
+ cz_hwmgr->clock_slow_down_freq = 25000;
+
+ cz_hwmgr->skip_clock_slow_down = 1;
+
+ cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */
+
+ cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */
+
+ cz_hwmgr->voting_rights_clients = 0x00C00033;
+
+ cz_hwmgr->static_screen_threshold = 8;
+
+ cz_hwmgr->ddi_power_gating_disabled = 0;
+
+ cz_hwmgr->bapm_enabled = 1;
+
+ cz_hwmgr->voltage_drop_threshold = 0;
+
+ cz_hwmgr->gfx_power_gating_threshold = 500;
+
+ cz_hwmgr->vce_slow_sclk_threshold = 20000;
+
+ cz_hwmgr->dce_slow_sclk_threshold = 30000;
+
+ cz_hwmgr->disable_driver_thermal_policy = 1;
+
+ cz_hwmgr->disable_nb_ps3_in_battery = 0;
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ABM);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_NonABMSupportInPPLib);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkDeepSleep);
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicM3Arbiter);
+
+ cz_hwmgr->override_dynamic_mgpg = 1;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicPatchPowerState);
+
+ cz_hwmgr->thermal_auto_throttling_treshold = 0;
+
+ cz_hwmgr->tdr_clock = 0;
+
+ cz_hwmgr->disable_gfx_power_gating_in_uvd = 0;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicUVDState);
+
+ cz_hwmgr->cc6_settings.cpu_cc6_disable = false;
+ cz_hwmgr->cc6_settings.cpu_pstate_disable = false;
+ cz_hwmgr->cc6_settings.nb_pstate_switch_disable = false;
+ cz_hwmgr->cc6_settings.cpu_pstate_separation_time = 0;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DisableVoltageIsland);
+
+ return 0;
+}
+
+static uint32_t cz_convert_8Bit_index_to_voltage(
+ struct pp_hwmgr *hwmgr, uint16_t voltage)
+{
+ return 6200 - (voltage * 25);
+}
+
+static int cz_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
+ struct phm_clock_and_voltage_limits *table)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend;
+ struct cz_sys_info *sys_info = &cz_hwmgr->sys_info;
+ struct phm_clock_voltage_dependency_table *dep_table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+ if (dep_table->count > 0) {
+ table->sclk = dep_table->entries[dep_table->count-1].clk;
+ table->vddc = cz_convert_8Bit_index_to_voltage(hwmgr,
+ (uint16_t)dep_table->entries[dep_table->count-1].v);
+ }
+ table->mclk = sys_info->nbp_memory_clock[0];
+ return 0;
+}
+
+static int cz_init_dynamic_state_adjustment_rule_settings(
+ struct pp_hwmgr *hwmgr,
+ ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table)
+{
+ uint32_t table_size =
+ sizeof(struct phm_clock_voltage_dependency_table) +
+ (7 * sizeof(struct phm_clock_voltage_dependency_record));
+
+ struct phm_clock_voltage_dependency_table *table_clk_vlt =
+ kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == table_clk_vlt) {
+ printk(KERN_ERR "[ powerplay ] Can not allocate memory!\n");
+ return -ENOMEM;
+ }
+
+ table_clk_vlt->count = 8;
+ table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
+ table_clk_vlt->entries[0].v = 0;
+ table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
+ table_clk_vlt->entries[1].v = 1;
+ table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
+ table_clk_vlt->entries[2].v = 2;
+ table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
+ table_clk_vlt->entries[3].v = 3;
+ table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
+ table_clk_vlt->entries[4].v = 4;
+ table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
+ table_clk_vlt->entries[5].v = 5;
+ table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
+ table_clk_vlt->entries[6].v = 6;
+ table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
+ table_clk_vlt->entries[7].v = 7;
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
+
+ return 0;
+}
+
+static int cz_get_system_info_data(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend;
+ ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info = NULL;
+ uint32_t i;
+ int result = 0;
+ uint8_t frev, crev;
+ uint16_t size;
+
+ info = (ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *) cgs_atom_get_data_table(
+ hwmgr->device,
+ GetIndexIntoMasterTable(DATA, IntegratedSystemInfo),
+ &size, &frev, &crev);
+
+ if (crev != 9) {
+ printk(KERN_ERR "[ powerplay ] Unsupported IGP table: %d %d\n", frev, crev);
+ return -EINVAL;
+ }
+
+ if (info == NULL) {
+ printk(KERN_ERR "[ powerplay ] Could not retrieve the Integrated System Info Table!\n");
+ return -EINVAL;
+ }
+
+ cz_hwmgr->sys_info.bootup_uma_clock =
+ le32_to_cpu(info->ulBootUpUMAClock);
+
+ cz_hwmgr->sys_info.bootup_engine_clock =
+ le32_to_cpu(info->ulBootUpEngineClock);
+
+ cz_hwmgr->sys_info.dentist_vco_freq =
+ le32_to_cpu(info->ulDentistVCOFreq);
+
+ cz_hwmgr->sys_info.system_config =
+ le32_to_cpu(info->ulSystemConfig);
+
+ cz_hwmgr->sys_info.bootup_nb_voltage_index =
+ le16_to_cpu(info->usBootUpNBVoltage);
+
+ cz_hwmgr->sys_info.htc_hyst_lmt =
+ (info->ucHtcHystLmt == 0) ? 5 : info->ucHtcHystLmt;
+
+ cz_hwmgr->sys_info.htc_tmp_lmt =
+ (info->ucHtcTmpLmt == 0) ? 203 : info->ucHtcTmpLmt;
+
+ if (cz_hwmgr->sys_info.htc_tmp_lmt <=
+ cz_hwmgr->sys_info.htc_hyst_lmt) {
+ printk(KERN_ERR "[ powerplay ] The htcTmpLmt should be larger than htcHystLmt.\n");
+ return -EINVAL;
+ }
+
+ cz_hwmgr->sys_info.nb_dpm_enable =
+ cz_hwmgr->enable_nb_ps_policy &&
+ (le32_to_cpu(info->ulSystemConfig) >> 3 & 0x1);
+
+ for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
+ if (i < CZ_NUM_NBPMEMORYCLOCK) {
+ cz_hwmgr->sys_info.nbp_memory_clock[i] =
+ le32_to_cpu(info->ulNbpStateMemclkFreq[i]);
+ }
+ cz_hwmgr->sys_info.nbp_n_clock[i] =
+ le32_to_cpu(info->ulNbpStateNClkFreq[i]);
+ }
+
+ for (i = 0; i < MAX_DISPLAY_CLOCK_LEVEL; i++) {
+ cz_hwmgr->sys_info.display_clock[i] =
+ le32_to_cpu(info->sDispClkVoltageMapping[i].ulMaximumSupportedCLK);
+ }
+
+ /* Here use 4 levels, make sure not exceed */
+ for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
+ cz_hwmgr->sys_info.nbp_voltage_index[i] =
+ le16_to_cpu(info->usNBPStateVoltage[i]);
+ }
+
+ if (!cz_hwmgr->sys_info.nb_dpm_enable) {
+ for (i = 1; i < CZ_NUM_NBPSTATES; i++) {
+ if (i < CZ_NUM_NBPMEMORYCLOCK) {
+ cz_hwmgr->sys_info.nbp_memory_clock[i] =
+ cz_hwmgr->sys_info.nbp_memory_clock[0];
+ }
+ cz_hwmgr->sys_info.nbp_n_clock[i] =
+ cz_hwmgr->sys_info.nbp_n_clock[0];
+ cz_hwmgr->sys_info.nbp_voltage_index[i] =
+ cz_hwmgr->sys_info.nbp_voltage_index[0];
+ }
+ }
+
+ if (le32_to_cpu(info->ulGPUCapInfo) &
+ SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableDFSBypass);
+ }
+
+ cz_hwmgr->sys_info.uma_channel_number = info->ucUMAChannelNumber;
+
+ cz_construct_max_power_limits_table (hwmgr,
+ &hwmgr->dyn_state.max_clock_voltage_on_ac);
+
+ cz_init_dynamic_state_adjustment_rule_settings(hwmgr,
+ &info->sDISPCLK_Voltage[0]);
+
+ return result;
+}
+
+static int cz_construct_boot_state(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ cz_hwmgr->boot_power_level.engineClock =
+ cz_hwmgr->sys_info.bootup_engine_clock;
+
+ cz_hwmgr->boot_power_level.vddcIndex =
+ (uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index;
+
+ cz_hwmgr->boot_power_level.dsDividerIndex = 0;
+
+ cz_hwmgr->boot_power_level.ssDividerIndex = 0;
+
+ cz_hwmgr->boot_power_level.allowGnbSlow = 1;
+
+ cz_hwmgr->boot_power_level.forceNBPstate = 0;
+
+ cz_hwmgr->boot_power_level.hysteresis_up = 0;
+
+ cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0;
+
+ cz_hwmgr->boot_power_level.display_wm = 0;
+
+ cz_hwmgr->boot_power_level.vce_wm = 0;
+
+ return 0;
+}
+
+static int cz_tf_reset_active_process_mask(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ return 0;
+}
+
+static int cz_tf_upload_pptable_to_smu(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct SMU8_Fusion_ClkTable *clock_table;
+ int ret;
+ uint32_t i;
+ void *table = NULL;
+ pp_atomctrl_clock_dividers_kong dividers;
+
+ struct phm_clock_voltage_dependency_table *vddc_table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+ struct phm_clock_voltage_dependency_table *vdd_gfx_table =
+ hwmgr->dyn_state.vdd_gfx_dependency_on_sclk;
+ struct phm_acp_clock_voltage_dependency_table *acp_table =
+ hwmgr->dyn_state.acp_clock_voltage_dependency_table;
+ struct phm_uvd_clock_voltage_dependency_table *uvd_table =
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+ struct phm_vce_clock_voltage_dependency_table *vce_table =
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+ if (!hwmgr->need_pp_table_upload)
+ return 0;
+
+ ret = smum_download_powerplay_table(hwmgr->smumgr, &table);
+
+ PP_ASSERT_WITH_CODE((0 == ret && NULL != table),
+ "Fail to get clock table from SMU!", return -EINVAL;);
+
+ clock_table = (struct SMU8_Fusion_ClkTable *)table;
+
+ /* patch clock table */
+ PP_ASSERT_WITH_CODE((vddc_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+ "Dependency table entry exceeds max limit!", return -EINVAL;);
+ PP_ASSERT_WITH_CODE((vdd_gfx_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+ "Dependency table entry exceeds max limit!", return -EINVAL;);
+ PP_ASSERT_WITH_CODE((acp_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+ "Dependency table entry exceeds max limit!", return -EINVAL;);
+ PP_ASSERT_WITH_CODE((uvd_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+ "Dependency table entry exceeds max limit!", return -EINVAL;);
+ PP_ASSERT_WITH_CODE((vce_table->count <= CZ_MAX_HARDWARE_POWERLEVELS),
+ "Dependency table entry exceeds max limit!", return -EINVAL;);
+
+ for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) {
+
+ /* vddc_sclk */
+ clock_table->SclkBreakdownTable.ClkLevel[i].GnbVid =
+ (i < vddc_table->count) ? (uint8_t)vddc_table->entries[i].v : 0;
+ clock_table->SclkBreakdownTable.ClkLevel[i].Frequency =
+ (i < vddc_table->count) ? vddc_table->entries[i].clk : 0;
+
+ atomctrl_get_engine_pll_dividers_kong(hwmgr,
+ clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
+ &dividers);
+
+ clock_table->SclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.pll_post_divider;
+
+ /* vddgfx_sclk */
+ clock_table->SclkBreakdownTable.ClkLevel[i].GfxVid =
+ (i < vdd_gfx_table->count) ? (uint8_t)vdd_gfx_table->entries[i].v : 0;
+
+ /* acp breakdown */
+ clock_table->AclkBreakdownTable.ClkLevel[i].GfxVid =
+ (i < acp_table->count) ? (uint8_t)acp_table->entries[i].v : 0;
+ clock_table->AclkBreakdownTable.ClkLevel[i].Frequency =
+ (i < acp_table->count) ? acp_table->entries[i].acpclk : 0;
+
+ atomctrl_get_engine_pll_dividers_kong(hwmgr,
+ clock_table->AclkBreakdownTable.ClkLevel[i].Frequency,
+ &dividers);
+
+ clock_table->AclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.pll_post_divider;
+
+
+ /* uvd breakdown */
+ clock_table->VclkBreakdownTable.ClkLevel[i].GfxVid =
+ (i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
+ clock_table->VclkBreakdownTable.ClkLevel[i].Frequency =
+ (i < uvd_table->count) ? uvd_table->entries[i].vclk : 0;
+
+ atomctrl_get_engine_pll_dividers_kong(hwmgr,
+ clock_table->VclkBreakdownTable.ClkLevel[i].Frequency,
+ &dividers);
+
+ clock_table->VclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.pll_post_divider;
+
+ clock_table->DclkBreakdownTable.ClkLevel[i].GfxVid =
+ (i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
+ clock_table->DclkBreakdownTable.ClkLevel[i].Frequency =
+ (i < uvd_table->count) ? uvd_table->entries[i].dclk : 0;
+
+ atomctrl_get_engine_pll_dividers_kong(hwmgr,
+ clock_table->DclkBreakdownTable.ClkLevel[i].Frequency,
+ &dividers);
+
+ clock_table->DclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.pll_post_divider;
+
+ /* vce breakdown */
+ clock_table->EclkBreakdownTable.ClkLevel[i].GfxVid =
+ (i < vce_table->count) ? (uint8_t)vce_table->entries[i].v : 0;
+ clock_table->EclkBreakdownTable.ClkLevel[i].Frequency =
+ (i < vce_table->count) ? vce_table->entries[i].ecclk : 0;
+
+
+ atomctrl_get_engine_pll_dividers_kong(hwmgr,
+ clock_table->EclkBreakdownTable.ClkLevel[i].Frequency,
+ &dividers);
+
+ clock_table->EclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.pll_post_divider;
+
+ }
+ ret = smum_upload_powerplay_table(hwmgr->smumgr);
+
+ return ret;
+}
+
+static int cz_tf_init_sclk_limit(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+ unsigned long clock = 0, level;
+
+ if (NULL == table || table->count <= 0)
+ return -EINVAL;
+
+ cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
+ cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk;
+
+ level = cz_get_max_sclk_level(hwmgr) - 1;
+
+ if (level < table->count)
+ clock = table->entries[level].clk;
+ else
+ clock = table->entries[table->count - 1].clk;
+
+ cz_hwmgr->sclk_dpm.soft_max_clk = clock;
+ cz_hwmgr->sclk_dpm.hard_max_clk = clock;
+
+ return 0;
+}
+
+static int cz_tf_init_uvd_limit(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_uvd_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+ unsigned long clock = 0, level;
+
+ if (NULL == table || table->count <= 0)
+ return -EINVAL;
+
+ cz_hwmgr->uvd_dpm.soft_min_clk = 0;
+ cz_hwmgr->uvd_dpm.hard_min_clk = 0;
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxUvdLevel);
+ level = smum_get_argument(hwmgr->smumgr);
+
+ if (level < table->count)
+ clock = table->entries[level].vclk;
+ else
+ clock = table->entries[table->count - 1].vclk;
+
+ cz_hwmgr->uvd_dpm.soft_max_clk = clock;
+ cz_hwmgr->uvd_dpm.hard_max_clk = clock;
+
+ return 0;
+}
+
+static int cz_tf_init_vce_limit(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_vce_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+ unsigned long clock = 0, level;
+
+ if (NULL == table || table->count <= 0)
+ return -EINVAL;
+
+ cz_hwmgr->vce_dpm.soft_min_clk = 0;
+ cz_hwmgr->vce_dpm.hard_min_clk = 0;
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxEclkLevel);
+ level = smum_get_argument(hwmgr->smumgr);
+
+ if (level < table->count)
+ clock = table->entries[level].ecclk;
+ else
+ clock = table->entries[table->count - 1].ecclk;
+
+ cz_hwmgr->vce_dpm.soft_max_clk = clock;
+ cz_hwmgr->vce_dpm.hard_max_clk = clock;
+
+ return 0;
+}
+
+static int cz_tf_init_acp_limit(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_acp_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.acp_clock_voltage_dependency_table;
+ unsigned long clock = 0, level;
+
+ if (NULL == table || table->count <= 0)
+ return -EINVAL;
+
+ cz_hwmgr->acp_dpm.soft_min_clk = 0;
+ cz_hwmgr->acp_dpm.hard_min_clk = 0;
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxAclkLevel);
+ level = smum_get_argument(hwmgr->smumgr);
+
+ if (level < table->count)
+ clock = table->entries[level].acpclk;
+ else
+ clock = table->entries[table->count - 1].acpclk;
+
+ cz_hwmgr->acp_dpm.soft_max_clk = clock;
+ cz_hwmgr->acp_dpm.hard_max_clk = clock;
+ return 0;
+}
+
+static int cz_tf_init_power_gate_state(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ cz_hwmgr->uvd_power_gated = false;
+ cz_hwmgr->vce_power_gated = false;
+ cz_hwmgr->samu_power_gated = false;
+ cz_hwmgr->acp_power_gated = false;
+ cz_hwmgr->pgacpinit = true;
+
+ return 0;
+}
+
+static int cz_tf_init_sclk_threshold(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ cz_hwmgr->low_sclk_interrupt_threshold = 0;
+
+ return 0;
+}
+static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+ unsigned long clock = 0;
+ unsigned long level;
+ unsigned long stable_pstate_sclk;
+ struct PP_Clocks clocks;
+ unsigned long percentage;
+
+ cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
+ level = cz_get_max_sclk_level(hwmgr) - 1;
+
+ if (level < table->count)
+ cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[level].clk;
+ else
+ cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk;
+
+ /*PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks);*/
+ clock = clocks.engineClock;
+
+ if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) {
+ cz_hwmgr->sclk_dpm.hard_min_clk = clock;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkHardMin,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.hard_min_clk,
+ PPSMC_MSG_SetSclkHardMin));
+ }
+
+ clock = cz_hwmgr->sclk_dpm.soft_min_clk;
+
+ /* update minimum clocks for Stable P-State feature */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState)) {
+ percentage = 75;
+ /*Sclk - calculate sclk value based on percentage and find FLOOR sclk from VddcDependencyOnSCLK table */
+ stable_pstate_sclk = (hwmgr->dyn_state.max_clock_voltage_on_ac.mclk *
+ percentage) / 100;
+
+ if (clock < stable_pstate_sclk)
+ clock = stable_pstate_sclk;
+ } else {
+ if (clock < hwmgr->gfx_arbiter.sclk)
+ clock = hwmgr->gfx_arbiter.sclk;
+ }
+
+ if (cz_hwmgr->sclk_dpm.soft_min_clk != clock) {
+ cz_hwmgr->sclk_dpm.soft_min_clk = clock;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_min_clk,
+ PPSMC_MSG_SetSclkSoftMin));
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState) &&
+ cz_hwmgr->sclk_dpm.soft_max_clk != clock) {
+ cz_hwmgr->sclk_dpm.soft_max_clk = clock;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+ }
+
+ return 0;
+}
+
+static int cz_tf_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkDeepSleep)) {
+ uint32_t clks = hwmgr->display_config.min_core_set_clock_in_sr;
+ if (clks == 0)
+ clks = CZ_MIN_DEEP_SLEEP_SCLK;
+
+ PP_DBG_LOG("Setting Deep Sleep Clock: %d\n", clks);
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetMinDeepSleepSclk,
+ clks);
+ }
+
+ return 0;
+}
+
+static int cz_tf_set_watermark_threshold(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr =
+ (struct cz_hwmgr *)(hwmgr->backend);
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetWatermarkFrequency,
+ cz_hwmgr->sclk_dpm.soft_max_clk);
+
+ return 0;
+}
+
+static int cz_tf_set_enabled_levels(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ return 0;
+}
+
+
+static int cz_tf_enable_nb_dpm(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ int ret = 0;
+
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ unsigned long dpm_features = 0;
+
+ if (!cz_hwmgr->is_nb_dpm_enabled) {
+ PP_DBG_LOG("enabling ALL SMU features.\n");
+ dpm_features |= NB_DPM_MASK;
+ ret = smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ PPSMC_MSG_EnableAllSmuFeatures,
+ dpm_features);
+ if (ret == 0)
+ cz_hwmgr->is_nb_dpm_enabled = true;
+ }
+
+ return ret;
+}
+
+static int cz_nbdpm_pstate_enable_disable(struct pp_hwmgr *hwmgr, bool enable, bool lock)
+{
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (hw_data->is_nb_dpm_enabled) {
+ if (enable) {
+ PP_DBG_LOG("enable Low Memory PState.\n");
+
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_EnableLowMemoryPstate,
+ (lock ? 1 : 0));
+ } else {
+ PP_DBG_LOG("disable Low Memory PState.\n");
+
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_DisableLowMemoryPstate,
+ (lock ? 1 : 0));
+ }
+ }
+
+ return 0;
+}
+
+static int cz_tf_update_low_mem_pstate(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ bool disable_switch;
+ bool enable_low_mem_state;
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+ const struct phm_set_power_state_input *states = (struct phm_set_power_state_input *)input;
+ const struct cz_power_state *pnew_state = cast_const_PhwCzPowerState(states->pnew_state);
+
+ if (hw_data->sys_info.nb_dpm_enable) {
+ disable_switch = hw_data->cc6_settings.nb_pstate_switch_disable ? true : false;
+ enable_low_mem_state = hw_data->cc6_settings.nb_pstate_switch_disable ? false : true;
+
+ if (pnew_state->action == FORCE_HIGH)
+ cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch);
+ else if(pnew_state->action == CANCEL_FORCE_HIGH)
+ cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch);
+ else
+ cz_nbdpm_pstate_enable_disable(hwmgr, enable_low_mem_state, disable_switch);
+ }
+ return 0;
+}
+
+static struct phm_master_table_item cz_set_power_state_list[] = {
+ {NULL, cz_tf_update_sclk_limit},
+ {NULL, cz_tf_set_deep_sleep_sclk_threshold},
+ {NULL, cz_tf_set_watermark_threshold},
+ {NULL, cz_tf_set_enabled_levels},
+ {NULL, cz_tf_enable_nb_dpm},
+ {NULL, cz_tf_update_low_mem_pstate},
+ {NULL, NULL}
+};
+
+static struct phm_master_table_header cz_set_power_state_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ cz_set_power_state_list
+};
+
+static struct phm_master_table_item cz_setup_asic_list[] = {
+ {NULL, cz_tf_reset_active_process_mask},
+ {NULL, cz_tf_upload_pptable_to_smu},
+ {NULL, cz_tf_init_sclk_limit},
+ {NULL, cz_tf_init_uvd_limit},
+ {NULL, cz_tf_init_vce_limit},
+ {NULL, cz_tf_init_acp_limit},
+ {NULL, cz_tf_init_power_gate_state},
+ {NULL, cz_tf_init_sclk_threshold},
+ {NULL, NULL}
+};
+
+static struct phm_master_table_header cz_setup_asic_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ cz_setup_asic_list
+};
+
+static int cz_tf_power_up_display_clock_sys_pll(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+ hw_data->disp_clk_bypass_pending = false;
+ hw_data->disp_clk_bypass = false;
+
+ return 0;
+}
+
+static int cz_tf_clear_nb_dpm_flag(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+ hw_data->is_nb_dpm_enabled = false;
+
+ return 0;
+}
+
+static int cz_tf_reset_cc6_data(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+
+ hw_data->cc6_settings.cc6_setting_changed = false;
+ hw_data->cc6_settings.cpu_pstate_separation_time = 0;
+ hw_data->cc6_settings.cpu_cc6_disable = false;
+ hw_data->cc6_settings.cpu_pstate_disable = false;
+
+ return 0;
+}
+
+static struct phm_master_table_item cz_power_down_asic_list[] = {
+ {NULL, cz_tf_power_up_display_clock_sys_pll},
+ {NULL, cz_tf_clear_nb_dpm_flag},
+ {NULL, cz_tf_reset_cc6_data},
+ {NULL, NULL}
+};
+
+static struct phm_master_table_header cz_power_down_asic_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ cz_power_down_asic_list
+};
+
+static int cz_tf_program_voting_clients(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ PHMCZ_WRITE_SMC_REGISTER(hwmgr->device, CG_FREQ_TRAN_VOTING_0,
+ PPCZ_VOTINGRIGHTSCLIENTS_DFLT0);
+ return 0;
+}
+
+static int cz_tf_start_dpm(struct pp_hwmgr *hwmgr, void *input, void *output,
+ void *storage, int result)
+{
+ int res = 0xff;
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ unsigned long dpm_features = 0;
+
+ cz_hwmgr->dpm_flags |= DPMFlags_SCLK_Enabled;
+ dpm_features |= SCLK_DPM_MASK;
+
+ res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_EnableAllSmuFeatures,
+ dpm_features);
+
+ return res;
+}
+
+static int cz_tf_program_bootup_state(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ cz_hwmgr->sclk_dpm.soft_min_clk = cz_hwmgr->sys_info.bootup_engine_clock;
+ cz_hwmgr->sclk_dpm.soft_max_clk = cz_hwmgr->sys_info.bootup_engine_clock;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_min_clk,
+ PPSMC_MSG_SetSclkSoftMin));
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+
+ return 0;
+}
+
+int cz_tf_reset_acp_boot_level(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ cz_hwmgr->acp_boot_level = 0xff;
+ return 0;
+}
+
+static bool cz_dpm_check_smu_features(struct pp_hwmgr *hwmgr,
+ unsigned long check_feature)
+{
+ int result;
+ unsigned long features;
+
+ result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_GetFeatureStatus, 0);
+ if (result == 0) {
+ features = smum_get_argument(hwmgr->smumgr);
+ if (features & check_feature)
+ return true;
+ }
+
+ return result;
+}
+
+static int cz_tf_check_for_dpm_disabled(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ if (cz_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn))
+ return PP_Result_TableImmediateExit;
+ return 0;
+}
+
+static int cz_tf_enable_didt(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result)
+{
+ /* TO DO */
+ return 0;
+}
+
+static int cz_tf_check_for_dpm_enabled(struct pp_hwmgr *hwmgr,
+ void *input, void *output,
+ void *storage, int result)
+{
+ if (!cz_dpm_check_smu_features(hwmgr,
+ SMU_EnabledFeatureScoreboard_SclkDpmOn))
+ return PP_Result_TableImmediateExit;
+ return 0;
+}
+
+static struct phm_master_table_item cz_disable_dpm_list[] = {
+ { NULL, cz_tf_check_for_dpm_enabled},
+ {NULL, NULL},
+};
+
+
+static struct phm_master_table_header cz_disable_dpm_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ cz_disable_dpm_list
+};
+
+static struct phm_master_table_item cz_enable_dpm_list[] = {
+ { NULL, cz_tf_check_for_dpm_disabled },
+ { NULL, cz_tf_program_voting_clients },
+ { NULL, cz_tf_start_dpm},
+ { NULL, cz_tf_program_bootup_state},
+ { NULL, cz_tf_enable_didt },
+ { NULL, cz_tf_reset_acp_boot_level },
+ {NULL, NULL},
+};
+
+static struct phm_master_table_header cz_enable_dpm_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ cz_enable_dpm_list
+};
+
+static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *prequest_ps,
+ const struct pp_power_state *pcurrent_ps)
+{
+ struct cz_power_state *cz_ps =
+ cast_PhwCzPowerState(&prequest_ps->hardware);
+
+ const struct cz_power_state *cz_current_ps =
+ cast_const_PhwCzPowerState(&pcurrent_ps->hardware);
+
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct PP_Clocks clocks;
+ bool force_high;
+ unsigned long num_of_active_displays = 4;
+
+ cz_ps->evclk = hwmgr->vce_arbiter.evclk;
+ cz_ps->ecclk = hwmgr->vce_arbiter.ecclk;
+
+ cz_ps->need_dfs_bypass = true;
+
+ cz_hwmgr->video_start = (hwmgr->uvd_arbiter.vclk != 0 || hwmgr->uvd_arbiter.dclk != 0 ||
+ hwmgr->vce_arbiter.evclk != 0 || hwmgr->vce_arbiter.ecclk != 0);
+
+ cz_hwmgr->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
+
+ /* to do PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */
+ /* PECI_GetNumberOfActiveDisplays(pHwMgr->pPECI, &numOfActiveDisplays); */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+ clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk;
+ else
+ clocks.memoryClock = 0;
+
+ if (clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+ clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+ force_high = (clocks.memoryClock > cz_hwmgr->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1])
+ || (num_of_active_displays >= 3);
+
+ cz_ps->action = cz_current_ps->action;
+
+ if ((force_high == false) && (cz_ps->action == FORCE_HIGH))
+ cz_ps->action = CANCEL_FORCE_HIGH;
+ else if ((force_high == true) && (cz_ps->action != FORCE_HIGH))
+ cz_ps->action = FORCE_HIGH;
+ else
+ cz_ps->action = DO_NOTHING;
+
+ return 0;
+}
+
+static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+
+ result = cz_initialize_dpm_defaults(hwmgr);
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] cz_initialize_dpm_defaults failed\n");
+ return result;
+ }
+
+ result = cz_get_system_info_data(hwmgr);
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] cz_get_system_info_data failed\n");
+ return result;
+ }
+
+ cz_construct_boot_state(hwmgr);
+
+ result = phm_construct_table(hwmgr, &cz_setup_asic_master,
+ &(hwmgr->setup_asic));
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] Fail to construct setup ASIC\n");
+ return result;
+ }
+
+ result = phm_construct_table(hwmgr, &cz_power_down_asic_master,
+ &(hwmgr->power_down_asic));
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] Fail to construct power down ASIC\n");
+ return result;
+ }
+
+ result = phm_construct_table(hwmgr, &cz_disable_dpm_master,
+ &(hwmgr->disable_dynamic_state_management));
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] Fail to disable_dynamic_state\n");
+ return result;
+ }
+ result = phm_construct_table(hwmgr, &cz_enable_dpm_master,
+ &(hwmgr->enable_dynamic_state_management));
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] Fail to enable_dynamic_state\n");
+ return result;
+ }
+ result = phm_construct_table(hwmgr, &cz_set_power_state_master,
+ &(hwmgr->set_power_state));
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] Fail to construct set_power_state\n");
+ return result;
+ }
+
+ result = phm_construct_table(hwmgr, &cz_phm_enable_clock_power_gatings_master, &(hwmgr->enable_clock_power_gatings));
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] Fail to construct enable_clock_power_gatings\n");
+ return result;
+ }
+ return result;
+}
+
+static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+ if (hwmgr != NULL || hwmgr->backend != NULL) {
+ kfree(hwmgr->backend);
+ kfree(hwmgr);
+ }
+ return 0;
+}
+
+int cz_phm_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (cz_hwmgr->sclk_dpm.soft_min_clk !=
+ cz_hwmgr->sclk_dpm.soft_max_clk)
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMin));
+ return 0;
+}
+
+int cz_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+ unsigned long clock = 0, level;
+
+ if (NULL == table || table->count <= 0)
+ return -EINVAL;
+
+ cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
+ cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk;
+
+ level = cz_get_max_sclk_level(hwmgr) - 1;
+
+ if (level < table->count)
+ clock = table->entries[level].clk;
+ else
+ clock = table->entries[table->count - 1].clk;
+
+ cz_hwmgr->sclk_dpm.soft_max_clk = clock;
+ cz_hwmgr->sclk_dpm.hard_max_clk = clock;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_min_clk,
+ PPSMC_MSG_SetSclkSoftMin));
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+
+ return 0;
+}
+
+int cz_phm_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (cz_hwmgr->sclk_dpm.soft_min_clk !=
+ cz_hwmgr->sclk_dpm.soft_max_clk) {
+ cz_hwmgr->sclk_dpm.soft_max_clk =
+ cz_hwmgr->sclk_dpm.soft_min_clk;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(hwmgr,
+ cz_hwmgr->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+ }
+
+ return 0;
+}
+
+static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+ enum amd_dpm_forced_level level)
+{
+ int ret = 0;
+
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_HIGH:
+ ret = cz_phm_force_dpm_highest(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_LOW:
+ ret = cz_phm_force_dpm_lowest(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ ret = cz_phm_unforce_dpm_levels(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ hwmgr->dpm_level = level;
+
+ return ret;
+}
+
+int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UVDPowerGating))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_UVDPowerOFF);
+ return 0;
+}
+
+int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UVDPowerGating)) {
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UVDDynamicPowerGating)) {
+ return smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ PPSMC_MSG_UVDPowerON, 1);
+ } else {
+ return smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ PPSMC_MSG_UVDPowerON, 0);
+ }
+ }
+
+ return 0;
+}
+
+int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_uvd_clock_voltage_dependency_table *ptable =
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+ if (!bgate) {
+ /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState)) {
+ cz_hwmgr->uvd_dpm.hard_min_clk =
+ ptable->entries[ptable->count - 1].vclk;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetUvdHardMin,
+ cz_get_uvd_level(hwmgr,
+ cz_hwmgr->uvd_dpm.hard_min_clk,
+ PPSMC_MSG_SetUvdHardMin));
+
+ cz_enable_disable_uvd_dpm(hwmgr, true);
+ } else
+ cz_enable_disable_uvd_dpm(hwmgr, true);
+ } else
+ cz_enable_disable_uvd_dpm(hwmgr, false);
+
+ return 0;
+}
+
+int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct phm_vce_clock_voltage_dependency_table *ptable =
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+ /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState)) {
+ cz_hwmgr->vce_dpm.hard_min_clk =
+ ptable->entries[ptable->count - 1].ecclk;
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkHardMin,
+ cz_get_eclk_level(hwmgr,
+ cz_hwmgr->vce_dpm.hard_min_clk,
+ PPSMC_MSG_SetEclkHardMin));
+ } else {
+ /*EPR# 419220 -HW limitation to to */
+ cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkHardMin,
+ cz_get_eclk_level(hwmgr,
+ cz_hwmgr->vce_dpm.hard_min_clk,
+ PPSMC_MSG_SetEclkHardMin));
+
+ }
+ return 0;
+}
+
+int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_VCEPowerGating))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_VCEPowerOFF);
+ return 0;
+}
+
+int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_VCEPowerGating))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_VCEPowerON);
+ return 0;
+}
+
+static int cz_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ return cz_hwmgr->sys_info.bootup_uma_clock;
+}
+
+static int cz_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+ struct pp_power_state *ps;
+ struct cz_power_state *cz_ps;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ cz_ps = cast_PhwCzPowerState(&ps->hardware);
+
+ if (low)
+ return cz_ps->levels[0].engineClock;
+ else
+ return cz_ps->levels[cz_ps->level-1].engineClock;
+}
+
+static int cz_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
+ struct pp_hw_power_state *hw_ps)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+ struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps);
+
+ cz_ps->level = 1;
+ cz_ps->nbps_flags = 0;
+ cz_ps->bapm_flags = 0;
+ cz_ps->levels[0] = cz_hwmgr->boot_power_level;
+
+ return 0;
+}
+
+static int cz_dpm_get_pp_table_entry_callback(
+ struct pp_hwmgr *hwmgr,
+ struct pp_hw_power_state *hw_ps,
+ unsigned int index,
+ const void *clock_info)
+{
+ struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps);
+
+ const ATOM_PPLIB_CZ_CLOCK_INFO *cz_clock_info = clock_info;
+
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+ uint8_t clock_info_index = cz_clock_info->index;
+
+ if (clock_info_index > (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1))
+ clock_info_index = (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1);
+
+ cz_ps->levels[index].engineClock = table->entries[clock_info_index].clk;
+ cz_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v;
+
+ cz_ps->level = index + 1;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
+ cz_ps->levels[index].dsDividerIndex = 5;
+ cz_ps->levels[index].ssDividerIndex = 5;
+ }
+
+ return 0;
+}
+
+static int cz_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ unsigned long ret = 0;
+
+ result = pp_tables_get_num_of_entries(hwmgr, &ret);
+
+ return result ? 0 : ret;
+}
+
+static int cz_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+ unsigned long entry, struct pp_power_state *ps)
+{
+ int result;
+ struct cz_power_state *cz_ps;
+
+ ps->hardware.magic = PhwCz_Magic;
+
+ cz_ps = cast_PhwCzPowerState(&(ps->hardware));
+
+ result = pp_tables_get_entry(hwmgr, entry, ps,
+ cz_dpm_get_pp_table_entry_callback);
+
+ cz_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK;
+ cz_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK;
+
+ return result;
+}
+
+int cz_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+ return sizeof(struct cz_power_state);
+}
+
+static void
+cz_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
+{
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+ struct phm_vce_clock_voltage_dependency_table *vce_table =
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table;
+
+ struct phm_uvd_clock_voltage_dependency_table *uvd_table =
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
+
+ uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
+ TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
+ uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+ TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
+ uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+ TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
+
+ uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
+ uint16_t vddnb, vddgfx;
+ int result;
+
+ if (sclk_index >= NUM_SCLK_LEVELS) {
+ seq_printf(m, "\n invalid sclk dpm profile %d\n", sclk_index);
+ } else {
+ sclk = table->entries[sclk_index].clk;
+ seq_printf(m, "\n index: %u sclk: %u MHz\n", sclk_index, sclk/100);
+ }
+
+ tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
+ CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
+ vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
+ tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
+ CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
+ vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
+ seq_printf(m, "\n vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
+
+ seq_printf(m, "\n uvd %sabled\n", cz_hwmgr->uvd_power_gated ? "dis" : "en");
+ if (!cz_hwmgr->uvd_power_gated) {
+ if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+ seq_printf(m, "\n invalid uvd dpm level %d\n", uvd_index);
+ } else {
+ vclk = uvd_table->entries[uvd_index].vclk;
+ dclk = uvd_table->entries[uvd_index].dclk;
+ seq_printf(m, "\n index: %u uvd vclk: %u MHz dclk: %u MHz\n", uvd_index, vclk/100, dclk/100);
+ }
+ }
+
+ seq_printf(m, "\n vce %sabled\n", cz_hwmgr->vce_power_gated ? "dis" : "en");
+ if (!cz_hwmgr->vce_power_gated) {
+ if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+ seq_printf(m, "\n invalid vce dpm level %d\n", vce_index);
+ } else {
+ ecclk = vce_table->entries[vce_index].ecclk;
+ seq_printf(m, "\n index: %u vce ecclk: %u MHz\n", vce_index, ecclk/100);
+ }
+ }
+
+ result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);
+ if (0 == result) {
+ activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
+ activity_percent = activity_percent > 100 ? 100 : activity_percent;
+ } else {
+ activity_percent = 50;
+ }
+
+ seq_printf(m, "\n [GPU load]: %u %%\n\n", activity_percent);
+}
+
+static void cz_hw_print_display_cfg(
+ const struct cc6_settings *cc6_settings)
+{
+ PP_DBG_LOG("New Display Configuration:\n");
+
+ PP_DBG_LOG(" cpu_cc6_disable: %d\n",
+ cc6_settings->cpu_cc6_disable);
+ PP_DBG_LOG(" cpu_pstate_disable: %d\n",
+ cc6_settings->cpu_pstate_disable);
+ PP_DBG_LOG(" nb_pstate_switch_disable: %d\n",
+ cc6_settings->nb_pstate_switch_disable);
+ PP_DBG_LOG(" cpu_pstate_separation_time: %d\n\n",
+ cc6_settings->cpu_pstate_separation_time);
+}
+
+ static int cz_set_cpu_power_state(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+ uint32_t data = 0;
+
+ if (hw_data->cc6_settings.cc6_setting_changed == true) {
+
+ hw_data->cc6_settings.cc6_setting_changed = false;
+
+ cz_hw_print_display_cfg(&hw_data->cc6_settings);
+
+ data |= (hw_data->cc6_settings.cpu_pstate_separation_time
+ & PWRMGT_SEPARATION_TIME_MASK)
+ << PWRMGT_SEPARATION_TIME_SHIFT;
+
+ data|= (hw_data->cc6_settings.cpu_cc6_disable ? 0x1 : 0x0)
+ << PWRMGT_DISABLE_CPU_CSTATES_SHIFT;
+
+ data|= (hw_data->cc6_settings.cpu_pstate_disable ? 0x1 : 0x0)
+ << PWRMGT_DISABLE_CPU_PSTATES_SHIFT;
+
+ PP_DBG_LOG("SetDisplaySizePowerParams data: 0x%X\n",
+ data);
+
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetDisplaySizePowerParams,
+ data);
+ }
+
+ return 0;
+}
+
+
+ static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
+ bool cc6_disable, bool pstate_disable, bool pstate_switch_disable)
+ {
+ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend);
+
+ if (separation_time !=
+ hw_data->cc6_settings.cpu_pstate_separation_time
+ || cc6_disable !=
+ hw_data->cc6_settings.cpu_cc6_disable
+ || pstate_disable !=
+ hw_data->cc6_settings.cpu_pstate_disable
+ || pstate_switch_disable !=
+ hw_data->cc6_settings.nb_pstate_switch_disable) {
+
+ hw_data->cc6_settings.cc6_setting_changed = true;
+
+ hw_data->cc6_settings.cpu_pstate_separation_time =
+ separation_time;
+ hw_data->cc6_settings.cpu_cc6_disable =
+ cc6_disable;
+ hw_data->cc6_settings.cpu_pstate_disable =
+ pstate_disable;
+ hw_data->cc6_settings.nb_pstate_switch_disable =
+ pstate_switch_disable;
+
+ }
+
+ return 0;
+}
+
+ static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr,
+ struct amd_pp_dal_clock_info*info)
+{
+ uint32_t i;
+ const struct phm_clock_voltage_dependency_table * table =
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl;
+ const struct phm_clock_and_voltage_limits* limits =
+ &hwmgr->dyn_state.max_clock_voltage_on_ac;
+
+ info->engine_max_clock = limits->sclk;
+ info->memory_max_clock = limits->mclk;
+
+ for (i = table->count - 1; i > 0; i--) {
+
+ if (limits->vddc >= table->entries[i].v) {
+ info->level = table->entries[i].clk;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static const struct pp_hwmgr_func cz_hwmgr_funcs = {
+ .backend_init = cz_hwmgr_backend_init,
+ .backend_fini = cz_hwmgr_backend_fini,
+ .asic_setup = NULL,
+ .apply_state_adjust_rules = cz_apply_state_adjust_rules,
+ .force_dpm_level = cz_dpm_force_dpm_level,
+ .get_power_state_size = cz_get_power_state_size,
+ .powerdown_uvd = cz_dpm_powerdown_uvd,
+ .powergate_uvd = cz_dpm_powergate_uvd,
+ .powergate_vce = cz_dpm_powergate_vce,
+ .get_mclk = cz_dpm_get_mclk,
+ .get_sclk = cz_dpm_get_sclk,
+ .patch_boot_state = cz_dpm_patch_boot_state,
+ .get_pp_table_entry = cz_dpm_get_pp_table_entry,
+ .get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries,
+ .print_current_perforce_level = cz_print_current_perforce_level,
+ .set_cpu_power_state = cz_set_cpu_power_state,
+ .store_cc6_data = cz_store_cc6_data,
+ .get_dal_power_level= cz_get_dal_power_level,
+};
+
+int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+ struct cz_hwmgr *cz_hwmgr;
+ int ret = 0;
+
+ cz_hwmgr = kzalloc(sizeof(struct cz_hwmgr), GFP_KERNEL);
+ if (cz_hwmgr == NULL)
+ return -ENOMEM;
+
+ hwmgr->backend = cz_hwmgr;
+ hwmgr->hwmgr_func = &cz_hwmgr_funcs;
+ hwmgr->pptable_func = &pptable_funcs;
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
new file mode 100644
index 000000000000..c477f1cf3f23
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2015 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 _CZ_HWMGR_H_
+#define _CZ_HWMGR_H_
+
+#include "cgs_common.h"
+#include "ppatomctrl.h"
+
+#define CZ_NUM_NBPSTATES 4
+#define CZ_NUM_NBPMEMORYCLOCK 2
+#define MAX_DISPLAY_CLOCK_LEVEL 8
+#define CZ_AT_DFLT 30
+#define CZ_MAX_HARDWARE_POWERLEVELS 8
+#define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
+#define CZ_MIN_DEEP_SLEEP_SCLK 800
+
+/* Carrizo device IDs */
+#define DEVICE_ID_CZ_9870 0x9870
+#define DEVICE_ID_CZ_9874 0x9874
+#define DEVICE_ID_CZ_9875 0x9875
+#define DEVICE_ID_CZ_9876 0x9876
+#define DEVICE_ID_CZ_9877 0x9877
+
+#define PHMCZ_WRITE_SMC_REGISTER(device, reg, value) \
+ cgs_write_ind_register(device, CGS_IND_REG__SMC, ix##reg, value)
+
+struct cz_dpm_entry {
+ uint32_t soft_min_clk;
+ uint32_t hard_min_clk;
+ uint32_t soft_max_clk;
+ uint32_t hard_max_clk;
+};
+
+struct cz_sys_info {
+ uint32_t bootup_uma_clock;
+ uint32_t bootup_engine_clock;
+ uint32_t dentist_vco_freq;
+ uint32_t nb_dpm_enable;
+ uint32_t nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK];
+ uint32_t nbp_n_clock[CZ_NUM_NBPSTATES];
+ uint16_t nbp_voltage_index[CZ_NUM_NBPSTATES];
+ uint32_t display_clock[MAX_DISPLAY_CLOCK_LEVEL];
+ uint16_t bootup_nb_voltage_index;
+ uint8_t htc_tmp_lmt;
+ uint8_t htc_hyst_lmt;
+ uint32_t system_config;
+ uint32_t uma_channel_number;
+};
+
+#define MAX_DISPLAYPHY_IDS 0x8
+#define DISPLAYPHY_LANEMASK 0xF
+#define UNKNOWN_TRANSMITTER_PHY_ID (-1)
+
+#define DISPLAYPHY_PHYID_SHIFT 24
+#define DISPLAYPHY_LANESELECT_SHIFT 16
+
+#define DISPLAYPHY_RX_SELECT 0x1
+#define DISPLAYPHY_TX_SELECT 0x2
+#define DISPLAYPHY_CORE_SELECT 0x4
+
+#define DDI_POWERGATING_ARG(phyID, lanemask, rx, tx, core) \
+ (((uint32_t)(phyID))<<DISPLAYPHY_PHYID_SHIFT | \
+ ((uint32_t)(lanemask))<<DISPLAYPHY_LANESELECT_SHIFT | \
+ ((rx) ? DISPLAYPHY_RX_SELECT : 0) | \
+ ((tx) ? DISPLAYPHY_TX_SELECT : 0) | \
+ ((core) ? DISPLAYPHY_CORE_SELECT : 0))
+
+struct cz_display_phy_info_entry {
+ uint8_t phy_present;
+ uint8_t active_lane_mapping;
+ uint8_t display_config_type;
+ uint8_t active_number_of_lanes;
+};
+
+#define CZ_MAX_DISPLAYPHY_IDS 10
+
+struct cz_display_phy_info {
+ bool display_phy_access_initialized;
+ struct cz_display_phy_info_entry entries[CZ_MAX_DISPLAYPHY_IDS];
+};
+
+struct cz_power_level {
+ uint32_t engineClock;
+ uint8_t vddcIndex;
+ uint8_t dsDividerIndex;
+ uint8_t ssDividerIndex;
+ uint8_t allowGnbSlow;
+ uint8_t forceNBPstate;
+ uint8_t display_wm;
+ uint8_t vce_wm;
+ uint8_t numSIMDToPowerDown;
+ uint8_t hysteresis_up;
+ uint8_t rsv[3];
+};
+
+struct cz_uvd_clocks {
+ uint32_t vclk;
+ uint32_t dclk;
+ uint32_t vclk_low_divider;
+ uint32_t vclk_high_divider;
+ uint32_t dclk_low_divider;
+ uint32_t dclk_high_divider;
+};
+
+enum cz_pstate_previous_action {
+ DO_NOTHING = 1,
+ FORCE_HIGH,
+ CANCEL_FORCE_HIGH
+};
+
+struct pp_disable_nb_ps_flags {
+ union {
+ struct {
+ uint32_t entry : 1;
+ uint32_t display : 1;
+ uint32_t driver: 1;
+ uint32_t vce : 1;
+ uint32_t uvd : 1;
+ uint32_t acp : 1;
+ uint32_t reserved: 26;
+ } bits;
+ uint32_t u32All;
+ };
+};
+
+struct cz_power_state {
+ unsigned int magic;
+ uint32_t level;
+ struct cz_uvd_clocks uvd_clocks;
+ uint32_t evclk;
+ uint32_t ecclk;
+ uint32_t samclk;
+ uint32_t acpclk;
+ bool need_dfs_bypass;
+ uint32_t nbps_flags;
+ uint32_t bapm_flags;
+ uint8_t dpm_0_pg_nb_ps_low;
+ uint8_t dpm_0_pg_nb_ps_high;
+ uint8_t dpm_x_nb_ps_low;
+ uint8_t dpm_x_nb_ps_high;
+ enum cz_pstate_previous_action action;
+ struct cz_power_level levels[CZ_MAX_HARDWARE_POWERLEVELS];
+ struct pp_disable_nb_ps_flags disable_nb_ps_flag;
+};
+
+#define DPMFlags_SCLK_Enabled 0x00000001
+#define DPMFlags_UVD_Enabled 0x00000002
+#define DPMFlags_VCE_Enabled 0x00000004
+#define DPMFlags_ACP_Enabled 0x00000008
+#define DPMFlags_ForceHighestValid 0x40000000
+#define DPMFlags_Debug 0x80000000
+
+#define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 /* bit 0 */
+#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000
+#define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000 /* bit 23 */
+#define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000 /* bit 24 */
+
+struct cc6_settings {
+ bool cc6_setting_changed;
+ bool nb_pstate_switch_disable;/* controls NB PState switch */
+ bool cpu_cc6_disable; /* controls CPU CState switch ( on or off) */
+ bool cpu_pstate_disable;
+ uint32_t cpu_pstate_separation_time;
+};
+
+struct cz_hwmgr {
+ uint32_t activity_target[CZ_MAX_HARDWARE_POWERLEVELS];
+ uint32_t dpm_interval;
+
+ uint32_t voltage_drop_threshold;
+
+ uint32_t voting_rights_clients;
+
+ uint32_t disable_driver_thermal_policy;
+
+ uint32_t static_screen_threshold;
+
+ uint32_t gfx_power_gating_threshold;
+
+ uint32_t activity_hysteresis;
+ uint32_t bootup_sclk_divider;
+ uint32_t gfx_ramp_step;
+ uint32_t gfx_ramp_delay; /* in micro-seconds */
+
+ uint32_t thermal_auto_throttling_treshold;
+
+ struct cz_sys_info sys_info;
+
+ struct cz_power_level boot_power_level;
+ struct cz_power_state *cz_current_ps;
+ struct cz_power_state *cz_requested_ps;
+
+ uint32_t mgcg_cgtt_local0;
+ uint32_t mgcg_cgtt_local1;
+
+ uint32_t tdr_clock; /* in 10khz unit */
+
+ uint32_t ddi_power_gating_disabled;
+ uint32_t disable_gfx_power_gating_in_uvd;
+ uint32_t disable_nb_ps3_in_battery;
+
+ uint32_t lock_nb_ps_in_uvd_play_back;
+
+ struct cz_display_phy_info display_phy_info;
+ uint32_t vce_slow_sclk_threshold; /* default 200mhz */
+ uint32_t dce_slow_sclk_threshold; /* default 300mhz */
+ uint32_t min_sclk_did; /* minimum sclk divider */
+
+ bool disp_clk_bypass;
+ bool disp_clk_bypass_pending;
+ uint32_t bapm_enabled;
+ uint32_t clock_slow_down_freq;
+ uint32_t skip_clock_slow_down;
+ uint32_t enable_nb_ps_policy;
+ uint32_t voltage_drop_in_dce_power_gating;
+ uint32_t uvd_dpm_interval;
+ uint32_t override_dynamic_mgpg;
+ uint32_t lclk_deep_enabled;
+
+ uint32_t uvd_performance;
+
+ bool video_start;
+ bool battery_state;
+ uint32_t lowest_valid;
+ uint32_t highest_valid;
+ uint32_t high_voltage_threshold;
+ uint32_t is_nb_dpm_enabled;
+ struct cc6_settings cc6_settings;
+ uint32_t is_voltage_island_enabled;
+
+ bool pgacpinit;
+
+ uint8_t disp_config;
+
+ /* PowerTune */
+ uint32_t power_containment_features;
+ bool cac_enabled;
+ bool disable_uvd_power_tune_feature;
+ bool enable_ba_pm_feature;
+ bool enable_tdc_limit_feature;
+
+ uint32_t sram_end;
+ uint32_t dpm_table_start;
+ uint32_t soft_regs_start;
+
+ uint8_t uvd_level_count;
+ uint8_t vce_level_count;
+
+ uint8_t acp_level_count;
+ uint8_t samu_level_count;
+ uint32_t fps_high_threshold;
+ uint32_t fps_low_threshold;
+
+ uint32_t dpm_flags;
+ struct cz_dpm_entry sclk_dpm;
+ struct cz_dpm_entry uvd_dpm;
+ struct cz_dpm_entry vce_dpm;
+ struct cz_dpm_entry acp_dpm;
+
+ uint8_t uvd_boot_level;
+ uint8_t vce_boot_level;
+ uint8_t acp_boot_level;
+ uint8_t samu_boot_level;
+ uint8_t uvd_interval;
+ uint8_t vce_interval;
+ uint8_t acp_interval;
+ uint8_t samu_interval;
+
+ uint8_t graphics_interval;
+ uint8_t graphics_therm_throttle_enable;
+ uint8_t graphics_voltage_change_enable;
+
+ uint8_t graphics_clk_slow_enable;
+ uint8_t graphics_clk_slow_divider;
+
+ uint32_t display_cac;
+ uint32_t low_sclk_interrupt_threshold;
+
+ uint32_t dram_log_addr_h;
+ uint32_t dram_log_addr_l;
+ uint32_t dram_log_phy_addr_h;
+ uint32_t dram_log_phy_addr_l;
+ uint32_t dram_log_buff_size;
+
+ bool uvd_power_gated;
+ bool vce_power_gated;
+ bool samu_power_gated;
+ bool acp_power_gated;
+ bool acp_power_up_no_dsp;
+ uint32_t active_process_mask;
+
+ uint32_t max_sclk_level;
+ uint32_t num_of_clk_entries;
+};
+
+struct pp_hwmgr;
+
+int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr);
+int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr);
+int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr);
+#endif /* _CZ_HWMGR_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
new file mode 100644
index 000000000000..e68edf06ed73
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "fiji_clockpowergating.h"
+#include "fiji_ppsmc.h"
+#include "fiji_hwmgr.h"
+
+int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ data->uvd_power_gated = false;
+ data->vce_power_gated = false;
+ data->samu_power_gated = false;
+ data->acp_power_gated = false;
+
+ return 0;
+}
+
+int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (data->uvd_power_gated == bgate)
+ return 0;
+
+ data->uvd_power_gated = bgate;
+
+ if (bgate)
+ fiji_update_uvd_dpm(hwmgr, true);
+ else
+ fiji_update_uvd_dpm(hwmgr, false);
+
+ return 0;
+}
+
+int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_set_power_state_input states;
+ const struct pp_power_state *pcurrent;
+ struct pp_power_state *requested;
+
+ if (data->vce_power_gated == bgate)
+ return 0;
+
+ data->vce_power_gated = bgate;
+
+ pcurrent = hwmgr->current_ps;
+ requested = hwmgr->request_ps;
+
+ states.pcurrent_state = &(pcurrent->hardware);
+ states.pnew_state = &(requested->hardware);
+
+ fiji_update_vce_dpm(hwmgr, &states);
+ fiji_enable_disable_vce_dpm(hwmgr, !bgate);
+
+ return 0;
+}
+
+int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (data->samu_power_gated == bgate)
+ return 0;
+
+ data->samu_power_gated = bgate;
+
+ if (bgate)
+ fiji_update_samu_dpm(hwmgr, true);
+ else
+ fiji_update_samu_dpm(hwmgr, false);
+
+ return 0;
+}
+
+int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (data->acp_power_gated == bgate)
+ return 0;
+
+ data->acp_power_gated = bgate;
+
+ if (bgate)
+ fiji_update_acp_dpm(hwmgr, true);
+ else
+ fiji_update_acp_dpm(hwmgr, false);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
new file mode 100644
index 000000000000..33af5f511ab8
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_clockpowergating.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 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 _FIJI_CLOCK_POWER_GATING_H_
+#define _FIJI_CLOCK_POWER_GATING_H_
+
+#include "fiji_hwmgr.h"
+#include "pp_asicblocks.h"
+
+extern int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
+extern int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
+#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
new file mode 100644
index 000000000000..32d43e8fecb2
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_dyn_defaults.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 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 FIJI_DYN_DEFAULTS_H
+#define FIJI_DYN_DEFAULTS_H
+
+/** \file
+* Volcanic Islands Dynamic default parameters.
+*/
+
+enum FIJIdpm_TrendDetection
+{
+ FIJIAdpm_TrendDetection_AUTO,
+ FIJIAdpm_TrendDetection_UP,
+ FIJIAdpm_TrendDetection_DOWN
+};
+typedef enum FIJIdpm_TrendDetection FIJIdpm_TrendDetection;
+
+/* We need to fill in the default values!!!!!!!!!!!!!!!!!!!!!!! */
+
+/* Bit vector representing same fields as hardware register. */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy ????
+ * HDP_busy
+ * IH_busy
+ * UVD_busy
+ * VCE_busy
+ * ACP_busy
+ * SAMU_busy
+ * SDMA enabled */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. ????
+ * SH_Gfx_busy
+ * RB_Gfx_busy
+ * VCE_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility.
+ * FE_Gfx_busy
+ * RB_Gfx_busy
+ * ACP_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility.
+ * FE_Gfx_busy
+ * SH_Gfx_busy
+ * UVD_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy
+ * VCE_busy
+ * ACP_busy
+ * SAMU_busy */
+
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP */
+#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP */
+
+
+/* thermal protection counter (units). */
+#define PPFIJI_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
+
+/* static screen threshold unit */
+#define PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT 0
+
+/* static screen threshold */
+#define PPFIJI_STATICSCREENTHRESHOLD_DFLT 0x00C8
+
+/* gfx idle clock stop threshold */
+#define PPFIJI_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
+
+/* Fixed reference divider to use when building baby stepping tables. */
+#define PPFIJI_REFERENCEDIVIDER_DFLT 4
+
+/* ULV voltage change delay time
+ * Used to be delay_vreg in N.I. split for S.I.
+ * Using N.I. delay_vreg value as default
+ * ReferenceClock = 2700
+ * VoltageResponseTime = 1000
+ * VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
+ */
+#define PPFIJI_ULVVOLTAGECHANGEDELAY_DFLT 1687
+
+#define PPFIJI_CGULVPARAMETER_DFLT 0x00040035
+#define PPFIJI_CGULVCONTROL_DFLT 0x00007450
+#define PPFIJI_TARGETACTIVITY_DFLT 30 /* 30%*/
+#define PPFIJI_MCLK_TARGETACTIVITY_DFLT 10 /* 10% */
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
new file mode 100644
index 000000000000..28031a7eddba
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c
@@ -0,0 +1,5127 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include "linux/delay.h"
+
+#include "hwmgr.h"
+#include "fiji_smumgr.h"
+#include "atombios.h"
+#include "hardwaremanager.h"
+#include "ppatomctrl.h"
+#include "atombios.h"
+#include "cgs_common.h"
+#include "fiji_dyn_defaults.h"
+#include "fiji_powertune.h"
+#include "smu73.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+#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 "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "pppcielanes.h"
+#include "fiji_hwmgr.h"
+#include "tonga_processpptables.h"
+#include "tonga_pptable.h"
+#include "pp_debug.h"
+#include "pp_acpi.h"
+#include "amd_pcie_helpers.h"
+#include "cgs_linux.h"
+#include "ppinterrupt.h"
+
+#include "fiji_clockpowergating.h"
+#include "fiji_thermal.h"
+
+#define VOLTAGE_SCALE 4
+#define SMC_RAM_END 0x40000
+#define VDDC_VDDCI_DELTA 300
+
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+
+#define MC_CG_ARB_FREQ_F0 0x0a /* boot-up default */
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+/* From smc_reg.h */
+#define SMC_CG_IND_START 0xc0030000
+#define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND */
+
+#define VOLTAGE_SCALE 4
+#define VOLTAGE_VID_OFFSET_SCALE1 625
+#define VOLTAGE_VID_OFFSET_SCALE2 100
+
+#define VDDC_VDDCI_DELTA 300
+
+#define ixSWRST_COMMAND_1 0x1400103
+#define MC_SEQ_CNTL__CAC_EN_MASK 0x40000000
+
+/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
+enum DPM_EVENT_SRC {
+ DPM_EVENT_SRC_ANALOG = 0, /* Internal analog trip point */
+ DPM_EVENT_SRC_EXTERNAL = 1, /* External (GPIO 17) signal */
+ DPM_EVENT_SRC_DIGITAL = 2, /* Internal digital trip point (DIG_THERM_DPM) */
+ DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3, /* Internal analog or external */
+ DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 /* Internal digital or external */
+};
+
+
+/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
+ * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
+ */
+uint16_t fiji_clock_stretcher_lookup_table[2][4] = { {600, 1050, 3, 0},
+ {600, 1050, 6, 1} };
+
+/* [FF, SS] type, [] 4 voltage ranges, and
+ * [Floor Freq, Boundary Freq, VID min , VID max]
+ */
+uint32_t fiji_clock_stretcher_ddt_table[2][4][4] =
+{ { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
+ { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
+
+/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
+ * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
+ */
+uint8_t fiji_clock_stretch_amount_conversion[2][6] = { {0, 1, 3, 2, 4, 5},
+ {0, 2, 4, 5, 6, 5} };
+
+const unsigned long PhwFiji_Magic = (unsigned long)(PHM_VIslands_Magic);
+
+struct fiji_power_state *cast_phw_fiji_power_state(
+ struct pp_hw_power_state *hw_ps)
+{
+ PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
+ "Invalid Powerstate Type!",
+ return NULL;);
+
+ return (struct fiji_power_state *)hw_ps;
+}
+
+const struct fiji_power_state *cast_const_phw_fiji_power_state(
+ const struct pp_hw_power_state *hw_ps)
+{
+ PP_ASSERT_WITH_CODE((PhwFiji_Magic == hw_ps->magic),
+ "Invalid Powerstate Type!",
+ return NULL;);
+
+ return (const struct fiji_power_state *)hw_ps;
+}
+
+static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+ return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON))
+ ? true : false;
+}
+
+static void fiji_init_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_ulv_parm *ulv = &data->ulv;
+
+ ulv->cg_ulv_parameter = PPFIJI_CGULVPARAMETER_DFLT;
+ data->voting_rights_clients0 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0;
+ data->voting_rights_clients1 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1;
+ data->voting_rights_clients2 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2;
+ data->voting_rights_clients3 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3;
+ data->voting_rights_clients4 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4;
+ data->voting_rights_clients5 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5;
+ data->voting_rights_clients6 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6;
+ data->voting_rights_clients7 = PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7;
+
+ data->static_screen_threshold_unit =
+ PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT;
+ data->static_screen_threshold =
+ PPFIJI_STATICSCREENTHRESHOLD_DFLT;
+
+ /* Unset ABM cap as it moved to DAL.
+ * Add PHM_PlatformCaps_NonABMSupportInPPLib
+ * for re-direct ABM related request to DAL
+ */
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ABM);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_NonABMSupportInPPLib);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicACTiming);
+
+ fiji_initialize_power_tune_defaults(hwmgr);
+
+ data->mclk_stutter_mode_threshold = 60000;
+ data->pcie_gen_performance.max = PP_PCIEGen1;
+ data->pcie_gen_performance.min = PP_PCIEGen3;
+ data->pcie_gen_power_saving.max = PP_PCIEGen1;
+ data->pcie_gen_power_saving.min = PP_PCIEGen3;
+ data->pcie_lane_performance.max = 0;
+ data->pcie_lane_performance.min = 16;
+ data->pcie_lane_power_saving.max = 0;
+ data->pcie_lane_power_saving.min = 16;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicUVDState);
+}
+
+static int fiji_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table,
+ uint16_t virtual_voltage_id, int32_t *sclk)
+{
+ uint8_t entryId;
+ uint8_t voltageId;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
+
+ /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
+ for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
+ voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
+ if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
+ break;
+ }
+
+ PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
+ "Can't find requested voltage id in vdd_dep_on_sclk table!",
+ return -EINVAL;
+ );
+
+ *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
+
+ return 0;
+}
+
+/**
+* Get Leakage VDDC based on leakage ID.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_get_evv_voltages(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint16_t vv_id;
+ uint16_t vddc = 0;
+ uint16_t evv_default = 1150;
+ uint16_t i, j;
+ uint32_t sclk = 0;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)hwmgr->pptable;
+ struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+ table_info->vdd_dep_on_sclk;
+ int result;
+
+ for (i = 0; i < FIJI_MAX_LEAKAGE_COUNT; i++) {
+ vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+ if (!fiji_get_sclk_for_voltage_evv(hwmgr,
+ table_info->vddc_lookup_table, vv_id, &sclk)) {
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher)) {
+ for (j = 1; j < sclk_table->count; j++) {
+ if (sclk_table->entries[j].clk == sclk &&
+ sclk_table->entries[j].cks_enable == 0) {
+ sclk += 5000;
+ break;
+ }
+ }
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableDriverEVV))
+ result = atomctrl_calculate_voltage_evv_on_sclk(hwmgr,
+ VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc, i, true);
+ else
+ result = -EINVAL;
+
+ if (result)
+ result = atomctrl_get_voltage_evv_on_sclk(hwmgr,
+ VOLTAGE_TYPE_VDDC, sclk,vv_id, &vddc);
+
+ /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
+ PP_ASSERT_WITH_CODE((vddc < 2000),
+ "Invalid VDDC value, greater than 2v!", result = -EINVAL;);
+
+ if (result)
+ /* 1.15V is the default safe value for Fiji */
+ vddc = evv_default;
+
+ /* the voltage should not be zero nor equal to leakage ID */
+ if (vddc != 0 && vddc != vv_id) {
+ data->vddc_leakage.actual_voltage
+ [data->vddc_leakage.count] = vddc;
+ data->vddc_leakage.leakage_id
+ [data->vddc_leakage.count] = vv_id;
+ data->vddc_leakage.count++;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Change virtual leakage voltage to actual value.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param pointer to changing voltage
+ * @param pointer to leakage table
+ */
+static void fiji_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
+ uint16_t *voltage, struct fiji_leakage_voltage *leakage_table)
+{
+ uint32_t index;
+
+ /* search for leakage voltage ID 0xff01 ~ 0xff08 */
+ for (index = 0; index < leakage_table->count; index++) {
+ /* if this voltage matches a leakage voltage ID */
+ /* patch with actual leakage voltage */
+ if (leakage_table->leakage_id[index] == *voltage) {
+ *voltage = leakage_table->actual_voltage[index];
+ break;
+ }
+ }
+
+ if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
+ printk(KERN_ERR "Voltage value looks like a Leakage ID but it's not patched \n");
+}
+
+/**
+* Patch voltage lookup table by EVV leakages.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pointer to voltage lookup table
+* @param pointer to leakage table
+* @return always 0
+*/
+static int fiji_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table,
+ struct fiji_leakage_voltage *leakage_table)
+{
+ uint32_t i;
+
+ for (i = 0; i < lookup_table->count; i++)
+ fiji_patch_with_vdd_leakage(hwmgr,
+ &lookup_table->entries[i].us_vdd, leakage_table);
+
+ return 0;
+}
+
+static int fiji_patch_clock_voltage_limits_with_vddc_leakage(
+ struct pp_hwmgr *hwmgr, struct fiji_leakage_voltage *leakage_table,
+ uint16_t *vddc)
+{
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ fiji_patch_with_vdd_leakage(hwmgr, (uint16_t *)vddc, leakage_table);
+ hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+ table_info->max_clock_voltage_on_dc.vddc;
+ return 0;
+}
+
+static int fiji_patch_voltage_dependency_tables_with_lookup_table(
+ struct pp_hwmgr *hwmgr)
+{
+ uint8_t entryId;
+ uint8_t voltageId;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+ table_info->vdd_dep_on_sclk;
+ struct phm_ppt_v1_clock_voltage_dependency_table *mclk_table =
+ table_info->vdd_dep_on_mclk;
+ struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+ table_info->mm_dep_table;
+
+ for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+ voltageId = sclk_table->entries[entryId].vddInd;
+ sclk_table->entries[entryId].vddc =
+ table_info->vddc_lookup_table->entries[voltageId].us_vdd;
+ }
+
+ for (entryId = 0; entryId < mclk_table->count; ++entryId) {
+ voltageId = mclk_table->entries[entryId].vddInd;
+ mclk_table->entries[entryId].vddc =
+ table_info->vddc_lookup_table->entries[voltageId].us_vdd;
+ }
+
+ for (entryId = 0; entryId < mm_table->count; ++entryId) {
+ voltageId = mm_table->entries[entryId].vddcInd;
+ mm_table->entries[entryId].vddc =
+ table_info->vddc_lookup_table->entries[voltageId].us_vdd;
+ }
+
+ return 0;
+
+}
+
+static int fiji_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+ /* Need to determine if we need calculated voltage. */
+ return 0;
+}
+
+static int fiji_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
+{
+ /* Need to determine if we need calculated voltage from mm table. */
+ return 0;
+}
+
+static int fiji_sort_lookup_table(struct pp_hwmgr *hwmgr,
+ struct phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+ uint32_t table_size, i, j;
+ struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
+ table_size = lookup_table->count;
+
+ PP_ASSERT_WITH_CODE(0 != lookup_table->count,
+ "Lookup table is empty", return -EINVAL);
+
+ /* Sorting voltages */
+ for (i = 0; i < table_size - 1; i++) {
+ for (j = i + 1; j > 0; j--) {
+ if (lookup_table->entries[j].us_vdd <
+ lookup_table->entries[j - 1].us_vdd) {
+ tmp_voltage_lookup_record = lookup_table->entries[j - 1];
+ lookup_table->entries[j - 1] = lookup_table->entries[j];
+ lookup_table->entries[j] = tmp_voltage_lookup_record;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int fiji_complete_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+ int tmp_result;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ tmp_result = fiji_patch_lookup_table_with_leakage(hwmgr,
+ table_info->vddc_lookup_table, &(data->vddc_leakage));
+ if (tmp_result)
+ result = tmp_result;
+
+ tmp_result = fiji_patch_clock_voltage_limits_with_vddc_leakage(hwmgr,
+ &(data->vddc_leakage), &table_info->max_clock_voltage_on_dc.vddc);
+ if (tmp_result)
+ result = tmp_result;
+
+ tmp_result = fiji_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
+ if (tmp_result)
+ result = tmp_result;
+
+ tmp_result = fiji_calc_voltage_dependency_tables(hwmgr);
+ if (tmp_result)
+ result = tmp_result;
+
+ tmp_result = fiji_calc_mm_voltage_dependency_table(hwmgr);
+ if (tmp_result)
+ result = tmp_result;
+
+ tmp_result = fiji_sort_lookup_table(hwmgr, table_info->vddc_lookup_table);
+ if(tmp_result)
+ result = tmp_result;
+
+ return result;
+}
+
+static int fiji_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ struct phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
+ table_info->vdd_dep_on_sclk;
+ struct phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
+ table_info->vdd_dep_on_mclk;
+
+ PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
+ "VDD dependency on SCLK table is missing. \
+ This table is mandatory", return -EINVAL);
+ PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
+ "VDD dependency on SCLK table has to have is missing. \
+ This table is mandatory", return -EINVAL);
+
+ PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
+ "VDD dependency on MCLK table is missing. \
+ This table is mandatory", return -EINVAL);
+ PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
+ "VDD dependency on MCLK table has to have is missing. \
+ This table is mandatory", return -EINVAL);
+
+ data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
+ data->max_vddc_in_pptable = (uint16_t)allowed_sclk_vdd_table->
+ entries[allowed_sclk_vdd_table->count - 1].vddc;
+
+ table_info->max_clock_voltage_on_ac.sclk =
+ allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
+ table_info->max_clock_voltage_on_ac.mclk =
+ allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
+ table_info->max_clock_voltage_on_ac.vddc =
+ allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+ table_info->max_clock_voltage_on_ac.vddci =
+ allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
+
+ hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
+ table_info->max_clock_voltage_on_ac.sclk;
+ hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
+ table_info->max_clock_voltage_on_ac.mclk;
+ hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
+ table_info->max_clock_voltage_on_ac.vddc;
+ hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
+ table_info->max_clock_voltage_on_ac.vddci;
+
+ return 0;
+}
+
+static uint16_t fiji_get_current_pcie_speed(struct pp_hwmgr *hwmgr)
+{
+ uint32_t speedCntl = 0;
+
+ /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
+ speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE,
+ ixPCIE_LC_SPEED_CNTL);
+ return((uint16_t)PHM_GET_FIELD(speedCntl,
+ PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
+}
+
+static int fiji_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr)
+{
+ uint32_t link_width;
+
+ /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */
+ link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
+ PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD);
+
+ PP_ASSERT_WITH_CODE((7 >= link_width),
+ "Invalid PCIe lane width!", return 0);
+
+ return decode_pcie_lane_width(link_width);
+}
+
+/** Patch the Boot State to match VBIOS boot clocks and voltage.
+*
+* @param hwmgr Pointer to the hardware manager.
+* @param pPowerState The address of the PowerState instance being created.
+*
+*/
+static int fiji_patch_boot_state(struct pp_hwmgr *hwmgr,
+ struct pp_hw_power_state *hw_ps)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_power_state *ps = (struct fiji_power_state *)hw_ps;
+ ATOM_FIRMWARE_INFO_V2_2 *fw_info;
+ uint16_t size;
+ uint8_t frev, crev;
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+ /* First retrieve the Boot clocks and VDDC from the firmware info table.
+ * We assume here that fw_info is unchanged if this call fails.
+ */
+ fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
+ hwmgr->device, index,
+ &size, &frev, &crev);
+ if (!fw_info)
+ /* During a test, there is no firmware info table. */
+ return 0;
+
+ /* Patch the state. */
+ data->vbios_boot_state.sclk_bootup_value =
+ le32_to_cpu(fw_info->ulDefaultEngineClock);
+ data->vbios_boot_state.mclk_bootup_value =
+ le32_to_cpu(fw_info->ulDefaultMemoryClock);
+ data->vbios_boot_state.mvdd_bootup_value =
+ le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
+ data->vbios_boot_state.vddc_bootup_value =
+ le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+ data->vbios_boot_state.vddci_bootup_value =
+ le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
+ data->vbios_boot_state.pcie_gen_bootup_value =
+ fiji_get_current_pcie_speed(hwmgr);
+ data->vbios_boot_state.pcie_lane_bootup_value =
+ (uint16_t)fiji_get_current_pcie_lane_number(hwmgr);
+
+ /* set boot power state */
+ ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
+ ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
+ ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
+ ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
+
+ return 0;
+}
+
+static int fiji_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t i;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ bool stay_in_boot;
+ int result;
+
+ data->dll_default_on = false;
+ data->sram_end = SMC_RAM_END;
+
+ for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++)
+ data->activity_target[i] = FIJI_AT_DFLT;
+
+ data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
+
+ data->mclk_activity_target = PPFIJI_MCLK_TARGETACTIVITY_DFLT;
+ data->mclk_dpm0_activity_target = 0xa;
+
+ data->sclk_dpm_key_disabled = 0;
+ data->mclk_dpm_key_disabled = 0;
+ data->pcie_dpm_key_disabled = 0;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UnTabledHardwareInterface);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkDeepSleep);
+
+ data->gpio_debug = 0;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicPatchPowerState);
+
+ /* need to set voltage control types before EVV patching */
+ data->voltage_control = FIJI_VOLTAGE_CONTROL_NONE;
+ data->vddci_control = FIJI_VOLTAGE_CONTROL_NONE;
+ data->mvdd_control = FIJI_VOLTAGE_CONTROL_NONE;
+
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
+ data->voltage_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableMVDDControl))
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
+ data->mvdd_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
+
+ if (data->mvdd_control == FIJI_VOLTAGE_CONTROL_NONE)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableMVDDControl);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ControlVDDCI)) {
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
+ data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_GPIO;
+ else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
+ data->vddci_control = FIJI_VOLTAGE_CONTROL_BY_SVID2;
+ }
+
+ if (data->vddci_control == FIJI_VOLTAGE_CONTROL_NONE)
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ControlVDDCI);
+
+ if (table_info && table_info->cac_dtp_table->usClockStretchAmount)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher);
+
+ fiji_init_dpm_defaults(hwmgr);
+
+ /* Get leakage voltage based on leakage ID. */
+ fiji_get_evv_voltages(hwmgr);
+
+ /* Patch our voltage dependency table with actual leakage voltage
+ * We need to perform leakage translation before it's used by other functions
+ */
+ fiji_complete_dependency_tables(hwmgr);
+
+ /* Parse pptable data read from VBIOS */
+ fiji_set_private_data_based_on_pptable(hwmgr);
+
+ /* ULV Support */
+ data->ulv.ulv_supported = true; /* ULV feature is enabled by default */
+
+ /* Initalize Dynamic State Adjustment Rule Settings */
+ result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
+
+ if (!result) {
+ data->uvd_enabled = false;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableSMU7ThermalManagement);
+ data->vddc_phase_shed_control = false;
+ }
+
+ stay_in_boot = phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StayInBootState);
+
+ if (0 == result) {
+ struct cgs_system_info sys_info = {0};
+
+ data->is_tlu_enabled = 0;
+ hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
+ FIJI_MAX_HARDWARE_POWERLEVELS;
+ hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
+ hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_FanSpeedInTableIsRPM);
+
+ if (table_info->cac_dtp_table->usDefaultTargetOperatingTemp &&
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.ucFanControlMode) {
+ hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM =
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM;
+ hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM =
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM;
+ hwmgr->dyn_state.cac_dtp_table->usOperatingTempMinLimit =
+ table_info->cac_dtp_table->usOperatingTempMinLimit;
+ hwmgr->dyn_state.cac_dtp_table->usOperatingTempMaxLimit =
+ table_info->cac_dtp_table->usOperatingTempMaxLimit;
+ hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
+ table_info->cac_dtp_table->usDefaultTargetOperatingTemp;
+ hwmgr->dyn_state.cac_dtp_table->usOperatingTempStep =
+ table_info->cac_dtp_table->usOperatingTempStep;
+ hwmgr->dyn_state.cac_dtp_table->usTargetOperatingTemp =
+ table_info->cac_dtp_table->usTargetOperatingTemp;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ODFuzzyFanControlSupport);
+ }
+
+ sys_info.size = sizeof(struct cgs_system_info);
+ sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
+ result = cgs_query_system_info(hwmgr->device, &sys_info);
+ if (result)
+ data->pcie_gen_cap = 0x30007;
+ else
+ data->pcie_gen_cap = (uint32_t)sys_info.value;
+ if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+ data->pcie_spc_cap = 20;
+ sys_info.size = sizeof(struct cgs_system_info);
+ sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
+ result = cgs_query_system_info(hwmgr->device, &sys_info);
+ if (result)
+ data->pcie_lane_cap = 0x2f0000;
+ else
+ data->pcie_lane_cap = (uint32_t)sys_info.value;
+ } else {
+ /* Ignore return value in here, we are cleaning up a mess. */
+ tonga_hwmgr_backend_fini(hwmgr);
+ }
+
+ return 0;
+}
+
+/**
+ * Read clock related registers.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+static int fiji_read_clock_registers(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ data->clock_registers.vCG_SPLL_FUNC_CNTL =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_SPLL_FUNC_CNTL);
+ data->clock_registers.vCG_SPLL_FUNC_CNTL_2 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_SPLL_FUNC_CNTL_2);
+ data->clock_registers.vCG_SPLL_FUNC_CNTL_3 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_SPLL_FUNC_CNTL_3);
+ data->clock_registers.vCG_SPLL_FUNC_CNTL_4 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_SPLL_FUNC_CNTL_4);
+ data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_SPLL_SPREAD_SPECTRUM);
+ data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_SPLL_SPREAD_SPECTRUM_2);
+
+ return 0;
+}
+
+/**
+ * Find out if memory is GDDR5.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+static int fiji_get_memory_type(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t temp;
+
+ temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
+
+ data->is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
+ ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
+ MC_SEQ_MISC0_GDDR5_SHIFT));
+
+ return 0;
+}
+
+/**
+ * Enables Dynamic Power Management by SMC
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+static int fiji_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
+{
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ GENERAL_PWRMGT, STATIC_PM_EN, 1);
+
+ return 0;
+}
+
+/**
+ * Initialize PowerGating States for different engines
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+static int fiji_init_power_gate_state(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ data->uvd_power_gated = false;
+ data->vce_power_gated = false;
+ data->samu_power_gated = false;
+ data->acp_power_gated = false;
+ data->pg_acp_init = true;
+
+ return 0;
+}
+
+static int fiji_init_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ data->low_sclk_interrupt_threshold = 0;
+
+ return 0;
+}
+
+static int fiji_setup_asic_task(struct pp_hwmgr *hwmgr)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = fiji_read_clock_registers(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to read clock registers!", result = tmp_result);
+
+ tmp_result = fiji_get_memory_type(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to get memory type!", result = tmp_result);
+
+ tmp_result = fiji_enable_acpi_power_management(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable ACPI power management!", result = tmp_result);
+
+ tmp_result = fiji_init_power_gate_state(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to init power gate state!", result = tmp_result);
+
+ tmp_result = tonga_get_mc_microcode_version(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to get MC microcode version!", result = tmp_result);
+
+ tmp_result = fiji_init_sclk_threshold(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to init sclk threshold!", result = tmp_result);
+
+ return result;
+}
+
+/**
+* Checks if we want to support voltage control
+*
+* @param hwmgr the address of the powerplay hardware manager.
+*/
+static bool fiji_voltage_control(const struct pp_hwmgr *hwmgr)
+{
+ const struct fiji_hwmgr *data =
+ (const struct fiji_hwmgr *)(hwmgr->backend);
+
+ return (FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control);
+}
+
+/**
+* Enable voltage control
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_enable_voltage_control(struct pp_hwmgr *hwmgr)
+{
+ /* enable voltage control */
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
+
+ return 0;
+}
+
+/**
+* Remove repeated voltage values and create table with unique values.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @param vol_table the pointer to changing voltage table
+* @return 0 in success
+*/
+
+static int fiji_trim_voltage_table(struct pp_hwmgr *hwmgr,
+ struct pp_atomctrl_voltage_table *vol_table)
+{
+ uint32_t i, j;
+ uint16_t vvalue;
+ bool found = false;
+ struct pp_atomctrl_voltage_table *table;
+
+ PP_ASSERT_WITH_CODE((NULL != vol_table),
+ "Voltage Table empty.", return -EINVAL);
+ table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
+ GFP_KERNEL);
+
+ if (NULL == table)
+ return -ENOMEM;
+
+ table->mask_low = vol_table->mask_low;
+ table->phase_delay = vol_table->phase_delay;
+
+ for (i = 0; i < vol_table->count; i++) {
+ vvalue = vol_table->entries[i].value;
+ found = false;
+
+ for (j = 0; j < table->count; j++) {
+ if (vvalue == table->entries[j].value) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ table->entries[table->count].value = vvalue;
+ table->entries[table->count].smio_low =
+ vol_table->entries[i].smio_low;
+ table->count++;
+ }
+ }
+
+ memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
+ kfree(table);
+
+ return 0;
+}
+
+static int fiji_get_svi2_mvdd_voltage_table(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+ uint32_t i;
+ int result;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct pp_atomctrl_voltage_table *vol_table = &(data->mvdd_voltage_table);
+
+ PP_ASSERT_WITH_CODE((0 != dep_table->count),
+ "Voltage Dependency Table empty.", return -EINVAL);
+
+ vol_table->mask_low = 0;
+ vol_table->phase_delay = 0;
+ vol_table->count = dep_table->count;
+
+ for (i = 0; i < dep_table->count; i++) {
+ vol_table->entries[i].value = dep_table->entries[i].mvdd;
+ vol_table->entries[i].smio_low = 0;
+ }
+
+ result = fiji_trim_voltage_table(hwmgr, vol_table);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to trim MVDD table.", return result);
+
+ return 0;
+}
+
+static int fiji_get_svi2_vddci_voltage_table(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+ uint32_t i;
+ int result;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct pp_atomctrl_voltage_table *vol_table = &(data->vddci_voltage_table);
+
+ PP_ASSERT_WITH_CODE((0 != dep_table->count),
+ "Voltage Dependency Table empty.", return -EINVAL);
+
+ vol_table->mask_low = 0;
+ vol_table->phase_delay = 0;
+ vol_table->count = dep_table->count;
+
+ for (i = 0; i < dep_table->count; i++) {
+ vol_table->entries[i].value = dep_table->entries[i].vddci;
+ vol_table->entries[i].smio_low = 0;
+ }
+
+ result = fiji_trim_voltage_table(hwmgr, vol_table);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to trim VDDCI table.", return result);
+
+ return 0;
+}
+
+static int fiji_get_svi2_vdd_voltage_table(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+ int i = 0;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct pp_atomctrl_voltage_table *vol_table = &(data->vddc_voltage_table);
+
+ PP_ASSERT_WITH_CODE((0 != lookup_table->count),
+ "Voltage Lookup Table empty.", return -EINVAL);
+
+ vol_table->mask_low = 0;
+ vol_table->phase_delay = 0;
+
+ vol_table->count = lookup_table->count;
+
+ for (i = 0; i < vol_table->count; i++) {
+ vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
+ vol_table->entries[i].smio_low = 0;
+ }
+
+ return 0;
+}
+
+/* ---- Voltage Tables ----
+ * If the voltage table would be bigger than
+ * what will fit into the state table on
+ * the SMC keep only the higher entries.
+ */
+static void fiji_trim_voltage_table_to_fit_state_table(struct pp_hwmgr *hwmgr,
+ uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table)
+{
+ unsigned int i, diff;
+
+ if (vol_table->count <= max_vol_steps)
+ return;
+
+ diff = vol_table->count - max_vol_steps;
+
+ for (i = 0; i < max_vol_steps; i++)
+ vol_table->entries[i] = vol_table->entries[i + diff];
+
+ vol_table->count = max_vol_steps;
+
+ return;
+}
+
+/**
+* Create Voltage Tables.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_construct_voltage_tables(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)hwmgr->pptable;
+ int result;
+
+ if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+ result = atomctrl_get_voltage_table_v3(hwmgr,
+ VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT,
+ &(data->mvdd_voltage_table));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve MVDD table.",
+ return result);
+ } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+ result = fiji_get_svi2_mvdd_voltage_table(hwmgr,
+ table_info->vdd_dep_on_mclk);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve SVI2 MVDD table from dependancy table.",
+ return result;);
+ }
+
+ if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+ result = atomctrl_get_voltage_table_v3(hwmgr,
+ VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT,
+ &(data->vddci_voltage_table));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve VDDCI table.",
+ return result);
+ } else if (FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+ result = fiji_get_svi2_vddci_voltage_table(hwmgr,
+ table_info->vdd_dep_on_mclk);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve SVI2 VDDCI table from dependancy table.",
+ return result);
+ }
+
+ if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+ result = fiji_get_svi2_vdd_voltage_table(hwmgr,
+ table_info->vddc_lookup_table);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve SVI2 VDDC table from lookup table.",
+ return result);
+ }
+
+ PP_ASSERT_WITH_CODE(
+ (data->vddc_voltage_table.count <= (SMU73_MAX_LEVELS_VDDC)),
+ "Too many voltage values for VDDC. Trimming to fit state table.",
+ fiji_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU73_MAX_LEVELS_VDDC, &(data->vddc_voltage_table)));
+
+ PP_ASSERT_WITH_CODE(
+ (data->vddci_voltage_table.count <= (SMU73_MAX_LEVELS_VDDCI)),
+ "Too many voltage values for VDDCI. Trimming to fit state table.",
+ fiji_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU73_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table)));
+
+ PP_ASSERT_WITH_CODE(
+ (data->mvdd_voltage_table.count <= (SMU73_MAX_LEVELS_MVDD)),
+ "Too many voltage values for MVDD. Trimming to fit state table.",
+ fiji_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU73_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table)));
+
+ return 0;
+}
+
+static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+ /* Program additional LP registers
+ * that are no longer programmed by VBIOS
+ */
+ cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP,
+ cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+
+ return 0;
+}
+
+/**
+* Programs static screed detection parameters
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_program_static_screen_threshold_parameters(
+ struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ /* Set static screen threshold unit */
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
+ data->static_screen_threshold_unit);
+ /* Set static screen threshold */
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
+ data->static_screen_threshold);
+
+ return 0;
+}
+
+/**
+* Setup display gap for glitch free memory clock switching.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_enable_display_gap(struct pp_hwmgr *hwmgr)
+{
+ uint32_t displayGap =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_DISPLAY_GAP_CNTL);
+
+ displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
+ DISP_GAP, DISPLAY_GAP_IGNORE);
+
+ displayGap = PHM_SET_FIELD(displayGap, CG_DISPLAY_GAP_CNTL,
+ DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_DISPLAY_GAP_CNTL, displayGap);
+
+ return 0;
+}
+
+/**
+* Programs activity state transition voting clients
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_program_voting_clients(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ /* Clear reset for voting clients before enabling DPM */
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
+
+ return 0;
+}
+
+/**
+* Get the location of various tables inside the FW image.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smumgr->backend);
+ uint32_t tmp;
+ int result;
+ bool error = false;
+
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, DpmTable),
+ &tmp, data->sram_end);
+
+ if (0 == result)
+ data->dpm_table_start = tmp;
+
+ error |= (0 != result);
+
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, SoftRegisters),
+ &tmp, data->sram_end);
+
+ if (!result) {
+ data->soft_regs_start = tmp;
+ smu_data->soft_regs_start = tmp;
+ }
+
+ error |= (0 != result);
+
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, mcRegisterTable),
+ &tmp, data->sram_end);
+
+ if (!result)
+ data->mc_reg_table_start = tmp;
+
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, FanTable),
+ &tmp, data->sram_end);
+
+ if (!result)
+ data->fan_table_start = tmp;
+
+ error |= (0 != result);
+
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, mcArbDramTimingTable),
+ &tmp, data->sram_end);
+
+ if (!result)
+ data->arb_table_start = tmp;
+
+ error |= (0 != result);
+
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, Version),
+ &tmp, data->sram_end);
+
+ if (!result)
+ hwmgr->microcode_version_info.SMC = tmp;
+
+ error |= (0 != result);
+
+ return error ? -1 : 0;
+}
+
+/* Copy one arb setting to another and then switch the active set.
+ * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants.
+ */
+static int fiji_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
+ uint32_t arb_src, uint32_t arb_dest)
+{
+ uint32_t mc_arb_dram_timing;
+ uint32_t mc_arb_dram_timing2;
+ uint32_t burst_time;
+ uint32_t mc_cg_config;
+
+ switch (arb_src) {
+ case MC_CG_ARB_FREQ_F0:
+ mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+ mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+ burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+ break;
+ case MC_CG_ARB_FREQ_F1:
+ mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
+ mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
+ burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (arb_dest) {
+ case MC_CG_ARB_FREQ_F0:
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+ PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
+ break;
+ case MC_CG_ARB_FREQ_F1:
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+ PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
+ mc_cg_config |= 0x0000000F;
+ cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
+ PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest);
+
+ return 0;
+}
+
+/**
+* Initial switch from ARB F0->F1
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+* This function is to be called from the SetPowerState table.
+*/
+static int fiji_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
+{
+ return fiji_copy_and_switch_arb_sets(hwmgr,
+ MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int fiji_reset_single_dpm_table(struct pp_hwmgr *hwmgr,
+ struct fiji_single_dpm_table *dpm_table, uint32_t count)
+{
+ int i;
+ PP_ASSERT_WITH_CODE(count <= MAX_REGULAR_DPM_NUMBER,
+ "Fatal error, can not set up single DPM table entries "
+ "to exceed max number!",);
+
+ dpm_table->count = count;
+ for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
+ dpm_table->dpm_levels[i].enabled = false;
+
+ return 0;
+}
+
+static void fiji_setup_pcie_table_entry(
+ struct fiji_single_dpm_table *dpm_table,
+ uint32_t index, uint32_t pcie_gen,
+ uint32_t pcie_lanes)
+{
+ dpm_table->dpm_levels[index].value = pcie_gen;
+ dpm_table->dpm_levels[index].param1 = pcie_lanes;
+ dpm_table->dpm_levels[index].enabled = 1;
+}
+
+static int fiji_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+ uint32_t i, max_entry;
+
+ PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels ||
+ data->use_pcie_power_saving_levels), "No pcie performance levels!",
+ return -EINVAL);
+
+ if (data->use_pcie_performance_levels &&
+ !data->use_pcie_power_saving_levels) {
+ data->pcie_gen_power_saving = data->pcie_gen_performance;
+ data->pcie_lane_power_saving = data->pcie_lane_performance;
+ } else if (!data->use_pcie_performance_levels &&
+ data->use_pcie_power_saving_levels) {
+ data->pcie_gen_performance = data->pcie_gen_power_saving;
+ data->pcie_lane_performance = data->pcie_lane_power_saving;
+ }
+
+ fiji_reset_single_dpm_table(hwmgr,
+ &data->dpm_table.pcie_speed_table, SMU73_MAX_LEVELS_LINK);
+
+ if (pcie_table != NULL) {
+ /* max_entry is used to make sure we reserve one PCIE level
+ * for boot level (fix for A+A PSPP issue).
+ * If PCIE table from PPTable have ULV entry + 8 entries,
+ * then ignore the last entry.*/
+ max_entry = (SMU73_MAX_LEVELS_LINK < pcie_table->count) ?
+ SMU73_MAX_LEVELS_LINK : pcie_table->count;
+ for (i = 1; i < max_entry; i++) {
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ pcie_table->entries[i].gen_speed),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ pcie_table->entries[i].lane_width));
+ }
+ data->dpm_table.pcie_speed_table.count = max_entry - 1;
+ } else {
+ /* Hardcode Pcie Table */
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Min_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Min_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+
+ data->dpm_table.pcie_speed_table.count = 6;
+ }
+ /* Populate last level for boot PCIE level, but do not increment count. */
+ fiji_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
+ data->dpm_table.pcie_speed_table.count,
+ get_pcie_gen_support(data->pcie_gen_cap,
+ PP_Min_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap,
+ PP_Max_PCIELane));
+
+ return 0;
+}
+
+/*
+ * This function is to initalize all DPM state tables
+ * for SMU7 based on the dependency table.
+ * Dynamic state patching function will then trim these
+ * state tables to the allowed range based
+ * on the power policy or external client requests,
+ * such as UVD request, etc.
+ */
+static int fiji_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint32_t i;
+
+ struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table =
+ table_info->vdd_dep_on_sclk;
+ struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+ table_info->vdd_dep_on_mclk;
+
+ PP_ASSERT_WITH_CODE(dep_sclk_table != NULL,
+ "SCLK dependency table is missing. This table is mandatory",
+ return -EINVAL);
+ PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1,
+ "SCLK dependency table has to have is missing. "
+ "This table is mandatory",
+ return -EINVAL);
+
+ PP_ASSERT_WITH_CODE(dep_mclk_table != NULL,
+ "MCLK dependency table is missing. This table is mandatory",
+ return -EINVAL);
+ PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1,
+ "MCLK dependency table has to have is missing. "
+ "This table is mandatory",
+ return -EINVAL);
+
+ /* clear the state table to reset everything to default */
+ fiji_reset_single_dpm_table(hwmgr,
+ &data->dpm_table.sclk_table, SMU73_MAX_LEVELS_GRAPHICS);
+ fiji_reset_single_dpm_table(hwmgr,
+ &data->dpm_table.mclk_table, SMU73_MAX_LEVELS_MEMORY);
+
+ /* Initialize Sclk DPM table based on allow Sclk values */
+ data->dpm_table.sclk_table.count = 0;
+ for (i = 0; i < dep_sclk_table->count; i++) {
+ if (i == 0 || data->dpm_table.sclk_table.dpm_levels
+ [data->dpm_table.sclk_table.count - 1].value !=
+ dep_sclk_table->entries[i].clk) {
+ data->dpm_table.sclk_table.dpm_levels
+ [data->dpm_table.sclk_table.count].value =
+ dep_sclk_table->entries[i].clk;
+ data->dpm_table.sclk_table.dpm_levels
+ [data->dpm_table.sclk_table.count].enabled =
+ (i == 0) ? true : false;
+ data->dpm_table.sclk_table.count++;
+ }
+ }
+
+ /* Initialize Mclk DPM table based on allow Mclk values */
+ data->dpm_table.mclk_table.count = 0;
+ for (i=0; i<dep_mclk_table->count; i++) {
+ if ( i==0 || data->dpm_table.mclk_table.dpm_levels
+ [data->dpm_table.mclk_table.count - 1].value !=
+ dep_mclk_table->entries[i].clk) {
+ data->dpm_table.mclk_table.dpm_levels
+ [data->dpm_table.mclk_table.count].value =
+ dep_mclk_table->entries[i].clk;
+ data->dpm_table.mclk_table.dpm_levels
+ [data->dpm_table.mclk_table.count].enabled =
+ (i == 0) ? true : false;
+ data->dpm_table.mclk_table.count++;
+ }
+ }
+
+ /* setup PCIE gen speed levels */
+ fiji_setup_default_pcie_table(hwmgr);
+
+ /* save a copy of the default DPM table */
+ memcpy(&(data->golden_dpm_table), &(data->dpm_table),
+ sizeof(struct fiji_dpm_table));
+
+ return 0;
+}
+
+/**
+ * @brief PhwFiji_GetVoltageOrder
+ * Returns index of requested voltage record in lookup(table)
+ * @param lookup_table - lookup list to search in
+ * @param voltage - voltage to look for
+ * @return 0 on success
+ */
+uint8_t fiji_get_voltage_index(
+ struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
+{
+ uint8_t count = (uint8_t) (lookup_table->count);
+ uint8_t i;
+
+ PP_ASSERT_WITH_CODE((NULL != lookup_table),
+ "Lookup Table empty.", return 0);
+ PP_ASSERT_WITH_CODE((0 != count),
+ "Lookup Table empty.", return 0);
+
+ for (i = 0; i < lookup_table->count; i++) {
+ /* find first voltage equal or bigger than requested */
+ if (lookup_table->entries[i].us_vdd >= voltage)
+ return i;
+ }
+ /* voltage is bigger than max voltage in the table */
+ return i - 1;
+}
+
+/**
+* Preparation of vddc and vddgfx CAC tables for SMC.
+*
+* @param hwmgr the address of the hardware manager
+* @param table the SMC DPM table structure to be populated
+* @return always 0
+*/
+static int fiji_populate_cac_table(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ uint32_t count;
+ uint8_t index;
+ int result = 0;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_voltage_lookup_table *lookup_table =
+ table_info->vddc_lookup_table;
+ /* tables is already swapped, so in order to use the value from it,
+ * we need to swap it back.
+ * We are populating vddc CAC data to BapmVddc table
+ * in split and merged mode
+ */
+ for( count = 0; count<lookup_table->count; count++) {
+ index = fiji_get_voltage_index(lookup_table,
+ data->vddc_voltage_table.entries[count].value);
+ table->BapmVddcVidLoSidd[count] = (uint8_t) ((6200 -
+ (lookup_table->entries[index].us_cac_low *
+ VOLTAGE_SCALE)) / 25);
+ table->BapmVddcVidHiSidd[count] = (uint8_t) ((6200 -
+ (lookup_table->entries[index].us_cac_high *
+ VOLTAGE_SCALE)) / 25);
+ }
+
+ return result;
+}
+
+/**
+* Preparation of voltage tables for SMC.
+*
+* @param hwmgr the address of the hardware manager
+* @param table the SMC DPM table structure to be populated
+* @return always 0
+*/
+
+int fiji_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ int result;
+
+ result = fiji_populate_cac_table(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "can not populate CAC voltage tables to SMC",
+ return -EINVAL);
+
+ return 0;
+}
+
+static int fiji_populate_ulv_level(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_Ulv *state)
+{
+ int result = 0;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ state->CcPwrDynRm = 0;
+ state->CcPwrDynRm1 = 0;
+
+ state->VddcOffset = (uint16_t) table_info->us_ulv_voltage_offset;
+ state->VddcOffsetVid = (uint8_t)( table_info->us_ulv_voltage_offset *
+ VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1 );
+
+ state->VddcPhase = (data->vddc_phase_shed_control) ? 0 : 1;
+
+ if (!result) {
+ CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm);
+ CONVERT_FROM_HOST_TO_SMC_UL(state->CcPwrDynRm1);
+ CONVERT_FROM_HOST_TO_SMC_US(state->VddcOffset);
+ }
+ return result;
+}
+
+static int fiji_populate_ulv_state(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ return fiji_populate_ulv_level(hwmgr, &table->Ulv);
+}
+
+static int32_t fiji_get_dpm_level_enable_mask_value(
+ struct fiji_single_dpm_table* dpm_table)
+{
+ int32_t i;
+ int32_t mask = 0;
+
+ for (i = dpm_table->count; i > 0; i--) {
+ mask = mask << 1;
+ if (dpm_table->dpm_levels[i - 1].enabled)
+ mask |= 0x1;
+ else
+ mask &= 0xFFFFFFFE;
+ }
+ return mask;
+}
+
+static int fiji_populate_smc_link_level(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_dpm_table *dpm_table = &data->dpm_table;
+ int i;
+
+ /* Index (dpm_table->pcie_speed_table.count)
+ * is reserved for PCIE boot level. */
+ for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+ table->LinkLevel[i].PcieGenSpeed =
+ (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+ table->LinkLevel[i].PcieLaneCount = (uint8_t)encode_pcie_lane_width(
+ dpm_table->pcie_speed_table.dpm_levels[i].param1);
+ table->LinkLevel[i].EnabledForActivity = 1;
+ table->LinkLevel[i].SPC = (uint8_t)(data->pcie_spc_cap & 0xff);
+ table->LinkLevel[i].DownThreshold = PP_HOST_TO_SMC_UL(5);
+ table->LinkLevel[i].UpThreshold = PP_HOST_TO_SMC_UL(30);
+ }
+
+ data->smc_state_table.LinkLevelCount =
+ (uint8_t)dpm_table->pcie_speed_table.count;
+ data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+ fiji_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+ return 0;
+}
+
+/**
+* Calculates the SCLK dividers using the provided engine clock
+*
+* @param hwmgr the address of the hardware manager
+* @param clock the engine clock to use to populate the structure
+* @param sclk the SMC SCLK structure to be populated
+*/
+static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+ uint32_t clock, struct SMU73_Discrete_GraphicsLevel *sclk)
+{
+ const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct pp_atomctrl_clock_dividers_vi dividers;
+ uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+ uint32_t spll_func_cntl_3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+ uint32_t spll_func_cntl_4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+ uint32_t cg_spll_spread_spectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t ref_clock;
+ uint32_t ref_divider;
+ uint32_t fbdiv;
+ int result;
+
+ /* get the engine clock dividers for this clock value */
+ result = atomctrl_get_engine_pll_dividers_vi(hwmgr, clock, &dividers);
+
+ PP_ASSERT_WITH_CODE(result == 0,
+ "Error retrieving Engine Clock dividers from VBIOS.",
+ return result);
+
+ /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
+ ref_clock = atomctrl_get_reference_clock(hwmgr);
+ ref_divider = 1 + dividers.uc_pll_ref_div;
+
+ /* low 14 bits is fraction and high 12 bits is divider */
+ fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+ /* SPLL_FUNC_CNTL setup */
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+ SPLL_REF_DIV, dividers.uc_pll_ref_div);
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+ SPLL_PDIV_A, dividers.uc_pll_post_div);
+
+ /* SPLL_FUNC_CNTL_3 setup*/
+ spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
+ SPLL_FB_DIV, fbdiv);
+
+ /* set to use fractional accumulation*/
+ spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3, CG_SPLL_FUNC_CNTL_3,
+ SPLL_DITHEN, 1);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+ struct pp_atomctrl_internal_ss_info ssInfo;
+
+ uint32_t vco_freq = clock * dividers.uc_pll_post_div;
+ if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr,
+ vco_freq, &ssInfo)) {
+ /*
+ * ss_info.speed_spectrum_percentage -- in unit of 0.01%
+ * ss_info.speed_spectrum_rate -- in unit of khz
+ *
+ * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
+ */
+ uint32_t clk_s = ref_clock * 5 /
+ (ref_divider * ssInfo.speed_spectrum_rate);
+ /* clkv = 2 * D * fbdiv / NS */
+ uint32_t clk_v = 4 * ssInfo.speed_spectrum_percentage *
+ fbdiv / (clk_s * 10000);
+
+ cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
+ CG_SPLL_SPREAD_SPECTRUM, CLKS, clk_s);
+ cg_spll_spread_spectrum = PHM_SET_FIELD(cg_spll_spread_spectrum,
+ CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+ cg_spll_spread_spectrum_2 = PHM_SET_FIELD(cg_spll_spread_spectrum_2,
+ CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clk_v);
+ }
+ }
+
+ sclk->SclkFrequency = clock;
+ sclk->CgSpllFuncCntl3 = spll_func_cntl_3;
+ sclk->CgSpllFuncCntl4 = spll_func_cntl_4;
+ sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum;
+ sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2;
+ sclk->SclkDid = (uint8_t)dividers.pll_post_divider;
+
+ return 0;
+}
+
+static uint16_t fiji_find_closest_vddci(struct pp_hwmgr *hwmgr, uint16_t vddci)
+{
+ uint32_t i;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct pp_atomctrl_voltage_table *vddci_table =
+ &(data->vddci_voltage_table);
+
+ for (i = 0; i < vddci_table->count; i++) {
+ if (vddci_table->entries[i].value >= vddci)
+ return vddci_table->entries[i].value;
+ }
+
+ PP_ASSERT_WITH_CODE(false,
+ "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
+ return vddci_table->entries[i].value);
+}
+
+static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr,
+ struct phm_ppt_v1_clock_voltage_dependency_table* dep_table,
+ uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
+{
+ uint32_t i;
+ uint16_t vddci;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ *voltage = *mvdd = 0;
+
+ /* clock - voltage dependency table is empty table */
+ if (dep_table->count == 0)
+ return -EINVAL;
+
+ for (i = 0; i < dep_table->count; i++) {
+ /* find first sclk bigger than request */
+ if (dep_table->entries[i].clk >= clock) {
+ *voltage |= (dep_table->entries[i].vddc *
+ VOLTAGE_SCALE) << VDDC_SHIFT;
+ if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
+ *voltage |= (data->vbios_boot_state.vddci_bootup_value *
+ VOLTAGE_SCALE) << VDDCI_SHIFT;
+ else if (dep_table->entries[i].vddci)
+ *voltage |= (dep_table->entries[i].vddci *
+ VOLTAGE_SCALE) << VDDCI_SHIFT;
+ else {
+ vddci = fiji_find_closest_vddci(hwmgr,
+ (dep_table->entries[i].vddc -
+ (uint16_t)data->vddc_vddci_delta));
+ *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+ }
+
+ if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+ *mvdd = data->vbios_boot_state.mvdd_bootup_value *
+ VOLTAGE_SCALE;
+ else if (dep_table->entries[i].mvdd)
+ *mvdd = (uint32_t) dep_table->entries[i].mvdd *
+ VOLTAGE_SCALE;
+
+ *voltage |= 1 << PHASES_SHIFT;
+ return 0;
+ }
+ }
+
+ /* sclk is bigger than max sclk in the dependence table */
+ *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+
+ if (FIJI_VOLTAGE_CONTROL_NONE == data->vddci_control)
+ *voltage |= (data->vbios_boot_state.vddci_bootup_value *
+ VOLTAGE_SCALE) << VDDCI_SHIFT;
+ else if (dep_table->entries[i-1].vddci) {
+ vddci = fiji_find_closest_vddci(hwmgr,
+ (dep_table->entries[i].vddc -
+ (uint16_t)data->vddc_vddci_delta));
+ *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+ }
+
+ if (FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control)
+ *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
+ else if (dep_table->entries[i].mvdd)
+ *mvdd = (uint32_t) dep_table->entries[i - 1].mvdd * VOLTAGE_SCALE;
+
+ return 0;
+}
+/**
+* Populates single SMC SCLK structure using the provided engine clock
+*
+* @param hwmgr the address of the hardware manager
+* @param clock the engine clock to use to populate the structure
+* @param sclk the SMC SCLK structure to be populated
+*/
+
+static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr,
+ uint32_t clock, uint16_t sclk_al_threshold,
+ struct SMU73_Discrete_GraphicsLevel *level)
+{
+ int result;
+ /* PP_Clocks minClocks; */
+ uint32_t threshold, mvdd;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ result = fiji_calculate_sclk_params(hwmgr, clock, level);
+
+ /* populate graphics levels */
+ result = fiji_get_dependency_volt_by_clk(hwmgr,
+ table_info->vdd_dep_on_sclk, clock,
+ &level->MinVoltage, &mvdd);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find VDDC voltage value for "
+ "VDDC engine clock dependency table",
+ return result);
+
+ level->SclkFrequency = clock;
+ level->ActivityLevel = sclk_al_threshold;
+ level->CcPwrDynRm = 0;
+ level->CcPwrDynRm1 = 0;
+ level->EnabledForActivity = 0;
+ level->EnabledForThrottle = 1;
+ level->UpHyst = 10;
+ level->DownHyst = 0;
+ level->VoltageDownHyst = 0;
+ level->PowerThrottle = 0;
+
+ threshold = clock * data->fast_watermark_threshold / 100;
+
+ /*
+ * TODO: get minimum clocks from dal configaration
+ * PECI_GetMinClockSettings(hwmgr->pPECI, &minClocks);
+ */
+ /* data->DisplayTiming.minClockInSR = minClocks.engineClockInSR; */
+
+ /* get level->DeepSleepDivId
+ if (phm_cap_enabled(hwmgr->platformDescriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
+ {
+ level->DeepSleepDivId = PhwFiji_GetSleepDividerIdFromClock(hwmgr, clock, minClocks.engineClockInSR);
+ } */
+
+ /* Default to slow, highest DPM level will be
+ * set to PPSMC_DISPLAY_WATERMARK_LOW later.
+ */
+ level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(level->MinVoltage);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->SclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_US(level->ActivityLevel);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl3);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->CgSpllFuncCntl4);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->SpllSpreadSpectrum2);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm);
+ CONVERT_FROM_HOST_TO_SMC_UL(level->CcPwrDynRm1);
+
+ return 0;
+}
+/**
+* Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+*
+* @param hwmgr the address of the hardware manager
+*/
+static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_dpm_table *dpm_table = &data->dpm_table;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_pcie_table *pcie_table = table_info->pcie_table;
+ uint8_t pcie_entry_cnt = (uint8_t) data->dpm_table.pcie_speed_table.count;
+ int result = 0;
+ uint32_t array = data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
+ uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) *
+ SMU73_MAX_LEVELS_GRAPHICS;
+ struct SMU73_Discrete_GraphicsLevel *levels =
+ data->smc_state_table.GraphicsLevel;
+ uint32_t i, max_entry;
+ uint8_t hightest_pcie_level_enabled = 0,
+ lowest_pcie_level_enabled = 0,
+ mid_pcie_level_enabled = 0,
+ count = 0;
+
+ for (i = 0; i < dpm_table->sclk_table.count; i++) {
+ result = fiji_populate_single_graphic_level(hwmgr,
+ dpm_table->sclk_table.dpm_levels[i].value,
+ (uint16_t)data->activity_target[i],
+ &levels[i]);
+ if (result)
+ return result;
+
+ /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+ if (i > 1)
+ levels[i].DeepSleepDivId = 0;
+ }
+
+ /* Only enable level 0 for now.*/
+ levels[0].EnabledForActivity = 1;
+
+ /* set highest level watermark to high */
+ levels[dpm_table->sclk_table.count - 1].DisplayWatermark =
+ PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ data->smc_state_table.GraphicsDpmLevelCount =
+ (uint8_t)dpm_table->sclk_table.count;
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+ fiji_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+ if (pcie_table != NULL) {
+ PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt),
+ "There must be 1 or more PCIE levels defined in PPTable.",
+ return -EINVAL);
+ max_entry = pcie_entry_cnt - 1;
+ for (i = 0; i < dpm_table->sclk_table.count; i++)
+ levels[i].pcieDpmLevel =
+ (uint8_t) ((i < max_entry)? i : max_entry);
+ } else {
+ while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+ ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+ (1 << (hightest_pcie_level_enabled + 1))) != 0 ))
+ hightest_pcie_level_enabled++;
+
+ while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+ ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+ (1 << lowest_pcie_level_enabled)) == 0 ))
+ lowest_pcie_level_enabled++;
+
+ while ((count < hightest_pcie_level_enabled) &&
+ ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+ (1 << (lowest_pcie_level_enabled + 1 + count))) == 0 ))
+ count++;
+
+ mid_pcie_level_enabled = (lowest_pcie_level_enabled + 1+ count) <
+ hightest_pcie_level_enabled?
+ (lowest_pcie_level_enabled + 1 + count) :
+ hightest_pcie_level_enabled;
+
+ /* set pcieDpmLevel to hightest_pcie_level_enabled */
+ for(i = 2; i < dpm_table->sclk_table.count; i++)
+ levels[i].pcieDpmLevel = hightest_pcie_level_enabled;
+
+ /* set pcieDpmLevel to lowest_pcie_level_enabled */
+ levels[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+ /* set pcieDpmLevel to mid_pcie_level_enabled */
+ levels[1].pcieDpmLevel = mid_pcie_level_enabled;
+ }
+ /* level count will send to smc once at init smc table and never change */
+ result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+ (uint32_t)array_size, data->sram_end);
+
+ return result;
+}
+
+/**
+ * MCLK Frequency Ratio
+ * SEQ_CG_RESP Bit[31:24] - 0x0
+ * Bit[27:24] \96 DDR3 Frequency ratio
+ * 0x0 <= 100MHz, 450 < 0x8 <= 500MHz
+ * 100 < 0x1 <= 150MHz, 500 < 0x9 <= 550MHz
+ * 150 < 0x2 <= 200MHz, 550 < 0xA <= 600MHz
+ * 200 < 0x3 <= 250MHz, 600 < 0xB <= 650MHz
+ * 250 < 0x4 <= 300MHz, 650 < 0xC <= 700MHz
+ * 300 < 0x5 <= 350MHz, 700 < 0xD <= 750MHz
+ * 350 < 0x6 <= 400MHz, 750 < 0xE <= 800MHz
+ * 400 < 0x7 <= 450MHz, 800 < 0xF
+ */
+static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock)
+{
+ if (mem_clock <= 10000) return 0x0;
+ if (mem_clock <= 15000) return 0x1;
+ if (mem_clock <= 20000) return 0x2;
+ if (mem_clock <= 25000) return 0x3;
+ if (mem_clock <= 30000) return 0x4;
+ if (mem_clock <= 35000) return 0x5;
+ if (mem_clock <= 40000) return 0x6;
+ if (mem_clock <= 45000) return 0x7;
+ if (mem_clock <= 50000) return 0x8;
+ if (mem_clock <= 55000) return 0x9;
+ if (mem_clock <= 60000) return 0xa;
+ if (mem_clock <= 65000) return 0xb;
+ if (mem_clock <= 70000) return 0xc;
+ if (mem_clock <= 75000) return 0xd;
+ if (mem_clock <= 80000) return 0xe;
+ /* mem_clock > 800MHz */
+ return 0xf;
+}
+
+/**
+* Populates the SMC MCLK structure using the provided memory clock
+*
+* @param hwmgr the address of the hardware manager
+* @param clock the memory clock to use to populate the structure
+* @param sclk the SMC SCLK structure to be populated
+*/
+static int fiji_calculate_mclk_params(struct pp_hwmgr *hwmgr,
+ uint32_t clock, struct SMU73_Discrete_MemoryLevel *mclk)
+{
+ struct pp_atomctrl_memory_clock_param mem_param;
+ int result;
+
+ result = atomctrl_get_memory_pll_dividers_vi(hwmgr, clock, &mem_param);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to get Memory PLL Dividers.",);
+
+ /* Save the result data to outpupt memory level structure */
+ mclk->MclkFrequency = clock;
+ mclk->MclkDivider = (uint8_t)mem_param.mpll_post_divider;
+ mclk->FreqRange = fiji_get_mclk_frequency_ratio(clock);
+
+ return result;
+}
+
+static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr,
+ uint32_t clock, struct SMU73_Discrete_MemoryLevel *mem_level)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ int result = 0;
+
+ if (table_info->vdd_dep_on_mclk) {
+ result = fiji_get_dependency_volt_by_clk(hwmgr,
+ table_info->vdd_dep_on_mclk, clock,
+ &mem_level->MinVoltage, &mem_level->MinMvdd);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find MinVddc voltage value from memory "
+ "VDDC voltage dependency table", return result);
+ }
+
+ mem_level->EnabledForThrottle = 1;
+ mem_level->EnabledForActivity = 0;
+ mem_level->UpHyst = 0;
+ mem_level->DownHyst = 100;
+ mem_level->VoltageDownHyst = 0;
+ mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+ mem_level->StutterEnable = false;
+
+ mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+ /* enable stutter mode if all the follow condition applied
+ * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
+ * &(data->DisplayTiming.numExistingDisplays));
+ */
+ data->display_timing.num_existing_displays = 1;
+
+ if ((data->mclk_stutter_mode_threshold) &&
+ (clock <= data->mclk_stutter_mode_threshold) &&
+ (!data->is_uvd_enabled) &&
+ (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL,
+ STUTTER_ENABLE) & 0x1))
+ mem_level->StutterEnable = true;
+
+ result = fiji_calculate_mclk_params(hwmgr, clock, mem_level);
+ if (!result) {
+ CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinMvdd);
+ CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_US(mem_level->ActivityLevel);
+ CONVERT_FROM_HOST_TO_SMC_UL(mem_level->MinVoltage);
+ }
+ return result;
+}
+
+/**
+* Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+*
+* @param hwmgr the address of the hardware manager
+*/
+static int fiji_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_dpm_table *dpm_table = &data->dpm_table;
+ int result;
+ /* populate MCLK dpm table to SMU7 */
+ uint32_t array = data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, MemoryLevel);
+ uint32_t array_size = sizeof(SMU73_Discrete_MemoryLevel) *
+ SMU73_MAX_LEVELS_MEMORY;
+ struct SMU73_Discrete_MemoryLevel *levels =
+ data->smc_state_table.MemoryLevel;
+ uint32_t i;
+
+ for (i = 0; i < dpm_table->mclk_table.count; i++) {
+ PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+ "can not populate memory level as memory clock is zero",
+ return -EINVAL);
+ result = fiji_populate_single_memory_level(hwmgr,
+ dpm_table->mclk_table.dpm_levels[i].value,
+ &levels[i]);
+ if (result)
+ return result;
+ }
+
+ /* Only enable level 0 for now. */
+ levels[0].EnabledForActivity = 1;
+
+ /* in order to prevent MC activity from stutter mode to push DPM up.
+ * the UVD change complements this by putting the MCLK in
+ * a higher state by default such that we are not effected by
+ * up threshold or and MCLK DPM latency.
+ */
+ levels[0].ActivityLevel = (uint16_t)data->mclk_dpm0_activity_target;
+ CONVERT_FROM_HOST_TO_SMC_US(levels[0].ActivityLevel);
+
+ data->smc_state_table.MemoryDpmLevelCount =
+ (uint8_t)dpm_table->mclk_table.count;
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+ fiji_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+ /* set highest level watermark to high */
+ levels[dpm_table->mclk_table.count - 1].DisplayWatermark =
+ PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ /* level count will send to smc once at init smc table and never change */
+ result = fiji_copy_bytes_to_smc(hwmgr->smumgr, array, (uint8_t *)levels,
+ (uint32_t)array_size, data->sram_end);
+
+ return result;
+}
+
+/**
+* Populates the SMC MVDD structure using the provided memory clock.
+*
+* @param hwmgr the address of the hardware manager
+* @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
+* @param voltage the SMC VOLTAGE structure to be populated
+*/
+int fiji_populate_mvdd_value(struct pp_hwmgr *hwmgr,
+ uint32_t mclk, SMIO_Pattern *smio_pat)
+{
+ const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint32_t i = 0;
+
+ if (FIJI_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+ /* find mvdd value which clock is more than request */
+ for (i = 0; i < table_info->vdd_dep_on_mclk->count; i++) {
+ if (mclk <= table_info->vdd_dep_on_mclk->entries[i].clk) {
+ smio_pat->Voltage = data->mvdd_voltage_table.entries[i].value;
+ break;
+ }
+ }
+ PP_ASSERT_WITH_CODE(i < table_info->vdd_dep_on_mclk->count,
+ "MVDD Voltage is outside the supported range.",
+ return -EINVAL);
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr,
+ SMU73_Discrete_DpmTable *table)
+{
+ int result = 0;
+ const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct pp_atomctrl_clock_dividers_vi dividers;
+ SMIO_Pattern vol_level;
+ uint32_t mvdd;
+ uint16_t us_mvdd;
+ uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+ uint32_t spll_func_cntl_2 = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+
+ table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (!data->sclk_dpm_key_disabled) {
+ /* Get MinVoltage and Frequency from DPM0,
+ * already converted to SMC_UL */
+ table->ACPILevel.SclkFrequency =
+ data->dpm_table.sclk_table.dpm_levels[0].value;
+ result = fiji_get_dependency_volt_by_clk(hwmgr,
+ table_info->vdd_dep_on_sclk,
+ table->ACPILevel.SclkFrequency,
+ &table->ACPILevel.MinVoltage, &mvdd);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Cannot find ACPI VDDC voltage value "
+ "in Clock Dependency Table",);
+ } else {
+ table->ACPILevel.SclkFrequency =
+ data->vbios_boot_state.sclk_bootup_value;
+ table->ACPILevel.MinVoltage =
+ data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE;
+ }
+
+ /* get the engine clock dividers for this clock value */
+ result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+ table->ACPILevel.SclkFrequency, &dividers);
+ PP_ASSERT_WITH_CODE(result == 0,
+ "Error retrieving Engine Clock dividers from VBIOS.",
+ return result);
+
+ table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+ table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+ table->ACPILevel.DeepSleepDivId = 0;
+
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+ SPLL_PWRON, 0);
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl, CG_SPLL_FUNC_CNTL,
+ SPLL_RESET, 1);
+ spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2, CG_SPLL_FUNC_CNTL_2,
+ SCLK_MUX_SEL, 4);
+
+ table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+ table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+ table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+ table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+ table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+ table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+ table->ACPILevel.CcPwrDynRm = 0;
+ table->ACPILevel.CcPwrDynRm1 = 0;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.MinVoltage);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+ if (!data->mclk_dpm_key_disabled) {
+ /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
+ table->MemoryACPILevel.MclkFrequency =
+ data->dpm_table.mclk_table.dpm_levels[0].value;
+ result = fiji_get_dependency_volt_by_clk(hwmgr,
+ table_info->vdd_dep_on_mclk,
+ table->MemoryACPILevel.MclkFrequency,
+ &table->MemoryACPILevel.MinVoltage, &mvdd);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Cannot find ACPI VDDCI voltage value "
+ "in Clock Dependency Table",);
+ } else {
+ table->MemoryACPILevel.MclkFrequency =
+ data->vbios_boot_state.mclk_bootup_value;
+ table->MemoryACPILevel.MinVoltage =
+ data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE;
+ }
+
+ us_mvdd = 0;
+ if ((FIJI_VOLTAGE_CONTROL_NONE == data->mvdd_control) ||
+ (data->mclk_dpm_key_disabled))
+ us_mvdd = data->vbios_boot_state.mvdd_bootup_value;
+ else {
+ if (!fiji_populate_mvdd_value(hwmgr,
+ data->dpm_table.mclk_table.dpm_levels[0].value,
+ &vol_level))
+ us_mvdd = vol_level.Voltage;
+ }
+
+ table->MemoryACPILevel.MinMvdd =
+ PP_HOST_TO_SMC_UL(us_mvdd * VOLTAGE_SCALE);
+
+ table->MemoryACPILevel.EnabledForThrottle = 0;
+ table->MemoryACPILevel.EnabledForActivity = 0;
+ table->MemoryACPILevel.UpHyst = 0;
+ table->MemoryACPILevel.DownHyst = 100;
+ table->MemoryACPILevel.VoltageDownHyst = 0;
+ table->MemoryACPILevel.ActivityLevel =
+ PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+ table->MemoryACPILevel.StutterEnable = false;
+ CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);
+
+ return result;
+}
+
+static int fiji_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+ SMU73_Discrete_DpmTable *table)
+{
+ int result = -EINVAL;
+ uint8_t count;
+ struct pp_atomctrl_clock_dividers_vi dividers;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+ table_info->mm_dep_table;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ table->VceLevelCount = (uint8_t)(mm_table->count);
+ table->VceBootLevel = 0;
+
+ for(count = 0; count < table->VceLevelCount; count++) {
+ table->VceLevel[count].Frequency = mm_table->entries[count].eclk;
+ table->VceLevel[count].MinVoltage |=
+ (mm_table->entries[count].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
+ table->VceLevel[count].MinVoltage |=
+ ((mm_table->entries[count].vddc - data->vddc_vddci_delta) *
+ VOLTAGE_SCALE) << VDDCI_SHIFT;
+ table->VceLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+ /*retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->VceLevel[count].Frequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for VCE engine clock",
+ return result);
+
+ table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].MinVoltage);
+ }
+ return result;
+}
+
+static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+ SMU73_Discrete_DpmTable *table)
+{
+ int result = -EINVAL;
+ uint8_t count;
+ struct pp_atomctrl_clock_dividers_vi dividers;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+ table_info->mm_dep_table;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ table->AcpLevelCount = (uint8_t)(mm_table->count);
+ table->AcpBootLevel = 0;
+
+ for (count = 0; count < table->AcpLevelCount; count++) {
+ table->AcpLevel[count].Frequency = mm_table->entries[count].aclk;
+ table->AcpLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+ VOLTAGE_SCALE) << VDDC_SHIFT;
+ table->AcpLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+ data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+ table->AcpLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->AcpLevel[count].Frequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for engine clock", return result);
+
+ table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].MinVoltage);
+ }
+ return result;
+}
+
+static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+ SMU73_Discrete_DpmTable *table)
+{
+ int result = -EINVAL;
+ uint8_t count;
+ struct pp_atomctrl_clock_dividers_vi dividers;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+ table_info->mm_dep_table;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ table->SamuBootLevel = 0;
+ table->SamuLevelCount = (uint8_t)(mm_table->count);
+
+ for (count = 0; count < table->SamuLevelCount; count++) {
+ /* not sure whether we need evclk or not */
+ table->SamuLevel[count].Frequency = mm_table->entries[count].samclock;
+ table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+ VOLTAGE_SCALE) << VDDC_SHIFT;
+ table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+ data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+ table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->SamuLevel[count].Frequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for samu clock", return result);
+
+ table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage);
+ }
+ return result;
+}
+
+static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr,
+ int32_t eng_clock, int32_t mem_clock,
+ struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs)
+{
+ uint32_t dram_timing;
+ uint32_t dram_timing2;
+ uint32_t burstTime;
+ ULONG state, trrds, trrdl;
+ int result;
+
+ result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+ eng_clock, mem_clock);
+ PP_ASSERT_WITH_CODE(result == 0,
+ "Error calling VBIOS to set DRAM_TIMING.", return result);
+
+ dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+ dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+ burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME);
+
+ state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0);
+ trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0);
+ trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0);
+
+ arb_regs->McArbDramTiming = PP_HOST_TO_SMC_UL(dram_timing);
+ arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dram_timing2);
+ arb_regs->McArbBurstTime = (uint8_t)burstTime;
+ arb_regs->TRRDS = (uint8_t)trrds;
+ arb_regs->TRRDL = (uint8_t)trrdl;
+
+ return 0;
+}
+
+static int fiji_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct SMU73_Discrete_MCArbDramTimingTable arb_regs;
+ uint32_t i, j;
+ int result = 0;
+
+ for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+ for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+ result = fiji_populate_memory_timing_parameters(hwmgr,
+ data->dpm_table.sclk_table.dpm_levels[i].value,
+ data->dpm_table.mclk_table.dpm_levels[j].value,
+ &arb_regs.entries[i][j]);
+ if (result)
+ break;
+ }
+ }
+
+ if (!result)
+ result = fiji_copy_bytes_to_smc(
+ hwmgr->smumgr,
+ data->arb_table_start,
+ (uint8_t *)&arb_regs,
+ sizeof(SMU73_Discrete_MCArbDramTimingTable),
+ data->sram_end);
+ return result;
+}
+
+static int fiji_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ int result = -EINVAL;
+ uint8_t count;
+ struct pp_atomctrl_clock_dividers_vi dividers;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table =
+ table_info->mm_dep_table;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ table->UvdLevelCount = (uint8_t)(mm_table->count);
+ table->UvdBootLevel = 0;
+
+ for (count = 0; count < table->UvdLevelCount; count++) {
+ table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+ table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+ table->UvdLevel[count].MinVoltage |= (mm_table->entries[count].vddc *
+ VOLTAGE_SCALE) << VDDC_SHIFT;
+ table->UvdLevel[count].MinVoltage |= ((mm_table->entries[count].vddc -
+ data->vddc_vddci_delta) * VOLTAGE_SCALE) << VDDCI_SHIFT;
+ table->UvdLevel[count].MinVoltage |= 1 << PHASES_SHIFT;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->UvdLevel[count].VclkFrequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for Vclk clock", return result);
+
+ table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->UvdLevel[count].DclkFrequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for Dclk clock", return result);
+
+ table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].MinVoltage);
+
+ }
+ return result;
+}
+
+static int fiji_find_boot_level(struct fiji_single_dpm_table *table,
+ uint32_t value, uint32_t *boot_level)
+{
+ int result = -EINVAL;
+ uint32_t i;
+
+ for (i = 0; i < table->count; i++) {
+ if (value == table->dpm_levels[i].value) {
+ *boot_level = i;
+ result = 0;
+ }
+ }
+ return result;
+}
+
+static int fiji_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ int result = 0;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ table->GraphicsBootLevel = 0;
+ table->MemoryBootLevel = 0;
+
+ /* find boot level from dpm table */
+ result = fiji_find_boot_level(&(data->dpm_table.sclk_table),
+ data->vbios_boot_state.sclk_bootup_value,
+ (uint32_t *)&(table->GraphicsBootLevel));
+
+ result = fiji_find_boot_level(&(data->dpm_table.mclk_table),
+ data->vbios_boot_state.mclk_bootup_value,
+ (uint32_t *)&(table->MemoryBootLevel));
+
+ table->BootVddc = data->vbios_boot_state.vddc_bootup_value *
+ VOLTAGE_SCALE;
+ table->BootVddci = data->vbios_boot_state.vddci_bootup_value *
+ VOLTAGE_SCALE;
+ table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value *
+ VOLTAGE_SCALE;
+
+ CONVERT_FROM_HOST_TO_SMC_US(table->BootVddc);
+ CONVERT_FROM_HOST_TO_SMC_US(table->BootVddci);
+ CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+ return 0;
+}
+
+static int fiji_populate_smc_initailial_state(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint8_t count, level;
+
+ count = (uint8_t)(table_info->vdd_dep_on_sclk->count);
+ for (level = 0; level < count; level++) {
+ if(table_info->vdd_dep_on_sclk->entries[level].clk >=
+ data->vbios_boot_state.sclk_bootup_value) {
+ data->smc_state_table.GraphicsBootLevel = level;
+ break;
+ }
+ }
+
+ count = (uint8_t)(table_info->vdd_dep_on_mclk->count);
+ for (level = 0; level < count; level++) {
+ if(table_info->vdd_dep_on_mclk->entries[level].clk >=
+ data->vbios_boot_state.mclk_bootup_value) {
+ data->smc_state_table.MemoryBootLevel = level;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+ uint32_t ro, efuse, efuse2, clock_freq, volt_without_cks,
+ volt_with_cks, value;
+ uint16_t clock_freq_u16;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint8_t type, i, j, cks_setting, stretch_amount, stretch_amount2,
+ volt_offset = 0;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
+ table_info->vdd_dep_on_sclk;
+
+ stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount;
+
+ /* Read SMU_Eefuse to read and calculate RO and determine
+ * if the part is SS or FF. if RO >= 1660MHz, part is FF.
+ */
+ efuse = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixSMU_EFUSE_0 + (146 * 4));
+ efuse2 = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixSMU_EFUSE_0 + (148 * 4));
+ efuse &= 0xFF000000;
+ efuse = efuse >> 24;
+ efuse2 &= 0xF;
+
+ if (efuse2 == 1)
+ ro = (2300 - 1350) * efuse / 255 + 1350;
+ else
+ ro = (2500 - 1000) * efuse / 255 + 1000;
+
+ if (ro >= 1660)
+ type = 0;
+ else
+ type = 1;
+
+ /* Populate Stretch amount */
+ data->smc_state_table.ClockStretcherAmount = stretch_amount;
+
+ /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
+ for (i = 0; i < sclk_table->count; i++) {
+ data->smc_state_table.Sclk_CKS_masterEn0_7 |=
+ sclk_table->entries[i].cks_enable << i;
+ volt_without_cks = (uint32_t)((14041 *
+ (sclk_table->entries[i].clk/100) / 10000 + 3571 + 75 - ro) * 1000 /
+ (4026 - (13924 * (sclk_table->entries[i].clk/100) / 10000)));
+ volt_with_cks = (uint32_t)((13946 *
+ (sclk_table->entries[i].clk/100) / 10000 + 3320 + 45 - ro) * 1000 /
+ (3664 - (11454 * (sclk_table->entries[i].clk/100) / 10000)));
+ if (volt_without_cks >= volt_with_cks)
+ volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
+ sclk_table->entries[i].cks_voffset) * 100 / 625) + 1);
+ data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
+ }
+
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+ STRETCH_ENABLE, 0x0);
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+ masterReset, 0x1);
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+ staticEnable, 0x1);
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, PWR_CKS_ENABLE,
+ masterReset, 0x0);
+
+ /* Populate CKS Lookup Table */
+ if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
+ stretch_amount2 = 0;
+ else if (stretch_amount == 3 || stretch_amount == 4)
+ stretch_amount2 = 1;
+ else {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher);
+ PP_ASSERT_WITH_CODE(false,
+ "Stretch Amount in PPTable not supported\n",
+ return -EINVAL);
+ }
+
+ value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixPWR_CKS_CNTL);
+ value &= 0xFFC2FF87;
+ data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].minFreq =
+ fiji_clock_stretcher_lookup_table[stretch_amount2][0];
+ data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].maxFreq =
+ fiji_clock_stretcher_lookup_table[stretch_amount2][1];
+ clock_freq_u16 = (uint16_t)(PP_SMC_TO_HOST_UL(data->smc_state_table.
+ GraphicsLevel[data->smc_state_table.GraphicsDpmLevelCount - 1].
+ SclkFrequency) / 100);
+ if (fiji_clock_stretcher_lookup_table[stretch_amount2][0] <
+ clock_freq_u16 &&
+ fiji_clock_stretcher_lookup_table[stretch_amount2][1] >
+ clock_freq_u16) {
+ /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
+ value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 16;
+ /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
+ value |= (fiji_clock_stretcher_lookup_table[stretch_amount2][2]) << 18;
+ /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
+ value |= (fiji_clock_stretch_amount_conversion
+ [fiji_clock_stretcher_lookup_table[stretch_amount2][3]]
+ [stretch_amount]) << 3;
+ }
+ CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
+ CKS_LOOKUPTableEntry[0].minFreq);
+ CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.CKS_LOOKUPTable.
+ CKS_LOOKUPTableEntry[0].maxFreq);
+ data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting =
+ fiji_clock_stretcher_lookup_table[stretch_amount2][2] & 0x7F;
+ data->smc_state_table.CKS_LOOKUPTable.CKS_LOOKUPTableEntry[0].setting |=
+ (fiji_clock_stretcher_lookup_table[stretch_amount2][3]) << 7;
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixPWR_CKS_CNTL, value);
+
+ /* Populate DDT Lookup Table */
+ for (i = 0; i < 4; i++) {
+ /* Assign the minimum and maximum VID stored
+ * in the last row of Clock Stretcher Voltage Table.
+ */
+ data->smc_state_table.ClockStretcherDataTable.
+ ClockStretcherDataTableEntry[i].minVID =
+ (uint8_t) fiji_clock_stretcher_ddt_table[type][i][2];
+ data->smc_state_table.ClockStretcherDataTable.
+ ClockStretcherDataTableEntry[i].maxVID =
+ (uint8_t) fiji_clock_stretcher_ddt_table[type][i][3];
+ /* Loop through each SCLK and check the frequency
+ * to see if it lies within the frequency for clock stretcher.
+ */
+ for (j = 0; j < data->smc_state_table.GraphicsDpmLevelCount; j++) {
+ cks_setting = 0;
+ clock_freq = PP_SMC_TO_HOST_UL(
+ data->smc_state_table.GraphicsLevel[j].SclkFrequency);
+ /* Check the allowed frequency against the sclk level[j].
+ * Sclk's endianness has already been converted,
+ * and it's in 10Khz unit,
+ * as opposed to Data table, which is in Mhz unit.
+ */
+ if (clock_freq >=
+ (fiji_clock_stretcher_ddt_table[type][i][0]) * 100) {
+ cks_setting |= 0x2;
+ if (clock_freq <
+ (fiji_clock_stretcher_ddt_table[type][i][1]) * 100)
+ cks_setting |= 0x1;
+ }
+ data->smc_state_table.ClockStretcherDataTable.
+ ClockStretcherDataTableEntry[i].setting |= cks_setting << (j * 2);
+ }
+ CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.
+ ClockStretcherDataTable.
+ ClockStretcherDataTableEntry[i].setting);
+ }
+
+ value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL);
+ value &= 0xFFFFFFFE;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixPWR_CKS_CNTL, value);
+
+ return 0;
+}
+
+/**
+* Populates the SMC VRConfig field in DPM table.
+*
+* @param hwmgr the address of the hardware manager
+* @param table the SMC DPM table structure to be populated
+* @return always 0
+*/
+static int fiji_populate_vr_config(struct pp_hwmgr *hwmgr,
+ struct SMU73_Discrete_DpmTable *table)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint16_t config;
+
+ config = VR_MERGED_WITH_VDDC;
+ table->VRConfig |= (config << VRCONF_VDDGFX_SHIFT);
+
+ /* Set Vddc Voltage Controller */
+ if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+ config = VR_SVI2_PLANE_1;
+ table->VRConfig |= config;
+ } else {
+ PP_ASSERT_WITH_CODE(false,
+ "VDDC should be on SVI2 control in merged mode!",);
+ }
+ /* Set Vddci Voltage Controller */
+ if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) {
+ config = VR_SVI2_PLANE_2; /* only in merged mode */
+ table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+ } else if (FIJI_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) {
+ config = VR_SMIO_PATTERN_1;
+ table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+ } else {
+ config = VR_STATIC_VOLTAGE;
+ table->VRConfig |= (config << VRCONF_VDDCI_SHIFT);
+ }
+ /* Set Mvdd Voltage Controller */
+ if(FIJI_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
+ config = VR_SVI2_PLANE_2;
+ table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+ } else if(FIJI_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+ config = VR_SMIO_PATTERN_2;
+ table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+ } else {
+ config = VR_STATIC_VOLTAGE;
+ table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+ }
+
+ return 0;
+}
+
+/**
+* Initializes the SMC table and uploads it
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data (PowerState)
+* @return always 0
+*/
+static int fiji_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct SMU73_Discrete_DpmTable *table = &(data->smc_state_table);
+ const struct fiji_ulv_parm *ulv = &(data->ulv);
+ uint8_t i;
+ struct pp_atomctrl_gpio_pin_assignment gpio_pin;
+
+ result = fiji_setup_default_dpm_tables(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to setup default DPM tables!", return result);
+
+ if(FIJI_VOLTAGE_CONTROL_NONE != data->voltage_control)
+ fiji_populate_smc_voltage_tables(hwmgr, table);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition))
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StepVddc))
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (data->is_memory_gddr5)
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ if (ulv->ulv_supported && table_info->us_ulv_voltage_offset) {
+ result = fiji_populate_ulv_state(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize ULV state!", return result);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
+ }
+
+ result = fiji_populate_smc_link_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Link Level!", return result);
+
+ result = fiji_populate_all_graphic_levels(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Graphics Level!", return result);
+
+ result = fiji_populate_all_memory_levels(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Memory Level!", return result);
+
+ result = fiji_populate_smc_acpi_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize ACPI Level!", return result);
+
+ result = fiji_populate_smc_vce_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize VCE Level!", return result);
+
+ result = fiji_populate_smc_acp_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize ACP Level!", return result);
+
+ result = fiji_populate_smc_samu_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize SAMU Level!", return result);
+
+ /* Since only the initial state is completely set up at this point
+ * (the other states are just copies of the boot state) we only
+ * need to populate the ARB settings for the initial state.
+ */
+ result = fiji_program_memory_timing_parameters(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to Write ARB settings for the initial state.", return result);
+
+ result = fiji_populate_smc_uvd_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize UVD Level!", return result);
+
+ result = fiji_populate_smc_boot_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Boot Level!", return result);
+
+ result = fiji_populate_smc_initailial_state(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Boot State!", return result);
+
+ result = fiji_populate_bapm_parameters_in_dpm_table(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to populate BAPM Parameters!", return result);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher)) {
+ result = fiji_populate_clock_stretcher_data_table(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to populate Clock Stretcher Data Table!",
+ return result);
+ }
+
+ table->GraphicsVoltageChangeEnable = 1;
+ table->GraphicsThermThrottleEnable = 1;
+ table->GraphicsInterval = 1;
+ table->VoltageInterval = 1;
+ table->ThermalInterval = 1;
+ table->TemperatureLimitHigh =
+ table_info->cac_dtp_table->usTargetOperatingTemp *
+ FIJI_Q88_FORMAT_CONVERSION_UNIT;
+ table->TemperatureLimitLow =
+ (table_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+ FIJI_Q88_FORMAT_CONVERSION_UNIT;
+ table->MemoryVoltageChangeEnable = 1;
+ table->MemoryInterval = 1;
+ table->VoltageResponseTime = 0;
+ table->PhaseResponseTime = 0;
+ table->MemoryThermThrottleEnable = 1;
+ table->PCIeBootLinkLevel = 0; /* 0:Gen1 1:Gen2 2:Gen3*/
+ table->PCIeGenInterval = 1;
+
+ result = fiji_populate_vr_config(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to populate VRConfig setting!", return result);
+
+ table->ThermGpio = 17;
+ table->SclkStepSize = 0x4000;
+
+ if (atomctrl_get_pp_assign_pin(hwmgr, VDDC_VRHOT_GPIO_PINID, &gpio_pin)) {
+ table->VRHotGpio = gpio_pin.uc_gpio_pin_bit_shift;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot);
+ } else {
+ table->VRHotGpio = FIJI_UNUSED_GPIO_PIN;
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot);
+ }
+
+ if (atomctrl_get_pp_assign_pin(hwmgr, PP_AC_DC_SWITCH_GPIO_PINID,
+ &gpio_pin)) {
+ table->AcDcGpio = gpio_pin.uc_gpio_pin_bit_shift;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition);
+ } else {
+ table->AcDcGpio = FIJI_UNUSED_GPIO_PIN;
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition);
+ }
+
+ /* Thermal Output GPIO */
+ if (atomctrl_get_pp_assign_pin(hwmgr, THERMAL_INT_OUTPUT_GPIO_PINID,
+ &gpio_pin)) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ThermalOutGPIO);
+
+ table->ThermOutGpio = gpio_pin.uc_gpio_pin_bit_shift;
+
+ /* For porlarity read GPIOPAD_A with assigned Gpio pin
+ * since VBIOS will program this register to set 'inactive state',
+ * driver can then determine 'active state' from this and
+ * program SMU with correct polarity
+ */
+ table->ThermOutPolarity = (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
+ (1 << gpio_pin.uc_gpio_pin_bit_shift))) ? 1:0;
+ table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+ /* if required, combine VRHot/PCC with thermal out GPIO */
+ if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot) &&
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_CombinePCCWithThermalSignal))
+ table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+ } else {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ThermalOutGPIO);
+ table->ThermOutGpio = 17;
+ table->ThermOutPolarity = 1;
+ table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+ }
+
+ for (i = 0; i < SMU73_MAX_ENTRIES_SMIO; i++)
+ table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+ CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+ CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+ CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+ CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+ /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+ result = fiji_copy_bytes_to_smc(hwmgr->smumgr,
+ data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, SystemFlags),
+ (uint8_t *)&(table->SystemFlags),
+ sizeof(SMU73_Discrete_DpmTable) - 3 * sizeof(SMU73_PIDController),
+ data->sram_end);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to upload dpm data to SMC memory!", return result);
+
+ return 0;
+}
+
+/**
+* Initialize the ARB DRAM timing table's index field.
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always 0
+*/
+static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr)
+{
+ const struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t tmp;
+ int result;
+
+ /* This is a read-modify-write on the first byte of the ARB table.
+ * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
+ * is the field 'current'.
+ * This solution is ugly, but we never write the whole table only
+ * individual fields in it.
+ * In reality this field should not be in that structure
+ * but in a soft register.
+ */
+ result = fiji_read_smc_sram_dword(hwmgr->smumgr,
+ data->arb_table_start, &tmp, data->sram_end);
+
+ if (result)
+ return result;
+
+ tmp &= 0x00FFFFFF;
+ tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+ return fiji_write_smc_sram_dword(hwmgr->smumgr,
+ data->arb_table_start, tmp, data->sram_end);
+}
+
+static int fiji_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr)
+{
+ if(phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_EnableVRHotGPIOInterrupt);
+
+ return 0;
+}
+
+static int fiji_enable_sclk_control(struct pp_hwmgr *hwmgr)
+{
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+ SCLK_PWRMGT_OFF, 0);
+ return 0;
+}
+
+static int fiji_enable_ulv(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_ulv_parm *ulv = &(data->ulv);
+
+ if (ulv->ulv_supported)
+ return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
+
+ return 0;
+}
+
+static int fiji_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkDeepSleep)) {
+ if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to enable Master Deep Sleep switch failed!",
+ return -1);
+ } else {
+ if (smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_MASTER_DeepSleep_OFF)) {
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to disable Master Deep Sleep switch failed!",
+ return -1);
+ }
+ }
+
+ return 0;
+}
+
+static int fiji_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t val, val0, val2;
+ uint32_t i, cpl_cntl, cpl_threshold, mc_threshold;
+
+ /* enable SCLK dpm */
+ if(!data->sclk_dpm_key_disabled)
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
+ "Failed to enable SCLK DPM during DPM Start Function!",
+ return -1);
+
+ /* enable MCLK dpm */
+ if(0 == data->mclk_dpm_key_disabled) {
+ cpl_threshold = 0;
+ mc_threshold = 0;
+
+ /* Read per MCD tile (0 - 7) */
+ for (i = 0; i < 8; i++) {
+ PHM_WRITE_FIELD(hwmgr->device, MC_CONFIG_MCD, MC_RD_ENABLE, i);
+ val = cgs_read_register(hwmgr->device, mmMC_SEQ_RESERVE_0_S) & 0xf0000000;
+ if (0xf0000000 != val) {
+ /* count number of MCQ that has channel(s) enabled */
+ cpl_threshold++;
+ /* only harvest 3 or full 4 supported */
+ mc_threshold = val ? 3 : 4;
+ }
+ }
+ PP_ASSERT_WITH_CODE(0 != cpl_threshold,
+ "Number of MCQ is zero!", return -EINVAL;);
+
+ mc_threshold = ((mc_threshold & LCAC_MC0_CNTL__MC0_THRESHOLD_MASK) <<
+ LCAC_MC0_CNTL__MC0_THRESHOLD__SHIFT) |
+ LCAC_MC0_CNTL__MC0_ENABLE_MASK;
+ cpl_cntl = ((cpl_threshold & LCAC_CPL_CNTL__CPL_THRESHOLD_MASK) <<
+ LCAC_CPL_CNTL__CPL_THRESHOLD__SHIFT) |
+ LCAC_CPL_CNTL__CPL_ENABLE_MASK;
+ cpl_cntl = (cpl_cntl | (8 << LCAC_CPL_CNTL__CPL_BLOCK_ID__SHIFT));
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC0_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC1_CNTL, mc_threshold);
+ if (8 == cpl_threshold) {
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC2_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC3_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC4_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC5_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC6_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC7_CNTL, mc_threshold);
+ }
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_CPL_CNTL, cpl_cntl);
+
+ udelay(5);
+
+ mc_threshold = mc_threshold |
+ (1 << LCAC_MC0_CNTL__MC0_SIGNAL_ID__SHIFT);
+ cpl_cntl = cpl_cntl | (1 << LCAC_CPL_CNTL__CPL_SIGNAL_ID__SHIFT);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC0_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC1_CNTL, mc_threshold);
+ if (8 == cpl_threshold) {
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC2_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC3_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC4_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC5_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC6_CNTL, mc_threshold);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC7_CNTL, mc_threshold);
+ }
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_CPL_CNTL, cpl_cntl);
+
+ /* Program CAC_EN per MCD (0-7) Tile */
+ val0 = val = cgs_read_register(hwmgr->device, mmMC_CONFIG_MCD);
+ val &= ~(MC_CONFIG_MCD__MCD0_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD1_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD2_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD3_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD4_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD5_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD6_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MCD7_WR_ENABLE_MASK |
+ MC_CONFIG_MCD__MC_RD_ENABLE_MASK);
+
+ for (i = 0; i < 8; i++) {
+ /* Enable MCD i Tile read & write */
+ val2 = (val | (i << MC_CONFIG_MCD__MC_RD_ENABLE__SHIFT) |
+ (1 << i));
+ cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val2);
+ /* Enbale CAC_ON MCD i Tile */
+ val2 = cgs_read_register(hwmgr->device, mmMC_SEQ_CNTL);
+ val2 |= MC_SEQ_CNTL__CAC_EN_MASK;
+ cgs_write_register(hwmgr->device, mmMC_SEQ_CNTL, val2);
+ }
+ /* Set MC_CONFIG_MCD back to its default setting val0 */
+ cgs_write_register(hwmgr->device, mmMC_CONFIG_MCD, val0);
+
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_Enable)),
+ "Failed to enable MCLK DPM during DPM Start Function!",
+ return -1);
+ }
+ return 0;
+}
+
+static int fiji_start_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ /*enable general power management */
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+ GLOBAL_PWRMGT_EN, 1);
+ /* enable sclk deep sleep */
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+ DYNAMIC_PM_EN, 1);
+ /* prepare for PCIE DPM */
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ data->soft_regs_start + offsetof(SMU73_SoftRegisters,
+ VoltageChangeTimeout), 0x1000);
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
+ SWRST_COMMAND_1, RESETLC, 0x0);
+
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_Voltage_Cntl_Enable)),
+ "Failed to enable voltage DPM during DPM Start Function!",
+ return -1);
+
+ if (fiji_enable_sclk_mclk_dpm(hwmgr)) {
+ printk(KERN_ERR "Failed to enable Sclk DPM and Mclk DPM!");
+ return -1;
+ }
+
+ /* enable PCIE dpm */
+ if(!data->pcie_dpm_key_disabled) {
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_Enable)),
+ "Failed to enable pcie DPM during DPM Start Function!",
+ return -1);
+ }
+
+ return 0;
+}
+
+static void fiji_set_dpm_event_sources(struct pp_hwmgr *hwmgr,
+ uint32_t sources)
+{
+ bool protection;
+ enum DPM_EVENT_SRC src;
+
+ switch (sources) {
+ default:
+ printk(KERN_ERR "Unknown throttling event sources.");
+ /* fall through */
+ case 0:
+ protection = false;
+ /* src is unused */
+ break;
+ case (1 << PHM_AutoThrottleSource_Thermal):
+ protection = true;
+ src = DPM_EVENT_SRC_DIGITAL;
+ break;
+ case (1 << PHM_AutoThrottleSource_External):
+ protection = true;
+ src = DPM_EVENT_SRC_EXTERNAL;
+ break;
+ case (1 << PHM_AutoThrottleSource_External) |
+ (1 << PHM_AutoThrottleSource_Thermal):
+ protection = true;
+ src = DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL;
+ break;
+ }
+ /* Order matters - don't enable thermal protection for the wrong source. */
+ if (protection) {
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL,
+ DPM_EVENT_SRC, src);
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+ THERMAL_PROTECTION_DIS,
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ThermalController));
+ } else
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+ THERMAL_PROTECTION_DIS, 1);
+}
+
+static int fiji_enable_auto_throttle_source(struct pp_hwmgr *hwmgr,
+ PHM_AutoThrottleSource source)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (!(data->active_auto_throttle_sources & (1 << source))) {
+ data->active_auto_throttle_sources |= 1 << source;
+ fiji_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
+ }
+ return 0;
+}
+
+static int fiji_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
+{
+ return fiji_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
+}
+
+static int fiji_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = (!fiji_is_dpm_running(hwmgr))? 0 : -1;
+ PP_ASSERT_WITH_CODE(result == 0,
+ "DPM is already running right now, no need to enable DPM!",
+ return 0);
+
+ if (fiji_voltage_control(hwmgr)) {
+ tmp_result = fiji_enable_voltage_control(hwmgr);
+ PP_ASSERT_WITH_CODE(tmp_result == 0,
+ "Failed to enable voltage control!",
+ result = tmp_result);
+ }
+
+ if (fiji_voltage_control(hwmgr)) {
+ tmp_result = fiji_construct_voltage_tables(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to contruct voltage tables!",
+ result = tmp_result);
+ }
+
+ tmp_result = fiji_initialize_mc_reg_table(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize MC reg table!", result = tmp_result);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EngineSpreadSpectrumSupport))
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 1);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ThermalController))
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 0);
+
+ tmp_result = fiji_program_static_screen_threshold_parameters(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to program static screen threshold parameters!",
+ result = tmp_result);
+
+ tmp_result = fiji_enable_display_gap(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable display gap!", result = tmp_result);
+
+ tmp_result = fiji_program_voting_clients(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to program voting clients!", result = tmp_result);
+
+ tmp_result = fiji_process_firmware_header(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to process firmware header!", result = tmp_result);
+
+ tmp_result = fiji_initial_switch_from_arbf0_to_f1(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize switch from ArbF0 to F1!",
+ result = tmp_result);
+
+ tmp_result = fiji_init_smc_table(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize SMC table!", result = tmp_result);
+
+ tmp_result = fiji_init_arb_table_index(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize ARB table index!", result = tmp_result);
+
+ tmp_result = fiji_populate_pm_fuses(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to populate PM fuses!", result = tmp_result);
+
+ tmp_result = fiji_enable_vrhot_gpio_interrupt(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
+
+ tmp_result = tonga_notify_smc_display_change(hwmgr, false);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to notify no display!", result = tmp_result);
+
+ tmp_result = fiji_enable_sclk_control(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable SCLK control!", result = tmp_result);
+
+ tmp_result = fiji_enable_ulv(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable ULV!", result = tmp_result);
+
+ tmp_result = fiji_enable_deep_sleep_master_switch(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable deep sleep master switch!", result = tmp_result);
+
+ tmp_result = fiji_start_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to start DPM!", result = tmp_result);
+
+ tmp_result = fiji_enable_smc_cac(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable SMC CAC!", result = tmp_result);
+
+ tmp_result = fiji_enable_power_containment(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable power containment!", result = tmp_result);
+
+ tmp_result = fiji_power_control_set_level(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to power control set level!", result = tmp_result);
+
+ tmp_result = fiji_enable_thermal_auto_throttle(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable thermal auto throttle!", result = tmp_result);
+
+ return result;
+}
+
+static int fiji_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t level, tmp;
+
+ if (!data->sclk_dpm_key_disabled) {
+ if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ level = 0;
+ tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
+ while (tmp >>= 1)
+ level++;
+ if (level)
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_SetEnabledMask,
+ (1 << level));
+ }
+ }
+
+ if (!data->mclk_dpm_key_disabled) {
+ if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ level = 0;
+ tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+ while (tmp >>= 1)
+ level++;
+ if (level)
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ (1 << level));
+ }
+ }
+
+ if (!data->pcie_dpm_key_disabled) {
+ if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+ level = 0;
+ tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
+ while (tmp >>= 1)
+ level++;
+ if (level)
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_ForceLevel,
+ (1 << level));
+ }
+ }
+ return 0;
+}
+
+static void fiji_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
+{
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)hwmgr->pptable;
+ struct phm_clock_voltage_dependency_table *table =
+ table_info->vddc_dep_on_dal_pwrl;
+ struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table;
+ enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level;
+ uint32_t req_vddc = 0, req_volt, i;
+
+ if (!table && !(dal_power_level >= PP_DAL_POWERLEVEL_ULTRALOW &&
+ dal_power_level <= PP_DAL_POWERLEVEL_PERFORMANCE))
+ return;
+
+ for (i= 0; i < table->count; i++) {
+ if (dal_power_level == table->entries[i].clk) {
+ req_vddc = table->entries[i].v;
+ break;
+ }
+ }
+
+ vddc_table = table_info->vdd_dep_on_sclk;
+ for (i= 0; i < vddc_table->count; i++) {
+ if (req_vddc <= vddc_table->entries[i].vddc) {
+ req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE)
+ << VDDC_SHIFT;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_VddC_Request, req_volt);
+ return;
+ }
+ }
+ printk(KERN_ERR "DAL requested level can not"
+ " found a available voltage in VDDC DPM Table \n");
+}
+
+static int fiji_upload_dpmlevel_enable_mask(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ fiji_apply_dal_min_voltage_request(hwmgr);
+
+ if (!data->sclk_dpm_key_disabled) {
+ if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_SetEnabledMask,
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+ }
+ return 0;
+}
+
+static int fiji_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (!fiji_is_dpm_running(hwmgr))
+ return -EINVAL;
+
+ if (!data->pcie_dpm_key_disabled) {
+ smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_UnForceLevel);
+ }
+
+ return fiji_upload_dpmlevel_enable_mask(hwmgr);
+}
+
+static uint32_t fiji_get_lowest_enabled_level(
+ struct pp_hwmgr *hwmgr, uint32_t mask)
+{
+ uint32_t level = 0;
+
+ while(0 == (mask & (1 << level)))
+ level++;
+
+ return level;
+}
+
+static int fiji_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data =
+ (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t level;
+
+ if (!data->sclk_dpm_key_disabled)
+ if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ level = fiji_get_lowest_enabled_level(hwmgr,
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_SetEnabledMask,
+ (1 << level));
+
+ }
+
+ if (!data->mclk_dpm_key_disabled) {
+ if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ level = fiji_get_lowest_enabled_level(hwmgr,
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ (1 << level));
+ }
+ }
+
+ if (!data->pcie_dpm_key_disabled) {
+ if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+ level = fiji_get_lowest_enabled_level(hwmgr,
+ data->dpm_level_enable_mask.pcie_dpm_enable_mask);
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_ForceLevel,
+ (1 << level));
+ }
+ }
+
+ return 0;
+
+}
+static int fiji_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+ enum amd_dpm_forced_level level)
+{
+ int ret = 0;
+
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_HIGH:
+ ret = fiji_force_dpm_highest(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_LOW:
+ ret = fiji_force_dpm_lowest(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ ret = fiji_unforce_dpm_levels(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ hwmgr->dpm_level = level;
+
+ return ret;
+}
+
+static int fiji_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+ return sizeof(struct fiji_power_state);
+}
+
+static int fiji_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
+ void *state, struct pp_power_state *power_state,
+ void *pp_table, uint32_t classification_flag)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_power_state *fiji_power_state =
+ (struct fiji_power_state *)(&(power_state->hardware));
+ struct fiji_performance_level *performance_level;
+ ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
+ ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
+ (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
+ ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
+ (ATOM_Tonga_SCLK_Dependency_Table *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+ ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+ (ATOM_Tonga_MCLK_Dependency_Table *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+
+ /* The following fields are not initialized here: id orderedList allStatesList */
+ power_state->classification.ui_label =
+ (le16_to_cpu(state_entry->usClassification) &
+ ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
+ ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+ power_state->classification.flags = classification_flag;
+ /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
+
+ power_state->classification.temporary_state = false;
+ power_state->classification.to_be_deleted = false;
+
+ power_state->validation.disallowOnDC =
+ (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
+ ATOM_Tonga_DISALLOW_ON_DC));
+
+ power_state->pcie.lanes = 0;
+
+ power_state->display.disableFrameModulation = false;
+ power_state->display.limitRefreshrate = false;
+ power_state->display.enableVariBright =
+ (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) &
+ ATOM_Tonga_ENABLE_VARIBRIGHT));
+
+ power_state->validation.supportedPowerLevels = 0;
+ power_state->uvd_clocks.VCLK = 0;
+ power_state->uvd_clocks.DCLK = 0;
+ power_state->temperatures.min = 0;
+ power_state->temperatures.max = 0;
+
+ performance_level = &(fiji_power_state->performance_levels
+ [fiji_power_state->performance_level_count++]);
+
+ PP_ASSERT_WITH_CODE(
+ (fiji_power_state->performance_level_count < SMU73_MAX_LEVELS_GRAPHICS),
+ "Performance levels exceeds SMC limit!",
+ return -1);
+
+ PP_ASSERT_WITH_CODE(
+ (fiji_power_state->performance_level_count <=
+ hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
+ "Performance levels exceeds Driver limit!",
+ return -1);
+
+ /* Performance levels are arranged from low to high. */
+ performance_level->memory_clock = mclk_dep_table->entries
+ [state_entry->ucMemoryClockIndexLow].ulMclk;
+ performance_level->engine_clock = sclk_dep_table->entries
+ [state_entry->ucEngineClockIndexLow].ulSclk;
+ performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
+ state_entry->ucPCIEGenLow);
+ performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
+ state_entry->ucPCIELaneHigh);
+
+ performance_level = &(fiji_power_state->performance_levels
+ [fiji_power_state->performance_level_count++]);
+ performance_level->memory_clock = mclk_dep_table->entries
+ [state_entry->ucMemoryClockIndexHigh].ulMclk;
+ performance_level->engine_clock = sclk_dep_table->entries
+ [state_entry->ucEngineClockIndexHigh].ulSclk;
+ performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap,
+ state_entry->ucPCIEGenHigh);
+ performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap,
+ state_entry->ucPCIELaneHigh);
+
+ return 0;
+}
+
+static int fiji_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+ unsigned long entry_index, struct pp_power_state *state)
+{
+ int result;
+ struct fiji_power_state *ps;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+ table_info->vdd_dep_on_mclk;
+
+ state->hardware.magic = PHM_VIslands_Magic;
+
+ ps = (struct fiji_power_state *)(&state->hardware);
+
+ result = tonga_get_powerplay_table_entry(hwmgr, entry_index, state,
+ fiji_get_pp_table_entry_callback_func);
+
+ /* This is the earliest time we have all the dependency table and the VBIOS boot state
+ * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
+ * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
+ */
+ if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
+ if (dep_mclk_table->entries[0].clk !=
+ data->vbios_boot_state.mclk_bootup_value)
+ printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
+ "does not match VBIOS boot MCLK level");
+ if (dep_mclk_table->entries[0].vddci !=
+ data->vbios_boot_state.vddci_bootup_value)
+ printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
+ "does not match VBIOS boot VDDCI level");
+ }
+
+ /* set DC compatible flag if this state supports DC */
+ if (!state->validation.disallowOnDC)
+ ps->dc_compatible = true;
+
+ if (state->classification.flags & PP_StateClassificationFlag_ACPI)
+ data->acpi_pcie_gen = ps->performance_levels[0].pcie_gen;
+
+ ps->uvd_clks.vclk = state->uvd_clocks.VCLK;
+ ps->uvd_clks.dclk = state->uvd_clocks.DCLK;
+
+ if (!result) {
+ uint32_t i;
+
+ switch (state->classification.ui_label) {
+ case PP_StateUILabel_Performance:
+ data->use_pcie_performance_levels = true;
+
+ for (i = 0; i < ps->performance_level_count; i++) {
+ if (data->pcie_gen_performance.max <
+ ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_performance.max =
+ ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_gen_performance.min >
+ ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_performance.min =
+ ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_lane_performance.max <
+ ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_performance.max =
+ ps->performance_levels[i].pcie_lane;
+
+ if (data->pcie_lane_performance.min >
+ ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_performance.min =
+ ps->performance_levels[i].pcie_lane;
+ }
+ break;
+ case PP_StateUILabel_Battery:
+ data->use_pcie_power_saving_levels = true;
+
+ for (i = 0; i < ps->performance_level_count; i++) {
+ if (data->pcie_gen_power_saving.max <
+ ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_power_saving.max =
+ ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_gen_power_saving.min >
+ ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_power_saving.min =
+ ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_lane_power_saving.max <
+ ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_power_saving.max =
+ ps->performance_levels[i].pcie_lane;
+
+ if (data->pcie_lane_power_saving.min >
+ ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_power_saving.min =
+ ps->performance_levels[i].pcie_lane;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static int fiji_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *request_ps,
+ const struct pp_power_state *current_ps)
+{
+ struct fiji_power_state *fiji_ps =
+ cast_phw_fiji_power_state(&request_ps->hardware);
+ uint32_t sclk;
+ uint32_t mclk;
+ struct PP_Clocks minimum_clocks = {0};
+ bool disable_mclk_switching;
+ bool disable_mclk_switching_for_frame_lock;
+ struct cgs_display_info info = {0};
+ const struct phm_clock_and_voltage_limits *max_limits;
+ uint32_t i;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ int32_t count;
+ int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
+
+ data->battery_state = (PP_StateUILabel_Battery ==
+ request_ps->classification.ui_label);
+
+ PP_ASSERT_WITH_CODE(fiji_ps->performance_level_count == 2,
+ "VI should always have 2 performance levels",);
+
+ max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
+ &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
+ &(hwmgr->dyn_state.max_clock_voltage_on_dc);
+
+ /* Cap clock DPM tables at DC MAX if it is in DC. */
+ if (PP_PowerSource_DC == hwmgr->power_source) {
+ for (i = 0; i < fiji_ps->performance_level_count; i++) {
+ if (fiji_ps->performance_levels[i].memory_clock > max_limits->mclk)
+ fiji_ps->performance_levels[i].memory_clock = max_limits->mclk;
+ if (fiji_ps->performance_levels[i].engine_clock > max_limits->sclk)
+ fiji_ps->performance_levels[i].engine_clock = max_limits->sclk;
+ }
+ }
+
+ fiji_ps->vce_clks.evclk = hwmgr->vce_arbiter.evclk;
+ fiji_ps->vce_clks.ecclk = hwmgr->vce_arbiter.ecclk;
+
+ fiji_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+
+ /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
+
+ /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState)) {
+ max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
+ stable_pstate_sclk = (max_limits->sclk * 75) / 100;
+
+ for (count = table_info->vdd_dep_on_sclk->count - 1;
+ count >= 0; count--) {
+ if (stable_pstate_sclk >=
+ table_info->vdd_dep_on_sclk->entries[count].clk) {
+ stable_pstate_sclk =
+ table_info->vdd_dep_on_sclk->entries[count].clk;
+ break;
+ }
+ }
+
+ if (count < 0)
+ stable_pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
+
+ stable_pstate_mclk = max_limits->mclk;
+
+ minimum_clocks.engineClock = stable_pstate_sclk;
+ minimum_clocks.memoryClock = stable_pstate_mclk;
+ }
+
+ if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
+ minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
+
+ if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+ minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+ fiji_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+
+ if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
+ PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <=
+ hwmgr->platform_descriptor.overdriveLimit.engineClock),
+ "Overdrive sclk exceeds limit",
+ hwmgr->gfx_arbiter.sclk_over_drive =
+ hwmgr->platform_descriptor.overdriveLimit.engineClock);
+
+ if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
+ fiji_ps->performance_levels[1].engine_clock =
+ hwmgr->gfx_arbiter.sclk_over_drive;
+ }
+
+ if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
+ PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <=
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock),
+ "Overdrive mclk exceeds limit",
+ hwmgr->gfx_arbiter.mclk_over_drive =
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock);
+
+ if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
+ fiji_ps->performance_levels[1].memory_clock =
+ hwmgr->gfx_arbiter.mclk_over_drive;
+ }
+
+ disable_mclk_switching_for_frame_lock = phm_cap_enabled(
+ hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
+
+ disable_mclk_switching = (1 < info.display_count) ||
+ disable_mclk_switching_for_frame_lock;
+
+ sclk = fiji_ps->performance_levels[0].engine_clock;
+ mclk = fiji_ps->performance_levels[0].memory_clock;
+
+ if (disable_mclk_switching)
+ mclk = fiji_ps->performance_levels
+ [fiji_ps->performance_level_count - 1].memory_clock;
+
+ if (sclk < minimum_clocks.engineClock)
+ sclk = (minimum_clocks.engineClock > max_limits->sclk) ?
+ max_limits->sclk : minimum_clocks.engineClock;
+
+ if (mclk < minimum_clocks.memoryClock)
+ mclk = (minimum_clocks.memoryClock > max_limits->mclk) ?
+ max_limits->mclk : minimum_clocks.memoryClock;
+
+ fiji_ps->performance_levels[0].engine_clock = sclk;
+ fiji_ps->performance_levels[0].memory_clock = mclk;
+
+ fiji_ps->performance_levels[1].engine_clock =
+ (fiji_ps->performance_levels[1].engine_clock >=
+ fiji_ps->performance_levels[0].engine_clock) ?
+ fiji_ps->performance_levels[1].engine_clock :
+ fiji_ps->performance_levels[0].engine_clock;
+
+ if (disable_mclk_switching) {
+ if (mclk < fiji_ps->performance_levels[1].memory_clock)
+ mclk = fiji_ps->performance_levels[1].memory_clock;
+
+ fiji_ps->performance_levels[0].memory_clock = mclk;
+ fiji_ps->performance_levels[1].memory_clock = mclk;
+ } else {
+ if (fiji_ps->performance_levels[1].memory_clock <
+ fiji_ps->performance_levels[0].memory_clock)
+ fiji_ps->performance_levels[1].memory_clock =
+ fiji_ps->performance_levels[0].memory_clock;
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState)) {
+ for (i = 0; i < fiji_ps->performance_level_count; i++) {
+ fiji_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
+ fiji_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
+ fiji_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
+ fiji_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
+ }
+ }
+
+ return 0;
+}
+
+static int fiji_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states =
+ (const struct phm_set_power_state_input *)input;
+ const struct fiji_power_state *fiji_ps =
+ cast_const_phw_fiji_power_state(states->pnew_state);
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
+ uint32_t sclk = fiji_ps->performance_levels
+ [fiji_ps->performance_level_count - 1].engine_clock;
+ struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
+ uint32_t mclk = fiji_ps->performance_levels
+ [fiji_ps->performance_level_count - 1].memory_clock;
+ struct PP_Clocks min_clocks = {0};
+ uint32_t i;
+ struct cgs_display_info info = {0};
+
+ data->need_update_smu7_dpm_table = 0;
+
+ for (i = 0; i < sclk_table->count; i++) {
+ if (sclk == sclk_table->dpm_levels[i].value)
+ break;
+ }
+
+ if (i >= sclk_table->count)
+ data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+ else {
+ /* TODO: Check SCLK in DAL's minimum clocks
+ * in case DeepSleep divider update is required.
+ */
+ if(data->display_timing.min_clock_in_sr != min_clocks.engineClockInSR)
+ data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
+ }
+
+ for (i = 0; i < mclk_table->count; i++) {
+ if (mclk == mclk_table->dpm_levels[i].value)
+ break;
+ }
+
+ if (i >= mclk_table->count)
+ data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+
+ if (data->display_timing.num_existing_displays != info.display_count)
+ data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
+
+ return 0;
+}
+
+static uint16_t fiji_get_maximum_link_speed(struct pp_hwmgr *hwmgr,
+ const struct fiji_power_state *fiji_ps)
+{
+ uint32_t i;
+ uint32_t sclk, max_sclk = 0;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_dpm_table *dpm_table = &data->dpm_table;
+
+ for (i = 0; i < fiji_ps->performance_level_count; i++) {
+ sclk = fiji_ps->performance_levels[i].engine_clock;
+ if (max_sclk < sclk)
+ max_sclk = sclk;
+ }
+
+ for (i = 0; i < dpm_table->sclk_table.count; i++) {
+ if (dpm_table->sclk_table.dpm_levels[i].value == max_sclk)
+ return (uint16_t) ((i >= dpm_table->pcie_speed_table.count) ?
+ dpm_table->pcie_speed_table.dpm_levels
+ [dpm_table->pcie_speed_table.count - 1].value :
+ dpm_table->pcie_speed_table.dpm_levels[i].value);
+ }
+
+ return 0;
+}
+
+static int fiji_request_link_speed_change_before_state_change(
+ struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states =
+ (const struct phm_set_power_state_input *)input;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ const struct fiji_power_state *fiji_nps =
+ cast_const_phw_fiji_power_state(states->pnew_state);
+ const struct fiji_power_state *fiji_cps =
+ cast_const_phw_fiji_power_state(states->pcurrent_state);
+
+ uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_nps);
+ uint16_t current_link_speed;
+
+ if (data->force_pcie_gen == PP_PCIEGenInvalid)
+ current_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_cps);
+ else
+ current_link_speed = data->force_pcie_gen;
+
+ data->force_pcie_gen = PP_PCIEGenInvalid;
+ data->pspp_notify_required = false;
+ if (target_link_speed > current_link_speed) {
+ switch(target_link_speed) {
+ case PP_PCIEGen3:
+ if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
+ break;
+ data->force_pcie_gen = PP_PCIEGen2;
+ if (current_link_speed == PP_PCIEGen2)
+ break;
+ case PP_PCIEGen2:
+ if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
+ break;
+ default:
+ data->force_pcie_gen = fiji_get_current_pcie_speed(hwmgr);
+ break;
+ }
+ } else {
+ if (target_link_speed < current_link_speed)
+ data->pspp_notify_required = true;
+ }
+
+ return 0;
+}
+
+static int fiji_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (0 == data->need_update_smu7_dpm_table)
+ return 0;
+
+ if ((0 == data->sclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+ PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+ "Trying to freeze SCLK DPM when DPM is disabled",);
+ PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_FreezeLevel),
+ "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ if ((0 == data->mclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table &
+ DPMTABLE_OD_UPDATE_MCLK)) {
+ PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+ "Trying to freeze MCLK DPM when DPM is disabled",);
+ PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_FreezeLevel),
+ "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ return 0;
+}
+
+static int fiji_populate_and_upload_sclk_mclk_dpm_levels(
+ struct pp_hwmgr *hwmgr, const void *input)
+{
+ int result = 0;
+ const struct phm_set_power_state_input *states =
+ (const struct phm_set_power_state_input *)input;
+ const struct fiji_power_state *fiji_ps =
+ cast_const_phw_fiji_power_state(states->pnew_state);
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t sclk = fiji_ps->performance_levels
+ [fiji_ps->performance_level_count - 1].engine_clock;
+ uint32_t mclk = fiji_ps->performance_levels
+ [fiji_ps->performance_level_count - 1].memory_clock;
+ struct fiji_dpm_table *dpm_table = &data->dpm_table;
+
+ struct fiji_dpm_table *golden_dpm_table = &data->golden_dpm_table;
+ uint32_t dpm_count, clock_percent;
+ uint32_t i;
+
+ if (0 == data->need_update_smu7_dpm_table)
+ return 0;
+
+ if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
+ dpm_table->sclk_table.dpm_levels
+ [dpm_table->sclk_table.count - 1].value = sclk;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_OD6PlusinACSupport) ||
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_OD6PlusinDCSupport)) {
+ /* Need to do calculation based on the golden DPM table
+ * as the Heatmap GPU Clock axis is also based on the default values
+ */
+ PP_ASSERT_WITH_CODE(
+ (golden_dpm_table->sclk_table.dpm_levels
+ [golden_dpm_table->sclk_table.count - 1].value != 0),
+ "Divide by 0!",
+ return -1);
+ dpm_count = dpm_table->sclk_table.count < 2 ?
+ 0 : dpm_table->sclk_table.count - 2;
+ for (i = dpm_count; i > 1; i--) {
+ if (sclk > golden_dpm_table->sclk_table.dpm_levels
+ [golden_dpm_table->sclk_table.count-1].value) {
+ clock_percent =
+ ((sclk - golden_dpm_table->sclk_table.dpm_levels
+ [golden_dpm_table->sclk_table.count-1].value) * 100) /
+ golden_dpm_table->sclk_table.dpm_levels
+ [golden_dpm_table->sclk_table.count-1].value;
+
+ dpm_table->sclk_table.dpm_levels[i].value =
+ golden_dpm_table->sclk_table.dpm_levels[i].value +
+ (golden_dpm_table->sclk_table.dpm_levels[i].value *
+ clock_percent)/100;
+
+ } else if (golden_dpm_table->sclk_table.dpm_levels
+ [dpm_table->sclk_table.count-1].value > sclk) {
+ clock_percent =
+ ((golden_dpm_table->sclk_table.dpm_levels
+ [golden_dpm_table->sclk_table.count - 1].value - sclk) *
+ 100) /
+ golden_dpm_table->sclk_table.dpm_levels
+ [golden_dpm_table->sclk_table.count-1].value;
+
+ dpm_table->sclk_table.dpm_levels[i].value =
+ golden_dpm_table->sclk_table.dpm_levels[i].value -
+ (golden_dpm_table->sclk_table.dpm_levels[i].value *
+ clock_percent) / 100;
+ } else
+ dpm_table->sclk_table.dpm_levels[i].value =
+ golden_dpm_table->sclk_table.dpm_levels[i].value;
+ }
+ }
+ }
+
+ if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
+ dpm_table->mclk_table.dpm_levels
+ [dpm_table->mclk_table.count - 1].value = mclk;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_OD6PlusinACSupport) ||
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_OD6PlusinDCSupport)) {
+
+ PP_ASSERT_WITH_CODE(
+ (golden_dpm_table->mclk_table.dpm_levels
+ [golden_dpm_table->mclk_table.count-1].value != 0),
+ "Divide by 0!",
+ return -1);
+ dpm_count = dpm_table->mclk_table.count < 2 ?
+ 0 : dpm_table->mclk_table.count - 2;
+ for (i = dpm_count; i > 1; i--) {
+ if (mclk > golden_dpm_table->mclk_table.dpm_levels
+ [golden_dpm_table->mclk_table.count-1].value) {
+ clock_percent = ((mclk -
+ golden_dpm_table->mclk_table.dpm_levels
+ [golden_dpm_table->mclk_table.count-1].value) * 100) /
+ golden_dpm_table->mclk_table.dpm_levels
+ [golden_dpm_table->mclk_table.count-1].value;
+
+ dpm_table->mclk_table.dpm_levels[i].value =
+ golden_dpm_table->mclk_table.dpm_levels[i].value +
+ (golden_dpm_table->mclk_table.dpm_levels[i].value *
+ clock_percent) / 100;
+
+ } else if (golden_dpm_table->mclk_table.dpm_levels
+ [dpm_table->mclk_table.count-1].value > mclk) {
+ clock_percent = ((golden_dpm_table->mclk_table.dpm_levels
+ [golden_dpm_table->mclk_table.count-1].value - mclk) * 100) /
+ golden_dpm_table->mclk_table.dpm_levels
+ [golden_dpm_table->mclk_table.count-1].value;
+
+ dpm_table->mclk_table.dpm_levels[i].value =
+ golden_dpm_table->mclk_table.dpm_levels[i].value -
+ (golden_dpm_table->mclk_table.dpm_levels[i].value *
+ clock_percent) / 100;
+ } else
+ dpm_table->mclk_table.dpm_levels[i].value =
+ golden_dpm_table->mclk_table.dpm_levels[i].value;
+ }
+ }
+ }
+
+ if (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
+ result = fiji_populate_all_memory_levels(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
+ return result);
+ }
+
+ if (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
+ /*populate MCLK dpm table to SMU7 */
+ result = fiji_populate_all_memory_levels(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
+ return result);
+ }
+
+ return result;
+}
+
+static int fiji_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
+ struct fiji_single_dpm_table * dpm_table,
+ uint32_t low_limit, uint32_t high_limit)
+{
+ uint32_t i;
+
+ for (i = 0; i < dpm_table->count; i++) {
+ if ((dpm_table->dpm_levels[i].value < low_limit) ||
+ (dpm_table->dpm_levels[i].value > high_limit))
+ dpm_table->dpm_levels[i].enabled = false;
+ else
+ dpm_table->dpm_levels[i].enabled = true;
+ }
+ return 0;
+}
+
+static int fiji_trim_dpm_states(struct pp_hwmgr *hwmgr,
+ const struct fiji_power_state *fiji_ps)
+{
+ int result = 0;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t high_limit_count;
+
+ PP_ASSERT_WITH_CODE((fiji_ps->performance_level_count >= 1),
+ "power state did not have any performance level",
+ return -1);
+
+ high_limit_count = (1 == fiji_ps->performance_level_count) ? 0 : 1;
+
+ fiji_trim_single_dpm_states(hwmgr,
+ &(data->dpm_table.sclk_table),
+ fiji_ps->performance_levels[0].engine_clock,
+ fiji_ps->performance_levels[high_limit_count].engine_clock);
+
+ fiji_trim_single_dpm_states(hwmgr,
+ &(data->dpm_table.mclk_table),
+ fiji_ps->performance_levels[0].memory_clock,
+ fiji_ps->performance_levels[high_limit_count].memory_clock);
+
+ return result;
+}
+
+static int fiji_generate_dpm_level_enable_mask(
+ struct pp_hwmgr *hwmgr, const void *input)
+{
+ int result;
+ const struct phm_set_power_state_input *states =
+ (const struct phm_set_power_state_input *)input;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ const struct fiji_power_state *fiji_ps =
+ cast_const_phw_fiji_power_state(states->pnew_state);
+
+ result = fiji_trim_dpm_states(hwmgr, fiji_ps);
+ if (result)
+ return result;
+
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+ fiji_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask =
+ fiji_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
+ data->last_mclk_dpm_enable_mask =
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+
+ if (data->uvd_enabled) {
+ if (data->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
+ }
+
+ data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+ fiji_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
+
+ return 0;
+}
+
+int fiji_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+ (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
+ (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
+}
+
+int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, enable?
+ PPSMC_MSG_VCEDPM_Enable :
+ PPSMC_MSG_VCEDPM_Disable);
+}
+
+int fiji_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, enable?
+ PPSMC_MSG_SAMUDPM_Enable :
+ PPSMC_MSG_SAMUDPM_Disable);
+}
+
+int fiji_enable_disable_acp_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, enable?
+ PPSMC_MSG_ACPDPM_Enable :
+ PPSMC_MSG_ACPDPM_Disable);
+}
+
+int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t mm_boot_level_offset, mm_boot_level_value;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (!bgate) {
+ data->smc_state_table.UvdBootLevel = 0;
+ if (table_info->mm_dep_table->count > 0)
+ data->smc_state_table.UvdBootLevel =
+ (uint8_t) (table_info->mm_dep_table->count - 1);
+ mm_boot_level_offset = data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, UvdBootLevel);
+ mm_boot_level_offset /= 4;
+ mm_boot_level_offset *= 4;
+ mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset);
+ mm_boot_level_value &= 0x00FFFFFF;
+ mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+ if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UVDDPM) ||
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState))
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_UVDDPM_SetEnabledMask,
+ (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
+ }
+
+ return fiji_enable_disable_uvd_dpm(hwmgr, !bgate);
+}
+
+int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states =
+ (const struct phm_set_power_state_input *)input;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ const struct fiji_power_state *fiji_nps =
+ cast_const_phw_fiji_power_state(states->pnew_state);
+ const struct fiji_power_state *fiji_cps =
+ cast_const_phw_fiji_power_state(states->pcurrent_state);
+
+ uint32_t mm_boot_level_offset, mm_boot_level_value;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (fiji_nps->vce_clks.evclk >0 &&
+ (fiji_cps == NULL || fiji_cps->vce_clks.evclk == 0)) {
+ data->smc_state_table.VceBootLevel =
+ (uint8_t) (table_info->mm_dep_table->count - 1);
+
+ mm_boot_level_offset = data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, VceBootLevel);
+ mm_boot_level_offset /= 4;
+ mm_boot_level_offset *= 4;
+ mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset);
+ mm_boot_level_value &= 0xFF00FFFF;
+ mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState)) {
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_VCEDPM_SetEnabledMask,
+ (uint32_t)1 << data->smc_state_table.VceBootLevel);
+
+ fiji_enable_disable_vce_dpm(hwmgr, true);
+ } else if (fiji_nps->vce_clks.evclk == 0 &&
+ fiji_cps != NULL &&
+ fiji_cps->vce_clks.evclk > 0)
+ fiji_enable_disable_vce_dpm(hwmgr, false);
+ }
+
+ return 0;
+}
+
+int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t mm_boot_level_offset, mm_boot_level_value;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (!bgate) {
+ data->smc_state_table.SamuBootLevel =
+ (uint8_t) (table_info->mm_dep_table->count - 1);
+ mm_boot_level_offset = data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, SamuBootLevel);
+ mm_boot_level_offset /= 4;
+ mm_boot_level_offset *= 4;
+ mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset);
+ mm_boot_level_value &= 0xFFFFFF00;
+ mm_boot_level_value |= data->smc_state_table.SamuBootLevel << 0;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState))
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SAMUDPM_SetEnabledMask,
+ (uint32_t)(1 << data->smc_state_table.SamuBootLevel));
+ }
+
+ return fiji_enable_disable_samu_dpm(hwmgr, !bgate);
+}
+
+int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t mm_boot_level_offset, mm_boot_level_value;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (!bgate) {
+ data->smc_state_table.AcpBootLevel =
+ (uint8_t) (table_info->mm_dep_table->count - 1);
+ mm_boot_level_offset = data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable, AcpBootLevel);
+ mm_boot_level_offset /= 4;
+ mm_boot_level_offset *= 4;
+ mm_boot_level_value = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset);
+ mm_boot_level_value &= 0xFFFF00FF;
+ mm_boot_level_value |= data->smc_state_table.AcpBootLevel << 8;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StablePState))
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_ACPDPM_SetEnabledMask,
+ (uint32_t)(1 << data->smc_state_table.AcpBootLevel));
+ }
+
+ return fiji_enable_disable_acp_dpm(hwmgr, !bgate);
+}
+
+static int fiji_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ int result = 0;
+ uint32_t low_sclk_interrupt_threshold = 0;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkThrottleLowNotification)
+ && (hwmgr->gfx_arbiter.sclk_threshold !=
+ data->low_sclk_interrupt_threshold)) {
+ data->low_sclk_interrupt_threshold =
+ hwmgr->gfx_arbiter.sclk_threshold;
+ low_sclk_interrupt_threshold =
+ data->low_sclk_interrupt_threshold;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+ result = fiji_copy_bytes_to_smc(
+ hwmgr->smumgr,
+ data->dpm_table_start +
+ offsetof(SMU73_Discrete_DpmTable,
+ LowSclkInterruptThreshold),
+ (uint8_t *)&low_sclk_interrupt_threshold,
+ sizeof(uint32_t),
+ data->sram_end);
+ }
+
+ return result;
+}
+
+static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+ return fiji_program_memory_timing_parameters(hwmgr);
+
+ return 0;
+}
+
+static int fiji_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if (0 == data->need_update_smu7_dpm_table)
+ return 0;
+
+ if ((0 == data->sclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+
+ PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+ "Trying to Unfreeze SCLK DPM when DPM is disabled",);
+ PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+ "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ if ((0 == data->mclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+
+ PP_ASSERT_WITH_CODE(true == fiji_is_dpm_running(hwmgr),
+ "Trying to Unfreeze MCLK DPM when DPM is disabled",);
+ PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+ "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ data->need_update_smu7_dpm_table = 0;
+
+ return 0;
+}
+
+/* Look up the voltaged based on DAL's requested level.
+ * and then send the requested VDDC voltage to SMC
+ */
+static void fiji_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
+{
+ return;
+}
+
+int fiji_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ /* Apply minimum voltage based on DAL's request level */
+ fiji_apply_dal_minimum_voltage_request(hwmgr);
+
+ if (0 == data->sclk_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this,
+ * we should skip this message.
+ */
+ if (!fiji_is_dpm_running(hwmgr))
+ printk(KERN_ERR "[ powerplay ] "
+ "Trying to set Enable Mask when DPM is disabled \n");
+
+ if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_SetEnabledMask,
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Set Sclk Dpm enable Mask failed", return -1);
+ }
+ }
+
+ if (0 == data->mclk_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this,
+ * we should skip this message.
+ */
+ if (!fiji_is_dpm_running(hwmgr))
+ printk(KERN_ERR "[ powerplay ]"
+ " Trying to set Enable Mask when DPM is disabled \n");
+
+ if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Set Mclk Dpm enable Mask failed", return -1);
+ }
+ }
+
+ return 0;
+}
+
+static int fiji_notify_link_speed_change_after_state_change(
+ struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states =
+ (const struct phm_set_power_state_input *)input;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ const struct fiji_power_state *fiji_ps =
+ cast_const_phw_fiji_power_state(states->pnew_state);
+ uint16_t target_link_speed = fiji_get_maximum_link_speed(hwmgr, fiji_ps);
+ uint8_t request;
+
+ if (data->pspp_notify_required) {
+ if (target_link_speed == PP_PCIEGen3)
+ request = PCIE_PERF_REQ_GEN3;
+ else if (target_link_speed == PP_PCIEGen2)
+ request = PCIE_PERF_REQ_GEN2;
+ else
+ request = PCIE_PERF_REQ_GEN1;
+
+ if(request == PCIE_PERF_REQ_GEN1 &&
+ fiji_get_current_pcie_speed(hwmgr) > 0)
+ return 0;
+
+ if (acpi_pcie_perf_request(hwmgr->device, request, false)) {
+ if (PP_PCIEGen2 == target_link_speed)
+ printk("PSPP request to switch to Gen2 from Gen3 Failed!");
+ else
+ printk("PSPP request to switch to Gen1 from Gen2 Failed!");
+ }
+ }
+
+ return 0;
+}
+
+static int fiji_set_power_state_tasks(struct pp_hwmgr *hwmgr,
+ const void *input)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = fiji_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to find DPM states clocks in DPM table!",
+ result = tmp_result);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PCIEPerformanceRequest)) {
+ tmp_result =
+ fiji_request_link_speed_change_before_state_change(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to request link speed change before state change!",
+ result = tmp_result);
+ }
+
+ tmp_result = fiji_freeze_sclk_mclk_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
+
+ tmp_result = fiji_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to populate and upload SCLK MCLK DPM levels!",
+ result = tmp_result);
+
+ tmp_result = fiji_generate_dpm_level_enable_mask(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to generate DPM level enabled mask!",
+ result = tmp_result);
+
+ tmp_result = fiji_update_vce_dpm(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to update VCE DPM!",
+ result = tmp_result);
+
+ tmp_result = fiji_update_sclk_threshold(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to update SCLK threshold!",
+ result = tmp_result);
+
+ tmp_result = fiji_program_mem_timing_parameters(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to program memory timing parameters!",
+ result = tmp_result);
+
+ tmp_result = fiji_unfreeze_sclk_mclk_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to unfreeze SCLK MCLK DPM!",
+ result = tmp_result);
+
+ tmp_result = fiji_upload_dpm_level_enable_mask(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to upload DPM level enabled mask!",
+ result = tmp_result);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PCIEPerformanceRequest)) {
+ tmp_result =
+ fiji_notify_link_speed_change_after_state_change(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to notify link speed change after state change!",
+ result = tmp_result);
+ }
+
+ return result;
+}
+
+static int fiji_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+ struct pp_power_state *ps;
+ struct fiji_power_state *fiji_ps;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
+
+ if (low)
+ return fiji_ps->performance_levels[0].engine_clock;
+ else
+ return fiji_ps->performance_levels
+ [fiji_ps->performance_level_count-1].engine_clock;
+}
+
+static int fiji_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+ struct pp_power_state *ps;
+ struct fiji_power_state *fiji_ps;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ fiji_ps = cast_phw_fiji_power_state(&ps->hardware);
+
+ if (low)
+ return fiji_ps->performance_levels[0].memory_clock;
+ else
+ return fiji_ps->performance_levels
+ [fiji_ps->performance_level_count-1].memory_clock;
+}
+
+static void fiji_print_current_perforce_level(
+ struct pp_hwmgr *hwmgr, struct seq_file *m)
+{
+ uint32_t sclk, mclk, activity_percent = 0;
+ uint32_t offset;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
+
+ sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+
+ smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
+
+ mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+ seq_printf(m, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n",
+ mclk / 100, sclk / 100);
+
+ offset = data->soft_regs_start + offsetof(SMU73_SoftRegisters, AverageGraphicsActivity);
+ activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
+ activity_percent += 0x80;
+ activity_percent >>= 8;
+
+ seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
+}
+
+static int fiji_program_display_gap(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t num_active_displays = 0;
+ uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+ uint32_t display_gap2;
+ uint32_t pre_vbi_time_in_us;
+ uint32_t frame_time_in_us;
+ uint32_t ref_clock;
+ uint32_t refresh_rate = 0;
+ struct cgs_display_info info = {0};
+ struct cgs_mode_info mode_info;
+
+ info.mode_info = &mode_info;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+ num_active_displays = info.display_count;
+
+ display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL,
+ DISP_GAP, (num_active_displays > 0)?
+ DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+ ref_clock = mode_info.ref_clock;
+ refresh_rate = mode_info.refresh_rate;
+
+ if (refresh_rate == 0)
+ refresh_rate = 60;
+
+ frame_time_in_us = 1000000 / refresh_rate;
+
+ pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
+ display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_DISPLAY_GAP_CNTL2, display_gap2);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ data->soft_regs_start +
+ offsetof(SMU73_SoftRegisters, PreVBlankGap), 0x64);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ data->soft_regs_start +
+ offsetof(SMU73_SoftRegisters, VBlankTimeout),
+ (frame_time_in_us - pre_vbi_time_in_us));
+
+ if (num_active_displays == 1)
+ tonga_notify_smc_display_change(hwmgr, true);
+
+ return 0;
+}
+
+int fiji_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
+{
+ return fiji_program_display_gap(hwmgr);
+}
+
+static int fiji_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr,
+ uint16_t us_max_fan_pwm)
+{
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
+
+ if (phm_is_hw_access_blocked(hwmgr))
+ return 0;
+
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
+}
+
+static int fiji_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr,
+ uint16_t us_max_fan_rpm)
+{
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
+
+ if (phm_is_hw_access_blocked(hwmgr))
+ return 0;
+
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
+}
+
+int fiji_dpm_set_interrupt_state(void *private_data,
+ unsigned src_id, unsigned type,
+ int enabled)
+{
+ uint32_t cg_thermal_int;
+ struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ switch (type) {
+ case AMD_THERMAL_IRQ_LOW_TO_HIGH:
+ if (enabled) {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ } else {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ }
+ break;
+
+ case AMD_THERMAL_IRQ_HIGH_TO_LOW:
+ if (enabled) {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ } else {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int fiji_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
+ const void *thermal_interrupt_info)
+{
+ int result;
+ const struct pp_interrupt_registration_info *info =
+ (const struct pp_interrupt_registration_info *)
+ thermal_interrupt_info;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
+ fiji_dpm_set_interrupt_state,
+ info->call_back, info->context);
+
+ if (result)
+ return -EINVAL;
+
+ result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
+ fiji_dpm_set_interrupt_state,
+ info->call_back, info->context);
+
+ if (result)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int fiji_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+ if (mode) {
+ /* stop auto-manage */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl))
+ fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
+ fiji_fan_ctrl_set_static_mode(hwmgr, mode);
+ } else
+ /* restart auto-manage */
+ fiji_fan_ctrl_reset_fan_speed_to_default(hwmgr);
+
+ return 0;
+}
+
+static int fiji_get_fan_control_mode(struct pp_hwmgr *hwmgr)
+{
+ if (hwmgr->fan_ctrl_is_in_default_mode)
+ return hwmgr->fan_ctrl_default_mode;
+ else
+ return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, FDO_PWM_MODE);
+}
+
+static const struct pp_hwmgr_func fiji_hwmgr_funcs = {
+ .backend_init = &fiji_hwmgr_backend_init,
+ .backend_fini = &tonga_hwmgr_backend_fini,
+ .asic_setup = &fiji_setup_asic_task,
+ .dynamic_state_management_enable = &fiji_enable_dpm_tasks,
+ .force_dpm_level = &fiji_dpm_force_dpm_level,
+ .get_num_of_pp_table_entries = &tonga_get_number_of_powerplay_table_entries,
+ .get_power_state_size = &fiji_get_power_state_size,
+ .get_pp_table_entry = &fiji_get_pp_table_entry,
+ .patch_boot_state = &fiji_patch_boot_state,
+ .apply_state_adjust_rules = &fiji_apply_state_adjust_rules,
+ .power_state_set = &fiji_set_power_state_tasks,
+ .get_sclk = &fiji_dpm_get_sclk,
+ .get_mclk = &fiji_dpm_get_mclk,
+ .print_current_perforce_level = &fiji_print_current_perforce_level,
+ .powergate_uvd = &fiji_phm_powergate_uvd,
+ .powergate_vce = &fiji_phm_powergate_vce,
+ .disable_clock_power_gating = &fiji_phm_disable_clock_power_gating,
+ .notify_smc_display_config_after_ps_adjustment =
+ &tonga_notify_smc_display_config_after_ps_adjustment,
+ .display_config_changed = &fiji_display_configuration_changed_task,
+ .set_max_fan_pwm_output = fiji_set_max_fan_pwm_output,
+ .set_max_fan_rpm_output = fiji_set_max_fan_rpm_output,
+ .get_temperature = fiji_thermal_get_temperature,
+ .stop_thermal_controller = fiji_thermal_stop_thermal_controller,
+ .get_fan_speed_info = fiji_fan_ctrl_get_fan_speed_info,
+ .get_fan_speed_percent = fiji_fan_ctrl_get_fan_speed_percent,
+ .set_fan_speed_percent = fiji_fan_ctrl_set_fan_speed_percent,
+ .reset_fan_speed_to_default = fiji_fan_ctrl_reset_fan_speed_to_default,
+ .get_fan_speed_rpm = fiji_fan_ctrl_get_fan_speed_rpm,
+ .set_fan_speed_rpm = fiji_fan_ctrl_set_fan_speed_rpm,
+ .uninitialize_thermal_controller = fiji_thermal_ctrl_uninitialize_thermal_controller,
+ .register_internal_thermal_interrupt = fiji_register_internal_thermal_interrupt,
+ .set_fan_control_mode = fiji_set_fan_control_mode,
+ .get_fan_control_mode = fiji_get_fan_control_mode,
+};
+
+int fiji_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data;
+ int ret = 0;
+
+ data = kzalloc(sizeof(struct fiji_hwmgr), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ hwmgr->backend = data;
+ hwmgr->hwmgr_func = &fiji_hwmgr_funcs;
+ hwmgr->pptable_func = &tonga_pptable_funcs;
+ pp_fiji_thermal_initialize(hwmgr);
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
new file mode 100644
index 000000000000..22e273b1c1c5
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2015 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 _FIJI_HWMGR_H_
+#define _FIJI_HWMGR_H_
+
+#include "hwmgr.h"
+#include "smu73.h"
+#include "smu73_discrete.h"
+#include "ppatomctrl.h"
+#include "fiji_ppsmc.h"
+
+#define FIJI_MAX_HARDWARE_POWERLEVELS 2
+#define FIJI_AT_DFLT 30
+
+#define FIJI_VOLTAGE_CONTROL_NONE 0x0
+#define FIJI_VOLTAGE_CONTROL_BY_GPIO 0x1
+#define FIJI_VOLTAGE_CONTROL_BY_SVID2 0x2
+#define FIJI_VOLTAGE_CONTROL_MERGED 0x3
+
+#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
+#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
+#define DPMTABLE_UPDATE_SCLK 0x00000004
+#define DPMTABLE_UPDATE_MCLK 0x00000008
+
+struct fiji_performance_level {
+ uint32_t memory_clock;
+ uint32_t engine_clock;
+ uint16_t pcie_gen;
+ uint16_t pcie_lane;
+};
+
+struct fiji_uvd_clocks {
+ uint32_t vclk;
+ uint32_t dclk;
+};
+
+struct fiji_vce_clocks {
+ uint32_t evclk;
+ uint32_t ecclk;
+};
+
+struct fiji_power_state {
+ uint32_t magic;
+ struct fiji_uvd_clocks uvd_clks;
+ struct fiji_vce_clocks vce_clks;
+ uint32_t sam_clk;
+ uint32_t acp_clk;
+ uint16_t performance_level_count;
+ bool dc_compatible;
+ uint32_t sclk_threshold;
+ struct fiji_performance_level performance_levels[FIJI_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct fiji_dpm_level {
+ bool enabled;
+ uint32_t value;
+ uint32_t param1;
+};
+
+#define FIJI_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define MAX_REGULAR_DPM_NUMBER 8
+#define FIJI_MINIMUM_ENGINE_CLOCK 2500
+
+struct fiji_single_dpm_table {
+ uint32_t count;
+ struct fiji_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
+};
+
+struct fiji_dpm_table {
+ struct fiji_single_dpm_table sclk_table;
+ struct fiji_single_dpm_table mclk_table;
+ struct fiji_single_dpm_table pcie_speed_table;
+ struct fiji_single_dpm_table vddc_table;
+ struct fiji_single_dpm_table vddci_table;
+ struct fiji_single_dpm_table mvdd_table;
+};
+
+struct fiji_clock_registers {
+ uint32_t vCG_SPLL_FUNC_CNTL;
+ uint32_t vCG_SPLL_FUNC_CNTL_2;
+ uint32_t vCG_SPLL_FUNC_CNTL_3;
+ uint32_t vCG_SPLL_FUNC_CNTL_4;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t vDLL_CNTL;
+ uint32_t vMCLK_PWRMGT_CNTL;
+ uint32_t vMPLL_AD_FUNC_CNTL;
+ uint32_t vMPLL_DQ_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL_1;
+ uint32_t vMPLL_FUNC_CNTL_2;
+ uint32_t vMPLL_SS1;
+ uint32_t vMPLL_SS2;
+};
+
+struct fiji_voltage_smio_registers {
+ uint32_t vS0_VID_LOWER_SMIO_CNTL;
+};
+
+#define FIJI_MAX_LEAKAGE_COUNT 8
+struct fiji_leakage_voltage {
+ uint16_t count;
+ uint16_t leakage_id[FIJI_MAX_LEAKAGE_COUNT];
+ uint16_t actual_voltage[FIJI_MAX_LEAKAGE_COUNT];
+};
+
+struct fiji_vbios_boot_state {
+ uint16_t mvdd_bootup_value;
+ uint16_t vddc_bootup_value;
+ uint16_t vddci_bootup_value;
+ uint32_t sclk_bootup_value;
+ uint32_t mclk_bootup_value;
+ uint16_t pcie_gen_bootup_value;
+ uint16_t pcie_lane_bootup_value;
+};
+
+struct fiji_bacos {
+ uint32_t best_match;
+ uint32_t baco_flags;
+ struct fiji_performance_level performance_level;
+};
+
+/* Ultra Low Voltage parameter structure */
+struct fiji_ulv_parm {
+ bool ulv_supported;
+ uint32_t cg_ulv_parameter;
+ uint32_t ulv_volt_change_delay;
+ struct fiji_performance_level ulv_power_level;
+};
+
+struct fiji_display_timing {
+ uint32_t min_clock_in_sr;
+ uint32_t num_existing_displays;
+};
+
+struct fiji_dpmlevel_enable_mask {
+ uint32_t uvd_dpm_enable_mask;
+ uint32_t vce_dpm_enable_mask;
+ uint32_t acp_dpm_enable_mask;
+ uint32_t samu_dpm_enable_mask;
+ uint32_t sclk_dpm_enable_mask;
+ uint32_t mclk_dpm_enable_mask;
+ uint32_t pcie_dpm_enable_mask;
+};
+
+struct fiji_pcie_perf_range {
+ uint16_t max;
+ uint16_t min;
+};
+
+struct fiji_hwmgr {
+ struct fiji_dpm_table dpm_table;
+ struct fiji_dpm_table golden_dpm_table;
+
+ uint32_t voting_rights_clients0;
+ uint32_t voting_rights_clients1;
+ uint32_t voting_rights_clients2;
+ uint32_t voting_rights_clients3;
+ uint32_t voting_rights_clients4;
+ uint32_t voting_rights_clients5;
+ uint32_t voting_rights_clients6;
+ uint32_t voting_rights_clients7;
+ uint32_t static_screen_threshold_unit;
+ uint32_t static_screen_threshold;
+ uint32_t voltage_control;
+ uint32_t vddc_vddci_delta;
+
+ uint32_t active_auto_throttle_sources;
+
+ struct fiji_clock_registers clock_registers;
+ struct fiji_voltage_smio_registers voltage_smio_registers;
+
+ bool is_memory_gddr5;
+ uint16_t acpi_vddc;
+ bool pspp_notify_required;
+ uint16_t force_pcie_gen;
+ uint16_t acpi_pcie_gen;
+ uint32_t pcie_gen_cap;
+ uint32_t pcie_lane_cap;
+ uint32_t pcie_spc_cap;
+ struct fiji_leakage_voltage vddc_leakage;
+ struct fiji_leakage_voltage Vddci_leakage;
+
+ uint32_t mvdd_control;
+ uint32_t vddc_mask_low;
+ uint32_t mvdd_mask_low;
+ uint16_t max_vddc_in_pptable;
+ uint16_t min_vddc_in_pptable;
+ uint16_t max_vddci_in_pptable;
+ uint16_t min_vddci_in_pptable;
+ uint32_t mclk_strobe_mode_threshold;
+ uint32_t mclk_stutter_mode_threshold;
+ uint32_t mclk_edc_enable_threshold;
+ uint32_t mclk_edcwr_enable_threshold;
+ bool is_uvd_enabled;
+ struct fiji_vbios_boot_state vbios_boot_state;
+
+ bool battery_state;
+ bool is_tlu_enabled;
+
+ /* ---- SMC SRAM Address of firmware header tables ---- */
+ uint32_t sram_end;
+ uint32_t dpm_table_start;
+ uint32_t soft_regs_start;
+ uint32_t mc_reg_table_start;
+ uint32_t fan_table_start;
+ uint32_t arb_table_start;
+ struct SMU73_Discrete_DpmTable smc_state_table;
+ struct SMU73_Discrete_Ulv ulv_setting;
+
+ /* ---- Stuff originally coming from Evergreen ---- */
+ uint32_t vddci_control;
+ struct pp_atomctrl_voltage_table vddc_voltage_table;
+ struct pp_atomctrl_voltage_table vddci_voltage_table;
+ struct pp_atomctrl_voltage_table mvdd_voltage_table;
+
+ uint32_t mgcg_cgtt_local2;
+ uint32_t mgcg_cgtt_local3;
+ uint32_t gpio_debug;
+ uint32_t mc_micro_code_feature;
+ uint32_t highest_mclk;
+ uint16_t acpi_vddci;
+ uint8_t mvdd_high_index;
+ uint8_t mvdd_low_index;
+ bool dll_default_on;
+ bool performance_request_registered;
+
+ /* ---- Low Power Features ---- */
+ struct fiji_bacos bacos;
+ struct fiji_ulv_parm ulv;
+
+ /* ---- CAC Stuff ---- */
+ uint32_t cac_table_start;
+ bool cac_configuration_required;
+ bool driver_calculate_cac_leakage;
+ bool cac_enabled;
+
+ /* ---- DPM2 Parameters ---- */
+ uint32_t power_containment_features;
+ bool enable_dte_feature;
+ bool enable_tdc_limit_feature;
+ bool enable_pkg_pwr_tracking_feature;
+ bool disable_uvd_power_tune_feature;
+ struct fiji_pt_defaults *power_tune_defaults;
+ struct SMU73_Discrete_PmFuses power_tune_table;
+ uint32_t dte_tj_offset;
+ uint32_t fast_watermark_threshold;
+
+ /* ---- Phase Shedding ---- */
+ bool vddc_phase_shed_control;
+
+ /* ---- DI/DT ---- */
+ struct fiji_display_timing display_timing;
+
+ /* ---- Thermal Temperature Setting ---- */
+ struct fiji_dpmlevel_enable_mask dpm_level_enable_mask;
+ uint32_t need_update_smu7_dpm_table;
+ uint32_t sclk_dpm_key_disabled;
+ uint32_t mclk_dpm_key_disabled;
+ uint32_t pcie_dpm_key_disabled;
+ uint32_t min_engine_clocks;
+ struct fiji_pcie_perf_range pcie_gen_performance;
+ struct fiji_pcie_perf_range pcie_lane_performance;
+ struct fiji_pcie_perf_range pcie_gen_power_saving;
+ struct fiji_pcie_perf_range pcie_lane_power_saving;
+ bool use_pcie_performance_levels;
+ bool use_pcie_power_saving_levels;
+ uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS];
+ uint32_t mclk_activity_target;
+ uint32_t mclk_dpm0_activity_target;
+ uint32_t low_sclk_interrupt_threshold;
+ uint32_t last_mclk_dpm_enable_mask;
+ bool uvd_enabled;
+
+ /* ---- Power Gating States ---- */
+ bool uvd_power_gated;
+ bool vce_power_gated;
+ bool samu_power_gated;
+ bool acp_power_gated;
+ bool pg_acp_init;
+ bool frtc_enabled;
+ bool frtc_status_changed;
+};
+
+/* To convert to Q8.8 format for firmware */
+#define FIJI_Q88_FORMAT_CONVERSION_UNIT 256
+
+enum Fiji_I2CLineID {
+ Fiji_I2CLineID_DDC1 = 0x90,
+ Fiji_I2CLineID_DDC2 = 0x91,
+ Fiji_I2CLineID_DDC3 = 0x92,
+ Fiji_I2CLineID_DDC4 = 0x93,
+ Fiji_I2CLineID_DDC5 = 0x94,
+ Fiji_I2CLineID_DDC6 = 0x95,
+ Fiji_I2CLineID_SCLSDA = 0x96,
+ Fiji_I2CLineID_DDCVGA = 0x97
+};
+
+#define Fiji_I2C_DDC1DATA 0
+#define Fiji_I2C_DDC1CLK 1
+#define Fiji_I2C_DDC2DATA 2
+#define Fiji_I2C_DDC2CLK 3
+#define Fiji_I2C_DDC3DATA 4
+#define Fiji_I2C_DDC3CLK 5
+#define Fiji_I2C_SDA 40
+#define Fiji_I2C_SCL 41
+#define Fiji_I2C_DDC4DATA 65
+#define Fiji_I2C_DDC4CLK 66
+#define Fiji_I2C_DDC5DATA 0x48
+#define Fiji_I2C_DDC5CLK 0x49
+#define Fiji_I2C_DDC6DATA 0x4a
+#define Fiji_I2C_DDC6CLK 0x4b
+#define Fiji_I2C_DDCVGADATA 0x4c
+#define Fiji_I2C_DDCVGACLK 0x4d
+
+#define FIJI_UNUSED_GPIO_PIN 0x7F
+
+extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
+extern int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
+extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr);
+extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
+extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display);
+int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
+int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
+
+#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X)
+#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X)
+
+#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X)
+#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X)
+
+#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X))
+#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X))
+
+#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X))
+
+#endif /* _FIJI_HWMGR_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
new file mode 100644
index 000000000000..6efcb2bac45f
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "smumgr.h"
+#include "fiji_hwmgr.h"
+#include "fiji_powertune.h"
+#include "fiji_smumgr.h"
+#include "smu73_discrete.h"
+#include "pp_debug.h"
+
+#define VOLTAGE_SCALE 4
+#define POWERTUNE_DEFAULT_SET_MAX 1
+
+struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
+ /*sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
+ {1, 0xF, 0xFD,
+ /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
+ 0x19, 5, 45}
+};
+
+void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *fiji_hwmgr = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint32_t tmp = 0;
+
+ if(table_info &&
+ table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
+ table_info->cac_dtp_table->usPowerTuneDataSetID)
+ fiji_hwmgr->power_tune_defaults =
+ &fiji_power_tune_data_set_array
+ [table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
+ else
+ fiji_hwmgr->power_tune_defaults = &fiji_power_tune_data_set_array[0];
+
+ /* Assume disabled */
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerContainment);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_CAC);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SQRamping);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DBRamping);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TDRamping);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TCPRamping);
+
+ fiji_hwmgr->dte_tj_offset = tmp;
+
+ if (!tmp) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerContainment);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_CAC);
+
+ fiji_hwmgr->fast_watermark_threshold = 100;
+
+ tmp = 1;
+ fiji_hwmgr->enable_dte_feature = tmp ? false : true;
+ fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
+ fiji_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
+ }
+}
+
+/* PPGen has the gain setting generated in x * 100 unit
+ * This function is to convert the unit to x * 4096(0x1000) unit.
+ * This is the unit expected by SMC firmware
+ */
+static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
+{
+ uint32_t tmp;
+ tmp = raw_setting * 4096 / 100;
+ return (uint16_t)tmp;
+}
+
+static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t* sda)
+{
+ switch (line) {
+ case Fiji_I2CLineID_DDC1 :
+ *scl = Fiji_I2C_DDC1CLK;
+ *sda = Fiji_I2C_DDC1DATA;
+ break;
+ case Fiji_I2CLineID_DDC2 :
+ *scl = Fiji_I2C_DDC2CLK;
+ *sda = Fiji_I2C_DDC2DATA;
+ break;
+ case Fiji_I2CLineID_DDC3 :
+ *scl = Fiji_I2C_DDC3CLK;
+ *sda = Fiji_I2C_DDC3DATA;
+ break;
+ case Fiji_I2CLineID_DDC4 :
+ *scl = Fiji_I2C_DDC4CLK;
+ *sda = Fiji_I2C_DDC4DATA;
+ break;
+ case Fiji_I2CLineID_DDC5 :
+ *scl = Fiji_I2C_DDC5CLK;
+ *sda = Fiji_I2C_DDC5DATA;
+ break;
+ case Fiji_I2CLineID_DDC6 :
+ *scl = Fiji_I2C_DDC6CLK;
+ *sda = Fiji_I2C_DDC6DATA;
+ break;
+ case Fiji_I2CLineID_SCLSDA :
+ *scl = Fiji_I2C_SCL;
+ *sda = Fiji_I2C_SDA;
+ break;
+ case Fiji_I2CLineID_DDCVGA :
+ *scl = Fiji_I2C_DDCVGACLK;
+ *sda = Fiji_I2C_DDCVGADATA;
+ break;
+ default:
+ *scl = 0;
+ *sda = 0;
+ break;
+ }
+}
+
+int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_pt_defaults *defaults = data->power_tune_defaults;
+ SMU73_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
+ struct pp_advance_fan_control_parameters *fan_table=
+ &hwmgr->thermal_controller.advanceFanControlParameters;
+ uint8_t uc_scl, uc_sda;
+
+ /* TDP number of fraction bits are changed from 8 to 7 for Fiji
+ * as requested by SMC team
+ */
+ dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
+ (uint16_t)(cac_dtp_table->usTDP * 128));
+ dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
+ (uint16_t)(cac_dtp_table->usTDP * 128));
+
+ PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
+ "Target Operating Temp is out of Range!",);
+
+ dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
+ dpm_table->GpuTjHyst = 8;
+
+ dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
+
+ /* The following are for new Fiji Multi-input fan/thermal control */
+ dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTargetOperatingTemp * 256);
+ dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTemperatureLimitHotspot * 256);
+ dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTemperatureLimitLiquid1 * 256);
+ dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTemperatureLimitLiquid2 * 256);
+ dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTemperatureLimitVrVddc * 256);
+ dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTemperatureLimitVrMvdd * 256);
+ dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
+ cac_dtp_table->usTemperatureLimitPlx * 256);
+
+ dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainEdge));
+ dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainHotspot));
+ dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainLiquid));
+ dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainVrVddc));
+ dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
+ dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainPlx));
+ dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
+ scale_fan_gain_settings(fan_table->usFanGainHbm));
+
+ dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
+ dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
+ dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
+ dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
+
+ get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
+ dpm_table->Liquid_I2C_LineSCL = uc_scl;
+ dpm_table->Liquid_I2C_LineSDA = uc_sda;
+
+ get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
+ dpm_table->Vr_I2C_LineSCL = uc_scl;
+ dpm_table->Vr_I2C_LineSDA = uc_sda;
+
+ get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
+ dpm_table->Plx_I2C_LineSCL = uc_scl;
+ dpm_table->Plx_I2C_LineSDA = uc_sda;
+
+ return 0;
+}
+
+static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_pt_defaults *defaults = data->power_tune_defaults;
+
+ data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
+ data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
+ data->power_tune_table.SviLoadLineTrimVddC = 3;
+ data->power_tune_table.SviLoadLineOffsetVddC = 0;
+
+ return 0;
+}
+
+static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
+{
+ uint16_t tdc_limit;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct fiji_pt_defaults *defaults = data->power_tune_defaults;
+
+ /* TDC number of fraction bits are changed from 8 to 7
+ * for Fiji as requested by SMC team
+ */
+ tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
+ data->power_tune_table.TDC_VDDC_PkgLimit =
+ CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
+ data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+ defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
+ data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
+
+ return 0;
+}
+
+static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct fiji_pt_defaults *defaults = data->power_tune_defaults;
+ uint32_t temp;
+
+ if (fiji_read_smc_sram_dword(hwmgr->smumgr,
+ fuse_table_offset +
+ offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
+ (uint32_t *)&temp, data->sram_end))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
+ return -EINVAL);
+ else {
+ data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
+ data->power_tune_table.LPMLTemperatureMin =
+ (uint8_t)((temp >> 16) & 0xff);
+ data->power_tune_table.LPMLTemperatureMax =
+ (uint8_t)((temp >> 8) & 0xff);
+ data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
+ }
+ return 0;
+}
+
+static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
+{
+ int i;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ /* Currently not used. Set all to zero. */
+ for (i = 0; i < 16; i++)
+ data->power_tune_table.LPMLTemperatureScaler[i] = 0;
+
+ return 0;
+}
+
+static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if( (hwmgr->thermal_controller.advanceFanControlParameters.
+ usFanOutputSensitivity & (1 << 15)) ||
+ 0 == hwmgr->thermal_controller.advanceFanControlParameters.
+ usFanOutputSensitivity )
+ hwmgr->thermal_controller.advanceFanControlParameters.
+ usFanOutputSensitivity = hwmgr->thermal_controller.
+ advanceFanControlParameters.usDefaultFanOutputSensitivity;
+
+ data->power_tune_table.FuzzyFan_PwmSetDelta =
+ PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
+ advanceFanControlParameters.usFanOutputSensitivity);
+ return 0;
+}
+
+static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
+{
+ int i;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ /* Currently not used. Set all to zero. */
+ for (i = 0; i < 16; i++)
+ data->power_tune_table.GnbLPML[i] = 0;
+
+ return 0;
+}
+
+static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
+{
+ /* int i, min, max;
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint8_t * pHiVID = data->power_tune_table.BapmVddCVidHiSidd;
+ uint8_t * pLoVID = data->power_tune_table.BapmVddCVidLoSidd;
+
+ min = max = pHiVID[0];
+ for (i = 0; i < 8; i++) {
+ if (0 != pHiVID[i]) {
+ if (min > pHiVID[i])
+ min = pHiVID[i];
+ if (max < pHiVID[i])
+ max = pHiVID[i];
+ }
+
+ if (0 != pLoVID[i]) {
+ if (min > pLoVID[i])
+ min = pLoVID[i];
+ if (max < pLoVID[i])
+ max = pLoVID[i];
+ }
+ }
+
+ PP_ASSERT_WITH_CODE((0 != min) && (0 != max), "BapmVddcVidSidd table does not exist!", return int_Failed);
+ data->power_tune_table.GnbLPMLMaxVid = (uint8_t)max;
+ data->power_tune_table.GnbLPMLMinVid = (uint8_t)min;
+*/
+ return 0;
+}
+
+static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
+ uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
+ struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+
+ HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
+ LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
+
+ data->power_tune_table.BapmVddCBaseLeakageHiSidd =
+ CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
+ data->power_tune_table.BapmVddCBaseLeakageLoSidd =
+ CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
+
+ return 0;
+}
+
+int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ uint32_t pm_fuse_table_offset;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerContainment)) {
+ if (fiji_read_smc_sram_dword(hwmgr->smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, PmFuseTable),
+ &pm_fuse_table_offset, data->sram_end))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to get pm_fuse_table_offset Failed!",
+ return -EINVAL);
+
+ /* DW6 */
+ if (fiji_populate_svi_load_line(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate SviLoadLine Failed!",
+ return -EINVAL);
+ /* DW7 */
+ if (fiji_populate_tdc_limit(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate TDCLimit Failed!", return -EINVAL);
+ /* DW8 */
+ if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate TdcWaterfallCtl, "
+ "LPMLTemperature Min and Max Failed!",
+ return -EINVAL);
+
+ /* DW9-DW12 */
+ if (0 != fiji_populate_temperature_scaler(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate LPMLTemperatureScaler Failed!",
+ return -EINVAL);
+
+ /* DW13-DW14 */
+ if(fiji_populate_fuzzy_fan(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate Fuzzy Fan Control parameters Failed!",
+ return -EINVAL);
+
+ /* DW15-DW18 */
+ if (fiji_populate_gnb_lpml(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate GnbLPML Failed!",
+ return -EINVAL);
+
+ /* DW19 */
+ if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate GnbLPML Min and Max Vid Failed!",
+ return -EINVAL);
+
+ /* DW20 */
+ if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
+ "Sidd Failed!", return -EINVAL);
+
+ if (fiji_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
+ (uint8_t *)&data->power_tune_table,
+ sizeof(struct SMU73_Discrete_PmFuses), data->sram_end))
+ PP_ASSERT_WITH_CODE(false,
+ "Attempt to download PmFuseTable Failed!",
+ return -EINVAL);
+ }
+ return 0;
+}
+
+int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ int result = 0;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_CAC)) {
+ int smc_result;
+ smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+ (uint16_t)(PPSMC_MSG_EnableCac));
+ PP_ASSERT_WITH_CODE((0 == smc_result),
+ "Failed to enable CAC in SMC.", result = -1);
+
+ data->cac_enabled = (0 == smc_result) ? true : false;
+ }
+ return result;
+}
+
+int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+
+ if(data->power_containment_features &
+ POWERCONTAINMENT_FEATURE_PkgPwrLimit)
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_PkgPwrSetLimit, n);
+ return 0;
+}
+
+static int fiji_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
+{
+ return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
+ PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
+}
+
+int fiji_enable_power_containment(struct pp_hwmgr *hwmgr)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ int smc_result;
+ int result = 0;
+
+ data->power_containment_features = 0;
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerContainment)) {
+ if (data->enable_dte_feature) {
+ smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+ (uint16_t)(PPSMC_MSG_EnableDTE));
+ PP_ASSERT_WITH_CODE((0 == smc_result),
+ "Failed to enable DTE in SMC.", result = -1;);
+ if (0 == smc_result)
+ data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
+ }
+
+ if (data->enable_tdc_limit_feature) {
+ smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+ (uint16_t)(PPSMC_MSG_TDCLimitEnable));
+ PP_ASSERT_WITH_CODE((0 == smc_result),
+ "Failed to enable TDCLimit in SMC.", result = -1;);
+ if (0 == smc_result)
+ data->power_containment_features |=
+ POWERCONTAINMENT_FEATURE_TDCLimit;
+ }
+
+ if (data->enable_pkg_pwr_tracking_feature) {
+ smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
+ (uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
+ PP_ASSERT_WITH_CODE((0 == smc_result),
+ "Failed to enable PkgPwrTracking in SMC.", result = -1;);
+ if (0 == smc_result) {
+ struct phm_cac_tdp_table *cac_table =
+ table_info->cac_dtp_table;
+ uint32_t default_limit =
+ (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
+
+ data->power_containment_features |=
+ POWERCONTAINMENT_FEATURE_PkgPwrLimit;
+
+ if (fiji_set_power_limit(hwmgr, default_limit))
+ printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
+ }
+ }
+ }
+ return result;
+}
+
+int fiji_power_control_set_level(struct pp_hwmgr *hwmgr)
+{
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
+ int adjust_percent, target_tdp;
+ int result = 0;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerContainment)) {
+ /* adjustment percentage has already been validated */
+ adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
+ hwmgr->platform_descriptor.TDPAdjustment :
+ (-1 * hwmgr->platform_descriptor.TDPAdjustment);
+ /* SMC requested that target_tdp to be 7 bit fraction in DPM table
+ * but message to be 8 bit fraction for messages
+ */
+ target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
+ result = fiji_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
+ }
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
new file mode 100644
index 000000000000..55e58200f33a
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_powertune.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 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 FIJI_POWERTUNE_H
+#define FIJI_POWERTUNE_H
+
+enum fiji_pt_config_reg_type {
+ FIJI_CONFIGREG_MMR = 0,
+ FIJI_CONFIGREG_SMC_IND,
+ FIJI_CONFIGREG_DIDT_IND,
+ FIJI_CONFIGREG_CACHE,
+ FIJI_CONFIGREG_MAX
+};
+
+/* PowerContainment Features */
+#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
+#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
+#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
+
+struct fiji_pt_config_reg {
+ uint32_t offset;
+ uint32_t mask;
+ uint32_t shift;
+ uint32_t value;
+ enum fiji_pt_config_reg_type type;
+};
+
+struct fiji_pt_defaults
+{
+ uint8_t SviLoadLineEn;
+ uint8_t SviLoadLineVddC;
+ uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+ uint8_t TDC_MAWt;
+ uint8_t TdcWaterfallCtl;
+ uint8_t DTEAmbientTempBase;
+};
+
+void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
+int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
+int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr);
+int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr);
+int fiji_enable_power_containment(struct pp_hwmgr *hwmgr);
+int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
+int fiji_power_control_set_level(struct pp_hwmgr *hwmgr);
+
+#endif /* FIJI_POWERTUNE_H */
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
new file mode 100644
index 000000000000..e76a7de9aa32
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <asm/div64.h>
+#include "fiji_thermal.h"
+#include "fiji_hwmgr.h"
+#include "fiji_smumgr.h"
+#include "fiji_ppsmc.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+
+int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
+ struct phm_fan_speed_info *fan_speed_info)
+{
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ fan_speed_info->supports_percent_read = true;
+ fan_speed_info->supports_percent_write = true;
+ fan_speed_info->min_percent = 0;
+ fan_speed_info->max_percent = 100;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
+ hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
+ fan_speed_info->supports_rpm_read = true;
+ fan_speed_info->supports_rpm_write = true;
+ fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
+ fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
+ } else {
+ fan_speed_info->min_rpm = 0;
+ fan_speed_info->max_rpm = 0;
+ }
+
+ return 0;
+}
+
+int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
+ uint32_t *speed)
+{
+ uint32_t duty100;
+ uint32_t duty;
+ uint64_t tmp64;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL1, FMAX_DUTY100);
+ duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+ if (duty100 == 0)
+ return -EINVAL;
+
+
+ tmp64 = (uint64_t)duty * 100;
+ do_div(tmp64, duty100);
+ *speed = (uint32_t)tmp64;
+
+ if (*speed > 100)
+ *speed = 100;
+
+ return 0;
+}
+
+int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+ uint32_t tach_period;
+ uint32_t crystal_clock_freq;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan ||
+ (hwmgr->thermal_controller.fanInfo.
+ ucTachometerPulsesPerRevolution == 0))
+ return 0;
+
+ tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_TACH_STATUS, TACH_PERIOD);
+
+ if (tach_period == 0)
+ return -EINVAL;
+
+ crystal_clock_freq = tonga_get_xclk(hwmgr);
+
+ *speed = 60 * crystal_clock_freq * 10000/ tach_period;
+
+ return 0;
+}
+
+/**
+* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
+* @param hwmgr the address of the powerplay hardware manager.
+* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
+* @exception Should always succeed.
+*/
+int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+
+ if (hwmgr->fan_ctrl_is_in_default_mode) {
+ hwmgr->fan_ctrl_default_mode =
+ PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, FDO_PWM_MODE);
+ hwmgr->tmin =
+ PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, TMIN);
+ hwmgr->fan_ctrl_is_in_default_mode = false;
+ }
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, TMIN, 0);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, FDO_PWM_MODE, mode);
+
+ return 0;
+}
+
+/**
+* Reset Fan Speed Control to default mode.
+* @param hwmgr the address of the powerplay hardware manager.
+* @exception Should always succeed.
+*/
+int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
+{
+ if (!hwmgr->fan_ctrl_is_in_default_mode) {
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, TMIN, hwmgr->tmin);
+ hwmgr->fan_ctrl_is_in_default_mode = true;
+ }
+
+ return 0;
+}
+
+int fiji_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
+ cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
+ result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_FanSpeedInTableIsRPM))
+ hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.usMaxFanRPM);
+ else
+ hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.usMaxFanPWM);
+
+ } else {
+ cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
+ result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
+ }
+
+ if (!result && hwmgr->thermal_controller.
+ advanceFanControlParameters.ucTargetTemperature)
+ result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetFanTemperatureTarget,
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.ucTargetTemperature);
+
+ return result;
+}
+
+
+int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
+}
+
+/**
+* Set Fan Speed in percent.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param speed is the percentage value (0% - 100%) to be set.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
+ uint32_t speed)
+{
+ uint32_t duty100;
+ uint32_t duty;
+ uint64_t tmp64;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ if (speed > 100)
+ speed = 100;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl))
+ fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
+
+ duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL1, FMAX_DUTY100);
+
+ if (duty100 == 0)
+ return -EINVAL;
+
+ tmp64 = (uint64_t)speed * 100;
+ do_div(tmp64, duty100);
+ duty = (uint32_t)tmp64;
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
+
+ return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reset Fan Speed to default.
+* @param hwmgr the address of the powerplay hardware manager.
+* @exception Always succeeds.
+*/
+int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl)) {
+ result = fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+ if (!result)
+ result = fiji_fan_ctrl_start_smc_fan_control(hwmgr);
+ } else
+ result = fiji_fan_ctrl_set_default_mode(hwmgr);
+
+ return result;
+}
+
+/**
+* Set Fan Speed in RPM.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param speed is the percentage value (min - max) to be set.
+* @exception Fails is the speed not lie between min and max.
+*/
+int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+ uint32_t tach_period;
+ uint32_t crystal_clock_freq;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan ||
+ (hwmgr->thermal_controller.fanInfo.
+ ucTachometerPulsesPerRevolution == 0) ||
+ (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
+ (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
+ return 0;
+
+ crystal_clock_freq = tonga_get_xclk(hwmgr);
+
+ tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_TACH_STATUS, TACH_PERIOD, tach_period);
+
+ return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reads the remote temperature from the SIslands thermal controller.
+*
+* @param hwmgr The address of the hardware manager.
+*/
+int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
+{
+ int temp;
+
+ temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_MULT_THERMAL_STATUS, CTF_TEMP);
+
+ /* Bit 9 means the reading is lower than the lowest usable value. */
+ if (temp & 0x200)
+ temp = FIJI_THERMAL_MAXIMUM_TEMP_READING;
+ else
+ temp = temp & 0x1ff;
+
+ temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ return temp;
+}
+
+/**
+* Set the requested temperature range for high and low alert signals
+*
+* @param hwmgr The address of the hardware manager.
+* @param range Temperature range to be programmed for high and low alert signals
+* @exception PP_Result_BadInput if the input data is not valid.
+*/
+static int fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
+ uint32_t low_temp, uint32_t high_temp)
+{
+ uint32_t low = FIJI_THERMAL_MINIMUM_ALERT_TEMP *
+ PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ uint32_t high = FIJI_THERMAL_MAXIMUM_ALERT_TEMP *
+ PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ if (low < low_temp)
+ low = low_temp;
+ if (high > high_temp)
+ high = high_temp;
+
+ if (low > high)
+ return -EINVAL;
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_INT, DIG_THERM_INTH,
+ (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_INT, DIG_THERM_INTL,
+ (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_CTRL, DIG_THERM_DPM,
+ (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+
+ return 0;
+}
+
+/**
+* Programs thermal controller one-time setting registers
+*
+* @param hwmgr The address of the hardware manager.
+*/
+static int fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+ if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_TACH_CTRL, EDGE_PER_REV,
+ hwmgr->thermal_controller.fanInfo.
+ ucTachometerPulsesPerRevolution - 1);
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
+
+ return 0;
+}
+
+/**
+* Enable thermal alerts on the RV770 thermal controller.
+*
+* @param hwmgr The address of the hardware manager.
+*/
+static int fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr)
+{
+ uint32_t alert;
+
+ alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_INT, THERM_INT_MASK);
+ alert &= ~(FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+ /* send message to SMU to enable internal thermal interrupts */
+ return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
+}
+
+/**
+* Disable thermal alerts on the RV770 thermal controller.
+* @param hwmgr The address of the hardware manager.
+*/
+static int fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr)
+{
+ uint32_t alert;
+
+ alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_INT, THERM_INT_MASK);
+ alert |= (FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+ /* send message to SMU to disable internal thermal interrupts */
+ return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
+}
+
+/**
+* Uninitialize the thermal controller.
+* Currently just disables alerts.
+* @param hwmgr The address of the hardware manager.
+*/
+int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+ int result = fiji_thermal_disable_alert(hwmgr);
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ fiji_fan_ctrl_set_default_mode(hwmgr);
+
+ return result;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from set temperature range routine
+*/
+int tf_fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
+ void *input, void *output, void *storage, int result)
+{
+ struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
+ SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+ uint32_t duty100;
+ uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+ uint16_t fdo_min, slope1, slope2;
+ uint32_t reference_clock;
+ int res;
+ uint64_t tmp64;
+
+ if (data->fan_table_start == 0) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl);
+ return 0;
+ }
+
+ duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL1, FMAX_DUTY100);
+
+ if (duty100 == 0) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl);
+ return 0;
+ }
+
+ tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
+ usPWMMin * duty100;
+ do_div(tmp64, 10000);
+ fdo_min = (uint16_t)tmp64;
+
+ t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+ t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+ pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+ pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+ slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+ slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+ fan_table.TempMin = cpu_to_be16((50 + hwmgr->
+ thermal_controller.advanceFanControlParameters.usTMin) / 100);
+ fan_table.TempMed = cpu_to_be16((50 + hwmgr->
+ thermal_controller.advanceFanControlParameters.usTMed) / 100);
+ fan_table.TempMax = cpu_to_be16((50 + hwmgr->
+ thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+ fan_table.Slope1 = cpu_to_be16(slope1);
+ fan_table.Slope2 = cpu_to_be16(slope2);
+
+ fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+ fan_table.HystDown = cpu_to_be16(hwmgr->
+ thermal_controller.advanceFanControlParameters.ucTHyst);
+
+ fan_table.HystUp = cpu_to_be16(1);
+
+ fan_table.HystSlope = cpu_to_be16(1);
+
+ fan_table.TempRespLim = cpu_to_be16(5);
+
+ reference_clock = tonga_get_xclk(hwmgr);
+
+ fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
+ thermal_controller.advanceFanControlParameters.ulCycleDelay *
+ reference_clock) / 1600);
+
+ fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+ fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
+ hwmgr->device, CGS_IND_REG__SMC,
+ CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+ res = fiji_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
+ (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
+ data->sram_end);
+
+ if (!res && hwmgr->thermal_controller.
+ advanceFanControlParameters.ucMinimumPWMLimit)
+ res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetFanMinPwm,
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.ucMinimumPWMLimit);
+
+ if (!res && hwmgr->thermal_controller.
+ advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
+ res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetFanSclkTarget,
+ hwmgr->thermal_controller.
+ advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
+
+ if (res)
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl);
+
+ return 0;
+}
+
+/**
+* Start the fan control on the SMC.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from set temperature range routine
+*/
+int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
+ void *input, void *output, void *storage, int result)
+{
+/* If the fantable setup has failed we could have disabled
+ * PHM_PlatformCaps_MicrocodeFanControl even after
+ * this function was included in the table.
+ * Make sure that we still think controlling the fan is OK.
+*/
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl)) {
+ fiji_fan_ctrl_start_smc_fan_control(hwmgr);
+ fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+ }
+
+ return 0;
+}
+
+/**
+* Set temperature range for high and low alerts
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from set temperature range routine
+*/
+int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
+ void *input, void *output, void *storage, int result)
+{
+ struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
+
+ if (range == NULL)
+ return -EINVAL;
+
+ return fiji_thermal_set_temperature_range(hwmgr, range->min, range->max);
+}
+
+/**
+* Programs one-time setting registers
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from initialize thermal controller routine
+*/
+int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
+ void *input, void *output, void *storage, int result)
+{
+ return fiji_thermal_initialize(hwmgr);
+}
+
+/**
+* Enable high and low alerts
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from enable alert routine
+*/
+int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
+ void *input, void *output, void *storage, int result)
+{
+ return fiji_thermal_enable_alert(hwmgr);
+}
+
+/**
+* Disable high and low alerts
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from disable alert routine
+*/
+static int tf_fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr,
+ void *input, void *output, void *storage, int result)
+{
+ return fiji_thermal_disable_alert(hwmgr);
+}
+
+static struct phm_master_table_item
+fiji_thermal_start_thermal_controller_master_list[] = {
+ {NULL, tf_fiji_thermal_initialize},
+ {NULL, tf_fiji_thermal_set_temperature_range},
+ {NULL, tf_fiji_thermal_enable_alert},
+/* We should restrict performance levels to low before we halt the SMC.
+ * On the other hand we are still in boot state when we do this
+ * so it would be pointless.
+ * If this assumption changes we have to revisit this table.
+ */
+ {NULL, tf_fiji_thermal_setup_fan_table},
+ {NULL, tf_fiji_thermal_start_smc_fan_control},
+ {NULL, NULL}
+};
+
+static struct phm_master_table_header
+fiji_thermal_start_thermal_controller_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ fiji_thermal_start_thermal_controller_master_list
+};
+
+static struct phm_master_table_item
+fiji_thermal_set_temperature_range_master_list[] = {
+ {NULL, tf_fiji_thermal_disable_alert},
+ {NULL, tf_fiji_thermal_set_temperature_range},
+ {NULL, tf_fiji_thermal_enable_alert},
+ {NULL, NULL}
+};
+
+struct phm_master_table_header
+fiji_thermal_set_temperature_range_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ fiji_thermal_set_temperature_range_master_list
+};
+
+int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+ if (!hwmgr->thermal_controller.fanInfo.bNoFan)
+ fiji_fan_ctrl_set_default_mode(hwmgr);
+ return 0;
+}
+
+/**
+* Initializes the thermal controller related functions in the Hardware Manager structure.
+* @param hwmgr The address of the hardware manager.
+* @exception Any error code from the low-level communication.
+*/
+int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ result = phm_construct_table(hwmgr,
+ &fiji_thermal_set_temperature_range_master,
+ &(hwmgr->set_temperature_range));
+
+ if (!result) {
+ result = phm_construct_table(hwmgr,
+ &fiji_thermal_start_thermal_controller_master,
+ &(hwmgr->start_thermal_controller));
+ if (result)
+ phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
+ }
+
+ if (!result)
+ hwmgr->fan_ctrl_is_in_default_mode = true;
+ return result;
+}
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
new file mode 100644
index 000000000000..8621493b8574
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_thermal.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 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 FIJI_THERMAL_H
+#define FIJI_THERMAL_H
+
+#include "hwmgr.h"
+
+#define FIJI_THERMAL_HIGH_ALERT_MASK 0x1
+#define FIJI_THERMAL_LOW_ALERT_MASK 0x2
+
+#define FIJI_THERMAL_MINIMUM_TEMP_READING -256
+#define FIJI_THERMAL_MAXIMUM_TEMP_READING 255
+
+#define FIJI_THERMAL_MINIMUM_ALERT_TEMP 0
+#define FIJI_THERMAL_MAXIMUM_ALERT_TEMP 255
+
+#define FDO_PWM_MODE_STATIC 1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+
+extern int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+
+extern int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr);
+extern int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+extern int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
+extern int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
+extern int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
+extern int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr);
+extern int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
+extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
new file mode 100644
index 000000000000..9deadabbc81c
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "hwmgr.h"
+
+static int phm_run_table(struct pp_hwmgr *hwmgr,
+ struct phm_runtime_table_header *rt_table,
+ void *input,
+ void *output,
+ void *temp_storage)
+{
+ int result = 0;
+ phm_table_function *function;
+
+ for (function = rt_table->function_list; NULL != *function; function++) {
+ int tmp = (*function)(hwmgr, input, output, temp_storage, result);
+
+ if (tmp == PP_Result_TableImmediateExit)
+ break;
+ if (tmp) {
+ if (0 == result)
+ result = tmp;
+ if (rt_table->exit_error)
+ break;
+ }
+ }
+
+ return result;
+}
+
+int phm_dispatch_table(struct pp_hwmgr *hwmgr,
+ struct phm_runtime_table_header *rt_table,
+ void *input, void *output)
+{
+ int result = 0;
+ void *temp_storage = NULL;
+
+ if (hwmgr == NULL || rt_table == NULL || rt_table->function_list == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
+ return 0; /*temp return ture because some function not implement on some asic */
+ }
+
+ if (0 != rt_table->storage_size) {
+ temp_storage = kzalloc(rt_table->storage_size, GFP_KERNEL);
+ if (temp_storage == NULL) {
+ printk(KERN_ERR "[ powerplay ] Could not allocate table temporary storage\n");
+ return -ENOMEM;
+ }
+ }
+
+ result = phm_run_table(hwmgr, rt_table, input, output, temp_storage);
+
+ if (NULL != temp_storage)
+ kfree(temp_storage);
+
+ return result;
+}
+
+int phm_construct_table(struct pp_hwmgr *hwmgr,
+ struct phm_master_table_header *master_table,
+ struct phm_runtime_table_header *rt_table)
+{
+ uint32_t function_count = 0;
+ const struct phm_master_table_item *table_item;
+ uint32_t size;
+ phm_table_function *run_time_list;
+ phm_table_function *rtf;
+
+ if (hwmgr == NULL || master_table == NULL || rt_table == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
+ return -EINVAL;
+ }
+
+ for (table_item = master_table->master_list;
+ NULL != table_item->tableFunction; table_item++) {
+ if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
+ (table_item->isFunctionNeededInRuntimeTable(hwmgr)))
+ function_count++;
+ }
+
+ size = (function_count + 1) * sizeof(phm_table_function);
+ run_time_list = kzalloc(size, GFP_KERNEL);
+
+ if (NULL == run_time_list)
+ return -ENOMEM;
+
+ rtf = run_time_list;
+ for (table_item = master_table->master_list;
+ NULL != table_item->tableFunction; table_item++) {
+ if ((rtf - run_time_list) > function_count) {
+ printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
+ kfree(run_time_list);
+ return -EINVAL;
+ }
+
+ if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
+ (table_item->isFunctionNeededInRuntimeTable(hwmgr))) {
+ *(rtf++) = table_item->tableFunction;
+ }
+ }
+
+ if ((rtf - run_time_list) > function_count) {
+ printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
+ kfree(run_time_list);
+ return -EINVAL;
+ }
+
+ *rtf = NULL;
+ rt_table->function_list = run_time_list;
+ rt_table->exit_error = (0 != (master_table->flags & PHM_MasterTableFlag_ExitOnError));
+ rt_table->storage_size = master_table->storage_size;
+ return 0;
+}
+
+int phm_destroy_table(struct pp_hwmgr *hwmgr,
+ struct phm_runtime_table_header *rt_table)
+{
+ if (hwmgr == NULL || rt_table == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Parameter\n");
+ return -EINVAL;
+ }
+
+ if (NULL == rt_table->function_list)
+ return 0;
+
+ kfree(rt_table->function_list);
+
+ rt_table->function_list = NULL;
+ rt_table->storage_size = 0;
+ rt_table->exit_error = false;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
new file mode 100644
index 000000000000..0f2d5e4bc241
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/errno.h>
+#include "hwmgr.h"
+#include "hardwaremanager.h"
+#include "power_state.h"
+#include "pp_acpi.h"
+#include "amd_acpi.h"
+#include "amd_powerplay.h"
+
+#define PHM_FUNC_CHECK(hw) \
+ do { \
+ if ((hw) == NULL || (hw)->hwmgr_func == NULL) \
+ return -EINVAL; \
+ } while (0)
+
+void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr)
+{
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableVoltageTransition);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableEngineTransition);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMemoryTransition);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGClockGating);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMGCGTSSM);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLSClockGating);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_Force3DClockSupport);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableLightSleep);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableMCLS);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisablePowerGating);
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableDPM);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DisableSMUUVDHandshake);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalAutoThrottling);
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_NoOD5Support);
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UserMaxClockForMultiDisplays);
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VpuRecoveryInProgress);
+
+ if (acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST) &&
+ acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION))
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest);
+}
+
+bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr)
+{
+ return hwmgr->block_hw_access;
+}
+
+int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block)
+{
+ hwmgr->block_hw_access = block;
+ return 0;
+}
+
+int phm_setup_asic(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface)) {
+ if (NULL != hwmgr->hwmgr_func->asic_setup)
+ return hwmgr->hwmgr_func->asic_setup(hwmgr);
+ } else {
+ return phm_dispatch_table(hwmgr, &(hwmgr->setup_asic),
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+int phm_power_down_asic(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface)) {
+ if (NULL != hwmgr->hwmgr_func->power_off_asic)
+ return hwmgr->hwmgr_func->power_off_asic(hwmgr);
+ } else {
+ return phm_dispatch_table(hwmgr, &(hwmgr->power_down_asic),
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+int phm_set_power_state(struct pp_hwmgr *hwmgr,
+ const struct pp_hw_power_state *pcurrent_state,
+ const struct pp_hw_power_state *pnew_power_state)
+{
+ struct phm_set_power_state_input states;
+
+ PHM_FUNC_CHECK(hwmgr);
+
+ states.pcurrent_state = pcurrent_state;
+ states.pnew_state = pnew_power_state;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface)) {
+ if (NULL != hwmgr->hwmgr_func->power_state_set)
+ return hwmgr->hwmgr_func->power_state_set(hwmgr, &states);
+ } else {
+ return phm_dispatch_table(hwmgr, &(hwmgr->set_power_state), &states, NULL);
+ }
+
+ return 0;
+}
+
+int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface)) {
+ if (NULL != hwmgr->hwmgr_func->dynamic_state_management_enable)
+ return hwmgr->hwmgr_func->dynamic_state_management_enable(hwmgr);
+ } else {
+ return phm_dispatch_table(hwmgr,
+ &(hwmgr->enable_dynamic_state_management),
+ NULL, NULL);
+ }
+ return 0;
+}
+
+int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->force_dpm_level != NULL)
+ return hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
+
+ return 0;
+}
+
+int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *adjusted_ps,
+ const struct pp_power_state *current_ps)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->apply_state_adjust_rules != NULL)
+ return hwmgr->hwmgr_func->apply_state_adjust_rules(
+ hwmgr,
+ adjusted_ps,
+ current_ps);
+ return 0;
+}
+
+int phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->powerdown_uvd != NULL)
+ return hwmgr->hwmgr_func->powerdown_uvd(hwmgr);
+ return 0;
+}
+
+int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->powergate_uvd != NULL)
+ return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
+ return 0;
+}
+
+int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->powergate_vce != NULL)
+ return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
+ return 0;
+}
+
+int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface)) {
+ if (NULL != hwmgr->hwmgr_func->enable_clock_power_gating)
+ return hwmgr->hwmgr_func->enable_clock_power_gating(hwmgr);
+ } else {
+ return phm_dispatch_table(hwmgr, &(hwmgr->enable_clock_power_gatings), NULL, NULL);
+ }
+ return 0;
+}
+
+int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface)) {
+ if (NULL != hwmgr->hwmgr_func->display_config_changed)
+ hwmgr->hwmgr_func->display_config_changed(hwmgr);
+ } else
+ return phm_dispatch_table(hwmgr, &hwmgr->display_configuration_changed, NULL, NULL);
+ return 0;
+}
+
+int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface))
+ if (NULL != hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment)
+ hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment(hwmgr);
+
+ return 0;
+}
+
+int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->stop_thermal_controller == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->stop_thermal_controller(hwmgr);
+}
+
+int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->register_internal_thermal_interrupt == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->register_internal_thermal_interrupt(hwmgr, info);
+}
+
+/**
+* Initializes the thermal controller subsystem.
+*
+* @param pHwMgr the address of the powerplay hardware manager.
+* @param pTemperatureRange the address of the structure holding the temperature range.
+* @exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the dispatcher.
+*/
+int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range)
+{
+ return phm_dispatch_table(hwmgr, &(hwmgr->start_thermal_controller), temperature_range, NULL);
+}
+
+
+bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration(hwmgr);
+}
+
+
+int phm_check_states_equal(struct pp_hwmgr *hwmgr,
+ const struct pp_hw_power_state *pstate1,
+ const struct pp_hw_power_state *pstate2,
+ bool *equal)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->check_states_equal == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->check_states_equal(hwmgr, pstate1, pstate2, equal);
+}
+
+int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
+ const struct amd_pp_display_configuration *display_config)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->store_cc6_data == NULL)
+ return -EINVAL;
+
+ hwmgr->display_config = *display_config;
+ /* to do pass other display configuration in furture */
+
+ if (hwmgr->hwmgr_func->store_cc6_data)
+ hwmgr->hwmgr_func->store_cc6_data(hwmgr,
+ display_config->cpu_pstate_separation_time,
+ display_config->cpu_cc6_disable,
+ display_config->cpu_pstate_disable,
+ display_config->nb_pstate_switch_disable);
+
+ return 0;
+}
+
+int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
+ struct amd_pp_dal_clock_info *info)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)
+ return -EINVAL;
+
+ return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);
+}
+
+int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)
+{
+ PHM_FUNC_CHECK(hwmgr);
+
+ if (hwmgr->hwmgr_func->set_cpu_power_state != NULL)
+ return hwmgr->hwmgr_func->set_cpu_power_state(hwmgr);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
new file mode 100644
index 000000000000..5fb98aa2e719
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "linux/delay.h"
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "cgs_common.h"
+#include "power_state.h"
+#include "hwmgr.h"
+#include "pppcielanes.h"
+#include "pp_debug.h"
+#include "ppatomctrl.h"
+
+extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
+extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
+extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr);
+
+int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
+{
+ struct pp_hwmgr *hwmgr;
+
+ if ((handle == NULL) || (pp_init == NULL))
+ return -EINVAL;
+
+ hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
+ if (hwmgr == NULL)
+ return -ENOMEM;
+
+ handle->hwmgr = hwmgr;
+ hwmgr->smumgr = handle->smu_mgr;
+ hwmgr->device = pp_init->device;
+ hwmgr->chip_family = pp_init->chip_family;
+ hwmgr->chip_id = pp_init->chip_id;
+ hwmgr->hw_revision = pp_init->rev_id;
+ hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
+ hwmgr->power_source = PP_PowerSource_AC;
+
+ switch (hwmgr->chip_family) {
+ case AMD_FAMILY_CZ:
+ cz_hwmgr_init(hwmgr);
+ break;
+ case AMD_FAMILY_VI:
+ switch (hwmgr->chip_id) {
+ case CHIP_TONGA:
+ tonga_hwmgr_init(hwmgr);
+ break;
+ case CHIP_FIJI:
+ fiji_hwmgr_init(hwmgr);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ phm_init_dynamic_caps(hwmgr);
+
+ return 0;
+}
+
+int hwmgr_fini(struct pp_hwmgr *hwmgr)
+{
+ if (hwmgr == NULL || hwmgr->ps == NULL)
+ return -EINVAL;
+
+ kfree(hwmgr->ps);
+ kfree(hwmgr);
+ return 0;
+}
+
+int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ unsigned int i;
+ unsigned int table_entries;
+ struct pp_power_state *state;
+ int size;
+
+ if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
+ return -EINVAL;
+
+ if (hwmgr->hwmgr_func->get_power_state_size == NULL)
+ return -EINVAL;
+
+ hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
+
+ hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
+ sizeof(struct pp_power_state);
+
+ hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL);
+
+ if (hwmgr->ps == NULL)
+ return -ENOMEM;
+
+ state = hwmgr->ps;
+
+ for (i = 0; i < table_entries; i++) {
+ result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
+
+ if (state->classification.flags & PP_StateClassificationFlag_Boot) {
+ hwmgr->boot_ps = state;
+ hwmgr->current_ps = hwmgr->request_ps = state;
+ }
+
+ state->id = i + 1; /* assigned unique num for every power state id */
+
+ if (state->classification.flags & PP_StateClassificationFlag_Uvd)
+ hwmgr->uvd_ps = state;
+ state = (struct pp_power_state *)((unsigned long)state + size);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns once the part of the register indicated by the mask has
+ * reached the given value.
+ */
+int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
+ uint32_t value, uint32_t mask)
+{
+ uint32_t i;
+ uint32_t cur_value;
+
+ if (hwmgr == NULL || hwmgr->device == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < hwmgr->usec_timeout; i++) {
+ cur_value = cgs_read_register(hwmgr->device, index);
+ if ((cur_value & mask) == (value & mask))
+ break;
+ udelay(1);
+ }
+
+ /* timeout means wrong logic*/
+ if (i == hwmgr->usec_timeout)
+ return -1;
+ return 0;
+}
+
+int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
+ uint32_t index, uint32_t value, uint32_t mask)
+{
+ uint32_t i;
+ uint32_t cur_value;
+
+ if (hwmgr == NULL || hwmgr->device == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < hwmgr->usec_timeout; i++) {
+ cur_value = cgs_read_register(hwmgr->device, index);
+ if ((cur_value & mask) != (value & mask))
+ break;
+ udelay(1);
+ }
+
+ /* timeout means wrong logic*/
+ if (i == hwmgr->usec_timeout)
+ return -1;
+ return 0;
+}
+
+
+/**
+ * Returns once the part of the register indicated by the mask has
+ * reached the given value.The indirect space is described by giving
+ * the memory-mapped index of the indirect index register.
+ */
+void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value,
+ uint32_t mask)
+{
+ if (hwmgr == NULL || hwmgr->device == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+ return;
+ }
+
+ cgs_write_register(hwmgr->device, indirect_port, index);
+ phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
+}
+
+void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value,
+ uint32_t mask)
+{
+ if (hwmgr == NULL || hwmgr->device == NULL) {
+ printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
+ return;
+ }
+
+ cgs_write_register(hwmgr->device, indirect_port, index);
+ phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
+ value, mask);
+}
+
+bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
+{
+ return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
+}
+
+bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
+{
+ return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
+}
+
+
+int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
+{
+ uint32_t i, j;
+ uint16_t vvalue;
+ bool found = false;
+ struct pp_atomctrl_voltage_table *table;
+
+ PP_ASSERT_WITH_CODE((NULL != vol_table),
+ "Voltage Table empty.", return -EINVAL);
+
+ table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
+ GFP_KERNEL);
+
+ if (NULL == table)
+ return -EINVAL;
+
+ table->mask_low = vol_table->mask_low;
+ table->phase_delay = vol_table->phase_delay;
+
+ for (i = 0; i < vol_table->count; i++) {
+ vvalue = vol_table->entries[i].value;
+ found = false;
+
+ for (j = 0; j < table->count; j++) {
+ if (vvalue == table->entries[j].value) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ table->entries[table->count].value = vvalue;
+ table->entries[table->count].smio_low =
+ vol_table->entries[i].smio_low;
+ table->count++;
+ }
+ }
+
+ memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
+ kfree(table);
+
+ return 0;
+}
+
+int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
+ phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+ uint32_t i;
+ int result;
+
+ PP_ASSERT_WITH_CODE((0 != dep_table->count),
+ "Voltage Dependency Table empty.", return -EINVAL);
+
+ PP_ASSERT_WITH_CODE((NULL != vol_table),
+ "vol_table empty.", return -EINVAL);
+
+ vol_table->mask_low = 0;
+ vol_table->phase_delay = 0;
+ vol_table->count = dep_table->count;
+
+ for (i = 0; i < dep_table->count; i++) {
+ vol_table->entries[i].value = dep_table->entries[i].mvdd;
+ vol_table->entries[i].smio_low = 0;
+ }
+
+ result = phm_trim_voltage_table(vol_table);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to trim MVDD table.", return result);
+
+ return 0;
+}
+
+int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
+ phm_ppt_v1_clock_voltage_dependency_table *dep_table)
+{
+ uint32_t i;
+ int result;
+
+ PP_ASSERT_WITH_CODE((0 != dep_table->count),
+ "Voltage Dependency Table empty.", return -EINVAL);
+
+ PP_ASSERT_WITH_CODE((NULL != vol_table),
+ "vol_table empty.", return -EINVAL);
+
+ vol_table->mask_low = 0;
+ vol_table->phase_delay = 0;
+ vol_table->count = dep_table->count;
+
+ for (i = 0; i < dep_table->count; i++) {
+ vol_table->entries[i].value = dep_table->entries[i].vddci;
+ vol_table->entries[i].smio_low = 0;
+ }
+
+ result = phm_trim_voltage_table(vol_table);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to trim VDDCI table.", return result);
+
+ return 0;
+}
+
+int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
+ phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+ int i = 0;
+
+ PP_ASSERT_WITH_CODE((0 != lookup_table->count),
+ "Voltage Lookup Table empty.", return -EINVAL);
+
+ PP_ASSERT_WITH_CODE((NULL != vol_table),
+ "vol_table empty.", return -EINVAL);
+
+ vol_table->mask_low = 0;
+ vol_table->phase_delay = 0;
+
+ vol_table->count = lookup_table->count;
+
+ for (i = 0; i < vol_table->count; i++) {
+ vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
+ vol_table->entries[i].smio_low = 0;
+ }
+
+ return 0;
+}
+
+void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps,
+ struct pp_atomctrl_voltage_table *vol_table)
+{
+ unsigned int i, diff;
+
+ if (vol_table->count <= max_vol_steps)
+ return;
+
+ diff = vol_table->count - max_vol_steps;
+
+ for (i = 0; i < max_vol_steps; i++)
+ vol_table->entries[i] = vol_table->entries[i + diff];
+
+ vol_table->count = max_vol_steps;
+
+ return;
+}
+
+int phm_reset_single_dpm_table(void *table,
+ uint32_t count, int max)
+{
+ int i;
+
+ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+
+ PP_ASSERT_WITH_CODE(count <= max,
+ "Fatal error, can not set up single DPM table entries to exceed max number!",
+ );
+
+ dpm_table->count = count;
+ for (i = 0; i < max; i++)
+ dpm_table->dpm_level[i].enabled = false;
+
+ return 0;
+}
+
+void phm_setup_pcie_table_entry(
+ void *table,
+ uint32_t index, uint32_t pcie_gen,
+ uint32_t pcie_lanes)
+{
+ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+ dpm_table->dpm_level[index].value = pcie_gen;
+ dpm_table->dpm_level[index].param1 = pcie_lanes;
+ dpm_table->dpm_level[index].enabled = 1;
+}
+
+int32_t phm_get_dpm_level_enable_mask_value(void *table)
+{
+ int32_t i;
+ int32_t mask = 0;
+ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+
+ for (i = dpm_table->count; i > 0; i--) {
+ mask = mask << 1;
+ if (dpm_table->dpm_level[i - 1].enabled)
+ mask |= 0x1;
+ else
+ mask &= 0xFFFFFFFE;
+ }
+
+ return mask;
+}
+
+uint8_t phm_get_voltage_index(
+ struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
+{
+ uint8_t count = (uint8_t) (lookup_table->count);
+ uint8_t i;
+
+ PP_ASSERT_WITH_CODE((NULL != lookup_table),
+ "Lookup Table empty.", return 0);
+ PP_ASSERT_WITH_CODE((0 != count),
+ "Lookup Table empty.", return 0);
+
+ for (i = 0; i < lookup_table->count; i++) {
+ /* find first voltage equal or bigger than requested */
+ if (lookup_table->entries[i].us_vdd >= voltage)
+ return i;
+ }
+ /* voltage is bigger than max voltage in the table */
+ return i - 1;
+}
+
+uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
+{
+ uint32_t i;
+
+ for (i = 0; i < vddci_table->count; i++) {
+ if (vddci_table->entries[i].value >= vddci)
+ return vddci_table->entries[i].value;
+ }
+
+ PP_ASSERT_WITH_CODE(false,
+ "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
+ return vddci_table->entries[i].value);
+}
+
+int phm_find_boot_level(void *table,
+ uint32_t value, uint32_t *boot_level)
+{
+ int result = -EINVAL;
+ uint32_t i;
+ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
+
+ for (i = 0; i < dpm_table->count; i++) {
+ if (value == dpm_table->dpm_level[i].value) {
+ *boot_level = i;
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table,
+ uint16_t virtual_voltage_id, int32_t *sclk)
+{
+ uint8_t entryId;
+ uint8_t voltageId;
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
+
+ /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
+ for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
+ voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
+ if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
+ break;
+ }
+
+ PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
+ "Can't find requested voltage id in vdd_dep_on_sclk table!",
+ return -EINVAL;
+ );
+
+ *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
+
+ return 0;
+}
+
+/**
+ * Initialize Dynamic State Adjustment Rule Settings
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ */
+int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
+{
+ uint32_t table_size;
+ struct phm_clock_voltage_dependency_table *table_clk_vlt;
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ /* initialize vddc_dep_on_dal_pwrl table */
+ table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
+ table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == table_clk_vlt) {
+ printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
+ return -ENOMEM;
+ } else {
+ table_clk_vlt->count = 4;
+ table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
+ table_clk_vlt->entries[0].v = 0;
+ table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
+ table_clk_vlt->entries[1].v = 720;
+ table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
+ table_clk_vlt->entries[2].v = 810;
+ table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
+ table_clk_vlt->entries[3].v = 900;
+ pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
+ }
+
+ return 0;
+}
+
+int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+ if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
+ kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+ }
+
+ if (NULL != hwmgr->backend) {
+ kfree(hwmgr->backend);
+ hwmgr->backend = NULL;
+ }
+
+ return 0;
+}
+
+uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
+{
+ uint32_t level = 0;
+
+ while (0 == (mask & (1 << level)))
+ level++;
+
+ return level;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h
new file mode 100644
index 000000000000..c9e6c2d80ea6
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 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 PP_HWMGR_PPT_H
+#define PP_HWMGR_PPT_H
+
+#include "hardwaremanager.h"
+#include "smumgr.h"
+#include "atom-types.h"
+
+struct phm_ppt_v1_clock_voltage_dependency_record {
+ uint32_t clk;
+ uint8_t vddInd;
+ uint16_t vdd_offset;
+ uint16_t vddc;
+ uint16_t vddgfx;
+ uint16_t vddci;
+ uint16_t mvdd;
+ uint8_t phases;
+ uint8_t cks_enable;
+ uint8_t cks_voffset;
+};
+
+typedef struct phm_ppt_v1_clock_voltage_dependency_record phm_ppt_v1_clock_voltage_dependency_record;
+
+struct phm_ppt_v1_clock_voltage_dependency_table {
+ uint32_t count; /* Number of entries. */
+ phm_ppt_v1_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+typedef struct phm_ppt_v1_clock_voltage_dependency_table phm_ppt_v1_clock_voltage_dependency_table;
+
+
+/* Multimedia Clock Voltage Dependency records and table */
+struct phm_ppt_v1_mm_clock_voltage_dependency_record {
+ uint32_t dclk; /* UVD D-clock */
+ uint32_t vclk; /* UVD V-clock */
+ uint32_t eclk; /* VCE clock */
+ uint32_t aclk; /* ACP clock */
+ uint32_t samclock; /* SAMU clock */
+ uint8_t vddcInd;
+ uint16_t vddgfx_offset;
+ uint16_t vddc;
+ uint16_t vddgfx;
+ uint8_t phases;
+};
+typedef struct phm_ppt_v1_mm_clock_voltage_dependency_record phm_ppt_v1_mm_clock_voltage_dependency_record;
+
+struct phm_ppt_v1_mm_clock_voltage_dependency_table {
+ uint32_t count; /* Number of entries. */
+ phm_ppt_v1_mm_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+typedef struct phm_ppt_v1_mm_clock_voltage_dependency_table phm_ppt_v1_mm_clock_voltage_dependency_table;
+
+struct phm_ppt_v1_voltage_lookup_record {
+ uint16_t us_calculated;
+ uint16_t us_vdd; /* Base voltage */
+ uint16_t us_cac_low;
+ uint16_t us_cac_mid;
+ uint16_t us_cac_high;
+};
+typedef struct phm_ppt_v1_voltage_lookup_record phm_ppt_v1_voltage_lookup_record;
+
+struct phm_ppt_v1_voltage_lookup_table {
+ uint32_t count;
+ phm_ppt_v1_voltage_lookup_record entries[1]; /* Dynamically allocate count entries. */
+};
+typedef struct phm_ppt_v1_voltage_lookup_table phm_ppt_v1_voltage_lookup_table;
+
+/* PCIE records and Table */
+
+struct phm_ppt_v1_pcie_record {
+ uint8_t gen_speed;
+ uint8_t lane_width;
+};
+typedef struct phm_ppt_v1_pcie_record phm_ppt_v1_pcie_record;
+
+struct phm_ppt_v1_pcie_table {
+ uint32_t count; /* Number of entries. */
+ phm_ppt_v1_pcie_record entries[1]; /* Dynamically allocate count entries. */
+};
+typedef struct phm_ppt_v1_pcie_table phm_ppt_v1_pcie_table;
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c
new file mode 100644
index 000000000000..7b2d5000292d
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c
@@ -0,0 +1,76 @@
+#include <linux/errno.h>
+#include "linux/delay.h"
+#include "hwmgr.h"
+#include "amd_acpi.h"
+
+bool acpi_atcs_functions_supported(void *device, uint32_t index)
+{
+ int32_t result;
+ struct atcs_verify_interface output_buf = {0};
+
+ int32_t temp_buffer = 1;
+
+ result = cgs_call_acpi_method(device, CGS_ACPI_METHOD_ATCS,
+ ATCS_FUNCTION_VERIFY_INTERFACE,
+ &temp_buffer,
+ &output_buf,
+ 1,
+ sizeof(temp_buffer),
+ sizeof(output_buf));
+
+ return result == 0 ? (output_buf.function_bits & (1 << (index - 1))) != 0 : false;
+}
+
+int acpi_pcie_perf_request(void *device, uint8_t perf_req, bool advertise)
+{
+ struct atcs_pref_req_input atcs_input;
+ struct atcs_pref_req_output atcs_output;
+ u32 retry = 3;
+ int result;
+ struct cgs_system_info info = {0};
+
+ if (!acpi_atcs_functions_supported(device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST))
+ return -EINVAL;
+
+ info.size = sizeof(struct cgs_system_info);
+ info.info_id = CGS_SYSTEM_INFO_ADAPTER_BDF_ID;
+ result = cgs_query_system_info(device, &info);
+ if (result != 0)
+ return -EINVAL;
+ atcs_input.client_id = (uint16_t)info.value;
+ atcs_input.size = sizeof(struct atcs_pref_req_input);
+ atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK;
+ atcs_input.flags = ATCS_WAIT_FOR_COMPLETION;
+ if (advertise)
+ atcs_input.flags |= ATCS_ADVERTISE_CAPS;
+ atcs_input.req_type = ATCS_PCIE_LINK_SPEED;
+ atcs_input.perf_req = perf_req;
+
+ atcs_output.size = sizeof(struct atcs_pref_req_input);
+
+ while (retry--) {
+ result = cgs_call_acpi_method(device,
+ CGS_ACPI_METHOD_ATCS,
+ ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST,
+ &atcs_input,
+ &atcs_output,
+ 0,
+ sizeof(atcs_input),
+ sizeof(atcs_output));
+ if (result != 0)
+ return -EIO;
+
+ switch (atcs_output.ret_val) {
+ case ATCS_REQUEST_REFUSED:
+ default:
+ return -EINVAL;
+ case ATCS_REQUEST_COMPLETE:
+ return 0;
+ case ATCS_REQUEST_IN_PROGRESS:
+ udelay(10);
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
new file mode 100644
index 000000000000..2a83a4af2904
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
@@ -0,0 +1,1207 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include "ppatomctrl.h"
+#include "atombios.h"
+#include "cgs_common.h"
+#include "pp_debug.h"
+#include "ppevvmath.h"
+
+#define MEM_ID_MASK 0xff000000
+#define MEM_ID_SHIFT 24
+#define CLOCK_RANGE_MASK 0x00ffffff
+#define CLOCK_RANGE_SHIFT 0
+#define LOW_NIBBLE_MASK 0xf
+#define DATA_EQU_PREV 0
+#define DATA_FROM_TABLE 4
+
+union voltage_object_info {
+ struct _ATOM_VOLTAGE_OBJECT_INFO v1;
+ struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
+ struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
+};
+
+static int atomctrl_retrieve_ac_timing(
+ uint8_t index,
+ ATOM_INIT_REG_BLOCK *reg_block,
+ pp_atomctrl_mc_reg_table *table)
+{
+ uint32_t i, j;
+ uint8_t tmem_id;
+ ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+ ((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
+
+ uint8_t num_ranges = 0;
+
+ while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
+ num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
+ tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
+
+ if (index == tmem_id) {
+ table->mc_reg_table_entry[num_ranges].mclk_max =
+ (uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >>
+ CLOCK_RANGE_SHIFT);
+
+ for (i = 0, j = 1; i < table->last; i++) {
+ if ((table->mc_reg_address[i].uc_pre_reg_data &
+ LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
+ table->mc_reg_table_entry[num_ranges].mc_data[i] =
+ (uint32_t)*((uint32_t *)reg_data + j);
+ j++;
+ } else if ((table->mc_reg_address[i].uc_pre_reg_data &
+ LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
+ table->mc_reg_table_entry[num_ranges].mc_data[i] =
+ table->mc_reg_table_entry[num_ranges].mc_data[i-1];
+ }
+ }
+ num_ranges++;
+ }
+
+ reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+ ((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
+ }
+
+ PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
+ "Invalid VramInfo table.", return -1);
+ table->num_entries = num_ranges;
+
+ return 0;
+}
+
+/**
+ * Get memory clock AC timing registers index from VBIOS table
+ * VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
+ * @param reg_block the address ATOM_INIT_REG_BLOCK
+ * @param table the address of MCRegTable
+ * @return 0
+ */
+static int atomctrl_set_mc_reg_address_table(
+ ATOM_INIT_REG_BLOCK *reg_block,
+ pp_atomctrl_mc_reg_table *table)
+{
+ uint8_t i = 0;
+ uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize))
+ / sizeof(ATOM_INIT_REG_INDEX_FORMAT));
+ ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
+
+ num_entries--; /* subtract 1 data end mark entry */
+
+ PP_ASSERT_WITH_CODE((num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+
+ /* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
+ while ((!(format->ucPreRegDataLength & ACCESS_PLACEHOLDER)) &&
+ (i < num_entries)) {
+ table->mc_reg_address[i].s1 =
+ (uint16_t)(le16_to_cpu(format->usRegIndex));
+ table->mc_reg_address[i].uc_pre_reg_data =
+ format->ucPreRegDataLength;
+
+ i++;
+ format = (ATOM_INIT_REG_INDEX_FORMAT *)
+ ((uint8_t *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
+ }
+
+ table->last = i;
+ return 0;
+}
+
+
+int atomctrl_initialize_mc_reg_table(
+ struct pp_hwmgr *hwmgr,
+ uint8_t module_index,
+ pp_atomctrl_mc_reg_table *table)
+{
+ ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
+ ATOM_INIT_REG_BLOCK *reg_block;
+ int result = 0;
+ u8 frev, crev;
+ u16 size;
+
+ vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *)
+ cgs_atom_get_data_table(hwmgr->device,
+ GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
+
+ if (module_index >= vram_info->ucNumOfVRAMModule) {
+ printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
+ result = -1;
+ } else if (vram_info->sHeader.ucTableFormatRevision < 2) {
+ printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
+ result = -1;
+ }
+
+ if (0 == result) {
+ reg_block = (ATOM_INIT_REG_BLOCK *)
+ ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
+ result = atomctrl_set_mc_reg_address_table(reg_block, table);
+ }
+
+ if (0 == result) {
+ result = atomctrl_retrieve_ac_timing(module_index,
+ reg_block, table);
+ }
+
+ return result;
+}
+
+/**
+ * Set DRAM timings based on engine clock and memory clock.
+ */
+int atomctrl_set_engine_dram_timings_rv770(
+ struct pp_hwmgr *hwmgr,
+ uint32_t engine_clock,
+ uint32_t memory_clock)
+{
+ SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters;
+
+ /* They are both in 10KHz Units. */
+ engine_clock_parameters.ulTargetEngineClock =
+ (uint32_t) engine_clock & SET_CLOCK_FREQ_MASK;
+ engine_clock_parameters.ulTargetEngineClock |=
+ (COMPUTE_ENGINE_PLL_PARAM << 24);
+
+ /* in 10 khz units.*/
+ engine_clock_parameters.sReserved.ulClock =
+ (uint32_t) memory_clock & SET_CLOCK_FREQ_MASK;
+ return cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
+ &engine_clock_parameters);
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ * WARNING: The tabled returned by this function is in
+ * dynamically allocated memory.
+ * The caller has to release if by calling kfree.
+ */
+static ATOM_VOLTAGE_OBJECT_INFO *get_voltage_info_table(void *device)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 size;
+ union voltage_object_info *voltage_info;
+
+ voltage_info = (union voltage_object_info *)
+ cgs_atom_get_data_table(device, index,
+ &size, &frev, &crev);
+
+ if (voltage_info != NULL)
+ return (ATOM_VOLTAGE_OBJECT_INFO *) &(voltage_info->v3);
+ else
+ return NULL;
+}
+
+static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3(
+ const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table,
+ uint8_t voltage_type, uint8_t voltage_mode)
+{
+ unsigned int size = le16_to_cpu(voltage_object_info_table->sHeader.usStructureSize);
+ unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
+ uint8_t *start = (uint8_t *)voltage_object_info_table;
+
+ while (offset < size) {
+ const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
+ (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
+
+ if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
+ voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
+ return voltage_object;
+
+ offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
+ }
+
+ return NULL;
+}
+
+/** atomctrl_get_memory_pll_dividers_si().
+ *
+ * @param hwmgr input parameter: pointer to HwMgr
+ * @param clock_value input parameter: memory clock
+ * @param dividers output parameter: memory PLL dividers
+ * @param strobe_mode input parameter: 1 for strobe mode, 0 for performance mode
+ */
+int atomctrl_get_memory_pll_dividers_si(
+ struct pp_hwmgr *hwmgr,
+ uint32_t clock_value,
+ pp_atomctrl_memory_clock_param *mpll_param,
+ bool strobe_mode)
+{
+ COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters;
+ int result;
+
+ mpll_parameters.ulClock = (uint32_t) clock_value;
+ mpll_parameters.ucInputFlag = (uint8_t)((strobe_mode) ? 1 : 0);
+
+ result = cgs_atom_exec_cmd_table
+ (hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
+ &mpll_parameters);
+
+ if (0 == result) {
+ mpll_param->mpll_fb_divider.clk_frac =
+ mpll_parameters.ulFbDiv.usFbDivFrac;
+ mpll_param->mpll_fb_divider.cl_kf =
+ mpll_parameters.ulFbDiv.usFbDiv;
+ mpll_param->mpll_post_divider =
+ (uint32_t)mpll_parameters.ucPostDiv;
+ mpll_param->vco_mode =
+ (uint32_t)(mpll_parameters.ucPllCntlFlag &
+ MPLL_CNTL_FLAG_VCO_MODE_MASK);
+ mpll_param->yclk_sel =
+ (uint32_t)((mpll_parameters.ucPllCntlFlag &
+ MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0);
+ mpll_param->qdr =
+ (uint32_t)((mpll_parameters.ucPllCntlFlag &
+ MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0);
+ mpll_param->half_rate =
+ (uint32_t)((mpll_parameters.ucPllCntlFlag &
+ MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0);
+ mpll_param->dll_speed =
+ (uint32_t)(mpll_parameters.ucDllSpeed);
+ mpll_param->bw_ctrl =
+ (uint32_t)(mpll_parameters.ucBWCntl);
+ }
+
+ return result;
+}
+
+/** atomctrl_get_memory_pll_dividers_vi().
+ *
+ * @param hwmgr input parameter: pointer to HwMgr
+ * @param clock_value input parameter: memory clock
+ * @param dividers output parameter: memory PLL dividers
+ */
+int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
+ uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param)
+{
+ COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters;
+ int result;
+
+ mpll_parameters.ulClock.ulClock = (uint32_t)clock_value;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
+ &mpll_parameters);
+
+ if (!result)
+ mpll_param->mpll_post_divider =
+ (uint32_t)mpll_parameters.ulClock.ucPostDiv;
+
+ return result;
+}
+
+int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
+ uint32_t clock_value,
+ pp_atomctrl_clock_dividers_kong *dividers)
+{
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters;
+ int result;
+
+ pll_parameters.ulClock = clock_value;
+
+ result = cgs_atom_exec_cmd_table
+ (hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
+ &pll_parameters);
+
+ if (0 == result) {
+ dividers->pll_post_divider = pll_parameters.ucPostDiv;
+ dividers->real_clock = pll_parameters.ulClock;
+ }
+
+ return result;
+}
+
+int atomctrl_get_engine_pll_dividers_vi(
+ struct pp_hwmgr *hwmgr,
+ uint32_t clock_value,
+ pp_atomctrl_clock_dividers_vi *dividers)
+{
+ COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
+ int result;
+
+ pll_patameters.ulClock.ulClock = clock_value;
+ pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
+
+ result = cgs_atom_exec_cmd_table
+ (hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
+ &pll_patameters);
+
+ if (0 == result) {
+ dividers->pll_post_divider =
+ pll_patameters.ulClock.ucPostDiv;
+ dividers->real_clock =
+ pll_patameters.ulClock.ulClock;
+
+ dividers->ul_fb_div.ul_fb_div_frac =
+ pll_patameters.ulFbDiv.usFbDivFrac;
+ dividers->ul_fb_div.ul_fb_div =
+ pll_patameters.ulFbDiv.usFbDiv;
+
+ dividers->uc_pll_ref_div =
+ pll_patameters.ucPllRefDiv;
+ dividers->uc_pll_post_div =
+ pll_patameters.ucPllPostDiv;
+ dividers->uc_pll_cntl_flag =
+ pll_patameters.ucPllCntlFlag;
+ }
+
+ return result;
+}
+
+int atomctrl_get_dfs_pll_dividers_vi(
+ struct pp_hwmgr *hwmgr,
+ uint32_t clock_value,
+ pp_atomctrl_clock_dividers_vi *dividers)
+{
+ COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
+ int result;
+
+ pll_patameters.ulClock.ulClock = clock_value;
+ pll_patameters.ulClock.ucPostDiv =
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK;
+
+ result = cgs_atom_exec_cmd_table
+ (hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
+ &pll_patameters);
+
+ if (0 == result) {
+ dividers->pll_post_divider =
+ pll_patameters.ulClock.ucPostDiv;
+ dividers->real_clock =
+ pll_patameters.ulClock.ulClock;
+
+ dividers->ul_fb_div.ul_fb_div_frac =
+ pll_patameters.ulFbDiv.usFbDivFrac;
+ dividers->ul_fb_div.ul_fb_div =
+ pll_patameters.ulFbDiv.usFbDiv;
+
+ dividers->uc_pll_ref_div =
+ pll_patameters.ucPllRefDiv;
+ dividers->uc_pll_post_div =
+ pll_patameters.ucPllPostDiv;
+ dividers->uc_pll_cntl_flag =
+ pll_patameters.ucPllCntlFlag;
+ }
+
+ return result;
+}
+
+/**
+ * Get the reference clock in 10KHz
+ */
+uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr)
+{
+ ATOM_FIRMWARE_INFO *fw_info;
+ u8 frev, crev;
+ u16 size;
+ uint32_t clock;
+
+ fw_info = (ATOM_FIRMWARE_INFO *)
+ cgs_atom_get_data_table(hwmgr->device,
+ GetIndexIntoMasterTable(DATA, FirmwareInfo),
+ &size, &frev, &crev);
+
+ if (fw_info == NULL)
+ clock = 2700;
+ else
+ clock = (uint32_t)(le16_to_cpu(fw_info->usReferenceClock));
+
+ return clock;
+}
+
+/**
+ * Returns true if the given voltage type is controlled by GPIO pins.
+ * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
+ * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
+ * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
+ */
+bool atomctrl_is_voltage_controled_by_gpio_v3(
+ struct pp_hwmgr *hwmgr,
+ uint8_t voltage_type,
+ uint8_t voltage_mode)
+{
+ ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
+ (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->device);
+ bool ret;
+
+ PP_ASSERT_WITH_CODE((NULL != voltage_info),
+ "Could not find Voltage Table in BIOS.", return false;);
+
+ ret = (NULL != atomctrl_lookup_voltage_type_v3
+ (voltage_info, voltage_type, voltage_mode)) ? true : false;
+
+ return ret;
+}
+
+int atomctrl_get_voltage_table_v3(
+ struct pp_hwmgr *hwmgr,
+ uint8_t voltage_type,
+ uint8_t voltage_mode,
+ pp_atomctrl_voltage_table *voltage_table)
+{
+ ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
+ (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->device);
+ const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
+ unsigned int i;
+
+ PP_ASSERT_WITH_CODE((NULL != voltage_info),
+ "Could not find Voltage Table in BIOS.", return -1;);
+
+ voltage_object = atomctrl_lookup_voltage_type_v3
+ (voltage_info, voltage_type, voltage_mode);
+
+ if (voltage_object == NULL)
+ return -1;
+
+ PP_ASSERT_WITH_CODE(
+ (voltage_object->asGpioVoltageObj.ucGpioEntryNum <=
+ PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES),
+ "Too many voltage entries!",
+ return -1;
+ );
+
+ for (i = 0; i < voltage_object->asGpioVoltageObj.ucGpioEntryNum; i++) {
+ voltage_table->entries[i].value =
+ voltage_object->asGpioVoltageObj.asVolGpioLut[i].usVoltageValue;
+ voltage_table->entries[i].smio_low =
+ voltage_object->asGpioVoltageObj.asVolGpioLut[i].ulVoltageId;
+ }
+
+ voltage_table->mask_low =
+ voltage_object->asGpioVoltageObj.ulGpioMaskVal;
+ voltage_table->count =
+ voltage_object->asGpioVoltageObj.ucGpioEntryNum;
+ voltage_table->phase_delay =
+ voltage_object->asGpioVoltageObj.ucPhaseDelay;
+
+ return 0;
+}
+
+static bool atomctrl_lookup_gpio_pin(
+ ATOM_GPIO_PIN_LUT * gpio_lookup_table,
+ const uint32_t pinId,
+ pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
+{
+ unsigned int size = le16_to_cpu(gpio_lookup_table->sHeader.usStructureSize);
+ unsigned int offset = offsetof(ATOM_GPIO_PIN_LUT, asGPIO_Pin[0]);
+ uint8_t *start = (uint8_t *)gpio_lookup_table;
+
+ while (offset < size) {
+ const ATOM_GPIO_PIN_ASSIGNMENT *pin_assignment =
+ (const ATOM_GPIO_PIN_ASSIGNMENT *)(start + offset);
+
+ if (pinId == pin_assignment->ucGPIO_ID) {
+ gpio_pin_assignment->uc_gpio_pin_bit_shift =
+ pin_assignment->ucGpioPinBitShift;
+ gpio_pin_assignment->us_gpio_pin_aindex =
+ le16_to_cpu(pin_assignment->usGpioPin_AIndex);
+ return false;
+ }
+
+ offset += offsetof(ATOM_GPIO_PIN_ASSIGNMENT, ucGPIO_ID) + 1;
+ }
+
+ return true;
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ * WARNING: The tabled returned by this function is in
+ * dynamically allocated memory.
+ * The caller has to release if by calling kfree.
+ */
+static ATOM_GPIO_PIN_LUT *get_gpio_lookup_table(void *device)
+{
+ u8 frev, crev;
+ u16 size;
+ void *table_address;
+
+ table_address = (ATOM_GPIO_PIN_LUT *)
+ cgs_atom_get_data_table(device,
+ GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT),
+ &size, &frev, &crev);
+
+ PP_ASSERT_WITH_CODE((NULL != table_address),
+ "Error retrieving BIOS Table Address!", return NULL;);
+
+ return (ATOM_GPIO_PIN_LUT *)table_address;
+}
+
+/**
+ * Returns 1 if the given pin id find in lookup table.
+ */
+bool atomctrl_get_pp_assign_pin(
+ struct pp_hwmgr *hwmgr,
+ const uint32_t pinId,
+ pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
+{
+ bool bRet = 0;
+ ATOM_GPIO_PIN_LUT *gpio_lookup_table =
+ get_gpio_lookup_table(hwmgr->device);
+
+ PP_ASSERT_WITH_CODE((NULL != gpio_lookup_table),
+ "Could not find GPIO lookup Table in BIOS.", return -1);
+
+ bRet = atomctrl_lookup_gpio_pin(gpio_lookup_table, pinId,
+ gpio_pin_assignment);
+
+ return bRet;
+}
+
+int atomctrl_calculate_voltage_evv_on_sclk(
+ struct pp_hwmgr *hwmgr,
+ uint8_t voltage_type,
+ uint32_t sclk,
+ uint16_t virtual_voltage_Id,
+ uint16_t *voltage,
+ uint16_t dpm_level,
+ bool debug)
+{
+ ATOM_ASIC_PROFILING_INFO_V3_4 *getASICProfilingInfo;
+
+ EFUSE_LINEAR_FUNC_PARAM sRO_fuse;
+ EFUSE_LINEAR_FUNC_PARAM sCACm_fuse;
+ EFUSE_LINEAR_FUNC_PARAM sCACb_fuse;
+ EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse;
+ EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse;
+ EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse;
+ EFUSE_INPUT_PARAMETER sInput_FuseValues;
+ READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues;
+
+ uint32_t ul_RO_fused, ul_CACb_fused, ul_CACm_fused, ul_Kt_Beta_fused, ul_Kv_m_fused, ul_Kv_b_fused;
+ fInt fSM_A0, fSM_A1, fSM_A2, fSM_A3, fSM_A4, fSM_A5, fSM_A6, fSM_A7;
+ fInt fMargin_RO_a, fMargin_RO_b, fMargin_RO_c, fMargin_fixed, fMargin_FMAX_mean, fMargin_Plat_mean, fMargin_FMAX_sigma, fMargin_Plat_sigma, fMargin_DC_sigma;
+ fInt fLkg_FT, repeat;
+ fInt fMicro_FMAX, fMicro_CR, fSigma_FMAX, fSigma_CR, fSigma_DC, fDC_SCLK, fSquared_Sigma_DC, fSquared_Sigma_CR, fSquared_Sigma_FMAX;
+ fInt fRLL_LoadLine, fPowerDPMx, fDerateTDP, fVDDC_base, fA_Term, fC_Term, fB_Term, fRO_DC_margin;
+ fInt fRO_fused, fCACm_fused, fCACb_fused, fKv_m_fused, fKv_b_fused, fKt_Beta_fused, fFT_Lkg_V0NORM;
+ fInt fSclk_margin, fSclk, fEVV_V;
+ fInt fV_min, fV_max, fT_prod, fLKG_Factor, fT_FT, fV_FT, fV_x, fTDP_Power, fTDP_Power_right, fTDP_Power_left, fTDP_Current, fV_NL;
+ uint32_t ul_FT_Lkg_V0NORM;
+ fInt fLn_MaxDivMin, fMin, fAverage, fRange;
+ fInt fRoots[2];
+ fInt fStepSize = GetScaledFraction(625, 100000);
+
+ int result;
+
+ getASICProfilingInfo = (ATOM_ASIC_PROFILING_INFO_V3_4 *)
+ cgs_atom_get_data_table(hwmgr->device,
+ GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
+ NULL, NULL, NULL);
+
+ if (!getASICProfilingInfo)
+ return -1;
+
+ if(getASICProfilingInfo->asHeader.ucTableFormatRevision < 3 ||
+ (getASICProfilingInfo->asHeader.ucTableFormatRevision == 3 &&
+ getASICProfilingInfo->asHeader.ucTableContentRevision < 4))
+ return -1;
+
+ /*-----------------------------------------------------------
+ *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
+ *-----------------------------------------------------------
+ */
+ fRLL_LoadLine = Divide(getASICProfilingInfo->ulLoadLineSlop, 1000);
+
+ switch (dpm_level) {
+ case 1:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm1);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM1, 1000);
+ break;
+ case 2:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm2);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM2, 1000);
+ break;
+ case 3:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm3);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM3, 1000);
+ break;
+ case 4:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm4);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM4, 1000);
+ break;
+ case 5:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm5);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM5, 1000);
+ break;
+ case 6:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm6);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM6, 1000);
+ break;
+ case 7:
+ fPowerDPMx = Convert_ULONG_ToFraction(getASICProfilingInfo->usPowerDpm7);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM7, 1000);
+ break;
+ default:
+ printk(KERN_ERR "DPM Level not supported\n");
+ fPowerDPMx = Convert_ULONG_ToFraction(1);
+ fDerateTDP = GetScaledFraction(getASICProfilingInfo->ulTdpDerateDPM0, 1000);
+ }
+
+ /*-------------------------
+ * DECODING FUSE VALUES
+ * ------------------------
+ */
+ /*Decode RO_Fused*/
+ sRO_fuse = getASICProfilingInfo->sRoFuse;
+
+ sInput_FuseValues.usEfuseIndex = sRO_fuse.usEfuseIndex;
+ sInput_FuseValues.ucBitShift = sRO_fuse.ucEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = sRO_fuse.ucEfuseLength;
+
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+
+ if (result)
+ return result;
+
+ /* Finally, the actual fuse value */
+ ul_RO_fused = sOutput_FuseValues.ulEfuseValue;
+ fMin = GetScaledFraction(sRO_fuse.ulEfuseMin, 1);
+ fRange = GetScaledFraction(sRO_fuse.ulEfuseEncodeRange, 1);
+ fRO_fused = fDecodeLinearFuse(ul_RO_fused, fMin, fRange, sRO_fuse.ucEfuseLength);
+
+ sCACm_fuse = getASICProfilingInfo->sCACm;
+
+ sInput_FuseValues.usEfuseIndex = sCACm_fuse.usEfuseIndex;
+ sInput_FuseValues.ucBitShift = sCACm_fuse.ucEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = sCACm_fuse.ucEfuseLength;
+
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+
+ if (result)
+ return result;
+
+ ul_CACm_fused = sOutput_FuseValues.ulEfuseValue;
+ fMin = GetScaledFraction(sCACm_fuse.ulEfuseMin, 1000);
+ fRange = GetScaledFraction(sCACm_fuse.ulEfuseEncodeRange, 1000);
+
+ fCACm_fused = fDecodeLinearFuse(ul_CACm_fused, fMin, fRange, sCACm_fuse.ucEfuseLength);
+
+ sCACb_fuse = getASICProfilingInfo->sCACb;
+
+ sInput_FuseValues.usEfuseIndex = sCACb_fuse.usEfuseIndex;
+ sInput_FuseValues.ucBitShift = sCACb_fuse.ucEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = sCACb_fuse.ucEfuseLength;
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+
+ if (result)
+ return result;
+
+ ul_CACb_fused = sOutput_FuseValues.ulEfuseValue;
+ fMin = GetScaledFraction(sCACb_fuse.ulEfuseMin, 1000);
+ fRange = GetScaledFraction(sCACb_fuse.ulEfuseEncodeRange, 1000);
+
+ fCACb_fused = fDecodeLinearFuse(ul_CACb_fused, fMin, fRange, sCACb_fuse.ucEfuseLength);
+
+ sKt_Beta_fuse = getASICProfilingInfo->sKt_b;
+
+ sInput_FuseValues.usEfuseIndex = sKt_Beta_fuse.usEfuseIndex;
+ sInput_FuseValues.ucBitShift = sKt_Beta_fuse.ucEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = sKt_Beta_fuse.ucEfuseLength;
+
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+
+ if (result)
+ return result;
+
+ ul_Kt_Beta_fused = sOutput_FuseValues.ulEfuseValue;
+ fAverage = GetScaledFraction(sKt_Beta_fuse.ulEfuseEncodeAverage, 1000);
+ fRange = GetScaledFraction(sKt_Beta_fuse.ulEfuseEncodeRange, 1000);
+
+ fKt_Beta_fused = fDecodeLogisticFuse(ul_Kt_Beta_fused,
+ fAverage, fRange, sKt_Beta_fuse.ucEfuseLength);
+
+ sKv_m_fuse = getASICProfilingInfo->sKv_m;
+
+ sInput_FuseValues.usEfuseIndex = sKv_m_fuse.usEfuseIndex;
+ sInput_FuseValues.ucBitShift = sKv_m_fuse.ucEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = sKv_m_fuse.ucEfuseLength;
+
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+ if (result)
+ return result;
+
+ ul_Kv_m_fused = sOutput_FuseValues.ulEfuseValue;
+ fAverage = GetScaledFraction(sKv_m_fuse.ulEfuseEncodeAverage, 1000);
+ fRange = GetScaledFraction((sKv_m_fuse.ulEfuseEncodeRange & 0x7fffffff), 1000);
+ fRange = fMultiply(fRange, ConvertToFraction(-1));
+
+ fKv_m_fused = fDecodeLogisticFuse(ul_Kv_m_fused,
+ fAverage, fRange, sKv_m_fuse.ucEfuseLength);
+
+ sKv_b_fuse = getASICProfilingInfo->sKv_b;
+
+ sInput_FuseValues.usEfuseIndex = sKv_b_fuse.usEfuseIndex;
+ sInput_FuseValues.ucBitShift = sKv_b_fuse.ucEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = sKv_b_fuse.ucEfuseLength;
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+
+ if (result)
+ return result;
+
+ ul_Kv_b_fused = sOutput_FuseValues.ulEfuseValue;
+ fAverage = GetScaledFraction(sKv_b_fuse.ulEfuseEncodeAverage, 1000);
+ fRange = GetScaledFraction(sKv_b_fuse.ulEfuseEncodeRange, 1000);
+
+ fKv_b_fused = fDecodeLogisticFuse(ul_Kv_b_fused,
+ fAverage, fRange, sKv_b_fuse.ucEfuseLength);
+
+ /* Decoding the Leakage - No special struct container */
+ /*
+ * usLkgEuseIndex=56
+ * ucLkgEfuseBitLSB=6
+ * ucLkgEfuseLength=10
+ * ulLkgEncodeLn_MaxDivMin=69077
+ * ulLkgEncodeMax=1000000
+ * ulLkgEncodeMin=1000
+ * ulEfuseLogisticAlpha=13
+ */
+
+ sInput_FuseValues.usEfuseIndex = getASICProfilingInfo->usLkgEuseIndex;
+ sInput_FuseValues.ucBitShift = getASICProfilingInfo->ucLkgEfuseBitLSB;
+ sInput_FuseValues.ucBitLength = getASICProfilingInfo->ucLkgEfuseLength;
+
+ sOutput_FuseValues.sEfuse = sInput_FuseValues;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &sOutput_FuseValues);
+
+ if (result)
+ return result;
+
+ ul_FT_Lkg_V0NORM = sOutput_FuseValues.ulEfuseValue;
+ fLn_MaxDivMin = GetScaledFraction(getASICProfilingInfo->ulLkgEncodeLn_MaxDivMin, 10000);
+ fMin = GetScaledFraction(getASICProfilingInfo->ulLkgEncodeMin, 10000);
+
+ fFT_Lkg_V0NORM = fDecodeLeakageID(ul_FT_Lkg_V0NORM,
+ fLn_MaxDivMin, fMin, getASICProfilingInfo->ucLkgEfuseLength);
+ fLkg_FT = fFT_Lkg_V0NORM;
+
+ /*-------------------------------------------
+ * PART 2 - Grabbing all required values
+ *-------------------------------------------
+ */
+ fSM_A0 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A0, 1000000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A0_sign)));
+ fSM_A1 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A1, 1000000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A1_sign)));
+ fSM_A2 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A2, 100000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A2_sign)));
+ fSM_A3 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A3, 1000000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A3_sign)));
+ fSM_A4 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A4, 1000000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A4_sign)));
+ fSM_A5 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A5, 1000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A5_sign)));
+ fSM_A6 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A6, 1000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A6_sign)));
+ fSM_A7 = fMultiply(GetScaledFraction(getASICProfilingInfo->ulSM_A7, 1000),
+ ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A7_sign)));
+
+ fMargin_RO_a = ConvertToFraction(getASICProfilingInfo->ulMargin_RO_a);
+ fMargin_RO_b = ConvertToFraction(getASICProfilingInfo->ulMargin_RO_b);
+ fMargin_RO_c = ConvertToFraction(getASICProfilingInfo->ulMargin_RO_c);
+
+ fMargin_fixed = ConvertToFraction(getASICProfilingInfo->ulMargin_fixed);
+
+ fMargin_FMAX_mean = GetScaledFraction(
+ getASICProfilingInfo->ulMargin_Fmax_mean, 10000);
+ fMargin_Plat_mean = GetScaledFraction(
+ getASICProfilingInfo->ulMargin_plat_mean, 10000);
+ fMargin_FMAX_sigma = GetScaledFraction(
+ getASICProfilingInfo->ulMargin_Fmax_sigma, 10000);
+ fMargin_Plat_sigma = GetScaledFraction(
+ getASICProfilingInfo->ulMargin_plat_sigma, 10000);
+
+ fMargin_DC_sigma = GetScaledFraction(
+ getASICProfilingInfo->ulMargin_DC_sigma, 100);
+ fMargin_DC_sigma = fDivide(fMargin_DC_sigma, ConvertToFraction(1000));
+
+ fCACm_fused = fDivide(fCACm_fused, ConvertToFraction(100));
+ fCACb_fused = fDivide(fCACb_fused, ConvertToFraction(100));
+ fKt_Beta_fused = fDivide(fKt_Beta_fused, ConvertToFraction(100));
+ fKv_m_fused = fNegate(fDivide(fKv_m_fused, ConvertToFraction(100)));
+ fKv_b_fused = fDivide(fKv_b_fused, ConvertToFraction(10));
+
+ fSclk = GetScaledFraction(sclk, 100);
+
+ fV_max = fDivide(GetScaledFraction(
+ getASICProfilingInfo->ulMaxVddc, 1000), ConvertToFraction(4));
+ fT_prod = GetScaledFraction(getASICProfilingInfo->ulBoardCoreTemp, 10);
+ fLKG_Factor = GetScaledFraction(getASICProfilingInfo->ulEvvLkgFactor, 100);
+ fT_FT = GetScaledFraction(getASICProfilingInfo->ulLeakageTemp, 10);
+ fV_FT = fDivide(GetScaledFraction(
+ getASICProfilingInfo->ulLeakageVoltage, 1000), ConvertToFraction(4));
+ fV_min = fDivide(GetScaledFraction(
+ getASICProfilingInfo->ulMinVddc, 1000), ConvertToFraction(4));
+
+ /*-----------------------
+ * PART 3
+ *-----------------------
+ */
+
+ fA_Term = fAdd(fMargin_RO_a, fAdd(fMultiply(fSM_A4,fSclk), fSM_A5));
+ fB_Term = fAdd(fAdd(fMultiply(fSM_A2, fSclk), fSM_A6), fMargin_RO_b);
+ fC_Term = fAdd(fMargin_RO_c,
+ fAdd(fMultiply(fSM_A0,fLkg_FT),
+ fAdd(fMultiply(fSM_A1, fMultiply(fLkg_FT,fSclk)),
+ fAdd(fMultiply(fSM_A3, fSclk),
+ fSubtract(fSM_A7,fRO_fused)))));
+
+ fVDDC_base = fSubtract(fRO_fused,
+ fSubtract(fMargin_RO_c,
+ fSubtract(fSM_A3, fMultiply(fSM_A1, fSclk))));
+ fVDDC_base = fDivide(fVDDC_base, fAdd(fMultiply(fSM_A0,fSclk), fSM_A2));
+
+ repeat = fSubtract(fVDDC_base,
+ fDivide(fMargin_DC_sigma, ConvertToFraction(1000)));
+
+ fRO_DC_margin = fAdd(fMultiply(fMargin_RO_a,
+ fGetSquare(repeat)),
+ fAdd(fMultiply(fMargin_RO_b, repeat),
+ fMargin_RO_c));
+
+ fDC_SCLK = fSubtract(fRO_fused,
+ fSubtract(fRO_DC_margin,
+ fSubtract(fSM_A3,
+ fMultiply(fSM_A2, repeat))));
+ fDC_SCLK = fDivide(fDC_SCLK, fAdd(fMultiply(fSM_A0,repeat), fSM_A1));
+
+ fSigma_DC = fSubtract(fSclk, fDC_SCLK);
+
+ fMicro_FMAX = fMultiply(fSclk, fMargin_FMAX_mean);
+ fMicro_CR = fMultiply(fSclk, fMargin_Plat_mean);
+ fSigma_FMAX = fMultiply(fSclk, fMargin_FMAX_sigma);
+ fSigma_CR = fMultiply(fSclk, fMargin_Plat_sigma);
+
+ fSquared_Sigma_DC = fGetSquare(fSigma_DC);
+ fSquared_Sigma_CR = fGetSquare(fSigma_CR);
+ fSquared_Sigma_FMAX = fGetSquare(fSigma_FMAX);
+
+ fSclk_margin = fAdd(fMicro_FMAX,
+ fAdd(fMicro_CR,
+ fAdd(fMargin_fixed,
+ fSqrt(fAdd(fSquared_Sigma_FMAX,
+ fAdd(fSquared_Sigma_DC, fSquared_Sigma_CR))))));
+ /*
+ fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
+ fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
+ fC_Term = fRO_DC_margin + fSM_A0 * fLkg_FT + fSM_A1 * fLkg_FT * (fSclk + fSclk_margin) + fSM_A3 * (fSclk + fSclk_margin) + fSM_A7 - fRO_fused;
+ */
+
+ fA_Term = fAdd(fMultiply(fSM_A4, fAdd(fSclk, fSclk_margin)), fSM_A5);
+ fB_Term = fAdd(fMultiply(fSM_A2, fAdd(fSclk, fSclk_margin)), fSM_A6);
+ fC_Term = fAdd(fRO_DC_margin,
+ fAdd(fMultiply(fSM_A0, fLkg_FT),
+ fAdd(fMultiply(fMultiply(fSM_A1, fLkg_FT),
+ fAdd(fSclk, fSclk_margin)),
+ fAdd(fMultiply(fSM_A3,
+ fAdd(fSclk, fSclk_margin)),
+ fSubtract(fSM_A7, fRO_fused)))));
+
+ SolveQuadracticEqn(fA_Term, fB_Term, fC_Term, fRoots);
+
+ if (GreaterThan(fRoots[0], fRoots[1]))
+ fEVV_V = fRoots[1];
+ else
+ fEVV_V = fRoots[0];
+
+ if (GreaterThan(fV_min, fEVV_V))
+ fEVV_V = fV_min;
+ else if (GreaterThan(fEVV_V, fV_max))
+ fEVV_V = fSubtract(fV_max, fStepSize);
+
+ fEVV_V = fRoundUpByStepSize(fEVV_V, fStepSize, 0);
+
+ /*-----------------
+ * PART 4
+ *-----------------
+ */
+
+ fV_x = fV_min;
+
+ while (GreaterThan(fAdd(fV_max, fStepSize), fV_x)) {
+ fTDP_Power_left = fMultiply(fMultiply(fMultiply(fAdd(
+ fMultiply(fCACm_fused, fV_x), fCACb_fused), fSclk),
+ fGetSquare(fV_x)), fDerateTDP);
+
+ fTDP_Power_right = fMultiply(fFT_Lkg_V0NORM, fMultiply(fLKG_Factor,
+ fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused,
+ fT_prod), fKv_b_fused), fV_x)), fV_x)));
+ fTDP_Power_right = fMultiply(fTDP_Power_right, fExponential(fMultiply(
+ fKt_Beta_fused, fT_prod)));
+ fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply(
+ fAdd(fMultiply(fKv_m_fused, fT_prod), fKv_b_fused), fV_FT)));
+ fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply(
+ fKt_Beta_fused, fT_FT)));
+
+ fTDP_Power = fAdd(fTDP_Power_left, fTDP_Power_right);
+
+ fTDP_Current = fDivide(fTDP_Power, fV_x);
+
+ fV_NL = fAdd(fV_x, fDivide(fMultiply(fTDP_Current, fRLL_LoadLine),
+ ConvertToFraction(10)));
+
+ fV_NL = fRoundUpByStepSize(fV_NL, fStepSize, 0);
+
+ if (GreaterThan(fV_max, fV_NL) &&
+ (GreaterThan(fV_NL,fEVV_V) ||
+ Equal(fV_NL, fEVV_V))) {
+ fV_NL = fMultiply(fV_NL, ConvertToFraction(1000));
+
+ *voltage = (uint16_t)fV_NL.partial.real;
+ break;
+ } else
+ fV_x = fAdd(fV_x, fStepSize);
+ }
+
+ return result;
+}
+
+/** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
+ * @param hwmgr input: pointer to hwManager
+ * @param voltage_type input: type of EVV voltage VDDC or VDDGFX
+ * @param sclk input: in 10Khz unit. DPM state SCLK frequency
+ * which is define in PPTable SCLK/VDDC dependence
+ * table associated with this virtual_voltage_Id
+ * @param virtual_voltage_Id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
+ * @param voltage output: real voltage level in unit of mv
+ */
+int atomctrl_get_voltage_evv_on_sclk(
+ struct pp_hwmgr *hwmgr,
+ uint8_t voltage_type,
+ uint32_t sclk, uint16_t virtual_voltage_Id,
+ uint16_t *voltage)
+{
+ int result;
+ GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
+
+ get_voltage_info_param_space.ucVoltageType =
+ voltage_type;
+ get_voltage_info_param_space.ucVoltageMode =
+ ATOM_GET_VOLTAGE_EVV_VOLTAGE;
+ get_voltage_info_param_space.usVoltageLevel =
+ virtual_voltage_Id;
+ get_voltage_info_param_space.ulSCLKFreq =
+ sclk;
+
+ result = cgs_atom_exec_cmd_table(hwmgr->device,
+ GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
+ &get_voltage_info_param_space);
+
+ if (0 != result)
+ return result;
+
+ *voltage = ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
+ (&get_voltage_info_param_space))->usVoltageLevel;
+
+ return result;
+}
+
+/**
+ * Get the mpll reference clock in 10KHz
+ */
+uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr)
+{
+ ATOM_COMMON_TABLE_HEADER *fw_info;
+ uint32_t clock;
+ u8 frev, crev;
+ u16 size;
+
+ fw_info = (ATOM_COMMON_TABLE_HEADER *)
+ cgs_atom_get_data_table(hwmgr->device,
+ GetIndexIntoMasterTable(DATA, FirmwareInfo),
+ &size, &frev, &crev);
+
+ if (fw_info == NULL)
+ clock = 2700;
+ else {
+ if ((fw_info->ucTableFormatRevision == 2) &&
+ (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) {
+ ATOM_FIRMWARE_INFO_V2_1 *fwInfo_2_1 =
+ (ATOM_FIRMWARE_INFO_V2_1 *)fw_info;
+ clock = (uint32_t)(le16_to_cpu(fwInfo_2_1->usMemoryReferenceClock));
+ } else {
+ ATOM_FIRMWARE_INFO *fwInfo_0_0 =
+ (ATOM_FIRMWARE_INFO *)fw_info;
+ clock = (uint32_t)(le16_to_cpu(fwInfo_0_0->usReferenceClock));
+ }
+ }
+
+ return clock;
+}
+
+/**
+ * Get the asic internal spread spectrum table
+ */
+static ATOM_ASIC_INTERNAL_SS_INFO *asic_internal_ss_get_ss_table(void *device)
+{
+ ATOM_ASIC_INTERNAL_SS_INFO *table = NULL;
+ u8 frev, crev;
+ u16 size;
+
+ table = (ATOM_ASIC_INTERNAL_SS_INFO *)
+ cgs_atom_get_data_table(device,
+ GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info),
+ &size, &frev, &crev);
+
+ return table;
+}
+
+/**
+ * Get the asic internal spread spectrum assignment
+ */
+static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr *hwmgr,
+ const uint8_t clockSource,
+ const uint32_t clockSpeed,
+ pp_atomctrl_internal_ss_info *ssEntry)
+{
+ ATOM_ASIC_INTERNAL_SS_INFO *table;
+ ATOM_ASIC_SS_ASSIGNMENT *ssInfo;
+ int entry_found = 0;
+
+ memset(ssEntry, 0x00, sizeof(pp_atomctrl_internal_ss_info));
+
+ table = asic_internal_ss_get_ss_table(hwmgr->device);
+
+ if (NULL == table)
+ return -1;
+
+ ssInfo = &table->asSpreadSpectrum[0];
+
+ while (((uint8_t *)ssInfo - (uint8_t *)table) <
+ le16_to_cpu(table->sHeader.usStructureSize)) {
+ if ((clockSource == ssInfo->ucClockIndication) &&
+ ((uint32_t)clockSpeed <= le32_to_cpu(ssInfo->ulTargetClockRange))) {
+ entry_found = 1;
+ break;
+ }
+
+ ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo +
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT));
+ }
+
+ if (entry_found) {
+ ssEntry->speed_spectrum_percentage =
+ ssInfo->usSpreadSpectrumPercentage;
+ ssEntry->speed_spectrum_rate = ssInfo->usSpreadRateInKhz;
+
+ if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) &&
+ (GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) ||
+ (GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) {
+ ssEntry->speed_spectrum_rate /= 100;
+ }
+
+ switch (ssInfo->ucSpreadSpectrumMode) {
+ case 0:
+ ssEntry->speed_spectrum_mode =
+ pp_atomctrl_spread_spectrum_mode_down;
+ break;
+ case 1:
+ ssEntry->speed_spectrum_mode =
+ pp_atomctrl_spread_spectrum_mode_center;
+ break;
+ default:
+ ssEntry->speed_spectrum_mode =
+ pp_atomctrl_spread_spectrum_mode_down;
+ break;
+ }
+ }
+
+ return entry_found ? 0 : 1;
+}
+
+/**
+ * Get the memory clock spread spectrum info
+ */
+int atomctrl_get_memory_clock_spread_spectrum(
+ struct pp_hwmgr *hwmgr,
+ const uint32_t memory_clock,
+ pp_atomctrl_internal_ss_info *ssInfo)
+{
+ return asic_internal_ss_get_ss_asignment(hwmgr,
+ ASIC_INTERNAL_MEMORY_SS, memory_clock, ssInfo);
+}
+/**
+ * Get the engine clock spread spectrum info
+ */
+int atomctrl_get_engine_clock_spread_spectrum(
+ struct pp_hwmgr *hwmgr,
+ const uint32_t engine_clock,
+ pp_atomctrl_internal_ss_info *ssInfo)
+{
+ return asic_internal_ss_get_ss_asignment(hwmgr,
+ ASIC_INTERNAL_ENGINE_SS, engine_clock, ssInfo);
+}
+
+int atomctrl_read_efuse(void *device, uint16_t start_index,
+ uint16_t end_index, uint32_t mask, uint32_t *efuse)
+{
+ int result;
+ READ_EFUSE_VALUE_PARAMETER efuse_param;
+
+ efuse_param.sEfuse.usEfuseIndex = (start_index / 32) * 4;
+ efuse_param.sEfuse.ucBitShift = (uint8_t)
+ (start_index - ((start_index / 32) * 32));
+ efuse_param.sEfuse.ucBitLength = (uint8_t)
+ ((end_index - start_index) + 1);
+
+ result = cgs_atom_exec_cmd_table(device,
+ GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
+ &efuse_param);
+ if (!result)
+ *efuse = efuse_param.ulEfuseValue & mask;
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h
new file mode 100644
index 000000000000..627420b80a5f
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2015 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 PP_ATOMVOLTAGECTRL_H
+#define PP_ATOMVOLTAGECTRL_H
+
+#include "hwmgr.h"
+
+#define MEM_TYPE_GDDR5 0x50
+#define MEM_TYPE_GDDR4 0x40
+#define MEM_TYPE_GDDR3 0x30
+#define MEM_TYPE_DDR2 0x20
+#define MEM_TYPE_GDDR1 0x10
+#define MEM_TYPE_DDR3 0xb0
+#define MEM_TYPE_MASK 0xF0
+
+
+/* As returned from PowerConnectorDetectionTable. */
+#define PP_ATOM_POWER_BUDGET_DISABLE_OVERDRIVE 0x80
+#define PP_ATOM_POWER_BUDGET_SHOW_WARNING 0x40
+#define PP_ATOM_POWER_BUDGET_SHOW_WAIVER 0x20
+#define PP_ATOM_POWER_POWER_BUDGET_BEHAVIOUR 0x0F
+
+/* New functions for Evergreen and beyond. */
+#define PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES 32
+
+struct pp_atomctrl_clock_dividers {
+ uint32_t pll_post_divider;
+ uint32_t pll_feedback_divider;
+ uint32_t pll_ref_divider;
+ bool enable_post_divider;
+};
+
+typedef struct pp_atomctrl_clock_dividers pp_atomctrl_clock_dividers;
+
+union pp_atomctrl_tcipll_fb_divider {
+ struct {
+ uint32_t ul_fb_div_frac : 14;
+ uint32_t ul_fb_div : 12;
+ uint32_t un_used : 6;
+ };
+ uint32_t ul_fb_divider;
+};
+
+typedef union pp_atomctrl_tcipll_fb_divider pp_atomctrl_tcipll_fb_divider;
+
+struct pp_atomctrl_clock_dividers_rv730 {
+ uint32_t pll_post_divider;
+ pp_atomctrl_tcipll_fb_divider mpll_feedback_divider;
+ uint32_t pll_ref_divider;
+ bool enable_post_divider;
+ bool enable_dithen;
+ uint32_t vco_mode;
+};
+typedef struct pp_atomctrl_clock_dividers_rv730 pp_atomctrl_clock_dividers_rv730;
+
+
+struct pp_atomctrl_clock_dividers_kong {
+ uint32_t pll_post_divider;
+ uint32_t real_clock;
+};
+typedef struct pp_atomctrl_clock_dividers_kong pp_atomctrl_clock_dividers_kong;
+
+struct pp_atomctrl_clock_dividers_ci {
+ uint32_t pll_post_divider; /* post divider value */
+ uint32_t real_clock;
+ pp_atomctrl_tcipll_fb_divider ul_fb_div; /* Output Parameter: PLL FB divider */
+ uint8_t uc_pll_ref_div; /* Output Parameter: PLL ref divider */
+ uint8_t uc_pll_post_div; /* Output Parameter: PLL post divider */
+ uint8_t uc_pll_cntl_flag; /*Output Flags: control flag */
+};
+typedef struct pp_atomctrl_clock_dividers_ci pp_atomctrl_clock_dividers_ci;
+
+struct pp_atomctrl_clock_dividers_vi {
+ uint32_t pll_post_divider; /* post divider value */
+ uint32_t real_clock;
+ pp_atomctrl_tcipll_fb_divider ul_fb_div; /*Output Parameter: PLL FB divider */
+ uint8_t uc_pll_ref_div; /*Output Parameter: PLL ref divider */
+ uint8_t uc_pll_post_div; /*Output Parameter: PLL post divider */
+ uint8_t uc_pll_cntl_flag; /*Output Flags: control flag */
+};
+typedef struct pp_atomctrl_clock_dividers_vi pp_atomctrl_clock_dividers_vi;
+
+union pp_atomctrl_s_mpll_fb_divider {
+ struct {
+ uint32_t cl_kf : 12;
+ uint32_t clk_frac : 12;
+ uint32_t un_used : 8;
+ };
+ uint32_t ul_fb_divider;
+};
+typedef union pp_atomctrl_s_mpll_fb_divider pp_atomctrl_s_mpll_fb_divider;
+
+enum pp_atomctrl_spread_spectrum_mode {
+ pp_atomctrl_spread_spectrum_mode_down = 0,
+ pp_atomctrl_spread_spectrum_mode_center
+};
+typedef enum pp_atomctrl_spread_spectrum_mode pp_atomctrl_spread_spectrum_mode;
+
+struct pp_atomctrl_memory_clock_param {
+ pp_atomctrl_s_mpll_fb_divider mpll_fb_divider;
+ uint32_t mpll_post_divider;
+ uint32_t bw_ctrl;
+ uint32_t dll_speed;
+ uint32_t vco_mode;
+ uint32_t yclk_sel;
+ uint32_t qdr;
+ uint32_t half_rate;
+};
+typedef struct pp_atomctrl_memory_clock_param pp_atomctrl_memory_clock_param;
+
+struct pp_atomctrl_internal_ss_info {
+ uint32_t speed_spectrum_percentage; /* in 1/100 percentage */
+ uint32_t speed_spectrum_rate; /* in KHz */
+ pp_atomctrl_spread_spectrum_mode speed_spectrum_mode;
+};
+typedef struct pp_atomctrl_internal_ss_info pp_atomctrl_internal_ss_info;
+
+#ifndef NUMBER_OF_M3ARB_PARAMS
+#define NUMBER_OF_M3ARB_PARAMS 3
+#endif
+
+#ifndef NUMBER_OF_M3ARB_PARAM_SETS
+#define NUMBER_OF_M3ARB_PARAM_SETS 10
+#endif
+
+struct pp_atomctrl_kong_system_info {
+ uint32_t ul_bootup_uma_clock; /* in 10kHz unit */
+ uint16_t us_max_nb_voltage; /* high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
+ uint16_t us_min_nb_voltage; /* low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
+ uint16_t us_bootup_nb_voltage; /* boot up NB voltage */
+ uint8_t uc_htc_tmp_lmt; /* bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD */
+ uint8_t uc_tj_offset; /* bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD */
+ /* 0: default 1: uvd 2: fs-3d */
+ uint32_t ul_csr_m3_srb_cntl[NUMBER_OF_M3ARB_PARAM_SETS][NUMBER_OF_M3ARB_PARAMS];/* arrays with values for CSR M3 arbiter for default */
+};
+typedef struct pp_atomctrl_kong_system_info pp_atomctrl_kong_system_info;
+
+struct pp_atomctrl_memory_info {
+ uint8_t memory_vendor;
+ uint8_t memory_type;
+};
+typedef struct pp_atomctrl_memory_info pp_atomctrl_memory_info;
+
+#define MAX_AC_TIMING_ENTRIES 16
+
+struct pp_atomctrl_memory_clock_range_table {
+ uint8_t num_entries;
+ uint8_t rsv[3];
+
+ uint32_t mclk[MAX_AC_TIMING_ENTRIES];
+};
+typedef struct pp_atomctrl_memory_clock_range_table pp_atomctrl_memory_clock_range_table;
+
+struct pp_atomctrl_voltage_table_entry {
+ uint16_t value;
+ uint32_t smio_low;
+};
+
+typedef struct pp_atomctrl_voltage_table_entry pp_atomctrl_voltage_table_entry;
+
+struct pp_atomctrl_voltage_table {
+ uint32_t count;
+ uint32_t mask_low;
+ uint32_t phase_delay; /* Used for ATOM_GPIO_VOLTAGE_OBJECT_V3 and later */
+ pp_atomctrl_voltage_table_entry entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES];
+};
+
+typedef struct pp_atomctrl_voltage_table pp_atomctrl_voltage_table;
+
+#define VBIOS_MC_REGISTER_ARRAY_SIZE 32
+#define VBIOS_MAX_AC_TIMING_ENTRIES 20
+
+struct pp_atomctrl_mc_reg_entry {
+ uint32_t mclk_max;
+ uint32_t mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct pp_atomctrl_mc_reg_entry pp_atomctrl_mc_reg_entry;
+
+struct pp_atomctrl_mc_register_address {
+ uint16_t s1;
+ uint8_t uc_pre_reg_data;
+};
+
+typedef struct pp_atomctrl_mc_register_address pp_atomctrl_mc_register_address;
+
+struct pp_atomctrl_mc_reg_table {
+ uint8_t last; /* number of registers */
+ uint8_t num_entries; /* number of AC timing entries */
+ pp_atomctrl_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
+ pp_atomctrl_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct pp_atomctrl_mc_reg_table pp_atomctrl_mc_reg_table;
+
+struct pp_atomctrl_gpio_pin_assignment {
+ uint16_t us_gpio_pin_aindex;
+ uint8_t uc_gpio_pin_bit_shift;
+};
+typedef struct pp_atomctrl_gpio_pin_assignment pp_atomctrl_gpio_pin_assignment;
+
+extern bool atomctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pinId, pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment);
+extern int atomctrl_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage);
+extern uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr);
+extern int atomctrl_get_memory_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t memory_clock, pp_atomctrl_internal_ss_info *ssInfo);
+extern int atomctrl_get_engine_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t engine_clock, pp_atomctrl_internal_ss_info *ssInfo);
+extern int atomctrl_initialize_mc_reg_table(struct pp_hwmgr *hwmgr, uint8_t module_index, pp_atomctrl_mc_reg_table *table);
+extern int atomctrl_set_engine_dram_timings_rv770(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint32_t memory_clock);
+extern uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr);
+extern int atomctrl_get_memory_pll_dividers_si(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param, bool strobe_mode);
+extern int atomctrl_get_engine_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
+extern int atomctrl_get_dfs_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
+extern bool atomctrl_is_voltage_controled_by_gpio_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode);
+extern int atomctrl_get_voltage_table_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode, pp_atomctrl_voltage_table *voltage_table);
+extern int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
+ uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param);
+extern int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
+ uint32_t clock_value,
+ pp_atomctrl_clock_dividers_kong *dividers);
+extern int atomctrl_read_efuse(void *device, uint16_t start_index,
+ uint16_t end_index, uint32_t mask, uint32_t *efuse);
+extern int atomctrl_calculate_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
+ uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage, uint16_t dpm_level, bool debug);
+
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h
new file mode 100644
index 000000000000..b7429a527828
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <asm/div64.h>
+
+#define SHIFT_AMOUNT 16 /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */
+
+#define PRECISION 5 /* Change this value to change the number of decimal places in the final output - 5 is a good default */
+
+#define SHIFTED_2 (2 << SHIFT_AMOUNT)
+#define MAX (1 << (SHIFT_AMOUNT - 1)) - 1 /* 32767 - Might change in the future */
+
+/* -------------------------------------------------------------------------------
+ * NEW TYPE - fINT
+ * -------------------------------------------------------------------------------
+ * A variable of type fInt can be accessed in 3 ways using the dot (.) operator
+ * fInt A;
+ * A.full => The full number as it is. Generally not easy to read
+ * A.partial.real => Only the integer portion
+ * A.partial.decimal => Only the fractional portion
+ */
+typedef union _fInt {
+ int full;
+ struct _partial {
+ unsigned int decimal: SHIFT_AMOUNT; /*Needs to always be unsigned*/
+ int real: 32 - SHIFT_AMOUNT;
+ } partial;
+} fInt;
+
+/* -------------------------------------------------------------------------------
+ * Function Declarations
+ * -------------------------------------------------------------------------------
+ */
+fInt ConvertToFraction(int); /* Use this to convert an INT to a FINT */
+fInt Convert_ULONG_ToFraction(uint32_t); /* Use this to convert an uint32_t to a FINT */
+fInt GetScaledFraction(int, int); /* Use this to convert an INT to a FINT after scaling it by a factor */
+int ConvertBackToInteger(fInt); /* Convert a FINT back to an INT that is scaled by 1000 (i.e. last 3 digits are the decimal digits) */
+
+fInt fNegate(fInt); /* Returns -1 * input fInt value */
+fInt fAdd (fInt, fInt); /* Returns the sum of two fInt numbers */
+fInt fSubtract (fInt A, fInt B); /* Returns A-B - Sometimes easier than Adding negative numbers */
+fInt fMultiply (fInt, fInt); /* Returns the product of two fInt numbers */
+fInt fDivide (fInt A, fInt B); /* Returns A/B */
+fInt fGetSquare(fInt); /* Returns the square of a fInt number */
+fInt fSqrt(fInt); /* Returns the Square Root of a fInt number */
+
+int uAbs(int); /* Returns the Absolute value of the Int */
+fInt fAbs(fInt); /* Returns the Absolute value of the fInt */
+int uPow(int base, int exponent); /* Returns base^exponent an INT */
+
+void SolveQuadracticEqn(fInt, fInt, fInt, fInt[]); /* Returns the 2 roots via the array */
+bool Equal(fInt, fInt); /* Returns true if two fInts are equal to each other */
+bool GreaterThan(fInt A, fInt B); /* Returns true if A > B */
+
+fInt fExponential(fInt exponent); /* Can be used to calculate e^exponent */
+fInt fNaturalLog(fInt value); /* Can be used to calculate ln(value) */
+
+/* Fuse decoding functions
+ * -------------------------------------------------------------------------------------
+ */
+fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength);
+fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength);
+fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength);
+
+/* Internal Support Functions - Use these ONLY for testing or adding to internal functions
+ * -------------------------------------------------------------------------------------
+ * Some of the following functions take two INTs as their input - This is unsafe for a variety of reasons.
+ */
+fInt Add (int, int); /* Add two INTs and return Sum as FINT */
+fInt Multiply (int, int); /* Multiply two INTs and return Product as FINT */
+fInt Divide (int, int); /* You get the idea... */
+fInt fNegate(fInt);
+
+int uGetScaledDecimal (fInt); /* Internal function */
+int GetReal (fInt A); /* Internal function */
+
+/* Future Additions and Incomplete Functions
+ * -------------------------------------------------------------------------------------
+ */
+int GetRoundedValue(fInt); /* Incomplete function - Useful only when Precision is lacking */
+ /* Let us say we have 2.126 but can only handle 2 decimal points. We could */
+ /* either chop of 6 and keep 2.12 or use this function to get 2.13, which is more accurate */
+
+/* -------------------------------------------------------------------------------------
+ * TROUBLESHOOTING INFORMATION
+ * -------------------------------------------------------------------------------------
+ * 1) ConvertToFraction - InputOutOfRangeException: Only accepts numbers smaller than MAX (default: 32767)
+ * 2) fAdd - OutputOutOfRangeException: Output bigger than MAX (default: 32767)
+ * 3) fMultiply - OutputOutOfRangeException:
+ * 4) fGetSquare - OutputOutOfRangeException:
+ * 5) fDivide - DivideByZeroException
+ * 6) fSqrt - NegativeSquareRootException: Input cannot be a negative number
+ */
+
+/* -------------------------------------------------------------------------------------
+ * START OF CODE
+ * -------------------------------------------------------------------------------------
+ */
+fInt fExponential(fInt exponent) /*Can be used to calculate e^exponent*/
+{
+ uint32_t i;
+ bool bNegated = false;
+
+ fInt fPositiveOne = ConvertToFraction(1);
+ fInt fZERO = ConvertToFraction(0);
+
+ fInt lower_bound = Divide(78, 10000);
+ fInt solution = fPositiveOne; /*Starting off with baseline of 1 */
+ fInt error_term;
+
+ uint32_t k_array[11] = {55452, 27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78};
+ uint32_t expk_array[11] = {2560000, 160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078};
+
+ if (GreaterThan(fZERO, exponent)) {
+ exponent = fNegate(exponent);
+ bNegated = true;
+ }
+
+ while (GreaterThan(exponent, lower_bound)) {
+ for (i = 0; i < 11; i++) {
+ if (GreaterThan(exponent, GetScaledFraction(k_array[i], 10000))) {
+ exponent = fSubtract(exponent, GetScaledFraction(k_array[i], 10000));
+ solution = fMultiply(solution, GetScaledFraction(expk_array[i], 10000));
+ }
+ }
+ }
+
+ error_term = fAdd(fPositiveOne, exponent);
+
+ solution = fMultiply(solution, error_term);
+
+ if (bNegated)
+ solution = fDivide(fPositiveOne, solution);
+
+ return solution;
+}
+
+fInt fNaturalLog(fInt value)
+{
+ uint32_t i;
+ fInt upper_bound = Divide(8, 1000);
+ fInt fNegativeOne = ConvertToFraction(-1);
+ fInt solution = ConvertToFraction(0); /*Starting off with baseline of 0 */
+ fInt error_term;
+
+ uint32_t k_array[10] = {160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078};
+ uint32_t logk_array[10] = {27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78};
+
+ while (GreaterThan(fAdd(value, fNegativeOne), upper_bound)) {
+ for (i = 0; i < 10; i++) {
+ if (GreaterThan(value, GetScaledFraction(k_array[i], 10000))) {
+ value = fDivide(value, GetScaledFraction(k_array[i], 10000));
+ solution = fAdd(solution, GetScaledFraction(logk_array[i], 10000));
+ }
+ }
+ }
+
+ error_term = fAdd(fNegativeOne, value);
+
+ return (fAdd(solution, error_term));
+}
+
+fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength)
+{
+ fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value);
+ fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
+
+ fInt f_decoded_value;
+
+ f_decoded_value = fDivide(f_fuse_value, f_bit_max_value);
+ f_decoded_value = fMultiply(f_decoded_value, f_range);
+ f_decoded_value = fAdd(f_decoded_value, f_min);
+
+ return f_decoded_value;
+}
+
+
+fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength)
+{
+ fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value);
+ fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
+
+ fInt f_CONSTANT_NEG13 = ConvertToFraction(-13);
+ fInt f_CONSTANT1 = ConvertToFraction(1);
+
+ fInt f_decoded_value;
+
+ f_decoded_value = fSubtract(fDivide(f_bit_max_value, f_fuse_value), f_CONSTANT1);
+ f_decoded_value = fNaturalLog(f_decoded_value);
+ f_decoded_value = fMultiply(f_decoded_value, fDivide(f_range, f_CONSTANT_NEG13));
+ f_decoded_value = fAdd(f_decoded_value, f_average);
+
+ return f_decoded_value;
+}
+
+fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength)
+{
+ fInt fLeakage;
+ fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1);
+
+ fLeakage = fMultiply(ln_max_div_min, Convert_ULONG_ToFraction(leakageID_fuse));
+ fLeakage = fDivide(fLeakage, f_bit_max_value);
+ fLeakage = fExponential(fLeakage);
+ fLeakage = fMultiply(fLeakage, f_min);
+
+ return fLeakage;
+}
+
+fInt ConvertToFraction(int X) /*Add all range checking here. Is it possible to make fInt a private declaration? */
+{
+ fInt temp;
+
+ if (X <= MAX)
+ temp.full = (X << SHIFT_AMOUNT);
+ else
+ temp.full = 0;
+
+ return temp;
+}
+
+fInt fNegate(fInt X)
+{
+ fInt CONSTANT_NEGONE = ConvertToFraction(-1);
+ return (fMultiply(X, CONSTANT_NEGONE));
+}
+
+fInt Convert_ULONG_ToFraction(uint32_t X)
+{
+ fInt temp;
+
+ if (X <= MAX)
+ temp.full = (X << SHIFT_AMOUNT);
+ else
+ temp.full = 0;
+
+ return temp;
+}
+
+fInt GetScaledFraction(int X, int factor)
+{
+ int times_shifted, factor_shifted;
+ bool bNEGATED;
+ fInt fValue;
+
+ times_shifted = 0;
+ factor_shifted = 0;
+ bNEGATED = false;
+
+ if (X < 0) {
+ X = -1*X;
+ bNEGATED = true;
+ }
+
+ if (factor < 0) {
+ factor = -1*factor;
+ bNEGATED = !bNEGATED; /*If bNEGATED = true due to X < 0, this will cover the case of negative cancelling negative */
+ }
+
+ if ((X > MAX) || factor > MAX) {
+ if ((X/factor) <= MAX) {
+ while (X > MAX) {
+ X = X >> 1;
+ times_shifted++;
+ }
+
+ while (factor > MAX) {
+ factor = factor >> 1;
+ factor_shifted++;
+ }
+ } else {
+ fValue.full = 0;
+ return fValue;
+ }
+ }
+
+ if (factor == 1)
+ return (ConvertToFraction(X));
+
+ fValue = fDivide(ConvertToFraction(X * uPow(-1, bNEGATED)), ConvertToFraction(factor));
+
+ fValue.full = fValue.full << times_shifted;
+ fValue.full = fValue.full >> factor_shifted;
+
+ return fValue;
+}
+
+/* Addition using two fInts */
+fInt fAdd (fInt X, fInt Y)
+{
+ fInt Sum;
+
+ Sum.full = X.full + Y.full;
+
+ return Sum;
+}
+
+/* Addition using two fInts */
+fInt fSubtract (fInt X, fInt Y)
+{
+ fInt Difference;
+
+ Difference.full = X.full - Y.full;
+
+ return Difference;
+}
+
+bool Equal(fInt A, fInt B)
+{
+ if (A.full == B.full)
+ return true;
+ else
+ return false;
+}
+
+bool GreaterThan(fInt A, fInt B)
+{
+ if (A.full > B.full)
+ return true;
+ else
+ return false;
+}
+
+fInt fMultiply (fInt X, fInt Y) /* Uses 64-bit integers (int64_t) */
+{
+ fInt Product;
+ int64_t tempProduct;
+ bool X_LessThanOne, Y_LessThanOne;
+
+ X_LessThanOne = (X.partial.real == 0 && X.partial.decimal != 0 && X.full >= 0);
+ Y_LessThanOne = (Y.partial.real == 0 && Y.partial.decimal != 0 && Y.full >= 0);
+
+ /*The following is for a very specific common case: Non-zero number with ONLY fractional portion*/
+ /* TEMPORARILY DISABLED - CAN BE USED TO IMPROVE PRECISION
+
+ if (X_LessThanOne && Y_LessThanOne) {
+ Product.full = X.full * Y.full;
+ return Product
+ }*/
+
+ tempProduct = ((int64_t)X.full) * ((int64_t)Y.full); /*Q(16,16)*Q(16,16) = Q(32, 32) - Might become a negative number! */
+ tempProduct = tempProduct >> 16; /*Remove lagging 16 bits - Will lose some precision from decimal; */
+ Product.full = (int)tempProduct; /*The int64_t will lose the leading 16 bits that were part of the integer portion */
+
+ return Product;
+}
+
+fInt fDivide (fInt X, fInt Y)
+{
+ fInt fZERO, fQuotient;
+ int64_t longlongX, longlongY;
+
+ fZERO = ConvertToFraction(0);
+
+ if (Equal(Y, fZERO))
+ return fZERO;
+
+ longlongX = (int64_t)X.full;
+ longlongY = (int64_t)Y.full;
+
+ longlongX = longlongX << 16; /*Q(16,16) -> Q(32,32) */
+
+ div64_s64(longlongX, longlongY); /*Q(32,32) divided by Q(16,16) = Q(16,16) Back to original format */
+
+ fQuotient.full = (int)longlongX;
+ return fQuotient;
+}
+
+int ConvertBackToInteger (fInt A) /*THIS is the function that will be used to check with the Golden settings table*/
+{
+ fInt fullNumber, scaledDecimal, scaledReal;
+
+ scaledReal.full = GetReal(A) * uPow(10, PRECISION-1); /* DOUBLE CHECK THISSSS!!! */
+
+ scaledDecimal.full = uGetScaledDecimal(A);
+
+ fullNumber = fAdd(scaledDecimal,scaledReal);
+
+ return fullNumber.full;
+}
+
+fInt fGetSquare(fInt A)
+{
+ return fMultiply(A,A);
+}
+
+/* x_new = x_old - (x_old^2 - C) / (2 * x_old) */
+fInt fSqrt(fInt num)
+{
+ fInt F_divide_Fprime, Fprime;
+ fInt test;
+ fInt twoShifted;
+ int seed, counter, error;
+ fInt x_new, x_old, C, y;
+
+ fInt fZERO = ConvertToFraction(0);
+
+ /* (0 > num) is the same as (num < 0), i.e., num is negative */
+
+ if (GreaterThan(fZERO, num) || Equal(fZERO, num))
+ return fZERO;
+
+ C = num;
+
+ if (num.partial.real > 3000)
+ seed = 60;
+ else if (num.partial.real > 1000)
+ seed = 30;
+ else if (num.partial.real > 100)
+ seed = 10;
+ else
+ seed = 2;
+
+ counter = 0;
+
+ if (Equal(num, fZERO)) /*Square Root of Zero is zero */
+ return fZERO;
+
+ twoShifted = ConvertToFraction(2);
+ x_new = ConvertToFraction(seed);
+
+ do {
+ counter++;
+
+ x_old.full = x_new.full;
+
+ test = fGetSquare(x_old); /*1.75*1.75 is reverting back to 1 when shifted down */
+ y = fSubtract(test, C); /*y = f(x) = x^2 - C; */
+
+ Fprime = fMultiply(twoShifted, x_old);
+ F_divide_Fprime = fDivide(y, Fprime);
+
+ x_new = fSubtract(x_old, F_divide_Fprime);
+
+ error = ConvertBackToInteger(x_new) - ConvertBackToInteger(x_old);
+
+ if (counter > 20) /*20 is already way too many iterations. If we dont have an answer by then, we never will*/
+ return x_new;
+
+ } while (uAbs(error) > 0);
+
+ return (x_new);
+}
+
+void SolveQuadracticEqn(fInt A, fInt B, fInt C, fInt Roots[])
+{
+ fInt *pRoots = &Roots[0];
+ fInt temp, root_first, root_second;
+ fInt f_CONSTANT10, f_CONSTANT100;
+
+ f_CONSTANT100 = ConvertToFraction(100);
+ f_CONSTANT10 = ConvertToFraction(10);
+
+ while(GreaterThan(A, f_CONSTANT100) || GreaterThan(B, f_CONSTANT100) || GreaterThan(C, f_CONSTANT100)) {
+ A = fDivide(A, f_CONSTANT10);
+ B = fDivide(B, f_CONSTANT10);
+ C = fDivide(C, f_CONSTANT10);
+ }
+
+ temp = fMultiply(ConvertToFraction(4), A); /* root = 4*A */
+ temp = fMultiply(temp, C); /* root = 4*A*C */
+ temp = fSubtract(fGetSquare(B), temp); /* root = b^2 - 4AC */
+ temp = fSqrt(temp); /*root = Sqrt (b^2 - 4AC); */
+
+ root_first = fSubtract(fNegate(B), temp); /* b - Sqrt(b^2 - 4AC) */
+ root_second = fAdd(fNegate(B), temp); /* b + Sqrt(b^2 - 4AC) */
+
+ root_first = fDivide(root_first, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */
+ root_first = fDivide(root_first, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */
+
+ root_second = fDivide(root_second, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */
+ root_second = fDivide(root_second, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */
+
+ *(pRoots + 0) = root_first;
+ *(pRoots + 1) = root_second;
+}
+
+/* -----------------------------------------------------------------------------
+ * SUPPORT FUNCTIONS
+ * -----------------------------------------------------------------------------
+ */
+
+/* Addition using two normal ints - Temporary - Use only for testing purposes?. */
+fInt Add (int X, int Y)
+{
+ fInt A, B, Sum;
+
+ A.full = (X << SHIFT_AMOUNT);
+ B.full = (Y << SHIFT_AMOUNT);
+
+ Sum.full = A.full + B.full;
+
+ return Sum;
+}
+
+/* Conversion Functions */
+int GetReal (fInt A)
+{
+ return (A.full >> SHIFT_AMOUNT);
+}
+
+/* Temporarily Disabled */
+int GetRoundedValue(fInt A) /*For now, round the 3rd decimal place */
+{
+ /* ROUNDING TEMPORARLY DISABLED
+ int temp = A.full;
+ int decimal_cutoff, decimal_mask = 0x000001FF;
+ decimal_cutoff = temp & decimal_mask;
+ if (decimal_cutoff > 0x147) {
+ temp += 673;
+ }*/
+
+ return ConvertBackToInteger(A)/10000; /*Temporary - in case this was used somewhere else */
+}
+
+fInt Multiply (int X, int Y)
+{
+ fInt A, B, Product;
+
+ A.full = X << SHIFT_AMOUNT;
+ B.full = Y << SHIFT_AMOUNT;
+
+ Product = fMultiply(A, B);
+
+ return Product;
+}
+
+fInt Divide (int X, int Y)
+{
+ fInt A, B, Quotient;
+
+ A.full = X << SHIFT_AMOUNT;
+ B.full = Y << SHIFT_AMOUNT;
+
+ Quotient = fDivide(A, B);
+
+ return Quotient;
+}
+
+int uGetScaledDecimal (fInt A) /*Converts the fractional portion to whole integers - Costly function */
+{
+ int dec[PRECISION];
+ int i, scaledDecimal = 0, tmp = A.partial.decimal;
+
+ for (i = 0; i < PRECISION; i++) {
+ dec[i] = tmp / (1 << SHIFT_AMOUNT);
+ tmp = tmp - ((1 << SHIFT_AMOUNT)*dec[i]);
+ tmp *= 10;
+ scaledDecimal = scaledDecimal + dec[i]*uPow(10, PRECISION - 1 -i);
+ }
+
+ return scaledDecimal;
+}
+
+int uPow(int base, int power)
+{
+ if (power == 0)
+ return 1;
+ else
+ return (base)*uPow(base, power - 1);
+}
+
+fInt fAbs(fInt A)
+{
+ if (A.partial.real < 0)
+ return (fMultiply(A, ConvertToFraction(-1)));
+ else
+ return A;
+}
+
+int uAbs(int X)
+{
+ if (X < 0)
+ return (X * -1);
+ else
+ return X;
+}
+
+fInt fRoundUpByStepSize(fInt A, fInt fStepSize, bool error_term)
+{
+ fInt solution;
+
+ solution = fDivide(A, fStepSize);
+ solution.partial.decimal = 0; /*All fractional digits changes to 0 */
+
+ if (error_term)
+ solution.partial.real += 1; /*Error term of 1 added */
+
+ solution = fMultiply(solution, fStepSize);
+ solution = fAdd(solution, fStepSize);
+
+ return solution;
+}
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c
new file mode 100644
index 000000000000..186496a34cbe
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+#include "atom-types.h"
+#include "atombios.h"
+#include "pppcielanes.h"
+
+/** \file
+ * Functions related to PCIe lane changes.
+ */
+
+/* For converting from number of lanes to lane bits. */
+static const unsigned char pp_r600_encode_lanes[] = {
+ 0, /* 0 Not Supported */
+ 1, /* 1 Lane */
+ 2, /* 2 Lanes */
+ 0, /* 3 Not Supported */
+ 3, /* 4 Lanes */
+ 0, /* 5 Not Supported */
+ 0, /* 6 Not Supported */
+ 0, /* 7 Not Supported */
+ 4, /* 8 Lanes */
+ 0, /* 9 Not Supported */
+ 0, /* 10 Not Supported */
+ 0, /* 11 Not Supported */
+ 5, /* 12 Lanes (Not actually supported) */
+ 0, /* 13 Not Supported */
+ 0, /* 14 Not Supported */
+ 0, /* 15 Not Supported */
+ 6 /* 16 Lanes */
+};
+
+static const unsigned char pp_r600_decoded_lanes[8] = { 16, 1, 2, 4, 8, 12, 16, };
+
+uint8_t encode_pcie_lane_width(uint32_t num_lanes)
+{
+ return pp_r600_encode_lanes[num_lanes];
+}
+
+uint8_t decode_pcie_lane_width(uint32_t num_lanes)
+{
+ return pp_r600_decoded_lanes[num_lanes];
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h b/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h
new file mode 100644
index 000000000000..70b163b35570
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 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 PP_PCIELANES_H
+#define PP_PCIELANES_H
+
+extern uint8_t encode_pcie_lane_width(uint32_t num_lanes);
+extern uint8_t decode_pcie_lane_width(uint32_t num_lanes);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
new file mode 100644
index 000000000000..2f1a14fe05b1
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
@@ -0,0 +1,1688 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "processpptables.h"
+#include <atom-types.h>
+#include <atombios.h>
+#include "pp_debug.h"
+#include "pptable.h"
+#include "power_state.h"
+#include "hwmgr.h"
+#include "hardwaremanager.h"
+
+
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
+#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
+
+#define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
+
+static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t vce_table_offset = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+
+ if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
+ (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table3) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+ if (le16_to_cpu(extended_header->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
+ vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
+ }
+ }
+
+ return vce_table_offset;
+}
+
+static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_vce_table_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0)
+ return table_offset + 1;
+
+ return 0;
+}
+
+static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
+ powerplay_table);
+ uint16_t table_size = 0;
+
+ if (table_offset > 0) {
+ const VCEClockInfoArray *p = (const VCEClockInfoArray *)
+ (((unsigned long) powerplay_table) + table_offset);
+ table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
+ }
+
+ return table_size;
+}
+
+static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0)
+ return table_offset + get_vce_clock_info_array_size(hwmgr,
+ powerplay_table);
+
+ return 0;
+}
+
+static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+ uint16_t table_size = 0;
+
+ if (table_offset > 0) {
+ const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
+ (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
+
+ table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
+ }
+ return table_size;
+}
+
+static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+
+ if (table_offset > 0)
+ return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
+
+ return 0;
+}
+
+static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
+
+ if (table_offset > 0)
+ return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
+
+ return NULL;
+}
+
+static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t uvd_table_offset = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+ if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
+ (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table3) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+ if (le16_to_cpu(extended_header->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
+ uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
+ }
+ }
+ return uvd_table_offset;
+}
+
+static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_uvd_table_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0)
+ return table_offset + 1;
+ return 0;
+}
+
+static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
+ powerplay_table);
+ uint16_t table_size = 0;
+
+ if (table_offset > 0) {
+ const UVDClockInfoArray *p = (const UVDClockInfoArray *)
+ (((unsigned long) powerplay_table)
+ + table_offset);
+ table_size = sizeof(UCHAR) +
+ p->ucNumEntries * sizeof(UVDClockInfo);
+ }
+
+ return table_size;
+}
+
+static uint16_t get_uvd_clock_voltage_limit_table_offset(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0)
+ return table_offset +
+ get_uvd_clock_info_array_size(hwmgr, powerplay_table);
+
+ return 0;
+}
+
+static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t samu_table_offset = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+ if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
+ (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table3) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+ if (le16_to_cpu(extended_header->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
+ samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
+ }
+ }
+
+ return samu_table_offset;
+}
+
+static uint16_t get_samu_clock_voltage_limit_table_offset(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t table_offset = get_samu_table_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0)
+ return table_offset + 1;
+
+ return 0;
+}
+
+static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t acp_table_offset = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+ if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+ const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
+ (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table3) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+ if (le16_to_cpu(pExtendedHeader->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
+ acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
+ }
+ }
+
+ return acp_table_offset;
+}
+
+static uint16_t get_acp_clock_voltage_limit_table_offset(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table);
+
+ if (tableOffset > 0)
+ return tableOffset + 1;
+
+ return 0;
+}
+
+static uint16_t get_cacp_tdp_table_offset(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t cacTdpTableOffset = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+ if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+ const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
+ (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table3) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+ if (le16_to_cpu(pExtendedHeader->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
+ cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
+ }
+ }
+
+ return cacTdpTableOffset;
+}
+
+static int get_cac_tdp_table(struct pp_hwmgr *hwmgr,
+ struct phm_cac_tdp_table **ptable,
+ const ATOM_PowerTune_Table *table,
+ uint16_t us_maximum_power_delivery_limit)
+{
+ unsigned long table_size;
+ struct phm_cac_tdp_table *tdp_table;
+
+ table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table);
+
+ tdp_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == tdp_table)
+ return -ENOMEM;
+
+ tdp_table->usTDP = le16_to_cpu(table->usTDP);
+ tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP);
+ tdp_table->usTDC = le16_to_cpu(table->usTDC);
+ tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit);
+ tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit);
+ tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage);
+ tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage);
+ tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit;
+
+ *ptable = tdp_table;
+
+ return 0;
+}
+
+static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t sclk_vdd_gfx_table_offset = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+ if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+ const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
+ (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table3) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+ if (le16_to_cpu(pExtendedHeader->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
+ sclk_vdd_gfx_table_offset =
+ le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
+ }
+ }
+
+ return sclk_vdd_gfx_table_offset;
+}
+
+static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table);
+
+ if (tableOffset > 0)
+ return tableOffset;
+
+ return 0;
+}
+
+
+static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
+ struct phm_clock_voltage_dependency_table **ptable,
+ const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table)
+{
+
+ unsigned long table_size, i;
+ struct phm_clock_voltage_dependency_table *dep_table;
+
+ table_size = sizeof(unsigned long) +
+ sizeof(struct phm_clock_voltage_dependency_table)
+ * table->ucNumEntries;
+
+ dep_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == dep_table)
+ return -ENOMEM;
+
+ dep_table->count = (unsigned long)table->ucNumEntries;
+
+ for (i = 0; i < dep_table->count; i++) {
+ dep_table->entries[i].clk =
+ ((unsigned long)table->entries[i].ucClockHigh << 16) |
+ le16_to_cpu(table->entries[i].usClockLow);
+ dep_table->entries[i].v =
+ (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+ }
+
+ *ptable = dep_table;
+
+ return 0;
+}
+
+static int get_valid_clk(struct pp_hwmgr *hwmgr,
+ struct phm_clock_array **ptable,
+ const struct phm_clock_voltage_dependency_table *table)
+{
+ unsigned long table_size, i;
+ struct phm_clock_array *clock_table;
+
+ table_size = sizeof(unsigned long) + sizeof(unsigned long) * table->count;
+ clock_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == clock_table)
+ return -ENOMEM;
+
+ clock_table->count = (unsigned long)table->count;
+
+ for (i = 0; i < clock_table->count; i++)
+ clock_table->values[i] = (unsigned long)table->entries[i].clk;
+
+ *ptable = clock_table;
+
+ return 0;
+}
+
+static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
+ struct phm_clock_and_voltage_limits *limits,
+ const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
+{
+ limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
+ le16_to_cpu(table->entries[0].usSclkLow);
+ limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) |
+ le16_to_cpu(table->entries[0].usMclkLow);
+ limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc);
+ limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci);
+
+ return 0;
+}
+
+
+static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
+ enum phm_platform_caps cap)
+{
+ if (enable)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
+ else
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
+}
+
+static int set_platform_caps(struct pp_hwmgr *hwmgr,
+ unsigned long powerplay_caps)
+{
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY),
+ PHM_PlatformCaps_PowerPlaySupport
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
+ PHM_PlatformCaps_BiosPowerSourceControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s),
+ PHM_PlatformCaps_EnableASPML0s
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1),
+ PHM_PlatformCaps_EnableASPML1
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS),
+ PHM_PlatformCaps_EnableBackbias
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC),
+ PHM_PlatformCaps_AutomaticDCTransition
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY),
+ PHM_PlatformCaps_GeminiPrimary
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC),
+ PHM_PlatformCaps_StepVddc
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL),
+ PHM_PlatformCaps_EnableVoltageControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL),
+ PHM_PlatformCaps_EnableSideportControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1),
+ PHM_PlatformCaps_TurnOffPll_ASPML1
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL),
+ PHM_PlatformCaps_EnableHTLinkControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL),
+ PHM_PlatformCaps_EnableMVDDControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL),
+ PHM_PlatformCaps_ControlVDDCI
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT),
+ PHM_PlatformCaps_RegulatorHot
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT),
+ PHM_PlatformCaps_BootStateOnAlert
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT),
+ PHM_PlatformCaps_DontWaitForVBlankOnAlert
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO),
+ PHM_PlatformCaps_BACO
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE),
+ PHM_PlatformCaps_NewCACVoltage
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY),
+ PHM_PlatformCaps_RevertGPIO5Polarity
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17),
+ PHM_PlatformCaps_Thermal2GPIO17
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE),
+ PHM_PlatformCaps_VRHotGPIOConfigurable
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION),
+ PHM_PlatformCaps_TempInversion
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV),
+ PHM_PlatformCaps_EVV
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
+ PHM_PlatformCaps_CombinePCCWithThermalSignal
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
+ PHM_PlatformCaps_LoadPostProductionFirmware
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC),
+ PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc
+ );
+
+ return 0;
+}
+
+static PP_StateClassificationFlags make_classification_flags(
+ struct pp_hwmgr *hwmgr,
+ USHORT classification,
+ USHORT classification2)
+{
+ PP_StateClassificationFlags result = 0;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ result |= PP_StateClassificationFlag_Boot;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+ result |= PP_StateClassificationFlag_Thermal;
+
+ if (classification &
+ ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+ result |= PP_StateClassificationFlag_LimitedPowerSource;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
+ result |= PP_StateClassificationFlag_Rest;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
+ result |= PP_StateClassificationFlag_Forced;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+ result |= PP_StateClassificationFlag_3DPerformance;
+
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
+ result |= PP_StateClassificationFlag_ACOverdriveTemplate;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ result |= PP_StateClassificationFlag_Uvd;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+ result |= PP_StateClassificationFlag_UvdHD;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+ result |= PP_StateClassificationFlag_UvdSD;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+ result |= PP_StateClassificationFlag_HD2;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
+ result |= PP_StateClassificationFlag_ACPI;
+
+ if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+ result |= PP_StateClassificationFlag_LimitedPowerSource_2;
+
+
+ if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
+ result |= PP_StateClassificationFlag_ULV;
+
+ if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+ result |= PP_StateClassificationFlag_UvdMVC;
+
+ return result;
+}
+
+static int init_non_clock_fields(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *ps,
+ uint8_t version,
+ const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) {
+ unsigned long rrr_index;
+ unsigned long tmp;
+
+ ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) &
+ ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+ ps->classification.flags = make_classification_flags(hwmgr,
+ le16_to_cpu(pnon_clock_info->usClassification),
+ le16_to_cpu(pnon_clock_info->usClassification2));
+
+ ps->classification.temporary_state = false;
+ ps->classification.to_be_deleted = false;
+ tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_SINGLE_DISPLAY_ONLY;
+
+ ps->validation.singleDisplayOnly = (0 != tmp);
+
+ tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_DISALLOW_ON_DC;
+
+ ps->validation.disallowOnDC = (0 != tmp);
+
+ ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
+ ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
+
+ ps->pcie.lanes = 0;
+
+ ps->display.disableFrameModulation = false;
+
+ rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
+ ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
+
+ if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
+ static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
+ { 0, 50, 0 };
+
+ ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
+ ps->display.explicitRefreshrate = look_up[rrr_index];
+ ps->display.limitRefreshrate = true;
+
+ if (ps->display.explicitRefreshrate == 0)
+ ps->display.limitRefreshrate = false;
+ } else
+ ps->display.limitRefreshrate = false;
+
+ tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_ENABLE_VARIBRIGHT;
+
+ ps->display.enableVariBright = (0 != tmp);
+
+ tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
+
+ ps->memory.dllOff = (0 != tmp);
+
+ ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
+
+ ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
+ pnon_clock_info->ucMinTemperature;
+
+ ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
+ pnon_clock_info->ucMaxTemperature;
+
+ tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
+
+ ps->software.disableLoadBalancing = tmp;
+
+ tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
+ ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
+
+ ps->software.enableSleepForTimestamps = (0 != tmp);
+
+ ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
+
+ if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
+ ps->uvd_clocks.VCLK = pnon_clock_info->ulVCLK;
+ ps->uvd_clocks.DCLK = pnon_clock_info->ulDCLK;
+ } else {
+ ps->uvd_clocks.VCLK = 0;
+ ps->uvd_clocks.DCLK = 0;
+ }
+
+ return 0;
+}
+
+static ULONG size_of_entry_v2(ULONG num_dpm_levels)
+{
+ return (sizeof(UCHAR) + sizeof(UCHAR) +
+ (num_dpm_levels * sizeof(UCHAR)));
+}
+
+static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
+ const StateArray * pstate_arrays,
+ ULONG entry_index)
+{
+ ULONG i;
+ const ATOM_PPLIB_STATE_V2 *pstate;
+
+ pstate = pstate_arrays->states;
+ if (entry_index <= pstate_arrays->ucNumEntries) {
+ for (i = 0; i < entry_index; i++)
+ pstate = (ATOM_PPLIB_STATE_V2 *)(
+ (unsigned long)pstate +
+ size_of_entry_v2(pstate->ucNumDPMLevels));
+ }
+ return pstate;
+}
+
+
+static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
+ struct pp_hwmgr *hwmgr)
+{
+ const void *table_addr = NULL;
+ uint8_t frev, crev;
+ uint16_t size;
+
+ table_addr = cgs_atom_get_data_table(hwmgr->device,
+ GetIndexIntoMasterTable(DATA, PowerPlayInfo),
+ &size, &frev, &crev);
+
+ hwmgr->soft_pp_table = table_addr;
+
+ return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
+}
+
+
+int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
+ unsigned long *num_of_entries)
+{
+ const StateArray *pstate_arrays;
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+
+ if (powerplay_table == NULL)
+ return -1;
+
+ if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
+ pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+ *num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
+ } else
+ *num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
+
+ return 0;
+}
+
+int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
+ unsigned long entry_index,
+ struct pp_power_state *ps,
+ pp_tables_hw_clock_info_callback func)
+{
+ int i;
+ const StateArray *pstate_arrays;
+ const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
+ const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+ int result = 0;
+ int res = 0;
+
+ const ClockInfoArray *pclock_arrays;
+
+ const NonClockInfoArray *pnon_clock_arrays;
+
+ const ATOM_PPLIB_STATE *pstate_entry;
+
+ if (powerplay_table == NULL)
+ return -1;
+
+ ps->classification.bios_index = entry_index;
+
+ if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
+ pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+ if (entry_index > pstate_arrays->ucNumEntries)
+ return -1;
+
+ pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
+ pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
+
+ pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
+
+ pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
+ (pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
+
+ result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
+
+ for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
+ const void *pclock_info = (const void *)(
+ (unsigned long)(pclock_arrays->clockInfo) +
+ (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
+ res = func(hwmgr, &ps->hardware, i, pclock_info);
+ if ((0 == result) && (0 != res))
+ result = res;
+ }
+ } else {
+ if (entry_index > powerplay_table->ucNumStates)
+ return -1;
+
+ pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table + powerplay_table->usStateArrayOffset +
+ entry_index * powerplay_table->ucStateEntrySize);
+
+ pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
+ le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
+ pstate_entry->ucNonClockStateIndex *
+ powerplay_table->ucNonClockSize);
+
+ result = init_non_clock_fields(hwmgr, ps,
+ powerplay_table->ucNonClockSize,
+ pnon_clock_info);
+
+ for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
+ const void *pclock_info = (const void *)((unsigned long)powerplay_table +
+ le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
+ pstate_entry->ucClockStateIndices[i] *
+ powerplay_table->ucClockInfoSize);
+
+ int res = func(hwmgr, &ps->hardware, i, pclock_info);
+
+ if ((0 == result) && (0 != res))
+ result = res;
+ }
+ }
+
+ if ((0 == result) &&
+ (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot)))
+ result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
+
+ return result;
+}
+
+
+
+static int init_powerplay_tables(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
+)
+{
+ return 0;
+}
+
+
+static int init_thermal_controller(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ return 0;
+}
+
+static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
+ const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
+{
+ hwmgr->platform_descriptor.overdriveLimit.engineClock =
+ le32_to_cpu(fw_info->ulASICMaxEngineClock);
+
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock =
+ le32_to_cpu(fw_info->ulASICMaxMemoryClock);
+
+ hwmgr->platform_descriptor.maxOverdriveVDDC =
+ le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
+
+ hwmgr->platform_descriptor.minOverdriveVDDC =
+ le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+
+ hwmgr->platform_descriptor.maxOverdriveVDDC =
+ le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+
+ hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+ return 0;
+}
+
+static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
+ const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
+{
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
+ const ATOM_PPLIB_EXTENDEDHEADER *header;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) <
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
+ return 0;
+
+ powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+
+ if (0 == powerplay_table3->usExtendendedHeaderOffset)
+ return 0;
+
+ header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
+
+ hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
+
+
+ hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+ hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+ hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+
+ return 0;
+}
+
+static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ int result;
+ uint8_t frev, crev;
+ uint16_t size;
+
+ const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
+
+ hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
+ hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+ hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+
+ /* We assume here that fw_info is unchanged if this call fails.*/
+ fw_info = cgs_atom_get_data_table(hwmgr->device,
+ GetIndexIntoMasterTable(DATA, FirmwareInfo),
+ &size, &frev, &crev);
+
+ if ((fw_info->ucTableFormatRevision == 1)
+ && (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
+ result = init_overdrive_limits_V1_4(hwmgr,
+ powerplay_table,
+ (const ATOM_FIRMWARE_INFO_V1_4 *)fw_info);
+
+ else if ((fw_info->ucTableFormatRevision == 2)
+ && (fw_info->usStructureSize >= sizeof(ATOM_FIRMWARE_INFO_V2_1)))
+ result = init_overdrive_limits_V2_1(hwmgr,
+ powerplay_table,
+ (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
+
+ if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0
+ && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0
+ && !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_OverdriveDisabledByPowerBudget))
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ACOverdriveSupport);
+
+ return result;
+}
+
+static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+ struct phm_uvd_clock_voltage_dependency_table **ptable,
+ const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table,
+ const UVDClockInfoArray *array)
+{
+ unsigned long table_size, i;
+ struct phm_uvd_clock_voltage_dependency_table *uvd_table;
+
+ table_size = sizeof(unsigned long) +
+ sizeof(struct phm_uvd_clock_voltage_dependency_table) *
+ table->numEntries;
+
+ uvd_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == uvd_table)
+ return -ENOMEM;
+
+ uvd_table->count = table->numEntries;
+
+ for (i = 0; i < table->numEntries; i++) {
+ const UVDClockInfo *entry =
+ &array->entries[table->entries[i].ucUVDClockInfoIndex];
+ uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+ uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16)
+ | le16_to_cpu(entry->usVClkLow);
+ uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16)
+ | le16_to_cpu(entry->usDClkLow);
+ }
+
+ *ptable = uvd_table;
+
+ return 0;
+}
+
+static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+ struct phm_vce_clock_voltage_dependency_table **ptable,
+ const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table,
+ const VCEClockInfoArray *array)
+{
+ unsigned long table_size, i;
+ struct phm_vce_clock_voltage_dependency_table *vce_table = NULL;
+
+ table_size = sizeof(unsigned long) +
+ sizeof(struct phm_vce_clock_voltage_dependency_table)
+ * table->numEntries;
+
+ vce_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == vce_table)
+ return -ENOMEM;
+
+ vce_table->count = table->numEntries;
+ for (i = 0; i < table->numEntries; i++) {
+ const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex];
+
+ vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+ vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16)
+ | le16_to_cpu(entry->usEVClkLow);
+ vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16)
+ | le16_to_cpu(entry->usECClkLow);
+ }
+
+ *ptable = vce_table;
+
+ return 0;
+}
+
+static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+ struct phm_samu_clock_voltage_dependency_table **ptable,
+ const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table)
+{
+ unsigned long table_size, i;
+ struct phm_samu_clock_voltage_dependency_table *samu_table;
+
+ table_size = sizeof(unsigned long) +
+ sizeof(struct phm_samu_clock_voltage_dependency_table) *
+ table->numEntries;
+
+ samu_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == samu_table)
+ return -ENOMEM;
+
+ samu_table->count = table->numEntries;
+
+ for (i = 0; i < table->numEntries; i++) {
+ samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+ samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16)
+ | le16_to_cpu(table->entries[i].usSAMClockLow);
+ }
+
+ *ptable = samu_table;
+
+ return 0;
+}
+
+static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
+ struct phm_acp_clock_voltage_dependency_table **ptable,
+ const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table)
+{
+ unsigned table_size, i;
+ struct phm_acp_clock_voltage_dependency_table *acp_table;
+
+ table_size = sizeof(unsigned long) +
+ sizeof(struct phm_acp_clock_voltage_dependency_table) *
+ table->numEntries;
+
+ acp_table = kzalloc(table_size, GFP_KERNEL);
+ if (NULL == acp_table)
+ return -ENOMEM;
+
+ acp_table->count = (unsigned long)table->numEntries;
+
+ for (i = 0; i < table->numEntries; i++) {
+ acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
+ acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16)
+ | le16_to_cpu(table->entries[i].usACPClockLow);
+ }
+
+ *ptable = acp_table;
+
+ return 0;
+}
+
+static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ ATOM_PPLIB_Clock_Voltage_Dependency_Table *table;
+ ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table;
+ int result = 0;
+
+ uint16_t vce_clock_info_array_offset;
+ uint16_t uvd_clock_info_array_offset;
+ uint16_t table_offset;
+
+ hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
+ hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
+ hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+ hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
+ hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
+ hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
+ hwmgr->dyn_state.ppm_parameter_table = NULL;
+ hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
+
+ vce_clock_info_array_offset = get_vce_clock_info_array_offset(
+ hwmgr, powerplay_table);
+ table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr,
+ powerplay_table);
+ if (vce_clock_info_array_offset > 0 && table_offset > 0) {
+ const VCEClockInfoArray *array = (const VCEClockInfoArray *)
+ (((unsigned long) powerplay_table) +
+ vce_clock_info_array_offset);
+ const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table =
+ (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_vce_clock_voltage_limit_table(hwmgr,
+ &hwmgr->dyn_state.vce_clock_voltage_dependency_table,
+ table, array);
+ }
+
+ uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table);
+ table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+
+ if (uvd_clock_info_array_offset > 0 && table_offset > 0) {
+ const UVDClockInfoArray *array = (const UVDClockInfoArray *)
+ (((unsigned long) powerplay_table) +
+ uvd_clock_info_array_offset);
+ const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable =
+ (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_uvd_clock_voltage_limit_table(hwmgr,
+ &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array);
+ }
+
+ table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0) {
+ const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable =
+ (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_samu_clock_voltage_limit_table(hwmgr,
+ &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable);
+ }
+
+ table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0) {
+ const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable =
+ (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_acp_clock_voltage_limit_table(hwmgr,
+ &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable);
+ }
+
+ table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table);
+ if (table_offset > 0) {
+ UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset);
+
+ if (rev_id > 0) {
+ const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table =
+ (const ATOM_PPLIB_POWERTUNE_Table_V1 *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table,
+ &tune_table->power_tune_table,
+ le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit));
+ hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
+ le16_to_cpu(tune_table->usTjMax);
+ } else {
+ const ATOM_PPLIB_POWERTUNE_Table *tune_table =
+ (const ATOM_PPLIB_POWERTUNE_Table *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_cac_tdp_table(hwmgr,
+ &hwmgr->dyn_state.cac_dtp_table,
+ &tune_table->power_tune_table, 255);
+ }
+ }
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
+ const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
+ (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
+ if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) {
+ table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (((unsigned long) powerplay_table4) +
+ powerplay_table4->usVddcDependencyOnSCLKOffset);
+ result = get_clock_voltage_dependency_table(hwmgr,
+ &hwmgr->dyn_state.vddc_dependency_on_sclk, table);
+ }
+
+ if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) {
+ table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (((unsigned long) powerplay_table4) +
+ powerplay_table4->usVddciDependencyOnMCLKOffset);
+ result = get_clock_voltage_dependency_table(hwmgr,
+ &hwmgr->dyn_state.vddci_dependency_on_mclk, table);
+ }
+
+ if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) {
+ table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (((unsigned long) powerplay_table4) +
+ powerplay_table4->usVddcDependencyOnMCLKOffset);
+ result = get_clock_voltage_dependency_table(hwmgr,
+ &hwmgr->dyn_state.vddc_dependency_on_mclk, table);
+ }
+
+ if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) {
+ limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
+ (((unsigned long) powerplay_table4) +
+ powerplay_table4->usMaxClockVoltageOnDCOffset);
+ result = get_clock_voltage_limit(hwmgr,
+ &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table);
+ }
+
+ if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) &&
+ (0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count))
+ result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values,
+ hwmgr->dyn_state.vddc_dependency_on_mclk);
+
+ if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) &&
+ (0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count))
+ result = get_valid_clk(hwmgr,
+ &hwmgr->dyn_state.valid_sclk_values,
+ hwmgr->dyn_state.vddc_dependency_on_sclk);
+
+ if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) {
+ table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (((unsigned long) powerplay_table4) +
+ powerplay_table4->usMvddDependencyOnMCLKOffset);
+ result = get_clock_voltage_dependency_table(hwmgr,
+ &hwmgr->dyn_state.mvdd_dependency_on_mclk, table);
+ }
+ }
+
+ table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr,
+ powerplay_table);
+
+ if (table_offset > 0) {
+ table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (((unsigned long) powerplay_table) + table_offset);
+ result = get_clock_voltage_dependency_table(hwmgr,
+ &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table);
+ }
+
+ return result;
+}
+
+static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
+ struct phm_cac_leakage_table **ptable,
+ const ATOM_PPLIB_CAC_Leakage_Table *table)
+{
+ struct phm_cac_leakage_table *cac_leakage_table;
+ unsigned long table_size, i;
+
+ if (hwmgr == NULL || table == NULL || ptable == NULL)
+ return -EINVAL;
+
+ table_size = sizeof(ULONG) +
+ (sizeof(struct phm_cac_leakage_table) * table->ucNumEntries);
+
+ cac_leakage_table = kzalloc(table_size, GFP_KERNEL);
+
+ if (cac_leakage_table == NULL)
+ return -ENOMEM;
+
+ cac_leakage_table->count = (ULONG)table->ucNumEntries;
+
+ for (i = 0; i < cac_leakage_table->count; i++) {
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EVV)) {
+ cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1);
+ cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2);
+ cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3);
+ } else {
+ cac_leakage_table->entries[i].Vddc = le16_to_cpu(table->entries[i].usVddc);
+ cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue);
+ }
+ }
+
+ *ptable = cac_leakage_table;
+
+ return 0;
+}
+
+static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
+ ATOM_PPLIB_PPM_Table *atom_ppm_table)
+{
+ struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
+
+ if (NULL == ptr)
+ return -ENOMEM;
+
+ ptr->ppm_design = atom_ppm_table->ucPpmDesign;
+ ptr->cpu_core_number = le16_to_cpu(atom_ppm_table->usCpuCoreNumber);
+ ptr->platform_tdp = le32_to_cpu(atom_ppm_table->ulPlatformTDP);
+ ptr->small_ac_platform_tdp = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP);
+ ptr->platform_tdc = le32_to_cpu(atom_ppm_table->ulPlatformTDC);
+ ptr->small_ac_platform_tdc = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC);
+ ptr->apu_tdp = le32_to_cpu(atom_ppm_table->ulApuTDP);
+ ptr->dgpu_tdp = le32_to_cpu(atom_ppm_table->ulDGpuTDP);
+ ptr->dgpu_ulv_power = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower);
+ ptr->tj_max = le32_to_cpu(atom_ppm_table->ulTjmax);
+ hwmgr->dyn_state.ppm_parameter_table = ptr;
+
+ return 0;
+}
+
+static int init_dpm2_parameters(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ int result = 0;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) {
+ const ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 =
+ (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table;
+ const ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 =
+ (const ATOM_PPLIB_POWERPLAYTABLE4 *)
+ (&ptable5->basicTable4);
+ const ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 =
+ (const ATOM_PPLIB_POWERPLAYTABLE3 *)
+ (&ptable4->basicTable3);
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
+ uint16_t table_offset;
+ ATOM_PPLIB_PPM_Table *atom_ppm_table;
+
+ hwmgr->platform_descriptor.TDPLimit = le32_to_cpu(ptable5->ulTDPLimit);
+ hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit);
+
+ hwmgr->platform_descriptor.TDPODLimit = le16_to_cpu(ptable5->usTDPODLimit);
+ hwmgr->platform_descriptor.TDPAdjustment = 0;
+
+ hwmgr->platform_descriptor.VidAdjustment = 0;
+ hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
+ hwmgr->platform_descriptor.VidMinLimit = 0;
+ hwmgr->platform_descriptor.VidMaxLimit = 1500000;
+ hwmgr->platform_descriptor.VidStep = 6250;
+
+ hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit);
+
+ if (hwmgr->platform_descriptor.TDPODLimit != 0)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerControl);
+
+ hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold);
+
+ hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage);
+
+ hwmgr->dyn_state.cac_leakage_table = NULL;
+
+ if (0 != ptable5->usCACLeakageTableOffset) {
+ const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table =
+ (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) +
+ le16_to_cpu(ptable5->usCACLeakageTableOffset));
+ result = get_cac_leakage_table(hwmgr,
+ &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table);
+ }
+
+ hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope);
+
+ hwmgr->dyn_state.ppm_parameter_table = NULL;
+
+ if (0 != ptable3->usExtendendedHeaderOffset) {
+ extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(ptable3->usExtendendedHeaderOffset));
+ if ((extended_header->usPPMTableOffset > 0) &&
+ le16_to_cpu(extended_header->usSize) >=
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) {
+ table_offset = le16_to_cpu(extended_header->usPPMTableOffset);
+ atom_ppm_table = (ATOM_PPLIB_PPM_Table *)
+ (((unsigned long)powerplay_table) + table_offset);
+ if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table))
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnablePlatformPowerManagement);
+ }
+ }
+ }
+ return result;
+}
+
+static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
+{
+ if (le16_to_cpu(powerplay_table->usTableSize) >=
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
+ const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
+ (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
+
+ if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) {
+ const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable =
+ (ATOM_PPLIB_PhaseSheddingLimits_Table *)
+ (((unsigned long)powerplay_table4) +
+ le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset));
+ struct phm_phase_shedding_limits_table *table;
+ unsigned long size, i;
+
+
+ size = sizeof(unsigned long) +
+ (sizeof(struct phm_phase_shedding_limits_table) *
+ ptable->ucNumEntries);
+
+ table = kzalloc(size, GFP_KERNEL);
+
+ if (table == NULL)
+ return -ENOMEM;
+
+ table->count = (unsigned long)ptable->ucNumEntries;
+
+ for (i = 0; i < table->count; i++) {
+ table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage);
+ table->entries[i].Sclk = ((unsigned long)ptable->entries[i].ucSclkHigh << 16)
+ | le16_to_cpu(ptable->entries[i].usSclkLow);
+ table->entries[i].Mclk = ((unsigned long)ptable->entries[i].ucMclkHigh << 16)
+ | le16_to_cpu(ptable->entries[i].usMclkLow);
+ }
+ hwmgr->dyn_state.vddc_phase_shed_limits_table = table;
+ }
+ }
+
+ return 0;
+}
+
+int get_number_of_vce_state_table_entries(
+ struct pp_hwmgr *hwmgr)
+{
+ const ATOM_PPLIB_POWERPLAYTABLE *table =
+ get_powerplay_table(hwmgr);
+ const ATOM_PPLIB_VCE_State_Table *vce_table =
+ get_vce_state_table(hwmgr, table);
+
+ if (vce_table > 0)
+ return vce_table->numEntries;
+
+ return 0;
+}
+
+int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
+ unsigned long i,
+ struct PP_VCEState *vce_state,
+ void **clock_info,
+ unsigned long *flag)
+{
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+
+ const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
+
+ unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
+
+ const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
+
+ const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + powerplay_table->usClockInfoArrayOffset);
+
+ const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
+
+ const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
+
+ unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
+
+ *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
+
+ vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | vce_clock_info->usEVClkLow;
+ vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | vce_clock_info->usECClkLow;
+
+ *clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize));
+
+ return 0;
+}
+
+
+static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table;
+
+ hwmgr->need_pp_table_upload = true;
+
+ powerplay_table = get_powerplay_table(hwmgr);
+
+ result = init_powerplay_tables(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_powerplay_tables failed", return result);
+
+ result = set_platform_caps(hwmgr,
+ le32_to_cpu(powerplay_table->ulPlatformCaps));
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "set_platform_caps failed", return result);
+
+ result = init_thermal_controller(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_thermal_controller failed", return result);
+
+ result = init_overdrive_limits(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_overdrive_limits failed", return result);
+
+ result = init_clock_voltage_dependency(hwmgr,
+ powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_clock_voltage_dependency failed", return result);
+
+ result = init_dpm2_parameters(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_dpm2_parameters failed", return result);
+
+ result = init_phase_shedding_table(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_phase_shedding_table failed", return result);
+
+ return result;
+}
+
+static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
+{
+ if (NULL != hwmgr->soft_pp_table) {
+ kfree(hwmgr->soft_pp_table);
+ hwmgr->soft_pp_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) {
+ kfree(hwmgr->dyn_state.vddc_dependency_on_sclk);
+ hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vddci_dependency_on_mclk) {
+ kfree(hwmgr->dyn_state.vddci_dependency_on_mclk);
+ hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) {
+ kfree(hwmgr->dyn_state.vddc_dependency_on_mclk);
+ hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.mvdd_dependency_on_mclk) {
+ kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk);
+ hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.valid_mclk_values) {
+ kfree(hwmgr->dyn_state.valid_mclk_values);
+ hwmgr->dyn_state.valid_mclk_values = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.valid_sclk_values) {
+ kfree(hwmgr->dyn_state.valid_sclk_values);
+ hwmgr->dyn_state.valid_sclk_values = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.cac_leakage_table) {
+ kfree(hwmgr->dyn_state.cac_leakage_table);
+ hwmgr->dyn_state.cac_leakage_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vddc_phase_shed_limits_table) {
+ kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table);
+ hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vce_clock_voltage_dependency_table) {
+ kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table);
+ hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.uvd_clock_voltage_dependency_table) {
+ kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
+ hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.samu_clock_voltage_dependency_table) {
+ kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table);
+ hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.acp_clock_voltage_dependency_table) {
+ kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table);
+ hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.cac_dtp_table) {
+ kfree(hwmgr->dyn_state.cac_dtp_table);
+ hwmgr->dyn_state.cac_dtp_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.ppm_parameter_table) {
+ kfree(hwmgr->dyn_state.ppm_parameter_table);
+ hwmgr->dyn_state.ppm_parameter_table = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vdd_gfx_dependency_on_sclk) {
+ kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk);
+ hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
+ }
+
+ if (NULL != hwmgr->dyn_state.vq_budgeting_table) {
+ kfree(hwmgr->dyn_state.vq_budgeting_table);
+ hwmgr->dyn_state.vq_budgeting_table = NULL;
+ }
+
+ return 0;
+}
+
+const struct pp_table_func pptable_funcs = {
+ .pptable_init = pp_tables_initialize,
+ .pptable_fini = pp_tables_uninitialize,
+ .pptable_get_number_of_vce_state_table_entries =
+ get_number_of_vce_state_table_entries,
+ .pptable_get_vce_state_table_entry =
+ get_vce_state_table_entry,
+};
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h
new file mode 100644
index 000000000000..30434802417e
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 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.
+ * Interface Functions related to the BIOS PowerPlay Tables.
+ *
+ */
+
+#ifndef PROCESSPPTABLES_H
+#define PROCESSPPTABLES_H
+
+struct pp_hwmgr;
+struct pp_power_state;
+struct pp_hw_power_state;
+
+extern const struct pp_table_func pptable_funcs;
+
+typedef int (*pp_tables_hw_clock_info_callback)(struct pp_hwmgr *hwmgr,
+ struct pp_hw_power_state *hw_ps,
+ unsigned int index,
+ const void *clock_info);
+
+int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
+ unsigned long *num_of_entries);
+
+int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
+ unsigned long entry_index,
+ struct pp_power_state *ps,
+ pp_tables_hw_clock_info_callback func);
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c
new file mode 100644
index 000000000000..e58d038a997b
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "hwmgr.h"
+#include "tonga_clockpowergating.h"
+#include "tonga_ppsmc.h"
+#include "tonga_hwmgr.h"
+
+int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cf_want_uvd_power_gating(hwmgr))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_UVDPowerOFF);
+ return 0;
+}
+
+int tonga_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cf_want_uvd_power_gating(hwmgr)) {
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UVDDynamicPowerGating)) {
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_UVDPowerON, 1);
+ } else {
+ return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_UVDPowerON, 0);
+ }
+ }
+
+ return 0;
+}
+
+int tonga_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cf_want_vce_power_gating(hwmgr))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_VCEPowerOFF);
+ return 0;
+}
+
+int tonga_phm_powerup_vce(struct pp_hwmgr *hwmgr)
+{
+ if (phm_cf_want_vce_power_gating(hwmgr))
+ return smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_VCEPowerON);
+ return 0;
+}
+
+int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
+{
+ int ret = 0;
+
+ switch (block) {
+ case PHM_AsicBlock_UVD_MVC:
+ case PHM_AsicBlock_UVD:
+ case PHM_AsicBlock_UVD_HD:
+ case PHM_AsicBlock_UVD_SD:
+ if (gating == PHM_ClockGateSetting_StaticOff)
+ ret = tonga_phm_powerdown_uvd(hwmgr);
+ else
+ ret = tonga_phm_powerup_uvd(hwmgr);
+ break;
+ case PHM_AsicBlock_GFX:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ data->uvd_power_gated = false;
+ data->vce_power_gated = false;
+
+ tonga_phm_powerup_uvd(hwmgr);
+ tonga_phm_powerup_vce(hwmgr);
+
+ return 0;
+}
+
+int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ if (data->uvd_power_gated == bgate)
+ return 0;
+
+ data->uvd_power_gated = bgate;
+
+ if (bgate) {
+ cgs_set_clockgating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_CG_STATE_UNGATE);
+ cgs_set_powergating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_GATE);
+ tonga_update_uvd_dpm(hwmgr, true);
+ tonga_phm_powerdown_uvd(hwmgr);
+ } else {
+ tonga_phm_powerup_uvd(hwmgr);
+ cgs_set_powergating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_UNGATE);
+ cgs_set_clockgating_state(hwmgr->device,
+ AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_GATE);
+
+ tonga_update_uvd_dpm(hwmgr, false);
+ }
+
+ return 0;
+}
+
+int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ struct phm_set_power_state_input states;
+ const struct pp_power_state *pcurrent;
+ struct pp_power_state *requested;
+
+ pcurrent = hwmgr->current_ps;
+ requested = hwmgr->request_ps;
+
+ states.pcurrent_state = &(pcurrent->hardware);
+ states.pnew_state = &(requested->hardware);
+
+ if (phm_cf_want_vce_power_gating(hwmgr)) {
+ if (data->vce_power_gated != bgate) {
+ if (bgate) {
+ cgs_set_clockgating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_UNGATE);
+ cgs_set_powergating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_GATE);
+ tonga_enable_disable_vce_dpm(hwmgr, false);
+ data->vce_power_gated = true;
+ } else {
+ tonga_phm_powerup_vce(hwmgr);
+ data->vce_power_gated = false;
+ cgs_set_powergating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_UNGATE);
+ cgs_set_clockgating_state(
+ hwmgr->device,
+ AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_GATE);
+
+ tonga_update_vce_dpm(hwmgr, &states);
+ tonga_enable_disable_vce_dpm(hwmgr, true);
+ return 0;
+ }
+ }
+ } else {
+ tonga_update_vce_dpm(hwmgr, &states);
+ tonga_enable_disable_vce_dpm(hwmgr, true);
+ return 0;
+ }
+
+ if (!data->vce_power_gated)
+ tonga_update_vce_dpm(hwmgr, &states);
+
+ return 0;
+}
+
+int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
+ const uint32_t *msg_id)
+{
+ PPSMC_Msg msg;
+ uint32_t value;
+
+ switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
+ case PP_GROUP_GFX:
+ switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
+ case PP_BLOCK_GFX_CG:
+ if (PP_STATE_SUPPORT_CG & *msg_id) {
+ msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_GFX_CGCG_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ if (PP_STATE_SUPPORT_LS & *msg_id) {
+ msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_GFX_CGLS_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ break;
+
+ case PP_BLOCK_GFX_MG:
+ /* For GFX MGCG, there are three different ones;
+ * CPF, RLC, and all others. CPF MGCG will not be used for Tonga.
+ * For GFX MGLS, Tonga will not support it.
+ * */
+ if (PP_STATE_SUPPORT_CG & *msg_id) {
+ msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = (CG_RLC_MGCG_MASK | CG_GFX_OTHERS_MGCG_MASK);
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case PP_GROUP_SYS:
+ switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
+ case PP_BLOCK_SYS_BIF:
+ if (PP_STATE_SUPPORT_LS & *msg_id) {
+ msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_SYS_BIF_MGLS_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ break;
+
+ case PP_BLOCK_SYS_MC:
+ if (PP_STATE_SUPPORT_CG & *msg_id) {
+ msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_SYS_MC_MGCG_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+
+ if (PP_STATE_SUPPORT_LS & *msg_id) {
+ msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_SYS_MC_MGLS_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+
+ }
+ break;
+
+ case PP_BLOCK_SYS_HDP:
+ if (PP_STATE_SUPPORT_CG & *msg_id) {
+ msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_SYS_HDP_MGCG_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+
+ if (PP_STATE_SUPPORT_LS & *msg_id) {
+ msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+
+ value = CG_SYS_HDP_MGLS_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ break;
+
+ case PP_BLOCK_SYS_SDMA:
+ if (PP_STATE_SUPPORT_CG & *msg_id) {
+ msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_SYS_SDMA_MGCG_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+
+ if (PP_STATE_SUPPORT_LS & *msg_id) {
+ msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+
+ value = CG_SYS_SDMA_MGLS_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ break;
+
+ case PP_BLOCK_SYS_ROM:
+ if (PP_STATE_SUPPORT_CG & *msg_id) {
+ msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
+ ? PPSMC_MSG_EnableClockGatingFeature
+ : PPSMC_MSG_DisableClockGatingFeature;
+ value = CG_SYS_ROM_MASK;
+
+ if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
+ return -1;
+ }
+ break;
+
+ default:
+ return -1;
+
+ }
+ break;
+
+ default:
+ return -1;
+
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h
new file mode 100644
index 000000000000..8bc38cb17b7f
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_clockpowergating.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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 _TONGA_CLOCK_POWER_GATING_H_
+#define _TONGA_CLOCK_POWER_GATING_H_
+
+#include "tonga_hwmgr.h"
+#include "pp_asicblocks.h"
+
+extern int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
+extern int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
+extern int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
+extern int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
+extern int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
+extern int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
+#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h
new file mode 100644
index 000000000000..080d69d77f04
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_dyn_defaults.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2015 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 TONGA_DYN_DEFAULTS_H
+#define TONGA_DYN_DEFAULTS_H
+
+
+/** \file
+ * Volcanic Islands Dynamic default parameters.
+ */
+
+enum TONGAdpm_TrendDetection {
+ TONGAdpm_TrendDetection_AUTO,
+ TONGAdpm_TrendDetection_UP,
+ TONGAdpm_TrendDetection_DOWN
+};
+typedef enum TONGAdpm_TrendDetection TONGAdpm_TrendDetection;
+
+/* Bit vector representing same fields as hardware register. */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy */
+/* HDP_busy */
+/* IH_busy */
+/* DRM_busy */
+/* DRMDMA_busy */
+/* UVD_busy */
+/* VCE_busy */
+/* ACP_busy */
+/* SAMU_busy */
+/* AVP_busy */
+/* SDMA enabled */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
+/* SH_Gfx_busy */
+/* RB_Gfx_busy */
+/* VCE_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
+/* FE_Gfx_busy */
+/* RB_Gfx_busy */
+/* ACP_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
+/* FE_Gfx_busy */
+/* SH_Gfx_busy */
+/* UVD_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy */
+/* VCE_busy */
+/* ACP_busy */
+/* SAMU_busy */
+
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP, DRMDMA */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP, DRMDMA */
+#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP, DRMDMA */
+
+
+/* thermal protection counter (units).*/
+#define PPTONGA_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
+
+/* static screen threshold unit */
+#define PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT 0
+
+/* static screen threshold */
+#define PPTONGA_STATICSCREENTHRESHOLD_DFLT 0x00C8
+
+/* gfx idle clock stop threshold */
+#define PPTONGA_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
+
+/* Fixed reference divider to use when building baby stepping tables. */
+#define PPTONGA_REFERENCEDIVIDER_DFLT 4
+
+/*
+ * ULV voltage change delay time
+ * Used to be delay_vreg in N.I. split for S.I.
+ * Using N.I. delay_vreg value as default
+ * ReferenceClock = 2700
+ * VoltageResponseTime = 1000
+ * VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
+ */
+
+#define PPTONGA_ULVVOLTAGECHANGEDELAY_DFLT 1687
+
+#define PPTONGA_CGULVPARAMETER_DFLT 0x00040035
+#define PPTONGA_CGULVCONTROL_DFLT 0x00007450
+#define PPTONGA_TARGETACTIVITY_DFLT 30 /*30% */
+#define PPTONGA_MCLK_TARGETACTIVITY_DFLT 10 /*10% */
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c
new file mode 100644
index 000000000000..44a925006479
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c
@@ -0,0 +1,6075 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include "linux/delay.h"
+#include "pp_acpi.h"
+#include "hwmgr.h"
+#include <atombios.h>
+#include "tonga_hwmgr.h"
+#include "pptable.h"
+#include "processpptables.h"
+#include "tonga_processpptables.h"
+#include "tonga_pptable.h"
+#include "pp_debug.h"
+#include "tonga_ppsmc.h"
+#include "cgs_common.h"
+#include "pppcielanes.h"
+#include "tonga_dyn_defaults.h"
+#include "smumgr.h"
+#include "tonga_smumgr.h"
+#include "tonga_clockpowergating.h"
+#include "tonga_thermal.h"
+
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+
+#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 "cgs_linux.h"
+#include "eventmgr.h"
+#include "amd_pcie_helpers.h"
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0 0x05
+#define MC_CG_SEQ_DRAMCONF_S1 0x06
+#define MC_CG_SEQ_YCLK_SUSPEND 0x04
+#define MC_CG_SEQ_YCLK_RESUME 0x0a
+
+#define PCIE_BUS_CLK 10000
+#define TCLK (PCIE_BUS_CLK / 10)
+
+#define SMC_RAM_END 0x40000
+#define SMC_CG_IND_START 0xc0030000
+#define SMC_CG_IND_END 0xc0040000 /* First byte after SMC_CG_IND*/
+
+#define VOLTAGE_SCALE 4
+#define VOLTAGE_VID_OFFSET_SCALE1 625
+#define VOLTAGE_VID_OFFSET_SCALE2 100
+
+#define VDDC_VDDCI_DELTA 200
+#define VDDC_VDDGFX_DELTA 300
+
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+
+typedef uint32_t PECI_RegistryValue;
+
+/* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] */
+uint16_t PP_ClockStretcherLookupTable[2][4] = {
+ {600, 1050, 3, 0},
+ {600, 1050, 6, 1} };
+
+/* [FF, SS] type, [] 4 voltage ranges, and [Floor Freq, Boundary Freq, VID min , VID max] */
+uint32_t PP_ClockStretcherDDTTable[2][4][4] = {
+ { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
+ { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
+
+/* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%] (coming from PWR_CKS_CNTL.stretch_amount reg spec) */
+uint8_t PP_ClockStretchAmountConversion[2][6] = {
+ {0, 1, 3, 2, 4, 5},
+ {0, 2, 4, 5, 6, 5} };
+
+/* Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */
+enum DPM_EVENT_SRC {
+ DPM_EVENT_SRC_ANALOG = 0, /* Internal analog trip point */
+ DPM_EVENT_SRC_EXTERNAL = 1, /* External (GPIO 17) signal */
+ DPM_EVENT_SRC_DIGITAL = 2, /* Internal digital trip point (DIG_THERM_DPM) */
+ DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3, /* Internal analog or external */
+ DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 /* Internal digital or external */
+};
+typedef enum DPM_EVENT_SRC DPM_EVENT_SRC;
+
+const unsigned long PhwTonga_Magic = (unsigned long)(PHM_VIslands_Magic);
+
+struct tonga_power_state *cast_phw_tonga_power_state(
+ struct pp_hw_power_state *hw_ps)
+{
+ if (hw_ps == NULL)
+ return NULL;
+
+ PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
+ "Invalid Powerstate Type!",
+ return NULL);
+
+ return (struct tonga_power_state *)hw_ps;
+}
+
+const struct tonga_power_state *cast_const_phw_tonga_power_state(
+ const struct pp_hw_power_state *hw_ps)
+{
+ if (hw_ps == NULL)
+ return NULL;
+
+ PP_ASSERT_WITH_CODE((PhwTonga_Magic == hw_ps->magic),
+ "Invalid Powerstate Type!",
+ return NULL);
+
+ return (const struct tonga_power_state *)hw_ps;
+}
+
+int tonga_add_voltage(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *look_up_table,
+ phm_ppt_v1_voltage_lookup_record *record)
+{
+ uint32_t i;
+ PP_ASSERT_WITH_CODE((NULL != look_up_table),
+ "Lookup Table empty.", return -1;);
+ PP_ASSERT_WITH_CODE((0 != look_up_table->count),
+ "Lookup Table empty.", return -1;);
+ PP_ASSERT_WITH_CODE((SMU72_MAX_LEVELS_VDDGFX >= look_up_table->count),
+ "Lookup Table is full.", return -1;);
+
+ /* This is to avoid entering duplicate calculated records. */
+ for (i = 0; i < look_up_table->count; i++) {
+ if (look_up_table->entries[i].us_vdd == record->us_vdd) {
+ if (look_up_table->entries[i].us_calculated == 1)
+ return 0;
+ else
+ break;
+ }
+ }
+
+ look_up_table->entries[i].us_calculated = 1;
+ look_up_table->entries[i].us_vdd = record->us_vdd;
+ look_up_table->entries[i].us_cac_low = record->us_cac_low;
+ look_up_table->entries[i].us_cac_mid = record->us_cac_mid;
+ look_up_table->entries[i].us_cac_high = record->us_cac_high;
+ /* Only increment the count when we're appending, not replacing duplicate entry. */
+ if (i == look_up_table->count)
+ look_up_table->count++;
+
+ return 0;
+}
+
+int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display)
+{
+ PPSMC_Msg msg = has_display? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
+
+ return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ? 0 : -1;
+}
+
+uint8_t tonga_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
+ uint32_t voltage)
+{
+ uint8_t count = (uint8_t) (voltage_table->count);
+ uint8_t i = 0;
+
+ PP_ASSERT_WITH_CODE((NULL != voltage_table),
+ "Voltage Table empty.", return 0;);
+ PP_ASSERT_WITH_CODE((0 != count),
+ "Voltage Table empty.", return 0;);
+
+ for (i = 0; i < count; i++) {
+ /* find first voltage bigger than requested */
+ if (voltage_table->entries[i].value >= voltage)
+ return i;
+ }
+
+ /* voltage is bigger than max voltage in the table */
+ return i - 1;
+}
+
+/**
+ * @brief PhwTonga_GetVoltageOrder
+ * Returns index of requested voltage record in lookup(table)
+ * @param hwmgr - pointer to hardware manager
+ * @param lookupTable - lookup list to search in
+ * @param voltage - voltage to look for
+ * @return 0 on success
+ */
+uint8_t tonga_get_voltage_index(phm_ppt_v1_voltage_lookup_table *look_up_table,
+ uint16_t voltage)
+{
+ uint8_t count = (uint8_t) (look_up_table->count);
+ uint8_t i;
+
+ PP_ASSERT_WITH_CODE((NULL != look_up_table), "Lookup Table empty.", return 0;);
+ PP_ASSERT_WITH_CODE((0 != count), "Lookup Table empty.", return 0;);
+
+ for (i = 0; i < count; i++) {
+ /* find first voltage equal or bigger than requested */
+ if (look_up_table->entries[i].us_vdd >= voltage)
+ return i;
+ }
+
+ /* voltage is bigger than max voltage in the table */
+ return i-1;
+}
+
+bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr)
+{
+ /*
+ * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
+ * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
+ * whereas voltage control is a fundemental change that will not be disabled
+ */
+
+ return (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) ? 1 : 0);
+}
+
+/**
+ * Re-generate the DPM level mask value
+ * @param hwmgr the address of the hardware manager
+ */
+static uint32_t tonga_get_dpm_level_enable_mask_value(
+ struct tonga_single_dpm_table * dpm_table)
+{
+ uint32_t i;
+ uint32_t mask_value = 0;
+
+ for (i = dpm_table->count; i > 0; i--) {
+ mask_value = mask_value << 1;
+
+ if (dpm_table->dpm_levels[i-1].enabled)
+ mask_value |= 0x1;
+ else
+ mask_value &= 0xFFFFFFFE;
+ }
+ return mask_value;
+}
+
+/**
+ * Retrieve DPM default values from registry (if available)
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ */
+void tonga_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ phw_tonga_ulv_parm *ulv = &(data->ulv);
+ uint32_t tmp;
+
+ ulv->ch_ulv_parameter = PPTONGA_CGULVPARAMETER_DFLT;
+ data->voting_rights_clients0 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0;
+ data->voting_rights_clients1 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1;
+ data->voting_rights_clients2 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2;
+ data->voting_rights_clients3 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3;
+ data->voting_rights_clients4 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4;
+ data->voting_rights_clients5 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5;
+ data->voting_rights_clients6 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6;
+ data->voting_rights_clients7 = PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7;
+
+ data->static_screen_threshold_unit = PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT;
+ data->static_screen_threshold = PPTONGA_STATICSCREENTHRESHOLD_DFLT;
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ABM);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_NonABMSupportInPPLib);
+
+ tmp = 0;
+ if (tmp == 0)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicACTiming);
+
+ tmp = 0;
+ if (0 != tmp)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DisableMemoryTransition);
+
+ data->mclk_strobe_mode_threshold = 40000;
+ data->mclk_stutter_mode_threshold = 30000;
+ data->mclk_edc_enable_threshold = 40000;
+ data->mclk_edc_wr_enable_threshold = 40000;
+
+ tmp = 0;
+ if (tmp != 0)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DisableMCLS);
+
+ data->pcie_gen_performance.max = PP_PCIEGen1;
+ data->pcie_gen_performance.min = PP_PCIEGen3;
+ data->pcie_gen_power_saving.max = PP_PCIEGen1;
+ data->pcie_gen_power_saving.min = PP_PCIEGen3;
+
+ data->pcie_lane_performance.max = 0;
+ data->pcie_lane_performance.min = 16;
+ data->pcie_lane_power_saving.max = 0;
+ data->pcie_lane_power_saving.min = 16;
+
+ tmp = 0;
+
+ if (tmp)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkThrottleLowNotification);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicUVDState);
+
+}
+
+int tonga_update_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ int result = 0;
+ uint32_t low_sclk_interrupt_threshold = 0;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SclkThrottleLowNotification)
+ && (hwmgr->gfx_arbiter.sclk_threshold != data->low_sclk_interrupt_threshold)) {
+ data->low_sclk_interrupt_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+ low_sclk_interrupt_threshold = data->low_sclk_interrupt_threshold;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold);
+
+ result = tonga_copy_bytes_to_smc(
+ hwmgr->smumgr,
+ data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable,
+ LowSclkInterruptThreshold),
+ (uint8_t *)&low_sclk_interrupt_threshold,
+ sizeof(uint32_t),
+ data->sram_end
+ );
+ }
+
+ return result;
+}
+
+/**
+ * Find SCLK value that is associated with specified virtual_voltage_Id.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param virtual_voltage_Id voltageId to look for.
+ * @param sclk output value .
+ * @return always 0 if success and 2 if association not found
+ */
+static int tonga_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table,
+ uint16_t virtual_voltage_id, uint32_t *sclk)
+{
+ uint8_t entryId;
+ uint8_t voltageId;
+ struct phm_ppt_v1_information *pptable_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -1);
+
+ /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
+ for (entryId = 0; entryId < pptable_info->vdd_dep_on_sclk->count; entryId++) {
+ voltageId = pptable_info->vdd_dep_on_sclk->entries[entryId].vddInd;
+ if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
+ break;
+ }
+
+ PP_ASSERT_WITH_CODE(entryId < pptable_info->vdd_dep_on_sclk->count,
+ "Can't find requested voltage id in vdd_dep_on_sclk table!",
+ return -1;
+ );
+
+ *sclk = pptable_info->vdd_dep_on_sclk->entries[entryId].clk;
+
+ return 0;
+}
+
+/**
+ * Get Leakage VDDC based on leakage ID.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return 2 if vddgfx returned is greater than 2V or if BIOS
+ */
+int tonga_get_evv_voltage(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+ uint16_t virtual_voltage_id;
+ uint16_t vddc = 0;
+ uint16_t vddgfx = 0;
+ uint16_t i, j;
+ uint32_t sclk = 0;
+
+ /* retrieve voltage for leakage ID (0xff01 + i) */
+ for (i = 0; i < TONGA_MAX_LEAKAGE_COUNT; i++) {
+ virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+
+ /* in split mode we should have only vddgfx EVV leakages */
+ if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+ if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
+ pptable_info->vddgfx_lookup_table, virtual_voltage_id, &sclk)) {
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher)) {
+ for (j = 1; j < sclk_table->count; j++) {
+ if (sclk_table->entries[j].clk == sclk &&
+ sclk_table->entries[j].cks_enable == 0) {
+ sclk += 5000;
+ break;
+ }
+ }
+ }
+ PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
+ (hwmgr, VOLTAGE_TYPE_VDDGFX, sclk,
+ virtual_voltage_id, &vddgfx),
+ "Error retrieving EVV voltage value!", continue);
+
+ /* need to make sure vddgfx is less than 2v or else, it could burn the ASIC. */
+ PP_ASSERT_WITH_CODE((vddgfx < 2000 && vddgfx != 0), "Invalid VDDGFX value!", return -1);
+
+ /* the voltage should not be zero nor equal to leakage ID */
+ if (vddgfx != 0 && vddgfx != virtual_voltage_id) {
+ data->vddcgfx_leakage.actual_voltage[data->vddcgfx_leakage.count] = vddgfx;
+ data->vddcgfx_leakage.leakage_id[data->vddcgfx_leakage.count] = virtual_voltage_id;
+ data->vddcgfx_leakage.count++;
+ }
+ }
+ } else {
+ /* in merged mode we have only vddc EVV leakages */
+ if (0 == tonga_get_sclk_for_voltage_evv(hwmgr,
+ pptable_info->vddc_lookup_table,
+ virtual_voltage_id, &sclk)) {
+ PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk
+ (hwmgr, VOLTAGE_TYPE_VDDC, sclk,
+ virtual_voltage_id, &vddc),
+ "Error retrieving EVV voltage value!", continue);
+
+ /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
+ if (vddc > 2000)
+ printk(KERN_ERR "[ powerplay ] Invalid VDDC value! \n");
+
+ /* the voltage should not be zero nor equal to leakage ID */
+ if (vddc != 0 && vddc != virtual_voltage_id) {
+ data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc;
+ data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id;
+ data->vddc_leakage.count++;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int tonga_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* enable SCLK dpm */
+ if (0 == data->sclk_dpm_key_disabled) {
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_DPM_Enable)),
+ "Failed to enable SCLK DPM during DPM Start Function!",
+ return -1);
+ }
+
+ /* enable MCLK dpm */
+ if (0 == data->mclk_dpm_key_disabled) {
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_Enable)),
+ "Failed to enable MCLK DPM during DPM Start Function!",
+ return -1);
+
+ PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC0_CNTL, 0x05);/* CH0,1 read */
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC1_CNTL, 0x05);/* CH2,3 read */
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_CPL_CNTL, 0x100005);/*Read */
+
+ udelay(10);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC0_CNTL, 0x400005);/* CH0,1 write */
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_MC1_CNTL, 0x400005);/* CH2,3 write */
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixLCAC_CPL_CNTL, 0x500005);/* write */
+
+ }
+
+ return 0;
+}
+
+int tonga_start_dpm(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* enable general power management */
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 1);
+ /* enable sclk deep sleep */
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 1);
+
+ /* prepare for PCIE DPM */
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start +
+ offsetof(SMU72_SoftRegisters, VoltageChangeTimeout), 0x1000);
+
+ PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE, SWRST_COMMAND_1, RESETLC, 0x0);
+
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_Voltage_Cntl_Enable)),
+ "Failed to enable voltage DPM during DPM Start Function!",
+ return -1);
+
+ if (0 != tonga_enable_sclk_mclk_dpm(hwmgr)) {
+ PP_ASSERT_WITH_CODE(0, "Failed to enable Sclk DPM and Mclk DPM!", return -1);
+ }
+
+ /* enable PCIE dpm */
+ if (0 == data->pcie_dpm_key_disabled) {
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_Enable)),
+ "Failed to enable pcie DPM during DPM Start Function!",
+ return -1
+ );
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_Falcon_QuickTransition)) {
+ smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_EnableACDCGPIOInterrupt);
+ }
+
+ return 0;
+}
+
+int tonga_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* disable SCLK dpm */
+ if (0 == data->sclk_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
+ PP_ASSERT_WITH_CODE(
+ (0 == tonga_is_dpm_running(hwmgr)),
+ "Trying to Disable SCLK DPM when DPM is disabled",
+ return -1
+ );
+
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_DPM_Disable)),
+ "Failed to disable SCLK DPM during DPM stop Function!",
+ return -1);
+ }
+
+ /* disable MCLK dpm */
+ if (0 == data->mclk_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
+ PP_ASSERT_WITH_CODE(
+ (0 == tonga_is_dpm_running(hwmgr)),
+ "Trying to Disable MCLK DPM when DPM is disabled",
+ return -1
+ );
+
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_Disable)),
+ "Failed to Disable MCLK DPM during DPM stop Function!",
+ return -1);
+ }
+
+ return 0;
+}
+
+int tonga_stop_dpm(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, 0);
+ /* disable sclk deep sleep*/
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, DYNAMIC_PM_EN, 0);
+
+ /* disable PCIE dpm */
+ if (0 == data->pcie_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
+ PP_ASSERT_WITH_CODE(
+ (0 == tonga_is_dpm_running(hwmgr)),
+ "Trying to Disable PCIE DPM when DPM is disabled",
+ return -1
+ );
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_Disable)),
+ "Failed to disable pcie DPM during DPM stop Function!",
+ return -1);
+ }
+
+ if (0 != tonga_disable_sclk_mclk_dpm(hwmgr))
+ PP_ASSERT_WITH_CODE(0, "Failed to disable Sclk DPM and Mclk DPM!", return -1);
+
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
+ PP_ASSERT_WITH_CODE(
+ (0 == tonga_is_dpm_running(hwmgr)),
+ "Trying to Disable Voltage CNTL when DPM is disabled",
+ return -1
+ );
+
+ PP_ASSERT_WITH_CODE(
+ (0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_Voltage_Cntl_Disable)),
+ "Failed to disable voltage DPM during DPM stop Function!",
+ return -1);
+
+ return 0;
+}
+
+int tonga_enable_sclk_control(struct pp_hwmgr *hwmgr)
+{
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, 0);
+
+ return 0;
+}
+
+/**
+ * Send a message to the SMC and return a parameter
+ *
+ * @param hwmgr: the address of the powerplay hardware manager.
+ * @param msg: the message to send.
+ * @param parameter: pointer to the received parameter
+ * @return The response that came from the SMC.
+ */
+PPSMC_Result tonga_send_msg_to_smc_return_parameter(
+ struct pp_hwmgr *hwmgr,
+ PPSMC_Msg msg,
+ uint32_t *parameter)
+{
+ int result;
+
+ result = smum_send_msg_to_smc(hwmgr->smumgr, msg);
+
+ if ((0 == result) && parameter) {
+ *parameter = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+ }
+
+ return result;
+}
+
+/**
+ * force DPM power State
+ *
+ * @param hwmgr: the address of the powerplay hardware manager.
+ * @param n : DPM level
+ * @return The response that came from the SMC.
+ */
+int tonga_dpm_force_state(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint32_t level_mask = 1 << n;
+
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
+ PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
+ "Trying to force SCLK when DPM is disabled", return -1;);
+ if (0 == data->sclk_dpm_key_disabled)
+ return (0 == smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ (PPSMC_Msg)(PPSMC_MSG_SCLKDPM_SetEnabledMask),
+ level_mask) ? 0 : 1);
+
+ return 0;
+}
+
+/**
+ * force DPM power State
+ *
+ * @param hwmgr: the address of the powerplay hardware manager.
+ * @param n : DPM level
+ * @return The response that came from the SMC.
+ */
+int tonga_dpm_force_state_mclk(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint32_t level_mask = 1 << n;
+
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message. */
+ PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
+ "Trying to Force MCLK when DPM is disabled", return -1;);
+ if (0 == data->mclk_dpm_key_disabled)
+ return (0 == smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ (PPSMC_Msg)(PPSMC_MSG_MCLKDPM_SetEnabledMask),
+ level_mask) ? 0 : 1);
+
+ return 0;
+}
+
+/**
+ * force DPM power State
+ *
+ * @param hwmgr: the address of the powerplay hardware manager.
+ * @param n : DPM level
+ * @return The response that came from the SMC.
+ */
+int tonga_dpm_force_state_pcie(struct pp_hwmgr *hwmgr, uint32_t n)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
+ PP_ASSERT_WITH_CODE(0 == tonga_is_dpm_running(hwmgr),
+ "Trying to Force PCIE level when DPM is disabled", return -1;);
+ if (0 == data->pcie_dpm_key_disabled)
+ return (0 == smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ (PPSMC_Msg)(PPSMC_MSG_PCIeDPM_ForceLevel),
+ n) ? 0 : 1);
+
+ return 0;
+}
+
+/**
+ * Set the initial state by calling SMC to switch to this state directly
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_set_boot_state(struct pp_hwmgr *hwmgr)
+{
+ /*
+ * SMC only stores one state that SW will ask to switch too,
+ * so we switch the the just uploaded one
+ */
+ return (0 == tonga_disable_sclk_mclk_dpm(hwmgr)) ? 0 : 1;
+}
+
+/**
+ * Get the location of various tables inside the FW image.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_process_firmware_header(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct tonga_smumgr *tonga_smu = (struct tonga_smumgr *)(hwmgr->smumgr->backend);
+
+ uint32_t tmp;
+ int result;
+ bool error = 0;
+
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ SMU72_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU72_Firmware_Header, DpmTable),
+ &tmp, data->sram_end);
+
+ if (0 == result) {
+ data->dpm_table_start = tmp;
+ }
+
+ error |= (0 != result);
+
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ SMU72_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU72_Firmware_Header, SoftRegisters),
+ &tmp, data->sram_end);
+
+ if (0 == result) {
+ data->soft_regs_start = tmp;
+ tonga_smu->ulSoftRegsStart = tmp;
+ }
+
+ error |= (0 != result);
+
+
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ SMU72_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU72_Firmware_Header, mcRegisterTable),
+ &tmp, data->sram_end);
+
+ if (0 == result) {
+ data->mc_reg_table_start = tmp;
+ }
+
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ SMU72_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU72_Firmware_Header, FanTable),
+ &tmp, data->sram_end);
+
+ if (0 == result) {
+ data->fan_table_start = tmp;
+ }
+
+ error |= (0 != result);
+
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ SMU72_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU72_Firmware_Header, mcArbDramTimingTable),
+ &tmp, data->sram_end);
+
+ if (0 == result) {
+ data->arb_table_start = tmp;
+ }
+
+ error |= (0 != result);
+
+
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ SMU72_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU72_Firmware_Header, Version),
+ &tmp, data->sram_end);
+
+ if (0 == result) {
+ hwmgr->microcode_version_info.SMC = tmp;
+ }
+
+ error |= (0 != result);
+
+ return error ? 1 : 0;
+}
+
+/**
+ * Read clock related registers.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_read_clock_registers(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ data->clock_registers.vCG_SPLL_FUNC_CNTL =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL);
+ data->clock_registers.vCG_SPLL_FUNC_CNTL_2 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_2);
+ data->clock_registers.vCG_SPLL_FUNC_CNTL_3 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_3);
+ data->clock_registers.vCG_SPLL_FUNC_CNTL_4 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_FUNC_CNTL_4);
+ data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM);
+ data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_SPLL_SPREAD_SPECTRUM_2);
+ data->clock_registers.vDLL_CNTL =
+ cgs_read_register(hwmgr->device, mmDLL_CNTL);
+ data->clock_registers.vMCLK_PWRMGT_CNTL =
+ cgs_read_register(hwmgr->device, mmMCLK_PWRMGT_CNTL);
+ data->clock_registers.vMPLL_AD_FUNC_CNTL =
+ cgs_read_register(hwmgr->device, mmMPLL_AD_FUNC_CNTL);
+ data->clock_registers.vMPLL_DQ_FUNC_CNTL =
+ cgs_read_register(hwmgr->device, mmMPLL_DQ_FUNC_CNTL);
+ data->clock_registers.vMPLL_FUNC_CNTL =
+ cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL);
+ data->clock_registers.vMPLL_FUNC_CNTL_1 =
+ cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_1);
+ data->clock_registers.vMPLL_FUNC_CNTL_2 =
+ cgs_read_register(hwmgr->device, mmMPLL_FUNC_CNTL_2);
+ data->clock_registers.vMPLL_SS1 =
+ cgs_read_register(hwmgr->device, mmMPLL_SS1);
+ data->clock_registers.vMPLL_SS2 =
+ cgs_read_register(hwmgr->device, mmMPLL_SS2);
+
+ return 0;
+}
+
+/**
+ * Find out if memory is GDDR5.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_get_memory_type(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint32_t temp;
+
+ temp = cgs_read_register(hwmgr->device, mmMC_SEQ_MISC0);
+
+ data->is_memory_GDDR5 = (MC_SEQ_MISC0_GDDR5_VALUE ==
+ ((temp & MC_SEQ_MISC0_GDDR5_MASK) >>
+ MC_SEQ_MISC0_GDDR5_SHIFT));
+
+ return 0;
+}
+
+/**
+ * Enables Dynamic Power Management by SMC
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_enable_acpi_power_management(struct pp_hwmgr *hwmgr)
+{
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, STATIC_PM_EN, 1);
+
+ return 0;
+}
+
+/**
+ * Initialize PowerGating States for different engines
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_init_power_gate_state(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ data->uvd_power_gated = 0;
+ data->vce_power_gated = 0;
+ data->samu_power_gated = 0;
+ data->acp_power_gated = 0;
+ data->pg_acp_init = 1;
+
+ return 0;
+}
+
+/**
+ * Checks if DPM is enabled
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_check_for_dpm_running(struct pp_hwmgr *hwmgr)
+{
+ /*
+ * We return the status of Voltage Control instead of checking SCLK/MCLK DPM
+ * because we may have test scenarios that need us intentionly disable SCLK/MCLK DPM,
+ * whereas voltage control is a fundemental change that will not be disabled
+ */
+ return (0 == tonga_is_dpm_running(hwmgr) ? 0 : 1);
+}
+
+/**
+ * Checks if DPM is stopped
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_check_for_dpm_stopped(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ if (0 != tonga_is_dpm_running(hwmgr)) {
+ /* If HW Virtualization is enabled, dpm_table_start will not have a valid value */
+ if (!data->dpm_table_start) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Remove repeated voltage values and create table with unique values.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param voltage_table the pointer to changing voltage table
+ * @return 1 in success
+ */
+
+static int tonga_trim_voltage_table(struct pp_hwmgr *hwmgr,
+ pp_atomctrl_voltage_table *voltage_table)
+{
+ uint32_t table_size, i, j;
+ uint16_t vvalue;
+ bool bVoltageFound = 0;
+ pp_atomctrl_voltage_table *table;
+
+ PP_ASSERT_WITH_CODE((NULL != voltage_table), "Voltage Table empty.", return -1;);
+ table_size = sizeof(pp_atomctrl_voltage_table);
+ table = kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == table)
+ return -ENOMEM;
+
+ memset(table, 0x00, table_size);
+ table->mask_low = voltage_table->mask_low;
+ table->phase_delay = voltage_table->phase_delay;
+
+ for (i = 0; i < voltage_table->count; i++) {
+ vvalue = voltage_table->entries[i].value;
+ bVoltageFound = 0;
+
+ for (j = 0; j < table->count; j++) {
+ if (vvalue == table->entries[j].value) {
+ bVoltageFound = 1;
+ break;
+ }
+ }
+
+ if (!bVoltageFound) {
+ table->entries[table->count].value = vvalue;
+ table->entries[table->count].smio_low =
+ voltage_table->entries[i].smio_low;
+ table->count++;
+ }
+ }
+
+ memcpy(table, voltage_table, sizeof(pp_atomctrl_voltage_table));
+
+ kfree(table);
+
+ return 0;
+}
+
+static int tonga_get_svi2_vdd_ci_voltage_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_clock_voltage_dependency_table *voltage_dependency_table)
+{
+ uint32_t i;
+ int result;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ pp_atomctrl_voltage_table *vddci_voltage_table = &(data->vddci_voltage_table);
+
+ PP_ASSERT_WITH_CODE((0 != voltage_dependency_table->count),
+ "Voltage Dependency Table empty.", return -1;);
+
+ vddci_voltage_table->mask_low = 0;
+ vddci_voltage_table->phase_delay = 0;
+ vddci_voltage_table->count = voltage_dependency_table->count;
+
+ for (i = 0; i < voltage_dependency_table->count; i++) {
+ vddci_voltage_table->entries[i].value =
+ voltage_dependency_table->entries[i].vddci;
+ vddci_voltage_table->entries[i].smio_low = 0;
+ }
+
+ result = tonga_trim_voltage_table(hwmgr, vddci_voltage_table);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to trim VDDCI table.", return result;);
+
+ return 0;
+}
+
+
+
+static int tonga_get_svi2_vdd_voltage_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *look_up_table,
+ pp_atomctrl_voltage_table *voltage_table)
+{
+ uint8_t i = 0;
+
+ PP_ASSERT_WITH_CODE((0 != look_up_table->count),
+ "Voltage Lookup Table empty.", return -1;);
+
+ voltage_table->mask_low = 0;
+ voltage_table->phase_delay = 0;
+
+ voltage_table->count = look_up_table->count;
+
+ for (i = 0; i < voltage_table->count; i++) {
+ voltage_table->entries[i].value = look_up_table->entries[i].us_vdd;
+ voltage_table->entries[i].smio_low = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * -------------------------------------------------------- Voltage Tables --------------------------------------------------------------------------
+ * If the voltage table would be bigger than what will fit into the state table on the SMC keep only the higher entries.
+ */
+
+static void tonga_trim_voltage_table_to_fit_state_table(
+ struct pp_hwmgr *hwmgr,
+ uint32_t max_voltage_steps,
+ pp_atomctrl_voltage_table *voltage_table)
+{
+ unsigned int i, diff;
+
+ if (voltage_table->count <= max_voltage_steps) {
+ return;
+ }
+
+ diff = voltage_table->count - max_voltage_steps;
+
+ for (i = 0; i < max_voltage_steps; i++) {
+ voltage_table->entries[i] = voltage_table->entries[i + diff];
+ }
+
+ voltage_table->count = max_voltage_steps;
+
+ return;
+}
+
+/**
+ * Create Voltage Tables.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_construct_voltage_tables(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ int result;
+
+ /* MVDD has only GPIO voltage control */
+ if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+ result = atomctrl_get_voltage_table_v3(hwmgr,
+ VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT, &(data->mvdd_voltage_table));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve MVDD table.", return result;);
+ }
+
+ if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
+ /* GPIO voltage */
+ result = atomctrl_get_voltage_table_v3(hwmgr,
+ VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT, &(data->vddci_voltage_table));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve VDDCI table.", return result;);
+ } else if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
+ /* SVI2 voltage */
+ result = tonga_get_svi2_vdd_ci_voltage_table(hwmgr,
+ pptable_info->vdd_dep_on_mclk);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve SVI2 VDDCI table from dependancy table.", return result;);
+ }
+
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+ /* VDDGFX has only SVI2 voltage control */
+ result = tonga_get_svi2_vdd_voltage_table(hwmgr,
+ pptable_info->vddgfx_lookup_table, &(data->vddgfx_voltage_table));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;);
+ }
+
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+ /* VDDC has only SVI2 voltage control */
+ result = tonga_get_svi2_vdd_voltage_table(hwmgr,
+ pptable_info->vddc_lookup_table, &(data->vddc_voltage_table));
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to retrieve SVI2 VDDC table from lookup table.", return result;);
+ }
+
+ PP_ASSERT_WITH_CODE(
+ (data->vddc_voltage_table.count <= (SMU72_MAX_LEVELS_VDDC)),
+ "Too many voltage values for VDDC. Trimming to fit state table.",
+ tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU72_MAX_LEVELS_VDDC, &(data->vddc_voltage_table));
+ );
+
+ PP_ASSERT_WITH_CODE(
+ (data->vddgfx_voltage_table.count <= (SMU72_MAX_LEVELS_VDDGFX)),
+ "Too many voltage values for VDDGFX. Trimming to fit state table.",
+ tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU72_MAX_LEVELS_VDDGFX, &(data->vddgfx_voltage_table));
+ );
+
+ PP_ASSERT_WITH_CODE(
+ (data->vddci_voltage_table.count <= (SMU72_MAX_LEVELS_VDDCI)),
+ "Too many voltage values for VDDCI. Trimming to fit state table.",
+ tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU72_MAX_LEVELS_VDDCI, &(data->vddci_voltage_table));
+ );
+
+ PP_ASSERT_WITH_CODE(
+ (data->mvdd_voltage_table.count <= (SMU72_MAX_LEVELS_MVDD)),
+ "Too many voltage values for MVDD. Trimming to fit state table.",
+ tonga_trim_voltage_table_to_fit_state_table(hwmgr,
+ SMU72_MAX_LEVELS_MVDD, &(data->mvdd_voltage_table));
+ );
+
+ return 0;
+}
+
+/**
+ * Vddc table preparation for SMC.
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param table the SMC DPM table structure to be populated
+ * @return always 0
+ */
+static int tonga_populate_smc_vddc_table(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ unsigned int count;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+ table->VddcLevelCount = data->vddc_voltage_table.count;
+ for (count = 0; count < table->VddcLevelCount; count++) {
+ table->VddcTable[count] =
+ PP_HOST_TO_SMC_US(data->vddc_voltage_table.entries[count].value * VOLTAGE_SCALE);
+ }
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount);
+ }
+ return 0;
+}
+
+/**
+ * VddGfx table preparation for SMC.
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param table the SMC DPM table structure to be populated
+ * @return always 0
+ */
+static int tonga_populate_smc_vdd_gfx_table(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ unsigned int count;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+ table->VddGfxLevelCount = data->vddgfx_voltage_table.count;
+ for (count = 0; count < data->vddgfx_voltage_table.count; count++) {
+ table->VddGfxTable[count] =
+ PP_HOST_TO_SMC_US(data->vddgfx_voltage_table.entries[count].value * VOLTAGE_SCALE);
+ }
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VddGfxLevelCount);
+ }
+ return 0;
+}
+
+/**
+ * Vddci table preparation for SMC.
+ *
+ * @param *hwmgr The address of the hardware manager.
+ * @param *table The SMC DPM table structure to be populated.
+ * @return 0
+ */
+static int tonga_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint32_t count;
+
+ table->VddciLevelCount = data->vddci_voltage_table.count;
+ for (count = 0; count < table->VddciLevelCount; count++) {
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
+ table->VddciTable[count] =
+ PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+ } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
+ table->SmioTable1.Pattern[count].Voltage =
+ PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+ /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level. */
+ table->SmioTable1.Pattern[count].Smio =
+ (uint8_t) count;
+ table->Smio[count] |=
+ data->vddci_voltage_table.entries[count].smio_low;
+ table->VddciTable[count] =
+ PP_HOST_TO_SMC_US(data->vddci_voltage_table.entries[count].value * VOLTAGE_SCALE);
+ }
+ }
+
+ table->SmioMask1 = data->vddci_voltage_table.mask_low;
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount);
+
+ return 0;
+}
+
+/**
+ * Mvdd table preparation for SMC.
+ *
+ * @param *hwmgr The address of the hardware manager.
+ * @param *table The SMC DPM table structure to be populated.
+ * @return 0
+ */
+static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint32_t count;
+
+ if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+ table->MvddLevelCount = data->mvdd_voltage_table.count;
+ for (count = 0; count < table->MvddLevelCount; count++) {
+ table->SmioTable2.Pattern[count].Voltage =
+ PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE);
+ /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/
+ table->SmioTable2.Pattern[count].Smio =
+ (uint8_t) count;
+ table->Smio[count] |=
+ data->mvdd_voltage_table.entries[count].smio_low;
+ }
+ table->SmioMask2 = data->vddci_voltage_table.mask_low;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount);
+ }
+
+ return 0;
+}
+
+/**
+ * Convert a voltage value in mv unit to VID number required by SMU firmware
+ */
+static uint8_t convert_to_vid(uint16_t vddc)
+{
+ return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
+}
+
+
+/**
+ * Preparation of vddc and vddgfx CAC tables for SMC.
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param table the SMC DPM table structure to be populated
+ * @return always 0
+ */
+static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ uint32_t count;
+ uint8_t index;
+ int result = 0;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table = pptable_info->vddgfx_lookup_table;
+ struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table = pptable_info->vddc_lookup_table;
+
+ /* pTables is already swapped, so in order to use the value from it, we need to swap it back. */
+ uint32_t vddcLevelCount = PP_SMC_TO_HOST_UL(table->VddcLevelCount);
+ uint32_t vddgfxLevelCount = PP_SMC_TO_HOST_UL(table->VddGfxLevelCount);
+
+ for (count = 0; count < vddcLevelCount; count++) {
+ /* We are populating vddc CAC data to BapmVddc table in split and merged mode */
+ index = tonga_get_voltage_index(vddc_lookup_table,
+ data->vddc_voltage_table.entries[count].value);
+ table->BapmVddcVidLoSidd[count] =
+ convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
+ table->BapmVddcVidHiSidd[count] =
+ convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
+ table->BapmVddcVidHiSidd2[count] =
+ convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
+ }
+
+ if ((data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2)) {
+ /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */
+ for (count = 0; count < vddgfxLevelCount; count++) {
+ index = tonga_get_voltage_index(vddgfx_lookup_table,
+ data->vddgfx_voltage_table.entries[count].value);
+ table->BapmVddGfxVidLoSidd[count] =
+ convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_low);
+ table->BapmVddGfxVidHiSidd[count] =
+ convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_mid);
+ table->BapmVddGfxVidHiSidd2[count] =
+ convert_to_vid(vddgfx_lookup_table->entries[index].us_cac_high);
+ }
+ } else {
+ for (count = 0; count < vddcLevelCount; count++) {
+ index = tonga_get_voltage_index(vddc_lookup_table,
+ data->vddc_voltage_table.entries[count].value);
+ table->BapmVddGfxVidLoSidd[count] =
+ convert_to_vid(vddc_lookup_table->entries[index].us_cac_low);
+ table->BapmVddGfxVidHiSidd[count] =
+ convert_to_vid(vddc_lookup_table->entries[index].us_cac_mid);
+ table->BapmVddGfxVidHiSidd2[count] =
+ convert_to_vid(vddc_lookup_table->entries[index].us_cac_high);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+ * Preparation of voltage tables for SMC.
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param table the SMC DPM table structure to be populated
+ * @return always 0
+ */
+
+int tonga_populate_smc_voltage_tables(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result;
+
+ result = tonga_populate_smc_vddc_table(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "can not populate VDDC voltage table to SMC", return -1);
+
+ result = tonga_populate_smc_vdd_ci_table(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "can not populate VDDCI voltage table to SMC", return -1);
+
+ result = tonga_populate_smc_vdd_gfx_table(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "can not populate VDDGFX voltage table to SMC", return -1);
+
+ result = tonga_populate_smc_mvdd_table(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "can not populate MVDD voltage table to SMC", return -1);
+
+ result = tonga_populate_cac_tables(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "can not populate CAC voltage tables to SMC", return -1);
+
+ return 0;
+}
+
+/**
+ * Populates the SMC VRConfig field in DPM table.
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param table the SMC DPM table structure to be populated
+ * @return always 0
+ */
+static int tonga_populate_vr_config(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint16_t config;
+
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) {
+ /* Splitted mode */
+ config = VR_SVI2_PLANE_1;
+ table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
+
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+ config = VR_SVI2_PLANE_2;
+ table->VRConfig |= config;
+ } else {
+ printk(KERN_ERR "[ powerplay ] VDDC and VDDGFX should be both on SVI2 control in splitted mode! \n");
+ }
+ } else {
+ /* Merged mode */
+ config = VR_MERGED_WITH_VDDC;
+ table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT);
+
+ /* Set Vddc Voltage Controller */
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) {
+ config = VR_SVI2_PLANE_1;
+ table->VRConfig |= config;
+ } else {
+ printk(KERN_ERR "[ powerplay ] VDDC should be on SVI2 control in merged mode! \n");
+ }
+ }
+
+ /* Set Vddci Voltage Controller */
+ if (TONGA_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_ci_control) {
+ config = VR_SVI2_PLANE_2; /* only in merged mode */
+ table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
+ } else if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->vdd_ci_control) {
+ config = VR_SMIO_PATTERN_1;
+ table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT);
+ }
+
+ /* Set Mvdd Voltage Controller */
+ if (TONGA_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
+ config = VR_SMIO_PATTERN_2;
+ table->VRConfig |= (config<<VRCONF_MVDD_SHIFT);
+ }
+
+ return 0;
+}
+
+static int tonga_get_dependecy_volt_by_clk(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_clock_voltage_dependency_table *allowed_clock_voltage_table,
+ uint32_t clock, SMU_VoltageLevel *voltage, uint32_t *mvdd)
+{
+ uint32_t i = 0;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ /* clock - voltage dependency table is empty table */
+ if (allowed_clock_voltage_table->count == 0)
+ return -1;
+
+ for (i = 0; i < allowed_clock_voltage_table->count; i++) {
+ /* find first sclk bigger than request */
+ if (allowed_clock_voltage_table->entries[i].clk >= clock) {
+ voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+ allowed_clock_voltage_table->entries[i].vddgfx);
+
+ voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+ allowed_clock_voltage_table->entries[i].vddc);
+
+ if (allowed_clock_voltage_table->entries[i].vddci) {
+ voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
+ allowed_clock_voltage_table->entries[i].vddci);
+ } else {
+ voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
+ allowed_clock_voltage_table->entries[i].vddc - data->vddc_vddci_delta);
+ }
+
+ if (allowed_clock_voltage_table->entries[i].mvdd) {
+ *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i].mvdd;
+ }
+
+ voltage->Phases = 1;
+ return 0;
+ }
+ }
+
+ /* sclk is bigger than max sclk in the dependence table */
+ voltage->VddGfx = tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+ allowed_clock_voltage_table->entries[i-1].vddgfx);
+ voltage->Vddc = tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+ allowed_clock_voltage_table->entries[i-1].vddc);
+
+ if (allowed_clock_voltage_table->entries[i-1].vddci) {
+ voltage->Vddci = tonga_get_voltage_id(&data->vddci_voltage_table,
+ allowed_clock_voltage_table->entries[i-1].vddci);
+ }
+ if (allowed_clock_voltage_table->entries[i-1].mvdd) {
+ *mvdd = (uint32_t) allowed_clock_voltage_table->entries[i-1].mvdd;
+ }
+
+ return 0;
+}
+
+/**
+ * Call SMC to reset S0/S1 to S1 and Reset SMIO to initial value
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_reset_to_default(struct pp_hwmgr *hwmgr)
+{
+ return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults) == 0) ? 0 : 1;
+}
+
+int tonga_populate_memory_timing_parameters(
+ struct pp_hwmgr *hwmgr,
+ uint32_t engine_clock,
+ uint32_t memory_clock,
+ struct SMU72_Discrete_MCArbDramTimingTableEntry *arb_regs
+ )
+{
+ uint32_t dramTiming;
+ uint32_t dramTiming2;
+ uint32_t burstTime;
+ int result;
+
+ result = atomctrl_set_engine_dram_timings_rv770(hwmgr,
+ engine_clock, memory_clock);
+
+ PP_ASSERT_WITH_CODE(result == 0,
+ "Error calling VBIOS to set DRAM_TIMING.", return result);
+
+ dramTiming = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+ dramTiming2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+ burstTime = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+
+ arb_regs->McArbDramTiming = PP_HOST_TO_SMC_UL(dramTiming);
+ arb_regs->McArbDramTiming2 = PP_HOST_TO_SMC_UL(dramTiming2);
+ arb_regs->McArbBurstTime = (uint8_t)burstTime;
+
+ return 0;
+}
+
+/**
+ * Setup parameters for the MC ARB.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ * This function is to be called from the SetPowerState table.
+ */
+int tonga_program_memory_timing_parameters(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ int result = 0;
+ SMU72_Discrete_MCArbDramTimingTable arb_regs;
+ uint32_t i, j;
+
+ memset(&arb_regs, 0x00, sizeof(SMU72_Discrete_MCArbDramTimingTable));
+
+ for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
+ for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+ result = tonga_populate_memory_timing_parameters
+ (hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
+ data->dpm_table.mclk_table.dpm_levels[j].value,
+ &arb_regs.entries[i][j]);
+
+ if (0 != result) {
+ break;
+ }
+ }
+ }
+
+ if (0 == result) {
+ result = tonga_copy_bytes_to_smc(
+ hwmgr->smumgr,
+ data->arb_table_start,
+ (uint8_t *)&arb_regs,
+ sizeof(SMU72_Discrete_MCArbDramTimingTable),
+ data->sram_end
+ );
+ }
+
+ return result;
+}
+
+static int tonga_populate_smc_link_level(struct pp_hwmgr *hwmgr, SMU72_Discrete_DpmTable *table)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct tonga_dpm_table *dpm_table = &data->dpm_table;
+ uint32_t i;
+
+ /* Index (dpm_table->pcie_speed_table.count) is reserved for PCIE boot level. */
+ for (i = 0; i <= dpm_table->pcie_speed_table.count; i++) {
+ table->LinkLevel[i].PcieGenSpeed =
+ (uint8_t)dpm_table->pcie_speed_table.dpm_levels[i].value;
+ table->LinkLevel[i].PcieLaneCount =
+ (uint8_t)encode_pcie_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
+ table->LinkLevel[i].EnabledForActivity =
+ 1;
+ table->LinkLevel[i].SPC =
+ (uint8_t)(data->pcie_spc_cap & 0xff);
+ table->LinkLevel[i].DownThreshold =
+ PP_HOST_TO_SMC_UL(5);
+ table->LinkLevel[i].UpThreshold =
+ PP_HOST_TO_SMC_UL(30);
+ }
+
+ data->smc_state_table.LinkLevelCount =
+ (uint8_t)dpm_table->pcie_speed_table.count;
+ data->dpm_level_enable_mask.pcie_dpm_enable_mask =
+ tonga_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+
+ return 0;
+}
+
+static int tonga_populate_smc_uvd_level(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result = 0;
+
+ uint8_t count;
+ pp_atomctrl_clock_dividers_vi dividers;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+ table->UvdLevelCount = (uint8_t) (mm_table->count);
+ table->UvdBootLevel = 0;
+
+ for (count = 0; count < table->UvdLevelCount; count++) {
+ table->UvdLevel[count].VclkFrequency = mm_table->entries[count].vclk;
+ table->UvdLevel[count].DclkFrequency = mm_table->entries[count].dclk;
+ table->UvdLevel[count].MinVoltage.Vddc =
+ tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+ mm_table->entries[count].vddc);
+ table->UvdLevel[count].MinVoltage.VddGfx =
+ (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+ tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+ mm_table->entries[count].vddgfx) : 0;
+ table->UvdLevel[count].MinVoltage.Vddci =
+ tonga_get_voltage_id(&data->vddci_voltage_table,
+ mm_table->entries[count].vddc - data->vddc_vddci_delta);
+ table->UvdLevel[count].MinVoltage.Phases = 1;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->UvdLevel[count].VclkFrequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for Vclk clock", return result);
+
+ table->UvdLevel[count].VclkDivider = (uint8_t)dividers.pll_post_divider;
+
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->UvdLevel[count].DclkFrequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for Dclk clock", return result);
+
+ table->UvdLevel[count].DclkDivider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].VclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->UvdLevel[count].DclkFrequency);
+ //CONVERT_FROM_HOST_TO_SMC_UL((uint32_t)table->UvdLevel[count].MinVoltage);
+ }
+
+ return result;
+
+}
+
+static int tonga_populate_smc_vce_level(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result = 0;
+
+ uint8_t count;
+ pp_atomctrl_clock_dividers_vi dividers;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+ table->VceLevelCount = (uint8_t) (mm_table->count);
+ table->VceBootLevel = 0;
+
+ for (count = 0; count < table->VceLevelCount; count++) {
+ table->VceLevel[count].Frequency =
+ mm_table->entries[count].eclk;
+ table->VceLevel[count].MinVoltage.Vddc =
+ tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+ mm_table->entries[count].vddc);
+ table->VceLevel[count].MinVoltage.VddGfx =
+ (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+ tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+ mm_table->entries[count].vddgfx) : 0;
+ table->VceLevel[count].MinVoltage.Vddci =
+ tonga_get_voltage_id(&data->vddci_voltage_table,
+ mm_table->entries[count].vddc - data->vddc_vddci_delta);
+ table->VceLevel[count].MinVoltage.Phases = 1;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->VceLevel[count].Frequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for VCE engine clock", return result);
+
+ table->VceLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VceLevel[count].Frequency);
+ }
+
+ return result;
+}
+
+static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result = 0;
+ uint8_t count;
+ pp_atomctrl_clock_dividers_vi dividers;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+ table->AcpLevelCount = (uint8_t) (mm_table->count);
+ table->AcpBootLevel = 0;
+
+ for (count = 0; count < table->AcpLevelCount; count++) {
+ table->AcpLevel[count].Frequency =
+ pptable_info->mm_dep_table->entries[count].aclk;
+ table->AcpLevel[count].MinVoltage.Vddc =
+ tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+ mm_table->entries[count].vddc);
+ table->AcpLevel[count].MinVoltage.VddGfx =
+ (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+ tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+ mm_table->entries[count].vddgfx) : 0;
+ table->AcpLevel[count].MinVoltage.Vddci =
+ tonga_get_voltage_id(&data->vddci_voltage_table,
+ mm_table->entries[count].vddc - data->vddc_vddci_delta);
+ table->AcpLevel[count].MinVoltage.Phases = 1;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->AcpLevel[count].Frequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for engine clock", return result);
+
+ table->AcpLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->AcpLevel[count].Frequency);
+ }
+
+ return result;
+}
+
+static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result = 0;
+ uint8_t count;
+ pp_atomctrl_clock_dividers_vi dividers;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+ table->SamuBootLevel = 0;
+ table->SamuLevelCount = (uint8_t) (mm_table->count);
+
+ for (count = 0; count < table->SamuLevelCount; count++) {
+ /* not sure whether we need evclk or not */
+ table->SamuLevel[count].Frequency =
+ pptable_info->mm_dep_table->entries[count].samclock;
+ table->SamuLevel[count].MinVoltage.Vddc =
+ tonga_get_voltage_index(pptable_info->vddc_lookup_table,
+ mm_table->entries[count].vddc);
+ table->SamuLevel[count].MinVoltage.VddGfx =
+ (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) ?
+ tonga_get_voltage_index(pptable_info->vddgfx_lookup_table,
+ mm_table->entries[count].vddgfx) : 0;
+ table->SamuLevel[count].MinVoltage.Vddci =
+ tonga_get_voltage_id(&data->vddci_voltage_table,
+ mm_table->entries[count].vddc - data->vddc_vddci_delta);
+ table->SamuLevel[count].MinVoltage.Phases = 1;
+
+ /* retrieve divider value for VBIOS */
+ result = atomctrl_get_dfs_pll_dividers_vi(hwmgr,
+ table->SamuLevel[count].Frequency, &dividers);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find divide id for samu clock", return result);
+
+ table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider;
+
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency);
+ }
+
+ return result;
+}
+
+/**
+ * Populates the SMC MCLK structure using the provided memory clock
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param memory_clock the memory clock to use to populate the structure
+ * @param sclk the SMC SCLK structure to be populated
+ */
+static int tonga_calculate_mclk_params(
+ struct pp_hwmgr *hwmgr,
+ uint32_t memory_clock,
+ SMU72_Discrete_MemoryLevel *mclk,
+ bool strobe_mode,
+ bool dllStateOn
+ )
+{
+ const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
+ uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
+ uint32_t mpll_ad_func_cntl = data->clock_registers.vMPLL_AD_FUNC_CNTL;
+ uint32_t mpll_dq_func_cntl = data->clock_registers.vMPLL_DQ_FUNC_CNTL;
+ uint32_t mpll_func_cntl = data->clock_registers.vMPLL_FUNC_CNTL;
+ uint32_t mpll_func_cntl_1 = data->clock_registers.vMPLL_FUNC_CNTL_1;
+ uint32_t mpll_func_cntl_2 = data->clock_registers.vMPLL_FUNC_CNTL_2;
+ uint32_t mpll_ss1 = data->clock_registers.vMPLL_SS1;
+ uint32_t mpll_ss2 = data->clock_registers.vMPLL_SS2;
+
+ pp_atomctrl_memory_clock_param mpll_param;
+ int result;
+
+ result = atomctrl_get_memory_pll_dividers_si(hwmgr,
+ memory_clock, &mpll_param, strobe_mode);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Error retrieving Memory Clock Parameters from VBIOS.", return result);
+
+ /* MPLL_FUNC_CNTL setup*/
+ mpll_func_cntl = PHM_SET_FIELD(mpll_func_cntl, MPLL_FUNC_CNTL, BWCTRL, mpll_param.bw_ctrl);
+
+ /* MPLL_FUNC_CNTL_1 setup*/
+ mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1,
+ MPLL_FUNC_CNTL_1, CLKF, mpll_param.mpll_fb_divider.cl_kf);
+ mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1,
+ MPLL_FUNC_CNTL_1, CLKFRAC, mpll_param.mpll_fb_divider.clk_frac);
+ mpll_func_cntl_1 = PHM_SET_FIELD(mpll_func_cntl_1,
+ MPLL_FUNC_CNTL_1, VCO_MODE, mpll_param.vco_mode);
+
+ /* MPLL_AD_FUNC_CNTL setup*/
+ mpll_ad_func_cntl = PHM_SET_FIELD(mpll_ad_func_cntl,
+ MPLL_AD_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
+
+ if (data->is_memory_GDDR5) {
+ /* MPLL_DQ_FUNC_CNTL setup*/
+ mpll_dq_func_cntl = PHM_SET_FIELD(mpll_dq_func_cntl,
+ MPLL_DQ_FUNC_CNTL, YCLK_SEL, mpll_param.yclk_sel);
+ mpll_dq_func_cntl = PHM_SET_FIELD(mpll_dq_func_cntl,
+ MPLL_DQ_FUNC_CNTL, YCLK_POST_DIV, mpll_param.mpll_post_divider);
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MemorySpreadSpectrumSupport)) {
+ /*
+ ************************************
+ Fref = Reference Frequency
+ NF = Feedback divider ratio
+ NR = Reference divider ratio
+ Fnom = Nominal VCO output frequency = Fref * NF / NR
+ Fs = Spreading Rate
+ D = Percentage down-spread / 2
+ Fint = Reference input frequency to PFD = Fref / NR
+ NS = Spreading rate divider ratio = int(Fint / (2 * Fs))
+ CLKS = NS - 1 = ISS_STEP_NUM[11:0]
+ NV = D * Fs / Fnom * 4 * ((Fnom/Fref * NR) ^ 2)
+ CLKV = 65536 * NV = ISS_STEP_SIZE[25:0]
+ *************************************
+ */
+ pp_atomctrl_internal_ss_info ss_info;
+ uint32_t freq_nom;
+ uint32_t tmp;
+ uint32_t reference_clock = atomctrl_get_mpll_reference_clock(hwmgr);
+
+ /* for GDDR5 for all modes and DDR3 */
+ if (1 == mpll_param.qdr)
+ freq_nom = memory_clock * 4 * (1 << mpll_param.mpll_post_divider);
+ else
+ freq_nom = memory_clock * 2 * (1 << mpll_param.mpll_post_divider);
+
+ /* tmp = (freq_nom / reference_clock * reference_divider) ^ 2 Note: S.I. reference_divider = 1*/
+ tmp = (freq_nom / reference_clock);
+ tmp = tmp * tmp;
+
+ if (0 == atomctrl_get_memory_clock_spread_spectrum(hwmgr, freq_nom, &ss_info)) {
+ /* ss_info.speed_spectrum_percentage -- in unit of 0.01% */
+ /* ss.Info.speed_spectrum_rate -- in unit of khz */
+ /* CLKS = reference_clock / (2 * speed_spectrum_rate * reference_divider) * 10 */
+ /* = reference_clock * 5 / speed_spectrum_rate */
+ uint32_t clks = reference_clock * 5 / ss_info.speed_spectrum_rate;
+
+ /* CLKV = 65536 * speed_spectrum_percentage / 2 * spreadSpecrumRate / freq_nom * 4 / 100000 * ((freq_nom / reference_clock) ^ 2) */
+ /* = 131 * speed_spectrum_percentage * speed_spectrum_rate / 100 * ((freq_nom / reference_clock) ^ 2) / freq_nom */
+ uint32_t clkv =
+ (uint32_t)((((131 * ss_info.speed_spectrum_percentage *
+ ss_info.speed_spectrum_rate) / 100) * tmp) / freq_nom);
+
+ mpll_ss1 = PHM_SET_FIELD(mpll_ss1, MPLL_SS1, CLKV, clkv);
+ mpll_ss2 = PHM_SET_FIELD(mpll_ss2, MPLL_SS2, CLKS, clks);
+ }
+ }
+
+ /* MCLK_PWRMGT_CNTL setup */
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, DLL_SPEED, mpll_param.dll_speed);
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, MRDCK0_PDNB, dllStateOn);
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, MRDCK1_PDNB, dllStateOn);
+
+
+ /* Save the result data to outpupt memory level structure */
+ mclk->MclkFrequency = memory_clock;
+ mclk->MpllFuncCntl = mpll_func_cntl;
+ mclk->MpllFuncCntl_1 = mpll_func_cntl_1;
+ mclk->MpllFuncCntl_2 = mpll_func_cntl_2;
+ mclk->MpllAdFuncCntl = mpll_ad_func_cntl;
+ mclk->MpllDqFuncCntl = mpll_dq_func_cntl;
+ mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl;
+ mclk->DllCntl = dll_cntl;
+ mclk->MpllSs1 = mpll_ss1;
+ mclk->MpllSs2 = mpll_ss2;
+
+ return 0;
+}
+
+static uint8_t tonga_get_mclk_frequency_ratio(uint32_t memory_clock,
+ bool strobe_mode)
+{
+ uint8_t mc_para_index;
+
+ if (strobe_mode) {
+ if (memory_clock < 12500) {
+ mc_para_index = 0x00;
+ } else if (memory_clock > 47500) {
+ mc_para_index = 0x0f;
+ } else {
+ mc_para_index = (uint8_t)((memory_clock - 10000) / 2500);
+ }
+ } else {
+ if (memory_clock < 65000) {
+ mc_para_index = 0x00;
+ } else if (memory_clock > 135000) {
+ mc_para_index = 0x0f;
+ } else {
+ mc_para_index = (uint8_t)((memory_clock - 60000) / 5000);
+ }
+ }
+
+ return mc_para_index;
+}
+
+static uint8_t tonga_get_ddr3_mclk_frequency_ratio(uint32_t memory_clock)
+{
+ uint8_t mc_para_index;
+
+ if (memory_clock < 10000) {
+ mc_para_index = 0;
+ } else if (memory_clock >= 80000) {
+ mc_para_index = 0x0f;
+ } else {
+ mc_para_index = (uint8_t)((memory_clock - 10000) / 5000 + 1);
+ }
+
+ return mc_para_index;
+}
+
+static int tonga_populate_single_memory_level(
+ struct pp_hwmgr *hwmgr,
+ uint32_t memory_clock,
+ SMU72_Discrete_MemoryLevel *memory_level
+ )
+{
+ uint32_t minMvdd = 0;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ int result = 0;
+ bool dllStateOn;
+ struct cgs_display_info info = {0};
+
+
+ if (NULL != pptable_info->vdd_dep_on_mclk) {
+ result = tonga_get_dependecy_volt_by_clk(hwmgr,
+ pptable_info->vdd_dep_on_mclk, memory_clock, &memory_level->MinVoltage, &minMvdd);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find MinVddc voltage value from memory VDDC voltage dependency table", return result);
+ }
+
+ if (data->mvdd_control == TONGA_VOLTAGE_CONTROL_NONE) {
+ memory_level->MinMvdd = data->vbios_boot_state.mvdd_bootup_value;
+ } else {
+ memory_level->MinMvdd = minMvdd;
+ }
+ memory_level->EnabledForThrottle = 1;
+ memory_level->EnabledForActivity = 0;
+ memory_level->UpHyst = 0;
+ memory_level->DownHyst = 100;
+ memory_level->VoltageDownHyst = 0;
+
+ /* Indicates maximum activity level for this performance level.*/
+ memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target;
+ memory_level->StutterEnable = 0;
+ memory_level->StrobeEnable = 0;
+ memory_level->EdcReadEnable = 0;
+ memory_level->EdcWriteEnable = 0;
+ memory_level->RttEnable = 0;
+
+ /* default set to low watermark. Highest level will be set to high later.*/
+ memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+ data->display_timing.num_existing_displays = info.display_count;
+
+ if ((data->mclk_stutter_mode_threshold != 0) &&
+ (memory_clock <= data->mclk_stutter_mode_threshold) &&
+ (data->is_uvd_enabled == 0)
+#if defined(LINUX)
+ && (PHM_READ_FIELD(hwmgr->device, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE) & 0x1)
+ && (data->display_timing.num_existing_displays <= 2)
+ && (data->display_timing.num_existing_displays != 0)
+#endif
+ )
+ memory_level->StutterEnable = 1;
+
+ /* decide strobe mode*/
+ memory_level->StrobeEnable = (data->mclk_strobe_mode_threshold != 0) &&
+ (memory_clock <= data->mclk_strobe_mode_threshold);
+
+ /* decide EDC mode and memory clock ratio*/
+ if (data->is_memory_GDDR5) {
+ memory_level->StrobeRatio = tonga_get_mclk_frequency_ratio(memory_clock,
+ memory_level->StrobeEnable);
+
+ if ((data->mclk_edc_enable_threshold != 0) &&
+ (memory_clock > data->mclk_edc_enable_threshold)) {
+ memory_level->EdcReadEnable = 1;
+ }
+
+ if ((data->mclk_edc_wr_enable_threshold != 0) &&
+ (memory_clock > data->mclk_edc_wr_enable_threshold)) {
+ memory_level->EdcWriteEnable = 1;
+ }
+
+ if (memory_level->StrobeEnable) {
+ if (tonga_get_mclk_frequency_ratio(memory_clock, 1) >=
+ ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC7) >> 16) & 0xf)) {
+ dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+ } else {
+ dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC6) >> 1) & 0x1) ? 1 : 0;
+ }
+
+ } else {
+ dllStateOn = data->dll_defaule_on;
+ }
+ } else {
+ memory_level->StrobeRatio =
+ tonga_get_ddr3_mclk_frequency_ratio(memory_clock);
+ dllStateOn = ((cgs_read_register(hwmgr->device, mmMC_SEQ_MISC5) >> 1) & 0x1) ? 1 : 0;
+ }
+
+ result = tonga_calculate_mclk_params(hwmgr,
+ memory_clock, memory_level, memory_level->StrobeEnable, dllStateOn);
+
+ if (0 == result) {
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MinMvdd);
+ /* MCLK frequency in units of 10KHz*/
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkFrequency);
+ /* Indicates maximum activity level for this performance level.*/
+ CONVERT_FROM_HOST_TO_SMC_US(memory_level->ActivityLevel);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_1);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllFuncCntl_2);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllAdFuncCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllDqFuncCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MclkPwrmgtCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->DllCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs1);
+ CONVERT_FROM_HOST_TO_SMC_UL(memory_level->MpllSs2);
+ }
+
+ return result;
+}
+
+/**
+ * Populates the SMC MVDD structure using the provided memory clock.
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
+ * @param voltage the SMC VOLTAGE structure to be populated
+ */
+int tonga_populate_mvdd_value(struct pp_hwmgr *hwmgr, uint32_t mclk, SMIO_Pattern *smio_pattern)
+{
+ const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint32_t i = 0;
+
+ if (TONGA_VOLTAGE_CONTROL_NONE != data->mvdd_control) {
+ /* find mvdd value which clock is more than request */
+ for (i = 0; i < pptable_info->vdd_dep_on_mclk->count; i++) {
+ if (mclk <= pptable_info->vdd_dep_on_mclk->entries[i].clk) {
+ /* Always round to higher voltage. */
+ smio_pattern->Voltage = data->mvdd_voltage_table.entries[i].value;
+ break;
+ }
+ }
+
+ PP_ASSERT_WITH_CODE(i < pptable_info->vdd_dep_on_mclk->count,
+ "MVDD Voltage is outside the supported range.", return -1);
+
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int tonga_populate_smv_acpi_level(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result = 0;
+ const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ pp_atomctrl_clock_dividers_vi dividers;
+ SMIO_Pattern voltage_level;
+ uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+ uint32_t spll_func_cntl_2 = data->clock_registers.vCG_SPLL_FUNC_CNTL_2;
+ uint32_t dll_cntl = data->clock_registers.vDLL_CNTL;
+ uint32_t mclk_pwrmgt_cntl = data->clock_registers.vMCLK_PWRMGT_CNTL;
+
+ /* The ACPI state should not do DPM on DC (or ever).*/
+ table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ table->ACPILevel.MinVoltage = data->smc_state_table.GraphicsLevel[0].MinVoltage;
+
+ /* assign zero for now*/
+ table->ACPILevel.SclkFrequency = atomctrl_get_reference_clock(hwmgr);
+
+ /* get the engine clock dividers for this clock value*/
+ result = atomctrl_get_engine_pll_dividers_vi(hwmgr,
+ table->ACPILevel.SclkFrequency, &dividers);
+
+ PP_ASSERT_WITH_CODE(result == 0,
+ "Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+ /* divider ID for required SCLK*/
+ table->ACPILevel.SclkDid = (uint8_t)dividers.pll_post_divider;
+ table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+ table->ACPILevel.DeepSleepDivId = 0;
+
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+ CG_SPLL_FUNC_CNTL, SPLL_PWRON, 0);
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+ CG_SPLL_FUNC_CNTL, SPLL_RESET, 1);
+ spll_func_cntl_2 = PHM_SET_FIELD(spll_func_cntl_2,
+ CG_SPLL_FUNC_CNTL_2, SCLK_MUX_SEL, 4);
+
+ table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+ table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+ table->ACPILevel.CgSpllFuncCntl3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+ table->ACPILevel.CgSpllFuncCntl4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+ table->ACPILevel.SpllSpreadSpectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+ table->ACPILevel.SpllSpreadSpectrum2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+ table->ACPILevel.CcPwrDynRm = 0;
+ table->ACPILevel.CcPwrDynRm1 = 0;
+
+
+ /* For various features to be enabled/disabled while this level is active.*/
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.Flags);
+ /* SCLK frequency in units of 10KHz*/
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl2);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl3);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CgSpllFuncCntl4);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.SpllSpreadSpectrum2);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->ACPILevel.CcPwrDynRm1);
+
+ /* table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;*/
+ table->MemoryACPILevel.MinVoltage = data->smc_state_table.MemoryLevel[0].MinVoltage;
+
+ /* CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage);*/
+
+ if (0 == tonga_populate_mvdd_value(hwmgr, 0, &voltage_level))
+ table->MemoryACPILevel.MinMvdd =
+ PP_HOST_TO_SMC_UL(voltage_level.Voltage * VOLTAGE_SCALE);
+ else
+ table->MemoryACPILevel.MinMvdd = 0;
+
+ /* Force reset on DLL*/
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, MRDCK0_RESET, 0x1);
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, MRDCK1_RESET, 0x1);
+
+ /* Disable DLL in ACPIState*/
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, MRDCK0_PDNB, 0);
+ mclk_pwrmgt_cntl = PHM_SET_FIELD(mclk_pwrmgt_cntl,
+ MCLK_PWRMGT_CNTL, MRDCK1_PDNB, 0);
+
+ /* Enable DLL bypass signal*/
+ dll_cntl = PHM_SET_FIELD(dll_cntl,
+ DLL_CNTL, MRDCK0_BYPASS, 0);
+ dll_cntl = PHM_SET_FIELD(dll_cntl,
+ DLL_CNTL, MRDCK1_BYPASS, 0);
+
+ table->MemoryACPILevel.DllCntl =
+ PP_HOST_TO_SMC_UL(dll_cntl);
+ table->MemoryACPILevel.MclkPwrmgtCntl =
+ PP_HOST_TO_SMC_UL(mclk_pwrmgt_cntl);
+ table->MemoryACPILevel.MpllAdFuncCntl =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_AD_FUNC_CNTL);
+ table->MemoryACPILevel.MpllDqFuncCntl =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_DQ_FUNC_CNTL);
+ table->MemoryACPILevel.MpllFuncCntl =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL);
+ table->MemoryACPILevel.MpllFuncCntl_1 =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_1);
+ table->MemoryACPILevel.MpllFuncCntl_2 =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_FUNC_CNTL_2);
+ table->MemoryACPILevel.MpllSs1 =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS1);
+ table->MemoryACPILevel.MpllSs2 =
+ PP_HOST_TO_SMC_UL(data->clock_registers.vMPLL_SS2);
+
+ table->MemoryACPILevel.EnabledForThrottle = 0;
+ table->MemoryACPILevel.EnabledForActivity = 0;
+ table->MemoryACPILevel.UpHyst = 0;
+ table->MemoryACPILevel.DownHyst = 100;
+ table->MemoryACPILevel.VoltageDownHyst = 0;
+ /* Indicates maximum activity level for this performance level.*/
+ table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target);
+
+ table->MemoryACPILevel.StutterEnable = 0;
+ table->MemoryACPILevel.StrobeEnable = 0;
+ table->MemoryACPILevel.EdcReadEnable = 0;
+ table->MemoryACPILevel.EdcWriteEnable = 0;
+ table->MemoryACPILevel.RttEnable = 0;
+
+ return result;
+}
+
+static int tonga_find_boot_level(struct tonga_single_dpm_table *table, uint32_t value, uint32_t *boot_level)
+{
+ int result = 0;
+ uint32_t i;
+
+ for (i = 0; i < table->count; i++) {
+ if (value == table->dpm_levels[i].value) {
+ *boot_level = i;
+ result = 0;
+ }
+ }
+ return result;
+}
+
+static int tonga_populate_smc_boot_level(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_DpmTable *table)
+{
+ int result = 0;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ table->GraphicsBootLevel = 0; /* 0 == DPM[0] (low), etc. */
+ table->MemoryBootLevel = 0; /* 0 == DPM[0] (low), etc. */
+
+ /* find boot level from dpm table*/
+ result = tonga_find_boot_level(&(data->dpm_table.sclk_table),
+ data->vbios_boot_state.sclk_bootup_value,
+ (uint32_t *)&(data->smc_state_table.GraphicsBootLevel));
+
+ if (0 != result) {
+ data->smc_state_table.GraphicsBootLevel = 0;
+ printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+ in dependency table. Using Graphics DPM level 0!");
+ result = 0;
+ }
+
+ result = tonga_find_boot_level(&(data->dpm_table.mclk_table),
+ data->vbios_boot_state.mclk_bootup_value,
+ (uint32_t *)&(data->smc_state_table.MemoryBootLevel));
+
+ if (0 != result) {
+ data->smc_state_table.MemoryBootLevel = 0;
+ printk(KERN_ERR "[ powerplay ] VBIOS did not find boot engine clock value \
+ in dependency table. Using Memory DPM level 0!");
+ result = 0;
+ }
+
+ table->BootVoltage.Vddc =
+ tonga_get_voltage_id(&(data->vddc_voltage_table),
+ data->vbios_boot_state.vddc_bootup_value);
+ table->BootVoltage.VddGfx =
+ tonga_get_voltage_id(&(data->vddgfx_voltage_table),
+ data->vbios_boot_state.vddgfx_bootup_value);
+ table->BootVoltage.Vddci =
+ tonga_get_voltage_id(&(data->vddci_voltage_table),
+ data->vbios_boot_state.vddci_bootup_value);
+ table->BootMVdd = data->vbios_boot_state.mvdd_bootup_value;
+
+ CONVERT_FROM_HOST_TO_SMC_US(table->BootMVdd);
+
+ return result;
+}
+
+
+/**
+ * Calculates the SCLK dividers using the provided engine clock
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param engine_clock the engine clock to use to populate the structure
+ * @param sclk the SMC SCLK structure to be populated
+ */
+int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr,
+ uint32_t engine_clock, SMU72_Discrete_GraphicsLevel *sclk)
+{
+ const tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ pp_atomctrl_clock_dividers_vi dividers;
+ uint32_t spll_func_cntl = data->clock_registers.vCG_SPLL_FUNC_CNTL;
+ uint32_t spll_func_cntl_3 = data->clock_registers.vCG_SPLL_FUNC_CNTL_3;
+ uint32_t spll_func_cntl_4 = data->clock_registers.vCG_SPLL_FUNC_CNTL_4;
+ uint32_t cg_spll_spread_spectrum = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t cg_spll_spread_spectrum_2 = data->clock_registers.vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t reference_clock;
+ uint32_t reference_divider;
+ uint32_t fbdiv;
+ int result;
+
+ /* get the engine clock dividers for this clock value*/
+ result = atomctrl_get_engine_pll_dividers_vi(hwmgr, engine_clock, &dividers);
+
+ PP_ASSERT_WITH_CODE(result == 0,
+ "Error retrieving Engine Clock dividers from VBIOS.", return result);
+
+ /* To get FBDIV we need to multiply this by 16384 and divide it by Fref.*/
+ reference_clock = atomctrl_get_reference_clock(hwmgr);
+
+ reference_divider = 1 + dividers.uc_pll_ref_div;
+
+ /* low 14 bits is fraction and high 12 bits is divider*/
+ fbdiv = dividers.ul_fb_div.ul_fb_divider & 0x3FFFFFF;
+
+ /* SPLL_FUNC_CNTL setup*/
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+ CG_SPLL_FUNC_CNTL, SPLL_REF_DIV, dividers.uc_pll_ref_div);
+ spll_func_cntl = PHM_SET_FIELD(spll_func_cntl,
+ CG_SPLL_FUNC_CNTL, SPLL_PDIV_A, dividers.uc_pll_post_div);
+
+ /* SPLL_FUNC_CNTL_3 setup*/
+ spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+ CG_SPLL_FUNC_CNTL_3, SPLL_FB_DIV, fbdiv);
+
+ /* set to use fractional accumulation*/
+ spll_func_cntl_3 = PHM_SET_FIELD(spll_func_cntl_3,
+ CG_SPLL_FUNC_CNTL_3, SPLL_DITHEN, 1);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EngineSpreadSpectrumSupport)) {
+ pp_atomctrl_internal_ss_info ss_info;
+
+ uint32_t vcoFreq = engine_clock * dividers.uc_pll_post_div;
+ if (0 == atomctrl_get_engine_clock_spread_spectrum(hwmgr, vcoFreq, &ss_info)) {
+ /*
+ * ss_info.speed_spectrum_percentage -- in unit of 0.01%
+ * ss_info.speed_spectrum_rate -- in unit of khz
+ */
+ /* clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2 */
+ uint32_t clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate);
+
+ /* clkv = 2 * D * fbdiv / NS */
+ uint32_t clkV = 4 * ss_info.speed_spectrum_percentage * fbdiv / (clkS * 10000);
+
+ cg_spll_spread_spectrum =
+ PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, CLKS, clkS);
+ cg_spll_spread_spectrum =
+ PHM_SET_FIELD(cg_spll_spread_spectrum, CG_SPLL_SPREAD_SPECTRUM, SSEN, 1);
+ cg_spll_spread_spectrum_2 =
+ PHM_SET_FIELD(cg_spll_spread_spectrum_2, CG_SPLL_SPREAD_SPECTRUM_2, CLKV, clkV);
+ }
+ }
+
+ sclk->SclkFrequency = engine_clock;
+ sclk->CgSpllFuncCntl3 = spll_func_cntl_3;
+ sclk->CgSpllFuncCntl4 = spll_func_cntl_4;
+ sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum;
+ sclk->SpllSpreadSpectrum2 = cg_spll_spread_spectrum_2;
+ sclk->SclkDid = (uint8_t)dividers.pll_post_divider;
+
+ return 0;
+}
+
+/**
+ * Populates single SMC SCLK structure using the provided engine clock
+ *
+ * @param hwmgr the address of the hardware manager
+ * @param engine_clock the engine clock to use to populate the structure
+ * @param sclk the SMC SCLK structure to be populated
+ */
+static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint16_t sclk_activity_level_threshold, SMU72_Discrete_GraphicsLevel *graphic_level)
+{
+ int result;
+ uint32_t threshold;
+ uint32_t mvdd;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level);
+
+
+ /* populate graphics levels*/
+ result = tonga_get_dependecy_volt_by_clk(hwmgr,
+ pptable_info->vdd_dep_on_sclk, engine_clock,
+ &graphic_level->MinVoltage, &mvdd);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "can not find VDDC voltage value for VDDC \
+ engine clock dependency table", return result);
+
+ /* SCLK frequency in units of 10KHz*/
+ graphic_level->SclkFrequency = engine_clock;
+
+ /* Indicates maximum activity level for this performance level. 50% for now*/
+ graphic_level->ActivityLevel = sclk_activity_level_threshold;
+
+ graphic_level->CcPwrDynRm = 0;
+ graphic_level->CcPwrDynRm1 = 0;
+ /* this level can be used if activity is high enough.*/
+ graphic_level->EnabledForActivity = 0;
+ /* this level can be used for throttling.*/
+ graphic_level->EnabledForThrottle = 1;
+ graphic_level->UpHyst = 0;
+ graphic_level->DownHyst = 0;
+ graphic_level->VoltageDownHyst = 0;
+ graphic_level->PowerThrottle = 0;
+
+ threshold = engine_clock * data->fast_watemark_threshold / 100;
+/*
+ *get the DAL clock. do it in funture.
+ PECI_GetMinClockSettings(hwmgr->peci, &minClocks);
+ data->display_timing.min_clock_insr = minClocks.engineClockInSR;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep))
+ {
+ graphic_level->DeepSleepDivId = PhwTonga_GetSleepDividerIdFromClock(hwmgr, engine_clock, minClocks.engineClockInSR);
+ }
+*/
+
+ /* Default to slow, highest DPM level will be set to PPSMC_DISPLAY_WATERMARK_LOW later.*/
+ graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+ if (0 == result) {
+ /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVoltage);*/
+ /* CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->MinVddcPhases);*/
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SclkFrequency);
+ CONVERT_FROM_HOST_TO_SMC_US(graphic_level->ActivityLevel);
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl3);
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CgSpllFuncCntl4);
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum);
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->SpllSpreadSpectrum2);
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm);
+ CONVERT_FROM_HOST_TO_SMC_UL(graphic_level->CcPwrDynRm1);
+ }
+
+ return result;
+}
+
+/**
+ * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
+ *
+ * @param hwmgr the address of the hardware manager
+ */
+static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct tonga_dpm_table *dpm_table = &data->dpm_table;
+ phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
+ uint8_t pcie_entry_count = (uint8_t) data->dpm_table.pcie_speed_table.count;
+ int result = 0;
+ uint32_t level_array_adress = data->dpm_table_start +
+ offsetof(SMU72_Discrete_DpmTable, GraphicsLevel);
+ uint32_t level_array_size = sizeof(SMU72_Discrete_GraphicsLevel) *
+ SMU72_MAX_LEVELS_GRAPHICS; /* 64 -> long; 32 -> int*/
+ SMU72_Discrete_GraphicsLevel *levels = data->smc_state_table.GraphicsLevel;
+ uint32_t i, maxEntry;
+ uint8_t highest_pcie_level_enabled = 0, lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0, count = 0;
+ PECI_RegistryValue reg_value;
+ memset(levels, 0x00, level_array_size);
+
+ for (i = 0; i < dpm_table->sclk_table.count; i++) {
+ result = tonga_populate_single_graphic_level(hwmgr,
+ dpm_table->sclk_table.dpm_levels[i].value,
+ (uint16_t)data->activity_target[i],
+ &(data->smc_state_table.GraphicsLevel[i]));
+
+ if (0 != result)
+ return result;
+
+ /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
+ if (i > 1)
+ data->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
+
+ if (0 == i) {
+ reg_value = 0;
+ if (reg_value != 0)
+ data->smc_state_table.GraphicsLevel[0].UpHyst = (uint8_t)reg_value;
+ }
+
+ if (1 == i) {
+ reg_value = 0;
+ if (reg_value != 0)
+ data->smc_state_table.GraphicsLevel[1].UpHyst = (uint8_t)reg_value;
+ }
+ }
+
+ /* Only enable level 0 for now. */
+ data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
+
+ /* set highest level watermark to high */
+ if (dpm_table->sclk_table.count > 1)
+ data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark =
+ PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ data->smc_state_table.GraphicsDpmLevelCount =
+ (uint8_t)dpm_table->sclk_table.count;
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask =
+ tonga_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+ if (pcie_table != NULL) {
+ PP_ASSERT_WITH_CODE((pcie_entry_count >= 1),
+ "There must be 1 or more PCIE levels defined in PPTable.", return -1);
+ maxEntry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/
+ for (i = 0; i < dpm_table->sclk_table.count; i++) {
+ data->smc_state_table.GraphicsLevel[i].pcieDpmLevel =
+ (uint8_t) ((i < maxEntry) ? i : maxEntry);
+ }
+ } else {
+ if (0 == data->dpm_level_enable_mask.pcie_dpm_enable_mask)
+ printk(KERN_ERR "[ powerplay ] Pcie Dpm Enablemask is 0!");
+
+ while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+ ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+ (1<<(highest_pcie_level_enabled+1))) != 0)) {
+ highest_pcie_level_enabled++;
+ }
+
+ while (data->dpm_level_enable_mask.pcie_dpm_enable_mask &&
+ ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+ (1<<lowest_pcie_level_enabled)) == 0)) {
+ lowest_pcie_level_enabled++;
+ }
+
+ while ((count < highest_pcie_level_enabled) &&
+ ((data->dpm_level_enable_mask.pcie_dpm_enable_mask &
+ (1<<(lowest_pcie_level_enabled+1+count))) == 0)) {
+ count++;
+ }
+ mid_pcie_level_enabled = (lowest_pcie_level_enabled+1+count) < highest_pcie_level_enabled ?
+ (lowest_pcie_level_enabled+1+count) : highest_pcie_level_enabled;
+
+
+ /* set pcieDpmLevel to highest_pcie_level_enabled*/
+ for (i = 2; i < dpm_table->sclk_table.count; i++) {
+ data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled;
+ }
+
+ /* set pcieDpmLevel to lowest_pcie_level_enabled*/
+ data->smc_state_table.GraphicsLevel[0].pcieDpmLevel = lowest_pcie_level_enabled;
+
+ /* set pcieDpmLevel to mid_pcie_level_enabled*/
+ data->smc_state_table.GraphicsLevel[1].pcieDpmLevel = mid_pcie_level_enabled;
+ }
+ /* level count will send to smc once at init smc table and never change*/
+ result = tonga_copy_bytes_to_smc(hwmgr->smumgr, level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
+
+ if (0 != result)
+ return result;
+
+ return 0;
+}
+
+/**
+ * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
+ *
+ * @param hwmgr the address of the hardware manager
+ */
+
+static int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct tonga_dpm_table *dpm_table = &data->dpm_table;
+ int result;
+ /* populate MCLK dpm table to SMU7 */
+ uint32_t level_array_adress = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, MemoryLevel);
+ uint32_t level_array_size = sizeof(SMU72_Discrete_MemoryLevel) * SMU72_MAX_LEVELS_MEMORY;
+ SMU72_Discrete_MemoryLevel *levels = data->smc_state_table.MemoryLevel;
+ uint32_t i;
+
+ memset(levels, 0x00, level_array_size);
+
+ for (i = 0; i < dpm_table->mclk_table.count; i++) {
+ PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value),
+ "can not populate memory level as memory clock is zero", return -1);
+ result = tonga_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
+ &(data->smc_state_table.MemoryLevel[i]));
+ if (0 != result) {
+ return result;
+ }
+ }
+
+ /* Only enable level 0 for now.*/
+ data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
+
+ /*
+ * in order to prevent MC activity from stutter mode to push DPM up.
+ * the UVD change complements this by putting the MCLK in a higher state
+ * by default such that we are not effected by up threshold or and MCLK DPM latency.
+ */
+ data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
+ CONVERT_FROM_HOST_TO_SMC_US(data->smc_state_table.MemoryLevel[0].ActivityLevel);
+
+ data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count;
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+ /* set highest level watermark to high*/
+ data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ /* level count will send to smc once at init smc table and never change*/
+ result = tonga_copy_bytes_to_smc(hwmgr->smumgr,
+ level_array_adress, (uint8_t *)levels, (uint32_t)level_array_size, data->sram_end);
+
+ if (0 != result) {
+ return result;
+ }
+
+ return 0;
+}
+
+struct TONGA_DLL_SPEED_SETTING {
+ uint16_t Min; /* Minimum Data Rate*/
+ uint16_t Max; /* Maximum Data Rate*/
+ uint32_t dll_speed; /* The desired DLL_SPEED setting*/
+};
+
+static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
+{
+ return 0;
+}
+
+/* ---------------------------------------- ULV related functions ----------------------------------------------------*/
+
+
+static int tonga_reset_single_dpm_table(
+ struct pp_hwmgr *hwmgr,
+ struct tonga_single_dpm_table *dpm_table,
+ uint32_t count)
+{
+ uint32_t i;
+ if (!(count <= MAX_REGULAR_DPM_NUMBER))
+ printk(KERN_ERR "[ powerplay ] Fatal error, can not set up single DPM \
+ table entries to exceed max number! \n");
+
+ dpm_table->count = count;
+ for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++) {
+ dpm_table->dpm_levels[i].enabled = 0;
+ }
+
+ return 0;
+}
+
+static void tonga_setup_pcie_table_entry(
+ struct tonga_single_dpm_table *dpm_table,
+ uint32_t index, uint32_t pcie_gen,
+ uint32_t pcie_lanes)
+{
+ dpm_table->dpm_levels[index].value = pcie_gen;
+ dpm_table->dpm_levels[index].param1 = pcie_lanes;
+ dpm_table->dpm_levels[index].enabled = 1;
+}
+
+static int tonga_setup_default_pcie_tables(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_pcie_table *pcie_table = pptable_info->pcie_table;
+ uint32_t i, maxEntry;
+
+ if (data->use_pcie_performance_levels && !data->use_pcie_power_saving_levels) {
+ data->pcie_gen_power_saving = data->pcie_gen_performance;
+ data->pcie_lane_power_saving = data->pcie_lane_performance;
+ } else if (!data->use_pcie_performance_levels && data->use_pcie_power_saving_levels) {
+ data->pcie_gen_performance = data->pcie_gen_power_saving;
+ data->pcie_lane_performance = data->pcie_lane_power_saving;
+ }
+
+ tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.pcie_speed_table, SMU72_MAX_LEVELS_LINK);
+
+ if (pcie_table != NULL) {
+ /*
+ * maxEntry is used to make sure we reserve one PCIE level for boot level (fix for A+A PSPP issue).
+ * If PCIE table from PPTable have ULV entry + 8 entries, then ignore the last entry.
+ */
+ maxEntry = (SMU72_MAX_LEVELS_LINK < pcie_table->count) ?
+ SMU72_MAX_LEVELS_LINK : pcie_table->count;
+ for (i = 1; i < maxEntry; i++) {
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i-1,
+ get_pcie_gen_support(data->pcie_gen_cap, pcie_table->entries[i].gen_speed),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ }
+ data->dpm_table.pcie_speed_table.count = maxEntry - 1;
+ } else {
+ /* Hardcode Pcie Table */
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Max_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+ data->dpm_table.pcie_speed_table.count = 6;
+ }
+ /* Populate last level for boot PCIE level, but do not increment count. */
+ tonga_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
+ data->dpm_table.pcie_speed_table.count,
+ get_pcie_gen_support(data->pcie_gen_cap, PP_Min_PCIEGen),
+ get_pcie_lane_support(data->pcie_lane_cap, PP_Max_PCIELane));
+
+ return 0;
+
+}
+
+/*
+ * This function is to initalize all DPM state tables for SMU7 based on the dependency table.
+ * Dynamic state patching function will then trim these state tables to the allowed range based
+ * on the power policy or external client requests, such as UVD request, etc.
+ */
+static int tonga_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint32_t i;
+
+ phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_sclk_table =
+ pptable_info->vdd_dep_on_sclk;
+ phm_ppt_v1_clock_voltage_dependency_table *allowed_vdd_mclk_table =
+ pptable_info->vdd_dep_on_mclk;
+
+ PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
+ "SCLK dependency table is missing. This table is mandatory", return -1);
+ PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1,
+ "SCLK dependency table has to have is missing. This table is mandatory", return -1);
+
+ PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
+ "MCLK dependency table is missing. This table is mandatory", return -1);
+ PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1,
+ "VMCLK dependency table has to have is missing. This table is mandatory", return -1);
+
+ /* clear the state table to reset everything to default */
+ memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table));
+ tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.sclk_table, SMU72_MAX_LEVELS_GRAPHICS);
+ tonga_reset_single_dpm_table(hwmgr, &data->dpm_table.mclk_table, SMU72_MAX_LEVELS_MEMORY);
+ /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.VddcTable, SMU72_MAX_LEVELS_VDDC); */
+ /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_gfx_table, SMU72_MAX_LEVELS_VDDGFX);*/
+ /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.vdd_ci_table, SMU72_MAX_LEVELS_VDDCI);*/
+ /* tonga_reset_single_dpm_table(hwmgr, &tonga_hwmgr->dpm_table.mvdd_table, SMU72_MAX_LEVELS_MVDD);*/
+
+ PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
+ "SCLK dependency table is missing. This table is mandatory", return -1);
+ /* Initialize Sclk DPM table based on allow Sclk values*/
+ data->dpm_table.sclk_table.count = 0;
+
+ for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+ if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
+ allowed_vdd_sclk_table->entries[i].clk) {
+ data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
+ allowed_vdd_sclk_table->entries[i].clk;
+ data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; to do */
+ data->dpm_table.sclk_table.count++;
+ }
+ }
+
+ PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL,
+ "MCLK dependency table is missing. This table is mandatory", return -1);
+ /* Initialize Mclk DPM table based on allow Mclk values */
+ data->dpm_table.mclk_table.count = 0;
+ for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+ if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value !=
+ allowed_vdd_mclk_table->entries[i].clk) {
+ data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
+ allowed_vdd_mclk_table->entries[i].clk;
+ data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; */
+ data->dpm_table.mclk_table.count++;
+ }
+ }
+
+ /* Initialize Vddc DPM table based on allow Vddc values. And populate corresponding std values. */
+ for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+ data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].vddc;
+ /* tonga_hwmgr->dpm_table.VddcTable.dpm_levels[i].param1 = stdVoltageTable->entries[i].Leakage; */
+ /* param1 is for corresponding std voltage */
+ data->dpm_table.vddc_table.dpm_levels[i].enabled = 1;
+ }
+ data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count;
+
+ if (NULL != allowed_vdd_mclk_table) {
+ /* Initialize Vddci DPM table based on allow Mclk values */
+ for (i = 0; i < allowed_vdd_mclk_table->count; i++) {
+ data->dpm_table.vdd_ci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].vddci;
+ data->dpm_table.vdd_ci_table.dpm_levels[i].enabled = 1;
+ data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].mvdd;
+ data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1;
+ }
+ data->dpm_table.vdd_ci_table.count = allowed_vdd_mclk_table->count;
+ data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count;
+ }
+
+ /* setup PCIE gen speed levels*/
+ tonga_setup_default_pcie_tables(hwmgr);
+
+ /* save a copy of the default DPM table*/
+ memcpy(&(data->golden_dpm_table), &(data->dpm_table), sizeof(struct tonga_dpm_table));
+
+ return 0;
+}
+
+int tonga_populate_smc_initial_state(struct pp_hwmgr *hwmgr,
+ const struct tonga_power_state *bootState)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ uint8_t count, level;
+
+ count = (uint8_t) (pptable_info->vdd_dep_on_sclk->count);
+ for (level = 0; level < count; level++) {
+ if (pptable_info->vdd_dep_on_sclk->entries[level].clk >=
+ bootState->performance_levels[0].engine_clock) {
+ data->smc_state_table.GraphicsBootLevel = level;
+ break;
+ }
+ }
+
+ count = (uint8_t) (pptable_info->vdd_dep_on_mclk->count);
+ for (level = 0; level < count; level++) {
+ if (pptable_info->vdd_dep_on_mclk->entries[level].clk >=
+ bootState->performance_levels[0].memory_clock) {
+ data->smc_state_table.MemoryBootLevel = level;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Initializes the SMC table and uploads it
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param pInput the pointer to input data (PowerState)
+ * @return always 0
+ */
+int tonga_init_smc_table(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ SMU72_Discrete_DpmTable *table = &(data->smc_state_table);
+ const phw_tonga_ulv_parm *ulv = &(data->ulv);
+ uint8_t i;
+ PECI_RegistryValue reg_value;
+ pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
+
+ result = tonga_setup_default_dpm_tables(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to setup default DPM tables!", return result;);
+ memset(&(data->smc_state_table), 0x00, sizeof(data->smc_state_table));
+ if (TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control) {
+ tonga_populate_smc_voltage_tables(hwmgr, table);
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition)) {
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_StepVddc)) {
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+ }
+
+ if (data->is_memory_GDDR5) {
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+ }
+
+ i = PHM_READ_FIELD(hwmgr->device, CC_MC_MAX_CHANNEL, NOOFCHAN);
+
+ if (i == 1 || i == 0) {
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_12CHANNEL;
+ }
+
+ if (ulv->ulv_supported && pptable_info->us_ulv_voltage_offset) {
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize ULV state!", return result;);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_ULV_PARAMETER, ulv->ch_ulv_parameter);
+ }
+
+ result = tonga_populate_smc_link_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Link Level!", return result;);
+
+ result = tonga_populate_all_graphic_levels(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Graphics Level!", return result;);
+
+ result = tonga_populate_all_memory_levels(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Memory Level!", return result;);
+
+ result = tonga_populate_smv_acpi_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize ACPI Level!", return result;);
+
+ result = tonga_populate_smc_vce_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize VCE Level!", return result;);
+
+ result = tonga_populate_smc_acp_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize ACP Level!", return result;);
+
+ result = tonga_populate_smc_samu_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize SAMU Level!", return result;);
+
+ /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */
+ /* need to populate the ARB settings for the initial state. */
+ result = tonga_program_memory_timing_parameters(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to Write ARB settings for the initial state.", return result;);
+
+ result = tonga_populate_smc_uvd_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize UVD Level!", return result;);
+
+ result = tonga_populate_smc_boot_level(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize Boot Level!", return result;);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher)) {
+ result = tonga_populate_clock_stretcher_data_table(hwmgr);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to populate Clock Stretcher Data Table!", return result;);
+ }
+ table->GraphicsVoltageChangeEnable = 1;
+ table->GraphicsThermThrottleEnable = 1;
+ table->GraphicsInterval = 1;
+ table->VoltageInterval = 1;
+ table->ThermalInterval = 1;
+ table->TemperatureLimitHigh =
+ pptable_info->cac_dtp_table->usTargetOperatingTemp *
+ TONGA_Q88_FORMAT_CONVERSION_UNIT;
+ table->TemperatureLimitLow =
+ (pptable_info->cac_dtp_table->usTargetOperatingTemp - 1) *
+ TONGA_Q88_FORMAT_CONVERSION_UNIT;
+ table->MemoryVoltageChangeEnable = 1;
+ table->MemoryInterval = 1;
+ table->VoltageResponseTime = 0;
+ table->PhaseResponseTime = 0;
+ table->MemoryThermThrottleEnable = 1;
+
+ /*
+ * Cail reads current link status and reports it as cap (we cannot change this due to some previous issues we had)
+ * SMC drops the link status to lowest level after enabling DPM by PowerPlay. After pnp or toggling CF, driver gets reloaded again
+ * but this time Cail reads current link status which was set to low by SMC and reports it as cap to powerplay
+ * To avoid it, we set PCIeBootLinkLevel to highest dpm level
+ */
+ PP_ASSERT_WITH_CODE((1 <= data->dpm_table.pcie_speed_table.count),
+ "There must be 1 or more PCIE levels defined in PPTable.",
+ return -1);
+
+ table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count);
+
+ table->PCIeGenInterval = 1;
+
+ result = tonga_populate_vr_config(hwmgr, table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to populate VRConfig setting!", return result);
+
+ table->ThermGpio = 17;
+ table->SclkStepSize = 0x4000;
+
+ reg_value = 0;
+ if ((0 == reg_value) &&
+ (0 == atomctrl_get_pp_assign_pin(hwmgr,
+ VDDC_VRHOT_GPIO_PINID, &gpio_pin_assignment))) {
+ table->VRHotGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot);
+ } else {
+ table->VRHotGpio = TONGA_UNUSED_GPIO_PIN;
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot);
+ }
+
+ /* ACDC Switch GPIO */
+ reg_value = 0;
+ if ((0 == reg_value) &&
+ (0 == atomctrl_get_pp_assign_pin(hwmgr,
+ PP_AC_DC_SWITCH_GPIO_PINID, &gpio_pin_assignment))) {
+ table->AcDcGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition);
+ } else {
+ table->AcDcGpio = TONGA_UNUSED_GPIO_PIN;
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition);
+ }
+
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_Falcon_QuickTransition);
+
+ reg_value = 0;
+ if (1 == reg_value) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_AutomaticDCTransition);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_Falcon_QuickTransition);
+ }
+
+ reg_value = 0;
+ if ((0 == reg_value) &&
+ (0 == atomctrl_get_pp_assign_pin(hwmgr,
+ THERMAL_INT_OUTPUT_GPIO_PINID, &gpio_pin_assignment))) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ThermalOutGPIO);
+
+ table->ThermOutGpio = gpio_pin_assignment.uc_gpio_pin_bit_shift;
+
+ table->ThermOutPolarity =
+ (0 == (cgs_read_register(hwmgr->device, mmGPIOPAD_A) &
+ (1 << gpio_pin_assignment.uc_gpio_pin_bit_shift))) ? 1:0;
+
+ table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_ONLY;
+
+ /* if required, combine VRHot/PCC with thermal out GPIO*/
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_RegulatorHot) &&
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_CombinePCCWithThermalSignal)){
+ table->ThermOutMode = SMU7_THERM_OUT_MODE_THERM_VRHOT;
+ }
+ } else {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ThermalOutGPIO);
+
+ table->ThermOutGpio = 17;
+ table->ThermOutPolarity = 1;
+ table->ThermOutMode = SMU7_THERM_OUT_MODE_DISABLE;
+ }
+
+ for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++) {
+ table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]);
+ }
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask2);
+ CONVERT_FROM_HOST_TO_SMC_UL(table->SclkStepSize);
+ CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitHigh);
+ CONVERT_FROM_HOST_TO_SMC_US(table->TemperatureLimitLow);
+ CONVERT_FROM_HOST_TO_SMC_US(table->VoltageResponseTime);
+ CONVERT_FROM_HOST_TO_SMC_US(table->PhaseResponseTime);
+
+ /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
+ result = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->dpm_table_start +
+ offsetof(SMU72_Discrete_DpmTable, SystemFlags),
+ (uint8_t *)&(table->SystemFlags),
+ sizeof(SMU72_Discrete_DpmTable)-3 * sizeof(SMU72_PIDController),
+ data->sram_end);
+
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to upload dpm data to SMC memory!", return result;);
+
+ return result;
+}
+
+/* Look up the voltaged based on DAL's requested level. and then send the requested VDDC voltage to SMC*/
+static void tonga_apply_dal_minimum_voltage_request(struct pp_hwmgr *hwmgr)
+{
+ return;
+}
+
+int tonga_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr)
+{
+ PPSMC_Result result;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* Apply minimum voltage based on DAL's request level */
+ tonga_apply_dal_minimum_voltage_request(hwmgr);
+
+ if (0 == data->sclk_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
+ if (0 != tonga_is_dpm_running(hwmgr))
+ printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
+
+ if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ result = smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ (PPSMC_Msg)PPSMC_MSG_SCLKDPM_SetEnabledMask,
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Set Sclk Dpm enable Mask failed", return -1);
+ }
+ }
+
+ if (0 == data->mclk_dpm_key_disabled) {
+ /* Checking if DPM is running. If we discover hang because of this, we should skip this message.*/
+ if (0 != tonga_is_dpm_running(hwmgr))
+ printk(KERN_ERR "[ powerplay ] Trying to set Enable Mask when DPM is disabled \n");
+
+ if (0 != data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ result = smum_send_msg_to_smc_with_parameter(
+ hwmgr->smumgr,
+ (PPSMC_Msg)PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Set Mclk Dpm enable Mask failed", return -1);
+ }
+ }
+
+ return 0;
+}
+
+
+int tonga_force_dpm_highest(struct pp_hwmgr *hwmgr)
+{
+ uint32_t level, tmp;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ if (0 == data->pcie_dpm_key_disabled) {
+ /* PCIE */
+ if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
+ level = 0;
+ tmp = data->dpm_level_enable_mask.pcie_dpm_enable_mask;
+ while (tmp >>= 1)
+ level++ ;
+
+ if (0 != level) {
+ PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
+ "force highest pcie dpm state failed!", return -1);
+ }
+ }
+ }
+
+ if (0 == data->sclk_dpm_key_disabled) {
+ /* SCLK */
+ if (data->dpm_level_enable_mask.sclk_dpm_enable_mask != 0) {
+ level = 0;
+ tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask;
+ while (tmp >>= 1)
+ level++ ;
+
+ if (0 != level) {
+ PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
+ "force highest sclk dpm state failed!", return -1);
+ if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
+ printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+ Curr_Sclk_Index does not match the level \n");
+
+ }
+ }
+ }
+
+ if (0 == data->mclk_dpm_key_disabled) {
+ /* MCLK */
+ if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
+ level = 0;
+ tmp = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+ while (tmp >>= 1)
+ level++ ;
+
+ if (0 != level) {
+ PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
+ "force highest mclk dpm state failed!", return -1);
+ if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
+ printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+ Curr_Mclk_Index does not match the level \n");
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Find the MC microcode version and store it in the HwMgr struct
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr)
+{
+ cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F);
+
+ hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA);
+
+ return 0;
+}
+
+/**
+ * Initialize Dynamic State Adjustment Rule Settings
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ */
+int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
+{
+ uint32_t table_size;
+ struct phm_clock_voltage_dependency_table *table_clk_vlt;
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ hwmgr->dyn_state.mclk_sclk_ratio = 4;
+ hwmgr->dyn_state.sclk_mclk_delta = 15000; /* 150 MHz */
+ hwmgr->dyn_state.vddc_vddci_delta = 200; /* 200mV */
+
+ /* initialize vddc_dep_on_dal_pwrl table */
+ table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
+ table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == table_clk_vlt) {
+ printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
+ return -ENOMEM;
+ } else {
+ table_clk_vlt->count = 4;
+ table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
+ table_clk_vlt->entries[0].v = 0;
+ table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
+ table_clk_vlt->entries[1].v = 720;
+ table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
+ table_clk_vlt->entries[2].v = 810;
+ table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
+ table_clk_vlt->entries[3].v = 900;
+ pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
+ }
+
+ return 0;
+}
+
+static int tonga_set_private_var_based_on_pptale(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ phm_ppt_v1_clock_voltage_dependency_table *allowed_sclk_vdd_table =
+ pptable_info->vdd_dep_on_sclk;
+ phm_ppt_v1_clock_voltage_dependency_table *allowed_mclk_vdd_table =
+ pptable_info->vdd_dep_on_mclk;
+
+ PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table != NULL,
+ "VDD dependency on SCLK table is missing. \
+ This table is mandatory", return -1);
+ PP_ASSERT_WITH_CODE(allowed_sclk_vdd_table->count >= 1,
+ "VDD dependency on SCLK table has to have is missing. \
+ This table is mandatory", return -1);
+
+ PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table != NULL,
+ "VDD dependency on MCLK table is missing. \
+ This table is mandatory", return -1);
+ PP_ASSERT_WITH_CODE(allowed_mclk_vdd_table->count >= 1,
+ "VDD dependency on MCLK table has to have is missing. \
+ This table is mandatory", return -1);
+
+ data->min_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[0].vddc;
+ data->max_vddc_in_pp_table = (uint16_t)allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+
+ pptable_info->max_clock_voltage_on_ac.sclk =
+ allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].clk;
+ pptable_info->max_clock_voltage_on_ac.mclk =
+ allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].clk;
+ pptable_info->max_clock_voltage_on_ac.vddc =
+ allowed_sclk_vdd_table->entries[allowed_sclk_vdd_table->count - 1].vddc;
+ pptable_info->max_clock_voltage_on_ac.vddci =
+ allowed_mclk_vdd_table->entries[allowed_mclk_vdd_table->count - 1].vddci;
+
+ hwmgr->dyn_state.max_clock_voltage_on_ac.sclk =
+ pptable_info->max_clock_voltage_on_ac.sclk;
+ hwmgr->dyn_state.max_clock_voltage_on_ac.mclk =
+ pptable_info->max_clock_voltage_on_ac.mclk;
+ hwmgr->dyn_state.max_clock_voltage_on_ac.vddc =
+ pptable_info->max_clock_voltage_on_ac.vddc;
+ hwmgr->dyn_state.max_clock_voltage_on_ac.vddci =
+ pptable_info->max_clock_voltage_on_ac.vddci;
+
+ return 0;
+}
+
+int tonga_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ int result = 1;
+
+ PP_ASSERT_WITH_CODE (0 == tonga_is_dpm_running(hwmgr),
+ "Trying to Unforce DPM when DPM is disabled. Returning without sending SMC message.",
+ return result);
+
+ if (0 == data->pcie_dpm_key_disabled) {
+ PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(
+ hwmgr->smumgr,
+ PPSMC_MSG_PCIeDPM_UnForceLevel)),
+ "unforce pcie level failed!",
+ return -1);
+ }
+
+ result = tonga_upload_dpm_level_enable_mask(hwmgr);
+
+ return result;
+}
+
+static uint32_t tonga_get_lowest_enable_level(
+ struct pp_hwmgr *hwmgr, uint32_t level_mask)
+{
+ uint32_t level = 0;
+
+ while (0 == (level_mask & (1 << level)))
+ level++;
+
+ return level;
+}
+
+static int tonga_force_dpm_lowest(struct pp_hwmgr *hwmgr)
+{
+ uint32_t level;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ if (0 == data->pcie_dpm_key_disabled) {
+ /* PCIE */
+ if (data->dpm_level_enable_mask.pcie_dpm_enable_mask != 0) {
+ level = tonga_get_lowest_enable_level(hwmgr,
+ data->dpm_level_enable_mask.pcie_dpm_enable_mask);
+ PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_pcie(hwmgr, level)),
+ "force lowest pcie dpm state failed!", return -1);
+ }
+ }
+
+ if (0 == data->sclk_dpm_key_disabled) {
+ /* SCLK */
+ if (0 != data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ level = tonga_get_lowest_enable_level(hwmgr,
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask);
+
+ PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state(hwmgr, level)),
+ "force sclk dpm state failed!", return -1);
+
+ if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX) != level)
+ printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+ Curr_Sclk_Index does not match the level \n");
+ }
+ }
+
+ if (0 == data->mclk_dpm_key_disabled) {
+ /* MCLK */
+ if (data->dpm_level_enable_mask.mclk_dpm_enable_mask != 0) {
+ level = tonga_get_lowest_enable_level(hwmgr,
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ PP_ASSERT_WITH_CODE((0 == tonga_dpm_force_state_mclk(hwmgr, level)),
+ "force lowest mclk dpm state failed!", return -1);
+ if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ TARGET_AND_CURRENT_PROFILE_INDEX, CURR_MCLK_INDEX) != level)
+ printk(KERN_ERR "[ powerplay ] Target_and_current_Profile_Index. \
+ Curr_Mclk_Index does not match the level \n");
+ }
+ }
+
+ return 0;
+}
+
+static int tonga_patch_voltage_dependency_tables_with_lookup_table(struct pp_hwmgr *hwmgr)
+{
+ uint8_t entryId;
+ uint8_t voltageId;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+ phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+ if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+ for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+ voltageId = sclk_table->entries[entryId].vddInd;
+ sclk_table->entries[entryId].vddgfx =
+ pptable_info->vddgfx_lookup_table->entries[voltageId].us_vdd;
+ }
+ } else {
+ for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+ voltageId = sclk_table->entries[entryId].vddInd;
+ sclk_table->entries[entryId].vddc =
+ pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
+ }
+ }
+
+ for (entryId = 0; entryId < mclk_table->count; ++entryId) {
+ voltageId = mclk_table->entries[entryId].vddInd;
+ mclk_table->entries[entryId].vddc =
+ pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
+ }
+
+ for (entryId = 0; entryId < mm_table->count; ++entryId) {
+ voltageId = mm_table->entries[entryId].vddcInd;
+ mm_table->entries[entryId].vddc =
+ pptable_info->vddc_lookup_table->entries[voltageId].us_vdd;
+ }
+
+ return 0;
+
+}
+
+static int tonga_calc_voltage_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+ uint8_t entryId;
+ phm_ppt_v1_voltage_lookup_record v_record;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ phm_ppt_v1_clock_voltage_dependency_table *sclk_table = pptable_info->vdd_dep_on_sclk;
+ phm_ppt_v1_clock_voltage_dependency_table *mclk_table = pptable_info->vdd_dep_on_mclk;
+
+ if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+ for (entryId = 0; entryId < sclk_table->count; ++entryId) {
+ if (sclk_table->entries[entryId].vdd_offset & (1 << 15))
+ v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
+ sclk_table->entries[entryId].vdd_offset - 0xFFFF;
+ else
+ v_record.us_vdd = sclk_table->entries[entryId].vddgfx +
+ sclk_table->entries[entryId].vdd_offset;
+
+ sclk_table->entries[entryId].vddc =
+ v_record.us_cac_low = v_record.us_cac_mid =
+ v_record.us_cac_high = v_record.us_vdd;
+
+ tonga_add_voltage(hwmgr, pptable_info->vddc_lookup_table, &v_record);
+ }
+
+ for (entryId = 0; entryId < mclk_table->count; ++entryId) {
+ if (mclk_table->entries[entryId].vdd_offset & (1 << 15))
+ v_record.us_vdd = mclk_table->entries[entryId].vddc +
+ mclk_table->entries[entryId].vdd_offset - 0xFFFF;
+ else
+ v_record.us_vdd = mclk_table->entries[entryId].vddc +
+ mclk_table->entries[entryId].vdd_offset;
+
+ mclk_table->entries[entryId].vddgfx = v_record.us_cac_low =
+ v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
+ tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
+ }
+ }
+
+ return 0;
+
+}
+
+static int tonga_calc_mm_voltage_dependency_table(struct pp_hwmgr *hwmgr)
+{
+ uint32_t entryId;
+ phm_ppt_v1_voltage_lookup_record v_record;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = pptable_info->mm_dep_table;
+
+ if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+ for (entryId = 0; entryId < mm_table->count; entryId++) {
+ if (mm_table->entries[entryId].vddgfx_offset & (1 << 15))
+ v_record.us_vdd = mm_table->entries[entryId].vddc +
+ mm_table->entries[entryId].vddgfx_offset - 0xFFFF;
+ else
+ v_record.us_vdd = mm_table->entries[entryId].vddc +
+ mm_table->entries[entryId].vddgfx_offset;
+
+ /* Add the calculated VDDGFX to the VDDGFX lookup table */
+ mm_table->entries[entryId].vddgfx = v_record.us_cac_low =
+ v_record.us_cac_mid = v_record.us_cac_high = v_record.us_vdd;
+ tonga_add_voltage(hwmgr, pptable_info->vddgfx_lookup_table, &v_record);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Change virtual leakage voltage to actual value.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param pointer to changing voltage
+ * @param pointer to leakage table
+ */
+static void tonga_patch_with_vdd_leakage(struct pp_hwmgr *hwmgr,
+ uint16_t *voltage, phw_tonga_leakage_voltage *pLeakageTable)
+{
+ uint32_t leakage_index;
+
+ /* search for leakage voltage ID 0xff01 ~ 0xff08 */
+ for (leakage_index = 0; leakage_index < pLeakageTable->count; leakage_index++) {
+ /* if this voltage matches a leakage voltage ID */
+ /* patch with actual leakage voltage */
+ if (pLeakageTable->leakage_id[leakage_index] == *voltage) {
+ *voltage = pLeakageTable->actual_voltage[leakage_index];
+ break;
+ }
+ }
+
+ if (*voltage > ATOM_VIRTUAL_VOLTAGE_ID0)
+ printk(KERN_ERR "[ powerplay ] Voltage value looks like a Leakage ID but it's not patched \n");
+}
+
+/**
+ * Patch voltage lookup table by EVV leakages.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param pointer to voltage lookup table
+ * @param pointer to leakage table
+ * @return always 0
+ */
+static int tonga_patch_lookup_table_with_leakage(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table,
+ phw_tonga_leakage_voltage *pLeakageTable)
+{
+ uint32_t i;
+
+ for (i = 0; i < lookup_table->count; i++) {
+ tonga_patch_with_vdd_leakage(hwmgr,
+ &lookup_table->entries[i].us_vdd, pLeakageTable);
+ }
+
+ return 0;
+}
+
+static int tonga_patch_clock_voltage_lomits_with_vddc_leakage(struct pp_hwmgr *hwmgr,
+ phw_tonga_leakage_voltage *pLeakageTable, uint16_t *Vddc)
+{
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddc, pLeakageTable);
+ hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+ pptable_info->max_clock_voltage_on_dc.vddc;
+
+ return 0;
+}
+
+static int tonga_patch_clock_voltage_limits_with_vddgfx_leakage(
+ struct pp_hwmgr *hwmgr, phw_tonga_leakage_voltage *pLeakageTable,
+ uint16_t *Vddgfx)
+{
+ tonga_patch_with_vdd_leakage(hwmgr, (uint16_t *)Vddgfx, pLeakageTable);
+ return 0;
+}
+
+int tonga_sort_lookup_table(struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table *lookup_table)
+{
+ uint32_t table_size, i, j;
+ phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record;
+ table_size = lookup_table->count;
+
+ PP_ASSERT_WITH_CODE(0 != lookup_table->count,
+ "Lookup table is empty", return -1);
+
+ /* Sorting voltages */
+ for (i = 0; i < table_size - 1; i++) {
+ for (j = i + 1; j > 0; j--) {
+ if (lookup_table->entries[j].us_vdd < lookup_table->entries[j-1].us_vdd) {
+ tmp_voltage_lookup_record = lookup_table->entries[j-1];
+ lookup_table->entries[j-1] = lookup_table->entries[j];
+ lookup_table->entries[j] = tmp_voltage_lookup_record;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int tonga_complete_dependency_tables(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+ int tmp_result;
+ tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (data->vdd_gfx_control == TONGA_VOLTAGE_CONTROL_BY_SVID2) {
+ tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
+ pptable_info->vddgfx_lookup_table, &(data->vddcgfx_leakage));
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ tmp_result = tonga_patch_clock_voltage_limits_with_vddgfx_leakage(hwmgr,
+ &(data->vddcgfx_leakage), &pptable_info->max_clock_voltage_on_dc.vddgfx);
+ if (tmp_result != 0)
+ result = tmp_result;
+ } else {
+ tmp_result = tonga_patch_lookup_table_with_leakage(hwmgr,
+ pptable_info->vddc_lookup_table, &(data->vddc_leakage));
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ tmp_result = tonga_patch_clock_voltage_lomits_with_vddc_leakage(hwmgr,
+ &(data->vddc_leakage), &pptable_info->max_clock_voltage_on_dc.vddc);
+ if (tmp_result != 0)
+ result = tmp_result;
+ }
+
+ tmp_result = tonga_patch_voltage_dependency_tables_with_lookup_table(hwmgr);
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ tmp_result = tonga_calc_voltage_dependency_tables(hwmgr);
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ tmp_result = tonga_calc_mm_voltage_dependency_table(hwmgr);
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddgfx_lookup_table);
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ tmp_result = tonga_sort_lookup_table(hwmgr, pptable_info->vddc_lookup_table);
+ if (tmp_result != 0)
+ result = tmp_result;
+
+ return result;
+}
+
+int tonga_init_sclk_threshold(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ data->low_sclk_interrupt_threshold = 0;
+
+ return 0;
+}
+
+int tonga_setup_asic_task(struct pp_hwmgr *hwmgr)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = tonga_read_clock_registers(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to read clock registers!", result = tmp_result);
+
+ tmp_result = tonga_get_memory_type(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to get memory type!", result = tmp_result);
+
+ tmp_result = tonga_enable_acpi_power_management(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable ACPI power management!", result = tmp_result);
+
+ tmp_result = tonga_init_power_gate_state(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to init power gate state!", result = tmp_result);
+
+ tmp_result = tonga_get_mc_microcode_version(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to get MC microcode version!", result = tmp_result);
+
+ tmp_result = tonga_init_sclk_threshold(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to init sclk threshold!", result = tmp_result);
+
+ return result;
+}
+
+/**
+ * Enable voltage control
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_enable_voltage_control(struct pp_hwmgr *hwmgr)
+{
+ /* enable voltage control */
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1);
+
+ return 0;
+}
+
+/**
+ * Checks if we want to support voltage control
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ */
+bool cf_tonga_voltage_control(const struct pp_hwmgr *hwmgr)
+{
+ const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ return(TONGA_VOLTAGE_CONTROL_NONE != data->voltage_control);
+}
+
+/*---------------------------MC----------------------------*/
+
+uint8_t tonga_get_memory_modile_index(struct pp_hwmgr *hwmgr)
+{
+ return (uint8_t) (0xFF & (cgs_read_register(hwmgr->device, mmBIOS_SCRATCH_4) >> 16));
+}
+
+bool tonga_check_s0_mc_reg_index(uint16_t inReg, uint16_t *outReg)
+{
+ bool result = 1;
+
+ switch (inReg) {
+ case mmMC_SEQ_RAS_TIMING:
+ *outReg = mmMC_SEQ_RAS_TIMING_LP;
+ break;
+
+ case mmMC_SEQ_DLL_STBY:
+ *outReg = mmMC_SEQ_DLL_STBY_LP;
+ break;
+
+ case mmMC_SEQ_G5PDX_CMD0:
+ *outReg = mmMC_SEQ_G5PDX_CMD0_LP;
+ break;
+
+ case mmMC_SEQ_G5PDX_CMD1:
+ *outReg = mmMC_SEQ_G5PDX_CMD1_LP;
+ break;
+
+ case mmMC_SEQ_G5PDX_CTRL:
+ *outReg = mmMC_SEQ_G5PDX_CTRL_LP;
+ break;
+
+ case mmMC_SEQ_CAS_TIMING:
+ *outReg = mmMC_SEQ_CAS_TIMING_LP;
+ break;
+
+ case mmMC_SEQ_MISC_TIMING:
+ *outReg = mmMC_SEQ_MISC_TIMING_LP;
+ break;
+
+ case mmMC_SEQ_MISC_TIMING2:
+ *outReg = mmMC_SEQ_MISC_TIMING2_LP;
+ break;
+
+ case mmMC_SEQ_PMG_DVS_CMD:
+ *outReg = mmMC_SEQ_PMG_DVS_CMD_LP;
+ break;
+
+ case mmMC_SEQ_PMG_DVS_CTL:
+ *outReg = mmMC_SEQ_PMG_DVS_CTL_LP;
+ break;
+
+ case mmMC_SEQ_RD_CTL_D0:
+ *outReg = mmMC_SEQ_RD_CTL_D0_LP;
+ break;
+
+ case mmMC_SEQ_RD_CTL_D1:
+ *outReg = mmMC_SEQ_RD_CTL_D1_LP;
+ break;
+
+ case mmMC_SEQ_WR_CTL_D0:
+ *outReg = mmMC_SEQ_WR_CTL_D0_LP;
+ break;
+
+ case mmMC_SEQ_WR_CTL_D1:
+ *outReg = mmMC_SEQ_WR_CTL_D1_LP;
+ break;
+
+ case mmMC_PMG_CMD_EMRS:
+ *outReg = mmMC_SEQ_PMG_CMD_EMRS_LP;
+ break;
+
+ case mmMC_PMG_CMD_MRS:
+ *outReg = mmMC_SEQ_PMG_CMD_MRS_LP;
+ break;
+
+ case mmMC_PMG_CMD_MRS1:
+ *outReg = mmMC_SEQ_PMG_CMD_MRS1_LP;
+ break;
+
+ case mmMC_SEQ_PMG_TIMING:
+ *outReg = mmMC_SEQ_PMG_TIMING_LP;
+ break;
+
+ case mmMC_PMG_CMD_MRS2:
+ *outReg = mmMC_SEQ_PMG_CMD_MRS2_LP;
+ break;
+
+ case mmMC_SEQ_WR_CTL_2:
+ *outReg = mmMC_SEQ_WR_CTL_2_LP;
+ break;
+
+ default:
+ result = 0;
+ break;
+ }
+
+ return result;
+}
+
+int tonga_set_s0_mc_reg_index(phw_tonga_mc_reg_table *table)
+{
+ uint32_t i;
+ uint16_t address;
+
+ for (i = 0; i < table->last; i++) {
+ table->mc_reg_address[i].s0 =
+ tonga_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address)
+ ? address : table->mc_reg_address[i].s1;
+ }
+ return 0;
+}
+
+int tonga_copy_vbios_smc_reg_table(const pp_atomctrl_mc_reg_table *table, phw_tonga_mc_reg_table *ni_table)
+{
+ uint8_t i, j;
+
+ PP_ASSERT_WITH_CODE((table->last <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+ PP_ASSERT_WITH_CODE((table->num_entries <= MAX_AC_TIMING_ENTRIES),
+ "Invalid VramInfo table.", return -1);
+
+ for (i = 0; i < table->last; i++) {
+ ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+ }
+ ni_table->last = table->last;
+
+ for (i = 0; i < table->num_entries; i++) {
+ ni_table->mc_reg_table_entry[i].mclk_max =
+ table->mc_reg_table_entry[i].mclk_max;
+ for (j = 0; j < table->last; j++) {
+ ni_table->mc_reg_table_entry[i].mc_data[j] =
+ table->mc_reg_table_entry[i].mc_data[j];
+ }
+ }
+
+ ni_table->num_entries = table->num_entries;
+
+ return 0;
+}
+
+/**
+ * VBIOS omits some information to reduce size, we need to recover them here.
+ * 1. when we see mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
+ * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
+ * 2. when we see mmMC_SEQ_RESERVE_M, bit[15:0] EMRS2, need to be write to mmMC_PMG_CMD_MRS1/_LP[15:0].
+ * 3. need to set these data for each clock range
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @param table the address of MCRegTable
+ * @return always 0
+ */
+int tonga_set_mc_special_registers(struct pp_hwmgr *hwmgr, phw_tonga_mc_reg_table *table)
+{
+ uint8_t i, j, k;
+ uint32_t temp_reg;
+ const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ for (i = 0, j = table->last; i < table->last; i++) {
+ PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+ switch (table->mc_reg_address[i].s1) {
+ /*
+ * mmMC_SEQ_MISC1, bit[31:16] EMRS1, need to be write to mmMC_PMG_CMD_EMRS /_LP[15:0].
+ * Bit[15:0] MRS, need to be update mmMC_PMG_CMD_MRS/_LP[15:0]
+ */
+ case mmMC_SEQ_MISC1:
+ temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS);
+ table->mc_reg_address[j].s1 = mmMC_PMG_CMD_EMRS;
+ table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_EMRS_LP;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ ((temp_reg & 0xffff0000)) |
+ ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+ }
+ j++;
+ PP_ASSERT_WITH_CODE((j < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+
+ temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS);
+ table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS;
+ table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS_LP;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ (temp_reg & 0xffff0000) |
+ (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+
+ if (!data->is_memory_GDDR5) {
+ table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+ }
+ }
+ j++;
+ PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+
+ if (!data->is_memory_GDDR5) {
+ table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
+ table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
+ }
+ j++;
+ PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+ }
+
+ break;
+
+ case mmMC_SEQ_RESERVE_M:
+ temp_reg = cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1);
+ table->mc_reg_address[j].s1 = mmMC_PMG_CMD_MRS1;
+ table->mc_reg_address[j].s0 = mmMC_SEQ_PMG_CMD_MRS1_LP;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ (temp_reg & 0xffff0000) |
+ (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+ }
+ j++;
+ PP_ASSERT_WITH_CODE((j <= SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE),
+ "Invalid VramInfo table.", return -1);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ table->last = j;
+
+ return 0;
+}
+
+int tonga_set_valid_flag(phw_tonga_mc_reg_table *table)
+{
+ uint8_t i, j;
+ for (i = 0; i < table->last; i++) {
+ for (j = 1; j < table->num_entries; j++) {
+ if (table->mc_reg_table_entry[j-1].mc_data[i] !=
+ table->mc_reg_table_entry[j].mc_data[i]) {
+ table->validflag |= (1<<i);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+ pp_atomctrl_mc_reg_table *table;
+ phw_tonga_mc_reg_table *ni_table = &data->tonga_mc_reg_table;
+ uint8_t module_index = tonga_get_memory_modile_index(hwmgr);
+
+ table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL);
+
+ if (NULL == table)
+ return -ENOMEM;
+
+ /* Program additional LP registers that are no longer programmed by VBIOS */
+ cgs_write_register(hwmgr->device, mmMC_SEQ_RAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RAS_TIMING));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_CAS_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_CAS_TIMING));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_DLL_STBY_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_DLL_STBY));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD0));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CMD1));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_G5PDX_CTRL));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CMD));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_DVS_CTL));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_MISC_TIMING2));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_EMRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_EMRS));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS1_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS1));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D0));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_D1));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D0));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_RD_CTL_D1));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_TIMING_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_PMG_TIMING));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_PMG_CMD_MRS2_LP, cgs_read_register(hwmgr->device, mmMC_PMG_CMD_MRS2));
+ cgs_write_register(hwmgr->device, mmMC_SEQ_WR_CTL_2_LP, cgs_read_register(hwmgr->device, mmMC_SEQ_WR_CTL_2));
+
+ memset(table, 0x00, sizeof(pp_atomctrl_mc_reg_table));
+
+ result = atomctrl_initialize_mc_reg_table(hwmgr, module_index, table);
+
+ if (0 == result)
+ result = tonga_copy_vbios_smc_reg_table(table, ni_table);
+
+ if (0 == result) {
+ tonga_set_s0_mc_reg_index(ni_table);
+ result = tonga_set_mc_special_registers(hwmgr, ni_table);
+ }
+
+ if (0 == result)
+ tonga_set_valid_flag(ni_table);
+
+ kfree(table);
+ return result;
+}
+
+/*
+* Copy one arb setting to another and then switch the active set.
+* arbFreqSrc and arbFreqDest is one of the MC_CG_ARB_FREQ_Fx constants.
+*/
+int tonga_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
+ uint32_t arbFreqSrc, uint32_t arbFreqDest)
+{
+ uint32_t mc_arb_dram_timing;
+ uint32_t mc_arb_dram_timing2;
+ uint32_t burst_time;
+ uint32_t mc_cg_config;
+
+ switch (arbFreqSrc) {
+ case MC_CG_ARB_FREQ_F0:
+ mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING);
+ mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2);
+ burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0);
+ break;
+
+ case MC_CG_ARB_FREQ_F1:
+ mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1);
+ mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1);
+ burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1);
+ break;
+
+ default:
+ return -1;
+ }
+
+ switch (arbFreqDest) {
+ case MC_CG_ARB_FREQ_F0:
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+ PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time);
+ break;
+
+ case MC_CG_ARB_FREQ_F1:
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+ cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+ PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time);
+ break;
+
+ default:
+ return -1;
+ }
+
+ mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG);
+ mc_cg_config |= 0x0000000F;
+ cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config);
+ PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arbFreqDest);
+
+ return 0;
+}
+
+/**
+ * Initial switch from ARB F0->F1
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ * This function is to be called from the SetPowerState table.
+ */
+int tonga_initial_switch_from_arb_f0_to_f1(struct pp_hwmgr *hwmgr)
+{
+ return tonga_copy_and_switch_arb_sets(hwmgr, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+/**
+ * Initialize the ARB DRAM timing table's index field.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_init_arb_table_index(struct pp_hwmgr *hwmgr)
+{
+ const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ uint32_t tmp;
+ int result;
+
+ /*
+ * This is a read-modify-write on the first byte of the ARB table.
+ * The first byte in the SMU72_Discrete_MCArbDramTimingTable structure is the field 'current'.
+ * This solution is ugly, but we never write the whole table only individual fields in it.
+ * In reality this field should not be in that structure but in a soft register.
+ */
+ result = tonga_read_smc_sram_dword(hwmgr->smumgr,
+ data->arb_table_start, &tmp, data->sram_end);
+
+ if (0 != result)
+ return result;
+
+ tmp &= 0x00FFFFFF;
+ tmp |= ((uint32_t)MC_CG_ARB_FREQ_F1) << 24;
+
+ return tonga_write_smc_sram_dword(hwmgr->smumgr,
+ data->arb_table_start, tmp, data->sram_end);
+}
+
+int tonga_populate_mc_reg_address(struct pp_hwmgr *hwmgr, SMU72_Discrete_MCRegisters *mc_reg_table)
+{
+ const struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ uint32_t i, j;
+
+ for (i = 0, j = 0; j < data->tonga_mc_reg_table.last; j++) {
+ if (data->tonga_mc_reg_table.validflag & 1<<j) {
+ PP_ASSERT_WITH_CODE(i < SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE,
+ "Index of mc_reg_table->address[] array out of boundary", return -1);
+ mc_reg_table->address[i].s0 =
+ PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s0);
+ mc_reg_table->address[i].s1 =
+ PP_HOST_TO_SMC_US(data->tonga_mc_reg_table.mc_reg_address[j].s1);
+ i++;
+ }
+ }
+
+ mc_reg_table->last = (uint8_t)i;
+
+ return 0;
+}
+
+/*convert register values from driver to SMC format */
+void tonga_convert_mc_registers(
+ const phw_tonga_mc_reg_entry * pEntry,
+ SMU72_Discrete_MCRegisterSet *pData,
+ uint32_t numEntries, uint32_t validflag)
+{
+ uint32_t i, j;
+
+ for (i = 0, j = 0; j < numEntries; j++) {
+ if (validflag & 1<<j) {
+ pData->value[i] = PP_HOST_TO_SMC_UL(pEntry->mc_data[j]);
+ i++;
+ }
+ }
+}
+
+/* find the entry in the memory range table, then populate the value to SMC's tonga_mc_reg_table */
+int tonga_convert_mc_reg_table_entry_to_smc(
+ struct pp_hwmgr *hwmgr,
+ const uint32_t memory_clock,
+ SMU72_Discrete_MCRegisterSet *mc_reg_table_data
+ )
+{
+ const tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ uint32_t i = 0;
+
+ for (i = 0; i < data->tonga_mc_reg_table.num_entries; i++) {
+ if (memory_clock <=
+ data->tonga_mc_reg_table.mc_reg_table_entry[i].mclk_max) {
+ break;
+ }
+ }
+
+ if ((i == data->tonga_mc_reg_table.num_entries) && (i > 0))
+ --i;
+
+ tonga_convert_mc_registers(&data->tonga_mc_reg_table.mc_reg_table_entry[i],
+ mc_reg_table_data, data->tonga_mc_reg_table.last, data->tonga_mc_reg_table.validflag);
+
+ return 0;
+}
+
+int tonga_convert_mc_reg_table_to_smc(struct pp_hwmgr *hwmgr,
+ SMU72_Discrete_MCRegisters *mc_reg_table)
+{
+ int result = 0;
+ tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ int res;
+ uint32_t i;
+
+ for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
+ res = tonga_convert_mc_reg_table_entry_to_smc(
+ hwmgr,
+ data->dpm_table.mclk_table.dpm_levels[i].value,
+ &mc_reg_table->data[i]
+ );
+
+ if (0 != res)
+ result = res;
+ }
+
+ return result;
+}
+
+int tonga_populate_initial_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+ int result;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ memset(&data->mc_reg_table, 0x00, sizeof(SMU72_Discrete_MCRegisters));
+ result = tonga_populate_mc_reg_address(hwmgr, &(data->mc_reg_table));
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize MCRegTable for the MC register addresses!", return result;);
+
+ result = tonga_convert_mc_reg_table_to_smc(hwmgr, &data->mc_reg_table);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "Failed to initialize MCRegTable for driver state!", return result;);
+
+ return tonga_copy_bytes_to_smc(hwmgr->smumgr, data->mc_reg_table_start,
+ (uint8_t *)&data->mc_reg_table, sizeof(SMU72_Discrete_MCRegisters), data->sram_end);
+}
+
+/**
+ * Programs static screed detection parameters
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_program_static_screen_threshold_parameters(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* Set static screen threshold unit*/
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT,
+ data->static_screen_threshold_unit);
+ /* Set static screen threshold*/
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__SMC, CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD,
+ data->static_screen_threshold);
+
+ return 0;
+}
+
+/**
+ * Setup display gap for glitch free memory clock switching.
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_enable_display_gap(struct pp_hwmgr *hwmgr)
+{
+ uint32_t display_gap = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+
+ display_gap = PHM_SET_FIELD(display_gap,
+ CG_DISPLAY_GAP_CNTL, DISP_GAP, DISPLAY_GAP_IGNORE);
+
+ display_gap = PHM_SET_FIELD(display_gap,
+ CG_DISPLAY_GAP_CNTL, DISP_GAP_MCHG, DISPLAY_GAP_VBLANK);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+ return 0;
+}
+
+/**
+ * Programs activity state transition voting clients
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return always 0
+ */
+int tonga_program_voting_clients(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data = (tonga_hwmgr *)(hwmgr->backend);
+
+ /* Clear reset for voting clients before enabling DPM */
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
+
+ return 0;
+}
+
+
+int tonga_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = tonga_check_for_dpm_stopped(hwmgr);
+
+ if (cf_tonga_voltage_control(hwmgr)) {
+ tmp_result = tonga_enable_voltage_control(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable voltage control!", result = tmp_result);
+
+ tmp_result = tonga_construct_voltage_tables(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to contruct voltage tables!", result = tmp_result);
+ }
+
+ tmp_result = tonga_initialize_mc_reg_table(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize MC reg table!", result = tmp_result);
+
+ tmp_result = tonga_program_static_screen_threshold_parameters(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to program static screen threshold parameters!", result = tmp_result);
+
+ tmp_result = tonga_enable_display_gap(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable display gap!", result = tmp_result);
+
+ tmp_result = tonga_program_voting_clients(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to program voting clients!", result = tmp_result);
+
+ tmp_result = tonga_process_firmware_header(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to process firmware header!", result = tmp_result);
+
+ tmp_result = tonga_initial_switch_from_arb_f0_to_f1(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize switch from ArbF0 to F1!", result = tmp_result);
+
+ tmp_result = tonga_init_smc_table(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize SMC table!", result = tmp_result);
+
+ tmp_result = tonga_init_arb_table_index(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to initialize ARB table index!", result = tmp_result);
+
+ tmp_result = tonga_populate_initial_mc_reg_table(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to populate initialize MC Reg table!", result = tmp_result);
+
+ tmp_result = tonga_notify_smc_display_change(hwmgr, false);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to notify no display!", result = tmp_result);
+
+ /* enable SCLK control */
+ tmp_result = tonga_enable_sclk_control(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to enable SCLK control!", result = tmp_result);
+
+ /* enable DPM */
+ tmp_result = tonga_start_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to start DPM!", result = tmp_result);
+
+ return result;
+}
+
+int tonga_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = tonga_check_for_dpm_running(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "SMC is still running!", return 0);
+
+ tmp_result = tonga_stop_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to stop DPM!", result = tmp_result);
+
+ tmp_result = tonga_reset_to_default(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result),
+ "Failed to reset to default!", result = tmp_result);
+
+ return result;
+}
+
+int tonga_reset_asic_tasks(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ result = tonga_set_boot_state(hwmgr);
+ if (0 != result)
+ printk(KERN_ERR "[ powerplay ] Failed to reset asic via set boot state! \n");
+
+ return result;
+}
+
+int tonga_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
+{
+ if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
+ kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
+ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
+ }
+
+ if (NULL != hwmgr->backend) {
+ kfree(hwmgr->backend);
+ hwmgr->backend = NULL;
+ }
+
+ return 0;
+}
+
+/**
+ * Initializes the Volcanic Islands Hardware Manager
+ *
+ * @param hwmgr the address of the powerplay hardware manager.
+ * @return 1 if success; otherwise appropriate error code.
+ */
+int tonga_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+ SMU72_Discrete_DpmTable *table = NULL;
+ tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ phw_tonga_ulv_parm *ulv;
+
+ PP_ASSERT_WITH_CODE((NULL != hwmgr),
+ "Invalid Parameter!", return -1;);
+
+ data->dll_defaule_on = 0;
+ data->sram_end = SMC_RAM_END;
+
+ data->activity_target[0] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[1] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[2] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[3] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[4] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[5] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[6] = PPTONGA_TARGETACTIVITY_DFLT;
+ data->activity_target[7] = PPTONGA_TARGETACTIVITY_DFLT;
+
+ data->vddc_vddci_delta = VDDC_VDDCI_DELTA;
+ data->vddc_vddgfx_delta = VDDC_VDDGFX_DELTA;
+ data->mclk_activity_target = PPTONGA_MCLK_TARGETACTIVITY_DFLT;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DisableVoltageIsland);
+
+ data->sclk_dpm_key_disabled = 0;
+ data->mclk_dpm_key_disabled = 0;
+ data->pcie_dpm_key_disabled = 0;
+ data->pcc_monitor_enabled = 0;
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_UnTabledHardwareInterface);
+
+ data->gpio_debug = 0;
+ data->engine_clock_data = 0;
+ data->memory_clock_data = 0;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DynamicPatchPowerState);
+
+ /* need to set voltage control types before EVV patching*/
+ data->voltage_control = TONGA_VOLTAGE_CONTROL_NONE;
+ data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_NONE;
+ data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_NONE;
+ data->mvdd_control = TONGA_VOLTAGE_CONTROL_NONE;
+
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2)) {
+ data->voltage_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ControlVDDGFX)) {
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
+ data->vdd_gfx_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
+ }
+ }
+
+ if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ControlVDDGFX);
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableMVDDControl)) {
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT)) {
+ data->mvdd_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
+ }
+ }
+
+ if (TONGA_VOLTAGE_CONTROL_NONE == data->mvdd_control) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableMVDDControl);
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ControlVDDCI)) {
+ if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
+ data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_GPIO;
+ else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
+ VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
+ data->vdd_ci_control = TONGA_VOLTAGE_CONTROL_BY_SVID2;
+ }
+
+ if (TONGA_VOLTAGE_CONTROL_NONE == data->vdd_ci_control)
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ControlVDDCI);
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_TablelessHardwareInterface);
+
+ if (pptable_info->cac_dtp_table->usClockStretchAmount != 0)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ClockStretcher);
+
+ /* Initializes DPM default values*/
+ tonga_initialize_dpm_defaults(hwmgr);
+
+ /* Get leakage voltage based on leakage ID.*/
+ PP_ASSERT_WITH_CODE((0 == tonga_get_evv_voltage(hwmgr)),
+ "Get EVV Voltage Failed. Abort Driver loading!", return -1);
+
+ tonga_complete_dependency_tables(hwmgr);
+
+ /* Parse pptable data read from VBIOS*/
+ tonga_set_private_var_based_on_pptale(hwmgr);
+
+ /* ULV Support*/
+ ulv = &(data->ulv);
+ ulv->ulv_supported = 0;
+
+ /* Initalize Dynamic State Adjustment Rule Settings*/
+ result = tonga_initializa_dynamic_state_adjustment_rule_settings(hwmgr);
+ if (result)
+ printk(KERN_ERR "[ powerplay ] tonga_initializa_dynamic_state_adjustment_rule_settings failed!\n");
+ data->uvd_enabled = 0;
+
+ table = &(data->smc_state_table);
+
+ /*
+ * if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable,
+ * Peak Current Control feature is enabled and we should program PCC HW register
+ */
+ if (0 == atomctrl_get_pp_assign_pin(hwmgr, VDDC_PCC_GPIO_PINID, &gpio_pin_assignment)) {
+ uint32_t temp_reg = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__SMC, ixCNB_PWRMGT_CNTL);
+
+ switch (gpio_pin_assignment.uc_gpio_pin_bit_shift) {
+ case 0:
+ temp_reg = PHM_SET_FIELD(temp_reg,
+ CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x1);
+ break;
+ case 1:
+ temp_reg = PHM_SET_FIELD(temp_reg,
+ CNB_PWRMGT_CNTL, GNB_SLOW_MODE, 0x2);
+ break;
+ case 2:
+ temp_reg = PHM_SET_FIELD(temp_reg,
+ CNB_PWRMGT_CNTL, GNB_SLOW, 0x1);
+ break;
+ case 3:
+ temp_reg = PHM_SET_FIELD(temp_reg,
+ CNB_PWRMGT_CNTL, FORCE_NB_PS1, 0x1);
+ break;
+ case 4:
+ temp_reg = PHM_SET_FIELD(temp_reg,
+ CNB_PWRMGT_CNTL, DPM_ENABLED, 0x1);
+ break;
+ default:
+ printk(KERN_ERR "[ powerplay ] Failed to setup PCC HW register! \
+ Wrong GPIO assigned for VDDC_PCC_GPIO_PINID! \n");
+ break;
+ }
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+ ixCNB_PWRMGT_CNTL, temp_reg);
+ }
+
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnableSMU7ThermalManagement);
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_SMU7);
+
+ data->vddc_phase_shed_control = 0;
+
+ if (0 == result) {
+ struct cgs_system_info sys_info = {0};
+
+ data->is_tlu_enabled = 0;
+ hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
+ TONGA_MAX_HARDWARE_POWERLEVELS;
+ hwmgr->platform_descriptor.hardwarePerformanceLevels = 2;
+ hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
+
+ sys_info.size = sizeof(struct cgs_system_info);
+ sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
+ result = cgs_query_system_info(hwmgr->device, &sys_info);
+ if (result)
+ data->pcie_gen_cap = 0x30007;
+ else
+ data->pcie_gen_cap = (uint32_t)sys_info.value;
+ if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+ data->pcie_spc_cap = 20;
+ sys_info.size = sizeof(struct cgs_system_info);
+ sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
+ result = cgs_query_system_info(hwmgr->device, &sys_info);
+ if (result)
+ data->pcie_lane_cap = 0x2f0000;
+ else
+ data->pcie_lane_cap = (uint32_t)sys_info.value;
+ } else {
+ /* Ignore return value in here, we are cleaning up a mess. */
+ tonga_hwmgr_backend_fini(hwmgr);
+ }
+
+ return result;
+}
+
+static int tonga_force_dpm_level(struct pp_hwmgr *hwmgr,
+ enum amd_dpm_forced_level level)
+{
+ int ret = 0;
+
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_HIGH:
+ ret = tonga_force_dpm_highest(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_LOW:
+ ret = tonga_force_dpm_lowest(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ ret = tonga_unforce_dpm_levels(hwmgr);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ hwmgr->dpm_level = level;
+ return ret;
+}
+
+static int tonga_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *prequest_ps,
+ const struct pp_power_state *pcurrent_ps)
+{
+ struct tonga_power_state *tonga_ps =
+ cast_phw_tonga_power_state(&prequest_ps->hardware);
+
+ uint32_t sclk;
+ uint32_t mclk;
+ struct PP_Clocks minimum_clocks = {0};
+ bool disable_mclk_switching;
+ bool disable_mclk_switching_for_frame_lock;
+ struct cgs_display_info info = {0};
+ const struct phm_clock_and_voltage_limits *max_limits;
+ uint32_t i;
+ tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ int32_t count;
+ int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
+
+ data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
+
+ PP_ASSERT_WITH_CODE(tonga_ps->performance_level_count == 2,
+ "VI should always have 2 performance levels",
+ );
+
+ max_limits = (PP_PowerSource_AC == hwmgr->power_source) ?
+ &(hwmgr->dyn_state.max_clock_voltage_on_ac) :
+ &(hwmgr->dyn_state.max_clock_voltage_on_dc);
+
+ if (PP_PowerSource_DC == hwmgr->power_source) {
+ for (i = 0; i < tonga_ps->performance_level_count; i++) {
+ if (tonga_ps->performance_levels[i].memory_clock > max_limits->mclk)
+ tonga_ps->performance_levels[i].memory_clock = max_limits->mclk;
+ if (tonga_ps->performance_levels[i].engine_clock > max_limits->sclk)
+ tonga_ps->performance_levels[i].engine_clock = max_limits->sclk;
+ }
+ }
+
+ tonga_ps->vce_clocks.EVCLK = hwmgr->vce_arbiter.evclk;
+ tonga_ps->vce_clocks.ECCLK = hwmgr->vce_arbiter.ecclk;
+
+ tonga_ps->acp_clk = hwmgr->acp_arbiter.acpclk;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+
+ /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
+
+ /* TO DO GetMinClockSettings(hwmgr->pPECI, &minimum_clocks); */
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
+
+ max_limits = &(hwmgr->dyn_state.max_clock_voltage_on_ac);
+ stable_pstate_sclk = (max_limits->sclk * 75) / 100;
+
+ for (count = pptable_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
+ if (stable_pstate_sclk >= pptable_info->vdd_dep_on_sclk->entries[count].clk) {
+ stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[count].clk;
+ break;
+ }
+ }
+
+ if (count < 0)
+ stable_pstate_sclk = pptable_info->vdd_dep_on_sclk->entries[0].clk;
+
+ stable_pstate_mclk = max_limits->mclk;
+
+ minimum_clocks.engineClock = stable_pstate_sclk;
+ minimum_clocks.memoryClock = stable_pstate_mclk;
+ }
+
+ if (minimum_clocks.engineClock < hwmgr->gfx_arbiter.sclk)
+ minimum_clocks.engineClock = hwmgr->gfx_arbiter.sclk;
+
+ if (minimum_clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
+ minimum_clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
+
+ tonga_ps->sclk_threshold = hwmgr->gfx_arbiter.sclk_threshold;
+
+ if (0 != hwmgr->gfx_arbiter.sclk_over_drive) {
+ PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.sclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.engineClock),
+ "Overdrive sclk exceeds limit",
+ hwmgr->gfx_arbiter.sclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.engineClock);
+
+ if (hwmgr->gfx_arbiter.sclk_over_drive >= hwmgr->gfx_arbiter.sclk)
+ tonga_ps->performance_levels[1].engine_clock = hwmgr->gfx_arbiter.sclk_over_drive;
+ }
+
+ if (0 != hwmgr->gfx_arbiter.mclk_over_drive) {
+ PP_ASSERT_WITH_CODE((hwmgr->gfx_arbiter.mclk_over_drive <= hwmgr->platform_descriptor.overdriveLimit.memoryClock),
+ "Overdrive mclk exceeds limit",
+ hwmgr->gfx_arbiter.mclk_over_drive = hwmgr->platform_descriptor.overdriveLimit.memoryClock);
+
+ if (hwmgr->gfx_arbiter.mclk_over_drive >= hwmgr->gfx_arbiter.mclk)
+ tonga_ps->performance_levels[1].memory_clock = hwmgr->gfx_arbiter.mclk_over_drive;
+ }
+
+ disable_mclk_switching_for_frame_lock = phm_cap_enabled(
+ hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
+
+ disable_mclk_switching = (1 < info.display_count) ||
+ disable_mclk_switching_for_frame_lock;
+
+ sclk = tonga_ps->performance_levels[0].engine_clock;
+ mclk = tonga_ps->performance_levels[0].memory_clock;
+
+ if (disable_mclk_switching)
+ mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count - 1].memory_clock;
+
+ if (sclk < minimum_clocks.engineClock)
+ sclk = (minimum_clocks.engineClock > max_limits->sclk) ? max_limits->sclk : minimum_clocks.engineClock;
+
+ if (mclk < minimum_clocks.memoryClock)
+ mclk = (minimum_clocks.memoryClock > max_limits->mclk) ? max_limits->mclk : minimum_clocks.memoryClock;
+
+ tonga_ps->performance_levels[0].engine_clock = sclk;
+ tonga_ps->performance_levels[0].memory_clock = mclk;
+
+ tonga_ps->performance_levels[1].engine_clock =
+ (tonga_ps->performance_levels[1].engine_clock >= tonga_ps->performance_levels[0].engine_clock) ?
+ tonga_ps->performance_levels[1].engine_clock :
+ tonga_ps->performance_levels[0].engine_clock;
+
+ if (disable_mclk_switching) {
+ if (mclk < tonga_ps->performance_levels[1].memory_clock)
+ mclk = tonga_ps->performance_levels[1].memory_clock;
+
+ tonga_ps->performance_levels[0].memory_clock = mclk;
+ tonga_ps->performance_levels[1].memory_clock = mclk;
+ } else {
+ if (tonga_ps->performance_levels[1].memory_clock < tonga_ps->performance_levels[0].memory_clock)
+ tonga_ps->performance_levels[1].memory_clock = tonga_ps->performance_levels[0].memory_clock;
+ }
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) {
+ for (i=0; i < tonga_ps->performance_level_count; i++) {
+ tonga_ps->performance_levels[i].engine_clock = stable_pstate_sclk;
+ tonga_ps->performance_levels[i].memory_clock = stable_pstate_mclk;
+ tonga_ps->performance_levels[i].pcie_gen = data->pcie_gen_performance.max;
+ tonga_ps->performance_levels[i].pcie_lane = data->pcie_gen_performance.max;
+ }
+ }
+
+ return 0;
+}
+
+int tonga_get_power_state_size(struct pp_hwmgr *hwmgr)
+{
+ return sizeof(struct tonga_power_state);
+}
+
+static int tonga_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
+{
+ struct pp_power_state *ps;
+ struct tonga_power_state *tonga_ps;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
+
+ if (low)
+ return tonga_ps->performance_levels[0].memory_clock;
+ else
+ return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
+}
+
+static int tonga_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
+{
+ struct pp_power_state *ps;
+ struct tonga_power_state *tonga_ps;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ ps = hwmgr->request_ps;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ tonga_ps = cast_phw_tonga_power_state(&ps->hardware);
+
+ if (low)
+ return tonga_ps->performance_levels[0].engine_clock;
+ else
+ return tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
+}
+
+static uint16_t tonga_get_current_pcie_speed(
+ struct pp_hwmgr *hwmgr)
+{
+ uint32_t speed_cntl = 0;
+
+ speed_cntl = cgs_read_ind_register(hwmgr->device,
+ CGS_IND_REG__PCIE,
+ ixPCIE_LC_SPEED_CNTL);
+ return((uint16_t)PHM_GET_FIELD(speed_cntl,
+ PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE));
+}
+
+static int tonga_get_current_pcie_lane_number(
+ struct pp_hwmgr *hwmgr)
+{
+ uint32_t link_width;
+
+ link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device,
+ CGS_IND_REG__PCIE,
+ PCIE_LC_LINK_WIDTH_CNTL,
+ LC_LINK_WIDTH_RD);
+
+ PP_ASSERT_WITH_CODE((7 >= link_width),
+ "Invalid PCIe lane width!", return 0);
+
+ return decode_pcie_lane_width(link_width);
+}
+
+static int tonga_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
+ struct pp_hw_power_state *hw_ps)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ struct tonga_power_state *ps = (struct tonga_power_state *)hw_ps;
+ ATOM_FIRMWARE_INFO_V2_2 *fw_info;
+ uint16_t size;
+ uint8_t frev, crev;
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+ /* First retrieve the Boot clocks and VDDC from the firmware info table.
+ * We assume here that fw_info is unchanged if this call fails.
+ */
+ fw_info = (ATOM_FIRMWARE_INFO_V2_2 *)cgs_atom_get_data_table(
+ hwmgr->device, index,
+ &size, &frev, &crev);
+ if (!fw_info)
+ /* During a test, there is no firmware info table. */
+ return 0;
+
+ /* Patch the state. */
+ data->vbios_boot_state.sclk_bootup_value = le32_to_cpu(fw_info->ulDefaultEngineClock);
+ data->vbios_boot_state.mclk_bootup_value = le32_to_cpu(fw_info->ulDefaultMemoryClock);
+ data->vbios_boot_state.mvdd_bootup_value = le16_to_cpu(fw_info->usBootUpMVDDCVoltage);
+ data->vbios_boot_state.vddc_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCVoltage);
+ data->vbios_boot_state.vddci_bootup_value = le16_to_cpu(fw_info->usBootUpVDDCIVoltage);
+ data->vbios_boot_state.pcie_gen_bootup_value = tonga_get_current_pcie_speed(hwmgr);
+ data->vbios_boot_state.pcie_lane_bootup_value =
+ (uint16_t)tonga_get_current_pcie_lane_number(hwmgr);
+
+ /* set boot power state */
+ ps->performance_levels[0].memory_clock = data->vbios_boot_state.mclk_bootup_value;
+ ps->performance_levels[0].engine_clock = data->vbios_boot_state.sclk_bootup_value;
+ ps->performance_levels[0].pcie_gen = data->vbios_boot_state.pcie_gen_bootup_value;
+ ps->performance_levels[0].pcie_lane = data->vbios_boot_state.pcie_lane_bootup_value;
+
+ return 0;
+}
+
+static int tonga_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr,
+ void *state, struct pp_power_state *power_state,
+ void *pp_table, uint32_t classification_flag)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ struct tonga_power_state *tonga_ps =
+ (struct tonga_power_state *)(&(power_state->hardware));
+
+ struct tonga_performance_level *performance_level;
+
+ ATOM_Tonga_State *state_entry = (ATOM_Tonga_State *)state;
+
+ ATOM_Tonga_POWERPLAYTABLE *powerplay_table =
+ (ATOM_Tonga_POWERPLAYTABLE *)pp_table;
+
+ ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
+ (ATOM_Tonga_SCLK_Dependency_Table *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+
+ ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+ (ATOM_Tonga_MCLK_Dependency_Table *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+
+ /* The following fields are not initialized here: id orderedList allStatesList */
+ power_state->classification.ui_label =
+ (le16_to_cpu(state_entry->usClassification) &
+ ATOM_PPLIB_CLASSIFICATION_UI_MASK) >>
+ ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
+ power_state->classification.flags = classification_flag;
+ /* NOTE: There is a classification2 flag in BIOS that is not being used right now */
+
+ power_state->classification.temporary_state = false;
+ power_state->classification.to_be_deleted = false;
+
+ power_state->validation.disallowOnDC =
+ (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_DISALLOW_ON_DC));
+
+ power_state->pcie.lanes = 0;
+
+ power_state->display.disableFrameModulation = false;
+ power_state->display.limitRefreshrate = false;
+ power_state->display.enableVariBright =
+ (0 != (le32_to_cpu(state_entry->ulCapsAndSettings) & ATOM_Tonga_ENABLE_VARIBRIGHT));
+
+ power_state->validation.supportedPowerLevels = 0;
+ power_state->uvd_clocks.VCLK = 0;
+ power_state->uvd_clocks.DCLK = 0;
+ power_state->temperatures.min = 0;
+ power_state->temperatures.max = 0;
+
+ performance_level = &(tonga_ps->performance_levels
+ [tonga_ps->performance_level_count++]);
+
+ PP_ASSERT_WITH_CODE(
+ (tonga_ps->performance_level_count < SMU72_MAX_LEVELS_GRAPHICS),
+ "Performance levels exceeds SMC limit!",
+ return -1);
+
+ PP_ASSERT_WITH_CODE(
+ (tonga_ps->performance_level_count <=
+ hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
+ "Performance levels exceeds Driver limit!",
+ return -1);
+
+ /* Performance levels are arranged from low to high. */
+ performance_level->memory_clock =
+ le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexLow].ulMclk);
+
+ performance_level->engine_clock =
+ le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexLow].ulSclk);
+
+ performance_level->pcie_gen = get_pcie_gen_support(
+ data->pcie_gen_cap,
+ state_entry->ucPCIEGenLow);
+
+ performance_level->pcie_lane = get_pcie_lane_support(
+ data->pcie_lane_cap,
+ state_entry->ucPCIELaneHigh);
+
+ performance_level =
+ &(tonga_ps->performance_levels[tonga_ps->performance_level_count++]);
+
+ performance_level->memory_clock =
+ le32_to_cpu(mclk_dep_table->entries[state_entry->ucMemoryClockIndexHigh].ulMclk);
+
+ performance_level->engine_clock =
+ le32_to_cpu(sclk_dep_table->entries[state_entry->ucEngineClockIndexHigh].ulSclk);
+
+ performance_level->pcie_gen = get_pcie_gen_support(
+ data->pcie_gen_cap,
+ state_entry->ucPCIEGenHigh);
+
+ performance_level->pcie_lane = get_pcie_lane_support(
+ data->pcie_lane_cap,
+ state_entry->ucPCIELaneHigh);
+
+ return 0;
+}
+
+static int tonga_get_pp_table_entry(struct pp_hwmgr *hwmgr,
+ unsigned long entry_index, struct pp_power_state *ps)
+{
+ int result;
+ struct tonga_power_state *tonga_ps;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table =
+ table_info->vdd_dep_on_mclk;
+
+ ps->hardware.magic = PhwTonga_Magic;
+
+ tonga_ps = cast_phw_tonga_power_state(&(ps->hardware));
+
+ result = tonga_get_powerplay_table_entry(hwmgr, entry_index, ps,
+ tonga_get_pp_table_entry_callback_func);
+
+ /* This is the earliest time we have all the dependency table and the VBIOS boot state
+ * as PP_Tables_GetPowerPlayTableEntry retrieves the VBIOS boot state
+ * if there is only one VDDCI/MCLK level, check if it's the same as VBIOS boot state
+ */
+ if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
+ if (dep_mclk_table->entries[0].clk !=
+ data->vbios_boot_state.mclk_bootup_value)
+ printk(KERN_ERR "Single MCLK entry VDDCI/MCLK dependency table "
+ "does not match VBIOS boot MCLK level");
+ if (dep_mclk_table->entries[0].vddci !=
+ data->vbios_boot_state.vddci_bootup_value)
+ printk(KERN_ERR "Single VDDCI entry VDDCI/MCLK dependency table "
+ "does not match VBIOS boot VDDCI level");
+ }
+
+ /* set DC compatible flag if this state supports DC */
+ if (!ps->validation.disallowOnDC)
+ tonga_ps->dc_compatible = true;
+
+ if (ps->classification.flags & PP_StateClassificationFlag_ACPI)
+ data->acpi_pcie_gen = tonga_ps->performance_levels[0].pcie_gen;
+ else if (ps->classification.flags & PP_StateClassificationFlag_Boot) {
+ if (data->bacos.best_match == 0xffff) {
+ /* For V.I. use boot state as base BACO state */
+ data->bacos.best_match = PP_StateClassificationFlag_Boot;
+ data->bacos.performance_level = tonga_ps->performance_levels[0];
+ }
+ }
+
+ tonga_ps->uvd_clocks.VCLK = ps->uvd_clocks.VCLK;
+ tonga_ps->uvd_clocks.DCLK = ps->uvd_clocks.DCLK;
+
+ if (!result) {
+ uint32_t i;
+
+ switch (ps->classification.ui_label) {
+ case PP_StateUILabel_Performance:
+ data->use_pcie_performance_levels = true;
+
+ for (i = 0; i < tonga_ps->performance_level_count; i++) {
+ if (data->pcie_gen_performance.max <
+ tonga_ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_performance.max =
+ tonga_ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_gen_performance.min >
+ tonga_ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_performance.min =
+ tonga_ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_lane_performance.max <
+ tonga_ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_performance.max =
+ tonga_ps->performance_levels[i].pcie_lane;
+
+ if (data->pcie_lane_performance.min >
+ tonga_ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_performance.min =
+ tonga_ps->performance_levels[i].pcie_lane;
+ }
+ break;
+ case PP_StateUILabel_Battery:
+ data->use_pcie_power_saving_levels = true;
+
+ for (i = 0; i < tonga_ps->performance_level_count; i++) {
+ if (data->pcie_gen_power_saving.max <
+ tonga_ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_power_saving.max =
+ tonga_ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_gen_power_saving.min >
+ tonga_ps->performance_levels[i].pcie_gen)
+ data->pcie_gen_power_saving.min =
+ tonga_ps->performance_levels[i].pcie_gen;
+
+ if (data->pcie_lane_power_saving.max <
+ tonga_ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_power_saving.max =
+ tonga_ps->performance_levels[i].pcie_lane;
+
+ if (data->pcie_lane_power_saving.min >
+ tonga_ps->performance_levels[i].pcie_lane)
+ data->pcie_lane_power_saving.min =
+ tonga_ps->performance_levels[i].pcie_lane;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static void
+tonga_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
+{
+ uint32_t sclk, mclk, activity_percent;
+ uint32_t offset;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetSclkFrequency));
+
+ sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+
+ smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)(PPSMC_MSG_API_GetMclkFrequency));
+
+ mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
+ seq_printf(m, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk/100, sclk/100);
+
+
+ offset = data->soft_regs_start + offsetof(SMU72_SoftRegisters, AverageGraphicsActivity);
+ activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset);
+ activity_percent += 0x80;
+ activity_percent >>= 8;
+
+ seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent);
+
+}
+
+static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+ const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ struct tonga_single_dpm_table *psclk_table = &(data->dpm_table.sclk_table);
+ uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
+ struct tonga_single_dpm_table *pmclk_table = &(data->dpm_table.mclk_table);
+ uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
+ struct PP_Clocks min_clocks = {0};
+ uint32_t i;
+ struct cgs_display_info info = {0};
+
+ data->need_update_smu7_dpm_table = 0;
+
+ for (i = 0; i < psclk_table->count; i++) {
+ if (sclk == psclk_table->dpm_levels[i].value)
+ break;
+ }
+
+ if (i >= psclk_table->count)
+ data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+ else {
+ /* TODO: Check SCLK in DAL's minimum clocks in case DeepSleep divider update is required.*/
+ if(data->display_timing.min_clock_insr != min_clocks.engineClockInSR)
+ data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
+ }
+
+ for (i=0; i < pmclk_table->count; i++) {
+ if (mclk == pmclk_table->dpm_levels[i].value)
+ break;
+ }
+
+ if (i >= pmclk_table->count)
+ data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+
+ if (data->display_timing.num_existing_displays != info.display_count)
+ data->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
+
+ return 0;
+}
+
+static uint16_t tonga_get_maximum_link_speed(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_ps)
+{
+ uint32_t i;
+ uint32_t sclk, max_sclk = 0;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ struct tonga_dpm_table *pdpm_table = &data->dpm_table;
+
+ for (i = 0; i < hw_ps->performance_level_count; i++) {
+ sclk = hw_ps->performance_levels[i].engine_clock;
+ if (max_sclk < sclk)
+ max_sclk = sclk;
+ }
+
+ for (i = 0; i < pdpm_table->sclk_table.count; i++) {
+ if (pdpm_table->sclk_table.dpm_levels[i].value == max_sclk)
+ return (uint16_t) ((i >= pdpm_table->pcie_speed_table.count) ?
+ pdpm_table->pcie_speed_table.dpm_levels[pdpm_table->pcie_speed_table.count-1].value :
+ pdpm_table->pcie_speed_table.dpm_levels[i].value);
+ }
+
+ return 0;
+}
+
+static int tonga_request_link_speed_change_before_state_change(struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
+ const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
+
+ uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_nps);
+ uint16_t current_link_speed;
+
+ if (data->force_pcie_gen == PP_PCIEGenInvalid)
+ current_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_cps);
+ else
+ current_link_speed = data->force_pcie_gen;
+
+ data->force_pcie_gen = PP_PCIEGenInvalid;
+ data->pspp_notify_required = false;
+ if (target_link_speed > current_link_speed) {
+ switch(target_link_speed) {
+ case PP_PCIEGen3:
+ if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false))
+ break;
+ data->force_pcie_gen = PP_PCIEGen2;
+ if (current_link_speed == PP_PCIEGen2)
+ break;
+ case PP_PCIEGen2:
+ if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false))
+ break;
+ default:
+ data->force_pcie_gen = tonga_get_current_pcie_speed(hwmgr);
+ break;
+ }
+ } else {
+ if (target_link_speed < current_link_speed)
+ data->pspp_notify_required = true;
+ }
+
+ return 0;
+}
+
+static int tonga_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ if (0 == data->need_update_smu7_dpm_table)
+ return 0;
+
+ if ((0 == data->sclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+ PP_ASSERT_WITH_CODE(
+ true == tonga_is_dpm_running(hwmgr),
+ "Trying to freeze SCLK DPM when DPM is disabled",
+ );
+ PP_ASSERT_WITH_CODE(
+ 0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_FreezeLevel),
+ "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ if ((0 == data->mclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table &
+ DPMTABLE_OD_UPDATE_MCLK)) {
+ PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr),
+ "Trying to freeze MCLK DPM when DPM is disabled",
+ );
+ PP_ASSERT_WITH_CODE(
+ 0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_MCLKDPM_FreezeLevel),
+ "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ return 0;
+}
+
+static int tonga_populate_and_upload_sclk_mclk_dpm_levels(struct pp_hwmgr *hwmgr, const void *input)
+{
+ int result = 0;
+
+ const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+ const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ uint32_t sclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].engine_clock;
+ uint32_t mclk = tonga_ps->performance_levels[tonga_ps->performance_level_count-1].memory_clock;
+ struct tonga_dpm_table *pdpm_table = &data->dpm_table;
+
+ struct tonga_dpm_table *pgolden_dpm_table = &data->golden_dpm_table;
+ uint32_t dpm_count, clock_percent;
+ uint32_t i;
+
+ if (0 == data->need_update_smu7_dpm_table)
+ return 0;
+
+ if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) {
+ pdpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value = sclk;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
+ /* Need to do calculation based on the golden DPM table
+ * as the Heatmap GPU Clock axis is also based on the default values
+ */
+ PP_ASSERT_WITH_CODE(
+ (pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value != 0),
+ "Divide by 0!",
+ return -1);
+ dpm_count = pdpm_table->sclk_table.count < 2 ? 0 : pdpm_table->sclk_table.count-2;
+ for (i = dpm_count; i > 1; i--) {
+ if (sclk > pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value) {
+ clock_percent = ((sclk - pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value)*100) /
+ pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
+
+ pdpm_table->sclk_table.dpm_levels[i].value =
+ pgolden_dpm_table->sclk_table.dpm_levels[i].value +
+ (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
+
+ } else if (pgolden_dpm_table->sclk_table.dpm_levels[pdpm_table->sclk_table.count-1].value > sclk) {
+ clock_percent = ((pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value - sclk)*100) /
+ pgolden_dpm_table->sclk_table.dpm_levels[pgolden_dpm_table->sclk_table.count-1].value;
+
+ pdpm_table->sclk_table.dpm_levels[i].value =
+ pgolden_dpm_table->sclk_table.dpm_levels[i].value -
+ (pgolden_dpm_table->sclk_table.dpm_levels[i].value * clock_percent)/100;
+ } else
+ pdpm_table->sclk_table.dpm_levels[i].value =
+ pgolden_dpm_table->sclk_table.dpm_levels[i].value;
+ }
+ }
+ }
+
+ if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) {
+ pdpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value = mclk;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) ||
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) {
+
+ PP_ASSERT_WITH_CODE(
+ (pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value != 0),
+ "Divide by 0!",
+ return -1);
+ dpm_count = pdpm_table->mclk_table.count < 2? 0 : pdpm_table->mclk_table.count-2;
+ for (i = dpm_count; i > 1; i--) {
+ if (mclk > pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value) {
+ clock_percent = ((mclk - pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value)*100) /
+ pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
+
+ pdpm_table->mclk_table.dpm_levels[i].value =
+ pgolden_dpm_table->mclk_table.dpm_levels[i].value +
+ (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
+
+ } else if (pgolden_dpm_table->mclk_table.dpm_levels[pdpm_table->mclk_table.count-1].value > mclk) {
+ clock_percent = ((pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value - mclk)*100) /
+ pgolden_dpm_table->mclk_table.dpm_levels[pgolden_dpm_table->mclk_table.count-1].value;
+
+ pdpm_table->mclk_table.dpm_levels[i].value =
+ pgolden_dpm_table->mclk_table.dpm_levels[i].value -
+ (pgolden_dpm_table->mclk_table.dpm_levels[i].value * clock_percent)/100;
+ } else
+ pdpm_table->mclk_table.dpm_levels[i].value = pgolden_dpm_table->mclk_table.dpm_levels[i].value;
+ }
+ }
+ }
+
+ if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
+ result = tonga_populate_all_memory_levels(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
+ return result);
+ }
+
+ if (data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
+ /*populate MCLK dpm table to SMU7 */
+ result = tonga_populate_all_memory_levels(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == result),
+ "Failed to populate MCLK during PopulateNewDPMClocksStates Function!",
+ return result);
+ }
+
+ return result;
+}
+
+static int tonga_trim_single_dpm_states(struct pp_hwmgr *hwmgr,
+ struct tonga_single_dpm_table * pdpm_table,
+ uint32_t low_limit, uint32_t high_limit)
+{
+ uint32_t i;
+
+ for (i = 0; i < pdpm_table->count; i++) {
+ if ((pdpm_table->dpm_levels[i].value < low_limit) ||
+ (pdpm_table->dpm_levels[i].value > high_limit))
+ pdpm_table->dpm_levels[i].enabled = false;
+ else
+ pdpm_table->dpm_levels[i].enabled = true;
+ }
+ return 0;
+}
+
+static int tonga_trim_dpm_states(struct pp_hwmgr *hwmgr, const struct tonga_power_state *hw_state)
+{
+ int result = 0;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ uint32_t high_limit_count;
+
+ PP_ASSERT_WITH_CODE((hw_state->performance_level_count >= 1),
+ "power state did not have any performance level",
+ return -1);
+
+ high_limit_count = (1 == hw_state->performance_level_count) ? 0: 1;
+
+ tonga_trim_single_dpm_states(hwmgr,
+ &(data->dpm_table.sclk_table),
+ hw_state->performance_levels[0].engine_clock,
+ hw_state->performance_levels[high_limit_count].engine_clock);
+
+ tonga_trim_single_dpm_states(hwmgr,
+ &(data->dpm_table.mclk_table),
+ hw_state->performance_levels[0].memory_clock,
+ hw_state->performance_levels[high_limit_count].memory_clock);
+
+ return result;
+}
+
+static int tonga_generate_dpm_level_enable_mask(struct pp_hwmgr *hwmgr, const void *input)
+{
+ int result;
+ const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+
+ result = tonga_trim_dpm_states(hwmgr, tonga_ps);
+ if (0 != result)
+ return result;
+
+ data->dpm_level_enable_mask.sclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.sclk_table);
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.mclk_table);
+ data->last_mclk_dpm_enable_mask = data->dpm_level_enable_mask.mclk_dpm_enable_mask;
+ if (data->uvd_enabled)
+ data->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
+
+ data->dpm_level_enable_mask.pcie_dpm_enable_mask = tonga_get_dpm_level_enable_mask_value(&data->dpm_table.pcie_speed_table);
+
+ return 0;
+}
+
+int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+ (PPSMC_Msg)PPSMC_MSG_VCEDPM_Enable :
+ (PPSMC_Msg)PPSMC_MSG_VCEDPM_Disable);
+}
+
+int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
+{
+ return smum_send_msg_to_smc(hwmgr->smumgr, enable ?
+ (PPSMC_Msg)PPSMC_MSG_UVDDPM_Enable :
+ (PPSMC_Msg)PPSMC_MSG_UVDDPM_Disable);
+}
+
+int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ uint32_t mm_boot_level_offset, mm_boot_level_value;
+ struct phm_ppt_v1_information *ptable_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (!bgate) {
+ data->smc_state_table.UvdBootLevel = (uint8_t) (ptable_information->mm_dep_table->count - 1);
+ mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, UvdBootLevel);
+ mm_boot_level_offset /= 4;
+ mm_boot_level_offset *= 4;
+ mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
+ mm_boot_level_value &= 0x00FFFFFF;
+ mm_boot_level_value |= data->smc_state_table.UvdBootLevel << 24;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+ if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM) ||
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_UVDDPM_SetEnabledMask,
+ (uint32_t)(1 << data->smc_state_table.UvdBootLevel));
+ }
+
+ return tonga_enable_disable_uvd_dpm(hwmgr, !bgate);
+}
+
+int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ const struct tonga_power_state *tonga_nps = cast_const_phw_tonga_power_state(states->pnew_state);
+ const struct tonga_power_state *tonga_cps = cast_const_phw_tonga_power_state(states->pcurrent_state);
+
+ uint32_t mm_boot_level_offset, mm_boot_level_value;
+ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (tonga_nps->vce_clocks.EVCLK > 0 && (tonga_cps == NULL || tonga_cps->vce_clocks.EVCLK == 0)) {
+ data->smc_state_table.VceBootLevel = (uint8_t) (pptable_info->mm_dep_table->count - 1);
+
+ mm_boot_level_offset = data->dpm_table_start + offsetof(SMU72_Discrete_DpmTable, VceBootLevel);
+ mm_boot_level_offset /= 4;
+ mm_boot_level_offset *= 4;
+ mm_boot_level_value = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset);
+ mm_boot_level_value &= 0xFF00FFFF;
+ mm_boot_level_value |= data->smc_state_table.VceBootLevel << 16;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_VCEDPM_SetEnabledMask,
+ (uint32_t)(1 << data->smc_state_table.VceBootLevel));
+
+ tonga_enable_disable_vce_dpm(hwmgr, true);
+ } else if (tonga_nps->vce_clocks.EVCLK == 0 && tonga_cps != NULL && tonga_cps->vce_clocks.EVCLK > 0)
+ tonga_enable_disable_vce_dpm(hwmgr, false);
+
+ return 0;
+}
+
+static int tonga_update_and_upload_mc_reg_table(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ uint32_t address;
+ int32_t result;
+
+ if (0 == (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
+ return 0;
+
+
+ memset(&data->mc_reg_table, 0, sizeof(SMU72_Discrete_MCRegisters));
+
+ result = tonga_convert_mc_reg_table_to_smc(hwmgr, &(data->mc_reg_table));
+
+ if(result != 0)
+ return result;
+
+
+ address = data->mc_reg_table_start + (uint32_t)offsetof(SMU72_Discrete_MCRegisters, data[0]);
+
+ return tonga_copy_bytes_to_smc(hwmgr->smumgr, address,
+ (uint8_t *)&data->mc_reg_table.data[0],
+ sizeof(SMU72_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
+ data->sram_end);
+}
+
+static int tonga_program_memory_timing_parameters_conditionally(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ if (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+ return tonga_program_memory_timing_parameters(hwmgr);
+
+ return 0;
+}
+
+static int tonga_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+
+ if (0 == data->need_update_smu7_dpm_table)
+ return 0;
+
+ if ((0 == data->sclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table &
+ (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+
+ PP_ASSERT_WITH_CODE(true == tonga_is_dpm_running(hwmgr),
+ "Trying to Unfreeze SCLK DPM when DPM is disabled",
+ );
+ PP_ASSERT_WITH_CODE(
+ 0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+ "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ if ((0 == data->mclk_dpm_key_disabled) &&
+ (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+
+ PP_ASSERT_WITH_CODE(
+ true == tonga_is_dpm_running(hwmgr),
+ "Trying to Unfreeze MCLK DPM when DPM is disabled",
+ );
+ PP_ASSERT_WITH_CODE(
+ 0 == smum_send_msg_to_smc(hwmgr->smumgr,
+ PPSMC_MSG_SCLKDPM_UnfreezeLevel),
+ "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
+ return -1);
+ }
+
+ data->need_update_smu7_dpm_table = 0;
+
+ return 0;
+}
+
+static int tonga_notify_link_speed_change_after_state_change(struct pp_hwmgr *hwmgr, const void *input)
+{
+ const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input;
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ const struct tonga_power_state *tonga_ps = cast_const_phw_tonga_power_state(states->pnew_state);
+ uint16_t target_link_speed = tonga_get_maximum_link_speed(hwmgr, tonga_ps);
+ uint8_t request;
+
+ if (data->pspp_notify_required ||
+ data->pcie_performance_request) {
+ if (target_link_speed == PP_PCIEGen3)
+ request = PCIE_PERF_REQ_GEN3;
+ else if (target_link_speed == PP_PCIEGen2)
+ request = PCIE_PERF_REQ_GEN2;
+ else
+ request = PCIE_PERF_REQ_GEN1;
+
+ if(request == PCIE_PERF_REQ_GEN1 && tonga_get_current_pcie_speed(hwmgr) > 0) {
+ data->pcie_performance_request = false;
+ return 0;
+ }
+
+ if (0 != acpi_pcie_perf_request(hwmgr->device, request, false)) {
+ if (PP_PCIEGen2 == target_link_speed)
+ printk("PSPP request to switch to Gen2 from Gen3 Failed!");
+ else
+ printk("PSPP request to switch to Gen1 from Gen2 Failed!");
+ }
+ }
+
+ data->pcie_performance_request = false;
+ return 0;
+}
+
+static int tonga_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
+{
+ int tmp_result, result = 0;
+
+ tmp_result = tonga_find_dpm_states_clocks_in_dpm_table(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to find DPM states clocks in DPM table!", result = tmp_result);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
+ tmp_result = tonga_request_link_speed_change_before_state_change(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to request link speed change before state change!", result = tmp_result);
+ }
+
+ tmp_result = tonga_freeze_sclk_mclk_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to freeze SCLK MCLK DPM!", result = tmp_result);
+
+ tmp_result = tonga_populate_and_upload_sclk_mclk_dpm_levels(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result);
+
+ tmp_result = tonga_generate_dpm_level_enable_mask(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to generate DPM level enabled mask!", result = tmp_result);
+
+ tmp_result = tonga_update_vce_dpm(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update VCE DPM!", result = tmp_result);
+
+ tmp_result = tonga_update_sclk_threshold(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update SCLK threshold!", result = tmp_result);
+
+ tmp_result = tonga_update_and_upload_mc_reg_table(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload MC reg table!", result = tmp_result);
+
+ tmp_result = tonga_program_memory_timing_parameters_conditionally(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to program memory timing parameters!", result = tmp_result);
+
+ tmp_result = tonga_unfreeze_sclk_mclk_dpm(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to unfreeze SCLK MCLK DPM!", result = tmp_result);
+
+ tmp_result = tonga_upload_dpm_level_enable_mask(hwmgr);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to upload DPM level enabled mask!", result = tmp_result);
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest)) {
+ tmp_result = tonga_notify_link_speed_change_after_state_change(hwmgr, input);
+ PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to notify link speed change after state change!", result = tmp_result);
+ }
+
+ return result;
+}
+
+/**
+* Set maximum target operating fan output PWM
+*
+* @param pHwMgr: the address of the powerplay hardware manager.
+* @param usMaxFanPwm: max operating fan PWM in percents
+* @return The response that came from the SMC.
+*/
+static int tonga_set_max_fan_pwm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
+{
+ hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
+
+ if (phm_is_hw_access_blocked(hwmgr))
+ return 0;
+
+ return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm) ? 0 : -1);
+}
+
+int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
+{
+ uint32_t num_active_displays = 0;
+ struct cgs_display_info info = {0};
+ info.mode_info = NULL;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+
+ num_active_displays = info.display_count;
+
+ if (num_active_displays > 1) /* to do && (pHwMgr->pPECI->displayConfiguration.bMultiMonitorInSync != TRUE)) */
+ tonga_notify_smc_display_change(hwmgr, false);
+ else
+ tonga_notify_smc_display_change(hwmgr, true);
+
+ return 0;
+}
+
+/**
+* Programs the display gap
+*
+* @param hwmgr the address of the powerplay hardware manager.
+* @return always OK
+*/
+int tonga_program_display_gap(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ uint32_t num_active_displays = 0;
+ uint32_t display_gap = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL);
+ uint32_t display_gap2;
+ uint32_t pre_vbi_time_in_us;
+ uint32_t frame_time_in_us;
+ uint32_t ref_clock;
+ uint32_t refresh_rate = 0;
+ struct cgs_display_info info = {0};
+ struct cgs_mode_info mode_info;
+
+ info.mode_info = &mode_info;
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+ num_active_displays = info.display_count;
+
+ display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, DISP_GAP, (num_active_displays > 0)? DISPLAY_GAP_VBLANK_OR_WM : DISPLAY_GAP_IGNORE);
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL, display_gap);
+
+ ref_clock = mode_info.ref_clock;
+ refresh_rate = mode_info.refresh_rate;
+
+ if(0 == refresh_rate)
+ refresh_rate = 60;
+
+ frame_time_in_us = 1000000 / refresh_rate;
+
+ pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
+ display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, PreVBlankGap), 0x64);
+
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start + offsetof(SMU72_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
+
+ if (num_active_displays == 1)
+ tonga_notify_smc_display_change(hwmgr, true);
+
+ return 0;
+}
+
+int tonga_display_configuration_changed_task(struct pp_hwmgr *hwmgr)
+{
+
+ tonga_program_display_gap(hwmgr);
+
+ /* to do PhwTonga_CacUpdateDisplayConfiguration(pHwMgr); */
+ return 0;
+}
+
+/**
+* Set maximum target operating fan output RPM
+*
+* @param pHwMgr: the address of the powerplay hardware manager.
+* @param usMaxFanRpm: max operating fan RPM value.
+* @return The response that came from the SMC.
+*/
+static int tonga_set_max_fan_rpm_output(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm)
+{
+ hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM = us_max_fan_pwm;
+
+ if (phm_is_hw_access_blocked(hwmgr))
+ return 0;
+
+ return (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanRpmMax, us_max_fan_pwm) ? 0 : -1);
+}
+
+uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr)
+{
+ uint32_t reference_clock;
+ uint32_t tc;
+ uint32_t divide;
+
+ ATOM_FIRMWARE_INFO *fw_info;
+ uint16_t size;
+ uint8_t frev, crev;
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+
+ tc = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK);
+
+ if (tc)
+ return TCLK;
+
+ fw_info = (ATOM_FIRMWARE_INFO *)cgs_atom_get_data_table(hwmgr->device, index,
+ &size, &frev, &crev);
+
+ if (!fw_info)
+ return 0;
+
+ reference_clock = le16_to_cpu(fw_info->usMinPixelClockPLL_Output);
+
+ divide = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_CLKPIN_CNTL, XTALIN_DIVIDE);
+
+ if (0 != divide)
+ return reference_clock / 4;
+
+ return reference_clock;
+}
+
+int tonga_dpm_set_interrupt_state(void *private_data,
+ unsigned src_id, unsigned type,
+ int enabled)
+{
+ uint32_t cg_thermal_int;
+ struct pp_hwmgr *hwmgr = ((struct pp_eventmgr *)private_data)->hwmgr;
+
+ if (hwmgr == NULL)
+ return -EINVAL;
+
+ switch (type) {
+ case AMD_THERMAL_IRQ_LOW_TO_HIGH:
+ if (enabled) {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ } else {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ }
+ break;
+
+ case AMD_THERMAL_IRQ_HIGH_TO_LOW:
+ if (enabled) {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ } else {
+ cg_thermal_int = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_THERMAL_INT, cg_thermal_int);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int tonga_register_internal_thermal_interrupt(struct pp_hwmgr *hwmgr,
+ const void *thermal_interrupt_info)
+{
+ int result;
+ const struct pp_interrupt_registration_info *info =
+ (const struct pp_interrupt_registration_info *)thermal_interrupt_info;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ result = cgs_add_irq_source(hwmgr->device, 230, AMD_THERMAL_IRQ_LAST,
+ tonga_dpm_set_interrupt_state,
+ info->call_back, info->context);
+
+ if (result)
+ return -EINVAL;
+
+ result = cgs_add_irq_source(hwmgr->device, 231, AMD_THERMAL_IRQ_LAST,
+ tonga_dpm_set_interrupt_state,
+ info->call_back, info->context);
+
+ if (result)
+ return -EINVAL;
+
+ return 0;
+}
+
+bool tonga_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ bool is_update_required = false;
+ struct cgs_display_info info = {0,0,NULL};
+
+ cgs_get_active_displays_info(hwmgr->device, &info);
+
+ if (data->display_timing.num_existing_displays != info.display_count)
+ is_update_required = true;
+/* TO DO NEED TO GET DEEP SLEEP CLOCK FROM DAL
+ if (phm_cap_enabled(hwmgr->hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
+ cgs_get_min_clock_settings(hwmgr->device, &min_clocks);
+ if(min_clocks.engineClockInSR != data->display_timing.minClockInSR)
+ is_update_required = true;
+*/
+ return is_update_required;
+}
+
+static inline bool tonga_are_power_levels_equal(const struct tonga_performance_level *pl1,
+ const struct tonga_performance_level *pl2)
+{
+ return ((pl1->memory_clock == pl2->memory_clock) &&
+ (pl1->engine_clock == pl2->engine_clock) &&
+ (pl1->pcie_gen == pl2->pcie_gen) &&
+ (pl1->pcie_lane == pl2->pcie_lane));
+}
+
+int tonga_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
+{
+ const struct tonga_power_state *psa = cast_const_phw_tonga_power_state(pstate1);
+ const struct tonga_power_state *psb = cast_const_phw_tonga_power_state(pstate2);
+ int i;
+
+ if (equal == NULL || psa == NULL || psb == NULL)
+ return -EINVAL;
+
+ /* If the two states don't even have the same number of performance levels they cannot be the same state. */
+ if (psa->performance_level_count != psb->performance_level_count) {
+ *equal = false;
+ return 0;
+ }
+
+ for (i = 0; i < psa->performance_level_count; i++) {
+ if (!tonga_are_power_levels_equal(&(psa->performance_levels[i]), &(psb->performance_levels[i]))) {
+ /* If we have found even one performance level pair that is different the states are different. */
+ *equal = false;
+ return 0;
+ }
+ }
+
+ /* If all performance levels are the same try to use the UVD clocks to break the tie.*/
+ *equal = ((psa->uvd_clocks.VCLK == psb->uvd_clocks.VCLK) && (psa->uvd_clocks.DCLK == psb->uvd_clocks.DCLK));
+ *equal &= ((psa->vce_clocks.EVCLK == psb->vce_clocks.EVCLK) && (psa->vce_clocks.ECCLK == psb->vce_clocks.ECCLK));
+ *equal &= (psa->sclk_threshold == psb->sclk_threshold);
+ *equal &= (psa->acp_clk == psb->acp_clk);
+
+ return 0;
+}
+
+static int tonga_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+ if (mode) {
+ /* stop auto-manage */
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl))
+ tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
+ tonga_fan_ctrl_set_static_mode(hwmgr, mode);
+ } else
+ /* restart auto-manage */
+ tonga_fan_ctrl_reset_fan_speed_to_default(hwmgr);
+
+ return 0;
+}
+
+static int tonga_get_fan_control_mode(struct pp_hwmgr *hwmgr)
+{
+ if (hwmgr->fan_ctrl_is_in_default_mode)
+ return hwmgr->fan_ctrl_default_mode;
+ else
+ return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_FDO_CTRL2, FDO_PWM_MODE);
+}
+
+static const struct pp_hwmgr_func tonga_hwmgr_funcs = {
+ .backend_init = &tonga_hwmgr_backend_init,
+ .backend_fini = &tonga_hwmgr_backend_fini,
+ .asic_setup = &tonga_setup_asic_task,
+ .dynamic_state_management_enable = &tonga_enable_dpm_tasks,
+ .apply_state_adjust_rules = tonga_apply_state_adjust_rules,
+ .force_dpm_level = &tonga_force_dpm_level,
+ .power_state_set = tonga_set_power_state_tasks,
+ .get_power_state_size = tonga_get_power_state_size,
+ .get_mclk = tonga_dpm_get_mclk,
+ .get_sclk = tonga_dpm_get_sclk,
+ .patch_boot_state = tonga_dpm_patch_boot_state,
+ .get_pp_table_entry = tonga_get_pp_table_entry,
+ .get_num_of_pp_table_entries = tonga_get_number_of_powerplay_table_entries,
+ .print_current_perforce_level = tonga_print_current_perforce_level,
+ .powerdown_uvd = tonga_phm_powerdown_uvd,
+ .powergate_uvd = tonga_phm_powergate_uvd,
+ .powergate_vce = tonga_phm_powergate_vce,
+ .disable_clock_power_gating = tonga_phm_disable_clock_power_gating,
+ .notify_smc_display_config_after_ps_adjustment = tonga_notify_smc_display_config_after_ps_adjustment,
+ .display_config_changed = tonga_display_configuration_changed_task,
+ .set_max_fan_pwm_output = tonga_set_max_fan_pwm_output,
+ .set_max_fan_rpm_output = tonga_set_max_fan_rpm_output,
+ .get_temperature = tonga_thermal_get_temperature,
+ .stop_thermal_controller = tonga_thermal_stop_thermal_controller,
+ .get_fan_speed_info = tonga_fan_ctrl_get_fan_speed_info,
+ .get_fan_speed_percent = tonga_fan_ctrl_get_fan_speed_percent,
+ .set_fan_speed_percent = tonga_fan_ctrl_set_fan_speed_percent,
+ .reset_fan_speed_to_default = tonga_fan_ctrl_reset_fan_speed_to_default,
+ .get_fan_speed_rpm = tonga_fan_ctrl_get_fan_speed_rpm,
+ .set_fan_speed_rpm = tonga_fan_ctrl_set_fan_speed_rpm,
+ .uninitialize_thermal_controller = tonga_thermal_ctrl_uninitialize_thermal_controller,
+ .register_internal_thermal_interrupt = tonga_register_internal_thermal_interrupt,
+ .check_smc_update_required_for_display_configuration = tonga_check_smc_update_required_for_display_configuration,
+ .check_states_equal = tonga_check_states_equal,
+ .set_fan_control_mode = tonga_set_fan_control_mode,
+ .get_fan_control_mode = tonga_get_fan_control_mode,
+};
+
+int tonga_hwmgr_init(struct pp_hwmgr *hwmgr)
+{
+ tonga_hwmgr *data;
+
+ data = kzalloc (sizeof(tonga_hwmgr), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ memset(data, 0x00, sizeof(tonga_hwmgr));
+
+ hwmgr->backend = data;
+ hwmgr->hwmgr_func = &tonga_hwmgr_funcs;
+ hwmgr->pptable_func = &tonga_pptable_funcs;
+ pp_tonga_thermal_initialize(hwmgr);
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h
new file mode 100644
index 000000000000..49168d262ccc
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2015 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 TONGA_HWMGR_H
+#define TONGA_HWMGR_H
+
+#include "hwmgr.h"
+#include "smu72_discrete.h"
+#include "ppatomctrl.h"
+#include "ppinterrupt.h"
+#include "tonga_powertune.h"
+
+#define TONGA_MAX_HARDWARE_POWERLEVELS 2
+#define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
+
+struct tonga_performance_level {
+ uint32_t memory_clock;
+ uint32_t engine_clock;
+ uint16_t pcie_gen;
+ uint16_t pcie_lane;
+};
+
+struct _phw_tonga_bacos {
+ uint32_t best_match;
+ uint32_t baco_flags;
+ struct tonga_performance_level performance_level;
+};
+typedef struct _phw_tonga_bacos phw_tonga_bacos;
+
+struct _phw_tonga_uvd_clocks {
+ uint32_t VCLK;
+ uint32_t DCLK;
+};
+
+typedef struct _phw_tonga_uvd_clocks phw_tonga_uvd_clocks;
+
+struct _phw_tonga_vce_clocks {
+ uint32_t EVCLK;
+ uint32_t ECCLK;
+};
+
+typedef struct _phw_tonga_vce_clocks phw_tonga_vce_clocks;
+
+struct tonga_power_state {
+ uint32_t magic;
+ phw_tonga_uvd_clocks uvd_clocks;
+ phw_tonga_vce_clocks vce_clocks;
+ uint32_t sam_clk;
+ uint32_t acp_clk;
+ uint16_t performance_level_count;
+ bool dc_compatible;
+ uint32_t sclk_threshold;
+ struct tonga_performance_level performance_levels[TONGA_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct _phw_tonga_dpm_level {
+ bool enabled;
+ uint32_t value;
+ uint32_t param1;
+};
+typedef struct _phw_tonga_dpm_level phw_tonga_dpm_level;
+
+#define TONGA_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define MAX_REGULAR_DPM_NUMBER 8
+#define TONGA_MINIMUM_ENGINE_CLOCK 2500
+
+struct tonga_single_dpm_table {
+ uint32_t count;
+ phw_tonga_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
+};
+
+struct tonga_dpm_table {
+ struct tonga_single_dpm_table sclk_table;
+ struct tonga_single_dpm_table mclk_table;
+ struct tonga_single_dpm_table pcie_speed_table;
+ struct tonga_single_dpm_table vddc_table;
+ struct tonga_single_dpm_table vdd_gfx_table;
+ struct tonga_single_dpm_table vdd_ci_table;
+ struct tonga_single_dpm_table mvdd_table;
+};
+typedef struct _phw_tonga_dpm_table phw_tonga_dpm_table;
+
+
+struct _phw_tonga_clock_regisiters {
+ uint32_t vCG_SPLL_FUNC_CNTL;
+ uint32_t vCG_SPLL_FUNC_CNTL_2;
+ uint32_t vCG_SPLL_FUNC_CNTL_3;
+ uint32_t vCG_SPLL_FUNC_CNTL_4;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t vDLL_CNTL;
+ uint32_t vMCLK_PWRMGT_CNTL;
+ uint32_t vMPLL_AD_FUNC_CNTL;
+ uint32_t vMPLL_DQ_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL_1;
+ uint32_t vMPLL_FUNC_CNTL_2;
+ uint32_t vMPLL_SS1;
+ uint32_t vMPLL_SS2;
+};
+typedef struct _phw_tonga_clock_regisiters phw_tonga_clock_registers;
+
+struct _phw_tonga_voltage_smio_registers {
+ uint32_t vs0_vid_lower_smio_cntl;
+};
+typedef struct _phw_tonga_voltage_smio_registers phw_tonga_voltage_smio_registers;
+
+
+struct _phw_tonga_mc_reg_entry {
+ uint32_t mclk_max;
+ uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct _phw_tonga_mc_reg_entry phw_tonga_mc_reg_entry;
+
+struct _phw_tonga_mc_reg_table {
+ uint8_t last; /* number of registers*/
+ uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
+ uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
+ phw_tonga_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+ SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+typedef struct _phw_tonga_mc_reg_table phw_tonga_mc_reg_table;
+
+#define DISABLE_MC_LOADMICROCODE 1
+#define DISABLE_MC_CFGPROGRAMMING 2
+
+/*Ultra Low Voltage parameter structure */
+struct _phw_tonga_ulv_parm{
+ bool ulv_supported;
+ uint32_t ch_ulv_parameter;
+ uint32_t ulv_volt_change_delay;
+ struct tonga_performance_level ulv_power_level;
+};
+typedef struct _phw_tonga_ulv_parm phw_tonga_ulv_parm;
+
+#define TONGA_MAX_LEAKAGE_COUNT 8
+
+struct _phw_tonga_leakage_voltage {
+ uint16_t count;
+ uint16_t leakage_id[TONGA_MAX_LEAKAGE_COUNT];
+ uint16_t actual_voltage[TONGA_MAX_LEAKAGE_COUNT];
+};
+typedef struct _phw_tonga_leakage_voltage phw_tonga_leakage_voltage;
+
+struct _phw_tonga_display_timing {
+ uint32_t min_clock_insr;
+ uint32_t num_existing_displays;
+};
+typedef struct _phw_tonga_display_timing phw_tonga_display_timing;
+
+struct _phw_tonga_dpmlevel_enable_mask {
+ uint32_t uvd_dpm_enable_mask;
+ uint32_t vce_dpm_enable_mask;
+ uint32_t acp_dpm_enable_mask;
+ uint32_t samu_dpm_enable_mask;
+ uint32_t sclk_dpm_enable_mask;
+ uint32_t mclk_dpm_enable_mask;
+ uint32_t pcie_dpm_enable_mask;
+};
+typedef struct _phw_tonga_dpmlevel_enable_mask phw_tonga_dpmlevel_enable_mask;
+
+struct _phw_tonga_pcie_perf_range {
+ uint16_t max;
+ uint16_t min;
+};
+typedef struct _phw_tonga_pcie_perf_range phw_tonga_pcie_perf_range;
+
+struct _phw_tonga_vbios_boot_state {
+ uint16_t mvdd_bootup_value;
+ uint16_t vddc_bootup_value;
+ uint16_t vddci_bootup_value;
+ uint16_t vddgfx_bootup_value;
+ uint32_t sclk_bootup_value;
+ uint32_t mclk_bootup_value;
+ uint16_t pcie_gen_bootup_value;
+ uint16_t pcie_lane_bootup_value;
+};
+typedef struct _phw_tonga_vbios_boot_state phw_tonga_vbios_boot_state;
+
+#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
+#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
+#define DPMTABLE_UPDATE_SCLK 0x00000004
+#define DPMTABLE_UPDATE_MCLK 0x00000008
+
+/* We need to review which fields are needed. */
+/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
+struct tonga_hwmgr {
+ struct tonga_dpm_table dpm_table;
+ struct tonga_dpm_table golden_dpm_table;
+
+ uint32_t voting_rights_clients0;
+ uint32_t voting_rights_clients1;
+ uint32_t voting_rights_clients2;
+ uint32_t voting_rights_clients3;
+ uint32_t voting_rights_clients4;
+ uint32_t voting_rights_clients5;
+ uint32_t voting_rights_clients6;
+ uint32_t voting_rights_clients7;
+ uint32_t static_screen_threshold_unit;
+ uint32_t static_screen_threshold;
+ uint32_t voltage_control;
+ uint32_t vdd_gfx_control;
+
+ uint32_t vddc_vddci_delta;
+ uint32_t vddc_vddgfx_delta;
+
+ struct pp_interrupt_registration_info internal_high_thermal_interrupt_info;
+ struct pp_interrupt_registration_info internal_low_thermal_interrupt_info;
+ struct pp_interrupt_registration_info smc_to_host_interrupt_info;
+ uint32_t active_auto_throttle_sources;
+
+ struct pp_interrupt_registration_info external_throttle_interrupt;
+ irq_handler_func_t external_throttle_callback;
+ void *external_throttle_context;
+
+ struct pp_interrupt_registration_info ctf_interrupt_info;
+ irq_handler_func_t ctf_callback;
+ void *ctf_context;
+
+ phw_tonga_clock_registers clock_registers;
+ phw_tonga_voltage_smio_registers voltage_smio_registers;
+
+ bool is_memory_GDDR5;
+ uint16_t acpi_vddc;
+ bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */
+ uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */
+ uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */
+ uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */
+ uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */
+ uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */
+ phw_tonga_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/
+ phw_tonga_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */
+ phw_tonga_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */
+
+ uint32_t mvdd_control;
+ uint32_t vddc_mask_low;
+ uint32_t mvdd_mask_low;
+ uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/
+ uint16_t min_vddc_in_pp_table;
+ uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */
+ uint16_t min_vddci_in_pp_table;
+ uint32_t mclk_strobe_mode_threshold;
+ uint32_t mclk_stutter_mode_threshold;
+ uint32_t mclk_edc_enable_threshold;
+ uint32_t mclk_edc_wr_enable_threshold;
+ bool is_uvd_enabled;
+ bool is_xdma_enabled;
+ phw_tonga_vbios_boot_state vbios_boot_state;
+
+ bool battery_state;
+ bool is_tlu_enabled;
+ bool pcie_performance_request;
+
+ /* -------------- SMC SRAM Address of firmware header tables ----------------*/
+ uint32_t sram_end; /* The first address after the SMC SRAM. */
+ uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */
+ uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */
+ uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */
+ uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */
+ uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */
+ SMU72_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */
+ SMU72_Discrete_MCRegisters mc_reg_table;
+ SMU72_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */
+ /* -------------- Stuff originally coming from Evergreen --------------------*/
+ phw_tonga_mc_reg_table tonga_mc_reg_table;
+ uint32_t vdd_ci_control;
+ pp_atomctrl_voltage_table vddc_voltage_table;
+ pp_atomctrl_voltage_table vddci_voltage_table;
+ pp_atomctrl_voltage_table vddgfx_voltage_table;
+ pp_atomctrl_voltage_table mvdd_voltage_table;
+
+ uint32_t mgcg_cgtt_local2;
+ uint32_t mgcg_cgtt_local3;
+ uint32_t gpio_debug;
+ uint32_t mc_micro_code_feature;
+ uint32_t highest_mclk;
+ uint16_t acpi_vdd_ci;
+ uint8_t mvdd_high_index;
+ uint8_t mvdd_low_index;
+ bool dll_defaule_on;
+ bool performance_request_registered;
+
+ /* ----------------- Low Power Features ---------------------*/
+ phw_tonga_bacos bacos;
+ phw_tonga_ulv_parm ulv;
+ /* ----------------- CAC Stuff ---------------------*/
+ uint32_t cac_table_start;
+ bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */
+ bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */
+ bool cac_enabled;
+ /* ----------------- DPM2 Parameters ---------------------*/
+ uint32_t power_containment_features;
+ bool enable_bapm_feature;
+ bool enable_tdc_limit_feature;
+ bool enable_pkg_pwr_tracking_feature;
+ bool disable_uvd_power_tune_feature;
+ phw_tonga_pt_defaults *power_tune_defaults;
+ SMU72_Discrete_PmFuses power_tune_table;
+ uint32_t ul_dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */
+ uint32_t fast_watemark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
+
+ /* ----------------- Phase Shedding ---------------------*/
+ bool vddc_phase_shed_control;
+ /* --------------------- DI/DT --------------------------*/
+ phw_tonga_display_timing display_timing;
+ /* --------- ReadRegistry data for memory and engine clock margins ---- */
+ uint32_t engine_clock_data;
+ uint32_t memory_clock_data;
+ /* -------- Thermal Temperature Setting --------------*/
+ phw_tonga_dpmlevel_enable_mask dpm_level_enable_mask;
+ uint32_t need_update_smu7_dpm_table;
+ uint32_t sclk_dpm_key_disabled;
+ uint32_t mclk_dpm_key_disabled;
+ uint32_t pcie_dpm_key_disabled;
+ uint32_t min_engine_clocks; /* used to store the previous dal min sclock */
+ phw_tonga_pcie_perf_range pcie_gen_performance;
+ phw_tonga_pcie_perf_range pcie_lane_performance;
+ phw_tonga_pcie_perf_range pcie_gen_power_saving;
+ phw_tonga_pcie_perf_range pcie_lane_power_saving;
+ bool use_pcie_performance_levels;
+ bool use_pcie_power_saving_levels;
+ uint32_t activity_target[SMU72_MAX_LEVELS_GRAPHICS]; /* percentage value from 0-100, default 50 */
+ uint32_t mclk_activity_target;
+ uint32_t low_sclk_interrupt_threshold;
+ uint32_t last_mclk_dpm_enable_mask;
+ bool uvd_enabled;
+ uint32_t pcc_monitor_enabled;
+
+ /* --------- Power Gating States ------------*/
+ bool uvd_power_gated; /* 1: gated, 0:not gated */
+ bool vce_power_gated; /* 1: gated, 0:not gated */
+ bool samu_power_gated; /* 1: gated, 0:not gated */
+ bool acp_power_gated; /* 1: gated, 0:not gated */
+ bool pg_acp_init;
+
+};
+
+typedef struct tonga_hwmgr tonga_hwmgr;
+
+#define TONGA_DPM2_NEAR_TDP_DEC 10
+#define TONGA_DPM2_ABOVE_SAFE_INC 5
+#define TONGA_DPM2_BELOW_SAFE_INC 20
+
+#define TONGA_DPM2_LTA_WINDOW_SIZE 7 /* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size is 128, then this value should be Log2(128) = 7. */
+
+#define TONGA_DPM2_LTS_TRUNCATE 0
+
+#define TONGA_DPM2_TDP_SAFE_LIMIT_PERCENT 80 /* Maximum 100 */
+
+#define TONGA_DPM2_MAXPS_PERCENT_H 90 /* Maximum 0xFF */
+#define TONGA_DPM2_MAXPS_PERCENT_M 90 /* Maximum 0xFF */
+
+#define TONGA_DPM2_PWREFFICIENCYRATIO_MARGIN 50
+
+#define TONGA_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
+#define TONGA_DPM2_SQ_RAMP_MIN_POWER 0x12
+#define TONGA_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
+#define TONGA_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E
+#define TONGA_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF
+
+#define TONGA_VOLTAGE_CONTROL_NONE 0x0
+#define TONGA_VOLTAGE_CONTROL_BY_GPIO 0x1
+#define TONGA_VOLTAGE_CONTROL_BY_SVID2 0x2
+#define TONGA_VOLTAGE_CONTROL_MERGED 0x3
+
+#define TONGA_Q88_FORMAT_CONVERSION_UNIT 256 /*To convert to Q8.8 format for firmware */
+
+#define TONGA_UNUSED_GPIO_PIN 0x7F
+
+#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X)
+#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X)
+
+#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X)
+#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X)
+
+#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X))
+#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X))
+
+#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X))
+
+int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
+int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
+int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
+int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
+int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
+uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h
new file mode 100644
index 000000000000..8e6670b3cb67
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_powertune.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 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 TONGA_POWERTUNE_H
+#define TONGA_POWERTUNE_H
+
+enum _phw_tonga_ptc_config_reg_type {
+ TONGA_CONFIGREG_MMR = 0,
+ TONGA_CONFIGREG_SMC_IND,
+ TONGA_CONFIGREG_DIDT_IND,
+ TONGA_CONFIGREG_CACHE,
+
+ TONGA_CONFIGREG_MAX
+};
+typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type;
+
+/* PowerContainment Features */
+#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
+#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
+#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
+
+struct _phw_tonga_pt_config_reg {
+ uint32_t Offset;
+ uint32_t Mask;
+ uint32_t Shift;
+ uint32_t Value;
+ phw_tonga_ptc_config_reg_type Type;
+};
+typedef struct _phw_tonga_pt_config_reg phw_tonga_pt_config_reg;
+
+struct _phw_tonga_pt_defaults {
+ uint8_t svi_load_line_en;
+ uint8_t svi_load_line_vddC;
+ uint8_t tdc_vddc_throttle_release_limit_perc;
+ uint8_t tdc_mawt;
+ uint8_t tdc_waterfall_ctl;
+ uint8_t dte_ambient_temp_base;
+ uint32_t display_cac;
+ uint32_t bamp_temp_gradient;
+ uint16_t bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+ uint16_t bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+};
+typedef struct _phw_tonga_pt_defaults phw_tonga_pt_defaults;
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h
new file mode 100644
index 000000000000..9a4456e6521b
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_pptable.h
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2015 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 TONGA_PPTABLE_H
+#define TONGA_PPTABLE_H
+
+/** \file
+ * This is a PowerPlay table header file
+ */
+#pragma pack(push, 1)
+
+#include "hwmgr.h"
+
+#define ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
+#define ATOM_TONGA_PP_FANPARAMETERS_NOFAN 0x80 /* No fan is connected to this controller. */
+
+#define ATOM_TONGA_PP_THERMALCONTROLLER_NONE 0
+#define ATOM_TONGA_PP_THERMALCONTROLLER_LM96163 17
+#define ATOM_TONGA_PP_THERMALCONTROLLER_TONGA 21
+#define ATOM_TONGA_PP_THERMALCONTROLLER_FIJI 22
+
+/*
+ * Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
+ * We probably should reserve the bit 0x80 for this use.
+ * To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here).
+ * The driver can pick the correct internal controller based on the ASIC.
+ */
+
+#define ATOM_TONGA_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 /* ADT7473 Fan Control + Internal Thermal Controller */
+#define ATOM_TONGA_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D /* EMC2103 Fan Control + Internal Thermal Controller */
+
+/*/* ATOM_TONGA_POWERPLAYTABLE::ulPlatformCaps */
+#define ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL 0x1 /* This cap indicates whether vddgfx will be a separated power rail. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY 0x2 /* This cap indicates whether this is a mobile part and CCC need to show Powerplay page. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 0x4 /* This cap indicates whether power source notificaiton is done by SBIOS directly. */
+#define ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND 0x8 /* Enable the option to overwrite voltage island feature to be disabled, regardless of VddGfx power rail support. */
+#define ____RETIRE16____ 0x10
+#define ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC 0x20 /* This cap indicates whether power source notificaiton is done by GPIO directly. */
+#define ____RETIRE64____ 0x40
+#define ____RETIRE128____ 0x80
+#define ____RETIRE256____ 0x100
+#define ____RETIRE512____ 0x200
+#define ____RETIRE1024____ 0x400
+#define ____RETIRE2048____ 0x800
+#define ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL 0x1000 /* This cap indicates dynamic MVDD is required. Uncheck to disable it. */
+#define ____RETIRE2000____ 0x2000
+#define ____RETIRE4000____ 0x4000
+#define ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 /* This cap indicates dynamic VDDCI is required. Uncheck to disable it. */
+#define ____RETIRE10000____ 0x10000
+#define ATOM_TONGA_PP_PLATFORM_CAP_BACO 0x20000 /* Enable to indicate the driver supports BACO state. */
+
+#define ATOM_TONGA_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17 0x100000 /* Enable to indicate the driver supports thermal2GPIO17. */
+#define ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL 0x1000000 /* Enable to indicate if thermal and PCC are sharing the same GPIO */
+#define ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE 0x2000000
+
+/* ATOM_PPLIB_NONCLOCK_INFO::usClassification */
+#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007
+#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0
+#define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0
+#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1
+#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3
+#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5
+/* 2, 4, 6, 7 are reserved */
+
+#define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008
+#define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010
+#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020
+#define ATOM_PPLIB_CLASSIFICATION_REST 0x0040
+#define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080
+#define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000
+
+/* ATOM_PPLIB_NONCLOCK_INFO::usClassification2 */
+#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001
+
+#define ATOM_Tonga_DISALLOW_ON_DC 0x00004000
+#define ATOM_Tonga_ENABLE_VARIBRIGHT 0x00008000
+
+#define ATOM_Tonga_TABLE_REVISION_TONGA 7
+
+typedef struct _ATOM_Tonga_POWERPLAYTABLE {
+ ATOM_COMMON_TABLE_HEADER sHeader;
+
+ UCHAR ucTableRevision;
+ USHORT usTableSize; /*the size of header structure */
+
+ ULONG ulGoldenPPID;
+ ULONG ulGoldenRevision;
+ USHORT usFormatID;
+
+ USHORT usVoltageTime; /*in microseconds */
+ ULONG ulPlatformCaps; /*See ATOM_Tonga_CAPS_* */
+
+ ULONG ulMaxODEngineClock; /*For Overdrive. */
+ ULONG ulMaxODMemoryClock; /*For Overdrive. */
+
+ USHORT usPowerControlLimit;
+ USHORT usUlvVoltageOffset; /*in mv units */
+
+ USHORT usStateArrayOffset; /*points to ATOM_Tonga_State_Array */
+ USHORT usFanTableOffset; /*points to ATOM_Tonga_Fan_Table */
+ USHORT usThermalControllerOffset; /*points to ATOM_Tonga_Thermal_Controller */
+ USHORT usReserv; /*CustomThermalPolicy removed for Tonga. Keep this filed as reserved. */
+
+ USHORT usMclkDependencyTableOffset; /*points to ATOM_Tonga_MCLK_Dependency_Table */
+ USHORT usSclkDependencyTableOffset; /*points to ATOM_Tonga_SCLK_Dependency_Table */
+ USHORT usVddcLookupTableOffset; /*points to ATOM_Tonga_Voltage_Lookup_Table */
+ USHORT usVddgfxLookupTableOffset; /*points to ATOM_Tonga_Voltage_Lookup_Table */
+
+ USHORT usMMDependencyTableOffset; /*points to ATOM_Tonga_MM_Dependency_Table */
+
+ USHORT usVCEStateTableOffset; /*points to ATOM_Tonga_VCE_State_Table; */
+
+ USHORT usPPMTableOffset; /*points to ATOM_Tonga_PPM_Table */
+ USHORT usPowerTuneTableOffset; /*points to ATOM_PowerTune_Table */
+
+ USHORT usHardLimitTableOffset; /*points to ATOM_Tonga_Hard_Limit_Table */
+
+ USHORT usPCIETableOffset; /*points to ATOM_Tonga_PCIE_Table */
+
+ USHORT usGPIOTableOffset; /*points to ATOM_Tonga_GPIO_Table */
+
+ USHORT usReserved[6]; /*TODO: modify reserved size to fit structure aligning */
+} ATOM_Tonga_POWERPLAYTABLE;
+
+typedef struct _ATOM_Tonga_State {
+ UCHAR ucEngineClockIndexHigh;
+ UCHAR ucEngineClockIndexLow;
+
+ UCHAR ucMemoryClockIndexHigh;
+ UCHAR ucMemoryClockIndexLow;
+
+ UCHAR ucPCIEGenLow;
+ UCHAR ucPCIEGenHigh;
+
+ UCHAR ucPCIELaneLow;
+ UCHAR ucPCIELaneHigh;
+
+ USHORT usClassification;
+ ULONG ulCapsAndSettings;
+ USHORT usClassification2;
+ UCHAR ucUnused[4];
+} ATOM_Tonga_State;
+
+typedef struct _ATOM_Tonga_State_Array {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries; /* Number of entries. */
+ ATOM_Tonga_State states[1]; /* Dynamically allocate entries. */
+} ATOM_Tonga_State_Array;
+
+typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
+ UCHAR ucVddcInd; /* Vddc voltage */
+ USHORT usVddci;
+ USHORT usVddgfxOffset; /* Offset relative to Vddc voltage */
+ USHORT usMvdd;
+ ULONG ulMclk;
+ USHORT usReserved;
+} ATOM_Tonga_MCLK_Dependency_Record;
+
+typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries; /* Number of entries. */
+ ATOM_Tonga_MCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */
+} ATOM_Tonga_MCLK_Dependency_Table;
+
+typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
+ UCHAR ucVddInd; /* Base voltage */
+ USHORT usVddcOffset; /* Offset relative to base voltage */
+ ULONG ulSclk;
+ USHORT usEdcCurrent;
+ UCHAR ucReliabilityTemperature;
+ UCHAR ucCKSVOffsetandDisable; /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
+} ATOM_Tonga_SCLK_Dependency_Record;
+
+typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries; /* Number of entries. */
+ ATOM_Tonga_SCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */
+} ATOM_Tonga_SCLK_Dependency_Table;
+
+typedef struct _ATOM_Tonga_PCIE_Record {
+ UCHAR ucPCIEGenSpeed;
+ UCHAR usPCIELaneWidth;
+ UCHAR ucReserved[2];
+} ATOM_Tonga_PCIE_Record;
+
+typedef struct _ATOM_Tonga_PCIE_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries; /* Number of entries. */
+ ATOM_Tonga_PCIE_Record entries[1]; /* Dynamically allocate entries. */
+} ATOM_Tonga_PCIE_Table;
+
+typedef struct _ATOM_Tonga_MM_Dependency_Record {
+ UCHAR ucVddcInd; /* VDDC voltage */
+ USHORT usVddgfxOffset; /* Offset relative to VDDC voltage */
+ ULONG ulDClk; /* UVD D-clock */
+ ULONG ulVClk; /* UVD V-clock */
+ ULONG ulEClk; /* VCE clock */
+ ULONG ulAClk; /* ACP clock */
+ ULONG ulSAMUClk; /* SAMU clock */
+} ATOM_Tonga_MM_Dependency_Record;
+
+typedef struct _ATOM_Tonga_MM_Dependency_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries; /* Number of entries. */
+ ATOM_Tonga_MM_Dependency_Record entries[1]; /* Dynamically allocate entries. */
+} ATOM_Tonga_MM_Dependency_Table;
+
+typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
+ USHORT usVdd; /* Base voltage */
+ USHORT usCACLow;
+ USHORT usCACMid;
+ USHORT usCACHigh;
+} ATOM_Tonga_Voltage_Lookup_Record;
+
+typedef struct _ATOM_Tonga_Voltage_Lookup_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries; /* Number of entries. */
+ ATOM_Tonga_Voltage_Lookup_Record entries[1]; /* Dynamically allocate entries. */
+} ATOM_Tonga_Voltage_Lookup_Table;
+
+typedef struct _ATOM_Tonga_Fan_Table {
+ UCHAR ucRevId; /* Change this if the table format changes or version changes so that the other fields are not the same. */
+ UCHAR ucTHyst; /* Temperature hysteresis. Integer. */
+ USHORT usTMin; /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+ USHORT usTMed; /* The middle temperature where we change slopes. */
+ USHORT usTHigh; /* The high point above TMed for adjusting the second slope. */
+ USHORT usPWMMin; /* The minimum PWM value in percent (0.01% increments). */
+ USHORT usPWMMed; /* The PWM value (in percent) at TMed. */
+ USHORT usPWMHigh; /* The PWM value at THigh. */
+ USHORT usTMax; /* The max temperature */
+ UCHAR ucFanControlMode; /* Legacy or Fuzzy Fan mode */
+ USHORT usFanPWMMax; /* Maximum allowed fan power in percent */
+ USHORT usFanOutputSensitivity; /* Sensitivity of fan reaction to temepature changes */
+ USHORT usFanRPMMax; /* The default value in RPM */
+ ULONG ulMinFanSCLKAcousticLimit; /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+ UCHAR ucTargetTemperature; /* Advanced fan controller target temperature. */
+ UCHAR ucMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. This should be set to the highest PWM that will run the fan at its lowest RPM. */
+ USHORT usReserved;
+} ATOM_Tonga_Fan_Table;
+
+typedef struct _ATOM_Fiji_Fan_Table {
+ UCHAR ucRevId; /* Change this if the table format changes or version changes so that the other fields are not the same. */
+ UCHAR ucTHyst; /* Temperature hysteresis. Integer. */
+ USHORT usTMin; /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+ USHORT usTMed; /* The middle temperature where we change slopes. */
+ USHORT usTHigh; /* The high point above TMed for adjusting the second slope. */
+ USHORT usPWMMin; /* The minimum PWM value in percent (0.01% increments). */
+ USHORT usPWMMed; /* The PWM value (in percent) at TMed. */
+ USHORT usPWMHigh; /* The PWM value at THigh. */
+ USHORT usTMax; /* The max temperature */
+ UCHAR ucFanControlMode; /* Legacy or Fuzzy Fan mode */
+ USHORT usFanPWMMax; /* Maximum allowed fan power in percent */
+ USHORT usFanOutputSensitivity; /* Sensitivity of fan reaction to temepature changes */
+ USHORT usFanRPMMax; /* The default value in RPM */
+ ULONG ulMinFanSCLKAcousticLimit; /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+ UCHAR ucTargetTemperature; /* Advanced fan controller target temperature. */
+ UCHAR ucMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. This should be set to the highest PWM that will run the fan at its lowest RPM. */
+ USHORT usFanGainEdge;
+ USHORT usFanGainHotspot;
+ USHORT usFanGainLiquid;
+ USHORT usFanGainVrVddc;
+ USHORT usFanGainVrMvdd;
+ USHORT usFanGainPlx;
+ USHORT usFanGainHbm;
+ USHORT usReserved;
+} ATOM_Fiji_Fan_Table;
+
+typedef struct _ATOM_Tonga_Thermal_Controller {
+ UCHAR ucRevId;
+ UCHAR ucType; /* one of ATOM_TONGA_PP_THERMALCONTROLLER_* */
+ UCHAR ucI2cLine; /* as interpreted by DAL I2C */
+ UCHAR ucI2cAddress;
+ UCHAR ucFanParameters; /* Fan Control Parameters. */
+ UCHAR ucFanMinRPM; /* Fan Minimum RPM (hundreds) -- for display purposes only. */
+ UCHAR ucFanMaxRPM; /* Fan Maximum RPM (hundreds) -- for display purposes only. */
+ UCHAR ucReserved;
+ UCHAR ucFlags; /* to be defined */
+} ATOM_Tonga_Thermal_Controller;
+
+typedef struct _ATOM_Tonga_VCE_State_Record {
+ UCHAR ucVCEClockIndex; /*index into usVCEDependencyTableOffset of 'ATOM_Tonga_MM_Dependency_Table' type */
+ UCHAR ucFlag; /* 2 bits indicates memory p-states */
+ UCHAR ucSCLKIndex; /*index into ATOM_Tonga_SCLK_Dependency_Table */
+ UCHAR ucMCLKIndex; /*index into ATOM_Tonga_MCLK_Dependency_Table */
+} ATOM_Tonga_VCE_State_Record;
+
+typedef struct _ATOM_Tonga_VCE_State_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries;
+ ATOM_Tonga_VCE_State_Record entries[1];
+} ATOM_Tonga_VCE_State_Table;
+
+typedef struct _ATOM_Tonga_PowerTune_Table {
+ UCHAR ucRevId;
+ USHORT usTDP;
+ USHORT usConfigurableTDP;
+ USHORT usTDC;
+ USHORT usBatteryPowerLimit;
+ USHORT usSmallPowerLimit;
+ USHORT usLowCACLeakage;
+ USHORT usHighCACLeakage;
+ USHORT usMaximumPowerDeliveryLimit;
+ USHORT usTjMax;
+ USHORT usPowerTuneDataSetID;
+ USHORT usEDCLimit;
+ USHORT usSoftwareShutdownTemp;
+ USHORT usClockStretchAmount;
+ USHORT usReserve[2];
+} ATOM_Tonga_PowerTune_Table;
+
+typedef struct _ATOM_Fiji_PowerTune_Table {
+ UCHAR ucRevId;
+ USHORT usTDP;
+ USHORT usConfigurableTDP;
+ USHORT usTDC;
+ USHORT usBatteryPowerLimit;
+ USHORT usSmallPowerLimit;
+ USHORT usLowCACLeakage;
+ USHORT usHighCACLeakage;
+ USHORT usMaximumPowerDeliveryLimit;
+ USHORT usTjMax; /* For Fiji, this is also usTemperatureLimitEdge; */
+ USHORT usPowerTuneDataSetID;
+ USHORT usEDCLimit;
+ USHORT usSoftwareShutdownTemp;
+ USHORT usClockStretchAmount;
+ USHORT usTemperatureLimitHotspot; /*The following are added for Fiji */
+ USHORT usTemperatureLimitLiquid1;
+ USHORT usTemperatureLimitLiquid2;
+ USHORT usTemperatureLimitVrVddc;
+ USHORT usTemperatureLimitVrMvdd;
+ USHORT usTemperatureLimitPlx;
+ UCHAR ucLiquid1_I2C_address; /*Liquid */
+ UCHAR ucLiquid2_I2C_address;
+ UCHAR ucLiquid_I2C_Line;
+ UCHAR ucVr_I2C_address; /*VR */
+ UCHAR ucVr_I2C_Line;
+ UCHAR ucPlx_I2C_address; /*PLX */
+ UCHAR ucPlx_I2C_Line;
+ USHORT usReserved;
+} ATOM_Fiji_PowerTune_Table;
+
+#define ATOM_PPM_A_A 1
+#define ATOM_PPM_A_I 2
+typedef struct _ATOM_Tonga_PPM_Table {
+ UCHAR ucRevId;
+ UCHAR ucPpmDesign; /*A+I or A+A */
+ USHORT usCpuCoreNumber;
+ ULONG ulPlatformTDP;
+ ULONG ulSmallACPlatformTDP;
+ ULONG ulPlatformTDC;
+ ULONG ulSmallACPlatformTDC;
+ ULONG ulApuTDP;
+ ULONG ulDGpuTDP;
+ ULONG ulDGpuUlvPower;
+ ULONG ulTjmax;
+} ATOM_Tonga_PPM_Table;
+
+typedef struct _ATOM_Tonga_Hard_Limit_Record {
+ ULONG ulSCLKLimit;
+ ULONG ulMCLKLimit;
+ USHORT usVddcLimit;
+ USHORT usVddciLimit;
+ USHORT usVddgfxLimit;
+} ATOM_Tonga_Hard_Limit_Record;
+
+typedef struct _ATOM_Tonga_Hard_Limit_Table {
+ UCHAR ucRevId;
+ UCHAR ucNumEntries;
+ ATOM_Tonga_Hard_Limit_Record entries[1];
+} ATOM_Tonga_Hard_Limit_Table;
+
+typedef struct _ATOM_Tonga_GPIO_Table {
+ UCHAR ucRevId;
+ UCHAR ucVRHotTriggeredSclkDpmIndex; /* If VRHot signal is triggered SCLK will be limited to this DPM level */
+ UCHAR ucReserve[5];
+} ATOM_Tonga_GPIO_Table;
+
+typedef struct _PPTable_Generic_SubTable_Header {
+ UCHAR ucRevId;
+} PPTable_Generic_SubTable_Header;
+
+
+#pragma pack(pop)
+
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c
new file mode 100644
index 000000000000..34f4bef3691f
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c
@@ -0,0 +1,1142 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include "tonga_processpptables.h"
+#include "ppatomctrl.h"
+#include "atombios.h"
+#include "pp_debug.h"
+#include "hwmgr.h"
+#include "cgs_common.h"
+#include "tonga_pptable.h"
+
+/**
+ * Private Function used during initialization.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE).
+ * @param cap Which capability to set/reset.
+ */
+static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap)
+{
+ if (setIt)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
+ else
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
+}
+
+
+/**
+ * Private Function used during initialization.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_caps the bit array (from BIOS) of capability bits.
+ * @exception the current implementation always returns 1.
+ */
+static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
+{
+ PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____),
+ "ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue);
+ PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____),
+ "ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue);
+ PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____),
+ "ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue);
+ PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____),
+ "ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue);
+ PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____),
+ "ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue);
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY),
+ PHM_PlatformCaps_PowerPlaySupport
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
+ PHM_PlatformCaps_BiosPowerSourceControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC),
+ PHM_PlatformCaps_AutomaticDCTransition
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL),
+ PHM_PlatformCaps_EnableMVDDControl
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL),
+ PHM_PlatformCaps_ControlVDDCI
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL),
+ PHM_PlatformCaps_ControlVDDGFX
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO),
+ PHM_PlatformCaps_BACO
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND),
+ PHM_PlatformCaps_DisableVoltageIsland
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
+ PHM_PlatformCaps_CombinePCCWithThermalSignal
+ );
+
+ set_hw_cap(
+ hwmgr,
+ 0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
+ PHM_PlatformCaps_LoadPostProductionFirmware
+ );
+
+ return 0;
+}
+
+/**
+ * Private Function to get the PowerPlay Table Address.
+ */
+const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
+{
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+
+ u16 size;
+ u8 frev, crev;
+ void *table_address;
+
+ table_address = (ATOM_Tonga_POWERPLAYTABLE *)
+ cgs_atom_get_data_table(hwmgr->device, index, &size, &frev, &crev);
+
+ hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/
+
+ return table_address;
+}
+
+static int get_vddc_lookup_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_voltage_lookup_table **lookup_table,
+ const ATOM_Tonga_Voltage_Lookup_Table *vddc_lookup_pp_tables,
+ uint32_t max_levels
+ )
+{
+ uint32_t table_size, i;
+ phm_ppt_v1_voltage_lookup_table *table;
+
+ PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
+ "Invalid CAC Leakage PowerPlay Table!", return 1);
+
+ table_size = sizeof(uint32_t) +
+ sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
+
+ table = (phm_ppt_v1_voltage_lookup_table *)
+ kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == table)
+ return -ENOMEM;
+
+ memset(table, 0x00, table_size);
+
+ table->count = vddc_lookup_pp_tables->ucNumEntries;
+
+ for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
+ table->entries[i].us_calculated = 0;
+ table->entries[i].us_vdd =
+ vddc_lookup_pp_tables->entries[i].usVdd;
+ table->entries[i].us_cac_low =
+ vddc_lookup_pp_tables->entries[i].usCACLow;
+ table->entries[i].us_cac_mid =
+ vddc_lookup_pp_tables->entries[i].usCACMid;
+ table->entries[i].us_cac_high =
+ vddc_lookup_pp_tables->entries[i].usCACHigh;
+ }
+
+ *lookup_table = table;
+
+ return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize Platform Power Management Parameter table
+ * @param hwmgr Pointer to the hardware manager.
+ * @param atom_ppm_table Pointer to PPM table in VBIOS
+ */
+static int get_platform_power_management_table(
+ struct pp_hwmgr *hwmgr,
+ ATOM_Tonga_PPM_Table *atom_ppm_table)
+{
+ struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL);
+ struct phm_ppt_v1_information *pp_table_information =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (NULL == ptr)
+ return -ENOMEM;
+
+ ptr->ppm_design
+ = atom_ppm_table->ucPpmDesign;
+ ptr->cpu_core_number
+ = atom_ppm_table->usCpuCoreNumber;
+ ptr->platform_tdp
+ = atom_ppm_table->ulPlatformTDP;
+ ptr->small_ac_platform_tdp
+ = atom_ppm_table->ulSmallACPlatformTDP;
+ ptr->platform_tdc
+ = atom_ppm_table->ulPlatformTDC;
+ ptr->small_ac_platform_tdc
+ = atom_ppm_table->ulSmallACPlatformTDC;
+ ptr->apu_tdp
+ = atom_ppm_table->ulApuTDP;
+ ptr->dgpu_tdp
+ = atom_ppm_table->ulDGpuTDP;
+ ptr->dgpu_ulv_power
+ = atom_ppm_table->ulDGpuUlvPower;
+ ptr->tj_max
+ = atom_ppm_table->ulTjmax;
+
+ pp_table_information->ppm_parameter_table = ptr;
+
+ return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize TDP limits for DPM2
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ */
+static int init_dpm_2_parameters(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+ )
+{
+ int result = 0;
+ struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ ATOM_Tonga_PPM_Table *atom_ppm_table;
+ uint32_t disable_ppm = 0;
+ uint32_t disable_power_control = 0;
+
+ pp_table_information->us_ulv_voltage_offset =
+ le16_to_cpu(powerplay_table->usUlvVoltageOffset);
+
+ pp_table_information->ppm_parameter_table = NULL;
+ pp_table_information->vddc_lookup_table = NULL;
+ pp_table_information->vddgfx_lookup_table = NULL;
+ /* TDP limits */
+ hwmgr->platform_descriptor.TDPODLimit =
+ le16_to_cpu(powerplay_table->usPowerControlLimit);
+ hwmgr->platform_descriptor.TDPAdjustment = 0;
+ hwmgr->platform_descriptor.VidAdjustment = 0;
+ hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
+ hwmgr->platform_descriptor.VidMinLimit = 0;
+ hwmgr->platform_descriptor.VidMaxLimit = 1500000;
+ hwmgr->platform_descriptor.VidStep = 6250;
+
+ disable_power_control = 0;
+ if (0 == disable_power_control) {
+ /* enable TDP overdrive (PowerControl) feature as well if supported */
+ if (hwmgr->platform_descriptor.TDPODLimit != 0)
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_PowerControl);
+ }
+
+ if (0 != powerplay_table->usVddcLookupTableOffset) {
+ const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
+ (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
+
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
+ }
+
+ if (0 != powerplay_table->usVddgfxLookupTableOffset) {
+ const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
+ (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
+
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
+ }
+
+ disable_ppm = 0;
+ if (0 == disable_ppm) {
+ atom_ppm_table = (ATOM_Tonga_PPM_Table *)
+ (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
+
+ if (0 != powerplay_table->usPPMTableOffset) {
+ if (1 == get_platform_power_management_table(hwmgr, atom_ppm_table)) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_EnablePlatformPowerManagement);
+ }
+ }
+ }
+
+ return result;
+}
+
+static int get_valid_clk(
+ struct pp_hwmgr *hwmgr,
+ struct phm_clock_array **clk_table,
+ const phm_ppt_v1_clock_voltage_dependency_table * clk_volt_pp_table
+ )
+{
+ uint32_t table_size, i;
+ struct phm_clock_array *table;
+
+ PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = sizeof(uint32_t) +
+ sizeof(uint32_t) * clk_volt_pp_table->count;
+
+ table = (struct phm_clock_array *)kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == table)
+ return -ENOMEM;
+
+ memset(table, 0x00, table_size);
+
+ table->count = (uint32_t)clk_volt_pp_table->count;
+
+ for (i = 0; i < table->count; i++)
+ table->values[i] = (uint32_t)clk_volt_pp_table->entries[i].clk;
+
+ *clk_table = table;
+
+ return 0;
+}
+
+static int get_hard_limits(
+ struct pp_hwmgr *hwmgr,
+ struct phm_clock_and_voltage_limits *limits,
+ const ATOM_Tonga_Hard_Limit_Table * limitable
+ )
+{
+ PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1);
+
+ /* currently we always take entries[0] parameters */
+ limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit;
+ limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit;
+ limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit;
+ limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit;
+ limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit;
+
+ return 0;
+}
+
+static int get_mclk_voltage_dependency_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table,
+ const ATOM_Tonga_MCLK_Dependency_Table * mclk_dep_table
+ )
+{
+ uint32_t table_size, i;
+ phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
+
+ PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+ * mclk_dep_table->ucNumEntries;
+
+ mclk_table = (phm_ppt_v1_clock_voltage_dependency_table *)
+ kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == mclk_table)
+ return -ENOMEM;
+
+ memset(mclk_table, 0x00, table_size);
+
+ mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
+
+ for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
+ mclk_table->entries[i].vddInd =
+ mclk_dep_table->entries[i].ucVddcInd;
+ mclk_table->entries[i].vdd_offset =
+ mclk_dep_table->entries[i].usVddgfxOffset;
+ mclk_table->entries[i].vddci =
+ mclk_dep_table->entries[i].usVddci;
+ mclk_table->entries[i].mvdd =
+ mclk_dep_table->entries[i].usMvdd;
+ mclk_table->entries[i].clk =
+ mclk_dep_table->entries[i].ulMclk;
+ }
+
+ *pp_tonga_mclk_dep_table = mclk_table;
+
+ return 0;
+}
+
+static int get_sclk_voltage_dependency_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table,
+ const ATOM_Tonga_SCLK_Dependency_Table * sclk_dep_table
+ )
+{
+ uint32_t table_size, i;
+ phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
+
+ PP_ASSERT_WITH_CODE((0 != sclk_dep_table->ucNumEntries),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
+ * sclk_dep_table->ucNumEntries;
+
+ sclk_table = (phm_ppt_v1_clock_voltage_dependency_table *)
+ kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == sclk_table)
+ return -ENOMEM;
+
+ memset(sclk_table, 0x00, table_size);
+
+ sclk_table->count = (uint32_t)sclk_dep_table->ucNumEntries;
+
+ for (i = 0; i < sclk_dep_table->ucNumEntries; i++) {
+ sclk_table->entries[i].vddInd =
+ sclk_dep_table->entries[i].ucVddInd;
+ sclk_table->entries[i].vdd_offset =
+ sclk_dep_table->entries[i].usVddcOffset;
+ sclk_table->entries[i].clk =
+ sclk_dep_table->entries[i].ulSclk;
+ sclk_table->entries[i].cks_enable =
+ (((sclk_dep_table->entries[i].ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
+ sclk_table->entries[i].cks_voffset =
+ (sclk_dep_table->entries[i].ucCKSVOffsetandDisable & 0x7F);
+ }
+
+ *pp_tonga_sclk_dep_table = sclk_table;
+
+ return 0;
+}
+
+static int get_pcie_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_pcie_table **pp_tonga_pcie_table,
+ const ATOM_Tonga_PCIE_Table * atom_pcie_table
+ )
+{
+ uint32_t table_size, i, pcie_count;
+ phm_ppt_v1_pcie_table *pcie_table;
+ struct phm_ppt_v1_information *pp_table_information =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ PP_ASSERT_WITH_CODE((0 != atom_pcie_table->ucNumEntries),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = sizeof(uint32_t) +
+ sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
+
+ pcie_table = (phm_ppt_v1_pcie_table *)kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == pcie_table)
+ return -ENOMEM;
+
+ memset(pcie_table, 0x00, table_size);
+
+ /*
+ * Make sure the number of pcie entries are less than or equal to sclk dpm levels.
+ * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
+ */
+ pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
+ if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
+ pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
+ else
+ printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
+ Disregarding the excess entries... \n");
+
+ pcie_table->count = pcie_count;
+
+ for (i = 0; i < pcie_count; i++) {
+ pcie_table->entries[i].gen_speed =
+ atom_pcie_table->entries[i].ucPCIEGenSpeed;
+ pcie_table->entries[i].lane_width =
+ atom_pcie_table->entries[i].usPCIELaneWidth;
+ }
+
+ *pp_tonga_pcie_table = pcie_table;
+
+ return 0;
+}
+
+static int get_cac_tdp_table(
+ struct pp_hwmgr *hwmgr,
+ struct phm_cac_tdp_table **cac_tdp_table,
+ const PPTable_Generic_SubTable_Header * table
+ )
+{
+ uint32_t table_size;
+ struct phm_cac_tdp_table *tdp_table;
+
+ table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table);
+ tdp_table = kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == tdp_table)
+ return -ENOMEM;
+
+ memset(tdp_table, 0x00, table_size);
+
+ hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == hwmgr->dyn_state.cac_dtp_table)
+ return -ENOMEM;
+
+ memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
+
+ if (table->ucRevId < 3) {
+ const ATOM_Tonga_PowerTune_Table *tonga_table =
+ (ATOM_Tonga_PowerTune_Table *)table;
+ tdp_table->usTDP = tonga_table->usTDP;
+ tdp_table->usConfigurableTDP =
+ tonga_table->usConfigurableTDP;
+ tdp_table->usTDC = tonga_table->usTDC;
+ tdp_table->usBatteryPowerLimit =
+ tonga_table->usBatteryPowerLimit;
+ tdp_table->usSmallPowerLimit =
+ tonga_table->usSmallPowerLimit;
+ tdp_table->usLowCACLeakage =
+ tonga_table->usLowCACLeakage;
+ tdp_table->usHighCACLeakage =
+ tonga_table->usHighCACLeakage;
+ tdp_table->usMaximumPowerDeliveryLimit =
+ tonga_table->usMaximumPowerDeliveryLimit;
+ tdp_table->usDefaultTargetOperatingTemp =
+ tonga_table->usTjMax;
+ tdp_table->usTargetOperatingTemp =
+ tonga_table->usTjMax; /*Set the initial temp to the same as default */
+ tdp_table->usPowerTuneDataSetID =
+ tonga_table->usPowerTuneDataSetID;
+ tdp_table->usSoftwareShutdownTemp =
+ tonga_table->usSoftwareShutdownTemp;
+ tdp_table->usClockStretchAmount =
+ tonga_table->usClockStretchAmount;
+ } else { /* Fiji and newer */
+ const ATOM_Fiji_PowerTune_Table *fijitable =
+ (ATOM_Fiji_PowerTune_Table *)table;
+ tdp_table->usTDP = fijitable->usTDP;
+ tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP;
+ tdp_table->usTDC = fijitable->usTDC;
+ tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit;
+ tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit;
+ tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage;
+ tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage;
+ tdp_table->usMaximumPowerDeliveryLimit =
+ fijitable->usMaximumPowerDeliveryLimit;
+ tdp_table->usDefaultTargetOperatingTemp =
+ fijitable->usTjMax;
+ tdp_table->usTargetOperatingTemp =
+ fijitable->usTjMax; /*Set the initial temp to the same as default */
+ tdp_table->usPowerTuneDataSetID =
+ fijitable->usPowerTuneDataSetID;
+ tdp_table->usSoftwareShutdownTemp =
+ fijitable->usSoftwareShutdownTemp;
+ tdp_table->usClockStretchAmount =
+ fijitable->usClockStretchAmount;
+ tdp_table->usTemperatureLimitHotspot =
+ fijitable->usTemperatureLimitHotspot;
+ tdp_table->usTemperatureLimitLiquid1 =
+ fijitable->usTemperatureLimitLiquid1;
+ tdp_table->usTemperatureLimitLiquid2 =
+ fijitable->usTemperatureLimitLiquid2;
+ tdp_table->usTemperatureLimitVrVddc =
+ fijitable->usTemperatureLimitVrVddc;
+ tdp_table->usTemperatureLimitVrMvdd =
+ fijitable->usTemperatureLimitVrMvdd;
+ tdp_table->usTemperatureLimitPlx =
+ fijitable->usTemperatureLimitPlx;
+ tdp_table->ucLiquid1_I2C_address =
+ fijitable->ucLiquid1_I2C_address;
+ tdp_table->ucLiquid2_I2C_address =
+ fijitable->ucLiquid2_I2C_address;
+ tdp_table->ucLiquid_I2C_Line =
+ fijitable->ucLiquid_I2C_Line;
+ tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address;
+ tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line;
+ tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address;
+ tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line;
+ }
+
+ *cac_tdp_table = tdp_table;
+
+ return 0;
+}
+
+static int get_mm_clock_voltage_table(
+ struct pp_hwmgr *hwmgr,
+ phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table,
+ const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table
+ )
+{
+ uint32_t table_size, i;
+ const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
+ phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
+
+ PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
+ "Invalid PowerPlay Table!", return -1);
+ table_size = sizeof(uint32_t) +
+ sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record)
+ * mm_dependency_table->ucNumEntries;
+ mm_table = (phm_ppt_v1_mm_clock_voltage_dependency_table *)
+ kzalloc(table_size, GFP_KERNEL);
+
+ if (NULL == mm_table)
+ return -ENOMEM;
+
+ memset(mm_table, 0x00, table_size);
+
+ mm_table->count = mm_dependency_table->ucNumEntries;
+
+ for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
+ mm_dependency_record = &mm_dependency_table->entries[i];
+ mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd;
+ mm_table->entries[i].vddgfx_offset = mm_dependency_record->usVddgfxOffset;
+ mm_table->entries[i].aclk = mm_dependency_record->ulAClk;
+ mm_table->entries[i].samclock = mm_dependency_record->ulSAMUClk;
+ mm_table->entries[i].eclk = mm_dependency_record->ulEClk;
+ mm_table->entries[i].vclk = mm_dependency_record->ulVClk;
+ mm_table->entries[i].dclk = mm_dependency_record->ulDClk;
+ }
+
+ *tonga_mm_table = mm_table;
+
+ return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Initialize clock voltage dependency
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ */
+static int init_clock_voltage_dependency(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+ )
+{
+ int result = 0;
+ struct phm_ppt_v1_information *pp_table_information =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
+ (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
+ const PPTable_Generic_SubTable_Header *pPowerTuneTable =
+ (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
+ const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
+ (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
+ const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
+ (const ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
+ const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
+ (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usHardLimitTableOffset));
+ const ATOM_Tonga_PCIE_Table *pcie_table =
+ (const ATOM_Tonga_PCIE_Table *)(((unsigned long) powerplay_table) +
+ le16_to_cpu(powerplay_table->usPCIETableOffset));
+
+ pp_table_information->vdd_dep_on_sclk = NULL;
+ pp_table_information->vdd_dep_on_mclk = NULL;
+ pp_table_information->mm_dep_table = NULL;
+ pp_table_information->pcie_table = NULL;
+
+ if (powerplay_table->usMMDependencyTableOffset != 0)
+ result = get_mm_clock_voltage_table(hwmgr,
+ &pp_table_information->mm_dep_table, mm_dependency_table);
+
+ if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
+ result = get_cac_tdp_table(hwmgr,
+ &pp_table_information->cac_dtp_table, pPowerTuneTable);
+
+ if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
+ result = get_sclk_voltage_dependency_table(hwmgr,
+ &pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
+
+ if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
+ result = get_mclk_voltage_dependency_table(hwmgr,
+ &pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
+
+ if (result == 0 && powerplay_table->usPCIETableOffset != 0)
+ result = get_pcie_table(hwmgr,
+ &pp_table_information->pcie_table, pcie_table);
+
+ if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
+ result = get_hard_limits(hwmgr,
+ &pp_table_information->max_clock_voltage_on_dc, pHardLimits);
+
+ hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
+ pp_table_information->max_clock_voltage_on_dc.sclk;
+ hwmgr->dyn_state.max_clock_voltage_on_dc.mclk =
+ pp_table_information->max_clock_voltage_on_dc.mclk;
+ hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
+ pp_table_information->max_clock_voltage_on_dc.vddc;
+ hwmgr->dyn_state.max_clock_voltage_on_dc.vddci =
+ pp_table_information->max_clock_voltage_on_dc.vddci;
+
+ if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk)
+ && (0 != pp_table_information->vdd_dep_on_mclk->count))
+ result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values,
+ pp_table_information->vdd_dep_on_mclk);
+
+ if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk)
+ && (0 != pp_table_information->vdd_dep_on_sclk->count))
+ result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
+ pp_table_information->vdd_dep_on_sclk);
+
+ return result;
+}
+
+/** Retrieves the (signed) Overdrive limits from VBIOS.
+ * The max engine clock, memory clock and max temperature come from the firmware info table.
+ *
+ * The information is placed into the platform descriptor.
+ *
+ * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated.
+ * @param powerplay_table the address of the PowerPlay table.
+ *
+ * @return 1 as long as the firmware info table was present and of a supported version.
+ */
+static int init_over_drive_limits(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
+{
+ hwmgr->platform_descriptor.overdriveLimit.engineClock =
+ le16_to_cpu(powerplay_table->ulMaxODEngineClock);
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock =
+ le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
+
+ hwmgr->platform_descriptor.minOverdriveVDDC = 0;
+ hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
+ hwmgr->platform_descriptor.overdriveVDDCStep = 0;
+
+ if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \
+ && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) {
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_ACOverdriveSupport);
+ }
+
+ return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Inspect the PowerPlay table for obvious signs of corruption.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ * @exception This implementation always returns 1.
+ */
+static int init_thermal_controller(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+ )
+{
+ const PPTable_Generic_SubTable_Header *fan_table;
+ ATOM_Tonga_Thermal_Controller *thermal_controller;
+
+ thermal_controller = (ATOM_Tonga_Thermal_Controller *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usThermalControllerOffset));
+ PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
+ "Thermal controller table not set!", return -1);
+
+ hwmgr->thermal_controller.ucType = thermal_controller->ucType;
+ hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
+ hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
+
+ hwmgr->thermal_controller.fanInfo.bNoFan =
+ (0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN));
+
+ hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
+ thermal_controller->ucFanParameters &
+ ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+
+ hwmgr->thermal_controller.fanInfo.ulMinRPM
+ = thermal_controller->ucFanMinRPM * 100UL;
+ hwmgr->thermal_controller.fanInfo.ulMaxRPM
+ = thermal_controller->ucFanMaxRPM * 100UL;
+
+ set_hw_cap(
+ hwmgr,
+ ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
+ PHM_PlatformCaps_ThermalController
+ );
+
+ if (0 == powerplay_table->usFanTableOffset)
+ return 0;
+
+ fan_table = (const PPTable_Generic_SubTable_Header *)
+ (((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usFanTableOffset));
+
+ PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
+ "Fan table not set!", return -1);
+ PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
+ "Unsupported fan table format!", return -1);
+
+ hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay
+ = 100000;
+ phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+ PHM_PlatformCaps_MicrocodeFanControl);
+
+ if (fan_table->ucRevId < 8) {
+ const ATOM_Tonga_Fan_Table *tonga_fan_table =
+ (ATOM_Tonga_Fan_Table *)fan_table;
+ hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
+ = tonga_fan_table->ucTHyst;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMin
+ = tonga_fan_table->usTMin;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMed
+ = tonga_fan_table->usTMed;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
+ = tonga_fan_table->usTHigh;
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
+ = tonga_fan_table->usPWMMin;
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
+ = tonga_fan_table->usPWMMed;
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
+ = tonga_fan_table->usPWMHigh;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+ = 10900; /* hard coded */
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+ = tonga_fan_table->usTMax;
+ hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
+ = tonga_fan_table->ucFanControlMode;
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
+ = tonga_fan_table->usFanPWMMax;
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
+ = 4836;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
+ = tonga_fan_table->usFanOutputSensitivity;
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
+ = tonga_fan_table->usFanRPMMax;
+ hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
+ = (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */
+ hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
+ = tonga_fan_table->ucTargetTemperature;
+ hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
+ = tonga_fan_table->ucMinimumPWMLimit;
+ } else {
+ const ATOM_Fiji_Fan_Table *fiji_fan_table =
+ (ATOM_Fiji_Fan_Table *)fan_table;
+ hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
+ = fiji_fan_table->ucTHyst;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMin
+ = fiji_fan_table->usTMin;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMed
+ = fiji_fan_table->usTMed;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
+ = fiji_fan_table->usTHigh;
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
+ = fiji_fan_table->usPWMMin;
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
+ = fiji_fan_table->usPWMMed;
+ hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
+ = fiji_fan_table->usPWMHigh;
+ hwmgr->thermal_controller.advanceFanControlParameters.usTMax
+ = fiji_fan_table->usTMax;
+ hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
+ = fiji_fan_table->ucFanControlMode;
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
+ = fiji_fan_table->usFanPWMMax;
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
+ = 4836;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
+ = fiji_fan_table->usFanOutputSensitivity;
+ hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
+ = fiji_fan_table->usFanRPMMax;
+ hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
+ = (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */
+ hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
+ = fiji_fan_table->ucTargetTemperature;
+ hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
+ = fiji_fan_table->ucMinimumPWMLimit;
+
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge
+ = fiji_fan_table->usFanGainEdge;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot
+ = fiji_fan_table->usFanGainHotspot;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid
+ = fiji_fan_table->usFanGainLiquid;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc
+ = fiji_fan_table->usFanGainVrVddc;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd
+ = fiji_fan_table->usFanGainVrMvdd;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx
+ = fiji_fan_table->usFanGainPlx;
+ hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm
+ = fiji_fan_table->usFanGainHbm;
+ }
+
+ return 0;
+}
+
+/**
+ * Private Function used during initialization.
+ * Inspect the PowerPlay table for obvious signs of corruption.
+ * @param hwmgr Pointer to the hardware manager.
+ * @param powerplay_table Pointer to the PowerPlay Table.
+ * @exception 2 if the powerplay table is incorrect.
+ */
+static int check_powerplay_tables(
+ struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
+ )
+{
+ const ATOM_Tonga_State_Array *state_arrays;
+
+ state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
+ le16_to_cpu(powerplay_table->usStateArrayOffset));
+
+ PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
+ powerplay_table->sHeader.ucTableFormatRevision),
+ "Unsupported PPTable format!", return -1);
+ PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset),
+ "State table is not set!", return -1);
+ PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
+ "Invalid PowerPlay Table!", return -1);
+ PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
+ "Invalid PowerPlay Table!", return -1);
+
+ return 0;
+}
+
+int tonga_pp_tables_initialize(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
+
+ hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
+
+ PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable),
+ "Failed to allocate hwmgr->pptable!", return -ENOMEM);
+
+ memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
+
+ powerplay_table = get_powerplay_table(hwmgr);
+
+ PP_ASSERT_WITH_CODE((NULL != powerplay_table),
+ "Missing PowerPlay Table!", return -1);
+
+ result = check_powerplay_tables(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "check_powerplay_tables failed", return result);
+
+ result = set_platform_caps(hwmgr,
+ le32_to_cpu(powerplay_table->ulPlatformCaps));
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "set_platform_caps failed", return result);
+
+ result = init_thermal_controller(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_thermal_controller failed", return result);
+
+ result = init_over_drive_limits(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_over_drive_limits failed", return result);
+
+ result = init_clock_voltage_dependency(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_clock_voltage_dependency failed", return result);
+
+ result = init_dpm_2_parameters(hwmgr, powerplay_table);
+
+ PP_ASSERT_WITH_CODE((result == 0),
+ "init_dpm_2_parameters failed", return result);
+
+ return result;
+}
+
+int tonga_pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
+{
+ int result = 0;
+ struct phm_ppt_v1_information *pp_table_information =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+
+ if (NULL != hwmgr->soft_pp_table) {
+ kfree(hwmgr->soft_pp_table);
+ hwmgr->soft_pp_table = NULL;
+ }
+
+ if (NULL != pp_table_information->vdd_dep_on_sclk)
+ pp_table_information->vdd_dep_on_sclk = NULL;
+
+ if (NULL != pp_table_information->vdd_dep_on_mclk)
+ pp_table_information->vdd_dep_on_mclk = NULL;
+
+ if (NULL != pp_table_information->valid_mclk_values)
+ pp_table_information->valid_mclk_values = NULL;
+
+ if (NULL != pp_table_information->valid_sclk_values)
+ pp_table_information->valid_sclk_values = NULL;
+
+ if (NULL != pp_table_information->vddc_lookup_table)
+ pp_table_information->vddc_lookup_table = NULL;
+
+ if (NULL != pp_table_information->vddgfx_lookup_table)
+ pp_table_information->vddgfx_lookup_table = NULL;
+
+ if (NULL != pp_table_information->mm_dep_table)
+ pp_table_information->mm_dep_table = NULL;
+
+ if (NULL != pp_table_information->cac_dtp_table)
+ pp_table_information->cac_dtp_table = NULL;
+
+ if (NULL != hwmgr->dyn_state.cac_dtp_table)
+ hwmgr->dyn_state.cac_dtp_table = NULL;
+
+ if (NULL != pp_table_information->ppm_parameter_table)
+ pp_table_information->ppm_parameter_table = NULL;
+
+ if (NULL != pp_table_information->pcie_table)
+ pp_table_information->pcie_table = NULL;
+
+ if (NULL != hwmgr->pptable) {
+ kfree(hwmgr->pptable);
+ hwmgr->pptable = NULL;
+ }
+
+ return result;
+}
+
+const struct pp_table_func tonga_pptable_funcs = {
+ .pptable_init = tonga_pp_tables_initialize,
+ .pptable_fini = tonga_pp_tables_uninitialize,
+};
+
+int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
+{
+ const ATOM_Tonga_State_Array * state_arrays;
+ const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+
+ PP_ASSERT_WITH_CODE((NULL != pp_table),
+ "Missing PowerPlay Table!", return -1);
+ PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
+ ATOM_Tonga_TABLE_REVISION_TONGA),
+ "Incorrect PowerPlay table revision!", return -1);
+
+ state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
+ le16_to_cpu(pp_table->usStateArrayOffset));
+
+ return (uint32_t)(state_arrays->ucNumEntries);
+}
+
+/**
+* Private function to convert flags stored in the BIOS to software flags in PowerPlay.
+*/
+static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
+ uint16_t classification, uint16_t classification2)
+{
+ uint32_t result = 0;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ result |= PP_StateClassificationFlag_Boot;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+ result |= PP_StateClassificationFlag_Thermal;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+ result |= PP_StateClassificationFlag_LimitedPowerSource;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
+ result |= PP_StateClassificationFlag_Rest;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
+ result |= PP_StateClassificationFlag_Forced;
+
+ if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
+ result |= PP_StateClassificationFlag_ACPI;
+
+ if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+ result |= PP_StateClassificationFlag_LimitedPowerSource_2;
+
+ return result;
+}
+
+/**
+* Create a Power State out of an entry in the PowerPlay table.
+* This function is called by the hardware back-end.
+* @param hwmgr Pointer to the hardware manager.
+* @param entry_index The index of the entry to be extracted from the table.
+* @param power_state The address of the PowerState instance being created.
+* @return -1 if the entry cannot be retrieved.
+*/
+int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr,
+ uint32_t entry_index, struct pp_power_state *power_state,
+ int (*call_back_func)(struct pp_hwmgr *, void *,
+ struct pp_power_state *, void *, uint32_t))
+{
+ int result = 0;
+ const ATOM_Tonga_State_Array * state_arrays;
+ const ATOM_Tonga_State *state_entry;
+ const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+
+ PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;);
+ power_state->classification.bios_index = entry_index;
+
+ if (pp_table->sHeader.ucTableFormatRevision >=
+ ATOM_Tonga_TABLE_REVISION_TONGA) {
+ state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
+ le16_to_cpu(pp_table->usStateArrayOffset));
+
+ PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
+ "Invalid PowerPlay Table State Array Offset.", return -1);
+ PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
+ "Invalid PowerPlay Table State Array.", return -1);
+ PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
+ "Invalid PowerPlay Table State Array Entry.", return -1);
+
+ state_entry = &(state_arrays->states[entry_index]);
+
+ result = call_back_func(hwmgr, (void *)state_entry, power_state,
+ (void *)pp_table,
+ make_classification_flags(hwmgr,
+ le16_to_cpu(state_entry->usClassification),
+ le16_to_cpu(state_entry->usClassification2)));
+ }
+
+ if (!result && (power_state->classification.flags &
+ PP_StateClassificationFlag_Boot))
+ result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware));
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h
new file mode 100644
index 000000000000..d24b8887f466
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 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 TONGA_PROCESSPPTABLES_H
+#define TONGA_PROCESSPPTABLES_H
+
+#include "hwmgr.h"
+
+extern const struct pp_table_func tonga_pptable_funcs;
+extern int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr);
+extern int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, uint32_t entry_index,
+ struct pp_power_state *power_state, int (*call_back_func)(struct pp_hwmgr *, void *,
+ struct pp_power_state *, void *, uint32_t));
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c
new file mode 100644
index 000000000000..a188174747c9
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <asm/div64.h>
+#include "tonga_thermal.h"
+#include "tonga_hwmgr.h"
+#include "tonga_smumgr.h"
+#include "tonga_ppsmc.h"
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+
+/**
+* Get Fan Speed Control Parameters.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pSpeed is the address of the structure where the result is to be placed.
+* @exception Always succeeds except if we cannot zero out the output structure.
+*/
+int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info)
+{
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ fan_speed_info->supports_percent_read = true;
+ fan_speed_info->supports_percent_write = true;
+ fan_speed_info->min_percent = 0;
+ fan_speed_info->max_percent = 100;
+
+ if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
+ fan_speed_info->supports_rpm_read = true;
+ fan_speed_info->supports_rpm_write = true;
+ fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
+ fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
+ } else {
+ fan_speed_info->min_rpm = 0;
+ fan_speed_info->max_rpm = 0;
+ }
+
+ return 0;
+}
+
+/**
+* Get Fan Speed in percent.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pSpeed is the address of the structure where the result is to be placed.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+ uint32_t duty100;
+ uint32_t duty;
+ uint64_t tmp64;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+ duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+ if (0 == duty100)
+ return -EINVAL;
+
+
+ tmp64 = (uint64_t)duty * 100;
+ do_div(tmp64, duty100);
+ *speed = (uint32_t)tmp64;
+
+ if (*speed > 100)
+ *speed = 100;
+
+ return 0;
+}
+
+/**
+* Get Fan Speed in RPM.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param speed is the address of the structure where the result is to be placed.
+* @exception Returns not supported if no fan is found or if pulses per revolution are not set
+*/
+int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
+{
+ return 0;
+}
+
+/**
+* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
+* @param hwmgr the address of the powerplay hardware manager.
+* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
+* @exception Should always succeed.
+*/
+int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
+{
+
+ if (hwmgr->fan_ctrl_is_in_default_mode) {
+ hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
+ hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
+ hwmgr->fan_ctrl_is_in_default_mode = false;
+ }
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
+
+ return 0;
+}
+
+/**
+* Reset Fan Speed Control to default mode.
+* @param hwmgr the address of the powerplay hardware manager.
+* @exception Should always succeed.
+*/
+int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
+{
+ if (!hwmgr->fan_ctrl_is_in_default_mode) {
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
+ hwmgr->fan_ctrl_is_in_default_mode = true;
+ }
+
+ return 0;
+}
+
+int tonga_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
+ cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
+ result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
+/*
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM))
+ hwmgr->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM);
+ else
+ hwmgr->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM);
+*/
+ } else {
+ cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
+ result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
+ }
+/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
+ if (result == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature != 0)
+ result = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanTemperatureTarget, \
+ hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature) ? 0 : -EINVAL);
+*/
+ return result;
+}
+
+
+int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
+{
+ return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL;
+}
+
+/**
+* Set Fan Speed in percent.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param speed is the percentage value (0% - 100%) to be set.
+* @exception Fails is the 100% setting appears to be 0.
+*/
+int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+ uint32_t duty100;
+ uint32_t duty;
+ uint64_t tmp64;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return -EINVAL;
+
+ if (speed > 100)
+ speed = 100;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
+ tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
+
+ duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+
+ if (0 == duty100)
+ return -EINVAL;
+
+ tmp64 = (uint64_t)speed * 100;
+ do_div(tmp64, duty100);
+ duty = (uint32_t)tmp64;
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
+
+ return tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+}
+
+/**
+* Reset Fan Speed to default.
+* @param hwmgr the address of the powerplay hardware manager.
+* @exception Always succeeds.
+*/
+int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ return 0;
+
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
+ result = tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+ if (0 == result)
+ result = tonga_fan_ctrl_start_smc_fan_control(hwmgr);
+ } else
+ result = tonga_fan_ctrl_set_default_mode(hwmgr);
+
+ return result;
+}
+
+/**
+* Set Fan Speed in RPM.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param speed is the percentage value (min - max) to be set.
+* @exception Fails is the speed not lie between min and max.
+*/
+int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
+{
+ return 0;
+}
+
+/**
+* Reads the remote temperature from the SIslands thermal controller.
+*
+* @param hwmgr The address of the hardware manager.
+*/
+int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr)
+{
+ int temp;
+
+ temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
+
+/* Bit 9 means the reading is lower than the lowest usable value. */
+ if (0 != (0x200 & temp))
+ temp = TONGA_THERMAL_MAXIMUM_TEMP_READING;
+ else
+ temp = (temp & 0x1ff);
+
+ temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ return temp;
+}
+
+/**
+* Set the requested temperature range for high and low alert signals
+*
+* @param hwmgr The address of the hardware manager.
+* @param range Temperature range to be programmed for high and low alert signals
+* @exception PP_Result_BadInput if the input data is not valid.
+*/
+static int tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
+{
+ uint32_t low = TONGA_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ uint32_t high = TONGA_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+ if (low < low_temp)
+ low = low_temp;
+ if (high > high_temp)
+ high = high_temp;
+
+ if (low > high)
+ return -EINVAL;
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+
+ return 0;
+}
+
+/**
+* Programs thermal controller one-time setting registers
+*
+* @param hwmgr The address of the hardware manager.
+*/
+static int tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+ if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+ CG_TACH_CTRL, EDGE_PER_REV,
+ hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
+
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
+
+ return 0;
+}
+
+/**
+* Enable thermal alerts on the RV770 thermal controller.
+*
+* @param hwmgr The address of the hardware manager.
+*/
+static int tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr)
+{
+ uint32_t alert;
+
+ alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
+ alert &= ~(TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+ /* send message to SMU to enable internal thermal interrupts */
+ return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
+}
+
+/**
+* Disable thermal alerts on the RV770 thermal controller.
+* @param hwmgr The address of the hardware manager.
+*/
+static int tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr)
+{
+ uint32_t alert;
+
+ alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
+ alert |= (TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
+ PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
+
+ /* send message to SMU to disable internal thermal interrupts */
+ return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
+}
+
+/**
+* Uninitialize the thermal controller.
+* Currently just disables alerts.
+* @param hwmgr The address of the hardware manager.
+*/
+int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+ int result = tonga_thermal_disable_alert(hwmgr);
+
+ if (hwmgr->thermal_controller.fanInfo.bNoFan)
+ tonga_fan_ctrl_set_default_mode(hwmgr);
+
+ return result;
+}
+
+/**
+* Set up the fan table to control the fan using the SMC.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from set temperature range routine
+*/
+int tf_tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+ struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
+ SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+ uint32_t duty100;
+ uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+ uint16_t fdo_min, slope1, slope2;
+ uint32_t reference_clock;
+ int res;
+ uint64_t tmp64;
+
+ if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
+ return 0;
+
+ if (0 == data->fan_table_start) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+ return 0;
+ }
+
+ duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
+
+ if (0 == duty100) {
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+ return 0;
+ }
+
+ tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
+ do_div(tmp64, 10000);
+ fdo_min = (uint16_t)tmp64;
+
+ t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
+ t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
+
+ pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
+ pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
+
+ slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+ slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+ fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
+ fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
+ fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
+
+ fan_table.Slope1 = cpu_to_be16(slope1);
+ fan_table.Slope2 = cpu_to_be16(slope2);
+
+ fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+ fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
+
+ fan_table.HystUp = cpu_to_be16(1);
+
+ fan_table.HystSlope = cpu_to_be16(1);
+
+ fan_table.TempRespLim = cpu_to_be16(5);
+
+ reference_clock = tonga_get_xclk(hwmgr);
+
+ fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
+
+ fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
+
+ fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
+
+ fan_table.FanControl_GL_Flag = 1;
+
+ res = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
+/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
+ if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
+ res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
+ hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
+
+ if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
+ res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
+ hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
+
+ if (0 != res)
+ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
+*/
+ return 0;
+}
+
+/**
+* Start the fan control on the SMC.
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from set temperature range routine
+*/
+int tf_tonga_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
+ * Make sure that we still think controlling the fan is OK.
+*/
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
+ tonga_fan_ctrl_start_smc_fan_control(hwmgr);
+ tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
+ }
+
+ return 0;
+}
+
+/**
+* Set temperature range for high and low alerts
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from set temperature range routine
+*/
+int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+ struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
+
+ if (range == NULL)
+ return -EINVAL;
+
+ return tonga_thermal_set_temperature_range(hwmgr, range->min, range->max);
+}
+
+/**
+* Programs one-time setting registers
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from initialize thermal controller routine
+*/
+int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+ return tonga_thermal_initialize(hwmgr);
+}
+
+/**
+* Enable high and low alerts
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from enable alert routine
+*/
+int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+ return tonga_thermal_enable_alert(hwmgr);
+}
+
+/**
+* Disable high and low alerts
+* @param hwmgr the address of the powerplay hardware manager.
+* @param pInput the pointer to input data
+* @param pOutput the pointer to output data
+* @param pStorage the pointer to temporary storage
+* @param Result the last failure code
+* @return result from disable alert routine
+*/
+static int tf_tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
+{
+ return tonga_thermal_disable_alert(hwmgr);
+}
+
+static struct phm_master_table_item tonga_thermal_start_thermal_controller_master_list[] = {
+ { NULL, tf_tonga_thermal_initialize },
+ { NULL, tf_tonga_thermal_set_temperature_range },
+ { NULL, tf_tonga_thermal_enable_alert },
+/* We should restrict performance levels to low before we halt the SMC.
+ * On the other hand we are still in boot state when we do this so it would be pointless.
+ * If this assumption changes we have to revisit this table.
+ */
+ { NULL, tf_tonga_thermal_setup_fan_table},
+ { NULL, tf_tonga_thermal_start_smc_fan_control},
+ { NULL, NULL }
+};
+
+static struct phm_master_table_header tonga_thermal_start_thermal_controller_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ tonga_thermal_start_thermal_controller_master_list
+};
+
+static struct phm_master_table_item tonga_thermal_set_temperature_range_master_list[] = {
+ { NULL, tf_tonga_thermal_disable_alert},
+ { NULL, tf_tonga_thermal_set_temperature_range},
+ { NULL, tf_tonga_thermal_enable_alert},
+ { NULL, NULL }
+};
+
+struct phm_master_table_header tonga_thermal_set_temperature_range_master = {
+ 0,
+ PHM_MasterTableFlag_None,
+ tonga_thermal_set_temperature_range_master_list
+};
+
+int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
+{
+ if (!hwmgr->thermal_controller.fanInfo.bNoFan)
+ tonga_fan_ctrl_set_default_mode(hwmgr);
+ return 0;
+}
+
+/**
+* Initializes the thermal controller related functions in the Hardware Manager structure.
+* @param hwmgr The address of the hardware manager.
+* @exception Any error code from the low-level communication.
+*/
+int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
+{
+ int result;
+
+ result = phm_construct_table(hwmgr, &tonga_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
+
+ if (0 == result) {
+ result = phm_construct_table(hwmgr,
+ &tonga_thermal_start_thermal_controller_master,
+ &(hwmgr->start_thermal_controller));
+ if (0 != result)
+ phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
+ }
+
+ if (0 == result)
+ hwmgr->fan_ctrl_is_in_default_mode = true;
+ return result;
+}
+
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h
new file mode 100644
index 000000000000..aa335f267e25
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_thermal.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 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 TONGA_THERMAL_H
+#define TONGA_THERMAL_H
+
+#include "hwmgr.h"
+
+#define TONGA_THERMAL_HIGH_ALERT_MASK 0x1
+#define TONGA_THERMAL_LOW_ALERT_MASK 0x2
+
+#define TONGA_THERMAL_MINIMUM_TEMP_READING -256
+#define TONGA_THERMAL_MAXIMUM_TEMP_READING 255
+
+#define TONGA_THERMAL_MINIMUM_ALERT_TEMP 0
+#define TONGA_THERMAL_MAXIMUM_ALERT_TEMP 255
+
+#define FDO_PWM_MODE_STATIC 1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+
+extern int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+extern int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
+
+extern int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr);
+extern int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+extern int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
+extern int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
+extern int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
+extern int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr);
+extern int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
+extern int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
+extern int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
+extern int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
new file mode 100644
index 000000000000..e61a3e67852e
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2015 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 _AMD_POWERPLAY_H_
+#define _AMD_POWERPLAY_H_
+
+#include <linux/seq_file.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include "amd_shared.h"
+#include "cgs_common.h"
+
+enum amd_pp_event {
+ AMD_PP_EVENT_INITIALIZE = 0,
+ AMD_PP_EVENT_UNINITIALIZE,
+ AMD_PP_EVENT_POWER_SOURCE_CHANGE,
+ AMD_PP_EVENT_SUSPEND,
+ AMD_PP_EVENT_RESUME,
+ AMD_PP_EVENT_ENTER_REST_STATE,
+ AMD_PP_EVENT_EXIT_REST_STATE,
+ AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE,
+ AMD_PP_EVENT_THERMAL_NOTIFICATION,
+ AMD_PP_EVENT_VBIOS_NOTIFICATION,
+ AMD_PP_EVENT_ENTER_THERMAL_STATE,
+ AMD_PP_EVENT_EXIT_THERMAL_STATE,
+ AMD_PP_EVENT_ENTER_FORCED_STATE,
+ AMD_PP_EVENT_EXIT_FORCED_STATE,
+ AMD_PP_EVENT_ENTER_EXCLUSIVE_MODE,
+ AMD_PP_EVENT_EXIT_EXCLUSIVE_MODE,
+ AMD_PP_EVENT_ENTER_SCREEN_SAVER,
+ AMD_PP_EVENT_EXIT_SCREEN_SAVER,
+ AMD_PP_EVENT_VPU_RECOVERY_BEGIN,
+ AMD_PP_EVENT_VPU_RECOVERY_END,
+ AMD_PP_EVENT_ENABLE_POWER_PLAY,
+ AMD_PP_EVENT_DISABLE_POWER_PLAY,
+ AMD_PP_EVENT_CHANGE_POWER_SOURCE_UI_LABEL,
+ AMD_PP_EVENT_ENABLE_USER2D_PERFORMANCE,
+ AMD_PP_EVENT_DISABLE_USER2D_PERFORMANCE,
+ AMD_PP_EVENT_ENABLE_USER3D_PERFORMANCE,
+ AMD_PP_EVENT_DISABLE_USER3D_PERFORMANCE,
+ AMD_PP_EVENT_ENABLE_OVER_DRIVE_TEST,
+ AMD_PP_EVENT_DISABLE_OVER_DRIVE_TEST,
+ AMD_PP_EVENT_ENABLE_REDUCED_REFRESH_RATE,
+ AMD_PP_EVENT_DISABLE_REDUCED_REFRESH_RATE,
+ AMD_PP_EVENT_ENABLE_GFX_CLOCK_GATING,
+ AMD_PP_EVENT_DISABLE_GFX_CLOCK_GATING,
+ AMD_PP_EVENT_ENABLE_CGPG,
+ AMD_PP_EVENT_DISABLE_CGPG,
+ AMD_PP_EVENT_ENTER_TEXT_MODE,
+ AMD_PP_EVENT_EXIT_TEXT_MODE,
+ AMD_PP_EVENT_VIDEO_START,
+ AMD_PP_EVENT_VIDEO_STOP,
+ AMD_PP_EVENT_ENABLE_USER_STATE,
+ AMD_PP_EVENT_DISABLE_USER_STATE,
+ AMD_PP_EVENT_READJUST_POWER_STATE,
+ AMD_PP_EVENT_START_INACTIVITY,
+ AMD_PP_EVENT_STOP_INACTIVITY,
+ AMD_PP_EVENT_LINKED_ADAPTERS_READY,
+ AMD_PP_EVENT_ADAPTER_SAFE_TO_DISABLE,
+ AMD_PP_EVENT_COMPLETE_INIT,
+ AMD_PP_EVENT_CRITICAL_THERMAL_FAULT,
+ AMD_PP_EVENT_BACKLIGHT_CHANGED,
+ AMD_PP_EVENT_ENABLE_VARI_BRIGHT,
+ AMD_PP_EVENT_DISABLE_VARI_BRIGHT,
+ AMD_PP_EVENT_ENABLE_VARI_BRIGHT_ON_POWER_XPRESS,
+ AMD_PP_EVENT_DISABLE_VARI_BRIGHT_ON_POWER_XPRESS,
+ AMD_PP_EVENT_SET_VARI_BRIGHT_LEVEL,
+ AMD_PP_EVENT_VARI_BRIGHT_MONITOR_MEASUREMENT,
+ AMD_PP_EVENT_SCREEN_ON,
+ AMD_PP_EVENT_SCREEN_OFF,
+ AMD_PP_EVENT_PRE_DISPLAY_CONFIG_CHANGE,
+ AMD_PP_EVENT_ENTER_ULP_STATE,
+ AMD_PP_EVENT_EXIT_ULP_STATE,
+ AMD_PP_EVENT_REGISTER_IP_STATE,
+ AMD_PP_EVENT_UNREGISTER_IP_STATE,
+ AMD_PP_EVENT_ENTER_MGPU_MODE,
+ AMD_PP_EVENT_EXIT_MGPU_MODE,
+ AMD_PP_EVENT_ENTER_MULTI_GPU_MODE,
+ AMD_PP_EVENT_PRE_SUSPEND,
+ AMD_PP_EVENT_PRE_RESUME,
+ AMD_PP_EVENT_ENTER_BACOS,
+ AMD_PP_EVENT_EXIT_BACOS,
+ AMD_PP_EVENT_RESUME_BACO,
+ AMD_PP_EVENT_RESET_BACO,
+ AMD_PP_EVENT_PRE_DISPLAY_PHY_ACCESS,
+ AMD_PP_EVENT_POST_DISPLAY_PHY_CCESS,
+ AMD_PP_EVENT_START_COMPUTE_APPLICATION,
+ AMD_PP_EVENT_STOP_COMPUTE_APPLICATION,
+ AMD_PP_EVENT_REDUCE_POWER_LIMIT,
+ AMD_PP_EVENT_ENTER_FRAME_LOCK,
+ AMD_PP_EVENT_EXIT_FRAME_LOOCK,
+ AMD_PP_EVENT_LONG_IDLE_REQUEST_BACO,
+ AMD_PP_EVENT_LONG_IDLE_ENTER_BACO,
+ AMD_PP_EVENT_LONG_IDLE_EXIT_BACO,
+ AMD_PP_EVENT_HIBERNATE,
+ AMD_PP_EVENT_CONNECTED_STANDBY,
+ AMD_PP_EVENT_ENTER_SELF_REFRESH,
+ AMD_PP_EVENT_EXIT_SELF_REFRESH,
+ AMD_PP_EVENT_START_AVFS_BTC,
+ AMD_PP_EVENT_MAX
+};
+
+enum amd_dpm_forced_level {
+ AMD_DPM_FORCED_LEVEL_AUTO = 0,
+ AMD_DPM_FORCED_LEVEL_LOW = 1,
+ AMD_DPM_FORCED_LEVEL_HIGH = 2,
+};
+
+struct amd_pp_init {
+ struct cgs_device *device;
+ uint32_t chip_family;
+ uint32_t chip_id;
+ uint32_t rev_id;
+};
+enum amd_pp_display_config_type{
+ AMD_PP_DisplayConfigType_None = 0,
+ AMD_PP_DisplayConfigType_DP54 ,
+ AMD_PP_DisplayConfigType_DP432 ,
+ AMD_PP_DisplayConfigType_DP324 ,
+ AMD_PP_DisplayConfigType_DP27,
+ AMD_PP_DisplayConfigType_DP243,
+ AMD_PP_DisplayConfigType_DP216,
+ AMD_PP_DisplayConfigType_DP162,
+ AMD_PP_DisplayConfigType_HDMI6G ,
+ AMD_PP_DisplayConfigType_HDMI297 ,
+ AMD_PP_DisplayConfigType_HDMI162,
+ AMD_PP_DisplayConfigType_LVDS,
+ AMD_PP_DisplayConfigType_DVI,
+ AMD_PP_DisplayConfigType_WIRELESS,
+ AMD_PP_DisplayConfigType_VGA
+};
+
+struct single_display_configuration
+{
+ uint32_t controller_index;
+ uint32_t controller_id;
+ uint32_t signal_type;
+ uint32_t display_state;
+ /* phy id for the primary internal transmitter */
+ uint8_t primary_transmitter_phyi_d;
+ /* bitmap with the active lanes */
+ uint8_t primary_transmitter_active_lanemap;
+ /* phy id for the secondary internal transmitter (for dual-link dvi) */
+ uint8_t secondary_transmitter_phy_id;
+ /* bitmap with the active lanes */
+ uint8_t secondary_transmitter_active_lanemap;
+ /* misc phy settings for SMU. */
+ uint32_t config_flags;
+ uint32_t display_type;
+ uint32_t view_resolution_cx;
+ uint32_t view_resolution_cy;
+ enum amd_pp_display_config_type displayconfigtype;
+ uint32_t vertical_refresh; /* for active display */
+};
+
+#define MAX_NUM_DISPLAY 32
+
+struct amd_pp_display_configuration {
+ bool nb_pstate_switch_disable;/* controls NB PState switch */
+ bool cpu_cc6_disable; /* controls CPU CState switch ( on or off) */
+ bool cpu_pstate_disable;
+ uint32_t cpu_pstate_separation_time;
+
+ uint32_t num_display; /* total number of display*/
+ uint32_t num_path_including_non_display;
+ uint32_t crossfire_display_index;
+ uint32_t min_mem_set_clock;
+ uint32_t min_core_set_clock;
+ /* unit 10KHz x bit*/
+ uint32_t min_bus_bandwidth;
+ /* minimum required stutter sclk, in 10khz uint32_t ulMinCoreSetClk;*/
+ uint32_t min_core_set_clock_in_sr;
+
+ struct single_display_configuration displays[MAX_NUM_DISPLAY];
+
+ uint32_t vrefresh; /* for active display*/
+
+ uint32_t min_vblank_time; /* for active display*/
+ bool multi_monitor_in_sync;
+ /* Controller Index of primary display - used in MCLK SMC switching hang
+ * SW Workaround*/
+ uint32_t crtc_index;
+ /* htotal*1000/pixelclk - used in MCLK SMC switching hang SW Workaround*/
+ uint32_t line_time_in_us;
+ bool invalid_vblank_time;
+
+ uint32_t display_clk;
+ /*
+ * for given display configuration if multimonitormnsync == false then
+ * Memory clock DPMS with this latency or below is allowed, DPMS with
+ * higher latency not allowed.
+ */
+ uint32_t dce_tolerable_mclk_in_active_latency;
+};
+
+struct amd_pp_dal_clock_info {
+ uint32_t engine_max_clock;
+ uint32_t memory_max_clock;
+ uint32_t level;
+};
+
+enum {
+ PP_GROUP_UNKNOWN = 0,
+ PP_GROUP_GFX = 1,
+ PP_GROUP_SYS,
+ PP_GROUP_MAX
+};
+
+#define PP_GROUP_MASK 0xF0000000
+#define PP_GROUP_SHIFT 28
+
+#define PP_BLOCK_MASK 0x0FFFFF00
+#define PP_BLOCK_SHIFT 8
+
+#define PP_BLOCK_GFX_CG 0x01
+#define PP_BLOCK_GFX_MG 0x02
+#define PP_BLOCK_SYS_BIF 0x01
+#define PP_BLOCK_SYS_MC 0x02
+#define PP_BLOCK_SYS_ROM 0x04
+#define PP_BLOCK_SYS_DRM 0x08
+#define PP_BLOCK_SYS_HDP 0x10
+#define PP_BLOCK_SYS_SDMA 0x20
+
+#define PP_STATE_MASK 0x0000000F
+#define PP_STATE_SHIFT 0
+#define PP_STATE_SUPPORT_MASK 0x000000F0
+#define PP_STATE_SUPPORT_SHIFT 0
+
+#define PP_STATE_CG 0x01
+#define PP_STATE_LS 0x02
+#define PP_STATE_DS 0x04
+#define PP_STATE_SD 0x08
+#define PP_STATE_SUPPORT_CG 0x10
+#define PP_STATE_SUPPORT_LS 0x20
+#define PP_STATE_SUPPORT_DS 0x40
+#define PP_STATE_SUPPORT_SD 0x80
+
+#define PP_CG_MSG_ID(group, block, support, state) (group << PP_GROUP_SHIFT |\
+ block << PP_BLOCK_SHIFT |\
+ support << PP_STATE_SUPPORT_SHIFT |\
+ state << PP_STATE_SHIFT)
+
+struct amd_powerplay_funcs {
+ int (*get_temperature)(void *handle);
+ int (*load_firmware)(void *handle);
+ int (*wait_for_fw_loading_complete)(void *handle);
+ int (*force_performance_level)(void *handle, enum amd_dpm_forced_level level);
+ enum amd_dpm_forced_level (*get_performance_level)(void *handle);
+ enum amd_pm_state_type (*get_current_power_state)(void *handle);
+ int (*get_sclk)(void *handle, bool low);
+ int (*get_mclk)(void *handle, bool low);
+ int (*powergate_vce)(void *handle, bool gate);
+ int (*powergate_uvd)(void *handle, bool gate);
+ int (*dispatch_tasks)(void *handle, enum amd_pp_event event_id,
+ void *input, void *output);
+ void (*print_current_performance_level)(void *handle,
+ struct seq_file *m);
+ int (*set_fan_control_mode)(void *handle, uint32_t mode);
+ int (*get_fan_control_mode)(void *handle);
+ int (*set_fan_speed_percent)(void *handle, uint32_t percent);
+ int (*get_fan_speed_percent)(void *handle, uint32_t *speed);
+};
+
+struct amd_powerplay {
+ void *pp_handle;
+ const struct amd_ip_funcs *ip_funcs;
+ const struct amd_powerplay_funcs *pp_funcs;
+};
+
+int amd_powerplay_init(struct amd_pp_init *pp_init,
+ struct amd_powerplay *amd_pp);
+int amd_powerplay_fini(void *handle);
+
+int amd_powerplay_display_configuration_change(void *handle, const void *input);
+
+int amd_powerplay_get_display_power_level(void *handle,
+ struct amd_pp_dal_clock_info *output);
+
+
+#endif /* _AMD_POWERPLAY_H_ */
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h
index 273616ab43db..9b698780aed8 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h
@@ -164,6 +164,7 @@ enum DPM_ARRAY {
#define PPSMC_MSG_SetLoggerAddressHigh ((uint16_t) 0x26C)
#define PPSMC_MSG_SetLoggerAddressLow ((uint16_t) 0x26D)
#define PPSMC_MSG_SetWatermarkFrequency ((uint16_t) 0x26E)
+#define PPSMC_MSG_SetDisplaySizePowerParams ((uint16_t) 0x26F)
/* REMOVE LATER*/
#define PPSMC_MSG_DPM_ForceState ((uint16_t) 0x104)
diff --git a/drivers/gpu/drm/amd/powerplay/inc/eventmanager.h b/drivers/gpu/drm/amd/powerplay/inc/eventmanager.h
new file mode 100644
index 000000000000..b9d84de8a44d
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/eventmanager.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 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 _EVENT_MANAGER_H_
+#define _EVENT_MANAGER_H_
+
+#include "power_state.h"
+#include "pp_power_source.h"
+#include "hardwaremanager.h"
+#include "pp_asicblocks.h"
+
+struct pp_eventmgr;
+enum amd_pp_event;
+
+enum PEM_EventDataValid {
+ PEM_EventDataValid_RequestedStateID = 0,
+ PEM_EventDataValid_RequestedUILabel,
+ PEM_EventDataValid_NewPowerState,
+ PEM_EventDataValid_RequestedPowerSource,
+ PEM_EventDataValid_RequestedClocks,
+ PEM_EventDataValid_CurrentTemperature,
+ PEM_EventDataValid_AsicBlocks,
+ PEM_EventDataValid_ODParameters,
+ PEM_EventDataValid_PXAdapterPrefs,
+ PEM_EventDataValid_PXUserPrefs,
+ PEM_EventDataValid_PXSwitchReason,
+ PEM_EventDataValid_PXSwitchPhase,
+ PEM_EventDataValid_HdVideo,
+ PEM_EventDataValid_BacklightLevel,
+ PEM_EventDatavalid_VariBrightParams,
+ PEM_EventDataValid_VariBrightLevel,
+ PEM_EventDataValid_VariBrightImmediateChange,
+ PEM_EventDataValid_PercentWhite,
+ PEM_EventDataValid_SdVideo,
+ PEM_EventDataValid_HTLinkChangeReason,
+ PEM_EventDataValid_HWBlocks,
+ PEM_EventDataValid_RequestedThermalState,
+ PEM_EventDataValid_MvcVideo,
+ PEM_EventDataValid_Max
+};
+
+typedef enum PEM_EventDataValid PEM_EventDataValid;
+
+/* Number of bits in ULONG variable */
+#define PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD (sizeof(unsigned long)*8)
+
+/* Number of ULONG entries used by event data valid bits */
+#define PEM_MAX_NUM_EVENTDATAVALID_ULONG_ENTRIES \
+ ((PEM_EventDataValid_Max + PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD - 1) / \
+ PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD)
+
+static inline void pem_set_event_data_valid(unsigned long *fields, PEM_EventDataValid valid_field)
+{
+ fields[valid_field / PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD] |=
+ (1UL << (valid_field % PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD));
+}
+
+static inline void pem_unset_event_data_valid(unsigned long *fields, PEM_EventDataValid valid_field)
+{
+ fields[valid_field / PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD] &=
+ ~(1UL << (valid_field % PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD));
+}
+
+static inline unsigned long pem_is_event_data_valid(const unsigned long *fields, PEM_EventDataValid valid_field)
+{
+ return fields[valid_field / PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD] &
+ (1UL << (valid_field % PEM_MAX_NUM_EVENTDATAVALID_BITS_PER_FIELD));
+}
+
+struct pem_event_data {
+ unsigned long valid_fields[100];
+ unsigned long requested_state_id;
+ enum PP_StateUILabel requested_ui_label;
+ struct pp_power_state *pnew_power_state;
+ enum pp_power_source requested_power_source;
+ struct PP_Clocks requested_clocks;
+ bool skip_state_adjust_rules;
+ struct phm_asic_blocks asic_blocks;
+ /* to doPP_ThermalState requestedThermalState;
+ enum ThermalStateRequestSrc requestThermalStateSrc;
+ PP_Temperature currentTemperature;*/
+
+};
+
+int pem_handle_event(struct pp_eventmgr *eventmgr, enum amd_pp_event event,
+ struct pem_event_data *event_data);
+
+bool pem_is_hw_access_blocked(struct pp_eventmgr *eventmgr);
+
+#endif /* _EVENT_MANAGER_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h b/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
new file mode 100644
index 000000000000..10437dcfd365
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/eventmgr.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 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 _EVENTMGR_H_
+#define _EVENTMGR_H_
+
+#include <linux/mutex.h>
+#include "pp_instance.h"
+#include "hardwaremanager.h"
+#include "eventmanager.h"
+#include "pp_feature.h"
+#include "pp_power_source.h"
+#include "power_state.h"
+
+typedef int (*pem_event_action)(struct pp_eventmgr *eventmgr,
+ struct pem_event_data *event_data);
+
+struct action_chain {
+ const char *description; /* action chain description for debugging purpose */
+ const pem_event_action **action_chain; /* pointer to chain of event actions */
+};
+
+struct pem_power_source_ui_state_info {
+ enum PP_StateUILabel current_ui_label;
+ enum PP_StateUILabel default_ui_lable;
+ unsigned long configurable_ui_mapping;
+};
+
+struct pp_clock_range {
+ uint32_t min_sclk_khz;
+ uint32_t max_sclk_khz;
+
+ uint32_t min_mclk_khz;
+ uint32_t max_mclk_khz;
+
+ uint32_t min_vclk_khz;
+ uint32_t max_vclk_khz;
+
+ uint32_t min_dclk_khz;
+ uint32_t max_dclk_khz;
+
+ uint32_t min_aclk_khz;
+ uint32_t max_aclk_khz;
+
+ uint32_t min_eclk_khz;
+ uint32_t max_eclk_khz;
+};
+
+enum pp_state {
+ UNINITIALIZED,
+ INACTIVE,
+ ACTIVE
+};
+
+enum pp_ring_index {
+ PP_RING_TYPE_GFX_INDEX = 0,
+ PP_RING_TYPE_DMA_INDEX,
+ PP_RING_TYPE_DMA1_INDEX,
+ PP_RING_TYPE_UVD_INDEX,
+ PP_RING_TYPE_VCE0_INDEX,
+ PP_RING_TYPE_VCE1_INDEX,
+ PP_RING_TYPE_CP1_INDEX,
+ PP_RING_TYPE_CP2_INDEX,
+ PP_NUM_RINGS,
+};
+
+struct pp_request {
+ uint32_t flags;
+ uint32_t sclk;
+ uint32_t sclk_throttle;
+ uint32_t mclk;
+ uint32_t vclk;
+ uint32_t dclk;
+ uint32_t eclk;
+ uint32_t aclk;
+ uint32_t iclk;
+ uint32_t vp8clk;
+ uint32_t rsv[32];
+};
+
+struct pp_eventmgr {
+ struct pp_hwmgr *hwmgr;
+ struct pp_smumgr *smumgr;
+
+ struct pp_feature_info features[PP_Feature_Max];
+ const struct action_chain *event_chain[AMD_PP_EVENT_MAX];
+ struct phm_platform_descriptor *platform_descriptor;
+ struct pp_clock_range clock_range;
+ enum pp_power_source current_power_source;
+ struct pem_power_source_ui_state_info ui_state_info[PP_PowerSource_Max];
+ enum pp_state states[PP_NUM_RINGS];
+ struct pp_request hi_req;
+ struct list_head context_list;
+ struct mutex lock;
+ bool block_adjust_power_state;
+ bool enable_cg;
+ bool enable_gfx_cgpg;
+ int (*pp_eventmgr_init)(struct pp_eventmgr *eventmgr);
+ void (*pp_eventmgr_fini)(struct pp_eventmgr *eventmgr);
+};
+
+int eventmgr_init(struct pp_instance *handle);
+int eventmgr_fini(struct pp_eventmgr *eventmgr);
+
+#endif /* _EVENTMGR_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h
new file mode 100644
index 000000000000..7ae494569a60
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2015 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 _FIJI_PP_SMC_H_
+#define _FIJI_PP_SMC_H_
+
+#pragma pack(push, 1)
+
+#define PPSMC_SWSTATE_FLAG_DC 0x01
+#define PPSMC_SWSTATE_FLAG_UVD 0x02
+#define PPSMC_SWSTATE_FLAG_VCE 0x04
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
+#define PPSMC_SYSTEMFLAG_GDDR5 0x04
+
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
+
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
+
+/* Defines for DPM 2.0 */
+#define PPSMC_DPM2FLAGS_TDPCLMP 0x01
+#define PPSMC_DPM2FLAGS_PWRSHFT 0x02
+#define PPSMC_DPM2FLAGS_OCP 0x04
+
+/* Defines for display watermark level */
+#define PPSMC_DISPLAY_WATERMARK_LOW 0
+#define PPSMC_DISPLAY_WATERMARK_HIGH 1
+
+/* In the HW performance level's state flags: */
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
+#define PPSMC_STATEFLAG_POWERBOOST 0x02
+#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
+#define PPSMC_STATEFLAG_POWERSHIFT 0x08
+#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10
+#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
+#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
+
+/* Fan control algorithm: */
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+ FAN_CONTROL_FUZZY,
+ FAN_CONTROL_TABLE
+};
+
+/* Gemini Modes*/
+#define PPSMC_GeminiModeNone 0 /*Single GPU board*/
+#define PPSMC_GeminiModeMaster 1 /*Master GPU on a Gemini board*/
+#define PPSMC_GeminiModeSlave 2 /*Slave GPU on a Gemini board*/
+
+
+/* Return codes for driver to SMC communication. */
+#define PPSMC_Result_OK ((uint16_t)0x01)
+#define PPSMC_Result_NoMore ((uint16_t)0x02)
+
+#define PPSMC_Result_NotNow ((uint16_t)0x03)
+
+#define PPSMC_Result_Failed ((uint16_t)0xFF)
+#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE)
+#define PPSMC_Result_UnknownVT ((uint16_t)0xFD)
+
+#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
+
+
+#define PPSMC_MSG_Halt ((uint16_t)0x10)
+#define PPSMC_MSG_Resume ((uint16_t)0x11)
+#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12)
+#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13)
+#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14)
+#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16)
+#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17)
+#define PPSMC_MSG_LevelUp ((uint16_t)0x18)
+#define PPSMC_MSG_LevelDown ((uint16_t)0x19)
+#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a)
+#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20)
+
+#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f)
+#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40)
+#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41)
+#define PPSMC_MSG_ForceHigh ((uint16_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43)
+
+#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52)
+#define PPSMC_MSG_EnableCac ((uint16_t)0x53)
+#define PPSMC_MSG_DisableCac ((uint16_t)0x54)
+#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55)
+#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56)
+#define PPSMC_CACHistoryStart ((uint16_t)0x57)
+#define PPSMC_CACHistoryStop ((uint16_t)0x58)
+#define PPSMC_TDPClampingActive ((uint16_t)0x59)
+#define PPSMC_TDPClampingInactive ((uint16_t)0x5A)
+#define PPSMC_StartFanControl ((uint16_t)0x5B)
+#define PPSMC_StopFanControl ((uint16_t)0x5C)
+#define PPSMC_NoDisplay ((uint16_t)0x5D)
+#define PPSMC_HasDisplay ((uint16_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60)
+#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61)
+#define PPSMC_MSG_EnableULV ((uint16_t)0x62)
+#define PPSMC_MSG_DisableULV ((uint16_t)0x63)
+#define PPSMC_MSG_EnterULV ((uint16_t)0x64)
+#define PPSMC_MSG_ExitULV ((uint16_t)0x65)
+#define PPSMC_PowerShiftActive ((uint16_t)0x6A)
+#define PPSMC_PowerShiftInactive ((uint16_t)0x6B)
+#define PPSMC_OCPActive ((uint16_t)0x6C)
+#define PPSMC_OCPInactive ((uint16_t)0x6D)
+#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F)
+#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70)
+#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71)
+#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72)
+#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73)
+#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74)
+#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75)
+#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76)
+#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77)
+#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78)
+#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79)
+#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A)
+#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B)
+#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C)
+#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
+
+#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E)
+#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F)
+#define PPSMC_FlushDataCache ((uint16_t)0x80)
+#define PPSMC_FlushInstrCache ((uint16_t)0x81)
+
+#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82)
+#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83)
+
+#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84)
+
+#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85)
+#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86)
+#define PPSMC_MSG_EnableDTE ((uint16_t)0x87)
+#define PPSMC_MSG_DisableDTE ((uint16_t)0x88)
+
+#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89)
+
+#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
+
+/* Trinity Specific Messages*/
+#define PPSMC_MSG_Test ((uint16_t) 0x100)
+#define PPSMC_MSG_DPM_Voltage_Pwrmgt ((uint16_t) 0x101)
+#define PPSMC_MSG_DPM_Config ((uint16_t) 0x102)
+#define PPSMC_MSG_PM_Controller_Start ((uint16_t) 0x103)
+#define PPSMC_MSG_DPM_ForceState ((uint16_t) 0x104)
+#define PPSMC_MSG_PG_PowerDownSIMD ((uint16_t) 0x105)
+#define PPSMC_MSG_PG_PowerUpSIMD ((uint16_t) 0x106)
+#define PPSMC_MSG_PM_Controller_Stop ((uint16_t) 0x107)
+#define PPSMC_MSG_PG_SIMD_Config ((uint16_t) 0x108)
+#define PPSMC_MSG_Voltage_Cntl_Enable ((uint16_t) 0x109)
+#define PPSMC_MSG_Thermal_Cntl_Enable ((uint16_t) 0x10a)
+#define PPSMC_MSG_Reset_Service ((uint16_t) 0x10b)
+#define PPSMC_MSG_VCEPowerOFF ((uint16_t) 0x10e)
+#define PPSMC_MSG_VCEPowerON ((uint16_t) 0x10f)
+#define PPSMC_MSG_DPM_Disable_VCE_HS ((uint16_t) 0x110)
+#define PPSMC_MSG_DPM_Enable_VCE_HS ((uint16_t) 0x111)
+#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint16_t) 0x112)
+#define PPSMC_MSG_DCEPowerOFF ((uint16_t) 0x113)
+#define PPSMC_MSG_DCEPowerON ((uint16_t) 0x114)
+#define PPSMC_MSG_PCIE_DDIPowerDown ((uint16_t) 0x117)
+#define PPSMC_MSG_PCIE_DDIPowerUp ((uint16_t) 0x118)
+#define PPSMC_MSG_PCIE_CascadePLLPowerDown ((uint16_t) 0x119)
+#define PPSMC_MSG_PCIE_CascadePLLPowerUp ((uint16_t) 0x11a)
+#define PPSMC_MSG_SYSPLLPowerOff ((uint16_t) 0x11b)
+#define PPSMC_MSG_SYSPLLPowerOn ((uint16_t) 0x11c)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint16_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint16_t) 0x11e)
+#define PPSMC_MSG_DISPLAYPHYStatusNotify ((uint16_t) 0x11f)
+#define PPSMC_MSG_EnableBAPM ((uint16_t) 0x120)
+#define PPSMC_MSG_DisableBAPM ((uint16_t) 0x121)
+#define PPSMC_MSG_Spmi_Enable ((uint16_t) 0x122)
+#define PPSMC_MSG_Spmi_Timer ((uint16_t) 0x123)
+#define PPSMC_MSG_LCLK_DPM_Config ((uint16_t) 0x124)
+#define PPSMC_MSG_VddNB_Request ((uint16_t) 0x125)
+#define PPSMC_MSG_PCIE_DDIPhyPowerDown ((uint32_t) 0x126)
+#define PPSMC_MSG_PCIE_DDIPhyPowerUp ((uint32_t) 0x127)
+#define PPSMC_MSG_MCLKDPM_Config ((uint16_t) 0x128)
+
+#define PPSMC_MSG_UVDDPM_Config ((uint16_t) 0x129)
+#define PPSMC_MSG_VCEDPM_Config ((uint16_t) 0x12A)
+#define PPSMC_MSG_ACPDPM_Config ((uint16_t) 0x12B)
+#define PPSMC_MSG_SAMUDPM_Config ((uint16_t) 0x12C)
+#define PPSMC_MSG_UVDDPM_SetEnabledMask ((uint16_t) 0x12D)
+#define PPSMC_MSG_VCEDPM_SetEnabledMask ((uint16_t) 0x12E)
+#define PPSMC_MSG_ACPDPM_SetEnabledMask ((uint16_t) 0x12F)
+#define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130)
+#define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131)
+#define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132)
+#define PPSMC_MSG_Thermal_Cntl_Disable ((uint16_t) 0x133)
+#define PPSMC_MSG_SetTDPLimit ((uint16_t) 0x134)
+#define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135)
+#define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136)
+#define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0x137)
+#define PPSMC_MSG_ACPPowerON ((uint16_t) 0x138)
+#define PPSMC_MSG_SAMPowerOFF ((uint16_t) 0x139)
+#define PPSMC_MSG_SAMPowerON ((uint16_t) 0x13a)
+#define PPSMC_MSG_SDMAPowerOFF ((uint16_t) 0x13b)
+#define PPSMC_MSG_SDMAPowerON ((uint16_t) 0x13c)
+#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d)
+#define PPSMC_MSG_IOMMUPowerOFF ((uint16_t) 0x13e)
+#define PPSMC_MSG_IOMMUPowerON ((uint16_t) 0x13f)
+#define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141)
+#define PPSMC_MSG_NBDPM_ForceNominal ((uint16_t) 0x142)
+#define PPSMC_MSG_NBDPM_ForcePerformance ((uint16_t) 0x143)
+#define PPSMC_MSG_NBDPM_UnForce ((uint16_t) 0x144)
+#define PPSMC_MSG_SCLKDPM_SetEnabledMask ((uint16_t) 0x145)
+#define PPSMC_MSG_MCLKDPM_SetEnabledMask ((uint16_t) 0x146)
+#define PPSMC_MSG_PCIeDPM_ForceLevel ((uint16_t) 0x147)
+#define PPSMC_MSG_PCIeDPM_UnForceLevel ((uint16_t) 0x148)
+#define PPSMC_MSG_EnableACDCGPIOInterrupt ((uint16_t) 0x149)
+#define PPSMC_MSG_EnableVRHotGPIOInterrupt ((uint16_t) 0x14a)
+#define PPSMC_MSG_SwitchToAC ((uint16_t) 0x14b)
+
+#define PPSMC_MSG_XDMAPowerOFF ((uint16_t) 0x14c)
+#define PPSMC_MSG_XDMAPowerON ((uint16_t) 0x14d)
+
+#define PPSMC_MSG_DPM_Enable ((uint16_t) 0x14e)
+#define PPSMC_MSG_DPM_Disable ((uint16_t) 0x14f)
+#define PPSMC_MSG_MCLKDPM_Enable ((uint16_t) 0x150)
+#define PPSMC_MSG_MCLKDPM_Disable ((uint16_t) 0x151)
+#define PPSMC_MSG_LCLKDPM_Enable ((uint16_t) 0x152)
+#define PPSMC_MSG_LCLKDPM_Disable ((uint16_t) 0x153)
+#define PPSMC_MSG_UVDDPM_Enable ((uint16_t) 0x154)
+#define PPSMC_MSG_UVDDPM_Disable ((uint16_t) 0x155)
+#define PPSMC_MSG_SAMUDPM_Enable ((uint16_t) 0x156)
+#define PPSMC_MSG_SAMUDPM_Disable ((uint16_t) 0x157)
+#define PPSMC_MSG_ACPDPM_Enable ((uint16_t) 0x158)
+#define PPSMC_MSG_ACPDPM_Disable ((uint16_t) 0x159)
+#define PPSMC_MSG_VCEDPM_Enable ((uint16_t) 0x15a)
+#define PPSMC_MSG_VCEDPM_Disable ((uint16_t) 0x15b)
+#define PPSMC_MSG_LCLKDPM_SetEnabledMask ((uint16_t) 0x15c)
+#define PPSMC_MSG_DPM_FPS_Mode ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode ((uint16_t) 0x15e)
+#define PPSMC_MSG_VddC_Request ((uint16_t) 0x15f)
+#define PPSMC_MSG_MCLKDPM_GetEnabledMask ((uint16_t) 0x160)
+#define PPSMC_MSG_LCLKDPM_GetEnabledMask ((uint16_t) 0x161)
+#define PPSMC_MSG_SCLKDPM_GetEnabledMask ((uint16_t) 0x162)
+#define PPSMC_MSG_UVDDPM_GetEnabledMask ((uint16_t) 0x163)
+#define PPSMC_MSG_SAMUDPM_GetEnabledMask ((uint16_t) 0x164)
+#define PPSMC_MSG_ACPDPM_GetEnabledMask ((uint16_t) 0x165)
+#define PPSMC_MSG_VCEDPM_GetEnabledMask ((uint16_t) 0x166)
+#define PPSMC_MSG_PCIeDPM_SetEnabledMask ((uint16_t) 0x167)
+#define PPSMC_MSG_PCIeDPM_GetEnabledMask ((uint16_t) 0x168)
+#define PPSMC_MSG_TDCLimitEnable ((uint16_t) 0x169)
+#define PPSMC_MSG_TDCLimitDisable ((uint16_t) 0x16a)
+#define PPSMC_MSG_DPM_AutoRotate_Mode ((uint16_t) 0x16b)
+#define PPSMC_MSG_DISPCLK_FROM_FCH ((uint16_t) 0x16c)
+#define PPSMC_MSG_DISPCLK_FROM_DFS ((uint16_t) 0x16d)
+#define PPSMC_MSG_DPREFCLK_FROM_FCH ((uint16_t) 0x16e)
+#define PPSMC_MSG_DPREFCLK_FROM_DFS ((uint16_t) 0x16f)
+#define PPSMC_MSG_PmStatusLogStart ((uint16_t) 0x170)
+#define PPSMC_MSG_PmStatusLogSample ((uint16_t) 0x171)
+#define PPSMC_MSG_SCLK_AutoDPM_ON ((uint16_t) 0x172)
+#define PPSMC_MSG_MCLK_AutoDPM_ON ((uint16_t) 0x173)
+#define PPSMC_MSG_LCLK_AutoDPM_ON ((uint16_t) 0x174)
+#define PPSMC_MSG_UVD_AutoDPM_ON ((uint16_t) 0x175)
+#define PPSMC_MSG_SAMU_AutoDPM_ON ((uint16_t) 0x176)
+#define PPSMC_MSG_ACP_AutoDPM_ON ((uint16_t) 0x177)
+#define PPSMC_MSG_VCE_AutoDPM_ON ((uint16_t) 0x178)
+#define PPSMC_MSG_PCIe_AutoDPM_ON ((uint16_t) 0x179)
+#define PPSMC_MSG_MASTER_AutoDPM_ON ((uint16_t) 0x17a)
+#define PPSMC_MSG_MASTER_AutoDPM_OFF ((uint16_t) 0x17b)
+#define PPSMC_MSG_DYNAMICDISPPHYPOWER ((uint16_t) 0x17c)
+#define PPSMC_MSG_CAC_COLLECTION_ON ((uint16_t) 0x17d)
+#define PPSMC_MSG_CAC_COLLECTION_OFF ((uint16_t) 0x17e)
+#define PPSMC_MSG_CAC_CORRELATION_ON ((uint16_t) 0x17f)
+#define PPSMC_MSG_CAC_CORRELATION_OFF ((uint16_t) 0x180)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON ((uint16_t) 0x181)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF ((uint16_t) 0x182)
+#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT ((uint16_t) 0x184)
+#define PPSMC_MSG_PkgPwrLimitEnable ((uint16_t) 0x185)
+#define PPSMC_MSG_PkgPwrLimitDisable ((uint16_t) 0x186)
+#define PPSMC_MSG_PkgPwrSetLimit ((uint16_t) 0x187)
+#define PPSMC_MSG_OverDriveSetTargetTdp ((uint16_t) 0x188)
+#define PPSMC_MSG_SCLKDPM_FreezeLevel ((uint16_t) 0x189)
+#define PPSMC_MSG_SCLKDPM_UnfreezeLevel ((uint16_t) 0x18A)
+#define PPSMC_MSG_MCLKDPM_FreezeLevel ((uint16_t) 0x18B)
+#define PPSMC_MSG_MCLKDPM_UnfreezeLevel ((uint16_t) 0x18C)
+#define PPSMC_MSG_START_DRAM_LOGGING ((uint16_t) 0x18D)
+#define PPSMC_MSG_STOP_DRAM_LOGGING ((uint16_t) 0x18E)
+#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F)
+#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190)
+#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191)
+#define PPSMC_MSG_DisableACDCGPIOInterrupt ((uint16_t) 0x192)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddc ((uint16_t) 0x193)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddci ((uint16_t) 0x194)
+#define PPSMC_MSG_SetVidOffset_1 ((uint16_t) 0x195)
+#define PPSMC_MSG_SetVidOffset_2 ((uint16_t) 0x207)
+#define PPSMC_MSG_GetVidOffset_1 ((uint16_t) 0x196)
+#define PPSMC_MSG_GetVidOffset_2 ((uint16_t) 0x208)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable ((uint16_t) 0x197)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable ((uint16_t) 0x198)
+#define PPSMC_MSG_SetTjMax ((uint16_t) 0x199)
+#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A)
+#define PPSMC_MSG_WaitForMclkSwitchFinish ((uint16_t) 0x19B)
+#define PPSMC_MSG_ENABLE_THERMAL_DPM ((uint16_t) 0x19C)
+#define PPSMC_MSG_DISABLE_THERMAL_DPM ((uint16_t) 0x19D)
+
+#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200)
+#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201)
+#define PPSMC_MSG_API_GetSclkBusy ((uint16_t) 0x202)
+#define PPSMC_MSG_API_GetMclkBusy ((uint16_t) 0x203)
+#define PPSMC_MSG_API_GetAsicPower ((uint16_t) 0x204)
+#define PPSMC_MSG_SetFanRpmMax ((uint16_t) 0x205)
+#define PPSMC_MSG_SetFanSclkTarget ((uint16_t) 0x206)
+#define PPSMC_MSG_SetFanMinPwm ((uint16_t) 0x209)
+#define PPSMC_MSG_SetFanTemperatureTarget ((uint16_t) 0x20A)
+
+#define PPSMC_MSG_BACO_StartMonitor ((uint16_t) 0x240)
+#define PPSMC_MSG_BACO_Cancel ((uint16_t) 0x241)
+#define PPSMC_MSG_EnableVddGfx ((uint16_t) 0x242)
+#define PPSMC_MSG_DisableVddGfx ((uint16_t) 0x243)
+#define PPSMC_MSG_UcodeAddressLow ((uint16_t) 0x244)
+#define PPSMC_MSG_UcodeAddressHigh ((uint16_t) 0x245)
+#define PPSMC_MSG_UcodeLoadStatus ((uint16_t) 0x246)
+
+#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t) 0x250)
+#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t) 0x251)
+#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t) 0x252)
+#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t) 0x253)
+#define PPSMC_MSG_LoadUcodes ((uint16_t) 0x254)
+#define PPSMC_MSG_PowerStateNotify ((uint16_t) 0x255)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI ((uint16_t) 0x256)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO ((uint16_t) 0x257)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI ((uint16_t) 0x258)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO ((uint16_t) 0x259)
+#define PPSMC_MSG_LoadVBios ((uint16_t) 0x25A)
+#define PPSMC_MSG_GetUcodeVersion ((uint16_t) 0x25B)
+#define DMCUSMC_MSG_PSREntry ((uint16_t) 0x25C)
+#define DMCUSMC_MSG_PSRExit ((uint16_t) 0x25D)
+#define PPSMC_MSG_EnableClockGatingFeature ((uint16_t) 0x260)
+#define PPSMC_MSG_DisableClockGatingFeature ((uint16_t) 0x261)
+#define PPSMC_MSG_IsDeviceRunning ((uint16_t) 0x262)
+#define PPSMC_MSG_LoadMetaData ((uint16_t) 0x263)
+#define PPSMC_MSG_TMON_AutoCaliberate_Enable ((uint16_t) 0x264)
+#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265)
+#define PPSMC_MSG_GetTelemetry1Slope ((uint16_t) 0x266)
+#define PPSMC_MSG_GetTelemetry1Offset ((uint16_t) 0x267)
+#define PPSMC_MSG_GetTelemetry2Slope ((uint16_t) 0x268)
+#define PPSMC_MSG_GetTelemetry2Offset ((uint16_t) 0x269)
+#define PPSMC_MSG_EnableAvfs ((uint16_t) 0x26A)
+#define PPSMC_MSG_DisableAvfs ((uint16_t) 0x26B)
+#define PPSMC_MSG_PerformBtc ((uint16_t) 0x26C)
+#define PPSMC_MSG_GetHbmCode ((uint16_t) 0x26D)
+#define PPSMC_MSG_GetVrVddcTemperature ((uint16_t) 0x26E)
+#define PPSMC_MSG_GetVrMvddTemperature ((uint16_t) 0x26F)
+#define PPSMC_MSG_GetLiquidTemperature ((uint16_t) 0x270)
+#define PPSMC_MSG_GetPlxTemperature ((uint16_t) 0x271)
+#define PPSMC_MSG_RequestI2CControl ((uint16_t) 0x272)
+#define PPSMC_MSG_ReleaseI2CControl ((uint16_t) 0x273)
+#define PPSMC_MSG_LedConfig ((uint16_t) 0x274)
+#define PPSMC_MSG_SetHbmFanCode ((uint16_t) 0x275)
+#define PPSMC_MSG_SetHbmThrottleCode ((uint16_t) 0x276)
+
+#define PPSMC_MSG_GetEnabledPsm ((uint16_t) 0x400)
+#define PPSMC_MSG_AgmStartPsm ((uint16_t) 0x401)
+#define PPSMC_MSG_AgmReadPsm ((uint16_t) 0x402)
+#define PPSMC_MSG_AgmResetPsm ((uint16_t) 0x403)
+#define PPSMC_MSG_ReadVftCell ((uint16_t) 0x404)
+
+/* AVFS Only - Remove Later */
+#define PPSMC_MSG_VftTableIsValid ((uint16_t) 0x666)
+
+/* If the SMC firmware has an event status soft register this is what the individual bits mean.*/
+#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
+#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
+#define PPSMC_EVENT_STATUS_DC 0x00000004
+
+typedef uint16_t PPSMC_Msg;
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/fiji_pwrvirus.h b/drivers/gpu/drm/amd/powerplay/inc/fiji_pwrvirus.h
new file mode 100644
index 000000000000..0262ad35502a
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/fiji_pwrvirus.h
@@ -0,0 +1,10299 @@
+/*
+ * Copyright 2015 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 _FIJI_PWRVIRUS_H_
+#define _FIJI_PWRVIRUS_H_
+
+#define mmCP_HYP_MEC1_UCODE_ADDR 0xf81a
+#define mmCP_HYP_MEC1_UCODE_DATA 0xf81b
+#define mmCP_HYP_MEC2_UCODE_ADDR 0xf81c
+#define mmCP_HYP_MEC2_UCODE_DATA 0xf81d
+
+enum PWR_Command
+{
+ PwrCmdNull = 0,
+ PwrCmdWrite,
+ PwrCmdEnd,
+ PwrCmdMax
+};
+typedef enum PWR_Command PWR_Command;
+
+struct PWR_Command_Table
+{
+ PWR_Command command;
+ ULONG data;
+ ULONG reg;
+};
+typedef struct PWR_Command_Table PWR_Command_Table;
+
+#define PWR_VIRUS_TABLE_SIZE 10243
+static PWR_Command_Table PwrVirusTable[PWR_VIRUS_TABLE_SIZE] =
+{
+ { PwrCmdWrite, 0x100100b6, mmPCIE_INDEX },
+ { PwrCmdWrite, 0x00000000, mmPCIE_DATA },
+ { PwrCmdWrite, 0x100100b6, mmPCIE_INDEX },
+ { PwrCmdWrite, 0x0300078c, mmPCIE_DATA },
+ { PwrCmdWrite, 0x00000000, mmBIF_CLK_CTRL },
+ { PwrCmdWrite, 0x00000001, mmBIF_CLK_CTRL },
+ { PwrCmdWrite, 0x00000000, mmBIF_CLK_CTRL },
+ { PwrCmdWrite, 0x00000003, mmBIF_FB_EN },
+ { PwrCmdWrite, 0x00000000, mmBIF_FB_EN },
+ { PwrCmdWrite, 0x00000001, mmBIF_DOORBELL_APER_EN },
+ { PwrCmdWrite, 0x00000000, mmBIF_DOORBELL_APER_EN },
+ { PwrCmdWrite, 0x014000c0, mmPCIE_INDEX },
+ { PwrCmdWrite, 0x00000000, mmPCIE_DATA },
+ { PwrCmdWrite, 0x014000c0, mmPCIE_INDEX },
+ { PwrCmdWrite, 0x22000000, mmPCIE_DATA },
+ { PwrCmdWrite, 0x014000c0, mmPCIE_INDEX },
+ { PwrCmdWrite, 0x00000000, mmPCIE_DATA },
+ /*
+ { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION },
+ { PwrCmdWrite, 0x00000000, mmMC_CITF_CNTL },
+ { PwrCmdWrite, 0x00000000, mmMC_VM_FB_LOCATION },
+ { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION },
+ { PwrCmdWrite, 0x00000000, mmMC_VM_FB_LOCATION },
+ { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION },
+ { PwrCmdWrite, 0x00000000, mmMC_VM_FB_OFFSET },*/
+ { PwrCmdWrite, 0x00000000, mmRLC_CSIB_ADDR_LO },
+ { PwrCmdWrite, 0x00000000, mmRLC_CSIB_ADDR_HI },
+ { PwrCmdWrite, 0x00000000, mmRLC_CSIB_LENGTH },
+ /*
+ { PwrCmdWrite, 0x00000000, mmMC_VM_MX_L1_TLB_CNTL },
+ { PwrCmdWrite, 0x00000001, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR },
+ { PwrCmdWrite, 0x00000000, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR },
+ { PwrCmdWrite, 0x00000000, mmMC_VM_FB_LOCATION },
+ { PwrCmdWrite, 0x009f0090, mmMC_VM_FB_LOCATION },*/
+ { PwrCmdWrite, 0x00000000, mmVM_CONTEXT0_CNTL },
+ { PwrCmdWrite, 0x00000000, mmVM_CONTEXT1_CNTL },
+ /*
+ { PwrCmdWrite, 0x00000000, mmMC_VM_AGP_BASE },
+ { PwrCmdWrite, 0x00000002, mmMC_VM_AGP_BOT },
+ { PwrCmdWrite, 0x00000000, mmMC_VM_AGP_TOP },*/
+ { PwrCmdWrite, 0x04000000, mmATC_VM_APERTURE0_LOW_ADDR },
+ { PwrCmdWrite, 0x0400ff20, mmATC_VM_APERTURE0_HIGH_ADDR },
+ { PwrCmdWrite, 0x00000002, mmATC_VM_APERTURE0_CNTL },
+ { PwrCmdWrite, 0x0000ffff, mmATC_VM_APERTURE0_CNTL2 },
+ { PwrCmdWrite, 0x00000001, mmATC_VM_APERTURE1_LOW_ADDR },
+ { PwrCmdWrite, 0x00000000, mmATC_VM_APERTURE1_HIGH_ADDR },
+ { PwrCmdWrite, 0x00000000, mmATC_VM_APERTURE1_CNTL },
+ { PwrCmdWrite, 0x00000000, mmATC_VM_APERTURE1_CNTL2 },
+ //{ PwrCmdWrite, 0x00000000, mmMC_ARB_RAMCFG },
+ { PwrCmdWrite, 0x12011003, mmGB_ADDR_CONFIG },
+ { PwrCmdWrite, 0x00800010, mmGB_TILE_MODE0 },
+ { PwrCmdWrite, 0x00800810, mmGB_TILE_MODE1 },
+ { PwrCmdWrite, 0x00801010, mmGB_TILE_MODE2 },
+ { PwrCmdWrite, 0x00801810, mmGB_TILE_MODE3 },
+ { PwrCmdWrite, 0x00802810, mmGB_TILE_MODE4 },
+ { PwrCmdWrite, 0x00802808, mmGB_TILE_MODE5 },
+ { PwrCmdWrite, 0x00802814, mmGB_TILE_MODE6 },
+ { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE7 },
+ { PwrCmdWrite, 0x00000004, mmGB_TILE_MODE8 },
+ { PwrCmdWrite, 0x02000008, mmGB_TILE_MODE9 },
+ { PwrCmdWrite, 0x02000010, mmGB_TILE_MODE10 },
+ { PwrCmdWrite, 0x06000014, mmGB_TILE_MODE11 },
+ { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE12 },
+ { PwrCmdWrite, 0x02400008, mmGB_TILE_MODE13 },
+ { PwrCmdWrite, 0x02400010, mmGB_TILE_MODE14 },
+ { PwrCmdWrite, 0x02400030, mmGB_TILE_MODE15 },
+ { PwrCmdWrite, 0x06400014, mmGB_TILE_MODE16 },
+ { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE17 },
+ { PwrCmdWrite, 0x0040000c, mmGB_TILE_MODE18 },
+ { PwrCmdWrite, 0x0100000c, mmGB_TILE_MODE19 },
+ { PwrCmdWrite, 0x0100001c, mmGB_TILE_MODE20 },
+ { PwrCmdWrite, 0x01000034, mmGB_TILE_MODE21 },
+ { PwrCmdWrite, 0x01000024, mmGB_TILE_MODE22 },
+ { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE23 },
+ { PwrCmdWrite, 0x0040001c, mmGB_TILE_MODE24 },
+ { PwrCmdWrite, 0x01000020, mmGB_TILE_MODE25 },
+ { PwrCmdWrite, 0x01000038, mmGB_TILE_MODE26 },
+ { PwrCmdWrite, 0x02c00008, mmGB_TILE_MODE27 },
+ { PwrCmdWrite, 0x02c00010, mmGB_TILE_MODE28 },
+ { PwrCmdWrite, 0x06c00014, mmGB_TILE_MODE29 },
+ { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE30 },
+ { PwrCmdWrite, 0x00000000, mmGB_TILE_MODE31 },
+ { PwrCmdWrite, 0x000000a8, mmGB_MACROTILE_MODE0 },
+ { PwrCmdWrite, 0x000000a4, mmGB_MACROTILE_MODE1 },
+ { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE2 },
+ { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE3 },
+ { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE4 },
+ { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE5 },
+ { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE6 },
+ { PwrCmdWrite, 0x00000000, mmGB_MACROTILE_MODE7 },
+ { PwrCmdWrite, 0x000000ee, mmGB_MACROTILE_MODE8 },
+ { PwrCmdWrite, 0x000000ea, mmGB_MACROTILE_MODE9 },
+ { PwrCmdWrite, 0x000000e9, mmGB_MACROTILE_MODE10 },
+ { PwrCmdWrite, 0x000000e5, mmGB_MACROTILE_MODE11 },
+ { PwrCmdWrite, 0x000000e4, mmGB_MACROTILE_MODE12 },
+ { PwrCmdWrite, 0x000000e0, mmGB_MACROTILE_MODE13 },
+ { PwrCmdWrite, 0x00000090, mmGB_MACROTILE_MODE14 },
+ { PwrCmdWrite, 0x00000000, mmGB_MACROTILE_MODE15 },
+ { PwrCmdWrite, 0x00900000, mmHDP_NONSURFACE_BASE },
+ { PwrCmdWrite, 0x00008000, mmHDP_NONSURFACE_INFO },
+ { PwrCmdWrite, 0x3fffffff, mmHDP_NONSURFACE_SIZE },
+ { PwrCmdWrite, 0x00000003, mmBIF_FB_EN },
+ //{ PwrCmdWrite, 0x00000000, mmMC_VM_FB_OFFSET },
+ { PwrCmdWrite, 0x00000000, mmSRBM_CNTL },
+ { PwrCmdWrite, 0x00020000, mmSRBM_CNTL },
+ { PwrCmdWrite, 0x80000000, mmATC_VMID0_PASID_MAPPING },
+ { PwrCmdWrite, 0x00000000, mmATC_VMID_PASID_MAPPING_UPDATE_STATUS },
+ { PwrCmdWrite, 0x00000000, mmRLC_CNTL },
+ { PwrCmdWrite, 0x00000000, mmRLC_CNTL },
+ { PwrCmdWrite, 0x00000000, mmRLC_CNTL },
+ { PwrCmdWrite, 0xe0000000, mmGRBM_GFX_INDEX },
+ { PwrCmdWrite, 0x00000000, mmCGTS_TCC_DISABLE },
+ { PwrCmdWrite, 0x00000000, mmTCP_ADDR_CONFIG },
+ { PwrCmdWrite, 0x000000ff, mmTCP_ADDR_CONFIG },
+ { PwrCmdWrite, 0x76543210, mmTCP_CHAN_STEER_LO },
+ { PwrCmdWrite, 0xfedcba98, mmTCP_CHAN_STEER_HI },
+ { PwrCmdWrite, 0x00000000, mmDB_DEBUG2 },
+ { PwrCmdWrite, 0x00000000, mmDB_DEBUG },
+ { PwrCmdWrite, 0x00002b16, mmCP_QUEUE_THRESHOLDS },
+ { PwrCmdWrite, 0x00006030, mmCP_MEQ_THRESHOLDS },
+ { PwrCmdWrite, 0x01000104, mmSPI_CONFIG_CNTL_1 },
+ { PwrCmdWrite, 0x98184020, mmPA_SC_FIFO_SIZE },
+ { PwrCmdWrite, 0x00000001, mmVGT_NUM_INSTANCES },
+ { PwrCmdWrite, 0x00000000, mmCP_PERFMON_CNTL },
+ { PwrCmdWrite, 0x01180000, mmSQ_CONFIG },
+ { PwrCmdWrite, 0x00000000, mmVGT_CACHE_INVALIDATION },
+ { PwrCmdWrite, 0x00000000, mmSQ_THREAD_TRACE_BASE },
+ { PwrCmdWrite, 0x0000df80, mmSQ_THREAD_TRACE_MASK },
+ { PwrCmdWrite, 0x02249249, mmSQ_THREAD_TRACE_MODE },
+ { PwrCmdWrite, 0x00000000, mmPA_SC_LINE_STIPPLE_STATE },
+ { PwrCmdWrite, 0x00000000, mmCB_PERFCOUNTER0_SELECT1 },
+ { PwrCmdWrite, 0x06000100, mmCGTT_VGT_CLK_CTRL },
+ { PwrCmdWrite, 0x00000007, mmPA_CL_ENHANCE },
+ { PwrCmdWrite, 0x00000001, mmPA_SC_ENHANCE },
+ { PwrCmdWrite, 0x00ffffff, mmPA_SC_FORCE_EOV_MAX_CNTS },
+ { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000010, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000020, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000030, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000040, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000050, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000060, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000070, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000080, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000090, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x000000a0, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x000000b0, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x000000c0, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x000000d0, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x000000e0, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x000000f0, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmRLC_PG_CNTL },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS2 },
+ { PwrCmdWrite, 0x15000000, mmCP_ME_CNTL },
+ { PwrCmdWrite, 0x50000000, mmCP_MEC_CNTL },
+ { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x0000000e, mmSH_MEM_APE1_BASE },
+ { PwrCmdWrite, 0x0000020d, mmSH_MEM_APE1_LIMIT },
+ { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000320, mmSH_MEM_CONFIG },
+ { PwrCmdWrite, 0x00000000, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_RB_VMID },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmRLC_CNTL },
+ { PwrCmdWrite, 0x00000000, mmRLC_CNTL },
+ { PwrCmdWrite, 0x00000000, mmRLC_SRM_CNTL },
+ { PwrCmdWrite, 0x00000002, mmRLC_SRM_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_ME_CNTL },
+ { PwrCmdWrite, 0x15000000, mmCP_ME_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_MEC_CNTL },
+ { PwrCmdWrite, 0x50000000, mmCP_MEC_CNTL },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x0840800a, mmCP_RB0_CNTL },
+ { PwrCmdWrite, 0xf30fff0f, mmTCC_CTRL },
+ { PwrCmdWrite, 0x00000002, mmTCC_EXE_DISABLE },
+ { PwrCmdWrite, 0x000000ff, mmTCP_ADDR_CONFIG },
+ { PwrCmdWrite, 0x540ff000, mmCP_CPC_IC_BASE_LO },
+ { PwrCmdWrite, 0x000000b4, mmCP_CPC_IC_BASE_HI },
+ { PwrCmdWrite, 0x00010000, mmCP_HYP_MEC1_UCODE_ADDR },
+ { PwrCmdWrite, 0x00041b75, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000710e8, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000910dd, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000a1081, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000b016f, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000c0e3c, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000d10ec, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000e0188, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00101b5d, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00150a6c, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00170c5e, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x001d0c8c, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x001e0cfe, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00221408, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00370d7b, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00390dcb, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x003c142f, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x003f0b27, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00400e63, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00500f62, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00460fa7, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00490fa7, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x005811d4, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00680ad6, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00760b00, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00780b0c, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00790af7, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x007d1aba, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x007e1abe, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00591260, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x005a12fb, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00861ac7, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x008c1b01, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x008d1b34, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00a014b9, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00a1152e, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00a216fb, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00a41890, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00a31906, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00a50b14, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00621387, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x005c0b27, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00160a75, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC1_UCODE_DATA },
+ { PwrCmdWrite, 0x00010000, mmCP_HYP_MEC2_UCODE_ADDR },
+ { PwrCmdWrite, 0x00041b75, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000710e8, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000910dd, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000a1081, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000b016f, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000c0e3c, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000d10ec, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000e0188, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00101b5d, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00150a6c, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00170c5e, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x001d0c8c, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x001e0cfe, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00221408, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00370d7b, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00390dcb, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x003c142f, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x003f0b27, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00400e63, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00500f62, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00460fa7, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00490fa7, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x005811d4, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00680ad6, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00760b00, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00780b0c, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00790af7, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x007d1aba, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x007e1abe, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00591260, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x005a12fb, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00861ac7, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x008c1b01, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x008d1b34, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00a014b9, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00a1152e, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00a216fb, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00a41890, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00a31906, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00a50b14, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00621387, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x005c0b27, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x00160a75, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x000f016a, mmCP_HYP_MEC2_UCODE_DATA },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI },
+ { PwrCmdWrite, 0x540fe800, mmCP_DFY_ADDR_LO },
+ { PwrCmdWrite, 0x7e000200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e020201, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e040204, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e060205, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a080500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a0a0303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54106f00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000400b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00004000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00804fac, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI },
+ { PwrCmdWrite, 0x540fef00, mmCP_DFY_ADDR_LO },
+ { PwrCmdWrite, 0xc0031502, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00001e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI },
+ { PwrCmdWrite, 0x540ff000, mmCP_DFY_ADDR_LO },
+ { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000145, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdcc10000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd010000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd410000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080061, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24ccffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3cd08000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1cd0ffcf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d018001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x050c0019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x84c00000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000067, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000006a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000006d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000008f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000099, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800000a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800000af, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x388c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08880002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98800003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000002d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28080001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d808001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc0700, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d10ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d10c017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d0d000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd0130b7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14cc0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000005d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14d00011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c01b10, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00e0080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00e0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x280c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00052, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28180039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x280c0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00052, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28180039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400053, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x280c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00052, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28180039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000069, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28080001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca88004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc00006f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28180080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d10c017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd0130b7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000013b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd4c0380, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdcc0388, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55dc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdcc038c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce0c0390, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce0c0394, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce4c0398, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce4c039c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce8c03a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56a80020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce8c03a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcecc03a8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcecc03ac, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf0c03b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57300020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf0c03b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4c03b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57740020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4c03bc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8c03c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57b80020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8c03c4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfcc03c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57fc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfcc03cc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05dc002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc12009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d200a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc012009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25e01c00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25e40300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25e800c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25ec003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e25c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de5c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xddc10000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02ee000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31100006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc1c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4df0388, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d7038c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d5dc01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4e30390, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d70394, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d62001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4e70398, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d7039c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d66401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4eb03a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d703a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d6a801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ef03a8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d703ac, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d6ec01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4f303b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d703b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d73001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4f703b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d703bc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d77401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4fb03c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d703c4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d7b801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ff03c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d703cc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d7fc01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4d70380, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1c88001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc0e0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc01e3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3cd00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0085, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc006a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc01e3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3cd00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1c88001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc080000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400051, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04180018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aac0027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce813265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80002f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04080002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08880001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080228, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000367, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9880fff3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04080010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08880001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80c0309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80c0319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9880fffc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00e0100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d4001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x155c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e80180, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x202c003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000bfc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000031, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900091a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05280196, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d4fe04, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800001b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000032b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000350, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000352, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000035f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000701, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000047c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000019f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d98001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00050, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0044, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9400036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40005b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40005d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840006d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11540015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19a4003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1998003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af0007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1264001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15dc000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d65400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a38003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd5c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7df1c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800045, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411326a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc415326b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425326e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293279, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000056, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800058, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00059, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259c8000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40005a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29988000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000073, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17300019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25140fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001b6d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4153279, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd00005f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000075, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26f00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15100010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d190004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af07fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4412e01, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0434001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4412e40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c031, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc031, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04343000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf413267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd1c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0160, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc810001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b4c0057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f4f400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55180020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2198003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x248dfffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc12e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af4007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33740003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26d80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ae8003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26680001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253348, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413348, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253348, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x958000d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000315, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04303000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26680001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800041, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1714000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25540800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x459801b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d77400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x199c01e2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e4002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e5c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e540002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc80c0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54d00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000282, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc80c0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54d00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8180011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000282, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000282, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc80c0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1334e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01334f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd413350, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813351, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd881334d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193273, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3275, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3271, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4153274, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50cc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cdcc011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05900008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd00006a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0006b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3272, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d594002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54d00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc12e23, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd012e24, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc12e25, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15540002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b340057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b280213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980198, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55e40020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x20cc003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc13249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113274, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc01e0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2d540002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x078c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07d40000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001239, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04f80000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x057c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd5c005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840007c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400069, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c018a6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4412e22, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800007c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c018a2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd4c005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680fffc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800002e3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800002e3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000069, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013273, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013275, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9540188f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc013cfff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc13249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x38d00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdcc30000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c01882, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000304, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x49980198, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55e40020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x459801a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04302000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000329, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc812e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04302000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16ec001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1998003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00031, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce00000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a18003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d43c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4093249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1888003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419324c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1598001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14d80011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24dc00ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31e00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31dc0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580fff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95801827, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14dc0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800006d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51dc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32200002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a0000ad, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04080000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af4003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740004d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca88005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24880001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f4b4009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313274, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d33400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28240100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a4004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1eecffdd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013273, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013275, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800003c3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aa80030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28240001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a8004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3272, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19e80042, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e8e800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de9c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3271, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50cc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ce8c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd30011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11e80007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce80001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd300001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b30003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240059, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1660001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e320009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0328000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e72400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0430000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02ac000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d310002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa87600, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280222, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4280058, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x22ec003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013273, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce813275, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8380018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57b00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04343108, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13740008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2374007e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32a80003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ec0057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e40213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc0199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cecc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ce4c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800003e7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980104, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x49980104, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800003f2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000448, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813279, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf41326e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x254c0700, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a641fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0726, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a640200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1237b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2264003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8813260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4280034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c01755, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce80000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde830000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce80000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0174c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4393265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bb80040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100044, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19180024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x551c003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000043d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c8000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840006c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28200000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000043f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x282000f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000053, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x195c00e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2555fff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0360001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32200002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5e124dc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aa80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef6c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e624001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80fff9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02ee000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2555fff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980158, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x49980158, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980170, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16200010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d43c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x195400e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1154000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc00e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e80488, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d0006c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18f807f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e40077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ec0199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6e400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000048e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000494, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800004de, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000685, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000686, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800006ac, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ccc001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1264000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d79400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e7a400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52a8001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d69401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x202c007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aec0028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800004cc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419324e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26e8003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aec003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12f4000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d324d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d75401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d290004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f8f4001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f52800f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50e00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800004d1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d0dc002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x6665fc00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da1c011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a644000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f534002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x6665fc00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e76401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800004d7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aec003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3257, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12f4000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d75401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52200002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da1c011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a644000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x202c003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e804e3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800004e7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800004f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000505, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x277401ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf41325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640fff4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17e00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84131db, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b301ff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26edf000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8413260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05a80507, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000050c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000528, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000057d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800005c2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800005f3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bd400e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c004d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d150005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00063b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2511fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000624, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1be00fe4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000066, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400068, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bd400e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c004d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d150005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400067, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00063b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2511fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000624, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bd400e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ed6c005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113271, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4153270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193272, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3273, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d51401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113274, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213275, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253276, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400061, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2730000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7db1800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00062, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000063, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400065, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce813260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc820001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b700057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b680213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46ec0188, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17e00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26e01000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c131fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x191807e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x192007ec, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x69dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de20014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x561c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013344, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13345, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425334d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419334e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d334f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213350, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253351, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b680057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46ec01b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce813260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800068, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2010007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1910003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd00001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd00001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2010003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x191807e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9540000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2511fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013344, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013345, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180050, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0052, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280042, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813273, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13275, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce813260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000068, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400067, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07d40000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00124f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x057c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b680057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc820001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46ec0190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4153249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2154003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bd800e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9c005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd80005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420004d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1e000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd413249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28340001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f598004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1be800e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce80005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801327a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800005f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000075, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424004c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41326e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28240100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a4004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x277401ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf41325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xda000068, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113277, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9540002d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425334d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419334e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d334f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213350, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253351, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b680057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b700213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b740199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46ec01b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1334a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1be000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0360001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc63124dc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aa80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef6c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80fff9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02ee000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fc14001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x194c1c03, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc0003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c002d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000697, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x194c00e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c004c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27301fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce00005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cf0c00d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b301ff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25100007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31100005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900008e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000075e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x202c007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a9feff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1374000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1774000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d30b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce813265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00ac006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00e0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28880700, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0006de, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14cc0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30d4000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41530b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19980028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800006c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15600008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8380023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fa38011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x282c2002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd3800025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x202400d0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28240006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d8003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x194c00e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c004c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27301fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce00005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cf0c00d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000712, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x194c1c03, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc0003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c002d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e80714, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000071c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000720, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000747, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000071d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800007c4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000732, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000745, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000744, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000072e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a64008c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b301fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000075e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0fff1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000723, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41f02f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000743, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8813247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0ffde, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000072e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0007e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15600008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84131db, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b301ff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8413260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc8000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x195800e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd80005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418004c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81326e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dd7fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51e00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1a001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46200200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04283247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af80057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af40213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6f400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2000025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc6990000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x329c325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x329c3269, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x329c3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc01defff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d8009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000078a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25980000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fff2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03e7ff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3f0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1f30001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03e4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001219, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d30b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bf0003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000b80, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x203c003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300700, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf0130b7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46200008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2000025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259c0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31dc0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ec0057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e40213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc0199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cecc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ce4c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000448, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31980002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19580066, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15600008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0120001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11980003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da18001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d24db, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9c005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580137b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00ee000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113269, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19080070, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x190c00e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2518000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05a80809, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000080e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000080f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000898, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000946, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800009e1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04a80811, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000815, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000834, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000085e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000085e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04341001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3045, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c091, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31300021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84002f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293059, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56a8001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000241, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000084a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02f0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4252087, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5668001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000084a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04341001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431ecaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02e0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31300021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84002f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293059, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56a8001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00021d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd410000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84802e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001a41, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43b02f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec80278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56f00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8813247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80802e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000085e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x950001fa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02e0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aec0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc01c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a40006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de6000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10e40008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e2e000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d10ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2110003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d10ff9e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0245301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801325f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0121fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29108eff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e524009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0127ff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e524009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0131fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e524009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801326e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013279, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000866, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000866, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0100010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd2400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0180003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd1c002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000866, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04a8089a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000089e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800008fa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000945, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000945, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31300022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d91801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x459801e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2738000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8300011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc79d3300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc7a13301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8393300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0260001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce793301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x964012a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c028009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800008d2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x242c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02620c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce81c080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01c082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0260400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6e400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae8001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2f0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800008d2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdf93300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce393301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000903, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31240022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ec30011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32f80000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x67180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bfc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd981325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000915, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c1325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0fff6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f818001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001606, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d838001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16240014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a2801f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e2a000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2264003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00075e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0228, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x66d80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1330000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13f40014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07fc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33e80010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680ffec, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04a80948, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000094c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000099b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800009e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800009e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d91801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x459801e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2738000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8300011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc79d3300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc7a13301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8393300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0260001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce793301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x964011fe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c028009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000978, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x242c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0260010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01c080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce81c082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0260800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6e400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae8001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2f0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000978, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdf93300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce393301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dda801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e838011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84802e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001802, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x469c0390, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4280011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0014df, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31280014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce8802ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800062, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31280034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04a809e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800009ec, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a45, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a59, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a59, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d91801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4a70250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53300020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e72401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b342010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x172c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b30c012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef7400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x66740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400041, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04383000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4393267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b38007e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33b40003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x4598001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740002f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4002eb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4002ec, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4002ed, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4002ee, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04382000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd84802e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001715, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04382000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffbc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04341001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431ecaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a55, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x233c0032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf0130b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49302ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8413247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5198001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193269, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2598000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80002f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53b8001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7db9801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000a5e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c01106, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e01, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e02, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e03, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c010fd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ce4c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc80c0072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x58e801fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce80001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc01e2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e4002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e5c0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e540002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8180011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9540000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8180011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x44cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55900020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x44cc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd812e01, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd012e02, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd412e03, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2264003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1e64001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14d00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ab1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a0010ac, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd880003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800010de, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc010ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d403f7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d0cc009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41b0367, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d958004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d85800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc1e0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d001fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05280adc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000af1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000adf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ae7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000ace, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd8d2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d803f7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc010ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d0cc009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11940014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29544001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29544003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000af4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd44d2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd44dc000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d0003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000ace, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd8d2c00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000b0a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd44d2c00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28148004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4593240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0105e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2198003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x199c0034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef3400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14e80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a8000af, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c01043, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18a01fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3620005c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2464003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc6290ce7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16ac001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ac003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ee6c00d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00fff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000367, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640102e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x199c0037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19a00035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0005d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16f8001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9780000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc035f0ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e764009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19b401f8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13740008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e76400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1000072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x199c0034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ae4003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000b7c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aec003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19a4003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12ec001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1374000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02e4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1774000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc01e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13fc0018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dbd800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d98ff15, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x592c00fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd80000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12e00016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da1800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x592c007e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12e00015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da1800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1264001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1620000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e32000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12e4001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5924007e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19a4003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013257, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd413258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00fdb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9780f5ca, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001219, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001b6d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d324e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431324d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07740003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x269c003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e4004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f67000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f674002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53740002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef6c011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ab42010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ab8c006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a8000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b740000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf40001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000bec, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000b47, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b34060b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec00ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a8004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef6c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3b000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc415325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18580037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x262001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d54001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14f00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd280200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd680208, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcda80210, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc6930200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc6970208, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc69b0210, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd900003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd940003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9400040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800010de, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14fc0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24f800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd88130b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d83c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4093249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1888003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000671, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419324c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1598001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14d80011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24e000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x321c0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580ffee, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c30, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9480000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800f29, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800f23, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800f1a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9600f502, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0f500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000f05, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1f30001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16e4001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640f4f4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33740002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40f4f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aec003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12ec001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1374000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02e4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1774000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12780001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bb80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00ac005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00e0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc8000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28884900, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ff3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17fc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400ee1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c40a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c40c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c40d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d0007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15580010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x255400ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c411, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c40f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c40e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c410, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e80033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ec0034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c414, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c415, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c413, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c412, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc0032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c030011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c038011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431c417, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435c416, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c419, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc418, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf413261, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013262, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13263, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813264, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc0030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17fc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d77000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000cd6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51b80020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53300020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f97801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3b000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000cd6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ca7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc0031, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435c40b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4280032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012c2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb81ff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f8cc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bf0060b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000cf4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0677, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13fc0017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb81fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc032800b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ffbc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d42011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17fc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd4c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800e6c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x596001fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ce0c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x505c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50600020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc0001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8240010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e800c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x122c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000d1f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8240010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x566c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413261, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13262, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b740008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x566c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce413261, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec13262, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012c2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb81fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f8cc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bf0060b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000d57, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0677, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13fc0017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb81fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0328009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ffbc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04143000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd413267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e51001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4153267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d2d0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19640057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19580213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19600199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da6400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1000025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04142000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd413267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4153267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d40030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d80034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05280d83, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c424001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000d8a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000d95, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000db1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000d95, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000dbc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11540010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e010001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00187c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d75400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4610000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580f3d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x526c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e80058, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e2ec01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc82c0072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5ae0073a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea2800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580f3c6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc3a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80fffb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980fff5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02a0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16200002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01c405, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd441c406, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580f3b1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c409, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11540010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4610000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580f3a5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00da7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50500020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8280072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5aac007e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12d80017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56a00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da1800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e82400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e58c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19d4003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28182002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00104f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc011000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c908009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d614011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca4800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cb0800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x20880188, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cb4800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x20240090, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28240004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd901a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1624001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841325f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00038, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ac0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ac0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b301ff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2330003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00038, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0001a2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24b00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ac0024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b304000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1910003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2220003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e2a000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00038, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d40030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18fc0034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24e8000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80e71, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000edd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e91, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e91, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ea1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000eaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e7c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e7f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e7f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e87, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000e8f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51dc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9e001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a200008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213262, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253261, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a200008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213264, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253263, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc820001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e82005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51e00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da1801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1800072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8180072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x59a001fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea2800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce80001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd180001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8200011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15980002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421c401, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400041, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425c401, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ee6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac2580, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac260c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac0828, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac2440, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac2390, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac0093, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac31dc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac31e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ede, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39ac7c06, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db07c00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39acc337, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db0c330, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39acc335, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db0c336, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39ac9002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db09001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39ac9012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db09011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39acec70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db0ec6f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ebc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5a10000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5a50000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05280eea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ef1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000efe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f11, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f2e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000efe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f1f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0f26f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e80058, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7daec01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc82c0072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5af8073a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eba800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0f25c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02a0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15980002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c405, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01c406, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56240020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c406, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0f24e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c409, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40f247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce190000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0f240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439c040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac2580, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac260c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac0828, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac2440, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac2390, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac0093, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac31dc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31ac31e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ef2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39ac7c06, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db07c00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39acc337, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db0c330, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39acc335, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db0c336, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39acec70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db0ec6f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39ac9002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db09002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39ac9012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3db09012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ef1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b740008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b780001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c1325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c034001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c038001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e0007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32240003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f88, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e52401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8280072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce81c080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56ac0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26f0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01c081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af000fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1334000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24e02000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f63400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e00074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32240003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1c083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000f9d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51e40020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5a401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8280072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce81c082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56ac0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26f0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01c083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1af000fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13380016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e00039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fa3800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e0007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1220001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fa3800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e00074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fa3800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81c078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1c084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d001e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31140005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31140006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00104f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05280fb7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28140002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000fbe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000fbe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000fc2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000fbe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000fd1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ff2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ff2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e80039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52a8003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d69401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140004b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d958004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d150005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x159c0011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31a00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31a40001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e25800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0fff5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580fff4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000fef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d100010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01326f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc011000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33b40003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0340008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000ffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c908009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d614011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca4800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cb0800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x282c2002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x208801a8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cb4800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x20240030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28340000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x507c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d7d401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x557c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28342002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000102f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1cccfe08, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00b33, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da2400f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da28002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1ac002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d2ac002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3ef40010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40f11d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde410000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdcc10000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd010000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd410000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdd810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xddc10000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde010000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c024001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100086, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5510003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001075, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15800f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15c002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d520002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cde0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e20001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001071, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c00036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00b01, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc200000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc1c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc180000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc0c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc240000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc40003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4080029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18a400e5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12500009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x248c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x200c006d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x200c0228, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410002b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18881fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d4072c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc00d1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd4c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3094000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x38d80000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x311c0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30940007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1620001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800010c4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00041, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x259c007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19a00030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800010cb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x199c0fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800010cb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000aac, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434002e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2020002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17780001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07a810d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000bfc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000104c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x200c007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28240007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xde430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24b00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d3249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b304000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x192400fd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06681110, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ac0024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19180070, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19100078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18f40058, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5978073a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001117, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001118, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001122, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000112d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001130, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001133, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000117b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24ec0f00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32ec0600, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000117b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24ec0f00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32ec0600, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000117b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc81c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001122, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc81c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55e00020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001122, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02a0200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e8e8009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x22a8003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x22a80074, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2774001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13740014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eb6800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25ecffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55700020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15f40010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13740002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x275c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15dc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39e00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc1c01e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e40008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc2001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e40008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e62000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da58001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001165, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc2001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1a0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e0d000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95000007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e02401e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06640008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05d80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc2401e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da58001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05e00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da2000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9600ffe6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00116b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce00001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce81c078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1c080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01c083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x22640435, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0528117e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x312c0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001185, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001182, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001182, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a0400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1198001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d81c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc130b7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19a000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de2c00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26200010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc415326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc420007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800011a3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d654001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c020001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800011b6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253279, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc415326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2730003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3b380006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3f38000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800011b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800011b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0430000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb10004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e57000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e578002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d67c002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0be40001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d3a4002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x202c002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26200010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e640010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce81325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434002e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17780001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07a811cf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00feb8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x954009a7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000bfc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1c07c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c07d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c08c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c07e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18f0012f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18f40612, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc00c1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cf7400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x39600004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0140004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11600001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18fc003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9740001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400041, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x166c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800011ee, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a6c003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800011e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ac007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ab00030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aac0fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001205, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x166c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11600001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ffbc00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a2800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81c07c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17fc001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03ae000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a0800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81c07c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17fc001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03ae000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81c200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a4000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81c07c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17fc001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30d00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000052, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640090f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1514001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19180038, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d324e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431324d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ab0c006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000127f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d3258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313257, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ab0c012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e624004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f67800f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53740002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef6c011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ab42010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a8000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b740000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f6b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf40001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1514001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0012e1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x964008d7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9800036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300677, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012aa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b34060b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f37000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec00ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a8002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef6c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7edec00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3b000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4140032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1858003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d0cc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d0006c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d407f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2598003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d190004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d5d4001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d52000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d514002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d958001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd5c002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc1325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1ccc001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14f00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd980003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9800040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd9c00040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800010de, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33f80003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800051, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc80003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24b00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18a800e5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1d980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7da9800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b74003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b304000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431326c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b4c00f8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50700020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04e81324, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18ac0024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50600020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30e40004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d71401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x596401fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b74008d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e76400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a640000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000132c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000133b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001344, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42530b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a68003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2024003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25980700, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11980014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d19000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd0130b7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce4130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de6800f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce40001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc428000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8240011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de6800f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffe0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00104f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28182002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340035, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140023, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d614011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4100026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05980008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca4800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d1a0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cb0800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3e280008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cb4800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x20240030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ca48001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b4c00f8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28340000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x507c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30e40004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d7d401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x557c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28342002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c018001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf81a2a4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c007eb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50500020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d0d001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1000072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8100072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x591c01fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45140210, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x595801fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11980009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1624001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400069, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a307fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x23304076, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc00e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0015, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x4514020c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a2001e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a204001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a64003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1264001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15dc000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dcdc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5dc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340022, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4412e01, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0434001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf430000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4412e40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c030, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41c031, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x248dfffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc12e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc812e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45140248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8200011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013257, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0434000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdb000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd140001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9980ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8200011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013259, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0337fff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f220009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55300020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d01c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c01d0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f01c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c01c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c000d61, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50500020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd0c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd0c00072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8240072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd240001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19682011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5a6c01fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12ec0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eeac00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aec0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4180011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf830000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfa0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4380007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d40038, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400029, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9540073d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18c80066, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30880001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00187c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd910000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x4220000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24e80007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24ec0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5310000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001465, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1000072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc82c0072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2c0001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18f02011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5aec01fc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12ec0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aec0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aa80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a8146a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1f0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1b400f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001478, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1b400e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001478, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1b400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1b400d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1b400f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f1b400e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000147a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f334002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000147b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e024001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000144a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb81ff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fbfc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x251001ef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94800007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00187c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42c0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd910000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40d325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800012c2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13f4000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bf0060b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800014a9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d325a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0677, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb81ff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0328007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb7800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13fc0017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ffbc00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03a0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45dc0390, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04183000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b380057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b340213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c424001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c428001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c42c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c430001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c434001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04182000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd813267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a0800fd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x109c000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce080228, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9880000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce480250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce880258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0ec75, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0fffb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc80230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce480250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce880258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52a80020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x66580001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0fffb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc80260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec80288, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf080290, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec80298, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf0802a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4802a8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27580001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0fffb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc802b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80802b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x178c000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b8003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cf8c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8802c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc802c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8802d0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf8802d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25b8ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd2800c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5230309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e3a400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001539, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd08034b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd880353, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b0353, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0228, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd14005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000154f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd080238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd08034b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2598ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3d200008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc80230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd900309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8100319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340801, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2198003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd910ce7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4190ce6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d918005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d918004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd810ce6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdd1054f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000156e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x090c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdcd050e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x040c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x110c0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc4001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41230a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41230b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41230c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc41230d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc480329, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc48032a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc4802e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f02e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d8003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09940001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x44100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x69100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000157f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4970290, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b0288, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b02a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49f0298, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x041c0040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dcdc002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d924019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d26400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001579, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d010021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d914019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd480298, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd8802a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10d40010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12180016, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc51f0309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d95800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d62000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdd00309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce113320, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f02e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b02b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18dc01e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9400e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c0001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800015aa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4a302b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12240004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e5e400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ab02a8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04100000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce4c0319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d9d8002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea14005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800015bc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04240001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e624004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d25000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2620000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0fff4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd0d3330, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce0802b8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd8802b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ab02e0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aa807f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f02d0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49702d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b02c8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49f02c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96800028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d4e000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9600000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d964002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d694001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800015e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cde4002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de94001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800015e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd64002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d694001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800015e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00163f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800015cd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930238, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d698002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd4802d8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x129c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc50f0319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11a0000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1e000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1198000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd953300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e0e000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a8000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce953301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce100319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b70280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73800a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x536c0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9780eb68, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001609, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30b40000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b400011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b70258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53780020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb3801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7faf8019, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x67b40001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x57b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4bb0260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fab8001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf880260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x66f40001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4353247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f7f4009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fff7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x269c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a00018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a00060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x269c0018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a40060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11dc0006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29dc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de5c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b70228, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc80230, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f514005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2510000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001644, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd080240, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f130005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001688, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00120d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001219, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001232, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340801, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f130004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01051e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42d051f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ed2c005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96c0fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01051f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000055, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5170309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x195c07f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x196007f6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04340001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x6b740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001665, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4a702a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ab0298, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f634014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e76401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56680020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8113320, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce480298, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce8802a0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc5170319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b702b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x255c000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f5f4001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8113330, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf4802b0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11340001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x195c07e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x196007ee, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8353300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1e4001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8353301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce4802d0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8100309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8100319, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc48f0250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd4c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x64d80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580005c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc24001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd2000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc435324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7df5c00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25980040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33380003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4393260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb000e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800016f1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3b0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a7003e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27380003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13b80004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a7000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07b80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a700064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800016df, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb30002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4392083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffca, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800016f2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940ff9c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd80802e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18fc0064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00042, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51980020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dd9801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x45980400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b380057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b340213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f7b400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f73400a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14f4001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x192807fa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4bf0258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4a70250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53fc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e7e401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x667c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0aec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eebc00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x43300007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7db30011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd3000025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc03ec005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfca200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x192807fa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc01f007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d1d0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2110007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x203c003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0017f5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18fc01e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00185b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8413247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40ffd5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0ea24, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14d4001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d52400e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49f0258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4a30250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51dc0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400017, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d534002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dae4005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32e0001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec80270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000174f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b740001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00178a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40fff3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001608, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ab0268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7daa4005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32a0001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001765, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc01f007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d1d0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2110007d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8013256, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c0017f2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd013254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4113248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b3034b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f13000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001855, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32a4001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8413247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800004f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd080260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce880268, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940ffc0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ec28001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32e0001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253255, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431324f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e72400c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9680fff7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aa4003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aa400e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32680003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a800046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4293260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1aa400e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800017e2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc027ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2e6400ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a4009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4240009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19e403e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26680003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12a80004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea68001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19e400e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea68001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea68001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19e40064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x32640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a40005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06640003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce412082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a640003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800017d0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16a40005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce412082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea64002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4292083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ea68005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a80ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc429325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26a400ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40ffca, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2024007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800017e3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4a70280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4ab0278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52640020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7eae8014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e6a401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56680020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce480278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce880280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x042c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec80270, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800017fe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800017fe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43b02eb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42302ec, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fa3801a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x47b8020c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x15e00008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1220000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2a206032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x513c001e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e3e001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4bf02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000180f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b3c0077, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1330000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd200000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4200007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd3800002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc30001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc1e0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04380032, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf80000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001427, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc413248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3269, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33fc0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdfc30000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4413249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bfc0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdfc30000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd441326a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x173c0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300303, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3f0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ff3c004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001842, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdfc30000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4413249, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c43c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x23fc003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1326d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bb80026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdf830000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd441326e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4393265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1fb8ffc6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xddc30000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf813265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001852, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c00142b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13252, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013253, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001878, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49f02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c00018, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c420001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13252, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013253, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c3000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c0012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001878, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41f02ed, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42302ee, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc13252, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013253, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e2a0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28340001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x313c0bcc, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x393c051f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3d3c050e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x393c0560, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3d3c054f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x393c1538, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3d3c1537, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b740800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e8007c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c42c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a8189a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800018c5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800018f2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c414001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d0007e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x50580020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d59401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc8140072, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09240002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c418001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4340004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc42130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a24002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2020002c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc418000d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1198001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14cc0004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7cd8c00a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc130b7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce0130b5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd1400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x5978073a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bb80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf800024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd800026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9600e8a8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9640e8a5, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800018a9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc55b0309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3d5c0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2598ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09780001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dad800c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0ffd2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580fff9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x442c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x65180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7df9c00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c13260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd901325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940fff1, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x66d80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x56ec0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26240007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940fff7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc023007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19e4003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7de1c009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dee000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96000007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c13260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd901325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc421325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x261c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940fff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000189e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28cc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43d3265, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bc800ea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18e00064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06281911, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14f4001d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24cc0003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x86800000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001915, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x800019af, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001a2b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8000016a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc48032b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc480333, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc48033b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc480343, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98800011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46640400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04203000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b3c0057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b200213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e3e000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e32000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04180000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f438001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00068, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213254, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a1c003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00065, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc01f007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1e0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97800062, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0bb80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x43bc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fcbc001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc7df032b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1fc00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0101, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c0102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33380003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4393260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb000e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001994, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3b0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f003e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27380003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13b80004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07b80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f00064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001982, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb30002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4392083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffcb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001995, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc1325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98800009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x41bc0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x53fc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e7fc011, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd3c00025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0012, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9bc0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x653c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dbd8001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940ff8f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2bfc0008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x043c2000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcfc13267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c410001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc55b0309, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x3d5c0010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2598ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x05540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d91800c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580fff8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09780001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x65180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9580005d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200101, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400058, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dc24001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41d3248, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25dc000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7df9c00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95c00053, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e41c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a70003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a7000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33240003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a400046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1a7000e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001a21, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f270009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x266400ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f003e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27240003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12640004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e724001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06640002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f00064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16700005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001a0f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x16700005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e730002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4252083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e724005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x26640001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a40ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x267000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffca, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001a22, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940ff9f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001a31, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8080280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213246, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4253245, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52200020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e26401a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x46640400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04203000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce013267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4213267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b180057, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b200213, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1b300199, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e1a000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e32000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce000024, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4970258, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4930250, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x51540020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4af0280, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4b30278, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x52ec0020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140020, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04280000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x65180001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800060, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x8c001628, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4193247, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x25980001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200101, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x30f00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95800056, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb0003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33380003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b800046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4393260, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bb000e4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001aa2, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc033ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2f3000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f3b0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf01325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b800ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4300009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9700fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f003e6, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27380003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13b80004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f000e8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07b80002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x19f00064, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33300002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0b300003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001a90, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x17b00005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf012082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01203f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x13300005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb30002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4392083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7fb38005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b80ffdf, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c00034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc00013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc431325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27300010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc439325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27b000ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b00ffca, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2030007b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf00325b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001aa3, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce01325d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04300001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7f2b0014, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ef2c01a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd2400025, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x4664001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000026, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400027, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x06a80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55100001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940ff9c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc49b02e9, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99800008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc430000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2b300008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf000013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04302000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcf013267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc4313267, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x244c00ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc4c0200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc44f0200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc410000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d158010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x059cc000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccdd0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0037, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000049, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c003a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500e69a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d0003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d40021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd840004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c003c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x14cc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c00028, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000033, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc438000b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0009, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x27fc0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43dc07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1bfc0078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7ffbc00c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x97c0fffd, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x99000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0120840, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x282c0040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001ae8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0121841, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x282c001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c07c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c08c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c079, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c07e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcec0001b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a200001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9a00ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x166c001f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04200004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9ac0fffb, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc434000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9b40ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc425c07f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8000034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940e66b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800004a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0036, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9900fffe, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18cc0021, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc00047, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc000046, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0039, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c003d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c40c001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24d003ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d47fea, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x18d87ff4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd00004c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd40004e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd80004d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c405, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc02a0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2aa80001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c406, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c406, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c406, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc414000e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x29540008, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x295c0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8c1325e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcdc0001a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11980002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x4110000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0160800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7d15000a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0164010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c080, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c081, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c082, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc01c083, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c084, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x98c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400048, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c003b, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x94c0ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000c16, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801c40a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd901c40d, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801c410, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801c40e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd801c40f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc40c0040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x09540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9940ffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04140096, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8400013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1c400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc411c401, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9500fffa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424003e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04d00001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x11100002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd01c40c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0180034, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd81c411, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd841c414, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0a540001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcd41c412, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x2468000f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc419c416, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x41980003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc41c003f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7dda0001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x12200002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x10cc0002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xccc1c40c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd901c411, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce41c412, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd8800013, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xce292e40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e01, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e02, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e03, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc412e00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000aa7, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc43c0007, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc120000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x31144000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x95400005, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xdc030000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd800002a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xcc3c000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b70, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x33f80003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd4400078, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x9780e601, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x188cfff0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x04e40002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001190, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400006, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x90000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc424005e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x96400003, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7c408001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x88000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80001b74, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000168, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110501, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120206, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130703, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92100400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92110105, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92120602, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x92130307, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI },
+ { PwrCmdWrite, 0x54106500, mmCP_DFY_ADDR_LO },
+ { PwrCmdWrite, 0x7e000200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e020204, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc00a0505, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xbf8c007f, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb8900904, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb8911a04, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb8920304, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb8930b44, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x921c0d0c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x921c1c13, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x921d0c12, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x811c1d1c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x811c111c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x921cff1c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000400, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x921dff10, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000100, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x81181d1c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e040218, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0701000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050102, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xe0501000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80050302, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI },
+ { PwrCmdWrite, 0x54106900, mmCP_DFY_ADDR_LO },
+ { PwrCmdWrite, 0x7e080200, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x7e100204, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xbefc00ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00010000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x24200087, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x262200ff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000001f0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x20222282, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x28182111, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000040c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd81a0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000080c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xd86c0000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x1100000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xbf810000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x80000004, mmCP_DFY_CNTL },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_ADDR_HI },
+ { PwrCmdWrite, 0x54116f00, mmCP_DFY_ADDR_LO },
+ { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4540fe8, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000041, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000000c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54116f00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb454105e, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000c0, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54117300, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4541065, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000500, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000001c, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54117700, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xc0310800, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000040, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4541069, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000444, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x0000008a, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x07808000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xffffffff, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000002, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xaaaaaaaa, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x55555555, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee40, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000010, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000001, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000004, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x54117b00, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00005301, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0xb4540fef, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x540fee20, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x000000b4, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x08000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_DFY_DATA_0 },
+ { PwrCmdWrite, 0x00000000, mmCP_MEC_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_MEC_CNTL },
+ { PwrCmdWrite, 0x00000004, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x54116f00, mmCP_MQD_BASE_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI },
+ { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI },
+ { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI },
+ { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE },
+ { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID },
+ { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL },
+ { PwrCmdWrite, 0x00000005, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x54117300, mmCP_MQD_BASE_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI },
+ { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI },
+ { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI },
+ { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE },
+ { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID },
+ { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL },
+ { PwrCmdWrite, 0x00000006, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x54117700, mmCP_MQD_BASE_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI },
+ { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI },
+ { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI },
+ { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE },
+ { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID },
+ { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL },
+ { PwrCmdWrite, 0x00000007, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x54117b00, mmCP_MQD_BASE_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_MQD_BASE_ADDR_HI },
+ { PwrCmdWrite, 0xb4540fef, mmCP_HQD_PQ_BASE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_BASE_HI },
+ { PwrCmdWrite, 0x540fee20, mmCP_HQD_PQ_WPTR_POLL_ADDR },
+ { PwrCmdWrite, 0x000000b4, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI },
+ { PwrCmdWrite, 0x00005301, mmCP_HQD_PERSISTENT_STATE },
+ { PwrCmdWrite, 0x00010000, mmCP_HQD_VMID },
+ { PwrCmdWrite, 0xc8318509, mmCP_HQD_PQ_CONTROL },
+ { PwrCmdWrite, 0x00000004, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000104, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000204, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000304, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000404, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000504, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000604, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000704, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000005, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000105, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000205, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000305, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000405, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000505, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000605, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000705, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000006, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000106, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000206, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000306, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000406, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000506, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000606, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000706, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000007, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000107, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000207, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000307, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000407, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000507, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000607, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000707, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000008, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000108, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000208, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000308, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000408, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000508, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000608, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000708, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000009, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000109, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000209, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000309, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000409, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000509, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000609, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000709, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_RPTR },
+ { PwrCmdWrite, 0x00000000, mmCP_HQD_PQ_WPTR },
+ { PwrCmdWrite, 0x00000001, mmCP_HQD_ACTIVE },
+ { PwrCmdWrite, 0x00000004, mmSRBM_GFX_CNTL },
+ { PwrCmdWrite, 0x01010101, mmCP_PQ_WPTR_POLL_CNTL1 },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdWrite, 0x00000000, mmGRBM_STATUS },
+ { PwrCmdEnd, 0x00000000, 0x00000000 },
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
new file mode 100644
index 000000000000..91795efe1336
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2015 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 _HARDWARE_MANAGER_H_
+#define _HARDWARE_MANAGER_H_
+
+
+
+struct pp_hwmgr;
+struct pp_hw_power_state;
+struct pp_power_state;
+enum amd_dpm_forced_level;
+struct PP_TemperatureRange;
+
+struct phm_fan_speed_info {
+ uint32_t min_percent;
+ uint32_t max_percent;
+ uint32_t min_rpm;
+ uint32_t max_rpm;
+ bool supports_percent_read;
+ bool supports_percent_write;
+ bool supports_rpm_read;
+ bool supports_rpm_write;
+};
+
+/* Automatic Power State Throttling */
+enum PHM_AutoThrottleSource
+{
+ PHM_AutoThrottleSource_Thermal,
+ PHM_AutoThrottleSource_External
+};
+
+typedef enum PHM_AutoThrottleSource PHM_AutoThrottleSource;
+
+enum phm_platform_caps {
+ PHM_PlatformCaps_AtomBiosPpV1 = 0,
+ PHM_PlatformCaps_PowerPlaySupport,
+ PHM_PlatformCaps_ACOverdriveSupport,
+ PHM_PlatformCaps_BacklightSupport,
+ PHM_PlatformCaps_ThermalController,
+ PHM_PlatformCaps_BiosPowerSourceControl,
+ PHM_PlatformCaps_DisableVoltageTransition,
+ PHM_PlatformCaps_DisableEngineTransition,
+ PHM_PlatformCaps_DisableMemoryTransition,
+ PHM_PlatformCaps_DynamicPowerManagement,
+ PHM_PlatformCaps_EnableASPML0s,
+ PHM_PlatformCaps_EnableASPML1,
+ PHM_PlatformCaps_OD5inACSupport,
+ PHM_PlatformCaps_OD5inDCSupport,
+ PHM_PlatformCaps_SoftStateOD5,
+ PHM_PlatformCaps_NoOD5Support,
+ PHM_PlatformCaps_ContinuousHardwarePerformanceRange,
+ PHM_PlatformCaps_ActivityReporting,
+ PHM_PlatformCaps_EnableBackbias,
+ PHM_PlatformCaps_OverdriveDisabledByPowerBudget,
+ PHM_PlatformCaps_ShowPowerBudgetWarning,
+ PHM_PlatformCaps_PowerBudgetWaiverAvailable,
+ PHM_PlatformCaps_GFXClockGatingSupport,
+ PHM_PlatformCaps_MMClockGatingSupport,
+ PHM_PlatformCaps_AutomaticDCTransition,
+ PHM_PlatformCaps_GeminiPrimary,
+ PHM_PlatformCaps_MemorySpreadSpectrumSupport,
+ PHM_PlatformCaps_EngineSpreadSpectrumSupport,
+ PHM_PlatformCaps_StepVddc,
+ PHM_PlatformCaps_DynamicPCIEGen2Support,
+ PHM_PlatformCaps_SMC,
+ PHM_PlatformCaps_FaultyInternalThermalReading, /* Internal thermal controller reports faulty temperature value when DAC2 is active */
+ PHM_PlatformCaps_EnableVoltageControl, /* indicates voltage can be controlled */
+ PHM_PlatformCaps_EnableSideportControl, /* indicates Sideport can be controlled */
+ PHM_PlatformCaps_VideoPlaybackEEUNotification, /* indicates EEU notification of video start/stop is required */
+ PHM_PlatformCaps_TurnOffPll_ASPML1, /* PCIE Turn Off PLL in ASPM L1 */
+ PHM_PlatformCaps_EnableHTLinkControl, /* indicates HT Link can be controlled by ACPI or CLMC overrided/automated mode. */
+ PHM_PlatformCaps_PerformanceStateOnly, /* indicates only performance power state to be used on current system. */
+ PHM_PlatformCaps_ExclusiveModeAlwaysHigh, /* In Exclusive (3D) mode always stay in High state. */
+ PHM_PlatformCaps_DisableMGClockGating, /* to disable Medium Grain Clock Gating or not */
+ PHM_PlatformCaps_DisableMGCGTSSM, /* TO disable Medium Grain Clock Gating Shader Complex control */
+ PHM_PlatformCaps_UVDAlwaysHigh, /* In UVD mode always stay in High state */
+ PHM_PlatformCaps_DisablePowerGating, /* to disable power gating */
+ PHM_PlatformCaps_CustomThermalPolicy, /* indicates only performance power state to be used on current system. */
+ PHM_PlatformCaps_StayInBootState, /* Stay in Boot State, do not do clock/voltage or PCIe Lane and Gen switching (RV7xx and up). */
+ PHM_PlatformCaps_SMCAllowSeparateSWThermalState, /* SMC use separate SW thermal state, instead of the default SMC thermal policy. */
+ PHM_PlatformCaps_MultiUVDStateSupport, /* Powerplay state table supports multi UVD states. */
+ PHM_PlatformCaps_EnableSCLKDeepSleepForUVD, /* With HW ECOs, we don't need to disable SCLK Deep Sleep for UVD state. */
+ PHM_PlatformCaps_EnableMCUHTLinkControl, /* Enable HT link control by MCU */
+ PHM_PlatformCaps_ABM, /* ABM support.*/
+ PHM_PlatformCaps_KongThermalPolicy, /* A thermal policy specific for Kong */
+ PHM_PlatformCaps_SwitchVDDNB, /* if the users want to switch VDDNB */
+ PHM_PlatformCaps_ULPS, /* support ULPS mode either through ACPI state or ULPS state */
+ PHM_PlatformCaps_NativeULPS, /* hardware capable of ULPS state (other than through the ACPI state) */
+ PHM_PlatformCaps_EnableMVDDControl, /* indicates that memory voltage can be controlled */
+ PHM_PlatformCaps_ControlVDDCI, /* Control VDDCI separately from VDDC. */
+ PHM_PlatformCaps_DisableDCODT, /* indicates if DC ODT apply or not */
+ PHM_PlatformCaps_DynamicACTiming, /* if the SMC dynamically re-programs MC SEQ register values */
+ PHM_PlatformCaps_EnableThermalIntByGPIO, /* enable throttle control through GPIO */
+ PHM_PlatformCaps_BootStateOnAlert, /* Go to boot state on alerts, e.g. on an AC->DC transition. */
+ PHM_PlatformCaps_DontWaitForVBlankOnAlert, /* Do NOT wait for VBLANK during an alert (e.g. AC->DC transition). */
+ PHM_PlatformCaps_Force3DClockSupport, /* indicates if the platform supports force 3D clock. */
+ PHM_PlatformCaps_MicrocodeFanControl, /* Fan is controlled by the SMC microcode. */
+ PHM_PlatformCaps_AdjustUVDPriorityForSP,
+ PHM_PlatformCaps_DisableLightSleep, /* Light sleep for evergreen family. */
+ PHM_PlatformCaps_DisableMCLS, /* MC Light sleep */
+ PHM_PlatformCaps_RegulatorHot, /* Enable throttling on 'regulator hot' events. */
+ PHM_PlatformCaps_BACO, /* Support Bus Alive Chip Off mode */
+ PHM_PlatformCaps_DisableDPM, /* Disable DPM, supported from Llano */
+ PHM_PlatformCaps_DynamicM3Arbiter, /* support dynamically change m3 arbitor parameters */
+ PHM_PlatformCaps_SclkDeepSleep, /* support sclk deep sleep */
+ PHM_PlatformCaps_DynamicPatchPowerState, /* this ASIC supports to patch power state dynamically */
+ PHM_PlatformCaps_ThermalAutoThrottling, /* enabling auto thermal throttling, */
+ PHM_PlatformCaps_SumoThermalPolicy, /* A thermal policy specific for Sumo */
+ PHM_PlatformCaps_PCIEPerformanceRequest, /* support to change RC voltage */
+ PHM_PlatformCaps_BLControlledByGPU, /* support varibright */
+ PHM_PlatformCaps_PowerContainment, /* support DPM2 power containment (AKA TDP clamping) */
+ PHM_PlatformCaps_SQRamping, /* support DPM2 SQ power throttle */
+ PHM_PlatformCaps_CAC, /* support Capacitance * Activity power estimation */
+ PHM_PlatformCaps_NIChipsets, /* Northern Island and beyond chipsets */
+ PHM_PlatformCaps_TrinityChipsets, /* Trinity chipset */
+ PHM_PlatformCaps_EvergreenChipsets, /* Evergreen family chipset */
+ PHM_PlatformCaps_PowerControl, /* Cayman and beyond chipsets */
+ PHM_PlatformCaps_DisableLSClockGating, /* to disable Light Sleep control for HDP memories */
+ PHM_PlatformCaps_BoostState, /* this ASIC supports boost state */
+ PHM_PlatformCaps_UserMaxClockForMultiDisplays, /* indicates if max memory clock is used for all status when multiple displays are connected */
+ PHM_PlatformCaps_RegWriteDelay, /* indicates if back to back reg write delay is required */
+ PHM_PlatformCaps_NonABMSupportInPPLib, /* ABM is not supported in PPLIB, (moved from PPLIB to DAL) */
+ PHM_PlatformCaps_GFXDynamicMGPowerGating, /* Enable Dynamic MG PowerGating on Trinity */
+ PHM_PlatformCaps_DisableSMUUVDHandshake, /* Disable SMU UVD Handshake */
+ PHM_PlatformCaps_DTE, /* Support Digital Temperature Estimation */
+ PHM_PlatformCaps_W5100Specifc_SmuSkipMsgDTE, /* This is for the feature requested by David B., and Tonny W.*/
+ PHM_PlatformCaps_UVDPowerGating, /* enable UVD power gating, supported from Llano */
+ PHM_PlatformCaps_UVDDynamicPowerGating, /* enable UVD Dynamic power gating, supported from UVD5 */
+ PHM_PlatformCaps_VCEPowerGating, /* Enable VCE power gating, supported for TN and later ASICs */
+ PHM_PlatformCaps_SamuPowerGating, /* Enable SAMU power gating, supported for KV and later ASICs */
+ PHM_PlatformCaps_UVDDPM, /* UVD clock DPM */
+ PHM_PlatformCaps_VCEDPM, /* VCE clock DPM */
+ PHM_PlatformCaps_SamuDPM, /* SAMU clock DPM */
+ PHM_PlatformCaps_AcpDPM, /* ACP clock DPM */
+ PHM_PlatformCaps_SclkDeepSleepAboveLow, /* Enable SCLK Deep Sleep on all DPM states */
+ PHM_PlatformCaps_DynamicUVDState, /* Dynamic UVD State */
+ PHM_PlatformCaps_WantSAMClkWithDummyBackEnd, /* Set SAM Clk With Dummy Back End */
+ PHM_PlatformCaps_WantUVDClkWithDummyBackEnd, /* Set UVD Clk With Dummy Back End */
+ PHM_PlatformCaps_WantVCEClkWithDummyBackEnd, /* Set VCE Clk With Dummy Back End */
+ PHM_PlatformCaps_WantACPClkWithDummyBackEnd, /* Set SAM Clk With Dummy Back End */
+ PHM_PlatformCaps_OD6inACSupport, /* indicates that the ASIC/back end supports OD6 */
+ PHM_PlatformCaps_OD6inDCSupport, /* indicates that the ASIC/back end supports OD6 in DC */
+ PHM_PlatformCaps_EnablePlatformPowerManagement, /* indicates that Platform Power Management feature is supported */
+ PHM_PlatformCaps_SurpriseRemoval, /* indicates that surprise removal feature is requested */
+ PHM_PlatformCaps_NewCACVoltage, /* indicates new CAC voltage table support */
+ PHM_PlatformCaps_DBRamping, /* for dI/dT feature */
+ PHM_PlatformCaps_TDRamping, /* for dI/dT feature */
+ PHM_PlatformCaps_TCPRamping, /* for dI/dT feature */
+ PHM_PlatformCaps_EnableSMU7ThermalManagement, /* SMC will manage thermal events */
+ PHM_PlatformCaps_FPS, /* FPS support */
+ PHM_PlatformCaps_ACP, /* ACP support */
+ PHM_PlatformCaps_SclkThrottleLowNotification, /* SCLK Throttle Low Notification */
+ PHM_PlatformCaps_XDMAEnabled, /* XDMA engine is enabled */
+ PHM_PlatformCaps_UseDummyBackEnd, /* use dummy back end */
+ PHM_PlatformCaps_EnableDFSBypass, /* Enable DFS bypass */
+ PHM_PlatformCaps_VddNBDirectRequest,
+ PHM_PlatformCaps_PauseMMSessions,
+ PHM_PlatformCaps_UnTabledHardwareInterface, /* Tableless/direct call hardware interface for CI and newer ASICs */
+ PHM_PlatformCaps_SMU7, /* indicates that vpuRecoveryBegin without SMU shutdown */
+ PHM_PlatformCaps_RevertGPIO5Polarity, /* indicates revert GPIO5 plarity table support */
+ PHM_PlatformCaps_Thermal2GPIO17, /* indicates thermal2GPIO17 table support */
+ PHM_PlatformCaps_ThermalOutGPIO, /* indicates ThermalOutGPIO support, pin number is assigned by VBIOS */
+ PHM_PlatformCaps_DisableMclkSwitchingForFrameLock, /* Disable memory clock switch during Framelock */
+ PHM_PlatformCaps_VRHotGPIOConfigurable, /* indicates VR_HOT GPIO configurable */
+ PHM_PlatformCaps_TempInversion, /* enable Temp Inversion feature */
+ PHM_PlatformCaps_IOIC3,
+ PHM_PlatformCaps_ConnectedStandby,
+ PHM_PlatformCaps_EVV,
+ PHM_PlatformCaps_EnableLongIdleBACOSupport,
+ PHM_PlatformCaps_CombinePCCWithThermalSignal,
+ PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc,
+ PHM_PlatformCaps_StablePState,
+ PHM_PlatformCaps_OD6PlusinACSupport,
+ PHM_PlatformCaps_OD6PlusinDCSupport,
+ PHM_PlatformCaps_ODThermalLimitUnlock,
+ PHM_PlatformCaps_ReducePowerLimit,
+ PHM_PlatformCaps_ODFuzzyFanControlSupport,
+ PHM_PlatformCaps_GeminiRegulatorFanControlSupport,
+ PHM_PlatformCaps_ControlVDDGFX,
+ PHM_PlatformCaps_BBBSupported,
+ PHM_PlatformCaps_DisableVoltageIsland,
+ PHM_PlatformCaps_FanSpeedInTableIsRPM,
+ PHM_PlatformCaps_GFXClockGatingManagedInCAIL,
+ PHM_PlatformCaps_IcelandULPSSWWorkAround,
+ PHM_PlatformCaps_FPSEnhancement,
+ PHM_PlatformCaps_LoadPostProductionFirmware,
+ PHM_PlatformCaps_VpuRecoveryInProgress,
+ PHM_PlatformCaps_Falcon_QuickTransition,
+ PHM_PlatformCaps_AVFS,
+ PHM_PlatformCaps_ClockStretcher,
+ PHM_PlatformCaps_TablelessHardwareInterface,
+ PHM_PlatformCaps_EnableDriverEVV,
+ PHM_PlatformCaps_Max
+};
+
+#define PHM_MAX_NUM_CAPS_BITS_PER_FIELD (sizeof(uint32_t)*8)
+
+/* Number of uint32_t entries used by CAPS table */
+#define PHM_MAX_NUM_CAPS_ULONG_ENTRIES \
+ ((PHM_PlatformCaps_Max + ((PHM_MAX_NUM_CAPS_BITS_PER_FIELD) - 1)) / (PHM_MAX_NUM_CAPS_BITS_PER_FIELD))
+
+struct pp_hw_descriptor {
+ uint32_t hw_caps[PHM_MAX_NUM_CAPS_ULONG_ENTRIES];
+};
+
+enum PHM_PerformanceLevelDesignation {
+ PHM_PerformanceLevelDesignation_Activity,
+ PHM_PerformanceLevelDesignation_PowerContainment
+};
+
+typedef enum PHM_PerformanceLevelDesignation PHM_PerformanceLevelDesignation;
+
+struct PHM_PerformanceLevel {
+ uint32_t coreClock;
+ uint32_t memory_clock;
+ uint32_t vddc;
+ uint32_t vddci;
+ uint32_t nonLocalMemoryFreq;
+ uint32_t nonLocalMemoryWidth;
+};
+
+typedef struct PHM_PerformanceLevel PHM_PerformanceLevel;
+
+/* Function for setting a platform cap */
+static inline void phm_cap_set(uint32_t *caps,
+ enum phm_platform_caps c)
+{
+ caps[c / PHM_MAX_NUM_CAPS_BITS_PER_FIELD] |= (1UL <<
+ (c & (PHM_MAX_NUM_CAPS_BITS_PER_FIELD - 1)));
+}
+
+static inline void phm_cap_unset(uint32_t *caps,
+ enum phm_platform_caps c)
+{
+ caps[c / PHM_MAX_NUM_CAPS_BITS_PER_FIELD] &= ~(1UL << (c & (PHM_MAX_NUM_CAPS_BITS_PER_FIELD - 1)));
+}
+
+static inline bool phm_cap_enabled(const uint32_t *caps, enum phm_platform_caps c)
+{
+ return (0 != (caps[c / PHM_MAX_NUM_CAPS_BITS_PER_FIELD] &
+ (1UL << (c & (PHM_MAX_NUM_CAPS_BITS_PER_FIELD - 1)))));
+}
+
+#define PP_PCIEGenInvalid 0xffff
+enum PP_PCIEGen {
+ PP_PCIEGen1 = 0, /* PCIE 1.0 - Transfer rate of 2.5 GT/s */
+ PP_PCIEGen2, /*PCIE 2.0 - Transfer rate of 5.0 GT/s */
+ PP_PCIEGen3 /*PCIE 3.0 - Transfer rate of 8.0 GT/s */
+};
+
+typedef enum PP_PCIEGen PP_PCIEGen;
+
+#define PP_Min_PCIEGen PP_PCIEGen1
+#define PP_Max_PCIEGen PP_PCIEGen3
+#define PP_Min_PCIELane 1
+#define PP_Max_PCIELane 32
+
+enum phm_clock_Type {
+ PHM_DispClock = 1,
+ PHM_SClock,
+ PHM_MemClock
+};
+
+#define MAX_NUM_CLOCKS 16
+
+struct PP_Clocks {
+ uint32_t engineClock;
+ uint32_t memoryClock;
+ uint32_t BusBandwidth;
+ uint32_t engineClockInSR;
+};
+
+struct phm_platform_descriptor {
+ uint32_t platformCaps[PHM_MAX_NUM_CAPS_ULONG_ENTRIES];
+ uint32_t vbiosInterruptId;
+ struct PP_Clocks overdriveLimit;
+ struct PP_Clocks clockStep;
+ uint32_t hardwareActivityPerformanceLevels;
+ uint32_t minimumClocksReductionPercentage;
+ uint32_t minOverdriveVDDC;
+ uint32_t maxOverdriveVDDC;
+ uint32_t overdriveVDDCStep;
+ uint32_t hardwarePerformanceLevels;
+ uint16_t powerBudget;
+ uint32_t TDPLimit;
+ uint32_t nearTDPLimit;
+ uint32_t nearTDPLimitAdjusted;
+ uint32_t SQRampingThreshold;
+ uint32_t CACLeakage;
+ uint16_t TDPODLimit;
+ uint32_t TDPAdjustment;
+ bool TDPAdjustmentPolarity;
+ uint16_t LoadLineSlope;
+ uint32_t VidMinLimit;
+ uint32_t VidMaxLimit;
+ uint32_t VidStep;
+ uint32_t VidAdjustment;
+ bool VidAdjustmentPolarity;
+};
+
+struct phm_clocks {
+ uint32_t num_of_entries;
+ uint32_t clock[MAX_NUM_CLOCKS];
+};
+
+enum PP_DAL_POWERLEVEL {
+ PP_DAL_POWERLEVEL_INVALID = 0,
+ PP_DAL_POWERLEVEL_ULTRALOW,
+ PP_DAL_POWERLEVEL_LOW,
+ PP_DAL_POWERLEVEL_NOMINAL,
+ PP_DAL_POWERLEVEL_PERFORMANCE,
+
+ PP_DAL_POWERLEVEL_0 = PP_DAL_POWERLEVEL_ULTRALOW,
+ PP_DAL_POWERLEVEL_1 = PP_DAL_POWERLEVEL_LOW,
+ PP_DAL_POWERLEVEL_2 = PP_DAL_POWERLEVEL_NOMINAL,
+ PP_DAL_POWERLEVEL_3 = PP_DAL_POWERLEVEL_PERFORMANCE,
+ PP_DAL_POWERLEVEL_4 = PP_DAL_POWERLEVEL_3+1,
+ PP_DAL_POWERLEVEL_5 = PP_DAL_POWERLEVEL_4+1,
+ PP_DAL_POWERLEVEL_6 = PP_DAL_POWERLEVEL_5+1,
+ PP_DAL_POWERLEVEL_7 = PP_DAL_POWERLEVEL_6+1,
+};
+
+
+extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr);
+extern int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate);
+extern int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate);
+extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
+extern int phm_setup_asic(struct pp_hwmgr *hwmgr);
+extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr);
+extern void phm_init_dynamic_caps(struct pp_hwmgr *hwmgr);
+extern bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr);
+extern int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block);
+extern int phm_set_power_state(struct pp_hwmgr *hwmgr,
+ const struct pp_hw_power_state *pcurrent_state,
+ const struct pp_hw_power_state *pnew_power_state);
+
+extern int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *adjusted_ps,
+ const struct pp_power_state *current_ps);
+
+extern int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level);
+extern int phm_display_configuration_changed(struct pp_hwmgr *hwmgr);
+extern int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
+extern int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info);
+extern int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range);
+extern int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr);
+extern bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr);
+
+extern int phm_check_states_equal(struct pp_hwmgr *hwmgr,
+ const struct pp_hw_power_state *pstate1,
+ const struct pp_hw_power_state *pstate2,
+ bool *equal);
+
+extern int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
+ const struct amd_pp_display_configuration *display_config);
+
+extern int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
+ struct amd_pp_dal_clock_info*info);
+
+extern int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr);
+
+extern int phm_power_down_asic(struct pp_hwmgr *hwmgr);
+
+#endif /* _HARDWARE_MANAGER_H_ */
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
new file mode 100644
index 000000000000..aeaa3dbba525
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -0,0 +1,801 @@
+/*
+ * Copyright 2015 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 _HWMGR_H_
+#define _HWMGR_H_
+
+#include <linux/seq_file.h>
+#include "amd_powerplay.h"
+#include "pp_instance.h"
+#include "hardwaremanager.h"
+#include "pp_power_source.h"
+#include "hwmgr_ppt.h"
+#include "ppatomctrl.h"
+#include "hwmgr_ppt.h"
+
+struct pp_instance;
+struct pp_hwmgr;
+struct pp_hw_power_state;
+struct pp_power_state;
+struct PP_VCEState;
+struct phm_fan_speed_info;
+struct pp_atomctrl_voltage_table;
+
+
+enum DISPLAY_GAP {
+ DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */
+ DISPLAY_GAP_VBLANK = 1, /* Wait for vblank. */
+ DISPLAY_GAP_WATERMARK = 2, /* Wait for MCHG watermark. (Note that HW may deassert WM in VBI depending on DC_STUTTER_CNTL.) */
+ DISPLAY_GAP_IGNORE = 3 /* Do not wait. */
+};
+typedef enum DISPLAY_GAP DISPLAY_GAP;
+
+
+struct vi_dpm_level {
+ bool enabled;
+ uint32_t value;
+ uint32_t param1;
+};
+
+struct vi_dpm_table {
+ uint32_t count;
+ struct vi_dpm_level dpm_level[1];
+};
+
+enum PP_Result {
+ PP_Result_TableImmediateExit = 0x13,
+};
+
+#define PCIE_PERF_REQ_REMOVE_REGISTRY 0
+#define PCIE_PERF_REQ_FORCE_LOWPOWER 1
+#define PCIE_PERF_REQ_GEN1 2
+#define PCIE_PERF_REQ_GEN2 3
+#define PCIE_PERF_REQ_GEN3 4
+
+enum PHM_BackEnd_Magic {
+ PHM_Dummy_Magic = 0xAA5555AA,
+ PHM_RV770_Magic = 0xDCBAABCD,
+ PHM_Kong_Magic = 0x239478DF,
+ PHM_NIslands_Magic = 0x736C494E,
+ PHM_Sumo_Magic = 0x8339FA11,
+ PHM_SIslands_Magic = 0x369431AC,
+ PHM_Trinity_Magic = 0x96751873,
+ PHM_CIslands_Magic = 0x38AC78B0,
+ PHM_Kv_Magic = 0xDCBBABC0,
+ PHM_VIslands_Magic = 0x20130307,
+ PHM_Cz_Magic = 0x67DCBA25
+};
+
+
+#define PHM_PCIE_POWERGATING_TARGET_GFX 0
+#define PHM_PCIE_POWERGATING_TARGET_DDI 1
+#define PHM_PCIE_POWERGATING_TARGET_PLLCASCADE 2
+#define PHM_PCIE_POWERGATING_TARGET_PHY 3
+
+typedef int (*phm_table_function)(struct pp_hwmgr *hwmgr, void *input,
+ void *output, void *storage, int result);
+
+typedef bool (*phm_check_function)(struct pp_hwmgr *hwmgr);
+
+struct phm_set_power_state_input {
+ const struct pp_hw_power_state *pcurrent_state;
+ const struct pp_hw_power_state *pnew_state;
+};
+
+struct phm_acp_arbiter {
+ uint32_t acpclk;
+};
+
+struct phm_uvd_arbiter {
+ uint32_t vclk;
+ uint32_t dclk;
+ uint32_t vclk_ceiling;
+ uint32_t dclk_ceiling;
+};
+
+struct phm_vce_arbiter {
+ uint32_t evclk;
+ uint32_t ecclk;
+};
+
+struct phm_gfx_arbiter {
+ uint32_t sclk;
+ uint32_t mclk;
+ uint32_t sclk_over_drive;
+ uint32_t mclk_over_drive;
+ uint32_t sclk_threshold;
+ uint32_t num_cus;
+};
+
+/* Entries in the master tables */
+struct phm_master_table_item {
+ phm_check_function isFunctionNeededInRuntimeTable;
+ phm_table_function tableFunction;
+};
+
+enum phm_master_table_flag {
+ PHM_MasterTableFlag_None = 0,
+ PHM_MasterTableFlag_ExitOnError = 1,
+};
+
+/* The header of the master tables */
+struct phm_master_table_header {
+ uint32_t storage_size;
+ uint32_t flags;
+ struct phm_master_table_item *master_list;
+};
+
+struct phm_runtime_table_header {
+ uint32_t storage_size;
+ bool exit_error;
+ phm_table_function *function_list;
+};
+
+struct phm_clock_array {
+ uint32_t count;
+ uint32_t values[1];
+};
+
+struct phm_clock_voltage_dependency_record {
+ uint32_t clk;
+ uint32_t v;
+};
+
+struct phm_vceclock_voltage_dependency_record {
+ uint32_t ecclk;
+ uint32_t evclk;
+ uint32_t v;
+};
+
+struct phm_uvdclock_voltage_dependency_record {
+ uint32_t vclk;
+ uint32_t dclk;
+ uint32_t v;
+};
+
+struct phm_samuclock_voltage_dependency_record {
+ uint32_t samclk;
+ uint32_t v;
+};
+
+struct phm_acpclock_voltage_dependency_record {
+ uint32_t acpclk;
+ uint32_t v;
+};
+
+struct phm_clock_voltage_dependency_table {
+ uint32_t count; /* Number of entries. */
+ struct phm_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_phase_shedding_limits_record {
+ uint32_t Voltage;
+ uint32_t Sclk;
+ uint32_t Mclk;
+};
+
+
+extern int phm_dispatch_table(struct pp_hwmgr *hwmgr,
+ struct phm_runtime_table_header *rt_table,
+ void *input, void *output);
+
+extern int phm_construct_table(struct pp_hwmgr *hwmgr,
+ struct phm_master_table_header *master_table,
+ struct phm_runtime_table_header *rt_table);
+
+extern int phm_destroy_table(struct pp_hwmgr *hwmgr,
+ struct phm_runtime_table_header *rt_table);
+
+
+struct phm_uvd_clock_voltage_dependency_record {
+ uint32_t vclk;
+ uint32_t dclk;
+ uint32_t v;
+};
+
+struct phm_uvd_clock_voltage_dependency_table {
+ uint8_t count;
+ struct phm_uvd_clock_voltage_dependency_record entries[1];
+};
+
+struct phm_acp_clock_voltage_dependency_record {
+ uint32_t acpclk;
+ uint32_t v;
+};
+
+struct phm_acp_clock_voltage_dependency_table {
+ uint32_t count;
+ struct phm_acp_clock_voltage_dependency_record entries[1];
+};
+
+struct phm_vce_clock_voltage_dependency_record {
+ uint32_t ecclk;
+ uint32_t evclk;
+ uint32_t v;
+};
+
+struct phm_phase_shedding_limits_table {
+ uint32_t count;
+ struct phm_phase_shedding_limits_record entries[1];
+};
+
+struct phm_vceclock_voltage_dependency_table {
+ uint8_t count; /* Number of entries. */
+ struct phm_vceclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_uvdclock_voltage_dependency_table {
+ uint8_t count; /* Number of entries. */
+ struct phm_uvdclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_samuclock_voltage_dependency_table {
+ uint8_t count; /* Number of entries. */
+ struct phm_samuclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_acpclock_voltage_dependency_table {
+ uint32_t count; /* Number of entries. */
+ struct phm_acpclock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
+};
+
+struct phm_vce_clock_voltage_dependency_table {
+ uint8_t count;
+ struct phm_vce_clock_voltage_dependency_record entries[1];
+};
+
+struct pp_hwmgr_func {
+ int (*backend_init)(struct pp_hwmgr *hw_mgr);
+ int (*backend_fini)(struct pp_hwmgr *hw_mgr);
+ int (*asic_setup)(struct pp_hwmgr *hw_mgr);
+ int (*get_power_state_size)(struct pp_hwmgr *hw_mgr);
+
+ int (*apply_state_adjust_rules)(struct pp_hwmgr *hwmgr,
+ struct pp_power_state *prequest_ps,
+ const struct pp_power_state *pcurrent_ps);
+
+ int (*force_dpm_level)(struct pp_hwmgr *hw_mgr,
+ enum amd_dpm_forced_level level);
+
+ int (*dynamic_state_management_enable)(
+ struct pp_hwmgr *hw_mgr);
+
+ int (*patch_boot_state)(struct pp_hwmgr *hwmgr,
+ struct pp_hw_power_state *hw_ps);
+
+ int (*get_pp_table_entry)(struct pp_hwmgr *hwmgr,
+ unsigned long, struct pp_power_state *);
+ int (*get_num_of_pp_table_entries)(struct pp_hwmgr *hwmgr);
+ int (*powerdown_uvd)(struct pp_hwmgr *hwmgr);
+ int (*powergate_vce)(struct pp_hwmgr *hwmgr, bool bgate);
+ int (*powergate_uvd)(struct pp_hwmgr *hwmgr, bool bgate);
+ int (*get_mclk)(struct pp_hwmgr *hwmgr, bool low);
+ int (*get_sclk)(struct pp_hwmgr *hwmgr, bool low);
+ int (*power_state_set)(struct pp_hwmgr *hwmgr,
+ const void *state);
+ void (*print_current_perforce_level)(struct pp_hwmgr *hwmgr,
+ struct seq_file *m);
+ int (*enable_clock_power_gating)(struct pp_hwmgr *hwmgr);
+ int (*notify_smc_display_config_after_ps_adjustment)(struct pp_hwmgr *hwmgr);
+ int (*display_config_changed)(struct pp_hwmgr *hwmgr);
+ int (*disable_clock_power_gating)(struct pp_hwmgr *hwmgr);
+ int (*update_clock_gatings)(struct pp_hwmgr *hwmgr,
+ const uint32_t *msg_id);
+ int (*set_max_fan_rpm_output)(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm);
+ int (*set_max_fan_pwm_output)(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm);
+ int (*get_temperature)(struct pp_hwmgr *hwmgr);
+ int (*stop_thermal_controller)(struct pp_hwmgr *hwmgr);
+ int (*get_fan_speed_info)(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
+ int (*set_fan_control_mode)(struct pp_hwmgr *hwmgr, uint32_t mode);
+ int (*get_fan_control_mode)(struct pp_hwmgr *hwmgr);
+ int (*set_fan_speed_percent)(struct pp_hwmgr *hwmgr, uint32_t percent);
+ int (*get_fan_speed_percent)(struct pp_hwmgr *hwmgr, uint32_t *speed);
+ int (*set_fan_speed_rpm)(struct pp_hwmgr *hwmgr, uint32_t percent);
+ int (*get_fan_speed_rpm)(struct pp_hwmgr *hwmgr, uint32_t *speed);
+ int (*reset_fan_speed_to_default)(struct pp_hwmgr *hwmgr);
+ int (*uninitialize_thermal_controller)(struct pp_hwmgr *hwmgr);
+ int (*register_internal_thermal_interrupt)(struct pp_hwmgr *hwmgr,
+ const void *thermal_interrupt_info);
+ bool (*check_smc_update_required_for_display_configuration)(struct pp_hwmgr *hwmgr);
+ int (*check_states_equal)(struct pp_hwmgr *hwmgr,
+ const struct pp_hw_power_state *pstate1,
+ const struct pp_hw_power_state *pstate2,
+ bool *equal);
+ int (*set_cpu_power_state)(struct pp_hwmgr *hwmgr);
+ int (*store_cc6_data)(struct pp_hwmgr *hwmgr, uint32_t separation_time,
+ bool cc6_disable, bool pstate_disable,
+ bool pstate_switch_disable);
+ int (*get_dal_power_level)(struct pp_hwmgr *hwmgr,
+ struct amd_pp_dal_clock_info *info);
+ int (*power_off_asic)(struct pp_hwmgr *hwmgr);
+};
+
+struct pp_table_func {
+ int (*pptable_init)(struct pp_hwmgr *hw_mgr);
+ int (*pptable_fini)(struct pp_hwmgr *hw_mgr);
+ int (*pptable_get_number_of_vce_state_table_entries)(struct pp_hwmgr *hw_mgr);
+ int (*pptable_get_vce_state_table_entry)(
+ struct pp_hwmgr *hwmgr,
+ unsigned long i,
+ struct PP_VCEState *vce_state,
+ void **clock_info,
+ unsigned long *flag);
+};
+
+union phm_cac_leakage_record {
+ struct {
+ uint16_t Vddc; /* in CI, we use it for StdVoltageHiSidd */
+ uint32_t Leakage; /* in CI, we use it for StdVoltageLoSidd */
+ };
+ struct {
+ uint16_t Vddc1;
+ uint16_t Vddc2;
+ uint16_t Vddc3;
+ };
+};
+
+struct phm_cac_leakage_table {
+ uint32_t count;
+ union phm_cac_leakage_record entries[1];
+};
+
+struct phm_samu_clock_voltage_dependency_record {
+ uint32_t samclk;
+ uint32_t v;
+};
+
+
+struct phm_samu_clock_voltage_dependency_table {
+ uint8_t count;
+ struct phm_samu_clock_voltage_dependency_record entries[1];
+};
+
+struct phm_cac_tdp_table {
+ uint16_t usTDP;
+ uint16_t usConfigurableTDP;
+ uint16_t usTDC;
+ uint16_t usBatteryPowerLimit;
+ uint16_t usSmallPowerLimit;
+ uint16_t usLowCACLeakage;
+ uint16_t usHighCACLeakage;
+ uint16_t usMaximumPowerDeliveryLimit;
+ uint16_t usOperatingTempMinLimit;
+ uint16_t usOperatingTempMaxLimit;
+ uint16_t usOperatingTempStep;
+ uint16_t usOperatingTempHyst;
+ uint16_t usDefaultTargetOperatingTemp;
+ uint16_t usTargetOperatingTemp;
+ uint16_t usPowerTuneDataSetID;
+ uint16_t usSoftwareShutdownTemp;
+ uint16_t usClockStretchAmount;
+ uint16_t usTemperatureLimitHotspot;
+ uint16_t usTemperatureLimitLiquid1;
+ uint16_t usTemperatureLimitLiquid2;
+ uint16_t usTemperatureLimitVrVddc;
+ uint16_t usTemperatureLimitVrMvdd;
+ uint16_t usTemperatureLimitPlx;
+ uint8_t ucLiquid1_I2C_address;
+ uint8_t ucLiquid2_I2C_address;
+ uint8_t ucLiquid_I2C_Line;
+ uint8_t ucVr_I2C_address;
+ uint8_t ucVr_I2C_Line;
+ uint8_t ucPlx_I2C_address;
+ uint8_t ucPlx_I2C_Line;
+};
+
+struct phm_ppm_table {
+ uint8_t ppm_design;
+ uint16_t cpu_core_number;
+ uint32_t platform_tdp;
+ uint32_t small_ac_platform_tdp;
+ uint32_t platform_tdc;
+ uint32_t small_ac_platform_tdc;
+ uint32_t apu_tdp;
+ uint32_t dgpu_tdp;
+ uint32_t dgpu_ulv_power;
+ uint32_t tj_max;
+};
+
+struct phm_vq_budgeting_record {
+ uint32_t ulCUs;
+ uint32_t ulSustainableSOCPowerLimitLow;
+ uint32_t ulSustainableSOCPowerLimitHigh;
+ uint32_t ulMinSclkLow;
+ uint32_t ulMinSclkHigh;
+ uint8_t ucDispConfig;
+ uint32_t ulDClk;
+ uint32_t ulEClk;
+ uint32_t ulSustainableSclk;
+ uint32_t ulSustainableCUs;
+};
+
+struct phm_vq_budgeting_table {
+ uint8_t numEntries;
+ struct phm_vq_budgeting_record entries[1];
+};
+
+struct phm_clock_and_voltage_limits {
+ uint32_t sclk;
+ uint32_t mclk;
+ uint16_t vddc;
+ uint16_t vddci;
+ uint16_t vddgfx;
+};
+
+/* Structure to hold PPTable information */
+
+struct phm_ppt_v1_information {
+ struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_sclk;
+ struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_mclk;
+ struct phm_clock_array *valid_sclk_values;
+ struct phm_clock_array *valid_mclk_values;
+ struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
+ struct phm_clock_and_voltage_limits max_clock_voltage_on_ac;
+ struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
+ struct phm_ppm_table *ppm_parameter_table;
+ struct phm_cac_tdp_table *cac_dtp_table;
+ struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_dep_table;
+ struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
+ struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table;
+ struct phm_ppt_v1_pcie_table *pcie_table;
+ uint16_t us_ulv_voltage_offset;
+};
+
+struct phm_dynamic_state_info {
+ struct phm_clock_voltage_dependency_table *vddc_dependency_on_sclk;
+ struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk;
+ struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk;
+ struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk;
+ struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
+ struct phm_clock_array *valid_sclk_values;
+ struct phm_clock_array *valid_mclk_values;
+ struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
+ struct phm_clock_and_voltage_limits max_clock_voltage_on_ac;
+ uint32_t mclk_sclk_ratio;
+ uint32_t sclk_mclk_delta;
+ uint32_t vddc_vddci_delta;
+ uint32_t min_vddc_for_pcie_gen2;
+ struct phm_cac_leakage_table *cac_leakage_table;
+ struct phm_phase_shedding_limits_table *vddc_phase_shed_limits_table;
+
+ struct phm_vce_clock_voltage_dependency_table
+ *vce_clock_voltage_dependency_table;
+ struct phm_uvd_clock_voltage_dependency_table
+ *uvd_clock_voltage_dependency_table;
+ struct phm_acp_clock_voltage_dependency_table
+ *acp_clock_voltage_dependency_table;
+ struct phm_samu_clock_voltage_dependency_table
+ *samu_clock_voltage_dependency_table;
+
+ struct phm_ppm_table *ppm_parameter_table;
+ struct phm_cac_tdp_table *cac_dtp_table;
+ struct phm_clock_voltage_dependency_table *vdd_gfx_dependency_on_sclk;
+ struct phm_vq_budgeting_table *vq_budgeting_table;
+};
+
+struct pp_fan_info {
+ bool bNoFan;
+ uint8_t ucTachometerPulsesPerRevolution;
+ uint32_t ulMinRPM;
+ uint32_t ulMaxRPM;
+};
+
+struct pp_advance_fan_control_parameters {
+ uint16_t usTMin; /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
+ uint16_t usTMed; /* The middle temperature where we change slopes. */
+ uint16_t usTHigh; /* The high temperature for setting the second slope. */
+ uint16_t usPWMMin; /* The minimum PWM value in percent (0.01% increments). */
+ uint16_t usPWMMed; /* The PWM value (in percent) at TMed. */
+ uint16_t usPWMHigh; /* The PWM value at THigh. */
+ uint8_t ucTHyst; /* Temperature hysteresis. Integer. */
+ uint32_t ulCycleDelay; /* The time between two invocations of the fan control routine in microseconds. */
+ uint16_t usTMax; /* The max temperature */
+ uint8_t ucFanControlMode;
+ uint16_t usFanPWMMinLimit;
+ uint16_t usFanPWMMaxLimit;
+ uint16_t usFanPWMStep;
+ uint16_t usDefaultMaxFanPWM;
+ uint16_t usFanOutputSensitivity;
+ uint16_t usDefaultFanOutputSensitivity;
+ uint16_t usMaxFanPWM; /* The max Fan PWM value for Fuzzy Fan Control feature */
+ uint16_t usFanRPMMinLimit; /* Minimum limit range in percentage, need to calculate based on minRPM/MaxRpm */
+ uint16_t usFanRPMMaxLimit; /* Maximum limit range in percentage, usually set to 100% by default */
+ uint16_t usFanRPMStep; /* Step increments/decerements, in percent */
+ uint16_t usDefaultMaxFanRPM; /* The max Fan RPM value for Fuzzy Fan Control feature, default from PPTable */
+ uint16_t usMaxFanRPM; /* The max Fan RPM value for Fuzzy Fan Control feature, user defined */
+ uint16_t usFanCurrentLow; /* Low current */
+ uint16_t usFanCurrentHigh; /* High current */
+ uint16_t usFanRPMLow; /* Low RPM */
+ uint16_t usFanRPMHigh; /* High RPM */
+ uint32_t ulMinFanSCLKAcousticLimit; /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
+ uint8_t ucTargetTemperature; /* Advanced fan controller target temperature. */
+ uint8_t ucMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. This should be set to the highest PWM that will run the fan at its lowest RPM. */
+ uint16_t usFanGainEdge; /* The following is added for Fiji */
+ uint16_t usFanGainHotspot;
+ uint16_t usFanGainLiquid;
+ uint16_t usFanGainVrVddc;
+ uint16_t usFanGainVrMvdd;
+ uint16_t usFanGainPlx;
+ uint16_t usFanGainHbm;
+};
+
+struct pp_thermal_controller_info {
+ uint8_t ucType;
+ uint8_t ucI2cLine;
+ uint8_t ucI2cAddress;
+ struct pp_fan_info fanInfo;
+ struct pp_advance_fan_control_parameters advanceFanControlParameters;
+};
+
+struct phm_microcode_version_info {
+ uint32_t SMC;
+ uint32_t DMCU;
+ uint32_t MC;
+ uint32_t NB;
+};
+
+/**
+ * The main hardware manager structure.
+ */
+struct pp_hwmgr {
+ uint32_t chip_family;
+ uint32_t chip_id;
+ uint32_t hw_revision;
+ uint32_t sub_sys_id;
+ uint32_t sub_vendor_id;
+
+ void *device;
+ struct pp_smumgr *smumgr;
+ const void *soft_pp_table;
+ bool need_pp_table_upload;
+ enum amd_dpm_forced_level dpm_level;
+ bool block_hw_access;
+ struct phm_gfx_arbiter gfx_arbiter;
+ struct phm_acp_arbiter acp_arbiter;
+ struct phm_uvd_arbiter uvd_arbiter;
+ struct phm_vce_arbiter vce_arbiter;
+ uint32_t usec_timeout;
+ void *pptable;
+ struct phm_platform_descriptor platform_descriptor;
+ void *backend;
+ enum PP_DAL_POWERLEVEL dal_power_level;
+ struct phm_dynamic_state_info dyn_state;
+ struct phm_runtime_table_header setup_asic;
+ struct phm_runtime_table_header power_down_asic;
+ struct phm_runtime_table_header disable_dynamic_state_management;
+ struct phm_runtime_table_header enable_dynamic_state_management;
+ struct phm_runtime_table_header set_power_state;
+ struct phm_runtime_table_header enable_clock_power_gatings;
+ struct phm_runtime_table_header display_configuration_changed;
+ struct phm_runtime_table_header start_thermal_controller;
+ struct phm_runtime_table_header set_temperature_range;
+ const struct pp_hwmgr_func *hwmgr_func;
+ const struct pp_table_func *pptable_func;
+ struct pp_power_state *ps;
+ enum pp_power_source power_source;
+ uint32_t num_ps;
+ struct pp_thermal_controller_info thermal_controller;
+ bool fan_ctrl_is_in_default_mode;
+ uint32_t fan_ctrl_default_mode;
+ uint32_t tmin;
+ struct phm_microcode_version_info microcode_version_info;
+ uint32_t ps_size;
+ struct pp_power_state *current_ps;
+ struct pp_power_state *request_ps;
+ struct pp_power_state *boot_ps;
+ struct pp_power_state *uvd_ps;
+ struct amd_pp_display_configuration display_config;
+};
+
+
+extern int hwmgr_init(struct amd_pp_init *pp_init,
+ struct pp_instance *handle);
+
+extern int hwmgr_fini(struct pp_hwmgr *hwmgr);
+
+extern int hw_init_power_state_table(struct pp_hwmgr *hwmgr);
+
+extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
+ uint32_t value, uint32_t mask);
+
+extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
+ uint32_t index, uint32_t value, uint32_t mask);
+
+extern uint32_t phm_read_indirect_register(struct pp_hwmgr *hwmgr,
+ uint32_t indirect_port, uint32_t index);
+
+extern void phm_write_indirect_register(struct pp_hwmgr *hwmgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value);
+
+extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value,
+ uint32_t mask);
+
+extern void phm_wait_for_indirect_register_unequal(
+ struct pp_hwmgr *hwmgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value,
+ uint32_t mask);
+
+extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr);
+extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr);
+extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr);
+
+extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table);
+extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
+extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table);
+extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table);
+extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table);
+extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max);
+extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes);
+extern int32_t phm_get_dpm_level_enable_mask_value(void *table);
+extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage);
+extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci);
+extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level);
+extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table,
+ uint16_t virtual_voltage_id, int32_t *sclk);
+extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
+extern int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr);
+extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask);
+
+
+#define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU
+
+#define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
+#define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK
+
+#define PHM_SET_FIELD(origval, reg, field, fieldval) \
+ (((origval) & ~PHM_FIELD_MASK(reg, field)) | \
+ (PHM_FIELD_MASK(reg, field) & ((fieldval) << PHM_FIELD_SHIFT(reg, field))))
+
+#define PHM_GET_FIELD(value, reg, field) \
+ (((value) & PHM_FIELD_MASK(reg, field)) >> \
+ PHM_FIELD_SHIFT(reg, field))
+
+
+#define PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, index, value, mask) \
+ phm_wait_on_register(hwmgr, index, value, mask)
+
+#define PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, index, value, mask) \
+ phm_wait_for_register_unequal(hwmgr, index, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \
+ phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX, index, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \
+ phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX, index, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, index, value, mask) \
+ phm_wait_on_indirect_register(hwmgr, mm##port##_INDEX_0, index, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, index, value, mask) \
+ phm_wait_for_indirect_register_unequal(hwmgr, mm##port##_INDEX_0, index, value, mask)
+
+/* Operations on named registers. */
+
+#define PHM_WAIT_REGISTER(hwmgr, reg, value, mask) \
+ PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg, value, mask)
+
+#define PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, value, mask) \
+ PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \
+ PHM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+#define PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \
+ PHM_WAIT_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, value, mask) \
+ PHM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+#define PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, value, mask) \
+ PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, port, ix##reg, value, mask)
+
+/* Operations on named fields. */
+
+#define PHM_READ_FIELD(device, reg, field) \
+ PHM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field)
+
+#define PHM_READ_INDIRECT_FIELD(device, port, reg, field) \
+ PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+ reg, field)
+
+#define PHM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \
+ PHM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+ reg, field)
+
+#define PHM_WRITE_FIELD(device, reg, field, fieldval) \
+ cgs_write_register(device, mm##reg, PHM_SET_FIELD( \
+ cgs_read_register(device, mm##reg), reg, field, fieldval))
+
+#define PHM_WRITE_INDIRECT_FIELD(device, port, reg, field, fieldval) \
+ cgs_write_ind_register(device, port, ix##reg, \
+ PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+ reg, field, fieldval))
+
+#define PHM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval) \
+ cgs_write_ind_register(device, port, ix##reg, \
+ PHM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+ reg, field, fieldval))
+
+#define PHM_WAIT_FIELD(hwmgr, reg, field, fieldval) \
+ PHM_WAIT_REGISTER(hwmgr, reg, (fieldval) \
+ << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \
+ PHM_WAIT_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \
+ << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr, port, reg, field, fieldval) \
+ PHM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, port, reg, (fieldval) \
+ << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_FIELD_UNEQUAL(hwmgr, reg, field, fieldval) \
+ PHM_WAIT_REGISTER_UNEQUAL(hwmgr, reg, (fieldval) \
+ << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \
+ PHM_WAIT_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval) \
+ << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr, port, reg, field, fieldval) \
+ PHM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(hwmgr, port, reg, (fieldval) \
+ << PHM_FIELD_SHIFT(reg, field), PHM_FIELD_MASK(reg, field))
+
+/* Operations on arrays of registers & fields. */
+
+#define PHM_READ_ARRAY_REGISTER(device, reg, offset) \
+ cgs_read_register(device, mm##reg + (offset))
+
+#define PHM_WRITE_ARRAY_REGISTER(device, reg, offset, value) \
+ cgs_write_register(device, mm##reg + (offset), value)
+
+#define PHM_WAIT_ARRAY_REGISTER(hwmgr, reg, offset, value, mask) \
+ PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask)
+
+#define PHM_WAIT_ARRAY_REGISTER_UNEQUAL(hwmgr, reg, offset, value, mask) \
+ PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset), value, mask)
+
+#define PHM_READ_ARRAY_FIELD(hwmgr, reg, offset, field) \
+ PHM_GET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset), reg, field)
+
+#define PHM_WRITE_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue) \
+ PHM_WRITE_ARRAY_REGISTER(hwmgr->device, reg, offset, \
+ PHM_SET_FIELD(PHM_READ_ARRAY_REGISTER(hwmgr->device, reg, offset), \
+ reg, field, fieldvalue))
+
+#define PHM_WAIT_ARRAY_FIELD(hwmgr, reg, offset, field, fieldvalue) \
+ PHM_WAIT_REGISTER_GIVEN_INDEX(hwmgr, mm##reg + (offset), \
+ (fieldvalue) << PHM_FIELD_SHIFT(reg, field), \
+ PHM_FIELD_MASK(reg, field))
+
+#define PHM_WAIT_ARRAY_FIELD_UNEQUAL(hwmgr, reg, offset, field, fieldvalue) \
+ PHM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(hwmgr, mm##reg + (offset), \
+ (fieldvalue) << PHM_FIELD_SHIFT(reg, field), \
+ PHM_FIELD_MASK(reg, field))
+
+#endif /* _HWMGR_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/inc/power_state.h b/drivers/gpu/drm/amd/powerplay/inc/power_state.h
new file mode 100644
index 000000000000..a3f0ce4d5835
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/power_state.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2015 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 PP_POWERSTATE_H
+#define PP_POWERSTATE_H
+
+struct pp_hw_power_state {
+ unsigned int magic;
+};
+
+struct pp_power_state;
+
+
+#define PP_INVALID_POWER_STATE_ID (0)
+
+
+/*
+ * An item of a list containing Power States.
+ */
+
+struct PP_StateLinkedList {
+ struct pp_power_state *next;
+ struct pp_power_state *prev;
+};
+
+
+enum PP_StateUILabel {
+ PP_StateUILabel_None,
+ PP_StateUILabel_Battery,
+ PP_StateUILabel_MiddleLow,
+ PP_StateUILabel_Balanced,
+ PP_StateUILabel_MiddleHigh,
+ PP_StateUILabel_Performance,
+ PP_StateUILabel_BACO
+};
+
+enum PP_StateClassificationFlag {
+ PP_StateClassificationFlag_Boot = 0x0001,
+ PP_StateClassificationFlag_Thermal = 0x0002,
+ PP_StateClassificationFlag_LimitedPowerSource = 0x0004,
+ PP_StateClassificationFlag_Rest = 0x0008,
+ PP_StateClassificationFlag_Forced = 0x0010,
+ PP_StateClassificationFlag_User3DPerformance = 0x0020,
+ PP_StateClassificationFlag_User2DPerformance = 0x0040,
+ PP_StateClassificationFlag_3DPerformance = 0x0080,
+ PP_StateClassificationFlag_ACOverdriveTemplate = 0x0100,
+ PP_StateClassificationFlag_Uvd = 0x0200,
+ PP_StateClassificationFlag_3DPerformanceLow = 0x0400,
+ PP_StateClassificationFlag_ACPI = 0x0800,
+ PP_StateClassificationFlag_HD2 = 0x1000,
+ PP_StateClassificationFlag_UvdHD = 0x2000,
+ PP_StateClassificationFlag_UvdSD = 0x4000,
+ PP_StateClassificationFlag_UserDCPerformance = 0x8000,
+ PP_StateClassificationFlag_DCOverdriveTemplate = 0x10000,
+ PP_StateClassificationFlag_BACO = 0x20000,
+ PP_StateClassificationFlag_LimitedPowerSource_2 = 0x40000,
+ PP_StateClassificationFlag_ULV = 0x80000,
+ PP_StateClassificationFlag_UvdMVC = 0x100000,
+};
+
+typedef unsigned int PP_StateClassificationFlags;
+
+struct PP_StateClassificationBlock {
+ enum PP_StateUILabel ui_label;
+ enum PP_StateClassificationFlag flags;
+ int bios_index;
+ bool temporary_state;
+ bool to_be_deleted;
+};
+
+struct PP_StatePcieBlock {
+ unsigned int lanes;
+};
+
+enum PP_RefreshrateSource {
+ PP_RefreshrateSource_EDID,
+ PP_RefreshrateSource_Explicit
+};
+
+struct PP_StateDisplayBlock {
+ bool disableFrameModulation;
+ bool limitRefreshrate;
+ enum PP_RefreshrateSource refreshrateSource;
+ int explicitRefreshrate;
+ int edidRefreshrateIndex;
+ bool enableVariBright;
+};
+
+struct PP_StateMemroyBlock {
+ bool dllOff;
+ uint8_t m3arb;
+ uint8_t unused[3];
+};
+
+struct PP_StateSoftwareAlgorithmBlock {
+ bool disableLoadBalancing;
+ bool enableSleepForTimestamps;
+};
+
+#define PP_TEMPERATURE_UNITS_PER_CENTIGRADES 1000
+
+/**
+ * Type to hold a temperature range.
+ */
+struct PP_TemperatureRange {
+ uint32_t min;
+ uint32_t max;
+};
+
+struct PP_StateValidationBlock {
+ bool singleDisplayOnly;
+ bool disallowOnDC;
+ uint8_t supportedPowerLevels;
+};
+
+struct PP_UVD_CLOCKS {
+ uint32_t VCLK;
+ uint32_t DCLK;
+};
+
+/**
+* Structure to hold a PowerPlay Power State.
+*/
+struct pp_power_state {
+ uint32_t id;
+ struct PP_StateLinkedList orderedList;
+ struct PP_StateLinkedList allStatesList;
+
+ struct PP_StateClassificationBlock classification;
+ struct PP_StateValidationBlock validation;
+ struct PP_StatePcieBlock pcie;
+ struct PP_StateDisplayBlock display;
+ struct PP_StateMemroyBlock memory;
+ struct PP_TemperatureRange temperatures;
+ struct PP_StateSoftwareAlgorithmBlock software;
+ struct PP_UVD_CLOCKS uvd_clocks;
+ struct pp_hw_power_state hardware;
+};
+
+
+/*Structure to hold a VCE state entry*/
+struct PP_VCEState {
+ uint32_t evclk;
+ uint32_t ecclk;
+ uint32_t sclk;
+ uint32_t mclk;
+};
+
+enum PP_MMProfilingState {
+ PP_MMProfilingState_NA = 0,
+ PP_MMProfilingState_Started,
+ PP_MMProfilingState_Stopped
+};
+
+struct PP_Clock_Engine_Request {
+ unsigned long clientType;
+ unsigned long ctxid;
+ uint64_t context_handle;
+ unsigned long sclk;
+ unsigned long sclkHardMin;
+ unsigned long mclk;
+ unsigned long iclk;
+ unsigned long evclk;
+ unsigned long ecclk;
+ unsigned long ecclkHardMin;
+ unsigned long vclk;
+ unsigned long dclk;
+ unsigned long samclk;
+ unsigned long acpclk;
+ unsigned long sclkOverdrive;
+ unsigned long mclkOverdrive;
+ unsigned long sclk_threshold;
+ unsigned long flag;
+ unsigned long vclk_ceiling;
+ unsigned long dclk_ceiling;
+ unsigned long num_cus;
+ unsigned long pmflag;
+ enum PP_MMProfilingState MMProfilingState;
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h b/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h
new file mode 100644
index 000000000000..3bd5e69b9045
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 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.
+ *
+ */
+
+extern bool acpi_atcs_functions_supported(void *device,
+ uint32_t index);
+extern int acpi_pcie_perf_request(void *device,
+ uint8_t perf_req,
+ bool advertise);
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h b/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h
new file mode 100644
index 000000000000..0c1593e53654
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_asicblocks.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 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 PP_ASICBLOCKS_H
+#define PP_ASICBLOCKS_H
+
+
+enum PHM_AsicBlock {
+ PHM_AsicBlock_GFX,
+ PHM_AsicBlock_UVD_MVC,
+ PHM_AsicBlock_UVD,
+ PHM_AsicBlock_UVD_HD,
+ PHM_AsicBlock_UVD_SD,
+ PHM_AsicBlock_Count
+};
+
+enum PHM_ClockGateSetting {
+ PHM_ClockGateSetting_StaticOn,
+ PHM_ClockGateSetting_StaticOff,
+ PHM_ClockGateSetting_Dynamic
+};
+
+struct phm_asic_blocks {
+ bool gfx : 1;
+ bool uvd : 1;
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h b/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
new file mode 100644
index 000000000000..d7d83b7c7f95
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h
@@ -0,0 +1,47 @@
+
+/*
+ * Copyright 2015 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 PP_DEBUG_H
+#define PP_DEBUG_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#define PP_ASSERT_WITH_CODE(cond, msg, code) \
+ do { \
+ if (!(cond)) { \
+ printk("%s\n", msg); \
+ code; \
+ } \
+ } while (0)
+
+
+#define PP_DBG_LOG(fmt, ...) \
+ do { \
+ if(0)printk(KERN_INFO "[ pp_dbg ] " fmt, ##__VA_ARGS__); \
+ } while (0)
+
+
+#endif /* PP_DEBUG_H */
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h b/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h
new file mode 100644
index 000000000000..0faf6a25c18b
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 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 _PP_FEATURE_H_
+#define _PP_FEATURE_H_
+
+/**
+ * PowerPlay feature ids.
+ */
+enum pp_feature {
+ PP_Feature_PowerPlay = 0,
+ PP_Feature_User2DPerformance,
+ PP_Feature_User3DPerformance,
+ PP_Feature_VariBright,
+ PP_Feature_VariBrightOnPowerXpress,
+ PP_Feature_ReducedRefreshRate,
+ PP_Feature_GFXClockGating,
+ PP_Feature_OverdriveTest,
+ PP_Feature_OverDrive,
+ PP_Feature_PowerBudgetWaiver,
+ PP_Feature_PowerControl,
+ PP_Feature_PowerControl_2,
+ PP_Feature_MultiUVDState,
+ PP_Feature_Force3DClock,
+ PP_Feature_BACO,
+ PP_Feature_PowerDown,
+ PP_Feature_DynamicUVDState,
+ PP_Feature_VCEDPM,
+ PP_Feature_PPM,
+ PP_Feature_ACP_POWERGATING,
+ PP_Feature_FFC,
+ PP_Feature_FPS,
+ PP_Feature_ViPG,
+ PP_Feature_Max
+};
+
+/**
+ * Struct for PowerPlay feature info.
+ */
+struct pp_feature_info {
+ bool supported; /* feature supported by PowerPlay */
+ bool enabled; /* feature enabled in PowerPlay */
+ bool enabled_default; /* default enable status of the feature */
+ uint32_t version; /* feature version */
+};
+
+#endif /* _PP_FEATURE_H_ */
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
new file mode 100644
index 000000000000..4d8ed1f33de4
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 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 _PP_INSTANCE_H_
+#define _PP_INSTANCE_H_
+
+#include "smumgr.h"
+#include "hwmgr.h"
+#include "eventmgr.h"
+
+#define PP_VALID 0x1F1F1F1F
+
+struct pp_instance {
+ uint32_t pp_valid;
+ struct pp_smumgr *smu_mgr;
+ struct pp_hwmgr *hwmgr;
+ struct pp_eventmgr *eventmgr;
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h b/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h
new file mode 100644
index 000000000000..b43315cc5d58
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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 PP_POWERSOURCE_H
+#define PP_POWERSOURCE_H
+
+enum pp_power_source {
+ PP_PowerSource_AC = 0,
+ PP_PowerSource_DC,
+ PP_PowerSource_LimitedPower,
+ PP_PowerSource_LimitedPower_2,
+ PP_PowerSource_Max
+};
+
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h b/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h
new file mode 100644
index 000000000000..c067e0925b6b
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 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 _PP_INTERRUPT_H_
+#define _PP_INTERRUPT_H_
+
+enum amd_thermal_irq {
+ AMD_THERMAL_IRQ_LOW_TO_HIGH = 0,
+ AMD_THERMAL_IRQ_HIGH_TO_LOW,
+
+ AMD_THERMAL_IRQ_LAST
+};
+
+/* The type of the interrupt callback functions in PowerPlay */
+typedef int (*irq_handler_func_t)(void *private_data,
+ unsigned src_id, const uint32_t *iv_entry);
+
+/* Event Manager action chain list information */
+struct pp_interrupt_registration_info {
+ irq_handler_func_t call_back; /* Pointer to callback function */
+ void *context; /* Pointer to callback function context */
+ uint32_t src_id; /* Registered interrupt id */
+ const uint32_t *iv_entry;
+};
+
+#endif /* _PP_INTERRUPT_H_ */
diff --git a/drivers/gpu/drm/amd/amdgpu/smu7.h b/drivers/gpu/drm/amd/powerplay/inc/smu7.h
index 75a380a15292..75a380a15292 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu7.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu7.h
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu72.h b/drivers/gpu/drm/amd/powerplay/inc/smu72.h
new file mode 100644
index 000000000000..b73d6b59ac32
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu72.h
@@ -0,0 +1,664 @@
+#ifndef SMU72_H
+#define SMU72_H
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(push, 1)
+#endif
+
+#define SMU__NUM_SCLK_DPM_STATE 8
+#define SMU__NUM_MCLK_DPM_LEVELS 4
+#define SMU__NUM_LCLK_DPM_LEVELS 8
+#define SMU__NUM_PCIE_DPM_LEVELS 8
+
+enum SID_OPTION {
+ SID_OPTION_HI,
+ SID_OPTION_LO,
+ SID_OPTION_COUNT
+};
+
+enum Poly3rdOrderCoeff {
+ LEAKAGE_TEMPERATURE_SCALAR,
+ LEAKAGE_VOLTAGE_SCALAR,
+ DYNAMIC_VOLTAGE_SCALAR,
+ POLY_3RD_ORDER_COUNT
+};
+
+struct SMU7_Poly3rdOrder_Data {
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+ uint8_t a_shift;
+ uint8_t b_shift;
+ uint8_t c_shift;
+ uint8_t x_shift;
+};
+
+typedef struct SMU7_Poly3rdOrder_Data SMU7_Poly3rdOrder_Data;
+
+struct Power_Calculator_Data {
+ uint16_t NoLoadVoltage;
+ uint16_t LoadVoltage;
+ uint16_t Resistance;
+ uint16_t Temperature;
+ uint16_t BaseLeakage;
+ uint16_t LkgTempScalar;
+ uint16_t LkgVoltScalar;
+ uint16_t LkgAreaScalar;
+ uint16_t LkgPower;
+ uint16_t DynVoltScalar;
+ uint32_t Cac;
+ uint32_t DynPower;
+ uint32_t TotalCurrent;
+ uint32_t TotalPower;
+};
+
+typedef struct Power_Calculator_Data PowerCalculatorData_t;
+
+struct Gc_Cac_Weight_Data {
+ uint8_t index;
+ uint32_t value;
+};
+
+typedef struct Gc_Cac_Weight_Data GcCacWeight_Data;
+
+
+typedef struct {
+ uint32_t high;
+ uint32_t low;
+} data_64_t;
+
+typedef struct {
+ data_64_t high;
+ data_64_t low;
+} data_128_t;
+
+#define SMU7_CONTEXT_ID_SMC 1
+#define SMU7_CONTEXT_ID_VBIOS 2
+
+#define SMU72_MAX_LEVELS_VDDC 16
+#define SMU72_MAX_LEVELS_VDDGFX 16
+#define SMU72_MAX_LEVELS_VDDCI 8
+#define SMU72_MAX_LEVELS_MVDD 4
+
+#define SMU_MAX_SMIO_LEVELS 4
+
+#define SMU72_MAX_LEVELS_GRAPHICS SMU__NUM_SCLK_DPM_STATE /* SCLK + SQ DPM + ULV */
+#define SMU72_MAX_LEVELS_MEMORY SMU__NUM_MCLK_DPM_LEVELS /* MCLK Levels DPM */
+#define SMU72_MAX_LEVELS_GIO SMU__NUM_LCLK_DPM_LEVELS /* LCLK Levels */
+#define SMU72_MAX_LEVELS_LINK SMU__NUM_PCIE_DPM_LEVELS /* PCIe speed and number of lanes. */
+#define SMU72_MAX_LEVELS_UVD 8 /* VCLK/DCLK levels for UVD. */
+#define SMU72_MAX_LEVELS_VCE 8 /* ECLK levels for VCE. */
+#define SMU72_MAX_LEVELS_ACP 8 /* ACLK levels for ACP. */
+#define SMU72_MAX_LEVELS_SAMU 8 /* SAMCLK levels for SAMU. */
+#define SMU72_MAX_ENTRIES_SMIO 32 /* Number of entries in SMIO table. */
+
+#define DPM_NO_LIMIT 0
+#define DPM_NO_UP 1
+#define DPM_GO_DOWN 2
+#define DPM_GO_UP 3
+
+#define SMU7_FIRST_DPM_GRAPHICS_LEVEL 0
+#define SMU7_FIRST_DPM_MEMORY_LEVEL 0
+
+#define GPIO_CLAMP_MODE_VRHOT 1
+#define GPIO_CLAMP_MODE_THERM 2
+#define GPIO_CLAMP_MODE_DC 4
+
+#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0
+#define SCRATCH_B_TARG_PCIE_INDEX_MASK (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3
+#define SCRATCH_B_CURR_PCIE_INDEX_MASK (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_UVD_INDEX_SHIFT 6
+#define SCRATCH_B_TARG_UVD_INDEX_MASK (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT)
+#define SCRATCH_B_CURR_UVD_INDEX_SHIFT 9
+#define SCRATCH_B_CURR_UVD_INDEX_MASK (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT)
+#define SCRATCH_B_TARG_VCE_INDEX_SHIFT 12
+#define SCRATCH_B_TARG_VCE_INDEX_MASK (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_VCE_INDEX_SHIFT 15
+#define SCRATCH_B_CURR_VCE_INDEX_MASK (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_ACP_INDEX_SHIFT 18
+#define SCRATCH_B_TARG_ACP_INDEX_MASK (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT)
+#define SCRATCH_B_CURR_ACP_INDEX_SHIFT 21
+#define SCRATCH_B_CURR_ACP_INDEX_MASK (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT)
+#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24
+#define SCRATCH_B_TARG_SAMU_INDEX_MASK (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT)
+#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27
+#define SCRATCH_B_CURR_SAMU_INDEX_MASK (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT)
+
+/* Virtualization Defines */
+#define CG_XDMA_MASK 0x1
+#define CG_XDMA_SHIFT 0
+#define CG_UVD_MASK 0x2
+#define CG_UVD_SHIFT 1
+#define CG_VCE_MASK 0x4
+#define CG_VCE_SHIFT 2
+#define CG_SAMU_MASK 0x8
+#define CG_SAMU_SHIFT 3
+#define CG_GFX_MASK 0x10
+#define CG_GFX_SHIFT 4
+#define CG_SDMA_MASK 0x20
+#define CG_SDMA_SHIFT 5
+#define CG_HDP_MASK 0x40
+#define CG_HDP_SHIFT 6
+#define CG_MC_MASK 0x80
+#define CG_MC_SHIFT 7
+#define CG_DRM_MASK 0x100
+#define CG_DRM_SHIFT 8
+#define CG_ROM_MASK 0x200
+#define CG_ROM_SHIFT 9
+#define CG_BIF_MASK 0x400
+#define CG_BIF_SHIFT 10
+
+#define SMU72_DTE_ITERATIONS 5
+#define SMU72_DTE_SOURCES 3
+#define SMU72_DTE_SINKS 1
+#define SMU72_NUM_CPU_TES 0
+#define SMU72_NUM_GPU_TES 1
+#define SMU72_NUM_NON_TES 2
+#define SMU72_DTE_FAN_SCALAR_MIN 0x100
+#define SMU72_DTE_FAN_SCALAR_MAX 0x166
+#define SMU72_DTE_FAN_TEMP_MAX 93
+#define SMU72_DTE_FAN_TEMP_MIN 83
+
+#if defined SMU__FUSION_ONLY
+#define SMU7_DTE_ITERATIONS 5
+#define SMU7_DTE_SOURCES 5
+#define SMU7_DTE_SINKS 3
+#define SMU7_NUM_CPU_TES 2
+#define SMU7_NUM_GPU_TES 1
+#define SMU7_NUM_NON_TES 2
+#endif
+
+struct SMU7_HystController_Data {
+ uint8_t waterfall_up;
+ uint8_t waterfall_down;
+ uint8_t waterfall_limit;
+ uint8_t spare;
+ uint16_t release_cnt;
+ uint16_t release_limit;
+};
+
+typedef struct SMU7_HystController_Data SMU7_HystController_Data;
+
+struct SMU72_PIDController {
+ uint32_t Ki;
+ int32_t LFWindupUpperLim;
+ int32_t LFWindupLowerLim;
+ uint32_t StatePrecision;
+ uint32_t LfPrecision;
+ uint32_t LfOffset;
+ uint32_t MaxState;
+ uint32_t MaxLfFraction;
+ uint32_t StateShift;
+};
+
+typedef struct SMU72_PIDController SMU72_PIDController;
+
+struct SMU7_LocalDpmScoreboard {
+ uint32_t PercentageBusy;
+
+ int32_t PIDError;
+ int32_t PIDIntegral;
+ int32_t PIDOutput;
+
+ uint32_t SigmaDeltaAccum;
+ uint32_t SigmaDeltaOutput;
+ uint32_t SigmaDeltaLevel;
+
+ uint32_t UtilizationSetpoint;
+
+ uint8_t TdpClampMode;
+ uint8_t TdcClampMode;
+ uint8_t ThermClampMode;
+ uint8_t VoltageBusy;
+
+ int8_t CurrLevel;
+ int8_t TargLevel;
+ uint8_t LevelChangeInProgress;
+ uint8_t UpHyst;
+
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t DpmEnable;
+ uint8_t DpmRunning;
+
+ uint8_t DpmForce;
+ uint8_t DpmForceLevel;
+ uint8_t DisplayWatermark;
+ uint8_t McArbIndex;
+
+ uint32_t MinimumPerfSclk;
+
+ uint8_t AcpiReq;
+ uint8_t AcpiAck;
+ uint8_t GfxClkSlow;
+ uint8_t GpioClampMode; /* bit0 = VRHOT: bit1 = THERM: bit2 = DC */
+
+ uint8_t FpsFilterWeight;
+ uint8_t EnabledLevelsChange;
+ uint8_t DteClampMode;
+ uint8_t FpsClampMode;
+
+ uint16_t LevelResidencyCounters[SMU72_MAX_LEVELS_GRAPHICS];
+ uint16_t LevelSwitchCounters[SMU72_MAX_LEVELS_GRAPHICS];
+
+ void (*TargetStateCalculator)(uint8_t);
+ void (*SavedTargetStateCalculator)(uint8_t);
+
+ uint16_t AutoDpmInterval;
+ uint16_t AutoDpmRange;
+
+ uint8_t FpsEnabled;
+ uint8_t MaxPerfLevel;
+ uint8_t AllowLowClkInterruptToHost;
+ uint8_t FpsRunning;
+
+ uint32_t MaxAllowedFrequency;
+
+ uint32_t FilteredSclkFrequency;
+ uint32_t LastSclkFrequency;
+ uint32_t FilteredSclkFrequencyCnt;
+};
+
+typedef struct SMU7_LocalDpmScoreboard SMU7_LocalDpmScoreboard;
+
+#define SMU7_MAX_VOLTAGE_CLIENTS 12
+
+typedef uint8_t (*VoltageChangeHandler_t)(uint16_t, uint8_t);
+
+struct SMU_VoltageLevel {
+ uint8_t Vddc;
+ uint8_t Vddci;
+ uint8_t VddGfx;
+ uint8_t Phases;
+};
+
+typedef struct SMU_VoltageLevel SMU_VoltageLevel;
+
+struct SMU7_VoltageScoreboard {
+ SMU_VoltageLevel CurrentVoltage;
+ SMU_VoltageLevel TargetVoltage;
+ uint16_t MaxVid;
+ uint8_t HighestVidOffset;
+ uint8_t CurrentVidOffset;
+
+ uint8_t ControllerBusy;
+ uint8_t CurrentVid;
+ uint8_t CurrentVddciVid;
+ uint8_t VddGfxShutdown; /* 0 = normal mode, 1 = shut down */
+
+ SMU_VoltageLevel RequestedVoltage[SMU7_MAX_VOLTAGE_CLIENTS];
+ uint8_t EnabledRequest[SMU7_MAX_VOLTAGE_CLIENTS];
+
+ uint8_t TargetIndex;
+ uint8_t Delay;
+ uint8_t ControllerEnable;
+ uint8_t ControllerRunning;
+ uint16_t CurrentStdVoltageHiSidd;
+ uint16_t CurrentStdVoltageLoSidd;
+ uint8_t OverrideVoltage;
+ uint8_t VddcUseUlvOffset;
+ uint8_t VddGfxUseUlvOffset;
+ uint8_t padding;
+
+ VoltageChangeHandler_t ChangeVddc;
+ VoltageChangeHandler_t ChangeVddGfx;
+ VoltageChangeHandler_t ChangeVddci;
+ VoltageChangeHandler_t ChangePhase;
+ VoltageChangeHandler_t ChangeMvdd;
+
+ VoltageChangeHandler_t functionLinks[6];
+
+ uint8_t *VddcFollower1;
+ uint8_t *VddcFollower2;
+ int16_t Driver_OD_RequestedVidOffset1;
+ int16_t Driver_OD_RequestedVidOffset2;
+
+};
+
+typedef struct SMU7_VoltageScoreboard SMU7_VoltageScoreboard;
+
+#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */
+
+struct SMU7_PCIeLinkSpeedScoreboard {
+ uint8_t DpmEnable;
+ uint8_t DpmRunning;
+ uint8_t DpmForce;
+ uint8_t DpmForceLevel;
+
+ uint8_t CurrentLinkSpeed;
+ uint8_t EnabledLevelsChange;
+ uint16_t AutoDpmInterval;
+
+ uint16_t AutoDpmRange;
+ uint16_t AutoDpmCount;
+
+ uint8_t DpmMode;
+ uint8_t AcpiReq;
+ uint8_t AcpiAck;
+ uint8_t CurrentLinkLevel;
+
+};
+
+typedef struct SMU7_PCIeLinkSpeedScoreboard SMU7_PCIeLinkSpeedScoreboard;
+
+/* -------------------------------------------------------- CAC table ------------------------------------------------------ */
+#define SMU7_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMU7_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+#define SMU7_SCALE_I 7
+#define SMU7_SCALE_R 12
+
+struct SMU7_PowerScoreboard {
+ PowerCalculatorData_t VddGfxPowerData[SID_OPTION_COUNT];
+ PowerCalculatorData_t VddcPowerData[SID_OPTION_COUNT];
+
+ uint32_t TotalGpuPower;
+ uint32_t TdcCurrent;
+
+ uint16_t VddciTotalPower;
+ uint16_t sparesasfsdfd;
+ uint16_t Vddr1Power;
+ uint16_t RocPower;
+
+ uint16_t CalcMeasPowerBlend;
+ uint8_t SidOptionPower;
+ uint8_t SidOptionCurrent;
+
+ uint32_t WinTime;
+
+ uint16_t Telemetry_1_slope;
+ uint16_t Telemetry_2_slope;
+ int32_t Telemetry_1_offset;
+ int32_t Telemetry_2_offset;
+
+ uint32_t VddcCurrentTelemetry;
+ uint32_t VddGfxCurrentTelemetry;
+ uint32_t VddcPowerTelemetry;
+ uint32_t VddGfxPowerTelemetry;
+ uint32_t VddciPowerTelemetry;
+
+ uint32_t VddcPower;
+ uint32_t VddGfxPower;
+ uint32_t VddciPower;
+
+ uint32_t TelemetryCurrent[2];
+ uint32_t TelemetryVoltage[2];
+ uint32_t TelemetryPower[2];
+};
+
+typedef struct SMU7_PowerScoreboard SMU7_PowerScoreboard;
+
+struct SMU7_ThermalScoreboard {
+ int16_t GpuLimit;
+ int16_t GpuHyst;
+ uint16_t CurrGnbTemp;
+ uint16_t FilteredGnbTemp;
+
+ uint8_t ControllerEnable;
+ uint8_t ControllerRunning;
+ uint8_t AutoTmonCalInterval;
+ uint8_t AutoTmonCalEnable;
+
+ uint8_t ThermalDpmEnabled;
+ uint8_t SclkEnabledMask;
+ uint8_t spare[2];
+ int32_t temperature_gradient;
+
+ SMU7_HystController_Data HystControllerData;
+ int32_t WeightedSensorTemperature;
+ uint16_t TemperatureLimit[SMU72_MAX_LEVELS_GRAPHICS];
+ uint32_t Alpha;
+};
+
+typedef struct SMU7_ThermalScoreboard SMU7_ThermalScoreboard;
+
+/* For FeatureEnables: */
+#define SMU7_SCLK_DPM_CONFIG_MASK 0x01
+#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK 0x02
+#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK 0x04
+#define SMU7_MCLK_DPM_CONFIG_MASK 0x08
+#define SMU7_UVD_DPM_CONFIG_MASK 0x10
+#define SMU7_VCE_DPM_CONFIG_MASK 0x20
+#define SMU7_ACP_DPM_CONFIG_MASK 0x40
+#define SMU7_SAMU_DPM_CONFIG_MASK 0x80
+#define SMU7_PCIEGEN_DPM_CONFIG_MASK 0x100
+
+#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE 0x00000001
+#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE 0x00000002
+#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE 0x00000100
+#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE 0x00000200
+#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE 0x00010000
+#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE 0x00020000
+
+/* All 'soft registers' should be uint32_t. */
+struct SMU72_SoftRegisters {
+ uint32_t RefClockFrequency;
+ uint32_t PmTimerPeriod;
+ uint32_t FeatureEnables;
+
+ uint32_t PreVBlankGap;
+ uint32_t VBlankTimeout;
+ uint32_t TrainTimeGap;
+
+ uint32_t MvddSwitchTime;
+ uint32_t LongestAcpiTrainTime;
+ uint32_t AcpiDelay;
+ uint32_t G5TrainTime;
+ uint32_t DelayMpllPwron;
+ uint32_t VoltageChangeTimeout;
+
+ uint32_t HandshakeDisables;
+
+ uint8_t DisplayPhy1Config;
+ uint8_t DisplayPhy2Config;
+ uint8_t DisplayPhy3Config;
+ uint8_t DisplayPhy4Config;
+
+ uint8_t DisplayPhy5Config;
+ uint8_t DisplayPhy6Config;
+ uint8_t DisplayPhy7Config;
+ uint8_t DisplayPhy8Config;
+
+ uint32_t AverageGraphicsActivity;
+ uint32_t AverageMemoryActivity;
+ uint32_t AverageGioActivity;
+
+ uint8_t SClkDpmEnabledLevels;
+ uint8_t MClkDpmEnabledLevels;
+ uint8_t LClkDpmEnabledLevels;
+ uint8_t PCIeDpmEnabledLevels;
+
+ uint8_t UVDDpmEnabledLevels;
+ uint8_t SAMUDpmEnabledLevels;
+ uint8_t ACPDpmEnabledLevels;
+ uint8_t VCEDpmEnabledLevels;
+
+ uint32_t DRAM_LOG_ADDR_H;
+ uint32_t DRAM_LOG_ADDR_L;
+ uint32_t DRAM_LOG_PHY_ADDR_H;
+ uint32_t DRAM_LOG_PHY_ADDR_L;
+ uint32_t DRAM_LOG_BUFF_SIZE;
+ uint32_t UlvEnterCount;
+ uint32_t UlvTime;
+ uint32_t UcodeLoadStatus;
+ uint32_t Reserved[2];
+
+};
+
+typedef struct SMU72_SoftRegisters SMU72_SoftRegisters;
+
+struct SMU72_Firmware_Header {
+ uint32_t Digest[5];
+ uint32_t Version;
+ uint32_t HeaderSize;
+ uint32_t Flags;
+ uint32_t EntryPoint;
+ uint32_t CodeSize;
+ uint32_t ImageSize;
+
+ uint32_t Rtos;
+ uint32_t SoftRegisters;
+ uint32_t DpmTable;
+ uint32_t FanTable;
+ uint32_t CacConfigTable;
+ uint32_t CacStatusTable;
+ uint32_t mcRegisterTable;
+ uint32_t mcArbDramTimingTable;
+ uint32_t PmFuseTable;
+ uint32_t Globals;
+ uint32_t ClockStretcherTable;
+ uint32_t Reserved[41];
+ uint32_t Signature;
+};
+
+typedef struct SMU72_Firmware_Header SMU72_Firmware_Header;
+
+#define SMU72_FIRMWARE_HEADER_LOCATION 0x20000
+
+enum DisplayConfig {
+ PowerDown = 1,
+ DP54x4,
+ DP54x2,
+ DP54x1,
+ DP27x4,
+ DP27x2,
+ DP27x1,
+ HDMI297,
+ HDMI162,
+ LVDS,
+ DP324x4,
+ DP324x2,
+ DP324x1
+};
+
+#define MC_BLOCK_COUNT 1
+#define CPL_BLOCK_COUNT 5
+#define SE_BLOCK_COUNT 15
+#define GC_BLOCK_COUNT 24
+
+struct SMU7_Local_Cac {
+ uint8_t BlockId;
+ uint8_t SignalId;
+ uint8_t Threshold;
+ uint8_t Padding;
+};
+
+typedef struct SMU7_Local_Cac SMU7_Local_Cac;
+
+struct SMU7_Local_Cac_Table {
+ SMU7_Local_Cac CplLocalCac[CPL_BLOCK_COUNT];
+ SMU7_Local_Cac McLocalCac[MC_BLOCK_COUNT];
+ SMU7_Local_Cac SeLocalCac[SE_BLOCK_COUNT];
+ SMU7_Local_Cac GcLocalCac[GC_BLOCK_COUNT];
+};
+
+typedef struct SMU7_Local_Cac_Table SMU7_Local_Cac_Table;
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+/* Description of Clock Gating bitmask for Tonga: */
+/* System Clock Gating */
+#define CG_SYS_BITMASK_FIRST_BIT 0 /* First bit of Sys CG bitmask */
+#define CG_SYS_BITMASK_LAST_BIT 9 /* Last bit of Sys CG bitmask */
+#define CG_SYS_BIF_MGLS_SHIFT 0
+#define CG_SYS_ROM_SHIFT 1
+#define CG_SYS_MC_MGCG_SHIFT 2
+#define CG_SYS_MC_MGLS_SHIFT 3
+#define CG_SYS_SDMA_MGCG_SHIFT 4
+#define CG_SYS_SDMA_MGLS_SHIFT 5
+#define CG_SYS_DRM_MGCG_SHIFT 6
+#define CG_SYS_HDP_MGCG_SHIFT 7
+#define CG_SYS_HDP_MGLS_SHIFT 8
+#define CG_SYS_DRM_MGLS_SHIFT 9
+
+#define CG_SYS_BIF_MGLS_MASK 0x1
+#define CG_SYS_ROM_MASK 0x2
+#define CG_SYS_MC_MGCG_MASK 0x4
+#define CG_SYS_MC_MGLS_MASK 0x8
+#define CG_SYS_SDMA_MGCG_MASK 0x10
+#define CG_SYS_SDMA_MGLS_MASK 0x20
+#define CG_SYS_DRM_MGCG_MASK 0x40
+#define CG_SYS_HDP_MGCG_MASK 0x80
+#define CG_SYS_HDP_MGLS_MASK 0x100
+#define CG_SYS_DRM_MGLS_MASK 0x200
+
+/* Graphics Clock Gating */
+#define CG_GFX_BITMASK_FIRST_BIT 16 /* First bit of Gfx CG bitmask */
+#define CG_GFX_BITMASK_LAST_BIT 20 /* Last bit of Gfx CG bitmask */
+#define CG_GFX_CGCG_SHIFT 16
+#define CG_GFX_CGLS_SHIFT 17
+#define CG_CPF_MGCG_SHIFT 18
+#define CG_RLC_MGCG_SHIFT 19
+#define CG_GFX_OTHERS_MGCG_SHIFT 20
+
+#define CG_GFX_CGCG_MASK 0x00010000
+#define CG_GFX_CGLS_MASK 0x00020000
+#define CG_CPF_MGCG_MASK 0x00040000
+#define CG_RLC_MGCG_MASK 0x00080000
+#define CG_GFX_OTHERS_MGCG_MASK 0x00100000
+
+/* Voltage Regulator Configuration */
+/* VR Config info is contained in dpmTable.VRConfig */
+
+#define VRCONF_VDDC_MASK 0x000000FF
+#define VRCONF_VDDC_SHIFT 0
+#define VRCONF_VDDGFX_MASK 0x0000FF00
+#define VRCONF_VDDGFX_SHIFT 8
+#define VRCONF_VDDCI_MASK 0x00FF0000
+#define VRCONF_VDDCI_SHIFT 16
+#define VRCONF_MVDD_MASK 0xFF000000
+#define VRCONF_MVDD_SHIFT 24
+
+#define VR_MERGED_WITH_VDDC 0
+#define VR_SVI2_PLANE_1 1
+#define VR_SVI2_PLANE_2 2
+#define VR_SMIO_PATTERN_1 3
+#define VR_SMIO_PATTERN_2 4
+#define VR_STATIC_VOLTAGE 5
+
+/* Clock Stretcher Configuration */
+
+#define CLOCK_STRETCHER_MAX_ENTRIES 0x4
+#define CKS_LOOKUPTable_MAX_ENTRIES 0x4
+
+/* The 'settings' field is subdivided in the following way: */
+#define CLOCK_STRETCHER_SETTING_DDT_MASK 0x01
+#define CLOCK_STRETCHER_SETTING_DDT_SHIFT 0x0
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_MASK 0x1E
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_SHIFT 0x1
+#define CLOCK_STRETCHER_SETTING_ENABLE_MASK 0x80
+#define CLOCK_STRETCHER_SETTING_ENABLE_SHIFT 0x7
+
+struct SMU_ClockStretcherDataTableEntry {
+ uint8_t minVID;
+ uint8_t maxVID;
+
+ uint16_t setting;
+};
+typedef struct SMU_ClockStretcherDataTableEntry SMU_ClockStretcherDataTableEntry;
+
+struct SMU_ClockStretcherDataTable {
+ SMU_ClockStretcherDataTableEntry ClockStretcherDataTableEntry[CLOCK_STRETCHER_MAX_ENTRIES];
+};
+typedef struct SMU_ClockStretcherDataTable SMU_ClockStretcherDataTable;
+
+struct SMU_CKS_LOOKUPTableEntry {
+ uint16_t minFreq;
+ uint16_t maxFreq;
+
+ uint8_t setting;
+ uint8_t padding[3];
+};
+typedef struct SMU_CKS_LOOKUPTableEntry SMU_CKS_LOOKUPTableEntry;
+
+struct SMU_CKS_LOOKUPTable {
+ SMU_CKS_LOOKUPTableEntry CKS_LOOKUPTableEntry[CKS_LOOKUPTable_MAX_ENTRIES];
+};
+typedef struct SMU_CKS_LOOKUPTable SMU_CKS_LOOKUPTable;
+
+#endif
+
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h b/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h
new file mode 100644
index 000000000000..98f76e925e65
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h
@@ -0,0 +1,760 @@
+#ifndef SMU72_DISCRETE_H
+#define SMU72_DISCRETE_H
+
+#include "smu72.h"
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(push, 1)
+#endif
+
+struct SMIO_Pattern {
+ uint16_t Voltage;
+ uint8_t Smio;
+ uint8_t padding;
+};
+
+typedef struct SMIO_Pattern SMIO_Pattern;
+
+struct SMIO_Table {
+ SMIO_Pattern Pattern[SMU_MAX_SMIO_LEVELS];
+};
+
+typedef struct SMIO_Table SMIO_Table;
+
+struct SMU72_Discrete_GraphicsLevel {
+ SMU_VoltageLevel MinVoltage;
+
+ uint32_t SclkFrequency;
+
+ uint8_t pcieDpmLevel;
+ uint8_t DeepSleepDivId;
+ uint16_t ActivityLevel;
+
+ uint32_t CgSpllFuncCntl3;
+ uint32_t CgSpllFuncCntl4;
+ uint32_t SpllSpreadSpectrum;
+ uint32_t SpllSpreadSpectrum2;
+ uint32_t CcPwrDynRm;
+ uint32_t CcPwrDynRm1;
+ uint8_t SclkDid;
+ uint8_t DisplayWatermark;
+ uint8_t EnabledForActivity;
+ uint8_t EnabledForThrottle;
+ uint8_t UpHyst;
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t PowerThrottle;
+};
+
+typedef struct SMU72_Discrete_GraphicsLevel SMU72_Discrete_GraphicsLevel;
+
+struct SMU72_Discrete_ACPILevel {
+ uint32_t Flags;
+ SMU_VoltageLevel MinVoltage;
+ uint32_t SclkFrequency;
+ uint8_t SclkDid;
+ uint8_t DisplayWatermark;
+ uint8_t DeepSleepDivId;
+ uint8_t padding;
+ uint32_t CgSpllFuncCntl;
+ uint32_t CgSpllFuncCntl2;
+ uint32_t CgSpllFuncCntl3;
+ uint32_t CgSpllFuncCntl4;
+ uint32_t SpllSpreadSpectrum;
+ uint32_t SpllSpreadSpectrum2;
+ uint32_t CcPwrDynRm;
+ uint32_t CcPwrDynRm1;
+};
+
+typedef struct SMU72_Discrete_ACPILevel SMU72_Discrete_ACPILevel;
+
+struct SMU72_Discrete_Ulv {
+ uint32_t CcPwrDynRm;
+ uint32_t CcPwrDynRm1;
+ uint16_t VddcOffset;
+ uint8_t VddcOffsetVid;
+ uint8_t VddcPhase;
+ uint32_t Reserved;
+};
+
+typedef struct SMU72_Discrete_Ulv SMU72_Discrete_Ulv;
+
+struct SMU72_Discrete_MemoryLevel {
+ SMU_VoltageLevel MinVoltage;
+ uint32_t MinMvdd;
+
+ uint32_t MclkFrequency;
+
+ uint8_t EdcReadEnable;
+ uint8_t EdcWriteEnable;
+ uint8_t RttEnable;
+ uint8_t StutterEnable;
+
+ uint8_t StrobeEnable;
+ uint8_t StrobeRatio;
+ uint8_t EnabledForThrottle;
+ uint8_t EnabledForActivity;
+
+ uint8_t UpHyst;
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t padding;
+
+ uint16_t ActivityLevel;
+ uint8_t DisplayWatermark;
+ uint8_t padding1;
+
+ uint32_t MpllFuncCntl;
+ uint32_t MpllFuncCntl_1;
+ uint32_t MpllFuncCntl_2;
+ uint32_t MpllAdFuncCntl;
+ uint32_t MpllDqFuncCntl;
+ uint32_t MclkPwrmgtCntl;
+ uint32_t DllCntl;
+ uint32_t MpllSs1;
+ uint32_t MpllSs2;
+};
+
+typedef struct SMU72_Discrete_MemoryLevel SMU72_Discrete_MemoryLevel;
+
+struct SMU72_Discrete_LinkLevel {
+ uint8_t PcieGenSpeed; /*< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3 */
+ uint8_t PcieLaneCount; /*< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16 */
+ uint8_t EnabledForActivity;
+ uint8_t SPC;
+ uint32_t DownThreshold;
+ uint32_t UpThreshold;
+ uint32_t Reserved;
+};
+
+typedef struct SMU72_Discrete_LinkLevel SMU72_Discrete_LinkLevel;
+
+/* MC ARB DRAM Timing registers. */
+struct SMU72_Discrete_MCArbDramTimingTableEntry {
+ uint32_t McArbDramTiming;
+ uint32_t McArbDramTiming2;
+ uint8_t McArbBurstTime;
+ uint8_t padding[3];
+};
+
+typedef struct SMU72_Discrete_MCArbDramTimingTableEntry SMU72_Discrete_MCArbDramTimingTableEntry;
+
+struct SMU72_Discrete_MCArbDramTimingTable {
+ SMU72_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS];
+};
+
+typedef struct SMU72_Discrete_MCArbDramTimingTable SMU72_Discrete_MCArbDramTimingTable;
+
+/* UVD VCLK/DCLK state (level) definition. */
+struct SMU72_Discrete_UvdLevel {
+ uint32_t VclkFrequency;
+ uint32_t DclkFrequency;
+ SMU_VoltageLevel MinVoltage;
+ uint8_t VclkDivider;
+ uint8_t DclkDivider;
+ uint8_t padding[2];
+};
+
+typedef struct SMU72_Discrete_UvdLevel SMU72_Discrete_UvdLevel;
+
+/* Clocks for other external blocks (VCE, ACP, SAMU). */
+struct SMU72_Discrete_ExtClkLevel {
+ uint32_t Frequency;
+ SMU_VoltageLevel MinVoltage;
+ uint8_t Divider;
+ uint8_t padding[3];
+};
+
+typedef struct SMU72_Discrete_ExtClkLevel SMU72_Discrete_ExtClkLevel;
+
+struct SMU72_Discrete_StateInfo {
+ uint32_t SclkFrequency;
+ uint32_t MclkFrequency;
+ uint32_t VclkFrequency;
+ uint32_t DclkFrequency;
+ uint32_t SamclkFrequency;
+ uint32_t AclkFrequency;
+ uint32_t EclkFrequency;
+ uint16_t MvddVoltage;
+ uint16_t padding16;
+ uint8_t DisplayWatermark;
+ uint8_t McArbIndex;
+ uint8_t McRegIndex;
+ uint8_t SeqIndex;
+ uint8_t SclkDid;
+ int8_t SclkIndex;
+ int8_t MclkIndex;
+ uint8_t PCIeGen;
+
+};
+
+typedef struct SMU72_Discrete_StateInfo SMU72_Discrete_StateInfo;
+
+struct SMU72_Discrete_DpmTable {
+ /* Multi-DPM controller settings */
+ SMU72_PIDController GraphicsPIDController;
+ SMU72_PIDController MemoryPIDController;
+ SMU72_PIDController LinkPIDController;
+
+ uint32_t SystemFlags;
+
+ /* SMIO masks for voltage and phase controls */
+ uint32_t VRConfig;
+ uint32_t SmioMask1;
+ uint32_t SmioMask2;
+ SMIO_Table SmioTable1;
+ SMIO_Table SmioTable2;
+
+ uint32_t VddcLevelCount;
+ uint32_t VddciLevelCount;
+ uint32_t VddGfxLevelCount;
+ uint32_t MvddLevelCount;
+
+ uint16_t VddcTable[SMU72_MAX_LEVELS_VDDC];
+ uint16_t VddGfxTable[SMU72_MAX_LEVELS_VDDGFX];
+ uint16_t VddciTable[SMU72_MAX_LEVELS_VDDCI];
+
+ uint8_t BapmVddGfxVidHiSidd[SMU72_MAX_LEVELS_VDDGFX];
+ uint8_t BapmVddGfxVidLoSidd[SMU72_MAX_LEVELS_VDDGFX];
+ uint8_t BapmVddGfxVidHiSidd2[SMU72_MAX_LEVELS_VDDGFX];
+
+ uint8_t BapmVddcVidHiSidd[SMU72_MAX_LEVELS_VDDC];
+ uint8_t BapmVddcVidLoSidd[SMU72_MAX_LEVELS_VDDC];
+ uint8_t BapmVddcVidHiSidd2[SMU72_MAX_LEVELS_VDDC];
+
+ uint8_t GraphicsDpmLevelCount;
+ uint8_t MemoryDpmLevelCount;
+ uint8_t LinkLevelCount;
+ uint8_t MasterDeepSleepControl;
+
+ uint8_t UvdLevelCount;
+ uint8_t VceLevelCount;
+ uint8_t AcpLevelCount;
+ uint8_t SamuLevelCount;
+
+ uint8_t ThermOutGpio;
+ uint8_t ThermOutPolarity;
+ uint8_t ThermOutMode;
+ uint8_t DPMFreezeAndForced;
+ uint32_t Reserved[4];
+
+ /* State table entries for each DPM state */
+ SMU72_Discrete_GraphicsLevel GraphicsLevel[SMU72_MAX_LEVELS_GRAPHICS];
+ SMU72_Discrete_MemoryLevel MemoryACPILevel;
+ SMU72_Discrete_MemoryLevel MemoryLevel[SMU72_MAX_LEVELS_MEMORY];
+ SMU72_Discrete_LinkLevel LinkLevel[SMU72_MAX_LEVELS_LINK];
+ SMU72_Discrete_ACPILevel ACPILevel;
+ SMU72_Discrete_UvdLevel UvdLevel[SMU72_MAX_LEVELS_UVD];
+ SMU72_Discrete_ExtClkLevel VceLevel[SMU72_MAX_LEVELS_VCE];
+ SMU72_Discrete_ExtClkLevel AcpLevel[SMU72_MAX_LEVELS_ACP];
+ SMU72_Discrete_ExtClkLevel SamuLevel[SMU72_MAX_LEVELS_SAMU];
+ SMU72_Discrete_Ulv Ulv;
+
+ uint32_t SclkStepSize;
+ uint32_t Smio[SMU72_MAX_ENTRIES_SMIO];
+
+ uint8_t UvdBootLevel;
+ uint8_t VceBootLevel;
+ uint8_t AcpBootLevel;
+ uint8_t SamuBootLevel;
+
+ uint8_t GraphicsBootLevel;
+ uint8_t GraphicsVoltageChangeEnable;
+ uint8_t GraphicsThermThrottleEnable;
+ uint8_t GraphicsInterval;
+
+ uint8_t VoltageInterval;
+ uint8_t ThermalInterval;
+ uint16_t TemperatureLimitHigh;
+
+ uint16_t TemperatureLimitLow;
+ uint8_t MemoryBootLevel;
+ uint8_t MemoryVoltageChangeEnable;
+
+ uint16_t BootMVdd;
+ uint8_t MemoryInterval;
+ uint8_t MemoryThermThrottleEnable;
+
+ uint16_t VoltageResponseTime;
+ uint16_t PhaseResponseTime;
+
+ uint8_t PCIeBootLinkLevel;
+ uint8_t PCIeGenInterval;
+ uint8_t DTEInterval;
+ uint8_t DTEMode;
+
+ uint8_t SVI2Enable;
+ uint8_t VRHotGpio;
+ uint8_t AcDcGpio;
+ uint8_t ThermGpio;
+
+ uint16_t PPM_PkgPwrLimit;
+ uint16_t PPM_TemperatureLimit;
+
+ uint16_t DefaultTdp;
+ uint16_t TargetTdp;
+
+ uint16_t FpsHighThreshold;
+ uint16_t FpsLowThreshold;
+
+ uint16_t BAPMTI_R[SMU72_DTE_ITERATIONS][SMU72_DTE_SOURCES][SMU72_DTE_SINKS];
+ uint16_t BAPMTI_RC[SMU72_DTE_ITERATIONS][SMU72_DTE_SOURCES][SMU72_DTE_SINKS];
+
+ uint8_t DTEAmbientTempBase;
+ uint8_t DTETjOffset;
+ uint8_t GpuTjMax;
+ uint8_t GpuTjHyst;
+
+ SMU_VoltageLevel BootVoltage;
+
+ uint32_t BAPM_TEMP_GRADIENT;
+
+ uint32_t LowSclkInterruptThreshold;
+ uint32_t VddGfxReChkWait;
+
+ uint8_t ClockStretcherAmount;
+
+ uint8_t Sclk_CKS_masterEn0_7;
+ uint8_t Sclk_CKS_masterEn8_15;
+ uint8_t padding[1];
+
+ uint8_t Sclk_voltageOffset[8];
+
+ SMU_ClockStretcherDataTable ClockStretcherDataTable;
+ SMU_CKS_LOOKUPTable CKS_LOOKUPTable;
+};
+
+typedef struct SMU72_Discrete_DpmTable SMU72_Discrete_DpmTable;
+
+/* --------------------------------------------------- AC Timing Parameters ------------------------------------------------ */
+#define SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE 16
+#define SMU72_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT SMU72_MAX_LEVELS_MEMORY /* DPM */
+
+struct SMU72_Discrete_MCRegisterAddress {
+ uint16_t s0;
+ uint16_t s1;
+};
+
+typedef struct SMU72_Discrete_MCRegisterAddress SMU72_Discrete_MCRegisterAddress;
+
+struct SMU72_Discrete_MCRegisterSet {
+ uint32_t value[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMU72_Discrete_MCRegisterSet SMU72_Discrete_MCRegisterSet;
+
+struct SMU72_Discrete_MCRegisters {
+ uint8_t last;
+ uint8_t reserved[3];
+ SMU72_Discrete_MCRegisterAddress address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+ SMU72_Discrete_MCRegisterSet data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMU72_Discrete_MCRegisters SMU72_Discrete_MCRegisters;
+
+
+/* --------------------------------------------------- Fan Table ----------------------------------------------------------- */
+
+struct SMU72_Discrete_FanTable {
+ uint16_t FdoMode;
+ int16_t TempMin;
+ int16_t TempMed;
+ int16_t TempMax;
+ int16_t Slope1;
+ int16_t Slope2;
+ int16_t FdoMin;
+ int16_t HystUp;
+ int16_t HystDown;
+ int16_t HystSlope;
+ int16_t TempRespLim;
+ int16_t TempCurr;
+ int16_t SlopeCurr;
+ int16_t PwmCurr;
+ uint32_t RefreshPeriod;
+ int16_t FdoMax;
+ uint8_t TempSrc;
+ int8_t FanControl_GL_Flag;
+};
+
+typedef struct SMU72_Discrete_FanTable SMU72_Discrete_FanTable;
+
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG 4
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG_BIT (0x1 << SMU7_DISCRETE_GPIO_SCLK_DEBUG)
+
+struct SMU7_MclkDpmScoreboard {
+
+ uint32_t PercentageBusy;
+
+ int32_t PIDError;
+ int32_t PIDIntegral;
+ int32_t PIDOutput;
+
+ uint32_t SigmaDeltaAccum;
+ uint32_t SigmaDeltaOutput;
+ uint32_t SigmaDeltaLevel;
+
+ uint32_t UtilizationSetpoint;
+
+ uint8_t TdpClampMode;
+ uint8_t TdcClampMode;
+ uint8_t ThermClampMode;
+ uint8_t VoltageBusy;
+
+ int8_t CurrLevel;
+ int8_t TargLevel;
+ uint8_t LevelChangeInProgress;
+ uint8_t UpHyst;
+
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t DpmEnable;
+ uint8_t DpmRunning;
+
+ uint8_t DpmForce;
+ uint8_t DpmForceLevel;
+ uint8_t DisplayWatermark;
+ uint8_t McArbIndex;
+
+ uint32_t MinimumPerfMclk;
+
+ uint8_t AcpiReq;
+ uint8_t AcpiAck;
+ uint8_t MclkSwitchInProgress;
+ uint8_t MclkSwitchCritical;
+
+ uint8_t IgnoreVBlank;
+ uint8_t TargetMclkIndex;
+ uint8_t TargetMvddIndex;
+ uint8_t MclkSwitchResult;
+
+ uint16_t VbiFailureCount;
+ uint8_t VbiWaitCounter;
+ uint8_t EnabledLevelsChange;
+
+ uint16_t LevelResidencyCountersN[SMU72_MAX_LEVELS_MEMORY];
+ uint16_t LevelSwitchCounters[SMU72_MAX_LEVELS_MEMORY];
+
+ void (*TargetStateCalculator)(uint8_t);
+ void (*SavedTargetStateCalculator)(uint8_t);
+
+ uint16_t AutoDpmInterval;
+ uint16_t AutoDpmRange;
+
+ uint16_t VbiTimeoutCount;
+ uint16_t MclkSwitchingTime;
+
+ uint8_t fastSwitch;
+ uint8_t Save_PIC_VDDGFX_EXIT;
+ uint8_t Save_PIC_VDDGFX_ENTER;
+ uint8_t padding;
+
+};
+
+typedef struct SMU7_MclkDpmScoreboard SMU7_MclkDpmScoreboard;
+
+struct SMU7_UlvScoreboard {
+ uint8_t EnterUlv;
+ uint8_t ExitUlv;
+ uint8_t UlvActive;
+ uint8_t WaitingForUlv;
+ uint8_t UlvEnable;
+ uint8_t UlvRunning;
+ uint8_t UlvMasterEnable;
+ uint8_t padding;
+ uint32_t UlvAbortedCount;
+ uint32_t UlvTimeStamp;
+};
+
+typedef struct SMU7_UlvScoreboard SMU7_UlvScoreboard;
+
+struct VddgfxSavedRegisters {
+ uint32_t GPU_DBG[3];
+ uint32_t MEC_BaseAddress_Hi;
+ uint32_t MEC_BaseAddress_Lo;
+ uint32_t THM_TMON0_CTRL2__RDIR_PRESENT;
+ uint32_t THM_TMON1_CTRL2__RDIR_PRESENT;
+ uint32_t CP_INT_CNTL;
+};
+
+typedef struct VddgfxSavedRegisters VddgfxSavedRegisters;
+
+struct SMU7_VddGfxScoreboard {
+ uint8_t VddGfxEnable;
+ uint8_t VddGfxActive;
+ uint8_t VPUResetOccured;
+ uint8_t padding;
+
+ uint32_t VddGfxEnteredCount;
+ uint32_t VddGfxAbortedCount;
+
+ uint32_t VddGfxVid;
+
+ VddgfxSavedRegisters SavedRegisters;
+};
+
+typedef struct SMU7_VddGfxScoreboard SMU7_VddGfxScoreboard;
+
+struct SMU7_TdcLimitScoreboard {
+ uint8_t Enable;
+ uint8_t Running;
+ uint16_t Alpha;
+ uint32_t FilteredIddc;
+ uint32_t IddcLimit;
+ uint32_t IddcHyst;
+ SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_TdcLimitScoreboard SMU7_TdcLimitScoreboard;
+
+struct SMU7_PkgPwrLimitScoreboard {
+ uint8_t Enable;
+ uint8_t Running;
+ uint16_t Alpha;
+ uint32_t FilteredPkgPwr;
+ uint32_t Limit;
+ uint32_t Hyst;
+ uint32_t LimitFromDriver;
+ SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_PkgPwrLimitScoreboard SMU7_PkgPwrLimitScoreboard;
+
+struct SMU7_BapmScoreboard {
+ uint32_t source_powers[SMU72_DTE_SOURCES];
+ uint32_t source_powers_last[SMU72_DTE_SOURCES];
+ int32_t entity_temperatures[SMU72_NUM_GPU_TES];
+ int32_t initial_entity_temperatures[SMU72_NUM_GPU_TES];
+ int32_t Limit;
+ int32_t Hyst;
+ int32_t therm_influence_coeff_table[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS * 2];
+ int32_t therm_node_table[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
+ uint16_t ConfigTDPPowerScalar;
+ uint16_t FanSpeedPowerScalar;
+ uint16_t OverDrivePowerScalar;
+ uint16_t OverDriveLimitScalar;
+ uint16_t FinalPowerScalar;
+ uint8_t VariantID;
+ uint8_t spare997;
+
+ SMU7_HystController_Data HystControllerData;
+
+ int32_t temperature_gradient_slope;
+ int32_t temperature_gradient;
+ uint32_t measured_temperature;
+};
+
+
+typedef struct SMU7_BapmScoreboard SMU7_BapmScoreboard;
+
+struct SMU7_AcpiScoreboard {
+ uint32_t SavedInterruptMask[2];
+ uint8_t LastACPIRequest;
+ uint8_t CgBifResp;
+ uint8_t RequestType;
+ uint8_t Padding;
+ SMU72_Discrete_ACPILevel D0Level;
+};
+
+typedef struct SMU7_AcpiScoreboard SMU7_AcpiScoreboard;
+
+struct SMU72_Discrete_PmFuses {
+ /* dw1 */
+ uint8_t SviLoadLineEn;
+ uint8_t SviLoadLineVddC;
+ uint8_t SviLoadLineTrimVddC;
+ uint8_t SviLoadLineOffsetVddC;
+
+ /* dw2 */
+ uint16_t TDC_VDDC_PkgLimit;
+ uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+ uint8_t TDC_MAWt;
+
+ /* dw3 */
+ uint8_t TdcWaterfallCtl;
+ uint8_t LPMLTemperatureMin;
+ uint8_t LPMLTemperatureMax;
+ uint8_t Reserved;
+
+ /* dw4-dw7 */
+ uint8_t LPMLTemperatureScaler[16];
+
+ /* dw8-dw9 */
+ int16_t FuzzyFan_ErrorSetDelta;
+ int16_t FuzzyFan_ErrorRateSetDelta;
+ int16_t FuzzyFan_PwmSetDelta;
+ uint16_t Reserved6;
+
+ /* dw10-dw14 */
+ uint8_t GnbLPML[16];
+
+ /* dw15 */
+ uint8_t GnbLPMLMaxVid;
+ uint8_t GnbLPMLMinVid;
+ uint8_t Reserved1[2];
+
+ /* dw16 */
+ uint16_t BapmVddCBaseLeakageHiSidd;
+ uint16_t BapmVddCBaseLeakageLoSidd;
+};
+
+typedef struct SMU72_Discrete_PmFuses SMU72_Discrete_PmFuses;
+
+struct SMU7_Discrete_Log_Header_Table {
+ uint32_t version;
+ uint32_t asic_id;
+ uint16_t flags;
+ uint16_t entry_size;
+ uint32_t total_size;
+ uint32_t num_of_entries;
+ uint8_t type;
+ uint8_t mode;
+ uint8_t filler_0[2];
+ uint32_t filler_1[2];
+};
+
+typedef struct SMU7_Discrete_Log_Header_Table SMU7_Discrete_Log_Header_Table;
+
+struct SMU7_Discrete_Log_Cntl {
+ uint8_t Enabled;
+ uint8_t Type;
+ uint8_t padding[2];
+ uint32_t BufferSize;
+ uint32_t SamplesLogged;
+ uint32_t SampleSize;
+ uint32_t AddrL;
+ uint32_t AddrH;
+};
+
+typedef struct SMU7_Discrete_Log_Cntl SMU7_Discrete_Log_Cntl;
+
+#define CAC_ACC_NW_NUM_OF_SIGNALS 87
+
+struct SMU7_Discrete_Cac_Collection_Table {
+ uint32_t temperature;
+ uint32_t cac_acc_nw[CAC_ACC_NW_NUM_OF_SIGNALS];
+};
+
+typedef struct SMU7_Discrete_Cac_Collection_Table SMU7_Discrete_Cac_Collection_Table;
+
+struct SMU7_Discrete_Cac_Verification_Table {
+ uint32_t VddcTotalPower;
+ uint32_t VddcLeakagePower;
+ uint32_t VddcConstantPower;
+ uint32_t VddcGfxDynamicPower;
+ uint32_t VddcUvdDynamicPower;
+ uint32_t VddcVceDynamicPower;
+ uint32_t VddcAcpDynamicPower;
+ uint32_t VddcPcieDynamicPower;
+ uint32_t VddcDceDynamicPower;
+ uint32_t VddcCurrent;
+ uint32_t VddcVoltage;
+ uint32_t VddciTotalPower;
+ uint32_t VddciLeakagePower;
+ uint32_t VddciConstantPower;
+ uint32_t VddciDynamicPower;
+ uint32_t Vddr1TotalPower;
+ uint32_t Vddr1LeakagePower;
+ uint32_t Vddr1ConstantPower;
+ uint32_t Vddr1DynamicPower;
+ uint32_t spare[4];
+ uint32_t temperature;
+};
+
+typedef struct SMU7_Discrete_Cac_Verification_Table SMU7_Discrete_Cac_Verification_Table;
+
+struct SMU7_Discrete_Pm_Status_Table {
+ /* Thermal entities */
+ int32_t T_meas_max;
+ int32_t T_meas_acc;
+ int32_t T_calc_max;
+ int32_t T_calc_acc;
+ uint32_t P_scalar_acc;
+ uint32_t P_calc_max;
+ uint32_t P_calc_acc;
+
+ /*Voltage domains */
+ uint32_t I_calc_max;
+ uint32_t I_calc_acc;
+ uint32_t I_calc_acc_vddci;
+ uint32_t V_calc_noload_acc;
+ uint32_t V_calc_load_acc;
+ uint32_t V_calc_noload_acc_vddci;
+ uint32_t P_meas_acc;
+ uint32_t V_meas_noload_acc;
+ uint32_t V_meas_load_acc;
+ uint32_t I_meas_acc;
+ uint32_t P_meas_acc_vddci;
+ uint32_t V_meas_noload_acc_vddci;
+ uint32_t V_meas_load_acc_vddci;
+ uint32_t I_meas_acc_vddci;
+
+ /*Frequency */
+ uint16_t Sclk_dpm_residency[8];
+ uint16_t Uvd_dpm_residency[8];
+ uint16_t Vce_dpm_residency[8];
+ uint16_t Mclk_dpm_residency[4];
+
+ /*Chip */
+ uint32_t P_vddci_acc;
+ uint32_t P_vddr1_acc;
+ uint32_t P_nte1_acc;
+ uint32_t PkgPwr_max;
+ uint32_t PkgPwr_acc;
+ uint32_t MclkSwitchingTime_max;
+ uint32_t MclkSwitchingTime_acc;
+ uint32_t FanPwm_acc;
+ uint32_t FanRpm_acc;
+
+ uint32_t AccCnt;
+};
+
+typedef struct SMU7_Discrete_Pm_Status_Table SMU7_Discrete_Pm_Status_Table;
+
+/*FIXME THESE NEED TO BE UPDATED */
+#define SMU7_SCLK_CAC 0x561
+#define SMU7_MCLK_CAC 0xF9
+#define SMU7_VCLK_CAC 0x2DE
+#define SMU7_DCLK_CAC 0x2DE
+#define SMU7_ECLK_CAC 0x25E
+#define SMU7_ACLK_CAC 0x25E
+#define SMU7_SAMCLK_CAC 0x25E
+#define SMU7_DISPCLK_CAC 0x100
+#define SMU7_CAC_CONSTANT 0x2EE3430
+#define SMU7_CAC_CONSTANT_SHIFT 18
+
+#define SMU7_VDDCI_MCLK_CONST 1765
+#define SMU7_VDDCI_MCLK_CONST_SHIFT 16
+#define SMU7_VDDCI_VDDCI_CONST 50958
+#define SMU7_VDDCI_VDDCI_CONST_SHIFT 14
+#define SMU7_VDDCI_CONST 11781
+
+#define SMU7_12C_VDDCI_MCLK_CONST 1623
+#define SMU7_12C_VDDCI_MCLK_CONST_SHIFT 15
+#define SMU7_12C_VDDCI_VDDCI_CONST 40088
+#define SMU7_12C_VDDCI_VDDCI_CONST_SHIFT 13
+#define SMU7_12C_VDDCI_CONST 20856
+
+#define SMU7_VDDCI_STROBE_PWR 1331
+
+#define SMU7_VDDR1_CONST 693
+#define SMU7_VDDR1_CAC_WEIGHT 20
+#define SMU7_VDDR1_CAC_WEIGHT_SHIFT 19
+#define SMU7_VDDR1_STROBE_PWR 512
+
+#define SMU7_AREA_COEFF_UVD 0xA78
+#define SMU7_AREA_COEFF_VCE 0x190A
+#define SMU7_AREA_COEFF_ACP 0x22D1
+#define SMU7_AREA_COEFF_SAMU 0x534
+
+/*ThermOutMode values */
+#define SMU7_THERM_OUT_MODE_DISABLE 0x0
+#define SMU7_THERM_OUT_MODE_THERM_ONLY 0x1
+#define SMU7_THERM_OUT_MODE_THERM_VRHOT 0x2
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu73.h b/drivers/gpu/drm/amd/powerplay/inc/smu73.h
new file mode 100644
index 000000000000..c6b12a4c00db
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu73.h
@@ -0,0 +1,720 @@
+/*
+ * Copyright 2015 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 _SMU73_H_
+#define _SMU73_H_
+
+#pragma pack(push, 1)
+enum SID_OPTION {
+ SID_OPTION_HI,
+ SID_OPTION_LO,
+ SID_OPTION_COUNT
+};
+
+enum Poly3rdOrderCoeff {
+ LEAKAGE_TEMPERATURE_SCALAR,
+ LEAKAGE_VOLTAGE_SCALAR,
+ DYNAMIC_VOLTAGE_SCALAR,
+ POLY_3RD_ORDER_COUNT
+};
+
+struct SMU7_Poly3rdOrder_Data
+{
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+ uint8_t a_shift;
+ uint8_t b_shift;
+ uint8_t c_shift;
+ uint8_t x_shift;
+};
+
+typedef struct SMU7_Poly3rdOrder_Data SMU7_Poly3rdOrder_Data;
+
+struct Power_Calculator_Data
+{
+ uint16_t NoLoadVoltage;
+ uint16_t LoadVoltage;
+ uint16_t Resistance;
+ uint16_t Temperature;
+ uint16_t BaseLeakage;
+ uint16_t LkgTempScalar;
+ uint16_t LkgVoltScalar;
+ uint16_t LkgAreaScalar;
+ uint16_t LkgPower;
+ uint16_t DynVoltScalar;
+ uint32_t Cac;
+ uint32_t DynPower;
+ uint32_t TotalCurrent;
+ uint32_t TotalPower;
+};
+
+typedef struct Power_Calculator_Data PowerCalculatorData_t;
+
+struct Gc_Cac_Weight_Data
+{
+ uint8_t index;
+ uint32_t value;
+};
+
+typedef struct Gc_Cac_Weight_Data GcCacWeight_Data;
+
+
+typedef struct {
+ uint32_t high;
+ uint32_t low;
+} data_64_t;
+
+typedef struct {
+ data_64_t high;
+ data_64_t low;
+} data_128_t;
+
+#define SMU__NUM_SCLK_DPM_STATE 8
+#define SMU__NUM_MCLK_DPM_LEVELS 4
+#define SMU__NUM_LCLK_DPM_LEVELS 8
+#define SMU__NUM_PCIE_DPM_LEVELS 8
+
+#define SMU7_CONTEXT_ID_SMC 1
+#define SMU7_CONTEXT_ID_VBIOS 2
+
+#define SMU73_MAX_LEVELS_VDDC 16
+#define SMU73_MAX_LEVELS_VDDGFX 16
+#define SMU73_MAX_LEVELS_VDDCI 8
+#define SMU73_MAX_LEVELS_MVDD 4
+
+#define SMU_MAX_SMIO_LEVELS 4
+
+#define SMU73_MAX_LEVELS_GRAPHICS SMU__NUM_SCLK_DPM_STATE // SCLK + SQ DPM + ULV
+#define SMU73_MAX_LEVELS_MEMORY SMU__NUM_MCLK_DPM_LEVELS // MCLK Levels DPM
+#define SMU73_MAX_LEVELS_GIO SMU__NUM_LCLK_DPM_LEVELS // LCLK Levels
+#define SMU73_MAX_LEVELS_LINK SMU__NUM_PCIE_DPM_LEVELS // PCIe speed and number of lanes.
+#define SMU73_MAX_LEVELS_UVD 8 // VCLK/DCLK levels for UVD.
+#define SMU73_MAX_LEVELS_VCE 8 // ECLK levels for VCE.
+#define SMU73_MAX_LEVELS_ACP 8 // ACLK levels for ACP.
+#define SMU73_MAX_LEVELS_SAMU 8 // SAMCLK levels for SAMU.
+#define SMU73_MAX_ENTRIES_SMIO 32 // Number of entries in SMIO table.
+
+#define DPM_NO_LIMIT 0
+#define DPM_NO_UP 1
+#define DPM_GO_DOWN 2
+#define DPM_GO_UP 3
+
+#define SMU7_FIRST_DPM_GRAPHICS_LEVEL 0
+#define SMU7_FIRST_DPM_MEMORY_LEVEL 0
+
+#define GPIO_CLAMP_MODE_VRHOT 1
+#define GPIO_CLAMP_MODE_THERM 2
+#define GPIO_CLAMP_MODE_DC 4
+
+#define SCRATCH_B_TARG_PCIE_INDEX_SHIFT 0
+#define SCRATCH_B_TARG_PCIE_INDEX_MASK (0x7<<SCRATCH_B_TARG_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_PCIE_INDEX_SHIFT 3
+#define SCRATCH_B_CURR_PCIE_INDEX_MASK (0x7<<SCRATCH_B_CURR_PCIE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_UVD_INDEX_SHIFT 6
+#define SCRATCH_B_TARG_UVD_INDEX_MASK (0x7<<SCRATCH_B_TARG_UVD_INDEX_SHIFT)
+#define SCRATCH_B_CURR_UVD_INDEX_SHIFT 9
+#define SCRATCH_B_CURR_UVD_INDEX_MASK (0x7<<SCRATCH_B_CURR_UVD_INDEX_SHIFT)
+#define SCRATCH_B_TARG_VCE_INDEX_SHIFT 12
+#define SCRATCH_B_TARG_VCE_INDEX_MASK (0x7<<SCRATCH_B_TARG_VCE_INDEX_SHIFT)
+#define SCRATCH_B_CURR_VCE_INDEX_SHIFT 15
+#define SCRATCH_B_CURR_VCE_INDEX_MASK (0x7<<SCRATCH_B_CURR_VCE_INDEX_SHIFT)
+#define SCRATCH_B_TARG_ACP_INDEX_SHIFT 18
+#define SCRATCH_B_TARG_ACP_INDEX_MASK (0x7<<SCRATCH_B_TARG_ACP_INDEX_SHIFT)
+#define SCRATCH_B_CURR_ACP_INDEX_SHIFT 21
+#define SCRATCH_B_CURR_ACP_INDEX_MASK (0x7<<SCRATCH_B_CURR_ACP_INDEX_SHIFT)
+#define SCRATCH_B_TARG_SAMU_INDEX_SHIFT 24
+#define SCRATCH_B_TARG_SAMU_INDEX_MASK (0x7<<SCRATCH_B_TARG_SAMU_INDEX_SHIFT)
+#define SCRATCH_B_CURR_SAMU_INDEX_SHIFT 27
+#define SCRATCH_B_CURR_SAMU_INDEX_MASK (0x7<<SCRATCH_B_CURR_SAMU_INDEX_SHIFT)
+
+// Virtualization Defines
+#define CG_XDMA_MASK 0x1
+#define CG_XDMA_SHIFT 0
+#define CG_UVD_MASK 0x2
+#define CG_UVD_SHIFT 1
+#define CG_VCE_MASK 0x4
+#define CG_VCE_SHIFT 2
+#define CG_SAMU_MASK 0x8
+#define CG_SAMU_SHIFT 3
+#define CG_GFX_MASK 0x10
+#define CG_GFX_SHIFT 4
+#define CG_SDMA_MASK 0x20
+#define CG_SDMA_SHIFT 5
+#define CG_HDP_MASK 0x40
+#define CG_HDP_SHIFT 6
+#define CG_MC_MASK 0x80
+#define CG_MC_SHIFT 7
+#define CG_DRM_MASK 0x100
+#define CG_DRM_SHIFT 8
+#define CG_ROM_MASK 0x200
+#define CG_ROM_SHIFT 9
+#define CG_BIF_MASK 0x400
+#define CG_BIF_SHIFT 10
+
+#define SMU73_DTE_ITERATIONS 5
+#define SMU73_DTE_SOURCES 3
+#define SMU73_DTE_SINKS 1
+#define SMU73_NUM_CPU_TES 0
+#define SMU73_NUM_GPU_TES 1
+#define SMU73_NUM_NON_TES 2
+#define SMU73_DTE_FAN_SCALAR_MIN 0x100
+#define SMU73_DTE_FAN_SCALAR_MAX 0x166
+#define SMU73_DTE_FAN_TEMP_MAX 93
+#define SMU73_DTE_FAN_TEMP_MIN 83
+
+#define SMU73_THERMAL_INPUT_LOOP_COUNT 6
+#define SMU73_THERMAL_CLAMP_MODE_COUNT 8
+
+
+struct SMU7_HystController_Data
+{
+ uint16_t waterfall_up;
+ uint16_t waterfall_down;
+ uint16_t waterfall_limit;
+ uint16_t release_cnt;
+ uint16_t release_limit;
+ uint16_t spare;
+};
+
+typedef struct SMU7_HystController_Data SMU7_HystController_Data;
+
+struct SMU73_PIDController
+{
+ uint32_t Ki;
+ int32_t LFWindupUpperLim;
+ int32_t LFWindupLowerLim;
+ uint32_t StatePrecision;
+
+ uint32_t LfPrecision;
+ uint32_t LfOffset;
+ uint32_t MaxState;
+ uint32_t MaxLfFraction;
+ uint32_t StateShift;
+};
+
+typedef struct SMU73_PIDController SMU73_PIDController;
+
+struct SMU7_LocalDpmScoreboard
+{
+ uint32_t PercentageBusy;
+
+ int32_t PIDError;
+ int32_t PIDIntegral;
+ int32_t PIDOutput;
+
+ uint32_t SigmaDeltaAccum;
+ uint32_t SigmaDeltaOutput;
+ uint32_t SigmaDeltaLevel;
+
+ uint32_t UtilizationSetpoint;
+
+ uint8_t TdpClampMode;
+ uint8_t TdcClampMode;
+ uint8_t ThermClampMode;
+ uint8_t VoltageBusy;
+
+ int8_t CurrLevel;
+ int8_t TargLevel;
+ uint8_t LevelChangeInProgress;
+ uint8_t UpHyst;
+
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t DpmEnable;
+ uint8_t DpmRunning;
+
+ uint8_t DpmForce;
+ uint8_t DpmForceLevel;
+ uint8_t DisplayWatermark;
+ uint8_t McArbIndex;
+
+ uint32_t MinimumPerfSclk;
+
+ uint8_t AcpiReq;
+ uint8_t AcpiAck;
+ uint8_t GfxClkSlow;
+ uint8_t GpioClampMode;
+
+ uint8_t spare2;
+ uint8_t EnabledLevelsChange;
+ uint8_t DteClampMode;
+ uint8_t FpsClampMode;
+
+ uint16_t LevelResidencyCounters [SMU73_MAX_LEVELS_GRAPHICS];
+ uint16_t LevelSwitchCounters [SMU73_MAX_LEVELS_GRAPHICS];
+
+ void (*TargetStateCalculator)(uint8_t);
+ void (*SavedTargetStateCalculator)(uint8_t);
+
+ uint16_t AutoDpmInterval;
+ uint16_t AutoDpmRange;
+
+ uint8_t FpsEnabled;
+ uint8_t MaxPerfLevel;
+ uint8_t AllowLowClkInterruptToHost;
+ uint8_t FpsRunning;
+
+ uint32_t MaxAllowedFrequency;
+
+ uint32_t FilteredSclkFrequency;
+ uint32_t LastSclkFrequency;
+ uint32_t FilteredSclkFrequencyCnt;
+
+ uint8_t LedEnable;
+ uint8_t LedPin0;
+ uint8_t LedPin1;
+ uint8_t LedPin2;
+ uint32_t LedAndMask;
+
+ uint16_t FpsAlpha;
+ uint16_t DeltaTime;
+ uint32_t CurrentFps;
+ uint32_t FilteredFps;
+ uint32_t FrameCount;
+ uint32_t FrameCountLast;
+ uint16_t FpsTargetScalar;
+ uint16_t FpsWaterfallLimitScalar;
+ uint16_t FpsAlphaScalar;
+ uint16_t spare8;
+ SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_LocalDpmScoreboard SMU7_LocalDpmScoreboard;
+
+#define SMU7_MAX_VOLTAGE_CLIENTS 12
+
+typedef uint8_t (*VoltageChangeHandler_t)(uint16_t, uint8_t);
+
+#define VDDC_MASK 0x00007FFF
+#define VDDC_SHIFT 0
+#define VDDCI_MASK 0x3FFF8000
+#define VDDCI_SHIFT 15
+#define PHASES_MASK 0xC0000000
+#define PHASES_SHIFT 30
+
+typedef uint32_t SMU_VoltageLevel;
+
+struct SMU7_VoltageScoreboard
+{
+ SMU_VoltageLevel TargetVoltage;
+ uint16_t MaxVid;
+ uint8_t HighestVidOffset;
+ uint8_t CurrentVidOffset;
+
+ uint16_t CurrentVddc;
+ uint16_t CurrentVddci;
+
+
+ uint8_t ControllerBusy;
+ uint8_t CurrentVid;
+ uint8_t CurrentVddciVid;
+ uint8_t padding;
+
+ SMU_VoltageLevel RequestedVoltage[SMU7_MAX_VOLTAGE_CLIENTS];
+ SMU_VoltageLevel TargetVoltageState;
+ uint8_t EnabledRequest[SMU7_MAX_VOLTAGE_CLIENTS];
+
+ uint8_t padding2;
+ uint8_t padding3;
+ uint8_t ControllerEnable;
+ uint8_t ControllerRunning;
+ uint16_t CurrentStdVoltageHiSidd;
+ uint16_t CurrentStdVoltageLoSidd;
+ uint8_t OverrideVoltage;
+ uint8_t padding4;
+ uint8_t padding5;
+ uint8_t CurrentPhases;
+
+ VoltageChangeHandler_t ChangeVddc;
+
+ VoltageChangeHandler_t ChangeVddci;
+ VoltageChangeHandler_t ChangePhase;
+ VoltageChangeHandler_t ChangeMvdd;
+
+ VoltageChangeHandler_t functionLinks[6];
+
+ uint16_t * VddcFollower1;
+
+ int16_t Driver_OD_RequestedVidOffset1;
+ int16_t Driver_OD_RequestedVidOffset2;
+
+};
+
+typedef struct SMU7_VoltageScoreboard SMU7_VoltageScoreboard;
+
+// -------------------------------------------------------------------------------------------------------------------------
+#define SMU7_MAX_PCIE_LINK_SPEEDS 3 /* 0:Gen1 1:Gen2 2:Gen3 */
+
+struct SMU7_PCIeLinkSpeedScoreboard
+{
+ uint8_t DpmEnable;
+ uint8_t DpmRunning;
+ uint8_t DpmForce;
+ uint8_t DpmForceLevel;
+
+ uint8_t CurrentLinkSpeed;
+ uint8_t EnabledLevelsChange;
+ uint16_t AutoDpmInterval;
+
+ uint16_t AutoDpmRange;
+ uint16_t AutoDpmCount;
+
+ uint8_t DpmMode;
+ uint8_t AcpiReq;
+ uint8_t AcpiAck;
+ uint8_t CurrentLinkLevel;
+
+};
+
+typedef struct SMU7_PCIeLinkSpeedScoreboard SMU7_PCIeLinkSpeedScoreboard;
+
+// -------------------------------------------------------- CAC table ------------------------------------------------------
+#define SMU7_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMU7_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+
+#define SMU7_SCALE_I 7
+#define SMU7_SCALE_R 12
+
+struct SMU7_PowerScoreboard
+{
+ uint32_t GpuPower;
+
+ uint32_t VddcPower;
+ uint32_t VddcVoltage;
+ uint32_t VddcCurrent;
+
+ uint32_t MvddPower;
+ uint32_t MvddVoltage;
+ uint32_t MvddCurrent;
+
+ uint32_t RocPower;
+
+ uint16_t Telemetry_1_slope;
+ uint16_t Telemetry_2_slope;
+ int32_t Telemetry_1_offset;
+ int32_t Telemetry_2_offset;
+};
+typedef struct SMU7_PowerScoreboard SMU7_PowerScoreboard;
+
+// For FeatureEnables:
+#define SMU7_SCLK_DPM_CONFIG_MASK 0x01
+#define SMU7_VOLTAGE_CONTROLLER_CONFIG_MASK 0x02
+#define SMU7_THERMAL_CONTROLLER_CONFIG_MASK 0x04
+#define SMU7_MCLK_DPM_CONFIG_MASK 0x08
+#define SMU7_UVD_DPM_CONFIG_MASK 0x10
+#define SMU7_VCE_DPM_CONFIG_MASK 0x20
+#define SMU7_ACP_DPM_CONFIG_MASK 0x40
+#define SMU7_SAMU_DPM_CONFIG_MASK 0x80
+#define SMU7_PCIEGEN_DPM_CONFIG_MASK 0x100
+
+#define SMU7_ACP_MCLK_HANDSHAKE_DISABLE 0x00000001
+#define SMU7_ACP_SCLK_HANDSHAKE_DISABLE 0x00000002
+#define SMU7_UVD_MCLK_HANDSHAKE_DISABLE 0x00000100
+#define SMU7_UVD_SCLK_HANDSHAKE_DISABLE 0x00000200
+#define SMU7_VCE_MCLK_HANDSHAKE_DISABLE 0x00010000
+#define SMU7_VCE_SCLK_HANDSHAKE_DISABLE 0x00020000
+
+// All 'soft registers' should be uint32_t.
+struct SMU73_SoftRegisters
+{
+ uint32_t RefClockFrequency;
+ uint32_t PmTimerPeriod;
+ uint32_t FeatureEnables;
+
+ uint32_t PreVBlankGap;
+ uint32_t VBlankTimeout;
+ uint32_t TrainTimeGap;
+
+ uint32_t MvddSwitchTime;
+ uint32_t LongestAcpiTrainTime;
+ uint32_t AcpiDelay;
+ uint32_t G5TrainTime;
+ uint32_t DelayMpllPwron;
+ uint32_t VoltageChangeTimeout;
+
+ uint32_t HandshakeDisables;
+
+ uint8_t DisplayPhy1Config;
+ uint8_t DisplayPhy2Config;
+ uint8_t DisplayPhy3Config;
+ uint8_t DisplayPhy4Config;
+
+ uint8_t DisplayPhy5Config;
+ uint8_t DisplayPhy6Config;
+ uint8_t DisplayPhy7Config;
+ uint8_t DisplayPhy8Config;
+
+ uint32_t AverageGraphicsActivity;
+ uint32_t AverageMemoryActivity;
+ uint32_t AverageGioActivity;
+
+ uint8_t SClkDpmEnabledLevels;
+ uint8_t MClkDpmEnabledLevels;
+ uint8_t LClkDpmEnabledLevels;
+ uint8_t PCIeDpmEnabledLevels;
+
+ uint8_t UVDDpmEnabledLevels;
+ uint8_t SAMUDpmEnabledLevels;
+ uint8_t ACPDpmEnabledLevels;
+ uint8_t VCEDpmEnabledLevels;
+
+ uint32_t DRAM_LOG_ADDR_H;
+ uint32_t DRAM_LOG_ADDR_L;
+ uint32_t DRAM_LOG_PHY_ADDR_H;
+ uint32_t DRAM_LOG_PHY_ADDR_L;
+ uint32_t DRAM_LOG_BUFF_SIZE;
+ uint32_t UlvEnterCount;
+ uint32_t UlvTime;
+ uint32_t UcodeLoadStatus;
+ uint32_t Reserved[2];
+
+};
+
+typedef struct SMU73_SoftRegisters SMU73_SoftRegisters;
+
+struct SMU73_Firmware_Header
+{
+ uint32_t Digest[5];
+ uint32_t Version;
+ uint32_t HeaderSize;
+ uint32_t Flags;
+ uint32_t EntryPoint;
+ uint32_t CodeSize;
+ uint32_t ImageSize;
+
+ uint32_t Rtos;
+ uint32_t SoftRegisters;
+ uint32_t DpmTable;
+ uint32_t FanTable;
+ uint32_t CacConfigTable;
+ uint32_t CacStatusTable;
+
+
+ uint32_t mcRegisterTable;
+
+
+ uint32_t mcArbDramTimingTable;
+
+
+
+
+ uint32_t PmFuseTable;
+ uint32_t Globals;
+ uint32_t ClockStretcherTable;
+ uint32_t Reserved[41];
+ uint32_t Signature;
+};
+
+typedef struct SMU73_Firmware_Header SMU73_Firmware_Header;
+
+#define SMU7_FIRMWARE_HEADER_LOCATION 0x20000
+
+enum DisplayConfig {
+ PowerDown = 1,
+ DP54x4,
+ DP54x2,
+ DP54x1,
+ DP27x4,
+ DP27x2,
+ DP27x1,
+ HDMI297,
+ HDMI162,
+ LVDS,
+ DP324x4,
+ DP324x2,
+ DP324x1
+};
+
+
+#define MC_BLOCK_COUNT 1
+#define CPL_BLOCK_COUNT 5
+#define SE_BLOCK_COUNT 15
+#define GC_BLOCK_COUNT 24
+
+struct SMU7_Local_Cac {
+ uint8_t BlockId;
+ uint8_t SignalId;
+ uint8_t Threshold;
+ uint8_t Padding;
+};
+
+typedef struct SMU7_Local_Cac SMU7_Local_Cac;
+
+struct SMU7_Local_Cac_Table {
+
+ SMU7_Local_Cac CplLocalCac[CPL_BLOCK_COUNT];
+ SMU7_Local_Cac McLocalCac[MC_BLOCK_COUNT];
+ SMU7_Local_Cac SeLocalCac[SE_BLOCK_COUNT];
+ SMU7_Local_Cac GcLocalCac[GC_BLOCK_COUNT];
+};
+
+typedef struct SMU7_Local_Cac_Table SMU7_Local_Cac_Table;
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+#endif
+
+// Description of Clock Gating bitmask for Tonga:
+// System Clock Gating
+#define CG_SYS_BITMASK_FIRST_BIT 0 // First bit of Sys CG bitmask
+#define CG_SYS_BITMASK_LAST_BIT 9 // Last bit of Sys CG bitmask
+#define CG_SYS_BIF_MGLS_SHIFT 0
+#define CG_SYS_ROM_SHIFT 1
+#define CG_SYS_MC_MGCG_SHIFT 2
+#define CG_SYS_MC_MGLS_SHIFT 3
+#define CG_SYS_SDMA_MGCG_SHIFT 4
+#define CG_SYS_SDMA_MGLS_SHIFT 5
+#define CG_SYS_DRM_MGCG_SHIFT 6
+#define CG_SYS_HDP_MGCG_SHIFT 7
+#define CG_SYS_HDP_MGLS_SHIFT 8
+#define CG_SYS_DRM_MGLS_SHIFT 9
+
+#define CG_SYS_BIF_MGLS_MASK 0x1
+#define CG_SYS_ROM_MASK 0x2
+#define CG_SYS_MC_MGCG_MASK 0x4
+#define CG_SYS_MC_MGLS_MASK 0x8
+#define CG_SYS_SDMA_MGCG_MASK 0x10
+#define CG_SYS_SDMA_MGLS_MASK 0x20
+#define CG_SYS_DRM_MGCG_MASK 0x40
+#define CG_SYS_HDP_MGCG_MASK 0x80
+#define CG_SYS_HDP_MGLS_MASK 0x100
+#define CG_SYS_DRM_MGLS_MASK 0x200
+
+// Graphics Clock Gating
+#define CG_GFX_BITMASK_FIRST_BIT 16 // First bit of Gfx CG bitmask
+#define CG_GFX_BITMASK_LAST_BIT 20 // Last bit of Gfx CG bitmask
+#define CG_GFX_CGCG_SHIFT 16
+#define CG_GFX_CGLS_SHIFT 17
+#define CG_CPF_MGCG_SHIFT 18
+#define CG_RLC_MGCG_SHIFT 19
+#define CG_GFX_OTHERS_MGCG_SHIFT 20
+
+#define CG_GFX_CGCG_MASK 0x00010000
+#define CG_GFX_CGLS_MASK 0x00020000
+#define CG_CPF_MGCG_MASK 0x00040000
+#define CG_RLC_MGCG_MASK 0x00080000
+#define CG_GFX_OTHERS_MGCG_MASK 0x00100000
+
+
+
+// Voltage Regulator Configuration
+// VR Config info is contained in dpmTable.VRConfig
+
+#define VRCONF_VDDC_MASK 0x000000FF
+#define VRCONF_VDDC_SHIFT 0
+#define VRCONF_VDDGFX_MASK 0x0000FF00
+#define VRCONF_VDDGFX_SHIFT 8
+#define VRCONF_VDDCI_MASK 0x00FF0000
+#define VRCONF_VDDCI_SHIFT 16
+#define VRCONF_MVDD_MASK 0xFF000000
+#define VRCONF_MVDD_SHIFT 24
+
+#define VR_MERGED_WITH_VDDC 0
+#define VR_SVI2_PLANE_1 1
+#define VR_SVI2_PLANE_2 2
+#define VR_SMIO_PATTERN_1 3
+#define VR_SMIO_PATTERN_2 4
+#define VR_STATIC_VOLTAGE 5
+
+// Clock Stretcher Configuration
+
+#define CLOCK_STRETCHER_MAX_ENTRIES 0x4
+#define CKS_LOOKUPTable_MAX_ENTRIES 0x4
+
+// The 'settings' field is subdivided in the following way:
+#define CLOCK_STRETCHER_SETTING_DDT_MASK 0x01
+#define CLOCK_STRETCHER_SETTING_DDT_SHIFT 0x0
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_MASK 0x1E
+#define CLOCK_STRETCHER_SETTING_STRETCH_AMOUNT_SHIFT 0x1
+#define CLOCK_STRETCHER_SETTING_ENABLE_MASK 0x80
+#define CLOCK_STRETCHER_SETTING_ENABLE_SHIFT 0x7
+
+struct SMU_ClockStretcherDataTableEntry {
+ uint8_t minVID;
+ uint8_t maxVID;
+
+
+ uint16_t setting;
+};
+typedef struct SMU_ClockStretcherDataTableEntry SMU_ClockStretcherDataTableEntry;
+
+struct SMU_ClockStretcherDataTable {
+ SMU_ClockStretcherDataTableEntry ClockStretcherDataTableEntry[CLOCK_STRETCHER_MAX_ENTRIES];
+};
+typedef struct SMU_ClockStretcherDataTable SMU_ClockStretcherDataTable;
+
+struct SMU_CKS_LOOKUPTableEntry {
+ uint16_t minFreq;
+ uint16_t maxFreq;
+
+ uint8_t setting;
+ uint8_t padding[3];
+};
+typedef struct SMU_CKS_LOOKUPTableEntry SMU_CKS_LOOKUPTableEntry;
+
+struct SMU_CKS_LOOKUPTable {
+ SMU_CKS_LOOKUPTableEntry CKS_LOOKUPTableEntry[CKS_LOOKUPTable_MAX_ENTRIES];
+};
+typedef struct SMU_CKS_LOOKUPTable SMU_CKS_LOOKUPTable;
+
+struct AgmAvfsData_t {
+ uint16_t avgPsmCount[28];
+ uint16_t minPsmCount[28];
+};
+typedef struct AgmAvfsData_t AgmAvfsData_t;
+
+// AVFS DEFINES
+
+enum VFT_COLUMNS {
+ SCLK0,
+ SCLK1,
+ SCLK2,
+ SCLK3,
+ SCLK4,
+ SCLK5,
+ SCLK6,
+ SCLK7,
+
+ NUM_VFT_COLUMNS
+};
+
+#define TEMP_RANGE_MAXSTEPS 12
+struct VFT_CELL_t {
+ uint16_t Voltage;
+};
+
+typedef struct VFT_CELL_t VFT_CELL_t;
+
+struct VFT_TABLE_t {
+ VFT_CELL_t Cell[TEMP_RANGE_MAXSTEPS][NUM_VFT_COLUMNS];
+ uint16_t AvfsGbv [NUM_VFT_COLUMNS];
+ uint16_t BtcGbv [NUM_VFT_COLUMNS];
+ uint16_t Temperature [TEMP_RANGE_MAXSTEPS];
+
+ uint8_t NumTemperatureSteps;
+ uint8_t padding[3];
+};
+typedef struct VFT_TABLE_t VFT_TABLE_t;
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h b/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h
new file mode 100644
index 000000000000..5916be08a7fe
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2015 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 _SMU73_DISCRETE_H_
+#define _SMU73_DISCRETE_H_
+
+#include "smu73.h"
+
+#pragma pack(push, 1)
+
+struct SMIO_Pattern
+{
+ uint16_t Voltage;
+ uint8_t Smio;
+ uint8_t padding;
+};
+
+typedef struct SMIO_Pattern SMIO_Pattern;
+
+struct SMIO_Table
+{
+ SMIO_Pattern Pattern[SMU_MAX_SMIO_LEVELS];
+};
+
+typedef struct SMIO_Table SMIO_Table;
+
+struct SMU73_Discrete_GraphicsLevel {
+ uint32_t MinVoltage;
+
+ uint32_t SclkFrequency;
+
+ uint8_t pcieDpmLevel;
+ uint8_t DeepSleepDivId;
+ uint16_t ActivityLevel;
+ uint32_t CgSpllFuncCntl3;
+ uint32_t CgSpllFuncCntl4;
+ uint32_t SpllSpreadSpectrum;
+ uint32_t SpllSpreadSpectrum2;
+ uint32_t CcPwrDynRm;
+ uint32_t CcPwrDynRm1;
+ uint8_t SclkDid;
+ uint8_t DisplayWatermark;
+ uint8_t EnabledForActivity;
+ uint8_t EnabledForThrottle;
+ uint8_t UpHyst;
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t PowerThrottle;
+};
+
+typedef struct SMU73_Discrete_GraphicsLevel SMU73_Discrete_GraphicsLevel;
+
+struct SMU73_Discrete_ACPILevel {
+ uint32_t Flags;
+ uint32_t MinVoltage;
+ uint32_t SclkFrequency;
+ uint8_t SclkDid;
+ uint8_t DisplayWatermark;
+ uint8_t DeepSleepDivId;
+ uint8_t padding;
+ uint32_t CgSpllFuncCntl;
+ uint32_t CgSpllFuncCntl2;
+ uint32_t CgSpllFuncCntl3;
+ uint32_t CgSpllFuncCntl4;
+ uint32_t SpllSpreadSpectrum;
+ uint32_t SpllSpreadSpectrum2;
+ uint32_t CcPwrDynRm;
+ uint32_t CcPwrDynRm1;
+};
+
+typedef struct SMU73_Discrete_ACPILevel SMU73_Discrete_ACPILevel;
+
+struct SMU73_Discrete_Ulv {
+ uint32_t CcPwrDynRm;
+ uint32_t CcPwrDynRm1;
+ uint16_t VddcOffset;
+ uint8_t VddcOffsetVid;
+ uint8_t VddcPhase;
+ uint32_t Reserved;
+};
+
+typedef struct SMU73_Discrete_Ulv SMU73_Discrete_Ulv;
+
+struct SMU73_Discrete_MemoryLevel
+{
+ uint32_t MinVoltage;
+ uint32_t MinMvdd;
+
+ uint32_t MclkFrequency;
+
+ uint8_t StutterEnable;
+ uint8_t FreqRange;
+ uint8_t EnabledForThrottle;
+ uint8_t EnabledForActivity;
+
+ uint8_t UpHyst;
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t padding;
+
+ uint16_t ActivityLevel;
+ uint8_t DisplayWatermark;
+ uint8_t MclkDivider;
+};
+
+typedef struct SMU73_Discrete_MemoryLevel SMU73_Discrete_MemoryLevel;
+
+struct SMU73_Discrete_LinkLevel
+{
+ uint8_t PcieGenSpeed; ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3
+ uint8_t PcieLaneCount; ///< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16
+ uint8_t EnabledForActivity;
+ uint8_t SPC;
+ uint32_t DownThreshold;
+ uint32_t UpThreshold;
+ uint32_t Reserved;
+};
+
+typedef struct SMU73_Discrete_LinkLevel SMU73_Discrete_LinkLevel;
+
+
+// MC ARB DRAM Timing registers.
+struct SMU73_Discrete_MCArbDramTimingTableEntry
+{
+ uint32_t McArbDramTiming;
+ uint32_t McArbDramTiming2;
+ uint8_t McArbBurstTime;
+ uint8_t TRRDS;
+ uint8_t TRRDL;
+ uint8_t padding;
+};
+
+typedef struct SMU73_Discrete_MCArbDramTimingTableEntry SMU73_Discrete_MCArbDramTimingTableEntry;
+
+struct SMU73_Discrete_MCArbDramTimingTable
+{
+ SMU73_Discrete_MCArbDramTimingTableEntry entries[SMU__NUM_SCLK_DPM_STATE][SMU__NUM_MCLK_DPM_LEVELS];
+};
+
+typedef struct SMU73_Discrete_MCArbDramTimingTable SMU73_Discrete_MCArbDramTimingTable;
+
+// UVD VCLK/DCLK state (level) definition.
+struct SMU73_Discrete_UvdLevel
+{
+ uint32_t VclkFrequency;
+ uint32_t DclkFrequency;
+ uint32_t MinVoltage;
+ uint8_t VclkDivider;
+ uint8_t DclkDivider;
+ uint8_t padding[2];
+};
+
+typedef struct SMU73_Discrete_UvdLevel SMU73_Discrete_UvdLevel;
+
+// Clocks for other external blocks (VCE, ACP, SAMU).
+struct SMU73_Discrete_ExtClkLevel
+{
+ uint32_t Frequency;
+ uint32_t MinVoltage;
+ uint8_t Divider;
+ uint8_t padding[3];
+};
+
+typedef struct SMU73_Discrete_ExtClkLevel SMU73_Discrete_ExtClkLevel;
+
+struct SMU73_Discrete_StateInfo
+{
+ uint32_t SclkFrequency;
+ uint32_t MclkFrequency;
+ uint32_t VclkFrequency;
+ uint32_t DclkFrequency;
+ uint32_t SamclkFrequency;
+ uint32_t AclkFrequency;
+ uint32_t EclkFrequency;
+ uint16_t MvddVoltage;
+ uint16_t padding16;
+ uint8_t DisplayWatermark;
+ uint8_t McArbIndex;
+ uint8_t McRegIndex;
+ uint8_t SeqIndex;
+ uint8_t SclkDid;
+ int8_t SclkIndex;
+ int8_t MclkIndex;
+ uint8_t PCIeGen;
+
+};
+
+typedef struct SMU73_Discrete_StateInfo SMU73_Discrete_StateInfo;
+
+struct SMU73_Discrete_DpmTable
+{
+ // Multi-DPM controller settings
+ SMU73_PIDController GraphicsPIDController;
+ SMU73_PIDController MemoryPIDController;
+ SMU73_PIDController LinkPIDController;
+
+ uint32_t SystemFlags;
+
+ // SMIO masks for voltage and phase controls
+ uint32_t VRConfig;
+ uint32_t SmioMask1;
+ uint32_t SmioMask2;
+ SMIO_Table SmioTable1;
+ SMIO_Table SmioTable2;
+
+ uint32_t MvddLevelCount;
+
+
+ uint8_t BapmVddcVidHiSidd [SMU73_MAX_LEVELS_VDDC];
+ uint8_t BapmVddcVidLoSidd [SMU73_MAX_LEVELS_VDDC];
+ uint8_t BapmVddcVidHiSidd2 [SMU73_MAX_LEVELS_VDDC];
+
+ uint8_t GraphicsDpmLevelCount;
+ uint8_t MemoryDpmLevelCount;
+ uint8_t LinkLevelCount;
+ uint8_t MasterDeepSleepControl;
+
+ uint8_t UvdLevelCount;
+ uint8_t VceLevelCount;
+ uint8_t AcpLevelCount;
+ uint8_t SamuLevelCount;
+
+ uint8_t ThermOutGpio;
+ uint8_t ThermOutPolarity;
+ uint8_t ThermOutMode;
+ uint8_t BootPhases;
+ uint32_t Reserved[4];
+
+ // State table entries for each DPM state
+ SMU73_Discrete_GraphicsLevel GraphicsLevel [SMU73_MAX_LEVELS_GRAPHICS];
+ SMU73_Discrete_MemoryLevel MemoryACPILevel;
+ SMU73_Discrete_MemoryLevel MemoryLevel [SMU73_MAX_LEVELS_MEMORY];
+ SMU73_Discrete_LinkLevel LinkLevel [SMU73_MAX_LEVELS_LINK];
+ SMU73_Discrete_ACPILevel ACPILevel;
+ SMU73_Discrete_UvdLevel UvdLevel [SMU73_MAX_LEVELS_UVD];
+ SMU73_Discrete_ExtClkLevel VceLevel [SMU73_MAX_LEVELS_VCE];
+ SMU73_Discrete_ExtClkLevel AcpLevel [SMU73_MAX_LEVELS_ACP];
+ SMU73_Discrete_ExtClkLevel SamuLevel [SMU73_MAX_LEVELS_SAMU];
+ SMU73_Discrete_Ulv Ulv;
+
+ uint32_t SclkStepSize;
+ uint32_t Smio [SMU73_MAX_ENTRIES_SMIO];
+
+ uint8_t UvdBootLevel;
+ uint8_t VceBootLevel;
+ uint8_t AcpBootLevel;
+ uint8_t SamuBootLevel;
+
+ uint8_t GraphicsBootLevel;
+ uint8_t GraphicsVoltageChangeEnable;
+ uint8_t GraphicsThermThrottleEnable;
+ uint8_t GraphicsInterval;
+
+ uint8_t VoltageInterval;
+ uint8_t ThermalInterval;
+ uint16_t TemperatureLimitHigh;
+
+ uint16_t TemperatureLimitLow;
+ uint8_t MemoryBootLevel;
+ uint8_t MemoryVoltageChangeEnable;
+
+ uint16_t BootMVdd;
+ uint8_t MemoryInterval;
+ uint8_t MemoryThermThrottleEnable;
+
+ uint16_t VoltageResponseTime;
+ uint16_t PhaseResponseTime;
+
+ uint8_t PCIeBootLinkLevel;
+ uint8_t PCIeGenInterval;
+ uint8_t DTEInterval;
+ uint8_t DTEMode;
+
+ uint8_t SVI2Enable;
+ uint8_t VRHotGpio;
+ uint8_t AcDcGpio;
+ uint8_t ThermGpio;
+
+ uint16_t PPM_PkgPwrLimit;
+ uint16_t PPM_TemperatureLimit;
+
+ uint16_t DefaultTdp;
+ uint16_t TargetTdp;
+
+ uint16_t FpsHighThreshold;
+ uint16_t FpsLowThreshold;
+
+ uint16_t TemperatureLimitEdge;
+ uint16_t TemperatureLimitHotspot;
+ uint16_t TemperatureLimitLiquid1;
+ uint16_t TemperatureLimitLiquid2;
+ uint16_t TemperatureLimitVrVddc;
+ uint16_t TemperatureLimitVrMvdd;
+ uint16_t TemperatureLimitPlx;
+
+ uint16_t FanGainEdge;
+ uint16_t FanGainHotspot;
+ uint16_t FanGainLiquid;
+ uint16_t FanGainVrVddc;
+ uint16_t FanGainVrMvdd;
+ uint16_t FanGainPlx;
+ uint16_t FanGainHbm;
+
+ uint8_t Liquid1_I2C_address;
+ uint8_t Liquid2_I2C_address;
+ uint8_t Vr_I2C_address;
+ uint8_t Plx_I2C_address;
+
+ uint8_t GeminiMode;
+ uint8_t spare17[3];
+ uint32_t GeminiApertureHigh;
+ uint32_t GeminiApertureLow;
+
+ uint8_t Liquid_I2C_LineSCL;
+ uint8_t Liquid_I2C_LineSDA;
+ uint8_t Vr_I2C_LineSCL;
+ uint8_t Vr_I2C_LineSDA;
+ uint8_t Plx_I2C_LineSCL;
+ uint8_t Plx_I2C_LineSDA;
+
+ uint8_t spare1253[2];
+ uint32_t spare123[2];
+
+ uint8_t DTEAmbientTempBase;
+ uint8_t DTETjOffset;
+ uint8_t GpuTjMax;
+ uint8_t GpuTjHyst;
+
+ uint16_t BootVddc;
+ uint16_t BootVddci;
+
+ uint32_t BAPM_TEMP_GRADIENT;
+
+ uint32_t LowSclkInterruptThreshold;
+ uint32_t VddGfxReChkWait;
+
+ uint8_t ClockStretcherAmount;
+ uint8_t Sclk_CKS_masterEn0_7;
+ uint8_t Sclk_CKS_masterEn8_15;
+ uint8_t DPMFreezeAndForced;
+
+ uint8_t Sclk_voltageOffset[8];
+
+ SMU_ClockStretcherDataTable ClockStretcherDataTable;
+ SMU_CKS_LOOKUPTable CKS_LOOKUPTable;
+};
+
+typedef struct SMU73_Discrete_DpmTable SMU73_Discrete_DpmTable;
+
+
+// --------------------------------------------------- Fan Table -----------------------------------------------------------
+struct SMU73_Discrete_FanTable
+{
+ uint16_t FdoMode;
+ int16_t TempMin;
+ int16_t TempMed;
+ int16_t TempMax;
+ int16_t Slope1;
+ int16_t Slope2;
+ int16_t FdoMin;
+ int16_t HystUp;
+ int16_t HystDown;
+ int16_t HystSlope;
+ int16_t TempRespLim;
+ int16_t TempCurr;
+ int16_t SlopeCurr;
+ int16_t PwmCurr;
+ uint32_t RefreshPeriod;
+ int16_t FdoMax;
+ uint8_t TempSrc;
+ int8_t Padding;
+};
+
+typedef struct SMU73_Discrete_FanTable SMU73_Discrete_FanTable;
+
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG 4
+#define SMU7_DISCRETE_GPIO_SCLK_DEBUG_BIT (0x1 << SMU7_DISCRETE_GPIO_SCLK_DEBUG)
+
+
+
+struct SMU7_MclkDpmScoreboard
+{
+
+ uint32_t PercentageBusy;
+
+ int32_t PIDError;
+ int32_t PIDIntegral;
+ int32_t PIDOutput;
+
+ uint32_t SigmaDeltaAccum;
+ uint32_t SigmaDeltaOutput;
+ uint32_t SigmaDeltaLevel;
+
+ uint32_t UtilizationSetpoint;
+
+ uint8_t TdpClampMode;
+ uint8_t TdcClampMode;
+ uint8_t ThermClampMode;
+ uint8_t VoltageBusy;
+
+ int8_t CurrLevel;
+ int8_t TargLevel;
+ uint8_t LevelChangeInProgress;
+ uint8_t UpHyst;
+
+ uint8_t DownHyst;
+ uint8_t VoltageDownHyst;
+ uint8_t DpmEnable;
+ uint8_t DpmRunning;
+
+ uint8_t DpmForce;
+ uint8_t DpmForceLevel;
+ uint8_t DisplayWatermark;
+ uint8_t McArbIndex;
+
+ uint32_t MinimumPerfMclk;
+
+ uint8_t AcpiReq;
+ uint8_t AcpiAck;
+ uint8_t MclkSwitchInProgress;
+ uint8_t MclkSwitchCritical;
+
+ uint8_t IgnoreVBlank;
+ uint8_t TargetMclkIndex;
+ uint8_t TargetMvddIndex;
+ uint8_t MclkSwitchResult;
+
+ uint16_t VbiFailureCount;
+ uint8_t VbiWaitCounter;
+ uint8_t EnabledLevelsChange;
+
+ uint16_t LevelResidencyCounters [SMU73_MAX_LEVELS_MEMORY];
+ uint16_t LevelSwitchCounters [SMU73_MAX_LEVELS_MEMORY];
+
+ void (*TargetStateCalculator)(uint8_t);
+ void (*SavedTargetStateCalculator)(uint8_t);
+
+ uint16_t AutoDpmInterval;
+ uint16_t AutoDpmRange;
+
+ uint16_t VbiTimeoutCount;
+ uint16_t MclkSwitchingTime;
+
+ uint8_t fastSwitch;
+ uint8_t Save_PIC_VDDGFX_EXIT;
+ uint8_t Save_PIC_VDDGFX_ENTER;
+ uint8_t padding;
+
+};
+
+typedef struct SMU7_MclkDpmScoreboard SMU7_MclkDpmScoreboard;
+
+struct SMU7_UlvScoreboard
+{
+ uint8_t EnterUlv;
+ uint8_t ExitUlv;
+ uint8_t UlvActive;
+ uint8_t WaitingForUlv;
+ uint8_t UlvEnable;
+ uint8_t UlvRunning;
+ uint8_t UlvMasterEnable;
+ uint8_t padding;
+ uint32_t UlvAbortedCount;
+ uint32_t UlvTimeStamp;
+};
+
+typedef struct SMU7_UlvScoreboard SMU7_UlvScoreboard;
+
+struct VddgfxSavedRegisters
+{
+ uint32_t GPU_DBG[3];
+ uint32_t MEC_BaseAddress_Hi;
+ uint32_t MEC_BaseAddress_Lo;
+ uint32_t THM_TMON0_CTRL2__RDIR_PRESENT;
+ uint32_t THM_TMON1_CTRL2__RDIR_PRESENT;
+ uint32_t CP_INT_CNTL;
+};
+
+typedef struct VddgfxSavedRegisters VddgfxSavedRegisters;
+
+struct SMU7_VddGfxScoreboard
+{
+ uint8_t VddGfxEnable;
+ uint8_t VddGfxActive;
+ uint8_t VPUResetOccured;
+ uint8_t padding;
+
+ uint32_t VddGfxEnteredCount;
+ uint32_t VddGfxAbortedCount;
+
+ uint32_t VddGfxVid;
+
+ VddgfxSavedRegisters SavedRegisters;
+};
+
+typedef struct SMU7_VddGfxScoreboard SMU7_VddGfxScoreboard;
+
+struct SMU7_TdcLimitScoreboard {
+ uint8_t Enable;
+ uint8_t Running;
+ uint16_t Alpha;
+ uint32_t FilteredIddc;
+ uint32_t IddcLimit;
+ uint32_t IddcHyst;
+ SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_TdcLimitScoreboard SMU7_TdcLimitScoreboard;
+
+struct SMU7_PkgPwrLimitScoreboard {
+ uint8_t Enable;
+ uint8_t Running;
+ uint16_t Alpha;
+ uint32_t FilteredPkgPwr;
+ uint32_t Limit;
+ uint32_t Hyst;
+ uint32_t LimitFromDriver;
+ SMU7_HystController_Data HystControllerData;
+};
+
+typedef struct SMU7_PkgPwrLimitScoreboard SMU7_PkgPwrLimitScoreboard;
+
+struct SMU7_BapmScoreboard {
+ uint32_t source_powers[SMU73_DTE_SOURCES];
+ uint32_t source_powers_last[SMU73_DTE_SOURCES];
+ int32_t entity_temperatures[SMU73_NUM_GPU_TES];
+ int32_t initial_entity_temperatures[SMU73_NUM_GPU_TES];
+ int32_t Limit;
+ int32_t Hyst;
+ int32_t therm_influence_coeff_table[SMU73_DTE_ITERATIONS * SMU73_DTE_SOURCES * SMU73_DTE_SINKS * 2];
+ int32_t therm_node_table[SMU73_DTE_ITERATIONS * SMU73_DTE_SOURCES * SMU73_DTE_SINKS];
+ uint16_t ConfigTDPPowerScalar;
+ uint16_t FanSpeedPowerScalar;
+ uint16_t OverDrivePowerScalar;
+ uint16_t OverDriveLimitScalar;
+ uint16_t FinalPowerScalar;
+ uint8_t VariantID;
+ uint8_t spare997;
+
+ SMU7_HystController_Data HystControllerData;
+
+ int32_t temperature_gradient_slope;
+ int32_t temperature_gradient;
+ uint32_t measured_temperature;
+};
+
+
+typedef struct SMU7_BapmScoreboard SMU7_BapmScoreboard;
+
+struct SMU7_AcpiScoreboard {
+ uint32_t SavedInterruptMask[2];
+ uint8_t LastACPIRequest;
+ uint8_t CgBifResp;
+ uint8_t RequestType;
+ uint8_t Padding;
+ SMU73_Discrete_ACPILevel D0Level;
+};
+
+typedef struct SMU7_AcpiScoreboard SMU7_AcpiScoreboard;
+
+struct SMU_QuadraticCoeffs {
+ int32_t m1;
+ uint32_t b;
+
+ int16_t m2;
+ uint8_t m1_shift;
+ uint8_t m2_shift;
+};
+
+typedef struct SMU_QuadraticCoeffs SMU_QuadraticCoeffs;
+
+struct SMU73_Discrete_PmFuses {
+ /* dw0-dw1 */
+ uint8_t BapmVddCVidHiSidd[8];
+
+ /* dw2-dw3 */
+ uint8_t BapmVddCVidLoSidd[8];
+
+ /* dw4-dw5 */
+ uint8_t VddCVid[8];
+
+ /* dw1*/
+ uint8_t SviLoadLineEn;
+ uint8_t SviLoadLineVddC;
+ uint8_t SviLoadLineTrimVddC;
+ uint8_t SviLoadLineOffsetVddC;
+
+ /* dw2 */
+ uint16_t TDC_VDDC_PkgLimit;
+ uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
+ uint8_t TDC_MAWt;
+
+ /* dw3 */
+ uint8_t TdcWaterfallCtl;
+ uint8_t LPMLTemperatureMin;
+ uint8_t LPMLTemperatureMax;
+ uint8_t Reserved;
+
+ /* dw4-dw7 */
+ uint8_t LPMLTemperatureScaler[16];
+
+ /* dw8-dw9 */
+ int16_t FuzzyFan_ErrorSetDelta;
+ int16_t FuzzyFan_ErrorRateSetDelta;
+ int16_t FuzzyFan_PwmSetDelta;
+ uint16_t Reserved6;
+
+ /* dw10-dw14 */
+ uint8_t GnbLPML[16];
+
+ /* dw15 */
+ uint8_t GnbLPMLMaxVid;
+ uint8_t GnbLPMLMinVid;
+ uint8_t Reserved1[2];
+
+ /* dw16 */
+ uint16_t BapmVddCBaseLeakageHiSidd;
+ uint16_t BapmVddCBaseLeakageLoSidd;
+
+ /* AVFS */
+ uint16_t VFT_Temp[3];
+ uint16_t padding;
+
+ SMU_QuadraticCoeffs VFT_ATE[3];
+
+ SMU_QuadraticCoeffs AVFS_GB;
+ SMU_QuadraticCoeffs ATE_ACBTC_GB;
+
+ SMU_QuadraticCoeffs P2V;
+
+ uint32_t PsmCharzFreq;
+
+ uint16_t InversionVoltage;
+ uint16_t PsmCharzTemp;
+
+ uint32_t EnabledAvfsModules;
+};
+
+typedef struct SMU73_Discrete_PmFuses SMU73_Discrete_PmFuses;
+
+struct SMU7_Discrete_Log_Header_Table {
+ uint32_t version;
+ uint32_t asic_id;
+ uint16_t flags;
+ uint16_t entry_size;
+ uint32_t total_size;
+ uint32_t num_of_entries;
+ uint8_t type;
+ uint8_t mode;
+ uint8_t filler_0[2];
+ uint32_t filler_1[2];
+};
+
+typedef struct SMU7_Discrete_Log_Header_Table SMU7_Discrete_Log_Header_Table;
+
+struct SMU7_Discrete_Log_Cntl {
+ uint8_t Enabled;
+ uint8_t Type;
+ uint8_t padding[2];
+ uint32_t BufferSize;
+ uint32_t SamplesLogged;
+ uint32_t SampleSize;
+ uint32_t AddrL;
+ uint32_t AddrH;
+};
+
+typedef struct SMU7_Discrete_Log_Cntl SMU7_Discrete_Log_Cntl;
+
+#define CAC_ACC_NW_NUM_OF_SIGNALS 87
+
+struct SMU7_Discrete_Cac_Collection_Table {
+ uint32_t temperature;
+ uint32_t cac_acc_nw[CAC_ACC_NW_NUM_OF_SIGNALS];
+};
+
+typedef struct SMU7_Discrete_Cac_Collection_Table SMU7_Discrete_Cac_Collection_Table;
+
+struct SMU7_Discrete_Cac_Verification_Table {
+ uint32_t VddcTotalPower;
+ uint32_t VddcLeakagePower;
+ uint32_t VddcConstantPower;
+ uint32_t VddcGfxDynamicPower;
+ uint32_t VddcUvdDynamicPower;
+ uint32_t VddcVceDynamicPower;
+ uint32_t VddcAcpDynamicPower;
+ uint32_t VddcPcieDynamicPower;
+ uint32_t VddcDceDynamicPower;
+ uint32_t VddcCurrent;
+ uint32_t VddcVoltage;
+ uint32_t VddciTotalPower;
+ uint32_t VddciLeakagePower;
+ uint32_t VddciConstantPower;
+ uint32_t VddciDynamicPower;
+ uint32_t Vddr1TotalPower;
+ uint32_t Vddr1LeakagePower;
+ uint32_t Vddr1ConstantPower;
+ uint32_t Vddr1DynamicPower;
+ uint32_t spare[4];
+ uint32_t temperature;
+};
+
+typedef struct SMU7_Discrete_Cac_Verification_Table SMU7_Discrete_Cac_Verification_Table;
+
+struct SMU7_Discrete_Pm_Status_Table {
+ //Thermal entities
+ int32_t T_meas_max[SMU73_THERMAL_INPUT_LOOP_COUNT];
+ int32_t T_meas_acc[SMU73_THERMAL_INPUT_LOOP_COUNT];
+ int32_t T_meas_acc_cnt[SMU73_THERMAL_INPUT_LOOP_COUNT];
+ uint32_t T_hbm_acc;
+
+ //Voltage domains
+ uint32_t I_calc_max;
+ uint32_t I_calc_acc;
+ uint32_t P_meas_acc;
+ uint32_t V_meas_load_acc;
+ uint32_t I_meas_acc;
+ uint32_t P_meas_acc_vddci;
+ uint32_t V_meas_load_acc_vddci;
+ uint32_t I_meas_acc_vddci;
+
+ //Frequency
+ uint16_t Sclk_dpm_residency[8];
+ uint16_t Uvd_dpm_residency[8];
+ uint16_t Vce_dpm_residency[8];
+
+ //Chip
+ uint32_t P_roc_acc;
+ uint32_t PkgPwr_max;
+ uint32_t PkgPwr_acc;
+ uint32_t MclkSwitchingTime_max;
+ uint32_t MclkSwitchingTime_acc;
+ uint32_t FanPwm_acc;
+ uint32_t FanRpm_acc;
+ uint32_t Gfx_busy_acc;
+ uint32_t Mc_busy_acc;
+ uint32_t Fps_acc;
+
+ uint32_t AccCnt;
+};
+
+typedef struct SMU7_Discrete_Pm_Status_Table SMU7_Discrete_Pm_Status_Table;
+
+//FIXME THESE NEED TO BE UPDATED
+#define SMU7_SCLK_CAC 0x561
+#define SMU7_MCLK_CAC 0xF9
+#define SMU7_VCLK_CAC 0x2DE
+#define SMU7_DCLK_CAC 0x2DE
+#define SMU7_ECLK_CAC 0x25E
+#define SMU7_ACLK_CAC 0x25E
+#define SMU7_SAMCLK_CAC 0x25E
+#define SMU7_DISPCLK_CAC 0x100
+#define SMU7_CAC_CONSTANT 0x2EE3430
+#define SMU7_CAC_CONSTANT_SHIFT 18
+
+#define SMU7_VDDCI_MCLK_CONST 1765
+#define SMU7_VDDCI_MCLK_CONST_SHIFT 16
+#define SMU7_VDDCI_VDDCI_CONST 50958
+#define SMU7_VDDCI_VDDCI_CONST_SHIFT 14
+#define SMU7_VDDCI_CONST 11781
+#define SMU7_VDDCI_STROBE_PWR 1331
+
+#define SMU7_VDDR1_CONST 693
+#define SMU7_VDDR1_CAC_WEIGHT 20
+#define SMU7_VDDR1_CAC_WEIGHT_SHIFT 19
+#define SMU7_VDDR1_STROBE_PWR 512
+
+#define SMU7_AREA_COEFF_UVD 0xA78
+#define SMU7_AREA_COEFF_VCE 0x190A
+#define SMU7_AREA_COEFF_ACP 0x22D1
+#define SMU7_AREA_COEFF_SAMU 0x534
+
+//ThermOutMode values
+#define SMU7_THERM_OUT_MODE_DISABLE 0x0
+#define SMU7_THERM_OUT_MODE_THERM_ONLY 0x1
+#define SMU7_THERM_OUT_MODE_THERM_VRHOT 0x2
+
+#pragma pack(pop)
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/amdgpu/smu7_discrete.h b/drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h
index 0b0b404ff091..0b0b404ff091 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu7_discrete.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h
diff --git a/drivers/gpu/drm/amd/amdgpu/smu7_fusion.h b/drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h
index 78ada9ffd508..78ada9ffd508 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu7_fusion.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h
diff --git a/drivers/gpu/drm/amd/amdgpu/smu8.h b/drivers/gpu/drm/amd/powerplay/inc/smu8.h
index d758d07b6a31..d758d07b6a31 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu8.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu8.h
diff --git a/drivers/gpu/drm/amd/amdgpu/smu8_fusion.h b/drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h
index 5c9cc3c0bbfa..0c37c94e9414 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu8_fusion.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h
@@ -48,6 +48,14 @@ struct SMU8_Port80MonitorTable {
uint8_t EnableDramShadow;
};
+/* Display specific power management parameters */
+#define PWRMGT_SEPARATION_TIME_SHIFT 0
+#define PWRMGT_SEPARATION_TIME_MASK 0xFFFF
+#define PWRMGT_DISABLE_CPU_CSTATES_SHIFT 16
+#define PWRMGT_DISABLE_CPU_CSTATES_MASK 0x1
+#define PWRMGT_DISABLE_CPU_PSTATES_SHIFT 24
+#define PWRMGT_DISABLE_CPU_PSTATES_MASK 0x1
+
/* Clock Table Definitions */
#define NUM_SCLK_LEVELS 8
#define NUM_LCLK_LEVELS 8
diff --git a/drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_cz.h b/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h
index f8ba071f39c8..f8ba071f39c8 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_cz.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h b/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h
new file mode 100644
index 000000000000..c24a81eebc7c
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h
@@ -0,0 +1,100 @@
+/*
+ * 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 SMU_UCODE_XFER_VI_H
+#define SMU_UCODE_XFER_VI_H
+
+#define SMU_DRAMData_TOC_VERSION 1
+#define MAX_IH_REGISTER_COUNT 65535
+#define SMU_DIGEST_SIZE_BYTES 20
+#define SMU_FB_SIZE_BYTES 1048576
+#define SMU_MAX_ENTRIES 12
+
+#define UCODE_ID_SMU 0
+#define UCODE_ID_SDMA0 1
+#define UCODE_ID_SDMA1 2
+#define UCODE_ID_CP_CE 3
+#define UCODE_ID_CP_PFP 4
+#define UCODE_ID_CP_ME 5
+#define UCODE_ID_CP_MEC 6
+#define UCODE_ID_CP_MEC_JT1 7
+#define UCODE_ID_CP_MEC_JT2 8
+#define UCODE_ID_GMCON_RENG 9
+#define UCODE_ID_RLC_G 10
+#define UCODE_ID_IH_REG_RESTORE 11
+#define UCODE_ID_VBIOS 12
+#define UCODE_ID_MISC_METADATA 13
+#define UCODE_ID_RLC_SCRATCH 32
+#define UCODE_ID_RLC_SRM_ARAM 33
+#define UCODE_ID_RLC_SRM_DRAM 34
+#define UCODE_ID_MEC_STORAGE 35
+#define UCODE_ID_VBIOS_PARAMETERS 36
+#define UCODE_META_DATA 0xFF
+
+#define UCODE_ID_SMU_MASK 0x00000001
+#define UCODE_ID_SDMA0_MASK 0x00000002
+#define UCODE_ID_SDMA1_MASK 0x00000004
+#define UCODE_ID_CP_CE_MASK 0x00000008
+#define UCODE_ID_CP_PFP_MASK 0x00000010
+#define UCODE_ID_CP_ME_MASK 0x00000020
+#define UCODE_ID_CP_MEC_MASK 0x00000040
+#define UCODE_ID_CP_MEC_JT1_MASK 0x00000080
+#define UCODE_ID_CP_MEC_JT2_MASK 0x00000100
+#define UCODE_ID_GMCON_RENG_MASK 0x00000200
+#define UCODE_ID_RLC_G_MASK 0x00000400
+#define UCODE_ID_IH_REG_RESTORE_MASK 0x00000800
+#define UCODE_ID_VBIOS_MASK 0x00001000
+
+#define UCODE_FLAG_UNHALT_MASK 0x1
+
+struct SMU_Entry {
+#ifndef __BIG_ENDIAN
+ uint16_t id;
+ uint16_t version;
+ uint32_t image_addr_high;
+ uint32_t image_addr_low;
+ uint32_t meta_data_addr_high;
+ uint32_t meta_data_addr_low;
+ uint32_t data_size_byte;
+ uint16_t flags;
+ uint16_t num_register_entries;
+#else
+ uint16_t version;
+ uint16_t id;
+ uint32_t image_addr_high;
+ uint32_t image_addr_low;
+ uint32_t meta_data_addr_high;
+ uint32_t meta_data_addr_low;
+ uint32_t data_size_byte;
+ uint16_t num_register_entries;
+ uint16_t flags;
+#endif
+};
+
+struct SMU_DRAMData_TOC {
+ uint32_t structure_version;
+ uint32_t num_entries;
+ struct SMU_Entry entry[SMU_MAX_ENTRIES];
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
new file mode 100644
index 000000000000..504f035d1843
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2015 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 _SMUMGR_H_
+#define _SMUMGR_H_
+#include <linux/types.h>
+#include "pp_instance.h"
+#include "amd_powerplay.h"
+
+struct pp_smumgr;
+struct pp_instance;
+
+#define smu_lower_32_bits(n) ((uint32_t)(n))
+#define smu_upper_32_bits(n) ((uint32_t)(((n)>>16)>>16))
+
+struct pp_smumgr_func {
+ int (*smu_init)(struct pp_smumgr *smumgr);
+ int (*smu_fini)(struct pp_smumgr *smumgr);
+ int (*start_smu)(struct pp_smumgr *smumgr);
+ int (*check_fw_load_finish)(struct pp_smumgr *smumgr,
+ uint32_t firmware);
+ int (*request_smu_load_fw)(struct pp_smumgr *smumgr);
+ int (*request_smu_load_specific_fw)(struct pp_smumgr *smumgr,
+ uint32_t firmware);
+ int (*get_argument)(struct pp_smumgr *smumgr);
+ int (*send_msg_to_smc)(struct pp_smumgr *smumgr, uint16_t msg);
+ int (*send_msg_to_smc_with_parameter)(struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter);
+ int (*download_pptable_settings)(struct pp_smumgr *smumgr,
+ void **table);
+ int (*upload_pptable_settings)(struct pp_smumgr *smumgr);
+};
+
+struct pp_smumgr {
+ uint32_t chip_family;
+ uint32_t chip_id;
+ uint32_t hw_revision;
+ void *device;
+ void *backend;
+ uint32_t usec_timeout;
+ bool reload_fw;
+ const struct pp_smumgr_func *smumgr_funcs;
+};
+
+
+extern int smum_init(struct amd_pp_init *pp_init,
+ struct pp_instance *handle);
+
+extern int smum_fini(struct pp_smumgr *smumgr);
+
+extern int smum_get_argument(struct pp_smumgr *smumgr);
+
+extern int smum_download_powerplay_table(struct pp_smumgr *smumgr, void **table);
+
+extern int smum_upload_powerplay_table(struct pp_smumgr *smumgr);
+
+extern int smum_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg);
+
+extern int smum_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter);
+
+extern int smum_wait_on_register(struct pp_smumgr *smumgr,
+ uint32_t index, uint32_t value, uint32_t mask);
+
+extern int smum_wait_for_register_unequal(struct pp_smumgr *smumgr,
+ uint32_t index, uint32_t value, uint32_t mask);
+
+extern int smum_wait_on_indirect_register(struct pp_smumgr *smumgr,
+ uint32_t indirect_port, uint32_t index,
+ uint32_t value, uint32_t mask);
+
+
+extern void smum_wait_for_indirect_register_unequal(
+ struct pp_smumgr *smumgr,
+ uint32_t indirect_port, uint32_t index,
+ uint32_t value, uint32_t mask);
+
+extern int smu_allocate_memory(void *device, uint32_t size,
+ enum cgs_gpu_mem_type type,
+ uint32_t byte_align, uint64_t *mc_addr,
+ void **kptr, void *handle);
+
+extern int smu_free_memory(void *device, void *handle);
+
+#define SMUM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
+
+#define SMUM_FIELD_MASK(reg, field) reg##__##field##_MASK
+
+#define SMUM_WAIT_INDIRECT_REGISTER_GIVEN_INDEX(smumgr, \
+ port, index, value, mask) \
+ smum_wait_on_indirect_register(smumgr, \
+ mm##port##_INDEX, index, value, mask)
+
+
+#define SMUM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr, \
+ index, value, mask) \
+ smum_wait_for_register_unequal(smumgr, \
+ index, value, mask)
+
+#define SMUM_WAIT_REGISTER_UNEQUAL(smumgr, reg, value, mask) \
+ SMUM_WAIT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr, \
+ mm##reg, value, mask)
+
+#define SMUM_WAIT_FIELD_UNEQUAL(smumgr, reg, field, fieldval) \
+ SMUM_WAIT_REGISTER_UNEQUAL(smumgr, reg, \
+ (fieldval) << SMUM_FIELD_SHIFT(reg, field), \
+ SMUM_FIELD_MASK(reg, field))
+
+#define SMUM_GET_FIELD(value, reg, field) \
+ (((value) & SMUM_FIELD_MASK(reg, field)) \
+ >> SMUM_FIELD_SHIFT(reg, field))
+
+#define SMUM_READ_FIELD(device, reg, field) \
+ SMUM_GET_FIELD(cgs_read_register(device, mm##reg), reg, field)
+
+#define SMUM_SET_FIELD(value, reg, field, field_val) \
+ (((value) & ~SMUM_FIELD_MASK(reg, field)) | \
+ (SMUM_FIELD_MASK(reg, field) & ((field_val) << \
+ SMUM_FIELD_SHIFT(reg, field))))
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(smumgr, \
+ port, index, value, mask) \
+ smum_wait_on_indirect_register(smumgr, \
+ mm##port##_INDEX_0, index, value, mask)
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr, \
+ port, index, value, mask) \
+ smum_wait_for_indirect_register_unequal(smumgr, \
+ mm##port##_INDEX_0, index, value, mask)
+
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, port, reg, value, mask) \
+ SMUM_WAIT_VFPF_INDIRECT_REGISTER_GIVEN_INDEX(smumgr, port, ix##reg, value, mask)
+
+#define SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(smumgr, port, reg, value, mask) \
+ SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL_GIVEN_INDEX(smumgr, port, ix##reg, value, mask)
+
+
+/*Operations on named fields.*/
+
+#define SMUM_READ_VFPF_INDIRECT_FIELD(device, port, reg, field) \
+ SMUM_GET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+ reg, field)
+
+#define SMUM_WRITE_FIELD(device, reg, field, fieldval) \
+ cgs_write_register(device, mm##reg, \
+ SMUM_SET_FIELD(cgs_read_register(device, mm##reg), reg, field, fieldval))
+
+#define SMUM_WRITE_VFPF_INDIRECT_FIELD(device, port, reg, field, fieldval) \
+ cgs_write_ind_register(device, port, ix##reg, \
+ SMUM_SET_FIELD(cgs_read_ind_register(device, port, ix##reg), \
+ reg, field, fieldval))
+
+#define SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, port, reg, field, fieldval) \
+ SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, port, reg, \
+ (fieldval) << SMUM_FIELD_SHIFT(reg, field), \
+ SMUM_FIELD_MASK(reg, field))
+
+#define SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, port, reg, field, fieldval) \
+ SMUM_WAIT_VFPF_INDIRECT_REGISTER_UNEQUAL(smumgr, port, reg, \
+ (fieldval) << SMUM_FIELD_SHIFT(reg, field), \
+ SMUM_FIELD_MASK(reg, field))
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h
new file mode 100644
index 000000000000..63631296d751
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2015 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 TONGA_PP_SMC_H
+#define TONGA_PP_SMC_H
+
+#pragma pack(push, 1)
+
+#define PPSMC_SWSTATE_FLAG_DC 0x01
+#define PPSMC_SWSTATE_FLAG_UVD 0x02
+#define PPSMC_SWSTATE_FLAG_VCE 0x04
+#define PPSMC_SWSTATE_FLAG_PCIE_X1 0x08
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
+#define PPSMC_SYSTEMFLAG_GDDR5 0x04
+
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
+
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
+#define PPSMC_SYSTEMFLAG_12CHANNEL 0x40
+
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
+
+#define PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH 0x10
+#define PPSMC_EXTRAFLAGS_DRIVER_TO_GPIO17 0x20
+#define PPSMC_EXTRAFLAGS_PCC_TO_GPIO17 0x40
+
+/* Defines for DPM 2.0 */
+#define PPSMC_DPM2FLAGS_TDPCLMP 0x01
+#define PPSMC_DPM2FLAGS_PWRSHFT 0x02
+#define PPSMC_DPM2FLAGS_OCP 0x04
+
+/* Defines for display watermark level */
+
+#define PPSMC_DISPLAY_WATERMARK_LOW 0
+#define PPSMC_DISPLAY_WATERMARK_HIGH 1
+
+/* In the HW performance level's state flags:*/
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
+#define PPSMC_STATEFLAG_POWERBOOST 0x02
+#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04
+#define PPSMC_STATEFLAG_POWERSHIFT 0x08
+#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10
+#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
+#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
+
+/* Fan control algorithm:*/
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+ FAN_CONTROL_FUZZY,
+ FAN_CONTROL_TABLE
+};
+
+/* Return codes for driver to SMC communication.*/
+
+#define PPSMC_Result_OK ((uint16_t)0x01)
+#define PPSMC_Result_NoMore ((uint16_t)0x02)
+#define PPSMC_Result_NotNow ((uint16_t)0x03)
+
+#define PPSMC_Result_Failed ((uint16_t)0xFF)
+#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE)
+#define PPSMC_Result_UnknownVT ((uint16_t)0xFD)
+
+typedef uint16_t PPSMC_Result;
+
+#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x))
+
+
+#define PPSMC_MSG_Halt ((uint16_t)0x10)
+#define PPSMC_MSG_Resume ((uint16_t)0x11)
+#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12)
+#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13)
+#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14)
+#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16)
+#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17)
+#define PPSMC_MSG_LevelUp ((uint16_t)0x18)
+#define PPSMC_MSG_LevelDown ((uint16_t)0x19)
+#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a)
+#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20)
+
+#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f)
+#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40)
+#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41)
+#define PPSMC_MSG_ForceHigh ((uint16_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43)
+
+#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52)
+#define PPSMC_MSG_EnableCac ((uint16_t)0x53)
+#define PPSMC_MSG_DisableCac ((uint16_t)0x54)
+#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55)
+#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56)
+#define PPSMC_CACHistoryStart ((uint16_t)0x57)
+#define PPSMC_CACHistoryStop ((uint16_t)0x58)
+#define PPSMC_TDPClampingActive ((uint16_t)0x59)
+#define PPSMC_TDPClampingInactive ((uint16_t)0x5A)
+#define PPSMC_StartFanControl ((uint16_t)0x5B)
+#define PPSMC_StopFanControl ((uint16_t)0x5C)
+#define PPSMC_NoDisplay ((uint16_t)0x5D)
+#define PPSMC_HasDisplay ((uint16_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60)
+#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61)
+#define PPSMC_MSG_EnableULV ((uint16_t)0x62)
+#define PPSMC_MSG_DisableULV ((uint16_t)0x63)
+#define PPSMC_MSG_EnterULV ((uint16_t)0x64)
+#define PPSMC_MSG_ExitULV ((uint16_t)0x65)
+#define PPSMC_PowerShiftActive ((uint16_t)0x6A)
+#define PPSMC_PowerShiftInactive ((uint16_t)0x6B)
+#define PPSMC_OCPActive ((uint16_t)0x6C)
+#define PPSMC_OCPInactive ((uint16_t)0x6D)
+#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F)
+#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70)
+#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71)
+#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72)
+#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73)
+#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74)
+#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75)
+#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76)
+#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77)
+#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78)
+#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79)
+#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A)
+#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B)
+#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C)
+#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D)
+
+#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E)
+#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F)
+#define PPSMC_FlushDataCache ((uint16_t)0x80)
+#define PPSMC_FlushInstrCache ((uint16_t)0x81)
+
+#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82)
+#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83)
+
+#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84)
+
+#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85)
+#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86)
+#define PPSMC_MSG_EnableDTE ((uint16_t)0x87)
+#define PPSMC_MSG_DisableDTE ((uint16_t)0x88)
+
+#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89)
+#define PPSMC_MSG_ChangeNearTDPLimit ((uint16_t)0x90)
+#define PPSMC_MSG_ChangeSafePowerLimit ((uint16_t)0x91)
+
+#define PPSMC_MSG_DPMStateSweepStart ((uint16_t)0x92)
+#define PPSMC_MSG_DPMStateSweepStop ((uint16_t)0x93)
+
+#define PPSMC_MSG_OVRDDisableSCLKDS ((uint16_t)0x94)
+#define PPSMC_MSG_CancelDisableOVRDSCLKDS ((uint16_t)0x95)
+#define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint16_t)0x96)
+#define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint16_t)0x97)
+#define PPSMC_MSG_GPIO17 ((uint16_t)0x98)
+
+#define PPSMC_MSG_API_SetSvi2Volt_Vddc ((uint16_t)0x99)
+#define PPSMC_MSG_API_SetSvi2Volt_Vddci ((uint16_t)0x9A)
+#define PPSMC_MSG_API_SetSvi2Volt_Mvdd ((uint16_t)0x9B)
+#define PPSMC_MSG_API_GetSvi2Volt_Vddc ((uint16_t)0x9C)
+#define PPSMC_MSG_API_GetSvi2Volt_Vddci ((uint16_t)0x9D)
+#define PPSMC_MSG_API_GetSvi2Volt_Mvdd ((uint16_t)0x9E)
+
+#define PPSMC_MSG_BREAK ((uint16_t)0xF8)
+
+/* Trinity Specific Messages*/
+#define PPSMC_MSG_Test ((uint16_t) 0x100)
+#define PPSMC_MSG_DPM_Voltage_Pwrmgt ((uint16_t) 0x101)
+#define PPSMC_MSG_DPM_Config ((uint16_t) 0x102)
+#define PPSMC_MSG_PM_Controller_Start ((uint16_t) 0x103)
+#define PPSMC_MSG_DPM_ForceState ((uint16_t) 0x104)
+#define PPSMC_MSG_PG_PowerDownSIMD ((uint16_t) 0x105)
+#define PPSMC_MSG_PG_PowerUpSIMD ((uint16_t) 0x106)
+#define PPSMC_MSG_PM_Controller_Stop ((uint16_t) 0x107)
+#define PPSMC_MSG_PG_SIMD_Config ((uint16_t) 0x108)
+#define PPSMC_MSG_Voltage_Cntl_Enable ((uint16_t) 0x109)
+#define PPSMC_MSG_Thermal_Cntl_Enable ((uint16_t) 0x10a)
+#define PPSMC_MSG_Reset_Service ((uint16_t) 0x10b)
+#define PPSMC_MSG_VCEPowerOFF ((uint16_t) 0x10e)
+#define PPSMC_MSG_VCEPowerON ((uint16_t) 0x10f)
+#define PPSMC_MSG_DPM_Disable_VCE_HS ((uint16_t) 0x110)
+#define PPSMC_MSG_DPM_Enable_VCE_HS ((uint16_t) 0x111)
+#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint16_t) 0x112)
+#define PPSMC_MSG_DCEPowerOFF ((uint16_t) 0x113)
+#define PPSMC_MSG_DCEPowerON ((uint16_t) 0x114)
+#define PPSMC_MSG_PCIE_DDIPowerDown ((uint16_t) 0x117)
+#define PPSMC_MSG_PCIE_DDIPowerUp ((uint16_t) 0x118)
+#define PPSMC_MSG_PCIE_CascadePLLPowerDown ((uint16_t) 0x119)
+#define PPSMC_MSG_PCIE_CascadePLLPowerUp ((uint16_t) 0x11a)
+#define PPSMC_MSG_SYSPLLPowerOff ((uint16_t) 0x11b)
+#define PPSMC_MSG_SYSPLLPowerOn ((uint16_t) 0x11c)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint16_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint16_t) 0x11e)
+#define PPSMC_MSG_DISPLAYPHYStatusNotify ((uint16_t) 0x11f)
+#define PPSMC_MSG_EnableBAPM ((uint16_t) 0x120)
+#define PPSMC_MSG_DisableBAPM ((uint16_t) 0x121)
+#define PPSMC_MSG_PCIE_PHYPowerDown ((uint16_t) 0x122)
+#define PPSMC_MSG_PCIE_PHYPowerUp ((uint16_t) 0x123)
+#define PPSMC_MSG_UVD_DPM_Config ((uint16_t) 0x124)
+#define PPSMC_MSG_Spmi_Enable ((uint16_t) 0x122)
+#define PPSMC_MSG_Spmi_Timer ((uint16_t) 0x123)
+#define PPSMC_MSG_LCLK_DPM_Config ((uint16_t) 0x124)
+#define PPSMC_MSG_NBDPM_Config ((uint16_t) 0x125)
+#define PPSMC_MSG_PCIE_DDIPhyPowerDown ((uint16_t) 0x126)
+#define PPSMC_MSG_PCIE_DDIPhyPowerUp ((uint16_t) 0x127)
+#define PPSMC_MSG_MCLKDPM_Config ((uint16_t) 0x128)
+
+#define PPSMC_MSG_UVDDPM_Config ((uint16_t) 0x129)
+#define PPSMC_MSG_VCEDPM_Config ((uint16_t) 0x12A)
+#define PPSMC_MSG_ACPDPM_Config ((uint16_t) 0x12B)
+#define PPSMC_MSG_SAMUDPM_Config ((uint16_t) 0x12C)
+#define PPSMC_MSG_UVDDPM_SetEnabledMask ((uint16_t) 0x12D)
+#define PPSMC_MSG_VCEDPM_SetEnabledMask ((uint16_t) 0x12E)
+#define PPSMC_MSG_ACPDPM_SetEnabledMask ((uint16_t) 0x12F)
+#define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130)
+#define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131)
+#define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132)
+#define PPSMC_MSG_Thermal_Cntl_Disable ((uint16_t) 0x133)
+#define PPSMC_MSG_SetTDPLimit ((uint16_t) 0x134)
+#define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135)
+#define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136)
+#define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0x137)
+#define PPSMC_MSG_ACPPowerON ((uint16_t) 0x138)
+#define PPSMC_MSG_SAMPowerOFF ((uint16_t) 0x139)
+#define PPSMC_MSG_SAMPowerON ((uint16_t) 0x13a)
+#define PPSMC_MSG_SDMAPowerOFF ((uint16_t) 0x13b)
+#define PPSMC_MSG_SDMAPowerON ((uint16_t) 0x13c)
+#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d)
+#define PPSMC_MSG_IOMMUPowerOFF ((uint16_t) 0x13e)
+#define PPSMC_MSG_IOMMUPowerON ((uint16_t) 0x13f)
+#define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141)
+#define PPSMC_MSG_NBDPM_ForceNominal ((uint16_t) 0x142)
+#define PPSMC_MSG_NBDPM_ForcePerformance ((uint16_t) 0x143)
+#define PPSMC_MSG_NBDPM_UnForce ((uint16_t) 0x144)
+#define PPSMC_MSG_SCLKDPM_SetEnabledMask ((uint16_t) 0x145)
+#define PPSMC_MSG_MCLKDPM_SetEnabledMask ((uint16_t) 0x146)
+#define PPSMC_MSG_PCIeDPM_ForceLevel ((uint16_t) 0x147)
+#define PPSMC_MSG_PCIeDPM_UnForceLevel ((uint16_t) 0x148)
+#define PPSMC_MSG_EnableACDCGPIOInterrupt ((uint16_t) 0x149)
+#define PPSMC_MSG_EnableVRHotGPIOInterrupt ((uint16_t) 0x14a)
+#define PPSMC_MSG_SwitchToAC ((uint16_t) 0x14b)
+
+#define PPSMC_MSG_XDMAPowerOFF ((uint16_t) 0x14c)
+#define PPSMC_MSG_XDMAPowerON ((uint16_t) 0x14d)
+
+#define PPSMC_MSG_DPM_Enable ((uint16_t)0x14e)
+#define PPSMC_MSG_DPM_Disable ((uint16_t)0x14f)
+#define PPSMC_MSG_MCLKDPM_Enable ((uint16_t)0x150)
+#define PPSMC_MSG_MCLKDPM_Disable ((uint16_t)0x151)
+#define PPSMC_MSG_LCLKDPM_Enable ((uint16_t)0x152)
+#define PPSMC_MSG_LCLKDPM_Disable ((uint16_t)0x153)
+#define PPSMC_MSG_UVDDPM_Enable ((uint16_t)0x154)
+#define PPSMC_MSG_UVDDPM_Disable ((uint16_t)0x155)
+#define PPSMC_MSG_SAMUDPM_Enable ((uint16_t)0x156)
+#define PPSMC_MSG_SAMUDPM_Disable ((uint16_t)0x157)
+#define PPSMC_MSG_ACPDPM_Enable ((uint16_t)0x158)
+#define PPSMC_MSG_ACPDPM_Disable ((uint16_t)0x159)
+#define PPSMC_MSG_VCEDPM_Enable ((uint16_t)0x15a)
+#define PPSMC_MSG_VCEDPM_Disable ((uint16_t)0x15b)
+#define PPSMC_MSG_LCLKDPM_SetEnabledMask ((uint16_t)0x15c)
+
+#define PPSMC_MSG_DPM_FPS_Mode ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode ((uint16_t) 0x15e)
+#define PPSMC_MSG_VddC_Request ((uint16_t) 0x15f)
+#define PPSMC_MSG_MCLKDPM_GetEnabledMask ((uint16_t) 0x160)
+#define PPSMC_MSG_LCLKDPM_GetEnabledMask ((uint16_t) 0x161)
+#define PPSMC_MSG_SCLKDPM_GetEnabledMask ((uint16_t) 0x162)
+#define PPSMC_MSG_UVDDPM_GetEnabledMask ((uint16_t) 0x163)
+#define PPSMC_MSG_SAMUDPM_GetEnabledMask ((uint16_t) 0x164)
+#define PPSMC_MSG_ACPDPM_GetEnabledMask ((uint16_t) 0x165)
+#define PPSMC_MSG_VCEDPM_GetEnabledMask ((uint16_t) 0x166)
+#define PPSMC_MSG_PCIeDPM_SetEnabledMask ((uint16_t) 0x167)
+#define PPSMC_MSG_PCIeDPM_GetEnabledMask ((uint16_t) 0x168)
+#define PPSMC_MSG_TDCLimitEnable ((uint16_t) 0x169)
+#define PPSMC_MSG_TDCLimitDisable ((uint16_t) 0x16a)
+#define PPSMC_MSG_DPM_AutoRotate_Mode ((uint16_t) 0x16b)
+#define PPSMC_MSG_DISPCLK_FROM_FCH ((uint16_t)0x16c)
+#define PPSMC_MSG_DISPCLK_FROM_DFS ((uint16_t)0x16d)
+#define PPSMC_MSG_DPREFCLK_FROM_FCH ((uint16_t)0x16e)
+#define PPSMC_MSG_DPREFCLK_FROM_DFS ((uint16_t)0x16f)
+#define PPSMC_MSG_PmStatusLogStart ((uint16_t)0x170)
+#define PPSMC_MSG_PmStatusLogSample ((uint16_t)0x171)
+#define PPSMC_MSG_SCLK_AutoDPM_ON ((uint16_t) 0x172)
+#define PPSMC_MSG_MCLK_AutoDPM_ON ((uint16_t) 0x173)
+#define PPSMC_MSG_LCLK_AutoDPM_ON ((uint16_t) 0x174)
+#define PPSMC_MSG_UVD_AutoDPM_ON ((uint16_t) 0x175)
+#define PPSMC_MSG_SAMU_AutoDPM_ON ((uint16_t) 0x176)
+#define PPSMC_MSG_ACP_AutoDPM_ON ((uint16_t) 0x177)
+#define PPSMC_MSG_VCE_AutoDPM_ON ((uint16_t) 0x178)
+#define PPSMC_MSG_PCIe_AutoDPM_ON ((uint16_t) 0x179)
+#define PPSMC_MSG_MASTER_AutoDPM_ON ((uint16_t) 0x17a)
+#define PPSMC_MSG_MASTER_AutoDPM_OFF ((uint16_t) 0x17b)
+#define PPSMC_MSG_DYNAMICDISPPHYPOWER ((uint16_t) 0x17c)
+#define PPSMC_MSG_CAC_COLLECTION_ON ((uint16_t) 0x17d)
+#define PPSMC_MSG_CAC_COLLECTION_OFF ((uint16_t) 0x17e)
+#define PPSMC_MSG_CAC_CORRELATION_ON ((uint16_t) 0x17f)
+#define PPSMC_MSG_CAC_CORRELATION_OFF ((uint16_t) 0x180)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON ((uint16_t) 0x181)
+#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF ((uint16_t) 0x182)
+#define PPSMC_MSG_UVD_HANDSHAKE_OFF ((uint16_t) 0x183)
+#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT ((uint16_t) 0x184)
+#define PPSMC_MSG_PkgPwrLimitEnable ((uint16_t) 0x185)
+#define PPSMC_MSG_PkgPwrLimitDisable ((uint16_t) 0x186)
+#define PPSMC_MSG_PkgPwrSetLimit ((uint16_t) 0x187)
+#define PPSMC_MSG_OverDriveSetTargetTdp ((uint16_t) 0x188)
+#define PPSMC_MSG_SCLKDPM_FreezeLevel ((uint16_t) 0x189)
+#define PPSMC_MSG_SCLKDPM_UnfreezeLevel ((uint16_t) 0x18A)
+#define PPSMC_MSG_MCLKDPM_FreezeLevel ((uint16_t) 0x18B)
+#define PPSMC_MSG_MCLKDPM_UnfreezeLevel ((uint16_t) 0x18C)
+#define PPSMC_MSG_START_DRAM_LOGGING ((uint16_t) 0x18D)
+#define PPSMC_MSG_STOP_DRAM_LOGGING ((uint16_t) 0x18E)
+#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F)
+#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190)
+#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191)
+#define PPSMC_MSG_DisableACDCGPIOInterrupt ((uint16_t) 0x192)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddc ((uint16_t) 0x193)
+#define PPSMC_MSG_OverrideVoltageControl_SetVddci ((uint16_t) 0x194)
+#define PPSMC_MSG_SetVidOffset_1 ((uint16_t) 0x195)
+#define PPSMC_MSG_SetVidOffset_2 ((uint16_t) 0x207)
+#define PPSMC_MSG_GetVidOffset_1 ((uint16_t) 0x196)
+#define PPSMC_MSG_GetVidOffset_2 ((uint16_t) 0x208)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable ((uint16_t) 0x197)
+#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable ((uint16_t) 0x198)
+#define PPSMC_MSG_SetTjMax ((uint16_t) 0x199)
+#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A)
+
+#define PPSMC_MSG_WaitForMclkSwitchFinish ((uint16_t) 0x19B)
+#define PPSMC_MSG_ENABLE_THERMAL_DPM ((uint16_t) 0x19C)
+#define PPSMC_MSG_DISABLE_THERMAL_DPM ((uint16_t) 0x19D)
+#define PPSMC_MSG_Enable_PCC ((uint16_t) 0x19E)
+#define PPSMC_MSG_Disable_PCC ((uint16_t) 0x19F)
+
+#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200)
+#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201)
+#define PPSMC_MSG_API_GetSclkBusy ((uint16_t) 0x202)
+#define PPSMC_MSG_API_GetMclkBusy ((uint16_t) 0x203)
+#define PPSMC_MSG_API_GetAsicPower ((uint16_t) 0x204)
+#define PPSMC_MSG_SetFanRpmMax ((uint16_t) 0x205)
+#define PPSMC_MSG_SetFanSclkTarget ((uint16_t) 0x206)
+#define PPSMC_MSG_SetFanMinPwm ((uint16_t) 0x209)
+#define PPSMC_MSG_SetFanTemperatureTarget ((uint16_t) 0x20A)
+
+#define PPSMC_MSG_BACO_StartMonitor ((uint16_t) 0x240)
+#define PPSMC_MSG_BACO_Cancel ((uint16_t) 0x241)
+#define PPSMC_MSG_EnableVddGfx ((uint16_t) 0x242)
+#define PPSMC_MSG_DisableVddGfx ((uint16_t) 0x243)
+#define PPSMC_MSG_UcodeAddressLow ((uint16_t) 0x244)
+#define PPSMC_MSG_UcodeAddressHigh ((uint16_t) 0x245)
+#define PPSMC_MSG_UcodeLoadStatus ((uint16_t) 0x246)
+
+#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t) 0x250)
+#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t) 0x251)
+#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t) 0x252)
+#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t) 0x253)
+#define PPSMC_MSG_LoadUcodes ((uint16_t) 0x254)
+#define PPSMC_MSG_PowerStateNotify ((uint16_t) 0x255)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI ((uint16_t) 0x256)
+#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO ((uint16_t) 0x257)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI ((uint16_t) 0x258)
+#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO ((uint16_t) 0x259)
+#define PPSMC_MSG_LoadVBios ((uint16_t) 0x25A)
+#define PPSMC_MSG_GetUcodeVersion ((uint16_t) 0x25B)
+#define DMCUSMC_MSG_PSREntry ((uint16_t) 0x25C)
+#define DMCUSMC_MSG_PSRExit ((uint16_t) 0x25D)
+#define PPSMC_MSG_EnableClockGatingFeature ((uint16_t) 0x260)
+#define PPSMC_MSG_DisableClockGatingFeature ((uint16_t) 0x261)
+#define PPSMC_MSG_IsDeviceRunning ((uint16_t) 0x262)
+#define PPSMC_MSG_LoadMetaData ((uint16_t) 0x263)
+#define PPSMC_MSG_TMON_AutoCaliberate_Enable ((uint16_t) 0x264)
+#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265)
+#define PPSMC_MSG_GetTelemetry1Slope ((uint16_t) 0x266)
+#define PPSMC_MSG_GetTelemetry1Offset ((uint16_t) 0x267)
+#define PPSMC_MSG_GetTelemetry2Slope ((uint16_t) 0x268)
+#define PPSMC_MSG_GetTelemetry2Offset ((uint16_t) 0x269)
+
+typedef uint16_t PPSMC_Msg;
+
+/* If the SMC firmware has an event status soft register this is what the individual bits mean.*/
+#define PPSMC_EVENT_STATUS_THERMAL 0x00000001
+#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002
+#define PPSMC_EVENT_STATUS_DC 0x00000004
+#define PPSMC_EVENT_STATUS_GPIO17 0x00000008
+
+
+#pragma pack(pop)
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile
new file mode 100644
index 000000000000..6c4ef135cf01
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the 'smu manager' sub-component of powerplay.
+# It provides the smu management services for the driver.
+
+SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o
+
+AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR))
+
+AMD_POWERPLAY_FILES += $(AMD_PP_SMUMGR)
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
new file mode 100644
index 000000000000..873a8d264d5c
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
@@ -0,0 +1,858 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include "linux/delay.h"
+#include "cgs_common.h"
+#include "smu/smu_8_0_d.h"
+#include "smu/smu_8_0_sh_mask.h"
+#include "smu8.h"
+#include "smu8_fusion.h"
+#include "cz_smumgr.h"
+#include "cz_ppsmc.h"
+#include "smu_ucode_xfer_cz.h"
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+#include "smumgr.h"
+
+#define SIZE_ALIGN_32(x) (((x) + 31) / 32 * 32)
+
+static enum cz_scratch_entry firmware_list[] = {
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
+};
+
+static int cz_smum_get_argument(struct pp_smumgr *smumgr)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ return cgs_read_register(smumgr->device,
+ mmSMU_MP1_SRBM2P_ARG_0);
+}
+
+static int cz_send_msg_to_smc_async(struct pp_smumgr *smumgr,
+ uint16_t msg)
+{
+ int result = 0;
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
+ SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+ if (result != 0) {
+ printk(KERN_ERR "[ powerplay ] cz_send_msg_to_smc_async failed\n");
+ return result;
+ }
+
+ cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0);
+ cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg);
+
+ return 0;
+}
+
+/* Send a message to the SMC, and wait for its response.*/
+static int cz_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+ int result = 0;
+
+ result = cz_send_msg_to_smc_async(smumgr, msg);
+ if (result != 0)
+ return result;
+
+ result = SMUM_WAIT_FIELD_UNEQUAL(smumgr,
+ SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+
+ if (result != 0)
+ return result;
+
+ return 0;
+}
+
+static int cz_set_smc_sram_address(struct pp_smumgr *smumgr,
+ uint32_t smc_address, uint32_t limit)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ if (0 != (3 & smc_address)) {
+ printk(KERN_ERR "[ powerplay ] SMC address must be 4 byte aligned\n");
+ return -1;
+ }
+
+ if (limit <= (smc_address + 3)) {
+ printk(KERN_ERR "[ powerplay ] SMC address beyond the SMC RAM area\n");
+ return -1;
+ }
+
+ cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX_0,
+ SMN_MP1_SRAM_START_ADDR + smc_address);
+
+ return 0;
+}
+
+static int cz_write_smc_sram_dword(struct pp_smumgr *smumgr,
+ uint32_t smc_address, uint32_t value, uint32_t limit)
+{
+ int result;
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ result = cz_set_smc_sram_address(smumgr, smc_address, limit);
+ cgs_write_register(smumgr->device, mmMP0PUB_IND_DATA_0, value);
+
+ return 0;
+}
+
+static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
+
+ return cz_send_msg_to_smc(smumgr, msg);
+}
+
+static int cz_request_smu_load_fw(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend);
+ int result = 0;
+ uint32_t smc_address;
+
+ if (!smumgr->reload_fw) {
+ printk(KERN_INFO "[ powerplay ] skip reloading...\n");
+ return 0;
+ }
+
+ smc_address = SMU8_FIRMWARE_HEADER_LOCATION +
+ offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+ cz_write_smc_sram_dword(smumgr, smc_address, 0, smc_address+4);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_DriverDramAddrHi,
+ cz_smu->toc_buffer.mc_addr_high);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_DriverDramAddrLo,
+ cz_smu->toc_buffer.mc_addr_low);
+
+ cz_send_msg_to_smc(smumgr, PPSMC_MSG_InitJobs);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_aram);
+ cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_power_profiling_index);
+
+ result = cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_initialize_index);
+
+ return result;
+}
+
+static int cz_check_fw_load_finish(struct pp_smumgr *smumgr,
+ uint32_t firmware)
+{
+ int i;
+ uint32_t index = SMN_MP1_SRAM_START_ADDR +
+ SMU8_FIRMWARE_HEADER_LOCATION +
+ offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ return cgs_read_register(smumgr->device,
+ mmSMU_MP1_SRBM2P_ARG_0);
+
+ cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX, index);
+
+ for (i = 0; i < smumgr->usec_timeout; i++) {
+ if (firmware ==
+ (cgs_read_register(smumgr->device, mmMP0PUB_IND_DATA) & firmware))
+ break;
+ udelay(1);
+ }
+
+ if (i >= smumgr->usec_timeout) {
+ printk(KERN_ERR "[ powerplay ] SMU check loaded firmware failed.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cz_load_mec_firmware(struct pp_smumgr *smumgr)
+{
+ uint32_t reg_data;
+ uint32_t tmp;
+ int ret = 0;
+ struct cgs_firmware_info info = {0};
+ struct cz_smumgr *cz_smu;
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ cz_smu = (struct cz_smumgr *)smumgr->backend;
+ ret = cgs_get_firmware_info(smumgr->device,
+ CGS_UCODE_ID_CP_MEC, &info);
+
+ if (ret)
+ return -EINVAL;
+
+ /* Disable MEC parsing/prefetching */
+ tmp = cgs_read_register(smumgr->device,
+ mmCP_MEC_CNTL);
+ tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1);
+ tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1);
+ cgs_write_register(smumgr->device, mmCP_MEC_CNTL, tmp);
+
+ tmp = cgs_read_register(smumgr->device,
+ mmCP_CPC_IC_BASE_CNTL);
+
+ tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0);
+ tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0);
+ tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
+ tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1);
+ cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_CNTL, tmp);
+
+ reg_data = smu_lower_32_bits(info.mc_addr) &
+ SMUM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO);
+ cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_LO, reg_data);
+
+ reg_data = smu_upper_32_bits(info.mc_addr) &
+ SMUM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI);
+ cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_HI, reg_data);
+
+ return 0;
+}
+
+static int cz_start_smu(struct pp_smumgr *smumgr)
+{
+ int ret = 0;
+ uint32_t fw_to_check = UCODE_ID_RLC_G_MASK |
+ UCODE_ID_SDMA0_MASK |
+ UCODE_ID_SDMA1_MASK |
+ UCODE_ID_CP_CE_MASK |
+ UCODE_ID_CP_ME_MASK |
+ UCODE_ID_CP_PFP_MASK |
+ UCODE_ID_CP_MEC_JT1_MASK |
+ UCODE_ID_CP_MEC_JT2_MASK;
+
+ cz_request_smu_load_fw(smumgr);
+ cz_check_fw_load_finish(smumgr, fw_to_check);
+
+ ret = cz_load_mec_firmware(smumgr);
+ if (ret)
+ printk(KERN_ERR "[ powerplay ] Mec Firmware load failed\n");
+
+ return ret;
+}
+
+static uint8_t cz_translate_firmware_enum_to_arg(
+ enum cz_scratch_entry firmware_enum)
+{
+ uint8_t ret = 0;
+
+ switch (firmware_enum) {
+ case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0:
+ ret = UCODE_ID_SDMA0;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1:
+ ret = UCODE_ID_SDMA1;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE:
+ ret = UCODE_ID_CP_CE;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP:
+ ret = UCODE_ID_CP_PFP;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME:
+ ret = UCODE_ID_CP_ME;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1:
+ ret = UCODE_ID_CP_MEC_JT1;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2:
+ ret = UCODE_ID_CP_MEC_JT2;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG:
+ ret = UCODE_ID_GMCON_RENG;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G:
+ ret = UCODE_ID_RLC_G;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH:
+ ret = UCODE_ID_RLC_SCRATCH;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM:
+ ret = UCODE_ID_RLC_SRM_ARAM;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM:
+ ret = UCODE_ID_RLC_SRM_DRAM;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM:
+ ret = UCODE_ID_DMCU_ERAM;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM:
+ ret = UCODE_ID_DMCU_IRAM;
+ break;
+ case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING:
+ ret = TASK_ARG_INIT_MM_PWR_LOG;
+ break;
+ case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT:
+ case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING:
+ case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS:
+ case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT:
+ case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START:
+ case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS:
+ ret = TASK_ARG_REG_MMIO;
+ break;
+ case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE:
+ ret = TASK_ARG_INIT_CLK_TABLE;
+ break;
+ }
+
+ return ret;
+}
+
+static enum cgs_ucode_id cz_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+ enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+ switch (fw_type) {
+ case UCODE_ID_SDMA0:
+ result = CGS_UCODE_ID_SDMA0;
+ break;
+ case UCODE_ID_SDMA1:
+ result = CGS_UCODE_ID_SDMA1;
+ break;
+ case UCODE_ID_CP_CE:
+ result = CGS_UCODE_ID_CP_CE;
+ break;
+ case UCODE_ID_CP_PFP:
+ result = CGS_UCODE_ID_CP_PFP;
+ break;
+ case UCODE_ID_CP_ME:
+ result = CGS_UCODE_ID_CP_ME;
+ break;
+ case UCODE_ID_CP_MEC_JT1:
+ result = CGS_UCODE_ID_CP_MEC_JT1;
+ break;
+ case UCODE_ID_CP_MEC_JT2:
+ result = CGS_UCODE_ID_CP_MEC_JT2;
+ break;
+ case UCODE_ID_RLC_G:
+ result = CGS_UCODE_ID_RLC_G;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static int cz_smu_populate_single_scratch_task(
+ struct pp_smumgr *smumgr,
+ enum cz_scratch_entry fw_enum,
+ uint8_t type, bool is_last)
+{
+ uint8_t i;
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+ struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++];
+
+ task->type = type;
+ task->arg = cz_translate_firmware_enum_to_arg(fw_enum);
+ task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count;
+
+ for (i = 0; i < cz_smu->scratch_buffer_length; i++)
+ if (cz_smu->scratch_buffer[i].firmware_ID == fw_enum)
+ break;
+
+ if (i >= cz_smu->scratch_buffer_length) {
+ printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
+ return -EINVAL;
+ }
+
+ task->addr.low = cz_smu->scratch_buffer[i].mc_addr_low;
+ task->addr.high = cz_smu->scratch_buffer[i].mc_addr_high;
+ task->size_bytes = cz_smu->scratch_buffer[i].data_size;
+
+ if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) {
+ struct cz_ih_meta_data *pIHReg_restore =
+ (struct cz_ih_meta_data *)cz_smu->scratch_buffer[i].kaddr;
+ pIHReg_restore->command =
+ METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD;
+ }
+
+ return 0;
+}
+
+static int cz_smu_populate_single_ucode_load_task(
+ struct pp_smumgr *smumgr,
+ enum cz_scratch_entry fw_enum,
+ bool is_last)
+{
+ uint8_t i;
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+ struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++];
+
+ task->type = TASK_TYPE_UCODE_LOAD;
+ task->arg = cz_translate_firmware_enum_to_arg(fw_enum);
+ task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count;
+
+ for (i = 0; i < cz_smu->driver_buffer_length; i++)
+ if (cz_smu->driver_buffer[i].firmware_ID == fw_enum)
+ break;
+
+ if (i >= cz_smu->driver_buffer_length) {
+ printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n");
+ return -EINVAL;
+ }
+
+ task->addr.low = cz_smu->driver_buffer[i].mc_addr_low;
+ task->addr.high = cz_smu->driver_buffer[i].mc_addr_high;
+ task->size_bytes = cz_smu->driver_buffer[i].data_size;
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_rlc_aram_save(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+ cz_smu->toc_entry_aram = cz_smu->toc_entry_used_count;
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ TASK_TYPE_UCODE_SAVE, true);
+
+ return 0;
+}
+
+static int cz_smu_initialize_toc_empty_job_list(struct pp_smumgr *smumgr)
+{
+ int i;
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+
+ for (i = 0; i < NUM_JOBLIST_ENTRIES; i++)
+ toc->JobList[i] = (uint8_t)IGNORE_JOB;
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_vddgfx_enter(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+
+ toc->JobList[JOB_GFX_SAVE] = (uint8_t)cz_smu->toc_entry_used_count;
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ TASK_TYPE_UCODE_SAVE, false);
+
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+ TASK_TYPE_UCODE_SAVE, true);
+
+ return 0;
+}
+
+
+static int cz_smu_construct_toc_for_vddgfx_exit(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr;
+
+ toc->JobList[JOB_GFX_RESTORE] = (uint8_t)cz_smu->toc_entry_used_count;
+
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false);
+
+ /* populate scratch */
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ TASK_TYPE_UCODE_LOAD, false);
+
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ TASK_TYPE_UCODE_LOAD, false);
+
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+ TASK_TYPE_UCODE_LOAD, true);
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_power_profiling(
+ struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+ cz_smu->toc_entry_power_profiling_index = cz_smu->toc_entry_used_count;
+
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+ TASK_TYPE_INITIALIZE, true);
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_bootup(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+ cz_smu->toc_entry_initialize_index = cz_smu->toc_entry_used_count;
+
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
+ cz_smu_populate_single_ucode_load_task(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true);
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_clock_table(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+ cz_smu->toc_entry_clock_table = cz_smu->toc_entry_used_count;
+
+ cz_smu_populate_single_scratch_task(smumgr,
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
+ TASK_TYPE_INITIALIZE, true);
+
+ return 0;
+}
+
+static int cz_smu_construct_toc(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+
+ cz_smu->toc_entry_used_count = 0;
+
+ cz_smu_initialize_toc_empty_job_list(smumgr);
+
+ cz_smu_construct_toc_for_rlc_aram_save(smumgr);
+
+ cz_smu_construct_toc_for_vddgfx_enter(smumgr);
+
+ cz_smu_construct_toc_for_vddgfx_exit(smumgr);
+
+ cz_smu_construct_toc_for_power_profiling(smumgr);
+
+ cz_smu_construct_toc_for_bootup(smumgr);
+
+ cz_smu_construct_toc_for_clock_table(smumgr);
+
+ return 0;
+}
+
+static int cz_smu_populate_firmware_entries(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ uint32_t firmware_type;
+ uint32_t i;
+ int ret;
+ enum cgs_ucode_id ucode_id;
+ struct cgs_firmware_info info = {0};
+
+ cz_smu->driver_buffer_length = 0;
+
+ for (i = 0; i < sizeof(firmware_list)/sizeof(*firmware_list); i++) {
+
+ firmware_type = cz_translate_firmware_enum_to_arg(
+ firmware_list[i]);
+
+ ucode_id = cz_convert_fw_type_to_cgs(firmware_type);
+
+ ret = cgs_get_firmware_info(smumgr->device,
+ ucode_id, &info);
+
+ if (ret == 0) {
+ cz_smu->driver_buffer[i].mc_addr_high =
+ smu_upper_32_bits(info.mc_addr);
+
+ cz_smu->driver_buffer[i].mc_addr_low =
+ smu_lower_32_bits(info.mc_addr);
+
+ cz_smu->driver_buffer[i].data_size = info.image_size;
+
+ cz_smu->driver_buffer[i].firmware_ID = firmware_list[i];
+ cz_smu->driver_buffer_length++;
+ }
+ }
+
+ return 0;
+}
+
+static int cz_smu_populate_single_scratch_entry(
+ struct pp_smumgr *smumgr,
+ enum cz_scratch_entry scratch_type,
+ uint32_t ulsize_byte,
+ struct cz_buffer_entry *entry)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ long long mc_addr =
+ ((long long)(cz_smu->smu_buffer.mc_addr_high) << 32)
+ | cz_smu->smu_buffer.mc_addr_low;
+
+ uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte);
+
+ mc_addr += cz_smu->smu_buffer_used_bytes;
+
+ entry->data_size = ulsize_byte;
+ entry->kaddr = (char *) cz_smu->smu_buffer.kaddr +
+ cz_smu->smu_buffer_used_bytes;
+ entry->mc_addr_low = smu_lower_32_bits(mc_addr);
+ entry->mc_addr_high = smu_upper_32_bits(mc_addr);
+ entry->firmware_ID = scratch_type;
+
+ cz_smu->smu_buffer_used_bytes += ulsize_aligned;
+
+ return 0;
+}
+
+static int cz_download_pptable_settings(struct pp_smumgr *smumgr, void **table)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ unsigned long i;
+
+ for (i = 0; i < cz_smu->scratch_buffer_length; i++) {
+ if (cz_smu->scratch_buffer[i].firmware_ID
+ == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
+ break;
+ }
+
+ *table = (struct SMU8_Fusion_ClkTable *)cz_smu->scratch_buffer[i].kaddr;
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_SetClkTableAddrHi,
+ cz_smu->scratch_buffer[i].mc_addr_high);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_SetClkTableAddrLo,
+ cz_smu->scratch_buffer[i].mc_addr_low);
+
+ cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_clock_table);
+
+ cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToDram);
+
+ return 0;
+}
+
+static int cz_upload_pptable_settings(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ unsigned long i;
+
+ for (i = 0; i < cz_smu->scratch_buffer_length; i++) {
+ if (cz_smu->scratch_buffer[i].firmware_ID
+ == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
+ break;
+ }
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_SetClkTableAddrHi,
+ cz_smu->scratch_buffer[i].mc_addr_high);
+
+ cz_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_SetClkTableAddrLo,
+ cz_smu->scratch_buffer[i].mc_addr_low);
+
+ cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob,
+ cz_smu->toc_entry_clock_table);
+
+ cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToSmu);
+
+ return 0;
+}
+
+static int cz_smu_init(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend;
+ uint64_t mc_addr = 0;
+ int ret = 0;
+
+ cz_smu->toc_buffer.data_size = 4096;
+ cz_smu->smu_buffer.data_size =
+ ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) +
+ ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) +
+ ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) +
+ ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) +
+ ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32);
+
+ ret = smu_allocate_memory(smumgr->device,
+ cz_smu->toc_buffer.data_size,
+ CGS_GPU_MEM_TYPE__GART_CACHEABLE,
+ PAGE_SIZE,
+ &mc_addr,
+ &cz_smu->toc_buffer.kaddr,
+ &cz_smu->toc_buffer.handle);
+ if (ret != 0)
+ return -1;
+
+ cz_smu->toc_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+ cz_smu->toc_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+ ret = smu_allocate_memory(smumgr->device,
+ cz_smu->smu_buffer.data_size,
+ CGS_GPU_MEM_TYPE__GART_CACHEABLE,
+ PAGE_SIZE,
+ &mc_addr,
+ &cz_smu->smu_buffer.kaddr,
+ &cz_smu->smu_buffer.handle);
+ if (ret != 0)
+ return -1;
+
+ cz_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+ cz_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+ cz_smu_populate_firmware_entries(smumgr);
+ if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
+ &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+ printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ return -1;
+ }
+
+ if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
+ &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+ printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ return -1;
+ }
+ if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+ UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
+ &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+ printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ return -1;
+ }
+
+ if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+ CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+ sizeof(struct SMU8_MultimediaPowerLogData),
+ &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+ printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ return -1;
+ }
+
+ if (0 != cz_smu_populate_single_scratch_entry(smumgr,
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
+ sizeof(struct SMU8_Fusion_ClkTable),
+ &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) {
+ printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n");
+ return -1;
+ }
+ cz_smu_construct_toc(smumgr);
+
+ return 0;
+}
+
+static int cz_smu_fini(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu;
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ cz_smu = (struct cz_smumgr *)smumgr->backend;
+ if (cz_smu) {
+ cgs_free_gpu_mem(smumgr->device,
+ cz_smu->toc_buffer.handle);
+ cgs_free_gpu_mem(smumgr->device,
+ cz_smu->smu_buffer.handle);
+ kfree(cz_smu);
+ kfree(smumgr);
+ }
+
+ return 0;
+}
+
+static const struct pp_smumgr_func cz_smu_funcs = {
+ .smu_init = cz_smu_init,
+ .smu_fini = cz_smu_fini,
+ .start_smu = cz_start_smu,
+ .check_fw_load_finish = cz_check_fw_load_finish,
+ .request_smu_load_fw = NULL,
+ .request_smu_load_specific_fw = NULL,
+ .get_argument = cz_smum_get_argument,
+ .send_msg_to_smc = cz_send_msg_to_smc,
+ .send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter,
+ .download_pptable_settings = cz_download_pptable_settings,
+ .upload_pptable_settings = cz_upload_pptable_settings,
+};
+
+int cz_smum_init(struct pp_smumgr *smumgr)
+{
+ struct cz_smumgr *cz_smu;
+
+ cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL);
+ if (cz_smu == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = cz_smu;
+ smumgr->smumgr_funcs = &cz_smu_funcs;
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
new file mode 100644
index 000000000000..883818039248
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015 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 _CZ_SMUMGR_H_
+#define _CZ_SMUMGR_H_
+
+
+#define MAX_NUM_FIRMWARE 8
+#define MAX_NUM_SCRATCH 11
+#define CZ_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024
+#define CZ_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048
+#define CZ_SCRATCH_SIZE_SDMA_METADATA 1024
+#define CZ_SCRATCH_SIZE_IH ((2*256+1)*4)
+
+enum cz_scratch_entry {
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
+ CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+ CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM,
+ CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM,
+ CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+ CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT,
+ CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING,
+ CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS,
+ CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT,
+ CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START,
+ CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS,
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE
+};
+
+struct cz_buffer_entry {
+ uint32_t data_size;
+ uint32_t mc_addr_low;
+ uint32_t mc_addr_high;
+ void *kaddr;
+ enum cz_scratch_entry firmware_ID;
+ unsigned long handle; /* as bo handle used when release bo */
+};
+
+struct cz_register_index_data_pair {
+ uint32_t offset;
+ uint32_t value;
+};
+
+struct cz_ih_meta_data {
+ uint32_t command;
+ struct cz_register_index_data_pair register_index_value_pair[1];
+};
+
+struct cz_smumgr {
+ uint8_t driver_buffer_length;
+ uint8_t scratch_buffer_length;
+ uint16_t toc_entry_used_count;
+ uint16_t toc_entry_initialize_index;
+ uint16_t toc_entry_power_profiling_index;
+ uint16_t toc_entry_aram;
+ uint16_t toc_entry_ih_register_restore_task_index;
+ uint16_t toc_entry_clock_table;
+ uint16_t ih_register_restore_task_size;
+ uint16_t smu_buffer_used_bytes;
+
+ struct cz_buffer_entry toc_buffer;
+ struct cz_buffer_entry smu_buffer;
+ struct cz_buffer_entry firmware_buffer;
+ struct cz_buffer_entry driver_buffer[MAX_NUM_FIRMWARE];
+ struct cz_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE];
+ struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH];
+};
+
+struct pp_smumgr;
+
+extern int cz_smum_init(struct pp_smumgr *smumgr);
+
+#endif
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
new file mode 100644
index 000000000000..cdbb9f89bf36
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "smumgr.h"
+#include "smu73.h"
+#include "smu_ucode_xfer_vi.h"
+#include "fiji_smumgr.h"
+#include "fiji_ppsmc.h"
+#include "smu73_discrete.h"
+#include "ppatomctrl.h"
+#include "smu/smu_7_1_3_d.h"
+#include "smu/smu_7_1_3_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+#include "oss/oss_3_0_d.h"
+#include "gca/gfx_8_0_d.h"
+#include "bif/bif_5_0_d.h"
+#include "bif/bif_5_0_sh_mask.h"
+#include "pp_debug.h"
+#include "fiji_pwrvirus.h"
+
+#define AVFS_EN_MSB 1568
+#define AVFS_EN_LSB 1568
+
+#define FIJI_SMC_SIZE 0x20000
+
+struct SMU73_Discrete_GraphicsLevel avfs_graphics_level[8] = {
+ /* Min Sclk pcie DeepSleep Activity CgSpll CgSpll spllSpread SpllSpread CcPwr CcPwr Sclk Display Enabled Enabled Voltage Power */
+ /* Voltage, Frequency, DpmLevel, DivId, Level, FuncCntl3, FuncCntl4, Spectrum, Spectrum2, DynRm, DynRm1 Did, Watermark, ForActivity, ForThrottle, UpHyst, DownHyst, DownHyst, Throttle */
+ { 0x3c0fd047, 0x30750000, 0x00, 0x03, 0x1e00, 0x00200410, 0x87020000, 0x21680000, 0x0c000000, 0, 0, 0x16, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0xa00fd047, 0x409c0000, 0x01, 0x04, 0x1e00, 0x00800510, 0x87020000, 0x21680000, 0x11000000, 0, 0, 0x16, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0410d047, 0x50c30000, 0x01, 0x00, 0x1e00, 0x00600410, 0x87020000, 0x21680000, 0x0d000000, 0, 0, 0x0e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0x6810d047, 0x60ea0000, 0x01, 0x00, 0x1e00, 0x00800410, 0x87020000, 0x21680000, 0x0e000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0xcc10d047, 0xe8fd0000, 0x01, 0x00, 0x1e00, 0x00e00410, 0x87020000, 0x21680000, 0x0f000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0x3011d047, 0x70110100, 0x01, 0x00, 0x1e00, 0x00400510, 0x87020000, 0x21680000, 0x10000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0x9411d047, 0xf8240100, 0x01, 0x00, 0x1e00, 0x00a00510, 0x87020000, 0x21680000, 0x11000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ { 0xf811d047, 0x80380100, 0x01, 0x00, 0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000, 0, 0, 0x0c, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }
+};
+
+static enum cgs_ucode_id fiji_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+ enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+ switch (fw_type) {
+ case UCODE_ID_SMU:
+ result = CGS_UCODE_ID_SMU;
+ break;
+ case UCODE_ID_SDMA0:
+ result = CGS_UCODE_ID_SDMA0;
+ break;
+ case UCODE_ID_SDMA1:
+ result = CGS_UCODE_ID_SDMA1;
+ break;
+ case UCODE_ID_CP_CE:
+ result = CGS_UCODE_ID_CP_CE;
+ break;
+ case UCODE_ID_CP_PFP:
+ result = CGS_UCODE_ID_CP_PFP;
+ break;
+ case UCODE_ID_CP_ME:
+ result = CGS_UCODE_ID_CP_ME;
+ break;
+ case UCODE_ID_CP_MEC:
+ result = CGS_UCODE_ID_CP_MEC;
+ break;
+ case UCODE_ID_CP_MEC_JT1:
+ result = CGS_UCODE_ID_CP_MEC_JT1;
+ break;
+ case UCODE_ID_CP_MEC_JT2:
+ result = CGS_UCODE_ID_CP_MEC_JT2;
+ break;
+ case UCODE_ID_RLC_G:
+ result = CGS_UCODE_ID_RLC_G;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+/**
+* Set the address for reading/writing the SMC SRAM space.
+* @param smumgr the address of the powerplay hardware manager.
+* @param smc_addr the address in the SMC RAM to access.
+*/
+static int fiji_set_smc_sram_address(struct pp_smumgr *smumgr,
+ uint32_t smc_addr, uint32_t limit)
+{
+ PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)),
+ "SMC address must be 4 byte aligned.", return -EINVAL;);
+ PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)),
+ "SMC address is beyond the SMC RAM area.", return -EINVAL;);
+
+ cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smc_addr);
+ SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+
+ return 0;
+}
+
+/**
+* Copy bytes from an array into the SMC RAM space.
+*
+* @param smumgr the address of the powerplay SMU manager.
+* @param smcStartAddress the start address in the SMC RAM to copy bytes to.
+* @param src the byte array to copy the bytes from.
+* @param byteCount the number of bytes to copy.
+*/
+int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr,
+ uint32_t smcStartAddress, const uint8_t *src,
+ uint32_t byteCount, uint32_t limit)
+{
+ int result;
+ uint32_t data, originalData;
+ uint32_t addr, extraShift;
+
+ PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
+ "SMC address must be 4 byte aligned.", return -EINVAL;);
+ PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
+ "SMC address is beyond the SMC RAM area.", return -EINVAL;);
+
+ addr = smcStartAddress;
+
+ while (byteCount >= 4) {
+ /* Bytes are written into the SMC addres space with the MSB first. */
+ data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
+
+ result = fiji_set_smc_sram_address(smumgr, addr, limit);
+ if (result)
+ return result;
+
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+
+ src += 4;
+ byteCount -= 4;
+ addr += 4;
+ }
+
+ if (byteCount) {
+ /* Now write the odd bytes left.
+ * Do a read modify write cycle.
+ */
+ data = 0;
+
+ result = fiji_set_smc_sram_address(smumgr, addr, limit);
+ if (result)
+ return result;
+
+ originalData = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
+ extraShift = 8 * (4 - byteCount);
+
+ while (byteCount > 0) {
+ /* Bytes are written into the SMC addres
+ * space with the MSB first.
+ */
+ data = (0x100 * data) + *src++;
+ byteCount--;
+ }
+ data <<= extraShift;
+ data |= (originalData & ~((~0UL) << extraShift));
+
+ result = fiji_set_smc_sram_address(smumgr, addr, limit);
+ if (!result)
+ return result;
+
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+ }
+ return 0;
+}
+
+int fiji_program_jump_on_start(struct pp_smumgr *smumgr)
+{
+ static unsigned char data[] = { 0xE0, 0x00, 0x80, 0x40 };
+
+ fiji_copy_bytes_to_smc(smumgr, 0x0, data, 4, sizeof(data) + 1);
+
+ return 0;
+}
+
+/**
+* Return if the SMC is currently running.
+*
+* @param smumgr the address of the powerplay hardware manager.
+*/
+bool fiji_is_smc_ram_running(struct pp_smumgr *smumgr)
+{
+ return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
+ CGS_IND_REG__SMC,
+ SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
+ && (0x20100 <= cgs_read_ind_register(smumgr->device,
+ CGS_IND_REG__SMC, ixSMC_PC_C)));
+}
+
+/**
+* Send a message to the SMC, and wait for its response.
+*
+* @param smumgr the address of the powerplay hardware manager.
+* @param msg the message to send.
+* @return The response that came from the SMC.
+*/
+int fiji_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+ if (!fiji_is_smc_ram_running(smumgr))
+ return -1;
+
+ if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
+ printk(KERN_ERR "Failed to send Previous Message.");
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ }
+
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+ return 0;
+}
+
+/**
+ * Send a message to the SMC with parameter
+ * @param smumgr: the address of the powerplay hardware manager.
+ * @param msg: the message to send.
+ * @param parameter: the parameter to send
+ * @return The response that came from the SMC.
+ */
+int fiji_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter)
+{
+ if (!fiji_is_smc_ram_running(smumgr))
+ return -1;
+
+ if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
+ printk(KERN_ERR "Failed to send Previous Message.");
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ }
+
+ cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+ return 0;
+}
+
+
+/**
+* Send a message to the SMC with parameter, do not wait for response
+*
+* @param smumgr: the address of the powerplay hardware manager.
+* @param msg: the message to send.
+* @param parameter: the parameter to send
+* @return The response that came from the SMC.
+*/
+int fiji_send_msg_to_smc_with_parameter_without_waiting(
+ struct pp_smumgr *smumgr, uint16_t msg, uint32_t parameter)
+{
+ if (1 != SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP)) {
+ printk(KERN_ERR "Failed to send Previous Message.");
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ }
+ cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+ return 0;
+}
+
+/**
+* Uploads the SMU firmware from .hex file
+*
+* @param smumgr the address of the powerplay SMU manager.
+* @return 0 or -1.
+*/
+
+static int fiji_upload_smu_firmware_image(struct pp_smumgr *smumgr)
+{
+ const uint8_t *src;
+ uint32_t byte_count;
+ uint32_t *data;
+ struct cgs_firmware_info info = {0};
+
+ cgs_get_firmware_info(smumgr->device,
+ fiji_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
+
+ if (info.image_size & 3) {
+ printk(KERN_ERR "SMC ucode is not 4 bytes aligned\n");
+ return -EINVAL;
+ }
+
+ if (info.image_size > FIJI_SMC_SIZE) {
+ printk(KERN_ERR "SMC address is beyond the SMC RAM area\n");
+ return -EINVAL;
+ }
+
+ cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
+ SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
+
+ byte_count = info.image_size;
+ src = (const uint8_t *)info.kptr;
+
+ data = (uint32_t *)src;
+ for (; byte_count >= 4; data++, byte_count -= 4)
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
+
+ SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+ return 0;
+}
+
+/**
+* Read a 32bit value from the SMC SRAM space.
+* ALL PARAMETERS ARE IN HOST BYTE ORDER.
+* @param smumgr the address of the powerplay hardware manager.
+* @param smc_addr the address in the SMC RAM to access.
+* @param value and output parameter for the data read from the SMC SRAM.
+*/
+int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+ uint32_t *value, uint32_t limit)
+{
+ int result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
+
+ if (result)
+ return result;
+
+ *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
+ return 0;
+}
+
+/**
+* Write a 32bit value to the SMC SRAM space.
+* ALL PARAMETERS ARE IN HOST BYTE ORDER.
+* @param smumgr the address of the powerplay hardware manager.
+* @param smc_addr the address in the SMC RAM to access.
+* @param value to write to the SMC SRAM.
+*/
+int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+ uint32_t value, uint32_t limit)
+{
+ int result;
+
+ result = fiji_set_smc_sram_address(smumgr, smc_addr, limit);
+
+ if (result)
+ return result;
+
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
+ return 0;
+}
+
+static uint32_t fiji_get_mask_for_firmware_type(uint32_t fw_type)
+{
+ uint32_t result = 0;
+
+ switch (fw_type) {
+ case UCODE_ID_SDMA0:
+ result = UCODE_ID_SDMA0_MASK;
+ break;
+ case UCODE_ID_SDMA1:
+ result = UCODE_ID_SDMA1_MASK;
+ break;
+ case UCODE_ID_CP_CE:
+ result = UCODE_ID_CP_CE_MASK;
+ break;
+ case UCODE_ID_CP_PFP:
+ result = UCODE_ID_CP_PFP_MASK;
+ break;
+ case UCODE_ID_CP_ME:
+ result = UCODE_ID_CP_ME_MASK;
+ break;
+ case UCODE_ID_CP_MEC_JT1:
+ result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
+ break;
+ case UCODE_ID_CP_MEC_JT2:
+ result = UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT2_MASK;
+ break;
+ case UCODE_ID_RLC_G:
+ result = UCODE_ID_RLC_G_MASK;
+ break;
+ default:
+ printk(KERN_ERR "UCode type is out of range!");
+ result = 0;
+ }
+
+ return result;
+}
+
+/* Populate one firmware image to the data structure */
+static int fiji_populate_single_firmware_entry(struct pp_smumgr *smumgr,
+ uint32_t fw_type, struct SMU_Entry *entry)
+{
+ int result;
+ struct cgs_firmware_info info = {0};
+
+ result = cgs_get_firmware_info(
+ smumgr->device,
+ fiji_convert_fw_type_to_cgs(fw_type),
+ &info);
+
+ if (!result) {
+ entry->version = 0;
+ entry->id = (uint16_t)fw_type;
+ entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
+ entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
+ entry->meta_data_addr_high = 0;
+ entry->meta_data_addr_low = 0;
+ entry->data_size_byte = info.image_size;
+ entry->num_register_entries = 0;
+
+ if (fw_type == UCODE_ID_RLC_G)
+ entry->flags = 1;
+ else
+ entry->flags = 0;
+ }
+
+ return result;
+}
+
+static int fiji_request_smu_load_fw(struct pp_smumgr *smumgr)
+{
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+ uint32_t fw_to_load;
+ struct SMU_DRAMData_TOC *toc;
+
+ if (priv->soft_regs_start)
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ priv->soft_regs_start +
+ offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
+ 0x0);
+
+ toc = (struct SMU_DRAMData_TOC *)priv->header;
+ toc->num_entries = 0;
+ toc->structure_version = 1;
+
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+ PP_ASSERT_WITH_CODE(
+ 0 == fiji_populate_single_firmware_entry(smumgr,
+ UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n" , return -1 );
+
+ fiji_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_DRV_DRAM_ADDR_HI,
+ priv->header_buffer.mc_addr_high);
+ fiji_send_msg_to_smc_with_parameter(smumgr,PPSMC_MSG_DRV_DRAM_ADDR_LO,
+ priv->header_buffer.mc_addr_low);
+
+ fw_to_load = UCODE_ID_RLC_G_MASK
+ + UCODE_ID_SDMA0_MASK
+ + UCODE_ID_SDMA1_MASK
+ + UCODE_ID_CP_CE_MASK
+ + UCODE_ID_CP_ME_MASK
+ + UCODE_ID_CP_PFP_MASK
+ + UCODE_ID_CP_MEC_MASK
+ + UCODE_ID_CP_MEC_JT1_MASK
+ + UCODE_ID_CP_MEC_JT2_MASK;
+
+ if (fiji_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_LoadUcodes, fw_to_load))
+ printk(KERN_ERR "Fail to Request SMU Load uCode");
+
+ return 0;
+}
+
+
+/* Check if the FW has been loaded, SMU will not return
+ * if loading has not finished.
+ */
+static int fiji_check_fw_load_finish(struct pp_smumgr *smumgr,
+ uint32_t fw_type)
+{
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+ uint32_t mask = fiji_get_mask_for_firmware_type(fw_type);
+
+ /* Check SOFT_REGISTERS_TABLE_28.UcodeLoadStatus */
+ if (smum_wait_on_indirect_register(smumgr, mmSMC_IND_INDEX,
+ priv->soft_regs_start +
+ offsetof(SMU73_SoftRegisters, UcodeLoadStatus),
+ mask, mask)) {
+ printk(KERN_ERR "check firmware loading failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int fiji_reload_firmware(struct pp_smumgr *smumgr)
+{
+ return smumgr->smumgr_funcs->start_smu(smumgr);
+}
+
+static bool fiji_is_hw_virtualization_enabled(struct pp_smumgr *smumgr)
+{
+ uint32_t value;
+
+ value = cgs_read_register(smumgr->device, mmBIF_IOV_FUNC_IDENTIFIER);
+ if (value & BIF_IOV_FUNC_IDENTIFIER__IOV_ENABLE_MASK) {
+ /* driver reads on SR-IOV enabled PF: 0x80000000
+ * driver reads on SR-IOV enabled VF: 0x80000001
+ * driver reads on SR-IOV disabled: 0x00000000
+ */
+ return true;
+ }
+ return false;
+}
+
+static int fiji_request_smu_specific_fw_load(struct pp_smumgr *smumgr, uint32_t fw_type)
+{
+ if (fiji_is_hw_virtualization_enabled(smumgr)) {
+ uint32_t masks = fiji_get_mask_for_firmware_type(fw_type);
+ if (fiji_send_msg_to_smc_with_parameter_without_waiting(smumgr,
+ PPSMC_MSG_LoadUcodes, masks))
+ printk(KERN_ERR "Fail to Request SMU Load uCode");
+ }
+ /* For non-virtualization cases,
+ * SMU loads all FWs at once in fiji_request_smu_load_fw.
+ */
+ return 0;
+}
+
+static int fiji_start_smu_in_protection_mode(struct pp_smumgr *smumgr)
+{
+ int result = 0;
+
+ /* Wait for smc boot up */
+ /* SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+ RCU_UC_EVENTS, boot_seq_done, 0); */
+
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+ result = fiji_upload_smu_firmware_image(smumgr);
+ if (result)
+ return result;
+
+ /* Clear status */
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ ixSMU_STATUS, 0);
+
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+ /* De-assert reset */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+ /* Wait for ROM firmware to initialize interrupt hendler */
+ /*SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND,
+ SMC_INTR_CNTL_MASK_0, 0x10040, 0xFFFFFFFF); */
+
+ /* Set SMU Auto Start */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMU_INPUT_DATA, AUTO_START, 1);
+
+ /* Clear firmware interrupt enable flag */
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ ixFIRMWARE_FLAGS, 0);
+
+ SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, RCU_UC_EVENTS,
+ INTERRUPTS_ENABLED, 1);
+
+ cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+ /* Wait for done bit to be set */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+ SMU_STATUS, SMU_DONE, 0);
+
+ /* Check pass/failed indicator */
+ if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMU_STATUS, SMU_PASS)) {
+ PP_ASSERT_WITH_CODE(false,
+ "SMU Firmware start failed!", return -1);
+ }
+
+ /* Wait for firmware to initialize */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+ FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+ return result;
+}
+
+static int fiji_start_smu_in_non_protection_mode(struct pp_smumgr *smumgr)
+{
+ int result = 0;
+
+ /* wait for smc boot up */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+ RCU_UC_EVENTS, boot_seq_done, 0);
+
+ /* Clear firmware interrupt enable flag */
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ ixFIRMWARE_FLAGS, 0);
+
+ /* Assert reset */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+ result = fiji_upload_smu_firmware_image(smumgr);
+ if (result)
+ return result;
+
+ /* Set smc instruct start point at 0x0 */
+ fiji_program_jump_on_start(smumgr);
+
+ /* Enable clock */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+ /* De-assert reset */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+ /* Wait for firmware to initialize */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+ FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+ return result;
+}
+
+int fiji_setup_pwr_virus(struct pp_smumgr *smumgr)
+{
+ int i, result = -1;
+ uint32_t reg, data;
+ PWR_Command_Table *virus = PwrVirusTable;
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+ priv->avfs.AvfsBtcStatus = AVFS_LOAD_VIRUS;
+ for (i = 0; (i < PWR_VIRUS_TABLE_SIZE); i++) {
+ switch (virus->command) {
+ case PwrCmdWrite:
+ reg = virus->reg;
+ data = virus->data;
+ cgs_write_register(smumgr->device, reg, data);
+ break;
+ case PwrCmdEnd:
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_LOADED;
+ result = 0;
+ break;
+ default:
+ printk(KERN_ERR "Table Exit with Invalid Command!");
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL;
+ result = -1;
+ break;
+ }
+ virus++;
+ }
+ return result;
+}
+
+static int fiji_start_avfs_btc(struct pp_smumgr *smumgr)
+{
+ int result = 0;
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_STARTED;
+ if (priv->avfs.AvfsBtcParam) {
+ if (!fiji_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_PerformBtc, priv->avfs.AvfsBtcParam)) {
+ if (!fiji_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs)) {
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_UNSAVED;
+ result = 0;
+ } else {
+ printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] Attempt"
+ " to Enable AVFS Failed!");
+ fiji_send_msg_to_smc(smumgr, PPSMC_MSG_DisableAvfs);
+ result = -1;
+ }
+ } else {
+ printk(KERN_ERR "[AVFS][fiji_start_avfs_btc] "
+ "PerformBTC SMU msg failed");
+ result = -1;
+ }
+ }
+ /* Soft-Reset to reset the engine before loading uCode */
+ /* halt */
+ cgs_write_register(smumgr->device, mmCP_MEC_CNTL, 0x50000000);
+ /* reset everything */
+ cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0xffffffff);
+ /* clear reset */
+ cgs_write_register(smumgr->device, mmGRBM_SOFT_RESET, 0);
+
+ return result;
+}
+
+int fiji_setup_pm_fuse_for_avfs(struct pp_smumgr *smumgr)
+{
+ int result = 0;
+ uint32_t table_start;
+ uint32_t charz_freq_addr, inversion_voltage_addr, charz_freq;
+ uint16_t inversion_voltage;
+
+ charz_freq = 0x30750000; /* In 10KHz units 0x00007530 Actual value */
+ inversion_voltage = 0x1A04; /* mV Q14.2 0x41A Actual value */
+
+ PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU73_Firmware_Header,
+ PmFuseTable), &table_start, 0x40000),
+ "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not communicate "
+ "starting address of PmFuse structure",
+ return -1;);
+
+ charz_freq_addr = table_start +
+ offsetof(struct SMU73_Discrete_PmFuses, PsmCharzFreq);
+ inversion_voltage_addr = table_start +
+ offsetof(struct SMU73_Discrete_PmFuses, InversionVoltage);
+
+ result = fiji_copy_bytes_to_smc(smumgr, charz_freq_addr,
+ (uint8_t *)(&charz_freq), sizeof(charz_freq), 0x40000);
+ PP_ASSERT_WITH_CODE(0 == result,
+ "[AVFS][fiji_setup_pm_fuse_for_avfs] charz_freq could not "
+ "be populated.", return -1;);
+
+ result = fiji_copy_bytes_to_smc(smumgr, inversion_voltage_addr,
+ (uint8_t *)(&inversion_voltage), sizeof(inversion_voltage), 0x40000);
+ PP_ASSERT_WITH_CODE(0 == result, "[AVFS][fiji_setup_pm_fuse_for_avfs] "
+ "charz_freq could not be populated.", return -1;);
+
+ return result;
+}
+
+int fiji_setup_graphics_level_structure(struct pp_smumgr *smumgr)
+{
+ int32_t vr_config;
+ uint32_t table_start;
+ uint32_t level_addr, vr_config_addr;
+ uint32_t level_size = sizeof(avfs_graphics_level);
+
+ PP_ASSERT_WITH_CODE(0 == fiji_read_smc_sram_dword(smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, DpmTable),
+ &table_start, 0x40000),
+ "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not "
+ "communicate starting address of DPM table",
+ return -1;);
+
+ /* Default value for vr_config =
+ * VR_MERGED_WITH_VDDC + VR_STATIC_VOLTAGE(VDDCI) */
+ vr_config = 0x01000500; /* Real value:0x50001 */
+
+ vr_config_addr = table_start +
+ offsetof(SMU73_Discrete_DpmTable, VRConfig);
+
+ PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, vr_config_addr,
+ (uint8_t *)&vr_config, sizeof(int32_t), 0x40000),
+ "[AVFS][Fiji_SetupGfxLvlStruct] Problems copying "
+ "vr_config value over to SMC",
+ return -1;);
+
+ level_addr = table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel);
+
+ PP_ASSERT_WITH_CODE(0 == fiji_copy_bytes_to_smc(smumgr, level_addr,
+ (uint8_t *)(&avfs_graphics_level), level_size, 0x40000),
+ "[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!",
+ return -1;);
+
+ return 0;
+}
+
+/* Work in Progress */
+int fiji_restore_vft_table(struct pp_smumgr *smumgr)
+{
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+ if (AVFS_BTC_COMPLETED_SAVED == priv->avfs.AvfsBtcStatus) {
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED;
+ return 0;
+ } else
+ return -EINVAL;
+}
+
+/* Work in Progress */
+int fiji_save_vft_table(struct pp_smumgr *smumgr)
+{
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+ if (AVFS_BTC_COMPLETED_SAVED == priv->avfs.AvfsBtcStatus) {
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED;
+ return 0;
+ } else
+ return -EINVAL;
+}
+
+int fiji_avfs_event_mgr(struct pp_smumgr *smumgr, bool smu_started)
+{
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+ switch (priv->avfs.AvfsBtcStatus) {
+ case AVFS_BTC_COMPLETED_SAVED: /*S3 State - Pre SMU Start */
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_RESTOREVFT_FAILED;
+ PP_ASSERT_WITH_CODE(0 == fiji_restore_vft_table(smumgr),
+ "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics "
+ "Level table over to SMU",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_RESTORED;
+ break;
+ case AVFS_BTC_COMPLETED_RESTORED: /*S3 State - Post SMU Start*/
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
+ PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
+ PPSMC_MSG_VftTableIsValid),
+ "[AVFS][fiji_avfs_event_mgr] SMU did not respond "
+ "correctly to VftTableIsValid Msg",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_SMUMSG_ERROR;
+ PP_ASSERT_WITH_CODE(0 == fiji_send_msg_to_smc(smumgr,
+ PPSMC_MSG_EnableAvfs),
+ "[AVFS][fiji_avfs_event_mgr] SMU did not respond "
+ "correctly to EnableAvfs Message Msg",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_SAVED;
+ break;
+ case AVFS_BTC_BOOT: /*Cold Boot State - Post SMU Start*/
+ if (!smu_started)
+ break;
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_FAILED;
+ PP_ASSERT_WITH_CODE(0 == fiji_setup_pm_fuse_for_avfs(smumgr),
+ "[AVFS][fiji_avfs_event_mgr] Failure at "
+ "fiji_setup_pm_fuse_for_avfs",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_DPMTABLESETUP_FAILED;
+ PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(smumgr),
+ "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level"
+ " table over to SMU",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_VIRUS_FAIL;
+ PP_ASSERT_WITH_CODE(0 == fiji_setup_pwr_virus(smumgr),
+ "[AVFS][fiji_avfs_event_mgr] Could not setup "
+ "Pwr Virus for AVFS ",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_FAILED;
+ PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(smumgr),
+ "[AVFS][fiji_avfs_event_mgr] Failure at "
+ "fiji_start_avfs_btc. AVFS Disabled",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_SAVEVFT_FAILED;
+ PP_ASSERT_WITH_CODE(0 == fiji_save_vft_table(smumgr),
+ "[AVFS][fiji_avfs_event_mgr] Could not save VFT Table",
+ return -1;);
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_COMPLETED_SAVED;
+ break;
+ case AVFS_BTC_DISABLED: /* Do nothing */
+ break;
+ case AVFS_BTC_NOTSUPPORTED: /* Do nothing */
+ break;
+ default:
+ printk(KERN_ERR "[AVFS] Something is broken. See log!");
+ break;
+ }
+ return 0;
+}
+
+static int fiji_start_smu(struct pp_smumgr *smumgr)
+{
+ int result = 0;
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+
+ /* Only start SMC if SMC RAM is not running */
+ if (!fiji_is_smc_ram_running(smumgr)) {
+ fiji_avfs_event_mgr(smumgr, false);
+
+ /* Check if SMU is running in protected mode */
+ if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
+ CGS_IND_REG__SMC,
+ SMU_FIRMWARE, SMU_MODE)) {
+ result = fiji_start_smu_in_non_protection_mode(smumgr);
+ if (result)
+ return result;
+ } else {
+ result = fiji_start_smu_in_protection_mode(smumgr);
+ if (result)
+ return result;
+ }
+ fiji_avfs_event_mgr(smumgr, true);
+ }
+
+ /* To initialize all clock gating before RLC loaded and running.*/
+ cgs_set_clockgating_state(smumgr->device,
+ AMD_IP_BLOCK_TYPE_GFX, AMD_CG_STATE_GATE);
+ cgs_set_clockgating_state(smumgr->device,
+ AMD_IP_BLOCK_TYPE_GMC, AMD_CG_STATE_GATE);
+ cgs_set_clockgating_state(smumgr->device,
+ AMD_IP_BLOCK_TYPE_SDMA, AMD_CG_STATE_GATE);
+ cgs_set_clockgating_state(smumgr->device,
+ AMD_IP_BLOCK_TYPE_COMMON, AMD_CG_STATE_GATE);
+
+ /* Setup SoftRegsStart here for register lookup in case
+ * DummyBackEnd is used and ProcessFirmwareHeader is not executed
+ */
+ fiji_read_smc_sram_dword(smumgr,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU73_Firmware_Header, SoftRegisters),
+ &(priv->soft_regs_start), 0x40000);
+
+ result = fiji_request_smu_load_fw(smumgr);
+
+ return result;
+}
+
+static bool fiji_is_hw_avfs_present(struct pp_smumgr *smumgr)
+{
+
+ uint32_t efuse = 0;
+ uint32_t mask = (1 << ((AVFS_EN_MSB - AVFS_EN_LSB) + 1)) - 1;
+
+ if (!atomctrl_read_efuse(smumgr->device, AVFS_EN_LSB, AVFS_EN_MSB,
+ mask, &efuse)) {
+ if (efuse)
+ return true;
+ }
+ return false;
+}
+
+/**
+* Write a 32bit value to the SMC SRAM space.
+* ALL PARAMETERS ARE IN HOST BYTE ORDER.
+* @param smumgr the address of the powerplay hardware manager.
+* @param smc_addr the address in the SMC RAM to access.
+* @param value to write to the SMC SRAM.
+*/
+static int fiji_smu_init(struct pp_smumgr *smumgr)
+{
+ struct fiji_smumgr *priv = (struct fiji_smumgr *)(smumgr->backend);
+ uint64_t mc_addr;
+
+ priv->header_buffer.data_size =
+ ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
+ smu_allocate_memory(smumgr->device,
+ priv->header_buffer.data_size,
+ CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+ PAGE_SIZE,
+ &mc_addr,
+ &priv->header_buffer.kaddr,
+ &priv->header_buffer.handle);
+
+ priv->header = priv->header_buffer.kaddr;
+ priv->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+ priv->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+ PP_ASSERT_WITH_CODE((NULL != priv->header),
+ "Out of memory.",
+ kfree(smumgr->backend);
+ cgs_free_gpu_mem(smumgr->device,
+ (cgs_handle_t)priv->header_buffer.handle);
+ return -1);
+
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_BOOT;
+ if (fiji_is_hw_avfs_present(smumgr))
+ /* AVFS Parameter
+ * 0 - BTC DC disabled, BTC AC disabled
+ * 1 - BTC DC enabled, BTC AC disabled
+ * 2 - BTC DC disabled, BTC AC enabled
+ * 3 - BTC DC enabled, BTC AC enabled
+ * Default is 0 - BTC DC disabled, BTC AC disabled
+ */
+ priv->avfs.AvfsBtcParam = 0;
+ else
+ priv->avfs.AvfsBtcStatus = AVFS_BTC_NOTSUPPORTED;
+
+ priv->acpi_optimization = 1;
+
+ return 0;
+}
+
+static int fiji_smu_fini(struct pp_smumgr *smumgr)
+{
+ if (smumgr->backend) {
+ kfree(smumgr->backend);
+ smumgr->backend = NULL;
+ }
+ return 0;
+}
+
+static const struct pp_smumgr_func fiji_smu_funcs = {
+ .smu_init = &fiji_smu_init,
+ .smu_fini = &fiji_smu_fini,
+ .start_smu = &fiji_start_smu,
+ .check_fw_load_finish = &fiji_check_fw_load_finish,
+ .request_smu_load_fw = &fiji_reload_firmware,
+ .request_smu_load_specific_fw = &fiji_request_smu_specific_fw_load,
+ .send_msg_to_smc = &fiji_send_msg_to_smc,
+ .send_msg_to_smc_with_parameter = &fiji_send_msg_to_smc_with_parameter,
+ .download_pptable_settings = NULL,
+ .upload_pptable_settings = NULL,
+};
+
+int fiji_smum_init(struct pp_smumgr *smumgr)
+{
+ struct fiji_smumgr *fiji_smu = NULL;
+
+ fiji_smu = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL);
+
+ if (fiji_smu == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = fiji_smu;
+ smumgr->smumgr_funcs = &fiji_smu_funcs;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h
new file mode 100644
index 000000000000..8cd22d9c9140
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015 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 _FIJI_SMUMANAGER_H_
+#define _FIJI_SMUMANAGER_H_
+
+enum AVFS_BTC_STATUS {
+ AVFS_BTC_BOOT = 0,
+ AVFS_BTC_BOOT_STARTEDSMU,
+ AVFS_LOAD_VIRUS,
+ AVFS_BTC_VIRUS_LOADED,
+ AVFS_BTC_VIRUS_FAIL,
+ AVFS_BTC_STARTED,
+ AVFS_BTC_FAILED,
+ AVFS_BTC_RESTOREVFT_FAILED,
+ AVFS_BTC_SAVEVFT_FAILED,
+ AVFS_BTC_DPMTABLESETUP_FAILED,
+ AVFS_BTC_COMPLETED_UNSAVED,
+ AVFS_BTC_COMPLETED_SAVED,
+ AVFS_BTC_COMPLETED_RESTORED,
+ AVFS_BTC_DISABLED,
+ AVFS_BTC_NOTSUPPORTED,
+ AVFS_BTC_SMUMSG_ERROR
+};
+
+struct fiji_smu_avfs {
+ enum AVFS_BTC_STATUS AvfsBtcStatus;
+ uint32_t AvfsBtcParam;
+};
+
+struct fiji_buffer_entry {
+ uint32_t data_size;
+ uint32_t mc_addr_low;
+ uint32_t mc_addr_high;
+ void *kaddr;
+ unsigned long handle;
+};
+
+struct fiji_smumgr {
+ uint8_t *header;
+ uint8_t *mec_image;
+ uint32_t soft_regs_start;
+ struct fiji_smu_avfs avfs;
+ uint32_t acpi_optimization;
+
+ struct fiji_buffer_entry header_buffer;
+};
+
+int fiji_smum_init(struct pp_smumgr *smumgr);
+int fiji_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
+ uint32_t *value, uint32_t limit);
+int fiji_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smc_addr,
+ uint32_t value, uint32_t limit);
+int fiji_copy_bytes_to_smc(struct pp_smumgr *smumgr, uint32_t smcStartAddress,
+ const uint8_t *src, uint32_t byteCount, uint32_t limit);
+
+#endif
+
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
new file mode 100644
index 000000000000..063ae71c9830
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "pp_instance.h"
+#include "smumgr.h"
+#include "cgs_common.h"
+#include "linux/delay.h"
+#include "cz_smumgr.h"
+#include "tonga_smumgr.h"
+#include "fiji_smumgr.h"
+
+int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
+{
+ struct pp_smumgr *smumgr;
+
+ if ((handle == NULL) || (pp_init == NULL))
+ return -EINVAL;
+
+ smumgr = kzalloc(sizeof(struct pp_smumgr), GFP_KERNEL);
+ if (smumgr == NULL)
+ return -ENOMEM;
+
+ smumgr->device = pp_init->device;
+ smumgr->chip_family = pp_init->chip_family;
+ smumgr->chip_id = pp_init->chip_id;
+ smumgr->hw_revision = pp_init->rev_id;
+ smumgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
+ smumgr->reload_fw = 1;
+ handle->smu_mgr = smumgr;
+
+ switch (smumgr->chip_family) {
+ case AMD_FAMILY_CZ:
+ cz_smum_init(smumgr);
+ break;
+ case AMD_FAMILY_VI:
+ switch (smumgr->chip_id) {
+ case CHIP_TONGA:
+ tonga_smum_init(smumgr);
+ break;
+ case CHIP_FIJI:
+ fiji_smum_init(smumgr);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ kfree(smumgr);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int smum_fini(struct pp_smumgr *smumgr)
+{
+ kfree(smumgr);
+ return 0;
+}
+
+int smum_get_argument(struct pp_smumgr *smumgr)
+{
+ if (NULL != smumgr->smumgr_funcs->get_argument)
+ return smumgr->smumgr_funcs->get_argument(smumgr);
+
+ return 0;
+}
+
+int smum_download_powerplay_table(struct pp_smumgr *smumgr,
+ void **table)
+{
+ if (NULL != smumgr->smumgr_funcs->download_pptable_settings)
+ return smumgr->smumgr_funcs->download_pptable_settings(smumgr,
+ table);
+
+ return 0;
+}
+
+int smum_upload_powerplay_table(struct pp_smumgr *smumgr)
+{
+ if (NULL != smumgr->smumgr_funcs->upload_pptable_settings)
+ return smumgr->smumgr_funcs->upload_pptable_settings(smumgr);
+
+ return 0;
+}
+
+int smum_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+ if (smumgr == NULL || smumgr->smumgr_funcs->send_msg_to_smc == NULL)
+ return -EINVAL;
+
+ return smumgr->smumgr_funcs->send_msg_to_smc(smumgr, msg);
+}
+
+int smum_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter)
+{
+ if (smumgr == NULL ||
+ smumgr->smumgr_funcs->send_msg_to_smc_with_parameter == NULL)
+ return -EINVAL;
+ return smumgr->smumgr_funcs->send_msg_to_smc_with_parameter(
+ smumgr, msg, parameter);
+}
+
+/*
+ * Returns once the part of the register indicated by the mask has
+ * reached the given value.
+ */
+int smum_wait_on_register(struct pp_smumgr *smumgr,
+ uint32_t index,
+ uint32_t value, uint32_t mask)
+{
+ uint32_t i;
+ uint32_t cur_value;
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < smumgr->usec_timeout; i++) {
+ cur_value = cgs_read_register(smumgr->device, index);
+ if ((cur_value & mask) == (value & mask))
+ break;
+ udelay(1);
+ }
+
+ /* timeout means wrong logic*/
+ if (i == smumgr->usec_timeout)
+ return -1;
+
+ return 0;
+}
+
+int smum_wait_for_register_unequal(struct pp_smumgr *smumgr,
+ uint32_t index,
+ uint32_t value, uint32_t mask)
+{
+ uint32_t i;
+ uint32_t cur_value;
+
+ if (smumgr == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < smumgr->usec_timeout; i++) {
+ cur_value = cgs_read_register(smumgr->device,
+ index);
+ if ((cur_value & mask) != (value & mask))
+ break;
+ udelay(1);
+ }
+
+ /* timeout means wrong logic */
+ if (i == smumgr->usec_timeout)
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Returns once the part of the register indicated by the mask
+ * has reached the given value.The indirect space is described by
+ * giving the memory-mapped index of the indirect index register.
+ */
+int smum_wait_on_indirect_register(struct pp_smumgr *smumgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value,
+ uint32_t mask)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ cgs_write_register(smumgr->device, indirect_port, index);
+ return smum_wait_on_register(smumgr, indirect_port + 1,
+ mask, value);
+}
+
+void smum_wait_for_indirect_register_unequal(
+ struct pp_smumgr *smumgr,
+ uint32_t indirect_port,
+ uint32_t index,
+ uint32_t value,
+ uint32_t mask)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return;
+ cgs_write_register(smumgr->device, indirect_port, index);
+ smum_wait_for_register_unequal(smumgr, indirect_port + 1,
+ value, mask);
+}
+
+int smu_allocate_memory(void *device, uint32_t size,
+ enum cgs_gpu_mem_type type,
+ uint32_t byte_align, uint64_t *mc_addr,
+ void **kptr, void *handle)
+{
+ int ret = 0;
+ cgs_handle_t cgs_handle;
+
+ if (device == NULL || handle == NULL ||
+ mc_addr == NULL || kptr == NULL)
+ return -EINVAL;
+
+ ret = cgs_alloc_gpu_mem(device, type, size, byte_align,
+ 0, 0, (cgs_handle_t *)handle);
+ if (ret)
+ return -ENOMEM;
+
+ cgs_handle = *(cgs_handle_t *)handle;
+
+ ret = cgs_gmap_gpu_mem(device, cgs_handle, mc_addr);
+ if (ret)
+ goto error_gmap;
+
+ ret = cgs_kmap_gpu_mem(device, cgs_handle, kptr);
+ if (ret)
+ goto error_kmap;
+
+ return 0;
+
+error_kmap:
+ cgs_gunmap_gpu_mem(device, cgs_handle);
+
+error_gmap:
+ cgs_free_gpu_mem(device, cgs_handle);
+ return ret;
+}
+
+int smu_free_memory(void *device, void *handle)
+{
+ cgs_handle_t cgs_handle = (cgs_handle_t)handle;
+
+ if (device == NULL || handle == NULL)
+ return -EINVAL;
+
+ cgs_kunmap_gpu_mem(device, cgs_handle);
+ cgs_gunmap_gpu_mem(device, cgs_handle);
+ cgs_free_gpu_mem(device, cgs_handle);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
new file mode 100644
index 000000000000..ebdb43a8daef
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+
+#include "smumgr.h"
+#include "tonga_smumgr.h"
+#include "pp_debug.h"
+#include "smu_ucode_xfer_vi.h"
+#include "tonga_ppsmc.h"
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
+#include "cgs_common.h"
+
+#define TONGA_SMC_SIZE 0x20000
+#define BUFFER_SIZE 80000
+#define MAX_STRING_SIZE 15
+#define BUFFER_SIZETWO 131072 /*128 *1024*/
+
+/**
+* Set the address for reading/writing the SMC SRAM space.
+* @param smumgr the address of the powerplay hardware manager.
+* @param smcAddress the address in the SMC RAM to access.
+*/
+static int tonga_set_smc_sram_address(struct pp_smumgr *smumgr,
+ uint32_t smcAddress, uint32_t limit)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+ PP_ASSERT_WITH_CODE((0 == (3 & smcAddress)),
+ "SMC address must be 4 byte aligned.",
+ return -1;);
+
+ PP_ASSERT_WITH_CODE((limit > (smcAddress + 3)),
+ "SMC address is beyond the SMC RAM area.",
+ return -1;);
+
+ cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smcAddress);
+ SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0);
+
+ return 0;
+}
+
+/**
+* Copy bytes from an array into the SMC RAM space.
+*
+* @param smumgr the address of the powerplay SMU manager.
+* @param smcStartAddress the start address in the SMC RAM to copy bytes to.
+* @param src the byte array to copy the bytes from.
+* @param byteCount the number of bytes to copy.
+*/
+int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr,
+ uint32_t smcStartAddress, const uint8_t *src,
+ uint32_t byteCount, uint32_t limit)
+{
+ uint32_t addr;
+ uint32_t data, orig_data;
+ int result = 0;
+ uint32_t extra_shift;
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+ PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)),
+ "SMC address must be 4 byte aligned.",
+ return 0;);
+
+ PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)),
+ "SMC address is beyond the SMC RAM area.",
+ return 0;);
+
+ addr = smcStartAddress;
+
+ while (byteCount >= 4) {
+ /*
+ * Bytes are written into the
+ * SMC address space with the MSB first
+ */
+ data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
+
+ result = tonga_set_smc_sram_address(smumgr, addr, limit);
+
+ if (result)
+ goto out;
+
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+
+ src += 4;
+ byteCount -= 4;
+ addr += 4;
+ }
+
+ if (0 != byteCount) {
+ /* Now write odd bytes left, do a read modify write cycle */
+ data = 0;
+
+ result = tonga_set_smc_sram_address(smumgr, addr, limit);
+ if (result)
+ goto out;
+
+ orig_data = cgs_read_register(smumgr->device,
+ mmSMC_IND_DATA_0);
+ extra_shift = 8 * (4 - byteCount);
+
+ while (byteCount > 0) {
+ data = (data << 8) + *src++;
+ byteCount--;
+ }
+
+ data <<= extra_shift;
+ data |= (orig_data & ~((~0UL) << extra_shift));
+
+ result = tonga_set_smc_sram_address(smumgr, addr, limit);
+ if (result)
+ goto out;
+
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
+ }
+
+out:
+ return result;
+}
+
+
+int tonga_program_jump_on_start(struct pp_smumgr *smumgr)
+{
+ static unsigned char pData[] = { 0xE0, 0x00, 0x80, 0x40 };
+
+ tonga_copy_bytes_to_smc(smumgr, 0x0, pData, 4, sizeof(pData)+1);
+
+ return 0;
+}
+
+/**
+* Return if the SMC is currently running.
+*
+* @param smumgr the address of the powerplay hardware manager.
+*/
+static int tonga_is_smc_ram_running(struct pp_smumgr *smumgr)
+{
+ return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_CLOCK_CNTL_0, ck_disable))
+ && (0x20100 <= cgs_read_ind_register(smumgr->device,
+ CGS_IND_REG__SMC, ixSMC_PC_C)));
+}
+
+static int tonga_send_msg_to_smc_offset(struct pp_smumgr *smumgr)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+ cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000);
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test);
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+ return 0;
+}
+
+/**
+* Send a message to the SMC, and wait for its response.
+*
+* @param smumgr the address of the powerplay hardware manager.
+* @param msg the message to send.
+* @return The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ if (!tonga_is_smc_ram_running(smumgr))
+ return -1;
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ PP_ASSERT_WITH_CODE(
+ 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
+ "Failed to send Previous Message.",
+ );
+
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ PP_ASSERT_WITH_CODE(
+ 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
+ "Failed to send Message.",
+ );
+
+ return 0;
+}
+
+/*
+* Send a message to the SMC, and do not wait for its response.
+*
+* @param smumgr the address of the powerplay hardware manager.
+* @param msg the message to send.
+* @return The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc_without_waiting
+ (struct pp_smumgr *smumgr, uint16_t msg)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ PP_ASSERT_WITH_CODE(
+ 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP),
+ "Failed to send Previous Message.",
+ );
+ cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg);
+
+ return 0;
+}
+
+/*
+* Send a message to the SMC with parameter
+*
+* @param smumgr: the address of the powerplay hardware manager.
+* @param msg: the message to send.
+* @param parameter: the parameter to send
+* @return The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ if (!tonga_is_smc_ram_running(smumgr))
+ return PPSMC_Result_Failed;
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+ cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+
+ return tonga_send_msg_to_smc(smumgr, msg);
+}
+
+/*
+* Send a message to the SMC with parameter, do not wait for response
+*
+* @param smumgr: the address of the powerplay hardware manager.
+* @param msg: the message to send.
+* @param parameter: the parameter to send
+* @return The response that came from the SMC.
+*/
+static int tonga_send_msg_to_smc_with_parameter_without_waiting(
+ struct pp_smumgr *smumgr,
+ uint16_t msg, uint32_t parameter)
+{
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0);
+
+ cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter);
+
+ return tonga_send_msg_to_smc_without_waiting(smumgr, msg);
+}
+
+/*
+ * Read a 32bit value from the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param smumgr the address of the powerplay hardware manager.
+ * @param smcAddress the address in the SMC RAM to access.
+ * @param value and output parameter for the data read from the SMC SRAM.
+ */
+int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr,
+ uint32_t smcAddress, uint32_t *value,
+ uint32_t limit)
+{
+ int result;
+
+ result = tonga_set_smc_sram_address(smumgr, smcAddress, limit);
+
+ if (0 != result)
+ return result;
+
+ *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0);
+
+ return 0;
+}
+
+/*
+ * Write a 32bit value to the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param smumgr the address of the powerplay hardware manager.
+ * @param smcAddress the address in the SMC RAM to access.
+ * @param value to write to the SMC SRAM.
+ */
+int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr,
+ uint32_t smcAddress, uint32_t value,
+ uint32_t limit)
+{
+ int result;
+
+ result = tonga_set_smc_sram_address(smumgr, smcAddress, limit);
+
+ if (0 != result)
+ return result;
+
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value);
+
+ return 0;
+}
+
+static int tonga_smu_fini(struct pp_smumgr *smumgr)
+{
+ if (smumgr->backend != NULL) {
+ kfree(smumgr->backend);
+ smumgr->backend = NULL;
+ }
+ return 0;
+}
+
+static enum cgs_ucode_id tonga_convert_fw_type_to_cgs(uint32_t fw_type)
+{
+ enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM;
+
+ switch (fw_type) {
+ case UCODE_ID_SMU:
+ result = CGS_UCODE_ID_SMU;
+ break;
+ case UCODE_ID_SDMA0:
+ result = CGS_UCODE_ID_SDMA0;
+ break;
+ case UCODE_ID_SDMA1:
+ result = CGS_UCODE_ID_SDMA1;
+ break;
+ case UCODE_ID_CP_CE:
+ result = CGS_UCODE_ID_CP_CE;
+ break;
+ case UCODE_ID_CP_PFP:
+ result = CGS_UCODE_ID_CP_PFP;
+ break;
+ case UCODE_ID_CP_ME:
+ result = CGS_UCODE_ID_CP_ME;
+ break;
+ case UCODE_ID_CP_MEC:
+ result = CGS_UCODE_ID_CP_MEC;
+ break;
+ case UCODE_ID_CP_MEC_JT1:
+ result = CGS_UCODE_ID_CP_MEC_JT1;
+ break;
+ case UCODE_ID_CP_MEC_JT2:
+ result = CGS_UCODE_ID_CP_MEC_JT2;
+ break;
+ case UCODE_ID_RLC_G:
+ result = CGS_UCODE_ID_RLC_G;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * Convert the PPIRI firmware type to SMU type mask.
+ * For MEC, we need to check all MEC related type
+*/
+static uint16_t tonga_get_mask_for_firmware_type(uint16_t firmwareType)
+{
+ uint16_t result = 0;
+
+ switch (firmwareType) {
+ case UCODE_ID_SDMA0:
+ result = UCODE_ID_SDMA0_MASK;
+ break;
+ case UCODE_ID_SDMA1:
+ result = UCODE_ID_SDMA1_MASK;
+ break;
+ case UCODE_ID_CP_CE:
+ result = UCODE_ID_CP_CE_MASK;
+ break;
+ case UCODE_ID_CP_PFP:
+ result = UCODE_ID_CP_PFP_MASK;
+ break;
+ case UCODE_ID_CP_ME:
+ result = UCODE_ID_CP_ME_MASK;
+ break;
+ case UCODE_ID_CP_MEC:
+ case UCODE_ID_CP_MEC_JT1:
+ case UCODE_ID_CP_MEC_JT2:
+ result = UCODE_ID_CP_MEC_MASK;
+ break;
+ case UCODE_ID_RLC_G:
+ result = UCODE_ID_RLC_G_MASK;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * Check if the FW has been loaded,
+ * SMU will not return if loading has not finished.
+*/
+static int tonga_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fwType)
+{
+ uint16_t fwMask = tonga_get_mask_for_firmware_type(fwType);
+
+ if (0 != SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND,
+ SOFT_REGISTERS_TABLE_28, fwMask, fwMask)) {
+ printk(KERN_ERR "[ powerplay ] check firmware loading failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Populate one firmware image to the data structure */
+static int tonga_populate_single_firmware_entry(struct pp_smumgr *smumgr,
+ uint16_t firmware_type,
+ struct SMU_Entry *pentry)
+{
+ int result;
+ struct cgs_firmware_info info = {0};
+
+ result = cgs_get_firmware_info(
+ smumgr->device,
+ tonga_convert_fw_type_to_cgs(firmware_type),
+ &info);
+
+ if (result == 0) {
+ pentry->version = 0;
+ pentry->id = (uint16_t)firmware_type;
+ pentry->image_addr_high = smu_upper_32_bits(info.mc_addr);
+ pentry->image_addr_low = smu_lower_32_bits(info.mc_addr);
+ pentry->meta_data_addr_high = 0;
+ pentry->meta_data_addr_low = 0;
+ pentry->data_size_byte = info.image_size;
+ pentry->num_register_entries = 0;
+
+ if (firmware_type == UCODE_ID_RLC_G)
+ pentry->flags = 1;
+ else
+ pentry->flags = 0;
+ } else {
+ return result;
+ }
+
+ return result;
+}
+
+static int tonga_request_smu_reload_fw(struct pp_smumgr *smumgr)
+{
+ struct tonga_smumgr *tonga_smu =
+ (struct tonga_smumgr *)(smumgr->backend);
+ uint16_t fw_to_load;
+ int result = 0;
+ struct SMU_DRAMData_TOC *toc;
+ /**
+ * First time this gets called during SmuMgr init,
+ * we haven't processed SMU header file yet,
+ * so Soft Register Start offset is unknown.
+ * However, for this case, UcodeLoadStatus is already 0,
+ * so we can skip this if the Soft Registers Start offset is 0.
+ */
+ cgs_write_ind_register(smumgr->device,
+ CGS_IND_REG__SMC, ixSOFT_REGISTERS_TABLE_28, 0);
+
+ tonga_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_SMU_DRAM_ADDR_HI,
+ tonga_smu->smu_buffer.mc_addr_high);
+ tonga_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_SMU_DRAM_ADDR_LO,
+ tonga_smu->smu_buffer.mc_addr_low);
+
+ toc = (struct SMU_DRAMData_TOC *)tonga_smu->pHeader;
+ toc->num_entries = 0;
+ toc->structure_version = 1;
+
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry(smumgr,
+ UCODE_ID_RLC_G,
+ &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n",
+ return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry(smumgr,
+ UCODE_ID_CP_CE,
+ &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n",
+ return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_populate_single_firmware_entry
+ (smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]),
+ "Failed to Get Firmware Entry.\n", return -1);
+
+ tonga_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_DRV_DRAM_ADDR_HI,
+ tonga_smu->header_buffer.mc_addr_high);
+ tonga_send_msg_to_smc_with_parameter(smumgr,
+ PPSMC_MSG_DRV_DRAM_ADDR_LO,
+ tonga_smu->header_buffer.mc_addr_low);
+
+ fw_to_load = UCODE_ID_RLC_G_MASK
+ + UCODE_ID_SDMA0_MASK
+ + UCODE_ID_SDMA1_MASK
+ + UCODE_ID_CP_CE_MASK
+ + UCODE_ID_CP_ME_MASK
+ + UCODE_ID_CP_PFP_MASK
+ + UCODE_ID_CP_MEC_MASK;
+
+ PP_ASSERT_WITH_CODE(
+ 0 == tonga_send_msg_to_smc_with_parameter_without_waiting(
+ smumgr, PPSMC_MSG_LoadUcodes, fw_to_load),
+ "Fail to Request SMU Load uCode", return 0);
+
+ return result;
+}
+
+static int tonga_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
+ uint32_t firmwareType)
+{
+ return 0;
+}
+
+/**
+ * Upload the SMC firmware to the SMC microcontroller.
+ *
+ * @param smumgr the address of the powerplay hardware manager.
+ * @param pFirmware the data structure containing the various sections of the firmware.
+ */
+static int tonga_smu_upload_firmware_image(struct pp_smumgr *smumgr)
+{
+ const uint8_t *src;
+ uint32_t byte_count;
+ uint32_t *data;
+ struct cgs_firmware_info info = {0};
+
+ if (smumgr == NULL || smumgr->device == NULL)
+ return -EINVAL;
+
+ cgs_get_firmware_info(smumgr->device,
+ tonga_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
+
+ if (info.image_size & 3) {
+ printk(KERN_ERR "[ powerplay ] SMC ucode is not 4 bytes aligned\n");
+ return -EINVAL;
+ }
+
+ if (info.image_size > TONGA_SMC_SIZE) {
+ printk(KERN_ERR "[ powerplay ] SMC address is beyond the SMC RAM area\n");
+ return -EINVAL;
+ }
+
+ cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000);
+ SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
+
+ byte_count = info.image_size;
+ src = (const uint8_t *)info.kptr;
+
+ data = (uint32_t *)src;
+ for (; byte_count >= 4; data++, byte_count -= 4)
+ cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]);
+
+ SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
+
+ return 0;
+}
+
+static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr)
+{
+ int result;
+
+ /* Assert reset */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+ result = tonga_smu_upload_firmware_image(smumgr);
+ if (result)
+ return result;
+
+ /* Clear status */
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ ixSMU_STATUS, 0);
+
+ /* Enable clock */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+ /* De-assert reset */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+ /* Set SMU Auto Start */
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMU_INPUT_DATA, AUTO_START, 1);
+
+ /* Clear firmware interrupt enable flag */
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ ixFIRMWARE_FLAGS, 0);
+
+ SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+ RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1);
+
+ /**
+ * Call Test SMU message with 0x20000 offset to trigger SMU start
+ */
+ tonga_send_msg_to_smc_offset(smumgr);
+
+ /* Wait for done bit to be set */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+ SMU_STATUS, SMU_DONE, 0);
+
+ /* Check pass/failed indicator */
+ if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device,
+ CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS)) {
+ printk(KERN_ERR "[ powerplay ] SMU Firmware start failed\n");
+ return -EINVAL;
+ }
+
+ /* Wait for firmware to initialize */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+ FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+ return 0;
+}
+
+
+static int tonga_start_in_non_protection_mode(struct pp_smumgr *smumgr)
+{
+ int result = 0;
+
+ /* wait for smc boot up */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
+ RCU_UC_EVENTS, boot_seq_done, 0);
+
+ /*Clear firmware interrupt enable flag*/
+ cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
+ ixFIRMWARE_FLAGS, 0);
+
+
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 1);
+
+ result = tonga_smu_upload_firmware_image(smumgr);
+
+ if (result != 0)
+ return result;
+
+ /* Set smc instruct start point at 0x0 */
+ tonga_program_jump_on_start(smumgr);
+
+
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0);
+
+ /*De-assert reset*/
+ SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMC_SYSCON_RESET_CNTL, rst_reg, 0);
+
+ /* Wait for firmware to initialize */
+ SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND,
+ FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1);
+
+ return result;
+}
+
+static int tonga_start_smu(struct pp_smumgr *smumgr)
+{
+ int result;
+
+ /* Only start SMC if SMC RAM is not running */
+ if (!tonga_is_smc_ram_running(smumgr)) {
+ /*Check if SMU is running in protected mode*/
+ if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
+ SMU_FIRMWARE, SMU_MODE)) {
+ result = tonga_start_in_non_protection_mode(smumgr);
+ if (result)
+ return result;
+ } else {
+ result = tonga_start_in_protection_mode(smumgr);
+ if (result)
+ return result;
+ }
+ }
+
+ result = tonga_request_smu_reload_fw(smumgr);
+
+ return result;
+}
+
+/**
+ * Write a 32bit value to the SMC SRAM space.
+ * ALL PARAMETERS ARE IN HOST BYTE ORDER.
+ * @param smumgr the address of the powerplay hardware manager.
+ * @param smcAddress the address in the SMC RAM to access.
+ * @param value to write to the SMC SRAM.
+ */
+static int tonga_smu_init(struct pp_smumgr *smumgr)
+{
+ struct tonga_smumgr *tonga_smu;
+ uint8_t *internal_buf;
+ uint64_t mc_addr = 0;
+ /* Allocate memory for backend private data */
+ tonga_smu = (struct tonga_smumgr *)(smumgr->backend);
+ tonga_smu->header_buffer.data_size =
+ ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
+ tonga_smu->smu_buffer.data_size = 200*4096;
+
+ smu_allocate_memory(smumgr->device,
+ tonga_smu->header_buffer.data_size,
+ CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+ PAGE_SIZE,
+ &mc_addr,
+ &tonga_smu->header_buffer.kaddr,
+ &tonga_smu->header_buffer.handle);
+
+ tonga_smu->pHeader = tonga_smu->header_buffer.kaddr;
+ tonga_smu->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+ tonga_smu->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+ PP_ASSERT_WITH_CODE((NULL != tonga_smu->pHeader),
+ "Out of memory.",
+ kfree(smumgr->backend);
+ cgs_free_gpu_mem(smumgr->device,
+ (cgs_handle_t)tonga_smu->header_buffer.handle);
+ return -1);
+
+ smu_allocate_memory(smumgr->device,
+ tonga_smu->smu_buffer.data_size,
+ CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
+ PAGE_SIZE,
+ &mc_addr,
+ &tonga_smu->smu_buffer.kaddr,
+ &tonga_smu->smu_buffer.handle);
+
+ internal_buf = tonga_smu->smu_buffer.kaddr;
+ tonga_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr);
+ tonga_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr);
+
+ PP_ASSERT_WITH_CODE((NULL != internal_buf),
+ "Out of memory.",
+ kfree(smumgr->backend);
+ cgs_free_gpu_mem(smumgr->device,
+ (cgs_handle_t)tonga_smu->smu_buffer.handle);
+ return -1;);
+
+ return 0;
+}
+
+static const struct pp_smumgr_func tonga_smu_funcs = {
+ .smu_init = &tonga_smu_init,
+ .smu_fini = &tonga_smu_fini,
+ .start_smu = &tonga_start_smu,
+ .check_fw_load_finish = &tonga_check_fw_load_finish,
+ .request_smu_load_fw = &tonga_request_smu_reload_fw,
+ .request_smu_load_specific_fw = &tonga_request_smu_load_specific_fw,
+ .send_msg_to_smc = &tonga_send_msg_to_smc,
+ .send_msg_to_smc_with_parameter = &tonga_send_msg_to_smc_with_parameter,
+ .download_pptable_settings = NULL,
+ .upload_pptable_settings = NULL,
+};
+
+int tonga_smum_init(struct pp_smumgr *smumgr)
+{
+ struct tonga_smumgr *tonga_smu = NULL;
+
+ tonga_smu = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL);
+
+ if (tonga_smu == NULL)
+ return -ENOMEM;
+
+ smumgr->backend = tonga_smu;
+ smumgr->smumgr_funcs = &tonga_smu_funcs;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h
new file mode 100644
index 000000000000..33c788d7f05c
--- /dev/null
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 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 _TONGA_SMUMGR_H_
+#define _TONGA_SMUMGR_H_
+
+struct tonga_buffer_entry {
+ uint32_t data_size;
+ uint32_t mc_addr_low;
+ uint32_t mc_addr_high;
+ void *kaddr;
+ unsigned long handle;
+};
+
+struct tonga_smumgr {
+ uint8_t *pHeader;
+ uint8_t *pMecImage;
+ uint32_t ulSoftRegsStart;
+
+ struct tonga_buffer_entry header_buffer;
+ struct tonga_buffer_entry smu_buffer;
+};
+
+extern int tonga_smum_init(struct pp_smumgr *smumgr);
+extern int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr,
+ uint32_t smcStartAddress, const uint8_t *src,
+ uint32_t byteCount, uint32_t limit);
+extern int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
+ uint32_t *value, uint32_t limit);
+extern int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr, uint32_t smcAddress,
+ uint32_t value, uint32_t limit);
+
+#endif
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
index 3a4820e863ec..8b2becd1aa07 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
@@ -47,6 +47,8 @@ static void amd_sched_rq_init(struct amd_sched_rq *rq)
static void amd_sched_rq_add_entity(struct amd_sched_rq *rq,
struct amd_sched_entity *entity)
{
+ if (!list_empty(&entity->list))
+ return;
spin_lock(&rq->lock);
list_add_tail(&entity->list, &rq->entities);
spin_unlock(&rq->lock);
@@ -55,6 +57,8 @@ static void amd_sched_rq_add_entity(struct amd_sched_rq *rq,
static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,
struct amd_sched_entity *entity)
{
+ if (list_empty(&entity->list))
+ return;
spin_lock(&rq->lock);
list_del_init(&entity->list);
if (rq->current_entity == entity)
@@ -138,9 +142,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
atomic_set(&entity->fence_seq, 0);
entity->fence_context = fence_context_alloc(1);
- /* Add the entity to the run queue */
- amd_sched_rq_add_entity(rq, entity);
-
return 0;
}
@@ -302,9 +303,11 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
spin_unlock(&entity->queue_lock);
/* first job wakes up scheduler */
- if (first)
+ if (first) {
+ /* Add the entity to the run queue */
+ amd_sched_rq_add_entity(entity->rq, entity);
amd_sched_wakeup(sched);
-
+ }
return added;
}
@@ -349,14 +352,17 @@ static struct amd_sched_entity *
amd_sched_select_entity(struct amd_gpu_scheduler *sched)
{
struct amd_sched_entity *entity;
+ int i;
if (!amd_sched_ready(sched))
return NULL;
/* Kernel run queue has higher priority than normal run queue*/
- entity = amd_sched_rq_select_entity(&sched->kernel_rq);
- if (entity == NULL)
- entity = amd_sched_rq_select_entity(&sched->sched_rq);
+ for (i = 0; i < AMD_SCHED_MAX_PRIORITY; i++) {
+ entity = amd_sched_rq_select_entity(&sched->sched_rq[i]);
+ if (entity)
+ break;
+ }
return entity;
}
@@ -478,12 +484,13 @@ int amd_sched_init(struct amd_gpu_scheduler *sched,
struct amd_sched_backend_ops *ops,
unsigned hw_submission, long timeout, const char *name)
{
+ int i;
sched->ops = ops;
sched->hw_submission_limit = hw_submission;
sched->name = name;
sched->timeout = timeout;
- amd_sched_rq_init(&sched->sched_rq);
- amd_sched_rq_init(&sched->kernel_rq);
+ for (i = 0; i < AMD_SCHED_MAX_PRIORITY; i++)
+ amd_sched_rq_init(&sched->sched_rq[i]);
init_waitqueue_head(&sched->wake_up_worker);
init_waitqueue_head(&sched->job_scheduled);
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
index a0f0ae53aacd..9403145d7bee 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
@@ -104,6 +104,12 @@ struct amd_sched_backend_ops {
struct fence *(*run_job)(struct amd_sched_job *sched_job);
};
+enum amd_sched_priority {
+ AMD_SCHED_PRIORITY_KERNEL = 0,
+ AMD_SCHED_PRIORITY_NORMAL,
+ AMD_SCHED_MAX_PRIORITY
+};
+
/**
* One scheduler is implemented for each hardware ring
*/
@@ -112,8 +118,7 @@ struct amd_gpu_scheduler {
uint32_t hw_submission_limit;
long timeout;
const char *name;
- struct amd_sched_rq sched_rq;
- struct amd_sched_rq kernel_rq;
+ struct amd_sched_rq sched_rq[AMD_SCHED_MAX_PRIORITY];
wait_queue_head_t wake_up_worker;
wait_queue_head_t job_scheduled;
atomic_t hw_rq_count;
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index cebcab560626..0293eb74d777 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -928,11 +928,10 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc,
}
}
- mutex_lock(&dev->struct_mutex);
if (dcrtc->cursor_obj) {
dcrtc->cursor_obj->update = NULL;
dcrtc->cursor_obj->update_data = NULL;
- drm_gem_object_unreference(&dcrtc->cursor_obj->obj);
+ drm_gem_object_unreference_unlocked(&dcrtc->cursor_obj->obj);
}
dcrtc->cursor_obj = obj;
dcrtc->cursor_w = w;
@@ -942,14 +941,12 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc,
obj->update_data = dcrtc;
obj->update = cursor_update;
}
- mutex_unlock(&dev->struct_mutex);
return ret;
}
static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
- struct drm_device *dev = crtc->dev;
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
int ret;
@@ -957,11 +954,9 @@ static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
if (!dcrtc->variant->has_spu_adv_reg)
return -EFAULT;
- mutex_lock(&dev->struct_mutex);
dcrtc->cursor_x = x;
dcrtc->cursor_y = y;
ret = armada_drm_crtc_cursor_update(dcrtc, false);
- mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -972,7 +967,7 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
struct armada_private *priv = crtc->dev->dev_private;
if (dcrtc->cursor_obj)
- drm_gem_object_unreference(&dcrtc->cursor_obj->obj);
+ drm_gem_object_unreference_unlocked(&dcrtc->cursor_obj->obj);
priv->dcrtc[dcrtc->num] = NULL;
drm_crtc_cleanup(&dcrtc->crtc);
@@ -1074,7 +1069,7 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
return 0;
}
-static struct drm_crtc_funcs armada_crtc_funcs = {
+static const struct drm_crtc_funcs armada_crtc_funcs = {
.cursor_set = armada_drm_crtc_cursor_set,
.cursor_move = armada_drm_crtc_cursor_move,
.destroy = armada_drm_crtc_destroy,
@@ -1216,14 +1211,14 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
&armada_primary_plane_funcs,
armada_primary_formats,
ARRAY_SIZE(armada_primary_formats),
- DRM_PLANE_TYPE_PRIMARY);
+ DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
return ret;
}
ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL,
- &armada_crtc_funcs);
+ &armada_crtc_funcs, NULL);
if (ret)
goto err_crtc_init;
diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c
index 471e45627f1e..d4f7ab0a30d4 100644
--- a/drivers/gpu/drm/armada/armada_debugfs.c
+++ b/drivers/gpu/drm/armada/armada_debugfs.c
@@ -21,9 +21,9 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)
struct armada_private *priv = dev->dev_private;
int ret;
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&priv->linear_lock);
ret = drm_mm_dump_table(m, &priv->linear);
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&priv->linear_lock);
return ret;
}
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index 4df6f2af2b21..3b2bb6128d40 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -57,7 +57,8 @@ struct armada_private {
DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8);
struct drm_fb_helper *fbdev;
struct armada_crtc *dcrtc[2];
- struct drm_mm linear;
+ struct drm_mm linear; /* protected by linear_lock */
+ struct mutex linear_lock;
struct drm_property *csc_yuv_prop;
struct drm_property *csc_rgb_prop;
struct drm_property *colorkey_prop;
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 77ab93d60125..3bd7e1cde99e 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -102,6 +102,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
dev->mode_config.preferred_depth = 24;
dev->mode_config.funcs = &armada_drm_mode_config_funcs;
drm_mm_init(&priv->linear, mem->start, resource_size(mem));
+ mutex_init(&priv->linear_lock);
ret = component_bind_all(dev->dev, dev);
if (ret)
diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c
index 1c90969def3e..5fa4bf20b232 100644
--- a/drivers/gpu/drm/armada/armada_fb.c
+++ b/drivers/gpu/drm/armada/armada_fb.c
@@ -35,7 +35,7 @@ static const struct drm_framebuffer_funcs armada_fb_funcs = {
};
struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
+ const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
{
struct armada_framebuffer *dfb;
uint8_t format, config;
@@ -101,7 +101,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
}
static struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
- struct drm_file *dfile, struct drm_mode_fb_cmd2 *mode)
+ struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
{
struct armada_gem_object *obj;
struct armada_framebuffer *dfb;
diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h
index ce3f12ebfc53..48073c4f54d8 100644
--- a/drivers/gpu/drm/armada/armada_fb.h
+++ b/drivers/gpu/drm/armada/armada_fb.h
@@ -19,6 +19,6 @@ struct armada_framebuffer {
#define drm_fb_obj(fb) drm_fb_to_armada_fb(fb)->obj
struct armada_framebuffer *armada_framebuffer_create(struct drm_device *,
- struct drm_mode_fb_cmd2 *, struct armada_gem_object *);
+ const struct drm_mode_fb_cmd2 *, struct armada_gem_object *);
#endif
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index 60a688ef81c7..6e731db31aa4 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -46,22 +46,26 @@ static size_t roundup_gem_size(size_t size)
return roundup(size, PAGE_SIZE);
}
-/* dev->struct_mutex is held here */
void armada_gem_free_object(struct drm_gem_object *obj)
{
struct armada_gem_object *dobj = drm_to_armada_gem(obj);
+ struct armada_private *priv = obj->dev->dev_private;
DRM_DEBUG_DRIVER("release obj %p\n", dobj);
drm_gem_free_mmap_offset(&dobj->obj);
+ might_lock(&priv->linear_lock);
+
if (dobj->page) {
/* page backed memory */
unsigned int order = get_order(dobj->obj.size);
__free_pages(dobj->page, order);
} else if (dobj->linear) {
/* linear backed memory */
+ mutex_lock(&priv->linear_lock);
drm_mm_remove_node(dobj->linear);
+ mutex_unlock(&priv->linear_lock);
kfree(dobj->linear);
if (dobj->addr)
iounmap(dobj->addr);
@@ -144,10 +148,10 @@ armada_gem_linear_back(struct drm_device *dev, struct armada_gem_object *obj)
if (!node)
return -ENOSPC;
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&priv->linear_lock);
ret = drm_mm_insert_node(&priv->linear, node, size, align,
DRM_MM_SEARCH_DEFAULT);
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&priv->linear_lock);
if (ret) {
kfree(node);
return ret;
@@ -158,9 +162,9 @@ armada_gem_linear_back(struct drm_device *dev, struct armada_gem_object *obj)
/* Ensure that the memory we're returning is cleared. */
ptr = ioremap_wc(obj->linear->start, size);
if (!ptr) {
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&priv->linear_lock);
drm_mm_remove_node(obj->linear);
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&priv->linear_lock);
kfree(obj->linear);
obj->linear = NULL;
return -ENOMEM;
@@ -274,18 +278,16 @@ int armada_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
struct armada_gem_object *obj;
int ret = 0;
- mutex_lock(&dev->struct_mutex);
obj = armada_gem_object_lookup(dev, file, handle);
if (!obj) {
DRM_ERROR("failed to lookup gem object\n");
- ret = -EINVAL;
- goto err_unlock;
+ return -EINVAL;
}
/* Don't allow imported objects to be mapped */
if (obj->obj.import_attach) {
ret = -EINVAL;
- goto err_unlock;
+ goto err_unref;
}
ret = drm_gem_create_mmap_offset(&obj->obj);
@@ -294,9 +296,8 @@ int armada_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
DRM_DEBUG_DRIVER("handle %#x offset %llx\n", handle, *offset);
}
- drm_gem_object_unreference(&obj->obj);
- err_unlock:
- mutex_unlock(&dev->struct_mutex);
+ err_unref:
+ drm_gem_object_unreference_unlocked(&obj->obj);
return ret;
}
@@ -352,13 +353,13 @@ int armada_gem_mmap_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
if (!dobj->obj.filp) {
- drm_gem_object_unreference(&dobj->obj);
+ drm_gem_object_unreference_unlocked(&dobj->obj);
return -EINVAL;
}
addr = vm_mmap(dobj->obj.filp, 0, args->size, PROT_READ | PROT_WRITE,
MAP_SHARED, args->offset);
- drm_gem_object_unreference(&dobj->obj);
+ drm_gem_object_unreference_unlocked(&dobj->obj);
if (IS_ERR_VALUE(addr))
return addr;
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index 5c22b380f8f3..148e8a42b2c6 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -460,7 +460,7 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
&armada_ovl_plane_funcs,
armada_ovl_formats,
ARRAY_SIZE(armada_ovl_formats),
- DRM_PLANE_TYPE_OVERLAY);
+ DRM_PLANE_TYPE_OVERLAY, NULL);
if (ret) {
kfree(dplane);
return ret;
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 05f6522c0457..eb5715994ac2 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -256,7 +256,6 @@ struct ast_framebuffer {
struct ast_fbdev {
struct drm_fb_helper helper;
struct ast_framebuffer afb;
- struct list_head fbdev_list;
void *sysram;
int size;
struct ttm_bo_kmap_obj mapping;
@@ -309,7 +308,7 @@ extern void ast_mode_fini(struct drm_device *dev);
int ast_framebuffer_init(struct drm_device *dev,
struct ast_framebuffer *ast_fb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
int ast_fbdev_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index a37e7ea4a00c..5320f8c57884 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -163,7 +163,7 @@ static struct fb_ops astfb_ops = {
};
static int astfb_create_object(struct ast_fbdev *afbdev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **gobj_p)
{
struct drm_device *dev = afbdev->helper.dev;
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 541a610667ad..9759009d1da3 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -309,7 +309,7 @@ static const struct drm_framebuffer_funcs ast_fb_funcs = {
int ast_framebuffer_init(struct drm_device *dev,
struct ast_framebuffer *ast_fb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -327,7 +327,7 @@ int ast_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
ast_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct ast_framebuffer *ast_fb;
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 69d19f3304a5..0123458cbd83 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -751,7 +751,7 @@ static int ast_encoder_init(struct drm_device *dev)
return -ENOMEM;
drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(&ast_encoder->base, &ast_enc_helper_funcs);
ast_encoder->base.possible_crtcs = 1;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 9f6e234e7029..468a14f266a7 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -344,7 +344,7 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
ret = drm_crtc_init_with_planes(dev, &crtc->base,
&planes->primary->base,
planes->cursor ? &planes->cursor->base : NULL,
- &atmel_hlcdc_crtc_funcs);
+ &atmel_hlcdc_crtc_funcs, NULL);
if (ret < 0)
goto fail;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 244df0a440b7..a45b32ba029e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -333,6 +333,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
.data = &atmel_hlcdc_dc_at91sam9x5,
},
{
+ .compatible = "atmel,sama5d2-hlcdc",
+ .data = &atmel_hlcdc_dc_sama5d4,
+ },
+ {
.compatible = "atmel,sama5d3-hlcdc",
.data = &atmel_hlcdc_dc_sama5d3,
},
@@ -342,6 +346,7 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
},
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
struct drm_display_mode *mode)
@@ -402,7 +407,7 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
}
static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
- struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
{
return drm_fb_cma_create(dev, file_priv, mode_cmd);
}
@@ -733,10 +738,6 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
if (!ddev)
return -ENOMEM;
- ret = drm_dev_set_unique(ddev, dev_name(ddev->dev));
- if (ret)
- goto err_unref;
-
ret = atmel_hlcdc_dc_load(ddev);
if (ret)
goto err_unref;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 067e4c144bd6..0f7ec016e7a9 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -146,7 +146,7 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
cfg);
}
-static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
.mode_set = atmel_hlcdc_rgb_encoder_mode_set,
.disable = atmel_hlcdc_panel_encoder_disable,
@@ -192,7 +192,7 @@ atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector)
return &rgb->encoder;
}
-static struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = {
.get_modes = atmel_hlcdc_panel_get_modes,
.mode_valid = atmel_hlcdc_rgb_mode_valid,
.best_encoder = atmel_hlcdc_rgb_best_encoder,
@@ -256,7 +256,7 @@ static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
&atmel_hlcdc_panel_encoder_helper_funcs);
ret = drm_encoder_init(dev, &panel->base.encoder,
&atmel_hlcdc_panel_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index d0299aed517e..1ffe9c329c46 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -941,7 +941,7 @@ atmel_hlcdc_plane_create(struct drm_device *dev,
ret = drm_universal_plane_init(dev, &plane->base, 0,
&layer_plane_funcs,
desc->formats->formats,
- desc->formats->nformats, type);
+ desc->formats->nformats, type, NULL);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
index 71f2687fc3cc..19b5adaebe24 100644
--- a/drivers/gpu/drm/bochs/bochs.h
+++ b/drivers/gpu/drm/bochs/bochs.h
@@ -149,7 +149,7 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
int bochs_framebuffer_init(struct drm_device *dev,
struct bochs_framebuffer *gfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr);
int bochs_bo_unpin(struct bochs_bo *bo);
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c
index 09a0637aab3e..7520bf81fc25 100644
--- a/drivers/gpu/drm/bochs/bochs_fbdev.c
+++ b/drivers/gpu/drm/bochs/bochs_fbdev.c
@@ -34,7 +34,7 @@ static struct fb_ops bochsfb_ops = {
};
static int bochsfb_create_object(struct bochs_device *bochs,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **gobj_p)
{
struct drm_device *dev = bochs->dev;
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 26bcd03a8cb6..2849f1b95eec 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -119,7 +119,7 @@ static int bochs_crtc_page_flip(struct drm_crtc *crtc,
bochs_crtc_mode_set_base(crtc, 0, 0, old_fb);
if (event) {
spin_lock_irqsave(&bochs->dev->event_lock, irqflags);
- drm_send_vblank_event(bochs->dev, -1, event);
+ drm_crtc_send_vblank_event(crtc, event);
spin_unlock_irqrestore(&bochs->dev->event_lock, irqflags);
}
return 0;
@@ -196,7 +196,7 @@ static void bochs_encoder_init(struct drm_device *dev)
encoder->possible_crtcs = 0x1;
drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs);
}
@@ -245,13 +245,13 @@ static enum drm_connector_status bochs_connector_detect(struct drm_connector
return connector_status_connected;
}
-struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
.get_modes = bochs_connector_get_modes,
.mode_valid = bochs_connector_mode_valid,
.best_encoder = bochs_connector_best_encoder,
};
-struct drm_connector_funcs bochs_connector_connector_funcs = {
+static const struct drm_connector_funcs bochs_connector_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = bochs_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -283,7 +283,7 @@ int bochs_kms_init(struct bochs_device *bochs)
bochs->dev->mode_config.preferred_depth = 24;
bochs->dev->mode_config.prefer_shadow = 0;
- bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs;
+ bochs->dev->mode_config.funcs = &bochs_mode_funcs;
bochs_crtc_init(bochs->dev);
bochs_encoder_init(bochs->dev);
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index f69e6bf9bb0e..d812ad014da5 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -484,7 +484,7 @@ static const struct drm_framebuffer_funcs bochs_fb_funcs = {
int bochs_framebuffer_init(struct drm_device *dev,
struct bochs_framebuffer *gfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -502,7 +502,7 @@ int bochs_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
bochs_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct bochs_framebuffer *bochs_fb;
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 6dddd392aa42..27e2022de89d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -22,7 +22,6 @@ config DRM_DW_HDMI_AHB_AUDIO
Designware HDMI block. This is used in conjunction with
the i.MX6 HDMI driver.
-
config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index d4e28beec30e..f13c33d67c03 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,6 +1,6 @@
ccflags-y := -Iinclude/drm
-obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
-obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
+obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
diff --git a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c
index 59f630f1c61a..122bb015f4a9 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c
@@ -21,7 +21,7 @@
#include <sound/pcm_drm_eld.h>
#include <sound/pcm_iec958.h>
-#include "dw_hdmi-audio.h"
+#include "dw-hdmi-audio.h"
#define DRIVER_NAME "dw-hdmi-ahb-audio"
diff --git a/drivers/gpu/drm/bridge/dw_hdmi-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
index 91f631beecc7..91f631beecc7 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi-audio.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 56de9f1c95fc..b0aac4733020 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -22,13 +22,14 @@
#include <drm/drm_of.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
#include <drm/bridge/dw_hdmi.h>
-#include "dw_hdmi.h"
-#include "dw_hdmi-audio.h"
+#include "dw-hdmi.h"
+#include "dw-hdmi-audio.h"
#define HDMI_EDID_LEN 512
@@ -1514,7 +1515,7 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
mutex_unlock(&hdmi->mutex);
}
-static struct drm_connector_funcs dw_hdmi_connector_funcs = {
+static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = dw_hdmi_connector_detect,
@@ -1522,13 +1523,24 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.force = dw_hdmi_connector_force,
};
-static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+static const struct drm_connector_funcs dw_hdmi_atomic_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
+ .force = dw_hdmi_connector_force,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
.mode_valid = dw_hdmi_connector_mode_valid,
.best_encoder = dw_hdmi_connector_best_encoder,
};
-static struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
.enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable,
.pre_enable = dw_hdmi_bridge_nop,
@@ -1645,10 +1657,15 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
- hdmi->connector.encoder = encoder;
+ if (drm_core_check_feature(drm, DRIVER_ATOMIC))
+ drm_connector_init(drm, &hdmi->connector,
+ &dw_hdmi_atomic_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ else
+ drm_connector_init(drm, &hdmi->connector,
+ &dw_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index fc9a560429d6..fc9a560429d6 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index 0ffa3a6a206a..7ecd59f70b8e 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -242,7 +242,7 @@ static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
return ptn_bridge->bridge.encoder;
}
-static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
.get_modes = ptn3460_get_modes,
.best_encoder = ptn3460_best_encoder,
};
@@ -258,7 +258,7 @@ static void ptn3460_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs ptn3460_connector_funcs = {
+static const struct drm_connector_funcs ptn3460_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ptn3460_detect,
@@ -299,7 +299,7 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge)
return ret;
}
-static struct drm_bridge_funcs ptn3460_bridge_funcs = {
+static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
.pre_enable = ptn3460_pre_enable,
.enable = ptn3460_enable,
.disable = ptn3460_disable,
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 705061537a27..b774d637a00f 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -153,7 +153,6 @@ struct cirrus_device {
struct cirrus_fbdev {
struct drm_fb_helper helper;
struct cirrus_framebuffer gfb;
- struct list_head fbdev_list;
void *sysram;
int size;
int x1, y1, x2, y2; /* dirty rect */
@@ -207,7 +206,7 @@ int cirrus_dumb_create(struct drm_file *file,
int cirrus_framebuffer_init(struct drm_device *dev,
struct cirrus_framebuffer *gfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 589103bcc06c..3b5be7272357 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -135,7 +135,7 @@ static struct fb_ops cirrusfb_ops = {
};
static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **gobj_p)
{
struct drm_device *dev = afbdev->helper.dev;
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
index 055fd86ba717..0907715e90fd 100644
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -29,7 +29,7 @@ static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
int cirrus_framebuffer_init(struct drm_device *dev,
struct cirrus_framebuffer *gfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -47,7 +47,7 @@ int cirrus_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
cirrus_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct cirrus_device *cdev = dev->dev_private;
struct drm_gem_object *obj;
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 61385f2298bf..4a02854a6963 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -489,7 +489,7 @@ static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev)
encoder->possible_crtcs = 0x1;
drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs);
return encoder;
@@ -533,12 +533,12 @@ static void cirrus_connector_destroy(struct drm_connector *connector)
kfree(connector);
}
-struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
.get_modes = cirrus_vga_get_modes,
.best_encoder = cirrus_connector_best_encoder,
};
-struct drm_connector_funcs cirrus_vga_connector_funcs = {
+static const struct drm_connector_funcs cirrus_vga_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = cirrus_vga_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index aeee083c7f95..3f74193885f1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -288,8 +288,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
state->crtcs[index] = crtc;
crtc_state->state = state;
- DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n",
- crtc->base.id, crtc_state, state);
+ DRM_DEBUG_ATOMIC("Added [CRTC:%d:%s] %p state to %p\n",
+ crtc->base.id, crtc->name, crtc_state, state);
return crtc_state;
}
@@ -316,8 +316,7 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
return 0;
- if (state->mode_blob)
- drm_property_unreference_blob(state->mode_blob);
+ drm_property_unreference_blob(state->mode_blob);
state->mode_blob = NULL;
if (mode) {
@@ -363,8 +362,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
if (blob == state->mode_blob)
return 0;
- if (state->mode_blob)
- drm_property_unreference_blob(state->mode_blob);
+ drm_property_unreference_blob(state->mode_blob);
state->mode_blob = NULL;
if (blob) {
@@ -419,8 +417,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
struct drm_property_blob *mode =
drm_property_lookup_blob(dev, val);
ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
- if (mode)
- drm_property_unreference_blob(mode);
+ drm_property_unreference_blob(mode);
return ret;
}
else if (crtc->funcs->atomic_set_property)
@@ -432,11 +429,20 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
}
EXPORT_SYMBOL(drm_atomic_crtc_set_property);
-/*
+/**
+ * drm_atomic_crtc_get_property - get property value from CRTC state
+ * @crtc: the drm CRTC to set a property on
+ * @state: the state object to get the property value from
+ * @property: the property to set
+ * @val: return location for the property value
+ *
* This function handles generic/core properties and calls out to
* driver's ->atomic_get_property() for driver properties. To ensure
* consistent behavior you must call this function rather than the
* driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
*/
static int
drm_atomic_crtc_get_property(struct drm_crtc *crtc,
@@ -480,8 +486,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
*/
if (state->active && !state->enable) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active without enabled\n",
+ crtc->base.id, crtc->name);
return -EINVAL;
}
@@ -490,14 +496,30 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
* be able to trigger. */
if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
WARN_ON(state->enable && !state->mode_blob)) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] enabled without mode blob\n",
- crtc->base.id);
+ 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)) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] disabled with mode blob\n",
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] disabled with mode blob\n",
+ crtc->base.id, crtc->name);
+ return -EINVAL;
+ }
+
+ /*
+ * Reject event generation for when a CRTC is off and stays off.
+ * It wouldn't be hard to implement this, but userspace has a track
+ * record of happily burning through 100% cpu (or worse, crash) when the
+ * display pipe is suspended. To avoid all that fun just reject updates
+ * that ask for events since likely that indicates a bug in the
+ * compositor's drawing loop. This is consistent with the vblank IOCTL
+ * and legacy page_flip IOCTL which also reject service on a disabled
+ * pipe.
+ */
+ if (state->event && !state->active && !crtc->state->active) {
+ DRM_DEBUG_ATOMIC("[CRTC:%d] requesting event but off\n",
crtc->base.id);
return -EINVAL;
}
@@ -543,8 +565,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
state->planes[index] = plane;
plane_state->state = state;
- DRM_DEBUG_ATOMIC("Added [PLANE:%d] %p state to %p\n",
- plane->base.id, plane_state, state);
+ DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n",
+ plane->base.id, plane->name, plane_state, state);
if (plane_state->crtc) {
struct drm_crtc_state *crtc_state;
@@ -619,11 +641,20 @@ int drm_atomic_plane_set_property(struct drm_plane *plane,
}
EXPORT_SYMBOL(drm_atomic_plane_set_property);
-/*
+/**
+ * drm_atomic_plane_get_property - get property value from plane state
+ * @plane: the drm plane to set a property on
+ * @state: the state object to get the property value from
+ * @property: the property to set
+ * @val: return location for the property value
+ *
* This function handles generic/core properties and calls out to
* driver's ->atomic_get_property() for driver properties. To ensure
* consistent behavior you must call this function rather than the
* driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
*/
static int
drm_atomic_plane_get_property(struct drm_plane *plane,
@@ -755,8 +786,8 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
}
if (plane_switching_crtc(state->state, plane, state)) {
- DRM_DEBUG_ATOMIC("[PLANE:%d] switching CRTC directly\n",
- plane->base.id);
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
+ plane->base.id, plane->name);
return -EINVAL;
}
@@ -875,11 +906,20 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_atomic_connector_set_property);
-/*
+/**
+ * drm_atomic_connector_get_property - get property value from connector state
+ * @connector: the drm connector to set a property on
+ * @state: the state object to get the property value from
+ * @property: the property to set
+ * @val: return location for the property value
+ *
* This function handles generic/core properties and calls out to
* driver's ->atomic_get_property() for driver properties. To ensure
* consistent behavior you must call this function rather than the
* driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
*/
static int
drm_atomic_connector_get_property(struct drm_connector *connector,
@@ -980,8 +1020,8 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
}
if (crtc)
- DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d]\n",
- plane_state, crtc->base.id);
+ DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d:%s]\n",
+ plane_state, crtc->base.id, crtc->name);
else
DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n",
plane_state);
@@ -1039,17 +1079,28 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
{
struct drm_crtc_state *crtc_state;
+ if (conn_state->crtc && conn_state->crtc != crtc) {
+ crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state,
+ conn_state->crtc);
+
+ crtc_state->connector_mask &=
+ ~(1 << drm_connector_index(conn_state->connector));
+ }
+
if (crtc) {
crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
+
+ crtc_state->connector_mask |=
+ 1 << drm_connector_index(conn_state->connector);
}
conn_state->crtc = crtc;
if (crtc)
- DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d]\n",
- conn_state, crtc->base.id);
+ DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d:%s]\n",
+ conn_state, crtc->base.id, crtc->name);
else
DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n",
conn_state);
@@ -1088,8 +1139,8 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
if (ret)
return ret;
- DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d] to %p\n",
- crtc->base.id, state);
+ DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d:%s] to %p\n",
+ crtc->base.id, crtc->name, state);
/*
* Changed connectors are already in @state, so only need to look at the
@@ -1148,35 +1199,6 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_add_affected_planes);
/**
- * drm_atomic_connectors_for_crtc - count number of connected outputs
- * @state: atomic state
- * @crtc: DRM crtc
- *
- * This function counts all connectors which will be connected to @crtc
- * according to @state. Useful to recompute the enable state for @crtc.
- */
-int
-drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
- struct drm_crtc *crtc)
-{
- struct drm_connector *connector;
- struct drm_connector_state *conn_state;
-
- int i, num_connected_connectors = 0;
-
- for_each_connector_in_state(state, connector, conn_state, i) {
- if (conn_state->crtc == crtc)
- num_connected_connectors++;
- }
-
- DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n",
- state, num_connected_connectors, crtc->base.id);
-
- return num_connected_connectors;
-}
-EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
-
-/**
* drm_atomic_legacy_backoff - locking backoff for legacy ioctls
* @state: atomic state
*
@@ -1191,12 +1213,7 @@ void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
retry:
drm_modeset_backoff(state->acquire_ctx);
- ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
- state->acquire_ctx);
- if (ret)
- goto retry;
- ret = drm_modeset_lock_all_crtcs(state->dev,
- state->acquire_ctx);
+ ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx);
if (ret)
goto retry;
}
@@ -1228,8 +1245,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
for_each_plane_in_state(state, plane, plane_state, i) {
ret = drm_atomic_plane_check(plane, plane_state);
if (ret) {
- DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n",
- plane->base.id);
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n",
+ plane->base.id, plane->name);
return ret;
}
}
@@ -1237,8 +1254,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
for_each_crtc_in_state(state, crtc, crtc_state, i) {
ret = drm_atomic_crtc_check(crtc, crtc_state);
if (ret) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic core check failed\n",
+ crtc->base.id, crtc->name);
return ret;
}
}
@@ -1249,8 +1266,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
if (!state->allow_modeset) {
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requires full modeset\n",
+ crtc->base.id, crtc->name);
return -EINVAL;
}
}
@@ -1433,7 +1450,7 @@ static int atomic_set_prop(struct drm_atomic_state *state,
}
/**
- * drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers.
+ * drm_atomic_clean_old_fb -- Unset old_fb pointers and set plane->fb pointers.
*
* @dev: drm device to check.
* @plane_mask: plane mask for planes that were updated.
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index e5aec45bf985..57cccd68ca52 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -52,6 +52,12 @@
* drm_atomic_helper_disable_plane(), drm_atomic_helper_disable_plane() and the
* various functions to implement set_property callbacks. New drivers must not
* implement these functions themselves but must use the provided helpers.
+ *
+ * The atomic helper uses the same function table structures as all other
+ * modesetting helpers. See the documentation for struct &drm_crtc_helper_funcs,
+ * struct &drm_encoder_helper_funcs and struct &drm_connector_helper_funcs. It
+ * also shares the struct &drm_plane_helper_funcs function table with the plane
+ * helpers.
*/
static void
drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
@@ -80,6 +86,26 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
}
}
+static bool
+check_pending_encoder_assignment(struct drm_atomic_state *state,
+ struct drm_encoder *new_encoder)
+{
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ int i;
+
+ for_each_connector_in_state(state, connector, conn_state, i) {
+ if (conn_state->best_encoder != new_encoder)
+ continue;
+
+ /* encoder already assigned and we're trying to re-steal it! */
+ if (connector->state->best_encoder != conn_state->best_encoder)
+ return false;
+ }
+
+ return true;
+}
+
static struct drm_crtc *
get_current_crtc_for_encoder(struct drm_device *dev,
struct drm_encoder *encoder)
@@ -116,9 +142,9 @@ steal_encoder(struct drm_atomic_state *state,
*/
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
- DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n",
+ DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], stealing it\n",
encoder->base.id, encoder->name,
- encoder_crtc->base.id);
+ encoder_crtc->base.id, encoder_crtc->name);
crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc);
if (IS_ERR(crtc_state))
@@ -219,16 +245,24 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
}
if (new_encoder == connector_state->best_encoder) {
- DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n",
+ DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",
connector->base.id,
connector->name,
new_encoder->base.id,
new_encoder->name,
- connector_state->crtc->base.id);
+ connector_state->crtc->base.id,
+ connector_state->crtc->name);
return 0;
}
+ if (!check_pending_encoder_assignment(state, new_encoder)) {
+ DRM_DEBUG_ATOMIC("Encoder for [CONNECTOR:%d:%s] already assigned\n",
+ connector->base.id,
+ connector->name);
+ return -EINVAL;
+ }
+
encoder_crtc = get_current_crtc_for_encoder(state->dev,
new_encoder);
@@ -251,12 +285,13 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
crtc_state = state->crtc_states[idx];
crtc_state->connectors_changed = true;
- DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
+ DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
connector->base.id,
connector->name,
new_encoder->base.id,
new_encoder->name,
- connector_state->crtc->base.id);
+ connector_state->crtc->base.id,
+ connector_state->crtc->name);
return 0;
}
@@ -340,8 +375,8 @@ mode_fixup(struct drm_atomic_state *state)
ret = funcs->mode_fixup(crtc, &crtc_state->mode,
&crtc_state->adjusted_mode);
if (!ret) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] fixup failed\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] fixup failed\n",
+ crtc->base.id, crtc->name);
return -EINVAL;
}
}
@@ -388,14 +423,14 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] mode changed\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode changed\n",
+ crtc->base.id, crtc->name);
crtc_state->mode_changed = true;
}
if (crtc->state->enable != crtc_state->enable) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enable changed\n",
+ crtc->base.id, crtc->name);
/*
* For clarity this assignment is done here, but
@@ -428,7 +463,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
* crtc only changed its mode but has the same set of connectors.
*/
for_each_crtc_in_state(state, crtc, crtc_state, i) {
- int num_connectors;
+ bool has_connectors =
+ !!crtc_state->connector_mask;
/*
* We must set ->active_changed after walking connectors for
@@ -436,18 +472,18 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
* a full modeset because update_connector_routing force that.
*/
if (crtc->state->active != crtc_state->active) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] active changed\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n",
+ crtc->base.id, crtc->name);
crtc_state->active_changed = true;
}
if (!drm_atomic_crtc_needs_modeset(crtc_state))
continue;
- DRM_DEBUG_ATOMIC("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
- crtc->base.id,
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] needs all connectors, enable: %c, active: %c\n",
+ crtc->base.id, crtc->name,
crtc_state->enable ? 'y' : 'n',
- crtc_state->active ? 'y' : 'n');
+ crtc_state->active ? 'y' : 'n');
ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret != 0)
@@ -457,12 +493,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
if (ret != 0)
return ret;
- num_connectors = drm_atomic_connectors_for_crtc(state,
- crtc);
-
- if (crtc_state->enable != !!num_connectors) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] enabled/connectors mismatch\n",
- crtc->base.id);
+ if (crtc_state->enable != has_connectors) {
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n",
+ crtc->base.id, crtc->name);
return -EINVAL;
}
@@ -509,8 +542,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
ret = funcs->atomic_check(plane, plane_state);
if (ret) {
- DRM_DEBUG_ATOMIC("[PLANE:%d] atomic driver check failed\n",
- plane->base.id);
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic driver check failed\n",
+ plane->base.id, plane->name);
return ret;
}
}
@@ -525,8 +558,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
ret = funcs->atomic_check(crtc, state->crtc_states[i]);
if (ret) {
- DRM_DEBUG_ATOMIC("[CRTC:%d] atomic driver check failed\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic driver check failed\n",
+ crtc->base.id, crtc->name);
return ret;
}
}
@@ -639,8 +672,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs = crtc->helper_private;
- DRM_DEBUG_ATOMIC("disabling [CRTC:%d]\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("disabling [CRTC:%d:%s]\n",
+ crtc->base.id, crtc->name);
/* Right function depends upon target state. */
@@ -751,8 +784,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs = crtc->helper_private;
if (crtc->state->enable && funcs->mode_set_nofb) {
- DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("modeset on [CRTC:%d:%s]\n",
+ crtc->base.id, crtc->name);
funcs->mode_set_nofb(crtc);
}
@@ -851,8 +884,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
funcs = crtc->helper_private;
if (crtc->state->enable) {
- DRM_DEBUG_ATOMIC("enabling [CRTC:%d]\n",
- crtc->base.id);
+ DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",
+ crtc->base.id, crtc->name);
if (funcs->enable)
funcs->enable(crtc);
@@ -1342,6 +1375,49 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
/**
+ * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
+ * @crtc: CRTC
+ * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
+ *
+ * Disables all planes associated with the given CRTC. This can be
+ * used for instance in the CRTC helper disable callback to disable
+ * all planes before shutting down the display pipeline.
+ *
+ * If the atomic-parameter is set the function calls the CRTC's
+ * atomic_begin hook before and atomic_flush hook after disabling the
+ * planes.
+ *
+ * It is a bug to call this function without having implemented the
+ * ->atomic_disable() plane hook.
+ */
+void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
+ bool atomic)
+{
+ const struct drm_crtc_helper_funcs *crtc_funcs =
+ crtc->helper_private;
+ struct drm_plane *plane;
+
+ if (atomic && crtc_funcs && crtc_funcs->atomic_begin)
+ crtc_funcs->atomic_begin(crtc, NULL);
+
+ drm_for_each_plane(plane, crtc->dev) {
+ const struct drm_plane_helper_funcs *plane_funcs =
+ plane->helper_private;
+
+ if (plane->state->crtc != crtc || !plane_funcs)
+ continue;
+
+ WARN_ON(!plane_funcs->atomic_disable);
+ if (plane_funcs->atomic_disable)
+ plane_funcs->atomic_disable(plane, NULL);
+ }
+
+ if (atomic && crtc_funcs && crtc_funcs->atomic_flush)
+ crtc_funcs->atomic_flush(crtc, NULL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
+
+/**
* drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
* @dev: DRM device
* @old_state: atomic state object with old state structures
@@ -1485,12 +1561,12 @@ retry:
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->crtc_h = crtc_h;
plane_state->src_x = src_x;
plane_state->src_y = src_y;
- plane_state->src_h = src_h;
plane_state->src_w = src_w;
+ plane_state->src_h = src_h;
if (plane == crtc->cursor)
state->legacy_cursor_update = true;
@@ -1609,12 +1685,12 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
drm_atomic_set_fb_for_plane(plane_state, NULL);
plane_state->crtc_x = 0;
plane_state->crtc_y = 0;
- plane_state->crtc_h = 0;
plane_state->crtc_w = 0;
+ plane_state->crtc_h = 0;
plane_state->src_x = 0;
plane_state->src_y = 0;
- plane_state->src_h = 0;
plane_state->src_w = 0;
+ plane_state->src_h = 0;
return 0;
}
@@ -1676,7 +1752,7 @@ static int update_output_state(struct drm_atomic_state *state,
if (crtc == set->crtc)
continue;
- if (!drm_atomic_connectors_for_crtc(state, crtc)) {
+ if (!crtc_state->connector_mask) {
ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
NULL);
if (ret < 0)
@@ -1797,16 +1873,16 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
drm_atomic_set_fb_for_plane(primary_state, set->fb);
primary_state->crtc_x = 0;
primary_state->crtc_y = 0;
- primary_state->crtc_h = vdisplay;
primary_state->crtc_w = hdisplay;
+ primary_state->crtc_h = vdisplay;
primary_state->src_x = set->x << 16;
primary_state->src_y = set->y << 16;
if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
- primary_state->src_h = hdisplay << 16;
primary_state->src_w = vdisplay << 16;
+ primary_state->src_h = hdisplay << 16;
} else {
- primary_state->src_h = vdisplay << 16;
primary_state->src_w = hdisplay << 16;
+ primary_state->src_h = vdisplay << 16;
}
commit:
@@ -1818,6 +1894,161 @@ commit:
}
/**
+ * drm_atomic_helper_disable_all - disable all currently active outputs
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * Loops through all connectors, finding those that aren't turned off and then
+ * turns them off by setting their DPMS mode to OFF and deactivating the CRTC
+ * that they are connected to.
+ *
+ * This is used for example in suspend/resume to disable all currently active
+ * functions when suspending.
+ *
+ * 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:
+ * 0 on success or a negative error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
+ */
+int drm_atomic_helper_disable_all(struct drm_device *dev,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_atomic_state *state;
+ struct drm_connector *conn;
+ int err;
+
+ state = drm_atomic_state_alloc(dev);
+ if (!state)
+ return -ENOMEM;
+
+ state->acquire_ctx = ctx;
+
+ drm_for_each_connector(conn, dev) {
+ struct drm_crtc *crtc = conn->state->crtc;
+ struct drm_crtc_state *crtc_state;
+
+ if (!crtc || conn->dpms != DRM_MODE_DPMS_ON)
+ continue;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ err = PTR_ERR(crtc_state);
+ goto free;
+ }
+
+ crtc_state->active = false;
+ }
+
+ err = drm_atomic_commit(state);
+
+free:
+ if (err < 0)
+ drm_atomic_state_free(state);
+
+ return err;
+}
+EXPORT_SYMBOL(drm_atomic_helper_disable_all);
+
+/**
+ * drm_atomic_helper_suspend - subsystem-level suspend helper
+ * @dev: DRM device
+ *
+ * Duplicates the current atomic state, disables all active outputs and then
+ * returns a pointer to the original atomic state to the caller. Drivers can
+ * pass this pointer to the drm_atomic_helper_resume() helper upon resume to
+ * restore the output configuration that was active at the time the system
+ * entered suspend.
+ *
+ * Note that it is potentially unsafe to use this. The atomic state object
+ * returned by this function is assumed to be persistent. Drivers must ensure
+ * that this holds true. Before calling this function, drivers must make sure
+ * to suspend fbdev emulation so that nothing can be using the device.
+ *
+ * Returns:
+ * A pointer to a copy of the state before suspend on success or an ERR_PTR()-
+ * encoded error code on failure. Drivers should store the returned atomic
+ * state object and pass it to the drm_atomic_helper_resume() helper upon
+ * resume.
+ *
+ * See also:
+ * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
+ * drm_atomic_helper_resume()
+ */
+struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ int err;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+ err = drm_modeset_lock_all_ctx(dev, &ctx);
+ if (err < 0) {
+ state = ERR_PTR(err);
+ goto unlock;
+ }
+
+ state = drm_atomic_helper_duplicate_state(dev, &ctx);
+ if (IS_ERR(state))
+ goto unlock;
+
+ err = drm_atomic_helper_disable_all(dev, &ctx);
+ if (err < 0) {
+ drm_atomic_state_free(state);
+ state = ERR_PTR(err);
+ goto unlock;
+ }
+
+unlock:
+ if (PTR_ERR(state) == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_suspend);
+
+/**
+ * drm_atomic_helper_resume - subsystem-level resume helper
+ * @dev: DRM device
+ * @state: atomic state to resume to
+ *
+ * Calls drm_mode_config_reset() to synchronize hardware and software states,
+ * grabs all modeset locks and commits the atomic state object. This can be
+ * used in conjunction with the drm_atomic_helper_suspend() helper to
+ * implement suspend/resume for drivers that support atomic mode-setting.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend()
+ */
+int drm_atomic_helper_resume(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ struct drm_mode_config *config = &dev->mode_config;
+ int err;
+
+ drm_mode_config_reset(dev);
+ drm_modeset_lock_all(dev);
+ state->acquire_ctx = config->acquire_ctx;
+ err = drm_atomic_commit(state);
+ drm_modeset_unlock_all(dev);
+
+ return err;
+}
+EXPORT_SYMBOL(drm_atomic_helper_resume);
+
+/**
* drm_atomic_helper_crtc_set_property - helper for crtc properties
* @crtc: DRM crtc
* @property: DRM property
@@ -2051,6 +2282,15 @@ retry:
goto fail;
drm_atomic_set_fb_for_plane(plane_state, fb);
+ /* Make sure we don't accidentally do a full modeset. */
+ state->allow_modeset = false;
+ if (!crtc_state->active) {
+ DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
+ crtc->base.id);
+ ret = -EINVAL;
+ goto fail;
+ }
+
ret = drm_atomic_async_commit(state);
if (ret != 0)
goto fail;
@@ -2173,6 +2413,12 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
* 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.
*/
/**
@@ -2184,7 +2430,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
*/
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
{
- if (crtc->state && crtc->state->mode_blob)
+ if (crtc->state)
drm_property_unreference_blob(crtc->state->mode_blob);
kfree(crtc->state);
crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
@@ -2252,8 +2498,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
- if (state->mode_blob)
- drm_property_unreference_blob(state->mode_blob);
+ drm_property_unreference_blob(state->mode_blob);
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
@@ -2368,6 +2613,28 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
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
+ * #connector ->state, usually required when initializing the drivers
+ * or when called from the ->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 ->reset hook for connectors
* @connector: drm connector
*
@@ -2377,11 +2644,11 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
*/
void drm_atomic_helper_connector_reset(struct drm_connector *connector)
{
- kfree(connector->state);
- connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+ struct drm_connector_state *conn_state =
+ kzalloc(sizeof(*conn_state), GFP_KERNEL);
- if (connector->state)
- connector->state->connector = connector;
+ kfree(connector->state);
+ __drm_atomic_helper_connector_reset(connector, conn_state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
@@ -2430,7 +2697,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
* @ctx: lock acquisition context
*
* Makes a copy of the current atomic state by looping over all objects and
- * duplicating their respective states.
+ * 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
@@ -2442,6 +2711,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
* 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,
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 6b8f7211e543..bd93453afa61 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -31,14 +31,14 @@
/**
* DOC: overview
*
- * drm_bridge represents a device that hangs on to an encoder. These are handy
- * when a regular drm_encoder entity isn't enough to represent the entire
+ * struct &drm_bridge represents a device that hangs on to an encoder. These are
+ * handy when a regular &drm_encoder entity isn't enough to represent the entire
* encoder chain.
*
- * A bridge is always associated to a single drm_encoder at a time, but can be
+ * A bridge is always attached to a single &drm_encoder at a time, but can be
* either connected to it directly, or through an intermediate bridge:
*
- * encoder ---> bridge B ---> bridge A
+ * encoder ---> bridge B ---> bridge A
*
* Here, the output of the encoder feeds to bridge B, and that furthers feeds to
* bridge A.
@@ -46,11 +46,16 @@
* The driver using the bridge is responsible to make the associations between
* the encoder and bridges. Once these links are made, the bridges will
* participate along with encoder functions to perform mode_set/enable/disable
- * through the ops provided in drm_bridge_funcs.
+ * through the ops provided in &drm_bridge_funcs.
*
* drm_bridge, like drm_panel, aren't drm_mode_object entities like planes,
- * crtcs, encoders or connectors. They just provide additional hooks to get the
- * desired output at the end of the encoder chain.
+ * CRTCs, encoders or connectors and hence are not visible to userspace. They
+ * just provide additional hooks to get the desired output at the end of the
+ * encoder chain.
+ *
+ * Bridges can also be chained up using the next pointer in struct &drm_bridge.
+ *
+ * Both legacy CRTC helpers and the new atomic modeset helpers support bridges.
*/
static DEFINE_MUTEX(bridge_lock);
@@ -122,34 +127,12 @@ EXPORT_SYMBOL(drm_bridge_attach);
/**
* DOC: bridge callbacks
*
- * The drm_bridge_funcs ops are populated by the bridge driver. The drm
- * internals(atomic and crtc helpers) use the helpers defined in drm_bridge.c
- * These helpers call a specific drm_bridge_funcs op for all the bridges
+ * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
+ * internals (atomic and CRTC helpers) use the helpers defined in drm_bridge.c
+ * These helpers call a specific &drm_bridge_funcs op for all the bridges
* during encoder configuration.
*
- * When creating a bridge driver, one can implement drm_bridge_funcs op with
- * the help of these rough rules:
- *
- * pre_enable: this contains things needed to be done for the bridge before
- * its clock and timings are enabled by its source. For a bridge, its source
- * is generally the encoder or bridge just before it in the encoder chain.
- *
- * enable: this contains things needed to be done for the bridge once its
- * source is enabled. In other words, enable is called once the source is
- * ready with clock and timing needed by the bridge.
- *
- * disable: this contains things needed to be done for the bridge assuming
- * that its source is still enabled, i.e. clock and timings are still on.
- *
- * post_disable: this contains things needed to be done for the bridge once
- * its source is disabled, i.e. once clocks and timings are off.
- *
- * mode_fixup: this should fixup the given mode for the bridge. It is called
- * after the encoder's mode fixup. mode_fixup can also reject a mode completely
- * if it's unsuitable for the hardware.
- *
- * mode_set: this sets up the mode for the bridge. It assumes that its source
- * (an encoder or a bridge) has set the mode too.
+ * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
*/
/**
@@ -159,7 +142,7 @@ EXPORT_SYMBOL(drm_bridge_attach);
* @mode: desired mode to be set for the bridge
* @adjusted_mode: updated mode that works for this bridge
*
- * Calls 'mode_fixup' drm_bridge_funcs op for all the bridges in the
+ * Calls ->mode_fixup() &drm_bridge_funcs op for all the bridges in the
* encoder chain, starting from the first bridge to the last.
*
* Note: the bridge passed should be the one closest to the encoder
@@ -186,11 +169,11 @@ bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
EXPORT_SYMBOL(drm_bridge_mode_fixup);
/**
- * drm_bridge_disable - calls 'disable' drm_bridge_funcs op for all
+ * drm_bridge_disable - calls ->disable() &drm_bridge_funcs op for all
* bridges in the encoder chain.
* @bridge: bridge control structure
*
- * Calls 'disable' drm_bridge_funcs op for all the bridges in the encoder
+ * Calls ->disable() &drm_bridge_funcs op for all the bridges in the encoder
* chain, starting from the last bridge to the first. These are called before
* calling the encoder's prepare op.
*
@@ -208,11 +191,11 @@ void drm_bridge_disable(struct drm_bridge *bridge)
EXPORT_SYMBOL(drm_bridge_disable);
/**
- * drm_bridge_post_disable - calls 'post_disable' drm_bridge_funcs op for
+ * drm_bridge_post_disable - calls ->post_disable() &drm_bridge_funcs op for
* all bridges in the encoder chain.
* @bridge: bridge control structure
*
- * Calls 'post_disable' drm_bridge_funcs op for all the bridges in the
+ * Calls ->post_disable() &drm_bridge_funcs op for all the bridges in the
* encoder chain, starting from the first bridge to the last. These are called
* after completing the encoder's prepare op.
*
@@ -236,7 +219,7 @@ EXPORT_SYMBOL(drm_bridge_post_disable);
* @mode: desired mode to be set for the bridge
* @adjusted_mode: updated mode that works for this bridge
*
- * Calls 'mode_set' drm_bridge_funcs op for all the bridges in the
+ * Calls ->mode_set() &drm_bridge_funcs op for all the bridges in the
* encoder chain, starting from the first bridge to the last.
*
* Note: the bridge passed should be the one closest to the encoder
@@ -256,11 +239,11 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
EXPORT_SYMBOL(drm_bridge_mode_set);
/**
- * drm_bridge_pre_enable - calls 'pre_enable' drm_bridge_funcs op for all
+ * drm_bridge_pre_enable - calls ->pre_enable() &drm_bridge_funcs op for all
* bridges in the encoder chain.
* @bridge: bridge control structure
*
- * Calls 'pre_enable' drm_bridge_funcs op for all the bridges in the encoder
+ * Calls ->pre_enable() &drm_bridge_funcs op for all the bridges in the encoder
* chain, starting from the last bridge to the first. These are called
* before calling the encoder's commit op.
*
@@ -278,11 +261,11 @@ void drm_bridge_pre_enable(struct drm_bridge *bridge)
EXPORT_SYMBOL(drm_bridge_pre_enable);
/**
- * drm_bridge_enable - calls 'enable' drm_bridge_funcs op for all bridges
+ * drm_bridge_enable - calls ->enable() &drm_bridge_funcs op for all bridges
* in the encoder chain.
* @bridge: bridge control structure
*
- * Calls 'enable' drm_bridge_funcs op for all the bridges in the encoder
+ * Calls ->enable() &drm_bridge_funcs op for all the bridges in the encoder
* chain, starting from the first bridge to the last. These are called
* after completing the encoder's commit op.
*
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 24c5434abd1c..d40bab29747e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -45,7 +45,7 @@
static struct drm_framebuffer *
internal_framebuffer_create(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *r,
+ const struct drm_mode_fb_cmd2 *r,
struct drm_file *file_priv);
/* Avoid boilerplate. I'm tired of typing. */
@@ -649,6 +649,18 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
DEFINE_WW_CLASS(crtc_ww_class);
+static unsigned int drm_num_crtcs(struct drm_device *dev)
+{
+ unsigned int num = 0;
+ struct drm_crtc *tmp;
+
+ drm_for_each_crtc(tmp, dev) {
+ num++;
+ }
+
+ return num;
+}
+
/**
* drm_crtc_init_with_planes - Initialise a new CRTC object with
* specified primary and cursor planes.
@@ -657,6 +669,7 @@ DEFINE_WW_CLASS(crtc_ww_class);
* @primary: Primary plane for CRTC
* @cursor: Cursor plane for CRTC
* @funcs: callbacks for the new CRTC
+ * @name: printf style format string for the CRTC name, or NULL for default name
*
* Inits a new object created as base part of a driver crtc object.
*
@@ -666,7 +679,8 @@ DEFINE_WW_CLASS(crtc_ww_class);
int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *primary,
struct drm_plane *cursor,
- const struct drm_crtc_funcs *funcs)
+ const struct drm_crtc_funcs *funcs,
+ const char *name, ...)
{
struct drm_mode_config *config = &dev->mode_config;
int ret;
@@ -682,6 +696,21 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
if (ret)
return ret;
+ if (name) {
+ va_list ap;
+
+ va_start(ap, name);
+ crtc->name = kvasprintf(GFP_KERNEL, name, ap);
+ va_end(ap);
+ } else {
+ crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
+ drm_num_crtcs(dev));
+ }
+ if (!crtc->name) {
+ drm_mode_object_put(dev, &crtc->base);
+ return -ENOMEM;
+ }
+
crtc->base.properties = &crtc->properties;
list_add_tail(&crtc->head, &config->crtc_list);
@@ -728,6 +757,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
if (crtc->state && crtc->funcs->atomic_destroy_state)
crtc->funcs->atomic_destroy_state(crtc, crtc->state);
+ kfree(crtc->name);
+
memset(crtc, 0, sizeof(*crtc));
}
EXPORT_SYMBOL(drm_crtc_cleanup);
@@ -1075,6 +1106,7 @@ EXPORT_SYMBOL(drm_connector_unplug_all);
* @encoder: the encoder to init
* @funcs: callbacks for this encoder
* @encoder_type: user visible type of the encoder
+ * @name: printf style format string for the encoder name, or NULL for default name
*
* Initialises a preallocated encoder. Encoder should be
* subclassed as part of driver encoder objects.
@@ -1085,7 +1117,7 @@ EXPORT_SYMBOL(drm_connector_unplug_all);
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
- int encoder_type)
+ int encoder_type, const char *name, ...)
{
int ret;
@@ -1098,9 +1130,17 @@ int drm_encoder_init(struct drm_device *dev,
encoder->dev = dev;
encoder->encoder_type = encoder_type;
encoder->funcs = funcs;
- encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
- drm_encoder_enum_list[encoder_type].name,
- encoder->base.id);
+ if (name) {
+ va_list ap;
+
+ va_start(ap, name);
+ encoder->name = kvasprintf(GFP_KERNEL, name, ap);
+ va_end(ap);
+ } else {
+ encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
+ drm_encoder_enum_list[encoder_type].name,
+ encoder->base.id);
+ }
if (!encoder->name) {
ret = -ENOMEM;
goto out_put;
@@ -1141,6 +1181,18 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
}
EXPORT_SYMBOL(drm_encoder_cleanup);
+static unsigned int drm_num_planes(struct drm_device *dev)
+{
+ unsigned int num = 0;
+ struct drm_plane *tmp;
+
+ drm_for_each_plane(tmp, dev) {
+ num++;
+ }
+
+ return num;
+}
+
/**
* drm_universal_plane_init - Initialize a new universal plane object
* @dev: DRM device
@@ -1150,6 +1202,7 @@ EXPORT_SYMBOL(drm_encoder_cleanup);
* @formats: array of supported formats (%DRM_FORMAT_*)
* @format_count: number of elements in @formats
* @type: type of plane (overlay, primary, cursor)
+ * @name: printf style format string for the plane name, or NULL for default name
*
* Initializes a plane object of type @type.
*
@@ -1160,7 +1213,8 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
- enum drm_plane_type type)
+ enum drm_plane_type type,
+ const char *name, ...)
{
struct drm_mode_config *config = &dev->mode_config;
int ret;
@@ -1182,6 +1236,22 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
return -ENOMEM;
}
+ if (name) {
+ va_list ap;
+
+ va_start(ap, name);
+ plane->name = kvasprintf(GFP_KERNEL, name, ap);
+ va_end(ap);
+ } else {
+ plane->name = kasprintf(GFP_KERNEL, "plane-%d",
+ drm_num_planes(dev));
+ }
+ if (!plane->name) {
+ kfree(plane->format_types);
+ drm_mode_object_put(dev, &plane->base);
+ return -ENOMEM;
+ }
+
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
plane->format_count = format_count;
plane->possible_crtcs = possible_crtcs;
@@ -1240,7 +1310,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
- formats, format_count, type);
+ formats, format_count, type, NULL);
}
EXPORT_SYMBOL(drm_plane_init);
@@ -1272,6 +1342,8 @@ void drm_plane_cleanup(struct drm_plane *plane)
if (plane->state && plane->funcs->atomic_destroy_state)
plane->funcs->atomic_destroy_state(plane, plane->state);
+ kfree(plane->name);
+
memset(plane, 0, sizeof(*plane));
}
EXPORT_SYMBOL(drm_plane_cleanup);
@@ -1801,7 +1873,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
copied = 0;
crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
drm_for_each_crtc(crtc, dev) {
- DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+ DRM_DEBUG_KMS("[CRTC:%d:%s]\n",
+ crtc->base.id, crtc->name);
if (put_user(crtc->base.id, crtc_id + copied)) {
ret = -EFAULT;
goto out;
@@ -2646,7 +2719,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
ret = -ENOENT;
goto out;
}
- DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+ DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
if (crtc_req->mode_valid) {
/* If we have a mode we need a framebuffer. */
@@ -3235,7 +3308,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
static struct drm_framebuffer *
internal_framebuffer_create(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *r,
+ const struct drm_mode_fb_cmd2 *r,
struct drm_file *file_priv)
{
struct drm_mode_config *config = &dev->mode_config;
@@ -4785,9 +4858,7 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
/* Do DPMS ourselves */
if (property == connector->dev->mode_config.dpms_property) {
- ret = 0;
- if (connector->funcs->dpms)
- ret = (*connector->funcs->dpms)(connector, (int)value);
+ ret = (*connector->funcs->dpms)(connector, (int)value);
} else if (connector->funcs->set_property)
ret = connector->funcs->set_property(connector, property, value);
@@ -4983,6 +5054,20 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector,
{
int i;
+ /*
+ * In the past, drivers have attempted to model the static association
+ * of connector to encoder in simple connector/encoder devices using a
+ * direct assignment of connector->encoder = encoder. This connection
+ * is a logical one and the responsibility of the core, so drivers are
+ * expected not to mess with this.
+ *
+ * Note that the error return should've been enough here, but a large
+ * majority of drivers ignores the return value, so add in a big WARN
+ * to get people's attention.
+ */
+ if (WARN_ON(connector->encoder))
+ return -EINVAL;
+
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0) {
connector->encoder_ids[i] = encoder->base.id;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ef534758a02c..a02a7f9a6a9d 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -51,6 +51,11 @@
* the same callbacks which drivers can use to e.g. restore the modeset
* configuration on resume with drm_helper_resume_force_mode().
*
+ * Note that this helper library doesn't track the current power state of CRTCs
+ * and encoders. It can call callbacks like ->dpms() even though the hardware is
+ * already in the desired state. This deficiency has been fixed in the atomic
+ * helpers.
+ *
* The driver callbacks are mostly compatible with the atomic modeset helpers,
* except for the handling of the primary plane: Atomic helpers require that the
* primary plane is implemented as a real standalone plane and not directly tied
@@ -62,6 +67,11 @@
* converting to the plane helpers). New drivers must not use these functions
* but need to implement the atomic interface instead, potentially using the
* atomic helpers for that.
+ *
+ * These legacy modeset helpers use the same function table structures as
+ * all other modesetting helpers. See the documentation for struct
+ * &drm_crtc_helper_funcs, struct &drm_encoder_helper_funcs and struct
+ * &drm_connector_helper_funcs.
*/
MODULE_AUTHOR("David Airlie, Jesse Barnes");
MODULE_DESCRIPTION("DRM KMS helper");
@@ -206,8 +216,8 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
* @dev: DRM device
*
* This function walks through the entire mode setting configuration of @dev. It
- * will remove any crtc links of unused encoders and encoder links of
- * disconnected connectors. Then it will disable all unused encoders and crtcs
+ * will remove any CRTC links of unused encoders and encoder links of
+ * disconnected connectors. Then it will disable all unused encoders and CRTCs
* either by calling their disable callback if available or by calling their
* dpms callback with DRM_MODE_DPMS_OFF.
*/
@@ -329,7 +339,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
DRM_DEBUG_KMS("CRTC fixup failed\n");
goto done;
}
- DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+ DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
crtc->hwmode = *adjusted_mode;
@@ -445,11 +455,36 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
* drm_crtc_helper_set_config - set a new config from userspace
* @set: mode set configuration
*
- * Setup a new configuration, provided by the upper layers (either an ioctl call
- * from userspace or internally e.g. from the fbdev support code) in @set, and
- * enable it. This is the main helper functions for drivers that implement
- * kernel mode setting with the crtc helper functions and the assorted
- * ->prepare(), ->modeset() and ->commit() helper callbacks.
+ * The drm_crtc_helper_set_config() helper function implements the set_config
+ * callback of struct &drm_crtc_funcs for drivers using the legacy CRTC helpers.
+ *
+ * It first tries to locate the best encoder for each connector by calling the
+ * connector ->best_encoder() (struct &drm_connector_helper_funcs) helper
+ * operation.
+ *
+ * After locating the appropriate encoders, the helper function will call the
+ * mode_fixup encoder and CRTC helper operations to adjust the requested mode,
+ * or reject it completely in which case an error will be returned to the
+ * application. If the new configuration after mode adjustment is identical to
+ * the current configuration the helper function will return without performing
+ * any other operation.
+ *
+ * If the adjusted mode is identical to the current mode but changes to the
+ * frame buffer need to be applied, the drm_crtc_helper_set_config() function
+ * will call the CRTC ->mode_set_base() (struct &drm_crtc_helper_funcs) helper
+ * operation.
+ *
+ * If the adjusted mode differs from the current mode, or if the
+ * ->mode_set_base() helper operation is not provided, the helper function
+ * performs a full mode set sequence by calling the ->prepare(), ->mode_set()
+ * and ->commit() CRTC and encoder helper operations, in that order.
+ * Alternatively it can also use the dpms and disable helper operations. For
+ * details see struct &drm_crtc_helper_funcs and struct
+ * &drm_encoder_helper_funcs.
+ *
+ * This function is deprecated. New drivers must implement atomic modeset
+ * support, for which this function is unsuitable. Instead drivers should use
+ * drm_atomic_helper_set_config().
*
* Returns:
* Returns 0 on success, negative errno numbers on failure.
@@ -484,11 +519,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
set->fb = NULL;
if (set->fb) {
- DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
- set->crtc->base.id, set->fb->base.id,
- (int)set->num_connectors, set->x, set->y);
+ DRM_DEBUG_KMS("[CRTC:%d:%s] [FB:%d] #connectors=%d (x y) (%i %i)\n",
+ set->crtc->base.id, set->crtc->name,
+ set->fb->base.id,
+ (int)set->num_connectors, set->x, set->y);
} else {
- DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
+ DRM_DEBUG_KMS("[CRTC:%d:%s] [NOFB]\n",
+ set->crtc->base.id, set->crtc->name);
drm_crtc_helper_disable(set->crtc);
return 0;
}
@@ -628,12 +665,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
connector->encoder->crtc = new_crtc;
}
if (new_crtc) {
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
- connector->base.id, connector->name,
- new_crtc->base.id);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d:%s]\n",
+ connector->base.id, connector->name,
+ new_crtc->base.id, new_crtc->name);
} else {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
- connector->base.id, connector->name);
+ connector->base.id, connector->name);
}
}
@@ -650,8 +687,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
set->x, set->y,
save_set.fb)) {
- DRM_ERROR("failed to set mode on [CRTC:%d]\n",
- set->crtc->base.id);
+ DRM_ERROR("failed to set mode on [CRTC:%d:%s]\n",
+ set->crtc->base.id, set->crtc->name);
set->crtc->primary->fb = save_set.fb;
ret = -EINVAL;
goto fail;
@@ -758,10 +795,18 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
* @connector: affected connector
* @mode: DPMS mode
*
- * This is the main helper function provided by the crtc helper framework for
+ * The drm_helper_connector_dpms() helper function implements the ->dpms()
+ * callback of struct &drm_connector_funcs for drivers using the legacy CRTC helpers.
+ *
+ * This is the main helper function provided by the CRTC helper framework for
* implementing the DPMS connector attribute. It computes the new desired DPMS
- * state for all encoders and crtcs in the output mesh and calls the ->dpms()
- * callback provided by the driver appropriately.
+ * state for all encoders and CRTCs in the output mesh and calls the ->dpms()
+ * callbacks provided by the driver in struct &drm_crtc_helper_funcs and struct
+ * &drm_encoder_helper_funcs appropriately.
+ *
+ * This function is deprecated. New drivers must implement atomic modeset
+ * support, for which this function is unsuitable. Instead drivers should use
+ * drm_atomic_helper_connector_dpms().
*
* Returns:
* Always returns 0.
@@ -818,7 +863,7 @@ EXPORT_SYMBOL(drm_helper_connector_dpms);
* metadata fields.
*/
void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
int i;
@@ -855,6 +900,12 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
* due to slight differences in allocating shared resources when the
* configuration is restored in a different order than when userspace set it up)
* need to use their own restore logic.
+ *
+ * This function is deprecated. New drivers should implement atomic mode-
+ * setting and use the atomic suspend/resume helpers.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
*/
void drm_helper_resume_force_mode(struct drm_device *dev)
{
@@ -913,9 +964,9 @@ EXPORT_SYMBOL(drm_helper_resume_force_mode);
* @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
+ * 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.
+ * to set up the CRTC.
*
* This is a transitional helper useful for converting drivers to the atomic
* interfaces.
@@ -979,7 +1030,7 @@ EXPORT_SYMBOL(drm_helper_crtc_mode_set);
* @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
+ * 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
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 809959d56d78..6ed90a2437e5 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -666,7 +666,9 @@ static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int por
}
static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_num,
- u8 vcpi, uint16_t pbn)
+ u8 vcpi, uint16_t pbn,
+ u8 number_sdp_streams,
+ u8 *sdp_stream_sink)
{
struct drm_dp_sideband_msg_req_body req;
memset(&req, 0, sizeof(req));
@@ -674,6 +676,9 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n
req.u.allocate_payload.port_number = port_num;
req.u.allocate_payload.vcpi = vcpi;
req.u.allocate_payload.pbn = pbn;
+ req.u.allocate_payload.number_sdp_streams = number_sdp_streams;
+ memcpy(req.u.allocate_payload.sdp_stream_sink, sdp_stream_sink,
+ number_sdp_streams);
drm_dp_encode_sideband_req(&req, msg);
msg->path_msg = true;
return 0;
@@ -973,17 +978,17 @@ static struct drm_dp_mst_port *drm_dp_get_port(struct drm_dp_mst_branch *mstb, u
static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port,
u8 *rad)
{
- int lct = port->parent->lct;
+ int parent_lct = port->parent->lct;
int shift = 4;
- int idx = lct / 2;
- if (lct > 1) {
- memcpy(rad, port->parent->rad, idx);
- shift = (lct % 2) ? 4 : 0;
+ int idx = (parent_lct - 1) / 2;
+ if (parent_lct > 1) {
+ memcpy(rad, port->parent->rad, idx + 1);
+ shift = (parent_lct % 2) ? 4 : 0;
} else
rad[0] = 0;
rad[idx] |= port->port_num << shift;
- return lct + 1;
+ return parent_lct + 1;
}
/*
@@ -1039,7 +1044,7 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb,
snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id);
for (i = 0; i < (mstb->lct - 1); i++) {
int shift = (i % 2) ? 0 : 4;
- int port_num = mstb->rad[i / 2] >> shift;
+ int port_num = (mstb->rad[i / 2] >> shift) & 0xf;
snprintf(temp, sizeof(temp), "-%d", port_num);
strlcat(proppath, temp, proppath_size);
}
@@ -1190,7 +1195,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_
for (i = 0; i < lct - 1; i++) {
int shift = (i % 2) ? 0 : 4;
- int port_num = rad[i / 2] >> shift;
+ int port_num = (rad[i / 2] >> shift) & 0xf;
list_for_each_entry(port, &mstb->ports, next) {
if (port->port_num == port_num) {
@@ -1210,6 +1215,50 @@ out:
return mstb;
}
+static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
+ struct drm_dp_mst_branch *mstb,
+ uint8_t *guid)
+{
+ struct drm_dp_mst_branch *found_mstb;
+ struct drm_dp_mst_port *port;
+
+ list_for_each_entry(port, &mstb->ports, next) {
+ if (!port->mstb)
+ continue;
+
+ if (port->guid_valid && memcmp(port->guid, guid, 16) == 0)
+ return port->mstb;
+
+ found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
+
+ if (found_mstb)
+ return found_mstb;
+ }
+
+ return NULL;
+}
+
+static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid(
+ struct drm_dp_mst_topology_mgr *mgr,
+ uint8_t *guid)
+{
+ struct drm_dp_mst_branch *mstb;
+
+ /* find the port by iterating down */
+ mutex_lock(&mgr->lock);
+
+ if (mgr->guid_valid && memcmp(mgr->guid, guid, 16) == 0)
+ mstb = mgr->mst_primary;
+ else
+ mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
+
+ if (mstb)
+ kref_get(&mstb->kref);
+
+ mutex_unlock(&mgr->lock);
+ return mstb;
+}
+
static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_branch *mstb)
{
@@ -1320,6 +1369,7 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr,
struct drm_dp_sideband_msg_tx *txmsg)
{
struct drm_dp_mst_branch *mstb = txmsg->dst;
+ u8 req_type;
/* both msg slots are full */
if (txmsg->seqno == -1) {
@@ -1336,7 +1386,13 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr,
txmsg->seqno = 1;
mstb->tx_slots[txmsg->seqno] = txmsg;
}
- hdr->broadcast = 0;
+
+ req_type = txmsg->msg[0] & 0x7f;
+ if (req_type == DP_CONNECTION_STATUS_NOTIFY ||
+ req_type == DP_RESOURCE_STATUS_NOTIFY)
+ hdr->broadcast = 1;
+ else
+ hdr->broadcast = 0;
hdr->path_msg = txmsg->path_msg;
hdr->lct = mstb->lct;
hdr->lcr = mstb->lct - 1;
@@ -1438,26 +1494,18 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
}
/* called holding qlock */
-static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
+static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_sideband_msg_tx *txmsg)
{
- struct drm_dp_sideband_msg_tx *txmsg;
int ret;
/* construct a chunk from the first msg in the tx_msg queue */
- if (list_empty(&mgr->tx_msg_upq)) {
- mgr->tx_up_in_progress = false;
- return;
- }
-
- txmsg = list_first_entry(&mgr->tx_msg_upq, struct drm_dp_sideband_msg_tx, next);
ret = process_single_tx_qlock(mgr, txmsg, true);
- if (ret == 1) {
- /* up txmsgs aren't put in slots - so free after we send it */
- list_del(&txmsg->next);
- kfree(txmsg);
- } else if (ret)
+
+ if (ret != 1)
DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
- mgr->tx_up_in_progress = true;
+
+ txmsg->dst->tx_slots[txmsg->seqno] = NULL;
}
static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
@@ -1562,6 +1610,8 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_sideband_msg_tx *txmsg;
struct drm_dp_mst_branch *mstb;
int len, ret;
+ u8 sinks[DRM_DP_MAX_SDP_STREAMS];
+ int i;
mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
if (!mstb)
@@ -1573,10 +1623,13 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
goto fail_put;
}
+ for (i = 0; i < port->num_sdp_streams; i++)
+ sinks[i] = i;
+
txmsg->dst = mstb;
len = build_allocate_payload(txmsg, port->port_num,
id,
- pbn);
+ pbn, port->num_sdp_streams, sinks);
drm_dp_queue_down_tx(mgr, txmsg);
@@ -1673,6 +1726,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
if (mgr->proposed_vcpis[i]) {
port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi);
req_payload.num_slots = mgr->proposed_vcpis[i]->num_slots;
+ req_payload.vcpi = mgr->proposed_vcpis[i]->vcpi;
} else {
port = NULL;
req_payload.num_slots = 0;
@@ -1688,6 +1742,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
if (req_payload.num_slots) {
drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload);
mgr->payloads[i].num_slots = req_payload.num_slots;
+ mgr->payloads[i].vcpi = req_payload.vcpi;
} else if (mgr->payloads[i].num_slots) {
mgr->payloads[i].num_slots = 0;
drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
@@ -1823,7 +1878,7 @@ static int drm_dp_encode_up_ack_reply(struct drm_dp_sideband_msg_tx *msg, u8 req
{
struct drm_dp_sideband_msg_reply_body reply;
- reply.reply_type = 1;
+ reply.reply_type = 0;
reply.req_type = req_type;
drm_dp_encode_sideband_reply(&reply, msg);
return 0;
@@ -1844,11 +1899,12 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
drm_dp_encode_up_ack_reply(txmsg, req_type);
mutex_lock(&mgr->qlock);
- list_add_tail(&txmsg->next, &mgr->tx_msg_upq);
- if (!mgr->tx_up_in_progress) {
- process_single_up_tx_qlock(mgr);
- }
+
+ process_single_up_tx_qlock(mgr, txmsg);
+
mutex_unlock(&mgr->qlock);
+
+ kfree(txmsg);
return 0;
}
@@ -2145,28 +2201,50 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
if (mgr->up_req_recv.have_eomt) {
struct drm_dp_sideband_msg_req_body msg;
- struct drm_dp_mst_branch *mstb;
+ struct drm_dp_mst_branch *mstb = NULL;
bool seqno;
- mstb = drm_dp_get_mst_branch_device(mgr,
- mgr->up_req_recv.initial_hdr.lct,
- mgr->up_req_recv.initial_hdr.rad);
- if (!mstb) {
- DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
- memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
- return 0;
+
+ if (!mgr->up_req_recv.initial_hdr.broadcast) {
+ mstb = drm_dp_get_mst_branch_device(mgr,
+ mgr->up_req_recv.initial_hdr.lct,
+ mgr->up_req_recv.initial_hdr.rad);
+ if (!mstb) {
+ DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
+ memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+ return 0;
+ }
}
seqno = mgr->up_req_recv.initial_hdr.seqno;
drm_dp_sideband_parse_req(&mgr->up_req_recv, &msg);
if (msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
- drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
+ drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
+
+ if (!mstb)
+ mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.conn_stat.guid);
+
+ if (!mstb) {
+ DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
+ memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+ return 0;
+ }
+
drm_dp_update_port(mstb, &msg.u.conn_stat);
DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
(*mgr->cbs->hotplug)(mgr);
} else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
- drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
+ drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
+ if (!mstb)
+ mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.resource_stat.guid);
+
+ if (!mstb) {
+ DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
+ memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+ return 0;
+ }
+
DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
}
@@ -2259,6 +2337,27 @@ out:
EXPORT_SYMBOL(drm_dp_mst_detect_port);
/**
+ * drm_dp_mst_port_has_audio() - Check whether port has audio capability or not
+ * @mgr: manager for this port
+ * @port: unverified pointer to a port.
+ *
+ * This returns whether the port supports audio or not.
+ */
+bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_port *port)
+{
+ bool ret = false;
+
+ port = drm_dp_get_validated_port_ref(mgr, port);
+ if (!port)
+ return ret;
+ ret = port->has_audio;
+ drm_dp_put_port(port);
+ return ret;
+}
+EXPORT_SYMBOL(drm_dp_mst_port_has_audio);
+
+/**
* drm_dp_mst_get_edid() - get EDID for an MST port
* @connector: toplevel connector to get EDID for
* @mgr: manager for this port
@@ -2283,6 +2382,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
edid = drm_get_edid(connector, &port->aux.ddc);
drm_mode_connector_set_tile_property(connector);
}
+ port->has_audio = drm_detect_monitor_audio(edid);
drm_dp_put_port(port);
return edid;
}
@@ -2566,7 +2666,7 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m,
seq_printf(m, "%smst: %p, %d\n", prefix, mstb, mstb->num_ports);
list_for_each_entry(port, &mstb->ports, next) {
- seq_printf(m, "%sport: %d: ddps: %d ldps: %d, %p, conn: %p\n", prefix, port->port_num, port->ddps, port->ldps, port, port->connector);
+ seq_printf(m, "%sport: %d: ddps: %d ldps: %d, sdp: %d/%d, %p, conn: %p\n", prefix, port->port_num, port->ddps, port->ldps, port->num_sdp_streams, port->num_sdp_stream_sinks, port, port->connector);
if (port->mstb)
drm_dp_mst_dump_mstb(m, port->mstb);
}
@@ -2736,7 +2836,6 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
mutex_init(&mgr->qlock);
mutex_init(&mgr->payload_lock);
mutex_init(&mgr->destroy_connector_lock);
- INIT_LIST_HEAD(&mgr->tx_msg_upq);
INIT_LIST_HEAD(&mgr->tx_msg_downq);
INIT_LIST_HEAD(&mgr->destroy_connector_list);
INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work);
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 7dd6728dd092..167c8d3d4a31 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -44,10 +44,6 @@ MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
-MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
-MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
-MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
-
module_param_named(debug, drm_debug, int, 0600);
static DEFINE_SPINLOCK(drm_minor_lock);
@@ -633,8 +629,17 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
}
}
+ if (parent) {
+ ret = drm_dev_set_unique(dev, dev_name(parent));
+ if (ret)
+ goto err_setunique;
+ }
+
return dev;
+err_setunique:
+ if (drm_core_check_feature(dev, DRIVER_GEM))
+ drm_gem_destroy(dev);
err_ctxbitmap:
drm_legacy_ctxbitmap_cleanup(dev);
drm_ht_remove(&dev->map_hash);
@@ -797,23 +802,18 @@ EXPORT_SYMBOL(drm_dev_unregister);
/**
* drm_dev_set_unique - Set the unique name of a DRM device
* @dev: device of which to set the unique name
- * @fmt: format string for unique name
+ * @name: unique name
*
- * Sets the unique name of a DRM device using the specified format string and
- * a variable list of arguments. Drivers can use this at driver probe time if
- * the unique name of the devices they drive is static.
+ * Sets the unique name of a DRM device using the specified string. Drivers
+ * can use this at driver probe time if the unique name of the devices they
+ * drive is static.
*
* Return: 0 on success or a negative error code on failure.
*/
-int drm_dev_set_unique(struct drm_device *dev, const char *fmt, ...)
+int drm_dev_set_unique(struct drm_device *dev, const char *name)
{
- va_list ap;
-
kfree(dev->unique);
-
- va_start(ap, fmt);
- dev->unique = kvasprintf(GFP_KERNEL, fmt, ap);
- va_end(ap);
+ dev->unique = kstrdup(name, GFP_KERNEL);
return dev->unique ? 0 : -ENOMEM;
}
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d5d2c03fd136..04cb4877fabd 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -637,8 +637,12 @@ static const struct minimode extra_modes[] = {
/*
* Probably taken from CEA-861 spec.
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
+ *
+ * Index using the VIC.
*/
static const struct drm_display_mode edid_cea_modes[] = {
+ /* 0 - dummy, VICs start at 1 */
+ { },
/* 1 - 640x480@60Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
@@ -987,9 +991,11 @@ static const struct drm_display_mode edid_cea_modes[] = {
};
/*
- * HDMI 1.4 4k modes.
+ * HDMI 1.4 4k modes. Index using the VIC.
*/
static const struct drm_display_mode edid_4k_modes[] = {
+ /* 0 - dummy, VICs start at 1 */
+ { },
/* 1 - 3840x2160@30Hz */
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
3840, 4016, 4104, 4400, 0,
@@ -2545,6 +2551,33 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
return clock;
}
+static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match,
+ unsigned int clock_tolerance)
+{
+ u8 vic;
+
+ if (!to_match->clock)
+ return 0;
+
+ for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) {
+ const struct drm_display_mode *cea_mode = &edid_cea_modes[vic];
+ unsigned int clock1, clock2;
+
+ /* Check both 60Hz and 59.94Hz */
+ clock1 = cea_mode->clock;
+ clock2 = cea_mode_alternate_clock(cea_mode);
+
+ if (abs(to_match->clock - clock1) > clock_tolerance &&
+ abs(to_match->clock - clock2) > clock_tolerance)
+ continue;
+
+ if (drm_mode_equal_no_clocks(to_match, cea_mode))
+ return vic;
+ }
+
+ return 0;
+}
+
/**
* drm_match_cea_mode - look for a CEA mode matching given mode
* @to_match: display mode
@@ -2554,13 +2587,13 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
*/
u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
{
- u8 mode;
+ u8 vic;
if (!to_match->clock)
return 0;
- for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
- const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
+ for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) {
+ const struct drm_display_mode *cea_mode = &edid_cea_modes[vic];
unsigned int clock1, clock2;
/* Check both 60Hz and 59.94Hz */
@@ -2570,12 +2603,17 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode))
- return mode + 1;
+ return vic;
}
return 0;
}
EXPORT_SYMBOL(drm_match_cea_mode);
+static bool drm_valid_cea_vic(u8 vic)
+{
+ return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes);
+}
+
/**
* drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to
* the input VIC from the CEA mode list
@@ -2585,10 +2623,7 @@ EXPORT_SYMBOL(drm_match_cea_mode);
*/
enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code)
{
- /* return picture aspect ratio for video_code - 1 to access the
- * right array element
- */
- return edid_cea_modes[video_code-1].picture_aspect_ratio;
+ return edid_cea_modes[video_code].picture_aspect_ratio;
}
EXPORT_SYMBOL(drm_get_cea_aspect_ratio);
@@ -2609,6 +2644,33 @@ hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode)
return cea_mode_alternate_clock(hdmi_mode);
}
+static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match,
+ unsigned int clock_tolerance)
+{
+ u8 vic;
+
+ if (!to_match->clock)
+ return 0;
+
+ for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) {
+ const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic];
+ unsigned int clock1, clock2;
+
+ /* Make sure to also match alternate clocks */
+ clock1 = hdmi_mode->clock;
+ clock2 = hdmi_mode_alternate_clock(hdmi_mode);
+
+ if (abs(to_match->clock - clock1) > clock_tolerance &&
+ abs(to_match->clock - clock2) > clock_tolerance)
+ continue;
+
+ if (drm_mode_equal_no_clocks(to_match, hdmi_mode))
+ return vic;
+ }
+
+ return 0;
+}
+
/*
* drm_match_hdmi_mode - look for a HDMI mode matching given mode
* @to_match: display mode
@@ -2619,13 +2681,13 @@ hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode)
*/
static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)
{
- u8 mode;
+ u8 vic;
if (!to_match->clock)
return 0;
- for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
- const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
+ for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) {
+ const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic];
unsigned int clock1, clock2;
/* Make sure to also match alternate clocks */
@@ -2635,11 +2697,16 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode))
- return mode + 1;
+ return vic;
}
return 0;
}
+static bool drm_valid_hdmi_vic(u8 vic)
+{
+ return vic > 0 && vic < ARRAY_SIZE(edid_4k_modes);
+}
+
static int
add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
{
@@ -2659,16 +2726,16 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
list_for_each_entry(mode, &connector->probed_modes, head) {
const struct drm_display_mode *cea_mode = NULL;
struct drm_display_mode *newmode;
- u8 mode_idx = drm_match_cea_mode(mode) - 1;
+ u8 vic = drm_match_cea_mode(mode);
unsigned int clock1, clock2;
- if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
- cea_mode = &edid_cea_modes[mode_idx];
+ if (drm_valid_cea_vic(vic)) {
+ cea_mode = &edid_cea_modes[vic];
clock2 = cea_mode_alternate_clock(cea_mode);
} else {
- mode_idx = drm_match_hdmi_mode(mode) - 1;
- if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
- cea_mode = &edid_4k_modes[mode_idx];
+ vic = drm_match_hdmi_mode(mode);
+ if (drm_valid_hdmi_vic(vic)) {
+ cea_mode = &edid_4k_modes[vic];
clock2 = hdmi_mode_alternate_clock(cea_mode);
}
}
@@ -2719,17 +2786,17 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *newmode;
- u8 cea_mode;
+ u8 vic;
if (video_db == NULL || video_index >= video_len)
return NULL;
/* CEA modes are numbered 1..127 */
- cea_mode = (video_db[video_index] & 127) - 1;
- if (cea_mode >= ARRAY_SIZE(edid_cea_modes))
+ vic = (video_db[video_index] & 127);
+ if (!drm_valid_cea_vic(vic))
return NULL;
- newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+ newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]);
if (!newmode)
return NULL;
@@ -2824,8 +2891,7 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic)
struct drm_device *dev = connector->dev;
struct drm_display_mode *newmode;
- vic--; /* VICs start at 1 */
- if (vic >= ARRAY_SIZE(edid_4k_modes)) {
+ if (!drm_valid_hdmi_vic(vic)) {
DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
return 0;
}
@@ -3116,20 +3182,24 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
{
const struct drm_display_mode *cea_mode;
int clock1, clock2, clock;
- u8 mode_idx;
+ u8 vic;
const char *type;
- mode_idx = drm_match_cea_mode(mode) - 1;
- if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
+ /*
+ * allow 5kHz clock difference either way to account for
+ * the 10kHz clock resolution limit of detailed timings.
+ */
+ vic = drm_match_cea_mode_clock_tolerance(mode, 5);
+ if (drm_valid_cea_vic(vic)) {
type = "CEA";
- cea_mode = &edid_cea_modes[mode_idx];
+ cea_mode = &edid_cea_modes[vic];
clock1 = cea_mode->clock;
clock2 = cea_mode_alternate_clock(cea_mode);
} else {
- mode_idx = drm_match_hdmi_mode(mode) - 1;
- if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
+ vic = drm_match_hdmi_mode_clock_tolerance(mode, 5);
+ if (drm_valid_hdmi_vic(vic)) {
type = "HDMI";
- cea_mode = &edid_4k_modes[mode_idx];
+ cea_mode = &edid_4k_modes[vic];
clock1 = cea_mode->clock;
clock2 = hdmi_mode_alternate_clock(cea_mode);
} else {
@@ -3147,7 +3217,7 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
return;
DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
- type, mode_idx + 1, mode->clock, clock);
+ type, vic, mode->clock, clock);
mode->clock = clock;
}
diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c
index d18b88b755c3..e8629076de32 100644
--- a/drivers/gpu/drm/drm_encoder_slave.c
+++ b/drivers/gpu/drm/drm_encoder_slave.c
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(drm_i2c_encoder_destroy);
* Wrapper fxns which can be plugged in to drm_encoder_helper_funcs:
*/
-static inline struct drm_encoder_slave_funcs *
+static inline const struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index c19a62561183..c895b6fddbd8 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -74,7 +74,7 @@ static struct drm_framebuffer_funcs drm_fb_cma_funcs = {
};
static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
+ const const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
unsigned int num_planes)
{
struct drm_fb_cma *fb_cma;
@@ -107,7 +107,7 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
* checked before calling this function.
*/
struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
- struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_fb_cma *fb_cma;
struct drm_gem_cma_object *objs[4];
@@ -266,7 +266,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
fbi = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(fbi)) {
ret = PTR_ERR(fbi);
- goto err_drm_gem_cma_free_object;
+ goto err_gem_free_object;
}
fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
@@ -299,8 +299,8 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
err_fb_info_destroy:
drm_fb_helper_release_fbi(helper);
-err_drm_gem_cma_free_object:
- drm_gem_cma_free_object(&obj->base);
+err_gem_free_object:
+ dev->driver->gem_free_object(&obj->base);
return ret;
}
@@ -348,9 +348,6 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
}
- /* disable all the possible outputs/crtcs before entering KMS mode */
- drm_helper_disable_unused_functions(dev);
-
ret = drm_fb_helper_initial_config(helper, preferred_bpp);
if (ret < 0) {
dev_err(dev->dev, "Failed to set initial hw configuration.\n");
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 69cbab5e5c81..1e103c4c6ee0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1251,7 +1251,7 @@ retry:
goto fail;
plane = mode_set->crtc->primary;
- plane_mask |= drm_plane_index(plane);
+ plane_mask |= (1 << drm_plane_index(plane));
plane->old_fb = plane->fb;
}
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6b5625e66119..1ea8790e5090 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -226,6 +226,8 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
init_waitqueue_head(&priv->event_wait);
priv->event_space = 4096; /* set aside 4k for event buffer */
+ mutex_init(&priv->event_read_lock);
+
if (drm_core_check_feature(dev, DRIVER_GEM))
drm_gem_open(dev, priv);
@@ -511,14 +513,28 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
{
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
- ssize_t ret = 0;
+ ssize_t ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
- spin_lock_irq(&dev->event_lock);
+ ret = mutex_lock_interruptible(&file_priv->event_read_lock);
+ if (ret)
+ return ret;
+
for (;;) {
- if (list_empty(&file_priv->event_list)) {
+ struct drm_pending_event *e = NULL;
+
+ spin_lock_irq(&dev->event_lock);
+ if (!list_empty(&file_priv->event_list)) {
+ e = list_first_entry(&file_priv->event_list,
+ struct drm_pending_event, link);
+ file_priv->event_space += e->event->length;
+ list_del(&e->link);
+ }
+ spin_unlock_irq(&dev->event_lock);
+
+ if (e == NULL) {
if (ret)
break;
@@ -527,36 +543,36 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
break;
}
- spin_unlock_irq(&dev->event_lock);
+ mutex_unlock(&file_priv->event_read_lock);
ret = wait_event_interruptible(file_priv->event_wait,
!list_empty(&file_priv->event_list));
- spin_lock_irq(&dev->event_lock);
- if (ret < 0)
- break;
-
- ret = 0;
+ if (ret >= 0)
+ ret = mutex_lock_interruptible(&file_priv->event_read_lock);
+ if (ret)
+ return ret;
} else {
- struct drm_pending_event *e;
-
- e = list_first_entry(&file_priv->event_list,
- struct drm_pending_event, link);
- if (e->event->length + ret > count)
+ unsigned length = e->event->length;
+
+ if (length > count - ret) {
+put_back_event:
+ spin_lock_irq(&dev->event_lock);
+ file_priv->event_space -= length;
+ list_add(&e->link, &file_priv->event_list);
+ spin_unlock_irq(&dev->event_lock);
break;
+ }
- if (__copy_to_user_inatomic(buffer + ret,
- e->event, e->event->length)) {
+ if (copy_to_user(buffer + ret, e->event, length)) {
if (ret == 0)
ret = -EFAULT;
- break;
+ goto put_back_event;
}
- file_priv->event_space += e->event->length;
- ret += e->event->length;
- list_del(&e->link);
+ ret += length;
e->destroy(e);
}
}
- spin_unlock_irq(&dev->event_lock);
+ mutex_unlock(&file_priv->event_read_lock);
return ret;
}
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index c7de454e8e88..2e8c77e71e1f 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -220,6 +220,9 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
static void
drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
{
+ struct drm_device *dev = obj->dev;
+ bool final = false;
+
if (WARN_ON(obj->handle_count == 0))
return;
@@ -229,14 +232,39 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
* checked for a name
*/
- mutex_lock(&obj->dev->object_name_lock);
+ mutex_lock(&dev->object_name_lock);
if (--obj->handle_count == 0) {
drm_gem_object_handle_free(obj);
drm_gem_object_exported_dma_buf_free(obj);
+ final = true;
}
- mutex_unlock(&obj->dev->object_name_lock);
+ mutex_unlock(&dev->object_name_lock);
- drm_gem_object_unreference_unlocked(obj);
+ if (final)
+ drm_gem_object_unreference_unlocked(obj);
+}
+
+/*
+ * Called at device or object close to release the file's
+ * handle references on objects.
+ */
+static int
+drm_gem_object_release_handle(int id, void *ptr, void *data)
+{
+ struct drm_file *file_priv = data;
+ struct drm_gem_object *obj = ptr;
+ struct drm_device *dev = obj->dev;
+
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_gem_remove_prime_handles(obj, file_priv);
+ drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+
+ if (dev->driver->gem_close_object)
+ dev->driver->gem_close_object(obj, file_priv);
+
+ drm_gem_object_handle_unreference_unlocked(obj);
+
+ return 0;
}
/**
@@ -244,8 +272,9 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
* @filp: drm file-private structure to use for the handle look up
* @handle: userspace handle to delete
*
- * Removes the GEM handle from the @filp lookup table and if this is the last
- * handle also cleans up linked resources like GEM names.
+ * Removes the GEM handle from the @filp lookup table which has been added with
+ * drm_gem_handle_create(). If this is the last handle also cleans up linked
+ * resources like GEM names.
*/
int
drm_gem_handle_delete(struct drm_file *filp, u32 handle)
@@ -276,14 +305,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock);
- if (drm_core_check_feature(dev, DRIVER_PRIME))
- drm_gem_remove_prime_handles(obj, filp);
- drm_vma_node_revoke(&obj->vma_node, filp->filp);
-
- if (dev->driver->gem_close_object)
- dev->driver->gem_close_object(obj, filp);
- drm_gem_object_handle_unreference_unlocked(obj);
-
+ drm_gem_object_release_handle(handle, obj, filp);
return 0;
}
EXPORT_SYMBOL(drm_gem_handle_delete);
@@ -314,6 +336,10 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy);
* This expects the dev->object_name_lock to be held already and will drop it
* before returning. Used to avoid races in establishing new handles when
* importing an object from either an flink name or a dma-buf.
+ *
+ * Handles must be release again through drm_gem_handle_delete(). This is done
+ * when userspace closes @file_priv for all attached handles, or through the
+ * GEM_CLOSE ioctl for individual handles.
*/
int
drm_gem_handle_create_tail(struct drm_file *file_priv,
@@ -321,9 +347,12 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
u32 *handlep)
{
struct drm_device *dev = obj->dev;
+ u32 handle;
int ret;
WARN_ON(!mutex_is_locked(&dev->object_name_lock));
+ if (obj->handle_count++ == 0)
+ drm_gem_object_reference(obj);
/*
* Get the user-visible handle using idr. Preload and perform
@@ -333,32 +362,38 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
spin_lock(&file_priv->table_lock);
ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
- drm_gem_object_reference(obj);
- obj->handle_count++;
+
spin_unlock(&file_priv->table_lock);
idr_preload_end();
+
mutex_unlock(&dev->object_name_lock);
- if (ret < 0) {
- drm_gem_object_handle_unreference_unlocked(obj);
- return ret;
- }
- *handlep = ret;
+ if (ret < 0)
+ goto err_unref;
+
+ handle = ret;
ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
- if (ret) {
- drm_gem_handle_delete(file_priv, *handlep);
- return ret;
- }
+ if (ret)
+ goto err_remove;
if (dev->driver->gem_open_object) {
ret = dev->driver->gem_open_object(obj, file_priv);
- if (ret) {
- drm_gem_handle_delete(file_priv, *handlep);
- return ret;
- }
+ if (ret)
+ goto err_revoke;
}
+ *handlep = handle;
return 0;
+
+err_revoke:
+ drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+err_remove:
+ spin_lock(&file_priv->table_lock);
+ idr_remove(&file_priv->object_idr, handle);
+ spin_unlock(&file_priv->table_lock);
+err_unref:
+ drm_gem_object_handle_unreference_unlocked(obj);
+ return ret;
}
/**
@@ -541,7 +576,17 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
}
EXPORT_SYMBOL(drm_gem_put_pages);
-/** Returns a reference to the object named by the handle. */
+/**
+ * drm_gem_object_lookup - look up a GEM object from it's handle
+ * @dev: DRM device
+ * @filp: DRM file private date
+ * @handle: userspace handle
+ *
+ * Returns:
+ *
+ * A reference to the object named by the handle if such exists on @filp, NULL
+ * otherwise.
+ */
struct drm_gem_object *
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
u32 handle)
@@ -615,7 +660,6 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
mutex_lock(&dev->object_name_lock);
- idr_preload(GFP_KERNEL);
/* prevent races with concurrent gem_close. */
if (obj->handle_count == 0) {
ret = -ENOENT;
@@ -623,7 +667,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
}
if (!obj->name) {
- ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_NOWAIT);
+ ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_KERNEL);
if (ret < 0)
goto err;
@@ -634,7 +678,6 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
ret = 0;
err:
- idr_preload_end();
mutex_unlock(&dev->object_name_lock);
drm_gem_object_unreference_unlocked(obj);
return ret;
@@ -699,29 +742,6 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
spin_lock_init(&file_private->table_lock);
}
-/*
- * Called at device close to release the file's
- * handle references on objects.
- */
-static int
-drm_gem_object_release_handle(int id, void *ptr, void *data)
-{
- struct drm_file *file_priv = data;
- struct drm_gem_object *obj = ptr;
- struct drm_device *dev = obj->dev;
-
- if (drm_core_check_feature(dev, DRIVER_PRIME))
- drm_gem_remove_prime_handles(obj, file_priv);
- drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
-
- if (dev->driver->gem_close_object)
- dev->driver->gem_close_object(obj, file_priv);
-
- drm_gem_object_handle_unreference_unlocked(obj);
-
- return 0;
-}
-
/**
* drm_gem_release - release file-private GEM resources
* @dev: drm_device which is being closed by userspace
@@ -774,6 +794,13 @@ drm_gem_object_free(struct kref *kref)
}
EXPORT_SYMBOL(drm_gem_object_free);
+/**
+ * drm_gem_vm_open - vma->ops->open implementation for GEM
+ * @vma: VM area structure
+ *
+ * This function implements the #vm_operations_struct open() callback for GEM
+ * drivers. This must be used together with drm_gem_vm_close().
+ */
void drm_gem_vm_open(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
@@ -782,6 +809,13 @@ void drm_gem_vm_open(struct vm_area_struct *vma)
}
EXPORT_SYMBOL(drm_gem_vm_open);
+/**
+ * drm_gem_vm_close - vma->ops->close implementation for GEM
+ * @vma: VM area structure
+ *
+ * This function implements the #vm_operations_struct close() callback for GEM
+ * drivers. This must be used together with drm_gem_vm_open().
+ */
void drm_gem_vm_close(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index e109b49cd25d..e5df53b6e229 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -59,11 +59,13 @@ __drm_gem_cma_create(struct drm_device *drm, size_t size)
struct drm_gem_object *gem_obj;
int ret;
- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
- if (!cma_obj)
+ if (drm->driver->gem_create_object)
+ gem_obj = drm->driver->gem_create_object(drm, size);
+ else
+ gem_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
+ if (!gem_obj)
return ERR_PTR(-ENOMEM);
-
- gem_obj = &cma_obj->base;
+ cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base);
ret = drm_gem_object_init(drm, gem_obj, size);
if (ret)
@@ -119,7 +121,7 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
return cma_obj;
error:
- drm_gem_cma_free_object(&cma_obj->base);
+ drm->driver->gem_free_object(&cma_obj->base);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_create);
@@ -169,7 +171,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv,
return cma_obj;
err_handle_create:
- drm_gem_cma_free_object(gem_obj);
+ drm->driver->gem_free_object(gem_obj);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 607f493ae801..d12a4efa651b 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -73,6 +73,9 @@ static int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
+MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
+MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
+MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
static void store_vblank(struct drm_device *dev, unsigned int pipe,
u32 vblank_count_inc,
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 2d5ca8eec13a..6e6a9c58d404 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -365,6 +365,44 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
}
EXPORT_SYMBOL(mipi_dsi_create_packet);
+/**
+ * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
+{
+ struct mipi_dsi_msg msg = {
+ .channel = dsi->channel,
+ .type = MIPI_DSI_SHUTDOWN_PERIPHERAL,
+ .tx_buf = (u8 [2]) { 0, 0 },
+ .tx_len = 2,
+ };
+
+ return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral);
+
+/**
+ * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
+{
+ struct mipi_dsi_msg msg = {
+ .channel = dsi->channel,
+ .type = MIPI_DSI_TURN_ON_PERIPHERAL,
+ .tx_buf = (u8 [2]) { 0, 0 },
+ .tx_len = 2,
+ };
+
+ return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
+
/*
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
* the payload in a long packet transmitted from the peripheral back to the
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index cd74a0953f42..20775c05235a 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -553,10 +553,10 @@ EXPORT_SYMBOL(drm_gtf_mode_complex);
* drivers/video/fbmon.c
*
* Standard GTF parameters:
- * M = 600
- * C = 40
- * K = 128
- * J = 20
+ * M = 600
+ * C = 40
+ * K = 128
+ * J = 20
*
* Returns:
* The modeline based on the GTF algorithm stored in a drm_display_mode object.
@@ -708,7 +708,8 @@ void drm_mode_set_name(struct drm_display_mode *mode)
}
EXPORT_SYMBOL(drm_mode_set_name);
-/** drm_mode_hsync - get the hsync of a mode
+/**
+ * drm_mode_hsync - get the hsync of a mode
* @mode: mode
*
* Returns:
@@ -917,13 +918,30 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ
} else if (mode1->clock != mode2->clock)
return false;
+ return drm_mode_equal_no_clocks(mode1, mode2);
+}
+EXPORT_SYMBOL(drm_mode_equal);
+
+/**
+ * drm_mode_equal_no_clocks - test modes for equality
+ * @mode1: first mode
+ * @mode2: second mode
+ *
+ * Check to see if @mode1 and @mode2 are equivalent, but
+ * don't check the pixel clocks.
+ *
+ * Returns:
+ * True if the modes are equal, false otherwise.
+ */
+bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
+{
if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) !=
(mode2->flags & DRM_MODE_FLAG_3D_MASK))
return false;
return drm_mode_equal_no_clocks_no_stereo(mode1, mode2);
}
-EXPORT_SYMBOL(drm_mode_equal);
+EXPORT_SYMBOL(drm_mode_equal_no_clocks);
/**
* drm_mode_equal_no_clocks_no_stereo - test modes for equality
@@ -1056,7 +1074,7 @@ static const char * const drm_mode_status_names[] = {
MODE_STATUS(ONE_SIZE),
MODE_STATUS(NO_REDUCED),
MODE_STATUS(NO_STEREO),
- MODE_STATUS(UNVERIFIED),
+ MODE_STATUS(STALE),
MODE_STATUS(BAD),
MODE_STATUS(ERROR),
};
@@ -1154,7 +1172,6 @@ EXPORT_SYMBOL(drm_mode_sort);
/**
* drm_mode_connector_list_update - update the mode list for the connector
* @connector: the connector to update
- * @merge_type_bits: whether to merge or overwrite type bits
*
* This moves the modes from the @connector probed_modes list
* to the actual mode list. It compares the probed mode against the current
@@ -1163,33 +1180,48 @@ EXPORT_SYMBOL(drm_mode_sort);
* This is just a helper functions doesn't validate any modes itself and also
* doesn't prune any invalid modes. Callers need to do that themselves.
*/
-void drm_mode_connector_list_update(struct drm_connector *connector,
- bool merge_type_bits)
+void drm_mode_connector_list_update(struct drm_connector *connector)
{
- struct drm_display_mode *mode;
struct drm_display_mode *pmode, *pt;
- int found_it;
WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
- list_for_each_entry_safe(pmode, pt, &connector->probed_modes,
- head) {
- found_it = 0;
+ list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
+ struct drm_display_mode *mode;
+ bool found_it = false;
+
/* go through current modes checking for the new probed mode */
list_for_each_entry(mode, &connector->modes, head) {
- if (drm_mode_equal(pmode, mode)) {
- found_it = 1;
- /* if equal delete the probed mode */
- mode->status = pmode->status;
- /* Merge type bits together */
- if (merge_type_bits)
- mode->type |= pmode->type;
- else
- mode->type = pmode->type;
- list_del(&pmode->head);
- drm_mode_destroy(connector->dev, pmode);
- break;
+ if (!drm_mode_equal(pmode, mode))
+ continue;
+
+ found_it = true;
+
+ /*
+ * If the old matching mode is stale (ie. left over
+ * from a previous probe) just replace it outright.
+ * Otherwise just merge the type bits between all
+ * equal probed modes.
+ *
+ * If two probed modes are considered equal, pick the
+ * actual timings from the one that's marked as
+ * preferred (in case the match isn't 100%). If
+ * multiple or zero preferred modes are present, favor
+ * the mode added to the probed_modes list first.
+ */
+ if (mode->status == MODE_STALE) {
+ drm_mode_copy(mode, pmode);
+ } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
+ (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
+ pmode->type |= mode->type;
+ drm_mode_copy(mode, pmode);
+ } else {
+ mode->type |= pmode->type;
}
+
+ list_del(&pmode->head);
+ drm_mode_destroy(connector->dev, pmode);
+ break;
}
if (!found_it) {
@@ -1212,7 +1244,7 @@ EXPORT_SYMBOL(drm_mode_connector_list_update);
* This uses the same parameters as the fb modedb.c, except for an extra
* force-enable, force-enable-digital and force-disable bit at the end:
*
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
*
* The intermediate drm_cmdline_mode structure is required to store additional
* options from the command line modline like the force-enable/disable flag.
@@ -1491,4 +1523,4 @@ int drm_mode_convert_umode(struct drm_display_mode *out,
out:
return ret;
-} \ No newline at end of file
+}
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 6675b1428410..e3a4adf03e7b 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -40,28 +40,33 @@
* The basic usage pattern is to:
*
* drm_modeset_acquire_init(&ctx)
- * retry:
+ * retry:
* foreach (lock in random_ordered_set_of_locks) {
- * ret = drm_modeset_lock(lock, &ctx)
- * if (ret == -EDEADLK) {
- * drm_modeset_backoff(&ctx);
- * goto retry;
- * }
+ * ret = drm_modeset_lock(lock, &ctx)
+ * if (ret == -EDEADLK) {
+ * drm_modeset_backoff(&ctx);
+ * goto retry;
+ * }
* }
- *
* ... do stuff ...
- *
* drm_modeset_drop_locks(&ctx);
* drm_modeset_acquire_fini(&ctx);
*/
/**
* drm_modeset_lock_all - take all modeset locks
- * @dev: drm device
+ * @dev: DRM device
*
* This function takes all modeset locks, suitable where a more fine-grained
- * scheme isn't (yet) implemented. Locks must be dropped with
- * drm_modeset_unlock_all.
+ * scheme isn't (yet) implemented. Locks must be dropped by calling the
+ * drm_modeset_unlock_all() function.
+ *
+ * This function is deprecated. It allocates a lock acquisition context and
+ * stores it in the DRM device's ->mode_config. This facilitate conversion of
+ * existing code because it removes the need to manually deal with the
+ * acquisition context, but it is also brittle because the context is global
+ * and care must be taken not to nest calls. New code should use the
+ * drm_modeset_lock_all_ctx() function and pass in the context explicitly.
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
@@ -78,39 +83,43 @@ void drm_modeset_lock_all(struct drm_device *dev)
drm_modeset_acquire_init(ctx, 0);
retry:
- ret = drm_modeset_lock(&config->connection_mutex, ctx);
- if (ret)
- goto fail;
- ret = drm_modeset_lock_all_crtcs(dev, ctx);
- if (ret)
- goto fail;
+ ret = drm_modeset_lock_all_ctx(dev, ctx);
+ if (ret < 0) {
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(ctx);
+ goto retry;
+ }
+
+ drm_modeset_acquire_fini(ctx);
+ kfree(ctx);
+ return;
+ }
WARN_ON(config->acquire_ctx);
- /* now we hold the locks, so now that it is safe, stash the
- * ctx for drm_modeset_unlock_all():
+ /*
+ * We hold the locks now, so it is safe to stash the acquisition
+ * context for drm_modeset_unlock_all().
*/
config->acquire_ctx = ctx;
drm_warn_on_modeset_not_all_locked(dev);
-
- return;
-
-fail:
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- goto retry;
- }
-
- kfree(ctx);
}
EXPORT_SYMBOL(drm_modeset_lock_all);
/**
* drm_modeset_unlock_all - drop all modeset locks
- * @dev: device
+ * @dev: DRM device
*
- * This function drop all modeset locks taken by drm_modeset_lock_all.
+ * This function drops all modeset locks taken by a previous call to the
+ * drm_modeset_lock_all() function.
+ *
+ * This function is deprecated. It uses the lock acquisition context stored
+ * in the DRM device's ->mode_config. This facilitates conversion of existing
+ * code because it removes the need to manually deal with the acquisition
+ * context, but it is also brittle because the context is global and care must
+ * be taken not to nest calls. New code should pass the acquisition context
+ * directly to the drm_modeset_drop_locks() function.
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
@@ -431,14 +440,34 @@ void drm_modeset_unlock(struct drm_modeset_lock *lock)
}
EXPORT_SYMBOL(drm_modeset_unlock);
-/* In some legacy codepaths it's convenient to just grab all the crtc and plane
- * related locks. */
-int drm_modeset_lock_all_crtcs(struct drm_device *dev,
- struct drm_modeset_acquire_ctx *ctx)
+/**
+ * drm_modeset_lock_all_ctx - take all modeset locks
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * This function takes all modeset locks, suitable where a more fine-grained
+ * scheme isn't (yet) implemented.
+ *
+ * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex
+ * since that lock isn't required for modeset state changes. Callers which
+ * need to grab that lock too need to do so outside of the acquire context
+ * @ctx.
+ *
+ * Locks acquired with this function should be released by calling the
+ * drm_modeset_drop_locks() function on @ctx.
+ *
+ * Returns: 0 on success or a negative error-code on failure.
+ */
+int drm_modeset_lock_all_ctx(struct drm_device *dev,
+ struct drm_modeset_acquire_ctx *ctx)
{
struct drm_crtc *crtc;
struct drm_plane *plane;
- int ret = 0;
+ int ret;
+
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ret;
drm_for_each_crtc(crtc, dev) {
ret = drm_modeset_lock(&crtc->mutex, ctx);
@@ -454,4 +483,4 @@ int drm_modeset_lock_all_crtcs(struct drm_device *dev,
return 0;
}
-EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
+EXPORT_SYMBOL(drm_modeset_lock_all_ctx);
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index fcd2a86acd2c..a1fff1179a97 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -410,6 +410,26 @@ int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
}
EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask);
+int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw)
+{
+ struct pci_dev *root;
+ u32 lnkcap;
+
+ *mlw = 0;
+ if (!dev->pdev)
+ return -EINVAL;
+
+ root = dev->pdev->bus->self;
+
+ pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
+
+ *mlw = (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
+
+ DRM_INFO("probing mlw for device %x:%x = %x\n", root->vendor, root->device, lnkcap);
+ return 0;
+}
+EXPORT_SYMBOL(drm_pcie_get_max_link_width);
+
#else
int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index d384ebcf0aaf..369d2898ff9e 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -57,6 +57,10 @@
* by the atomic helpers.
*
* Again drivers are strongly urged to switch to the new interfaces.
+ *
+ * The plane helpers share the function table structures with other helpers,
+ * specifically also the atomic helpers. See struct &drm_plane_helper_funcs for
+ * the details.
*/
/*
@@ -164,6 +168,8 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
if (hscale < 0 || vscale < 0) {
DRM_DEBUG_KMS("Invalid scaling of plane\n");
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dest, false);
return -ERANGE;
}
@@ -180,6 +186,8 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
if (!can_position && !drm_rect_equals(dest, clip)) {
DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
+ drm_rect_debug_print("dst: ", dest, false);
+ drm_rect_debug_print("clip: ", clip, false);
return -EINVAL;
}
@@ -367,7 +375,7 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
&drm_primary_helper_funcs,
safe_modeset_formats,
ARRAY_SIZE(safe_modeset_formats),
- DRM_PLANE_TYPE_PRIMARY);
+ DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
primary = NULL;
@@ -394,7 +402,8 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *primary;
primary = create_primary_plane(dev);
- return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
+ return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs,
+ NULL);
}
EXPORT_SYMBOL(drm_crtc_init);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 9f935f55d74c..27aa7183b20b 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -313,19 +313,15 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
*
* Export callbacks:
*
- * - @gem_prime_pin (optional): prepare a GEM object for exporting
- *
- * - @gem_prime_get_sg_table: provide a scatter/gather table of pinned pages
- *
- * - @gem_prime_vmap: vmap a buffer exported by your driver
- *
- * - @gem_prime_vunmap: vunmap a buffer exported by your driver
- *
- * - @gem_prime_mmap (optional): mmap a buffer exported by your driver
+ * * @gem_prime_pin (optional): prepare a GEM object for exporting
+ * * @gem_prime_get_sg_table: provide a scatter/gather table of pinned pages
+ * * @gem_prime_vmap: vmap a buffer exported by your driver
+ * * @gem_prime_vunmap: vunmap a buffer exported by your driver
+ * * @gem_prime_mmap (optional): mmap a buffer exported by your driver
*
* Import callback:
*
- * - @gem_prime_import_sg_table (import): produce a GEM object from another
+ * * @gem_prime_import_sg_table (import): produce a GEM object from another
* driver's scatter/gather table
*/
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index f8b5fcfa91a2..e714b5a7955f 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -53,6 +53,9 @@
* This helper library can be used independently of the modeset helper library.
* Drivers can also overwrite different parts e.g. use their own hotplug
* handling code to avoid probing unrelated outputs.
+ *
+ * The probe helpers share the function table structures with other display
+ * helper libraries. See struct &drm_connector_helper_funcs for the details.
*/
static bool drm_kms_helper_poll = true;
@@ -126,9 +129,64 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked);
-
-static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector,
- uint32_t maxX, uint32_t maxY, bool merge_type_bits)
+/**
+ * drm_helper_probe_single_connector_modes - get complete set of display modes
+ * @connector: connector to probe
+ * @maxX: max width for modes
+ * @maxY: max height for modes
+ *
+ * Based on the helper callbacks implemented by @connector in struct
+ * &drm_connector_helper_funcs try to detect all valid modes. Modes will first
+ * be added to the connector's probed_modes list, then culled (based on validity
+ * and the @maxX, @maxY parameters) and put into the normal modes list.
+ *
+ * Intended to be used as a generic implementation of the ->fill_modes()
+ * @connector vfunc for drivers that use the CRTC helpers for output mode
+ * filtering and detection.
+ *
+ * The basic procedure is as follows
+ *
+ * 1. All modes currently on the connector's modes list are marked as stale
+ *
+ * 2. New modes are added to the connector's probed_modes list with
+ * drm_mode_probed_add(). New modes start their life with status as OK.
+ * Modes are added from a single source using the following priority order.
+ *
+ * - debugfs 'override_edid' (used for testing only)
+ * - firmware EDID (drm_load_edid_firmware())
+ * - connector helper ->get_modes() vfunc
+ * - if the connector status is connector_status_connected, standard
+ * VESA DMT modes up to 1024x768 are automatically added
+ * (drm_add_modes_noedid())
+ *
+ * Finally modes specified via the kernel command line (video=...) are
+ * added in addition to what the earlier probes produced
+ * (drm_helper_probe_add_cmdline_mode()). These modes are generated
+ * using the VESA GTF/CVT formulas.
+ *
+ * 3. Modes are moved from the probed_modes list to the modes list. Potential
+ * duplicates are merged together (see drm_mode_connector_list_update()).
+ * After this step the probed_modes list will be empty again.
+ *
+ * 4. Any non-stale mode on the modes list then undergoes validation
+ *
+ * - drm_mode_validate_basic() performs basic sanity checks
+ * - drm_mode_validate_size() filters out modes larger than @maxX and @maxY
+ * (if specified)
+ * - drm_mode_validate_flag() checks the modes againt basic connector
+ * capabilites (interlace_allowed,doublescan_allowed,stereo_allowed)
+ * - the optional connector ->mode_valid() helper can perform driver and/or
+ * hardware specific checks
+ *
+ * 5. Any mode whose status is not OK is pruned from the connector's modes list,
+ * accompanied by a debug message indicating the reason for the mode's
+ * rejection (see drm_mode_prune_invalid()).
+ *
+ * Returns:
+ * The number of modes found on @connector.
+ */
+int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
+ uint32_t maxX, uint32_t maxY)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
@@ -143,9 +201,11 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
connector->name);
- /* set all modes to the unverified state */
+ /* set all old modes to the stale state */
list_for_each_entry(mode, &connector->modes, head)
- mode->status = MODE_UNVERIFIED;
+ mode->status = MODE_STALE;
+
+ old_status = connector->status;
if (connector->force) {
if (connector->force == DRM_FORCE_ON ||
@@ -156,33 +216,32 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
if (connector->funcs->force)
connector->funcs->force(connector);
} else {
- old_status = connector->status;
-
connector->status = connector->funcs->detect(connector, true);
+ }
+
+ /*
+ * Normally either the driver's hpd code or the poll loop should
+ * pick up any changes and fire the hotplug event. But if
+ * userspace sneaks in a probe, we might miss a change. Hence
+ * check here, and if anything changed start the hotplug code.
+ */
+ if (old_status != connector->status) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
+ connector->base.id,
+ connector->name,
+ drm_get_connector_status_name(old_status),
+ drm_get_connector_status_name(connector->status));
/*
- * Normally either the driver's hpd code or the poll loop should
- * pick up any changes and fire the hotplug event. But if
- * userspace sneaks in a probe, we might miss a change. Hence
- * check here, and if anything changed start the hotplug code.
+ * The hotplug event code might call into the fb
+ * helpers, and so expects that we do not hold any
+ * locks. Fire up the poll struct instead, it will
+ * disable itself again.
*/
- if (old_status != connector->status) {
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
- connector->base.id,
- connector->name,
- old_status, connector->status);
-
- /*
- * The hotplug event code might call into the fb
- * helpers, and so expects that we do not hold any
- * locks. Fire up the poll struct instead, it will
- * disable itself again.
- */
- dev->mode_config.delayed_event = true;
- if (dev->mode_config.poll_enabled)
- schedule_delayed_work(&dev->mode_config.output_poll_work,
- 0);
- }
+ dev->mode_config.delayed_event = true;
+ if (dev->mode_config.poll_enabled)
+ schedule_delayed_work(&dev->mode_config.output_poll_work,
+ 0);
}
/* Re-enable polling in case the global poll config changed. */
@@ -199,17 +258,16 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
goto prune;
}
+ if (connector->override_edid) {
+ struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
+
+ count = drm_add_edid_modes(connector, edid);
+ drm_edid_to_eld(connector, edid);
+ } else {
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
- count = drm_load_edid_firmware(connector);
- if (count == 0)
+ count = drm_load_edid_firmware(connector);
+ if (count == 0)
#endif
- {
- if (connector->override_edid) {
- struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
-
- count = drm_add_edid_modes(connector, edid);
- drm_edid_to_eld(connector, edid);
- } else
count = (*connector_funcs->get_modes)(connector);
}
@@ -219,7 +277,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
if (count == 0)
goto prune;
- drm_mode_connector_list_update(connector, merge_type_bits);
+ drm_mode_connector_list_update(connector);
if (connector->interlace_allowed)
mode_flags |= DRM_MODE_FLAG_INTERLACE;
@@ -263,49 +321,9 @@ prune:
return count;
}
-
-/**
- * drm_helper_probe_single_connector_modes - get complete set of display modes
- * @connector: connector to probe
- * @maxX: max width for modes
- * @maxY: max height for modes
- *
- * Based on the helper callbacks implemented by @connector try to detect all
- * valid modes. Modes will first be added to the connector's probed_modes list,
- * then culled (based on validity and the @maxX, @maxY parameters) and put into
- * the normal modes list.
- *
- * Intended to be use as a generic implementation of the ->fill_modes()
- * @connector vfunc for drivers that use the crtc helpers for output mode
- * filtering and detection.
- *
- * Returns:
- * The number of modes found on @connector.
- */
-int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
- uint32_t maxX, uint32_t maxY)
-{
- return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, true);
-}
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
/**
- * drm_helper_probe_single_connector_modes_nomerge - get complete set of display modes
- * @connector: connector to probe
- * @maxX: max width for modes
- * @maxY: max height for modes
- *
- * This operates like drm_hehlper_probe_single_connector_modes except it
- * replaces the mode bits instead of merging them for preferred modes.
- */
-int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector *connector,
- uint32_t maxX, uint32_t maxY)
-{
- return drm_helper_probe_single_connector_modes_merge_bits(connector, maxX, maxY, false);
-}
-EXPORT_SYMBOL(drm_helper_probe_single_connector_modes_nomerge);
-
-/**
* drm_kms_helper_hotplug_event - fire off KMS hotplug events
* @dev: drm_device whose connector state changed
*
diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c
index 531ac4cc9756..a8e2c8603945 100644
--- a/drivers/gpu/drm/drm_rect.c
+++ b/drivers/gpu/drm/drm_rect.c
@@ -275,22 +275,23 @@ EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed);
/**
* drm_rect_debug_print - print the rectangle information
+ * @prefix: prefix string
* @r: rectangle to print
* @fixed_point: rectangle is in 16.16 fixed point format
*/
-void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point)
+void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
{
int w = drm_rect_width(r);
int h = drm_rect_height(r);
if (fixed_point)
- DRM_DEBUG_KMS("%d.%06ux%d.%06u%+d.%06u%+d.%06u\n",
+ DRM_DEBUG_KMS("%s%d.%06ux%d.%06u%+d.%06u%+d.%06u\n", prefix,
w >> 16, ((w & 0xffff) * 15625) >> 10,
h >> 16, ((h & 0xffff) * 15625) >> 10,
r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10,
r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10);
else
- DRM_DEBUG_KMS("%dx%d%+d%+d\n", w, h, r->x1, r->y1);
+ DRM_DEBUG_KMS("%s%dx%d%+d%+d\n", prefix, w, h, r->x1, r->y1);
}
EXPORT_SYMBOL(drm_rect_debug_print);
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 615b7e667320..d503f8e8c2d1 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -167,47 +167,35 @@ static ssize_t status_store(struct device *device,
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_device *dev = connector->dev;
- enum drm_connector_status old_status;
+ enum drm_connector_force old_force;
int ret;
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (ret)
return ret;
- old_status = connector->status;
+ old_force = connector->force;
- if (sysfs_streq(buf, "detect")) {
+ if (sysfs_streq(buf, "detect"))
connector->force = 0;
- connector->status = connector->funcs->detect(connector, true);
- } else if (sysfs_streq(buf, "on")) {
+ else if (sysfs_streq(buf, "on"))
connector->force = DRM_FORCE_ON;
- } else if (sysfs_streq(buf, "on-digital")) {
+ else if (sysfs_streq(buf, "on-digital"))
connector->force = DRM_FORCE_ON_DIGITAL;
- } else if (sysfs_streq(buf, "off")) {
+ else if (sysfs_streq(buf, "off"))
connector->force = DRM_FORCE_OFF;
- } else
+ else
ret = -EINVAL;
- if (ret == 0 && connector->force) {
- if (connector->force == DRM_FORCE_ON ||
- connector->force == DRM_FORCE_ON_DIGITAL)
- connector->status = connector_status_connected;
- else
- connector->status = connector_status_disconnected;
- if (connector->funcs->force)
- connector->funcs->force(connector);
- }
-
- if (old_status != connector->status) {
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+ if (old_force != connector->force || !connector->force) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
connector->base.id,
connector->name,
- old_status, connector->status);
+ old_force, connector->force);
- dev->mode_config.delayed_event = true;
- if (dev->mode_config.poll_enabled)
- schedule_delayed_work(&dev->mode_config.output_poll_work,
- 0);
+ connector->funcs->fill_modes(connector,
+ dev->mode_config.max_width,
+ dev->mode_config.max_height);
}
mutex_unlock(&dev->mode_config.mutex);
@@ -252,27 +240,33 @@ static ssize_t edid_show(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off,
size_t count)
{
- struct device *connector_dev = container_of(kobj, struct device, kobj);
+ struct device *connector_dev = kobj_to_dev(kobj);
struct drm_connector *connector = to_drm_connector(connector_dev);
unsigned char *edid;
size_t size;
+ ssize_t ret = 0;
+ mutex_lock(&connector->dev->mode_config.mutex);
if (!connector->edid_blob_ptr)
- return 0;
+ goto unlock;
edid = connector->edid_blob_ptr->data;
size = connector->edid_blob_ptr->length;
if (!edid)
- return 0;
+ goto unlock;
if (off >= size)
- return 0;
+ goto unlock;
if (off + count > size)
count = size - off;
memcpy(buf, edid + off, count);
- return count;
+ ret = count;
+unlock:
+ mutex_unlock(&connector->dev->mode_config.mutex);
+
+ return ret;
}
static ssize_t modes_show(struct device *device,
@@ -283,10 +277,12 @@ static ssize_t modes_show(struct device *device,
struct drm_display_mode *mode;
int written = 0;
+ mutex_lock(&connector->dev->mode_config.mutex);
list_for_each_entry(mode, &connector->modes, head) {
written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
mode->name);
}
+ mutex_unlock(&connector->dev->mode_config.mutex);
return written;
}
diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig
new file mode 100644
index 000000000000..2cde7a5442fb
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -0,0 +1,20 @@
+
+config DRM_ETNAVIV
+ tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
+ depends on DRM
+ depends on ARCH_MXC || ARCH_DOVE
+ select SHMEM
+ select TMPFS
+ select IOMMU_API
+ select IOMMU_SUPPORT
+ select WANT_DEV_COREDUMP
+ help
+ DRM driver for Vivante GPUs.
+
+config DRM_ETNAVIV_REGISTER_LOGGING
+ bool "enable ETNAVIV register logging"
+ depends on DRM_ETNAVIV
+ help
+ Compile in support for logging register reads/writes in a format
+ that can be parsed by envytools demsm tool. If enabled, register
+ logging can be switched on via etnaviv.reglog=y module param.
diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
new file mode 100644
index 000000000000..1086e9876f91
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -0,0 +1,14 @@
+etnaviv-y := \
+ etnaviv_buffer.o \
+ etnaviv_cmd_parser.o \
+ etnaviv_drv.o \
+ etnaviv_dump.o \
+ etnaviv_gem_prime.o \
+ etnaviv_gem_submit.o \
+ etnaviv_gem.o \
+ etnaviv_gpu.o \
+ etnaviv_iommu_v2.o \
+ etnaviv_iommu.o \
+ etnaviv_mmu.o
+
+obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o
diff --git a/drivers/gpu/drm/etnaviv/cmdstream.xml.h b/drivers/gpu/drm/etnaviv/cmdstream.xml.h
new file mode 100644
index 000000000000..8c44ba9a694e
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/cmdstream.xml.h
@@ -0,0 +1,218 @@
+#ifndef CMDSTREAM_XML
+#define CMDSTREAM_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- cmdstream.xml ( 12589 bytes, from 2014-02-17 14:57:56)
+- common.xml ( 18437 bytes, from 2015-03-25 11:27:41)
+
+Copyright (C) 2014
+*/
+
+
+#define FE_OPCODE_LOAD_STATE 0x00000001
+#define FE_OPCODE_END 0x00000002
+#define FE_OPCODE_NOP 0x00000003
+#define FE_OPCODE_DRAW_2D 0x00000004
+#define FE_OPCODE_DRAW_PRIMITIVES 0x00000005
+#define FE_OPCODE_DRAW_INDEXED_PRIMITIVES 0x00000006
+#define FE_OPCODE_WAIT 0x00000007
+#define FE_OPCODE_LINK 0x00000008
+#define FE_OPCODE_STALL 0x00000009
+#define FE_OPCODE_CALL 0x0000000a
+#define FE_OPCODE_RETURN 0x0000000b
+#define FE_OPCODE_CHIP_SELECT 0x0000000d
+#define PRIMITIVE_TYPE_POINTS 0x00000001
+#define PRIMITIVE_TYPE_LINES 0x00000002
+#define PRIMITIVE_TYPE_LINE_STRIP 0x00000003
+#define PRIMITIVE_TYPE_TRIANGLES 0x00000004
+#define PRIMITIVE_TYPE_TRIANGLE_STRIP 0x00000005
+#define PRIMITIVE_TYPE_TRIANGLE_FAN 0x00000006
+#define PRIMITIVE_TYPE_LINE_LOOP 0x00000007
+#define PRIMITIVE_TYPE_QUADS 0x00000008
+#define VIV_FE_LOAD_STATE 0x00000000
+
+#define VIV_FE_LOAD_STATE_HEADER 0x00000000
+#define VIV_FE_LOAD_STATE_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_LOAD_STATE_HEADER_OP__SHIFT 27
+#define VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE 0x08000000
+#define VIV_FE_LOAD_STATE_HEADER_FIXP 0x04000000
+#define VIV_FE_LOAD_STATE_HEADER_COUNT__MASK 0x03ff0000
+#define VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT 16
+#define VIV_FE_LOAD_STATE_HEADER_COUNT(x) (((x) << VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK)
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK 0x0000ffff
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT 0
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET(x) (((x) << VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT) & VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK)
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR 2
+
+#define VIV_FE_END 0x00000000
+
+#define VIV_FE_END_HEADER 0x00000000
+#define VIV_FE_END_HEADER_EVENT_ID__MASK 0x0000001f
+#define VIV_FE_END_HEADER_EVENT_ID__SHIFT 0
+#define VIV_FE_END_HEADER_EVENT_ID(x) (((x) << VIV_FE_END_HEADER_EVENT_ID__SHIFT) & VIV_FE_END_HEADER_EVENT_ID__MASK)
+#define VIV_FE_END_HEADER_EVENT_ENABLE 0x00000100
+#define VIV_FE_END_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_END_HEADER_OP__SHIFT 27
+#define VIV_FE_END_HEADER_OP_END 0x10000000
+
+#define VIV_FE_NOP 0x00000000
+
+#define VIV_FE_NOP_HEADER 0x00000000
+#define VIV_FE_NOP_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_NOP_HEADER_OP__SHIFT 27
+#define VIV_FE_NOP_HEADER_OP_NOP 0x18000000
+
+#define VIV_FE_DRAW_2D 0x00000000
+
+#define VIV_FE_DRAW_2D_HEADER 0x00000000
+#define VIV_FE_DRAW_2D_HEADER_COUNT__MASK 0x0000ff00
+#define VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT 8
+#define VIV_FE_DRAW_2D_HEADER_COUNT(x) (((x) << VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_COUNT__MASK)
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK 0x07ff0000
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT 16
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT(x) (((x) << VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK)
+#define VIV_FE_DRAW_2D_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_DRAW_2D_HEADER_OP__SHIFT 27
+#define VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D 0x20000000
+
+#define VIV_FE_DRAW_2D_TOP_LEFT 0x00000008
+#define VIV_FE_DRAW_2D_TOP_LEFT_X__MASK 0x0000ffff
+#define VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT 0
+#define VIV_FE_DRAW_2D_TOP_LEFT_X(x) (((x) << VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_X__MASK)
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK 0xffff0000
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT 16
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y(x) (((x) << VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK)
+
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT 0x0000000c
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK 0x0000ffff
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT 0
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x) (((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK)
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK 0xffff0000
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT 16
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(x) (((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK)
+
+#define VIV_FE_DRAW_PRIMITIVES 0x00000000
+
+#define VIV_FE_DRAW_PRIMITIVES_HEADER 0x00000000
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__SHIFT 27
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES 0x28000000
+
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND 0x00000004
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT 0
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE(x) (((x) << VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK)
+
+#define VIV_FE_DRAW_PRIMITIVES_START 0x00000008
+
+#define VIV_FE_DRAW_PRIMITIVES_COUNT 0x0000000c
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES 0x00000000
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER 0x00000000
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__SHIFT 27
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES 0x30000000
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND 0x00000004
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT 0
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE(x) (((x) << VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK)
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_START 0x00000008
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COUNT 0x0000000c
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_OFFSET 0x00000010
+
+#define VIV_FE_WAIT 0x00000000
+
+#define VIV_FE_WAIT_HEADER 0x00000000
+#define VIV_FE_WAIT_HEADER_DELAY__MASK 0x0000ffff
+#define VIV_FE_WAIT_HEADER_DELAY__SHIFT 0
+#define VIV_FE_WAIT_HEADER_DELAY(x) (((x) << VIV_FE_WAIT_HEADER_DELAY__SHIFT) & VIV_FE_WAIT_HEADER_DELAY__MASK)
+#define VIV_FE_WAIT_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_WAIT_HEADER_OP__SHIFT 27
+#define VIV_FE_WAIT_HEADER_OP_WAIT 0x38000000
+
+#define VIV_FE_LINK 0x00000000
+
+#define VIV_FE_LINK_HEADER 0x00000000
+#define VIV_FE_LINK_HEADER_PREFETCH__MASK 0x0000ffff
+#define VIV_FE_LINK_HEADER_PREFETCH__SHIFT 0
+#define VIV_FE_LINK_HEADER_PREFETCH(x) (((x) << VIV_FE_LINK_HEADER_PREFETCH__SHIFT) & VIV_FE_LINK_HEADER_PREFETCH__MASK)
+#define VIV_FE_LINK_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_LINK_HEADER_OP__SHIFT 27
+#define VIV_FE_LINK_HEADER_OP_LINK 0x40000000
+
+#define VIV_FE_LINK_ADDRESS 0x00000004
+
+#define VIV_FE_STALL 0x00000000
+
+#define VIV_FE_STALL_HEADER 0x00000000
+#define VIV_FE_STALL_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_STALL_HEADER_OP__SHIFT 27
+#define VIV_FE_STALL_HEADER_OP_STALL 0x48000000
+
+#define VIV_FE_STALL_TOKEN 0x00000004
+#define VIV_FE_STALL_TOKEN_FROM__MASK 0x0000001f
+#define VIV_FE_STALL_TOKEN_FROM__SHIFT 0
+#define VIV_FE_STALL_TOKEN_FROM(x) (((x) << VIV_FE_STALL_TOKEN_FROM__SHIFT) & VIV_FE_STALL_TOKEN_FROM__MASK)
+#define VIV_FE_STALL_TOKEN_TO__MASK 0x00001f00
+#define VIV_FE_STALL_TOKEN_TO__SHIFT 8
+#define VIV_FE_STALL_TOKEN_TO(x) (((x) << VIV_FE_STALL_TOKEN_TO__SHIFT) & VIV_FE_STALL_TOKEN_TO__MASK)
+
+#define VIV_FE_CALL 0x00000000
+
+#define VIV_FE_CALL_HEADER 0x00000000
+#define VIV_FE_CALL_HEADER_PREFETCH__MASK 0x0000ffff
+#define VIV_FE_CALL_HEADER_PREFETCH__SHIFT 0
+#define VIV_FE_CALL_HEADER_PREFETCH(x) (((x) << VIV_FE_CALL_HEADER_PREFETCH__SHIFT) & VIV_FE_CALL_HEADER_PREFETCH__MASK)
+#define VIV_FE_CALL_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_CALL_HEADER_OP__SHIFT 27
+#define VIV_FE_CALL_HEADER_OP_CALL 0x50000000
+
+#define VIV_FE_CALL_ADDRESS 0x00000004
+
+#define VIV_FE_CALL_RETURN_PREFETCH 0x00000008
+
+#define VIV_FE_CALL_RETURN_ADDRESS 0x0000000c
+
+#define VIV_FE_RETURN 0x00000000
+
+#define VIV_FE_RETURN_HEADER 0x00000000
+#define VIV_FE_RETURN_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_RETURN_HEADER_OP__SHIFT 27
+#define VIV_FE_RETURN_HEADER_OP_RETURN 0x58000000
+
+#define VIV_FE_CHIP_SELECT 0x00000000
+
+#define VIV_FE_CHIP_SELECT_HEADER 0x00000000
+#define VIV_FE_CHIP_SELECT_HEADER_OP__MASK 0xf8000000
+#define VIV_FE_CHIP_SELECT_HEADER_OP__SHIFT 27
+#define VIV_FE_CHIP_SELECT_HEADER_OP_CHIP_SELECT 0x68000000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP15 0x00008000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP14 0x00004000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP13 0x00002000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP12 0x00001000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP11 0x00000800
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP10 0x00000400
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP9 0x00000200
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP8 0x00000100
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP7 0x00000080
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP6 0x00000040
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP5 0x00000020
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP4 0x00000010
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP3 0x00000008
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP2 0x00000004
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP1 0x00000002
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP0 0x00000001
+
+
+#endif /* CMDSTREAM_XML */
diff --git a/drivers/gpu/drm/etnaviv/common.xml.h b/drivers/gpu/drm/etnaviv/common.xml.h
new file mode 100644
index 000000000000..9e585d51fb78
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/common.xml.h
@@ -0,0 +1,249 @@
+#ifndef COMMON_XML
+#define COMMON_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state_vg.xml ( 5973 bytes, from 2015-03-25 11:26:01)
+- common.xml ( 18437 bytes, from 2015-03-25 11:27:41)
+
+Copyright (C) 2015
+*/
+
+
+#define PIPE_ID_PIPE_3D 0x00000000
+#define PIPE_ID_PIPE_2D 0x00000001
+#define SYNC_RECIPIENT_FE 0x00000001
+#define SYNC_RECIPIENT_RA 0x00000005
+#define SYNC_RECIPIENT_PE 0x00000007
+#define SYNC_RECIPIENT_DE 0x0000000b
+#define SYNC_RECIPIENT_VG 0x0000000f
+#define SYNC_RECIPIENT_TESSELATOR 0x00000010
+#define SYNC_RECIPIENT_VG2 0x00000011
+#define SYNC_RECIPIENT_TESSELATOR2 0x00000012
+#define SYNC_RECIPIENT_VG3 0x00000013
+#define SYNC_RECIPIENT_TESSELATOR3 0x00000014
+#define ENDIAN_MODE_NO_SWAP 0x00000000
+#define ENDIAN_MODE_SWAP_16 0x00000001
+#define ENDIAN_MODE_SWAP_32 0x00000002
+#define chipModel_GC300 0x00000300
+#define chipModel_GC320 0x00000320
+#define chipModel_GC350 0x00000350
+#define chipModel_GC355 0x00000355
+#define chipModel_GC400 0x00000400
+#define chipModel_GC410 0x00000410
+#define chipModel_GC420 0x00000420
+#define chipModel_GC450 0x00000450
+#define chipModel_GC500 0x00000500
+#define chipModel_GC530 0x00000530
+#define chipModel_GC600 0x00000600
+#define chipModel_GC700 0x00000700
+#define chipModel_GC800 0x00000800
+#define chipModel_GC860 0x00000860
+#define chipModel_GC880 0x00000880
+#define chipModel_GC1000 0x00001000
+#define chipModel_GC2000 0x00002000
+#define chipModel_GC2100 0x00002100
+#define chipModel_GC4000 0x00004000
+#define RGBA_BITS_R 0x00000001
+#define RGBA_BITS_G 0x00000002
+#define RGBA_BITS_B 0x00000004
+#define RGBA_BITS_A 0x00000008
+#define chipFeatures_FAST_CLEAR 0x00000001
+#define chipFeatures_SPECIAL_ANTI_ALIASING 0x00000002
+#define chipFeatures_PIPE_3D 0x00000004
+#define chipFeatures_DXT_TEXTURE_COMPRESSION 0x00000008
+#define chipFeatures_DEBUG_MODE 0x00000010
+#define chipFeatures_Z_COMPRESSION 0x00000020
+#define chipFeatures_YUV420_SCALER 0x00000040
+#define chipFeatures_MSAA 0x00000080
+#define chipFeatures_DC 0x00000100
+#define chipFeatures_PIPE_2D 0x00000200
+#define chipFeatures_ETC1_TEXTURE_COMPRESSION 0x00000400
+#define chipFeatures_FAST_SCALER 0x00000800
+#define chipFeatures_HIGH_DYNAMIC_RANGE 0x00001000
+#define chipFeatures_YUV420_TILER 0x00002000
+#define chipFeatures_MODULE_CG 0x00004000
+#define chipFeatures_MIN_AREA 0x00008000
+#define chipFeatures_NO_EARLY_Z 0x00010000
+#define chipFeatures_NO_422_TEXTURE 0x00020000
+#define chipFeatures_BUFFER_INTERLEAVING 0x00040000
+#define chipFeatures_BYTE_WRITE_2D 0x00080000
+#define chipFeatures_NO_SCALER 0x00100000
+#define chipFeatures_YUY2_AVERAGING 0x00200000
+#define chipFeatures_HALF_PE_CACHE 0x00400000
+#define chipFeatures_HALF_TX_CACHE 0x00800000
+#define chipFeatures_YUY2_RENDER_TARGET 0x01000000
+#define chipFeatures_MEM32 0x02000000
+#define chipFeatures_PIPE_VG 0x04000000
+#define chipFeatures_VGTS 0x08000000
+#define chipFeatures_FE20 0x10000000
+#define chipFeatures_BYTE_WRITE_3D 0x20000000
+#define chipFeatures_RS_YUV_TARGET 0x40000000
+#define chipFeatures_32_BIT_INDICES 0x80000000
+#define chipMinorFeatures0_FLIP_Y 0x00000001
+#define chipMinorFeatures0_DUAL_RETURN_BUS 0x00000002
+#define chipMinorFeatures0_ENDIANNESS_CONFIG 0x00000004
+#define chipMinorFeatures0_TEXTURE_8K 0x00000008
+#define chipMinorFeatures0_CORRECT_TEXTURE_CONVERTER 0x00000010
+#define chipMinorFeatures0_SPECIAL_MSAA_LOD 0x00000020
+#define chipMinorFeatures0_FAST_CLEAR_FLUSH 0x00000040
+#define chipMinorFeatures0_2DPE20 0x00000080
+#define chipMinorFeatures0_CORRECT_AUTO_DISABLE 0x00000100
+#define chipMinorFeatures0_RENDERTARGET_8K 0x00000200
+#define chipMinorFeatures0_2BITPERTILE 0x00000400
+#define chipMinorFeatures0_SEPARATE_TILE_STATUS_WHEN_INTERLEAVED 0x00000800
+#define chipMinorFeatures0_SUPER_TILED 0x00001000
+#define chipMinorFeatures0_VG_20 0x00002000
+#define chipMinorFeatures0_TS_EXTENDED_COMMANDS 0x00004000
+#define chipMinorFeatures0_COMPRESSION_FIFO_FIXED 0x00008000
+#define chipMinorFeatures0_HAS_SIGN_FLOOR_CEIL 0x00010000
+#define chipMinorFeatures0_VG_FILTER 0x00020000
+#define chipMinorFeatures0_VG_21 0x00040000
+#define chipMinorFeatures0_SHADER_HAS_W 0x00080000
+#define chipMinorFeatures0_HAS_SQRT_TRIG 0x00100000
+#define chipMinorFeatures0_MORE_MINOR_FEATURES 0x00200000
+#define chipMinorFeatures0_MC20 0x00400000
+#define chipMinorFeatures0_MSAA_SIDEBAND 0x00800000
+#define chipMinorFeatures0_BUG_FIXES0 0x01000000
+#define chipMinorFeatures0_VAA 0x02000000
+#define chipMinorFeatures0_BYPASS_IN_MSAA 0x04000000
+#define chipMinorFeatures0_HZ 0x08000000
+#define chipMinorFeatures0_NEW_TEXTURE 0x10000000
+#define chipMinorFeatures0_2D_A8_TARGET 0x20000000
+#define chipMinorFeatures0_CORRECT_STENCIL 0x40000000
+#define chipMinorFeatures0_ENHANCE_VR 0x80000000
+#define chipMinorFeatures1_RSUV_SWIZZLE 0x00000001
+#define chipMinorFeatures1_V2_COMPRESSION 0x00000002
+#define chipMinorFeatures1_VG_DOUBLE_BUFFER 0x00000004
+#define chipMinorFeatures1_EXTRA_EVENT_STATES 0x00000008
+#define chipMinorFeatures1_NO_STRIPING_NEEDED 0x00000010
+#define chipMinorFeatures1_TEXTURE_STRIDE 0x00000020
+#define chipMinorFeatures1_BUG_FIXES3 0x00000040
+#define chipMinorFeatures1_AUTO_DISABLE 0x00000080
+#define chipMinorFeatures1_AUTO_RESTART_TS 0x00000100
+#define chipMinorFeatures1_DISABLE_PE_GATING 0x00000200
+#define chipMinorFeatures1_L2_WINDOWING 0x00000400
+#define chipMinorFeatures1_HALF_FLOAT 0x00000800
+#define chipMinorFeatures1_PIXEL_DITHER 0x00001000
+#define chipMinorFeatures1_TWO_STENCIL_REFERENCE 0x00002000
+#define chipMinorFeatures1_EXTENDED_PIXEL_FORMAT 0x00004000
+#define chipMinorFeatures1_CORRECT_MIN_MAX_DEPTH 0x00008000
+#define chipMinorFeatures1_2D_DITHER 0x00010000
+#define chipMinorFeatures1_BUG_FIXES5 0x00020000
+#define chipMinorFeatures1_NEW_2D 0x00040000
+#define chipMinorFeatures1_NEW_FP 0x00080000
+#define chipMinorFeatures1_TEXTURE_HALIGN 0x00100000
+#define chipMinorFeatures1_NON_POWER_OF_TWO 0x00200000
+#define chipMinorFeatures1_LINEAR_TEXTURE_SUPPORT 0x00400000
+#define chipMinorFeatures1_HALTI0 0x00800000
+#define chipMinorFeatures1_CORRECT_OVERFLOW_VG 0x01000000
+#define chipMinorFeatures1_NEGATIVE_LOG_FIX 0x02000000
+#define chipMinorFeatures1_RESOLVE_OFFSET 0x04000000
+#define chipMinorFeatures1_OK_TO_GATE_AXI_CLOCK 0x08000000
+#define chipMinorFeatures1_MMU_VERSION 0x10000000
+#define chipMinorFeatures1_WIDE_LINE 0x20000000
+#define chipMinorFeatures1_BUG_FIXES6 0x40000000
+#define chipMinorFeatures1_FC_FLUSH_STALL 0x80000000
+#define chipMinorFeatures2_LINE_LOOP 0x00000001
+#define chipMinorFeatures2_LOGIC_OP 0x00000002
+#define chipMinorFeatures2_UNK2 0x00000004
+#define chipMinorFeatures2_SUPERTILED_TEXTURE 0x00000008
+#define chipMinorFeatures2_UNK4 0x00000010
+#define chipMinorFeatures2_RECT_PRIMITIVE 0x00000020
+#define chipMinorFeatures2_COMPOSITION 0x00000040
+#define chipMinorFeatures2_CORRECT_AUTO_DISABLE_COUNT 0x00000080
+#define chipMinorFeatures2_UNK8 0x00000100
+#define chipMinorFeatures2_UNK9 0x00000200
+#define chipMinorFeatures2_UNK10 0x00000400
+#define chipMinorFeatures2_SAMPLERBASE_16 0x00000800
+#define chipMinorFeatures2_UNK12 0x00001000
+#define chipMinorFeatures2_UNK13 0x00002000
+#define chipMinorFeatures2_UNK14 0x00004000
+#define chipMinorFeatures2_EXTRA_TEXTURE_STATE 0x00008000
+#define chipMinorFeatures2_FULL_DIRECTFB 0x00010000
+#define chipMinorFeatures2_2D_TILING 0x00020000
+#define chipMinorFeatures2_THREAD_WALKER_IN_PS 0x00040000
+#define chipMinorFeatures2_TILE_FILLER 0x00080000
+#define chipMinorFeatures2_UNK20 0x00100000
+#define chipMinorFeatures2_2D_MULTI_SOURCE_BLIT 0x00200000
+#define chipMinorFeatures2_UNK22 0x00400000
+#define chipMinorFeatures2_UNK23 0x00800000
+#define chipMinorFeatures2_UNK24 0x01000000
+#define chipMinorFeatures2_MIXED_STREAMS 0x02000000
+#define chipMinorFeatures2_2D_420_L2CACHE 0x04000000
+#define chipMinorFeatures2_UNK27 0x08000000
+#define chipMinorFeatures2_2D_NO_INDEX8_BRUSH 0x10000000
+#define chipMinorFeatures2_TEXTURE_TILED_READ 0x20000000
+#define chipMinorFeatures2_UNK30 0x40000000
+#define chipMinorFeatures2_UNK31 0x80000000
+#define chipMinorFeatures3_ROTATION_STALL_FIX 0x00000001
+#define chipMinorFeatures3_UNK1 0x00000002
+#define chipMinorFeatures3_2D_MULTI_SOURCE_BLT_EX 0x00000004
+#define chipMinorFeatures3_UNK3 0x00000008
+#define chipMinorFeatures3_UNK4 0x00000010
+#define chipMinorFeatures3_UNK5 0x00000020
+#define chipMinorFeatures3_UNK6 0x00000040
+#define chipMinorFeatures3_UNK7 0x00000080
+#define chipMinorFeatures3_UNK8 0x00000100
+#define chipMinorFeatures3_UNK9 0x00000200
+#define chipMinorFeatures3_BUG_FIXES10 0x00000400
+#define chipMinorFeatures3_UNK11 0x00000800
+#define chipMinorFeatures3_BUG_FIXES11 0x00001000
+#define chipMinorFeatures3_UNK13 0x00002000
+#define chipMinorFeatures3_UNK14 0x00004000
+#define chipMinorFeatures3_UNK15 0x00008000
+#define chipMinorFeatures3_UNK16 0x00010000
+#define chipMinorFeatures3_UNK17 0x00020000
+#define chipMinorFeatures3_UNK18 0x00040000
+#define chipMinorFeatures3_UNK19 0x00080000
+#define chipMinorFeatures3_UNK20 0x00100000
+#define chipMinorFeatures3_UNK21 0x00200000
+#define chipMinorFeatures3_UNK22 0x00400000
+#define chipMinorFeatures3_UNK23 0x00800000
+#define chipMinorFeatures3_UNK24 0x01000000
+#define chipMinorFeatures3_UNK25 0x02000000
+#define chipMinorFeatures3_UNK26 0x04000000
+#define chipMinorFeatures3_UNK27 0x08000000
+#define chipMinorFeatures3_UNK28 0x10000000
+#define chipMinorFeatures3_UNK29 0x20000000
+#define chipMinorFeatures3_UNK30 0x40000000
+#define chipMinorFeatures3_UNK31 0x80000000
+#define chipMinorFeatures4_UNK0 0x00000001
+#define chipMinorFeatures4_UNK1 0x00000002
+#define chipMinorFeatures4_UNK2 0x00000004
+#define chipMinorFeatures4_UNK3 0x00000008
+#define chipMinorFeatures4_UNK4 0x00000010
+#define chipMinorFeatures4_UNK5 0x00000020
+#define chipMinorFeatures4_UNK6 0x00000040
+#define chipMinorFeatures4_UNK7 0x00000080
+#define chipMinorFeatures4_UNK8 0x00000100
+#define chipMinorFeatures4_UNK9 0x00000200
+#define chipMinorFeatures4_UNK10 0x00000400
+#define chipMinorFeatures4_UNK11 0x00000800
+#define chipMinorFeatures4_UNK12 0x00001000
+#define chipMinorFeatures4_UNK13 0x00002000
+#define chipMinorFeatures4_UNK14 0x00004000
+#define chipMinorFeatures4_UNK15 0x00008000
+#define chipMinorFeatures4_UNK16 0x00010000
+#define chipMinorFeatures4_UNK17 0x00020000
+#define chipMinorFeatures4_UNK18 0x00040000
+#define chipMinorFeatures4_UNK19 0x00080000
+#define chipMinorFeatures4_UNK20 0x00100000
+#define chipMinorFeatures4_UNK21 0x00200000
+#define chipMinorFeatures4_UNK22 0x00400000
+#define chipMinorFeatures4_UNK23 0x00800000
+#define chipMinorFeatures4_UNK24 0x01000000
+#define chipMinorFeatures4_UNK25 0x02000000
+#define chipMinorFeatures4_UNK26 0x04000000
+#define chipMinorFeatures4_UNK27 0x08000000
+#define chipMinorFeatures4_UNK28 0x10000000
+#define chipMinorFeatures4_UNK29 0x20000000
+#define chipMinorFeatures4_UNK30 0x40000000
+#define chipMinorFeatures4_UNK31 0x80000000
+
+#endif /* COMMON_XML */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
new file mode 100644
index 000000000000..332c55ebba6d
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2014 Etnaviv Project
+ * Author: Christian Gmeiner <christian.gmeiner@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_mmu.h"
+
+#include "common.xml.h"
+#include "state.xml.h"
+#include "cmdstream.xml.h"
+
+/*
+ * Command Buffer helper:
+ */
+
+
+static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data)
+{
+ u32 *vaddr = (u32 *)buffer->vaddr;
+
+ BUG_ON(buffer->user_size >= buffer->size);
+
+ vaddr[buffer->user_size / 4] = data;
+ buffer->user_size += 4;
+}
+
+static inline void CMD_LOAD_STATE(struct etnaviv_cmdbuf *buffer,
+ u32 reg, u32 value)
+{
+ u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR;
+
+ buffer->user_size = ALIGN(buffer->user_size, 8);
+
+ /* write a register via cmd stream */
+ OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE |
+ VIV_FE_LOAD_STATE_HEADER_COUNT(1) |
+ VIV_FE_LOAD_STATE_HEADER_OFFSET(index));
+ OUT(buffer, value);
+}
+
+static inline void CMD_END(struct etnaviv_cmdbuf *buffer)
+{
+ buffer->user_size = ALIGN(buffer->user_size, 8);
+
+ OUT(buffer, VIV_FE_END_HEADER_OP_END);
+}
+
+static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer)
+{
+ buffer->user_size = ALIGN(buffer->user_size, 8);
+
+ OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | 200);
+}
+
+static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer,
+ u16 prefetch, u32 address)
+{
+ buffer->user_size = ALIGN(buffer->user_size, 8);
+
+ OUT(buffer, VIV_FE_LINK_HEADER_OP_LINK |
+ VIV_FE_LINK_HEADER_PREFETCH(prefetch));
+ OUT(buffer, address);
+}
+
+static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer,
+ u32 from, u32 to)
+{
+ buffer->user_size = ALIGN(buffer->user_size, 8);
+
+ OUT(buffer, VIV_FE_STALL_HEADER_OP_STALL);
+ OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to));
+}
+
+static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe)
+{
+ u32 flush;
+ u32 stall;
+
+ /*
+ * This assumes that if we're switching to 2D, we're switching
+ * away from 3D, and vice versa. Hence, if we're switching to
+ * the 2D core, we need to flush the 3D depth and color caches,
+ * otherwise we need to flush the 2D pixel engine cache.
+ */
+ if (pipe == ETNA_PIPE_2D)
+ flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR;
+ else
+ flush = VIVS_GL_FLUSH_CACHE_PE2D;
+
+ stall = VIVS_GL_SEMAPHORE_TOKEN_FROM(SYNC_RECIPIENT_FE) |
+ VIVS_GL_SEMAPHORE_TOKEN_TO(SYNC_RECIPIENT_PE);
+
+ CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush);
+ CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, stall);
+
+ CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+
+ CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT,
+ VIVS_GL_PIPE_SELECT_PIPE(pipe));
+}
+
+static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_cmdbuf *buf)
+{
+ return buf->paddr - gpu->memory_base;
+}
+
+static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
+ struct etnaviv_cmdbuf *buf, u32 off, u32 len)
+{
+ u32 size = buf->size;
+ u32 *ptr = buf->vaddr + off;
+
+ dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
+ ptr, gpu_va(gpu, buf) + off, size - len * 4 - off);
+
+ print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
+ ptr, len * 4, 0);
+}
+
+u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
+{
+ struct etnaviv_cmdbuf *buffer = gpu->buffer;
+
+ /* initialize buffer */
+ buffer->user_size = 0;
+
+ CMD_WAIT(buffer);
+ CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + buffer->user_size - 4);
+
+ return buffer->user_size / 8;
+}
+
+void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
+{
+ struct etnaviv_cmdbuf *buffer = gpu->buffer;
+
+ /* Replace the last WAIT with an END */
+ buffer->user_size -= 16;
+
+ CMD_END(buffer);
+ mb();
+}
+
+void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
+ struct etnaviv_cmdbuf *cmdbuf)
+{
+ struct etnaviv_cmdbuf *buffer = gpu->buffer;
+ u32 *lw = buffer->vaddr + buffer->user_size - 16;
+ u32 back, link_target, link_size, reserve_size, extra_size = 0;
+
+ if (drm_debug & DRM_UT_DRIVER)
+ etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
+
+ /*
+ * If we need to flush the MMU prior to submitting this buffer, we
+ * will need to append a mmu flush load state, followed by a new
+ * link to this buffer - a total of four additional words.
+ */
+ if (gpu->mmu->need_flush || gpu->switch_context) {
+ /* link command */
+ extra_size += 2;
+ /* flush command */
+ if (gpu->mmu->need_flush)
+ extra_size += 2;
+ /* pipe switch commands */
+ if (gpu->switch_context)
+ extra_size += 8;
+ }
+
+ reserve_size = (6 + extra_size) * 4;
+
+ /*
+ * if we are going to completely overflow the buffer, we need to wrap.
+ */
+ if (buffer->user_size + reserve_size > buffer->size)
+ buffer->user_size = 0;
+
+ /* save offset back into main buffer */
+ back = buffer->user_size + reserve_size - 6 * 4;
+ link_target = gpu_va(gpu, buffer) + buffer->user_size;
+ link_size = 6;
+
+ /* Skip over any extra instructions */
+ link_target += extra_size * sizeof(u32);
+
+ if (drm_debug & DRM_UT_DRIVER)
+ pr_info("stream link to 0x%08x @ 0x%08x %p\n",
+ link_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr);
+
+ /* jump back from cmd to main buffer */
+ CMD_LINK(cmdbuf, link_size, link_target);
+
+ link_target = gpu_va(gpu, cmdbuf);
+ link_size = cmdbuf->size / 8;
+
+
+
+ if (drm_debug & DRM_UT_DRIVER) {
+ print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
+ cmdbuf->vaddr, cmdbuf->size, 0);
+
+ pr_info("link op: %p\n", lw);
+ pr_info("link addr: %p\n", lw + 1);
+ pr_info("addr: 0x%08x\n", link_target);
+ pr_info("back: 0x%08x\n", gpu_va(gpu, buffer) + back);
+ pr_info("event: %d\n", event);
+ }
+
+ if (gpu->mmu->need_flush || gpu->switch_context) {
+ u32 new_target = gpu_va(gpu, buffer) + buffer->user_size;
+
+ if (gpu->mmu->need_flush) {
+ /* Add the MMU flush */
+ CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU,
+ VIVS_GL_FLUSH_MMU_FLUSH_FEMMU |
+ VIVS_GL_FLUSH_MMU_FLUSH_UNK1 |
+ VIVS_GL_FLUSH_MMU_FLUSH_UNK2 |
+ VIVS_GL_FLUSH_MMU_FLUSH_PEMMU |
+ VIVS_GL_FLUSH_MMU_FLUSH_UNK4);
+
+ gpu->mmu->need_flush = false;
+ }
+
+ if (gpu->switch_context) {
+ etnaviv_cmd_select_pipe(buffer, cmdbuf->exec_state);
+ gpu->switch_context = false;
+ }
+
+ /* And the link to the first buffer */
+ CMD_LINK(buffer, link_size, link_target);
+
+ /* Update the link target to point to above instructions */
+ link_target = new_target;
+ link_size = extra_size;
+ }
+
+ /* trigger event */
+ CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
+ VIVS_GL_EVENT_FROM_PE);
+
+ /* append WAIT/LINK to main buffer */
+ CMD_WAIT(buffer);
+ CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + (buffer->user_size - 4));
+
+ /* Change WAIT into a LINK command; write the address first. */
+ *(lw + 1) = link_target;
+ mb();
+ *(lw) = VIV_FE_LINK_HEADER_OP_LINK |
+ VIV_FE_LINK_HEADER_PREFETCH(link_size);
+ mb();
+
+ if (drm_debug & DRM_UT_DRIVER)
+ etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c b/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c
new file mode 100644
index 000000000000..dcfd565c88d1
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+
+#include "etnaviv_gem.h"
+#include "etnaviv_gpu.h"
+
+#include "cmdstream.xml.h"
+
+#define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
+
+struct etna_validation_state {
+ struct etnaviv_gpu *gpu;
+ const struct drm_etnaviv_gem_submit_reloc *relocs;
+ unsigned int num_relocs;
+ u32 *start;
+};
+
+static const struct {
+ u16 offset;
+ u16 size;
+} etnaviv_sensitive_states[] __initconst = {
+#define ST(start, num) { (start) >> 2, (num) }
+ /* 2D */
+ ST(0x1200, 1),
+ ST(0x1228, 1),
+ ST(0x1238, 1),
+ ST(0x1284, 1),
+ ST(0x128c, 1),
+ ST(0x1304, 1),
+ ST(0x1310, 1),
+ ST(0x1318, 1),
+ ST(0x12800, 4),
+ ST(0x128a0, 4),
+ ST(0x128c0, 4),
+ ST(0x12970, 4),
+ ST(0x12a00, 8),
+ ST(0x12b40, 8),
+ ST(0x12b80, 8),
+ ST(0x12ce0, 8),
+ /* 3D */
+ ST(0x0644, 1),
+ ST(0x064c, 1),
+ ST(0x0680, 8),
+ ST(0x1410, 1),
+ ST(0x1430, 1),
+ ST(0x1458, 1),
+ ST(0x1460, 8),
+ ST(0x1480, 8),
+ ST(0x1500, 8),
+ ST(0x1520, 8),
+ ST(0x1608, 1),
+ ST(0x1610, 1),
+ ST(0x1658, 1),
+ ST(0x165c, 1),
+ ST(0x1664, 1),
+ ST(0x1668, 1),
+ ST(0x16a4, 1),
+ ST(0x16c0, 8),
+ ST(0x16e0, 8),
+ ST(0x1740, 8),
+ ST(0x2400, 14 * 16),
+ ST(0x10800, 32 * 16),
+#undef ST
+};
+
+#define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
+static DECLARE_BITMAP(etnaviv_states, ETNAVIV_STATES_SIZE);
+
+void __init etnaviv_validate_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(etnaviv_sensitive_states); i++)
+ bitmap_set(etnaviv_states, etnaviv_sensitive_states[i].offset,
+ etnaviv_sensitive_states[i].size);
+}
+
+static void etnaviv_warn_if_non_sensitive(struct etna_validation_state *state,
+ unsigned int buf_offset, unsigned int state_addr)
+{
+ if (state->num_relocs && state->relocs->submit_offset < buf_offset) {
+ dev_warn_once(state->gpu->dev,
+ "%s: relocation for non-sensitive state 0x%x at offset %u\n",
+ __func__, state_addr,
+ state->relocs->submit_offset);
+ while (state->num_relocs &&
+ state->relocs->submit_offset < buf_offset) {
+ state->relocs++;
+ state->num_relocs--;
+ }
+ }
+}
+
+static bool etnaviv_validate_load_state(struct etna_validation_state *state,
+ u32 *ptr, unsigned int state_offset, unsigned int num)
+{
+ unsigned int size = min(ETNAVIV_STATES_SIZE, state_offset + num);
+ unsigned int st_offset = state_offset, buf_offset;
+
+ for_each_set_bit_from(st_offset, etnaviv_states, size) {
+ buf_offset = (ptr - state->start +
+ st_offset - state_offset) * 4;
+
+ etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4);
+ if (state->num_relocs &&
+ state->relocs->submit_offset == buf_offset) {
+ state->relocs++;
+ state->num_relocs--;
+ continue;
+ }
+
+ dev_warn_ratelimited(state->gpu->dev,
+ "%s: load state touches restricted state 0x%x at offset %u\n",
+ __func__, st_offset * 4, buf_offset);
+ return false;
+ }
+
+ if (state->num_relocs) {
+ buf_offset = (ptr - state->start + num) * 4;
+ etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4 +
+ state->relocs->submit_offset -
+ buf_offset);
+ }
+
+ return true;
+}
+
+static uint8_t cmd_length[32] = {
+ [FE_OPCODE_DRAW_PRIMITIVES] = 4,
+ [FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6,
+ [FE_OPCODE_NOP] = 2,
+ [FE_OPCODE_STALL] = 2,
+};
+
+bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, u32 *stream,
+ unsigned int size,
+ struct drm_etnaviv_gem_submit_reloc *relocs,
+ unsigned int reloc_size)
+{
+ struct etna_validation_state state;
+ u32 *buf = stream;
+ u32 *end = buf + size;
+
+ state.gpu = gpu;
+ state.relocs = relocs;
+ state.num_relocs = reloc_size;
+ state.start = stream;
+
+ while (buf < end) {
+ u32 cmd = *buf;
+ unsigned int len, n, off;
+ unsigned int op = cmd >> 27;
+
+ switch (op) {
+ case FE_OPCODE_LOAD_STATE:
+ n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
+ len = ALIGN(1 + n, 2);
+ if (buf + len > end)
+ break;
+
+ off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET);
+ if (!etnaviv_validate_load_state(&state, buf + 1,
+ off, n))
+ return false;
+ break;
+
+ case FE_OPCODE_DRAW_2D:
+ n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT);
+ if (n == 0)
+ n = 256;
+ len = 2 + n * 2;
+ break;
+
+ default:
+ len = cmd_length[op];
+ if (len == 0) {
+ dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
+ __func__, op, buf - state.start);
+ return false;
+ }
+ break;
+ }
+
+ buf += len;
+ }
+
+ if (buf > end) {
+ dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
+ __func__, buf - state.start, size);
+ return false;
+ }
+
+ return true;
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
new file mode 100644
index 000000000000..5c89ebb52fd2
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/component.h>
+#include <linux/of_platform.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_mmu.h"
+#include "etnaviv_gem.h"
+
+#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
+static bool reglog;
+MODULE_PARM_DESC(reglog, "Enable register read/write logging");
+module_param(reglog, bool, 0600);
+#else
+#define reglog 0
+#endif
+
+void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
+ const char *dbgname)
+{
+ struct resource *res;
+ void __iomem *ptr;
+
+ if (name)
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ else
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ ptr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ptr)) {
+ dev_err(&pdev->dev, "failed to ioremap %s: %ld\n", name,
+ PTR_ERR(ptr));
+ return ptr;
+ }
+
+ if (reglog)
+ dev_printk(KERN_DEBUG, &pdev->dev, "IO:region %s 0x%p %08zx\n",
+ dbgname, ptr, (size_t)resource_size(res));
+
+ return ptr;
+}
+
+void etnaviv_writel(u32 data, void __iomem *addr)
+{
+ if (reglog)
+ printk(KERN_DEBUG "IO:W %p %08x\n", addr, data);
+
+ writel(data, addr);
+}
+
+u32 etnaviv_readl(const void __iomem *addr)
+{
+ u32 val = readl(addr);
+
+ if (reglog)
+ printk(KERN_DEBUG "IO:R %p %08x\n", addr, val);
+
+ return val;
+}
+
+/*
+ * DRM operations:
+ */
+
+
+static void load_gpu(struct drm_device *dev)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ unsigned int i;
+
+ for (i = 0; i < ETNA_MAX_PIPES; i++) {
+ struct etnaviv_gpu *g = priv->gpu[i];
+
+ if (g) {
+ int ret;
+
+ ret = etnaviv_gpu_init(g);
+ if (ret) {
+ dev_err(g->dev, "hw init failed: %d\n", ret);
+ priv->gpu[i] = NULL;
+ }
+ }
+ }
+}
+
+static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
+{
+ struct etnaviv_file_private *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ file->driver_priv = ctx;
+
+ return 0;
+}
+
+static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_file_private *ctx = file->driver_priv;
+ unsigned int i;
+
+ for (i = 0; i < ETNA_MAX_PIPES; i++) {
+ struct etnaviv_gpu *gpu = priv->gpu[i];
+
+ if (gpu) {
+ mutex_lock(&gpu->lock);
+ if (gpu->lastctx == ctx)
+ gpu->lastctx = NULL;
+ mutex_unlock(&gpu->lock);
+ }
+ }
+
+ kfree(ctx);
+}
+
+/*
+ * DRM debugfs:
+ */
+
+#ifdef CONFIG_DEBUG_FS
+static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+
+ etnaviv_gem_describe_objects(priv, m);
+
+ return 0;
+}
+
+static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m)
+{
+ int ret;
+
+ read_lock(&dev->vma_offset_manager->vm_lock);
+ ret = drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
+ read_unlock(&dev->vma_offset_manager->vm_lock);
+
+ return ret;
+}
+
+static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+ seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev));
+
+ mutex_lock(&gpu->mmu->lock);
+ drm_mm_dump_table(m, &gpu->mmu->mm);
+ mutex_unlock(&gpu->mmu->lock);
+
+ return 0;
+}
+
+static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+ struct etnaviv_cmdbuf *buf = gpu->buffer;
+ u32 size = buf->size;
+ u32 *ptr = buf->vaddr;
+ u32 i;
+
+ seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
+ buf->vaddr, (u64)buf->paddr, size - buf->user_size);
+
+ for (i = 0; i < size / 4; i++) {
+ if (i && !(i % 4))
+ seq_puts(m, "\n");
+ if (i % 4 == 0)
+ seq_printf(m, "\t0x%p: ", ptr + i);
+ seq_printf(m, "%08x ", *(ptr + i));
+ }
+ seq_puts(m, "\n");
+}
+
+static int etnaviv_ring_show(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+ seq_printf(m, "Ring Buffer (%s): ", dev_name(gpu->dev));
+
+ mutex_lock(&gpu->lock);
+ etnaviv_buffer_dump(gpu, m);
+ mutex_unlock(&gpu->lock);
+
+ return 0;
+}
+
+static int show_unlocked(struct seq_file *m, void *arg)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ int (*show)(struct drm_device *dev, struct seq_file *m) =
+ node->info_ent->data;
+
+ return show(dev, m);
+}
+
+static int show_each_gpu(struct seq_file *m, void *arg)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_gpu *gpu;
+ int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
+ node->info_ent->data;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < ETNA_MAX_PIPES; i++) {
+ gpu = priv->gpu[i];
+ if (!gpu)
+ continue;
+
+ ret = show(gpu, m);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static struct drm_info_list etnaviv_debugfs_list[] = {
+ {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
+ {"gem", show_unlocked, 0, etnaviv_gem_show},
+ { "mm", show_unlocked, 0, etnaviv_mm_show },
+ {"mmu", show_each_gpu, 0, etnaviv_mmu_show},
+ {"ring", show_each_gpu, 0, etnaviv_ring_show},
+};
+
+static int etnaviv_debugfs_init(struct drm_minor *minor)
+{
+ struct drm_device *dev = minor->dev;
+ int ret;
+
+ ret = drm_debugfs_create_files(etnaviv_debugfs_list,
+ ARRAY_SIZE(etnaviv_debugfs_list),
+ minor->debugfs_root, minor);
+
+ if (ret) {
+ dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static void etnaviv_debugfs_cleanup(struct drm_minor *minor)
+{
+ drm_debugfs_remove_files(etnaviv_debugfs_list,
+ ARRAY_SIZE(etnaviv_debugfs_list), minor);
+}
+#endif
+
+/*
+ * DRM ioctls:
+ */
+
+static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct drm_etnaviv_param *args = data;
+ struct etnaviv_gpu *gpu;
+
+ if (args->pipe >= ETNA_MAX_PIPES)
+ return -EINVAL;
+
+ gpu = priv->gpu[args->pipe];
+ if (!gpu)
+ return -ENXIO;
+
+ return etnaviv_gpu_get_param(gpu, args->param, &args->value);
+}
+
+static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_etnaviv_gem_new *args = data;
+
+ if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED |
+ ETNA_BO_FORCE_MMU))
+ return -EINVAL;
+
+ return etnaviv_gem_new_handle(dev, file, args->size,
+ args->flags, &args->handle);
+}
+
+#define TS(t) ((struct timespec){ \
+ .tv_sec = (t).tv_sec, \
+ .tv_nsec = (t).tv_nsec \
+})
+
+static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_etnaviv_gem_cpu_prep *args = data;
+ struct drm_gem_object *obj;
+ int ret;
+
+ if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
+ return -EINVAL;
+
+ obj = drm_gem_object_lookup(dev, file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
+
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_etnaviv_gem_cpu_fini *args = data;
+ struct drm_gem_object *obj;
+ int ret;
+
+ if (args->flags)
+ return -EINVAL;
+
+ obj = drm_gem_object_lookup(dev, file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ ret = etnaviv_gem_cpu_fini(obj);
+
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_etnaviv_gem_info *args = data;
+ struct drm_gem_object *obj;
+ int ret;
+
+ if (args->pad)
+ return -EINVAL;
+
+ obj = drm_gem_object_lookup(dev, file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ ret = etnaviv_gem_mmap_offset(obj, &args->offset);
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_etnaviv_wait_fence *args = data;
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct timespec *timeout = &TS(args->timeout);
+ struct etnaviv_gpu *gpu;
+
+ if (args->flags & ~(ETNA_WAIT_NONBLOCK))
+ return -EINVAL;
+
+ if (args->pipe >= ETNA_MAX_PIPES)
+ return -EINVAL;
+
+ gpu = priv->gpu[args->pipe];
+ if (!gpu)
+ return -ENXIO;
+
+ if (args->flags & ETNA_WAIT_NONBLOCK)
+ timeout = NULL;
+
+ return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
+ timeout);
+}
+
+static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_etnaviv_gem_userptr *args = data;
+ int access;
+
+ if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
+ args->flags == 0)
+ return -EINVAL;
+
+ if (offset_in_page(args->user_ptr | args->user_size) ||
+ (uintptr_t)args->user_ptr != args->user_ptr ||
+ (u32)args->user_size != args->user_size ||
+ args->user_ptr & ~PAGE_MASK)
+ return -EINVAL;
+
+ if (args->flags & ETNA_USERPTR_WRITE)
+ access = VERIFY_WRITE;
+ else
+ access = VERIFY_READ;
+
+ if (!access_ok(access, (void __user *)(unsigned long)args->user_ptr,
+ args->user_size))
+ return -EFAULT;
+
+ return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
+ args->user_size, args->flags,
+ &args->handle);
+}
+
+static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct drm_etnaviv_gem_wait *args = data;
+ struct timespec *timeout = &TS(args->timeout);
+ struct drm_gem_object *obj;
+ struct etnaviv_gpu *gpu;
+ int ret;
+
+ if (args->flags & ~(ETNA_WAIT_NONBLOCK))
+ return -EINVAL;
+
+ if (args->pipe >= ETNA_MAX_PIPES)
+ return -EINVAL;
+
+ gpu = priv->gpu[args->pipe];
+ if (!gpu)
+ return -ENXIO;
+
+ obj = drm_gem_object_lookup(dev, file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ if (args->flags & ETNA_WAIT_NONBLOCK)
+ timeout = NULL;
+
+ ret = etnaviv_gem_wait_bo(gpu, obj, timeout);
+
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+static const struct drm_ioctl_desc etnaviv_ioctls[] = {
+#define ETNA_IOCTL(n, func, flags) \
+ DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
+ ETNA_IOCTL(GET_PARAM, get_param, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_NEW, gem_new, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_INFO, gem_info, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_AUTH|DRM_RENDER_ALLOW),
+ ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_AUTH|DRM_RENDER_ALLOW),
+};
+
+static const struct vm_operations_struct vm_ops = {
+ .fault = etnaviv_gem_fault,
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = no_llseek,
+ .mmap = etnaviv_gem_mmap,
+};
+
+static struct drm_driver etnaviv_drm_driver = {
+ .driver_features = DRIVER_HAVE_IRQ |
+ DRIVER_GEM |
+ DRIVER_PRIME |
+ DRIVER_RENDER,
+ .open = etnaviv_open,
+ .preclose = etnaviv_preclose,
+ .set_busid = drm_platform_set_busid,
+ .gem_free_object = etnaviv_gem_free_object,
+ .gem_vm_ops = &vm_ops,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_pin = etnaviv_gem_prime_pin,
+ .gem_prime_unpin = etnaviv_gem_prime_unpin,
+ .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table,
+ .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
+ .gem_prime_vmap = etnaviv_gem_prime_vmap,
+ .gem_prime_vunmap = etnaviv_gem_prime_vunmap,
+#ifdef CONFIG_DEBUG_FS
+ .debugfs_init = etnaviv_debugfs_init,
+ .debugfs_cleanup = etnaviv_debugfs_cleanup,
+#endif
+ .ioctls = etnaviv_ioctls,
+ .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS,
+ .fops = &fops,
+ .name = "etnaviv",
+ .desc = "etnaviv DRM",
+ .date = "20151214",
+ .major = 1,
+ .minor = 0,
+};
+
+/*
+ * Platform driver:
+ */
+static int etnaviv_bind(struct device *dev)
+{
+ struct etnaviv_drm_private *priv;
+ struct drm_device *drm;
+ int ret;
+
+ drm = drm_dev_alloc(&etnaviv_drm_driver, dev);
+ if (!drm)
+ return -ENOMEM;
+
+ drm->platformdev = to_platform_device(dev);
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "failed to allocate private data\n");
+ ret = -ENOMEM;
+ goto out_unref;
+ }
+ drm->dev_private = priv;
+
+ priv->wq = alloc_ordered_workqueue("etnaviv", 0);
+ if (!priv->wq) {
+ ret = -ENOMEM;
+ goto out_wq;
+ }
+
+ mutex_init(&priv->gem_lock);
+ INIT_LIST_HEAD(&priv->gem_list);
+ priv->num_gpus = 0;
+
+ dev_set_drvdata(dev, drm);
+
+ ret = component_bind_all(dev, drm);
+ if (ret < 0)
+ goto out_bind;
+
+ load_gpu(drm);
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ goto out_register;
+
+ return 0;
+
+out_register:
+ component_unbind_all(dev, drm);
+out_bind:
+ flush_workqueue(priv->wq);
+ destroy_workqueue(priv->wq);
+out_wq:
+ kfree(priv);
+out_unref:
+ drm_dev_unref(drm);
+
+ return ret;
+}
+
+static void etnaviv_unbind(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct etnaviv_drm_private *priv = drm->dev_private;
+
+ drm_dev_unregister(drm);
+
+ flush_workqueue(priv->wq);
+ destroy_workqueue(priv->wq);
+
+ component_unbind_all(dev, drm);
+
+ drm->dev_private = NULL;
+ kfree(priv);
+
+ drm_put_dev(drm);
+}
+
+static const struct component_master_ops etnaviv_master_ops = {
+ .bind = etnaviv_bind,
+ .unbind = etnaviv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ struct device_node *np = data;
+
+ return dev->of_node == np;
+}
+
+static int compare_str(struct device *dev, void *data)
+{
+ return !strcmp(dev_name(dev), data);
+}
+
+static int etnaviv_pdev_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct component_match *match = NULL;
+
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+ if (node) {
+ struct device_node *core_node;
+ int i;
+
+ for (i = 0; ; i++) {
+ core_node = of_parse_phandle(node, "cores", i);
+ if (!core_node)
+ break;
+
+ component_match_add(&pdev->dev, &match, compare_of,
+ core_node);
+ of_node_put(core_node);
+ }
+ } else if (dev->platform_data) {
+ char **names = dev->platform_data;
+ unsigned i;
+
+ for (i = 0; names[i]; i++)
+ component_match_add(dev, &match, compare_str, names[i]);
+ }
+
+ return component_master_add_with_match(dev, &etnaviv_master_ops, match);
+}
+
+static int etnaviv_pdev_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &etnaviv_master_ops);
+
+ return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+ { .compatible = "fsl,imx-gpu-subsystem" },
+ { .compatible = "marvell,dove-gpu-subsystem" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
+static struct platform_driver etnaviv_platform_driver = {
+ .probe = etnaviv_pdev_probe,
+ .remove = etnaviv_pdev_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "etnaviv",
+ .of_match_table = dt_match,
+ },
+};
+
+static int __init etnaviv_init(void)
+{
+ int ret;
+
+ etnaviv_validate_init();
+
+ ret = platform_driver_register(&etnaviv_gpu_driver);
+ if (ret != 0)
+ return ret;
+
+ ret = platform_driver_register(&etnaviv_platform_driver);
+ if (ret != 0)
+ platform_driver_unregister(&etnaviv_gpu_driver);
+
+ return ret;
+}
+module_init(etnaviv_init);
+
+static void __exit etnaviv_exit(void)
+{
+ platform_driver_unregister(&etnaviv_gpu_driver);
+ platform_driver_unregister(&etnaviv_platform_driver);
+}
+module_exit(etnaviv_exit);
+
+MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
+MODULE_DESCRIPTION("etnaviv DRM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:etnaviv");
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
new file mode 100644
index 000000000000..d6bd438bd5be
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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/>.
+ */
+
+#ifndef __ETNAVIV_DRV_H__
+#define __ETNAVIV_DRV_H__
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/iommu.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem.h>
+#include <drm/etnaviv_drm.h>
+
+struct etnaviv_cmdbuf;
+struct etnaviv_gpu;
+struct etnaviv_mmu;
+struct etnaviv_gem_object;
+struct etnaviv_gem_submit;
+
+struct etnaviv_file_private {
+ /* currently we don't do anything useful with this.. but when
+ * per-context address spaces are supported we'd keep track of
+ * the context's page-tables here.
+ */
+ int dummy;
+};
+
+struct etnaviv_drm_private {
+ int num_gpus;
+ struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
+
+ /* list of GEM objects: */
+ struct mutex gem_lock;
+ struct list_head gem_list;
+
+ struct workqueue_struct *wq;
+};
+
+static inline void etnaviv_queue_work(struct drm_device *dev,
+ struct work_struct *w)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+
+ queue_work(priv->wq, w);
+}
+
+int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
+ struct drm_file *file);
+
+int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset);
+int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu,
+ struct drm_gem_object *obj, u32 *iova);
+void etnaviv_gem_put_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj);
+struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj);
+void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj);
+void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
+ struct dma_buf_attachment *attach, struct sg_table *sg);
+int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
+void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
+void *etnaviv_gem_vaddr(struct drm_gem_object *obj);
+int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
+ struct timespec *timeout);
+int etnaviv_gem_cpu_fini(struct drm_gem_object *obj);
+void etnaviv_gem_free_object(struct drm_gem_object *obj);
+int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
+ u32 size, u32 flags, u32 *handle);
+struct drm_gem_object *etnaviv_gem_new_locked(struct drm_device *dev,
+ u32 size, u32 flags);
+struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
+ u32 size, u32 flags);
+int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
+ uintptr_t ptr, u32 size, u32 flags, u32 *handle);
+u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
+void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
+void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
+ struct etnaviv_cmdbuf *cmdbuf);
+void etnaviv_validate_init(void);
+bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
+ u32 *stream, unsigned int size,
+ struct drm_etnaviv_gem_submit_reloc *relocs, unsigned int reloc_size);
+
+#ifdef CONFIG_DEBUG_FS
+void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
+ struct seq_file *m);
+#endif
+
+void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name,
+ const char *dbgname);
+void etnaviv_writel(u32 data, void __iomem *addr);
+u32 etnaviv_readl(const void __iomem *addr);
+
+#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
+#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
+
+/*
+ * Return the storage size of a structure with a variable length array.
+ * The array is nelem elements of elem_size, where the base structure
+ * is defined by base. If the size overflows size_t, return zero.
+ */
+static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base)
+{
+ if (elem_size && nelem > (SIZE_MAX - base) / elem_size)
+ return 0;
+ return base + nelem * elem_size;
+}
+
+/* returns true if fence a comes after fence b */
+static inline bool fence_after(u32 a, u32 b)
+{
+ return (s32)(a - b) > 0;
+}
+
+static inline bool fence_after_eq(u32 a, u32 b)
+{
+ return (s32)(a - b) >= 0;
+}
+
+static inline unsigned long etnaviv_timeout_to_jiffies(
+ const struct timespec *timeout)
+{
+ unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
+ unsigned long start_jiffies = jiffies;
+ unsigned long remaining_jiffies;
+
+ if (time_after(start_jiffies, timeout_jiffies))
+ remaining_jiffies = 0;
+ else
+ remaining_jiffies = timeout_jiffies - start_jiffies;
+
+ return remaining_jiffies;
+}
+
+#endif /* __ETNAVIV_DRV_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
new file mode 100644
index 000000000000..bf8fa859e8be
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/devcoredump.h>
+#include "etnaviv_dump.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_mmu.h"
+#include "state.xml.h"
+#include "state_hi.xml.h"
+
+struct core_dump_iterator {
+ void *start;
+ struct etnaviv_dump_object_header *hdr;
+ void *data;
+};
+
+static const unsigned short etnaviv_dump_registers[] = {
+ VIVS_HI_AXI_STATUS,
+ VIVS_HI_CLOCK_CONTROL,
+ VIVS_HI_IDLE_STATE,
+ VIVS_HI_AXI_CONFIG,
+ VIVS_HI_INTR_ENBL,
+ VIVS_HI_CHIP_IDENTITY,
+ VIVS_HI_CHIP_FEATURE,
+ VIVS_HI_CHIP_MODEL,
+ VIVS_HI_CHIP_REV,
+ VIVS_HI_CHIP_DATE,
+ VIVS_HI_CHIP_TIME,
+ VIVS_HI_CHIP_MINOR_FEATURE_0,
+ VIVS_HI_CACHE_CONTROL,
+ VIVS_HI_AXI_CONTROL,
+ VIVS_PM_POWER_CONTROLS,
+ VIVS_PM_MODULE_CONTROLS,
+ VIVS_PM_MODULE_STATUS,
+ VIVS_PM_PULSE_EATER,
+ VIVS_MC_MMU_FE_PAGE_TABLE,
+ VIVS_MC_MMU_TX_PAGE_TABLE,
+ VIVS_MC_MMU_PE_PAGE_TABLE,
+ VIVS_MC_MMU_PEZ_PAGE_TABLE,
+ VIVS_MC_MMU_RA_PAGE_TABLE,
+ VIVS_MC_DEBUG_MEMORY,
+ VIVS_MC_MEMORY_BASE_ADDR_RA,
+ VIVS_MC_MEMORY_BASE_ADDR_FE,
+ VIVS_MC_MEMORY_BASE_ADDR_TX,
+ VIVS_MC_MEMORY_BASE_ADDR_PEZ,
+ VIVS_MC_MEMORY_BASE_ADDR_PE,
+ VIVS_MC_MEMORY_TIMING_CONTROL,
+ VIVS_MC_BUS_CONFIG,
+ VIVS_FE_DMA_STATUS,
+ VIVS_FE_DMA_DEBUG_STATE,
+ VIVS_FE_DMA_ADDRESS,
+ VIVS_FE_DMA_LOW,
+ VIVS_FE_DMA_HIGH,
+ VIVS_FE_AUTO_FLUSH,
+};
+
+static void etnaviv_core_dump_header(struct core_dump_iterator *iter,
+ u32 type, void *data_end)
+{
+ struct etnaviv_dump_object_header *hdr = iter->hdr;
+
+ hdr->magic = cpu_to_le32(ETDUMP_MAGIC);
+ hdr->type = cpu_to_le32(type);
+ hdr->file_offset = cpu_to_le32(iter->data - iter->start);
+ hdr->file_size = cpu_to_le32(data_end - iter->data);
+
+ iter->hdr++;
+ iter->data += hdr->file_size;
+}
+
+static void etnaviv_core_dump_registers(struct core_dump_iterator *iter,
+ struct etnaviv_gpu *gpu)
+{
+ struct etnaviv_dump_registers *reg = iter->data;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) {
+ reg->reg = etnaviv_dump_registers[i];
+ reg->value = gpu_read(gpu, etnaviv_dump_registers[i]);
+ }
+
+ etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg);
+}
+
+static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter,
+ struct etnaviv_gpu *gpu, size_t mmu_size)
+{
+ etnaviv_iommu_dump(gpu->mmu, iter->data);
+
+ etnaviv_core_dump_header(iter, ETDUMP_BUF_MMU, iter->data + mmu_size);
+}
+
+static void etnaviv_core_dump_mem(struct core_dump_iterator *iter, u32 type,
+ void *ptr, size_t size, u64 iova)
+{
+ memcpy(iter->data, ptr, size);
+
+ iter->hdr->iova = cpu_to_le64(iova);
+
+ etnaviv_core_dump_header(iter, type, iter->data + size);
+}
+
+void etnaviv_core_dump(struct etnaviv_gpu *gpu)
+{
+ struct core_dump_iterator iter;
+ struct etnaviv_vram_mapping *vram;
+ struct etnaviv_gem_object *obj;
+ struct etnaviv_cmdbuf *cmd;
+ unsigned int n_obj, n_bomap_pages;
+ size_t file_size, mmu_size;
+ __le64 *bomap, *bomap_start;
+
+ mmu_size = etnaviv_iommu_dump_size(gpu->mmu);
+
+ /* We always dump registers, mmu, ring and end marker */
+ n_obj = 4;
+ n_bomap_pages = 0;
+ file_size = ARRAY_SIZE(etnaviv_dump_registers) *
+ sizeof(struct etnaviv_dump_registers) +
+ mmu_size + gpu->buffer->size;
+
+ /* Add in the active command buffers */
+ list_for_each_entry(cmd, &gpu->active_cmd_list, node) {
+ file_size += cmd->size;
+ n_obj++;
+ }
+
+ /* Add in the active buffer objects */
+ list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
+ if (!vram->use)
+ continue;
+
+ obj = vram->object;
+ file_size += obj->base.size;
+ n_bomap_pages += obj->base.size >> PAGE_SHIFT;
+ n_obj++;
+ }
+
+ /* If we have any buffer objects, add a bomap object */
+ if (n_bomap_pages) {
+ file_size += n_bomap_pages * sizeof(__le64);
+ n_obj++;
+ }
+
+ /* Add the size of the headers */
+ file_size += sizeof(*iter.hdr) * n_obj;
+
+ /* Allocate the file in vmalloc memory, it's likely to be big */
+ iter.start = vmalloc(file_size);
+ if (!iter.start) {
+ dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
+ return;
+ }
+
+ /* Point the data member after the headers */
+ iter.hdr = iter.start;
+ iter.data = &iter.hdr[n_obj];
+
+ memset(iter.hdr, 0, iter.data - iter.start);
+
+ etnaviv_core_dump_registers(&iter, gpu);
+ etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
+ etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
+ gpu->buffer->size, gpu->buffer->paddr);
+
+ list_for_each_entry(cmd, &gpu->active_cmd_list, node)
+ etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
+ cmd->size, cmd->paddr);
+
+ /* Reserve space for the bomap */
+ if (n_bomap_pages) {
+ bomap_start = bomap = iter.data;
+ memset(bomap, 0, sizeof(*bomap) * n_bomap_pages);
+ etnaviv_core_dump_header(&iter, ETDUMP_BUF_BOMAP,
+ bomap + n_bomap_pages);
+ } else {
+ /* Silence warning */
+ bomap_start = bomap = NULL;
+ }
+
+ list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
+ struct page **pages;
+ void *vaddr;
+
+ if (vram->use == 0)
+ continue;
+
+ obj = vram->object;
+
+ pages = etnaviv_gem_get_pages(obj);
+ if (pages) {
+ int j;
+
+ iter.hdr->data[0] = bomap - bomap_start;
+
+ for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++)
+ *bomap++ = cpu_to_le64(page_to_phys(*pages++));
+ }
+
+ iter.hdr->iova = cpu_to_le64(vram->iova);
+
+ vaddr = etnaviv_gem_vaddr(&obj->base);
+ if (vaddr && !IS_ERR(vaddr))
+ memcpy(iter.data, vaddr, obj->base.size);
+
+ etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data +
+ obj->base.size);
+ }
+
+ etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data);
+
+ dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.h b/drivers/gpu/drm/etnaviv/etnaviv_dump.h
new file mode 100644
index 000000000000..97f2f8db9133
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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/>.
+ *
+ * Etnaviv devcoredump file definitions
+ */
+#ifndef ETNAVIV_DUMP_H
+#define ETNAVIV_DUMP_H
+
+#include <linux/types.h>
+
+enum {
+ ETDUMP_MAGIC = 0x414e5445,
+ ETDUMP_BUF_REG = 0,
+ ETDUMP_BUF_MMU,
+ ETDUMP_BUF_RING,
+ ETDUMP_BUF_CMD,
+ ETDUMP_BUF_BOMAP,
+ ETDUMP_BUF_BO,
+ ETDUMP_BUF_END,
+};
+
+struct etnaviv_dump_object_header {
+ __le32 magic;
+ __le32 type;
+ __le32 file_offset;
+ __le32 file_size;
+ __le64 iova;
+ __le32 data[2];
+};
+
+/* Registers object, an array of these */
+struct etnaviv_dump_registers {
+ __le32 reg;
+ __le32 value;
+};
+
+#ifdef __KERNEL__
+struct etnaviv_gpu;
+void etnaviv_core_dump(struct etnaviv_gpu *gpu);
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
new file mode 100644
index 000000000000..9f77c3b94cc6
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -0,0 +1,899 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/shmem_fs.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_mmu.h"
+
+static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
+{
+ struct drm_device *dev = etnaviv_obj->base.dev;
+ struct sg_table *sgt = etnaviv_obj->sgt;
+
+ /*
+ * For non-cached buffers, ensure the new pages are clean
+ * because display controller, GPU, etc. are not coherent.
+ */
+ if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
+ dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+}
+
+static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
+{
+ struct drm_device *dev = etnaviv_obj->base.dev;
+ struct sg_table *sgt = etnaviv_obj->sgt;
+
+ /*
+ * For non-cached buffers, ensure the new pages are clean
+ * because display controller, GPU, etc. are not coherent:
+ *
+ * WARNING: The DMA API does not support concurrent CPU
+ * and device access to the memory area. With BIDIRECTIONAL,
+ * we will clean the cache lines which overlap the region,
+ * and invalidate all cache lines (partially) contained in
+ * the region.
+ *
+ * If you have dirty data in the overlapping cache lines,
+ * that will corrupt the GPU-written data. If you have
+ * written into the remainder of the region, this can
+ * discard those writes.
+ */
+ if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
+ dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+}
+
+/* called with etnaviv_obj->lock held */
+static int etnaviv_gem_shmem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+ struct drm_device *dev = etnaviv_obj->base.dev;
+ struct page **p = drm_gem_get_pages(&etnaviv_obj->base);
+
+ if (IS_ERR(p)) {
+ dev_err(dev->dev, "could not get pages: %ld\n", PTR_ERR(p));
+ return PTR_ERR(p);
+ }
+
+ etnaviv_obj->pages = p;
+
+ return 0;
+}
+
+static void put_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+ if (etnaviv_obj->sgt) {
+ etnaviv_gem_scatterlist_unmap(etnaviv_obj);
+ sg_free_table(etnaviv_obj->sgt);
+ kfree(etnaviv_obj->sgt);
+ etnaviv_obj->sgt = NULL;
+ }
+ if (etnaviv_obj->pages) {
+ drm_gem_put_pages(&etnaviv_obj->base, etnaviv_obj->pages,
+ true, false);
+
+ etnaviv_obj->pages = NULL;
+ }
+}
+
+struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+ int ret;
+
+ lockdep_assert_held(&etnaviv_obj->lock);
+
+ if (!etnaviv_obj->pages) {
+ ret = etnaviv_obj->ops->get_pages(etnaviv_obj);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
+
+ if (!etnaviv_obj->sgt) {
+ struct drm_device *dev = etnaviv_obj->base.dev;
+ int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+ struct sg_table *sgt;
+
+ sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
+ if (IS_ERR(sgt)) {
+ dev_err(dev->dev, "failed to allocate sgt: %ld\n",
+ PTR_ERR(sgt));
+ return ERR_CAST(sgt);
+ }
+
+ etnaviv_obj->sgt = sgt;
+
+ etnaviv_gem_scatter_map(etnaviv_obj);
+ }
+
+ return etnaviv_obj->pages;
+}
+
+void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+ lockdep_assert_held(&etnaviv_obj->lock);
+ /* when we start tracking the pin count, then do something here */
+}
+
+static int etnaviv_gem_mmap_obj(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ pgprot_t vm_page_prot;
+
+ vma->vm_flags &= ~VM_PFNMAP;
+ vma->vm_flags |= VM_MIXEDMAP;
+
+ vm_page_prot = vm_get_page_prot(vma->vm_flags);
+
+ if (etnaviv_obj->flags & ETNA_BO_WC) {
+ vma->vm_page_prot = pgprot_writecombine(vm_page_prot);
+ } else if (etnaviv_obj->flags & ETNA_BO_UNCACHED) {
+ vma->vm_page_prot = pgprot_noncached(vm_page_prot);
+ } else {
+ /*
+ * Shunt off cached objs to shmem file so they have their own
+ * address_space (so unmap_mapping_range does what we want,
+ * in particular in the case of mmap'd dmabufs)
+ */
+ fput(vma->vm_file);
+ get_file(obj->filp);
+ vma->vm_pgoff = 0;
+ vma->vm_file = obj->filp;
+
+ vma->vm_page_prot = vm_page_prot;
+ }
+
+ return 0;
+}
+
+int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct etnaviv_gem_object *obj;
+ int ret;
+
+ ret = drm_gem_mmap(filp, vma);
+ if (ret) {
+ DBG("mmap failed: %d", ret);
+ return ret;
+ }
+
+ obj = to_etnaviv_bo(vma->vm_private_data);
+ return etnaviv_gem_mmap_obj(vma->vm_private_data, vma);
+}
+
+int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct drm_gem_object *obj = vma->vm_private_data;
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ struct page **pages, *page;
+ pgoff_t pgoff;
+ int ret;
+
+ /*
+ * Make sure we don't parallel update on a fault, nor move or remove
+ * something from beneath our feet. Note that vm_insert_page() is
+ * specifically coded to take care of this, so we don't have to.
+ */
+ ret = mutex_lock_interruptible(&etnaviv_obj->lock);
+ if (ret)
+ goto out;
+
+ /* make sure we have pages attached now */
+ pages = etnaviv_gem_get_pages(etnaviv_obj);
+ mutex_unlock(&etnaviv_obj->lock);
+
+ if (IS_ERR(pages)) {
+ ret = PTR_ERR(pages);
+ goto out;
+ }
+
+ /* We don't use vmf->pgoff since that has the fake offset: */
+ pgoff = ((unsigned long)vmf->virtual_address -
+ vma->vm_start) >> PAGE_SHIFT;
+
+ page = pages[pgoff];
+
+ VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
+ page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT);
+
+ ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
+
+out:
+ switch (ret) {
+ case -EAGAIN:
+ case 0:
+ case -ERESTARTSYS:
+ case -EINTR:
+ case -EBUSY:
+ /*
+ * EBUSY is ok: this just means that another thread
+ * already did the job.
+ */
+ return VM_FAULT_NOPAGE;
+ case -ENOMEM:
+ return VM_FAULT_OOM;
+ default:
+ return VM_FAULT_SIGBUS;
+ }
+}
+
+int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset)
+{
+ int ret;
+
+ /* Make it mmapable */
+ ret = drm_gem_create_mmap_offset(obj);
+ if (ret)
+ dev_err(obj->dev->dev, "could not allocate mmap offset\n");
+ else
+ *offset = drm_vma_node_offset_addr(&obj->vma_node);
+
+ return ret;
+}
+
+static struct etnaviv_vram_mapping *
+etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj,
+ struct etnaviv_iommu *mmu)
+{
+ struct etnaviv_vram_mapping *mapping;
+
+ list_for_each_entry(mapping, &obj->vram_list, obj_node) {
+ if (mapping->mmu == mmu)
+ return mapping;
+ }
+
+ return NULL;
+}
+
+int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu,
+ struct drm_gem_object *obj, u32 *iova)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ struct etnaviv_vram_mapping *mapping;
+ struct page **pages;
+ int ret = 0;
+
+ mutex_lock(&etnaviv_obj->lock);
+ mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
+ if (mapping) {
+ /*
+ * Holding the object lock prevents the use count changing
+ * beneath us. If the use count is zero, the MMU might be
+ * reaping this object, so take the lock and re-check that
+ * the MMU owns this mapping to close this race.
+ */
+ if (mapping->use == 0) {
+ mutex_lock(&gpu->mmu->lock);
+ if (mapping->mmu == gpu->mmu)
+ mapping->use += 1;
+ else
+ mapping = NULL;
+ mutex_unlock(&gpu->mmu->lock);
+ if (mapping)
+ goto out;
+ } else {
+ mapping->use += 1;
+ goto out;
+ }
+ }
+
+ pages = etnaviv_gem_get_pages(etnaviv_obj);
+ if (IS_ERR(pages)) {
+ ret = PTR_ERR(pages);
+ goto out;
+ }
+
+ /*
+ * See if we have a reaped vram mapping we can re-use before
+ * allocating a fresh mapping.
+ */
+ mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, NULL);
+ if (!mapping) {
+ mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+ if (!mapping) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&mapping->scan_node);
+ mapping->object = etnaviv_obj;
+ } else {
+ list_del(&mapping->obj_node);
+ }
+
+ mapping->mmu = gpu->mmu;
+ mapping->use = 1;
+
+ ret = etnaviv_iommu_map_gem(gpu->mmu, etnaviv_obj, gpu->memory_base,
+ mapping);
+ if (ret < 0)
+ kfree(mapping);
+ else
+ list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
+
+out:
+ mutex_unlock(&etnaviv_obj->lock);
+
+ if (!ret) {
+ /* Take a reference on the object */
+ drm_gem_object_reference(obj);
+ *iova = mapping->iova;
+ }
+
+ return ret;
+}
+
+void etnaviv_gem_put_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ struct etnaviv_vram_mapping *mapping;
+
+ mutex_lock(&etnaviv_obj->lock);
+ mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu);
+
+ WARN_ON(mapping->use == 0);
+ mapping->use -= 1;
+ mutex_unlock(&etnaviv_obj->lock);
+
+ drm_gem_object_unreference_unlocked(obj);
+}
+
+void *etnaviv_gem_vaddr(struct drm_gem_object *obj)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ mutex_lock(&etnaviv_obj->lock);
+ if (!etnaviv_obj->vaddr) {
+ struct page **pages = etnaviv_gem_get_pages(etnaviv_obj);
+
+ if (IS_ERR(pages))
+ return ERR_CAST(pages);
+
+ etnaviv_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
+ VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+ }
+ mutex_unlock(&etnaviv_obj->lock);
+
+ return etnaviv_obj->vaddr;
+}
+
+static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
+{
+ if (op & ETNA_PREP_READ)
+ return DMA_FROM_DEVICE;
+ else if (op & ETNA_PREP_WRITE)
+ return DMA_TO_DEVICE;
+ else
+ return DMA_BIDIRECTIONAL;
+}
+
+int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
+ struct timespec *timeout)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ struct drm_device *dev = obj->dev;
+ bool write = !!(op & ETNA_PREP_WRITE);
+ int ret;
+
+ if (op & ETNA_PREP_NOSYNC) {
+ if (!reservation_object_test_signaled_rcu(etnaviv_obj->resv,
+ write))
+ return -EBUSY;
+ } else {
+ unsigned long remain = etnaviv_timeout_to_jiffies(timeout);
+
+ ret = reservation_object_wait_timeout_rcu(etnaviv_obj->resv,
+ write, true, remain);
+ if (ret <= 0)
+ return ret == 0 ? -ETIMEDOUT : ret;
+ }
+
+ if (etnaviv_obj->flags & ETNA_BO_CACHED) {
+ if (!etnaviv_obj->sgt) {
+ void *ret;
+
+ mutex_lock(&etnaviv_obj->lock);
+ ret = etnaviv_gem_get_pages(etnaviv_obj);
+ mutex_unlock(&etnaviv_obj->lock);
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ }
+
+ dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
+ etnaviv_obj->sgt->nents,
+ etnaviv_op_to_dma_dir(op));
+ etnaviv_obj->last_cpu_prep_op = op;
+ }
+
+ return 0;
+}
+
+int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ if (etnaviv_obj->flags & ETNA_BO_CACHED) {
+ /* fini without a prep is almost certainly a userspace error */
+ WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
+ dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
+ etnaviv_obj->sgt->nents,
+ etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
+ etnaviv_obj->last_cpu_prep_op = 0;
+ }
+
+ return 0;
+}
+
+int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+ struct timespec *timeout)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void etnaviv_gem_describe_fence(struct fence *fence,
+ const char *type, struct seq_file *m)
+{
+ if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags))
+ seq_printf(m, "\t%9s: %s %s seq %u\n",
+ type,
+ fence->ops->get_driver_name(fence),
+ fence->ops->get_timeline_name(fence),
+ fence->seqno);
+}
+
+static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ struct reservation_object *robj = etnaviv_obj->resv;
+ struct reservation_object_list *fobj;
+ struct fence *fence;
+ unsigned long off = drm_vma_node_start(&obj->vma_node);
+
+ seq_printf(m, "%08x: %c %2d (%2d) %08lx %p %zd\n",
+ etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
+ obj->name, obj->refcount.refcount.counter,
+ off, etnaviv_obj->vaddr, obj->size);
+
+ rcu_read_lock();
+ fobj = rcu_dereference(robj->fence);
+ if (fobj) {
+ unsigned int i, shared_count = fobj->shared_count;
+
+ for (i = 0; i < shared_count; i++) {
+ fence = rcu_dereference(fobj->shared[i]);
+ etnaviv_gem_describe_fence(fence, "Shared", m);
+ }
+ }
+
+ fence = rcu_dereference(robj->fence_excl);
+ if (fence)
+ etnaviv_gem_describe_fence(fence, "Exclusive", m);
+ rcu_read_unlock();
+}
+
+void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
+ struct seq_file *m)
+{
+ struct etnaviv_gem_object *etnaviv_obj;
+ int count = 0;
+ size_t size = 0;
+
+ mutex_lock(&priv->gem_lock);
+ list_for_each_entry(etnaviv_obj, &priv->gem_list, gem_node) {
+ struct drm_gem_object *obj = &etnaviv_obj->base;
+
+ seq_puts(m, " ");
+ etnaviv_gem_describe(obj, m);
+ count++;
+ size += obj->size;
+ }
+ mutex_unlock(&priv->gem_lock);
+
+ seq_printf(m, "Total %d objects, %zu bytes\n", count, size);
+}
+#endif
+
+static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
+{
+ if (etnaviv_obj->vaddr)
+ vunmap(etnaviv_obj->vaddr);
+ put_pages(etnaviv_obj);
+}
+
+static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
+ .get_pages = etnaviv_gem_shmem_get_pages,
+ .release = etnaviv_gem_shmem_release,
+};
+
+void etnaviv_gem_free_object(struct drm_gem_object *obj)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+ struct etnaviv_vram_mapping *mapping, *tmp;
+
+ /* object should not be active */
+ WARN_ON(is_active(etnaviv_obj));
+
+ list_del(&etnaviv_obj->gem_node);
+
+ list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
+ obj_node) {
+ struct etnaviv_iommu *mmu = mapping->mmu;
+
+ WARN_ON(mapping->use);
+
+ if (mmu)
+ etnaviv_iommu_unmap_gem(mmu, mapping);
+
+ list_del(&mapping->obj_node);
+ kfree(mapping);
+ }
+
+ drm_gem_free_mmap_offset(obj);
+ etnaviv_obj->ops->release(etnaviv_obj);
+ if (etnaviv_obj->resv == &etnaviv_obj->_resv)
+ reservation_object_fini(&etnaviv_obj->_resv);
+ drm_gem_object_release(obj);
+
+ kfree(etnaviv_obj);
+}
+
+int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ mutex_lock(&priv->gem_lock);
+ list_add_tail(&etnaviv_obj->gem_node, &priv->gem_list);
+ mutex_unlock(&priv->gem_lock);
+
+ return 0;
+}
+
+static int etnaviv_gem_new_impl(struct drm_device *dev, u32 size, u32 flags,
+ struct reservation_object *robj, const struct etnaviv_gem_ops *ops,
+ struct drm_gem_object **obj)
+{
+ struct etnaviv_gem_object *etnaviv_obj;
+ unsigned sz = sizeof(*etnaviv_obj);
+ bool valid = true;
+
+ /* validate flags */
+ switch (flags & ETNA_BO_CACHE_MASK) {
+ case ETNA_BO_UNCACHED:
+ case ETNA_BO_CACHED:
+ case ETNA_BO_WC:
+ break;
+ default:
+ valid = false;
+ }
+
+ if (!valid) {
+ dev_err(dev->dev, "invalid cache flag: %x\n",
+ (flags & ETNA_BO_CACHE_MASK));
+ return -EINVAL;
+ }
+
+ etnaviv_obj = kzalloc(sz, GFP_KERNEL);
+ if (!etnaviv_obj)
+ return -ENOMEM;
+
+ etnaviv_obj->flags = flags;
+ etnaviv_obj->ops = ops;
+ if (robj) {
+ etnaviv_obj->resv = robj;
+ } else {
+ etnaviv_obj->resv = &etnaviv_obj->_resv;
+ reservation_object_init(&etnaviv_obj->_resv);
+ }
+
+ mutex_init(&etnaviv_obj->lock);
+ INIT_LIST_HEAD(&etnaviv_obj->vram_list);
+
+ *obj = &etnaviv_obj->base;
+
+ return 0;
+}
+
+static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
+ u32 size, u32 flags)
+{
+ struct drm_gem_object *obj = NULL;
+ int ret;
+
+ size = PAGE_ALIGN(size);
+
+ ret = etnaviv_gem_new_impl(dev, size, flags, NULL,
+ &etnaviv_gem_shmem_ops, &obj);
+ if (ret)
+ goto fail;
+
+ ret = drm_gem_object_init(dev, obj, size);
+ if (ret == 0) {
+ struct address_space *mapping;
+
+ /*
+ * Our buffers are kept pinned, so allocating them
+ * from the MOVABLE zone is a really bad idea, and
+ * conflicts with CMA. See coments above new_inode()
+ * why this is required _and_ expected if you're
+ * going to pin these pages.
+ */
+ mapping = file_inode(obj->filp)->i_mapping;
+ mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
+ }
+
+ if (ret)
+ goto fail;
+
+ return obj;
+
+fail:
+ if (obj)
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ERR_PTR(ret);
+}
+
+/* convenience method to construct a GEM buffer object, and userspace handle */
+int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
+ u32 size, u32 flags, u32 *handle)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ obj = __etnaviv_gem_new(dev, size, flags);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ ret = etnaviv_gem_obj_add(dev, obj);
+ if (ret < 0) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ret;
+ }
+
+ ret = drm_gem_handle_create(file, obj, handle);
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
+ u32 size, u32 flags)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ obj = __etnaviv_gem_new(dev, size, flags);
+ if (IS_ERR(obj))
+ return obj;
+
+ ret = etnaviv_gem_obj_add(dev, obj);
+ if (ret < 0) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(ret);
+ }
+
+ return obj;
+}
+
+int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
+ struct reservation_object *robj, const struct etnaviv_gem_ops *ops,
+ struct etnaviv_gem_object **res)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ ret = etnaviv_gem_new_impl(dev, size, flags, robj, ops, &obj);
+ if (ret)
+ return ret;
+
+ drm_gem_private_object_init(dev, obj, size);
+
+ *res = to_etnaviv_bo(obj);
+
+ return 0;
+}
+
+struct get_pages_work {
+ struct work_struct work;
+ struct mm_struct *mm;
+ struct task_struct *task;
+ struct etnaviv_gem_object *etnaviv_obj;
+};
+
+static struct page **etnaviv_gem_userptr_do_get_pages(
+ struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct task_struct *task)
+{
+ int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+ struct page **pvec;
+ uintptr_t ptr;
+
+ pvec = drm_malloc_ab(npages, sizeof(struct page *));
+ if (!pvec)
+ return ERR_PTR(-ENOMEM);
+
+ pinned = 0;
+ ptr = etnaviv_obj->userptr.ptr;
+
+ down_read(&mm->mmap_sem);
+ while (pinned < npages) {
+ ret = get_user_pages(task, mm, ptr, npages - pinned,
+ !etnaviv_obj->userptr.ro, 0,
+ pvec + pinned, NULL);
+ if (ret < 0)
+ break;
+
+ ptr += ret * PAGE_SIZE;
+ pinned += ret;
+ }
+ up_read(&mm->mmap_sem);
+
+ if (ret < 0) {
+ release_pages(pvec, pinned, 0);
+ drm_free_large(pvec);
+ return ERR_PTR(ret);
+ }
+
+ return pvec;
+}
+
+static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work)
+{
+ struct get_pages_work *work = container_of(_work, typeof(*work), work);
+ struct etnaviv_gem_object *etnaviv_obj = work->etnaviv_obj;
+ struct page **pvec;
+
+ pvec = etnaviv_gem_userptr_do_get_pages(etnaviv_obj, work->mm, work->task);
+
+ mutex_lock(&etnaviv_obj->lock);
+ if (IS_ERR(pvec)) {
+ etnaviv_obj->userptr.work = ERR_CAST(pvec);
+ } else {
+ etnaviv_obj->userptr.work = NULL;
+ etnaviv_obj->pages = pvec;
+ }
+
+ mutex_unlock(&etnaviv_obj->lock);
+ drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+
+ mmput(work->mm);
+ put_task_struct(work->task);
+ kfree(work);
+}
+
+static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+ struct page **pvec = NULL;
+ struct get_pages_work *work;
+ struct mm_struct *mm;
+ int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+
+ if (etnaviv_obj->userptr.work) {
+ if (IS_ERR(etnaviv_obj->userptr.work)) {
+ ret = PTR_ERR(etnaviv_obj->userptr.work);
+ etnaviv_obj->userptr.work = NULL;
+ } else {
+ ret = -EAGAIN;
+ }
+ return ret;
+ }
+
+ mm = get_task_mm(etnaviv_obj->userptr.task);
+ pinned = 0;
+ if (mm == current->mm) {
+ pvec = drm_malloc_ab(npages, sizeof(struct page *));
+ if (!pvec) {
+ mmput(mm);
+ return -ENOMEM;
+ }
+
+ pinned = __get_user_pages_fast(etnaviv_obj->userptr.ptr, npages,
+ !etnaviv_obj->userptr.ro, pvec);
+ if (pinned < 0) {
+ drm_free_large(pvec);
+ mmput(mm);
+ return pinned;
+ }
+
+ if (pinned == npages) {
+ etnaviv_obj->pages = pvec;
+ mmput(mm);
+ return 0;
+ }
+ }
+
+ release_pages(pvec, pinned, 0);
+ drm_free_large(pvec);
+
+ work = kmalloc(sizeof(*work), GFP_KERNEL);
+ if (!work) {
+ mmput(mm);
+ return -ENOMEM;
+ }
+
+ get_task_struct(current);
+ drm_gem_object_reference(&etnaviv_obj->base);
+
+ work->mm = mm;
+ work->task = current;
+ work->etnaviv_obj = etnaviv_obj;
+
+ etnaviv_obj->userptr.work = &work->work;
+ INIT_WORK(&work->work, __etnaviv_gem_userptr_get_pages);
+
+ etnaviv_queue_work(etnaviv_obj->base.dev, &work->work);
+
+ return -EAGAIN;
+}
+
+static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj)
+{
+ if (etnaviv_obj->sgt) {
+ etnaviv_gem_scatterlist_unmap(etnaviv_obj);
+ sg_free_table(etnaviv_obj->sgt);
+ kfree(etnaviv_obj->sgt);
+ }
+ if (etnaviv_obj->pages) {
+ int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+
+ release_pages(etnaviv_obj->pages, npages, 0);
+ drm_free_large(etnaviv_obj->pages);
+ }
+ put_task_struct(etnaviv_obj->userptr.task);
+}
+
+static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = {
+ .get_pages = etnaviv_gem_userptr_get_pages,
+ .release = etnaviv_gem_userptr_release,
+};
+
+int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
+ uintptr_t ptr, u32 size, u32 flags, u32 *handle)
+{
+ struct etnaviv_gem_object *etnaviv_obj;
+ int ret;
+
+ ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, NULL,
+ &etnaviv_gem_userptr_ops, &etnaviv_obj);
+ if (ret)
+ return ret;
+
+ etnaviv_obj->userptr.ptr = ptr;
+ etnaviv_obj->userptr.task = current;
+ etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
+ get_task_struct(current);
+
+ ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+ return ret;
+ }
+
+ ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
new file mode 100644
index 000000000000..a300b4b3d545
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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/>.
+ */
+
+#ifndef __ETNAVIV_GEM_H__
+#define __ETNAVIV_GEM_H__
+
+#include <linux/reservation.h>
+#include "etnaviv_drv.h"
+
+struct etnaviv_gem_ops;
+struct etnaviv_gem_object;
+
+struct etnaviv_gem_userptr {
+ uintptr_t ptr;
+ struct task_struct *task;
+ struct work_struct *work;
+ bool ro;
+};
+
+struct etnaviv_vram_mapping {
+ struct list_head obj_node;
+ struct list_head scan_node;
+ struct list_head mmu_node;
+ struct etnaviv_gem_object *object;
+ struct etnaviv_iommu *mmu;
+ struct drm_mm_node vram_node;
+ unsigned int use;
+ u32 iova;
+};
+
+struct etnaviv_gem_object {
+ struct drm_gem_object base;
+ const struct etnaviv_gem_ops *ops;
+ struct mutex lock;
+
+ u32 flags;
+
+ struct list_head gem_node;
+ struct etnaviv_gpu *gpu; /* non-null if active */
+ atomic_t gpu_active;
+ u32 access;
+
+ struct page **pages;
+ struct sg_table *sgt;
+ void *vaddr;
+
+ /* normally (resv == &_resv) except for imported bo's */
+ struct reservation_object *resv;
+ struct reservation_object _resv;
+
+ struct list_head vram_list;
+
+ /* cache maintenance */
+ u32 last_cpu_prep_op;
+
+ struct etnaviv_gem_userptr userptr;
+};
+
+static inline
+struct etnaviv_gem_object *to_etnaviv_bo(struct drm_gem_object *obj)
+{
+ return container_of(obj, struct etnaviv_gem_object, base);
+}
+
+struct etnaviv_gem_ops {
+ int (*get_pages)(struct etnaviv_gem_object *);
+ void (*release)(struct etnaviv_gem_object *);
+};
+
+static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
+{
+ return atomic_read(&etnaviv_obj->gpu_active) != 0;
+}
+
+#define MAX_CMDS 4
+
+/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
+ * associated with the cmdstream submission for synchronization (and
+ * make it easier to unwind when things go wrong, etc). This only
+ * lasts for the duration of the submit-ioctl.
+ */
+struct etnaviv_gem_submit {
+ struct drm_device *dev;
+ struct etnaviv_gpu *gpu;
+ struct ww_acquire_ctx ticket;
+ u32 fence;
+ unsigned int nr_bos;
+ struct {
+ u32 flags;
+ struct etnaviv_gem_object *obj;
+ u32 iova;
+ } bos[0];
+};
+
+int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
+ struct timespec *timeout);
+int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
+ struct reservation_object *robj, const struct etnaviv_gem_ops *ops,
+ struct etnaviv_gem_object **res);
+int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
+struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj);
+void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj);
+
+#endif /* __ETNAVIV_GEM_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
new file mode 100644
index 000000000000..e94db4f95770
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/dma-buf.h>
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+
+
+struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ BUG_ON(!etnaviv_obj->sgt); /* should have already pinned! */
+
+ return etnaviv_obj->sgt;
+}
+
+void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj)
+{
+ return etnaviv_gem_vaddr(obj);
+}
+
+void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+ /* TODO msm_gem_vunmap() */
+}
+
+int etnaviv_gem_prime_pin(struct drm_gem_object *obj)
+{
+ if (!obj->import_attach) {
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ mutex_lock(&etnaviv_obj->lock);
+ etnaviv_gem_get_pages(etnaviv_obj);
+ mutex_unlock(&etnaviv_obj->lock);
+ }
+ return 0;
+}
+
+void etnaviv_gem_prime_unpin(struct drm_gem_object *obj)
+{
+ if (!obj->import_attach) {
+ struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+ mutex_lock(&etnaviv_obj->lock);
+ etnaviv_gem_put_pages(to_etnaviv_bo(obj));
+ mutex_unlock(&etnaviv_obj->lock);
+ }
+}
+
+static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj)
+{
+ if (etnaviv_obj->vaddr)
+ dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf,
+ etnaviv_obj->vaddr);
+
+ /* Don't drop the pages for imported dmabuf, as they are not
+ * ours, just free the array we allocated:
+ */
+ if (etnaviv_obj->pages)
+ drm_free_large(etnaviv_obj->pages);
+
+ drm_prime_gem_destroy(&etnaviv_obj->base, etnaviv_obj->sgt);
+}
+
+static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = {
+ /* .get_pages should never be called */
+ .release = etnaviv_gem_prime_release,
+};
+
+struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
+ struct dma_buf_attachment *attach, struct sg_table *sgt)
+{
+ struct etnaviv_gem_object *etnaviv_obj;
+ size_t size = PAGE_ALIGN(attach->dmabuf->size);
+ int ret, npages;
+
+ ret = etnaviv_gem_new_private(dev, size, ETNA_BO_WC,
+ attach->dmabuf->resv,
+ &etnaviv_gem_prime_ops, &etnaviv_obj);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ npages = size / PAGE_SIZE;
+
+ etnaviv_obj->sgt = sgt;
+ etnaviv_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+ if (!etnaviv_obj->pages) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ ret = drm_prime_sg_to_page_addr_arrays(sgt, etnaviv_obj->pages,
+ NULL, npages);
+ if (ret)
+ goto fail;
+
+ ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
+ if (ret)
+ goto fail;
+
+ return &etnaviv_obj->base;
+
+fail:
+ drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
new file mode 100644
index 000000000000..1aba01a999df
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/reservation.h>
+#include "etnaviv_drv.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
+
+/*
+ * Cmdstream submission:
+ */
+
+#define BO_INVALID_FLAGS ~(ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE)
+/* make sure these don't conflict w/ ETNAVIV_SUBMIT_BO_x */
+#define BO_LOCKED 0x4000
+#define BO_PINNED 0x2000
+
+static inline void __user *to_user_ptr(u64 address)
+{
+ return (void __user *)(uintptr_t)address;
+}
+
+static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
+ struct etnaviv_gpu *gpu, size_t nr)
+{
+ struct etnaviv_gem_submit *submit;
+ size_t sz = size_vstruct(nr, sizeof(submit->bos[0]), sizeof(*submit));
+
+ submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
+ if (submit) {
+ submit->dev = dev;
+ submit->gpu = gpu;
+
+ /* initially, until copy_from_user() and bo lookup succeeds: */
+ submit->nr_bos = 0;
+
+ ww_acquire_init(&submit->ticket, &reservation_ww_class);
+ }
+
+ return submit;
+}
+
+static int submit_lookup_objects(struct etnaviv_gem_submit *submit,
+ struct drm_file *file, struct drm_etnaviv_gem_submit_bo *submit_bos,
+ unsigned nr_bos)
+{
+ struct drm_etnaviv_gem_submit_bo *bo;
+ unsigned i;
+ int ret = 0;
+
+ spin_lock(&file->table_lock);
+
+ for (i = 0, bo = submit_bos; i < nr_bos; i++, bo++) {
+ struct drm_gem_object *obj;
+
+ if (bo->flags & BO_INVALID_FLAGS) {
+ DRM_ERROR("invalid flags: %x\n", bo->flags);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ submit->bos[i].flags = bo->flags;
+
+ /* normally use drm_gem_object_lookup(), but for bulk lookup
+ * all under single table_lock just hit object_idr directly:
+ */
+ obj = idr_find(&file->object_idr, bo->handle);
+ if (!obj) {
+ DRM_ERROR("invalid handle %u at index %u\n",
+ bo->handle, i);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /*
+ * Take a refcount on the object. The file table lock
+ * prevents the object_idr's refcount on this being dropped.
+ */
+ drm_gem_object_reference(obj);
+
+ submit->bos[i].obj = to_etnaviv_bo(obj);
+ }
+
+out_unlock:
+ submit->nr_bos = i;
+ spin_unlock(&file->table_lock);
+
+ return ret;
+}
+
+static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i)
+{
+ if (submit->bos[i].flags & BO_LOCKED) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+ ww_mutex_unlock(&etnaviv_obj->resv->lock);
+ submit->bos[i].flags &= ~BO_LOCKED;
+ }
+}
+
+static int submit_lock_objects(struct etnaviv_gem_submit *submit)
+{
+ int contended, slow_locked = -1, i, ret = 0;
+
+retry:
+ for (i = 0; i < submit->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+ if (slow_locked == i)
+ slow_locked = -1;
+
+ contended = i;
+
+ if (!(submit->bos[i].flags & BO_LOCKED)) {
+ ret = ww_mutex_lock_interruptible(&etnaviv_obj->resv->lock,
+ &submit->ticket);
+ if (ret == -EALREADY)
+ DRM_ERROR("BO at index %u already on submit list\n",
+ i);
+ if (ret)
+ goto fail;
+ submit->bos[i].flags |= BO_LOCKED;
+ }
+ }
+
+ ww_acquire_done(&submit->ticket);
+
+ return 0;
+
+fail:
+ for (; i >= 0; i--)
+ submit_unlock_object(submit, i);
+
+ if (slow_locked > 0)
+ submit_unlock_object(submit, slow_locked);
+
+ if (ret == -EDEADLK) {
+ struct etnaviv_gem_object *etnaviv_obj;
+
+ etnaviv_obj = submit->bos[contended].obj;
+
+ /* we lost out in a seqno race, lock and retry.. */
+ ret = ww_mutex_lock_slow_interruptible(&etnaviv_obj->resv->lock,
+ &submit->ticket);
+ if (!ret) {
+ submit->bos[contended].flags |= BO_LOCKED;
+ slow_locked = contended;
+ goto retry;
+ }
+ }
+
+ return ret;
+}
+
+static int submit_fence_sync(const struct etnaviv_gem_submit *submit)
+{
+ unsigned int context = submit->gpu->fence_context;
+ int i, ret = 0;
+
+ for (i = 0; i < submit->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+ bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE;
+
+ ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static void submit_unpin_objects(struct etnaviv_gem_submit *submit)
+{
+ int i;
+
+ for (i = 0; i < submit->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+ if (submit->bos[i].flags & BO_PINNED)
+ etnaviv_gem_put_iova(submit->gpu, &etnaviv_obj->base);
+
+ submit->bos[i].iova = 0;
+ submit->bos[i].flags &= ~BO_PINNED;
+ }
+}
+
+static int submit_pin_objects(struct etnaviv_gem_submit *submit)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < submit->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+ u32 iova;
+
+ ret = etnaviv_gem_get_iova(submit->gpu, &etnaviv_obj->base,
+ &iova);
+ if (ret)
+ break;
+
+ submit->bos[i].flags |= BO_PINNED;
+ submit->bos[i].iova = iova;
+ }
+
+ return ret;
+}
+
+static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx,
+ struct etnaviv_gem_object **obj, u32 *iova)
+{
+ if (idx >= submit->nr_bos) {
+ DRM_ERROR("invalid buffer index: %u (out of %u)\n",
+ idx, submit->nr_bos);
+ return -EINVAL;
+ }
+
+ if (obj)
+ *obj = submit->bos[idx].obj;
+ if (iova)
+ *iova = submit->bos[idx].iova;
+
+ return 0;
+}
+
+/* process the reloc's and patch up the cmdstream as needed: */
+static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream,
+ u32 size, const struct drm_etnaviv_gem_submit_reloc *relocs,
+ u32 nr_relocs)
+{
+ u32 i, last_offset = 0;
+ u32 *ptr = stream;
+ int ret;
+
+ for (i = 0; i < nr_relocs; i++) {
+ const struct drm_etnaviv_gem_submit_reloc *r = relocs + i;
+ struct etnaviv_gem_object *bobj;
+ u32 iova, off;
+
+ if (unlikely(r->flags)) {
+ DRM_ERROR("invalid reloc flags\n");
+ return -EINVAL;
+ }
+
+ if (r->submit_offset % 4) {
+ DRM_ERROR("non-aligned reloc offset: %u\n",
+ r->submit_offset);
+ return -EINVAL;
+ }
+
+ /* offset in dwords: */
+ off = r->submit_offset / 4;
+
+ if ((off >= size ) ||
+ (off < last_offset)) {
+ DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
+ return -EINVAL;
+ }
+
+ ret = submit_bo(submit, r->reloc_idx, &bobj, &iova);
+ if (ret)
+ return ret;
+
+ if (r->reloc_offset >=
+ bobj->base.size - sizeof(*ptr)) {
+ DRM_ERROR("relocation %u outside object", i);
+ return -EINVAL;
+ }
+
+ ptr[off] = iova + r->reloc_offset;
+
+ last_offset = off;
+ }
+
+ return 0;
+}
+
+static void submit_cleanup(struct etnaviv_gem_submit *submit)
+{
+ unsigned i;
+
+ for (i = 0; i < submit->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+ submit_unlock_object(submit, i);
+ drm_gem_object_unreference_unlocked(&etnaviv_obj->base);
+ }
+
+ ww_acquire_fini(&submit->ticket);
+ kfree(submit);
+}
+
+int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct drm_etnaviv_gem_submit *args = data;
+ struct drm_etnaviv_gem_submit_reloc *relocs;
+ struct drm_etnaviv_gem_submit_bo *bos;
+ struct etnaviv_gem_submit *submit;
+ struct etnaviv_cmdbuf *cmdbuf;
+ struct etnaviv_gpu *gpu;
+ void *stream;
+ int ret;
+
+ if (args->pipe >= ETNA_MAX_PIPES)
+ return -EINVAL;
+
+ gpu = priv->gpu[args->pipe];
+ if (!gpu)
+ return -ENXIO;
+
+ if (args->stream_size % 4) {
+ DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
+ args->stream_size);
+ return -EINVAL;
+ }
+
+ if (args->exec_state != ETNA_PIPE_3D &&
+ args->exec_state != ETNA_PIPE_2D &&
+ args->exec_state != ETNA_PIPE_VG) {
+ DRM_ERROR("invalid exec_state: 0x%x\n", args->exec_state);
+ return -EINVAL;
+ }
+
+ /*
+ * Copy the command submission and bo array to kernel space in
+ * one go, and do this outside of any locks.
+ */
+ bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
+ relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs));
+ stream = drm_malloc_ab(1, args->stream_size);
+ cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8,
+ args->nr_bos);
+ if (!bos || !relocs || !stream || !cmdbuf) {
+ ret = -ENOMEM;
+ goto err_submit_cmds;
+ }
+
+ cmdbuf->exec_state = args->exec_state;
+ cmdbuf->ctx = file->driver_priv;
+
+ ret = copy_from_user(bos, to_user_ptr(args->bos),
+ args->nr_bos * sizeof(*bos));
+ if (ret) {
+ ret = -EFAULT;
+ goto err_submit_cmds;
+ }
+
+ ret = copy_from_user(relocs, to_user_ptr(args->relocs),
+ args->nr_relocs * sizeof(*relocs));
+ if (ret) {
+ ret = -EFAULT;
+ goto err_submit_cmds;
+ }
+
+ ret = copy_from_user(stream, to_user_ptr(args->stream),
+ args->stream_size);
+ if (ret) {
+ ret = -EFAULT;
+ goto err_submit_cmds;
+ }
+
+ submit = submit_create(dev, gpu, args->nr_bos);
+ if (!submit) {
+ ret = -ENOMEM;
+ goto err_submit_cmds;
+ }
+
+ ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
+ if (ret)
+ goto err_submit_objects;
+
+ ret = submit_lock_objects(submit);
+ if (ret)
+ goto err_submit_objects;
+
+ if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4,
+ relocs, args->nr_relocs)) {
+ ret = -EINVAL;
+ goto err_submit_objects;
+ }
+
+ ret = submit_fence_sync(submit);
+ if (ret)
+ goto err_submit_objects;
+
+ ret = submit_pin_objects(submit);
+ if (ret)
+ goto out;
+
+ ret = submit_reloc(submit, stream, args->stream_size / 4,
+ relocs, args->nr_relocs);
+ if (ret)
+ goto out;
+
+ memcpy(cmdbuf->vaddr, stream, args->stream_size);
+ cmdbuf->user_size = ALIGN(args->stream_size, 8);
+
+ ret = etnaviv_gpu_submit(gpu, submit, cmdbuf);
+ if (ret == 0)
+ cmdbuf = NULL;
+
+ args->fence = submit->fence;
+
+out:
+ submit_unpin_objects(submit);
+
+ /*
+ * If we're returning -EAGAIN, it may be due to the userptr code
+ * wanting to run its workqueue outside of any locks. Flush our
+ * workqueue to ensure that it is run in a timely manner.
+ */
+ if (ret == -EAGAIN)
+ flush_workqueue(priv->wq);
+
+err_submit_objects:
+ submit_cleanup(submit);
+
+err_submit_cmds:
+ /* if we still own the cmdbuf */
+ if (cmdbuf)
+ etnaviv_gpu_cmdbuf_free(cmdbuf);
+ if (stream)
+ drm_free_large(stream);
+ if (bos)
+ drm_free_large(bos);
+ if (relocs)
+ drm_free_large(relocs);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
new file mode 100644
index 000000000000..056a72e6ed26
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -0,0 +1,1647 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/component.h>
+#include <linux/fence.h>
+#include <linux/moduleparam.h>
+#include <linux/of_device.h>
+#include "etnaviv_dump.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_mmu.h"
+#include "etnaviv_iommu.h"
+#include "etnaviv_iommu_v2.h"
+#include "common.xml.h"
+#include "state.xml.h"
+#include "state_hi.xml.h"
+#include "cmdstream.xml.h"
+
+static const struct platform_device_id gpu_ids[] = {
+ { .name = "etnaviv-gpu,2d" },
+ { },
+};
+
+static bool etnaviv_dump_core = true;
+module_param_named(dump_core, etnaviv_dump_core, bool, 0600);
+
+/*
+ * Driver functions:
+ */
+
+int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
+{
+ switch (param) {
+ case ETNAVIV_PARAM_GPU_MODEL:
+ *value = gpu->identity.model;
+ break;
+
+ case ETNAVIV_PARAM_GPU_REVISION:
+ *value = gpu->identity.revision;
+ break;
+
+ case ETNAVIV_PARAM_GPU_FEATURES_0:
+ *value = gpu->identity.features;
+ break;
+
+ case ETNAVIV_PARAM_GPU_FEATURES_1:
+ *value = gpu->identity.minor_features0;
+ break;
+
+ case ETNAVIV_PARAM_GPU_FEATURES_2:
+ *value = gpu->identity.minor_features1;
+ break;
+
+ case ETNAVIV_PARAM_GPU_FEATURES_3:
+ *value = gpu->identity.minor_features2;
+ break;
+
+ case ETNAVIV_PARAM_GPU_FEATURES_4:
+ *value = gpu->identity.minor_features3;
+ break;
+
+ case ETNAVIV_PARAM_GPU_STREAM_COUNT:
+ *value = gpu->identity.stream_count;
+ break;
+
+ case ETNAVIV_PARAM_GPU_REGISTER_MAX:
+ *value = gpu->identity.register_max;
+ break;
+
+ case ETNAVIV_PARAM_GPU_THREAD_COUNT:
+ *value = gpu->identity.thread_count;
+ break;
+
+ case ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE:
+ *value = gpu->identity.vertex_cache_size;
+ break;
+
+ case ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT:
+ *value = gpu->identity.shader_core_count;
+ break;
+
+ case ETNAVIV_PARAM_GPU_PIXEL_PIPES:
+ *value = gpu->identity.pixel_pipes;
+ break;
+
+ case ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
+ *value = gpu->identity.vertex_output_buffer_size;
+ break;
+
+ case ETNAVIV_PARAM_GPU_BUFFER_SIZE:
+ *value = gpu->identity.buffer_size;
+ break;
+
+ case ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT:
+ *value = gpu->identity.instruction_count;
+ break;
+
+ case ETNAVIV_PARAM_GPU_NUM_CONSTANTS:
+ *value = gpu->identity.num_constants;
+ break;
+
+ default:
+ DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void etnaviv_hw_specs(struct etnaviv_gpu *gpu)
+{
+ if (gpu->identity.minor_features0 &
+ chipMinorFeatures0_MORE_MINOR_FEATURES) {
+ u32 specs[2];
+
+ specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS);
+ specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2);
+
+ gpu->identity.stream_count =
+ (specs[0] & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
+ >> VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT;
+ gpu->identity.register_max =
+ (specs[0] & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
+ >> VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT;
+ gpu->identity.thread_count =
+ (specs[0] & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
+ >> VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT;
+ gpu->identity.vertex_cache_size =
+ (specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
+ >> VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT;
+ gpu->identity.shader_core_count =
+ (specs[0] & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
+ >> VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT;
+ gpu->identity.pixel_pipes =
+ (specs[0] & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
+ >> VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT;
+ gpu->identity.vertex_output_buffer_size =
+ (specs[0] & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
+ >> VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT;
+
+ gpu->identity.buffer_size =
+ (specs[1] & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
+ >> VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT;
+ gpu->identity.instruction_count =
+ (specs[1] & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
+ >> VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT;
+ gpu->identity.num_constants =
+ (specs[1] & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
+ >> VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT;
+ }
+
+ /* Fill in the stream count if not specified */
+ if (gpu->identity.stream_count == 0) {
+ if (gpu->identity.model >= 0x1000)
+ gpu->identity.stream_count = 4;
+ else
+ gpu->identity.stream_count = 1;
+ }
+
+ /* Convert the register max value */
+ if (gpu->identity.register_max)
+ gpu->identity.register_max = 1 << gpu->identity.register_max;
+ else if (gpu->identity.model == 0x0400)
+ gpu->identity.register_max = 32;
+ else
+ gpu->identity.register_max = 64;
+
+ /* Convert thread count */
+ if (gpu->identity.thread_count)
+ gpu->identity.thread_count = 1 << gpu->identity.thread_count;
+ else if (gpu->identity.model == 0x0400)
+ gpu->identity.thread_count = 64;
+ else if (gpu->identity.model == 0x0500 ||
+ gpu->identity.model == 0x0530)
+ gpu->identity.thread_count = 128;
+ else
+ gpu->identity.thread_count = 256;
+
+ if (gpu->identity.vertex_cache_size == 0)
+ gpu->identity.vertex_cache_size = 8;
+
+ if (gpu->identity.shader_core_count == 0) {
+ if (gpu->identity.model >= 0x1000)
+ gpu->identity.shader_core_count = 2;
+ else
+ gpu->identity.shader_core_count = 1;
+ }
+
+ if (gpu->identity.pixel_pipes == 0)
+ gpu->identity.pixel_pipes = 1;
+
+ /* Convert virtex buffer size */
+ if (gpu->identity.vertex_output_buffer_size) {
+ gpu->identity.vertex_output_buffer_size =
+ 1 << gpu->identity.vertex_output_buffer_size;
+ } else if (gpu->identity.model == 0x0400) {
+ if (gpu->identity.revision < 0x4000)
+ gpu->identity.vertex_output_buffer_size = 512;
+ else if (gpu->identity.revision < 0x4200)
+ gpu->identity.vertex_output_buffer_size = 256;
+ else
+ gpu->identity.vertex_output_buffer_size = 128;
+ } else {
+ gpu->identity.vertex_output_buffer_size = 512;
+ }
+
+ switch (gpu->identity.instruction_count) {
+ case 0:
+ if ((gpu->identity.model == 0x2000 &&
+ gpu->identity.revision == 0x5108) ||
+ gpu->identity.model == 0x880)
+ gpu->identity.instruction_count = 512;
+ else
+ gpu->identity.instruction_count = 256;
+ break;
+
+ case 1:
+ gpu->identity.instruction_count = 1024;
+ break;
+
+ case 2:
+ gpu->identity.instruction_count = 2048;
+ break;
+
+ default:
+ gpu->identity.instruction_count = 256;
+ break;
+ }
+
+ if (gpu->identity.num_constants == 0)
+ gpu->identity.num_constants = 168;
+}
+
+static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
+{
+ u32 chipIdentity;
+
+ chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY);
+
+ /* Special case for older graphic cores. */
+ if (((chipIdentity & VIVS_HI_CHIP_IDENTITY_FAMILY__MASK)
+ >> VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT) == 0x01) {
+ gpu->identity.model = 0x500; /* gc500 */
+ gpu->identity.revision =
+ (chipIdentity & VIVS_HI_CHIP_IDENTITY_REVISION__MASK)
+ >> VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT;
+ } else {
+
+ gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL);
+ gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV);
+
+ /*
+ * !!!! HACK ALERT !!!!
+ * Because people change device IDs without letting software
+ * know about it - here is the hack to make it all look the
+ * same. Only for GC400 family.
+ */
+ if ((gpu->identity.model & 0xff00) == 0x0400 &&
+ gpu->identity.model != 0x0420) {
+ gpu->identity.model = gpu->identity.model & 0x0400;
+ }
+
+ /* Another special case */
+ if (gpu->identity.model == 0x300 &&
+ gpu->identity.revision == 0x2201) {
+ u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE);
+ u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME);
+
+ if (chipDate == 0x20080814 && chipTime == 0x12051100) {
+ /*
+ * This IP has an ECO; put the correct
+ * revision in it.
+ */
+ gpu->identity.revision = 0x1051;
+ }
+ }
+ }
+
+ dev_info(gpu->dev, "model: GC%x, revision: %x\n",
+ gpu->identity.model, gpu->identity.revision);
+
+ gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE);
+
+ /* Disable fast clear on GC700. */
+ if (gpu->identity.model == 0x700)
+ gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
+
+ if ((gpu->identity.model == 0x500 && gpu->identity.revision < 2) ||
+ (gpu->identity.model == 0x300 && gpu->identity.revision < 0x2000)) {
+
+ /*
+ * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these
+ * registers.
+ */
+ gpu->identity.minor_features0 = 0;
+ gpu->identity.minor_features1 = 0;
+ gpu->identity.minor_features2 = 0;
+ gpu->identity.minor_features3 = 0;
+ } else
+ gpu->identity.minor_features0 =
+ gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0);
+
+ if (gpu->identity.minor_features0 &
+ chipMinorFeatures0_MORE_MINOR_FEATURES) {
+ gpu->identity.minor_features1 =
+ gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1);
+ gpu->identity.minor_features2 =
+ gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2);
+ gpu->identity.minor_features3 =
+ gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3);
+ }
+
+ /* GC600 idle register reports zero bits where modules aren't present */
+ if (gpu->identity.model == chipModel_GC600) {
+ gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
+ VIVS_HI_IDLE_STATE_RA |
+ VIVS_HI_IDLE_STATE_SE |
+ VIVS_HI_IDLE_STATE_PA |
+ VIVS_HI_IDLE_STATE_SH |
+ VIVS_HI_IDLE_STATE_PE |
+ VIVS_HI_IDLE_STATE_DE |
+ VIVS_HI_IDLE_STATE_FE;
+ } else {
+ gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP;
+ }
+
+ etnaviv_hw_specs(gpu);
+}
+
+static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock)
+{
+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock |
+ VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD);
+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
+}
+
+static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
+{
+ u32 control, idle;
+ unsigned long timeout;
+ bool failed = true;
+
+ /* TODO
+ *
+ * - clock gating
+ * - puls eater
+ * - what about VG?
+ */
+
+ /* We hope that the GPU resets in under one second */
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ while (time_is_after_jiffies(timeout)) {
+ control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+ VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+ /* enable clock */
+ etnaviv_gpu_load_clock(gpu, control);
+
+ /* Wait for stable clock. Vivante's code waited for 1ms */
+ usleep_range(1000, 10000);
+
+ /* isolate the GPU. */
+ control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+ /* set soft reset. */
+ control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+ /* wait for reset. */
+ msleep(1);
+
+ /* reset soft reset bit. */
+ control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET;
+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+ /* reset GPU isolation. */
+ control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU;
+ gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
+
+ /* read idle register. */
+ idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+ /* try reseting again if FE it not idle */
+ if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) {
+ dev_dbg(gpu->dev, "FE is not idle\n");
+ continue;
+ }
+
+ /* read reset register. */
+ control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
+
+ /* is the GPU idle? */
+ if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) ||
+ ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) {
+ dev_dbg(gpu->dev, "GPU is not idle\n");
+ continue;
+ }
+
+ failed = false;
+ break;
+ }
+
+ if (failed) {
+ idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+ control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
+
+ dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, 2D %sidle\n",
+ idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ",
+ control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ",
+ control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not ");
+
+ return -EBUSY;
+ }
+
+ /* We rely on the GPU running, so program the clock */
+ control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+ VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+ /* enable clock */
+ etnaviv_gpu_load_clock(gpu, control);
+
+ return 0;
+}
+
+static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
+{
+ u16 prefetch;
+
+ if (gpu->identity.model == chipModel_GC320 &&
+ gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400 &&
+ (gpu->identity.revision == 0x5007 ||
+ gpu->identity.revision == 0x5220)) {
+ u32 mc_memory_debug;
+
+ mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff;
+
+ if (gpu->identity.revision == 0x5007)
+ mc_memory_debug |= 0x0c;
+ else
+ mc_memory_debug |= 0x08;
+
+ gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug);
+ }
+
+ /*
+ * Update GPU AXI cache atttribute to "cacheable, no allocate".
+ * This is necessary to prevent the iMX6 SoC locking up.
+ */
+ gpu_write(gpu, VIVS_HI_AXI_CONFIG,
+ VIVS_HI_AXI_CONFIG_AWCACHE(2) |
+ VIVS_HI_AXI_CONFIG_ARCACHE(2));
+
+ /* GC2000 rev 5108 needs a special bus config */
+ if (gpu->identity.model == 0x2000 && gpu->identity.revision == 0x5108) {
+ u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG);
+ bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK |
+ VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK);
+ bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) |
+ VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0);
+ gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
+ }
+
+ /* set base addresses */
+ gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
+ gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
+ gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
+ gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
+ gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
+
+ /* setup the MMU page table pointers */
+ etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain);
+
+ /* Start command processor */
+ prefetch = etnaviv_buffer_init(gpu);
+
+ gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
+ gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS,
+ gpu->buffer->paddr - gpu->memory_base);
+ gpu_write(gpu, VIVS_FE_COMMAND_CONTROL,
+ VIVS_FE_COMMAND_CONTROL_ENABLE |
+ VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
+}
+
+int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
+{
+ int ret, i;
+ struct iommu_domain *iommu;
+ enum etnaviv_iommu_version version;
+ bool mmuv2;
+
+ ret = pm_runtime_get_sync(gpu->dev);
+ if (ret < 0)
+ return ret;
+
+ etnaviv_hw_identify(gpu);
+
+ if (gpu->identity.model == 0) {
+ dev_err(gpu->dev, "Unknown GPU model\n");
+ pm_runtime_put_autosuspend(gpu->dev);
+ return -ENXIO;
+ }
+
+ ret = etnaviv_hw_reset(gpu);
+ if (ret)
+ goto fail;
+
+ /* Setup IOMMU.. eventually we will (I think) do this once per context
+ * and have separate page tables per context. For now, to keep things
+ * simple and to get something working, just use a single address space:
+ */
+ mmuv2 = gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION;
+ dev_dbg(gpu->dev, "mmuv2: %d\n", mmuv2);
+
+ if (!mmuv2) {
+ iommu = etnaviv_iommu_domain_alloc(gpu);
+ version = ETNAVIV_IOMMU_V1;
+ } else {
+ iommu = etnaviv_iommu_v2_domain_alloc(gpu);
+ version = ETNAVIV_IOMMU_V2;
+ }
+
+ if (!iommu) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* TODO: we will leak here memory - fix it! */
+
+ gpu->mmu = etnaviv_iommu_new(gpu, iommu, version);
+ if (!gpu->mmu) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* Create buffer: */
+ gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE, 0);
+ if (!gpu->buffer) {
+ ret = -ENOMEM;
+ dev_err(gpu->dev, "could not create command buffer\n");
+ goto fail;
+ }
+ if (gpu->buffer->paddr - gpu->memory_base > 0x80000000) {
+ ret = -EINVAL;
+ dev_err(gpu->dev,
+ "command buffer outside valid memory window\n");
+ goto free_buffer;
+ }
+
+ /* Setup event management */
+ spin_lock_init(&gpu->event_spinlock);
+ init_completion(&gpu->event_free);
+ for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+ gpu->event[i].used = false;
+ complete(&gpu->event_free);
+ }
+
+ /* Now program the hardware */
+ mutex_lock(&gpu->lock);
+ etnaviv_gpu_hw_init(gpu);
+ mutex_unlock(&gpu->lock);
+
+ pm_runtime_mark_last_busy(gpu->dev);
+ pm_runtime_put_autosuspend(gpu->dev);
+
+ return 0;
+
+free_buffer:
+ etnaviv_gpu_cmdbuf_free(gpu->buffer);
+ gpu->buffer = NULL;
+fail:
+ pm_runtime_mark_last_busy(gpu->dev);
+ pm_runtime_put_autosuspend(gpu->dev);
+
+ return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+struct dma_debug {
+ u32 address[2];
+ u32 state[2];
+};
+
+static void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug)
+{
+ u32 i;
+
+ debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+ debug->state[0] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
+
+ for (i = 0; i < 500; i++) {
+ debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+ debug->state[1] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE);
+
+ if (debug->address[0] != debug->address[1])
+ break;
+
+ if (debug->state[0] != debug->state[1])
+ break;
+ }
+}
+
+int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
+{
+ struct dma_debug debug;
+ u32 dma_lo, dma_hi, axi, idle;
+ int ret;
+
+ seq_printf(m, "%s Status:\n", dev_name(gpu->dev));
+
+ ret = pm_runtime_get_sync(gpu->dev);
+ if (ret < 0)
+ return ret;
+
+ dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW);
+ dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH);
+ axi = gpu_read(gpu, VIVS_HI_AXI_STATUS);
+ idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+ verify_dma(gpu, &debug);
+
+ seq_puts(m, "\tfeatures\n");
+ seq_printf(m, "\t minor_features0: 0x%08x\n",
+ gpu->identity.minor_features0);
+ seq_printf(m, "\t minor_features1: 0x%08x\n",
+ gpu->identity.minor_features1);
+ seq_printf(m, "\t minor_features2: 0x%08x\n",
+ gpu->identity.minor_features2);
+ seq_printf(m, "\t minor_features3: 0x%08x\n",
+ gpu->identity.minor_features3);
+
+ seq_puts(m, "\tspecs\n");
+ seq_printf(m, "\t stream_count: %d\n",
+ gpu->identity.stream_count);
+ seq_printf(m, "\t register_max: %d\n",
+ gpu->identity.register_max);
+ seq_printf(m, "\t thread_count: %d\n",
+ gpu->identity.thread_count);
+ seq_printf(m, "\t vertex_cache_size: %d\n",
+ gpu->identity.vertex_cache_size);
+ seq_printf(m, "\t shader_core_count: %d\n",
+ gpu->identity.shader_core_count);
+ seq_printf(m, "\t pixel_pipes: %d\n",
+ gpu->identity.pixel_pipes);
+ seq_printf(m, "\t vertex_output_buffer_size: %d\n",
+ gpu->identity.vertex_output_buffer_size);
+ seq_printf(m, "\t buffer_size: %d\n",
+ gpu->identity.buffer_size);
+ seq_printf(m, "\t instruction_count: %d\n",
+ gpu->identity.instruction_count);
+ seq_printf(m, "\t num_constants: %d\n",
+ gpu->identity.num_constants);
+
+ seq_printf(m, "\taxi: 0x%08x\n", axi);
+ seq_printf(m, "\tidle: 0x%08x\n", idle);
+ idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP;
+ if ((idle & VIVS_HI_IDLE_STATE_FE) == 0)
+ seq_puts(m, "\t FE is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_DE) == 0)
+ seq_puts(m, "\t DE is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_PE) == 0)
+ seq_puts(m, "\t PE is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_SH) == 0)
+ seq_puts(m, "\t SH is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_PA) == 0)
+ seq_puts(m, "\t PA is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_SE) == 0)
+ seq_puts(m, "\t SE is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_RA) == 0)
+ seq_puts(m, "\t RA is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_TX) == 0)
+ seq_puts(m, "\t TX is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_VG) == 0)
+ seq_puts(m, "\t VG is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_IM) == 0)
+ seq_puts(m, "\t IM is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_FP) == 0)
+ seq_puts(m, "\t FP is not idle\n");
+ if ((idle & VIVS_HI_IDLE_STATE_TS) == 0)
+ seq_puts(m, "\t TS is not idle\n");
+ if (idle & VIVS_HI_IDLE_STATE_AXI_LP)
+ seq_puts(m, "\t AXI low power mode\n");
+
+ if (gpu->identity.features & chipFeatures_DEBUG_MODE) {
+ u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0);
+ u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1);
+ u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE);
+
+ seq_puts(m, "\tMC\n");
+ seq_printf(m, "\t read0: 0x%08x\n", read0);
+ seq_printf(m, "\t read1: 0x%08x\n", read1);
+ seq_printf(m, "\t write: 0x%08x\n", write);
+ }
+
+ seq_puts(m, "\tDMA ");
+
+ if (debug.address[0] == debug.address[1] &&
+ debug.state[0] == debug.state[1]) {
+ seq_puts(m, "seems to be stuck\n");
+ } else if (debug.address[0] == debug.address[1]) {
+ seq_puts(m, "adress is constant\n");
+ } else {
+ seq_puts(m, "is runing\n");
+ }
+
+ seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]);
+ seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]);
+ seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]);
+ seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]);
+ seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n",
+ dma_lo, dma_hi);
+
+ ret = 0;
+
+ pm_runtime_mark_last_busy(gpu->dev);
+ pm_runtime_put_autosuspend(gpu->dev);
+
+ return ret;
+}
+#endif
+
+/*
+ * Power Management:
+ */
+static int enable_clk(struct etnaviv_gpu *gpu)
+{
+ if (gpu->clk_core)
+ clk_prepare_enable(gpu->clk_core);
+ if (gpu->clk_shader)
+ clk_prepare_enable(gpu->clk_shader);
+
+ return 0;
+}
+
+static int disable_clk(struct etnaviv_gpu *gpu)
+{
+ if (gpu->clk_core)
+ clk_disable_unprepare(gpu->clk_core);
+ if (gpu->clk_shader)
+ clk_disable_unprepare(gpu->clk_shader);
+
+ return 0;
+}
+
+static int enable_axi(struct etnaviv_gpu *gpu)
+{
+ if (gpu->clk_bus)
+ clk_prepare_enable(gpu->clk_bus);
+
+ return 0;
+}
+
+static int disable_axi(struct etnaviv_gpu *gpu)
+{
+ if (gpu->clk_bus)
+ clk_disable_unprepare(gpu->clk_bus);
+
+ return 0;
+}
+
+/*
+ * Hangcheck detection for locked gpu:
+ */
+static void recover_worker(struct work_struct *work)
+{
+ struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
+ recover_work);
+ unsigned long flags;
+ unsigned int i;
+
+ dev_err(gpu->dev, "hangcheck recover!\n");
+
+ if (pm_runtime_get_sync(gpu->dev) < 0)
+ return;
+
+ mutex_lock(&gpu->lock);
+
+ /* Only catch the first event, or when manually re-armed */
+ if (etnaviv_dump_core) {
+ etnaviv_core_dump(gpu);
+ etnaviv_dump_core = false;
+ }
+
+ etnaviv_hw_reset(gpu);
+
+ /* complete all events, the GPU won't do it after the reset */
+ spin_lock_irqsave(&gpu->event_spinlock, flags);
+ for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+ if (!gpu->event[i].used)
+ continue;
+ fence_signal(gpu->event[i].fence);
+ gpu->event[i].fence = NULL;
+ gpu->event[i].used = false;
+ complete(&gpu->event_free);
+ /*
+ * Decrement the PM count for each stuck event. This is safe
+ * even in atomic context as we use ASYNC RPM here.
+ */
+ pm_runtime_put_autosuspend(gpu->dev);
+ }
+ spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+ gpu->completed_fence = gpu->active_fence;
+
+ etnaviv_gpu_hw_init(gpu);
+ gpu->switch_context = true;
+
+ mutex_unlock(&gpu->lock);
+ pm_runtime_mark_last_busy(gpu->dev);
+ pm_runtime_put_autosuspend(gpu->dev);
+
+ /* Retire the buffer objects in a work */
+ etnaviv_queue_work(gpu->drm, &gpu->retire_work);
+}
+
+static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
+{
+ DBG("%s", dev_name(gpu->dev));
+ mod_timer(&gpu->hangcheck_timer,
+ round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
+}
+
+static void hangcheck_handler(unsigned long data)
+{
+ struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
+ u32 fence = gpu->completed_fence;
+ bool progress = false;
+
+ if (fence != gpu->hangcheck_fence) {
+ gpu->hangcheck_fence = fence;
+ progress = true;
+ }
+
+ if (!progress) {
+ u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
+ int change = dma_addr - gpu->hangcheck_dma_addr;
+
+ if (change < 0 || change > 16) {
+ gpu->hangcheck_dma_addr = dma_addr;
+ progress = true;
+ }
+ }
+
+ if (!progress && fence_after(gpu->active_fence, fence)) {
+ dev_err(gpu->dev, "hangcheck detected gpu lockup!\n");
+ dev_err(gpu->dev, " completed fence: %u\n", fence);
+ dev_err(gpu->dev, " active fence: %u\n",
+ gpu->active_fence);
+ etnaviv_queue_work(gpu->drm, &gpu->recover_work);
+ }
+
+ /* if still more pending work, reset the hangcheck timer: */
+ if (fence_after(gpu->active_fence, gpu->hangcheck_fence))
+ hangcheck_timer_reset(gpu);
+}
+
+static void hangcheck_disable(struct etnaviv_gpu *gpu)
+{
+ del_timer_sync(&gpu->hangcheck_timer);
+ cancel_work_sync(&gpu->recover_work);
+}
+
+/* fence object management */
+struct etnaviv_fence {
+ struct etnaviv_gpu *gpu;
+ struct fence base;
+};
+
+static inline struct etnaviv_fence *to_etnaviv_fence(struct fence *fence)
+{
+ return container_of(fence, struct etnaviv_fence, base);
+}
+
+static const char *etnaviv_fence_get_driver_name(struct fence *fence)
+{
+ return "etnaviv";
+}
+
+static const char *etnaviv_fence_get_timeline_name(struct fence *fence)
+{
+ struct etnaviv_fence *f = to_etnaviv_fence(fence);
+
+ return dev_name(f->gpu->dev);
+}
+
+static bool etnaviv_fence_enable_signaling(struct fence *fence)
+{
+ return true;
+}
+
+static bool etnaviv_fence_signaled(struct fence *fence)
+{
+ struct etnaviv_fence *f = to_etnaviv_fence(fence);
+
+ return fence_completed(f->gpu, f->base.seqno);
+}
+
+static void etnaviv_fence_release(struct fence *fence)
+{
+ struct etnaviv_fence *f = to_etnaviv_fence(fence);
+
+ kfree_rcu(f, base.rcu);
+}
+
+static const struct fence_ops etnaviv_fence_ops = {
+ .get_driver_name = etnaviv_fence_get_driver_name,
+ .get_timeline_name = etnaviv_fence_get_timeline_name,
+ .enable_signaling = etnaviv_fence_enable_signaling,
+ .signaled = etnaviv_fence_signaled,
+ .wait = fence_default_wait,
+ .release = etnaviv_fence_release,
+};
+
+static struct fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu)
+{
+ struct etnaviv_fence *f;
+
+ f = kzalloc(sizeof(*f), GFP_KERNEL);
+ if (!f)
+ return NULL;
+
+ f->gpu = gpu;
+
+ fence_init(&f->base, &etnaviv_fence_ops, &gpu->fence_spinlock,
+ gpu->fence_context, ++gpu->next_fence);
+
+ return &f->base;
+}
+
+int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
+ unsigned int context, bool exclusive)
+{
+ struct reservation_object *robj = etnaviv_obj->resv;
+ struct reservation_object_list *fobj;
+ struct fence *fence;
+ int i, ret;
+
+ if (!exclusive) {
+ ret = reservation_object_reserve_shared(robj);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * If we have any shared fences, then the exclusive fence
+ * should be ignored as it will already have been signalled.
+ */
+ fobj = reservation_object_get_list(robj);
+ if (!fobj || fobj->shared_count == 0) {
+ /* Wait on any existing exclusive fence which isn't our own */
+ fence = reservation_object_get_excl(robj);
+ if (fence && fence->context != context) {
+ ret = fence_wait(fence, true);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (!exclusive || !fobj)
+ return 0;
+
+ for (i = 0; i < fobj->shared_count; i++) {
+ fence = rcu_dereference_protected(fobj->shared[i],
+ reservation_object_held(robj));
+ if (fence->context != context) {
+ ret = fence_wait(fence, true);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * event management:
+ */
+
+static unsigned int event_alloc(struct etnaviv_gpu *gpu)
+{
+ unsigned long ret, flags;
+ unsigned int i, event = ~0U;
+
+ ret = wait_for_completion_timeout(&gpu->event_free,
+ msecs_to_jiffies(10 * 10000));
+ if (!ret)
+ dev_err(gpu->dev, "wait_for_completion_timeout failed");
+
+ spin_lock_irqsave(&gpu->event_spinlock, flags);
+
+ /* find first free event */
+ for (i = 0; i < ARRAY_SIZE(gpu->event); i++) {
+ if (gpu->event[i].used == false) {
+ gpu->event[i].used = true;
+ event = i;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+
+ return event;
+}
+
+static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpu->event_spinlock, flags);
+
+ if (gpu->event[event].used == false) {
+ dev_warn(gpu->dev, "event %u is already marked as free",
+ event);
+ spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+ } else {
+ gpu->event[event].used = false;
+ spin_unlock_irqrestore(&gpu->event_spinlock, flags);
+
+ complete(&gpu->event_free);
+ }
+}
+
+/*
+ * Cmdstream submission/retirement:
+ */
+
+struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
+ size_t nr_bos)
+{
+ struct etnaviv_cmdbuf *cmdbuf;
+ size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo[0]),
+ sizeof(*cmdbuf));
+
+ cmdbuf = kzalloc(sz, GFP_KERNEL);
+ if (!cmdbuf)
+ return NULL;
+
+ cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr,
+ GFP_KERNEL);
+ if (!cmdbuf->vaddr) {
+ kfree(cmdbuf);
+ return NULL;
+ }
+
+ cmdbuf->gpu = gpu;
+ cmdbuf->size = size;
+
+ return cmdbuf;
+}
+
+void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
+{
+ dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size,
+ cmdbuf->vaddr, cmdbuf->paddr);
+ kfree(cmdbuf);
+}
+
+static void retire_worker(struct work_struct *work)
+{
+ struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
+ retire_work);
+ u32 fence = gpu->completed_fence;
+ struct etnaviv_cmdbuf *cmdbuf, *tmp;
+ unsigned int i;
+
+ mutex_lock(&gpu->lock);
+ list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list, node) {
+ if (!fence_is_signaled(cmdbuf->fence))
+ break;
+
+ list_del(&cmdbuf->node);
+ fence_put(cmdbuf->fence);
+
+ for (i = 0; i < cmdbuf->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = cmdbuf->bo[i];
+
+ atomic_dec(&etnaviv_obj->gpu_active);
+ /* drop the refcount taken in etnaviv_gpu_submit */
+ etnaviv_gem_put_iova(gpu, &etnaviv_obj->base);
+ }
+
+ etnaviv_gpu_cmdbuf_free(cmdbuf);
+ }
+
+ gpu->retired_fence = fence;
+
+ mutex_unlock(&gpu->lock);
+
+ wake_up_all(&gpu->fence_event);
+}
+
+int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
+ u32 fence, struct timespec *timeout)
+{
+ int ret;
+
+ if (fence_after(fence, gpu->next_fence)) {
+ DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
+ fence, gpu->next_fence);
+ return -EINVAL;
+ }
+
+ if (!timeout) {
+ /* No timeout was requested: just test for completion */
+ ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
+ } else {
+ unsigned long remaining = etnaviv_timeout_to_jiffies(timeout);
+
+ ret = wait_event_interruptible_timeout(gpu->fence_event,
+ fence_completed(gpu, fence),
+ remaining);
+ if (ret == 0) {
+ DBG("timeout waiting for fence: %u (retired: %u completed: %u)",
+ fence, gpu->retired_fence,
+ gpu->completed_fence);
+ ret = -ETIMEDOUT;
+ } else if (ret != -ERESTARTSYS) {
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Wait for an object to become inactive. This, on it's own, is not race
+ * free: the object is moved by the retire worker off the active list, and
+ * then the iova is put. Moreover, the object could be re-submitted just
+ * after we notice that it's become inactive.
+ *
+ * Although the retirement happens under the gpu lock, we don't want to hold
+ * that lock in this function while waiting.
+ */
+int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
+ struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
+{
+ unsigned long remaining;
+ long ret;
+
+ if (!timeout)
+ return !is_active(etnaviv_obj) ? 0 : -EBUSY;
+
+ remaining = etnaviv_timeout_to_jiffies(timeout);
+
+ ret = wait_event_interruptible_timeout(gpu->fence_event,
+ !is_active(etnaviv_obj),
+ remaining);
+ if (ret > 0) {
+ struct etnaviv_drm_private *priv = gpu->drm->dev_private;
+
+ /* Synchronise with the retire worker */
+ flush_workqueue(priv->wq);
+ return 0;
+ } else if (ret == -ERESTARTSYS) {
+ return -ERESTARTSYS;
+ } else {
+ return -ETIMEDOUT;
+ }
+}
+
+int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu)
+{
+ return pm_runtime_get_sync(gpu->dev);
+}
+
+void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu)
+{
+ pm_runtime_mark_last_busy(gpu->dev);
+ pm_runtime_put_autosuspend(gpu->dev);
+}
+
+/* add bo's to gpu's ring, and kick gpu: */
+int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
+ struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf)
+{
+ struct fence *fence;
+ unsigned int event, i;
+ int ret;
+
+ ret = etnaviv_gpu_pm_get_sync(gpu);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&gpu->lock);
+
+ /*
+ * TODO
+ *
+ * - flush
+ * - data endian
+ * - prefetch
+ *
+ */
+
+ event = event_alloc(gpu);
+ if (unlikely(event == ~0U)) {
+ DRM_ERROR("no free event\n");
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ fence = etnaviv_gpu_fence_alloc(gpu);
+ if (!fence) {
+ event_free(gpu, event);
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ gpu->event[event].fence = fence;
+ submit->fence = fence->seqno;
+ gpu->active_fence = submit->fence;
+
+ if (gpu->lastctx != cmdbuf->ctx) {
+ gpu->mmu->need_flush = true;
+ gpu->switch_context = true;
+ gpu->lastctx = cmdbuf->ctx;
+ }
+
+ etnaviv_buffer_queue(gpu, event, cmdbuf);
+
+ cmdbuf->fence = fence;
+ list_add_tail(&cmdbuf->node, &gpu->active_cmd_list);
+
+ /* We're committed to adding this command buffer, hold a PM reference */
+ pm_runtime_get_noresume(gpu->dev);
+
+ for (i = 0; i < submit->nr_bos; i++) {
+ struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+ u32 iova;
+
+ /* Each cmdbuf takes a refcount on the iova */
+ etnaviv_gem_get_iova(gpu, &etnaviv_obj->base, &iova);
+ cmdbuf->bo[i] = etnaviv_obj;
+ atomic_inc(&etnaviv_obj->gpu_active);
+
+ if (submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE)
+ reservation_object_add_excl_fence(etnaviv_obj->resv,
+ fence);
+ else
+ reservation_object_add_shared_fence(etnaviv_obj->resv,
+ fence);
+ }
+ cmdbuf->nr_bos = submit->nr_bos;
+ hangcheck_timer_reset(gpu);
+ ret = 0;
+
+out_unlock:
+ mutex_unlock(&gpu->lock);
+
+ etnaviv_gpu_pm_put(gpu);
+
+ return ret;
+}
+
+/*
+ * Init/Cleanup:
+ */
+static irqreturn_t irq_handler(int irq, void *data)
+{
+ struct etnaviv_gpu *gpu = data;
+ irqreturn_t ret = IRQ_NONE;
+
+ u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
+
+ if (intr != 0) {
+ int event;
+
+ pm_runtime_mark_last_busy(gpu->dev);
+
+ dev_dbg(gpu->dev, "intr 0x%08x\n", intr);
+
+ if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) {
+ dev_err(gpu->dev, "AXI bus error\n");
+ intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR;
+ }
+
+ while ((event = ffs(intr)) != 0) {
+ struct fence *fence;
+
+ event -= 1;
+
+ intr &= ~(1 << event);
+
+ dev_dbg(gpu->dev, "event %u\n", event);
+
+ fence = gpu->event[event].fence;
+ gpu->event[event].fence = NULL;
+ fence_signal(fence);
+
+ /*
+ * Events can be processed out of order. Eg,
+ * - allocate and queue event 0
+ * - allocate event 1
+ * - event 0 completes, we process it
+ * - allocate and queue event 0
+ * - event 1 and event 0 complete
+ * we can end up processing event 0 first, then 1.
+ */
+ if (fence_after(fence->seqno, gpu->completed_fence))
+ gpu->completed_fence = fence->seqno;
+
+ event_free(gpu, event);
+
+ /*
+ * We need to balance the runtime PM count caused by
+ * each submission. Upon submission, we increment
+ * the runtime PM counter, and allocate one event.
+ * So here, we put the runtime PM count for each
+ * completed event.
+ */
+ pm_runtime_put_autosuspend(gpu->dev);
+ }
+
+ /* Retire the buffer objects in a work */
+ etnaviv_queue_work(gpu->drm, &gpu->retire_work);
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
+{
+ int ret;
+
+ ret = enable_clk(gpu);
+ if (ret)
+ return ret;
+
+ ret = enable_axi(gpu);
+ if (ret) {
+ disable_clk(gpu);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
+{
+ int ret;
+
+ ret = disable_axi(gpu);
+ if (ret)
+ return ret;
+
+ ret = disable_clk(gpu);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
+{
+ if (gpu->buffer) {
+ unsigned long timeout;
+
+ /* Replace the last WAIT with END */
+ etnaviv_buffer_end(gpu);
+
+ /*
+ * We know that only the FE is busy here, this should
+ * happen quickly (as the WAIT is only 200 cycles). If
+ * we fail, just warn and continue.
+ */
+ timeout = jiffies + msecs_to_jiffies(100);
+ do {
+ u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+ if ((idle & gpu->idle_mask) == gpu->idle_mask)
+ break;
+
+ if (time_is_before_jiffies(timeout)) {
+ dev_warn(gpu->dev,
+ "timed out waiting for idle: idle=0x%x\n",
+ idle);
+ break;
+ }
+
+ udelay(5);
+ } while (1);
+ }
+
+ return etnaviv_gpu_clk_disable(gpu);
+}
+
+#ifdef CONFIG_PM
+static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
+{
+ u32 clock;
+ int ret;
+
+ ret = mutex_lock_killable(&gpu->lock);
+ if (ret)
+ return ret;
+
+ clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
+ VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
+
+ etnaviv_gpu_load_clock(gpu, clock);
+ etnaviv_gpu_hw_init(gpu);
+
+ gpu->switch_context = true;
+
+ mutex_unlock(&gpu->lock);
+
+ return 0;
+}
+#endif
+
+static int etnaviv_gpu_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = data;
+ struct etnaviv_drm_private *priv = drm->dev_private;
+ struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+ int ret;
+
+#ifdef CONFIG_PM
+ ret = pm_runtime_get_sync(gpu->dev);
+#else
+ ret = etnaviv_gpu_clk_enable(gpu);
+#endif
+ if (ret < 0)
+ return ret;
+
+ gpu->drm = drm;
+ gpu->fence_context = fence_context_alloc(1);
+ spin_lock_init(&gpu->fence_spinlock);
+
+ INIT_LIST_HEAD(&gpu->active_cmd_list);
+ INIT_WORK(&gpu->retire_work, retire_worker);
+ INIT_WORK(&gpu->recover_work, recover_worker);
+ init_waitqueue_head(&gpu->fence_event);
+
+ setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
+ (unsigned long)gpu);
+
+ priv->gpu[priv->num_gpus++] = gpu;
+
+ pm_runtime_mark_last_busy(gpu->dev);
+ pm_runtime_put_autosuspend(gpu->dev);
+
+ return 0;
+}
+
+static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+
+ DBG("%s", dev_name(gpu->dev));
+
+ hangcheck_disable(gpu);
+
+#ifdef CONFIG_PM
+ pm_runtime_get_sync(gpu->dev);
+ pm_runtime_put_sync_suspend(gpu->dev);
+#else
+ etnaviv_gpu_hw_suspend(gpu);
+#endif
+
+ if (gpu->buffer) {
+ etnaviv_gpu_cmdbuf_free(gpu->buffer);
+ gpu->buffer = NULL;
+ }
+
+ if (gpu->mmu) {
+ etnaviv_iommu_destroy(gpu->mmu);
+ gpu->mmu = NULL;
+ }
+
+ gpu->drm = NULL;
+}
+
+static const struct component_ops gpu_ops = {
+ .bind = etnaviv_gpu_bind,
+ .unbind = etnaviv_gpu_unbind,
+};
+
+static const struct of_device_id etnaviv_gpu_match[] = {
+ {
+ .compatible = "vivante,gc"
+ },
+ { /* sentinel */ }
+};
+
+static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct etnaviv_gpu *gpu;
+ int err = 0;
+
+ gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
+ if (!gpu)
+ return -ENOMEM;
+
+ gpu->dev = &pdev->dev;
+ mutex_init(&gpu->lock);
+
+ /*
+ * Set the GPU base address to the start of physical memory. This
+ * ensures that if we have up to 2GB, the v1 MMU can address the
+ * highest memory. This is important as command buffers may be
+ * allocated outside of this limit.
+ */
+ gpu->memory_base = PHYS_OFFSET;
+
+ /* Map registers: */
+ gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev));
+ if (IS_ERR(gpu->mmio))
+ return PTR_ERR(gpu->mmio);
+
+ /* Get Interrupt: */
+ gpu->irq = platform_get_irq(pdev, 0);
+ if (gpu->irq < 0) {
+ err = gpu->irq;
+ dev_err(dev, "failed to get irq: %d\n", err);
+ goto fail;
+ }
+
+ err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
+ dev_name(gpu->dev), gpu);
+ if (err) {
+ dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
+ goto fail;
+ }
+
+ /* Get Clocks: */
+ gpu->clk_bus = devm_clk_get(&pdev->dev, "bus");
+ DBG("clk_bus: %p", gpu->clk_bus);
+ if (IS_ERR(gpu->clk_bus))
+ gpu->clk_bus = NULL;
+
+ gpu->clk_core = devm_clk_get(&pdev->dev, "core");
+ DBG("clk_core: %p", gpu->clk_core);
+ if (IS_ERR(gpu->clk_core))
+ gpu->clk_core = NULL;
+
+ gpu->clk_shader = devm_clk_get(&pdev->dev, "shader");
+ DBG("clk_shader: %p", gpu->clk_shader);
+ if (IS_ERR(gpu->clk_shader))
+ gpu->clk_shader = NULL;
+
+ /* TODO: figure out max mapped size */
+ dev_set_drvdata(dev, gpu);
+
+ /*
+ * We treat the device as initially suspended. The runtime PM
+ * autosuspend delay is rather arbitary: no measurements have
+ * yet been performed to determine an appropriate value.
+ */
+ pm_runtime_use_autosuspend(gpu->dev);
+ pm_runtime_set_autosuspend_delay(gpu->dev, 200);
+ pm_runtime_enable(gpu->dev);
+
+ err = component_add(&pdev->dev, &gpu_ops);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to register component: %d\n", err);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return err;
+}
+
+static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &gpu_ops);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int etnaviv_gpu_rpm_suspend(struct device *dev)
+{
+ struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+ u32 idle, mask;
+
+ /* If we have outstanding fences, we're not idle */
+ if (gpu->completed_fence != gpu->active_fence)
+ return -EBUSY;
+
+ /* Check whether the hardware (except FE) is idle */
+ mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE;
+ idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask;
+ if (idle != mask)
+ return -EBUSY;
+
+ return etnaviv_gpu_hw_suspend(gpu);
+}
+
+static int etnaviv_gpu_rpm_resume(struct device *dev)
+{
+ struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+ int ret;
+
+ ret = etnaviv_gpu_clk_enable(gpu);
+ if (ret)
+ return ret;
+
+ /* Re-initialise the basic hardware state */
+ if (gpu->drm && gpu->buffer) {
+ ret = etnaviv_gpu_hw_resume(gpu);
+ if (ret) {
+ etnaviv_gpu_clk_disable(gpu);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume,
+ NULL)
+};
+
+struct platform_driver etnaviv_gpu_driver = {
+ .driver = {
+ .name = "etnaviv-gpu",
+ .owner = THIS_MODULE,
+ .pm = &etnaviv_gpu_pm_ops,
+ .of_match_table = etnaviv_gpu_match,
+ },
+ .probe = etnaviv_gpu_platform_probe,
+ .remove = etnaviv_gpu_platform_remove,
+ .id_table = gpu_ids,
+};
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
new file mode 100644
index 000000000000..c75d50359ab0
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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/>.
+ */
+
+#ifndef __ETNAVIV_GPU_H__
+#define __ETNAVIV_GPU_H__
+
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include "etnaviv_drv.h"
+
+struct etnaviv_gem_submit;
+
+struct etnaviv_chip_identity {
+ /* Chip model. */
+ u32 model;
+
+ /* Revision value.*/
+ u32 revision;
+
+ /* Supported feature fields. */
+ u32 features;
+
+ /* Supported minor feature fields. */
+ u32 minor_features0;
+
+ /* Supported minor feature 1 fields. */
+ u32 minor_features1;
+
+ /* Supported minor feature 2 fields. */
+ u32 minor_features2;
+
+ /* Supported minor feature 3 fields. */
+ u32 minor_features3;
+
+ /* Number of streams supported. */
+ u32 stream_count;
+
+ /* Total number of temporary registers per thread. */
+ u32 register_max;
+
+ /* Maximum number of threads. */
+ u32 thread_count;
+
+ /* Number of shader cores. */
+ u32 shader_core_count;
+
+ /* Size of the vertex cache. */
+ u32 vertex_cache_size;
+
+ /* Number of entries in the vertex output buffer. */
+ u32 vertex_output_buffer_size;
+
+ /* Number of pixel pipes. */
+ u32 pixel_pipes;
+
+ /* Number of instructions. */
+ u32 instruction_count;
+
+ /* Number of constants. */
+ u32 num_constants;
+
+ /* Buffer size */
+ u32 buffer_size;
+};
+
+struct etnaviv_event {
+ bool used;
+ struct fence *fence;
+};
+
+struct etnaviv_cmdbuf;
+
+struct etnaviv_gpu {
+ struct drm_device *drm;
+ struct device *dev;
+ struct mutex lock;
+ struct etnaviv_chip_identity identity;
+ struct etnaviv_file_private *lastctx;
+ bool switch_context;
+
+ /* 'ring'-buffer: */
+ struct etnaviv_cmdbuf *buffer;
+
+ /* bus base address of memory */
+ u32 memory_base;
+
+ /* event management: */
+ struct etnaviv_event event[30];
+ struct completion event_free;
+ spinlock_t event_spinlock;
+
+ /* list of currently in-flight command buffers */
+ struct list_head active_cmd_list;
+
+ u32 idle_mask;
+
+ /* Fencing support */
+ u32 next_fence;
+ u32 active_fence;
+ u32 completed_fence;
+ u32 retired_fence;
+ wait_queue_head_t fence_event;
+ unsigned int fence_context;
+ spinlock_t fence_spinlock;
+
+ /* worker for handling active-list retiring: */
+ struct work_struct retire_work;
+
+ void __iomem *mmio;
+ int irq;
+
+ struct etnaviv_iommu *mmu;
+
+ /* Power Control: */
+ struct clk *clk_bus;
+ struct clk *clk_core;
+ struct clk *clk_shader;
+
+ /* Hang Detction: */
+#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */
+#define DRM_ETNAVIV_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD)
+ struct timer_list hangcheck_timer;
+ u32 hangcheck_fence;
+ u32 hangcheck_dma_addr;
+ struct work_struct recover_work;
+};
+
+struct etnaviv_cmdbuf {
+ /* device this cmdbuf is allocated for */
+ struct etnaviv_gpu *gpu;
+ /* user context key, must be unique between all active users */
+ struct etnaviv_file_private *ctx;
+ /* cmdbuf properties */
+ void *vaddr;
+ dma_addr_t paddr;
+ u32 size;
+ u32 user_size;
+ /* fence after which this buffer is to be disposed */
+ struct fence *fence;
+ /* target exec state */
+ u32 exec_state;
+ /* per GPU in-flight list */
+ struct list_head node;
+ /* BOs attached to this command buffer */
+ unsigned int nr_bos;
+ struct etnaviv_gem_object *bo[0];
+};
+
+static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
+{
+ etnaviv_writel(data, gpu->mmio + reg);
+}
+
+static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg)
+{
+ return etnaviv_readl(gpu->mmio + reg);
+}
+
+static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence)
+{
+ return fence_after_eq(gpu->completed_fence, fence);
+}
+
+static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence)
+{
+ return fence_after_eq(gpu->retired_fence, fence);
+}
+
+int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value);
+
+int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
+
+#ifdef CONFIG_DEBUG_FS
+int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
+#endif
+
+int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
+ unsigned int context, bool exclusive);
+
+void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
+int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
+ u32 fence, struct timespec *timeout);
+int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
+ struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
+int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
+ struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf);
+struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
+ u32 size, size_t nr_bos);
+void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
+int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
+void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
+
+extern struct platform_driver etnaviv_gpu_driver;
+
+#endif /* __ETNAVIV_GPU_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
new file mode 100644
index 000000000000..522cfd447892
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitops.h>
+
+#include "etnaviv_gpu.h"
+#include "etnaviv_mmu.h"
+#include "etnaviv_iommu.h"
+#include "state_hi.xml.h"
+
+#define PT_SIZE SZ_2M
+#define PT_ENTRIES (PT_SIZE / sizeof(u32))
+
+#define GPU_MEM_START 0x80000000
+
+struct etnaviv_iommu_domain_pgtable {
+ u32 *pgtable;
+ dma_addr_t paddr;
+};
+
+struct etnaviv_iommu_domain {
+ struct iommu_domain domain;
+ struct device *dev;
+ void *bad_page_cpu;
+ dma_addr_t bad_page_dma;
+ struct etnaviv_iommu_domain_pgtable pgtable;
+ spinlock_t map_lock;
+};
+
+static struct etnaviv_iommu_domain *to_etnaviv_domain(struct iommu_domain *domain)
+{
+ return container_of(domain, struct etnaviv_iommu_domain, domain);
+}
+
+static int pgtable_alloc(struct etnaviv_iommu_domain_pgtable *pgtable,
+ size_t size)
+{
+ pgtable->pgtable = dma_alloc_coherent(NULL, size, &pgtable->paddr, GFP_KERNEL);
+ if (!pgtable->pgtable)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void pgtable_free(struct etnaviv_iommu_domain_pgtable *pgtable,
+ size_t size)
+{
+ dma_free_coherent(NULL, size, pgtable->pgtable, pgtable->paddr);
+}
+
+static u32 pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
+ unsigned long iova)
+{
+ /* calcuate index into page table */
+ unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
+ phys_addr_t paddr;
+
+ paddr = pgtable->pgtable[index];
+
+ return paddr;
+}
+
+static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
+ unsigned long iova, phys_addr_t paddr)
+{
+ /* calcuate index into page table */
+ unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
+
+ pgtable->pgtable[index] = paddr;
+}
+
+static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain)
+{
+ u32 *p;
+ int ret, i;
+
+ etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev,
+ SZ_4K,
+ &etnaviv_domain->bad_page_dma,
+ GFP_KERNEL);
+ if (!etnaviv_domain->bad_page_cpu)
+ return -ENOMEM;
+
+ p = etnaviv_domain->bad_page_cpu;
+ for (i = 0; i < SZ_4K / 4; i++)
+ *p++ = 0xdead55aa;
+
+ ret = pgtable_alloc(&etnaviv_domain->pgtable, PT_SIZE);
+ if (ret < 0) {
+ dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+ etnaviv_domain->bad_page_cpu,
+ etnaviv_domain->bad_page_dma);
+ return ret;
+ }
+
+ for (i = 0; i < PT_ENTRIES; i++)
+ etnaviv_domain->pgtable.pgtable[i] =
+ etnaviv_domain->bad_page_dma;
+
+ spin_lock_init(&etnaviv_domain->map_lock);
+
+ return 0;
+}
+
+static void etnaviv_domain_free(struct iommu_domain *domain)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+
+ pgtable_free(&etnaviv_domain->pgtable, PT_SIZE);
+
+ dma_free_coherent(etnaviv_domain->dev, SZ_4K,
+ etnaviv_domain->bad_page_cpu,
+ etnaviv_domain->bad_page_dma);
+
+ kfree(etnaviv_domain);
+}
+
+static int etnaviv_iommuv1_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+
+ if (size != SZ_4K)
+ return -EINVAL;
+
+ spin_lock(&etnaviv_domain->map_lock);
+ pgtable_write(&etnaviv_domain->pgtable, iova, paddr);
+ spin_unlock(&etnaviv_domain->map_lock);
+
+ return 0;
+}
+
+static size_t etnaviv_iommuv1_unmap(struct iommu_domain *domain,
+ unsigned long iova, size_t size)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+
+ if (size != SZ_4K)
+ return -EINVAL;
+
+ spin_lock(&etnaviv_domain->map_lock);
+ pgtable_write(&etnaviv_domain->pgtable, iova,
+ etnaviv_domain->bad_page_dma);
+ spin_unlock(&etnaviv_domain->map_lock);
+
+ return SZ_4K;
+}
+
+static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+
+ return pgtable_read(&etnaviv_domain->pgtable, iova);
+}
+
+static size_t etnaviv_iommuv1_dump_size(struct iommu_domain *domain)
+{
+ return PT_SIZE;
+}
+
+static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+
+ memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
+}
+
+static struct etnaviv_iommu_ops etnaviv_iommu_ops = {
+ .ops = {
+ .domain_free = etnaviv_domain_free,
+ .map = etnaviv_iommuv1_map,
+ .unmap = etnaviv_iommuv1_unmap,
+ .iova_to_phys = etnaviv_iommu_iova_to_phys,
+ .pgsize_bitmap = SZ_4K,
+ },
+ .dump_size = etnaviv_iommuv1_dump_size,
+ .dump = etnaviv_iommuv1_dump,
+};
+
+void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
+ struct iommu_domain *domain)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
+ u32 pgtable;
+
+ /* set page table address in MC */
+ pgtable = (u32)etnaviv_domain->pgtable.paddr;
+
+ gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);
+ gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable);
+ gpu_write(gpu, VIVS_MC_MMU_PE_PAGE_TABLE, pgtable);
+ gpu_write(gpu, VIVS_MC_MMU_PEZ_PAGE_TABLE, pgtable);
+ gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
+}
+
+struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu)
+{
+ struct etnaviv_iommu_domain *etnaviv_domain;
+ int ret;
+
+ etnaviv_domain = kzalloc(sizeof(*etnaviv_domain), GFP_KERNEL);
+ if (!etnaviv_domain)
+ return NULL;
+
+ etnaviv_domain->dev = gpu->dev;
+
+ etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING;
+ etnaviv_domain->domain.ops = &etnaviv_iommu_ops.ops;
+ etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START;
+ etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + PT_ENTRIES * SZ_4K - 1;
+
+ ret = __etnaviv_iommu_init(etnaviv_domain);
+ if (ret)
+ goto out_free;
+
+ return &etnaviv_domain->domain;
+
+out_free:
+ kfree(etnaviv_domain);
+ return NULL;
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.h b/drivers/gpu/drm/etnaviv/etnaviv_iommu.h
new file mode 100644
index 000000000000..cf45503f6b6f
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@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/>.
+ */
+
+#ifndef __ETNAVIV_IOMMU_H__
+#define __ETNAVIV_IOMMU_H__
+
+#include <linux/iommu.h>
+struct etnaviv_gpu;
+
+struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu);
+void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu,
+ struct iommu_domain *domain);
+struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
+
+#endif /* __ETNAVIV_IOMMU_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
new file mode 100644
index 000000000000..fbb4aed3dc80
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitops.h>
+
+#include "etnaviv_gpu.h"
+#include "etnaviv_iommu.h"
+#include "state_hi.xml.h"
+
+
+struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu)
+{
+ /* TODO */
+ return NULL;
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h
new file mode 100644
index 000000000000..603ea41c5389
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner@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/>.
+ */
+
+#ifndef __ETNAVIV_IOMMU_V2_H__
+#define __ETNAVIV_IOMMU_V2_H__
+
+#include <linux/iommu.h>
+struct etnaviv_gpu;
+
+struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu);
+
+#endif /* __ETNAVIV_IOMMU_V2_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
new file mode 100644
index 000000000000..6743bc648dc8
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_mmu.h"
+
+static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device *dev,
+ unsigned long iova, int flags, void *arg)
+{
+ DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
+ return 0;
+}
+
+int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
+ struct sg_table *sgt, unsigned len, int prot)
+{
+ struct iommu_domain *domain = iommu->domain;
+ struct scatterlist *sg;
+ unsigned int da = iova;
+ unsigned int i, j;
+ int ret;
+
+ if (!domain || !sgt)
+ return -EINVAL;
+
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ u32 pa = sg_dma_address(sg) - sg->offset;
+ size_t bytes = sg_dma_len(sg) + sg->offset;
+
+ VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
+
+ ret = iommu_map(domain, da, pa, bytes, prot);
+ if (ret)
+ goto fail;
+
+ da += bytes;
+ }
+
+ return 0;
+
+fail:
+ da = iova;
+
+ for_each_sg(sgt->sgl, sg, i, j) {
+ size_t bytes = sg_dma_len(sg) + sg->offset;
+
+ iommu_unmap(domain, da, bytes);
+ da += bytes;
+ }
+ return ret;
+}
+
+int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
+ struct sg_table *sgt, unsigned len)
+{
+ struct iommu_domain *domain = iommu->domain;
+ struct scatterlist *sg;
+ unsigned int da = iova;
+ int i;
+
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ size_t bytes = sg_dma_len(sg) + sg->offset;
+ size_t unmapped;
+
+ unmapped = iommu_unmap(domain, da, bytes);
+ if (unmapped < bytes)
+ return unmapped;
+
+ VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
+
+ BUG_ON(!PAGE_ALIGNED(bytes));
+
+ da += bytes;
+ }
+
+ return 0;
+}
+
+static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu *mmu,
+ struct etnaviv_vram_mapping *mapping)
+{
+ struct etnaviv_gem_object *etnaviv_obj = mapping->object;
+
+ etnaviv_iommu_unmap(mmu, mapping->vram_node.start,
+ etnaviv_obj->sgt, etnaviv_obj->base.size);
+ drm_mm_remove_node(&mapping->vram_node);
+}
+
+int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
+ struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
+ struct etnaviv_vram_mapping *mapping)
+{
+ struct etnaviv_vram_mapping *free = NULL;
+ struct sg_table *sgt = etnaviv_obj->sgt;
+ struct drm_mm_node *node;
+ int ret;
+
+ lockdep_assert_held(&etnaviv_obj->lock);
+
+ mutex_lock(&mmu->lock);
+
+ /* v1 MMU can optimize single entry (contiguous) scatterlists */
+ if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) {
+ u32 iova;
+
+ iova = sg_dma_address(sgt->sgl) - memory_base;
+ if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) {
+ mapping->iova = iova;
+ list_add_tail(&mapping->mmu_node, &mmu->mappings);
+ mutex_unlock(&mmu->lock);
+ return 0;
+ }
+ }
+
+ node = &mapping->vram_node;
+ while (1) {
+ struct etnaviv_vram_mapping *m, *n;
+ struct list_head list;
+ bool found;
+
+ ret = drm_mm_insert_node_in_range(&mmu->mm, node,
+ etnaviv_obj->base.size, 0, mmu->last_iova, ~0UL,
+ DRM_MM_SEARCH_DEFAULT);
+
+ if (ret != -ENOSPC)
+ break;
+
+ /*
+ * If we did not search from the start of the MMU region,
+ * try again in case there are free slots.
+ */
+ if (mmu->last_iova) {
+ mmu->last_iova = 0;
+ mmu->need_flush = true;
+ continue;
+ }
+
+ /* Try to retire some entries */
+ drm_mm_init_scan(&mmu->mm, etnaviv_obj->base.size, 0, 0);
+
+ found = 0;
+ INIT_LIST_HEAD(&list);
+ list_for_each_entry(free, &mmu->mappings, mmu_node) {
+ /* If this vram node has not been used, skip this. */
+ if (!free->vram_node.mm)
+ continue;
+
+ /*
+ * If the iova is pinned, then it's in-use,
+ * so we must keep its mapping.
+ */
+ if (free->use)
+ continue;
+
+ list_add(&free->scan_node, &list);
+ if (drm_mm_scan_add_block(&free->vram_node)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Nothing found, clean up and fail */
+ list_for_each_entry_safe(m, n, &list, scan_node)
+ BUG_ON(drm_mm_scan_remove_block(&m->vram_node));
+ break;
+ }
+
+ /*
+ * drm_mm does not allow any other operations while
+ * scanning, so we have to remove all blocks first.
+ * If drm_mm_scan_remove_block() returns false, we
+ * can leave the block pinned.
+ */
+ list_for_each_entry_safe(m, n, &list, scan_node)
+ if (!drm_mm_scan_remove_block(&m->vram_node))
+ list_del_init(&m->scan_node);
+
+ /*
+ * Unmap the blocks which need to be reaped from the MMU.
+ * Clear the mmu pointer to prevent the get_iova finding
+ * this mapping.
+ */
+ list_for_each_entry_safe(m, n, &list, scan_node) {
+ etnaviv_iommu_remove_mapping(mmu, m);
+ m->mmu = NULL;
+ list_del_init(&m->mmu_node);
+ list_del_init(&m->scan_node);
+ }
+
+ /*
+ * We removed enough mappings so that the new allocation will
+ * succeed. Ensure that the MMU will be flushed before the
+ * associated commit requesting this mapping, and retry the
+ * allocation one more time.
+ */
+ mmu->need_flush = true;
+ }
+
+ if (ret < 0) {
+ mutex_unlock(&mmu->lock);
+ return ret;
+ }
+
+ mmu->last_iova = node->start + etnaviv_obj->base.size;
+ mapping->iova = node->start;
+ ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size,
+ IOMMU_READ | IOMMU_WRITE);
+
+ if (ret < 0) {
+ drm_mm_remove_node(node);
+ mutex_unlock(&mmu->lock);
+ return ret;
+ }
+
+ list_add_tail(&mapping->mmu_node, &mmu->mappings);
+ mutex_unlock(&mmu->lock);
+
+ return ret;
+}
+
+void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
+ struct etnaviv_vram_mapping *mapping)
+{
+ WARN_ON(mapping->use);
+
+ mutex_lock(&mmu->lock);
+
+ /* If the vram node is on the mm, unmap and remove the node */
+ if (mapping->vram_node.mm == &mmu->mm)
+ etnaviv_iommu_remove_mapping(mmu, mapping);
+
+ list_del(&mapping->mmu_node);
+ mutex_unlock(&mmu->lock);
+}
+
+void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu)
+{
+ drm_mm_takedown(&mmu->mm);
+ iommu_domain_free(mmu->domain);
+ kfree(mmu);
+}
+
+struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu,
+ struct iommu_domain *domain, enum etnaviv_iommu_version version)
+{
+ struct etnaviv_iommu *mmu;
+
+ mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
+ if (!mmu)
+ return ERR_PTR(-ENOMEM);
+
+ mmu->domain = domain;
+ mmu->gpu = gpu;
+ mmu->version = version;
+ mutex_init(&mmu->lock);
+ INIT_LIST_HEAD(&mmu->mappings);
+
+ drm_mm_init(&mmu->mm, domain->geometry.aperture_start,
+ domain->geometry.aperture_end -
+ domain->geometry.aperture_start + 1);
+
+ iommu_set_fault_handler(domain, etnaviv_fault_handler, gpu->dev);
+
+ return mmu;
+}
+
+size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu)
+{
+ struct etnaviv_iommu_ops *ops;
+
+ ops = container_of(iommu->domain->ops, struct etnaviv_iommu_ops, ops);
+
+ return ops->dump_size(iommu->domain);
+}
+
+void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf)
+{
+ struct etnaviv_iommu_ops *ops;
+
+ ops = container_of(iommu->domain->ops, struct etnaviv_iommu_ops, ops);
+
+ ops->dump(iommu->domain, buf);
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
new file mode 100644
index 000000000000..fff215a47630
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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/>.
+ */
+
+#ifndef __ETNAVIV_MMU_H__
+#define __ETNAVIV_MMU_H__
+
+#include <linux/iommu.h>
+
+enum etnaviv_iommu_version {
+ ETNAVIV_IOMMU_V1 = 0,
+ ETNAVIV_IOMMU_V2,
+};
+
+struct etnaviv_gpu;
+struct etnaviv_vram_mapping;
+
+struct etnaviv_iommu_ops {
+ struct iommu_ops ops;
+ size_t (*dump_size)(struct iommu_domain *);
+ void (*dump)(struct iommu_domain *, void *);
+};
+
+struct etnaviv_iommu {
+ struct etnaviv_gpu *gpu;
+ struct iommu_domain *domain;
+
+ enum etnaviv_iommu_version version;
+
+ /* memory manager for GPU address area */
+ struct mutex lock;
+ struct list_head mappings;
+ struct drm_mm mm;
+ u32 last_iova;
+ bool need_flush;
+};
+
+struct etnaviv_gem_object;
+
+int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names,
+ int cnt);
+int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova,
+ struct sg_table *sgt, unsigned len, int prot);
+int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova,
+ struct sg_table *sgt, unsigned len);
+int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
+ struct etnaviv_gem_object *etnaviv_obj, u32 memory_base,
+ struct etnaviv_vram_mapping *mapping);
+void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
+ struct etnaviv_vram_mapping *mapping);
+void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
+
+size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu);
+void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);
+
+struct etnaviv_iommu *etnaviv_iommu_new(struct etnaviv_gpu *gpu,
+ struct iommu_domain *domain, enum etnaviv_iommu_version version);
+
+#endif /* __ETNAVIV_MMU_H__ */
diff --git a/drivers/gpu/drm/etnaviv/state.xml.h b/drivers/gpu/drm/etnaviv/state.xml.h
new file mode 100644
index 000000000000..368218304566
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/state.xml.h
@@ -0,0 +1,351 @@
+#ifndef STATE_XML
+#define STATE_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state.xml ( 18882 bytes, from 2015-03-25 11:42:32)
+- common.xml ( 18437 bytes, from 2015-03-25 11:27:41)
+- state_hi.xml ( 23420 bytes, from 2015-03-25 11:47:21)
+- state_2d.xml ( 51549 bytes, from 2015-03-25 11:25:06)
+- state_3d.xml ( 54600 bytes, from 2015-03-25 11:25:19)
+- state_vg.xml ( 5973 bytes, from 2015-03-25 11:26:01)
+
+Copyright (C) 2015
+*/
+
+
+#define VARYING_COMPONENT_USE_UNUSED 0x00000000
+#define VARYING_COMPONENT_USE_USED 0x00000001
+#define VARYING_COMPONENT_USE_POINTCOORD_X 0x00000002
+#define VARYING_COMPONENT_USE_POINTCOORD_Y 0x00000003
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK 0x000000ff
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT 0
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x) (((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK)
+#define VIVS_FE 0x00000000
+
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0) (0x00000600 + 0x4*(i0))
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE 0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN 0x00000010
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK 0x0000000f
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT 0
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE 0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE 0x00000001
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT 0x00000002
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT 0x00000003
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT 0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT 0x00000005
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT 0x00000008
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT 0x00000009
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED 0x0000000b
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2 0x0000000c
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2 0x0000000d
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK 0x00000030
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT 4
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE 0x00000080
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK 0x00000700
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT 8
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK 0x00003000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT 12
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK 0x0000c000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT 14
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF 0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON 0x00008000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK 0x00ff0000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT 16
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK 0xff000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT 24
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK)
+
+#define VIVS_FE_CMD_STREAM_BASE_ADDR 0x00000640
+
+#define VIVS_FE_INDEX_STREAM_BASE_ADDR 0x00000644
+
+#define VIVS_FE_INDEX_STREAM_CONTROL 0x00000648
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK 0x00000003
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT 0
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR 0x00000000
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT 0x00000001
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT 0x00000002
+
+#define VIVS_FE_VERTEX_STREAM_BASE_ADDR 0x0000064c
+
+#define VIVS_FE_VERTEX_STREAM_CONTROL 0x00000650
+
+#define VIVS_FE_COMMAND_ADDRESS 0x00000654
+
+#define VIVS_FE_COMMAND_CONTROL 0x00000658
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK 0x0000ffff
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT 0
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x) (((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK)
+#define VIVS_FE_COMMAND_CONTROL_ENABLE 0x00010000
+
+#define VIVS_FE_DMA_STATUS 0x0000065c
+
+#define VIVS_FE_DMA_DEBUG_STATE 0x00000660
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK 0x0000001f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT 0
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE 0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC 0x00000001
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0 0x00000002
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0 0x00000003
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1 0x00000004
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1 0x00000005
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR 0x00000006
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD 0x00000007
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL 0x00000008
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL 0x00000009
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA 0x0000000a
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX 0x0000000b
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW 0x0000000c
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0 0x0000000d
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1 0x0000000e
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0 0x0000000f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1 0x00000010
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO 0x00000011
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT 0x00000012
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK 0x00000013
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END 0x00000014
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL 0x00000015
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK 0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT 8
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE 0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START 0x00000100
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ 0x00000200
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END 0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK 0x00000c00
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT 10
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE 0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID 0x00000400
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID 0x00000800
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK 0x00003000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT 12
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE 0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX 0x00001000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL 0x00002000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK 0x0000c000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT 14
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE 0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR 0x00004000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC 0x00008000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK 0x00030000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT 16
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE 0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE 0x00010000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS 0x00020000
+
+#define VIVS_FE_DMA_ADDRESS 0x00000664
+
+#define VIVS_FE_DMA_LOW 0x00000668
+
+#define VIVS_FE_DMA_HIGH 0x0000066c
+
+#define VIVS_FE_AUTO_FLUSH 0x00000670
+
+#define VIVS_FE_UNK00678 0x00000678
+
+#define VIVS_FE_UNK0067C 0x0000067c
+
+#define VIVS_FE_VERTEX_STREAMS(i0) (0x00000000 + 0x4*(i0))
+#define VIVS_FE_VERTEX_STREAMS__ESIZE 0x00000004
+#define VIVS_FE_VERTEX_STREAMS__LEN 0x00000008
+
+#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0) (0x00000680 + 0x4*(i0))
+
+#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0) (0x000006a0 + 0x4*(i0))
+
+#define VIVS_FE_UNK00700(i0) (0x00000700 + 0x4*(i0))
+#define VIVS_FE_UNK00700__ESIZE 0x00000004
+#define VIVS_FE_UNK00700__LEN 0x00000010
+
+#define VIVS_FE_UNK00740(i0) (0x00000740 + 0x4*(i0))
+#define VIVS_FE_UNK00740__ESIZE 0x00000004
+#define VIVS_FE_UNK00740__LEN 0x00000010
+
+#define VIVS_FE_UNK00780(i0) (0x00000780 + 0x4*(i0))
+#define VIVS_FE_UNK00780__ESIZE 0x00000004
+#define VIVS_FE_UNK00780__LEN 0x00000010
+
+#define VIVS_GL 0x00000000
+
+#define VIVS_GL_PIPE_SELECT 0x00003800
+#define VIVS_GL_PIPE_SELECT_PIPE__MASK 0x00000001
+#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT 0
+#define VIVS_GL_PIPE_SELECT_PIPE(x) (((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK)
+
+#define VIVS_GL_EVENT 0x00003804
+#define VIVS_GL_EVENT_EVENT_ID__MASK 0x0000001f
+#define VIVS_GL_EVENT_EVENT_ID__SHIFT 0
+#define VIVS_GL_EVENT_EVENT_ID(x) (((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK)
+#define VIVS_GL_EVENT_FROM_FE 0x00000020
+#define VIVS_GL_EVENT_FROM_PE 0x00000040
+#define VIVS_GL_EVENT_SOURCE__MASK 0x00001f00
+#define VIVS_GL_EVENT_SOURCE__SHIFT 8
+#define VIVS_GL_EVENT_SOURCE(x) (((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK)
+
+#define VIVS_GL_SEMAPHORE_TOKEN 0x00003808
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK 0x0000001f
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT 0
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x) (((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK)
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK 0x00001f00
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT 8
+#define VIVS_GL_SEMAPHORE_TOKEN_TO(x) (((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK)
+
+#define VIVS_GL_FLUSH_CACHE 0x0000380c
+#define VIVS_GL_FLUSH_CACHE_DEPTH 0x00000001
+#define VIVS_GL_FLUSH_CACHE_COLOR 0x00000002
+#define VIVS_GL_FLUSH_CACHE_TEXTURE 0x00000004
+#define VIVS_GL_FLUSH_CACHE_PE2D 0x00000008
+#define VIVS_GL_FLUSH_CACHE_TEXTUREVS 0x00000010
+#define VIVS_GL_FLUSH_CACHE_SHADER_L1 0x00000020
+#define VIVS_GL_FLUSH_CACHE_SHADER_L2 0x00000040
+
+#define VIVS_GL_FLUSH_MMU 0x00003810
+#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU 0x00000001
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1 0x00000002
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2 0x00000004
+#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU 0x00000008
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4 0x00000010
+
+#define VIVS_GL_VERTEX_ELEMENT_CONFIG 0x00003814
+
+#define VIVS_GL_MULTI_SAMPLE_CONFIG 0x00003818
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK 0x00000003
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT 0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE 0x00000000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X 0x00000001
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X 0x00000002
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK 0x00000008
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK 0x000000f0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT 4
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x) (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK 0x00000100
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK 0x00007000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT 12
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x) (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK 0x00008000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK 0x00030000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT 16
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x) (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK 0x00080000
+
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS 0x0000381c
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK 0x000000ff
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT 0
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x) (((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK)
+
+#define VIVS_GL_VARYING_NUM_COMPONENTS 0x00003820
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK 0x00000007
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT 0
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK 0x00000070
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT 4
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK 0x00000700
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT 8
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK 0x00007000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT 12
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK 0x00070000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT 16
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK 0x00700000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT 20
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK 0x07000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT 24
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK 0x70000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT 28
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK)
+
+#define VIVS_GL_VARYING_COMPONENT_USE(i0) (0x00003828 + 0x4*(i0))
+#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE 0x00000004
+#define VIVS_GL_VARYING_COMPONENT_USE__LEN 0x00000002
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK 0x00000003
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT 0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK 0x0000000c
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT 2
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK 0x00000030
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT 4
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK 0x000000c0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT 6
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK 0x00000300
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT 8
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK 0x00000c00
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT 10
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK 0x00003000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT 12
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK 0x0000c000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT 14
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK 0x00030000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT 16
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK 0x000c0000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT 18
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK 0x00300000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT 20
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK 0x00c00000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT 22
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK 0x03000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT 24
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK 0x0c000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT 26
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK 0x30000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT 28
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK 0xc0000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT 30
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK)
+
+#define VIVS_GL_UNK03834 0x00003834
+
+#define VIVS_GL_UNK03838 0x00003838
+
+#define VIVS_GL_API_MODE 0x0000384c
+#define VIVS_GL_API_MODE_OPENGL 0x00000000
+#define VIVS_GL_API_MODE_OPENVG 0x00000001
+#define VIVS_GL_API_MODE_OPENCL 0x00000002
+
+#define VIVS_GL_CONTEXT_POINTER 0x00003850
+
+#define VIVS_GL_UNK03A00 0x00003a00
+
+#define VIVS_GL_STALL_TOKEN 0x00003c00
+#define VIVS_GL_STALL_TOKEN_FROM__MASK 0x0000001f
+#define VIVS_GL_STALL_TOKEN_FROM__SHIFT 0
+#define VIVS_GL_STALL_TOKEN_FROM(x) (((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK)
+#define VIVS_GL_STALL_TOKEN_TO__MASK 0x00001f00
+#define VIVS_GL_STALL_TOKEN_TO__SHIFT 8
+#define VIVS_GL_STALL_TOKEN_TO(x) (((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK)
+#define VIVS_GL_STALL_TOKEN_FLIP0 0x40000000
+#define VIVS_GL_STALL_TOKEN_FLIP1 0x80000000
+
+#define VIVS_DUMMY 0x00000000
+
+#define VIVS_DUMMY_DUMMY 0x0003fffc
+
+
+#endif /* STATE_XML */
diff --git a/drivers/gpu/drm/etnaviv/state_hi.xml.h b/drivers/gpu/drm/etnaviv/state_hi.xml.h
new file mode 100644
index 000000000000..0064f2640396
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/state_hi.xml.h
@@ -0,0 +1,407 @@
+#ifndef STATE_HI_XML
+#define STATE_HI_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state_hi.xml ( 23420 bytes, from 2015-03-25 11:47:21)
+- common.xml ( 18437 bytes, from 2015-03-25 11:27:41)
+
+Copyright (C) 2015
+*/
+
+
+#define MMU_EXCEPTION_SLAVE_NOT_PRESENT 0x00000001
+#define MMU_EXCEPTION_PAGE_NOT_PRESENT 0x00000002
+#define MMU_EXCEPTION_WRITE_VIOLATION 0x00000003
+#define VIVS_HI 0x00000000
+
+#define VIVS_HI_CLOCK_CONTROL 0x00000000
+#define VIVS_HI_CLOCK_CONTROL_CLK3D_DIS 0x00000001
+#define VIVS_HI_CLOCK_CONTROL_CLK2D_DIS 0x00000002
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK 0x000001fc
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT 2
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(x) (((x) << VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT) & VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK)
+#define VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD 0x00000200
+#define VIVS_HI_CLOCK_CONTROL_DISABLE_RAM_CLK_GATING 0x00000400
+#define VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS 0x00000800
+#define VIVS_HI_CLOCK_CONTROL_SOFT_RESET 0x00001000
+#define VIVS_HI_CLOCK_CONTROL_IDLE_3D 0x00010000
+#define VIVS_HI_CLOCK_CONTROL_IDLE_2D 0x00020000
+#define VIVS_HI_CLOCK_CONTROL_IDLE_VG 0x00040000
+#define VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU 0x00080000
+#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK 0x00f00000
+#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT 20
+#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(x) (((x) << VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT) & VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK)
+
+#define VIVS_HI_IDLE_STATE 0x00000004
+#define VIVS_HI_IDLE_STATE_FE 0x00000001
+#define VIVS_HI_IDLE_STATE_DE 0x00000002
+#define VIVS_HI_IDLE_STATE_PE 0x00000004
+#define VIVS_HI_IDLE_STATE_SH 0x00000008
+#define VIVS_HI_IDLE_STATE_PA 0x00000010
+#define VIVS_HI_IDLE_STATE_SE 0x00000020
+#define VIVS_HI_IDLE_STATE_RA 0x00000040
+#define VIVS_HI_IDLE_STATE_TX 0x00000080
+#define VIVS_HI_IDLE_STATE_VG 0x00000100
+#define VIVS_HI_IDLE_STATE_IM 0x00000200
+#define VIVS_HI_IDLE_STATE_FP 0x00000400
+#define VIVS_HI_IDLE_STATE_TS 0x00000800
+#define VIVS_HI_IDLE_STATE_AXI_LP 0x80000000
+
+#define VIVS_HI_AXI_CONFIG 0x00000008
+#define VIVS_HI_AXI_CONFIG_AWID__MASK 0x0000000f
+#define VIVS_HI_AXI_CONFIG_AWID__SHIFT 0
+#define VIVS_HI_AXI_CONFIG_AWID(x) (((x) << VIVS_HI_AXI_CONFIG_AWID__SHIFT) & VIVS_HI_AXI_CONFIG_AWID__MASK)
+#define VIVS_HI_AXI_CONFIG_ARID__MASK 0x000000f0
+#define VIVS_HI_AXI_CONFIG_ARID__SHIFT 4
+#define VIVS_HI_AXI_CONFIG_ARID(x) (((x) << VIVS_HI_AXI_CONFIG_ARID__SHIFT) & VIVS_HI_AXI_CONFIG_ARID__MASK)
+#define VIVS_HI_AXI_CONFIG_AWCACHE__MASK 0x00000f00
+#define VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT 8
+#define VIVS_HI_AXI_CONFIG_AWCACHE(x) (((x) << VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_AWCACHE__MASK)
+#define VIVS_HI_AXI_CONFIG_ARCACHE__MASK 0x0000f000
+#define VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT 12
+#define VIVS_HI_AXI_CONFIG_ARCACHE(x) (((x) << VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_ARCACHE__MASK)
+
+#define VIVS_HI_AXI_STATUS 0x0000000c
+#define VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK 0x0000000f
+#define VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT 0
+#define VIVS_HI_AXI_STATUS_WR_ERR_ID(x) (((x) << VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK)
+#define VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK 0x000000f0
+#define VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT 4
+#define VIVS_HI_AXI_STATUS_RD_ERR_ID(x) (((x) << VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK)
+#define VIVS_HI_AXI_STATUS_DET_WR_ERR 0x00000100
+#define VIVS_HI_AXI_STATUS_DET_RD_ERR 0x00000200
+
+#define VIVS_HI_INTR_ACKNOWLEDGE 0x00000010
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK 0x7fffffff
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT 0
+#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC(x) (((x) << VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT) & VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK)
+#define VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR 0x80000000
+
+#define VIVS_HI_INTR_ENBL 0x00000014
+#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK 0xffffffff
+#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT 0
+#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC(x) (((x) << VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT) & VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK)
+
+#define VIVS_HI_CHIP_IDENTITY 0x00000018
+#define VIVS_HI_CHIP_IDENTITY_FAMILY__MASK 0xff000000
+#define VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT 24
+#define VIVS_HI_CHIP_IDENTITY_FAMILY(x) (((x) << VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT) & VIVS_HI_CHIP_IDENTITY_FAMILY__MASK)
+#define VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK 0x00ff0000
+#define VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT 16
+#define VIVS_HI_CHIP_IDENTITY_PRODUCT(x) (((x) << VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT) & VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK)
+#define VIVS_HI_CHIP_IDENTITY_REVISION__MASK 0x0000f000
+#define VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT 12
+#define VIVS_HI_CHIP_IDENTITY_REVISION(x) (((x) << VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT) & VIVS_HI_CHIP_IDENTITY_REVISION__MASK)
+
+#define VIVS_HI_CHIP_FEATURE 0x0000001c
+
+#define VIVS_HI_CHIP_MODEL 0x00000020
+
+#define VIVS_HI_CHIP_REV 0x00000024
+
+#define VIVS_HI_CHIP_DATE 0x00000028
+
+#define VIVS_HI_CHIP_TIME 0x0000002c
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_0 0x00000034
+
+#define VIVS_HI_CACHE_CONTROL 0x00000038
+
+#define VIVS_HI_MEMORY_COUNTER_RESET 0x0000003c
+
+#define VIVS_HI_PROFILE_READ_BYTES8 0x00000040
+
+#define VIVS_HI_PROFILE_WRITE_BYTES8 0x00000044
+
+#define VIVS_HI_CHIP_SPECS 0x00000048
+#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK 0x0000000f
+#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT 0
+#define VIVS_HI_CHIP_SPECS_STREAM_COUNT(x) (((x) << VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK 0x000000f0
+#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT 4
+#define VIVS_HI_CHIP_SPECS_REGISTER_MAX(x) (((x) << VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT) & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK)
+#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK 0x00000f00
+#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT 8
+#define VIVS_HI_CHIP_SPECS_THREAD_COUNT(x) (((x) << VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK 0x0001f000
+#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT 12
+#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE(x) (((x) << VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK)
+#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK 0x01f00000
+#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT 20
+#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT(x) (((x) << VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK 0x0e000000
+#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT 25
+#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES(x) (((x) << VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT) & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK)
+#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK 0xf0000000
+#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT 28
+#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE(x) (((x) << VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK)
+
+#define VIVS_HI_PROFILE_WRITE_BURSTS 0x0000004c
+
+#define VIVS_HI_PROFILE_WRITE_REQUESTS 0x00000050
+
+#define VIVS_HI_PROFILE_READ_BURSTS 0x00000058
+
+#define VIVS_HI_PROFILE_READ_REQUESTS 0x0000005c
+
+#define VIVS_HI_PROFILE_READ_LASTS 0x00000060
+
+#define VIVS_HI_GP_OUT0 0x00000064
+
+#define VIVS_HI_GP_OUT1 0x00000068
+
+#define VIVS_HI_GP_OUT2 0x0000006c
+
+#define VIVS_HI_AXI_CONTROL 0x00000070
+#define VIVS_HI_AXI_CONTROL_WR_FULL_BURST_MODE 0x00000001
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_1 0x00000074
+
+#define VIVS_HI_PROFILE_TOTAL_CYCLES 0x00000078
+
+#define VIVS_HI_PROFILE_IDLE_CYCLES 0x0000007c
+
+#define VIVS_HI_CHIP_SPECS_2 0x00000080
+#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK 0x000000ff
+#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT 0
+#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE(x) (((x) << VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT) & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK)
+#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK 0x0000ff00
+#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT 8
+#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT(x) (((x) << VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT) & VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK)
+#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK 0xffff0000
+#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT 16
+#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS(x) (((x) << VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT) & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK)
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_2 0x00000084
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_3 0x00000088
+
+#define VIVS_HI_CHIP_MINOR_FEATURE_4 0x00000094
+
+#define VIVS_PM 0x00000000
+
+#define VIVS_PM_POWER_CONTROLS 0x00000100
+#define VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING 0x00000001
+#define VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING 0x00000002
+#define VIVS_PM_POWER_CONTROLS_DISABLE_STARVE_MODULE_CLOCK_GATING 0x00000004
+#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK 0x000000f0
+#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT 4
+#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER(x) (((x) << VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK)
+#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK 0xffff0000
+#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT 16
+#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER(x) (((x) << VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT) & VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK)
+
+#define VIVS_PM_MODULE_CONTROLS 0x00000104
+#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_FE 0x00000001
+#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_DE 0x00000002
+#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PE 0x00000004
+
+#define VIVS_PM_MODULE_STATUS 0x00000108
+#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_FE 0x00000001
+#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_DE 0x00000002
+#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_PE 0x00000004
+
+#define VIVS_PM_PULSE_EATER 0x0000010c
+
+#define VIVS_MMUv2 0x00000000
+
+#define VIVS_MMUv2_SAFE_ADDRESS 0x00000180
+
+#define VIVS_MMUv2_CONFIGURATION 0x00000184
+#define VIVS_MMUv2_CONFIGURATION_MODE__MASK 0x00000001
+#define VIVS_MMUv2_CONFIGURATION_MODE__SHIFT 0
+#define VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K 0x00000000
+#define VIVS_MMUv2_CONFIGURATION_MODE_MODE1_K 0x00000001
+#define VIVS_MMUv2_CONFIGURATION_MODE_MASK 0x00000008
+#define VIVS_MMUv2_CONFIGURATION_FLUSH__MASK 0x00000010
+#define VIVS_MMUv2_CONFIGURATION_FLUSH__SHIFT 4
+#define VIVS_MMUv2_CONFIGURATION_FLUSH_FLUSH 0x00000010
+#define VIVS_MMUv2_CONFIGURATION_FLUSH_MASK 0x00000080
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS_MASK 0x00000100
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK 0xfffffc00
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT 10
+#define VIVS_MMUv2_CONFIGURATION_ADDRESS(x) (((x) << VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT) & VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK)
+
+#define VIVS_MMUv2_STATUS 0x00000188
+#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK 0x00000003
+#define VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT 0
+#define VIVS_MMUv2_STATUS_EXCEPTION0(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK)
+#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK 0x00000030
+#define VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT 4
+#define VIVS_MMUv2_STATUS_EXCEPTION1(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION1__MASK)
+#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK 0x00000300
+#define VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT 8
+#define VIVS_MMUv2_STATUS_EXCEPTION2(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION2__MASK)
+#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK 0x00003000
+#define VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT 12
+#define VIVS_MMUv2_STATUS_EXCEPTION3(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION3__MASK)
+
+#define VIVS_MMUv2_CONTROL 0x0000018c
+#define VIVS_MMUv2_CONTROL_ENABLE 0x00000001
+
+#define VIVS_MMUv2_EXCEPTION_ADDR(i0) (0x00000190 + 0x4*(i0))
+#define VIVS_MMUv2_EXCEPTION_ADDR__ESIZE 0x00000004
+#define VIVS_MMUv2_EXCEPTION_ADDR__LEN 0x00000004
+
+#define VIVS_MC 0x00000000
+
+#define VIVS_MC_MMU_FE_PAGE_TABLE 0x00000400
+
+#define VIVS_MC_MMU_TX_PAGE_TABLE 0x00000404
+
+#define VIVS_MC_MMU_PE_PAGE_TABLE 0x00000408
+
+#define VIVS_MC_MMU_PEZ_PAGE_TABLE 0x0000040c
+
+#define VIVS_MC_MMU_RA_PAGE_TABLE 0x00000410
+
+#define VIVS_MC_DEBUG_MEMORY 0x00000414
+#define VIVS_MC_DEBUG_MEMORY_SPECIAL_PATCH_GC320 0x00000008
+#define VIVS_MC_DEBUG_MEMORY_FAST_CLEAR_BYPASS 0x00100000
+#define VIVS_MC_DEBUG_MEMORY_COMPRESSION_BYPASS 0x00200000
+
+#define VIVS_MC_MEMORY_BASE_ADDR_RA 0x00000418
+
+#define VIVS_MC_MEMORY_BASE_ADDR_FE 0x0000041c
+
+#define VIVS_MC_MEMORY_BASE_ADDR_TX 0x00000420
+
+#define VIVS_MC_MEMORY_BASE_ADDR_PEZ 0x00000424
+
+#define VIVS_MC_MEMORY_BASE_ADDR_PE 0x00000428
+
+#define VIVS_MC_MEMORY_TIMING_CONTROL 0x0000042c
+
+#define VIVS_MC_MEMORY_FLUSH 0x00000430
+
+#define VIVS_MC_PROFILE_CYCLE_COUNTER 0x00000438
+
+#define VIVS_MC_DEBUG_READ0 0x0000043c
+
+#define VIVS_MC_DEBUG_READ1 0x00000440
+
+#define VIVS_MC_DEBUG_WRITE 0x00000444
+
+#define VIVS_MC_PROFILE_RA_READ 0x00000448
+
+#define VIVS_MC_PROFILE_TX_READ 0x0000044c
+
+#define VIVS_MC_PROFILE_FE_READ 0x00000450
+
+#define VIVS_MC_PROFILE_PE_READ 0x00000454
+
+#define VIVS_MC_PROFILE_DE_READ 0x00000458
+
+#define VIVS_MC_PROFILE_SH_READ 0x0000045c
+
+#define VIVS_MC_PROFILE_PA_READ 0x00000460
+
+#define VIVS_MC_PROFILE_SE_READ 0x00000464
+
+#define VIVS_MC_PROFILE_MC_READ 0x00000468
+
+#define VIVS_MC_PROFILE_HI_READ 0x0000046c
+
+#define VIVS_MC_PROFILE_CONFIG0 0x00000470
+#define VIVS_MC_PROFILE_CONFIG0_FE__MASK 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT 0
+#define VIVS_MC_PROFILE_CONFIG0_FE_RESET 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG0_DE__MASK 0x00000f00
+#define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT 8
+#define VIVS_MC_PROFILE_CONFIG0_DE_RESET 0x00000f00
+#define VIVS_MC_PROFILE_CONFIG0_PE__MASK 0x000f0000
+#define VIVS_MC_PROFILE_CONFIG0_PE__SHIFT 16
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE 0x00000000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE 0x00010000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE 0x00020000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE 0x00030000
+#define VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D 0x000b0000
+#define VIVS_MC_PROFILE_CONFIG0_PE_RESET 0x000f0000
+#define VIVS_MC_PROFILE_CONFIG0_SH__MASK 0x0f000000
+#define VIVS_MC_PROFILE_CONFIG0_SH__SHIFT 24
+#define VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES 0x04000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER 0x07000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER 0x08000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER 0x09000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER 0x0a000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER 0x0b000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER 0x0c000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER 0x0d000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER 0x0e000000
+#define VIVS_MC_PROFILE_CONFIG0_SH_RESET 0x0f000000
+
+#define VIVS_MC_PROFILE_CONFIG1 0x00000474
+#define VIVS_MC_PROFILE_CONFIG1_PA__MASK 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG1_PA__SHIFT 0
+#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER 0x00000003
+#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER 0x00000004
+#define VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER 0x00000005
+#define VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER 0x00000006
+#define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER 0x00000007
+#define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER 0x00000008
+#define VIVS_MC_PROFILE_CONFIG1_PA_RESET 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG1_SE__MASK 0x00000f00
+#define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT 8
+#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT 0x00000000
+#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT 0x00000100
+#define VIVS_MC_PROFILE_CONFIG1_SE_RESET 0x00000f00
+#define VIVS_MC_PROFILE_CONFIG1_RA__MASK 0x000f0000
+#define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT 16
+#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT 0x00000000
+#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT 0x00010000
+#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z 0x00020000
+#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT 0x00030000
+#define VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER 0x00090000
+#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER 0x000a0000
+#define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT 0x000b0000
+#define VIVS_MC_PROFILE_CONFIG1_RA_RESET 0x000f0000
+#define VIVS_MC_PROFILE_CONFIG1_TX__MASK 0x0f000000
+#define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT 24
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS 0x00000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS 0x01000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS 0x02000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS 0x03000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_UNKNOWN 0x04000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT 0x05000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT 0x06000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT 0x07000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT 0x08000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT 0x09000000
+#define VIVS_MC_PROFILE_CONFIG1_TX_RESET 0x0f000000
+
+#define VIVS_MC_PROFILE_CONFIG2 0x00000478
+#define VIVS_MC_PROFILE_CONFIG2_MC__MASK 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG2_MC__SHIFT 0
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE 0x00000001
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP 0x00000002
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE 0x00000003
+#define VIVS_MC_PROFILE_CONFIG2_MC_RESET 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG2_HI__MASK 0x00000f00
+#define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT 8
+#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED 0x00000000
+#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED 0x00000100
+#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED 0x00000200
+#define VIVS_MC_PROFILE_CONFIG2_HI_RESET 0x00000f00
+
+#define VIVS_MC_PROFILE_CONFIG3 0x0000047c
+
+#define VIVS_MC_BUS_CONFIG 0x00000480
+#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK 0x0000000f
+#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT 0
+#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(x) (((x) << VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK)
+#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK 0x000000f0
+#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT 4
+#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(x) (((x) << VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT) & VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK)
+
+#define VIVS_MC_START_COMPOSITION 0x00000554
+
+#define VIVS_MC_128B_MERGE 0x00000558
+
+
+#endif /* STATE_HI_XML */
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 96e86cf4455b..83efca941388 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -118,7 +118,7 @@ config DRM_EXYNOS_ROTATOR
config DRM_EXYNOS_GSC
bool "GScaler"
- depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
+ depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !VIDEO_SAMSUNG_EXYNOS_GSC
help
Choose this option if you want to use Exynos GSC for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index fbe1b3174f75..1bf6a21130c7 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -21,11 +21,11 @@
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
+#include "exynos_drm_fb.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_iommu.h"
#define WINDOWS_NR 3
-#define CURSOR_WIN 2
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
static const char * const decon_clks_name[] = {
@@ -56,6 +56,7 @@ struct decon_context {
struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc;
struct exynos_drm_plane planes[WINDOWS_NR];
+ struct exynos_drm_plane_config configs[WINDOWS_NR];
void __iomem *addr;
struct clk *clks[ARRAY_SIZE(decon_clks_name)];
int pipe;
@@ -71,6 +72,12 @@ static const uint32_t decon_formats[] = {
DRM_FORMAT_ARGB8888,
};
+static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
+ DRM_PLANE_TYPE_PRIMARY,
+ DRM_PLANE_TYPE_OVERLAY,
+ DRM_PLANE_TYPE_CURSOR,
+};
+
static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
u32 val)
{
@@ -241,15 +248,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win,
protect ? ~0 : 0);
}
-static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane)
+static void decon_atomic_begin(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
+ int i;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
- decon_shadow_protect_win(ctx, plane->zpos, true);
+ for (i = ctx->first_win; i < WINDOWS_NR; i++)
+ decon_shadow_protect_win(ctx, i, true);
}
#define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s))
@@ -259,21 +267,24 @@ static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
+ struct exynos_drm_plane_state *state =
+ to_exynos_plane_state(plane->base.state);
struct decon_context *ctx = crtc->ctx;
- struct drm_plane_state *state = plane->base.state;
- unsigned int win = plane->zpos;
- unsigned int bpp = state->fb->bits_per_pixel >> 3;
- unsigned int pitch = state->fb->pitches[0];
+ struct drm_framebuffer *fb = state->base.fb;
+ unsigned int win = plane->index;
+ unsigned int bpp = fb->bits_per_pixel >> 3;
+ unsigned int pitch = fb->pitches[0];
+ dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0);
u32 val;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
- val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
+ val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y);
writel(val, ctx->addr + DECON_VIDOSDxA(win));
- val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) |
- COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1);
+ val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) |
+ COORDINATE_Y(state->crtc.y + state->crtc.h - 1);
writel(val, ctx->addr + DECON_VIDOSDxB(win));
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
@@ -284,20 +295,20 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
VIDOSD_Wx_ALPHA_B_F(0x0);
writel(val, ctx->addr + DECON_VIDOSDxD(win));
- writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win));
+ writel(dma_addr, ctx->addr + DECON_VIDW0xADD0B0(win));
- val = plane->dma_addr[0] + pitch * plane->crtc_h;
+ val = dma_addr + pitch * state->src.h;
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
if (ctx->out_type != IFTYPE_HDMI)
- val = BIT_VAL(pitch - plane->crtc_w * bpp, 27, 14)
- | BIT_VAL(plane->crtc_w * bpp, 13, 0);
+ val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14)
+ | BIT_VAL(state->crtc.w * bpp, 13, 0);
else
- val = BIT_VAL(pitch - plane->crtc_w * bpp, 29, 15)
- | BIT_VAL(plane->crtc_w * bpp, 14, 0);
+ val = BIT_VAL(pitch - state->crtc.w * bpp, 29, 15)
+ | BIT_VAL(state->crtc.w * bpp, 14, 0);
writel(val, ctx->addr + DECON_VIDW0xADD2(win));
- decon_win_set_pixfmt(ctx, win, state->fb);
+ decon_win_set_pixfmt(ctx, win, fb);
/* window enable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
@@ -310,7 +321,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;
- unsigned int win = plane->zpos;
+ unsigned int win = plane->index;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
@@ -326,15 +337,16 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
-static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane)
+static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
+ int i;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
- decon_shadow_protect_win(ctx, plane->zpos, false);
+ for (i = ctx->first_win; i < WINDOWS_NR; i++)
+ decon_shadow_protect_win(ctx, i, false);
if (ctx->out_type == IFTYPE_I80)
set_bit(BIT_WIN_UPDATED, &ctx->flags);
@@ -377,20 +389,12 @@ static void decon_swreset(struct decon_context *ctx)
static void decon_enable(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- int ret;
- int i;
if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags))
return;
pm_runtime_get_sync(ctx->dev);
- for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
- ret = clk_prepare_enable(ctx->clks[i]);
- if (ret < 0)
- goto err;
- }
-
set_bit(BIT_CLKS_ENABLED, &ctx->flags);
/* if vblank was enabled status, enable it again. */
@@ -399,11 +403,6 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
decon_commit(ctx->crtc);
- return;
-err:
- while (--i >= 0)
- clk_disable_unprepare(ctx->clks[i]);
-
set_bit(BIT_SUSPENDED, &ctx->flags);
}
@@ -425,9 +424,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
decon_swreset(ctx);
- for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
- clk_disable_unprepare(ctx->clks[i]);
-
clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
pm_runtime_put_sync(ctx->dev);
@@ -478,7 +474,6 @@ err:
static struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable = decon_enable,
.disable = decon_disable,
- .commit = decon_commit,
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
.atomic_begin = decon_atomic_begin,
@@ -495,7 +490,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane;
enum exynos_drm_output_type out_type;
- enum drm_plane_type type;
unsigned int win;
int ret;
@@ -505,10 +499,13 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
for (win = ctx->first_win; win < WINDOWS_NR; win++) {
int tmp = (win == ctx->first_win) ? 0 : win;
- type = exynos_plane_get_type(tmp, CURSOR_WIN);
- ret = exynos_plane_init(drm_dev, &ctx->planes[win],
- 1 << ctx->pipe, type, decon_formats,
- ARRAY_SIZE(decon_formats), win);
+ ctx->configs[win].pixel_formats = decon_formats;
+ ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats);
+ ctx->configs[win].zpos = win;
+ ctx->configs[win].type = decon_win_types[tmp];
+
+ ret = exynos_plane_init(drm_dev, &ctx->planes[win], win,
+ 1 << ctx->pipe, &ctx->configs[win]);
if (ret)
return ret;
}
@@ -581,6 +578,44 @@ out:
return IRQ_HANDLED;
}
+#ifdef CONFIG_PM
+static int exynos5433_decon_suspend(struct device *dev)
+{
+ struct decon_context *ctx = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
+ clk_disable_unprepare(ctx->clks[i]);
+
+ return 0;
+}
+
+static int exynos5433_decon_resume(struct device *dev)
+{
+ struct decon_context *ctx = dev_get_drvdata(dev);
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
+ ret = clk_prepare_enable(ctx->clks[i]);
+ if (ret < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0)
+ clk_disable_unprepare(ctx->clks[i]);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops exynos5433_decon_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume,
+ NULL)
+};
+
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
{
.compatible = "samsung,exynos5433-decon",
@@ -684,6 +719,7 @@ struct platform_driver exynos5433_decon_driver = {
.remove = exynos5433_decon_remove,
.driver = {
.name = "exynos5433-decon",
+ .pm = &exynos5433_decon_pm_ops,
.of_match_table = exynos5433_decon_driver_dt_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index ead2b16e237d..52bda3b42fe0 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -30,6 +30,7 @@
#include "exynos_drm_crtc.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_drv.h"
+#include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h"
#include "exynos_drm_iommu.h"
@@ -40,13 +41,13 @@
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define WINDOWS_NR 2
-#define CURSOR_WIN 1
struct decon_context {
struct device *dev;
struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc;
struct exynos_drm_plane planes[WINDOWS_NR];
+ struct exynos_drm_plane_config configs[WINDOWS_NR];
struct clk *pclk;
struct clk *aclk;
struct clk *eclk;
@@ -81,6 +82,11 @@ static const uint32_t decon_formats[] = {
DRM_FORMAT_BGRA8888,
};
+static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
+ DRM_PLANE_TYPE_PRIMARY,
+ DRM_PLANE_TYPE_CURSOR,
+};
+
static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
@@ -119,13 +125,8 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
}
/* Wait for vsync, as disable channel takes effect at next vsync */
- if (ch_enabled) {
- unsigned int state = ctx->suspended;
-
- ctx->suspended = 0;
+ if (ch_enabled)
decon_wait_for_vblank(ctx->crtc);
- ctx->suspended = state;
- }
}
static int decon_ctx_initialize(struct decon_context *ctx,
@@ -384,30 +385,32 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
writel(val, ctx->regs + SHADOWCON);
}
-static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane)
+static void decon_atomic_begin(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
+ int i;
if (ctx->suspended)
return;
- decon_shadow_protect_win(ctx, plane->zpos, true);
+ for (i = 0; i < WINDOWS_NR; i++)
+ decon_shadow_protect_win(ctx, i, true);
}
static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
+ struct exynos_drm_plane_state *state =
+ to_exynos_plane_state(plane->base.state);
struct decon_context *ctx = crtc->ctx;
- struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
- struct drm_plane_state *state = plane->base.state;
+ struct drm_framebuffer *fb = state->base.fb;
int padding;
unsigned long val, alpha;
unsigned int last_x;
unsigned int last_y;
- unsigned int win = plane->zpos;
- unsigned int bpp = state->fb->bits_per_pixel >> 3;
- unsigned int pitch = state->fb->pitches[0];
+ unsigned int win = plane->index;
+ unsigned int bpp = fb->bits_per_pixel >> 3;
+ unsigned int pitch = fb->pitches[0];
if (ctx->suspended)
return;
@@ -423,41 +426,32 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
*/
/* buffer start address */
- val = (unsigned long)plane->dma_addr[0];
+ val = (unsigned long)exynos_drm_fb_dma_addr(fb, 0);
writel(val, ctx->regs + VIDW_BUF_START(win));
- padding = (pitch / bpp) - state->fb->width;
+ padding = (pitch / bpp) - fb->width;
/* buffer size */
- writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
- writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win));
+ writel(fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
+ writel(fb->height, ctx->regs + VIDW_WHOLE_Y(win));
/* offset from the start of the buffer to read */
- writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win));
- writel(plane->src_y, ctx->regs + VIDW_OFFSET_Y(win));
+ writel(state->src.x, ctx->regs + VIDW_OFFSET_X(win));
+ writel(state->src.y, ctx->regs + VIDW_OFFSET_Y(win));
DRM_DEBUG_KMS("start addr = 0x%lx\n",
(unsigned long)val);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
- plane->crtc_w, plane->crtc_h);
-
- /*
- * OSD position.
- * In case the window layout goes of LCD layout, DECON fails.
- */
- if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay)
- plane->crtc_x = mode->hdisplay - plane->crtc_w;
- if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay)
- plane->crtc_y = mode->vdisplay - plane->crtc_h;
+ state->crtc.w, state->crtc.h);
- val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
- VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
+ val = VIDOSDxA_TOPLEFT_X(state->crtc.x) |
+ VIDOSDxA_TOPLEFT_Y(state->crtc.y);
writel(val, ctx->regs + VIDOSD_A(win));
- last_x = plane->crtc_x + plane->crtc_w;
+ last_x = state->crtc.x + state->crtc.w;
if (last_x)
last_x--;
- last_y = plane->crtc_y + plane->crtc_h;
+ last_y = state->crtc.y + state->crtc.h;
if (last_y)
last_y--;
@@ -466,7 +460,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
writel(val, ctx->regs + VIDOSD_B(win));
DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
- plane->crtc_x, plane->crtc_y, last_x, last_y);
+ state->crtc.x, state->crtc.y, last_x, last_y);
/* OSD alpha */
alpha = VIDOSDxC_ALPHA0_R_F(0x0) |
@@ -481,7 +475,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
writel(alpha, ctx->regs + VIDOSD_D(win));
- decon_win_set_pixfmt(ctx, win, state->fb);
+ decon_win_set_pixfmt(ctx, win, fb);
/* hardware window 0 doesn't support color key. */
if (win != 0)
@@ -505,7 +499,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;
- unsigned int win = plane->zpos;
+ unsigned int win = plane->index;
u32 val;
if (ctx->suspended)
@@ -524,15 +518,16 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
writel(val, ctx->regs + DECON_UPDATE);
}
-static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane)
+static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
+ int i;
if (ctx->suspended)
return;
- decon_shadow_protect_win(ctx, plane->zpos, false);
+ for (i = 0; i < WINDOWS_NR; i++)
+ decon_shadow_protect_win(ctx, i, false);
}
static void decon_init(struct decon_context *ctx)
@@ -555,39 +550,12 @@ static void decon_init(struct decon_context *ctx)
static void decon_enable(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- int ret;
if (!ctx->suspended)
return;
- ctx->suspended = false;
-
pm_runtime_get_sync(ctx->dev);
- ret = clk_prepare_enable(ctx->pclk);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret);
- return;
- }
-
- ret = clk_prepare_enable(ctx->aclk);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret);
- return;
- }
-
- ret = clk_prepare_enable(ctx->eclk);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret);
- return;
- }
-
- ret = clk_prepare_enable(ctx->vclk);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret);
- return;
- }
-
decon_init(ctx);
/* if vblank was enabled status, enable it again. */
@@ -595,6 +563,8 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
decon_enable_vblank(ctx->crtc);
decon_commit(ctx->crtc);
+
+ ctx->suspended = false;
}
static void decon_disable(struct exynos_drm_crtc *crtc)
@@ -613,11 +583,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < WINDOWS_NR; i++)
decon_disable_plane(crtc, &ctx->planes[i]);
- clk_disable_unprepare(ctx->vclk);
- clk_disable_unprepare(ctx->eclk);
- clk_disable_unprepare(ctx->aclk);
- clk_disable_unprepare(ctx->pclk);
-
pm_runtime_put_sync(ctx->dev);
ctx->suspended = true;
@@ -679,8 +644,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
struct decon_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
struct exynos_drm_plane *exynos_plane;
- enum drm_plane_type type;
- unsigned int zpos;
+ unsigned int i;
int ret;
ret = decon_ctx_initialize(ctx, drm_dev);
@@ -689,11 +653,14 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
return ret;
}
- for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
- type = exynos_plane_get_type(zpos, CURSOR_WIN);
- ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
- 1 << ctx->pipe, type, decon_formats,
- ARRAY_SIZE(decon_formats), zpos);
+ for (i = 0; i < WINDOWS_NR; i++) {
+ ctx->configs[i].pixel_formats = decon_formats;
+ ctx->configs[i].num_pixel_formats = ARRAY_SIZE(decon_formats);
+ ctx->configs[i].zpos = i;
+ ctx->configs[i].type = decon_win_types[i];
+
+ ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
+ 1 << ctx->pipe, &ctx->configs[i]);
if (ret)
return ret;
}
@@ -843,11 +810,63 @@ static int decon_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int exynos7_decon_suspend(struct device *dev)
+{
+ struct decon_context *ctx = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(ctx->vclk);
+ clk_disable_unprepare(ctx->eclk);
+ clk_disable_unprepare(ctx->aclk);
+ clk_disable_unprepare(ctx->pclk);
+
+ return 0;
+}
+
+static int exynos7_decon_resume(struct device *dev)
+{
+ struct decon_context *ctx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(ctx->pclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(ctx->aclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(ctx->eclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(ctx->vclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos7_decon_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume,
+ NULL)
+};
+
struct platform_driver decon_driver = {
.probe = decon_probe,
.remove = decon_remove,
.driver = {
.name = "exynos-decon",
+ .pm = &exynos7_decon_pm_ops,
.of_match_table = decon_driver_dt_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 124fb9a56f02..b79c316c2ad2 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -953,7 +953,7 @@ static void exynos_dp_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs exynos_dp_connector_funcs = {
+static const struct drm_connector_funcs exynos_dp_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = exynos_dp_detect,
@@ -998,7 +998,7 @@ static struct drm_encoder *exynos_dp_best_encoder(
return &dp->encoder;
}
-static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
.get_modes = exynos_dp_get_modes,
.best_encoder = exynos_dp_best_encoder,
};
@@ -1009,9 +1009,9 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
{
int ret;
- encoder->bridge = dp->bridge;
- dp->bridge->encoder = encoder;
- ret = drm_bridge_attach(encoder->dev, dp->bridge);
+ encoder->bridge->next = dp->ptn_bridge;
+ dp->ptn_bridge->encoder = encoder;
+ ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
if (ret) {
DRM_ERROR("Failed to attach bridge to drm\n");
return ret;
@@ -1020,14 +1020,15 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
return 0;
}
-static int exynos_dp_create_connector(struct drm_encoder *encoder)
+static int exynos_dp_bridge_attach(struct drm_bridge *bridge)
{
- struct exynos_dp_device *dp = encoder_to_dp(encoder);
+ struct exynos_dp_device *dp = bridge->driver_private;
+ struct drm_encoder *encoder = &dp->encoder;
struct drm_connector *connector = &dp->connector;
int ret;
/* Pre-empt DP connector creation if there's a bridge */
- if (dp->bridge) {
+ if (dp->ptn_bridge) {
ret = exynos_drm_attach_lcd_bridge(dp, encoder);
if (!ret)
return 0;
@@ -1052,27 +1053,16 @@ static int exynos_dp_create_connector(struct drm_encoder *encoder)
return ret;
}
-static bool exynos_dp_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void exynos_dp_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
-}
-
-static void exynos_dp_enable(struct drm_encoder *encoder)
+static void exynos_dp_bridge_enable(struct drm_bridge *bridge)
{
- struct exynos_dp_device *dp = encoder_to_dp(encoder);
+ struct exynos_dp_device *dp = bridge->driver_private;
struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
if (dp->dpms_mode == DRM_MODE_DPMS_ON)
return;
+ pm_runtime_get_sync(dp->dev);
+
if (dp->panel) {
if (drm_panel_prepare(dp->panel)) {
DRM_ERROR("failed to setup the panel\n");
@@ -1083,7 +1073,6 @@ static void exynos_dp_enable(struct drm_encoder *encoder)
if (crtc->ops->clock_enable)
crtc->ops->clock_enable(dp_to_crtc(dp), true);
- clk_prepare_enable(dp->clock);
phy_power_on(dp->phy);
exynos_dp_init_dp(dp);
enable_irq(dp->irq);
@@ -1092,9 +1081,9 @@ static void exynos_dp_enable(struct drm_encoder *encoder)
dp->dpms_mode = DRM_MODE_DPMS_ON;
}
-static void exynos_dp_disable(struct drm_encoder *encoder)
+static void exynos_dp_bridge_disable(struct drm_bridge *bridge)
{
- struct exynos_dp_device *dp = encoder_to_dp(encoder);
+ struct exynos_dp_device *dp = bridge->driver_private;
struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
@@ -1110,7 +1099,6 @@ static void exynos_dp_disable(struct drm_encoder *encoder)
disable_irq(dp->irq);
flush_work(&dp->hotplug_work);
phy_power_off(dp->phy);
- clk_disable_unprepare(dp->clock);
if (crtc->ops->clock_enable)
crtc->ops->clock_enable(dp_to_crtc(dp), false);
@@ -1120,17 +1108,82 @@ static void exynos_dp_disable(struct drm_encoder *encoder)
DRM_ERROR("failed to turnoff the panel\n");
}
+ pm_runtime_put_sync(dp->dev);
+
dp->dpms_mode = DRM_MODE_DPMS_OFF;
}
-static struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
+static void exynos_dp_bridge_nop(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
+static const struct drm_bridge_funcs exynos_dp_bridge_funcs = {
+ .enable = exynos_dp_bridge_enable,
+ .disable = exynos_dp_bridge_disable,
+ .pre_enable = exynos_dp_bridge_nop,
+ .post_disable = exynos_dp_bridge_nop,
+ .attach = exynos_dp_bridge_attach,
+};
+
+static int exynos_dp_create_connector(struct drm_encoder *encoder)
+{
+ struct exynos_dp_device *dp = encoder_to_dp(encoder);
+ struct drm_device *drm_dev = dp->drm_dev;
+ struct drm_bridge *bridge;
+ int ret;
+
+ bridge = devm_kzalloc(drm_dev->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("failed to allocate for drm bridge\n");
+ return -ENOMEM;
+ }
+
+ dp->bridge = bridge;
+
+ encoder->bridge = bridge;
+ bridge->driver_private = dp;
+ bridge->encoder = encoder;
+ bridge->funcs = &exynos_dp_bridge_funcs;
+
+ ret = drm_bridge_attach(drm_dev, bridge);
+ if (ret) {
+ DRM_ERROR("failed to attach drm bridge\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool exynos_dp_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void exynos_dp_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void exynos_dp_enable(struct drm_encoder *encoder)
+{
+}
+
+static void exynos_dp_disable(struct drm_encoder *encoder)
+{
+}
+
+static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
.mode_fixup = exynos_dp_mode_fixup,
.mode_set = exynos_dp_mode_set,
.enable = exynos_dp_enable,
.disable = exynos_dp_disable,
};
-static struct drm_encoder_funcs exynos_dp_encoder_funcs = {
+static const struct drm_encoder_funcs exynos_dp_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -1238,7 +1291,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
}
}
- if (!dp->panel && !dp->bridge) {
+ if (!dp->panel && !dp->ptn_bridge) {
ret = exynos_dp_dt_parse_panel(dp);
if (ret)
return ret;
@@ -1289,10 +1342,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
- phy_power_on(dp->phy);
-
- exynos_dp_init_dp(dp);
-
ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler,
irq_flags, "exynos-dp", dp);
if (ret) {
@@ -1313,7 +1362,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
@@ -1343,8 +1392,9 @@ static const struct component_ops exynos_dp_ops = {
static int exynos_dp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *panel_node, *bridge_node, *endpoint;
+ struct device_node *panel_node = NULL, *bridge_node, *endpoint = NULL;
struct exynos_dp_device *dp;
+ int ret;
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
GFP_KERNEL);
@@ -1353,36 +1403,96 @@ static int exynos_dp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dp);
+ /* This is for the backward compatibility. */
panel_node = of_parse_phandle(dev->of_node, "panel", 0);
if (panel_node) {
dp->panel = of_drm_find_panel(panel_node);
of_node_put(panel_node);
if (!dp->panel)
return -EPROBE_DEFER;
+ } else {
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint) {
+ panel_node = of_graph_get_remote_port_parent(endpoint);
+ if (panel_node) {
+ dp->panel = of_drm_find_panel(panel_node);
+ of_node_put(panel_node);
+ if (!dp->panel)
+ return -EPROBE_DEFER;
+ } else {
+ DRM_ERROR("no port node for panel device.\n");
+ return -EINVAL;
+ }
+ }
}
+ if (endpoint)
+ goto out;
+
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
if (endpoint) {
bridge_node = of_graph_get_remote_port_parent(endpoint);
if (bridge_node) {
- dp->bridge = of_drm_find_bridge(bridge_node);
+ dp->ptn_bridge = of_drm_find_bridge(bridge_node);
of_node_put(bridge_node);
- if (!dp->bridge)
+ if (!dp->ptn_bridge)
return -EPROBE_DEFER;
} else
return -EPROBE_DEFER;
}
- return component_add(&pdev->dev, &exynos_dp_ops);
+out:
+ pm_runtime_enable(dev);
+
+ ret = component_add(&pdev->dev, &exynos_dp_ops);
+ if (ret)
+ goto err_disable_pm_runtime;
+
+ return ret;
+
+err_disable_pm_runtime:
+ pm_runtime_disable(dev);
+
+ return ret;
}
static int exynos_dp_remove(struct platform_device *pdev)
{
+ pm_runtime_disable(&pdev->dev);
component_del(&pdev->dev, &exynos_dp_ops);
return 0;
}
+#ifdef CONFIG_PM
+static int exynos_dp_suspend(struct device *dev)
+{
+ struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(dp->clock);
+
+ return 0;
+}
+
+static int exynos_dp_resume(struct device *dev)
+{
+ struct exynos_dp_device *dp = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(dp->clock);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dp_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL)
+};
+
static const struct of_device_id exynos_dp_match[] = {
{ .compatible = "samsung,exynos5-dp" },
{},
@@ -1395,6 +1505,7 @@ struct platform_driver dp_driver = {
.driver = {
.name = "exynos-dp",
.owner = THIS_MODULE,
+ .pm = &exynos_dp_pm_ops,
.of_match_table = exynos_dp_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index e413b6f7b0e7..66eec4b2d5c6 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -153,6 +153,7 @@ struct exynos_dp_device {
struct drm_connector connector;
struct drm_panel *panel;
struct drm_bridge *bridge;
+ struct drm_bridge *ptn_bridge;
struct clk *clock;
unsigned int irq;
void __iomem *reg_base;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index e69357172ffb..e36579c1c025 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -68,35 +68,23 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct drm_plane *plane;
exynos_crtc->event = crtc->state->event;
- drm_atomic_crtc_for_each_plane(plane, crtc) {
- struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-
- if (exynos_crtc->ops->atomic_begin)
- exynos_crtc->ops->atomic_begin(exynos_crtc,
- exynos_plane);
- }
+ if (exynos_crtc->ops->atomic_begin)
+ exynos_crtc->ops->atomic_begin(exynos_crtc);
}
static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct drm_plane *plane;
- drm_atomic_crtc_for_each_plane(plane, crtc) {
- struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-
- if (exynos_crtc->ops->atomic_flush)
- exynos_crtc->ops->atomic_flush(exynos_crtc,
- exynos_plane);
- }
+ if (exynos_crtc->ops->atomic_flush)
+ exynos_crtc->ops->atomic_flush(exynos_crtc);
}
-static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
+static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.enable = exynos_drm_crtc_enable,
.disable = exynos_drm_crtc_disable,
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
@@ -116,7 +104,7 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
kfree(exynos_crtc);
}
-static struct drm_crtc_funcs exynos_crtc_funcs = {
+static const struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.destroy = exynos_drm_crtc_destroy,
@@ -153,7 +141,7 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
private->crtc[pipe] = crtc;
ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
- &exynos_crtc_funcs);
+ &exynos_crtc_funcs, NULL);
if (ret < 0)
goto err_crtc;
@@ -215,29 +203,6 @@ void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
-void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
-{
- struct exynos_drm_crtc *exynos_crtc;
- struct drm_device *dev = fb->dev;
- struct drm_crtc *crtc;
-
- /*
- * make sure that overlay data are updated to real hardware
- * for all encoders.
- */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- exynos_crtc = to_exynos_crtc(crtc);
-
- /*
- * wait for vblank interrupt
- * - this makes sure that overlay data are updated to
- * real hardware.
- */
- if (exynos_crtc->ops->wait_for_vblank)
- exynos_crtc->ops->wait_for_vblank(exynos_crtc);
- }
-}
-
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
enum exynos_drm_output_type out_type)
{
@@ -261,3 +226,29 @@ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
if (exynos_crtc->ops->te_handler)
exynos_crtc->ops->te_handler(exynos_crtc);
}
+
+void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
+ struct drm_file *file)
+{
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct drm_pending_vblank_event *e;
+ unsigned long flags;
+
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ e = exynos_crtc->event;
+ if (e && e->base.file_priv == file) {
+ exynos_crtc->event = NULL;
+ /*
+ * event will be destroyed by core part
+ * so below line should be removed later with core changes
+ */
+ e->base.destroy(&e->base);
+ /*
+ * event_space will be increased by core part
+ * so below line should be removed later with core changes.
+ */
+ file->event_space += sizeof(e->event);
+ atomic_dec(&exynos_crtc->pending_update);
+ }
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index f9f365bd0257..cfdcf3e4eb1b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -28,7 +28,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe);
void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc);
void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
struct exynos_drm_plane *exynos_plane);
-void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
/* This function gets pipe value to crtc device matched with out_type. */
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
@@ -41,4 +40,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
*/
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc);
+/* This function cancels a page flip request. */
+void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
+ struct drm_file *file);
+
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index c748b8790de3..05350ae0785b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -57,7 +57,7 @@ static void exynos_dpi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs exynos_dpi_connector_funcs = {
+static const struct drm_connector_funcs exynos_dpi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = exynos_dpi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -100,7 +100,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector)
return &ctx->encoder;
}
-static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
.get_modes = exynos_dpi_get_modes,
.best_encoder = exynos_dpi_best_encoder,
};
@@ -161,14 +161,14 @@ static void exynos_dpi_disable(struct drm_encoder *encoder)
}
}
-static struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
.mode_fixup = exynos_dpi_mode_fixup,
.mode_set = exynos_dpi_mode_set,
.enable = exynos_dpi_enable,
.disable = exynos_dpi_disable,
};
-static struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
+static const struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -309,7 +309,7 @@ int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2c6019d6a205..68f0f36f6e7e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -304,45 +304,6 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
-{
- struct drm_connector *connector;
-
- drm_modeset_lock_all(dev);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- int old_dpms = connector->dpms;
-
- if (connector->funcs->dpms)
- connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
-
- /* Set the old mode back to the connector for resume */
- connector->dpms = old_dpms;
- }
- drm_modeset_unlock_all(dev);
-
- return 0;
-}
-
-static int exynos_drm_resume(struct drm_device *dev)
-{
- struct drm_connector *connector;
-
- drm_modeset_lock_all(dev);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->funcs->dpms) {
- int dpms = connector->dpms;
-
- connector->dpms = DRM_MODE_DPMS_OFF;
- connector->funcs->dpms(connector, dpms);
- }
- }
- drm_modeset_unlock_all(dev);
-
- return 0;
-}
-#endif
-
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_exynos_file_private *file_priv;
@@ -369,7 +330,12 @@ err_file_priv_free:
static void exynos_drm_preclose(struct drm_device *dev,
struct drm_file *file)
{
+ struct drm_crtc *crtc;
+
exynos_drm_subdrv_close(dev, file);
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ exynos_drm_crtc_cancel_page_flip(crtc, file);
}
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
@@ -476,31 +442,54 @@ static struct drm_driver exynos_drm_driver = {
};
#ifdef CONFIG_PM_SLEEP
-static int exynos_drm_sys_suspend(struct device *dev)
+static int exynos_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
- pm_message_t message;
+ struct drm_connector *connector;
if (pm_runtime_suspended(dev) || !drm_dev)
return 0;
- message.event = PM_EVENT_SUSPEND;
- return exynos_drm_suspend(drm_dev, message);
+ drm_modeset_lock_all(drm_dev);
+ drm_for_each_connector(connector, drm_dev) {
+ int old_dpms = connector->dpms;
+
+ if (connector->funcs->dpms)
+ connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
+ /* Set the old mode back to the connector for resume */
+ connector->dpms = old_dpms;
+ }
+ drm_modeset_unlock_all(drm_dev);
+
+ return 0;
}
-static int exynos_drm_sys_resume(struct device *dev)
+static int exynos_drm_resume(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
+ struct drm_connector *connector;
if (pm_runtime_suspended(dev) || !drm_dev)
return 0;
- return exynos_drm_resume(drm_dev);
+ drm_modeset_lock_all(drm_dev);
+ drm_for_each_connector(connector, drm_dev) {
+ if (connector->funcs->dpms) {
+ int dpms = connector->dpms;
+
+ connector->dpms = DRM_MODE_DPMS_OFF;
+ connector->funcs->dpms(connector, dpms);
+ }
+ }
+ drm_modeset_unlock_all(drm_dev);
+
+ return 0;
}
#endif
static const struct dev_pm_ops exynos_drm_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume)
};
/* forward declaration */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index f1eda7fa4e3c..17b5ded72ff1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -38,25 +38,46 @@ enum exynos_drm_output_type {
EXYNOS_DISPLAY_TYPE_VIDI,
};
+struct exynos_drm_rect {
+ unsigned int x, y;
+ unsigned int w, h;
+};
+
/*
- * Exynos drm common overlay structure.
+ * Exynos drm plane state structure.
*
- * @base: plane object
- * @src_x: offset x on a framebuffer to be displayed.
- * - the unit is screen coordinates.
- * @src_y: offset y on a framebuffer to be displayed.
- * - the unit is screen coordinates.
- * @src_w: width of a partial image to be displayed from framebuffer.
- * @src_h: height of a partial image to be displayed from framebuffer.
- * @crtc_x: offset x on hardware screen.
- * @crtc_y: offset y on hardware screen.
- * @crtc_w: window width to be displayed (hardware screen).
- * @crtc_h: window height to be displayed (hardware screen).
+ * @base: plane_state object (contains drm_framebuffer pointer)
+ * @src: rectangle of the source image data to be displayed (clipped to
+ * visible part).
+ * @crtc: rectangle of the target image position on hardware screen
+ * (clipped to visible part).
* @h_ratio: horizontal scaling ratio, 16.16 fixed point
* @v_ratio: vertical scaling ratio, 16.16 fixed point
- * @dma_addr: array of bus(accessed by dma) address to the memory region
- * allocated for a overlay.
- * @zpos: order of overlay layer(z position).
+ *
+ * this structure consists plane state data that will be applied to hardware
+ * specific overlay info.
+ */
+
+struct exynos_drm_plane_state {
+ struct drm_plane_state base;
+ struct exynos_drm_rect crtc;
+ struct exynos_drm_rect src;
+ unsigned int h_ratio;
+ unsigned int v_ratio;
+ unsigned int zpos;
+};
+
+static inline struct exynos_drm_plane_state *
+to_exynos_plane_state(struct drm_plane_state *state)
+{
+ return container_of(state, struct exynos_drm_plane_state, base);
+}
+
+/*
+ * Exynos drm common overlay structure.
+ *
+ * @base: plane object
+ * @index: hardware index of the overlay layer
*
* this structure is common to exynos SoC and its contents would be copied
* to hardware specific overlay info.
@@ -64,21 +85,33 @@ enum exynos_drm_output_type {
struct exynos_drm_plane {
struct drm_plane base;
- unsigned int src_x;
- unsigned int src_y;
- unsigned int src_w;
- unsigned int src_h;
- unsigned int crtc_x;
- unsigned int crtc_y;
- unsigned int crtc_w;
- unsigned int crtc_h;
- unsigned int h_ratio;
- unsigned int v_ratio;
- dma_addr_t dma_addr[MAX_FB_BUFFER];
- unsigned int zpos;
+ const struct exynos_drm_plane_config *config;
+ unsigned int index;
struct drm_framebuffer *pending_fb;
};
+#define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0)
+#define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1)
+#define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2)
+
+/*
+ * Exynos DRM plane configuration structure.
+ *
+ * @zpos: initial z-position of the plane.
+ * @type: type of the plane (primary, cursor or overlay).
+ * @pixel_formats: supported pixel formats.
+ * @num_pixel_formats: number of elements in 'pixel_formats'.
+ * @capabilities: supported features (see EXYNOS_DRM_PLANE_CAP_*)
+ */
+
+struct exynos_drm_plane_config {
+ unsigned int zpos;
+ enum drm_plane_type type;
+ const uint32_t *pixel_formats;
+ unsigned int num_pixel_formats;
+ unsigned int capabilities;
+};
+
/*
* Exynos drm crtc ops
*
@@ -90,8 +123,8 @@ struct exynos_drm_plane {
* @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated.
* @atomic_check: validate state
- * @atomic_begin: prepare a window to receive a update
- * @atomic_flush: mark the end of a window update
+ * @atomic_begin: prepare device to receive an update
+ * @atomic_flush: mark the end of device update
* @update_plane: apply hardware specific overlay data to registers.
* @disable_plane: disable hardware specific overlay.
* @te_handler: trigger to transfer video image at the tearing effect
@@ -111,14 +144,12 @@ struct exynos_drm_crtc_ops {
void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
int (*atomic_check)(struct exynos_drm_crtc *crtc,
struct drm_crtc_state *state);
- void (*atomic_begin)(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane);
+ void (*atomic_begin)(struct exynos_drm_crtc *crtc);
void (*update_plane)(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane);
void (*disable_plane)(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane);
- void (*atomic_flush)(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane);
+ void (*atomic_flush)(struct exynos_drm_crtc *crtc);
void (*te_handler)(struct exynos_drm_crtc *crtc);
void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable);
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 12b03b364703..d84a498ef099 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1458,66 +1458,6 @@ static const struct mipi_dsi_host_ops exynos_dsi_ops = {
.transfer = exynos_dsi_host_transfer,
};
-static int exynos_dsi_poweron(struct exynos_dsi *dsi)
-{
- struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
- int ret, i;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
- if (ret < 0) {
- dev_err(dsi->dev, "cannot enable regulators %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < driver_data->num_clks; i++) {
- ret = clk_prepare_enable(dsi->clks[i]);
- if (ret < 0)
- goto err_clk;
- }
-
- ret = phy_power_on(dsi->phy);
- if (ret < 0) {
- dev_err(dsi->dev, "cannot enable phy %d\n", ret);
- goto err_clk;
- }
-
- return 0;
-
-err_clk:
- while (--i > -1)
- clk_disable_unprepare(dsi->clks[i]);
- regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
-
- return ret;
-}
-
-static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
-{
- struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
- int ret, i;
-
- usleep_range(10000, 20000);
-
- if (dsi->state & DSIM_STATE_INITIALIZED) {
- dsi->state &= ~DSIM_STATE_INITIALIZED;
-
- exynos_dsi_disable_clock(dsi);
-
- exynos_dsi_disable_irq(dsi);
- }
-
- dsi->state &= ~DSIM_STATE_CMD_LPM;
-
- phy_power_off(dsi->phy);
-
- for (i = driver_data->num_clks - 1; i > -1; i--)
- clk_disable_unprepare(dsi->clks[i]);
-
- ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
- if (ret < 0)
- dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
-}
-
static void exynos_dsi_enable(struct drm_encoder *encoder)
{
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
@@ -1526,16 +1466,14 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
if (dsi->state & DSIM_STATE_ENABLED)
return;
- ret = exynos_dsi_poweron(dsi);
- if (ret < 0)
- return;
+ pm_runtime_get_sync(dsi->dev);
dsi->state |= DSIM_STATE_ENABLED;
ret = drm_panel_prepare(dsi->panel);
if (ret < 0) {
dsi->state &= ~DSIM_STATE_ENABLED;
- exynos_dsi_poweroff(dsi);
+ pm_runtime_put_sync(dsi->dev);
return;
}
@@ -1547,7 +1485,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
dsi->state &= ~DSIM_STATE_ENABLED;
exynos_dsi_set_display_enable(dsi, false);
drm_panel_unprepare(dsi->panel);
- exynos_dsi_poweroff(dsi);
+ pm_runtime_put_sync(dsi->dev);
return;
}
@@ -1569,7 +1507,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
dsi->state &= ~DSIM_STATE_ENABLED;
- exynos_dsi_poweroff(dsi);
+ pm_runtime_put_sync(dsi->dev);
}
static enum drm_connector_status
@@ -1603,7 +1541,7 @@ static void exynos_dsi_connector_destroy(struct drm_connector *connector)
connector->dev = NULL;
}
-static struct drm_connector_funcs exynos_dsi_connector_funcs = {
+static const struct drm_connector_funcs exynos_dsi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = exynos_dsi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1631,7 +1569,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
return &dsi->encoder;
}
-static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
.get_modes = exynos_dsi_get_modes,
.best_encoder = exynos_dsi_best_encoder,
};
@@ -1684,14 +1622,14 @@ static void exynos_dsi_mode_set(struct drm_encoder *encoder,
vm->hsync_len = m->hsync_end - m->hsync_start;
}
-static struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
.mode_fixup = exynos_dsi_mode_fixup,
.mode_set = exynos_dsi_mode_set,
.enable = exynos_dsi_enable,
.disable = exynos_dsi_disable,
};
-static struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
+static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -1797,13 +1735,13 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
ep = of_graph_get_next_endpoint(node, NULL);
if (!ep) {
- ret = -ENXIO;
+ ret = -EINVAL;
goto end;
}
dsi->bridge_node = of_graph_get_remote_port_parent(ep);
if (!dsi->bridge_node) {
- ret = -ENXIO;
+ ret = -EINVAL;
goto end;
}
end:
@@ -1831,7 +1769,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
@@ -1954,22 +1892,99 @@ static int exynos_dsi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &dsi->encoder);
+ pm_runtime_enable(dev);
+
return component_add(dev, &exynos_dsi_component_ops);
}
static int exynos_dsi_remove(struct platform_device *pdev)
{
+ pm_runtime_disable(&pdev->dev);
+
component_del(&pdev->dev, &exynos_dsi_component_ops);
return 0;
}
+#ifdef CONFIG_PM
+static int exynos_dsi_suspend(struct device *dev)
+{
+ struct drm_encoder *encoder = dev_get_drvdata(dev);
+ struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+ struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
+ int ret, i;
+
+ usleep_range(10000, 20000);
+
+ if (dsi->state & DSIM_STATE_INITIALIZED) {
+ dsi->state &= ~DSIM_STATE_INITIALIZED;
+
+ exynos_dsi_disable_clock(dsi);
+
+ exynos_dsi_disable_irq(dsi);
+ }
+
+ dsi->state &= ~DSIM_STATE_CMD_LPM;
+
+ phy_power_off(dsi->phy);
+
+ for (i = driver_data->num_clks - 1; i > -1; i--)
+ clk_disable_unprepare(dsi->clks[i]);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
+ if (ret < 0)
+ dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
+
+ return 0;
+}
+
+static int exynos_dsi_resume(struct device *dev)
+{
+ struct drm_encoder *encoder = dev_get_drvdata(dev);
+ struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+ struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
+ int ret, i;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
+ if (ret < 0) {
+ dev_err(dsi->dev, "cannot enable regulators %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < driver_data->num_clks; i++) {
+ ret = clk_prepare_enable(dsi->clks[i]);
+ if (ret < 0)
+ goto err_clk;
+ }
+
+ ret = phy_power_on(dsi->phy);
+ if (ret < 0) {
+ dev_err(dsi->dev, "cannot enable phy %d\n", ret);
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+ while (--i > -1)
+ clk_disable_unprepare(dsi->clks[i]);
+ regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dsi_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL)
+};
+
struct platform_driver dsi_driver = {
.probe = exynos_dsi_probe,
.remove = exynos_dsi_remove,
.driver = {
.name = "exynos-dsi",
.owner = THIS_MODULE,
+ .pm = &exynos_dsi_pm_ops,
.of_match_table = exynos_dsi_of_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index fcea28bdbc42..d614194644c8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -37,6 +37,7 @@
struct exynos_drm_fb {
struct drm_framebuffer fb;
struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
+ dma_addr_t dma_addr[MAX_FB_BUFFER];
};
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
@@ -70,9 +71,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
unsigned int i;
- /* make sure that overlay data are updated before relesing fb. */
- exynos_drm_crtc_complete_scanout(fb);
-
drm_framebuffer_cleanup(fb);
for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem); i++) {
@@ -109,7 +107,7 @@ static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
return 0;
}
-static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
+static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
.destroy = exynos_drm_fb_destroy,
.create_handle = exynos_drm_fb_create_handle,
.dirty = exynos_drm_fb_dirty,
@@ -117,7 +115,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct exynos_drm_gem **exynos_gem,
int count)
{
@@ -135,6 +133,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
goto err;
exynos_fb->exynos_gem[i] = exynos_gem[i];
+ exynos_fb->dma_addr[i] = exynos_gem[i]->dma_addr
+ + mode_cmd->offsets[i];
}
drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
@@ -154,7 +154,7 @@ err:
static struct drm_framebuffer *
exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
struct drm_gem_object *obj;
@@ -189,21 +189,14 @@ err:
return ERR_PTR(ret);
}
-struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index)
+dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
- struct exynos_drm_gem *exynos_gem;
if (index >= MAX_FB_BUFFER)
- return NULL;
-
- exynos_gem = exynos_fb->exynos_gem[index];
- if (!exynos_gem)
- return NULL;
-
- DRM_DEBUG_KMS("dma_addr: 0x%lx\n", (unsigned long)exynos_gem->dma_addr);
+ return DMA_ERROR_CODE;
- return exynos_gem;
+ return exynos_fb->dma_addr[index];
}
static void exynos_drm_output_poll_changed(struct drm_device *dev)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
index 726a2d44371f..3a9e75b2cf6b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -12,18 +12,17 @@
*/
#ifndef _EXYNOS_DRM_FB_H_
-#define _EXYNOS_DRM_FB_H
+#define _EXYNOS_DRM_FB_H_
#include "exynos_drm_gem.h"
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct exynos_drm_gem **exynos_gem,
int count);
-/* get gem object of a drm framebuffer */
-struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index);
+dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index);
void exynos_drm_mode_config_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index bd75c1531cac..70194d0e4fe4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -29,6 +29,7 @@
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
+#include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_plane.h"
@@ -87,7 +88,6 @@
/* FIMD has totally five hardware windows. */
#define WINDOWS_NR 5
-#define CURSOR_WIN 4
struct fimd_driver_data {
unsigned int timing_base;
@@ -150,6 +150,7 @@ struct fimd_context {
struct drm_device *drm_dev;
struct exynos_drm_crtc *crtc;
struct exynos_drm_plane planes[WINDOWS_NR];
+ struct exynos_drm_plane_config configs[WINDOWS_NR];
struct clk *bus_clk;
struct clk *lcd_clk;
void __iomem *regs;
@@ -187,6 +188,14 @@ static const struct of_device_id fimd_driver_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
+static const enum drm_plane_type fimd_win_types[WINDOWS_NR] = {
+ DRM_PLANE_TYPE_PRIMARY,
+ DRM_PLANE_TYPE_OVERLAY,
+ DRM_PLANE_TYPE_OVERLAY,
+ DRM_PLANE_TYPE_OVERLAY,
+ DRM_PLANE_TYPE_CURSOR,
+};
+
static const uint32_t fimd_formats[] = {
DRM_FORMAT_C8,
DRM_FORMAT_XRGB1555,
@@ -478,7 +487,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
- struct drm_framebuffer *fb)
+ uint32_t pixel_format, int width)
{
unsigned long val;
@@ -489,11 +498,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
* So the request format is ARGB8888 then change it to XRGB8888.
*/
if (ctx->driver_data->has_limited_fmt && !win) {
- if (fb->pixel_format == DRM_FORMAT_ARGB8888)
- fb->pixel_format = DRM_FORMAT_XRGB8888;
+ if (pixel_format == DRM_FORMAT_ARGB8888)
+ pixel_format = DRM_FORMAT_XRGB8888;
}
- switch (fb->pixel_format) {
+ switch (pixel_format) {
case DRM_FORMAT_C8:
val |= WINCON0_BPPMODE_8BPP_PALETTE;
val |= WINCONx_BURSTLEN_8WORD;
@@ -529,17 +538,15 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
break;
}
- DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
-
/*
- * In case of exynos, setting dma-burst to 16Word causes permanent
- * tearing for very small buffers, e.g. cursor buffer. Burst Mode
- * switching which is based on plane size is not recommended as
- * plane size varies alot towards the end of the screen and rapid
- * movement causes unstable DMA which results into iommu crash/tear.
+ * Setting dma-burst to 16Word causes permanent tearing for very small
+ * buffers, e.g. cursor buffer. Burst Mode switching which based on
+ * plane size is not recommended as plane size varies alot towards the
+ * end of the screen and rapid movement causes unstable DMA, but it is
+ * still better to change dma-burst than displaying garbage.
*/
- if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+ if (width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_4WORD;
}
@@ -615,64 +622,68 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
writel(val, ctx->regs + reg);
}
-static void fimd_atomic_begin(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane)
+static void fimd_atomic_begin(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
+ int i;
if (ctx->suspended)
return;
- fimd_shadow_protect_win(ctx, plane->zpos, true);
+ for (i = 0; i < WINDOWS_NR; i++)
+ fimd_shadow_protect_win(ctx, i, true);
}
-static void fimd_atomic_flush(struct exynos_drm_crtc *crtc,
- struct exynos_drm_plane *plane)
+static void fimd_atomic_flush(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
+ int i;
if (ctx->suspended)
return;
- fimd_shadow_protect_win(ctx, plane->zpos, false);
+ for (i = 0; i < WINDOWS_NR; i++)
+ fimd_shadow_protect_win(ctx, i, false);
}
static void fimd_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
+ struct exynos_drm_plane_state *state =
+ to_exynos_plane_state(plane->base.state);
struct fimd_context *ctx = crtc->ctx;
- struct drm_plane_state *state = plane->base.state;
+ struct drm_framebuffer *fb = state->base.fb;
dma_addr_t dma_addr;
unsigned long val, size, offset;
unsigned int last_x, last_y, buf_offsize, line_size;
- unsigned int win = plane->zpos;
- unsigned int bpp = state->fb->bits_per_pixel >> 3;
- unsigned int pitch = state->fb->pitches[0];
+ unsigned int win = plane->index;
+ unsigned int bpp = fb->bits_per_pixel >> 3;
+ unsigned int pitch = fb->pitches[0];
if (ctx->suspended)
return;
- offset = plane->src_x * bpp;
- offset += plane->src_y * pitch;
+ offset = state->src.x * bpp;
+ offset += state->src.y * pitch;
/* buffer start address */
- dma_addr = plane->dma_addr[0] + offset;
+ dma_addr = exynos_drm_fb_dma_addr(fb, 0) + offset;
val = (unsigned long)dma_addr;
writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
/* buffer end address */
- size = pitch * plane->crtc_h;
+ size = pitch * state->crtc.h;
val = (unsigned long)(dma_addr + size);
writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
(unsigned long)dma_addr, val, size);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
- plane->crtc_w, plane->crtc_h);
+ state->crtc.w, state->crtc.h);
/* buffer size */
- buf_offsize = pitch - (plane->crtc_w * bpp);
- line_size = plane->crtc_w * bpp;
+ buf_offsize = pitch - (state->crtc.w * bpp);
+ line_size = state->crtc.w * bpp;
val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
@@ -680,16 +691,16 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
/* OSD position */
- val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
- VIDOSDxA_TOPLEFT_Y(plane->crtc_y) |
- VIDOSDxA_TOPLEFT_X_E(plane->crtc_x) |
- VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y);
+ val = VIDOSDxA_TOPLEFT_X(state->crtc.x) |
+ VIDOSDxA_TOPLEFT_Y(state->crtc.y) |
+ VIDOSDxA_TOPLEFT_X_E(state->crtc.x) |
+ VIDOSDxA_TOPLEFT_Y_E(state->crtc.y);
writel(val, ctx->regs + VIDOSD_A(win));
- last_x = plane->crtc_x + plane->crtc_w;
+ last_x = state->crtc.x + state->crtc.w;
if (last_x)
last_x--;
- last_y = plane->crtc_y + plane->crtc_h;
+ last_y = state->crtc.y + state->crtc.h;
if (last_y)
last_y--;
@@ -699,20 +710,20 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
writel(val, ctx->regs + VIDOSD_B(win));
DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
- plane->crtc_x, plane->crtc_y, last_x, last_y);
+ state->crtc.x, state->crtc.y, last_x, last_y);
/* OSD size */
if (win != 3 && win != 4) {
u32 offset = VIDOSD_D(win);
if (win == 0)
offset = VIDOSD_C(win);
- val = plane->crtc_w * plane->crtc_h;
+ val = state->crtc.w * state->crtc.h;
writel(val, ctx->regs + offset);
DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
}
- fimd_win_set_pixfmt(ctx, win, state->fb);
+ fimd_win_set_pixfmt(ctx, win, fb->pixel_format, state->src.w);
/* hardware window 0 doesn't support color key. */
if (win != 0)
@@ -731,7 +742,7 @@ static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct fimd_context *ctx = crtc->ctx;
- unsigned int win = plane->zpos;
+ unsigned int win = plane->index;
if (ctx->suspended)
return;
@@ -745,7 +756,6 @@ static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
static void fimd_enable(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
- int ret;
if (!ctx->suspended)
return;
@@ -754,18 +764,6 @@ static void fimd_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev);
- ret = clk_prepare_enable(ctx->bus_clk);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
- return;
- }
-
- ret = clk_prepare_enable(ctx->lcd_clk);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
- return;
- }
-
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
fimd_enable_vblank(ctx->crtc);
@@ -795,11 +793,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc)
writel(0, ctx->regs + VIDCON0);
- clk_disable_unprepare(ctx->lcd_clk);
- clk_disable_unprepare(ctx->bus_clk);
-
pm_runtime_put_sync(ctx->dev);
-
ctx->suspended = true;
}
@@ -941,18 +935,19 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm_dev = data;
struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane;
- enum drm_plane_type type;
- unsigned int zpos;
+ unsigned int i;
int ret;
ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
- for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
- type = exynos_plane_get_type(zpos, CURSOR_WIN);
- ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
- 1 << ctx->pipe, type, fimd_formats,
- ARRAY_SIZE(fimd_formats), zpos);
+ for (i = 0; i < WINDOWS_NR; i++) {
+ ctx->configs[i].pixel_formats = fimd_formats;
+ ctx->configs[i].num_pixel_formats = ARRAY_SIZE(fimd_formats);
+ ctx->configs[i].zpos = i;
+ ctx->configs[i].type = fimd_win_types[i];
+ ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
+ 1 << ctx->pipe, &ctx->configs[i]);
if (ret)
return ret;
}
@@ -1121,12 +1116,49 @@ static int fimd_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int exynos_fimd_suspend(struct device *dev)
+{
+ struct fimd_context *ctx = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(ctx->lcd_clk);
+ clk_disable_unprepare(ctx->bus_clk);
+
+ return 0;
+}
+
+static int exynos_fimd_resume(struct device *dev)
+{
+ struct fimd_context *ctx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(ctx->bus_clk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(ctx->lcd_clk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_fimd_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL)
+};
+
struct platform_driver fimd_driver = {
.probe = fimd_probe,
.remove = fimd_remove,
.driver = {
.name = "exynos4-fb",
.owner = THIS_MODULE,
+ .pm = &exynos_fimd_pm_ops,
.of_match_table = fimd_driver_dt_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 252eb301470c..32358c5e3db4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -14,6 +14,7 @@
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
+#include <linux/pfn_t.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
@@ -490,7 +491,8 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
}
pfn = page_to_pfn(exynos_gem->pages[page_offset]);
- ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
+ ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
+ __pfn_to_pfn_t(pfn, PFN_DEV));
out:
switch (ret) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 37ab8b282db6..9ca5047959ec 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -55,8 +55,6 @@ struct exynos_drm_gem {
struct sg_table *sgt;
};
-struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-
/* destroy a buffer with gem object */
void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem);
@@ -91,10 +89,6 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *filp);
-/* map user space allocated by malloc to pages. */
-int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-
/* get buffer information to memory region allocated by gem. */
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -123,28 +117,6 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
- return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
-}
-
-/* get a copy of a virtual memory region. */
-struct vm_area_struct *exynos_gem_get_vma(struct vm_area_struct *vma);
-
-/* release a userspace virtual memory area. */
-void exynos_gem_put_vma(struct vm_area_struct *vma);
-
-/* get pages from user space. */
-int exynos_gem_get_pages_from_userptr(unsigned long start,
- unsigned int npages,
- struct page **pages,
- struct vm_area_struct *vma);
-
-/* drop the reference to pages. */
-void exynos_gem_put_pages_to_userptr(struct page **pages,
- unsigned int npages,
- struct vm_area_struct *vma);
-
/* map sgt with dma region. */
int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,
struct sg_table *sgt,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 11b87d2a7913..7aecd23cfa11 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -15,7 +15,8 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
-#include <plat/map-base.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
@@ -126,6 +127,7 @@ struct gsc_capability {
* @ippdrv: prepare initialization using ippdrv.
* @regs_res: register resources.
* @regs: memory mapped io registers.
+ * @sysreg: handle to SYSREG block regmap.
* @lock: locking of operations.
* @gsc_clk: gsc gate clock.
* @sc: scaler infomations.
@@ -138,6 +140,7 @@ struct gsc_context {
struct exynos_drm_ippdrv ippdrv;
struct resource *regs_res;
void __iomem *regs;
+ struct regmap *sysreg;
struct mutex lock;
struct clk *gsc_clk;
struct gsc_scaler sc;
@@ -437,9 +440,12 @@ static int gsc_sw_reset(struct gsc_context *ctx)
static void gsc_set_gscblk_fimd_wb(struct gsc_context *ctx, bool enable)
{
- u32 gscblk_cfg;
+ unsigned int gscblk_cfg;
- gscblk_cfg = readl(SYSREG_GSCBLK_CFG1);
+ if (!ctx->sysreg)
+ return;
+
+ regmap_read(ctx->sysreg, SYSREG_GSCBLK_CFG1, &gscblk_cfg);
if (enable)
gscblk_cfg |= GSC_BLK_DISP1WB_DEST(ctx->id) |
@@ -448,7 +454,7 @@ static void gsc_set_gscblk_fimd_wb(struct gsc_context *ctx, bool enable)
else
gscblk_cfg |= GSC_BLK_PXLASYNC_LO_MASK_WB(ctx->id);
- writel(gscblk_cfg, SYSREG_GSCBLK_CFG1);
+ regmap_write(ctx->sysreg, SYSREG_GSCBLK_CFG1, gscblk_cfg);
}
static void gsc_handle_irq(struct gsc_context *ctx, bool enable,
@@ -1215,10 +1221,10 @@ static int gsc_clk_ctrl(struct gsc_context *ctx, bool enable)
DRM_DEBUG_KMS("enable[%d]\n", enable);
if (enable) {
- clk_enable(ctx->gsc_clk);
+ clk_prepare_enable(ctx->gsc_clk);
ctx->suspended = false;
} else {
- clk_disable(ctx->gsc_clk);
+ clk_disable_unprepare(ctx->gsc_clk);
ctx->suspended = true;
}
@@ -1663,6 +1669,15 @@ static int gsc_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
+ if (dev->of_node) {
+ ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,sysreg");
+ if (IS_ERR(ctx->sysreg)) {
+ dev_warn(dev, "failed to get system register.\n");
+ ctx->sysreg = NULL;
+ }
+ }
+
/* clock control */
ctx->gsc_clk = devm_clk_get(dev, "gscl");
if (IS_ERR(ctx->gsc_clk)) {
@@ -1713,7 +1728,6 @@ static int gsc_probe(struct platform_device *pdev)
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
- pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = exynos_drm_ippdrv_register(ippdrv);
@@ -1797,6 +1811,12 @@ static const struct dev_pm_ops gsc_pm_ops = {
SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
+static const struct of_device_id exynos_drm_gsc_of_match[] = {
+ { .compatible = "samsung,exynos5-gsc" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, exynos_drm_gsc_of_match);
+
struct platform_driver gsc_driver = {
.probe = gsc_probe,
.remove = gsc_remove,
@@ -1804,6 +1824,7 @@ struct platform_driver gsc_driver = {
.name = "exynos-drm-gsc",
.owner = THIS_MODULE,
.pm = &gsc_pm_ops,
+ .of_match_table = of_match_ptr(exynos_drm_gsc_of_match),
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 8994eab56ba8..4eaef36aec5a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -389,7 +389,7 @@ already_disabled:
mutex_unlock(&mic_mutex);
}
-struct drm_bridge_funcs mic_bridge_funcs = {
+static const struct drm_bridge_funcs mic_bridge_funcs = {
.disable = mic_disable,
.post_disable = mic_post_disable,
.pre_enable = mic_pre_enable,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 179311760bb7..d86227236f55 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -56,93 +56,213 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last)
return size;
}
-static void exynos_plane_mode_set(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h)
+static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state)
+
{
- struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+ struct drm_plane_state *state = &exynos_state->base;
+ struct drm_crtc *crtc = exynos_state->base.crtc;
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ int crtc_x, crtc_y;
+ unsigned int crtc_w, crtc_h;
+ unsigned int src_x, src_y;
+ unsigned int src_w, src_h;
unsigned int actual_w;
unsigned int actual_h;
+ /*
+ * The original src/dest coordinates are stored in exynos_state->base,
+ * but we want to keep another copy internal to our driver that we can
+ * clip/modify ourselves.
+ */
+
+ crtc_x = state->crtc_x;
+ crtc_y = state->crtc_y;
+ crtc_w = state->crtc_w;
+ crtc_h = state->crtc_h;
+
+ src_x = state->src_x >> 16;
+ src_y = state->src_y >> 16;
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+
+ /* set ratio */
+ exynos_state->h_ratio = (src_w << 16) / crtc_w;
+ exynos_state->v_ratio = (src_h << 16) / crtc_h;
+
+ /* clip to visible area */
actual_w = exynos_plane_get_size(crtc_x, crtc_w, mode->hdisplay);
actual_h = exynos_plane_get_size(crtc_y, crtc_h, mode->vdisplay);
if (crtc_x < 0) {
if (actual_w)
- src_x -= crtc_x;
+ src_x += ((-crtc_x) * exynos_state->h_ratio) >> 16;
crtc_x = 0;
}
if (crtc_y < 0) {
if (actual_h)
- src_y -= crtc_y;
+ src_y += ((-crtc_y) * exynos_state->v_ratio) >> 16;
crtc_y = 0;
}
- /* set ratio */
- exynos_plane->h_ratio = (src_w << 16) / crtc_w;
- exynos_plane->v_ratio = (src_h << 16) / crtc_h;
-
/* set drm framebuffer data. */
- exynos_plane->src_x = src_x;
- exynos_plane->src_y = src_y;
- exynos_plane->src_w = (actual_w * exynos_plane->h_ratio) >> 16;
- exynos_plane->src_h = (actual_h * exynos_plane->v_ratio) >> 16;
+ exynos_state->src.x = src_x;
+ exynos_state->src.y = src_y;
+ exynos_state->src.w = (actual_w * exynos_state->h_ratio) >> 16;
+ exynos_state->src.h = (actual_h * exynos_state->v_ratio) >> 16;
/* set plane range to be displayed. */
- exynos_plane->crtc_x = crtc_x;
- exynos_plane->crtc_y = crtc_y;
- exynos_plane->crtc_w = actual_w;
- exynos_plane->crtc_h = actual_h;
+ exynos_state->crtc.x = crtc_x;
+ exynos_state->crtc.y = crtc_y;
+ exynos_state->crtc.w = actual_w;
+ exynos_state->crtc.h = actual_h;
DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
- exynos_plane->crtc_x, exynos_plane->crtc_y,
- exynos_plane->crtc_w, exynos_plane->crtc_h);
+ exynos_state->crtc.x, exynos_state->crtc.y,
+ exynos_state->crtc.w, exynos_state->crtc.h);
+}
+
+static void exynos_drm_plane_reset(struct drm_plane *plane)
+{
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+ struct exynos_drm_plane_state *exynos_state;
+
+ if (plane->state) {
+ exynos_state = to_exynos_plane_state(plane->state);
+ if (exynos_state->base.fb)
+ drm_framebuffer_unreference(exynos_state->base.fb);
+ kfree(exynos_state);
+ plane->state = NULL;
+ }
+
+ exynos_state = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
+ if (exynos_state) {
+ exynos_state->zpos = exynos_plane->config->zpos;
+ plane->state = &exynos_state->base;
+ plane->state->plane = plane;
+ }
+}
+
+static struct drm_plane_state *
+exynos_drm_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct exynos_drm_plane_state *exynos_state;
+ struct exynos_drm_plane_state *copy;
+
+ exynos_state = to_exynos_plane_state(plane->state);
+ copy = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+ copy->zpos = exynos_state->zpos;
+ return &copy->base;
+}
+
+static void exynos_drm_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct exynos_drm_plane_state *old_exynos_state =
+ to_exynos_plane_state(old_state);
+ __drm_atomic_helper_plane_destroy_state(plane, old_state);
+ kfree(old_exynos_state);
+}
+
+static int exynos_drm_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+ struct exynos_drm_plane_state *exynos_state =
+ to_exynos_plane_state(state);
+ struct exynos_drm_private *dev_priv = plane->dev->dev_private;
+ const struct exynos_drm_plane_config *config = exynos_plane->config;
- plane->crtc = crtc;
+ if (property == dev_priv->plane_zpos_property &&
+ (config->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS))
+ exynos_state->zpos = val;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int exynos_drm_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ const struct exynos_drm_plane_state *exynos_state =
+ container_of(state, const struct exynos_drm_plane_state, base);
+ struct exynos_drm_private *dev_priv = plane->dev->dev_private;
+
+ if (property == dev_priv->plane_zpos_property)
+ *val = exynos_state->zpos;
+ else
+ return -EINVAL;
+
+ return 0;
}
static struct drm_plane_funcs exynos_plane_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,
+ .set_property = drm_atomic_helper_plane_set_property,
+ .reset = exynos_drm_plane_reset,
+ .atomic_duplicate_state = exynos_drm_plane_duplicate_state,
+ .atomic_destroy_state = exynos_drm_plane_destroy_state,
+ .atomic_set_property = exynos_drm_plane_atomic_set_property,
+ .atomic_get_property = exynos_drm_plane_atomic_get_property,
};
+static int
+exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config,
+ struct exynos_drm_plane_state *state)
+{
+ bool width_ok = false, height_ok = false;
+
+ if (config->capabilities & EXYNOS_DRM_PLANE_CAP_SCALE)
+ return 0;
+
+ if (state->src.w == state->crtc.w)
+ width_ok = true;
+
+ if (state->src.h == state->crtc.h)
+ height_ok = true;
+
+ if ((config->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) &&
+ state->h_ratio == (1 << 15))
+ width_ok = true;
+
+ if ((config->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) &&
+ state->v_ratio == (1 << 15))
+ height_ok = true;
+
+ if (width_ok & height_ok)
+ return 0;
+
+ DRM_DEBUG_KMS("scaling mode is not supported");
+ return -ENOTSUPP;
+}
+
static int exynos_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
- int nr;
- int i;
+ struct exynos_drm_plane_state *exynos_state =
+ to_exynos_plane_state(state);
+ int ret = 0;
- if (!state->fb)
+ if (!state->crtc || !state->fb)
return 0;
- nr = drm_format_num_planes(state->fb->pixel_format);
- for (i = 0; i < nr; i++) {
- struct exynos_drm_gem *exynos_gem =
- exynos_drm_fb_gem(state->fb, i);
- if (!exynos_gem) {
- DRM_DEBUG_KMS("gem object is null\n");
- return -EFAULT;
- }
-
- exynos_plane->dma_addr[i] = exynos_gem->dma_addr +
- state->fb->offsets[i];
+ /* translate state into exynos_state */
+ exynos_plane_mode_set(exynos_state);
- DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
- i, (unsigned long)exynos_plane->dma_addr[i]);
- }
-
- return 0;
+ ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state);
+ return ret;
}
static void exynos_plane_atomic_update(struct drm_plane *plane,
@@ -155,12 +275,7 @@ static void exynos_plane_atomic_update(struct drm_plane *plane,
if (!state->crtc)
return;
- exynos_plane_mode_set(plane, state->crtc, state->fb,
- state->crtc_x, state->crtc_y,
- state->crtc_w, state->crtc_h,
- state->src_x >> 16, state->src_y >> 16,
- state->src_w >> 16, state->src_h >> 16);
-
+ plane->crtc = state->crtc;
exynos_plane->pending_fb = state->fb;
if (exynos_crtc->ops->update_plane)
@@ -177,8 +292,7 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane,
return;
if (exynos_crtc->ops->disable_plane)
- exynos_crtc->ops->disable_plane(exynos_crtc,
- exynos_plane);
+ exynos_crtc->ops->disable_plane(exynos_crtc, exynos_plane);
}
static const struct drm_plane_helper_funcs plane_helper_funcs = {
@@ -196,8 +310,8 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
prop = dev_priv->plane_zpos_property;
if (!prop) {
- prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
- "zpos", 0, MAX_PLANE - 1);
+ prop = drm_property_create_range(dev, 0, "zpos",
+ 0, MAX_PLANE - 1);
if (!prop)
return;
@@ -207,28 +321,19 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
drm_object_attach_property(&plane->base, prop, zpos);
}
-enum drm_plane_type exynos_plane_get_type(unsigned int zpos,
- unsigned int cursor_win)
-{
- if (zpos == DEFAULT_WIN)
- return DRM_PLANE_TYPE_PRIMARY;
- else if (zpos == cursor_win)
- return DRM_PLANE_TYPE_CURSOR;
- else
- return DRM_PLANE_TYPE_OVERLAY;
-}
-
int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane,
- unsigned long possible_crtcs, enum drm_plane_type type,
- const uint32_t *formats, unsigned int fcount,
- unsigned int zpos)
+ unsigned int index, unsigned long possible_crtcs,
+ const struct exynos_drm_plane_config *config)
{
int err;
- err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs,
- &exynos_plane_funcs, formats, fcount,
- type);
+ err = drm_universal_plane_init(dev, &exynos_plane->base,
+ possible_crtcs,
+ &exynos_plane_funcs,
+ config->pixel_formats,
+ config->num_pixel_formats,
+ config->type, NULL);
if (err) {
DRM_ERROR("failed to initialize plane\n");
return err;
@@ -236,10 +341,10 @@ int exynos_plane_init(struct drm_device *dev,
drm_plane_helper_add(&exynos_plane->base, &plane_helper_funcs);
- exynos_plane->zpos = zpos;
+ exynos_plane->index = index;
+ exynos_plane->config = config;
- if (type == DRM_PLANE_TYPE_OVERLAY)
- exynos_plane_attach_zpos_property(&exynos_plane->base, zpos);
+ exynos_plane_attach_zpos_property(&exynos_plane->base, config->zpos);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index abb641e64c23..9aafad164cdf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -9,10 +9,7 @@
*
*/
-enum drm_plane_type exynos_plane_get_type(unsigned int zpos,
- unsigned int cursor_win);
int exynos_plane_init(struct drm_device *dev,
- struct exynos_drm_plane *exynos_plane,
- unsigned long possible_crtcs, enum drm_plane_type type,
- const uint32_t *formats, unsigned int fcount,
- unsigned int zpos);
+ struct exynos_drm_plane *exynos_plane, unsigned int index,
+ unsigned long possible_crtcs,
+ const struct exynos_drm_plane_config *config);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 2f5c118f4c8e..bea0f7826d30 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -790,10 +790,10 @@ static int rotator_remove(struct platform_device *pdev)
static int rotator_clk_crtl(struct rot_context *rot, bool enable)
{
if (enable) {
- clk_enable(rot->clock);
+ clk_prepare_enable(rot->clock);
rot->suspended = false;
} else {
- clk_disable(rot->clock);
+ clk_disable_unprepare(rot->clock);
rot->suspended = true;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 669362c53f49..62ac4e5fa51d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -24,12 +24,12 @@
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
+#include "exynos_drm_fb.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h"
/* vidi has totally three virtual windows. */
#define WINDOWS_NR 3
-#define CURSOR_WIN 2
#define ctx_from_connector(c) container_of(c, struct vidi_context, \
connector)
@@ -89,6 +89,12 @@ static const uint32_t formats[] = {
DRM_FORMAT_NV12,
};
+static const enum drm_plane_type vidi_win_types[WINDOWS_NR] = {
+ DRM_PLANE_TYPE_PRIMARY,
+ DRM_PLANE_TYPE_OVERLAY,
+ DRM_PLANE_TYPE_CURSOR,
+};
+
static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
{
struct vidi_context *ctx = crtc->ctx;
@@ -125,12 +131,15 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
static void vidi_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
+ struct drm_plane_state *state = plane->base.state;
struct vidi_context *ctx = crtc->ctx;
+ dma_addr_t addr;
if (ctx->suspended)
return;
- DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr);
+ addr = exynos_drm_fb_dma_addr(state->fb, 0);
+ DRM_DEBUG_KMS("dma_addr = %pad\n", &addr);
if (ctx->vblank_on)
schedule_work(&ctx->work);
@@ -330,7 +339,7 @@ static void vidi_connector_destroy(struct drm_connector *connector)
{
}
-static struct drm_connector_funcs vidi_connector_funcs = {
+static const struct drm_connector_funcs vidi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = vidi_detect,
@@ -374,7 +383,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
return &ctx->encoder;
}
-static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
.get_modes = vidi_get_modes,
.best_encoder = vidi_best_encoder,
};
@@ -422,14 +431,14 @@ static void exynos_vidi_disable(struct drm_encoder *encoder)
{
}
-static struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
.mode_fixup = exynos_vidi_mode_fixup,
.mode_set = exynos_vidi_mode_set,
.enable = exynos_vidi_enable,
.disable = exynos_vidi_disable,
};
-static struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
+static const struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -439,17 +448,21 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm_dev = data;
struct drm_encoder *encoder = &ctx->encoder;
struct exynos_drm_plane *exynos_plane;
- enum drm_plane_type type;
- unsigned int zpos;
+ struct exynos_drm_plane_config plane_config = { 0 };
+ unsigned int i;
int pipe, ret;
vidi_ctx_initialize(ctx, drm_dev);
- for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
- type = exynos_plane_get_type(zpos, CURSOR_WIN);
- ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
- 1 << ctx->pipe, type, formats,
- ARRAY_SIZE(formats), zpos);
+ plane_config.pixel_formats = formats;
+ plane_config.num_pixel_formats = ARRAY_SIZE(formats);
+
+ for (i = 0; i < WINDOWS_NR; i++) {
+ plane_config.zpos = i;
+ plane_config.type = vidi_win_types[i];
+
+ ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
+ 1 << ctx->pipe, &plane_config);
if (ret)
return ret;
}
@@ -473,7 +486,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 57b675563e94..21a29dbce18c 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -113,7 +113,7 @@ struct hdmi_context {
void __iomem *regs_hdmiphy;
struct i2c_client *hdmiphy_port;
struct i2c_adapter *ddc_adpt;
- struct gpio_desc *hpd_gpio;
+ struct gpio_desc *hpd_gpio;
int irq;
struct regmap *pmureg;
struct clk *hdmi;
@@ -956,7 +956,7 @@ static void hdmi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs hdmi_connector_funcs = {
+static const struct drm_connector_funcs hdmi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = hdmi_detect,
@@ -1030,7 +1030,7 @@ static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
return &hdata->encoder;
}
-static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
.get_modes = hdmi_get_modes,
.mode_valid = hdmi_mode_valid,
.best_encoder = hdmi_best_encoder,
@@ -1588,8 +1588,6 @@ static void hdmi_enable(struct drm_encoder *encoder)
if (hdata->powered)
return;
- hdata->powered = true;
-
pm_runtime_get_sync(hdata->dev);
if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
@@ -1599,10 +1597,9 @@ static void hdmi_enable(struct drm_encoder *encoder)
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 1);
- clk_prepare_enable(hdata->hdmi);
- clk_prepare_enable(hdata->sclk_hdmi);
-
hdmi_conf_apply(hdata);
+
+ hdata->powered = true;
}
static void hdmi_disable(struct drm_encoder *encoder)
@@ -1633,9 +1630,6 @@ static void hdmi_disable(struct drm_encoder *encoder)
cancel_delayed_work(&hdata->hotplug_work);
- clk_disable_unprepare(hdata->sclk_hdmi);
- clk_disable_unprepare(hdata->hdmi);
-
/* reset pmu hdmiphy control bit to disable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
@@ -1647,14 +1641,14 @@ static void hdmi_disable(struct drm_encoder *encoder)
hdata->powered = false;
}
-static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
.mode_fixup = hdmi_mode_fixup,
.mode_set = hdmi_mode_set,
.enable = hdmi_enable,
.disable = hdmi_disable,
};
-static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
+static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -1793,7 +1787,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
@@ -1978,12 +1972,49 @@ static int hdmi_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int exynos_hdmi_suspend(struct device *dev)
+{
+ struct hdmi_context *hdata = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(hdata->sclk_hdmi);
+ clk_disable_unprepare(hdata->hdmi);
+
+ return 0;
+}
+
+static int exynos_hdmi_resume(struct device *dev)
+{
+ struct hdmi_context *hdata = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(hdata->hdmi);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(hdata->sclk_hdmi);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the sclk_mixer clk [%d]\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_hdmi_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
+};
+
struct platform_driver hdmi_driver = {
.probe = hdmi_probe,
.remove = hdmi_remove,
.driver = {
.name = "exynos-hdmi",
.owner = THIS_MODULE,
+ .pm = &exynos_hdmi_pm_ops,
.of_match_table = hdmi_match_types,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index d09f8f9a8939..b5fbc1cbf024 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -37,12 +37,12 @@
#include "exynos_drm_drv.h"
#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
-#define CURSOR_WIN 1
/* The pixelformats that are natively supported by the mixer. */
#define MXR_FORMAT_RGB565 4
@@ -76,7 +76,9 @@ enum mixer_flag_bits {
static const uint32_t mixer_formats[] = {
DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_ARGB4444,
DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_ARGB1555,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
@@ -111,6 +113,31 @@ struct mixer_drv_data {
bool has_sclk;
};
+static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
+ {
+ .zpos = 0,
+ .type = DRM_PLANE_TYPE_PRIMARY,
+ .pixel_formats = mixer_formats,
+ .num_pixel_formats = ARRAY_SIZE(mixer_formats),
+ .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
+ EXYNOS_DRM_PLANE_CAP_ZPOS,
+ }, {
+ .zpos = 1,
+ .type = DRM_PLANE_TYPE_CURSOR,
+ .pixel_formats = mixer_formats,
+ .num_pixel_formats = ARRAY_SIZE(mixer_formats),
+ .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
+ EXYNOS_DRM_PLANE_CAP_ZPOS,
+ }, {
+ .zpos = 2,
+ .type = DRM_PLANE_TYPE_OVERLAY,
+ .pixel_formats = vp_formats,
+ .num_pixel_formats = ARRAY_SIZE(vp_formats),
+ .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
+ EXYNOS_DRM_PLANE_CAP_ZPOS,
+ },
+};
+
static const u8 filter_y_horiz_tap8[] = {
0, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 0, 0, 0,
@@ -140,6 +167,18 @@ static const u8 filter_cr_horiz_tap4[] = {
70, 59, 48, 37, 27, 19, 11, 5,
};
+static inline bool is_alpha_format(unsigned int pixel_format)
+{
+ switch (pixel_format) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_ARGB4444:
+ return true;
+ default:
+ return false;
+ }
+}
+
static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
{
return readl(res->vp_regs + reg_id);
@@ -269,6 +308,37 @@ static void vp_default_filter(struct mixer_resources *res)
filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
}
+static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
+ bool alpha)
+{
+ struct mixer_resources *res = &ctx->mixer_res;
+ u32 val;
+
+ val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+ if (alpha) {
+ /* blending based on pixel alpha */
+ val |= MXR_GRP_CFG_BLEND_PRE_MUL;
+ val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
+ }
+ mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
+ val, MXR_GRP_CFG_MISC_MASK);
+}
+
+static void mixer_cfg_vp_blend(struct mixer_context *ctx)
+{
+ struct mixer_resources *res = &ctx->mixer_res;
+ u32 val;
+
+ /*
+ * No blending at the moment since the NV12/NV21 pixelformats don't
+ * have an alpha channel. However the mixer supports a global alpha
+ * value for a layer. Once this functionality is exposed, we can
+ * support blending of the video layer through this.
+ */
+ val = 0;
+ mixer_reg_write(res, MXR_VIDEO_CFG, val);
+}
+
static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
{
struct mixer_resources *res = &ctx->mixer_res;
@@ -350,7 +420,7 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
}
static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
- bool enable)
+ unsigned int priority, bool enable)
{
struct mixer_resources *res = &ctx->mixer_res;
u32 val = enable ? ~0 : 0;
@@ -358,20 +428,24 @@ static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win,
switch (win) {
case 0:
mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+ mixer_reg_writemask(res, MXR_LAYER_CFG,
+ MXR_LAYER_CFG_GRP0_VAL(priority),
+ MXR_LAYER_CFG_GRP0_MASK);
break;
case 1:
mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+ mixer_reg_writemask(res, MXR_LAYER_CFG,
+ MXR_LAYER_CFG_GRP1_VAL(priority),
+ MXR_LAYER_CFG_GRP1_MASK);
break;
- case 2:
+ case VP_DEFAULT_WIN:
if (ctx->vp_enabled) {
vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
mixer_reg_writemask(res, MXR_CFG, val,
MXR_CFG_VP_ENABLE);
-
- /* control blending of graphic layer 0 */
- mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val,
- MXR_GRP_CFG_BLEND_PRE_MUL |
- MXR_GRP_CFG_PIXEL_BLEND_EN);
+ mixer_reg_writemask(res, MXR_LAYER_CFG,
+ MXR_LAYER_CFG_VP_VAL(priority),
+ MXR_LAYER_CFG_VP_MASK);
}
break;
}
@@ -399,10 +473,11 @@ static void mixer_stop(struct mixer_context *ctx)
static void vp_video_buffer(struct mixer_context *ctx,
struct exynos_drm_plane *plane)
{
+ struct exynos_drm_plane_state *state =
+ to_exynos_plane_state(plane->base.state);
+ struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
struct mixer_resources *res = &ctx->mixer_res;
- struct drm_plane_state *state = plane->base.state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_display_mode *mode = &state->crtc->mode;
+ struct drm_framebuffer *fb = state->base.fb;
unsigned long flags;
dma_addr_t luma_addr[2], chroma_addr[2];
bool tiled_mode = false;
@@ -422,8 +497,8 @@ static void vp_video_buffer(struct mixer_context *ctx,
return;
}
- luma_addr[0] = plane->dma_addr[0];
- chroma_addr[0] = plane->dma_addr[1];
+ luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0);
+ chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1);
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
ctx->interlace = true;
@@ -441,7 +516,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
}
spin_lock_irqsave(&res->reg_slock, flags);
- mixer_vsync_set_update(ctx, false);
/* interlace or progressive scan mode */
val = (ctx->interlace ? ~0 : 0);
@@ -459,24 +533,24 @@ static void vp_video_buffer(struct mixer_context *ctx,
vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
VP_IMG_VSIZE(fb->height / 2));
- vp_reg_write(res, VP_SRC_WIDTH, plane->src_w);
- vp_reg_write(res, VP_SRC_HEIGHT, plane->src_h);
+ vp_reg_write(res, VP_SRC_WIDTH, state->src.w);
+ vp_reg_write(res, VP_SRC_HEIGHT, state->src.h);
vp_reg_write(res, VP_SRC_H_POSITION,
- VP_SRC_H_POSITION_VAL(plane->src_x));
- vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
+ VP_SRC_H_POSITION_VAL(state->src.x));
+ vp_reg_write(res, VP_SRC_V_POSITION, state->src.y);
- vp_reg_write(res, VP_DST_WIDTH, plane->crtc_w);
- vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
+ vp_reg_write(res, VP_DST_WIDTH, state->crtc.w);
+ vp_reg_write(res, VP_DST_H_POSITION, state->crtc.x);
if (ctx->interlace) {
- vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h / 2);
- vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
+ vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h / 2);
+ vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y / 2);
} else {
- vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h);
- vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
+ vp_reg_write(res, VP_DST_HEIGHT, state->crtc.h);
+ vp_reg_write(res, VP_DST_V_POSITION, state->crtc.y);
}
- vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
- vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
+ vp_reg_write(res, VP_H_RATIO, state->h_ratio);
+ vp_reg_write(res, VP_V_RATIO, state->v_ratio);
vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
@@ -488,10 +562,10 @@ static void vp_video_buffer(struct mixer_context *ctx,
mixer_cfg_scan(ctx, mode->vdisplay);
mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
- mixer_cfg_layer(ctx, plane->zpos, true);
+ mixer_cfg_layer(ctx, plane->index, state->zpos + 1, true);
+ mixer_cfg_vp_blend(ctx);
mixer_run(ctx);
- mixer_vsync_set_update(ctx, true);
spin_unlock_irqrestore(&res->reg_slock, flags);
mixer_regs_dump(ctx);
@@ -505,39 +579,16 @@ static void mixer_layer_update(struct mixer_context *ctx)
mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
}
-static int mixer_setup_scale(const struct exynos_drm_plane *plane,
- unsigned int *x_ratio, unsigned int *y_ratio)
-{
- if (plane->crtc_w != plane->src_w) {
- if (plane->crtc_w == 2 * plane->src_w)
- *x_ratio = 1;
- else
- goto fail;
- }
-
- if (plane->crtc_h != plane->src_h) {
- if (plane->crtc_h == 2 * plane->src_h)
- *y_ratio = 1;
- else
- goto fail;
- }
-
- return 0;
-
-fail:
- DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
- return -ENOTSUPP;
-}
-
static void mixer_graph_buffer(struct mixer_context *ctx,
struct exynos_drm_plane *plane)
{
+ struct exynos_drm_plane_state *state =
+ to_exynos_plane_state(plane->base.state);
+ struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
struct mixer_resources *res = &ctx->mixer_res;
- struct drm_plane_state *state = plane->base.state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_display_mode *mode = &state->crtc->mode;
+ struct drm_framebuffer *fb = state->base.fb;
unsigned long flags;
- unsigned int win = plane->zpos;
+ unsigned int win = plane->index;
unsigned int x_ratio = 0, y_ratio = 0;
unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
dma_addr_t dma_addr;
@@ -546,10 +597,12 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
switch (fb->pixel_format) {
case DRM_FORMAT_XRGB4444:
+ case DRM_FORMAT_ARGB4444:
fmt = MXR_FORMAT_ARGB4444;
break;
case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_ARGB1555:
fmt = MXR_FORMAT_ARGB1555;
break;
@@ -567,17 +620,17 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
return;
}
- /* check if mixer supports requested scaling setup */
- if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
- return;
+ /* ratio is already checked by common plane code */
+ x_ratio = state->h_ratio == (1 << 15);
+ y_ratio = state->v_ratio == (1 << 15);
- dst_x_offset = plane->crtc_x;
- dst_y_offset = plane->crtc_y;
+ dst_x_offset = state->crtc.x;
+ dst_y_offset = state->crtc.y;
/* converting dma address base and source offset */
- dma_addr = plane->dma_addr[0]
- + (plane->src_x * fb->bits_per_pixel >> 3)
- + (plane->src_y * fb->pitches[0]);
+ dma_addr = exynos_drm_fb_dma_addr(fb, 0)
+ + (state->src.x * fb->bits_per_pixel >> 3)
+ + (state->src.y * fb->pitches[0]);
src_x_offset = 0;
src_y_offset = 0;
@@ -587,7 +640,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
ctx->interlace = false;
spin_lock_irqsave(&res->reg_slock, flags);
- mixer_vsync_set_update(ctx, false);
/* setup format */
mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
@@ -605,8 +657,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
mixer_reg_write(res, MXR_RESOLUTION, val);
}
- val = MXR_GRP_WH_WIDTH(plane->src_w);
- val |= MXR_GRP_WH_HEIGHT(plane->src_h);
+ val = MXR_GRP_WH_WIDTH(state->src.w);
+ val |= MXR_GRP_WH_HEIGHT(state->src.h);
val |= MXR_GRP_WH_H_SCALE(x_ratio);
val |= MXR_GRP_WH_V_SCALE(y_ratio);
mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
@@ -626,7 +678,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
mixer_cfg_scan(ctx, mode->vdisplay);
mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
- mixer_cfg_layer(ctx, win, true);
+ mixer_cfg_layer(ctx, win, state->zpos + 1, true);
+ mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->pixel_format));
/* layer update mandatory for mixer 16.0.33.0 */
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
@@ -635,7 +688,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
mixer_run(ctx);
- mixer_vsync_set_update(ctx, true);
spin_unlock_irqrestore(&res->reg_slock, flags);
mixer_regs_dump(ctx);
@@ -660,10 +712,8 @@ static void mixer_win_reset(struct mixer_context *ctx)
{
struct mixer_resources *res = &ctx->mixer_res;
unsigned long flags;
- u32 val; /* value stored to register */
spin_lock_irqsave(&res->reg_slock, flags);
- mixer_vsync_set_update(ctx, false);
mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
@@ -674,40 +724,14 @@ static void mixer_win_reset(struct mixer_context *ctx)
mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
MXR_STATUS_BURST_MASK);
- /* setting default layer priority: layer1 > layer0 > video
- * because typical usage scenario would be
- * layer1 - OSD
- * layer0 - framebuffer
- * video - video overlay
- */
- val = MXR_LAYER_CFG_GRP1_VAL(3);
- val |= MXR_LAYER_CFG_GRP0_VAL(2);
- if (ctx->vp_enabled)
- val |= MXR_LAYER_CFG_VP_VAL(1);
- mixer_reg_write(res, MXR_LAYER_CFG, val);
+ /* reset default layer priority */
+ mixer_reg_write(res, MXR_LAYER_CFG, 0);
/* setting background color */
mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
- /* setting graphical layers */
- val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
- val |= MXR_GRP_CFG_WIN_BLEND_EN;
- val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
-
- /* Don't blend layer 0 onto the mixer background */
- mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
-
- /* Blend layer 1 into layer 0 */
- val |= MXR_GRP_CFG_BLEND_PRE_MUL;
- val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
- mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
-
- /* setting video layers */
- val = MXR_GRP_CFG_ALPHA_VAL(0);
- mixer_reg_write(res, MXR_VIDEO_CFG, val);
-
if (ctx->vp_enabled) {
/* configuration of Video Processor Registers */
vp_win_reset(ctx);
@@ -720,7 +744,6 @@ static void mixer_win_reset(struct mixer_context *ctx)
if (ctx->vp_enabled)
mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
- mixer_vsync_set_update(ctx, true);
spin_unlock_irqrestore(&res->reg_slock, flags);
}
@@ -951,17 +974,27 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
}
+static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
+{
+ struct mixer_context *mixer_ctx = crtc->ctx;
+
+ if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
+ return;
+
+ mixer_vsync_set_update(mixer_ctx, false);
+}
+
static void mixer_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct mixer_context *mixer_ctx = crtc->ctx;
- DRM_DEBUG_KMS("win: %d\n", plane->zpos);
+ DRM_DEBUG_KMS("win: %d\n", plane->index);
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
return;
- if (plane->zpos > 1 && mixer_ctx->vp_enabled)
+ if (plane->index == VP_DEFAULT_WIN)
vp_video_buffer(mixer_ctx, plane);
else
mixer_graph_buffer(mixer_ctx, plane);
@@ -974,18 +1007,24 @@ static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
struct mixer_resources *res = &mixer_ctx->mixer_res;
unsigned long flags;
- DRM_DEBUG_KMS("win: %d\n", plane->zpos);
+ DRM_DEBUG_KMS("win: %d\n", plane->index);
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
return;
spin_lock_irqsave(&res->reg_slock, flags);
- mixer_vsync_set_update(mixer_ctx, false);
+ mixer_cfg_layer(mixer_ctx, plane->index, 0, false);
+ spin_unlock_irqrestore(&res->reg_slock, flags);
+}
- mixer_cfg_layer(mixer_ctx, plane->zpos, false);
+static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
+{
+ struct mixer_context *mixer_ctx = crtc->ctx;
+
+ if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
+ return;
mixer_vsync_set_update(mixer_ctx, true);
- spin_unlock_irqrestore(&res->reg_slock, flags);
}
static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
@@ -1020,42 +1059,13 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
{
struct mixer_context *ctx = crtc->ctx;
struct mixer_resources *res = &ctx->mixer_res;
- int ret;
if (test_bit(MXR_BIT_POWERED, &ctx->flags))
return;
pm_runtime_get_sync(ctx->dev);
- ret = clk_prepare_enable(res->mixer);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
- return;
- }
- ret = clk_prepare_enable(res->hdmi);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
- return;
- }
- if (ctx->vp_enabled) {
- ret = clk_prepare_enable(res->vp);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
- ret);
- return;
- }
- if (ctx->has_sclk) {
- ret = clk_prepare_enable(res->sclk_mixer);
- if (ret < 0) {
- DRM_ERROR("Failed to prepare_enable the " \
- "sclk_mixer clk [%d]\n",
- ret);
- return;
- }
- }
- }
-
- set_bit(MXR_BIT_POWERED, &ctx->flags);
+ mixer_vsync_set_update(ctx, false);
mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
@@ -1064,12 +1074,15 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
}
mixer_win_reset(ctx);
+
+ mixer_vsync_set_update(ctx, true);
+
+ set_bit(MXR_BIT_POWERED, &ctx->flags);
}
static void mixer_disable(struct exynos_drm_crtc *crtc)
{
struct mixer_context *ctx = crtc->ctx;
- struct mixer_resources *res = &ctx->mixer_res;
int i;
if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
@@ -1081,17 +1094,9 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < MIXER_WIN_NR; i++)
mixer_disable_plane(crtc, &ctx->planes[i]);
- clear_bit(MXR_BIT_POWERED, &ctx->flags);
+ pm_runtime_put(ctx->dev);
- clk_disable_unprepare(res->hdmi);
- clk_disable_unprepare(res->mixer);
- if (ctx->vp_enabled) {
- clk_disable_unprepare(res->vp);
- if (ctx->has_sclk)
- clk_disable_unprepare(res->sclk_mixer);
- }
-
- pm_runtime_put_sync(ctx->dev);
+ clear_bit(MXR_BIT_POWERED, &ctx->flags);
}
/* Only valid for Mixer version 16.0.33.0 */
@@ -1122,8 +1127,10 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
.wait_for_vblank = mixer_wait_for_vblank,
+ .atomic_begin = mixer_atomic_begin,
.update_plane = mixer_update_plane,
.disable_plane = mixer_disable_plane,
+ .atomic_flush = mixer_atomic_flush,
.atomic_check = mixer_atomic_check,
};
@@ -1187,30 +1194,19 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
struct mixer_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
struct exynos_drm_plane *exynos_plane;
- unsigned int zpos;
+ unsigned int i;
int ret;
ret = mixer_initialize(ctx, drm_dev);
if (ret)
return ret;
- for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
- enum drm_plane_type type;
- const uint32_t *formats;
- unsigned int fcount;
-
- if (zpos < VP_DEFAULT_WIN) {
- formats = mixer_formats;
- fcount = ARRAY_SIZE(mixer_formats);
- } else {
- formats = vp_formats;
- fcount = ARRAY_SIZE(vp_formats);
- }
+ for (i = 0; i < MIXER_WIN_NR; i++) {
+ if (i == VP_DEFAULT_WIN && !ctx->vp_enabled)
+ continue;
- type = exynos_plane_get_type(zpos, CURSOR_WIN);
- ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
- 1 << ctx->pipe, type, formats, fcount,
- zpos);
+ ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
+ 1 << ctx->pipe, &plane_configs[i]);
if (ret)
return ret;
}
@@ -1293,10 +1289,70 @@ static int mixer_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int exynos_mixer_suspend(struct device *dev)
+{
+ struct mixer_context *ctx = dev_get_drvdata(dev);
+ struct mixer_resources *res = &ctx->mixer_res;
+
+ clk_disable_unprepare(res->hdmi);
+ clk_disable_unprepare(res->mixer);
+ if (ctx->vp_enabled) {
+ clk_disable_unprepare(res->vp);
+ if (ctx->has_sclk)
+ clk_disable_unprepare(res->sclk_mixer);
+ }
+
+ return 0;
+}
+
+static int exynos_mixer_resume(struct device *dev)
+{
+ struct mixer_context *ctx = dev_get_drvdata(dev);
+ struct mixer_resources *res = &ctx->mixer_res;
+ int ret;
+
+ ret = clk_prepare_enable(res->mixer);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(res->hdmi);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
+ return ret;
+ }
+ if (ctx->vp_enabled) {
+ ret = clk_prepare_enable(res->vp);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n",
+ ret);
+ return ret;
+ }
+ if (ctx->has_sclk) {
+ ret = clk_prepare_enable(res->sclk_mixer);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the " \
+ "sclk_mixer clk [%d]\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_mixer_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
+};
+
struct platform_driver mixer_driver = {
.driver = {
.name = "exynos-mixer",
.owner = THIS_MODULE,
+ .pm = &exynos_mixer_pm_ops,
.of_match_table = mixer_match_types,
},
.probe = mixer_probe,
diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h
index 9ad592707aaf..4704a993cbb7 100644
--- a/drivers/gpu/drm/exynos/regs-gsc.h
+++ b/drivers/gpu/drm/exynos/regs-gsc.h
@@ -273,12 +273,12 @@
#define GSC_CLK_GATE_MODE_SNOOP_CNT(x) ((x) << 0)
/* SYSCON. GSCBLK_CFG */
-#define SYSREG_GSCBLK_CFG1 (S3C_VA_SYS + 0x0224)
+#define SYSREG_GSCBLK_CFG1 0x0224
#define GSC_BLK_DISP1WB_DEST(x) (x << 10)
#define GSC_BLK_SW_RESET_WB_DEST(x) (1 << (18 + x))
#define GSC_BLK_PXLASYNC_LO_MASK_WB(x) (0 << (14 + x))
#define GSC_BLK_GSCL_WB_IN_SRC_SEL(x) (1 << (2 * x))
-#define SYSREG_GSCBLK_CFG2 (S3C_VA_SYS + 0x2000)
+#define SYSREG_GSCBLK_CFG2 0x2000
#define PXLASYNC_LO_MASK_CAMIF_GSCL(x) (1 << (x))
#endif /* EXYNOS_REGS_GSC_H_ */
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
index ac60260c2389..7f22df5bf707 100644
--- a/drivers/gpu/drm/exynos/regs-mixer.h
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -113,6 +113,7 @@
#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
#define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17)
#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16)
+#define MXR_GRP_CFG_MISC_MASK ((3 << 16) | (3 << 20))
#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
@@ -145,8 +146,11 @@
/* bit for MXR_LAYER_CFG */
#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0)
#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_GRP0_MASK MXR_LAYER_CFG_GRP0_VAL(~0)
#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
+#define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0)
#endif /* SAMSUNG_REGS_MIXER_H */
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
index 82a3d311e164..d8ab8f0af10c 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
@@ -175,7 +175,7 @@ int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
primary = fsl_dcu_drm_primary_create_plane(fsl_dev->drm);
ret = drm_crtc_init_with_planes(fsl_dev->drm, crtc, primary, NULL,
- &fsl_dcu_drm_crtc_funcs);
+ &fsl_dcu_drm_crtc_funcs, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index 1930234ba5f1..fca97d3fc846 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -363,7 +363,6 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
fsl_dev->np = dev->of_node;
drm->dev_private = fsl_dev;
dev_set_drvdata(dev, fsl_dev);
- drm_dev_set_unique(drm, dev_name(dev));
ret = drm_dev_register(drm, 0);
if (ret < 0)
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
index 51daaea40b4d..4b13cf919575 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
@@ -249,7 +249,7 @@ struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
&fsl_dcu_drm_plane_funcs,
fsl_dcu_drm_plane_formats,
ARRAY_SIZE(fsl_dcu_drm_plane_formats),
- DRM_PLANE_TYPE_PRIMARY);
+ DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
primary = NULL;
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index fe8ab5da04fb..8780deba5e8a 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -57,7 +57,7 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
encoder->possible_crtcs = 1;
ret = drm_encoder_init(fsl_dev->drm, encoder, &encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index 3531f90e53d0..8745971a7680 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -619,6 +619,8 @@ const struct psb_ops cdv_chip_ops = {
.init_pm = cdv_init_pm,
.save_regs = cdv_save_display_registers,
.restore_regs = cdv_restore_display_registers,
+ .save_crtc = gma_crtc_save,
+ .restore_crtc = gma_crtc_restore,
.power_down = cdv_power_down,
.power_up = cdv_power_up,
.update_wm = cdv_update_wm,
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index 248c33a35ebf..d0717a85c7ec 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -273,7 +273,7 @@ void cdv_intel_crt_init(struct drm_device *dev,
encoder = &gma_encoder->base;
drm_encoder_init(dev, encoder,
- &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC);
+ &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 7d47b3d5cc0d..6126546295e9 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -983,8 +983,6 @@ const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = {
};
const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
- .save = gma_crtc_save,
- .restore = gma_crtc_restore,
.cursor_set = gma_crtc_cursor_set,
.cursor_move = gma_crtc_cursor_move,
.gamma_set = gma_crtc_gamma_set,
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index 17cea400ae32..7bb1f1aff932 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -2020,7 +2020,8 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev
encoder = &gma_encoder->base;
drm_connector_init(dev, connector, &cdv_intel_dp_connector_funcs, type);
- drm_encoder_init(dev, encoder, &cdv_intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &cdv_intel_dp_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 6b1d3340ba14..ddf2d7700759 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -270,8 +270,6 @@ static const struct drm_connector_helper_funcs
static const struct drm_connector_funcs cdv_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
- .save = cdv_hdmi_save,
- .restore = cdv_hdmi_restore,
.detect = cdv_hdmi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = cdv_hdmi_set_property,
@@ -306,13 +304,16 @@ void cdv_hdmi_init(struct drm_device *dev,
connector = &gma_connector->base;
connector->polled = DRM_CONNECTOR_POLL_HPD;
+ gma_connector->save = cdv_hdmi_save;
+ gma_connector->restore = cdv_hdmi_restore;
+
encoder = &gma_encoder->base;
drm_connector_init(dev, connector,
&cdv_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_DVID);
drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
gma_encoder->type = INTEL_OUTPUT_HDMI;
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 211069b2b951..813ef23a8054 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -530,8 +530,6 @@ static const struct drm_connector_helper_funcs
static const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = {
.dpms = drm_helper_connector_dpms,
- .save = cdv_intel_lvds_save,
- .restore = cdv_intel_lvds_restore,
.detect = cdv_intel_lvds_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = cdv_intel_lvds_set_property,
@@ -643,6 +641,8 @@ void cdv_intel_lvds_init(struct drm_device *dev,
gma_encoder->dev_priv = lvds_priv;
connector = &gma_connector->base;
+ gma_connector->save = cdv_intel_lvds_save;
+ gma_connector->restore = cdv_intel_lvds_restore;
encoder = &gma_encoder->base;
@@ -652,7 +652,7 @@ void cdv_intel_lvds_init(struct drm_device *dev,
drm_encoder_init(dev, encoder,
&cdv_intel_lvds_enc_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 2eaf1b31c7bd..cb95765050cc 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/pfn_t.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
@@ -132,7 +133,8 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
for (i = 0; i < page_num; i++) {
pfn = (phys_addr >> PAGE_SHIFT);
- ret = vm_insert_mixed(vma, address, pfn);
+ ret = vm_insert_mixed(vma, address,
+ __pfn_to_pfn_t(pfn, PFN_DEV));
if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0)))
break;
else if (unlikely(ret != 0)) {
@@ -241,7 +243,7 @@ static struct fb_ops psbfb_unaccel_ops = {
*/
static int psb_framebuffer_init(struct drm_device *dev,
struct psb_framebuffer *fb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct gtt_range *gt)
{
u32 bpp, depth;
@@ -284,7 +286,7 @@ static int psb_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *psb_framebuffer_create
(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct gtt_range *gt)
{
struct psb_framebuffer *fb;
@@ -406,8 +408,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
memset(dev_priv->vram_addr + backing->offset, 0, size);
- mutex_lock(&dev->struct_mutex);
-
info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
@@ -463,17 +463,15 @@ static int psbfb_create(struct psb_fbdev *fbdev,
dev_dbg(dev->dev, "allocated %dx%d fb\n",
psbfb->base.width, psbfb->base.height);
- mutex_unlock(&dev->struct_mutex);
return 0;
out_unref:
if (backing->stolen)
psb_gtt_free_range(dev, backing);
else
- drm_gem_object_unreference(&backing->gem);
+ drm_gem_object_unreference_unlocked(&backing->gem);
drm_fb_helper_release_fbi(&fbdev->psb_fb_helper);
out_err1:
- mutex_unlock(&dev->struct_mutex);
psb_gtt_free_range(dev, backing);
return ret;
}
@@ -488,7 +486,7 @@ out_err1:
*/
static struct drm_framebuffer *psb_user_framebuffer_create
(struct drm_device *dev, struct drm_file *filp,
- struct drm_mode_fb_cmd2 *cmd)
+ const struct drm_mode_fb_cmd2 *cmd)
{
struct gtt_range *r;
struct drm_gem_object *obj;
@@ -569,7 +567,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
drm_framebuffer_cleanup(&psbfb->base);
if (psbfb->gtt)
- drm_gem_object_unreference(&psbfb->gtt->gem);
+ drm_gem_object_unreference_unlocked(&psbfb->gtt->gem);
return 0;
}
@@ -784,12 +782,8 @@ void psb_modeset_cleanup(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
if (dev_priv->modeset) {
- mutex_lock(&dev->struct_mutex);
-
drm_kms_helper_poll_fini(dev);
psb_fbdev_fini(dev);
drm_mode_config_cleanup(dev);
-
- mutex_unlock(&dev->struct_mutex);
}
}
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c
index c707fa6fca85..506224b3a0ad 100644
--- a/drivers/gpu/drm/gma500/gem.c
+++ b/drivers/gpu/drm/gma500/gem.c
@@ -62,15 +62,10 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
int ret = 0;
struct drm_gem_object *obj;
- mutex_lock(&dev->struct_mutex);
-
/* GEM does all our handle to object mapping */
obj = drm_gem_object_lookup(dev, file, handle);
- if (obj == NULL) {
- ret = -ENOENT;
- goto unlock;
- }
- /* What validation is needed here ? */
+ if (obj == NULL)
+ return -ENOENT;
/* Make it mmapable */
ret = drm_gem_create_mmap_offset(obj);
@@ -78,9 +73,7 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
goto out;
*offset = drm_vma_node_offset_addr(&obj->vma_node);
out:
- drm_gem_object_unreference(obj);
-unlock:
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
return ret;
}
@@ -130,7 +123,7 @@ int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size,
return ret;
}
/* We have the initial and handle reference but need only one now */
- drm_gem_object_unreference(&r->gem);
+ drm_gem_object_unreference_unlocked(&r->gem);
*handlep = handle;
return 0;
}
@@ -189,7 +182,7 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
/* Make sure we don't parallel update on a fault, nor move or remove
something from beneath our feet */
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&dev_priv->mmap_mutex);
/* For now the mmap pins the object and it stays pinned. As things
stand that will do us no harm */
@@ -215,7 +208,7 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
fail:
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&dev_priv->mmap_mutex);
switch (ret) {
case 0:
case -ERESTARTSYS:
diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
index 001b450b27b3..ff17af4cfc64 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -349,8 +349,6 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
/* If we didn't get a handle then turn the cursor off */
if (!handle) {
temp = CURSOR_MODE_DISABLE;
- mutex_lock(&dev->struct_mutex);
-
if (gma_power_begin(dev, false)) {
REG_WRITE(control, temp);
REG_WRITE(base, 0);
@@ -362,11 +360,9 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
gt = container_of(gma_crtc->cursor_obj,
struct gtt_range, gem);
psb_gtt_unpin(gt);
- drm_gem_object_unreference(gma_crtc->cursor_obj);
+ drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj);
gma_crtc->cursor_obj = NULL;
}
-
- mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -376,7 +372,6 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
return -EINVAL;
}
- mutex_lock(&dev->struct_mutex);
obj = drm_gem_object_lookup(dev, file_priv, handle);
if (!obj) {
ret = -ENOENT;
@@ -441,17 +436,15 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
if (gma_crtc->cursor_obj) {
gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem);
psb_gtt_unpin(gt);
- drm_gem_object_unreference(gma_crtc->cursor_obj);
+ drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj);
}
gma_crtc->cursor_obj = obj;
unlock:
- mutex_unlock(&dev->struct_mutex);
return ret;
unref_cursor:
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
return ret;
}
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index ce015db59dc6..8f69225ce2b4 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -425,6 +425,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
if (!resume) {
mutex_init(&dev_priv->gtt_mutex);
+ mutex_init(&dev_priv->mmap_mutex);
psb_gtt_alloc(dev);
}
diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c
index 265ad0de44a6..e2ab858122f9 100644
--- a/drivers/gpu/drm/gma500/mdfld_device.c
+++ b/drivers/gpu/drm/gma500/mdfld_device.c
@@ -546,6 +546,8 @@ const struct psb_ops mdfld_chip_ops = {
.save_regs = mdfld_save_registers,
.restore_regs = mdfld_restore_registers,
+ .save_crtc = gma_crtc_save,
+ .restore_crtc = gma_crtc_restore,
.power_down = mdfld_power_down,
.power_up = mdfld_power_up,
};
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
index d4813e03f5ee..7cd87a0c2385 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
@@ -821,14 +821,18 @@ void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = dsi_config->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
-
u32 pipeconf_reg = PIPEACONF;
u32 dspcntr_reg = DSPACNTR;
+ u32 pipeconf, dspcntr;
- u32 pipeconf = dev_priv->pipeconf[pipe];
- u32 dspcntr = dev_priv->dspcntr[pipe];
u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+ if (WARN_ON(pipe < 0))
+ return;
+
+ pipeconf = dev_priv->pipeconf[pipe];
+ dspcntr = dev_priv->dspcntr[pipe];
+
if (pipe) {
pipeconf_reg = PIPECCONF;
dspcntr_reg = DSPCCNTR;
@@ -994,7 +998,7 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
drm_encoder_init(dev,
encoder,
p_funcs->encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
drm_encoder_helper_add(encoder,
p_funcs->encoder_helper_funcs);
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 89f705c3a5eb..d758f4cc6805 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -405,8 +405,6 @@ static struct drm_encoder *mdfld_dsi_connector_best_encoder(
/*DSI connector funcs*/
static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
.dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
- .save = mdfld_dsi_connector_save,
- .restore = mdfld_dsi_connector_restore,
.detect = mdfld_dsi_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = mdfld_dsi_connector_set_property,
@@ -563,6 +561,9 @@ void mdfld_dsi_output_init(struct drm_device *dev,
connector = &dsi_connector->base.base;
+ dsi_connector->base.save = mdfld_dsi_connector_save;
+ dsi_connector->base.restore = mdfld_dsi_connector_restore;
+
drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
index 368a03ae3010..ba30b43a3412 100644
--- a/drivers/gpu/drm/gma500/oaktrail_device.c
+++ b/drivers/gpu/drm/gma500/oaktrail_device.c
@@ -568,6 +568,8 @@ const struct psb_ops oaktrail_chip_ops = {
.save_regs = oaktrail_save_display_registers,
.restore_regs = oaktrail_restore_display_registers,
+ .save_crtc = gma_crtc_save,
+ .restore_crtc = gma_crtc_restore,
.power_down = oaktrail_power_down,
.power_up = oaktrail_power_up,
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 2310d879cdc2..2d18499d6060 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -654,7 +654,7 @@ void oaktrail_hdmi_init(struct drm_device *dev,
drm_encoder_init(dev, encoder,
&oaktrail_hdmi_enc_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 83bbc271bcfb..f7038f12ac76 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -323,7 +323,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
DRM_MODE_CONNECTOR_LVDS);
drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
gma_encoder->type = INTEL_OUTPUT_LVDS;
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c
index b6b135fcd59c..bea8578846d1 100644
--- a/drivers/gpu/drm/gma500/power.c
+++ b/drivers/gpu/drm/gma500/power.c
@@ -187,7 +187,7 @@ static bool gma_resume_pci(struct pci_dev *pdev)
*/
int gma_power_suspend(struct device *_dev)
{
- struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev);
+ struct pci_dev *pdev = to_pci_dev(_dev);
struct drm_device *dev = pci_get_drvdata(pdev);
struct drm_psb_private *dev_priv = dev->dev_private;
@@ -214,7 +214,7 @@ int gma_power_suspend(struct device *_dev)
*/
int gma_power_resume(struct device *_dev)
{
- struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev);
+ struct pci_dev *pdev = to_pci_dev(_dev);
struct drm_device *dev = pci_get_drvdata(pdev);
mutex_lock(&power_mutex);
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index 07df7d4eea72..dc0f8527570c 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -181,7 +181,7 @@ static int psb_save_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
- struct drm_connector *connector;
+ struct gma_connector *connector;
struct psb_state *regs = &dev_priv->regs.psb;
/* Display arbitration control + watermarks */
@@ -198,12 +198,12 @@ static int psb_save_display_registers(struct drm_device *dev)
drm_modeset_lock_all(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (drm_helper_crtc_in_use(crtc))
- crtc->funcs->save(crtc);
+ dev_priv->ops->save_crtc(crtc);
}
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- if (connector->funcs->save)
- connector->funcs->save(connector);
+ list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
+ if (connector->save)
+ connector->save(&connector->base);
drm_modeset_unlock_all(dev);
return 0;
@@ -219,7 +219,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
- struct drm_connector *connector;
+ struct gma_connector *connector;
struct psb_state *regs = &dev_priv->regs.psb;
/* Display arbitration + watermarks */
@@ -238,11 +238,11 @@ static int psb_restore_display_registers(struct drm_device *dev)
drm_modeset_lock_all(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
if (drm_helper_crtc_in_use(crtc))
- crtc->funcs->restore(crtc);
+ dev_priv->ops->restore_crtc(crtc);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- if (connector->funcs->restore)
- connector->funcs->restore(connector);
+ list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
+ if (connector->restore)
+ connector->restore(&connector->base);
drm_modeset_unlock_all(dev);
return 0;
@@ -354,6 +354,8 @@ const struct psb_ops psb_chip_ops = {
.init_pm = psb_init_pm,
.save_regs = psb_save_display_registers,
.restore_regs = psb_restore_display_registers,
+ .save_crtc = gma_crtc_save,
+ .restore_crtc = gma_crtc_restore,
.power_down = psb_power_down,
.power_up = psb_power_up,
};
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index e21726ecac32..b74372760d7f 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -465,6 +465,8 @@ struct drm_psb_private {
struct mutex gtt_mutex;
struct resource *gtt_mem; /* Our PCI resource */
+ struct mutex mmap_mutex;
+
struct psb_mmu_driver *mmu;
struct psb_mmu_pd *pf_pd;
@@ -651,6 +653,8 @@ struct psb_ops {
void (*init_pm)(struct drm_device *dev);
int (*save_regs)(struct drm_device *dev);
int (*restore_regs)(struct drm_device *dev);
+ void (*save_crtc)(struct drm_crtc *crtc);
+ void (*restore_crtc)(struct drm_crtc *crtc);
int (*power_up)(struct drm_device *dev);
int (*power_down)(struct drm_device *dev);
void (*update_wm)(struct drm_device *dev, struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 6659da88fe5b..dcdbc37e55e1 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -439,8 +439,6 @@ const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
};
const struct drm_crtc_funcs psb_intel_crtc_funcs = {
- .save = gma_crtc_save,
- .restore = gma_crtc_restore,
.cursor_set = gma_crtc_cursor_set,
.cursor_move = gma_crtc_cursor_move,
.gamma_set = gma_crtc_gamma_set,
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index 860dd2177ca1..2a3b7c684db2 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -140,6 +140,9 @@ struct gma_encoder {
struct gma_connector {
struct drm_connector base;
struct gma_encoder *encoder;
+
+ void (*save)(struct drm_connector *connector);
+ void (*restore)(struct drm_connector *connector);
};
struct psb_intel_crtc_state {
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index ce0645d0c1e5..b1b93317d054 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -653,8 +653,6 @@ const struct drm_connector_helper_funcs
const struct drm_connector_funcs psb_intel_lvds_connector_funcs = {
.dpms = drm_helper_connector_dpms,
- .save = psb_intel_lvds_save,
- .restore = psb_intel_lvds_restore,
.detect = psb_intel_lvds_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = psb_intel_lvds_set_property,
@@ -715,6 +713,9 @@ void psb_intel_lvds_init(struct drm_device *dev,
gma_encoder->dev_priv = lvds_priv;
connector = &gma_connector->base;
+ gma_connector->save = psb_intel_lvds_save;
+ gma_connector->restore = psb_intel_lvds_restore;
+
encoder = &gma_encoder->base;
drm_connector_init(dev, connector,
&psb_intel_lvds_connector_funcs,
@@ -722,7 +723,7 @@ void psb_intel_lvds_init(struct drm_device *dev,
drm_encoder_init(dev, encoder,
&psb_intel_lvds_enc_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
gma_connector_attach_encoder(gma_connector, gma_encoder);
gma_encoder->type = INTEL_OUTPUT_LVDS;
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 58529cea575d..e787d376ba67 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1837,8 +1837,6 @@ static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = {
static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = {
.dpms = drm_helper_connector_dpms,
- .save = psb_intel_sdvo_save,
- .restore = psb_intel_sdvo_restore,
.detect = psb_intel_sdvo_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = psb_intel_sdvo_set_property,
@@ -2021,6 +2019,9 @@ psb_intel_sdvo_connector_init(struct psb_intel_sdvo_connector *connector,
connector->base.base.doublescan_allowed = 0;
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
+ connector->base.save = psb_intel_sdvo_save;
+ connector->base.restore = psb_intel_sdvo_restore;
+
gma_connector_attach_encoder(&connector->base, &encoder->base);
drm_connector_register(&connector->base.base);
}
@@ -2525,7 +2526,8 @@ bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
/* encoder type will be decided later */
gma_encoder = &psb_intel_sdvo->base;
gma_encoder->type = INTEL_OUTPUT_SDVO;
- drm_encoder_init(dev, &gma_encoder->base, &psb_intel_sdvo_enc_funcs, 0);
+ drm_encoder_init(dev, &gma_encoder->base, &psb_intel_sdvo_enc_funcs,
+ 0, NULL);
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 00416f23b5cb..533d1e3d4a99 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -752,7 +752,7 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
adv7511->f_tmds = mode->clock;
}
-static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
+static const struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
.dpms = adv7511_encoder_dpms,
.mode_valid = adv7511_encoder_mode_valid,
.mode_set = adv7511_encoder_mode_set,
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index d9a72c96e56c..90db5f4dcce5 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -371,7 +371,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
return 0;
}
-static struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
+static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
.set_config = ch7006_encoder_set_config,
.destroy = ch7006_encoder_destroy,
.dpms = ch7006_encoder_dpms,
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
index 002ce7874332..c400428f6c8c 100644
--- a/drivers/gpu/drm/i2c/sil164_drv.c
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
@@ -341,7 +341,7 @@ sil164_encoder_destroy(struct drm_encoder *encoder)
drm_i2c_encoder_destroy(encoder);
}
-static struct drm_encoder_slave_funcs sil164_encoder_funcs = {
+static const struct drm_encoder_slave_funcs sil164_encoder_funcs = {
.set_config = sil164_encoder_set_config,
.destroy = sil164_encoder_destroy,
.dpms = sil164_encoder_dpms,
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 896b6aaf8c4d..34e38749a817 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -22,6 +22,7 @@
#include <sound/asoundef.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
@@ -855,18 +856,6 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
priv->dpms = mode;
}
-static void
-tda998x_encoder_save(struct drm_encoder *encoder)
-{
- DBG("");
-}
-
-static void
-tda998x_encoder_restore(struct drm_encoder *encoder)
-{
- DBG("");
-}
-
static bool
tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
@@ -878,7 +867,10 @@ tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
static int tda998x_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- if (mode->clock > 150000)
+ /* TDA19988 dotclock can go up to 165MHz */
+ struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
+
+ if (mode->clock > ((priv->rev == TDA19988) ? 165000 : 150000))
return MODE_CLOCK_HIGH;
if (mode->htotal >= BIT(13))
return MODE_BAD_HVALUE;
@@ -1351,8 +1343,6 @@ static void tda998x_encoder_commit(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = {
.dpms = tda998x_encoder_dpms,
- .save = tda998x_encoder_save,
- .restore = tda998x_encoder_restore,
.mode_fixup = tda998x_encoder_mode_fixup,
.prepare = tda998x_encoder_prepare,
.commit = tda998x_encoder_commit,
@@ -1393,10 +1383,13 @@ static void tda998x_connector_destroy(struct drm_connector *connector)
}
static const struct drm_connector_funcs tda998x_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
+ .dpms = drm_atomic_helper_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = tda998x_connector_detect,
.destroy = tda998x_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int tda998x_bind(struct device *dev, struct device *master, void *data)
@@ -1437,7 +1430,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
goto err_encoder;
@@ -1453,7 +1446,6 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
if (ret)
goto err_sysfs;
- priv->connector.encoder = &priv->encoder;
drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
return 0;
@@ -1472,6 +1464,7 @@ static void tda998x_unbind(struct device *dev, struct device *master,
{
struct tda998x_priv *priv = dev_get_drvdata(dev);
+ drm_connector_unregister(&priv->connector);
drm_connector_cleanup(&priv->connector);
drm_encoder_cleanup(&priv->encoder);
tda998x_destroy(priv);
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 051eab33e4c7..fcd77b27514d 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -10,6 +10,7 @@ config DRM_I915
# the shmem_readpage() which depends upon tmpfs
select SHMEM
select TMPFS
+ select STOP_MACHINE
select DRM_KMS_HELPER
select DRM_PANEL
select DRM_MIPI_DSI
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 44d290ae1999..0851de07bd13 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -77,6 +77,7 @@ i915-y += dvo_ch7017.o \
dvo_tfp410.o \
intel_crt.o \
intel_ddi.o \
+ intel_dp_link_training.o \
intel_dp_mst.o \
intel_dp.o \
intel_dsi.o \
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h
index 0e2c1b9648a7..5e6a3013da49 100644
--- a/drivers/gpu/drm/i915/dvo.h
+++ b/drivers/gpu/drm/i915/dvo.h
@@ -32,7 +32,8 @@ struct intel_dvo_device {
const char *name;
int type;
/* DVOA/B/C output register */
- u32 dvo_reg;
+ i915_reg_t dvo_reg;
+ i915_reg_t dvo_srcdim_reg;
/* GPIO register used for i2c bus to control this device */
u32 gpio;
int slave_addr;
@@ -128,11 +129,11 @@ struct intel_dvo_dev_ops {
void (*dump_regs)(struct intel_dvo_device *dvo);
};
-extern struct intel_dvo_dev_ops sil164_ops;
-extern struct intel_dvo_dev_ops ch7xxx_ops;
-extern struct intel_dvo_dev_ops ivch_ops;
-extern struct intel_dvo_dev_ops tfp410_ops;
-extern struct intel_dvo_dev_ops ch7017_ops;
-extern struct intel_dvo_dev_ops ns2501_ops;
+extern const struct intel_dvo_dev_ops sil164_ops;
+extern const struct intel_dvo_dev_ops ch7xxx_ops;
+extern const struct intel_dvo_dev_ops ivch_ops;
+extern const struct intel_dvo_dev_ops tfp410_ops;
+extern const struct intel_dvo_dev_ops ch7017_ops;
+extern const struct intel_dvo_dev_ops ns2501_ops;
#endif /* _INTEL_DVO_H */
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
index cbb22027a3ce..b3c7c199200c 100644
--- a/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -402,7 +402,7 @@ static void ch7017_destroy(struct intel_dvo_device *dvo)
}
}
-struct intel_dvo_dev_ops ch7017_ops = {
+const struct intel_dvo_dev_ops ch7017_ops = {
.init = ch7017_init,
.detect = ch7017_detect,
.mode_valid = ch7017_mode_valid,
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 4b4acc1a06fe..44b3159f2fe8 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -356,7 +356,7 @@ static void ch7xxx_destroy(struct intel_dvo_device *dvo)
}
}
-struct intel_dvo_dev_ops ch7xxx_ops = {
+const struct intel_dvo_dev_ops ch7xxx_ops = {
.init = ch7xxx_init,
.detect = ch7xxx_detect,
.mode_valid = ch7xxx_mode_valid,
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index ff9f1b077d83..4950b82f5b49 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -490,7 +490,7 @@ static void ivch_destroy(struct intel_dvo_device *dvo)
}
}
-struct intel_dvo_dev_ops ivch_ops = {
+const struct intel_dvo_dev_ops ivch_ops = {
.init = ivch_init,
.dpms = ivch_dpms,
.get_hw_state = ivch_get_hw_state,
diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c
index 063859fff0f0..2379c33cfe51 100644
--- a/drivers/gpu/drm/i915/dvo_ns2501.c
+++ b/drivers/gpu/drm/i915/dvo_ns2501.c
@@ -698,7 +698,7 @@ static void ns2501_destroy(struct intel_dvo_device *dvo)
}
}
-struct intel_dvo_dev_ops ns2501_ops = {
+const struct intel_dvo_dev_ops ns2501_ops = {
.init = ns2501_init,
.detect = ns2501_detect,
.mode_valid = ns2501_mode_valid,
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
index 26f13eb634f9..1c1a0674dbab 100644
--- a/drivers/gpu/drm/i915/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/dvo_sil164.c
@@ -267,7 +267,7 @@ static void sil164_destroy(struct intel_dvo_device *dvo)
}
}
-struct intel_dvo_dev_ops sil164_ops = {
+const struct intel_dvo_dev_ops sil164_ops = {
.init = sil164_init,
.detect = sil164_detect,
.mode_valid = sil164_mode_valid,
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
index 6f1a0a6d4e22..31e181da93db 100644
--- a/drivers/gpu/drm/i915/dvo_tfp410.c
+++ b/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -306,7 +306,7 @@ static void tfp410_destroy(struct intel_dvo_device *dvo)
}
}
-struct intel_dvo_dev_ops tfp410_ops = {
+const struct intel_dvo_dev_ops tfp410_ops = {
.init = tfp410_init,
.detect = tfp410_detect,
.mode_valid = tfp410_mode_valid,
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index db58c8d664c2..814d894ed925 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -407,14 +407,14 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = {
* LRI.
*/
struct drm_i915_reg_descriptor {
- u32 addr;
+ i915_reg_t addr;
u32 mask;
u32 value;
};
/* Convenience macro for adding 32-bit registers. */
-#define REG32(address, ...) \
- { .addr = address, __VA_ARGS__ }
+#define REG32(_reg, ...) \
+ { .addr = (_reg), __VA_ARGS__ }
/*
* Convenience macro for adding 64-bit registers.
@@ -423,8 +423,13 @@ struct drm_i915_reg_descriptor {
* access commands only allow 32-bit accesses. Hence, we have to include
* entries for both halves of the 64-bit registers.
*/
-#define REG64(addr) \
- REG32(addr), REG32(addr + sizeof(u32))
+#define REG64(_reg) \
+ { .addr = _reg }, \
+ { .addr = _reg ## _UDW }
+
+#define REG64_IDX(_reg, idx) \
+ { .addr = _reg(idx) }, \
+ { .addr = _reg ## _UDW(idx) }
static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
REG64(GPGPU_THREADS_DISPATCHED),
@@ -451,14 +456,14 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
REG32(GEN7_GPGPU_DISPATCHDIMX),
REG32(GEN7_GPGPU_DISPATCHDIMY),
REG32(GEN7_GPGPU_DISPATCHDIMZ),
- REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)),
- REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)),
- REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)),
- REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)),
- REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)),
- REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)),
- REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)),
- REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)),
+ REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 0),
+ REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 1),
+ REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 2),
+ REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 3),
+ REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 0),
+ REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 1),
+ REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 2),
+ REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 3),
REG32(GEN7_SO_WRITE_OFFSET(0)),
REG32(GEN7_SO_WRITE_OFFSET(1)),
REG32(GEN7_SO_WRITE_OFFSET(2)),
@@ -592,7 +597,7 @@ static bool check_sorted(int ring_id,
bool ret = true;
for (i = 0; i < reg_count; i++) {
- u32 curr = reg_table[i].addr;
+ u32 curr = i915_mmio_reg_offset(reg_table[i].addr);
if (curr < previous) {
DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n",
@@ -847,7 +852,7 @@ find_reg(const struct drm_i915_reg_descriptor *table,
int i;
for (i = 0; i < count; i++) {
- if (table[i].addr == addr)
+ if (i915_mmio_reg_offset(table[i].addr) == addr)
return &table[i];
}
}
@@ -1023,7 +1028,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
* to the register. Hence, limit OACONTROL writes to
* only MI_LOAD_REGISTER_IMM commands.
*/
- if (reg_addr == OACONTROL) {
+ if (reg_addr == i915_mmio_reg_offset(OACONTROL)) {
if (desc->cmd.value == MI_LOAD_REGISTER_MEM) {
DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n");
return false;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 8aab974b0564..0fc38bb7276c 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1142,8 +1142,34 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
MEMSTAT_VID_SHIFT);
seq_printf(m, "Current P-state: %d\n",
(rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
- } else if (IS_GEN6(dev) || (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) ||
- IS_BROADWELL(dev) || IS_GEN9(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+ u32 freq_sts;
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+ seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
+ seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
+
+ seq_printf(m, "actual GPU freq: %d MHz\n",
+ intel_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
+
+ seq_printf(m, "current GPU freq: %d MHz\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq));
+
+ seq_printf(m, "max GPU freq: %d MHz\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+
+ seq_printf(m, "min GPU freq: %d MHz\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
+
+ seq_printf(m, "idle GPU freq: %d MHz\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
+
+ seq_printf(m,
+ "efficient (RPe) frequency: %d MHz\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
+ mutex_unlock(&dev_priv->rps.hw_lock);
+ } else if (INTEL_INFO(dev)->gen >= 6) {
u32 rp_state_limits;
u32 gt_perf_status;
u32 rp_state_cap;
@@ -1252,18 +1278,21 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 :
rp_state_cap >> 16) & 0xff;
- max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
+ max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+ GEN9_FREQ_SCALER : 1);
seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
intel_gpu_freq(dev_priv, max_freq));
max_freq = (rp_state_cap & 0xff00) >> 8;
- max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
+ max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+ GEN9_FREQ_SCALER : 1);
seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
intel_gpu_freq(dev_priv, max_freq));
max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 :
rp_state_cap >> 0) & 0xff;
- max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
+ max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+ GEN9_FREQ_SCALER : 1);
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
intel_gpu_freq(dev_priv, max_freq));
seq_printf(m, "Max overclocked frequency: %dMHz\n",
@@ -1281,33 +1310,6 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
seq_printf(m,
"efficient (RPe) frequency: %d MHz\n",
intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
- } else if (IS_VALLEYVIEW(dev)) {
- u32 freq_sts;
-
- mutex_lock(&dev_priv->rps.hw_lock);
- freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
- seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
- seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
-
- seq_printf(m, "actual GPU freq: %d MHz\n",
- intel_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
-
- seq_printf(m, "current GPU freq: %d MHz\n",
- intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq));
-
- seq_printf(m, "max GPU freq: %d MHz\n",
- intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
-
- seq_printf(m, "min GPU freq: %d MHz\n",
- intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
-
- seq_printf(m, "idle GPU freq: %d MHz\n",
- intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
-
- seq_printf(m,
- "efficient (RPe) frequency: %d MHz\n",
- intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
- mutex_unlock(&dev_priv->rps.hw_lock);
} else {
seq_puts(m, "no P-state info available\n");
}
@@ -1523,7 +1525,7 @@ static int gen6_drpc_info(struct seq_file *m)
seq_printf(m, "RC information accurate: %s\n", yesno(count < 51));
}
- gt_core_status = readl(dev_priv->regs + GEN6_GT_CORE_STATUS);
+ gt_core_status = I915_READ_FW(GEN6_GT_CORE_STATUS);
trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4, true);
rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
@@ -1599,7 +1601,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
return vlv_drpc_info(m);
else if (INTEL_INFO(dev)->gen >= 6)
return gen6_drpc_info(m);
@@ -1636,11 +1638,11 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
intel_runtime_pm_get(dev_priv);
mutex_lock(&dev_priv->fbc.lock);
- if (intel_fbc_enabled(dev_priv))
+ if (intel_fbc_is_active(dev_priv))
seq_puts(m, "FBC enabled\n");
else
seq_printf(m, "FBC disabled: %s\n",
- intel_no_fbc_reason_str(dev_priv->fbc.no_fbc_reason));
+ dev_priv->fbc.no_fbc_reason);
if (INTEL_INFO(dev_priv)->gen >= 7)
seq_printf(m, "Compressing: %s\n",
@@ -1740,7 +1742,7 @@ static int i915_sr_status(struct seq_file *m, void *unused)
sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
else if (IS_PINEVIEW(dev))
sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
- else if (IS_VALLEYVIEW(dev))
+ else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
sr_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
intel_runtime_pm_put(dev_priv);
@@ -1801,7 +1803,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
if (ret)
goto out;
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
/* Convert GT frequency to 50 HZ units */
min_gpu_freq =
dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER;
@@ -1821,7 +1823,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
&ia_freq);
seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
intel_gpu_freq(dev_priv, (gpu_freq *
- (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1))),
+ (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+ GEN9_FREQ_SCALER : 1))),
((ia_freq >> 0) & 0xff) * 100,
((ia_freq >> 8) & 0xff) * 100);
}
@@ -1839,25 +1842,31 @@ static int i915_opregion(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
- void *data = kmalloc(OPREGION_SIZE, GFP_KERNEL);
int ret;
- if (data == NULL)
- return -ENOMEM;
-
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
goto out;
- if (opregion->header) {
- memcpy(data, opregion->header, OPREGION_SIZE);
- seq_write(m, data, OPREGION_SIZE);
- }
+ if (opregion->header)
+ seq_write(m, opregion->header, OPREGION_SIZE);
mutex_unlock(&dev->struct_mutex);
out:
- kfree(data);
+ return 0;
+}
+
+static int i915_vbt(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_opregion *opregion = &dev_priv->opregion;
+
+ if (opregion->vbt)
+ seq_write(m, opregion->vbt, opregion->vbt_size);
+
return 0;
}
@@ -1865,31 +1874,29 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
- struct intel_fbdev *ifbdev = NULL;
- struct intel_framebuffer *fb;
+ struct intel_framebuffer *fbdev_fb = NULL;
struct drm_framebuffer *drm_fb;
#ifdef CONFIG_DRM_FBDEV_EMULATION
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- ifbdev = dev_priv->fbdev;
- fb = to_intel_framebuffer(ifbdev->helper.fb);
-
- seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
- fb->base.width,
- fb->base.height,
- fb->base.depth,
- fb->base.bits_per_pixel,
- fb->base.modifier[0],
- atomic_read(&fb->base.refcount.refcount));
- describe_obj(m, fb->obj);
- seq_putc(m, '\n');
+ if (to_i915(dev)->fbdev) {
+ fbdev_fb = to_intel_framebuffer(to_i915(dev)->fbdev->helper.fb);
+
+ seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
+ fbdev_fb->base.width,
+ fbdev_fb->base.height,
+ fbdev_fb->base.depth,
+ fbdev_fb->base.bits_per_pixel,
+ fbdev_fb->base.modifier[0],
+ atomic_read(&fbdev_fb->base.refcount.refcount));
+ describe_obj(m, fbdev_fb->obj);
+ seq_putc(m, '\n');
+ }
#endif
mutex_lock(&dev->mode_config.fb_lock);
drm_for_each_fb(drm_fb, dev) {
- fb = to_intel_framebuffer(drm_fb);
- if (ifbdev && &fb->base == ifbdev->helper.fb)
+ struct intel_framebuffer *fb = to_intel_framebuffer(drm_fb);
+ if (fb == fbdev_fb)
continue;
seq_printf(m, "user size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
@@ -2402,6 +2409,12 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data)
guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
seq_printf(m, "\tversion found: %d.%d\n",
guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found);
+ seq_printf(m, "\theader: offset is %d; size = %d\n",
+ guc_fw->header_offset, guc_fw->header_size);
+ seq_printf(m, "\tuCode: offset is %d; size = %d\n",
+ guc_fw->ucode_offset, guc_fw->ucode_size);
+ seq_printf(m, "\tRSA: offset is %d; size = %d\n",
+ guc_fw->rsa_offset, guc_fw->rsa_size);
tmp = I915_READ(GUC_STATUS);
@@ -2461,15 +2474,15 @@ static int i915_guc_info(struct seq_file *m, void *data)
if (!HAS_GUC_SCHED(dev_priv->dev))
return 0;
+ if (mutex_lock_interruptible(&dev->struct_mutex))
+ return 0;
+
/* Take a local copy of the GuC data, so we can dump it at leisure */
- spin_lock(&dev_priv->guc.host2guc_lock);
guc = dev_priv->guc;
- if (guc.execbuf_client) {
- spin_lock(&guc.execbuf_client->wq_lock);
+ if (guc.execbuf_client)
client = *guc.execbuf_client;
- spin_unlock(&guc.execbuf_client->wq_lock);
- }
- spin_unlock(&dev_priv->guc.host2guc_lock);
+
+ mutex_unlock(&dev->struct_mutex);
seq_printf(m, "GuC total action count: %llu\n", guc.action_count);
seq_printf(m, "GuC action failure count: %u\n", guc.action_fail);
@@ -2550,7 +2563,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
yesno(work_busy(&dev_priv->psr.work.work)));
if (HAS_DDI(dev))
- enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+ enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
else {
for_each_pipe(dev_priv, pipe) {
stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
@@ -2570,9 +2583,12 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
}
seq_puts(m, "\n");
- /* CHV PSR has no kind of performance counter */
- if (HAS_DDI(dev)) {
- psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
+ /*
+ * VLV/CHV PSR has no kind of performance counter
+ * SKL+ Perf counter is reset to 0 everytime DC state is entered
+ */
+ if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+ psrperf = I915_READ(EDP_PSR_PERF_CNT) &
EDP_PSR_PERF_CNT_MASK;
seq_printf(m, "Performance_Counter: %u\n", psrperf);
@@ -2673,77 +2689,6 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused)
return 0;
}
-static const char *power_domain_str(enum intel_display_power_domain domain)
-{
- switch (domain) {
- case POWER_DOMAIN_PIPE_A:
- return "PIPE_A";
- case POWER_DOMAIN_PIPE_B:
- return "PIPE_B";
- case POWER_DOMAIN_PIPE_C:
- return "PIPE_C";
- case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
- return "PIPE_A_PANEL_FITTER";
- case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
- return "PIPE_B_PANEL_FITTER";
- case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
- return "PIPE_C_PANEL_FITTER";
- case POWER_DOMAIN_TRANSCODER_A:
- return "TRANSCODER_A";
- case POWER_DOMAIN_TRANSCODER_B:
- return "TRANSCODER_B";
- case POWER_DOMAIN_TRANSCODER_C:
- return "TRANSCODER_C";
- case POWER_DOMAIN_TRANSCODER_EDP:
- return "TRANSCODER_EDP";
- case POWER_DOMAIN_PORT_DDI_A_2_LANES:
- return "PORT_DDI_A_2_LANES";
- case POWER_DOMAIN_PORT_DDI_A_4_LANES:
- return "PORT_DDI_A_4_LANES";
- case POWER_DOMAIN_PORT_DDI_B_2_LANES:
- return "PORT_DDI_B_2_LANES";
- case POWER_DOMAIN_PORT_DDI_B_4_LANES:
- return "PORT_DDI_B_4_LANES";
- case POWER_DOMAIN_PORT_DDI_C_2_LANES:
- return "PORT_DDI_C_2_LANES";
- case POWER_DOMAIN_PORT_DDI_C_4_LANES:
- return "PORT_DDI_C_4_LANES";
- case POWER_DOMAIN_PORT_DDI_D_2_LANES:
- return "PORT_DDI_D_2_LANES";
- case POWER_DOMAIN_PORT_DDI_D_4_LANES:
- return "PORT_DDI_D_4_LANES";
- case POWER_DOMAIN_PORT_DDI_E_2_LANES:
- return "PORT_DDI_E_2_LANES";
- case POWER_DOMAIN_PORT_DSI:
- return "PORT_DSI";
- case POWER_DOMAIN_PORT_CRT:
- return "PORT_CRT";
- case POWER_DOMAIN_PORT_OTHER:
- return "PORT_OTHER";
- case POWER_DOMAIN_VGA:
- return "VGA";
- case POWER_DOMAIN_AUDIO:
- return "AUDIO";
- case POWER_DOMAIN_PLLS:
- return "PLLS";
- case POWER_DOMAIN_AUX_A:
- return "AUX_A";
- case POWER_DOMAIN_AUX_B:
- return "AUX_B";
- case POWER_DOMAIN_AUX_C:
- return "AUX_C";
- case POWER_DOMAIN_AUX_D:
- return "AUX_D";
- case POWER_DOMAIN_GMBUS:
- return "GMBUS";
- case POWER_DOMAIN_INIT:
- return "INIT";
- default:
- MISSING_CASE(domain);
- return "?";
- }
-}
-
static int i915_power_domain_info(struct seq_file *m, void *unused)
{
struct drm_info_node *node = m->private;
@@ -2769,7 +2714,7 @@ static int i915_power_domain_info(struct seq_file *m, void *unused)
continue;
seq_printf(m, " %-23s %d\n",
- power_domain_str(power_domain),
+ intel_display_power_domain_str(power_domain),
power_domains->domain_use_count[power_domain]);
}
}
@@ -2779,6 +2724,51 @@ static int i915_power_domain_info(struct seq_file *m, void *unused)
return 0;
}
+static int i915_dmc_info(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_csr *csr;
+
+ if (!HAS_CSR(dev)) {
+ seq_puts(m, "not supported\n");
+ return 0;
+ }
+
+ csr = &dev_priv->csr;
+
+ intel_runtime_pm_get(dev_priv);
+
+ seq_printf(m, "fw loaded: %s\n", yesno(csr->dmc_payload != NULL));
+ seq_printf(m, "path: %s\n", csr->fw_path);
+
+ if (!csr->dmc_payload)
+ goto out;
+
+ seq_printf(m, "version: %d.%d\n", CSR_VERSION_MAJOR(csr->version),
+ CSR_VERSION_MINOR(csr->version));
+
+ if (IS_SKYLAKE(dev) && csr->version >= CSR_VERSION(1, 6)) {
+ seq_printf(m, "DC3 -> DC5 count: %d\n",
+ I915_READ(SKL_CSR_DC3_DC5_COUNT));
+ seq_printf(m, "DC5 -> DC6 count: %d\n",
+ I915_READ(SKL_CSR_DC5_DC6_COUNT));
+ } else if (IS_BROXTON(dev) && 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)));
+ seq_printf(m, "ssp base: 0x%08x\n", I915_READ(CSR_SSP_BASE));
+ seq_printf(m, "htp: 0x%08x\n", I915_READ(CSR_HTP_SKL));
+
+ intel_runtime_pm_put(dev_priv);
+
+ return 0;
+}
+
static void intel_seq_print_mode(struct seq_file *m, int tabs,
struct drm_display_mode *mode)
{
@@ -2865,6 +2855,20 @@ static void intel_dp_info(struct seq_file *m,
intel_panel_info(m, &intel_connector->panel);
}
+static void intel_dp_mst_info(struct seq_file *m,
+ struct intel_connector *intel_connector)
+{
+ struct intel_encoder *intel_encoder = intel_connector->encoder;
+ struct intel_dp_mst_encoder *intel_mst =
+ enc_to_mst(&intel_encoder->base);
+ struct intel_digital_port *intel_dig_port = intel_mst->primary;
+ struct intel_dp *intel_dp = &intel_dig_port->dp;
+ bool has_audio = drm_dp_mst_port_has_audio(&intel_dp->mst_mgr,
+ intel_connector->port);
+
+ seq_printf(m, "\taudio support: %s\n", yesno(has_audio));
+}
+
static void intel_hdmi_info(struct seq_file *m,
struct intel_connector *intel_connector)
{
@@ -2908,6 +2912,8 @@ static void intel_connector_info(struct seq_file *m,
intel_hdmi_info(m, intel_connector);
else if (intel_encoder->type == INTEL_OUTPUT_LVDS)
intel_lvds_info(m, intel_connector);
+ else if (intel_encoder->type == INTEL_OUTPUT_DP_MST)
+ intel_dp_mst_info(m, intel_connector);
}
seq_printf(m, "\tmodes:\n");
@@ -2946,6 +2952,107 @@ static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y)
return cursor_active(dev, pipe);
}
+static const char *plane_type(enum drm_plane_type type)
+{
+ switch (type) {
+ case DRM_PLANE_TYPE_OVERLAY:
+ return "OVL";
+ case DRM_PLANE_TYPE_PRIMARY:
+ return "PRI";
+ case DRM_PLANE_TYPE_CURSOR:
+ return "CUR";
+ /*
+ * Deliberately omitting default: to generate compiler warnings
+ * when a new drm_plane_type gets added.
+ */
+ }
+
+ return "unknown";
+}
+
+static const char *plane_rotation(unsigned int rotation)
+{
+ static char buf[48];
+ /*
+ * According to doc only one DRM_ROTATE_ is allowed but this
+ * will print them all to visualize if the values are misused
+ */
+ snprintf(buf, sizeof(buf),
+ "%s%s%s%s%s%s(0x%08x)",
+ (rotation & BIT(DRM_ROTATE_0)) ? "0 " : "",
+ (rotation & BIT(DRM_ROTATE_90)) ? "90 " : "",
+ (rotation & BIT(DRM_ROTATE_180)) ? "180 " : "",
+ (rotation & BIT(DRM_ROTATE_270)) ? "270 " : "",
+ (rotation & BIT(DRM_REFLECT_X)) ? "FLIPX " : "",
+ (rotation & BIT(DRM_REFLECT_Y)) ? "FLIPY " : "",
+ rotation);
+
+ return buf;
+}
+
+static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct intel_plane *intel_plane;
+
+ for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+ struct drm_plane_state *state;
+ struct drm_plane *plane = &intel_plane->base;
+
+ if (!plane->state) {
+ seq_puts(m, "plane->state is NULL!\n");
+ continue;
+ }
+
+ state = plane->state;
+
+ seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n",
+ plane->base.id,
+ plane_type(intel_plane->base.type),
+ state->crtc_x, state->crtc_y,
+ state->crtc_w, state->crtc_h,
+ (state->src_x >> 16),
+ ((state->src_x & 0xffff) * 15625) >> 10,
+ (state->src_y >> 16),
+ ((state->src_y & 0xffff) * 15625) >> 10,
+ (state->src_w >> 16),
+ ((state->src_w & 0xffff) * 15625) >> 10,
+ (state->src_h >> 16),
+ ((state->src_h & 0xffff) * 15625) >> 10,
+ state->fb ? drm_get_format_name(state->fb->pixel_format) : "N/A",
+ plane_rotation(state->rotation));
+ }
+}
+
+static void intel_scaler_info(struct seq_file *m, struct intel_crtc *intel_crtc)
+{
+ struct intel_crtc_state *pipe_config;
+ int num_scalers = intel_crtc->num_scalers;
+ int i;
+
+ pipe_config = to_intel_crtc_state(intel_crtc->base.state);
+
+ /* Not all platformas have a scaler */
+ if (num_scalers) {
+ seq_printf(m, "\tnum_scalers=%d, scaler_users=%x scaler_id=%d",
+ num_scalers,
+ pipe_config->scaler_state.scaler_users,
+ pipe_config->scaler_state.scaler_id);
+
+ for (i = 0; i < SKL_NUM_SCALERS; i++) {
+ struct intel_scaler *sc =
+ &pipe_config->scaler_state.scalers[i];
+
+ seq_printf(m, ", scalers[%d]: use=%s, mode=%x",
+ i, yesno(sc->in_use), sc->mode);
+ }
+ seq_puts(m, "\n");
+ } else {
+ seq_puts(m, "\tNo scalers available on this platform\n");
+ }
+}
+
static int i915_display_info(struct seq_file *m, void *unused)
{
struct drm_info_node *node = m->private;
@@ -2965,10 +3072,12 @@ static int i915_display_info(struct seq_file *m, void *unused)
pipe_config = to_intel_crtc_state(crtc->base.state);
- seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n",
+ seq_printf(m, "CRTC %d: pipe: %c, active=%s, (size=%dx%d), dither=%s, bpp=%d\n",
crtc->base.base.id, pipe_name(crtc->pipe),
yesno(pipe_config->base.active),
- pipe_config->pipe_src_w, pipe_config->pipe_src_h);
+ pipe_config->pipe_src_w, pipe_config->pipe_src_h,
+ yesno(pipe_config->dither), pipe_config->pipe_bpp);
+
if (pipe_config->base.active) {
intel_crtc_info(m, crtc);
@@ -2978,6 +3087,8 @@ static int i915_display_info(struct seq_file *m, void *unused)
x, y, crtc->base.cursor->state->crtc_w,
crtc->base.cursor->state->crtc_h,
crtc->cursor_addr, yesno(active));
+ intel_scaler_info(m, crtc);
+ intel_plane_info(m, crtc);
}
seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s \n",
@@ -3112,7 +3223,8 @@ static int i915_wa_registers(struct seq_file *m, void *unused)
seq_printf(m, "Workarounds applied: %d\n", dev_priv->workarounds.count);
for (i = 0; i < dev_priv->workarounds.count; ++i) {
- u32 addr, mask, value, read;
+ i915_reg_t addr;
+ u32 mask, value, read;
bool ok;
addr = dev_priv->workarounds.reg[i].addr;
@@ -3121,7 +3233,7 @@ static int i915_wa_registers(struct seq_file *m, void *unused)
read = I915_READ(addr);
ok = (value & mask) == (read & mask);
seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X, read: 0x%08x, status: %s\n",
- addr, value, mask, read, ok ? "OK" : "FAIL");
+ i915_mmio_reg_offset(addr), value, mask, read, ok ? "OK" : "FAIL");
}
intel_runtime_pm_put(dev_priv);
@@ -3892,7 +4004,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
ret = i8xx_pipe_crc_ctl_reg(&source, &val);
else if (INTEL_INFO(dev)->gen < 5)
ret = i9xx_pipe_crc_ctl_reg(dev, pipe, &source, &val);
- else if (IS_VALLEYVIEW(dev))
+ else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
ret = vlv_pipe_crc_ctl_reg(dev, pipe, &source, &val);
else if (IS_GEN5(dev) || IS_GEN6(dev))
ret = ilk_pipe_crc_ctl_reg(&source, &val);
@@ -3961,7 +4073,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
if (IS_G4X(dev))
g4x_undo_pipe_scramble_reset(dev, pipe);
- else if (IS_VALLEYVIEW(dev))
+ else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_undo_pipe_scramble_reset(dev, pipe);
else if (IS_HASWELL(dev) && pipe == PIPE_A)
hsw_trans_edp_pipe_A_crc_wa(dev, false);
@@ -4351,7 +4463,8 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[8])
* - WM1+ latency values in 0.5us units
* - latencies are in us on gen9/vlv/chv
*/
- if (INTEL_INFO(dev)->gen >= 9 || IS_VALLEYVIEW(dev))
+ if (INTEL_INFO(dev)->gen >= 9 || IS_VALLEYVIEW(dev) ||
+ IS_CHERRYVIEW(dev))
latency *= 10;
else if (level > 0)
latency *= 5;
@@ -5025,7 +5138,7 @@ static void gen9_sseu_device_status(struct drm_device *dev,
stat->slice_total++;
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
ss_cnt = INTEL_INFO(dev)->subslice_per_slice;
for (ss = 0; ss < ss_max; ss++) {
@@ -5225,6 +5338,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_ips_status", i915_ips_status, 0},
{"i915_sr_status", i915_sr_status, 0},
{"i915_opregion", i915_opregion, 0},
+ {"i915_vbt", i915_vbt, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_context_status", i915_context_status, 0},
{"i915_dump_lrc", i915_dump_lrc, 0},
@@ -5238,6 +5352,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_energy_uJ", i915_energy_uJ, 0},
{"i915_runtime_pm_status", i915_runtime_pm_status, 0},
{"i915_power_domain_info", i915_power_domain_info, 0},
+ {"i915_dmc_info", i915_dmc_info, 0},
{"i915_display_info", i915_display_info, 0},
{"i915_semaphore_status", i915_semaphore_status, 0},
{"i915_shared_dplls_info", i915_shared_dplls_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index b4741d121a74..d70d96fe553b 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -28,7 +28,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/async.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
@@ -170,6 +169,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_RESOURCE_STREAMER:
value = HAS_RESOURCE_STREAMER(dev);
break;
+ case I915_PARAM_HAS_EXEC_SOFTPIN:
+ value = 1;
+ break;
default:
DRM_DEBUG("Unknown parameter %d\n", param->param);
return -EINVAL;
@@ -257,7 +259,7 @@ intel_setup_mchbar(struct drm_device *dev)
u32 temp;
bool enabled;
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
return;
dev_priv->mchbar_need_disable = false;
@@ -338,7 +340,7 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
i915_resume_switcheroo(dev);
dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
- pr_err("switched off\n");
+ pr_info("switched off\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
i915_suspend_switcheroo(dev, pmm);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
@@ -368,7 +370,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- ret = intel_parse_bios(dev);
+ ret = intel_bios_init(dev_priv);
if (ret)
DRM_INFO("failed to find VBIOS tables\n");
@@ -396,12 +398,16 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (ret)
goto cleanup_vga_switcheroo;
- intel_power_domains_init_hw(dev_priv);
+ intel_power_domains_init_hw(dev_priv, false);
+
+ intel_csr_ucode_init(dev_priv);
ret = intel_irq_install(dev_priv);
if (ret)
goto cleanup_gem_stolen;
+ intel_setup_gmbus(dev);
+
/* Important: The output setup functions called by modeset_init need
* working irqs for e.g. gmbus and dp aux transfers. */
intel_modeset_init(dev);
@@ -437,7 +443,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
* scanning against hotplug events. Hence do this first and ignore the
* tiny window where we will loose hotplug notifactions.
*/
- async_schedule(intel_fbdev_initial_config, dev_priv);
+ intel_fbdev_initial_config_async(dev);
drm_kms_helper_poll_init(dev);
@@ -451,6 +457,7 @@ cleanup_gem:
cleanup_irq:
intel_guc_ucode_fini(dev);
drm_irq_uninstall(dev);
+ intel_teardown_gmbus(dev);
cleanup_gem_stolen:
i915_gem_cleanup_stolen(dev);
cleanup_vga_switcheroo:
@@ -663,7 +670,8 @@ static void gen9_sseu_info_init(struct drm_device *dev)
* supports EU power gating on devices with more than one EU
* pair per subslice.
*/
- info->has_slice_pg = (IS_SKYLAKE(dev) && (info->slice_total > 1));
+ info->has_slice_pg = ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) &&
+ (info->slice_total > 1));
info->has_subslice_pg = (IS_BROXTON(dev) && (info->subslice_total > 1));
info->has_eu_pg = (info->eu_per_subslice > 2);
}
@@ -777,7 +785,7 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
info->num_sprites[PIPE_A] = 2;
info->num_sprites[PIPE_B] = 2;
info->num_sprites[PIPE_C] = 1;
- } else if (IS_VALLEYVIEW(dev))
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
for_each_pipe(dev_priv, pipe)
info->num_sprites[pipe] = 2;
else
@@ -789,7 +797,7 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
info->num_pipes = 0;
} else if (info->num_pipes > 0 &&
(INTEL_INFO(dev)->gen == 7 || INTEL_INFO(dev)->gen == 8) &&
- !IS_VALLEYVIEW(dev)) {
+ HAS_PCH_SPLIT(dev)) {
u32 fuse_strap = I915_READ(FUSE_STRAP);
u32 sfuse_strap = I915_READ(SFUSE_STRAP);
@@ -834,9 +842,6 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
static void intel_init_dpio(struct drm_i915_private *dev_priv)
{
- if (!IS_VALLEYVIEW(dev_priv))
- return;
-
/*
* IOSF_PORT_DPIO is used for VLV x2 PHY (DP/HDMI B and C),
* CHV x1 PHY (DP/HDMI D)
@@ -845,7 +850,7 @@ static void intel_init_dpio(struct drm_i915_private *dev_priv)
if (IS_CHERRYVIEW(dev_priv)) {
DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO_2;
DPIO_PHY_IOSF_PORT(DPIO_PHY1) = IOSF_PORT_DPIO;
- } else {
+ } else if (IS_VALLEYVIEW(dev_priv)) {
DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO;
}
}
@@ -890,11 +895,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->mmio_flip_lock);
mutex_init(&dev_priv->sb_lock);
mutex_init(&dev_priv->modeset_restore_lock);
- mutex_init(&dev_priv->csr_lock);
mutex_init(&dev_priv->av_mutex);
intel_pm_setup(dev);
+ intel_runtime_pm_get(dev_priv);
+
intel_display_crc_init(dev);
i915_dump_device_info(dev_priv);
@@ -937,9 +943,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_uncore_init(dev);
- /* Load CSR Firmware for SKL */
- intel_csr_ucode_init(dev);
-
ret = i915_gem_gtt_init(dev);
if (ret)
goto out_freecsr;
@@ -1028,7 +1031,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev);
- intel_setup_gmbus(dev);
intel_opregion_setup(dev);
i915_gem_load(dev);
@@ -1087,6 +1089,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
i915_audio_component_init(dev_priv);
+ intel_runtime_pm_put(dev_priv);
+
return 0;
out_power_well:
@@ -1099,7 +1103,6 @@ out_gem_unload:
if (dev->pdev->msi_enabled)
pci_disable_msi(dev->pdev);
- intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
pm_qos_remove_request(&dev_priv->pm_qos);
destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
@@ -1113,7 +1116,7 @@ out_mtrrfree:
out_gtt:
i915_global_gtt_cleanup(dev);
out_freecsr:
- intel_csr_ucode_fini(dev);
+ intel_csr_ucode_fini(dev_priv);
intel_uncore_fini(dev);
pci_iounmap(dev->pdev, dev_priv->regs);
put_bridge:
@@ -1122,6 +1125,9 @@ free_priv:
kmem_cache_destroy(dev_priv->requests);
kmem_cache_destroy(dev_priv->vmas);
kmem_cache_destroy(dev_priv->objects);
+
+ intel_runtime_pm_put(dev_priv);
+
kfree(dev_priv);
return ret;
}
@@ -1131,6 +1137,8 @@ int i915_driver_unload(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
+ intel_fbdev_fini(dev);
+
i915_audio_component_cleanup(dev_priv);
ret = i915_gem_suspend(dev);
@@ -1153,8 +1161,6 @@ int i915_driver_unload(struct drm_device *dev)
acpi_video_unregister();
- intel_fbdev_fini(dev);
-
drm_vblank_cleanup(dev);
intel_modeset_cleanup(dev);
@@ -1196,9 +1202,8 @@ int i915_driver_unload(struct drm_device *dev)
intel_fbc_cleanup_cfb(dev_priv);
i915_gem_cleanup_stolen(dev);
- intel_csr_ucode_fini(dev);
+ intel_csr_ucode_fini(dev_priv);
- intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
destroy_workqueue(dev_priv->hotplug.dp_wq);
@@ -1264,8 +1269,6 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
- if (file_priv && file_priv->bsd_ring)
- file_priv->bsd_ring = NULL;
kfree(file_priv);
}
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 760e0ce4aa26..3ac616d7363b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -228,161 +228,111 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.need_gfx_hws = 1, .has_hotplug = 1, \
.has_fbc = 1, \
.ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
- .has_llc = 1
+ .has_llc = 1, \
+ GEN_DEFAULT_PIPEOFFSETS, \
+ IVB_CURSOR_OFFSETS
static const struct intel_device_info intel_ivybridge_d_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_ivybridge_m_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
.is_mobile = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_ivybridge_q_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
.num_pipes = 0, /* legal, last one wins */
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
+#define VLV_FEATURES \
+ .gen = 7, .num_pipes = 2, \
+ .need_gfx_hws = 1, .has_hotplug = 1, \
+ .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
+ .display_mmio_offset = VLV_DISPLAY_BASE, \
+ GEN_DEFAULT_PIPEOFFSETS, \
+ CURSOR_OFFSETS
+
static const struct intel_device_info intel_valleyview_m_info = {
- GEN7_FEATURES,
- .is_mobile = 1,
- .num_pipes = 2,
+ VLV_FEATURES,
.is_valleyview = 1,
- .display_mmio_offset = VLV_DISPLAY_BASE,
- .has_fbc = 0, /* legal, last one wins */
- .has_llc = 0, /* legal, last one wins */
- GEN_DEFAULT_PIPEOFFSETS,
- CURSOR_OFFSETS,
+ .is_mobile = 1,
};
static const struct intel_device_info intel_valleyview_d_info = {
- GEN7_FEATURES,
- .num_pipes = 2,
+ VLV_FEATURES,
.is_valleyview = 1,
- .display_mmio_offset = VLV_DISPLAY_BASE,
- .has_fbc = 0, /* legal, last one wins */
- .has_llc = 0, /* legal, last one wins */
- GEN_DEFAULT_PIPEOFFSETS,
- CURSOR_OFFSETS,
};
+#define HSW_FEATURES \
+ GEN7_FEATURES, \
+ .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, \
+ .has_ddi = 1, \
+ .has_fpga_dbg = 1
+
static const struct intel_device_info intel_haswell_d_info = {
- GEN7_FEATURES,
+ HSW_FEATURES,
.is_haswell = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_haswell_m_info = {
- GEN7_FEATURES,
+ HSW_FEATURES,
.is_haswell = 1,
.is_mobile = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_broadwell_d_info = {
- .gen = 8, .num_pipes = 3,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
- .has_llc = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .has_fbc = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
+ HSW_FEATURES,
+ .gen = 8,
};
static const struct intel_device_info intel_broadwell_m_info = {
- .gen = 8, .is_mobile = 1, .num_pipes = 3,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
- .has_llc = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .has_fbc = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
+ HSW_FEATURES,
+ .gen = 8, .is_mobile = 1,
};
static const struct intel_device_info intel_broadwell_gt3d_info = {
- .gen = 8, .num_pipes = 3,
- .need_gfx_hws = 1, .has_hotplug = 1,
+ HSW_FEATURES,
+ .gen = 8,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
- .has_llc = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .has_fbc = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_broadwell_gt3m_info = {
- .gen = 8, .is_mobile = 1, .num_pipes = 3,
- .need_gfx_hws = 1, .has_hotplug = 1,
+ HSW_FEATURES,
+ .gen = 8, .is_mobile = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
- .has_llc = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .has_fbc = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_cherryview_info = {
.gen = 8, .num_pipes = 3,
.need_gfx_hws = 1, .has_hotplug = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
- .is_valleyview = 1,
+ .is_cherryview = 1,
.display_mmio_offset = VLV_DISPLAY_BASE,
GEN_CHV_PIPEOFFSETS,
CURSOR_OFFSETS,
};
static const struct intel_device_info intel_skylake_info = {
+ HSW_FEATURES,
.is_skylake = 1,
- .gen = 9, .num_pipes = 3,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
- .has_llc = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .has_fbc = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
+ .gen = 9,
};
static const struct intel_device_info intel_skylake_gt3_info = {
+ HSW_FEATURES,
.is_skylake = 1,
- .gen = 9, .num_pipes = 3,
- .need_gfx_hws = 1, .has_hotplug = 1,
+ .gen = 9,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
- .has_llc = 1,
- .has_ddi = 1,
- .has_fpga_dbg = 1,
- .has_fbc = 1,
- GEN_DEFAULT_PIPEOFFSETS,
- IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_broxton_info = {
.is_preliminary = 1,
+ .is_broxton = 1,
.gen = 9,
.need_gfx_hws = 1, .has_hotplug = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
@@ -394,50 +344,67 @@ static const struct intel_device_info intel_broxton_info = {
IVB_CURSOR_OFFSETS,
};
+static const struct intel_device_info intel_kabylake_info = {
+ HSW_FEATURES,
+ .is_preliminary = 1,
+ .is_kabylake = 1,
+ .gen = 9,
+};
+
+static const struct intel_device_info intel_kabylake_gt3_info = {
+ HSW_FEATURES,
+ .is_preliminary = 1,
+ .is_kabylake = 1,
+ .gen = 9,
+ .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
+};
+
/*
* Make sure any device matches here are from most specific to most
* general. For example, since the Quanta match is based on the subsystem
* and subvendor IDs, we need it to come before the more general IVB
* PCI ID matches, otherwise we'll use the wrong info struct above.
*/
-#define INTEL_PCI_IDS \
- INTEL_I830_IDS(&intel_i830_info), \
- INTEL_I845G_IDS(&intel_845g_info), \
- INTEL_I85X_IDS(&intel_i85x_info), \
- INTEL_I865G_IDS(&intel_i865g_info), \
- INTEL_I915G_IDS(&intel_i915g_info), \
- INTEL_I915GM_IDS(&intel_i915gm_info), \
- INTEL_I945G_IDS(&intel_i945g_info), \
- INTEL_I945GM_IDS(&intel_i945gm_info), \
- INTEL_I965G_IDS(&intel_i965g_info), \
- INTEL_G33_IDS(&intel_g33_info), \
- INTEL_I965GM_IDS(&intel_i965gm_info), \
- INTEL_GM45_IDS(&intel_gm45_info), \
- INTEL_G45_IDS(&intel_g45_info), \
- INTEL_PINEVIEW_IDS(&intel_pineview_info), \
- INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info), \
- INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info), \
- INTEL_SNB_D_IDS(&intel_sandybridge_d_info), \
- INTEL_SNB_M_IDS(&intel_sandybridge_m_info), \
- INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */ \
- INTEL_IVB_M_IDS(&intel_ivybridge_m_info), \
- INTEL_IVB_D_IDS(&intel_ivybridge_d_info), \
- INTEL_HSW_D_IDS(&intel_haswell_d_info), \
- INTEL_HSW_M_IDS(&intel_haswell_m_info), \
- INTEL_VLV_M_IDS(&intel_valleyview_m_info), \
- INTEL_VLV_D_IDS(&intel_valleyview_d_info), \
- INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info), \
- INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), \
- INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \
- INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \
- INTEL_CHV_IDS(&intel_cherryview_info), \
- INTEL_SKL_GT1_IDS(&intel_skylake_info), \
- INTEL_SKL_GT2_IDS(&intel_skylake_info), \
- INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info), \
- INTEL_BXT_IDS(&intel_broxton_info)
-
-static const struct pci_device_id pciidlist[] = { /* aka */
- INTEL_PCI_IDS,
+static const struct pci_device_id pciidlist[] = {
+ INTEL_I830_IDS(&intel_i830_info),
+ INTEL_I845G_IDS(&intel_845g_info),
+ INTEL_I85X_IDS(&intel_i85x_info),
+ INTEL_I865G_IDS(&intel_i865g_info),
+ INTEL_I915G_IDS(&intel_i915g_info),
+ INTEL_I915GM_IDS(&intel_i915gm_info),
+ INTEL_I945G_IDS(&intel_i945g_info),
+ INTEL_I945GM_IDS(&intel_i945gm_info),
+ INTEL_I965G_IDS(&intel_i965g_info),
+ INTEL_G33_IDS(&intel_g33_info),
+ INTEL_I965GM_IDS(&intel_i965gm_info),
+ INTEL_GM45_IDS(&intel_gm45_info),
+ INTEL_G45_IDS(&intel_g45_info),
+ INTEL_PINEVIEW_IDS(&intel_pineview_info),
+ INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info),
+ INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info),
+ INTEL_SNB_D_IDS(&intel_sandybridge_d_info),
+ INTEL_SNB_M_IDS(&intel_sandybridge_m_info),
+ INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */
+ INTEL_IVB_M_IDS(&intel_ivybridge_m_info),
+ INTEL_IVB_D_IDS(&intel_ivybridge_d_info),
+ INTEL_HSW_D_IDS(&intel_haswell_d_info),
+ INTEL_HSW_M_IDS(&intel_haswell_m_info),
+ INTEL_VLV_M_IDS(&intel_valleyview_m_info),
+ INTEL_VLV_D_IDS(&intel_valleyview_d_info),
+ INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),
+ INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),
+ INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),
+ INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info),
+ INTEL_CHV_IDS(&intel_cherryview_info),
+ INTEL_SKL_GT1_IDS(&intel_skylake_info),
+ INTEL_SKL_GT2_IDS(&intel_skylake_info),
+ INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info),
+ INTEL_SKL_GT4_IDS(&intel_skylake_gt3_info),
+ INTEL_BXT_IDS(&intel_broxton_info),
+ INTEL_KBL_GT1_IDS(&intel_kabylake_info),
+ INTEL_KBL_GT2_IDS(&intel_kabylake_info),
+ INTEL_KBL_GT3_IDS(&intel_kabylake_gt3_info),
+ INTEL_KBL_GT4_IDS(&intel_kabylake_gt3_info),
{0, 0, 0}
};
@@ -463,7 +430,7 @@ static enum intel_pch intel_virt_detect_pch(struct drm_device *dev)
} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
ret = PCH_LPT;
DRM_DEBUG_KMS("Assuming LynxPoint PCH\n");
- } else if (IS_SKYLAKE(dev)) {
+ } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
ret = PCH_SPT;
DRM_DEBUG_KMS("Assuming SunrisePoint PCH\n");
}
@@ -526,12 +493,15 @@ void intel_detect_pch(struct drm_device *dev)
} else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_SPT;
DRM_DEBUG_KMS("Found SunrisePoint PCH\n");
- WARN_ON(!IS_SKYLAKE(dev));
+ WARN_ON(!IS_SKYLAKE(dev) &&
+ !IS_KABYLAKE(dev));
} else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_SPT;
DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
- WARN_ON(!IS_SKYLAKE(dev));
- } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) {
+ WARN_ON(!IS_SKYLAKE(dev) &&
+ !IS_KABYLAKE(dev));
+ } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) ||
+ (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE)) {
dev_priv->pch_type = intel_virt_detect_pch(dev);
} else
continue;
@@ -570,47 +540,31 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
return true;
}
-void i915_firmware_load_error_print(const char *fw_path, int err)
-{
- DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err);
-
- /*
- * If the reason is not known assume -ENOENT since that's the most
- * usual failure mode.
- */
- if (!err)
- err = -ENOENT;
-
- if (!(IS_BUILTIN(CONFIG_DRM_I915) && err == -ENOENT))
- return;
-
- DRM_ERROR(
- "The driver is built-in, so to load the firmware you need to\n"
- "include it either in the kernel (see CONFIG_EXTRA_FIRMWARE) or\n"
- "in your initrd/initramfs image.\n");
-}
-
static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
- struct drm_encoder *encoder;
+ struct intel_encoder *encoder;
drm_modeset_lock_all(dev);
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-
- if (intel_encoder->suspend)
- intel_encoder->suspend(intel_encoder);
- }
+ for_each_intel_encoder(dev, encoder)
+ if (encoder->suspend)
+ encoder->suspend(encoder);
drm_modeset_unlock_all(dev);
}
static int intel_suspend_complete(struct drm_i915_private *dev_priv);
static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
bool rpm_resume);
-static int skl_resume_prepare(struct drm_i915_private *dev_priv);
static int bxt_resume_prepare(struct drm_i915_private *dev_priv);
+static bool suspend_to_idle(struct drm_i915_private *dev_priv)
+{
+#if IS_ENABLED(CONFIG_ACPI_SLEEP)
+ if (acpi_target_system_state() < ACPI_STATE_S3)
+ return true;
+#endif
+ return false;
+}
static int i915_drm_suspend(struct drm_device *dev)
{
@@ -623,6 +577,8 @@ static int i915_drm_suspend(struct drm_device *dev)
dev_priv->modeset_restore = MODESET_SUSPENDED;
mutex_unlock(&dev_priv->modeset_restore_lock);
+ disable_rpm_wakeref_asserts(dev_priv);
+
/* We do a lot of poking in a lot of registers, make sure they work
* properly. */
intel_display_set_init_power(dev_priv, true);
@@ -635,7 +591,7 @@ static int i915_drm_suspend(struct drm_device *dev)
if (error) {
dev_err(&dev->pdev->dev,
"GEM idle failed, resume might fail\n");
- return error;
+ goto out;
}
intel_guc_suspend(dev);
@@ -663,11 +619,7 @@ static int i915_drm_suspend(struct drm_device *dev)
i915_save_state(dev);
- opregion_target_state = PCI_D3cold;
-#if IS_ENABLED(CONFIG_ACPI_SLEEP)
- if (acpi_target_system_state() < ACPI_STATE_S3)
- opregion_target_state = PCI_D1;
-#endif
+ opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold;
intel_opregion_notify_adapter(dev, opregion_target_state);
intel_uncore_forcewake_reset(dev, false);
@@ -679,20 +631,42 @@ static int i915_drm_suspend(struct drm_device *dev)
intel_display_set_init_power(dev_priv, false);
- return 0;
+ if (HAS_CSR(dev_priv))
+ flush_work(&dev_priv->csr.work);
+
+out:
+ enable_rpm_wakeref_asserts(dev_priv);
+
+ return error;
}
static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
{
struct drm_i915_private *dev_priv = drm_dev->dev_private;
+ bool fw_csr;
int ret;
+ disable_rpm_wakeref_asserts(dev_priv);
+
+ fw_csr = suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload;
+ /*
+ * In case of firmware assisted context save/restore don't manually
+ * deinit the power domains. This also means the CSR/DMC firmware will
+ * stay active, it will power down any HW resources as required and
+ * also enable deeper system power states that would be blocked if the
+ * firmware was inactive.
+ */
+ if (!fw_csr)
+ intel_power_domains_suspend(dev_priv);
+
ret = intel_suspend_complete(dev_priv);
if (ret) {
DRM_ERROR("Suspend complete failed: %d\n", ret);
+ if (!fw_csr)
+ intel_power_domains_init_hw(dev_priv, true);
- return ret;
+ goto out;
}
pci_disable_device(drm_dev->pdev);
@@ -711,7 +685,12 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
if (!(hibernation && INTEL_INFO(dev_priv)->gen < 6))
pci_set_power_state(drm_dev->pdev, PCI_D3hot);
- return 0;
+ dev_priv->suspended_to_idle = suspend_to_idle(dev_priv);
+
+out:
+ enable_rpm_wakeref_asserts(dev_priv);
+
+ return ret;
}
int i915_suspend_switcheroo(struct drm_device *dev, pm_message_t state)
@@ -742,6 +721,8 @@ static int i915_drm_resume(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ disable_rpm_wakeref_asserts(dev_priv);
+
mutex_lock(&dev->struct_mutex);
i915_gem_restore_gtt_mappings(dev);
mutex_unlock(&dev->struct_mutex);
@@ -806,6 +787,8 @@ static int i915_drm_resume(struct drm_device *dev)
drm_kms_helper_poll_enable(dev);
+ enable_rpm_wakeref_asserts(dev_priv);
+
return 0;
}
@@ -823,12 +806,16 @@ static int i915_drm_resume_early(struct drm_device *dev)
* FIXME: This should be solved with a special hdmi sink device or
* similar so that power domains can be employed.
*/
- if (pci_enable_device(dev->pdev))
- return -EIO;
+ if (pci_enable_device(dev->pdev)) {
+ ret = -EIO;
+ goto out;
+ }
pci_set_master(dev->pdev);
- if (IS_VALLEYVIEW(dev_priv))
+ disable_rpm_wakeref_asserts(dev_priv);
+
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
ret = vlv_resume_prepare(dev_priv, false);
if (ret)
DRM_ERROR("Resume prepare failed: %d, continuing anyway\n",
@@ -838,13 +825,18 @@ static int i915_drm_resume_early(struct drm_device *dev)
if (IS_BROXTON(dev))
ret = bxt_resume_prepare(dev_priv);
- else if (IS_SKYLAKE(dev_priv))
- ret = skl_resume_prepare(dev_priv);
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
hsw_disable_pc8(dev_priv);
intel_uncore_sanitize(dev);
- intel_power_domains_init_hw(dev_priv);
+
+ if (!(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload))
+ intel_power_domains_init_hw(dev_priv, true);
+
+out:
+ dev_priv->suspended_to_idle = false;
+
+ enable_rpm_wakeref_asserts(dev_priv);
return ret;
}
@@ -1051,15 +1043,6 @@ static int i915_pm_resume(struct device *dev)
return i915_drm_resume(drm_dev);
}
-static int skl_suspend_complete(struct drm_i915_private *dev_priv)
-{
- /* Enabling DC6 is not a hard requirement to enter runtime D3 */
-
- skl_uninit_cdclk(dev_priv);
-
- return 0;
-}
-
static int hsw_suspend_complete(struct drm_i915_private *dev_priv)
{
hsw_enable_pc8(dev_priv);
@@ -1099,16 +1082,6 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv)
return 0;
}
-static int skl_resume_prepare(struct drm_i915_private *dev_priv)
-{
- struct drm_device *dev = dev_priv->dev;
-
- skl_init_cdclk(dev_priv);
- intel_csr_load_program(dev);
-
- return 0;
-}
-
/*
* Save all Gunit registers that may be lost after a D3 and a subsequent
* S0i[R123] transition. The list of registers needing a save/restore is
@@ -1497,6 +1470,9 @@ static int intel_runtime_suspend(struct device *device)
return -EAGAIN;
}
+
+ disable_rpm_wakeref_asserts(dev_priv);
+
/*
* We are safe here against re-faults, since the fault handler takes
* an RPM reference.
@@ -1504,6 +1480,8 @@ static int intel_runtime_suspend(struct device *device)
i915_gem_release_all_mmaps(dev_priv);
mutex_unlock(&dev->struct_mutex);
+ cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
+
intel_guc_suspend(dev);
intel_suspend_gt_powersave(dev);
@@ -1514,11 +1492,15 @@ static int intel_runtime_suspend(struct device *device)
DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret);
intel_runtime_pm_enable_interrupts(dev_priv);
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
- cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
intel_uncore_forcewake_reset(dev, false);
+
+ enable_rpm_wakeref_asserts(dev_priv);
+ WARN_ON_ONCE(atomic_read(&dev_priv->pm.wakeref_count));
dev_priv->pm.suspended = true;
/*
@@ -1562,6 +1544,9 @@ static int intel_runtime_resume(struct device *device)
DRM_DEBUG_KMS("Resuming device\n");
+ WARN_ON_ONCE(atomic_read(&dev_priv->pm.wakeref_count));
+ disable_rpm_wakeref_asserts(dev_priv);
+
intel_opregion_notify_adapter(dev, PCI_D0);
dev_priv->pm.suspended = false;
@@ -1572,11 +1557,9 @@ static int intel_runtime_resume(struct device *device)
if (IS_BROXTON(dev))
ret = bxt_resume_prepare(dev_priv);
- else if (IS_SKYLAKE(dev))
- ret = skl_resume_prepare(dev_priv);
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
hsw_disable_pc8(dev_priv);
- else if (IS_VALLEYVIEW(dev_priv))
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
ret = vlv_resume_prepare(dev_priv, true);
/*
@@ -1593,11 +1576,13 @@ static int intel_runtime_resume(struct device *device)
* power well, so hpd is reinitialized from there. For
* everyone else do it here.
*/
- if (!IS_VALLEYVIEW(dev_priv))
+ if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
intel_hpd_init(dev_priv);
intel_enable_gt_powersave(dev);
+ enable_rpm_wakeref_asserts(dev_priv);
+
if (ret)
DRM_ERROR("Runtime resume failed, disabling it (%d)\n", ret);
else
@@ -1616,11 +1601,9 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv)
if (IS_BROXTON(dev_priv))
ret = bxt_suspend_complete(dev_priv);
- else if (IS_SKYLAKE(dev_priv))
- ret = skl_suspend_complete(dev_priv);
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
ret = hsw_suspend_complete(dev_priv);
- else if (IS_VALLEYVIEW(dev_priv))
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
ret = vlv_suspend_complete(dev_priv);
else
ret = 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f4af19a0d569..f0f75d7c0d94 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -33,6 +33,7 @@
#include <uapi/drm/i915_drm.h>
#include <uapi/drm/drm_fourcc.h>
+#include <drm/drmP.h>
#include "i915_reg.h"
#include "intel_bios.h"
#include "intel_ringbuffer.h"
@@ -57,7 +58,7 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20151010"
+#define DRIVER_DATE "20151218"
#undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */
@@ -180,15 +181,11 @@ enum intel_display_power_domain {
POWER_DOMAIN_TRANSCODER_B,
POWER_DOMAIN_TRANSCODER_C,
POWER_DOMAIN_TRANSCODER_EDP,
- POWER_DOMAIN_PORT_DDI_A_2_LANES,
- POWER_DOMAIN_PORT_DDI_A_4_LANES,
- POWER_DOMAIN_PORT_DDI_B_2_LANES,
- POWER_DOMAIN_PORT_DDI_B_4_LANES,
- POWER_DOMAIN_PORT_DDI_C_2_LANES,
- POWER_DOMAIN_PORT_DDI_C_4_LANES,
- POWER_DOMAIN_PORT_DDI_D_2_LANES,
- POWER_DOMAIN_PORT_DDI_D_4_LANES,
- POWER_DOMAIN_PORT_DDI_E_2_LANES,
+ POWER_DOMAIN_PORT_DDI_A_LANES,
+ POWER_DOMAIN_PORT_DDI_B_LANES,
+ POWER_DOMAIN_PORT_DDI_C_LANES,
+ POWER_DOMAIN_PORT_DDI_D_LANES,
+ POWER_DOMAIN_PORT_DDI_E_LANES,
POWER_DOMAIN_PORT_DSI,
POWER_DOMAIN_PORT_CRT,
POWER_DOMAIN_PORT_OTHER,
@@ -200,6 +197,7 @@ enum intel_display_power_domain {
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_AUX_D,
POWER_DOMAIN_GMBUS,
+ POWER_DOMAIN_MODESET,
POWER_DOMAIN_INIT,
POWER_DOMAIN_NUM,
@@ -289,7 +287,7 @@ struct i915_hotplug {
list_for_each_entry(intel_plane, \
&(dev)->mode_config.plane_list, \
base.head) \
- if ((intel_plane)->pipe == (intel_crtc)->pipe)
+ for_each_if ((intel_plane)->pipe == (intel_crtc)->pipe)
#define for_each_intel_crtc(dev, intel_crtc) \
list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
@@ -306,15 +304,15 @@ struct i915_hotplug {
#define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
- if ((intel_encoder)->base.crtc == (__crtc))
+ for_each_if ((intel_encoder)->base.crtc == (__crtc))
#define for_each_connector_on_encoder(dev, __encoder, intel_connector) \
list_for_each_entry((intel_connector), &(dev)->mode_config.connector_list, base.head) \
- if ((intel_connector)->base.encoder == (__encoder))
+ for_each_if ((intel_connector)->base.encoder == (__encoder))
#define for_each_power_domain(domain, mask) \
for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \
- if ((1 << (domain)) & (mask))
+ for_each_if ((1 << (domain)) & (mask))
struct drm_i915_private;
struct i915_mm_struct;
@@ -460,7 +458,9 @@ struct intel_opregion {
u32 swsci_gbda_sub_functions;
u32 swsci_sbcb_sub_functions;
struct opregion_asle *asle;
- void *vbt;
+ void *rvda;
+ const void *vbt;
+ u32 vbt_size;
u32 *lid_state;
struct work_struct asle_work;
};
@@ -631,11 +631,9 @@ struct drm_i915_display_funcs {
int target, int refclk,
struct dpll *match_clock,
struct dpll *best_clock);
+ int (*compute_pipe_wm)(struct intel_crtc *crtc,
+ struct drm_atomic_state *state);
void (*update_wm)(struct drm_crtc *crtc);
- void (*update_sprite_wm)(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width, uint32_t sprite_height,
- int pixel_size, bool enable, bool scaled);
int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
/* Returns the active state of the crtc, and if the crtc is active,
@@ -693,18 +691,18 @@ struct intel_uncore_funcs {
void (*force_wake_put)(struct drm_i915_private *dev_priv,
enum forcewake_domains domains);
- uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
- uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
- uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
- uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
+ uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
+ uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
+ uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
+ uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
- void (*mmio_writeb)(struct drm_i915_private *dev_priv, off_t offset,
+ void (*mmio_writeb)(struct drm_i915_private *dev_priv, i915_reg_t r,
uint8_t val, bool trace);
- void (*mmio_writew)(struct drm_i915_private *dev_priv, off_t offset,
+ void (*mmio_writew)(struct drm_i915_private *dev_priv, i915_reg_t r,
uint16_t val, bool trace);
- void (*mmio_writel)(struct drm_i915_private *dev_priv, off_t offset,
+ void (*mmio_writel)(struct drm_i915_private *dev_priv, i915_reg_t r,
uint32_t val, bool trace);
- void (*mmio_writeq)(struct drm_i915_private *dev_priv, off_t offset,
+ void (*mmio_writeq)(struct drm_i915_private *dev_priv, i915_reg_t r,
uint64_t val, bool trace);
};
@@ -721,11 +719,11 @@ struct intel_uncore {
enum forcewake_domain_id id;
unsigned wake_count;
struct timer_list timer;
- u32 reg_set;
+ i915_reg_t reg_set;
u32 val_set;
u32 val_clear;
- u32 reg_ack;
- u32 reg_post;
+ i915_reg_t reg_ack;
+ i915_reg_t reg_post;
u32 val_reset;
} fw_domain[FW_DOMAIN_ID_COUNT];
};
@@ -735,25 +733,24 @@ struct intel_uncore {
for ((i__) = 0, (domain__) = &(dev_priv__)->uncore.fw_domain[0]; \
(i__) < FW_DOMAIN_ID_COUNT; \
(i__)++, (domain__) = &(dev_priv__)->uncore.fw_domain[i__]) \
- if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__)))
+ for_each_if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__)))
#define for_each_fw_domain(domain__, dev_priv__, i__) \
for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
-enum csr_state {
- FW_UNINITIALIZED = 0,
- FW_LOADED,
- FW_FAILED
-};
+#define CSR_VERSION(major, minor) ((major) << 16 | (minor))
+#define CSR_VERSION_MAJOR(version) ((version) >> 16)
+#define CSR_VERSION_MINOR(version) ((version) & 0xffff)
struct intel_csr {
+ struct work_struct work;
const char *fw_path;
uint32_t *dmc_payload;
uint32_t dmc_fw_size;
+ uint32_t version;
uint32_t mmio_count;
- uint32_t mmioaddr[8];
+ i915_reg_t mmioaddr[8];
uint32_t mmiodata[8];
- enum csr_state state;
};
#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
@@ -769,8 +766,11 @@ struct intel_csr {
func(is_crestline) sep \
func(is_ivybridge) sep \
func(is_valleyview) sep \
+ func(is_cherryview) sep \
func(is_haswell) sep \
func(is_skylake) sep \
+ func(is_broxton) sep \
+ func(is_kabylake) sep \
func(is_preliminary) sep \
func(has_fbc) sep \
func(has_pipe_cxsr) sep \
@@ -906,7 +906,6 @@ struct i915_fbc {
/* This is always the inner lock when overlapping with struct_mutex and
* it's the outer lock when overlapping with stolen_lock. */
struct mutex lock;
- unsigned long uncompressed_size;
unsigned threshold;
unsigned int fb_id;
unsigned int possible_framebuffer_bits;
@@ -919,38 +918,21 @@ struct i915_fbc {
bool false_color;
- /* Tracks whether the HW is actually enabled, not whether the feature is
- * possible. */
bool enabled;
+ bool active;
struct intel_fbc_work {
- struct delayed_work work;
- struct intel_crtc *crtc;
+ bool scheduled;
+ struct work_struct work;
struct drm_framebuffer *fb;
- } *fbc_work;
-
- enum no_fbc_reason {
- FBC_OK, /* FBC is enabled */
- FBC_UNSUPPORTED, /* FBC is not supported by this chipset */
- FBC_NO_OUTPUT, /* no outputs enabled to compress */
- FBC_STOLEN_TOO_SMALL, /* not enough space for buffers */
- FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
- FBC_MODE_TOO_LARGE, /* mode too large for compression */
- FBC_BAD_PLANE, /* fbc not supported on plane */
- FBC_NOT_TILED, /* buffer not tiled */
- FBC_MULTIPLE_PIPES, /* more than one pipe active */
- FBC_MODULE_PARAM,
- FBC_CHIP_DEFAULT, /* disabled by default on this chip */
- FBC_ROTATION, /* rotation is not supported */
- FBC_IN_DBG_MASTER, /* kernel debugger is active */
- FBC_BAD_STRIDE, /* stride is not supported */
- FBC_PIXEL_RATE, /* pixel rate is too big */
- FBC_PIXEL_FORMAT /* pixel format is invalid */
- } no_fbc_reason;
-
- bool (*fbc_enabled)(struct drm_i915_private *dev_priv);
- void (*enable_fbc)(struct intel_crtc *crtc);
- void (*disable_fbc)(struct drm_i915_private *dev_priv);
+ unsigned long enable_jiffies;
+ } work;
+
+ const char *no_fbc_reason;
+
+ bool (*is_active)(struct drm_i915_private *dev_priv);
+ void (*activate)(struct intel_crtc *crtc);
+ void (*deactivate)(struct drm_i915_private *dev_priv);
};
/**
@@ -1020,7 +1002,7 @@ struct intel_gmbus {
struct i2c_adapter adapter;
u32 force_bit;
u32 reg0;
- u32 gpio_reg;
+ i915_reg_t gpio_reg;
struct i2c_algo_bit_data bit_algo;
struct drm_i915_private *dev_priv;
};
@@ -1623,6 +1605,8 @@ struct skl_wm_level {
* For more, read the Documentation/power/runtime_pm.txt.
*/
struct i915_runtime_pm {
+ atomic_t wakeref_count;
+ atomic_t atomic_seq;
bool suspended;
bool irqs_enabled;
};
@@ -1669,7 +1653,7 @@ struct i915_frontbuffer_tracking {
};
struct i915_wa_reg {
- u32 addr;
+ i915_reg_t addr;
u32 value;
/* bitmask representing WA bits */
u32 mask;
@@ -1698,6 +1682,13 @@ struct i915_execbuffer_params {
struct drm_i915_gem_request *request;
};
+/* used in computing the new watermarks state */
+struct intel_wm_config {
+ unsigned int num_pipes_active;
+ bool sprites_enabled;
+ bool sprites_scaled;
+};
+
struct drm_i915_private {
struct drm_device *dev;
struct kmem_cache *objects;
@@ -1718,9 +1709,6 @@ struct drm_i915_private {
struct intel_csr csr;
- /* Display CSR-related protection */
- struct mutex csr_lock;
-
struct intel_gmbus gmbus[GMBUS_NUM_PINS];
/** gmbus_mutex protects against concurrent usage of the single hw gmbus
@@ -1735,6 +1723,8 @@ struct drm_i915_private {
/* MMIO base address for MIPI regs */
uint32_t mipi_mmio_base;
+ uint32_t psr_mmio_base;
+
wait_queue_head_t gmbus_wait_queue;
struct pci_dev *bridge_dev;
@@ -1900,6 +1890,7 @@ struct drm_i915_private {
u32 chv_phy_control;
u32 suspend_count;
+ bool suspended_to_idle;
struct i915_suspend_saved_registers regfile;
struct vlv_s0ix_state vlv_s0ix_state;
@@ -1922,6 +1913,9 @@ struct drm_i915_private {
*/
uint16_t skl_latency[8];
+ /* Committed wm config */
+ struct intel_wm_config config;
+
/*
* The skl_wm_values structure is a bit too big for stack
* allocation, so we keep the staging struct where we store
@@ -1956,6 +1950,8 @@ struct drm_i915_private {
/* perform PHY state sanity checks? */
bool chv_phy_assert[2];
+ struct intel_encoder *dig_port_map[I915_MAX_PORTS];
+
/*
* NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
* will be rejected. Instead look for a better place.
@@ -1980,7 +1976,7 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
/* Iterate over initialised rings */
#define for_each_ring(ring__, dev_priv__, i__) \
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
- if (((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__)))
+ for_each_if ((((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__))))
enum hdmi_force_audio {
HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
@@ -2445,6 +2441,15 @@ struct drm_i915_cmd_table {
#define INTEL_DEVID(p) (INTEL_INFO(p)->device_id)
#define INTEL_REVID(p) (__I915__(p)->dev->pdev->revision)
+#define REVID_FOREVER 0xff
+/*
+ * Return true if revision is in range [since,until] inclusive.
+ *
+ * Use 0 for open-ended since, and REVID_FOREVER for open-ended until.
+ */
+#define IS_REVID(p, since, until) \
+ (INTEL_REVID(p) >= (since) && INTEL_REVID(p) <= (until))
+
#define IS_I830(dev) (INTEL_DEVID(dev) == 0x3577)
#define IS_845G(dev) (INTEL_DEVID(dev) == 0x2562)
#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x)
@@ -2467,11 +2472,12 @@ struct drm_i915_cmd_table {
INTEL_DEVID(dev) == 0x0152 || \
INTEL_DEVID(dev) == 0x015a)
#define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview)
-#define IS_CHERRYVIEW(dev) (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
+#define IS_CHERRYVIEW(dev) (INTEL_INFO(dev)->is_cherryview)
#define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell)
-#define IS_BROADWELL(dev) (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
+#define IS_BROADWELL(dev) (!INTEL_INFO(dev)->is_cherryview && IS_GEN8(dev))
#define IS_SKYLAKE(dev) (INTEL_INFO(dev)->is_skylake)
-#define IS_BROXTON(dev) (!INTEL_INFO(dev)->is_skylake && IS_GEN9(dev))
+#define IS_BROXTON(dev) (INTEL_INFO(dev)->is_broxton)
+#define IS_KABYLAKE(dev) (INTEL_INFO(dev)->is_kabylake)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
#define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \
(INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
@@ -2499,6 +2505,14 @@ struct drm_i915_cmd_table {
#define IS_SKL_ULX(dev) (INTEL_DEVID(dev) == 0x190E || \
INTEL_DEVID(dev) == 0x1915 || \
INTEL_DEVID(dev) == 0x191E)
+#define IS_KBL_ULT(dev) (INTEL_DEVID(dev) == 0x5906 || \
+ INTEL_DEVID(dev) == 0x5913 || \
+ INTEL_DEVID(dev) == 0x5916 || \
+ INTEL_DEVID(dev) == 0x5921 || \
+ INTEL_DEVID(dev) == 0x5926)
+#define IS_KBL_ULX(dev) (INTEL_DEVID(dev) == 0x590E || \
+ INTEL_DEVID(dev) == 0x5915 || \
+ INTEL_DEVID(dev) == 0x591E)
#define IS_SKL_GT3(dev) (IS_SKYLAKE(dev) && \
(INTEL_DEVID(dev) & 0x00F0) == 0x0020)
#define IS_SKL_GT4(dev) (IS_SKYLAKE(dev) && \
@@ -2506,16 +2520,21 @@ struct drm_i915_cmd_table {
#define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
-#define SKL_REVID_A0 (0x0)
-#define SKL_REVID_B0 (0x1)
-#define SKL_REVID_C0 (0x2)
-#define SKL_REVID_D0 (0x3)
-#define SKL_REVID_E0 (0x4)
-#define SKL_REVID_F0 (0x5)
+#define SKL_REVID_A0 0x0
+#define SKL_REVID_B0 0x1
+#define SKL_REVID_C0 0x2
+#define SKL_REVID_D0 0x3
+#define SKL_REVID_E0 0x4
+#define SKL_REVID_F0 0x5
+
+#define IS_SKL_REVID(p, since, until) (IS_SKYLAKE(p) && IS_REVID(p, since, until))
+
+#define BXT_REVID_A0 0x0
+#define BXT_REVID_A1 0x1
+#define BXT_REVID_B0 0x3
+#define BXT_REVID_C0 0x9
-#define BXT_REVID_A0 (0x0)
-#define BXT_REVID_B0 (0x3)
-#define BXT_REVID_C0 (0x9)
+#define IS_BXT_REVID(p, since, until) (IS_BROXTON(p) && IS_REVID(p, since, until))
/*
* The genX designation typically refers to the render engine, so render
@@ -2587,23 +2606,25 @@ struct drm_i915_cmd_table {
#define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg)
#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
- IS_SKYLAKE(dev))
+ IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
#define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \
IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \
- IS_SKYLAKE(dev))
+ IS_CHERRYVIEW(dev) || IS_SKYLAKE(dev) || \
+ IS_KABYLAKE(dev))
#define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6)
#define HAS_RC6p(dev) (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
#define HAS_CSR(dev) (IS_GEN9(dev))
-#define HAS_GUC_UCODE(dev) (IS_GEN9(dev))
-#define HAS_GUC_SCHED(dev) (IS_GEN9(dev))
+#define HAS_GUC_UCODE(dev) (IS_GEN9(dev) && !IS_KABYLAKE(dev))
+#define HAS_GUC_SCHED(dev) (IS_GEN9(dev) && !IS_KABYLAKE(dev))
#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \
INTEL_INFO(dev)->gen >= 8)
#define HAS_CORE_RING_FREQ(dev) (INTEL_INFO(dev)->gen >= 6 && \
- !IS_VALLEYVIEW(dev) && !IS_BROXTON(dev))
+ !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && \
+ !IS_BROXTON(dev))
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
@@ -2614,17 +2635,20 @@ struct drm_i915_cmd_table {
#define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100
#define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00
#define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100
+#define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */
#define INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type)
#define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT)
#define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT)
#define HAS_PCH_LPT_LP(dev) (__I915__(dev)->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE)
+#define HAS_PCH_LPT_H(dev) (__I915__(dev)->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP)
#define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE)
-#define HAS_GMCH_DISPLAY(dev) (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev))
+#define HAS_GMCH_DISPLAY(dev) (INTEL_INFO(dev)->gen < 5 || \
+ IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
/* DPF == dynamic parity feature */
#define HAS_L3_DPF(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
@@ -2650,6 +2674,7 @@ struct i915_params {
int panel_use_ssc;
int vbt_sdvo_panel_type;
int enable_rc6;
+ int enable_dc;
int enable_fbc;
int enable_ppgtt;
int enable_execlists;
@@ -2698,7 +2723,6 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
-void i915_firmware_load_error_print(const char *fw_path, int err);
/* intel_hotplug.c */
void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask);
@@ -2755,17 +2779,47 @@ void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
uint32_t mask,
uint32_t bits);
-void
-ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
-void
-ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
+void ilk_update_display_irq(struct drm_i915_private *dev_priv,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask);
+static inline void
+ilk_enable_display_irq(struct drm_i915_private *dev_priv, uint32_t bits)
+{
+ ilk_update_display_irq(dev_priv, bits, bits);
+}
+static inline void
+ilk_disable_display_irq(struct drm_i915_private *dev_priv, uint32_t bits)
+{
+ ilk_update_display_irq(dev_priv, bits, 0);
+}
+void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
+ enum pipe pipe,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask);
+static inline void bdw_enable_pipe_irq(struct drm_i915_private *dev_priv,
+ enum pipe pipe, uint32_t bits)
+{
+ bdw_update_pipe_irq(dev_priv, pipe, bits, bits);
+}
+static inline void bdw_disable_pipe_irq(struct drm_i915_private *dev_priv,
+ enum pipe pipe, uint32_t bits)
+{
+ bdw_update_pipe_irq(dev_priv, pipe, bits, 0);
+}
void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
uint32_t interrupt_mask,
uint32_t enabled_irq_mask);
-#define ibx_enable_display_interrupt(dev_priv, bits) \
- ibx_display_interrupt_update((dev_priv), (bits), (bits))
-#define ibx_disable_display_interrupt(dev_priv, bits) \
- ibx_display_interrupt_update((dev_priv), (bits), 0)
+static inline void
+ibx_enable_display_interrupt(struct drm_i915_private *dev_priv, uint32_t bits)
+{
+ ibx_display_interrupt_update(dev_priv, bits, bits);
+}
+static inline void
+ibx_disable_display_interrupt(struct drm_i915_private *dev_priv, uint32_t bits)
+{
+ ibx_display_interrupt_update(dev_priv, bits, 0);
+}
+
/* i915_gem.c */
int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -2834,6 +2888,7 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_UPDATE (1<<5)
#define PIN_ZONE_4G (1<<6)
#define PIN_HIGH (1<<7)
+#define PIN_OFFSET_FIXED (1<<8)
#define PIN_OFFSET_MASK (~4095)
int __must_check
i915_gem_object_pin(struct drm_i915_gem_object *obj,
@@ -2869,6 +2924,9 @@ static inline int __sg_page_count(struct scatterlist *sg)
return sg->length >> PAGE_SHIFT;
}
+struct page *
+i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n);
+
static inline struct page *
i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
{
@@ -3008,8 +3066,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write);
int __must_check
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
u32 alignment,
- struct intel_engine_cs *pipelined,
- struct drm_i915_gem_request **pipelined_request,
const struct i915_ggtt_view *view);
void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
const struct i915_ggtt_view *view);
@@ -3184,6 +3240,7 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
unsigned long start,
unsigned long end,
unsigned flags);
+int __must_check i915_gem_evict_for_vma(struct i915_vma *target);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
/* belongs in i915_gem_gtt.h */
@@ -3312,6 +3369,10 @@ static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
}
extern void intel_i2c_reset(struct drm_device *dev);
+/* intel_bios.c */
+int intel_bios_init(struct drm_i915_private *dev_priv);
+bool intel_bios_is_valid_vbt(const void *buf, size_t size);
+
/* intel_opregion.c */
#ifdef CONFIG_ACPI
extern int intel_opregion_setup(struct drm_device *dev);
@@ -3364,7 +3425,6 @@ extern void intel_set_rps(struct drm_device *dev, u8 val);
extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
bool enable);
extern void intel_detect_pch(struct drm_device *dev);
-extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
extern int intel_enable_rc6(const struct drm_device *dev);
extern bool i915_semaphore_is_enabled(struct drm_device *dev);
@@ -3447,6 +3507,32 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg)
#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg)
+#define __raw_read(x, s) \
+static inline uint##x##_t __raw_i915_read##x(struct drm_i915_private *dev_priv, \
+ i915_reg_t reg) \
+{ \
+ return read##s(dev_priv->regs + i915_mmio_reg_offset(reg)); \
+}
+
+#define __raw_write(x, s) \
+static inline void __raw_i915_write##x(struct drm_i915_private *dev_priv, \
+ i915_reg_t reg, uint##x##_t val) \
+{ \
+ write##s(val, dev_priv->regs + i915_mmio_reg_offset(reg)); \
+}
+__raw_read(8, b)
+__raw_read(16, w)
+__raw_read(32, l)
+__raw_read(64, q)
+
+__raw_write(8, b)
+__raw_write(16, w)
+__raw_write(32, l)
+__raw_write(64, q)
+
+#undef __raw_read
+#undef __raw_write
+
/* These are untraced mmio-accessors that are only valid to be used inside
* criticial sections inside IRQ handlers where forcewake is explicitly
* controlled.
@@ -3454,8 +3540,8 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
* Note: Should only be used between intel_uncore_forcewake_irqlock() and
* intel_uncore_forcewake_irqunlock().
*/
-#define I915_READ_FW(reg__) readl(dev_priv->regs + (reg__))
-#define I915_WRITE_FW(reg__, val__) writel(val__, dev_priv->regs + (reg__))
+#define I915_READ_FW(reg__) __raw_i915_read32(dev_priv, (reg__))
+#define I915_WRITE_FW(reg__, val__) __raw_i915_write32(dev_priv, (reg__), (val__))
#define POSTING_READ_FW(reg__) (void)I915_READ_FW(reg__)
/* "Broadcast RGB" property */
@@ -3463,9 +3549,9 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
#define INTEL_BROADCAST_RGB_FULL 1
#define INTEL_BROADCAST_RGB_LIMITED 2
-static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev)
+static inline i915_reg_t i915_vgacntrl_reg(struct drm_device *dev)
{
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
return VLV_VGACNTRL;
else if (INTEL_INFO(dev)->gen >= 5)
return CPU_VGACNTRL;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f56af0aaafde..ddc21d4b388d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2797,6 +2797,8 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
struct intel_engine_cs *ring)
{
+ struct intel_ringbuffer *buffer;
+
while (!list_empty(&ring->active_list)) {
struct drm_i915_gem_object *obj;
@@ -2812,18 +2814,16 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
* are the ones that keep the context and ringbuffer backing objects
* pinned in place.
*/
- while (!list_empty(&ring->execlist_queue)) {
- struct drm_i915_gem_request *submit_req;
- submit_req = list_first_entry(&ring->execlist_queue,
- struct drm_i915_gem_request,
- execlist_link);
- list_del(&submit_req->execlist_link);
+ if (i915.enable_execlists) {
+ spin_lock_irq(&ring->execlist_lock);
- if (submit_req->ctx != ring->default_context)
- intel_lr_context_unpin(submit_req);
+ /* list_splice_tail_init checks for empty lists */
+ list_splice_tail_init(&ring->execlist_queue,
+ &ring->execlist_retired_req_list);
- i915_gem_request_unreference(submit_req);
+ spin_unlock_irq(&ring->execlist_lock);
+ intel_execlists_retire_requests(ring);
}
/*
@@ -2842,6 +2842,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
i915_gem_request_retire(request);
}
+
+ /* Having flushed all requests from all queues, we know that all
+ * ringbuffers must now be empty. However, since we do not reclaim
+ * all space when retiring the request (to prevent HEADs colliding
+ * with rapid ringbuffer wraparound) the amount of available space
+ * upon reset is less than when we start. Do one more pass over
+ * all the ringbuffers to reset last_retired_head.
+ */
+ list_for_each_entry(buffer, &ring->buffers, link) {
+ buffer->last_retired_head = buffer->tail;
+ intel_ring_update_space(buffer);
+ }
}
void i915_gem_reset(struct drm_device *dev)
@@ -2982,6 +2994,10 @@ i915_gem_idle_work_handler(struct work_struct *work)
if (!list_empty(&ring->request_list))
return;
+ /* we probably should sync with hangcheck here, using cancel_work_sync.
+ * Also locking seems to be fubar here, ring->request_list is protected
+ * by dev->struct_mutex. */
+
intel_mark_idle(dev);
if (mutex_trylock(&dev->struct_mutex)) {
@@ -3106,7 +3122,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
if (ret == 0)
ret = __i915_wait_request(req[i], reset_counter, true,
args->timeout_ns > 0 ? &args->timeout_ns : NULL,
- file->driver_priv);
+ to_rps_client(file));
i915_gem_request_unreference__unlocked(req[i]);
}
return ret;
@@ -3472,7 +3488,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
if (flags & PIN_MAPPABLE)
end = min_t(u64, end, dev_priv->gtt.mappable_end);
if (flags & PIN_ZONE_4G)
- end = min_t(u64, end, (1ULL << 32));
+ end = min_t(u64, end, (1ULL << 32) - PAGE_SIZE);
if (alignment == 0)
alignment = flags & PIN_MAPPABLE ? fence_alignment :
@@ -3509,30 +3525,50 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
if (IS_ERR(vma))
goto err_unpin;
- if (flags & PIN_HIGH) {
- search_flag = DRM_MM_SEARCH_BELOW;
- alloc_flag = DRM_MM_CREATE_TOP;
+ if (flags & PIN_OFFSET_FIXED) {
+ uint64_t offset = flags & PIN_OFFSET_MASK;
+
+ if (offset & (alignment - 1) || offset + size > end) {
+ ret = -EINVAL;
+ goto err_free_vma;
+ }
+ vma->node.start = offset;
+ vma->node.size = size;
+ vma->node.color = obj->cache_level;
+ ret = drm_mm_reserve_node(&vm->mm, &vma->node);
+ if (ret) {
+ ret = i915_gem_evict_for_vma(vma);
+ if (ret == 0)
+ ret = drm_mm_reserve_node(&vm->mm, &vma->node);
+ }
+ if (ret)
+ goto err_free_vma;
} else {
- search_flag = DRM_MM_SEARCH_DEFAULT;
- alloc_flag = DRM_MM_CREATE_DEFAULT;
- }
+ if (flags & PIN_HIGH) {
+ search_flag = DRM_MM_SEARCH_BELOW;
+ alloc_flag = DRM_MM_CREATE_TOP;
+ } else {
+ search_flag = DRM_MM_SEARCH_DEFAULT;
+ alloc_flag = DRM_MM_CREATE_DEFAULT;
+ }
search_free:
- ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
- size, alignment,
- obj->cache_level,
- start, end,
- search_flag,
- alloc_flag);
- if (ret) {
- ret = i915_gem_evict_something(dev, vm, size, alignment,
- obj->cache_level,
- start, end,
- flags);
- if (ret == 0)
- goto search_free;
+ ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
+ size, alignment,
+ obj->cache_level,
+ start, end,
+ search_flag,
+ alloc_flag);
+ if (ret) {
+ ret = i915_gem_evict_something(dev, vm, size, alignment,
+ obj->cache_level,
+ start, end,
+ flags);
+ if (ret == 0)
+ goto search_free;
- goto err_free_vma;
+ goto err_free_vma;
+ }
}
if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) {
ret = -EINVAL;
@@ -3886,7 +3922,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
* cacheline, whereas normally such cachelines would get
* invalidated.
*/
- if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
return -ENODEV;
level = I915_CACHE_LLC;
@@ -3929,17 +3965,11 @@ rpm_put:
int
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
u32 alignment,
- struct intel_engine_cs *pipelined,
- struct drm_i915_gem_request **pipelined_request,
const struct i915_ggtt_view *view)
{
u32 old_read_domains, old_write_domain;
int ret;
- ret = i915_gem_object_sync(obj, pipelined, pipelined_request);
- if (ret)
- return ret;
-
/* Mark the pin_display early so that we account for the
* display coherency whilst setting up the cache domains.
*/
@@ -4129,6 +4159,10 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
vma->node.start < (flags & PIN_OFFSET_MASK))
return true;
+ if (flags & PIN_OFFSET_FIXED &&
+ vma->node.start != (flags & PIN_OFFSET_MASK))
+ return true;
+
return false;
}
@@ -4541,10 +4575,8 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
{
struct i915_vma *vma;
list_for_each_entry(vma, &obj->vma_list, vma_link) {
- if (i915_is_ggtt(vma->vm) &&
- vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
- continue;
- if (vma->vm == vm)
+ if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL &&
+ vma->vm == vm)
return vma;
}
return NULL;
@@ -4633,7 +4665,6 @@ int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice)
struct intel_engine_cs *ring = req->ring;
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200);
u32 *remap_info = dev_priv->l3_parity.remap_info[slice];
int i, ret;
@@ -4649,10 +4680,10 @@ int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice)
* here because no other code should access these registers other than
* at initialization time.
*/
- for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
+ for (i = 0; i < GEN7_L3LOG_SIZE / 4; i++) {
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(ring, reg_base + i);
- intel_ring_emit(ring, remap_info[i/4]);
+ intel_ring_emit_reg(ring, GEN7_L3LOG(slice, i));
+ intel_ring_emit(ring, remap_info[i]);
}
intel_ring_advance(ring);
@@ -4820,18 +4851,9 @@ i915_gem_init_hw(struct drm_device *dev)
if (HAS_GUC_UCODE(dev)) {
ret = intel_guc_ucode_load(dev);
if (ret) {
- /*
- * If we got an error and GuC submission is enabled, map
- * the error to -EIO so the GPU will be declared wedged.
- * OTOH, if we didn't intend to use the GuC anyway, just
- * discard the error and carry on.
- */
- DRM_ERROR("Failed to initialize GuC, error %d%s\n", ret,
- i915.enable_guc_submission ? "" :
- " (ignored)");
- ret = i915.enable_guc_submission ? -EIO : 0;
- if (ret)
- goto out;
+ DRM_ERROR("Failed to initialize GuC, error %d\n", ret);
+ ret = -EIO;
+ goto out;
}
}
@@ -4894,14 +4916,6 @@ int i915_gem_init(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
- if (IS_VALLEYVIEW(dev)) {
- /* VLVA0 (potential hack), BIOS isn't actually waking us */
- I915_WRITE(VLV_GTLC_WAKE_CTRL, VLV_GTLC_ALLOWWAKEREQ);
- if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) &
- VLV_GTLC_ALLOWWAKEACK), 10))
- DRM_DEBUG_DRIVER("allow wake ack timed out\n");
- }
-
if (!i915.enable_execlists) {
dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
dev_priv->gt.init_rings = i915_gem_init_rings;
@@ -5019,7 +5033,7 @@ i915_gem_load(struct drm_device *dev)
dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
- if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev))
+ if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
dev_priv->num_fence_regs = 32;
else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dev_priv->num_fence_regs = 16;
@@ -5240,6 +5254,21 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
return false;
}
+/* Like i915_gem_object_get_page(), but mark the returned page dirty */
+struct page *
+i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n)
+{
+ struct page *page;
+
+ /* Only default objects have per-page dirty tracking */
+ if (WARN_ON(obj->ops != &i915_gem_object_ops))
+ return NULL;
+
+ page = i915_gem_object_get_page(obj, n);
+ set_page_dirty(page);
+ return page;
+}
+
/* Allocate a new GEM object and fill it with the supplied data */
struct drm_i915_gem_object *
i915_gem_object_create_from_data(struct drm_device *dev,
@@ -5265,6 +5294,7 @@ i915_gem_object_create_from_data(struct drm_device *dev,
i915_gem_object_pin_pages(obj);
sg = obj->pages;
bytes = sg_copy_from_buffer(sg->sgl, sg->nents, (void *)data, size);
+ obj->dirty = 1; /* Backing store is now out of date */
i915_gem_object_unpin_pages(obj);
if (WARN_ON(bytes != size)) {
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 02ceb7a4b481..c25083c78ba7 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -189,8 +189,15 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
* shouldn't touch the cache level, especially as that
* would make the object snooped which might have a
* negative performance impact.
+ *
+ * Snooping is required on non-llc platforms in execlist
+ * mode, but since all GGTT accesses use PAT entry 0 we
+ * get snooping anyway regardless of cache_level.
+ *
+ * This is only applicable for Ivy Bridge devices since
+ * later platforms don't have L3 control bits in the PTE.
*/
- if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) {
+ if (IS_IVYBRIDGE(dev)) {
ret = i915_gem_object_set_cache_level(obj, I915_CACHE_L3_LLC);
/* Failure shouldn't ever happen this early */
if (WARN_ON(ret)) {
@@ -340,6 +347,10 @@ void i915_gem_context_reset(struct drm_device *dev)
i915_gem_context_unreference(lctx);
ring->last_context = NULL;
}
+
+ /* Force the GPU state to be reinitialised on enabling */
+ if (ring->default_context)
+ ring->default_context->legacy_hw_ctx.initialized = false;
}
}
@@ -554,7 +565,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
if (signaller == ring)
continue;
- intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+ intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base));
intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
}
}
@@ -579,7 +590,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
if (signaller == ring)
continue;
- intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+ intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base));
intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
}
}
@@ -708,7 +719,7 @@ static int do_switch(struct drm_i915_gem_request *req)
if (ret)
goto unpin_out;
- if (!to->legacy_hw_ctx.initialized) {
+ if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) {
hw_flags |= MI_RESTORE_INHIBIT;
/* NB: If we inhibit the restore, the context is not allowed to
* die because future work may end up depending on valid address
@@ -923,6 +934,14 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
case I915_CONTEXT_PARAM_NO_ZEROMAP:
args->value = ctx->flags & CONTEXT_NO_ZEROMAP;
break;
+ case I915_CONTEXT_PARAM_GTT_SIZE:
+ if (ctx->ppgtt)
+ args->value = ctx->ppgtt->base.total;
+ else if (to_i915(dev)->mm.aliasing_ppgtt)
+ args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total;
+ else
+ args->value = to_i915(dev)->gtt.base.total;
+ break;
default:
ret = -EINVAL;
break;
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index d71a133ceff5..07c6e4d320c9 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -199,6 +199,45 @@ found:
return ret;
}
+int
+i915_gem_evict_for_vma(struct i915_vma *target)
+{
+ struct drm_mm_node *node, *next;
+
+ list_for_each_entry_safe(node, next,
+ &target->vm->mm.head_node.node_list,
+ node_list) {
+ struct i915_vma *vma;
+ int ret;
+
+ if (node->start + node->size <= target->node.start)
+ continue;
+ if (node->start >= target->node.start + target->node.size)
+ break;
+
+ vma = container_of(node, typeof(*vma), node);
+
+ if (vma->pin_count) {
+ if (!vma->exec_entry || (vma->pin_count > 1))
+ /* Object is pinned for some other use */
+ return -EBUSY;
+
+ /* We need to evict a buffer in the same batch */
+ if (vma->exec_entry->flags & EXEC_OBJECT_PINNED)
+ /* Overlapping fixed objects in the same batch */
+ return -EINVAL;
+
+ return -ENOSPC;
+ }
+
+ ret = i915_vma_unbind(vma);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* i915_gem_evict_vm - Evict all idle vmas from a vm
* @vm: Address space to cleanse
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 6ed7d63a0688..dccb517361b3 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -249,6 +249,31 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
obj->cache_level != I915_CACHE_NONE);
}
+/* Used to convert any address to canonical form.
+ * Starting from gen8, some commands (e.g. STATE_BASE_ADDRESS,
+ * MI_LOAD_REGISTER_MEM and others, see Broadwell PRM Vol2a) require the
+ * addresses to be in a canonical form:
+ * "GraphicsAddress[63:48] are ignored by the HW and assumed to be in correct
+ * canonical form [63:48] == [47]."
+ */
+#define GEN8_HIGH_ADDRESS_BIT 47
+static inline uint64_t gen8_canonical_addr(uint64_t address)
+{
+ return sign_extend64(address, GEN8_HIGH_ADDRESS_BIT);
+}
+
+static inline uint64_t gen8_noncanonical_addr(uint64_t address)
+{
+ return address & ((1ULL << (GEN8_HIGH_ADDRESS_BIT + 1)) - 1);
+}
+
+static inline uint64_t
+relocation_target(struct drm_i915_gem_relocation_entry *reloc,
+ uint64_t target_offset)
+{
+ return gen8_canonical_addr((int)reloc->delta + target_offset);
+}
+
static int
relocate_entry_cpu(struct drm_i915_gem_object *obj,
struct drm_i915_gem_relocation_entry *reloc,
@@ -256,7 +281,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
{
struct drm_device *dev = obj->base.dev;
uint32_t page_offset = offset_in_page(reloc->offset);
- uint64_t delta = reloc->delta + target_offset;
+ uint64_t delta = relocation_target(reloc, target_offset);
char *vaddr;
int ret;
@@ -264,7 +289,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
if (ret)
return ret;
- vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+ vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
reloc->offset >> PAGE_SHIFT));
*(uint32_t *)(vaddr + page_offset) = lower_32_bits(delta);
@@ -273,7 +298,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
if (page_offset == 0) {
kunmap_atomic(vaddr);
- vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+ vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
(reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
}
@@ -292,7 +317,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint64_t delta = reloc->delta + target_offset;
+ uint64_t delta = relocation_target(reloc, target_offset);
uint64_t offset;
void __iomem *reloc_page;
int ret;
@@ -347,7 +372,7 @@ relocate_entry_clflush(struct drm_i915_gem_object *obj,
{
struct drm_device *dev = obj->base.dev;
uint32_t page_offset = offset_in_page(reloc->offset);
- uint64_t delta = (int)reloc->delta + target_offset;
+ uint64_t delta = relocation_target(reloc, target_offset);
char *vaddr;
int ret;
@@ -355,7 +380,7 @@ relocate_entry_clflush(struct drm_i915_gem_object *obj,
if (ret)
return ret;
- vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+ vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
reloc->offset >> PAGE_SHIFT));
clflush_write32(vaddr + page_offset, lower_32_bits(delta));
@@ -364,7 +389,7 @@ relocate_entry_clflush(struct drm_i915_gem_object *obj,
if (page_offset == 0) {
kunmap_atomic(vaddr);
- vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+ vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
(reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
}
@@ -395,7 +420,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
target_i915_obj = target_vma->obj;
target_obj = &target_vma->obj->base;
- target_offset = target_vma->node.start;
+ target_offset = gen8_canonical_addr(target_vma->node.start);
/* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
* pipe_control writes because the gpu doesn't properly redirect them
@@ -599,6 +624,8 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
flags |= PIN_GLOBAL | PIN_MAPPABLE;
if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+ if (entry->flags & EXEC_OBJECT_PINNED)
+ flags |= entry->offset | PIN_OFFSET_FIXED;
if ((flags & PIN_MAPPABLE) == 0)
flags |= PIN_HIGH;
}
@@ -670,6 +697,10 @@ eb_vma_misplaced(struct i915_vma *vma)
vma->node.start & (entry->alignment - 1))
return true;
+ if (entry->flags & EXEC_OBJECT_PINNED &&
+ vma->node.start != entry->offset)
+ return true;
+
if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS &&
vma->node.start < BATCH_OFFSET_BIAS)
return true;
@@ -695,6 +726,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
struct i915_vma *vma;
struct i915_address_space *vm;
struct list_head ordered_vmas;
+ struct list_head pinned_vmas;
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
int retry;
@@ -703,6 +735,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm;
INIT_LIST_HEAD(&ordered_vmas);
+ INIT_LIST_HEAD(&pinned_vmas);
while (!list_empty(vmas)) {
struct drm_i915_gem_exec_object2 *entry;
bool need_fence, need_mappable;
@@ -721,7 +754,9 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
obj->tiling_mode != I915_TILING_NONE;
need_mappable = need_fence || need_reloc_mappable(vma);
- if (need_mappable) {
+ if (entry->flags & EXEC_OBJECT_PINNED)
+ list_move_tail(&vma->exec_list, &pinned_vmas);
+ else if (need_mappable) {
entry->flags |= __EXEC_OBJECT_NEEDS_MAP;
list_move(&vma->exec_list, &ordered_vmas);
} else
@@ -731,6 +766,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
obj->base.pending_write_domain = 0;
}
list_splice(&ordered_vmas, vmas);
+ list_splice(&pinned_vmas, vmas);
/* Attempt to pin all of the buffers into the GTT.
* This is done in 3 phases:
@@ -983,6 +1019,21 @@ validate_exec_list(struct drm_device *dev,
if (exec[i].flags & invalid_flags)
return -EINVAL;
+ /* Offset can be used as input (EXEC_OBJECT_PINNED), reject
+ * any non-page-aligned or non-canonical addresses.
+ */
+ if (exec[i].flags & EXEC_OBJECT_PINNED) {
+ if (exec[i].offset !=
+ gen8_canonical_addr(exec[i].offset & PAGE_MASK))
+ return -EINVAL;
+
+ /* From drm_mm perspective address space is continuous,
+ * so from this point we're always using non-canonical
+ * form internally.
+ */
+ exec[i].offset = gen8_noncanonical_addr(exec[i].offset);
+ }
+
if (exec[i].alignment && !is_power_of_2(exec[i].alignment))
return -EINVAL;
@@ -1114,7 +1165,7 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
for (i = 0; i < 4; i++) {
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(ring, GEN7_SO_WRITE_OFFSET(i));
+ intel_ring_emit_reg(ring, GEN7_SO_WRITE_OFFSET(i));
intel_ring_emit(ring, 0);
}
@@ -1241,7 +1292,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
intel_ring_emit(ring, MI_NOOP);
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(ring, INSTPM);
+ intel_ring_emit_reg(ring, INSTPM);
intel_ring_emit(ring, instp_mask << 16 | instp_mode);
intel_ring_advance(ring);
@@ -1317,7 +1368,8 @@ eb_get_batch(struct eb_vmas *eb)
* Note that actual hangs have only been observed on gen7, but for
* paranoia do it everywhere.
*/
- vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS;
+ if ((vma->exec_entry->flags & EXEC_OBJECT_PINNED) == 0)
+ vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS;
return vma->obj;
}
@@ -1675,6 +1727,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
/* Copy the new buffer offsets back to the user's exec list. */
for (i = 0; i < args->buffer_count; i++) {
+ exec2_list[i].offset =
+ gen8_canonical_addr(exec2_list[i].offset);
ret = __copy_to_user(&user_exec_list[i].offset,
&exec2_list[i].offset,
sizeof(user_exec_list[i].offset));
@@ -1740,6 +1794,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
int i;
for (i = 0; i < args->buffer_count; i++) {
+ exec2_list[i].offset =
+ gen8_canonical_addr(exec2_list[i].offset);
ret = __copy_to_user(&user_exec_list[i].offset,
&exec2_list[i].offset,
sizeof(user_exec_list[i].offset));
diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c
index f010391b87f5..598198543dcd 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence.c
+++ b/drivers/gpu/drm/i915/i915_gem_fence.c
@@ -59,7 +59,7 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int fence_reg_lo, fence_reg_hi;
+ i915_reg_t fence_reg_lo, fence_reg_hi;
int fence_pitch_shift;
if (INTEL_INFO(dev)->gen >= 6) {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 86c7500454b4..56f4f2e58d53 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -24,6 +24,7 @@
*/
#include <linux/seq_file.h>
+#include <linux/stop_machine.h>
#include <drm/drmP.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
@@ -104,9 +105,11 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
{
bool has_aliasing_ppgtt;
bool has_full_ppgtt;
+ bool has_full_48bit_ppgtt;
has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
+ has_full_48bit_ppgtt = IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9;
if (intel_vgpu_active(dev))
has_full_ppgtt = false; /* emulation is too hard */
@@ -125,6 +128,9 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
if (enable_ppgtt == 2 && has_full_ppgtt)
return 2;
+ if (enable_ppgtt == 3 && has_full_48bit_ppgtt)
+ return 3;
+
#ifdef CONFIG_INTEL_IOMMU
/* Disable ppgtt on SNB if VT-d is on. */
if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) {
@@ -134,14 +140,13 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
#endif
/* Early VLV doesn't have this */
- if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
- dev->pdev->revision < 0xb) {
+ if (IS_VALLEYVIEW(dev) && dev->pdev->revision < 0xb) {
DRM_DEBUG_DRIVER("disabling PPGTT on pre-B3 step VLV\n");
return 0;
}
if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists)
- return 2;
+ return has_full_48bit_ppgtt ? 3 : 2;
else
return has_aliasing_ppgtt ? 1 : 0;
}
@@ -661,10 +666,10 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req,
return ret;
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(ring, GEN8_RING_PDP_UDW(ring, entry));
+ intel_ring_emit_reg(ring, GEN8_RING_PDP_UDW(ring, entry));
intel_ring_emit(ring, upper_32_bits(addr));
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(ring, GEN8_RING_PDP_LDW(ring, entry));
+ intel_ring_emit_reg(ring, GEN8_RING_PDP_LDW(ring, entry));
intel_ring_emit(ring, lower_32_bits(addr));
intel_ring_advance(ring);
@@ -764,10 +769,10 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
gen8_ppgtt_clear_pte_range(vm, &ppgtt->pdp, start, length,
scratch_pte);
} else {
- uint64_t templ4, pml4e;
+ uint64_t pml4e;
struct i915_page_directory_pointer *pdp;
- gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, templ4, pml4e) {
+ gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, pml4e) {
gen8_ppgtt_clear_pte_range(vm, pdp, start, length,
scratch_pte);
}
@@ -833,10 +838,10 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
cache_level);
} else {
struct i915_page_directory_pointer *pdp;
- uint64_t templ4, pml4e;
+ uint64_t pml4e;
uint64_t length = (uint64_t)pages->orig_nents << PAGE_SHIFT;
- gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, templ4, pml4e) {
+ gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, pml4e) {
gen8_ppgtt_insert_pte_entries(vm, pdp, &sg_iter,
start, cache_level);
}
@@ -904,14 +909,13 @@ static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create)
enum vgt_g2v_type msg;
struct drm_device *dev = ppgtt->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned int offset = vgtif_reg(pdp0_lo);
int i;
if (USES_FULL_48BIT_PPGTT(dev)) {
u64 daddr = px_dma(&ppgtt->pml4);
- I915_WRITE(offset, lower_32_bits(daddr));
- I915_WRITE(offset + 4, upper_32_bits(daddr));
+ I915_WRITE(vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
+ I915_WRITE(vgtif_reg(pdp[0].hi), upper_32_bits(daddr));
msg = (create ? VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY);
@@ -919,10 +923,8 @@ static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create)
for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
- I915_WRITE(offset, lower_32_bits(daddr));
- I915_WRITE(offset + 4, upper_32_bits(daddr));
-
- offset += 8;
+ I915_WRITE(vgtif_reg(pdp[i].lo), lower_32_bits(daddr));
+ I915_WRITE(vgtif_reg(pdp[i].hi), upper_32_bits(daddr));
}
msg = (create ? VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
@@ -1017,10 +1019,9 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_address_space *vm,
{
struct drm_device *dev = vm->dev;
struct i915_page_table *pt;
- uint64_t temp;
uint32_t pde;
- gen8_for_each_pde(pt, pd, start, length, temp, pde) {
+ gen8_for_each_pde(pt, pd, start, length, pde) {
/* Don't reallocate page tables */
if (test_bit(pde, pd->used_pdes)) {
/* Scratch is never allocated this way */
@@ -1079,13 +1080,12 @@ gen8_ppgtt_alloc_page_directories(struct i915_address_space *vm,
{
struct drm_device *dev = vm->dev;
struct i915_page_directory *pd;
- uint64_t temp;
uint32_t pdpe;
uint32_t pdpes = I915_PDPES_PER_PDP(dev);
WARN_ON(!bitmap_empty(new_pds, pdpes));
- gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
+ gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
if (test_bit(pdpe, pdp->used_pdpes))
continue;
@@ -1133,12 +1133,11 @@ gen8_ppgtt_alloc_page_dirpointers(struct i915_address_space *vm,
{
struct drm_device *dev = vm->dev;
struct i915_page_directory_pointer *pdp;
- uint64_t temp;
uint32_t pml4e;
WARN_ON(!bitmap_empty(new_pdps, GEN8_PML4ES_PER_PML4));
- gen8_for_each_pml4e(pdp, pml4, start, length, temp, pml4e) {
+ gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
if (!test_bit(pml4e, pml4->used_pml4es)) {
pdp = alloc_pdp(dev);
if (IS_ERR(pdp))
@@ -1222,7 +1221,6 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
struct i915_page_directory *pd;
const uint64_t orig_start = start;
const uint64_t orig_length = length;
- uint64_t temp;
uint32_t pdpe;
uint32_t pdpes = I915_PDPES_PER_PDP(dev);
int ret;
@@ -1249,7 +1247,7 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
}
/* For every page directory referenced, allocate page tables */
- gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
+ gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
ret = gen8_ppgtt_alloc_pagetabs(vm, pd, start, length,
new_page_tables + pdpe * BITS_TO_LONGS(I915_PDES));
if (ret)
@@ -1261,7 +1259,7 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
/* Allocations have completed successfully, so set the bitmaps, and do
* the mappings. */
- gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
+ gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
gen8_pde_t *const page_directory = kmap_px(pd);
struct i915_page_table *pt;
uint64_t pd_len = length;
@@ -1271,7 +1269,7 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
/* Every pd should be allocated, we just did that above. */
WARN_ON(!pd);
- gen8_for_each_pde(pt, pd, pd_start, pd_len, temp, pde) {
+ gen8_for_each_pde(pt, pd, pd_start, pd_len, pde) {
/* Same reasoning as pd */
WARN_ON(!pt);
WARN_ON(!pd_len);
@@ -1308,6 +1306,8 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
err_out:
while (pdpe--) {
+ unsigned long temp;
+
for_each_set_bit(temp, new_page_tables + pdpe *
BITS_TO_LONGS(I915_PDES), I915_PDES)
free_pt(dev, pdp->page_directory[pdpe]->page_table[temp]);
@@ -1330,7 +1330,7 @@ static int gen8_alloc_va_range_4lvl(struct i915_address_space *vm,
struct i915_hw_ppgtt *ppgtt =
container_of(vm, struct i915_hw_ppgtt, base);
struct i915_page_directory_pointer *pdp;
- uint64_t temp, pml4e;
+ uint64_t pml4e;
int ret = 0;
/* Do the pml4 allocations first, so we don't need to track the newly
@@ -1349,7 +1349,7 @@ static int gen8_alloc_va_range_4lvl(struct i915_address_space *vm,
"The allocation has spanned more than 512GB. "
"It is highly likely this is incorrect.");
- gen8_for_each_pml4e(pdp, pml4, start, length, temp, pml4e) {
+ gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
WARN_ON(!pdp);
ret = gen8_alloc_va_range_3lvl(vm, pdp, start, length);
@@ -1389,10 +1389,9 @@ static void gen8_dump_pdp(struct i915_page_directory_pointer *pdp,
struct seq_file *m)
{
struct i915_page_directory *pd;
- uint64_t temp;
uint32_t pdpe;
- gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
+ gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
struct i915_page_table *pt;
uint64_t pd_len = length;
uint64_t pd_start = start;
@@ -1402,7 +1401,7 @@ static void gen8_dump_pdp(struct i915_page_directory_pointer *pdp,
continue;
seq_printf(m, "\tPDPE #%d\n", pdpe);
- gen8_for_each_pde(pt, pd, pd_start, pd_len, temp, pde) {
+ gen8_for_each_pde(pt, pd, pd_start, pd_len, pde) {
uint32_t pte;
gen8_pte_t *pt_vaddr;
@@ -1452,11 +1451,11 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
gen8_dump_pdp(&ppgtt->pdp, start, length, scratch_pte, m);
} else {
- uint64_t templ4, pml4e;
+ uint64_t pml4e;
struct i915_pml4 *pml4 = &ppgtt->pml4;
struct i915_page_directory_pointer *pdp;
- gen8_for_each_pml4e(pdp, pml4, start, length, templ4, pml4e) {
+ gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
if (!test_bit(pml4e, pml4->used_pml4es))
continue;
@@ -1662,9 +1661,9 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
return ret;
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
- intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
+ intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(ring));
intel_ring_emit(ring, PP_DIR_DCLV_2G);
- intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
+ intel_ring_emit_reg(ring, RING_PP_DIR_BASE(ring));
intel_ring_emit(ring, get_pd_offset(ppgtt));
intel_ring_emit(ring, MI_NOOP);
intel_ring_advance(ring);
@@ -1699,9 +1698,9 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
return ret;
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
- intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
+ intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(ring));
intel_ring_emit(ring, PP_DIR_DCLV_2G);
- intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
+ intel_ring_emit_reg(ring, RING_PP_DIR_BASE(ring));
intel_ring_emit(ring, get_pd_offset(ppgtt));
intel_ring_emit(ring, MI_NOOP);
intel_ring_advance(ring);
@@ -2352,6 +2351,9 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
int i = 0;
struct sg_page_iter sg_iter;
dma_addr_t addr = 0; /* shut up gcc */
+ int rpm_atomic_seq;
+
+ rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
addr = sg_dma_address(sg_iter.sg) +
@@ -2378,6 +2380,34 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
*/
I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
POSTING_READ(GFX_FLSH_CNTL_GEN6);
+
+ assert_rpm_atomic_end(dev_priv, rpm_atomic_seq);
+}
+
+struct insert_entries {
+ struct i915_address_space *vm;
+ struct sg_table *st;
+ uint64_t start;
+ enum i915_cache_level level;
+ u32 flags;
+};
+
+static int gen8_ggtt_insert_entries__cb(void *_arg)
+{
+ struct insert_entries *arg = _arg;
+ gen8_ggtt_insert_entries(arg->vm, arg->st,
+ arg->start, arg->level, arg->flags);
+ return 0;
+}
+
+static void gen8_ggtt_insert_entries__BKL(struct i915_address_space *vm,
+ struct sg_table *st,
+ uint64_t start,
+ enum i915_cache_level level,
+ u32 flags)
+{
+ struct insert_entries arg = { vm, st, start, level, flags };
+ stop_machine(gen8_ggtt_insert_entries__cb, &arg, NULL);
}
/*
@@ -2398,6 +2428,9 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
int i = 0;
struct sg_page_iter sg_iter;
dma_addr_t addr = 0;
+ int rpm_atomic_seq;
+
+ rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
addr = sg_page_iter_dma_address(&sg_iter);
@@ -2422,6 +2455,8 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
*/
I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
POSTING_READ(GFX_FLSH_CNTL_GEN6);
+
+ assert_rpm_atomic_end(dev_priv, rpm_atomic_seq);
}
static void gen8_ggtt_clear_range(struct i915_address_space *vm,
@@ -2436,6 +2471,9 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
(gen8_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
int i;
+ int rpm_atomic_seq;
+
+ rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
if (WARN(num_entries > max_entries,
"First entry = %d; Num entries = %d (max=%d)\n",
@@ -2448,6 +2486,8 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
for (i = 0; i < num_entries; i++)
gen8_set_pte(&gtt_base[i], scratch_pte);
readl(gtt_base);
+
+ assert_rpm_atomic_end(dev_priv, rpm_atomic_seq);
}
static void gen6_ggtt_clear_range(struct i915_address_space *vm,
@@ -2462,6 +2502,9 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
(gen6_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
int i;
+ int rpm_atomic_seq;
+
+ rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
if (WARN(num_entries > max_entries,
"First entry = %d; Num entries = %d (max=%d)\n",
@@ -2474,6 +2517,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
for (i = 0; i < num_entries; i++)
iowrite32(scratch_pte, &gtt_base[i]);
readl(gtt_base);
+
+ assert_rpm_atomic_end(dev_priv, rpm_atomic_seq);
}
static void i915_ggtt_insert_entries(struct i915_address_space *vm,
@@ -2481,11 +2526,17 @@ static void i915_ggtt_insert_entries(struct i915_address_space *vm,
uint64_t start,
enum i915_cache_level cache_level, u32 unused)
{
+ struct drm_i915_private *dev_priv = vm->dev->dev_private;
unsigned int flags = (cache_level == I915_CACHE_NONE) ?
AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
+ int rpm_atomic_seq;
+
+ rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
intel_gtt_insert_sg_entries(pages, start >> PAGE_SHIFT, flags);
+ assert_rpm_atomic_end(dev_priv, rpm_atomic_seq);
+
}
static void i915_ggtt_clear_range(struct i915_address_space *vm,
@@ -2493,9 +2544,16 @@ static void i915_ggtt_clear_range(struct i915_address_space *vm,
uint64_t length,
bool unused)
{
+ struct drm_i915_private *dev_priv = vm->dev->dev_private;
unsigned first_entry = start >> PAGE_SHIFT;
unsigned num_entries = length >> PAGE_SHIFT;
+ int rpm_atomic_seq;
+
+ rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
+
intel_gtt_clear_range(first_entry, num_entries);
+
+ assert_rpm_atomic_end(dev_priv, rpm_atomic_seq);
}
static int ggtt_bind_vma(struct i915_vma *vma,
@@ -2996,6 +3054,9 @@ static int gen8_gmch_probe(struct drm_device *dev,
dev_priv->gtt.base.bind_vma = ggtt_bind_vma;
dev_priv->gtt.base.unbind_vma = ggtt_unbind_vma;
+ if (IS_CHERRYVIEW(dev_priv))
+ dev_priv->gtt.base.insert_entries = gen8_ggtt_insert_entries__BKL;
+
return ret;
}
@@ -3303,7 +3364,7 @@ static struct sg_table *
intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
struct drm_i915_gem_object *obj)
{
- struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
+ struct intel_rotation_info *rot_info = &ggtt_view->params.rotation_info;
unsigned int size_pages = rot_info->size >> PAGE_SHIFT;
unsigned int size_pages_uv;
struct sg_page_iter sg_iter;
@@ -3535,7 +3596,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj,
if (view->type == I915_GGTT_VIEW_NORMAL) {
return obj->base.size;
} else if (view->type == I915_GGTT_VIEW_ROTATED) {
- return view->rotation_info.size;
+ return view->params.rotation_info.size;
} else if (view->type == I915_GGTT_VIEW_PARTIAL) {
return view->params.partial.size << PAGE_SHIFT;
} else {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index a216397ead52..b448ad832dcf 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -156,13 +156,10 @@ struct i915_ggtt_view {
u64 offset;
unsigned int size;
} partial;
+ struct intel_rotation_info rotation_info;
} params;
struct sg_table *pages;
-
- union {
- struct intel_rotation_info rotation_info;
- };
};
extern const struct i915_ggtt_view i915_ggtt_view_normal;
@@ -458,32 +455,29 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
* between from start until start + length. On gen8+ it simply iterates
* over every page directory entry in a page directory.
*/
-#define gen8_for_each_pde(pt, pd, start, length, temp, iter) \
- for (iter = gen8_pde_index(start); \
- length > 0 && iter < I915_PDES ? \
- (pt = (pd)->page_table[iter]), 1 : 0; \
- iter++, \
- temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \
- temp = min(temp, length), \
- start += temp, length -= temp)
-
-#define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \
- for (iter = gen8_pdpe_index(start); \
- length > 0 && (iter < I915_PDPES_PER_PDP(dev)) ? \
- (pd = (pdp)->page_directory[iter]), 1 : 0; \
- iter++, \
- temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \
- temp = min(temp, length), \
- start += temp, length -= temp)
-
-#define gen8_for_each_pml4e(pdp, pml4, start, length, temp, iter) \
- for (iter = gen8_pml4e_index(start); \
- length > 0 && iter < GEN8_PML4ES_PER_PML4 ? \
- (pdp = (pml4)->pdps[iter]), 1 : 0; \
- iter++, \
- temp = ALIGN(start+1, 1ULL << GEN8_PML4E_SHIFT) - start, \
- temp = min(temp, length), \
- start += temp, length -= temp)
+#define gen8_for_each_pde(pt, pd, start, length, iter) \
+ for (iter = gen8_pde_index(start); \
+ length > 0 && iter < I915_PDES && \
+ (pt = (pd)->page_table[iter], true); \
+ ({ u64 temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT); \
+ temp = min(temp - start, length); \
+ start += temp, length -= temp; }), ++iter)
+
+#define gen8_for_each_pdpe(pd, pdp, start, length, iter) \
+ for (iter = gen8_pdpe_index(start); \
+ length > 0 && iter < I915_PDPES_PER_PDP(dev) && \
+ (pd = (pdp)->page_directory[iter], true); \
+ ({ u64 temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT); \
+ temp = min(temp - start, length); \
+ start += temp, length -= temp; }), ++iter)
+
+#define gen8_for_each_pml4e(pdp, pml4, start, length, iter) \
+ for (iter = gen8_pml4e_index(start); \
+ length > 0 && iter < GEN8_PML4ES_PER_PML4 && \
+ (pdp = (pml4)->pdps[iter], true); \
+ ({ u64 temp = ALIGN(start+1, 1ULL << GEN8_PML4E_SHIFT); \
+ temp = min(temp - start, length); \
+ start += temp, length -= temp; }), ++iter)
static inline uint32_t gen8_pte_index(uint64_t address)
{
@@ -556,7 +550,7 @@ i915_ggtt_view_equal(const struct i915_ggtt_view *a,
if (a->type != b->type)
return false;
- if (a->type == I915_GGTT_VIEW_PARTIAL)
+ if (a->type != I915_GGTT_VIEW_NORMAL)
return !memcmp(&a->params, &b->params, sizeof(a->params));
return true;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c
index 5026a6267a88..fc7e6d5c6251 100644
--- a/drivers/gpu/drm/i915/i915_gem_render_state.c
+++ b/drivers/gpu/drm/i915/i915_gem_render_state.c
@@ -103,7 +103,7 @@ static int render_state_setup(struct render_state *so)
if (ret)
return ret;
- page = sg_page(so->obj->pages->sgl);
+ page = i915_gem_object_get_dirty_page(so->obj, 0);
d = kmap(page);
while (i < rodata->batch_items) {
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 87e919a06b27..3476877fc0d6 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -433,7 +433,8 @@ int i915_gem_init_stolen(struct drm_device *dev)
&reserved_size);
break;
default:
- if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv))
+ if (IS_BROADWELL(dev_priv) ||
+ IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev))
bdw_get_stolen_reserved(dev_priv, &reserved_base,
&reserved_size);
else
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 8a6717cc265c..7410f6c962e7 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -176,6 +176,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
return -EINVAL;
}
+ intel_runtime_pm_get(dev_priv);
+
mutex_lock(&dev->struct_mutex);
if (obj->pin_display || obj->framebuffer_references) {
ret = -EBUSY;
@@ -269,6 +271,8 @@ err:
drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
+ intel_runtime_pm_put(dev_priv);
+
return ret;
}
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 2f04e4f2ff35..06ca4082735b 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -366,6 +366,17 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
err_printf(m, "Suspend count: %u\n", error->suspend_count);
err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device);
err_printf(m, "IOMMU enabled?: %d\n", error->iommu);
+
+ if (HAS_CSR(dev)) {
+ struct intel_csr *csr = &dev_priv->csr;
+
+ err_printf(m, "DMC loaded: %s\n",
+ yesno(csr->dmc_payload != NULL));
+ err_printf(m, "DMC fw version: %d.%d\n",
+ CSR_VERSION_MAJOR(csr->version),
+ CSR_VERSION_MINOR(csr->version));
+ }
+
err_printf(m, "EIR: 0x%08x\n", error->eir);
err_printf(m, "IER: 0x%08x\n", error->ier);
if (INTEL_INFO(dev)->gen >= 8) {
@@ -862,7 +873,7 @@ static void i915_record_ring_state(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
if (INTEL_INFO(dev)->gen >= 6) {
- ering->rc_psmi = I915_READ(ring->mmio_base + 0x50);
+ ering->rc_psmi = I915_READ(RING_PSMI_CTL(ring->mmio_base));
ering->fault_reg = I915_READ(RING_FAULT_REG(ring));
if (INTEL_INFO(dev)->gen >= 8)
gen8_record_semaphore_state(dev_priv, error, ring, ering);
@@ -899,7 +910,7 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->ctl = I915_READ_CTL(ring);
if (I915_NEED_GFX_HWS(dev)) {
- int mmio;
+ i915_reg_t mmio;
if (IS_GEN7(dev)) {
switch (ring->id) {
@@ -1071,6 +1082,25 @@ static void i915_gem_record_rings(struct drm_device *dev,
list_for_each_entry(request, &ring->request_list, list) {
struct drm_i915_error_request *erq;
+ if (count >= error->ring[i].num_requests) {
+ /*
+ * If the ring request list was changed in
+ * between the point where the error request
+ * list was created and dimensioned and this
+ * point then just exit early to avoid crashes.
+ *
+ * We don't need to communicate that the
+ * request list changed state during error
+ * state capture and that the error state is
+ * slightly incorrect as a consequence since we
+ * are typically only interested in the request
+ * list state at the point of error state
+ * capture, not in any changes happening during
+ * the capture.
+ */
+ break;
+ }
+
erq = &error->ring[i].requests[count++];
erq->seqno = request->seqno;
erq->jiffies = request->emitted_jiffies;
@@ -1181,7 +1211,7 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
if (IS_VALLEYVIEW(dev)) {
error->gtier[0] = I915_READ(GTIER);
error->ier = I915_READ(VLV_IER);
- error->forcewake = I915_READ(FORCEWAKE_VLV);
+ error->forcewake = I915_READ_FW(FORCEWAKE_VLV);
}
if (IS_GEN7(dev))
@@ -1193,14 +1223,14 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
}
if (IS_GEN6(dev)) {
- error->forcewake = I915_READ(FORCEWAKE);
+ error->forcewake = I915_READ_FW(FORCEWAKE);
error->gab_ctl = I915_READ(GAB_CTL);
error->gfx_mode = I915_READ(GFX_MODE);
}
/* 2: Registers which belong to multiple generations */
if (INTEL_INFO(dev)->gen >= 7)
- error->forcewake = I915_READ(FORCEWAKE_MT);
+ error->forcewake = I915_READ_FW(FORCEWAKE_MT);
if (INTEL_INFO(dev)->gen >= 6) {
error->derrmr = I915_READ(DERRMR);
diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h
index c4cb1c0c4d0d..685c7991e24f 100644
--- a/drivers/gpu/drm/i915/i915_guc_reg.h
+++ b/drivers/gpu/drm/i915/i915_guc_reg.h
@@ -26,7 +26,7 @@
/* Definitions of GuC H/W registers, bits, etc */
-#define GUC_STATUS 0xc000
+#define GUC_STATUS _MMIO(0xc000)
#define GS_BOOTROM_SHIFT 1
#define GS_BOOTROM_MASK (0x7F << GS_BOOTROM_SHIFT)
#define GS_BOOTROM_RSA_FAILED (0x50 << GS_BOOTROM_SHIFT)
@@ -39,40 +39,41 @@
#define GS_MIA_MASK (0x07 << GS_MIA_SHIFT)
#define GS_MIA_CORE_STATE (1 << GS_MIA_SHIFT)
-#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4))
+#define SOFT_SCRATCH(n) _MMIO(0xc180 + (n) * 4)
-#define UOS_RSA_SCRATCH(i) (0xc200 + (i) * 4)
-#define DMA_ADDR_0_LOW 0xc300
-#define DMA_ADDR_0_HIGH 0xc304
-#define DMA_ADDR_1_LOW 0xc308
-#define DMA_ADDR_1_HIGH 0xc30c
+#define UOS_RSA_SCRATCH(i) _MMIO(0xc200 + (i) * 4)
+#define UOS_RSA_SCRATCH_MAX_COUNT 64
+#define DMA_ADDR_0_LOW _MMIO(0xc300)
+#define DMA_ADDR_0_HIGH _MMIO(0xc304)
+#define DMA_ADDR_1_LOW _MMIO(0xc308)
+#define DMA_ADDR_1_HIGH _MMIO(0xc30c)
#define DMA_ADDRESS_SPACE_WOPCM (7 << 16)
#define DMA_ADDRESS_SPACE_GTT (8 << 16)
-#define DMA_COPY_SIZE 0xc310
-#define DMA_CTRL 0xc314
+#define DMA_COPY_SIZE _MMIO(0xc310)
+#define DMA_CTRL _MMIO(0xc314)
#define UOS_MOVE (1<<4)
#define START_DMA (1<<0)
-#define DMA_GUC_WOPCM_OFFSET 0xc340
+#define DMA_GUC_WOPCM_OFFSET _MMIO(0xc340)
#define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */
-#define GUC_MAX_IDLE_COUNT 0xC3E4
+#define GUC_MAX_IDLE_COUNT _MMIO(0xC3E4)
-#define GUC_WOPCM_SIZE 0xc050
+#define GUC_WOPCM_SIZE _MMIO(0xc050)
#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */
/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
#define GUC_WOPCM_TOP (GUC_WOPCM_SIZE_VALUE)
-#define GEN8_GT_PM_CONFIG 0x138140
-#define GEN9LP_GT_PM_CONFIG 0x138140
-#define GEN9_GT_PM_CONFIG 0x13816c
+#define GEN8_GT_PM_CONFIG _MMIO(0x138140)
+#define GEN9LP_GT_PM_CONFIG _MMIO(0x138140)
+#define GEN9_GT_PM_CONFIG _MMIO(0x13816c)
#define GT_DOORBELL_ENABLE (1<<0)
-#define GEN8_GTCR 0x4274
+#define GEN8_GTCR _MMIO(0x4274)
#define GEN8_GTCR_INVALIDATE (1<<0)
-#define GUC_ARAT_C6DIS 0xA178
+#define GUC_ARAT_C6DIS _MMIO(0xA178)
-#define GUC_SHIM_CONTROL 0xc064
+#define GUC_SHIM_CONTROL _MMIO(0xc064)
#define GUC_DISABLE_SRAM_INIT_TO_ZEROES (1<<0)
#define GUC_ENABLE_READ_CACHE_LOGIC (1<<1)
#define GUC_ENABLE_MIA_CACHING (1<<2)
@@ -89,21 +90,21 @@
GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA | \
GUC_ENABLE_MIA_CLOCK_GATING)
-#define HOST2GUC_INTERRUPT 0xc4c8
+#define HOST2GUC_INTERRUPT _MMIO(0xc4c8)
#define HOST2GUC_TRIGGER (1<<0)
#define DRBMISC1 0x1984
#define DOORBELL_ENABLE (1<<0)
-#define GEN8_DRBREGL(x) (0x1000 + (x) * 8)
+#define GEN8_DRBREGL(x) _MMIO(0x1000 + (x) * 8)
#define GEN8_DRB_VALID (1<<0)
-#define GEN8_DRBREGU(x) (GEN8_DRBREGL(x) + 4)
+#define GEN8_DRBREGU(x) _MMIO(0x1000 + (x) * 8 + 4)
-#define DE_GUCRMR 0x44054
+#define DE_GUCRMR _MMIO(0x44054)
-#define GUC_BCS_RCS_IER 0xC550
-#define GUC_VCS2_VCS1_IER 0xC554
-#define GUC_WD_VECS_IER 0xC558
-#define GUC_PM_P24C_IER 0xC55C
+#define GUC_BCS_RCS_IER _MMIO(0xC550)
+#define GUC_VCS2_VCS1_IER _MMIO(0xC554)
+#define GUC_WD_VECS_IER _MMIO(0xC558)
+#define GUC_PM_P24C_IER _MMIO(0xC55C)
#endif
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 036b42bae827..05aa7e61cbe0 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -27,7 +27,7 @@
#include "intel_guc.h"
/**
- * DOC: GuC Client
+ * DOC: GuC-based command submission
*
* i915_guc_client:
* We use the term client to avoid confusion with contexts. A i915_guc_client is
@@ -86,7 +86,6 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
return -EINVAL;
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
- spin_lock(&dev_priv->guc.host2guc_lock);
dev_priv->guc.action_count += 1;
dev_priv->guc.action_cmd = data[0];
@@ -119,7 +118,6 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
}
dev_priv->guc.action_status = status;
- spin_unlock(&dev_priv->guc.host2guc_lock);
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
return ret;
@@ -161,9 +159,9 @@ static int host2guc_sample_forcewake(struct intel_guc *guc,
data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
/* WaRsDisableCoarsePowerGating:skl,bxt */
if (!intel_enable_rc6(dev_priv->dev) ||
- (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
- (IS_SKL_GT3(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)) ||
- (IS_SKL_GT4(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1) ||
+ (IS_SKL_GT3(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0)) ||
+ (IS_SKL_GT4(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0)))
data[1] = 0;
else
/* bit 0 and 1 are for Render and Media domain separately */
@@ -258,7 +256,7 @@ static void guc_disable_doorbell(struct intel_guc *guc,
struct drm_i915_private *dev_priv = guc_to_i915(guc);
struct guc_doorbell_info *doorbell;
void *base;
- int drbreg = GEN8_DRBREGL(client->doorbell_id);
+ i915_reg_t drbreg = GEN8_DRBREGL(client->doorbell_id);
int value;
base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
@@ -292,16 +290,12 @@ static uint32_t select_doorbell_cacheline(struct intel_guc *guc)
const uint32_t cacheline_size = cache_line_size();
uint32_t offset;
- spin_lock(&guc->host2guc_lock);
-
/* Doorbell uses a single cache line within a page */
offset = offset_in_page(guc->db_cacheline);
/* Moving to next cache line to reduce contention */
guc->db_cacheline += cacheline_size;
- spin_unlock(&guc->host2guc_lock);
-
DRM_DEBUG_DRIVER("selected doorbell cacheline 0x%x, next 0x%x, linesize %u\n",
offset, guc->db_cacheline, cacheline_size);
@@ -322,13 +316,11 @@ static uint16_t assign_doorbell(struct intel_guc *guc, uint32_t priority)
const uint16_t end = start + half;
uint16_t id;
- spin_lock(&guc->host2guc_lock);
id = find_next_zero_bit(guc->doorbell_bitmap, end, start);
if (id == end)
id = GUC_INVALID_DOORBELL_ID;
else
bitmap_set(guc->doorbell_bitmap, id, 1);
- spin_unlock(&guc->host2guc_lock);
DRM_DEBUG_DRIVER("assigned %s priority doorbell id 0x%x\n",
hi_pri ? "high" : "normal", id);
@@ -338,9 +330,7 @@ static uint16_t assign_doorbell(struct intel_guc *guc, uint32_t priority)
static void release_doorbell(struct intel_guc *guc, uint16_t id)
{
- spin_lock(&guc->host2guc_lock);
bitmap_clear(guc->doorbell_bitmap, id, 1);
- spin_unlock(&guc->host2guc_lock);
}
/*
@@ -487,16 +477,13 @@ static int guc_get_workqueue_space(struct i915_guc_client *gc, u32 *offset)
struct guc_process_desc *desc;
void *base;
u32 size = sizeof(struct guc_wq_item);
- int ret = 0, timeout_counter = 200;
+ int ret = -ETIMEDOUT, timeout_counter = 200;
base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
desc = base + gc->proc_desc_offset;
while (timeout_counter-- > 0) {
- ret = wait_for_atomic(CIRC_SPACE(gc->wq_tail, desc->head,
- gc->wq_size) >= size, 1);
-
- if (!ret) {
+ if (CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size) >= size) {
*offset = gc->wq_tail;
/* advance the tail for next workqueue item */
@@ -505,7 +492,11 @@ static int guc_get_workqueue_space(struct i915_guc_client *gc, u32 *offset)
/* this will break the loop */
timeout_counter = 0;
+ ret = 0;
}
+
+ if (timeout_counter)
+ usleep_range(1000, 2000);
};
kunmap_atomic(base);
@@ -577,7 +568,7 @@ static void lr_context_update(struct drm_i915_gem_request *rq)
WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
- page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+ page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj);
@@ -588,8 +579,7 @@ static void lr_context_update(struct drm_i915_gem_request *rq)
/**
* i915_guc_submit() - Submit commands through GuC
* @client: the guc client where commands will go through
- * @ctx: LRC where commands come from
- * @ring: HW engine that will excute the commands
+ * @rq: request associated with the commands
*
* Return: 0 if succeed
*/
@@ -598,15 +588,12 @@ int i915_guc_submit(struct i915_guc_client *client,
{
struct intel_guc *guc = client->guc;
enum intel_ring_id ring_id = rq->ring->id;
- unsigned long flags;
int q_ret, b_ret;
/* Need this because of the deferred pin ctx and ring */
/* Shall we move this right after ring is pinned? */
lr_context_update(rq);
- spin_lock_irqsave(&client->wq_lock, flags);
-
q_ret = guc_add_workqueue_item(client, rq);
if (q_ret == 0)
b_ret = guc_ring_doorbell(client);
@@ -621,12 +608,8 @@ int i915_guc_submit(struct i915_guc_client *client,
} else {
client->retcode = 0;
}
- spin_unlock_irqrestore(&client->wq_lock, flags);
-
- spin_lock(&guc->host2guc_lock);
guc->submissions[ring_id] += 1;
guc->last_seqno[ring_id] = rq->seqno;
- spin_unlock(&guc->host2guc_lock);
return q_ret;
}
@@ -678,7 +661,7 @@ static struct drm_i915_gem_object *gem_allocate_guc_obj(struct drm_device *dev,
/**
* gem_release_guc_obj() - Release gem object allocated for GuC usage
* @obj: gem obj to be released
- */
+ */
static void gem_release_guc_obj(struct drm_i915_gem_object *obj)
{
if (!obj)
@@ -731,7 +714,8 @@ static void guc_client_free(struct drm_device *dev,
* The kernel client to replace ExecList submission is created with
* NORMAL priority. Priority of a client for scheduler can be HIGH,
* while a preemption context can use CRITICAL.
- * @ctx the context to own the client (we use the default render context)
+ * @ctx: the context that owns the client (we use the default render
+ * context)
*
* Return: An i915_guc_client object if success.
*/
@@ -768,7 +752,6 @@ static struct i915_guc_client *guc_client_alloc(struct drm_device *dev,
client->client_obj = obj;
client->wq_offset = GUC_DB_SIZE;
client->wq_size = GUC_WQ_SIZE;
- spin_lock_init(&client->wq_lock);
client->doorbell_offset = select_doorbell_cacheline(guc);
@@ -871,8 +854,6 @@ int i915_guc_submission_init(struct drm_device *dev)
if (!guc->ctx_pool_obj)
return -ENOMEM;
- spin_lock_init(&dev_priv->guc.host2guc_lock);
-
ida_init(&guc->ctx_ids);
guc_create_log(guc);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0d228f909dcb..fa8afa7860ae 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -139,7 +139,8 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
/*
* We should clear IMR at preinstall/uninstall, and just check at postinstall.
*/
-static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg)
+static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
+ i915_reg_t reg)
{
u32 val = I915_READ(reg);
@@ -147,7 +148,7 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg)
return;
WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
- reg, val);
+ i915_mmio_reg_offset(reg), val);
I915_WRITE(reg, 0xffffffff);
POSTING_READ(reg);
I915_WRITE(reg, 0xffffffff);
@@ -214,9 +215,9 @@ void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
* @interrupt_mask: mask of interrupt bits to update
* @enabled_irq_mask: mask of interrupt bits to enable
*/
-static void ilk_update_display_irq(struct drm_i915_private *dev_priv,
- uint32_t interrupt_mask,
- uint32_t enabled_irq_mask)
+void ilk_update_display_irq(struct drm_i915_private *dev_priv,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask)
{
uint32_t new_val;
@@ -238,18 +239,6 @@ static void ilk_update_display_irq(struct drm_i915_private *dev_priv,
}
}
-void
-ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
-{
- ilk_update_display_irq(dev_priv, mask, mask);
-}
-
-void
-ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
-{
- ilk_update_display_irq(dev_priv, mask, 0);
-}
-
/**
* ilk_update_gt_irq - update GTIMR
* @dev_priv: driver private
@@ -283,27 +272,27 @@ void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask)
ilk_update_gt_irq(dev_priv, mask, 0);
}
-static u32 gen6_pm_iir(struct drm_i915_private *dev_priv)
+static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
{
return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
}
-static u32 gen6_pm_imr(struct drm_i915_private *dev_priv)
+static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
{
return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR;
}
-static u32 gen6_pm_ier(struct drm_i915_private *dev_priv)
+static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
{
return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER;
}
/**
- * snb_update_pm_irq - update GEN6_PMIMR
- * @dev_priv: driver private
- * @interrupt_mask: mask of interrupt bits to update
- * @enabled_irq_mask: mask of interrupt bits to enable
- */
+ * snb_update_pm_irq - update GEN6_PMIMR
+ * @dev_priv: driver private
+ * @interrupt_mask: mask of interrupt bits to update
+ * @enabled_irq_mask: mask of interrupt bits to enable
+ */
static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
uint32_t interrupt_mask,
uint32_t enabled_irq_mask)
@@ -350,7 +339,7 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
void gen6_reset_rps_interrupts(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t reg = gen6_pm_iir(dev_priv);
+ i915_reg_t reg = gen6_pm_iir(dev_priv);
spin_lock_irq(&dev_priv->irq_lock);
I915_WRITE(reg, dev_priv->pm_rps_events);
@@ -417,11 +406,11 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
}
/**
- * bdw_update_port_irq - update DE port interrupt
- * @dev_priv: driver private
- * @interrupt_mask: mask of interrupt bits to update
- * @enabled_irq_mask: mask of interrupt bits to enable
- */
+ * bdw_update_port_irq - update DE port interrupt
+ * @dev_priv: driver private
+ * @interrupt_mask: mask of interrupt bits to update
+ * @enabled_irq_mask: mask of interrupt bits to enable
+ */
static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
uint32_t interrupt_mask,
uint32_t enabled_irq_mask)
@@ -449,6 +438,38 @@ static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
}
/**
+ * bdw_update_pipe_irq - update DE pipe interrupt
+ * @dev_priv: driver private
+ * @pipe: pipe whose interrupt to update
+ * @interrupt_mask: mask of interrupt bits to update
+ * @enabled_irq_mask: mask of interrupt bits to enable
+ */
+void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
+ enum pipe pipe,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask)
+{
+ uint32_t new_val;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
+ if (WARN_ON(!intel_irqs_enabled(dev_priv)))
+ return;
+
+ new_val = dev_priv->de_irq_mask[pipe];
+ new_val &= ~interrupt_mask;
+ new_val |= (~enabled_irq_mask & interrupt_mask);
+
+ if (new_val != dev_priv->de_irq_mask[pipe]) {
+ dev_priv->de_irq_mask[pipe] = new_val;
+ I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+ POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+ }
+}
+
+/**
* ibx_display_interrupt_update - update SDEIMR
* @dev_priv: driver private
* @interrupt_mask: mask of interrupt bits to update
@@ -477,7 +498,7 @@ static void
__i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
u32 enable_mask, u32 status_mask)
{
- u32 reg = PIPESTAT(pipe);
+ i915_reg_t reg = PIPESTAT(pipe);
u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
assert_spin_locked(&dev_priv->irq_lock);
@@ -504,7 +525,7 @@ static void
__i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
u32 enable_mask, u32 status_mask)
{
- u32 reg = PIPESTAT(pipe);
+ i915_reg_t reg = PIPESTAT(pipe);
u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
assert_spin_locked(&dev_priv->irq_lock);
@@ -560,7 +581,7 @@ i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
{
u32 enable_mask;
- if (IS_VALLEYVIEW(dev_priv->dev))
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev,
status_mask);
else
@@ -574,7 +595,7 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
{
u32 enable_mask;
- if (IS_VALLEYVIEW(dev_priv->dev))
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev,
status_mask);
else
@@ -665,8 +686,7 @@ static u32 i8xx_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long high_frame;
- unsigned long low_frame;
+ i915_reg_t high_frame, low_frame;
u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
struct intel_crtc *intel_crtc =
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
@@ -717,9 +737,7 @@ static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
}
-/* raw reads, only for fast reads of display block, no need for forcewake etc. */
-#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-
+/* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */
static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
@@ -733,9 +751,9 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
vtotal /= 2;
if (IS_GEN2(dev))
- position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
+ position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
else
- position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
+ position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
/*
* On HSW, the DSL reg (0x70000) appears to return 0 if we
@@ -827,7 +845,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
* We can split this into vertical and horizontal
* scanout position.
*/
- position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
+ position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
/* convert to pixel counts */
vbl_start *= htotal;
@@ -1085,6 +1103,14 @@ static void gen6_pm_rps_work(struct work_struct *work)
spin_unlock_irq(&dev_priv->irq_lock);
return;
}
+
+ /*
+ * The RPS work is synced during runtime suspend, we don't require a
+ * wakeref. TODO: instead of disabling the asserts make sure that we
+ * always hold an RPM reference while the work is running.
+ */
+ DISABLE_RPM_WAKEREF_ASSERTS(dev_priv);
+
pm_iir = dev_priv->rps.pm_iir;
dev_priv->rps.pm_iir = 0;
/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
@@ -1097,7 +1123,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
if ((pm_iir & dev_priv->pm_rps_events) == 0 && !client_boost)
- return;
+ goto out;
mutex_lock(&dev_priv->rps.hw_lock);
@@ -1152,6 +1178,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
intel_set_rps(dev_priv->dev, new_delay);
mutex_unlock(&dev_priv->rps.hw_lock);
+out:
+ ENABLE_RPM_WAKEREF_ASSERTS(dev_priv);
}
@@ -1188,7 +1216,7 @@ static void ivybridge_parity_work(struct work_struct *work)
POSTING_READ(GEN7_MISCCPCTL);
while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
- u32 reg;
+ i915_reg_t reg;
slice--;
if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
@@ -1196,7 +1224,7 @@ static void ivybridge_parity_work(struct work_struct *work)
dev_priv->l3_parity.which_slice &= ~(1<<slice);
- reg = GEN7_L3CDERRST1 + (slice * 0x200);
+ reg = GEN7_L3CDERRST1(slice);
error_status = I915_READ(reg);
row = GEN7_PARITY_ERROR_ROW(error_status);
@@ -1290,70 +1318,69 @@ static void snb_gt_irq_handler(struct drm_device *dev,
ivybridge_parity_error_irq_handler(dev, gt_iir);
}
+static __always_inline void
+gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift)
+{
+ if (iir & (GT_RENDER_USER_INTERRUPT << test_shift))
+ notify_ring(ring);
+ if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
+ intel_lrc_irq_handler(ring);
+}
+
static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
u32 master_ctl)
{
irqreturn_t ret = IRQ_NONE;
if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
- u32 tmp = I915_READ_FW(GEN8_GT_IIR(0));
- if (tmp) {
- I915_WRITE_FW(GEN8_GT_IIR(0), tmp);
+ u32 iir = I915_READ_FW(GEN8_GT_IIR(0));
+ if (iir) {
+ I915_WRITE_FW(GEN8_GT_IIR(0), iir);
ret = IRQ_HANDLED;
- if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT))
- intel_lrc_irq_handler(&dev_priv->ring[RCS]);
- if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT))
- notify_ring(&dev_priv->ring[RCS]);
+ gen8_cs_irq_handler(&dev_priv->ring[RCS],
+ iir, GEN8_RCS_IRQ_SHIFT);
- if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT))
- intel_lrc_irq_handler(&dev_priv->ring[BCS]);
- if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT))
- notify_ring(&dev_priv->ring[BCS]);
+ gen8_cs_irq_handler(&dev_priv->ring[BCS],
+ iir, GEN8_BCS_IRQ_SHIFT);
} else
DRM_ERROR("The master control interrupt lied (GT0)!\n");
}
if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
- u32 tmp = I915_READ_FW(GEN8_GT_IIR(1));
- if (tmp) {
- I915_WRITE_FW(GEN8_GT_IIR(1), tmp);
+ u32 iir = I915_READ_FW(GEN8_GT_IIR(1));
+ if (iir) {
+ I915_WRITE_FW(GEN8_GT_IIR(1), iir);
ret = IRQ_HANDLED;
- if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT))
- intel_lrc_irq_handler(&dev_priv->ring[VCS]);
- if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT))
- notify_ring(&dev_priv->ring[VCS]);
+ gen8_cs_irq_handler(&dev_priv->ring[VCS],
+ iir, GEN8_VCS1_IRQ_SHIFT);
- if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))
- intel_lrc_irq_handler(&dev_priv->ring[VCS2]);
- if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))
- notify_ring(&dev_priv->ring[VCS2]);
+ gen8_cs_irq_handler(&dev_priv->ring[VCS2],
+ iir, GEN8_VCS2_IRQ_SHIFT);
} else
DRM_ERROR("The master control interrupt lied (GT1)!\n");
}
if (master_ctl & GEN8_GT_VECS_IRQ) {
- u32 tmp = I915_READ_FW(GEN8_GT_IIR(3));
- if (tmp) {
- I915_WRITE_FW(GEN8_GT_IIR(3), tmp);
+ u32 iir = I915_READ_FW(GEN8_GT_IIR(3));
+ if (iir) {
+ I915_WRITE_FW(GEN8_GT_IIR(3), iir);
ret = IRQ_HANDLED;
- if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT))
- intel_lrc_irq_handler(&dev_priv->ring[VECS]);
- if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT))
- notify_ring(&dev_priv->ring[VECS]);
+ gen8_cs_irq_handler(&dev_priv->ring[VECS],
+ iir, GEN8_VECS_IRQ_SHIFT);
} else
DRM_ERROR("The master control interrupt lied (GT3)!\n");
}
if (master_ctl & GEN8_GT_PM_IRQ) {
- u32 tmp = I915_READ_FW(GEN8_GT_IIR(2));
- if (tmp & dev_priv->pm_rps_events) {
+ u32 iir = I915_READ_FW(GEN8_GT_IIR(2));
+ if (iir & dev_priv->pm_rps_events) {
I915_WRITE_FW(GEN8_GT_IIR(2),
- tmp & dev_priv->pm_rps_events);
+ iir & dev_priv->pm_rps_events);
ret = IRQ_HANDLED;
- gen6_rps_irq_handler(dev_priv, tmp);
+ gen6_rps_irq_handler(dev_priv, iir);
} else
DRM_ERROR("The master control interrupt lied (PM)!\n");
}
@@ -1625,7 +1652,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
spin_lock(&dev_priv->irq_lock);
for_each_pipe(dev_priv, pipe) {
- int reg;
+ i915_reg_t reg;
u32 mask, iir_bit = 0;
/*
@@ -1706,7 +1733,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
*/
POSTING_READ(PORT_HOTPLUG_STAT);
- if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
+ if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
if (hotplug_trigger) {
@@ -1741,6 +1768,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
while (true) {
/* Find, clear, then process each source of interrupt */
@@ -1775,6 +1805,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
}
out:
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
@@ -1788,6 +1820,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
for (;;) {
master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
iir = I915_READ(VLV_IIR);
@@ -1818,6 +1853,8 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
POSTING_READ(GEN8_MASTER_IRQ);
}
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
@@ -1827,8 +1864,24 @@ static void ibx_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
struct drm_i915_private *dev_priv = to_i915(dev);
u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
+ /*
+ * Somehow the PCH doesn't seem to really ack the interrupt to the CPU
+ * unless we touch the hotplug register, even if hotplug_trigger is
+ * zero. Not acking leads to "The master control interrupt lied (SDE)!"
+ * errors.
+ */
dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
+ if (!hotplug_trigger) {
+ u32 mask = PORTA_HOTPLUG_STATUS_MASK |
+ PORTD_HOTPLUG_STATUS_MASK |
+ PORTC_HOTPLUG_STATUS_MASK |
+ PORTB_HOTPLUG_STATUS_MASK;
+ dig_hotplug_reg &= ~mask;
+ }
+
I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
+ if (!hotplug_trigger)
+ return;
intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
dig_hotplug_reg, hpd,
@@ -1843,8 +1896,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
- if (hotplug_trigger)
- ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+ ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
if (pch_iir & SDE_AUDIO_POWER_MASK) {
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -1937,8 +1989,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
- if (hotplug_trigger)
- ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+ ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -2134,6 +2185,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
/* We get interrupts on unclaimed registers, so check for this before we
* do any I915_{READ,WRITE}. */
intel_uncore_check_errors(dev);
@@ -2192,6 +2246,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
POSTING_READ(SDEIER);
}
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
@@ -2224,6 +2281,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
if (INTEL_INFO(dev_priv)->gen >= 9)
aux_mask |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
GEN9_AUX_CHANNEL_D;
@@ -2231,7 +2291,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
if (!master_ctl)
- return IRQ_NONE;
+ goto out;
I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
@@ -2354,14 +2414,21 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
spt_irq_handler(dev, pch_iir);
else
cpt_irq_handler(dev, pch_iir);
- } else
- DRM_ERROR("The master control interrupt lied (SDE)!\n");
-
+ } else {
+ /*
+ * Like on previous PCH there seems to be something
+ * fishy going on with forwarding PCH interrupts.
+ */
+ DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n");
+ }
}
I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
POSTING_READ_FW(GEN8_MASTER_IRQ);
+out:
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
@@ -2644,7 +2711,7 @@ static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
DE_PIPE_VBLANK(pipe);
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- ironlake_enable_display_irq(dev_priv, bit);
+ ilk_enable_display_irq(dev_priv, bit);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return 0;
@@ -2669,10 +2736,9 @@ static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK;
- I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
- POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+ bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
return 0;
}
@@ -2699,7 +2765,7 @@ static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
DE_PIPE_VBLANK(pipe);
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- ironlake_disable_display_irq(dev_priv, bit);
+ ilk_disable_display_irq(dev_priv, bit);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
@@ -2720,9 +2786,7 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK;
- I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
- POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+ bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
@@ -2961,6 +3025,13 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
if (!i915.enable_hangcheck)
return;
+ /*
+ * The hangcheck work is synced during runtime suspend, we don't
+ * require a wakeref. TODO: instead of disabling the asserts make
+ * sure that we hold a reference when this work is running.
+ */
+ DISABLE_RPM_WAKEREF_ASSERTS(dev_priv);
+
for_each_ring(ring, dev_priv, i) {
u64 acthd;
u32 seqno;
@@ -3052,13 +3123,18 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
}
}
- if (rings_hung)
- return i915_handle_error(dev, true, "Ring hung");
+ if (rings_hung) {
+ i915_handle_error(dev, true, "Ring hung");
+ goto out;
+ }
if (busy_count)
/* Reset timer case chip hangs without another request
* being added */
i915_queue_hangcheck(dev);
+
+out:
+ ENABLE_RPM_WAKEREF_ASSERTS(dev_priv);
}
void i915_queue_hangcheck(struct drm_device *dev)
@@ -3451,7 +3527,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
* setup is guaranteed to run in single-threaded context. But we
* need it to make the assert_spin_locked happy. */
spin_lock_irq(&dev_priv->irq_lock);
- ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+ ilk_enable_display_irq(dev_priv, DE_PCU_EVENT);
spin_unlock_irq(&dev_priv->irq_lock);
}
@@ -3850,13 +3926,18 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
u16 flip_mask =
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+ irqreturn_t ret;
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
+ ret = IRQ_NONE;
iir = I915_READ16(IIR);
if (iir == 0)
- return IRQ_NONE;
+ goto out;
while (iir & ~flip_mask) {
/* Can't rely on pipestat interrupt bit in iir as it might
@@ -3869,7 +3950,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
for_each_pipe(dev_priv, pipe) {
- int reg = PIPESTAT(pipe);
+ i915_reg_t reg = PIPESTAT(pipe);
pipe_stats[pipe] = I915_READ(reg);
/*
@@ -3905,8 +3986,12 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
iir = new_iir;
}
+ ret = IRQ_HANDLED;
+
+out:
+ enable_rpm_wakeref_asserts(dev_priv);
- return IRQ_HANDLED;
+ return ret;
}
static void i8xx_irq_uninstall(struct drm_device * dev)
@@ -4035,6 +4120,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
iir = I915_READ(IIR);
do {
bool irq_received = (iir & ~flip_mask) != 0;
@@ -4050,7 +4138,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
for_each_pipe(dev_priv, pipe) {
- int reg = PIPESTAT(pipe);
+ i915_reg_t reg = PIPESTAT(pipe);
pipe_stats[pipe] = I915_READ(reg);
/* Clear the PIPE*STAT regs before the IIR */
@@ -4117,6 +4205,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
iir = new_iir;
} while (iir & ~flip_mask);
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
@@ -4256,6 +4346,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
+ /* IRQs are synced during runtime_suspend, we don't require a wakeref */
+ disable_rpm_wakeref_asserts(dev_priv);
+
iir = I915_READ(IIR);
for (;;) {
@@ -4272,7 +4365,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
for_each_pipe(dev_priv, pipe) {
- int reg = PIPESTAT(pipe);
+ i915_reg_t reg = PIPESTAT(pipe);
pipe_stats[pipe] = I915_READ(reg);
/*
@@ -4341,6 +4434,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
iir = new_iir;
}
+ enable_rpm_wakeref_asserts(dev_priv);
+
return ret;
}
@@ -4384,7 +4479,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
/* Let's track the enabled rps events */
- if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
+ if (IS_VALLEYVIEW(dev_priv))
/* WaGsvRC0ResidencyMethod:vlv */
dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
else
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 4be13a5eb932..835d6099c769 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -32,6 +32,7 @@ struct i915_params i915 __read_mostly = {
.panel_use_ssc = -1,
.vbt_sdvo_panel_type = -1,
.enable_rc6 = -1,
+ .enable_dc = -1,
.enable_fbc = -1,
.enable_execlists = -1,
.enable_hangcheck = true,
@@ -80,6 +81,11 @@ MODULE_PARM_DESC(enable_rc6,
"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
"default: -1 (use per-chip default)");
+module_param_named_unsafe(enable_dc, i915.enable_dc, int, 0400);
+MODULE_PARM_DESC(enable_dc,
+ "Enable power-saving display C-states. "
+ "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6)");
+
module_param_named_unsafe(enable_fbc, i915.enable_fbc, int, 0600);
MODULE_PARM_DESC(enable_fbc,
"Enable frame buffer compression for power savings "
@@ -112,7 +118,7 @@ MODULE_PARM_DESC(enable_hangcheck,
module_param_named_unsafe(enable_ppgtt, i915.enable_ppgtt, int, 0400);
MODULE_PARM_DESC(enable_ppgtt,
"Override PPGTT usage. "
- "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
+ "(-1=auto [default], 0=disabled, 1=aliasing, 2=full, 3=full with extended address space)");
module_param_named_unsafe(enable_execlists, i915.enable_execlists, int, 0400);
MODULE_PARM_DESC(enable_execlists,
@@ -126,7 +132,7 @@ module_param_named_unsafe(preliminary_hw_support, i915.preliminary_hw_support, i
MODULE_PARM_DESC(preliminary_hw_support,
"Enable preliminary hardware support.");
-module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0600);
+module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0400);
MODULE_PARM_DESC(disable_power_well,
"Disable display power wells when possible "
"(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)");
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index bc7b8faba84d..007ae83a4086 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -25,14 +25,43 @@
#ifndef _I915_REG_H_
#define _I915_REG_H_
+typedef struct {
+ uint32_t reg;
+} i915_reg_t;
+
+#define _MMIO(r) ((const i915_reg_t){ .reg = (r) })
+
+#define INVALID_MMIO_REG _MMIO(0)
+
+static inline uint32_t i915_mmio_reg_offset(i915_reg_t reg)
+{
+ return reg.reg;
+}
+
+static inline bool i915_mmio_reg_equal(i915_reg_t a, i915_reg_t b)
+{
+ return i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b);
+}
+
+static inline bool i915_mmio_reg_valid(i915_reg_t reg)
+{
+ return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG);
+}
+
#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
#define _PLANE(plane, a, b) _PIPE(plane, a, b)
-#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a)))
+#define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b)
+#define _TRANS(tran, a, b) ((a) + (tran)*((b)-(a)))
+#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
#define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
+#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
#define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \
(pipe) == PIPE_B ? (b) : (c))
+#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PIPE3(pipe, a, b, c))
#define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \
(port) == PORT_B ? (b) : (c))
+#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PORT3(pipe, a, b, c))
#define _MASKED_FIELD(mask, value) ({ \
if (__builtin_constant_p(mask)) \
@@ -105,14 +134,14 @@
#define GRDOM_RESET_STATUS (1<<1)
#define GRDOM_RESET_ENABLE (1<<0)
-#define ILK_GDSR (MCHBAR_MIRROR_BASE + 0x2ca4)
+#define ILK_GDSR _MMIO(MCHBAR_MIRROR_BASE + 0x2ca4)
#define ILK_GRDOM_FULL (0<<1)
#define ILK_GRDOM_RENDER (1<<1)
#define ILK_GRDOM_MEDIA (3<<1)
#define ILK_GRDOM_MASK (3<<1)
#define ILK_GRDOM_RESET_ENABLE (1<<0)
-#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */
+#define GEN6_MBCUNIT_SNPCR _MMIO(0x900c) /* for LLC config */
#define GEN6_MBC_SNPCR_SHIFT 21
#define GEN6_MBC_SNPCR_MASK (3<<21)
#define GEN6_MBC_SNPCR_MAX (0<<21)
@@ -120,31 +149,31 @@
#define GEN6_MBC_SNPCR_LOW (2<<21)
#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */
-#define VLV_G3DCTL 0x9024
-#define VLV_GSCKGCTL 0x9028
+#define VLV_G3DCTL _MMIO(0x9024)
+#define VLV_GSCKGCTL _MMIO(0x9028)
-#define GEN6_MBCTL 0x0907c
+#define GEN6_MBCTL _MMIO(0x0907c)
#define GEN6_MBCTL_ENABLE_BOOT_FETCH (1 << 4)
#define GEN6_MBCTL_CTX_FETCH_NEEDED (1 << 3)
#define GEN6_MBCTL_BME_UPDATE_ENABLE (1 << 2)
#define GEN6_MBCTL_MAE_UPDATE_ENABLE (1 << 1)
#define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0)
-#define GEN6_GDRST 0x941c
+#define GEN6_GDRST _MMIO(0x941c)
#define GEN6_GRDOM_FULL (1 << 0)
#define GEN6_GRDOM_RENDER (1 << 1)
#define GEN6_GRDOM_MEDIA (1 << 2)
#define GEN6_GRDOM_BLT (1 << 3)
-#define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228)
-#define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518)
-#define RING_PP_DIR_DCLV(ring) ((ring)->mmio_base+0x220)
+#define RING_PP_DIR_BASE(ring) _MMIO((ring)->mmio_base+0x228)
+#define RING_PP_DIR_BASE_READ(ring) _MMIO((ring)->mmio_base+0x518)
+#define RING_PP_DIR_DCLV(ring) _MMIO((ring)->mmio_base+0x220)
#define PP_DIR_DCLV_2G 0xffffffff
-#define GEN8_RING_PDP_UDW(ring, n) ((ring)->mmio_base+0x270 + ((n) * 8 + 4))
-#define GEN8_RING_PDP_LDW(ring, n) ((ring)->mmio_base+0x270 + (n) * 8)
+#define GEN8_RING_PDP_UDW(ring, n) _MMIO((ring)->mmio_base+0x270 + (n) * 8 + 4)
+#define GEN8_RING_PDP_LDW(ring, n) _MMIO((ring)->mmio_base+0x270 + (n) * 8)
-#define GEN8_R_PWR_CLK_STATE 0x20C8
+#define GEN8_R_PWR_CLK_STATE _MMIO(0x20C8)
#define GEN8_RPCS_ENABLE (1 << 31)
#define GEN8_RPCS_S_CNT_ENABLE (1 << 18)
#define GEN8_RPCS_S_CNT_SHIFT 15
@@ -157,7 +186,7 @@
#define GEN8_RPCS_EU_MIN_SHIFT 0
#define GEN8_RPCS_EU_MIN_MASK (0xf << GEN8_RPCS_EU_MIN_SHIFT)
-#define GAM_ECOCHK 0x4090
+#define GAM_ECOCHK _MMIO(0x4090)
#define BDW_DISABLE_HDC_INVALIDATION (1<<25)
#define ECOCHK_SNB_BIT (1<<10)
#define ECOCHK_DIS_TLB (1<<8)
@@ -170,15 +199,15 @@
#define ECOCHK_PPGTT_WT_HSW (0x2<<3)
#define ECOCHK_PPGTT_WB_HSW (0x3<<3)
-#define GAC_ECO_BITS 0x14090
+#define GAC_ECO_BITS _MMIO(0x14090)
#define ECOBITS_SNB_BIT (1<<13)
#define ECOBITS_PPGTT_CACHE64B (3<<8)
#define ECOBITS_PPGTT_CACHE4B (0<<8)
-#define GAB_CTL 0x24000
+#define GAB_CTL _MMIO(0x24000)
#define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8)
-#define GEN6_STOLEN_RESERVED 0x1082C0
+#define GEN6_STOLEN_RESERVED _MMIO(0x1082C0)
#define GEN6_STOLEN_RESERVED_ADDR_MASK (0xFFF << 20)
#define GEN7_STOLEN_RESERVED_ADDR_MASK (0x3FFF << 18)
#define GEN6_STOLEN_RESERVED_SIZE_MASK (3 << 4)
@@ -200,6 +229,7 @@
#define VGA_ST01_MDA 0x3ba
#define VGA_ST01_CGA 0x3da
+#define _VGA_MSR_WRITE _MMIO(0x3c2)
#define VGA_MSR_WRITE 0x3c2
#define VGA_MSR_READ 0x3cc
#define VGA_MSR_MEM_EN (1<<1)
@@ -377,10 +407,12 @@
#define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1)
#define MI_BATCH_RESOURCE_STREAMER (1<<10)
-#define MI_PREDICATE_SRC0 (0x2400)
-#define MI_PREDICATE_SRC1 (0x2408)
+#define MI_PREDICATE_SRC0 _MMIO(0x2400)
+#define MI_PREDICATE_SRC0_UDW _MMIO(0x2400 + 4)
+#define MI_PREDICATE_SRC1 _MMIO(0x2408)
+#define MI_PREDICATE_SRC1_UDW _MMIO(0x2408 + 4)
-#define MI_PREDICATE_RESULT_2 (0x2214)
+#define MI_PREDICATE_RESULT_2 _MMIO(0x2214)
#define LOWER_SLICE_ENABLED (1<<0)
#define LOWER_SLICE_DISABLED (0<<0)
@@ -509,49 +541,61 @@
/*
* Registers used only by the command parser
*/
-#define BCS_SWCTRL 0x22200
-
-#define GPGPU_THREADS_DISPATCHED 0x2290
-#define HS_INVOCATION_COUNT 0x2300
-#define DS_INVOCATION_COUNT 0x2308
-#define IA_VERTICES_COUNT 0x2310
-#define IA_PRIMITIVES_COUNT 0x2318
-#define VS_INVOCATION_COUNT 0x2320
-#define GS_INVOCATION_COUNT 0x2328
-#define GS_PRIMITIVES_COUNT 0x2330
-#define CL_INVOCATION_COUNT 0x2338
-#define CL_PRIMITIVES_COUNT 0x2340
-#define PS_INVOCATION_COUNT 0x2348
-#define PS_DEPTH_COUNT 0x2350
+#define BCS_SWCTRL _MMIO(0x22200)
+
+#define GPGPU_THREADS_DISPATCHED _MMIO(0x2290)
+#define GPGPU_THREADS_DISPATCHED_UDW _MMIO(0x2290 + 4)
+#define HS_INVOCATION_COUNT _MMIO(0x2300)
+#define HS_INVOCATION_COUNT_UDW _MMIO(0x2300 + 4)
+#define DS_INVOCATION_COUNT _MMIO(0x2308)
+#define DS_INVOCATION_COUNT_UDW _MMIO(0x2308 + 4)
+#define IA_VERTICES_COUNT _MMIO(0x2310)
+#define IA_VERTICES_COUNT_UDW _MMIO(0x2310 + 4)
+#define IA_PRIMITIVES_COUNT _MMIO(0x2318)
+#define IA_PRIMITIVES_COUNT_UDW _MMIO(0x2318 + 4)
+#define VS_INVOCATION_COUNT _MMIO(0x2320)
+#define VS_INVOCATION_COUNT_UDW _MMIO(0x2320 + 4)
+#define GS_INVOCATION_COUNT _MMIO(0x2328)
+#define GS_INVOCATION_COUNT_UDW _MMIO(0x2328 + 4)
+#define GS_PRIMITIVES_COUNT _MMIO(0x2330)
+#define GS_PRIMITIVES_COUNT_UDW _MMIO(0x2330 + 4)
+#define CL_INVOCATION_COUNT _MMIO(0x2338)
+#define CL_INVOCATION_COUNT_UDW _MMIO(0x2338 + 4)
+#define CL_PRIMITIVES_COUNT _MMIO(0x2340)
+#define CL_PRIMITIVES_COUNT_UDW _MMIO(0x2340 + 4)
+#define PS_INVOCATION_COUNT _MMIO(0x2348)
+#define PS_INVOCATION_COUNT_UDW _MMIO(0x2348 + 4)
+#define PS_DEPTH_COUNT _MMIO(0x2350)
+#define PS_DEPTH_COUNT_UDW _MMIO(0x2350 + 4)
/* There are the 4 64-bit counter registers, one for each stream output */
-#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8)
+#define GEN7_SO_NUM_PRIMS_WRITTEN(n) _MMIO(0x5200 + (n) * 8)
+#define GEN7_SO_NUM_PRIMS_WRITTEN_UDW(n) _MMIO(0x5200 + (n) * 8 + 4)
-#define GEN7_SO_PRIM_STORAGE_NEEDED(n) (0x5240 + (n) * 8)
+#define GEN7_SO_PRIM_STORAGE_NEEDED(n) _MMIO(0x5240 + (n) * 8)
+#define GEN7_SO_PRIM_STORAGE_NEEDED_UDW(n) _MMIO(0x5240 + (n) * 8 + 4)
-#define GEN7_3DPRIM_END_OFFSET 0x2420
-#define GEN7_3DPRIM_START_VERTEX 0x2430
-#define GEN7_3DPRIM_VERTEX_COUNT 0x2434
-#define GEN7_3DPRIM_INSTANCE_COUNT 0x2438
-#define GEN7_3DPRIM_START_INSTANCE 0x243C
-#define GEN7_3DPRIM_BASE_VERTEX 0x2440
+#define GEN7_3DPRIM_END_OFFSET _MMIO(0x2420)
+#define GEN7_3DPRIM_START_VERTEX _MMIO(0x2430)
+#define GEN7_3DPRIM_VERTEX_COUNT _MMIO(0x2434)
+#define GEN7_3DPRIM_INSTANCE_COUNT _MMIO(0x2438)
+#define GEN7_3DPRIM_START_INSTANCE _MMIO(0x243C)
+#define GEN7_3DPRIM_BASE_VERTEX _MMIO(0x2440)
-#define GEN7_GPGPU_DISPATCHDIMX 0x2500
-#define GEN7_GPGPU_DISPATCHDIMY 0x2504
-#define GEN7_GPGPU_DISPATCHDIMZ 0x2508
+#define GEN7_GPGPU_DISPATCHDIMX _MMIO(0x2500)
+#define GEN7_GPGPU_DISPATCHDIMY _MMIO(0x2504)
+#define GEN7_GPGPU_DISPATCHDIMZ _MMIO(0x2508)
-#define OACONTROL 0x2360
+#define OACONTROL _MMIO(0x2360)
#define _GEN7_PIPEA_DE_LOAD_SL 0x70068
#define _GEN7_PIPEB_DE_LOAD_SL 0x71068
-#define GEN7_PIPE_DE_LOAD_SL(pipe) _PIPE(pipe, \
- _GEN7_PIPEA_DE_LOAD_SL, \
- _GEN7_PIPEB_DE_LOAD_SL)
+#define GEN7_PIPE_DE_LOAD_SL(pipe) _MMIO_PIPE(pipe, _GEN7_PIPEA_DE_LOAD_SL, _GEN7_PIPEB_DE_LOAD_SL)
/*
* Reset registers
*/
-#define DEBUG_RESET_I830 0x6070
+#define DEBUG_RESET_I830 _MMIO(0x6070)
#define DEBUG_RESET_FULL (1<<7)
#define DEBUG_RESET_RENDER (1<<8)
#define DEBUG_RESET_DISPLAY (1<<9)
@@ -559,7 +603,7 @@
/*
* IOSF sideband
*/
-#define VLV_IOSF_DOORBELL_REQ (VLV_DISPLAY_BASE + 0x2100)
+#define VLV_IOSF_DOORBELL_REQ _MMIO(VLV_DISPLAY_BASE + 0x2100)
#define IOSF_DEVFN_SHIFT 24
#define IOSF_OPCODE_SHIFT 16
#define IOSF_PORT_SHIFT 8
@@ -576,8 +620,8 @@
#define IOSF_PORT_CCU 0xA9
#define IOSF_PORT_GPS_CORE 0x48
#define IOSF_PORT_FLISDSI 0x1B
-#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104)
-#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108)
+#define VLV_IOSF_DATA _MMIO(VLV_DISPLAY_BASE + 0x2104)
+#define VLV_IOSF_ADDR _MMIO(VLV_DISPLAY_BASE + 0x2108)
/* See configdb bunit SB addr map */
#define BUNIT_REG_BISOC 0x11
@@ -609,6 +653,7 @@
/* See the PUNIT HAS v0.8 for the below bits */
enum punit_power_well {
+ /* These numbers are fixed and must match the position of the pw bits */
PUNIT_POWER_WELL_RENDER = 0,
PUNIT_POWER_WELL_MEDIA = 1,
PUNIT_POWER_WELL_DISP2D = 3,
@@ -621,10 +666,12 @@ enum punit_power_well {
PUNIT_POWER_WELL_DPIO_RX1 = 11,
PUNIT_POWER_WELL_DPIO_CMN_D = 12,
- PUNIT_POWER_WELL_NUM,
+ /* Not actual bit groups. Used as IDs for lookup_power_well() */
+ PUNIT_POWER_WELL_ALWAYS_ON,
};
enum skl_disp_power_wells {
+ /* These numbers are fixed and must match the position of the pw bits */
SKL_DISP_PW_MISC_IO,
SKL_DISP_PW_DDI_A_E,
SKL_DISP_PW_DDI_B,
@@ -632,6 +679,10 @@ enum skl_disp_power_wells {
SKL_DISP_PW_DDI_D,
SKL_DISP_PW_1 = 14,
SKL_DISP_PW_2,
+
+ /* Not actual bit groups. Used as IDs for lookup_power_well() */
+ SKL_DISP_PW_ALWAYS_ON,
+ SKL_DISP_PW_DC_OFF,
};
#define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2))
@@ -804,35 +855,35 @@ enum skl_disp_power_wells {
*
* Note: DDI0 is digital port B, DD1 is digital port C, and DDI2 is
* digital port D (CHV) or port A (BXT).
- */
-/*
- * Dual channel PHY (VLV/CHV/BXT)
- * ---------------------------------
- * | CH0 | CH1 |
- * | CMN/PLL/REF | CMN/PLL/REF |
- * |---------------|---------------| Display PHY
- * | PCS01 | PCS23 | PCS01 | PCS23 |
- * |-------|-------|-------|-------|
- * |TX0|TX1|TX2|TX3|TX0|TX1|TX2|TX3|
- * ---------------------------------
- * | DDI0 | DDI1 | DP/HDMI ports
- * ---------------------------------
*
- * Single channel PHY (CHV/BXT)
- * -----------------
- * | CH0 |
- * | CMN/PLL/REF |
- * |---------------| Display PHY
- * | PCS01 | PCS23 |
- * |-------|-------|
- * |TX0|TX1|TX2|TX3|
- * -----------------
- * | DDI2 | DP/HDMI port
- * -----------------
+ *
+ * Dual channel PHY (VLV/CHV/BXT)
+ * ---------------------------------
+ * | CH0 | CH1 |
+ * | CMN/PLL/REF | CMN/PLL/REF |
+ * |---------------|---------------| Display PHY
+ * | PCS01 | PCS23 | PCS01 | PCS23 |
+ * |-------|-------|-------|-------|
+ * |TX0|TX1|TX2|TX3|TX0|TX1|TX2|TX3|
+ * ---------------------------------
+ * | DDI0 | DDI1 | DP/HDMI ports
+ * ---------------------------------
+ *
+ * Single channel PHY (CHV/BXT)
+ * -----------------
+ * | CH0 |
+ * | CMN/PLL/REF |
+ * |---------------| Display PHY
+ * | PCS01 | PCS23 |
+ * |-------|-------|
+ * |TX0|TX1|TX2|TX3|
+ * -----------------
+ * | DDI2 | DP/HDMI port
+ * -----------------
*/
#define DPIO_DEVFN 0
-#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110)
+#define DPIO_CTL _MMIO(VLV_DISPLAY_BASE + 0x2110)
#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */
#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */
#define DPIO_SFR_BYPASS (1<<1)
@@ -1185,9 +1236,9 @@ enum skl_disp_power_wells {
#define DPIO_UPAR_SHIFT 30
/* BXT PHY registers */
-#define _BXT_PHY(phy, a, b) _PIPE((phy), (a), (b))
+#define _BXT_PHY(phy, a, b) _MMIO_PIPE((phy), (a), (b))
-#define BXT_P_CR_GT_DISP_PWRON 0x138090
+#define BXT_P_CR_GT_DISP_PWRON _MMIO(0x138090)
#define GT_DISPLAY_POWER_ON(phy) (1 << (phy))
#define _PHY_CTL_FAMILY_EDP 0x64C80
@@ -1203,7 +1254,7 @@ enum skl_disp_power_wells {
#define PORT_PLL_ENABLE (1 << 31)
#define PORT_PLL_LOCK (1 << 30)
#define PORT_PLL_REF_SEL (1 << 27)
-#define BXT_PORT_PLL_ENABLE(port) _PORT(port, _PORT_PLL_A, _PORT_PLL_B)
+#define BXT_PORT_PLL_ENABLE(port) _MMIO_PORT(port, _PORT_PLL_A, _PORT_PLL_B)
#define _PORT_PLL_EBB_0_A 0x162034
#define _PORT_PLL_EBB_0_B 0x6C034
@@ -1214,7 +1265,7 @@ enum skl_disp_power_wells {
#define PORT_PLL_P2_SHIFT 8
#define PORT_PLL_P2_MASK (0x1f << PORT_PLL_P2_SHIFT)
#define PORT_PLL_P2(x) ((x) << PORT_PLL_P2_SHIFT)
-#define BXT_PORT_PLL_EBB_0(port) _PORT3(port, _PORT_PLL_EBB_0_A, \
+#define BXT_PORT_PLL_EBB_0(port) _MMIO_PORT3(port, _PORT_PLL_EBB_0_A, \
_PORT_PLL_EBB_0_B, \
_PORT_PLL_EBB_0_C)
@@ -1223,7 +1274,7 @@ enum skl_disp_power_wells {
#define _PORT_PLL_EBB_4_C 0x6C344
#define PORT_PLL_10BIT_CLK_ENABLE (1 << 13)
#define PORT_PLL_RECALIBRATE (1 << 14)
-#define BXT_PORT_PLL_EBB_4(port) _PORT3(port, _PORT_PLL_EBB_4_A, \
+#define BXT_PORT_PLL_EBB_4(port) _MMIO_PORT3(port, _PORT_PLL_EBB_4_A, \
_PORT_PLL_EBB_4_B, \
_PORT_PLL_EBB_4_C)
@@ -1259,7 +1310,7 @@ enum skl_disp_power_wells {
#define _PORT_PLL_BASE(port) _PORT3(port, _PORT_PLL_0_A, \
_PORT_PLL_0_B, \
_PORT_PLL_0_C)
-#define BXT_PORT_PLL(port, idx) (_PORT_PLL_BASE(port) + (idx) * 4)
+#define BXT_PORT_PLL(port, idx) _MMIO(_PORT_PLL_BASE(port) + (idx) * 4)
/* BXT PHY common lane registers */
#define _PORT_CL1CM_DW0_A 0x162000
@@ -1297,7 +1348,7 @@ enum skl_disp_power_wells {
_PORT_CL1CM_DW30_A)
/* Defined for PHY0 only */
-#define BXT_PORT_CL2CM_DW6_BC 0x6C358
+#define BXT_PORT_CL2CM_DW6_BC _MMIO(0x6C358)
#define DW6_OLDO_DYN_PWR_DOWN_EN (1 << 28)
/* BXT PHY Ref registers */
@@ -1337,10 +1388,10 @@ enum skl_disp_power_wells {
#define _PORT_PCS_DW10_GRP_A 0x162C28
#define _PORT_PCS_DW10_GRP_B 0x6CC28
#define _PORT_PCS_DW10_GRP_C 0x6CE28
-#define BXT_PORT_PCS_DW10_LN01(port) _PORT3(port, _PORT_PCS_DW10_LN01_A, \
+#define BXT_PORT_PCS_DW10_LN01(port) _MMIO_PORT3(port, _PORT_PCS_DW10_LN01_A, \
_PORT_PCS_DW10_LN01_B, \
_PORT_PCS_DW10_LN01_C)
-#define BXT_PORT_PCS_DW10_GRP(port) _PORT3(port, _PORT_PCS_DW10_GRP_A, \
+#define BXT_PORT_PCS_DW10_GRP(port) _MMIO_PORT3(port, _PORT_PCS_DW10_GRP_A, \
_PORT_PCS_DW10_GRP_B, \
_PORT_PCS_DW10_GRP_C)
#define TX2_SWING_CALC_INIT (1 << 31)
@@ -1357,13 +1408,13 @@ enum skl_disp_power_wells {
#define _PORT_PCS_DW12_GRP_C 0x6CE30
#define LANESTAGGER_STRAP_OVRD (1 << 6)
#define LANE_STAGGER_MASK 0x1F
-#define BXT_PORT_PCS_DW12_LN01(port) _PORT3(port, _PORT_PCS_DW12_LN01_A, \
+#define BXT_PORT_PCS_DW12_LN01(port) _MMIO_PORT3(port, _PORT_PCS_DW12_LN01_A, \
_PORT_PCS_DW12_LN01_B, \
_PORT_PCS_DW12_LN01_C)
-#define BXT_PORT_PCS_DW12_LN23(port) _PORT3(port, _PORT_PCS_DW12_LN23_A, \
+#define BXT_PORT_PCS_DW12_LN23(port) _MMIO_PORT3(port, _PORT_PCS_DW12_LN23_A, \
_PORT_PCS_DW12_LN23_B, \
_PORT_PCS_DW12_LN23_C)
-#define BXT_PORT_PCS_DW12_GRP(port) _PORT3(port, _PORT_PCS_DW12_GRP_A, \
+#define BXT_PORT_PCS_DW12_GRP(port) _MMIO_PORT3(port, _PORT_PCS_DW12_GRP_A, \
_PORT_PCS_DW12_GRP_B, \
_PORT_PCS_DW12_GRP_C)
@@ -1377,10 +1428,10 @@ enum skl_disp_power_wells {
#define _PORT_TX_DW2_GRP_A 0x162D08
#define _PORT_TX_DW2_GRP_B 0x6CD08
#define _PORT_TX_DW2_GRP_C 0x6CF08
-#define BXT_PORT_TX_DW2_GRP(port) _PORT3(port, _PORT_TX_DW2_GRP_A, \
+#define BXT_PORT_TX_DW2_GRP(port) _MMIO_PORT3(port, _PORT_TX_DW2_GRP_A, \
_PORT_TX_DW2_GRP_B, \
_PORT_TX_DW2_GRP_C)
-#define BXT_PORT_TX_DW2_LN0(port) _PORT3(port, _PORT_TX_DW2_LN0_A, \
+#define BXT_PORT_TX_DW2_LN0(port) _MMIO_PORT3(port, _PORT_TX_DW2_LN0_A, \
_PORT_TX_DW2_LN0_B, \
_PORT_TX_DW2_LN0_C)
#define MARGIN_000_SHIFT 16
@@ -1394,10 +1445,10 @@ enum skl_disp_power_wells {
#define _PORT_TX_DW3_GRP_A 0x162D0C
#define _PORT_TX_DW3_GRP_B 0x6CD0C
#define _PORT_TX_DW3_GRP_C 0x6CF0C
-#define BXT_PORT_TX_DW3_GRP(port) _PORT3(port, _PORT_TX_DW3_GRP_A, \
+#define BXT_PORT_TX_DW3_GRP(port) _MMIO_PORT3(port, _PORT_TX_DW3_GRP_A, \
_PORT_TX_DW3_GRP_B, \
_PORT_TX_DW3_GRP_C)
-#define BXT_PORT_TX_DW3_LN0(port) _PORT3(port, _PORT_TX_DW3_LN0_A, \
+#define BXT_PORT_TX_DW3_LN0(port) _MMIO_PORT3(port, _PORT_TX_DW3_LN0_A, \
_PORT_TX_DW3_LN0_B, \
_PORT_TX_DW3_LN0_C)
#define SCALE_DCOMP_METHOD (1 << 26)
@@ -1409,10 +1460,10 @@ enum skl_disp_power_wells {
#define _PORT_TX_DW4_GRP_A 0x162D10
#define _PORT_TX_DW4_GRP_B 0x6CD10
#define _PORT_TX_DW4_GRP_C 0x6CF10
-#define BXT_PORT_TX_DW4_LN0(port) _PORT3(port, _PORT_TX_DW4_LN0_A, \
+#define BXT_PORT_TX_DW4_LN0(port) _MMIO_PORT3(port, _PORT_TX_DW4_LN0_A, \
_PORT_TX_DW4_LN0_B, \
_PORT_TX_DW4_LN0_C)
-#define BXT_PORT_TX_DW4_GRP(port) _PORT3(port, _PORT_TX_DW4_GRP_A, \
+#define BXT_PORT_TX_DW4_GRP(port) _MMIO_PORT3(port, _PORT_TX_DW4_GRP_A, \
_PORT_TX_DW4_GRP_B, \
_PORT_TX_DW4_GRP_C)
#define DEEMPH_SHIFT 24
@@ -1423,17 +1474,17 @@ enum skl_disp_power_wells {
#define _PORT_TX_DW14_LN0_C 0x6C938
#define LATENCY_OPTIM_SHIFT 30
#define LATENCY_OPTIM (1 << LATENCY_OPTIM_SHIFT)
-#define BXT_PORT_TX_DW14_LN(port, lane) (_PORT3((port), _PORT_TX_DW14_LN0_A, \
+#define BXT_PORT_TX_DW14_LN(port, lane) _MMIO(_PORT3((port), _PORT_TX_DW14_LN0_A, \
_PORT_TX_DW14_LN0_B, \
_PORT_TX_DW14_LN0_C) + \
_BXT_LANE_OFFSET(lane))
/* UAIMI scratch pad register 1 */
-#define UAIMI_SPR1 0x4F074
+#define UAIMI_SPR1 _MMIO(0x4F074)
/* SKL VccIO mask */
#define SKL_VCCIO_MASK 0x1
/* SKL balance leg register */
-#define DISPIO_CR_TX_BMU_CR0 0x6C00C
+#define DISPIO_CR_TX_BMU_CR0 _MMIO(0x6C00C)
/* I_boost values */
#define BALANCE_LEG_SHIFT(port) (8+3*(port))
#define BALANCE_LEG_MASK(port) (7<<(8+3*(port)))
@@ -1450,7 +1501,7 @@ enum skl_disp_power_wells {
* [0-15] @ 0x100000 gen6,vlv,chv
* [0-31] @ 0x100000 gen7+
*/
-#define FENCE_REG(i) (0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4)
+#define FENCE_REG(i) _MMIO(0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4)
#define I830_FENCE_START_MASK 0x07f80000
#define I830_FENCE_TILING_Y_SHIFT 12
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
@@ -1463,21 +1514,21 @@ enum skl_disp_power_wells {
#define I915_FENCE_START_MASK 0x0ff00000
#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8)
-#define FENCE_REG_965_LO(i) (0x03000 + (i) * 8)
-#define FENCE_REG_965_HI(i) (0x03000 + (i) * 8 + 4)
+#define FENCE_REG_965_LO(i) _MMIO(0x03000 + (i) * 8)
+#define FENCE_REG_965_HI(i) _MMIO(0x03000 + (i) * 8 + 4)
#define I965_FENCE_PITCH_SHIFT 2
#define I965_FENCE_TILING_Y_SHIFT 1
#define I965_FENCE_REG_VALID (1<<0)
#define I965_FENCE_MAX_PITCH_VAL 0x0400
-#define FENCE_REG_GEN6_LO(i) (0x100000 + (i) * 8)
-#define FENCE_REG_GEN6_HI(i) (0x100000 + (i) * 8 + 4)
+#define FENCE_REG_GEN6_LO(i) _MMIO(0x100000 + (i) * 8)
+#define FENCE_REG_GEN6_HI(i) _MMIO(0x100000 + (i) * 8 + 4)
#define GEN6_FENCE_PITCH_SHIFT 32
#define GEN7_FENCE_MAX_PITCH_VAL 0x0800
/* control register for cpu gtt access */
-#define TILECTL 0x101000
+#define TILECTL _MMIO(0x101000)
#define TILECTL_SWZCTL (1 << 0)
#define TILECTL_TLBPF (1 << 1)
#define TILECTL_TLB_PREFETCH_DIS (1 << 2)
@@ -1486,30 +1537,30 @@ enum skl_disp_power_wells {
/*
* Instruction and interrupt control regs
*/
-#define PGTBL_CTL 0x02020
+#define PGTBL_CTL _MMIO(0x02020)
#define PGTBL_ADDRESS_LO_MASK 0xfffff000 /* bits [31:12] */
#define PGTBL_ADDRESS_HI_MASK 0x000000f0 /* bits [35:32] (gen4) */
-#define PGTBL_ER 0x02024
-#define PRB0_BASE (0x2030-0x30)
-#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */
-#define PRB2_BASE (0x2050-0x30) /* gen3 */
-#define SRB0_BASE (0x2100-0x30) /* gen2 */
-#define SRB1_BASE (0x2110-0x30) /* gen2 */
-#define SRB2_BASE (0x2120-0x30) /* 830 */
-#define SRB3_BASE (0x2130-0x30) /* 830 */
+#define PGTBL_ER _MMIO(0x02024)
+#define PRB0_BASE (0x2030-0x30)
+#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */
+#define PRB2_BASE (0x2050-0x30) /* gen3 */
+#define SRB0_BASE (0x2100-0x30) /* gen2 */
+#define SRB1_BASE (0x2110-0x30) /* gen2 */
+#define SRB2_BASE (0x2120-0x30) /* 830 */
+#define SRB3_BASE (0x2130-0x30) /* 830 */
#define RENDER_RING_BASE 0x02000
#define BSD_RING_BASE 0x04000
#define GEN6_BSD_RING_BASE 0x12000
#define GEN8_BSD2_RING_BASE 0x1c000
#define VEBOX_RING_BASE 0x1a000
#define BLT_RING_BASE 0x22000
-#define RING_TAIL(base) ((base)+0x30)
-#define RING_HEAD(base) ((base)+0x34)
-#define RING_START(base) ((base)+0x38)
-#define RING_CTL(base) ((base)+0x3c)
-#define RING_SYNC_0(base) ((base)+0x40)
-#define RING_SYNC_1(base) ((base)+0x44)
-#define RING_SYNC_2(base) ((base)+0x48)
+#define RING_TAIL(base) _MMIO((base)+0x30)
+#define RING_HEAD(base) _MMIO((base)+0x34)
+#define RING_START(base) _MMIO((base)+0x38)
+#define RING_CTL(base) _MMIO((base)+0x3c)
+#define RING_SYNC_0(base) _MMIO((base)+0x40)
+#define RING_SYNC_1(base) _MMIO((base)+0x44)
+#define RING_SYNC_2(base) _MMIO((base)+0x48)
#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE))
#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE))
#define GEN6_RVESYNC (RING_SYNC_2(RENDER_RING_BASE))
@@ -1522,51 +1573,52 @@ enum skl_disp_power_wells {
#define GEN6_VEBSYNC (RING_SYNC_0(VEBOX_RING_BASE))
#define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE))
#define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE))
-#define GEN6_NOSYNC 0
-#define RING_PSMI_CTL(base) ((base)+0x50)
-#define RING_MAX_IDLE(base) ((base)+0x54)
-#define RING_HWS_PGA(base) ((base)+0x80)
-#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
-#define RING_RESET_CTL(base) ((base)+0xd0)
+#define GEN6_NOSYNC INVALID_MMIO_REG
+#define RING_PSMI_CTL(base) _MMIO((base)+0x50)
+#define RING_MAX_IDLE(base) _MMIO((base)+0x54)
+#define RING_HWS_PGA(base) _MMIO((base)+0x80)
+#define RING_HWS_PGA_GEN6(base) _MMIO((base)+0x2080)
+#define RING_RESET_CTL(base) _MMIO((base)+0xd0)
#define RESET_CTL_REQUEST_RESET (1 << 0)
#define RESET_CTL_READY_TO_RESET (1 << 1)
-#define HSW_GTT_CACHE_EN 0x4024
+#define HSW_GTT_CACHE_EN _MMIO(0x4024)
#define GTT_CACHE_EN_ALL 0xF0007FFF
-#define GEN7_WR_WATERMARK 0x4028
-#define GEN7_GFX_PRIO_CTRL 0x402C
-#define ARB_MODE 0x4030
+#define GEN7_WR_WATERMARK _MMIO(0x4028)
+#define GEN7_GFX_PRIO_CTRL _MMIO(0x402C)
+#define ARB_MODE _MMIO(0x4030)
#define ARB_MODE_SWIZZLE_SNB (1<<4)
#define ARB_MODE_SWIZZLE_IVB (1<<5)
-#define GEN7_GFX_PEND_TLB0 0x4034
-#define GEN7_GFX_PEND_TLB1 0x4038
+#define GEN7_GFX_PEND_TLB0 _MMIO(0x4034)
+#define GEN7_GFX_PEND_TLB1 _MMIO(0x4038)
/* L3, CVS, ZTLB, RCC, CASC LRA min, max values */
-#define GEN7_LRA_LIMITS(i) (0x403C + (i) * 4)
+#define GEN7_LRA_LIMITS(i) _MMIO(0x403C + (i) * 4)
#define GEN7_LRA_LIMITS_REG_NUM 13
-#define GEN7_MEDIA_MAX_REQ_COUNT 0x4070
-#define GEN7_GFX_MAX_REQ_COUNT 0x4074
+#define GEN7_MEDIA_MAX_REQ_COUNT _MMIO(0x4070)
+#define GEN7_GFX_MAX_REQ_COUNT _MMIO(0x4074)
-#define GAMTARBMODE 0x04a08
+#define GAMTARBMODE _MMIO(0x04a08)
#define ARB_MODE_BWGTLB_DISABLE (1<<9)
#define ARB_MODE_SWIZZLE_BDW (1<<1)
-#define RENDER_HWS_PGA_GEN7 (0x04080)
-#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id)
+#define RENDER_HWS_PGA_GEN7 _MMIO(0x04080)
+#define RING_FAULT_REG(ring) _MMIO(0x4094 + 0x100*(ring)->id)
#define RING_FAULT_GTTSEL_MASK (1<<11)
#define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff)
#define RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3)
#define RING_FAULT_VALID (1<<0)
-#define DONE_REG 0x40b0
-#define GEN8_PRIVATE_PAT_LO 0x40e0
-#define GEN8_PRIVATE_PAT_HI (0x40e0 + 4)
-#define BSD_HWS_PGA_GEN7 (0x04180)
-#define BLT_HWS_PGA_GEN7 (0x04280)
-#define VEBOX_HWS_PGA_GEN7 (0x04380)
-#define RING_ACTHD(base) ((base)+0x74)
-#define RING_ACTHD_UDW(base) ((base)+0x5c)
-#define RING_NOPID(base) ((base)+0x94)
-#define RING_IMR(base) ((base)+0xa8)
-#define RING_HWSTAM(base) ((base)+0x98)
-#define RING_TIMESTAMP(base) ((base)+0x358)
+#define DONE_REG _MMIO(0x40b0)
+#define GEN8_PRIVATE_PAT_LO _MMIO(0x40e0)
+#define GEN8_PRIVATE_PAT_HI _MMIO(0x40e0 + 4)
+#define BSD_HWS_PGA_GEN7 _MMIO(0x04180)
+#define BLT_HWS_PGA_GEN7 _MMIO(0x04280)
+#define VEBOX_HWS_PGA_GEN7 _MMIO(0x04380)
+#define RING_ACTHD(base) _MMIO((base)+0x74)
+#define RING_ACTHD_UDW(base) _MMIO((base)+0x5c)
+#define RING_NOPID(base) _MMIO((base)+0x94)
+#define RING_IMR(base) _MMIO((base)+0xa8)
+#define RING_HWSTAM(base) _MMIO((base)+0x98)
+#define RING_TIMESTAMP(base) _MMIO((base)+0x358)
+#define RING_TIMESTAMP_UDW(base) _MMIO((base)+0x358 + 4)
#define TAIL_ADDR 0x001FFFF8
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
@@ -1583,57 +1635,65 @@ enum skl_disp_power_wells {
#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */
#define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */
-#define GEN7_TLB_RD_ADDR 0x4700
+#define GEN7_TLB_RD_ADDR _MMIO(0x4700)
#if 0
-#define PRB0_TAIL 0x02030
-#define PRB0_HEAD 0x02034
-#define PRB0_START 0x02038
-#define PRB0_CTL 0x0203c
-#define PRB1_TAIL 0x02040 /* 915+ only */
-#define PRB1_HEAD 0x02044 /* 915+ only */
-#define PRB1_START 0x02048 /* 915+ only */
-#define PRB1_CTL 0x0204c /* 915+ only */
+#define PRB0_TAIL _MMIO(0x2030)
+#define PRB0_HEAD _MMIO(0x2034)
+#define PRB0_START _MMIO(0x2038)
+#define PRB0_CTL _MMIO(0x203c)
+#define PRB1_TAIL _MMIO(0x2040) /* 915+ only */
+#define PRB1_HEAD _MMIO(0x2044) /* 915+ only */
+#define PRB1_START _MMIO(0x2048) /* 915+ only */
+#define PRB1_CTL _MMIO(0x204c) /* 915+ only */
#endif
-#define IPEIR_I965 0x02064
-#define IPEHR_I965 0x02068
-#define GEN7_SC_INSTDONE 0x07100
-#define GEN7_SAMPLER_INSTDONE 0x0e160
-#define GEN7_ROW_INSTDONE 0x0e164
+#define IPEIR_I965 _MMIO(0x2064)
+#define IPEHR_I965 _MMIO(0x2068)
+#define GEN7_SC_INSTDONE _MMIO(0x7100)
+#define GEN7_SAMPLER_INSTDONE _MMIO(0xe160)
+#define GEN7_ROW_INSTDONE _MMIO(0xe164)
#define I915_NUM_INSTDONE_REG 4
-#define RING_IPEIR(base) ((base)+0x64)
-#define RING_IPEHR(base) ((base)+0x68)
+#define RING_IPEIR(base) _MMIO((base)+0x64)
+#define RING_IPEHR(base) _MMIO((base)+0x68)
/*
* On GEN4, only the render ring INSTDONE exists and has a different
* layout than the GEN7+ version.
* The GEN2 counterpart of this register is GEN2_INSTDONE.
*/
-#define RING_INSTDONE(base) ((base)+0x6c)
-#define RING_INSTPS(base) ((base)+0x70)
-#define RING_DMA_FADD(base) ((base)+0x78)
-#define RING_DMA_FADD_UDW(base) ((base)+0x60) /* gen8+ */
-#define RING_INSTPM(base) ((base)+0xc0)
-#define RING_MI_MODE(base) ((base)+0x9c)
-#define INSTPS 0x02070 /* 965+ only */
-#define GEN4_INSTDONE1 0x0207c /* 965+ only, aka INSTDONE_2 on SNB */
-#define ACTHD_I965 0x02074
-#define HWS_PGA 0x02080
+#define RING_INSTDONE(base) _MMIO((base)+0x6c)
+#define RING_INSTPS(base) _MMIO((base)+0x70)
+#define RING_DMA_FADD(base) _MMIO((base)+0x78)
+#define RING_DMA_FADD_UDW(base) _MMIO((base)+0x60) /* gen8+ */
+#define RING_INSTPM(base) _MMIO((base)+0xc0)
+#define RING_MI_MODE(base) _MMIO((base)+0x9c)
+#define INSTPS _MMIO(0x2070) /* 965+ only */
+#define GEN4_INSTDONE1 _MMIO(0x207c) /* 965+ only, aka INSTDONE_2 on SNB */
+#define ACTHD_I965 _MMIO(0x2074)
+#define HWS_PGA _MMIO(0x2080)
#define HWS_ADDRESS_MASK 0xfffff000
#define HWS_START_ADDRESS_SHIFT 4
-#define PWRCTXA 0x2088 /* 965GM+ only */
+#define PWRCTXA _MMIO(0x2088) /* 965GM+ only */
#define PWRCTX_EN (1<<0)
-#define IPEIR 0x02088
-#define IPEHR 0x0208c
-#define GEN2_INSTDONE 0x02090
-#define NOPID 0x02094
-#define HWSTAM 0x02098
-#define DMA_FADD_I8XX 0x020d0
-#define RING_BBSTATE(base) ((base)+0x110)
-#define RING_BBADDR(base) ((base)+0x140)
-#define RING_BBADDR_UDW(base) ((base)+0x168) /* gen8+ */
-
-#define ERROR_GEN6 0x040a0
-#define GEN7_ERR_INT 0x44040
+#define IPEIR _MMIO(0x2088)
+#define IPEHR _MMIO(0x208c)
+#define GEN2_INSTDONE _MMIO(0x2090)
+#define NOPID _MMIO(0x2094)
+#define HWSTAM _MMIO(0x2098)
+#define DMA_FADD_I8XX _MMIO(0x20d0)
+#define RING_BBSTATE(base) _MMIO((base)+0x110)
+#define RING_BB_PPGTT (1 << 5)
+#define RING_SBBADDR(base) _MMIO((base)+0x114) /* hsw+ */
+#define RING_SBBSTATE(base) _MMIO((base)+0x118) /* hsw+ */
+#define RING_SBBADDR_UDW(base) _MMIO((base)+0x11c) /* gen8+ */
+#define RING_BBADDR(base) _MMIO((base)+0x140)
+#define RING_BBADDR_UDW(base) _MMIO((base)+0x168) /* gen8+ */
+#define RING_BB_PER_CTX_PTR(base) _MMIO((base)+0x1c0) /* gen8+ */
+#define RING_INDIRECT_CTX(base) _MMIO((base)+0x1c4) /* gen8+ */
+#define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base)+0x1c8) /* gen8+ */
+#define RING_CTX_TIMESTAMP(base) _MMIO((base)+0x3a8) /* gen8+ */
+
+#define ERROR_GEN6 _MMIO(0x40a0)
+#define GEN7_ERR_INT _MMIO(0x44040)
#define ERR_INT_POISON (1<<31)
#define ERR_INT_MMIO_UNCLAIMED (1<<13)
#define ERR_INT_PIPE_CRC_DONE_C (1<<8)
@@ -1645,13 +1705,13 @@ enum skl_disp_power_wells {
#define ERR_INT_FIFO_UNDERRUN_A (1<<0)
#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<((pipe)*3))
-#define GEN8_FAULT_TLB_DATA0 0x04b10
-#define GEN8_FAULT_TLB_DATA1 0x04b14
+#define GEN8_FAULT_TLB_DATA0 _MMIO(0x4b10)
+#define GEN8_FAULT_TLB_DATA1 _MMIO(0x4b14)
-#define FPGA_DBG 0x42300
+#define FPGA_DBG _MMIO(0x42300)
#define FPGA_DBG_RM_NOCLAIM (1<<31)
-#define DERRMR 0x44050
+#define DERRMR _MMIO(0x44050)
/* Note that HBLANK events are reserved on bdw+ */
#define DERRMR_PIPEA_SCANLINE (1<<0)
#define DERRMR_PIPEA_PRI_FLIP_DONE (1<<1)
@@ -1675,29 +1735,29 @@ enum skl_disp_power_wells {
* for various sorts of correct behavior. The top 16 bits of each are
* the enables for writing to the corresponding low bit.
*/
-#define _3D_CHICKEN 0x02084
+#define _3D_CHICKEN _MMIO(0x2084)
#define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10)
-#define _3D_CHICKEN2 0x0208c
+#define _3D_CHICKEN2 _MMIO(0x208c)
/* Disables pipelining of read flushes past the SF-WIZ interface.
* Required on all Ironlake steppings according to the B-Spec, but the
* particular danger of not doing so is not specified.
*/
# define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14)
-#define _3D_CHICKEN3 0x02090
+#define _3D_CHICKEN3 _MMIO(0x2090)
#define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10)
#define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5)
#define _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x) ((x)<<1) /* gen8+ */
#define _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH (1 << 1) /* gen6 */
-#define MI_MODE 0x0209c
+#define MI_MODE _MMIO(0x209c)
# define VS_TIMER_DISPATCH (1 << 6)
# define MI_FLUSH_ENABLE (1 << 12)
# define ASYNC_FLIP_PERF_DISABLE (1 << 14)
# define MODE_IDLE (1 << 9)
# define STOP_RING (1 << 8)
-#define GEN6_GT_MODE 0x20d0
-#define GEN7_GT_MODE 0x7008
+#define GEN6_GT_MODE _MMIO(0x20d0)
+#define GEN7_GT_MODE _MMIO(0x7008)
#define GEN6_WIZ_HASHING(hi, lo) (((hi) << 9) | ((lo) << 7))
#define GEN6_WIZ_HASHING_8x8 GEN6_WIZ_HASHING(0, 0)
#define GEN6_WIZ_HASHING_8x4 GEN6_WIZ_HASHING(0, 1)
@@ -1707,9 +1767,9 @@ enum skl_disp_power_wells {
#define GEN9_IZ_HASHING_MASK(slice) (0x3 << ((slice) * 2))
#define GEN9_IZ_HASHING(slice, val) ((val) << ((slice) * 2))
-#define GFX_MODE 0x02520
-#define GFX_MODE_GEN7 0x0229c
-#define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c)
+#define GFX_MODE _MMIO(0x2520)
+#define GFX_MODE_GEN7 _MMIO(0x229c)
+#define RING_MODE_GEN7(ring) _MMIO((ring)->mmio_base+0x29c)
#define GFX_RUN_LIST_ENABLE (1<<15)
#define GFX_INTERRUPT_STEERING (1<<14)
#define GFX_TLB_INVALIDATE_EXPLICIT (1<<13)
@@ -1727,36 +1787,36 @@ enum skl_disp_power_wells {
#define VLV_DISPLAY_BASE 0x180000
#define VLV_MIPI_BASE VLV_DISPLAY_BASE
-#define VLV_GU_CTL0 (VLV_DISPLAY_BASE + 0x2030)
-#define VLV_GU_CTL1 (VLV_DISPLAY_BASE + 0x2034)
-#define SCPD0 0x0209c /* 915+ only */
-#define IER 0x020a0
-#define IIR 0x020a4
-#define IMR 0x020a8
-#define ISR 0x020ac
-#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060)
+#define VLV_GU_CTL0 _MMIO(VLV_DISPLAY_BASE + 0x2030)
+#define VLV_GU_CTL1 _MMIO(VLV_DISPLAY_BASE + 0x2034)
+#define SCPD0 _MMIO(0x209c) /* 915+ only */
+#define IER _MMIO(0x20a0)
+#define IIR _MMIO(0x20a4)
+#define IMR _MMIO(0x20a8)
+#define ISR _MMIO(0x20ac)
+#define VLV_GUNIT_CLOCK_GATE _MMIO(VLV_DISPLAY_BASE + 0x2060)
#define GINT_DIS (1<<22)
#define GCFG_DIS (1<<8)
-#define VLV_GUNIT_CLOCK_GATE2 (VLV_DISPLAY_BASE + 0x2064)
-#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084)
-#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0)
-#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4)
-#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8)
-#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac)
-#define VLV_PCBR (VLV_DISPLAY_BASE + 0x2120)
+#define VLV_GUNIT_CLOCK_GATE2 _MMIO(VLV_DISPLAY_BASE + 0x2064)
+#define VLV_IIR_RW _MMIO(VLV_DISPLAY_BASE + 0x2084)
+#define VLV_IER _MMIO(VLV_DISPLAY_BASE + 0x20a0)
+#define VLV_IIR _MMIO(VLV_DISPLAY_BASE + 0x20a4)
+#define VLV_IMR _MMIO(VLV_DISPLAY_BASE + 0x20a8)
+#define VLV_ISR _MMIO(VLV_DISPLAY_BASE + 0x20ac)
+#define VLV_PCBR _MMIO(VLV_DISPLAY_BASE + 0x2120)
#define VLV_PCBR_ADDR_SHIFT 12
#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
-#define EIR 0x020b0
-#define EMR 0x020b4
-#define ESR 0x020b8
+#define EIR _MMIO(0x20b0)
+#define EMR _MMIO(0x20b4)
+#define ESR _MMIO(0x20b8)
#define GM45_ERROR_PAGE_TABLE (1<<5)
#define GM45_ERROR_MEM_PRIV (1<<4)
#define I915_ERROR_PAGE_TABLE (1<<4)
#define GM45_ERROR_CP_PRIV (1<<3)
#define I915_ERROR_MEMORY_REFRESH (1<<1)
#define I915_ERROR_INSTRUCTION (1<<0)
-#define INSTPM 0x020c0
+#define INSTPM _MMIO(0x20c0)
#define INSTPM_SELF_EN (1<<12) /* 915GM only */
#define INSTPM_AGPBUSY_INT_EN (1<<11) /* gen3: when disabled, pending interrupts
will not assert AGPBUSY# and will only
@@ -1764,14 +1824,14 @@ enum skl_disp_power_wells {
#define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */
#define INSTPM_TLB_INVALIDATE (1<<9)
#define INSTPM_SYNC_FLUSH (1<<5)
-#define ACTHD 0x020c8
-#define MEM_MODE 0x020cc
+#define ACTHD _MMIO(0x20c8)
+#define MEM_MODE _MMIO(0x20cc)
#define MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1<<3) /* 830 only */
#define MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1<<2) /* 830/845 only */
#define MEM_DISPLAY_TRICKLE_FEED_DISABLE (1<<2) /* 85x only */
-#define FW_BLC 0x020d8
-#define FW_BLC2 0x020dc
-#define FW_BLC_SELF 0x020e0 /* 915+ only */
+#define FW_BLC _MMIO(0x20d8)
+#define FW_BLC2 _MMIO(0x20dc)
+#define FW_BLC_SELF _MMIO(0x20e0) /* 915+ only */
#define FW_BLC_SELF_EN_MASK (1<<31)
#define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */
#define FW_BLC_SELF_EN (1<<15) /* 945 only */
@@ -1779,7 +1839,7 @@ enum skl_disp_power_wells {
#define MM_FIFO_WATERMARK 0x0001F000
#define LM_BURST_LENGTH 0x00000700
#define LM_FIFO_WATERMARK 0x0000001F
-#define MI_ARB_STATE 0x020e4 /* 915+ only */
+#define MI_ARB_STATE _MMIO(0x20e4) /* 915+ only */
/* Make render/texture TLB fetches lower priorty than associated data
* fetches. This is not turned on by default
@@ -1843,11 +1903,11 @@ enum skl_disp_power_wells {
#define MI_ARB_DISPLAY_PRIORITY_A_B (0 << 0) /* display A > display B */
#define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */
-#define MI_STATE 0x020e4 /* gen2 only */
+#define MI_STATE _MMIO(0x20e4) /* gen2 only */
#define MI_AGPBUSY_INT_EN (1 << 1) /* 85x only */
#define MI_AGPBUSY_830_MODE (1 << 0) /* 85x only */
-#define CACHE_MODE_0 0x02120 /* 915+ only */
+#define CACHE_MODE_0 _MMIO(0x2120) /* 915+ only */
#define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1<<8)
#define CM0_IZ_OPT_DISABLE (1<<6)
#define CM0_ZR_OPT_DISABLE (1<<5)
@@ -1856,32 +1916,32 @@ enum skl_disp_power_wells {
#define CM0_COLOR_EVICT_DISABLE (1<<3)
#define CM0_DEPTH_WRITE_DISABLE (1<<1)
#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
-#define GFX_FLSH_CNTL 0x02170 /* 915+ only */
-#define GFX_FLSH_CNTL_GEN6 0x101008
+#define GFX_FLSH_CNTL _MMIO(0x2170) /* 915+ only */
+#define GFX_FLSH_CNTL_GEN6 _MMIO(0x101008)
#define GFX_FLSH_CNTL_EN (1<<0)
-#define ECOSKPD 0x021d0
+#define ECOSKPD _MMIO(0x21d0)
#define ECO_GATING_CX_ONLY (1<<3)
#define ECO_FLIP_DONE (1<<0)
-#define CACHE_MODE_0_GEN7 0x7000 /* IVB+ */
+#define CACHE_MODE_0_GEN7 _MMIO(0x7000) /* IVB+ */
#define RC_OP_FLUSH_ENABLE (1<<0)
#define HIZ_RAW_STALL_OPT_DISABLE (1<<2)
-#define CACHE_MODE_1 0x7004 /* IVB+ */
+#define CACHE_MODE_1 _MMIO(0x7004) /* IVB+ */
#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
#define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1<<6)
#define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1<<1)
-#define GEN6_BLITTER_ECOSKPD 0x221d0
+#define GEN6_BLITTER_ECOSKPD _MMIO(0x221d0)
#define GEN6_BLITTER_LOCK_SHIFT 16
#define GEN6_BLITTER_FBC_NOTIFY (1<<3)
-#define GEN6_RC_SLEEP_PSMI_CONTROL 0x2050
+#define GEN6_RC_SLEEP_PSMI_CONTROL _MMIO(0x2050)
#define GEN6_PSMI_SLEEP_MSG_DISABLE (1 << 0)
#define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12)
#define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1<<10)
/* Fuse readout registers for GT */
-#define CHV_FUSE_GT (VLV_DISPLAY_BASE + 0x2168)
+#define CHV_FUSE_GT _MMIO(VLV_DISPLAY_BASE + 0x2168)
#define CHV_FGT_DISABLE_SS0 (1 << 10)
#define CHV_FGT_DISABLE_SS1 (1 << 11)
#define CHV_FGT_EU_DIS_SS0_R0_SHIFT 16
@@ -1893,7 +1953,7 @@ enum skl_disp_power_wells {
#define CHV_FGT_EU_DIS_SS1_R1_SHIFT 28
#define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
-#define GEN8_FUSE2 0x9120
+#define GEN8_FUSE2 _MMIO(0x9120)
#define GEN8_F2_SS_DIS_SHIFT 21
#define GEN8_F2_SS_DIS_MASK (0x7 << GEN8_F2_SS_DIS_SHIFT)
#define GEN8_F2_S_ENA_SHIFT 25
@@ -1902,22 +1962,22 @@ enum skl_disp_power_wells {
#define GEN9_F2_SS_DIS_SHIFT 20
#define GEN9_F2_SS_DIS_MASK (0xf << GEN9_F2_SS_DIS_SHIFT)
-#define GEN8_EU_DISABLE0 0x9134
+#define GEN8_EU_DISABLE0 _MMIO(0x9134)
#define GEN8_EU_DIS0_S0_MASK 0xffffff
#define GEN8_EU_DIS0_S1_SHIFT 24
#define GEN8_EU_DIS0_S1_MASK (0xff << GEN8_EU_DIS0_S1_SHIFT)
-#define GEN8_EU_DISABLE1 0x9138
+#define GEN8_EU_DISABLE1 _MMIO(0x9138)
#define GEN8_EU_DIS1_S1_MASK 0xffff
#define GEN8_EU_DIS1_S2_SHIFT 16
#define GEN8_EU_DIS1_S2_MASK (0xffff << GEN8_EU_DIS1_S2_SHIFT)
-#define GEN8_EU_DISABLE2 0x913c
+#define GEN8_EU_DISABLE2 _MMIO(0x913c)
#define GEN8_EU_DIS2_S2_MASK 0xff
-#define GEN9_EU_DISABLE(slice) (0x9134 + (slice)*0x4)
+#define GEN9_EU_DISABLE(slice) _MMIO(0x9134 + (slice)*0x4)
-#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
+#define GEN6_BSD_SLEEP_PSMI_CONTROL _MMIO(0x12050)
#define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0)
#define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
#define GEN6_BSD_SLEEP_INDICATOR (1 << 3)
@@ -1995,9 +2055,9 @@ enum skl_disp_power_wells {
#define I915_ASLE_INTERRUPT (1<<0)
#define I915_BSD_USER_INTERRUPT (1<<25)
-#define GEN6_BSD_RNCID 0x12198
+#define GEN6_BSD_RNCID _MMIO(0x12198)
-#define GEN7_FF_THREAD_MODE 0x20a0
+#define GEN7_FF_THREAD_MODE _MMIO(0x20a0)
#define GEN7_FF_SCHED_MASK 0x0077070
#define GEN8_FF_DS_REF_CNT_FFME (1 << 19)
#define GEN7_FF_TS_SCHED_HS1 (0x5<<16)
@@ -2018,9 +2078,9 @@ enum skl_disp_power_wells {
* Framebuffer compression (915+ only)
*/
-#define FBC_CFB_BASE 0x03200 /* 4k page aligned */
-#define FBC_LL_BASE 0x03204 /* 4k page aligned */
-#define FBC_CONTROL 0x03208
+#define FBC_CFB_BASE _MMIO(0x3200) /* 4k page aligned */
+#define FBC_LL_BASE _MMIO(0x3204) /* 4k page aligned */
+#define FBC_CONTROL _MMIO(0x3208)
#define FBC_CTL_EN (1<<31)
#define FBC_CTL_PERIODIC (1<<30)
#define FBC_CTL_INTERVAL_SHIFT (16)
@@ -2028,14 +2088,14 @@ enum skl_disp_power_wells {
#define FBC_CTL_C3_IDLE (1<<13)
#define FBC_CTL_STRIDE_SHIFT (5)
#define FBC_CTL_FENCENO_SHIFT (0)
-#define FBC_COMMAND 0x0320c
+#define FBC_COMMAND _MMIO(0x320c)
#define FBC_CMD_COMPRESS (1<<0)
-#define FBC_STATUS 0x03210
+#define FBC_STATUS _MMIO(0x3210)
#define FBC_STAT_COMPRESSING (1<<31)
#define FBC_STAT_COMPRESSED (1<<30)
#define FBC_STAT_MODIFIED (1<<29)
#define FBC_STAT_CURRENT_LINE_SHIFT (0)
-#define FBC_CONTROL2 0x03214
+#define FBC_CONTROL2 _MMIO(0x3214)
#define FBC_CTL_FENCE_DBL (0<<4)
#define FBC_CTL_IDLE_IMM (0<<2)
#define FBC_CTL_IDLE_FULL (1<<2)
@@ -2043,17 +2103,17 @@ enum skl_disp_power_wells {
#define FBC_CTL_IDLE_DEBUG (3<<2)
#define FBC_CTL_CPU_FENCE (1<<1)
#define FBC_CTL_PLANE(plane) ((plane)<<0)
-#define FBC_FENCE_OFF 0x03218 /* BSpec typo has 321Bh */
-#define FBC_TAG(i) (0x03300 + (i) * 4)
+#define FBC_FENCE_OFF _MMIO(0x3218) /* BSpec typo has 321Bh */
+#define FBC_TAG(i) _MMIO(0x3300 + (i) * 4)
-#define FBC_STATUS2 0x43214
+#define FBC_STATUS2 _MMIO(0x43214)
#define FBC_COMPRESSION_MASK 0x7ff
#define FBC_LL_SIZE (1536)
/* Framebuffer compression for GM45+ */
-#define DPFC_CB_BASE 0x3200
-#define DPFC_CONTROL 0x3208
+#define DPFC_CB_BASE _MMIO(0x3200)
+#define DPFC_CONTROL _MMIO(0x3208)
#define DPFC_CTL_EN (1<<31)
#define DPFC_CTL_PLANE(plane) ((plane)<<30)
#define IVB_DPFC_CTL_PLANE(plane) ((plane)<<29)
@@ -2064,37 +2124,37 @@ enum skl_disp_power_wells {
#define DPFC_CTL_LIMIT_1X (0<<6)
#define DPFC_CTL_LIMIT_2X (1<<6)
#define DPFC_CTL_LIMIT_4X (2<<6)
-#define DPFC_RECOMP_CTL 0x320c
+#define DPFC_RECOMP_CTL _MMIO(0x320c)
#define DPFC_RECOMP_STALL_EN (1<<27)
#define DPFC_RECOMP_STALL_WM_SHIFT (16)
#define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000)
#define DPFC_RECOMP_TIMER_COUNT_SHIFT (0)
#define DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f)
-#define DPFC_STATUS 0x3210
+#define DPFC_STATUS _MMIO(0x3210)
#define DPFC_INVAL_SEG_SHIFT (16)
#define DPFC_INVAL_SEG_MASK (0x07ff0000)
#define DPFC_COMP_SEG_SHIFT (0)
#define DPFC_COMP_SEG_MASK (0x000003ff)
-#define DPFC_STATUS2 0x3214
-#define DPFC_FENCE_YOFF 0x3218
-#define DPFC_CHICKEN 0x3224
+#define DPFC_STATUS2 _MMIO(0x3214)
+#define DPFC_FENCE_YOFF _MMIO(0x3218)
+#define DPFC_CHICKEN _MMIO(0x3224)
#define DPFC_HT_MODIFY (1<<31)
/* Framebuffer compression for Ironlake */
-#define ILK_DPFC_CB_BASE 0x43200
-#define ILK_DPFC_CONTROL 0x43208
+#define ILK_DPFC_CB_BASE _MMIO(0x43200)
+#define ILK_DPFC_CONTROL _MMIO(0x43208)
#define FBC_CTL_FALSE_COLOR (1<<10)
/* The bit 28-8 is reserved */
#define DPFC_RESERVED (0x1FFFFF00)
-#define ILK_DPFC_RECOMP_CTL 0x4320c
-#define ILK_DPFC_STATUS 0x43210
-#define ILK_DPFC_FENCE_YOFF 0x43218
-#define ILK_DPFC_CHICKEN 0x43224
-#define ILK_FBC_RT_BASE 0x2128
+#define ILK_DPFC_RECOMP_CTL _MMIO(0x4320c)
+#define ILK_DPFC_STATUS _MMIO(0x43210)
+#define ILK_DPFC_FENCE_YOFF _MMIO(0x43218)
+#define ILK_DPFC_CHICKEN _MMIO(0x43224)
+#define ILK_FBC_RT_BASE _MMIO(0x2128)
#define ILK_FBC_RT_VALID (1<<0)
#define SNB_FBC_FRONT_BUFFER (1<<1)
-#define ILK_DISPLAY_CHICKEN1 0x42000
+#define ILK_DISPLAY_CHICKEN1 _MMIO(0x42000)
#define ILK_FBCQ_DIS (1<<22)
#define ILK_PABSTRETCH_DIS (1<<21)
@@ -2104,31 +2164,31 @@ enum skl_disp_power_wells {
*
* The following two registers are of type GTTMMADR
*/
-#define SNB_DPFC_CTL_SA 0x100100
+#define SNB_DPFC_CTL_SA _MMIO(0x100100)
#define SNB_CPU_FENCE_ENABLE (1<<29)
-#define DPFC_CPU_FENCE_OFFSET 0x100104
+#define DPFC_CPU_FENCE_OFFSET _MMIO(0x100104)
/* Framebuffer compression for Ivybridge */
-#define IVB_FBC_RT_BASE 0x7020
+#define IVB_FBC_RT_BASE _MMIO(0x7020)
-#define IPS_CTL 0x43408
+#define IPS_CTL _MMIO(0x43408)
#define IPS_ENABLE (1 << 31)
-#define MSG_FBC_REND_STATE 0x50380
+#define MSG_FBC_REND_STATE _MMIO(0x50380)
#define FBC_REND_NUKE (1<<2)
#define FBC_REND_CACHE_CLEAN (1<<1)
/*
* GPIO regs
*/
-#define GPIOA 0x5010
-#define GPIOB 0x5014
-#define GPIOC 0x5018
-#define GPIOD 0x501c
-#define GPIOE 0x5020
-#define GPIOF 0x5024
-#define GPIOG 0x5028
-#define GPIOH 0x502c
+#define GPIOA _MMIO(0x5010)
+#define GPIOB _MMIO(0x5014)
+#define GPIOC _MMIO(0x5018)
+#define GPIOD _MMIO(0x501c)
+#define GPIOE _MMIO(0x5020)
+#define GPIOF _MMIO(0x5024)
+#define GPIOG _MMIO(0x5028)
+#define GPIOH _MMIO(0x502c)
# define GPIO_CLOCK_DIR_MASK (1 << 0)
# define GPIO_CLOCK_DIR_IN (0 << 1)
# define GPIO_CLOCK_DIR_OUT (1 << 1)
@@ -2144,7 +2204,7 @@ enum skl_disp_power_wells {
# define GPIO_DATA_VAL_IN (1 << 12)
# define GPIO_DATA_PULLUP_DISABLE (1 << 13)
-#define GMBUS0 (dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
+#define GMBUS0 _MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
#define GMBUS_RATE_100KHZ (0<<8)
#define GMBUS_RATE_50KHZ (1<<8)
#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */
@@ -2163,7 +2223,7 @@ enum skl_disp_power_wells {
#define GMBUS_PIN_2_BXT 2
#define GMBUS_PIN_3_BXT 3
#define GMBUS_NUM_PINS 7 /* including 0 */
-#define GMBUS1 (dev_priv->gpio_mmio_base + 0x5104) /* command/status */
+#define GMBUS1 _MMIO(dev_priv->gpio_mmio_base + 0x5104) /* command/status */
#define GMBUS_SW_CLR_INT (1<<31)
#define GMBUS_SW_RDY (1<<30)
#define GMBUS_ENT (1<<29) /* enable timeout */
@@ -2177,7 +2237,7 @@ enum skl_disp_power_wells {
#define GMBUS_SLAVE_ADDR_SHIFT 1
#define GMBUS_SLAVE_READ (1<<0)
#define GMBUS_SLAVE_WRITE (0<<0)
-#define GMBUS2 (dev_priv->gpio_mmio_base + 0x5108) /* status */
+#define GMBUS2 _MMIO(dev_priv->gpio_mmio_base + 0x5108) /* status */
#define GMBUS_INUSE (1<<15)
#define GMBUS_HW_WAIT_PHASE (1<<14)
#define GMBUS_STALL_TIMEOUT (1<<13)
@@ -2185,14 +2245,14 @@ enum skl_disp_power_wells {
#define GMBUS_HW_RDY (1<<11)
#define GMBUS_SATOER (1<<10)
#define GMBUS_ACTIVE (1<<9)
-#define GMBUS3 (dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */
-#define GMBUS4 (dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */
+#define GMBUS3 _MMIO(dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */
+#define GMBUS4 _MMIO(dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */
#define GMBUS_SLAVE_TIMEOUT_EN (1<<4)
#define GMBUS_NAK_EN (1<<3)
#define GMBUS_IDLE_EN (1<<2)
#define GMBUS_HW_WAIT_EN (1<<1)
#define GMBUS_HW_RDY_EN (1<<0)
-#define GMBUS5 (dev_priv->gpio_mmio_base + 0x5120) /* byte index */
+#define GMBUS5 _MMIO(dev_priv->gpio_mmio_base + 0x5120) /* byte index */
#define GMBUS_2BYTE_INDEX_EN (1<<31)
/*
@@ -2201,11 +2261,11 @@ enum skl_disp_power_wells {
#define _DPLL_A (dev_priv->info.display_mmio_offset + 0x6014)
#define _DPLL_B (dev_priv->info.display_mmio_offset + 0x6018)
#define _CHV_DPLL_C (dev_priv->info.display_mmio_offset + 0x6030)
-#define DPLL(pipe) _PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C)
+#define DPLL(pipe) _MMIO_PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C)
-#define VGA0 0x6000
-#define VGA1 0x6004
-#define VGA_PD 0x6010
+#define VGA0 _MMIO(0x6000)
+#define VGA1 _MMIO(0x6004)
+#define VGA_PD _MMIO(0x6010)
#define VGA0_PD_P2_DIV_4 (1 << 7)
#define VGA0_PD_P1_DIV_2 (1 << 5)
#define VGA0_PD_P1_SHIFT 0
@@ -2241,9 +2301,9 @@ enum skl_disp_power_wells {
#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
/* Additional CHV pll/phy registers */
-#define DPIO_PHY_STATUS (VLV_DISPLAY_BASE + 0x6240)
+#define DPIO_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x6240)
#define DPLL_PORTD_READY_MASK (0xf)
-#define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100)
+#define DISPLAY_PHY_CONTROL _MMIO(VLV_DISPLAY_BASE + 0x60100)
#define PHY_CH_POWER_DOWN_OVRD_EN(phy, ch) (1 << (2*(phy)+(ch)+27))
#define PHY_LDO_DELAY_0NS 0x0
#define PHY_LDO_DELAY_200NS 0x1
@@ -2254,7 +2314,7 @@ enum skl_disp_power_wells {
#define PHY_CH_DEEP_PSR 0x7
#define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6*(phy)+3*(ch)+2))
#define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy))
-#define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104)
+#define DISPLAY_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x60104)
#define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30))
#define PHY_STATUS_CMN_LDO(phy, ch) (1 << (6-(6*(phy)+3*(ch))))
#define PHY_STATUS_SPLINE_LDO(phy, ch, spline) (1 << (8-(6*(phy)+3*(ch)+(spline))))
@@ -2300,7 +2360,7 @@ enum skl_disp_power_wells {
#define _DPLL_A_MD (dev_priv->info.display_mmio_offset + 0x601c)
#define _DPLL_B_MD (dev_priv->info.display_mmio_offset + 0x6020)
#define _CHV_DPLL_C_MD (dev_priv->info.display_mmio_offset + 0x603c)
-#define DPLL_MD(pipe) _PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD)
+#define DPLL_MD(pipe) _MMIO_PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD)
/*
* UDI pixel divider, controlling how many pixels are stuffed into a packet.
@@ -2339,12 +2399,12 @@ enum skl_disp_power_wells {
#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
-#define _FPA0 0x06040
-#define _FPA1 0x06044
-#define _FPB0 0x06048
-#define _FPB1 0x0604c
-#define FP0(pipe) _PIPE(pipe, _FPA0, _FPB0)
-#define FP1(pipe) _PIPE(pipe, _FPA1, _FPB1)
+#define _FPA0 0x6040
+#define _FPA1 0x6044
+#define _FPB0 0x6048
+#define _FPB1 0x604c
+#define FP0(pipe) _MMIO_PIPE(pipe, _FPA0, _FPB0)
+#define FP1(pipe) _MMIO_PIPE(pipe, _FPA1, _FPB1)
#define FP_N_DIV_MASK 0x003f0000
#define FP_N_PINEVIEW_DIV_MASK 0x00ff0000
#define FP_N_DIV_SHIFT 16
@@ -2353,7 +2413,7 @@ enum skl_disp_power_wells {
#define FP_M2_DIV_MASK 0x0000003f
#define FP_M2_PINEVIEW_DIV_MASK 0x000000ff
#define FP_M2_DIV_SHIFT 0
-#define DPLL_TEST 0x606c
+#define DPLL_TEST _MMIO(0x606c)
#define DPLLB_TEST_SDVO_DIV_1 (0 << 22)
#define DPLLB_TEST_SDVO_DIV_2 (1 << 22)
#define DPLLB_TEST_SDVO_DIV_4 (2 << 22)
@@ -2364,12 +2424,12 @@ enum skl_disp_power_wells {
#define DPLLA_TEST_N_BYPASS (1 << 3)
#define DPLLA_TEST_M_BYPASS (1 << 2)
#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
-#define D_STATE 0x6104
+#define D_STATE _MMIO(0x6104)
#define DSTATE_GFX_RESET_I830 (1<<6)
#define DSTATE_PLL_D3_OFF (1<<3)
#define DSTATE_GFX_CLOCK_GATING (1<<1)
#define DSTATE_DOT_CLOCK_GATING (1<<0)
-#define DSPCLK_GATE_D (dev_priv->info.display_mmio_offset + 0x6200)
+#define DSPCLK_GATE_D _MMIO(dev_priv->info.display_mmio_offset + 0x6200)
# define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */
# define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */
# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */
@@ -2408,7 +2468,7 @@ enum skl_disp_power_wells {
# define ZVUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 830 */
# define OVLUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 845,865 */
-#define RENCLK_GATE_D1 0x6204
+#define RENCLK_GATE_D1 _MMIO(0x6204)
# define BLITTER_CLOCK_GATE_DISABLE (1 << 13) /* 945GM only */
# define MPEG_CLOCK_GATE_DISABLE (1 << 12) /* 945GM only */
# define PC_FE_CLOCK_GATE_DISABLE (1 << 11)
@@ -2472,35 +2532,35 @@ enum skl_disp_power_wells {
# define I965_FT_CLOCK_GATE_DISABLE (1 << 1)
# define I965_DM_CLOCK_GATE_DISABLE (1 << 0)
-#define RENCLK_GATE_D2 0x6208
+#define RENCLK_GATE_D2 _MMIO(0x6208)
#define VF_UNIT_CLOCK_GATE_DISABLE (1 << 9)
#define GS_UNIT_CLOCK_GATE_DISABLE (1 << 7)
#define CL_UNIT_CLOCK_GATE_DISABLE (1 << 6)
-#define VDECCLK_GATE_D 0x620C /* g4x only */
+#define VDECCLK_GATE_D _MMIO(0x620C) /* g4x only */
#define VCP_UNIT_CLOCK_GATE_DISABLE (1 << 4)
-#define RAMCLK_GATE_D 0x6210 /* CRL only */
-#define DEUC 0x6214 /* CRL only */
+#define RAMCLK_GATE_D _MMIO(0x6210) /* CRL only */
+#define DEUC _MMIO(0x6214) /* CRL only */
-#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500)
+#define FW_BLC_SELF_VLV _MMIO(VLV_DISPLAY_BASE + 0x6500)
#define FW_CSPWRDWNEN (1<<15)
-#define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504)
+#define MI_ARB_VLV _MMIO(VLV_DISPLAY_BASE + 0x6504)
-#define CZCLK_CDCLK_FREQ_RATIO (VLV_DISPLAY_BASE + 0x6508)
+#define CZCLK_CDCLK_FREQ_RATIO _MMIO(VLV_DISPLAY_BASE + 0x6508)
#define CDCLK_FREQ_SHIFT 4
#define CDCLK_FREQ_MASK (0x1f << CDCLK_FREQ_SHIFT)
#define CZCLK_FREQ_MASK 0xf
-#define GCI_CONTROL (VLV_DISPLAY_BASE + 0x650C)
+#define GCI_CONTROL _MMIO(VLV_DISPLAY_BASE + 0x650C)
#define PFI_CREDIT_63 (9 << 28) /* chv only */
#define PFI_CREDIT_31 (8 << 28) /* chv only */
#define PFI_CREDIT(x) (((x) - 8) << 28) /* 8-15 */
#define PFI_CREDIT_RESEND (1 << 27)
#define VGA_FAST_MODE_DISABLE (1 << 14)
-#define GMBUSFREQ_VLV (VLV_DISPLAY_BASE + 0x6510)
+#define GMBUSFREQ_VLV _MMIO(VLV_DISPLAY_BASE + 0x6510)
/*
* Palette regs
@@ -2508,8 +2568,8 @@ enum skl_disp_power_wells {
#define PALETTE_A_OFFSET 0xa000
#define PALETTE_B_OFFSET 0xa800
#define CHV_PALETTE_C_OFFSET 0xc000
-#define PALETTE(pipe, i) (dev_priv->info.palette_offsets[pipe] + \
- dev_priv->info.display_mmio_offset + (i) * 4)
+#define PALETTE(pipe, i) _MMIO(dev_priv->info.palette_offsets[pipe] + \
+ dev_priv->info.display_mmio_offset + (i) * 4)
/* MCH MMIO space */
@@ -2527,37 +2587,37 @@ enum skl_disp_power_wells {
#define MCHBAR_MIRROR_BASE_SNB 0x140000
-#define CTG_STOLEN_RESERVED (MCHBAR_MIRROR_BASE + 0x34)
-#define ELK_STOLEN_RESERVED (MCHBAR_MIRROR_BASE + 0x48)
+#define CTG_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x34)
+#define ELK_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x48)
#define G4X_STOLEN_RESERVED_ADDR1_MASK (0xFFFF << 16)
#define G4X_STOLEN_RESERVED_ADDR2_MASK (0xFFF << 4)
/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */
-#define DCLK (MCHBAR_MIRROR_BASE_SNB + 0x5e04)
+#define DCLK _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04)
/* 915-945 and GM965 MCH register controlling DRAM channel access */
-#define DCC 0x10200
+#define DCC _MMIO(MCHBAR_MIRROR_BASE + 0x200)
#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0)
#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0)
#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0)
#define DCC_ADDRESSING_MODE_MASK (3 << 0)
#define DCC_CHANNEL_XOR_DISABLE (1 << 10)
#define DCC_CHANNEL_XOR_BIT_17 (1 << 9)
-#define DCC2 0x10204
+#define DCC2 _MMIO(MCHBAR_MIRROR_BASE + 0x204)
#define DCC2_MODIFIED_ENHANCED_DISABLE (1 << 20)
/* Pineview MCH register contains DDR3 setting */
-#define CSHRDDR3CTL 0x101a8
+#define CSHRDDR3CTL _MMIO(MCHBAR_MIRROR_BASE + 0x1a8)
#define CSHRDDR3CTL_DDR3 (1 << 2)
/* 965 MCH register controlling DRAM channel configuration */
-#define C0DRB3 0x10206
-#define C1DRB3 0x10606
+#define C0DRB3 _MMIO(MCHBAR_MIRROR_BASE + 0x206)
+#define C1DRB3 _MMIO(MCHBAR_MIRROR_BASE + 0x606)
/* snb MCH registers for reading the DRAM channel configuration */
-#define MAD_DIMM_C0 (MCHBAR_MIRROR_BASE_SNB + 0x5004)
-#define MAD_DIMM_C1 (MCHBAR_MIRROR_BASE_SNB + 0x5008)
-#define MAD_DIMM_C2 (MCHBAR_MIRROR_BASE_SNB + 0x500C)
+#define MAD_DIMM_C0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5004)
+#define MAD_DIMM_C1 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5008)
+#define MAD_DIMM_C2 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C)
#define MAD_DIMM_ECC_MASK (0x3 << 24)
#define MAD_DIMM_ECC_OFF (0x0 << 24)
#define MAD_DIMM_ECC_IO_ON_LOGIC_OFF (0x1 << 24)
@@ -2577,14 +2637,14 @@ enum skl_disp_power_wells {
#define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT)
/* snb MCH registers for priority tuning */
-#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10)
+#define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10)
#define MCH_SSKPD_WM0_MASK 0x3f
#define MCH_SSKPD_WM0_VAL 0xc
-#define MCH_SECP_NRG_STTS (MCHBAR_MIRROR_BASE_SNB + 0x592c)
+#define MCH_SECP_NRG_STTS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x592c)
/* Clocking configuration register */
-#define CLKCFG 0x10c00
+#define CLKCFG _MMIO(MCHBAR_MIRROR_BASE + 0xc00)
#define CLKCFG_FSB_400 (5 << 0) /* hrawclk 100 */
#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */
#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */
@@ -2600,26 +2660,26 @@ enum skl_disp_power_wells {
#define CLKCFG_MEM_800 (3 << 4)
#define CLKCFG_MEM_MASK (7 << 4)
-#define HPLLVCO (MCHBAR_MIRROR_BASE + 0xc38)
-#define HPLLVCO_MOBILE (MCHBAR_MIRROR_BASE + 0xc0f)
+#define HPLLVCO _MMIO(MCHBAR_MIRROR_BASE + 0xc38)
+#define HPLLVCO_MOBILE _MMIO(MCHBAR_MIRROR_BASE + 0xc0f)
-#define TSC1 0x11001
+#define TSC1 _MMIO(0x11001)
#define TSE (1<<0)
-#define TR1 0x11006
-#define TSFS 0x11020
+#define TR1 _MMIO(0x11006)
+#define TSFS _MMIO(0x11020)
#define TSFS_SLOPE_MASK 0x0000ff00
#define TSFS_SLOPE_SHIFT 8
#define TSFS_INTR_MASK 0x000000ff
-#define CRSTANDVID 0x11100
-#define PXVFREQ(i) (0x11110 + (i) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
+#define CRSTANDVID _MMIO(0x11100)
+#define PXVFREQ(fstart) _MMIO(0x11110 + (fstart) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
#define PXVFREQ_PX_MASK 0x7f000000
#define PXVFREQ_PX_SHIFT 24
-#define VIDFREQ_BASE 0x11110
-#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
-#define VIDFREQ2 0x11114
-#define VIDFREQ3 0x11118
-#define VIDFREQ4 0x1111c
+#define VIDFREQ_BASE _MMIO(0x11110)
+#define VIDFREQ1 _MMIO(0x11110) /* VIDFREQ1-4 (0x1111c) (Cantiga) */
+#define VIDFREQ2 _MMIO(0x11114)
+#define VIDFREQ3 _MMIO(0x11118)
+#define VIDFREQ4 _MMIO(0x1111c)
#define VIDFREQ_P0_MASK 0x1f000000
#define VIDFREQ_P0_SHIFT 24
#define VIDFREQ_P0_CSCLK_MASK 0x00f00000
@@ -2631,8 +2691,8 @@ enum skl_disp_power_wells {
#define VIDFREQ_P1_CSCLK_MASK 0x000000f0
#define VIDFREQ_P1_CSCLK_SHIFT 4
#define VIDFREQ_P1_CRCLK_MASK 0x0000000f
-#define INTTOEXT_BASE_ILK 0x11300
-#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */
+#define INTTOEXT_BASE_ILK _MMIO(0x11300)
+#define INTTOEXT_BASE _MMIO(0x11120) /* INTTOEXT1-8 (0x1113c) */
#define INTTOEXT_MAP3_SHIFT 24
#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT)
#define INTTOEXT_MAP2_SHIFT 16
@@ -2641,7 +2701,7 @@ enum skl_disp_power_wells {
#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT)
#define INTTOEXT_MAP0_SHIFT 0
#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT)
-#define MEMSWCTL 0x11170 /* Ironlake only */
+#define MEMSWCTL _MMIO(0x11170) /* Ironlake only */
#define MEMCTL_CMD_MASK 0xe000
#define MEMCTL_CMD_SHIFT 13
#define MEMCTL_CMD_RCLK_OFF 0
@@ -2656,8 +2716,8 @@ enum skl_disp_power_wells {
#define MEMCTL_FREQ_SHIFT 8
#define MEMCTL_SFCAVM (1<<7)
#define MEMCTL_TGT_VID_MASK 0x007f
-#define MEMIHYST 0x1117c
-#define MEMINTREN 0x11180 /* 16 bits */
+#define MEMIHYST _MMIO(0x1117c)
+#define MEMINTREN _MMIO(0x11180) /* 16 bits */
#define MEMINT_RSEXIT_EN (1<<8)
#define MEMINT_CX_SUPR_EN (1<<7)
#define MEMINT_CONT_BUSY_EN (1<<6)
@@ -2667,7 +2727,7 @@ enum skl_disp_power_wells {
#define MEMINT_UP_EVAL_EN (1<<2)
#define MEMINT_DOWN_EVAL_EN (1<<1)
#define MEMINT_SW_CMD_EN (1<<0)
-#define MEMINTRSTR 0x11182 /* 16 bits */
+#define MEMINTRSTR _MMIO(0x11182) /* 16 bits */
#define MEM_RSEXIT_MASK 0xc000
#define MEM_RSEXIT_SHIFT 14
#define MEM_CONT_BUSY_MASK 0x3000
@@ -2687,7 +2747,7 @@ enum skl_disp_power_wells {
#define MEM_INT_STEER_CMR 1
#define MEM_INT_STEER_SMI 2
#define MEM_INT_STEER_SCI 3
-#define MEMINTRSTS 0x11184
+#define MEMINTRSTS _MMIO(0x11184)
#define MEMINT_RSEXIT (1<<7)
#define MEMINT_CONT_BUSY (1<<6)
#define MEMINT_AVG_BUSY (1<<5)
@@ -2696,7 +2756,7 @@ enum skl_disp_power_wells {
#define MEMINT_UP_EVAL (1<<2)
#define MEMINT_DOWN_EVAL (1<<1)
#define MEMINT_SW_CMD (1<<0)
-#define MEMMODECTL 0x11190
+#define MEMMODECTL _MMIO(0x11190)
#define MEMMODE_BOOST_EN (1<<31)
#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
#define MEMMODE_BOOST_FREQ_SHIFT 24
@@ -2713,8 +2773,8 @@ enum skl_disp_power_wells {
#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */
#define MEMMODE_FMAX_SHIFT 4
#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */
-#define RCBMAXAVG 0x1119c
-#define MEMSWCTL2 0x1119e /* Cantiga only */
+#define RCBMAXAVG _MMIO(0x1119c)
+#define MEMSWCTL2 _MMIO(0x1119e) /* Cantiga only */
#define SWMEMCMD_RENDER_OFF (0 << 13)
#define SWMEMCMD_RENDER_ON (1 << 13)
#define SWMEMCMD_SWFREQ (2 << 13)
@@ -2726,11 +2786,11 @@ enum skl_disp_power_wells {
#define SWFREQ_MASK 0x0380 /* P0-7 */
#define SWFREQ_SHIFT 7
#define TARVID_MASK 0x001f
-#define MEMSTAT_CTG 0x111a0
-#define RCBMINAVG 0x111a0
-#define RCUPEI 0x111b0
-#define RCDNEI 0x111b4
-#define RSTDBYCTL 0x111b8
+#define MEMSTAT_CTG _MMIO(0x111a0)
+#define RCBMINAVG _MMIO(0x111a0)
+#define RCUPEI _MMIO(0x111b0)
+#define RCDNEI _MMIO(0x111b4)
+#define RSTDBYCTL _MMIO(0x111b8)
#define RS1EN (1<<31)
#define RS2EN (1<<30)
#define RS3EN (1<<29)
@@ -2774,10 +2834,10 @@ enum skl_disp_power_wells {
#define RS_CSTATE_C367_RS2 (3<<4)
#define REDSAVES (1<<3) /* no context save if was idle during rs0 */
#define REDRESTORES (1<<2) /* no restore if was idle during rs0 */
-#define VIDCTL 0x111c0
-#define VIDSTS 0x111c8
-#define VIDSTART 0x111cc /* 8 bits */
-#define MEMSTAT_ILK 0x111f8
+#define VIDCTL _MMIO(0x111c0)
+#define VIDSTS _MMIO(0x111c8)
+#define VIDSTART _MMIO(0x111cc) /* 8 bits */
+#define MEMSTAT_ILK _MMIO(0x111f8)
#define MEMSTAT_VID_MASK 0x7f00
#define MEMSTAT_VID_SHIFT 8
#define MEMSTAT_PSTATE_MASK 0x00f8
@@ -2788,55 +2848,55 @@ enum skl_disp_power_wells {
#define MEMSTAT_SRC_CTL_TRB 1
#define MEMSTAT_SRC_CTL_THM 2
#define MEMSTAT_SRC_CTL_STDBY 3
-#define RCPREVBSYTUPAVG 0x113b8
-#define RCPREVBSYTDNAVG 0x113bc
-#define PMMISC 0x11214
+#define RCPREVBSYTUPAVG _MMIO(0x113b8)
+#define RCPREVBSYTDNAVG _MMIO(0x113bc)
+#define PMMISC _MMIO(0x11214)
#define MCPPCE_EN (1<<0) /* enable PM_MSG from PCH->MPC */
-#define SDEW 0x1124c
-#define CSIEW0 0x11250
-#define CSIEW1 0x11254
-#define CSIEW2 0x11258
-#define PEW(i) (0x1125c + (i) * 4) /* 5 registers */
-#define DEW(i) (0x11270 + (i) * 4) /* 3 registers */
-#define MCHAFE 0x112c0
-#define CSIEC 0x112e0
-#define DMIEC 0x112e4
-#define DDREC 0x112e8
-#define PEG0EC 0x112ec
-#define PEG1EC 0x112f0
-#define GFXEC 0x112f4
-#define RPPREVBSYTUPAVG 0x113b8
-#define RPPREVBSYTDNAVG 0x113bc
-#define ECR 0x11600
+#define SDEW _MMIO(0x1124c)
+#define CSIEW0 _MMIO(0x11250)
+#define CSIEW1 _MMIO(0x11254)
+#define CSIEW2 _MMIO(0x11258)
+#define PEW(i) _MMIO(0x1125c + (i) * 4) /* 5 registers */
+#define DEW(i) _MMIO(0x11270 + (i) * 4) /* 3 registers */
+#define MCHAFE _MMIO(0x112c0)
+#define CSIEC _MMIO(0x112e0)
+#define DMIEC _MMIO(0x112e4)
+#define DDREC _MMIO(0x112e8)
+#define PEG0EC _MMIO(0x112ec)
+#define PEG1EC _MMIO(0x112f0)
+#define GFXEC _MMIO(0x112f4)
+#define RPPREVBSYTUPAVG _MMIO(0x113b8)
+#define RPPREVBSYTDNAVG _MMIO(0x113bc)
+#define ECR _MMIO(0x11600)
#define ECR_GPFE (1<<31)
#define ECR_IMONE (1<<30)
#define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */
-#define OGW0 0x11608
-#define OGW1 0x1160c
-#define EG0 0x11610
-#define EG1 0x11614
-#define EG2 0x11618
-#define EG3 0x1161c
-#define EG4 0x11620
-#define EG5 0x11624
-#define EG6 0x11628
-#define EG7 0x1162c
-#define PXW(i) (0x11664 + (i) * 4) /* 4 registers */
-#define PXWL(i) (0x11680 + (i) * 4) /* 8 registers */
-#define LCFUSE02 0x116c0
+#define OGW0 _MMIO(0x11608)
+#define OGW1 _MMIO(0x1160c)
+#define EG0 _MMIO(0x11610)
+#define EG1 _MMIO(0x11614)
+#define EG2 _MMIO(0x11618)
+#define EG3 _MMIO(0x1161c)
+#define EG4 _MMIO(0x11620)
+#define EG5 _MMIO(0x11624)
+#define EG6 _MMIO(0x11628)
+#define EG7 _MMIO(0x1162c)
+#define PXW(i) _MMIO(0x11664 + (i) * 4) /* 4 registers */
+#define PXWL(i) _MMIO(0x11680 + (i) * 8) /* 8 registers */
+#define LCFUSE02 _MMIO(0x116c0)
#define LCFUSE_HIV_MASK 0x000000ff
-#define CSIPLL0 0x12c10
-#define DDRMPLL1 0X12c20
-#define PEG_BAND_GAP_DATA 0x14d68
+#define CSIPLL0 _MMIO(0x12c10)
+#define DDRMPLL1 _MMIO(0X12c20)
+#define PEG_BAND_GAP_DATA _MMIO(0x14d68)
-#define GEN6_GT_THREAD_STATUS_REG 0x13805c
+#define GEN6_GT_THREAD_STATUS_REG _MMIO(0x13805c)
#define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7
-#define GEN6_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x5948)
-#define BXT_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x7070)
-#define GEN6_RP_STATE_LIMITS (MCHBAR_MIRROR_BASE_SNB + 0x5994)
-#define GEN6_RP_STATE_CAP (MCHBAR_MIRROR_BASE_SNB + 0x5998)
-#define BXT_RP_STATE_CAP 0x138170
+#define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948)
+#define BXT_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7070)
+#define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994)
+#define GEN6_RP_STATE_CAP _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998)
+#define BXT_RP_STATE_CAP _MMIO(0x138170)
#define INTERVAL_1_28_US(us) (((us) * 100) >> 7)
#define INTERVAL_1_33_US(us) (((us) * 3) >> 2)
@@ -2850,7 +2910,7 @@ enum skl_disp_power_wells {
/*
* Logical Context regs
*/
-#define CCID 0x2180
+#define CCID _MMIO(0x2180)
#define CCID_EN (1<<0)
/*
* Notes on SNB/IVB/VLV context size:
@@ -2865,7 +2925,7 @@ enum skl_disp_power_wells {
* - GT1 size just indicates how much of render context
* doesn't need saving on GT1
*/
-#define CXT_SIZE 0x21a0
+#define CXT_SIZE _MMIO(0x21a0)
#define GEN6_CXT_POWER_SIZE(cxt_reg) (((cxt_reg) >> 24) & 0x3f)
#define GEN6_CXT_RING_SIZE(cxt_reg) (((cxt_reg) >> 18) & 0x3f)
#define GEN6_CXT_RENDER_SIZE(cxt_reg) (((cxt_reg) >> 12) & 0x3f)
@@ -2874,7 +2934,7 @@ enum skl_disp_power_wells {
#define GEN6_CXT_TOTAL_SIZE(cxt_reg) (GEN6_CXT_RING_SIZE(cxt_reg) + \
GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \
GEN6_CXT_PIPELINE_SIZE(cxt_reg))
-#define GEN7_CXT_SIZE 0x21a8
+#define GEN7_CXT_SIZE _MMIO(0x21a8)
#define GEN7_CXT_POWER_SIZE(ctx_reg) (((ctx_reg) >> 25) & 0x7f)
#define GEN7_CXT_RING_SIZE(ctx_reg) (((ctx_reg) >> 22) & 0x7)
#define GEN7_CXT_RENDER_SIZE(ctx_reg) (((ctx_reg) >> 16) & 0x3f)
@@ -2894,23 +2954,30 @@ enum skl_disp_power_wells {
/* Same as Haswell, but 72064 bytes now. */
#define GEN8_CXT_TOTAL_SIZE (18 * PAGE_SIZE)
-#define CHV_CLK_CTL1 0x101100
-#define VLV_CLK_CTL2 0x101104
+#define CHV_CLK_CTL1 _MMIO(0x101100)
+#define VLV_CLK_CTL2 _MMIO(0x101104)
#define CLK_CTL2_CZCOUNT_30NS_SHIFT 28
/*
* Overlay regs
*/
-#define OVADD 0x30000
-#define DOVSTA 0x30008
+#define OVADD _MMIO(0x30000)
+#define DOVSTA _MMIO(0x30008)
#define OC_BUF (0x3<<20)
-#define OGAMC5 0x30010
-#define OGAMC4 0x30014
-#define OGAMC3 0x30018
-#define OGAMC2 0x3001c
-#define OGAMC1 0x30020
-#define OGAMC0 0x30024
+#define OGAMC5 _MMIO(0x30010)
+#define OGAMC4 _MMIO(0x30014)
+#define OGAMC3 _MMIO(0x30018)
+#define OGAMC2 _MMIO(0x3001c)
+#define OGAMC1 _MMIO(0x30020)
+#define OGAMC0 _MMIO(0x30024)
+
+/*
+ * GEN9 clock gating regs
+ */
+#define GEN9_CLKGATE_DIS_0 _MMIO(0x46530)
+#define PWM2_GATING_DIS (1 << 14)
+#define PWM1_GATING_DIS (1 << 13)
/*
* Display engine regs
@@ -2970,28 +3037,18 @@ enum skl_disp_power_wells {
#define _PIPE_CRC_RES_4_B_IVB 0x61070
#define _PIPE_CRC_RES_5_B_IVB 0x61074
-#define PIPE_CRC_CTL(pipe) _TRANSCODER2(pipe, _PIPE_CRC_CTL_A)
-#define PIPE_CRC_RES_1_IVB(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_1_A_IVB)
-#define PIPE_CRC_RES_2_IVB(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_2_A_IVB)
-#define PIPE_CRC_RES_3_IVB(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_3_A_IVB)
-#define PIPE_CRC_RES_4_IVB(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_4_A_IVB)
-#define PIPE_CRC_RES_5_IVB(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_5_A_IVB)
-
-#define PIPE_CRC_RES_RED(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_RED_A)
-#define PIPE_CRC_RES_GREEN(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_GREEN_A)
-#define PIPE_CRC_RES_BLUE(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_BLUE_A)
-#define PIPE_CRC_RES_RES1_I915(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_RES1_A_I915)
-#define PIPE_CRC_RES_RES2_G4X(pipe) \
- _TRANSCODER2(pipe, _PIPE_CRC_RES_RES2_A_G4X)
+#define PIPE_CRC_CTL(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_CTL_A)
+#define PIPE_CRC_RES_1_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_1_A_IVB)
+#define PIPE_CRC_RES_2_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_2_A_IVB)
+#define PIPE_CRC_RES_3_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_3_A_IVB)
+#define PIPE_CRC_RES_4_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_4_A_IVB)
+#define PIPE_CRC_RES_5_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_5_A_IVB)
+
+#define PIPE_CRC_RES_RED(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_RED_A)
+#define PIPE_CRC_RES_GREEN(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_GREEN_A)
+#define PIPE_CRC_RES_BLUE(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_BLUE_A)
+#define PIPE_CRC_RES_RES1_I915(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_RES1_A_I915)
+#define PIPE_CRC_RES_RES2_G4X(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_RES2_A_G4X)
/* Pipe A timing regs */
#define _HTOTAL_A 0x60000
@@ -3023,20 +3080,20 @@ enum skl_disp_power_wells {
#define CHV_TRANSCODER_C_OFFSET 0x63000
#define TRANSCODER_EDP_OFFSET 0x6f000
-#define _TRANSCODER2(pipe, reg) (dev_priv->info.trans_offsets[(pipe)] - \
+#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 HTOTAL(trans) _TRANSCODER2(trans, _HTOTAL_A)
-#define HBLANK(trans) _TRANSCODER2(trans, _HBLANK_A)
-#define HSYNC(trans) _TRANSCODER2(trans, _HSYNC_A)
-#define VTOTAL(trans) _TRANSCODER2(trans, _VTOTAL_A)
-#define VBLANK(trans) _TRANSCODER2(trans, _VBLANK_A)
-#define VSYNC(trans) _TRANSCODER2(trans, _VSYNC_A)
-#define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A)
-#define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A)
-#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
-#define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A)
+#define HTOTAL(trans) _MMIO_TRANS2(trans, _HTOTAL_A)
+#define HBLANK(trans) _MMIO_TRANS2(trans, _HBLANK_A)
+#define HSYNC(trans) _MMIO_TRANS2(trans, _HSYNC_A)
+#define VTOTAL(trans) _MMIO_TRANS2(trans, _VTOTAL_A)
+#define VBLANK(trans) _MMIO_TRANS2(trans, _VBLANK_A)
+#define VSYNC(trans) _MMIO_TRANS2(trans, _VSYNC_A)
+#define BCLRPAT(trans) _MMIO_TRANS2(trans, _BCLRPAT_A)
+#define VSYNCSHIFT(trans) _MMIO_TRANS2(trans, _VSYNCSHIFT_A)
+#define PIPESRC(trans) _MMIO_TRANS2(trans, _PIPEASRC)
+#define PIPE_MULT(trans) _MMIO_TRANS2(trans, _PIPE_MULT_A)
/* VLV eDP PSR registers */
#define _PSRCTLA (VLV_DISPLAY_BASE + 0x60090)
@@ -3052,14 +3109,14 @@ enum skl_disp_power_wells {
#define VLV_EDP_PSR_DBL_FRAME (1<<10)
#define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff<<16)
#define VLV_EDP_PSR_IDLE_FRAME_SHIFT 16
-#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+#define VLV_PSRCTL(pipe) _MMIO_PIPE(pipe, _PSRCTLA, _PSRCTLB)
#define _VSCSDPA (VLV_DISPLAY_BASE + 0x600a0)
#define _VSCSDPB (VLV_DISPLAY_BASE + 0x610a0)
#define VLV_EDP_PSR_SDP_FREQ_MASK (3<<30)
#define VLV_EDP_PSR_SDP_FREQ_ONCE (1<<31)
#define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1<<30)
-#define VLV_VSCSDP(pipe) _PIPE(pipe, _VSCSDPA, _VSCSDPB)
+#define VLV_VSCSDP(pipe) _MMIO_PIPE(pipe, _VSCSDPA, _VSCSDPB)
#define _PSRSTATA (VLV_DISPLAY_BASE + 0x60094)
#define _PSRSTATB (VLV_DISPLAY_BASE + 0x61094)
@@ -3072,11 +3129,12 @@ enum skl_disp_power_wells {
#define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4<<0)
#define VLV_EDP_PSR_EXIT (5<<0)
#define VLV_EDP_PSR_IN_TRANS (1<<7)
-#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+#define VLV_PSRSTAT(pipe) _MMIO_PIPE(pipe, _PSRSTATA, _PSRSTATB)
/* HSW+ eDP PSR registers */
-#define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
-#define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0)
+#define HSW_EDP_PSR_BASE 0x64800
+#define BDW_EDP_PSR_BASE 0x6f800
+#define EDP_PSR_CTL _MMIO(dev_priv->psr_mmio_base + 0)
#define EDP_PSR_ENABLE (1<<31)
#define BDW_PSR_SINGLE_FRAME (1<<30)
#define EDP_PSR_LINK_STANDBY (1<<27)
@@ -3099,14 +3157,10 @@ enum skl_disp_power_wells {
#define EDP_PSR_TP1_TIME_0us (3<<4)
#define EDP_PSR_IDLE_FRAME_SHIFT 0
-#define EDP_PSR_AUX_CTL(dev) (EDP_PSR_BASE(dev) + 0x10)
-#define EDP_PSR_AUX_DATA1(dev) (EDP_PSR_BASE(dev) + 0x14)
-#define EDP_PSR_AUX_DATA2(dev) (EDP_PSR_BASE(dev) + 0x18)
-#define EDP_PSR_AUX_DATA3(dev) (EDP_PSR_BASE(dev) + 0x1c)
-#define EDP_PSR_AUX_DATA4(dev) (EDP_PSR_BASE(dev) + 0x20)
-#define EDP_PSR_AUX_DATA5(dev) (EDP_PSR_BASE(dev) + 0x24)
+#define EDP_PSR_AUX_CTL _MMIO(dev_priv->psr_mmio_base + 0x10)
+#define EDP_PSR_AUX_DATA(i) _MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */
-#define EDP_PSR_STATUS_CTL(dev) (EDP_PSR_BASE(dev) + 0x40)
+#define EDP_PSR_STATUS_CTL _MMIO(dev_priv->psr_mmio_base + 0x40)
#define EDP_PSR_STATUS_STATE_MASK (7<<29)
#define EDP_PSR_STATUS_STATE_IDLE (0<<29)
#define EDP_PSR_STATUS_STATE_SRDONACK (1<<29)
@@ -3130,15 +3184,15 @@ enum skl_disp_power_wells {
#define EDP_PSR_STATUS_SENDING_TP1 (1<<4)
#define EDP_PSR_STATUS_IDLE_MASK 0xf
-#define EDP_PSR_PERF_CNT(dev) (EDP_PSR_BASE(dev) + 0x44)
+#define EDP_PSR_PERF_CNT _MMIO(dev_priv->psr_mmio_base + 0x44)
#define EDP_PSR_PERF_CNT_MASK 0xffffff
-#define EDP_PSR_DEBUG_CTL(dev) (EDP_PSR_BASE(dev) + 0x60)
+#define EDP_PSR_DEBUG_CTL _MMIO(dev_priv->psr_mmio_base + 0x60)
#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_PSR2_CTL 0x6f900
+#define EDP_PSR2_CTL _MMIO(0x6f900)
#define EDP_PSR2_ENABLE (1<<31)
#define EDP_SU_TRACK_ENABLE (1<<30)
#define EDP_MAX_SU_DISABLE_TIME(t) ((t)<<20)
@@ -3153,9 +3207,9 @@ enum skl_disp_power_wells {
#define EDP_PSR2_IDLE_MASK 0xf
/* VGA port control */
-#define ADPA 0x61100
-#define PCH_ADPA 0xe1100
-#define VLV_ADPA (VLV_DISPLAY_BASE + ADPA)
+#define ADPA _MMIO(0x61100)
+#define PCH_ADPA _MMIO(0xe1100)
+#define VLV_ADPA _MMIO(VLV_DISPLAY_BASE + 0x61100)
#define ADPA_DAC_ENABLE (1<<31)
#define ADPA_DAC_DISABLE 0
@@ -3201,7 +3255,7 @@ enum skl_disp_power_wells {
/* Hotplug control (945+ only) */
-#define PORT_HOTPLUG_EN (dev_priv->info.display_mmio_offset + 0x61110)
+#define PORT_HOTPLUG_EN _MMIO(dev_priv->info.display_mmio_offset + 0x61110)
#define PORTB_HOTPLUG_INT_EN (1 << 29)
#define PORTC_HOTPLUG_INT_EN (1 << 28)
#define PORTD_HOTPLUG_INT_EN (1 << 27)
@@ -3231,7 +3285,7 @@ enum skl_disp_power_wells {
#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
-#define PORT_HOTPLUG_STAT (dev_priv->info.display_mmio_offset + 0x61114)
+#define PORT_HOTPLUG_STAT _MMIO(dev_priv->info.display_mmio_offset + 0x61114)
/*
* HDMI/DP bits are gen4+
*
@@ -3296,21 +3350,23 @@ enum skl_disp_power_wells {
/* SDVO and HDMI port control.
* The same register may be used for SDVO or HDMI */
-#define GEN3_SDVOB 0x61140
-#define GEN3_SDVOC 0x61160
+#define _GEN3_SDVOB 0x61140
+#define _GEN3_SDVOC 0x61160
+#define GEN3_SDVOB _MMIO(_GEN3_SDVOB)
+#define GEN3_SDVOC _MMIO(_GEN3_SDVOC)
#define GEN4_HDMIB GEN3_SDVOB
#define GEN4_HDMIC GEN3_SDVOC
-#define VLV_HDMIB (VLV_DISPLAY_BASE + GEN4_HDMIB)
-#define VLV_HDMIC (VLV_DISPLAY_BASE + GEN4_HDMIC)
-#define CHV_HDMID (VLV_DISPLAY_BASE + 0x6116C)
-#define PCH_SDVOB 0xe1140
+#define VLV_HDMIB _MMIO(VLV_DISPLAY_BASE + 0x61140)
+#define VLV_HDMIC _MMIO(VLV_DISPLAY_BASE + 0x61160)
+#define CHV_HDMID _MMIO(VLV_DISPLAY_BASE + 0x6116C)
+#define PCH_SDVOB _MMIO(0xe1140)
#define PCH_HDMIB PCH_SDVOB
-#define PCH_HDMIC 0xe1150
-#define PCH_HDMID 0xe1160
+#define PCH_HDMIC _MMIO(0xe1150)
+#define PCH_HDMID _MMIO(0xe1160)
-#define PORT_DFT_I9XX 0x61150
+#define PORT_DFT_I9XX _MMIO(0x61150)
#define DC_BALANCE_RESET (1 << 25)
-#define PORT_DFT2_G4X (dev_priv->info.display_mmio_offset + 0x61154)
+#define PORT_DFT2_G4X _MMIO(dev_priv->info.display_mmio_offset + 0x61154)
#define DC_BALANCE_RESET_VLV (1 << 31)
#define PIPE_SCRAMBLE_RESET_MASK ((1 << 14) | (0x3 << 0))
#define PIPE_C_SCRAMBLE_RESET (1 << 14) /* chv */
@@ -3370,9 +3426,12 @@ enum skl_disp_power_wells {
/* DVO port control */
-#define DVOA 0x61120
-#define DVOB 0x61140
-#define DVOC 0x61160
+#define _DVOA 0x61120
+#define DVOA _MMIO(_DVOA)
+#define _DVOB 0x61140
+#define DVOB _MMIO(_DVOB)
+#define _DVOC 0x61160
+#define DVOC _MMIO(_DVOC)
#define DVO_ENABLE (1 << 31)
#define DVO_PIPE_B_SELECT (1 << 30)
#define DVO_PIPE_STALL_UNUSED (0 << 28)
@@ -3397,14 +3456,14 @@ enum skl_disp_power_wells {
#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */
#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */
#define DVO_PRESERVE_MASK (0x7<<24)
-#define DVOA_SRCDIM 0x61124
-#define DVOB_SRCDIM 0x61144
-#define DVOC_SRCDIM 0x61164
+#define DVOA_SRCDIM _MMIO(0x61124)
+#define DVOB_SRCDIM _MMIO(0x61144)
+#define DVOC_SRCDIM _MMIO(0x61164)
#define DVO_SRCDIM_HORIZONTAL_SHIFT 12
#define DVO_SRCDIM_VERTICAL_SHIFT 0
/* LVDS port control */
-#define LVDS 0x61180
+#define LVDS _MMIO(0x61180)
/*
* Enables the LVDS port. This bit must be set before DPLLs are enabled, as
* the DPLL semantics change when the LVDS is assigned to that pipe.
@@ -3454,13 +3513,13 @@ enum skl_disp_power_wells {
#define LVDS_B0B3_POWER_UP (3 << 2)
/* Video Data Island Packet control */
-#define VIDEO_DIP_DATA 0x61178
+#define VIDEO_DIP_DATA _MMIO(0x61178)
/* Read the description of VIDEO_DIP_DATA (before Haswell) or VIDEO_DIP_ECC
* (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
* of the infoframe structure specified by CEA-861. */
#define VIDEO_DIP_DATA_SIZE 32
#define VIDEO_DIP_VSC_DATA_SIZE 36
-#define VIDEO_DIP_CTL 0x61170
+#define VIDEO_DIP_CTL _MMIO(0x61170)
/* Pre HSW: */
#define VIDEO_DIP_ENABLE (1 << 31)
#define VIDEO_DIP_PORT(port) ((port) << 29)
@@ -3487,7 +3546,7 @@ enum skl_disp_power_wells {
#define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0)
/* Panel power sequencing */
-#define PP_STATUS 0x61200
+#define PP_STATUS _MMIO(0x61200)
#define PP_ON (1 << 31)
/*
* Indicates that all dependencies of the panel are on:
@@ -3513,14 +3572,14 @@ enum skl_disp_power_wells {
#define PP_SEQUENCE_STATE_ON_S1_2 (0xa << 0)
#define PP_SEQUENCE_STATE_ON_S1_3 (0xb << 0)
#define PP_SEQUENCE_STATE_RESET (0xf << 0)
-#define PP_CONTROL 0x61204
+#define PP_CONTROL _MMIO(0x61204)
#define POWER_TARGET_ON (1 << 0)
-#define PP_ON_DELAYS 0x61208
-#define PP_OFF_DELAYS 0x6120c
-#define PP_DIVISOR 0x61210
+#define PP_ON_DELAYS _MMIO(0x61208)
+#define PP_OFF_DELAYS _MMIO(0x6120c)
+#define PP_DIVISOR _MMIO(0x61210)
/* Panel fitting */
-#define PFIT_CONTROL (dev_priv->info.display_mmio_offset + 0x61230)
+#define PFIT_CONTROL _MMIO(dev_priv->info.display_mmio_offset + 0x61230)
#define PFIT_ENABLE (1 << 31)
#define PFIT_PIPE_MASK (3 << 29)
#define PFIT_PIPE_SHIFT 29
@@ -3538,7 +3597,7 @@ enum skl_disp_power_wells {
#define PFIT_SCALING_PROGRAMMED (1 << 26)
#define PFIT_SCALING_PILLAR (2 << 26)
#define PFIT_SCALING_LETTER (3 << 26)
-#define PFIT_PGM_RATIOS (dev_priv->info.display_mmio_offset + 0x61234)
+#define PFIT_PGM_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61234)
/* Pre-965 */
#define PFIT_VERT_SCALE_SHIFT 20
#define PFIT_VERT_SCALE_MASK 0xfff00000
@@ -3550,25 +3609,25 @@ enum skl_disp_power_wells {
#define PFIT_HORIZ_SCALE_SHIFT_965 0
#define PFIT_HORIZ_SCALE_MASK_965 0x00001fff
-#define PFIT_AUTO_RATIOS (dev_priv->info.display_mmio_offset + 0x61238)
+#define PFIT_AUTO_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61238)
#define _VLV_BLC_PWM_CTL2_A (dev_priv->info.display_mmio_offset + 0x61250)
#define _VLV_BLC_PWM_CTL2_B (dev_priv->info.display_mmio_offset + 0x61350)
-#define VLV_BLC_PWM_CTL2(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
- _VLV_BLC_PWM_CTL2_B)
+#define VLV_BLC_PWM_CTL2(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
+ _VLV_BLC_PWM_CTL2_B)
#define _VLV_BLC_PWM_CTL_A (dev_priv->info.display_mmio_offset + 0x61254)
#define _VLV_BLC_PWM_CTL_B (dev_priv->info.display_mmio_offset + 0x61354)
-#define VLV_BLC_PWM_CTL(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
- _VLV_BLC_PWM_CTL_B)
+#define VLV_BLC_PWM_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
+ _VLV_BLC_PWM_CTL_B)
#define _VLV_BLC_HIST_CTL_A (dev_priv->info.display_mmio_offset + 0x61260)
#define _VLV_BLC_HIST_CTL_B (dev_priv->info.display_mmio_offset + 0x61360)
-#define VLV_BLC_HIST_CTL(pipe) _PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
- _VLV_BLC_HIST_CTL_B)
+#define VLV_BLC_HIST_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
+ _VLV_BLC_HIST_CTL_B)
/* Backlight control */
-#define BLC_PWM_CTL2 (dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */
+#define BLC_PWM_CTL2 _MMIO(dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */
#define BLM_PWM_ENABLE (1 << 31)
#define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */
#define BLM_PIPE_SELECT (1 << 29)
@@ -3591,7 +3650,7 @@ enum skl_disp_power_wells {
#define BLM_PHASE_IN_COUNT_MASK (0xff << 8)
#define BLM_PHASE_IN_INCR_SHIFT (0)
#define BLM_PHASE_IN_INCR_MASK (0xff << 0)
-#define BLC_PWM_CTL (dev_priv->info.display_mmio_offset + 0x61254)
+#define BLC_PWM_CTL _MMIO(dev_priv->info.display_mmio_offset + 0x61254)
/*
* This is the most significant 15 bits of the number of backlight cycles in a
* complete cycle of the modulated backlight control.
@@ -3613,25 +3672,25 @@ enum skl_disp_power_wells {
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe)
#define BLM_POLARITY_PNV (1 << 0) /* pnv only */
-#define BLC_HIST_CTL (dev_priv->info.display_mmio_offset + 0x61260)
+#define BLC_HIST_CTL _MMIO(dev_priv->info.display_mmio_offset + 0x61260)
#define BLM_HISTOGRAM_ENABLE (1 << 31)
/* New registers for PCH-split platforms. Safe where new bits show up, the
* register layout machtes with gen4 BLC_PWM_CTL[12]. */
-#define BLC_PWM_CPU_CTL2 0x48250
-#define BLC_PWM_CPU_CTL 0x48254
+#define BLC_PWM_CPU_CTL2 _MMIO(0x48250)
+#define BLC_PWM_CPU_CTL _MMIO(0x48254)
-#define HSW_BLC_PWM2_CTL 0x48350
+#define HSW_BLC_PWM2_CTL _MMIO(0x48350)
/* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is
* like the normal CTL from gen4 and earlier. Hooray for confusing naming. */
-#define BLC_PWM_PCH_CTL1 0xc8250
+#define BLC_PWM_PCH_CTL1 _MMIO(0xc8250)
#define BLM_PCH_PWM_ENABLE (1 << 31)
#define BLM_PCH_OVERRIDE_ENABLE (1 << 30)
#define BLM_PCH_POLARITY (1 << 29)
-#define BLC_PWM_PCH_CTL2 0xc8254
+#define BLC_PWM_PCH_CTL2 _MMIO(0xc8254)
-#define UTIL_PIN_CTL 0x48400
+#define UTIL_PIN_CTL _MMIO(0x48400)
#define UTIL_PIN_ENABLE (1 << 31)
#define UTIL_PIN_PIPE(x) ((x) << 29)
@@ -3651,18 +3710,18 @@ enum skl_disp_power_wells {
#define _BXT_BLC_PWM_FREQ2 0xC8354
#define _BXT_BLC_PWM_DUTY2 0xC8358
-#define BXT_BLC_PWM_CTL(controller) _PIPE(controller, \
+#define BXT_BLC_PWM_CTL(controller) _MMIO_PIPE(controller, \
_BXT_BLC_PWM_CTL1, _BXT_BLC_PWM_CTL2)
-#define BXT_BLC_PWM_FREQ(controller) _PIPE(controller, \
+#define BXT_BLC_PWM_FREQ(controller) _MMIO_PIPE(controller, \
_BXT_BLC_PWM_FREQ1, _BXT_BLC_PWM_FREQ2)
-#define BXT_BLC_PWM_DUTY(controller) _PIPE(controller, \
+#define BXT_BLC_PWM_DUTY(controller) _MMIO_PIPE(controller, \
_BXT_BLC_PWM_DUTY1, _BXT_BLC_PWM_DUTY2)
-#define PCH_GTC_CTL 0xe7000
+#define PCH_GTC_CTL _MMIO(0xe7000)
#define PCH_GTC_ENABLE (1 << 31)
/* TV port control */
-#define TV_CTL 0x68000
+#define TV_CTL _MMIO(0x68000)
/* Enables the TV encoder */
# define TV_ENC_ENABLE (1 << 31)
/* Sources the TV encoder input from pipe B instead of A. */
@@ -3729,7 +3788,7 @@ enum skl_disp_power_wells {
# define TV_TEST_MODE_MONITOR_DETECT (7 << 0)
# define TV_TEST_MODE_MASK (7 << 0)
-#define TV_DAC 0x68004
+#define TV_DAC _MMIO(0x68004)
# define TV_DAC_SAVE 0x00ffff00
/*
* Reports that DAC state change logic has reported change (RO).
@@ -3780,13 +3839,13 @@ enum skl_disp_power_wells {
* where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
* -1 (0x3) being the only legal negative value.
*/
-#define TV_CSC_Y 0x68010
+#define TV_CSC_Y _MMIO(0x68010)
# define TV_RY_MASK 0x07ff0000
# define TV_RY_SHIFT 16
# define TV_GY_MASK 0x00000fff
# define TV_GY_SHIFT 0
-#define TV_CSC_Y2 0x68014
+#define TV_CSC_Y2 _MMIO(0x68014)
# define TV_BY_MASK 0x07ff0000
# define TV_BY_SHIFT 16
/*
@@ -3797,13 +3856,13 @@ enum skl_disp_power_wells {
# define TV_AY_MASK 0x000003ff
# define TV_AY_SHIFT 0
-#define TV_CSC_U 0x68018
+#define TV_CSC_U _MMIO(0x68018)
# define TV_RU_MASK 0x07ff0000
# define TV_RU_SHIFT 16
# define TV_GU_MASK 0x000007ff
# define TV_GU_SHIFT 0
-#define TV_CSC_U2 0x6801c
+#define TV_CSC_U2 _MMIO(0x6801c)
# define TV_BU_MASK 0x07ff0000
# define TV_BU_SHIFT 16
/*
@@ -3814,13 +3873,13 @@ enum skl_disp_power_wells {
# define TV_AU_MASK 0x000003ff
# define TV_AU_SHIFT 0
-#define TV_CSC_V 0x68020
+#define TV_CSC_V _MMIO(0x68020)
# define TV_RV_MASK 0x0fff0000
# define TV_RV_SHIFT 16
# define TV_GV_MASK 0x000007ff
# define TV_GV_SHIFT 0
-#define TV_CSC_V2 0x68024
+#define TV_CSC_V2 _MMIO(0x68024)
# define TV_BV_MASK 0x07ff0000
# define TV_BV_SHIFT 16
/*
@@ -3831,7 +3890,7 @@ enum skl_disp_power_wells {
# define TV_AV_MASK 0x000007ff
# define TV_AV_SHIFT 0
-#define TV_CLR_KNOBS 0x68028
+#define TV_CLR_KNOBS _MMIO(0x68028)
/* 2s-complement brightness adjustment */
# define TV_BRIGHTNESS_MASK 0xff000000
# define TV_BRIGHTNESS_SHIFT 24
@@ -3845,7 +3904,7 @@ enum skl_disp_power_wells {
# define TV_HUE_MASK 0x000000ff
# define TV_HUE_SHIFT 0
-#define TV_CLR_LEVEL 0x6802c
+#define TV_CLR_LEVEL _MMIO(0x6802c)
/* Controls the DAC level for black */
# define TV_BLACK_LEVEL_MASK 0x01ff0000
# define TV_BLACK_LEVEL_SHIFT 16
@@ -3853,7 +3912,7 @@ enum skl_disp_power_wells {
# define TV_BLANK_LEVEL_MASK 0x000001ff
# define TV_BLANK_LEVEL_SHIFT 0
-#define TV_H_CTL_1 0x68030
+#define TV_H_CTL_1 _MMIO(0x68030)
/* Number of pixels in the hsync. */
# define TV_HSYNC_END_MASK 0x1fff0000
# define TV_HSYNC_END_SHIFT 16
@@ -3861,7 +3920,7 @@ enum skl_disp_power_wells {
# define TV_HTOTAL_MASK 0x00001fff
# define TV_HTOTAL_SHIFT 0
-#define TV_H_CTL_2 0x68034
+#define TV_H_CTL_2 _MMIO(0x68034)
/* Enables the colorburst (needed for non-component color) */
# define TV_BURST_ENA (1 << 31)
/* Offset of the colorburst from the start of hsync, in pixels minus one. */
@@ -3871,7 +3930,7 @@ enum skl_disp_power_wells {
# define TV_HBURST_LEN_SHIFT 0
# define TV_HBURST_LEN_MASK 0x0001fff
-#define TV_H_CTL_3 0x68038
+#define TV_H_CTL_3 _MMIO(0x68038)
/* End of hblank, measured in pixels minus one from start of hsync */
# define TV_HBLANK_END_SHIFT 16
# define TV_HBLANK_END_MASK 0x1fff0000
@@ -3879,7 +3938,7 @@ enum skl_disp_power_wells {
# define TV_HBLANK_START_SHIFT 0
# define TV_HBLANK_START_MASK 0x0001fff
-#define TV_V_CTL_1 0x6803c
+#define TV_V_CTL_1 _MMIO(0x6803c)
/* XXX */
# define TV_NBR_END_SHIFT 16
# define TV_NBR_END_MASK 0x07ff0000
@@ -3890,7 +3949,7 @@ enum skl_disp_power_wells {
# define TV_VI_END_F2_SHIFT 0
# define TV_VI_END_F2_MASK 0x0000003f
-#define TV_V_CTL_2 0x68040
+#define TV_V_CTL_2 _MMIO(0x68040)
/* Length of vsync, in half lines */
# define TV_VSYNC_LEN_MASK 0x07ff0000
# define TV_VSYNC_LEN_SHIFT 16
@@ -3906,7 +3965,7 @@ enum skl_disp_power_wells {
# define TV_VSYNC_START_F2_MASK 0x0000007f
# define TV_VSYNC_START_F2_SHIFT 0
-#define TV_V_CTL_3 0x68044
+#define TV_V_CTL_3 _MMIO(0x68044)
/* Enables generation of the equalization signal */
# define TV_EQUAL_ENA (1 << 31)
/* Length of vsync, in half lines */
@@ -3924,7 +3983,7 @@ enum skl_disp_power_wells {
# define TV_VEQ_START_F2_MASK 0x000007f
# define TV_VEQ_START_F2_SHIFT 0
-#define TV_V_CTL_4 0x68048
+#define TV_V_CTL_4 _MMIO(0x68048)
/*
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
@@ -3938,7 +3997,7 @@ enum skl_disp_power_wells {
# define TV_VBURST_END_F1_MASK 0x000000ff
# define TV_VBURST_END_F1_SHIFT 0
-#define TV_V_CTL_5 0x6804c
+#define TV_V_CTL_5 _MMIO(0x6804c)
/*
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
@@ -3952,7 +4011,7 @@ enum skl_disp_power_wells {
# define TV_VBURST_END_F2_MASK 0x000000ff
# define TV_VBURST_END_F2_SHIFT 0
-#define TV_V_CTL_6 0x68050
+#define TV_V_CTL_6 _MMIO(0x68050)
/*
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
@@ -3966,7 +4025,7 @@ enum skl_disp_power_wells {
# define TV_VBURST_END_F3_MASK 0x000000ff
# define TV_VBURST_END_F3_SHIFT 0
-#define TV_V_CTL_7 0x68054
+#define TV_V_CTL_7 _MMIO(0x68054)
/*
* Offset to start of vertical colorburst, measured in one less than the
* number of lines from vertical start.
@@ -3980,7 +4039,7 @@ enum skl_disp_power_wells {
# define TV_VBURST_END_F4_MASK 0x000000ff
# define TV_VBURST_END_F4_SHIFT 0
-#define TV_SC_CTL_1 0x68060
+#define TV_SC_CTL_1 _MMIO(0x68060)
/* Turns on the first subcarrier phase generation DDA */
# define TV_SC_DDA1_EN (1 << 31)
/* Turns on the first subcarrier phase generation DDA */
@@ -4002,7 +4061,7 @@ enum skl_disp_power_wells {
# define TV_SCDDA1_INC_MASK 0x00000fff
# define TV_SCDDA1_INC_SHIFT 0
-#define TV_SC_CTL_2 0x68064
+#define TV_SC_CTL_2 _MMIO(0x68064)
/* Sets the rollover for the second subcarrier phase generation DDA */
# define TV_SCDDA2_SIZE_MASK 0x7fff0000
# define TV_SCDDA2_SIZE_SHIFT 16
@@ -4010,7 +4069,7 @@ enum skl_disp_power_wells {
# define TV_SCDDA2_INC_MASK 0x00007fff
# define TV_SCDDA2_INC_SHIFT 0
-#define TV_SC_CTL_3 0x68068
+#define TV_SC_CTL_3 _MMIO(0x68068)
/* Sets the rollover for the third subcarrier phase generation DDA */
# define TV_SCDDA3_SIZE_MASK 0x7fff0000
# define TV_SCDDA3_SIZE_SHIFT 16
@@ -4018,7 +4077,7 @@ enum skl_disp_power_wells {
# define TV_SCDDA3_INC_MASK 0x00007fff
# define TV_SCDDA3_INC_SHIFT 0
-#define TV_WIN_POS 0x68070
+#define TV_WIN_POS _MMIO(0x68070)
/* X coordinate of the display from the start of horizontal active */
# define TV_XPOS_MASK 0x1fff0000
# define TV_XPOS_SHIFT 16
@@ -4026,7 +4085,7 @@ enum skl_disp_power_wells {
# define TV_YPOS_MASK 0x00000fff
# define TV_YPOS_SHIFT 0
-#define TV_WIN_SIZE 0x68074
+#define TV_WIN_SIZE _MMIO(0x68074)
/* Horizontal size of the display window, measured in pixels*/
# define TV_XSIZE_MASK 0x1fff0000
# define TV_XSIZE_SHIFT 16
@@ -4038,7 +4097,7 @@ enum skl_disp_power_wells {
# define TV_YSIZE_MASK 0x00000fff
# define TV_YSIZE_SHIFT 0
-#define TV_FILTER_CTL_1 0x68080
+#define TV_FILTER_CTL_1 _MMIO(0x68080)
/*
* Enables automatic scaling calculation.
*
@@ -4071,7 +4130,7 @@ enum skl_disp_power_wells {
# define TV_HSCALE_FRAC_MASK 0x00003fff
# define TV_HSCALE_FRAC_SHIFT 0
-#define TV_FILTER_CTL_2 0x68084
+#define TV_FILTER_CTL_2 _MMIO(0x68084)
/*
* Sets the integer part of the 3.15 fixed-point vertical scaling factor.
*
@@ -4087,7 +4146,7 @@ enum skl_disp_power_wells {
# define TV_VSCALE_FRAC_MASK 0x00007fff
# define TV_VSCALE_FRAC_SHIFT 0
-#define TV_FILTER_CTL_3 0x68088
+#define TV_FILTER_CTL_3 _MMIO(0x68088)
/*
* Sets the integer part of the 3.15 fixed-point vertical scaling factor.
*
@@ -4107,7 +4166,7 @@ enum skl_disp_power_wells {
# define TV_VSCALE_IP_FRAC_MASK 0x00007fff
# define TV_VSCALE_IP_FRAC_SHIFT 0
-#define TV_CC_CONTROL 0x68090
+#define TV_CC_CONTROL _MMIO(0x68090)
# define TV_CC_ENABLE (1 << 31)
/*
* Specifies which field to send the CC data in.
@@ -4123,7 +4182,7 @@ enum skl_disp_power_wells {
# define TV_CC_LINE_MASK 0x0000003f
# define TV_CC_LINE_SHIFT 0
-#define TV_CC_DATA 0x68094
+#define TV_CC_DATA _MMIO(0x68094)
# define TV_CC_RDY (1 << 31)
/* Second word of CC data to be transmitted. */
# define TV_CC_DATA_2_MASK 0x007f0000
@@ -4132,20 +4191,20 @@ enum skl_disp_power_wells {
# define TV_CC_DATA_1_MASK 0x0000007f
# define TV_CC_DATA_1_SHIFT 0
-#define TV_H_LUMA(i) (0x68100 + (i) * 4) /* 60 registers */
-#define TV_H_CHROMA(i) (0x68200 + (i) * 4) /* 60 registers */
-#define TV_V_LUMA(i) (0x68300 + (i) * 4) /* 43 registers */
-#define TV_V_CHROMA(i) (0x68400 + (i) * 4) /* 43 registers */
+#define TV_H_LUMA(i) _MMIO(0x68100 + (i) * 4) /* 60 registers */
+#define TV_H_CHROMA(i) _MMIO(0x68200 + (i) * 4) /* 60 registers */
+#define TV_V_LUMA(i) _MMIO(0x68300 + (i) * 4) /* 43 registers */
+#define TV_V_CHROMA(i) _MMIO(0x68400 + (i) * 4) /* 43 registers */
/* Display Port */
-#define DP_A 0x64000 /* eDP */
-#define DP_B 0x64100
-#define DP_C 0x64200
-#define DP_D 0x64300
+#define DP_A _MMIO(0x64000) /* eDP */
+#define DP_B _MMIO(0x64100)
+#define DP_C _MMIO(0x64200)
+#define DP_D _MMIO(0x64300)
-#define VLV_DP_B (VLV_DISPLAY_BASE + DP_B)
-#define VLV_DP_C (VLV_DISPLAY_BASE + DP_C)
-#define CHV_DP_D (VLV_DISPLAY_BASE + DP_D)
+#define VLV_DP_B _MMIO(VLV_DISPLAY_BASE + 0x64100)
+#define VLV_DP_C _MMIO(VLV_DISPLAY_BASE + 0x64200)
+#define CHV_DP_D _MMIO(VLV_DISPLAY_BASE + 0x64300)
#define DP_PORT_EN (1 << 31)
#define DP_PIPEB_SELECT (1 << 30)
@@ -4199,7 +4258,7 @@ enum skl_disp_power_wells {
/* eDP */
#define DP_PLL_FREQ_270MHZ (0 << 16)
-#define DP_PLL_FREQ_160MHZ (1 << 16)
+#define DP_PLL_FREQ_162MHZ (1 << 16)
#define DP_PLL_FREQ_MASK (3 << 16)
/* locked once port is enabled */
@@ -4232,33 +4291,36 @@ enum skl_disp_power_wells {
* is 20 bytes in each direction, hence the 5 fixed
* data registers
*/
-#define DPA_AUX_CH_CTL 0x64010
-#define DPA_AUX_CH_DATA1 0x64014
-#define DPA_AUX_CH_DATA2 0x64018
-#define DPA_AUX_CH_DATA3 0x6401c
-#define DPA_AUX_CH_DATA4 0x64020
-#define DPA_AUX_CH_DATA5 0x64024
-
-#define DPB_AUX_CH_CTL 0x64110
-#define DPB_AUX_CH_DATA1 0x64114
-#define DPB_AUX_CH_DATA2 0x64118
-#define DPB_AUX_CH_DATA3 0x6411c
-#define DPB_AUX_CH_DATA4 0x64120
-#define DPB_AUX_CH_DATA5 0x64124
-
-#define DPC_AUX_CH_CTL 0x64210
-#define DPC_AUX_CH_DATA1 0x64214
-#define DPC_AUX_CH_DATA2 0x64218
-#define DPC_AUX_CH_DATA3 0x6421c
-#define DPC_AUX_CH_DATA4 0x64220
-#define DPC_AUX_CH_DATA5 0x64224
-
-#define DPD_AUX_CH_CTL 0x64310
-#define DPD_AUX_CH_DATA1 0x64314
-#define DPD_AUX_CH_DATA2 0x64318
-#define DPD_AUX_CH_DATA3 0x6431c
-#define DPD_AUX_CH_DATA4 0x64320
-#define DPD_AUX_CH_DATA5 0x64324
+#define _DPA_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64010)
+#define _DPA_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64014)
+#define _DPA_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64018)
+#define _DPA_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6401c)
+#define _DPA_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64020)
+#define _DPA_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64024)
+
+#define _DPB_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64110)
+#define _DPB_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64114)
+#define _DPB_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64118)
+#define _DPB_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6411c)
+#define _DPB_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64120)
+#define _DPB_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64124)
+
+#define _DPC_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64210)
+#define _DPC_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64214)
+#define _DPC_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64218)
+#define _DPC_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6421c)
+#define _DPC_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64220)
+#define _DPC_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64224)
+
+#define _DPD_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64310)
+#define _DPD_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64314)
+#define _DPD_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64318)
+#define _DPD_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6431c)
+#define _DPD_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64320)
+#define _DPD_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64324)
+
+#define DP_AUX_CH_CTL(port) _MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)
+#define DP_AUX_CH_DATA(port, i) _MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31)
#define DP_AUX_CH_CTL_DONE (1 << 30)
@@ -4335,10 +4397,10 @@ enum skl_disp_power_wells {
#define _PIPEB_LINK_N_G4X 0x71064
#define PIPEA_DP_LINK_N_MASK (0xffffff)
-#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X)
-#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X)
-#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X)
-#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X)
+#define PIPE_DATA_M_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X)
+#define PIPE_DATA_N_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X)
+#define PIPE_LINK_M_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X)
+#define PIPE_LINK_N_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X)
/* Display & cursor control */
@@ -4454,15 +4516,15 @@ enum skl_disp_power_wells {
*/
#define PIPE_EDP_OFFSET 0x7f000
-#define _PIPE2(pipe, reg) (dev_priv->info.pipe_offsets[pipe] - \
+#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 PIPECONF(pipe) _PIPE2(pipe, _PIPEACONF)
-#define PIPEDSL(pipe) _PIPE2(pipe, _PIPEADSL)
-#define PIPEFRAME(pipe) _PIPE2(pipe, _PIPEAFRAMEHIGH)
-#define PIPEFRAMEPIXEL(pipe) _PIPE2(pipe, _PIPEAFRAMEPIXEL)
-#define PIPESTAT(pipe) _PIPE2(pipe, _PIPEASTAT)
+#define PIPECONF(pipe) _MMIO_PIPE2(pipe, _PIPEACONF)
+#define PIPEDSL(pipe) _MMIO_PIPE2(pipe, _PIPEADSL)
+#define PIPEFRAME(pipe) _MMIO_PIPE2(pipe, _PIPEAFRAMEHIGH)
+#define PIPEFRAMEPIXEL(pipe) _MMIO_PIPE2(pipe, _PIPEAFRAMEPIXEL)
+#define PIPESTAT(pipe) _MMIO_PIPE2(pipe, _PIPEASTAT)
#define _PIPE_MISC_A 0x70030
#define _PIPE_MISC_B 0x71030
@@ -4474,9 +4536,9 @@ enum skl_disp_power_wells {
#define PIPEMISC_DITHER_ENABLE (1<<4)
#define PIPEMISC_DITHER_TYPE_MASK (3<<2)
#define PIPEMISC_DITHER_TYPE_SP (0<<2)
-#define PIPEMISC(pipe) _PIPE2(pipe, _PIPE_MISC_A)
+#define PIPEMISC(pipe) _MMIO_PIPE2(pipe, _PIPE_MISC_A)
-#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028)
+#define VLV_DPFLIPSTAT _MMIO(VLV_DISPLAY_BASE + 0x70028)
#define PIPEB_LINE_COMPARE_INT_EN (1<<29)
#define PIPEB_HLINE_INT_EN (1<<28)
#define PIPEB_VBLANK_INT_EN (1<<27)
@@ -4497,7 +4559,7 @@ enum skl_disp_power_wells {
#define SPRITEE_FLIPDONE_INT_EN (1<<9)
#define PLANEC_FLIPDONE_INT_EN (1<<8)
-#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */
+#define DPINVGTT _MMIO(VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */
#define SPRITEF_INVALID_GTT_INT_EN (1<<27)
#define SPRITEE_INVALID_GTT_INT_EN (1<<26)
#define PLANEC_INVALID_GTT_INT_EN (1<<25)
@@ -4527,7 +4589,7 @@ enum skl_disp_power_wells {
#define DPINVGTT_STATUS_MASK 0xff
#define DPINVGTT_STATUS_MASK_CHV 0xfff
-#define DSPARB (dev_priv->info.display_mmio_offset + 0x70030)
+#define DSPARB _MMIO(dev_priv->info.display_mmio_offset + 0x70030)
#define DSPARB_CSTART_MASK (0x7f << 7)
#define DSPARB_CSTART_SHIFT 7
#define DSPARB_BSTART_MASK (0x7f)
@@ -4542,7 +4604,7 @@ enum skl_disp_power_wells {
#define DSPARB_SPRITEC_MASK_VLV (0xff << 16)
#define DSPARB_SPRITED_SHIFT_VLV 24
#define DSPARB_SPRITED_MASK_VLV (0xff << 24)
-#define DSPARB2 (VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */
+#define DSPARB2 _MMIO(VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */
#define DSPARB_SPRITEA_HI_SHIFT_VLV 0
#define DSPARB_SPRITEA_HI_MASK_VLV (0x1 << 0)
#define DSPARB_SPRITEB_HI_SHIFT_VLV 4
@@ -4555,14 +4617,14 @@ enum skl_disp_power_wells {
#define DSPARB_SPRITEE_HI_MASK_VLV (0x1 << 16)
#define DSPARB_SPRITEF_HI_SHIFT_VLV 20
#define DSPARB_SPRITEF_HI_MASK_VLV (0x1 << 20)
-#define DSPARB3 (VLV_DISPLAY_BASE + 0x7006c) /* chv */
+#define DSPARB3 _MMIO(VLV_DISPLAY_BASE + 0x7006c) /* chv */
#define DSPARB_SPRITEE_SHIFT_VLV 0
#define DSPARB_SPRITEE_MASK_VLV (0xff << 0)
#define DSPARB_SPRITEF_SHIFT_VLV 8
#define DSPARB_SPRITEF_MASK_VLV (0xff << 8)
/* pnv/gen4/g4x/vlv/chv */
-#define DSPFW1 (dev_priv->info.display_mmio_offset + 0x70034)
+#define DSPFW1 _MMIO(dev_priv->info.display_mmio_offset + 0x70034)
#define DSPFW_SR_SHIFT 23
#define DSPFW_SR_MASK (0x1ff<<23)
#define DSPFW_CURSORB_SHIFT 16
@@ -4573,7 +4635,7 @@ enum skl_disp_power_wells {
#define DSPFW_PLANEA_SHIFT 0
#define DSPFW_PLANEA_MASK (0x7f<<0)
#define DSPFW_PLANEA_MASK_VLV (0xff<<0) /* vlv/chv */
-#define DSPFW2 (dev_priv->info.display_mmio_offset + 0x70038)
+#define DSPFW2 _MMIO(dev_priv->info.display_mmio_offset + 0x70038)
#define DSPFW_FBC_SR_EN (1<<31) /* g4x */
#define DSPFW_FBC_SR_SHIFT 28
#define DSPFW_FBC_SR_MASK (0x7<<28) /* g4x */
@@ -4589,7 +4651,7 @@ enum skl_disp_power_wells {
#define DSPFW_SPRITEA_SHIFT 0
#define DSPFW_SPRITEA_MASK (0x7f<<0) /* g4x */
#define DSPFW_SPRITEA_MASK_VLV (0xff<<0) /* vlv/chv */
-#define DSPFW3 (dev_priv->info.display_mmio_offset + 0x7003c)
+#define DSPFW3 _MMIO(dev_priv->info.display_mmio_offset + 0x7003c)
#define DSPFW_HPLL_SR_EN (1<<31)
#define PINEVIEW_SELF_REFRESH_EN (1<<30)
#define DSPFW_CURSOR_SR_SHIFT 24
@@ -4600,14 +4662,14 @@ enum skl_disp_power_wells {
#define DSPFW_HPLL_SR_MASK (0x1ff<<0)
/* vlv/chv */
-#define DSPFW4 (VLV_DISPLAY_BASE + 0x70070)
+#define DSPFW4 _MMIO(VLV_DISPLAY_BASE + 0x70070)
#define DSPFW_SPRITEB_WM1_SHIFT 16
#define DSPFW_SPRITEB_WM1_MASK (0xff<<16)
#define DSPFW_CURSORA_WM1_SHIFT 8
#define DSPFW_CURSORA_WM1_MASK (0x3f<<8)
#define DSPFW_SPRITEA_WM1_SHIFT 0
#define DSPFW_SPRITEA_WM1_MASK (0xff<<0)
-#define DSPFW5 (VLV_DISPLAY_BASE + 0x70074)
+#define DSPFW5 _MMIO(VLV_DISPLAY_BASE + 0x70074)
#define DSPFW_PLANEB_WM1_SHIFT 24
#define DSPFW_PLANEB_WM1_MASK (0xff<<24)
#define DSPFW_PLANEA_WM1_SHIFT 16
@@ -4616,11 +4678,11 @@ enum skl_disp_power_wells {
#define DSPFW_CURSORB_WM1_MASK (0x3f<<8)
#define DSPFW_CURSOR_SR_WM1_SHIFT 0
#define DSPFW_CURSOR_SR_WM1_MASK (0x3f<<0)
-#define DSPFW6 (VLV_DISPLAY_BASE + 0x70078)
+#define DSPFW6 _MMIO(VLV_DISPLAY_BASE + 0x70078)
#define DSPFW_SR_WM1_SHIFT 0
#define DSPFW_SR_WM1_MASK (0x1ff<<0)
-#define DSPFW7 (VLV_DISPLAY_BASE + 0x7007c)
-#define DSPFW7_CHV (VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */
+#define DSPFW7 _MMIO(VLV_DISPLAY_BASE + 0x7007c)
+#define DSPFW7_CHV _MMIO(VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */
#define DSPFW_SPRITED_WM1_SHIFT 24
#define DSPFW_SPRITED_WM1_MASK (0xff<<24)
#define DSPFW_SPRITED_SHIFT 16
@@ -4629,7 +4691,7 @@ enum skl_disp_power_wells {
#define DSPFW_SPRITEC_WM1_MASK (0xff<<8)
#define DSPFW_SPRITEC_SHIFT 0
#define DSPFW_SPRITEC_MASK_VLV (0xff<<0)
-#define DSPFW8_CHV (VLV_DISPLAY_BASE + 0x700b8)
+#define DSPFW8_CHV _MMIO(VLV_DISPLAY_BASE + 0x700b8)
#define DSPFW_SPRITEF_WM1_SHIFT 24
#define DSPFW_SPRITEF_WM1_MASK (0xff<<24)
#define DSPFW_SPRITEF_SHIFT 16
@@ -4638,7 +4700,7 @@ enum skl_disp_power_wells {
#define DSPFW_SPRITEE_WM1_MASK (0xff<<8)
#define DSPFW_SPRITEE_SHIFT 0
#define DSPFW_SPRITEE_MASK_VLV (0xff<<0)
-#define DSPFW9_CHV (VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */
+#define DSPFW9_CHV _MMIO(VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */
#define DSPFW_PLANEC_WM1_SHIFT 24
#define DSPFW_PLANEC_WM1_MASK (0xff<<24)
#define DSPFW_PLANEC_SHIFT 16
@@ -4649,7 +4711,7 @@ enum skl_disp_power_wells {
#define DSPFW_CURSORC_MASK (0x3f<<0)
/* vlv/chv high order bits */
-#define DSPHOWM (VLV_DISPLAY_BASE + 0x70064)
+#define DSPHOWM _MMIO(VLV_DISPLAY_BASE + 0x70064)
#define DSPFW_SR_HI_SHIFT 24
#define DSPFW_SR_HI_MASK (3<<24) /* 2 bits for chv, 1 for vlv */
#define DSPFW_SPRITEF_HI_SHIFT 23
@@ -4670,7 +4732,7 @@ enum skl_disp_power_wells {
#define DSPFW_SPRITEA_HI_MASK (1<<4)
#define DSPFW_PLANEA_HI_SHIFT 0
#define DSPFW_PLANEA_HI_MASK (1<<0)
-#define DSPHOWM1 (VLV_DISPLAY_BASE + 0x70068)
+#define DSPHOWM1 _MMIO(VLV_DISPLAY_BASE + 0x70068)
#define DSPFW_SR_WM1_HI_SHIFT 24
#define DSPFW_SR_WM1_HI_MASK (3<<24) /* 2 bits for chv, 1 for vlv */
#define DSPFW_SPRITEF_WM1_HI_SHIFT 23
@@ -4693,7 +4755,7 @@ enum skl_disp_power_wells {
#define DSPFW_PLANEA_WM1_HI_MASK (1<<0)
/* drain latency register values*/
-#define VLV_DDL(pipe) (VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe))
+#define VLV_DDL(pipe) _MMIO(VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe))
#define DDL_CURSOR_SHIFT 24
#define DDL_SPRITE_SHIFT(sprite) (8+8*(sprite))
#define DDL_PLANE_SHIFT 0
@@ -4701,7 +4763,7 @@ enum skl_disp_power_wells {
#define DDL_PRECISION_LOW (0<<7)
#define DRAIN_LATENCY_MASK 0x7f
-#define CBR1_VLV (VLV_DISPLAY_BASE + 0x70400)
+#define CBR1_VLV _MMIO(VLV_DISPLAY_BASE + 0x70400)
#define CBR_PND_DEADLINE_DISABLE (1<<31)
#define CBR_PWM_CLOCK_MUX_SELECT (1<<30)
@@ -4739,51 +4801,51 @@ enum skl_disp_power_wells {
#define I965_CURSOR_DFT_WM 8
/* Watermark register definitions for SKL */
-#define CUR_WM_A_0 0x70140
-#define CUR_WM_B_0 0x71140
-#define PLANE_WM_1_A_0 0x70240
-#define PLANE_WM_1_B_0 0x71240
-#define PLANE_WM_2_A_0 0x70340
-#define PLANE_WM_2_B_0 0x71340
-#define PLANE_WM_TRANS_1_A_0 0x70268
-#define PLANE_WM_TRANS_1_B_0 0x71268
-#define PLANE_WM_TRANS_2_A_0 0x70368
-#define PLANE_WM_TRANS_2_B_0 0x71368
-#define CUR_WM_TRANS_A_0 0x70168
-#define CUR_WM_TRANS_B_0 0x71168
+#define _CUR_WM_A_0 0x70140
+#define _CUR_WM_B_0 0x71140
+#define _PLANE_WM_1_A_0 0x70240
+#define _PLANE_WM_1_B_0 0x71240
+#define _PLANE_WM_2_A_0 0x70340
+#define _PLANE_WM_2_B_0 0x71340
+#define _PLANE_WM_TRANS_1_A_0 0x70268
+#define _PLANE_WM_TRANS_1_B_0 0x71268
+#define _PLANE_WM_TRANS_2_A_0 0x70368
+#define _PLANE_WM_TRANS_2_B_0 0x71368
+#define _CUR_WM_TRANS_A_0 0x70168
+#define _CUR_WM_TRANS_B_0 0x71168
#define PLANE_WM_EN (1 << 31)
#define PLANE_WM_LINES_SHIFT 14
#define PLANE_WM_LINES_MASK 0x1f
#define PLANE_WM_BLOCKS_MASK 0x3ff
-#define CUR_WM_0(pipe) _PIPE(pipe, CUR_WM_A_0, CUR_WM_B_0)
-#define CUR_WM(pipe, level) (CUR_WM_0(pipe) + ((4) * (level)))
-#define CUR_WM_TRANS(pipe) _PIPE(pipe, CUR_WM_TRANS_A_0, CUR_WM_TRANS_B_0)
+#define _CUR_WM_0(pipe) _PIPE(pipe, _CUR_WM_A_0, _CUR_WM_B_0)
+#define CUR_WM(pipe, level) _MMIO(_CUR_WM_0(pipe) + ((4) * (level)))
+#define CUR_WM_TRANS(pipe) _MMIO_PIPE(pipe, _CUR_WM_TRANS_A_0, _CUR_WM_TRANS_B_0)
-#define _PLANE_WM_1(pipe) _PIPE(pipe, PLANE_WM_1_A_0, PLANE_WM_1_B_0)
-#define _PLANE_WM_2(pipe) _PIPE(pipe, PLANE_WM_2_A_0, PLANE_WM_2_B_0)
+#define _PLANE_WM_1(pipe) _PIPE(pipe, _PLANE_WM_1_A_0, _PLANE_WM_1_B_0)
+#define _PLANE_WM_2(pipe) _PIPE(pipe, _PLANE_WM_2_A_0, _PLANE_WM_2_B_0)
#define _PLANE_WM_BASE(pipe, plane) \
_PLANE(plane, _PLANE_WM_1(pipe), _PLANE_WM_2(pipe))
#define PLANE_WM(pipe, plane, level) \
- (_PLANE_WM_BASE(pipe, plane) + ((4) * (level)))
+ _MMIO(_PLANE_WM_BASE(pipe, plane) + ((4) * (level)))
#define _PLANE_WM_TRANS_1(pipe) \
- _PIPE(pipe, PLANE_WM_TRANS_1_A_0, PLANE_WM_TRANS_1_B_0)
+ _PIPE(pipe, _PLANE_WM_TRANS_1_A_0, _PLANE_WM_TRANS_1_B_0)
#define _PLANE_WM_TRANS_2(pipe) \
- _PIPE(pipe, PLANE_WM_TRANS_2_A_0, PLANE_WM_TRANS_2_B_0)
+ _PIPE(pipe, _PLANE_WM_TRANS_2_A_0, _PLANE_WM_TRANS_2_B_0)
#define PLANE_WM_TRANS(pipe, plane) \
- _PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe))
+ _MMIO(_PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe)))
/* define the Watermark register on Ironlake */
-#define WM0_PIPEA_ILK 0x45100
+#define WM0_PIPEA_ILK _MMIO(0x45100)
#define WM0_PIPE_PLANE_MASK (0xffff<<16)
#define WM0_PIPE_PLANE_SHIFT 16
#define WM0_PIPE_SPRITE_MASK (0xff<<8)
#define WM0_PIPE_SPRITE_SHIFT 8
#define WM0_PIPE_CURSOR_MASK (0xff)
-#define WM0_PIPEB_ILK 0x45104
-#define WM0_PIPEC_IVB 0x45200
-#define WM1_LP_ILK 0x45108
+#define WM0_PIPEB_ILK _MMIO(0x45104)
+#define WM0_PIPEC_IVB _MMIO(0x45200)
+#define WM1_LP_ILK _MMIO(0x45108)
#define WM1_LP_SR_EN (1<<31)
#define WM1_LP_LATENCY_SHIFT 24
#define WM1_LP_LATENCY_MASK (0x7f<<24)
@@ -4793,13 +4855,13 @@ enum skl_disp_power_wells {
#define WM1_LP_SR_MASK (0x7ff<<8)
#define WM1_LP_SR_SHIFT 8
#define WM1_LP_CURSOR_MASK (0xff)
-#define WM2_LP_ILK 0x4510c
+#define WM2_LP_ILK _MMIO(0x4510c)
#define WM2_LP_EN (1<<31)
-#define WM3_LP_ILK 0x45110
+#define WM3_LP_ILK _MMIO(0x45110)
#define WM3_LP_EN (1<<31)
-#define WM1S_LP_ILK 0x45120
-#define WM2S_LP_IVB 0x45124
-#define WM3S_LP_IVB 0x45128
+#define WM1S_LP_ILK _MMIO(0x45120)
+#define WM2S_LP_IVB _MMIO(0x45124)
+#define WM3S_LP_IVB _MMIO(0x45128)
#define WM1S_LP_EN (1<<31)
#define HSW_WM_LP_VAL(lat, fbc, pri, cur) \
@@ -4807,7 +4869,7 @@ enum skl_disp_power_wells {
((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur))
/* Memory latency timer register */
-#define MLTR_ILK 0x11222
+#define MLTR_ILK _MMIO(0x11222)
#define MLTR_WM1_SHIFT 0
#define MLTR_WM2_SHIFT 8
/* the unit of memory self-refresh latency time is 0.5us */
@@ -4815,7 +4877,7 @@ enum skl_disp_power_wells {
/* the address where we get all kinds of latency value */
-#define SSKPD 0x5d10
+#define SSKPD _MMIO(0x5d10)
#define SSKPD_WM_MASK 0x3f
#define SSKPD_WM0_SHIFT 0
#define SSKPD_WM1_SHIFT 8
@@ -4848,8 +4910,8 @@ enum skl_disp_power_wells {
/* GM45+ just has to be different */
#define _PIPEA_FRMCOUNT_G4X 0x70040
#define _PIPEA_FLIPCOUNT_G4X 0x70044
-#define PIPE_FRMCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_G4X)
-#define PIPE_FLIPCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X)
+#define PIPE_FRMCOUNT_G4X(pipe) _MMIO_PIPE2(pipe, _PIPEA_FRMCOUNT_G4X)
+#define PIPE_FLIPCOUNT_G4X(pipe) _MMIO_PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X)
/* Cursor A & B regs */
#define _CURACNTR 0x70080
@@ -4887,7 +4949,7 @@ enum skl_disp_power_wells {
#define CURSOR_POS_SIGN 0x8000
#define CURSOR_X_SHIFT 0
#define CURSOR_Y_SHIFT 16
-#define CURSIZE 0x700a0
+#define CURSIZE _MMIO(0x700a0)
#define _CURBCNTR 0x700c0
#define _CURBBASE 0x700c4
#define _CURBPOS 0x700c8
@@ -4896,7 +4958,7 @@ enum skl_disp_power_wells {
#define _CURBBASE_IVB 0x71084
#define _CURBPOS_IVB 0x71088
-#define _CURSOR2(pipe, reg) (dev_priv->info.cursor_offsets[(pipe)] - \
+#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)
@@ -4957,16 +5019,16 @@ enum skl_disp_power_wells {
#define _DSPAOFFSET 0x701A4 /* HSW */
#define _DSPASURFLIVE 0x701AC
-#define DSPCNTR(plane) _PIPE2(plane, _DSPACNTR)
-#define DSPADDR(plane) _PIPE2(plane, _DSPAADDR)
-#define DSPSTRIDE(plane) _PIPE2(plane, _DSPASTRIDE)
-#define DSPPOS(plane) _PIPE2(plane, _DSPAPOS)
-#define DSPSIZE(plane) _PIPE2(plane, _DSPASIZE)
-#define DSPSURF(plane) _PIPE2(plane, _DSPASURF)
-#define DSPTILEOFF(plane) _PIPE2(plane, _DSPATILEOFF)
-#define DSPLINOFF(plane) DSPADDR(plane)
-#define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET)
-#define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE)
+#define DSPCNTR(plane) _MMIO_PIPE2(plane, _DSPACNTR)
+#define DSPADDR(plane) _MMIO_PIPE2(plane, _DSPAADDR)
+#define DSPSTRIDE(plane) _MMIO_PIPE2(plane, _DSPASTRIDE)
+#define DSPPOS(plane) _MMIO_PIPE2(plane, _DSPAPOS)
+#define DSPSIZE(plane) _MMIO_PIPE2(plane, _DSPASIZE)
+#define DSPSURF(plane) _MMIO_PIPE2(plane, _DSPASURF)
+#define DSPTILEOFF(plane) _MMIO_PIPE2(plane, _DSPATILEOFF)
+#define DSPLINOFF(plane) DSPADDR(plane)
+#define DSPOFFSET(plane) _MMIO_PIPE2(plane, _DSPAOFFSET)
+#define DSPSURFLIVE(plane) _MMIO_PIPE2(plane, _DSPASURFLIVE)
/* CHV pipe B blender and primary plane */
#define _CHV_BLEND_A 0x60a00
@@ -4980,11 +5042,11 @@ enum skl_disp_power_wells {
#define _PRIMCNSTALPHA_A 0x60a10
#define PRIM_CONST_ALPHA_ENABLE (1<<31)
-#define CHV_BLEND(pipe) _TRANSCODER2(pipe, _CHV_BLEND_A)
-#define CHV_CANVAS(pipe) _TRANSCODER2(pipe, _CHV_CANVAS_A)
-#define PRIMPOS(plane) _TRANSCODER2(plane, _PRIMPOS_A)
-#define PRIMSIZE(plane) _TRANSCODER2(plane, _PRIMSIZE_A)
-#define PRIMCNSTALPHA(plane) _TRANSCODER2(plane, _PRIMCNSTALPHA_A)
+#define CHV_BLEND(pipe) _MMIO_TRANS2(pipe, _CHV_BLEND_A)
+#define CHV_CANVAS(pipe) _MMIO_TRANS2(pipe, _CHV_CANVAS_A)
+#define PRIMPOS(plane) _MMIO_TRANS2(plane, _PRIMPOS_A)
+#define PRIMSIZE(plane) _MMIO_TRANS2(plane, _PRIMSIZE_A)
+#define PRIMCNSTALPHA(plane) _MMIO_TRANS2(plane, _PRIMCNSTALPHA_A)
/* Display/Sprite base address macros */
#define DISP_BASEADDR_MASK (0xfffff000)
@@ -5002,9 +5064,10 @@ enum skl_disp_power_wells {
* [10:1f] all
* [30:32] all
*/
-#define SWF0(i) (dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4)
-#define SWF1(i) (dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4)
-#define SWF3(i) (dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4)
+#define SWF0(i) _MMIO(dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4)
+#define SWF1(i) _MMIO(dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4)
+#define SWF3(i) _MMIO(dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4)
+#define SWF_ILK(i) _MMIO(0x4F000 + (i) * 4)
/* Pipe B */
#define _PIPEBDSL (dev_priv->info.display_mmio_offset + 0x71000)
@@ -5086,18 +5149,18 @@ enum skl_disp_power_wells {
#define _DVSBSCALE 0x73204
#define _DVSBGAMC 0x73300
-#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR)
-#define DVSLINOFF(pipe) _PIPE(pipe, _DVSALINOFF, _DVSBLINOFF)
-#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
-#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS)
-#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF)
-#define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL)
-#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE)
-#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE)
-#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
-#define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL)
-#define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK)
-#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE)
+#define DVSCNTR(pipe) _MMIO_PIPE(pipe, _DVSACNTR, _DVSBCNTR)
+#define DVSLINOFF(pipe) _MMIO_PIPE(pipe, _DVSALINOFF, _DVSBLINOFF)
+#define DVSSTRIDE(pipe) _MMIO_PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
+#define DVSPOS(pipe) _MMIO_PIPE(pipe, _DVSAPOS, _DVSBPOS)
+#define DVSSURF(pipe) _MMIO_PIPE(pipe, _DVSASURF, _DVSBSURF)
+#define DVSKEYMAX(pipe) _MMIO_PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL)
+#define DVSSIZE(pipe) _MMIO_PIPE(pipe, _DVSASIZE, _DVSBSIZE)
+#define DVSSCALE(pipe) _MMIO_PIPE(pipe, _DVSASCALE, _DVSBSCALE)
+#define DVSTILEOFF(pipe) _MMIO_PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
+#define DVSKEYVAL(pipe) _MMIO_PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL)
+#define DVSKEYMSK(pipe) _MMIO_PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK)
+#define DVSSURFLIVE(pipe) _MMIO_PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE)
#define _SPRA_CTL 0x70280
#define SPRITE_ENABLE (1<<31)
@@ -5160,20 +5223,20 @@ enum skl_disp_power_wells {
#define _SPRB_SCALE 0x71304
#define _SPRB_GAMC 0x71400
-#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
-#define SPRLINOFF(pipe) _PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF)
-#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE)
-#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS)
-#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE)
-#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL)
-#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK)
-#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
-#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX)
-#define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF)
-#define SPROFFSET(pipe) _PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET)
-#define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE)
-#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
-#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
+#define SPRCTL(pipe) _MMIO_PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
+#define SPRLINOFF(pipe) _MMIO_PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF)
+#define SPRSTRIDE(pipe) _MMIO_PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE)
+#define SPRPOS(pipe) _MMIO_PIPE(pipe, _SPRA_POS, _SPRB_POS)
+#define SPRSIZE(pipe) _MMIO_PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE)
+#define SPRKEYVAL(pipe) _MMIO_PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL)
+#define SPRKEYMSK(pipe) _MMIO_PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK)
+#define SPRSURF(pipe) _MMIO_PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
+#define SPRKEYMAX(pipe) _MMIO_PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX)
+#define SPRTILEOFF(pipe) _MMIO_PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF)
+#define SPROFFSET(pipe) _MMIO_PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET)
+#define SPRSCALE(pipe) _MMIO_PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE)
+#define SPRGAMC(pipe) _MMIO_PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
+#define SPRSURFLIVE(pipe) _MMIO_PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
#define _SPACNTR (VLV_DISPLAY_BASE + 0x72180)
#define SP_ENABLE (1<<31)
@@ -5223,18 +5286,18 @@ enum skl_disp_power_wells {
#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8)
#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4)
-#define SPCNTR(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR)
-#define SPLINOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF)
-#define SPSTRIDE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE)
-#define SPPOS(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS)
-#define SPSIZE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE)
-#define SPKEYMINVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL)
-#define SPKEYMSK(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK)
-#define SPSURF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF)
-#define SPKEYMAXVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
-#define SPTILEOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF)
-#define SPCONSTALPHA(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA)
-#define SPGAMC(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC)
+#define SPCNTR(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR)
+#define SPLINOFF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF)
+#define SPSTRIDE(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE)
+#define SPPOS(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS)
+#define SPSIZE(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE)
+#define SPKEYMINVAL(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL)
+#define SPKEYMSK(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK)
+#define SPSURF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF)
+#define SPKEYMAXVAL(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
+#define SPTILEOFF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF)
+#define SPCONSTALPHA(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA)
+#define SPGAMC(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC)
/*
* CHV pipe B sprite CSC
@@ -5243,29 +5306,29 @@ enum skl_disp_power_wells {
* |yg| = |c3 c4 c5| x |yg + yg_ioff| + |yg_ooff|
* |cb| |c6 c7 c8| |cb + cr_ioff| |cb_ooff|
*/
-#define SPCSCYGOFF(sprite) (VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000)
-#define SPCSCCBOFF(sprite) (VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000)
-#define SPCSCCROFF(sprite) (VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000)
+#define SPCSCYGOFF(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000)
+#define SPCSCCBOFF(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000)
+#define SPCSCCROFF(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000)
#define SPCSC_OOFF(x) (((x) & 0x7ff) << 16) /* s11 */
#define SPCSC_IOFF(x) (((x) & 0x7ff) << 0) /* s11 */
-#define SPCSCC01(sprite) (VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000)
-#define SPCSCC23(sprite) (VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000)
-#define SPCSCC45(sprite) (VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000)
-#define SPCSCC67(sprite) (VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000)
-#define SPCSCC8(sprite) (VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000)
+#define SPCSCC01(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000)
+#define SPCSCC23(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000)
+#define SPCSCC45(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000)
+#define SPCSCC67(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000)
+#define SPCSCC8(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000)
#define SPCSC_C1(x) (((x) & 0x7fff) << 16) /* s3.12 */
#define SPCSC_C0(x) (((x) & 0x7fff) << 0) /* s3.12 */
-#define SPCSCYGICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000)
-#define SPCSCCBICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000)
-#define SPCSCCRICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000)
+#define SPCSCYGICLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000)
+#define SPCSCCBICLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000)
+#define SPCSCCRICLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000)
#define SPCSC_IMAX(x) (((x) & 0x7ff) << 16) /* s11 */
#define SPCSC_IMIN(x) (((x) & 0x7ff) << 0) /* s11 */
-#define SPCSCYGOCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000)
-#define SPCSCCBOCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000)
-#define SPCSCCROCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000)
+#define SPCSCYGOCLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000)
+#define SPCSCCBOCLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000)
+#define SPCSCCROCLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000)
#define SPCSC_OMAX(x) ((x) << 16) /* u10 */
#define SPCSC_OMIN(x) ((x) << 0) /* u10 */
@@ -5346,7 +5409,7 @@ enum skl_disp_power_wells {
#define _PLANE_CTL_2(pipe) _PIPE(pipe, _PLANE_CTL_2_A, _PLANE_CTL_2_B)
#define _PLANE_CTL_3(pipe) _PIPE(pipe, _PLANE_CTL_3_A, _PLANE_CTL_3_B)
#define PLANE_CTL(pipe, plane) \
- _PLANE(plane, _PLANE_CTL_1(pipe), _PLANE_CTL_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_CTL_1(pipe), _PLANE_CTL_2(pipe))
#define _PLANE_STRIDE_1_B 0x71188
#define _PLANE_STRIDE_2_B 0x71288
@@ -5358,7 +5421,7 @@ enum skl_disp_power_wells {
#define _PLANE_STRIDE_3(pipe) \
_PIPE(pipe, _PLANE_STRIDE_3_A, _PLANE_STRIDE_3_B)
#define PLANE_STRIDE(pipe, plane) \
- _PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe))
#define _PLANE_POS_1_B 0x7118c
#define _PLANE_POS_2_B 0x7128c
@@ -5367,7 +5430,7 @@ enum skl_disp_power_wells {
#define _PLANE_POS_2(pipe) _PIPE(pipe, _PLANE_POS_2_A, _PLANE_POS_2_B)
#define _PLANE_POS_3(pipe) _PIPE(pipe, _PLANE_POS_3_A, _PLANE_POS_3_B)
#define PLANE_POS(pipe, plane) \
- _PLANE(plane, _PLANE_POS_1(pipe), _PLANE_POS_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_POS_1(pipe), _PLANE_POS_2(pipe))
#define _PLANE_SIZE_1_B 0x71190
#define _PLANE_SIZE_2_B 0x71290
@@ -5376,7 +5439,7 @@ enum skl_disp_power_wells {
#define _PLANE_SIZE_2(pipe) _PIPE(pipe, _PLANE_SIZE_2_A, _PLANE_SIZE_2_B)
#define _PLANE_SIZE_3(pipe) _PIPE(pipe, _PLANE_SIZE_3_A, _PLANE_SIZE_3_B)
#define PLANE_SIZE(pipe, plane) \
- _PLANE(plane, _PLANE_SIZE_1(pipe), _PLANE_SIZE_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_SIZE_1(pipe), _PLANE_SIZE_2(pipe))
#define _PLANE_SURF_1_B 0x7119c
#define _PLANE_SURF_2_B 0x7129c
@@ -5385,35 +5448,35 @@ enum skl_disp_power_wells {
#define _PLANE_SURF_2(pipe) _PIPE(pipe, _PLANE_SURF_2_A, _PLANE_SURF_2_B)
#define _PLANE_SURF_3(pipe) _PIPE(pipe, _PLANE_SURF_3_A, _PLANE_SURF_3_B)
#define PLANE_SURF(pipe, plane) \
- _PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe))
#define _PLANE_OFFSET_1_B 0x711a4
#define _PLANE_OFFSET_2_B 0x712a4
#define _PLANE_OFFSET_1(pipe) _PIPE(pipe, _PLANE_OFFSET_1_A, _PLANE_OFFSET_1_B)
#define _PLANE_OFFSET_2(pipe) _PIPE(pipe, _PLANE_OFFSET_2_A, _PLANE_OFFSET_2_B)
#define PLANE_OFFSET(pipe, plane) \
- _PLANE(plane, _PLANE_OFFSET_1(pipe), _PLANE_OFFSET_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_OFFSET_1(pipe), _PLANE_OFFSET_2(pipe))
#define _PLANE_KEYVAL_1_B 0x71194
#define _PLANE_KEYVAL_2_B 0x71294
#define _PLANE_KEYVAL_1(pipe) _PIPE(pipe, _PLANE_KEYVAL_1_A, _PLANE_KEYVAL_1_B)
#define _PLANE_KEYVAL_2(pipe) _PIPE(pipe, _PLANE_KEYVAL_2_A, _PLANE_KEYVAL_2_B)
#define PLANE_KEYVAL(pipe, plane) \
- _PLANE(plane, _PLANE_KEYVAL_1(pipe), _PLANE_KEYVAL_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_KEYVAL_1(pipe), _PLANE_KEYVAL_2(pipe))
#define _PLANE_KEYMSK_1_B 0x71198
#define _PLANE_KEYMSK_2_B 0x71298
#define _PLANE_KEYMSK_1(pipe) _PIPE(pipe, _PLANE_KEYMSK_1_A, _PLANE_KEYMSK_1_B)
#define _PLANE_KEYMSK_2(pipe) _PIPE(pipe, _PLANE_KEYMSK_2_A, _PLANE_KEYMSK_2_B)
#define PLANE_KEYMSK(pipe, plane) \
- _PLANE(plane, _PLANE_KEYMSK_1(pipe), _PLANE_KEYMSK_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_KEYMSK_1(pipe), _PLANE_KEYMSK_2(pipe))
#define _PLANE_KEYMAX_1_B 0x711a0
#define _PLANE_KEYMAX_2_B 0x712a0
#define _PLANE_KEYMAX_1(pipe) _PIPE(pipe, _PLANE_KEYMAX_1_A, _PLANE_KEYMAX_1_B)
#define _PLANE_KEYMAX_2(pipe) _PIPE(pipe, _PLANE_KEYMAX_2_A, _PLANE_KEYMAX_2_B)
#define PLANE_KEYMAX(pipe, plane) \
- _PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe))
#define _PLANE_BUF_CFG_1_B 0x7127c
#define _PLANE_BUF_CFG_2_B 0x7137c
@@ -5422,7 +5485,7 @@ enum skl_disp_power_wells {
#define _PLANE_BUF_CFG_2(pipe) \
_PIPE(pipe, _PLANE_BUF_CFG_2_A, _PLANE_BUF_CFG_2_B)
#define PLANE_BUF_CFG(pipe, plane) \
- _PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe))
#define _PLANE_NV12_BUF_CFG_1_B 0x71278
#define _PLANE_NV12_BUF_CFG_2_B 0x71378
@@ -5431,26 +5494,26 @@ enum skl_disp_power_wells {
#define _PLANE_NV12_BUF_CFG_2(pipe) \
_PIPE(pipe, _PLANE_NV12_BUF_CFG_2_A, _PLANE_NV12_BUF_CFG_2_B)
#define PLANE_NV12_BUF_CFG(pipe, plane) \
- _PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe))
+ _MMIO_PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe))
/* SKL new cursor registers */
#define _CUR_BUF_CFG_A 0x7017c
#define _CUR_BUF_CFG_B 0x7117c
-#define CUR_BUF_CFG(pipe) _PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B)
+#define CUR_BUF_CFG(pipe) _MMIO_PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B)
/* VBIOS regs */
-#define VGACNTRL 0x71400
+#define VGACNTRL _MMIO(0x71400)
# define VGA_DISP_DISABLE (1 << 31)
# define VGA_2X_MODE (1 << 30)
# define VGA_PIPE_B_SELECT (1 << 29)
-#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400)
+#define VLV_VGACNTRL _MMIO(VLV_DISPLAY_BASE + 0x71400)
/* Ironlake */
-#define CPU_VGACNTRL 0x41000
+#define CPU_VGACNTRL _MMIO(0x41000)
-#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030
+#define DIGITAL_PORT_HOTPLUG_CNTRL _MMIO(0x44030)
#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4)
#define DIGITAL_PORTA_PULSE_DURATION_2ms (0 << 2) /* pre-HSW */
#define DIGITAL_PORTA_PULSE_DURATION_4_5ms (1 << 2) /* pre-HSW */
@@ -5463,26 +5526,26 @@ enum skl_disp_power_wells {
#define DIGITAL_PORTA_HOTPLUG_LONG_DETECT (2 << 0)
/* refresh rate hardware control */
-#define RR_HW_CTL 0x45300
+#define RR_HW_CTL _MMIO(0x45300)
#define RR_HW_LOW_POWER_FRAMES_MASK 0xff
#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00
-#define FDI_PLL_BIOS_0 0x46000
+#define FDI_PLL_BIOS_0 _MMIO(0x46000)
#define FDI_PLL_FB_CLOCK_MASK 0xff
-#define FDI_PLL_BIOS_1 0x46004
-#define FDI_PLL_BIOS_2 0x46008
-#define DISPLAY_PORT_PLL_BIOS_0 0x4600c
-#define DISPLAY_PORT_PLL_BIOS_1 0x46010
-#define DISPLAY_PORT_PLL_BIOS_2 0x46014
+#define FDI_PLL_BIOS_1 _MMIO(0x46004)
+#define FDI_PLL_BIOS_2 _MMIO(0x46008)
+#define DISPLAY_PORT_PLL_BIOS_0 _MMIO(0x4600c)
+#define DISPLAY_PORT_PLL_BIOS_1 _MMIO(0x46010)
+#define DISPLAY_PORT_PLL_BIOS_2 _MMIO(0x46014)
-#define PCH_3DCGDIS0 0x46020
+#define PCH_3DCGDIS0 _MMIO(0x46020)
# define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18)
# define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1)
-#define PCH_3DCGDIS1 0x46024
+#define PCH_3DCGDIS1 _MMIO(0x46024)
# define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11)
-#define FDI_PLL_FREQ_CTL 0x46030
+#define FDI_PLL_FREQ_CTL _MMIO(0x46030)
#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24)
#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00
#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff
@@ -5519,14 +5582,14 @@ enum skl_disp_power_wells {
#define _PIPEB_LINK_M2 0x61048
#define _PIPEB_LINK_N2 0x6104c
-#define PIPE_DATA_M1(tran) _TRANSCODER2(tran, _PIPEA_DATA_M1)
-#define PIPE_DATA_N1(tran) _TRANSCODER2(tran, _PIPEA_DATA_N1)
-#define PIPE_DATA_M2(tran) _TRANSCODER2(tran, _PIPEA_DATA_M2)
-#define PIPE_DATA_N2(tran) _TRANSCODER2(tran, _PIPEA_DATA_N2)
-#define PIPE_LINK_M1(tran) _TRANSCODER2(tran, _PIPEA_LINK_M1)
-#define PIPE_LINK_N1(tran) _TRANSCODER2(tran, _PIPEA_LINK_N1)
-#define PIPE_LINK_M2(tran) _TRANSCODER2(tran, _PIPEA_LINK_M2)
-#define PIPE_LINK_N2(tran) _TRANSCODER2(tran, _PIPEA_LINK_N2)
+#define PIPE_DATA_M1(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_M1)
+#define PIPE_DATA_N1(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_N1)
+#define PIPE_DATA_M2(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_M2)
+#define PIPE_DATA_N2(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_N2)
+#define PIPE_LINK_M1(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_M1)
+#define PIPE_LINK_N1(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_N1)
+#define PIPE_LINK_M2(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_M2)
+#define PIPE_LINK_N2(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_N2)
/* CPU panel fitter */
/* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */
@@ -5549,11 +5612,11 @@ enum skl_disp_power_wells {
#define _PFA_HSCALE 0x68090
#define _PFB_HSCALE 0x68890
-#define PF_CTL(pipe) _PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1)
-#define PF_WIN_SZ(pipe) _PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ)
-#define PF_WIN_POS(pipe) _PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS)
-#define PF_VSCALE(pipe) _PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE)
-#define PF_HSCALE(pipe) _PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE)
+#define PF_CTL(pipe) _MMIO_PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1)
+#define PF_WIN_SZ(pipe) _MMIO_PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ)
+#define PF_WIN_POS(pipe) _MMIO_PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS)
+#define PF_VSCALE(pipe) _MMIO_PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE)
+#define PF_HSCALE(pipe) _MMIO_PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE)
#define _PSA_CTL 0x68180
#define _PSB_CTL 0x68980
@@ -5563,9 +5626,9 @@ enum skl_disp_power_wells {
#define _PSA_WIN_POS 0x68170
#define _PSB_WIN_POS 0x68970
-#define PS_CTL(pipe) _PIPE(pipe, _PSA_CTL, _PSB_CTL)
-#define PS_WIN_SZ(pipe) _PIPE(pipe, _PSA_WIN_SZ, _PSB_WIN_SZ)
-#define PS_WIN_POS(pipe) _PIPE(pipe, _PSA_WIN_POS, _PSB_WIN_POS)
+#define PS_CTL(pipe) _MMIO_PIPE(pipe, _PSA_CTL, _PSB_CTL)
+#define PS_WIN_SZ(pipe) _MMIO_PIPE(pipe, _PSA_WIN_SZ, _PSB_WIN_SZ)
+#define PS_WIN_POS(pipe) _MMIO_PIPE(pipe, _PSA_WIN_POS, _PSB_WIN_POS)
/*
* Skylake scalers
@@ -5654,48 +5717,63 @@ enum skl_disp_power_wells {
#define _PS_ECC_STAT_1C 0x691D0
#define _ID(id, a, b) ((a) + (id)*((b)-(a)))
-#define SKL_PS_CTRL(pipe, id) _PIPE(pipe, \
+#define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_1A_CTRL, _PS_2A_CTRL), \
_ID(id, _PS_1B_CTRL, _PS_2B_CTRL))
-#define SKL_PS_PWR_GATE(pipe, id) _PIPE(pipe, \
+#define SKL_PS_PWR_GATE(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_PWR_GATE_1A, _PS_PWR_GATE_2A), \
_ID(id, _PS_PWR_GATE_1B, _PS_PWR_GATE_2B))
-#define SKL_PS_WIN_POS(pipe, id) _PIPE(pipe, \
+#define SKL_PS_WIN_POS(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_WIN_POS_1A, _PS_WIN_POS_2A), \
_ID(id, _PS_WIN_POS_1B, _PS_WIN_POS_2B))
-#define SKL_PS_WIN_SZ(pipe, id) _PIPE(pipe, \
+#define SKL_PS_WIN_SZ(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_WIN_SZ_1A, _PS_WIN_SZ_2A), \
_ID(id, _PS_WIN_SZ_1B, _PS_WIN_SZ_2B))
-#define SKL_PS_VSCALE(pipe, id) _PIPE(pipe, \
+#define SKL_PS_VSCALE(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_VSCALE_1A, _PS_VSCALE_2A), \
_ID(id, _PS_VSCALE_1B, _PS_VSCALE_2B))
-#define SKL_PS_HSCALE(pipe, id) _PIPE(pipe, \
+#define SKL_PS_HSCALE(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_HSCALE_1A, _PS_HSCALE_2A), \
_ID(id, _PS_HSCALE_1B, _PS_HSCALE_2B))
-#define SKL_PS_VPHASE(pipe, id) _PIPE(pipe, \
+#define SKL_PS_VPHASE(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_VPHASE_1A, _PS_VPHASE_2A), \
_ID(id, _PS_VPHASE_1B, _PS_VPHASE_2B))
-#define SKL_PS_HPHASE(pipe, id) _PIPE(pipe, \
+#define SKL_PS_HPHASE(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_HPHASE_1A, _PS_HPHASE_2A), \
_ID(id, _PS_HPHASE_1B, _PS_HPHASE_2B))
-#define SKL_PS_ECC_STAT(pipe, id) _PIPE(pipe, \
+#define SKL_PS_ECC_STAT(pipe, id) _MMIO_PIPE(pipe, \
_ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A), \
- _ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B)
+ _ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B))
/* legacy palette */
#define _LGC_PALETTE_A 0x4a000
#define _LGC_PALETTE_B 0x4a800
-#define LGC_PALETTE(pipe, i) (_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4)
+#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4)
#define _GAMMA_MODE_A 0x4a480
#define _GAMMA_MODE_B 0x4ac80
-#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
+#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
#define GAMMA_MODE_MODE_MASK (3 << 0)
#define GAMMA_MODE_MODE_8BIT (0 << 0)
#define GAMMA_MODE_MODE_10BIT (1 << 0)
#define GAMMA_MODE_MODE_12BIT (2 << 0)
#define GAMMA_MODE_MODE_SPLIT (3 << 0)
+/* DMC/CSR */
+#define CSR_PROGRAM(i) _MMIO(0x80000 + (i) * 4)
+#define CSR_SSP_BASE_ADDR_GEN9 0x00002FC0
+#define CSR_HTP_ADDR_SKL 0x00500034
+#define CSR_SSP_BASE _MMIO(0x8F074)
+#define CSR_HTP_SKL _MMIO(0x8F004)
+#define CSR_LAST_WRITE _MMIO(0x8F034)
+#define CSR_LAST_WRITE_VALUE 0xc003b400
+/* MMIO address range for CSR program (0x80000 - 0x82FFF) */
+#define CSR_MMIO_START_RANGE 0x80000
+#define CSR_MMIO_END_RANGE 0x8FFFF
+#define SKL_CSR_DC3_DC5_COUNT _MMIO(0x80030)
+#define SKL_CSR_DC5_DC6_COUNT _MMIO(0x8002C)
+#define BXT_CSR_DC3_DC5_COUNT _MMIO(0x80038)
+
/* interrupts */
#define DE_MASTER_IRQ_CONTROL (1 << 31)
#define DE_SPRITEB_FLIP_DONE (1 << 29)
@@ -5747,20 +5825,20 @@ enum skl_disp_power_wells {
#define DE_PIPEA_VBLANK_IVB (1<<0)
#define DE_PIPE_VBLANK_IVB(pipe) (1 << ((pipe) * 5))
-#define VLV_MASTER_IER 0x4400c /* Gunit master IER */
+#define VLV_MASTER_IER _MMIO(0x4400c) /* Gunit master IER */
#define MASTER_INTERRUPT_ENABLE (1<<31)
-#define DEISR 0x44000
-#define DEIMR 0x44004
-#define DEIIR 0x44008
-#define DEIER 0x4400c
+#define DEISR _MMIO(0x44000)
+#define DEIMR _MMIO(0x44004)
+#define DEIIR _MMIO(0x44008)
+#define DEIER _MMIO(0x4400c)
-#define GTISR 0x44010
-#define GTIMR 0x44014
-#define GTIIR 0x44018
-#define GTIER 0x4401c
+#define GTISR _MMIO(0x44010)
+#define GTIMR _MMIO(0x44014)
+#define GTIIR _MMIO(0x44018)
+#define GTIER _MMIO(0x4401c)
-#define GEN8_MASTER_IRQ 0x44200
+#define GEN8_MASTER_IRQ _MMIO(0x44200)
#define GEN8_MASTER_IRQ_CONTROL (1<<31)
#define GEN8_PCU_IRQ (1<<30)
#define GEN8_DE_PCH_IRQ (1<<23)
@@ -5777,10 +5855,10 @@ enum skl_disp_power_wells {
#define GEN8_GT_BCS_IRQ (1<<1)
#define GEN8_GT_RCS_IRQ (1<<0)
-#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which)))
-#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which)))
-#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
-#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
+#define GEN8_GT_ISR(which) _MMIO(0x44300 + (0x10 * (which)))
+#define GEN8_GT_IMR(which) _MMIO(0x44304 + (0x10 * (which)))
+#define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which)))
+#define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which)))
#define GEN8_RCS_IRQ_SHIFT 0
#define GEN8_BCS_IRQ_SHIFT 16
@@ -5789,10 +5867,10 @@ enum skl_disp_power_wells {
#define GEN8_VECS_IRQ_SHIFT 0
#define GEN8_WD_IRQ_SHIFT 16
-#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
-#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
-#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
-#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_ISR(pipe) _MMIO(0x44400 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IMR(pipe) _MMIO(0x44404 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IIR(pipe) _MMIO(0x44408 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IER(pipe) _MMIO(0x4440c + (0x10 * (pipe)))
#define GEN8_PIPE_FIFO_UNDERRUN (1 << 31)
#define GEN8_PIPE_CDCLK_CRC_ERROR (1 << 29)
#define GEN8_PIPE_CDCLK_CRC_DONE (1 << 28)
@@ -5825,10 +5903,10 @@ enum skl_disp_power_wells {
GEN9_PIPE_PLANE2_FAULT | \
GEN9_PIPE_PLANE1_FAULT)
-#define GEN8_DE_PORT_ISR 0x44440
-#define GEN8_DE_PORT_IMR 0x44444
-#define GEN8_DE_PORT_IIR 0x44448
-#define GEN8_DE_PORT_IER 0x4444c
+#define GEN8_DE_PORT_ISR _MMIO(0x44440)
+#define GEN8_DE_PORT_IMR _MMIO(0x44444)
+#define GEN8_DE_PORT_IIR _MMIO(0x44448)
+#define GEN8_DE_PORT_IER _MMIO(0x4444c)
#define GEN9_AUX_CHANNEL_D (1 << 27)
#define GEN9_AUX_CHANNEL_C (1 << 26)
#define GEN9_AUX_CHANNEL_B (1 << 25)
@@ -5842,23 +5920,23 @@ enum skl_disp_power_wells {
#define BXT_DE_PORT_GMBUS (1 << 1)
#define GEN8_AUX_CHANNEL_A (1 << 0)
-#define GEN8_DE_MISC_ISR 0x44460
-#define GEN8_DE_MISC_IMR 0x44464
-#define GEN8_DE_MISC_IIR 0x44468
-#define GEN8_DE_MISC_IER 0x4446c
+#define GEN8_DE_MISC_ISR _MMIO(0x44460)
+#define GEN8_DE_MISC_IMR _MMIO(0x44464)
+#define GEN8_DE_MISC_IIR _MMIO(0x44468)
+#define GEN8_DE_MISC_IER _MMIO(0x4446c)
#define GEN8_DE_MISC_GSE (1 << 27)
-#define GEN8_PCU_ISR 0x444e0
-#define GEN8_PCU_IMR 0x444e4
-#define GEN8_PCU_IIR 0x444e8
-#define GEN8_PCU_IER 0x444ec
+#define GEN8_PCU_ISR _MMIO(0x444e0)
+#define GEN8_PCU_IMR _MMIO(0x444e4)
+#define GEN8_PCU_IIR _MMIO(0x444e8)
+#define GEN8_PCU_IER _MMIO(0x444ec)
-#define ILK_DISPLAY_CHICKEN2 0x42004
+#define ILK_DISPLAY_CHICKEN2 _MMIO(0x42004)
/* Required on all Ironlake and Sandybridge according to the B-Spec. */
#define ILK_ELPIN_409_SELECT (1 << 25)
#define ILK_DPARB_GATE (1<<22)
#define ILK_VSDPFD_FULL (1<<21)
-#define FUSE_STRAP 0x42014
+#define FUSE_STRAP _MMIO(0x42014)
#define ILK_INTERNAL_GRAPHICS_DISABLE (1 << 31)
#define ILK_INTERNAL_DISPLAY_DISABLE (1 << 30)
#define ILK_DISPLAY_DEBUG_DISABLE (1 << 29)
@@ -5867,18 +5945,18 @@ enum skl_disp_power_wells {
#define HSW_CDCLK_LIMIT (1 << 24)
#define ILK_DESKTOP (1 << 23)
-#define ILK_DSPCLK_GATE_D 0x42020
+#define ILK_DSPCLK_GATE_D _MMIO(0x42020)
#define ILK_VRHUNIT_CLOCK_GATE_DISABLE (1 << 28)
#define ILK_DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9)
#define ILK_DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8)
#define ILK_DPFDUNIT_CLOCK_GATE_ENABLE (1 << 7)
#define ILK_DPARBUNIT_CLOCK_GATE_ENABLE (1 << 5)
-#define IVB_CHICKEN3 0x4200c
+#define IVB_CHICKEN3 _MMIO(0x4200c)
# define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5)
# define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2)
-#define CHICKEN_PAR1_1 0x42080
+#define CHICKEN_PAR1_1 _MMIO(0x42080)
#define DPA_MASK_VBLANK_SRD (1 << 15)
#define FORCE_ARB_IDLE_PLANES (1 << 14)
@@ -5886,70 +5964,70 @@ enum skl_disp_power_wells {
#define _CHICKEN_PIPESL_1_B 0x420b4
#define HSW_FBCQ_DIS (1 << 22)
#define BDW_DPRS_MASK_VBLANK_SRD (1 << 0)
-#define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
+#define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
-#define DISP_ARB_CTL 0x45000
+#define DISP_ARB_CTL _MMIO(0x45000)
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
#define DISP_FBC_WM_DIS (1<<15)
-#define DISP_ARB_CTL2 0x45004
+#define DISP_ARB_CTL2 _MMIO(0x45004)
#define DISP_DATA_PARTITION_5_6 (1<<6)
-#define DBUF_CTL 0x45008
+#define DBUF_CTL _MMIO(0x45008)
#define DBUF_POWER_REQUEST (1<<31)
#define DBUF_POWER_STATE (1<<30)
-#define GEN7_MSG_CTL 0x45010
+#define GEN7_MSG_CTL _MMIO(0x45010)
#define WAIT_FOR_PCH_RESET_ACK (1<<1)
#define WAIT_FOR_PCH_FLR_ACK (1<<0)
-#define HSW_NDE_RSTWRN_OPT 0x46408
+#define HSW_NDE_RSTWRN_OPT _MMIO(0x46408)
#define RESET_PCH_HANDSHAKE_ENABLE (1<<4)
-#define SKL_DFSM 0x51000
+#define SKL_DFSM _MMIO(0x51000)
#define SKL_DFSM_CDCLK_LIMIT_MASK (3 << 23)
#define SKL_DFSM_CDCLK_LIMIT_675 (0 << 23)
#define SKL_DFSM_CDCLK_LIMIT_540 (1 << 23)
#define SKL_DFSM_CDCLK_LIMIT_450 (2 << 23)
#define SKL_DFSM_CDCLK_LIMIT_337_5 (3 << 23)
-#define FF_SLICE_CS_CHICKEN2 0x20e4
+#define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4)
#define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8)
/* GEN7 chicken */
-#define GEN7_COMMON_SLICE_CHICKEN1 0x7010
+#define GEN7_COMMON_SLICE_CHICKEN1 _MMIO(0x7010)
# define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26))
# define GEN9_RHWO_OPTIMIZATION_DISABLE (1<<14)
-#define COMMON_SLICE_CHICKEN2 0x7014
+#define COMMON_SLICE_CHICKEN2 _MMIO(0x7014)
# define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0)
-#define HIZ_CHICKEN 0x7018
+#define HIZ_CHICKEN _MMIO(0x7018)
# define CHV_HZ_8X8_MODE_IN_1X (1<<15)
# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE (1<<3)
-#define GEN9_SLICE_COMMON_ECO_CHICKEN0 0x7308
+#define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308)
#define DISABLE_PIXEL_MASK_CAMMING (1<<14)
-#define GEN7_L3SQCREG1 0xB010
+#define GEN7_L3SQCREG1 _MMIO(0xB010)
#define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000
-#define GEN8_L3SQCREG1 0xB100
+#define GEN8_L3SQCREG1 _MMIO(0xB100)
#define BDW_WA_L3SQCREG1_DEFAULT 0x784000
-#define GEN7_L3CNTLREG1 0xB01C
+#define GEN7_L3CNTLREG1 _MMIO(0xB01C)
#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C47FF8C
#define GEN7_L3AGDIS (1<<19)
-#define GEN7_L3CNTLREG2 0xB020
-#define GEN7_L3CNTLREG3 0xB024
+#define GEN7_L3CNTLREG2 _MMIO(0xB020)
+#define GEN7_L3CNTLREG3 _MMIO(0xB024)
-#define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030
+#define GEN7_L3_CHICKEN_MODE_REGISTER _MMIO(0xB030)
#define GEN7_WA_L3_CHICKEN_MODE 0x20000000
-#define GEN7_L3SQCREG4 0xb034
+#define GEN7_L3SQCREG4 _MMIO(0xb034)
#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27)
-#define GEN8_L3SQCREG4 0xb118
+#define GEN8_L3SQCREG4 _MMIO(0xb118)
#define GEN8_LQSC_RO_PERF_DIS (1<<27)
#define GEN8_LQSC_FLUSH_COHERENT_LINES (1<<21)
/* GEN8 chicken */
-#define HDC_CHICKEN0 0x7300
+#define HDC_CHICKEN0 _MMIO(0x7300)
#define HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE (1<<15)
#define HDC_FENCE_DEST_SLM_DISABLE (1<<14)
#define HDC_DONOT_FETCH_MEM_WHEN_MASKED (1<<11)
@@ -5958,17 +6036,17 @@ enum skl_disp_power_wells {
#define HDC_BARRIER_PERFORMANCE_DISABLE (1<<10)
/* GEN9 chicken */
-#define SLICE_ECO_CHICKEN0 0x7308
+#define SLICE_ECO_CHICKEN0 _MMIO(0x7308)
#define PIXEL_MASK_CAMMING_DISABLE (1 << 14)
/* WaCatErrorRejectionIssue */
-#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030
+#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG _MMIO(0x9030)
#define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11)
-#define HSW_SCRATCH1 0xb038
+#define HSW_SCRATCH1 _MMIO(0xb038)
#define HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE (1<<27)
-#define BDW_SCRATCH1 0xb11c
+#define BDW_SCRATCH1 _MMIO(0xb11c)
#define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1<<2)
/* PCH */
@@ -6062,12 +6140,12 @@ enum skl_disp_power_wells {
SDE_FDI_RXB_CPT | \
SDE_FDI_RXA_CPT)
-#define SDEISR 0xc4000
-#define SDEIMR 0xc4004
-#define SDEIIR 0xc4008
-#define SDEIER 0xc400c
+#define SDEISR _MMIO(0xc4000)
+#define SDEIMR _MMIO(0xc4004)
+#define SDEIIR _MMIO(0xc4008)
+#define SDEIER _MMIO(0xc400c)
-#define SERR_INT 0xc4040
+#define SERR_INT _MMIO(0xc4040)
#define SERR_INT_POISON (1<<31)
#define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6)
#define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3)
@@ -6075,7 +6153,7 @@ enum skl_disp_power_wells {
#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<((pipe)*3))
/* digital port hotplug */
-#define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */
+#define PCH_PORT_HOTPLUG _MMIO(0xc4030) /* SHOTPLUG_CTL */
#define PORTA_HOTPLUG_ENABLE (1 << 28) /* LPT:LP+ & BXT */
#define PORTA_HOTPLUG_STATUS_MASK (3 << 24) /* SPT+ & BXT */
#define PORTA_HOTPLUG_NO_DETECT (0 << 24) /* SPT+ & BXT */
@@ -6112,42 +6190,42 @@ enum skl_disp_power_wells {
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTB_HOTPLUG_LONG_DETECT (2 << 0)
-#define PCH_PORT_HOTPLUG2 0xc403C /* SHOTPLUG_CTL2 SPT+ */
+#define PCH_PORT_HOTPLUG2 _MMIO(0xc403C) /* SHOTPLUG_CTL2 SPT+ */
#define PORTE_HOTPLUG_ENABLE (1 << 4)
#define PORTE_HOTPLUG_STATUS_MASK (3 << 0)
#define PORTE_HOTPLUG_NO_DETECT (0 << 0)
#define PORTE_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTE_HOTPLUG_LONG_DETECT (2 << 0)
-#define PCH_GPIOA 0xc5010
-#define PCH_GPIOB 0xc5014
-#define PCH_GPIOC 0xc5018
-#define PCH_GPIOD 0xc501c
-#define PCH_GPIOE 0xc5020
-#define PCH_GPIOF 0xc5024
+#define PCH_GPIOA _MMIO(0xc5010)
+#define PCH_GPIOB _MMIO(0xc5014)
+#define PCH_GPIOC _MMIO(0xc5018)
+#define PCH_GPIOD _MMIO(0xc501c)
+#define PCH_GPIOE _MMIO(0xc5020)
+#define PCH_GPIOF _MMIO(0xc5024)
-#define PCH_GMBUS0 0xc5100
-#define PCH_GMBUS1 0xc5104
-#define PCH_GMBUS2 0xc5108
-#define PCH_GMBUS3 0xc510c
-#define PCH_GMBUS4 0xc5110
-#define PCH_GMBUS5 0xc5120
+#define PCH_GMBUS0 _MMIO(0xc5100)
+#define PCH_GMBUS1 _MMIO(0xc5104)
+#define PCH_GMBUS2 _MMIO(0xc5108)
+#define PCH_GMBUS3 _MMIO(0xc510c)
+#define PCH_GMBUS4 _MMIO(0xc5110)
+#define PCH_GMBUS5 _MMIO(0xc5120)
#define _PCH_DPLL_A 0xc6014
#define _PCH_DPLL_B 0xc6018
-#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
+#define PCH_DPLL(pll) _MMIO(pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
#define _PCH_FPA0 0xc6040
#define FP_CB_TUNE (0x3<<22)
#define _PCH_FPA1 0xc6044
#define _PCH_FPB0 0xc6048
#define _PCH_FPB1 0xc604c
-#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
-#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
+#define PCH_FP0(pll) _MMIO(pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
+#define PCH_FP1(pll) _MMIO(pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
-#define PCH_DPLL_TEST 0xc606c
+#define PCH_DPLL_TEST _MMIO(0xc606c)
-#define PCH_DREF_CONTROL 0xC6200
+#define PCH_DREF_CONTROL _MMIO(0xC6200)
#define DREF_CONTROL_MASK 0x7fc3
#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13)
#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13)
@@ -6170,19 +6248,19 @@ enum skl_disp_power_wells {
#define DREF_SSC4_DISABLE (0)
#define DREF_SSC4_ENABLE (1)
-#define PCH_RAWCLK_FREQ 0xc6204
+#define PCH_RAWCLK_FREQ _MMIO(0xc6204)
#define FDL_TP1_TIMER_SHIFT 12
#define FDL_TP1_TIMER_MASK (3<<12)
#define FDL_TP2_TIMER_SHIFT 10
#define FDL_TP2_TIMER_MASK (3<<10)
#define RAWCLK_FREQ_MASK 0x3ff
-#define PCH_DPLL_TMR_CFG 0xc6208
+#define PCH_DPLL_TMR_CFG _MMIO(0xc6208)
-#define PCH_SSC4_PARMS 0xc6210
-#define PCH_SSC4_AUX_PARMS 0xc6214
+#define PCH_SSC4_PARMS _MMIO(0xc6210)
+#define PCH_SSC4_AUX_PARMS _MMIO(0xc6214)
-#define PCH_DPLL_SEL 0xc7000
+#define PCH_DPLL_SEL _MMIO(0xc7000)
#define TRANS_DPLLB_SEL(pipe) (1 << ((pipe) * 4))
#define TRANS_DPLLA_SEL(pipe) 0
#define TRANS_DPLL_ENABLE(pipe) (1 << ((pipe) * 4 + 3))
@@ -6230,79 +6308,73 @@ enum skl_disp_power_wells {
#define _VIDEO_DIP_DATA_B 0xe1208
#define _VIDEO_DIP_GCP_B 0xe1210
-#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B)
-#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
-#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
+#define TVIDEO_DIP_CTL(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B)
+#define TVIDEO_DIP_DATA(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
+#define TVIDEO_DIP_GCP(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
/* Per-transcoder DIP controls (VLV) */
-#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200)
-#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208)
-#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210)
+#define _VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200)
+#define _VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208)
+#define _VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210)
-#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170)
-#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174)
-#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178)
+#define _VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170)
+#define _VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174)
+#define _VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178)
-#define CHV_VIDEO_DIP_CTL_C (VLV_DISPLAY_BASE + 0x611f0)
-#define CHV_VIDEO_DIP_DATA_C (VLV_DISPLAY_BASE + 0x611f4)
-#define CHV_VIDEO_DIP_GDCP_PAYLOAD_C (VLV_DISPLAY_BASE + 0x611f8)
+#define _CHV_VIDEO_DIP_CTL_C (VLV_DISPLAY_BASE + 0x611f0)
+#define _CHV_VIDEO_DIP_DATA_C (VLV_DISPLAY_BASE + 0x611f4)
+#define _CHV_VIDEO_DIP_GDCP_PAYLOAD_C (VLV_DISPLAY_BASE + 0x611f8)
#define VLV_TVIDEO_DIP_CTL(pipe) \
- _PIPE3((pipe), VLV_VIDEO_DIP_CTL_A, \
- VLV_VIDEO_DIP_CTL_B, CHV_VIDEO_DIP_CTL_C)
+ _MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_CTL_A, \
+ _VLV_VIDEO_DIP_CTL_B, _CHV_VIDEO_DIP_CTL_C)
#define VLV_TVIDEO_DIP_DATA(pipe) \
- _PIPE3((pipe), VLV_VIDEO_DIP_DATA_A, \
- VLV_VIDEO_DIP_DATA_B, CHV_VIDEO_DIP_DATA_C)
+ _MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_DATA_A, \
+ _VLV_VIDEO_DIP_DATA_B, _CHV_VIDEO_DIP_DATA_C)
#define VLV_TVIDEO_DIP_GCP(pipe) \
- _PIPE3((pipe), VLV_VIDEO_DIP_GDCP_PAYLOAD_A, \
- VLV_VIDEO_DIP_GDCP_PAYLOAD_B, CHV_VIDEO_DIP_GDCP_PAYLOAD_C)
+ _MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_GDCP_PAYLOAD_A, \
+ _VLV_VIDEO_DIP_GDCP_PAYLOAD_B, _CHV_VIDEO_DIP_GDCP_PAYLOAD_C)
/* Haswell DIP controls */
-#define HSW_VIDEO_DIP_CTL_A 0x60200
-#define HSW_VIDEO_DIP_AVI_DATA_A 0x60220
-#define HSW_VIDEO_DIP_VS_DATA_A 0x60260
-#define HSW_VIDEO_DIP_SPD_DATA_A 0x602A0
-#define HSW_VIDEO_DIP_GMP_DATA_A 0x602E0
-#define HSW_VIDEO_DIP_VSC_DATA_A 0x60320
-#define HSW_VIDEO_DIP_AVI_ECC_A 0x60240
-#define HSW_VIDEO_DIP_VS_ECC_A 0x60280
-#define HSW_VIDEO_DIP_SPD_ECC_A 0x602C0
-#define HSW_VIDEO_DIP_GMP_ECC_A 0x60300
-#define HSW_VIDEO_DIP_VSC_ECC_A 0x60344
-#define HSW_VIDEO_DIP_GCP_A 0x60210
-
-#define HSW_VIDEO_DIP_CTL_B 0x61200
-#define HSW_VIDEO_DIP_AVI_DATA_B 0x61220
-#define HSW_VIDEO_DIP_VS_DATA_B 0x61260
-#define HSW_VIDEO_DIP_SPD_DATA_B 0x612A0
-#define HSW_VIDEO_DIP_GMP_DATA_B 0x612E0
-#define HSW_VIDEO_DIP_VSC_DATA_B 0x61320
-#define HSW_VIDEO_DIP_BVI_ECC_B 0x61240
-#define HSW_VIDEO_DIP_VS_ECC_B 0x61280
-#define HSW_VIDEO_DIP_SPD_ECC_B 0x612C0
-#define HSW_VIDEO_DIP_GMP_ECC_B 0x61300
-#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344
-#define HSW_VIDEO_DIP_GCP_B 0x61210
-
-#define HSW_TVIDEO_DIP_CTL(trans) \
- _TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A)
-#define HSW_TVIDEO_DIP_AVI_DATA(trans, i) \
- (_TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A) + (i) * 4)
-#define HSW_TVIDEO_DIP_VS_DATA(trans, i) \
- (_TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A) + (i) * 4)
-#define HSW_TVIDEO_DIP_SPD_DATA(trans, i) \
- (_TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A) + (i) * 4)
-#define HSW_TVIDEO_DIP_GCP(trans) \
- _TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A)
-#define HSW_TVIDEO_DIP_VSC_DATA(trans, i) \
- (_TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A) + (i) * 4)
-
-#define HSW_STEREO_3D_CTL_A 0x70020
-#define S3D_ENABLE (1<<31)
-#define HSW_STEREO_3D_CTL_B 0x71020
-
-#define HSW_STEREO_3D_CTL(trans) \
- _PIPE2(trans, HSW_STEREO_3D_CTL_A)
+
+#define _HSW_VIDEO_DIP_CTL_A 0x60200
+#define _HSW_VIDEO_DIP_AVI_DATA_A 0x60220
+#define _HSW_VIDEO_DIP_VS_DATA_A 0x60260
+#define _HSW_VIDEO_DIP_SPD_DATA_A 0x602A0
+#define _HSW_VIDEO_DIP_GMP_DATA_A 0x602E0
+#define _HSW_VIDEO_DIP_VSC_DATA_A 0x60320
+#define _HSW_VIDEO_DIP_AVI_ECC_A 0x60240
+#define _HSW_VIDEO_DIP_VS_ECC_A 0x60280
+#define _HSW_VIDEO_DIP_SPD_ECC_A 0x602C0
+#define _HSW_VIDEO_DIP_GMP_ECC_A 0x60300
+#define _HSW_VIDEO_DIP_VSC_ECC_A 0x60344
+#define _HSW_VIDEO_DIP_GCP_A 0x60210
+
+#define _HSW_VIDEO_DIP_CTL_B 0x61200
+#define _HSW_VIDEO_DIP_AVI_DATA_B 0x61220
+#define _HSW_VIDEO_DIP_VS_DATA_B 0x61260
+#define _HSW_VIDEO_DIP_SPD_DATA_B 0x612A0
+#define _HSW_VIDEO_DIP_GMP_DATA_B 0x612E0
+#define _HSW_VIDEO_DIP_VSC_DATA_B 0x61320
+#define _HSW_VIDEO_DIP_BVI_ECC_B 0x61240
+#define _HSW_VIDEO_DIP_VS_ECC_B 0x61280
+#define _HSW_VIDEO_DIP_SPD_ECC_B 0x612C0
+#define _HSW_VIDEO_DIP_GMP_ECC_B 0x61300
+#define _HSW_VIDEO_DIP_VSC_ECC_B 0x61344
+#define _HSW_VIDEO_DIP_GCP_B 0x61210
+
+#define HSW_TVIDEO_DIP_CTL(trans) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_CTL_A)
+#define HSW_TVIDEO_DIP_AVI_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_AVI_DATA_A + (i) * 4)
+#define HSW_TVIDEO_DIP_VS_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VS_DATA_A + (i) * 4)
+#define HSW_TVIDEO_DIP_SPD_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_SPD_DATA_A + (i) * 4)
+#define HSW_TVIDEO_DIP_GCP(trans) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A)
+#define HSW_TVIDEO_DIP_VSC_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4)
+
+#define _HSW_STEREO_3D_CTL_A 0x70020
+#define S3D_ENABLE (1<<31)
+#define _HSW_STEREO_3D_CTL_B 0x71020
+
+#define HSW_STEREO_3D_CTL(trans) _MMIO_PIPE2(trans, _HSW_STEREO_3D_CTL_A)
#define _PCH_TRANS_HTOTAL_B 0xe1000
#define _PCH_TRANS_HBLANK_B 0xe1004
@@ -6310,16 +6382,15 @@ enum skl_disp_power_wells {
#define _PCH_TRANS_VTOTAL_B 0xe100c
#define _PCH_TRANS_VBLANK_B 0xe1010
#define _PCH_TRANS_VSYNC_B 0xe1014
-#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028
+#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028
-#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B)
-#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B)
-#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B)
-#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B)
-#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B)
-#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B)
-#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \
- _PCH_TRANS_VSYNCSHIFT_B)
+#define PCH_TRANS_HTOTAL(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B)
+#define PCH_TRANS_HBLANK(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B)
+#define PCH_TRANS_HSYNC(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B)
+#define PCH_TRANS_VTOTAL(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B)
+#define PCH_TRANS_VBLANK(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B)
+#define PCH_TRANS_VSYNC(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B)
+#define PCH_TRANS_VSYNCSHIFT(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, _PCH_TRANS_VSYNCSHIFT_B)
#define _PCH_TRANSB_DATA_M1 0xe1030
#define _PCH_TRANSB_DATA_N1 0xe1034
@@ -6330,19 +6401,19 @@ enum skl_disp_power_wells {
#define _PCH_TRANSB_LINK_M2 0xe1048
#define _PCH_TRANSB_LINK_N2 0xe104c
-#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1)
-#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1)
-#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2)
-#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2)
-#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1)
-#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1)
-#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2)
-#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2)
+#define PCH_TRANS_DATA_M1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1)
+#define PCH_TRANS_DATA_N1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1)
+#define PCH_TRANS_DATA_M2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2)
+#define PCH_TRANS_DATA_N2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2)
+#define PCH_TRANS_LINK_M1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1)
+#define PCH_TRANS_LINK_N1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1)
+#define PCH_TRANS_LINK_M2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2)
+#define PCH_TRANS_LINK_N2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2)
#define _PCH_TRANSACONF 0xf0008
#define _PCH_TRANSBCONF 0xf1008
-#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF)
-#define LPT_TRANSCONF _PCH_TRANSACONF /* lpt has only one transcoder */
+#define PCH_TRANSCONF(pipe) _MMIO_PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF)
+#define LPT_TRANSCONF PCH_TRANSCONF(PIPE_A) /* lpt has only one transcoder */
#define TRANS_DISABLE (0<<31)
#define TRANS_ENABLE (1<<31)
#define TRANS_STATE_MASK (1<<30)
@@ -6363,47 +6434,47 @@ enum skl_disp_power_wells {
#define _TRANSA_CHICKEN1 0xf0060
#define _TRANSB_CHICKEN1 0xf1060
-#define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
+#define TRANS_CHICKEN1(pipe) _MMIO_PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
#define TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE (1<<10)
#define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4)
#define _TRANSA_CHICKEN2 0xf0064
#define _TRANSB_CHICKEN2 0xf1064
-#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
+#define TRANS_CHICKEN2(pipe) _MMIO_PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31)
#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29)
#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27)
#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26)
#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25)
-#define SOUTH_CHICKEN1 0xc2000
+#define SOUTH_CHICKEN1 _MMIO(0xc2000)
#define FDIA_PHASE_SYNC_SHIFT_OVR 19
#define FDIA_PHASE_SYNC_SHIFT_EN 18
#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2)))
#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
#define FDI_BC_BIFURCATION_SELECT (1 << 12)
#define SPT_PWM_GRANULARITY (1<<0)
-#define SOUTH_CHICKEN2 0xc2004
+#define SOUTH_CHICKEN2 _MMIO(0xc2004)
#define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13)
#define FDI_MPHY_IOSFSB_RESET_CTL (1<<12)
#define LPT_PWM_GRANULARITY (1<<5)
#define DPLS_EDP_PPS_FIX_DIS (1<<0)
-#define _FDI_RXA_CHICKEN 0xc200c
-#define _FDI_RXB_CHICKEN 0xc2010
+#define _FDI_RXA_CHICKEN 0xc200c
+#define _FDI_RXB_CHICKEN 0xc2010
#define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1)
#define FDI_RX_PHASE_SYNC_POINTER_EN (1<<0)
-#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN)
+#define FDI_RX_CHICKEN(pipe) _MMIO_PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN)
-#define SOUTH_DSPCLK_GATE_D 0xc2020
+#define SOUTH_DSPCLK_GATE_D _MMIO(0xc2020)
#define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30)
#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
#define PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14)
#define PCH_LP_PARTITION_LEVEL_DISABLE (1<<12)
/* CPU: FDI_TX */
-#define _FDI_TXA_CTL 0x60100
-#define _FDI_TXB_CTL 0x61100
-#define FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL)
+#define _FDI_TXA_CTL 0x60100
+#define _FDI_TXB_CTL 0x61100
+#define FDI_TX_CTL(pipe) _MMIO_PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL)
#define FDI_TX_DISABLE (0<<31)
#define FDI_TX_ENABLE (1<<31)
#define FDI_LINK_TRAIN_PATTERN_1 (0<<28)
@@ -6453,7 +6524,7 @@ enum skl_disp_power_wells {
/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
#define _FDI_RXA_CTL 0xf000c
#define _FDI_RXB_CTL 0xf100c
-#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
+#define FDI_RX_CTL(pipe) _MMIO_PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
#define FDI_RX_ENABLE (1<<31)
/* train, dp width same as FDI_TX */
#define FDI_FS_ERRC_ENABLE (1<<27)
@@ -6489,14 +6560,14 @@ enum skl_disp_power_wells {
#define FDI_RX_TP1_TO_TP2_48 (2<<20)
#define FDI_RX_TP1_TO_TP2_64 (3<<20)
#define FDI_RX_FDI_DELAY_90 (0x90<<0)
-#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
+#define FDI_RX_MISC(pipe) _MMIO_PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
-#define _FDI_RXA_TUSIZE1 0xf0030
-#define _FDI_RXA_TUSIZE2 0xf0038
-#define _FDI_RXB_TUSIZE1 0xf1030
-#define _FDI_RXB_TUSIZE2 0xf1038
-#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1)
-#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2)
+#define _FDI_RXA_TUSIZE1 0xf0030
+#define _FDI_RXA_TUSIZE2 0xf0038
+#define _FDI_RXB_TUSIZE1 0xf1030
+#define _FDI_RXB_TUSIZE2 0xf1038
+#define FDI_RX_TUSIZE1(pipe) _MMIO_PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe) _MMIO_PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2)
/* FDI_RX interrupt register format */
#define FDI_RX_INTER_LANE_ALIGN (1<<10)
@@ -6511,44 +6582,41 @@ enum skl_disp_power_wells {
#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1)
#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0)
-#define _FDI_RXA_IIR 0xf0014
-#define _FDI_RXA_IMR 0xf0018
-#define _FDI_RXB_IIR 0xf1014
-#define _FDI_RXB_IMR 0xf1018
-#define FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR)
-#define FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR)
+#define _FDI_RXA_IIR 0xf0014
+#define _FDI_RXA_IMR 0xf0018
+#define _FDI_RXB_IIR 0xf1014
+#define _FDI_RXB_IMR 0xf1018
+#define FDI_RX_IIR(pipe) _MMIO_PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe) _MMIO_PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR)
-#define FDI_PLL_CTL_1 0xfe000
-#define FDI_PLL_CTL_2 0xfe004
+#define FDI_PLL_CTL_1 _MMIO(0xfe000)
+#define FDI_PLL_CTL_2 _MMIO(0xfe004)
-#define PCH_LVDS 0xe1180
+#define PCH_LVDS _MMIO(0xe1180)
#define LVDS_DETECTED (1 << 1)
/* vlv has 2 sets of panel control regs. */
-#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200)
-#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204)
-#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208)
+#define _PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200)
+#define _PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204)
+#define _PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208)
#define PANEL_PORT_SELECT_VLV(port) ((port) << 30)
-#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c)
-#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210)
-
-#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300)
-#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304)
-#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308)
-#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c)
-#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310)
-
-#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS)
-#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL)
-#define VLV_PIPE_PP_ON_DELAYS(pipe) \
- _PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS)
-#define VLV_PIPE_PP_OFF_DELAYS(pipe) \
- _PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS)
-#define VLV_PIPE_PP_DIVISOR(pipe) \
- _PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR)
-
-#define PCH_PP_STATUS 0xc7200
-#define PCH_PP_CONTROL 0xc7204
+#define _PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c)
+#define _PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210)
+
+#define _PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300)
+#define _PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304)
+#define _PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308)
+#define _PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c)
+#define _PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310)
+
+#define VLV_PIPE_PP_STATUS(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_STATUS, _PIPEB_PP_STATUS)
+#define VLV_PIPE_PP_CONTROL(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_CONTROL, _PIPEB_PP_CONTROL)
+#define VLV_PIPE_PP_ON_DELAYS(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_ON_DELAYS, _PIPEB_PP_ON_DELAYS)
+#define VLV_PIPE_PP_OFF_DELAYS(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_OFF_DELAYS, _PIPEB_PP_OFF_DELAYS)
+#define VLV_PIPE_PP_DIVISOR(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_DIVISOR, _PIPEB_PP_DIVISOR)
+
+#define _PCH_PP_STATUS 0xc7200
+#define _PCH_PP_CONTROL 0xc7204
#define PANEL_UNLOCK_REGS (0xabcd << 16)
#define PANEL_UNLOCK_MASK (0xffff << 16)
#define BXT_POWER_CYCLE_DELAY_MASK (0x1f0)
@@ -6558,7 +6626,7 @@ enum skl_disp_power_wells {
#define PANEL_POWER_RESET (1 << 1)
#define PANEL_POWER_OFF (0 << 0)
#define PANEL_POWER_ON (1 << 0)
-#define PCH_PP_ON_DELAYS 0xc7208
+#define _PCH_PP_ON_DELAYS 0xc7208
#define PANEL_PORT_SELECT_MASK (3 << 30)
#define PANEL_PORT_SELECT_LVDS (0 << 30)
#define PANEL_PORT_SELECT_DPA (1 << 30)
@@ -6569,52 +6637,64 @@ enum skl_disp_power_wells {
#define PANEL_LIGHT_ON_DELAY_MASK (0x1fff)
#define PANEL_LIGHT_ON_DELAY_SHIFT 0
-#define PCH_PP_OFF_DELAYS 0xc720c
+#define _PCH_PP_OFF_DELAYS 0xc720c
#define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000)
#define PANEL_POWER_DOWN_DELAY_SHIFT 16
#define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff)
#define PANEL_LIGHT_OFF_DELAY_SHIFT 0
-#define PCH_PP_DIVISOR 0xc7210
+#define _PCH_PP_DIVISOR 0xc7210
#define PP_REFERENCE_DIVIDER_MASK (0xffffff00)
#define PP_REFERENCE_DIVIDER_SHIFT 8
#define PANEL_POWER_CYCLE_DELAY_MASK (0x1f)
#define PANEL_POWER_CYCLE_DELAY_SHIFT 0
+#define PCH_PP_STATUS _MMIO(_PCH_PP_STATUS)
+#define PCH_PP_CONTROL _MMIO(_PCH_PP_CONTROL)
+#define PCH_PP_ON_DELAYS _MMIO(_PCH_PP_ON_DELAYS)
+#define PCH_PP_OFF_DELAYS _MMIO(_PCH_PP_OFF_DELAYS)
+#define PCH_PP_DIVISOR _MMIO(_PCH_PP_DIVISOR)
+
/* BXT PPS changes - 2nd set of PPS registers */
#define _BXT_PP_STATUS2 0xc7300
#define _BXT_PP_CONTROL2 0xc7304
#define _BXT_PP_ON_DELAYS2 0xc7308
#define _BXT_PP_OFF_DELAYS2 0xc730c
-#define BXT_PP_STATUS(n) _PIPE(n, PCH_PP_STATUS, _BXT_PP_STATUS2)
-#define BXT_PP_CONTROL(n) _PIPE(n, PCH_PP_CONTROL, _BXT_PP_CONTROL2)
-#define BXT_PP_ON_DELAYS(n) _PIPE(n, PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2)
-#define BXT_PP_OFF_DELAYS(n) _PIPE(n, PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2)
-
-#define PCH_DP_B 0xe4100
-#define PCH_DPB_AUX_CH_CTL 0xe4110
-#define PCH_DPB_AUX_CH_DATA1 0xe4114
-#define PCH_DPB_AUX_CH_DATA2 0xe4118
-#define PCH_DPB_AUX_CH_DATA3 0xe411c
-#define PCH_DPB_AUX_CH_DATA4 0xe4120
-#define PCH_DPB_AUX_CH_DATA5 0xe4124
-
-#define PCH_DP_C 0xe4200
-#define PCH_DPC_AUX_CH_CTL 0xe4210
-#define PCH_DPC_AUX_CH_DATA1 0xe4214
-#define PCH_DPC_AUX_CH_DATA2 0xe4218
-#define PCH_DPC_AUX_CH_DATA3 0xe421c
-#define PCH_DPC_AUX_CH_DATA4 0xe4220
-#define PCH_DPC_AUX_CH_DATA5 0xe4224
-
-#define PCH_DP_D 0xe4300
-#define PCH_DPD_AUX_CH_CTL 0xe4310
-#define PCH_DPD_AUX_CH_DATA1 0xe4314
-#define PCH_DPD_AUX_CH_DATA2 0xe4318
-#define PCH_DPD_AUX_CH_DATA3 0xe431c
-#define PCH_DPD_AUX_CH_DATA4 0xe4320
-#define PCH_DPD_AUX_CH_DATA5 0xe4324
+#define BXT_PP_STATUS(n) _MMIO_PIPE(n, _PCH_PP_STATUS, _BXT_PP_STATUS2)
+#define BXT_PP_CONTROL(n) _MMIO_PIPE(n, _PCH_PP_CONTROL, _BXT_PP_CONTROL2)
+#define BXT_PP_ON_DELAYS(n) _MMIO_PIPE(n, _PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2)
+#define BXT_PP_OFF_DELAYS(n) _MMIO_PIPE(n, _PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2)
+
+#define _PCH_DP_B 0xe4100
+#define PCH_DP_B _MMIO(_PCH_DP_B)
+#define _PCH_DPB_AUX_CH_CTL 0xe4110
+#define _PCH_DPB_AUX_CH_DATA1 0xe4114
+#define _PCH_DPB_AUX_CH_DATA2 0xe4118
+#define _PCH_DPB_AUX_CH_DATA3 0xe411c
+#define _PCH_DPB_AUX_CH_DATA4 0xe4120
+#define _PCH_DPB_AUX_CH_DATA5 0xe4124
+
+#define _PCH_DP_C 0xe4200
+#define PCH_DP_C _MMIO(_PCH_DP_C)
+#define _PCH_DPC_AUX_CH_CTL 0xe4210
+#define _PCH_DPC_AUX_CH_DATA1 0xe4214
+#define _PCH_DPC_AUX_CH_DATA2 0xe4218
+#define _PCH_DPC_AUX_CH_DATA3 0xe421c
+#define _PCH_DPC_AUX_CH_DATA4 0xe4220
+#define _PCH_DPC_AUX_CH_DATA5 0xe4224
+
+#define _PCH_DP_D 0xe4300
+#define PCH_DP_D _MMIO(_PCH_DP_D)
+#define _PCH_DPD_AUX_CH_CTL 0xe4310
+#define _PCH_DPD_AUX_CH_DATA1 0xe4314
+#define _PCH_DPD_AUX_CH_DATA2 0xe4318
+#define _PCH_DPD_AUX_CH_DATA3 0xe431c
+#define _PCH_DPD_AUX_CH_DATA4 0xe4320
+#define _PCH_DPD_AUX_CH_DATA5 0xe4324
+
+#define PCH_DP_AUX_CH_CTL(port) _MMIO_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_CTL, _PCH_DPC_AUX_CH_CTL)
+#define PCH_DP_AUX_CH_DATA(port, i) _MMIO(_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_DATA1, _PCH_DPC_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
/* CPT */
#define PORT_TRANS_A_SEL_CPT 0
@@ -6627,10 +6707,10 @@ enum skl_disp_power_wells {
#define SDVO_PORT_TO_PIPE_CHV(val) (((val) & (3<<24)) >> 24)
#define DP_PORT_TO_PIPE_CHV(val) (((val) & (3<<16)) >> 16)
-#define TRANS_DP_CTL_A 0xe0300
-#define TRANS_DP_CTL_B 0xe1300
-#define TRANS_DP_CTL_C 0xe2300
-#define TRANS_DP_CTL(pipe) _PIPE(pipe, TRANS_DP_CTL_A, TRANS_DP_CTL_B)
+#define _TRANS_DP_CTL_A 0xe0300
+#define _TRANS_DP_CTL_B 0xe1300
+#define _TRANS_DP_CTL_C 0xe2300
+#define TRANS_DP_CTL(pipe) _MMIO_PIPE(pipe, _TRANS_DP_CTL_A, _TRANS_DP_CTL_B)
#define TRANS_DP_OUTPUT_ENABLE (1<<31)
#define TRANS_DP_PORT_SEL_B (0<<29)
#define TRANS_DP_PORT_SEL_C (1<<29)
@@ -6683,40 +6763,40 @@ enum skl_disp_power_wells {
#define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22)
-#define VLV_PMWGICZ 0x1300a4
+#define VLV_PMWGICZ _MMIO(0x1300a4)
-#define FORCEWAKE 0xA18C
-#define FORCEWAKE_VLV 0x1300b0
-#define FORCEWAKE_ACK_VLV 0x1300b4
-#define FORCEWAKE_MEDIA_VLV 0x1300b8
-#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc
-#define FORCEWAKE_ACK_HSW 0x130044
-#define FORCEWAKE_ACK 0x130090
-#define VLV_GTLC_WAKE_CTRL 0x130090
+#define FORCEWAKE _MMIO(0xA18C)
+#define FORCEWAKE_VLV _MMIO(0x1300b0)
+#define FORCEWAKE_ACK_VLV _MMIO(0x1300b4)
+#define FORCEWAKE_MEDIA_VLV _MMIO(0x1300b8)
+#define FORCEWAKE_ACK_MEDIA_VLV _MMIO(0x1300bc)
+#define FORCEWAKE_ACK_HSW _MMIO(0x130044)
+#define FORCEWAKE_ACK _MMIO(0x130090)
+#define VLV_GTLC_WAKE_CTRL _MMIO(0x130090)
#define VLV_GTLC_RENDER_CTX_EXISTS (1 << 25)
#define VLV_GTLC_MEDIA_CTX_EXISTS (1 << 24)
#define VLV_GTLC_ALLOWWAKEREQ (1 << 0)
-#define VLV_GTLC_PW_STATUS 0x130094
+#define VLV_GTLC_PW_STATUS _MMIO(0x130094)
#define VLV_GTLC_ALLOWWAKEACK (1 << 0)
#define VLV_GTLC_ALLOWWAKEERR (1 << 1)
#define VLV_GTLC_PW_MEDIA_STATUS_MASK (1 << 5)
#define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7)
-#define FORCEWAKE_MT 0xa188 /* multi-threaded */
-#define FORCEWAKE_MEDIA_GEN9 0xa270
-#define FORCEWAKE_RENDER_GEN9 0xa278
-#define FORCEWAKE_BLITTER_GEN9 0xa188
-#define FORCEWAKE_ACK_MEDIA_GEN9 0x0D88
-#define FORCEWAKE_ACK_RENDER_GEN9 0x0D84
-#define FORCEWAKE_ACK_BLITTER_GEN9 0x130044
+#define FORCEWAKE_MT _MMIO(0xa188) /* multi-threaded */
+#define FORCEWAKE_MEDIA_GEN9 _MMIO(0xa270)
+#define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278)
+#define FORCEWAKE_BLITTER_GEN9 _MMIO(0xa188)
+#define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0x0D88)
+#define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0x0D84)
+#define FORCEWAKE_ACK_BLITTER_GEN9 _MMIO(0x130044)
#define FORCEWAKE_KERNEL 0x1
#define FORCEWAKE_USER 0x2
-#define FORCEWAKE_MT_ACK 0x130040
-#define ECOBUS 0xa180
+#define FORCEWAKE_MT_ACK _MMIO(0x130040)
+#define ECOBUS _MMIO(0xa180)
#define FORCEWAKE_MT_ENABLE (1<<5)
-#define VLV_SPAREG2H 0xA194
+#define VLV_SPAREG2H _MMIO(0xA194)
-#define GTFIFODBG 0x120000
+#define GTFIFODBG _MMIO(0x120000)
#define GT_FIFO_SBDROPERR (1<<6)
#define GT_FIFO_BLOBDROPERR (1<<5)
#define GT_FIFO_SB_READ_ABORTERR (1<<4)
@@ -6725,23 +6805,23 @@ enum skl_disp_power_wells {
#define GT_FIFO_IAWRERR (1<<1)
#define GT_FIFO_IARDERR (1<<0)
-#define GTFIFOCTL 0x120008
+#define GTFIFOCTL _MMIO(0x120008)
#define GT_FIFO_FREE_ENTRIES_MASK 0x7f
#define GT_FIFO_NUM_RESERVED_ENTRIES 20
#define GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL (1 << 12)
#define GT_FIFO_CTL_RC6_POLICY_STALL (1 << 11)
-#define HSW_IDICR 0x9008
+#define HSW_IDICR _MMIO(0x9008)
#define IDIHASHMSK(x) (((x) & 0x3f) << 16)
-#define HSW_EDRAM_PRESENT 0x120010
+#define HSW_EDRAM_PRESENT _MMIO(0x120010)
#define EDRAM_ENABLED 0x1
-#define GEN6_UCGCTL1 0x9400
+#define GEN6_UCGCTL1 _MMIO(0x9400)
# define GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE (1 << 16)
# define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5)
# define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7)
-#define GEN6_UCGCTL2 0x9404
+#define GEN6_UCGCTL2 _MMIO(0x9404)
# define GEN6_VFUNIT_CLOCK_GATE_DISABLE (1 << 31)
# define GEN7_VDSUNIT_CLOCK_GATE_DISABLE (1 << 30)
# define GEN7_TDLUNIT_CLOCK_GATE_DISABLE (1 << 22)
@@ -6749,30 +6829,30 @@ enum skl_disp_power_wells {
# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12)
# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11)
-#define GEN6_UCGCTL3 0x9408
+#define GEN6_UCGCTL3 _MMIO(0x9408)
-#define GEN7_UCGCTL4 0x940c
+#define GEN7_UCGCTL4 _MMIO(0x940c)
#define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25)
-#define GEN6_RCGCTL1 0x9410
-#define GEN6_RCGCTL2 0x9414
-#define GEN6_RSTCTL 0x9420
+#define GEN6_RCGCTL1 _MMIO(0x9410)
+#define GEN6_RCGCTL2 _MMIO(0x9414)
+#define GEN6_RSTCTL _MMIO(0x9420)
-#define GEN8_UCGCTL6 0x9430
+#define GEN8_UCGCTL6 _MMIO(0x9430)
#define GEN8_GAPSUNIT_CLOCK_GATE_DISABLE (1<<24)
#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14)
#define GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ (1<<28)
-#define GEN6_GFXPAUSE 0xA000
-#define GEN6_RPNSWREQ 0xA008
+#define GEN6_GFXPAUSE _MMIO(0xA000)
+#define GEN6_RPNSWREQ _MMIO(0xA008)
#define GEN6_TURBO_DISABLE (1<<31)
#define GEN6_FREQUENCY(x) ((x)<<25)
#define HSW_FREQUENCY(x) ((x)<<24)
#define GEN9_FREQUENCY(x) ((x)<<23)
#define GEN6_OFFSET(x) ((x)<<19)
#define GEN6_AGGRESSIVE_TURBO (0<<15)
-#define GEN6_RC_VIDEO_FREQ 0xA00C
-#define GEN6_RC_CONTROL 0xA090
+#define GEN6_RC_VIDEO_FREQ _MMIO(0xA00C)
+#define GEN6_RC_CONTROL _MMIO(0xA090)
#define GEN6_RC_CTL_RC6pp_ENABLE (1<<16)
#define GEN6_RC_CTL_RC6p_ENABLE (1<<17)
#define GEN6_RC_CTL_RC6_ENABLE (1<<18)
@@ -6782,16 +6862,16 @@ enum skl_disp_power_wells {
#define GEN7_RC_CTL_TO_MODE (1<<28)
#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27)
#define GEN6_RC_CTL_HW_ENABLE (1<<31)
-#define GEN6_RP_DOWN_TIMEOUT 0xA010
-#define GEN6_RP_INTERRUPT_LIMITS 0xA014
-#define GEN6_RPSTAT1 0xA01C
+#define GEN6_RP_DOWN_TIMEOUT _MMIO(0xA010)
+#define GEN6_RP_INTERRUPT_LIMITS _MMIO(0xA014)
+#define GEN6_RPSTAT1 _MMIO(0xA01C)
#define GEN6_CAGF_SHIFT 8
#define HSW_CAGF_SHIFT 7
#define GEN9_CAGF_SHIFT 23
#define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT)
#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT)
#define GEN9_CAGF_MASK (0x1ff << GEN9_CAGF_SHIFT)
-#define GEN6_RP_CONTROL 0xA024
+#define GEN6_RP_CONTROL _MMIO(0xA024)
#define GEN6_RP_MEDIA_TURBO (1<<11)
#define GEN6_RP_MEDIA_MODE_MASK (3<<9)
#define GEN6_RP_MEDIA_HW_TURBO_MODE (3<<9)
@@ -6805,53 +6885,53 @@ enum skl_disp_power_wells {
#define GEN6_RP_UP_BUSY_CONT (0x4<<3)
#define GEN6_RP_DOWN_IDLE_AVG (0x2<<0)
#define GEN6_RP_DOWN_IDLE_CONT (0x1<<0)
-#define GEN6_RP_UP_THRESHOLD 0xA02C
-#define GEN6_RP_DOWN_THRESHOLD 0xA030
-#define GEN6_RP_CUR_UP_EI 0xA050
+#define GEN6_RP_UP_THRESHOLD _MMIO(0xA02C)
+#define GEN6_RP_DOWN_THRESHOLD _MMIO(0xA030)
+#define GEN6_RP_CUR_UP_EI _MMIO(0xA050)
#define GEN6_CURICONT_MASK 0xffffff
-#define GEN6_RP_CUR_UP 0xA054
+#define GEN6_RP_CUR_UP _MMIO(0xA054)
#define GEN6_CURBSYTAVG_MASK 0xffffff
-#define GEN6_RP_PREV_UP 0xA058
-#define GEN6_RP_CUR_DOWN_EI 0xA05C
+#define GEN6_RP_PREV_UP _MMIO(0xA058)
+#define GEN6_RP_CUR_DOWN_EI _MMIO(0xA05C)
#define GEN6_CURIAVG_MASK 0xffffff
-#define GEN6_RP_CUR_DOWN 0xA060
-#define GEN6_RP_PREV_DOWN 0xA064
-#define GEN6_RP_UP_EI 0xA068
-#define GEN6_RP_DOWN_EI 0xA06C
-#define GEN6_RP_IDLE_HYSTERSIS 0xA070
-#define GEN6_RPDEUHWTC 0xA080
-#define GEN6_RPDEUC 0xA084
-#define GEN6_RPDEUCSW 0xA088
-#define GEN6_RC_STATE 0xA094
-#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098
-#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C
-#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0
-#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8
-#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC
-#define GEN6_RC_SLEEP 0xA0B0
-#define GEN6_RCUBMABDTMR 0xA0B0
-#define GEN6_RC1e_THRESHOLD 0xA0B4
-#define GEN6_RC6_THRESHOLD 0xA0B8
-#define GEN6_RC6p_THRESHOLD 0xA0BC
-#define VLV_RCEDATA 0xA0BC
-#define GEN6_RC6pp_THRESHOLD 0xA0C0
-#define GEN6_PMINTRMSK 0xA168
+#define GEN6_RP_CUR_DOWN _MMIO(0xA060)
+#define GEN6_RP_PREV_DOWN _MMIO(0xA064)
+#define GEN6_RP_UP_EI _MMIO(0xA068)
+#define GEN6_RP_DOWN_EI _MMIO(0xA06C)
+#define GEN6_RP_IDLE_HYSTERSIS _MMIO(0xA070)
+#define GEN6_RPDEUHWTC _MMIO(0xA080)
+#define GEN6_RPDEUC _MMIO(0xA084)
+#define GEN6_RPDEUCSW _MMIO(0xA088)
+#define GEN6_RC_STATE _MMIO(0xA094)
+#define GEN6_RC1_WAKE_RATE_LIMIT _MMIO(0xA098)
+#define GEN6_RC6_WAKE_RATE_LIMIT _MMIO(0xA09C)
+#define GEN6_RC6pp_WAKE_RATE_LIMIT _MMIO(0xA0A0)
+#define GEN6_RC_EVALUATION_INTERVAL _MMIO(0xA0A8)
+#define GEN6_RC_IDLE_HYSTERSIS _MMIO(0xA0AC)
+#define GEN6_RC_SLEEP _MMIO(0xA0B0)
+#define GEN6_RCUBMABDTMR _MMIO(0xA0B0)
+#define GEN6_RC1e_THRESHOLD _MMIO(0xA0B4)
+#define GEN6_RC6_THRESHOLD _MMIO(0xA0B8)
+#define GEN6_RC6p_THRESHOLD _MMIO(0xA0BC)
+#define VLV_RCEDATA _MMIO(0xA0BC)
+#define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0)
+#define GEN6_PMINTRMSK _MMIO(0xA168)
#define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31)
-#define VLV_PWRDWNUPCTL 0xA294
-#define GEN9_MEDIA_PG_IDLE_HYSTERESIS 0xA0C4
-#define GEN9_RENDER_PG_IDLE_HYSTERESIS 0xA0C8
-#define GEN9_PG_ENABLE 0xA210
+#define VLV_PWRDWNUPCTL _MMIO(0xA294)
+#define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4)
+#define GEN9_RENDER_PG_IDLE_HYSTERESIS _MMIO(0xA0C8)
+#define GEN9_PG_ENABLE _MMIO(0xA210)
#define GEN9_RENDER_PG_ENABLE (1<<0)
#define GEN9_MEDIA_PG_ENABLE (1<<1)
-#define VLV_CHICKEN_3 (VLV_DISPLAY_BASE + 0x7040C)
+#define VLV_CHICKEN_3 _MMIO(VLV_DISPLAY_BASE + 0x7040C)
#define PIXEL_OVERLAP_CNT_MASK (3 << 30)
#define PIXEL_OVERLAP_CNT_SHIFT 30
-#define GEN6_PMISR 0x44020
-#define GEN6_PMIMR 0x44024 /* rps_lock */
-#define GEN6_PMIIR 0x44028
-#define GEN6_PMIER 0x4402C
+#define GEN6_PMISR _MMIO(0x44020)
+#define GEN6_PMIMR _MMIO(0x44024) /* rps_lock */
+#define GEN6_PMIIR _MMIO(0x44028)
+#define GEN6_PMIER _MMIO(0x4402C)
#define GEN6_PM_MBOX_EVENT (1<<25)
#define GEN6_PM_THERMAL_EVENT (1<<24)
#define GEN6_PM_RP_DOWN_TIMEOUT (1<<6)
@@ -6863,30 +6943,30 @@ enum skl_disp_power_wells {
GEN6_PM_RP_DOWN_THRESHOLD | \
GEN6_PM_RP_DOWN_TIMEOUT)
-#define GEN7_GT_SCRATCH(i) (0x4F100 + (i) * 4)
+#define GEN7_GT_SCRATCH(i) _MMIO(0x4F100 + (i) * 4)
#define GEN7_GT_SCRATCH_REG_NUM 8
-#define VLV_GTLC_SURVIVABILITY_REG 0x130098
+#define VLV_GTLC_SURVIVABILITY_REG _MMIO(0x130098)
#define VLV_GFX_CLK_STATUS_BIT (1<<3)
#define VLV_GFX_CLK_FORCE_ON_BIT (1<<2)
-#define GEN6_GT_GFX_RC6_LOCKED 0x138104
-#define VLV_COUNTER_CONTROL 0x138104
+#define GEN6_GT_GFX_RC6_LOCKED _MMIO(0x138104)
+#define VLV_COUNTER_CONTROL _MMIO(0x138104)
#define VLV_COUNT_RANGE_HIGH (1<<15)
#define VLV_MEDIA_RC0_COUNT_EN (1<<5)
#define VLV_RENDER_RC0_COUNT_EN (1<<4)
#define VLV_MEDIA_RC6_COUNT_EN (1<<1)
#define VLV_RENDER_RC6_COUNT_EN (1<<0)
-#define GEN6_GT_GFX_RC6 0x138108
-#define VLV_GT_RENDER_RC6 0x138108
-#define VLV_GT_MEDIA_RC6 0x13810C
+#define GEN6_GT_GFX_RC6 _MMIO(0x138108)
+#define VLV_GT_RENDER_RC6 _MMIO(0x138108)
+#define VLV_GT_MEDIA_RC6 _MMIO(0x13810C)
-#define GEN6_GT_GFX_RC6p 0x13810C
-#define GEN6_GT_GFX_RC6pp 0x138110
-#define VLV_RENDER_C0_COUNT 0x138118
-#define VLV_MEDIA_C0_COUNT 0x13811C
+#define GEN6_GT_GFX_RC6p _MMIO(0x13810C)
+#define GEN6_GT_GFX_RC6pp _MMIO(0x138110)
+#define VLV_RENDER_C0_COUNT _MMIO(0x138118)
+#define VLV_MEDIA_C0_COUNT _MMIO(0x13811C)
-#define GEN6_PCODE_MAILBOX 0x138124
+#define GEN6_PCODE_MAILBOX _MMIO(0x138124)
#define GEN6_PCODE_READY (1<<31)
#define GEN6_PCODE_WRITE_RC6VIDS 0x4
#define GEN6_PCODE_READ_RC6VIDS 0x5
@@ -6909,12 +6989,12 @@ enum skl_disp_power_wells {
#define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17
#define DISPLAY_IPS_CONTROL 0x19
#define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A
-#define GEN6_PCODE_DATA 0x138128
+#define GEN6_PCODE_DATA _MMIO(0x138128)
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
-#define GEN6_PCODE_DATA1 0x13812C
+#define GEN6_PCODE_DATA1 _MMIO(0x13812C)
-#define GEN6_GT_CORE_STATUS 0x138060
+#define GEN6_GT_CORE_STATUS _MMIO(0x138060)
#define GEN6_CORE_CPD_STATE_MASK (7<<4)
#define GEN6_RCn_MASK 7
#define GEN6_RC0 0
@@ -6922,26 +7002,26 @@ enum skl_disp_power_wells {
#define GEN6_RC6 3
#define GEN6_RC7 4
-#define GEN8_GT_SLICE_INFO 0x138064
+#define GEN8_GT_SLICE_INFO _MMIO(0x138064)
#define GEN8_LSLICESTAT_MASK 0x7
-#define CHV_POWER_SS0_SIG1 0xa720
-#define CHV_POWER_SS1_SIG1 0xa728
+#define CHV_POWER_SS0_SIG1 _MMIO(0xa720)
+#define CHV_POWER_SS1_SIG1 _MMIO(0xa728)
#define CHV_SS_PG_ENABLE (1<<1)
#define CHV_EU08_PG_ENABLE (1<<9)
#define CHV_EU19_PG_ENABLE (1<<17)
#define CHV_EU210_PG_ENABLE (1<<25)
-#define CHV_POWER_SS0_SIG2 0xa724
-#define CHV_POWER_SS1_SIG2 0xa72c
+#define CHV_POWER_SS0_SIG2 _MMIO(0xa724)
+#define CHV_POWER_SS1_SIG2 _MMIO(0xa72c)
#define CHV_EU311_PG_ENABLE (1<<1)
-#define GEN9_SLICE_PGCTL_ACK(slice) (0x804c + (slice)*0x4)
+#define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice)*0x4)
#define GEN9_PGCTL_SLICE_ACK (1 << 0)
#define GEN9_PGCTL_SS_ACK(subslice) (1 << (2 + (subslice)*2))
-#define GEN9_SS01_EU_PGCTL_ACK(slice) (0x805c + (slice)*0x8)
-#define GEN9_SS23_EU_PGCTL_ACK(slice) (0x8060 + (slice)*0x8)
+#define GEN9_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + (slice)*0x8)
+#define GEN9_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + (slice)*0x8)
#define GEN9_PGCTL_SSA_EU08_ACK (1 << 0)
#define GEN9_PGCTL_SSA_EU19_ACK (1 << 2)
#define GEN9_PGCTL_SSA_EU210_ACK (1 << 4)
@@ -6951,18 +7031,17 @@ enum skl_disp_power_wells {
#define GEN9_PGCTL_SSB_EU210_ACK (1 << 12)
#define GEN9_PGCTL_SSB_EU311_ACK (1 << 14)
-#define GEN7_MISCCPCTL (0x9424)
+#define GEN7_MISCCPCTL _MMIO(0x9424)
#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0)
#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1<<2)
#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1<<4)
#define GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE (1<<6)
-#define GEN8_GARBCNTL 0xB004
+#define GEN8_GARBCNTL _MMIO(0xB004)
#define GEN9_GAPS_TSV_CREDIT_DISABLE (1<<7)
/* IVYBRIDGE DPF */
-#define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */
-#define HSW_L3CDERRST11 0xB208 /* L3CD Error Status register 1 slice 1 */
+#define GEN7_L3CDERRST1(slice) _MMIO(0xB008 + (slice) * 0x200) /* L3CD Error Status 1 */
#define GEN7_L3CDERRST1_ROW_MASK (0x7ff<<14)
#define GEN7_PARITY_ERROR_VALID (1<<13)
#define GEN7_L3CDERRST1_BANK_MASK (3<<11)
@@ -6975,119 +7054,102 @@ enum skl_disp_power_wells {
((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8)
#define GEN7_L3CDERRST1_ENABLE (1<<7)
-#define GEN7_L3LOG_BASE 0xB070
-#define HSW_L3LOG_BASE_SLICE1 0xB270
+#define GEN7_L3LOG(slice, i) _MMIO(0xB070 + (slice) * 0x200 + (i) * 4)
#define GEN7_L3LOG_SIZE 0x80
-#define GEN7_HALF_SLICE_CHICKEN1 0xe100 /* IVB GT1 + VLV */
-#define GEN7_HALF_SLICE_CHICKEN1_GT2 0xf100
+#define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */
+#define GEN7_HALF_SLICE_CHICKEN1_GT2 _MMIO(0xf100)
#define GEN7_MAX_PS_THREAD_DEP (8<<12)
#define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1<<10)
#define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1<<4)
#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3)
-#define GEN9_HALF_SLICE_CHICKEN5 0xe188
+#define GEN9_HALF_SLICE_CHICKEN5 _MMIO(0xe188)
#define GEN9_DG_MIRROR_FIX_ENABLE (1<<5)
#define GEN9_CCS_TLB_PREFETCH_ENABLE (1<<3)
-#define GEN8_ROW_CHICKEN 0xe4f0
+#define GEN8_ROW_CHICKEN _MMIO(0xe4f0)
#define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1<<8)
#define STALL_DOP_GATING_DISABLE (1<<5)
-#define GEN7_ROW_CHICKEN2 0xe4f4
-#define GEN7_ROW_CHICKEN2_GT2 0xf4f4
+#define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4)
+#define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4)
#define DOP_CLOCK_GATING_DISABLE (1<<0)
-#define HSW_ROW_CHICKEN3 0xe49c
+#define HSW_ROW_CHICKEN3 _MMIO(0xe49c)
#define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6)
-#define HALF_SLICE_CHICKEN2 0xe180
+#define HALF_SLICE_CHICKEN2 _MMIO(0xe180)
#define GEN8_ST_PO_DISABLE (1<<13)
-#define HALF_SLICE_CHICKEN3 0xe184
+#define HALF_SLICE_CHICKEN3 _MMIO(0xe184)
#define HSW_SAMPLE_C_PERFORMANCE (1<<9)
#define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8)
#define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1<<5)
#define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1)
-#define GEN9_HALF_SLICE_CHICKEN7 0xe194
+#define GEN9_HALF_SLICE_CHICKEN7 _MMIO(0xe194)
#define GEN9_ENABLE_YV12_BUGFIX (1<<4)
/* Audio */
-#define G4X_AUD_VID_DID (dev_priv->info.display_mmio_offset + 0x62020)
+#define G4X_AUD_VID_DID _MMIO(dev_priv->info.display_mmio_offset + 0x62020)
#define INTEL_AUDIO_DEVCL 0x808629FB
#define INTEL_AUDIO_DEVBLC 0x80862801
#define INTEL_AUDIO_DEVCTG 0x80862802
-#define G4X_AUD_CNTL_ST 0x620B4
+#define G4X_AUD_CNTL_ST _MMIO(0x620B4)
#define G4X_ELDV_DEVCL_DEVBLC (1 << 13)
#define G4X_ELDV_DEVCTG (1 << 14)
#define G4X_ELD_ADDR_MASK (0xf << 5)
#define G4X_ELD_ACK (1 << 4)
-#define G4X_HDMIW_HDMIEDID 0x6210C
+#define G4X_HDMIW_HDMIEDID _MMIO(0x6210C)
#define _IBX_HDMIW_HDMIEDID_A 0xE2050
#define _IBX_HDMIW_HDMIEDID_B 0xE2150
-#define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
- _IBX_HDMIW_HDMIEDID_A, \
- _IBX_HDMIW_HDMIEDID_B)
+#define IBX_HDMIW_HDMIEDID(pipe) _MMIO_PIPE(pipe, _IBX_HDMIW_HDMIEDID_A, \
+ _IBX_HDMIW_HDMIEDID_B)
#define _IBX_AUD_CNTL_ST_A 0xE20B4
#define _IBX_AUD_CNTL_ST_B 0xE21B4
-#define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \
- _IBX_AUD_CNTL_ST_A, \
- _IBX_AUD_CNTL_ST_B)
+#define IBX_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _IBX_AUD_CNTL_ST_A, \
+ _IBX_AUD_CNTL_ST_B)
#define IBX_ELD_BUFFER_SIZE_MASK (0x1f << 10)
#define IBX_ELD_ADDRESS_MASK (0x1f << 5)
#define IBX_ELD_ACK (1 << 4)
-#define IBX_AUD_CNTL_ST2 0xE20C0
+#define IBX_AUD_CNTL_ST2 _MMIO(0xE20C0)
#define IBX_CP_READY(port) ((1 << 1) << (((port) - 1) * 4))
#define IBX_ELD_VALID(port) ((1 << 0) << (((port) - 1) * 4))
#define _CPT_HDMIW_HDMIEDID_A 0xE5050
#define _CPT_HDMIW_HDMIEDID_B 0xE5150
-#define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
- _CPT_HDMIW_HDMIEDID_A, \
- _CPT_HDMIW_HDMIEDID_B)
+#define CPT_HDMIW_HDMIEDID(pipe) _MMIO_PIPE(pipe, _CPT_HDMIW_HDMIEDID_A, _CPT_HDMIW_HDMIEDID_B)
#define _CPT_AUD_CNTL_ST_A 0xE50B4
#define _CPT_AUD_CNTL_ST_B 0xE51B4
-#define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \
- _CPT_AUD_CNTL_ST_A, \
- _CPT_AUD_CNTL_ST_B)
-#define CPT_AUD_CNTRL_ST2 0xE50C0
+#define CPT_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _CPT_AUD_CNTL_ST_A, _CPT_AUD_CNTL_ST_B)
+#define CPT_AUD_CNTRL_ST2 _MMIO(0xE50C0)
#define _VLV_HDMIW_HDMIEDID_A (VLV_DISPLAY_BASE + 0x62050)
#define _VLV_HDMIW_HDMIEDID_B (VLV_DISPLAY_BASE + 0x62150)
-#define VLV_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
- _VLV_HDMIW_HDMIEDID_A, \
- _VLV_HDMIW_HDMIEDID_B)
+#define VLV_HDMIW_HDMIEDID(pipe) _MMIO_PIPE(pipe, _VLV_HDMIW_HDMIEDID_A, _VLV_HDMIW_HDMIEDID_B)
#define _VLV_AUD_CNTL_ST_A (VLV_DISPLAY_BASE + 0x620B4)
#define _VLV_AUD_CNTL_ST_B (VLV_DISPLAY_BASE + 0x621B4)
-#define VLV_AUD_CNTL_ST(pipe) _PIPE(pipe, \
- _VLV_AUD_CNTL_ST_A, \
- _VLV_AUD_CNTL_ST_B)
-#define VLV_AUD_CNTL_ST2 (VLV_DISPLAY_BASE + 0x620C0)
+#define VLV_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _VLV_AUD_CNTL_ST_A, _VLV_AUD_CNTL_ST_B)
+#define VLV_AUD_CNTL_ST2 _MMIO(VLV_DISPLAY_BASE + 0x620C0)
/* These are the 4 32-bit write offset registers for each stream
* output buffer. It determines the offset from the
* 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to.
*/
-#define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4)
+#define GEN7_SO_WRITE_OFFSET(n) _MMIO(0x5280 + (n) * 4)
#define _IBX_AUD_CONFIG_A 0xe2000
#define _IBX_AUD_CONFIG_B 0xe2100
-#define IBX_AUD_CFG(pipe) _PIPE(pipe, \
- _IBX_AUD_CONFIG_A, \
- _IBX_AUD_CONFIG_B)
+#define IBX_AUD_CFG(pipe) _MMIO_PIPE(pipe, _IBX_AUD_CONFIG_A, _IBX_AUD_CONFIG_B)
#define _CPT_AUD_CONFIG_A 0xe5000
#define _CPT_AUD_CONFIG_B 0xe5100
-#define CPT_AUD_CFG(pipe) _PIPE(pipe, \
- _CPT_AUD_CONFIG_A, \
- _CPT_AUD_CONFIG_B)
+#define CPT_AUD_CFG(pipe) _MMIO_PIPE(pipe, _CPT_AUD_CONFIG_A, _CPT_AUD_CONFIG_B)
#define _VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000)
#define _VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100)
-#define VLV_AUD_CFG(pipe) _PIPE(pipe, \
- _VLV_AUD_CONFIG_A, \
- _VLV_AUD_CONFIG_B)
+#define VLV_AUD_CFG(pipe) _MMIO_PIPE(pipe, _VLV_AUD_CONFIG_A, _VLV_AUD_CONFIG_B)
#define AUD_CONFIG_N_VALUE_INDEX (1 << 29)
#define AUD_CONFIG_N_PROG_ENABLE (1 << 28)
@@ -7112,72 +7174,62 @@ enum skl_disp_power_wells {
/* HSW Audio */
#define _HSW_AUD_CONFIG_A 0x65000
#define _HSW_AUD_CONFIG_B 0x65100
-#define HSW_AUD_CFG(pipe) _PIPE(pipe, \
- _HSW_AUD_CONFIG_A, \
- _HSW_AUD_CONFIG_B)
+#define HSW_AUD_CFG(pipe) _MMIO_PIPE(pipe, _HSW_AUD_CONFIG_A, _HSW_AUD_CONFIG_B)
#define _HSW_AUD_MISC_CTRL_A 0x65010
#define _HSW_AUD_MISC_CTRL_B 0x65110
-#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \
- _HSW_AUD_MISC_CTRL_A, \
- _HSW_AUD_MISC_CTRL_B)
+#define HSW_AUD_MISC_CTRL(pipe) _MMIO_PIPE(pipe, _HSW_AUD_MISC_CTRL_A, _HSW_AUD_MISC_CTRL_B)
#define _HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4
#define _HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4
-#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \
- _HSW_AUD_DIP_ELD_CTRL_ST_A, \
- _HSW_AUD_DIP_ELD_CTRL_ST_B)
+#define HSW_AUD_DIP_ELD_CTRL(pipe) _MMIO_PIPE(pipe, _HSW_AUD_DIP_ELD_CTRL_ST_A, _HSW_AUD_DIP_ELD_CTRL_ST_B)
/* Audio Digital Converter */
#define _HSW_AUD_DIG_CNVT_1 0x65080
#define _HSW_AUD_DIG_CNVT_2 0x65180
-#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \
- _HSW_AUD_DIG_CNVT_1, \
- _HSW_AUD_DIG_CNVT_2)
+#define AUD_DIG_CNVT(pipe) _MMIO_PIPE(pipe, _HSW_AUD_DIG_CNVT_1, _HSW_AUD_DIG_CNVT_2)
#define DIP_PORT_SEL_MASK 0x3
#define _HSW_AUD_EDID_DATA_A 0x65050
#define _HSW_AUD_EDID_DATA_B 0x65150
-#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \
- _HSW_AUD_EDID_DATA_A, \
- _HSW_AUD_EDID_DATA_B)
+#define HSW_AUD_EDID_DATA(pipe) _MMIO_PIPE(pipe, _HSW_AUD_EDID_DATA_A, _HSW_AUD_EDID_DATA_B)
-#define HSW_AUD_PIPE_CONV_CFG 0x6507c
-#define HSW_AUD_PIN_ELD_CP_VLD 0x650c0
+#define HSW_AUD_PIPE_CONV_CFG _MMIO(0x6507c)
+#define HSW_AUD_PIN_ELD_CP_VLD _MMIO(0x650c0)
#define AUDIO_INACTIVE(trans) ((1 << 3) << ((trans) * 4))
#define AUDIO_OUTPUT_ENABLE(trans) ((1 << 2) << ((trans) * 4))
#define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4))
#define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4))
-#define HSW_AUD_CHICKENBIT 0x65f10
+#define HSW_AUD_CHICKENBIT _MMIO(0x65f10)
#define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15)
/* HSW Power Wells */
-#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */
-#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */
-#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */
-#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */
+#define HSW_PWR_WELL_BIOS _MMIO(0x45400) /* CTL1 */
+#define HSW_PWR_WELL_DRIVER _MMIO(0x45404) /* CTL2 */
+#define HSW_PWR_WELL_KVMR _MMIO(0x45408) /* CTL3 */
+#define HSW_PWR_WELL_DEBUG _MMIO(0x4540C) /* CTL4 */
#define HSW_PWR_WELL_ENABLE_REQUEST (1<<31)
#define HSW_PWR_WELL_STATE_ENABLED (1<<30)
-#define HSW_PWR_WELL_CTL5 0x45410
+#define HSW_PWR_WELL_CTL5 _MMIO(0x45410)
#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31)
#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20)
#define HSW_PWR_WELL_FORCE_ON (1<<19)
-#define HSW_PWR_WELL_CTL6 0x45414
+#define HSW_PWR_WELL_CTL6 _MMIO(0x45414)
/* SKL Fuse Status */
-#define SKL_FUSE_STATUS 0x42000
+#define SKL_FUSE_STATUS _MMIO(0x42000)
#define SKL_FUSE_DOWNLOAD_STATUS (1<<31)
#define SKL_FUSE_PG0_DIST_STATUS (1<<27)
#define SKL_FUSE_PG1_DIST_STATUS (1<<26)
#define SKL_FUSE_PG2_DIST_STATUS (1<<25)
/* 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(tran) _TRANSCODER2(tran, TRANS_DDI_FUNC_CTL_A)
+#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(tran) _MMIO_TRANS2(tran, _TRANS_DDI_FUNC_CTL_A)
#define TRANS_DDI_FUNC_ENABLE (1<<31)
/* Those bits are ignored by pipe EDP since it can only connect to DDI A */
@@ -7207,9 +7259,9 @@ enum skl_disp_power_wells {
#define TRANS_DDI_BFI_ENABLE (1<<4)
/* DisplayPort Transport Control */
-#define DP_TP_CTL_A 0x64040
-#define DP_TP_CTL_B 0x64140
-#define DP_TP_CTL(port) _PORT(port, DP_TP_CTL_A, DP_TP_CTL_B)
+#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_MODE_SST (0<<27)
#define DP_TP_CTL_MODE_MST (1<<27)
@@ -7225,9 +7277,9 @@ enum skl_disp_power_wells {
#define DP_TP_CTL_SCRAMBLE_DISABLE (1<<7)
/* DisplayPort Transport Status */
-#define DP_TP_STATUS_A 0x64044
-#define DP_TP_STATUS_B 0x64144
-#define DP_TP_STATUS(port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B)
+#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_IDLE_DONE (1<<25)
#define DP_TP_STATUS_ACT_SENT (1<<24)
#define DP_TP_STATUS_MODE_STATUS_MST (1<<23)
@@ -7237,9 +7289,9 @@ enum skl_disp_power_wells {
#define DP_TP_STATUS_PAYLOAD_MAPPING_VC0 (3 << 0)
/* DDI Buffer Control */
-#define DDI_BUF_CTL_A 0x64000
-#define DDI_BUF_CTL_B 0x64100
-#define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B)
+#define _DDI_BUF_CTL_A 0x64000
+#define _DDI_BUF_CTL_B 0x64100
+#define DDI_BUF_CTL(port) _MMIO_PORT(port, _DDI_BUF_CTL_A, _DDI_BUF_CTL_B)
#define DDI_BUF_CTL_ENABLE (1<<31)
#define DDI_BUF_TRANS_SELECT(n) ((n) << 24)
#define DDI_BUF_EMP_MASK (0xf<<24)
@@ -7252,17 +7304,17 @@ enum skl_disp_power_wells {
#define DDI_INIT_DISPLAY_DETECTED (1<<0)
/* DDI Buffer Translations */
-#define DDI_BUF_TRANS_A 0x64E00
-#define DDI_BUF_TRANS_B 0x64E60
-#define DDI_BUF_TRANS_LO(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8)
-#define DDI_BUF_TRANS_HI(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8 + 4)
+#define _DDI_BUF_TRANS_A 0x64E00
+#define _DDI_BUF_TRANS_B 0x64E60
+#define DDI_BUF_TRANS_LO(port, i) _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8)
+#define DDI_BUF_TRANS_HI(port, i) _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8 + 4)
/* Sideband Interface (SBI) is programmed indirectly, via
* SBI_ADDR, which contains the register offset; and SBI_DATA,
* which contains the payload */
-#define SBI_ADDR 0xC6000
-#define SBI_DATA 0xC6004
-#define SBI_CTL_STAT 0xC6008
+#define SBI_ADDR _MMIO(0xC6000)
+#define SBI_DATA _MMIO(0xC6004)
+#define SBI_CTL_STAT _MMIO(0xC6008)
#define SBI_CTL_DEST_ICLK (0x0<<16)
#define SBI_CTL_DEST_MPHY (0x1<<16)
#define SBI_CTL_OP_IORD (0x2<<8)
@@ -7275,6 +7327,7 @@ enum skl_disp_power_wells {
#define SBI_READY (0x0<<0)
/* SBI offsets */
+#define SBI_SSCDIVINTPHASE 0x0200
#define SBI_SSCDIVINTPHASE6 0x0600
#define SBI_SSCDIVINTPHASE_DIVSEL_MASK ((0x7f)<<1)
#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1)
@@ -7282,6 +7335,7 @@ enum skl_disp_power_wells {
#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8)
#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15)
#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0)
+#define SBI_SSCDITHPHASE 0x0204
#define SBI_SSCCTL 0x020c
#define SBI_SSCCTL6 0x060C
#define SBI_SSCCTL_PATHALT (1<<3)
@@ -7293,12 +7347,12 @@ enum skl_disp_power_wells {
#define SBI_GEN0_CFG_BUFFENABLE_DISABLE (1<<0)
/* LPT PIXCLK_GATE */
-#define PIXCLK_GATE 0xC6020
+#define PIXCLK_GATE _MMIO(0xC6020)
#define PIXCLK_GATE_UNGATE (1<<0)
#define PIXCLK_GATE_GATE (0<<0)
/* SPLL */
-#define SPLL_CTL 0x46020
+#define SPLL_CTL _MMIO(0x46020)
#define SPLL_PLL_ENABLE (1<<31)
#define SPLL_PLL_SSC (1<<28)
#define SPLL_PLL_NON_SSC (2<<28)
@@ -7310,9 +7364,9 @@ enum skl_disp_power_wells {
#define SPLL_PLL_FREQ_MASK (3<<26)
/* WRPLL */
-#define WRPLL_CTL1 0x46040
-#define WRPLL_CTL2 0x46060
-#define WRPLL_CTL(pll) (pll == 0 ? WRPLL_CTL1 : WRPLL_CTL2)
+#define _WRPLL_CTL1 0x46040
+#define _WRPLL_CTL2 0x46060
+#define WRPLL_CTL(pll) _MMIO_PIPE(pll, _WRPLL_CTL1, _WRPLL_CTL2)
#define WRPLL_PLL_ENABLE (1<<31)
#define WRPLL_PLL_SSC (1<<28)
#define WRPLL_PLL_NON_SSC (2<<28)
@@ -7329,9 +7383,9 @@ enum skl_disp_power_wells {
#define WRPLL_DIVIDER_FB_MASK (0xff<<16)
/* Port clock selection */
-#define PORT_CLK_SEL_A 0x46100
-#define PORT_CLK_SEL_B 0x46104
-#define PORT_CLK_SEL(port) _PORT(port, PORT_CLK_SEL_A, PORT_CLK_SEL_B)
+#define _PORT_CLK_SEL_A 0x46100
+#define _PORT_CLK_SEL_B 0x46104
+#define PORT_CLK_SEL(port) _MMIO_PORT(port, _PORT_CLK_SEL_A, _PORT_CLK_SEL_B)
#define PORT_CLK_SEL_LCPLL_2700 (0<<29)
#define PORT_CLK_SEL_LCPLL_1350 (1<<29)
#define PORT_CLK_SEL_LCPLL_810 (2<<29)
@@ -7343,18 +7397,18 @@ enum skl_disp_power_wells {
#define PORT_CLK_SEL_MASK (7<<29)
/* Transcoder clock selection */
-#define TRANS_CLK_SEL_A 0x46140
-#define TRANS_CLK_SEL_B 0x46144
-#define TRANS_CLK_SEL(tran) _TRANSCODER(tran, TRANS_CLK_SEL_A, TRANS_CLK_SEL_B)
+#define _TRANS_CLK_SEL_A 0x46140
+#define _TRANS_CLK_SEL_B 0x46144
+#define TRANS_CLK_SEL(tran) _MMIO_TRANS(tran, _TRANS_CLK_SEL_A, _TRANS_CLK_SEL_B)
/* For each transcoder, we need to select the corresponding port clock */
#define TRANS_CLK_SEL_DISABLED (0x0<<29)
#define TRANS_CLK_SEL_PORT(x) (((x)+1)<<29)
-#define TRANSA_MSA_MISC 0x60410
-#define TRANSB_MSA_MISC 0x61410
-#define TRANSC_MSA_MISC 0x62410
-#define TRANS_EDP_MSA_MISC 0x6f410
-#define TRANS_MSA_MISC(tran) _TRANSCODER2(tran, TRANSA_MSA_MISC)
+#define _TRANSA_MSA_MISC 0x60410
+#define _TRANSB_MSA_MISC 0x61410
+#define _TRANSC_MSA_MISC 0x62410
+#define _TRANS_EDP_MSA_MISC 0x6f410
+#define TRANS_MSA_MISC(tran) _MMIO_TRANS2(tran, _TRANSA_MSA_MISC)
#define TRANS_MSA_SYNC_CLK (1<<0)
#define TRANS_MSA_6_BPC (0<<5)
@@ -7364,7 +7418,7 @@ enum skl_disp_power_wells {
#define TRANS_MSA_16_BPC (4<<5)
/* LCPLL Control */
-#define LCPLL_CTL 0x130040
+#define LCPLL_CTL _MMIO(0x130040)
#define LCPLL_PLL_DISABLE (1<<31)
#define LCPLL_PLL_LOCK (1<<30)
#define LCPLL_CLK_FREQ_MASK (3<<26)
@@ -7384,7 +7438,7 @@ enum skl_disp_power_wells {
*/
/* CDCLK_CTL */
-#define CDCLK_CTL 0x46000
+#define CDCLK_CTL _MMIO(0x46000)
#define CDCLK_FREQ_SEL_MASK (3<<26)
#define CDCLK_FREQ_450_432 (0<<26)
#define CDCLK_FREQ_540 (1<<26)
@@ -7400,12 +7454,12 @@ enum skl_disp_power_wells {
#define BXT_CDCLK_SSA_PRECHARGE_ENABLE (1<<16)
/* LCPLL_CTL */
-#define LCPLL1_CTL 0x46010
-#define LCPLL2_CTL 0x46014
+#define LCPLL1_CTL _MMIO(0x46010)
+#define LCPLL2_CTL _MMIO(0x46014)
#define LCPLL_PLL_ENABLE (1<<31)
/* DPLL control1 */
-#define DPLL_CTRL1 0x6C058
+#define DPLL_CTRL1 _MMIO(0x6C058)
#define DPLL_CTRL1_HDMI_MODE(id) (1<<((id)*6+5))
#define DPLL_CTRL1_SSC(id) (1<<((id)*6+4))
#define DPLL_CTRL1_LINK_RATE_MASK(id) (7<<((id)*6+1))
@@ -7420,7 +7474,7 @@ enum skl_disp_power_wells {
#define DPLL_CTRL1_LINK_RATE_2160 5
/* DPLL control2 */
-#define DPLL_CTRL2 0x6C05C
+#define DPLL_CTRL2 _MMIO(0x6C05C)
#define DPLL_CTRL2_DDI_CLK_OFF(port) (1<<((port)+15))
#define DPLL_CTRL2_DDI_CLK_SEL_MASK(port) (3<<((port)*3+1))
#define DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port) ((port)*3+1)
@@ -7428,21 +7482,21 @@ enum skl_disp_power_wells {
#define DPLL_CTRL2_DDI_SEL_OVERRIDE(port) (1<<((port)*3))
/* DPLL Status */
-#define DPLL_STATUS 0x6C060
+#define DPLL_STATUS _MMIO(0x6C060)
#define DPLL_LOCK(id) (1<<((id)*8))
/* DPLL cfg */
-#define DPLL1_CFGCR1 0x6C040
-#define DPLL2_CFGCR1 0x6C048
-#define DPLL3_CFGCR1 0x6C050
+#define _DPLL1_CFGCR1 0x6C040
+#define _DPLL2_CFGCR1 0x6C048
+#define _DPLL3_CFGCR1 0x6C050
#define DPLL_CFGCR1_FREQ_ENABLE (1<<31)
#define DPLL_CFGCR1_DCO_FRACTION_MASK (0x7fff<<9)
#define DPLL_CFGCR1_DCO_FRACTION(x) ((x)<<9)
#define DPLL_CFGCR1_DCO_INTEGER_MASK (0x1ff)
-#define DPLL1_CFGCR2 0x6C044
-#define DPLL2_CFGCR2 0x6C04C
-#define DPLL3_CFGCR2 0x6C054
+#define _DPLL1_CFGCR2 0x6C044
+#define _DPLL2_CFGCR2 0x6C04C
+#define _DPLL3_CFGCR2 0x6C054
#define DPLL_CFGCR2_QDIV_RATIO_MASK (0xff<<8)
#define DPLL_CFGCR2_QDIV_RATIO(x) ((x)<<8)
#define DPLL_CFGCR2_QDIV_MODE(x) ((x)<<7)
@@ -7460,58 +7514,59 @@ enum skl_disp_power_wells {
#define DPLL_CFGCR2_PDIV_7 (4<<2)
#define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3)
-#define DPLL_CFGCR1(id) (DPLL1_CFGCR1 + ((id) - SKL_DPLL1) * 8)
-#define DPLL_CFGCR2(id) (DPLL1_CFGCR2 + ((id) - SKL_DPLL1) * 8)
+#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR2)
+#define DPLL_CFGCR2(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR2, _DPLL2_CFGCR2)
/* BXT display engine PLL */
-#define BXT_DE_PLL_CTL 0x6d000
+#define BXT_DE_PLL_CTL _MMIO(0x6d000)
#define BXT_DE_PLL_RATIO(x) (x) /* {60,65,100} * 19.2MHz */
#define BXT_DE_PLL_RATIO_MASK 0xff
-#define BXT_DE_PLL_ENABLE 0x46070
+#define BXT_DE_PLL_ENABLE _MMIO(0x46070)
#define BXT_DE_PLL_PLL_ENABLE (1 << 31)
#define BXT_DE_PLL_LOCK (1 << 30)
/* GEN9 DC */
-#define DC_STATE_EN 0x45504
+#define DC_STATE_EN _MMIO(0x45504)
+#define DC_STATE_DISABLE 0
#define DC_STATE_EN_UPTO_DC5 (1<<0)
#define DC_STATE_EN_DC9 (1<<3)
#define DC_STATE_EN_UPTO_DC6 (2<<0)
#define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3
-#define DC_STATE_DEBUG 0x45520
+#define DC_STATE_DEBUG _MMIO(0x45520)
#define DC_STATE_DEBUG_MASK_MEMORY_UP (1<<1)
/* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register,
* since on HSW we can't write to it using I915_WRITE. */
-#define D_COMP_HSW (MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
-#define D_COMP_BDW 0x138144
+#define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
+#define D_COMP_BDW _MMIO(0x138144)
#define D_COMP_RCOMP_IN_PROGRESS (1<<9)
#define D_COMP_COMP_FORCE (1<<8)
#define D_COMP_COMP_DISABLE (1<<0)
/* Pipe WM_LINETIME - watermark line time */
-#define PIPE_WM_LINETIME_A 0x45270
-#define PIPE_WM_LINETIME_B 0x45274
-#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, PIPE_WM_LINETIME_A, \
- PIPE_WM_LINETIME_B)
+#define _PIPE_WM_LINETIME_A 0x45270
+#define _PIPE_WM_LINETIME_B 0x45274
+#define PIPE_WM_LINETIME(pipe) _MMIO_PIPE(pipe, _PIPE_WM_LINETIME_A, _PIPE_WM_LINETIME_B)
#define PIPE_WM_LINETIME_MASK (0x1ff)
#define PIPE_WM_LINETIME_TIME(x) ((x))
#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16)
#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16)
/* SFUSE_STRAP */
-#define SFUSE_STRAP 0xc2014
+#define SFUSE_STRAP _MMIO(0xc2014)
#define SFUSE_STRAP_FUSE_LOCK (1<<13)
#define SFUSE_STRAP_DISPLAY_DISABLED (1<<7)
+#define SFUSE_STRAP_CRT_DISABLED (1<<6)
#define SFUSE_STRAP_DDIB_DETECTED (1<<2)
#define SFUSE_STRAP_DDIC_DETECTED (1<<1)
#define SFUSE_STRAP_DDID_DETECTED (1<<0)
-#define WM_MISC 0x45260
+#define WM_MISC _MMIO(0x45260)
#define WM_MISC_DATA_PARTITION_5_6 (1 << 0)
-#define WM_DBG 0x45280
+#define WM_DBG _MMIO(0x45280)
#define WM_DBG_DISALLOW_MULTIPLE_LP (1<<0)
#define WM_DBG_DISALLOW_MAXFIFO (1<<1)
#define WM_DBG_DISALLOW_SPRITE (1<<2)
@@ -7548,28 +7603,29 @@ enum skl_disp_power_wells {
#define _PIPE_B_CSC_POSTOFF_ME 0x49144
#define _PIPE_B_CSC_POSTOFF_LO 0x49148
-#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
-#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
-#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
-#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU)
-#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV)
-#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV)
-#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE)
-#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI)
-#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME)
-#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO)
-#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI)
-#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
-#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
+#define PIPE_CSC_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
+#define PIPE_CSC_COEFF_BY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
+#define PIPE_CSC_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
+#define PIPE_CSC_COEFF_BU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU)
+#define PIPE_CSC_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV)
+#define PIPE_CSC_COEFF_BV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV)
+#define PIPE_CSC_MODE(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE)
+#define PIPE_CSC_PREOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI)
+#define PIPE_CSC_PREOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME)
+#define PIPE_CSC_PREOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO)
+#define PIPE_CSC_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI)
+#define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
+#define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
/* MIPI DSI registers */
#define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */
+#define _MMIO_MIPI(port, a, c) _MMIO(_MIPI_PORT(port, a, c))
/* BXT MIPI clock controls */
#define BXT_MAX_VAR_OUTPUT_KHZ 39500
-#define BXT_MIPI_CLOCK_CTL 0x46090
+#define BXT_MIPI_CLOCK_CTL _MMIO(0x46090)
#define BXT_MIPI1_DIV_SHIFT 26
#define BXT_MIPI2_DIV_SHIFT 10
#define BXT_MIPI_DIV_SHIFT(port) \
@@ -7631,20 +7687,20 @@ enum skl_disp_power_wells {
/* BXT MIPI mode configure */
#define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8
#define _BXT_MIPIC_TRANS_HACTIVE 0x6B8F8
-#define BXT_MIPI_TRANS_HACTIVE(tc) _MIPI_PORT(tc, \
+#define BXT_MIPI_TRANS_HACTIVE(tc) _MMIO_MIPI(tc, \
_BXT_MIPIA_TRANS_HACTIVE, _BXT_MIPIC_TRANS_HACTIVE)
#define _BXT_MIPIA_TRANS_VACTIVE 0x6B0FC
#define _BXT_MIPIC_TRANS_VACTIVE 0x6B8FC
-#define BXT_MIPI_TRANS_VACTIVE(tc) _MIPI_PORT(tc, \
+#define BXT_MIPI_TRANS_VACTIVE(tc) _MMIO_MIPI(tc, \
_BXT_MIPIA_TRANS_VACTIVE, _BXT_MIPIC_TRANS_VACTIVE)
#define _BXT_MIPIA_TRANS_VTOTAL 0x6B100
#define _BXT_MIPIC_TRANS_VTOTAL 0x6B900
-#define BXT_MIPI_TRANS_VTOTAL(tc) _MIPI_PORT(tc, \
+#define BXT_MIPI_TRANS_VTOTAL(tc) _MMIO_MIPI(tc, \
_BXT_MIPIA_TRANS_VTOTAL, _BXT_MIPIC_TRANS_VTOTAL)
-#define BXT_DSI_PLL_CTL 0x161000
+#define BXT_DSI_PLL_CTL _MMIO(0x161000)
#define BXT_DSI_PLL_PVD_RATIO_SHIFT 16
#define BXT_DSI_PLL_PVD_RATIO_MASK (3 << BXT_DSI_PLL_PVD_RATIO_SHIFT)
#define BXT_DSI_PLL_PVD_RATIO_1 (1 << BXT_DSI_PLL_PVD_RATIO_SHIFT)
@@ -7660,21 +7716,20 @@ enum skl_disp_power_wells {
#define BXT_DSI_PLL_RATIO_MAX 0x7D
#define BXT_DSI_PLL_RATIO_MIN 0x22
#define BXT_DSI_PLL_RATIO_MASK 0xFF
-#define BXT_REF_CLOCK_KHZ 19500
+#define BXT_REF_CLOCK_KHZ 19200
-#define BXT_DSI_PLL_ENABLE 0x46080
+#define BXT_DSI_PLL_ENABLE _MMIO(0x46080)
#define BXT_DSI_PLL_DO_ENABLE (1 << 31)
#define BXT_DSI_PLL_LOCKED (1 << 30)
#define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190)
#define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700)
-#define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
+#define MIPI_PORT_CTRL(port) _MMIO_MIPI(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
/* BXT port control */
#define _BXT_MIPIA_PORT_CTRL 0x6B0C0
#define _BXT_MIPIC_PORT_CTRL 0x6B8C0
-#define BXT_MIPI_PORT_CTRL(tc) _MIPI_PORT(tc, _BXT_MIPIA_PORT_CTRL, \
- _BXT_MIPIC_PORT_CTRL)
+#define BXT_MIPI_PORT_CTRL(tc) _MMIO_MIPI(tc, _BXT_MIPIA_PORT_CTRL, _BXT_MIPIC_PORT_CTRL)
#define DPI_ENABLE (1 << 31) /* A + C */
#define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27
@@ -7718,8 +7773,7 @@ enum skl_disp_power_wells {
#define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194)
#define _MIPIC_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704)
-#define MIPI_TEARING_CTRL(port) _MIPI_PORT(port, \
- _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
+#define MIPI_TEARING_CTRL(port) _MMIO_MIPI(port, _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
#define TEARING_EFFECT_DELAY_SHIFT 0
#define TEARING_EFFECT_DELAY_MASK (0xffff << 0)
@@ -7730,8 +7784,7 @@ enum skl_disp_power_wells {
#define _MIPIA_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb000)
#define _MIPIC_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800)
-#define MIPI_DEVICE_READY(port) _MIPI_PORT(port, _MIPIA_DEVICE_READY, \
- _MIPIC_DEVICE_READY)
+#define MIPI_DEVICE_READY(port) _MMIO_MIPI(port, _MIPIA_DEVICE_READY, _MIPIC_DEVICE_READY)
#define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */
#define ULPS_STATE_MASK (3 << 1)
#define ULPS_STATE_ENTER (2 << 1)
@@ -7741,12 +7794,10 @@ enum skl_disp_power_wells {
#define _MIPIA_INTR_STAT (dev_priv->mipi_mmio_base + 0xb004)
#define _MIPIC_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804)
-#define MIPI_INTR_STAT(port) _MIPI_PORT(port, _MIPIA_INTR_STAT, \
- _MIPIC_INTR_STAT)
+#define MIPI_INTR_STAT(port) _MMIO_MIPI(port, _MIPIA_INTR_STAT, _MIPIC_INTR_STAT)
#define _MIPIA_INTR_EN (dev_priv->mipi_mmio_base + 0xb008)
#define _MIPIC_INTR_EN (dev_priv->mipi_mmio_base + 0xb808)
-#define MIPI_INTR_EN(port) _MIPI_PORT(port, _MIPIA_INTR_EN, \
- _MIPIC_INTR_EN)
+#define MIPI_INTR_EN(port) _MMIO_MIPI(port, _MIPIA_INTR_EN, _MIPIC_INTR_EN)
#define TEARING_EFFECT (1 << 31)
#define SPL_PKT_SENT_INTERRUPT (1 << 30)
#define GEN_READ_DATA_AVAIL (1 << 29)
@@ -7782,8 +7833,7 @@ enum skl_disp_power_wells {
#define _MIPIA_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb00c)
#define _MIPIC_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c)
-#define MIPI_DSI_FUNC_PRG(port) _MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \
- _MIPIC_DSI_FUNC_PRG)
+#define MIPI_DSI_FUNC_PRG(port) _MMIO_MIPI(port, _MIPIA_DSI_FUNC_PRG, _MIPIC_DSI_FUNC_PRG)
#define CMD_MODE_DATA_WIDTH_MASK (7 << 13)
#define CMD_MODE_NOT_SUPPORTED (0 << 13)
#define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13)
@@ -7806,32 +7856,27 @@ enum skl_disp_power_wells {
#define _MIPIA_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb010)
#define _MIPIC_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810)
-#define MIPI_HS_TX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \
- _MIPIC_HS_TX_TIMEOUT)
+#define MIPI_HS_TX_TIMEOUT(port) _MMIO_MIPI(port, _MIPIA_HS_TX_TIMEOUT, _MIPIC_HS_TX_TIMEOUT)
#define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff
#define _MIPIA_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb014)
#define _MIPIC_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814)
-#define MIPI_LP_RX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \
- _MIPIC_LP_RX_TIMEOUT)
+#define MIPI_LP_RX_TIMEOUT(port) _MMIO_MIPI(port, _MIPIA_LP_RX_TIMEOUT, _MIPIC_LP_RX_TIMEOUT)
#define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff
#define _MIPIA_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb018)
#define _MIPIC_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818)
-#define MIPI_TURN_AROUND_TIMEOUT(port) _MIPI_PORT(port, \
- _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
+#define MIPI_TURN_AROUND_TIMEOUT(port) _MMIO_MIPI(port, _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
#define TURN_AROUND_TIMEOUT_MASK 0x3f
#define _MIPIA_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb01c)
#define _MIPIC_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c)
-#define MIPI_DEVICE_RESET_TIMER(port) _MIPI_PORT(port, \
- _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
+#define MIPI_DEVICE_RESET_TIMER(port) _MMIO_MIPI(port, _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
#define DEVICE_RESET_TIMER_MASK 0xffff
#define _MIPIA_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb020)
#define _MIPIC_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820)
-#define MIPI_DPI_RESOLUTION(port) _MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \
- _MIPIC_DPI_RESOLUTION)
+#define MIPI_DPI_RESOLUTION(port) _MMIO_MIPI(port, _MIPIA_DPI_RESOLUTION, _MIPIC_DPI_RESOLUTION)
#define VERTICAL_ADDRESS_SHIFT 16
#define VERTICAL_ADDRESS_MASK (0xffff << 16)
#define HORIZONTAL_ADDRESS_SHIFT 0
@@ -7839,8 +7884,7 @@ enum skl_disp_power_wells {
#define _MIPIA_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb024)
#define _MIPIC_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824)
-#define MIPI_DBI_FIFO_THROTTLE(port) _MIPI_PORT(port, \
- _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
+#define MIPI_DBI_FIFO_THROTTLE(port) _MMIO_MIPI(port, _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
#define DBI_FIFO_EMPTY_HALF (0 << 0)
#define DBI_FIFO_EMPTY_QUARTER (1 << 0)
#define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0)
@@ -7848,50 +7892,41 @@ enum skl_disp_power_wells {
/* regs below are bits 15:0 */
#define _MIPIA_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb028)
#define _MIPIC_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828)
-#define MIPI_HSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \
- _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
+#define MIPI_HSYNC_PADDING_COUNT(port) _MMIO_MIPI(port, _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
#define _MIPIA_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb02c)
#define _MIPIC_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c)
-#define MIPI_HBP_COUNT(port) _MIPI_PORT(port, _MIPIA_HBP_COUNT, \
- _MIPIC_HBP_COUNT)
+#define MIPI_HBP_COUNT(port) _MMIO_MIPI(port, _MIPIA_HBP_COUNT, _MIPIC_HBP_COUNT)
#define _MIPIA_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb030)
#define _MIPIC_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830)
-#define MIPI_HFP_COUNT(port) _MIPI_PORT(port, _MIPIA_HFP_COUNT, \
- _MIPIC_HFP_COUNT)
+#define MIPI_HFP_COUNT(port) _MMIO_MIPI(port, _MIPIA_HFP_COUNT, _MIPIC_HFP_COUNT)
#define _MIPIA_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb034)
#define _MIPIC_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834)
-#define MIPI_HACTIVE_AREA_COUNT(port) _MIPI_PORT(port, \
- _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
+#define MIPI_HACTIVE_AREA_COUNT(port) _MMIO_MIPI(port, _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
#define _MIPIA_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb038)
#define _MIPIC_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838)
-#define MIPI_VSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \
- _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
+#define MIPI_VSYNC_PADDING_COUNT(port) _MMIO_MIPI(port, _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
#define _MIPIA_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb03c)
#define _MIPIC_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c)
-#define MIPI_VBP_COUNT(port) _MIPI_PORT(port, _MIPIA_VBP_COUNT, \
- _MIPIC_VBP_COUNT)
+#define MIPI_VBP_COUNT(port) _MMIO_MIPI(port, _MIPIA_VBP_COUNT, _MIPIC_VBP_COUNT)
#define _MIPIA_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb040)
#define _MIPIC_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840)
-#define MIPI_VFP_COUNT(port) _MIPI_PORT(port, _MIPIA_VFP_COUNT, \
- _MIPIC_VFP_COUNT)
+#define MIPI_VFP_COUNT(port) _MMIO_MIPI(port, _MIPIA_VFP_COUNT, _MIPIC_VFP_COUNT)
#define _MIPIA_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb044)
#define _MIPIC_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844)
-#define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MIPI_PORT(port, \
- _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
+#define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MMIO_MIPI(port, _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
/* regs above are bits 15:0 */
#define _MIPIA_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb048)
#define _MIPIC_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848)
-#define MIPI_DPI_CONTROL(port) _MIPI_PORT(port, _MIPIA_DPI_CONTROL, \
- _MIPIC_DPI_CONTROL)
+#define MIPI_DPI_CONTROL(port) _MMIO_MIPI(port, _MIPIA_DPI_CONTROL, _MIPIC_DPI_CONTROL)
#define DPI_LP_MODE (1 << 6)
#define BACKLIGHT_OFF (1 << 5)
#define BACKLIGHT_ON (1 << 4)
@@ -7902,29 +7937,26 @@ enum skl_disp_power_wells {
#define _MIPIA_DPI_DATA (dev_priv->mipi_mmio_base + 0xb04c)
#define _MIPIC_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c)
-#define MIPI_DPI_DATA(port) _MIPI_PORT(port, _MIPIA_DPI_DATA, \
- _MIPIC_DPI_DATA)
+#define MIPI_DPI_DATA(port) _MMIO_MIPI(port, _MIPIA_DPI_DATA, _MIPIC_DPI_DATA)
#define COMMAND_BYTE_SHIFT 0
#define COMMAND_BYTE_MASK (0x3f << 0)
#define _MIPIA_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb050)
#define _MIPIC_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850)
-#define MIPI_INIT_COUNT(port) _MIPI_PORT(port, _MIPIA_INIT_COUNT, \
- _MIPIC_INIT_COUNT)
+#define MIPI_INIT_COUNT(port) _MMIO_MIPI(port, _MIPIA_INIT_COUNT, _MIPIC_INIT_COUNT)
#define MASTER_INIT_TIMER_SHIFT 0
#define MASTER_INIT_TIMER_MASK (0xffff << 0)
#define _MIPIA_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb054)
#define _MIPIC_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854)
-#define MIPI_MAX_RETURN_PKT_SIZE(port) _MIPI_PORT(port, \
+#define MIPI_MAX_RETURN_PKT_SIZE(port) _MMIO_MIPI(port, \
_MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE)
#define MAX_RETURN_PKT_SIZE_SHIFT 0
#define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0)
#define _MIPIA_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb058)
#define _MIPIC_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858)
-#define MIPI_VIDEO_MODE_FORMAT(port) _MIPI_PORT(port, \
- _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
+#define MIPI_VIDEO_MODE_FORMAT(port) _MMIO_MIPI(port, _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
#define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4)
#define DISABLE_VIDEO_BTA (1 << 3)
#define IP_TG_CONFIG (1 << 2)
@@ -7934,8 +7966,7 @@ enum skl_disp_power_wells {
#define _MIPIA_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb05c)
#define _MIPIC_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c)
-#define MIPI_EOT_DISABLE(port) _MIPI_PORT(port, _MIPIA_EOT_DISABLE, \
- _MIPIC_EOT_DISABLE)
+#define MIPI_EOT_DISABLE(port) _MMIO_MIPI(port, _MIPIA_EOT_DISABLE, _MIPIC_EOT_DISABLE)
#define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7)
#define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6)
#define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5)
@@ -7947,31 +7978,26 @@ enum skl_disp_power_wells {
#define _MIPIA_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb060)
#define _MIPIC_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860)
-#define MIPI_LP_BYTECLK(port) _MIPI_PORT(port, _MIPIA_LP_BYTECLK, \
- _MIPIC_LP_BYTECLK)
+#define MIPI_LP_BYTECLK(port) _MMIO_MIPI(port, _MIPIA_LP_BYTECLK, _MIPIC_LP_BYTECLK)
#define LP_BYTECLK_SHIFT 0
#define LP_BYTECLK_MASK (0xffff << 0)
/* bits 31:0 */
#define _MIPIA_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb064)
#define _MIPIC_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864)
-#define MIPI_LP_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \
- _MIPIC_LP_GEN_DATA)
+#define MIPI_LP_GEN_DATA(port) _MMIO_MIPI(port, _MIPIA_LP_GEN_DATA, _MIPIC_LP_GEN_DATA)
/* bits 31:0 */
#define _MIPIA_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb068)
#define _MIPIC_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868)
-#define MIPI_HS_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \
- _MIPIC_HS_GEN_DATA)
+#define MIPI_HS_GEN_DATA(port) _MMIO_MIPI(port, _MIPIA_HS_GEN_DATA, _MIPIC_HS_GEN_DATA)
#define _MIPIA_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb06c)
#define _MIPIC_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c)
-#define MIPI_LP_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \
- _MIPIC_LP_GEN_CTRL)
+#define MIPI_LP_GEN_CTRL(port) _MMIO_MIPI(port, _MIPIA_LP_GEN_CTRL, _MIPIC_LP_GEN_CTRL)
#define _MIPIA_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb070)
#define _MIPIC_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870)
-#define MIPI_HS_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \
- _MIPIC_HS_GEN_CTRL)
+#define MIPI_HS_GEN_CTRL(port) _MMIO_MIPI(port, _MIPIA_HS_GEN_CTRL, _MIPIC_HS_GEN_CTRL)
#define LONG_PACKET_WORD_COUNT_SHIFT 8
#define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8)
#define SHORT_PACKET_PARAM_SHIFT 8
@@ -7984,8 +8010,7 @@ enum skl_disp_power_wells {
#define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074)
#define _MIPIC_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874)
-#define MIPI_GEN_FIFO_STAT(port) _MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \
- _MIPIC_GEN_FIFO_STAT)
+#define MIPI_GEN_FIFO_STAT(port) _MMIO_MIPI(port, _MIPIA_GEN_FIFO_STAT, _MIPIC_GEN_FIFO_STAT)
#define DPI_FIFO_EMPTY (1 << 28)
#define DBI_FIFO_EMPTY (1 << 27)
#define LP_CTRL_FIFO_EMPTY (1 << 26)
@@ -8003,16 +8028,14 @@ enum skl_disp_power_wells {
#define _MIPIA_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb078)
#define _MIPIC_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878)
-#define MIPI_HS_LP_DBI_ENABLE(port) _MIPI_PORT(port, \
- _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
+#define MIPI_HS_LP_DBI_ENABLE(port) _MMIO_MIPI(port, _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
#define DBI_HS_LP_MODE_MASK (1 << 0)
#define DBI_LP_MODE (1 << 0)
#define DBI_HS_MODE (0 << 0)
#define _MIPIA_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb080)
#define _MIPIC_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880)
-#define MIPI_DPHY_PARAM(port) _MIPI_PORT(port, _MIPIA_DPHY_PARAM, \
- _MIPIC_DPHY_PARAM)
+#define MIPI_DPHY_PARAM(port) _MMIO_MIPI(port, _MIPIA_DPHY_PARAM, _MIPIC_DPHY_PARAM)
#define EXIT_ZERO_COUNT_SHIFT 24
#define EXIT_ZERO_COUNT_MASK (0x3f << 24)
#define TRAIL_COUNT_SHIFT 16
@@ -8025,15 +8048,11 @@ enum skl_disp_power_wells {
/* 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)
-#define MIPI_DBI_BW_CTRL(port) _MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \
- _MIPIC_DBI_BW_CTRL)
-
-#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
- + 0xb088)
-#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
- + 0xb888)
-#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MIPI_PORT(port, \
- _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
+#define MIPI_DBI_BW_CTRL(port) _MMIO_MIPI(port, _MIPIA_DBI_BW_CTRL, _MIPIC_DBI_BW_CTRL)
+
+#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base + 0xb088)
+#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base + 0xb888)
+#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MMIO_MIPI(port, _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
#define LP_HS_SSW_CNT_SHIFT 16
#define LP_HS_SSW_CNT_MASK (0xffff << 16)
#define HS_LP_PWR_SW_CNT_SHIFT 0
@@ -8041,19 +8060,16 @@ enum skl_disp_power_wells {
#define _MIPIA_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb08c)
#define _MIPIC_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c)
-#define MIPI_STOP_STATE_STALL(port) _MIPI_PORT(port, \
- _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
+#define MIPI_STOP_STATE_STALL(port) _MMIO_MIPI(port, _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
#define STOP_STATE_STALL_COUNTER_SHIFT 0
#define STOP_STATE_STALL_COUNTER_MASK (0xff << 0)
#define _MIPIA_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb090)
#define _MIPIC_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890)
-#define MIPI_INTR_STAT_REG_1(port) _MIPI_PORT(port, \
- _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
+#define MIPI_INTR_STAT_REG_1(port) _MMIO_MIPI(port, _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
#define _MIPIA_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb094)
#define _MIPIC_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894)
-#define MIPI_INTR_EN_REG_1(port) _MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \
- _MIPIC_INTR_EN_REG_1)
+#define MIPI_INTR_EN_REG_1(port) _MMIO_MIPI(port, _MIPIA_INTR_EN_REG_1, _MIPIC_INTR_EN_REG_1)
#define RX_CONTENTION_DETECTED (1 << 0)
/* XXX: only pipe A ?!? */
@@ -8073,8 +8089,7 @@ enum skl_disp_power_wells {
#define _MIPIA_CTRL (dev_priv->mipi_mmio_base + 0xb104)
#define _MIPIC_CTRL (dev_priv->mipi_mmio_base + 0xb904)
-#define MIPI_CTRL(port) _MIPI_PORT(port, _MIPIA_CTRL, \
- _MIPIC_CTRL)
+#define MIPI_CTRL(port) _MMIO_MIPI(port, _MIPIA_CTRL, _MIPIC_CTRL)
#define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */
#define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5)
#define ESCAPE_CLOCK_DIVIDER_1 (0 << 5)
@@ -8087,29 +8102,24 @@ enum skl_disp_power_wells {
#define RGB_FLIP_TO_BGR (1 << 2)
#define BXT_PIPE_SELECT_MASK (7 << 7)
-#define BXT_PIPE_SELECT_C (2 << 7)
-#define BXT_PIPE_SELECT_B (1 << 7)
-#define BXT_PIPE_SELECT_A (0 << 7)
+#define BXT_PIPE_SELECT(pipe) ((pipe) << 7)
#define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108)
#define _MIPIC_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908)
-#define MIPI_DATA_ADDRESS(port) _MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \
- _MIPIC_DATA_ADDRESS)
+#define MIPI_DATA_ADDRESS(port) _MMIO_MIPI(port, _MIPIA_DATA_ADDRESS, _MIPIC_DATA_ADDRESS)
#define DATA_MEM_ADDRESS_SHIFT 5
#define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5)
#define DATA_VALID (1 << 0)
#define _MIPIA_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb10c)
#define _MIPIC_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c)
-#define MIPI_DATA_LENGTH(port) _MIPI_PORT(port, _MIPIA_DATA_LENGTH, \
- _MIPIC_DATA_LENGTH)
+#define MIPI_DATA_LENGTH(port) _MMIO_MIPI(port, _MIPIA_DATA_LENGTH, _MIPIC_DATA_LENGTH)
#define DATA_LENGTH_SHIFT 0
#define DATA_LENGTH_MASK (0xfffff << 0)
#define _MIPIA_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb110)
#define _MIPIC_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910)
-#define MIPI_COMMAND_ADDRESS(port) _MIPI_PORT(port, \
- _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
+#define MIPI_COMMAND_ADDRESS(port) _MMIO_MIPI(port, _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
#define COMMAND_MEM_ADDRESS_SHIFT 5
#define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5)
#define AUTO_PWG_ENABLE (1 << 2)
@@ -8118,21 +8128,17 @@ enum skl_disp_power_wells {
#define _MIPIA_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb114)
#define _MIPIC_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914)
-#define MIPI_COMMAND_LENGTH(port) _MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \
- _MIPIC_COMMAND_LENGTH)
+#define MIPI_COMMAND_LENGTH(port) _MMIO_MIPI(port, _MIPIA_COMMAND_LENGTH, _MIPIC_COMMAND_LENGTH)
#define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */
#define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n)))
#define _MIPIA_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb118)
#define _MIPIC_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918)
-#define MIPI_READ_DATA_RETURN(port, n) \
- (_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \
- + 4 * (n)) /* n: 0...7 */
+#define MIPI_READ_DATA_RETURN(port, n) _MMIO(_MIPI(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) + 4 * (n)) /* n: 0...7 */
#define _MIPIA_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb138)
#define _MIPIC_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938)
-#define MIPI_READ_DATA_VALID(port) _MIPI_PORT(port, \
- _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
+#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): */
@@ -8140,12 +8146,12 @@ enum skl_disp_power_wells {
#define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
/* MOCS (Memory Object Control State) registers */
-#define GEN9_LNCFCMOCS0 0xb020 /* L3 Cache Control base */
+#define GEN9_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */
-#define GEN9_GFX_MOCS_0 0xc800 /* Graphics MOCS base register*/
-#define GEN9_MFX0_MOCS_0 0xc900 /* Media 0 MOCS base register*/
-#define GEN9_MFX1_MOCS_0 0xca00 /* Media 1 MOCS base register*/
-#define GEN9_VEBOX_MOCS_0 0xcb00 /* Video MOCS base register*/
-#define GEN9_BLT_MOCS_0 0xcc00 /* Blitter MOCS base register*/
+#define GEN9_GFX_MOCS(i) _MMIO(0xc800 + (i) * 4) /* Graphics MOCS registers */
+#define GEN9_MFX0_MOCS(i) _MMIO(0xc900 + (i) * 4) /* Media 0 MOCS registers */
+#define GEN9_MFX1_MOCS(i) _MMIO(0xca00 + (i) * 4) /* Media 1 MOCS registers */
+#define GEN9_VEBOX_MOCS(i) _MMIO(0xcb00 + (i) * 4) /* Video MOCS registers */
+#define GEN9_BLT_MOCS(i) _MMIO(0xcc00 + (i) * 4) /* Blitter MOCS registers */
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 2d9182189422..a2aa09ce3202 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -49,7 +49,7 @@ static void i915_save_display(struct drm_device *dev)
dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
- } else if (!IS_VALLEYVIEW(dev)) {
+ } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
@@ -84,7 +84,7 @@ static void i915_restore_display(struct drm_device *dev)
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
- } else if (!IS_VALLEYVIEW(dev)) {
+ } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 50ce9ce2b269..37e3f0ddf8e0 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -35,7 +35,8 @@
#define dev_to_drm_minor(d) dev_get_drvdata((d))
#ifdef CONFIG_PM
-static u32 calc_residency(struct drm_device *dev, const u32 reg)
+static u32 calc_residency(struct drm_device *dev,
+ i915_reg_t reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u64 raw_time; /* 32b value may overflow during fixed point math */
@@ -48,7 +49,7 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
intel_runtime_pm_get(dev_priv);
/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
units = 1;
div = dev_priv->czclk_freq;
@@ -283,7 +284,7 @@ static ssize_t gt_act_freq_mhz_show(struct device *kdev,
intel_runtime_pm_get(dev_priv);
mutex_lock(&dev_priv->rps.hw_lock);
- if (IS_VALLEYVIEW(dev_priv->dev)) {
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
u32 freq;
freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
ret = intel_gpu_freq(dev_priv, (freq >> 8) & 0xff);
@@ -597,7 +598,7 @@ void i915_setup_sysfs(struct drm_device *dev)
if (ret)
DRM_ERROR("RC6p residency sysfs setup failed\n");
}
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
ret = sysfs_merge_group(&dev->primary->kdev->kobj,
&media_rc6_attr_group);
if (ret)
@@ -618,7 +619,7 @@ void i915_setup_sysfs(struct drm_device *dev)
}
ret = 0;
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
ret = sysfs_create_files(&dev->primary->kdev->kobj, vlv_attrs);
else if (INTEL_INFO(dev)->gen >= 6)
ret = sysfs_create_files(&dev->primary->kdev->kobj, gen6_attrs);
@@ -634,7 +635,7 @@ void i915_setup_sysfs(struct drm_device *dev)
void i915_teardown_sysfs(struct drm_device *dev)
{
sysfs_remove_bin_file(&dev->primary->kdev->kobj, &error_state_attr);
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
sysfs_remove_files(&dev->primary->kdev->kobj, vlv_attrs);
else
sysfs_remove_files(&dev->primary->kdev->kobj, gen6_attrs);
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 04fe8491c8b6..52b2d409945d 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -664,7 +664,7 @@ TRACE_EVENT(i915_flip_complete,
);
TRACE_EVENT_CONDITION(i915_reg_rw,
- TP_PROTO(bool write, u32 reg, u64 val, int len, bool trace),
+ TP_PROTO(bool write, i915_reg_t reg, u64 val, int len, bool trace),
TP_ARGS(write, reg, val, len, trace),
@@ -679,7 +679,7 @@ TRACE_EVENT_CONDITION(i915_reg_rw,
TP_fast_assign(
__entry->val = (u64)val;
- __entry->reg = reg;
+ __entry->reg = i915_mmio_reg_offset(reg);
__entry->write = write;
__entry->len = len;
),
diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
index 5eee75bff170..dea7429be4d0 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.c
+++ b/drivers/gpu/drm/i915/i915_vgpu.c
@@ -69,13 +69,13 @@ void i915_check_vgpu(struct drm_device *dev)
if (!IS_HASWELL(dev))
return;
- magic = readq(dev_priv->regs + vgtif_reg(magic));
+ magic = __raw_i915_read64(dev_priv, vgtif_reg(magic));
if (magic != VGT_MAGIC)
return;
version = INTEL_VGT_IF_VERSION_ENCODE(
- readw(dev_priv->regs + vgtif_reg(version_major)),
- readw(dev_priv->regs + vgtif_reg(version_minor)));
+ __raw_i915_read16(dev_priv, vgtif_reg(version_major)),
+ __raw_i915_read16(dev_priv, vgtif_reg(version_minor)));
if (version != INTEL_VGT_IF_VERSION) {
DRM_INFO("VGT interface version mismatch!\n");
return;
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index 21c97f44d637..3c83b47b5f69 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -92,14 +92,10 @@ struct vgt_if {
uint32_t g2v_notify;
uint32_t rsv6[7];
- uint32_t pdp0_lo;
- uint32_t pdp0_hi;
- uint32_t pdp1_lo;
- uint32_t pdp1_hi;
- uint32_t pdp2_lo;
- uint32_t pdp2_hi;
- uint32_t pdp3_lo;
- uint32_t pdp3_hi;
+ struct {
+ uint32_t lo;
+ uint32_t hi;
+ } pdp[4];
uint32_t execlist_context_descriptor_lo;
uint32_t execlist_context_descriptor_hi;
@@ -108,7 +104,7 @@ struct vgt_if {
} __packed;
#define vgtif_reg(x) \
- (VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x)
+ _MMIO((VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x))
/* vGPU display status to be used by the host side */
#define VGT_DRV_DISPLAY_NOT_READY 0
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index f1975f267710..d0b1c9afa35e 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -94,6 +94,9 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base);
crtc_state->update_pipe = false;
+ crtc_state->disable_lp_wm = false;
+ crtc_state->disable_cxsr = false;
+ crtc_state->wm_changed = false;
return &crtc_state->base;
}
@@ -205,8 +208,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev,
* but since this plane is unchanged just do the
* minimum required validation.
*/
- if (plane->type == DRM_PLANE_TYPE_PRIMARY)
- intel_crtc->atomic.wait_for_flips = true;
crtc_state->base.planes_changed = true;
}
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index a11980696595..c6bb0fc1edfb 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -84,6 +84,7 @@ intel_plane_duplicate_state(struct drm_plane *plane)
state = &intel_state->base;
__drm_atomic_helper_plane_duplicate_state(plane, state);
+ intel_state->wait_req = NULL;
return state;
}
@@ -100,6 +101,7 @@ void
intel_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
+ WARN_ON(state && to_intel_plane_state(state)->wait_req);
drm_atomic_helper_plane_destroy_state(plane, state);
}
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 4dccd9b003a1..31f6d212fb1b 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -161,9 +161,9 @@ static bool audio_rate_need_prog(struct intel_crtc *crtc,
}
static bool intel_eld_uptodate(struct drm_connector *connector,
- int reg_eldv, uint32_t bits_eldv,
- int reg_elda, uint32_t bits_elda,
- int reg_edid)
+ i915_reg_t reg_eldv, uint32_t bits_eldv,
+ i915_reg_t reg_elda, uint32_t bits_elda,
+ i915_reg_t reg_edid)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
uint8_t *eld = connector->eld;
@@ -262,7 +262,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
tmp |= AUD_CONFIG_N_PROG_ENABLE;
tmp &= ~AUD_CONFIG_UPPER_N_MASK;
tmp &= ~AUD_CONFIG_LOWER_N_MASK;
- if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
+ if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT) ||
+ intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DP_MST))
tmp |= AUD_CONFIG_N_VALUE_INDEX;
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
@@ -364,8 +365,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder)
enum port port = intel_dig_port->port;
enum pipe pipe = intel_crtc->pipe;
uint32_t tmp, eldv;
- int aud_config;
- int aud_cntrl_st2;
+ i915_reg_t aud_config, aud_cntrl_st2;
DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n",
port_name(port), pipe_name(pipe));
@@ -376,7 +376,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder)
if (HAS_PCH_IBX(dev_priv->dev)) {
aud_config = IBX_AUD_CFG(pipe);
aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
- } else if (IS_VALLEYVIEW(dev_priv)) {
+ } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
aud_config = VLV_AUD_CFG(pipe);
aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
} else {
@@ -416,10 +416,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
uint32_t eldv;
uint32_t tmp;
int len, i;
- int hdmiw_hdmiedid;
- int aud_config;
- int aud_cntl_st;
- int aud_cntrl_st2;
+ i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
DRM_DEBUG_KMS("Enable audio codec on port %c, pipe %c, %u bytes ELD\n",
port_name(port), pipe_name(pipe), drm_eld_size(eld));
@@ -439,7 +436,8 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
aud_config = IBX_AUD_CFG(pipe);
aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
- } else if (IS_VALLEYVIEW(connector->dev)) {
+ } else if (IS_VALLEYVIEW(connector->dev) ||
+ IS_CHERRYVIEW(connector->dev)) {
hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
aud_config = VLV_AUD_CFG(pipe);
aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
@@ -478,7 +476,8 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
- if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
+ if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT) ||
+ intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DP_MST))
tmp |= AUD_CONFIG_N_VALUE_INDEX;
else
tmp |= audio_config_hdmi_pixel_clock(adjusted_mode);
@@ -516,7 +515,8 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
/* ELD Conn_Type */
connector->eld[5] &= ~(3 << 2);
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
+ intel_pipe_has_type(crtc, INTEL_OUTPUT_DP_MST))
connector->eld[5] |= (1 << 2);
connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
@@ -525,6 +525,10 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
dev_priv->display.audio_codec_enable(connector, intel_encoder,
adjusted_mode);
+ mutex_lock(&dev_priv->av_mutex);
+ intel_dig_port->audio_connector = connector;
+ mutex_unlock(&dev_priv->av_mutex);
+
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
}
@@ -548,6 +552,10 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
if (dev_priv->display.audio_codec_disable)
dev_priv->display.audio_codec_disable(intel_encoder);
+ mutex_lock(&dev_priv->av_mutex);
+ intel_dig_port->audio_connector = NULL;
+ mutex_unlock(&dev_priv->av_mutex);
+
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
}
@@ -563,7 +571,7 @@ void intel_init_audio(struct drm_device *dev)
if (IS_G4X(dev)) {
dev_priv->display.audio_codec_enable = g4x_audio_codec_enable;
dev_priv->display.audio_codec_disable = g4x_audio_codec_disable;
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
dev_priv->display.audio_codec_enable = ilk_audio_codec_enable;
dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
} else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) {
@@ -591,7 +599,7 @@ static void i915_audio_component_codec_wake_override(struct device *dev,
struct drm_i915_private *dev_priv = dev_to_i915(dev);
u32 tmp;
- if (!IS_SKYLAKE(dev_priv))
+ if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv))
return;
/*
@@ -632,44 +640,40 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
int port, int rate)
{
struct drm_i915_private *dev_priv = dev_to_i915(dev);
- struct drm_device *drm_dev = dev_priv->dev;
struct intel_encoder *intel_encoder;
- struct intel_digital_port *intel_dig_port;
struct intel_crtc *crtc;
struct drm_display_mode *mode;
struct i915_audio_component *acomp = dev_priv->audio_component;
- enum pipe pipe = -1;
+ enum pipe pipe = INVALID_PIPE;
u32 tmp;
int n;
+ int err = 0;
- /* HSW, BDW SKL need this fix */
+ /* HSW, BDW, SKL, KBL need this fix */
if (!IS_SKYLAKE(dev_priv) &&
- !IS_BROADWELL(dev_priv) &&
- !IS_HASWELL(dev_priv))
+ !IS_KABYLAKE(dev_priv) &&
+ !IS_BROADWELL(dev_priv) &&
+ !IS_HASWELL(dev_priv))
return 0;
mutex_lock(&dev_priv->av_mutex);
/* 1. get the pipe */
- for_each_intel_encoder(drm_dev, intel_encoder) {
- if (intel_encoder->type != INTEL_OUTPUT_HDMI)
- continue;
- intel_dig_port = enc_to_dig_port(&intel_encoder->base);
- if (port == intel_dig_port->port) {
- crtc = to_intel_crtc(intel_encoder->base.crtc);
- if (!crtc) {
- DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__);
- continue;
- }
- pipe = crtc->pipe;
- break;
- }
+ intel_encoder = dev_priv->dig_port_map[port];
+ /* intel_encoder might be NULL for DP MST */
+ if (!intel_encoder || !intel_encoder->base.crtc ||
+ intel_encoder->type != INTEL_OUTPUT_HDMI) {
+ DRM_DEBUG_KMS("no valid port %c\n", port_name(port));
+ err = -ENODEV;
+ goto unlock;
}
-
+ crtc = to_intel_crtc(intel_encoder->base.crtc);
+ pipe = crtc->pipe;
if (pipe == INVALID_PIPE) {
DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port));
- mutex_unlock(&dev_priv->av_mutex);
- return -ENODEV;
+ err = -ENODEV;
+ goto unlock;
}
+
DRM_DEBUG_KMS("pipe %c connects port %c\n",
pipe_name(pipe), port_name(port));
mode = &crtc->config->base.adjusted_mode;
@@ -682,8 +686,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
- mutex_unlock(&dev_priv->av_mutex);
- return 0;
+ goto unlock;
}
n = audio_config_get_n(mode, rate);
@@ -693,8 +696,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
- mutex_unlock(&dev_priv->av_mutex);
- return 0;
+ goto unlock;
}
/* 3. set the N/CTS/M */
@@ -702,8 +704,37 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
tmp = audio_config_setup_n_reg(n, tmp);
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+ unlock:
mutex_unlock(&dev_priv->av_mutex);
- return 0;
+ return err;
+}
+
+static int i915_audio_component_get_eld(struct device *dev, int port,
+ bool *enabled,
+ unsigned char *buf, int max_bytes)
+{
+ struct drm_i915_private *dev_priv = dev_to_i915(dev);
+ struct intel_encoder *intel_encoder;
+ struct intel_digital_port *intel_dig_port;
+ const u8 *eld;
+ int ret = -EINVAL;
+
+ mutex_lock(&dev_priv->av_mutex);
+ intel_encoder = dev_priv->dig_port_map[port];
+ /* intel_encoder might be NULL for DP MST */
+ if (intel_encoder) {
+ ret = 0;
+ intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+ *enabled = intel_dig_port->audio_connector != NULL;
+ if (*enabled) {
+ eld = intel_dig_port->audio_connector->eld;
+ ret = drm_eld_size(eld);
+ memcpy(buf, eld, min(max_bytes, ret));
+ }
+ }
+
+ mutex_unlock(&dev_priv->av_mutex);
+ return ret;
}
static const struct i915_audio_component_ops i915_audio_component_ops = {
@@ -713,6 +744,7 @@ static const struct i915_audio_component_ops i915_audio_component_ops = {
.codec_wake_override = i915_audio_component_codec_wake_override,
.get_cdclk_freq = i915_audio_component_get_cdclk_freq,
.sync_audio_rate = i915_audio_component_sync_audio_rate,
+ .get_eld = i915_audio_component_get_eld,
};
static int i915_audio_component_bind(struct device *i915_dev,
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index ce82f9c7df24..eba3e0f87181 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -24,7 +24,7 @@
* Eric Anholt <eric@anholt.net>
*
*/
-#include <linux/dmi.h>
+
#include <drm/drm_dp_helper.h>
#include <drm/drmP.h>
#include <drm/i915_drm.h>
@@ -332,10 +332,10 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
drm_mode_debug_printmodeline(panel_fixed_mode);
}
-static int intel_bios_ssc_frequency(struct drm_device *dev,
+static int intel_bios_ssc_frequency(struct drm_i915_private *dev_priv,
bool alternate)
{
- switch (INTEL_INFO(dev)->gen) {
+ switch (INTEL_INFO(dev_priv)->gen) {
case 2:
return alternate ? 66667 : 48000;
case 3:
@@ -350,26 +350,29 @@ static void
parse_general_features(struct drm_i915_private *dev_priv,
const struct bdb_header *bdb)
{
- struct drm_device *dev = dev_priv->dev;
const struct bdb_general_features *general;
general = find_section(bdb, BDB_GENERAL_FEATURES);
- if (general) {
- dev_priv->vbt.int_tv_support = general->int_tv_support;
+ if (!general)
+ return;
+
+ dev_priv->vbt.int_tv_support = general->int_tv_support;
+ /* int_crt_support can't be trusted on earlier platforms */
+ if (bdb->version >= 155 &&
+ (HAS_DDI(dev_priv) || IS_VALLEYVIEW(dev_priv)))
dev_priv->vbt.int_crt_support = general->int_crt_support;
- dev_priv->vbt.lvds_use_ssc = general->enable_ssc;
- dev_priv->vbt.lvds_ssc_freq =
- intel_bios_ssc_frequency(dev, 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;
- 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,
- dev_priv->vbt.lvds_use_ssc,
- dev_priv->vbt.lvds_ssc_freq,
- dev_priv->vbt.display_clock_mode,
- dev_priv->vbt.fdi_rx_polarity_inverted);
- }
+ dev_priv->vbt.lvds_use_ssc = general->enable_ssc;
+ dev_priv->vbt.lvds_ssc_freq =
+ 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;
+ 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,
+ dev_priv->vbt.lvds_use_ssc,
+ dev_priv->vbt.lvds_ssc_freq,
+ dev_priv->vbt.display_clock_mode,
+ dev_priv->vbt.fdi_rx_polarity_inverted);
}
static void
@@ -1054,10 +1057,9 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
static void parse_ddi_ports(struct drm_i915_private *dev_priv,
const struct bdb_header *bdb)
{
- struct drm_device *dev = dev_priv->dev;
enum port port;
- if (!HAS_DDI(dev))
+ if (!HAS_DDI(dev_priv))
return;
if (!dev_priv->vbt.child_dev_num)
@@ -1170,7 +1172,6 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
static void
init_vbt_defaults(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = dev_priv->dev;
enum port port;
dev_priv->vbt.crt_ddc_pin = GMBUS_PIN_VGADDC;
@@ -1195,8 +1196,8 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
* Core/SandyBridge/IvyBridge use alternative (120MHz) reference
* clock for LVDS.
*/
- dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev,
- !HAS_PCH_SPLIT(dev));
+ dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev_priv,
+ !HAS_PCH_SPLIT(dev_priv));
DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq);
for (port = PORT_A; port < I915_MAX_PORTS; port++) {
@@ -1211,88 +1212,79 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
}
}
-static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
+static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt)
{
- DRM_DEBUG_KMS("Falling back to manually reading VBT from "
- "VBIOS ROM for %s\n",
- id->ident);
- return 1;
+ const void *_vbt = vbt;
+
+ return _vbt + vbt->bdb_offset;
}
-static const struct dmi_system_id intel_no_opregion_vbt[] = {
- {
- .callback = intel_no_opregion_vbt_callback,
- .ident = "ThinkCentre A57",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"),
- },
- },
- { }
-};
-
-static const struct bdb_header *validate_vbt(const void *base,
- size_t size,
- const void *_vbt,
- const char *source)
+/**
+ * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT
+ * @buf: pointer to a buffer to validate
+ * @size: size of the buffer
+ *
+ * Returns true on valid VBT.
+ */
+bool intel_bios_is_valid_vbt(const void *buf, size_t size)
{
- size_t offset = _vbt - base;
- const struct vbt_header *vbt = _vbt;
+ const struct vbt_header *vbt = buf;
const struct bdb_header *bdb;
- if (offset + sizeof(struct vbt_header) > size) {
+ if (!vbt)
+ return false;
+
+ if (sizeof(struct vbt_header) > size) {
DRM_DEBUG_DRIVER("VBT header incomplete\n");
- return NULL;
+ return false;
}
if (memcmp(vbt->signature, "$VBT", 4)) {
DRM_DEBUG_DRIVER("VBT invalid signature\n");
- return NULL;
+ return false;
}
- offset += vbt->bdb_offset;
- if (offset + sizeof(struct bdb_header) > size) {
+ if (vbt->bdb_offset + sizeof(struct bdb_header) > size) {
DRM_DEBUG_DRIVER("BDB header incomplete\n");
- return NULL;
+ return false;
}
- bdb = base + offset;
- if (offset + bdb->bdb_size > size) {
+ bdb = get_bdb_header(vbt);
+ if (vbt->bdb_offset + bdb->bdb_size > size) {
DRM_DEBUG_DRIVER("BDB incomplete\n");
- return NULL;
+ return false;
}
- DRM_DEBUG_KMS("Using VBT from %s: %20s\n",
- source, vbt->signature);
- return bdb;
+ return vbt;
}
-static const struct bdb_header *find_vbt(void __iomem *bios, size_t size)
+static const struct vbt_header *find_vbt(void __iomem *bios, size_t size)
{
- const struct bdb_header *bdb = NULL;
size_t i;
/* Scour memory looking for the VBT signature. */
for (i = 0; i + 4 < size; i++) {
- if (ioread32(bios + i) == *((const u32 *) "$VBT")) {
- /*
- * This is the one place where we explicitly discard the
- * address space (__iomem) of the BIOS/VBT. From now on
- * everything is based on 'base', and treated as regular
- * memory.
- */
- void *_bios = (void __force *) bios;
+ void *vbt;
- bdb = validate_vbt(_bios, size, _bios + i, "PCI ROM");
- break;
- }
+ if (ioread32(bios + i) != *((const u32 *) "$VBT"))
+ continue;
+
+ /*
+ * This is the one place where we explicitly discard the address
+ * space (__iomem) of the BIOS/VBT.
+ */
+ vbt = (void __force *) bios + i;
+ if (intel_bios_is_valid_vbt(vbt, size - i))
+ return vbt;
+
+ break;
}
- return bdb;
+ return NULL;
}
/**
- * intel_parse_bios - find VBT and initialize settings from the BIOS
+ * intel_bios_init - find VBT and initialize settings from the BIOS
* @dev: DRM device
*
* Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
@@ -1301,37 +1293,39 @@ static const struct bdb_header *find_vbt(void __iomem *bios, size_t size)
* Returns 0 on success, nonzero on failure.
*/
int
-intel_parse_bios(struct drm_device *dev)
+intel_bios_init(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct pci_dev *pdev = dev->pdev;
- const struct bdb_header *bdb = NULL;
+ struct pci_dev *pdev = dev_priv->dev->pdev;
+ const struct vbt_header *vbt = dev_priv->opregion.vbt;
+ const struct bdb_header *bdb;
u8 __iomem *bios = NULL;
- if (HAS_PCH_NOP(dev))
+ if (HAS_PCH_NOP(dev_priv))
return -ENODEV;
init_vbt_defaults(dev_priv);
- /* XXX Should this validation be moved to intel_opregion.c? */
- if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt)
- bdb = validate_vbt(dev_priv->opregion.header, OPREGION_SIZE,
- dev_priv->opregion.vbt, "OpRegion");
-
- if (bdb == NULL) {
+ if (!vbt) {
size_t size;
bios = pci_map_rom(pdev, &size);
if (!bios)
return -1;
- bdb = find_vbt(bios, size);
- if (!bdb) {
+ vbt = find_vbt(bios, size);
+ if (!vbt) {
pci_unmap_rom(pdev, bios);
return -1;
}
+
+ DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n");
}
+ bdb = get_bdb_header(vbt);
+
+ DRM_DEBUG_KMS("VBT signature \"%.*s\", BDB version %d\n",
+ (int)sizeof(vbt->signature), vbt->signature, bdb->version);
+
/* Grab useful general definitions */
parse_general_features(dev_priv, bdb);
parse_general_definitions(dev_priv, bdb);
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 7ec8c9aefb84..54eac1003a1e 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -28,8 +28,6 @@
#ifndef _I830_BIOS_H_
#define _I830_BIOS_H_
-#include <drm/drmP.h>
-
struct vbt_header {
u8 signature[20]; /**< Always starts with 'VBT$' */
u16 version; /**< decimal */
@@ -588,8 +586,6 @@ struct bdb_psr {
struct psr_table psr_table[16];
} __packed;
-int intel_parse_bios(struct drm_device *dev);
-
/*
* Driver<->VBIOS interaction occurs through scratch bits in
* GR18 & SWF*.
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 6a2c76e367a5..9c89df1af036 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -50,7 +50,7 @@ struct intel_crt {
* encoder's enable/disable callbacks */
struct intel_connector *connector;
bool force_hotplug_required;
- u32 adpa_reg;
+ i915_reg_t adpa_reg;
};
static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
@@ -480,12 +480,8 @@ intel_crt_load_detect(struct intel_crt *crt)
uint32_t vsample;
uint32_t vblank, vblank_start, vblank_end;
uint32_t dsl;
- uint32_t bclrpat_reg;
- uint32_t vtotal_reg;
- uint32_t vblank_reg;
- uint32_t vsync_reg;
- uint32_t pipeconf_reg;
- uint32_t pipe_dsl_reg;
+ i915_reg_t bclrpat_reg, vtotal_reg,
+ vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg;
uint8_t st00;
enum drm_connector_status status;
@@ -518,7 +514,7 @@ intel_crt_load_detect(struct intel_crt *crt)
/* Wait for next Vblank to substitue
* border color for Color info */
intel_wait_for_vblank(dev, pipe);
- st00 = I915_READ8(VGA_MSR_WRITE);
+ st00 = I915_READ8(_VGA_MSR_WRITE);
status = ((st00 & (1 << 4)) != 0) ?
connector_status_connected :
connector_status_disconnected;
@@ -563,7 +559,7 @@ intel_crt_load_detect(struct intel_crt *crt)
do {
count++;
/* Read the ST00 VGA status register */
- st00 = I915_READ8(VGA_MSR_WRITE);
+ st00 = I915_READ8(_VGA_MSR_WRITE);
if (st00 & (1 << 4))
detect++;
} while ((I915_READ(pipe_dsl_reg) == dsl));
@@ -781,11 +777,37 @@ void intel_crt_init(struct drm_device *dev)
struct intel_crt *crt;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
+ i915_reg_t adpa_reg;
+ u32 adpa;
/* Skip machines without VGA that falsely report hotplug events */
if (dmi_check_system(intel_no_crt))
return;
+ if (HAS_PCH_SPLIT(dev))
+ adpa_reg = PCH_ADPA;
+ else if (IS_VALLEYVIEW(dev))
+ adpa_reg = VLV_ADPA;
+ else
+ adpa_reg = ADPA;
+
+ adpa = I915_READ(adpa_reg);
+ if ((adpa & ADPA_DAC_ENABLE) == 0) {
+ /*
+ * On some machines (some IVB at least) CRT can be
+ * fused off, but there's no known fuse bit to
+ * indicate that. On these machine the ADPA register
+ * works normally, except the DAC enable bit won't
+ * take. So the only way to tell is attempt to enable
+ * it and see what happens.
+ */
+ I915_WRITE(adpa_reg, adpa | ADPA_DAC_ENABLE |
+ ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
+ if ((I915_READ(adpa_reg) & ADPA_DAC_ENABLE) == 0)
+ return;
+ I915_WRITE(adpa_reg, adpa);
+ }
+
crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
if (!crt)
return;
@@ -802,7 +824,7 @@ void intel_crt_init(struct drm_device *dev)
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
intel_connector_attach_encoder(intel_connector, &crt->base);
@@ -819,15 +841,10 @@ void intel_crt_init(struct drm_device *dev)
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
- if (HAS_PCH_SPLIT(dev))
- crt->adpa_reg = PCH_ADPA;
- else if (IS_VALLEYVIEW(dev))
- crt->adpa_reg = VLV_ADPA;
- else
- crt->adpa_reg = ADPA;
+ crt->adpa_reg = adpa_reg;
crt->base.compute_config = intel_crt_compute_config;
- if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
crt->base.disable = pch_disable_crt;
crt->base.post_disable = pch_post_disable_crt;
} else {
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index 9e530a739354..9bb63a85997a 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -47,21 +47,10 @@
MODULE_FIRMWARE(I915_CSR_SKL);
MODULE_FIRMWARE(I915_CSR_BXT);
-/*
-* SKL CSR registers for DC5 and DC6
-*/
-#define CSR_PROGRAM(i) (0x80000 + (i) * 4)
-#define CSR_SSP_BASE_ADDR_GEN9 0x00002FC0
-#define CSR_HTP_ADDR_SKL 0x00500034
-#define CSR_SSP_BASE 0x8F074
-#define CSR_HTP_SKL 0x8F004
-#define CSR_LAST_WRITE 0x8F034
-#define CSR_LAST_WRITE_VALUE 0xc003b400
-/* MMIO address range for CSR program (0x80000 - 0x82FFF) */
+#define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 23)
+
#define CSR_MAX_FW_SIZE 0x2FFF
#define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF
-#define CSR_MMIO_START_RANGE 0x80000
-#define CSR_MMIO_END_RANGE 0x8FFFF
struct intel_css_header {
/* 0x09 for DMC */
@@ -177,167 +166,146 @@ struct stepping_info {
char substepping;
};
+/*
+ * Kabylake derivated from Skylake H0, so SKL H0
+ * is the right firmware for KBL A0 (revid 0).
+ */
+static const struct stepping_info kbl_stepping_info[] = {
+ {'H', '0'}, {'I', '0'}
+};
+
static const struct stepping_info skl_stepping_info[] = {
- {'A', '0'}, {'B', '0'}, {'C', '0'},
- {'D', '0'}, {'E', '0'}, {'F', '0'},
- {'G', '0'}, {'H', '0'}, {'I', '0'}
+ {'A', '0'}, {'B', '0'}, {'C', '0'},
+ {'D', '0'}, {'E', '0'}, {'F', '0'},
+ {'G', '0'}, {'H', '0'}, {'I', '0'}
};
-static struct stepping_info bxt_stepping_info[] = {
+static const struct stepping_info bxt_stepping_info[] = {
{'A', '0'}, {'A', '1'}, {'A', '2'},
{'B', '0'}, {'B', '1'}, {'B', '2'}
};
-static char intel_get_stepping(struct drm_device *dev)
-{
- if (IS_SKYLAKE(dev) && (dev->pdev->revision <
- ARRAY_SIZE(skl_stepping_info)))
- return skl_stepping_info[dev->pdev->revision].stepping;
- else if (IS_BROXTON(dev) && (dev->pdev->revision <
- ARRAY_SIZE(bxt_stepping_info)))
- return bxt_stepping_info[dev->pdev->revision].stepping;
- else
- return -ENODATA;
-}
-
-static char intel_get_substepping(struct drm_device *dev)
-{
- if (IS_SKYLAKE(dev) && (dev->pdev->revision <
- ARRAY_SIZE(skl_stepping_info)))
- return skl_stepping_info[dev->pdev->revision].substepping;
- else if (IS_BROXTON(dev) && (dev->pdev->revision <
- ARRAY_SIZE(bxt_stepping_info)))
- return bxt_stepping_info[dev->pdev->revision].substepping;
- else
- return -ENODATA;
-}
-
-/**
- * intel_csr_load_status_get() - to get firmware loading status.
- * @dev_priv: i915 device.
- *
- * This function helps to get the firmware loading status.
- *
- * Return: Firmware loading status.
- */
-enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv)
+static const struct stepping_info *intel_get_stepping_info(struct drm_device *dev)
{
- enum csr_state state;
-
- mutex_lock(&dev_priv->csr_lock);
- state = dev_priv->csr.state;
- mutex_unlock(&dev_priv->csr_lock);
+ const struct stepping_info *si;
+ unsigned int size;
+
+ if (IS_KABYLAKE(dev)) {
+ size = ARRAY_SIZE(kbl_stepping_info);
+ si = kbl_stepping_info;
+ } else if (IS_SKYLAKE(dev)) {
+ size = ARRAY_SIZE(skl_stepping_info);
+ si = skl_stepping_info;
+ } else if (IS_BROXTON(dev)) {
+ size = ARRAY_SIZE(bxt_stepping_info);
+ si = bxt_stepping_info;
+ } else {
+ return NULL;
+ }
- return state;
-}
+ if (INTEL_REVID(dev) < size)
+ return si + INTEL_REVID(dev);
-/**
- * intel_csr_load_status_set() - help to set firmware loading status.
- * @dev_priv: i915 device.
- * @state: enumeration of firmware loading status.
- *
- * Set the firmware loading status.
- */
-void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
- enum csr_state state)
-{
- mutex_lock(&dev_priv->csr_lock);
- dev_priv->csr.state = state;
- mutex_unlock(&dev_priv->csr_lock);
+ return NULL;
}
/**
* intel_csr_load_program() - write the firmware from memory to register.
- * @dev: drm device.
+ * @dev_priv: i915 drm device.
*
* CSR firmware is read from a .bin file and kept in internal memory one time.
* Everytime display comes back from low power state this function is called to
* copy the firmware from internal memory to registers.
*/
-void intel_csr_load_program(struct drm_device *dev)
+void intel_csr_load_program(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
u32 *payload = dev_priv->csr.dmc_payload;
uint32_t i, fw_size;
- if (!IS_GEN9(dev)) {
+ if (!IS_GEN9(dev_priv)) {
DRM_ERROR("No CSR support available for this platform\n");
return;
}
- /*
- * FIXME: Firmware gets lost on S3/S4, but not when entering system
- * standby or suspend-to-idle (which is just like forced runtime pm).
- * Unfortunately the ACPI subsystem doesn't yet give us a way to
- * differentiate this, hence figure it out with this hack.
- */
- if (I915_READ(CSR_PROGRAM(0)))
+ if (!dev_priv->csr.dmc_payload) {
+ DRM_ERROR("Tried to program CSR with empty payload\n");
return;
+ }
- mutex_lock(&dev_priv->csr_lock);
fw_size = dev_priv->csr.dmc_fw_size;
for (i = 0; i < fw_size; i++)
I915_WRITE(CSR_PROGRAM(i), payload[i]);
for (i = 0; i < dev_priv->csr.mmio_count; i++) {
I915_WRITE(dev_priv->csr.mmioaddr[i],
- dev_priv->csr.mmiodata[i]);
+ dev_priv->csr.mmiodata[i]);
}
-
- dev_priv->csr.state = FW_LOADED;
- mutex_unlock(&dev_priv->csr_lock);
}
-static void finish_csr_load(const struct firmware *fw, void *context)
+static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
+ const struct firmware *fw)
{
- struct drm_i915_private *dev_priv = context;
struct drm_device *dev = dev_priv->dev;
struct intel_css_header *css_header;
struct intel_package_header *package_header;
struct intel_dmc_header *dmc_header;
struct intel_csr *csr = &dev_priv->csr;
- char stepping = intel_get_stepping(dev);
- char substepping = intel_get_substepping(dev);
+ const struct stepping_info *stepping_info = intel_get_stepping_info(dev);
+ char stepping, substepping;
uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes;
uint32_t i;
uint32_t *dmc_payload;
- bool fw_loaded = false;
- if (!fw) {
- i915_firmware_load_error_print(csr->fw_path, 0);
- goto out;
- }
+ if (!fw)
+ return NULL;
- if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
+ if (!stepping_info) {
DRM_ERROR("Unknown stepping info, firmware loading failed\n");
- goto out;
+ return NULL;
}
+ stepping = stepping_info->stepping;
+ substepping = stepping_info->substepping;
+
/* Extract CSS Header information*/
css_header = (struct intel_css_header *)fw->data;
if (sizeof(struct intel_css_header) !=
- (css_header->header_len * 4)) {
+ (css_header->header_len * 4)) {
DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
- (css_header->header_len * 4));
- goto out;
+ (css_header->header_len * 4));
+ return NULL;
+ }
+
+ csr->version = css_header->version;
+
+ if (IS_SKYLAKE(dev) && csr->version < SKL_CSR_VERSION_REQUIRED) {
+ DRM_INFO("Refusing to load old Skylake DMC firmware v%u.%u,"
+ " please upgrade to v%u.%u or later"
+ " [https://01.org/linuxgraphics/intel-linux-graphics-firmwares].\n",
+ CSR_VERSION_MAJOR(csr->version),
+ CSR_VERSION_MINOR(csr->version),
+ CSR_VERSION_MAJOR(SKL_CSR_VERSION_REQUIRED),
+ CSR_VERSION_MINOR(SKL_CSR_VERSION_REQUIRED));
+ return NULL;
}
+
readcount += sizeof(struct intel_css_header);
/* Extract Package Header information*/
package_header = (struct intel_package_header *)
- &fw->data[readcount];
+ &fw->data[readcount];
if (sizeof(struct intel_package_header) !=
- (package_header->header_len * 4)) {
+ (package_header->header_len * 4)) {
DRM_ERROR("Firmware has wrong package header length %u bytes\n",
- (package_header->header_len * 4));
- goto out;
+ (package_header->header_len * 4));
+ return NULL;
}
readcount += sizeof(struct intel_package_header);
/* Search for dmc_offset to find firware binary. */
for (i = 0; i < package_header->num_entries; i++) {
if (package_header->fw_info[i].substepping == '*' &&
- stepping == package_header->fw_info[i].stepping) {
+ stepping == package_header->fw_info[i].stepping) {
dmc_offset = package_header->fw_info[i].offset;
break;
} else if (stepping == package_header->fw_info[i].stepping &&
@@ -345,12 +313,12 @@ static void finish_csr_load(const struct firmware *fw, void *context)
dmc_offset = package_header->fw_info[i].offset;
break;
} else if (package_header->fw_info[i].stepping == '*' &&
- package_header->fw_info[i].substepping == '*')
+ package_header->fw_info[i].substepping == '*')
dmc_offset = package_header->fw_info[i].offset;
}
if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
- goto out;
+ return NULL;
}
readcount += dmc_offset;
@@ -358,26 +326,26 @@ static void finish_csr_load(const struct firmware *fw, void *context)
dmc_header = (struct intel_dmc_header *)&fw->data[readcount];
if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
- (dmc_header->header_len));
- goto out;
+ (dmc_header->header_len));
+ return NULL;
}
readcount += sizeof(struct intel_dmc_header);
/* Cache the dmc header info. */
if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
DRM_ERROR("Firmware has wrong mmio count %u\n",
- dmc_header->mmio_count);
- goto out;
+ dmc_header->mmio_count);
+ return NULL;
}
csr->mmio_count = dmc_header->mmio_count;
for (i = 0; i < dmc_header->mmio_count; i++) {
if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE ||
- dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
+ dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
- dmc_header->mmioaddr[i]);
- goto out;
+ dmc_header->mmioaddr[i]);
+ return NULL;
}
- csr->mmioaddr[i] = dmc_header->mmioaddr[i];
+ csr->mmioaddr[i] = _MMIO(dmc_header->mmioaddr[i]);
csr->mmiodata[i] = dmc_header->mmiodata[i];
}
@@ -385,56 +353,80 @@ static void finish_csr_load(const struct firmware *fw, void *context)
nbytes = dmc_header->fw_size * 4;
if (nbytes > CSR_MAX_FW_SIZE) {
DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
- goto out;
+ return NULL;
}
csr->dmc_fw_size = dmc_header->fw_size;
- csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
- if (!csr->dmc_payload) {
+ dmc_payload = kmalloc(nbytes, GFP_KERNEL);
+ if (!dmc_payload) {
DRM_ERROR("Memory allocation failed for dmc payload\n");
- goto out;
+ return NULL;
}
- dmc_payload = csr->dmc_payload;
memcpy(dmc_payload, &fw->data[readcount], nbytes);
+ return dmc_payload;
+}
+
+static void csr_load_work_fn(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv;
+ struct intel_csr *csr;
+ const struct firmware *fw;
+ int ret;
+
+ dev_priv = container_of(work, typeof(*dev_priv), csr.work);
+ csr = &dev_priv->csr;
+
+ ret = request_firmware(&fw, dev_priv->csr.fw_path,
+ &dev_priv->dev->pdev->dev);
+ if (!fw)
+ goto out;
+
+ dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw);
+ if (!dev_priv->csr.dmc_payload)
+ goto out;
+
/* load csr program during system boot, as needed for DC states */
- intel_csr_load_program(dev);
- fw_loaded = true;
+ intel_csr_load_program(dev_priv);
- DRM_DEBUG_KMS("Finished loading %s\n", dev_priv->csr.fw_path);
out:
- if (fw_loaded)
- intel_runtime_pm_put(dev_priv);
- else
- intel_csr_load_status_set(dev_priv, FW_FAILED);
+ if (dev_priv->csr.dmc_payload) {
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ DRM_INFO("Finished loading %s (v%u.%u)\n",
+ dev_priv->csr.fw_path,
+ CSR_VERSION_MAJOR(csr->version),
+ CSR_VERSION_MINOR(csr->version));
+ } else {
+ DRM_ERROR("Failed to load DMC firmware, disabling rpm\n");
+ }
release_firmware(fw);
}
/**
* intel_csr_ucode_init() - initialize the firmware loading.
- * @dev: drm device.
+ * @dev_priv: i915 drm device.
*
* This function is called at the time of loading the display driver to read
* firmware from a .bin file and copied into a internal memory.
*/
-void intel_csr_ucode_init(struct drm_device *dev)
+void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_csr *csr = &dev_priv->csr;
- int ret;
- if (!HAS_CSR(dev))
+ INIT_WORK(&dev_priv->csr.work, csr_load_work_fn);
+
+ if (!HAS_CSR(dev_priv))
return;
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev_priv))
csr->fw_path = I915_CSR_SKL;
else if (IS_BROXTON(dev_priv))
csr->fw_path = I915_CSR_BXT;
else {
DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
- intel_csr_load_status_set(dev_priv, FW_FAILED);
return;
}
@@ -444,43 +436,24 @@ void intel_csr_ucode_init(struct drm_device *dev)
* Obtain a runtime pm reference, until CSR is loaded,
* to avoid entering runtime-suspend.
*/
- intel_runtime_pm_get(dev_priv);
-
- /* CSR supported for platform, load firmware */
- ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path,
- &dev_priv->dev->pdev->dev,
- GFP_KERNEL, dev_priv,
- finish_csr_load);
- if (ret) {
- i915_firmware_load_error_print(csr->fw_path, ret);
- intel_csr_load_status_set(dev_priv, FW_FAILED);
- }
+ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+
+ schedule_work(&dev_priv->csr.work);
}
/**
* intel_csr_ucode_fini() - unload the CSR firmware.
- * @dev: drm device.
+ * @dev_priv: i915 drm device.
*
* Firmmware unloading includes freeing the internal momory and reset the
* firmware loading status.
*/
-void intel_csr_ucode_fini(struct drm_device *dev)
+void intel_csr_ucode_fini(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (!HAS_CSR(dev))
+ if (!HAS_CSR(dev_priv))
return;
- intel_csr_load_status_set(dev_priv, FW_FAILED);
- kfree(dev_priv->csr.dmc_payload);
-}
+ flush_work(&dev_priv->csr.work);
-void assert_csr_loaded(struct drm_i915_private *dev_priv)
-{
- WARN_ONCE(intel_csr_load_status_get(dev_priv) != FW_LOADED,
- "CSR is not loaded.\n");
- WARN_ONCE(!I915_READ(CSR_PROGRAM(0)),
- "CSR program storage start is NULL\n");
- WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
- WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
+ kfree(dev_priv->csr.dmc_payload);
}
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index a6752a61d99f..e6408e5583d7 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -133,12 +133,12 @@ static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
{ 0x00002016, 0x000000A0, 0x0 },
{ 0x00005012, 0x0000009B, 0x0 },
{ 0x00007011, 0x00000088, 0x0 },
- { 0x00009010, 0x000000C7, 0x0 },
+ { 0x80009010, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
{ 0x00002016, 0x0000009B, 0x0 },
{ 0x00005012, 0x00000088, 0x0 },
- { 0x00007011, 0x000000C7, 0x0 },
+ { 0x80007011, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
{ 0x00002016, 0x000000DF, 0x0 },
- { 0x00005012, 0x000000C7, 0x0 },
+ { 0x80005012, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
};
/* Skylake U */
@@ -146,12 +146,12 @@ static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = {
{ 0x0000201B, 0x000000A2, 0x0 },
{ 0x00005012, 0x00000088, 0x0 },
{ 0x00007011, 0x00000087, 0x0 },
- { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost level 0x1 */
+ { 0x80009010, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
{ 0x0000201B, 0x0000009D, 0x0 },
- { 0x00005012, 0x000000C7, 0x0 },
- { 0x00007011, 0x000000C7, 0x0 },
+ { 0x80005012, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
+ { 0x80007011, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
{ 0x00002016, 0x00000088, 0x0 },
- { 0x00005012, 0x000000C7, 0x0 },
+ { 0x80005012, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */
};
/* Skylake Y */
@@ -159,12 +159,12 @@ static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = {
{ 0x00000018, 0x000000A2, 0x0 },
{ 0x00005012, 0x00000088, 0x0 },
{ 0x00007011, 0x00000087, 0x0 },
- { 0x80009010, 0x000000C7, 0x3 }, /* Uses I_boost level 0x3 */
+ { 0x80009010, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */
{ 0x00000018, 0x0000009D, 0x0 },
- { 0x00005012, 0x000000C7, 0x0 },
- { 0x00007011, 0x000000C7, 0x0 },
+ { 0x80005012, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */
+ { 0x80007011, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */
{ 0x00000018, 0x00000088, 0x0 },
- { 0x00005012, 0x000000C7, 0x0 },
+ { 0x80005012, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */
};
/*
@@ -345,7 +345,7 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
static bool
intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port)
{
- return intel_dig_port->hdmi.hdmi_reg;
+ return i915_mmio_reg_valid(intel_dig_port->hdmi.hdmi_reg);
}
static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev,
@@ -353,10 +353,10 @@ static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev,
{
const struct ddi_buf_trans *ddi_translations;
- if (IS_SKL_ULX(dev)) {
+ if (IS_SKL_ULX(dev) || IS_KBL_ULX(dev)) {
ddi_translations = skl_y_ddi_translations_dp;
*n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
- } else if (IS_SKL_ULT(dev)) {
+ } else if (IS_SKL_ULT(dev) || IS_KBL_ULT(dev)) {
ddi_translations = skl_u_ddi_translations_dp;
*n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp);
} else {
@@ -373,7 +373,7 @@ static const struct ddi_buf_trans *skl_get_buf_trans_edp(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
const struct ddi_buf_trans *ddi_translations;
- if (IS_SKL_ULX(dev)) {
+ if (IS_SKL_ULX(dev) || IS_KBL_ULX(dev)) {
if (dev_priv->edp_low_vswing) {
ddi_translations = skl_y_ddi_translations_edp;
*n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp);
@@ -381,7 +381,7 @@ static const struct ddi_buf_trans *skl_get_buf_trans_edp(struct drm_device *dev,
ddi_translations = skl_y_ddi_translations_dp;
*n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
}
- } else if (IS_SKL_ULT(dev)) {
+ } else if (IS_SKL_ULT(dev) || IS_KBL_ULT(dev)) {
if (dev_priv->edp_low_vswing) {
ddi_translations = skl_u_ddi_translations_edp;
*n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp);
@@ -408,7 +408,7 @@ skl_get_buf_trans_hdmi(struct drm_device *dev,
{
const struct ddi_buf_trans *ddi_translations;
- if (IS_SKL_ULX(dev)) {
+ if (IS_SKL_ULX(dev) || IS_KBL_ULX(dev)) {
ddi_translations = skl_y_ddi_translations_hdmi;
*n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi);
} else {
@@ -448,7 +448,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
bxt_ddi_vswing_sequence(dev, hdmi_level, port,
INTEL_OUTPUT_HDMI);
return;
- } else if (IS_SKYLAKE(dev)) {
+ } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
ddi_translations_fdi = NULL;
ddi_translations_dp =
skl_get_buf_trans_dp(dev, &n_dp_entries);
@@ -576,7 +576,7 @@ void intel_prepare_ddi(struct drm_device *dev)
static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
enum port port)
{
- uint32_t reg = DDI_BUF_CTL(port);
+ i915_reg_t reg = DDI_BUF_CTL(port);
int i;
for (i = 0; i < 16; i++) {
@@ -675,15 +675,16 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
temp = I915_READ(DP_TP_STATUS(PORT_E));
if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
DRM_DEBUG_KMS("FDI link training done on step %d\n", i);
+ break;
+ }
- /* Enable normal pixel sending for FDI */
- I915_WRITE(DP_TP_CTL(PORT_E),
- DP_TP_CTL_FDI_AUTOTRAIN |
- DP_TP_CTL_LINK_TRAIN_NORMAL |
- DP_TP_CTL_ENHANCED_FRAME_ENABLE |
- DP_TP_CTL_ENABLE);
-
- return;
+ /*
+ * Leave things enabled even if we failed to train FDI.
+ * Results in less fireworks from the state checker.
+ */
+ if (i == ARRAY_SIZE(hsw_ddi_translations_fdi) * 2 - 1) {
+ DRM_ERROR("FDI link training failed!\n");
+ break;
}
temp = I915_READ(DDI_BUF_CTL(PORT_E));
@@ -712,7 +713,12 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
POSTING_READ(FDI_RX_MISC(PIPE_A));
}
- DRM_ERROR("FDI link training failed!\n");
+ /* Enable normal pixel sending for FDI */
+ I915_WRITE(DP_TP_CTL(PORT_E),
+ DP_TP_CTL_FDI_AUTOTRAIN |
+ DP_TP_CTL_LINK_TRAIN_NORMAL |
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE |
+ DP_TP_CTL_ENABLE);
}
void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
@@ -931,7 +937,8 @@ static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
/* Otherwise a < c && b >= d, do nothing */
}
-static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg)
+static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
+ i915_reg_t reg)
{
int refclk = LC_FREQ;
int n, p, r;
@@ -967,7 +974,7 @@ static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg)
static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
uint32_t dpll)
{
- uint32_t cfgcr1_reg, cfgcr2_reg;
+ i915_reg_t cfgcr1_reg, cfgcr2_reg;
uint32_t cfgcr1_val, cfgcr2_val;
uint32_t p0, p1, p2, dco_freq;
@@ -1112,10 +1119,10 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
link_clock = 270000;
break;
case PORT_CLK_SEL_WRPLL1:
- link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
+ link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(0));
break;
case PORT_CLK_SEL_WRPLL2:
- link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
+ link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(1));
break;
case PORT_CLK_SEL_SPLL:
pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
@@ -1184,7 +1191,7 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
if (INTEL_INFO(dev)->gen <= 8)
hsw_ddi_clock_get(encoder, pipe_config);
- else if (IS_SKYLAKE(dev))
+ else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
skl_ddi_clock_get(encoder, pipe_config);
else if (IS_BROXTON(dev))
bxt_ddi_clock_get(encoder, pipe_config);
@@ -1780,7 +1787,7 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_encoder *intel_encoder =
intel_ddi_get_crtc_new_encoder(crtc_state);
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
return skl_ddi_pll_select(intel_crtc, crtc_state,
intel_encoder);
else if (IS_BROXTON(dev))
@@ -1942,7 +1949,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder)
{
- uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
+ i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
uint32_t val = I915_READ(reg);
val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
@@ -2097,21 +2104,21 @@ static void skl_ddi_set_iboost(struct drm_device *dev, u32 level,
iboost = dp_iboost;
} else {
ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
- iboost = ddi_translations[port].i_boost;
+ iboost = ddi_translations[level].i_boost;
}
} else if (type == INTEL_OUTPUT_EDP) {
if (dp_iboost) {
iboost = dp_iboost;
} else {
ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
- iboost = ddi_translations[port].i_boost;
+ iboost = ddi_translations[level].i_boost;
}
} else if (type == INTEL_OUTPUT_HDMI) {
if (hdmi_iboost) {
iboost = hdmi_iboost;
} else {
ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries);
- iboost = ddi_translations[port].i_boost;
+ iboost = ddi_translations[level].i_boost;
}
} else {
return;
@@ -2263,7 +2270,7 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
level = translate_signal_level(signal_levels);
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
skl_ddi_set_iboost(dev, level, port, encoder->type);
else if (IS_BROXTON(dev))
bxt_ddi_vswing_sequence(dev, level, port, encoder->type);
@@ -2271,30 +2278,21 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
return DDI_BUF_TRANS_SELECT(level);
}
-static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
+void intel_ddi_clk_select(struct intel_encoder *encoder,
+ const struct intel_crtc_state *pipe_config)
{
- struct drm_encoder *encoder = &intel_encoder->base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
- enum port port = intel_ddi_get_encoder_port(intel_encoder);
- int type = intel_encoder->type;
- int hdmi_level;
-
- if (type == INTEL_OUTPUT_EDP) {
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- intel_edp_panel_on(intel_dp);
- }
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum port port = intel_ddi_get_encoder_port(encoder);
- if (IS_SKYLAKE(dev)) {
- uint32_t dpll = crtc->config->ddi_pll_sel;
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+ uint32_t dpll = pipe_config->ddi_pll_sel;
uint32_t val;
/*
* DPLL0 is used for eDP and is the only "private" DPLL (as
* opposed to shared) on SKL
*/
- if (type == INTEL_OUTPUT_EDP) {
+ if (encoder->type == INTEL_OUTPUT_EDP) {
WARN_ON(dpll != SKL_DPLL0);
val = I915_READ(DPLL_CTRL1);
@@ -2302,7 +2300,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
DPLL_CTRL1_SSC(dpll) |
DPLL_CTRL1_LINK_RATE_MASK(dpll));
- val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6);
+ val |= pipe_config->dpll_hw_state.ctrl1 << (dpll * 6);
I915_WRITE(DPLL_CTRL1, val);
POSTING_READ(DPLL_CTRL1);
@@ -2318,11 +2316,29 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
I915_WRITE(DPLL_CTRL2, val);
- } else if (INTEL_INFO(dev)->gen < 9) {
- WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE);
- I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel);
+ } else if (INTEL_INFO(dev_priv)->gen < 9) {
+ WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE);
+ I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel);
+ }
+}
+
+static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
+{
+ struct drm_encoder *encoder = &intel_encoder->base;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
+ enum port port = intel_ddi_get_encoder_port(intel_encoder);
+ int type = intel_encoder->type;
+ int hdmi_level;
+
+ if (type == INTEL_OUTPUT_EDP) {
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ intel_edp_panel_on(intel_dp);
}
+ intel_ddi_clk_select(intel_encoder, crtc->config);
+
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -2381,7 +2397,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
intel_edp_panel_off(intel_dp);
}
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) |
DPLL_CTRL2_DDI_CLK_OFF(port)));
else if (INTEL_INFO(dev)->gen < 9)
@@ -2553,7 +2569,7 @@ static const char * const skl_ddi_pll_names[] = {
};
struct skl_dpll_regs {
- u32 ctl, cfgcr1, cfgcr2;
+ i915_reg_t ctl, cfgcr1, cfgcr2;
};
/* this array is indexed by the *shared* pll id */
@@ -2566,13 +2582,13 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = {
},
{
/* DPLL 2 */
- .ctl = WRPLL_CTL1,
+ .ctl = WRPLL_CTL(0),
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
},
{
/* DPLL 3 */
- .ctl = WRPLL_CTL2,
+ .ctl = WRPLL_CTL(1),
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
},
@@ -2992,22 +3008,22 @@ void intel_ddi_pll_init(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t val = I915_READ(LCPLL_CTL);
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
skl_shared_dplls_init(dev_priv);
else if (IS_BROXTON(dev))
bxt_shared_dplls_init(dev_priv);
else
hsw_shared_dplls_init(dev_priv);
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
int cdclk_freq;
cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
dev_priv->skl_boot_cdclk = cdclk_freq;
+ if (skl_sanitize_cdclk(dev_priv))
+ DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
DRM_ERROR("LCPLL1 is disabled\n");
- else
- intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
} else if (IS_BROXTON(dev)) {
broxton_init_cdclk(dev);
broxton_ddi_phy_init(dev);
@@ -3026,11 +3042,11 @@ void intel_ddi_pll_init(struct drm_device *dev)
}
}
-void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder)
+void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
{
- struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
- struct intel_dp *intel_dp = &intel_dig_port->dp;
- struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_i915_private *dev_priv =
+ to_i915(intel_dig_port->base.base.dev);
enum port port = intel_dig_port->port;
uint32_t val;
bool wait = false;
@@ -3098,6 +3114,19 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc)
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
}
+bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
+ struct intel_crtc *intel_crtc)
+{
+ u32 temp;
+
+ if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
+ temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
+ if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe))
+ return true;
+ }
+ return false;
+}
+
void intel_ddi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
@@ -3141,7 +3170,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
pipe_config->has_hdmi_sink = true;
intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- if (intel_hdmi->infoframe_enabled(&encoder->base))
+ if (intel_hdmi->infoframe_enabled(&encoder->base, pipe_config))
pipe_config->has_infoframe = true;
break;
case TRANS_DDI_MODE_SELECT_DVI:
@@ -3158,11 +3187,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
break;
}
- if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
- temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
- if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe))
- pipe_config->has_audio = true;
- }
+ pipe_config->has_audio =
+ intel_ddi_is_audio_enabled(dev_priv, intel_crtc);
if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp_bpp &&
pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) {
@@ -3274,7 +3300,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
encoder = &intel_encoder->base;
drm_encoder_init(dev, encoder, &intel_ddi_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
intel_encoder->compute_config = intel_ddi_compute_config;
intel_encoder->enable = intel_enable_ddi;
@@ -3285,10 +3311,25 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_encoder->get_config = intel_ddi_get_config;
intel_dig_port->port = port;
+ dev_priv->dig_port_map[port] = intel_encoder;
intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
(DDI_BUF_PORT_REVERSAL |
DDI_A_4_LANES);
+ /*
+ * Bspec says that DDI_A_4_LANES is the only supported configuration
+ * for Broxton. Yet some BIOS fail to set this bit on port A if eDP
+ * wasn't lit up at boot. Force this bit on in our internal
+ * configuration so that we use the proper lane count for our
+ * calculations.
+ */
+ if (IS_BROXTON(dev) && port == PORT_A) {
+ if (!(intel_dig_port->saved_port_bits & DDI_A_4_LANES)) {
+ DRM_DEBUG_KMS("BXT BIOS forgot to set DDI_A_4_LANES for port A; fixing\n");
+ intel_dig_port->saved_port_bits |= DDI_A_4_LANES;
+ }
+ }
+
intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
intel_encoder->cloneable = 0;
@@ -3302,8 +3343,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
* On BXT A0/A1, sw needs to activate DDIA HPD logic and
* interrupts to check the external panel connection.
*/
- if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)
- && port == PORT_B)
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1) && port == PORT_B)
dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port;
else
dev_priv->hotplug.irq_port[port] = intel_dig_port;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 32cf97346978..2f00828ccc6e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -44,6 +44,8 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h>
#include <linux/dma_remapping.h>
+#include <linux/reservation.h>
+#include <linux/dma-buf.h>
/* Primary plane formats for gen <= 3 */
static const uint32_t i8xx_primary_formats[] = {
@@ -186,7 +188,7 @@ int intel_hrawclk(struct drm_device *dev)
uint32_t clkcfg;
/* There is no CLKCFG reg in Valleyview. VLV hrawclk is 200 MHz */
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
return 200;
clkcfg = I915_READ(CLKCFG);
@@ -214,7 +216,7 @@ int intel_hrawclk(struct drm_device *dev)
static void intel_update_czclk(struct drm_i915_private *dev_priv)
{
- if (!IS_VALLEYVIEW(dev_priv))
+ if (!(IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)))
return;
dev_priv->czclk_freq = vlv_get_cck_clock_hpll(dev_priv, "czclk",
@@ -715,11 +717,12 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
INTELPllInvalid("m1 out of range\n");
- if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev) && !IS_BROXTON(dev))
+ if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev) &&
+ !IS_CHERRYVIEW(dev) && !IS_BROXTON(dev))
if (clock->m1 <= clock->m2)
INTELPllInvalid("m1 <= m2\n");
- if (!IS_VALLEYVIEW(dev) && !IS_BROXTON(dev)) {
+ if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && !IS_BROXTON(dev)) {
if (clock->p < limit->p.min || limit->p.max < clock->p)
INTELPllInvalid("p out of range\n");
if (clock->m < limit->m.min || limit->m.max < clock->m)
@@ -1096,7 +1099,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg = PIPEDSL(pipe);
+ i915_reg_t reg = PIPEDSL(pipe);
u32 line1, line2;
u32 line_mask;
@@ -1136,7 +1139,7 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
enum pipe pipe = crtc->pipe;
if (INTEL_INFO(dev)->gen >= 4) {
- int reg = PIPECONF(cpu_transcoder);
+ i915_reg_t reg = PIPECONF(cpu_transcoder);
/* Wait for the Pipe State to go off */
if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
@@ -1286,7 +1289,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
struct drm_device *dev = dev_priv->dev;
- int pp_reg;
+ i915_reg_t pp_reg;
u32 val;
enum pipe panel_pipe = PIPE_A;
bool locked = true;
@@ -1304,7 +1307,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv,
I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT)
panel_pipe = PIPE_B;
/* XXX: else fix for eDP */
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
/* presumably write lock depends on pipe, not port select */
pp_reg = VLV_PIPE_PP_CONTROL(pipe);
panel_pipe = pipe;
@@ -1422,7 +1425,7 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
"plane %d assertion failure, should be off on pipe %c but is still active\n",
sprite, pipe_name(pipe));
}
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
for_each_sprite(dev_priv, pipe, sprite) {
u32 val = I915_READ(SPCNTR(pipe, sprite));
I915_STATE_WARN(val & SP_ENABLE,
@@ -1481,8 +1484,7 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
return false;
if (HAS_PCH_CPT(dev_priv->dev)) {
- u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe);
- u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg);
+ u32 trans_dp_ctl = I915_READ(TRANS_DP_CTL(pipe));
if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel)
return false;
} else if (IS_CHERRYVIEW(dev_priv->dev)) {
@@ -1546,12 +1548,13 @@ static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
}
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
- enum pipe pipe, int reg, u32 port_sel)
+ enum pipe pipe, i915_reg_t reg,
+ u32 port_sel)
{
u32 val = I915_READ(reg);
I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
- reg, pipe_name(pipe));
+ i915_mmio_reg_offset(reg), pipe_name(pipe));
I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
&& (val & DP_PIPEB_SELECT),
@@ -1559,12 +1562,12 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
}
static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
- enum pipe pipe, int reg)
+ enum pipe pipe, i915_reg_t reg)
{
u32 val = I915_READ(reg);
I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
"PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
- reg, pipe_name(pipe));
+ i915_mmio_reg_offset(reg), pipe_name(pipe));
I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
&& (val & SDVO_PIPE_B_SELECT),
@@ -1600,14 +1603,11 @@ static void vlv_enable_pll(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int reg = DPLL(crtc->pipe);
+ i915_reg_t reg = DPLL(crtc->pipe);
u32 dpll = pipe_config->dpll_hw_state.dpll;
assert_pipe_disabled(dev_priv, crtc->pipe);
- /* No really, not for ILK+ */
- BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
-
/* PLL is protected by panel, make sure we can write it */
if (IS_MOBILE(dev_priv->dev))
assert_panel_unlocked(dev_priv, crtc->pipe);
@@ -1645,8 +1645,6 @@ static void chv_enable_pll(struct intel_crtc *crtc,
assert_pipe_disabled(dev_priv, crtc->pipe);
- BUG_ON(!IS_CHERRYVIEW(dev_priv->dev));
-
mutex_lock(&dev_priv->sb_lock);
/* Enable back the 10bit clock to display controller */
@@ -1689,7 +1687,7 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int reg = DPLL(crtc->pipe);
+ i915_reg_t reg = DPLL(crtc->pipe);
u32 dpll = crtc->config->dpll_hw_state.dpll;
assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -1838,7 +1836,7 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
unsigned int expected_mask)
{
u32 port_mask;
- int dpll_reg;
+ i915_reg_t dpll_reg;
switch (dport->port) {
case PORT_B:
@@ -1963,7 +1961,8 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
struct drm_device *dev = dev_priv->dev;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- uint32_t reg, val, pipeconf_val;
+ i915_reg_t reg;
+ uint32_t val, pipeconf_val;
/* PCH only available on ILK+ */
BUG_ON(!HAS_PCH_SPLIT(dev));
@@ -2052,7 +2051,8 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
struct drm_device *dev = dev_priv->dev;
- uint32_t reg, val;
+ i915_reg_t reg;
+ uint32_t val;
/* FDI relies on the transcoder */
assert_fdi_tx_disabled(dev_priv, pipe);
@@ -2069,7 +2069,7 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe));
- if (!HAS_PCH_IBX(dev)) {
+ if (HAS_PCH_CPT(dev)) {
/* Workaround: Clear the timing override chicken bit again. */
reg = TRANS_CHICKEN2(pipe);
val = I915_READ(reg);
@@ -2107,10 +2107,9 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = crtc->pipe;
- enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
- pipe);
+ enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
enum pipe pch_transcoder;
- int reg;
+ i915_reg_t reg;
u32 val;
DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe));
@@ -2130,7 +2129,7 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
* need the check.
*/
if (HAS_GMCH_DISPLAY(dev_priv->dev))
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI))
+ if (crtc->config->has_dsi_encoder)
assert_dsi_pll_enabled(dev_priv);
else
assert_pll_enabled(dev_priv, pipe);
@@ -2171,7 +2170,7 @@ static void intel_disable_pipe(struct intel_crtc *crtc)
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
enum pipe pipe = crtc->pipe;
- int reg;
+ i915_reg_t reg;
u32 val;
DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe));
@@ -2270,20 +2269,20 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height,
fb_format_modifier, 0));
}
-static int
+static void
intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
const struct drm_plane_state *plane_state)
{
- struct intel_rotation_info *info = &view->rotation_info;
+ struct intel_rotation_info *info = &view->params.rotation_info;
unsigned int tile_height, tile_pitch;
*view = i915_ggtt_view_normal;
if (!plane_state)
- return 0;
+ return;
if (!intel_rotation_90_or_270(plane_state->rotation))
- return 0;
+ return;
*view = i915_ggtt_view_rotated;
@@ -2310,8 +2309,6 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
info->size_uv = info->width_pages_uv * info->height_pages_uv *
PAGE_SIZE;
}
-
- return 0;
}
static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
@@ -2319,7 +2316,7 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
if (INTEL_INFO(dev_priv)->gen >= 9)
return 256 * 1024;
else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv) ||
- IS_VALLEYVIEW(dev_priv))
+ IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
return 128 * 1024;
else if (INTEL_INFO(dev_priv)->gen >= 4)
return 4 * 1024;
@@ -2330,9 +2327,7 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
int
intel_pin_and_fence_fb_obj(struct drm_plane *plane,
struct drm_framebuffer *fb,
- const struct drm_plane_state *plane_state,
- struct intel_engine_cs *pipelined,
- struct drm_i915_gem_request **pipelined_request)
+ const struct drm_plane_state *plane_state)
{
struct drm_device *dev = fb->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2367,9 +2362,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
return -EINVAL;
}
- ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
- if (ret)
- return ret;
+ intel_fill_fb_ggtt_view(&view, fb, plane_state);
/* Note that the w/a also requires 64 PTE of padding following the
* bo. We currently fill all unused PTE with the shadow page and so
@@ -2388,11 +2381,10 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
*/
intel_runtime_pm_get(dev_priv);
- dev_priv->mm.interruptible = false;
- ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined,
- pipelined_request, &view);
+ ret = i915_gem_object_pin_to_display_plane(obj, alignment,
+ &view);
if (ret)
- goto err_interruptible;
+ goto err_pm;
/* Install a fence for tiled scan-out. Pre-i965 always needs a
* fence, whereas 965+ only requires a fence if using
@@ -2418,14 +2410,12 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
i915_gem_object_pin_fence(obj);
}
- dev_priv->mm.interruptible = true;
intel_runtime_pm_put(dev_priv);
return 0;
err_unpin:
i915_gem_object_unpin_from_display_plane(obj, &view);
-err_interruptible:
- dev_priv->mm.interruptible = true;
+err_pm:
intel_runtime_pm_put(dev_priv);
return ret;
}
@@ -2435,12 +2425,10 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
{
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct i915_ggtt_view view;
- int ret;
WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
- ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
- WARN_ONCE(ret, "Couldn't get view from plane state!");
+ intel_fill_fb_ggtt_view(&view, fb, plane_state);
if (view.type == I915_GGTT_VIEW_NORMAL)
i915_gem_object_unpin_fence(obj);
@@ -2695,7 +2683,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
int plane = intel_crtc->plane;
unsigned long linear_offset;
u32 dspcntr;
- u32 reg = DSPCNTR(plane);
+ i915_reg_t reg = DSPCNTR(plane);
int pixel_size;
if (!visible || !fb) {
@@ -2825,7 +2813,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
int plane = intel_crtc->plane;
unsigned long linear_offset;
u32 dspcntr;
- u32 reg = DSPCNTR(plane);
+ i915_reg_t reg = DSPCNTR(plane);
int pixel_size;
if (!visible || !fb) {
@@ -2950,30 +2938,32 @@ u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
}
}
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
- struct drm_i915_gem_object *obj,
- unsigned int plane)
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+ struct drm_i915_gem_object *obj,
+ unsigned int plane)
{
- const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
+ struct i915_ggtt_view view;
struct i915_vma *vma;
- unsigned char *offset;
+ u64 offset;
- if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
- view = &i915_ggtt_view_rotated;
+ intel_fill_fb_ggtt_view(&view, intel_plane->base.fb,
+ intel_plane->base.state);
- vma = i915_gem_obj_to_ggtt_view(obj, view);
+ vma = i915_gem_obj_to_ggtt_view(obj, &view);
if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
- view->type))
+ view.type))
return -1;
- offset = (unsigned char *)vma->node.start;
+ offset = vma->node.start;
if (plane == 1) {
- offset += vma->ggtt_view.rotation_info.uv_start_page *
+ offset += vma->ggtt_view.params.rotation_info.uv_start_page *
PAGE_SIZE;
}
- return (unsigned long)offset;
+ WARN_ON(upper_32_bits(offset));
+
+ return lower_32_bits(offset);
}
static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -3099,7 +3089,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
u32 tile_height, plane_offset, plane_size;
unsigned int rotation;
int x_offset, y_offset;
- unsigned long surf_addr;
+ u32 surf_addr;
struct intel_crtc_state *crtc_state = intel_crtc->config;
struct intel_plane_state *plane_state;
int src_x = 0, src_y = 0, src_w = 0, src_h = 0;
@@ -3197,8 +3187,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (dev_priv->fbc.disable_fbc)
- dev_priv->fbc.disable_fbc(dev_priv);
+ if (dev_priv->fbc.deactivate)
+ dev_priv->fbc.deactivate(dev_priv);
dev_priv->display.update_primary_plane(crtc, fb, x, y);
@@ -3227,10 +3217,9 @@ static void intel_update_primary_planes(struct drm_device *dev)
struct intel_plane_state *plane_state;
drm_modeset_lock_crtc(crtc, &plane->base);
-
plane_state = to_intel_plane_state(plane->base.state);
- if (plane_state->base.fb)
+ if (crtc->state->active && plane_state->base.fb)
plane->commit_plane(&plane->base, plane_state);
drm_modeset_unlock_crtc(crtc);
@@ -3306,32 +3295,6 @@ void intel_finish_reset(struct drm_device *dev)
drm_modeset_unlock_all(dev);
}
-static void
-intel_finish_fb(struct drm_framebuffer *old_fb)
-{
- struct drm_i915_gem_object *obj = intel_fb_obj(old_fb);
- struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
- bool was_interruptible = dev_priv->mm.interruptible;
- int ret;
-
- /* Big Hammer, we also need to ensure that any pending
- * MI_WAIT_FOR_EVENT inside a user batch buffer on the
- * current scanout is retired before unpinning the old
- * framebuffer. Note that we rely on userspace rendering
- * into the buffer attached to the pipe they are waiting
- * on. If not, userspace generates a GPU hang with IPEHR
- * point to the MI_WAIT_FOR_EVENT.
- *
- * This should only fail upon a hung GPU, in which case we
- * can safely continue.
- */
- dev_priv->mm.interruptible = false;
- ret = i915_gem_object_wait_rendering(obj, true);
- dev_priv->mm.interruptible = was_interruptible;
-
- WARN_ON(ret);
-}
-
static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -3401,7 +3364,8 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp;
+ i915_reg_t reg;
+ u32 temp;
/* enable normal train */
reg = FDI_TX_CTL(pipe);
@@ -3443,7 +3407,8 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp, tries;
+ i915_reg_t reg;
+ u32 temp, tries;
/* FDI needs bits from pipe first */
assert_pipe_enabled(dev_priv, pipe);
@@ -3543,7 +3508,8 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp, i, retry;
+ i915_reg_t reg;
+ u32 temp, i, retry;
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
for train result */
@@ -3675,7 +3641,8 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp, i, j;
+ i915_reg_t reg;
+ u32 temp, i, j;
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
for train result */
@@ -3792,8 +3759,8 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = intel_crtc->pipe;
- u32 reg, temp;
-
+ i915_reg_t reg;
+ u32 temp;
/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
reg = FDI_RX_CTL(pipe);
@@ -3829,7 +3796,8 @@ static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc)
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = intel_crtc->pipe;
- u32 reg, temp;
+ i915_reg_t reg;
+ u32 temp;
/* Switch from PCDclk to Rawclk */
reg = FDI_RX_CTL(pipe);
@@ -3859,7 +3827,8 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp;
+ i915_reg_t reg;
+ u32 temp;
/* disable CPU FDI tx and PCH FDI rx */
reg = FDI_TX_CTL(pipe);
@@ -3952,15 +3921,23 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
work->pending_flip_obj);
}
-void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ long ret;
WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
- if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
- !intel_crtc_has_pending_flip(crtc),
- 60*HZ) == 0)) {
+
+ ret = wait_event_interruptible_timeout(
+ dev_priv->pending_flip_queue,
+ !intel_crtc_has_pending_flip(crtc),
+ 60*HZ);
+
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
spin_lock_irq(&dev->event_lock);
@@ -3971,11 +3948,22 @@ void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
spin_unlock_irq(&dev->event_lock);
}
- if (crtc->primary->fb) {
- mutex_lock(&dev->struct_mutex);
- intel_finish_fb(crtc->primary->fb);
- mutex_unlock(&dev->struct_mutex);
- }
+ return 0;
+}
+
+static void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
+{
+ u32 temp;
+
+ I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE);
+
+ mutex_lock(&dev_priv->sb_lock);
+
+ temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
+ temp |= SBI_SSCCTL_DISABLE;
+ intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
+
+ mutex_unlock(&dev_priv->sb_lock);
}
/* Program iCLKIP clock to the desired frequency */
@@ -3987,18 +3975,7 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
u32 divsel, phaseinc, auxdiv, phasedir = 0;
u32 temp;
- mutex_lock(&dev_priv->sb_lock);
-
- /* It is necessary to ungate the pixclk gate prior to programming
- * the divisors, and gate it back when it is done.
- */
- I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE);
-
- /* Disable SSCCTL */
- intel_sbi_write(dev_priv, SBI_SSCCTL6,
- intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK) |
- SBI_SSCCTL_DISABLE,
- SBI_ICLK);
+ lpt_disable_iclkip(dev_priv);
/* 20MHz is a corner case which is out of range for the 7-bit divisor */
if (clock == 20000) {
@@ -4016,7 +3993,7 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
u32 iclk_pi_range = 64;
u32 desired_divisor, msb_divisor_value, pi_value;
- desired_divisor = (iclk_virtual_root_freq / clock);
+ desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq, clock);
msb_divisor_value = desired_divisor / iclk_pi_range;
pi_value = desired_divisor % iclk_pi_range;
@@ -4038,6 +4015,8 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
phasedir,
phaseinc);
+ mutex_lock(&dev_priv->sb_lock);
+
/* Program SSCDIVINTPHASE6 */
temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
@@ -4059,12 +4038,12 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
temp &= ~SBI_SSCCTL_DISABLE;
intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
+ mutex_unlock(&dev_priv->sb_lock);
+
/* Wait for initialization time */
udelay(24);
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
-
- mutex_unlock(&dev_priv->sb_lock);
}
static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
@@ -4135,6 +4114,22 @@ static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc)
}
}
+/* Return which DP Port should be selected for Transcoder DP control */
+static enum port
+intel_trans_dp_port_sel(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct intel_encoder *encoder;
+
+ for_each_encoder_on_crtc(dev, crtc, encoder) {
+ if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+ encoder->type == INTEL_OUTPUT_EDP)
+ return enc_to_dig_port(&encoder->base)->port;
+ }
+
+ return -1;
+}
+
/*
* Enable PCH resources required for PCH ports:
* - PCH PLLs
@@ -4149,7 +4144,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp;
+ u32 temp;
assert_pch_transcoder_disabled(dev_priv, pipe);
@@ -4161,6 +4156,12 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
I915_WRITE(FDI_RX_TUSIZE1(pipe),
I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
+ /*
+ * Sometimes spurious CPU pipe underruns happen during FDI
+ * training, at least with VGA+HDMI cloning. Suppress them.
+ */
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
/* For PCH output, training FDI link */
dev_priv->display.fdi_link_train(crtc);
@@ -4194,10 +4195,14 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
intel_fdi_normal_train(crtc);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+
/* For PCH DP, enable TRANS_DP_CTL */
if (HAS_PCH_CPT(dev) && intel_crtc->config->has_dp_encoder) {
+ const struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config->base.adjusted_mode;
u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5;
- reg = TRANS_DP_CTL(pipe);
+ i915_reg_t reg = TRANS_DP_CTL(pipe);
temp = I915_READ(reg);
temp &= ~(TRANS_DP_PORT_SEL_MASK |
TRANS_DP_SYNC_MASK |
@@ -4205,19 +4210,19 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
temp |= TRANS_DP_OUTPUT_ENABLE;
temp |= bpc << 9; /* same format but at 11:9 */
- if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+ if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
- if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+ if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
switch (intel_trans_dp_port_sel(crtc)) {
- case PCH_DP_B:
+ case PORT_B:
temp |= TRANS_DP_PORT_SEL_B;
break;
- case PCH_DP_C:
+ case PORT_C:
temp |= TRANS_DP_PORT_SEL_C;
break;
- case PCH_DP_D:
+ case PORT_D:
temp |= TRANS_DP_PORT_SEL_D;
break;
default:
@@ -4357,7 +4362,7 @@ static void intel_shared_dpll_commit(struct drm_atomic_state *state)
static void cpt_verify_modeset(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int dslreg = PIPEDSL(pipe);
+ i915_reg_t dslreg = PIPEDSL(pipe);
u32 temp;
temp = I915_READ(dslreg);
@@ -4650,7 +4655,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
return;
if (HAS_GMCH_DISPLAY(dev_priv->dev)) {
- if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI))
+ if (intel_crtc->config->has_dsi_encoder)
assert_dsi_pll_enabled(dev_priv);
else
assert_pll_enabled(dev_priv, pipe);
@@ -4667,7 +4672,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
}
for (i = 0; i < 256; i++) {
- u32 palreg;
+ i915_reg_t palreg;
if (HAS_GMCH_DISPLAY(dev))
palreg = PALETTE(pipe, i);
@@ -4721,14 +4726,6 @@ intel_post_enable_primary(struct drm_crtc *crtc)
int pipe = intel_crtc->pipe;
/*
- * BDW signals flip done immediately if the plane
- * is disabled, even if the plane enable is already
- * armed to occur at the next vblank :(
- */
- if (IS_BROADWELL(dev))
- intel_wait_for_vblank(dev, pipe);
-
- /*
* FIXME IPS should be fine as long as one plane is
* enabled, but in practice it seems to have problems
* when going from primary only to sprite only and vice
@@ -4746,9 +4743,9 @@ intel_post_enable_primary(struct drm_crtc *crtc)
if (IS_GEN2(dev))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
- /* Underruns don't raise interrupts, so check manually. */
- if (HAS_GMCH_DISPLAY(dev))
- i9xx_check_fifo_underruns(dev_priv);
+ /* Underruns don't always raise interrupts, so check manually. */
+ intel_check_cpu_fifo_underruns(dev_priv);
+ intel_check_pch_fifo_underruns(dev_priv);
}
/**
@@ -4805,31 +4802,26 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
static void intel_post_plane_update(struct intel_crtc *crtc)
{
struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
+ struct intel_crtc_state *pipe_config =
+ to_intel_crtc_state(crtc->base.state);
struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_plane *plane;
if (atomic->wait_vblank)
intel_wait_for_vblank(dev, crtc->pipe);
intel_frontbuffer_flip(dev, atomic->fb_bits);
- if (atomic->disable_cxsr)
- crtc->wm.cxsr_allowed = true;
+ crtc->wm.cxsr_allowed = true;
- if (crtc->atomic.update_wm_post)
+ if (pipe_config->wm_changed && pipe_config->base.active)
intel_update_watermarks(&crtc->base);
if (atomic->update_fbc)
- intel_fbc_update(dev_priv);
+ intel_fbc_update(crtc);
if (atomic->post_enable_primary)
intel_post_enable_primary(&crtc->base);
- drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks)
- intel_update_sprite_watermarks(plane, &crtc->base,
- 0, 0, 0, false, false);
-
memset(atomic, 0, sizeof(*atomic));
}
@@ -4838,23 +4830,11 @@ static void intel_pre_plane_update(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
- struct drm_plane *p;
-
- /* Track fb's for any planes being disabled */
- drm_for_each_plane_mask(p, dev, atomic->disabled_planes) {
- struct intel_plane *plane = to_intel_plane(p);
-
- mutex_lock(&dev->struct_mutex);
- i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL,
- plane->frontbuffer_bit);
- mutex_unlock(&dev->struct_mutex);
- }
-
- if (atomic->wait_for_flips)
- intel_crtc_wait_for_pending_flips(&crtc->base);
+ struct intel_crtc_state *pipe_config =
+ to_intel_crtc_state(crtc->base.state);
if (atomic->disable_fbc)
- intel_fbc_disable_crtc(crtc);
+ intel_fbc_deactivate(crtc);
if (crtc->atomic.disable_ips)
hsw_disable_ips(crtc);
@@ -4862,10 +4842,13 @@ static void intel_pre_plane_update(struct intel_crtc *crtc)
if (atomic->pre_disable_primary)
intel_pre_disable_primary(&crtc->base);
- if (atomic->disable_cxsr) {
+ if (pipe_config->disable_cxsr) {
crtc->wm.cxsr_allowed = false;
intel_set_memory_cxsr(dev_priv, false);
}
+
+ if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed)
+ intel_update_watermarks(&crtc->base);
}
static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
@@ -4900,6 +4883,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
return;
if (intel_crtc->config->has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
+
+ if (intel_crtc->config->has_pch_encoder)
intel_prepare_shared_dpll(intel_crtc);
if (intel_crtc->config->has_dp_encoder)
@@ -4917,7 +4903,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
- intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_enable)
@@ -4955,6 +4940,13 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
if (HAS_PCH_CPT(dev))
cpt_verify_modeset(dev, intel_crtc->pipe);
+
+ /* Must wait for vblank to avoid spurious PCH FIFO underruns */
+ if (intel_crtc->config->has_pch_encoder)
+ intel_wait_for_vblank(dev, pipe);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
+
+ intel_fbc_enable(intel_crtc);
}
/* IPS only exists on ULT machines and is tied to pipe A. */
@@ -4972,11 +4964,14 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
int pipe = intel_crtc->pipe, hsw_workaround_pipe;
struct intel_crtc_state *pipe_config =
to_intel_crtc_state(crtc->state);
- bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
if (WARN_ON(intel_crtc->active))
return;
+ if (intel_crtc->config->has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ false);
+
if (intel_crtc_to_shared_dpll(intel_crtc))
intel_enable_shared_dpll(intel_crtc);
@@ -5001,21 +4996,20 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
- intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+ if (intel_crtc->config->has_pch_encoder)
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+ else
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+
for_each_encoder_on_crtc(dev, crtc, encoder) {
- if (encoder->pre_pll_enable)
- encoder->pre_pll_enable(encoder);
if (encoder->pre_enable)
encoder->pre_enable(encoder);
}
- if (intel_crtc->config->has_pch_encoder) {
- intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
- true);
+ if (intel_crtc->config->has_pch_encoder)
dev_priv->display.fdi_link_train(crtc);
- }
- if (!is_dsi)
+ if (!intel_crtc->config->has_dsi_encoder)
intel_ddi_enable_pipe_clock(intel_crtc);
if (INTEL_INFO(dev)->gen >= 9)
@@ -5030,7 +5024,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc_load_lut(crtc);
intel_ddi_set_pipe_settings(crtc);
- if (!is_dsi)
+ if (!intel_crtc->config->has_dsi_encoder)
intel_ddi_enable_transcoder_func(crtc);
intel_update_watermarks(crtc);
@@ -5039,7 +5033,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
if (intel_crtc->config->has_pch_encoder)
lpt_pch_enable(crtc);
- if (intel_crtc->config->dp_encoder_is_mst && !is_dsi)
+ if (intel_crtc->config->dp_encoder_is_mst)
intel_ddi_set_vc_payload_alloc(crtc, true);
assert_vblank_disabled(crtc);
@@ -5050,6 +5044,14 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_opregion_notify_encoder(encoder, true);
}
+ if (intel_crtc->config->has_pch_encoder) {
+ intel_wait_for_vblank(dev, pipe);
+ intel_wait_for_vblank(dev, pipe);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ true);
+ }
+
/* If we change the relative order between pipe/planes enabling, we need
* to change the workaround. */
hsw_workaround_pipe = pipe_config->hsw_workaround_pipe;
@@ -5057,6 +5059,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_wait_for_vblank(dev, hsw_workaround_pipe);
intel_wait_for_vblank(dev, hsw_workaround_pipe);
}
+
+ intel_fbc_enable(intel_crtc);
}
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
@@ -5081,7 +5085,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
- u32 reg, temp;
+
+ if (intel_crtc->config->has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->disable(encoder);
@@ -5089,15 +5095,22 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
drm_crtc_vblank_off(crtc);
assert_vblank_disabled(crtc);
+ /*
+ * Sometimes spurious CPU pipe underruns happen when the
+ * pipe is already disabled, but FDI RX/TX is still enabled.
+ * Happens at least with VGA+HDMI cloning. Suppress them.
+ */
if (intel_crtc->config->has_pch_encoder)
- intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
intel_disable_pipe(intel_crtc);
ironlake_pfit_disable(intel_crtc, false);
- if (intel_crtc->config->has_pch_encoder)
+ if (intel_crtc->config->has_pch_encoder) {
ironlake_fdi_disable(crtc);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+ }
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->post_disable)
@@ -5107,6 +5120,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
ironlake_disable_pch_transcoder(dev_priv, pipe);
if (HAS_PCH_CPT(dev)) {
+ i915_reg_t reg;
+ u32 temp;
+
/* disable TRANS_DP_CTL */
reg = TRANS_DP_CTL(pipe);
temp = I915_READ(reg);
@@ -5123,6 +5139,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
ironlake_fdi_pll_disable(intel_crtc);
}
+
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
+
+ intel_fbc_disable_crtc(intel_crtc);
}
static void haswell_crtc_disable(struct drm_crtc *crtc)
@@ -5132,7 +5152,10 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
- bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
+
+ if (intel_crtc->config->has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ false);
for_each_encoder_on_crtc(dev, crtc, encoder) {
intel_opregion_notify_encoder(encoder, false);
@@ -5142,15 +5165,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
drm_crtc_vblank_off(crtc);
assert_vblank_disabled(crtc);
- if (intel_crtc->config->has_pch_encoder)
- intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
- false);
intel_disable_pipe(intel_crtc);
if (intel_crtc->config->dp_encoder_is_mst)
intel_ddi_set_vc_payload_alloc(crtc, false);
- if (!is_dsi)
+ if (!intel_crtc->config->has_dsi_encoder)
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
if (INTEL_INFO(dev)->gen >= 9)
@@ -5158,17 +5178,23 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
else
ironlake_pfit_disable(intel_crtc, false);
- if (!is_dsi)
+ if (!intel_crtc->config->has_dsi_encoder)
intel_ddi_disable_pipe_clock(intel_crtc);
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ if (encoder->post_disable)
+ encoder->post_disable(encoder);
+
if (intel_crtc->config->has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
+ lpt_disable_iclkip(dev_priv);
intel_ddi_fdi_disable(crtc);
+
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ true);
}
- for_each_encoder_on_crtc(dev, crtc, encoder)
- if (encoder->post_disable)
- encoder->post_disable(encoder);
+ intel_fbc_disable_crtc(intel_crtc);
}
static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@ -5199,15 +5225,15 @@ static enum intel_display_power_domain port_to_power_domain(enum port port)
{
switch (port) {
case PORT_A:
- return POWER_DOMAIN_PORT_DDI_A_4_LANES;
+ return POWER_DOMAIN_PORT_DDI_A_LANES;
case PORT_B:
- return POWER_DOMAIN_PORT_DDI_B_4_LANES;
+ return POWER_DOMAIN_PORT_DDI_B_LANES;
case PORT_C:
- return POWER_DOMAIN_PORT_DDI_C_4_LANES;
+ return POWER_DOMAIN_PORT_DDI_C_LANES;
case PORT_D:
- return POWER_DOMAIN_PORT_DDI_D_4_LANES;
+ return POWER_DOMAIN_PORT_DDI_D_LANES;
case PORT_E:
- return POWER_DOMAIN_PORT_DDI_E_2_LANES;
+ return POWER_DOMAIN_PORT_DDI_E_LANES;
default:
MISSING_CASE(port);
return POWER_DOMAIN_PORT_OTHER;
@@ -5234,10 +5260,6 @@ static enum intel_display_power_domain port_to_aux_power_domain(enum port port)
}
}
-#define for_each_power_domain(domain, mask) \
- for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \
- if ((1 << (domain)) & (mask))
-
enum intel_display_power_domain
intel_display_port_power_domain(struct intel_encoder *intel_encoder)
{
@@ -5302,13 +5324,11 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum pipe pipe = intel_crtc->pipe;
unsigned long mask;
- enum transcoder transcoder;
+ enum transcoder transcoder = intel_crtc->config->cpu_transcoder;
if (!crtc->state->active)
return 0;
- transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
-
mask = BIT(POWER_DOMAIN_PIPE(pipe));
mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
if (intel_crtc->config->pch_pfit.enabled ||
@@ -5395,7 +5415,7 @@ static void intel_update_max_cdclk(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
if (limit == SKL_DFSM_CDCLK_LIMIT_675)
@@ -5452,7 +5472,7 @@ static void intel_update_cdclk(struct drm_device *dev)
* BSpec erroneously claims we should aim for 4MHz, but
* in fact 1MHz is the correct frequency.
*/
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
/*
* Program the gmbus_freq based on the cdclk frequency.
* BSpec erroneously claims we should aim for 4MHz, but
@@ -5812,32 +5832,16 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE)
DRM_ERROR("DBuf power disable timeout\n");
- /*
- * DMC assumes ownership of LCPLL and will get confused if we touch it.
- */
- if (dev_priv->csr.dmc_payload) {
- /* disable DPLL0 */
- I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) &
- ~LCPLL_PLL_ENABLE);
- if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
- DRM_ERROR("Couldn't disable DPLL0\n");
- }
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+ /* disable DPLL0 */
+ I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
+ if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
+ DRM_ERROR("Couldn't disable DPLL0\n");
}
void skl_init_cdclk(struct drm_i915_private *dev_priv)
{
- u32 val;
unsigned int required_vco;
- /* enable PCH reset handshake */
- val = I915_READ(HSW_NDE_RSTWRN_OPT);
- I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
-
- /* enable PG1 and Misc I/O */
- intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
-
/* DPLL0 not enabled (happens on early BIOS versions) */
if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) {
/* enable DPLL0 */
@@ -5858,6 +5862,45 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv)
DRM_ERROR("DBuf power enable timeout\n");
}
+int skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
+{
+ uint32_t lcpll1 = I915_READ(LCPLL1_CTL);
+ uint32_t cdctl = I915_READ(CDCLK_CTL);
+ int freq = dev_priv->skl_boot_cdclk;
+
+ /*
+ * check if the pre-os intialized the display
+ * There is SWF18 scratchpad register defined which is set by the
+ * pre-os which can be used by the OS drivers to check the status
+ */
+ if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0)
+ goto sanitize;
+
+ /* Is PLL enabled and locked ? */
+ if (!((lcpll1 & LCPLL_PLL_ENABLE) && (lcpll1 & LCPLL_PLL_LOCK)))
+ goto sanitize;
+
+ /* DPLL okay; verify the cdclock
+ *
+ * Noticed in some instances that the freq selection is correct but
+ * decimal part is programmed wrong from BIOS where pre-os does not
+ * enable display. Verify the same as well.
+ */
+ if (cdctl == ((cdctl & CDCLK_FREQ_SEL_MASK) | skl_cdclk_decimal(freq)))
+ /* All well; nothing to sanitize */
+ return false;
+sanitize:
+ /*
+ * As of now initialize with max cdclk till
+ * we get dynamic cdclk support
+ * */
+ dev_priv->skl_boot_cdclk = dev_priv->max_cdclk_freq;
+ skl_init_cdclk(dev_priv);
+
+ /* we did have to sanitize */
+ return true;
+}
+
/* Adjust CDclk dividers to allow high res or save power if possible */
static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
{
@@ -6139,13 +6182,10 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
- bool is_dsi;
if (WARN_ON(intel_crtc->active))
return;
- is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
-
if (intel_crtc->config->has_dp_encoder)
intel_dp_set_m_n(intel_crtc, M1_N1);
@@ -6168,7 +6208,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
if (encoder->pre_pll_enable)
encoder->pre_pll_enable(encoder);
- if (!is_dsi) {
+ if (!intel_crtc->config->has_dsi_encoder) {
if (IS_CHERRYVIEW(dev)) {
chv_prepare_pll(intel_crtc, intel_crtc->config);
chv_enable_pll(intel_crtc, intel_crtc->config);
@@ -6247,6 +6287,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
+
+ intel_fbc_enable(intel_crtc);
}
static void i9xx_pfit_disable(struct intel_crtc *crtc)
@@ -6294,7 +6336,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
if (encoder->post_disable)
encoder->post_disable(encoder);
- if (!intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI)) {
+ if (!intel_crtc->config->has_dsi_encoder) {
if (IS_CHERRYVIEW(dev))
chv_disable_pll(dev_priv, pipe);
else if (IS_VALLEYVIEW(dev))
@@ -6309,6 +6351,8 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
if (!IS_GEN2(dev))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
+ intel_fbc_disable_crtc(intel_crtc);
}
static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
@@ -6322,7 +6366,8 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
return;
if (to_intel_plane_state(crtc->primary->state)->visible) {
- intel_crtc_wait_for_pending_flips(crtc);
+ WARN_ON(intel_crtc->unpin_work);
+
intel_pre_disable_primary(crtc);
intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
@@ -6447,13 +6492,11 @@ static void intel_connector_check_state(struct intel_connector *connector)
int intel_connector_init(struct intel_connector *connector)
{
- struct drm_connector_state *connector_state;
+ drm_atomic_helper_connector_reset(&connector->base);
- connector_state = kzalloc(sizeof *connector_state, GFP_KERNEL);
- if (!connector_state)
+ if (!connector->base.state)
return -ENOMEM;
- connector->base.state = connector_state;
return 0;
}
@@ -6642,6 +6685,15 @@ static void hsw_compute_ips_config(struct intel_crtc *crtc,
pipe_config_supports_ips(dev_priv, pipe_config);
}
+static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
+{
+ const struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+ /* GDG double wide on either pipe, otherwise pipe A only */
+ return INTEL_INFO(dev_priv)->gen < 4 &&
+ (crtc->pipe == PIPE_A || IS_I915G(dev_priv));
+}
+
static int intel_crtc_compute_config(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config)
{
@@ -6651,23 +6703,24 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
/* FIXME should check pixel clock limits on all platforms */
if (INTEL_INFO(dev)->gen < 4) {
- int clock_limit = dev_priv->max_cdclk_freq;
+ int clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
/*
- * Enable pixel doubling when the dot clock
+ * Enable double wide mode when the dot clock
* is > 90% of the (display) core speed.
- *
- * GDG double wide on either pipe,
- * otherwise pipe A only.
*/
- if ((crtc->pipe == PIPE_A || IS_I915G(dev)) &&
- adjusted_mode->crtc_clock > clock_limit * 9 / 10) {
+ if (intel_crtc_supports_double_wide(crtc) &&
+ adjusted_mode->crtc_clock > clock_limit) {
clock_limit *= 2;
pipe_config->double_wide = true;
}
- if (adjusted_mode->crtc_clock > clock_limit * 9 / 10)
+ if (adjusted_mode->crtc_clock > clock_limit) {
+ DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
+ adjusted_mode->crtc_clock, clock_limit,
+ yesno(pipe_config->double_wide));
return -EINVAL;
+ }
}
/*
@@ -7144,7 +7197,7 @@ static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
WARN_ON(!crtc_state->base.state);
- if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) {
refclk = 100000;
} else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
@@ -7432,7 +7485,7 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = crtc->pipe;
- int dpll_reg = DPLL(crtc->pipe);
+ i915_reg_t dpll_reg = DPLL(crtc->pipe);
enum dpio_channel port = vlv_pipe_to_channel(pipe);
u32 loopfilter, tribuf_calcntr;
u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
@@ -7843,7 +7896,7 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
pipeconf |= PIPECONF_DOUBLE_WIDE;
/* only g4x and later have fancy bpc/dither controls */
- if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
+ if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
/* Bspec claims that we can't use dithering for 30bpp pipes. */
if (intel_crtc->config->dither && intel_crtc->config->pipe_bpp != 30)
pipeconf |= PIPECONF_DITHER_EN |
@@ -7883,7 +7936,8 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
} else
pipeconf |= PIPECONF_PROGRESSIVE;
- if (IS_VALLEYVIEW(dev) && intel_crtc->config->limited_color_range)
+ if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
+ intel_crtc->config->limited_color_range)
pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
@@ -7898,8 +7952,6 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
int refclk, num_connectors = 0;
intel_clock_t clock;
bool ok;
- bool is_dsi = false;
- struct intel_encoder *encoder;
const intel_limit_t *limit;
struct drm_atomic_state *state = crtc_state->base.state;
struct drm_connector *connector;
@@ -7909,26 +7961,14 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
memset(&crtc_state->dpll_hw_state, 0,
sizeof(crtc_state->dpll_hw_state));
- for_each_connector_in_state(state, connector, connector_state, i) {
- if (connector_state->crtc != &crtc->base)
- continue;
-
- encoder = to_intel_encoder(connector_state->best_encoder);
-
- switch (encoder->type) {
- case INTEL_OUTPUT_DSI:
- is_dsi = true;
- break;
- default:
- break;
- }
+ if (crtc_state->has_dsi_encoder)
+ return 0;
- num_connectors++;
+ for_each_connector_in_state(state, connector, connector_state, i) {
+ if (connector_state->crtc == &crtc->base)
+ num_connectors++;
}
- if (is_dsi)
- return 0;
-
if (!crtc_state->clock_set) {
refclk = i9xx_get_refclk(crtc_state, num_connectors);
@@ -8144,7 +8184,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
if (!(tmp & PIPECONF_ENABLE))
return false;
- if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
+ if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
switch (tmp & PIPECONF_BPC_MASK) {
case PIPECONF_6BPC:
pipe_config->pipe_bpp = 18;
@@ -8160,7 +8200,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
}
}
- if (IS_VALLEYVIEW(dev) && (tmp & PIPECONF_COLOR_RANGE_SELECT))
+ if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
+ (tmp & PIPECONF_COLOR_RANGE_SELECT))
pipe_config->limited_color_range = true;
if (INTEL_INFO(dev)->gen < 4)
@@ -8188,7 +8229,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
pipe_config->pixel_multiplier = 1;
}
pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe));
- if (!IS_VALLEYVIEW(dev)) {
+ if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
/*
* DPLL_DVO_2X_MODE must be enabled for both DPLLs
* on 830. Filter it out here so that we don't
@@ -8540,6 +8581,67 @@ static void lpt_disable_clkout_dp(struct drm_device *dev)
mutex_unlock(&dev_priv->sb_lock);
}
+#define BEND_IDX(steps) ((50 + (steps)) / 5)
+
+static const uint16_t sscdivintphase[] = {
+ [BEND_IDX( 50)] = 0x3B23,
+ [BEND_IDX( 45)] = 0x3B23,
+ [BEND_IDX( 40)] = 0x3C23,
+ [BEND_IDX( 35)] = 0x3C23,
+ [BEND_IDX( 30)] = 0x3D23,
+ [BEND_IDX( 25)] = 0x3D23,
+ [BEND_IDX( 20)] = 0x3E23,
+ [BEND_IDX( 15)] = 0x3E23,
+ [BEND_IDX( 10)] = 0x3F23,
+ [BEND_IDX( 5)] = 0x3F23,
+ [BEND_IDX( 0)] = 0x0025,
+ [BEND_IDX( -5)] = 0x0025,
+ [BEND_IDX(-10)] = 0x0125,
+ [BEND_IDX(-15)] = 0x0125,
+ [BEND_IDX(-20)] = 0x0225,
+ [BEND_IDX(-25)] = 0x0225,
+ [BEND_IDX(-30)] = 0x0325,
+ [BEND_IDX(-35)] = 0x0325,
+ [BEND_IDX(-40)] = 0x0425,
+ [BEND_IDX(-45)] = 0x0425,
+ [BEND_IDX(-50)] = 0x0525,
+};
+
+/*
+ * Bend CLKOUT_DP
+ * steps -50 to 50 inclusive, in steps of 5
+ * < 0 slow down the clock, > 0 speed up the clock, 0 == no bend (135MHz)
+ * change in clock period = -(steps / 10) * 5.787 ps
+ */
+static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
+{
+ uint32_t tmp;
+ int idx = BEND_IDX(steps);
+
+ if (WARN_ON(steps % 5 != 0))
+ return;
+
+ if (WARN_ON(idx >= ARRAY_SIZE(sscdivintphase)))
+ return;
+
+ mutex_lock(&dev_priv->sb_lock);
+
+ if (steps % 10 != 0)
+ tmp = 0xAAAAAAAB;
+ else
+ tmp = 0x00000000;
+ intel_sbi_write(dev_priv, SBI_SSCDITHPHASE, tmp, SBI_ICLK);
+
+ tmp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE, SBI_ICLK);
+ tmp &= 0xffff0000;
+ tmp |= sscdivintphase[idx];
+ intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE, tmp, SBI_ICLK);
+
+ mutex_unlock(&dev_priv->sb_lock);
+}
+
+#undef BEND_IDX
+
static void lpt_init_pch_refclk(struct drm_device *dev)
{
struct intel_encoder *encoder;
@@ -8555,10 +8657,12 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
}
}
- if (has_vga)
+ if (has_vga) {
+ lpt_bend_clkout_dp(to_i915(dev), 0);
lpt_enable_clkout_dp(dev, true, true);
- else
+ } else {
lpt_disable_clkout_dp(dev);
+ }
}
/*
@@ -8921,7 +9025,7 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
memset(&crtc_state->dpll_hw_state, 0,
sizeof(crtc_state->dpll_hw_state));
- is_lvds = intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS);
+ is_lvds = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS);
WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
"Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
@@ -9350,8 +9454,8 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
- I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
- I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
+ I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
+ I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
"CPU PWM1 enabled\n");
@@ -9695,14 +9799,10 @@ static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
else
cdclk = 337500;
- /*
- * FIXME move the cdclk caclulation to
- * compute_config() so we can fail gracegully.
- */
if (cdclk > dev_priv->max_cdclk_freq) {
- DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
- cdclk, dev_priv->max_cdclk_freq);
- cdclk = dev_priv->max_cdclk_freq;
+ DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
+ cdclk, dev_priv->max_cdclk_freq);
+ return -EINVAL;
}
to_intel_atomic_state(state)->cdclk = cdclk;
@@ -9797,6 +9897,7 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
break;
case PORT_CLK_SEL_SPLL:
pipe_config->shared_dpll = DPLL_ID_SPLL;
+ break;
}
}
@@ -9813,7 +9914,7 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
skylake_get_ddi_pll(dev_priv, port, pipe_config);
else if (IS_BROXTON(dev))
bxt_get_ddi_pll(dev_priv, port, pipe_config);
@@ -10154,20 +10255,17 @@ __intel_framebuffer_create(struct drm_device *dev,
int ret;
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
- if (!intel_fb) {
- drm_gem_object_unreference(&obj->base);
+ if (!intel_fb)
return ERR_PTR(-ENOMEM);
- }
ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
if (ret)
goto err;
return &intel_fb->base;
+
err:
- drm_gem_object_unreference(&obj->base);
kfree(intel_fb);
-
return ERR_PTR(ret);
}
@@ -10207,6 +10305,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
struct drm_display_mode *mode,
int depth, int bpp)
{
+ struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
@@ -10221,7 +10320,11 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
bpp);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
- return intel_framebuffer_create(dev, &mode_cmd, obj);
+ fb = intel_framebuffer_create(dev, &mode_cmd, obj);
+ if (IS_ERR(fb))
+ drm_gem_object_unreference_unlocked(&obj->base);
+
+ return fb;
}
static struct drm_framebuffer *
@@ -11124,7 +11227,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
*/
if (ring->id == RCS) {
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(ring, DERRMR);
+ intel_ring_emit_reg(ring, DERRMR);
intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
DERRMR_PIPEB_PRI_FLIP_DONE |
DERRMR_PIPEC_PRI_FLIP_DONE));
@@ -11134,7 +11237,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
else
intel_ring_emit(ring, MI_STORE_REGISTER_MEM |
MI_SRM_LRM_GLOBAL_GTT);
- intel_ring_emit(ring, DERRMR);
+ intel_ring_emit_reg(ring, DERRMR);
intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
if (IS_GEN8(dev)) {
intel_ring_emit(ring, 0);
@@ -11174,18 +11277,23 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
return true;
else if (i915.enable_execlists)
return true;
+ else if (obj->base.dma_buf &&
+ !reservation_object_test_signaled_rcu(obj->base.dma_buf->resv,
+ false))
+ return true;
else
return ring != i915_gem_request_get_ring(obj->last_write_req);
}
static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
+ unsigned int rotation,
struct intel_unpin_work *work)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
const enum pipe pipe = intel_crtc->pipe;
- u32 ctl, stride;
+ u32 ctl, stride, tile_height;
ctl = I915_READ(PLANE_CTL(pipe, 0));
ctl &= ~PLANE_CTL_TILED_MASK;
@@ -11209,9 +11317,16 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
* The stride is either expressed as a multiple of 64 bytes chunks for
* linear buffers or in number of tiles for tiled buffers.
*/
- stride = fb->pitches[0] /
- intel_fb_stride_alignment(dev, fb->modifier[0],
- fb->pixel_format);
+ if (intel_rotation_90_or_270(rotation)) {
+ /* stride = Surface height in tiles */
+ tile_height = intel_tile_height(dev, fb->pixel_format,
+ fb->modifier[0], 0);
+ stride = DIV_ROUND_UP(fb->height, tile_height);
+ } else {
+ stride = fb->pitches[0] /
+ intel_fb_stride_alignment(dev, fb->modifier[0],
+ fb->pixel_format);
+ }
/*
* Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
@@ -11232,10 +11347,9 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
struct intel_framebuffer *intel_fb =
to_intel_framebuffer(intel_crtc->base.primary->fb);
struct drm_i915_gem_object *obj = intel_fb->obj;
+ i915_reg_t reg = DSPCNTR(intel_crtc->plane);
u32 dspcntr;
- u32 reg;
- reg = DSPCNTR(intel_crtc->plane);
dspcntr = I915_READ(reg);
if (obj->tiling_mode != I915_TILING_NONE)
@@ -11269,7 +11383,7 @@ static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
intel_pipe_update_start(crtc);
if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
- skl_do_mmio_flip(crtc, work);
+ skl_do_mmio_flip(crtc, mmio_flip->rotation, work);
else
/* use_mmio_flip() retricts MMIO flips to ilk+ */
ilk_do_mmio_flip(crtc, work);
@@ -11281,6 +11395,9 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
{
struct intel_mmio_flip *mmio_flip =
container_of(work, struct intel_mmio_flip, work);
+ struct intel_framebuffer *intel_fb =
+ to_intel_framebuffer(mmio_flip->crtc->base.primary->fb);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
if (mmio_flip->req) {
WARN_ON(__i915_wait_request(mmio_flip->req,
@@ -11290,16 +11407,19 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
i915_gem_request_unreference__unlocked(mmio_flip->req);
}
+ /* For framebuffer backed by dmabuf, wait for fence */
+ if (obj->base.dma_buf)
+ WARN_ON(reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv,
+ false, false,
+ MAX_SCHEDULE_TIMEOUT) < 0);
+
intel_do_mmio_flip(mmio_flip);
kfree(mmio_flip);
}
static int intel_queue_mmio_flip(struct drm_device *dev,
struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_i915_gem_object *obj,
- struct intel_engine_cs *ring,
- uint32_t flags)
+ struct drm_i915_gem_object *obj)
{
struct intel_mmio_flip *mmio_flip;
@@ -11310,6 +11430,7 @@ static int intel_queue_mmio_flip(struct drm_device *dev,
mmio_flip->i915 = to_i915(dev);
mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
mmio_flip->crtc = to_intel_crtc(crtc);
+ mmio_flip->rotation = crtc->primary->state->rotation;
INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
schedule_work(&mmio_flip->work);
@@ -11493,7 +11614,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(pipe)) + 1;
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
ring = &dev_priv->ring[BCS];
if (obj->tiling_mode != intel_fb_obj(work->old_fb)->tiling_mode)
/* vlv: DISPLAY_FLIP fails to change tiling */
@@ -11515,9 +11636,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
* synchronisation, so all we want here is to pin the framebuffer
* into the display plane and skip any waits.
*/
+ if (!mmio_flip) {
+ ret = i915_gem_object_sync(obj, ring, &request);
+ if (ret)
+ goto cleanup_pending;
+ }
+
ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
- crtc->primary->state,
- mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring, &request);
+ crtc->primary->state);
if (ret)
goto cleanup_pending;
@@ -11526,8 +11652,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
work->gtt_offset += intel_crtc->dspaddr_offset;
if (mmio_flip) {
- ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
- page_flip_flags);
+ ret = intel_queue_mmio_flip(dev, crtc, obj);
if (ret)
goto cleanup_unpin;
@@ -11558,7 +11683,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
to_intel_plane(primary)->frontbuffer_bit);
mutex_unlock(&dev->struct_mutex);
- intel_fbc_disable_crtc(intel_crtc);
+ intel_fbc_deactivate(intel_crtc);
intel_frontbuffer_flip_prepare(dev,
to_intel_plane(primary)->frontbuffer_bit);
@@ -11641,21 +11766,41 @@ retry:
static bool intel_wm_need_update(struct drm_plane *plane,
struct drm_plane_state *state)
{
- /* Update watermarks on tiling changes. */
- if (!plane->state->fb || !state->fb ||
- plane->state->fb->modifier[0] != state->fb->modifier[0] ||
- plane->state->rotation != state->rotation)
+ struct intel_plane_state *new = to_intel_plane_state(state);
+ struct intel_plane_state *cur = to_intel_plane_state(plane->state);
+
+ /* Update watermarks on tiling or size changes. */
+ if (new->visible != cur->visible)
return true;
- if (plane->state->crtc_w != state->crtc_w)
+ if (!cur->base.fb || !new->base.fb)
+ return false;
+
+ if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] ||
+ cur->base.rotation != new->base.rotation ||
+ drm_rect_width(&new->src) != drm_rect_width(&cur->src) ||
+ drm_rect_height(&new->src) != drm_rect_height(&cur->src) ||
+ drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) ||
+ drm_rect_height(&new->dst) != drm_rect_height(&cur->dst))
return true;
return false;
}
+static bool needs_scaling(struct intel_plane_state *state)
+{
+ int src_w = drm_rect_width(&state->src) >> 16;
+ int src_h = drm_rect_height(&state->src) >> 16;
+ int dst_w = drm_rect_width(&state->dst);
+ int dst_h = drm_rect_height(&state->dst);
+
+ return (src_w != dst_w || src_h != dst_h);
+}
+
int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
+ struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
struct drm_crtc *crtc = crtc_state->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_plane *plane = plane_state->plane;
@@ -11668,7 +11813,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
bool mode_changed = needs_modeset(crtc_state);
bool was_crtc_enabled = crtc->state->active;
bool is_crtc_enabled = crtc_state->active;
-
bool turn_off, turn_on, visible, was_visible;
struct drm_framebuffer *fb = plane_state->fb;
@@ -11681,14 +11825,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
return ret;
}
- /*
- * Disabling a plane is always okay; we just need to update
- * fb tracking in a special way since cleanup_fb() won't
- * get called by the plane helpers.
- */
- if (old_plane_state->base.fb && !fb)
- intel_crtc->atomic.disabled_planes |= 1 << i;
-
was_visible = old_plane_state->visible;
visible = to_intel_plane_state(plane_state)->visible;
@@ -11711,25 +11847,17 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
plane->base.id, was_visible, visible,
turn_off, turn_on, mode_changed);
- if (turn_on) {
- intel_crtc->atomic.update_wm_pre = true;
- /* must disable cxsr around plane enable/disable */
- if (plane->type != DRM_PLANE_TYPE_CURSOR) {
- intel_crtc->atomic.disable_cxsr = true;
- /* to potentially re-enable cxsr */
- intel_crtc->atomic.wait_vblank = true;
- intel_crtc->atomic.update_wm_post = true;
- }
- } else if (turn_off) {
- intel_crtc->atomic.update_wm_post = true;
+ if (turn_on || turn_off) {
+ pipe_config->wm_changed = true;
+
/* must disable cxsr around plane enable/disable */
if (plane->type != DRM_PLANE_TYPE_CURSOR) {
if (is_crtc_enabled)
intel_crtc->atomic.wait_vblank = true;
- intel_crtc->atomic.disable_cxsr = true;
+ pipe_config->disable_cxsr = true;
}
} else if (intel_wm_need_update(plane, plane_state)) {
- intel_crtc->atomic.update_wm_pre = true;
+ pipe_config->wm_changed = true;
}
if (visible || was_visible)
@@ -11738,7 +11866,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
- intel_crtc->atomic.wait_for_flips = true;
intel_crtc->atomic.pre_disable_primary = turn_off;
intel_crtc->atomic.post_enable_primary = turn_on;
@@ -11786,11 +11913,23 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
case DRM_PLANE_TYPE_CURSOR:
break;
case DRM_PLANE_TYPE_OVERLAY:
- if (turn_off && !mode_changed) {
+ /*
+ * WaCxSRDisabledForSpriteScaling:ivb
+ *
+ * cstate->update_wm was already set above, so this flag will
+ * take effect when we commit and program watermarks.
+ */
+ if (IS_IVYBRIDGE(dev) &&
+ needs_scaling(to_intel_plane_state(plane_state)) &&
+ !needs_scaling(old_plane_state)) {
+ to_intel_crtc_state(crtc_state)->disable_lp_wm = true;
+ } else if (turn_off && !mode_changed) {
intel_crtc->atomic.wait_vblank = true;
intel_crtc->atomic.update_sprite_watermarks |=
1 << i;
}
+
+ break;
}
return 0;
}
@@ -11863,7 +12002,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
}
if (mode_changed && !crtc_state->active)
- intel_crtc->atomic.update_wm_post = true;
+ pipe_config->wm_changed = true;
if (mode_changed && crtc_state->enable &&
dev_priv->display.crtc_compute_clock &&
@@ -11875,6 +12014,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
}
ret = 0;
+ if (dev_priv->display.compute_pipe_wm) {
+ ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
+ if (ret)
+ return ret;
+ }
+
if (INTEL_INFO(dev)->gen >= 9) {
if (mode_changed)
ret = skl_update_scaler_crtc(pipe_config);
@@ -11948,7 +12093,7 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
struct drm_connector_state *connector_state;
int bpp, i;
- if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)))
+ if ((IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)))
bpp = 10*3;
else if (INTEL_INFO(dev)->gen >= 5)
bpp = 12*3;
@@ -12064,7 +12209,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->dpll_hw_state.pll9,
pipe_config->dpll_hw_state.pll10,
pipe_config->dpll_hw_state.pcsdw12);
- } else if (IS_SKYLAKE(dev)) {
+ } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: "
"ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
pipe_config->ddi_pll_sel,
@@ -12322,6 +12467,18 @@ intel_modeset_update_crtc_state(struct drm_atomic_state *state)
crtc->hwmode = crtc->state->adjusted_mode;
else
crtc->hwmode.crtc_clock = 0;
+
+ /*
+ * Update legacy state to satisfy fbc code. This can
+ * be removed when fbc uses the atomic state.
+ */
+ if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
+ struct drm_plane_state *plane_state = crtc->primary->state;
+
+ crtc->primary->fb = plane_state->fb;
+ crtc->x = plane_state->src_x >> 16;
+ crtc->y = plane_state->src_y >> 16;
+ }
}
}
@@ -12347,7 +12504,7 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2)
list_for_each_entry((intel_crtc), \
&(dev)->mode_config.crtc_list, \
base.head) \
- if (mask & (1 <<(intel_crtc)->pipe))
+ for_each_if (mask & (1 <<(intel_crtc)->pipe))
static bool
intel_compare_m_n(unsigned int m, unsigned int n,
@@ -12531,6 +12688,8 @@ intel_pipe_config_compare(struct drm_device *dev,
} else
PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2);
+ PIPE_CONF_CHECK_I(has_dsi_encoder);
+
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay);
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal);
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_start);
@@ -12548,7 +12707,7 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_I(pixel_multiplier);
PIPE_CONF_CHECK_I(has_hdmi_sink);
if ((INTEL_INFO(dev)->gen < 8 && !IS_HASWELL(dev)) ||
- IS_VALLEYVIEW(dev))
+ IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
PIPE_CONF_CHECK_I(limited_color_range);
PIPE_CONF_CHECK_I(has_infoframe);
@@ -13085,6 +13244,45 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
return 0;
}
+/*
+ * Handle calculation of various watermark data at the end of the atomic check
+ * phase. The code here should be run after the per-crtc and per-plane 'check'
+ * handlers to ensure that all derived state has been updated.
+ */
+static void calc_watermark_data(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *cstate;
+ struct drm_plane *plane;
+ struct drm_plane_state *pstate;
+
+ /*
+ * Calculate watermark configuration details now that derived
+ * plane/crtc state is all properly updated.
+ */
+ drm_for_each_crtc(crtc, dev) {
+ cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?:
+ crtc->state;
+
+ if (cstate->active)
+ intel_state->wm_config.num_pipes_active++;
+ }
+ drm_for_each_legacy_plane(plane, dev) {
+ pstate = drm_atomic_get_existing_plane_state(state, plane) ?:
+ plane->state;
+
+ if (!to_intel_plane_state(pstate)->visible)
+ continue;
+
+ intel_state->wm_config.sprites_enabled = true;
+ if (pstate->crtc_w != pstate->src_w >> 16 ||
+ pstate->crtc_h != pstate->src_h >> 16)
+ intel_state->wm_config.sprites_scaled = true;
+ }
+}
+
/**
* intel_atomic_check - validate state object
* @dev: drm device
@@ -13093,6 +13291,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
static int intel_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
int ret, i;
@@ -13160,10 +13359,81 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
return ret;
} else
- to_intel_atomic_state(state)->cdclk =
- to_i915(state->dev)->cdclk_freq;
+ intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
+
+ ret = drm_atomic_helper_check_planes(state->dev, state);
+ if (ret)
+ return ret;
- return drm_atomic_helper_check_planes(state->dev, state);
+ calc_watermark_data(state);
+
+ return 0;
+}
+
+static int intel_atomic_prepare_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_plane_state *plane_state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ int i, ret;
+
+ if (async) {
+ DRM_DEBUG_KMS("i915 does not yet support async commit\n");
+ return -EINVAL;
+ }
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ ret = intel_crtc_wait_for_pending_flips(crtc);
+ if (ret)
+ return ret;
+
+ if (atomic_read(&to_intel_crtc(crtc)->unpin_work_count) >= 2)
+ flush_workqueue(dev_priv->wq);
+ }
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (!ret && !async && !i915_reset_in_progress(&dev_priv->gpu_error)) {
+ u32 reset_counter;
+
+ reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+ mutex_unlock(&dev->struct_mutex);
+
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ struct intel_plane_state *intel_plane_state =
+ to_intel_plane_state(plane_state);
+
+ if (!intel_plane_state->wait_req)
+ continue;
+
+ ret = __i915_wait_request(intel_plane_state->wait_req,
+ reset_counter, true,
+ NULL, NULL);
+
+ /* Swallow -EIO errors to allow updates during hw lockup. */
+ if (ret == -EIO)
+ ret = 0;
+
+ if (ret)
+ break;
+ }
+
+ if (!ret)
+ return 0;
+
+ mutex_lock(&dev->struct_mutex);
+ drm_atomic_helper_cleanup_planes(dev, state);
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
}
/**
@@ -13187,22 +13457,20 @@ static int intel_atomic_commit(struct drm_device *dev,
bool async)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
+ struct drm_crtc *crtc;
int ret = 0;
int i;
bool any_ms = false;
- if (async) {
- DRM_DEBUG_KMS("i915 does not yet support async commit\n");
- return -EINVAL;
- }
-
- ret = drm_atomic_helper_prepare_planes(dev, state);
- if (ret)
+ ret = intel_atomic_prepare_commit(dev, state, async);
+ if (ret) {
+ DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
return ret;
+ }
drm_atomic_helper_swap_state(dev, state);
+ dev_priv->wm.config = to_intel_atomic_state(state)->wm_config;
for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -13218,6 +13486,16 @@ static int intel_atomic_commit(struct drm_device *dev,
dev_priv->display.crtc_disable(crtc);
intel_crtc->active = false;
intel_disable_shared_dpll(intel_crtc);
+
+ /*
+ * Underruns don't always raise
+ * interrupts, so check manually.
+ */
+ intel_check_cpu_fifo_underruns(dev_priv);
+ intel_check_pch_fifo_underruns(dev_priv);
+
+ if (!crtc->state->active)
+ intel_update_watermarks(crtc);
}
}
@@ -13240,6 +13518,9 @@ static int intel_atomic_commit(struct drm_device *dev,
to_intel_crtc_state(crtc->state)->update_pipe;
unsigned long put_domains = 0;
+ if (modeset)
+ intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
+
if (modeset && crtc->state->active) {
update_scanline_offset(to_intel_crtc(crtc));
dev_priv->display.crtc_enable(crtc);
@@ -13255,18 +13536,26 @@ static int intel_atomic_commit(struct drm_device *dev,
if (!modeset)
intel_pre_plane_update(intel_crtc);
- drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+ if (crtc->state->active &&
+ (crtc->state->planes_changed || update_pipe))
+ drm_atomic_helper_commit_planes_on_crtc(crtc_state);
if (put_domains)
modeset_put_power_domains(dev_priv, put_domains);
intel_post_plane_update(intel_crtc);
+
+ if (modeset)
+ intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
}
/* FIXME: add subpixel order */
drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ mutex_lock(&dev->struct_mutex);
drm_atomic_helper_cleanup_planes(dev, state);
+ mutex_unlock(&dev->struct_mutex);
if (any_ms)
intel_modeset_check_state(dev, state);
@@ -13435,6 +13724,8 @@ static void intel_shared_dpll_init(struct drm_device *dev)
* bits. Some older platforms need special physical address handling for
* cursor planes.
*
+ * Must be called with struct_mutex held.
+ *
* Returns 0 on success, negative error code on failure.
*/
int
@@ -13445,28 +13736,71 @@ intel_prepare_plane_fb(struct drm_plane *plane,
struct drm_framebuffer *fb = new_state->fb;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
+ struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb);
int ret = 0;
- if (!obj)
+ if (!obj && !old_obj)
return 0;
- mutex_lock(&dev->struct_mutex);
+ if (old_obj) {
+ struct drm_crtc_state *crtc_state =
+ drm_atomic_get_existing_crtc_state(new_state->state, plane->state->crtc);
+
+ /* Big Hammer, we also need to ensure that any pending
+ * MI_WAIT_FOR_EVENT inside a user batch buffer on the
+ * current scanout is retired before unpinning the old
+ * framebuffer. Note that we rely on userspace rendering
+ * into the buffer attached to the pipe they are waiting
+ * on. If not, userspace generates a GPU hang with IPEHR
+ * point to the MI_WAIT_FOR_EVENT.
+ *
+ * This should only fail upon a hung GPU, in which case we
+ * can safely continue.
+ */
+ if (needs_modeset(crtc_state))
+ ret = i915_gem_object_wait_rendering(old_obj, true);
+
+ /* Swallow -EIO errors to allow updates during hw lockup. */
+ if (ret && ret != -EIO)
+ return ret;
+ }
+
+ /* For framebuffer backed by dmabuf, wait for fence */
+ if (obj && obj->base.dma_buf) {
+ long lret;
+
+ lret = reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv,
+ false, true,
+ MAX_SCHEDULE_TIMEOUT);
+ if (lret == -ERESTARTSYS)
+ return lret;
+
+ WARN(lret < 0, "waiting returns %li\n", lret);
+ }
- if (plane->type == DRM_PLANE_TYPE_CURSOR &&
+ if (!obj) {
+ ret = 0;
+ } else if (plane->type == DRM_PLANE_TYPE_CURSOR &&
INTEL_INFO(dev)->cursor_needs_physical) {
int align = IS_I830(dev) ? 16 * 1024 : 256;
ret = i915_gem_object_attach_phys(obj, align);
if (ret)
DRM_DEBUG_KMS("failed to attach phys object\n");
} else {
- ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL, NULL);
+ ret = intel_pin_and_fence_fb_obj(plane, fb, new_state);
}
- if (ret == 0)
- i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
+ if (ret == 0) {
+ if (obj) {
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(new_state);
- mutex_unlock(&dev->struct_mutex);
+ i915_gem_request_assign(&plane_state->wait_req,
+ obj->last_write_req);
+ }
+
+ i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
+ }
return ret;
}
@@ -13477,23 +13811,35 @@ intel_prepare_plane_fb(struct drm_plane *plane,
* @fb: old framebuffer that was on plane
*
* Cleans up a framebuffer that has just been removed from a plane.
+ *
+ * Must be called with struct_mutex held.
*/
void
intel_cleanup_plane_fb(struct drm_plane *plane,
const struct drm_plane_state *old_state)
{
struct drm_device *dev = plane->dev;
- struct drm_i915_gem_object *obj = intel_fb_obj(old_state->fb);
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct intel_plane_state *old_intel_state;
+ struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb);
+ struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb);
- if (!obj)
+ old_intel_state = to_intel_plane_state(old_state);
+
+ if (!obj && !old_obj)
return;
- if (plane->type != DRM_PLANE_TYPE_CURSOR ||
- !INTEL_INFO(dev)->cursor_needs_physical) {
- mutex_lock(&dev->struct_mutex);
+ if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
+ !INTEL_INFO(dev)->cursor_needs_physical))
intel_unpin_fb_obj(old_state->fb, old_state);
- mutex_unlock(&dev->struct_mutex);
- }
+
+ /* prepare_fb aborted? */
+ if ((old_obj && (old_obj->frontbuffer_bits & intel_plane->frontbuffer_bit)) ||
+ (obj && !(obj->frontbuffer_bits & intel_plane->frontbuffer_bit)))
+ i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
+
+ i915_gem_request_assign(&old_intel_state->wait_req, NULL);
+
}
int
@@ -13512,7 +13858,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state
crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk;
- if (!crtc_clock || !cdclk)
+ if (WARN_ON_ONCE(!crtc_clock || cdclk < crtc_clock))
return DRM_PLANE_HELPER_NO_SCALING;
/*
@@ -13560,18 +13906,8 @@ intel_commit_primary_plane(struct drm_plane *plane,
struct drm_framebuffer *fb = state->base.fb;
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc;
- struct drm_rect *src = &state->src;
crtc = crtc ? crtc : plane->crtc;
- intel_crtc = to_intel_crtc(crtc);
-
- plane->fb = fb;
- crtc->x = src->x1 >> 16;
- crtc->y = src->y1 >> 16;
-
- if (!crtc->state->active)
- return;
dev_priv->display.update_primary_plane(crtc, fb,
state->src.x1 >> 16,
@@ -13597,12 +13933,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
to_intel_crtc_state(old_crtc_state);
bool modeset = needs_modeset(crtc->state);
- if (intel_crtc->atomic.update_wm_pre)
- intel_update_watermarks(crtc);
-
/* Perform vblank evasion around commit operation */
- if (crtc->state->active)
- intel_pipe_update_start(intel_crtc);
+ intel_pipe_update_start(intel_crtc);
if (modeset)
return;
@@ -13618,8 +13950,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (crtc->state->active)
- intel_pipe_update_end(intel_crtc);
+ intel_pipe_update_end(intel_crtc);
}
/**
@@ -13696,7 +14027,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
drm_universal_plane_init(dev, &primary->base, 0,
&intel_plane_funcs,
intel_primary_formats, num_formats,
- DRM_PLANE_TYPE_PRIMARY);
+ DRM_PLANE_TYPE_PRIMARY, NULL);
if (INTEL_INFO(dev)->gen >= 4)
intel_create_rotation_property(dev, primary);
@@ -13848,7 +14179,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
&intel_plane_funcs,
intel_cursor_formats,
ARRAY_SIZE(intel_cursor_formats),
- DRM_PLANE_TYPE_CURSOR);
+ DRM_PLANE_TYPE_CURSOR, NULL);
if (INTEL_INFO(dev)->gen >= 4) {
if (!dev->mode_config.rotation_property)
@@ -13925,7 +14256,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
goto fail;
ret = drm_crtc_init_with_planes(dev, &intel_crtc->base, primary,
- cursor, &intel_crtc_funcs);
+ cursor, &intel_crtc_funcs, NULL);
if (ret)
goto fail;
@@ -14051,7 +14382,14 @@ static bool intel_crt_present(struct drm_device *dev)
if (IS_CHERRYVIEW(dev))
return false;
- if (IS_VALLEYVIEW(dev) && !dev_priv->vbt.int_crt_support)
+ if (HAS_PCH_LPT_H(dev) && I915_READ(SFUSE_STRAP) & SFUSE_STRAP_CRT_DISABLED)
+ return false;
+
+ /* DDI E can't be used if DDI A requires 4 lanes */
+ if (HAS_DDI(dev) && I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)
+ return false;
+
+ if (!dev_priv->vbt.int_crt_support)
return false;
return true;
@@ -14087,7 +14425,7 @@ static void intel_setup_outputs(struct drm_device *dev)
*/
found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED;
/* WaIgnoreDDIAStrap: skl */
- if (found || IS_SKYLAKE(dev))
+ if (found || IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
intel_ddi_init(dev, PORT_A);
/* DDI B, C and D detection is indicated by the SFUSE_STRAP
@@ -14103,7 +14441,7 @@ static void intel_setup_outputs(struct drm_device *dev)
/*
* On SKL we don't have a way to detect DDI-E so we rely on VBT.
*/
- if (IS_SKYLAKE(dev) &&
+ if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) &&
(dev_priv->vbt.ddi_port_info[PORT_E].supports_dp ||
dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi ||
dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi))
@@ -14118,7 +14456,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) {
/* PCH SDVOB multiplex with HDMIB */
- found = intel_sdvo_init(dev, PCH_SDVOB, true);
+ found = intel_sdvo_init(dev, PCH_SDVOB, PORT_B);
if (!found)
intel_hdmi_init(dev, PCH_HDMIB, PORT_B);
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
@@ -14136,7 +14474,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(PCH_DP_D) & DP_DETECTED)
intel_dp_init(dev, PCH_DP_D, PORT_D);
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
/*
* The DP_DETECTED bit is the latched state of the DDC
* SDA pin at boot. However since eDP doesn't require DDC
@@ -14174,7 +14512,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOB\n");
- found = intel_sdvo_init(dev, GEN3_SDVOB, true);
+ found = intel_sdvo_init(dev, GEN3_SDVOB, PORT_B);
if (!found && IS_G4X(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
intel_hdmi_init(dev, GEN4_HDMIB, PORT_B);
@@ -14188,7 +14526,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOC\n");
- found = intel_sdvo_init(dev, GEN3_SDVOC, false);
+ found = intel_sdvo_init(dev, GEN3_SDVOC, PORT_C);
}
if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) {
@@ -14285,7 +14623,7 @@ u32 intel_fb_pitch_limit(struct drm_device *dev, uint64_t fb_modifier,
* pixels and 32K bytes."
*/
return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768);
- } else if (gen >= 5 && !IS_VALLEYVIEW(dev)) {
+ } else if (gen >= 5 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
return 32*1024;
} else if (gen >= 4) {
if (fb_modifier == I915_FORMAT_MOD_X_TILED)
@@ -14389,7 +14727,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
}
break;
case DRM_FORMAT_ABGR8888:
- if (!IS_VALLEYVIEW(dev) && INTEL_INFO(dev)->gen < 9) {
+ if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
+ INTEL_INFO(dev)->gen < 9) {
DRM_DEBUG("unsupported pixel format: %s\n",
drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
@@ -14405,7 +14744,7 @@ static int intel_framebuffer_init(struct drm_device *dev,
}
break;
case DRM_FORMAT_ABGR2101010:
- if (!IS_VALLEYVIEW(dev)) {
+ if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
DRM_DEBUG("unsupported pixel format: %s\n",
drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
@@ -14454,8 +14793,9 @@ static int intel_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
intel_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
- struct drm_mode_fb_cmd2 *user_mode_cmd)
+ const struct drm_mode_fb_cmd2 *user_mode_cmd)
{
+ struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
@@ -14464,7 +14804,11 @@ intel_user_framebuffer_create(struct drm_device *dev,
if (&obj->base == NULL)
return ERR_PTR(-ENOENT);
- return intel_framebuffer_create(dev, &mode_cmd, obj);
+ fb = intel_framebuffer_create(dev, &mode_cmd, obj);
+ if (IS_ERR(fb))
+ drm_gem_object_unreference_unlocked(&obj->base);
+
+ return fb;
}
#ifndef CONFIG_DRM_FBDEV_EMULATION
@@ -14528,7 +14872,7 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.crtc_disable = ironlake_crtc_disable;
dev_priv->display.update_primary_plane =
ironlake_update_primary_plane;
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.get_initial_plane_config =
i9xx_get_initial_plane_config;
@@ -14549,7 +14893,7 @@ static void intel_init_display(struct drm_device *dev)
}
/* Returns the core display clock speed */
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
dev_priv->display.get_display_clock_speed =
skylake_get_display_clock_speed;
else if (IS_BROXTON(dev))
@@ -14561,7 +14905,7 @@ static void intel_init_display(struct drm_device *dev)
else if (IS_HASWELL(dev))
dev_priv->display.get_display_clock_speed =
haswell_get_display_clock_speed;
- else if (IS_VALLEYVIEW(dev))
+ else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
dev_priv->display.get_display_clock_speed =
valleyview_get_display_clock_speed;
else if (IS_GEN5(dev))
@@ -14589,9 +14933,6 @@ static void intel_init_display(struct drm_device *dev)
else if (IS_I945GM(dev) || IS_845G(dev))
dev_priv->display.get_display_clock_speed =
i9xx_misc_get_display_clock_speed;
- else if (IS_PINEVIEW(dev))
- dev_priv->display.get_display_clock_speed =
- pnv_get_display_clock_speed;
else if (IS_I915GM(dev))
dev_priv->display.get_display_clock_speed =
i915gm_get_display_clock_speed;
@@ -14622,7 +14963,7 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.modeset_calc_cdclk =
broadwell_modeset_calc_cdclk;
}
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
dev_priv->display.modeset_commit_cdclk =
valleyview_modeset_commit_cdclk;
dev_priv->display.modeset_calc_cdclk =
@@ -14838,7 +15179,7 @@ static void i915_disable_vga(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u8 sr1;
- u32 vga_reg = i915_vgacntrl_reg(dev);
+ i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
/* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
@@ -14954,9 +15295,6 @@ void intel_modeset_init(struct drm_device *dev)
i915_disable_vga(dev);
intel_setup_outputs(dev);
- /* Just in case the BIOS is doing something questionable. */
- intel_fbc_disable(dev_priv);
-
drm_modeset_lock_all(dev);
intel_modeset_setup_hw_state(dev);
drm_modeset_unlock_all(dev);
@@ -15043,10 +15381,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg;
+ i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder);
/* Clear any frame start delays used for debugging left by the BIOS */
- reg = PIPECONF(crtc->config->cpu_transcoder);
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
/* restore vblank interrupts to correct state */
@@ -15113,6 +15450,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
crtc->base.state->active = crtc->active;
crtc->base.enabled = crtc->active;
+ crtc->base.state->connector_mask = 0;
/* Because we only establish the connector -> encoder ->
* crtc links if something is active, this means the
@@ -15200,7 +15538,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
void i915_redisable_vga_power_on(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 vga_reg = i915_vgacntrl_reg(dev);
+ i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
@@ -15239,7 +15577,7 @@ static void readout_plane_state(struct intel_crtc *crtc)
struct intel_plane_state *plane_state =
to_intel_plane_state(primary->state);
- plane_state->visible =
+ plane_state->visible = crtc->active &&
primary_get_hw_state(to_intel_plane(primary));
if (plane_state->visible)
@@ -15315,7 +15653,21 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
for_each_intel_connector(dev, connector) {
if (connector->get_hw_state(connector)) {
connector->base.dpms = DRM_MODE_DPMS_ON;
- connector->base.encoder = &connector->encoder->base;
+
+ encoder = connector->encoder;
+ connector->base.encoder = &encoder->base;
+
+ if (encoder->base.crtc &&
+ encoder->base.crtc->state->active) {
+ /*
+ * This has to be done during hardware readout
+ * because anything calling .crtc_disable may
+ * rely on the connector_mask being accurate.
+ */
+ encoder->base.crtc->state->connector_mask |=
+ 1 << drm_connector_index(&connector->base);
+ }
+
} else {
connector->base.dpms = DRM_MODE_DPMS_OFF;
connector->base.encoder = NULL;
@@ -15400,7 +15752,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev)
pll->on = false;
}
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_wm_get_hw_state(dev);
else if (IS_GEN9(dev))
skl_wm_get_hw_state(dev);
@@ -15496,8 +15848,7 @@ void intel_modeset_gem_init(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(c->primary,
c->primary->fb,
- c->primary->state,
- NULL, NULL);
+ c->primary->state);
mutex_unlock(&dev->struct_mutex);
if (ret) {
DRM_ERROR("failed to pin boot fb on pipe %d\n",
@@ -15524,7 +15875,7 @@ void intel_connector_unregister(struct intel_connector *intel_connector)
void intel_modeset_cleanup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_connector *connector;
+ struct intel_connector *connector;
intel_disable_gt_powersave(dev);
@@ -15551,12 +15902,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
flush_scheduled_work();
/* destroy the backlight and sysfs files before encoders/connectors */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- struct intel_connector *intel_connector;
-
- intel_connector = to_intel_connector(connector);
- intel_connector->unregister(intel_connector);
- }
+ for_each_intel_connector(dev, connector)
+ connector->unregister(connector);
drm_mode_config_cleanup(dev);
@@ -15565,6 +15912,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
intel_cleanup_gt_powersave(dev);
mutex_unlock(&dev->struct_mutex);
+
+ intel_teardown_gmbus(dev);
}
/*
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 78b8ec84d576..796e3d313cb9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -389,8 +389,7 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
* We don't have power sequencer currently.
* Pick one that's not used by other ports.
*/
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
+ for_each_intel_encoder(dev, encoder) {
struct intel_dp *tmp;
if (encoder->type != INTEL_OUTPUT_EDP)
@@ -517,7 +516,7 @@ void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
struct intel_encoder *encoder;
- if (WARN_ON(!IS_VALLEYVIEW(dev)))
+ if (WARN_ON(!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)))
return;
/*
@@ -530,7 +529,7 @@ void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv)
* should use them always.
*/
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+ for_each_intel_encoder(dev, encoder) {
struct intel_dp *intel_dp;
if (encoder->type != INTEL_OUTPUT_EDP)
@@ -541,7 +540,8 @@ void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv)
}
}
-static u32 _pp_ctrl_reg(struct intel_dp *intel_dp)
+static i915_reg_t
+_pp_ctrl_reg(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -553,7 +553,8 @@ static u32 _pp_ctrl_reg(struct intel_dp *intel_dp)
return VLV_PIPE_PP_CONTROL(vlv_power_sequencer_pipe(intel_dp));
}
-static u32 _pp_stat_reg(struct intel_dp *intel_dp)
+static i915_reg_t
+_pp_stat_reg(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -580,9 +581,9 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
pps_lock(intel_dp);
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
- u32 pp_ctrl_reg, pp_div_reg;
+ i915_reg_t pp_ctrl_reg, pp_div_reg;
u32 pp_div;
pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
@@ -608,7 +609,7 @@ static bool edp_have_panel_power(struct intel_dp *intel_dp)
lockdep_assert_held(&dev_priv->pps_mutex);
- if (IS_VALLEYVIEW(dev) &&
+ if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
intel_dp->pps_pipe == INVALID_PIPE)
return false;
@@ -622,7 +623,7 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
lockdep_assert_held(&dev_priv->pps_mutex);
- if (IS_VALLEYVIEW(dev) &&
+ if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
intel_dp->pps_pipe == INVALID_PIPE)
return false;
@@ -652,7 +653,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
+ i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg;
uint32_t status;
bool done;
@@ -679,7 +680,7 @@ static uint32_t i9xx_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
* The clock divider is based off the hrawclk, and would like to run at
* 2MHz. So, take the hrawclk value and divide by 2 and use that
*/
- return index ? 0 : intel_hrawclk(dev) / 2;
+ return index ? 0 : DIV_ROUND_CLOSEST(intel_hrawclk(dev), 2);
}
static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
@@ -692,10 +693,10 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
return 0;
if (intel_dig_port->port == PORT_A) {
- return DIV_ROUND_UP(dev_priv->cdclk_freq, 2000);
+ return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000);
} else {
- return DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
+ return DIV_ROUND_CLOSEST(intel_pch_rawclk(dev), 2);
}
}
@@ -709,7 +710,7 @@ static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
if (index)
return 0;
return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000);
- } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
+ } else if (HAS_PCH_LPT_H(dev_priv)) {
/* Workaround for non-ULT HSW */
switch (index) {
case 0: return 63;
@@ -717,7 +718,7 @@ static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
default: return 0;
}
} else {
- return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
+ return index ? 0 : DIV_ROUND_CLOSEST(intel_pch_rawclk(dev), 2);
}
}
@@ -750,7 +751,7 @@ static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
else
precharge = 5;
- if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL)
+ if (IS_BROADWELL(dev) && intel_dig_port->port == PORT_A)
timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
else
timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
@@ -789,8 +790,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
- uint32_t ch_data = ch_ctl + 4;
+ i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg;
uint32_t aux_clock_divider;
int i, ret, recv_bytes;
uint32_t status;
@@ -854,7 +854,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
for (try = 0; try < 5; try++) {
/* Load the send data into the aux channel data registers */
for (i = 0; i < send_bytes; i += 4)
- I915_WRITE(ch_data + i,
+ I915_WRITE(intel_dp->aux_ch_data_reg[i >> 2],
intel_dp_pack_aux(send + i,
send_bytes - i));
@@ -914,11 +914,32 @@ done:
/* Unload any bytes sent back from the other side */
recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+
+ /*
+ * By BSpec: "Message sizes of 0 or >20 are not allowed."
+ * We have no idea of what happened so we return -EBUSY so
+ * drm layer takes care for the necessary retries.
+ */
+ if (recv_bytes == 0 || recv_bytes > 20) {
+ DRM_DEBUG_KMS("Forbidden recv_bytes = %d on aux transaction\n",
+ recv_bytes);
+ /*
+ * FIXME: This patch was created on top of a series that
+ * organize the retries at drm level. There EBUSY should
+ * also take care for 1ms wait before retrying.
+ * That aux retries re-org is still needed and after that is
+ * merged we remove this sleep from here.
+ */
+ usleep_range(1000, 1500);
+ ret = -EBUSY;
+ goto out;
+ }
+
if (recv_bytes > recv_size)
recv_bytes = recv_size;
for (i = 0; i < recv_bytes; i += 4)
- intel_dp_unpack_aux(I915_READ(ch_data + i),
+ intel_dp_unpack_aux(I915_READ(intel_dp->aux_ch_data_reg[i >> 2]),
recv + i, recv_bytes - i);
ret = recv_bytes;
@@ -1005,96 +1026,206 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
return ret;
}
-static void
-intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+static i915_reg_t g4x_aux_ctl_reg(struct drm_i915_private *dev_priv,
+ enum port port)
{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- enum port port = intel_dig_port->port;
- struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
- const char *name = NULL;
- uint32_t porte_aux_ctl_reg = DPA_AUX_CH_CTL;
- int ret;
+ switch (port) {
+ case PORT_B:
+ case PORT_C:
+ case PORT_D:
+ return DP_AUX_CH_CTL(port);
+ default:
+ MISSING_CASE(port);
+ return DP_AUX_CH_CTL(PORT_B);
+ }
+}
- /* On SKL we don't have Aux for port E so we rely on VBT to set
- * a proper alternate aux channel.
- */
- if (IS_SKYLAKE(dev) && port == PORT_E) {
- switch (info->alternate_aux_channel) {
- case DP_AUX_B:
- porte_aux_ctl_reg = DPB_AUX_CH_CTL;
- break;
- case DP_AUX_C:
- porte_aux_ctl_reg = DPC_AUX_CH_CTL;
- break;
- case DP_AUX_D:
- porte_aux_ctl_reg = DPD_AUX_CH_CTL;
- break;
- case DP_AUX_A:
- default:
- porte_aux_ctl_reg = DPA_AUX_CH_CTL;
- }
+static i915_reg_t g4x_aux_data_reg(struct drm_i915_private *dev_priv,
+ enum port port, int index)
+{
+ switch (port) {
+ case PORT_B:
+ case PORT_C:
+ case PORT_D:
+ return DP_AUX_CH_DATA(port, index);
+ default:
+ MISSING_CASE(port);
+ return DP_AUX_CH_DATA(PORT_B, index);
}
+}
+static i915_reg_t ilk_aux_ctl_reg(struct drm_i915_private *dev_priv,
+ enum port port)
+{
switch (port) {
case PORT_A:
- intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
- name = "DPDDC-A";
- break;
+ return DP_AUX_CH_CTL(port);
case PORT_B:
- intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
- name = "DPDDC-B";
- break;
case PORT_C:
- intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
- name = "DPDDC-C";
- break;
case PORT_D:
- intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
- name = "DPDDC-D";
- break;
- case PORT_E:
- intel_dp->aux_ch_ctl_reg = porte_aux_ctl_reg;
- name = "DPDDC-E";
- break;
+ return PCH_DP_AUX_CH_CTL(port);
default:
- BUG();
+ MISSING_CASE(port);
+ return DP_AUX_CH_CTL(PORT_A);
}
+}
- /*
- * The AUX_CTL register is usually DP_CTL + 0x10.
- *
- * On Haswell and Broadwell though:
- * - Both port A DDI_BUF_CTL and DDI_AUX_CTL are on the CPU
- * - Port B/C/D AUX channels are on the PCH, DDI_BUF_CTL on the CPU
- *
- * Skylake moves AUX_CTL back next to DDI_BUF_CTL, on the CPU.
- */
- if (!IS_HASWELL(dev) && !IS_BROADWELL(dev) && port != PORT_E)
- intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
+static i915_reg_t ilk_aux_data_reg(struct drm_i915_private *dev_priv,
+ enum port port, int index)
+{
+ switch (port) {
+ case PORT_A:
+ return DP_AUX_CH_DATA(port, index);
+ case PORT_B:
+ case PORT_C:
+ case PORT_D:
+ return PCH_DP_AUX_CH_DATA(port, index);
+ default:
+ MISSING_CASE(port);
+ return DP_AUX_CH_DATA(PORT_A, index);
+ }
+}
+
+/*
+ * On SKL we don't have Aux for port E so we rely
+ * on VBT to set a proper alternate aux channel.
+ */
+static enum port skl_porte_aux_port(struct drm_i915_private *dev_priv)
+{
+ const struct ddi_vbt_port_info *info =
+ &dev_priv->vbt.ddi_port_info[PORT_E];
+
+ switch (info->alternate_aux_channel) {
+ case DP_AUX_A:
+ return PORT_A;
+ case DP_AUX_B:
+ return PORT_B;
+ case DP_AUX_C:
+ return PORT_C;
+ case DP_AUX_D:
+ return PORT_D;
+ default:
+ MISSING_CASE(info->alternate_aux_channel);
+ return PORT_A;
+ }
+}
+
+static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
+ enum port port)
+{
+ if (port == PORT_E)
+ port = skl_porte_aux_port(dev_priv);
+
+ switch (port) {
+ case PORT_A:
+ case PORT_B:
+ case PORT_C:
+ case PORT_D:
+ return DP_AUX_CH_CTL(port);
+ default:
+ MISSING_CASE(port);
+ return DP_AUX_CH_CTL(PORT_A);
+ }
+}
+
+static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
+ enum port port, int index)
+{
+ if (port == PORT_E)
+ port = skl_porte_aux_port(dev_priv);
+
+ switch (port) {
+ case PORT_A:
+ case PORT_B:
+ case PORT_C:
+ case PORT_D:
+ return DP_AUX_CH_DATA(port, index);
+ default:
+ MISSING_CASE(port);
+ return DP_AUX_CH_DATA(PORT_A, index);
+ }
+}
+
+static i915_reg_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv,
+ enum port port)
+{
+ if (INTEL_INFO(dev_priv)->gen >= 9)
+ return skl_aux_ctl_reg(dev_priv, port);
+ else if (HAS_PCH_SPLIT(dev_priv))
+ return ilk_aux_ctl_reg(dev_priv, port);
+ else
+ return g4x_aux_ctl_reg(dev_priv, port);
+}
+
+static i915_reg_t intel_aux_data_reg(struct drm_i915_private *dev_priv,
+ enum port port, int index)
+{
+ if (INTEL_INFO(dev_priv)->gen >= 9)
+ return skl_aux_data_reg(dev_priv, port, index);
+ else if (HAS_PCH_SPLIT(dev_priv))
+ return ilk_aux_data_reg(dev_priv, port, index);
+ else
+ return g4x_aux_data_reg(dev_priv, port, index);
+}
+
+static void intel_aux_reg_init(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ int i;
+
+ intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port);
+ for (i = 0; i < ARRAY_SIZE(intel_dp->aux_ch_data_reg); i++)
+ intel_dp->aux_ch_data_reg[i] = intel_aux_data_reg(dev_priv, port, i);
+}
+
+static void
+intel_dp_aux_fini(struct intel_dp *intel_dp)
+{
+ drm_dp_aux_unregister(&intel_dp->aux);
+ kfree(intel_dp->aux.name);
+}
+
+static int
+intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ enum port port = intel_dig_port->port;
+ int ret;
+
+ intel_aux_reg_init(intel_dp);
+
+ intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c", port_name(port));
+ if (!intel_dp->aux.name)
+ return -ENOMEM;
- intel_dp->aux.name = name;
intel_dp->aux.dev = dev->dev;
intel_dp->aux.transfer = intel_dp_aux_transfer;
- DRM_DEBUG_KMS("registering %s bus for %s\n", name,
+ DRM_DEBUG_KMS("registering %s bus for %s\n",
+ intel_dp->aux.name,
connector->base.kdev->kobj.name);
ret = drm_dp_aux_register(&intel_dp->aux);
if (ret < 0) {
DRM_ERROR("drm_dp_aux_register() for %s failed (%d)\n",
- name, ret);
- return;
+ intel_dp->aux.name, ret);
+ kfree(intel_dp->aux.name);
+ return ret;
}
ret = sysfs_create_link(&connector->base.kdev->kobj,
&intel_dp->aux.ddc.dev.kobj,
intel_dp->aux.ddc.dev.kobj.name);
if (ret < 0) {
- DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret);
- drm_dp_aux_unregister(&intel_dp->aux);
+ DRM_ERROR("sysfs_create_link() for %s failed (%d)\n",
+ intel_dp->aux.name, ret);
+ intel_dp_aux_fini(intel_dp);
+ return ret;
}
+
+ return 0;
}
static void
@@ -1186,10 +1317,13 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
}
-static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
+
/* WaDisableHBR2:skl */
- if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
return false;
if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
@@ -1200,14 +1334,16 @@ static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
}
static int
-intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
int size;
if (IS_BROXTON(dev)) {
*source_rates = bxt_rates;
size = ARRAY_SIZE(bxt_rates);
- } else if (IS_SKYLAKE(dev)) {
+ } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
*source_rates = skl_rates;
size = ARRAY_SIZE(skl_rates);
} else {
@@ -1216,7 +1352,7 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
}
/* This depends on the fact that 5.4 is last value in the array */
- if (!intel_dp_source_supports_hbr2(dev))
+ if (!intel_dp_source_supports_hbr2(intel_dp))
size--;
return size;
@@ -1281,12 +1417,11 @@ static int intersect_rates(const int *source_rates, int source_len,
static int intel_dp_common_rates(struct intel_dp *intel_dp,
int *common_rates)
{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
const int *source_rates, *sink_rates;
int source_len, sink_len;
sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
- source_len = intel_dp_source_rates(dev, &source_rates);
+ source_len = intel_dp_source_rates(intel_dp, &source_rates);
return intersect_rates(source_rates, source_len,
sink_rates, sink_len,
@@ -1311,7 +1446,6 @@ static void snprintf_int_array(char *str, size_t len,
static void intel_dp_print_rates(struct intel_dp *intel_dp)
{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
const int *source_rates, *sink_rates;
int source_len, sink_len, common_len;
int common_rates[DP_MAX_SUPPORTED_RATES];
@@ -1320,7 +1454,7 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
if ((drm_debug & DRM_UT_KMS) == 0)
return;
- source_len = intel_dp_source_rates(dev, &source_rates);
+ source_len = intel_dp_source_rates(intel_dp, &source_rates);
snprintf_int_array(str, sizeof(str), source_rates, source_len);
DRM_DEBUG_KMS("source rates: %s\n", str);
@@ -1362,8 +1496,8 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
return rate_to_index(rate, intel_dp->sink_rates);
}
-static void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
- uint8_t *link_bw, uint8_t *rate_select)
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+ uint8_t *link_bw, uint8_t *rate_select)
{
if (intel_dp->num_sink_rates) {
*link_bw = 0;
@@ -1423,7 +1557,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
return ret;
}
- if (!HAS_PCH_SPLIT(dev))
+ if (HAS_GMCH_DISPLAY(dev))
intel_gmch_panel_fitting(intel_crtc, pipe_config,
intel_connector->panel.fitting_mode);
else
@@ -1527,7 +1661,7 @@ found:
&pipe_config->dp_m2_n2);
}
- if (IS_SKYLAKE(dev) && is_edp(intel_dp))
+ if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) && is_edp(intel_dp))
skl_edp_set_pll_config(pipe_config);
else if (IS_BROXTON(dev))
/* handled in ddi */;
@@ -1539,37 +1673,6 @@ found:
return true;
}
-static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
-{
- struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpa_ctl;
-
- DRM_DEBUG_KMS("eDP PLL enable for clock %d\n",
- crtc->config->port_clock);
- dpa_ctl = I915_READ(DP_A);
- dpa_ctl &= ~DP_PLL_FREQ_MASK;
-
- if (crtc->config->port_clock == 162000) {
- /* For a long time we've carried around a ILK-DevA w/a for the
- * 160MHz clock. If we're really unlucky, it's still required.
- */
- DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n");
- dpa_ctl |= DP_PLL_FREQ_160MHZ;
- intel_dp->DP |= DP_PLL_FREQ_160MHZ;
- } else {
- dpa_ctl |= DP_PLL_FREQ_270MHZ;
- intel_dp->DP |= DP_PLL_FREQ_270MHZ;
- }
-
- I915_WRITE(DP_A, dpa_ctl);
-
- POSTING_READ(DP_A);
- udelay(500);
-}
-
void intel_dp_set_link_params(struct intel_dp *intel_dp,
const struct intel_crtc_state *pipe_config)
{
@@ -1614,9 +1717,6 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count);
- if (crtc->config->has_audio)
- intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
-
/* Split out the IBX/CPU vs CPT settings */
if (IS_GEN7(dev) && port == PORT_A) {
@@ -1643,7 +1743,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
} else {
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
- crtc->config->limited_color_range)
+ !IS_CHERRYVIEW(dev) && crtc->config->limited_color_range)
intel_dp->DP |= DP_COLOR_RANGE_16_235;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1677,7 +1777,7 @@ static void wait_panel_status(struct intel_dp *intel_dp,
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pp_stat_reg, pp_ctrl_reg;
+ i915_reg_t pp_stat_reg, pp_ctrl_reg;
lockdep_assert_held(&dev_priv->pps_mutex);
@@ -1767,7 +1867,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
enum intel_display_power_domain power_domain;
u32 pp;
- u32 pp_stat_reg, pp_ctrl_reg;
+ i915_reg_t pp_stat_reg, pp_ctrl_reg;
bool need_to_disable = !intel_dp->want_panel_vdd;
lockdep_assert_held(&dev_priv->pps_mutex);
@@ -1843,7 +1943,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
struct intel_encoder *intel_encoder = &intel_dig_port->base;
enum intel_display_power_domain power_domain;
u32 pp;
- u32 pp_stat_reg, pp_ctrl_reg;
+ i915_reg_t pp_stat_reg, pp_ctrl_reg;
lockdep_assert_held(&dev_priv->pps_mutex);
@@ -1930,7 +2030,7 @@ static void edp_panel_on(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
- u32 pp_ctrl_reg;
+ i915_reg_t pp_ctrl_reg;
lockdep_assert_held(&dev_priv->pps_mutex);
@@ -1992,7 +2092,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
enum intel_display_power_domain power_domain;
u32 pp;
- u32 pp_ctrl_reg;
+ i915_reg_t pp_ctrl_reg;
lockdep_assert_held(&dev_priv->pps_mutex);
@@ -2043,7 +2143,7 @@ static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
- u32 pp_ctrl_reg;
+ i915_reg_t pp_ctrl_reg;
/*
* If we enable the backlight right away following a panel power
@@ -2084,7 +2184,7 @@ static void _intel_edp_backlight_off(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
- u32 pp_ctrl_reg;
+ i915_reg_t pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
@@ -2143,27 +2243,61 @@ static void intel_edp_backlight_power(struct intel_connector *connector,
_intel_edp_backlight_off(intel_dp);
}
+static const char *state_string(bool enabled)
+{
+ return enabled ? "on" : "off";
+}
+
+static void assert_dp_port(struct intel_dp *intel_dp, bool state)
+{
+ 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);
+ bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN;
+
+ I915_STATE_WARN(cur_state != state,
+ "DP port %c state assertion failure (expected %s, current %s)\n",
+ port_name(dig_port->port),
+ state_string(state), state_string(cur_state));
+}
+#define assert_dp_port_disabled(d) assert_dp_port((d), false)
+
+static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
+{
+ bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE;
+
+ I915_STATE_WARN(cur_state != state,
+ "eDP PLL state assertion failure (expected %s, current %s)\n",
+ state_string(state), state_string(cur_state));
+}
+#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
+#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
+
static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpa_ctl;
+ struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- assert_pipe_disabled(dev_priv,
- to_intel_crtc(crtc)->pipe);
+ assert_pipe_disabled(dev_priv, crtc->pipe);
+ assert_dp_port_disabled(intel_dp);
+ assert_edp_pll_disabled(dev_priv);
+
+ DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
+ crtc->config->port_clock);
+
+ intel_dp->DP &= ~DP_PLL_FREQ_MASK;
+
+ if (crtc->config->port_clock == 162000)
+ intel_dp->DP |= DP_PLL_FREQ_162MHZ;
+ else
+ intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+
+ I915_WRITE(DP_A, intel_dp->DP);
+ POSTING_READ(DP_A);
+ udelay(500);
- DRM_DEBUG_KMS("\n");
- dpa_ctl = I915_READ(DP_A);
- WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n");
- WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
-
- /* We don't adjust intel_dp->DP while tearing down the link, to
- * facilitate link retraining (e.g. after hotplug). Hence clear all
- * enable bits here to ensure that we don't enable too much. */
- intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
intel_dp->DP |= DP_PLL_ENABLE;
+
I915_WRITE(DP_A, intel_dp->DP);
POSTING_READ(DP_A);
udelay(200);
@@ -2172,24 +2306,18 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
static void ironlake_edp_pll_off(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpa_ctl;
+ struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+ assert_pipe_disabled(dev_priv, crtc->pipe);
+ assert_dp_port_disabled(intel_dp);
+ assert_edp_pll_enabled(dev_priv);
- assert_pipe_disabled(dev_priv,
- to_intel_crtc(crtc)->pipe);
+ DRM_DEBUG_KMS("disabling eDP PLL\n");
- dpa_ctl = I915_READ(DP_A);
- WARN((dpa_ctl & DP_PLL_ENABLE) == 0,
- "dp pll off, should be on\n");
- WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+ intel_dp->DP &= ~DP_PLL_ENABLE;
- /* We can't rely on the value tracked for the DP register in
- * intel_dp->DP because link_down must not change that (otherwise link
- * re-training will fail. */
- dpa_ctl &= ~DP_PLL_ENABLE;
- I915_WRITE(DP_A, dpa_ctl);
+ I915_WRITE(DP_A, intel_dp->DP);
POSTING_READ(DP_A);
udelay(200);
}
@@ -2258,7 +2386,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
}
DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n",
- intel_dp->output_reg);
+ i915_mmio_reg_offset(intel_dp->output_reg));
} else if (IS_CHERRYVIEW(dev)) {
*pipe = DP_PORT_TO_PIPE_CHV(tmp);
} else {
@@ -2310,7 +2438,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
pipe_config->base.adjusted_mode.flags |= flags;
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
- tmp & DP_COLOR_RANGE_16_235)
+ !IS_CHERRYVIEW(dev) && tmp & DP_COLOR_RANGE_16_235)
pipe_config->limited_color_range = true;
pipe_config->has_dp_encoder = true;
@@ -2321,7 +2449,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
intel_dp_get_m_n(crtc, pipe_config);
if (port == PORT_A) {
- if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
+ if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ)
pipe_config->port_clock = 162000;
else
pipe_config->port_clock = 270000;
@@ -2386,6 +2514,8 @@ static void ilk_post_disable_dp(struct intel_encoder *encoder)
enum port port = dp_to_dig_port(intel_dp)->port;
intel_dp_link_down(intel_dp);
+
+ /* Only ilk+ has port A */
if (port == PORT_A)
ironlake_edp_pll_off(intel_dp);
}
@@ -2545,6 +2675,8 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc =
+ to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc);
/* enable with pattern 1 (as per spec) */
_intel_dp_set_link_train(intel_dp, &intel_dp->DP,
@@ -2560,6 +2692,8 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp)
* fail when the power sequencer is freshly used for this port.
*/
intel_dp->DP |= DP_PORT_EN;
+ if (crtc->config->has_audio)
+ intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
I915_WRITE(intel_dp->output_reg, intel_dp->DP);
POSTING_READ(intel_dp->output_reg);
@@ -2572,24 +2706,49 @@ static void intel_enable_dp(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ enum pipe pipe = crtc->pipe;
if (WARN_ON(dp_reg & DP_PORT_EN))
return;
pps_lock(intel_dp);
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_init_panel_power_sequencer(intel_dp);
+ /*
+ * We get an occasional spurious underrun between the port
+ * enable and vdd enable, when enabling port A eDP.
+ *
+ * FIXME: Not sure if this applies to (PCH) port D eDP as well
+ */
+ if (port == PORT_A)
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
intel_dp_enable_port(intel_dp);
+ if (port == PORT_A && IS_GEN5(dev_priv)) {
+ /*
+ * Underrun reporting for the other pipe was disabled in
+ * g4x_pre_enable_dp(). The eDP PLL and port have now been
+ * enabled, so it's now safe to re-enable underrun reporting.
+ */
+ intel_wait_for_vblank_if_active(dev_priv->dev, !pipe);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, true);
+ }
+
edp_panel_vdd_on(intel_dp);
edp_panel_on(intel_dp);
edp_panel_vdd_off(intel_dp, true);
+ if (port == PORT_A)
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+
pps_unlock(intel_dp);
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
unsigned int lane_mask = 0x0;
if (IS_CHERRYVIEW(dev))
@@ -2605,7 +2764,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
if (crtc->config->has_audio) {
DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
- pipe_name(crtc->pipe));
+ pipe_name(pipe));
intel_audio_codec_enable(encoder);
}
}
@@ -2628,16 +2787,29 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
static void g4x_pre_enable_dp(struct intel_encoder *encoder)
{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
- struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
intel_dp_prepare(encoder);
+ if (port == PORT_A && IS_GEN5(dev_priv)) {
+ /*
+ * We get FIFO underruns on the other pipe when
+ * enabling the CPU eDP PLL, and when enabling CPU
+ * eDP port. We could potentially avoid the PLL
+ * underrun with a vblank wait just prior to enabling
+ * the PLL, but that doesn't appear to help the port
+ * enable case. Just sweep it all under the rug.
+ */
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, false);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, false);
+ }
+
/* Only ilk+ has port A */
- if (dport->port == PORT_A) {
- ironlake_set_pll_cpu_edp(intel_dp);
+ if (port == PORT_A)
ironlake_edp_pll_on(intel_dp);
- }
}
static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
@@ -2645,7 +2817,7 @@ static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = intel_dig_port->base.base.dev->dev_private;
enum pipe pipe = intel_dp->pps_pipe;
- int pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
+ i915_reg_t pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
edp_panel_vdd_off_sync(intel_dp);
@@ -2677,8 +2849,7 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
return;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
+ for_each_intel_encoder(dev, encoder) {
struct intel_dp *intel_dp;
enum port port;
@@ -3043,7 +3214,7 @@ intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset,
* Fetch AUX CH registers 0x202 - 0x207 which contain
* link status information
*/
-static bool
+bool
intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
{
return intel_dp_dpcd_read_wake(&intel_dp->aux,
@@ -3053,7 +3224,7 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_
}
/* These are source-specific values. */
-static uint8_t
+uint8_t
intel_dp_voltage_max(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3066,7 +3237,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
if (dev_priv->edp_low_vswing && port == PORT_A)
return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
- } else if (IS_VALLEYVIEW(dev))
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
else if (IS_GEN7(dev) && port == PORT_A)
return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
@@ -3076,7 +3247,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
}
-static uint8_t
+uint8_t
intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3107,7 +3278,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
default:
return DP_TRAIN_PRE_EMPH_LEVEL_0;
}
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
return DP_TRAIN_PRE_EMPH_LEVEL_3;
@@ -3418,38 +3589,6 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
return 0;
}
-static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
- const uint8_t link_status[DP_LINK_STATUS_SIZE])
-{
- uint8_t v = 0;
- uint8_t p = 0;
- int lane;
- uint8_t voltage_max;
- uint8_t preemph_max;
-
- for (lane = 0; lane < intel_dp->lane_count; lane++) {
- uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
- uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
-
- if (this_v > v)
- v = this_v;
- if (this_p > p)
- p = this_p;
- }
-
- voltage_max = intel_dp_voltage_max(intel_dp);
- if (v >= voltage_max)
- v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
-
- preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
- if (p >= preemph_max)
- p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
-
- for (lane = 0; lane < 4; lane++)
- intel_dp->train_set[lane] = v | p;
-}
-
static uint32_t
gen4_signal_levels(uint8_t train_set)
{
@@ -3547,13 +3686,13 @@ gen7_edp_signal_levels(uint8_t train_set)
}
}
-/* Properly updates "DP" with the correct signal levels. */
-static void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
enum port port = intel_dig_port->port;
struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
uint32_t signal_levels, mask = 0;
uint8_t train_set = intel_dp->train_set[0];
@@ -3588,74 +3727,27 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
(train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
DP_TRAIN_PRE_EMPHASIS_SHIFT);
- *DP = (*DP & ~mask) | signal_levels;
-}
-
-static bool
-intel_dp_set_link_train(struct intel_dp *intel_dp,
- uint32_t *DP,
- uint8_t dp_train_pat)
-{
- struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- struct drm_i915_private *dev_priv =
- to_i915(intel_dig_port->base.base.dev);
- uint8_t buf[sizeof(intel_dp->train_set) + 1];
- int ret, len;
-
- _intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
+ intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels;
- I915_WRITE(intel_dp->output_reg, *DP);
+ I915_WRITE(intel_dp->output_reg, intel_dp->DP);
POSTING_READ(intel_dp->output_reg);
-
- buf[0] = dp_train_pat;
- if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
- DP_TRAINING_PATTERN_DISABLE) {
- /* don't write DP_TRAINING_LANEx_SET on disable */
- len = 1;
- } else {
- /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
- memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
- len = intel_dp->lane_count + 1;
- }
-
- ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
- buf, len);
-
- return ret == len;
}
-static bool
-intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP,
- uint8_t dp_train_pat)
-{
- if (!intel_dp->train_set_valid)
- memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
- intel_dp_set_signal_levels(intel_dp, DP);
- return intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
-}
-
-static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
- const uint8_t link_status[DP_LINK_STATUS_SIZE])
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ uint8_t dp_train_pat)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv =
to_i915(intel_dig_port->base.base.dev);
- int ret;
- intel_get_adjust_train(intel_dp, link_status);
- intel_dp_set_signal_levels(intel_dp, DP);
+ _intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat);
- I915_WRITE(intel_dp->output_reg, *DP);
+ I915_WRITE(intel_dp->output_reg, intel_dp->DP);
POSTING_READ(intel_dp->output_reg);
-
- ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
- intel_dp->train_set, intel_dp->lane_count);
-
- return ret == intel_dp->lane_count;
}
-static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -3686,232 +3778,6 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
DRM_ERROR("Timed out waiting for DP idle patterns\n");
}
-/* Enable corresponding port and start training pattern 1 */
-static void
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
-{
- struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
- struct drm_device *dev = encoder->dev;
- int i;
- uint8_t voltage;
- int voltage_tries, loop_tries;
- uint32_t DP = intel_dp->DP;
- uint8_t link_config[2];
- uint8_t link_bw, rate_select;
-
- if (HAS_DDI(dev))
- intel_ddi_prepare_link_retrain(encoder);
-
- intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
- &link_bw, &rate_select);
-
- /* Write the link configuration data */
- link_config[0] = link_bw;
- link_config[1] = intel_dp->lane_count;
- if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
- link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
- drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
- if (intel_dp->num_sink_rates)
- drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
- &rate_select, 1);
-
- link_config[0] = 0;
- link_config[1] = DP_SET_ANSI_8B10B;
- drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
-
- DP |= DP_PORT_EN;
-
- /* clock recovery */
- if (!intel_dp_reset_link_train(intel_dp, &DP,
- DP_TRAINING_PATTERN_1 |
- DP_LINK_SCRAMBLING_DISABLE)) {
- DRM_ERROR("failed to enable link training\n");
- return;
- }
-
- voltage = 0xff;
- voltage_tries = 0;
- loop_tries = 0;
- for (;;) {
- uint8_t link_status[DP_LINK_STATUS_SIZE];
-
- drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
- DRM_ERROR("failed to get link status\n");
- break;
- }
-
- if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
- DRM_DEBUG_KMS("clock recovery OK\n");
- break;
- }
-
- /*
- * if we used previously trained voltage and pre-emphasis values
- * and we don't get clock recovery, reset link training values
- */
- if (intel_dp->train_set_valid) {
- DRM_DEBUG_KMS("clock recovery not ok, reset");
- /* clear the flag as we are not reusing train set */
- intel_dp->train_set_valid = false;
- if (!intel_dp_reset_link_train(intel_dp, &DP,
- DP_TRAINING_PATTERN_1 |
- DP_LINK_SCRAMBLING_DISABLE)) {
- DRM_ERROR("failed to enable link training\n");
- return;
- }
- continue;
- }
-
- /* Check to see if we've tried the max voltage */
- for (i = 0; i < intel_dp->lane_count; i++)
- if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
- break;
- if (i == intel_dp->lane_count) {
- ++loop_tries;
- if (loop_tries == 5) {
- DRM_ERROR("too many full retries, give up\n");
- break;
- }
- intel_dp_reset_link_train(intel_dp, &DP,
- DP_TRAINING_PATTERN_1 |
- DP_LINK_SCRAMBLING_DISABLE);
- voltage_tries = 0;
- continue;
- }
-
- /* Check to see if we've tried the same voltage 5 times */
- if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
- ++voltage_tries;
- if (voltage_tries == 5) {
- DRM_ERROR("too many voltage retries, give up\n");
- break;
- }
- } else
- voltage_tries = 0;
- voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
-
- /* Update training set as requested by target */
- if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
- DRM_ERROR("failed to update link training\n");
- break;
- }
- }
-
- intel_dp->DP = DP;
-}
-
-static void
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
-{
- struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- struct drm_device *dev = dig_port->base.base.dev;
- bool channel_eq = false;
- int tries, cr_tries;
- uint32_t DP = intel_dp->DP;
- uint32_t training_pattern = DP_TRAINING_PATTERN_2;
-
- /*
- * Training Pattern 3 for HBR2 or 1.2 devices that support it.
- *
- * Intel platforms that support HBR2 also support TPS3. TPS3 support is
- * also mandatory for downstream devices that support HBR2.
- *
- * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
- * supported but still not enabled.
- */
- if (intel_dp_source_supports_hbr2(dev) &&
- drm_dp_tps3_supported(intel_dp->dpcd))
- training_pattern = DP_TRAINING_PATTERN_3;
- else if (intel_dp->link_rate == 540000)
- DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
-
- /* channel equalization */
- if (!intel_dp_set_link_train(intel_dp, &DP,
- training_pattern |
- DP_LINK_SCRAMBLING_DISABLE)) {
- DRM_ERROR("failed to start channel equalization\n");
- return;
- }
-
- tries = 0;
- cr_tries = 0;
- channel_eq = false;
- for (;;) {
- uint8_t link_status[DP_LINK_STATUS_SIZE];
-
- if (cr_tries > 5) {
- DRM_ERROR("failed to train DP, aborting\n");
- break;
- }
-
- drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
- DRM_ERROR("failed to get link status\n");
- break;
- }
-
- /* Make sure clock is still ok */
- if (!drm_dp_clock_recovery_ok(link_status,
- intel_dp->lane_count)) {
- intel_dp->train_set_valid = false;
- intel_dp_link_training_clock_recovery(intel_dp);
- intel_dp_set_link_train(intel_dp, &DP,
- training_pattern |
- DP_LINK_SCRAMBLING_DISABLE);
- cr_tries++;
- continue;
- }
-
- if (drm_dp_channel_eq_ok(link_status,
- intel_dp->lane_count)) {
- channel_eq = true;
- break;
- }
-
- /* Try 5 times, then try clock recovery if that fails */
- if (tries > 5) {
- intel_dp->train_set_valid = false;
- intel_dp_link_training_clock_recovery(intel_dp);
- intel_dp_set_link_train(intel_dp, &DP,
- training_pattern |
- DP_LINK_SCRAMBLING_DISABLE);
- tries = 0;
- cr_tries++;
- continue;
- }
-
- /* Update training set as requested by target */
- if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
- DRM_ERROR("failed to update link training\n");
- break;
- }
- ++tries;
- }
-
- intel_dp_set_idle_link_train(intel_dp);
-
- intel_dp->DP = DP;
-
- if (channel_eq) {
- intel_dp->train_set_valid = true;
- DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
- }
-}
-
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
-{
- intel_dp_set_link_train(intel_dp, &intel_dp->DP,
- DP_TRAINING_PATTERN_DISABLE);
-}
-
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
-{
- intel_dp_link_training_clock_recovery(intel_dp);
- intel_dp_link_training_channel_equalization(intel_dp);
-}
-
static void
intel_dp_link_down(struct intel_dp *intel_dp)
{
@@ -3954,6 +3820,13 @@ intel_dp_link_down(struct intel_dp *intel_dp)
* matching HDMI port to be enabled on transcoder A.
*/
if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B && port != PORT_A) {
+ /*
+ * We get CPU/PCH FIFO underruns on the other pipe when
+ * doing the workaround. Sweep them under the rug.
+ */
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
/* always enable with pattern 1 (as per spec) */
DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK);
DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1;
@@ -3963,9 +3836,15 @@ intel_dp_link_down(struct intel_dp *intel_dp)
DP &= ~DP_PORT_EN;
I915_WRITE(intel_dp->output_reg, DP);
POSTING_READ(intel_dp->output_reg);
+
+ intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
}
msleep(intel_dp->panel_power_down_delay);
+
+ intel_dp->DP = DP;
}
static bool
@@ -4013,7 +3892,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
}
DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n",
- yesno(intel_dp_source_supports_hbr2(dev)),
+ yesno(intel_dp_source_supports_hbr2(intel_dp)),
yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
/* Intermediate frequency support */
@@ -4103,9 +3982,12 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
u8 buf;
int ret = 0;
+ int count = 0;
+ int attempts = 10;
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
@@ -4120,7 +4002,22 @@ static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
goto out;
}
- intel_dp->sink_crc.started = false;
+ do {
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+ if (drm_dp_dpcd_readb(&intel_dp->aux,
+ DP_TEST_SINK_MISC, &buf) < 0) {
+ ret = -EIO;
+ goto out;
+ }
+ count = buf & DP_TEST_COUNT_MASK;
+ } while (--attempts && count);
+
+ if (attempts == 0) {
+ DRM_ERROR("TIMEOUT: Sink CRC counter is not zeroed\n");
+ ret = -ETIMEDOUT;
+ }
+
out:
hsw_enable_ips(intel_crtc);
return ret;
@@ -4129,27 +4026,26 @@ static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
u8 buf;
int ret;
- if (intel_dp->sink_crc.started) {
- ret = intel_dp_sink_crc_stop(intel_dp);
- if (ret)
- return ret;
- }
-
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
return -EIO;
if (!(buf & DP_TEST_CRC_SUPPORTED))
return -ENOTTY;
- intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
-
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
return -EIO;
+ if (buf & DP_TEST_SINK_START) {
+ ret = intel_dp_sink_crc_stop(intel_dp);
+ if (ret)
+ return ret;
+ }
+
hsw_disable_ips(intel_crtc);
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
@@ -4158,7 +4054,7 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
return -EIO;
}
- intel_dp->sink_crc.started = true;
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
return 0;
}
@@ -4170,7 +4066,6 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
u8 buf;
int count, ret;
int attempts = 6;
- bool old_equal_new;
ret = intel_dp_sink_crc_start(intel_dp);
if (ret)
@@ -4186,35 +4081,17 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
}
count = buf & DP_TEST_COUNT_MASK;
- /*
- * Count might be reset during the loop. In this case
- * last known count needs to be reset as well.
- */
- if (count == 0)
- intel_dp->sink_crc.last_count = 0;
-
- if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
- ret = -EIO;
- goto stop;
- }
-
- old_equal_new = (count == intel_dp->sink_crc.last_count &&
- !memcmp(intel_dp->sink_crc.last_crc, crc,
- 6 * sizeof(u8)));
-
- } while (--attempts && (count == 0 || old_equal_new));
-
- intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
- memcpy(intel_dp->sink_crc.last_crc, crc, 6 * sizeof(u8));
+ } while (--attempts && count == 0);
if (attempts == 0) {
- if (old_equal_new) {
- DRM_DEBUG_KMS("Unreliable Sink CRC counter: Current returned CRC is identical to the previous one\n");
- } else {
- DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
- ret = -ETIMEDOUT;
- goto stop;
- }
+ DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
+ ret = -ETIMEDOUT;
+ goto stop;
+ }
+
+ if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
+ ret = -EIO;
+ goto stop;
}
stop:
@@ -4314,13 +4191,6 @@ static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
uint8_t rxdata = 0;
int status = 0;
- intel_dp->compliance_test_active = 0;
- intel_dp->compliance_test_type = 0;
- intel_dp->compliance_test_data = 0;
-
- intel_dp->aux.i2c_nack_count = 0;
- intel_dp->aux.i2c_defer_count = 0;
-
status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_REQUEST, &rxdata, 1);
if (status <= 0) {
DRM_DEBUG_KMS("Could not read test request from sink\n");
@@ -4436,6 +4306,14 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+ /*
+ * Clearing compliance test variables to allow capturing
+ * of values for next automated test request.
+ */
+ intel_dp->compliance_test_active = 0;
+ intel_dp->compliance_test_type = 0;
+ intel_dp->compliance_test_data = 0;
+
if (!intel_encoder->base.crtc)
return;
@@ -4466,7 +4344,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
}
- if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
+ /* if link training is requested we should perform it always */
+ if ((intel_dp->compliance_test_type == DP_TEST_LINK_TRAINING) ||
+ (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count))) {
DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
intel_encoder->base.name);
intel_dp_start_link_train(intel_dp);
@@ -4678,47 +4558,12 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
return cpt_digital_port_connected(dev_priv, port);
else if (IS_BROXTON(dev_priv))
return bxt_digital_port_connected(dev_priv, port);
- else if (IS_VALLEYVIEW(dev_priv))
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
return vlv_digital_port_connected(dev_priv, port);
else
return g4x_digital_port_connected(dev_priv, port);
}
-static enum drm_connector_status
-ironlake_dp_detect(struct intel_dp *intel_dp)
-{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-
- if (!intel_digital_port_connected(dev_priv, intel_dig_port))
- return connector_status_disconnected;
-
- return intel_dp_detect_dpcd(intel_dp);
-}
-
-static enum drm_connector_status
-g4x_dp_detect(struct intel_dp *intel_dp)
-{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
- struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-
- /* Can't disconnect eDP, but you can close the lid... */
- if (is_edp(intel_dp)) {
- enum drm_connector_status status;
-
- status = intel_panel_detect(dev);
- if (status == connector_status_unknown)
- status = connector_status_connected;
- return status;
- }
-
- if (!intel_digital_port_connected(dev->dev_private, intel_dig_port))
- return connector_status_disconnected;
-
- return intel_dp_detect_dpcd(intel_dp);
-}
-
static struct edid *
intel_dp_get_edid(struct intel_dp *intel_dp)
{
@@ -4791,12 +4636,19 @@ intel_dp_detect(struct drm_connector *connector, bool force)
/* Can't disconnect eDP, but you can close the lid... */
if (is_edp(intel_dp))
status = edp_detect(intel_dp);
- else if (HAS_PCH_SPLIT(dev))
- status = ironlake_dp_detect(intel_dp);
+ else if (intel_digital_port_connected(to_i915(dev),
+ dp_to_dig_port(intel_dp)))
+ status = intel_dp_detect_dpcd(intel_dp);
else
- status = g4x_dp_detect(intel_dp);
- if (status != connector_status_connected)
+ status = connector_status_disconnected;
+
+ if (status != connector_status_connected) {
+ intel_dp->compliance_test_active = 0;
+ intel_dp->compliance_test_type = 0;
+ intel_dp->compliance_test_data = 0;
+
goto out;
+ }
intel_dp_probe_oui(intel_dp);
@@ -4810,6 +4662,14 @@ intel_dp_detect(struct drm_connector *connector, bool force)
goto out;
}
+ /*
+ * Clearing NACK and defer counts to get their exact values
+ * while reading EDID which are required by Compliance tests
+ * 4.2.2.4 and 4.2.2.5
+ */
+ intel_dp->aux.i2c_nack_count = 0;
+ intel_dp->aux.i2c_defer_count = 0;
+
intel_dp_set_edid(intel_dp);
if (intel_encoder->type != INTEL_OUTPUT_EDP)
@@ -5014,7 +4874,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &intel_dig_port->dp;
- drm_dp_aux_unregister(&intel_dp->aux);
+ intel_dp_aux_fini(intel_dp);
intel_dp_mst_encoder_cleanup(intel_dig_port);
if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
@@ -5092,7 +4952,7 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
* Read out the current power sequencer assignment,
* in case the BIOS did something with it.
*/
- if (IS_VALLEYVIEW(encoder->dev))
+ if (IS_VALLEYVIEW(encoder->dev) || IS_CHERRYVIEW(encoder->dev))
vlv_initial_power_sequencer_setup(intel_dp);
intel_edp_panel_vdd_sanitize(intel_dp);
@@ -5204,25 +5064,6 @@ put_power:
return ret;
}
-/* Return which DP Port should be selected for Transcoder DP control */
-int
-intel_trans_dp_port_sel(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct intel_encoder *intel_encoder;
- struct intel_dp *intel_dp;
-
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
- intel_dp = enc_to_intel_dp(&intel_encoder->base);
-
- if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
- intel_encoder->type == INTEL_OUTPUT_EDP)
- return intel_dp->output_reg;
- }
-
- return -1;
-}
-
/* check the VBT to see whether the eDP is on another port */
bool intel_dp_is_edp(struct drm_device *dev, enum port port)
{
@@ -5294,7 +5135,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
struct edp_power_seq cur, vbt, spec,
*final = &intel_dp->pps_delays;
u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0;
- int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg = 0;
+ i915_reg_t pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg;
lockdep_assert_held(&dev_priv->pps_mutex);
@@ -5416,7 +5257,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_on, pp_off, pp_div, port_sel = 0;
int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev);
- int pp_on_reg, pp_off_reg, pp_div_reg = 0, pp_ctrl_reg;
+ i915_reg_t pp_on_reg, pp_off_reg, pp_div_reg, pp_ctrl_reg;
enum port port = dp_to_dig_port(intel_dp)->port;
const struct edp_power_seq *seq = &intel_dp->pps_delays;
@@ -5471,7 +5312,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
/* Haswell doesn't have any port selection bits for the panel
* power sequencer any more. */
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
port_sel = PANEL_PORT_SELECT_VLV(port);
} else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
if (port == PORT_A)
@@ -5578,17 +5419,17 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
DRM_ERROR("Unsupported refreshrate type\n");
}
} else if (INTEL_INFO(dev)->gen > 6) {
- u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder);
+ i915_reg_t reg = PIPECONF(intel_crtc->config->cpu_transcoder);
u32 val;
val = I915_READ(reg);
if (index > DRRS_HIGH_RR) {
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
else
val |= PIPECONF_EDP_RR_MODE_SWITCH;
} else {
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
else
val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
@@ -5955,7 +5796,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
}
mutex_unlock(&dev->mode_config.mutex);
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
intel_dp->edp_notifier.notifier_call = edp_notify_handler;
register_reboot_notifier(&intel_dp->edp_notifier);
@@ -5996,14 +5837,14 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum port port = intel_dig_port->port;
- int type;
+ int type, ret;
intel_dp->pps_pipe = INVALID_PIPE;
/* intel_dp vfuncs */
if (INTEL_INFO(dev)->gen >= 9)
intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
- else if (IS_VALLEYVIEW(dev))
+ else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider;
else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
@@ -6017,6 +5858,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
else
intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
+ if (HAS_DDI(dev))
+ intel_dp->prepare_link_retrain = intel_ddi_prepare_link_retrain;
+
/* Preserve the current hw state. */
intel_dp->DP = I915_READ(intel_dp->output_reg);
intel_dp->attached_connector = intel_connector;
@@ -6035,8 +5879,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_encoder->type = INTEL_OUTPUT_EDP;
/* eDP only on port B and/or C on vlv/chv */
- if (WARN_ON(IS_VALLEYVIEW(dev) && is_edp(intel_dp) &&
- port != PORT_B && port != PORT_C))
+ if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
+ is_edp(intel_dp) && port != PORT_B && port != PORT_C))
return false;
DRM_DEBUG_KMS("Adding %s connector on port %c\n",
@@ -6068,7 +5912,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
break;
case PORT_B:
intel_encoder->hpd_pin = HPD_PORT_B;
- if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0))
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
intel_encoder->hpd_pin = HPD_PORT_A;
break;
case PORT_C:
@@ -6087,14 +5931,16 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
if (is_edp(intel_dp)) {
pps_lock(intel_dp);
intel_dp_init_panel_power_timestamps(intel_dp);
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_initial_power_sequencer_setup(intel_dp);
else
intel_dp_init_panel_power_sequencer(dev, intel_dp);
pps_unlock(intel_dp);
}
- intel_dp_aux_init(intel_dp, intel_connector);
+ ret = intel_dp_aux_init(intel_dp, intel_connector);
+ if (ret)
+ goto fail;
/* init MST on ports that can support it */
if (HAS_DP_MST(dev) &&
@@ -6103,20 +5949,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_connector->base.base.id);
if (!intel_edp_init_connector(intel_dp, intel_connector)) {
- drm_dp_aux_unregister(&intel_dp->aux);
- if (is_edp(intel_dp)) {
- cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
- /*
- * vdd might still be enabled do to the delayed vdd off.
- * Make sure vdd is actually turned off here.
- */
- pps_lock(intel_dp);
- edp_panel_vdd_off_sync(intel_dp);
- pps_unlock(intel_dp);
- }
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- return false;
+ intel_dp_aux_fini(intel_dp);
+ intel_dp_mst_encoder_cleanup(intel_dig_port);
+ goto fail;
}
intel_dp_add_properties(intel_dp, connector);
@@ -6133,10 +5968,27 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
i915_debugfs_connector_add(connector);
return true;
+
+fail:
+ if (is_edp(intel_dp)) {
+ cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+ /*
+ * vdd might still be enabled do to the delayed vdd off.
+ * Make sure vdd is actually turned off here.
+ */
+ pps_lock(intel_dp);
+ edp_panel_vdd_off_sync(intel_dp);
+ pps_unlock(intel_dp);
+ }
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+
+ return false;
}
void
-intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
+intel_dp_init(struct drm_device *dev,
+ i915_reg_t output_reg, enum port port)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_digital_port *intel_dig_port;
@@ -6155,8 +6007,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_encoder = &intel_dig_port->base;
encoder = &intel_encoder->base;
- drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
- DRM_MODE_ENCODER_TMDS);
+ if (drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL))
+ goto err_encoder_init;
intel_encoder->compute_config = intel_dp_compute_config;
intel_encoder->disable = intel_disable_dp;
@@ -6182,6 +6035,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
}
intel_dig_port->port = port;
+ dev_priv->dig_port_map[port] = intel_encoder;
intel_dig_port->dp.output_reg = output_reg;
intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
@@ -6205,6 +6059,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
err_init_connector:
drm_encoder_cleanup(encoder);
+err_encoder_init:
kfree(intel_connector);
err_connector_alloc:
kfree(intel_dig_port);
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
new file mode 100644
index 000000000000..88887938e0bf
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright © 2008-2015 Intel Corporation
+ *
+ * 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 "intel_drv.h"
+
+static void
+intel_get_adjust_train(struct intel_dp *intel_dp,
+ const uint8_t link_status[DP_LINK_STATUS_SIZE])
+{
+ uint8_t v = 0;
+ uint8_t p = 0;
+ int lane;
+ uint8_t voltage_max;
+ uint8_t preemph_max;
+
+ for (lane = 0; lane < intel_dp->lane_count; lane++) {
+ uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
+ uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
+
+ if (this_v > v)
+ v = this_v;
+ if (this_p > p)
+ p = this_p;
+ }
+
+ voltage_max = intel_dp_voltage_max(intel_dp);
+ if (v >= voltage_max)
+ v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
+
+ preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
+ if (p >= preemph_max)
+ p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+ for (lane = 0; lane < 4; lane++)
+ intel_dp->train_set[lane] = v | p;
+}
+
+static bool
+intel_dp_set_link_train(struct intel_dp *intel_dp,
+ uint8_t dp_train_pat)
+{
+ uint8_t buf[sizeof(intel_dp->train_set) + 1];
+ int ret, len;
+
+ intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
+
+ buf[0] = dp_train_pat;
+ if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
+ DP_TRAINING_PATTERN_DISABLE) {
+ /* don't write DP_TRAINING_LANEx_SET on disable */
+ len = 1;
+ } else {
+ /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
+ memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
+ len = intel_dp->lane_count + 1;
+ }
+
+ ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
+ buf, len);
+
+ return ret == len;
+}
+
+static bool
+intel_dp_reset_link_train(struct intel_dp *intel_dp,
+ uint8_t dp_train_pat)
+{
+ if (!intel_dp->train_set_valid)
+ memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
+ intel_dp_set_signal_levels(intel_dp);
+ return intel_dp_set_link_train(intel_dp, dp_train_pat);
+}
+
+static bool
+intel_dp_update_link_train(struct intel_dp *intel_dp)
+{
+ int ret;
+
+ intel_dp_set_signal_levels(intel_dp);
+
+ ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
+ intel_dp->train_set, intel_dp->lane_count);
+
+ return ret == intel_dp->lane_count;
+}
+
+/* Enable corresponding port and start training pattern 1 */
+static void
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+{
+ int i;
+ uint8_t voltage;
+ int voltage_tries, loop_tries;
+ uint8_t link_config[2];
+ uint8_t link_bw, rate_select;
+
+ if (intel_dp->prepare_link_retrain)
+ intel_dp->prepare_link_retrain(intel_dp);
+
+ intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
+ &link_bw, &rate_select);
+
+ /* Write the link configuration data */
+ link_config[0] = link_bw;
+ link_config[1] = intel_dp->lane_count;
+ if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+ link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+ drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+ if (intel_dp->num_sink_rates)
+ drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
+ &rate_select, 1);
+
+ link_config[0] = 0;
+ link_config[1] = DP_SET_ANSI_8B10B;
+ drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
+
+ intel_dp->DP |= DP_PORT_EN;
+
+ /* clock recovery */
+ if (!intel_dp_reset_link_train(intel_dp,
+ DP_TRAINING_PATTERN_1 |
+ DP_LINK_SCRAMBLING_DISABLE)) {
+ DRM_ERROR("failed to enable link training\n");
+ return;
+ }
+
+ voltage = 0xff;
+ voltage_tries = 0;
+ loop_tries = 0;
+ for (;;) {
+ uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+ drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+ if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ DRM_ERROR("failed to get link status\n");
+ break;
+ }
+
+ if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+ DRM_DEBUG_KMS("clock recovery OK\n");
+ break;
+ }
+
+ /*
+ * if we used previously trained voltage and pre-emphasis values
+ * and we don't get clock recovery, reset link training values
+ */
+ if (intel_dp->train_set_valid) {
+ DRM_DEBUG_KMS("clock recovery not ok, reset");
+ /* clear the flag as we are not reusing train set */
+ intel_dp->train_set_valid = false;
+ if (!intel_dp_reset_link_train(intel_dp,
+ DP_TRAINING_PATTERN_1 |
+ DP_LINK_SCRAMBLING_DISABLE)) {
+ DRM_ERROR("failed to enable link training\n");
+ return;
+ }
+ continue;
+ }
+
+ /* Check to see if we've tried the max voltage */
+ for (i = 0; i < intel_dp->lane_count; i++)
+ if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+ break;
+ if (i == intel_dp->lane_count) {
+ ++loop_tries;
+ if (loop_tries == 5) {
+ DRM_ERROR("too many full retries, give up\n");
+ break;
+ }
+ intel_dp_reset_link_train(intel_dp,
+ DP_TRAINING_PATTERN_1 |
+ DP_LINK_SCRAMBLING_DISABLE);
+ voltage_tries = 0;
+ continue;
+ }
+
+ /* Check to see if we've tried the same voltage 5 times */
+ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++voltage_tries;
+ if (voltage_tries == 5) {
+ DRM_ERROR("too many voltage retries, give up\n");
+ break;
+ }
+ } else
+ voltage_tries = 0;
+ voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+ /* Update training set as requested by target */
+ intel_get_adjust_train(intel_dp, link_status);
+ if (!intel_dp_update_link_train(intel_dp)) {
+ DRM_ERROR("failed to update link training\n");
+ break;
+ }
+ }
+}
+
+static void
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+{
+ bool channel_eq = false;
+ int tries, cr_tries;
+ uint32_t training_pattern = DP_TRAINING_PATTERN_2;
+
+ /*
+ * Training Pattern 3 for HBR2 or 1.2 devices that support it.
+ *
+ * Intel platforms that support HBR2 also support TPS3. TPS3 support is
+ * also mandatory for downstream devices that support HBR2.
+ *
+ * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
+ * supported but still not enabled.
+ */
+ if (intel_dp_source_supports_hbr2(intel_dp) &&
+ drm_dp_tps3_supported(intel_dp->dpcd))
+ training_pattern = DP_TRAINING_PATTERN_3;
+ else if (intel_dp->link_rate == 540000)
+ DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
+
+ /* channel equalization */
+ if (!intel_dp_set_link_train(intel_dp,
+ training_pattern |
+ DP_LINK_SCRAMBLING_DISABLE)) {
+ DRM_ERROR("failed to start channel equalization\n");
+ return;
+ }
+
+ tries = 0;
+ cr_tries = 0;
+ channel_eq = false;
+ for (;;) {
+ uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+ if (cr_tries > 5) {
+ DRM_ERROR("failed to train DP, aborting\n");
+ break;
+ }
+
+ drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
+ if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ DRM_ERROR("failed to get link status\n");
+ break;
+ }
+
+ /* Make sure clock is still ok */
+ if (!drm_dp_clock_recovery_ok(link_status,
+ intel_dp->lane_count)) {
+ intel_dp->train_set_valid = false;
+ intel_dp_link_training_clock_recovery(intel_dp);
+ intel_dp_set_link_train(intel_dp,
+ training_pattern |
+ DP_LINK_SCRAMBLING_DISABLE);
+ cr_tries++;
+ continue;
+ }
+
+ if (drm_dp_channel_eq_ok(link_status,
+ intel_dp->lane_count)) {
+ channel_eq = true;
+ break;
+ }
+
+ /* Try 5 times, then try clock recovery if that fails */
+ if (tries > 5) {
+ intel_dp->train_set_valid = false;
+ intel_dp_link_training_clock_recovery(intel_dp);
+ intel_dp_set_link_train(intel_dp,
+ training_pattern |
+ DP_LINK_SCRAMBLING_DISABLE);
+ tries = 0;
+ cr_tries++;
+ continue;
+ }
+
+ /* Update training set as requested by target */
+ intel_get_adjust_train(intel_dp, link_status);
+ if (!intel_dp_update_link_train(intel_dp)) {
+ DRM_ERROR("failed to update link training\n");
+ break;
+ }
+ ++tries;
+ }
+
+ intel_dp_set_idle_link_train(intel_dp);
+
+ if (channel_eq) {
+ intel_dp->train_set_valid = true;
+ DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
+ }
+}
+
+void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+{
+ intel_dp_set_link_train(intel_dp,
+ DP_TRAINING_PATTERN_DISABLE);
+}
+
+void
+intel_dp_start_link_train(struct intel_dp *intel_dp)
+{
+ intel_dp_link_training_clock_recovery(intel_dp);
+ intel_dp_link_training_channel_equalization(intel_dp);
+}
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 0639275fc471..fa0dabf578dc 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -78,6 +78,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
return false;
}
+ if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, found->port))
+ pipe_config->has_audio = true;
mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
pipe_config->pbn = mst_pbn;
@@ -102,6 +104,11 @@ static void intel_mst_disable_dp(struct intel_encoder *encoder)
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;
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = encoder->base.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
int ret;
DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
@@ -112,6 +119,10 @@ static void intel_mst_disable_dp(struct intel_encoder *encoder)
if (ret) {
DRM_ERROR("failed to update payload %d\n", ret);
}
+ if (intel_crtc->config->has_audio) {
+ intel_audio_codec_disable(encoder);
+ intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
+ }
}
static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
@@ -173,20 +184,14 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
intel_mst->port = found->port;
if (intel_dp->active_mst_links == 0) {
- enum port port = intel_ddi_get_encoder_port(encoder);
+ intel_ddi_clk_select(encoder, intel_crtc->config);
intel_dp_set_link_params(intel_dp, intel_crtc->config);
- /* FIXME: add support for SKL */
- if (INTEL_INFO(dev)->gen < 9)
- I915_WRITE(PORT_CLK_SEL(port),
- intel_crtc->config->ddi_pll_sel);
-
intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
-
intel_dp_start_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
}
@@ -214,6 +219,7 @@ static void intel_mst_enable_dp(struct intel_encoder *encoder)
struct intel_dp *intel_dp = &intel_dig_port->dp;
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
enum port port = intel_dig_port->port;
int ret;
@@ -226,6 +232,13 @@ static void intel_mst_enable_dp(struct intel_encoder *encoder)
ret = drm_dp_check_act_status(&intel_dp->mst_mgr);
ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr);
+
+ if (crtc->config->has_audio) {
+ DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
+ pipe_name(crtc->pipe));
+ intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
+ intel_audio_codec_enable(encoder);
+ }
}
static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
@@ -251,6 +264,9 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
pipe_config->has_dp_encoder = true;
+ pipe_config->has_audio =
+ intel_ddi_is_audio_enabled(dev_priv, crtc);
+
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (temp & TRANS_DDI_PHSYNC)
flags |= DRM_MODE_FLAG_PHSYNC;
@@ -414,7 +430,10 @@ static void intel_connector_add_to_fbdev(struct intel_connector *connector)
{
#ifdef CONFIG_DRM_FBDEV_EMULATION
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, &connector->base);
+
+ if (dev_priv->fbdev)
+ drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper,
+ &connector->base);
#endif
}
@@ -422,7 +441,10 @@ static void intel_connector_remove_from_fbdev(struct intel_connector *connector)
{
#ifdef CONFIG_DRM_FBDEV_EMULATION
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, &connector->base);
+
+ if (dev_priv->fbdev)
+ drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper,
+ &connector->base);
#endif
}
@@ -512,7 +534,7 @@ static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
drm_kms_helper_hotplug_event(dev);
}
-static struct drm_dp_mst_topology_cbs mst_cbs = {
+static const struct drm_dp_mst_topology_cbs mst_cbs = {
.add_connector = intel_dp_add_mst_connector,
.register_connector = intel_dp_register_mst_connector,
.destroy_connector = intel_dp_destroy_mst_connector,
@@ -536,7 +558,7 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum
intel_mst->primary = intel_dig_port;
drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
- DRM_MODE_ENCODER_DPMST);
+ DRM_MODE_ENCODER_DPMST, NULL);
intel_encoder->type = INTEL_OUTPUT_DP_MST;
intel_encoder->crtc_mask = 0x7;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0d00f07b7163..ea5415851c6e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -123,8 +123,6 @@ struct intel_framebuffer {
struct intel_fbdev {
struct drm_fb_helper helper;
struct intel_framebuffer *fb;
- struct list_head fbdev_list;
- struct drm_display_mode *our_mode;
int preferred_bpp;
};
@@ -250,6 +248,7 @@ struct intel_atomic_state {
unsigned int cdclk;
bool dpll_set;
struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
+ struct intel_wm_config wm_config;
};
struct intel_plane_state {
@@ -280,6 +279,9 @@ struct intel_plane_state {
int scaler_id;
struct drm_intel_sprite_colorkey ckey;
+
+ /* async flip related structures */
+ struct drm_i915_gem_request *wait_req;
};
struct intel_initial_plane_config {
@@ -334,6 +336,21 @@ struct intel_crtc_scaler_state {
/* drm_mode->private_flags */
#define I915_MODE_FLAG_INHERITED 1
+struct intel_pipe_wm {
+ struct intel_wm_level wm[5];
+ uint32_t linetime;
+ bool fbc_wm_enabled;
+ bool pipe_enabled;
+ bool sprites_enabled;
+ bool sprites_scaled;
+};
+
+struct skl_pipe_wm {
+ struct skl_wm_level wm[8];
+ struct skl_wm_level trans_wm;
+ uint32_t linetime;
+};
+
struct intel_crtc_state {
struct drm_crtc_state base;
@@ -348,7 +365,9 @@ struct intel_crtc_state {
#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
unsigned long quirks;
- bool update_pipe;
+ bool update_pipe; /* can a fast modeset be performed? */
+ bool disable_cxsr;
+ bool wm_changed; /* watermarks are updated */
/* Pipe source size (ie. panel fitter input size)
* All planes will be positioned inside this space,
@@ -376,6 +395,9 @@ struct intel_crtc_state {
* accordingly. */
bool has_dp_encoder;
+ /* DSI has special cases */
+ bool has_dsi_encoder;
+
/* Whether we should send NULL infoframes. Required for audio. */
bool has_hdmi_sink;
@@ -468,6 +490,20 @@ struct intel_crtc_state {
/* w/a for waiting 2 vblanks during crtc enable */
enum pipe hsw_workaround_pipe;
+
+ /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */
+ bool disable_lp_wm;
+
+ struct {
+ /*
+ * optimal watermarks, programmed post-vblank when this state
+ * is committed
+ */
+ union {
+ struct intel_pipe_wm ilk;
+ struct skl_pipe_wm skl;
+ } optimal;
+ } wm;
};
struct vlv_wm_state {
@@ -479,26 +515,12 @@ struct vlv_wm_state {
bool cxsr;
};
-struct intel_pipe_wm {
- struct intel_wm_level wm[5];
- uint32_t linetime;
- bool fbc_wm_enabled;
- bool pipe_enabled;
- bool sprites_enabled;
- bool sprites_scaled;
-};
-
struct intel_mmio_flip {
struct work_struct work;
struct drm_i915_private *i915;
struct drm_i915_gem_request *req;
struct intel_crtc *crtc;
-};
-
-struct skl_pipe_wm {
- struct skl_wm_level wm[8];
- struct skl_wm_level trans_wm;
- uint32_t linetime;
+ unsigned int rotation;
};
/*
@@ -509,13 +531,9 @@ struct skl_pipe_wm {
*/
struct intel_crtc_atomic_commit {
/* Sleepable operations to perform before commit */
- bool wait_for_flips;
bool disable_fbc;
bool disable_ips;
- bool disable_cxsr;
bool pre_disable_primary;
- bool update_wm_pre, update_wm_post;
- unsigned disabled_planes;
/* Sleepable operations to perform after commit */
unsigned fb_bits;
@@ -567,9 +585,10 @@ struct intel_crtc {
/* per-pipe watermark state */
struct {
/* watermarks currently being used */
- struct intel_pipe_wm active;
- /* SKL wm values currently in use */
- struct skl_pipe_wm skl_active;
+ union {
+ struct intel_pipe_wm ilk;
+ struct skl_pipe_wm skl;
+ } active;
/* allow CxSR on this pipe */
bool cxsr_allowed;
} wm;
@@ -677,7 +696,7 @@ struct cxsr_latency {
#define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
struct intel_hdmi {
- u32 hdmi_reg;
+ i915_reg_t hdmi_reg;
int ddc_bus;
bool limited_color_range;
bool color_range_auto;
@@ -693,7 +712,8 @@ struct intel_hdmi {
void (*set_infoframes)(struct drm_encoder *encoder,
bool enable,
const struct drm_display_mode *adjusted_mode);
- bool (*infoframe_enabled)(struct drm_encoder *encoder);
+ bool (*infoframe_enabled)(struct drm_encoder *encoder,
+ const struct intel_crtc_state *pipe_config);
};
struct intel_dp_mst_encoder;
@@ -719,15 +739,10 @@ enum link_m_n_set {
M2_N2
};
-struct sink_crc {
- bool started;
- u8 last_crc[6];
- int last_count;
-};
-
struct intel_dp {
- uint32_t output_reg;
- uint32_t aux_ch_ctl_reg;
+ i915_reg_t output_reg;
+ i915_reg_t aux_ch_ctl_reg;
+ i915_reg_t aux_ch_data_reg[5];
uint32_t DP;
int link_rate;
uint8_t lane_count;
@@ -741,7 +756,6 @@ struct intel_dp {
/* sink rates as reported by DP_SUPPORTED_LINK_RATES */
uint8_t num_sink_rates;
int sink_rates[DP_MAX_SUPPORTED_RATES];
- struct sink_crc sink_crc;
struct drm_dp_aux aux;
uint8_t train_set[4];
int panel_power_up_delay;
@@ -783,6 +797,10 @@ struct intel_dp {
bool has_aux_irq,
int send_bytes,
uint32_t aux_clock_divider);
+
+ /* This is called before a link training is starterd */
+ void (*prepare_link_retrain)(struct intel_dp *intel_dp);
+
bool train_set_valid;
/* Displayport compliance testing */
@@ -799,6 +817,8 @@ struct intel_digital_port {
struct intel_hdmi hdmi;
enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
bool release_cl2_override;
+ /* for communication with audio component; protected by av_mutex */
+ const struct drm_connector *audio_connector;
};
struct intel_dp_mst_encoder {
@@ -942,7 +962,8 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum pipe pipe);
void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum transcoder pch_transcoder);
-void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv);
+void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv);
+void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv);
/* i915_irq.c */
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
@@ -973,6 +994,8 @@ void intel_crt_init(struct drm_device *dev);
/* intel_ddi.c */
+void intel_ddi_clk_select(struct intel_encoder *encoder,
+ const struct intel_crtc_state *pipe_config);
void intel_prepare_ddi(struct drm_device *dev);
void hsw_fdi_link_train(struct drm_crtc *crtc);
void intel_ddi_init(struct drm_device *dev, enum port port);
@@ -987,9 +1010,11 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc);
bool intel_ddi_pll_select(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state);
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
-void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
+void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp);
bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
void intel_ddi_fdi_disable(struct drm_crtc *crtc);
+bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
+ struct intel_crtc *intel_crtc);
void intel_ddi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config);
struct intel_encoder *
@@ -1055,6 +1080,15 @@ intel_wait_for_vblank(struct drm_device *dev, int pipe)
{
drm_wait_one_vblank(dev, pipe);
}
+static inline void
+intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
+{
+ const struct intel_crtc *crtc =
+ to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
+
+ if (crtc->active)
+ intel_wait_for_vblank(dev, pipe);
+}
int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
struct intel_digital_port *dport,
@@ -1068,9 +1102,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx);
int intel_pin_and_fence_fb_obj(struct drm_plane *plane,
struct drm_framebuffer *fb,
- const struct drm_plane_state *plane_state,
- struct intel_engine_cs *pipelined,
- struct drm_i915_gem_request **pipelined_request);
+ const struct drm_plane_state *plane_state);
struct drm_framebuffer *
__intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
@@ -1151,7 +1183,10 @@ void broxton_ddi_phy_uninit(struct drm_device *dev);
void bxt_enable_dc9(struct drm_i915_private *dev_priv);
void bxt_disable_dc9(struct drm_i915_private *dev_priv);
void skl_init_cdclk(struct drm_i915_private *dev_priv);
+int skl_sanitize_cdclk(struct drm_i915_private *dev_priv);
void skl_uninit_cdclk(struct drm_i915_private *dev_priv);
+void skl_enable_dc6(struct drm_i915_private *dev_priv);
+void skl_disable_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);
@@ -1172,31 +1207,26 @@ enum intel_display_power_domain
intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder);
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
struct intel_crtc_state *pipe_config);
-void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
- struct drm_i915_gem_object *obj,
- unsigned int plane);
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+ struct drm_i915_gem_object *obj,
+ unsigned int plane);
u32 skl_plane_ctl_format(uint32_t pixel_format);
u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
u32 skl_plane_ctl_rotation(unsigned int rotation);
/* intel_csr.c */
-void intel_csr_ucode_init(struct drm_device *dev);
-enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv);
-void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
- enum csr_state state);
-void intel_csr_load_program(struct drm_device *dev);
-void intel_csr_ucode_fini(struct drm_device *dev);
-void assert_csr_loaded(struct drm_i915_private *dev_priv);
+void intel_csr_ucode_init(struct drm_i915_private *);
+void intel_csr_load_program(struct drm_i915_private *);
+void intel_csr_ucode_fini(struct drm_i915_private *);
/* intel_dp.c */
-void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
+void intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port);
bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
void intel_dp_set_link_params(struct intel_dp *intel_dp,
@@ -1234,6 +1264,22 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
struct intel_digital_port *port);
void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+ uint8_t dp_train_pat);
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp);
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
+uint8_t
+intel_dp_voltage_max(struct intel_dp *intel_dp);
+uint8_t
+intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing);
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+ uint8_t *link_bw, uint8_t *rate_select);
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
+bool
+intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]);
+
/* intel_dp_mst.c */
int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
@@ -1248,7 +1294,7 @@ void intel_dvo_init(struct drm_device *dev);
/* legacy fbdev emulation in intel_fbdev.c */
#ifdef CONFIG_DRM_FBDEV_EMULATION
extern int intel_fbdev_init(struct drm_device *dev);
-extern void intel_fbdev_initial_config(void *data, async_cookie_t cookie);
+extern void intel_fbdev_initial_config_async(struct drm_device *dev);
extern void intel_fbdev_fini(struct drm_device *dev);
extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
@@ -1259,7 +1305,7 @@ static inline int intel_fbdev_init(struct drm_device *dev)
return 0;
}
-static inline void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
+static inline void intel_fbdev_initial_config_async(struct drm_device *dev)
{
}
@@ -1277,9 +1323,11 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)
#endif
/* intel_fbc.c */
-bool intel_fbc_enabled(struct drm_i915_private *dev_priv);
-void intel_fbc_update(struct drm_i915_private *dev_priv);
+bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
+void intel_fbc_deactivate(struct intel_crtc *crtc);
+void intel_fbc_update(struct intel_crtc *crtc);
void intel_fbc_init(struct drm_i915_private *dev_priv);
+void intel_fbc_enable(struct intel_crtc *crtc);
void intel_fbc_disable(struct drm_i915_private *dev_priv);
void intel_fbc_disable_crtc(struct intel_crtc *crtc);
void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
@@ -1287,11 +1335,10 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
enum fb_op_origin origin);
void intel_fbc_flush(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits, enum fb_op_origin origin);
-const char *intel_no_fbc_reason_str(enum no_fbc_reason reason);
void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv);
/* intel_hdmi.c */
-void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
+void intel_hdmi_init(struct drm_device *dev, i915_reg_t hdmi_reg, enum port port);
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
@@ -1367,8 +1414,13 @@ void intel_psr_single_frame_update(struct drm_device *dev,
/* intel_runtime_pm.c */
int intel_power_domains_init(struct drm_i915_private *);
void intel_power_domains_fini(struct drm_i915_private *);
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume);
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv);
+void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv);
+void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv);
void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);
+const char *
+intel_display_power_domain_str(enum intel_display_power_domain domain);
bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
@@ -1378,6 +1430,89 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
void intel_display_power_put(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
+
+static inline void
+assert_rpm_device_not_suspended(struct drm_i915_private *dev_priv)
+{
+ WARN_ONCE(dev_priv->pm.suspended,
+ "Device suspended during HW access\n");
+}
+
+static inline void
+assert_rpm_wakelock_held(struct drm_i915_private *dev_priv)
+{
+ assert_rpm_device_not_suspended(dev_priv);
+ /* FIXME: Needs to be converted back to WARN_ONCE, but currently causes
+ * too much noise. */
+ if (!atomic_read(&dev_priv->pm.wakeref_count))
+ DRM_DEBUG_DRIVER("RPM wakelock ref not held during HW access");
+}
+
+static inline int
+assert_rpm_atomic_begin(struct drm_i915_private *dev_priv)
+{
+ int seq = atomic_read(&dev_priv->pm.atomic_seq);
+
+ assert_rpm_wakelock_held(dev_priv);
+
+ return seq;
+}
+
+static inline void
+assert_rpm_atomic_end(struct drm_i915_private *dev_priv, int begin_seq)
+{
+ WARN_ONCE(atomic_read(&dev_priv->pm.atomic_seq) != begin_seq,
+ "HW access outside of RPM atomic section\n");
+}
+
+/**
+ * disable_rpm_wakeref_asserts - disable the RPM assert checks
+ * @dev_priv: i915 device instance
+ *
+ * This function disable asserts that check if we hold an RPM wakelock
+ * reference, while keeping the device-not-suspended checks still enabled.
+ * It's meant to be used only in special circumstances where our rule about
+ * the wakelock refcount wrt. the device power state doesn't hold. According
+ * to this rule at any point where we access the HW or want to keep the HW in
+ * an active state we must hold an RPM wakelock reference acquired via one of
+ * the intel_runtime_pm_get() helpers. Currently there are a few special spots
+ * where this rule doesn't hold: the IRQ and suspend/resume handlers, the
+ * forcewake release timer, and the GPU RPS and hangcheck works. All other
+ * users should avoid using this function.
+ *
+ * Any calls to this function must have a symmetric call to
+ * enable_rpm_wakeref_asserts().
+ */
+static inline void
+disable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv)
+{
+ atomic_inc(&dev_priv->pm.wakeref_count);
+}
+
+/**
+ * enable_rpm_wakeref_asserts - re-enable the RPM assert checks
+ * @dev_priv: i915 device instance
+ *
+ * This function re-enables the RPM assert checks after disabling them with
+ * disable_rpm_wakeref_asserts. It's meant to be used only in special
+ * circumstances otherwise its use should be avoided.
+ *
+ * Any calls to this function must have a symmetric call to
+ * disable_rpm_wakeref_asserts().
+ */
+static inline void
+enable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv)
+{
+ atomic_dec(&dev_priv->pm.wakeref_count);
+}
+
+/* TODO: convert users of these to rely instead on proper RPM refcounting */
+#define DISABLE_RPM_WAKEREF_ASSERTS(dev_priv) \
+ disable_rpm_wakeref_asserts(dev_priv)
+
+#define ENABLE_RPM_WAKEREF_ASSERTS(dev_priv) \
+ enable_rpm_wakeref_asserts(dev_priv)
+
void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
@@ -1395,12 +1530,6 @@ void intel_init_clock_gating(struct drm_device *dev);
void intel_suspend_hw(struct drm_device *dev);
int ilk_wm_max_level(const struct drm_device *dev);
void intel_update_watermarks(struct drm_crtc *crtc);
-void intel_update_sprite_watermarks(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width,
- uint32_t sprite_height,
- int pixel_size,
- bool enabled, bool scaled);
void intel_init_pm(struct drm_device *dev);
void intel_pm_setup(struct drm_device *dev);
void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
@@ -1428,7 +1557,8 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
/* intel_sdvo.c */
-bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob);
+bool intel_sdvo_init(struct drm_device *dev,
+ i915_reg_t reg, enum port port);
/* intel_sprite.c */
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 170ae6f4866e..44742fa2f616 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -60,7 +60,8 @@ static void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
DRM_ERROR("DPI FIFOs are not empty\n");
}
-static void write_data(struct drm_i915_private *dev_priv, u32 reg,
+static void write_data(struct drm_i915_private *dev_priv,
+ i915_reg_t reg,
const u8 *data, u32 len)
{
u32 i, j;
@@ -75,7 +76,8 @@ static void write_data(struct drm_i915_private *dev_priv, u32 reg,
}
}
-static void read_data(struct drm_i915_private *dev_priv, u32 reg,
+static void read_data(struct drm_i915_private *dev_priv,
+ i915_reg_t reg,
u8 *data, u32 len)
{
u32 i, j;
@@ -98,7 +100,8 @@ static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host,
struct mipi_dsi_packet packet;
ssize_t ret;
const u8 *header, *data;
- u32 data_reg, data_mask, ctrl_reg, ctrl_mask;
+ i915_reg_t data_reg, ctrl_reg;
+ u32 data_mask, ctrl_mask;
ret = mipi_dsi_create_packet(&packet, msg);
if (ret < 0)
@@ -263,16 +266,18 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
}
static bool intel_dsi_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_state *config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
base);
struct intel_connector *intel_connector = intel_dsi->attached_connector;
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
- struct drm_display_mode *adjusted_mode = &config->base.adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
DRM_DEBUG_KMS("\n");
+ pipe_config->has_dsi_encoder = true;
+
if (fixed_mode)
intel_fixed_panel_mode(fixed_mode, adjusted_mode);
@@ -364,7 +369,7 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_dsi_device_ready(encoder);
else if (IS_BROXTON(dev))
bxt_dsi_device_ready(encoder);
@@ -377,10 +382,10 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder)
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
- u32 temp;
- u32 port_ctrl;
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+ u32 temp;
+
temp = I915_READ(VLV_CHICKEN_3);
temp &= ~PIXEL_OVERLAP_CNT_MASK |
intel_dsi->pixel_overlap <<
@@ -389,8 +394,9 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder)
}
for_each_dsi_port(port, intel_dsi->ports) {
- port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
- MIPI_PORT_CTRL(port);
+ i915_reg_t port_ctrl = IS_BROXTON(dev) ?
+ BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+ u32 temp;
temp = I915_READ(port_ctrl);
@@ -416,13 +422,13 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
- u32 temp;
- u32 port_ctrl;
for_each_dsi_port(port, intel_dsi->ports) {
+ i915_reg_t port_ctrl = IS_BROXTON(dev) ?
+ BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+ u32 temp;
+
/* de-assert ip_tg_enable signal */
- port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
- MIPI_PORT_CTRL(port);
temp = I915_READ(port_ctrl);
I915_WRITE(port_ctrl, temp & ~DPI_ENABLE);
POSTING_READ(port_ctrl);
@@ -458,6 +464,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
intel_panel_enable_backlight(intel_dsi->attached_connector);
}
+static void intel_dsi_prepare(struct intel_encoder *intel_encoder);
+
static void intel_dsi_pre_enable(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
@@ -470,13 +478,16 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
DRM_DEBUG_KMS("\n");
+ intel_dsi_prepare(encoder);
+ intel_enable_dsi_pll(encoder);
+
/* Panel Enable over CRC PMIC */
if (intel_dsi->gpio_panel)
gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
msleep(intel_dsi->panel_on_delay);
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
/*
* Disable DPOunit clock gating, can stall pipe
* and we need DPLL REFA always enabled
@@ -580,11 +591,13 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
- u32 val;
- u32 port_ctrl = 0;
DRM_DEBUG_KMS("\n");
for_each_dsi_port(port, intel_dsi->ports) {
+ /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */
+ i915_reg_t port_ctrl = IS_BROXTON(dev) ?
+ BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A);
+ u32 val;
I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
ULPS_STATE_ENTER);
@@ -598,12 +611,6 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
ULPS_STATE_ENTER);
usleep_range(2000, 2500);
- if (IS_BROXTON(dev))
- port_ctrl = BXT_MIPI_PORT_CTRL(port);
- else if (IS_VALLEYVIEW(dev))
- /* Common bit for both MIPI Port A & MIPI Port C */
- port_ctrl = MIPI_PORT_CTRL(PORT_A);
-
/* Wait till Clock lanes are in LP-00 state for MIPI Port A
* only. MIPI Port C has no similar bit for checking
*/
@@ -656,7 +663,6 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
struct drm_device *dev = encoder->base.dev;
enum intel_display_power_domain power_domain;
- u32 dpi_enabled, func, ctrl_reg;
enum port port;
DRM_DEBUG_KMS("\n");
@@ -667,17 +673,18 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
/* XXX: this only works for one DSI output */
for_each_dsi_port(port, intel_dsi->ports) {
+ i915_reg_t ctrl_reg = IS_BROXTON(dev) ?
+ BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+ u32 dpi_enabled, func;
+
func = I915_READ(MIPI_DSI_FUNC_PRG(port));
- ctrl_reg = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
- MIPI_PORT_CTRL(port);
dpi_enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
/* Due to some hardware limitations on BYT, MIPI Port C DPI
* Enable bit does not get set. To check whether DSI Port C
* was enabled in BIOS, check the Pipe B enable bit
*/
- if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
- (port == PORT_C))
+ if (IS_VALLEYVIEW(dev) && port == PORT_C)
dpi_enabled = I915_READ(PIPECONF(PIPE_B)) &
PIPECONF_ENABLE;
@@ -698,6 +705,8 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
u32 pclk = 0;
DRM_DEBUG_KMS("\n");
+ pipe_config->has_dsi_encoder = true;
+
/*
* DPLL_MD is not used in case of DSI, reading will get some default value
* set dpll_md = 0
@@ -706,7 +715,8 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
if (IS_BROXTON(encoder->base.dev))
pclk = bxt_get_dsi_pclk(encoder, pipe_config->pipe_bpp);
- else if (IS_VALLEYVIEW(encoder->base.dev))
+ else if (IS_VALLEYVIEW(encoder->base.dev) ||
+ IS_CHERRYVIEW(encoder->base.dev))
pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp);
if (!pclk)
@@ -859,7 +869,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
}
for_each_dsi_port(port, intel_dsi->ports) {
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
/*
* escape clock divider, 20MHz, shared for A and C.
* device ready must be off when doing this! txclkesc?
@@ -875,21 +885,12 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
I915_WRITE(MIPI_CTRL(port), tmp |
READ_REQUEST_PRIORITY_HIGH);
} else if (IS_BROXTON(dev)) {
- /*
- * FIXME:
- * BXT can connect any PIPE to any MIPI port.
- * Select the pipe based on the MIPI port read from
- * VBT for now. Pick PIPE A for MIPI port A and C
- * for port C.
- */
+ enum pipe pipe = intel_crtc->pipe;
+
tmp = I915_READ(MIPI_CTRL(port));
tmp &= ~BXT_PIPE_SELECT_MASK;
- if (port == PORT_A)
- tmp |= BXT_PIPE_SELECT_A;
- else if (port == PORT_C)
- tmp |= BXT_PIPE_SELECT_C;
-
+ tmp |= BXT_PIPE_SELECT(pipe);
I915_WRITE(MIPI_CTRL(port), tmp);
}
@@ -1025,15 +1026,6 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
}
}
-static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
-{
- DRM_DEBUG_KMS("\n");
-
- intel_dsi_prepare(encoder);
- intel_enable_dsi_pll(encoder);
-
-}
-
static enum drm_connector_status
intel_dsi_detect(struct drm_connector *connector, bool force)
{
@@ -1128,7 +1120,7 @@ void intel_dsi_init(struct drm_device *dev)
if (!dev_priv->vbt.has_mipi)
return;
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
dev_priv->mipi_mmio_base = VLV_MIPI_BASE;
} else {
DRM_ERROR("Unsupported Mipi device to reg base");
@@ -1151,11 +1143,10 @@ void intel_dsi_init(struct drm_device *dev)
connector = &intel_connector->base;
- drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI);
+ drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
+ NULL);
- /* XXX: very likely not all of these are needed */
intel_encoder->compute_config = intel_dsi_compute_config;
- intel_encoder->pre_pll_enable = intel_dsi_pre_pll_enable;
intel_encoder->pre_enable = intel_dsi_pre_enable;
intel_encoder->enable = intel_dsi_enable_nop;
intel_encoder->disable = intel_dsi_pre_disable;
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index e6cb25239941..02551ff228c2 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -117,7 +117,7 @@ static inline struct intel_dsi_host *to_intel_dsi_host(struct mipi_dsi_host *h)
#define for_each_dsi_port(__port, __ports_mask) \
for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++) \
- if ((__ports_mask) & (1 << (__port)))
+ for_each_if ((__ports_mask) & (1 << (__port)))
static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
{
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index cb3cf3986212..fbd2b51810ca 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -561,7 +561,7 @@ void intel_enable_dsi_pll(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_enable_dsi_pll(encoder);
else if (IS_BROXTON(dev))
bxt_enable_dsi_pll(encoder);
@@ -571,7 +571,7 @@ void intel_disable_dsi_pll(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_disable_dsi_pll(encoder);
else if (IS_BROXTON(dev))
bxt_disable_dsi_pll(encoder);
@@ -599,6 +599,6 @@ void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
if (IS_BROXTON(dev))
bxt_dsi_reset_clocks(encoder, port);
- else if (IS_VALLEYVIEW(dev))
+ else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_dsi_reset_clocks(encoder, port);
}
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 8492053e0ff0..286baec979c8 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -44,6 +44,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_TMDS,
.name = "sil164",
.dvo_reg = DVOC,
+ .dvo_srcdim_reg = DVOC_SRCDIM,
.slave_addr = SIL164_ADDR,
.dev_ops = &sil164_ops,
},
@@ -51,6 +52,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_TMDS,
.name = "ch7xxx",
.dvo_reg = DVOC,
+ .dvo_srcdim_reg = DVOC_SRCDIM,
.slave_addr = CH7xxx_ADDR,
.dev_ops = &ch7xxx_ops,
},
@@ -58,6 +60,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_TMDS,
.name = "ch7xxx",
.dvo_reg = DVOC,
+ .dvo_srcdim_reg = DVOC_SRCDIM,
.slave_addr = 0x75, /* For some ch7010 */
.dev_ops = &ch7xxx_ops,
},
@@ -65,6 +68,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_LVDS,
.name = "ivch",
.dvo_reg = DVOA,
+ .dvo_srcdim_reg = DVOA_SRCDIM,
.slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
.dev_ops = &ivch_ops,
},
@@ -72,6 +76,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_TMDS,
.name = "tfp410",
.dvo_reg = DVOC,
+ .dvo_srcdim_reg = DVOC_SRCDIM,
.slave_addr = TFP410_ADDR,
.dev_ops = &tfp410_ops,
},
@@ -79,6 +84,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_LVDS,
.name = "ch7017",
.dvo_reg = DVOC,
+ .dvo_srcdim_reg = DVOC_SRCDIM,
.slave_addr = 0x75,
.gpio = GMBUS_PIN_DPB,
.dev_ops = &ch7017_ops,
@@ -87,6 +93,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.type = INTEL_DVO_CHIP_TMDS,
.name = "ns2501",
.dvo_reg = DVOB,
+ .dvo_srcdim_reg = DVOB_SRCDIM,
.slave_addr = NS2501_ADDR,
.dev_ops = &ns2501_ops,
}
@@ -171,7 +178,7 @@ static void intel_disable_dvo(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
- u32 dvo_reg = intel_dvo->dev.dvo_reg;
+ i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
u32 temp = I915_READ(dvo_reg);
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
@@ -184,7 +191,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- u32 dvo_reg = intel_dvo->dev.dvo_reg;
+ i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
u32 temp = I915_READ(dvo_reg);
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
@@ -255,20 +262,8 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder)
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
int pipe = crtc->pipe;
u32 dvo_val;
- u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg;
-
- switch (dvo_reg) {
- case DVOA:
- default:
- dvo_srcdim_reg = DVOA_SRCDIM;
- break;
- case DVOB:
- dvo_srcdim_reg = DVOB_SRCDIM;
- break;
- case DVOC:
- dvo_srcdim_reg = DVOC_SRCDIM;
- break;
- }
+ i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
+ i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg;
/* Save the data order, since I don't know what it should be set to. */
dvo_val = I915_READ(dvo_reg) &
@@ -434,7 +429,7 @@ void intel_dvo_init(struct drm_device *dev)
intel_encoder = &intel_dvo->base;
drm_encoder_init(dev, &intel_encoder->base,
- &intel_dvo_enc_funcs, encoder_type);
+ &intel_dvo_enc_funcs, encoder_type, NULL);
intel_encoder->disable = intel_disable_dvo;
intel_encoder->enable = intel_enable_dvo;
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index cf47352b7b8e..a1988a486b92 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -43,7 +43,17 @@
static inline bool fbc_supported(struct drm_i915_private *dev_priv)
{
- return dev_priv->fbc.enable_fbc != NULL;
+ return dev_priv->fbc.activate != NULL;
+}
+
+static inline bool fbc_on_pipe_a_only(struct drm_i915_private *dev_priv)
+{
+ return IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8;
+}
+
+static inline bool fbc_on_plane_a_only(struct drm_i915_private *dev_priv)
+{
+ return INTEL_INFO(dev_priv)->gen < 4;
}
/*
@@ -59,11 +69,51 @@ static unsigned int get_crtc_fence_y_offset(struct intel_crtc *crtc)
return crtc->base.y - crtc->adjusted_y;
}
-static void i8xx_fbc_disable(struct drm_i915_private *dev_priv)
+/*
+ * For SKL+, the plane source size used by the hardware is based on the value we
+ * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value
+ * we wrote to PIPESRC.
+ */
+static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc,
+ int *width, int *height)
+{
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(crtc->base.primary->state);
+ int w, h;
+
+ if (intel_rotation_90_or_270(plane_state->base.rotation)) {
+ w = drm_rect_height(&plane_state->src) >> 16;
+ h = drm_rect_width(&plane_state->src) >> 16;
+ } else {
+ w = drm_rect_width(&plane_state->src) >> 16;
+ h = drm_rect_height(&plane_state->src) >> 16;
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+}
+
+static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc,
+ struct drm_framebuffer *fb)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ int lines;
+
+ intel_fbc_get_plane_source_size(crtc, NULL, &lines);
+ if (INTEL_INFO(dev_priv)->gen >= 7)
+ lines = min(lines, 2048);
+
+ /* Hardware needs the full buffer stride, not just the active area. */
+ return lines * fb->pitches[0];
+}
+
+static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv)
{
u32 fbc_ctl;
- dev_priv->fbc.enabled = false;
+ dev_priv->fbc.active = false;
/* Disable compression */
fbc_ctl = I915_READ(FBC_CONTROL);
@@ -78,11 +128,9 @@ static void i8xx_fbc_disable(struct drm_i915_private *dev_priv)
DRM_DEBUG_KMS("FBC idle timed out\n");
return;
}
-
- DRM_DEBUG_KMS("disabled FBC\n");
}
-static void i8xx_fbc_enable(struct intel_crtc *crtc)
+static void i8xx_fbc_activate(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct drm_framebuffer *fb = crtc->base.primary->fb;
@@ -91,10 +139,10 @@ static void i8xx_fbc_enable(struct intel_crtc *crtc)
int i;
u32 fbc_ctl;
- dev_priv->fbc.enabled = true;
+ dev_priv->fbc.active = true;
/* Note: fbc.threshold == 1 for i8xx */
- cfb_pitch = dev_priv->fbc.uncompressed_size / FBC_LL_SIZE;
+ cfb_pitch = intel_fbc_calculate_cfb_size(crtc, fb) / FBC_LL_SIZE;
if (fb->pitches[0] < cfb_pitch)
cfb_pitch = fb->pitches[0];
@@ -127,24 +175,21 @@ static void i8xx_fbc_enable(struct intel_crtc *crtc)
fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
fbc_ctl |= obj->fence_reg;
I915_WRITE(FBC_CONTROL, fbc_ctl);
-
- DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
- cfb_pitch, crtc->base.y, plane_name(crtc->plane));
}
-static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv)
+static bool i8xx_fbc_is_active(struct drm_i915_private *dev_priv)
{
return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
}
-static void g4x_fbc_enable(struct intel_crtc *crtc)
+static void g4x_fbc_activate(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct drm_framebuffer *fb = crtc->base.primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
u32 dpfc_ctl;
- dev_priv->fbc.enabled = true;
+ dev_priv->fbc.active = true;
dpfc_ctl = DPFC_CTL_PLANE(crtc->plane) | DPFC_SR_EN;
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
@@ -157,38 +202,35 @@ static void g4x_fbc_enable(struct intel_crtc *crtc)
/* enable it... */
I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
- DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane));
}
-static void g4x_fbc_disable(struct drm_i915_private *dev_priv)
+static void g4x_fbc_deactivate(struct drm_i915_private *dev_priv)
{
u32 dpfc_ctl;
- dev_priv->fbc.enabled = false;
+ dev_priv->fbc.active = false;
/* Disable compression */
dpfc_ctl = I915_READ(DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(DPFC_CONTROL, dpfc_ctl);
-
- DRM_DEBUG_KMS("disabled FBC\n");
}
}
-static bool g4x_fbc_enabled(struct drm_i915_private *dev_priv)
+static bool g4x_fbc_is_active(struct drm_i915_private *dev_priv)
{
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
}
-static void intel_fbc_nuke(struct drm_i915_private *dev_priv)
+/* This function forces a CFB recompression through the nuke operation. */
+static void intel_fbc_recompress(struct drm_i915_private *dev_priv)
{
I915_WRITE(MSG_FBC_REND_STATE, FBC_REND_NUKE);
POSTING_READ(MSG_FBC_REND_STATE);
}
-static void ilk_fbc_enable(struct intel_crtc *crtc)
+static void ilk_fbc_activate(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct drm_framebuffer *fb = crtc->base.primary->fb;
@@ -197,7 +239,7 @@ static void ilk_fbc_enable(struct intel_crtc *crtc)
int threshold = dev_priv->fbc.threshold;
unsigned int y_offset;
- dev_priv->fbc.enabled = true;
+ dev_priv->fbc.active = true;
dpfc_ctl = DPFC_CTL_PLANE(crtc->plane);
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
@@ -231,33 +273,29 @@ static void ilk_fbc_enable(struct intel_crtc *crtc)
I915_WRITE(DPFC_CPU_FENCE_OFFSET, y_offset);
}
- intel_fbc_nuke(dev_priv);
-
- DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane));
+ intel_fbc_recompress(dev_priv);
}
-static void ilk_fbc_disable(struct drm_i915_private *dev_priv)
+static void ilk_fbc_deactivate(struct drm_i915_private *dev_priv)
{
u32 dpfc_ctl;
- dev_priv->fbc.enabled = false;
+ dev_priv->fbc.active = false;
/* Disable compression */
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
-
- DRM_DEBUG_KMS("disabled FBC\n");
}
}
-static bool ilk_fbc_enabled(struct drm_i915_private *dev_priv)
+static bool ilk_fbc_is_active(struct drm_i915_private *dev_priv)
{
return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
}
-static void gen7_fbc_enable(struct intel_crtc *crtc)
+static void gen7_fbc_activate(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct drm_framebuffer *fb = crtc->base.primary->fb;
@@ -265,7 +303,7 @@ static void gen7_fbc_enable(struct intel_crtc *crtc)
u32 dpfc_ctl;
int threshold = dev_priv->fbc.threshold;
- dev_priv->fbc.enabled = true;
+ dev_priv->fbc.active = true;
dpfc_ctl = 0;
if (IS_IVYBRIDGE(dev_priv))
@@ -310,155 +348,120 @@ static void gen7_fbc_enable(struct intel_crtc *crtc)
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, get_crtc_fence_y_offset(crtc));
- intel_fbc_nuke(dev_priv);
-
- DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane));
+ intel_fbc_recompress(dev_priv);
}
/**
- * intel_fbc_enabled - Is FBC enabled?
+ * intel_fbc_is_active - Is FBC active?
* @dev_priv: i915 device instance
*
* This function is used to verify the current state of FBC.
* FIXME: This should be tracked in the plane config eventually
* instead of queried at runtime for most callers.
*/
-bool intel_fbc_enabled(struct drm_i915_private *dev_priv)
+bool intel_fbc_is_active(struct drm_i915_private *dev_priv)
{
- return dev_priv->fbc.enabled;
+ return dev_priv->fbc.active;
}
-static void intel_fbc_enable(struct intel_crtc *crtc,
- const struct drm_framebuffer *fb)
+static void intel_fbc_activate(const struct drm_framebuffer *fb)
{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct drm_i915_private *dev_priv = fb->dev->dev_private;
+ struct intel_crtc *crtc = dev_priv->fbc.crtc;
- dev_priv->fbc.enable_fbc(crtc);
+ dev_priv->fbc.activate(crtc);
- dev_priv->fbc.crtc = crtc;
dev_priv->fbc.fb_id = fb->base.id;
dev_priv->fbc.y = crtc->base.y;
}
static void intel_fbc_work_fn(struct work_struct *__work)
{
- struct intel_fbc_work *work =
- container_of(to_delayed_work(__work),
- struct intel_fbc_work, work);
- struct drm_i915_private *dev_priv = work->crtc->base.dev->dev_private;
- struct drm_framebuffer *crtc_fb = work->crtc->base.primary->fb;
+ struct drm_i915_private *dev_priv =
+ container_of(__work, struct drm_i915_private, fbc.work.work);
+ struct intel_fbc_work *work = &dev_priv->fbc.work;
+ struct intel_crtc *crtc = dev_priv->fbc.crtc;
+ int delay_ms = 50;
+
+retry:
+ /* Delay the actual enabling to let pageflipping cease and the
+ * display to settle before starting the compression. Note that
+ * this delay also serves a second purpose: it allows for a
+ * vblank to pass after disabling the FBC before we attempt
+ * to modify the control registers.
+ *
+ * A more complicated solution would involve tracking vblanks
+ * following the termination of the page-flipping sequence
+ * and indeed performing the enable as a co-routine and not
+ * waiting synchronously upon the vblank.
+ *
+ * WaFbcWaitForVBlankBeforeEnable:ilk,snb
+ */
+ wait_remaining_ms_from_jiffies(work->enable_jiffies, delay_ms);
mutex_lock(&dev_priv->fbc.lock);
- if (work == dev_priv->fbc.fbc_work) {
- /* Double check that we haven't switched fb without cancelling
- * the prior work.
- */
- if (crtc_fb == work->fb)
- intel_fbc_enable(work->crtc, work->fb);
- dev_priv->fbc.fbc_work = NULL;
+ /* Were we cancelled? */
+ if (!work->scheduled)
+ goto out;
+
+ /* Were we delayed again while this function was sleeping? */
+ if (time_after(work->enable_jiffies + msecs_to_jiffies(delay_ms),
+ jiffies)) {
+ mutex_unlock(&dev_priv->fbc.lock);
+ goto retry;
}
- mutex_unlock(&dev_priv->fbc.lock);
- kfree(work);
+ if (crtc->base.primary->fb == work->fb)
+ intel_fbc_activate(work->fb);
+
+ work->scheduled = false;
+
+out:
+ mutex_unlock(&dev_priv->fbc.lock);
}
static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
-
- if (dev_priv->fbc.fbc_work == NULL)
- return;
-
- DRM_DEBUG_KMS("cancelling pending FBC enable\n");
-
- /* Synchronisation is provided by struct_mutex and checking of
- * dev_priv->fbc.fbc_work, so we can perform the cancellation
- * entirely asynchronously.
- */
- if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
- /* tasklet was killed before being run, clean up */
- kfree(dev_priv->fbc.fbc_work);
-
- /* Mark the work as no longer wanted so that if it does
- * wake-up (because the work was already running and waiting
- * for our mutex), it will discover that is no longer
- * necessary to run.
- */
- dev_priv->fbc.fbc_work = NULL;
+ dev_priv->fbc.work.scheduled = false;
}
-static void intel_fbc_schedule_enable(struct intel_crtc *crtc)
+static void intel_fbc_schedule_activation(struct intel_crtc *crtc)
{
- struct intel_fbc_work *work;
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_fbc_work *work = &dev_priv->fbc.work;
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
- intel_fbc_cancel_work(dev_priv);
-
- work = kzalloc(sizeof(*work), GFP_KERNEL);
- if (work == NULL) {
- DRM_ERROR("Failed to allocate FBC work structure\n");
- intel_fbc_enable(crtc, crtc->base.primary->fb);
- return;
- }
-
- work->crtc = crtc;
+ /* It is useless to call intel_fbc_cancel_work() in this function since
+ * we're not releasing fbc.lock, so it won't have an opportunity to grab
+ * it to discover that it was cancelled. So we just update the expected
+ * jiffy count. */
work->fb = crtc->base.primary->fb;
- INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
-
- dev_priv->fbc.fbc_work = work;
+ work->scheduled = true;
+ work->enable_jiffies = jiffies;
- /* Delay the actual enabling to let pageflipping cease and the
- * display to settle before starting the compression. Note that
- * this delay also serves a second purpose: it allows for a
- * vblank to pass after disabling the FBC before we attempt
- * to modify the control registers.
- *
- * A more complicated solution would involve tracking vblanks
- * following the termination of the page-flipping sequence
- * and indeed performing the enable as a co-routine and not
- * waiting synchronously upon the vblank.
- *
- * WaFbcWaitForVBlankBeforeEnable:ilk,snb
- */
- schedule_delayed_work(&work->work, msecs_to_jiffies(50));
+ schedule_work(&work->work);
}
-static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
+static void __intel_fbc_deactivate(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
intel_fbc_cancel_work(dev_priv);
- dev_priv->fbc.disable_fbc(dev_priv);
- dev_priv->fbc.crtc = NULL;
-}
-
-/**
- * intel_fbc_disable - disable FBC
- * @dev_priv: i915 device instance
- *
- * This function disables FBC.
- */
-void intel_fbc_disable(struct drm_i915_private *dev_priv)
-{
- if (!fbc_supported(dev_priv))
- return;
-
- mutex_lock(&dev_priv->fbc.lock);
- __intel_fbc_disable(dev_priv);
- mutex_unlock(&dev_priv->fbc.lock);
+ if (dev_priv->fbc.active)
+ dev_priv->fbc.deactivate(dev_priv);
}
/*
- * intel_fbc_disable_crtc - disable FBC if it's associated with crtc
+ * intel_fbc_deactivate - deactivate FBC if it's associated with crtc
* @crtc: the CRTC
*
- * This function disables FBC if it's associated with the provided CRTC.
+ * This function deactivates FBC if it's associated with the provided CRTC.
*/
-void intel_fbc_disable_crtc(struct intel_crtc *crtc)
+void intel_fbc_deactivate(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
@@ -467,85 +470,42 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc)
mutex_lock(&dev_priv->fbc.lock);
if (dev_priv->fbc.crtc == crtc)
- __intel_fbc_disable(dev_priv);
+ __intel_fbc_deactivate(dev_priv);
mutex_unlock(&dev_priv->fbc.lock);
}
-const char *intel_no_fbc_reason_str(enum no_fbc_reason reason)
-{
- switch (reason) {
- case FBC_OK:
- return "FBC enabled but currently disabled in hardware";
- case FBC_UNSUPPORTED:
- return "unsupported by this chipset";
- case FBC_NO_OUTPUT:
- return "no output";
- case FBC_STOLEN_TOO_SMALL:
- return "not enough stolen memory";
- case FBC_UNSUPPORTED_MODE:
- return "mode incompatible with compression";
- case FBC_MODE_TOO_LARGE:
- return "mode too large for compression";
- case FBC_BAD_PLANE:
- return "FBC unsupported on plane";
- case FBC_NOT_TILED:
- return "framebuffer not tiled or fenced";
- case FBC_MULTIPLE_PIPES:
- return "more than one pipe active";
- case FBC_MODULE_PARAM:
- return "disabled per module param";
- case FBC_CHIP_DEFAULT:
- return "disabled per chip default";
- case FBC_ROTATION:
- return "rotation unsupported";
- case FBC_IN_DBG_MASTER:
- return "Kernel debugger is active";
- case FBC_BAD_STRIDE:
- return "framebuffer stride not supported";
- case FBC_PIXEL_RATE:
- return "pixel rate is too big";
- case FBC_PIXEL_FORMAT:
- return "pixel format is invalid";
- default:
- MISSING_CASE(reason);
- return "unknown reason";
- }
-}
-
static void set_no_fbc_reason(struct drm_i915_private *dev_priv,
- enum no_fbc_reason reason)
+ const char *reason)
{
if (dev_priv->fbc.no_fbc_reason == reason)
return;
dev_priv->fbc.no_fbc_reason = reason;
- DRM_DEBUG_KMS("Disabling FBC: %s\n", intel_no_fbc_reason_str(reason));
+ DRM_DEBUG_KMS("Disabling FBC: %s\n", reason);
}
-static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv)
+static bool crtc_can_fbc(struct intel_crtc *crtc)
{
- struct drm_crtc *crtc = NULL, *tmp_crtc;
- enum pipe pipe;
- bool pipe_a_only = false;
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
- pipe_a_only = true;
+ if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A)
+ return false;
- for_each_pipe(dev_priv, pipe) {
- tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ if (fbc_on_plane_a_only(dev_priv) && crtc->plane != PLANE_A)
+ return false;
- if (intel_crtc_active(tmp_crtc) &&
- to_intel_plane_state(tmp_crtc->primary->state)->visible)
- crtc = tmp_crtc;
+ return true;
+}
- if (pipe_a_only)
- break;
- }
+static bool crtc_is_valid(struct intel_crtc *crtc)
+{
+ if (!intel_crtc_active(&crtc->base))
+ return false;
- if (!crtc || crtc->primary->fb == NULL)
- return NULL;
+ if (!to_intel_plane_state(crtc->base.primary->state)->visible)
+ return false;
- return crtc;
+ return true;
}
static bool multiple_pipes_ok(struct drm_i915_private *dev_priv)
@@ -581,7 +541,8 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv,
* reserved range size, so it always assumes the maximum (8mb) is used.
* If we enable FBC using a CFB on that memory range we'll get FIFO
* underruns, even if that range is not reserved by the BIOS. */
- if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv))
+ if (IS_BROADWELL(dev_priv) ||
+ IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
end = dev_priv->gtt.stolen_size - 8 * 1024 * 1024;
else
end = dev_priv->gtt.stolen_usable_size;
@@ -617,11 +578,17 @@ again:
}
}
-static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, int size,
- int fb_cpp)
+static int intel_fbc_alloc_cfb(struct intel_crtc *crtc)
{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct drm_framebuffer *fb = crtc->base.primary->state->fb;
struct drm_mm_node *uninitialized_var(compressed_llb);
- int ret;
+ int size, fb_cpp, ret;
+
+ WARN_ON(drm_mm_node_allocated(&dev_priv->fbc.compressed_fb));
+
+ size = intel_fbc_calculate_cfb_size(crtc, fb);
+ fb_cpp = drm_format_plane_cpp(fb->pixel_format, 0);
ret = find_compression_threshold(dev_priv, &dev_priv->fbc.compressed_fb,
size, fb_cpp);
@@ -656,8 +623,6 @@ static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, int size,
dev_priv->mm.stolen_base + compressed_llb->start);
}
- dev_priv->fbc.uncompressed_size = size;
-
DRM_DEBUG_KMS("reserved %llu bytes of contiguous stolen space for FBC, threshold: %d\n",
dev_priv->fbc.compressed_fb.size,
dev_priv->fbc.threshold);
@@ -674,18 +639,15 @@ err_llb:
static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
{
- if (dev_priv->fbc.uncompressed_size == 0)
- return;
-
- i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb);
+ if (drm_mm_node_allocated(&dev_priv->fbc.compressed_fb))
+ i915_gem_stolen_remove_node(dev_priv,
+ &dev_priv->fbc.compressed_fb);
if (dev_priv->fbc.compressed_llb) {
i915_gem_stolen_remove_node(dev_priv,
dev_priv->fbc.compressed_llb);
kfree(dev_priv->fbc.compressed_llb);
}
-
- dev_priv->fbc.uncompressed_size = 0;
}
void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
@@ -698,63 +660,6 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
mutex_unlock(&dev_priv->fbc.lock);
}
-/*
- * For SKL+, the plane source size used by the hardware is based on the value we
- * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value
- * we wrote to PIPESRC.
- */
-static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc,
- int *width, int *height)
-{
- struct intel_plane_state *plane_state =
- to_intel_plane_state(crtc->base.primary->state);
- int w, h;
-
- if (intel_rotation_90_or_270(plane_state->base.rotation)) {
- w = drm_rect_height(&plane_state->src) >> 16;
- h = drm_rect_width(&plane_state->src) >> 16;
- } else {
- w = drm_rect_width(&plane_state->src) >> 16;
- h = drm_rect_height(&plane_state->src) >> 16;
- }
-
- if (width)
- *width = w;
- if (height)
- *height = h;
-}
-
-static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- struct drm_framebuffer *fb = crtc->base.primary->fb;
- int lines;
-
- intel_fbc_get_plane_source_size(crtc, NULL, &lines);
- if (INTEL_INFO(dev_priv)->gen >= 7)
- lines = min(lines, 2048);
-
- return lines * fb->pitches[0];
-}
-
-static int intel_fbc_setup_cfb(struct intel_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- struct drm_framebuffer *fb = crtc->base.primary->fb;
- int size, cpp;
-
- size = intel_fbc_calculate_cfb_size(crtc);
- cpp = drm_format_plane_cpp(fb->pixel_format, 0);
-
- if (size <= dev_priv->fbc.uncompressed_size)
- return 0;
-
- /* Release any current block */
- __intel_fbc_cleanup_cfb(dev_priv);
-
- return intel_fbc_alloc_cfb(dev_priv, size, cpp);
-}
-
static bool stride_is_valid(struct drm_i915_private *dev_priv,
unsigned int stride)
{
@@ -829,87 +734,46 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
}
/**
- * __intel_fbc_update - enable/disable FBC as needed, unlocked
- * @dev_priv: i915 device instance
- *
- * Set up the framebuffer compression hardware at mode set time. We
- * enable it if possible:
- * - plane A only (on pre-965)
- * - no pixel mulitply/line duplication
- * - no alpha buffer discard
- * - no dual wide
- * - framebuffer <= max_hdisplay in width, max_vdisplay in height
- *
- * We can't assume that any compression will take place (worst case),
- * so the compressed buffer has to be the same size as the uncompressed
- * one. It also must reside (along with the line length buffer) in
- * stolen memory.
+ * __intel_fbc_update - activate/deactivate FBC as needed, unlocked
+ * @crtc: the CRTC that triggered the update
*
- * We need to enable/disable FBC on a global basis.
+ * This function completely reevaluates the status of FBC, then activates,
+ * deactivates or maintains it on the same state.
*/
-static void __intel_fbc_update(struct drm_i915_private *dev_priv)
+static void __intel_fbc_update(struct intel_crtc *crtc)
{
- struct drm_crtc *crtc = NULL;
- struct intel_crtc *intel_crtc;
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
const struct drm_display_mode *adjusted_mode;
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
- /* disable framebuffer compression in vGPU */
- if (intel_vgpu_active(dev_priv->dev))
- i915.enable_fbc = 0;
-
- if (i915.enable_fbc < 0) {
- set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT);
+ if (!multiple_pipes_ok(dev_priv)) {
+ set_no_fbc_reason(dev_priv, "more than one pipe active");
goto out_disable;
}
- if (!i915.enable_fbc) {
- set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM);
- goto out_disable;
- }
+ if (!dev_priv->fbc.enabled || dev_priv->fbc.crtc != crtc)
+ return;
- /*
- * If FBC is already on, we just have to verify that we can
- * keep it that way...
- * Need to disable if:
- * - more than one pipe is active
- * - changing FBC params (stride, fence, mode)
- * - new fb is too large to fit in compressed buffer
- * - going to an unsupported config (interlace, pixel multiply, etc.)
- */
- crtc = intel_fbc_find_crtc(dev_priv);
- if (!crtc) {
- set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT);
+ if (!crtc_is_valid(crtc)) {
+ set_no_fbc_reason(dev_priv, "no output");
goto out_disable;
}
- if (!multiple_pipes_ok(dev_priv)) {
- set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES);
- goto out_disable;
- }
-
- intel_crtc = to_intel_crtc(crtc);
- fb = crtc->primary->fb;
+ fb = crtc->base.primary->fb;
obj = intel_fb_obj(fb);
- adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+ adjusted_mode = &crtc->config->base.adjusted_mode;
if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
- set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE);
+ set_no_fbc_reason(dev_priv, "incompatible mode");
goto out_disable;
}
- if (!intel_fbc_hw_tracking_covers_screen(intel_crtc)) {
- set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE);
- goto out_disable;
- }
-
- if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) &&
- intel_crtc->plane != PLANE_A) {
- set_no_fbc_reason(dev_priv, FBC_BAD_PLANE);
+ if (!intel_fbc_hw_tracking_covers_screen(crtc)) {
+ set_no_fbc_reason(dev_priv, "mode too large for compression");
goto out_disable;
}
@@ -918,41 +782,46 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
*/
if (obj->tiling_mode != I915_TILING_X ||
obj->fence_reg == I915_FENCE_REG_NONE) {
- set_no_fbc_reason(dev_priv, FBC_NOT_TILED);
+ set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced");
goto out_disable;
}
if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) &&
- crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) {
- set_no_fbc_reason(dev_priv, FBC_ROTATION);
+ crtc->base.primary->state->rotation != BIT(DRM_ROTATE_0)) {
+ set_no_fbc_reason(dev_priv, "rotation unsupported");
goto out_disable;
}
if (!stride_is_valid(dev_priv, fb->pitches[0])) {
- set_no_fbc_reason(dev_priv, FBC_BAD_STRIDE);
+ set_no_fbc_reason(dev_priv, "framebuffer stride not supported");
goto out_disable;
}
if (!pixel_format_is_valid(fb)) {
- set_no_fbc_reason(dev_priv, FBC_PIXEL_FORMAT);
- goto out_disable;
- }
-
- /* If the kernel debugger is active, always disable compression */
- if (in_dbg_master()) {
- set_no_fbc_reason(dev_priv, FBC_IN_DBG_MASTER);
+ set_no_fbc_reason(dev_priv, "pixel format is invalid");
goto out_disable;
}
/* WaFbcExceedCdClockThreshold:hsw,bdw */
if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
- ilk_pipe_pixel_rate(intel_crtc->config) >=
+ ilk_pipe_pixel_rate(crtc->config) >=
dev_priv->cdclk_freq * 95 / 100) {
- set_no_fbc_reason(dev_priv, FBC_PIXEL_RATE);
+ set_no_fbc_reason(dev_priv, "pixel rate is too big");
goto out_disable;
}
- if (intel_fbc_setup_cfb(intel_crtc)) {
- set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL);
+ /* It is possible for the required CFB size change without a
+ * crtc->disable + crtc->enable since it is possible to change the
+ * stride without triggering a full modeset. Since we try to
+ * over-allocate the CFB, there's a chance we may keep FBC enabled even
+ * if this happens, but if we exceed the current CFB size we'll have to
+ * disable FBC. Notice that it would be possible to disable FBC, wait
+ * for a frame, free the stolen node, then try to reenable FBC in case
+ * we didn't get any invalidate/deactivate calls, but this would require
+ * a lot of tracking just for a specific case. If we conclude it's an
+ * important case, we can implement it later. */
+ if (intel_fbc_calculate_cfb_size(crtc, fb) >
+ dev_priv->fbc.compressed_fb.size * dev_priv->fbc.threshold) {
+ set_no_fbc_reason(dev_priv, "CFB requirements changed");
goto out_disable;
}
@@ -961,12 +830,13 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
* cannot be unpinned (and have its GTT offset and fence revoked)
* without first being decoupled from the scanout and FBC disabled.
*/
- if (dev_priv->fbc.crtc == intel_crtc &&
+ if (dev_priv->fbc.crtc == crtc &&
dev_priv->fbc.fb_id == fb->base.id &&
- dev_priv->fbc.y == crtc->y)
+ dev_priv->fbc.y == crtc->base.y &&
+ dev_priv->fbc.active)
return;
- if (intel_fbc_enabled(dev_priv)) {
+ if (intel_fbc_is_active(dev_priv)) {
/* We update FBC along two paths, after changing fb/crtc
* configuration (modeswitching) and after page-flipping
* finishes. For the latter, we know that not only did
@@ -990,36 +860,37 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
* disabling paths we do need to wait for a vblank at
* some point. And we wait before enabling FBC anyway.
*/
- DRM_DEBUG_KMS("disabling active FBC for update\n");
- __intel_fbc_disable(dev_priv);
+ DRM_DEBUG_KMS("deactivating FBC for update\n");
+ __intel_fbc_deactivate(dev_priv);
}
- intel_fbc_schedule_enable(intel_crtc);
- dev_priv->fbc.no_fbc_reason = FBC_OK;
+ intel_fbc_schedule_activation(crtc);
+ dev_priv->fbc.no_fbc_reason = "FBC enabled (not necessarily active)";
return;
out_disable:
/* Multiple disables should be harmless */
- if (intel_fbc_enabled(dev_priv)) {
- DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
- __intel_fbc_disable(dev_priv);
+ if (intel_fbc_is_active(dev_priv)) {
+ DRM_DEBUG_KMS("unsupported config, deactivating FBC\n");
+ __intel_fbc_deactivate(dev_priv);
}
- __intel_fbc_cleanup_cfb(dev_priv);
}
/*
- * intel_fbc_update - enable/disable FBC as needed
- * @dev_priv: i915 device instance
+ * intel_fbc_update - activate/deactivate FBC as needed
+ * @crtc: the CRTC that triggered the update
*
- * This function reevaluates the overall state and enables or disables FBC.
+ * This function reevaluates the overall state and activates or deactivates FBC.
*/
-void intel_fbc_update(struct drm_i915_private *dev_priv)
+void intel_fbc_update(struct intel_crtc *crtc)
{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
if (!fbc_supported(dev_priv))
return;
mutex_lock(&dev_priv->fbc.lock);
- __intel_fbc_update(dev_priv);
+ __intel_fbc_update(crtc);
mutex_unlock(&dev_priv->fbc.lock);
}
@@ -1039,16 +910,13 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
if (dev_priv->fbc.enabled)
fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe);
- else if (dev_priv->fbc.fbc_work)
- fbc_bits = INTEL_FRONTBUFFER_PRIMARY(
- dev_priv->fbc.fbc_work->crtc->pipe);
else
fbc_bits = dev_priv->fbc.possible_framebuffer_bits;
dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits);
if (dev_priv->fbc.busy_bits)
- __intel_fbc_disable(dev_priv);
+ __intel_fbc_deactivate(dev_priv);
mutex_unlock(&dev_priv->fbc.lock);
}
@@ -1066,11 +934,136 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,
dev_priv->fbc.busy_bits &= ~frontbuffer_bits;
- if (!dev_priv->fbc.busy_bits) {
+ if (!dev_priv->fbc.busy_bits && dev_priv->fbc.enabled) {
+ if (origin != ORIGIN_FLIP && dev_priv->fbc.active) {
+ intel_fbc_recompress(dev_priv);
+ } else {
+ __intel_fbc_deactivate(dev_priv);
+ __intel_fbc_update(dev_priv->fbc.crtc);
+ }
+ }
+
+ mutex_unlock(&dev_priv->fbc.lock);
+}
+
+/**
+ * intel_fbc_enable: tries to enable FBC on the CRTC
+ * @crtc: the CRTC
+ *
+ * This function checks if it's possible to enable FBC on the following CRTC,
+ * then enables it. Notice that it doesn't activate FBC.
+ */
+void intel_fbc_enable(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ if (!fbc_supported(dev_priv))
+ return;
+
+ mutex_lock(&dev_priv->fbc.lock);
+
+ if (dev_priv->fbc.enabled) {
+ WARN_ON(dev_priv->fbc.crtc == crtc);
+ goto out;
+ }
+
+ WARN_ON(dev_priv->fbc.active);
+ WARN_ON(dev_priv->fbc.crtc != NULL);
+
+ if (intel_vgpu_active(dev_priv->dev)) {
+ set_no_fbc_reason(dev_priv, "VGPU is active");
+ goto out;
+ }
+
+ if (i915.enable_fbc < 0) {
+ set_no_fbc_reason(dev_priv, "disabled per chip default");
+ goto out;
+ }
+
+ if (!i915.enable_fbc) {
+ set_no_fbc_reason(dev_priv, "disabled per module param");
+ goto out;
+ }
+
+ if (!crtc_can_fbc(crtc)) {
+ set_no_fbc_reason(dev_priv, "no enabled pipes can have FBC");
+ goto out;
+ }
+
+ if (intel_fbc_alloc_cfb(crtc)) {
+ set_no_fbc_reason(dev_priv, "not enough stolen memory");
+ goto out;
+ }
+
+ DRM_DEBUG_KMS("Enabling FBC on pipe %c\n", pipe_name(crtc->pipe));
+ dev_priv->fbc.no_fbc_reason = "FBC enabled but not active yet\n";
+
+ dev_priv->fbc.enabled = true;
+ dev_priv->fbc.crtc = crtc;
+out:
+ mutex_unlock(&dev_priv->fbc.lock);
+}
+
+/**
+ * __intel_fbc_disable - disable FBC
+ * @dev_priv: i915 device instance
+ *
+ * This is the low level function that actually disables FBC. Callers should
+ * grab the FBC lock.
+ */
+static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
+{
+ struct intel_crtc *crtc = dev_priv->fbc.crtc;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
+ WARN_ON(!dev_priv->fbc.enabled);
+ WARN_ON(dev_priv->fbc.active);
+ assert_pipe_disabled(dev_priv, crtc->pipe);
+
+ DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe));
+
+ __intel_fbc_cleanup_cfb(dev_priv);
+
+ dev_priv->fbc.enabled = false;
+ dev_priv->fbc.crtc = NULL;
+}
+
+/**
+ * intel_fbc_disable_crtc - disable FBC if it's associated with crtc
+ * @crtc: the CRTC
+ *
+ * This function disables FBC if it's associated with the provided CRTC.
+ */
+void intel_fbc_disable_crtc(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ if (!fbc_supported(dev_priv))
+ return;
+
+ mutex_lock(&dev_priv->fbc.lock);
+ if (dev_priv->fbc.crtc == crtc) {
+ WARN_ON(!dev_priv->fbc.enabled);
+ WARN_ON(dev_priv->fbc.active);
__intel_fbc_disable(dev_priv);
- __intel_fbc_update(dev_priv);
}
+ mutex_unlock(&dev_priv->fbc.lock);
+}
+/**
+ * intel_fbc_disable - globally disable FBC
+ * @dev_priv: i915 device instance
+ *
+ * This function disables FBC regardless of which CRTC is associated with it.
+ */
+void intel_fbc_disable(struct drm_i915_private *dev_priv)
+{
+ if (!fbc_supported(dev_priv))
+ return;
+
+ mutex_lock(&dev_priv->fbc.lock);
+ if (dev_priv->fbc.enabled)
+ __intel_fbc_disable(dev_priv);
mutex_unlock(&dev_priv->fbc.lock);
}
@@ -1084,11 +1077,14 @@ void intel_fbc_init(struct drm_i915_private *dev_priv)
{
enum pipe pipe;
+ INIT_WORK(&dev_priv->fbc.work.work, intel_fbc_work_fn);
mutex_init(&dev_priv->fbc.lock);
+ dev_priv->fbc.enabled = false;
+ dev_priv->fbc.active = false;
+ dev_priv->fbc.work.scheduled = false;
if (!HAS_FBC(dev_priv)) {
- dev_priv->fbc.enabled = false;
- dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED;
+ dev_priv->fbc.no_fbc_reason = "unsupported by this chipset";
return;
}
@@ -1096,30 +1092,34 @@ void intel_fbc_init(struct drm_i915_private *dev_priv)
dev_priv->fbc.possible_framebuffer_bits |=
INTEL_FRONTBUFFER_PRIMARY(pipe);
- if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
+ if (fbc_on_pipe_a_only(dev_priv))
break;
}
if (INTEL_INFO(dev_priv)->gen >= 7) {
- dev_priv->fbc.fbc_enabled = ilk_fbc_enabled;
- dev_priv->fbc.enable_fbc = gen7_fbc_enable;
- dev_priv->fbc.disable_fbc = ilk_fbc_disable;
+ dev_priv->fbc.is_active = ilk_fbc_is_active;
+ dev_priv->fbc.activate = gen7_fbc_activate;
+ dev_priv->fbc.deactivate = ilk_fbc_deactivate;
} else if (INTEL_INFO(dev_priv)->gen >= 5) {
- dev_priv->fbc.fbc_enabled = ilk_fbc_enabled;
- dev_priv->fbc.enable_fbc = ilk_fbc_enable;
- dev_priv->fbc.disable_fbc = ilk_fbc_disable;
+ dev_priv->fbc.is_active = ilk_fbc_is_active;
+ dev_priv->fbc.activate = ilk_fbc_activate;
+ dev_priv->fbc.deactivate = ilk_fbc_deactivate;
} else if (IS_GM45(dev_priv)) {
- dev_priv->fbc.fbc_enabled = g4x_fbc_enabled;
- dev_priv->fbc.enable_fbc = g4x_fbc_enable;
- dev_priv->fbc.disable_fbc = g4x_fbc_disable;
+ dev_priv->fbc.is_active = g4x_fbc_is_active;
+ dev_priv->fbc.activate = g4x_fbc_activate;
+ dev_priv->fbc.deactivate = g4x_fbc_deactivate;
} else {
- dev_priv->fbc.fbc_enabled = i8xx_fbc_enabled;
- dev_priv->fbc.enable_fbc = i8xx_fbc_enable;
- dev_priv->fbc.disable_fbc = i8xx_fbc_disable;
+ dev_priv->fbc.is_active = i8xx_fbc_is_active;
+ dev_priv->fbc.activate = i8xx_fbc_activate;
+ dev_priv->fbc.deactivate = i8xx_fbc_deactivate;
/* This value was pulled out of someone's hat */
I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
}
- dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv);
+ /* We still don't have any sort of hardware state readout for FBC, so
+ * deactivate it in case the BIOS activated it to make sure software
+ * matches the hardware state. */
+ if (dev_priv->fbc.is_active(dev_priv))
+ dev_priv->fbc.deactivate(dev_priv);
}
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 4fd5fdfef6bd..bea75cafc623 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -119,7 +119,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
{
struct intel_fbdev *ifbdev =
container_of(helper, struct intel_fbdev, helper);
- struct drm_framebuffer *fb;
+ struct drm_framebuffer *fb = NULL;
struct drm_device *dev = helper->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_mode_fb_cmd2 mode_cmd = {};
@@ -138,6 +138,8 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
+ mutex_lock(&dev->struct_mutex);
+
size = mode_cmd.pitches[0] * mode_cmd.height;
size = PAGE_ALIGN(size);
@@ -156,26 +158,21 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
if (IS_ERR(fb)) {
+ drm_gem_object_unreference(&obj->base);
ret = PTR_ERR(fb);
- goto out_unref;
+ goto out;
}
- /* Flush everything out, we'll be doing GTT only from now on */
- ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL, NULL);
- if (ret) {
- DRM_ERROR("failed to pin obj: %d\n", ret);
- goto out_fb;
- }
+ mutex_unlock(&dev->struct_mutex);
ifbdev->fb = to_intel_framebuffer(fb);
return 0;
-out_fb:
- drm_framebuffer_remove(fb);
-out_unref:
- drm_gem_object_unreference(&obj->base);
out:
+ mutex_unlock(&dev->struct_mutex);
+ if (!IS_ERR_OR_NULL(fb))
+ drm_framebuffer_unreference(fb);
return ret;
}
@@ -193,8 +190,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
int size, ret;
bool prealloc = false;
- mutex_lock(&dev->struct_mutex);
-
if (intel_fb &&
(sizes->fb_width > intel_fb->base.width ||
sizes->fb_height > intel_fb->base.height)) {
@@ -209,7 +204,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
ret = intelfb_alloc(helper, sizes);
if (ret)
- goto out_unlock;
+ return ret;
intel_fb = ifbdev->fb;
} else {
DRM_DEBUG_KMS("re-using BIOS fb\n");
@@ -221,8 +216,19 @@ static int intelfb_create(struct drm_fb_helper *helper,
obj = intel_fb->obj;
size = obj->base.size;
+ mutex_lock(&dev->struct_mutex);
+
+ /* Pin the GGTT vma for our access via info->screen_base.
+ * This also validates that any existing fb inherited from the
+ * BIOS is suitable for own access.
+ */
+ ret = intel_pin_and_fence_fb_obj(NULL, &ifbdev->fb->base, NULL);
+ if (ret)
+ goto out_unlock;
+
info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info)) {
+ DRM_ERROR("Failed to allocate fb_info\n");
ret = PTR_ERR(info);
goto out_unpin;
}
@@ -249,6 +255,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
size);
if (!info->screen_base) {
+ DRM_ERROR("Failed to remap framebuffer into virtual memory\n");
ret = -ENOSPC;
goto out_destroy_fbi;
}
@@ -281,7 +288,6 @@ out_destroy_fbi:
drm_fb_helper_release_fbi(helper);
out_unpin:
i915_gem_object_ggtt_unpin(obj);
- drm_gem_object_unreference(&obj->base);
out_unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -520,14 +526,20 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
static void intel_fbdev_destroy(struct drm_device *dev,
struct intel_fbdev *ifbdev)
{
+ /* We rely on the object-free to release the VMA pinning for
+ * the info->screen_base mmaping. Leaking the VMA is simpler than
+ * trying to rectify all the possible error paths leading here.
+ */
drm_fb_helper_unregister_fbi(&ifbdev->helper);
drm_fb_helper_release_fbi(&ifbdev->helper);
drm_fb_helper_fini(&ifbdev->helper);
- drm_framebuffer_unregister_private(&ifbdev->fb->base);
- drm_framebuffer_remove(&ifbdev->fb->base);
+ if (ifbdev->fb) {
+ drm_framebuffer_unregister_private(&ifbdev->fb->base);
+ drm_framebuffer_remove(&ifbdev->fb->base);
+ }
}
/*
@@ -702,13 +714,20 @@ int intel_fbdev_init(struct drm_device *dev)
return 0;
}
-void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
+static void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
{
struct drm_i915_private *dev_priv = data;
struct intel_fbdev *ifbdev = dev_priv->fbdev;
/* Due to peculiar init order wrt to hpd handling this is separate. */
- drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
+ if (drm_fb_helper_initial_config(&ifbdev->helper,
+ ifbdev->preferred_bpp))
+ intel_fbdev_fini(dev_priv->dev);
+}
+
+void intel_fbdev_initial_config_async(struct drm_device *dev)
+{
+ async_schedule(intel_fbdev_initial_config, to_i915(dev));
}
void intel_fbdev_fini(struct drm_device *dev)
@@ -719,7 +738,8 @@ void intel_fbdev_fini(struct drm_device *dev)
flush_work(&dev_priv->fbdev_suspend_work);
- async_synchronize_full();
+ if (!current_is_async())
+ async_synchronize_full();
intel_fbdev_destroy(dev, dev_priv->fbdev);
kfree(dev_priv->fbdev);
dev_priv->fbdev = NULL;
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 54daa66c6970..bda526660e20 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -84,38 +84,21 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
return true;
}
-/**
- * i9xx_check_fifo_underruns - check for fifo underruns
- * @dev_priv: i915 device instance
- *
- * This function checks for fifo underruns on GMCH platforms. This needs to be
- * done manually on modeset to make sure that we catch all underruns since they
- * do not generate an interrupt by themselves on these platforms.
- */
-void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
+static void i9xx_check_fifo_underruns(struct intel_crtc *crtc)
{
- struct intel_crtc *crtc;
-
- spin_lock_irq(&dev_priv->irq_lock);
-
- for_each_intel_crtc(dev_priv->dev, crtc) {
- u32 reg = PIPESTAT(crtc->pipe);
- u32 pipestat;
-
- if (crtc->cpu_fifo_underrun_disabled)
- continue;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ i915_reg_t reg = PIPESTAT(crtc->pipe);
+ u32 pipestat = I915_READ(reg) & 0xffff0000;
- pipestat = I915_READ(reg) & 0xffff0000;
- if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
- continue;
+ assert_spin_locked(&dev_priv->irq_lock);
- I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
- POSTING_READ(reg);
+ if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
+ return;
- DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
- }
+ I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+ POSTING_READ(reg);
- spin_unlock_irq(&dev_priv->irq_lock);
+ DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
}
static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -123,7 +106,7 @@ static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
bool enable, bool old)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg = PIPESTAT(pipe);
+ i915_reg_t reg = PIPESTAT(pipe);
u32 pipestat = I915_READ(reg) & 0xffff0000;
assert_spin_locked(&dev_priv->irq_lock);
@@ -145,9 +128,26 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
DE_PIPEB_FIFO_UNDERRUN;
if (enable)
- ironlake_enable_display_irq(dev_priv, bit);
+ ilk_enable_display_irq(dev_priv, bit);
else
- ironlake_disable_display_irq(dev_priv, bit);
+ ilk_disable_display_irq(dev_priv, bit);
+}
+
+static void ivybridge_check_fifo_underruns(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+ uint32_t err_int = I915_READ(GEN7_ERR_INT);
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ if ((err_int & ERR_INT_FIFO_UNDERRUN(pipe)) == 0)
+ return;
+
+ I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
+ POSTING_READ(GEN7_ERR_INT);
+
+ DRM_ERROR("fifo underrun on pipe %c\n", pipe_name(pipe));
}
static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -161,9 +161,9 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
if (!ivb_can_enable_err_int(dev))
return;
- ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ ilk_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
} else {
- ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ ilk_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
if (old &&
I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
@@ -178,14 +178,10 @@ static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
- assert_spin_locked(&dev_priv->irq_lock);
-
if (enable)
- dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN;
+ bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_FIFO_UNDERRUN);
else
- dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN;
- I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
- POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+ bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_FIFO_UNDERRUN);
}
static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -202,6 +198,24 @@ static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
ibx_disable_display_interrupt(dev_priv, bit);
}
+static void cpt_check_pch_fifo_underruns(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum transcoder pch_transcoder = (enum transcoder) crtc->pipe;
+ uint32_t serr_int = I915_READ(SERR_INT);
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ if ((serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) == 0)
+ return;
+
+ I915_WRITE(SERR_INT, SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
+ POSTING_READ(SERR_INT);
+
+ DRM_ERROR("pch fifo underrun on pch transcoder %c\n",
+ transcoder_name(pch_transcoder));
+}
+
static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
enum transcoder pch_transcoder,
bool enable, bool old)
@@ -375,3 +389,56 @@ void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
DRM_ERROR("PCH transcoder %c FIFO underrun\n",
transcoder_name(pch_transcoder));
}
+
+/**
+ * intel_check_cpu_fifo_underruns - check for CPU fifo underruns immediately
+ * @dev_priv: i915 device instance
+ *
+ * Check for CPU fifo underruns immediately. Useful on IVB/HSW where the shared
+ * error interrupt may have been disabled, and so CPU fifo underruns won't
+ * necessarily raise an interrupt, and on GMCH platforms where underruns never
+ * raise an interrupt.
+ */
+void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv)
+{
+ struct intel_crtc *crtc;
+
+ spin_lock_irq(&dev_priv->irq_lock);
+
+ for_each_intel_crtc(dev_priv->dev, crtc) {
+ if (crtc->cpu_fifo_underrun_disabled)
+ continue;
+
+ if (HAS_GMCH_DISPLAY(dev_priv))
+ i9xx_check_fifo_underruns(crtc);
+ else if (IS_GEN7(dev_priv))
+ ivybridge_check_fifo_underruns(crtc);
+ }
+
+ spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+/**
+ * intel_check_pch_fifo_underruns - check for PCH fifo underruns immediately
+ * @dev_priv: i915 device instance
+ *
+ * Check for PCH fifo underruns immediately. Useful on CPT/PPT where the shared
+ * error interrupt may have been disabled, and so PCH fifo underruns won't
+ * necessarily raise an interrupt.
+ */
+void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv)
+{
+ struct intel_crtc *crtc;
+
+ spin_lock_irq(&dev_priv->irq_lock);
+
+ for_each_intel_crtc(dev_priv->dev, crtc) {
+ if (crtc->pch_fifo_underrun_disabled)
+ continue;
+
+ if (HAS_PCH_CPT(dev_priv))
+ cpt_check_pch_fifo_underruns(crtc);
+ }
+
+ spin_unlock_irq(&dev_priv->irq_lock);
+}
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 081d5f648d26..822952235dcf 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -42,8 +42,6 @@ struct i915_guc_client {
uint32_t wq_offset;
uint32_t wq_size;
-
- spinlock_t wq_lock; /* Protects all data below */
uint32_t wq_tail;
/* GuC submission statistics & status */
@@ -76,11 +74,17 @@ struct intel_guc_fw {
uint16_t guc_fw_minor_wanted;
uint16_t guc_fw_major_found;
uint16_t guc_fw_minor_found;
+
+ uint32_t header_size;
+ uint32_t header_offset;
+ uint32_t rsa_size;
+ uint32_t rsa_offset;
+ uint32_t ucode_size;
+ uint32_t ucode_offset;
};
struct intel_guc {
struct intel_guc_fw guc_fw;
-
uint32_t log_flags;
struct drm_i915_gem_object *log_obj;
@@ -89,8 +93,6 @@ struct intel_guc {
struct i915_guc_client *execbuf_client;
- spinlock_t host2guc_lock; /* Protects all data below */
-
DECLARE_BITMAP(doorbell_bitmap, GUC_MAX_DOORBELLS);
uint32_t db_cacheline; /* Cyclic counter mod pagesize */
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 593d2f585978..40b2ea572e16 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -122,6 +122,78 @@
#define GUC_CTL_MAX_DWORDS (GUC_CTL_RSRVD + 1)
+/**
+ * DOC: GuC Firmware Layout
+ *
+ * The GuC firmware layout looks like this:
+ *
+ * +-------------------------------+
+ * | guc_css_header |
+ * | contains major/minor version |
+ * +-------------------------------+
+ * | uCode |
+ * +-------------------------------+
+ * | RSA signature |
+ * +-------------------------------+
+ * | modulus key |
+ * +-------------------------------+
+ * | exponent val |
+ * +-------------------------------+
+ *
+ * The firmware may or may not have modulus key and exponent data. The header,
+ * uCode and RSA signature are must-have components that will be used by driver.
+ * Length of each components, which is all in dwords, can be found in header.
+ * In the case that modulus and exponent are not present in fw, a.k.a truncated
+ * image, the length value still appears in header.
+ *
+ * Driver will do some basic fw size validation based on the following rules:
+ *
+ * 1. Header, uCode and RSA are must-have components.
+ * 2. All firmware components, if they present, are in the sequence illustrated
+ * in the layout table above.
+ * 3. Length info of each component can be found in header, in dwords.
+ * 4. Modulus and exponent key are not required by driver. They may not appear
+ * in fw. So driver will load a truncated firmware in this case.
+ */
+
+struct guc_css_header {
+ uint32_t module_type;
+ /* header_size includes all non-uCode bits, including css_header, rsa
+ * key, modulus key and exponent data. */
+ uint32_t header_size_dw;
+ uint32_t header_version;
+ uint32_t module_id;
+ uint32_t module_vendor;
+ union {
+ struct {
+ uint8_t day;
+ uint8_t month;
+ uint16_t year;
+ };
+ uint32_t date;
+ };
+ uint32_t size_dw; /* uCode plus header_size_dw */
+ uint32_t key_size_dw;
+ uint32_t modulus_size_dw;
+ uint32_t exponent_size_dw;
+ union {
+ struct {
+ uint8_t hour;
+ uint8_t min;
+ uint16_t sec;
+ };
+ uint32_t time;
+ };
+
+ char username[8];
+ char buildnumber[12];
+ uint32_t device_id;
+ uint32_t guc_sw_version;
+ uint32_t prod_preprod_fw;
+ uint32_t reserved[12];
+ uint32_t header_info;
+} __packed;
+
struct guc_doorbell_info {
u32 db_status;
u32 cookie;
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 3541f76c65a7..550921f2ef7d 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -31,7 +31,7 @@
#include "intel_guc.h"
/**
- * DOC: GuC
+ * DOC: GuC-specific firmware loader
*
* intel_guc:
* Top level structure of guc. It handles firmware loading and manages client
@@ -208,16 +208,6 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
/*
* Transfer the firmware image to RAM for execution by the microcontroller.
*
- * GuC Firmware layout:
- * +-------------------------------+ ----
- * | CSS header | 128B
- * | contains major/minor version |
- * +-------------------------------+ ----
- * | uCode |
- * +-------------------------------+ ----
- * | RSA signature | 256B
- * +-------------------------------+ ----
- *
* 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.
@@ -225,33 +215,29 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
* Note that GuC needs the CSS header plus uKernel code to be copied by the
* DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
*/
-
-#define UOS_CSS_HEADER_OFFSET 0
-#define UOS_VER_MINOR_OFFSET 0x44
-#define UOS_VER_MAJOR_OFFSET 0x46
-#define UOS_CSS_HEADER_SIZE 0x80
-#define UOS_RSA_SIG_SIZE 0x100
-
static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
{
struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
unsigned long offset;
struct sg_table *sg = fw_obj->pages;
- u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
+ u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
int i, ret = 0;
- /* uCode size, also is where RSA signature starts */
- offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
- I915_WRITE(DMA_COPY_SIZE, ucode_size);
+ /* where RSA signature starts */
+ offset = guc_fw->rsa_offset;
/* Copy RSA signature from the fw image to HW for verification */
- sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
- for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
+ sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset);
+ for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++)
I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
+ /* 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 = i915_gem_obj_ggtt_offset(fw_obj);
+ offset = i915_gem_obj_ggtt_offset(fw_obj) + 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);
@@ -322,8 +308,8 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
/* WaDisableMinuteIaClockGating:skl,bxt */
- if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) {
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) &
~GUC_ENABLE_MIA_CLOCK_GATING));
}
@@ -378,6 +364,9 @@ int intel_guc_ucode_load(struct drm_device *dev)
struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
int err = 0;
+ if (!i915.enable_guc_submission)
+ return 0;
+
DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
@@ -457,10 +446,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
{
struct drm_i915_gem_object *obj;
const struct firmware *fw;
- const u8 *css_header;
- const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
- const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
- - 0x8000; /* 32k reserved (8K stack + 24k context) */
+ struct guc_css_header *css;
+ size_t size;
int err;
DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
@@ -474,12 +461,52 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
guc_fw->guc_fw_path, fw);
- DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
- fw->size, minsize, maxsize);
- /* Check the size of the blob befoe examining buffer contents */
- if (fw->size < minsize || fw->size > maxsize)
+ /* Check the size of the blob before examining buffer contents */
+ if (fw->size < sizeof(struct guc_css_header)) {
+ DRM_ERROR("Firmware header is missing\n");
goto fail;
+ }
+
+ css = (struct guc_css_header *)fw->data;
+
+ /* Firmware bits always start from header */
+ guc_fw->header_offset = 0;
+ guc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
+ css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
+
+ if (guc_fw->header_size != sizeof(struct guc_css_header)) {
+ DRM_ERROR("CSS header definition mismatch\n");
+ goto fail;
+ }
+
+ /* then, uCode */
+ guc_fw->ucode_offset = guc_fw->header_offset + guc_fw->header_size;
+ guc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
+
+ /* now RSA */
+ if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
+ DRM_ERROR("RSA key size is bad\n");
+ goto fail;
+ }
+ guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
+ guc_fw->rsa_size = css->key_size_dw * sizeof(u32);
+
+ /* At least, it should have header, uCode and RSA. Size of all three. */
+ size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size;
+ if (fw->size < size) {
+ DRM_ERROR("Missing firmware components\n");
+ goto fail;
+ }
+
+ /* Header and uCode will be loaded to WOPCM. Size of the two. */
+ size = guc_fw->header_size + guc_fw->ucode_size;
+
+ /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
+ if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
+ DRM_ERROR("Firmware is too large to fit in WOPCM\n");
+ goto fail;
+ }
/*
* The GuC firmware image has the version number embedded at a well-known
@@ -487,9 +514,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
* TWO bytes each (i.e. u16), although all pointers and offsets are defined
* in terms of bytes (u8).
*/
- css_header = fw->data + UOS_CSS_HEADER_OFFSET;
- guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
- guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
+ guc_fw->guc_fw_major_found = css->guc_sw_version >> 16;
+ guc_fw->guc_fw_minor_found = css->guc_sw_version & 0xFFFF;
if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
@@ -566,6 +592,9 @@ void intel_guc_ucode_init(struct drm_device *dev)
fw_path = ""; /* unknown device */
}
+ if (!i915.enable_guc_submission)
+ return;
+
guc_fw->guc_dev = dev;
guc_fw->guc_fw_path = fw_path;
guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index e6c035b0fc1c..4a77639a489d 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -78,7 +78,7 @@ static u32 g4x_infoframe_index(enum hdmi_infoframe_type type)
case HDMI_INFOFRAME_TYPE_VENDOR:
return VIDEO_DIP_SELECT_VENDOR;
default:
- DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
+ MISSING_CASE(type);
return 0;
}
}
@@ -93,7 +93,7 @@ static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type)
case HDMI_INFOFRAME_TYPE_VENDOR:
return VIDEO_DIP_ENABLE_VENDOR;
default:
- DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
+ MISSING_CASE(type);
return 0;
}
}
@@ -108,15 +108,16 @@ static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type)
case HDMI_INFOFRAME_TYPE_VENDOR:
return VIDEO_DIP_ENABLE_VS_HSW;
default:
- DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
+ MISSING_CASE(type);
return 0;
}
}
-static u32 hsw_dip_data_reg(struct drm_i915_private *dev_priv,
- enum transcoder cpu_transcoder,
- enum hdmi_infoframe_type type,
- int i)
+static i915_reg_t
+hsw_dip_data_reg(struct drm_i915_private *dev_priv,
+ enum transcoder cpu_transcoder,
+ enum hdmi_infoframe_type type,
+ int i)
{
switch (type) {
case HDMI_INFOFRAME_TYPE_AVI:
@@ -126,8 +127,8 @@ static u32 hsw_dip_data_reg(struct drm_i915_private *dev_priv,
case HDMI_INFOFRAME_TYPE_VENDOR:
return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
default:
- DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
- return 0;
+ MISSING_CASE(type);
+ return INVALID_MMIO_REG;
}
}
@@ -168,10 +169,10 @@ 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 drm_encoder *encoder,
+ const struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(encoder->dev);
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
u32 val = I915_READ(VIDEO_DIP_CTL);
@@ -193,8 +194,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+ i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
u32 val = I915_READ(reg);
+ int i;
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
@@ -223,13 +225,13 @@ 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 drm_encoder *encoder,
+ const struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+ struct drm_i915_private *dev_priv = to_i915(encoder->dev);
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
- int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+ enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
+ i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
u32 val = I915_READ(reg);
if ((val & VIDEO_DIP_ENABLE) == 0)
@@ -251,8 +253,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+ i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
u32 val = I915_READ(reg);
+ int i;
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
@@ -284,13 +287,12 @@ 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 drm_encoder *encoder,
+ const struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
- u32 val = I915_READ(reg);
+ struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+ enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
+ u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
if ((val & VIDEO_DIP_ENABLE) == 0)
return false;
@@ -308,8 +310,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+ i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
u32 val = I915_READ(reg);
+ int i;
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
@@ -338,14 +341,13 @@ 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 drm_encoder *encoder,
+ const struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+ struct drm_i915_private *dev_priv = to_i915(encoder->dev);
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
- int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
- u32 val = I915_READ(reg);
+ 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;
@@ -367,14 +369,12 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
- u32 data_reg;
+ i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
+ i915_reg_t data_reg;
int i;
u32 val = I915_READ(ctl_reg);
data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0);
- if (data_reg == 0)
- return;
val &= ~hsw_infoframe_enable(type);
I915_WRITE(ctl_reg, val);
@@ -396,13 +396,11 @@ 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 drm_encoder *encoder,
+ const struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
- u32 val = I915_READ(ctl_reg);
+ struct drm_i915_private *dev_priv = to_i915(encoder->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 |
VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
@@ -513,7 +511,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
- u32 reg = VIDEO_DIP_CTL;
+ i915_reg_t reg = VIDEO_DIP_CTL;
u32 val = I915_READ(reg);
u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
@@ -633,11 +631,12 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
- u32 reg, val = 0;
+ i915_reg_t reg;
+ u32 val = 0;
if (HAS_DDI(dev_priv))
reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder);
- else if (IS_VALLEYVIEW(dev_priv))
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
else if (HAS_PCH_SPLIT(dev_priv->dev))
reg = TVIDEO_DIP_GCP(crtc->pipe);
@@ -666,7 +665,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
- u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+ i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
u32 val = I915_READ(reg);
u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
@@ -717,7 +716,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+ i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
u32 val = I915_READ(reg);
assert_hdmi_port_disabled(intel_hdmi);
@@ -760,7 +759,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+ i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
u32 val = I915_READ(reg);
u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
@@ -811,7 +810,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
+ i915_reg_t reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
u32 val = I915_READ(reg);
assert_hdmi_port_disabled(intel_hdmi);
@@ -925,7 +924,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_hdmi->infoframe_enabled(&encoder->base))
+ if (intel_hdmi->infoframe_enabled(&encoder->base, pipe_config))
pipe_config->has_infoframe = true;
if (tmp & SDVO_AUDIO_ENABLE)
@@ -1108,6 +1107,13 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
* matching DP port to be enabled on transcoder A.
*/
if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) {
+ /*
+ * We get CPU/PCH FIFO underruns on the other pipe when
+ * doing the workaround. Sweep them under the rug.
+ */
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
temp &= ~SDVO_PIPE_B_SELECT;
temp |= SDVO_ENABLE;
/*
@@ -1122,6 +1128,10 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
temp &= ~SDVO_ENABLE;
I915_WRITE(intel_hdmi->hdmi_reg, temp);
POSTING_READ(intel_hdmi->hdmi_reg);
+
+ intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
}
intel_hdmi->set_infoframes(&encoder->base, false, NULL);
@@ -1338,14 +1348,15 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
struct edid *edid = NULL;
bool connected = false;
- intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+ if (force) {
+ intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
- if (force)
edid = drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus));
- intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+ intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+ }
to_intel_connector(connector)->detect_edid = edid;
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -2040,7 +2051,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
* On BXT A0/A1, sw needs to activate DDIA HPD logic and
* interrupts to check the external panel connection.
*/
- if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0))
+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
intel_encoder->hpd_pin = HPD_PORT_A;
else
intel_encoder->hpd_pin = HPD_PORT_B;
@@ -2088,7 +2099,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
BUG();
}
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
intel_hdmi->write_infoframe = vlv_write_infoframe;
intel_hdmi->set_infoframes = vlv_set_infoframes;
intel_hdmi->infoframe_enabled = vlv_infoframe_enabled;
@@ -2132,8 +2143,10 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
}
}
-void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
+void intel_hdmi_init(struct drm_device *dev,
+ i915_reg_t hdmi_reg, enum port port)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_digital_port *intel_dig_port;
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
@@ -2151,7 +2164,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
intel_encoder = &intel_dig_port->base;
drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
intel_encoder->compute_config = intel_hdmi_compute_config;
if (HAS_PCH_SPLIT(dev)) {
@@ -2202,8 +2215,9 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
intel_dig_port->port = port;
+ dev_priv->dig_port_map[port] = intel_encoder;
intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
- intel_dig_port->dp.output_reg = 0;
+ intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
intel_hdmi_init_connector(intel_dig_port, intel_connector);
}
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index b17785719598..bee673005d48 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -407,7 +407,7 @@ void intel_hpd_irq_handler(struct drm_device *dev,
* hotplug bits itself. So only WARN about unexpected
* interrupts on saner platforms.
*/
- WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev),
+ WARN_ONCE(!HAS_GMCH_DISPLAY(dev),
"Received HPD interrupt on pin %d although disabled\n", i);
continue;
}
@@ -468,9 +468,14 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
list_for_each_entry(connector, &mode_config->connector_list, head) {
struct intel_connector *intel_connector = to_intel_connector(connector);
connector->polled = intel_connector->polled;
- if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
- connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ /* MST has a dynamic intel_connector->encoder and it's reprobing
+ * is all handled by the MST helpers. */
if (intel_connector->mst_port)
+ continue;
+
+ if (!connector->polled && I915_HAS_HOTPLUG(dev) &&
+ intel_connector->encoder->hpd_pin > HPD_NONE)
connector->polled = DRM_CONNECTOR_POLL_HPD;
}
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 8324654037b6..25254b5c1ac5 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -36,7 +36,7 @@
struct gmbus_pin {
const char *name;
- int reg;
+ i915_reg_t reg;
};
/* Map gmbus pin pairs to names and registers. */
@@ -63,9 +63,9 @@ static const struct gmbus_pin gmbus_pins_skl[] = {
};
static const struct gmbus_pin gmbus_pins_bxt[] = {
- [GMBUS_PIN_1_BXT] = { "dpb", PCH_GPIOB },
- [GMBUS_PIN_2_BXT] = { "dpc", PCH_GPIOC },
- [GMBUS_PIN_3_BXT] = { "misc", PCH_GPIOD },
+ [GMBUS_PIN_1_BXT] = { "dpb", GPIOB },
+ [GMBUS_PIN_2_BXT] = { "dpc", GPIOC },
+ [GMBUS_PIN_3_BXT] = { "misc", GPIOD },
};
/* pin is expected to be valid */
@@ -74,7 +74,7 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
{
if (IS_BROXTON(dev_priv))
return &gmbus_pins_bxt[pin];
- else if (IS_SKYLAKE(dev_priv))
+ else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
return &gmbus_pins_skl[pin];
else if (IS_BROADWELL(dev_priv))
return &gmbus_pins_bdw[pin];
@@ -89,14 +89,15 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
if (IS_BROXTON(dev_priv))
size = ARRAY_SIZE(gmbus_pins_bxt);
- else if (IS_SKYLAKE(dev_priv))
+ else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
size = ARRAY_SIZE(gmbus_pins_skl);
else if (IS_BROADWELL(dev_priv))
size = ARRAY_SIZE(gmbus_pins_bdw);
else
size = ARRAY_SIZE(gmbus_pins);
- return pin < size && get_gmbus_pin(dev_priv, pin)->reg;
+ return pin < size &&
+ i915_mmio_reg_valid(get_gmbus_pin(dev_priv, pin)->reg);
}
/* Intel GPIO access functions */
@@ -240,9 +241,8 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
algo = &bus->bit_algo;
- bus->gpio_reg = dev_priv->gpio_mmio_base +
- get_gmbus_pin(dev_priv, pin)->reg;
-
+ bus->gpio_reg = _MMIO(dev_priv->gpio_mmio_base +
+ i915_mmio_reg_offset(get_gmbus_pin(dev_priv, pin)->reg));
bus->adapter.algo_data = algo;
algo->setsda = set_data;
algo->setscl = set_clock;
@@ -472,9 +472,7 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
}
static int
-gmbus_xfer(struct i2c_adapter *adapter,
- struct i2c_msg *msgs,
- int num)
+do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus,
@@ -483,14 +481,6 @@ gmbus_xfer(struct i2c_adapter *adapter,
int i = 0, inc, try = 0;
int ret = 0;
- intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
- mutex_lock(&dev_priv->gmbus_mutex);
-
- if (bus->force_bit) {
- ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
- goto out;
- }
-
retry:
I915_WRITE(GMBUS0, bus->reg0);
@@ -505,17 +495,13 @@ retry:
ret = gmbus_xfer_write(dev_priv, &msgs[i]);
}
+ if (!ret)
+ ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
+ GMBUS_HW_WAIT_EN);
if (ret == -ETIMEDOUT)
goto timeout;
- if (ret == -ENXIO)
- goto clear_err;
-
- ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
- GMBUS_HW_WAIT_EN);
- if (ret == -ENXIO)
+ else if (ret)
goto clear_err;
- if (ret)
- goto timeout;
}
/* Generate a STOP condition on the bus. Note that gmbus can't generata
@@ -589,13 +575,34 @@ timeout:
bus->adapter.name, bus->reg0 & 0xff);
I915_WRITE(GMBUS0, 0);
- /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+ /*
+ * Hardware may not support GMBUS over these pins? Try GPIO bitbanging
+ * instead. Use EAGAIN to have i2c core retry.
+ */
bus->force_bit = 1;
- ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
+ ret = -EAGAIN;
out:
- mutex_unlock(&dev_priv->gmbus_mutex);
+ return ret;
+}
+static int
+gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
+ adapter);
+ struct drm_i915_private *dev_priv = bus->dev_priv;
+ int ret;
+
+ intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+ mutex_lock(&dev_priv->gmbus_mutex);
+
+ if (bus->force_bit)
+ ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
+ else
+ ret = do_gmbus_xfer(adapter, msgs, num);
+
+ mutex_unlock(&dev_priv->gmbus_mutex);
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
return ret;
@@ -628,12 +635,13 @@ int intel_setup_gmbus(struct drm_device *dev)
if (HAS_PCH_NOP(dev))
return 0;
- else if (HAS_PCH_SPLIT(dev))
- dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
- else if (IS_VALLEYVIEW(dev))
+
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
- else
- dev_priv->gpio_mmio_base = 0;
+ else if (!HAS_GMCH_DISPLAY(dev_priv))
+ dev_priv->gpio_mmio_base =
+ i915_mmio_reg_offset(PCH_GPIOA) -
+ i915_mmio_reg_offset(GPIOA);
mutex_init(&dev_priv->gmbus_mutex);
init_waitqueue_head(&dev_priv->gmbus_wait_queue);
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 88e12bdf79e2..3aa614731d7e 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -190,16 +190,21 @@
#define GEN8_CTX_L3LLC_COHERENT (1<<5)
#define GEN8_CTX_PRIVILEGE (1<<8)
-#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \
+#define ASSIGN_CTX_REG(reg_state, pos, reg, val) do { \
+ (reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \
+ (reg_state)[(pos)+1] = (val); \
+} while (0)
+
+#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \
const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \
reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \
reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
-}
+} while (0)
-#define ASSIGN_CTX_PML4(ppgtt, reg_state) { \
+#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \
reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \
reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \
-}
+} while (0)
enum {
ADVANCED_CONTEXT = 0,
@@ -284,8 +289,8 @@ static bool disable_lite_restore_wa(struct intel_engine_cs *ring)
{
struct drm_device *dev = ring->dev;
- return ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) &&
+ return (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1)) &&
(ring->id == VCS || ring->id == VCS2);
}
@@ -367,7 +372,7 @@ static int execlists_update_context(struct drm_i915_gem_request *rq)
WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
- page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+ page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
reg_state[CTX_RING_TAIL+1] = rq->tail;
@@ -921,7 +926,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params,
intel_logical_ring_emit(ringbuf, MI_NOOP);
intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
- intel_logical_ring_emit(ringbuf, INSTPM);
+ intel_logical_ring_emit_reg(ringbuf, INSTPM);
intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
intel_logical_ring_advance(ringbuf);
@@ -1096,7 +1101,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req)
intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(w->count));
for (i = 0; i < w->count; i++) {
- intel_logical_ring_emit(ringbuf, w->reg[i].addr);
+ intel_logical_ring_emit_reg(ringbuf, w->reg[i].addr);
intel_logical_ring_emit(ringbuf, w->reg[i].value);
}
intel_logical_ring_emit(ringbuf, MI_NOOP);
@@ -1120,6 +1125,8 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req)
batch[__index] = (cmd); \
} while (0)
+#define wa_ctx_emit_reg(batch, index, reg) \
+ wa_ctx_emit((batch), (index), i915_mmio_reg_offset(reg))
/*
* In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after
@@ -1149,17 +1156,17 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring,
* this batch updates GEN8_L3SQCREG4 with default value we need to
* set this bit here to retain the WA during flush.
*/
- if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0)
+ if (IS_SKL_REVID(ring->dev, 0, SKL_REVID_E0))
l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS;
wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT));
- wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
+ wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
wa_ctx_emit(batch, index, 0);
wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
- wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
+ wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
wa_ctx_emit(batch, index, l3sqc4_flush);
wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6));
@@ -1172,7 +1179,7 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring,
wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT));
- wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
+ wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
wa_ctx_emit(batch, index, 0);
@@ -1314,8 +1321,8 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring,
uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
/* WaDisableCtxRestoreArbitration:skl,bxt */
- if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) ||
- (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0)))
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1))
wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE);
/* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */
@@ -1340,18 +1347,18 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *ring,
uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
- if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_B0)) ||
- (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) {
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
- wa_ctx_emit(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0);
+ wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0);
wa_ctx_emit(batch, index,
_MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING));
wa_ctx_emit(batch, index, MI_NOOP);
}
/* WaDisableCtxRestoreArbitration:skl,bxt */
- if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) ||
- (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0)))
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1))
wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE);
wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END);
@@ -1418,7 +1425,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring)
return ret;
}
- page = i915_gem_object_get_page(wa_ctx->obj, 0);
+ page = i915_gem_object_get_dirty_page(wa_ctx->obj, 0);
batch = kmap_atomic(page);
offset = 0;
@@ -1472,12 +1479,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
- if (ring->status_page.obj) {
- I915_WRITE(RING_HWS_PGA(ring->mmio_base),
- (u32)ring->status_page.gfx_addr);
- POSTING_READ(RING_HWS_PGA(ring->mmio_base));
- }
-
I915_WRITE(RING_MODE_GEN7(ring),
_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
@@ -1562,9 +1563,9 @@ static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) {
const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
- intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_UDW(ring, i));
+ intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_UDW(ring, i));
intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr));
- intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_LDW(ring, i));
+ intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_LDW(ring, i));
intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr));
}
@@ -1893,8 +1894,10 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
dev_priv = ring->dev->dev_private;
- intel_logical_ring_stop(ring);
- WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
+ if (ring->buffer) {
+ intel_logical_ring_stop(ring);
+ WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
+ }
if (ring->cleanup)
ring->cleanup(ring);
@@ -1908,6 +1911,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
}
lrc_destroy_wa_ctx_obj(ring);
+ ring->dev = NULL;
}
static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
@@ -1923,17 +1927,18 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
i915_gem_batch_pool_init(dev, &ring->batch_pool);
init_waitqueue_head(&ring->irq_queue);
+ INIT_LIST_HEAD(&ring->buffers);
INIT_LIST_HEAD(&ring->execlist_queue);
INIT_LIST_HEAD(&ring->execlist_retired_req_list);
spin_lock_init(&ring->execlist_lock);
ret = i915_cmd_parser_init_ring(ring);
if (ret)
- return ret;
+ goto error;
ret = intel_lr_context_deferred_alloc(ring->default_context, ring);
if (ret)
- return ret;
+ goto error;
/* As this is the default context, always pin it */
ret = intel_lr_context_do_pin(
@@ -1944,9 +1949,13 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
DRM_ERROR(
"Failed to pin and map ringbuffer %s: %d\n",
ring->name, ret);
- return ret;
+ goto error;
}
+ return 0;
+
+error:
+ intel_logical_ring_cleanup(ring);
return ret;
}
@@ -1972,7 +1981,7 @@ static int logical_render_ring_init(struct drm_device *dev)
ring->init_hw = gen8_init_render_ring;
ring->init_context = gen8_init_rcs_context;
ring->cleanup = intel_fini_pipe_control;
- if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
ring->get_seqno = bxt_a_get_seqno;
ring->set_seqno = bxt_a_set_seqno;
} else {
@@ -2024,7 +2033,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
ring->init_hw = gen8_init_common_ring;
- if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
ring->get_seqno = bxt_a_get_seqno;
ring->set_seqno = bxt_a_set_seqno;
} else {
@@ -2079,7 +2088,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
ring->init_hw = gen8_init_common_ring;
- if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
ring->get_seqno = bxt_a_get_seqno;
ring->set_seqno = bxt_a_set_seqno;
} else {
@@ -2109,7 +2118,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
ring->init_hw = gen8_init_common_ring;
- if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
ring->get_seqno = bxt_a_get_seqno;
ring->set_seqno = bxt_a_set_seqno;
} else {
@@ -2255,7 +2264,7 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
/* The second page of the context object contains some fields which must
* be set up prior to the first execution. */
- page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+ page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
/* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM
@@ -2263,46 +2272,31 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
* only for the first context restore: on a subsequent save, the GPU will
* recreate this batchbuffer with new values (including all the missing
* MI_LOAD_REGISTER_IMM commands that we are not initializing here). */
- if (ring->id == RCS)
- reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14);
- else
- reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11);
- reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED;
- reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring);
- reg_state[CTX_CONTEXT_CONTROL+1] =
- _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
- CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
- CTX_CTRL_RS_CTX_ENABLE);
- reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base);
- reg_state[CTX_RING_HEAD+1] = 0;
- reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);
- reg_state[CTX_RING_TAIL+1] = 0;
- reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base);
+ reg_state[CTX_LRI_HEADER_0] =
+ MI_LOAD_REGISTER_IMM(ring->id == RCS ? 14 : 11) | MI_LRI_FORCE_POSTED;
+ ASSIGN_CTX_REG(reg_state, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(ring),
+ _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
+ CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
+ CTX_CTRL_RS_CTX_ENABLE));
+ ASSIGN_CTX_REG(reg_state, CTX_RING_HEAD, RING_HEAD(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_RING_TAIL, RING_TAIL(ring->mmio_base), 0);
/* Ring buffer start address is not known until the buffer is pinned.
* It is written to the context image in execlists_update_context()
*/
- reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base);
- reg_state[CTX_RING_BUFFER_CONTROL+1] =
- ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID;
- reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168;
- reg_state[CTX_BB_HEAD_U+1] = 0;
- reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140;
- reg_state[CTX_BB_HEAD_L+1] = 0;
- reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110;
- reg_state[CTX_BB_STATE+1] = (1<<5);
- reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c;
- reg_state[CTX_SECOND_BB_HEAD_U+1] = 0;
- reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114;
- reg_state[CTX_SECOND_BB_HEAD_L+1] = 0;
- reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118;
- reg_state[CTX_SECOND_BB_STATE+1] = 0;
+ ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_START, RING_START(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_CONTROL, RING_CTL(ring->mmio_base),
+ ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID);
+ ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_U, RING_BBADDR_UDW(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_L, RING_BBADDR(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_BB_STATE, RING_BBSTATE(ring->mmio_base),
+ RING_BB_PPGTT);
+ ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_U, RING_SBBADDR_UDW(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_L, RING_SBBADDR(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_STATE, RING_SBBSTATE(ring->mmio_base), 0);
if (ring->id == RCS) {
- reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0;
- reg_state[CTX_BB_PER_CTX_PTR+1] = 0;
- reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4;
- reg_state[CTX_RCS_INDIRECT_CTX+1] = 0;
- reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8;
- reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0;
+ ASSIGN_CTX_REG(reg_state, CTX_BB_PER_CTX_PTR, RING_BB_PER_CTX_PTR(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX, RING_INDIRECT_CTX(ring->mmio_base), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX_OFFSET, RING_INDIRECT_CTX_OFFSET(ring->mmio_base), 0);
if (ring->wa_ctx.obj) {
struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx;
uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj);
@@ -2319,18 +2313,17 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
0x01;
}
}
- reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9);
- reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED;
- reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8;
- reg_state[CTX_CTX_TIMESTAMP+1] = 0;
- reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3);
- reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3);
- reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2);
- reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2);
- reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1);
- reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1);
- reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
- reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
+ reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9) | MI_LRI_FORCE_POSTED;
+ ASSIGN_CTX_REG(reg_state, CTX_CTX_TIMESTAMP, RING_CTX_TIMESTAMP(ring->mmio_base), 0);
+ /* PDP values well be assigned later if needed */
+ ASSIGN_CTX_REG(reg_state, CTX_PDP3_UDW, GEN8_RING_PDP_UDW(ring, 3), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP3_LDW, GEN8_RING_PDP_LDW(ring, 3), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP2_UDW, GEN8_RING_PDP_UDW(ring, 2), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP2_LDW, GEN8_RING_PDP_LDW(ring, 2), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP1_UDW, GEN8_RING_PDP_UDW(ring, 1), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP1_LDW, GEN8_RING_PDP_LDW(ring, 1), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(ring, 0), 0);
+ ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(ring, 0), 0);
if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
/* 64b PPGTT (48bit canonical)
@@ -2352,14 +2345,11 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
if (ring->id == RCS) {
reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
- reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE;
- reg_state[CTX_R_PWR_CLK_STATE+1] = make_rpcs(dev);
+ ASSIGN_CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE,
+ make_rpcs(dev));
}
kunmap_atomic(reg_state);
-
- ctx_obj->dirty = 1;
- set_page_dirty(page);
i915_gem_object_unpin_pages(ctx_obj);
return 0;
@@ -2543,7 +2533,7 @@ void intel_lr_context_reset(struct drm_device *dev,
WARN(1, "Failed get_pages for context obj\n");
continue;
}
- page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+ page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
reg_state[CTX_RING_HEAD+1] = 0;
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 4e60d54ba66d..0b821b91723a 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -29,16 +29,16 @@
#define GEN8_CSB_PTR_MASK 0x07
/* Execlists regs */
-#define RING_ELSP(ring) ((ring)->mmio_base+0x230)
-#define RING_EXECLIST_STATUS_LO(ring) ((ring)->mmio_base+0x234)
-#define RING_EXECLIST_STATUS_HI(ring) ((ring)->mmio_base+0x234 + 4)
-#define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244)
+#define RING_ELSP(ring) _MMIO((ring)->mmio_base + 0x230)
+#define RING_EXECLIST_STATUS_LO(ring) _MMIO((ring)->mmio_base + 0x234)
+#define RING_EXECLIST_STATUS_HI(ring) _MMIO((ring)->mmio_base + 0x234 + 4)
+#define RING_CONTEXT_CONTROL(ring) _MMIO((ring)->mmio_base + 0x244)
#define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3)
#define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0)
#define CTX_CTRL_RS_CTX_ENABLE (1 << 1)
-#define RING_CONTEXT_STATUS_BUF_LO(ring, i) ((ring)->mmio_base+0x370 + (i) * 8)
-#define RING_CONTEXT_STATUS_BUF_HI(ring, i) ((ring)->mmio_base+0x370 + (i) * 8 + 4)
-#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0)
+#define RING_CONTEXT_STATUS_BUF_LO(ring, i) _MMIO((ring)->mmio_base + 0x370 + (i) * 8)
+#define RING_CONTEXT_STATUS_BUF_HI(ring, i) _MMIO((ring)->mmio_base + 0x370 + (i) * 8 + 4)
+#define RING_CONTEXT_STATUS_PTR(ring) _MMIO((ring)->mmio_base + 0x3a0)
/* Logical Rings */
int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request);
@@ -70,6 +70,11 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
ringbuf->tail += 4;
}
+static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf,
+ i915_reg_t reg)
+{
+ intel_logical_ring_emit(ringbuf, i915_mmio_reg_offset(reg));
+}
/* Logical Ring Contexts */
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 7f39b8ad88ae..0da0240caf81 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -51,7 +51,7 @@ struct intel_lvds_encoder {
struct intel_encoder base;
bool is_dual_link;
- u32 reg;
+ i915_reg_t reg;
u32 a3_power;
struct intel_lvds_connector *attached_connector;
@@ -210,7 +210,7 @@ static void intel_enable_lvds(struct intel_encoder *encoder)
struct intel_connector *intel_connector =
&lvds_encoder->attached_connector->base;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 ctl_reg, stat_reg;
+ i915_reg_t ctl_reg, stat_reg;
if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL;
@@ -235,7 +235,7 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev;
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 ctl_reg, stat_reg;
+ i915_reg_t ctl_reg, stat_reg;
if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL;
@@ -939,7 +939,7 @@ void intel_lvds_init(struct drm_device *dev)
struct drm_display_mode *downclock_mode = NULL;
struct edid *edid;
struct drm_crtc *crtc;
- u32 lvds_reg;
+ i915_reg_t lvds_reg;
u32 lvds;
int pipe;
u8 pin;
@@ -1025,7 +1025,7 @@ void intel_lvds_init(struct drm_device *dev)
DRM_MODE_CONNECTOR_LVDS);
drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
intel_encoder->enable = intel_enable_lvds;
intel_encoder->pre_enable = intel_pre_enable_lvds;
@@ -1164,8 +1164,7 @@ out:
DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
lvds_encoder->is_dual_link ? "dual" : "single");
- lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) &
- LVDS_A3_POWER_MASK;
+ lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK;
lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
index 6d3c6c0a5c62..fed7bea19cc9 100644
--- a/drivers/gpu/drm/i915/intel_mocs.c
+++ b/drivers/gpu/drm/i915/intel_mocs.c
@@ -143,7 +143,7 @@ static bool get_mocs_settings(struct drm_device *dev,
{
bool result = false;
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
table->size = ARRAY_SIZE(skylake_mocs_table);
table->table = skylake_mocs_table;
result = true;
@@ -159,11 +159,30 @@ static bool get_mocs_settings(struct drm_device *dev,
return result;
}
+static i915_reg_t mocs_register(enum intel_ring_id ring, int index)
+{
+ switch (ring) {
+ case RCS:
+ return GEN9_GFX_MOCS(index);
+ case VCS:
+ return GEN9_MFX0_MOCS(index);
+ case BCS:
+ return GEN9_BLT_MOCS(index);
+ case VECS:
+ return GEN9_VEBOX_MOCS(index);
+ case VCS2:
+ return GEN9_MFX1_MOCS(index);
+ default:
+ MISSING_CASE(ring);
+ return INVALID_MMIO_REG;
+ }
+}
+
/**
* emit_mocs_control_table() - emit the mocs control table
* @req: Request to set up the MOCS table for.
* @table: The values to program into the control regs.
- * @reg_base: The base for the engine that needs to be programmed.
+ * @ring: The engine for whom to emit the registers.
*
* This function simply emits a MI_LOAD_REGISTER_IMM command for the
* given table starting at the given address.
@@ -172,7 +191,7 @@ static bool get_mocs_settings(struct drm_device *dev,
*/
static int emit_mocs_control_table(struct drm_i915_gem_request *req,
const struct drm_i915_mocs_table *table,
- u32 reg_base)
+ enum intel_ring_id ring)
{
struct intel_ringbuffer *ringbuf = req->ringbuf;
unsigned int index;
@@ -191,7 +210,7 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req,
MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
for (index = 0; index < table->size; index++) {
- intel_logical_ring_emit(ringbuf, reg_base + index * 4);
+ intel_logical_ring_emit_reg(ringbuf, mocs_register(ring, index));
intel_logical_ring_emit(ringbuf,
table->table[index].control_value);
}
@@ -205,7 +224,7 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req,
* that value to all the used entries.
*/
for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
- intel_logical_ring_emit(ringbuf, reg_base + index * 4);
+ intel_logical_ring_emit_reg(ringbuf, mocs_register(ring, index));
intel_logical_ring_emit(ringbuf, table->table[0].control_value);
}
@@ -253,7 +272,7 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
value = (table->table[count].l3cc_value & 0xffff) |
((table->table[count + 1].l3cc_value & 0xffff) << 16);
- intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4);
+ intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
intel_logical_ring_emit(ringbuf, value);
}
@@ -270,7 +289,7 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
* they are reserved by the hardware.
*/
for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) {
- intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4);
+ intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
intel_logical_ring_emit(ringbuf, value);
value = filler;
@@ -304,26 +323,16 @@ int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req)
int ret;
if (get_mocs_settings(req->ring->dev, &t)) {
- /* Program the control registers */
- ret = emit_mocs_control_table(req, &t, GEN9_GFX_MOCS_0);
- if (ret)
- return ret;
-
- ret = emit_mocs_control_table(req, &t, GEN9_MFX0_MOCS_0);
- if (ret)
- return ret;
+ struct drm_i915_private *dev_priv = req->i915;
+ struct intel_engine_cs *ring;
+ enum intel_ring_id ring_id;
- ret = emit_mocs_control_table(req, &t, GEN9_MFX1_MOCS_0);
- if (ret)
- return ret;
-
- ret = emit_mocs_control_table(req, &t, GEN9_VEBOX_MOCS_0);
- if (ret)
- return ret;
-
- ret = emit_mocs_control_table(req, &t, GEN9_BLT_MOCS_0);
- if (ret)
- return ret;
+ /* Program the control registers */
+ for_each_ring(ring, dev_priv, ring_id) {
+ ret = emit_mocs_control_table(req, &t, ring_id);
+ if (ret)
+ return ret;
+ }
/* Now program the l3cc registers */
ret = emit_mocs_l3cc_table(req, &t);
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 6dc13c02c28e..c15718b4862a 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -26,6 +26,7 @@
*/
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include <acpi/video.h>
#include <drm/drmP.h>
@@ -46,6 +47,7 @@
#define OPREGION_SWSCI_OFFSET 0x200
#define OPREGION_ASLE_OFFSET 0x300
#define OPREGION_VBT_OFFSET 0x400
+#define OPREGION_ASLE_EXT_OFFSET 0x1C00
#define OPREGION_SIGNATURE "IntelGraphicsMem"
#define MBOX_ACPI (1<<0)
@@ -120,7 +122,16 @@ struct opregion_asle {
u64 fdss;
u32 fdsp;
u32 stat;
- u8 rsvd[70];
+ u64 rvda; /* Physical address of raw vbt data */
+ u32 rvds; /* Size of raw vbt data */
+ u8 rsvd[58];
+} __packed;
+
+/* OpRegion mailbox #5: ASLE ext */
+struct opregion_asle_ext {
+ u32 phed; /* Panel Header */
+ u8 bddc[256]; /* Panel EDID */
+ u8 rsvd[764];
} __packed;
/* Driver readiness indicator */
@@ -411,7 +422,7 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_connector *intel_connector;
+ struct intel_connector *connector;
struct opregion_asle *asle = dev_priv->opregion.asle;
DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
@@ -435,8 +446,8 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
* only one).
*/
DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
- list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head)
- intel_panel_set_backlight_acpi(intel_connector, bclp, 255);
+ for_each_intel_connector(dev, connector)
+ intel_panel_set_backlight_acpi(connector, bclp, 255);
asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -682,7 +693,7 @@ static void intel_didl_outputs(struct drm_device *dev)
}
if (!acpi_video_bus) {
- DRM_ERROR("No ACPI video bus found\n");
+ DRM_DEBUG_KMS("No ACPI video bus found\n");
return;
}
@@ -826,6 +837,10 @@ void intel_opregion_fini(struct drm_device *dev)
/* just clear all opregion memory pointers now */
memunmap(opregion->header);
+ if (opregion->rvda) {
+ memunmap(opregion->rvda);
+ opregion->rvda = NULL;
+ }
opregion->header = NULL;
opregion->acpi = NULL;
opregion->swsci = NULL;
@@ -894,6 +909,25 @@ static void swsci_setup(struct drm_device *dev)
static inline void swsci_setup(struct drm_device *dev) {}
#endif /* CONFIG_ACPI */
+static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
+{
+ DRM_DEBUG_KMS("Falling back to manually reading VBT from "
+ "VBIOS ROM for %s\n", id->ident);
+ return 1;
+}
+
+static const struct dmi_system_id intel_no_opregion_vbt[] = {
+ {
+ .callback = intel_no_opregion_vbt_callback,
+ .ident = "ThinkCentre A57",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"),
+ },
+ },
+ { }
+};
+
int intel_opregion_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -907,6 +941,7 @@ int intel_opregion_setup(struct drm_device *dev)
BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100);
BUILD_BUG_ON(sizeof(struct opregion_swsci) != 0x100);
BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100);
+ BUILD_BUG_ON(sizeof(struct opregion_asle_ext) != 0x400);
pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
@@ -931,8 +966,6 @@ int intel_opregion_setup(struct drm_device *dev)
goto err_out;
}
opregion->header = base;
- opregion->vbt = base + OPREGION_VBT_OFFSET;
-
opregion->lid_state = base + ACPI_CLID;
mboxes = opregion->header->mboxes;
@@ -946,6 +979,7 @@ int intel_opregion_setup(struct drm_device *dev)
opregion->swsci = base + OPREGION_SWSCI_OFFSET;
swsci_setup(dev);
}
+
if (mboxes & MBOX_ASLE) {
DRM_DEBUG_DRIVER("ASLE supported\n");
opregion->asle = base + OPREGION_ASLE_OFFSET;
@@ -953,6 +987,37 @@ int intel_opregion_setup(struct drm_device *dev)
opregion->asle->ardy = ASLE_ARDY_NOT_READY;
}
+ if (mboxes & MBOX_ASLE_EXT)
+ DRM_DEBUG_DRIVER("ASLE extension supported\n");
+
+ if (!dmi_check_system(intel_no_opregion_vbt)) {
+ const void *vbt = NULL;
+ u32 vbt_size = 0;
+
+ if (opregion->header->opregion_ver >= 2 && opregion->asle &&
+ opregion->asle->rvda && opregion->asle->rvds) {
+ opregion->rvda = memremap(opregion->asle->rvda,
+ opregion->asle->rvds,
+ MEMREMAP_WB);
+ vbt = opregion->rvda;
+ vbt_size = opregion->asle->rvds;
+ }
+
+ if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
+ DRM_DEBUG_KMS("Found valid VBT in ACPI OpRegion (RVDA)\n");
+ opregion->vbt = vbt;
+ opregion->vbt_size = vbt_size;
+ } else {
+ vbt = base + OPREGION_VBT_OFFSET;
+ vbt_size = OPREGION_ASLE_EXT_OFFSET - OPREGION_VBT_OFFSET;
+ if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
+ DRM_DEBUG_KMS("Found valid VBT in ACPI OpRegion (Mailbox #4)\n");
+ opregion->vbt = vbt;
+ opregion->vbt_size = vbt_size;
+ }
+ }
+ }
+
return 0;
err_out:
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 444542696a2c..76f1980a7541 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -749,7 +749,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
if (ret != 0)
return ret;
- ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, NULL,
+ ret = i915_gem_object_pin_to_display_plane(new_bo, 0,
&i915_ggtt_view_normal);
if (ret != 0)
return ret;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index a24df35e11e7..21ee6477bf98 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -461,8 +461,7 @@ static inline u32 scale_hw_to_user(struct intel_connector *connector,
static u32 intel_panel_compute_brightness(struct intel_connector *connector,
u32 val)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
WARN_ON(panel->backlight.max == 0);
@@ -480,45 +479,40 @@ static u32 intel_panel_compute_brightness(struct intel_connector *connector,
static u32 lpt_get_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
}
static u32 pch_get_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
}
static u32 i9xx_get_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 val;
val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
- if (INTEL_INFO(dev)->gen < 4)
+ if (INTEL_INFO(dev_priv)->gen < 4)
val >>= 1;
if (panel->backlight.combination_mode) {
u8 lbpc;
- pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+ pci_read_config_byte(dev_priv->dev->pdev, PCI_LBPC, &lbpc);
val *= lbpc;
}
return val;
}
-static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe)
+static u32 _vlv_get_backlight(struct drm_i915_private *dev_priv, enum pipe pipe)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
return 0;
@@ -527,17 +521,16 @@ static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe)
static u32 vlv_get_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
enum pipe pipe = intel_get_pipe_from_connector(connector);
- return _vlv_get_backlight(dev, pipe);
+ return _vlv_get_backlight(dev_priv, pipe);
}
static u32 bxt_get_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(BXT_BLC_PWM_DUTY(panel->backlight.controller));
}
@@ -553,8 +546,7 @@ static u32 pwm_get_backlight(struct intel_connector *connector)
static u32 intel_panel_get_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 val = 0;
@@ -573,16 +565,14 @@ static u32 intel_panel_get_backlight(struct intel_connector *connector)
static void lpt_set_backlight(struct intel_connector *connector, u32 level)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
}
static void pch_set_backlight(struct intel_connector *connector, u32 level)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 tmp;
tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
@@ -591,8 +581,7 @@ static void pch_set_backlight(struct intel_connector *connector, u32 level)
static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 tmp, mask;
@@ -603,10 +592,10 @@ static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
lbpc = level * 0xfe / panel->backlight.max + 1;
level /= lbpc;
- pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
+ pci_write_config_byte(dev_priv->dev->pdev, PCI_LBPC, lbpc);
}
- if (IS_GEN4(dev)) {
+ if (IS_GEN4(dev_priv)) {
mask = BACKLIGHT_DUTY_CYCLE_MASK;
} else {
level <<= 1;
@@ -619,8 +608,7 @@ static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
static void vlv_set_backlight(struct intel_connector *connector, u32 level)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
enum pipe pipe = intel_get_pipe_from_connector(connector);
u32 tmp;
@@ -633,8 +621,7 @@ static void vlv_set_backlight(struct intel_connector *connector, u32 level)
static void bxt_set_backlight(struct intel_connector *connector, u32 level)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
I915_WRITE(BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
@@ -663,8 +650,7 @@ intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
static void intel_panel_set_backlight(struct intel_connector *connector,
u32 user_level, u32 user_max)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 hw_level;
@@ -690,8 +676,7 @@ static void intel_panel_set_backlight(struct intel_connector *connector,
void intel_panel_set_backlight_acpi(struct intel_connector *connector,
u32 user_level, u32 user_max)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = intel_get_pipe_from_connector(connector);
u32 hw_level;
@@ -726,8 +711,7 @@ void intel_panel_set_backlight_acpi(struct intel_connector *connector,
static void lpt_disable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 tmp;
intel_panel_actually_set_backlight(connector, 0);
@@ -752,8 +736,7 @@ static void lpt_disable_backlight(struct intel_connector *connector)
static void pch_disable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 tmp;
intel_panel_actually_set_backlight(connector, 0);
@@ -772,8 +755,7 @@ static void i9xx_disable_backlight(struct intel_connector *connector)
static void i965_disable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 tmp;
intel_panel_actually_set_backlight(connector, 0);
@@ -784,8 +766,7 @@ static void i965_disable_backlight(struct intel_connector *connector)
static void vlv_disable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
enum pipe pipe = intel_get_pipe_from_connector(connector);
u32 tmp;
@@ -800,8 +781,7 @@ static void vlv_disable_backlight(struct intel_connector *connector)
static void bxt_disable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 tmp, val;
@@ -830,8 +810,7 @@ static void pwm_disable_backlight(struct intel_connector *connector)
void intel_panel_disable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
if (!panel->backlight.present)
@@ -843,7 +822,7 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
* backlight. This will leave the backlight on unnecessarily when
* another client is not activated.
*/
- if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
+ if (dev_priv->dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
return;
}
@@ -860,8 +839,7 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
static void lpt_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pch_ctl1, pch_ctl2;
@@ -893,8 +871,7 @@ static void lpt_enable_backlight(struct intel_connector *connector)
static void pch_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = intel_get_pipe_from_connector(connector);
enum transcoder cpu_transcoder =
@@ -940,8 +917,7 @@ static void pch_enable_backlight(struct intel_connector *connector)
static void i9xx_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, freq;
@@ -958,7 +934,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
ctl = freq << 17;
if (panel->backlight.combination_mode)
ctl |= BLM_LEGACY_MODE;
- if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
+ if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm)
ctl |= BLM_POLARITY_PNV;
I915_WRITE(BLC_PWM_CTL, ctl);
@@ -972,14 +948,13 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
* 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
* that has backlight.
*/
- if (IS_GEN2(dev))
+ if (IS_GEN2(dev_priv))
I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
}
static void i965_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = intel_get_pipe_from_connector(connector);
u32 ctl, ctl2, freq;
@@ -1012,8 +987,7 @@ static void i965_enable_backlight(struct intel_connector *connector)
static void vlv_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = intel_get_pipe_from_connector(connector);
u32 ctl, ctl2;
@@ -1044,8 +1018,7 @@ static void vlv_enable_backlight(struct intel_connector *connector)
static void bxt_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = intel_get_pipe_from_connector(connector);
u32 pwm_ctl, val;
@@ -1102,8 +1075,7 @@ static void pwm_enable_backlight(struct intel_connector *connector)
void intel_panel_enable_backlight(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = intel_get_pipe_from_connector(connector);
@@ -1264,14 +1236,21 @@ static void intel_backlight_device_unregister(struct intel_connector *connector)
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
/*
+ * BXT: PWM clock frequency = 19.2 MHz.
+ */
+static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
+{
+ return KHz(19200) / pwm_freq_hz;
+}
+
+/*
* SPT: This value represents the period of the PWM stream in clock periods
* multiplied by 16 (default increment) or 128 (alternate increment selected in
* SCHICKEN_1 bit 0). PWM clock is 24 MHz.
*/
static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 mul, clock;
if (I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY)
@@ -1291,8 +1270,7 @@ static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
u32 mul, clock;
if (I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY)
@@ -1300,7 +1278,7 @@ static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
else
mul = 128;
- if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE)
+ if (HAS_PCH_LPT_H(dev_priv))
clock = MHz(135); /* LPT:H */
else
clock = MHz(24); /* LPT:LP */
@@ -1335,22 +1313,28 @@ static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
int clock;
if (IS_PINEVIEW(dev))
- clock = intel_hrawclk(dev);
+ clock = MHz(intel_hrawclk(dev));
else
- clock = 1000 * dev_priv->display.get_display_clock_speed(dev);
+ clock = 1000 * dev_priv->cdclk_freq;
return clock / (pwm_freq_hz * 32);
}
/*
* Gen4: This value represents the period of the PWM stream in display core
- * clocks multiplied by 128.
+ * clocks ([DevCTG] HRAW clocks) multiplied by 128.
+ *
*/
static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int clock = 1000 * dev_priv->display.get_display_clock_speed(dev);
+ int clock;
+
+ if (IS_G4X(dev_priv))
+ clock = MHz(intel_hrawclk(dev));
+ else
+ clock = 1000 * dev_priv->cdclk_freq;
return clock / (pwm_freq_hz * 128);
}
@@ -1379,20 +1363,23 @@ static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
static u32 get_backlight_max_vbt(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
u32 pwm;
- if (!pwm_freq_hz) {
- DRM_DEBUG_KMS("backlight frequency not specified in VBT\n");
+ if (!panel->backlight.hz_to_pwm) {
+ DRM_DEBUG_KMS("backlight frequency conversion not supported\n");
return 0;
}
- if (!panel->backlight.hz_to_pwm) {
- DRM_DEBUG_KMS("backlight frequency setting from VBT currently not supported on this platform\n");
- return 0;
+ if (pwm_freq_hz) {
+ DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n",
+ pwm_freq_hz);
+ } else {
+ pwm_freq_hz = 200;
+ DRM_DEBUG_KMS("default backlight frequency %u Hz\n",
+ pwm_freq_hz);
}
pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
@@ -1401,8 +1388,6 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector)
return 0;
}
- DRM_DEBUG_KMS("backlight frequency %u Hz from VBT\n", pwm_freq_hz);
-
return pwm;
}
@@ -1411,8 +1396,7 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector)
*/
static u32 get_backlight_min_vbt(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
int min;
@@ -1437,8 +1421,7 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector)
static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pch_ctl1, pch_ctl2, val;
@@ -1467,8 +1450,7 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
@@ -1498,17 +1480,16 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, val;
ctl = I915_READ(BLC_PWM_CTL);
- if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
+ if (IS_GEN2(dev_priv) || IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
- if (IS_PINEVIEW(dev))
+ if (IS_PINEVIEW(dev_priv))
panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
panel->backlight.max = ctl >> 17;
@@ -1536,8 +1517,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu
static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, ctl2, val;
@@ -1570,8 +1550,7 @@ static int i965_setup_backlight(struct intel_connector *connector, enum pipe unu
static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, ctl2, val;
@@ -1592,7 +1571,7 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
panel->backlight.min = get_backlight_min_vbt(connector);
- val = _vlv_get_backlight(dev, pipe);
+ val = _vlv_get_backlight(dev_priv, pipe);
panel->backlight.level = intel_panel_compute_brightness(connector, val);
panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
@@ -1604,8 +1583,7 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
static int
bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pwm_ctl, val;
@@ -1683,8 +1661,7 @@ static int pwm_setup_backlight(struct intel_connector *connector,
int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
{
- struct drm_device *dev = connector->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_connector *intel_connector = to_intel_connector(connector);
struct intel_panel *panel = &intel_connector->panel;
int ret;
@@ -1739,35 +1716,35 @@ void intel_panel_destroy_backlight(struct drm_connector *connector)
static void
intel_panel_init_backlight_funcs(struct intel_panel *panel)
{
- struct intel_connector *intel_connector =
+ struct intel_connector *connector =
container_of(panel, struct intel_connector, panel);
- struct drm_device *dev = intel_connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- if (IS_BROXTON(dev)) {
+ if (IS_BROXTON(dev_priv)) {
panel->backlight.setup = bxt_setup_backlight;
panel->backlight.enable = bxt_enable_backlight;
panel->backlight.disable = bxt_disable_backlight;
panel->backlight.set = bxt_set_backlight;
panel->backlight.get = bxt_get_backlight;
- } else if (HAS_PCH_LPT(dev) || HAS_PCH_SPT(dev)) {
+ panel->backlight.hz_to_pwm = bxt_hz_to_pwm;
+ } else if (HAS_PCH_LPT(dev_priv) || HAS_PCH_SPT(dev_priv)) {
panel->backlight.setup = lpt_setup_backlight;
panel->backlight.enable = lpt_enable_backlight;
panel->backlight.disable = lpt_disable_backlight;
panel->backlight.set = lpt_set_backlight;
panel->backlight.get = lpt_get_backlight;
- if (HAS_PCH_LPT(dev))
+ if (HAS_PCH_LPT(dev_priv))
panel->backlight.hz_to_pwm = lpt_hz_to_pwm;
else
panel->backlight.hz_to_pwm = spt_hz_to_pwm;
- } else if (HAS_PCH_SPLIT(dev)) {
+ } else if (HAS_PCH_SPLIT(dev_priv)) {
panel->backlight.setup = pch_setup_backlight;
panel->backlight.enable = pch_enable_backlight;
panel->backlight.disable = pch_disable_backlight;
panel->backlight.set = pch_set_backlight;
panel->backlight.get = pch_get_backlight;
panel->backlight.hz_to_pwm = pch_hz_to_pwm;
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
if (dev_priv->vbt.has_mipi) {
panel->backlight.setup = pwm_setup_backlight;
panel->backlight.enable = pwm_enable_backlight;
@@ -1782,7 +1759,7 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
panel->backlight.get = vlv_get_backlight;
panel->backlight.hz_to_pwm = vlv_hz_to_pwm;
}
- } else if (IS_GEN4(dev)) {
+ } else if (IS_GEN4(dev_priv)) {
panel->backlight.setup = i965_setup_backlight;
panel->backlight.enable = i965_enable_backlight;
panel->backlight.disable = i965_disable_backlight;
@@ -1828,7 +1805,7 @@ void intel_backlight_register(struct drm_device *dev)
{
struct intel_connector *connector;
- list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
+ for_each_intel_connector(dev, connector)
intel_backlight_device_register(connector);
}
@@ -1836,6 +1813,6 @@ void intel_backlight_unregister(struct drm_device *dev)
{
struct intel_connector *connector;
- list_for_each_entry(connector, &dev->mode_config.connector_list, base.head)
+ for_each_intel_connector(dev, connector)
intel_backlight_device_unregister(connector);
}
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index f091ad12d694..eb5fa05cf476 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -66,6 +66,14 @@ static void bxt_init_clock_gating(struct drm_device *dev)
*/
I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
+
+ /*
+ * Wa: Backlight PWM may stop in the asserted state, causing backlight
+ * to stay fully on.
+ */
+ if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER))
+ I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
+ PWM1_GATING_DIS | PWM2_GATING_DIS);
}
static void i915_pineview_get_mem_freq(struct drm_device *dev)
@@ -283,7 +291,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
struct drm_device *dev = dev_priv->dev;
u32 val;
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0);
POSTING_READ(FW_BLC_SELF_VLV);
dev_priv->wm.vlv.cxsr = enable;
@@ -1708,13 +1716,6 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
}
-struct skl_pipe_wm_parameters {
- bool active;
- uint32_t pipe_htotal;
- uint32_t pixel_rate; /* in KHz */
- struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
-};
-
struct ilk_wm_maximums {
uint16_t pri;
uint16_t spr;
@@ -1722,13 +1723,6 @@ struct ilk_wm_maximums {
uint16_t fbc;
};
-/* used in computing the new watermarks state */
-struct intel_wm_config {
- unsigned int num_pipes_active;
- bool sprites_enabled;
- bool sprites_scaled;
-};
-
/*
* For both WM_PIPE and WM_LP.
* mem_value must be in 0.1us units.
@@ -1979,9 +1973,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
const struct intel_crtc *intel_crtc,
int level,
struct intel_crtc_state *cstate,
+ struct intel_plane_state *pristate,
+ struct intel_plane_state *sprstate,
+ struct intel_plane_state *curstate,
struct intel_wm_level *result)
{
- struct intel_plane *intel_plane;
uint16_t pri_latency = dev_priv->wm.pri_latency[level];
uint16_t spr_latency = dev_priv->wm.spr_latency[level];
uint16_t cur_latency = dev_priv->wm.cur_latency[level];
@@ -1993,29 +1989,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
cur_latency *= 5;
}
- for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) {
- struct intel_plane_state *pstate =
- to_intel_plane_state(intel_plane->base.state);
-
- switch (intel_plane->base.type) {
- case DRM_PLANE_TYPE_PRIMARY:
- result->pri_val = ilk_compute_pri_wm(cstate, pstate,
- pri_latency,
- level);
- result->fbc_val = ilk_compute_fbc_wm(cstate, pstate,
- result->pri_val);
- break;
- case DRM_PLANE_TYPE_OVERLAY:
- result->spr_val = ilk_compute_spr_wm(cstate, pstate,
- spr_latency);
- break;
- case DRM_PLANE_TYPE_CURSOR:
- result->cur_val = ilk_compute_cur_wm(cstate, pstate,
- cur_latency);
- break;
- }
- }
-
+ result->pri_val = ilk_compute_pri_wm(cstate, pristate,
+ pri_latency, level);
+ result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency);
+ result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency);
+ result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val);
result->enable = true;
}
@@ -2274,34 +2252,19 @@ static void skl_setup_wm_latency(struct drm_device *dev)
intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
}
-static void ilk_compute_wm_config(struct drm_device *dev,
- struct intel_wm_config *config)
-{
- struct intel_crtc *intel_crtc;
-
- /* Compute the currently _active_ config */
- for_each_intel_crtc(dev, intel_crtc) {
- const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
-
- if (!wm->pipe_enabled)
- continue;
-
- config->sprites_enabled |= wm->sprites_enabled;
- config->sprites_scaled |= wm->sprites_scaled;
- config->num_pipes_active++;
- }
-}
-
/* Compute new watermarks for the pipe */
-static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
- struct intel_pipe_wm *pipe_wm)
+static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
+ struct drm_atomic_state *state)
{
- struct drm_crtc *crtc = cstate->base.crtc;
- struct drm_device *dev = crtc->dev;
+ struct intel_pipe_wm *pipe_wm;
+ struct drm_device *dev = intel_crtc->base.dev;
const struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc_state *cstate = NULL;
struct intel_plane *intel_plane;
+ struct drm_plane_state *ps;
+ struct intel_plane_state *pristate = NULL;
struct intel_plane_state *sprstate = NULL;
+ struct intel_plane_state *curstate = NULL;
int level, max_level = ilk_wm_max_level(dev);
/* LP0 watermark maximums depend on this pipe alone */
struct intel_wm_config config = {
@@ -2309,11 +2272,24 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
};
struct ilk_wm_maximums max;
+ cstate = intel_atomic_get_crtc_state(state, intel_crtc);
+ if (IS_ERR(cstate))
+ return PTR_ERR(cstate);
+
+ pipe_wm = &cstate->wm.optimal.ilk;
+
for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
- if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) {
- sprstate = to_intel_plane_state(intel_plane->base.state);
- break;
- }
+ ps = drm_atomic_get_plane_state(state,
+ &intel_plane->base);
+ if (IS_ERR(ps))
+ return PTR_ERR(ps);
+
+ if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY)
+ pristate = to_intel_plane_state(ps);
+ else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY)
+ sprstate = to_intel_plane_state(ps);
+ else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
+ curstate = to_intel_plane_state(ps);
}
config.sprites_enabled = sprstate->visible;
@@ -2322,7 +2298,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
pipe_wm->pipe_enabled = cstate->base.active;
- pipe_wm->sprites_enabled = sprstate->visible;
+ pipe_wm->sprites_enabled = config.sprites_enabled;
pipe_wm->sprites_scaled = config.sprites_scaled;
/* ILK/SNB: LP2+ watermarks only w/o sprites */
@@ -2333,24 +2309,27 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
if (config.sprites_scaled)
max_level = 0;
- ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]);
+ ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
+ pristate, sprstate, curstate, &pipe_wm->wm[0]);
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
- pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
+ pipe_wm->linetime = hsw_compute_linetime_wm(dev,
+ &intel_crtc->base);
/* LP0 watermarks always use 1/2 DDB partitioning */
ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
/* At least LP0 must be valid */
if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
- return false;
+ return -EINVAL;
ilk_compute_wm_reg_maximums(dev, 1, &max);
for (level = 1; level <= max_level; level++) {
struct intel_wm_level wm = {};
- ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm);
+ ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate,
+ pristate, sprstate, curstate, &wm);
/*
* Disable any watermark level that exceeds the
@@ -2363,7 +2342,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
pipe_wm->wm[level] = wm;
}
- return true;
+ return 0;
}
/*
@@ -2378,7 +2357,9 @@ static void ilk_merge_wm_level(struct drm_device *dev,
ret_wm->enable = true;
for_each_intel_crtc(dev, intel_crtc) {
- const struct intel_pipe_wm *active = &intel_crtc->wm.active;
+ const struct intel_crtc_state *cstate =
+ to_intel_crtc_state(intel_crtc->base.state);
+ const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
const struct intel_wm_level *wm = &active->wm[level];
if (!active->pipe_enabled)
@@ -2449,7 +2430,7 @@ static void ilk_wm_merge(struct drm_device *dev,
* enabled sometime later.
*/
if (IS_GEN5(dev) && !merged->fbc_wm_enabled &&
- intel_fbc_enabled(dev_priv)) {
+ intel_fbc_is_active(dev_priv)) {
for (level = 2; level <= max_level; level++) {
struct intel_wm_level *wm = &merged->wm[level];
@@ -2526,14 +2507,15 @@ static void ilk_compute_wm_results(struct drm_device *dev,
/* LP0 register values */
for_each_intel_crtc(dev, intel_crtc) {
+ const struct intel_crtc_state *cstate =
+ to_intel_crtc_state(intel_crtc->base.state);
enum pipe pipe = intel_crtc->pipe;
- const struct intel_wm_level *r =
- &intel_crtc->wm.active.wm[0];
+ const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0];
if (WARN_ON(!r->enable))
continue;
- results->wm_linetime[pipe] = intel_crtc->wm.active.linetime;
+ results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime;
results->wm_pipe[pipe] =
(r->pri_val << WM0_PIPE_PLANE_SHIFT) |
@@ -2755,18 +2737,40 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
#define SKL_DDB_SIZE 896 /* in blocks */
#define BXT_DDB_SIZE 512
+/*
+ * Return the index of a plane in the SKL DDB and wm result arrays. Primary
+ * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and
+ * other universal planes are in indices 1..n. Note that this may leave unused
+ * indices between the top "sprite" plane and the cursor.
+ */
+static int
+skl_wm_plane_id(const struct intel_plane *plane)
+{
+ switch (plane->base.type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ return 0;
+ case DRM_PLANE_TYPE_CURSOR:
+ return PLANE_CURSOR;
+ case DRM_PLANE_TYPE_OVERLAY:
+ return plane->plane + 1;
+ default:
+ MISSING_CASE(plane->base.type);
+ return plane->plane;
+ }
+}
+
static void
skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
- struct drm_crtc *for_crtc,
+ const struct intel_crtc_state *cstate,
const struct intel_wm_config *config,
- const struct skl_pipe_wm_parameters *params,
struct skl_ddb_entry *alloc /* out */)
{
+ struct drm_crtc *for_crtc = cstate->base.crtc;
struct drm_crtc *crtc;
unsigned int pipe_size, ddb_size;
int nth_active_pipe;
- if (!params->active) {
+ if (!cstate->base.active) {
alloc->start = 0;
alloc->end = 0;
return;
@@ -2837,19 +2841,29 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
}
static unsigned int
-skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y)
+skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
+ const struct drm_plane_state *pstate,
+ int y)
{
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+ struct drm_framebuffer *fb = pstate->fb;
/* for planar format */
- if (p->y_bytes_per_pixel) {
+ if (fb->pixel_format == DRM_FORMAT_NV12) {
if (y) /* y-plane data rate */
- return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel;
+ return intel_crtc->config->pipe_src_w *
+ intel_crtc->config->pipe_src_h *
+ drm_format_plane_cpp(fb->pixel_format, 0);
else /* uv-plane data rate */
- return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel;
+ return (intel_crtc->config->pipe_src_w/2) *
+ (intel_crtc->config->pipe_src_h/2) *
+ drm_format_plane_cpp(fb->pixel_format, 1);
}
/* for packed formats */
- return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
+ return intel_crtc->config->pipe_src_w *
+ intel_crtc->config->pipe_src_h *
+ drm_format_plane_cpp(fb->pixel_format, 0);
}
/*
@@ -2858,46 +2872,55 @@ skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y)
* 3 * 4096 * 8192 * 4 < 2^32
*/
static unsigned int
-skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
- const struct skl_pipe_wm_parameters *params)
+skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate)
{
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+ struct drm_device *dev = intel_crtc->base.dev;
+ const struct intel_plane *intel_plane;
unsigned int total_data_rate = 0;
- int plane;
- for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
- const struct intel_plane_wm_parameters *p;
+ for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+ const struct drm_plane_state *pstate = intel_plane->base.state;
- p = &params->plane[plane];
- if (!p->enabled)
+ if (pstate->fb == NULL)
continue;
- total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */
- if (p->y_bytes_per_pixel) {
- total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */
- }
+ if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
+ continue;
+
+ /* packed/uv */
+ total_data_rate += skl_plane_relative_data_rate(cstate,
+ pstate,
+ 0);
+
+ if (pstate->fb->pixel_format == DRM_FORMAT_NV12)
+ /* y-plane */
+ total_data_rate += skl_plane_relative_data_rate(cstate,
+ pstate,
+ 1);
}
return total_data_rate;
}
static void
-skl_allocate_pipe_ddb(struct drm_crtc *crtc,
- const struct intel_wm_config *config,
- const struct skl_pipe_wm_parameters *params,
+skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
struct skl_ddb_allocation *ddb /* out */)
{
+ struct drm_crtc *crtc = cstate->base.crtc;
struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_wm_config *config = &dev_priv->wm.config;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_plane *intel_plane;
enum pipe pipe = intel_crtc->pipe;
struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
uint16_t alloc_size, start, cursor_blocks;
uint16_t minimum[I915_MAX_PLANES];
uint16_t y_minimum[I915_MAX_PLANES];
unsigned int total_data_rate;
- int plane;
- skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc);
+ skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc);
alloc_size = skl_ddb_entry_size(alloc);
if (alloc_size == 0) {
memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
@@ -2914,17 +2937,20 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
alloc->end -= cursor_blocks;
/* 1. Allocate the mininum required blocks for each active plane */
- for_each_plane(dev_priv, pipe, plane) {
- const struct intel_plane_wm_parameters *p;
+ for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+ struct drm_plane *plane = &intel_plane->base;
+ struct drm_framebuffer *fb = plane->state->fb;
+ int id = skl_wm_plane_id(intel_plane);
- p = &params->plane[plane];
- if (!p->enabled)
+ if (fb == NULL)
+ continue;
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
continue;
- minimum[plane] = 8;
- alloc_size -= minimum[plane];
- y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0;
- alloc_size -= y_minimum[plane];
+ minimum[id] = 8;
+ alloc_size -= minimum[id];
+ y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
+ alloc_size -= y_minimum[id];
}
/*
@@ -2933,45 +2959,50 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
*
* FIXME: we may not allocate every single block here.
*/
- total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
+ total_data_rate = skl_get_total_relative_data_rate(cstate);
start = alloc->start;
- for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
- const struct intel_plane_wm_parameters *p;
+ for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+ struct drm_plane *plane = &intel_plane->base;
+ struct drm_plane_state *pstate = intel_plane->base.state;
unsigned int data_rate, y_data_rate;
uint16_t plane_blocks, y_plane_blocks = 0;
+ int id = skl_wm_plane_id(intel_plane);
- p = &params->plane[plane];
- if (!p->enabled)
+ if (pstate->fb == NULL)
+ continue;
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
continue;
- data_rate = skl_plane_relative_data_rate(p, 0);
+ data_rate = skl_plane_relative_data_rate(cstate, pstate, 0);
/*
* allocation for (packed formats) or (uv-plane part of planar format):
* promote the expression to 64 bits to avoid overflowing, the
* result is < available as data_rate / total_data_rate < 1
*/
- plane_blocks = minimum[plane];
+ plane_blocks = minimum[id];
plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
total_data_rate);
- ddb->plane[pipe][plane].start = start;
- ddb->plane[pipe][plane].end = start + plane_blocks;
+ ddb->plane[pipe][id].start = start;
+ ddb->plane[pipe][id].end = start + plane_blocks;
start += plane_blocks;
/*
* allocation for y_plane part of planar format:
*/
- if (p->y_bytes_per_pixel) {
- y_data_rate = skl_plane_relative_data_rate(p, 1);
- y_plane_blocks = y_minimum[plane];
+ if (pstate->fb->pixel_format == DRM_FORMAT_NV12) {
+ y_data_rate = skl_plane_relative_data_rate(cstate,
+ pstate,
+ 1);
+ y_plane_blocks = y_minimum[id];
y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate,
total_data_rate);
- ddb->y_plane[pipe][plane].start = start;
- ddb->y_plane[pipe][plane].end = start + y_plane_blocks;
+ ddb->y_plane[pipe][id].start = start;
+ ddb->y_plane[pipe][id].end = start + y_plane_blocks;
start += y_plane_blocks;
}
@@ -3041,104 +3072,27 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
- enum pipe pipe = intel_crtc->pipe;
- if (memcmp(new_ddb->plane[pipe], cur_ddb->plane[pipe],
- sizeof(new_ddb->plane[pipe])))
- return true;
-
- if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR],
- sizeof(new_ddb->plane[pipe][PLANE_CURSOR])))
+ /*
+ * If ddb allocation of pipes changed, it may require recalculation of
+ * watermarks
+ */
+ if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe)))
return true;
return false;
}
-static void skl_compute_wm_global_parameters(struct drm_device *dev,
- struct intel_wm_config *config)
-{
- struct drm_crtc *crtc;
- struct drm_plane *plane;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- config->num_pipes_active += to_intel_crtc(crtc)->active;
-
- /* FIXME: I don't think we need those two global parameters on SKL */
- list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- struct intel_plane *intel_plane = to_intel_plane(plane);
-
- config->sprites_enabled |= intel_plane->wm.enabled;
- config->sprites_scaled |= intel_plane->wm.scaled;
- }
-}
-
-static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
- struct skl_pipe_wm_parameters *p)
-{
- struct drm_device *dev = crtc->dev;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_plane *plane;
- struct drm_framebuffer *fb;
- int i = 1; /* Index for sprite planes start */
-
- p->active = intel_crtc->active;
- if (p->active) {
- p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
- p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
-
- fb = crtc->primary->state->fb;
- /* For planar: Bpp is for uv plane, y_Bpp is for y plane */
- if (fb) {
- p->plane[0].enabled = true;
- p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
- drm_format_plane_cpp(fb->pixel_format, 1) :
- drm_format_plane_cpp(fb->pixel_format, 0);
- p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
- drm_format_plane_cpp(fb->pixel_format, 0) : 0;
- p->plane[0].tiling = fb->modifier[0];
- } else {
- p->plane[0].enabled = false;
- p->plane[0].bytes_per_pixel = 0;
- p->plane[0].y_bytes_per_pixel = 0;
- p->plane[0].tiling = DRM_FORMAT_MOD_NONE;
- }
- p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
- p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
- p->plane[0].rotation = crtc->primary->state->rotation;
-
- fb = crtc->cursor->state->fb;
- p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0;
- if (fb) {
- p->plane[PLANE_CURSOR].enabled = true;
- p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8;
- p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w;
- p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h;
- } else {
- p->plane[PLANE_CURSOR].enabled = false;
- p->plane[PLANE_CURSOR].bytes_per_pixel = 0;
- p->plane[PLANE_CURSOR].horiz_pixels = 64;
- p->plane[PLANE_CURSOR].vert_pixels = 64;
- }
- }
-
- list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- struct intel_plane *intel_plane = to_intel_plane(plane);
-
- if (intel_plane->pipe == pipe &&
- plane->type == DRM_PLANE_TYPE_OVERLAY)
- p->plane[i++] = intel_plane->wm;
- }
-}
-
static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
- struct skl_pipe_wm_parameters *p,
- struct intel_plane_wm_parameters *p_params,
+ struct intel_crtc_state *cstate,
+ struct intel_plane *intel_plane,
uint16_t ddb_allocation,
int level,
uint16_t *out_blocks, /* out */
uint8_t *out_lines /* out */)
{
+ struct drm_plane *plane = &intel_plane->base;
+ struct drm_framebuffer *fb = plane->state->fb;
uint32_t latency = dev_priv->wm.skl_latency[level];
uint32_t method1, method2;
uint32_t plane_bytes_per_line, plane_blocks_per_line;
@@ -3146,31 +3100,33 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
uint32_t selected_result;
uint8_t bytes_per_pixel;
- if (latency == 0 || !p->active || !p_params->enabled)
+ if (latency == 0 || !cstate->base.active || !fb)
return false;
- bytes_per_pixel = p_params->y_bytes_per_pixel ?
- p_params->y_bytes_per_pixel :
- p_params->bytes_per_pixel;
- method1 = skl_wm_method1(p->pixel_rate,
+ bytes_per_pixel = drm_format_plane_cpp(fb->pixel_format, 0);
+ method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
bytes_per_pixel,
latency);
- method2 = skl_wm_method2(p->pixel_rate,
- p->pipe_htotal,
- p_params->horiz_pixels,
+ method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
+ cstate->base.adjusted_mode.crtc_htotal,
+ cstate->pipe_src_w,
bytes_per_pixel,
- p_params->tiling,
+ fb->modifier[0],
latency);
- plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel;
+ plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel;
plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
- if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
- p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
+ if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+ fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
uint32_t min_scanlines = 4;
uint32_t y_tile_minimum;
- if (intel_rotation_90_or_270(p_params->rotation)) {
- switch (p_params->bytes_per_pixel) {
+ if (intel_rotation_90_or_270(plane->state->rotation)) {
+ int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
+ drm_format_plane_cpp(fb->pixel_format, 1) :
+ drm_format_plane_cpp(fb->pixel_format, 0);
+
+ switch (bpp) {
case 1:
min_scanlines = 16;
break;
@@ -3194,8 +3150,8 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
if (level >= 1 && level <= 7) {
- if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
- p_params->tiling == I915_FORMAT_MOD_Yf_TILED)
+ if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+ fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)
res_lines += 4;
else
res_blocks++;
@@ -3212,84 +3168,80 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
struct skl_ddb_allocation *ddb,
- struct skl_pipe_wm_parameters *p,
- enum pipe pipe,
+ struct intel_crtc_state *cstate,
int level,
- int num_planes,
struct skl_wm_level *result)
{
+ struct drm_device *dev = dev_priv->dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+ struct intel_plane *intel_plane;
uint16_t ddb_blocks;
- int i;
+ enum pipe pipe = intel_crtc->pipe;
+
+ for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+ int i = skl_wm_plane_id(intel_plane);
- for (i = 0; i < num_planes; i++) {
ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]);
result->plane_en[i] = skl_compute_plane_wm(dev_priv,
- p, &p->plane[i],
+ cstate,
+ intel_plane,
ddb_blocks,
level,
&result->plane_res_b[i],
&result->plane_res_l[i]);
}
-
- ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]);
- result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p,
- &p->plane[PLANE_CURSOR],
- ddb_blocks, level,
- &result->plane_res_b[PLANE_CURSOR],
- &result->plane_res_l[PLANE_CURSOR]);
}
static uint32_t
-skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p)
+skl_compute_linetime_wm(struct intel_crtc_state *cstate)
{
- if (!to_intel_crtc(crtc)->active)
+ if (!cstate->base.active)
return 0;
- if (WARN_ON(p->pixel_rate == 0))
+ if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0))
return 0;
- return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
+ return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000,
+ skl_pipe_pixel_rate(cstate));
}
-static void skl_compute_transition_wm(struct drm_crtc *crtc,
- struct skl_pipe_wm_parameters *params,
+static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
struct skl_wm_level *trans_wm /* out */)
{
+ struct drm_crtc *crtc = cstate->base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int i;
+ struct intel_plane *intel_plane;
- if (!params->active)
+ if (!cstate->base.active)
return;
/* Until we know more, just disable transition WMs */
- for (i = 0; i < intel_num_planes(intel_crtc); i++)
+ for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) {
+ int i = skl_wm_plane_id(intel_plane);
+
trans_wm->plane_en[i] = false;
- trans_wm->plane_en[PLANE_CURSOR] = false;
+ }
}
-static void skl_compute_pipe_wm(struct drm_crtc *crtc,
+static void skl_compute_pipe_wm(struct intel_crtc_state *cstate,
struct skl_ddb_allocation *ddb,
- struct skl_pipe_wm_parameters *params,
struct skl_pipe_wm *pipe_wm)
{
- struct drm_device *dev = crtc->dev;
+ struct drm_device *dev = cstate->base.crtc->dev;
const struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int level, max_level = ilk_wm_max_level(dev);
for (level = 0; level <= max_level; level++) {
- skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe,
- level, intel_num_planes(intel_crtc),
- &pipe_wm->wm[level]);
+ skl_compute_wm_level(dev_priv, ddb, cstate,
+ level, &pipe_wm->wm[level]);
}
- pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
+ pipe_wm->linetime = skl_compute_linetime_wm(cstate);
- skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm);
+ skl_compute_transition_wm(cstate, &pipe_wm->trans_wm);
}
static void skl_compute_wm_results(struct drm_device *dev,
- struct skl_pipe_wm_parameters *p,
struct skl_pipe_wm *p_wm,
struct skl_wm_values *r,
struct intel_crtc *intel_crtc)
@@ -3346,7 +3298,8 @@ static void skl_compute_wm_results(struct drm_device *dev,
r->wm_linetime[pipe] = p_wm->linetime;
}
-static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg,
+static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
+ i915_reg_t reg,
const struct skl_ddb_entry *entry)
{
if (entry->end)
@@ -3361,7 +3314,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
struct drm_device *dev = dev_priv->dev;
struct intel_crtc *crtc;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+ for_each_intel_crtc(dev, crtc) {
int i, level, max_level = ilk_wm_max_level(dev);
enum pipe pipe = crtc->pipe;
@@ -3533,28 +3486,25 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
}
static bool skl_update_pipe_wm(struct drm_crtc *crtc,
- struct skl_pipe_wm_parameters *params,
- struct intel_wm_config *config,
struct skl_ddb_allocation *ddb, /* out */
struct skl_pipe_wm *pipe_wm /* out */)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
- skl_compute_wm_pipe_parameters(crtc, params);
- skl_allocate_pipe_ddb(crtc, config, params, ddb);
- skl_compute_pipe_wm(crtc, ddb, params, pipe_wm);
+ skl_allocate_pipe_ddb(cstate, ddb);
+ skl_compute_pipe_wm(cstate, ddb, pipe_wm);
- if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm)))
+ if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm)))
return false;
- intel_crtc->wm.skl_active = *pipe_wm;
+ intel_crtc->wm.active.skl = *pipe_wm;
return true;
}
static void skl_update_other_pipe_wm(struct drm_device *dev,
struct drm_crtc *crtc,
- struct intel_wm_config *config,
struct skl_wm_values *r)
{
struct intel_crtc *intel_crtc;
@@ -3573,9 +3523,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
* Otherwise, because of this_crtc being freshly enabled/disabled, the
* other active pipes need new DDB allocation and WM values.
*/
- list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
- base.head) {
- struct skl_pipe_wm_parameters params = {};
+ for_each_intel_crtc(dev, intel_crtc) {
struct skl_pipe_wm pipe_wm = {};
bool wm_changed;
@@ -3586,7 +3534,6 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
continue;
wm_changed = skl_update_pipe_wm(&intel_crtc->base,
- &params, config,
&r->ddb, &pipe_wm);
/*
@@ -3596,7 +3543,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
*/
WARN_ON(!wm_changed);
- skl_compute_wm_results(dev, &params, &pipe_wm, r, intel_crtc);
+ skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
r->dirty[intel_crtc->pipe] = true;
}
}
@@ -3626,10 +3573,9 @@ static void skl_update_wm(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct skl_pipe_wm_parameters params = {};
struct skl_wm_values *results = &dev_priv->wm.skl_results;
- struct skl_pipe_wm pipe_wm = {};
- struct intel_wm_config config = {};
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+ struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl;
/* Clear all dirty flags */
@@ -3637,16 +3583,13 @@ static void skl_update_wm(struct drm_crtc *crtc)
skl_clear_wm(results, intel_crtc->pipe);
- skl_compute_wm_global_parameters(dev, &config);
-
- if (!skl_update_pipe_wm(crtc, &params, &config,
- &results->ddb, &pipe_wm))
+ if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
return;
- skl_compute_wm_results(dev, &params, &pipe_wm, results, intel_crtc);
+ skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
results->dirty[intel_crtc->pipe] = true;
- skl_update_other_pipe_wm(dev, crtc, &config, results);
+ skl_update_other_pipe_wm(dev, crtc, results);
skl_write_wm_values(dev_priv, results);
skl_flush_wm_values(dev_priv, results);
@@ -3654,71 +3597,23 @@ static void skl_update_wm(struct drm_crtc *crtc)
dev_priv->wm.skl_hw = *results;
}
-static void
-skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
- uint32_t sprite_width, uint32_t sprite_height,
- int pixel_size, bool enabled, bool scaled)
-{
- struct intel_plane *intel_plane = to_intel_plane(plane);
- struct drm_framebuffer *fb = plane->state->fb;
-
- intel_plane->wm.enabled = enabled;
- intel_plane->wm.scaled = scaled;
- intel_plane->wm.horiz_pixels = sprite_width;
- intel_plane->wm.vert_pixels = sprite_height;
- intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE;
-
- /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */
- intel_plane->wm.bytes_per_pixel =
- (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
- drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size;
- intel_plane->wm.y_bytes_per_pixel =
- (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
- drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0;
-
- /*
- * Framebuffer can be NULL on plane disable, but it does not
- * matter for watermarks if we assume no tiling in that case.
- */
- if (fb)
- intel_plane->wm.tiling = fb->modifier[0];
- intel_plane->wm.rotation = plane->state->rotation;
-
- skl_update_wm(crtc);
-}
-
-static void ilk_update_wm(struct drm_crtc *crtc)
+static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_device *dev = dev_priv->dev;
+ struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
struct ilk_wm_maximums max;
+ struct intel_wm_config *config = &dev_priv->wm.config;
struct ilk_wm_values results = {};
enum intel_ddb_partitioning partitioning;
- struct intel_pipe_wm pipe_wm = {};
- struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
- struct intel_wm_config config = {};
-
- WARN_ON(cstate->base.active != intel_crtc->active);
- intel_compute_pipe_wm(cstate, &pipe_wm);
-
- if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
- return;
-
- intel_crtc->wm.active = pipe_wm;
-
- ilk_compute_wm_config(dev, &config);
-
- ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max);
- ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
+ ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max);
+ ilk_wm_merge(dev, config, &max, &lp_wm_1_2);
/* 5/6 split only in single pipe config on IVB+ */
if (INTEL_INFO(dev)->gen >= 7 &&
- config.num_pipes_active == 1 && config.sprites_enabled) {
- ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
- ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
+ config->num_pipes_active == 1 && config->sprites_enabled) {
+ ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max);
+ ilk_wm_merge(dev, config, &max, &lp_wm_5_6);
best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
} else {
@@ -3733,14 +3628,13 @@ static void ilk_update_wm(struct drm_crtc *crtc)
ilk_write_wm_values(dev_priv, &results);
}
-static void
-ilk_update_sprite_wm(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width, uint32_t sprite_height,
- int pixel_size, bool enabled, bool scaled)
+static void ilk_update_wm(struct drm_crtc *crtc)
{
- struct drm_device *dev = plane->dev;
- struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+
+ WARN_ON(cstate->base.active != intel_crtc->active);
/*
* IVB workaround: must disable low power watermarks for at least
@@ -3749,10 +3643,14 @@ ilk_update_sprite_wm(struct drm_plane *plane,
*
* WaCxSRDisabledForSpriteScaling:ivb
*/
- if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
- intel_wait_for_vblank(dev, intel_plane->pipe);
+ if (cstate->disable_lp_wm) {
+ ilk_disable_lp_wm(crtc->dev);
+ intel_wait_for_vblank(crtc->dev, intel_crtc->pipe);
+ }
+
+ intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
- ilk_update_wm(crtc);
+ ilk_program_watermarks(dev_priv);
}
static void skl_pipe_wm_active_state(uint32_t val,
@@ -3805,7 +3703,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct skl_wm_values *hw = &dev_priv->wm.skl_hw;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct skl_pipe_wm *active = &intel_crtc->wm.skl_active;
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+ struct skl_pipe_wm *active = &cstate->wm.optimal.skl;
enum pipe pipe = intel_crtc->pipe;
int level, i, max_level;
uint32_t temp;
@@ -3849,6 +3748,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
temp = hw->plane_trans[pipe][PLANE_CURSOR];
skl_pipe_wm_active_state(temp, active, true, true, i, 0);
+
+ intel_crtc->wm.active.skl = *active;
}
void skl_wm_get_hw_state(struct drm_device *dev)
@@ -3868,9 +3769,10 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct ilk_wm_values *hw = &dev_priv->wm.hw;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_pipe_wm *active = &intel_crtc->wm.active;
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+ struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
enum pipe pipe = intel_crtc->pipe;
- static const unsigned int wm0_pipe_reg[] = {
+ static const i915_reg_t wm0_pipe_reg[] = {
[PIPE_A] = WM0_PIPEA_ILK,
[PIPE_B] = WM0_PIPEB_ILK,
[PIPE_C] = WM0_PIPEC_IVB,
@@ -3907,6 +3809,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
for (level = 0; level <= max_level; level++)
active->wm[level].enable = true;
}
+
+ intel_crtc->wm.active.ilk = *active;
}
#define _FW_WM(value, plane) \
@@ -4132,21 +4036,6 @@ void intel_update_watermarks(struct drm_crtc *crtc)
dev_priv->display.update_wm(crtc);
}
-void intel_update_sprite_watermarks(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width,
- uint32_t sprite_height,
- int pixel_size,
- bool enabled, bool scaled)
-{
- struct drm_i915_private *dev_priv = plane->dev->dev_private;
-
- if (dev_priv->display.update_sprite_wm)
- dev_priv->display.update_sprite_wm(plane, crtc,
- sprite_width, sprite_height,
- pixel_size, enabled, scaled);
-}
-
/**
* Lock protecting IPS related data structures
*/
@@ -4414,7 +4303,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
struct drm_i915_private *dev_priv = dev->dev_private;
/* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
- if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0))
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
return;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
@@ -4515,7 +4404,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
mutex_lock(&dev_priv->rps.hw_lock);
if (dev_priv->rps.enabled) {
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
vlv_set_rps_idle(dev_priv);
else
gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
@@ -4568,7 +4457,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv,
void intel_set_rps(struct drm_device *dev, u8 val)
{
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
valleyview_set_rps(dev, val);
else
gen6_set_rps(dev, val);
@@ -4612,7 +4501,7 @@ static void valleyview_disable_rps(struct drm_device *dev)
static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
{
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
if (mode & (GEN7_RC_CTL_TO_MODE | GEN6_RC_CTL_EI_MODE(1)))
mode = GEN6_RC_CTL_RC6_ENABLE;
else
@@ -4689,7 +4578,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
dev_priv->rps.max_freq = dev_priv->rps.rp0_freq;
dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
- if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) {
+ if (IS_HASWELL(dev) || IS_BROADWELL(dev) ||
+ IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
ret = sandybridge_pcode_read(dev_priv,
HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
&ddcc_status);
@@ -4701,7 +4591,7 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
dev_priv->rps.max_freq);
}
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
/* Store the frequency values in 16.66 MHZ units, which is
the natural hardware unit for SKL */
dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
@@ -4738,7 +4628,7 @@ static void gen9_enable_rps(struct drm_device *dev)
gen6_init_rps_frequencies(dev);
/* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
- if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
return;
}
@@ -4806,8 +4696,8 @@ static void gen9_enable_rc6(struct drm_device *dev)
DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
"on" : "off");
/* WaRsUseTimeoutMode */
- if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) {
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */
I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
GEN7_RC_CTL_TO_MODE |
@@ -5055,7 +4945,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev)
/* convert DDR frequency from units of 266.6MHz to bandwidth */
min_ring_freq = mult_frac(min_ring_freq, 8, 3);
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
/* Convert GT frequency to 50 HZ units */
min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER;
max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER;
@@ -5073,7 +4963,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev)
int diff = max_gpu_freq - gpu_freq;
unsigned int ia_freq = 0, ring_freq = 0;
- if (IS_SKYLAKE(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
/*
* ring_freq = 2 * GT. ring_freq is in 100MHz units
* No floor required for ring frequency on SKL.
@@ -5208,7 +5098,17 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
static int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
{
- return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
+ u32 val;
+
+ val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
+ /*
+ * According to the BYT Punit GPU turbo HAS 1.1.6.3 the minimum value
+ * for the minimum frequency in GPLL mode is 0xc1. Contrary to this on
+ * a BYT-M B0 the above register contains 0xbf. Moreover when setting
+ * a frequency Punit will not allow values below 0xc0. Clamp it 0xc0
+ * to make sure it matches what Punit accepts.
+ */
+ return max_t(u32, val, 0xc0);
}
/* Check that the pctx buffer wasn't move under us. */
@@ -6113,7 +6013,17 @@ static void intel_init_emon(struct drm_device *dev)
void intel_init_gt_powersave(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6);
+ /*
+ * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
+ * requirement.
+ */
+ if (!i915.enable_rc6) {
+ DRM_INFO("RC6 disabled, disabling runtime PM support\n");
+ intel_runtime_pm_get(dev_priv);
+ }
if (IS_CHERRYVIEW(dev))
cherryview_init_gt_powersave(dev);
@@ -6123,10 +6033,15 @@ void intel_init_gt_powersave(struct drm_device *dev)
void intel_cleanup_gt_powersave(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
if (IS_CHERRYVIEW(dev))
return;
else if (IS_VALLEYVIEW(dev))
valleyview_cleanup_gt_powersave(dev);
+
+ if (!i915.enable_rc6)
+ intel_runtime_pm_put(dev_priv);
}
static void gen6_suspend_rps(struct drm_device *dev)
@@ -6201,7 +6116,7 @@ static void intel_gen6_powersave_work(struct work_struct *work)
} else if (INTEL_INFO(dev)->gen >= 9) {
gen9_enable_rc6(dev);
gen9_enable_rps(dev);
- if (IS_SKYLAKE(dev))
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
__gen6_update_ring_freq(dev);
} else if (IS_BROADWELL(dev)) {
gen8_enable_rps(dev);
@@ -7057,7 +6972,6 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->display.init_clock_gating =
bxt_init_clock_gating;
dev_priv->display.update_wm = skl_update_wm;
- dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
} else if (HAS_PCH_SPLIT(dev)) {
ilk_setup_wm_latency(dev);
@@ -7066,7 +6980,7 @@ void intel_init_pm(struct drm_device *dev)
(!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
dev_priv->display.update_wm = ilk_update_wm;
- dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
+ dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");
@@ -7331,4 +7245,6 @@ void intel_pm_setup(struct drm_device *dev)
INIT_LIST_HEAD(&dev_priv->rps.mmioflips.link);
dev_priv->pm.suspended = false;
+ atomic_set(&dev_priv->pm.wakeref_count, 0);
+ atomic_set(&dev_priv->pm.atomic_seq, 0);
}
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 213581c215b3..9ccff3011523 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -80,7 +80,7 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
+ i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
uint32_t *data = (uint32_t *) vsc_psr;
unsigned int i;
@@ -151,13 +151,31 @@ static void vlv_psr_enable_sink(struct intel_dp *intel_dp)
DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
}
+static i915_reg_t psr_aux_ctl_reg(struct drm_i915_private *dev_priv,
+ enum port port)
+{
+ if (INTEL_INFO(dev_priv)->gen >= 9)
+ return DP_AUX_CH_CTL(port);
+ else
+ return EDP_PSR_AUX_CTL;
+}
+
+static i915_reg_t psr_aux_data_reg(struct drm_i915_private *dev_priv,
+ enum port port, int index)
+{
+ if (INTEL_INFO(dev_priv)->gen >= 9)
+ return DP_AUX_CH_DATA(port, index);
+ else
+ return EDP_PSR_AUX_DATA(index);
+}
+
static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t aux_clock_divider;
- uint32_t aux_data_reg, aux_ctl_reg;
+ i915_reg_t aux_ctl_reg;
int precharge = 0x3;
static const uint8_t aux_msg[] = {
[0] = DP_AUX_NATIVE_WRITE << 4,
@@ -166,29 +184,24 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
[3] = 1 - 1,
[4] = DP_SET_POWER_D0,
};
+ enum port port = dig_port->port;
int i;
BUILD_BUG_ON(sizeof(aux_msg) > 20);
aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
- drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
- DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
-
/* Enable AUX frame sync at sink */
if (dev_priv->psr.aux_frame_sync)
drm_dp_dpcd_writeb(&intel_dp->aux,
DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF,
DP_AUX_FRAME_SYNC_ENABLE);
- aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ?
- DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev);
- aux_ctl_reg = (INTEL_INFO(dev)->gen >= 9) ?
- DPA_AUX_CH_CTL : EDP_PSR_AUX_CTL(dev);
+ aux_ctl_reg = psr_aux_ctl_reg(dev_priv, port);
/* Setup AUX registers */
for (i = 0; i < sizeof(aux_msg); i += 4)
- I915_WRITE(aux_data_reg + i,
+ I915_WRITE(psr_aux_data_reg(dev_priv, port, i >> 2),
intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
if (INTEL_INFO(dev)->gen >= 9) {
@@ -254,30 +267,20 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t max_sleep_time = 0x1f;
- /* Lately it was identified that depending on panel idle frame count
- * calculated at HW can be off by 1. So let's use what came
- * from VBT + 1.
- * There are also other cases where panel demands at least 4
- * but VBT is not being set. To cover these 2 cases lets use
- * at least 5 when VBT isn't set to be on the safest side.
+ /*
+ * Let's respect VBT in case VBT asks a higher idle_frame value.
+ * Let's use 6 as the minimum to cover all known cases including
+ * the off-by-one issue that HW has in some cases. Also there are
+ * cases where sink should be able to train
+ * with the 5 or 6 idle patterns.
*/
- uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ?
- dev_priv->vbt.psr.idle_frames + 1 : 5;
+ uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames);
uint32_t val = 0x0;
- const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
-
- if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) {
- /* It doesn't mean we shouldn't send TPS patters, so let's
- send the minimal TP1 possible and skip TP2. */
- val |= EDP_PSR_TP1_TIME_100us;
- val |= EDP_PSR_TP2_TP3_TIME_0us;
- val |= EDP_PSR_SKIP_AUX_EXIT;
- /* Sink should be able to train with the 5 or 6 idle patterns */
- idle_frames += 4;
- }
- I915_WRITE(EDP_PSR_CTL(dev), val |
- (IS_BROADWELL(dev) ? 0 : link_entry_time) |
+ if (IS_HASWELL(dev))
+ val |= EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
+
+ I915_WRITE(EDP_PSR_CTL, val |
max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
EDP_PSR_ENABLE);
@@ -324,8 +327,8 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
return false;
}
- if (!IS_VALLEYVIEW(dev) && ((dev_priv->vbt.psr.full_link) ||
- (dig_port->port != PORT_A))) {
+ if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
+ ((dev_priv->vbt.psr.full_link) || (dig_port->port != PORT_A))) {
DRM_DEBUG_KMS("PSR condition failed: Link Standby requested/needed but not supported on this platform\n");
return false;
}
@@ -340,7 +343,7 @@ static void intel_psr_activate(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
+ WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
WARN_ON(dev_priv->psr.active);
lockdep_assert_held(&dev_priv->psr.lock);
@@ -403,9 +406,14 @@ void intel_psr_enable(struct intel_dp *intel_dp)
skl_psr_setup_su_vsc(intel_dp);
}
- /* Avoid continuous PSR exit by masking memup and hpd */
- I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
- EDP_PSR_DEBUG_MASK_HPD);
+ /*
+ * 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_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
+ EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
/* Enable PSR on the panel */
hsw_psr_enable_sink(intel_dp);
@@ -427,6 +435,19 @@ void intel_psr_enable(struct intel_dp *intel_dp)
vlv_psr_enable_source(intel_dp);
}
+ /*
+ * FIXME: Activation should happen immediately since this function
+ * is just called after pipe is fully trained and enabled.
+ * However on every platform we face issues when first activation
+ * follows a modeset so quickly.
+ * - On VLV/CHV we get bank screen on first activation
+ * - On HSW/BDW we get a recoverable frozen screen until next
+ * exit-activate sequence.
+ */
+ if (INTEL_INFO(dev)->gen < 9)
+ schedule_delayed_work(&dev_priv->psr.work,
+ msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5));
+
dev_priv->psr.enabled = intel_dp;
unlock:
mutex_unlock(&dev_priv->psr.lock);
@@ -466,17 +487,17 @@ static void hsw_psr_disable(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
if (dev_priv->psr.active) {
- I915_WRITE(EDP_PSR_CTL(dev),
- I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
+ I915_WRITE(EDP_PSR_CTL,
+ I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
/* Wait till PSR is idle */
- if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
+ if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
DRM_ERROR("Timed out waiting for PSR Idle State\n");
dev_priv->psr.active = false;
} else {
- WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
+ WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
}
}
@@ -498,11 +519,15 @@ void intel_psr_disable(struct intel_dp *intel_dp)
return;
}
+ /* Disable PSR on Source */
if (HAS_DDI(dev))
hsw_psr_disable(intel_dp);
else
vlv_psr_disable(intel_dp);
+ /* Disable PSR on Sink */
+ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0);
+
dev_priv->psr.enabled = NULL;
mutex_unlock(&dev_priv->psr.lock);
@@ -523,7 +548,7 @@ static void intel_psr_work(struct work_struct *work)
* and be ready for re-enable.
*/
if (HAS_DDI(dev_priv->dev)) {
- if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
+ if (wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
return;
@@ -566,11 +591,11 @@ static void intel_psr_exit(struct drm_device *dev)
return;
if (HAS_DDI(dev)) {
- val = I915_READ(EDP_PSR_CTL(dev));
+ val = I915_READ(EDP_PSR_CTL);
WARN_ON(!(val & EDP_PSR_ENABLE));
- I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
+ I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
} else {
val = I915_READ(VLV_PSRCTL(pipe));
@@ -620,7 +645,7 @@ void intel_psr_single_frame_update(struct drm_device *dev,
* Single frame update is already supported on BDW+ but it requires
* many W/A and it isn't really needed.
*/
- if (!IS_VALLEYVIEW(dev))
+ if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
return;
mutex_lock(&dev_priv->psr.lock);
@@ -700,7 +725,6 @@ void intel_psr_flush(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
enum pipe pipe;
- int delay_ms = HAS_DDI(dev) ? 100 : 500;
mutex_lock(&dev_priv->psr.lock);
if (!dev_priv->psr.enabled) {
@@ -714,29 +738,14 @@ void intel_psr_flush(struct drm_device *dev,
frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits;
- if (HAS_DDI(dev)) {
- /*
- * By definition every flush should mean invalidate + flush,
- * however on core platforms let's minimize the
- * disable/re-enable so we can avoid the invalidate when flip
- * originated the flush.
- */
- if (frontbuffer_bits && origin != ORIGIN_FLIP)
- intel_psr_exit(dev);
- } else {
- /*
- * On Valleyview and Cherryview we don't use hardware tracking
- * so any plane updates or cursor moves don't result in a PSR
- * invalidating. Which means we need to manually fake this in
- * software for all flushes.
- */
- if (frontbuffer_bits)
- intel_psr_exit(dev);
- }
+ /* By definition flush = invalidate + flush */
+ if (frontbuffer_bits)
+ intel_psr_exit(dev);
if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
- schedule_delayed_work(&dev_priv->psr.work,
- msecs_to_jiffies(delay_ms));
+ if (!work_busy(&dev_priv->psr.work.work))
+ schedule_delayed_work(&dev_priv->psr.work,
+ msecs_to_jiffies(100));
mutex_unlock(&dev_priv->psr.lock);
}
@@ -751,6 +760,9 @@ void intel_psr_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ?
+ HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE;
+
INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work);
mutex_init(&dev_priv->psr.lock);
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 9461a238f5d5..339701d7a9a5 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -27,29 +27,13 @@
*
*/
+#include <linux/log2.h>
#include <drm/drmP.h>
#include "i915_drv.h"
#include <drm/i915_drm.h>
#include "i915_trace.h"
#include "intel_drv.h"
-bool
-intel_ring_initialized(struct intel_engine_cs *ring)
-{
- struct drm_device *dev = ring->dev;
-
- if (!dev)
- return false;
-
- if (i915.enable_execlists) {
- struct intel_context *dctx = ring->default_context;
- struct intel_ringbuffer *ringbuf = dctx->engine[ring->id].ringbuf;
-
- return ringbuf->obj;
- } else
- return ring->buffer && ring->buffer->obj;
-}
-
int __intel_ring_space(int head, int tail, int size)
{
int space = head - tail;
@@ -481,7 +465,7 @@ static void intel_ring_setup_status_page(struct intel_engine_cs *ring)
{
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = ring->dev->dev_private;
- u32 mmio = 0;
+ i915_reg_t mmio;
/* The ring status page addresses are no longer next to the rest of
* the ring registers as of gen7.
@@ -524,7 +508,7 @@ static void intel_ring_setup_status_page(struct intel_engine_cs *ring)
* invalidating the TLB?
*/
if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
- u32 reg = RING_INSTPM(ring->mmio_base);
+ i915_reg_t reg = RING_INSTPM(ring->mmio_base);
/* ring should be idle before issuing a sync flush*/
WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
@@ -733,7 +717,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
for (i = 0; i < w->count; i++) {
- intel_ring_emit(ring, w->reg[i].addr);
+ intel_ring_emit_reg(ring, w->reg[i].addr);
intel_ring_emit(ring, w->reg[i].value);
}
intel_ring_emit(ring, MI_NOOP);
@@ -766,7 +750,8 @@ static int intel_rcs_ctx_init(struct drm_i915_gem_request *req)
}
static int wa_add(struct drm_i915_private *dev_priv,
- const u32 addr, const u32 mask, const u32 val)
+ i915_reg_t addr,
+ const u32 mask, const u32 val)
{
const u32 idx = dev_priv->workarounds.count;
@@ -924,17 +909,15 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring)
WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
- if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) == SKL_REVID_A0 ||
- INTEL_REVID(dev) == SKL_REVID_B0)) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) {
- /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
+ /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1))
WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
GEN9_DG_MIRROR_FIX_ENABLE);
- }
- if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) {
- /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
+ /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
GEN9_RHWO_OPTIMIZATION_DISABLE);
/*
@@ -944,12 +927,10 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring)
*/
}
- if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) ||
- IS_BROXTON(dev)) {
- /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
+ /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
+ if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER) || IS_BROXTON(dev))
WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
GEN9_ENABLE_YV12_BUGFIX);
- }
/* Wa4x4STCOptimizationDisable:skl,bxt */
/* WaDisablePartialResolveInVc:skl,bxt */
@@ -961,24 +942,22 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring)
GEN9_CCS_TLB_PREFETCH_ENABLE);
/* WaDisableMaskBasedCammingInRCC:skl,bxt */
- if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_C0) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0))
+ if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_C0) ||
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1))
WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
PIXEL_MASK_CAMMING_DISABLE);
/* WaForceContextSaveRestoreNonCoherent:skl,bxt */
tmp = HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT;
- if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_F0) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) >= BXT_REVID_B0))
+ if (IS_SKL_REVID(dev, SKL_REVID_F0, SKL_REVID_F0) ||
+ IS_BXT_REVID(dev, BXT_REVID_B0, REVID_FOREVER))
tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE;
WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp);
/* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */
- if (IS_SKYLAKE(dev) ||
- (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_B0)) {
+ if (IS_SKYLAKE(dev) || IS_BXT_REVID(dev, 0, BXT_REVID_B0))
WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
GEN8_SAMPLER_POWER_BYPASS_DIS);
- }
/* WaDisableSTUnitPowerOptimization:skl,bxt */
WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
@@ -1000,7 +979,7 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *ring)
* Only consider slices where one, and only one, subslice has 7
* EUs
*/
- if (hweight8(dev_priv->info.subslice_7eu[i]) != 1)
+ if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
continue;
/*
@@ -1038,11 +1017,7 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
if (ret)
return ret;
- if (INTEL_REVID(dev) <= SKL_REVID_D0) {
- /* WaDisableHDCInvalidation:skl */
- I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
- BDW_DISABLE_HDC_INVALIDATION);
-
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
/* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
I915_WRITE(FF_SLICE_CS_CHICKEN2,
_MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
@@ -1051,23 +1026,23 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
* involving this register should also be added to WA batch as required.
*/
- if (INTEL_REVID(dev) <= SKL_REVID_E0)
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_E0))
/* WaDisableLSQCROPERFforOCL:skl */
I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
GEN8_LQSC_RO_PERF_DIS);
/* WaEnableGapsTsvCreditFix:skl */
- if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) {
+ if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER)) {
I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
GEN9_GAPS_TSV_CREDIT_DISABLE));
}
/* WaDisablePowerCompilerClockGating:skl */
- if (INTEL_REVID(dev) == SKL_REVID_B0)
+ if (IS_SKL_REVID(dev, SKL_REVID_B0, SKL_REVID_B0))
WA_SET_BIT_MASKED(HIZ_CHICKEN,
BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
- if (INTEL_REVID(dev) <= SKL_REVID_D0) {
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_F0)) {
/*
*Use Force Non-Coherent whenever executing a 3D context. This
* is a workaround for a possible hang in the unlikely event
@@ -1076,21 +1051,23 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
/* WaForceEnableNonCoherent:skl */
WA_SET_BIT_MASKED(HDC_CHICKEN0,
HDC_FORCE_NON_COHERENT);
+
+ /* WaDisableHDCInvalidation:skl */
+ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
+ BDW_DISABLE_HDC_INVALIDATION);
}
- if (INTEL_REVID(dev) == SKL_REVID_C0 ||
- INTEL_REVID(dev) == SKL_REVID_D0)
- /* WaBarrierPerformanceFixDisable:skl */
+ /* WaBarrierPerformanceFixDisable:skl */
+ if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0))
WA_SET_BIT_MASKED(HDC_CHICKEN0,
HDC_FENCE_DEST_SLM_DISABLE |
HDC_BARRIER_PERFORMANCE_DISABLE);
/* WaDisableSbeCacheDispatchPortSharing:skl */
- if (INTEL_REVID(dev) <= SKL_REVID_F0) {
+ if (IS_SKL_REVID(dev, 0, SKL_REVID_F0))
WA_SET_BIT_MASKED(
GEN7_HALF_SLICE_CHICKEN1,
GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
- }
return skl_tune_iz_hashing(ring);
}
@@ -1107,11 +1084,11 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring)
/* WaStoreMultiplePTEenable:bxt */
/* This is a requirement according to Hardware specification */
- if (INTEL_REVID(dev) == BXT_REVID_A0)
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
/* WaSetClckGatingDisableMedia:bxt */
- if (INTEL_REVID(dev) == BXT_REVID_A0) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
}
@@ -1121,7 +1098,7 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring)
STALL_DOP_GATING_DISABLE);
/* WaDisableSbeCacheDispatchPortSharing:bxt */
- if (INTEL_REVID(dev) <= BXT_REVID_B0) {
+ if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) {
WA_SET_BIT_MASKED(
GEN7_HALF_SLICE_CHICKEN1,
GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
@@ -1319,11 +1296,13 @@ static int gen6_signal(struct drm_i915_gem_request *signaller_req,
return ret;
for_each_ring(useless, dev_priv, i) {
- u32 mbox_reg = signaller->semaphore.mbox.signal[i];
- if (mbox_reg != GEN6_NOSYNC) {
+ i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[i];
+
+ if (i915_mmio_reg_valid(mbox_reg)) {
u32 seqno = i915_gem_request_get_seqno(signaller_req);
+
intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(signaller, mbox_reg);
+ intel_ring_emit_reg(signaller, mbox_reg);
intel_ring_emit(signaller, seqno);
}
}
@@ -2004,11 +1983,35 @@ static int init_phys_status_page(struct intel_engine_cs *ring)
void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
{
- iounmap(ringbuf->virtual_start);
+ if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
+ vunmap(ringbuf->virtual_start);
+ else
+ iounmap(ringbuf->virtual_start);
ringbuf->virtual_start = NULL;
i915_gem_object_ggtt_unpin(ringbuf->obj);
}
+static u32 *vmap_obj(struct drm_i915_gem_object *obj)
+{
+ struct sg_page_iter sg_iter;
+ struct page **pages;
+ void *addr;
+ int i;
+
+ pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
+ if (pages == NULL)
+ return NULL;
+
+ i = 0;
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0)
+ pages[i++] = sg_page_iter_page(&sg_iter);
+
+ addr = vmap(pages, i, 0, PAGE_KERNEL);
+ drm_free_large(pages);
+
+ return addr;
+}
+
int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
struct intel_ringbuffer *ringbuf)
{
@@ -2016,21 +2019,39 @@ int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj = ringbuf->obj;
int ret;
- ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
- if (ret)
- return ret;
+ if (HAS_LLC(dev_priv) && !obj->stolen) {
+ ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, 0);
+ if (ret)
+ return ret;
- ret = i915_gem_object_set_to_gtt_domain(obj, true);
- if (ret) {
- i915_gem_object_ggtt_unpin(obj);
- return ret;
- }
+ ret = i915_gem_object_set_to_cpu_domain(obj, true);
+ if (ret) {
+ i915_gem_object_ggtt_unpin(obj);
+ return ret;
+ }
- ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
- i915_gem_obj_ggtt_offset(obj), ringbuf->size);
- if (ringbuf->virtual_start == NULL) {
- i915_gem_object_ggtt_unpin(obj);
- return -EINVAL;
+ ringbuf->virtual_start = vmap_obj(obj);
+ if (ringbuf->virtual_start == NULL) {
+ i915_gem_object_ggtt_unpin(obj);
+ return -ENOMEM;
+ }
+ } else {
+ ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
+ if (ret)
+ return ret;
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
+ if (ret) {
+ i915_gem_object_ggtt_unpin(obj);
+ return ret;
+ }
+
+ ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
+ i915_gem_obj_ggtt_offset(obj), ringbuf->size);
+ if (ringbuf->virtual_start == NULL) {
+ i915_gem_object_ggtt_unpin(obj);
+ return -EINVAL;
+ }
}
return 0;
@@ -2070,10 +2091,14 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
int ret;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
- if (ring == NULL)
+ if (ring == NULL) {
+ DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
+ engine->name);
return ERR_PTR(-ENOMEM);
+ }
ring->ring = engine;
+ list_add(&ring->link, &engine->buffers);
ring->size = size;
/* Workaround an erratum on the i830 which causes a hang if
@@ -2089,8 +2114,9 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
if (ret) {
- DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
- engine->name, ret);
+ DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
+ engine->name, ret);
+ list_del(&ring->link);
kfree(ring);
return ERR_PTR(ret);
}
@@ -2102,6 +2128,7 @@ void
intel_ringbuffer_free(struct intel_ringbuffer *ring)
{
intel_destroy_ringbuffer_obj(ring);
+ list_del(&ring->link);
kfree(ring);
}
@@ -2117,14 +2144,17 @@ static int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->execlist_queue);
+ INIT_LIST_HEAD(&ring->buffers);
i915_gem_batch_pool_init(dev, &ring->batch_pool);
memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
init_waitqueue_head(&ring->irq_queue);
ringbuf = intel_engine_create_ringbuffer(ring, 32 * PAGE_SIZE);
- if (IS_ERR(ringbuf))
- return PTR_ERR(ringbuf);
+ if (IS_ERR(ringbuf)) {
+ ret = PTR_ERR(ringbuf);
+ goto error;
+ }
ring->buffer = ringbuf;
if (I915_NEED_GFX_HWS(dev)) {
@@ -2153,8 +2183,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
return 0;
error:
- intel_ringbuffer_free(ringbuf);
- ring->buffer = NULL;
+ intel_cleanup_ring_buffer(ring);
return ret;
}
@@ -2167,12 +2196,14 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
dev_priv = to_i915(ring->dev);
- intel_stop_ring_buffer(ring);
- WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0);
+ if (ring->buffer) {
+ intel_stop_ring_buffer(ring);
+ WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0);
- intel_unpin_ringbuffer_obj(ring->buffer);
- intel_ringbuffer_free(ring->buffer);
- ring->buffer = NULL;
+ intel_unpin_ringbuffer_obj(ring->buffer);
+ intel_ringbuffer_free(ring->buffer);
+ ring->buffer = NULL;
+ }
if (ring->cleanup)
ring->cleanup(ring);
@@ -2181,6 +2212,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
i915_cmd_parser_fini_ring(ring);
i915_gem_batch_pool_fini(&ring->batch_pool);
+ ring->dev = NULL;
}
static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 49fa41dc0eb6..49574ffe54bc 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -100,6 +100,7 @@ struct intel_ringbuffer {
void __iomem *virtual_start;
struct intel_engine_cs *ring;
+ struct list_head link;
u32 head;
u32 tail;
@@ -157,6 +158,7 @@ struct intel_engine_cs {
u32 mmio_base;
struct drm_device *dev;
struct intel_ringbuffer *buffer;
+ struct list_head buffers;
/*
* A pool of objects to use as shadow copies of client batch buffers
@@ -247,7 +249,7 @@ struct intel_engine_cs {
/* our mbox written by others */
u32 wait[I915_NUM_RINGS];
/* mboxes this ring signals to */
- u32 signal[I915_NUM_RINGS];
+ i915_reg_t signal[I915_NUM_RINGS];
} mbox;
u64 signal_ggtt[I915_NUM_RINGS];
};
@@ -348,7 +350,11 @@ struct intel_engine_cs {
u32 (*get_cmd_length_mask)(u32 cmd_header);
};
-bool intel_ring_initialized(struct intel_engine_cs *ring);
+static inline bool
+intel_ring_initialized(struct intel_engine_cs *ring)
+{
+ return ring->dev != NULL;
+}
static inline unsigned
intel_ring_flag(struct intel_engine_cs *ring)
@@ -441,6 +447,11 @@ static inline void intel_ring_emit(struct intel_engine_cs *ring,
iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
ringbuf->tail += 4;
}
+static inline void intel_ring_emit_reg(struct intel_engine_cs *ring,
+ i915_reg_t reg)
+{
+ intel_ring_emit(ring, i915_mmio_reg_offset(reg));
+}
static inline void intel_ring_advance(struct intel_engine_cs *ring)
{
struct intel_ringbuffer *ringbuf = ring->buffer;
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 7e23d65c9b24..ddbdbffe829a 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -49,25 +49,88 @@
* present for a given platform.
*/
-#define GEN9_ENABLE_DC5(dev) 0
-#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev)
-
#define for_each_power_well(i, power_well, domain_mask, power_domains) \
for (i = 0; \
i < (power_domains)->power_well_count && \
((power_well) = &(power_domains)->power_wells[i]); \
i++) \
- if ((power_well)->domains & (domain_mask))
+ for_each_if ((power_well)->domains & (domain_mask))
#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \
for (i = (power_domains)->power_well_count - 1; \
i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\
i--) \
- if ((power_well)->domains & (domain_mask))
+ for_each_if ((power_well)->domains & (domain_mask))
bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
int power_well_id);
+const char *
+intel_display_power_domain_str(enum intel_display_power_domain domain)
+{
+ switch (domain) {
+ case POWER_DOMAIN_PIPE_A:
+ return "PIPE_A";
+ case POWER_DOMAIN_PIPE_B:
+ return "PIPE_B";
+ case POWER_DOMAIN_PIPE_C:
+ return "PIPE_C";
+ case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
+ return "PIPE_A_PANEL_FITTER";
+ case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
+ return "PIPE_B_PANEL_FITTER";
+ case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
+ return "PIPE_C_PANEL_FITTER";
+ case POWER_DOMAIN_TRANSCODER_A:
+ return "TRANSCODER_A";
+ case POWER_DOMAIN_TRANSCODER_B:
+ return "TRANSCODER_B";
+ case POWER_DOMAIN_TRANSCODER_C:
+ return "TRANSCODER_C";
+ case POWER_DOMAIN_TRANSCODER_EDP:
+ return "TRANSCODER_EDP";
+ case POWER_DOMAIN_PORT_DDI_A_LANES:
+ return "PORT_DDI_A_LANES";
+ case POWER_DOMAIN_PORT_DDI_B_LANES:
+ return "PORT_DDI_B_LANES";
+ case POWER_DOMAIN_PORT_DDI_C_LANES:
+ return "PORT_DDI_C_LANES";
+ case POWER_DOMAIN_PORT_DDI_D_LANES:
+ return "PORT_DDI_D_LANES";
+ case POWER_DOMAIN_PORT_DDI_E_LANES:
+ return "PORT_DDI_E_LANES";
+ case POWER_DOMAIN_PORT_DSI:
+ return "PORT_DSI";
+ case POWER_DOMAIN_PORT_CRT:
+ return "PORT_CRT";
+ case POWER_DOMAIN_PORT_OTHER:
+ return "PORT_OTHER";
+ case POWER_DOMAIN_VGA:
+ return "VGA";
+ case POWER_DOMAIN_AUDIO:
+ return "AUDIO";
+ case POWER_DOMAIN_PLLS:
+ return "PLLS";
+ case POWER_DOMAIN_AUX_A:
+ return "AUX_A";
+ case POWER_DOMAIN_AUX_B:
+ return "AUX_B";
+ case POWER_DOMAIN_AUX_C:
+ return "AUX_C";
+ case POWER_DOMAIN_AUX_D:
+ return "AUX_D";
+ case POWER_DOMAIN_GMBUS:
+ return "GMBUS";
+ case POWER_DOMAIN_INIT:
+ return "INIT";
+ case POWER_DOMAIN_MODESET:
+ return "MODESET";
+ default:
+ MISSING_CASE(domain);
+ return "?";
+ }
+}
+
static void intel_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
@@ -244,12 +307,6 @@ static void skl_power_well_post_enable(struct drm_i915_private *dev_priv,
gen8_irq_power_well_post_enable(dev_priv,
1 << PIPE_C | 1 << PIPE_B);
}
-
- if (power_well->data == SKL_DISP_PW_1) {
- if (!dev_priv->power_domains.initializing)
- intel_prepare_ddi(dev);
- gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_A);
- }
}
static void hsw_set_power_well(struct drm_i915_private *dev_priv,
@@ -292,58 +349,38 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_TRANSCODER_C) | \
BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \
BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_E_LANES) | \
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_AUX_D) | \
BIT(POWER_DOMAIN_AUDIO) | \
BIT(POWER_DOMAIN_VGA) | \
BIT(POWER_DOMAIN_INIT))
-#define SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS ( \
- SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
- BIT(POWER_DOMAIN_PLLS) | \
- BIT(POWER_DOMAIN_PIPE_A) | \
- BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
- BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \
- BIT(POWER_DOMAIN_AUX_A) | \
- BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_E_LANES) | \
BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_DDI_B_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_DDI_C_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_DDI_D_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \
BIT(POWER_DOMAIN_INIT))
-#define SKL_DISPLAY_MISC_IO_POWER_DOMAINS ( \
- SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \
- BIT(POWER_DOMAIN_PLLS) | \
+#define SKL_DISPLAY_DC_OFF_POWER_DOMAINS ( \
+ SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
+ BIT(POWER_DOMAIN_MODESET) | \
+ BIT(POWER_DOMAIN_AUX_A) | \
BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \
- (POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \
+ (POWER_DOMAIN_MASK & ~( \
SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
- SKL_DISPLAY_DDI_A_E_POWER_DOMAINS | \
- SKL_DISPLAY_DDI_B_POWER_DOMAINS | \
- SKL_DISPLAY_DDI_C_POWER_DOMAINS | \
- SKL_DISPLAY_DDI_D_POWER_DOMAINS | \
- SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) | \
+ SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) | \
BIT(POWER_DOMAIN_INIT))
#define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS ( \
@@ -354,10 +391,8 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_TRANSCODER_C) | \
BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \
BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_AUDIO) | \
@@ -369,11 +404,15 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_PIPE_A) | \
BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
BIT(POWER_DOMAIN_AUX_A) | \
BIT(POWER_DOMAIN_PLLS) | \
BIT(POWER_DOMAIN_INIT))
+#define BXT_DISPLAY_DC_OFF_POWER_DOMAINS ( \
+ BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
+ BIT(POWER_DOMAIN_MODESET) | \
+ BIT(POWER_DOMAIN_AUX_A) | \
+ BIT(POWER_DOMAIN_INIT))
#define BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \
(POWER_DOMAIN_MASK & ~(BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS | \
BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) | \
@@ -417,46 +456,74 @@ static void assert_can_disable_dc9(struct drm_i915_private *dev_priv)
*/
}
-void bxt_enable_dc9(struct drm_i915_private *dev_priv)
+static void gen9_set_dc_state_debugmask_memory_up(
+ struct drm_i915_private *dev_priv)
{
uint32_t val;
- assert_can_enable_dc9(dev_priv);
+ /* The below bit doesn't need to be cleared ever afterwards */
+ val = I915_READ(DC_STATE_DEBUG);
+ if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) {
+ val |= DC_STATE_DEBUG_MASK_MEMORY_UP;
+ I915_WRITE(DC_STATE_DEBUG, val);
+ POSTING_READ(DC_STATE_DEBUG);
+ }
+}
- DRM_DEBUG_KMS("Enabling DC9\n");
+static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
+{
+ uint32_t val;
+ uint32_t mask;
+
+ mask = DC_STATE_EN_UPTO_DC5;
+ if (IS_BROXTON(dev_priv))
+ mask |= DC_STATE_EN_DC9;
+ else
+ mask |= DC_STATE_EN_UPTO_DC6;
+
+ WARN_ON_ONCE(state & ~mask);
+
+ if (i915.enable_dc == 0)
+ state = DC_STATE_DISABLE;
+ else if (i915.enable_dc == 1 && state > DC_STATE_EN_UPTO_DC5)
+ state = DC_STATE_EN_UPTO_DC5;
+
+ if (state & DC_STATE_EN_UPTO_DC5_DC6_MASK)
+ gen9_set_dc_state_debugmask_memory_up(dev_priv);
val = I915_READ(DC_STATE_EN);
- val |= DC_STATE_EN_DC9;
+ DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n",
+ val & mask, state);
+ val &= ~mask;
+ val |= state;
I915_WRITE(DC_STATE_EN, val);
POSTING_READ(DC_STATE_EN);
}
-void bxt_disable_dc9(struct drm_i915_private *dev_priv)
+void bxt_enable_dc9(struct drm_i915_private *dev_priv)
{
- uint32_t val;
+ assert_can_enable_dc9(dev_priv);
+
+ DRM_DEBUG_KMS("Enabling DC9\n");
+ gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9);
+}
+
+void bxt_disable_dc9(struct drm_i915_private *dev_priv)
+{
assert_can_disable_dc9(dev_priv);
DRM_DEBUG_KMS("Disabling DC9\n");
- val = I915_READ(DC_STATE_EN);
- val &= ~DC_STATE_EN_DC9;
- I915_WRITE(DC_STATE_EN, val);
- POSTING_READ(DC_STATE_EN);
+ gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
}
-static void gen9_set_dc_state_debugmask_memory_up(
- struct drm_i915_private *dev_priv)
+static void assert_csr_loaded(struct drm_i915_private *dev_priv)
{
- uint32_t val;
-
- /* The below bit doesn't need to be cleared ever afterwards */
- val = I915_READ(DC_STATE_DEBUG);
- if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) {
- val |= DC_STATE_DEBUG_MASK_MEMORY_UP;
- I915_WRITE(DC_STATE_DEBUG, val);
- POSTING_READ(DC_STATE_DEBUG);
- }
+ WARN_ONCE(!I915_READ(CSR_PROGRAM(0)),
+ "CSR program storage start is NULL\n");
+ WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
+ WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
}
static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
@@ -471,16 +538,13 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5),
"DC5 already programmed to be enabled.\n");
- WARN_ONCE(dev_priv->pm.suspended,
- "DC5 cannot be enabled, if platform is runtime-suspended.\n");
+ assert_rpm_wakelock_held(dev_priv);
assert_csr_loaded(dev_priv);
}
static void assert_can_disable_dc5(struct drm_i915_private *dev_priv)
{
- bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv,
- SKL_DISP_PW_2);
/*
* During initialization, the firmware may not be loaded yet.
* We still want to make sure that the DC enabling flag is cleared.
@@ -488,40 +552,16 @@ static void assert_can_disable_dc5(struct drm_i915_private *dev_priv)
if (dev_priv->power_domains.initializing)
return;
- WARN_ONCE(!pg2_enabled, "PG2 not enabled to disable DC5.\n");
- WARN_ONCE(dev_priv->pm.suspended,
- "Disabling of DC5 while platform is runtime-suspended should never happen.\n");
+ assert_rpm_wakelock_held(dev_priv);
}
static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
{
- uint32_t val;
-
assert_can_enable_dc5(dev_priv);
DRM_DEBUG_KMS("Enabling DC5\n");
- gen9_set_dc_state_debugmask_memory_up(dev_priv);
-
- val = I915_READ(DC_STATE_EN);
- val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
- val |= DC_STATE_EN_UPTO_DC5;
- I915_WRITE(DC_STATE_EN, val);
- POSTING_READ(DC_STATE_EN);
-}
-
-static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
-{
- uint32_t val;
-
- assert_can_disable_dc5(dev_priv);
-
- DRM_DEBUG_KMS("Disabling DC5\n");
-
- val = I915_READ(DC_STATE_EN);
- val &= ~DC_STATE_EN_UPTO_DC5;
- I915_WRITE(DC_STATE_EN, val);
- POSTING_READ(DC_STATE_EN);
+ gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
}
static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
@@ -547,40 +587,37 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv)
if (dev_priv->power_domains.initializing)
return;
- assert_csr_loaded(dev_priv);
WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
"DC6 already programmed to be disabled.\n");
}
-static void skl_enable_dc6(struct drm_i915_private *dev_priv)
+static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv)
{
- uint32_t val;
+ assert_can_disable_dc5(dev_priv);
+
+ if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1)
+ assert_can_disable_dc6(dev_priv);
+ gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+}
+
+void skl_enable_dc6(struct drm_i915_private *dev_priv)
+{
assert_can_enable_dc6(dev_priv);
DRM_DEBUG_KMS("Enabling DC6\n");
- gen9_set_dc_state_debugmask_memory_up(dev_priv);
+ gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
- val = I915_READ(DC_STATE_EN);
- val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
- val |= DC_STATE_EN_UPTO_DC6;
- I915_WRITE(DC_STATE_EN, val);
- POSTING_READ(DC_STATE_EN);
}
-static void skl_disable_dc6(struct drm_i915_private *dev_priv)
+void skl_disable_dc6(struct drm_i915_private *dev_priv)
{
- uint32_t val;
-
assert_can_disable_dc6(dev_priv);
DRM_DEBUG_KMS("Disabling DC6\n");
- val = I915_READ(DC_STATE_EN);
- val &= ~DC_STATE_EN_UPTO_DC6;
- I915_WRITE(DC_STATE_EN, val);
- POSTING_READ(DC_STATE_EN);
+ gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
}
static void skl_set_power_well(struct drm_i915_private *dev_priv,
@@ -630,20 +667,16 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
!I915_READ(HSW_PWR_WELL_BIOS),
"Invalid for power well status to be enabled, unless done by the BIOS, \
when request is to disable!\n");
- if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
- power_well->data == SKL_DISP_PW_2) {
- if (SKL_ENABLE_DC6(dev)) {
- skl_disable_dc6(dev_priv);
- /*
- * DDI buffer programming unnecessary during driver-load/resume
- * as it's already done during modeset initialization then.
- * It's also invalid here as encoder list is still uninitialized.
- */
- if (!dev_priv->power_domains.initializing)
- intel_prepare_ddi(dev);
- } else {
- gen9_disable_dc5(dev_priv);
- }
+ if (power_well->data == SKL_DISP_PW_2) {
+ /*
+ * DDI buffer programming unnecessary during
+ * driver-load/resume as it's already done
+ * during modeset initialization then. It's
+ * also invalid here as encoder list is still
+ * uninitialized.
+ */
+ if (!dev_priv->power_domains.initializing)
+ intel_prepare_ddi(dev);
}
I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
}
@@ -658,34 +691,9 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
}
} else {
if (enable_requested) {
- if (IS_SKYLAKE(dev) &&
- (power_well->data == SKL_DISP_PW_1) &&
- (intel_csr_load_status_get(dev_priv) == FW_LOADED))
- DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n");
- else {
- I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
- POSTING_READ(HSW_PWR_WELL_DRIVER);
- DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
- }
-
- if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
- power_well->data == SKL_DISP_PW_2) {
- enum csr_state state;
- /* TODO: wait for a completion event or
- * similar here instead of busy
- * waiting using wait_for function.
- */
- wait_for((state = intel_csr_load_status_get(dev_priv)) !=
- FW_UNINITIALIZED, 1000);
- if (state != FW_LOADED)
- DRM_DEBUG("CSR firmware not ready (%d)\n",
- state);
- else
- if (SKL_ENABLE_DC6(dev))
- skl_enable_dc6(dev_priv);
- else
- gen9_enable_dc5(dev_priv);
- }
+ I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
+ POSTING_READ(HSW_PWR_WELL_DRIVER);
+ DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
}
}
@@ -760,6 +768,41 @@ static void skl_power_well_disable(struct drm_i915_private *dev_priv,
skl_set_power_well(dev_priv, power_well, false);
}
+static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
+ struct i915_power_well *power_well)
+{
+ return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0;
+}
+
+static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
+ struct i915_power_well *power_well)
+{
+ gen9_disable_dc5_dc6(dev_priv);
+}
+
+static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
+ struct i915_power_well *power_well)
+{
+ if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1)
+ skl_enable_dc6(dev_priv);
+ else
+ gen9_enable_dc5(dev_priv);
+}
+
+static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv,
+ struct i915_power_well *power_well)
+{
+ if (power_well->count > 0) {
+ gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+ } else {
+ if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 &&
+ i915.enable_dc != 1)
+ gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
+ else
+ gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
+ }
+}
+
static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
@@ -974,10 +1017,12 @@ static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_pr
int power_well_id)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
- struct i915_power_well *power_well;
int i;
- for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
+ for (i = 0; i < power_domains->power_well_count; i++) {
+ struct i915_power_well *power_well;
+
+ power_well = &power_domains->power_wells[i];
if (power_well->data == power_well_id)
return power_well;
}
@@ -1452,13 +1497,17 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
mutex_lock(&power_domains->lock);
- WARN_ON(!power_domains->domain_use_count[domain]);
+ WARN(!power_domains->domain_use_count[domain],
+ "Use count on domain %s is already zero\n",
+ intel_display_power_domain_str(domain));
power_domains->domain_use_count[domain]--;
for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
- WARN_ON(!power_well->count);
+ WARN(!power_well->count,
+ "Use count on power well %s is already zero",
+ power_well->name);
- if (!--power_well->count && i915.disable_power_well)
+ if (!--power_well->count)
intel_power_well_disable(dev_priv, power_well);
}
@@ -1470,14 +1519,10 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
#define HSW_ALWAYS_ON_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PIPE_A) | \
BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \
BIT(POWER_DOMAIN_PORT_CRT) | \
BIT(POWER_DOMAIN_PLLS) | \
BIT(POWER_DOMAIN_AUX_A) | \
@@ -1501,49 +1546,42 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK
#define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
BIT(POWER_DOMAIN_PORT_CRT) | \
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define CHV_DPIO_CMN_D_POWER_DOMAINS ( \
- BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
- BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \
BIT(POWER_DOMAIN_AUX_D) | \
BIT(POWER_DOMAIN_INIT))
@@ -1591,6 +1629,13 @@ static const struct i915_power_well_ops skl_power_well_ops = {
.is_enabled = skl_power_well_enabled,
};
+static const struct i915_power_well_ops gen9_dc_off_power_well_ops = {
+ .sync_hw = gen9_dc_off_power_well_sync_hw,
+ .enable = gen9_dc_off_power_well_enable,
+ .disable = gen9_dc_off_power_well_disable,
+ .is_enabled = gen9_dc_off_power_well_enabled,
+};
+
static struct i915_power_well hsw_power_wells[] = {
{
.name = "always-on",
@@ -1646,6 +1691,7 @@ static struct i915_power_well vlv_power_wells[] = {
.always_on = 1,
.domains = VLV_ALWAYS_ON_POWER_DOMAINS,
.ops = &i9xx_always_on_power_well_ops,
+ .data = PUNIT_POWER_WELL_ALWAYS_ON,
},
{
.name = "display",
@@ -1747,20 +1793,29 @@ static struct i915_power_well skl_power_wells[] = {
.always_on = 1,
.domains = SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS,
.ops = &i9xx_always_on_power_well_ops,
+ .data = SKL_DISP_PW_ALWAYS_ON,
},
{
.name = "power well 1",
- .domains = SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS,
+ /* Handled by the DMC firmware */
+ .domains = 0,
.ops = &skl_power_well_ops,
.data = SKL_DISP_PW_1,
},
{
.name = "MISC IO power well",
- .domains = SKL_DISPLAY_MISC_IO_POWER_DOMAINS,
+ /* Handled by the DMC firmware */
+ .domains = 0,
.ops = &skl_power_well_ops,
.data = SKL_DISP_PW_MISC_IO,
},
{
+ .name = "DC off",
+ .domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS,
+ .ops = &gen9_dc_off_power_well_ops,
+ .data = SKL_DISP_PW_DC_OFF,
+ },
+ {
.name = "power well 2",
.domains = SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS,
.ops = &skl_power_well_ops,
@@ -1792,6 +1847,34 @@ static struct i915_power_well skl_power_wells[] = {
},
};
+void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv)
+{
+ struct i915_power_well *well;
+
+ if (!IS_SKYLAKE(dev_priv))
+ return;
+
+ well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
+ intel_power_well_enable(dev_priv, well);
+
+ well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO);
+ intel_power_well_enable(dev_priv, well);
+}
+
+void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv)
+{
+ struct i915_power_well *well;
+
+ if (!IS_SKYLAKE(dev_priv))
+ return;
+
+ well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
+ intel_power_well_disable(dev_priv, well);
+
+ well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO);
+ intel_power_well_disable(dev_priv, well);
+}
+
static struct i915_power_well bxt_power_wells[] = {
{
.name = "always-on",
@@ -1806,11 +1889,17 @@ static struct i915_power_well bxt_power_wells[] = {
.data = SKL_DISP_PW_1,
},
{
+ .name = "DC off",
+ .domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS,
+ .ops = &gen9_dc_off_power_well_ops,
+ .data = SKL_DISP_PW_DC_OFF,
+ },
+ {
.name = "power well 2",
.domains = BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS,
.ops = &skl_power_well_ops,
.data = SKL_DISP_PW_2,
- }
+ },
};
static int
@@ -1820,7 +1909,7 @@ sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv,
if (disable_power_well >= 0)
return !!disable_power_well;
- if (IS_SKYLAKE(dev_priv)) {
+ if (IS_BROXTON(dev_priv)) {
DRM_DEBUG_KMS("Disabling display power well support\n");
return 0;
}
@@ -1859,7 +1948,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
set_power_wells(power_domains, hsw_power_wells);
} else if (IS_BROADWELL(dev_priv->dev)) {
set_power_wells(power_domains, bdw_power_wells);
- } else if (IS_SKYLAKE(dev_priv->dev)) {
+ } else if (IS_SKYLAKE(dev_priv->dev) || IS_KABYLAKE(dev_priv->dev)) {
set_power_wells(power_domains, skl_power_wells);
} else if (IS_BROXTON(dev_priv->dev)) {
set_power_wells(power_domains, bxt_power_wells);
@@ -1874,21 +1963,6 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
return 0;
}
-static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
-{
- struct drm_device *dev = dev_priv->dev;
- struct device *device = &dev->pdev->dev;
-
- if (!HAS_RUNTIME_PM(dev))
- return;
-
- if (!intel_enable_rc6(dev))
- return;
-
- /* Make sure we're not suspended first. */
- pm_runtime_get_sync(device);
-}
-
/**
* intel_power_domains_fini - finalizes the power domain structures
* @dev_priv: i915 device instance
@@ -1899,15 +1973,32 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
*/
void intel_power_domains_fini(struct drm_i915_private *dev_priv)
{
- intel_runtime_pm_disable(dev_priv);
+ struct device *device = &dev_priv->dev->pdev->dev;
- /* The i915.ko module is still not prepared to be loaded when
+ /*
+ * The i915.ko module is still not prepared to be loaded when
* the power well is not enabled, so just enable it in case
- * we're going to unload/reload. */
+ * we're going to unload/reload.
+ * The following also reacquires the RPM reference the core passed
+ * to the driver during loading, which is dropped in
+ * intel_runtime_pm_enable(). We have to hand back the control of the
+ * device to the core with this reference held.
+ */
intel_display_set_init_power(dev_priv, true);
+
+ /* Remove the refcount we took to keep power well support disabled. */
+ if (!i915.disable_power_well)
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ /*
+ * Remove the refcount we took in intel_runtime_pm_enable() in case
+ * the platform doesn't support runtime PM.
+ */
+ if (!HAS_RUNTIME_PM(dev_priv))
+ pm_runtime_put(device);
}
-static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
+static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
struct i915_power_well *power_well;
@@ -1922,6 +2013,47 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
mutex_unlock(&power_domains->lock);
}
+static void skl_display_core_init(struct drm_i915_private *dev_priv,
+ bool resume)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ 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);
+
+ /* enable PG1 and Misc I/O */
+ mutex_lock(&power_domains->lock);
+ skl_pw1_misc_io_init(dev_priv);
+ mutex_unlock(&power_domains->lock);
+
+ if (!resume)
+ return;
+
+ skl_init_cdclk(dev_priv);
+
+ if (dev_priv->csr.dmc_payload)
+ intel_csr_load_program(dev_priv);
+}
+
+static void skl_display_core_uninit(struct drm_i915_private *dev_priv)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+ gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+ skl_uninit_cdclk(dev_priv);
+
+ /* The spec doesn't call for removing the reset handshake flag */
+ /* disable PG1 and Misc I/O */
+ mutex_lock(&power_domains->lock);
+ skl_pw1_misc_io_fini(dev_priv);
+ mutex_unlock(&power_domains->lock);
+}
+
static void chv_phy_control_init(struct drm_i915_private *dev_priv)
{
struct i915_power_well *cmn_bc =
@@ -2044,14 +2176,16 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
* This function initializes the hardware power domain state and enables all
* power domains using intel_display_set_init_power().
*/
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
{
struct drm_device *dev = dev_priv->dev;
struct i915_power_domains *power_domains = &dev_priv->power_domains;
power_domains->initializing = true;
- if (IS_CHERRYVIEW(dev)) {
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
+ skl_display_core_init(dev_priv, resume);
+ } else if (IS_CHERRYVIEW(dev)) {
mutex_lock(&power_domains->lock);
chv_phy_control_init(dev_priv);
mutex_unlock(&power_domains->lock);
@@ -2063,11 +2197,34 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
/* For now, we need the power well to be always enabled. */
intel_display_set_init_power(dev_priv, true);
- intel_power_domains_resume(dev_priv);
+ /* Disable power support if the user asked so. */
+ if (!i915.disable_power_well)
+ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+ intel_power_domains_sync_hw(dev_priv);
power_domains->initializing = false;
}
/**
+ * intel_power_domains_suspend - suspend power domain state
+ * @dev_priv: i915 device instance
+ *
+ * This function prepares the hardware power domain state before entering
+ * system suspend. It must be paired with intel_power_domains_init_hw().
+ */
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
+{
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+ skl_display_core_uninit(dev_priv);
+
+ /*
+ * Even if power well support was disabled we still want to disable
+ * power wells while we are system suspended.
+ */
+ if (!i915.disable_power_well)
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+}
+
+/**
* intel_runtime_pm_get - grab a runtime pm reference
* @dev_priv: i915 device instance
*
@@ -2082,11 +2239,10 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
- if (!HAS_RUNTIME_PM(dev))
- return;
-
pm_runtime_get_sync(device);
- WARN(dev_priv->pm.suspended, "Device still suspended.\n");
+
+ atomic_inc(&dev_priv->pm.wakeref_count);
+ assert_rpm_wakelock_held(dev_priv);
}
/**
@@ -2111,11 +2267,10 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
- if (!HAS_RUNTIME_PM(dev))
- return;
-
- WARN(dev_priv->pm.suspended, "Getting nosync-ref while suspended.\n");
+ assert_rpm_wakelock_held(dev_priv);
pm_runtime_get_noresume(device);
+
+ atomic_inc(&dev_priv->pm.wakeref_count);
}
/**
@@ -2131,8 +2286,9 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
- if (!HAS_RUNTIME_PM(dev))
- return;
+ assert_rpm_wakelock_held(dev_priv);
+ if (atomic_dec_and_test(&dev_priv->pm.wakeref_count))
+ atomic_inc(&dev_priv->pm.atomic_seq);
pm_runtime_mark_last_busy(device);
pm_runtime_put_autosuspend(device);
@@ -2153,22 +2309,27 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
- if (!HAS_RUNTIME_PM(dev))
- return;
+ pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
+ pm_runtime_mark_last_busy(device);
/*
- * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
- * requirement.
+ * Take a permanent reference to disable the RPM functionality and drop
+ * it only when unloading the driver. Use the low level get/put helpers,
+ * so the driver's own RPM reference tracking asserts also work on
+ * platforms without RPM support.
*/
- if (!intel_enable_rc6(dev)) {
- DRM_INFO("RC6 disabled, disabling runtime PM support\n");
- return;
+ if (!HAS_RUNTIME_PM(dev)) {
+ pm_runtime_dont_use_autosuspend(device);
+ pm_runtime_get_sync(device);
+ } else {
+ pm_runtime_use_autosuspend(device);
}
- pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
- pm_runtime_mark_last_busy(device);
- pm_runtime_use_autosuspend(device);
-
+ /*
+ * The core calls the driver load handler with an RPM reference held.
+ * We drop that here and will reacquire it during unloading in
+ * intel_power_domains_fini().
+ */
pm_runtime_put_autosuspend(device);
}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index c42b636c2087..2e1da060b0e1 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -74,7 +74,7 @@ struct intel_sdvo {
struct i2c_adapter ddc;
/* Register for the SDVO device: SDVOB or SDVOC */
- uint32_t sdvo_reg;
+ i915_reg_t sdvo_reg;
/* Active outputs controlled by this SDVO output */
uint16_t controlled_output;
@@ -120,8 +120,7 @@ struct intel_sdvo {
*/
bool is_tv;
- /* On different gens SDVOB is at different places. */
- bool is_sdvob;
+ enum port port;
/* This is for current tv format name */
int tv_format_index;
@@ -245,7 +244,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
u32 bval = val, cval = val;
int i;
- if (intel_sdvo->sdvo_reg == PCH_SDVOB) {
+ if (HAS_PCH_SPLIT(dev_priv)) {
I915_WRITE(intel_sdvo->sdvo_reg, val);
POSTING_READ(intel_sdvo->sdvo_reg);
/*
@@ -259,7 +258,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
return;
}
- if (intel_sdvo->sdvo_reg == GEN3_SDVOB)
+ if (intel_sdvo->port == PORT_B)
cval = I915_READ(GEN3_SDVOC);
else
bval = I915_READ(GEN3_SDVOB);
@@ -422,7 +421,7 @@ static const struct _sdvo_cmd_name {
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
};
-#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC")
+#define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC")
static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
const void *args, int args_len)
@@ -1282,14 +1281,10 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
sdvox |= SDVO_BORDER_ENABLE;
} else {
sdvox = I915_READ(intel_sdvo->sdvo_reg);
- switch (intel_sdvo->sdvo_reg) {
- case GEN3_SDVOB:
+ if (intel_sdvo->port == PORT_B)
sdvox &= SDVOB_PRESERVE_MASK;
- break;
- case GEN3_SDVOC:
+ else
sdvox &= SDVOC_PRESERVE_MASK;
- break;
- }
sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
}
@@ -1464,12 +1459,23 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
* matching DP port to be enabled on transcoder A.
*/
if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
+ /*
+ * We get CPU/PCH FIFO underruns on the other pipe when
+ * doing the workaround. Sweep them under the rug.
+ */
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
temp &= ~SDVO_PIPE_B_SELECT;
temp |= SDVO_ENABLE;
intel_sdvo_write_sdvox(intel_sdvo, temp);
temp &= ~SDVO_ENABLE;
intel_sdvo_write_sdvox(intel_sdvo, temp);
+
+ intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
}
}
@@ -2251,7 +2257,7 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
{
struct sdvo_device_mapping *mapping;
- if (sdvo->is_sdvob)
+ if (sdvo->port == PORT_B)
mapping = &(dev_priv->sdvo_mappings[0]);
else
mapping = &(dev_priv->sdvo_mappings[1]);
@@ -2269,7 +2275,7 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
struct sdvo_device_mapping *mapping;
u8 pin;
- if (sdvo->is_sdvob)
+ if (sdvo->port == PORT_B)
mapping = &dev_priv->sdvo_mappings[0];
else
mapping = &dev_priv->sdvo_mappings[1];
@@ -2307,7 +2313,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo)
struct drm_i915_private *dev_priv = dev->dev_private;
struct sdvo_device_mapping *my_mapping, *other_mapping;
- if (sdvo->is_sdvob) {
+ if (sdvo->port == PORT_B) {
my_mapping = &dev_priv->sdvo_mappings[0];
other_mapping = &dev_priv->sdvo_mappings[1];
} else {
@@ -2332,7 +2338,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo)
/* No SDVO device info is found for another DVO port,
* so use mapping assumption we had before BIOS parsing.
*/
- if (sdvo->is_sdvob)
+ if (sdvo->port == PORT_B)
return 0x70;
else
return 0x72;
@@ -2939,18 +2945,31 @@ intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
return i2c_add_adapter(&sdvo->ddc) == 0;
}
-bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
+static void assert_sdvo_port_valid(const struct drm_i915_private *dev_priv,
+ enum port port)
+{
+ if (HAS_PCH_SPLIT(dev_priv))
+ WARN_ON(port != PORT_B);
+ else
+ WARN_ON(port != PORT_B && port != PORT_C);
+}
+
+bool intel_sdvo_init(struct drm_device *dev,
+ i915_reg_t sdvo_reg, enum port port)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
struct intel_sdvo *intel_sdvo;
int i;
+
+ assert_sdvo_port_valid(dev_priv, port);
+
intel_sdvo = kzalloc(sizeof(*intel_sdvo), GFP_KERNEL);
if (!intel_sdvo)
return false;
intel_sdvo->sdvo_reg = sdvo_reg;
- intel_sdvo->is_sdvob = is_sdvob;
+ intel_sdvo->port = port;
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1;
intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo);
if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev))
@@ -2959,7 +2978,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
/* encoder type will be decided later */
intel_encoder = &intel_sdvo->base;
intel_encoder->type = INTEL_OUTPUT_SDVO;
- drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
+ drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0,
+ NULL);
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
@@ -3000,8 +3020,10 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
* hotplug lines.
*/
if (intel_sdvo->hotplug_active) {
- intel_encoder->hpd_pin =
- intel_sdvo->is_sdvob ? HPD_SDVO_B : HPD_SDVO_C;
+ if (intel_sdvo->port == PORT_B)
+ intel_encoder->hpd_pin = HPD_SDVO_B;
+ else
+ intel_encoder->hpd_pin = HPD_SDVO_C;
}
/*
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 56dc132e8e20..4ff7a1f4183e 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -192,10 +192,9 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
const int pipe = intel_plane->pipe;
const int plane = intel_plane->plane + 1;
u32 plane_ctl, stride_div, stride;
- int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
const struct drm_intel_sprite_colorkey *key =
&to_intel_plane_state(drm_plane->state)->ckey;
- unsigned long surf_addr;
+ u32 surf_addr;
u32 tile_height, plane_offset, plane_size;
unsigned int rotation;
int x_offset, y_offset;
@@ -212,10 +211,6 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
rotation = drm_plane->state->rotation;
plane_ctl |= skl_plane_ctl_rotation(rotation);
- intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h,
- pixel_size, true,
- src_w != crtc_w || src_h != crtc_h);
-
stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
fb->pixel_format);
@@ -297,8 +292,6 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
I915_WRITE(PLANE_SURF(pipe, plane), 0);
POSTING_READ(PLANE_SURF(pipe, plane));
-
- intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
}
static void
@@ -541,10 +534,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
sprctl |= SPRITE_PIPE_CSC_ENABLE;
- intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size,
- true,
- src_w != crtc_w || src_h != crtc_h);
-
/* Sizes are 0 based */
src_w--;
src_h--;
@@ -678,10 +667,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (IS_GEN6(dev))
dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
- intel_update_sprite_watermarks(plane, crtc, src_w, src_h,
- pixel_size, true,
- src_w != crtc_w || src_h != crtc_h);
-
/* Sizes are 0 based */
src_w--;
src_h--;
@@ -832,8 +817,8 @@ intel_check_sprite_plane(struct drm_plane *plane,
hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
if (hscale < 0) {
DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
- drm_rect_debug_print(src, true);
- drm_rect_debug_print(dst, false);
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
return hscale;
}
@@ -841,8 +826,8 @@ intel_check_sprite_plane(struct drm_plane *plane,
vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
if (vscale < 0) {
DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
- drm_rect_debug_print(src, true);
- drm_rect_debug_print(dst, false);
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
return vscale;
}
@@ -938,9 +923,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
crtc = crtc ? crtc : plane->crtc;
- if (!crtc->state->active)
- return;
-
if (state->visible) {
intel_plane->update_plane(plane, crtc, fb,
state->dst.x1, state->dst.y1,
@@ -969,7 +951,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
return -EINVAL;
- if (IS_VALLEYVIEW(dev) &&
+ if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
set->flags & I915_SET_COLORKEY_DESTINATION)
return -EINVAL;
@@ -1104,7 +1086,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
intel_plane->max_downscale = 1;
}
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
intel_plane->update_plane = vlv_update_plane;
intel_plane->disable_plane = vlv_disable_plane;
@@ -1141,7 +1123,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
&intel_plane_funcs,
plane_formats, num_plane_formats,
- DRM_PLANE_TYPE_OVERLAY);
+ DRM_PLANE_TYPE_OVERLAY, NULL);
if (ret) {
kfree(intel_plane);
goto out;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 6bea78944cd6..948cbff6c62e 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1645,7 +1645,7 @@ intel_tv_init(struct drm_device *dev)
DRM_MODE_CONNECTOR_SVIDEO);
drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
- DRM_MODE_ENCODER_TVDAC);
+ DRM_MODE_ENCODER_TVDAC, NULL);
intel_encoder->compute_config = intel_tv_compute_config;
intel_encoder->get_config = intel_tv_get_config;
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 43cba129a0c0..277e60ae0e47 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -29,19 +29,7 @@
#define FORCEWAKE_ACK_TIMEOUT_MS 50
-#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
-#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
-#define __raw_i915_write16(dev_priv__, reg__, val__) writew(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-#define __raw_i915_write32(dev_priv__, reg__, val__) writel(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_i915_read64(dev_priv__, reg__) readq((dev_priv__)->regs + (reg__))
-#define __raw_i915_write64(dev_priv__, reg__, val__) writeq(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
+#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32((dev_priv__), (reg__))
static const char * const forcewake_domain_names[] = {
"render",
@@ -62,17 +50,10 @@ intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id)
return "unknown";
}
-static void
-assert_device_not_suspended(struct drm_i915_private *dev_priv)
-{
- WARN_ONCE(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended,
- "Device suspended\n");
-}
-
static inline void
fw_domain_reset(const struct intel_uncore_forcewake_domain *d)
{
- WARN_ON(d->reg_set == 0);
+ WARN_ON(!i915_mmio_reg_valid(d->reg_set));
__raw_i915_write32(d->i915, d->reg_set, d->val_reset);
}
@@ -118,7 +99,7 @@ static inline void
fw_domain_posting_read(const struct intel_uncore_forcewake_domain *d)
{
/* something from same cacheline, but not from the set register */
- if (d->reg_post)
+ if (i915_mmio_reg_valid(d->reg_post))
__raw_posting_read(d->i915, d->reg_post);
}
@@ -248,7 +229,7 @@ static void intel_uncore_fw_release_timer(unsigned long arg)
struct intel_uncore_forcewake_domain *domain = (void *)arg;
unsigned long irqflags;
- assert_device_not_suspended(domain->i915);
+ assert_rpm_device_not_suspended(domain->i915);
spin_lock_irqsave(&domain->i915->uncore.lock, irqflags);
if (WARN_ON(domain->wake_count == 0))
@@ -423,7 +404,7 @@ void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
if (!dev_priv->uncore.funcs.force_wake_get)
return;
- WARN_ON(dev_priv->pm.suspended);
+ assert_rpm_wakelock_held(dev_priv);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
__intel_uncore_forcewake_get(dev_priv, fw_domains);
@@ -525,8 +506,7 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
}
/* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(reg) \
- ((reg) < 0x40000 && (reg) != FORCEWAKE)
+#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000)
#define REG_RANGE(reg, start, end) ((reg) >= (start) && (reg) < (end))
@@ -589,7 +569,7 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
REG_RANGE((reg), 0x9400, 0x9800)
#define FORCEWAKE_GEN9_BLITTER_RANGE_OFFSET(reg) \
- ((reg) < 0x40000 &&\
+ ((reg) < 0x40000 && \
!FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) && \
!FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg) && \
!FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg) && \
@@ -605,8 +585,8 @@ ilk_dummy_write(struct drm_i915_private *dev_priv)
}
static void
-hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read,
- bool before)
+hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv,
+ i915_reg_t reg, bool read, bool before)
{
const char *op = read ? "reading" : "writing to";
const char *when = before ? "before" : "after";
@@ -616,7 +596,7 @@ hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read,
if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) {
WARN(1, "Unclaimed register detected %s %s register 0x%x\n",
- when, op, reg);
+ when, op, i915_mmio_reg_offset(reg));
__raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
i915.mmio_debug--; /* Only report the first N failures */
}
@@ -641,7 +621,7 @@ hsw_unclaimed_reg_detect(struct drm_i915_private *dev_priv)
#define GEN2_READ_HEADER(x) \
u##x val = 0; \
- assert_device_not_suspended(dev_priv);
+ assert_rpm_wakelock_held(dev_priv);
#define GEN2_READ_FOOTER \
trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
@@ -649,7 +629,7 @@ hsw_unclaimed_reg_detect(struct drm_i915_private *dev_priv)
#define __gen2_read(x) \
static u##x \
-gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen2_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
GEN2_READ_HEADER(x); \
val = __raw_i915_read##x(dev_priv, reg); \
GEN2_READ_FOOTER; \
@@ -657,7 +637,7 @@ gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
#define __gen5_read(x) \
static u##x \
-gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen5_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
GEN2_READ_HEADER(x); \
ilk_dummy_write(dev_priv); \
val = __raw_i915_read##x(dev_priv, reg); \
@@ -680,9 +660,10 @@ __gen2_read(64)
#undef GEN2_READ_HEADER
#define GEN6_READ_HEADER(x) \
+ u32 offset = i915_mmio_reg_offset(reg); \
unsigned long irqflags; \
u##x val = 0; \
- assert_device_not_suspended(dev_priv); \
+ assert_rpm_wakelock_held(dev_priv); \
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
#define GEN6_READ_FOOTER \
@@ -714,20 +695,12 @@ static inline void __force_wake_get(struct drm_i915_private *dev_priv,
dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
}
-#define __vgpu_read(x) \
-static u##x \
-vgpu_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- GEN6_READ_HEADER(x); \
- val = __raw_i915_read##x(dev_priv, reg); \
- GEN6_READ_FOOTER; \
-}
-
#define __gen6_read(x) \
static u##x \
-gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen6_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
GEN6_READ_HEADER(x); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
- if (NEEDS_FORCE_WAKE(reg)) \
+ if (NEEDS_FORCE_WAKE(offset)) \
__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
val = __raw_i915_read##x(dev_priv, reg); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
@@ -736,47 +709,56 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
#define __vlv_read(x) \
static u##x \
-vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+vlv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
+ enum forcewake_domains fw_engine = 0; \
GEN6_READ_HEADER(x); \
- if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
- else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
+ if (!NEEDS_FORCE_WAKE(offset)) \
+ fw_engine = 0; \
+ else if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_RENDER; \
+ else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_MEDIA; \
+ if (fw_engine) \
+ __force_wake_get(dev_priv, fw_engine); \
val = __raw_i915_read##x(dev_priv, reg); \
GEN6_READ_FOOTER; \
}
#define __chv_read(x) \
static u##x \
-chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+chv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
+ enum forcewake_domains fw_engine = 0; \
GEN6_READ_HEADER(x); \
- if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
- else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
- else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, \
- FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
+ if (!NEEDS_FORCE_WAKE(offset)) \
+ fw_engine = 0; \
+ else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_RENDER; \
+ else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_MEDIA; \
+ else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+ if (fw_engine) \
+ __force_wake_get(dev_priv, fw_engine); \
val = __raw_i915_read##x(dev_priv, reg); \
GEN6_READ_FOOTER; \
}
#define SKL_NEEDS_FORCE_WAKE(reg) \
- ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
+ ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
#define __gen9_read(x) \
static u##x \
-gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen9_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
enum forcewake_domains fw_engine; \
GEN6_READ_HEADER(x); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
- if (!SKL_NEEDS_FORCE_WAKE(reg)) \
+ if (!SKL_NEEDS_FORCE_WAKE(offset)) \
fw_engine = 0; \
- else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \
fw_engine = FORCEWAKE_RENDER; \
- else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \
fw_engine = FORCEWAKE_MEDIA; \
- else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \
fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
else \
fw_engine = FORCEWAKE_BLITTER; \
@@ -787,10 +769,6 @@ gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
GEN6_READ_FOOTER; \
}
-__vgpu_read(8)
-__vgpu_read(16)
-__vgpu_read(32)
-__vgpu_read(64)
__gen9_read(8)
__gen9_read(16)
__gen9_read(32)
@@ -812,19 +790,46 @@ __gen6_read(64)
#undef __chv_read
#undef __vlv_read
#undef __gen6_read
-#undef __vgpu_read
#undef GEN6_READ_FOOTER
#undef GEN6_READ_HEADER
+#define VGPU_READ_HEADER(x) \
+ unsigned long irqflags; \
+ u##x val = 0; \
+ assert_rpm_device_not_suspended(dev_priv); \
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define VGPU_READ_FOOTER \
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+ trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
+ return val
+
+#define __vgpu_read(x) \
+static u##x \
+vgpu_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
+ VGPU_READ_HEADER(x); \
+ val = __raw_i915_read##x(dev_priv, reg); \
+ VGPU_READ_FOOTER; \
+}
+
+__vgpu_read(8)
+__vgpu_read(16)
+__vgpu_read(32)
+__vgpu_read(64)
+
+#undef __vgpu_read
+#undef VGPU_READ_FOOTER
+#undef VGPU_READ_HEADER
+
#define GEN2_WRITE_HEADER \
trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
- assert_device_not_suspended(dev_priv); \
+ assert_rpm_wakelock_held(dev_priv); \
#define GEN2_WRITE_FOOTER
#define __gen2_write(x) \
static void \
-gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen2_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
GEN2_WRITE_HEADER; \
__raw_i915_write##x(dev_priv, reg, val); \
GEN2_WRITE_FOOTER; \
@@ -832,7 +837,7 @@ gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
#define __gen5_write(x) \
static void \
-gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen5_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
GEN2_WRITE_HEADER; \
ilk_dummy_write(dev_priv); \
__raw_i915_write##x(dev_priv, reg, val); \
@@ -855,9 +860,10 @@ __gen2_write(64)
#undef GEN2_WRITE_HEADER
#define GEN6_WRITE_HEADER \
+ u32 offset = i915_mmio_reg_offset(reg); \
unsigned long irqflags; \
trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
- assert_device_not_suspended(dev_priv); \
+ assert_rpm_wakelock_held(dev_priv); \
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
#define GEN6_WRITE_FOOTER \
@@ -865,10 +871,10 @@ __gen2_write(64)
#define __gen6_write(x) \
static void \
-gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen6_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
GEN6_WRITE_HEADER; \
- if (NEEDS_FORCE_WAKE(reg)) { \
+ if (NEEDS_FORCE_WAKE(offset)) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
__raw_i915_write##x(dev_priv, reg, val); \
@@ -880,10 +886,10 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
#define __hsw_write(x) \
static void \
-hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+hsw_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
GEN6_WRITE_HEADER; \
- if (NEEDS_FORCE_WAKE(reg)) { \
+ if (NEEDS_FORCE_WAKE(offset)) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
@@ -896,15 +902,7 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
GEN6_WRITE_FOOTER; \
}
-#define __vgpu_write(x) \
-static void vgpu_write##x(struct drm_i915_private *dev_priv, \
- off_t reg, u##x val, bool trace) { \
- GEN6_WRITE_HEADER; \
- __raw_i915_write##x(dev_priv, reg, val); \
- GEN6_WRITE_FOOTER; \
-}
-
-static const u32 gen8_shadowed_regs[] = {
+static const i915_reg_t gen8_shadowed_regs[] = {
FORCEWAKE_MT,
GEN6_RPNSWREQ,
GEN6_RC_VIDEO_FREQ,
@@ -915,11 +913,12 @@ static const u32 gen8_shadowed_regs[] = {
/* TODO: Other registers are not yet used */
};
-static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
+static bool is_gen8_shadowed(struct drm_i915_private *dev_priv,
+ i915_reg_t reg)
{
int i;
for (i = 0; i < ARRAY_SIZE(gen8_shadowed_regs); i++)
- if (reg == gen8_shadowed_regs[i])
+ if (i915_mmio_reg_equal(reg, gen8_shadowed_regs[i]))
return true;
return false;
@@ -927,10 +926,10 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
#define __gen8_write(x) \
static void \
-gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen8_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
GEN6_WRITE_HEADER; \
hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
- if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) \
+ if (NEEDS_FORCE_WAKE(offset) && !is_gen8_shadowed(dev_priv, reg)) \
__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
__raw_i915_write##x(dev_priv, reg, val); \
hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
@@ -940,22 +939,25 @@ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
#define __chv_write(x) \
static void \
-chv_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
- bool shadowed = is_gen8_shadowed(dev_priv, reg); \
+chv_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
+ enum forcewake_domains fw_engine = 0; \
GEN6_WRITE_HEADER; \
- if (!shadowed) { \
- if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
- else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
- else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
- __force_wake_get(dev_priv, FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
- } \
+ if (!NEEDS_FORCE_WAKE(offset) || \
+ is_gen8_shadowed(dev_priv, reg)) \
+ fw_engine = 0; \
+ else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_RENDER; \
+ else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_MEDIA; \
+ else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \
+ fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+ if (fw_engine) \
+ __force_wake_get(dev_priv, fw_engine); \
__raw_i915_write##x(dev_priv, reg, val); \
GEN6_WRITE_FOOTER; \
}
-static const u32 gen9_shadowed_regs[] = {
+static const i915_reg_t gen9_shadowed_regs[] = {
RING_TAIL(RENDER_RING_BASE),
RING_TAIL(GEN6_BSD_RING_BASE),
RING_TAIL(VEBOX_RING_BASE),
@@ -968,11 +970,12 @@ static const u32 gen9_shadowed_regs[] = {
/* TODO: Other registers are not yet used */
};
-static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg)
+static bool is_gen9_shadowed(struct drm_i915_private *dev_priv,
+ i915_reg_t reg)
{
int i;
for (i = 0; i < ARRAY_SIZE(gen9_shadowed_regs); i++)
- if (reg == gen9_shadowed_regs[i])
+ if (i915_mmio_reg_equal(reg, gen9_shadowed_regs[i]))
return true;
return false;
@@ -980,19 +983,19 @@ static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg)
#define __gen9_write(x) \
static void \
-gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
+gen9_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, \
bool trace) { \
enum forcewake_domains fw_engine; \
GEN6_WRITE_HEADER; \
hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
- if (!SKL_NEEDS_FORCE_WAKE(reg) || \
+ if (!SKL_NEEDS_FORCE_WAKE(offset) || \
is_gen9_shadowed(dev_priv, reg)) \
fw_engine = 0; \
- else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \
fw_engine = FORCEWAKE_RENDER; \
- else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \
fw_engine = FORCEWAKE_MEDIA; \
- else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \
fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
else \
fw_engine = FORCEWAKE_BLITTER; \
@@ -1024,20 +1027,41 @@ __gen6_write(8)
__gen6_write(16)
__gen6_write(32)
__gen6_write(64)
-__vgpu_write(8)
-__vgpu_write(16)
-__vgpu_write(32)
-__vgpu_write(64)
#undef __gen9_write
#undef __chv_write
#undef __gen8_write
#undef __hsw_write
#undef __gen6_write
-#undef __vgpu_write
#undef GEN6_WRITE_FOOTER
#undef GEN6_WRITE_HEADER
+#define VGPU_WRITE_HEADER \
+ unsigned long irqflags; \
+ trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+ assert_rpm_device_not_suspended(dev_priv); \
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define VGPU_WRITE_FOOTER \
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+
+#define __vgpu_write(x) \
+static void vgpu_write##x(struct drm_i915_private *dev_priv, \
+ i915_reg_t reg, u##x val, bool trace) { \
+ VGPU_WRITE_HEADER; \
+ __raw_i915_write##x(dev_priv, reg, val); \
+ VGPU_WRITE_FOOTER; \
+}
+
+__vgpu_write(8)
+__vgpu_write(16)
+__vgpu_write(32)
+__vgpu_write(64)
+
+#undef __vgpu_write
+#undef VGPU_WRITE_FOOTER
+#undef VGPU_WRITE_HEADER
+
#define ASSIGN_WRITE_MMIO_VFUNCS(x) \
do { \
dev_priv->uncore.funcs.mmio_writeb = x##_write8; \
@@ -1057,7 +1081,8 @@ do { \
static void fw_domain_init(struct drm_i915_private *dev_priv,
enum forcewake_domain_id domain_id,
- u32 reg_set, u32 reg_ack)
+ i915_reg_t reg_set,
+ i915_reg_t reg_ack)
{
struct intel_uncore_forcewake_domain *d;
@@ -1083,12 +1108,10 @@ static void fw_domain_init(struct drm_i915_private *dev_priv,
d->val_clear = _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL);
}
- if (IS_VALLEYVIEW(dev_priv))
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
d->reg_post = FORCEWAKE_ACK_VLV;
else if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv) || IS_GEN8(dev_priv))
d->reg_post = ECOBUS;
- else
- d->reg_post = 0;
d->i915 = dev_priv;
d->id = domain_id;
@@ -1118,7 +1141,7 @@ static void intel_uncore_fw_domains_init(struct drm_device *dev)
FORCEWAKE_ACK_BLITTER_GEN9);
fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA,
FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
dev_priv->uncore.funcs.force_wake_get = fw_domains_get;
if (!IS_CHERRYVIEW(dev))
dev_priv->uncore.funcs.force_wake_put =
@@ -1262,12 +1285,14 @@ void intel_uncore_fini(struct drm_device *dev)
#define GEN_RANGE(l, h) GENMASK(h, l)
static const struct register_whitelist {
- uint64_t offset;
+ i915_reg_t offset_ldw, offset_udw;
uint32_t size;
/* supported gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
uint32_t gen_bitmask;
} whitelist[] = {
- { RING_TIMESTAMP(RENDER_RING_BASE), 8, GEN_RANGE(4, 9) },
+ { .offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE),
+ .offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE),
+ .size = 8, .gen_bitmask = GEN_RANGE(4, 9) },
};
int i915_reg_read_ioctl(struct drm_device *dev,
@@ -1277,11 +1302,11 @@ int i915_reg_read_ioctl(struct drm_device *dev,
struct drm_i915_reg_read *reg = data;
struct register_whitelist const *entry = whitelist;
unsigned size;
- u64 offset;
+ i915_reg_t offset_ldw, offset_udw;
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
- if (entry->offset == (reg->offset & -entry->size) &&
+ if (i915_mmio_reg_offset(entry->offset_ldw) == (reg->offset & -entry->size) &&
(1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
break;
}
@@ -1293,27 +1318,28 @@ int i915_reg_read_ioctl(struct drm_device *dev,
* be naturally aligned (and those that are not so aligned merely
* limit the available flags for that register).
*/
- offset = entry->offset;
+ offset_ldw = entry->offset_ldw;
+ offset_udw = entry->offset_udw;
size = entry->size;
- size |= reg->offset ^ offset;
+ size |= reg->offset ^ i915_mmio_reg_offset(offset_ldw);
intel_runtime_pm_get(dev_priv);
switch (size) {
case 8 | 1:
- reg->val = I915_READ64_2x32(offset, offset+4);
+ reg->val = I915_READ64_2x32(offset_ldw, offset_udw);
break;
case 8:
- reg->val = I915_READ64(offset);
+ reg->val = I915_READ64(offset_ldw);
break;
case 4:
- reg->val = I915_READ(offset);
+ reg->val = I915_READ(offset_ldw);
break;
case 2:
- reg->val = I915_READ16(offset);
+ reg->val = I915_READ16(offset_ldw);
break;
case 1:
- reg->val = I915_READ8(offset);
+ reg->val = I915_READ8(offset_ldw);
break;
default:
ret = -EINVAL;
@@ -1470,7 +1496,7 @@ static int gen6_do_reset(struct drm_device *dev)
}
static int wait_for_register(struct drm_i915_private *dev_priv,
- const u32 reg,
+ i915_reg_t reg,
const u32 mask,
const u32 value,
const unsigned long timeout_ms)
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 2b81a417cf29..35ca4f007839 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -10,15 +10,6 @@ config DRM_IMX
help
enable i.MX graphics support
-config DRM_IMX_FB_HELPER
- tristate "provide legacy framebuffer /dev/fb0"
- select DRM_KMS_CMA_HELPER
- depends on DRM_IMX
- help
- The DRM framework can provide a legacy /dev/fb0 framebuffer
- for your device. This is necessary to get a framebuffer console
- and also for applications using the legacy framebuffer API
-
config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
select DRM_PANEL
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index 98605ea2ad9d..063825fecbe2 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -137,7 +137,7 @@ static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24);
}
-static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
.mode_fixup = dw_hdmi_imx_encoder_mode_fixup,
.mode_set = dw_hdmi_imx_encoder_mode_set,
.prepare = dw_hdmi_imx_encoder_prepare,
@@ -145,7 +145,7 @@ static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
.disable = dw_hdmi_imx_encoder_disable,
};
-static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
+static const struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -251,7 +251,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
}
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 7b990b4e96d2..2f57d7967417 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -39,46 +39,41 @@ struct imx_drm_component {
struct imx_drm_device {
struct drm_device *drm;
struct imx_drm_crtc *crtc[MAX_CRTC];
- int pipes;
+ unsigned int pipes;
struct drm_fbdev_cma *fbhelper;
};
struct imx_drm_crtc {
struct drm_crtc *crtc;
- int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
};
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
+#endif
-int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
+unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
- return crtc->pipe;
+ return drm_crtc_index(crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
-#endif
}
static int imx_drm_driver_unload(struct drm_device *drm)
{
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
-#endif
drm_kms_helper_poll_fini(drm);
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
if (imxdrm->fbhelper)
drm_fbdev_cma_fini(imxdrm->fbhelper);
-#endif
component_unbind_all(drm->dev, drm);
@@ -128,19 +123,19 @@ EXPORT_SYMBOL_GPL(imx_drm_set_bus_format);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{
- return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
+ return drm_crtc_vblank_get(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
{
- drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
+ drm_crtc_vblank_put(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
{
- drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
+ drm_crtc_handle_vblank(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
@@ -214,14 +209,12 @@ EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
static void imx_drm_output_poll_changed(struct drm_device *drm)
{
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
-#endif
}
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.output_poll_changed = imx_drm_output_poll_changed,
};
@@ -307,11 +300,12 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
* The fb helper takes copies of key hardware information, so the
* crtcs/connectors/encoders must not change after this point.
*/
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
if (legacyfb_depth != 16 && legacyfb_depth != 32) {
dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
legacyfb_depth = 16;
}
+ drm_helper_disable_unused_functions(drm);
imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
drm->mode_config.num_crtc, MAX_CRTC);
if (IS_ERR(imxdrm->fbhelper)) {
@@ -362,12 +356,11 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
return -ENOMEM;
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
- imx_drm_crtc->pipe = imxdrm->pipes++;
imx_drm_crtc->crtc = crtc;
crtc->port = port;
- imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
+ imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc;
*new_crtc = imx_drm_crtc;
@@ -379,12 +372,12 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
- imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+ imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL);
return 0;
err_register:
- imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
+ imxdrm->crtc[--imxdrm->pipes] = NULL;
kfree(imx_drm_crtc);
return ret;
}
@@ -396,10 +389,11 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
{
struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
+ unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc);
drm_crtc_cleanup(imx_drm_crtc->crtc);
- imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
+ imxdrm->crtc[pipe] = NULL;
kfree(imx_drm_crtc);
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index 83284b4d4be1..71cf6d9c714f 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -13,7 +13,7 @@ struct drm_plane;
struct imx_drm_crtc;
struct platform_device;
-int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
+unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
struct imx_drm_crtc_helper_funcs {
int (*enable_vblank)(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index abacc8f67469..22ac482231ed 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -358,23 +358,23 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
drm_panel_unprepare(imx_ldb_ch->panel);
}
-static struct drm_connector_funcs imx_ldb_connector_funcs = {
+static const struct drm_connector_funcs imx_ldb_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_ldb_connector_detect,
.destroy = imx_drm_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
.get_modes = imx_ldb_connector_get_modes,
.best_encoder = imx_ldb_connector_best_encoder,
};
-static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
+static const struct drm_encoder_funcs imx_ldb_encoder_funcs = {
.destroy = imx_drm_encoder_destroy,
};
-static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
.dpms = imx_ldb_encoder_dpms,
.mode_fixup = imx_ldb_encoder_mode_fixup,
.prepare = imx_ldb_encoder_prepare,
@@ -422,7 +422,7 @@ static int imx_ldb_register(struct drm_device *drm,
drm_encoder_helper_add(&imx_ldb_ch->encoder,
&imx_ldb_encoder_helper_funcs);
drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
drm_connector_helper_add(&imx_ldb_ch->connector,
&imx_ldb_connector_helper_funcs);
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index f9597146dc67..292349f0b132 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -360,24 +360,24 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
tve_disable(tve);
}
-static struct drm_connector_funcs imx_tve_connector_funcs = {
+static const struct drm_connector_funcs imx_tve_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_tve_connector_detect,
.destroy = imx_drm_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
.get_modes = imx_tve_connector_get_modes,
.best_encoder = imx_tve_connector_best_encoder,
.mode_valid = imx_tve_connector_mode_valid,
};
-static struct drm_encoder_funcs imx_tve_encoder_funcs = {
+static const struct drm_encoder_funcs imx_tve_encoder_funcs = {
.destroy = imx_drm_encoder_destroy,
};
-static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
.dpms = imx_tve_encoder_dpms,
.mode_fixup = imx_tve_encoder_mode_fixup,
.prepare = imx_tve_encoder_prepare,
@@ -508,7 +508,7 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
- encoder_type);
+ encoder_type, NULL);
drm_connector_helper_add(&tve->connector,
&imx_tve_connector_helper_funcs);
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 4ab841eebee1..30a57185bdb4 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -270,7 +270,7 @@ static void ipu_crtc_commit(struct drm_crtc *crtc)
ipu_fb_enable(ipu_crtc);
}
-static struct drm_crtc_helper_funcs ipu_helper_funcs = {
+static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
.dpms = ipu_crtc_dpms,
.mode_fixup = ipu_crtc_mode_fixup,
.mode_set = ipu_crtc_mode_set,
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index e2ff410bab74..591ba2f1ae03 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -401,7 +401,8 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
&ipu_plane_funcs, ipu_plane_formats,
- ARRAY_SIZE(ipu_plane_formats), type);
+ ARRAY_SIZE(ipu_plane_formats), type,
+ NULL);
if (ret) {
DRM_ERROR("failed to initialize plane\n");
kfree(ipu_plane);
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 2e9b9f1b5cd2..0ffef172afb4 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -148,23 +148,23 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
drm_panel_unprepare(imxpd->panel);
}
-static struct drm_connector_funcs imx_pd_connector_funcs = {
+static const struct drm_connector_funcs imx_pd_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_pd_connector_detect,
.destroy = imx_drm_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
.get_modes = imx_pd_connector_get_modes,
.best_encoder = imx_pd_connector_best_encoder,
};
-static struct drm_encoder_funcs imx_pd_encoder_funcs = {
+static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
.destroy = imx_drm_encoder_destroy,
};
-static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
.dpms = imx_pd_encoder_dpms,
.mode_fixup = imx_pd_encoder_mode_fixup,
.prepare = imx_pd_encoder_prepare,
@@ -192,7 +192,7 @@ static int imx_pd_register(struct drm_device *drm,
drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
- DRM_MODE_ENCODER_NONE);
+ DRM_MODE_ENCODER_NONE, NULL);
drm_connector_helper_add(&imxpd->connector,
&imx_pd_connector_helper_funcs);
@@ -204,8 +204,6 @@ static int imx_pd_register(struct drm_device *drm,
drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
- imxpd->connector.encoder = &imxpd->encoder;
-
return 0;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 912151c36d59..205b2801d3b8 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -252,7 +252,7 @@ void mgag200_fbdev_fini(struct mga_device *mdev);
/* mgag200_main.c */
int mgag200_framebuffer_init(struct drm_device *dev,
struct mga_framebuffer *mfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index b35b5b2db4ec..d9b04b008feb 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -138,7 +138,7 @@ static struct fb_ops mgag200fb_ops = {
};
static int mgag200fb_create_object(struct mga_fbdev *afbdev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **gobj_p)
{
struct drm_device *dev = afbdev->helper.dev;
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index b1a0f5656175..9147444d5bf2 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -29,7 +29,7 @@ static const struct drm_framebuffer_funcs mga_fb_funcs = {
int mgag200_framebuffer_init(struct drm_device *dev,
struct mga_framebuffer *gfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -47,7 +47,7 @@ int mgag200_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
mgag200_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct mga_framebuffer *mga_fb;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index c99d3fe12881..dc13c4857e6f 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1538,7 +1538,7 @@ static struct drm_encoder *mga_encoder_init(struct drm_device *dev)
encoder->possible_crtcs = 0x1;
drm_encoder_init(dev, encoder, &mga_encoder_encoder_funcs,
- DRM_MODE_ENCODER_DAC);
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &mga_encoder_helper_funcs);
return encoder;
@@ -1564,7 +1564,7 @@ static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode,
int bits_per_pixel)
{
uint32_t total_area, divisor;
- int64_t active_area, pixels_per_second, bandwidth;
+ uint64_t active_area, pixels_per_second, bandwidth;
uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
divisor = 1024;
@@ -1684,13 +1684,13 @@ static void mga_connector_destroy(struct drm_connector *connector)
kfree(connector);
}
-struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
.get_modes = mga_vga_get_modes,
.mode_valid = mga_vga_mode_valid,
.best_encoder = mga_connector_best_encoder,
};
-struct drm_connector_funcs mga_vga_connector_funcs = {
+static const struct drm_connector_funcs mga_vga_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = mga_vga_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 84d3ec98e6b9..215495c2780c 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -54,3 +54,11 @@ config DRM_MSM_DSI_20NM_PHY
default y
help
Choose this option if the 20nm DSI PHY is used on the platform.
+
+config DRM_MSM_DSI_28NM_8960_PHY
+ bool "Enable DSI 28nm 8960 PHY driver in MSM DRM"
+ depends on DRM_MSM_DSI
+ default y
+ help
+ Choose this option if the 28nm DSI PHY 8960 variant is used on the
+ platform.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 1c90290be716..065ad4138799 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -54,6 +54,7 @@ msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
+ mdp/mdp4/mdp4_dsi_encoder.o \
dsi/dsi_cfg.o \
dsi/dsi_host.o \
dsi/dsi_manager.o \
@@ -62,10 +63,12 @@ msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o
msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o
+msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o
ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y)
msm-y += dsi/pll/dsi_pll.o
msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o
+msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o
endif
obj-$(CONFIG_DRM_MSM) += msm.o
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 1ea2df524fac..950d27d26b30 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -19,10 +19,6 @@
#include "adreno_gpu.h"
-#if defined(DOWNSTREAM_CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
-# include <mach/kgsl.h>
-#endif
-
#define ANY_ID 0xff
bool hang_debug = false;
@@ -168,7 +164,6 @@ static void set_gpu_pdev(struct drm_device *dev,
static int adreno_bind(struct device *dev, struct device *master, void *data)
{
static struct adreno_platform_config config = {};
-#ifdef CONFIG_OF
struct device_node *child, *node = dev->of_node;
u32 val;
int ret;
@@ -205,53 +200,6 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
return -ENXIO;
}
-#else
- struct kgsl_device_platform_data *pdata = dev->platform_data;
- uint32_t version = socinfo_get_version();
- if (cpu_is_apq8064ab()) {
- config.fast_rate = 450000000;
- config.slow_rate = 27000000;
- config.bus_freq = 4;
- config.rev = ADRENO_REV(3, 2, 1, 0);
- } else if (cpu_is_apq8064()) {
- config.fast_rate = 400000000;
- config.slow_rate = 27000000;
- config.bus_freq = 4;
-
- if (SOCINFO_VERSION_MAJOR(version) == 2)
- config.rev = ADRENO_REV(3, 2, 0, 2);
- else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
- (SOCINFO_VERSION_MINOR(version) == 1))
- config.rev = ADRENO_REV(3, 2, 0, 1);
- else
- config.rev = ADRENO_REV(3, 2, 0, 0);
-
- } else if (cpu_is_msm8960ab()) {
- config.fast_rate = 400000000;
- config.slow_rate = 320000000;
- config.bus_freq = 4;
-
- if (SOCINFO_VERSION_MINOR(version) == 0)
- config.rev = ADRENO_REV(3, 2, 1, 0);
- else
- config.rev = ADRENO_REV(3, 2, 1, 1);
-
- } else if (cpu_is_msm8930()) {
- config.fast_rate = 400000000;
- config.slow_rate = 27000000;
- config.bus_freq = 3;
-
- if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
- (SOCINFO_VERSION_MINOR(version) == 2))
- config.rev = ADRENO_REV(3, 0, 5, 2);
- else
- config.rev = ADRENO_REV(3, 0, 5, 0);
-
- }
-# ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
- config.bus_scale_table = pdata->bus_scale_table;
-# endif
-#endif
dev->platform_data = &config;
set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
return 0;
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 5f5a3732cdf6..749fbb28ec3d 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -31,10 +31,12 @@ enum msm_dsi_phy_type {
MSM_DSI_PHY_28NM_HPM,
MSM_DSI_PHY_28NM_LP,
MSM_DSI_PHY_20NM,
+ MSM_DSI_PHY_28NM_8960,
MSM_DSI_PHY_MAX
};
#define DSI_DEV_REGULATOR_MAX 8
+#define DSI_BUS_CLK_MAX 4
/* Regulators for DSI devices */
struct dsi_reg_entry {
@@ -89,7 +91,7 @@ int msm_dsi_manager_phy_enable(int id,
u32 *clk_pre, u32 *clk_post);
void msm_dsi_manager_phy_disable(int id);
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
-bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len);
+bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
@@ -143,7 +145,7 @@ int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg);
void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
- u32 iova, u32 len);
+ u32 dma_base, u32 len);
int msm_dsi_host_enable(struct mipi_dsi_host *host);
int msm_dsi_host_disable(struct mipi_dsi_host *host);
int msm_dsi_host_power_on(struct mipi_dsi_host *host);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
index 5872d5e5934f..2a827d8093a2 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -13,9 +13,26 @@
#include "dsi_cfg.h"
-/* DSI v2 has not been supported by now */
-static const struct msm_dsi_config dsi_v2_cfg = {
+static const char * const dsi_v2_bus_clk_names[] = {
+ "core_mmss_clk", "iface_clk", "bus_clk",
+};
+
+static const struct msm_dsi_config apq8064_dsi_cfg = {
.io_offset = 0,
+ .reg_cfg = {
+ .num = 3,
+ .regs = {
+ {"vdda", 1200000, 1200000, 100000, 100},
+ {"avdd", 3000000, 3000000, 110000, 100},
+ {"vddio", 1800000, 1800000, 100000, 100},
+ },
+ },
+ .bus_clk_names = dsi_v2_bus_clk_names,
+ .num_bus_clks = ARRAY_SIZE(dsi_v2_bus_clk_names),
+};
+
+static const char * const dsi_6g_bus_clk_names[] = {
+ "mdp_core_clk", "iface_clk", "bus_clk", "core_mmss_clk",
};
static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = {
@@ -29,6 +46,12 @@ static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
+ .bus_clk_names = dsi_6g_bus_clk_names,
+ .num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names),
+};
+
+static const char * const dsi_8916_bus_clk_names[] = {
+ "mdp_core_clk", "iface_clk", "bus_clk",
};
static const struct msm_dsi_config msm8916_dsi_cfg = {
@@ -42,6 +65,8 @@ static const struct msm_dsi_config msm8916_dsi_cfg = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
+ .bus_clk_names = dsi_8916_bus_clk_names,
+ .num_bus_clks = ARRAY_SIZE(dsi_8916_bus_clk_names),
};
static const struct msm_dsi_config msm8994_dsi_cfg = {
@@ -57,11 +82,13 @@ static const struct msm_dsi_config msm8994_dsi_cfg = {
{"lab_reg", -1, -1, -1, -1},
{"ibb_reg", -1, -1, -1, -1},
},
- }
+ },
+ .bus_clk_names = dsi_6g_bus_clk_names,
+ .num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names),
};
static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
- {MSM_DSI_VER_MAJOR_V2, U32_MAX, &dsi_v2_cfg},
+ {MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0,
&msm8974_apq8084_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1,
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
index 4cf887240177..a68c836744a3 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
@@ -25,11 +25,15 @@
#define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
+#define MSM_DSI_V2_VER_MINOR_8064 0x0
+
#define DSI_6G_REG_SHIFT 4
struct msm_dsi_config {
u32 io_offset;
struct dsi_reg_config reg_cfg;
+ const char * const *bus_clk_names;
+ const int num_bus_clks;
};
struct msm_dsi_cfg_handler {
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 4c49868efcda..48f9967b4a1b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -24,26 +24,36 @@
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <video/mipi_display.h>
#include "dsi.h"
#include "dsi.xml.h"
+#include "sfpb.xml.h"
#include "dsi_cfg.h"
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
{
u32 ver;
- u32 ver_6g;
if (!major || !minor)
return -EINVAL;
- /* From DSI6G(v3), addition of a 6G_HW_VERSION register at offset 0
+ /*
+ * From DSI6G(v3), addition of a 6G_HW_VERSION register at offset 0
* makes all other registers 4-byte shifted down.
+ *
+ * In order to identify between DSI6G(v3) and beyond, and DSIv2 and
+ * older, we read the DSI_VERSION register without any shift(offset
+ * 0x1f0). In the case of DSIv2, this hast to be a non-zero value. In
+ * the case of DSI6G, this has to be zero (the offset points to a
+ * scratch register which we never touch)
*/
- ver_6g = msm_readl(base + REG_DSI_6G_HW_VERSION);
- if (ver_6g == 0) {
- ver = msm_readl(base + REG_DSI_VERSION);
+
+ ver = msm_readl(base + REG_DSI_VERSION);
+ if (ver) {
+ /* older dsi host, there is no register shift */
ver = FIELD(ver, DSI_VERSION_MAJOR);
if (ver <= MSM_DSI_VER_MAJOR_V2) {
/* old versions */
@@ -54,12 +64,17 @@ static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
return -EINVAL;
}
} else {
+ /*
+ * newer host, offset 0 has 6G_HW_VERSION, the rest of the
+ * registers are shifted down, read DSI_VERSION again with
+ * the shifted offset
+ */
ver = msm_readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION);
ver = FIELD(ver, DSI_VERSION_MAJOR);
if (ver == MSM_DSI_VER_MAJOR_6G) {
/* 6G version */
*major = ver;
- *minor = ver_6g;
+ *minor = msm_readl(base + REG_DSI_6G_HW_VERSION);
return 0;
} else {
return -EINVAL;
@@ -91,10 +106,9 @@ struct msm_dsi_host {
void __iomem *ctrl_base;
struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
- struct clk *mdp_core_clk;
- struct clk *ahb_clk;
- struct clk *axi_clk;
- struct clk *mmss_misc_ahb_clk;
+
+ struct clk *bus_clks[DSI_BUS_CLK_MAX];
+
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
@@ -102,6 +116,14 @@ struct msm_dsi_host {
struct clk *pixel_clk_src;
u32 byte_clk_rate;
+ u32 esc_clk_rate;
+
+ /* DSI v2 specific clocks */
+ struct clk *src_clk;
+ struct clk *esc_clk_src;
+ struct clk *dsi_clk_src;
+
+ u32 src_clk_rate;
struct gpio_desc *disp_en_gpio;
struct gpio_desc *te_gpio;
@@ -119,9 +141,19 @@ struct msm_dsi_host {
struct work_struct err_work;
struct workqueue_struct *workqueue;
+ /* DSI 6G TX buffer*/
struct drm_gem_object *tx_gem_obj;
+
+ /* DSI v2 TX buffer */
+ void *tx_buf;
+ dma_addr_t tx_buf_paddr;
+
+ int tx_size;
+
u8 *rx_buf;
+ struct regmap *sfpb;
+
struct drm_display_mode *mode;
/* connected device info */
@@ -165,21 +197,31 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
struct msm_dsi_host *msm_host)
{
const struct msm_dsi_cfg_handler *cfg_hnd = NULL;
+ struct device *dev = &msm_host->pdev->dev;
struct regulator *gdsc_reg;
+ struct clk *ahb_clk;
int ret;
u32 major = 0, minor = 0;
- gdsc_reg = regulator_get(&msm_host->pdev->dev, "gdsc");
+ gdsc_reg = regulator_get(dev, "gdsc");
if (IS_ERR(gdsc_reg)) {
pr_err("%s: cannot get gdsc\n", __func__);
goto exit;
}
+
+ ahb_clk = clk_get(dev, "iface_clk");
+ if (IS_ERR(ahb_clk)) {
+ pr_err("%s: cannot get interface clock\n", __func__);
+ goto put_gdsc;
+ }
+
ret = regulator_enable(gdsc_reg);
if (ret) {
pr_err("%s: unable to enable gdsc\n", __func__);
- goto put_gdsc;
+ goto put_clk;
}
- ret = clk_prepare_enable(msm_host->ahb_clk);
+
+ ret = clk_prepare_enable(ahb_clk);
if (ret) {
pr_err("%s: unable to enable ahb_clk\n", __func__);
goto disable_gdsc;
@@ -196,9 +238,11 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
DBG("%s: Version %x:%x\n", __func__, major, minor);
disable_clks:
- clk_disable_unprepare(msm_host->ahb_clk);
+ clk_disable_unprepare(ahb_clk);
disable_gdsc:
regulator_disable(gdsc_reg);
+put_clk:
+ clk_put(ahb_clk);
put_gdsc:
regulator_put(gdsc_reg);
exit:
@@ -295,40 +339,23 @@ static int dsi_regulator_init(struct msm_dsi_host *msm_host)
static int dsi_clk_init(struct msm_dsi_host *msm_host)
{
struct device *dev = &msm_host->pdev->dev;
- int ret = 0;
-
- msm_host->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk");
- if (IS_ERR(msm_host->mdp_core_clk)) {
- ret = PTR_ERR(msm_host->mdp_core_clk);
- pr_err("%s: Unable to get mdp core clk. ret=%d\n",
- __func__, ret);
- goto exit;
- }
-
- msm_host->ahb_clk = devm_clk_get(dev, "iface_clk");
- if (IS_ERR(msm_host->ahb_clk)) {
- ret = PTR_ERR(msm_host->ahb_clk);
- pr_err("%s: Unable to get mdss ahb clk. ret=%d\n",
- __func__, ret);
- goto exit;
- }
-
- msm_host->axi_clk = devm_clk_get(dev, "bus_clk");
- if (IS_ERR(msm_host->axi_clk)) {
- ret = PTR_ERR(msm_host->axi_clk);
- pr_err("%s: Unable to get axi bus clk. ret=%d\n",
- __func__, ret);
- goto exit;
- }
-
- msm_host->mmss_misc_ahb_clk = devm_clk_get(dev, "core_mmss_clk");
- if (IS_ERR(msm_host->mmss_misc_ahb_clk)) {
- ret = PTR_ERR(msm_host->mmss_misc_ahb_clk);
- pr_err("%s: Unable to get mmss misc ahb clk. ret=%d\n",
- __func__, ret);
- goto exit;
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+ const struct msm_dsi_config *cfg = cfg_hnd->cfg;
+ int i, ret = 0;
+
+ /* get bus clocks */
+ for (i = 0; i < cfg->num_bus_clks; i++) {
+ msm_host->bus_clks[i] = devm_clk_get(dev,
+ cfg->bus_clk_names[i]);
+ if (IS_ERR(msm_host->bus_clks[i])) {
+ ret = PTR_ERR(msm_host->bus_clks[i]);
+ pr_err("%s: Unable to get %s, ret = %d\n",
+ __func__, cfg->bus_clk_names[i], ret);
+ goto exit;
+ }
}
+ /* get link and source clocks */
msm_host->byte_clk = devm_clk_get(dev, "byte_clk");
if (IS_ERR(msm_host->byte_clk)) {
ret = PTR_ERR(msm_host->byte_clk);
@@ -356,80 +383,85 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host)
goto exit;
}
- msm_host->byte_clk_src = devm_clk_get(dev, "byte_clk_src");
- if (IS_ERR(msm_host->byte_clk_src)) {
- ret = PTR_ERR(msm_host->byte_clk_src);
+ msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk);
+ if (!msm_host->byte_clk_src) {
+ ret = -ENODEV;
pr_err("%s: can't find byte_clk_src. ret=%d\n", __func__, ret);
- msm_host->byte_clk_src = NULL;
goto exit;
}
- msm_host->pixel_clk_src = devm_clk_get(dev, "pixel_clk_src");
- if (IS_ERR(msm_host->pixel_clk_src)) {
- ret = PTR_ERR(msm_host->pixel_clk_src);
+ msm_host->pixel_clk_src = clk_get_parent(msm_host->pixel_clk);
+ if (!msm_host->pixel_clk_src) {
+ ret = -ENODEV;
pr_err("%s: can't find pixel_clk_src. ret=%d\n", __func__, ret);
- msm_host->pixel_clk_src = NULL;
goto exit;
}
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
+ msm_host->src_clk = devm_clk_get(dev, "src_clk");
+ if (IS_ERR(msm_host->src_clk)) {
+ ret = PTR_ERR(msm_host->src_clk);
+ pr_err("%s: can't find dsi_src_clk. ret=%d\n",
+ __func__, ret);
+ msm_host->src_clk = NULL;
+ goto exit;
+ }
+
+ msm_host->esc_clk_src = clk_get_parent(msm_host->esc_clk);
+ if (!msm_host->esc_clk_src) {
+ ret = -ENODEV;
+ pr_err("%s: can't get esc_clk_src. ret=%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ msm_host->dsi_clk_src = clk_get_parent(msm_host->src_clk);
+ if (!msm_host->dsi_clk_src) {
+ ret = -ENODEV;
+ pr_err("%s: can't get dsi_clk_src. ret=%d\n",
+ __func__, ret);
+ }
+ }
exit:
return ret;
}
static int dsi_bus_clk_enable(struct msm_dsi_host *msm_host)
{
- int ret;
+ const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg;
+ int i, ret;
DBG("id=%d", msm_host->id);
- ret = clk_prepare_enable(msm_host->mdp_core_clk);
- if (ret) {
- pr_err("%s: failed to enable mdp_core_clock, %d\n",
- __func__, ret);
- goto core_clk_err;
- }
-
- ret = clk_prepare_enable(msm_host->ahb_clk);
- if (ret) {
- pr_err("%s: failed to enable ahb clock, %d\n", __func__, ret);
- goto ahb_clk_err;
- }
-
- ret = clk_prepare_enable(msm_host->axi_clk);
- if (ret) {
- pr_err("%s: failed to enable ahb clock, %d\n", __func__, ret);
- goto axi_clk_err;
- }
-
- ret = clk_prepare_enable(msm_host->mmss_misc_ahb_clk);
- if (ret) {
- pr_err("%s: failed to enable mmss misc ahb clk, %d\n",
- __func__, ret);
- goto misc_ahb_clk_err;
+ for (i = 0; i < cfg->num_bus_clks; i++) {
+ ret = clk_prepare_enable(msm_host->bus_clks[i]);
+ if (ret) {
+ pr_err("%s: failed to enable bus clock %d ret %d\n",
+ __func__, i, ret);
+ goto err;
+ }
}
return 0;
+err:
+ for (; i > 0; i--)
+ clk_disable_unprepare(msm_host->bus_clks[i]);
-misc_ahb_clk_err:
- clk_disable_unprepare(msm_host->axi_clk);
-axi_clk_err:
- clk_disable_unprepare(msm_host->ahb_clk);
-ahb_clk_err:
- clk_disable_unprepare(msm_host->mdp_core_clk);
-core_clk_err:
return ret;
}
static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host)
{
+ const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg;
+ int i;
+
DBG("");
- clk_disable_unprepare(msm_host->mmss_misc_ahb_clk);
- clk_disable_unprepare(msm_host->axi_clk);
- clk_disable_unprepare(msm_host->ahb_clk);
- clk_disable_unprepare(msm_host->mdp_core_clk);
+
+ for (i = cfg->num_bus_clks - 1; i >= 0; i--)
+ clk_disable_unprepare(msm_host->bus_clks[i]);
}
-static int dsi_link_clk_enable(struct msm_dsi_host *msm_host)
+static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host)
{
int ret;
@@ -476,11 +508,98 @@ error:
return ret;
}
-static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
+static int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
{
+ int ret;
+
+ DBG("Set clk rates: pclk=%d, byteclk=%d, esc_clk=%d, dsi_src_clk=%d",
+ msm_host->mode->clock, msm_host->byte_clk_rate,
+ msm_host->esc_clk_rate, msm_host->src_clk_rate);
+
+ ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate);
+ if (ret) {
+ pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret);
+ goto error;
+ }
+
+ ret = clk_set_rate(msm_host->esc_clk, msm_host->esc_clk_rate);
+ if (ret) {
+ pr_err("%s: Failed to set rate esc clk, %d\n", __func__, ret);
+ goto error;
+ }
+
+ ret = clk_set_rate(msm_host->src_clk, msm_host->src_clk_rate);
+ if (ret) {
+ pr_err("%s: Failed to set rate src clk, %d\n", __func__, ret);
+ goto error;
+ }
+
+ ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000);
+ if (ret) {
+ pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret);
+ goto error;
+ }
+
+ ret = clk_prepare_enable(msm_host->byte_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable dsi byte clk\n", __func__);
+ goto error;
+ }
+
+ ret = clk_prepare_enable(msm_host->esc_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable dsi esc clk\n", __func__);
+ goto esc_clk_err;
+ }
+
+ ret = clk_prepare_enable(msm_host->src_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable dsi src clk\n", __func__);
+ goto src_clk_err;
+ }
+
+ ret = clk_prepare_enable(msm_host->pixel_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
+ goto pixel_clk_err;
+ }
+
+ return 0;
+
+pixel_clk_err:
+ clk_disable_unprepare(msm_host->src_clk);
+src_clk_err:
clk_disable_unprepare(msm_host->esc_clk);
- clk_disable_unprepare(msm_host->pixel_clk);
+esc_clk_err:
clk_disable_unprepare(msm_host->byte_clk);
+error:
+ return ret;
+}
+
+static int dsi_link_clk_enable(struct msm_dsi_host *msm_host)
+{
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G)
+ return dsi_link_clk_enable_6g(msm_host);
+ else
+ return dsi_link_clk_enable_v2(msm_host);
+}
+
+static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
+{
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) {
+ clk_disable_unprepare(msm_host->esc_clk);
+ clk_disable_unprepare(msm_host->pixel_clk);
+ clk_disable_unprepare(msm_host->byte_clk);
+ } else {
+ clk_disable_unprepare(msm_host->pixel_clk);
+ clk_disable_unprepare(msm_host->src_clk);
+ clk_disable_unprepare(msm_host->esc_clk);
+ clk_disable_unprepare(msm_host->byte_clk);
+ }
}
static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable)
@@ -515,6 +634,7 @@ unlock_ret:
static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
{
struct drm_display_mode *mode = msm_host->mode;
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
u8 lanes = msm_host->lanes;
u32 bpp = dsi_get_bpp(msm_host->format);
u32 pclk_rate;
@@ -534,6 +654,47 @@ static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate);
+ msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk);
+
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
+ unsigned int esc_mhz, esc_div;
+ unsigned long byte_mhz;
+
+ msm_host->src_clk_rate = (pclk_rate * bpp) / 8;
+
+ /*
+ * esc clock is byte clock followed by a 4 bit divider,
+ * we need to find an escape clock frequency within the
+ * mipi DSI spec range within the maximum divider limit
+ * We iterate here between an escape clock frequencey
+ * between 20 Mhz to 5 Mhz and pick up the first one
+ * that can be supported by our divider
+ */
+
+ byte_mhz = msm_host->byte_clk_rate / 1000000;
+
+ for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) {
+ esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz);
+
+ /*
+ * TODO: Ideally, we shouldn't know what sort of divider
+ * is available in mmss_cc, we're just assuming that
+ * it'll always be a 4 bit divider. Need to come up with
+ * a better way here.
+ */
+ if (esc_div >= 1 && esc_div <= 16)
+ break;
+ }
+
+ if (esc_mhz < 5)
+ return -EINVAL;
+
+ msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div;
+
+ DBG("esc=%d, src=%d", msm_host->esc_clk_rate,
+ msm_host->src_clk_rate);
+ }
+
return 0;
}
@@ -835,29 +996,46 @@ static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host)
static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size)
{
struct drm_device *dev = msm_host->dev;
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
int ret;
u32 iova;
- mutex_lock(&dev->struct_mutex);
- msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED);
- if (IS_ERR(msm_host->tx_gem_obj)) {
- ret = PTR_ERR(msm_host->tx_gem_obj);
- pr_err("%s: failed to allocate gem, %d\n", __func__, ret);
- msm_host->tx_gem_obj = NULL;
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) {
+ mutex_lock(&dev->struct_mutex);
+ msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED);
+ if (IS_ERR(msm_host->tx_gem_obj)) {
+ ret = PTR_ERR(msm_host->tx_gem_obj);
+ pr_err("%s: failed to allocate gem, %d\n",
+ __func__, ret);
+ msm_host->tx_gem_obj = NULL;
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 0, &iova);
mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ if (ret) {
+ pr_err("%s: failed to get iova, %d\n", __func__, ret);
+ return ret;
+ }
- ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 0, &iova);
- if (ret) {
- pr_err("%s: failed to get iova, %d\n", __func__, ret);
- return ret;
- }
- mutex_unlock(&dev->struct_mutex);
+ if (iova & 0x07) {
+ pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
+ return -EINVAL;
+ }
- if (iova & 0x07) {
- pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
- return -EINVAL;
+ msm_host->tx_size = msm_host->tx_gem_obj->size;
+ } else {
+ msm_host->tx_buf = dma_alloc_coherent(dev->dev, size,
+ &msm_host->tx_buf_paddr, GFP_KERNEL);
+ if (!msm_host->tx_buf) {
+ ret = -ENOMEM;
+ pr_err("%s: failed to allocate tx buf, %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ msm_host->tx_size = size;
}
return 0;
@@ -874,14 +1052,19 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
msm_host->tx_gem_obj = NULL;
mutex_unlock(&dev->struct_mutex);
}
+
+ if (msm_host->tx_buf)
+ dma_free_coherent(dev->dev, msm_host->tx_size, msm_host->tx_buf,
+ msm_host->tx_buf_paddr);
}
/*
* prepare cmd buffer to be txed
*/
-static int dsi_cmd_dma_add(struct drm_gem_object *tx_gem,
- const struct mipi_dsi_msg *msg)
+static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host,
+ const struct mipi_dsi_msg *msg)
{
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
struct mipi_dsi_packet packet;
int len;
int ret;
@@ -894,17 +1077,20 @@ static int dsi_cmd_dma_add(struct drm_gem_object *tx_gem,
}
len = (packet.size + 3) & (~0x3);
- if (len > tx_gem->size) {
+ if (len > msm_host->tx_size) {
pr_err("%s: packet size is too big\n", __func__);
return -EINVAL;
}
- data = msm_gem_vaddr(tx_gem);
-
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- pr_err("%s: get vaddr failed, %d\n", __func__, ret);
- return ret;
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) {
+ data = msm_gem_vaddr(msm_host->tx_gem_obj);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ pr_err("%s: get vaddr failed, %d\n", __func__, ret);
+ return ret;
+ }
+ } else {
+ data = msm_host->tx_buf;
}
/* MSM specific command format in memory */
@@ -970,17 +1156,21 @@ static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg)
return msg->rx_len;
}
-
static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len)
{
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
int ret;
- u32 iova;
+ u32 dma_base;
bool triggered;
- ret = msm_gem_get_iova(msm_host->tx_gem_obj, 0, &iova);
- if (ret) {
- pr_err("%s: failed to get iova: %d\n", __func__, ret);
- return ret;
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) {
+ ret = msm_gem_get_iova(msm_host->tx_gem_obj, 0, &dma_base);
+ if (ret) {
+ pr_err("%s: failed to get iova: %d\n", __func__, ret);
+ return ret;
+ }
+ } else {
+ dma_base = msm_host->tx_buf_paddr;
}
reinit_completion(&msm_host->dma_comp);
@@ -988,7 +1178,7 @@ static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len)
dsi_wait4video_eng_busy(msm_host);
triggered = msm_dsi_manager_cmd_xfer_trigger(
- msm_host->id, iova, len);
+ msm_host->id, dma_base, len);
if (triggered) {
ret = wait_for_completion_timeout(&msm_host->dma_comp,
msecs_to_jiffies(200));
@@ -1060,7 +1250,7 @@ static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host,
int bllp_len = msm_host->mode->hdisplay *
dsi_get_bpp(msm_host->format) / 8;
- len = dsi_cmd_dma_add(msm_host->tx_gem_obj, msg);
+ len = dsi_cmd_dma_add(msm_host, msg);
if (!len) {
pr_err("%s: failed to add cmd type = 0x%x\n",
__func__, msg->type);
@@ -1383,6 +1573,16 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
msm_host->device_node = device_node;
+ if (of_property_read_bool(np, "syscon-sfpb")) {
+ 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",
+ __func__);
+ return PTR_ERR(msm_host->sfpb);
+ }
+ }
+
return 0;
}
@@ -1408,12 +1608,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
goto fail;
}
- ret = dsi_clk_init(msm_host);
- if (ret) {
- pr_err("%s: unable to initialize dsi clks\n", __func__);
- goto fail;
- }
-
msm_host->ctrl_base = msm_ioremap(pdev, "dsi_ctrl", "DSI CTRL");
if (IS_ERR(msm_host->ctrl_base)) {
pr_err("%s: unable to map Dsi ctrl base\n", __func__);
@@ -1437,6 +1631,12 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
goto fail;
}
+ ret = dsi_clk_init(msm_host);
+ if (ret) {
+ pr_err("%s: unable to initialize dsi clks\n", __func__);
+ goto fail;
+ }
+
msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL);
if (!msm_host->rx_buf) {
pr_err("%s: alloc rx temp buf failed\n", __func__);
@@ -1750,11 +1950,12 @@ int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
return ret;
}
-void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 iova, u32 len)
+void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 dma_base,
+ u32 len)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
- dsi_write(msm_host, REG_DSI_DMA_BASE, iova);
+ dsi_write(msm_host, REG_DSI_DMA_BASE, dma_base);
dsi_write(msm_host, REG_DSI_DMA_LEN, len);
dsi_write(msm_host, REG_DSI_TRIG_DMA, 1);
@@ -1766,6 +1967,7 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
struct msm_dsi_pll *src_pll)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
struct clk *byte_clk_provider, *pixel_clk_provider;
int ret;
@@ -1791,6 +1993,22 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
goto exit;
}
+ if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
+ ret = clk_set_parent(msm_host->dsi_clk_src, pixel_clk_provider);
+ if (ret) {
+ pr_err("%s: can't set parent to dsi_clk_src. ret=%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ ret = clk_set_parent(msm_host->esc_clk_src, byte_clk_provider);
+ if (ret) {
+ pr_err("%s: can't set parent to esc_clk_src. ret=%d\n",
+ __func__, ret);
+ goto exit;
+ }
+ }
+
exit:
return ret;
}
@@ -1828,6 +2046,20 @@ int msm_dsi_host_disable(struct mipi_dsi_host *host)
return 0;
}
+static void msm_dsi_sfpb_config(struct msm_dsi_host *msm_host, bool enable)
+{
+ enum sfpb_ahb_arb_master_port_en en;
+
+ if (!msm_host->sfpb)
+ return;
+
+ en = enable ? SFPB_MASTER_PORT_ENABLE : SFPB_MASTER_PORT_DISABLE;
+
+ regmap_update_bits(msm_host->sfpb, REG_SFPB_GPREG,
+ SFPB_GPREG_MASTER_PORT_EN__MASK,
+ SFPB_GPREG_MASTER_PORT_EN(en));
+}
+
int msm_dsi_host_power_on(struct mipi_dsi_host *host)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
@@ -1840,6 +2072,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
goto unlock_ret;
}
+ msm_dsi_sfpb_config(msm_host, true);
+
ret = dsi_calc_clk_rate(msm_host);
if (ret) {
pr_err("%s: unable to calc clk rate, %d\n", __func__, ret);
@@ -1862,7 +2096,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)
dsi_phy_sw_reset(msm_host);
ret = msm_dsi_manager_phy_enable(msm_host->id,
msm_host->byte_clk_rate * 8,
- clk_get_rate(msm_host->esc_clk),
+ msm_host->esc_clk_rate,
&clk_pre, &clk_post);
dsi_bus_clk_disable(msm_host);
if (ret) {
@@ -1927,6 +2161,8 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host)
dsi_host_regulator_disable(msm_host);
+ msm_dsi_sfpb_config(msm_host, false);
+
DBG("-");
msm_host->power_on = false;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 0455ff75074a..58ba7ec17f51 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -774,7 +774,7 @@ restore_host0:
return ret;
}
-bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
+bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
@@ -784,9 +784,9 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
return false;
if (IS_SYNC_NEEDED() && msm_dsi0)
- msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len);
+ msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, dma_base, len);
- msm_dsi_host_cmd_xfer_commit(host, iova, len);
+ msm_dsi_host_cmd_xfer_commit(host, dma_base, len);
return true;
}
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index f1f955f571fa..91a95fb04a4a 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -277,6 +277,10 @@ static const struct of_device_id dsi_phy_dt_match[] = {
{ .compatible = "qcom,dsi-phy-20nm",
.data = &dsi_phy_20nm_cfgs },
#endif
+#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
+ { .compatible = "qcom,dsi-phy-28nm-8960",
+ .data = &dsi_phy_28nm_8960_cfgs },
+#endif
{}
};
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index 0456b253239f..0d54ed00386d 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -43,6 +43,7 @@ struct msm_dsi_phy_cfg {
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs;
struct msm_dsi_dphy_timing {
u32 clk_pre;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
new file mode 100644
index 000000000000..197b039ca1f1
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "dsi_phy.h"
+#include "dsi.xml.h"
+
+static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
+ struct msm_dsi_dphy_timing *timing)
+{
+ void __iomem *base = phy->base;
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_0,
+ DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_1,
+ DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_2,
+ DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_3, 0x0);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_4,
+ DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_5,
+ DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_6,
+ DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_7,
+ DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_8,
+ DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_9,
+ DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
+ DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_10,
+ DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_11,
+ DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
+}
+
+static void dsi_28nm_phy_regulator_init(struct msm_dsi_phy *phy)
+{
+ void __iomem *base = phy->reg_base;
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 1);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 1);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4,
+ 0x100);
+}
+
+static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy)
+{
+ void __iomem *base = phy->reg_base;
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 0xa);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 0x4);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0x0);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, 0x20);
+}
+
+static void dsi_28nm_phy_calibration(struct msm_dsi_phy *phy)
+{
+ void __iomem *base = phy->reg_base;
+ u32 status;
+ int i = 5000;
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CAL_PWR_CFG,
+ 0x3);
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_2, 0x0);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_1, 0x5a);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_3, 0x10);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_4, 0x1);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_0, 0x1);
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x1);
+ usleep_range(5000, 6000);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x0);
+
+ do {
+ status = dsi_phy_read(base +
+ REG_DSI_28nm_8960_PHY_MISC_CAL_STATUS);
+
+ if (!(status & DSI_28nm_8960_PHY_MISC_CAL_STATUS_CAL_BUSY))
+ break;
+
+ udelay(1);
+ } while (--i > 0);
+}
+
+static void dsi_28nm_phy_lane_config(struct msm_dsi_phy *phy)
+{
+ void __iomem *base = phy->base;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_0(i), 0x80);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_1(i), 0x45);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_2(i), 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_DATAPATH(i),
+ 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_0(i),
+ 0x01);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_1(i),
+ 0x66);
+ }
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_0, 0x40);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_1, 0x67);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_2, 0x0);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_DATAPATH, 0x0);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR0, 0x1);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR1, 0x88);
+}
+
+static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+ const unsigned long bit_rate, const unsigned long esc_rate)
+{
+ struct msm_dsi_dphy_timing *timing = &phy->timing;
+ void __iomem *base = phy->base;
+
+ DBG("");
+
+ if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
+ dev_err(&phy->pdev->dev,
+ "%s: D-PHY timing calculation failed\n", __func__);
+ return -EINVAL;
+ }
+
+ dsi_28nm_phy_regulator_init(phy);
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LDO_CTRL, 0x04);
+
+ /* strength control */
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_0, 0xff);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_1, 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_2, 0x06);
+
+ /* phy ctrl */
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x5f);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_1, 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_2, 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_3, 0x10);
+
+ dsi_28nm_phy_regulator_ctrl(phy);
+
+ dsi_28nm_phy_calibration(phy);
+
+ dsi_28nm_phy_lane_config(phy);
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0f);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_1, 0x03);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_0, 0x03);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0);
+
+ dsi_28nm_dphy_set_timing(phy, timing);
+
+ return 0;
+}
+
+static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
+{
+ dsi_phy_write(phy->base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x0);
+
+ /*
+ * Wait for the registers writes to complete in order to
+ * ensure that the phy is completely disabled
+ */
+ wmb();
+}
+
+const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = {
+ .type = MSM_DSI_PHY_28NM_8960,
+ .src_pll_truthtable = { {true, true}, {false, true} },
+ .reg_cfg = {
+ .num = 1,
+ .regs = {
+ {"vddio", 1800000, 1800000, 100000, 100},
+ },
+ },
+ .ops = {
+ .enable = dsi_28nm_phy_enable,
+ .disable = dsi_28nm_phy_disable,
+ },
+};
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
index 5104fc9f9a53..5cd438f91afe 100644
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
@@ -151,6 +151,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
case MSM_DSI_PHY_28NM_LP:
pll = msm_dsi_pll_28nm_init(pdev, type, id);
break;
+ case MSM_DSI_PHY_28NM_8960:
+ pll = msm_dsi_pll_28nm_8960_init(pdev, id);
+ break;
default:
pll = ERR_PTR(-ENXIO);
break;
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
index 063caa2c5740..80b6038334a6 100644
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
@@ -93,6 +93,16 @@ static inline struct msm_dsi_pll *msm_dsi_pll_28nm_init(
return ERR_PTR(-ENODEV);
}
#endif
+#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
+struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
+ int id);
+#else
+struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
+ int id)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
#endif /* __DSI_PLL_H__ */
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c
new file mode 100644
index 000000000000..38c90e1eb002
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "dsi_pll.h"
+#include "dsi.xml.h"
+
+/*
+ * DSI PLL 28nm (8960/A family) - clock diagram (eg: DSI1):
+ *
+ *
+ * +------+
+ * dsi1vco_clk ----o-----| DIV1 |---dsi1pllbit (not exposed as clock)
+ * F * byte_clk | +------+
+ * | bit clock divider (F / 8)
+ * |
+ * | +------+
+ * o-----| DIV2 |---dsi0pllbyte---o---> To byte RCG
+ * | +------+ | (sets parent rate)
+ * | byte clock divider (F) |
+ * | |
+ * | o---> To esc RCG
+ * | (doesn't set parent rate)
+ * |
+ * | +------+
+ * o-----| DIV3 |----dsi0pll------o---> To dsi RCG
+ * +------+ | (sets parent rate)
+ * dsi clock divider (F * magic) |
+ * |
+ * o---> To pixel rcg
+ * (doesn't set parent rate)
+ */
+
+#define POLL_MAX_READS 8000
+#define POLL_TIMEOUT_US 1
+
+#define NUM_PROVIDED_CLKS 2
+
+#define VCO_REF_CLK_RATE 27000000
+#define VCO_MIN_RATE 600000000
+#define VCO_MAX_RATE 1200000000
+
+#define DSI_BYTE_PLL_CLK 0
+#define DSI_PIXEL_PLL_CLK 1
+
+#define VCO_PREF_DIV_RATIO 27
+
+struct pll_28nm_cached_state {
+ unsigned long vco_rate;
+ u8 postdiv3;
+ u8 postdiv2;
+ u8 postdiv1;
+};
+
+struct clk_bytediv {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+struct dsi_pll_28nm {
+ struct msm_dsi_pll base;
+
+ int id;
+ struct platform_device *pdev;
+ void __iomem *mmio;
+
+ /* custom byte clock divider */
+ struct clk_bytediv *bytediv;
+
+ /* private clocks: */
+ struct clk *clks[NUM_DSI_CLOCKS_MAX];
+ u32 num_clks;
+
+ /* clock-provider: */
+ struct clk *provided_clks[NUM_PROVIDED_CLKS];
+ struct clk_onecell_data clk_data;
+
+ struct pll_28nm_cached_state cached_state;
+};
+
+#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base)
+
+static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
+ int nb_tries, int timeout_us)
+{
+ bool pll_locked = false;
+ u32 val;
+
+ while (nb_tries--) {
+ val = pll_read(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_RDY);
+ pll_locked = !!(val & DSI_28nm_8960_PHY_PLL_RDY_PLL_RDY);
+
+ if (pll_locked)
+ break;
+
+ udelay(timeout_us);
+ }
+ DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
+
+ return pll_locked;
+}
+
+/*
+ * Clock Callbacks
+ */
+static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+ void __iomem *base = pll_28nm->mmio;
+ u32 val, temp, fb_divider;
+
+ DBG("rate=%lu, parent's=%lu", rate, parent_rate);
+
+ temp = rate / 10;
+ val = VCO_REF_CLK_RATE / 10;
+ fb_divider = (temp * VCO_PREF_DIV_RATIO) / val;
+ fb_divider = fb_divider / 2 - 1;
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1,
+ fb_divider & 0xff);
+
+ val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2);
+
+ val |= (fb_divider >> 8) & 0x07;
+
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2,
+ val);
+
+ val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3);
+
+ val |= (VCO_PREF_DIV_RATIO - 1) & 0x3f;
+
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3,
+ val);
+
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_6,
+ 0xf);
+
+ val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
+ val |= 0x7 << 4;
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8,
+ val);
+
+ return 0;
+}
+
+static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
+{
+ struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+
+ return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
+ POLL_TIMEOUT_US);
+}
+
+static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+ void __iomem *base = pll_28nm->mmio;
+ unsigned long vco_rate;
+ u32 status, fb_divider, temp, ref_divider;
+
+ VERB("parent_rate=%lu", parent_rate);
+
+ status = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0);
+
+ if (status & DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE) {
+ fb_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1);
+ fb_divider &= 0xff;
+ temp = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2) & 0x07;
+ fb_divider = (temp << 8) | fb_divider;
+ fb_divider += 1;
+
+ ref_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3);
+ ref_divider &= 0x3f;
+ ref_divider += 1;
+
+ /* multiply by 2 */
+ vco_rate = (parent_rate / ref_divider) * fb_divider * 2;
+ } else {
+ vco_rate = 0;
+ }
+
+ DBG("returning vco rate = %lu", vco_rate);
+
+ return vco_rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_28nm_vco = {
+ .round_rate = msm_dsi_pll_helper_clk_round_rate,
+ .set_rate = dsi_pll_28nm_clk_set_rate,
+ .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
+ .prepare = msm_dsi_pll_helper_clk_prepare,
+ .unprepare = msm_dsi_pll_helper_clk_unprepare,
+ .is_enabled = dsi_pll_28nm_clk_is_enabled,
+};
+
+/*
+ * Custom byte clock divier clk_ops
+ *
+ * This clock is the entry point to configuring the PLL. The user (dsi host)
+ * will set this clock's rate to the desired byte clock rate. The VCO lock
+ * frequency is a multiple of the byte clock rate. The multiplication factor
+ * (shown as F in the diagram above) is a function of the byte clock rate.
+ *
+ * This custom divider clock ensures that its parent (VCO) is set to the
+ * desired rate, and that the byte clock postdivider (POSTDIV2) is configured
+ * accordingly
+ */
+#define to_clk_bytediv(_hw) container_of(_hw, struct clk_bytediv, hw)
+
+static unsigned long clk_bytediv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_bytediv *bytediv = to_clk_bytediv(hw);
+ unsigned int div;
+
+ div = pll_read(bytediv->reg) & 0xff;
+
+ return parent_rate / (div + 1);
+}
+
+/* find multiplication factor(wrt byte clock) at which the VCO should be set */
+static unsigned int get_vco_mul_factor(unsigned long byte_clk_rate)
+{
+ unsigned long bit_mhz;
+
+ /* convert to bit clock in Mhz */
+ bit_mhz = (byte_clk_rate * 8) / 1000000;
+
+ if (bit_mhz < 125)
+ return 64;
+ else if (bit_mhz < 250)
+ return 32;
+ else if (bit_mhz < 600)
+ return 16;
+ else
+ return 8;
+}
+
+static long clk_bytediv_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long best_parent;
+ unsigned int factor;
+
+ factor = get_vco_mul_factor(rate);
+
+ best_parent = rate * factor;
+ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
+
+ return *prate / factor;
+}
+
+static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_bytediv *bytediv = to_clk_bytediv(hw);
+ u32 val;
+ unsigned int factor;
+
+ factor = get_vco_mul_factor(rate);
+
+ val = pll_read(bytediv->reg);
+ val |= (factor - 1) & 0xff;
+ pll_write(bytediv->reg, val);
+
+ return 0;
+}
+
+/* Our special byte clock divider ops */
+static const struct clk_ops clk_bytediv_ops = {
+ .round_rate = clk_bytediv_round_rate,
+ .set_rate = clk_bytediv_set_rate,
+ .recalc_rate = clk_bytediv_recalc_rate,
+};
+
+/*
+ * PLL Callbacks
+ */
+static int dsi_pll_28nm_enable_seq(struct msm_dsi_pll *pll)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+ struct device *dev = &pll_28nm->pdev->dev;
+ void __iomem *base = pll_28nm->mmio;
+ bool locked;
+ unsigned int bit_div, byte_div;
+ int max_reads = 1000, timeout_us = 100;
+ u32 val;
+
+ DBG("id=%d", pll_28nm->id);
+
+ /*
+ * before enabling the PLL, configure the bit clock divider since we
+ * don't expose it as a clock to the outside world
+ * 1: read back the byte clock divider that should already be set
+ * 2: divide by 8 to get bit clock divider
+ * 3: write it to POSTDIV1
+ */
+ val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9);
+ byte_div = val + 1;
+ bit_div = byte_div / 8;
+
+ val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
+ val &= ~0xf;
+ val |= (bit_div - 1);
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, val);
+
+ /* enable the PLL */
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0,
+ DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE);
+
+ locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
+
+ if (unlikely(!locked))
+ dev_err(dev, "DSI PLL lock failed\n");
+ else
+ DBG("DSI PLL lock success");
+
+ return locked ? 0 : -EINVAL;
+}
+
+static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+
+ DBG("id=%d", pll_28nm->id);
+ pll_write(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, 0x00);
+}
+
+static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+ struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
+ void __iomem *base = pll_28nm->mmio;
+
+ cached_state->postdiv3 =
+ pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10);
+ cached_state->postdiv2 =
+ pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9);
+ cached_state->postdiv1 =
+ pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
+
+ cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw);
+}
+
+static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+ struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
+ void __iomem *base = pll_28nm->mmio;
+ int ret;
+
+ ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
+ cached_state->vco_rate, 0);
+ if (ret) {
+ dev_err(&pll_28nm->pdev->dev,
+ "restore vco rate failed. ret=%d\n", ret);
+ return ret;
+ }
+
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10,
+ cached_state->postdiv3);
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9,
+ cached_state->postdiv2);
+ pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8,
+ cached_state->postdiv1);
+
+ return 0;
+}
+
+static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll,
+ struct clk **byte_clk_provider,
+ struct clk **pixel_clk_provider)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+
+ if (byte_clk_provider)
+ *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK];
+ if (pixel_clk_provider)
+ *pixel_clk_provider =
+ pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK];
+
+ return 0;
+}
+
+static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
+
+ msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev,
+ pll_28nm->clks, pll_28nm->num_clks);
+}
+
+static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
+{
+ char *clk_name, *parent_name, *vco_name;
+ struct clk_init_data vco_init = {
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_ops_dsi_pll_28nm_vco,
+ };
+ struct device *dev = &pll_28nm->pdev->dev;
+ struct clk **clks = pll_28nm->clks;
+ struct clk **provided_clks = pll_28nm->provided_clks;
+ struct clk_bytediv *bytediv;
+ struct clk_init_data bytediv_init = { };
+ int ret, num = 0;
+
+ DBG("%d", pll_28nm->id);
+
+ bytediv = devm_kzalloc(dev, sizeof(*bytediv), GFP_KERNEL);
+ if (!bytediv)
+ return -ENOMEM;
+
+ vco_name = devm_kzalloc(dev, 32, GFP_KERNEL);
+ if (!vco_name)
+ return -ENOMEM;
+
+ parent_name = devm_kzalloc(dev, 32, GFP_KERNEL);
+ if (!parent_name)
+ return -ENOMEM;
+
+ clk_name = devm_kzalloc(dev, 32, GFP_KERNEL);
+ if (!clk_name)
+ return -ENOMEM;
+
+ pll_28nm->bytediv = bytediv;
+
+ snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id);
+ vco_init.name = vco_name;
+
+ pll_28nm->base.clk_hw.init = &vco_init;
+
+ clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw);
+
+ /* prepare and register bytediv */
+ bytediv->hw.init = &bytediv_init;
+ bytediv->reg = pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_9;
+
+ snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->id);
+ snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id);
+
+ bytediv_init.name = clk_name;
+ bytediv_init.ops = &clk_bytediv_ops;
+ bytediv_init.flags = CLK_SET_RATE_PARENT;
+ bytediv_init.parent_names = (const char * const *) &parent_name;
+ bytediv_init.num_parents = 1;
+
+ /* DIV2 */
+ clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] =
+ clk_register(dev, &bytediv->hw);
+
+ snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id);
+ /* DIV3 */
+ clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] =
+ clk_register_divider(dev, clk_name,
+ parent_name, 0, pll_28nm->mmio +
+ REG_DSI_28nm_8960_PHY_PLL_CTRL_10,
+ 0, 8, 0, NULL);
+
+ pll_28nm->num_clks = num;
+
+ pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS;
+ pll_28nm->clk_data.clks = provided_clks;
+
+ 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);
+ return ret;
+ }
+
+ return 0;
+}
+
+struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
+ int id)
+{
+ struct dsi_pll_28nm *pll_28nm;
+ struct msm_dsi_pll *pll;
+ int ret;
+
+ if (!pdev)
+ return ERR_PTR(-ENODEV);
+
+ pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
+ if (!pll_28nm)
+ return ERR_PTR(-ENOMEM);
+
+ pll_28nm->pdev = pdev;
+ pll_28nm->id = id + 1;
+
+ 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__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pll = &pll_28nm->base;
+ pll->min_rate = VCO_MIN_RATE;
+ pll->max_rate = VCO_MAX_RATE;
+ pll->get_provider = dsi_pll_28nm_get_provider;
+ pll->destroy = dsi_pll_28nm_destroy;
+ pll->disable_seq = dsi_pll_28nm_disable_seq;
+ pll->save_state = dsi_pll_28nm_save_state;
+ pll->restore_state = dsi_pll_28nm_restore_state;
+
+ pll->en_seq_cnt = 1;
+ pll->enable_seqs[0] = dsi_pll_28nm_enable_seq;
+
+ ret = pll_28nm_register(pll_28nm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return pll;
+}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 1f4a95eeb348..9a0989c0b4de 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -17,6 +17,8 @@
*/
#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+
#include "hdmi.h"
void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
@@ -322,8 +324,6 @@ fail:
* The hdmi device:
*/
-#include <linux/of_gpio.h>
-
#define HDMI_CFG(item, entry) \
.item ## _names = item ##_names_ ## entry, \
.item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)
@@ -388,17 +388,6 @@ static struct hdmi_platform_config hdmi_tx_8996_config = {
.hpd_freq = hpd_clk_freq_8x74,
};
-static const struct of_device_id dt_match[] = {
- { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config },
- { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
- { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
- { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
- { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
- { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
- {}
-};
-
-#ifdef CONFIG_OF
static int get_gpio(struct device *dev, struct device_node *of_node, const char *name)
{
int gpio = of_get_named_gpio(of_node, name, 0);
@@ -413,7 +402,6 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
}
return gpio;
}
-#endif
static int hdmi_bind(struct device *dev, struct device *master, void *data)
{
@@ -421,16 +409,12 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
struct msm_drm_private *priv = drm->dev_private;
static struct hdmi_platform_config *hdmi_cfg;
struct hdmi *hdmi;
-#ifdef CONFIG_OF
struct device_node *of_node = dev->of_node;
- const struct of_device_id *match;
- match = of_match_node(dt_match, of_node);
- if (match && match->data) {
- hdmi_cfg = (struct hdmi_platform_config *)match->data;
- DBG("hdmi phy: %s", match->compatible);
- } else {
- dev_err(dev, "unknown phy: %s\n", of_node->name);
+ 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);
return -ENXIO;
}
@@ -443,55 +427,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi_cfg->mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
hdmi_cfg->mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
-#else
- static struct hdmi_platform_config config = {};
- static const char *hpd_clk_names[] = {
- "core_clk", "master_iface_clk", "slave_iface_clk",
- };
- if (cpu_is_apq8064()) {
- static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
- config.phy_init = hdmi_phy_8960_init;
- config.hpd_reg_names = hpd_reg_names;
- config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
- config.hpd_clk_names = hpd_clk_names;
- config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
- config.ddc_clk_gpio = 70;
- config.ddc_data_gpio = 71;
- config.hpd_gpio = 72;
- config.mux_en_gpio = -1;
- config.mux_sel_gpio = -1;
- } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
- static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
- config.phy_init = hdmi_phy_8960_init;
- config.hpd_reg_names = hpd_reg_names;
- config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
- config.hpd_clk_names = hpd_clk_names;
- config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
- config.ddc_clk_gpio = 100;
- config.ddc_data_gpio = 101;
- config.hpd_gpio = 102;
- config.mux_en_gpio = -1;
- config.mux_sel_gpio = -1;
- } else if (cpu_is_msm8x60()) {
- static const char *hpd_reg_names[] = {
- "8901_hdmi_mvs", "8901_mpp0"
- };
- config.phy_init = hdmi_phy_8x60_init;
- config.hpd_reg_names = hpd_reg_names;
- config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
- config.hpd_clk_names = hpd_clk_names;
- config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
- config.ddc_clk_gpio = 170;
- config.ddc_data_gpio = 171;
- config.hpd_gpio = 172;
- config.mux_en_gpio = -1;
- config.mux_sel_gpio = -1;
- }
- config.mmio_name = "hdmi_msm_hdmi_addr";
- config.qfprom_mmio_name = "hdmi_msm_qfprom_addr";
-
- hdmi_cfg = &config;
-#endif
dev->platform_data = hdmi_cfg;
hdmi = hdmi_init(to_platform_device(dev));
@@ -529,6 +464,16 @@ static int hdmi_dev_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id dt_match[] = {
+ { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config },
+ { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
+ { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
+ { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
+ { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
+ { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
+ {}
+};
+
static struct platform_driver hdmi_driver = {
.probe = hdmi_dev_probe,
.remove = hdmi_dev_remove,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 6ac9aa165768..28df397c3b04 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -678,7 +678,8 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
drm_flip_work_init(&mdp4_crtc->unref_cursor_work,
"unref cursor", unref_cursor_worker);
- drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs);
+ drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs,
+ NULL);
drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
plane->crtc = crtc;
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c
new file mode 100644
index 000000000000..2f57e9453b67
--- /dev/null
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, Inforce Computing. All rights reserved.
+ *
+ * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mdp4_kms.h"
+
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+struct mdp4_dsi_encoder {
+ struct drm_encoder base;
+ struct drm_panel *panel;
+ bool enabled;
+};
+#define to_mdp4_dsi_encoder(x) container_of(x, struct mdp4_dsi_encoder, base)
+
+static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
+{
+ struct msm_drm_private *priv = encoder->dev->dev_private;
+ return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
+
+ drm_encoder_cleanup(encoder);
+ kfree(mdp4_dsi_encoder);
+}
+
+static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
+ .destroy = mdp4_dsi_encoder_destroy,
+};
+
+static bool mdp4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+ uint32_t dsi_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+ uint32_t display_v_start, display_v_end;
+ uint32_t hsync_start_x, hsync_end_x;
+
+ mode = adjusted_mode;
+
+ DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+ mode->base.id, mode->name,
+ mode->vrefresh, mode->clock,
+ mode->hdisplay, mode->hsync_start,
+ mode->hsync_end, mode->htotal,
+ mode->vdisplay, mode->vsync_start,
+ mode->vsync_end, mode->vtotal,
+ mode->type, mode->flags);
+
+ ctrl_pol = 0;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ ctrl_pol |= MDP4_DSI_CTRL_POLARITY_HSYNC_LOW;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ ctrl_pol |= MDP4_DSI_CTRL_POLARITY_VSYNC_LOW;
+ /* probably need to get DATA_EN polarity from panel.. */
+
+ dsi_hsync_skew = 0; /* get this from panel? */
+
+ hsync_start_x = (mode->htotal - mode->hsync_start);
+ hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
+
+ vsync_period = mode->vtotal * mode->htotal;
+ vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
+ display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dsi_hsync_skew;
+ display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dsi_hsync_skew - 1;
+
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_CTRL,
+ MDP4_DSI_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
+ MDP4_DSI_HSYNC_CTRL_PERIOD(mode->htotal));
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_PERIOD, vsync_period);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_LEN, vsync_len);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_HCTRL,
+ MDP4_DSI_DISPLAY_HCTRL_START(hsync_start_x) |
+ MDP4_DSI_DISPLAY_HCTRL_END(hsync_end_x));
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VSTART, display_v_start);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VEND, display_v_end);
+
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_CTRL_POLARITY, ctrl_pol);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_UNDERFLOW_CLR,
+ MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY |
+ MDP4_DSI_UNDERFLOW_CLR_COLOR(0xff));
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_HCTL,
+ MDP4_DSI_ACTIVE_HCTL_START(0) |
+ MDP4_DSI_ACTIVE_HCTL_END(0));
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_SKEW, dsi_hsync_skew);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_BORDER_CLR, 0);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VSTART, 0);
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VEND, 0);
+}
+
+static void mdp4_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+
+ if (!mdp4_dsi_encoder->enabled)
+ return;
+
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
+
+ /*
+ * Wait for a vsync so we know the ENABLE=0 latched before
+ * the (connector) source of the vsync's gets disabled,
+ * otherwise we end up in a funny state if we re-enable
+ * before the disable latches, which results that some of
+ * the settings changes for the new modeset (like new
+ * scanout buffer) don't latch properly..
+ */
+ mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
+
+ mdp4_dsi_encoder->enabled = false;
+}
+
+static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+
+ if (mdp4_dsi_encoder->enabled)
+ return;
+
+ mdp4_crtc_set_config(encoder->crtc,
+ MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
+ MDP4_DMA_CONFIG_DEFLKR_EN |
+ MDP4_DMA_CONFIG_DITHER_EN |
+ MDP4_DMA_CONFIG_R_BPC(BPC8) |
+ MDP4_DMA_CONFIG_G_BPC(BPC8) |
+ MDP4_DMA_CONFIG_B_BPC(BPC8) |
+ MDP4_DMA_CONFIG_PACK(0x21));
+
+ mdp4_crtc_set_intf(encoder->crtc, INTF_DSI_VIDEO, 0);
+
+ mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 1);
+
+ mdp4_dsi_encoder->enabled = true;
+}
+
+static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = {
+ .mode_fixup = mdp4_dsi_encoder_mode_fixup,
+ .mode_set = mdp4_dsi_encoder_mode_set,
+ .disable = mdp4_dsi_encoder_disable,
+ .enable = mdp4_dsi_encoder_enable,
+};
+
+/* initialize encoder */
+struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
+{
+ struct drm_encoder *encoder = NULL;
+ struct mdp4_dsi_encoder *mdp4_dsi_encoder;
+ int ret;
+
+ mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL);
+ if (!mdp4_dsi_encoder) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ encoder = &mdp4_dsi_encoder->base;
+
+ drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, NULL);
+ drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs);
+
+ return encoder;
+
+fail:
+ if (encoder)
+ mdp4_dsi_encoder_destroy(encoder);
+
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
index 89614c6a6c1b..a21df54cb50f 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
@@ -262,7 +262,7 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev)
encoder = &mdp4_dtv_encoder->base;
drm_encoder_init(dev, encoder, &mdp4_dtv_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs);
mdp4_dtv_encoder->src_clk = devm_clk_get(dev->dev, "src_clk");
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
index 5ed38cf548a1..a521207db8a1 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
@@ -29,7 +29,7 @@ void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
{
- DRM_ERROR("errors: %08x\n", irqstatus);
+ DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
}
void mdp4_irq_preinstall(struct msm_kms *kms)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index 077f7521a971..5a8e3d6bcbff 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -169,7 +169,14 @@ static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder)
{
/* if we had >1 encoder, we'd need something more clever: */
- return mdp4_dtv_round_pixclk(encoder, rate);
+ switch (encoder->encoder_type) {
+ case DRM_MODE_ENCODER_TMDS:
+ return mdp4_dtv_round_pixclk(encoder, rate);
+ case DRM_MODE_ENCODER_LVDS:
+ case DRM_MODE_ENCODER_DSI:
+ default:
+ return rate;
+ }
}
static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
@@ -240,19 +247,18 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
return 0;
}
-#ifdef CONFIG_OF
-static struct drm_panel *detect_panel(struct drm_device *dev)
+static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev)
{
struct device_node *endpoint, *panel_node;
struct device_node *np = dev->dev->of_node;
- struct drm_panel *panel = NULL;
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) {
- dev_err(dev->dev, "no valid endpoint\n");
- return ERR_PTR(-ENODEV);
+ DBG("no endpoint in MDP4 to fetch LVDS panel\n");
+ return NULL;
}
+ /* don't proceed if we have an endpoint but no panel_node tied to it */
panel_node = of_graph_get_remote_port_parent(endpoint);
if (!panel_node) {
dev_err(dev->dev, "no valid panel node\n");
@@ -262,132 +268,185 @@ static struct drm_panel *detect_panel(struct drm_device *dev)
of_node_put(endpoint);
- panel = of_drm_find_panel(panel_node);
- if (!panel) {
- of_node_put(panel_node);
- return ERR_PTR(-EPROBE_DEFER);
- }
-
- return panel;
+ return panel_node;
}
-#else
-static struct drm_panel *detect_panel(struct drm_device *dev)
-{
- // ??? maybe use a module param to specify which panel is attached?
-}
-#endif
-static int modeset_init(struct mdp4_kms *mdp4_kms)
+static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
+ int intf_type)
{
struct drm_device *dev = mdp4_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
- struct drm_plane *plane;
- struct drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector *connector;
- struct drm_panel *panel;
+ struct device_node *panel_node;
+ struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
+ int i, dsi_id;
int ret;
- /* construct non-private planes: */
- plane = mdp4_plane_init(dev, VG1, false);
- if (IS_ERR(plane)) {
- dev_err(dev->dev, "failed to construct plane for VG1\n");
- ret = PTR_ERR(plane);
- goto fail;
- }
- priv->planes[priv->num_planes++] = plane;
+ switch (intf_type) {
+ case DRM_MODE_ENCODER_LVDS:
+ /*
+ * bail out early if:
+ * - there is no panel node (no need to initialize lcdc
+ * encoder and lvds connector), or
+ * - panel node is a bad pointer
+ */
+ panel_node = mdp4_detect_lcdc_panel(dev);
+ if (IS_ERR_OR_NULL(panel_node))
+ return PTR_ERR(panel_node);
+
+ encoder = mdp4_lcdc_encoder_init(dev, panel_node);
+ if (IS_ERR(encoder)) {
+ dev_err(dev->dev, "failed to construct LCDC encoder\n");
+ return PTR_ERR(encoder);
+ }
- plane = mdp4_plane_init(dev, VG2, false);
- if (IS_ERR(plane)) {
- dev_err(dev->dev, "failed to construct plane for VG2\n");
- ret = PTR_ERR(plane);
- goto fail;
- }
- priv->planes[priv->num_planes++] = plane;
+ /* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
+ encoder->possible_crtcs = 1 << DMA_P;
- /*
- * Setup the LCDC/LVDS path: RGB2 -> DMA_P -> LCDC -> LVDS:
- */
+ connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
+ if (IS_ERR(connector)) {
+ dev_err(dev->dev, "failed to initialize LVDS connector\n");
+ return PTR_ERR(connector);
+ }
- panel = detect_panel(dev);
- if (IS_ERR(panel)) {
- ret = PTR_ERR(panel);
- dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret);
- goto fail;
- }
+ priv->encoders[priv->num_encoders++] = encoder;
+ priv->connectors[priv->num_connectors++] = connector;
- plane = mdp4_plane_init(dev, RGB2, true);
- if (IS_ERR(plane)) {
- dev_err(dev->dev, "failed to construct plane for RGB2\n");
- ret = PTR_ERR(plane);
- goto fail;
- }
+ break;
+ 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");
+ return PTR_ERR(encoder);
+ }
- crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, 0, DMA_P);
- if (IS_ERR(crtc)) {
- dev_err(dev->dev, "failed to construct crtc for DMA_P\n");
- ret = PTR_ERR(crtc);
- goto fail;
- }
+ /* DTV can be hooked to DMA_E: */
+ encoder->possible_crtcs = 1 << 1;
- encoder = mdp4_lcdc_encoder_init(dev, panel);
- if (IS_ERR(encoder)) {
- dev_err(dev->dev, "failed to construct LCDC encoder\n");
- ret = PTR_ERR(encoder);
- goto fail;
- }
+ if (priv->hdmi) {
+ /* Construct bridge/connector for HDMI: */
+ ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+ if (ret) {
+ dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+ return ret;
+ }
+ }
- /* LCDC can be hooked to DMA_P: */
- encoder->possible_crtcs = 1 << priv->num_crtcs;
+ priv->encoders[priv->num_encoders++] = encoder;
- priv->crtcs[priv->num_crtcs++] = crtc;
- priv->encoders[priv->num_encoders++] = encoder;
+ break;
+ case DRM_MODE_ENCODER_DSI:
+ /* only DSI1 supported for now */
+ dsi_id = 0;
- connector = mdp4_lvds_connector_init(dev, panel, encoder);
- if (IS_ERR(connector)) {
- ret = PTR_ERR(connector);
- dev_err(dev->dev, "failed to initialize LVDS connector: %d\n", ret);
- goto fail;
- }
+ if (!priv->dsi[dsi_id])
+ break;
- priv->connectors[priv->num_connectors++] = connector;
+ for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
+ dsi_encs[i] = mdp4_dsi_encoder_init(dev);
+ if (IS_ERR(dsi_encs[i])) {
+ ret = PTR_ERR(dsi_encs[i]);
+ dev_err(dev->dev,
+ "failed to construct DSI encoder: %d\n",
+ ret);
+ return ret;
+ }
- /*
- * Setup DTV/HDMI path: RGB1 -> DMA_E -> DTV -> HDMI:
- */
+ /* TODO: Add DMA_S later? */
+ dsi_encs[i]->possible_crtcs = 1 << DMA_P;
+ priv->encoders[priv->num_encoders++] = dsi_encs[i];
+ }
- plane = mdp4_plane_init(dev, RGB1, true);
- if (IS_ERR(plane)) {
- dev_err(dev->dev, "failed to construct plane for RGB1\n");
- ret = PTR_ERR(plane);
- goto fail;
- }
+ ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
+ if (ret) {
+ dev_err(dev->dev, "failed to initialize DSI: %d\n",
+ ret);
+ return ret;
+ }
- crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, 1, DMA_E);
- if (IS_ERR(crtc)) {
- dev_err(dev->dev, "failed to construct crtc for DMA_E\n");
- ret = PTR_ERR(crtc);
- goto fail;
+ break;
+ default:
+ dev_err(dev->dev, "Invalid or unsupported interface\n");
+ return -EINVAL;
}
- encoder = mdp4_dtv_encoder_init(dev);
- if (IS_ERR(encoder)) {
- dev_err(dev->dev, "failed to construct DTV encoder\n");
- ret = PTR_ERR(encoder);
- goto fail;
+ return 0;
+}
+
+static int modeset_init(struct mdp4_kms *mdp4_kms)
+{
+ struct drm_device *dev = mdp4_kms->dev;
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ int i, ret;
+ static const enum mdp4_pipe rgb_planes[] = {
+ RGB1, RGB2,
+ };
+ static const enum mdp4_pipe vg_planes[] = {
+ VG1, VG2,
+ };
+ static const enum mdp4_dma mdp4_crtcs[] = {
+ DMA_P, DMA_E,
+ };
+ static const char * const mdp4_crtc_names[] = {
+ "DMA_P", "DMA_E",
+ };
+ static const int mdp4_intfs[] = {
+ DRM_MODE_ENCODER_LVDS,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_ENCODER_TMDS,
+ };
+
+ /* construct non-private planes: */
+ 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,
+ "failed to construct plane for VG%d\n", i + 1);
+ ret = PTR_ERR(plane);
+ goto fail;
+ }
+ priv->planes[priv->num_planes++] = plane;
}
- /* DTV can be hooked to DMA_E: */
- encoder->possible_crtcs = 1 << priv->num_crtcs;
+ 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,
+ "failed to construct plane for RGB%d\n", i + 1);
+ ret = PTR_ERR(plane);
+ goto fail;
+ }
+
+ 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",
+ mdp4_crtc_names[i]);
+ ret = PTR_ERR(crtc);
+ goto fail;
+ }
+
+ priv->crtcs[priv->num_crtcs++] = crtc;
+ }
- priv->crtcs[priv->num_crtcs++] = crtc;
- priv->encoders[priv->num_encoders++] = encoder;
+ /*
+ * we currently set up two relatively fixed paths:
+ *
+ * LCDC/LVDS path: RGB1 -> DMA_P -> LCDC -> LVDS
+ * or
+ * DSI path: RGB1 -> DMA_P -> DSI1 -> DSI Panel
+ *
+ * DTV/HDMI path: RGB2 -> DMA_E -> DTV -> HDMI
+ */
- if (priv->hdmi) {
- /* Construct bridge/connector for HDMI: */
- ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+ 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 HDMI: %d\n", ret);
+ dev_err(dev->dev, "failed to initialize intf: %d, %d\n",
+ i, ret);
goto fail;
}
}
@@ -558,17 +617,10 @@ fail:
static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
{
static struct mdp4_platform_config config = {};
-#ifdef CONFIG_OF
- /* TODO */
+
+ /* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
config.max_clk = 266667000;
config.iommu = iommu_domain_alloc(&platform_bus_type);
-#else
- if (cpu_is_apq8064())
- config.max_clk = 266667000;
- else
- config.max_clk = 200000000;
-
- config.iommu = msm_get_iommu_domain(DISPLAY_READ_DOMAIN);
-#endif
+
return &config;
}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
index 8a7f6e1e2bca..d2c96ef431f4 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
@@ -157,7 +157,7 @@ static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
break;
default:
- WARN_ON("invalid pipe");
+ WARN(1, "invalid pipe");
break;
}
@@ -212,10 +212,19 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
- struct drm_panel *panel);
+ struct device_node *panel_node);
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
- struct drm_panel *panel, struct drm_encoder *encoder);
+ struct device_node *panel_node, struct drm_encoder *encoder);
+
+#ifdef CONFIG_DRM_MSM_DSI
+struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev);
+#else
+static inline struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
#ifdef CONFIG_COMMON_CLK
struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
index 4cd6e721aa0a..cd63fedb67cc 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
@@ -23,6 +23,7 @@
struct mdp4_lcdc_encoder {
struct drm_encoder base;
+ struct device_node *panel_node;
struct drm_panel *panel;
struct clk *lcdc_clk;
unsigned long int pixclock;
@@ -338,7 +339,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
- struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+ struct drm_panel *panel;
int i, ret;
if (WARN_ON(!mdp4_lcdc_encoder->enabled))
@@ -346,6 +347,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
+ panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
if (panel) {
drm_panel_disable(panel);
drm_panel_unprepare(panel);
@@ -381,7 +383,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
to_mdp4_lcdc_encoder(encoder);
unsigned long pc = mdp4_lcdc_encoder->pixclock;
struct mdp4_kms *mdp4_kms = get_kms(encoder);
- struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+ struct drm_panel *panel;
int i, ret;
if (WARN_ON(mdp4_lcdc_encoder->enabled))
@@ -414,6 +416,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
if (ret)
dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
+ panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
if (panel) {
drm_panel_prepare(panel);
drm_panel_enable(panel);
@@ -442,7 +445,7 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
/* initialize encoder */
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
- struct drm_panel *panel)
+ struct device_node *panel_node)
{
struct drm_encoder *encoder = NULL;
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
@@ -455,12 +458,12 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
goto fail;
}
- mdp4_lcdc_encoder->panel = panel;
+ mdp4_lcdc_encoder->panel_node = panel_node;
encoder = &mdp4_lcdc_encoder->base;
drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
/* TODO: do we need different pll in other cases? */
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
index 921185133d38..e73e1742b250 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
@@ -23,6 +23,7 @@
struct mdp4_lvds_connector {
struct drm_connector base;
struct drm_encoder *encoder;
+ struct device_node *panel_node;
struct drm_panel *panel;
};
#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
@@ -33,6 +34,10 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
+ if (!mdp4_lvds_connector->panel)
+ mdp4_lvds_connector->panel =
+ of_drm_find_panel(mdp4_lvds_connector->panel_node);
+
return mdp4_lvds_connector->panel ?
connector_status_connected :
connector_status_disconnected;
@@ -42,10 +47,6 @@ static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
{
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
- struct drm_panel *panel = mdp4_lvds_connector->panel;
-
- if (panel)
- drm_panel_detach(panel);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
@@ -60,9 +61,14 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
struct drm_panel *panel = mdp4_lvds_connector->panel;
int ret = 0;
- if (panel)
+ if (panel) {
+ drm_panel_attach(panel, connector);
+
ret = panel->funcs->get_modes(panel);
+ drm_panel_detach(panel);
+ }
+
return ret;
}
@@ -111,7 +117,7 @@ static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs
/* initialize connector */
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
- struct drm_panel *panel, struct drm_encoder *encoder)
+ struct device_node *panel_node, struct drm_encoder *encoder)
{
struct drm_connector *connector = NULL;
struct mdp4_lvds_connector *mdp4_lvds_connector;
@@ -124,7 +130,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
}
mdp4_lvds_connector->encoder = encoder;
- mdp4_lvds_connector->panel = panel;
+ mdp4_lvds_connector->panel_node = panel_node;
connector = &mdp4_lvds_connector->base;
@@ -141,9 +147,6 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
drm_mode_connector_attach_encoder(connector, encoder);
- if (panel)
- drm_panel_attach(panel, connector);
-
return connector;
fail:
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 30d57e74c42f..9f96dfe67769 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -397,7 +397,8 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
- mdp4_plane->formats, mdp4_plane->nformats, type);
+ mdp4_plane->formats, mdp4_plane->nformats,
+ type, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
index bb1225aa2f75..57f73f0c120d 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
@@ -553,9 +553,7 @@ fail:
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
{
static struct mdp5_cfg_platform config = {};
-#ifdef CONFIG_OF
- /* TODO */
-#endif
+
config.iommu = iommu_domain_alloc(&platform_bus_type);
return &config;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
index 8e6c9b598a57..1aa21dba663d 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
@@ -326,7 +326,7 @@ struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
mdp5_cmd_enc->ctl = ctl;
drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
- DRM_MODE_ENCODER_DSI);
+ DRM_MODE_ENCODER_DSI, NULL);
drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 7f9f4ac88029..20cee5ce4071 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -797,7 +797,8 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
snprintf(mdp5_crtc->name, sizeof(mdp5_crtc->name), "%s:%d",
pipe2name(mdp5_plane_pipe(plane)), id);
- drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
+ drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs,
+ NULL);
drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
"unref cursor", unref_cursor_worker);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
index c9e32b08a7a0..0d737cad03a6 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
@@ -293,6 +293,24 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
.enable = mdp5_encoder_enable,
};
+int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
+{
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_kms *mdp5_kms = get_kms(encoder);
+ int intf = mdp5_encoder->intf.num;
+
+ return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
+}
+
+u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
+{
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_kms *mdp5_kms = get_kms(encoder);
+ int intf = mdp5_encoder->intf.num;
+
+ return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
+}
+
int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder)
{
@@ -354,7 +372,7 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
spin_lock_init(&mdp5_encoder->intf_lock);
- drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type);
+ drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type, NULL);
drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
index b0d4b53b97f4..73bc3e312fd4 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
@@ -31,7 +31,7 @@ void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
{
- DRM_ERROR("errors: %08x\n", irqstatus);
+ DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
}
void mdp5_irq_preinstall(struct msm_kms *kms)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index b532faa8026d..e115318402bd 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -468,6 +468,127 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
return 0;
}
+static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder(encoder, dev)
+ if (encoder->crtc == crtc)
+ return encoder;
+
+ return NULL;
+}
+
+static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
+ unsigned int flags, int *vpos, int *hpos,
+ ktime_t *stime, ktime_t *etime,
+ const struct drm_display_mode *mode)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
+ int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
+ int ret = 0;
+
+ crtc = priv->crtcs[pipe];
+ if (!crtc) {
+ DRM_ERROR("Invalid crtc %d\n", pipe);
+ return 0;
+ }
+
+ encoder = get_encoder_from_crtc(crtc);
+ if (!encoder) {
+ DRM_ERROR("no encoder found for crtc %d\n", pipe);
+ return 0;
+ }
+
+ ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+ vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
+
+ /*
+ * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
+ * the end of VFP. Translate the porch values relative to the line
+ * counter positions.
+ */
+
+ vactive_start = vsw + vbp + 1;
+
+ vactive_end = vactive_start + mode->crtc_vdisplay;
+
+ /* last scan line before VSYNC */
+ vfp_end = mode->crtc_vtotal;
+
+ if (stime)
+ *stime = ktime_get();
+
+ line = mdp5_encoder_get_linecount(encoder);
+
+ if (line < vactive_start) {
+ line -= vactive_start;
+ ret |= DRM_SCANOUTPOS_IN_VBLANK;
+ } else if (line > vactive_end) {
+ line = line - vfp_end - vactive_start;
+ ret |= DRM_SCANOUTPOS_IN_VBLANK;
+ } else {
+ line -= vactive_start;
+ }
+
+ *vpos = line;
+ *hpos = 0;
+
+ if (etime)
+ *etime = ktime_get();
+
+ return ret;
+}
+
+static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_crtc *crtc;
+
+ if (pipe < 0 || pipe >= priv->num_crtcs) {
+ DRM_ERROR("Invalid crtc %d\n", pipe);
+ return -EINVAL;
+ }
+
+ crtc = priv->crtcs[pipe];
+ if (!crtc) {
+ DRM_ERROR("Invalid crtc %d\n", pipe);
+ return -EINVAL;
+ }
+
+ return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
+ vblank_time, flags,
+ &crtc->mode);
+}
+
+static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
+
+ if (pipe < 0 || pipe >= priv->num_crtcs)
+ return 0;
+
+ crtc = priv->crtcs[pipe];
+ if (!crtc)
+ return 0;
+
+ encoder = get_encoder_from_crtc(crtc);
+ if (!encoder)
+ return 0;
+
+ return mdp5_encoder_get_framecount(encoder);
+}
+
struct msm_kms *mdp5_kms_init(struct drm_device *dev)
{
struct platform_device *pdev = dev->platformdev;
@@ -590,6 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
!config->hw->intf.base[i])
continue;
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
+
+ mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
}
mdp5_disable(mdp5_kms);
mdelay(16);
@@ -635,6 +758,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
dev->mode_config.max_width = config->hw->lm.max_width;
dev->mode_config.max_height = config->hw->lm.max_height;
+ dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp;
+ dev->driver->get_scanout_position = mdp5_get_scanoutpos;
+ dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
+ dev->max_vblank_count = 0xffffffff;
+ dev->vblank_disable_immediate = true;
+
return kms;
fail:
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 84f65d415598..00730ba08a60 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -222,6 +222,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf, struct mdp5_ctl *ctl);
int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder);
+int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
+u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
#ifdef CONFIG_DRM_MSM_DSI
struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 81cd49045ffc..432c09836b0e 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -904,7 +904,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
mdp5_plane->formats, mdp5_plane->nformats,
- type);
+ type, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index b88ce514eb8e..9a30807b900b 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -237,20 +237,9 @@ static int msm_unload(struct drm_device *dev)
static int get_mdp_ver(struct platform_device *pdev)
{
-#ifdef CONFIG_OF
- static const struct of_device_id match_types[] = { {
- .compatible = "qcom,mdss_mdp",
- .data = (void *)5,
- }, {
- /* end node */
- } };
struct device *dev = &pdev->dev;
- const struct of_device_id *match;
- match = of_match_node(match_types, dev->of_node);
- if (match)
- return (int)(unsigned long)match->data;
-#endif
- return 4;
+
+ return (int) (unsigned long) of_device_get_match_data(dev);
}
#include <linux/of_address.h>
@@ -258,10 +247,10 @@ static int get_mdp_ver(struct platform_device *pdev)
static int msm_init_vram(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
+ struct device_node *node;
unsigned long size = 0;
int ret = 0;
-#ifdef CONFIG_OF
/* In the device-tree world, we could have a 'memory-region'
* phandle, which gives us a link to our "vram". Allocating
* is all nicely abstracted behind the dma api, but we need
@@ -278,7 +267,6 @@ static int msm_init_vram(struct drm_device *dev)
* as corruption on screen before we have a chance to
* load and do initial modeset)
*/
- struct device_node *node;
node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
if (node) {
@@ -288,14 +276,12 @@ static int msm_init_vram(struct drm_device *dev)
return ret;
size = r.end - r.start;
DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start);
- } else
-#endif
- /* if we have no IOMMU, then we need to use carveout allocator.
- * Grab the entire CMA chunk carved out in early startup in
- * mach-msm:
- */
- if (!iommu_present(&platform_bus_type)) {
+ /* if we have no IOMMU, then we need to use carveout allocator.
+ * Grab the entire CMA chunk carved out in early startup in
+ * mach-msm:
+ */
+ } else if (!iommu_present(&platform_bus_type)) {
DRM_INFO("using %s VRAM carveout\n", vram);
size = memparse(vram, NULL);
}
@@ -1035,9 +1021,9 @@ static const struct dev_pm_ops msm_pm_ops = {
* Componentized driver support:
*/
-#ifdef CONFIG_OF
-/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx
- * (or probably any other).. so probably some room for some helpers
+/*
+ * NOTE: duplication of the same code as exynos or imx (or probably any other).
+ * so probably some room for some helpers
*/
static int compare_of(struct device *dev, void *data)
{
@@ -1062,12 +1048,6 @@ static int add_components(struct device *dev, struct component_match **matchptr,
return 0;
}
-#else
-static int compare_dev(struct device *dev, void *data)
-{
- return dev == data;
-}
-#endif
static int msm_drm_bind(struct device *dev)
{
@@ -1091,35 +1071,9 @@ static const struct component_master_ops msm_drm_ops = {
static int msm_pdev_probe(struct platform_device *pdev)
{
struct component_match *match = NULL;
-#ifdef CONFIG_OF
+
add_components(&pdev->dev, &match, "connectors");
add_components(&pdev->dev, &match, "gpus");
-#else
- /* For non-DT case, it kinda sucks. We don't actually have a way
- * to know whether or not we are waiting for certain devices (or if
- * they are simply not present). But for non-DT we only need to
- * care about apq8064/apq8060/etc (all mdp4/a3xx):
- */
- static const char *devnames[] = {
- "hdmi_msm.0", "kgsl-3d0.0",
- };
- int i;
-
- DBG("Adding components..");
-
- for (i = 0; i < ARRAY_SIZE(devnames); i++) {
- struct device *dev;
-
- dev = bus_find_device_by_name(&platform_bus_type,
- NULL, devnames[i]);
- if (!dev) {
- dev_info(&pdev->dev, "still waiting for %s\n", devnames[i]);
- return -EPROBE_DEFER;
- }
-
- component_match_add(&pdev->dev, &match, compare_dev, dev);
- }
-#endif
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
@@ -1138,8 +1092,10 @@ static const struct platform_device_id msm_id[] = {
};
static const struct of_device_id dt_match[] = {
- { .compatible = "qcom,mdp" }, /* mdp4 */
- { .compatible = "qcom,mdss_mdp" }, /* mdp5 */
+ { .compatible = "qcom,mdp4", .data = (void *) 4 }, /* mdp4 */
+ { .compatible = "qcom,mdp5", .data = (void *) 5 }, /* mdp5 */
+ /* to support downstream DT files */
+ { .compatible = "qcom,mdss_mdp", .data = (void *) 5 }, /* mdp5 */
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 3be7a56b14f1..c1e7bba2fdb7 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -31,14 +31,9 @@
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/of_graph.h>
+#include <linux/of_device.h>
#include <asm/sizes.h>
-#ifndef CONFIG_OF
-#include <mach/board.h>
-#include <mach/socinfo.h>
-#include <mach/iommu_domains.h>
-#endif
-
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -240,9 +235,9 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane);
struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
+ const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
- struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
+ struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 121713281417..a474d6cf5d9f 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -138,7 +138,7 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb)
}
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
- struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
+ struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *bos[4] = {0};
struct drm_framebuffer *fb;
@@ -168,7 +168,7 @@ out_unref:
}
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
+ const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 3f6ec077b51d..d95af6eba602 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -121,7 +121,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
/* note: if fb creation failed, we can't rely on fb destroy
* to unref the bo:
*/
- drm_gem_object_unreference(fbdev->bo);
+ drm_gem_object_unreference_unlocked(fbdev->bo);
ret = PTR_ERR(fb);
goto fail;
}
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index c76cc853b08a..3cedb8d5c855 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
+#include <linux/pfn_t.h>
#include "msm_drv.h"
#include "msm_gem.h"
@@ -222,7 +223,8 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
pfn, pfn << PAGE_SHIFT);
- ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
+ ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
+ __pfn_to_pfn_t(pfn, PFN_DEV));
out_unlock:
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
index a34b437dbc8f..2527bf4ca5d9 100644
--- a/drivers/gpu/drm/nouveau/Kbuild
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -24,7 +24,6 @@ nouveau-y += nouveau_hwmon.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
nouveau-y += nouveau_nvif.o
nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
-nouveau-y += nouveau_sysfs.o
nouveau-y += nouveau_usif.o # userspace <-> nvif
nouveau-y += nouveau_vga.o
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 3d96b49fe662..6f04397d43a7 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -1081,8 +1081,6 @@ nouveau_crtc_set_config(struct drm_mode_set *set)
}
static const struct drm_crtc_funcs nv04_crtc_funcs = {
- .save = nv_crtc_save,
- .restore = nv_crtc_restore,
.cursor_set = nv04_crtc_cursor_set,
.cursor_move = nv04_crtc_cursor_move,
.gamma_set = nv_crtc_gamma_set,
@@ -1123,6 +1121,9 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
nv_crtc->index = crtc_num;
nv_crtc->last_dpms = NV_DPMS_CLEARED;
+ nv_crtc->save = nv_crtc_save;
+ nv_crtc->restore = nv_crtc_restore;
+
drm_crtc_init(dev, &nv_crtc->base, &nv04_crtc_funcs);
drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs);
drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c
index 78cb033bc015..b48eec395f07 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dac.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c
@@ -504,8 +504,6 @@ static void nv04_dac_destroy(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs nv04_dac_helper_funcs = {
.dpms = nv04_dac_dpms,
- .save = nv04_dac_save,
- .restore = nv04_dac_restore,
.mode_fixup = nv04_dac_mode_fixup,
.prepare = nv04_dac_prepare,
.commit = nv04_dac_commit,
@@ -515,8 +513,6 @@ static const struct drm_encoder_helper_funcs nv04_dac_helper_funcs = {
static const struct drm_encoder_helper_funcs nv17_dac_helper_funcs = {
.dpms = nv04_dac_dpms,
- .save = nv04_dac_save,
- .restore = nv04_dac_restore,
.mode_fixup = nv04_dac_mode_fixup,
.prepare = nv04_dac_prepare,
.commit = nv04_dac_commit,
@@ -545,12 +541,16 @@ nv04_dac_create(struct drm_connector *connector, struct dcb_output *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
+ nv_encoder->enc_save = nv04_dac_save;
+ nv_encoder->enc_restore = nv04_dac_restore;
+
if (nv_gf4_disp_arch(dev))
helper = &nv17_dac_helper_funcs;
else
helper = &nv04_dac_helper_funcs;
- drm_encoder_init(dev, encoder, &nv04_dac_funcs, DRM_MODE_ENCODER_DAC);
+ drm_encoder_init(dev, encoder, &nv04_dac_funcs, DRM_MODE_ENCODER_DAC,
+ NULL);
drm_encoder_helper_add(encoder, helper);
encoder->possible_crtcs = entry->heads;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
index 429ab5e3025a..05bfd151d1d8 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
@@ -652,8 +652,6 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
.dpms = nv04_lvds_dpms,
- .save = nv04_dfp_save,
- .restore = nv04_dfp_restore,
.mode_fixup = nv04_dfp_mode_fixup,
.prepare = nv04_dfp_prepare,
.commit = nv04_dfp_commit,
@@ -663,8 +661,6 @@ static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
static const struct drm_encoder_helper_funcs nv04_tmds_helper_funcs = {
.dpms = nv04_tmds_dpms,
- .save = nv04_dfp_save,
- .restore = nv04_dfp_restore,
.mode_fixup = nv04_dfp_mode_fixup,
.prepare = nv04_dfp_prepare,
.commit = nv04_dfp_commit,
@@ -701,12 +697,15 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_output *entry)
if (!nv_encoder)
return -ENOMEM;
+ nv_encoder->enc_save = nv04_dfp_save;
+ nv_encoder->enc_restore = nv04_dfp_restore;
+
encoder = to_drm_encoder(nv_encoder);
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
- drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type);
+ drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type, NULL);
drm_encoder_helper_add(encoder, helper);
encoder->possible_crtcs = entry->heads;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c
index 9e650081c357..b4a6bc433ef5 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c
@@ -39,7 +39,8 @@ nv04_display_create(struct drm_device *dev)
struct dcb_table *dcb = &drm->vbios.dcb;
struct drm_connector *connector, *ct;
struct drm_encoder *encoder;
- struct drm_crtc *crtc;
+ struct nouveau_encoder *nv_encoder;
+ struct nouveau_crtc *crtc;
struct nv04_display *disp;
int i, ret;
@@ -107,14 +108,11 @@ nv04_display_create(struct drm_device *dev)
}
/* Save previous state */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- crtc->funcs->save(crtc);
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- const struct drm_encoder_helper_funcs *func = encoder->helper_private;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
+ crtc->save(&crtc->base);
- func->save(encoder);
- }
+ list_for_each_entry(nv_encoder, &dev->mode_config.encoder_list, base.base.head)
+ nv_encoder->enc_save(&nv_encoder->base.base);
nouveau_overlay_init(dev);
@@ -126,8 +124,9 @@ nv04_display_destroy(struct drm_device *dev)
{
struct nv04_display *disp = nv04_display(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct drm_encoder *encoder;
+ struct nouveau_encoder *encoder;
struct drm_crtc *crtc;
+ struct nouveau_crtc *nv_crtc;
/* Turn every CRTC off. */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -139,14 +138,11 @@ nv04_display_destroy(struct drm_device *dev)
}
/* Restore state */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- const struct drm_encoder_helper_funcs *func = encoder->helper_private;
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
+ encoder->enc_restore(&encoder->base.base);
- func->restore(encoder);
- }
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- crtc->funcs->restore(crtc);
+ list_for_each_entry(nv_crtc, &dev->mode_config.crtc_list, base.head)
+ nv_crtc->restore(&nv_crtc->base);
nouveau_hw_save_vga_fonts(dev, 0);
@@ -159,8 +155,8 @@ nv04_display_destroy(struct drm_device *dev)
int
nv04_display_init(struct drm_device *dev)
{
- struct drm_encoder *encoder;
- struct drm_crtc *crtc;
+ struct nouveau_encoder *encoder;
+ struct nouveau_crtc *crtc;
/* meh.. modeset apparently doesn't setup all the regs and depends
* on pre-existing state, for now load the state of the card *before*
@@ -170,14 +166,11 @@ nv04_display_init(struct drm_device *dev)
* save/restore "pre-load" state, but more general so we can save
* on suspend too.
*/
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- const struct drm_encoder_helper_funcs *func = encoder->helper_private;
-
- func->restore(encoder);
- }
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
+ crtc->save(&crtc->base);
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- crtc->funcs->restore(crtc);
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
+ encoder->enc_save(&encoder->base.base);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
index 5345eb5378a8..54e9fb9eb5c0 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
@@ -192,8 +192,6 @@ static const struct drm_encoder_funcs nv04_tv_funcs = {
static const struct drm_encoder_helper_funcs nv04_tv_helper_funcs = {
.dpms = nv04_tv_dpms,
- .save = drm_i2c_encoder_save,
- .restore = drm_i2c_encoder_restore,
.mode_fixup = drm_i2c_encoder_mode_fixup,
.prepare = nv04_tv_prepare,
.commit = nv04_tv_commit,
@@ -225,9 +223,13 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
/* Initialize the common members */
encoder = to_drm_encoder(nv_encoder);
- drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC);
+ drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC,
+ NULL);
drm_encoder_helper_add(encoder, &nv04_tv_helper_funcs);
+ nv_encoder->enc_save = drm_i2c_encoder_save;
+ nv_encoder->enc_restore = drm_i2c_encoder_restore;
+
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
nv_encoder->dcb = entry;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index b734195d80a0..163317d26de9 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -769,10 +769,8 @@ static void nv17_tv_destroy(struct drm_encoder *encoder)
kfree(tv_enc);
}
-static struct drm_encoder_helper_funcs nv17_tv_helper_funcs = {
+static const struct drm_encoder_helper_funcs nv17_tv_helper_funcs = {
.dpms = nv17_tv_dpms,
- .save = nv17_tv_save,
- .restore = nv17_tv_restore,
.mode_fixup = nv17_tv_mode_fixup,
.prepare = nv17_tv_prepare,
.commit = nv17_tv_commit,
@@ -780,14 +778,14 @@ static struct drm_encoder_helper_funcs nv17_tv_helper_funcs = {
.detect = nv17_tv_detect,
};
-static struct drm_encoder_slave_funcs nv17_tv_slave_funcs = {
+static const struct drm_encoder_slave_funcs nv17_tv_slave_funcs = {
.get_modes = nv17_tv_get_modes,
.mode_valid = nv17_tv_mode_valid,
.create_resources = nv17_tv_create_resources,
.set_property = nv17_tv_set_property,
};
-static struct drm_encoder_funcs nv17_tv_funcs = {
+static const struct drm_encoder_funcs nv17_tv_funcs = {
.destroy = nv17_tv_destroy,
};
@@ -816,10 +814,14 @@ nv17_tv_create(struct drm_connector *connector, struct dcb_output *entry)
tv_enc->base.dcb = entry;
tv_enc->base.or = ffs(entry->or) - 1;
- drm_encoder_init(dev, encoder, &nv17_tv_funcs, DRM_MODE_ENCODER_TVDAC);
+ drm_encoder_init(dev, encoder, &nv17_tv_funcs, DRM_MODE_ENCODER_TVDAC,
+ NULL);
drm_encoder_helper_add(encoder, &nv17_tv_helper_funcs);
to_encoder_slave(encoder)->slave_funcs = &nv17_tv_slave_funcs;
+ tv_enc->base.enc_save = nv17_tv_save;
+ tv_enc->base.enc_restore = nv17_tv_restore;
+
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0002.h b/drivers/gpu/drm/nouveau/include/nvif/cl0002.h
new file mode 100644
index 000000000000..6d72ed38da32
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl0002.h
@@ -0,0 +1,66 @@
+#ifndef __NVIF_CL0002_H__
+#define __NVIF_CL0002_H__
+
+struct nv_dma_v0 {
+ __u8 version;
+#define NV_DMA_V0_TARGET_VM 0x00
+#define NV_DMA_V0_TARGET_VRAM 0x01
+#define NV_DMA_V0_TARGET_PCI 0x02
+#define NV_DMA_V0_TARGET_PCI_US 0x03
+#define NV_DMA_V0_TARGET_AGP 0x04
+ __u8 target;
+#define NV_DMA_V0_ACCESS_VM 0x00
+#define NV_DMA_V0_ACCESS_RD 0x01
+#define NV_DMA_V0_ACCESS_WR 0x02
+#define NV_DMA_V0_ACCESS_RDWR (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
+ __u8 access;
+ __u8 pad03[5];
+ __u64 start;
+ __u64 limit;
+ /* ... chipset-specific class data */
+};
+
+struct nv50_dma_v0 {
+ __u8 version;
+#define NV50_DMA_V0_PRIV_VM 0x00
+#define NV50_DMA_V0_PRIV_US 0x01
+#define NV50_DMA_V0_PRIV__S 0x02
+ __u8 priv;
+#define NV50_DMA_V0_PART_VM 0x00
+#define NV50_DMA_V0_PART_256 0x01
+#define NV50_DMA_V0_PART_1KB 0x02
+ __u8 part;
+#define NV50_DMA_V0_COMP_NONE 0x00
+#define NV50_DMA_V0_COMP_1 0x01
+#define NV50_DMA_V0_COMP_2 0x02
+#define NV50_DMA_V0_COMP_VM 0x03
+ __u8 comp;
+#define NV50_DMA_V0_KIND_PITCH 0x00
+#define NV50_DMA_V0_KIND_VM 0x7f
+ __u8 kind;
+ __u8 pad05[3];
+};
+
+struct gf100_dma_v0 {
+ __u8 version;
+#define GF100_DMA_V0_PRIV_VM 0x00
+#define GF100_DMA_V0_PRIV_US 0x01
+#define GF100_DMA_V0_PRIV__S 0x02
+ __u8 priv;
+#define GF100_DMA_V0_KIND_PITCH 0x00
+#define GF100_DMA_V0_KIND_VM 0xff
+ __u8 kind;
+ __u8 pad03[5];
+};
+
+struct gf119_dma_v0 {
+ __u8 version;
+#define GF119_DMA_V0_PAGE_LP 0x00
+#define GF119_DMA_V0_PAGE_SP 0x01
+ __u8 page;
+#define GF119_DMA_V0_KIND_PITCH 0x00
+#define GF119_DMA_V0_KIND_VM 0xff
+ __u8 kind;
+ __u8 pad03[5];
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0046.h b/drivers/gpu/drm/nouveau/include/nvif/cl0046.h
new file mode 100644
index 000000000000..a6a71f4ad91e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl0046.h
@@ -0,0 +1,28 @@
+#ifndef __NVIF_CL0046_H__
+#define __NVIF_CL0046_H__
+
+#define NV04_DISP_NTFY_VBLANK 0x00
+#define NV04_DISP_NTFY_CONN 0x01
+
+struct nv04_disp_mthd_v0 {
+ __u8 version;
+#define NV04_DISP_SCANOUTPOS 0x00
+ __u8 method;
+ __u8 head;
+ __u8 pad03[5];
+};
+
+struct nv04_disp_scanoutpos_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __s64 time[2];
+ __u16 vblanks;
+ __u16 vblanke;
+ __u16 vtotal;
+ __u16 vline;
+ __u16 hblanks;
+ __u16 hblanke;
+ __u16 htotal;
+ __u16 hline;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl006b.h b/drivers/gpu/drm/nouveau/include/nvif/cl006b.h
new file mode 100644
index 000000000000..309ab8a3d9e8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl006b.h
@@ -0,0 +1,11 @@
+#ifndef __NVIF_CL006B_H__
+#define __NVIF_CL006B_H__
+
+struct nv03_channel_dma_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[2];
+ __u32 offset;
+ __u64 pushbuf;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
new file mode 100644
index 000000000000..331620a52afa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h
@@ -0,0 +1,45 @@
+#ifndef __NVIF_CL0080_H__
+#define __NVIF_CL0080_H__
+
+struct nv_device_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u64 device; /* device identifier, ~0 for client default */
+};
+
+#define NV_DEVICE_V0_INFO 0x00
+#define NV_DEVICE_V0_TIME 0x01
+
+struct nv_device_info_v0 {
+ __u8 version;
+#define NV_DEVICE_INFO_V0_IGP 0x00
+#define NV_DEVICE_INFO_V0_PCI 0x01
+#define NV_DEVICE_INFO_V0_AGP 0x02
+#define NV_DEVICE_INFO_V0_PCIE 0x03
+#define NV_DEVICE_INFO_V0_SOC 0x04
+ __u8 platform;
+ __u16 chipset; /* from NV_PMC_BOOT_0 */
+ __u8 revision; /* from NV_PMC_BOOT_0 */
+#define NV_DEVICE_INFO_V0_TNT 0x01
+#define NV_DEVICE_INFO_V0_CELSIUS 0x02
+#define NV_DEVICE_INFO_V0_KELVIN 0x03
+#define NV_DEVICE_INFO_V0_RANKINE 0x04
+#define NV_DEVICE_INFO_V0_CURIE 0x05
+#define NV_DEVICE_INFO_V0_TESLA 0x06
+#define NV_DEVICE_INFO_V0_FERMI 0x07
+#define NV_DEVICE_INFO_V0_KEPLER 0x08
+#define NV_DEVICE_INFO_V0_MAXWELL 0x09
+ __u8 family;
+ __u8 pad06[2];
+ __u64 ram_size;
+ __u64 ram_user;
+ char chip[16];
+ char name[64];
+};
+
+struct nv_device_time_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u64 time;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl506e.h b/drivers/gpu/drm/nouveau/include/nvif/cl506e.h
new file mode 100644
index 000000000000..aa94b8cf9679
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl506e.h
@@ -0,0 +1,12 @@
+#ifndef __NVIF_CL506E_H__
+#define __NVIF_CL506E_H__
+
+struct nv50_channel_dma_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[6];
+ __u64 vm;
+ __u64 pushbuf;
+ __u64 offset;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl506f.h b/drivers/gpu/drm/nouveau/include/nvif/cl506f.h
new file mode 100644
index 000000000000..3b7101966de4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl506f.h
@@ -0,0 +1,13 @@
+#ifndef __NVIF_CL506F_H__
+#define __NVIF_CL506F_H__
+
+struct nv50_channel_gpfifo_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[2];
+ __u32 ilength;
+ __u64 ioffset;
+ __u64 pushbuf;
+ __u64 vm;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
new file mode 100644
index 000000000000..d15c296b5f33
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
@@ -0,0 +1,99 @@
+#ifndef __NVIF_CL5070_H__
+#define __NVIF_CL5070_H__
+
+#define NV50_DISP_MTHD 0x00
+
+struct nv50_disp_mthd_v0 {
+ __u8 version;
+#define NV50_DISP_SCANOUTPOS 0x00
+ __u8 method;
+ __u8 head;
+ __u8 pad03[5];
+};
+
+struct nv50_disp_scanoutpos_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __s64 time[2];
+ __u16 vblanks;
+ __u16 vblanke;
+ __u16 vtotal;
+ __u16 vline;
+ __u16 hblanks;
+ __u16 hblanke;
+ __u16 htotal;
+ __u16 hline;
+};
+
+struct nv50_disp_mthd_v1 {
+ __u8 version;
+#define NV50_DISP_MTHD_V1_DAC_PWR 0x10
+#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
+#define NV50_DISP_MTHD_V1_SOR_PWR 0x20
+#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
+#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
+#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
+#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24
+#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
+ __u8 method;
+ __u16 hasht;
+ __u16 hashm;
+ __u8 pad06[2];
+};
+
+struct nv50_disp_dac_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 data;
+ __u8 vsync;
+ __u8 hsync;
+ __u8 pad05[3];
+};
+
+struct nv50_disp_dac_load_v0 {
+ __u8 version;
+ __u8 load;
+ __u8 pad02[2];
+ __u32 data;
+};
+
+struct nv50_disp_sor_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 pad02[6];
+};
+
+struct nv50_disp_sor_hda_eld_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u8 data[];
+};
+
+struct nv50_disp_sor_hdmi_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 max_ac_packet;
+ __u8 rekey;
+ __u8 pad04[4];
+};
+
+struct nv50_disp_sor_lvds_script_v0 {
+ __u8 version;
+ __u8 pad01[1];
+ __u16 script;
+ __u8 pad04[4];
+};
+
+struct nv50_disp_sor_dp_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 pad02[6];
+};
+
+struct nv50_disp_pior_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 type;
+ __u8 pad03[5];
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507a.h b/drivers/gpu/drm/nouveau/include/nvif/cl507a.h
new file mode 100644
index 000000000000..12e0643b78bd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl507a.h
@@ -0,0 +1,11 @@
+#ifndef __NVIF_CL507A_H__
+#define __NVIF_CL507A_H__
+
+struct nv50_disp_cursor_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+};
+
+#define NV50_DISP_CURSOR_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507b.h b/drivers/gpu/drm/nouveau/include/nvif/cl507b.h
new file mode 100644
index 000000000000..99e9d8c47f60
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl507b.h
@@ -0,0 +1,11 @@
+#ifndef __NVIF_CL507B_H__
+#define __NVIF_CL507B_H__
+
+struct nv50_disp_overlay_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+};
+
+#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507c.h b/drivers/gpu/drm/nouveau/include/nvif/cl507c.h
new file mode 100644
index 000000000000..6af70dbdfd9f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl507c.h
@@ -0,0 +1,12 @@
+#ifndef __NVIF_CL507C_H__
+#define __NVIF_CL507C_H__
+
+struct nv50_disp_base_channel_dma_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+ __u64 pushbuf;
+};
+
+#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507d.h b/drivers/gpu/drm/nouveau/include/nvif/cl507d.h
new file mode 100644
index 000000000000..5ab0c9e4c6a3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl507d.h
@@ -0,0 +1,11 @@
+#ifndef __NVIF_CL507D_H__
+#define __NVIF_CL507D_H__
+
+struct nv50_disp_core_channel_dma_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u64 pushbuf;
+};
+
+#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507e.h b/drivers/gpu/drm/nouveau/include/nvif/cl507e.h
new file mode 100644
index 000000000000..c06209f3cac4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl507e.h
@@ -0,0 +1,12 @@
+#ifndef __NVIF_CL507E_H__
+#define __NVIF_CL507E_H__
+
+struct nv50_disp_overlay_channel_dma_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+ __u64 pushbuf;
+};
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl826e.h b/drivers/gpu/drm/nouveau/include/nvif/cl826e.h
new file mode 100644
index 000000000000..05e6ef7cd190
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl826e.h
@@ -0,0 +1,14 @@
+#ifndef __NVIF_CL826E_H__
+#define __NVIF_CL826E_H__
+
+struct g82_channel_dma_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[6];
+ __u64 vm;
+ __u64 pushbuf;
+ __u64 offset;
+};
+
+#define G82_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl826f.h b/drivers/gpu/drm/nouveau/include/nvif/cl826f.h
new file mode 100644
index 000000000000..cecafcb1e954
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl826f.h
@@ -0,0 +1,15 @@
+#ifndef __NVIF_CL826F_H__
+#define __NVIF_CL826F_H__
+
+struct g82_channel_gpfifo_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[2];
+ __u32 ilength;
+ __u64 ioffset;
+ __u64 pushbuf;
+ __u64 vm;
+};
+
+#define G82_CHANNEL_GPFIFO_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl906f.h b/drivers/gpu/drm/nouveau/include/nvif/cl906f.h
new file mode 100644
index 000000000000..2caf0838fcfd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl906f.h
@@ -0,0 +1,14 @@
+#ifndef __NVIF_CL906F_H__
+#define __NVIF_CL906F_H__
+
+struct fermi_channel_gpfifo_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[2];
+ __u32 ilength;
+ __u64 ioffset;
+ __u64 vm;
+};
+
+#define FERMI_CHANNEL_GPFIFO_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl9097.h b/drivers/gpu/drm/nouveau/include/nvif/cl9097.h
new file mode 100644
index 000000000000..4057676d2981
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl9097.h
@@ -0,0 +1,44 @@
+#ifndef __NVIF_CL9097_H__
+#define __NVIF_CL9097_H__
+
+#define FERMI_A_ZBC_COLOR 0x00
+#define FERMI_A_ZBC_DEPTH 0x01
+
+struct fermi_a_zbc_color_v0 {
+ __u8 version;
+#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO 0x01
+#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE 0x02
+#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32 0x04
+#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16 0x08
+#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16 0x0c
+#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16 0x10
+#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16 0x14
+#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16 0x16
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8 0x18
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8 0x1c
+#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10 0x20
+#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10 0x24
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8 0x28
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8 0x2c
+#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8 0x30
+#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8 0x34
+#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8 0x38
+#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10 0x3c
+#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11 0x40
+ __u8 format;
+ __u8 index;
+ __u8 pad03[5];
+ __u32 ds[4];
+ __u32 l2[4];
+};
+
+struct fermi_a_zbc_depth_v0 {
+ __u8 version;
+#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32 0x01
+ __u8 format;
+ __u8 index;
+ __u8 pad03[5];
+ __u32 ds;
+ __u32 l2;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cla06f.h b/drivers/gpu/drm/nouveau/include/nvif/cla06f.h
new file mode 100644
index 000000000000..85b7827eb782
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/cla06f.h
@@ -0,0 +1,21 @@
+#ifndef __NVIF_CLA06F_H__
+#define __NVIF_CLA06F_H__
+
+struct kepler_channel_gpfifo_a_v0 {
+ __u8 version;
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR 0x01
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPDEC 0x02
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPPP 0x04
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSVLD 0x08
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0 0x10
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1 0x20
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40
+ __u8 engine;
+ __u16 chid;
+ __u32 ilength;
+ __u64 ioffset;
+ __u64 vm;
+};
+
+#define KEPLER_CHANNEL_GPFIFO_A_V0_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h
index 95a64d89547c..4179cd65ac0a 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -1,16 +1,21 @@
#ifndef __NVIF_CLASS_H__
#define __NVIF_CLASS_H__
-/*******************************************************************************
- * class identifiers
- ******************************************************************************/
+/* these class numbers are made up by us, and not nvidia-assigned */
+#define NVIF_CLASS_CONTROL /* if0001.h */ -1
+#define NVIF_CLASS_PERFMON /* if0002.h */ -2
+#define NVIF_CLASS_PERFDOM /* if0003.h */ -3
+#define NVIF_CLASS_SW_NV04 /* if0004.h */ -4
+#define NVIF_CLASS_SW_NV10 /* if0005.h */ -5
+#define NVIF_CLASS_SW_NV50 /* if0005.h */ -6
+#define NVIF_CLASS_SW_GF100 /* if0005.h */ -7
/* the below match nvidia-assigned (either in hw, or sw) class numbers */
-#define NV_DEVICE 0x00000080
+#define NV_DEVICE /* cl0080.h */ 0x00000080
-#define NV_DMA_FROM_MEMORY 0x00000002
-#define NV_DMA_TO_MEMORY 0x00000003
-#define NV_DMA_IN_MEMORY 0x0000003d
+#define NV_DMA_FROM_MEMORY /* cl0002.h */ 0x00000002
+#define NV_DMA_TO_MEMORY /* cl0002.h */ 0x00000003
+#define NV_DMA_IN_MEMORY /* cl0002.h */ 0x0000003d
#define FERMI_TWOD_A 0x0000902d
@@ -19,85 +24,85 @@
#define KEPLER_INLINE_TO_MEMORY_A 0x0000a040
#define KEPLER_INLINE_TO_MEMORY_B 0x0000a140
-#define NV04_DISP 0x00000046
-
-#define NV03_CHANNEL_DMA 0x0000006b
-#define NV10_CHANNEL_DMA 0x0000006e
-#define NV17_CHANNEL_DMA 0x0000176e
-#define NV40_CHANNEL_DMA 0x0000406e
-#define NV50_CHANNEL_DMA 0x0000506e
-#define G82_CHANNEL_DMA 0x0000826e
-
-#define NV50_CHANNEL_GPFIFO 0x0000506f
-#define G82_CHANNEL_GPFIFO 0x0000826f
-#define FERMI_CHANNEL_GPFIFO 0x0000906f
-#define KEPLER_CHANNEL_GPFIFO_A 0x0000a06f
-#define MAXWELL_CHANNEL_GPFIFO_A 0x0000b06f
-
-#define NV50_DISP 0x00005070
-#define G82_DISP 0x00008270
-#define GT200_DISP 0x00008370
-#define GT214_DISP 0x00008570
-#define GT206_DISP 0x00008870
-#define GF110_DISP 0x00009070
-#define GK104_DISP 0x00009170
-#define GK110_DISP 0x00009270
-#define GM107_DISP 0x00009470
-#define GM204_DISP 0x00009570
+#define NV04_DISP /* cl0046.h */ 0x00000046
+
+#define NV03_CHANNEL_DMA /* cl506b.h */ 0x0000006b
+#define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e
+#define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e
+#define NV40_CHANNEL_DMA /* cl506b.h */ 0x0000406e
+#define NV50_CHANNEL_DMA /* cl506e.h */ 0x0000506e
+#define G82_CHANNEL_DMA /* cl826e.h */ 0x0000826e
+
+#define NV50_CHANNEL_GPFIFO /* cl506f.h */ 0x0000506f
+#define G82_CHANNEL_GPFIFO /* cl826f.h */ 0x0000826f
+#define FERMI_CHANNEL_GPFIFO /* cl906f.h */ 0x0000906f
+#define KEPLER_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000a06f
+#define MAXWELL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000b06f
+
+#define NV50_DISP /* cl5070.h */ 0x00005070
+#define G82_DISP /* cl5070.h */ 0x00008270
+#define GT200_DISP /* cl5070.h */ 0x00008370
+#define GT214_DISP /* cl5070.h */ 0x00008570
+#define GT206_DISP /* cl5070.h */ 0x00008870
+#define GF110_DISP /* cl5070.h */ 0x00009070
+#define GK104_DISP /* cl5070.h */ 0x00009170
+#define GK110_DISP /* cl5070.h */ 0x00009270
+#define GM107_DISP /* cl5070.h */ 0x00009470
+#define GM204_DISP /* cl5070.h */ 0x00009570
#define NV31_MPEG 0x00003174
#define G82_MPEG 0x00008274
#define NV74_VP2 0x00007476
-#define NV50_DISP_CURSOR 0x0000507a
-#define G82_DISP_CURSOR 0x0000827a
-#define GT214_DISP_CURSOR 0x0000857a
-#define GF110_DISP_CURSOR 0x0000907a
-#define GK104_DISP_CURSOR 0x0000917a
-
-#define NV50_DISP_OVERLAY 0x0000507b
-#define G82_DISP_OVERLAY 0x0000827b
-#define GT214_DISP_OVERLAY 0x0000857b
-#define GF110_DISP_OVERLAY 0x0000907b
-#define GK104_DISP_OVERLAY 0x0000917b
-
-#define NV50_DISP_BASE_CHANNEL_DMA 0x0000507c
-#define G82_DISP_BASE_CHANNEL_DMA 0x0000827c
-#define GT200_DISP_BASE_CHANNEL_DMA 0x0000837c
-#define GT214_DISP_BASE_CHANNEL_DMA 0x0000857c
-#define GF110_DISP_BASE_CHANNEL_DMA 0x0000907c
-#define GK104_DISP_BASE_CHANNEL_DMA 0x0000917c
-#define GK110_DISP_BASE_CHANNEL_DMA 0x0000927c
-
-#define NV50_DISP_CORE_CHANNEL_DMA 0x0000507d
-#define G82_DISP_CORE_CHANNEL_DMA 0x0000827d
-#define GT200_DISP_CORE_CHANNEL_DMA 0x0000837d
-#define GT214_DISP_CORE_CHANNEL_DMA 0x0000857d
-#define GT206_DISP_CORE_CHANNEL_DMA 0x0000887d
-#define GF110_DISP_CORE_CHANNEL_DMA 0x0000907d
-#define GK104_DISP_CORE_CHANNEL_DMA 0x0000917d
-#define GK110_DISP_CORE_CHANNEL_DMA 0x0000927d
-#define GM107_DISP_CORE_CHANNEL_DMA 0x0000947d
-#define GM204_DISP_CORE_CHANNEL_DMA 0x0000957d
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA 0x0000507e
-#define G82_DISP_OVERLAY_CHANNEL_DMA 0x0000827e
-#define GT200_DISP_OVERLAY_CHANNEL_DMA 0x0000837e
-#define GT214_DISP_OVERLAY_CHANNEL_DMA 0x0000857e
-#define GF110_DISP_OVERLAY_CONTROL_DMA 0x0000907e
-#define GK104_DISP_OVERLAY_CONTROL_DMA 0x0000917e
-
-#define FERMI_A 0x00009097
-#define FERMI_B 0x00009197
-#define FERMI_C 0x00009297
-
-#define KEPLER_A 0x0000a097
-#define KEPLER_B 0x0000a197
-#define KEPLER_C 0x0000a297
-
-#define MAXWELL_A 0x0000b097
-#define MAXWELL_B 0x0000b197
+#define NV50_DISP_CURSOR /* cl507a.h */ 0x0000507a
+#define G82_DISP_CURSOR /* cl507a.h */ 0x0000827a
+#define GT214_DISP_CURSOR /* cl507a.h */ 0x0000857a
+#define GF110_DISP_CURSOR /* cl507a.h */ 0x0000907a
+#define GK104_DISP_CURSOR /* cl507a.h */ 0x0000917a
+
+#define NV50_DISP_OVERLAY /* cl507b.h */ 0x0000507b
+#define G82_DISP_OVERLAY /* cl507b.h */ 0x0000827b
+#define GT214_DISP_OVERLAY /* cl507b.h */ 0x0000857b
+#define GF110_DISP_OVERLAY /* cl507b.h */ 0x0000907b
+#define GK104_DISP_OVERLAY /* cl507b.h */ 0x0000917b
+
+#define NV50_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000507c
+#define G82_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000827c
+#define GT200_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000837c
+#define GT214_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000857c
+#define GF110_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000907c
+#define GK104_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000917c
+#define GK110_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000927c
+
+#define NV50_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000507d
+#define G82_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000827d
+#define GT200_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000837d
+#define GT214_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000857d
+#define GT206_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000887d
+#define GF110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000907d
+#define GK104_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000917d
+#define GK110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000927d
+#define GM107_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000947d
+#define GM204_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000957d
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e
+#define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e
+#define GT200_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000837e
+#define GT214_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000857e
+#define GF110_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000907e
+#define GK104_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000917e
+
+#define FERMI_A /* cl9097.h */ 0x00009097
+#define FERMI_B /* cl9097.h */ 0x00009197
+#define FERMI_C /* cl9097.h */ 0x00009297
+
+#define KEPLER_A /* cl9097.h */ 0x0000a097
+#define KEPLER_B /* cl9097.h */ 0x0000a197
+#define KEPLER_C /* cl9097.h */ 0x0000a297
+
+#define MAXWELL_A /* cl9097.h */ 0x0000b097
+#define MAXWELL_B /* cl9097.h */ 0x0000b197
#define NV74_BSP 0x000074b0
@@ -133,540 +138,4 @@
#define MAXWELL_COMPUTE_B 0x0000b1c0
#define NV74_CIPHER 0x000074c1
-
-/*******************************************************************************
- * client
- ******************************************************************************/
-
-#define NV_CLIENT_DEVLIST 0x00
-
-struct nv_client_devlist_v0 {
- __u8 version;
- __u8 count;
- __u8 pad02[6];
- __u64 device[];
-};
-
-
-/*******************************************************************************
- * device
- ******************************************************************************/
-
-struct nv_device_v0 {
- __u8 version;
- __u8 pad01[7];
- __u64 device; /* device identifier, ~0 for client default */
-};
-
-#define NV_DEVICE_V0_INFO 0x00
-#define NV_DEVICE_V0_TIME 0x01
-
-struct nv_device_info_v0 {
- __u8 version;
-#define NV_DEVICE_INFO_V0_IGP 0x00
-#define NV_DEVICE_INFO_V0_PCI 0x01
-#define NV_DEVICE_INFO_V0_AGP 0x02
-#define NV_DEVICE_INFO_V0_PCIE 0x03
-#define NV_DEVICE_INFO_V0_SOC 0x04
- __u8 platform;
- __u16 chipset; /* from NV_PMC_BOOT_0 */
- __u8 revision; /* from NV_PMC_BOOT_0 */
-#define NV_DEVICE_INFO_V0_TNT 0x01
-#define NV_DEVICE_INFO_V0_CELSIUS 0x02
-#define NV_DEVICE_INFO_V0_KELVIN 0x03
-#define NV_DEVICE_INFO_V0_RANKINE 0x04
-#define NV_DEVICE_INFO_V0_CURIE 0x05
-#define NV_DEVICE_INFO_V0_TESLA 0x06
-#define NV_DEVICE_INFO_V0_FERMI 0x07
-#define NV_DEVICE_INFO_V0_KEPLER 0x08
-#define NV_DEVICE_INFO_V0_MAXWELL 0x09
- __u8 family;
- __u8 pad06[2];
- __u64 ram_size;
- __u64 ram_user;
- char chip[16];
- char name[64];
-};
-
-struct nv_device_time_v0 {
- __u8 version;
- __u8 pad01[7];
- __u64 time;
-};
-
-
-/*******************************************************************************
- * context dma
- ******************************************************************************/
-
-struct nv_dma_v0 {
- __u8 version;
-#define NV_DMA_V0_TARGET_VM 0x00
-#define NV_DMA_V0_TARGET_VRAM 0x01
-#define NV_DMA_V0_TARGET_PCI 0x02
-#define NV_DMA_V0_TARGET_PCI_US 0x03
-#define NV_DMA_V0_TARGET_AGP 0x04
- __u8 target;
-#define NV_DMA_V0_ACCESS_VM 0x00
-#define NV_DMA_V0_ACCESS_RD 0x01
-#define NV_DMA_V0_ACCESS_WR 0x02
-#define NV_DMA_V0_ACCESS_RDWR (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
- __u8 access;
- __u8 pad03[5];
- __u64 start;
- __u64 limit;
- /* ... chipset-specific class data */
-};
-
-struct nv50_dma_v0 {
- __u8 version;
-#define NV50_DMA_V0_PRIV_VM 0x00
-#define NV50_DMA_V0_PRIV_US 0x01
-#define NV50_DMA_V0_PRIV__S 0x02
- __u8 priv;
-#define NV50_DMA_V0_PART_VM 0x00
-#define NV50_DMA_V0_PART_256 0x01
-#define NV50_DMA_V0_PART_1KB 0x02
- __u8 part;
-#define NV50_DMA_V0_COMP_NONE 0x00
-#define NV50_DMA_V0_COMP_1 0x01
-#define NV50_DMA_V0_COMP_2 0x02
-#define NV50_DMA_V0_COMP_VM 0x03
- __u8 comp;
-#define NV50_DMA_V0_KIND_PITCH 0x00
-#define NV50_DMA_V0_KIND_VM 0x7f
- __u8 kind;
- __u8 pad05[3];
-};
-
-struct gf100_dma_v0 {
- __u8 version;
-#define GF100_DMA_V0_PRIV_VM 0x00
-#define GF100_DMA_V0_PRIV_US 0x01
-#define GF100_DMA_V0_PRIV__S 0x02
- __u8 priv;
-#define GF100_DMA_V0_KIND_PITCH 0x00
-#define GF100_DMA_V0_KIND_VM 0xff
- __u8 kind;
- __u8 pad03[5];
-};
-
-struct gf119_dma_v0 {
- __u8 version;
-#define GF119_DMA_V0_PAGE_LP 0x00
-#define GF119_DMA_V0_PAGE_SP 0x01
- __u8 page;
-#define GF119_DMA_V0_KIND_PITCH 0x00
-#define GF119_DMA_V0_KIND_VM 0xff
- __u8 kind;
- __u8 pad03[5];
-};
-
-
-/*******************************************************************************
- * perfmon
- ******************************************************************************/
-
-#define NVIF_PERFMON_V0_QUERY_DOMAIN 0x00
-#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x01
-#define NVIF_PERFMON_V0_QUERY_SOURCE 0x02
-
-struct nvif_perfmon_query_domain_v0 {
- __u8 version;
- __u8 id;
- __u8 counter_nr;
- __u8 iter;
- __u16 signal_nr;
- __u8 pad05[2];
- char name[64];
-};
-
-struct nvif_perfmon_query_signal_v0 {
- __u8 version;
- __u8 domain;
- __u16 iter;
- __u8 signal;
- __u8 source_nr;
- __u8 pad05[2];
- char name[64];
-};
-
-struct nvif_perfmon_query_source_v0 {
- __u8 version;
- __u8 domain;
- __u8 signal;
- __u8 iter;
- __u8 pad04[4];
- __u32 source;
- __u32 mask;
- char name[64];
-};
-
-
-/*******************************************************************************
- * perfdom
- ******************************************************************************/
-
-struct nvif_perfdom_v0 {
- __u8 version;
- __u8 domain;
- __u8 mode;
- __u8 pad03[1];
- struct {
- __u8 signal[4];
- __u64 source[4][8];
- __u16 logic_op;
- } ctr[4];
-};
-
-#define NVIF_PERFDOM_V0_INIT 0x00
-#define NVIF_PERFDOM_V0_SAMPLE 0x01
-#define NVIF_PERFDOM_V0_READ 0x02
-
-struct nvif_perfdom_init {
-};
-
-struct nvif_perfdom_sample {
-};
-
-struct nvif_perfdom_read_v0 {
- __u8 version;
- __u8 pad01[7];
- __u32 ctr[4];
- __u32 clk;
- __u8 pad04[4];
-};
-
-
-/*******************************************************************************
- * device control
- ******************************************************************************/
-
-#define NVIF_CONTROL_PSTATE_INFO 0x00
-#define NVIF_CONTROL_PSTATE_ATTR 0x01
-#define NVIF_CONTROL_PSTATE_USER 0x02
-
-struct nvif_control_pstate_info_v0 {
- __u8 version;
- __u8 count; /* out: number of power states */
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON (-2)
- __s8 ustate_ac; /* out: target pstate index */
- __s8 ustate_dc; /* out: target pstate index */
- __s8 pwrsrc; /* out: current power source */
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON (-2)
- __s8 pstate; /* out: current pstate index */
- __u8 pad06[2];
-};
-
-struct nvif_control_pstate_attr_v0 {
- __u8 version;
-#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT (-1)
- __s8 state; /* in: index of pstate to query
- * out: pstate identifier
- */
- __u8 index; /* in: index of attribute to query
- * out: index of next attribute, or 0 if no more
- */
- __u8 pad03[5];
- __u32 min;
- __u32 max;
- char name[32];
- char unit[16];
-};
-
-struct nvif_control_pstate_user_v0 {
- __u8 version;
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN (-1)
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON (-2)
- __s8 ustate; /* in: pstate identifier */
- __s8 pwrsrc; /* in: target power source */
- __u8 pad03[5];
-};
-
-
-/*******************************************************************************
- * DMA FIFO channels
- ******************************************************************************/
-
-struct nv03_channel_dma_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 offset;
- __u64 pushbuf;
-};
-
-struct nv50_channel_dma_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[6];
- __u64 vm;
- __u64 pushbuf;
- __u64 offset;
-};
-
-#define G82_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/*******************************************************************************
- * GPFIFO channels
- ******************************************************************************/
-
-struct nv50_channel_gpfifo_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 ilength;
- __u64 ioffset;
- __u64 pushbuf;
- __u64 vm;
-};
-
-struct fermi_channel_gpfifo_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 ilength;
- __u64 ioffset;
- __u64 vm;
-};
-
-struct kepler_channel_gpfifo_a_v0 {
- __u8 version;
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR 0x01
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPDEC 0x02
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPPP 0x04
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSVLD 0x08
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0 0x10
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1 0x20
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40
- __u8 engine;
- __u16 chid;
- __u32 ilength;
- __u64 ioffset;
- __u64 vm;
-};
-
-/*******************************************************************************
- * legacy display
- ******************************************************************************/
-
-#define NV04_DISP_NTFY_VBLANK 0x00
-#define NV04_DISP_NTFY_CONN 0x01
-
-struct nv04_disp_mthd_v0 {
- __u8 version;
-#define NV04_DISP_SCANOUTPOS 0x00
- __u8 method;
- __u8 head;
- __u8 pad03[5];
-};
-
-struct nv04_disp_scanoutpos_v0 {
- __u8 version;
- __u8 pad01[7];
- __s64 time[2];
- __u16 vblanks;
- __u16 vblanke;
- __u16 vtotal;
- __u16 vline;
- __u16 hblanks;
- __u16 hblanke;
- __u16 htotal;
- __u16 hline;
-};
-
-/*******************************************************************************
- * display
- ******************************************************************************/
-
-#define NV50_DISP_MTHD 0x00
-
-struct nv50_disp_mthd_v0 {
- __u8 version;
-#define NV50_DISP_SCANOUTPOS 0x00
- __u8 method;
- __u8 head;
- __u8 pad03[5];
-};
-
-struct nv50_disp_mthd_v1 {
- __u8 version;
-#define NV50_DISP_MTHD_V1_DAC_PWR 0x10
-#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
-#define NV50_DISP_MTHD_V1_SOR_PWR 0x20
-#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
-#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
-#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
-#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24
-#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
- __u8 method;
- __u16 hasht;
- __u16 hashm;
- __u8 pad06[2];
-};
-
-struct nv50_disp_dac_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 data;
- __u8 vsync;
- __u8 hsync;
- __u8 pad05[3];
-};
-
-struct nv50_disp_dac_load_v0 {
- __u8 version;
- __u8 load;
- __u8 pad02[2];
- __u32 data;
-};
-
-struct nv50_disp_sor_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 pad02[6];
-};
-
-struct nv50_disp_sor_hda_eld_v0 {
- __u8 version;
- __u8 pad01[7];
- __u8 data[];
-};
-
-struct nv50_disp_sor_hdmi_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 max_ac_packet;
- __u8 rekey;
- __u8 pad04[4];
-};
-
-struct nv50_disp_sor_lvds_script_v0 {
- __u8 version;
- __u8 pad01[1];
- __u16 script;
- __u8 pad04[4];
-};
-
-struct nv50_disp_sor_dp_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 pad02[6];
-};
-
-struct nv50_disp_pior_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 type;
- __u8 pad03[5];
-};
-
-/* core */
-struct nv50_disp_core_channel_dma_v0 {
- __u8 version;
- __u8 pad01[7];
- __u64 pushbuf;
-};
-
-#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/* cursor immediate */
-struct nv50_disp_cursor_v0 {
- __u8 version;
- __u8 head;
- __u8 pad02[6];
-};
-
-#define NV50_DISP_CURSOR_V0_NTFY_UEVENT 0x00
-
-/* base */
-struct nv50_disp_base_channel_dma_v0 {
- __u8 version;
- __u8 head;
- __u8 pad02[6];
- __u64 pushbuf;
-};
-
-#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/* overlay */
-struct nv50_disp_overlay_channel_dma_v0 {
- __u8 version;
- __u8 head;
- __u8 pad02[6];
- __u64 pushbuf;
-};
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/* overlay immediate */
-struct nv50_disp_overlay_v0 {
- __u8 version;
- __u8 head;
- __u8 pad02[6];
-};
-
-#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00
-
-/*******************************************************************************
- * software
- ******************************************************************************/
-
-#define NVSW_NTFY_UEVENT 0x00
-
-#define NV04_NVSW_GET_REF 0x00
-
-struct nv04_nvsw_get_ref_v0 {
- __u8 version;
- __u8 pad01[3];
- __u32 ref;
-};
-
-/*******************************************************************************
- * fermi
- ******************************************************************************/
-
-#define FERMI_A_ZBC_COLOR 0x00
-#define FERMI_A_ZBC_DEPTH 0x01
-
-struct fermi_a_zbc_color_v0 {
- __u8 version;
-#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO 0x01
-#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE 0x02
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32 0x04
-#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16 0x08
-#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16 0x0c
-#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16 0x10
-#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16 0x14
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16 0x16
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8 0x18
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8 0x1c
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10 0x20
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10 0x24
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8 0x28
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8 0x2c
-#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8 0x30
-#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8 0x34
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8 0x38
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10 0x3c
-#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11 0x40
- __u8 format;
- __u8 index;
- __u8 pad03[5];
- __u32 ds[4];
- __u32 l2[4];
-};
-
-struct fermi_a_zbc_depth_v0 {
- __u8 version;
-#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32 0x01
- __u8 format;
- __u8 index;
- __u8 pad03[5];
- __u32 ds;
- __u32 l2;
-};
-
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h
index 700a9b206726..e0ed2f4b2f43 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/device.h
@@ -2,7 +2,7 @@
#define __NVIF_DEVICE_H__
#include <nvif/object.h>
-#include <nvif/class.h>
+#include <nvif/cl0080.h>
struct nvif_device {
struct nvif_object object;
@@ -63,6 +63,7 @@ u64 nvif_device_time(struct nvif_device *);
#define nvxx_clk(a) nvxx_device(a)->clk
#define nvxx_i2c(a) nvxx_device(a)->i2c
#define nvxx_therm(a) nvxx_device(a)->therm
+#define nvxx_volt(a) nvxx_device(a)->volt
#include <core/device.h>
#include <engine/fifo.h>
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0000.h b/drivers/gpu/drm/nouveau/include/nvif/if0000.h
new file mode 100644
index 000000000000..85c44e8a1201
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0000.h
@@ -0,0 +1,12 @@
+#ifndef __NVIF_IF0000_H__
+#define __NVIF_IF0000_H__
+
+#define NV_CLIENT_DEVLIST 0x00
+
+struct nv_client_devlist_v0 {
+ __u8 version;
+ __u8 count;
+ __u8 pad02[6];
+ __u64 device[];
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0001.h b/drivers/gpu/drm/nouveau/include/nvif/if0001.h
new file mode 100644
index 000000000000..bd5b64125eed
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0001.h
@@ -0,0 +1,46 @@
+#ifndef __NVIF_IF0001_H__
+#define __NVIF_IF0001_H__
+
+#define NVIF_CONTROL_PSTATE_INFO 0x00
+#define NVIF_CONTROL_PSTATE_ATTR 0x01
+#define NVIF_CONTROL_PSTATE_USER 0x02
+
+struct nvif_control_pstate_info_v0 {
+ __u8 version;
+ __u8 count; /* out: number of power states */
+#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE (-1)
+#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON (-2)
+ __s8 ustate_ac; /* out: target pstate index */
+ __s8 ustate_dc; /* out: target pstate index */
+ __s8 pwrsrc; /* out: current power source */
+#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN (-1)
+#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON (-2)
+ __s8 pstate; /* out: current pstate index */
+ __u8 pad06[2];
+};
+
+struct nvif_control_pstate_attr_v0 {
+ __u8 version;
+#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT (-1)
+ __s8 state; /* in: index of pstate to query
+ * out: pstate identifier
+ */
+ __u8 index; /* in: index of attribute to query
+ * out: index of next attribute, or 0 if no more
+ */
+ __u8 pad03[5];
+ __u32 min;
+ __u32 max;
+ char name[32];
+ char unit[16];
+};
+
+struct nvif_control_pstate_user_v0 {
+ __u8 version;
+#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN (-1)
+#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON (-2)
+ __s8 ustate; /* in: pstate identifier */
+ __s8 pwrsrc; /* in: target power source */
+ __u8 pad03[5];
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0002.h b/drivers/gpu/drm/nouveau/include/nvif/if0002.h
new file mode 100644
index 000000000000..c04c91d0b818
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0002.h
@@ -0,0 +1,38 @@
+#ifndef __NVIF_IF0002_H__
+#define __NVIF_IF0002_H__
+
+#define NVIF_PERFMON_V0_QUERY_DOMAIN 0x00
+#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x01
+#define NVIF_PERFMON_V0_QUERY_SOURCE 0x02
+
+struct nvif_perfmon_query_domain_v0 {
+ __u8 version;
+ __u8 id;
+ __u8 counter_nr;
+ __u8 iter;
+ __u16 signal_nr;
+ __u8 pad05[2];
+ char name[64];
+};
+
+struct nvif_perfmon_query_signal_v0 {
+ __u8 version;
+ __u8 domain;
+ __u16 iter;
+ __u8 signal;
+ __u8 source_nr;
+ __u8 pad05[2];
+ char name[64];
+};
+
+struct nvif_perfmon_query_source_v0 {
+ __u8 version;
+ __u8 domain;
+ __u8 signal;
+ __u8 iter;
+ __u8 pad04[4];
+ __u32 source;
+ __u32 mask;
+ char name[64];
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0003.h b/drivers/gpu/drm/nouveau/include/nvif/if0003.h
new file mode 100644
index 000000000000..0cd03efb80a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0003.h
@@ -0,0 +1,33 @@
+#ifndef __NVIF_IF0003_H__
+#define __NVIF_IF0003_H__
+
+struct nvif_perfdom_v0 {
+ __u8 version;
+ __u8 domain;
+ __u8 mode;
+ __u8 pad03[1];
+ struct {
+ __u8 signal[4];
+ __u64 source[4][8];
+ __u16 logic_op;
+ } ctr[4];
+};
+
+#define NVIF_PERFDOM_V0_INIT 0x00
+#define NVIF_PERFDOM_V0_SAMPLE 0x01
+#define NVIF_PERFDOM_V0_READ 0x02
+
+struct nvif_perfdom_init {
+};
+
+struct nvif_perfdom_sample {
+};
+
+struct nvif_perfdom_read_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u32 ctr[4];
+ __u32 clk;
+ __u8 pad04[4];
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0004.h b/drivers/gpu/drm/nouveau/include/nvif/if0004.h
new file mode 100644
index 000000000000..bd5cd428cfd7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0004.h
@@ -0,0 +1,13 @@
+#ifndef __NVIF_IF0004_H__
+#define __NVIF_IF0004_H__
+
+#define NV04_NVSW_NTFY_UEVENT 0x00
+
+#define NV04_NVSW_GET_REF 0x00
+
+struct nv04_nvsw_get_ref_v0 {
+ __u8 version;
+ __u8 pad01[3];
+ __u32 ref;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0005.h b/drivers/gpu/drm/nouveau/include/nvif/if0005.h
new file mode 100644
index 000000000000..abfd373bb68b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0005.h
@@ -0,0 +1,4 @@
+#ifndef __NVIF_IF0005_H__
+#define __NVIF_IF0005_H__
+#define NV10_NVSW_NTFY_UEVENT 0x00
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
index b0ac0215ebf9..c5f5eb83a594 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
@@ -55,14 +55,6 @@ struct nvif_ioctl_new_v0 {
__u64 token;
__u64 object;
__u32 handle;
-/* these class numbers are made up by us, and not nvidia-assigned */
-#define NVIF_IOCTL_NEW_V0_CONTROL -1
-#define NVIF_IOCTL_NEW_V0_PERFMON -2
-#define NVIF_IOCTL_NEW_V0_PERFDOM -3
-#define NVIF_IOCTL_NEW_V0_SW_NV04 -4
-#define NVIF_IOCTL_NEW_V0_SW_NV10 -5
-#define NVIF_IOCTL_NEW_V0_SW_NV50 -6
-#define NVIF_IOCTL_NEW_V0_SW_GF100 -7
__s32 oclass;
__u8 data[]; /* class data (class.h) */
};
diff --git a/drivers/gpu/drm/nouveau/include/nvif/unpack.h b/drivers/gpu/drm/nouveau/include/nvif/unpack.h
index 5933188b4a77..751bcf4930a7 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/unpack.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/unpack.h
@@ -1,24 +1,28 @@
#ifndef __NVIF_UNPACK_H__
#define __NVIF_UNPACK_H__
-#define nvif_unvers(d) ({ \
- ret = (size == sizeof(d)) ? 0 : -ENOSYS; \
- (ret == 0); \
+#define nvif_unvers(r,d,s,m) ({ \
+ void **_data = (d); __u32 *_size = (s); int _ret = (r); \
+ if (_ret == -ENOSYS && *_size == sizeof(m)) { \
+ *_data = NULL; \
+ *_size = _ret = 0; \
+ } \
+ _ret; \
})
-#define nvif_unpack(d,vl,vh,m) ({ \
- if ((vl) == 0 || ret == -ENOSYS) { \
- int _size = sizeof(d); \
- if (_size <= size && (d).version >= (vl) && \
- (d).version <= (vh)) { \
- data = (u8 *)data + _size; \
- size = size - _size; \
- ret = ((m) || !size) ? 0 : -E2BIG; \
- } else { \
- ret = -ENOSYS; \
+#define nvif_unpack(r,d,s,m,vl,vh,x) ({ \
+ void **_data = (d); __u32 *_size = (s); \
+ int _ret = (r), _vl = (vl), _vh = (vh); \
+ if (_ret == -ENOSYS && *_size >= sizeof(m) && \
+ (m).version >= _vl && (m).version <= _vh) { \
+ *_data = (__u8 *)*_data + sizeof(m); \
+ *_size = *_size - sizeof(m); \
+ if (_ret = 0, !(x)) { \
+ _ret = *_size ? -E2BIG : 0; \
+ *_data = NULL; \
+ *_size = 0; \
} \
} \
- (ret == 0); \
+ _ret; \
})
-
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
index 7cc2becabc69..d3bd250103d5 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
@@ -13,6 +13,8 @@ struct nvbios_perfE {
u32 vdec;
u32 disp;
u32 script;
+ u8 pcie_speed;
+ u8 pcie_width;
};
u16 nvbios_perf_entry(struct nvkm_bios *, int idx,
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
index 8708f0a4e188..6b33bc058924 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
@@ -2,6 +2,7 @@
#define __NVKM_CLK_H__
#include <core/subdev.h>
#include <core/notify.h>
+#include <subdev/pci.h>
struct nvbios_pll;
struct nvkm_pll_vals;
@@ -38,7 +39,7 @@ enum nv_clk_src {
nv_clk_src_hubk06,
nv_clk_src_hubk07,
nv_clk_src_copy,
- nv_clk_src_daemon,
+ nv_clk_src_pmu,
nv_clk_src_disp,
nv_clk_src_vdec,
@@ -59,6 +60,8 @@ struct nvkm_pstate {
struct nvkm_cstate base;
u8 pstate;
u8 fanspeed;
+ enum nvkm_pcie_speed pcie_speed;
+ u8 pcie_width;
};
struct nvkm_domain {
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
index c4dcd2680fe1..ea23e24a246c 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
@@ -6,4 +6,5 @@ int gf100_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **);
int gf117_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **);
int gk104_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **);
int gk20a_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **);
+int gm204_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
index 3d4dbbf9aab3..0ffa2ec106d6 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
@@ -37,4 +37,5 @@ int gf100_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **);
int gk104_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **);
int gk20a_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **);
int gm107_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **);
+int gm204_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
index fee0a97c44c5..ddb913889d7e 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
@@ -2,6 +2,12 @@
#define __NVKM_PCI_H__
#include <core/subdev.h>
+enum nvkm_pcie_speed {
+ NVKM_PCIE_SPEED_2_5,
+ NVKM_PCIE_SPEED_5_0,
+ NVKM_PCIE_SPEED_8_0,
+};
+
struct nvkm_pci {
const struct nvkm_pci_func *func;
struct nvkm_subdev subdev;
@@ -18,6 +24,11 @@ struct nvkm_pci {
bool acquired;
} agp;
+ struct {
+ enum nvkm_pcie_speed speed;
+ u8 width;
+ } pcie;
+
bool msi;
};
@@ -34,4 +45,9 @@ int nv4c_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
int g84_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
int g94_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
+int gf106_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
+int gk104_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
+
+/* pcie functions */
+int nvkm_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8 width);
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 7f50cf5f929e..50f52ffe5b0c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -25,6 +25,8 @@
#include <nvif/driver.h>
#include <nvif/ioctl.h>
#include <nvif/class.h>
+#include <nvif/cl0002.h>
+#include <nvif/cla06f.h>
#include <nvif/unpack.h>
#include "nouveau_drm.h"
@@ -87,18 +89,18 @@ nouveau_abi16_swclass(struct nouveau_drm *drm)
{
switch (drm->device.info.family) {
case NV_DEVICE_INFO_V0_TNT:
- return NVIF_IOCTL_NEW_V0_SW_NV04;
+ return NVIF_CLASS_SW_NV04;
case NV_DEVICE_INFO_V0_CELSIUS:
case NV_DEVICE_INFO_V0_KELVIN:
case NV_DEVICE_INFO_V0_RANKINE:
case NV_DEVICE_INFO_V0_CURIE:
- return NVIF_IOCTL_NEW_V0_SW_NV10;
+ return NVIF_CLASS_SW_NV10;
case NV_DEVICE_INFO_V0_TESLA:
- return NVIF_IOCTL_NEW_V0_SW_NV50;
+ return NVIF_CLASS_SW_NV50;
case NV_DEVICE_INFO_V0_FERMI:
case NV_DEVICE_INFO_V0_KEPLER:
case NV_DEVICE_INFO_V0_MAXWELL:
- return NVIF_IOCTL_NEW_V0_SW_GF100;
+ return NVIF_CLASS_SW_GF100;
}
return 0x0000;
@@ -355,9 +357,9 @@ nouveau_abi16_usif(struct drm_file *file_priv, void *data, u32 size)
} *args = data;
struct nouveau_abi16_chan *chan;
struct nouveau_abi16 *abi16;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
switch (args->v0.type) {
case NVIF_IOCTL_V0_NEW:
case NVIF_IOCTL_V0_MTHD:
@@ -433,10 +435,10 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
/* nvsw: compatibility with older 0x*6e class identifier */
for (i = 0; !oclass && i < ret; i++) {
switch (sclass[i].oclass) {
- case NVIF_IOCTL_NEW_V0_SW_NV04:
- case NVIF_IOCTL_NEW_V0_SW_NV10:
- case NVIF_IOCTL_NEW_V0_SW_NV50:
- case NVIF_IOCTL_NEW_V0_SW_GF100:
+ case NVIF_CLASS_SW_NV04:
+ case NVIF_CLASS_SW_NV10:
+ case NVIF_CLASS_SW_NV50:
+ case NVIF_CLASS_SW_GF100:
oclass = sclass[i].oclass;
break;
default:
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 1860f389f21f..3f804a8c590c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -24,6 +24,11 @@
#include <nvif/os.h>
#include <nvif/class.h>
+#include <nvif/cl0002.h>
+#include <nvif/cl006b.h>
+#include <nvif/cl506f.h>
+#include <nvif/cl906f.h>
+#include <nvif/cla06f.h>
#include <nvif/ioctl.h>
/*XXX*/
@@ -378,7 +383,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
/* allocate software object class (used for fences on <= nv05) */
if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
ret = nvif_object_init(&chan->user, 0x006e,
- NVIF_IOCTL_NEW_V0_SW_NV04,
+ NVIF_CLASS_SW_NV04,
NULL, 0, &chan->nvsw);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 2e7cbe933533..fcebfae5d426 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -42,6 +42,8 @@
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
+#include <nvif/class.h>
+#include <nvif/cl0046.h>
#include <nvif/event.h>
MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
@@ -56,6 +58,10 @@ MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
int nouveau_duallink = 1;
module_param_named(duallink, nouveau_duallink, int, 0400);
+MODULE_PARM_DESC(hdmimhz, "Force a maximum HDMI pixel clock (in MHz)");
+int nouveau_hdmimhz = 0;
+module_param_named(hdmimhz, nouveau_hdmimhz, int, 0400);
+
struct nouveau_encoder *
find_encoder(struct drm_connector *connector, int type)
{
@@ -809,12 +815,23 @@ nouveau_connector_get_modes(struct drm_connector *connector)
}
static unsigned
-get_tmds_link_bandwidth(struct drm_connector *connector)
+get_tmds_link_bandwidth(struct drm_connector *connector, bool hdmi)
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_drm *drm = nouveau_drm(connector->dev);
struct dcb_output *dcb = nv_connector->detected_encoder->dcb;
+ if (hdmi) {
+ if (nouveau_hdmimhz > 0)
+ return nouveau_hdmimhz * 1000;
+ /* Note: these limits are conservative, some Fermi's
+ * can do 297 MHz. Unclear how this can be determined.
+ */
+ if (drm->device.info.family >= NV_DEVICE_INFO_V0_KEPLER)
+ return 297000;
+ if (drm->device.info.family >= NV_DEVICE_INFO_V0_FERMI)
+ return 225000;
+ }
if (dcb->location != DCB_LOC_ON_CHIP ||
drm->device.info.chipset >= 0x46)
return 165000;
@@ -835,6 +852,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
unsigned min_clock = 25000, max_clock = min_clock;
unsigned clock = mode->clock;
+ bool hdmi;
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_LVDS:
@@ -847,8 +865,10 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
max_clock = 400000;
break;
case DCB_OUTPUT_TMDS:
- max_clock = get_tmds_link_bandwidth(connector);
- if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
+ hdmi = drm_detect_hdmi_monitor(nv_connector->edid);
+ max_clock = get_tmds_link_bandwidth(connector, hdmi);
+ if (!hdmi && nouveau_duallink &&
+ nv_encoder->dcb->duallink_possible)
max_clock *= 2;
break;
case DCB_OUTPUT_ANALOG:
@@ -898,8 +918,6 @@ nouveau_connector_helper_funcs = {
static const struct drm_connector_funcs
nouveau_connector_funcs = {
.dpms = drm_helper_connector_dpms,
- .save = NULL,
- .restore = NULL,
.detect = nouveau_connector_detect,
.destroy = nouveau_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -910,8 +928,6 @@ nouveau_connector_funcs = {
static const struct drm_connector_funcs
nouveau_connector_funcs_lvds = {
.dpms = drm_helper_connector_dpms,
- .save = NULL,
- .restore = NULL,
.detect = nouveau_connector_detect_lvds,
.destroy = nouveau_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -944,8 +960,6 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
static const struct drm_connector_funcs
nouveau_connector_funcs_dp = {
.dpms = nouveau_connector_dp_dpms,
- .save = NULL,
- .restore = NULL,
.detect = nouveau_connector_detect,
.destroy = nouveau_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -969,10 +983,13 @@ nouveau_connector_hotplug(struct nvif_notify *notify)
NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
+ mutex_lock(&drm->dev->mode_config.mutex);
if (plugged)
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
else
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ mutex_unlock(&drm->dev->mode_config.mutex);
+
drm_helper_hpd_irq_event(connector->dev);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index f19cb1c5fc5a..863f10b8d818 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -73,6 +73,9 @@ struct nouveau_crtc {
int (*set_dither)(struct nouveau_crtc *crtc, bool update);
int (*set_scale)(struct nouveau_crtc *crtc, bool update);
int (*set_color_vibrance)(struct nouveau_crtc *crtc, bool update);
+
+ void (*save)(struct drm_crtc *crtc);
+ void (*restore)(struct drm_crtc *crtc);
};
static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
index 5392e07edfc6..3d0dc199b253 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -28,6 +28,9 @@
* Ben Skeggs <bskeggs@redhat.com>
*/
+#include <linux/debugfs.h>
+#include <nvif/class.h>
+#include <nvif/if0001.h>
#include "nouveau_debugfs.h"
#include "nouveau_drm.h"
@@ -43,22 +46,233 @@ nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
return 0;
}
+static int
+nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct nouveau_debugfs *debugfs = nouveau_debugfs(node->minor->dev);
+ struct nvif_object *ctrl = &debugfs->ctrl;
+ struct nvif_control_pstate_info_v0 info = {};
+ int ret, i;
+
+ if (!debugfs)
+ return -ENODEV;
+
+ ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < info.count + 1; i++) {
+ const s32 state = i < info.count ? i :
+ NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT;
+ struct nvif_control_pstate_attr_v0 attr = {
+ .state = state,
+ .index = 0,
+ };
+
+ ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
+ &attr, sizeof(attr));
+ if (ret)
+ return ret;
+
+ if (i < info.count)
+ seq_printf(m, "%02x:", attr.state);
+ else
+ seq_printf(m, "%s:", info.pwrsrc == 0 ? "DC" :
+ info.pwrsrc == 1 ? "AC" : "--");
+
+ attr.index = 0;
+ do {
+ attr.state = state;
+ ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
+ &attr, sizeof(attr));
+ if (ret)
+ return ret;
+
+ seq_printf(m, " %s %d", attr.name, attr.min);
+ if (attr.min != attr.max)
+ seq_printf(m, "-%d", attr.max);
+ seq_printf(m, " %s", attr.unit);
+ } while (attr.index);
+
+ if (state >= 0) {
+ if (info.ustate_ac == state)
+ seq_printf(m, " AC");
+ if (info.ustate_dc == state)
+ seq_printf(m, " DC");
+ if (info.pstate == state)
+ seq_printf(m, " *");
+ } else {
+ if (info.ustate_ac < -1)
+ seq_printf(m, " AC");
+ if (info.ustate_dc < -1)
+ seq_printf(m, " DC");
+ }
+
+ seq_printf(m, "\n");
+ }
+
+ return 0;
+}
+
+static ssize_t
+nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct nouveau_debugfs *debugfs = nouveau_debugfs(node->minor->dev);
+ struct nvif_object *ctrl = &debugfs->ctrl;
+ struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };
+ char buf[32] = {}, *tmp, *cur = buf;
+ long value, ret;
+
+ if (!debugfs)
+ return -ENODEV;
+
+ if (len >= sizeof(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+
+ if ((tmp = strchr(buf, '\n')))
+ *tmp = '\0';
+
+ if (!strncasecmp(cur, "dc:", 3)) {
+ args.pwrsrc = 0;
+ cur += 3;
+ } else
+ if (!strncasecmp(cur, "ac:", 3)) {
+ args.pwrsrc = 1;
+ cur += 3;
+ }
+
+ if (!strcasecmp(cur, "none"))
+ args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN;
+ else
+ if (!strcasecmp(cur, "auto"))
+ args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON;
+ else {
+ ret = kstrtol(cur, 16, &value);
+ if (ret)
+ return ret;
+ args.ustate = value;
+ }
+
+ ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static int
+nouveau_debugfs_pstate_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, nouveau_debugfs_pstate_get, inode->i_private);
+}
+
+static const struct file_operations nouveau_pstate_fops = {
+ .owner = THIS_MODULE,
+ .open = nouveau_debugfs_pstate_open,
+ .read = seq_read,
+ .write = nouveau_debugfs_pstate_set,
+};
+
static struct drm_info_list nouveau_debugfs_list[] = {
{ "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
};
#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
-int
-nouveau_debugfs_init(struct drm_minor *minor)
+static const struct nouveau_debugfs_files {
+ const char *name;
+ const struct file_operations *fops;
+} nouveau_debugfs_files[] = {
+ {"pstate", &nouveau_pstate_fops},
+};
+
+static int
+nouveau_debugfs_create_file(struct drm_minor *minor,
+ const struct nouveau_debugfs_files *ndf)
{
- drm_debugfs_create_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
- minor->debugfs_root, minor);
+ struct drm_info_node *node;
+
+ node = kmalloc(sizeof(*node), GFP_KERNEL);
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->minor = minor;
+ node->info_ent = (const void *)ndf->fops;
+ node->dent = debugfs_create_file(ndf->name, S_IRUGO | S_IWUSR,
+ minor->debugfs_root, node, ndf->fops);
+ if (!node->dent) {
+ kfree(node);
+ return -ENOMEM;
+ }
+
+ mutex_lock(&minor->debugfs_lock);
+ list_add(&node->list, &minor->debugfs_list);
+ mutex_unlock(&minor->debugfs_lock);
return 0;
}
+int
+nouveau_drm_debugfs_init(struct drm_minor *minor)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
+ ret = nouveau_debugfs_create_file(minor,
+ &nouveau_debugfs_files[i]);
+
+ if (ret)
+ return ret;
+ }
+
+ return drm_debugfs_create_files(nouveau_debugfs_list,
+ NOUVEAU_DEBUGFS_ENTRIES,
+ minor->debugfs_root, minor);
+}
+
void
-nouveau_debugfs_takedown(struct drm_minor *minor)
+nouveau_drm_debugfs_cleanup(struct drm_minor *minor)
{
+ int i;
+
drm_debugfs_remove_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
minor);
+
+ for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
+ drm_debugfs_remove_files((struct drm_info_list *)
+ nouveau_debugfs_files[i].fops,
+ 1, minor);
+ }
+}
+
+int
+nouveau_debugfs_init(struct nouveau_drm *drm)
+{
+ int ret;
+
+ drm->debugfs = kzalloc(sizeof(*drm->debugfs), GFP_KERNEL);
+ if (!drm->debugfs)
+ return -ENOMEM;
+
+ ret = nvif_object_init(&drm->device.object, 0, NVIF_CLASS_CONTROL,
+ NULL, 0, &drm->debugfs->ctrl);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void
+nouveau_debugfs_fini(struct nouveau_drm *drm)
+{
+ if (drm->debugfs && drm->debugfs->ctrl.priv)
+ nvif_object_fini(&drm->debugfs->ctrl);
+
+ kfree(drm->debugfs);
+ drm->debugfs = NULL;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.h b/drivers/gpu/drm/nouveau/nouveau_debugfs.h
index a62af6fb5f99..b8c03ff5bf05 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.h
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.h
@@ -4,16 +4,43 @@
#include <drm/drmP.h>
#if defined(CONFIG_DEBUG_FS)
-extern int nouveau_debugfs_init(struct drm_minor *);
-extern void nouveau_debugfs_takedown(struct drm_minor *);
+
+#include "nouveau_drm.h"
+
+struct nouveau_debugfs {
+ struct nvif_object ctrl;
+};
+
+static inline struct nouveau_debugfs *
+nouveau_debugfs(struct drm_device *dev)
+{
+ return nouveau_drm(dev)->debugfs;
+}
+
+extern int nouveau_drm_debugfs_init(struct drm_minor *);
+extern void nouveau_drm_debugfs_cleanup(struct drm_minor *);
+extern int nouveau_debugfs_init(struct nouveau_drm *);
+extern void nouveau_debugfs_fini(struct nouveau_drm *);
#else
static inline int
-nouveau_debugfs_init(struct drm_minor *minor)
+nouveau_drm_debugfs_init(struct drm_minor *minor)
{
return 0;
}
-static inline void nouveau_debugfs_takedown(struct drm_minor *minor)
+static inline void
+nouveau_drm_debugfs_cleanup(struct drm_minor *minor)
+{
+}
+
+static inline int
+nouveau_debugfs_init(struct nouveau_drm *drm)
+{
+ return 0;
+}
+
+static inline void
+nouveau_debugfs_fini(struct nouveau_drm *drm)
{
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 64c8d932d5f1..24be27d3cd18 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -39,6 +39,7 @@
#include "nouveau_fence.h"
+#include <nvif/cl0046.h>
#include <nvif/event.h>
static int
@@ -246,7 +247,7 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
int
nouveau_framebuffer_init(struct drm_device *dev,
struct nouveau_framebuffer *nv_fb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct nouveau_bo *nvbo)
{
struct nouveau_display *disp = nouveau_display(dev);
@@ -272,7 +273,7 @@ nouveau_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
nouveau_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct nouveau_framebuffer *nouveau_fb;
struct drm_gem_object *gem;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index 856abe0f070d..5a57d8b472c4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -23,7 +23,7 @@ nouveau_framebuffer(struct drm_framebuffer *fb)
}
int nouveau_framebuffer_init(struct drm_device *, struct nouveau_framebuffer *,
- struct drm_mode_fb_cmd2 *, struct nouveau_bo *);
+ const struct drm_mode_fb_cmd2 *, struct nouveau_bo *);
struct nouveau_page_flip_state {
struct list_head head;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 1d3ee5179ab8..2f2f252e3fb6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -37,12 +37,16 @@
#include <core/pci.h>
#include <core/tegra.h>
+#include <nvif/class.h>
+#include <nvif/cl0002.h>
+#include <nvif/cla06f.h>
+#include <nvif/if0004.h>
+
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
#include "nouveau_vga.h"
-#include "nouveau_sysfs.h"
#include "nouveau_hwmon.h"
#include "nouveau_acpi.h"
#include "nouveau_bios.h"
@@ -256,8 +260,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
}
ret = nvif_notify_init(&drm->nvsw, nouveau_flip_complete,
- false, NVSW_NTFY_UEVENT, NULL, 0, 0,
- &drm->flip);
+ false, NV04_NVSW_NTFY_UEVENT,
+ NULL, 0, 0, &drm->flip);
if (ret == 0)
ret = nvif_notify_get(&drm->flip);
if (ret) {
@@ -448,7 +452,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
goto fail_dispinit;
}
- nouveau_sysfs_init(dev);
+ nouveau_debugfs_init(drm);
nouveau_hwmon_init(dev);
nouveau_accel_init(drm);
nouveau_fbcon_init(dev);
@@ -486,7 +490,7 @@ nouveau_drm_unload(struct drm_device *dev)
nouveau_fbcon_fini(dev);
nouveau_accel_fini(drm);
nouveau_hwmon_fini(dev);
- nouveau_sysfs_fini(dev);
+ nouveau_debugfs_fini(drm);
if (dev->mode_config.num_crtc)
nouveau_display_fini(dev);
@@ -928,8 +932,8 @@ driver_stub = {
.lastclose = nouveau_vga_lastclose,
#if defined(CONFIG_DEBUG_FS)
- .debugfs_init = nouveau_debugfs_init,
- .debugfs_cleanup = nouveau_debugfs_takedown,
+ .debugfs_init = nouveau_drm_debugfs_init,
+ .debugfs_cleanup = nouveau_drm_debugfs_cleanup,
#endif
.get_vblank_counter = drm_vblank_no_hw_counter,
@@ -1003,7 +1007,6 @@ static void nouveau_display_options(void)
DRM_DEBUG_DRIVER("... modeset : %d\n", nouveau_modeset);
DRM_DEBUG_DRIVER("... runpm : %d\n", nouveau_runtime_pm);
DRM_DEBUG_DRIVER("... vram_pushbuf : %d\n", nouveau_vram_pushbuf);
- DRM_DEBUG_DRIVER("... pstate : %d\n", nouveau_pstate);
}
static const struct dev_pm_ops nouveau_pm_ops = {
@@ -1046,10 +1049,6 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,
goto err_free;
}
- err = drm_dev_set_unique(drm, "%s", dev_name(&pdev->dev));
- if (err < 0)
- goto err_free;
-
drm->platformdev = pdev;
platform_set_drvdata(pdev, drm);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index a02813e994ec..5c363ed1c842 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -164,7 +164,7 @@ struct nouveau_drm {
/* power management */
struct nouveau_hwmon *hwmon;
- struct nouveau_sysfs *sysfs;
+ struct nouveau_debugfs *debugfs;
/* display power reference */
bool have_disp_power_ref;
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index b37da95105b0..ee6a6d3fc80f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -63,6 +63,9 @@ struct nouveau_encoder {
u32 datarate;
} dp;
};
+
+ void (*enc_save)(struct drm_encoder *encoder);
+ void (*enc_restore)(struct drm_encoder *encoder);
};
struct nouveau_encoder *
@@ -80,7 +83,7 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
return &enc->base.base;
}
-static inline struct drm_encoder_slave_funcs *
+static inline const struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 1e2e9e27a03b..ca77ad001978 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -34,7 +34,6 @@
struct nouveau_fbdev {
struct drm_fb_helper helper;
struct nouveau_framebuffer nouveau_fb;
- struct list_head fbdev_list;
struct drm_device *dev;
unsigned int saved_flags;
struct nvif_object surf2d;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 574c36b492ee..9a8c5b727f59 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -30,6 +30,7 @@
#include <linux/hrtimer.h>
#include <trace/events/fence.h>
+#include <nvif/cl826e.h>
#include <nvif/notify.h>
#include <nvif/event.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
index 491c7149d197..8e13467d0ddb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
@@ -34,6 +34,8 @@
#include "nouveau_drm.h"
#include "nouveau_hwmon.h"
+#include <nvkm/subdev/volt.h>
+
#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
static ssize_t
nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
@@ -512,6 +514,35 @@ static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR,
nouveau_hwmon_get_pwm1_max,
nouveau_hwmon_set_pwm1_max, 0);
+static ssize_t
+nouveau_hwmon_get_in0_input(struct device *d,
+ struct device_attribute *a, char *buf)
+{
+ struct drm_device *dev = dev_get_drvdata(d);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvkm_volt *volt = nvxx_volt(&drm->device);
+ int ret;
+
+ ret = nvkm_volt_get(volt);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", ret / 1000);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO,
+ nouveau_hwmon_get_in0_input, NULL, 0);
+
+static ssize_t
+nouveau_hwmon_get_in0_label(struct device *d,
+ struct device_attribute *a, char *buf)
+{
+ return sprintf(buf, "GPU core\n");
+}
+
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO,
+ nouveau_hwmon_get_in0_label, NULL, 0);
+
static struct attribute *hwmon_default_attributes[] = {
&sensor_dev_attr_name.dev_attr.attr,
&sensor_dev_attr_update_rate.dev_attr.attr,
@@ -542,6 +573,12 @@ static struct attribute *hwmon_pwm_fan_attributes[] = {
NULL
};
+static struct attribute *hwmon_in0_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_label.dev_attr.attr,
+ NULL
+};
+
static const struct attribute_group hwmon_default_attrgroup = {
.attrs = hwmon_default_attributes,
};
@@ -554,6 +591,9 @@ static const struct attribute_group hwmon_fan_rpm_attrgroup = {
static const struct attribute_group hwmon_pwm_fan_attrgroup = {
.attrs = hwmon_pwm_fan_attributes,
};
+static const struct attribute_group hwmon_in0_attrgroup = {
+ .attrs = hwmon_in0_attributes,
+};
#endif
int
@@ -562,6 +602,7 @@ nouveau_hwmon_init(struct drm_device *dev)
#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvkm_therm *therm = nvxx_therm(&drm->device);
+ struct nvkm_volt *volt = nvxx_volt(&drm->device);
struct nouveau_hwmon *hwmon;
struct device *hwmon_dev;
int ret = 0;
@@ -613,6 +654,14 @@ nouveau_hwmon_init(struct drm_device *dev)
goto error;
}
+ if (volt && nvkm_volt_get(volt) >= 0) {
+ ret = sysfs_create_group(&hwmon_dev->kobj,
+ &hwmon_in0_attrgroup);
+
+ if (ret)
+ goto error;
+ }
+
hwmon->hwmon = hwmon_dev;
return 0;
@@ -638,6 +687,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup);
sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup);
sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup);
+ sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_in0_attrgroup);
hwmon_device_unregister(hwmon->hwmon);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c
index 60e32c4e4e49..8a70cec59bcd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_platform.c
+++ b/drivers/gpu/drm/nouveau/nouveau_platform.c
@@ -78,3 +78,14 @@ struct platform_driver nouveau_platform_driver = {
.probe = nouveau_platform_probe,
.remove = nouveau_platform_remove,
};
+
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) || IS_ENABLED(CONFIG_ARCH_TEGRA_132_SOC)
+MODULE_FIRMWARE("nvidia/gk20a/fecs_data.bin");
+MODULE_FIRMWARE("nvidia/gk20a/fecs_inst.bin");
+MODULE_FIRMWARE("nvidia/gk20a/gpccs_data.bin");
+MODULE_FIRMWARE("nvidia/gk20a/gpccs_inst.bin");
+MODULE_FIRMWARE("nvidia/gk20a/sw_bundle_init.bin");
+MODULE_FIRMWARE("nvidia/gk20a/sw_ctx.bin");
+MODULE_FIRMWARE("nvidia/gk20a/sw_method_init.bin");
+MODULE_FIRMWARE("nvidia/gk20a/sw_nonctx.bin");
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c
deleted file mode 100644
index 5dac3546c1b8..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <nvif/os.h>
-#include <nvif/class.h>
-#include <nvif/ioctl.h>
-
-#include "nouveau_sysfs.h"
-
-MODULE_PARM_DESC(pstate, "enable sysfs pstate file, which will be moved in the future");
-int nouveau_pstate;
-module_param_named(pstate, nouveau_pstate, int, 0400);
-
-static inline struct drm_device *
-drm_device(struct device *d)
-{
- return dev_get_drvdata(d);
-}
-
-#define snappendf(p,r,f,a...) do { \
- snprintf(p, r, f, ##a); \
- r -= strlen(p); \
- p += strlen(p); \
-} while(0)
-
-static ssize_t
-nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b)
-{
- struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
- struct nvif_control_pstate_info_v0 info = {};
- size_t cnt = PAGE_SIZE;
- char *buf = b;
- int ret, i;
-
- ret = nvif_mthd(&sysfs->ctrl, NVIF_CONTROL_PSTATE_INFO,
- &info, sizeof(info));
- if (ret)
- return ret;
-
- for (i = 0; i < info.count + 1; i++) {
- const s32 state = i < info.count ? i :
- NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT;
- struct nvif_control_pstate_attr_v0 attr = {
- .state = state,
- .index = 0,
- };
-
- ret = nvif_mthd(&sysfs->ctrl, NVIF_CONTROL_PSTATE_ATTR,
- &attr, sizeof(attr));
- if (ret)
- return ret;
-
- if (i < info.count)
- snappendf(buf, cnt, "%02x:", attr.state);
- else
- snappendf(buf, cnt, "%s:", info.pwrsrc == 0 ? "DC" :
- info.pwrsrc == 1 ? "AC" :
- "--");
-
- attr.index = 0;
- do {
- attr.state = state;
- ret = nvif_mthd(&sysfs->ctrl,
- NVIF_CONTROL_PSTATE_ATTR,
- &attr, sizeof(attr));
- if (ret)
- return ret;
-
- snappendf(buf, cnt, " %s %d", attr.name, attr.min);
- if (attr.min != attr.max)
- snappendf(buf, cnt, "-%d", attr.max);
- snappendf(buf, cnt, " %s", attr.unit);
- } while (attr.index);
-
- if (state >= 0) {
- if (info.ustate_ac == state)
- snappendf(buf, cnt, " AC");
- if (info.ustate_dc == state)
- snappendf(buf, cnt, " DC");
- if (info.pstate == state)
- snappendf(buf, cnt, " *");
- } else {
- if (info.ustate_ac < -1)
- snappendf(buf, cnt, " AC");
- if (info.ustate_dc < -1)
- snappendf(buf, cnt, " DC");
- }
-
- snappendf(buf, cnt, "\n");
- }
-
- return strlen(b);
-}
-
-static ssize_t
-nouveau_sysfs_pstate_set(struct device *d, struct device_attribute *a,
- const char *buf, size_t count)
-{
- struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
- struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };
- long value, ret;
- char *tmp;
-
- if ((tmp = strchr(buf, '\n')))
- *tmp = '\0';
-
- if (!strncasecmp(buf, "dc:", 3)) {
- args.pwrsrc = 0;
- buf += 3;
- } else
- if (!strncasecmp(buf, "ac:", 3)) {
- args.pwrsrc = 1;
- buf += 3;
- }
-
- if (!strcasecmp(buf, "none"))
- args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN;
- else
- if (!strcasecmp(buf, "auto"))
- args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON;
- else {
- ret = kstrtol(buf, 16, &value);
- if (ret)
- return ret;
- args.ustate = value;
- }
-
- ret = nvif_mthd(&sysfs->ctrl, NVIF_CONTROL_PSTATE_USER,
- &args, sizeof(args));
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static DEVICE_ATTR(pstate, S_IRUGO | S_IWUSR,
- nouveau_sysfs_pstate_get, nouveau_sysfs_pstate_set);
-
-void
-nouveau_sysfs_fini(struct drm_device *dev)
-{
- struct nouveau_sysfs *sysfs = nouveau_sysfs(dev);
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvif_device *device = &drm->device;
-
- if (sysfs && sysfs->ctrl.priv) {
- device_remove_file(nvxx_device(device)->dev, &dev_attr_pstate);
- nvif_object_fini(&sysfs->ctrl);
- }
-
- drm->sysfs = NULL;
- kfree(sysfs);
-}
-
-int
-nouveau_sysfs_init(struct drm_device *dev)
-{
- struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvif_device *device = &drm->device;
- struct nouveau_sysfs *sysfs;
- int ret;
-
- if (!nouveau_pstate)
- return 0;
-
- sysfs = drm->sysfs = kzalloc(sizeof(*sysfs), GFP_KERNEL);
- if (!sysfs)
- return -ENOMEM;
-
- ret = nvif_object_init(&device->object, 0, NVIF_IOCTL_NEW_V0_CONTROL,
- NULL, 0, &sysfs->ctrl);
- if (ret == 0)
- device_create_file(nvxx_device(device)->dev, &dev_attr_pstate);
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.h b/drivers/gpu/drm/nouveau/nouveau_sysfs.h
deleted file mode 100644
index 4e5ea9241b28..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_sysfs.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __NOUVEAU_SYSFS_H__
-#define __NOUVEAU_SYSFS_H__
-
-#include "nouveau_drm.h"
-
-struct nouveau_sysfs {
- struct nvif_object ctrl;
-};
-
-static inline struct nouveau_sysfs *
-nouveau_sysfs(struct drm_device *dev)
-{
- return nouveau_drm(dev)->sysfs;
-}
-
-int nouveau_sysfs_init(struct drm_device *);
-void nouveau_sysfs_fini(struct drm_device *);
-
-extern int nouveau_pstate;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c
index 6ae1b3494bcd..e9f52ef0be83 100644
--- a/drivers/gpu/drm/nouveau/nouveau_usif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_usif.c
@@ -130,20 +130,21 @@ usif_notify_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
struct nvif_notify_req_v0 v0;
} *req;
struct usif_notify *ntfy;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
if (usif_notify_find(f, args->v0.index))
return -EEXIST;
} else
return ret;
req = data;
+ ret = -ENOSYS;
if (!(ntfy = kmalloc(sizeof(*ntfy), GFP_KERNEL)))
return -ENOMEM;
atomic_set(&ntfy->enabled, 0);
- if (nvif_unpack(req->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, true))) {
ntfy->reply = sizeof(struct nvif_notify_rep_v0) + req->v0.reply;
ntfy->route = req->v0.route;
ntfy->token = req->v0.token;
@@ -171,9 +172,9 @@ usif_notify_del(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
struct nvif_ioctl_ntfy_del_v0 v0;
} *args = data;
struct usif_notify *ntfy;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
if (!(ntfy = usif_notify_find(f, args->v0.index)))
return -ENOENT;
} else
@@ -194,9 +195,9 @@ usif_notify_get(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
struct nvif_ioctl_ntfy_del_v0 v0;
} *args = data;
struct usif_notify *ntfy;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
if (!(ntfy = usif_notify_find(f, args->v0.index)))
return -ENOENT;
} else
@@ -233,9 +234,9 @@ usif_notify_put(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
struct nvif_ioctl_ntfy_put_v0 v0;
} *args = data;
struct usif_notify *ntfy;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
if (!(ntfy = usif_notify_find(f, args->v0.index)))
return -ENOENT;
} else
@@ -270,13 +271,13 @@ usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
struct nvif_ioctl_new_v0 v0;
} *args = data;
struct usif_object *object;
- int ret;
+ int ret = -ENOSYS;
if (!(object = kmalloc(sizeof(*object), GFP_KERNEL)))
return -ENOMEM;
list_add(&object->head, &cli->objects);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
object->route = args->v0.route;
object->token = args->v0.token;
args->v0.route = NVDRM_OBJECT_USIF;
@@ -310,7 +311,7 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
if (ret = -EFAULT, copy_from_user(argv, user, size))
goto done;
- if (nvif_unpack(argv->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(-ENOSYS, &data, &size, argv->v0, 0, 0, true))) {
/* block access to objects not created via this interface */
owner = argv->v0.owner;
if (argv->v0.object == 0ULL)
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c
index f3d705d67738..3022d24ed88b 100644
--- a/drivers/gpu/drm/nouveau/nv04_fence.c
+++ b/drivers/gpu/drm/nouveau/nv04_fence.c
@@ -26,6 +26,8 @@
#include "nouveau_dma.h"
#include "nouveau_fence.h"
+#include <nvif/if0004.h>
+
struct nv04_fence_chan {
struct nouveau_fence_chan base;
};
diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c
index 80b6eb8b3d02..6a141c9bf5b7 100644
--- a/drivers/gpu/drm/nouveau/nv17_fence.c
+++ b/drivers/gpu/drm/nouveau/nv17_fence.c
@@ -24,6 +24,7 @@
#include <nvif/os.h>
#include <nvif/class.h>
+#include <nvif/cl0002.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index c053c50b346a..ea3921652449 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -28,8 +28,16 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_dp_helper.h>
+#include <drm/drm_fb_helper.h>
#include <nvif/class.h>
+#include <nvif/cl0002.h>
+#include <nvif/cl5070.h>
+#include <nvif/cl507a.h>
+#include <nvif/cl507b.h>
+#include <nvif/cl507c.h>
+#include <nvif/cl507d.h>
+#include <nvif/cl507e.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
@@ -773,7 +781,6 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
*/
if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
(nv_connector->underscan == UNDERSCAN_AUTO &&
- nv_connector->edid &&
drm_detect_hdmi_monitor(nv_connector->edid)))) {
u32 bX = nv_connector->underscan_hborder;
u32 bY = nv_connector->underscan_vborder;
@@ -1717,7 +1724,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
encoder = to_drm_encoder(nv_encoder);
encoder->possible_crtcs = dcbe->heads;
encoder->possible_clones = 0;
- drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type);
+ drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, NULL);
drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
drm_mode_connector_attach_encoder(connector, encoder);
@@ -1961,10 +1968,17 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
if (nv_encoder->dcb->sorconf.link & 1) {
- if (mode->clock < 165000)
- proto = 0x1;
- else
- proto = 0x5;
+ proto = 0x1;
+ /* Only enable dual-link if:
+ * - Need to (i.e. rate > 165MHz)
+ * - DCB says we can
+ * - Not an HDMI monitor, since there's no dual-link
+ * on HDMI.
+ */
+ if (mode->clock >= 165000 &&
+ nv_encoder->dcb->duallink_possible &&
+ !drm_detect_hdmi_monitor(nv_connector->edid))
+ proto |= 0x4;
} else {
proto = 0x2;
}
@@ -2125,7 +2139,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
encoder = to_drm_encoder(nv_encoder);
encoder->possible_crtcs = dcbe->heads;
encoder->possible_clones = 0;
- drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type);
+ drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, NULL);
drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
drm_mode_connector_attach_encoder(connector, encoder);
@@ -2305,7 +2319,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
encoder = to_drm_encoder(nv_encoder);
encoder->possible_crtcs = dcbe->heads;
encoder->possible_clones = 0;
- drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type);
+ drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, NULL);
drm_encoder_helper_add(encoder, &nv50_pior_hfunc);
drm_mode_connector_attach_encoder(connector, encoder);
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c
index f0d96e5da6b4..3695ccce68c7 100644
--- a/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -24,6 +24,7 @@
#include <nvif/os.h>
#include <nvif/class.h>
+#include <nvif/cl0002.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c
index 297e1e953fa6..e1943910858e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/client.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c
@@ -28,6 +28,7 @@
#include <nvif/class.h>
#include <nvif/event.h>
+#include <nvif/if0000.h>
#include <nvif/unpack.h>
struct nvkm_client_notify {
@@ -96,7 +97,7 @@ nvkm_client_notify_new(struct nvkm_object *object,
struct nvif_notify_req_v0 v0;
} *req = data;
u8 index, reply;
- int ret;
+ int ret = -ENOSYS;
for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
if (!client->notify[index])
@@ -111,7 +112,7 @@ nvkm_client_notify_new(struct nvkm_object *object,
return -ENOMEM;
nvif_ioctl(object, "notify new size %d\n", size);
- if (nvif_unpack(req->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, true))) {
nvif_ioctl(object, "notify new vers %d reply %d route %02x "
"token %llx\n", req->v0.version,
req->v0.reply, req->v0.route, req->v0.token);
@@ -143,10 +144,10 @@ nvkm_client_mthd_devlist(struct nvkm_object *object, void *data, u32 size)
union {
struct nv_client_devlist_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "client devlist size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "client devlist vers %d count %d\n",
args->v0.version, args->v0.count);
if (size == sizeof(args->v0.device[0]) * args->v0.count) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
index d87d6ab03cc7..b0db51847c36 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
@@ -34,10 +34,10 @@ nvkm_ioctl_nop(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_nop_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "nop size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "nop vers %lld\n", args->v0.version);
args->v0.version = NVIF_VERSION_LATEST;
}
@@ -52,10 +52,10 @@ nvkm_ioctl_sclass(struct nvkm_object *object, void *data, u32 size)
struct nvif_ioctl_sclass_v0 v0;
} *args = data;
struct nvkm_oclass oclass;
- int ret, i = 0;
+ int ret = -ENOSYS, i = 0;
nvif_ioctl(object, "sclass size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "sclass vers %d count %d\n",
args->v0.version, args->v0.count);
if (size != args->v0.count * sizeof(args->v0.oclass[0]))
@@ -86,10 +86,10 @@ nvkm_ioctl_new(struct nvkm_object *parent, void *data, u32 size)
struct nvkm_client *client = parent->client;
struct nvkm_object *object = NULL;
struct nvkm_oclass oclass;
- int ret, i = 0;
+ int ret = -ENOSYS, i = 0;
nvif_ioctl(parent, "new size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(parent, "new vers %d handle %08x class %08x "
"route %02x token %llx object %016llx\n",
args->v0.version, args->v0.handle, args->v0.oclass,
@@ -147,10 +147,10 @@ nvkm_ioctl_del(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_del none;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "delete size %d\n", size);
- if (nvif_unvers(args->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
nvif_ioctl(object, "delete\n");
nvkm_object_fini(object, false);
nvkm_object_del(&object);
@@ -165,10 +165,10 @@ nvkm_ioctl_mthd(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_mthd_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "mthd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "mthd vers %d mthd %02x\n",
args->v0.version, args->v0.method);
ret = nvkm_object_mthd(object, args->v0.method, data, size);
@@ -189,10 +189,10 @@ nvkm_ioctl_rd(struct nvkm_object *object, void *data, u32 size)
u16 b16;
u32 b32;
} v;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "rd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "rd vers %d size %d addr %016llx\n",
args->v0.version, args->v0.size, args->v0.addr);
switch (args->v0.size) {
@@ -223,10 +223,10 @@ nvkm_ioctl_wr(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_wr_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "wr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object,
"wr vers %d size %d addr %016llx data %08x\n",
args->v0.version, args->v0.size, args->v0.addr,
@@ -251,10 +251,10 @@ nvkm_ioctl_map(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_map_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "map size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "map vers %d\n", args->v0.version);
ret = nvkm_object_map(object, &args->v0.handle,
&args->v0.length);
@@ -269,10 +269,10 @@ nvkm_ioctl_unmap(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_unmap none;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "unmap size %d\n", size);
- if (nvif_unvers(args->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
nvif_ioctl(object, "unmap\n");
}
@@ -286,10 +286,10 @@ nvkm_ioctl_ntfy_new(struct nvkm_object *object, void *data, u32 size)
struct nvif_ioctl_ntfy_new_v0 v0;
} *args = data;
struct nvkm_event *event;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "ntfy new size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "ntfy new vers %d event %02x\n",
args->v0.version, args->v0.event);
ret = nvkm_object_ntfy(object, args->v0.event, &event);
@@ -312,10 +312,10 @@ nvkm_ioctl_ntfy_del(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_ntfy_del_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "ntfy del size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "ntfy del vers %d index %d\n",
args->v0.version, args->v0.index);
ret = nvkm_client_notify_del(client, args->v0.index);
@@ -331,10 +331,10 @@ nvkm_ioctl_ntfy_get(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_ntfy_get_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "ntfy get size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "ntfy get vers %d index %d\n",
args->v0.version, args->v0.index);
ret = nvkm_client_notify_get(client, args->v0.index);
@@ -350,10 +350,10 @@ nvkm_ioctl_ntfy_put(struct nvkm_object *object, void *data, u32 size)
union {
struct nvif_ioctl_ntfy_put_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "ntfy put size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "ntfy put vers %d index %d\n",
args->v0.version, args->v0.index);
ret = nvkm_client_notify_put(client, args->v0.index);
@@ -421,12 +421,12 @@ nvkm_ioctl(struct nvkm_client *client, bool supervisor,
union {
struct nvif_ioctl_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
client->super = supervisor;
nvif_ioctl(object, "size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object,
"vers %d type %02x object %016llx owner %02x\n",
args->v0.version, args->v0.type, args->v0.object,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
index c541a1c012dc..e2b944dce9b8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
@@ -22,19 +22,65 @@
* Authors: Ben Skeggs
*/
#include "priv.h"
+#include <core/enum.h>
#include <nvif/class.h>
+static const struct nvkm_enum
+gk104_ce_launcherr_report[] = {
+ { 0x0, "NO_ERR" },
+ { 0x1, "2D_LAYER_EXCEEDS_DEPTH" },
+ { 0x2, "INVALID_ARGUMENT" },
+ { 0x3, "MEM2MEM_RECT_OUT_OF_BOUNDS" },
+ { 0x4, "SRC_LINE_EXCEEDS_PITCH" },
+ { 0x5, "SRC_LINE_EXCEEDS_NEG_PITCH" },
+ { 0x6, "DST_LINE_EXCEEDS_PITCH" },
+ { 0x7, "DST_LINE_EXCEEDS_NEG_PITCH" },
+ { 0x8, "BAD_SRC_PIXEL_COMP_REF" },
+ { 0x9, "INVALID_VALUE" },
+ { 0xa, "UNUSED_FIELD" },
+ { 0xb, "INVALID_OPERATION" },
+ {}
+};
+
+static void
+gk104_ce_intr_launcherr(struct nvkm_engine *ce, const u32 base)
+{
+ struct nvkm_subdev *subdev = &ce->subdev;
+ struct nvkm_device *device = subdev->device;
+ u32 stat = nvkm_rd32(device, 0x104f14 + base);
+ const struct nvkm_enum *en =
+ nvkm_enum_find(gk104_ce_launcherr_report, stat & 0x0000000f);
+ nvkm_warn(subdev, "LAUNCHERR %08x [%s]\n", stat, en ? en->name : "");
+ nvkm_wr32(device, 0x104f14 + base, 0x00000000);
+}
+
void
gk104_ce_intr(struct nvkm_engine *ce)
{
const u32 base = (ce->subdev.index - NVKM_ENGINE_CE0) * 0x1000;
struct nvkm_subdev *subdev = &ce->subdev;
struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0x104908 + base);
- if (stat) {
- nvkm_warn(subdev, "intr %08x\n", stat);
- nvkm_wr32(device, 0x104908 + base, stat);
+ u32 mask = nvkm_rd32(device, 0x104904 + base);
+ u32 intr = nvkm_rd32(device, 0x104908 + base) & mask;
+ if (intr & 0x00000001) {
+ nvkm_warn(subdev, "BLOCKPIPE\n");
+ nvkm_wr32(device, 0x104908 + base, 0x00000001);
+ intr &= ~0x00000001;
+ }
+ if (intr & 0x00000002) {
+ nvkm_warn(subdev, "NONBLOCKPIPE\n");
+ nvkm_wr32(device, 0x104908 + base, 0x00000002);
+ intr &= ~0x00000002;
+ }
+ if (intr & 0x00000004) {
+ gk104_ce_intr_launcherr(ce, base);
+ nvkm_wr32(device, 0x104908 + base, 0x00000004);
+ intr &= ~0x00000004;
+ }
+ if (intr) {
+ nvkm_warn(subdev, "intr %08x\n", intr);
+ nvkm_wr32(device, 0x104908 + base, intr);
}
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index bbc9824af6e0..b1ba1c782a2b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -1388,7 +1388,7 @@ nvc1_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gf106_pci_new,
.pmu = gf100_pmu_new,
.therm = gt215_therm_new,
.timer = nv41_timer_new,
@@ -1423,7 +1423,7 @@ nvc3_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gf106_pci_new,
.pmu = gf100_pmu_new,
.therm = gt215_therm_new,
.timer = nv41_timer_new,
@@ -1566,7 +1566,7 @@ nvcf_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gf106_pci_new,
.pmu = gf100_pmu_new,
.therm = gt215_therm_new,
.timer = nv41_timer_new,
@@ -1601,7 +1601,7 @@ nvd7_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gf106_pci_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
.ce[0] = gf100_ce_new,
@@ -1634,7 +1634,7 @@ nvd9_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gf106_pci_new,
.pmu = gf119_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1669,7 +1669,7 @@ nve4_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk104_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1706,7 +1706,7 @@ nve6_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk104_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1743,7 +1743,7 @@ nve7_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk104_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1804,7 +1804,7 @@ nvf0_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk110_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1840,7 +1840,7 @@ nvf1_chipset = {
.mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk110_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1876,7 +1876,7 @@ nv106_chipset = {
.mc = gk20a_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk208_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1912,7 +1912,7 @@ nv108_chipset = {
.mc = gk20a_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gk208_pmu_new,
.therm = gf119_therm_new,
.timer = nv41_timer_new,
@@ -1948,7 +1948,7 @@ nv117_chipset = {
.mc = gk20a_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gm107_pmu_new,
.therm = gm107_therm_new,
.timer = gk20a_timer_new,
@@ -1973,13 +1973,13 @@ nv124_chipset = {
.fuse = gm107_fuse_new,
.gpio = gk104_gpio_new,
.i2c = gm204_i2c_new,
- .ibus = gk104_ibus_new,
+ .ibus = gm204_ibus_new,
.imem = nv50_instmem_new,
- .ltc = gm107_ltc_new,
+ .ltc = gm204_ltc_new,
.mc = gk20a_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gm107_pmu_new,
.timer = gk20a_timer_new,
.volt = gk104_volt_new,
@@ -2004,13 +2004,13 @@ nv126_chipset = {
.fuse = gm107_fuse_new,
.gpio = gk104_gpio_new,
.i2c = gm204_i2c_new,
- .ibus = gk104_ibus_new,
+ .ibus = gm204_ibus_new,
.imem = nv50_instmem_new,
- .ltc = gm107_ltc_new,
+ .ltc = gm204_ltc_new,
.mc = gk20a_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
- .pci = g94_pci_new,
+ .pci = gk104_pci_new,
.pmu = gm107_pmu_new,
.timer = gk20a_timer_new,
.volt = gk104_volt_new,
@@ -2033,7 +2033,7 @@ nv12b_chipset = {
.fuse = gm107_fuse_new,
.ibus = gk20a_ibus_new,
.imem = gk20a_instmem_new,
- .ltc = gm107_ltc_new,
+ .ltc = gm204_ltc_new,
.mc = gk20a_mc_new,
.mmu = gf100_mmu_new,
.timer = gk20a_timer_new,
@@ -2494,7 +2494,8 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
device->pri = ioremap(mmio_base, mmio_size);
if (!device->pri) {
nvdev_error(device, "unable to map PRI\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
index cf8bc068e9b7..b0ece71aefde 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
@@ -27,6 +27,7 @@
#include <subdev/clk.h>
#include <nvif/class.h>
+#include <nvif/if0001.h>
#include <nvif/ioctl.h>
#include <nvif/unpack.h>
@@ -37,10 +38,10 @@ nvkm_control_mthd_pstate_info(struct nvkm_control *ctrl, void *data, u32 size)
struct nvif_control_pstate_info_v0 v0;
} *args = data;
struct nvkm_clk *clk = ctrl->device->clk;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(&ctrl->object, "control pstate info size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(&ctrl->object, "control pstate info vers %d\n",
args->v0.version);
} else
@@ -75,10 +76,10 @@ nvkm_control_mthd_pstate_attr(struct nvkm_control *ctrl, void *data, u32 size)
struct nvkm_cstate *cstate;
int i = 0, j = -1;
u32 lo, hi;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(&ctrl->object, "control pstate attr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(&ctrl->object,
"control pstate attr vers %d state %d index %d\n",
args->v0.version, args->v0.state, args->v0.index);
@@ -143,10 +144,10 @@ nvkm_control_mthd_pstate_user(struct nvkm_control *ctrl, void *data, u32 size)
struct nvif_control_pstate_user_v0 v0;
} *args = data;
struct nvkm_clk *clk = ctrl->device->clk;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(&ctrl->object, "control pstate user size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(&ctrl->object,
"control pstate user vers %d ustate %d pwrsrc %d\n",
args->v0.version, args->v0.ustate, args->v0.pwrsrc);
@@ -204,7 +205,7 @@ nvkm_control_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
const struct nvkm_device_oclass
nvkm_control_oclass = {
- .base.oclass = NVIF_IOCTL_NEW_V0_CONTROL,
+ .base.oclass = NVIF_CLASS_CONTROL,
.base.minver = -1,
.base.maxver = -1,
.ctor = nvkm_control_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
index 1ae48f27029d..137066426ed7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
@@ -31,6 +31,7 @@
#include <subdev/timer.h>
#include <nvif/class.h>
+#include <nvif/cl0080.h>
#include <nvif/unpack.h>
struct nvkm_udevice {
@@ -48,10 +49,10 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
union {
struct nv_device_info_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "device info size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "device info vers %d\n", args->v0.version);
} else
return ret;
@@ -123,13 +124,16 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
static int
nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size)
{
+ struct nvkm_object *object = &udev->object;
struct nvkm_device *device = udev->device;
union {
struct nv_device_time_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ nvif_ioctl(object, "device time size %d\n", size);
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
+ nvif_ioctl(object, "device time vers %d\n", args->v0.version);
args->v0.time = nvkm_timer_read(device->timer);
}
@@ -140,6 +144,7 @@ static int
nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
{
struct nvkm_udevice *udev = nvkm_udevice(object);
+ nvif_ioctl(object, "device mthd %08x\n", mthd);
switch (mthd) {
case NV_DEVICE_V0_INFO:
return nvkm_udevice_info(udev, data, size);
@@ -331,10 +336,10 @@ nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size,
struct nvkm_object *parent = &client->object;
const struct nvkm_object_func *func;
struct nvkm_udevice *udev;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create device size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create device v%d device %016llx\n",
args->v0.version, args->v0.device);
} else
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
index 44b67719f64d..785fa76d0fbf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -32,6 +32,7 @@
#include <subdev/bios/dcb.h>
#include <nvif/class.h>
+#include <nvif/cl0046.h>
#include <nvif/event.h>
#include <nvif/unpack.h>
@@ -58,9 +59,9 @@ nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size,
union {
struct nvif_notify_head_req_v0 v0;
} *req = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(req->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) {
notify->size = sizeof(struct nvif_notify_head_rep_v0);
if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
notify->types = 1;
@@ -96,9 +97,9 @@ nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
struct nvif_notify_conn_req_v0 v0;
} *req = data;
struct nvkm_output *outp;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(req->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) {
notify->size = sizeof(struct nvif_notify_conn_rep_v0);
list_for_each_entry(outp, &disp->outp, head) {
if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c
index 1fd89edefc26..83f152300ec0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c
@@ -27,6 +27,7 @@
#include <core/client.h>
#include <nvif/class.h>
+#include <nvif/cl507c.h>
#include <nvif/unpack.h>
int
@@ -41,11 +42,11 @@ nv50_disp_base_new(const struct nv50_disp_dmac_func *func,
} *args = data;
struct nvkm_object *parent = oclass->parent;
struct nv50_disp *disp = root->disp;
- int head, ret;
+ int head, ret = -ENOSYS;
u64 push;
nvif_ioctl(parent, "create disp base channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp base channel dma vers %d "
"pushbuf %016llx head %d\n",
args->v0.version, args->v0.pushbuf, args->v0.head);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
index 01803c0679b6..dd2953bc9264 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
@@ -28,7 +28,7 @@
#include <core/ramht.h>
#include <engine/dma.h>
-#include <nvif/class.h>
+#include <nvif/cl507d.h>
#include <nvif/event.h>
#include <nvif/unpack.h>
@@ -134,9 +134,9 @@ nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
union {
struct nvif_notify_uevent_req none;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unvers(args->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = chan->chid;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c
index db4a9b3e0e09..b547c8b833ca 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c
@@ -28,6 +28,7 @@
#include <subdev/timer.h>
#include <nvif/class.h>
+#include <nvif/cl507d.h>
#include <nvif/unpack.h>
int
@@ -42,10 +43,10 @@ nv50_disp_core_new(const struct nv50_disp_dmac_func *func,
} *args = data;
struct nvkm_object *parent = oclass->parent;
u64 push;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create disp core channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp core channel dma vers %d "
"pushbuf %016llx\n",
args->v0.version, args->v0.pushbuf);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
index 225858e62cf6..8b1320499a0f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
@@ -27,6 +27,7 @@
#include <core/client.h>
#include <nvif/class.h>
+#include <nvif/cl507a.h>
#include <nvif/unpack.h>
int
@@ -41,10 +42,10 @@ nv50_disp_curs_new(const struct nv50_disp_chan_func *func,
} *args = data;
struct nvkm_object *parent = oclass->parent;
struct nv50_disp *disp = root->disp;
- int head, ret;
+ int head, ret = -ENOSYS;
nvif_ioctl(parent, "create disp cursor size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp cursor vers %d head %d\n",
args->v0.version, args->v0.head);
if (args->v0.head > disp->base.head.nr)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
index 9bfa9e7dc161..c9b78b8f9c87 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
@@ -27,7 +27,7 @@
#include <core/client.h>
#include <subdev/timer.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -39,10 +39,10 @@ nv50_dac_power(NV50_DISP_MTHD_V1)
struct nv50_disp_dac_pwr_v0 v0;
} *args = data;
u32 stat;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp dac pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp dac pwr vers %d state %d data %d "
"vsync %d hsync %d\n",
args->v0.version, args->v0.state, args->v0.data,
@@ -76,10 +76,10 @@ nv50_dac_sense(NV50_DISP_MTHD_V1)
} *args = data;
const u32 doff = outp->or * 0x800;
u32 loadval;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp dac load size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp dac load vers %d data %08x\n",
args->v0.version, args->v0.data);
if (args->v0.data & 0xfff00000)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 186fd3ac78f6..f0314664349c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -158,7 +158,7 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
switch (outp->info.type) {
case DCB_OUTPUT_TMDS:
*conf = (ctrl & 0x00000f00) >> 8;
- if (pclk >= 165000)
+ if (*conf == 5)
*conf |= 0x0100;
break;
case DCB_OUTPUT_LVDS:
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c
index af99efbd63f7..da6129b2b78f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c
@@ -29,7 +29,7 @@
#include <subdev/bios/dcb.h>
#include <subdev/timer.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -41,10 +41,10 @@ gf119_hda_eld(NV50_DISP_MTHD_V1)
} *args = data;
const u32 soff = outp->or * 0x030;
const u32 hoff = head * 0x800;
- int ret, i;
+ int ret = -ENOSYS, i;
nvif_ioctl(object, "disp sor hda eld size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp sor hda eld vers %d\n",
args->v0.version);
if (size > 0x60)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
index c1590b746f13..6f0436df0219 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
@@ -27,7 +27,7 @@
#include <core/client.h>
#include <subdev/timer.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -38,10 +38,10 @@ gt215_hda_eld(NV50_DISP_MTHD_V1)
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x800;
- int ret, i;
+ int ret = -ENOSYS, i;
nvif_ioctl(object, "disp sor hda eld size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp sor hda eld vers %d\n",
args->v0.version);
if (size > 0x60)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
index ee9e800a8f06..1c4256e8cbd6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
@@ -25,7 +25,7 @@
#include <core/client.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -37,10 +37,10 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c
index b5af025d3b04..632f02da1382 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c
@@ -25,7 +25,7 @@
#include <core/client.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -37,10 +37,10 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1)
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
index 110dc19e4f67..4e8067d511d7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
@@ -25,7 +25,7 @@
#include <core/client.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -38,10 +38,10 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1)
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
index 61237dbfa35a..f1afc16494b6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
@@ -26,7 +26,7 @@
#include <core/client.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -38,10 +38,10 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1)
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 32e73a975b58..4226d2153b9c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -391,7 +391,7 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
switch (outp->info.type) {
case DCB_OUTPUT_TMDS:
*conf = (ctrl & 0x00000f00) >> 8;
- if (pclk >= 165000)
+ if (*conf == 5)
*conf |= 0x0100;
break;
case DCB_OUTPUT_LVDS:
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
index cd888a1e443c..3940b9c966ec 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
@@ -27,6 +27,7 @@
#include <core/client.h>
#include <nvif/class.h>
+#include <nvif/cl507b.h>
#include <nvif/unpack.h>
int
@@ -41,10 +42,10 @@ nv50_disp_oimm_new(const struct nv50_disp_chan_func *func,
} *args = data;
struct nvkm_object *parent = oclass->parent;
struct nv50_disp *disp = root->disp;
- int head, ret;
+ int head, ret = -ENOSYS;
nvif_ioctl(parent, "create disp overlay size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp overlay vers %d head %d\n",
args->v0.version, args->v0.head);
if (args->v0.head > disp->base.head.nr)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c
index 6fa296c047b8..2a49c46425cd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c
@@ -27,6 +27,7 @@
#include <core/client.h>
#include <nvif/class.h>
+#include <nvif/cl507e.h>
#include <nvif/unpack.h>
int
@@ -41,11 +42,11 @@ nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func,
} *args = data;
struct nvkm_object *parent = oclass->parent;
struct nv50_disp *disp = root->disp;
- int head, ret;
+ int head, ret = -ENOSYS;
u64 push;
nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp overlay channel dma vers %d "
"pushbuf %016llx head %d\n",
args->v0.version, args->v0.pushbuf, args->v0.head);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
index ab524bde7795..6c532eadba17 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
@@ -28,7 +28,7 @@
#include <subdev/i2c.h>
#include <subdev/timer.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -40,10 +40,10 @@ nv50_pior_power(NV50_DISP_MTHD_V1)
struct nv50_disp_pior_pwr_v0 v0;
} *args = data;
u32 ctrl, type;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp pior pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
args->v0.version, args->v0.state, args->v0.type);
if (args->v0.type > 0x0f)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c
index 8591726871ac..335d88823c22 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c
@@ -29,6 +29,7 @@
#include <subdev/timer.h>
#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -39,12 +40,12 @@ gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0)
const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300));
const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300));
union {
- struct nv04_disp_scanoutpos_v0 v0;
+ struct nv50_disp_scanoutpos_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp scanoutpos size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp scanoutpos vers %d\n",
args->v0.version);
args->v0.vblanke = (blanke & 0xffff0000) >> 16;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
index 2be846374d39..f535f43231e2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
@@ -27,6 +27,7 @@
#include <core/client.h>
#include <nvif/class.h>
+#include <nvif/cl0046.h>
#include <nvif/unpack.h>
struct nv04_disp_root {
@@ -45,10 +46,10 @@ nv04_disp_scanoutpos(struct nv04_disp_root *root,
struct nv04_disp_scanoutpos_v0 v0;
} *args = data;
u32 line;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp scanoutpos size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp scanoutpos vers %d\n",
args->v0.version);
args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff;
@@ -85,10 +86,10 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
union {
struct nv04_disp_mthd_v0 v0;
} *args = data;
- int head, ret;
+ int head, ret = -ENOSYS;
nvif_ioctl(object, "disp mthd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
args->v0.version, args->v0.method, args->v0.head);
mthd = args->v0.method;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
index 06fb24d88702..2f9cecd81d04 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
@@ -29,6 +29,7 @@
#include <subdev/timer.h>
#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -39,12 +40,12 @@ nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0)
const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540));
const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540));
union {
- struct nv04_disp_scanoutpos_v0 v0;
+ struct nv50_disp_scanoutpos_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp scanoutpos size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp scanoutpos vers %d\n",
args->v0.version);
args->v0.vblanke = (blanke & 0xffff0000) >> 16;
@@ -78,19 +79,19 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
struct nvkm_output *outp = NULL;
struct nvkm_output *temp;
u16 type, mask = 0;
- int head, ret;
+ int head, ret = -ENOSYS;
if (mthd != NV50_DISP_MTHD)
return -EINVAL;
nvif_ioctl(object, "disp mthd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
args->v0.version, args->v0.method, args->v0.head);
mthd = args->v0.method;
head = args->v0.head;
} else
- if (nvif_unpack(args->v1, 1, 1, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
nvif_ioctl(object, "disp mthd vers %d mthd %02x "
"type %04x mask %04x\n",
args->v1.version, args->v1.method,
@@ -143,8 +144,9 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
union {
struct nv50_disp_sor_lvds_script_v0 v0;
} *args = data;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor lvds script size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor lvds script "
"vers %d name %04x\n",
args->v0.version, args->v0.script);
@@ -159,8 +161,9 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
union {
struct nv50_disp_sor_dp_pwr_v0 v0;
} *args = data;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor dp pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n",
args->v0.version, args->v0.state);
if (args->v0.state == 0) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
index 29e0d2a9a839..53596bed3c36 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
@@ -27,7 +27,7 @@
#include <core/client.h>
#include <subdev/timer.h>
-#include <nvif/class.h>
+#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
@@ -39,10 +39,10 @@ nv50_sor_power(NV50_DISP_MTHD_V1)
} *args = data;
const u32 soff = outp->or * 0x800;
u32 stat;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "disp sor pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor pwr vers %d state %d\n",
args->v0.version, args->v0.state);
stat = !!args->v0.state;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c
index 45ab062661a4..13c661b1ef14 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c
@@ -28,7 +28,7 @@
#include <subdev/fb.h>
#include <subdev/instmem.h>
-#include <nvif/class.h>
+#include <nvif/cl0002.h>
#include <nvif/unpack.h>
static int
@@ -69,7 +69,7 @@ nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *func, struct nvkm_dma *dma,
struct nvkm_fb *fb = device->fb;
void *data = *pdata;
u32 size = *psize;
- int ret;
+ int ret = -ENOSYS;
nvkm_object_ctor(&nvkm_dmaobj_func, oclass, &dmaobj->object);
dmaobj->func = func;
@@ -77,7 +77,7 @@ nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *func, struct nvkm_dma *dma,
RB_CLEAR_NODE(&dmaobj->rb);
nvif_ioctl(parent, "create dma size %d\n", *psize);
- if (nvif_unpack(args->v0, 0, 0, true)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(parent, "create dma vers %d target %d access %d "
"start %016llx limit %016llx\n",
args->v0.version, args->v0.target, args->v0.access,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c
index 13e341cc4e32..ef7ac360101e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c
@@ -28,7 +28,7 @@
#include <core/gpuobj.h>
#include <subdev/fb.h>
-#include <nvif/class.h>
+#include <nvif/cl0002.h>
#include <nvif/unpack.h>
struct gf100_dmaobj {
@@ -87,10 +87,11 @@ gf100_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass,
if (ret)
return ret;
+ ret = -ENOSYS;
args = data;
nvif_ioctl(parent, "create gf100 dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent,
"create gf100 dma vers %d priv %d kind %02x\n",
args->v0.version, args->v0.priv, args->v0.kind);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c
index 0e1af8b4db84..c068cee34588 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c
@@ -28,7 +28,7 @@
#include <core/gpuobj.h>
#include <subdev/fb.h>
-#include <nvif/class.h>
+#include <nvif/cl0002.h>
#include <nvif/unpack.h>
struct gf119_dmaobj {
@@ -85,10 +85,11 @@ gf119_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass,
if (ret)
return ret;
+ ret = -ENOSYS;
args = data;
nvif_ioctl(parent, "create gf119 dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent,
"create gf100 dma vers %d page %d kind %02x\n",
args->v0.version, args->v0.page, args->v0.kind);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c
index 5b7ce313ea14..6a85b5dea643 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c
@@ -28,7 +28,7 @@
#include <core/gpuobj.h>
#include <subdev/fb.h>
-#include <nvif/class.h>
+#include <nvif/cl0002.h>
#include <nvif/unpack.h>
struct nv50_dmaobj {
@@ -87,10 +87,11 @@ nv50_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass,
if (ret)
return ret;
+ ret = -ENOSYS;
args = data;
nvif_ioctl(parent, "create nv50 dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create nv50 dma vers %d priv %d part %d "
"comp %d kind %02x\n", args->v0.version,
args->v0.priv, args->v0.part, args->v0.comp,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
index 1fbbfbe6ca9c..cfc7d5725a61 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
@@ -129,9 +129,9 @@ nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
union {
struct nvif_notify_uevent_req none;
} *req = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unvers(req->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, req->none))) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c
index 04305241ceed..aeb3387a3fb0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c
@@ -28,7 +28,7 @@
#include <subdev/mmu.h>
#include <subdev/timer.h>
-#include <nvif/class.h>
+#include <nvif/cl826e.h>
int
g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c
index a5ca52c7b74f..caa914074752 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c
@@ -27,6 +27,7 @@
#include <core/ramht.h>
#include <nvif/class.h>
+#include <nvif/cl826e.h>
#include <nvif/unpack.h>
static int
@@ -35,14 +36,14 @@ g84_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
{
struct nvkm_object *parent = oclass->parent;
union {
- struct nv50_channel_dma_v0 v0;
+ struct g82_channel_dma_v0 v0;
} *args = data;
struct nv50_fifo *fifo = nv50_fifo(base);
struct nv50_fifo_chan *chan;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel dma vers %d vm %llx "
"pushbuf %llx offset %016llx\n",
args->v0.version, args->v0.vm, args->v0.pushbuf,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
index bfcc6408a772..edec30fd3ecd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
@@ -29,6 +29,7 @@
#include <subdev/instmem.h>
#include <nvif/class.h>
+#include <nvif/cl006b.h>
#include <nvif/unpack.h>
void
@@ -167,10 +168,10 @@ nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct nv04_fifo_chan *chan = NULL;
struct nvkm_device *device = fifo->base.engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %08x\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c
index 34f68e5bd040..f5f355ff005d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c
@@ -29,6 +29,7 @@
#include <subdev/instmem.h>
#include <nvif/class.h>
+#include <nvif/cl006b.h>
#include <nvif/unpack.h>
static int
@@ -43,10 +44,10 @@ nv10_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct nv04_fifo_chan *chan = NULL;
struct nvkm_device *device = fifo->base.engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %08x\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c
index ed7cc9f2b540..7edc6a564b5d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c
@@ -29,6 +29,7 @@
#include <subdev/instmem.h>
#include <nvif/class.h>
+#include <nvif/cl006b.h>
#include <nvif/unpack.h>
static int
@@ -43,10 +44,10 @@ nv17_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct nv04_fifo_chan *chan = NULL;
struct nvkm_device *device = fifo->base.engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %08x\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c
index 043b6c325949..0ec179fc40a1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c
@@ -29,6 +29,7 @@
#include <subdev/instmem.h>
#include <nvif/class.h>
+#include <nvif/cl006b.h>
#include <nvif/unpack.h>
static bool
@@ -188,10 +189,10 @@ nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct nv04_fifo_chan *chan = NULL;
struct nvkm_device *device = fifo->base.engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx "
"offset %08x\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c
index 6b3b15f12c39..480bc3777be5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c
@@ -27,6 +27,7 @@
#include <core/ramht.h>
#include <nvif/class.h>
+#include <nvif/cl506e.h>
#include <nvif/unpack.h>
static int
@@ -39,10 +40,10 @@ nv50_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
} *args = data;
struct nv50_fifo *fifo = nv50_fifo(base);
struct nv50_fifo_chan *chan;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel dma vers %d vm %llx "
"pushbuf %llx offset %016llx\n",
args->v0.version, args->v0.vm, args->v0.pushbuf,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
index ff6fcbda615b..36a39c7fd8d2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
@@ -47,7 +47,7 @@ gf100_fifo_uevent_fini(struct nvkm_fifo *fifo)
}
void
-gf100_fifo_runlist_update(struct gf100_fifo *fifo)
+gf100_fifo_runlist_commit(struct gf100_fifo *fifo)
{
struct gf100_fifo_chan *chan;
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
@@ -77,6 +77,22 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo)
mutex_unlock(&subdev->mutex);
}
+void
+gf100_fifo_runlist_remove(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
+{
+ mutex_lock(&fifo->base.engine.subdev.mutex);
+ list_del_init(&chan->head);
+ mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
+void
+gf100_fifo_runlist_insert(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
+{
+ mutex_lock(&fifo->base.engine.subdev.mutex);
+ list_add_tail(&chan->head, &fifo->chan);
+ mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
static inline int
gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn)
{
@@ -139,7 +155,7 @@ gf100_fifo_recover_work(struct work_struct *work)
}
}
- gf100_fifo_runlist_update(fifo);
+ gf100_fifo_runlist_commit(fifo);
nvkm_wr32(device, 0x00262c, engm);
nvkm_mask(device, 0x002630, engm, 0x00000000);
}
@@ -239,7 +255,7 @@ gf100_fifo_fault_engine[] = {
{ 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC },
{ 0x15, "PCE0", NULL, NVKM_ENGINE_CE0 },
{ 0x16, "PCE1", NULL, NVKM_ENGINE_CE1 },
- { 0x17, "PDAEMON" },
+ { 0x17, "PMU" },
{}
};
@@ -270,7 +286,7 @@ gf100_fifo_fault_hubclient[] = {
{ 0x0c, "PMSPPP" },
{ 0x0d, "PMSVLD" },
{ 0x11, "PCOUNTER" },
- { 0x12, "PDAEMON" },
+ { 0x12, "PMU" },
{ 0x14, "CCACHE" },
{ 0x15, "CCACHE_POST" },
{}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
index c649ca9b53e3..08c33c3ceaf7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
@@ -5,6 +5,7 @@
#include <subdev/mmu.h>
+struct gf100_fifo_chan;
struct gf100_fifo {
struct nvkm_fifo base;
@@ -27,5 +28,7 @@ struct gf100_fifo {
};
void gf100_fifo_intr_engine(struct gf100_fifo *);
-void gf100_fifo_runlist_update(struct gf100_fifo *);
+void gf100_fifo_runlist_insert(struct gf100_fifo *, struct gf100_fifo_chan *);
+void gf100_fifo_runlist_remove(struct gf100_fifo *, struct gf100_fifo_chan *);
+void gf100_fifo_runlist_commit(struct gf100_fifo *);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
index 98970a0b7a66..4fcd147d43c8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -47,7 +47,7 @@ gk104_fifo_uevent_init(struct nvkm_fifo *fifo)
}
void
-gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine)
+gk104_fifo_runlist_commit(struct gk104_fifo *fifo, u32 engine)
{
struct gk104_fifo_engn *engn = &fifo->engine[engine];
struct gk104_fifo_chan *chan;
@@ -78,6 +78,22 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine)
mutex_unlock(&subdev->mutex);
}
+void
+gk104_fifo_runlist_remove(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan)
+{
+ mutex_lock(&fifo->base.engine.subdev.mutex);
+ list_del_init(&chan->head);
+ mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
+void
+gk104_fifo_runlist_insert(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan)
+{
+ mutex_lock(&fifo->base.engine.subdev.mutex);
+ list_add_tail(&chan->head, &fifo->engine[chan->engine].chan);
+ mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
static inline struct nvkm_engine *
gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn)
{
@@ -112,7 +128,7 @@ gk104_fifo_recover_work(struct work_struct *work)
nvkm_subdev_fini(&engine->subdev, false);
WARN_ON(nvkm_subdev_init(&engine->subdev));
}
- gk104_fifo_runlist_update(fifo, gk104_fifo_subdev_engine(engn));
+ gk104_fifo_runlist_commit(fifo, gk104_fifo_subdev_engine(engn));
}
nvkm_wr32(device, 0x00262c, engm);
@@ -180,7 +196,7 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo)
spin_lock_irqsave(&fifo->base.lock, flags);
for (engn = 0; engn < ARRAY_SIZE(fifo->engine); engn++) {
- u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04));
+ u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x08));
u32 busy = (stat & 0x80000000);
u32 next = (stat & 0x07ff0000) >> 16;
u32 chsw = (stat & 0x00008000);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
index 5afd9b5ec5d1..bec519d8f91e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
@@ -5,6 +5,7 @@
#include <subdev/mmu.h>
+struct gk104_fifo_chan;
struct gk104_fifo_engn {
struct nvkm_memory *runlist[2];
int cur_runlist;
@@ -35,7 +36,9 @@ void gk104_fifo_fini(struct nvkm_fifo *);
void gk104_fifo_intr(struct nvkm_fifo *);
void gk104_fifo_uevent_init(struct nvkm_fifo *);
void gk104_fifo_uevent_fini(struct nvkm_fifo *);
-void gk104_fifo_runlist_update(struct gk104_fifo *, u32 engine);
+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 *, u32 engine);
static inline u64
gk104_fifo_engine_subdev(int engine)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c
index 820132363f68..77c2f2a28bf3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c
@@ -27,6 +27,7 @@
#include <core/ramht.h>
#include <nvif/class.h>
+#include <nvif/cl826f.h>
#include <nvif/unpack.h>
static int
@@ -35,15 +36,15 @@ g84_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
{
struct nvkm_object *parent = oclass->parent;
union {
- struct nv50_channel_gpfifo_v0 v0;
+ struct g82_channel_gpfifo_v0 v0;
} *args = data;
struct nv50_fifo *fifo = nv50_fifo(base);
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx "
"pushbuf %llx ioffset %016llx "
"ilength %08x\n",
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
index e7cbc139c1d4..cbc67f262322 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
@@ -29,6 +29,7 @@
#include <subdev/timer.h>
#include <nvif/class.h>
+#include <nvif/cl906f.h>
#include <nvif/unpack.h>
static u32
@@ -138,9 +139,9 @@ gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
u32 coff = chan->base.chid * 8;
if (!list_empty(&chan->head) && !chan->killed) {
- list_del_init(&chan->head);
+ gf100_fifo_runlist_remove(fifo, chan);
nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000);
- gf100_fifo_runlist_update(fifo);
+ gf100_fifo_runlist_commit(fifo);
}
gf100_fifo_intr_engine(fifo);
@@ -160,9 +161,9 @@ gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr);
if (list_empty(&chan->head) && !chan->killed) {
- list_add_tail(&chan->head, &fifo->chan);
+ gf100_fifo_runlist_insert(fifo, chan);
nvkm_wr32(device, 0x003004 + coff, 0x001f0001);
- gf100_fifo_runlist_update(fifo);
+ gf100_fifo_runlist_commit(fifo);
}
}
@@ -199,10 +200,10 @@ gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct nvkm_object *parent = oclass->parent;
struct gf100_fifo_chan *chan;
u64 usermem, ioffset, ilength;
- int ret, i;
+ int ret = -ENOSYS, i;
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.vm, args->v0.ioffset,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
index 0b817540a9e4..2e1df01bd928 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
@@ -30,6 +30,7 @@
#include <subdev/timer.h>
#include <nvif/class.h>
+#include <nvif/cla06f.h>
#include <nvif/unpack.h>
static int
@@ -151,9 +152,9 @@ gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
u32 coff = chan->base.chid * 8;
if (!list_empty(&chan->head)) {
- list_del_init(&chan->head);
+ gk104_fifo_runlist_remove(fifo, chan);
nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800);
- gk104_fifo_runlist_update(fifo, chan->engine);
+ gk104_fifo_runlist_commit(fifo, chan->engine);
}
nvkm_wr32(device, 0x800000 + coff, 0x00000000);
@@ -172,9 +173,9 @@ gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr);
if (list_empty(&chan->head) && !chan->killed) {
- list_add_tail(&chan->head, &fifo->engine[chan->engine].chan);
+ gk104_fifo_runlist_insert(fifo, chan);
nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
- gk104_fifo_runlist_update(fifo, chan->engine);
+ gk104_fifo_runlist_commit(fifo, chan->engine);
nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
}
}
@@ -213,10 +214,10 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct gk104_fifo_chan *chan;
u64 usermem, ioffset, ilength;
u32 engines;
- int ret, i;
+ int ret = -ENOSYS, i;
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx "
"ioffset %016llx ilength %08x engine %08x\n",
args->v0.version, args->v0.vm, args->v0.ioffset,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c
index a8c69f878221..c5a7de9db259 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c
@@ -27,6 +27,7 @@
#include <core/ramht.h>
#include <nvif/class.h>
+#include <nvif/cl506f.h>
#include <nvif/unpack.h>
static int
@@ -40,10 +41,10 @@ nv50_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
struct nv50_fifo *fifo = nv50_fifo(base);
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx "
"pushbuf %llx ioffset %016llx "
"ilength %08x\n",
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
index ddaa16a71c84..ad0a6cfe7580 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
@@ -55,7 +55,7 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info)
gk104_grctx_generate_rop_active_fbps(gr);
- nvkm_mask(device, 0x5044b0, 0x8000000, 0x8000000);
+ nvkm_mask(device, 0x5044b0, 0x08000000, 0x08000000);
gf100_gr_wait_idle(gr);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
index 7dacb3cc0668..e168b83a10c9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
@@ -247,10 +247,7 @@ init:
tpc_strand_info(-1);
ld b32 $r4 D[$r0 + #tpc_count]
- mov $r5 NV_PGRAPH_GPC0_TPC0
- ld b32 $r6 D[$r0 + #gpc_id]
- shl b32 $r6 15
- add b32 $r5 $r6
+ gpc_addr($r5, NV_PGRAPH_GPC0_TPC0)
tpc_strand_init_tpc_loop:
add b32 $r14 $r5 NV_TPC_STRAND_CNT
call(nv_rd32)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
index 11bf363a6ae9..5136f9161706 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
@@ -289,7 +289,7 @@ uint32_t gm107_grgpc_code[] = {
0x020014fe,
0x12004002,
0xbd0002f6,
- 0x05b34104,
+ 0x05ad4104,
0x400010fe,
0x00f60700,
0x0204bd00,
@@ -387,180 +387,180 @@ uint32_t gm107_grgpc_code[] = {
0x7e00008f,
0x98000314,
0x00850504,
- 0x06985040,
- 0x0f64b604,
-/* 0x04e3: tpc_strand_init_tpc_loop */
- 0xb80056bb,
- 0x0005705e,
- 0x0000657e,
- 0x74bdf6b2,
-/* 0x04f0: tpc_strand_init_idx_loop */
- 0x05605eb8,
- 0x7e7fb200,
- 0xb800008f,
- 0x0005885e,
- 0x7e082f95,
- 0xb800008f,
- 0x00058c5e,
- 0x7e082f95,
- 0xb800008f,
- 0x0005905e,
- 0x0000657e,
- 0xb606f5b6,
- 0xf4b601f0,
- 0x002fbb08,
- 0xb6003fbb,
- 0x62b60170,
- 0xbf1bf401,
- 0x080050b7,
- 0xf40142b6,
- 0x3f0fa81b,
- 0x501d608e,
- 0xb201e5f0,
- 0x008f7eff,
- 0x8e0d0f00,
- 0xf0501da8,
- 0xffb201e5,
- 0x00008f7e,
- 0x0003147e,
- 0x02010080,
- 0xbd0003f6,
- 0xf024bd04,
- 0x00801f29,
- 0x02f60230,
-/* 0x0577: main */
- 0xf404bd00,
- 0x28f40031,
- 0x7e240d00,
- 0xf4000037,
- 0xe4b0f401,
- 0x1d18f404,
- 0x020181fe,
- 0xfd20bd06,
- 0xe4b60412,
- 0x051efd01,
- 0x7e0018fe,
- 0xf400064a,
-/* 0x05a6: main_not_ctx_xfer */
- 0xef94d40e,
- 0x01f5f010,
- 0x0002f87e,
-/* 0x05b3: ih */
- 0xf9c70ef4,
- 0x0188fe80,
- 0x90f980f9,
- 0xb0f9a0f9,
- 0xe0f9d0f9,
- 0x04bdf0f9,
- 0xcf02004a,
- 0xabc400aa,
- 0x1f0bf404,
- 0x004e240d,
- 0x00eecf1a,
- 0xcf19004f,
- 0x047e00ff,
- 0x010e0000,
- 0xf61d0040,
- 0x04bd000e,
-/* 0x05f0: ih_no_fifo */
- 0xf6010040,
- 0x04bd000a,
- 0xe0fcf0fc,
- 0xb0fcd0fc,
- 0x90fca0fc,
- 0x88fe80fc,
- 0xf480fc00,
- 0x01f80032,
-/* 0x0610: hub_barrier_done */
- 0x0e98010f,
- 0x04febb04,
- 0x188effb2,
- 0x8f7e4094,
- 0x00f80000,
-/* 0x0624: ctx_redswitch */
- 0x0080200f,
- 0x0ff60185,
- 0x0e04bd00,
-/* 0x0631: ctx_redswitch_delay */
- 0x01e2b608,
- 0xf1fd1bf4,
- 0xf10800f5,
- 0x800200f5,
- 0xf6018500,
- 0x04bd000f,
-/* 0x064a: ctx_xfer */
- 0x008000f8,
- 0x0ff60281,
- 0x8e04bd00,
- 0xf0501dc4,
- 0xffb201e5,
- 0x00008f7e,
- 0x7e0711f4,
-/* 0x0667: ctx_xfer_not_load */
- 0x7e000624,
- 0xbd000216,
- 0x47fc8024,
- 0x0002f602,
- 0x2cf004bd,
- 0x0320b601,
- 0x024afc80,
- 0xbd0002f6,
- 0x8e0c0f04,
- 0xf0501da8,
- 0xffb201e5,
- 0x00008f7e,
- 0x0003147e,
+ 0x55f05040,
+/* 0x04dd: tpc_strand_init_tpc_loop */
+ 0x705eb801,
+ 0x657e0005,
+ 0xf6b20000,
+/* 0x04ea: tpc_strand_init_idx_loop */
+ 0x5eb874bd,
+ 0xb2000560,
+ 0x008f7e7f,
+ 0x885eb800,
+ 0x2f950005,
+ 0x008f7e08,
+ 0x8c5eb800,
+ 0x2f950005,
+ 0x008f7e08,
+ 0x905eb800,
+ 0x657e0005,
+ 0xf5b60000,
+ 0x01f0b606,
+ 0xbb08f4b6,
+ 0x3fbb002f,
+ 0x0170b600,
+ 0xf40162b6,
+ 0x50b7bf1b,
+ 0x42b60800,
+ 0xa81bf401,
0x608e3f0f,
0xe5f0501d,
0x7effb201,
0x0f00008f,
- 0x1d9c8e00,
+ 0x1da88e0d,
0x01e5f050,
0x8f7effb2,
- 0x010f0000,
- 0x0003147e,
- 0xb601fcf0,
- 0xa88e03f0,
- 0xe5f0501d,
- 0x7effb201,
- 0xf000008f,
- 0xa5f001ac,
- 0x00008b02,
- 0x040c9850,
- 0xbb0fc4b6,
- 0x0c9800bc,
- 0x010d9800,
- 0x3d7e000e,
- 0xacf00001,
- 0x40008b01,
- 0x040c9850,
- 0xbb0fc4b6,
- 0x0c9800bc,
- 0x020d9801,
- 0x4e060f98,
- 0x3d7e0800,
- 0xacf00001,
- 0x04a5f001,
- 0x5030008b,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x020c9800,
- 0x98030d98,
- 0x004e080f,
- 0x013d7e02,
- 0x020a7e00,
- 0x03147e00,
- 0x0601f400,
-/* 0x073f: ctx_xfer_post */
- 0x7e1a12f4,
- 0x0f000227,
- 0x1da88e0d,
+ 0x147e0000,
+ 0x00800003,
+ 0x03f60201,
+ 0xbd04bd00,
+ 0x1f29f024,
+ 0x02300080,
+ 0xbd0002f6,
+/* 0x0571: main */
+ 0x0031f404,
+ 0x0d0028f4,
+ 0x00377e24,
+ 0xf401f400,
+ 0xf404e4b0,
+ 0x81fe1d18,
+ 0xbd060201,
+ 0x0412fd20,
+ 0xfd01e4b6,
+ 0x18fe051e,
+ 0x06447e00,
+ 0xd40ef400,
+/* 0x05a0: main_not_ctx_xfer */
+ 0xf010ef94,
+ 0xf87e01f5,
+ 0x0ef40002,
+/* 0x05ad: ih */
+ 0xfe80f9c7,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0x004a04bd,
+ 0x00aacf02,
+ 0xf404abc4,
+ 0x240d1f0b,
+ 0xcf1a004e,
+ 0x004f00ee,
+ 0x00ffcf19,
+ 0x0000047e,
+ 0x0040010e,
+ 0x000ef61d,
+/* 0x05ea: ih_no_fifo */
+ 0x004004bd,
+ 0x000af601,
+ 0xf0fc04bd,
+ 0xd0fce0fc,
+ 0xa0fcb0fc,
+ 0x80fc90fc,
+ 0xfc0088fe,
+ 0x0032f480,
+/* 0x060a: hub_barrier_done */
+ 0x010f01f8,
+ 0xbb040e98,
+ 0xffb204fe,
+ 0x4094188e,
+ 0x00008f7e,
+/* 0x061e: ctx_redswitch */
+ 0x200f00f8,
+ 0x01850080,
+ 0xbd000ff6,
+/* 0x062b: ctx_redswitch_delay */
+ 0xb6080e04,
+ 0x1bf401e2,
+ 0x00f5f1fd,
+ 0x00f5f108,
+ 0x85008002,
+ 0x000ff601,
+ 0x00f804bd,
+/* 0x0644: ctx_xfer */
+ 0x02810080,
+ 0xbd000ff6,
+ 0x1dc48e04,
+ 0x01e5f050,
+ 0x8f7effb2,
+ 0x11f40000,
+ 0x061e7e07,
+/* 0x0661: ctx_xfer_not_load */
+ 0x02167e00,
+ 0x8024bd00,
+ 0xf60247fc,
+ 0x04bd0002,
+ 0xb6012cf0,
+ 0xfc800320,
+ 0x02f6024a,
+ 0x0f04bd00,
+ 0x1da88e0c,
0x01e5f050,
0x8f7effb2,
0x147e0000,
-/* 0x0756: ctx_xfer_done */
- 0x107e0003,
- 0x00f80006,
+ 0x3f0f0003,
+ 0x501d608e,
+ 0xb201e5f0,
+ 0x008f7eff,
+ 0x8e000f00,
+ 0xf0501d9c,
+ 0xffb201e5,
+ 0x00008f7e,
+ 0x147e010f,
+ 0xfcf00003,
+ 0x03f0b601,
+ 0x501da88e,
+ 0xb201e5f0,
+ 0x008f7eff,
+ 0x01acf000,
+ 0x8b02a5f0,
+ 0x98500000,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98000c98,
+ 0x000e010d,
+ 0x00013d7e,
+ 0x8b01acf0,
+ 0x98504000,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98010c98,
+ 0x0f98020d,
+ 0x08004e06,
+ 0x00013d7e,
+ 0xf001acf0,
+ 0x008b04a5,
+ 0x0c985030,
+ 0x0fc4b604,
+ 0x9800bcbb,
+ 0x0d98020c,
+ 0x080f9803,
+ 0x7e02004e,
+ 0x7e00013d,
+ 0x7e00020a,
+ 0xf4000314,
+ 0x12f40601,
+/* 0x0739: ctx_xfer_post */
+ 0x02277e1a,
+ 0x8e0d0f00,
+ 0xf0501da8,
+ 0xffb201e5,
+ 0x00008f7e,
+ 0x0003147e,
+/* 0x0750: ctx_xfer_done */
+ 0x00060a7e,
+ 0x000000f8,
+ 0x00000000,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
index 9f5dfc85147a..1f81069edc58 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -34,6 +34,7 @@
#include <engine/fifo.h>
#include <nvif/class.h>
+#include <nvif/cl9097.h>
#include <nvif/unpack.h>
/*******************************************************************************
@@ -139,6 +140,12 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format,
/*******************************************************************************
* Graphics object classes
******************************************************************************/
+#define gf100_gr_object(p) container_of((p), struct gf100_gr_object, object)
+
+struct gf100_gr_object {
+ struct nvkm_object object;
+ struct gf100_gr_chan *chan;
+};
static int
gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
@@ -147,9 +154,9 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
union {
struct fermi_a_zbc_color_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
switch (args->v0.format) {
case FERMI_A_ZBC_COLOR_V0_FMT_ZERO:
case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE:
@@ -193,9 +200,9 @@ gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size)
union {
struct fermi_a_zbc_depth_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
switch (args->v0.format) {
case FERMI_A_ZBC_DEPTH_V0_FMT_FP32:
ret = gf100_gr_zbc_depth_get(gr, args->v0.format,
@@ -213,6 +220,7 @@ gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size)
static int
gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
{
+ nvif_ioctl(object, "fermi mthd %08x\n", mthd);
switch (mthd) {
case FERMI_A_ZBC_COLOR:
return gf100_fermi_mthd_zbc_color(object, data, size);
@@ -256,6 +264,27 @@ gf100_gr_mthd_sw(struct nvkm_device *device, u16 class, u32 mthd, u32 data)
return false;
}
+static const struct nvkm_object_func
+gf100_gr_object_func = {
+};
+
+static int
+gf100_gr_object_new(const struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_gr_chan *chan = gf100_gr_chan(oclass->parent);
+ struct gf100_gr_object *object;
+
+ if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
+ return -ENOMEM;
+ *pobject = &object->object;
+
+ nvkm_object_ctor(oclass->base.func ? oclass->base.func :
+ &gf100_gr_object_func, oclass, &object->object);
+ object->chan = chan;
+ return 0;
+}
+
static int
gf100_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass)
{
@@ -265,6 +294,7 @@ gf100_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass)
while (gr->func->sclass[c].oclass) {
if (c++ == index) {
*sclass = gr->func->sclass[index];
+ sclass->ctor = gf100_gr_object_new;
return index;
}
}
@@ -826,7 +856,41 @@ gf100_gr_units(struct nvkm_gr *base)
return cfg;
}
+static const struct nvkm_bitfield gf100_dispatch_error[] = {
+ { 0x00000001, "INJECTED_BUNDLE_ERROR" },
+ { 0x00000002, "CLASS_SUBCH_MISMATCH" },
+ { 0x00000004, "SUBCHSW_DURING_NOTIFY" },
+ {}
+};
+
+static const struct nvkm_bitfield gf100_m2mf_error[] = {
+ { 0x00000001, "PUSH_TOO_MUCH_DATA" },
+ { 0x00000002, "PUSH_NOT_ENOUGH_DATA" },
+ {}
+};
+
+static const struct nvkm_bitfield gf100_unk6_error[] = {
+ { 0x00000001, "TEMP_TOO_SMALL" },
+ {}
+};
+
+static const struct nvkm_bitfield gf100_ccache_error[] = {
+ { 0x00000001, "INTR" },
+ { 0x00000002, "LDCONST_OOB" },
+ {}
+};
+
+static const struct nvkm_bitfield gf100_macro_error[] = {
+ { 0x00000001, "TOO_FEW_PARAMS" },
+ { 0x00000002, "TOO_MANY_PARAMS" },
+ { 0x00000004, "ILLEGAL_OPCODE" },
+ { 0x00000008, "DOUBLE_BRANCH" },
+ { 0x00000010, "WATCHDOG" },
+ {}
+};
+
static const struct nvkm_bitfield gk104_sked_error[] = {
+ { 0x00000040, "CTA_RESUME" },
{ 0x00000080, "CONSTANT_BUFFER_SIZE" },
{ 0x00000200, "LOCAL_MEMORY_SIZE_POS" },
{ 0x00000400, "LOCAL_MEMORY_SIZE_NEG" },
@@ -836,6 +900,8 @@ static const struct nvkm_bitfield gk104_sked_error[] = {
{ 0x00040000, "TOTAL_THREADS" },
{ 0x00100000, "PROGRAM_OFFSET" },
{ 0x00200000, "SHARED_MEMORY_SIZE" },
+ { 0x00800000, "CTA_THREAD_DIMENSION_ZERO" },
+ { 0x01000000, "MEMORY_WINDOW_OVERLAP" },
{ 0x02000000, "SHARED_CONFIG_TOO_SMALL" },
{ 0x04000000, "TOTAL_REGISTER_COUNT" },
{}
@@ -1005,12 +1071,16 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
{
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
+ char error[128];
u32 trap = nvkm_rd32(device, 0x400108);
int rop, gpc;
if (trap & 0x00000001) {
u32 stat = nvkm_rd32(device, 0x404000);
- nvkm_error(subdev, "DISPATCH %08x\n", stat);
+
+ nvkm_snprintbf(error, sizeof(error), gf100_dispatch_error,
+ stat & 0x3fffffff);
+ nvkm_error(subdev, "DISPATCH %08x [%s]\n", stat, error);
nvkm_wr32(device, 0x404000, 0xc0000000);
nvkm_wr32(device, 0x400108, 0x00000001);
trap &= ~0x00000001;
@@ -1018,7 +1088,11 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
if (trap & 0x00000002) {
u32 stat = nvkm_rd32(device, 0x404600);
- nvkm_error(subdev, "M2MF %08x\n", stat);
+
+ nvkm_snprintbf(error, sizeof(error), gf100_m2mf_error,
+ stat & 0x3fffffff);
+ nvkm_error(subdev, "M2MF %08x [%s]\n", stat, error);
+
nvkm_wr32(device, 0x404600, 0xc0000000);
nvkm_wr32(device, 0x400108, 0x00000002);
trap &= ~0x00000002;
@@ -1026,7 +1100,10 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
if (trap & 0x00000008) {
u32 stat = nvkm_rd32(device, 0x408030);
- nvkm_error(subdev, "CCACHE %08x\n", stat);
+
+ nvkm_snprintbf(error, sizeof(error), gf100_m2mf_error,
+ stat & 0x3fffffff);
+ nvkm_error(subdev, "CCACHE %08x [%s]\n", stat, error);
nvkm_wr32(device, 0x408030, 0xc0000000);
nvkm_wr32(device, 0x400108, 0x00000008);
trap &= ~0x00000008;
@@ -1034,7 +1111,8 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
if (trap & 0x00000010) {
u32 stat = nvkm_rd32(device, 0x405840);
- nvkm_error(subdev, "SHADER %08x\n", stat);
+ nvkm_error(subdev, "SHADER %08x, sph: 0x%06x, stage: 0x%02x\n",
+ stat, stat & 0xffffff, (stat >> 24) & 0x3f);
nvkm_wr32(device, 0x405840, 0xc0000000);
nvkm_wr32(device, 0x400108, 0x00000010);
trap &= ~0x00000010;
@@ -1042,7 +1120,11 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
if (trap & 0x00000040) {
u32 stat = nvkm_rd32(device, 0x40601c);
- nvkm_error(subdev, "UNK6 %08x\n", stat);
+
+ nvkm_snprintbf(error, sizeof(error), gf100_unk6_error,
+ stat & 0x3fffffff);
+ nvkm_error(subdev, "UNK6 %08x [%s]\n", stat, error);
+
nvkm_wr32(device, 0x40601c, 0xc0000000);
nvkm_wr32(device, 0x400108, 0x00000040);
trap &= ~0x00000040;
@@ -1050,7 +1132,16 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
if (trap & 0x00000080) {
u32 stat = nvkm_rd32(device, 0x404490);
- nvkm_error(subdev, "MACRO %08x\n", stat);
+ u32 pc = nvkm_rd32(device, 0x404494);
+ u32 op = nvkm_rd32(device, 0x40449c);
+
+ nvkm_snprintbf(error, sizeof(error), gf100_macro_error,
+ stat & 0x1fffffff);
+ nvkm_error(subdev, "MACRO %08x [%s], pc: 0x%03x%s, op: 0x%08x\n",
+ stat, error, pc & 0x7ff,
+ (pc & 0x10000000) ? "" : " (invalid)",
+ op);
+
nvkm_wr32(device, 0x404490, 0xc0000000);
nvkm_wr32(device, 0x400108, 0x00000080);
trap &= ~0x00000080;
@@ -1058,10 +1149,9 @@ gf100_gr_trap_intr(struct gf100_gr *gr)
if (trap & 0x00000100) {
u32 stat = nvkm_rd32(device, 0x407020) & 0x3fffffff;
- char sked[128];
- nvkm_snprintbf(sked, sizeof(sked), gk104_sked_error, stat);
- nvkm_error(subdev, "SKED: %08x [%s]\n", stat, sked);
+ nvkm_snprintbf(error, sizeof(error), gk104_sked_error, stat);
+ nvkm_error(subdev, "SKED: %08x [%s]\n", stat, error);
if (stat)
nvkm_wr32(device, 0x407020, 0x40000000);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
index 2721592d3031..f19fabef8d73 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
@@ -27,6 +27,8 @@
#include <core/option.h>
#include <nvif/class.h>
+#include <nvif/if0002.h>
+#include <nvif/if0003.h>
#include <nvif/ioctl.h>
#include <nvif/unpack.h>
@@ -210,10 +212,10 @@ nvkm_perfdom_init(struct nvkm_perfdom *dom, void *data, u32 size)
} *args = data;
struct nvkm_object *object = &dom->object;
struct nvkm_pm *pm = dom->perfmon->pm;
- int ret, i;
+ int ret = -ENOSYS, i;
nvif_ioctl(object, "perfdom init size %d\n", size);
- if (nvif_unvers(args->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
nvif_ioctl(object, "perfdom init\n");
} else
return ret;
@@ -240,10 +242,10 @@ nvkm_perfdom_sample(struct nvkm_perfdom *dom, void *data, u32 size)
} *args = data;
struct nvkm_object *object = &dom->object;
struct nvkm_pm *pm = dom->perfmon->pm;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(object, "perfdom sample size %d\n", size);
- if (nvif_unvers(args->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
nvif_ioctl(object, "perfdom sample\n");
} else
return ret;
@@ -264,10 +266,10 @@ nvkm_perfdom_read(struct nvkm_perfdom *dom, void *data, u32 size)
} *args = data;
struct nvkm_object *object = &dom->object;
struct nvkm_pm *pm = dom->perfmon->pm;
- int ret, i;
+ int ret = -ENOSYS, i;
nvif_ioctl(object, "perfdom read size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "perfdom read vers %d\n", args->v0.version);
} else
return ret;
@@ -374,10 +376,10 @@ nvkm_perfdom_new_(struct nvkm_perfmon *perfmon,
struct nvkm_perfctr *ctr[4] = {};
struct nvkm_perfdom *dom;
int c, s, m;
- int ret;
+ int ret = -ENOSYS;
nvif_ioctl(parent, "create perfdom size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n",
args->v0.version, args->v0.domain, args->v0.mode);
} else
@@ -439,10 +441,10 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon *perfmon,
struct nvkm_pm *pm = perfmon->pm;
struct nvkm_perfdom *dom;
u8 domain_nr;
- int di, ret;
+ int di, ret = -ENOSYS;
nvif_ioctl(object, "perfmon query domain size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "perfmon domain vers %d iter %02x\n",
args->v0.version, args->v0.iter);
di = (args->v0.iter & 0xff) - 1;
@@ -490,10 +492,10 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon *perfmon,
struct nvkm_perfsig *sig;
const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false);
const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all);
- int ret, si;
+ int ret = -ENOSYS, si;
nvif_ioctl(object, "perfmon query signal size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object,
"perfmon query signal vers %d dom %d iter %04x\n",
args->v0.version, args->v0.domain, args->v0.iter);
@@ -543,10 +545,10 @@ nvkm_perfmon_mthd_query_source(struct nvkm_perfmon *perfmon,
struct nvkm_perfsig *sig;
struct nvkm_perfsrc *src;
u8 source_nr = 0;
- int si, ret;
+ int si, ret = -ENOSYS;
nvif_ioctl(object, "perfmon query source size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object,
"perfmon source vers %d dom %d sig %02x iter %02x\n",
args->v0.version, args->v0.domain, args->v0.signal,
@@ -612,7 +614,7 @@ nvkm_perfmon_child_get(struct nvkm_object *object, int index,
struct nvkm_oclass *oclass)
{
if (index == 0) {
- oclass->base.oclass = NVIF_IOCTL_NEW_V0_PERFDOM;
+ oclass->base.oclass = NVIF_CLASS_PERFDOM;
oclass->base.minver = 0;
oclass->base.maxver = 0;
oclass->ctor = nvkm_perfmon_child_new;
@@ -679,7 +681,7 @@ nvkm_pm_oclass_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
static const struct nvkm_device_oclass
nvkm_pm_oclass = {
- .base.oclass = NVIF_IOCTL_NEW_V0_PERFMON,
+ .base.oclass = NVIF_CLASS_PERFMON,
.base.minver = -1,
.base.maxver = -1,
.ctor = nvkm_pm_oclass_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c
index d082f4f73a80..f28967065639 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c
@@ -53,9 +53,9 @@ nvkm_sw_chan_event_ctor(struct nvkm_object *object, void *data, u32 size,
union {
struct nvif_notify_uevent_req none;
} *req = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unvers(req->none)) {
+ if (!(ret = nvif_unvers(ret, &data, &size, req->none))) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
index b01ef7eca906..ea8f4247b628 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
@@ -28,8 +28,8 @@
#include <engine/disp.h>
#include <engine/fifo.h>
+#include <nvif/class.h>
#include <nvif/event.h>
-#include <nvif/ioctl.h>
/*******************************************************************************
* software context
@@ -143,7 +143,7 @@ static const struct nvkm_sw_func
gf100_sw = {
.chan_new = gf100_sw_chan_new,
.sclass = {
- { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_GF100 } },
+ { nvkm_nvsw_new, { -1, -1, NVIF_CLASS_SW_GF100 } },
{}
}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
index 445217ffa791..b6675fe1b0ce 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
@@ -27,6 +27,7 @@
#include "nvsw.h"
#include <nvif/class.h>
+#include <nvif/if0004.h>
#include <nvif/ioctl.h>
#include <nvif/unpack.h>
@@ -46,9 +47,9 @@ nv04_nvsw_mthd_get_ref(struct nvkm_nvsw *nvsw, void *data, u32 size)
union {
struct nv04_nvsw_get_ref_v0 v0;
} *args = data;
- int ret;
+ int ret = -ENOSYS;
- if (nvif_unpack(args->v0, 0, 0, false)) {
+ if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
args->v0.ref = atomic_read(&chan->ref);
}
@@ -126,7 +127,7 @@ static const struct nvkm_sw_func
nv04_sw = {
.chan_new = nv04_sw_chan_new,
.sclass = {
- { nv04_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV04 } },
+ { nv04_nvsw_new, { -1, -1, NVIF_CLASS_SW_NV04 } },
{}
}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
index adf70d92b244..09d22fcd194c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
@@ -25,7 +25,7 @@
#include "chan.h"
#include "nvsw.h"
-#include <nvif/ioctl.h>
+#include <nvif/class.h>
/*******************************************************************************
* software context
@@ -56,7 +56,7 @@ static const struct nvkm_sw_func
nv10_sw = {
.chan_new = nv10_sw_chan_new,
.sclass = {
- { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV10 } },
+ { nvkm_nvsw_new, { -1, -1, NVIF_CLASS_SW_NV10 } },
{}
}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
index a381196af69d..01573d187f2c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
@@ -28,8 +28,8 @@
#include <engine/fifo/chan.h>
#include <subdev/bar.h>
+#include <nvif/class.h>
#include <nvif/event.h>
-#include <nvif/ioctl.h>
/*******************************************************************************
* software context
@@ -136,7 +136,7 @@ static const struct nvkm_sw_func
nv50_sw = {
.chan_new = nv50_sw_chan_new,
.sclass = {
- { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV50 } },
+ { nvkm_nvsw_new, { -1, -1, NVIF_CLASS_SW_NV50 } },
{}
}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c
index 66cf986b9572..33dd03fff3c4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c
@@ -24,7 +24,7 @@
#include "nvsw.h"
#include "chan.h"
-#include <nvif/class.h>
+#include <nvif/if0004.h>
static int
nvkm_nvsw_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
@@ -41,7 +41,7 @@ nvkm_nvsw_ntfy_(struct nvkm_object *object, u32 mthd,
{
struct nvkm_nvsw *nvsw = nvkm_nvsw(object);
switch (mthd) {
- case NVSW_NTFY_UEVENT:
+ case NV04_NVSW_NTFY_UEVENT:
*pevent = &nvsw->chan->event;
return 0;
default:
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
index 8304b806f2a6..a8d5d67feeaf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
@@ -143,16 +143,19 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len,
switch (outp->type) {
case DCB_OUTPUT_DP:
switch (conf & 0x00e00000) {
- case 0x00000000:
+ case 0x00000000: /* 1.62 */
outp->dpconf.link_bw = 0x06;
break;
- case 0x00200000:
+ case 0x00200000: /* 2.7 */
outp->dpconf.link_bw = 0x0a;
break;
- case 0x00400000:
- default:
+ case 0x00400000: /* 5.4 */
outp->dpconf.link_bw = 0x14;
break;
+ case 0x00600000: /* 8.1 */
+ default:
+ outp->dpconf.link_bw = 0x1e;
+ break;
}
switch ((conf & 0x0f000000) >> 24) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
index aa7e33b42b30..636bfb665bb9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
@@ -24,6 +24,7 @@
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/perf.h>
+#include <subdev/pci.h>
u16
nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
@@ -145,6 +146,21 @@ nvbios_perfEp(struct nvkm_bios *bios, int idx,
break;
case 0x40:
info->voltage = nvbios_rd08(bios, perf + 0x02);
+ switch (nvbios_rd08(bios, perf + 0xb) & 0x3) {
+ case 0:
+ info->pcie_speed = NVKM_PCIE_SPEED_5_0;
+ break;
+ case 3:
+ case 1:
+ info->pcie_speed = NVKM_PCIE_SPEED_2_5;
+ break;
+ case 2:
+ info->pcie_speed = NVKM_PCIE_SPEED_8_0;
+ break;
+ default:
+ break;
+ }
+ info->pcie_width = 0xff;
break;
default:
return 0x0000;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
index dc8682c91cc7..889cce2eb727 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
@@ -176,6 +176,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
{
struct nvkm_subdev *subdev = &clk->subdev;
struct nvkm_ram *ram = subdev->device->fb->ram;
+ struct nvkm_pci *pci = subdev->device->pci;
struct nvkm_pstate *pstate;
int ret, idx = 0;
@@ -187,6 +188,8 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
nvkm_debug(subdev, "setting performance state %d\n", pstatei);
clk->pstate = pstatei;
+ nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width);
+
if (ram && ram->func->calc) {
int khz = pstate->base.domain[nv_clk_src_mem];
do {
@@ -330,6 +333,8 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx)
pstate->pstate = perfE.pstate;
pstate->fanspeed = perfE.fanspeed;
+ pstate->pcie_speed = perfE.pcie_speed;
+ pstate->pcie_width = perfE.pcie_width;
cstate->voltage = perfE.voltage;
cstate->domain[nv_clk_src_core] = perfE.core;
cstate->domain[nv_clk_src_shader] = perfE.shader;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
index a52b7e7fce41..78c449b417b7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
@@ -188,7 +188,7 @@ gf100_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
return read_clk(clk, 0x08);
case nv_clk_src_copy:
return read_clk(clk, 0x09);
- case nv_clk_src_daemon:
+ case nv_clk_src_pmu:
return read_clk(clk, 0x0c);
case nv_clk_src_vdec:
return read_clk(clk, 0x0e);
@@ -325,7 +325,7 @@ gf100_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate)
(ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) ||
(ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) ||
(ret = calc_clk(clk, cstate, 0x09, nv_clk_src_copy)) ||
- (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) ||
+ (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_pmu)) ||
(ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec)))
return ret;
@@ -447,7 +447,7 @@ gf100_clk = {
{ nv_clk_src_rop , 0x04 },
{ nv_clk_src_mem , 0x05, 0, "memory", 1000 },
{ nv_clk_src_vdec , 0x06 },
- { nv_clk_src_daemon , 0x0a },
+ { nv_clk_src_pmu , 0x0a },
{ nv_clk_src_hubk07 , 0x0b },
{ nv_clk_src_max }
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
index 396f7e4dad0a..975c401bccab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
@@ -209,7 +209,7 @@ gk104_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
return read_clk(clk, 0x07);
case nv_clk_src_hubk01:
return read_clk(clk, 0x08);
- case nv_clk_src_daemon:
+ case nv_clk_src_pmu:
return read_clk(clk, 0x0c);
case nv_clk_src_vdec:
return read_clk(clk, 0x0e);
@@ -346,7 +346,7 @@ gk104_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate)
(ret = calc_clk(clk, cstate, 0x02, nv_clk_src_hubk07)) ||
(ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) ||
(ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) ||
- (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) ||
+ (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_pmu)) ||
(ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec)))
return ret;
@@ -492,7 +492,7 @@ gk104_clk = {
{ nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
{ nv_clk_src_hubk01 , 0x05 },
{ nv_clk_src_vdec , 0x06 },
- { nv_clk_src_daemon , 0x07 },
+ { nv_clk_src_pmu , 0x07 },
{ nv_clk_src_max }
}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
index 254094ab7fb8..5da2aa8cc333 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
@@ -141,9 +141,8 @@ gk20a_pllg_calc_rate(struct gk20a_clk *clk)
rate = clk->parent_rate * clk->n;
divider = clk->m * pl_to_div[clk->pl];
- do_div(rate, divider);
- return rate / 2;
+ return rate / divider / 2;
}
static int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
index c233e3f653ce..056702ef69aa 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
@@ -158,7 +158,7 @@ gt215_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
return read_clk(clk, 0x20, false);
case nv_clk_src_vdec:
return read_clk(clk, 0x21, false);
- case nv_clk_src_daemon:
+ case nv_clk_src_pmu:
return read_clk(clk, 0x25, false);
case nv_clk_src_host:
hsrc = (nvkm_rd32(device, 0xc040) & 0x30000000) >> 28;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
index f5edfadb5b46..1b5fb02eab2a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
@@ -132,7 +132,7 @@ static const struct nvkm_enum vm_engine[] = {
{ 0x0000000b, "PCOUNTER" },
{ 0x0000000c, "SEMAPHORE_BG" },
{ 0x0000000d, "PCE0" },
- { 0x0000000e, "PDAEMON" },
+ { 0x0000000e, "PMU" },
{}
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
index 9df45030ff9f..1fa3ade468ae 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
@@ -216,11 +216,11 @@ r1373f4_fini(struct gk104_ramfuc *fuc)
ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16));
ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000);
if (ram->mode == 2) {
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002);
- ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000);
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000002);
+ ram_mask(fuc, 0x1373f4, 0x00001100, 0x00000000);
} else {
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001);
- ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000);
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001);
+ ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
}
ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
index de888fa62b3e..7e77a7466992 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
@@ -2,3 +2,4 @@ nvkm-y += nvkm/subdev/ibus/gf100.o
nvkm-y += nvkm/subdev/ibus/gf117.o
nvkm-y += nvkm/subdev/ibus/gk104.o
nvkm-y += nvkm/subdev/ibus/gk20a.o
+nvkm-y += nvkm/subdev/ibus/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
index ba33609f643c..b5cee3f89aaa 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
@@ -21,7 +21,7 @@
*
* Authors: Ben Skeggs
*/
-#include <subdev/ibus.h>
+#include "priv.h"
static void
gk104_ibus_intr_hub(struct nvkm_subdev *ibus, int i)
@@ -56,7 +56,7 @@ gk104_ibus_intr_gpc(struct nvkm_subdev *ibus, int i)
nvkm_mask(device, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000);
}
-static void
+void
gk104_ibus_intr(struct nvkm_subdev *ibus)
{
struct nvkm_device *device = ibus->device;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm204.c
new file mode 100644
index 000000000000..b3839dc254ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm204.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+static const struct nvkm_subdev_func
+gm204_ibus = {
+ .intr = gk104_ibus_intr,
+};
+
+int
+gm204_ibus_new(struct nvkm_device *device, int index,
+ struct nvkm_subdev **pibus)
+{
+ struct nvkm_subdev *ibus;
+ if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL)))
+ return -ENOMEM;
+ nvkm_subdev_ctor(&gm204_ibus, device, index, 0, ibus);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h
index 48e1b6365ce6..01caf798cf31 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h
@@ -4,4 +4,5 @@
#include <subdev/ibus.h>
void gf100_ibus_intr(struct nvkm_subdev *);
+void gk104_ibus_intr(struct nvkm_subdev *);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
index 14107b5b7811..4c20fec64d96 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
@@ -56,7 +56,6 @@ struct gk20a_instobj {
/* CPU mapping */
u32 *vaddr;
- struct list_head vaddr_node;
};
#define gk20a_instobj(p) container_of((p), struct gk20a_instobj, memory)
@@ -66,7 +65,6 @@ struct gk20a_instobj {
struct gk20a_instobj_dma {
struct gk20a_instobj base;
- u32 *cpuaddr;
dma_addr_t handle;
struct nvkm_mm_node r;
};
@@ -79,6 +77,11 @@ struct gk20a_instobj_dma {
struct gk20a_instobj_iommu {
struct gk20a_instobj base;
+ /* to link into gk20a_instmem::vaddr_lru */
+ struct list_head vaddr_node;
+ /* how many clients are using vaddr? */
+ u32 use_cpt;
+
/* will point to the higher half of pages */
dma_addr_t *dma_addrs;
/* array of base.mem->size pages (+ dma_addr_ts) */
@@ -107,8 +110,6 @@ struct gk20a_instmem {
/* Only used by DMA API */
struct dma_attrs attrs;
-
- void __iomem * (*cpu_map)(struct nvkm_memory *);
};
#define gk20a_instmem(p) container_of((p), struct gk20a_instmem, base)
@@ -130,70 +131,58 @@ gk20a_instobj_size(struct nvkm_memory *memory)
return (u64)gk20a_instobj(memory)->mem.size << 12;
}
-static void __iomem *
-gk20a_instobj_cpu_map_dma(struct nvkm_memory *memory)
-{
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
- struct gk20a_instobj_dma *node = gk20a_instobj_dma(memory);
- struct device *dev = node->base.imem->base.subdev.device->dev;
- int npages = nvkm_memory_size(memory) >> 12;
- struct page *pages[npages];
- int i;
-
- /* we shouldn't see a gk20a on anything but arm/arm64 anyways */
- /* phys_to_page does not exist on all platforms... */
- pages[0] = pfn_to_page(dma_to_phys(dev, node->handle) >> PAGE_SHIFT);
- for (i = 1; i < npages; i++)
- pages[i] = pages[0] + i;
-
- return vmap(pages, npages, VM_MAP, pgprot_writecombine(PAGE_KERNEL));
-#else
- BUG();
- return NULL;
-#endif
-}
-
-static void __iomem *
-gk20a_instobj_cpu_map_iommu(struct nvkm_memory *memory)
+/*
+ * Recycle the vaddr of obj. Must be called with gk20a_instmem::lock held.
+ */
+static void
+gk20a_instobj_iommu_recycle_vaddr(struct gk20a_instobj_iommu *obj)
{
- struct gk20a_instobj_iommu *node = gk20a_instobj_iommu(memory);
- int npages = nvkm_memory_size(memory) >> 12;
-
- return vmap(node->pages, npages, VM_MAP,
- pgprot_writecombine(PAGE_KERNEL));
+ struct gk20a_instmem *imem = obj->base.imem;
+ /* there should not be any user left... */
+ WARN_ON(obj->use_cpt);
+ list_del(&obj->vaddr_node);
+ vunmap(obj->base.vaddr);
+ obj->base.vaddr = NULL;
+ imem->vaddr_use -= nvkm_memory_size(&obj->base.memory);
+ nvkm_debug(&imem->base.subdev, "vaddr used: %x/%x\n", imem->vaddr_use,
+ imem->vaddr_max);
}
/*
- * Must be called while holding gk20a_instmem_lock
+ * Must be called while holding gk20a_instmem::lock
*/
static void
gk20a_instmem_vaddr_gc(struct gk20a_instmem *imem, const u64 size)
{
while (imem->vaddr_use + size > imem->vaddr_max) {
- struct gk20a_instobj *obj;
-
/* no candidate that can be unmapped, abort... */
if (list_empty(&imem->vaddr_lru))
break;
- obj = list_first_entry(&imem->vaddr_lru, struct gk20a_instobj,
- vaddr_node);
- list_del(&obj->vaddr_node);
- vunmap(obj->vaddr);
- obj->vaddr = NULL;
- imem->vaddr_use -= nvkm_memory_size(&obj->memory);
- nvkm_debug(&imem->base.subdev, "(GC) vaddr used: %x/%x\n",
- imem->vaddr_use, imem->vaddr_max);
-
+ gk20a_instobj_iommu_recycle_vaddr(
+ list_first_entry(&imem->vaddr_lru,
+ struct gk20a_instobj_iommu, vaddr_node));
}
}
static void __iomem *
-gk20a_instobj_acquire(struct nvkm_memory *memory)
+gk20a_instobj_acquire_dma(struct nvkm_memory *memory)
{
struct gk20a_instobj *node = gk20a_instobj(memory);
struct gk20a_instmem *imem = node->imem;
struct nvkm_ltc *ltc = imem->base.subdev.device->ltc;
+
+ nvkm_ltc_flush(ltc);
+
+ return node->vaddr;
+}
+
+static void __iomem *
+gk20a_instobj_acquire_iommu(struct nvkm_memory *memory)
+{
+ struct gk20a_instobj_iommu *node = gk20a_instobj_iommu(memory);
+ struct gk20a_instmem *imem = node->base.imem;
+ struct nvkm_ltc *ltc = imem->base.subdev.device->ltc;
const u64 size = nvkm_memory_size(memory);
unsigned long flags;
@@ -201,19 +190,21 @@ gk20a_instobj_acquire(struct nvkm_memory *memory)
spin_lock_irqsave(&imem->lock, flags);
- if (node->vaddr) {
- /* remove us from the LRU list since we cannot be unmapped */
- list_del(&node->vaddr_node);
-
+ if (node->base.vaddr) {
+ if (!node->use_cpt) {
+ /* remove from LRU list since mapping in use again */
+ list_del(&node->vaddr_node);
+ }
goto out;
}
/* try to free some address space if we reached the limit */
gk20a_instmem_vaddr_gc(imem, size);
- node->vaddr = imem->cpu_map(memory);
-
- if (!node->vaddr) {
+ /* map the pages */
+ node->base.vaddr = vmap(node->pages, size >> PAGE_SHIFT, VM_MAP,
+ pgprot_writecombine(PAGE_KERNEL));
+ if (!node->base.vaddr) {
nvkm_error(&imem->base.subdev, "cannot map instobj - "
"this is not going to end well...\n");
goto out;
@@ -224,24 +215,41 @@ gk20a_instobj_acquire(struct nvkm_memory *memory)
imem->vaddr_use, imem->vaddr_max);
out:
+ node->use_cpt++;
spin_unlock_irqrestore(&imem->lock, flags);
- return node->vaddr;
+ return node->base.vaddr;
}
static void
-gk20a_instobj_release(struct nvkm_memory *memory)
+gk20a_instobj_release_dma(struct nvkm_memory *memory)
{
struct gk20a_instobj *node = gk20a_instobj(memory);
struct gk20a_instmem *imem = node->imem;
struct nvkm_ltc *ltc = imem->base.subdev.device->ltc;
+
+ nvkm_ltc_invalidate(ltc);
+}
+
+static void
+gk20a_instobj_release_iommu(struct nvkm_memory *memory)
+{
+ struct gk20a_instobj_iommu *node = gk20a_instobj_iommu(memory);
+ struct gk20a_instmem *imem = node->base.imem;
+ struct nvkm_ltc *ltc = imem->base.subdev.device->ltc;
unsigned long flags;
spin_lock_irqsave(&imem->lock, flags);
- /* add ourselves to the LRU list so our CPU mapping can be freed */
- list_add_tail(&node->vaddr_node, &imem->vaddr_lru);
+ /* we should at least have one user to release... */
+ if (WARN_ON(node->use_cpt == 0))
+ goto out;
+
+ /* add unused objs to the LRU list to recycle their mapping */
+ if (--node->use_cpt == 0)
+ list_add_tail(&node->vaddr_node, &imem->vaddr_lru);
+out:
spin_unlock_irqrestore(&imem->lock, flags);
wmb();
@@ -272,37 +280,6 @@ gk20a_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset)
nvkm_vm_map_at(vma, offset, &node->mem);
}
-/*
- * Clear the CPU mapping of an instobj if it exists
- */
-static void
-gk20a_instobj_dtor(struct gk20a_instobj *node)
-{
- struct gk20a_instmem *imem = node->imem;
- struct gk20a_instobj *obj;
- unsigned long flags;
-
- spin_lock_irqsave(&imem->lock, flags);
-
- if (!node->vaddr)
- goto out;
-
- list_for_each_entry(obj, &imem->vaddr_lru, vaddr_node) {
- if (obj == node) {
- list_del(&obj->vaddr_node);
- break;
- }
- }
- vunmap(node->vaddr);
- node->vaddr = NULL;
- imem->vaddr_use -= nvkm_memory_size(&node->memory);
- nvkm_debug(&imem->base.subdev, "vaddr used: %x/%x\n",
- imem->vaddr_use, imem->vaddr_max);
-
-out:
- spin_unlock_irqrestore(&imem->lock, flags);
-}
-
static void *
gk20a_instobj_dtor_dma(struct nvkm_memory *memory)
{
@@ -310,12 +287,10 @@ gk20a_instobj_dtor_dma(struct nvkm_memory *memory)
struct gk20a_instmem *imem = node->base.imem;
struct device *dev = imem->base.subdev.device->dev;
- gk20a_instobj_dtor(&node->base);
-
- if (unlikely(!node->cpuaddr))
+ if (unlikely(!node->base.vaddr))
goto out;
- dma_free_attrs(dev, node->base.mem.size << PAGE_SHIFT, node->cpuaddr,
+ dma_free_attrs(dev, node->base.mem.size << PAGE_SHIFT, node->base.vaddr,
node->handle, &imem->attrs);
out:
@@ -329,13 +304,20 @@ gk20a_instobj_dtor_iommu(struct nvkm_memory *memory)
struct gk20a_instmem *imem = node->base.imem;
struct device *dev = imem->base.subdev.device->dev;
struct nvkm_mm_node *r;
+ unsigned long flags;
int i;
- gk20a_instobj_dtor(&node->base);
-
if (unlikely(list_empty(&node->base.mem.regions)))
goto out;
+ spin_lock_irqsave(&imem->lock, flags);
+
+ /* vaddr has already been recycled */
+ if (node->base.vaddr)
+ gk20a_instobj_iommu_recycle_vaddr(node);
+
+ spin_unlock_irqrestore(&imem->lock, flags);
+
r = list_first_entry(&node->base.mem.regions, struct nvkm_mm_node,
rl_entry);
@@ -366,8 +348,8 @@ gk20a_instobj_func_dma = {
.target = gk20a_instobj_target,
.addr = gk20a_instobj_addr,
.size = gk20a_instobj_size,
- .acquire = gk20a_instobj_acquire,
- .release = gk20a_instobj_release,
+ .acquire = gk20a_instobj_acquire_dma,
+ .release = gk20a_instobj_release_dma,
.rd32 = gk20a_instobj_rd32,
.wr32 = gk20a_instobj_wr32,
.map = gk20a_instobj_map,
@@ -379,8 +361,8 @@ gk20a_instobj_func_iommu = {
.target = gk20a_instobj_target,
.addr = gk20a_instobj_addr,
.size = gk20a_instobj_size,
- .acquire = gk20a_instobj_acquire,
- .release = gk20a_instobj_release,
+ .acquire = gk20a_instobj_acquire_iommu,
+ .release = gk20a_instobj_release_iommu,
.rd32 = gk20a_instobj_rd32,
.wr32 = gk20a_instobj_wr32,
.map = gk20a_instobj_map,
@@ -400,10 +382,10 @@ gk20a_instobj_ctor_dma(struct gk20a_instmem *imem, u32 npages, u32 align,
nvkm_memory_ctor(&gk20a_instobj_func_dma, &node->base.memory);
- node->cpuaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT,
- &node->handle, GFP_KERNEL,
- &imem->attrs);
- if (!node->cpuaddr) {
+ node->base.vaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT,
+ &node->handle, GFP_KERNEL,
+ &imem->attrs);
+ if (!node->base.vaddr) {
nvkm_error(subdev, "cannot allocate DMA memory\n");
return -ENOMEM;
}
@@ -609,18 +591,14 @@ gk20a_instmem_new(struct nvkm_device *device, int index,
imem->mm = &tdev->iommu.mm;
imem->domain = tdev->iommu.domain;
imem->iommu_pgshift = tdev->iommu.pgshift;
- imem->cpu_map = gk20a_instobj_cpu_map_iommu;
imem->iommu_bit = tdev->func->iommu_bit;
nvkm_info(&imem->base.subdev, "using IOMMU\n");
} else {
init_dma_attrs(&imem->attrs);
- /* We will access the memory through our own mapping */
dma_set_attr(DMA_ATTR_NON_CONSISTENT, &imem->attrs);
dma_set_attr(DMA_ATTR_WEAK_ORDERING, &imem->attrs);
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &imem->attrs);
- dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &imem->attrs);
- imem->cpu_map = gk20a_instobj_cpu_map_dma;
nvkm_info(&imem->base.subdev, "using DMA API\n");
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
index e5df3d865f0c..f8108df3cb38 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
@@ -2,3 +2,4 @@ nvkm-y += nvkm/subdev/ltc/base.o
nvkm-y += nvkm/subdev/ltc/gf100.o
nvkm-y += nvkm/subdev/ltc/gk104.o
nvkm-y += nvkm/subdev/ltc/gm107.o
+nvkm-y += nvkm/subdev/ltc/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
index 3043bbfd7384..2af1f9e100fc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
@@ -26,16 +26,16 @@
#include <subdev/fb.h>
#include <subdev/timer.h>
-static void
+void
gm107_ltc_cbc_clear(struct nvkm_ltc *ltc, u32 start, u32 limit)
{
struct nvkm_device *device = ltc->subdev.device;
nvkm_wr32(device, 0x17e270, start);
nvkm_wr32(device, 0x17e274, limit);
- nvkm_wr32(device, 0x17e26c, 0x00000004);
+ nvkm_mask(device, 0x17e26c, 0x00000000, 0x00000004);
}
-static void
+void
gm107_ltc_cbc_wait(struct nvkm_ltc *ltc)
{
struct nvkm_device *device = ltc->subdev.device;
@@ -51,7 +51,7 @@ gm107_ltc_cbc_wait(struct nvkm_ltc *ltc)
}
}
-static void
+void
gm107_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4])
{
struct nvkm_device *device = ltc->subdev.device;
@@ -62,7 +62,7 @@ gm107_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4])
nvkm_wr32(device, 0x17e348, color[3]);
}
-static void
+void
gm107_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth)
{
struct nvkm_device *device = ltc->subdev.device;
@@ -84,7 +84,7 @@ gm107_ltc_lts_isr(struct nvkm_ltc *ltc, int c, int s)
}
}
-static void
+void
gm107_ltc_intr(struct nvkm_ltc *ltc)
{
struct nvkm_device *device = ltc->subdev.device;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm204.c
new file mode 100644
index 000000000000..5ad6fb9d022d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm204.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+static int
+gm204_ltc_oneinit(struct nvkm_ltc *ltc)
+{
+ struct nvkm_device *device = ltc->subdev.device;
+
+ ltc->ltc_nr = nvkm_rd32(device, 0x12006c);
+ ltc->lts_nr = nvkm_rd32(device, 0x17e280) >> 28;
+
+ return gf100_ltc_oneinit_tag_ram(ltc);
+}
+static void
+gm204_ltc_init(struct nvkm_ltc *ltc)
+{
+ nvkm_wr32(ltc->subdev.device, 0x17e278, ltc->tag_base);
+}
+
+static const struct nvkm_ltc_func
+gm204_ltc = {
+ .oneinit = gm204_ltc_oneinit,
+ .init = gm204_ltc_init,
+ .intr = gm107_ltc_intr, /*XXX: not validated */
+ .cbc_clear = gm107_ltc_cbc_clear,
+ .cbc_wait = gm107_ltc_cbc_wait,
+ .zbc = 16,
+ .zbc_clear_color = gm107_ltc_zbc_clear_color,
+ .zbc_clear_depth = gm107_ltc_zbc_clear_depth,
+ .invalidate = gf100_ltc_invalidate,
+ .flush = gf100_ltc_flush,
+};
+
+int
+gm204_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc)
+{
+ return nvkm_ltc_new_(&gm204_ltc, device, index, pltc);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
index 4e3755b82769..6d81c695ed0d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
@@ -31,4 +31,10 @@ void gf100_ltc_zbc_clear_color(struct nvkm_ltc *, int, const u32[4]);
void gf100_ltc_zbc_clear_depth(struct nvkm_ltc *, int, const u32);
void gf100_ltc_invalidate(struct nvkm_ltc *);
void gf100_ltc_flush(struct nvkm_ltc *);
+
+void gm107_ltc_intr(struct nvkm_ltc *);
+void gm107_ltc_cbc_clear(struct nvkm_ltc *, u32, u32);
+void gm107_ltc_cbc_wait(struct nvkm_ltc *);
+void gm107_ltc_zbc_clear_color(struct nvkm_ltc *, int, const u32[4]);
+void gm107_ltc_zbc_clear_depth(struct nvkm_ltc *, int, const u32);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
index 4476ef75acd6..3c2519fdeb81 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
@@ -1,5 +1,6 @@
nvkm-y += nvkm/subdev/pci/agp.o
nvkm-y += nvkm/subdev/pci/base.o
+nvkm-y += nvkm/subdev/pci/pcie.o
nvkm-y += nvkm/subdev/pci/nv04.o
nvkm-y += nvkm/subdev/pci/nv40.o
nvkm-y += nvkm/subdev/pci/nv46.o
@@ -7,3 +8,5 @@ nvkm-y += nvkm/subdev/pci/nv4c.o
nvkm-y += nvkm/subdev/pci/g84.o
nvkm-y += nvkm/subdev/pci/g94.o
nvkm-y += nvkm/subdev/pci/gf100.o
+nvkm-y += nvkm/subdev/pci/gf106.o
+nvkm-y += nvkm/subdev/pci/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
index d671dcfaff3c..65057c8310a2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
@@ -107,6 +107,15 @@ nvkm_pci_preinit(struct nvkm_subdev *subdev)
}
static int
+nvkm_pci_oneinit(struct nvkm_subdev *subdev)
+{
+ struct nvkm_pci *pci = nvkm_pci(subdev);
+ if (pci_is_pcie(pci->pdev))
+ return nvkm_pcie_oneinit(pci);
+ return 0;
+}
+
+static int
nvkm_pci_init(struct nvkm_subdev *subdev)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
@@ -117,6 +126,8 @@ nvkm_pci_init(struct nvkm_subdev *subdev)
ret = nvkm_agp_init(pci);
if (ret)
return ret;
+ } else if (pci_is_pcie(pci->pdev)) {
+ nvkm_pcie_init(pci);
}
if (pci->func->init)
@@ -143,6 +154,7 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev)
static const struct nvkm_subdev_func
nvkm_pci_func = {
.dtor = nvkm_pci_dtor,
+ .oneinit = nvkm_pci_oneinit,
.preinit = nvkm_pci_preinit,
.init = nvkm_pci_init,
.fini = nvkm_pci_fini,
@@ -160,6 +172,8 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
pci->func = func;
pci->pdev = device->func->pci(device)->pdev;
pci->irq = -1;
+ pci->pcie.speed = -1;
+ pci->pcie.width = -1;
if (device->type == NVKM_DEVICE_AGP)
nvkm_agp_ctor(pci);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c
index 3faa6bfb895b..62438d892f42 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c
@@ -25,6 +25,80 @@
#include <core/pci.h>
+static int
+g84_pcie_version_supported(struct nvkm_pci *pci)
+{
+ /* g84 and g86 report wrong information about what they support */
+ return 1;
+}
+
+int
+g84_pcie_version(struct nvkm_pci *pci)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ return (nvkm_rd32(device, 0x00154c) & 0x1) + 1;
+}
+
+void
+g84_pcie_set_version(struct nvkm_pci *pci, u8 ver)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ nvkm_mask(device, 0x00154c, 0x1, (ver >= 2 ? 0x1 : 0x0));
+}
+
+static void
+g84_pcie_set_cap_speed(struct nvkm_pci *pci, bool full_speed)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ nvkm_mask(device, 0x00154c, 0x80, full_speed ? 0x80 : 0x0);
+}
+
+enum nvkm_pcie_speed
+g84_pcie_cur_speed(struct nvkm_pci *pci)
+{
+ u32 reg_v = nvkm_pci_rd32(pci, 0x88) & 0x30000;
+ switch (reg_v) {
+ case 0x30000:
+ return NVKM_PCIE_SPEED_8_0;
+ case 0x20000:
+ return NVKM_PCIE_SPEED_5_0;
+ case 0x10000:
+ default:
+ return NVKM_PCIE_SPEED_2_5;
+ }
+}
+
+enum nvkm_pcie_speed
+g84_pcie_max_speed(struct nvkm_pci *pci)
+{
+ u32 reg_v = nvkm_pci_rd32(pci, 0x460) & 0x3300;
+ if (reg_v == 0x2200)
+ return NVKM_PCIE_SPEED_5_0;
+ return NVKM_PCIE_SPEED_2_5;
+}
+
+void
+g84_pcie_set_link_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed)
+{
+ u32 mask_value;
+
+ if (speed == NVKM_PCIE_SPEED_5_0)
+ mask_value = 0x20;
+ else
+ mask_value = 0x10;
+
+ nvkm_pci_mask(pci, 0x460, 0x30, mask_value);
+ nvkm_pci_mask(pci, 0x460, 0x1, 0x1);
+}
+
+int
+g84_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
+{
+ g84_pcie_set_cap_speed(pci, speed == NVKM_PCIE_SPEED_5_0);
+ g84_pcie_set_link_speed(pci, speed);
+ return 0;
+}
+
void
g84_pci_init(struct nvkm_pci *pci)
{
@@ -48,6 +122,14 @@ g84_pci_init(struct nvkm_pci *pci)
nvkm_pci_mask(pci, 0x041c, 0x00000060, 0x00000000);
}
+int
+g84_pcie_init(struct nvkm_pci *pci)
+{
+ bool full_speed = g84_pcie_cur_speed(pci) == NVKM_PCIE_SPEED_5_0;
+ g84_pcie_set_cap_speed(pci, full_speed);
+ return 0;
+}
+
static const struct nvkm_pci_func
g84_pci_func = {
.init = g84_pci_init,
@@ -55,6 +137,16 @@ g84_pci_func = {
.wr08 = nv40_pci_wr08,
.wr32 = nv40_pci_wr32,
.msi_rearm = nv46_pci_msi_rearm,
+
+ .pcie.init = g84_pcie_init,
+ .pcie.set_link = g84_pcie_set_link,
+
+ .pcie.max_speed = g84_pcie_max_speed,
+ .pcie.cur_speed = g84_pcie_cur_speed,
+
+ .pcie.set_version = g84_pcie_set_version,
+ .pcie.version = g84_pcie_version,
+ .pcie.version_supported = g84_pcie_version_supported,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c
index cd311ee311cc..43444123bc04 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c
@@ -23,6 +23,14 @@
*/
#include "priv.h"
+int
+g94_pcie_version_supported(struct nvkm_pci *pci)
+{
+ if ((nvkm_pci_rd32(pci, 0x460) & 0x200) == 0x200)
+ return 2;
+ return 1;
+}
+
static const struct nvkm_pci_func
g94_pci_func = {
.init = g84_pci_init,
@@ -30,6 +38,16 @@ g94_pci_func = {
.wr08 = nv40_pci_wr08,
.wr32 = nv40_pci_wr32,
.msi_rearm = nv40_pci_msi_rearm,
+
+ .pcie.init = g84_pcie_init,
+ .pcie.set_link = g84_pcie_set_link,
+
+ .pcie.max_speed = g84_pcie_max_speed,
+ .pcie.cur_speed = g84_pcie_cur_speed,
+
+ .pcie.set_version = g84_pcie_set_version,
+ .pcie.version = g84_pcie_version,
+ .pcie.version_supported = g94_pcie_version_supported,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c
index 25e1ae70867f..e30ea676baf6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c
@@ -29,6 +29,53 @@ gf100_pci_msi_rearm(struct nvkm_pci *pci)
nvkm_pci_wr08(pci, 0x0704, 0xff);
}
+void
+gf100_pcie_set_version(struct nvkm_pci *pci, u8 ver)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ nvkm_mask(device, 0x02241c, 0x1, ver > 1 ? 1 : 0);
+}
+
+int
+gf100_pcie_version(struct nvkm_pci *pci)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ return (nvkm_rd32(device, 0x02241c) & 0x1) + 1;
+}
+
+void
+gf100_pcie_set_cap_speed(struct nvkm_pci *pci, bool full_speed)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ nvkm_mask(device, 0x02241c, 0x80, full_speed ? 0x80 : 0x0);
+}
+
+int
+gf100_pcie_cap_speed(struct nvkm_pci *pci)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ u8 punits_pci_cap_speed = nvkm_rd32(device, 0x02241c) & 0x80;
+ if (punits_pci_cap_speed == 0x80)
+ return 1;
+ return 0;
+}
+
+int
+gf100_pcie_init(struct nvkm_pci *pci)
+{
+ bool full_speed = g84_pcie_cur_speed(pci) == NVKM_PCIE_SPEED_5_0;
+ gf100_pcie_set_cap_speed(pci, full_speed);
+ return 0;
+}
+
+int
+gf100_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
+{
+ gf100_pcie_set_cap_speed(pci, speed == NVKM_PCIE_SPEED_5_0);
+ g84_pcie_set_link_speed(pci, speed);
+ return 0;
+}
+
static const struct nvkm_pci_func
gf100_pci_func = {
.init = g84_pci_init,
@@ -36,6 +83,16 @@ gf100_pci_func = {
.wr08 = nv40_pci_wr08,
.wr32 = nv40_pci_wr32,
.msi_rearm = gf100_pci_msi_rearm,
+
+ .pcie.init = gf100_pcie_init,
+ .pcie.set_link = gf100_pcie_set_link,
+
+ .pcie.max_speed = g84_pcie_max_speed,
+ .pcie.cur_speed = g84_pcie_cur_speed,
+
+ .pcie.set_version = gf100_pcie_set_version,
+ .pcie.version = gf100_pcie_version,
+ .pcie.version_supported = g94_pcie_version_supported,
};
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf106.c
new file mode 100644
index 000000000000..c3b798c5c6dd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf106.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
+ *
+ * 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: Karol Herbst <nouveau@karolherbst.de>
+ */
+#include "priv.h"
+
+static const struct nvkm_pci_func
+gf106_pci_func = {
+ .init = g84_pci_init,
+ .rd32 = nv40_pci_rd32,
+ .wr08 = nv40_pci_wr08,
+ .wr32 = nv40_pci_wr32,
+ .msi_rearm = nv40_pci_msi_rearm,
+
+ .pcie.init = gf100_pcie_init,
+ .pcie.set_link = gf100_pcie_set_link,
+
+ .pcie.max_speed = g84_pcie_max_speed,
+ .pcie.cur_speed = g84_pcie_cur_speed,
+
+ .pcie.set_version = gf100_pcie_set_version,
+ .pcie.version = gf100_pcie_version,
+ .pcie.version_supported = g94_pcie_version_supported,
+};
+
+int
+gf106_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci)
+{
+ return nvkm_pci_new_(&gf106_pci_func, device, index, ppci);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gk104.c
new file mode 100644
index 000000000000..e68030507d88
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gk104.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
+ *
+ * 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: Karol Herbst <nouveau@karolherbst.de>
+ */
+#include "priv.h"
+
+static int
+gk104_pcie_version_supported(struct nvkm_pci *pci)
+{
+ return (nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x4) == 0x4 ? 2 : 1;
+}
+
+static void
+gk104_pcie_set_cap_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed)
+{
+ struct nvkm_device *device = pci->subdev.device;
+
+ switch (speed) {
+ case NVKM_PCIE_SPEED_2_5:
+ gf100_pcie_set_cap_speed(pci, false);
+ nvkm_mask(device, 0x8c1c0, 0x30000, 0x10000);
+ break;
+ case NVKM_PCIE_SPEED_5_0:
+ gf100_pcie_set_cap_speed(pci, true);
+ nvkm_mask(device, 0x8c1c0, 0x30000, 0x20000);
+ break;
+ case NVKM_PCIE_SPEED_8_0:
+ gf100_pcie_set_cap_speed(pci, true);
+ nvkm_mask(device, 0x8c1c0, 0x30000, 0x30000);
+ break;
+ }
+}
+
+static enum nvkm_pcie_speed
+gk104_pcie_cap_speed(struct nvkm_pci *pci)
+{
+ int speed = gf100_pcie_cap_speed(pci);
+
+ if (speed == 0)
+ return NVKM_PCIE_SPEED_2_5;
+
+ if (speed >= 1) {
+ int speed2 = nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x30000;
+ switch (speed2) {
+ case 0x00000:
+ case 0x10000:
+ return NVKM_PCIE_SPEED_2_5;
+ case 0x20000:
+ return NVKM_PCIE_SPEED_5_0;
+ case 0x30000:
+ return NVKM_PCIE_SPEED_8_0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void
+gk104_pcie_set_lnkctl_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed)
+{
+ u8 reg_v = 0;
+ switch (speed) {
+ case NVKM_PCIE_SPEED_2_5:
+ reg_v = 1;
+ break;
+ case NVKM_PCIE_SPEED_5_0:
+ reg_v = 2;
+ break;
+ case NVKM_PCIE_SPEED_8_0:
+ reg_v = 3;
+ break;
+ }
+ nvkm_pci_mask(pci, 0xa8, 0x3, reg_v);
+}
+
+static enum nvkm_pcie_speed
+gk104_pcie_lnkctl_speed(struct nvkm_pci *pci)
+{
+ u8 reg_v = nvkm_pci_rd32(pci, 0xa8) & 0x3;
+ switch (reg_v) {
+ case 0:
+ case 1:
+ return NVKM_PCIE_SPEED_2_5;
+ case 2:
+ return NVKM_PCIE_SPEED_5_0;
+ case 3:
+ return NVKM_PCIE_SPEED_8_0;
+ }
+ return -1;
+}
+
+static enum nvkm_pcie_speed
+gk104_pcie_max_speed(struct nvkm_pci *pci)
+{
+ u32 max_speed = nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x300000;
+ switch (max_speed) {
+ case 0x000000:
+ return NVKM_PCIE_SPEED_8_0;
+ case 0x100000:
+ return NVKM_PCIE_SPEED_5_0;
+ case 0x200000:
+ return NVKM_PCIE_SPEED_2_5;
+ }
+ return NVKM_PCIE_SPEED_2_5;
+}
+
+static void
+gk104_pcie_set_link_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed)
+{
+ struct nvkm_device *device = pci->subdev.device;
+ u32 mask_value;
+
+ switch (speed) {
+ case NVKM_PCIE_SPEED_8_0:
+ mask_value = 0x00000;
+ break;
+ case NVKM_PCIE_SPEED_5_0:
+ mask_value = 0x40000;
+ break;
+ case NVKM_PCIE_SPEED_2_5:
+ default:
+ mask_value = 0x80000;
+ break;
+ }
+
+ nvkm_mask(device, 0x8c040, 0xc0000, mask_value);
+ nvkm_mask(device, 0x8c040, 0x1, 0x1);
+}
+
+static int
+gk104_pcie_init(struct nvkm_pci * pci)
+{
+ enum nvkm_pcie_speed lnkctl_speed, max_speed, cap_speed;
+ struct nvkm_subdev *subdev = &pci->subdev;
+
+ if (gf100_pcie_version(pci) < 2)
+ return 0;
+
+ lnkctl_speed = gk104_pcie_lnkctl_speed(pci);
+ max_speed = gk104_pcie_max_speed(pci);
+ cap_speed = gk104_pcie_cap_speed(pci);
+
+ if (cap_speed != max_speed) {
+ nvkm_trace(subdev, "adjusting cap to max speed\n");
+ gk104_pcie_set_cap_speed(pci, max_speed);
+ cap_speed = gk104_pcie_cap_speed(pci);
+ if (cap_speed != max_speed)
+ nvkm_warn(subdev, "failed to adjust cap speed\n");
+ }
+
+ if (lnkctl_speed != max_speed) {
+ nvkm_debug(subdev, "adjusting lnkctl to max speed\n");
+ gk104_pcie_set_lnkctl_speed(pci, max_speed);
+ lnkctl_speed = gk104_pcie_lnkctl_speed(pci);
+ if (lnkctl_speed != max_speed)
+ nvkm_error(subdev, "failed to adjust lnkctl speed\n");
+ }
+
+ return 0;
+}
+
+static int
+gk104_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
+{
+ struct nvkm_subdev *subdev = &pci->subdev;
+ enum nvkm_pcie_speed lnk_ctl_speed = gk104_pcie_lnkctl_speed(pci);
+ enum nvkm_pcie_speed lnk_cap_speed = gk104_pcie_cap_speed(pci);
+
+ if (speed > lnk_cap_speed) {
+ speed = lnk_cap_speed;
+ nvkm_warn(subdev, "dropping requested speed due too low cap"
+ " speed\n");
+ }
+
+ if (speed > lnk_ctl_speed) {
+ speed = lnk_ctl_speed;
+ nvkm_warn(subdev, "dropping requested speed due too low"
+ " lnkctl speed\n");
+ }
+
+ gk104_pcie_set_link_speed(pci, speed);
+ return 0;
+}
+
+
+static const struct nvkm_pci_func
+gk104_pci_func = {
+ .init = g84_pci_init,
+ .rd32 = nv40_pci_rd32,
+ .wr08 = nv40_pci_wr08,
+ .wr32 = nv40_pci_wr32,
+ .msi_rearm = nv40_pci_msi_rearm,
+
+ .pcie.init = gk104_pcie_init,
+ .pcie.set_link = gk104_pcie_set_link,
+
+ .pcie.max_speed = gk104_pcie_max_speed,
+ .pcie.cur_speed = g84_pcie_cur_speed,
+
+ .pcie.set_version = gf100_pcie_set_version,
+ .pcie.version = gf100_pcie_version,
+ .pcie.version_supported = gk104_pcie_version_supported,
+};
+
+int
+gk104_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci)
+{
+ return nvkm_pci_new_(&gk104_pci_func, device, index, ppci);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c
new file mode 100644
index 000000000000..d71e5db5028a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/pcie.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
+ *
+ * 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: Karol Herbst <git@karolherbst.de>
+ */
+#include "priv.h"
+
+static char *nvkm_pcie_speeds[] = {
+ "2.5GT/s",
+ "5.0GT/s",
+ "8.0GT/s",
+};
+
+static enum nvkm_pcie_speed
+nvkm_pcie_speed(enum pci_bus_speed speed)
+{
+ switch (speed) {
+ case PCIE_SPEED_2_5GT:
+ return NVKM_PCIE_SPEED_2_5;
+ case PCIE_SPEED_5_0GT:
+ return NVKM_PCIE_SPEED_5_0;
+ case PCIE_SPEED_8_0GT:
+ return NVKM_PCIE_SPEED_8_0;
+ default:
+ /* XXX 0x16 is 8_0, assume 0x17 will be 16_0 for now */
+ if (speed == 0x17)
+ return NVKM_PCIE_SPEED_8_0;
+ return -1;
+ }
+}
+
+static int
+nvkm_pcie_get_version(struct nvkm_pci *pci)
+{
+ if (!pci->func->pcie.version)
+ return -ENOSYS;
+
+ return pci->func->pcie.version(pci);
+}
+
+static int
+nvkm_pcie_get_max_version(struct nvkm_pci *pci)
+{
+ if (!pci->func->pcie.version_supported)
+ return -ENOSYS;
+
+ return pci->func->pcie.version_supported(pci);
+}
+
+static int
+nvkm_pcie_set_version(struct nvkm_pci *pci, int version)
+{
+ if (!pci->func->pcie.set_version)
+ return -ENOSYS;
+
+ nvkm_trace(&pci->subdev, "set to version %i\n", version);
+ pci->func->pcie.set_version(pci, version);
+ return nvkm_pcie_get_version(pci);
+}
+
+int
+nvkm_pcie_oneinit(struct nvkm_pci *pci)
+{
+ if (pci->func->pcie.max_speed)
+ nvkm_debug(&pci->subdev, "pcie max speed: %s\n",
+ nvkm_pcie_speeds[pci->func->pcie.max_speed(pci)]);
+ return 0;
+}
+
+int
+nvkm_pcie_init(struct nvkm_pci *pci)
+{
+ struct nvkm_subdev *subdev = &pci->subdev;
+ int ret;
+
+ /* raise pcie version first */
+ ret = nvkm_pcie_get_version(pci);
+ if (ret > 0) {
+ int max_version = nvkm_pcie_get_max_version(pci);
+ if (max_version > 0 && max_version > ret)
+ ret = nvkm_pcie_set_version(pci, max_version);
+
+ if (ret < max_version)
+ nvkm_error(subdev, "couldn't raise version: %i\n", ret);
+ }
+
+ if (pci->func->pcie.init)
+ pci->func->pcie.init(pci);
+
+ if (pci->pcie.speed != -1)
+ nvkm_pcie_set_link(pci, pci->pcie.speed, pci->pcie.width);
+
+ return 0;
+}
+
+int
+nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
+{
+ struct nvkm_subdev *subdev = &pci->subdev;
+ enum nvkm_pcie_speed cur_speed, max_speed;
+ struct pci_bus *pbus;
+ int ret;
+
+ if (!pci || !pci_is_pcie(pci->pdev))
+ return 0;
+ pbus = pci->pdev->bus;
+
+ if (!pci->func->pcie.set_link)
+ return -ENOSYS;
+
+ nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]);
+
+ if (pci->func->pcie.version(pci) < 2) {
+ nvkm_error(subdev, "setting link failed due to low version\n");
+ return -ENODEV;
+ }
+
+ cur_speed = pci->func->pcie.cur_speed(pci);
+ max_speed = min(nvkm_pcie_speed(pbus->max_bus_speed),
+ pci->func->pcie.max_speed(pci));
+
+ nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]);
+
+ if (speed > max_speed) {
+ nvkm_debug(subdev, "%s not supported by bus or card, dropping"
+ "requested speed to %s", nvkm_pcie_speeds[speed],
+ nvkm_pcie_speeds[max_speed]);
+ speed = max_speed;
+ }
+
+ pci->pcie.speed = speed;
+ pci->pcie.width = width;
+
+ if (speed == cur_speed) {
+ nvkm_debug(subdev, "requested matches current speed\n");
+ return speed;
+ }
+
+ nvkm_debug(subdev, "set link to %s x%i\n",
+ nvkm_pcie_speeds[speed], width);
+
+ ret = pci->func->pcie.set_link(pci, speed, width);
+ if (ret < 0)
+ nvkm_error(subdev, "setting link failed: %i\n", ret);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h
index cf46d38d0b0a..23de3180aae5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h
@@ -12,6 +12,18 @@ struct nvkm_pci_func {
void (*wr08)(struct nvkm_pci *, u16 addr, u8 data);
void (*wr32)(struct nvkm_pci *, u16 addr, u32 data);
void (*msi_rearm)(struct nvkm_pci *);
+
+ struct {
+ int (*init)(struct nvkm_pci *);
+ int (*set_link)(struct nvkm_pci *, enum nvkm_pcie_speed, u8);
+
+ enum nvkm_pcie_speed (*max_speed)(struct nvkm_pci *);
+ enum nvkm_pcie_speed (*cur_speed)(struct nvkm_pci *);
+
+ void (*set_version)(struct nvkm_pci *, u8);
+ int (*version)(struct nvkm_pci *);
+ int (*version_supported)(struct nvkm_pci *);
+ } pcie;
};
u32 nv40_pci_rd32(struct nvkm_pci *, u16);
@@ -22,4 +34,25 @@ void nv40_pci_msi_rearm(struct nvkm_pci *);
void nv46_pci_msi_rearm(struct nvkm_pci *);
void g84_pci_init(struct nvkm_pci *pci);
+
+/* pcie functions */
+void g84_pcie_set_version(struct nvkm_pci *, u8);
+int g84_pcie_version(struct nvkm_pci *);
+void g84_pcie_set_link_speed(struct nvkm_pci *, enum nvkm_pcie_speed);
+enum nvkm_pcie_speed g84_pcie_cur_speed(struct nvkm_pci *);
+enum nvkm_pcie_speed g84_pcie_max_speed(struct nvkm_pci *);
+int g84_pcie_init(struct nvkm_pci *);
+int g84_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8);
+
+int g94_pcie_version_supported(struct nvkm_pci *);
+
+void gf100_pcie_set_version(struct nvkm_pci *, u8);
+int gf100_pcie_version(struct nvkm_pci *);
+void gf100_pcie_set_cap_speed(struct nvkm_pci *, bool);
+int gf100_pcie_cap_speed(struct nvkm_pci *);
+int gf100_pcie_init(struct nvkm_pci *);
+int gf100_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8);
+
+int nvkm_pcie_oneinit(struct nvkm_pci *);
+int nvkm_pcie_init(struct nvkm_pci *);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
index 302557c52d03..770294457274 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
@@ -24,8 +24,8 @@ uint32_t gf100_pmu_data[] = {
0x00000000,
/* 0x0058: proc_list_head */
0x54534f48,
- 0x00000512,
- 0x000004af,
+ 0x00000507,
+ 0x000004a4,
0x00000000,
0x00000000,
0x00000000,
@@ -46,8 +46,8 @@ uint32_t gf100_pmu_data[] = {
0x00000000,
0x00000000,
0x584d454d,
- 0x0000075e,
- 0x00000750,
+ 0x00000753,
+ 0x00000745,
0x00000000,
0x00000000,
0x00000000,
@@ -68,8 +68,8 @@ uint32_t gf100_pmu_data[] = {
0x00000000,
0x00000000,
0x46524550,
- 0x00000762,
- 0x00000760,
+ 0x00000757,
+ 0x00000755,
0x00000000,
0x00000000,
0x00000000,
@@ -90,8 +90,8 @@ uint32_t gf100_pmu_data[] = {
0x00000000,
0x00000000,
0x5f433249,
- 0x00000b92,
- 0x00000a35,
+ 0x00000b87,
+ 0x00000a2a,
0x00000000,
0x00000000,
0x00000000,
@@ -112,8 +112,8 @@ uint32_t gf100_pmu_data[] = {
0x00000000,
0x00000000,
0x54534554,
- 0x00000bbb,
- 0x00000b94,
+ 0x00000bb0,
+ 0x00000b89,
0x00000000,
0x00000000,
0x00000000,
@@ -134,8 +134,8 @@ uint32_t gf100_pmu_data[] = {
0x00000000,
0x00000000,
0x454c4449,
- 0x00000bc7,
- 0x00000bc5,
+ 0x00000bbc,
+ 0x00000bba,
0x00000000,
0x00000000,
0x00000000,
@@ -229,26 +229,26 @@ uint32_t gf100_pmu_data[] = {
/* 0x0370: memx_func_head */
0x00000001,
0x00000000,
- 0x00000551,
+ 0x00000546,
/* 0x037c: memx_func_next */
0x00000002,
0x00000000,
- 0x000005db,
+ 0x000005d0,
0x00000003,
0x00000002,
- 0x000006a5,
+ 0x0000069a,
0x00040004,
0x00000000,
- 0x000006c1,
+ 0x000006b6,
0x00010005,
0x00000000,
- 0x000006de,
+ 0x000006d3,
0x00010006,
0x00000000,
- 0x00000663,
+ 0x00000658,
0x00000007,
0x00000000,
- 0x000006e9,
+ 0x000006de,
/* 0x03c4: memx_func_tail */
/* 0x03c4: memx_ts_start */
0x00000000,
@@ -917,7 +917,7 @@ uint32_t gf100_pmu_data[] = {
};
uint32_t gf100_pmu_code[] = {
- 0x039e0ef5,
+ 0x03930ef5,
/* 0x0004: rd32 */
0x07a007f1,
0xd00604b6,
@@ -987,7 +987,7 @@ uint32_t gf100_pmu_code[] = {
0xbb9a0a98,
0x1cf4029a,
0x01d7f00f,
- 0x02dd21f5,
+ 0x02d221f5,
0x0ef494bd,
/* 0x00f9: intr_watchdog_next_time */
0x9b0a9815,
@@ -1039,7 +1039,7 @@ uint32_t gf100_pmu_code[] = {
0x48e7f1c0,
0x53e3f14f,
0x00d7f054,
- 0x034221f5,
+ 0x033721f5,
0x07f1c0fc,
0x04b604c0,
0x000cd006,
@@ -1048,760 +1048,758 @@ uint32_t gf100_pmu_code[] = {
0x04b60688,
0x0009d006,
/* 0x01ca: intr_skip_subintr */
- 0x89c404bd,
- 0x070bf420,
- 0xffbfa4f1,
-/* 0x01d4: intr_skip_pause */
- 0xf44089c4,
- 0xa4f1070b,
-/* 0x01de: intr_skip_user0 */
- 0x07f0ffbf,
- 0x0604b604,
- 0xbd0008d0,
- 0xfe80fc04,
- 0xf0fc0088,
- 0xd0fce0fc,
- 0xb0fcc0fc,
- 0x90fca0fc,
- 0x00fc80fc,
- 0xf80032f4,
-/* 0x0205: ticks_from_ns */
- 0xf9c0f901,
- 0xcbd7f1b0,
- 0x00d3f000,
- 0x041321f5,
- 0x03e8ccec,
- 0xf400b4b0,
- 0xeeec120b,
- 0xd7f103e8,
- 0xd3f000cb,
- 0x1321f500,
-/* 0x022d: ticks_from_ns_quit */
- 0x02ceb904,
- 0xc0fcb0fc,
-/* 0x0236: ticks_from_us */
- 0xc0f900f8,
+ 0x97f104bd,
+ 0x90bd00e0,
+ 0xf00489fd,
+ 0x04b60407,
+ 0x0008d006,
+ 0x80fc04bd,
+ 0xfc0088fe,
+ 0xfce0fcf0,
+ 0xfcc0fcd0,
+ 0xfca0fcb0,
+ 0xfc80fc90,
+ 0x0032f400,
+/* 0x01fa: ticks_from_ns */
+ 0xc0f901f8,
0xd7f1b0f9,
0xd3f000cb,
- 0x1321f500,
- 0x02ceb904,
- 0xf400b4b0,
- 0xe4bd050b,
-/* 0x0250: ticks_from_us_quit */
- 0xc0fcb0fc,
-/* 0x0256: ticks_to_us */
- 0xd7f100f8,
- 0xd3f000cb,
- 0xecedff00,
-/* 0x0262: timer */
- 0x90f900f8,
- 0x32f480f9,
- 0x03f89810,
- 0xf40086b0,
- 0x84bd651c,
- 0xb63807f0,
- 0x08d00604,
- 0xf004bd00,
- 0x84b63487,
- 0x0088cf06,
- 0xbb9a0998,
- 0xe9bb0298,
- 0x03fe8000,
- 0xb60887f0,
- 0x88cf0684,
- 0x0284f000,
- 0xf0261bf4,
- 0x84b63487,
- 0x0088cf06,
- 0xf406e0b8,
- 0xe8b8090b,
- 0x111cf406,
-/* 0x02b8: timer_reset */
- 0xb63407f0,
- 0x0ed00604,
- 0x8004bd00,
-/* 0x02c6: timer_enable */
- 0x87f09a0e,
- 0x3807f001,
+ 0x0821f500,
+ 0xe8ccec04,
+ 0x00b4b003,
+ 0xec120bf4,
+ 0xf103e8ee,
+ 0xf000cbd7,
+ 0x21f500d3,
+/* 0x0222: ticks_from_ns_quit */
+ 0xceb90408,
+ 0xfcb0fc02,
+/* 0x022b: ticks_from_us */
+ 0xf900f8c0,
+ 0xf1b0f9c0,
+ 0xf000cbd7,
+ 0x21f500d3,
+ 0xceb90408,
+ 0x00b4b002,
+ 0xbd050bf4,
+/* 0x0245: ticks_from_us_quit */
+ 0xfcb0fce4,
+/* 0x024b: ticks_to_us */
+ 0xf100f8c0,
+ 0xf000cbd7,
+ 0xedff00d3,
+/* 0x0257: timer */
+ 0xf900f8ec,
+ 0xf480f990,
+ 0xf8981032,
+ 0x0086b003,
+ 0xbd651cf4,
+ 0x3807f084,
0xd00604b6,
0x04bd0008,
-/* 0x02d4: timer_done */
- 0xfc1031f4,
- 0xf890fc80,
-/* 0x02dd: send_proc */
- 0xf980f900,
- 0x05e89890,
- 0xf004e998,
- 0x89b80486,
- 0x2a0bf406,
- 0x940398c4,
- 0x80b60488,
- 0x008ebb18,
- 0x8000fa98,
- 0x8d80008a,
- 0x028c8001,
- 0xb6038b80,
- 0x94f00190,
- 0x04e98007,
-/* 0x0317: send_done */
- 0xfc0231f4,
- 0xf880fc90,
-/* 0x031d: find */
- 0xf080f900,
- 0x31f45887,
-/* 0x0325: find_loop */
- 0x008a9801,
- 0xf406aeb8,
- 0x80b6100b,
- 0x6886b158,
- 0xf01bf402,
-/* 0x033b: find_done */
- 0xb90132f4,
- 0x80fc028e,
-/* 0x0342: send */
- 0x21f500f8,
- 0x01f4031d,
-/* 0x034b: recv */
- 0xf900f897,
- 0x9880f990,
- 0xe99805e8,
- 0x0132f404,
- 0xf40689b8,
- 0x89c43d0b,
- 0x0180b603,
- 0x800784f0,
- 0xea9805e8,
- 0xfef0f902,
- 0xf0f9018f,
- 0x9402efb9,
- 0xe9bb0499,
- 0x18e0b600,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0xf0fca5f9,
- 0xf400f8fe,
- 0xf0fc0131,
-/* 0x0398: recv_done */
- 0x90fc80fc,
-/* 0x039e: init */
- 0x17f100f8,
- 0x14b60108,
- 0x0011cf06,
- 0x010911e7,
- 0xfe0814b6,
- 0x17f10014,
- 0x13f000e0,
- 0x1c07f000,
- 0xd00604b6,
- 0x04bd0001,
- 0xf0ff17f0,
- 0x04b61407,
- 0x0001d006,
- 0x17f004bd,
- 0x0015f102,
- 0x1007f008,
+ 0xb63487f0,
+ 0x88cf0684,
+ 0x9a099800,
+ 0xbb0298bb,
+ 0xfe8000e9,
+ 0x0887f003,
+ 0xcf0684b6,
+ 0x84f00088,
+ 0x261bf402,
+ 0xb63487f0,
+ 0x88cf0684,
+ 0x06e0b800,
+ 0xb8090bf4,
+ 0x1cf406e8,
+/* 0x02ad: timer_reset */
+ 0x3407f011,
0xd00604b6,
- 0x04bd0001,
- 0x011a17f1,
- 0xfe0013f0,
- 0x31f40010,
- 0x0117f010,
- 0xb63807f0,
+ 0x04bd000e,
+/* 0x02bb: timer_enable */
+ 0xf09a0e80,
+ 0x07f00187,
+ 0x0604b638,
+ 0xbd0008d0,
+/* 0x02c9: timer_done */
+ 0x1031f404,
+ 0x90fc80fc,
+/* 0x02d2: send_proc */
+ 0x80f900f8,
+ 0xe89890f9,
+ 0x04e99805,
+ 0xb80486f0,
+ 0x0bf40689,
+ 0x0398c42a,
+ 0xb6048894,
+ 0x8ebb1880,
+ 0x00fa9800,
+ 0x80008a80,
+ 0x8c80018d,
+ 0x038b8002,
+ 0xf00190b6,
+ 0xe9800794,
+ 0x0231f404,
+/* 0x030c: send_done */
+ 0x80fc90fc,
+/* 0x0312: find */
+ 0x80f900f8,
+ 0xf45887f0,
+/* 0x031a: find_loop */
+ 0x8a980131,
+ 0x06aeb800,
+ 0xb6100bf4,
+ 0x86b15880,
+ 0x1bf40268,
+ 0x0132f4f0,
+/* 0x0330: find_done */
+ 0xfc028eb9,
+/* 0x0337: send */
+ 0xf500f880,
+ 0xf4031221,
+ 0x00f89701,
+/* 0x0340: recv */
+ 0x80f990f9,
+ 0x9805e898,
+ 0x32f404e9,
+ 0x0689b801,
+ 0xc43d0bf4,
+ 0x80b60389,
+ 0x0784f001,
+ 0x9805e880,
+ 0xf0f902ea,
+ 0xf9018ffe,
+ 0x02efb9f0,
+ 0xbb049994,
+ 0xe0b600e9,
+ 0x03eb9818,
+ 0x9802ec98,
+ 0xee9801ed,
+ 0xfca5f900,
+ 0x00f8fef0,
+ 0xfc0131f4,
+/* 0x038d: recv_done */
+ 0xfc80fcf0,
+/* 0x0393: init */
+ 0xf100f890,
+ 0xb6010817,
+ 0x11cf0614,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf10014fe,
+ 0xf000e017,
+ 0x07f00013,
+ 0x0604b61c,
+ 0xbd0001d0,
+ 0xff17f004,
+ 0xb61407f0,
0x01d00604,
0xf004bd00,
-/* 0x0402: init_proc */
- 0xf19858f7,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x0413: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb9301dff,
- 0x34f10234,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0xe2ff01b4,
- 0x0234b930,
- 0xffff34f1,
- 0xb61034b6,
- 0xc3bb1045,
- 0x01b4bb00,
- 0xbb3012ff,
- 0x40fc00b3,
- 0x20fc30fc,
- 0x00f810fc,
-/* 0x0464: host_send */
- 0x04b017f1,
- 0xcf0614b6,
- 0x27f10011,
- 0x24b604a0,
- 0x0022cf06,
- 0xf40612b8,
- 0x1ec4320b,
- 0x04ee9407,
- 0x0270e0b7,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0x034221f5,
- 0xc40110b6,
- 0x07f10f1e,
- 0x04b604b0,
- 0x000ed006,
- 0x0ef404bd,
-/* 0x04ad: host_send_done */
-/* 0x04af: host_recv */
- 0xf100f8ba,
- 0xf14e4917,
- 0xb8525413,
- 0x0bf406e1,
-/* 0x04bd: host_recv_wait */
- 0xcc17f1aa,
+ 0x15f10217,
+ 0x07f00800,
+ 0x0604b610,
+ 0xbd0001d0,
+ 0x1a17f104,
+ 0x0013f001,
+ 0xf40010fe,
+ 0x17f01031,
+ 0x3807f001,
+ 0xd00604b6,
+ 0x04bd0001,
+/* 0x03f7: init_proc */
+ 0x9858f7f0,
+ 0x16b001f1,
+ 0xfa0bf400,
+ 0xf0b615f9,
+ 0xf20ef458,
+/* 0x0408: mulu32_32_64 */
+ 0x20f910f9,
+ 0x40f930f9,
+ 0x9510e195,
+ 0xc4bd10d2,
+ 0xedffb4bd,
+ 0x301dffc0,
+ 0xf10234b9,
+ 0xb6ffff34,
+ 0x45b61034,
+ 0x00c3bb10,
+ 0xff01b4bb,
+ 0x34b930e2,
+ 0xff34f102,
+ 0x1034b6ff,
+ 0xbb1045b6,
+ 0xb4bb00c3,
+ 0x3012ff01,
+ 0xfc00b3bb,
+ 0xfc30fc40,
+ 0xf810fc20,
+/* 0x0459: host_send */
+ 0xb017f100,
0x0614b604,
0xf10011cf,
- 0xb604c827,
+ 0xb604a027,
0x22cf0624,
- 0x0816f000,
- 0xf40612b8,
- 0x23c4e60b,
- 0x0434b607,
- 0x02f030b7,
- 0x80033b80,
- 0x3d80023c,
- 0x003e8001,
- 0xf00120b6,
- 0x07f10f24,
- 0x04b604c8,
- 0x0002d006,
- 0x27f004bd,
- 0x0007f040,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x0512: host_init */
- 0x17f100f8,
+ 0x0612b800,
+ 0xc4320bf4,
+ 0xee94071e,
+ 0x70e0b704,
+ 0x03eb9802,
+ 0x9802ec98,
+ 0xee9801ed,
+ 0x3721f500,
+ 0x0110b603,
+ 0xf10f1ec4,
+ 0xb604b007,
+ 0x0ed00604,
+ 0xf404bd00,
+/* 0x04a2: host_send_done */
+ 0x00f8ba0e,
+/* 0x04a4: host_recv */
+ 0x4e4917f1,
+ 0x525413f1,
+ 0xf406e1b8,
+/* 0x04b2: host_recv_wait */
+ 0x17f1aa0b,
+ 0x14b604cc,
+ 0x0011cf06,
+ 0x04c827f1,
+ 0xcf0624b6,
+ 0x16f00022,
+ 0x0612b808,
+ 0xc4e60bf4,
+ 0x34b60723,
+ 0xf030b704,
+ 0x033b8002,
+ 0x80023c80,
+ 0x3e80013d,
+ 0x0120b600,
+ 0xf10f24f0,
+ 0xb604c807,
+ 0x02d00604,
+ 0xf004bd00,
+ 0x07f04027,
+ 0x0604b600,
+ 0xbd0002d0,
+/* 0x0507: host_init */
+ 0xf100f804,
+ 0xb6008017,
+ 0x15f11014,
+ 0x07f10270,
+ 0x04b604d0,
+ 0x0001d006,
+ 0x17f104bd,
0x14b60080,
- 0x7015f110,
- 0xd007f102,
+ 0xf015f110,
+ 0xdc07f102,
0x0604b604,
0xbd0001d0,
- 0x8017f104,
- 0x1014b600,
- 0x02f015f1,
- 0x04dc07f1,
+ 0x0117f004,
+ 0x04c407f1,
0xd00604b6,
0x04bd0001,
- 0xf10117f0,
- 0xb604c407,
- 0x01d00604,
- 0xf804bd00,
-/* 0x0551: memx_func_enter */
- 0x2067f100,
- 0x5d77f116,
- 0xff73f1f5,
+/* 0x0546: memx_func_enter */
+ 0x67f100f8,
+ 0x77f11620,
+ 0x73f1f55d,
+ 0x6eb9ffff,
+ 0x0421f402,
+ 0xfd02d8b9,
+ 0x60f90487,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+ 0xfe77f13f,
+ 0xff73f1ff,
0x026eb9ff,
0xb90421f4,
0x87fd02d8,
0xf960f904,
0xfcd0fc80,
0x3f21f4e0,
- 0xfffe77f1,
- 0xffff73f1,
+ 0x26f067f1,
0xf4026eb9,
0xd8b90421,
0x0487fd02,
0x80f960f9,
0xe0fcd0fc,
- 0xf13f21f4,
- 0xb926f067,
- 0x21f4026e,
- 0x02d8b904,
- 0xf90487fd,
- 0xfc80f960,
- 0xf4e0fcd0,
- 0x67f03f21,
- 0xe007f104,
- 0x0604b607,
- 0xbd0006d0,
-/* 0x05bd: memx_func_enter_wait */
- 0xc067f104,
- 0x0664b607,
- 0xf00066cf,
- 0x0bf40464,
- 0x2c67f0f3,
- 0xcf0664b6,
- 0x06800066,
-/* 0x05db: memx_func_leave */
- 0xf000f8f1,
- 0x64b62c67,
- 0x0066cf06,
- 0xf0f20680,
+ 0xf03f21f4,
0x07f10467,
- 0x04b607e4,
+ 0x04b607e0,
0x0006d006,
-/* 0x05f6: memx_func_leave_wait */
+/* 0x05b2: memx_func_enter_wait */
0x67f104bd,
0x64b607c0,
0x0066cf06,
0xf40464f0,
- 0x67f1f31b,
- 0x77f126f0,
- 0x73f00001,
- 0x026eb900,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f905,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x162067f1,
- 0xf4026eb9,
- 0xd8b90421,
- 0x0587fd02,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0xf13f21f4,
- 0xf00aa277,
+ 0x67f0f30b,
+ 0x0664b62c,
+ 0x800066cf,
+ 0x00f8f106,
+/* 0x05d0: memx_func_leave */
+ 0xb62c67f0,
+ 0x66cf0664,
+ 0xf2068000,
+ 0xf10467f0,
+ 0xb607e407,
+ 0x06d00604,
+/* 0x05eb: memx_func_leave_wait */
+ 0xf104bd00,
+ 0xb607c067,
+ 0x66cf0664,
+ 0x0464f000,
+ 0xf1f31bf4,
+ 0xf126f067,
+ 0xf0000177,
0x6eb90073,
0x0421f402,
0xfd02d8b9,
0x60f90587,
0xd0fc80f9,
0x21f4e0fc,
-/* 0x0663: memx_func_wait_vblank */
- 0x9800f83f,
- 0x66b00016,
- 0x130bf400,
- 0xf40166b0,
- 0x0ef4060b,
-/* 0x0675: memx_func_wait_vblank_head1 */
- 0x2077f12e,
- 0x070ef400,
-/* 0x067c: memx_func_wait_vblank_head0 */
- 0x000877f1,
-/* 0x0680: memx_func_wait_vblank_0 */
- 0x07c467f1,
- 0xcf0664b6,
- 0x67fd0066,
- 0xf31bf404,
-/* 0x0690: memx_func_wait_vblank_1 */
- 0x07c467f1,
- 0xcf0664b6,
- 0x67fd0066,
- 0xf30bf404,
-/* 0x06a0: memx_func_wait_vblank_fini */
- 0xf80410b6,
-/* 0x06a5: memx_func_wr32 */
- 0x00169800,
- 0xb6011598,
- 0x60f90810,
- 0xd0fc50f9,
- 0x21f4e0fc,
- 0x0242b63f,
- 0xf8e91bf4,
-/* 0x06c1: memx_func_wait */
- 0x2c87f000,
- 0xcf0684b6,
- 0x1e980088,
- 0x011d9800,
- 0x98021c98,
- 0x10b6031b,
- 0xa421f410,
-/* 0x06de: memx_func_delay */
- 0x1e9800f8,
+ 0x2067f13f,
+ 0x026eb916,
+ 0xb90421f4,
+ 0x87fd02d8,
+ 0xf960f905,
+ 0xfcd0fc80,
+ 0x3f21f4e0,
+ 0x0aa277f1,
+ 0xb90073f0,
+ 0x21f4026e,
+ 0x02d8b904,
+ 0xf90587fd,
+ 0xfc80f960,
+ 0xf4e0fcd0,
+ 0x00f83f21,
+/* 0x0658: memx_func_wait_vblank */
+ 0xb0001698,
+ 0x0bf40066,
+ 0x0166b013,
+ 0xf4060bf4,
+/* 0x066a: memx_func_wait_vblank_head1 */
+ 0x77f12e0e,
+ 0x0ef40020,
+/* 0x0671: memx_func_wait_vblank_head0 */
+ 0x0877f107,
+/* 0x0675: memx_func_wait_vblank_0 */
+ 0xc467f100,
+ 0x0664b607,
+ 0xfd0066cf,
+ 0x1bf40467,
+/* 0x0685: memx_func_wait_vblank_1 */
+ 0xc467f1f3,
+ 0x0664b607,
+ 0xfd0066cf,
+ 0x0bf40467,
+/* 0x0695: memx_func_wait_vblank_fini */
+ 0x0410b6f3,
+/* 0x069a: memx_func_wr32 */
+ 0x169800f8,
+ 0x01159800,
+ 0xf90810b6,
+ 0xfc50f960,
+ 0xf4e0fcd0,
+ 0x42b63f21,
+ 0xe91bf402,
+/* 0x06b6: memx_func_wait */
+ 0x87f000f8,
+ 0x0684b62c,
+ 0x980088cf,
+ 0x1d98001e,
+ 0x021c9801,
+ 0xb6031b98,
+ 0x21f41010,
+/* 0x06d3: memx_func_delay */
+ 0x9800f8a4,
+ 0x10b6001e,
+ 0x7f21f404,
+/* 0x06de: memx_func_train */
+ 0x00f800f8,
+/* 0x06e0: memx_exec */
+ 0xd0f9e0f9,
+ 0xb902c1b9,
+/* 0x06ea: memx_exec_next */
+ 0x139802b2,
0x0410b600,
+ 0x01f034e7,
+ 0x01e033e7,
+ 0xf00132b6,
+ 0x35980c30,
+ 0xb855f9de,
+ 0x1ef40612,
+ 0xf10b98e4,
+ 0xbbf20c98,
+ 0xb7f102cb,
+ 0xb4b607c4,
+ 0x00bbcf06,
+ 0xe0fcd0fc,
+ 0x033721f5,
+/* 0x0726: memx_info */
+ 0xc67000f8,
+ 0x0e0bf401,
+/* 0x072c: memx_info_data */
+ 0x03ccc7f1,
+ 0x0800b7f1,
+/* 0x0737: memx_info_train */
+ 0xf10b0ef4,
+ 0xf10bccc7,
+/* 0x073f: memx_info_send */
+ 0xf50100b7,
+ 0xf8033721,
+/* 0x0745: memx_recv */
+ 0x01d6b000,
+ 0xb0980bf4,
+ 0x0bf400d6,
+/* 0x0753: memx_init */
+ 0xf800f8d8,
+/* 0x0755: perf_recv */
+/* 0x0757: perf_init */
+ 0xf800f800,
+/* 0x0759: i2c_drive_scl */
+ 0x0036b000,
+ 0xf1110bf4,
+ 0xb607e007,
+ 0x01d00604,
+ 0xf804bd00,
+/* 0x076d: i2c_drive_scl_lo */
+ 0xe407f100,
+ 0x0604b607,
+ 0xbd0001d0,
+/* 0x077b: i2c_drive_sda */
+ 0xb000f804,
+ 0x0bf40036,
+ 0xe007f111,
+ 0x0604b607,
+ 0xbd0002d0,
+/* 0x078f: i2c_drive_sda_lo */
+ 0xf100f804,
+ 0xb607e407,
+ 0x02d00604,
+ 0xf804bd00,
+/* 0x079d: i2c_sense_scl */
+ 0x0132f400,
+ 0x07c437f1,
+ 0xcf0634b6,
+ 0x31fd0033,
+ 0x060bf404,
+/* 0x07b3: i2c_sense_scl_done */
+ 0xf80131f4,
+/* 0x07b5: i2c_sense_sda */
+ 0x0132f400,
+ 0x07c437f1,
+ 0xcf0634b6,
+ 0x32fd0033,
+ 0x060bf404,
+/* 0x07cb: i2c_sense_sda_done */
+ 0xf80131f4,
+/* 0x07cd: i2c_raise_scl */
+ 0xf140f900,
+ 0xf0089847,
+ 0x21f50137,
+/* 0x07da: i2c_raise_scl_wait */
+ 0xe7f10759,
+ 0x21f403e8,
+ 0x9d21f57f,
+ 0x0901f407,
+ 0xf40142b6,
+/* 0x07ee: i2c_raise_scl_done */
+ 0x40fcef1b,
+/* 0x07f2: i2c_start */
+ 0x21f500f8,
+ 0x11f4079d,
+ 0xb521f50d,
+ 0x0611f407,
+/* 0x0803: i2c_start_rep */
+ 0xf0300ef4,
+ 0x21f50037,
+ 0x37f00759,
+ 0x7b21f501,
+ 0x0076bb07,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b607cd,
+ 0x1f11f404,
+/* 0x0830: i2c_start_send */
+ 0xf50037f0,
+ 0xf1077b21,
+ 0xf41388e7,
+ 0x37f07f21,
+ 0x5921f500,
+ 0x88e7f107,
+ 0x7f21f413,
+/* 0x084c: i2c_start_out */
+/* 0x084e: i2c_stop */
+ 0x37f000f8,
+ 0x5921f500,
+ 0x0037f007,
+ 0x077b21f5,
+ 0x03e8e7f1,
+ 0xf07f21f4,
+ 0x21f50137,
+ 0xe7f10759,
+ 0x21f41388,
+ 0x0137f07f,
+ 0x077b21f5,
+ 0x1388e7f1,
0xf87f21f4,
-/* 0x06e9: memx_func_train */
-/* 0x06eb: memx_exec */
- 0xf900f800,
- 0xb9d0f9e0,
- 0xb2b902c1,
-/* 0x06f5: memx_exec_next */
- 0x00139802,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12b855f9,
- 0xe41ef406,
- 0x98f10b98,
- 0xcbbbf20c,
- 0xc4b7f102,
- 0x06b4b607,
- 0xfc00bbcf,
- 0xf5e0fcd0,
- 0xf8034221,
-/* 0x0731: memx_info */
- 0x01c67000,
-/* 0x0737: memx_info_data */
- 0xf10e0bf4,
- 0xf103ccc7,
- 0xf40800b7,
-/* 0x0742: memx_info_train */
- 0xc7f10b0e,
- 0xb7f10bcc,
-/* 0x074a: memx_info_send */
- 0x21f50100,
- 0x00f80342,
-/* 0x0750: memx_recv */
- 0xf401d6b0,
- 0xd6b0980b,
- 0xd80bf400,
-/* 0x075e: memx_init */
- 0x00f800f8,
-/* 0x0760: perf_recv */
-/* 0x0762: perf_init */
- 0x00f800f8,
-/* 0x0764: i2c_drive_scl */
- 0xf40036b0,
- 0x07f1110b,
- 0x04b607e0,
- 0x0001d006,
- 0x00f804bd,
-/* 0x0778: i2c_drive_scl_lo */
- 0x07e407f1,
- 0xd00604b6,
- 0x04bd0001,
-/* 0x0786: i2c_drive_sda */
- 0x36b000f8,
- 0x110bf400,
- 0x07e007f1,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x079a: i2c_drive_sda_lo */
- 0x07f100f8,
- 0x04b607e4,
- 0x0002d006,
- 0x00f804bd,
-/* 0x07a8: i2c_sense_scl */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0431fd00,
- 0xf4060bf4,
-/* 0x07be: i2c_sense_scl_done */
- 0x00f80131,
-/* 0x07c0: i2c_sense_sda */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0432fd00,
- 0xf4060bf4,
-/* 0x07d6: i2c_sense_sda_done */
- 0x00f80131,
-/* 0x07d8: i2c_raise_scl */
- 0x47f140f9,
- 0x37f00898,
- 0x6421f501,
-/* 0x07e5: i2c_raise_scl_wait */
+/* 0x0881: i2c_bitw */
+ 0x7b21f500,
0xe8e7f107,
0x7f21f403,
- 0x07a821f5,
- 0xb60901f4,
- 0x1bf40142,
-/* 0x07f9: i2c_raise_scl_done */
- 0xf840fcef,
-/* 0x07fd: i2c_start */
- 0xa821f500,
- 0x0d11f407,
- 0x07c021f5,
- 0xf40611f4,
-/* 0x080e: i2c_start_rep */
- 0x37f0300e,
- 0x6421f500,
- 0x0137f007,
- 0x078621f5,
0xb60076bb,
0x50f90465,
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0xd821f550,
+ 0xcd21f550,
0x0464b607,
-/* 0x083b: i2c_start_send */
- 0xf01f11f4,
- 0x21f50037,
- 0xe7f10786,
- 0x21f41388,
- 0x0037f07f,
- 0x076421f5,
- 0x1388e7f1,
-/* 0x0857: i2c_start_out */
- 0xf87f21f4,
-/* 0x0859: i2c_stop */
- 0x0037f000,
- 0x076421f5,
- 0xf50037f0,
- 0xf1078621,
- 0xf403e8e7,
+ 0xf11811f4,
+ 0xf41388e7,
0x37f07f21,
- 0x6421f501,
+ 0x5921f500,
0x88e7f107,
0x7f21f413,
- 0xf50137f0,
- 0xf1078621,
- 0xf41388e7,
- 0x00f87f21,
-/* 0x088c: i2c_bitw */
- 0x078621f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07d821f5,
- 0xf40464b6,
- 0xe7f11811,
+/* 0x08c0: i2c_bitw_out */
+/* 0x08c2: i2c_bitr */
+ 0x37f000f8,
+ 0x7b21f501,
+ 0xe8e7f107,
+ 0x7f21f403,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xcd21f550,
+ 0x0464b607,
+ 0xf51b11f4,
+ 0xf007b521,
+ 0x21f50037,
+ 0xe7f10759,
0x21f41388,
- 0x0037f07f,
- 0x076421f5,
- 0x1388e7f1,
-/* 0x08cb: i2c_bitw_out */
- 0xf87f21f4,
-/* 0x08cd: i2c_bitr */
- 0x0137f000,
- 0x078621f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07d821f5,
- 0xf40464b6,
- 0x21f51b11,
- 0x37f007c0,
- 0x6421f500,
- 0x88e7f107,
- 0x7f21f413,
- 0xf4013cf0,
-/* 0x0912: i2c_bitr_done */
- 0x00f80131,
-/* 0x0914: i2c_get_byte */
- 0xf00057f0,
-/* 0x091a: i2c_get_byte_next */
- 0x54b60847,
+ 0x013cf07f,
+/* 0x0907: i2c_bitr_done */
+ 0xf80131f4,
+/* 0x0909: i2c_get_byte */
+ 0x0057f000,
+/* 0x090f: i2c_get_byte_next */
+ 0xb60847f0,
+ 0x76bb0154,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb608c221,
+ 0x11f40464,
+ 0x0553fd2b,
+ 0xf40142b6,
+ 0x37f0d81b,
0x0076bb01,
0xf90465b6,
0x04659450,
0xbd0256bb,
0x0475fd50,
0x21f550fc,
- 0x64b608cd,
- 0x2b11f404,
- 0xb60553fd,
- 0x1bf40142,
- 0x0137f0d8,
+ 0x64b60881,
+/* 0x0959: i2c_get_byte_done */
+/* 0x095b: i2c_put_byte */
+ 0xf000f804,
+/* 0x095e: i2c_put_byte_next */
+ 0x42b60847,
+ 0x3854ff01,
0xb60076bb,
0x50f90465,
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x8c21f550,
+ 0x8121f550,
0x0464b608,
-/* 0x0964: i2c_get_byte_done */
-/* 0x0966: i2c_put_byte */
- 0x47f000f8,
-/* 0x0969: i2c_put_byte_next */
- 0x0142b608,
- 0xbb3854ff,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x088c21f5,
- 0xf40464b6,
- 0x46b03411,
- 0xd81bf400,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0xcd21f550,
- 0x0464b608,
- 0xbb0f11f4,
- 0x36b00076,
- 0x061bf401,
-/* 0x09bf: i2c_put_byte_done */
- 0xf80132f4,
-/* 0x09c1: i2c_addr */
- 0x0076bb00,
+ 0xb03411f4,
+ 0x1bf40046,
+ 0x0076bbd8,
0xf90465b6,
0x04659450,
0xbd0256bb,
0x0475fd50,
0x21f550fc,
- 0x64b607fd,
- 0x2911f404,
- 0x012ec3e7,
- 0xfd0134b6,
- 0x76bb0553,
+ 0x64b608c2,
+ 0x0f11f404,
+ 0xb00076bb,
+ 0x1bf40136,
+ 0x0132f406,
+/* 0x09b4: i2c_put_byte_done */
+/* 0x09b6: i2c_addr */
+ 0x76bb00f8,
0x0465b600,
0x659450f9,
0x0256bb04,
0x75fd50bd,
0xf550fc04,
- 0xb6096621,
-/* 0x0a06: i2c_addr_done */
- 0x00f80464,
-/* 0x0a08: i2c_acquire_addr */
- 0xb6f8cec7,
- 0xe0b702e4,
- 0xee980d1c,
-/* 0x0a17: i2c_acquire */
- 0xf500f800,
- 0xf40a0821,
- 0xd9f00421,
- 0x3f21f403,
-/* 0x0a26: i2c_release */
- 0x21f500f8,
- 0x21f40a08,
- 0x03daf004,
- 0xf83f21f4,
-/* 0x0a35: i2c_recv */
- 0x0132f400,
- 0xb6f8c1c7,
- 0x16b00214,
- 0x3a1ff528,
- 0xf413a001,
- 0x0032980c,
- 0x0ccc13a0,
- 0xf4003198,
- 0xd0f90231,
- 0xd0f9e0f9,
- 0x000067f1,
- 0x100063f1,
- 0xbb016792,
+ 0xb607f221,
+ 0x11f40464,
+ 0x2ec3e729,
+ 0x0134b601,
+ 0xbb0553fd,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x0a1721f5,
- 0xfc0464b6,
- 0x00d6b0d0,
- 0x00b31bf5,
- 0xbb0057f0,
+ 0x095b21f5,
+/* 0x09fb: i2c_addr_done */
+ 0xf80464b6,
+/* 0x09fd: i2c_acquire_addr */
+ 0xf8cec700,
+ 0xb702e4b6,
+ 0x980d1ce0,
+ 0x00f800ee,
+/* 0x0a0c: i2c_acquire */
+ 0x09fd21f5,
+ 0xf00421f4,
+ 0x21f403d9,
+/* 0x0a1b: i2c_release */
+ 0xf500f83f,
+ 0xf409fd21,
+ 0xdaf00421,
+ 0x3f21f403,
+/* 0x0a2a: i2c_recv */
+ 0x32f400f8,
+ 0xf8c1c701,
+ 0xb00214b6,
+ 0x1ff52816,
+ 0x13a0013a,
+ 0x32980cf4,
+ 0xcc13a000,
+ 0x0031980c,
+ 0xf90231f4,
+ 0xf9e0f9d0,
+ 0x0067f1d0,
+ 0x0063f100,
+ 0x01679210,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x0c21f550,
+ 0x0464b60a,
+ 0xd6b0d0fc,
+ 0xb31bf500,
+ 0x0057f000,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xb621f550,
+ 0x0464b609,
+ 0x00d011f5,
+ 0xbbe0c5c7,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x09c121f5,
+ 0x095b21f5,
0xf50464b6,
- 0xc700d011,
- 0x76bbe0c5,
+ 0xf000ad11,
+ 0x76bb0157,
0x0465b600,
0x659450f9,
0x0256bb04,
0x75fd50bd,
0xf550fc04,
- 0xb6096621,
+ 0xb609b621,
0x11f50464,
- 0x57f000ad,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b609c1,
- 0x8a11f504,
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b60914,
- 0x6a11f404,
- 0xbbe05bcb,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x085921f5,
- 0xb90464b6,
- 0x74bd025b,
-/* 0x0b3b: i2c_recv_not_rd08 */
- 0xb0430ef4,
- 0x1bf401d6,
- 0x0057f03d,
- 0x09c121f5,
- 0xc73311f4,
- 0x21f5e0c5,
- 0x11f40966,
- 0x0057f029,
- 0x09c121f5,
- 0xc71f11f4,
- 0x21f5e0b5,
- 0x11f40966,
- 0x5921f515,
- 0xc774bd08,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0b7b: i2c_recv_not_wr08 */
-/* 0x0b7b: i2c_recv_done */
- 0xc7030ef4,
- 0x21f5f8ce,
- 0xe0fc0a26,
- 0x12f4d0fc,
- 0x027cb90a,
- 0x034221f5,
-/* 0x0b90: i2c_recv_exit */
-/* 0x0b92: i2c_init */
+ 0x76bb008a,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb6090921,
+ 0x11f40464,
+ 0xe05bcb6a,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x4e21f550,
+ 0x0464b608,
+ 0xbd025bb9,
+ 0x430ef474,
+/* 0x0b30: i2c_recv_not_rd08 */
+ 0xf401d6b0,
+ 0x57f03d1b,
+ 0xb621f500,
+ 0x3311f409,
+ 0xf5e0c5c7,
+ 0xf4095b21,
+ 0x57f02911,
+ 0xb621f500,
+ 0x1f11f409,
+ 0xf5e0b5c7,
+ 0xf4095b21,
+ 0x21f51511,
+ 0x74bd084e,
+ 0xf408c5c7,
+ 0x32f4091b,
+ 0x030ef402,
+/* 0x0b70: i2c_recv_not_wr08 */
+/* 0x0b70: i2c_recv_done */
+ 0xf5f8cec7,
+ 0xfc0a1b21,
+ 0xf4d0fce0,
+ 0x7cb90a12,
+ 0x3721f502,
+/* 0x0b85: i2c_recv_exit */
+/* 0x0b87: i2c_init */
+ 0xf800f803,
+/* 0x0b89: test_recv */
+ 0xd817f100,
+ 0x0614b605,
+ 0xb60011cf,
+ 0x07f10110,
+ 0x04b605d8,
+ 0x0001d006,
+ 0xe7f104bd,
+ 0xe3f1d900,
+ 0x21f5134f,
+ 0x00f80257,
+/* 0x0bb0: test_init */
+ 0x0800e7f1,
+ 0x025721f5,
+/* 0x0bba: idle_recv */
0x00f800f8,
-/* 0x0b94: test_recv */
- 0x05d817f1,
- 0xcf0614b6,
- 0x10b60011,
- 0xd807f101,
- 0x0604b605,
- 0xbd0001d0,
- 0x00e7f104,
- 0x4fe3f1d9,
- 0x6221f513,
-/* 0x0bbb: test_init */
- 0xf100f802,
- 0xf50800e7,
- 0xf8026221,
-/* 0x0bc5: idle_recv */
-/* 0x0bc7: idle */
- 0xf400f800,
- 0x17f10031,
- 0x14b605d4,
- 0x0011cf06,
- 0xf10110b6,
- 0xb605d407,
- 0x01d00604,
-/* 0x0be3: idle_loop */
- 0xf004bd00,
- 0x32f45817,
-/* 0x0be9: idle_proc */
-/* 0x0be9: idle_proc_exec */
- 0xb910f902,
- 0x21f5021e,
- 0x10fc034b,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0bfd: idle_proc_next */
- 0x5810b6ef,
- 0xf4061fb8,
- 0x02f4e61b,
- 0x0028f4dd,
- 0x00bb0ef4,
+/* 0x0bbc: idle */
+ 0xf10031f4,
+ 0xb605d417,
+ 0x11cf0614,
+ 0x0110b600,
+ 0x05d407f1,
+ 0xd00604b6,
+ 0x04bd0001,
+/* 0x0bd8: idle_loop */
+ 0xf45817f0,
+/* 0x0bde: idle_proc */
+/* 0x0bde: idle_proc_exec */
+ 0x10f90232,
+ 0xf5021eb9,
+ 0xfc034021,
+ 0x0911f410,
+ 0xf40231f4,
+/* 0x0bf2: idle_proc_next */
+ 0x10b6ef0e,
+ 0x061fb858,
+ 0xf4e61bf4,
+ 0x28f4dd02,
+ 0xbb0ef400,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h
index 31552af9b06e..7bf6b39ed205 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h
@@ -24,8 +24,8 @@ uint32_t gf119_pmu_data[] = {
0x00000000,
/* 0x0058: proc_list_head */
0x54534f48,
- 0x0000049d,
- 0x00000446,
+ 0x00000492,
+ 0x0000043b,
0x00000000,
0x00000000,
0x00000000,
@@ -46,8 +46,8 @@ uint32_t gf119_pmu_data[] = {
0x00000000,
0x00000000,
0x584d454d,
- 0x0000068b,
- 0x0000067d,
+ 0x00000680,
+ 0x00000672,
0x00000000,
0x00000000,
0x00000000,
@@ -68,8 +68,8 @@ uint32_t gf119_pmu_data[] = {
0x00000000,
0x00000000,
0x46524550,
- 0x0000068f,
- 0x0000068d,
+ 0x00000684,
+ 0x00000682,
0x00000000,
0x00000000,
0x00000000,
@@ -90,8 +90,8 @@ uint32_t gf119_pmu_data[] = {
0x00000000,
0x00000000,
0x5f433249,
- 0x00000aaa,
- 0x0000094d,
+ 0x00000a9f,
+ 0x00000942,
0x00000000,
0x00000000,
0x00000000,
@@ -112,8 +112,8 @@ uint32_t gf119_pmu_data[] = {
0x00000000,
0x00000000,
0x54534554,
- 0x00000acd,
- 0x00000aac,
+ 0x00000ac2,
+ 0x00000aa1,
0x00000000,
0x00000000,
0x00000000,
@@ -134,8 +134,8 @@ uint32_t gf119_pmu_data[] = {
0x00000000,
0x00000000,
0x454c4449,
- 0x00000ad9,
- 0x00000ad7,
+ 0x00000ace,
+ 0x00000acc,
0x00000000,
0x00000000,
0x00000000,
@@ -229,26 +229,26 @@ uint32_t gf119_pmu_data[] = {
/* 0x0370: memx_func_head */
0x00000001,
0x00000000,
- 0x000004d3,
+ 0x000004c8,
/* 0x037c: memx_func_next */
0x00000002,
0x00000000,
- 0x00000554,
+ 0x00000549,
0x00000003,
0x00000002,
- 0x000005d8,
+ 0x000005cd,
0x00040004,
0x00000000,
- 0x000005f4,
+ 0x000005e9,
0x00010005,
0x00000000,
- 0x0000060e,
+ 0x00000603,
0x00010006,
0x00000000,
- 0x000005d3,
+ 0x000005c8,
0x00000007,
0x00000000,
- 0x00000619,
+ 0x0000060e,
/* 0x03c4: memx_func_tail */
/* 0x03c4: memx_ts_start */
0x00000000,
@@ -916,7 +916,7 @@ uint32_t gf119_pmu_data[] = {
};
uint32_t gf119_pmu_code[] = {
- 0x034d0ef5,
+ 0x03420ef5,
/* 0x0004: rd32 */
0x07a007f1,
0xbd000ed0,
@@ -977,7 +977,7 @@ uint32_t gf119_pmu_code[] = {
0xbb9a0a98,
0x1cf4029a,
0x01d7f00f,
- 0x028c21f5,
+ 0x028121f5,
0x0ef494bd,
/* 0x00d5: intr_watchdog_next_time */
0x9b0a9815,
@@ -1025,716 +1025,714 @@ uint32_t gf119_pmu_code[] = {
0xf14f48e7,
0xf05453e3,
0x21f500d7,
- 0xc0fc02f1,
+ 0xc0fc02e6,
0x04c007f1,
0xbd000cd0,
/* 0x0185: intr_subintr_skip_fifo */
0x8807f104,
0x0009d006,
/* 0x018e: intr_skip_subintr */
- 0x89c404bd,
- 0x070bf420,
- 0xffbfa4f1,
-/* 0x0198: intr_skip_pause */
- 0xf44089c4,
- 0xa4f1070b,
-/* 0x01a2: intr_skip_user0 */
- 0x07f0ffbf,
- 0x0008d004,
- 0x80fc04bd,
- 0xfc0088fe,
- 0xfce0fcf0,
- 0xfcc0fcd0,
- 0xfca0fcb0,
- 0xfc80fc90,
- 0x0032f400,
-/* 0x01c6: ticks_from_ns */
- 0xc0f901f8,
- 0xd7f1b0f9,
- 0xd3f00144,
- 0xb321f500,
- 0xe8ccec03,
- 0x00b4b003,
- 0xec120bf4,
- 0xf103e8ee,
- 0xf00144d7,
- 0x21f500d3,
-/* 0x01ee: ticks_from_ns_quit */
- 0xceb903b3,
- 0xfcb0fc02,
-/* 0x01f7: ticks_from_us */
- 0xf900f8c0,
+ 0x97f104bd,
+ 0x90bd00e0,
+ 0xf00489fd,
+ 0x08d00407,
+ 0xfc04bd00,
+ 0x0088fe80,
+ 0xe0fcf0fc,
+ 0xc0fcd0fc,
+ 0xa0fcb0fc,
+ 0x80fc90fc,
+ 0x32f400fc,
+/* 0x01bb: ticks_from_ns */
+ 0xf901f800,
0xf1b0f9c0,
0xf00144d7,
0x21f500d3,
- 0xceb903b3,
- 0x00b4b002,
- 0xbd050bf4,
-/* 0x0211: ticks_from_us_quit */
- 0xfcb0fce4,
-/* 0x0217: ticks_to_us */
- 0xf100f8c0,
- 0xf00144d7,
- 0xedff00d3,
-/* 0x0223: timer */
- 0xf900f8ec,
- 0xf480f990,
- 0xf8981032,
- 0x0086b003,
- 0xbd531cf4,
- 0x3807f084,
- 0xbd0008d0,
- 0x3487f004,
- 0x980088cf,
- 0x98bb9a09,
- 0x00e9bb02,
- 0xf003fe80,
- 0x88cf0887,
- 0x0284f000,
- 0xf0201bf4,
- 0x88cf3487,
- 0x06e0b800,
- 0xb8090bf4,
- 0x1cf406e8,
-/* 0x026d: timer_reset */
- 0x3407f00e,
- 0xbd000ed0,
- 0x9a0e8004,
-/* 0x0278: timer_enable */
- 0xf00187f0,
- 0x08d03807,
-/* 0x0283: timer_done */
- 0xf404bd00,
- 0x80fc1031,
- 0x00f890fc,
-/* 0x028c: send_proc */
- 0x90f980f9,
- 0x9805e898,
- 0x86f004e9,
- 0x0689b804,
- 0xc42a0bf4,
- 0x88940398,
- 0x1880b604,
- 0x98008ebb,
- 0x8a8000fa,
- 0x018d8000,
- 0x80028c80,
- 0x90b6038b,
- 0x0794f001,
- 0xf404e980,
-/* 0x02c6: send_done */
- 0x90fc0231,
- 0x00f880fc,
-/* 0x02cc: find */
- 0x87f080f9,
- 0x0131f458,
-/* 0x02d4: find_loop */
- 0xb8008a98,
- 0x0bf406ae,
- 0x5880b610,
- 0x026886b1,
- 0xf4f01bf4,
-/* 0x02ea: find_done */
- 0x8eb90132,
- 0xf880fc02,
-/* 0x02f1: send */
- 0xcc21f500,
- 0x9701f402,
-/* 0x02fa: recv */
- 0x90f900f8,
- 0xe89880f9,
- 0x04e99805,
- 0xb80132f4,
- 0x0bf40689,
- 0x0389c43d,
- 0xf00180b6,
- 0xe8800784,
- 0x02ea9805,
- 0x8ffef0f9,
- 0xb9f0f901,
- 0x999402ef,
- 0x00e9bb04,
- 0x9818e0b6,
- 0xec9803eb,
- 0x01ed9802,
- 0xf900ee98,
- 0xfef0fca5,
- 0x31f400f8,
-/* 0x0347: recv_done */
- 0xfcf0fc01,
+ 0xccec03a8,
+ 0xb4b003e8,
+ 0x120bf400,
+ 0x03e8eeec,
+ 0x0144d7f1,
+ 0xf500d3f0,
+/* 0x01e3: ticks_from_ns_quit */
+ 0xb903a821,
+ 0xb0fc02ce,
+ 0x00f8c0fc,
+/* 0x01ec: ticks_from_us */
+ 0xb0f9c0f9,
+ 0x0144d7f1,
+ 0xf500d3f0,
+ 0xb903a821,
+ 0xb4b002ce,
+ 0x050bf400,
+/* 0x0206: ticks_from_us_quit */
+ 0xb0fce4bd,
+ 0x00f8c0fc,
+/* 0x020c: ticks_to_us */
+ 0x0144d7f1,
+ 0xff00d3f0,
+ 0x00f8eced,
+/* 0x0218: timer */
+ 0x80f990f9,
+ 0x981032f4,
+ 0x86b003f8,
+ 0x531cf400,
+ 0x07f084bd,
+ 0x0008d038,
+ 0x87f004bd,
+ 0x0088cf34,
+ 0xbb9a0998,
+ 0xe9bb0298,
+ 0x03fe8000,
+ 0xcf0887f0,
+ 0x84f00088,
+ 0x201bf402,
+ 0xcf3487f0,
+ 0xe0b80088,
+ 0x090bf406,
+ 0xf406e8b8,
+/* 0x0262: timer_reset */
+ 0x07f00e1c,
+ 0x000ed034,
+ 0x0e8004bd,
+/* 0x026d: timer_enable */
+ 0x0187f09a,
+ 0xd03807f0,
+ 0x04bd0008,
+/* 0x0278: timer_done */
+ 0xfc1031f4,
0xf890fc80,
-/* 0x034d: init */
- 0x0817f100,
- 0x0011cf01,
- 0x010911e7,
- 0xfe0814b6,
- 0x17f10014,
- 0x13f000e0,
- 0x1c07f000,
+/* 0x0281: send_proc */
+ 0xf980f900,
+ 0x05e89890,
+ 0xf004e998,
+ 0x89b80486,
+ 0x2a0bf406,
+ 0x940398c4,
+ 0x80b60488,
+ 0x008ebb18,
+ 0x8000fa98,
+ 0x8d80008a,
+ 0x028c8001,
+ 0xb6038b80,
+ 0x94f00190,
+ 0x04e98007,
+/* 0x02bb: send_done */
+ 0xfc0231f4,
+ 0xf880fc90,
+/* 0x02c1: find */
+ 0xf080f900,
+ 0x31f45887,
+/* 0x02c9: find_loop */
+ 0x008a9801,
+ 0xf406aeb8,
+ 0x80b6100b,
+ 0x6886b158,
+ 0xf01bf402,
+/* 0x02df: find_done */
+ 0xb90132f4,
+ 0x80fc028e,
+/* 0x02e6: send */
+ 0x21f500f8,
+ 0x01f402c1,
+/* 0x02ef: recv */
+ 0xf900f897,
+ 0x9880f990,
+ 0xe99805e8,
+ 0x0132f404,
+ 0xf40689b8,
+ 0x89c43d0b,
+ 0x0180b603,
+ 0x800784f0,
+ 0xea9805e8,
+ 0xfef0f902,
+ 0xf0f9018f,
+ 0x9402efb9,
+ 0xe9bb0499,
+ 0x18e0b600,
+ 0x9803eb98,
+ 0xed9802ec,
+ 0x00ee9801,
+ 0xf0fca5f9,
+ 0xf400f8fe,
+ 0xf0fc0131,
+/* 0x033c: recv_done */
+ 0x90fc80fc,
+/* 0x0342: init */
+ 0x17f100f8,
+ 0x11cf0108,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf10014fe,
+ 0xf000e017,
+ 0x07f00013,
+ 0x0001d01c,
+ 0x17f004bd,
+ 0x1407f0ff,
0xbd0001d0,
- 0xff17f004,
- 0xd01407f0,
+ 0x0217f004,
+ 0x080015f1,
+ 0xd01007f0,
0x04bd0001,
- 0xf10217f0,
- 0xf0080015,
- 0x01d01007,
- 0xf104bd00,
- 0xf000f617,
- 0x10fe0013,
- 0x1031f400,
- 0xf00117f0,
- 0x01d03807,
- 0xf004bd00,
-/* 0x03a2: init_proc */
- 0xf19858f7,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x03b3: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb9301dff,
- 0x34f10234,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0xe2ff01b4,
- 0x0234b930,
- 0xffff34f1,
- 0xb61034b6,
- 0xc3bb1045,
- 0x01b4bb00,
- 0xbb3012ff,
- 0x40fc00b3,
- 0x20fc30fc,
- 0x00f810fc,
-/* 0x0404: host_send */
- 0x04b017f1,
- 0xf10011cf,
- 0xcf04a027,
- 0x12b80022,
- 0x2f0bf406,
- 0x94071ec4,
- 0xe0b704ee,
- 0xeb980270,
- 0x02ec9803,
- 0x9801ed98,
- 0x21f500ee,
- 0x10b602f1,
- 0x0f1ec401,
- 0x04b007f1,
- 0xbd000ed0,
- 0xc30ef404,
-/* 0x0444: host_send_done */
-/* 0x0446: host_recv */
- 0x17f100f8,
- 0x13f14e49,
- 0xe1b85254,
- 0xb30bf406,
-/* 0x0454: host_recv_wait */
- 0x04cc17f1,
- 0xf10011cf,
- 0xcf04c827,
- 0x16f00022,
- 0x0612b808,
- 0xc4ec0bf4,
- 0x34b60723,
- 0xf030b704,
- 0x033b8002,
- 0x80023c80,
- 0x3e80013d,
- 0x0120b600,
- 0xf10f24f0,
- 0xd004c807,
+ 0x00f617f1,
+ 0xfe0013f0,
+ 0x31f40010,
+ 0x0117f010,
+ 0xd03807f0,
+ 0x04bd0001,
+/* 0x0397: init_proc */
+ 0x9858f7f0,
+ 0x16b001f1,
+ 0xfa0bf400,
+ 0xf0b615f9,
+ 0xf20ef458,
+/* 0x03a8: mulu32_32_64 */
+ 0x20f910f9,
+ 0x40f930f9,
+ 0x9510e195,
+ 0xc4bd10d2,
+ 0xedffb4bd,
+ 0x301dffc0,
+ 0xf10234b9,
+ 0xb6ffff34,
+ 0x45b61034,
+ 0x00c3bb10,
+ 0xff01b4bb,
+ 0x34b930e2,
+ 0xff34f102,
+ 0x1034b6ff,
+ 0xbb1045b6,
+ 0xb4bb00c3,
+ 0x3012ff01,
+ 0xfc00b3bb,
+ 0xfc30fc40,
+ 0xf810fc20,
+/* 0x03f9: host_send */
+ 0xb017f100,
+ 0x0011cf04,
+ 0x04a027f1,
+ 0xb80022cf,
+ 0x0bf40612,
+ 0x071ec42f,
+ 0xb704ee94,
+ 0x980270e0,
+ 0xec9803eb,
+ 0x01ed9802,
+ 0xf500ee98,
+ 0xb602e621,
+ 0x1ec40110,
+ 0xb007f10f,
+ 0x000ed004,
+ 0x0ef404bd,
+/* 0x0439: host_send_done */
+/* 0x043b: host_recv */
+ 0xf100f8c3,
+ 0xf14e4917,
+ 0xb8525413,
+ 0x0bf406e1,
+/* 0x0449: host_recv_wait */
+ 0xcc17f1b3,
+ 0x0011cf04,
+ 0x04c827f1,
+ 0xf00022cf,
+ 0x12b80816,
+ 0xec0bf406,
+ 0xb60723c4,
+ 0x30b70434,
+ 0x3b8002f0,
+ 0x023c8003,
+ 0x80013d80,
+ 0x20b6003e,
+ 0x0f24f001,
+ 0x04c807f1,
+ 0xbd0002d0,
+ 0x4027f004,
+ 0xd00007f0,
0x04bd0002,
- 0xf04027f0,
- 0x02d00007,
- 0xf804bd00,
-/* 0x049d: host_init */
- 0x8017f100,
- 0x1014b600,
- 0x027015f1,
- 0x04d007f1,
- 0xbd0001d0,
- 0x8017f104,
- 0x1014b600,
- 0x02f015f1,
- 0x04dc07f1,
- 0xbd0001d0,
- 0x0117f004,
- 0x04c407f1,
- 0xbd0001d0,
-/* 0x04d3: memx_func_enter */
- 0xf100f804,
- 0xf1162067,
- 0xf1f55d77,
+/* 0x0492: host_init */
+ 0x17f100f8,
+ 0x14b60080,
+ 0x7015f110,
+ 0xd007f102,
+ 0x0001d004,
+ 0x17f104bd,
+ 0x14b60080,
+ 0xf015f110,
+ 0xdc07f102,
+ 0x0001d004,
+ 0x17f004bd,
+ 0xc407f101,
+ 0x0001d004,
+ 0x00f804bd,
+/* 0x04c8: memx_func_enter */
+ 0x162067f1,
+ 0xf55d77f1,
+ 0xffff73f1,
+ 0xf4026eb9,
+ 0xd8b90421,
+ 0x0487fd02,
+ 0x80f960f9,
+ 0xe0fcd0fc,
+ 0xf13321f4,
+ 0xf1fffe77,
0xb9ffff73,
0x21f4026e,
0x02d8b904,
0xf90487fd,
0xfc80f960,
0xf4e0fcd0,
- 0x77f13321,
- 0x73f1fffe,
- 0x6eb9ffff,
+ 0x67f13321,
+ 0x6eb926f0,
0x0421f402,
0xfd02d8b9,
0x60f90487,
0xd0fc80f9,
0x21f4e0fc,
- 0xf067f133,
- 0x026eb926,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f904,
- 0xfcd0fc80,
- 0x3321f4e0,
- 0xf10467f0,
- 0xd007e007,
- 0x04bd0006,
-/* 0x053c: memx_func_enter_wait */
- 0x07c067f1,
- 0xf00066cf,
- 0x0bf40464,
- 0x2c67f0f6,
- 0x800066cf,
- 0x00f8f106,
-/* 0x0554: memx_func_leave */
- 0xcf2c67f0,
- 0x06800066,
- 0x0467f0f2,
- 0x07e407f1,
+ 0x0467f033,
+ 0x07e007f1,
0xbd0006d0,
-/* 0x0569: memx_func_leave_wait */
+/* 0x0531: memx_func_enter_wait */
0xc067f104,
0x0066cf07,
0xf40464f0,
- 0x67f1f61b,
- 0x77f126f0,
- 0x73f00001,
- 0x026eb900,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f905,
- 0xfcd0fc80,
- 0x3321f4e0,
- 0x162067f1,
- 0xf4026eb9,
- 0xd8b90421,
- 0x0587fd02,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0xf13321f4,
- 0xf00aa277,
+ 0x67f0f60b,
+ 0x0066cf2c,
+ 0xf8f10680,
+/* 0x0549: memx_func_leave */
+ 0x2c67f000,
+ 0x800066cf,
+ 0x67f0f206,
+ 0xe407f104,
+ 0x0006d007,
+/* 0x055e: memx_func_leave_wait */
+ 0x67f104bd,
+ 0x66cf07c0,
+ 0x0464f000,
+ 0xf1f61bf4,
+ 0xf126f067,
+ 0xf0000177,
0x6eb90073,
0x0421f402,
0xfd02d8b9,
0x60f90587,
0xd0fc80f9,
0x21f4e0fc,
-/* 0x05d3: memx_func_wait_vblank */
- 0xb600f833,
- 0x00f80410,
-/* 0x05d8: memx_func_wr32 */
- 0x98001698,
- 0x10b60115,
- 0xf960f908,
- 0xfcd0fc50,
+ 0x2067f133,
+ 0x026eb916,
+ 0xb90421f4,
+ 0x87fd02d8,
+ 0xf960f905,
+ 0xfcd0fc80,
0x3321f4e0,
- 0xf40242b6,
- 0x00f8e91b,
-/* 0x05f4: memx_func_wait */
- 0xcf2c87f0,
- 0x1e980088,
- 0x011d9800,
- 0x98021c98,
- 0x10b6031b,
- 0x8621f410,
-/* 0x060e: memx_func_delay */
- 0x1e9800f8,
+ 0x0aa277f1,
+ 0xb90073f0,
+ 0x21f4026e,
+ 0x02d8b904,
+ 0xf90587fd,
+ 0xfc80f960,
+ 0xf4e0fcd0,
+ 0x00f83321,
+/* 0x05c8: memx_func_wait_vblank */
+ 0xf80410b6,
+/* 0x05cd: memx_func_wr32 */
+ 0x00169800,
+ 0xb6011598,
+ 0x60f90810,
+ 0xd0fc50f9,
+ 0x21f4e0fc,
+ 0x0242b633,
+ 0xf8e91bf4,
+/* 0x05e9: memx_func_wait */
+ 0x2c87f000,
+ 0x980088cf,
+ 0x1d98001e,
+ 0x021c9801,
+ 0xb6031b98,
+ 0x21f41010,
+/* 0x0603: memx_func_delay */
+ 0x9800f886,
+ 0x10b6001e,
+ 0x6721f404,
+/* 0x060e: memx_func_train */
+ 0x00f800f8,
+/* 0x0610: memx_exec */
+ 0xd0f9e0f9,
+ 0xb902c1b9,
+/* 0x061a: memx_exec_next */
+ 0x139802b2,
0x0410b600,
- 0xf86721f4,
-/* 0x0619: memx_func_train */
-/* 0x061b: memx_exec */
- 0xf900f800,
- 0xb9d0f9e0,
- 0xb2b902c1,
-/* 0x0625: memx_exec_next */
- 0x00139802,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12b855f9,
- 0xe41ef406,
- 0x98f10b98,
- 0xcbbbf20c,
- 0xc4b7f102,
- 0x00bbcf07,
- 0xe0fcd0fc,
- 0x02f121f5,
-/* 0x065e: memx_info */
- 0xc67000f8,
- 0x0e0bf401,
-/* 0x0664: memx_info_data */
- 0x03ccc7f1,
- 0x0800b7f1,
-/* 0x066f: memx_info_train */
- 0xf10b0ef4,
- 0xf10bccc7,
-/* 0x0677: memx_info_send */
- 0xf50100b7,
- 0xf802f121,
-/* 0x067d: memx_recv */
- 0x01d6b000,
- 0xb09b0bf4,
- 0x0bf400d6,
-/* 0x068b: memx_init */
- 0xf800f8d8,
-/* 0x068d: perf_recv */
-/* 0x068f: perf_init */
- 0xf800f800,
-/* 0x0691: i2c_drive_scl */
- 0x0036b000,
- 0xf10e0bf4,
- 0xd007e007,
+ 0x01f034e7,
+ 0x01e033e7,
+ 0xf00132b6,
+ 0x35980c30,
+ 0xb855f9de,
+ 0x1ef40612,
+ 0xf10b98e4,
+ 0xbbf20c98,
+ 0xb7f102cb,
+ 0xbbcf07c4,
+ 0xfcd0fc00,
+ 0xe621f5e0,
+/* 0x0653: memx_info */
+ 0x7000f802,
+ 0x0bf401c6,
+/* 0x0659: memx_info_data */
+ 0xccc7f10e,
+ 0x00b7f103,
+ 0x0b0ef408,
+/* 0x0664: memx_info_train */
+ 0x0bccc7f1,
+ 0x0100b7f1,
+/* 0x066c: memx_info_send */
+ 0x02e621f5,
+/* 0x0672: memx_recv */
+ 0xd6b000f8,
+ 0x9b0bf401,
+ 0xf400d6b0,
+ 0x00f8d80b,
+/* 0x0680: memx_init */
+/* 0x0682: perf_recv */
+ 0x00f800f8,
+/* 0x0684: perf_init */
+/* 0x0686: i2c_drive_scl */
+ 0x36b000f8,
+ 0x0e0bf400,
+ 0x07e007f1,
+ 0xbd0001d0,
+/* 0x0697: i2c_drive_scl_lo */
+ 0xf100f804,
+ 0xd007e407,
0x04bd0001,
-/* 0x06a2: i2c_drive_scl_lo */
- 0x07f100f8,
- 0x01d007e4,
- 0xf804bd00,
-/* 0x06ad: i2c_drive_sda */
- 0x0036b000,
- 0xf10e0bf4,
- 0xd007e007,
+/* 0x06a2: i2c_drive_sda */
+ 0x36b000f8,
+ 0x0e0bf400,
+ 0x07e007f1,
+ 0xbd0002d0,
+/* 0x06b3: i2c_drive_sda_lo */
+ 0xf100f804,
+ 0xd007e407,
0x04bd0002,
-/* 0x06be: i2c_drive_sda_lo */
- 0x07f100f8,
- 0x02d007e4,
- 0xf804bd00,
-/* 0x06c9: i2c_sense_scl */
- 0x0132f400,
- 0x07c437f1,
- 0xfd0033cf,
- 0x0bf40431,
- 0x0131f406,
-/* 0x06dc: i2c_sense_scl_done */
-/* 0x06de: i2c_sense_sda */
+/* 0x06be: i2c_sense_scl */
0x32f400f8,
0xc437f101,
0x0033cf07,
- 0xf40432fd,
+ 0xf40431fd,
0x31f4060b,
-/* 0x06f1: i2c_sense_sda_done */
-/* 0x06f3: i2c_raise_scl */
- 0xf900f801,
- 0x9847f140,
- 0x0137f008,
- 0x069121f5,
-/* 0x0700: i2c_raise_scl_wait */
- 0x03e8e7f1,
- 0xf56721f4,
- 0xf406c921,
- 0x42b60901,
- 0xef1bf401,
-/* 0x0714: i2c_raise_scl_done */
- 0x00f840fc,
-/* 0x0718: i2c_start */
- 0x06c921f5,
- 0xf50d11f4,
- 0xf406de21,
- 0x0ef40611,
-/* 0x0729: i2c_start_rep */
- 0x0037f030,
- 0x069121f5,
+/* 0x06d1: i2c_sense_scl_done */
+/* 0x06d3: i2c_sense_sda */
+ 0xf400f801,
+ 0x37f10132,
+ 0x33cf07c4,
+ 0x0432fd00,
+ 0xf4060bf4,
+/* 0x06e6: i2c_sense_sda_done */
+ 0x00f80131,
+/* 0x06e8: i2c_raise_scl */
+ 0x47f140f9,
+ 0x37f00898,
+ 0x8621f501,
+/* 0x06f5: i2c_raise_scl_wait */
+ 0xe8e7f106,
+ 0x6721f403,
+ 0x06be21f5,
+ 0xb60901f4,
+ 0x1bf40142,
+/* 0x0709: i2c_raise_scl_done */
+ 0xf840fcef,
+/* 0x070d: i2c_start */
+ 0xbe21f500,
+ 0x0d11f406,
+ 0x06d321f5,
+ 0xf40611f4,
+/* 0x071e: i2c_start_rep */
+ 0x37f0300e,
+ 0x8621f500,
+ 0x0137f006,
+ 0x06a221f5,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xe821f550,
+ 0x0464b606,
+/* 0x074b: i2c_start_send */
+ 0xf01f11f4,
+ 0x21f50037,
+ 0xe7f106a2,
+ 0x21f41388,
+ 0x0037f067,
+ 0x068621f5,
+ 0x1388e7f1,
+/* 0x0767: i2c_start_out */
+ 0xf86721f4,
+/* 0x0769: i2c_stop */
+ 0x0037f000,
+ 0x068621f5,
+ 0xf50037f0,
+ 0xf106a221,
+ 0xf403e8e7,
+ 0x37f06721,
+ 0x8621f501,
+ 0x88e7f106,
+ 0x6721f413,
0xf50137f0,
- 0xbb06ad21,
+ 0xf106a221,
+ 0xf41388e7,
+ 0x00f86721,
+/* 0x079c: i2c_bitw */
+ 0x06a221f5,
+ 0x03e8e7f1,
+ 0xbb6721f4,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x06f321f5,
+ 0x06e821f5,
0xf40464b6,
-/* 0x0756: i2c_start_send */
- 0x37f01f11,
- 0xad21f500,
- 0x88e7f106,
- 0x6721f413,
- 0xf50037f0,
- 0xf1069121,
- 0xf41388e7,
-/* 0x0772: i2c_start_out */
- 0x00f86721,
-/* 0x0774: i2c_stop */
- 0xf50037f0,
- 0xf0069121,
- 0x21f50037,
- 0xe7f106ad,
- 0x21f403e8,
- 0x0137f067,
- 0x069121f5,
- 0x1388e7f1,
- 0xf06721f4,
- 0x21f50137,
- 0xe7f106ad,
+ 0xe7f11811,
0x21f41388,
-/* 0x07a7: i2c_bitw */
- 0xf500f867,
- 0xf106ad21,
- 0xf403e8e7,
- 0x76bb6721,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb606f321,
- 0x11f40464,
- 0x88e7f118,
- 0x6721f413,
- 0xf50037f0,
- 0xf1069121,
- 0xf41388e7,
-/* 0x07e6: i2c_bitw_out */
- 0x00f86721,
-/* 0x07e8: i2c_bitr */
- 0xf50137f0,
- 0xf106ad21,
- 0xf403e8e7,
- 0x76bb6721,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb606f321,
- 0x11f40464,
- 0xde21f51b,
- 0x0037f006,
- 0x069121f5,
+ 0x0037f067,
+ 0x068621f5,
0x1388e7f1,
- 0xf06721f4,
- 0x31f4013c,
-/* 0x082d: i2c_bitr_done */
-/* 0x082f: i2c_get_byte */
- 0xf000f801,
- 0x47f00057,
-/* 0x0835: i2c_get_byte_next */
- 0x0154b608,
+/* 0x07db: i2c_bitw_out */
+ 0xf86721f4,
+/* 0x07dd: i2c_bitr */
+ 0x0137f000,
+ 0x06a221f5,
+ 0x03e8e7f1,
+ 0xbb6721f4,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x06e821f5,
+ 0xf40464b6,
+ 0x21f51b11,
+ 0x37f006d3,
+ 0x8621f500,
+ 0x88e7f106,
+ 0x6721f413,
+ 0xf4013cf0,
+/* 0x0822: i2c_bitr_done */
+ 0x00f80131,
+/* 0x0824: i2c_get_byte */
+ 0xf00057f0,
+/* 0x082a: i2c_get_byte_next */
+ 0x54b60847,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b607dd,
+ 0x2b11f404,
+ 0xb60553fd,
+ 0x1bf40142,
+ 0x0137f0d8,
0xb60076bb,
0x50f90465,
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0xe821f550,
+ 0x9c21f550,
0x0464b607,
- 0xfd2b11f4,
- 0x42b60553,
- 0xd81bf401,
- 0xbb0137f0,
+/* 0x0874: i2c_get_byte_done */
+/* 0x0876: i2c_put_byte */
+ 0x47f000f8,
+/* 0x0879: i2c_put_byte_next */
+ 0x0142b608,
+ 0xbb3854ff,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x07a721f5,
-/* 0x087f: i2c_get_byte_done */
- 0xf80464b6,
-/* 0x0881: i2c_put_byte */
- 0x0847f000,
-/* 0x0884: i2c_put_byte_next */
- 0xff0142b6,
- 0x76bb3854,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb607a721,
- 0x11f40464,
- 0x0046b034,
- 0xbbd81bf4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07e821f5,
+ 0x079c21f5,
0xf40464b6,
- 0x76bb0f11,
- 0x0136b000,
- 0xf4061bf4,
-/* 0x08da: i2c_put_byte_done */
- 0x00f80132,
-/* 0x08dc: i2c_addr */
+ 0x46b03411,
+ 0xd81bf400,
0xb60076bb,
0x50f90465,
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x1821f550,
+ 0xdd21f550,
0x0464b607,
- 0xe72911f4,
- 0xb6012ec3,
- 0x53fd0134,
- 0x0076bb05,
+ 0xbb0f11f4,
+ 0x36b00076,
+ 0x061bf401,
+/* 0x08cf: i2c_put_byte_done */
+ 0xf80132f4,
+/* 0x08d1: i2c_addr */
+ 0x0076bb00,
0xf90465b6,
0x04659450,
0xbd0256bb,
0x0475fd50,
0x21f550fc,
- 0x64b60881,
-/* 0x0921: i2c_addr_done */
-/* 0x0923: i2c_acquire_addr */
- 0xc700f804,
- 0xe4b6f8ce,
- 0x14e0b705,
-/* 0x092f: i2c_acquire */
- 0xf500f8d0,
- 0xf4092321,
- 0xd9f00421,
+ 0x64b6070d,
+ 0x2911f404,
+ 0x012ec3e7,
+ 0xfd0134b6,
+ 0x76bb0553,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb6087621,
+/* 0x0916: i2c_addr_done */
+ 0x00f80464,
+/* 0x0918: i2c_acquire_addr */
+ 0xb6f8cec7,
+ 0xe0b705e4,
+ 0x00f8d014,
+/* 0x0924: i2c_acquire */
+ 0x091821f5,
+ 0xf00421f4,
+ 0x21f403d9,
+/* 0x0933: i2c_release */
+ 0xf500f833,
+ 0xf4091821,
+ 0xdaf00421,
0x3321f403,
-/* 0x093e: i2c_release */
- 0x21f500f8,
- 0x21f40923,
- 0x03daf004,
- 0xf83321f4,
-/* 0x094d: i2c_recv */
- 0x0132f400,
- 0xb6f8c1c7,
- 0x16b00214,
- 0x3a1ff528,
- 0xf413a001,
- 0x0032980c,
- 0x0ccc13a0,
- 0xf4003198,
- 0xd0f90231,
- 0xd0f9e0f9,
- 0x000067f1,
- 0x100063f1,
- 0xbb016792,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x092f21f5,
- 0xfc0464b6,
- 0x00d6b0d0,
- 0x00b31bf5,
- 0xbb0057f0,
+/* 0x0942: i2c_recv */
+ 0x32f400f8,
+ 0xf8c1c701,
+ 0xb00214b6,
+ 0x1ff52816,
+ 0x13a0013a,
+ 0x32980cf4,
+ 0xcc13a000,
+ 0x0031980c,
+ 0xf90231f4,
+ 0xf9e0f9d0,
+ 0x0067f1d0,
+ 0x0063f100,
+ 0x01679210,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x2421f550,
+ 0x0464b609,
+ 0xd6b0d0fc,
+ 0xb31bf500,
+ 0x0057f000,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xd121f550,
+ 0x0464b608,
+ 0x00d011f5,
+ 0xbbe0c5c7,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x08dc21f5,
+ 0x087621f5,
0xf50464b6,
- 0xc700d011,
- 0x76bbe0c5,
+ 0xf000ad11,
+ 0x76bb0157,
0x0465b600,
0x659450f9,
0x0256bb04,
0x75fd50bd,
0xf550fc04,
- 0xb6088121,
+ 0xb608d121,
0x11f50464,
- 0x57f000ad,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b608dc,
- 0x8a11f504,
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b6082f,
- 0x6a11f404,
- 0xbbe05bcb,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x077421f5,
- 0xb90464b6,
- 0x74bd025b,
-/* 0x0a53: i2c_recv_not_rd08 */
- 0xb0430ef4,
- 0x1bf401d6,
- 0x0057f03d,
- 0x08dc21f5,
- 0xc73311f4,
- 0x21f5e0c5,
- 0x11f40881,
- 0x0057f029,
- 0x08dc21f5,
- 0xc71f11f4,
- 0x21f5e0b5,
- 0x11f40881,
- 0x7421f515,
- 0xc774bd07,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0a93: i2c_recv_not_wr08 */
-/* 0x0a93: i2c_recv_done */
- 0xc7030ef4,
- 0x21f5f8ce,
- 0xe0fc093e,
- 0x12f4d0fc,
- 0x027cb90a,
- 0x02f121f5,
-/* 0x0aa8: i2c_recv_exit */
-/* 0x0aaa: i2c_init */
- 0x00f800f8,
-/* 0x0aac: test_recv */
- 0x05d817f1,
- 0xb60011cf,
- 0x07f10110,
- 0x01d005d8,
- 0xf104bd00,
- 0xf1d900e7,
- 0xf5134fe3,
- 0xf8022321,
-/* 0x0acd: test_init */
- 0x00e7f100,
- 0x2321f508,
-/* 0x0ad7: idle_recv */
+ 0x76bb008a,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb6082421,
+ 0x11f40464,
+ 0xe05bcb6a,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x6921f550,
+ 0x0464b607,
+ 0xbd025bb9,
+ 0x430ef474,
+/* 0x0a48: i2c_recv_not_rd08 */
+ 0xf401d6b0,
+ 0x57f03d1b,
+ 0xd121f500,
+ 0x3311f408,
+ 0xf5e0c5c7,
+ 0xf4087621,
+ 0x57f02911,
+ 0xd121f500,
+ 0x1f11f408,
+ 0xf5e0b5c7,
+ 0xf4087621,
+ 0x21f51511,
+ 0x74bd0769,
+ 0xf408c5c7,
+ 0x32f4091b,
+ 0x030ef402,
+/* 0x0a88: i2c_recv_not_wr08 */
+/* 0x0a88: i2c_recv_done */
+ 0xf5f8cec7,
+ 0xfc093321,
+ 0xf4d0fce0,
+ 0x7cb90a12,
+ 0xe621f502,
+/* 0x0a9d: i2c_recv_exit */
+/* 0x0a9f: i2c_init */
0xf800f802,
-/* 0x0ad9: idle */
- 0x0031f400,
- 0x05d417f1,
- 0xb60011cf,
- 0x07f10110,
- 0x01d005d4,
-/* 0x0aef: idle_loop */
- 0xf004bd00,
- 0x32f45817,
-/* 0x0af5: idle_proc */
-/* 0x0af5: idle_proc_exec */
- 0xb910f902,
- 0x21f5021e,
- 0x10fc02fa,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0b09: idle_proc_next */
- 0x5810b6ef,
- 0xf4061fb8,
- 0x02f4e61b,
- 0x0028f4dd,
- 0x00c10ef4,
+/* 0x0aa1: test_recv */
+ 0xd817f100,
+ 0x0011cf05,
+ 0xf10110b6,
+ 0xd005d807,
+ 0x04bd0001,
+ 0xd900e7f1,
+ 0x134fe3f1,
+ 0x021821f5,
+/* 0x0ac2: test_init */
+ 0xe7f100f8,
+ 0x21f50800,
+ 0x00f80218,
+/* 0x0acc: idle_recv */
+/* 0x0ace: idle */
+ 0x31f400f8,
+ 0xd417f100,
+ 0x0011cf05,
+ 0xf10110b6,
+ 0xd005d407,
+ 0x04bd0001,
+/* 0x0ae4: idle_loop */
+ 0xf45817f0,
+/* 0x0aea: idle_proc */
+/* 0x0aea: idle_proc_exec */
+ 0x10f90232,
+ 0xf5021eb9,
+ 0xfc02ef21,
+ 0x0911f410,
+ 0xf40231f4,
+/* 0x0afe: idle_proc_next */
+ 0x10b6ef0e,
+ 0x061fb858,
+ 0xf4e61bf4,
+ 0x28f4dd02,
+ 0xc10ef400,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
index fe4f63deeaab..8a2b628642ac 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
@@ -24,8 +24,8 @@ uint32_t gk208_pmu_data[] = {
0x00000000,
/* 0x0058: proc_list_head */
0x54534f48,
- 0x00000453,
- 0x00000404,
+ 0x00000447,
+ 0x000003f8,
0x00000000,
0x00000000,
0x00000000,
@@ -46,8 +46,8 @@ uint32_t gk208_pmu_data[] = {
0x00000000,
0x00000000,
0x584d454d,
- 0x0000062d,
- 0x0000061f,
+ 0x00000621,
+ 0x00000613,
0x00000000,
0x00000000,
0x00000000,
@@ -68,8 +68,8 @@ uint32_t gk208_pmu_data[] = {
0x00000000,
0x00000000,
0x46524550,
- 0x00000631,
- 0x0000062f,
+ 0x00000625,
+ 0x00000623,
0x00000000,
0x00000000,
0x00000000,
@@ -90,8 +90,8 @@ uint32_t gk208_pmu_data[] = {
0x00000000,
0x00000000,
0x5f433249,
- 0x00000a35,
- 0x000008dc,
+ 0x00000a29,
+ 0x000008d0,
0x00000000,
0x00000000,
0x00000000,
@@ -112,8 +112,8 @@ uint32_t gk208_pmu_data[] = {
0x00000000,
0x00000000,
0x54534554,
- 0x00000a56,
- 0x00000a37,
+ 0x00000a4a,
+ 0x00000a2b,
0x00000000,
0x00000000,
0x00000000,
@@ -134,8 +134,8 @@ uint32_t gk208_pmu_data[] = {
0x00000000,
0x00000000,
0x454c4449,
- 0x00000a61,
- 0x00000a5f,
+ 0x00000a55,
+ 0x00000a53,
0x00000000,
0x00000000,
0x00000000,
@@ -229,26 +229,26 @@ uint32_t gk208_pmu_data[] = {
/* 0x0370: memx_func_head */
0x00000001,
0x00000000,
- 0x00000483,
+ 0x00000477,
/* 0x037c: memx_func_next */
0x00000002,
0x00000000,
- 0x00000500,
+ 0x000004f4,
0x00000003,
0x00000002,
- 0x00000580,
+ 0x00000574,
0x00040004,
0x00000000,
- 0x0000059d,
+ 0x00000591,
0x00010005,
0x00000000,
- 0x000005b7,
+ 0x000005ab,
0x00010006,
0x00000000,
- 0x0000057b,
+ 0x0000056f,
0x00000007,
0x00000000,
- 0x000005c3,
+ 0x000005b7,
/* 0x03c4: memx_func_tail */
/* 0x03c4: memx_ts_start */
0x00000000,
@@ -916,7 +916,7 @@ uint32_t gk208_pmu_data[] = {
};
uint32_t gk208_pmu_code[] = {
- 0x031c0ef5,
+ 0x03100ef5,
/* 0x0004: rd32 */
0xf607a040,
0x04bd000e,
@@ -972,7 +972,7 @@ uint32_t gk208_pmu_code[] = {
0x0a98280b,
0x029abb9a,
0x0d0e1cf4,
- 0x02617e01,
+ 0x02557e01,
0xf494bd00,
/* 0x00c2: intr_watchdog_next_time */
0x0a98140e,
@@ -1017,21 +1017,16 @@ uint32_t gk208_pmu_code[] = {
0xc0f900cc,
0xf14f484e,
0x0d5453e3,
- 0x02c27e00,
+ 0x02b67e00,
0x40c0fc00,
0x0cf604c0,
/* 0x0167: intr_subintr_skip_fifo */
0x4004bd00,
0x09f60688,
/* 0x016f: intr_skip_subintr */
- 0xc404bd00,
- 0x0bf42089,
- 0xbfa4f107,
-/* 0x0179: intr_skip_pause */
- 0x4089c4ff,
- 0xf1070bf4,
-/* 0x0183: intr_skip_user0 */
- 0x00ffbfa4,
+ 0x4904bd00,
+ 0x90bd00e0,
+ 0x000489fd,
0x0008f604,
0x80fc04bd,
0xfc0088fe,
@@ -1040,35 +1035,35 @@ uint32_t gk208_pmu_code[] = {
0xfca0fcb0,
0xfc80fc90,
0x0032f400,
-/* 0x01a6: ticks_from_ns */
+/* 0x019a: ticks_from_ns */
0xc0f901f8,
0xd7f1b0f9,
0xd3f00144,
- 0x7721f500,
+ 0x6b21f500,
0xe8ccec03,
0x00b4b003,
0xec120bf4,
0xf103e8ee,
0xf00144d7,
0x21f500d3,
-/* 0x01ce: ticks_from_ns_quit */
- 0xceb20377,
+/* 0x01c2: ticks_from_ns_quit */
+ 0xceb2036b,
0xc0fcb0fc,
-/* 0x01d6: ticks_from_us */
+/* 0x01ca: ticks_from_us */
0xc0f900f8,
0xd7f1b0f9,
0xd3f00144,
- 0x7721f500,
+ 0x6b21f500,
0xb0ceb203,
0x0bf400b4,
-/* 0x01ef: ticks_from_us_quit */
+/* 0x01e3: ticks_from_us_quit */
0xfce4bd05,
0xf8c0fcb0,
-/* 0x01f5: ticks_to_us */
+/* 0x01e9: ticks_to_us */
0x44d7f100,
0x00d3f001,
0xf8ecedff,
-/* 0x0201: timer */
+/* 0x01f5: timer */
0xf990f900,
0x1032f480,
0xb003f898,
@@ -1086,17 +1081,17 @@ uint32_t gk208_pmu_code[] = {
0xa60088cf,
0x080bf4e0,
0x1cf4e8a6,
-/* 0x0245: timer_reset */
+/* 0x0239: timer_reset */
0xf634000d,
0x04bd000e,
-/* 0x024f: timer_enable */
+/* 0x0243: timer_enable */
0x089a0eb5,
0xf6380001,
0x04bd0008,
-/* 0x0258: timer_done */
+/* 0x024c: timer_done */
0xfc1031f4,
0xf890fc80,
-/* 0x0261: send_proc */
+/* 0x0255: send_proc */
0xf980f900,
0x05e89890,
0xf004e998,
@@ -1111,24 +1106,24 @@ uint32_t gk208_pmu_code[] = {
0x90b6038b,
0x0794f001,
0xf404e9b5,
-/* 0x029a: send_done */
+/* 0x028e: send_done */
0x90fc0231,
0x00f880fc,
-/* 0x02a0: find */
+/* 0x0294: find */
0x580880f9,
-/* 0x02a7: find_loop */
+/* 0x029b: find_loop */
0x980131f4,
0xaea6008a,
0xb6100bf4,
0x86b15880,
0x1bf40268,
0x0132f4f1,
-/* 0x02bc: find_done */
+/* 0x02b0: find_done */
0x80fc8eb2,
-/* 0x02c2: send */
- 0xa07e00f8,
+/* 0x02b6: send */
+ 0x947e00f8,
0x01f40002,
-/* 0x02cb: recv */
+/* 0x02bf: recv */
0xf900f89b,
0x9880f990,
0xe99805e8,
@@ -1148,10 +1143,10 @@ uint32_t gk208_pmu_code[] = {
0xa5f900ee,
0xf8fef0fc,
0x0131f400,
-/* 0x0316: recv_done */
+/* 0x030a: recv_done */
0x80fcf0fc,
0x00f890fc,
-/* 0x031c: init */
+/* 0x0310: init */
0xcf010841,
0x11e70011,
0x14b60109,
@@ -1170,12 +1165,12 @@ uint32_t gk208_pmu_code[] = {
0x011031f4,
0xf6380001,
0x04bd0001,
-/* 0x0366: init_proc */
+/* 0x035a: init_proc */
0xf198580f,
0x0016b001,
0xf9fa0bf4,
0x58f0b615,
-/* 0x0377: mulu32_32_64 */
+/* 0x036b: mulu32_32_64 */
0xf9f20ef4,
0xf920f910,
0x9540f930,
@@ -1196,7 +1191,7 @@ uint32_t gk208_pmu_code[] = {
0x00b3bb30,
0x30fc40fc,
0x10fc20fc,
-/* 0x03c6: host_send */
+/* 0x03ba: host_send */
0xb04100f8,
0x0011cf04,
0xcf04a042,
@@ -1207,18 +1202,18 @@ uint32_t gk208_pmu_code[] = {
0x03eb9802,
0x9802ec98,
0xee9801ed,
- 0x02c27e00,
+ 0x02b67e00,
0x0110b600,
0x400f1ec4,
0x0ef604b0,
0xf404bd00,
-/* 0x0402: host_send_done */
+/* 0x03f6: host_send_done */
0x00f8c70e,
-/* 0x0404: host_recv */
+/* 0x03f8: host_recv */
0xf14e4941,
0xa6525413,
0xb90bf4e1,
-/* 0x0410: host_recv_wait */
+/* 0x0404: host_recv_wait */
0xcf04cc41,
0xc8420011,
0x0022cf04,
@@ -1235,7 +1230,7 @@ uint32_t gk208_pmu_code[] = {
0x04bd0002,
0x00004002,
0xbd0002f6,
-/* 0x0453: host_init */
+/* 0x0447: host_init */
0x4100f804,
0x14b60080,
0x7015f110,
@@ -1248,7 +1243,7 @@ uint32_t gk208_pmu_code[] = {
0x0104bd00,
0x04c44001,
0xbd0001f6,
-/* 0x0483: memx_func_enter */
+/* 0x0477: memx_func_enter */
0xf100f804,
0xf1162067,
0xf1f55d77,
@@ -1275,19 +1270,19 @@ uint32_t gk208_pmu_code[] = {
0x00002e7e,
0xe0400406,
0x0006f607,
-/* 0x04ea: memx_func_enter_wait */
+/* 0x04de: memx_func_enter_wait */
0xc04604bd,
0x0066cf07,
0xf40464f0,
0x2c06f70b,
0xb50066cf,
0x00f8f106,
-/* 0x0500: memx_func_leave */
+/* 0x04f4: memx_func_leave */
0x66cf2c06,
0xf206b500,
0xe4400406,
0x0006f607,
-/* 0x0512: memx_func_leave_wait */
+/* 0x0506: memx_func_leave_wait */
0xc04604bd,
0x0066cf07,
0xf40464f0,
@@ -1314,10 +1309,10 @@ uint32_t gk208_pmu_code[] = {
0xf960f905,
0xfcd0fc80,
0x002e7ee0,
-/* 0x057b: memx_func_wait_vblank */
+/* 0x056f: memx_func_wait_vblank */
0xb600f800,
0x00f80410,
-/* 0x0580: memx_func_wr32 */
+/* 0x0574: memx_func_wr32 */
0x98001698,
0x10b60115,
0xf960f908,
@@ -1325,23 +1320,23 @@ uint32_t gk208_pmu_code[] = {
0x002e7ee0,
0x0242b600,
0xf8e81bf4,
-/* 0x059d: memx_func_wait */
+/* 0x0591: memx_func_wait */
0xcf2c0800,
0x1e980088,
0x011d9800,
0x98021c98,
0x10b6031b,
0x00797e10,
-/* 0x05b7: memx_func_delay */
+/* 0x05ab: memx_func_delay */
0x9800f800,
0x10b6001e,
0x005d7e04,
-/* 0x05c3: memx_func_train */
+/* 0x05b7: memx_func_train */
0xf800f800,
-/* 0x05c5: memx_exec */
+/* 0x05b9: memx_exec */
0xf9e0f900,
0xb2c1b2d0,
-/* 0x05cd: memx_exec_next */
+/* 0x05c1: memx_exec_next */
0x001398b2,
0xe70410b6,
0xe701f034,
@@ -1354,111 +1349,111 @@ uint32_t gk208_pmu_code[] = {
0x02cbbbf2,
0xcf07c44b,
0xd0fc00bb,
- 0xc27ee0fc,
+ 0xb67ee0fc,
0x00f80002,
-/* 0x0604: memx_info */
+/* 0x05f8: memx_info */
0xf401c670,
-/* 0x060a: memx_info_data */
+/* 0x05fe: memx_info_data */
0xcc4c0c0b,
0x08004b03,
-/* 0x0613: memx_info_train */
+/* 0x0607: memx_info_train */
0x4c090ef4,
0x004b0bcc,
-/* 0x0619: memx_info_send */
- 0x02c27e01,
-/* 0x061f: memx_recv */
+/* 0x060d: memx_info_send */
+ 0x02b67e01,
+/* 0x0613: memx_recv */
0xb000f800,
0x0bf401d6,
0x00d6b0a3,
0xf8dc0bf4,
-/* 0x062d: memx_init */
-/* 0x062f: perf_recv */
+/* 0x0621: memx_init */
+/* 0x0623: perf_recv */
0xf800f800,
-/* 0x0631: perf_init */
-/* 0x0633: i2c_drive_scl */
+/* 0x0625: perf_init */
+/* 0x0627: i2c_drive_scl */
0xb000f800,
0x0bf40036,
0x07e0400d,
0xbd0001f6,
-/* 0x0643: i2c_drive_scl_lo */
+/* 0x0637: i2c_drive_scl_lo */
0x4000f804,
0x01f607e4,
0xf804bd00,
-/* 0x064d: i2c_drive_sda */
+/* 0x0641: i2c_drive_sda */
0x0036b000,
0x400d0bf4,
0x02f607e0,
0xf804bd00,
-/* 0x065d: i2c_drive_sda_lo */
+/* 0x0651: i2c_drive_sda_lo */
0x07e44000,
0xbd0002f6,
-/* 0x0667: i2c_sense_scl */
+/* 0x065b: i2c_sense_scl */
0xf400f804,
0xc4430132,
0x0033cf07,
0xf40431fd,
0x31f4060b,
-/* 0x0679: i2c_sense_scl_done */
-/* 0x067b: i2c_sense_sda */
+/* 0x066d: i2c_sense_scl_done */
+/* 0x066f: i2c_sense_sda */
0xf400f801,
0xc4430132,
0x0033cf07,
0xf40432fd,
0x31f4060b,
-/* 0x068d: i2c_sense_sda_done */
-/* 0x068f: i2c_raise_scl */
+/* 0x0681: i2c_sense_sda_done */
+/* 0x0683: i2c_raise_scl */
0xf900f801,
0x08984440,
- 0x337e0103,
-/* 0x069a: i2c_raise_scl_wait */
+ 0x277e0103,
+/* 0x068e: i2c_raise_scl_wait */
0xe84e0006,
0x005d7e03,
- 0x06677e00,
+ 0x065b7e00,
0x0901f400,
0xf40142b6,
-/* 0x06ae: i2c_raise_scl_done */
+/* 0x06a2: i2c_raise_scl_done */
0x40fcef1b,
-/* 0x06b2: i2c_start */
- 0x677e00f8,
+/* 0x06a6: i2c_start */
+ 0x5b7e00f8,
0x11f40006,
- 0x067b7e0d,
+ 0x066f7e0d,
0x0611f400,
-/* 0x06c3: i2c_start_rep */
+/* 0x06b7: i2c_start_rep */
0x032e0ef4,
- 0x06337e00,
+ 0x06277e00,
0x7e010300,
- 0xbb00064d,
+ 0xbb000641,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x00068f7e,
+ 0x0006837e,
0xf40464b6,
-/* 0x06ee: i2c_start_send */
+/* 0x06e2: i2c_start_send */
0x00031d11,
- 0x00064d7e,
+ 0x0006417e,
0x7e13884e,
0x0300005d,
- 0x06337e00,
+ 0x06277e00,
0x13884e00,
0x00005d7e,
-/* 0x0708: i2c_start_out */
-/* 0x070a: i2c_stop */
+/* 0x06fc: i2c_start_out */
+/* 0x06fe: i2c_stop */
0x000300f8,
- 0x0006337e,
- 0x4d7e0003,
+ 0x0006277e,
+ 0x417e0003,
0xe84e0006,
0x005d7e03,
0x7e010300,
- 0x4e000633,
+ 0x4e000627,
0x5d7e1388,
0x01030000,
- 0x00064d7e,
+ 0x0006417e,
0x7e13884e,
0xf800005d,
-/* 0x0739: i2c_bitw */
- 0x064d7e00,
+/* 0x072d: i2c_bitw */
+ 0x06417e00,
0x03e84e00,
0x00005d7e,
0xb60076bb,
@@ -1466,18 +1461,18 @@ uint32_t gk208_pmu_code[] = {
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x068f7e50,
+ 0x06837e50,
0x0464b600,
0x4e1711f4,
0x5d7e1388,
0x00030000,
- 0x0006337e,
+ 0x0006277e,
0x7e13884e,
-/* 0x0777: i2c_bitw_out */
+/* 0x076b: i2c_bitw_out */
0xf800005d,
-/* 0x0779: i2c_bitr */
+/* 0x076d: i2c_bitr */
0x7e010300,
- 0x4e00064d,
+ 0x4e000641,
0x5d7e03e8,
0x76bb0000,
0x0465b600,
@@ -1485,25 +1480,25 @@ uint32_t gk208_pmu_code[] = {
0x0256bb04,
0x75fd50bd,
0x7e50fc04,
- 0xb600068f,
+ 0xb6000683,
0x11f40464,
- 0x067b7e1a,
+ 0x066f7e1a,
0x7e000300,
- 0x4e000633,
+ 0x4e000627,
0x5d7e1388,
0x3cf00000,
0x0131f401,
-/* 0x07bc: i2c_bitr_done */
-/* 0x07be: i2c_get_byte */
+/* 0x07b0: i2c_bitr_done */
+/* 0x07b2: i2c_get_byte */
0x000500f8,
-/* 0x07c2: i2c_get_byte_next */
+/* 0x07b6: i2c_get_byte_next */
0x54b60804,
0x0076bb01,
0xf90465b6,
0x04659450,
0xbd0256bb,
0x0475fd50,
- 0x797e50fc,
+ 0x6d7e50fc,
0x64b60007,
0x2a11f404,
0xb60553fd,
@@ -1514,11 +1509,11 @@ uint32_t gk208_pmu_code[] = {
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x0007397e,
-/* 0x080b: i2c_get_byte_done */
+ 0x00072d7e,
+/* 0x07ff: i2c_get_byte_done */
0xf80464b6,
-/* 0x080d: i2c_put_byte */
-/* 0x080f: i2c_put_byte_next */
+/* 0x0801: i2c_put_byte */
+/* 0x0803: i2c_put_byte_next */
0xb6080400,
0x54ff0142,
0x0076bb38,
@@ -1526,7 +1521,7 @@ uint32_t gk208_pmu_code[] = {
0x04659450,
0xbd0256bb,
0x0475fd50,
- 0x397e50fc,
+ 0x2d7e50fc,
0x64b60007,
0x3411f404,
0xf40046b0,
@@ -1536,20 +1531,20 @@ uint32_t gk208_pmu_code[] = {
0x0256bb04,
0x75fd50bd,
0x7e50fc04,
- 0xb6000779,
+ 0xb600076d,
0x11f40464,
0x0076bb0f,
0xf40136b0,
0x32f4061b,
-/* 0x0865: i2c_put_byte_done */
-/* 0x0867: i2c_addr */
+/* 0x0859: i2c_put_byte_done */
+/* 0x085b: i2c_addr */
0xbb00f801,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x0006b27e,
+ 0x0006a67e,
0xf40464b6,
0xc3e72911,
0x34b6012e,
@@ -1559,25 +1554,25 @@ uint32_t gk208_pmu_code[] = {
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x080d7e50,
+ 0x08017e50,
0x0464b600,
-/* 0x08ac: i2c_addr_done */
-/* 0x08ae: i2c_acquire_addr */
+/* 0x08a0: i2c_addr_done */
+/* 0x08a2: i2c_acquire_addr */
0xcec700f8,
0x05e4b6f8,
0xd014e0b7,
-/* 0x08ba: i2c_acquire */
- 0xae7e00f8,
+/* 0x08ae: i2c_acquire */
+ 0xa27e00f8,
0x047e0008,
0xd9f00000,
0x002e7e03,
-/* 0x08cb: i2c_release */
+/* 0x08bf: i2c_release */
0x7e00f800,
- 0x7e0008ae,
+ 0x7e0008a2,
0xf0000004,
0x2e7e03da,
0x00f80000,
-/* 0x08dc: i2c_recv */
+/* 0x08d0: i2c_recv */
0xc70132f4,
0x14b6f8c1,
0x2816b002,
@@ -1596,7 +1591,7 @@ uint32_t gk208_pmu_code[] = {
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x08ba7e50,
+ 0x08ae7e50,
0x0464b600,
0xd6b0d0fc,
0xb01bf500,
@@ -1606,7 +1601,7 @@ uint32_t gk208_pmu_code[] = {
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x0008677e,
+ 0x00085b7e,
0xf50464b6,
0xc700cc11,
0x76bbe0c5,
@@ -1615,7 +1610,7 @@ uint32_t gk208_pmu_code[] = {
0x0256bb04,
0x75fd50bd,
0x7e50fc04,
- 0xb600080d,
+ 0xb6000801,
0x11f50464,
0x010500a9,
0xb60076bb,
@@ -1623,7 +1618,7 @@ uint32_t gk208_pmu_code[] = {
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x08677e50,
+ 0x085b7e50,
0x0464b600,
0x008711f5,
0xb60076bb,
@@ -1631,7 +1626,7 @@ uint32_t gk208_pmu_code[] = {
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0x07be7e50,
+ 0x07b27e50,
0x0464b600,
0xcb6711f4,
0x76bbe05b,
@@ -1640,36 +1635,36 @@ uint32_t gk208_pmu_code[] = {
0x0256bb04,
0x75fd50bd,
0x7e50fc04,
- 0xb600070a,
+ 0xb60006fe,
0x5bb20464,
0x0ef474bd,
-/* 0x09e1: i2c_recv_not_rd08 */
+/* 0x09d5: i2c_recv_not_rd08 */
0x01d6b041,
0x053b1bf4,
- 0x08677e00,
+ 0x085b7e00,
0x3211f400,
0x7ee0c5c7,
- 0xf400080d,
+ 0xf4000801,
0x00052811,
- 0x0008677e,
+ 0x00085b7e,
0xc71f11f4,
- 0x0d7ee0b5,
+ 0x017ee0b5,
0x11f40008,
- 0x070a7e15,
+ 0x06fe7e15,
0xc774bd00,
0x1bf408c5,
0x0232f409,
-/* 0x0a1f: i2c_recv_not_wr08 */
-/* 0x0a1f: i2c_recv_done */
+/* 0x0a13: i2c_recv_not_wr08 */
+/* 0x0a13: i2c_recv_done */
0xc7030ef4,
- 0xcb7ef8ce,
+ 0xbf7ef8ce,
0xe0fc0008,
0x12f4d0fc,
0x7e7cb209,
-/* 0x0a33: i2c_recv_exit */
- 0xf80002c2,
-/* 0x0a35: i2c_init */
-/* 0x0a37: test_recv */
+/* 0x0a27: i2c_recv_exit */
+ 0xf80002b6,
+/* 0x0a29: i2c_init */
+/* 0x0a2b: test_recv */
0x4100f800,
0x11cf0458,
0x0110b600,
@@ -1677,28 +1672,28 @@ uint32_t gk208_pmu_code[] = {
0x04bd0001,
0xd900e7f1,
0x134fe3f1,
- 0x0002017e,
-/* 0x0a56: test_init */
+ 0x0001f57e,
+/* 0x0a4a: test_init */
0x004e00f8,
- 0x02017e08,
-/* 0x0a5f: idle_recv */
+ 0x01f57e08,
+/* 0x0a53: idle_recv */
0xf800f800,
-/* 0x0a61: idle */
+/* 0x0a55: idle */
0x0031f400,
0xcf045441,
0x10b60011,
0x04544001,
0xbd0001f6,
-/* 0x0a75: idle_loop */
+/* 0x0a69: idle_loop */
0xf4580104,
-/* 0x0a7a: idle_proc */
-/* 0x0a7a: idle_proc_exec */
+/* 0x0a6e: idle_proc */
+/* 0x0a6e: idle_proc_exec */
0x10f90232,
- 0xcb7e1eb2,
+ 0xbf7e1eb2,
0x10fc0002,
0xf40911f4,
0x0ef40231,
-/* 0x0a8d: idle_proc_next */
+/* 0x0a81: idle_proc_next */
0x5810b6f0,
0x1bf41fa6,
0xe002f4e8,
@@ -1728,4 +1723,7 @@ uint32_t gk208_pmu_code[] = {
0x00000000,
0x00000000,
0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
index 2686f8fad0f5..516569270bac 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
@@ -24,8 +24,8 @@ uint32_t gt215_pmu_data[] = {
0x00000000,
/* 0x0058: proc_list_head */
0x54534f48,
- 0x00000512,
- 0x000004af,
+ 0x00000507,
+ 0x000004a4,
0x00000000,
0x00000000,
0x00000000,
@@ -46,8 +46,8 @@ uint32_t gt215_pmu_data[] = {
0x00000000,
0x00000000,
0x584d454d,
- 0x00000842,
- 0x00000834,
+ 0x00000837,
+ 0x00000829,
0x00000000,
0x00000000,
0x00000000,
@@ -68,8 +68,8 @@ uint32_t gt215_pmu_data[] = {
0x00000000,
0x00000000,
0x46524550,
- 0x00000846,
- 0x00000844,
+ 0x0000083b,
+ 0x00000839,
0x00000000,
0x00000000,
0x00000000,
@@ -90,8 +90,8 @@ uint32_t gt215_pmu_data[] = {
0x00000000,
0x00000000,
0x5f433249,
- 0x00000c76,
- 0x00000b19,
+ 0x00000c6b,
+ 0x00000b0e,
0x00000000,
0x00000000,
0x00000000,
@@ -112,8 +112,8 @@ uint32_t gt215_pmu_data[] = {
0x00000000,
0x00000000,
0x54534554,
- 0x00000c9f,
- 0x00000c78,
+ 0x00000c94,
+ 0x00000c6d,
0x00000000,
0x00000000,
0x00000000,
@@ -134,8 +134,8 @@ uint32_t gt215_pmu_data[] = {
0x00000000,
0x00000000,
0x454c4449,
- 0x00000cab,
- 0x00000ca9,
+ 0x00000ca0,
+ 0x00000c9e,
0x00000000,
0x00000000,
0x00000000,
@@ -229,26 +229,26 @@ uint32_t gt215_pmu_data[] = {
/* 0x0370: memx_func_head */
0x00000001,
0x00000000,
- 0x00000551,
+ 0x00000546,
/* 0x037c: memx_func_next */
0x00000002,
0x00000000,
- 0x000005a8,
+ 0x0000059d,
0x00000003,
0x00000002,
- 0x0000063a,
+ 0x0000062f,
0x00040004,
0x00000000,
- 0x00000656,
+ 0x0000064b,
0x00010005,
0x00000000,
- 0x00000673,
+ 0x00000668,
0x00010006,
0x00000000,
- 0x000005f8,
+ 0x000005ed,
0x00000007,
0x00000000,
- 0x0000067e,
+ 0x00000673,
/* 0x03c4: memx_func_tail */
/* 0x03c4: memx_ts_start */
0x00000000,
@@ -917,7 +917,7 @@ uint32_t gt215_pmu_data[] = {
};
uint32_t gt215_pmu_code[] = {
- 0x039e0ef5,
+ 0x03930ef5,
/* 0x0004: rd32 */
0x07a007f1,
0xd00604b6,
@@ -987,7 +987,7 @@ uint32_t gt215_pmu_code[] = {
0xbb9a0a98,
0x1cf4029a,
0x01d7f00f,
- 0x02dd21f5,
+ 0x02d221f5,
0x0ef494bd,
/* 0x00f9: intr_watchdog_next_time */
0x9b0a9815,
@@ -1039,7 +1039,7 @@ uint32_t gt215_pmu_code[] = {
0x48e7f1c0,
0x53e3f14f,
0x00d7f054,
- 0x034221f5,
+ 0x033721f5,
0x07f1c0fc,
0x04b604c0,
0x000cd006,
@@ -1048,820 +1048,818 @@ uint32_t gt215_pmu_code[] = {
0x04b60688,
0x0009d006,
/* 0x01ca: intr_skip_subintr */
- 0x89c404bd,
- 0x070bf420,
- 0xffbfa4f1,
-/* 0x01d4: intr_skip_pause */
- 0xf44089c4,
- 0xa4f1070b,
-/* 0x01de: intr_skip_user0 */
- 0x07f0ffbf,
- 0x0604b604,
- 0xbd0008d0,
- 0xfe80fc04,
- 0xf0fc0088,
- 0xd0fce0fc,
- 0xb0fcc0fc,
- 0x90fca0fc,
- 0x00fc80fc,
- 0xf80032f4,
-/* 0x0205: ticks_from_ns */
- 0xf9c0f901,
- 0xcbd7f1b0,
- 0x00d3f000,
- 0x041321f5,
- 0x03e8ccec,
- 0xf400b4b0,
- 0xeeec120b,
- 0xd7f103e8,
- 0xd3f000cb,
- 0x1321f500,
-/* 0x022d: ticks_from_ns_quit */
- 0x02ceb904,
- 0xc0fcb0fc,
-/* 0x0236: ticks_from_us */
- 0xc0f900f8,
+ 0x97f104bd,
+ 0x90bd00e0,
+ 0xf00489fd,
+ 0x04b60407,
+ 0x0008d006,
+ 0x80fc04bd,
+ 0xfc0088fe,
+ 0xfce0fcf0,
+ 0xfcc0fcd0,
+ 0xfca0fcb0,
+ 0xfc80fc90,
+ 0x0032f400,
+/* 0x01fa: ticks_from_ns */
+ 0xc0f901f8,
0xd7f1b0f9,
0xd3f000cb,
- 0x1321f500,
- 0x02ceb904,
- 0xf400b4b0,
- 0xe4bd050b,
-/* 0x0250: ticks_from_us_quit */
- 0xc0fcb0fc,
-/* 0x0256: ticks_to_us */
- 0xd7f100f8,
- 0xd3f000cb,
- 0xecedff00,
-/* 0x0262: timer */
- 0x90f900f8,
- 0x32f480f9,
- 0x03f89810,
- 0xf40086b0,
- 0x84bd651c,
- 0xb63807f0,
- 0x08d00604,
- 0xf004bd00,
- 0x84b63487,
- 0x0088cf06,
- 0xbb9a0998,
- 0xe9bb0298,
- 0x03fe8000,
- 0xb60887f0,
- 0x88cf0684,
- 0x0284f000,
- 0xf0261bf4,
- 0x84b63487,
- 0x0088cf06,
- 0xf406e0b8,
- 0xe8b8090b,
- 0x111cf406,
-/* 0x02b8: timer_reset */
- 0xb63407f0,
- 0x0ed00604,
- 0x8004bd00,
-/* 0x02c6: timer_enable */
- 0x87f09a0e,
- 0x3807f001,
+ 0x0821f500,
+ 0xe8ccec04,
+ 0x00b4b003,
+ 0xec120bf4,
+ 0xf103e8ee,
+ 0xf000cbd7,
+ 0x21f500d3,
+/* 0x0222: ticks_from_ns_quit */
+ 0xceb90408,
+ 0xfcb0fc02,
+/* 0x022b: ticks_from_us */
+ 0xf900f8c0,
+ 0xf1b0f9c0,
+ 0xf000cbd7,
+ 0x21f500d3,
+ 0xceb90408,
+ 0x00b4b002,
+ 0xbd050bf4,
+/* 0x0245: ticks_from_us_quit */
+ 0xfcb0fce4,
+/* 0x024b: ticks_to_us */
+ 0xf100f8c0,
+ 0xf000cbd7,
+ 0xedff00d3,
+/* 0x0257: timer */
+ 0xf900f8ec,
+ 0xf480f990,
+ 0xf8981032,
+ 0x0086b003,
+ 0xbd651cf4,
+ 0x3807f084,
0xd00604b6,
0x04bd0008,
-/* 0x02d4: timer_done */
- 0xfc1031f4,
- 0xf890fc80,
-/* 0x02dd: send_proc */
- 0xf980f900,
- 0x05e89890,
- 0xf004e998,
- 0x89b80486,
- 0x2a0bf406,
- 0x940398c4,
- 0x80b60488,
- 0x008ebb18,
- 0x8000fa98,
- 0x8d80008a,
- 0x028c8001,
- 0xb6038b80,
- 0x94f00190,
- 0x04e98007,
-/* 0x0317: send_done */
- 0xfc0231f4,
- 0xf880fc90,
-/* 0x031d: find */
- 0xf080f900,
- 0x31f45887,
-/* 0x0325: find_loop */
- 0x008a9801,
- 0xf406aeb8,
- 0x80b6100b,
- 0x6886b158,
- 0xf01bf402,
-/* 0x033b: find_done */
- 0xb90132f4,
- 0x80fc028e,
-/* 0x0342: send */
- 0x21f500f8,
- 0x01f4031d,
-/* 0x034b: recv */
- 0xf900f897,
- 0x9880f990,
- 0xe99805e8,
- 0x0132f404,
- 0xf40689b8,
- 0x89c43d0b,
- 0x0180b603,
- 0x800784f0,
- 0xea9805e8,
- 0xfef0f902,
- 0xf0f9018f,
- 0x9402efb9,
- 0xe9bb0499,
- 0x18e0b600,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0xf0fca5f9,
- 0xf400f8fe,
- 0xf0fc0131,
-/* 0x0398: recv_done */
- 0x90fc80fc,
-/* 0x039e: init */
- 0x17f100f8,
- 0x14b60108,
- 0x0011cf06,
- 0x010911e7,
- 0xfe0814b6,
- 0x17f10014,
- 0x13f000e0,
- 0x1c07f000,
- 0xd00604b6,
- 0x04bd0001,
- 0xf0ff17f0,
- 0x04b61407,
- 0x0001d006,
- 0x17f004bd,
- 0x0015f102,
- 0x1007f008,
+ 0xb63487f0,
+ 0x88cf0684,
+ 0x9a099800,
+ 0xbb0298bb,
+ 0xfe8000e9,
+ 0x0887f003,
+ 0xcf0684b6,
+ 0x84f00088,
+ 0x261bf402,
+ 0xb63487f0,
+ 0x88cf0684,
+ 0x06e0b800,
+ 0xb8090bf4,
+ 0x1cf406e8,
+/* 0x02ad: timer_reset */
+ 0x3407f011,
0xd00604b6,
- 0x04bd0001,
- 0x011a17f1,
- 0xfe0013f0,
- 0x31f40010,
- 0x0117f010,
- 0xb63807f0,
+ 0x04bd000e,
+/* 0x02bb: timer_enable */
+ 0xf09a0e80,
+ 0x07f00187,
+ 0x0604b638,
+ 0xbd0008d0,
+/* 0x02c9: timer_done */
+ 0x1031f404,
+ 0x90fc80fc,
+/* 0x02d2: send_proc */
+ 0x80f900f8,
+ 0xe89890f9,
+ 0x04e99805,
+ 0xb80486f0,
+ 0x0bf40689,
+ 0x0398c42a,
+ 0xb6048894,
+ 0x8ebb1880,
+ 0x00fa9800,
+ 0x80008a80,
+ 0x8c80018d,
+ 0x038b8002,
+ 0xf00190b6,
+ 0xe9800794,
+ 0x0231f404,
+/* 0x030c: send_done */
+ 0x80fc90fc,
+/* 0x0312: find */
+ 0x80f900f8,
+ 0xf45887f0,
+/* 0x031a: find_loop */
+ 0x8a980131,
+ 0x06aeb800,
+ 0xb6100bf4,
+ 0x86b15880,
+ 0x1bf40268,
+ 0x0132f4f0,
+/* 0x0330: find_done */
+ 0xfc028eb9,
+/* 0x0337: send */
+ 0xf500f880,
+ 0xf4031221,
+ 0x00f89701,
+/* 0x0340: recv */
+ 0x80f990f9,
+ 0x9805e898,
+ 0x32f404e9,
+ 0x0689b801,
+ 0xc43d0bf4,
+ 0x80b60389,
+ 0x0784f001,
+ 0x9805e880,
+ 0xf0f902ea,
+ 0xf9018ffe,
+ 0x02efb9f0,
+ 0xbb049994,
+ 0xe0b600e9,
+ 0x03eb9818,
+ 0x9802ec98,
+ 0xee9801ed,
+ 0xfca5f900,
+ 0x00f8fef0,
+ 0xfc0131f4,
+/* 0x038d: recv_done */
+ 0xfc80fcf0,
+/* 0x0393: init */
+ 0xf100f890,
+ 0xb6010817,
+ 0x11cf0614,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf10014fe,
+ 0xf000e017,
+ 0x07f00013,
+ 0x0604b61c,
+ 0xbd0001d0,
+ 0xff17f004,
+ 0xb61407f0,
0x01d00604,
0xf004bd00,
-/* 0x0402: init_proc */
- 0xf19858f7,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x0413: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb9301dff,
- 0x34f10234,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0xe2ff01b4,
- 0x0234b930,
- 0xffff34f1,
- 0xb61034b6,
- 0xc3bb1045,
- 0x01b4bb00,
- 0xbb3012ff,
- 0x40fc00b3,
- 0x20fc30fc,
- 0x00f810fc,
-/* 0x0464: host_send */
- 0x04b017f1,
- 0xcf0614b6,
- 0x27f10011,
- 0x24b604a0,
- 0x0022cf06,
- 0xf40612b8,
- 0x1ec4320b,
- 0x04ee9407,
- 0x0270e0b7,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0x034221f5,
- 0xc40110b6,
- 0x07f10f1e,
- 0x04b604b0,
- 0x000ed006,
- 0x0ef404bd,
-/* 0x04ad: host_send_done */
-/* 0x04af: host_recv */
- 0xf100f8ba,
- 0xf14e4917,
- 0xb8525413,
- 0x0bf406e1,
-/* 0x04bd: host_recv_wait */
- 0xcc17f1aa,
+ 0x15f10217,
+ 0x07f00800,
+ 0x0604b610,
+ 0xbd0001d0,
+ 0x1a17f104,
+ 0x0013f001,
+ 0xf40010fe,
+ 0x17f01031,
+ 0x3807f001,
+ 0xd00604b6,
+ 0x04bd0001,
+/* 0x03f7: init_proc */
+ 0x9858f7f0,
+ 0x16b001f1,
+ 0xfa0bf400,
+ 0xf0b615f9,
+ 0xf20ef458,
+/* 0x0408: mulu32_32_64 */
+ 0x20f910f9,
+ 0x40f930f9,
+ 0x9510e195,
+ 0xc4bd10d2,
+ 0xedffb4bd,
+ 0x301dffc0,
+ 0xf10234b9,
+ 0xb6ffff34,
+ 0x45b61034,
+ 0x00c3bb10,
+ 0xff01b4bb,
+ 0x34b930e2,
+ 0xff34f102,
+ 0x1034b6ff,
+ 0xbb1045b6,
+ 0xb4bb00c3,
+ 0x3012ff01,
+ 0xfc00b3bb,
+ 0xfc30fc40,
+ 0xf810fc20,
+/* 0x0459: host_send */
+ 0xb017f100,
0x0614b604,
0xf10011cf,
- 0xb604c827,
+ 0xb604a027,
0x22cf0624,
- 0x0816f000,
- 0xf40612b8,
- 0x23c4e60b,
- 0x0434b607,
- 0x02f030b7,
- 0x80033b80,
- 0x3d80023c,
- 0x003e8001,
- 0xf00120b6,
- 0x07f10f24,
- 0x04b604c8,
- 0x0002d006,
- 0x27f004bd,
- 0x0007f040,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x0512: host_init */
- 0x17f100f8,
+ 0x0612b800,
+ 0xc4320bf4,
+ 0xee94071e,
+ 0x70e0b704,
+ 0x03eb9802,
+ 0x9802ec98,
+ 0xee9801ed,
+ 0x3721f500,
+ 0x0110b603,
+ 0xf10f1ec4,
+ 0xb604b007,
+ 0x0ed00604,
+ 0xf404bd00,
+/* 0x04a2: host_send_done */
+ 0x00f8ba0e,
+/* 0x04a4: host_recv */
+ 0x4e4917f1,
+ 0x525413f1,
+ 0xf406e1b8,
+/* 0x04b2: host_recv_wait */
+ 0x17f1aa0b,
+ 0x14b604cc,
+ 0x0011cf06,
+ 0x04c827f1,
+ 0xcf0624b6,
+ 0x16f00022,
+ 0x0612b808,
+ 0xc4e60bf4,
+ 0x34b60723,
+ 0xf030b704,
+ 0x033b8002,
+ 0x80023c80,
+ 0x3e80013d,
+ 0x0120b600,
+ 0xf10f24f0,
+ 0xb604c807,
+ 0x02d00604,
+ 0xf004bd00,
+ 0x07f04027,
+ 0x0604b600,
+ 0xbd0002d0,
+/* 0x0507: host_init */
+ 0xf100f804,
+ 0xb6008017,
+ 0x15f11014,
+ 0x07f10270,
+ 0x04b604d0,
+ 0x0001d006,
+ 0x17f104bd,
0x14b60080,
- 0x7015f110,
- 0xd007f102,
+ 0xf015f110,
+ 0xdc07f102,
0x0604b604,
0xbd0001d0,
- 0x8017f104,
- 0x1014b600,
- 0x02f015f1,
- 0x04dc07f1,
+ 0x0117f004,
+ 0x04c407f1,
0xd00604b6,
0x04bd0001,
- 0xf10117f0,
- 0xb604c407,
- 0x01d00604,
- 0xf804bd00,
-/* 0x0551: memx_func_enter */
- 0x1087f100,
- 0x028eb916,
- 0xb90421f4,
- 0x67f102d7,
- 0x63f1fffc,
- 0x76fdffff,
- 0x0267f104,
- 0x0576fd00,
- 0x70f980f9,
- 0xe0fcd0fc,
- 0xf03f21f4,
- 0x07f10467,
- 0x04b607e0,
- 0x0006d006,
-/* 0x058a: memx_func_enter_wait */
- 0x67f104bd,
- 0x64b607c0,
- 0x0066cf06,
- 0xf40464f0,
- 0x67f0f30b,
- 0x0664b62c,
- 0x800066cf,
- 0x00f8f106,
-/* 0x05a8: memx_func_leave */
- 0xb62c67f0,
- 0x66cf0664,
- 0xf2068000,
+/* 0x0546: memx_func_enter */
+ 0x87f100f8,
+ 0x8eb91610,
+ 0x0421f402,
+ 0xf102d7b9,
+ 0xf1fffc67,
+ 0xfdffff63,
+ 0x67f10476,
+ 0x76fd0002,
+ 0xf980f905,
+ 0xfcd0fc70,
+ 0x3f21f4e0,
0xf10467f0,
- 0xb607e407,
+ 0xb607e007,
0x06d00604,
-/* 0x05c3: memx_func_leave_wait */
+/* 0x057f: memx_func_enter_wait */
0xf104bd00,
0xb607c067,
0x66cf0664,
0x0464f000,
- 0xf1f31bf4,
- 0xb9161087,
- 0x21f4028e,
- 0x02d7b904,
- 0xffcc67f1,
- 0xffff63f1,
- 0xf90476fd,
- 0xfc70f980,
- 0xf4e0fcd0,
- 0x00f83f21,
-/* 0x05f8: memx_func_wait_vblank */
- 0xb0001698,
- 0x0bf40066,
- 0x0166b013,
- 0xf4060bf4,
-/* 0x060a: memx_func_wait_vblank_head1 */
- 0x77f12e0e,
- 0x0ef40020,
-/* 0x0611: memx_func_wait_vblank_head0 */
- 0x0877f107,
-/* 0x0615: memx_func_wait_vblank_0 */
- 0xc467f100,
- 0x0664b607,
- 0xfd0066cf,
- 0x1bf40467,
-/* 0x0625: memx_func_wait_vblank_1 */
- 0xc467f1f3,
- 0x0664b607,
- 0xfd0066cf,
- 0x0bf40467,
-/* 0x0635: memx_func_wait_vblank_fini */
- 0x0410b6f3,
-/* 0x063a: memx_func_wr32 */
- 0x169800f8,
- 0x01159800,
- 0xf90810b6,
- 0xfc50f960,
- 0xf4e0fcd0,
- 0x42b63f21,
- 0xe91bf402,
-/* 0x0656: memx_func_wait */
- 0x87f000f8,
- 0x0684b62c,
- 0x980088cf,
- 0x1d98001e,
- 0x021c9801,
- 0xb6031b98,
- 0x21f41010,
-/* 0x0673: memx_func_delay */
- 0x9800f8a4,
- 0x10b6001e,
- 0x7f21f404,
-/* 0x067e: memx_func_train */
- 0x57f100f8,
- 0x77f10003,
- 0x97f10000,
- 0x93f00000,
- 0x029eb970,
- 0xb90421f4,
- 0xe7f102d8,
- 0x21f42710,
-/* 0x069d: memx_func_train_loop_outer */
- 0x0158e07f,
- 0x0083f101,
- 0xe097f102,
- 0x1193f011,
- 0x80f990f9,
+ 0xf0f30bf4,
+ 0x64b62c67,
+ 0x0066cf06,
+ 0xf8f10680,
+/* 0x059d: memx_func_leave */
+ 0x2c67f000,
+ 0xcf0664b6,
+ 0x06800066,
+ 0x0467f0f2,
+ 0x07e407f1,
+ 0xd00604b6,
+ 0x04bd0006,
+/* 0x05b8: memx_func_leave_wait */
+ 0x07c067f1,
+ 0xcf0664b6,
+ 0x64f00066,
+ 0xf31bf404,
+ 0x161087f1,
+ 0xf4028eb9,
+ 0xd7b90421,
+ 0xcc67f102,
+ 0xff63f1ff,
+ 0x0476fdff,
+ 0x70f980f9,
0xe0fcd0fc,
- 0xf93f21f4,
- 0x0067f150,
-/* 0x06bd: memx_func_train_loop_inner */
- 0x1187f100,
- 0x9068ff11,
- 0xfd109894,
- 0x97f10589,
- 0x93f00720,
- 0xf990f910,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x008097f1,
- 0xb91093f0,
- 0x21f4029e,
- 0x02d8b904,
- 0xf92088c5,
- 0xfc80f990,
- 0xf4e0fcd0,
- 0x97f13f21,
- 0x93f0053c,
- 0x0287f110,
- 0x0083f130,
- 0xf990f980,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x0560e7f1,
- 0xf110e3f0,
- 0xf10000d7,
- 0x908000d3,
- 0xb7f100dc,
- 0xb3f08480,
- 0xa421f41e,
- 0x000057f1,
- 0xffff97f1,
- 0x830093f1,
-/* 0x073c: memx_func_train_loop_4x */
- 0x0080a7f1,
- 0xb910a3f0,
- 0x21f402ae,
- 0x02d8b904,
- 0xffdfb7f1,
- 0xffffb3f1,
- 0xf9048bfd,
- 0xfc80f9a0,
- 0xf4e0fcd0,
- 0xa7f13f21,
- 0xa3f0053c,
- 0x0287f110,
- 0x0083f130,
- 0xf9a0f980,
+ 0xf83f21f4,
+/* 0x05ed: memx_func_wait_vblank */
+ 0x00169800,
+ 0xf40066b0,
+ 0x66b0130b,
+ 0x060bf401,
+/* 0x05ff: memx_func_wait_vblank_head1 */
+ 0xf12e0ef4,
+ 0xf4002077,
+/* 0x0606: memx_func_wait_vblank_head0 */
+ 0x77f1070e,
+/* 0x060a: memx_func_wait_vblank_0 */
+ 0x67f10008,
+ 0x64b607c4,
+ 0x0066cf06,
+ 0xf40467fd,
+/* 0x061a: memx_func_wait_vblank_1 */
+ 0x67f1f31b,
+ 0x64b607c4,
+ 0x0066cf06,
+ 0xf40467fd,
+/* 0x062a: memx_func_wait_vblank_fini */
+ 0x10b6f30b,
+/* 0x062f: memx_func_wr32 */
+ 0x9800f804,
+ 0x15980016,
+ 0x0810b601,
+ 0x50f960f9,
+ 0xe0fcd0fc,
+ 0xb63f21f4,
+ 0x1bf40242,
+/* 0x064b: memx_func_wait */
+ 0xf000f8e9,
+ 0x84b62c87,
+ 0x0088cf06,
+ 0x98001e98,
+ 0x1c98011d,
+ 0x031b9802,
+ 0xf41010b6,
+ 0x00f8a421,
+/* 0x0668: memx_func_delay */
+ 0xb6001e98,
+ 0x21f40410,
+/* 0x0673: memx_func_train */
+ 0xf100f87f,
+ 0xf1000357,
+ 0xf1000077,
+ 0xf0000097,
+ 0x9eb97093,
+ 0x0421f402,
+ 0xf102d8b9,
+ 0xf42710e7,
+/* 0x0692: memx_func_train_loop_outer */
+ 0x58e07f21,
+ 0x83f10101,
+ 0x97f10200,
+ 0x93f011e0,
+ 0xf990f911,
0xfcd0fc80,
0x3f21f4e0,
- 0x0560e7f1,
- 0xf110e3f0,
- 0xf10000d7,
- 0xb98000d3,
- 0xb7f102dc,
- 0xb3f02710,
- 0xa421f400,
- 0xf402eeb9,
- 0xddb90421,
- 0x949dff02,
+ 0x67f150f9,
+/* 0x06b2: memx_func_train_loop_inner */
+ 0x87f10000,
+ 0x68ff1111,
+ 0x10989490,
+ 0xf10589fd,
+ 0xf0072097,
+ 0x90f91093,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+ 0x8097f13f,
+ 0x1093f000,
+ 0xf4029eb9,
+ 0xd8b90421,
+ 0x2088c502,
+ 0x80f990f9,
+ 0xe0fcd0fc,
+ 0xf13f21f4,
+ 0xf0053c97,
+ 0x87f11093,
+ 0x83f13002,
+ 0x90f98000,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+ 0x60e7f13f,
+ 0x10e3f005,
+ 0x0000d7f1,
+ 0x8000d3f1,
+ 0xf100dc90,
+ 0xf08480b7,
+ 0x21f41eb3,
+ 0x0057f1a4,
+ 0xff97f100,
+ 0x0093f1ff,
+/* 0x0731: memx_func_train_loop_4x */
+ 0x80a7f183,
+ 0x10a3f000,
+ 0xf402aeb9,
+ 0xd8b90421,
+ 0xdfb7f102,
+ 0xffb3f1ff,
+ 0x048bfdff,
+ 0x80f9a0f9,
+ 0xe0fcd0fc,
+ 0xf13f21f4,
+ 0xf0053ca7,
+ 0x87f110a3,
+ 0x83f13002,
+ 0xa0f98000,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+ 0x60e7f13f,
+ 0x10e3f005,
+ 0x0000d7f1,
+ 0x8000d3f1,
+ 0xf102dcb9,
+ 0xf02710b7,
+ 0x21f400b3,
+ 0x02eeb9a4,
+ 0xb90421f4,
+ 0x9dff02dd,
+ 0x0150b694,
+ 0xf4045670,
+ 0x7aa0921e,
+ 0xa9800bcc,
+ 0x0160b600,
+ 0x700470b6,
+ 0x1ef51066,
+ 0x50fcff00,
0x700150b6,
- 0x1ef40456,
- 0xcc7aa092,
- 0x00a9800b,
- 0xb60160b6,
- 0x66700470,
- 0x001ef510,
- 0xb650fcff,
- 0x56700150,
- 0xd41ef507,
-/* 0x07cf: memx_exec */
- 0xf900f8fe,
- 0xb9d0f9e0,
- 0xb2b902c1,
-/* 0x07d9: memx_exec_next */
- 0x00139802,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12b855f9,
- 0xe41ef406,
- 0x98f10b98,
- 0xcbbbf20c,
- 0xc4b7f102,
- 0x06b4b607,
- 0xfc00bbcf,
- 0xf5e0fcd0,
- 0xf8034221,
-/* 0x0815: memx_info */
- 0x01c67000,
-/* 0x081b: memx_info_data */
- 0xf10e0bf4,
- 0xf103ccc7,
- 0xf40800b7,
-/* 0x0826: memx_info_train */
- 0xc7f10b0e,
- 0xb7f10bcc,
-/* 0x082e: memx_info_send */
- 0x21f50100,
- 0x00f80342,
-/* 0x0834: memx_recv */
- 0xf401d6b0,
- 0xd6b0980b,
- 0xd80bf400,
-/* 0x0842: memx_init */
- 0x00f800f8,
-/* 0x0844: perf_recv */
-/* 0x0846: perf_init */
- 0x00f800f8,
-/* 0x0848: i2c_drive_scl */
- 0xf40036b0,
- 0x07f1110b,
- 0x04b607e0,
- 0x0001d006,
- 0x00f804bd,
-/* 0x085c: i2c_drive_scl_lo */
- 0x07e407f1,
- 0xd00604b6,
- 0x04bd0001,
-/* 0x086a: i2c_drive_sda */
- 0x36b000f8,
- 0x110bf400,
- 0x07e007f1,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x087e: i2c_drive_sda_lo */
- 0x07f100f8,
- 0x04b607e4,
- 0x0002d006,
- 0x00f804bd,
-/* 0x088c: i2c_sense_scl */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0431fd00,
- 0xf4060bf4,
-/* 0x08a2: i2c_sense_scl_done */
- 0x00f80131,
-/* 0x08a4: i2c_sense_sda */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0432fd00,
- 0xf4060bf4,
-/* 0x08ba: i2c_sense_sda_done */
- 0x00f80131,
-/* 0x08bc: i2c_raise_scl */
- 0x47f140f9,
- 0x37f00898,
- 0x4821f501,
-/* 0x08c9: i2c_raise_scl_wait */
+ 0x1ef50756,
+ 0x00f8fed4,
+/* 0x07c4: memx_exec */
+ 0xd0f9e0f9,
+ 0xb902c1b9,
+/* 0x07ce: memx_exec_next */
+ 0x139802b2,
+ 0x0410b600,
+ 0x01f034e7,
+ 0x01e033e7,
+ 0xf00132b6,
+ 0x35980c30,
+ 0xb855f9de,
+ 0x1ef40612,
+ 0xf10b98e4,
+ 0xbbf20c98,
+ 0xb7f102cb,
+ 0xb4b607c4,
+ 0x00bbcf06,
+ 0xe0fcd0fc,
+ 0x033721f5,
+/* 0x080a: memx_info */
+ 0xc67000f8,
+ 0x0e0bf401,
+/* 0x0810: memx_info_data */
+ 0x03ccc7f1,
+ 0x0800b7f1,
+/* 0x081b: memx_info_train */
+ 0xf10b0ef4,
+ 0xf10bccc7,
+/* 0x0823: memx_info_send */
+ 0xf50100b7,
+ 0xf8033721,
+/* 0x0829: memx_recv */
+ 0x01d6b000,
+ 0xb0980bf4,
+ 0x0bf400d6,
+/* 0x0837: memx_init */
+ 0xf800f8d8,
+/* 0x0839: perf_recv */
+/* 0x083b: perf_init */
+ 0xf800f800,
+/* 0x083d: i2c_drive_scl */
+ 0x0036b000,
+ 0xf1110bf4,
+ 0xb607e007,
+ 0x01d00604,
+ 0xf804bd00,
+/* 0x0851: i2c_drive_scl_lo */
+ 0xe407f100,
+ 0x0604b607,
+ 0xbd0001d0,
+/* 0x085f: i2c_drive_sda */
+ 0xb000f804,
+ 0x0bf40036,
+ 0xe007f111,
+ 0x0604b607,
+ 0xbd0002d0,
+/* 0x0873: i2c_drive_sda_lo */
+ 0xf100f804,
+ 0xb607e407,
+ 0x02d00604,
+ 0xf804bd00,
+/* 0x0881: i2c_sense_scl */
+ 0x0132f400,
+ 0x07c437f1,
+ 0xcf0634b6,
+ 0x31fd0033,
+ 0x060bf404,
+/* 0x0897: i2c_sense_scl_done */
+ 0xf80131f4,
+/* 0x0899: i2c_sense_sda */
+ 0x0132f400,
+ 0x07c437f1,
+ 0xcf0634b6,
+ 0x32fd0033,
+ 0x060bf404,
+/* 0x08af: i2c_sense_sda_done */
+ 0xf80131f4,
+/* 0x08b1: i2c_raise_scl */
+ 0xf140f900,
+ 0xf0089847,
+ 0x21f50137,
+/* 0x08be: i2c_raise_scl_wait */
+ 0xe7f1083d,
+ 0x21f403e8,
+ 0x8121f57f,
+ 0x0901f408,
+ 0xf40142b6,
+/* 0x08d2: i2c_raise_scl_done */
+ 0x40fcef1b,
+/* 0x08d6: i2c_start */
+ 0x21f500f8,
+ 0x11f40881,
+ 0x9921f50d,
+ 0x0611f408,
+/* 0x08e7: i2c_start_rep */
+ 0xf0300ef4,
+ 0x21f50037,
+ 0x37f0083d,
+ 0x5f21f501,
+ 0x0076bb08,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b608b1,
+ 0x1f11f404,
+/* 0x0914: i2c_start_send */
+ 0xf50037f0,
+ 0xf1085f21,
+ 0xf41388e7,
+ 0x37f07f21,
+ 0x3d21f500,
+ 0x88e7f108,
+ 0x7f21f413,
+/* 0x0930: i2c_start_out */
+/* 0x0932: i2c_stop */
+ 0x37f000f8,
+ 0x3d21f500,
+ 0x0037f008,
+ 0x085f21f5,
+ 0x03e8e7f1,
+ 0xf07f21f4,
+ 0x21f50137,
+ 0xe7f1083d,
+ 0x21f41388,
+ 0x0137f07f,
+ 0x085f21f5,
+ 0x1388e7f1,
+ 0xf87f21f4,
+/* 0x0965: i2c_bitw */
+ 0x5f21f500,
0xe8e7f108,
0x7f21f403,
- 0x088c21f5,
- 0xb60901f4,
- 0x1bf40142,
-/* 0x08dd: i2c_raise_scl_done */
- 0xf840fcef,
-/* 0x08e1: i2c_start */
- 0x8c21f500,
- 0x0d11f408,
- 0x08a421f5,
- 0xf40611f4,
-/* 0x08f2: i2c_start_rep */
- 0x37f0300e,
- 0x4821f500,
- 0x0137f008,
- 0x086a21f5,
0xb60076bb,
0x50f90465,
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0xbc21f550,
+ 0xb121f550,
0x0464b608,
-/* 0x091f: i2c_start_send */
- 0xf01f11f4,
- 0x21f50037,
- 0xe7f1086a,
- 0x21f41388,
- 0x0037f07f,
- 0x084821f5,
- 0x1388e7f1,
-/* 0x093b: i2c_start_out */
- 0xf87f21f4,
-/* 0x093d: i2c_stop */
- 0x0037f000,
- 0x084821f5,
- 0xf50037f0,
- 0xf1086a21,
- 0xf403e8e7,
+ 0xf11811f4,
+ 0xf41388e7,
0x37f07f21,
- 0x4821f501,
+ 0x3d21f500,
0x88e7f108,
0x7f21f413,
- 0xf50137f0,
- 0xf1086a21,
- 0xf41388e7,
- 0x00f87f21,
-/* 0x0970: i2c_bitw */
- 0x086a21f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x08bc21f5,
- 0xf40464b6,
- 0xe7f11811,
+/* 0x09a4: i2c_bitw_out */
+/* 0x09a6: i2c_bitr */
+ 0x37f000f8,
+ 0x5f21f501,
+ 0xe8e7f108,
+ 0x7f21f403,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xb121f550,
+ 0x0464b608,
+ 0xf51b11f4,
+ 0xf0089921,
+ 0x21f50037,
+ 0xe7f1083d,
0x21f41388,
- 0x0037f07f,
- 0x084821f5,
- 0x1388e7f1,
-/* 0x09af: i2c_bitw_out */
- 0xf87f21f4,
-/* 0x09b1: i2c_bitr */
- 0x0137f000,
- 0x086a21f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x08bc21f5,
- 0xf40464b6,
- 0x21f51b11,
- 0x37f008a4,
- 0x4821f500,
- 0x88e7f108,
- 0x7f21f413,
- 0xf4013cf0,
-/* 0x09f6: i2c_bitr_done */
- 0x00f80131,
-/* 0x09f8: i2c_get_byte */
- 0xf00057f0,
-/* 0x09fe: i2c_get_byte_next */
- 0x54b60847,
+ 0x013cf07f,
+/* 0x09eb: i2c_bitr_done */
+ 0xf80131f4,
+/* 0x09ed: i2c_get_byte */
+ 0x0057f000,
+/* 0x09f3: i2c_get_byte_next */
+ 0xb60847f0,
+ 0x76bb0154,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb609a621,
+ 0x11f40464,
+ 0x0553fd2b,
+ 0xf40142b6,
+ 0x37f0d81b,
0x0076bb01,
0xf90465b6,
0x04659450,
0xbd0256bb,
0x0475fd50,
0x21f550fc,
- 0x64b609b1,
- 0x2b11f404,
- 0xb60553fd,
- 0x1bf40142,
- 0x0137f0d8,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x7021f550,
- 0x0464b609,
-/* 0x0a48: i2c_get_byte_done */
-/* 0x0a4a: i2c_put_byte */
- 0x47f000f8,
-/* 0x0a4d: i2c_put_byte_next */
- 0x0142b608,
- 0xbb3854ff,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x097021f5,
- 0xf40464b6,
- 0x46b03411,
- 0xd81bf400,
+ 0x64b60965,
+/* 0x0a3d: i2c_get_byte_done */
+/* 0x0a3f: i2c_put_byte */
+ 0xf000f804,
+/* 0x0a42: i2c_put_byte_next */
+ 0x42b60847,
+ 0x3854ff01,
0xb60076bb,
0x50f90465,
0xbb046594,
0x50bd0256,
0xfc0475fd,
- 0xb121f550,
+ 0x6521f550,
0x0464b609,
- 0xbb0f11f4,
- 0x36b00076,
- 0x061bf401,
-/* 0x0aa3: i2c_put_byte_done */
- 0xf80132f4,
-/* 0x0aa5: i2c_addr */
- 0x0076bb00,
+ 0xb03411f4,
+ 0x1bf40046,
+ 0x0076bbd8,
0xf90465b6,
0x04659450,
0xbd0256bb,
0x0475fd50,
0x21f550fc,
- 0x64b608e1,
- 0x2911f404,
- 0x012ec3e7,
- 0xfd0134b6,
- 0x76bb0553,
+ 0x64b609a6,
+ 0x0f11f404,
+ 0xb00076bb,
+ 0x1bf40136,
+ 0x0132f406,
+/* 0x0a98: i2c_put_byte_done */
+/* 0x0a9a: i2c_addr */
+ 0x76bb00f8,
0x0465b600,
0x659450f9,
0x0256bb04,
0x75fd50bd,
0xf550fc04,
- 0xb60a4a21,
-/* 0x0aea: i2c_addr_done */
- 0x00f80464,
-/* 0x0aec: i2c_acquire_addr */
- 0xb6f8cec7,
- 0xe0b702e4,
- 0xee980d1c,
-/* 0x0afb: i2c_acquire */
- 0xf500f800,
- 0xf40aec21,
- 0xd9f00421,
- 0x3f21f403,
-/* 0x0b0a: i2c_release */
- 0x21f500f8,
- 0x21f40aec,
- 0x03daf004,
- 0xf83f21f4,
-/* 0x0b19: i2c_recv */
- 0x0132f400,
- 0xb6f8c1c7,
- 0x16b00214,
- 0x3a1ff528,
- 0xf413a001,
- 0x0032980c,
- 0x0ccc13a0,
- 0xf4003198,
- 0xd0f90231,
- 0xd0f9e0f9,
- 0x000067f1,
- 0x100063f1,
- 0xbb016792,
+ 0xb608d621,
+ 0x11f40464,
+ 0x2ec3e729,
+ 0x0134b601,
+ 0xbb0553fd,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x0afb21f5,
- 0xfc0464b6,
- 0x00d6b0d0,
- 0x00b31bf5,
- 0xbb0057f0,
+ 0x0a3f21f5,
+/* 0x0adf: i2c_addr_done */
+ 0xf80464b6,
+/* 0x0ae1: i2c_acquire_addr */
+ 0xf8cec700,
+ 0xb702e4b6,
+ 0x980d1ce0,
+ 0x00f800ee,
+/* 0x0af0: i2c_acquire */
+ 0x0ae121f5,
+ 0xf00421f4,
+ 0x21f403d9,
+/* 0x0aff: i2c_release */
+ 0xf500f83f,
+ 0xf40ae121,
+ 0xdaf00421,
+ 0x3f21f403,
+/* 0x0b0e: i2c_recv */
+ 0x32f400f8,
+ 0xf8c1c701,
+ 0xb00214b6,
+ 0x1ff52816,
+ 0x13a0013a,
+ 0x32980cf4,
+ 0xcc13a000,
+ 0x0031980c,
+ 0xf90231f4,
+ 0xf9e0f9d0,
+ 0x0067f1d0,
+ 0x0063f100,
+ 0x01679210,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xf021f550,
+ 0x0464b60a,
+ 0xd6b0d0fc,
+ 0xb31bf500,
+ 0x0057f000,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x9a21f550,
+ 0x0464b60a,
+ 0x00d011f5,
+ 0xbbe0c5c7,
0x65b60076,
0x9450f904,
0x56bb0465,
0xfd50bd02,
0x50fc0475,
- 0x0aa521f5,
+ 0x0a3f21f5,
0xf50464b6,
- 0xc700d011,
- 0x76bbe0c5,
+ 0xf000ad11,
+ 0x76bb0157,
0x0465b600,
0x659450f9,
0x0256bb04,
0x75fd50bd,
0xf550fc04,
- 0xb60a4a21,
+ 0xb60a9a21,
0x11f50464,
- 0x57f000ad,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b60aa5,
- 0x8a11f504,
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b609f8,
- 0x6a11f404,
- 0xbbe05bcb,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x093d21f5,
- 0xb90464b6,
- 0x74bd025b,
-/* 0x0c1f: i2c_recv_not_rd08 */
- 0xb0430ef4,
- 0x1bf401d6,
- 0x0057f03d,
- 0x0aa521f5,
- 0xc73311f4,
- 0x21f5e0c5,
- 0x11f40a4a,
- 0x0057f029,
- 0x0aa521f5,
- 0xc71f11f4,
- 0x21f5e0b5,
- 0x11f40a4a,
- 0x3d21f515,
- 0xc774bd09,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0c5f: i2c_recv_not_wr08 */
-/* 0x0c5f: i2c_recv_done */
- 0xc7030ef4,
- 0x21f5f8ce,
- 0xe0fc0b0a,
- 0x12f4d0fc,
- 0x027cb90a,
- 0x034221f5,
-/* 0x0c74: i2c_recv_exit */
-/* 0x0c76: i2c_init */
+ 0x76bb008a,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb609ed21,
+ 0x11f40464,
+ 0xe05bcb6a,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x3221f550,
+ 0x0464b609,
+ 0xbd025bb9,
+ 0x430ef474,
+/* 0x0c14: i2c_recv_not_rd08 */
+ 0xf401d6b0,
+ 0x57f03d1b,
+ 0x9a21f500,
+ 0x3311f40a,
+ 0xf5e0c5c7,
+ 0xf40a3f21,
+ 0x57f02911,
+ 0x9a21f500,
+ 0x1f11f40a,
+ 0xf5e0b5c7,
+ 0xf40a3f21,
+ 0x21f51511,
+ 0x74bd0932,
+ 0xf408c5c7,
+ 0x32f4091b,
+ 0x030ef402,
+/* 0x0c54: i2c_recv_not_wr08 */
+/* 0x0c54: i2c_recv_done */
+ 0xf5f8cec7,
+ 0xfc0aff21,
+ 0xf4d0fce0,
+ 0x7cb90a12,
+ 0x3721f502,
+/* 0x0c69: i2c_recv_exit */
+/* 0x0c6b: i2c_init */
+ 0xf800f803,
+/* 0x0c6d: test_recv */
+ 0xd817f100,
+ 0x0614b605,
+ 0xb60011cf,
+ 0x07f10110,
+ 0x04b605d8,
+ 0x0001d006,
+ 0xe7f104bd,
+ 0xe3f1d900,
+ 0x21f5134f,
+ 0x00f80257,
+/* 0x0c94: test_init */
+ 0x0800e7f1,
+ 0x025721f5,
+/* 0x0c9e: idle_recv */
0x00f800f8,
-/* 0x0c78: test_recv */
- 0x05d817f1,
- 0xcf0614b6,
- 0x10b60011,
- 0xd807f101,
- 0x0604b605,
- 0xbd0001d0,
- 0x00e7f104,
- 0x4fe3f1d9,
- 0x6221f513,
-/* 0x0c9f: test_init */
- 0xf100f802,
- 0xf50800e7,
- 0xf8026221,
-/* 0x0ca9: idle_recv */
-/* 0x0cab: idle */
- 0xf400f800,
- 0x17f10031,
- 0x14b605d4,
- 0x0011cf06,
- 0xf10110b6,
- 0xb605d407,
- 0x01d00604,
-/* 0x0cc7: idle_loop */
- 0xf004bd00,
- 0x32f45817,
-/* 0x0ccd: idle_proc */
-/* 0x0ccd: idle_proc_exec */
- 0xb910f902,
- 0x21f5021e,
- 0x10fc034b,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0ce1: idle_proc_next */
- 0x5810b6ef,
- 0xf4061fb8,
- 0x02f4e61b,
- 0x0028f4dd,
- 0x00bb0ef4,
+/* 0x0ca0: idle */
+ 0xf10031f4,
+ 0xb605d417,
+ 0x11cf0614,
+ 0x0110b600,
+ 0x05d407f1,
+ 0xd00604b6,
+ 0x04bd0001,
+/* 0x0cbc: idle_loop */
+ 0xf45817f0,
+/* 0x0cc2: idle_proc */
+/* 0x0cc2: idle_proc_exec */
+ 0x10f90232,
+ 0xf5021eb9,
+ 0xfc034021,
+ 0x0911f410,
+ 0xf40231f4,
+/* 0x0cd6: idle_proc_next */
+ 0x10b6ef0e,
+ 0x061fb858,
+ 0xf4e61bf4,
+ 0x28f4dd02,
+ 0xbb0ef400,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
index 5cf5be63cbef..ad35fa57be94 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
@@ -225,17 +225,11 @@ intr:
nv_iowr(NV_PPWR_SUBINTR, $r9)
intr_skip_subintr:
- and $r9 $r8 NV_PPWR_INTR_PAUSE
- bra z #intr_skip_pause
- and $r10 0xffbf
-
- intr_skip_pause:
- and $r9 $r8 NV_PPWR_INTR_USER0
- bra z #intr_skip_user0
- and $r10 0xffbf
-
- intr_skip_user0:
+ mov $r9 (NV_PPWR_INTR_USER0 | NV_PPWR_INTR_USER1 | NV_PPWR_INTR_PAUSE)
+ not b32 $r9
+ and $r8 $r9
nv_iowr(NV_PPWR_INTR_ACK, $r8)
+
pop $r8
mov $flags $r8
pop $r15
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
index 6326fdc5a48d..2c92ffb5f9d0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
@@ -107,7 +107,7 @@ nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
{
struct nvkm_subdev *subdev = &therm->subdev;
struct nvkm_device *device = subdev->device;
- u32 mask = enable ? 0x80000000 : 0x0000000;
+ u32 mask = enable ? 0x80000000 : 0x00000000;
if (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask);
else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask);
else {
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig
index 6c220cd3497a..336ad4de9981 100644
--- a/drivers/gpu/drm/omapdrm/Kconfig
+++ b/drivers/gpu/drm/omapdrm/Kconfig
@@ -1,9 +1,8 @@
-
config DRM_OMAP
tristate "OMAP DRM"
depends on DRM
depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
- depends on OMAP2_DSS
+ select OMAP2_DSS
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select FB_SYS_FILLRECT
@@ -14,13 +13,18 @@ config DRM_OMAP
help
DRM display driver for OMAP2/3/4 based boards.
+if DRM_OMAP
+
config DRM_OMAP_NUM_CRTCS
int "Number of CRTCs"
range 1 10
default 1 if ARCH_OMAP2 || ARCH_OMAP3
default 2 if ARCH_OMAP4
- depends on DRM_OMAP
help
Select the number of video overlays which can be used as framebuffers.
The remaining overlays are reserved for video.
+source "drivers/gpu/drm/omapdrm/dss/Kconfig"
+source "drivers/gpu/drm/omapdrm/displays/Kconfig"
+
+endif
diff --git a/drivers/gpu/drm/omapdrm/Makefile b/drivers/gpu/drm/omapdrm/Makefile
index 778372b062ad..fe4c2228bc18 100644
--- a/drivers/gpu/drm/omapdrm/Makefile
+++ b/drivers/gpu/drm/omapdrm/Makefile
@@ -3,6 +3,9 @@
# Direct Rendering Infrastructure (DRI)
#
+obj-y += dss/
+obj-y += displays/
+
ccflags-y := -Iinclude/drm -Werror
omapdrm-y := omap_drv.o \
omap_irq.o \
@@ -12,10 +15,11 @@ omapdrm-y := omap_drv.o \
omap_encoder.o \
omap_connector.o \
omap_fb.o \
- omap_fbdev.o \
omap_gem.o \
omap_gem_dmabuf.o \
omap_dmm_tiler.o \
tcm-sita.o
+omapdrm-$(CONFIG_DRM_FBDEV_EMULATION) += omap_fbdev.o
+
obj-$(CONFIG_DRM_OMAP) += omapdrm.o
diff --git a/drivers/video/fbdev/omap2/displays-new/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig
index 574710141a61..2a618afe0f53 100644
--- a/drivers/video/fbdev/omap2/displays-new/Kconfig
+++ b/drivers/gpu/drm/omapdrm/displays/Kconfig
@@ -1,5 +1,4 @@
-menu "OMAP Display Device Drivers (new device model)"
- depends on OMAP2_DSS
+menu "OMAPDRM External Display Device Drivers"
config DISPLAY_ENCODER_OPA362
tristate "OPA362 external analog amplifier"
diff --git a/drivers/video/fbdev/omap2/displays-new/Makefile b/drivers/gpu/drm/omapdrm/displays/Makefile
index 9aa176bfbf2e..9aa176bfbf2e 100644
--- a/drivers/video/fbdev/omap2/displays-new/Makefile
+++ b/drivers/gpu/drm/omapdrm/displays/Makefile
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
index 8511c648a15c..8511c648a15c 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c
+++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c
index d811e6dcaef7..d811e6dcaef7 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
+++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
index 6ee4129bc0c0..6ee4129bc0c0 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
+++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
index 8c246c213e06..8c246c213e06 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
index d9048b3df495..d9048b3df495 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
index 990af6baeb0f..990af6baeb0f 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
index f7be3489f744..e780fd4f8b46 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
@@ -83,8 +83,7 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
if (r)
return r;
- if (ddata->enable_gpio)
- gpiod_set_value_cansleep(ddata->enable_gpio, 1);
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 1);
@@ -102,12 +101,11 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
if (!omapdss_device_is_enabled(dssdev))
return;
- if (ddata->enable_gpio)
- gpiod_set_value_cansleep(ddata->enable_gpio, 0);
-
if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 0);
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
+
in->ops.dpi->disable(in);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
index 3414c2609320..3414c2609320 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-dsi-cm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
index 18eb60e9c9ec..18eb60e9c9ec 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
index 8a928c9a2fc9..8a928c9a2fc9 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
index abfd1f6e3327..abfd1f6e3327 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
index 31efcca801bd..31efcca801bd 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
index 4d657f3ab679..4d657f3ab679 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
index 68e3b68a2920..68e3b68a2920 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/gpu/drm/omapdrm/dss/Kconfig
index d1fa730c7d54..d1fa730c7d54 100644
--- a/drivers/video/fbdev/omap2/dss/Kconfig
+++ b/drivers/gpu/drm/omapdrm/dss/Kconfig
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile
index b5136d3d4b77..b5136d3d4b77 100644
--- a/drivers/video/fbdev/omap2/dss/Makefile
+++ b/drivers/gpu/drm/omapdrm/dss/Makefile
diff --git a/drivers/video/fbdev/omap2/dss/apply.c b/drivers/gpu/drm/omapdrm/dss/apply.c
index 663ccc3bf4e5..663ccc3bf4e5 100644
--- a/drivers/video/fbdev/omap2/dss/apply.c
+++ b/drivers/gpu/drm/omapdrm/dss/apply.c
diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c
index 54eeb507f9b3..54eeb507f9b3 100644
--- a/drivers/video/fbdev/omap2/dss/core.c
+++ b/drivers/gpu/drm/omapdrm/dss/core.c
diff --git a/drivers/video/fbdev/omap2/dss/dispc-compat.c b/drivers/gpu/drm/omapdrm/dss/dispc-compat.c
index 633c461fbc6e..0918b3bfe82a 100644
--- a/drivers/video/fbdev/omap2/dss/dispc-compat.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc-compat.c
@@ -476,7 +476,7 @@ static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
int r;
u32 irq;
- if (dispc_mgr_is_enabled(channel) == false)
+ if (!dispc_mgr_is_enabled(channel))
return;
/*
@@ -524,7 +524,7 @@ static void dispc_mgr_enable_digit_out(void)
int r;
u32 irq_mask;
- if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
+ if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
return;
/*
@@ -562,7 +562,7 @@ static void dispc_mgr_disable_digit_out(void)
u32 irq_mask;
int num_irqs;
- if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
+ if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
return;
/*
diff --git a/drivers/video/fbdev/omap2/dss/dispc-compat.h b/drivers/gpu/drm/omapdrm/dss/dispc-compat.h
index 14a69b3d4fb0..14a69b3d4fb0 100644
--- a/drivers/video/fbdev/omap2/dss/dispc-compat.h
+++ b/drivers/gpu/drm/omapdrm/dss/dispc-compat.h
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index be716c9ffb88..6b50476ec669 100644
--- a/drivers/video/fbdev/omap2/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -99,6 +99,11 @@ struct dispc_features {
/* PIXEL_INC is not added to the last pixel of a line */
bool last_pixel_inc_missing:1;
+
+ /* POL_FREQ has ALIGN bit */
+ bool supports_sync_align:1;
+
+ bool has_writeback:1;
};
#define DISPC_MAX_NR_FIFOS 5
@@ -246,6 +251,11 @@ struct color_conv_coef {
int full_range;
};
+static unsigned long dispc_fclk_rate(void);
+static unsigned long dispc_core_clk_rate(void);
+static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
+static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
+
static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
@@ -571,7 +581,7 @@ EXPORT_SYMBOL(dispc_mgr_go_busy);
void dispc_mgr_go(enum omap_channel channel)
{
- WARN_ON(dispc_mgr_is_enabled(channel) == false);
+ WARN_ON(!dispc_mgr_is_enabled(channel));
WARN_ON(dispc_mgr_go_busy(channel));
DSSDBG("GO %s\n", mgr_desc[channel].name);
@@ -707,19 +717,20 @@ static void dispc_setup_color_conv_coef(void)
{
int i;
int num_ovl = dss_feat_get_num_ovls();
- int num_wb = dss_feat_get_num_wbs();
const struct color_conv_coef ctbl_bt601_5_ovl = {
+ /* YUV -> RGB */
298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
};
const struct color_conv_coef ctbl_bt601_5_wb = {
- 66, 112, -38, 129, -94, -74, 25, -18, 112, 0,
+ /* RGB -> YUV */
+ 66, 129, 25, 112, -94, -18, -38, -74, 112, 0,
};
for (i = 1; i < num_ovl; i++)
dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
- for (; i < num_wb; i++)
- dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb);
+ if (dispc.feat->has_writeback)
+ dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb);
}
static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
@@ -970,6 +981,10 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
return;
}
break;
+ case OMAP_DSS_CHANNEL_WB:
+ chan = 0;
+ chan2 = 3;
+ break;
default:
BUG();
return;
@@ -988,7 +1003,6 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
{
int shift;
u32 val;
- enum omap_channel channel;
switch (plane) {
case OMAP_DSS_GFX:
@@ -1006,23 +1020,23 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
- if (dss_has_feature(FEAT_MGR_LCD3)) {
- if (FLD_GET(val, 31, 30) == 0)
- channel = FLD_GET(val, shift, shift);
- else if (FLD_GET(val, 31, 30) == 1)
- channel = OMAP_DSS_CHANNEL_LCD2;
- else
- channel = OMAP_DSS_CHANNEL_LCD3;
- } else if (dss_has_feature(FEAT_MGR_LCD2)) {
- if (FLD_GET(val, 31, 30) == 0)
- channel = FLD_GET(val, shift, shift);
- else
- channel = OMAP_DSS_CHANNEL_LCD2;
- } else {
- channel = FLD_GET(val, shift, shift);
- }
+ if (FLD_GET(val, shift, shift) == 1)
+ return OMAP_DSS_CHANNEL_DIGIT;
+
+ if (!dss_has_feature(FEAT_MGR_LCD2))
+ return OMAP_DSS_CHANNEL_LCD;
- return channel;
+ switch (FLD_GET(val, 31, 30)) {
+ case 0:
+ default:
+ return OMAP_DSS_CHANNEL_LCD;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD2;
+ case 2:
+ return OMAP_DSS_CHANNEL_LCD3;
+ case 3:
+ return OMAP_DSS_CHANNEL_WB;
+ }
}
void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
@@ -1050,6 +1064,8 @@ static void dispc_configure_burst_sizes(void)
/* Configure burst size always to maximum size */
for (i = 0; i < dss_feat_get_num_ovls(); ++i)
dispc_ovl_set_burst_size(i, burst_size);
+ if (dispc.feat->has_writeback)
+ dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size);
}
static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
@@ -1196,6 +1212,17 @@ static void dispc_init_fifos(void)
dispc_ovl_set_fifo_threshold(i, low, high);
}
+
+ if (dispc.feat->has_writeback) {
+ u32 low, high;
+ const bool use_fifomerge = false;
+ const bool manual_update = false;
+
+ dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high,
+ use_fifomerge, manual_update);
+
+ dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high);
+ }
}
static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
@@ -1248,7 +1275,6 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
plane != OMAP_DSS_WB)
dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
}
-EXPORT_SYMBOL(dispc_ovl_set_fifo_threshold);
void dispc_enable_fifomerge(bool enable)
{
@@ -1307,7 +1333,6 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
*fifo_high = total_fifo_size - buf_unit;
}
}
-EXPORT_SYMBOL(dispc_ovl_compute_fifo_thresholds);
static void dispc_ovl_set_mflag(enum omap_plane plane, bool enable)
{
@@ -1364,6 +1389,25 @@ static void dispc_init_mflag(void)
dispc_ovl_set_mflag_threshold(i, low, high);
}
+
+ if (dispc.feat->has_writeback) {
+ u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB);
+ u32 unit = dss_feat_get_buffer_size_unit();
+ u32 low, high;
+
+ dispc_ovl_set_mflag(OMAP_DSS_WB, true);
+
+ /*
+ * Simulation team suggests below thesholds:
+ * HT = fifosize * 5 / 8;
+ * LT = fifosize * 4 / 8;
+ */
+
+ low = size * 4 / 8 / unit;
+ high = size * 5 / 8 / unit;
+
+ dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high);
+ }
}
static void dispc_ovl_set_fir(enum omap_plane plane,
@@ -2438,7 +2482,7 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
if (width == out_width && height == out_height)
return 0;
- if (pclk == 0 || mgr_timings->pixelclock == 0) {
+ if (!mem_to_mem && (pclk == 0 || mgr_timings->pixelclock == 0)) {
DSSERR("cannot calculate scaling settings: pclk is zero\n");
return -EINVAL;
}
@@ -2816,8 +2860,25 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
+ if (mem_to_mem)
+ l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */
+ else
+ l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */
dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
+ if (mem_to_mem) {
+ /* WBDELAYCOUNT */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
+ } else {
+ int wbdelay;
+
+ wbdelay = min(mgr_timings->vfp + mgr_timings->vsw +
+ mgr_timings->vbp, 255);
+
+ /* WBDELAYCOUNT */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
+ }
+
return r;
}
@@ -2896,7 +2957,7 @@ static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
}
-void dispc_set_loadmode(enum omap_dss_load_mode mode)
+static void dispc_set_loadmode(enum omap_dss_load_mode mode)
{
REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
}
@@ -3163,6 +3224,10 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
FLD_VAL(hs, 13, 13) |
FLD_VAL(vs, 12, 12);
+ /* always set ALIGN bit when available */
+ if (dispc.feat->supports_sync_align)
+ l |= (1 << 18);
+
dispc_write_reg(DISPC_POL_FREQ(channel), l);
if (dispc.syscon_pol) {
@@ -3220,7 +3285,7 @@ void dispc_mgr_set_timings(enum omap_channel channel,
DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
} else {
- if (t.interlace == true)
+ if (t.interlace)
t.y_res /= 2;
}
@@ -3237,7 +3302,7 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
dispc_write_reg(DISPC_DIVISORo(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
- if (dss_has_feature(FEAT_CORE_CLK_DIV) == false &&
+ if (!dss_has_feature(FEAT_CORE_CLK_DIV) &&
channel == OMAP_DSS_CHANNEL_LCD)
dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
}
@@ -3251,7 +3316,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
*pck_div = FLD_GET(l, 7, 0);
}
-unsigned long dispc_fclk_rate(void)
+static unsigned long dispc_fclk_rate(void)
{
struct dss_pll *pll;
unsigned long r = 0;
@@ -3282,7 +3347,7 @@ unsigned long dispc_fclk_rate(void)
return r;
}
-unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
+static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
{
struct dss_pll *pll;
int lcd;
@@ -3323,7 +3388,7 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
}
}
-unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
+static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
{
unsigned long r;
@@ -3348,7 +3413,7 @@ void dispc_set_tv_pclk(unsigned long pclk)
dispc.tv_pclk_rate = pclk;
}
-unsigned long dispc_core_clk_rate(void)
+static unsigned long dispc_core_clk_rate(void)
{
return dispc.core_clk_rate;
}
@@ -3448,6 +3513,7 @@ static void dispc_dump_regs(struct seq_file *s)
[OMAP_DSS_VIDEO1] = "VID1",
[OMAP_DSS_VIDEO2] = "VID2",
[OMAP_DSS_VIDEO3] = "VID3",
+ [OMAP_DSS_WB] = "WB",
};
const char **p_names;
@@ -3554,6 +3620,35 @@ static void dispc_dump_regs(struct seq_file *s)
DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
}
+ if (dispc.feat->has_writeback) {
+ i = OMAP_DSS_WB;
+ DUMPREG(i, DISPC_OVL_BA0);
+ DUMPREG(i, DISPC_OVL_BA1);
+ DUMPREG(i, DISPC_OVL_SIZE);
+ DUMPREG(i, DISPC_OVL_ATTRIBUTES);
+ DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
+ DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
+ DUMPREG(i, DISPC_OVL_ROW_INC);
+ DUMPREG(i, DISPC_OVL_PIXEL_INC);
+
+ if (dss_has_feature(FEAT_MFLAG))
+ DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
+
+ DUMPREG(i, DISPC_OVL_FIR);
+ DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
+ DUMPREG(i, DISPC_OVL_ACCU0);
+ DUMPREG(i, DISPC_OVL_ACCU1);
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ DUMPREG(i, DISPC_OVL_BA0_UV);
+ DUMPREG(i, DISPC_OVL_BA1_UV);
+ DUMPREG(i, DISPC_OVL_FIR2);
+ DUMPREG(i, DISPC_OVL_ACCU2_0);
+ DUMPREG(i, DISPC_OVL_ACCU2_1);
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
+ }
+
#undef DISPC_REG
#undef DUMPREG
@@ -3854,6 +3949,8 @@ static const struct dispc_features omap44xx_dispc_feats = {
.num_fifos = 5,
.gfx_fifo_workaround = true,
.set_max_preload = true,
+ .supports_sync_align = true,
+ .has_writeback = true,
};
static const struct dispc_features omap54xx_dispc_feats = {
@@ -3875,6 +3972,8 @@ static const struct dispc_features omap54xx_dispc_feats = {
.gfx_fifo_workaround = true,
.mstandby_workaround = true,
.set_max_preload = true,
+ .supports_sync_align = true,
+ .has_writeback = true,
};
static int dispc_init_features(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/omap2/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h
index 3043d6e0a5f9..483744223dd1 100644
--- a/drivers/video/fbdev/omap2/dss/dispc.h
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.h
@@ -908,6 +908,8 @@ static inline u16 DISPC_MFLAG_THRESHOLD_OFFSET(enum omap_plane plane)
return 0x0868;
case OMAP_DSS_VIDEO3:
return 0x086c;
+ case OMAP_DSS_WB:
+ return 0x0870;
default:
BUG();
return 0;
diff --git a/drivers/video/fbdev/omap2/dss/dispc_coefs.c b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
index 038c15b04215..038c15b04215 100644
--- a/drivers/video/fbdev/omap2/dss/dispc_coefs.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c b/drivers/gpu/drm/omapdrm/dss/display-sysfs.c
index 6ad0991f8259..6ad0991f8259 100644
--- a/drivers/video/fbdev/omap2/dss/display-sysfs.c
+++ b/drivers/gpu/drm/omapdrm/dss/display-sysfs.c
diff --git a/drivers/video/fbdev/omap2/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c
index ef5b9027985d..ef5b9027985d 100644
--- a/drivers/video/fbdev/omap2/dss/display.c
+++ b/drivers/gpu/drm/omapdrm/dss/display.c
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
index fb45b6432968..7953e6a52346 100644
--- a/drivers/video/fbdev/omap2/dss/dpi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -395,7 +395,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
goto err_no_reg;
}
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err_no_out_mgr;
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index b3606def5b7b..43be4b2a7b05 100644
--- a/drivers/video/fbdev/omap2/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -144,7 +144,7 @@ struct dsi_reg { u16 module; u16 idx; };
#define DSI_IRQ_TA_TIMEOUT (1 << 20)
#define DSI_IRQ_ERROR_MASK \
(DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
- DSI_IRQ_TA_TIMEOUT | DSI_IRQ_SYNC_LOST)
+ DSI_IRQ_TA_TIMEOUT)
#define DSI_IRQ_CHANNEL_MASK 0xf
/* Virtual channel interrupts */
@@ -3833,7 +3833,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
u16 word_count;
int r;
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c
index bf407b6ba15c..bf407b6ba15c 100644
--- a/drivers/video/fbdev/omap2/dss/dss-of.c
+++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c
index 9200a8668b49..f95ff319e68e 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/gpu/drm/omapdrm/dss/dss.c
@@ -1264,12 +1264,18 @@ static int dss_runtime_suspend(struct device *dev)
{
dss_save_context();
dss_set_min_bus_tput(dev, 0);
+
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
static int dss_runtime_resume(struct device *dev)
{
int r;
+
+ pinctrl_pm_select_default_state(dev);
+
/*
* Set an arbitrarily high tput request to ensure OPP100.
* What we should really do is to make a request to stay in OPP100,
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h
index 2406bcdb831a..9a6453235585 100644
--- a/drivers/video/fbdev/omap2/dss/dss.h
+++ b/drivers/gpu/drm/omapdrm/dss/dss.h
@@ -343,7 +343,8 @@ u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
#else
static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
{
- WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
+ WARN(1, "%s: DSI not compiled in, returning pixel_size as 0\n",
+ __func__);
return 0;
}
#endif
@@ -378,7 +379,6 @@ void dispc_lcd_enable_signal(bool enable);
void dispc_pck_free_enable(bool enable);
void dispc_enable_fifomerge(bool enable);
void dispc_enable_gamma_table(bool enable);
-void dispc_set_loadmode(enum omap_dss_load_mode mode);
typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
unsigned long pck, void *data);
@@ -388,7 +388,6 @@ bool dispc_div_calc(unsigned long dispc,
bool dispc_mgr_timings_ok(enum omap_channel channel,
const struct omap_video_timings *timings);
-unsigned long dispc_fclk_rate(void);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);
@@ -398,9 +397,6 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
bool manual_update);
-unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
-unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
-unsigned long dispc_core_clk_rate(void);
void dispc_mgr_set_clock_div(enum omap_channel channel,
const struct dispc_clock_info *cinfo);
int dispc_mgr_get_clock_div(enum omap_channel channel,
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/gpu/drm/omapdrm/dss/dss_features.c
index b0b6dfd657bf..c886a2927f73 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.c
+++ b/drivers/gpu/drm/omapdrm/dss/dss_features.c
@@ -46,7 +46,6 @@ struct omap_dss_features {
const int num_mgrs;
const int num_ovls;
- const int num_wbs;
const enum omap_display_type *supported_displays;
const enum omap_dss_output_id *supported_outputs;
const enum omap_color_mode *supported_color_modes;
@@ -735,7 +734,6 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
- .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
.supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
@@ -757,7 +755,6 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
- .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
.supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
@@ -779,7 +776,6 @@ static const struct omap_dss_features omap4_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
- .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
.supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
@@ -825,11 +821,6 @@ int dss_feat_get_num_ovls(void)
}
EXPORT_SYMBOL(dss_feat_get_num_ovls);
-int dss_feat_get_num_wbs(void)
-{
- return omap_current_dss_features->num_wbs;
-}
-
unsigned long dss_feat_get_param_min(enum dss_range_param param)
{
return omap_current_dss_features->dss_params[param].min;
@@ -844,13 +835,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
{
return omap_current_dss_features->supported_displays[channel];
}
-EXPORT_SYMBOL(dss_feat_get_supported_displays);
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
{
return omap_current_dss_features->supported_outputs[channel];
}
-EXPORT_SYMBOL(dss_feat_get_supported_outputs);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
{
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.h b/drivers/gpu/drm/omapdrm/dss/dss_features.h
index 100f7a2d0638..3d67d39f192f 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.h
+++ b/drivers/gpu/drm/omapdrm/dss/dss_features.h
@@ -86,7 +86,6 @@ enum dss_range_param {
};
/* DSS Feature Functions */
-int dss_feat_get_num_wbs(void);
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
@@ -102,4 +101,8 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
bool dss_has_feature(enum dss_feat_id id);
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
void dss_features_init(enum omapdss_version version);
+
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
+
#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h
index 53616b02b613..53616b02b613 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 94c8d5549b4c..7103c659a534 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -343,7 +343,7 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
index fa72e735dad2..fa72e735dad2 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
index a069f96ec6f6..a069f96ec6f6 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index b59ba7902be1..a955a2c4c061 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -373,7 +373,7 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
index 8ea531d2652c..8ea531d2652c 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
index f2f1022c5516..f2f1022c5516 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5_core.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/gpu/drm/omapdrm/dss/hdmi_common.c
index 1b8fcc6c4ba1..1b8fcc6c4ba1 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_common.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_common.c
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
index 1f5d19c119ce..1f5d19c119ce 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
index 06e23a7c432c..06e23a7c432c 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
index 7c544bc56fb5..7c544bc56fb5 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
diff --git a/drivers/video/fbdev/omap2/dss/manager-sysfs.c b/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c
index a7414fb12830..a7414fb12830 100644
--- a/drivers/video/fbdev/omap2/dss/manager-sysfs.c
+++ b/drivers/gpu/drm/omapdrm/dss/manager-sysfs.c
diff --git a/drivers/video/fbdev/omap2/dss/manager.c b/drivers/gpu/drm/omapdrm/dss/manager.c
index 1aac9b4191a9..08a67f4f6a20 100644
--- a/drivers/video/fbdev/omap2/dss/manager.c
+++ b/drivers/gpu/drm/omapdrm/dss/manager.c
@@ -210,7 +210,7 @@ static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
return -EINVAL;
/* fifohandcheck should be used only with stallmode */
- if (stallmode == false && fifohandcheck == true)
+ if (!stallmode && fifohandcheck)
return -EINVAL;
/*
diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
index 8b6f6d5fdd68..136d30484d02 100644
--- a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -199,10 +199,8 @@ static int __init omapdss_boot_init(void)
omapdss_walk_device(dss, true);
for_each_available_child_of_node(dss, child) {
- if (!of_find_property(child, "compatible", NULL)) {
- of_node_put(child);
+ if (!of_find_property(child, "compatible", NULL))
continue;
- }
omapdss_walk_device(child, true);
}
diff --git a/drivers/video/fbdev/omap2/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
index 16072159bd24..16072159bd24 100644
--- a/drivers/video/fbdev/omap2/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
diff --git a/drivers/video/fbdev/omap2/dss/overlay-sysfs.c b/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c
index 4cc5ddebfb34..4cc5ddebfb34 100644
--- a/drivers/video/fbdev/omap2/dss/overlay-sysfs.c
+++ b/drivers/gpu/drm/omapdrm/dss/overlay-sysfs.c
diff --git a/drivers/video/fbdev/omap2/dss/overlay.c b/drivers/gpu/drm/omapdrm/dss/overlay.c
index 2f7cee985cdd..2f7cee985cdd 100644
--- a/drivers/video/fbdev/omap2/dss/overlay.c
+++ b/drivers/gpu/drm/omapdrm/dss/overlay.c
diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c
index f974ddcd3b6e..f974ddcd3b6e 100644
--- a/drivers/video/fbdev/omap2/dss/pll.c
+++ b/drivers/gpu/drm/omapdrm/dss/pll.c
diff --git a/drivers/video/fbdev/omap2/dss/rfbi.c b/drivers/gpu/drm/omapdrm/dss/rfbi.c
index 1525a494d057..aea6a1d0fb20 100644
--- a/drivers/video/fbdev/omap2/dss/rfbi.c
+++ b/drivers/gpu/drm/omapdrm/dss/rfbi.c
@@ -880,7 +880,7 @@ static int rfbi_display_enable(struct omap_dss_device *dssdev)
struct omap_dss_device *out = &rfbi.output;
int r;
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c
index 5843580a1deb..d747cc6b59e1 100644
--- a/drivers/video/fbdev/omap2/dss/sdi.c
+++ b/drivers/gpu/drm/omapdrm/dss/sdi.c
@@ -136,7 +136,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
unsigned long pck;
int r;
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
diff --git a/drivers/video/fbdev/omap2/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index d05a54922ba6..08f9def76e27 100644
--- a/drivers/video/fbdev/omap2/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -515,7 +515,7 @@ static int venc_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&venc.venc_lock);
- if (out == NULL || out->manager == NULL) {
+ if (out->manager == NULL) {
DSSERR("Failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
diff --git a/drivers/video/fbdev/omap2/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c
index b1ec59e42940..b1ec59e42940 100644
--- a/drivers/video/fbdev/omap2/dss/video-pll.c
+++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index ad09590e8a46..2ed0754ed19e 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -524,7 +524,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
- &omap_crtc_funcs);
+ &omap_crtc_funcs, NULL);
if (ret < 0) {
kfree(omap_crtc);
return NULL;
diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c
index ee91a25127f9..6f5fc14fc015 100644
--- a/drivers/gpu/drm/omapdrm/omap_debugfs.c
+++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c
@@ -51,6 +51,7 @@ static int mm_show(struct seq_file *m, void *arg)
return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
}
+#ifdef CONFIG_DRM_FBDEV_EMULATION
static int fb_show(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -73,12 +74,15 @@ static int fb_show(struct seq_file *m, void *arg)
return 0;
}
+#endif
/* list of debufs files that are applicable to all devices */
static struct drm_info_list omap_debugfs_list[] = {
{"gem", gem_show, 0},
{"mm", mm_show, 0},
+#ifdef CONFIG_DRM_FBDEV_EMULATION
{"fb", fb_show, 0},
+#endif
};
/* list of debugfs files that are specific to devices with dmm/tiler */
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index 7841970de48d..dfebdc4aa0f2 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -363,6 +363,7 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
u32 min_align = 128;
int ret;
unsigned long flags;
+ size_t slot_bytes;
BUG_ON(!validfmt(fmt));
@@ -371,13 +372,15 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
h = DIV_ROUND_UP(h, geom[fmt].slot_h);
/* convert alignment to slots */
- min_align = max(min_align, (geom[fmt].slot_w * geom[fmt].cpp));
- align = ALIGN(align, min_align);
- align /= geom[fmt].slot_w * geom[fmt].cpp;
+ slot_bytes = geom[fmt].slot_w * geom[fmt].cpp;
+ min_align = max(min_align, slot_bytes);
+ align = (align > min_align) ? ALIGN(align, min_align) : min_align;
+ align /= slot_bytes;
block->fmt = fmt;
- ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area);
+ ret = tcm_reserve_2d(containers[fmt], w, h, align, -1, slot_bytes,
+ &block->area);
if (ret) {
kfree(block);
return ERR_PTR(-ENOMEM);
@@ -739,8 +742,7 @@ static int omap_dmm_probe(struct platform_device *dev)
programming during reill operations */
for (i = 0; i < omap_dmm->num_lut; i++) {
omap_dmm->tcm[i] = sita_init(omap_dmm->container_width,
- omap_dmm->container_height,
- NULL);
+ omap_dmm->container_height);
if (!omap_dmm->tcm[i]) {
dev_err(&dev->dev, "failed to allocate container\n");
@@ -1030,4 +1032,3 @@ struct platform_driver omap_dmm_driver = {
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Andy Gross <andy.gross@ti.com>");
MODULE_DESCRIPTION("OMAP DMM/Tiler Driver");
-MODULE_ALIAS("platform:" DMM_DRIVER_NAME);
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 5c6609cbb6a2..dfafdb602ad2 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -547,14 +547,19 @@ static int ioctl_set_param(struct drm_device *dev, void *data,
return 0;
}
+#define OMAP_BO_USER_MASK 0x00ffffff /* flags settable by userspace */
+
static int ioctl_gem_new(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_omap_gem_new *args = data;
+ u32 flags = args->flags & OMAP_BO_USER_MASK;
+
VERB("%p:%p: size=0x%08x, flags=%08x", dev, file_priv,
- args->size.bytes, args->flags);
- return omap_gem_new_handle(dev, file_priv, args->size,
- args->flags, &args->handle);
+ args->size.bytes, flags);
+
+ return omap_gem_new_handle(dev, file_priv, args->size, flags,
+ &args->handle);
}
static int ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
@@ -692,10 +697,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
drm_crtc_vblank_off(priv->crtcs[i]);
priv->fbdev = omap_fbdev_init(dev);
- if (!priv->fbdev) {
- dev_warn(dev->dev, "omap_fbdev_init failed\n");
- /* well, limp along without an fbdev.. maybe X11 will work? */
- }
/* store off drm_device for use in pm ops */
dev_set_drvdata(dev->dev, dev);
@@ -831,7 +832,8 @@ static const struct file_operations omapdriver_fops = {
};
static struct drm_driver omap_drm_driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
+ DRIVER_ATOMIC,
.load = dev_load,
.unload = dev_unload,
.open = dev_open,
@@ -928,35 +930,23 @@ static struct platform_driver pdev = {
.remove = pdev_remove,
};
+static struct platform_driver * const drivers[] = {
+ &omap_dmm_driver,
+ &pdev,
+};
+
static int __init omap_drm_init(void)
{
- int r;
-
DBG("init");
- r = platform_driver_register(&omap_dmm_driver);
- if (r) {
- pr_err("DMM driver registration failed\n");
- return r;
- }
-
- r = platform_driver_register(&pdev);
- if (r) {
- pr_err("omapdrm driver registration failed\n");
- platform_driver_unregister(&omap_dmm_driver);
- return r;
- }
-
- return 0;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit omap_drm_fini(void)
{
DBG("fini");
- platform_driver_unregister(&pdev);
-
- platform_driver_unregister(&omap_dmm_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
/* need late_initcall() so we load after dss_driver's are loaded */
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 5c367aad8a6e..9e0030731c37 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -36,11 +36,7 @@
#define MODULE_NAME "omapdrm"
-/* max # of mapper-id's that can be assigned.. todo, come up with a better
- * (but still inexpensive) way to store/access per-buffer mapper private
- * data..
- */
-#define MAX_MAPPERS 2
+struct omap_drm_usergart;
/* parameters which describe (unrotated) coordinates of scanout within a fb: */
struct omap_drm_window {
@@ -97,6 +93,7 @@ struct omap_drm_private {
/* list of GEM objects: */
struct list_head obj_list;
+ struct omap_drm_usergart *usergart;
bool has_dmm;
/* properties: */
@@ -138,8 +135,18 @@ void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
void omap_drm_irq_uninstall(struct drm_device *dev);
int omap_drm_irq_install(struct drm_device *dev);
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev);
void omap_fbdev_free(struct drm_device *dev);
+#else
+static inline struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
+{
+ return NULL;
+}
+static inline void omap_fbdev_free(struct drm_device *dev)
+{
+}
+#endif
struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
@@ -172,9 +179,9 @@ void copy_timings_drm_to_omap(struct omap_video_timings *timings,
uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats,
uint32_t max_formats, enum omap_color_mode supported_modes);
struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
- struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
+ struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
+ const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
int omap_framebuffer_pin(struct drm_framebuffer *fb);
void omap_framebuffer_unpin(struct drm_framebuffer *fb);
@@ -248,7 +255,7 @@ struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);
static inline int objects_lookup(struct drm_device *dev,
struct drm_file *filp, uint32_t pixel_format,
- struct drm_gem_object **bos, uint32_t *handles)
+ struct drm_gem_object **bos, const uint32_t *handles)
{
int i, n = drm_format_num_planes(pixel_format);
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index 7d9b32a0eb43..61714e9670ae 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -110,8 +110,6 @@ static int omap_encoder_update(struct drm_encoder *encoder,
struct omap_dss_driver *dssdrv = dssdev->driver;
int ret;
- dssdev->src->manager = omap_dss_get_overlay_manager(channel);
-
if (dssdrv->check_timings) {
ret = dssdrv->check_timings(dssdev, timings);
} else {
@@ -178,7 +176,7 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev,
encoder = &omap_encoder->base;
drm_encoder_init(dev, encoder, &omap_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
return encoder;
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 636a1f921569..ad202dfc1a49 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -364,7 +364,7 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
#endif
struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
- struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
+ struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *bos[4];
struct drm_framebuffer *fb;
@@ -386,7 +386,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
}
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
+ const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
{
struct omap_framebuffer *omap_fb = NULL;
struct drm_framebuffer *fb = NULL;
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 24f92bea39c7..3cb16f0cf381 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -295,6 +295,10 @@ fini:
drm_fb_helper_fini(helper);
fail:
kfree(fbdev);
+
+ dev_warn(dev->dev, "omap_fbdev_init failed\n");
+ /* well, limp along without an fbdev.. maybe X11 will work? */
+
return NULL;
}
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index 7ed08fdc4c42..8495a1a4b617 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -19,30 +19,22 @@
#include <linux/shmem_fs.h>
#include <linux/spinlock.h>
+#include <linux/pfn_t.h>
#include <drm/drm_vma_manager.h>
#include "omap_drv.h"
#include "omap_dmm_tiler.h"
-/* remove these once drm core helpers are merged */
-struct page **_drm_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-void _drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
- bool dirty, bool accessed);
-int _drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size);
-
/*
* GEM buffer object implementation.
*/
-#define to_omap_bo(x) container_of(x, struct omap_gem_object, base)
-
/* note: we use upper 8 bits of flags for driver-internal flags: */
-#define OMAP_BO_DMA 0x01000000 /* actually is physically contiguous */
+#define OMAP_BO_DMA 0x01000000 /* actually is physically contiguous */
#define OMAP_BO_EXT_SYNC 0x02000000 /* externally allocated sync object */
#define OMAP_BO_EXT_MEM 0x04000000 /* externally allocated memory */
-
struct omap_gem_object {
struct drm_gem_object base;
@@ -119,8 +111,7 @@ struct omap_gem_object {
} *sync;
};
-static int get_pages(struct drm_gem_object *obj, struct page ***pages);
-static uint64_t mmap_offset(struct drm_gem_object *obj);
+#define to_omap_bo(x) container_of(x, struct omap_gem_object, base)
/* To deal with userspace mmap'ings of 2d tiled buffers, which (a) are
* not necessarily pinned in TILER all the time, and (b) when they are
@@ -134,27 +125,69 @@ static uint64_t mmap_offset(struct drm_gem_object *obj);
* for later..
*/
#define NUM_USERGART_ENTRIES 2
-struct usergart_entry {
+struct omap_drm_usergart_entry {
struct tiler_block *block; /* the reserved tiler block */
dma_addr_t paddr;
struct drm_gem_object *obj; /* the current pinned obj */
pgoff_t obj_pgoff; /* page offset of obj currently
mapped in */
};
-static struct {
- struct usergart_entry entry[NUM_USERGART_ENTRIES];
+
+struct omap_drm_usergart {
+ struct omap_drm_usergart_entry entry[NUM_USERGART_ENTRIES];
int height; /* height in rows */
int height_shift; /* ilog2(height in rows) */
int slot_shift; /* ilog2(width per slot) */
int stride_pfn; /* stride in pages */
int last; /* index of last used entry */
-} *usergart;
+};
+
+/* -----------------------------------------------------------------------------
+ * Helpers
+ */
+
+/** get mmap offset */
+static uint64_t mmap_offset(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ int ret;
+ size_t size;
+
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+ /* Make it mmapable */
+ size = omap_gem_mmap_size(obj);
+ ret = drm_gem_create_mmap_offset_size(obj, size);
+ if (ret) {
+ dev_err(dev->dev, "could not allocate mmap offset\n");
+ return 0;
+ }
+
+ return drm_vma_node_offset_addr(&obj->vma_node);
+}
+
+/* GEM objects can either be allocated from contiguous memory (in which
+ * case obj->filp==NULL), or w/ shmem backing (obj->filp!=NULL). But non
+ * contiguous buffers can be remapped in TILER/DMM if they need to be
+ * contiguous... but we don't do this all the time to reduce pressure
+ * on TILER/DMM space when we know at allocation time that the buffer
+ * will need to be scanned out.
+ */
+static inline bool is_shmem(struct drm_gem_object *obj)
+{
+ return obj->filp != NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * Eviction
+ */
static void evict_entry(struct drm_gem_object *obj,
- enum tiler_fmt fmt, struct usergart_entry *entry)
+ enum tiler_fmt fmt, struct omap_drm_usergart_entry *entry)
{
struct omap_gem_object *omap_obj = to_omap_bo(obj);
- int n = usergart[fmt].height;
+ struct omap_drm_private *priv = obj->dev->dev_private;
+ int n = priv->usergart[fmt].height;
size_t size = PAGE_SIZE * n;
loff_t off = mmap_offset(obj) +
(entry->obj_pgoff << PAGE_SHIFT);
@@ -180,46 +213,25 @@ static void evict_entry(struct drm_gem_object *obj,
static void evict(struct drm_gem_object *obj)
{
struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ struct omap_drm_private *priv = obj->dev->dev_private;
if (omap_obj->flags & OMAP_BO_TILED) {
enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
int i;
- if (!usergart)
- return;
-
for (i = 0; i < NUM_USERGART_ENTRIES; i++) {
- struct usergart_entry *entry = &usergart[fmt].entry[i];
+ struct omap_drm_usergart_entry *entry =
+ &priv->usergart[fmt].entry[i];
+
if (entry->obj == obj)
evict_entry(obj, fmt, entry);
}
}
}
-/* GEM objects can either be allocated from contiguous memory (in which
- * case obj->filp==NULL), or w/ shmem backing (obj->filp!=NULL). But non
- * contiguous buffers can be remapped in TILER/DMM if they need to be
- * contiguous... but we don't do this all the time to reduce pressure
- * on TILER/DMM space when we know at allocation time that the buffer
- * will need to be scanned out.
- */
-static inline bool is_shmem(struct drm_gem_object *obj)
-{
- return obj->filp != NULL;
-}
-
-/**
- * shmem buffers that are mapped cached can simulate coherency via using
- * page faulting to keep track of dirty pages
+/* -----------------------------------------------------------------------------
+ * Page Management
*/
-static inline bool is_cached_coherent(struct drm_gem_object *obj)
-{
- struct omap_gem_object *omap_obj = to_omap_bo(obj);
- return is_shmem(obj) &&
- ((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED);
-}
-
-static DEFINE_SPINLOCK(sync_lock);
/** ensure backing pages are allocated */
static int omap_gem_attach_pages(struct drm_gem_object *obj)
@@ -272,6 +284,28 @@ free_pages:
return ret;
}
+/* acquire pages when needed (for example, for DMA where physically
+ * contiguous buffer is not required
+ */
+static int get_pages(struct drm_gem_object *obj, struct page ***pages)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ int ret = 0;
+
+ if (is_shmem(obj) && !omap_obj->pages) {
+ ret = omap_gem_attach_pages(obj);
+ if (ret) {
+ dev_err(obj->dev->dev, "could not attach pages\n");
+ return ret;
+ }
+ }
+
+ /* TODO: even phys-contig.. we should have a list of pages? */
+ *pages = omap_obj->pages;
+
+ return 0;
+}
+
/** release backing pages */
static void omap_gem_detach_pages(struct drm_gem_object *obj)
{
@@ -301,26 +335,6 @@ uint32_t omap_gem_flags(struct drm_gem_object *obj)
return to_omap_bo(obj)->flags;
}
-/** get mmap offset */
-static uint64_t mmap_offset(struct drm_gem_object *obj)
-{
- struct drm_device *dev = obj->dev;
- int ret;
- size_t size;
-
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
- /* Make it mmapable */
- size = omap_gem_mmap_size(obj);
- ret = drm_gem_create_mmap_offset_size(obj, size);
- if (ret) {
- dev_err(dev->dev, "could not allocate mmap offset\n");
- return 0;
- }
-
- return drm_vma_node_offset_addr(&obj->vma_node);
-}
-
uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj)
{
uint64_t offset;
@@ -362,6 +376,10 @@ int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h)
return -EINVAL;
}
+/* -----------------------------------------------------------------------------
+ * Fault Handling
+ */
+
/* Normal handling for the case of faulting in non-tiled buffers */
static int fault_1d(struct drm_gem_object *obj,
struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -385,7 +403,8 @@ static int fault_1d(struct drm_gem_object *obj,
VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
pfn, pfn << PAGE_SHIFT);
- return vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
+ return vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
+ __pfn_to_pfn_t(pfn, PFN_DEV));
}
/* Special handling for the case of faulting in 2d tiled buffers */
@@ -393,7 +412,8 @@ static int fault_2d(struct drm_gem_object *obj,
struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct omap_gem_object *omap_obj = to_omap_bo(obj);
- struct usergart_entry *entry;
+ struct omap_drm_private *priv = obj->dev->dev_private;
+ struct omap_drm_usergart_entry *entry;
enum tiler_fmt fmt = gem2fmt(omap_obj->flags);
struct page *pages[64]; /* XXX is this too much to have on stack? */
unsigned long pfn;
@@ -406,8 +426,8 @@ static int fault_2d(struct drm_gem_object *obj,
* that need to be mapped in to fill 4kb wide CPU page. If the slot
* height is 64, then 64 pages fill a 4kb wide by 64 row region.
*/
- const int n = usergart[fmt].height;
- const int n_shift = usergart[fmt].height_shift;
+ const int n = priv->usergart[fmt].height;
+ const int n_shift = priv->usergart[fmt].height_shift;
/*
* If buffer width in bytes > PAGE_SIZE then the virtual stride is
@@ -428,11 +448,11 @@ static int fault_2d(struct drm_gem_object *obj,
base_pgoff = round_down(pgoff, m << n_shift);
/* figure out buffer width in slots */
- slots = omap_obj->width >> usergart[fmt].slot_shift;
+ slots = omap_obj->width >> priv->usergart[fmt].slot_shift;
vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT);
- entry = &usergart[fmt].entry[usergart[fmt].last];
+ entry = &priv->usergart[fmt].entry[priv->usergart[fmt].last];
/* evict previous buffer using this usergart entry, if any: */
if (entry->obj)
@@ -478,13 +498,15 @@ static int fault_2d(struct drm_gem_object *obj,
pfn, pfn << PAGE_SHIFT);
for (i = n; i > 0; i--) {
- vm_insert_mixed(vma, (unsigned long)vaddr, pfn);
- pfn += usergart[fmt].stride_pfn;
+ vm_insert_mixed(vma, (unsigned long)vaddr,
+ __pfn_to_pfn_t(pfn, PFN_DEV));
+ pfn += priv->usergart[fmt].stride_pfn;
vaddr += PAGE_SIZE * m;
}
/* simple round-robin: */
- usergart[fmt].last = (usergart[fmt].last + 1) % NUM_USERGART_ENTRIES;
+ priv->usergart[fmt].last = (priv->usergart[fmt].last + 1)
+ % NUM_USERGART_ENTRIES;
return 0;
}
@@ -596,6 +618,9 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj,
return 0;
}
+/* -----------------------------------------------------------------------------
+ * Dumb Buffers
+ */
/**
* omap_gem_dumb_create - create a dumb buffer
@@ -653,6 +678,7 @@ fail:
return ret;
}
+#ifdef CONFIG_DRM_FBDEV_EMULATION
/* Set scrolling position. This allows us to implement fast scrolling
* for console.
*
@@ -689,6 +715,22 @@ fail:
return ret;
}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Memory Management & DMA Sync
+ */
+
+/**
+ * shmem buffers that are mapped cached can simulate coherency via using
+ * page faulting to keep track of dirty pages
+ */
+static inline bool is_cached_coherent(struct drm_gem_object *obj)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ return is_shmem(obj) &&
+ ((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED);
+}
/* Sync the buffer for CPU access.. note pages should already be
* attached, ie. omap_gem_get_pages()
@@ -865,28 +907,6 @@ int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient)
return ret;
}
-/* acquire pages when needed (for example, for DMA where physically
- * contiguous buffer is not required
- */
-static int get_pages(struct drm_gem_object *obj, struct page ***pages)
-{
- struct omap_gem_object *omap_obj = to_omap_bo(obj);
- int ret = 0;
-
- if (is_shmem(obj) && !omap_obj->pages) {
- ret = omap_gem_attach_pages(obj);
- if (ret) {
- dev_err(obj->dev->dev, "could not attach pages\n");
- return ret;
- }
- }
-
- /* TODO: even phys-contig.. we should have a list of pages? */
- *pages = omap_obj->pages;
-
- return 0;
-}
-
/* if !remap, and we don't have pages backing, then fail, rather than
* increasing the pin count (which we don't really do yet anyways,
* because we don't support swapping pages back out). And 'remap'
@@ -924,6 +944,7 @@ int omap_gem_put_pages(struct drm_gem_object *obj)
return 0;
}
+#ifdef CONFIG_DRM_FBDEV_EMULATION
/* Get kernel virtual address for CPU access.. this more or less only
* exists for omap_fbdev. This should be called with struct_mutex
* held.
@@ -942,6 +963,11 @@ void *omap_gem_vaddr(struct drm_gem_object *obj)
}
return omap_obj->vaddr;
}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
#ifdef CONFIG_PM
/* re-pin objects in DMM in resume path: */
@@ -971,6 +997,10 @@ int omap_gem_resume(struct device *dev)
}
#endif
+/* -----------------------------------------------------------------------------
+ * DebugFS
+ */
+
#ifdef CONFIG_DEBUG_FS
void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
{
@@ -1017,9 +1047,12 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m)
}
#endif
-/* Buffer Synchronization:
+/* -----------------------------------------------------------------------------
+ * Buffer Synchronization
*/
+static DEFINE_SPINLOCK(sync_lock);
+
struct omap_gem_sync_waiter {
struct list_head list;
struct omap_gem_object *omap_obj;
@@ -1265,6 +1298,10 @@ unlock:
return ret;
}
+/* -----------------------------------------------------------------------------
+ * Constructor & Destructor
+ */
+
/* don't call directly.. called from GEM core when it is time to actually
* free the object..
*/
@@ -1282,8 +1319,6 @@ void omap_gem_free_object(struct drm_gem_object *obj)
list_del(&omap_obj->mm_list);
spin_unlock(&priv->list_lock);
- drm_gem_free_mmap_offset(obj);
-
/* this means the object is still pinned.. which really should
* not happen. I think..
*/
@@ -1308,31 +1343,7 @@ void omap_gem_free_object(struct drm_gem_object *obj)
drm_gem_object_release(obj);
- kfree(obj);
-}
-
-/* convenience method to construct a GEM buffer object, and userspace handle */
-int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
- union omap_gem_size gsize, uint32_t flags, uint32_t *handle)
-{
- struct drm_gem_object *obj;
- int ret;
-
- obj = omap_gem_new(dev, gsize, flags);
- if (!obj)
- return -ENOMEM;
-
- ret = drm_gem_handle_create(file, obj, handle);
- if (ret) {
- drm_gem_object_release(obj);
- kfree(obj); /* TODO isn't there a dtor to call? just copying i915 */
- return ret;
- }
-
- /* drop reference from allocate - handle holds it now */
- drm_gem_object_unreference_unlocked(obj);
-
- return 0;
+ kfree(omap_obj);
}
/* GEM buffer object constructor */
@@ -1341,15 +1352,15 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
{
struct omap_drm_private *priv = dev->dev_private;
struct omap_gem_object *omap_obj;
- struct drm_gem_object *obj = NULL;
+ struct drm_gem_object *obj;
struct address_space *mapping;
size_t size;
int ret;
if (flags & OMAP_BO_TILED) {
- if (!usergart) {
+ if (!priv->usergart) {
dev_err(dev->dev, "Tiled buffers require DMM\n");
- goto fail;
+ return NULL;
}
/* tiled buffers are always shmem paged backed.. when they are
@@ -1420,16 +1431,42 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
return obj;
fail:
- if (obj)
+ omap_gem_free_object(obj);
+ return NULL;
+}
+
+/* convenience method to construct a GEM buffer object, and userspace handle */
+int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
+ union omap_gem_size gsize, uint32_t flags, uint32_t *handle)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ obj = omap_gem_new(dev, gsize, flags);
+ if (!obj)
+ return -ENOMEM;
+
+ ret = drm_gem_handle_create(file, obj, handle);
+ if (ret) {
omap_gem_free_object(obj);
+ return ret;
+ }
- return NULL;
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(obj);
+
+ return 0;
}
-/* init/cleanup.. if DMM is used, we need to set some stuff up.. */
+/* -----------------------------------------------------------------------------
+ * Init & Cleanup
+ */
+
+/* If DMM is used, we need to set some stuff up.. */
void omap_gem_init(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
+ struct omap_drm_usergart *usergart;
const enum tiler_fmt fmts[] = {
TILFMT_8BIT, TILFMT_16BIT, TILFMT_32BIT
};
@@ -1458,10 +1495,11 @@ void omap_gem_init(struct drm_device *dev)
usergart[i].stride_pfn = tiler_stride(fmts[i], 0) >> PAGE_SHIFT;
usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i);
for (j = 0; j < NUM_USERGART_ENTRIES; j++) {
- struct usergart_entry *entry = &usergart[i].entry[j];
- struct tiler_block *block =
- tiler_reserve_2d(fmts[i], w, h,
- PAGE_SIZE);
+ struct omap_drm_usergart_entry *entry;
+ struct tiler_block *block;
+
+ entry = &usergart[i].entry[j];
+ block = tiler_reserve_2d(fmts[i], w, h, PAGE_SIZE);
if (IS_ERR(block)) {
dev_err(dev->dev,
"reserve failed: %d, %d, %ld\n",
@@ -1477,13 +1515,16 @@ void omap_gem_init(struct drm_device *dev)
}
}
+ priv->usergart = usergart;
priv->has_dmm = true;
}
void omap_gem_deinit(struct drm_device *dev)
{
+ struct omap_drm_private *priv = dev->dev_private;
+
/* I believe we can rely on there being no more outstanding GEM
* objects which could depend on usergart/dmm at this point.
*/
- kfree(usergart);
+ kfree(priv->usergart);
}
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 3054bda72688..d75b197eff46 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -188,33 +188,6 @@ static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
.atomic_disable = omap_plane_atomic_disable,
};
-static void omap_plane_reset(struct drm_plane *plane)
-{
- struct omap_plane *omap_plane = to_omap_plane(plane);
- struct omap_plane_state *omap_state;
-
- if (plane->state && plane->state->fb)
- drm_framebuffer_unreference(plane->state->fb);
-
- kfree(plane->state);
- plane->state = NULL;
-
- omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
- if (omap_state == NULL)
- return;
-
- /*
- * Set defaults depending on whether we are a primary or overlay
- * plane.
- */
- omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
- ? 0 : omap_plane->id;
- omap_state->base.rotation = BIT(DRM_ROTATE_0);
-
- plane->state = &omap_state->base;
- plane->state->plane = plane;
-}
-
static void omap_plane_destroy(struct drm_plane *plane)
{
struct omap_plane *omap_plane = to_omap_plane(plane);
@@ -270,6 +243,32 @@ static void omap_plane_atomic_destroy_state(struct drm_plane *plane,
kfree(to_omap_plane_state(state));
}
+static void omap_plane_reset(struct drm_plane *plane)
+{
+ struct omap_plane *omap_plane = to_omap_plane(plane);
+ struct omap_plane_state *omap_state;
+
+ if (plane->state) {
+ omap_plane_atomic_destroy_state(plane, plane->state);
+ plane->state = NULL;
+ }
+
+ omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
+ if (omap_state == NULL)
+ return;
+
+ /*
+ * Set defaults depending on whether we are a primary or overlay
+ * plane.
+ */
+ omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
+ ? 0 : omap_plane->id;
+ omap_state->base.rotation = BIT(DRM_ROTATE_0);
+
+ plane->state = &omap_state->base;
+ plane->state->plane = plane;
+}
+
static int omap_plane_atomic_set_property(struct drm_plane *plane,
struct drm_plane_state *state,
struct drm_property *property,
@@ -366,7 +365,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
&omap_plane_funcs, omap_plane->formats,
- omap_plane->nformats, type);
+ omap_plane->nformats, type, NULL);
if (ret < 0)
goto error;
diff --git a/drivers/gpu/drm/omapdrm/tcm-sita.c b/drivers/gpu/drm/omapdrm/tcm-sita.c
index efb609510540..c10fdfc0930f 100644
--- a/drivers/gpu/drm/omapdrm/tcm-sita.c
+++ b/drivers/gpu/drm/omapdrm/tcm-sita.c
@@ -5,8 +5,9 @@
*
* Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
* Lajos Molnar <molnar@ti.com>
+ * Andy Gross <andy.gross@ti.com>
*
- * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2012 Texas Instruments, Inc.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,687 +18,244 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/bitmap.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
+#include "tcm.h"
-#include "tcm-sita.h"
-
-#define ALIGN_DOWN(value, align) ((value) & ~((align) - 1))
-
-/* Individual selection criteria for different scan areas */
-static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL;
-static s32 CR_R2L_T2B = CR_DIAGONAL_BALANCE;
-
-/*********************************************
- * TCM API - Sita Implementation
- *********************************************/
-static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
- struct tcm_area *area);
-static s32 sita_reserve_1d(struct tcm *tcm, u32 slots, struct tcm_area *area);
-static s32 sita_free(struct tcm *tcm, struct tcm_area *area);
-static void sita_deinit(struct tcm *tcm);
-
-/*********************************************
- * Main Scanner functions
- *********************************************/
-static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
- struct tcm_area *area);
-
-static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
- struct tcm_area *field, struct tcm_area *area);
-
-static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
- struct tcm_area *field, struct tcm_area *area);
-
-static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
- struct tcm_area *field, struct tcm_area *area);
-
-/*********************************************
- * Support Infrastructure Methods
- *********************************************/
-static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
-
-static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
- struct tcm_area *field, s32 criteria,
- struct score *best);
-
-static void get_nearness_factor(struct tcm_area *field,
- struct tcm_area *candidate,
- struct nearness_factor *nf);
-
-static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
- struct neighbor_stats *stat);
-
-static void fill_area(struct tcm *tcm,
- struct tcm_area *area, struct tcm_area *parent);
-
-
-/*********************************************/
-
-/*********************************************
- * Utility Methods
- *********************************************/
-struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
-{
- struct tcm *tcm;
- struct sita_pvt *pvt;
- struct tcm_area area = {0};
- s32 i;
-
- if (width == 0 || height == 0)
- return NULL;
-
- tcm = kmalloc(sizeof(*tcm), GFP_KERNEL);
- pvt = kmalloc(sizeof(*pvt), GFP_KERNEL);
- if (!tcm || !pvt)
- goto error;
-
- memset(tcm, 0, sizeof(*tcm));
- memset(pvt, 0, sizeof(*pvt));
-
- /* Updating the pointers to SiTA implementation APIs */
- tcm->height = height;
- tcm->width = width;
- tcm->reserve_2d = sita_reserve_2d;
- tcm->reserve_1d = sita_reserve_1d;
- tcm->free = sita_free;
- tcm->deinit = sita_deinit;
- tcm->pvt = (void *)pvt;
-
- spin_lock_init(&(pvt->lock));
-
- /* Creating tam map */
- pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
- if (!pvt->map)
- goto error;
-
- for (i = 0; i < tcm->width; i++) {
- pvt->map[i] =
- kmalloc(sizeof(**pvt->map) * tcm->height,
- GFP_KERNEL);
- if (pvt->map[i] == NULL) {
- while (i--)
- kfree(pvt->map[i]);
- kfree(pvt->map);
- goto error;
- }
- }
-
- if (attr && attr->x <= tcm->width && attr->y <= tcm->height) {
- pvt->div_pt.x = attr->x;
- pvt->div_pt.y = attr->y;
-
- } else {
- /* Defaulting to 3:1 ratio on width for 2D area split */
- /* Defaulting to 3:1 ratio on height for 2D and 1D split */
- pvt->div_pt.x = (tcm->width * 3) / 4;
- pvt->div_pt.y = (tcm->height * 3) / 4;
- }
-
- spin_lock(&(pvt->lock));
- assign(&area, 0, 0, width - 1, height - 1);
- fill_area(tcm, &area, NULL);
- spin_unlock(&(pvt->lock));
- return tcm;
-
-error:
- kfree(tcm);
- kfree(pvt);
- return NULL;
-}
-
-static void sita_deinit(struct tcm *tcm)
-{
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- struct tcm_area area = {0};
- s32 i;
-
- area.p1.x = tcm->width - 1;
- area.p1.y = tcm->height - 1;
-
- spin_lock(&(pvt->lock));
- fill_area(tcm, &area, NULL);
- spin_unlock(&(pvt->lock));
-
- for (i = 0; i < tcm->height; i++)
- kfree(pvt->map[i]);
- kfree(pvt->map);
- kfree(pvt);
-}
-
-/**
- * Reserve a 1D area in the container
- *
- * @param num_slots size of 1D area
- * @param area pointer to the area that will be populated with the
- * reserved area
- *
- * @return 0 on success, non-0 error value on failure.
+static unsigned long mask[8];
+/*
+ * pos position in bitmap
+ * w width in slots
+ * h height in slots
+ * map ptr to bitmap
+ * stride slots in a row
*/
-static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
- struct tcm_area *area)
+static void free_slots(unsigned long pos, uint16_t w, uint16_t h,
+ unsigned long *map, uint16_t stride)
{
- s32 ret;
- struct tcm_area field = {0};
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
-
- spin_lock(&(pvt->lock));
-
- /* Scanning entire container */
- assign(&field, tcm->width - 1, tcm->height - 1, 0, 0);
+ int i;
- ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area);
- if (!ret)
- /* update map */
- fill_area(tcm, area, area);
-
- spin_unlock(&(pvt->lock));
- return ret;
+ for (i = 0; i < h; i++, pos += stride)
+ bitmap_clear(map, pos, w);
}
-/**
- * Reserve a 2D area in the container
- *
- * @param w width
- * @param h height
- * @param area pointer to the area that will be populated with the reserved
- * area
- *
- * @return 0 on success, non-0 error value on failure.
+/*
+ * w width in slots
+ * pos ptr to position
+ * map ptr to bitmap
+ * num_bits number of bits in bitmap
*/
-static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
- struct tcm_area *area)
+static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map,
+ size_t num_bits)
{
- s32 ret;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ unsigned long search_count = 0;
+ unsigned long bit;
+ bool area_found = false;
- /* not supporting more than 64 as alignment */
- if (align > 64)
- return -EINVAL;
+ *pos = num_bits - w;
- /* we prefer 1, 32 and 64 as alignment */
- align = align <= 1 ? 1 : align <= 32 ? 32 : 64;
+ while (search_count < num_bits) {
+ bit = find_next_bit(map, num_bits, *pos);
- spin_lock(&(pvt->lock));
- ret = scan_areas_and_find_fit(tcm, w, h, align, area);
- if (!ret)
- /* update map */
- fill_area(tcm, area, area);
+ if (bit - *pos >= w) {
+ /* found a long enough free area */
+ bitmap_set(map, *pos, w);
+ area_found = true;
+ break;
+ }
- spin_unlock(&(pvt->lock));
- return ret;
+ search_count = num_bits - bit + w;
+ *pos = bit - w;
+ }
+
+ return (area_found) ? 0 : -ENOMEM;
}
-/**
- * Unreserve a previously allocated 2D or 1D area
- * @param area area to be freed
- * @return 0 - success
+/*
+ * w = width in slots
+ * h = height in slots
+ * a = align in slots (mask, 2^n-1, 0 is unaligned)
+ * offset = offset in bytes from 4KiB
+ * pos = position in bitmap for buffer
+ * map = bitmap ptr
+ * num_bits = size of bitmap
+ * stride = bits in one row of container
*/
-static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
+static int l2r_t2b(uint16_t w, uint16_t h, uint16_t a, int16_t offset,
+ unsigned long *pos, unsigned long slot_bytes,
+ unsigned long *map, size_t num_bits, size_t slot_stride)
{
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
-
- spin_lock(&(pvt->lock));
+ int i;
+ unsigned long index;
+ bool area_free;
+ unsigned long slots_per_band = PAGE_SIZE / slot_bytes;
+ unsigned long bit_offset = (offset > 0) ? offset / slot_bytes : 0;
+ unsigned long curr_bit = bit_offset;
+
+ /* reset alignment to 1 if we are matching a specific offset */
+ /* adjust alignment - 1 to get to the format expected in bitmaps */
+ a = (offset > 0) ? 0 : a - 1;
+
+ /* FIXME Return error if slots_per_band > stride */
+
+ while (curr_bit < num_bits) {
+ *pos = bitmap_find_next_zero_area(map, num_bits, curr_bit, w,
+ a);
+
+ /* skip forward if we are not at right offset */
+ if (bit_offset > 0 && (*pos % slots_per_band != bit_offset)) {
+ curr_bit = ALIGN(*pos, slots_per_band) + bit_offset;
+ continue;
+ }
- /* check that this is in fact an existing area */
- WARN_ON(pvt->map[area->p0.x][area->p0.y] != area ||
- pvt->map[area->p1.x][area->p1.y] != area);
+ /* skip forward to next row if we overlap end of row */
+ if ((*pos % slot_stride) + w > slot_stride) {
+ curr_bit = ALIGN(*pos, slot_stride) + bit_offset;
+ continue;
+ }
- /* Clear the contents of the associated tiles in the map */
- fill_area(tcm, area, NULL);
+ /* TODO: Handle overlapping 4K boundaries */
- spin_unlock(&(pvt->lock));
+ /* break out of look if we will go past end of container */
+ if ((*pos + slot_stride * h) > num_bits)
+ break;
- return 0;
-}
+ /* generate mask that represents out matching pattern */
+ bitmap_clear(mask, 0, slot_stride);
+ bitmap_set(mask, (*pos % BITS_PER_LONG), w);
-/**
- * Note: In general the cordinates in the scan field area relevant to the can
- * sweep directions. The scan origin (e.g. top-left corner) will always be
- * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x
- * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y
- * <= p0.y
- */
+ /* assume the area is free until we find an overlap */
+ area_free = true;
-/**
- * Raster scan horizontally right to left from top to bottom to find a place for
- * a 2D area of given size inside a scan field.
- *
- * @param w width of desired area
- * @param h height of desired area
- * @param align desired area alignment
- * @param area pointer to the area that will be set to the best position
- * @param field area to scan (inclusive)
- *
- * @return 0 on success, non-0 error value on failure.
- */
-static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
- struct tcm_area *field, struct tcm_area *area)
-{
- s32 x, y;
- s16 start_x, end_x, start_y, end_y, found_x = -1;
- struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
- struct score best = {{0}, {0}, {0}, 0};
-
- start_x = field->p0.x;
- end_x = field->p1.x;
- start_y = field->p0.y;
- end_y = field->p1.y;
-
- /* check scan area co-ordinates */
- if (field->p0.x < field->p1.x ||
- field->p1.y < field->p0.y)
- return -EINVAL;
-
- /* check if allocation would fit in scan area */
- if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y))
- return -ENOSPC;
-
- /* adjust start_x and end_y, as allocation would not fit beyond */
- start_x = ALIGN_DOWN(start_x - w + 1, align); /* - 1 to be inclusive */
- end_y = end_y - h + 1;
-
- /* check if allocation would still fit in scan area */
- if (start_x < end_x)
- return -ENOSPC;
-
- /* scan field top-to-bottom, right-to-left */
- for (y = start_y; y <= end_y; y++) {
- for (x = start_x; x >= end_x; x -= align) {
- if (is_area_free(map, x, y, w, h)) {
- found_x = x;
-
- /* update best candidate */
- if (update_candidate(tcm, x, y, w, h, field,
- CR_R2L_T2B, &best))
- goto done;
-
- /* change upper x bound */
- end_x = x + 1;
+ /* check subsequent rows to see if complete area is free */
+ for (i = 1; i < h; i++) {
+ index = *pos / BITS_PER_LONG + i * 8;
+ if (bitmap_intersects(&map[index], mask,
+ (*pos % BITS_PER_LONG) + w)) {
+ area_free = false;
break;
- } else if (map[x][y] && map[x][y]->is2d) {
- /* step over 2D areas */
- x = ALIGN(map[x][y]->p0.x - w + 1, align);
}
}
- /* break if you find a free area shouldering the scan field */
- if (found_x == start_x)
+ if (area_free)
break;
- }
-
- if (!best.a.tcm)
- return -ENOSPC;
-done:
- assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
- return 0;
-}
-
-/**
- * Raster scan horizontally left to right from top to bottom to find a place for
- * a 2D area of given size inside a scan field.
- *
- * @param w width of desired area
- * @param h height of desired area
- * @param align desired area alignment
- * @param area pointer to the area that will be set to the best position
- * @param field area to scan (inclusive)
- *
- * @return 0 on success, non-0 error value on failure.
- */
-static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
- struct tcm_area *field, struct tcm_area *area)
-{
- s32 x, y;
- s16 start_x, end_x, start_y, end_y, found_x = -1;
- struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
- struct score best = {{0}, {0}, {0}, 0};
-
- start_x = field->p0.x;
- end_x = field->p1.x;
- start_y = field->p0.y;
- end_y = field->p1.y;
-
- /* check scan area co-ordinates */
- if (field->p1.x < field->p0.x ||
- field->p1.y < field->p0.y)
- return -EINVAL;
-
- /* check if allocation would fit in scan area */
- if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
- return -ENOSPC;
-
- start_x = ALIGN(start_x, align);
-
- /* check if allocation would still fit in scan area */
- if (w > LEN(end_x, start_x))
- return -ENOSPC;
-
- /* adjust end_x and end_y, as allocation would not fit beyond */
- end_x = end_x - w + 1; /* + 1 to be inclusive */
- end_y = end_y - h + 1;
-
- /* scan field top-to-bottom, left-to-right */
- for (y = start_y; y <= end_y; y++) {
- for (x = start_x; x <= end_x; x += align) {
- if (is_area_free(map, x, y, w, h)) {
- found_x = x;
-
- /* update best candidate */
- if (update_candidate(tcm, x, y, w, h, field,
- CR_L2R_T2B, &best))
- goto done;
- /* change upper x bound */
- end_x = x - 1;
- break;
- } else if (map[x][y] && map[x][y]->is2d) {
- /* step over 2D areas */
- x = ALIGN_DOWN(map[x][y]->p1.x, align);
- }
- }
+ /* go forward past this match */
+ if (bit_offset > 0)
+ curr_bit = ALIGN(*pos, slots_per_band) + bit_offset;
+ else
+ curr_bit = *pos + a + 1;
+ }
- /* break if you find a free area shouldering the scan field */
- if (found_x == start_x)
- break;
+ if (area_free) {
+ /* set area as in-use. iterate over rows */
+ for (i = 0, index = *pos; i < h; i++, index += slot_stride)
+ bitmap_set(map, index, w);
}
- if (!best.a.tcm)
- return -ENOSPC;
-done:
- assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
- return 0;
+ return (area_free) ? 0 : -ENOMEM;
}
-/**
- * Raster scan horizontally right to left from bottom to top to find a place
- * for a 1D area of given size inside a scan field.
- *
- * @param num_slots size of desired area
- * @param align desired area alignment
- * @param area pointer to the area that will be set to the best
- * position
- * @param field area to scan (inclusive)
- *
- * @return 0 on success, non-0 error value on failure.
- */
-static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
- struct tcm_area *field, struct tcm_area *area)
+static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
+ struct tcm_area *area)
{
- s32 found = 0;
- s16 x, y;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- struct tcm_area *p;
-
- /* check scan area co-ordinates */
- if (field->p0.y < field->p1.y)
- return -EINVAL;
-
- /**
- * Currently we only support full width 1D scan field, which makes sense
- * since 1D slot-ordering spans the full container width.
- */
- if (tcm->width != field->p0.x - field->p1.x + 1)
- return -EINVAL;
-
- /* check if allocation would fit in scan area */
- if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y))
- return -ENOSPC;
-
- x = field->p0.x;
- y = field->p0.y;
-
- /* find num_slots consecutive free slots to the left */
- while (found < num_slots) {
- if (y < 0)
- return -ENOSPC;
-
- /* remember bottom-right corner */
- if (found == 0) {
- area->p1.x = x;
- area->p1.y = y;
- }
-
- /* skip busy regions */
- p = pvt->map[x][y];
- if (p) {
- /* move to left of 2D areas, top left of 1D */
- x = p->p0.x;
- if (!p->is2d)
- y = p->p0.y;
-
- /* start over */
- found = 0;
- } else {
- /* count consecutive free slots */
- found++;
- if (found == num_slots)
- break;
- }
-
- /* move to the left */
- if (x == 0)
- y--;
- x = (x ? : tcm->width) - 1;
-
+ unsigned long pos;
+ int ret;
+
+ spin_lock(&(tcm->lock));
+ ret = r2l_b2t_1d(num_slots, &pos, tcm->bitmap, tcm->map_size);
+ if (!ret) {
+ area->p0.x = pos % tcm->width;
+ area->p0.y = pos / tcm->width;
+ area->p1.x = (pos + num_slots - 1) % tcm->width;
+ area->p1.y = (pos + num_slots - 1) / tcm->width;
}
+ spin_unlock(&(tcm->lock));
- /* set top-left corner */
- area->p0.x = x;
- area->p0.y = y;
- return 0;
+ return ret;
}
-/**
- * Find a place for a 2D area of given size inside a scan field based on its
- * alignment needs.
- *
- * @param w width of desired area
- * @param h height of desired area
- * @param align desired area alignment
- * @param area pointer to the area that will be set to the best position
- *
- * @return 0 on success, non-0 error value on failure.
- */
-static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
- struct tcm_area *area)
+static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align,
+ int16_t offset, uint16_t slot_bytes,
+ struct tcm_area *area)
{
- s32 ret = 0;
- struct tcm_area field = {0};
- u16 boundary_x, boundary_y;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
-
- if (align > 1) {
- /* prefer top-left corner */
- boundary_x = pvt->div_pt.x - 1;
- boundary_y = pvt->div_pt.y - 1;
-
- /* expand width and height if needed */
- if (w > pvt->div_pt.x)
- boundary_x = tcm->width - 1;
- if (h > pvt->div_pt.y)
- boundary_y = tcm->height - 1;
-
- assign(&field, 0, 0, boundary_x, boundary_y);
- ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
-
- /* scan whole container if failed, but do not scan 2x */
- if (ret != 0 && (boundary_x != tcm->width - 1 ||
- boundary_y != tcm->height - 1)) {
- /* scan the entire container if nothing found */
- assign(&field, 0, 0, tcm->width - 1, tcm->height - 1);
- ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
- }
- } else if (align == 1) {
- /* prefer top-right corner */
- boundary_x = pvt->div_pt.x;
- boundary_y = pvt->div_pt.y - 1;
-
- /* expand width and height if needed */
- if (w > (tcm->width - pvt->div_pt.x))
- boundary_x = 0;
- if (h > pvt->div_pt.y)
- boundary_y = tcm->height - 1;
-
- assign(&field, tcm->width - 1, 0, boundary_x, boundary_y);
- ret = scan_r2l_t2b(tcm, w, h, align, &field, area);
-
- /* scan whole container if failed, but do not scan 2x */
- if (ret != 0 && (boundary_x != 0 ||
- boundary_y != tcm->height - 1)) {
- /* scan the entire container if nothing found */
- assign(&field, tcm->width - 1, 0, 0, tcm->height - 1);
- ret = scan_r2l_t2b(tcm, w, h, align, &field,
- area);
- }
+ unsigned long pos;
+ int ret;
+
+ spin_lock(&(tcm->lock));
+ ret = l2r_t2b(w, h, align, offset, &pos, slot_bytes, tcm->bitmap,
+ tcm->map_size, tcm->width);
+
+ if (!ret) {
+ area->p0.x = pos % tcm->width;
+ area->p0.y = pos / tcm->width;
+ area->p1.x = area->p0.x + w - 1;
+ area->p1.y = area->p0.y + h - 1;
}
+ spin_unlock(&(tcm->lock));
return ret;
}
-/* check if an entire area is free */
-static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h)
+static void sita_deinit(struct tcm *tcm)
{
- u16 x = 0, y = 0;
- for (y = y0; y < y0 + h; y++) {
- for (x = x0; x < x0 + w; x++) {
- if (map[x][y])
- return false;
- }
- }
- return true;
+ kfree(tcm);
}
-/* fills an area with a parent tcm_area */
-static void fill_area(struct tcm *tcm, struct tcm_area *area,
- struct tcm_area *parent)
+static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
{
- s32 x, y;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- struct tcm_area a, a_;
-
- /* set area's tcm; otherwise, enumerator considers it invalid */
- area->tcm = tcm;
-
- tcm_for_each_slice(a, *area, a_) {
- for (x = a.p0.x; x <= a.p1.x; ++x)
- for (y = a.p0.y; y <= a.p1.y; ++y)
- pvt->map[x][y] = parent;
+ unsigned long pos;
+ uint16_t w, h;
+ pos = area->p0.x + area->p0.y * tcm->width;
+ if (area->is2d) {
+ w = area->p1.x - area->p0.x + 1;
+ h = area->p1.y - area->p0.y + 1;
+ } else {
+ w = area->p1.x + area->p1.y * tcm->width - pos + 1;
+ h = 1;
}
+
+ spin_lock(&(tcm->lock));
+ free_slots(pos, w, h, tcm->bitmap, tcm->width);
+ spin_unlock(&(tcm->lock));
+ return 0;
}
-/**
- * Compares a candidate area to the current best area, and if it is a better
- * fit, it updates the best to this one.
- *
- * @param x0, y0, w, h top, left, width, height of candidate area
- * @param field scan field
- * @param criteria scan criteria
- * @param best best candidate and its scores
- *
- * @return 1 (true) if the candidate area is known to be the final best, so no
- * more searching should be performed
- */
-static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
- struct tcm_area *field, s32 criteria,
- struct score *best)
+struct tcm *sita_init(u16 width, u16 height)
{
- struct score me; /* score for area */
-
- /*
- * NOTE: For horizontal bias we always give the first found, because our
- * scan is horizontal-raster-based and the first candidate will always
- * have the horizontal bias.
- */
- bool first = criteria & CR_BIAS_HORIZONTAL;
-
- assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1);
-
- /* calculate score for current candidate */
- if (!first) {
- get_neighbor_stats(tcm, &me.a, &me.n);
- me.neighs = me.n.edge + me.n.busy;
- get_nearness_factor(field, &me.a, &me.f);
- }
-
- /* the 1st candidate is always the best */
- if (!best->a.tcm)
- goto better;
+ struct tcm *tcm;
+ size_t map_size = BITS_TO_LONGS(width*height) * sizeof(unsigned long);
- BUG_ON(first);
+ if (width == 0 || height == 0)
+ return NULL;
- /* diagonal balance check */
- if ((criteria & CR_DIAGONAL_BALANCE) &&
- best->neighs <= me.neighs &&
- (best->neighs < me.neighs ||
- /* this implies that neighs and occupied match */
- best->n.busy < me.n.busy ||
- (best->n.busy == me.n.busy &&
- /* check the nearness factor */
- best->f.x + best->f.y > me.f.x + me.f.y)))
- goto better;
+ tcm = kzalloc(sizeof(*tcm) + map_size, GFP_KERNEL);
+ if (!tcm)
+ goto error;
- /* not better, keep going */
- return 0;
+ /* Updating the pointers to SiTA implementation APIs */
+ tcm->height = height;
+ tcm->width = width;
+ tcm->reserve_2d = sita_reserve_2d;
+ tcm->reserve_1d = sita_reserve_1d;
+ tcm->free = sita_free;
+ tcm->deinit = sita_deinit;
-better:
- /* save current area as best */
- memcpy(best, &me, sizeof(me));
- best->a.tcm = tcm;
- return first;
-}
+ spin_lock_init(&tcm->lock);
+ tcm->bitmap = (unsigned long *)(tcm + 1);
+ bitmap_clear(tcm->bitmap, 0, width*height);
-/**
- * Calculate the nearness factor of an area in a search field. The nearness
- * factor is smaller if the area is closer to the search origin.
- */
-static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area,
- struct nearness_factor *nf)
-{
- /**
- * Using signed math as field coordinates may be reversed if
- * search direction is right-to-left or bottom-to-top.
- */
- nf->x = (s32)(area->p0.x - field->p0.x) * 1000 /
- (field->p1.x - field->p0.x);
- nf->y = (s32)(area->p0.y - field->p0.y) * 1000 /
- (field->p1.y - field->p0.y);
-}
+ tcm->map_size = width*height;
-/* get neighbor statistics */
-static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
- struct neighbor_stats *stat)
-{
- s16 x = 0, y = 0;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
-
- /* Clearing any exisiting values */
- memset(stat, 0, sizeof(*stat));
-
- /* process top & bottom edges */
- for (x = area->p0.x; x <= area->p1.x; x++) {
- if (area->p0.y == 0)
- stat->edge++;
- else if (pvt->map[x][area->p0.y - 1])
- stat->busy++;
-
- if (area->p1.y == tcm->height - 1)
- stat->edge++;
- else if (pvt->map[x][area->p1.y + 1])
- stat->busy++;
- }
+ return tcm;
- /* process left & right edges */
- for (y = area->p0.y; y <= area->p1.y; ++y) {
- if (area->p0.x == 0)
- stat->edge++;
- else if (pvt->map[area->p0.x - 1][y])
- stat->busy++;
-
- if (area->p1.x == tcm->width - 1)
- stat->edge++;
- else if (pvt->map[area->p1.x + 1][y])
- stat->busy++;
- }
+error:
+ kfree(tcm);
+ return NULL;
}
diff --git a/drivers/gpu/drm/omapdrm/tcm.h b/drivers/gpu/drm/omapdrm/tcm.h
index a8d5ce47686f..ef7df7d6fc84 100644
--- a/drivers/gpu/drm/omapdrm/tcm.h
+++ b/drivers/gpu/drm/omapdrm/tcm.h
@@ -61,18 +61,17 @@ struct tcm {
unsigned int y_offset; /* offset to use for y coordinates */
- /* 'pvt' structure shall contain any tcm details (attr) along with
- linked list of allocated areas and mutex for mutually exclusive access
- to the list. It may also contain copies of width and height to notice
- any changes to the publicly available width and height fields. */
- void *pvt;
+ spinlock_t lock;
+ unsigned long *bitmap;
+ size_t map_size;
/* function table */
- s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u8 align,
+ s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align,
+ int16_t offset, uint16_t slot_bytes,
struct tcm_area *area);
s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
- s32 (*free) (struct tcm *tcm, struct tcm_area *area);
- void (*deinit) (struct tcm *tcm);
+ s32 (*free)(struct tcm *tcm, struct tcm_area *area);
+ void (*deinit)(struct tcm *tcm);
};
/*=============================================================================
@@ -91,7 +90,7 @@ struct tcm {
*
*/
-struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr);
+struct tcm *sita_init(u16 width, u16 height);
/**
@@ -120,6 +119,9 @@ static inline void tcm_deinit(struct tcm *tcm)
* all values may be supported by the container manager,
* but it must support 0 (1), 32 and 64.
* 0 value is equivalent to 1.
+ * @param offset Offset requirement, in bytes. This is the offset
+ * from a 4KiB aligned virtual address.
+ * @param slot_bytes Width of slot in bytes
* @param area Pointer to where the reserved area should be stored.
*
* @return 0 on success. Non-0 error code on failure. Also,
@@ -129,7 +131,8 @@ static inline void tcm_deinit(struct tcm *tcm)
* allocation.
*/
static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
- u16 align, struct tcm_area *area)
+ u16 align, int16_t offset, uint16_t slot_bytes,
+ struct tcm_area *area)
{
/* perform rudimentary error checking */
s32 res = tcm == NULL ? -ENODEV :
@@ -140,7 +143,8 @@ static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
if (!res) {
area->is2d = true;
- res = tcm->reserve_2d(tcm, height, width, align, area);
+ res = tcm->reserve_2d(tcm, height, width, align, offset,
+ slot_bytes, area);
area->tcm = res ? NULL : tcm;
}
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 7d4704b1292b..1500ab99f548 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -31,6 +31,16 @@ 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_PANASONIC_VVX10F034N00
+ tristate "Panasonic VVX10F034N00 1920x1200 video mode panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for Panasonic VVX10F034N00
+ WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some
+ Xperia Z2 tablets
+
config DRM_PANEL_SAMSUNG_S6E8AA0
tristate "Samsung S6E8AA0 DSI video mode panel"
depends on OF
@@ -51,4 +61,13 @@ config DRM_PANEL_SHARP_LQ101R1SX01
To compile this driver as a module, choose M here: the module
will be called panel-sharp-lq101r1sx01.
+config DRM_PANEL_SHARP_LS043T1LE01
+ tristate "Sharp LS043T1LE01 qHD video mode panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
+ (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
+
endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index d0f016dd7ddb..f277eed933d6 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,7 @@
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
+obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
new file mode 100644
index 000000000000..7f915f706fa6
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2015 Red Hat
+ * Copyright (C) 2015 Sony Mobile Communications Inc.
+ * Author: Werner Johansson <werner.johansson@sonymobile.com>
+ *
+ * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/backlight.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+/*
+ * When power is turned off to this panel a minimum off time of 500ms has to be
+ * observed before powering back on as there's no external reset pin. Keep
+ * track of earliest wakeup time and delay subsequent prepare call accordingly
+ */
+#define MIN_POFF_MS (500)
+
+struct wuxga_nt_panel {
+ struct drm_panel base;
+ struct mipi_dsi_device *dsi;
+
+ struct backlight_device *backlight;
+ struct regulator *supply;
+
+ bool prepared;
+ bool enabled;
+
+ ktime_t earliest_wake;
+
+ const struct drm_display_mode *mode;
+};
+
+static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct wuxga_nt_panel, base);
+}
+
+static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
+{
+ struct mipi_dsi_device *dsi = wuxga_nt->dsi;
+ int ret;
+
+ ret = mipi_dsi_turn_on_peripheral(dsi);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wuxga_nt_panel_disable(struct drm_panel *panel)
+{
+ struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
+
+ if (!wuxga_nt->enabled)
+ return 0;
+
+ mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
+
+ if (wuxga_nt->backlight) {
+ wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN;
+ wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK;
+ backlight_update_status(wuxga_nt->backlight);
+ }
+
+ wuxga_nt->enabled = false;
+
+ return 0;
+}
+
+static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
+{
+ struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
+
+ if (!wuxga_nt->prepared)
+ return 0;
+
+ regulator_disable(wuxga_nt->supply);
+ wuxga_nt->earliest_wake = ktime_add_ms(ktime_get_real(), MIN_POFF_MS);
+ wuxga_nt->prepared = false;
+
+ return 0;
+}
+
+static int wuxga_nt_panel_prepare(struct drm_panel *panel)
+{
+ struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
+ int ret;
+ s64 enablewait;
+
+ if (wuxga_nt->prepared)
+ return 0;
+
+ /*
+ * If the user re-enabled the panel before the required off-time then
+ * we need to wait the remaining period before re-enabling regulator
+ */
+ enablewait = ktime_ms_delta(wuxga_nt->earliest_wake, ktime_get_real());
+
+ /* Sanity check, this should never happen */
+ if (enablewait > MIN_POFF_MS)
+ enablewait = MIN_POFF_MS;
+
+ if (enablewait > 0)
+ msleep(enablewait);
+
+ ret = regulator_enable(wuxga_nt->supply);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * A minimum delay of 250ms is required after power-up until commands
+ * can be sent
+ */
+ msleep(250);
+
+ ret = wuxga_nt_panel_on(wuxga_nt);
+ if (ret < 0) {
+ dev_err(panel->dev, "failed to set panel on: %d\n", ret);
+ goto poweroff;
+ }
+
+ wuxga_nt->prepared = true;
+
+ return 0;
+
+poweroff:
+ regulator_disable(wuxga_nt->supply);
+
+ return ret;
+}
+
+static int wuxga_nt_panel_enable(struct drm_panel *panel)
+{
+ struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
+
+ if (wuxga_nt->enabled)
+ return 0;
+
+ if (wuxga_nt->backlight) {
+ wuxga_nt->backlight->props.power = FB_BLANK_UNBLANK;
+ wuxga_nt->backlight->props.state &= ~BL_CORE_FBBLANK;
+ backlight_update_status(wuxga_nt->backlight);
+ }
+
+ wuxga_nt->enabled = true;
+
+ return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+ .clock = 164402,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 152,
+ .hsync_end = 1920 + 152 + 52,
+ .htotal = 1920 + 152 + 52 + 20,
+ .vdisplay = 1200,
+ .vsync_start = 1200 + 24,
+ .vsync_end = 1200 + 24 + 6,
+ .vtotal = 1200 + 24 + 6 + 48,
+ .vrefresh = 60,
+};
+
+static int wuxga_nt_panel_get_modes(struct drm_panel *panel)
+{
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(panel->drm, &default_mode);
+ if (!mode) {
+ dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ default_mode.vrefresh);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ drm_mode_probed_add(panel->connector, mode);
+
+ panel->connector->display_info.width_mm = 217;
+ panel->connector->display_info.height_mm = 136;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs wuxga_nt_panel_funcs = {
+ .disable = wuxga_nt_panel_disable,
+ .unprepare = wuxga_nt_panel_unprepare,
+ .prepare = wuxga_nt_panel_prepare,
+ .enable = wuxga_nt_panel_enable,
+ .get_modes = wuxga_nt_panel_get_modes,
+};
+
+static const struct of_device_id wuxga_nt_of_match[] = {
+ { .compatible = "panasonic,vvx10f034n00", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);
+
+static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
+{
+ struct device *dev = &wuxga_nt->dsi->dev;
+ struct device_node *np;
+ int ret;
+
+ wuxga_nt->mode = &default_mode;
+
+ wuxga_nt->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(wuxga_nt->supply))
+ return PTR_ERR(wuxga_nt->supply);
+
+ np = of_parse_phandle(dev->of_node, "backlight", 0);
+ if (np) {
+ wuxga_nt->backlight = of_find_backlight_by_node(np);
+ of_node_put(np);
+
+ if (!wuxga_nt->backlight)
+ return -EPROBE_DEFER;
+ }
+
+ drm_panel_init(&wuxga_nt->base);
+ wuxga_nt->base.funcs = &wuxga_nt_panel_funcs;
+ wuxga_nt->base.dev = &wuxga_nt->dsi->dev;
+
+ ret = drm_panel_add(&wuxga_nt->base);
+ if (ret < 0)
+ goto put_backlight;
+
+ return 0;
+
+put_backlight:
+ if (wuxga_nt->backlight)
+ put_device(&wuxga_nt->backlight->dev);
+
+ return ret;
+}
+
+static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
+{
+ if (wuxga_nt->base.dev)
+ drm_panel_remove(&wuxga_nt->base);
+
+ if (wuxga_nt->backlight)
+ put_device(&wuxga_nt->backlight->dev);
+}
+
+static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi)
+{
+ struct wuxga_nt_panel *wuxga_nt;
+ int ret;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_HSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS |
+ MIPI_DSI_MODE_LPM;
+
+ wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL);
+ if (!wuxga_nt)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, wuxga_nt);
+
+ wuxga_nt->dsi = dsi;
+
+ ret = wuxga_nt_panel_add(wuxga_nt);
+ if (ret < 0)
+ return ret;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)
+{
+ struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = wuxga_nt_panel_disable(&wuxga_nt->base);
+ if (ret < 0)
+ dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_detach(&wuxga_nt->base);
+ wuxga_nt_panel_del(wuxga_nt);
+
+ return 0;
+}
+
+static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
+
+ wuxga_nt_panel_disable(&wuxga_nt->base);
+}
+
+static struct mipi_dsi_driver wuxga_nt_panel_driver = {
+ .driver = {
+ .name = "panel-panasonic-vvx10f034n00",
+ .of_match_table = wuxga_nt_of_match,
+ },
+ .probe = wuxga_nt_panel_probe,
+ .remove = wuxga_nt_panel_remove,
+ .shutdown = wuxga_nt_panel_shutdown,
+};
+module_mipi_dsi_driver(wuxga_nt_panel_driver);
+
+MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
+MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
new file mode 100644
index 000000000000..3aeb0bda4947
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2015 Red Hat
+ * Copyright (C) 2015 Sony Mobile Communications Inc.
+ * Author: Werner Johansson <werner.johansson@sonymobile.com>
+ *
+ * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct sharp_nt_panel {
+ struct drm_panel base;
+ struct mipi_dsi_device *dsi;
+
+ struct backlight_device *backlight;
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+
+ bool prepared;
+ bool enabled;
+
+ const struct drm_display_mode *mode;
+};
+
+static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct sharp_nt_panel, base);
+}
+
+static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
+{
+ struct mipi_dsi_device *dsi = sharp_nt->dsi;
+ int ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0)
+ return ret;
+
+ msleep(120);
+
+ /* Novatek two-lane operation */
+ ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Set both MCU and RGB I/F to 24bpp */
+ ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
+ (MIPI_DCS_PIXEL_FMT_24BIT << 4));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
+{
+ struct mipi_dsi_device *dsi = sharp_nt->dsi;
+ int ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
+{
+ struct mipi_dsi_device *dsi = sharp_nt->dsi;
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+
+static int sharp_nt_panel_disable(struct drm_panel *panel)
+{
+ struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
+
+ if (!sharp_nt->enabled)
+ return 0;
+
+ if (sharp_nt->backlight) {
+ sharp_nt->backlight->props.power = FB_BLANK_POWERDOWN;
+ backlight_update_status(sharp_nt->backlight);
+ }
+
+ sharp_nt->enabled = false;
+
+ return 0;
+}
+
+static int sharp_nt_panel_unprepare(struct drm_panel *panel)
+{
+ struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
+ int ret;
+
+ if (!sharp_nt->prepared)
+ return 0;
+
+ ret = sharp_nt_panel_off(sharp_nt);
+ if (ret < 0) {
+ dev_err(panel->dev, "failed to set panel off: %d\n", ret);
+ return ret;
+ }
+
+ regulator_disable(sharp_nt->supply);
+ if (sharp_nt->reset_gpio)
+ gpiod_set_value(sharp_nt->reset_gpio, 0);
+
+ sharp_nt->prepared = false;
+
+ return 0;
+}
+
+static int sharp_nt_panel_prepare(struct drm_panel *panel)
+{
+ struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
+ int ret;
+
+ if (sharp_nt->prepared)
+ return 0;
+
+ ret = regulator_enable(sharp_nt->supply);
+ if (ret < 0)
+ return ret;
+
+ msleep(20);
+
+ if (sharp_nt->reset_gpio) {
+ gpiod_set_value(sharp_nt->reset_gpio, 1);
+ msleep(1);
+ gpiod_set_value(sharp_nt->reset_gpio, 0);
+ msleep(1);
+ gpiod_set_value(sharp_nt->reset_gpio, 1);
+ msleep(10);
+ }
+
+ ret = sharp_nt_panel_init(sharp_nt);
+ if (ret < 0) {
+ dev_err(panel->dev, "failed to init panel: %d\n", ret);
+ goto poweroff;
+ }
+
+ ret = sharp_nt_panel_on(sharp_nt);
+ if (ret < 0) {
+ dev_err(panel->dev, "failed to set panel on: %d\n", ret);
+ goto poweroff;
+ }
+
+ sharp_nt->prepared = true;
+
+ return 0;
+
+poweroff:
+ regulator_disable(sharp_nt->supply);
+ if (sharp_nt->reset_gpio)
+ gpiod_set_value(sharp_nt->reset_gpio, 0);
+ return ret;
+}
+
+static int sharp_nt_panel_enable(struct drm_panel *panel)
+{
+ struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
+
+ if (sharp_nt->enabled)
+ return 0;
+
+ if (sharp_nt->backlight) {
+ sharp_nt->backlight->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(sharp_nt->backlight);
+ }
+
+ sharp_nt->enabled = true;
+
+ return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+ .clock = 41118,
+ .hdisplay = 540,
+ .hsync_start = 540 + 48,
+ .hsync_end = 540 + 48 + 80,
+ .htotal = 540 + 48 + 80 + 32,
+ .vdisplay = 960,
+ .vsync_start = 960 + 3,
+ .vsync_end = 960 + 3 + 15,
+ .vtotal = 960 + 3 + 15 + 1,
+ .vrefresh = 60,
+};
+
+static int sharp_nt_panel_get_modes(struct drm_panel *panel)
+{
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(panel->drm, &default_mode);
+ if (!mode) {
+ dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ default_mode.vrefresh);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ drm_mode_probed_add(panel->connector, mode);
+
+ panel->connector->display_info.width_mm = 54;
+ panel->connector->display_info.height_mm = 95;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs sharp_nt_panel_funcs = {
+ .disable = sharp_nt_panel_disable,
+ .unprepare = sharp_nt_panel_unprepare,
+ .prepare = sharp_nt_panel_prepare,
+ .enable = sharp_nt_panel_enable,
+ .get_modes = sharp_nt_panel_get_modes,
+};
+
+static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
+{
+ struct device *dev = &sharp_nt->dsi->dev;
+ struct device_node *np;
+ int ret;
+
+ sharp_nt->mode = &default_mode;
+
+ sharp_nt->supply = devm_regulator_get(dev, "avdd");
+ if (IS_ERR(sharp_nt->supply))
+ return PTR_ERR(sharp_nt->supply);
+
+ sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(sharp_nt->reset_gpio)) {
+ dev_err(dev, "cannot get reset-gpios %ld\n",
+ PTR_ERR(sharp_nt->reset_gpio));
+ sharp_nt->reset_gpio = NULL;
+ } else {
+ gpiod_set_value(sharp_nt->reset_gpio, 0);
+ }
+
+ np = of_parse_phandle(dev->of_node, "backlight", 0);
+ if (np) {
+ sharp_nt->backlight = of_find_backlight_by_node(np);
+ of_node_put(np);
+
+ if (!sharp_nt->backlight)
+ return -EPROBE_DEFER;
+ }
+
+ drm_panel_init(&sharp_nt->base);
+ sharp_nt->base.funcs = &sharp_nt_panel_funcs;
+ sharp_nt->base.dev = &sharp_nt->dsi->dev;
+
+ ret = drm_panel_add(&sharp_nt->base);
+ if (ret < 0)
+ goto put_backlight;
+
+ return 0;
+
+put_backlight:
+ if (sharp_nt->backlight)
+ put_device(&sharp_nt->backlight->dev);
+
+ return ret;
+}
+
+static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
+{
+ if (sharp_nt->base.dev)
+ drm_panel_remove(&sharp_nt->base);
+
+ if (sharp_nt->backlight)
+ put_device(&sharp_nt->backlight->dev);
+}
+
+static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
+{
+ struct sharp_nt_panel *sharp_nt;
+ int ret;
+
+ dsi->lanes = 2;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_HSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS |
+ MIPI_DSI_MODE_EOT_PACKET;
+
+ sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
+ if (!sharp_nt)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, sharp_nt);
+
+ sharp_nt->dsi = dsi;
+
+ ret = sharp_nt_panel_add(sharp_nt);
+ if (ret < 0)
+ return ret;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
+{
+ struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = sharp_nt_panel_disable(&sharp_nt->base);
+ if (ret < 0)
+ dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_detach(&sharp_nt->base);
+ sharp_nt_panel_del(sharp_nt);
+
+ return 0;
+}
+
+static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
+
+ sharp_nt_panel_disable(&sharp_nt->base);
+}
+
+static const struct of_device_id sharp_nt_of_match[] = {
+ { .compatible = "sharp,ls043t1le01-qhd", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
+
+static struct mipi_dsi_driver sharp_nt_panel_driver = {
+ .driver = {
+ .name = "panel-sharp-ls043t1le01-qhd",
+ .of_match_table = sharp_nt_of_match,
+ },
+ .probe = sharp_nt_panel_probe,
+ .remove = sharp_nt_panel_remove,
+ .shutdown = sharp_nt_panel_shutdown,
+};
+module_mipi_dsi_driver(sharp_nt_panel_driver);
+
+MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
+MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index f97b73ec4713..f88a631c43ab 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -44,6 +44,10 @@ struct panel_desc {
unsigned int bpc;
+ /**
+ * @width: width (in millimeters) of the panel's active display area
+ * @height: height (in millimeters) of the panel's active display area
+ */
struct {
unsigned int width;
unsigned int height;
@@ -832,6 +836,34 @@ static const struct panel_desc innolux_g121i1_l01 = {
},
};
+static const struct drm_display_mode innolux_g121x1_l03_mode = {
+ .clock = 65000,
+ .hdisplay = 1024,
+ .hsync_start = 1024 + 0,
+ .hsync_end = 1024 + 1,
+ .htotal = 1024 + 0 + 1 + 320,
+ .vdisplay = 768,
+ .vsync_start = 768 + 38,
+ .vsync_end = 768 + 38 + 1,
+ .vtotal = 768 + 38 + 1 + 0,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc innolux_g121x1_l03 = {
+ .modes = &innolux_g121x1_l03_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 246,
+ .height = 185,
+ },
+ .delay = {
+ .enable = 200,
+ .unprepare = 200,
+ .disable = 400,
+ },
+};
+
static const struct drm_display_mode innolux_n116bge_mode = {
.clock = 76420,
.hdisplay = 1366,
@@ -902,6 +934,30 @@ static const struct panel_desc innolux_zj070na_01p = {
},
};
+static const struct display_timing kyo_tcg121xglp_timing = {
+ .pixelclock = { 52000000, 65000000, 71000000 },
+ .hactive = { 1024, 1024, 1024 },
+ .hfront_porch = { 2, 2, 2 },
+ .hback_porch = { 2, 2, 2 },
+ .hsync_len = { 86, 124, 244 },
+ .vactive = { 768, 768, 768 },
+ .vfront_porch = { 2, 2, 2 },
+ .vback_porch = { 2, 2, 2 },
+ .vsync_len = { 6, 34, 73 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc kyo_tcg121xglp = {
+ .timings = &kyo_tcg121xglp_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 246,
+ .height = 184,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+};
+
static const struct drm_display_mode lg_lb070wv8_mode = {
.clock = 33246,
.hdisplay = 800,
@@ -1027,6 +1083,30 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
+static const struct drm_display_mode qd43003c0_40_mode = {
+ .clock = 9000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 8,
+ .hsync_end = 480 + 8 + 4,
+ .htotal = 480 + 8 + 4 + 39,
+ .vdisplay = 272,
+ .vsync_start = 272 + 4,
+ .vsync_end = 272 + 4 + 10,
+ .vtotal = 272 + 4 + 10 + 2,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc qd43003c0_40 = {
+ .modes = &qd43003c0_40_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 95,
+ .height = 53,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
static const struct drm_display_mode samsung_ltn101nt05_mode = {
.clock = 54030,
.hdisplay = 1024,
@@ -1158,6 +1238,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible ="innolux,g121i1-l01",
.data = &innolux_g121i1_l01
}, {
+ .compatible = "innolux,g121x1-l03",
+ .data = &innolux_g121x1_l03,
+ }, {
.compatible = "innolux,n116bge",
.data = &innolux_n116bge,
}, {
@@ -1167,6 +1250,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "innolux,zj070na-01p",
.data = &innolux_zj070na_01p,
}, {
+ .compatible = "kyo,tcg121xglp",
+ .data = &kyo_tcg121xglp,
+ }, {
.compatible = "lg,lb070wv8",
.data = &lg_lb070wv8,
}, {
@@ -1182,6 +1268,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "ortustech,com43h4m85ulc",
.data = &ortustech_com43h4m85ulc,
}, {
+ .compatible = "qiaodian,qd43003c0-40",
+ .data = &qd43003c0_40,
+ }, {
.compatible = "samsung,ltn101nt05",
.data = &samsung_ltn101nt05,
}, {
@@ -1263,6 +1352,36 @@ static const struct panel_desc_dsi auo_b080uan01 = {
.lanes = 4,
};
+static const struct drm_display_mode boe_tv080wum_nl0_mode = {
+ .clock = 160000,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 120,
+ .hsync_end = 1200 + 120 + 20,
+ .htotal = 1200 + 120 + 20 + 21,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 21,
+ .vsync_end = 1920 + 21 + 3,
+ .vtotal = 1920 + 21 + 3 + 18,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc_dsi boe_tv080wum_nl0 = {
+ .desc = {
+ .modes = &boe_tv080wum_nl0_mode,
+ .num_modes = 1,
+ .size = {
+ .width = 107,
+ .height = 172,
+ },
+ },
+ .flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
+ .format = MIPI_DSI_FMT_RGB888,
+ .lanes = 4,
+};
+
static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
.clock = 71000,
.hdisplay = 800,
@@ -1348,11 +1467,15 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
.lanes = 4,
};
+
static const struct of_device_id dsi_of_match[] = {
{
.compatible = "auo,b080uan01",
.data = &auo_b080uan01
}, {
+ .compatible = "boe,tv080wum-nl0",
+ .data = &boe_tv080wum_nl0
+ }, {
.compatible = "lg,ld070wx3-sl01",
.data = &lg_ld070wx3_sl01
}, {
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 183aea1abebc..86276519b2ef 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -521,7 +521,7 @@ static const struct drm_framebuffer_funcs qxl_fb_funcs = {
int
qxl_framebuffer_init(struct drm_device *dev,
struct qxl_framebuffer *qfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -876,16 +876,6 @@ static const struct drm_connector_helper_funcs qxl_connector_helper_funcs = {
.best_encoder = qxl_best_encoder,
};
-static void qxl_conn_save(struct drm_connector *connector)
-{
- DRM_DEBUG("\n");
-}
-
-static void qxl_conn_restore(struct drm_connector *connector)
-{
- DRM_DEBUG("\n");
-}
-
static enum drm_connector_status qxl_conn_detect(
struct drm_connector *connector,
bool force)
@@ -932,10 +922,8 @@ static void qxl_conn_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs qxl_connector_funcs = {
.dpms = drm_helper_connector_dpms,
- .save = qxl_conn_save,
- .restore = qxl_conn_restore,
.detect = qxl_conn_detect,
- .fill_modes = drm_helper_probe_single_connector_modes_nomerge,
+ .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = qxl_conn_set_property,
.destroy = qxl_conn_destroy,
};
@@ -980,7 +968,7 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
&qxl_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
drm_encoder_init(dev, &qxl_output->enc, &qxl_enc_funcs,
- DRM_MODE_ENCODER_VIRTUAL);
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
/* we get HPD via client monitors config */
connector->polled = DRM_CONNECTOR_POLL_HPD;
@@ -1003,7 +991,7 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
static struct drm_framebuffer *
qxl_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct qxl_framebuffer *qxl_fb;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 01a86948eb8c..6e6b9b1519b8 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -390,7 +390,7 @@ void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state);
int
qxl_framebuffer_init(struct drm_device *dev,
struct qxl_framebuffer *rfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
void qxl_send_monitors_config(struct qxl_device *qdev);
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index c4a552637c93..7136e521e6db 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -40,7 +40,6 @@
struct qxl_fbdev {
struct drm_fb_helper helper;
struct qxl_framebuffer qfb;
- struct list_head fbdev_list;
struct qxl_device *qdev;
spinlock_t delayed_ops_lock;
@@ -283,7 +282,7 @@ int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
}
static int qxlfb_create_pinned_object(struct qxl_fbdev *qfbdev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **gobj_p)
{
struct qxl_device *qdev = qfbdev->qdev;
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index b28370e014c6..5e1d7899dd72 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -32,7 +32,7 @@ static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo)
struct qxl_bo *bo;
struct qxl_device *qdev;
- bo = container_of(tbo, struct qxl_bo, tbo);
+ bo = to_qxl_bo(tbo);
qdev = (struct qxl_device *)bo->gem_base.dev->dev_private;
qxl_surface_evict(qdev, bo, false);
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 0cbc4c987164..953412766416 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -201,7 +201,7 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
placement->num_busy_placement = 1;
return;
}
- qbo = container_of(bo, struct qxl_bo, tbo);
+ qbo = to_qxl_bo(bo);
qxl_ttm_placement_from_domain(qbo, QXL_GEM_DOMAIN_CPU, false);
*placement = qbo->placement;
}
@@ -365,7 +365,7 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
if (!qxl_ttm_bo_is_qxl_bo(bo))
return;
- qbo = container_of(bo, struct qxl_bo, tbo);
+ qbo = to_qxl_bo(bo);
qdev = qbo->gem_base.dev->dev_private;
if (bo->mem.mem_type == TTM_PL_PRIV0 && qbo->surface_id)
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 421ae130809b..9909f5c68d76 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -5,12 +5,3 @@ config DRM_RADEON_USERPTR
help
This option selects CONFIG_MMU_NOTIFIER if it isn't already
selected to enabled full userptr support.
-
-config DRM_RADEON_UMS
- bool "Enable userspace modesetting on radeon (DEPRECATED)"
- depends on DRM_RADEON
- help
- Choose this option if you still need userspace modesetting.
-
- Userspace modesetting is deprecated for quite some time now, so
- enable this only if you have ancient versions of the DDX drivers.
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index dea53e36a2ef..08bd17d3925c 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -58,10 +58,6 @@ $(obj)/evergreen_cs.o: $(obj)/evergreen_reg_safe.h $(obj)/cayman_reg_safe.h
radeon-y := radeon_drv.o
-# add UMS driver
-radeon-$(CONFIG_DRM_RADEON_UMS)+= radeon_cp.o radeon_state.o radeon_mem.o \
- radeon_irq.o r300_cmdbuf.o r600_cp.o r600_blit.o drm_buffer.o
-
# add KMS driver
radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
radeon_atombios.o radeon_agp.o atombios_crtc.o radeon_combios.o \
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index dac78ad24b31..801dd60ac192 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -25,6 +25,7 @@
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/radeon_drm.h>
#include <drm/drm_fixed.h>
#include "radeon.h"
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index bd73b4069069..44ee72e04df9 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -302,77 +302,31 @@ static int convert_bpc_to_bpp(int bpc)
return bpc * 3;
}
-/* get the max pix clock supported by the link rate and lane num */
-static int dp_get_max_dp_pix_clock(int link_rate,
- int lane_num,
- int bpp)
-{
- return (link_rate * lane_num * 8) / bpp;
-}
-
/***** radeon specific DP functions *****/
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
- const u8 dpcd[DP_DPCD_SIZE])
-{
- int max_link_rate;
-
- if (radeon_connector_is_dp12_capable(connector))
- max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
- else
- max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
-
- return max_link_rate;
-}
-
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
- const u8 dpcd[DP_DPCD_SIZE],
- int pix_clock)
-{
- int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
- int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
- int max_lane_num = drm_dp_max_lane_count(dpcd);
- int lane_num;
- int max_dp_pix_clock;
-
- for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
- max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
- if (pix_clock <= max_dp_pix_clock)
- break;
- }
-
- return lane_num;
-}
-
-static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
- const u8 dpcd[DP_DPCD_SIZE],
- int pix_clock)
+int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+ const u8 dpcd[DP_DPCD_SIZE],
+ unsigned pix_clock,
+ unsigned *dp_lanes, unsigned *dp_rate)
{
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
- int lane_num, max_pix_clock;
-
- if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
- ENCODER_OBJECT_ID_NUTMEG)
- return 270000;
-
- lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
- max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
- if (pix_clock <= max_pix_clock)
- return 162000;
- max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
- if (pix_clock <= max_pix_clock)
- return 270000;
- if (radeon_connector_is_dp12_capable(connector)) {
- max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
- if (pix_clock <= max_pix_clock)
- return 540000;
+ static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+ unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+ unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+ unsigned lane_num, i, max_pix_clock;
+
+ for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+ for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+ max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+ if (max_pix_clock >= pix_clock) {
+ *dp_lanes = lane_num;
+ *dp_rate = link_rates[i];
+ return 0;
+ }
+ }
}
- return radeon_dp_get_max_link_rate(connector, dpcd);
+ return -EINVAL;
}
static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
@@ -491,6 +445,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_connector;
+ int ret;
if (!radeon_connector->con_priv)
return;
@@ -498,10 +453,14 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
- dig_connector->dp_clock =
- radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
- dig_connector->dp_lane_count =
- radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+ ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+ mode->clock,
+ &dig_connector->dp_lane_count,
+ &dig_connector->dp_clock);
+ if (ret) {
+ dig_connector->dp_clock = 0;
+ dig_connector->dp_lane_count = 0;
+ }
}
}
@@ -510,7 +469,8 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_connector;
- int dp_clock;
+ unsigned dp_clock, dp_lanes;
+ int ret;
if ((mode->clock > 340000) &&
(!radeon_connector_is_dp12_capable(connector)))
@@ -520,8 +480,12 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
return MODE_CLOCK_HIGH;
dig_connector = radeon_connector->con_priv;
- dp_clock =
- radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+ ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+ mode->clock,
+ &dp_lanes,
+ &dp_clock);
+ if (ret)
+ return MODE_CLOCK_HIGH;
if ((dp_clock == 540000) &&
(!radeon_connector_is_dp12_capable(connector)))
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index bb292143997e..01b20e14a247 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -2767,23 +2767,27 @@ radeon_add_atom_encoder(struct drm_device *dev,
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
radeon_encoder->rmx_type = RMX_FULL;
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_LVDS, NULL);
radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
} else {
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
}
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder);
drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_TVDAC, NULL);
radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder);
drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
break;
@@ -2797,13 +2801,16 @@ radeon_add_atom_encoder(struct drm_device *dev,
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
radeon_encoder->rmx_type = RMX_FULL;
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_LVDS, NULL);
radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
} else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
} else {
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
}
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
@@ -2820,11 +2827,14 @@ radeon_add_atom_encoder(struct drm_device *dev,
/* these are handled by the primary encoders */
radeon_encoder->is_ext_encoder = true;
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_LVDS, NULL);
else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
else
- drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs);
break;
}
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index f81fb2641097..4c30d8c65558 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -4132,10 +4132,10 @@ struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
* @rdev: radeon_device pointer
* @ib: radeon indirect buffer object
*
- * Emits an DE (drawing engine) or CE (constant engine) IB
+ * Emits a DE (drawing engine) or CE (constant engine) IB
* on the gfx ring. IBs are usually generated by userspace
* acceleration drivers and submitted to the kernel for
- * sheduling on the ring. This function schedules the IB
+ * scheduling on the ring. This function schedules the IB
* on the gfx ring for execution by the GPU.
*/
void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index 752072771388..6bfc46369db1 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -301,6 +301,22 @@ void dce6_dp_audio_set_dto(struct radeon_device *rdev,
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
if (ASIC_IS_DCE8(rdev)) {
+ unsigned int div = (RREG32(DENTIST_DISPCLK_CNTL) &
+ DENTIST_DPREFCLK_WDIVIDER_MASK) >>
+ DENTIST_DPREFCLK_WDIVIDER_SHIFT;
+
+ if (div < 128 && div >= 96)
+ div -= 64;
+ else if (div >= 64)
+ div = div / 2 - 16;
+ else if (div >= 8)
+ div /= 4;
+ else
+ div = 0;
+
+ if (div)
+ clock = rdev->clock.gpupll_outputfreq * 10 / div;
+
WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
} else {
diff --git a/drivers/gpu/drm/radeon/drm_buffer.c b/drivers/gpu/drm/radeon/drm_buffer.c
deleted file mode 100644
index f4e0f3a3d7b1..000000000000
--- a/drivers/gpu/drm/radeon/drm_buffer.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 Pauli Nieminen.
- * 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.
- *
- *
- **************************************************************************/
-/*
- * Multipart buffer for coping data which is larger than the page size.
- *
- * Authors:
- * Pauli Nieminen <suokkos-at-gmail-dot-com>
- */
-
-#include <linux/export.h>
-#include "drm_buffer.h"
-
-/**
- * Allocate the drm buffer object.
- *
- * buf: Pointer to a pointer where the object is stored.
- * size: The number of bytes to allocate.
- */
-int drm_buffer_alloc(struct drm_buffer **buf, int size)
-{
- int nr_pages = size / PAGE_SIZE + 1;
- int idx;
-
- /* Allocating pointer table to end of structure makes drm_buffer
- * variable sized */
- *buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *),
- GFP_KERNEL);
-
- if (*buf == NULL) {
- DRM_ERROR("Failed to allocate drm buffer object to hold"
- " %d bytes in %d pages.\n",
- size, nr_pages);
- return -ENOMEM;
- }
-
- (*buf)->size = size;
-
- for (idx = 0; idx < nr_pages; ++idx) {
-
- (*buf)->data[idx] =
- kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE),
- GFP_KERNEL);
-
-
- if ((*buf)->data[idx] == NULL) {
- DRM_ERROR("Failed to allocate %dth page for drm"
- " buffer with %d bytes and %d pages.\n",
- idx + 1, size, nr_pages);
- goto error_out;
- }
-
- }
-
- return 0;
-
-error_out:
-
- for (; idx >= 0; --idx)
- kfree((*buf)->data[idx]);
-
- kfree(*buf);
- return -ENOMEM;
-}
-
-/**
- * Copy the user data to the begin of the buffer and reset the processing
- * iterator.
- *
- * user_data: A pointer the data that is copied to the buffer.
- * size: The Number of bytes to copy.
- */
-int drm_buffer_copy_from_user(struct drm_buffer *buf,
- void __user *user_data, int size)
-{
- int nr_pages = size / PAGE_SIZE + 1;
- int idx;
-
- if (size > buf->size) {
- DRM_ERROR("Requesting to copy %d bytes to a drm buffer with"
- " %d bytes space\n",
- size, buf->size);
- return -EFAULT;
- }
-
- for (idx = 0; idx < nr_pages; ++idx) {
-
- if (copy_from_user(buf->data[idx],
- user_data + idx * PAGE_SIZE,
- min(PAGE_SIZE, size - idx * PAGE_SIZE))) {
- DRM_ERROR("Failed to copy user data (%p) to drm buffer"
- " (%p) %dth page.\n",
- user_data, buf, idx);
- return -EFAULT;
-
- }
- }
- buf->iterator = 0;
- return 0;
-}
-
-/**
- * Free the drm buffer object
- */
-void drm_buffer_free(struct drm_buffer *buf)
-{
-
- if (buf != NULL) {
-
- int nr_pages = buf->size / PAGE_SIZE + 1;
- int idx;
- for (idx = 0; idx < nr_pages; ++idx)
- kfree(buf->data[idx]);
-
- kfree(buf);
- }
-}
-
-/**
- * Read an object from buffer that may be split to multiple parts. If object
- * is not split function just returns the pointer to object in buffer. But in
- * case of split object data is copied to given stack object that is suplied
- * by caller.
- *
- * The processing location of the buffer is also advanced to the next byte
- * after the object.
- *
- * objsize: The size of the objet in bytes.
- * stack_obj: A pointer to a memory location where object can be copied.
- */
-void *drm_buffer_read_object(struct drm_buffer *buf,
- int objsize, void *stack_obj)
-{
- int idx = drm_buffer_index(buf);
- int page = drm_buffer_page(buf);
- void *obj = NULL;
-
- if (idx + objsize <= PAGE_SIZE) {
- obj = &buf->data[page][idx];
- } else {
- /* The object is split which forces copy to temporary object.*/
- int beginsz = PAGE_SIZE - idx;
- memcpy(stack_obj, &buf->data[page][idx], beginsz);
-
- memcpy(stack_obj + beginsz, &buf->data[page + 1][0],
- objsize - beginsz);
-
- obj = stack_obj;
- }
-
- drm_buffer_advance(buf, objsize);
- return obj;
-}
diff --git a/drivers/gpu/drm/radeon/drm_buffer.h b/drivers/gpu/drm/radeon/drm_buffer.h
deleted file mode 100644
index c80d3a340b94..000000000000
--- a/drivers/gpu/drm/radeon/drm_buffer.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 Pauli Nieminen.
- * 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.
- *
- *
- **************************************************************************/
-/*
- * Multipart buffer for coping data which is larger than the page size.
- *
- * Authors:
- * Pauli Nieminen <suokkos-at-gmail-dot-com>
- */
-
-#ifndef _DRM_BUFFER_H_
-#define _DRM_BUFFER_H_
-
-#include <drm/drmP.h>
-
-struct drm_buffer {
- int iterator;
- int size;
- char *data[];
-};
-
-
-/**
- * Return the index of page that buffer is currently pointing at.
- */
-static inline int drm_buffer_page(struct drm_buffer *buf)
-{
- return buf->iterator / PAGE_SIZE;
-}
-/**
- * Return the index of the current byte in the page
- */
-static inline int drm_buffer_index(struct drm_buffer *buf)
-{
- return buf->iterator & (PAGE_SIZE - 1);
-}
-/**
- * Return number of bytes that is left to process
- */
-static inline int drm_buffer_unprocessed(struct drm_buffer *buf)
-{
- return buf->size - buf->iterator;
-}
-
-/**
- * Advance the buffer iterator number of bytes that is given.
- */
-static inline void drm_buffer_advance(struct drm_buffer *buf, int bytes)
-{
- buf->iterator += bytes;
-}
-
-/**
- * Allocate the drm buffer object.
- *
- * buf: A pointer to a pointer where the object is stored.
- * size: The number of bytes to allocate.
- */
-extern int drm_buffer_alloc(struct drm_buffer **buf, int size);
-
-/**
- * Copy the user data to the begin of the buffer and reset the processing
- * iterator.
- *
- * user_data: A pointer the data that is copied to the buffer.
- * size: The Number of bytes to copy.
- */
-extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
- void __user *user_data, int size);
-
-/**
- * Free the drm buffer object
- */
-extern void drm_buffer_free(struct drm_buffer *buf);
-
-/**
- * Read an object from buffer that may be split to multiple parts. If object
- * is not split function just returns the pointer to object in buffer. But in
- * case of split object data is copied to given stack object that is suplied
- * by caller.
- *
- * The processing location of the buffer is also advanced to the next byte
- * after the object.
- *
- * objsize: The size of the objet in bytes.
- * stack_obj: A pointer to a memory location where object can be copied.
- */
-extern void *drm_buffer_read_object(struct drm_buffer *buf,
- int objsize, void *stack_obj);
-
-/**
- * Returns the pointer to the dword which is offset number of elements from the
- * current processing location.
- *
- * Caller must make sure that dword is not split in the buffer. This
- * requirement is easily met if all the sizes of objects in buffer are
- * multiples of dword and PAGE_SIZE is multiple dword.
- *
- * Call to this function doesn't change the processing location.
- *
- * offset: The index of the dword relative to the internat iterator.
- */
-static inline void *drm_buffer_pointer_to_dword(struct drm_buffer *buffer,
- int offset)
-{
- int iter = buffer->iterator + offset * 4;
- return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)];
-}
-/**
- * Returns the pointer to the dword which is offset number of elements from
- * the current processing location.
- *
- * Call to this function doesn't change the processing location.
- *
- * offset: The index of the byte relative to the internat iterator.
- */
-static inline void *drm_buffer_pointer_to_byte(struct drm_buffer *buffer,
- int offset)
-{
- int iter = buffer->iterator + offset;
- return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)];
-}
-
-#endif
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 9e7e2bf03b81..5eae0a88dd3e 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3150,7 +3150,8 @@ void r100_bandwidth_update(struct radeon_device *rdev)
{
fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff;
fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff;
- fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff;
+ fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff;
+ fixed20_12 crit_point_ff = {0};
uint32_t temp, data, mem_trcd, mem_trp, mem_tras;
fixed20_12 memtcas_ff[8] = {
dfixed_init(1),
@@ -3204,7 +3205,7 @@ void r100_bandwidth_update(struct radeon_device *rdev)
fixed20_12 min_mem_eff;
fixed20_12 mc_latency_sclk, mc_latency_mclk, k1;
fixed20_12 cur_latency_mclk, cur_latency_sclk;
- fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate,
+ fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate = {0},
disp_drain_rate2, read_return_rate;
fixed20_12 time_disp1_drop_priority;
int c;
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c
deleted file mode 100644
index 9418e388b045..000000000000
--- a/drivers/gpu/drm/radeon/r300_cmdbuf.c
+++ /dev/null
@@ -1,1186 +0,0 @@
-/* r300_cmdbuf.c -- Command buffer emission for R300 -*- linux-c -*-
- *
- * Copyright (C) The Weather Channel, Inc. 2002.
- * Copyright (C) 2004 Nicolai Haehnle.
- * All Rights Reserved.
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * 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
- * PRECISION INSIGHT 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:
- * Nicolai Haehnle <prefect_@gmx.net>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-#include "r300_reg.h"
-#include "drm_buffer.h"
-
-#include <asm/unaligned.h>
-
-#define R300_SIMULTANEOUS_CLIPRECTS 4
-
-/* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects
- */
-static const int r300_cliprect_cntl[4] = {
- 0xAAAA,
- 0xEEEE,
- 0xFEFE,
- 0xFFFE
-};
-
-/**
- * Emit up to R300_SIMULTANEOUS_CLIPRECTS cliprects from the given command
- * buffer, starting with index n.
- */
-static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf, int n)
-{
- struct drm_clip_rect box;
- int nr;
- int i;
- RING_LOCALS;
-
- nr = cmdbuf->nbox - n;
- if (nr > R300_SIMULTANEOUS_CLIPRECTS)
- nr = R300_SIMULTANEOUS_CLIPRECTS;
-
- DRM_DEBUG("%i cliprects\n", nr);
-
- if (nr) {
- BEGIN_RING(6 + nr * 2);
- OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1));
-
- for (i = 0; i < nr; ++i) {
- if (copy_from_user
- (&box, &cmdbuf->boxes[n + i], sizeof(box))) {
- DRM_ERROR("copy cliprect faulted\n");
- return -EFAULT;
- }
-
- box.x2--; /* Hardware expects inclusive bottom-right corner */
- box.y2--;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
- box.x1 = (box.x1) &
- R300_CLIPRECT_MASK;
- box.y1 = (box.y1) &
- R300_CLIPRECT_MASK;
- box.x2 = (box.x2) &
- R300_CLIPRECT_MASK;
- box.y2 = (box.y2) &
- R300_CLIPRECT_MASK;
- } else {
- box.x1 = (box.x1 + R300_CLIPRECT_OFFSET) &
- R300_CLIPRECT_MASK;
- box.y1 = (box.y1 + R300_CLIPRECT_OFFSET) &
- R300_CLIPRECT_MASK;
- box.x2 = (box.x2 + R300_CLIPRECT_OFFSET) &
- R300_CLIPRECT_MASK;
- box.y2 = (box.y2 + R300_CLIPRECT_OFFSET) &
- R300_CLIPRECT_MASK;
- }
-
- OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
- (box.y1 << R300_CLIPRECT_Y_SHIFT));
- OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
- (box.y2 << R300_CLIPRECT_Y_SHIFT));
-
- }
-
- OUT_RING_REG(R300_RE_CLIPRECT_CNTL, r300_cliprect_cntl[nr - 1]);
-
- /* TODO/SECURITY: Force scissors to a safe value, otherwise the
- * client might be able to trample over memory.
- * The impact should be very limited, but I'd rather be safe than
- * sorry.
- */
- OUT_RING(CP_PACKET0(R300_RE_SCISSORS_TL, 1));
- OUT_RING(0);
- OUT_RING(R300_SCISSORS_X_MASK | R300_SCISSORS_Y_MASK);
- ADVANCE_RING();
- } else {
- /* Why we allow zero cliprect rendering:
- * There are some commands in a command buffer that must be submitted
- * even when there are no cliprects, e.g. DMA buffer discard
- * or state setting (though state setting could be avoided by
- * simulating a loss of context).
- *
- * Now since the cmdbuf interface is so chaotic right now (and is
- * bound to remain that way for a bit until things settle down),
- * it is basically impossible to filter out the commands that are
- * necessary and those that aren't.
- *
- * So I choose the safe way and don't do any filtering at all;
- * instead, I simply set up the engine so that all rendering
- * can't produce any fragments.
- */
- BEGIN_RING(2);
- OUT_RING_REG(R300_RE_CLIPRECT_CNTL, 0);
- ADVANCE_RING();
- }
-
- /* flus cache and wait idle clean after cliprect change */
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- OUT_RING(R300_RB3D_DC_FLUSH);
- ADVANCE_RING();
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_RING(RADEON_WAIT_3D_IDLECLEAN);
- ADVANCE_RING();
- /* set flush flag */
- dev_priv->track_flush |= RADEON_FLUSH_EMITED;
-
- return 0;
-}
-
-static u8 r300_reg_flags[0x10000 >> 2];
-
-void r300_init_reg_flags(struct drm_device *dev)
-{
- int i;
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- memset(r300_reg_flags, 0, 0x10000 >> 2);
-#define ADD_RANGE_MARK(reg, count,mark) \
- for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\
- r300_reg_flags[i]|=(mark);
-
-#define MARK_SAFE 1
-#define MARK_CHECK_OFFSET 2
-
-#define ADD_RANGE(reg, count) ADD_RANGE_MARK(reg, count, MARK_SAFE)
-
- /* these match cmducs() command in r300_driver/r300/r300_cmdbuf.c */
- ADD_RANGE(R300_SE_VPORT_XSCALE, 6);
- ADD_RANGE(R300_VAP_CNTL, 1);
- ADD_RANGE(R300_SE_VTE_CNTL, 2);
- ADD_RANGE(0x2134, 2);
- ADD_RANGE(R300_VAP_CNTL_STATUS, 1);
- ADD_RANGE(R300_VAP_INPUT_CNTL_0, 2);
- ADD_RANGE(0x21DC, 1);
- ADD_RANGE(R300_VAP_UNKNOWN_221C, 1);
- ADD_RANGE(R300_VAP_CLIP_X_0, 4);
- ADD_RANGE(R300_VAP_PVS_STATE_FLUSH_REG, 1);
- ADD_RANGE(R300_VAP_UNKNOWN_2288, 1);
- ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);
- ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
- ADD_RANGE(R300_GB_ENABLE, 1);
- ADD_RANGE(R300_GB_MSPOS0, 5);
- ADD_RANGE(R300_TX_INVALTAGS, 1);
- ADD_RANGE(R300_TX_ENABLE, 1);
- ADD_RANGE(0x4200, 4);
- ADD_RANGE(0x4214, 1);
- ADD_RANGE(R300_RE_POINTSIZE, 1);
- ADD_RANGE(0x4230, 3);
- ADD_RANGE(R300_RE_LINE_CNT, 1);
- ADD_RANGE(R300_RE_UNK4238, 1);
- ADD_RANGE(0x4260, 3);
- ADD_RANGE(R300_RE_SHADE, 4);
- ADD_RANGE(R300_RE_POLYGON_MODE, 5);
- ADD_RANGE(R300_RE_ZBIAS_CNTL, 1);
- ADD_RANGE(R300_RE_ZBIAS_T_FACTOR, 4);
- ADD_RANGE(R300_RE_OCCLUSION_CNTL, 1);
- ADD_RANGE(R300_RE_CULL_CNTL, 1);
- ADD_RANGE(0x42C0, 2);
- ADD_RANGE(R300_RS_CNTL_0, 2);
-
- ADD_RANGE(R300_SU_REG_DEST, 1);
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530)
- ADD_RANGE(RV530_FG_ZBREG_DEST, 1);
-
- ADD_RANGE(R300_SC_HYPERZ, 2);
- ADD_RANGE(0x43E8, 1);
-
- ADD_RANGE(0x46A4, 5);
-
- ADD_RANGE(R300_RE_FOG_STATE, 1);
- ADD_RANGE(R300_FOG_COLOR_R, 3);
- ADD_RANGE(R300_PP_ALPHA_TEST, 2);
- ADD_RANGE(0x4BD8, 1);
- ADD_RANGE(R300_PFS_PARAM_0_X, 64);
- ADD_RANGE(0x4E00, 1);
- ADD_RANGE(R300_RB3D_CBLEND, 2);
- ADD_RANGE(R300_RB3D_COLORMASK, 1);
- ADD_RANGE(R300_RB3D_BLEND_COLOR, 3);
- ADD_RANGE_MARK(R300_RB3D_COLOROFFSET0, 1, MARK_CHECK_OFFSET); /* check offset */
- ADD_RANGE(R300_RB3D_COLORPITCH0, 1);
- ADD_RANGE(0x4E50, 9);
- ADD_RANGE(0x4E88, 1);
- ADD_RANGE(0x4EA0, 2);
- ADD_RANGE(R300_ZB_CNTL, 3);
- ADD_RANGE(R300_ZB_FORMAT, 4);
- ADD_RANGE_MARK(R300_ZB_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
- ADD_RANGE(R300_ZB_DEPTHPITCH, 1);
- ADD_RANGE(R300_ZB_DEPTHCLEARVALUE, 1);
- ADD_RANGE(R300_ZB_ZMASK_OFFSET, 13);
- ADD_RANGE(R300_ZB_ZPASS_DATA, 2); /* ZB_ZPASS_DATA, ZB_ZPASS_ADDR */
-
- ADD_RANGE(R300_TX_FILTER_0, 16);
- ADD_RANGE(R300_TX_FILTER1_0, 16);
- ADD_RANGE(R300_TX_SIZE_0, 16);
- ADD_RANGE(R300_TX_FORMAT_0, 16);
- ADD_RANGE(R300_TX_PITCH_0, 16);
- /* Texture offset is dangerous and needs more checking */
- ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
- ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);
- ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
-
- /* Sporadic registers used as primitives are emitted */
- ADD_RANGE(R300_ZB_ZCACHE_CTLSTAT, 1);
- ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
- ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
- ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
- ADD_RANGE(R500_VAP_INDEX_OFFSET, 1);
- ADD_RANGE(R500_US_CONFIG, 2);
- ADD_RANGE(R500_US_CODE_ADDR, 3);
- ADD_RANGE(R500_US_FC_CTRL, 1);
- ADD_RANGE(R500_RS_IP_0, 16);
- ADD_RANGE(R500_RS_INST_0, 16);
- ADD_RANGE(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2);
- ADD_RANGE(R500_RB3D_CONSTANT_COLOR_AR, 2);
- ADD_RANGE(R500_ZB_FIFO_SIZE, 2);
- } else {
- ADD_RANGE(R300_PFS_CNTL_0, 3);
- ADD_RANGE(R300_PFS_NODE_0, 4);
- ADD_RANGE(R300_PFS_TEXI_0, 64);
- ADD_RANGE(R300_PFS_INSTR0_0, 64);
- ADD_RANGE(R300_PFS_INSTR1_0, 64);
- ADD_RANGE(R300_PFS_INSTR2_0, 64);
- ADD_RANGE(R300_PFS_INSTR3_0, 64);
- ADD_RANGE(R300_RS_INTERP_0, 8);
- ADD_RANGE(R300_RS_ROUTE_0, 8);
-
- }
-}
-
-static __inline__ int r300_check_range(unsigned reg, int count)
-{
- int i;
- if (reg & ~0xffff)
- return -1;
- for (i = (reg >> 2); i < (reg >> 2) + count; i++)
- if (r300_reg_flags[i] != MARK_SAFE)
- return 1;
- return 0;
-}
-
-static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
- dev_priv,
- drm_radeon_kcmd_buffer_t
- * cmdbuf,
- drm_r300_cmd_header_t
- header)
-{
- int reg;
- int sz;
- int i;
- u32 *value;
- RING_LOCALS;
-
- sz = header.packet0.count;
- reg = (header.packet0.reghi << 8) | header.packet0.reglo;
-
- if ((sz > 64) || (sz < 0)) {
- DRM_ERROR("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
- reg, sz);
- return -EINVAL;
- }
-
- for (i = 0; i < sz; i++) {
- switch (r300_reg_flags[(reg >> 2) + i]) {
- case MARK_SAFE:
- break;
- case MARK_CHECK_OFFSET:
- value = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
- if (!radeon_check_offset(dev_priv, *value)) {
- DRM_ERROR("Offset failed range check (reg=%04x sz=%d)\n",
- reg, sz);
- return -EINVAL;
- }
- break;
- default:
- DRM_ERROR("Register %04x failed check as flag=%02x\n",
- reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
- return -EINVAL;
- }
- }
-
- BEGIN_RING(1 + sz);
- OUT_RING(CP_PACKET0(reg, sz - 1));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
-
- return 0;
-}
-
-/**
- * Emits a packet0 setting arbitrary registers.
- * Called by r300_do_cp_cmdbuf.
- *
- * Note that checks are performed on contents and addresses of the registers
- */
-static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- drm_r300_cmd_header_t header)
-{
- int reg;
- int sz;
- RING_LOCALS;
-
- sz = header.packet0.count;
- reg = (header.packet0.reghi << 8) | header.packet0.reglo;
-
- if (!sz)
- return 0;
-
- if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
- return -EINVAL;
-
- if (reg + sz * 4 >= 0x10000) {
- DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg,
- sz);
- return -EINVAL;
- }
-
- if (r300_check_range(reg, sz)) {
- /* go and check everything */
- return r300_emit_carefully_checked_packet0(dev_priv, cmdbuf,
- header);
- }
- /* the rest of the data is safe to emit, whatever the values the user passed */
-
- BEGIN_RING(1 + sz);
- OUT_RING(CP_PACKET0(reg, sz - 1));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
-
- return 0;
-}
-
-/**
- * Uploads user-supplied vertex program instructions or parameters onto
- * the graphics card.
- * Called by r300_do_cp_cmdbuf.
- */
-static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- drm_r300_cmd_header_t header)
-{
- int sz;
- int addr;
- RING_LOCALS;
-
- sz = header.vpu.count;
- addr = (header.vpu.adrhi << 8) | header.vpu.adrlo;
-
- if (!sz)
- return 0;
- if (sz * 16 > drm_buffer_unprocessed(cmdbuf->buffer))
- return -EINVAL;
-
- /* VAP is very sensitive so we purge cache before we program it
- * and we also flush its state before & after */
- BEGIN_RING(6);
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- OUT_RING(R300_RB3D_DC_FLUSH);
- OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_RING(RADEON_WAIT_3D_IDLECLEAN);
- OUT_RING(CP_PACKET0(R300_VAP_PVS_STATE_FLUSH_REG, 0));
- OUT_RING(0);
- ADVANCE_RING();
- /* set flush flag */
- dev_priv->track_flush |= RADEON_FLUSH_EMITED;
-
- BEGIN_RING(3 + sz * 4);
- OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr);
- OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz * 4);
- ADVANCE_RING();
-
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_VAP_PVS_STATE_FLUSH_REG, 0));
- OUT_RING(0);
- ADVANCE_RING();
-
- return 0;
-}
-
-/**
- * Emit a clear packet from userspace.
- * Called by r300_emit_packet3.
- */
-static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- RING_LOCALS;
-
- if (8 * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
- return -EINVAL;
-
- BEGIN_RING(10);
- OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
- OUT_RING(R300_PRIM_TYPE_POINT | R300_PRIM_WALK_RING |
- (1 << R300_PRIM_NUM_VERTICES_SHIFT));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, 8);
- ADVANCE_RING();
-
- BEGIN_RING(4);
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- OUT_RING(R300_RB3D_DC_FLUSH);
- OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_RING(RADEON_WAIT_3D_IDLECLEAN);
- ADVANCE_RING();
- /* set flush flag */
- dev_priv->track_flush |= RADEON_FLUSH_EMITED;
-
- return 0;
-}
-
-static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- u32 header)
-{
- int count, i, k;
-#define MAX_ARRAY_PACKET 64
- u32 *data;
- u32 narrays;
- RING_LOCALS;
-
- count = (header & RADEON_CP_PACKET_COUNT_MASK) >> 16;
-
- if ((count + 1) > MAX_ARRAY_PACKET) {
- DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
- count);
- return -EINVAL;
- }
- /* carefully check packet contents */
-
- /* We have already read the header so advance the buffer. */
- drm_buffer_advance(cmdbuf->buffer, 4);
-
- narrays = *(u32 *)drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
- k = 0;
- i = 1;
- while ((k < narrays) && (i < (count + 1))) {
- i++; /* skip attribute field */
- data = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
- if (!radeon_check_offset(dev_priv, *data)) {
- DRM_ERROR
- ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
- k, i);
- return -EINVAL;
- }
- k++;
- i++;
- if (k == narrays)
- break;
- /* have one more to process, they come in pairs */
- data = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
- if (!radeon_check_offset(dev_priv, *data)) {
- DRM_ERROR
- ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
- k, i);
- return -EINVAL;
- }
- k++;
- i++;
- }
- /* do the counts match what we expect ? */
- if ((k != narrays) || (i != (count + 1))) {
- DRM_ERROR
- ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
- k, i, narrays, count + 1);
- return -EINVAL;
- }
-
- /* all clear, output packet */
-
- BEGIN_RING(count + 2);
- OUT_RING(header);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 1);
- ADVANCE_RING();
-
- return 0;
-}
-
-static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
- int count, ret;
- RING_LOCALS;
-
-
- count = (*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16;
-
- if (*cmd & 0x8000) {
- u32 offset;
- u32 *cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
- if (*cmd1 & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
- | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
-
- u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
- offset = *cmd2 << 10;
- ret = !radeon_check_offset(dev_priv, offset);
- if (ret) {
- DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
- return -EINVAL;
- }
- }
-
- if ((*cmd1 & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
- (*cmd1 & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
- offset = *cmd3 << 10;
- ret = !radeon_check_offset(dev_priv, offset);
- if (ret) {
- DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
- return -EINVAL;
- }
-
- }
- }
-
- BEGIN_RING(count+2);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
- ADVANCE_RING();
-
- return 0;
-}
-
-static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
- u32 *cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
- int count;
- int expected_count;
- RING_LOCALS;
-
- count = (*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16;
-
- expected_count = *cmd1 >> 16;
- if (!(*cmd1 & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
- expected_count = (expected_count+1)/2;
-
- if (count && count != expected_count) {
- DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n",
- count, expected_count);
- return -EINVAL;
- }
-
- BEGIN_RING(count+2);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
- ADVANCE_RING();
-
- if (!count) {
- drm_r300_cmd_header_t stack_header, *header;
- u32 *cmd1, *cmd2, *cmd3;
-
- if (drm_buffer_unprocessed(cmdbuf->buffer)
- < 4*4 + sizeof(stack_header)) {
- DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
- return -EINVAL;
- }
-
- header = drm_buffer_read_object(cmdbuf->buffer,
- sizeof(stack_header), &stack_header);
-
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
- cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
- cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
- cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
-
- if (header->header.cmd_type != R300_CMD_PACKET3 ||
- header->packet3.packet != R300_CMD_PACKET3_RAW ||
- *cmd != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
- DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
- return -EINVAL;
- }
-
- if ((*cmd1 & 0x8000ffff) != 0x80000810) {
- DRM_ERROR("Invalid indx_buffer reg address %08X\n",
- *cmd1);
- return -EINVAL;
- }
- if (!radeon_check_offset(dev_priv, *cmd2)) {
- DRM_ERROR("Invalid indx_buffer offset is %08X\n",
- *cmd2);
- return -EINVAL;
- }
- if (*cmd3 != expected_count) {
- DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
- *cmd3, expected_count);
- return -EINVAL;
- }
-
- BEGIN_RING(4);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, 4);
- ADVANCE_RING();
- }
-
- return 0;
-}
-
-static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- u32 *header;
- int count;
- RING_LOCALS;
-
- if (4 > drm_buffer_unprocessed(cmdbuf->buffer))
- return -EINVAL;
-
- /* Fixme !! This simply emits a packet without much checking.
- We need to be smarter. */
-
- /* obtain first word - actual packet3 header */
- header = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
-
- /* Is it packet 3 ? */
- if ((*header >> 30) != 0x3) {
- DRM_ERROR("Not a packet3 header (0x%08x)\n", *header);
- return -EINVAL;
- }
-
- count = (*header >> 16) & 0x3fff;
-
- /* Check again now that we know how much data to expect */
- if ((count + 2) * 4 > drm_buffer_unprocessed(cmdbuf->buffer)) {
- DRM_ERROR
- ("Expected packet3 of length %d but have only %d bytes left\n",
- (count + 2) * 4, drm_buffer_unprocessed(cmdbuf->buffer));
- return -EINVAL;
- }
-
- /* Is it a packet type we know about ? */
- switch (*header & 0xff00) {
- case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
- return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, *header);
-
- case RADEON_CNTL_BITBLT_MULTI:
- return r300_emit_bitblt_multi(dev_priv, cmdbuf);
-
- case RADEON_CP_INDX_BUFFER:
- DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n");
- return -EINVAL;
- case RADEON_CP_3D_DRAW_IMMD_2:
- /* triggers drawing using in-packet vertex data */
- case RADEON_CP_3D_DRAW_VBUF_2:
- /* triggers drawing of vertex buffers setup elsewhere */
- dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
- RADEON_PURGE_EMITED);
- break;
- case RADEON_CP_3D_DRAW_INDX_2:
- /* triggers drawing using indices to vertex buffer */
- /* whenever we send vertex we clear flush & purge */
- dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
- RADEON_PURGE_EMITED);
- return r300_emit_draw_indx_2(dev_priv, cmdbuf);
- case RADEON_WAIT_FOR_IDLE:
- case RADEON_CP_NOP:
- /* these packets are safe */
- break;
- default:
- DRM_ERROR("Unknown packet3 header (0x%08x)\n", *header);
- return -EINVAL;
- }
-
- BEGIN_RING(count + 2);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
- ADVANCE_RING();
-
- return 0;
-}
-
-/**
- * Emit a rendering packet3 from userspace.
- * Called by r300_do_cp_cmdbuf.
- */
-static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- drm_r300_cmd_header_t header)
-{
- int n;
- int ret;
- int orig_iter = cmdbuf->buffer->iterator;
-
- /* This is a do-while-loop so that we run the interior at least once,
- * even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale.
- */
- n = 0;
- do {
- if (cmdbuf->nbox > R300_SIMULTANEOUS_CLIPRECTS) {
- ret = r300_emit_cliprects(dev_priv, cmdbuf, n);
- if (ret)
- return ret;
-
- cmdbuf->buffer->iterator = orig_iter;
- }
-
- switch (header.packet3.packet) {
- case R300_CMD_PACKET3_CLEAR:
- DRM_DEBUG("R300_CMD_PACKET3_CLEAR\n");
- ret = r300_emit_clear(dev_priv, cmdbuf);
- if (ret) {
- DRM_ERROR("r300_emit_clear failed\n");
- return ret;
- }
- break;
-
- case R300_CMD_PACKET3_RAW:
- DRM_DEBUG("R300_CMD_PACKET3_RAW\n");
- ret = r300_emit_raw_packet3(dev_priv, cmdbuf);
- if (ret) {
- DRM_ERROR("r300_emit_raw_packet3 failed\n");
- return ret;
- }
- break;
-
- default:
- DRM_ERROR("bad packet3 type %i at byte %d\n",
- header.packet3.packet,
- cmdbuf->buffer->iterator - (int)sizeof(header));
- return -EINVAL;
- }
-
- n += R300_SIMULTANEOUS_CLIPRECTS;
- } while (n < cmdbuf->nbox);
-
- return 0;
-}
-
-/* Some of the R300 chips seem to be extremely touchy about the two registers
- * that are configured in r300_pacify.
- * Among the worst offenders seems to be the R300 ND (0x4E44): When userspace
- * sends a command buffer that contains only state setting commands and a
- * vertex program/parameter upload sequence, this will eventually lead to a
- * lockup, unless the sequence is bracketed by calls to r300_pacify.
- * So we should take great care to *always* call r300_pacify before
- * *anything* 3D related, and again afterwards. This is what the
- * call bracket in r300_do_cp_cmdbuf is for.
- */
-
-/**
- * Emit the sequence to pacify R300.
- */
-static void r300_pacify(drm_radeon_private_t *dev_priv)
-{
- uint32_t cache_z, cache_3d, cache_2d;
- RING_LOCALS;
-
- cache_z = R300_ZC_FLUSH;
- cache_2d = R300_RB2D_DC_FLUSH;
- cache_3d = R300_RB3D_DC_FLUSH;
- if (!(dev_priv->track_flush & RADEON_PURGE_EMITED)) {
- /* we can purge, primitive where draw since last purge */
- cache_z |= R300_ZC_FREE;
- cache_2d |= R300_RB2D_DC_FREE;
- cache_3d |= R300_RB3D_DC_FREE;
- }
-
- /* flush & purge zbuffer */
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0));
- OUT_RING(cache_z);
- ADVANCE_RING();
- /* flush & purge 3d */
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- OUT_RING(cache_3d);
- ADVANCE_RING();
- /* flush & purge texture */
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_TX_INVALTAGS, 0));
- OUT_RING(0);
- ADVANCE_RING();
- /* FIXME: is this one really needed ? */
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_RB3D_AARESOLVE_CTL, 0));
- OUT_RING(0);
- ADVANCE_RING();
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_RING(RADEON_WAIT_3D_IDLECLEAN);
- ADVANCE_RING();
- /* flush & purge 2d through E2 as RB2D will trigger lockup */
- BEGIN_RING(4);
- OUT_RING(CP_PACKET0(R300_DSTCACHE_CTLSTAT, 0));
- OUT_RING(cache_2d);
- OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_RING(RADEON_WAIT_2D_IDLECLEAN |
- RADEON_WAIT_HOST_IDLECLEAN);
- ADVANCE_RING();
- /* set flush & purge flags */
- dev_priv->track_flush |= RADEON_FLUSH_EMITED | RADEON_PURGE_EMITED;
-}
-
-/**
- * Called by r300_do_cp_cmdbuf to update the internal buffer age and state.
- * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
- * be careful about how this function is called.
- */
-static void r300_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf)
-{
- drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
-
- buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
- buf->pending = 1;
- buf->used = 0;
-}
-
-static void r300_cmd_wait(drm_radeon_private_t * dev_priv,
- drm_r300_cmd_header_t header)
-{
- u32 wait_until;
- RING_LOCALS;
-
- if (!header.wait.flags)
- return;
-
- wait_until = 0;
-
- switch(header.wait.flags) {
- case R300_WAIT_2D:
- wait_until = RADEON_WAIT_2D_IDLE;
- break;
- case R300_WAIT_3D:
- wait_until = RADEON_WAIT_3D_IDLE;
- break;
- case R300_NEW_WAIT_2D_3D:
- wait_until = RADEON_WAIT_2D_IDLE|RADEON_WAIT_3D_IDLE;
- break;
- case R300_NEW_WAIT_2D_2D_CLEAN:
- wait_until = RADEON_WAIT_2D_IDLE|RADEON_WAIT_2D_IDLECLEAN;
- break;
- case R300_NEW_WAIT_3D_3D_CLEAN:
- wait_until = RADEON_WAIT_3D_IDLE|RADEON_WAIT_3D_IDLECLEAN;
- break;
- case R300_NEW_WAIT_2D_2D_CLEAN_3D_3D_CLEAN:
- wait_until = RADEON_WAIT_2D_IDLE|RADEON_WAIT_2D_IDLECLEAN;
- wait_until |= RADEON_WAIT_3D_IDLE|RADEON_WAIT_3D_IDLECLEAN;
- break;
- default:
- return;
- }
-
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_RING(wait_until);
- ADVANCE_RING();
-}
-
-static int r300_scratch(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- drm_r300_cmd_header_t header)
-{
- u32 *ref_age_base;
- u32 i, *buf_idx, h_pending;
- u64 *ptr_addr;
- u64 stack_ptr_addr;
- RING_LOCALS;
-
- if (drm_buffer_unprocessed(cmdbuf->buffer) <
- (sizeof(u64) + header.scratch.n_bufs * sizeof(*buf_idx))) {
- return -EINVAL;
- }
-
- if (header.scratch.reg >= 5) {
- return -EINVAL;
- }
-
- dev_priv->scratch_ages[header.scratch.reg]++;
-
- ptr_addr = drm_buffer_read_object(cmdbuf->buffer,
- sizeof(stack_ptr_addr), &stack_ptr_addr);
- ref_age_base = (u32 *)(unsigned long)get_unaligned(ptr_addr);
-
- for (i=0; i < header.scratch.n_bufs; i++) {
- buf_idx = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
- *buf_idx *= 2; /* 8 bytes per buf */
-
- if (copy_to_user(ref_age_base + *buf_idx,
- &dev_priv->scratch_ages[header.scratch.reg],
- sizeof(u32)))
- return -EINVAL;
-
- if (copy_from_user(&h_pending,
- ref_age_base + *buf_idx + 1,
- sizeof(u32)))
- return -EINVAL;
-
- if (h_pending == 0)
- return -EINVAL;
-
- h_pending--;
-
- if (copy_to_user(ref_age_base + *buf_idx + 1,
- &h_pending,
- sizeof(u32)))
- return -EINVAL;
-
- drm_buffer_advance(cmdbuf->buffer, sizeof(*buf_idx));
- }
-
- BEGIN_RING(2);
- OUT_RING( CP_PACKET0( RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0 ) );
- OUT_RING( dev_priv->scratch_ages[header.scratch.reg] );
- ADVANCE_RING();
-
- return 0;
-}
-
-/**
- * Uploads user-supplied vertex program instructions or parameters onto
- * the graphics card.
- * Called by r300_do_cp_cmdbuf.
- */
-static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- drm_r300_cmd_header_t header)
-{
- int sz;
- int addr;
- int type;
- int isclamp;
- int stride;
- RING_LOCALS;
-
- sz = header.r500fp.count;
- /* address is 9 bits 0 - 8, bit 1 of flags is part of address */
- addr = ((header.r500fp.adrhi_flags & 1) << 8) | header.r500fp.adrlo;
-
- type = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_TYPE);
- isclamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
-
- addr |= (type << 16);
- addr |= (isclamp << 17);
-
- stride = type ? 4 : 6;
-
- DRM_DEBUG("r500fp %d %d type: %d\n", sz, addr, type);
- if (!sz)
- return 0;
- if (sz * stride * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
- return -EINVAL;
-
- BEGIN_RING(3 + sz * stride);
- OUT_RING_REG(R500_GA_US_VECTOR_INDEX, addr);
- OUT_RING(CP_PACKET0_TABLE(R500_GA_US_VECTOR_DATA, sz * stride - 1));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz * stride);
-
- ADVANCE_RING();
-
- return 0;
-}
-
-
-/**
- * Parses and validates a user-supplied command buffer and emits appropriate
- * commands on the DMA ring buffer.
- * Called by the ioctl handler function radeon_cp_cmdbuf.
- */
-int r300_do_cp_cmdbuf(struct drm_device *dev,
- struct drm_file *file_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf = NULL;
- int emit_dispatch_age = 0;
- int ret = 0;
-
- DRM_DEBUG("\n");
-
- /* pacify */
- r300_pacify(dev_priv);
-
- if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) {
- ret = r300_emit_cliprects(dev_priv, cmdbuf, 0);
- if (ret)
- goto cleanup;
- }
-
- while (drm_buffer_unprocessed(cmdbuf->buffer)
- >= sizeof(drm_r300_cmd_header_t)) {
- int idx;
- drm_r300_cmd_header_t *header, stack_header;
-
- header = drm_buffer_read_object(cmdbuf->buffer,
- sizeof(stack_header), &stack_header);
-
- switch (header->header.cmd_type) {
- case R300_CMD_PACKET0:
- DRM_DEBUG("R300_CMD_PACKET0\n");
- ret = r300_emit_packet0(dev_priv, cmdbuf, *header);
- if (ret) {
- DRM_ERROR("r300_emit_packet0 failed\n");
- goto cleanup;
- }
- break;
-
- case R300_CMD_VPU:
- DRM_DEBUG("R300_CMD_VPU\n");
- ret = r300_emit_vpu(dev_priv, cmdbuf, *header);
- if (ret) {
- DRM_ERROR("r300_emit_vpu failed\n");
- goto cleanup;
- }
- break;
-
- case R300_CMD_PACKET3:
- DRM_DEBUG("R300_CMD_PACKET3\n");
- ret = r300_emit_packet3(dev_priv, cmdbuf, *header);
- if (ret) {
- DRM_ERROR("r300_emit_packet3 failed\n");
- goto cleanup;
- }
- break;
-
- case R300_CMD_END3D:
- DRM_DEBUG("R300_CMD_END3D\n");
- /* TODO:
- Ideally userspace driver should not need to issue this call,
- i.e. the drm driver should issue it automatically and prevent
- lockups.
-
- In practice, we do not understand why this call is needed and what
- it does (except for some vague guesses that it has to do with cache
- coherence) and so the user space driver does it.
-
- Once we are sure which uses prevent lockups the code could be moved
- into the kernel and the userspace driver will not
- need to use this command.
-
- Note that issuing this command does not hurt anything
- except, possibly, performance */
- r300_pacify(dev_priv);
- break;
-
- case R300_CMD_CP_DELAY:
- /* simple enough, we can do it here */
- DRM_DEBUG("R300_CMD_CP_DELAY\n");
- {
- int i;
- RING_LOCALS;
-
- BEGIN_RING(header->delay.count);
- for (i = 0; i < header->delay.count; i++)
- OUT_RING(RADEON_CP_PACKET2);
- ADVANCE_RING();
- }
- break;
-
- case R300_CMD_DMA_DISCARD:
- DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
- idx = header->dma.buf_idx;
- if (idx < 0 || idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- idx, dma->buf_count - 1);
- ret = -EINVAL;
- goto cleanup;
- }
-
- buf = dma->buflist[idx];
- if (buf->file_priv != file_priv || buf->pending) {
- DRM_ERROR("bad buffer %p %p %d\n",
- buf->file_priv, file_priv,
- buf->pending);
- ret = -EINVAL;
- goto cleanup;
- }
-
- emit_dispatch_age = 1;
- r300_discard_buffer(dev, file_priv->master, buf);
- break;
-
- case R300_CMD_WAIT:
- DRM_DEBUG("R300_CMD_WAIT\n");
- r300_cmd_wait(dev_priv, *header);
- break;
-
- case R300_CMD_SCRATCH:
- DRM_DEBUG("R300_CMD_SCRATCH\n");
- ret = r300_scratch(dev_priv, cmdbuf, *header);
- if (ret) {
- DRM_ERROR("r300_scratch failed\n");
- goto cleanup;
- }
- break;
-
- case R300_CMD_R500FP:
- if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
- DRM_ERROR("Calling r500 command on r300 card\n");
- ret = -EINVAL;
- goto cleanup;
- }
- DRM_DEBUG("R300_CMD_R500FP\n");
- ret = r300_emit_r500fp(dev_priv, cmdbuf, *header);
- if (ret) {
- DRM_ERROR("r300_emit_r500fp failed\n");
- goto cleanup;
- }
- break;
- default:
- DRM_ERROR("bad cmd_type %i at byte %d\n",
- header->header.cmd_type,
- cmdbuf->buffer->iterator - (int)sizeof(*header));
- ret = -EINVAL;
- goto cleanup;
- }
- }
-
- DRM_DEBUG("END\n");
-
- cleanup:
- r300_pacify(dev_priv);
-
- /* We emit the vertex buffer age here, outside the pacifier "brackets"
- * for two reasons:
- * (1) This may coalesce multiple age emissions into a single one and
- * (2) more importantly, some chips lock up hard when scratch registers
- * are written inside the pacifier bracket.
- */
- if (emit_dispatch_age) {
- RING_LOCALS;
-
- /* Emit the vertex buffer age */
- BEGIN_RING(2);
- RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch);
- ADVANCE_RING();
- }
-
- COMMIT_RING();
-
- return ret;
-}
diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c
deleted file mode 100644
index daf7572be976..000000000000
--- a/drivers/gpu/drm/radeon/r600_blit.c
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * Copyright 2009 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 (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Alex Deucher <alexander.deucher@amd.com>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-
-#include "r600_blit_shaders.h"
-
-/* 23 bits of float fractional data */
-#define I2F_FRAC_BITS 23
-#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1)
-
-/*
- * Converts unsigned integer into 32-bit IEEE floating point representation.
- * Will be exact from 0 to 2^24. Above that, we round towards zero
- * as the fractional bits will not fit in a float. (It would be better to
- * round towards even as the fpu does, but that is slower.)
- */
-static __pure uint32_t int2float(uint32_t x)
-{
- uint32_t msb, exponent, fraction;
-
- /* Zero is special */
- if (!x) return 0;
-
- /* Get location of the most significant bit */
- msb = __fls(x);
-
- /*
- * Use a rotate instead of a shift because that works both leftwards
- * and rightwards due to the mod(32) behaviour. This means we don't
- * need to check to see if we are above 2^24 or not.
- */
- fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK;
- exponent = (127 + msb) << I2F_FRAC_BITS;
-
- return fraction + exponent;
-}
-
-#define DI_PT_RECTLIST 0x11
-#define DI_INDEX_SIZE_16_BIT 0x0
-#define DI_SRC_SEL_AUTO_INDEX 0x2
-
-#define FMT_8 0x1
-#define FMT_5_6_5 0x8
-#define FMT_8_8_8_8 0x1a
-#define COLOR_8 0x1
-#define COLOR_5_6_5 0x8
-#define COLOR_8_8_8_8 0x1a
-
-static void
-set_render_target(drm_radeon_private_t *dev_priv, int format, int w, int h, u64 gpu_addr)
-{
- u32 cb_color_info;
- int pitch, slice;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- h = ALIGN(h, 8);
- if (h < 8)
- h = 8;
-
- cb_color_info = ((format << 2) | (1 << 27));
- pitch = (w / 8) - 1;
- slice = ((w * h) / 64) - 1;
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_R600) &&
- ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV770)) {
- BEGIN_RING(21 + 2);
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_BASE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(gpu_addr >> 8);
- OUT_RING(CP_PACKET3(R600_IT_SURFACE_BASE_UPDATE, 0));
- OUT_RING(2 << 0);
- } else {
- BEGIN_RING(21);
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_BASE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(gpu_addr >> 8);
- }
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_SIZE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING((pitch << 0) | (slice << 10));
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_VIEW - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(0);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_INFO - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(cb_color_info);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_TILE - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(0);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_FRAG - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(0);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_CB_COLOR0_MASK - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(0);
-
- ADVANCE_RING();
-}
-
-static void
-cp_set_surface_sync(drm_radeon_private_t *dev_priv,
- u32 sync_type, u32 size, u64 mc_addr)
-{
- u32 cp_coher_size;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- if (size == 0xffffffff)
- cp_coher_size = 0xffffffff;
- else
- cp_coher_size = ((size + 255) >> 8);
-
- BEGIN_RING(5);
- OUT_RING(CP_PACKET3(R600_IT_SURFACE_SYNC, 3));
- OUT_RING(sync_type);
- OUT_RING(cp_coher_size);
- OUT_RING((mc_addr >> 8));
- OUT_RING(10); /* poll interval */
- ADVANCE_RING();
-}
-
-static void
-set_shaders(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- u64 gpu_addr;
- int i;
- u32 *vs, *ps;
- uint32_t sq_pgm_resources;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- /* load shaders */
- vs = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset);
- ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256);
-
- for (i = 0; i < r6xx_vs_size; i++)
- vs[i] = cpu_to_le32(r6xx_vs[i]);
- for (i = 0; i < r6xx_ps_size; i++)
- ps[i] = cpu_to_le32(r6xx_ps[i]);
-
- dev_priv->blit_vb->used = 512;
-
- gpu_addr = dev_priv->gart_buffers_offset + dev_priv->blit_vb->offset;
-
- /* setup shader regs */
- sq_pgm_resources = (1 << 0);
-
- BEGIN_RING(9 + 12);
- /* VS */
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_START_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(gpu_addr >> 8);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_RESOURCES_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(sq_pgm_resources);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_CF_OFFSET_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(0);
-
- /* PS */
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_START_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING((gpu_addr + 256) >> 8);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_RESOURCES_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(sq_pgm_resources | (1 << 28));
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_EXPORTS_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(2);
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1));
- OUT_RING((R600_SQ_PGM_CF_OFFSET_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING(0);
- ADVANCE_RING();
-
- cp_set_surface_sync(dev_priv,
- R600_SH_ACTION_ENA, 512, gpu_addr);
-}
-
-static void
-set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr)
-{
- uint32_t sq_vtx_constant_word2;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8));
-#ifdef __BIG_ENDIAN
- sq_vtx_constant_word2 |= (2 << 30);
-#endif
-
- BEGIN_RING(9);
- OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
- OUT_RING(0x460);
- OUT_RING(gpu_addr & 0xffffffff);
- OUT_RING(48 - 1);
- OUT_RING(sq_vtx_constant_word2);
- OUT_RING(1 << 0);
- OUT_RING(0);
- OUT_RING(0);
- OUT_RING(R600_SQ_TEX_VTX_VALID_BUFFER << 30);
- ADVANCE_RING();
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710))
- cp_set_surface_sync(dev_priv,
- R600_TC_ACTION_ENA, 48, gpu_addr);
- else
- cp_set_surface_sync(dev_priv,
- R600_VC_ACTION_ENA, 48, gpu_addr);
-}
-
-static void
-set_tex_resource(drm_radeon_private_t *dev_priv,
- int format, int w, int h, int pitch, u64 gpu_addr)
-{
- uint32_t sq_tex_resource_word0, sq_tex_resource_word1, sq_tex_resource_word4;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- if (h < 1)
- h = 1;
-
- sq_tex_resource_word0 = (1 << 0);
- sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) |
- ((w - 1) << 19));
-
- sq_tex_resource_word1 = (format << 26);
- sq_tex_resource_word1 |= ((h - 1) << 0);
-
- sq_tex_resource_word4 = ((1 << 14) |
- (0 << 16) |
- (1 << 19) |
- (2 << 22) |
- (3 << 25));
-
- BEGIN_RING(9);
- OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
- OUT_RING(0);
- OUT_RING(sq_tex_resource_word0);
- OUT_RING(sq_tex_resource_word1);
- OUT_RING(gpu_addr >> 8);
- OUT_RING(gpu_addr >> 8);
- OUT_RING(sq_tex_resource_word4);
- OUT_RING(0);
- OUT_RING(R600_SQ_TEX_VTX_VALID_TEXTURE << 30);
- ADVANCE_RING();
-
-}
-
-static void
-set_scissors(drm_radeon_private_t *dev_priv, int x1, int y1, int x2, int y2)
-{
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(12);
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2));
- OUT_RING((R600_PA_SC_SCREEN_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING((x1 << 0) | (y1 << 16));
- OUT_RING((x2 << 0) | (y2 << 16));
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2));
- OUT_RING((R600_PA_SC_GENERIC_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING((x1 << 0) | (y1 << 16) | (1 << 31));
- OUT_RING((x2 << 0) | (y2 << 16));
-
- OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2));
- OUT_RING((R600_PA_SC_WINDOW_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2);
- OUT_RING((x1 << 0) | (y1 << 16) | (1 << 31));
- OUT_RING((x2 << 0) | (y2 << 16));
- ADVANCE_RING();
-}
-
-static void
-draw_auto(drm_radeon_private_t *dev_priv)
-{
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(10);
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));
- OUT_RING((R600_VGT_PRIMITIVE_TYPE - R600_SET_CONFIG_REG_OFFSET) >> 2);
- OUT_RING(DI_PT_RECTLIST);
-
- OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0));
-#ifdef __BIG_ENDIAN
- OUT_RING((2 << 2) | DI_INDEX_SIZE_16_BIT);
-#else
- OUT_RING(DI_INDEX_SIZE_16_BIT);
-#endif
-
- OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0));
- OUT_RING(1);
-
- OUT_RING(CP_PACKET3(R600_IT_DRAW_INDEX_AUTO, 1));
- OUT_RING(3);
- OUT_RING(DI_SRC_SEL_AUTO_INDEX);
-
- ADVANCE_RING();
- COMMIT_RING();
-}
-
-static void
-set_default_state(drm_radeon_private_t *dev_priv)
-{
- int i;
- u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2;
- u32 sq_thread_resource_mgmt, sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2;
- int num_ps_gprs, num_vs_gprs, num_temp_gprs, num_gs_gprs, num_es_gprs;
- int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads;
- int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
- RING_LOCALS;
-
- switch ((dev_priv->flags & RADEON_FAMILY_MASK)) {
- case CHIP_R600:
- num_ps_gprs = 192;
- num_vs_gprs = 56;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 136;
- num_vs_threads = 48;
- num_gs_threads = 4;
- num_es_threads = 4;
- num_ps_stack_entries = 128;
- num_vs_stack_entries = 128;
- num_gs_stack_entries = 0;
- num_es_stack_entries = 0;
- break;
- case CHIP_RV630:
- case CHIP_RV635:
- num_ps_gprs = 84;
- num_vs_gprs = 36;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 144;
- num_vs_threads = 40;
- num_gs_threads = 4;
- num_es_threads = 4;
- num_ps_stack_entries = 40;
- num_vs_stack_entries = 40;
- num_gs_stack_entries = 32;
- num_es_stack_entries = 16;
- break;
- case CHIP_RV610:
- case CHIP_RV620:
- case CHIP_RS780:
- case CHIP_RS880:
- default:
- num_ps_gprs = 84;
- num_vs_gprs = 36;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 136;
- num_vs_threads = 48;
- num_gs_threads = 4;
- num_es_threads = 4;
- num_ps_stack_entries = 40;
- num_vs_stack_entries = 40;
- num_gs_stack_entries = 32;
- num_es_stack_entries = 16;
- break;
- case CHIP_RV670:
- num_ps_gprs = 144;
- num_vs_gprs = 40;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 136;
- num_vs_threads = 48;
- num_gs_threads = 4;
- num_es_threads = 4;
- num_ps_stack_entries = 40;
- num_vs_stack_entries = 40;
- num_gs_stack_entries = 32;
- num_es_stack_entries = 16;
- break;
- case CHIP_RV770:
- num_ps_gprs = 192;
- num_vs_gprs = 56;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 188;
- num_vs_threads = 60;
- num_gs_threads = 0;
- num_es_threads = 0;
- num_ps_stack_entries = 256;
- num_vs_stack_entries = 256;
- num_gs_stack_entries = 0;
- num_es_stack_entries = 0;
- break;
- case CHIP_RV730:
- case CHIP_RV740:
- num_ps_gprs = 84;
- num_vs_gprs = 36;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 188;
- num_vs_threads = 60;
- num_gs_threads = 0;
- num_es_threads = 0;
- num_ps_stack_entries = 128;
- num_vs_stack_entries = 128;
- num_gs_stack_entries = 0;
- num_es_stack_entries = 0;
- break;
- case CHIP_RV710:
- num_ps_gprs = 192;
- num_vs_gprs = 56;
- num_temp_gprs = 4;
- num_gs_gprs = 0;
- num_es_gprs = 0;
- num_ps_threads = 144;
- num_vs_threads = 48;
- num_gs_threads = 0;
- num_es_threads = 0;
- num_ps_stack_entries = 128;
- num_vs_stack_entries = 128;
- num_gs_stack_entries = 0;
- num_es_stack_entries = 0;
- break;
- }
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710))
- sq_config = 0;
- else
- sq_config = R600_VC_ENABLE;
-
- sq_config |= (R600_DX9_CONSTS |
- R600_ALU_INST_PREFER_VECTOR |
- R600_PS_PRIO(0) |
- R600_VS_PRIO(1) |
- R600_GS_PRIO(2) |
- R600_ES_PRIO(3));
-
- sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(num_ps_gprs) |
- R600_NUM_VS_GPRS(num_vs_gprs) |
- R600_NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
- sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(num_gs_gprs) |
- R600_NUM_ES_GPRS(num_es_gprs));
- sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(num_ps_threads) |
- R600_NUM_VS_THREADS(num_vs_threads) |
- R600_NUM_GS_THREADS(num_gs_threads) |
- R600_NUM_ES_THREADS(num_es_threads));
- sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
- R600_NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
- sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
- R600_NUM_ES_STACK_ENTRIES(num_es_stack_entries));
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
- BEGIN_RING(r7xx_default_size + 10);
- for (i = 0; i < r7xx_default_size; i++)
- OUT_RING(r7xx_default_state[i]);
- } else {
- BEGIN_RING(r6xx_default_size + 10);
- for (i = 0; i < r6xx_default_size; i++)
- OUT_RING(r6xx_default_state[i]);
- }
- OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
- OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT);
- /* SQ config */
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 6));
- OUT_RING((R600_SQ_CONFIG - R600_SET_CONFIG_REG_OFFSET) >> 2);
- OUT_RING(sq_config);
- OUT_RING(sq_gpr_resource_mgmt_1);
- OUT_RING(sq_gpr_resource_mgmt_2);
- OUT_RING(sq_thread_resource_mgmt);
- OUT_RING(sq_stack_resource_mgmt_1);
- OUT_RING(sq_stack_resource_mgmt_2);
- ADVANCE_RING();
-}
-
-static int r600_nomm_get_vb(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- dev_priv->blit_vb = radeon_freelist_get(dev);
- if (!dev_priv->blit_vb) {
- DRM_ERROR("Unable to allocate vertex buffer for blit\n");
- return -EAGAIN;
- }
- return 0;
-}
-
-static void r600_nomm_put_vb(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- dev_priv->blit_vb->used = 0;
- radeon_cp_discard_buffer(dev, dev_priv->blit_vb->file_priv->master, dev_priv->blit_vb);
-}
-
-static void *r600_nomm_get_vb_ptr(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- return (((char *)dev->agp_buffer_map->handle +
- dev_priv->blit_vb->offset + dev_priv->blit_vb->used));
-}
-
-int
-r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- int ret;
- DRM_DEBUG("\n");
-
- ret = r600_nomm_get_vb(dev);
- if (ret)
- return ret;
-
- dev_priv->blit_vb->file_priv = file_priv;
-
- set_default_state(dev_priv);
- set_shaders(dev);
-
- return 0;
-}
-
-
-void
-r600_done_blit_copy(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(5);
- OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
- OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT);
- /* wait for 3D idle clean */
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));
- OUT_RING((R600_WAIT_UNTIL - R600_SET_CONFIG_REG_OFFSET) >> 2);
- OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_3D_IDLECLEAN);
-
- ADVANCE_RING();
- COMMIT_RING();
-
- r600_nomm_put_vb(dev);
-}
-
-void
-r600_blit_copy(struct drm_device *dev,
- uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
- int size_bytes)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- int max_bytes;
- u64 vb_addr;
- u32 *vb;
-
- vb = r600_nomm_get_vb_ptr(dev);
-
- if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) {
- max_bytes = 8192;
-
- while (size_bytes) {
- int cur_size = size_bytes;
- int src_x = src_gpu_addr & 255;
- int dst_x = dst_gpu_addr & 255;
- int h = 1;
- src_gpu_addr = src_gpu_addr & ~255;
- dst_gpu_addr = dst_gpu_addr & ~255;
-
- if (!src_x && !dst_x) {
- h = (cur_size / max_bytes);
- if (h > 8192)
- h = 8192;
- if (h == 0)
- h = 1;
- else
- cur_size = max_bytes;
- } else {
- if (cur_size > max_bytes)
- cur_size = max_bytes;
- if (cur_size > (max_bytes - dst_x))
- cur_size = (max_bytes - dst_x);
- if (cur_size > (max_bytes - src_x))
- cur_size = (max_bytes - src_x);
- }
-
- if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
-
- r600_nomm_put_vb(dev);
- r600_nomm_get_vb(dev);
- if (!dev_priv->blit_vb)
- return;
- set_shaders(dev);
- vb = r600_nomm_get_vb_ptr(dev);
- }
-
- vb[0] = int2float(dst_x);
- vb[1] = 0;
- vb[2] = int2float(src_x);
- vb[3] = 0;
-
- vb[4] = int2float(dst_x);
- vb[5] = int2float(h);
- vb[6] = int2float(src_x);
- vb[7] = int2float(h);
-
- vb[8] = int2float(dst_x + cur_size);
- vb[9] = int2float(h);
- vb[10] = int2float(src_x + cur_size);
- vb[11] = int2float(h);
-
- /* src */
- set_tex_resource(dev_priv, FMT_8,
- src_x + cur_size, h, src_x + cur_size,
- src_gpu_addr);
-
- cp_set_surface_sync(dev_priv,
- R600_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
-
- /* dst */
- set_render_target(dev_priv, COLOR_8,
- dst_x + cur_size, h,
- dst_gpu_addr);
-
- /* scissors */
- set_scissors(dev_priv, dst_x, 0, dst_x + cur_size, h);
-
- /* Vertex buffer setup */
- vb_addr = dev_priv->gart_buffers_offset +
- dev_priv->blit_vb->offset +
- dev_priv->blit_vb->used;
- set_vtx_resource(dev_priv, vb_addr);
-
- /* draw */
- draw_auto(dev_priv);
-
- cp_set_surface_sync(dev_priv,
- R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
- cur_size * h, dst_gpu_addr);
-
- vb += 12;
- dev_priv->blit_vb->used += 12 * 4;
-
- src_gpu_addr += cur_size * h;
- dst_gpu_addr += cur_size * h;
- size_bytes -= cur_size * h;
- }
- } else {
- max_bytes = 8192 * 4;
-
- while (size_bytes) {
- int cur_size = size_bytes;
- int src_x = (src_gpu_addr & 255);
- int dst_x = (dst_gpu_addr & 255);
- int h = 1;
- src_gpu_addr = src_gpu_addr & ~255;
- dst_gpu_addr = dst_gpu_addr & ~255;
-
- if (!src_x && !dst_x) {
- h = (cur_size / max_bytes);
- if (h > 8192)
- h = 8192;
- if (h == 0)
- h = 1;
- else
- cur_size = max_bytes;
- } else {
- if (cur_size > max_bytes)
- cur_size = max_bytes;
- if (cur_size > (max_bytes - dst_x))
- cur_size = (max_bytes - dst_x);
- if (cur_size > (max_bytes - src_x))
- cur_size = (max_bytes - src_x);
- }
-
- if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
- r600_nomm_put_vb(dev);
- r600_nomm_get_vb(dev);
- if (!dev_priv->blit_vb)
- return;
-
- set_shaders(dev);
- vb = r600_nomm_get_vb_ptr(dev);
- }
-
- vb[0] = int2float(dst_x / 4);
- vb[1] = 0;
- vb[2] = int2float(src_x / 4);
- vb[3] = 0;
-
- vb[4] = int2float(dst_x / 4);
- vb[5] = int2float(h);
- vb[6] = int2float(src_x / 4);
- vb[7] = int2float(h);
-
- vb[8] = int2float((dst_x + cur_size) / 4);
- vb[9] = int2float(h);
- vb[10] = int2float((src_x + cur_size) / 4);
- vb[11] = int2float(h);
-
- /* src */
- set_tex_resource(dev_priv, FMT_8_8_8_8,
- (src_x + cur_size) / 4,
- h, (src_x + cur_size) / 4,
- src_gpu_addr);
-
- cp_set_surface_sync(dev_priv,
- R600_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
-
- /* dst */
- set_render_target(dev_priv, COLOR_8_8_8_8,
- (dst_x + cur_size) / 4, h,
- dst_gpu_addr);
-
- /* scissors */
- set_scissors(dev_priv, (dst_x / 4), 0, (dst_x + cur_size / 4), h);
-
- /* Vertex buffer setup */
- vb_addr = dev_priv->gart_buffers_offset +
- dev_priv->blit_vb->offset +
- dev_priv->blit_vb->used;
- set_vtx_resource(dev_priv, vb_addr);
-
- /* draw */
- draw_auto(dev_priv);
-
- cp_set_surface_sync(dev_priv,
- R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
- cur_size * h, dst_gpu_addr);
-
- vb += 12;
- dev_priv->blit_vb->used += 12 * 4;
-
- src_gpu_addr += cur_size * h;
- dst_gpu_addr += cur_size * h;
- size_bytes -= cur_size * h;
- }
- }
-}
-
-void
-r600_blit_swap(struct drm_device *dev,
- uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
- int sx, int sy, int dx, int dy,
- int w, int h, int src_pitch, int dst_pitch, int cpp)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- int cb_format, tex_format;
- int sx2, sy2, dx2, dy2;
- u64 vb_addr;
- u32 *vb;
-
- if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
-
- r600_nomm_put_vb(dev);
- r600_nomm_get_vb(dev);
- if (!dev_priv->blit_vb)
- return;
-
- set_shaders(dev);
- }
- vb = r600_nomm_get_vb_ptr(dev);
-
- sx2 = sx + w;
- sy2 = sy + h;
- dx2 = dx + w;
- dy2 = dy + h;
-
- vb[0] = int2float(dx);
- vb[1] = int2float(dy);
- vb[2] = int2float(sx);
- vb[3] = int2float(sy);
-
- vb[4] = int2float(dx);
- vb[5] = int2float(dy2);
- vb[6] = int2float(sx);
- vb[7] = int2float(sy2);
-
- vb[8] = int2float(dx2);
- vb[9] = int2float(dy2);
- vb[10] = int2float(sx2);
- vb[11] = int2float(sy2);
-
- switch(cpp) {
- case 4:
- cb_format = COLOR_8_8_8_8;
- tex_format = FMT_8_8_8_8;
- break;
- case 2:
- cb_format = COLOR_5_6_5;
- tex_format = FMT_5_6_5;
- break;
- default:
- cb_format = COLOR_8;
- tex_format = FMT_8;
- break;
- }
-
- /* src */
- set_tex_resource(dev_priv, tex_format,
- src_pitch / cpp,
- sy2, src_pitch / cpp,
- src_gpu_addr);
-
- cp_set_surface_sync(dev_priv,
- R600_TC_ACTION_ENA, src_pitch * sy2, src_gpu_addr);
-
- /* dst */
- set_render_target(dev_priv, cb_format,
- dst_pitch / cpp, dy2,
- dst_gpu_addr);
-
- /* scissors */
- set_scissors(dev_priv, dx, dy, dx2, dy2);
-
- /* Vertex buffer setup */
- vb_addr = dev_priv->gart_buffers_offset +
- dev_priv->blit_vb->offset +
- dev_priv->blit_vb->used;
- set_vtx_resource(dev_priv, vb_addr);
-
- /* draw */
- draw_auto(dev_priv);
-
- cp_set_surface_sync(dev_priv,
- R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
- dst_pitch * dy2, dst_gpu_addr);
-
- dev_priv->blit_vb->used += 12 * 4;
-}
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
deleted file mode 100644
index e231eeafef23..000000000000
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ /dev/null
@@ -1,2660 +0,0 @@
-/*
- * Copyright 2008-2009 Advanced Micro Devices, Inc.
- * Copyright 2008 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 (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Dave Airlie <airlied@redhat.com>
- * Alex Deucher <alexander.deucher@amd.com>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-
-#include <linux/module.h>
-
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-
-#define PFP_UCODE_SIZE 576
-#define PM4_UCODE_SIZE 1792
-#define R700_PFP_UCODE_SIZE 848
-#define R700_PM4_UCODE_SIZE 1360
-
-/* Firmware Names */
-MODULE_FIRMWARE("radeon/R600_pfp.bin");
-MODULE_FIRMWARE("radeon/R600_me.bin");
-MODULE_FIRMWARE("radeon/RV610_pfp.bin");
-MODULE_FIRMWARE("radeon/RV610_me.bin");
-MODULE_FIRMWARE("radeon/RV630_pfp.bin");
-MODULE_FIRMWARE("radeon/RV630_me.bin");
-MODULE_FIRMWARE("radeon/RV620_pfp.bin");
-MODULE_FIRMWARE("radeon/RV620_me.bin");
-MODULE_FIRMWARE("radeon/RV635_pfp.bin");
-MODULE_FIRMWARE("radeon/RV635_me.bin");
-MODULE_FIRMWARE("radeon/RV670_pfp.bin");
-MODULE_FIRMWARE("radeon/RV670_me.bin");
-MODULE_FIRMWARE("radeon/RS780_pfp.bin");
-MODULE_FIRMWARE("radeon/RS780_me.bin");
-MODULE_FIRMWARE("radeon/RV770_pfp.bin");
-MODULE_FIRMWARE("radeon/RV770_me.bin");
-MODULE_FIRMWARE("radeon/RV730_pfp.bin");
-MODULE_FIRMWARE("radeon/RV730_me.bin");
-MODULE_FIRMWARE("radeon/RV710_pfp.bin");
-MODULE_FIRMWARE("radeon/RV710_me.bin");
-
-
-int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
- unsigned family, u32 *ib, int *l);
-void r600_cs_legacy_init(void);
-
-
-# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
-# define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1))
-
-#define R600_PTE_VALID (1 << 0)
-#define R600_PTE_SYSTEM (1 << 1)
-#define R600_PTE_SNOOPED (1 << 2)
-#define R600_PTE_READABLE (1 << 5)
-#define R600_PTE_WRITEABLE (1 << 6)
-
-/* MAX values used for gfx init */
-#define R6XX_MAX_SH_GPRS 256
-#define R6XX_MAX_TEMP_GPRS 16
-#define R6XX_MAX_SH_THREADS 256
-#define R6XX_MAX_SH_STACK_ENTRIES 4096
-#define R6XX_MAX_BACKENDS 8
-#define R6XX_MAX_BACKENDS_MASK 0xff
-#define R6XX_MAX_SIMDS 8
-#define R6XX_MAX_SIMDS_MASK 0xff
-#define R6XX_MAX_PIPES 8
-#define R6XX_MAX_PIPES_MASK 0xff
-
-#define R7XX_MAX_SH_GPRS 256
-#define R7XX_MAX_TEMP_GPRS 16
-#define R7XX_MAX_SH_THREADS 256
-#define R7XX_MAX_SH_STACK_ENTRIES 4096
-#define R7XX_MAX_BACKENDS 8
-#define R7XX_MAX_BACKENDS_MASK 0xff
-#define R7XX_MAX_SIMDS 16
-#define R7XX_MAX_SIMDS_MASK 0xffff
-#define R7XX_MAX_PIPES 8
-#define R7XX_MAX_PIPES_MASK 0xff
-
-static int r600_do_wait_for_fifo(drm_radeon_private_t *dev_priv, int entries)
-{
- int i;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- int slots;
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
- slots = (RADEON_READ(R600_GRBM_STATUS)
- & R700_CMDFIFO_AVAIL_MASK);
- else
- slots = (RADEON_READ(R600_GRBM_STATUS)
- & R600_CMDFIFO_AVAIL_MASK);
- if (slots >= entries)
- return 0;
- DRM_UDELAY(1);
- }
- DRM_INFO("wait for fifo failed status : 0x%08X 0x%08X\n",
- RADEON_READ(R600_GRBM_STATUS),
- RADEON_READ(R600_GRBM_STATUS2));
-
- return -EBUSY;
-}
-
-static int r600_do_wait_for_idle(drm_radeon_private_t *dev_priv)
-{
- int i, ret;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
- ret = r600_do_wait_for_fifo(dev_priv, 8);
- else
- ret = r600_do_wait_for_fifo(dev_priv, 16);
- if (ret)
- return ret;
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(RADEON_READ(R600_GRBM_STATUS) & R600_GUI_ACTIVE))
- return 0;
- DRM_UDELAY(1);
- }
- DRM_INFO("wait idle failed status : 0x%08X 0x%08X\n",
- RADEON_READ(R600_GRBM_STATUS),
- RADEON_READ(R600_GRBM_STATUS2));
-
- return -EBUSY;
-}
-
-void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
-{
- struct drm_sg_mem *entry = dev->sg;
- int max_pages;
- int pages;
- int i;
-
- if (!entry)
- return;
-
- if (gart_info->bus_addr) {
- max_pages = (gart_info->table_size / sizeof(u64));
- pages = (entry->pages <= max_pages)
- ? entry->pages : max_pages;
-
- for (i = 0; i < pages; i++) {
- if (!entry->busaddr[i])
- break;
- pci_unmap_page(dev->pdev, entry->busaddr[i],
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- }
- if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
- gart_info->bus_addr = 0;
- }
-}
-
-/* R600 has page table setup */
-int r600_page_table_init(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_ati_pcigart_info *gart_info = &dev_priv->gart_info;
- struct drm_local_map *map = &gart_info->mapping;
- struct drm_sg_mem *entry = dev->sg;
- int ret = 0;
- int i, j;
- int pages;
- u64 page_base;
- dma_addr_t entry_addr;
- int max_ati_pages, max_real_pages, gart_idx;
-
- /* okay page table is available - lets rock */
- max_ati_pages = (gart_info->table_size / sizeof(u64));
- max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
-
- pages = (entry->pages <= max_real_pages) ?
- entry->pages : max_real_pages;
-
- memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u64));
-
- gart_idx = 0;
- for (i = 0; i < pages; i++) {
- entry->busaddr[i] = pci_map_page(dev->pdev,
- entry->pagelist[i], 0,
- PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) {
- DRM_ERROR("unable to map PCIGART pages!\n");
- r600_page_table_cleanup(dev, gart_info);
- goto done;
- }
- entry_addr = entry->busaddr[i];
- for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
- page_base = (u64) entry_addr & ATI_PCIGART_PAGE_MASK;
- page_base |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED;
- page_base |= R600_PTE_READABLE | R600_PTE_WRITEABLE;
-
- DRM_WRITE64(map, gart_idx * sizeof(u64), page_base);
-
- gart_idx++;
-
- if ((i % 128) == 0)
- DRM_DEBUG("page entry %d: 0x%016llx\n",
- i, (unsigned long long)page_base);
- entry_addr += ATI_PCIGART_PAGE_SIZE;
- }
- }
- ret = 1;
-done:
- return ret;
-}
-
-static void r600_vm_flush_gart_range(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- u32 resp, countdown = 1000;
- RADEON_WRITE(R600_VM_CONTEXT0_INVALIDATION_LOW_ADDR, dev_priv->gart_vm_start >> 12);
- RADEON_WRITE(R600_VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
- RADEON_WRITE(R600_VM_CONTEXT0_REQUEST_RESPONSE, 2);
-
- do {
- resp = RADEON_READ(R600_VM_CONTEXT0_REQUEST_RESPONSE);
- countdown--;
- DRM_UDELAY(1);
- } while (((resp & 0xf0) == 0) && countdown);
-}
-
-static void r600_vm_init(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- /* initialise the VM to use the page table we constructed up there */
- u32 vm_c0, i;
- u32 mc_rd_a;
- u32 vm_l2_cntl, vm_l2_cntl3;
- /* okay set up the PCIE aperture type thingo */
- RADEON_WRITE(R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR, dev_priv->gart_vm_start >> 12);
- RADEON_WRITE(R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
- RADEON_WRITE(R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
-
- /* setup MC RD a */
- mc_rd_a = R600_MCD_L1_TLB | R600_MCD_L1_FRAG_PROC | R600_MCD_SYSTEM_ACCESS_MODE_IN_SYS |
- R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | R600_MCD_EFFECTIVE_L1_TLB_SIZE(5) |
- R600_MCD_EFFECTIVE_L1_QUEUE_SIZE(5) | R600_MCD_WAIT_L2_QUERY;
-
- RADEON_WRITE(R600_MCD_RD_A_CNTL, mc_rd_a);
- RADEON_WRITE(R600_MCD_RD_B_CNTL, mc_rd_a);
-
- RADEON_WRITE(R600_MCD_WR_A_CNTL, mc_rd_a);
- RADEON_WRITE(R600_MCD_WR_B_CNTL, mc_rd_a);
-
- RADEON_WRITE(R600_MCD_RD_GFX_CNTL, mc_rd_a);
- RADEON_WRITE(R600_MCD_WR_GFX_CNTL, mc_rd_a);
-
- RADEON_WRITE(R600_MCD_RD_SYS_CNTL, mc_rd_a);
- RADEON_WRITE(R600_MCD_WR_SYS_CNTL, mc_rd_a);
-
- RADEON_WRITE(R600_MCD_RD_HDP_CNTL, mc_rd_a | R600_MCD_L1_STRICT_ORDERING);
- RADEON_WRITE(R600_MCD_WR_HDP_CNTL, mc_rd_a /*| R600_MCD_L1_STRICT_ORDERING*/);
-
- RADEON_WRITE(R600_MCD_RD_PDMA_CNTL, mc_rd_a);
- RADEON_WRITE(R600_MCD_WR_PDMA_CNTL, mc_rd_a);
-
- RADEON_WRITE(R600_MCD_RD_SEM_CNTL, mc_rd_a | R600_MCD_SEMAPHORE_MODE);
- RADEON_WRITE(R600_MCD_WR_SEM_CNTL, mc_rd_a);
-
- vm_l2_cntl = R600_VM_L2_CACHE_EN | R600_VM_L2_FRAG_PROC | R600_VM_ENABLE_PTE_CACHE_LRU_W;
- vm_l2_cntl |= R600_VM_L2_CNTL_QUEUE_SIZE(7);
- RADEON_WRITE(R600_VM_L2_CNTL, vm_l2_cntl);
-
- RADEON_WRITE(R600_VM_L2_CNTL2, 0);
- vm_l2_cntl3 = (R600_VM_L2_CNTL3_BANK_SELECT_0(0) |
- R600_VM_L2_CNTL3_BANK_SELECT_1(1) |
- R600_VM_L2_CNTL3_CACHE_UPDATE_MODE(2));
- RADEON_WRITE(R600_VM_L2_CNTL3, vm_l2_cntl3);
-
- vm_c0 = R600_VM_ENABLE_CONTEXT | R600_VM_PAGE_TABLE_DEPTH_FLAT;
-
- RADEON_WRITE(R600_VM_CONTEXT0_CNTL, vm_c0);
-
- vm_c0 &= ~R600_VM_ENABLE_CONTEXT;
-
- /* disable all other contexts */
- for (i = 1; i < 8; i++)
- RADEON_WRITE(R600_VM_CONTEXT0_CNTL + (i * 4), vm_c0);
-
- RADEON_WRITE(R600_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, dev_priv->gart_info.bus_addr >> 12);
- RADEON_WRITE(R600_VM_CONTEXT0_PAGE_TABLE_START_ADDR, dev_priv->gart_vm_start >> 12);
- RADEON_WRITE(R600_VM_CONTEXT0_PAGE_TABLE_END_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
-
- r600_vm_flush_gart_range(dev);
-}
-
-static int r600_cp_init_microcode(drm_radeon_private_t *dev_priv)
-{
- struct platform_device *pdev;
- const char *chip_name;
- size_t pfp_req_size, me_req_size;
- char fw_name[30];
- int err;
-
- pdev = platform_device_register_simple("r600_cp", 0, NULL, 0);
- err = IS_ERR(pdev);
- if (err) {
- printk(KERN_ERR "r600_cp: Failed to register firmware\n");
- return -EINVAL;
- }
-
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_R600: chip_name = "R600"; break;
- case CHIP_RV610: chip_name = "RV610"; break;
- case CHIP_RV630: chip_name = "RV630"; break;
- case CHIP_RV620: chip_name = "RV620"; break;
- case CHIP_RV635: chip_name = "RV635"; break;
- case CHIP_RV670: chip_name = "RV670"; break;
- case CHIP_RS780:
- case CHIP_RS880: chip_name = "RS780"; break;
- case CHIP_RV770: chip_name = "RV770"; break;
- case CHIP_RV730:
- case CHIP_RV740: chip_name = "RV730"; break;
- case CHIP_RV710: chip_name = "RV710"; break;
- default: BUG();
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
- pfp_req_size = R700_PFP_UCODE_SIZE * 4;
- me_req_size = R700_PM4_UCODE_SIZE * 4;
- } else {
- pfp_req_size = PFP_UCODE_SIZE * 4;
- me_req_size = PM4_UCODE_SIZE * 12;
- }
-
- DRM_INFO("Loading %s CP Microcode\n", chip_name);
-
- snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
- err = request_firmware(&dev_priv->pfp_fw, fw_name, &pdev->dev);
- if (err)
- goto out;
- if (dev_priv->pfp_fw->size != pfp_req_size) {
- printk(KERN_ERR
- "r600_cp: Bogus length %zu in firmware \"%s\"\n",
- dev_priv->pfp_fw->size, fw_name);
- err = -EINVAL;
- goto out;
- }
-
- snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
- err = request_firmware(&dev_priv->me_fw, fw_name, &pdev->dev);
- if (err)
- goto out;
- if (dev_priv->me_fw->size != me_req_size) {
- printk(KERN_ERR
- "r600_cp: Bogus length %zu in firmware \"%s\"\n",
- dev_priv->me_fw->size, fw_name);
- err = -EINVAL;
- }
-out:
- platform_device_unregister(pdev);
-
- if (err) {
- if (err != -EINVAL)
- printk(KERN_ERR
- "r600_cp: Failed to load firmware \"%s\"\n",
- fw_name);
- release_firmware(dev_priv->pfp_fw);
- dev_priv->pfp_fw = NULL;
- release_firmware(dev_priv->me_fw);
- dev_priv->me_fw = NULL;
- }
- return err;
-}
-
-static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
-{
- const __be32 *fw_data;
- int i;
-
- if (!dev_priv->me_fw || !dev_priv->pfp_fw)
- return;
-
- r600_do_cp_stop(dev_priv);
-
- RADEON_WRITE(R600_CP_RB_CNTL,
-#ifdef __BIG_ENDIAN
- R600_BUF_SWAP_32BIT |
-#endif
- R600_RB_NO_UPDATE |
- R600_RB_BLKSZ(15) |
- R600_RB_BUFSZ(3));
-
- RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
- RADEON_READ(R600_GRBM_SOFT_RESET);
- mdelay(15);
- RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
-
- fw_data = (const __be32 *)dev_priv->me_fw->data;
- RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
- for (i = 0; i < PM4_UCODE_SIZE * 3; i++)
- RADEON_WRITE(R600_CP_ME_RAM_DATA,
- be32_to_cpup(fw_data++));
-
- fw_data = (const __be32 *)dev_priv->pfp_fw->data;
- RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
- for (i = 0; i < PFP_UCODE_SIZE; i++)
- RADEON_WRITE(R600_CP_PFP_UCODE_DATA,
- be32_to_cpup(fw_data++));
-
- RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
- RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
- RADEON_WRITE(R600_CP_ME_RAM_RADDR, 0);
-
-}
-
-static void r700_vm_init(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- /* initialise the VM to use the page table we constructed up there */
- u32 vm_c0, i;
- u32 mc_vm_md_l1;
- u32 vm_l2_cntl, vm_l2_cntl3;
- /* okay set up the PCIE aperture type thingo */
- RADEON_WRITE(R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR, dev_priv->gart_vm_start >> 12);
- RADEON_WRITE(R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
- RADEON_WRITE(R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
-
- mc_vm_md_l1 = R700_ENABLE_L1_TLB |
- R700_ENABLE_L1_FRAGMENT_PROCESSING |
- R700_SYSTEM_ACCESS_MODE_IN_SYS |
- R700_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
- R700_EFFECTIVE_L1_TLB_SIZE(5) |
- R700_EFFECTIVE_L1_QUEUE_SIZE(5);
-
- RADEON_WRITE(R700_MC_VM_MD_L1_TLB0_CNTL, mc_vm_md_l1);
- RADEON_WRITE(R700_MC_VM_MD_L1_TLB1_CNTL, mc_vm_md_l1);
- RADEON_WRITE(R700_MC_VM_MD_L1_TLB2_CNTL, mc_vm_md_l1);
- RADEON_WRITE(R700_MC_VM_MB_L1_TLB0_CNTL, mc_vm_md_l1);
- RADEON_WRITE(R700_MC_VM_MB_L1_TLB1_CNTL, mc_vm_md_l1);
- RADEON_WRITE(R700_MC_VM_MB_L1_TLB2_CNTL, mc_vm_md_l1);
- RADEON_WRITE(R700_MC_VM_MB_L1_TLB3_CNTL, mc_vm_md_l1);
-
- vm_l2_cntl = R600_VM_L2_CACHE_EN | R600_VM_L2_FRAG_PROC | R600_VM_ENABLE_PTE_CACHE_LRU_W;
- vm_l2_cntl |= R700_VM_L2_CNTL_QUEUE_SIZE(7);
- RADEON_WRITE(R600_VM_L2_CNTL, vm_l2_cntl);
-
- RADEON_WRITE(R600_VM_L2_CNTL2, 0);
- vm_l2_cntl3 = R700_VM_L2_CNTL3_BANK_SELECT(0) | R700_VM_L2_CNTL3_CACHE_UPDATE_MODE(2);
- RADEON_WRITE(R600_VM_L2_CNTL3, vm_l2_cntl3);
-
- vm_c0 = R600_VM_ENABLE_CONTEXT | R600_VM_PAGE_TABLE_DEPTH_FLAT;
-
- RADEON_WRITE(R600_VM_CONTEXT0_CNTL, vm_c0);
-
- vm_c0 &= ~R600_VM_ENABLE_CONTEXT;
-
- /* disable all other contexts */
- for (i = 1; i < 8; i++)
- RADEON_WRITE(R600_VM_CONTEXT0_CNTL + (i * 4), vm_c0);
-
- RADEON_WRITE(R700_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, dev_priv->gart_info.bus_addr >> 12);
- RADEON_WRITE(R700_VM_CONTEXT0_PAGE_TABLE_START_ADDR, dev_priv->gart_vm_start >> 12);
- RADEON_WRITE(R700_VM_CONTEXT0_PAGE_TABLE_END_ADDR, (dev_priv->gart_vm_start + dev_priv->gart_size - 1) >> 12);
-
- r600_vm_flush_gart_range(dev);
-}
-
-static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv)
-{
- const __be32 *fw_data;
- int i;
-
- if (!dev_priv->me_fw || !dev_priv->pfp_fw)
- return;
-
- r600_do_cp_stop(dev_priv);
-
- RADEON_WRITE(R600_CP_RB_CNTL,
-#ifdef __BIG_ENDIAN
- R600_BUF_SWAP_32BIT |
-#endif
- R600_RB_NO_UPDATE |
- R600_RB_BLKSZ(15) |
- R600_RB_BUFSZ(3));
-
- RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
- RADEON_READ(R600_GRBM_SOFT_RESET);
- mdelay(15);
- RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
-
- fw_data = (const __be32 *)dev_priv->pfp_fw->data;
- RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
- for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
- RADEON_WRITE(R600_CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++));
- RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
-
- fw_data = (const __be32 *)dev_priv->me_fw->data;
- RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
- for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
- RADEON_WRITE(R600_CP_ME_RAM_DATA, be32_to_cpup(fw_data++));
- RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
-
- RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
- RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
- RADEON_WRITE(R600_CP_ME_RAM_RADDR, 0);
-
-}
-
-static void r600_test_writeback(drm_radeon_private_t *dev_priv)
-{
- u32 tmp;
-
- /* Start with assuming that writeback doesn't work */
- dev_priv->writeback_works = 0;
-
- /* Writeback doesn't seem to work everywhere, test it here and possibly
- * enable it if it appears to work
- */
- radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(1), 0);
-
- RADEON_WRITE(R600_SCRATCH_REG1, 0xdeadbeef);
-
- for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
- u32 val;
-
- val = radeon_read_ring_rptr(dev_priv, R600_SCRATCHOFF(1));
- if (val == 0xdeadbeef)
- break;
- DRM_UDELAY(1);
- }
-
- if (tmp < dev_priv->usec_timeout) {
- dev_priv->writeback_works = 1;
- DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
- } else {
- dev_priv->writeback_works = 0;
- DRM_INFO("writeback test failed\n");
- }
- if (radeon_no_wb == 1) {
- dev_priv->writeback_works = 0;
- DRM_INFO("writeback forced off\n");
- }
-
- if (!dev_priv->writeback_works) {
- /* Disable writeback to avoid unnecessary bus master transfer */
- RADEON_WRITE(R600_CP_RB_CNTL,
-#ifdef __BIG_ENDIAN
- R600_BUF_SWAP_32BIT |
-#endif
- RADEON_READ(R600_CP_RB_CNTL) |
- R600_RB_NO_UPDATE);
- RADEON_WRITE(R600_SCRATCH_UMSK, 0);
- }
-}
-
-int r600_do_engine_reset(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- u32 cp_ptr, cp_me_cntl, cp_rb_cntl;
-
- DRM_INFO("Resetting GPU\n");
-
- cp_ptr = RADEON_READ(R600_CP_RB_WPTR);
- cp_me_cntl = RADEON_READ(R600_CP_ME_CNTL);
- RADEON_WRITE(R600_CP_ME_CNTL, R600_CP_ME_HALT);
-
- RADEON_WRITE(R600_GRBM_SOFT_RESET, 0x7fff);
- RADEON_READ(R600_GRBM_SOFT_RESET);
- DRM_UDELAY(50);
- RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
- RADEON_READ(R600_GRBM_SOFT_RESET);
-
- RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);
- cp_rb_cntl = RADEON_READ(R600_CP_RB_CNTL);
- RADEON_WRITE(R600_CP_RB_CNTL,
-#ifdef __BIG_ENDIAN
- R600_BUF_SWAP_32BIT |
-#endif
- R600_RB_RPTR_WR_ENA);
-
- RADEON_WRITE(R600_CP_RB_RPTR_WR, cp_ptr);
- RADEON_WRITE(R600_CP_RB_WPTR, cp_ptr);
- RADEON_WRITE(R600_CP_RB_CNTL, cp_rb_cntl);
- RADEON_WRITE(R600_CP_ME_CNTL, cp_me_cntl);
-
- /* Reset the CP ring */
- r600_do_cp_reset(dev_priv);
-
- /* The CP is no longer running after an engine reset */
- dev_priv->cp_running = 0;
-
- /* Reset any pending vertex, indirect buffers */
- radeon_freelist_reset(dev);
-
- return 0;
-
-}
-
-static u32 r600_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
- u32 num_backends,
- u32 backend_disable_mask)
-{
- u32 backend_map = 0;
- u32 enabled_backends_mask;
- u32 enabled_backends_count;
- u32 cur_pipe;
- u32 swizzle_pipe[R6XX_MAX_PIPES];
- u32 cur_backend;
- u32 i;
-
- if (num_tile_pipes > R6XX_MAX_PIPES)
- num_tile_pipes = R6XX_MAX_PIPES;
- if (num_tile_pipes < 1)
- num_tile_pipes = 1;
- if (num_backends > R6XX_MAX_BACKENDS)
- num_backends = R6XX_MAX_BACKENDS;
- if (num_backends < 1)
- num_backends = 1;
-
- enabled_backends_mask = 0;
- enabled_backends_count = 0;
- for (i = 0; i < R6XX_MAX_BACKENDS; ++i) {
- if (((backend_disable_mask >> i) & 1) == 0) {
- enabled_backends_mask |= (1 << i);
- ++enabled_backends_count;
- }
- if (enabled_backends_count == num_backends)
- break;
- }
-
- if (enabled_backends_count == 0) {
- enabled_backends_mask = 1;
- enabled_backends_count = 1;
- }
-
- if (enabled_backends_count != num_backends)
- num_backends = enabled_backends_count;
-
- memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R6XX_MAX_PIPES);
- switch (num_tile_pipes) {
- case 1:
- swizzle_pipe[0] = 0;
- break;
- case 2:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- break;
- case 3:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- break;
- case 4:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- break;
- case 5:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- swizzle_pipe[4] = 4;
- break;
- case 6:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 5;
- swizzle_pipe[4] = 1;
- swizzle_pipe[5] = 3;
- break;
- case 7:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 1;
- swizzle_pipe[5] = 3;
- swizzle_pipe[6] = 5;
- break;
- case 8:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 1;
- swizzle_pipe[5] = 3;
- swizzle_pipe[6] = 5;
- swizzle_pipe[7] = 7;
- break;
- }
-
- cur_backend = 0;
- for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) {
- while (((1 << cur_backend) & enabled_backends_mask) == 0)
- cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS;
-
- backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2)));
-
- cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS;
- }
-
- return backend_map;
-}
-
-static int r600_count_pipe_bits(uint32_t val)
-{
- return hweight32(val);
-}
-
-static void r600_gfx_init(struct drm_device *dev,
- drm_radeon_private_t *dev_priv)
-{
- int i, j, num_qd_pipes;
- u32 sx_debug_1;
- u32 tc_cntl;
- u32 arb_pop;
- u32 num_gs_verts_per_thread;
- u32 vgt_gs_per_es;
- u32 gs_prim_buffer_depth = 0;
- u32 sq_ms_fifo_sizes;
- u32 sq_config;
- u32 sq_gpr_resource_mgmt_1 = 0;
- u32 sq_gpr_resource_mgmt_2 = 0;
- u32 sq_thread_resource_mgmt = 0;
- u32 sq_stack_resource_mgmt_1 = 0;
- u32 sq_stack_resource_mgmt_2 = 0;
- u32 hdp_host_path_cntl;
- u32 backend_map;
- u32 gb_tiling_config = 0;
- u32 cc_rb_backend_disable;
- u32 cc_gc_shader_pipe_config;
- u32 ramcfg;
-
- /* setup chip specs */
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_R600:
- dev_priv->r600_max_pipes = 4;
- dev_priv->r600_max_tile_pipes = 8;
- dev_priv->r600_max_simds = 4;
- dev_priv->r600_max_backends = 4;
- dev_priv->r600_max_gprs = 256;
- dev_priv->r600_max_threads = 192;
- dev_priv->r600_max_stack_entries = 256;
- dev_priv->r600_max_hw_contexts = 8;
- dev_priv->r600_max_gs_threads = 16;
- dev_priv->r600_sx_max_export_size = 128;
- dev_priv->r600_sx_max_export_pos_size = 16;
- dev_priv->r600_sx_max_export_smx_size = 128;
- dev_priv->r600_sq_num_cf_insts = 2;
- break;
- case CHIP_RV630:
- case CHIP_RV635:
- dev_priv->r600_max_pipes = 2;
- dev_priv->r600_max_tile_pipes = 2;
- dev_priv->r600_max_simds = 3;
- dev_priv->r600_max_backends = 1;
- dev_priv->r600_max_gprs = 128;
- dev_priv->r600_max_threads = 192;
- dev_priv->r600_max_stack_entries = 128;
- dev_priv->r600_max_hw_contexts = 8;
- dev_priv->r600_max_gs_threads = 4;
- dev_priv->r600_sx_max_export_size = 128;
- dev_priv->r600_sx_max_export_pos_size = 16;
- dev_priv->r600_sx_max_export_smx_size = 128;
- dev_priv->r600_sq_num_cf_insts = 2;
- break;
- case CHIP_RV610:
- case CHIP_RS780:
- case CHIP_RS880:
- case CHIP_RV620:
- dev_priv->r600_max_pipes = 1;
- dev_priv->r600_max_tile_pipes = 1;
- dev_priv->r600_max_simds = 2;
- dev_priv->r600_max_backends = 1;
- dev_priv->r600_max_gprs = 128;
- dev_priv->r600_max_threads = 192;
- dev_priv->r600_max_stack_entries = 128;
- dev_priv->r600_max_hw_contexts = 4;
- dev_priv->r600_max_gs_threads = 4;
- dev_priv->r600_sx_max_export_size = 128;
- dev_priv->r600_sx_max_export_pos_size = 16;
- dev_priv->r600_sx_max_export_smx_size = 128;
- dev_priv->r600_sq_num_cf_insts = 1;
- break;
- case CHIP_RV670:
- dev_priv->r600_max_pipes = 4;
- dev_priv->r600_max_tile_pipes = 4;
- dev_priv->r600_max_simds = 4;
- dev_priv->r600_max_backends = 4;
- dev_priv->r600_max_gprs = 192;
- dev_priv->r600_max_threads = 192;
- dev_priv->r600_max_stack_entries = 256;
- dev_priv->r600_max_hw_contexts = 8;
- dev_priv->r600_max_gs_threads = 16;
- dev_priv->r600_sx_max_export_size = 128;
- dev_priv->r600_sx_max_export_pos_size = 16;
- dev_priv->r600_sx_max_export_smx_size = 128;
- dev_priv->r600_sq_num_cf_insts = 2;
- break;
- default:
- break;
- }
-
- /* Initialize HDP */
- j = 0;
- for (i = 0; i < 32; i++) {
- RADEON_WRITE((0x2c14 + j), 0x00000000);
- RADEON_WRITE((0x2c18 + j), 0x00000000);
- RADEON_WRITE((0x2c1c + j), 0x00000000);
- RADEON_WRITE((0x2c20 + j), 0x00000000);
- RADEON_WRITE((0x2c24 + j), 0x00000000);
- j += 0x18;
- }
-
- RADEON_WRITE(R600_GRBM_CNTL, R600_GRBM_READ_TIMEOUT(0xff));
-
- /* setup tiling, simd, pipe config */
- ramcfg = RADEON_READ(R600_RAMCFG);
-
- switch (dev_priv->r600_max_tile_pipes) {
- case 1:
- gb_tiling_config |= R600_PIPE_TILING(0);
- break;
- case 2:
- gb_tiling_config |= R600_PIPE_TILING(1);
- break;
- case 4:
- gb_tiling_config |= R600_PIPE_TILING(2);
- break;
- case 8:
- gb_tiling_config |= R600_PIPE_TILING(3);
- break;
- default:
- break;
- }
-
- gb_tiling_config |= R600_BANK_TILING((ramcfg >> R600_NOOFBANK_SHIFT) & R600_NOOFBANK_MASK);
-
- gb_tiling_config |= R600_GROUP_SIZE(0);
-
- if (((ramcfg >> R600_NOOFROWS_SHIFT) & R600_NOOFROWS_MASK) > 3) {
- gb_tiling_config |= R600_ROW_TILING(3);
- gb_tiling_config |= R600_SAMPLE_SPLIT(3);
- } else {
- gb_tiling_config |=
- R600_ROW_TILING(((ramcfg >> R600_NOOFROWS_SHIFT) & R600_NOOFROWS_MASK));
- gb_tiling_config |=
- R600_SAMPLE_SPLIT(((ramcfg >> R600_NOOFROWS_SHIFT) & R600_NOOFROWS_MASK));
- }
-
- gb_tiling_config |= R600_BANK_SWAPS(1);
-
- cc_rb_backend_disable = RADEON_READ(R600_CC_RB_BACKEND_DISABLE) & 0x00ff0000;
- cc_rb_backend_disable |=
- R600_BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R6XX_MAX_BACKENDS_MASK);
-
- cc_gc_shader_pipe_config = RADEON_READ(R600_CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
- cc_gc_shader_pipe_config |=
- R600_INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R6XX_MAX_PIPES_MASK);
- cc_gc_shader_pipe_config |=
- R600_INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R6XX_MAX_SIMDS_MASK);
-
- backend_map = r600_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
- (R6XX_MAX_BACKENDS -
- r600_count_pipe_bits((cc_rb_backend_disable &
- R6XX_MAX_BACKENDS_MASK) >> 16)),
- (cc_rb_backend_disable >> 16));
- gb_tiling_config |= R600_BACKEND_MAP(backend_map);
-
- RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config);
- RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- if (gb_tiling_config & 0xc0) {
- dev_priv->r600_group_size = 512;
- } else {
- dev_priv->r600_group_size = 256;
- }
- dev_priv->r600_npipes = 1 << ((gb_tiling_config >> 1) & 0x7);
- if (gb_tiling_config & 0x30) {
- dev_priv->r600_nbanks = 8;
- } else {
- dev_priv->r600_nbanks = 4;
- }
-
- RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
- RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
- RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
-
- num_qd_pipes =
- R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8);
- RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
- RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
-
- /* set HW defaults for 3D engine */
- RADEON_WRITE(R600_CP_QUEUE_THRESHOLDS, (R600_ROQ_IB1_START(0x16) |
- R600_ROQ_IB2_START(0x2b)));
-
- RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, (R600_MEQ_END(0x40) |
- R600_ROQ_END(0x40)));
-
- RADEON_WRITE(R600_TA_CNTL_AUX, (R600_DISABLE_CUBE_ANISO |
- R600_SYNC_GRADIENT |
- R600_SYNC_WALKER |
- R600_SYNC_ALIGNER));
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV670)
- RADEON_WRITE(R600_ARB_GDEC_RD_CNTL, 0x00000021);
-
- sx_debug_1 = RADEON_READ(R600_SX_DEBUG_1);
- sx_debug_1 |= R600_SMX_EVENT_RELEASE;
- if (((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_R600))
- sx_debug_1 |= R600_ENABLE_NEW_SMX_ADDRESS;
- RADEON_WRITE(R600_SX_DEBUG_1, sx_debug_1);
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880))
- RADEON_WRITE(R600_DB_DEBUG, R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE);
- else
- RADEON_WRITE(R600_DB_DEBUG, 0);
-
- RADEON_WRITE(R600_DB_WATERMARKS, (R600_DEPTH_FREE(4) |
- R600_DEPTH_FLUSH(16) |
- R600_DEPTH_PENDING_FREE(4) |
- R600_DEPTH_CACHELINE_FREE(16)));
- RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
- RADEON_WRITE(R600_VGT_NUM_INSTANCES, 0);
-
- RADEON_WRITE(R600_SPI_CONFIG_CNTL, R600_GPR_WRITE_PRIORITY(0));
- RADEON_WRITE(R600_SPI_CONFIG_CNTL_1, R600_VTX_DONE_DELAY(0));
-
- sq_ms_fifo_sizes = RADEON_READ(R600_SQ_MS_FIFO_SIZES);
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {
- sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(0xa) |
- R600_FETCH_FIFO_HIWATER(0xa) |
- R600_DONE_FIFO_HIWATER(0xe0) |
- R600_ALU_UPDATE_FIFO_HIWATER(0x8));
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630)) {
- sq_ms_fifo_sizes &= ~R600_DONE_FIFO_HIWATER(0xff);
- sq_ms_fifo_sizes |= R600_DONE_FIFO_HIWATER(0x4);
- }
- RADEON_WRITE(R600_SQ_MS_FIFO_SIZES, sq_ms_fifo_sizes);
-
- /* SQ_CONFIG, SQ_GPR_RESOURCE_MGMT, SQ_THREAD_RESOURCE_MGMT, SQ_STACK_RESOURCE_MGMT
- * should be adjusted as needed by the 2D/3D drivers. This just sets default values
- */
- sq_config = RADEON_READ(R600_SQ_CONFIG);
- sq_config &= ~(R600_PS_PRIO(3) |
- R600_VS_PRIO(3) |
- R600_GS_PRIO(3) |
- R600_ES_PRIO(3));
- sq_config |= (R600_DX9_CONSTS |
- R600_VC_ENABLE |
- R600_PS_PRIO(0) |
- R600_VS_PRIO(1) |
- R600_GS_PRIO(2) |
- R600_ES_PRIO(3));
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600) {
- sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(124) |
- R600_NUM_VS_GPRS(124) |
- R600_NUM_CLAUSE_TEMP_GPRS(4));
- sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(0) |
- R600_NUM_ES_GPRS(0));
- sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(136) |
- R600_NUM_VS_THREADS(48) |
- R600_NUM_GS_THREADS(4) |
- R600_NUM_ES_THREADS(4));
- sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(128) |
- R600_NUM_VS_STACK_ENTRIES(128));
- sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(0) |
- R600_NUM_ES_STACK_ENTRIES(0));
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {
- /* no vertex cache */
- sq_config &= ~R600_VC_ENABLE;
-
- sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(44) |
- R600_NUM_VS_GPRS(44) |
- R600_NUM_CLAUSE_TEMP_GPRS(2));
- sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(17) |
- R600_NUM_ES_GPRS(17));
- sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(79) |
- R600_NUM_VS_THREADS(78) |
- R600_NUM_GS_THREADS(4) |
- R600_NUM_ES_THREADS(31));
- sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(40) |
- R600_NUM_VS_STACK_ENTRIES(40));
- sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(32) |
- R600_NUM_ES_STACK_ENTRIES(16));
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV635)) {
- sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(44) |
- R600_NUM_VS_GPRS(44) |
- R600_NUM_CLAUSE_TEMP_GPRS(2));
- sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(18) |
- R600_NUM_ES_GPRS(18));
- sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(79) |
- R600_NUM_VS_THREADS(78) |
- R600_NUM_GS_THREADS(4) |
- R600_NUM_ES_THREADS(31));
- sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(40) |
- R600_NUM_VS_STACK_ENTRIES(40));
- sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(32) |
- R600_NUM_ES_STACK_ENTRIES(16));
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV670) {
- sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(44) |
- R600_NUM_VS_GPRS(44) |
- R600_NUM_CLAUSE_TEMP_GPRS(2));
- sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(17) |
- R600_NUM_ES_GPRS(17));
- sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(79) |
- R600_NUM_VS_THREADS(78) |
- R600_NUM_GS_THREADS(4) |
- R600_NUM_ES_THREADS(31));
- sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(64) |
- R600_NUM_VS_STACK_ENTRIES(64));
- sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(64) |
- R600_NUM_ES_STACK_ENTRIES(64));
- }
-
- RADEON_WRITE(R600_SQ_CONFIG, sq_config);
- RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_1, sq_gpr_resource_mgmt_1);
- RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_2, sq_gpr_resource_mgmt_2);
- RADEON_WRITE(R600_SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt);
- RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_1, sq_stack_resource_mgmt_1);
- RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_2, sq_stack_resource_mgmt_2);
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880))
- RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_TC_ONLY));
- else
- RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_VC_AND_TC));
-
- RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_2S, (R600_S0_X(0xc) |
- R600_S0_Y(0x4) |
- R600_S1_X(0x4) |
- R600_S1_Y(0xc)));
- RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_4S, (R600_S0_X(0xe) |
- R600_S0_Y(0xe) |
- R600_S1_X(0x2) |
- R600_S1_Y(0x2) |
- R600_S2_X(0xa) |
- R600_S2_Y(0x6) |
- R600_S3_X(0x6) |
- R600_S3_Y(0xa)));
- RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_8S_WD0, (R600_S0_X(0xe) |
- R600_S0_Y(0xb) |
- R600_S1_X(0x4) |
- R600_S1_Y(0xc) |
- R600_S2_X(0x1) |
- R600_S2_Y(0x6) |
- R600_S3_X(0xa) |
- R600_S3_Y(0xe)));
- RADEON_WRITE(R600_PA_SC_AA_SAMPLE_LOCS_8S_WD1, (R600_S4_X(0x6) |
- R600_S4_Y(0x1) |
- R600_S5_X(0x0) |
- R600_S5_Y(0x0) |
- R600_S6_X(0xb) |
- R600_S6_Y(0x4) |
- R600_S7_X(0x7) |
- R600_S7_Y(0x8)));
-
-
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_R600:
- case CHIP_RV630:
- case CHIP_RV635:
- gs_prim_buffer_depth = 0;
- break;
- case CHIP_RV610:
- case CHIP_RS780:
- case CHIP_RS880:
- case CHIP_RV620:
- gs_prim_buffer_depth = 32;
- break;
- case CHIP_RV670:
- gs_prim_buffer_depth = 128;
- break;
- default:
- break;
- }
-
- num_gs_verts_per_thread = dev_priv->r600_max_pipes * 16;
- vgt_gs_per_es = gs_prim_buffer_depth + num_gs_verts_per_thread;
- /* Max value for this is 256 */
- if (vgt_gs_per_es > 256)
- vgt_gs_per_es = 256;
-
- RADEON_WRITE(R600_VGT_ES_PER_GS, 128);
- RADEON_WRITE(R600_VGT_GS_PER_ES, vgt_gs_per_es);
- RADEON_WRITE(R600_VGT_GS_PER_VS, 2);
- RADEON_WRITE(R600_VGT_GS_VERTEX_REUSE, 16);
-
- /* more default values. 2D/3D driver should adjust as needed */
- RADEON_WRITE(R600_PA_SC_LINE_STIPPLE_STATE, 0);
- RADEON_WRITE(R600_VGT_STRMOUT_EN, 0);
- RADEON_WRITE(R600_SX_MISC, 0);
- RADEON_WRITE(R600_PA_SC_MODE_CNTL, 0);
- RADEON_WRITE(R600_PA_SC_AA_CONFIG, 0);
- RADEON_WRITE(R600_PA_SC_LINE_STIPPLE, 0);
- RADEON_WRITE(R600_SPI_INPUT_Z, 0);
- RADEON_WRITE(R600_SPI_PS_IN_CONTROL_0, R600_NUM_INTERP(2));
- RADEON_WRITE(R600_CB_COLOR7_FRAG, 0);
-
- /* clear render buffer base addresses */
- RADEON_WRITE(R600_CB_COLOR0_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR1_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR2_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR3_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR4_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR5_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR6_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR7_BASE, 0);
-
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_RV610:
- case CHIP_RS780:
- case CHIP_RS880:
- case CHIP_RV620:
- tc_cntl = R600_TC_L2_SIZE(8);
- break;
- case CHIP_RV630:
- case CHIP_RV635:
- tc_cntl = R600_TC_L2_SIZE(4);
- break;
- case CHIP_R600:
- tc_cntl = R600_TC_L2_SIZE(0) | R600_L2_DISABLE_LATE_HIT;
- break;
- default:
- tc_cntl = R600_TC_L2_SIZE(0);
- break;
- }
-
- RADEON_WRITE(R600_TC_CNTL, tc_cntl);
-
- hdp_host_path_cntl = RADEON_READ(R600_HDP_HOST_PATH_CNTL);
- RADEON_WRITE(R600_HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
-
- arb_pop = RADEON_READ(R600_ARB_POP);
- arb_pop |= R600_ENABLE_TC128;
- RADEON_WRITE(R600_ARB_POP, arb_pop);
-
- RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
- RADEON_WRITE(R600_PA_CL_ENHANCE, (R600_CLIP_VTX_REORDER_ENA |
- R600_NUM_CLIP_SEQ(3)));
- RADEON_WRITE(R600_PA_SC_ENHANCE, R600_FORCE_EOV_MAX_CLK_CNT(4095));
-
-}
-
-static u32 r700_get_tile_pipe_to_backend_map(drm_radeon_private_t *dev_priv,
- u32 num_tile_pipes,
- u32 num_backends,
- u32 backend_disable_mask)
-{
- u32 backend_map = 0;
- u32 enabled_backends_mask;
- u32 enabled_backends_count;
- u32 cur_pipe;
- u32 swizzle_pipe[R7XX_MAX_PIPES];
- u32 cur_backend;
- u32 i;
- bool force_no_swizzle;
-
- if (num_tile_pipes > R7XX_MAX_PIPES)
- num_tile_pipes = R7XX_MAX_PIPES;
- if (num_tile_pipes < 1)
- num_tile_pipes = 1;
- if (num_backends > R7XX_MAX_BACKENDS)
- num_backends = R7XX_MAX_BACKENDS;
- if (num_backends < 1)
- num_backends = 1;
-
- enabled_backends_mask = 0;
- enabled_backends_count = 0;
- for (i = 0; i < R7XX_MAX_BACKENDS; ++i) {
- if (((backend_disable_mask >> i) & 1) == 0) {
- enabled_backends_mask |= (1 << i);
- ++enabled_backends_count;
- }
- if (enabled_backends_count == num_backends)
- break;
- }
-
- if (enabled_backends_count == 0) {
- enabled_backends_mask = 1;
- enabled_backends_count = 1;
- }
-
- if (enabled_backends_count != num_backends)
- num_backends = enabled_backends_count;
-
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_RV770:
- case CHIP_RV730:
- force_no_swizzle = false;
- break;
- case CHIP_RV710:
- case CHIP_RV740:
- default:
- force_no_swizzle = true;
- break;
- }
-
- memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES);
- switch (num_tile_pipes) {
- case 1:
- swizzle_pipe[0] = 0;
- break;
- case 2:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- break;
- case 3:
- if (force_no_swizzle) {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- } else {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 1;
- }
- break;
- case 4:
- if (force_no_swizzle) {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- } else {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 3;
- swizzle_pipe[3] = 1;
- }
- break;
- case 5:
- if (force_no_swizzle) {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- swizzle_pipe[4] = 4;
- } else {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 1;
- swizzle_pipe[4] = 3;
- }
- break;
- case 6:
- if (force_no_swizzle) {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- swizzle_pipe[4] = 4;
- swizzle_pipe[5] = 5;
- } else {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 5;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- }
- break;
- case 7:
- if (force_no_swizzle) {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- swizzle_pipe[4] = 4;
- swizzle_pipe[5] = 5;
- swizzle_pipe[6] = 6;
- } else {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- swizzle_pipe[6] = 5;
- }
- break;
- case 8:
- if (force_no_swizzle) {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 1;
- swizzle_pipe[2] = 2;
- swizzle_pipe[3] = 3;
- swizzle_pipe[4] = 4;
- swizzle_pipe[5] = 5;
- swizzle_pipe[6] = 6;
- swizzle_pipe[7] = 7;
- } else {
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- swizzle_pipe[6] = 7;
- swizzle_pipe[7] = 5;
- }
- break;
- }
-
- cur_backend = 0;
- for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) {
- while (((1 << cur_backend) & enabled_backends_mask) == 0)
- cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS;
-
- backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2)));
-
- cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS;
- }
-
- return backend_map;
-}
-
-static void r700_gfx_init(struct drm_device *dev,
- drm_radeon_private_t *dev_priv)
-{
- int i, j, num_qd_pipes;
- u32 ta_aux_cntl;
- u32 sx_debug_1;
- u32 smx_dc_ctl0;
- u32 db_debug3;
- u32 num_gs_verts_per_thread;
- u32 vgt_gs_per_es;
- u32 gs_prim_buffer_depth = 0;
- u32 sq_ms_fifo_sizes;
- u32 sq_config;
- u32 sq_thread_resource_mgmt;
- u32 hdp_host_path_cntl;
- u32 sq_dyn_gpr_size_simd_ab_0;
- u32 backend_map;
- u32 gb_tiling_config = 0;
- u32 cc_rb_backend_disable;
- u32 cc_gc_shader_pipe_config;
- u32 mc_arb_ramcfg;
- u32 db_debug4;
-
- /* setup chip specs */
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_RV770:
- dev_priv->r600_max_pipes = 4;
- dev_priv->r600_max_tile_pipes = 8;
- dev_priv->r600_max_simds = 10;
- dev_priv->r600_max_backends = 4;
- dev_priv->r600_max_gprs = 256;
- dev_priv->r600_max_threads = 248;
- dev_priv->r600_max_stack_entries = 512;
- dev_priv->r600_max_hw_contexts = 8;
- dev_priv->r600_max_gs_threads = 16 * 2;
- dev_priv->r600_sx_max_export_size = 128;
- dev_priv->r600_sx_max_export_pos_size = 16;
- dev_priv->r600_sx_max_export_smx_size = 112;
- dev_priv->r600_sq_num_cf_insts = 2;
-
- dev_priv->r700_sx_num_of_sets = 7;
- dev_priv->r700_sc_prim_fifo_size = 0xF9;
- dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
- dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
- break;
- case CHIP_RV730:
- dev_priv->r600_max_pipes = 2;
- dev_priv->r600_max_tile_pipes = 4;
- dev_priv->r600_max_simds = 8;
- dev_priv->r600_max_backends = 2;
- dev_priv->r600_max_gprs = 128;
- dev_priv->r600_max_threads = 248;
- dev_priv->r600_max_stack_entries = 256;
- dev_priv->r600_max_hw_contexts = 8;
- dev_priv->r600_max_gs_threads = 16 * 2;
- dev_priv->r600_sx_max_export_size = 256;
- dev_priv->r600_sx_max_export_pos_size = 32;
- dev_priv->r600_sx_max_export_smx_size = 224;
- dev_priv->r600_sq_num_cf_insts = 2;
-
- dev_priv->r700_sx_num_of_sets = 7;
- dev_priv->r700_sc_prim_fifo_size = 0xf9;
- dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
- dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
- if (dev_priv->r600_sx_max_export_pos_size > 16) {
- dev_priv->r600_sx_max_export_pos_size -= 16;
- dev_priv->r600_sx_max_export_smx_size += 16;
- }
- break;
- case CHIP_RV710:
- dev_priv->r600_max_pipes = 2;
- dev_priv->r600_max_tile_pipes = 2;
- dev_priv->r600_max_simds = 2;
- dev_priv->r600_max_backends = 1;
- dev_priv->r600_max_gprs = 256;
- dev_priv->r600_max_threads = 192;
- dev_priv->r600_max_stack_entries = 256;
- dev_priv->r600_max_hw_contexts = 4;
- dev_priv->r600_max_gs_threads = 8 * 2;
- dev_priv->r600_sx_max_export_size = 128;
- dev_priv->r600_sx_max_export_pos_size = 16;
- dev_priv->r600_sx_max_export_smx_size = 112;
- dev_priv->r600_sq_num_cf_insts = 1;
-
- dev_priv->r700_sx_num_of_sets = 7;
- dev_priv->r700_sc_prim_fifo_size = 0x40;
- dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
- dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
- break;
- case CHIP_RV740:
- dev_priv->r600_max_pipes = 4;
- dev_priv->r600_max_tile_pipes = 4;
- dev_priv->r600_max_simds = 8;
- dev_priv->r600_max_backends = 4;
- dev_priv->r600_max_gprs = 256;
- dev_priv->r600_max_threads = 248;
- dev_priv->r600_max_stack_entries = 512;
- dev_priv->r600_max_hw_contexts = 8;
- dev_priv->r600_max_gs_threads = 16 * 2;
- dev_priv->r600_sx_max_export_size = 256;
- dev_priv->r600_sx_max_export_pos_size = 32;
- dev_priv->r600_sx_max_export_smx_size = 224;
- dev_priv->r600_sq_num_cf_insts = 2;
-
- dev_priv->r700_sx_num_of_sets = 7;
- dev_priv->r700_sc_prim_fifo_size = 0x100;
- dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
- dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
-
- if (dev_priv->r600_sx_max_export_pos_size > 16) {
- dev_priv->r600_sx_max_export_pos_size -= 16;
- dev_priv->r600_sx_max_export_smx_size += 16;
- }
- break;
- default:
- break;
- }
-
- /* Initialize HDP */
- j = 0;
- for (i = 0; i < 32; i++) {
- RADEON_WRITE((0x2c14 + j), 0x00000000);
- RADEON_WRITE((0x2c18 + j), 0x00000000);
- RADEON_WRITE((0x2c1c + j), 0x00000000);
- RADEON_WRITE((0x2c20 + j), 0x00000000);
- RADEON_WRITE((0x2c24 + j), 0x00000000);
- j += 0x18;
- }
-
- RADEON_WRITE(R600_GRBM_CNTL, R600_GRBM_READ_TIMEOUT(0xff));
-
- /* setup tiling, simd, pipe config */
- mc_arb_ramcfg = RADEON_READ(R700_MC_ARB_RAMCFG);
-
- switch (dev_priv->r600_max_tile_pipes) {
- case 1:
- gb_tiling_config |= R600_PIPE_TILING(0);
- break;
- case 2:
- gb_tiling_config |= R600_PIPE_TILING(1);
- break;
- case 4:
- gb_tiling_config |= R600_PIPE_TILING(2);
- break;
- case 8:
- gb_tiling_config |= R600_PIPE_TILING(3);
- break;
- default:
- break;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)
- gb_tiling_config |= R600_BANK_TILING(1);
- else
- gb_tiling_config |= R600_BANK_TILING((mc_arb_ramcfg >> R700_NOOFBANK_SHIFT) & R700_NOOFBANK_MASK);
-
- gb_tiling_config |= R600_GROUP_SIZE(0);
-
- if (((mc_arb_ramcfg >> R700_NOOFROWS_SHIFT) & R700_NOOFROWS_MASK) > 3) {
- gb_tiling_config |= R600_ROW_TILING(3);
- gb_tiling_config |= R600_SAMPLE_SPLIT(3);
- } else {
- gb_tiling_config |=
- R600_ROW_TILING(((mc_arb_ramcfg >> R700_NOOFROWS_SHIFT) & R700_NOOFROWS_MASK));
- gb_tiling_config |=
- R600_SAMPLE_SPLIT(((mc_arb_ramcfg >> R700_NOOFROWS_SHIFT) & R700_NOOFROWS_MASK));
- }
-
- gb_tiling_config |= R600_BANK_SWAPS(1);
-
- cc_rb_backend_disable = RADEON_READ(R600_CC_RB_BACKEND_DISABLE) & 0x00ff0000;
- cc_rb_backend_disable |=
- R600_BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R7XX_MAX_BACKENDS_MASK);
-
- cc_gc_shader_pipe_config = RADEON_READ(R600_CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
- cc_gc_shader_pipe_config |=
- R600_INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R7XX_MAX_PIPES_MASK);
- cc_gc_shader_pipe_config |=
- R600_INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R7XX_MAX_SIMDS_MASK);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)
- backend_map = 0x28;
- else
- backend_map = r700_get_tile_pipe_to_backend_map(dev_priv,
- dev_priv->r600_max_tile_pipes,
- (R7XX_MAX_BACKENDS -
- r600_count_pipe_bits((cc_rb_backend_disable &
- R7XX_MAX_BACKENDS_MASK) >> 16)),
- (cc_rb_backend_disable >> 16));
- gb_tiling_config |= R600_BACKEND_MAP(backend_map);
-
- RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config);
- RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- if (gb_tiling_config & 0xc0) {
- dev_priv->r600_group_size = 512;
- } else {
- dev_priv->r600_group_size = 256;
- }
- dev_priv->r600_npipes = 1 << ((gb_tiling_config >> 1) & 0x7);
- if (gb_tiling_config & 0x30) {
- dev_priv->r600_nbanks = 8;
- } else {
- dev_priv->r600_nbanks = 4;
- }
-
- RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
- RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
- RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
-
- RADEON_WRITE(R700_CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
- RADEON_WRITE(R700_CGTS_SYS_TCC_DISABLE, 0);
- RADEON_WRITE(R700_CGTS_TCC_DISABLE, 0);
- RADEON_WRITE(R700_CGTS_USER_SYS_TCC_DISABLE, 0);
- RADEON_WRITE(R700_CGTS_USER_TCC_DISABLE, 0);
-
- num_qd_pipes =
- R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8);
- RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
- RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
-
- /* set HW defaults for 3D engine */
- RADEON_WRITE(R600_CP_QUEUE_THRESHOLDS, (R600_ROQ_IB1_START(0x16) |
- R600_ROQ_IB2_START(0x2b)));
-
- RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, R700_STQ_SPLIT(0x30));
-
- ta_aux_cntl = RADEON_READ(R600_TA_CNTL_AUX);
- RADEON_WRITE(R600_TA_CNTL_AUX, ta_aux_cntl | R600_DISABLE_CUBE_ANISO);
-
- sx_debug_1 = RADEON_READ(R700_SX_DEBUG_1);
- sx_debug_1 |= R700_ENABLE_NEW_SMX_ADDRESS;
- RADEON_WRITE(R700_SX_DEBUG_1, sx_debug_1);
-
- smx_dc_ctl0 = RADEON_READ(R600_SMX_DC_CTL0);
- smx_dc_ctl0 &= ~R700_CACHE_DEPTH(0x1ff);
- smx_dc_ctl0 |= R700_CACHE_DEPTH((dev_priv->r700_sx_num_of_sets * 64) - 1);
- RADEON_WRITE(R600_SMX_DC_CTL0, smx_dc_ctl0);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) != CHIP_RV740)
- RADEON_WRITE(R700_SMX_EVENT_CTL, (R700_ES_FLUSH_CTL(4) |
- R700_GS_FLUSH_CTL(4) |
- R700_ACK_FLUSH_CTL(3) |
- R700_SYNC_FLUSH_CTL));
-
- db_debug3 = RADEON_READ(R700_DB_DEBUG3);
- db_debug3 &= ~R700_DB_CLK_OFF_DELAY(0x1f);
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_RV770:
- case CHIP_RV740:
- db_debug3 |= R700_DB_CLK_OFF_DELAY(0x1f);
- break;
- case CHIP_RV710:
- case CHIP_RV730:
- default:
- db_debug3 |= R700_DB_CLK_OFF_DELAY(2);
- break;
- }
- RADEON_WRITE(R700_DB_DEBUG3, db_debug3);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) != CHIP_RV770) {
- db_debug4 = RADEON_READ(RV700_DB_DEBUG4);
- db_debug4 |= RV700_DISABLE_TILE_COVERED_FOR_PS_ITER;
- RADEON_WRITE(RV700_DB_DEBUG4, db_debug4);
- }
-
- RADEON_WRITE(R600_SX_EXPORT_BUFFER_SIZES, (R600_COLOR_BUFFER_SIZE((dev_priv->r600_sx_max_export_size / 4) - 1) |
- R600_POSITION_BUFFER_SIZE((dev_priv->r600_sx_max_export_pos_size / 4) - 1) |
- R600_SMX_BUFFER_SIZE((dev_priv->r600_sx_max_export_smx_size / 4) - 1)));
-
- RADEON_WRITE(R700_PA_SC_FIFO_SIZE_R7XX, (R700_SC_PRIM_FIFO_SIZE(dev_priv->r700_sc_prim_fifo_size) |
- R700_SC_HIZ_TILE_FIFO_SIZE(dev_priv->r700_sc_hiz_tile_fifo_size) |
- R700_SC_EARLYZ_TILE_FIFO_SIZE(dev_priv->r700_sc_earlyz_tile_fifo_fize)));
-
- RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
-
- RADEON_WRITE(R600_VGT_NUM_INSTANCES, 1);
-
- RADEON_WRITE(R600_SPI_CONFIG_CNTL, R600_GPR_WRITE_PRIORITY(0));
-
- RADEON_WRITE(R600_SPI_CONFIG_CNTL_1, R600_VTX_DONE_DELAY(4));
-
- RADEON_WRITE(R600_CP_PERFMON_CNTL, 0);
-
- sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(16 * dev_priv->r600_sq_num_cf_insts) |
- R600_DONE_FIFO_HIWATER(0xe0) |
- R600_ALU_UPDATE_FIFO_HIWATER(0x8));
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_RV770:
- case CHIP_RV730:
- case CHIP_RV710:
- sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x1);
- break;
- case CHIP_RV740:
- default:
- sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
- break;
- }
- RADEON_WRITE(R600_SQ_MS_FIFO_SIZES, sq_ms_fifo_sizes);
-
- /* SQ_CONFIG, SQ_GPR_RESOURCE_MGMT, SQ_THREAD_RESOURCE_MGMT, SQ_STACK_RESOURCE_MGMT
- * should be adjusted as needed by the 2D/3D drivers. This just sets default values
- */
- sq_config = RADEON_READ(R600_SQ_CONFIG);
- sq_config &= ~(R600_PS_PRIO(3) |
- R600_VS_PRIO(3) |
- R600_GS_PRIO(3) |
- R600_ES_PRIO(3));
- sq_config |= (R600_DX9_CONSTS |
- R600_VC_ENABLE |
- R600_EXPORT_SRC_C |
- R600_PS_PRIO(0) |
- R600_VS_PRIO(1) |
- R600_GS_PRIO(2) |
- R600_ES_PRIO(3));
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)
- /* no vertex cache */
- sq_config &= ~R600_VC_ENABLE;
-
- RADEON_WRITE(R600_SQ_CONFIG, sq_config);
-
- RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_1, (R600_NUM_PS_GPRS((dev_priv->r600_max_gprs * 24)/64) |
- R600_NUM_VS_GPRS((dev_priv->r600_max_gprs * 24)/64) |
- R600_NUM_CLAUSE_TEMP_GPRS(((dev_priv->r600_max_gprs * 24)/64)/2)));
-
- RADEON_WRITE(R600_SQ_GPR_RESOURCE_MGMT_2, (R600_NUM_GS_GPRS((dev_priv->r600_max_gprs * 7)/64) |
- R600_NUM_ES_GPRS((dev_priv->r600_max_gprs * 7)/64)));
-
- sq_thread_resource_mgmt = (R600_NUM_PS_THREADS((dev_priv->r600_max_threads * 4)/8) |
- R600_NUM_VS_THREADS((dev_priv->r600_max_threads * 2)/8) |
- R600_NUM_ES_THREADS((dev_priv->r600_max_threads * 1)/8));
- if (((dev_priv->r600_max_threads * 1) / 8) > dev_priv->r600_max_gs_threads)
- sq_thread_resource_mgmt |= R600_NUM_GS_THREADS(dev_priv->r600_max_gs_threads);
- else
- sq_thread_resource_mgmt |= R600_NUM_GS_THREADS((dev_priv->r600_max_gs_threads * 1)/8);
- RADEON_WRITE(R600_SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt);
-
- RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_1, (R600_NUM_PS_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4) |
- R600_NUM_VS_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4)));
-
- RADEON_WRITE(R600_SQ_STACK_RESOURCE_MGMT_2, (R600_NUM_GS_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4) |
- R600_NUM_ES_STACK_ENTRIES((dev_priv->r600_max_stack_entries * 1)/4)));
-
- sq_dyn_gpr_size_simd_ab_0 = (R700_SIMDA_RING0((dev_priv->r600_max_gprs * 38)/64) |
- R700_SIMDA_RING1((dev_priv->r600_max_gprs * 38)/64) |
- R700_SIMDB_RING0((dev_priv->r600_max_gprs * 38)/64) |
- R700_SIMDB_RING1((dev_priv->r600_max_gprs * 38)/64));
-
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_0, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_1, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_2, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_3, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_4, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_5, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_6, sq_dyn_gpr_size_simd_ab_0);
- RADEON_WRITE(R700_SQ_DYN_GPR_SIZE_SIMD_AB_7, sq_dyn_gpr_size_simd_ab_0);
-
- RADEON_WRITE(R700_PA_SC_FORCE_EOV_MAX_CNTS, (R700_FORCE_EOV_MAX_CLK_CNT(4095) |
- R700_FORCE_EOV_MAX_REZ_CNT(255)));
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)
- RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, (R600_CACHE_INVALIDATION(R600_TC_ONLY) |
- R700_AUTO_INVLD_EN(R700_ES_AND_GS_AUTO)));
- else
- RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, (R600_CACHE_INVALIDATION(R600_VC_AND_TC) |
- R700_AUTO_INVLD_EN(R700_ES_AND_GS_AUTO)));
-
- switch (dev_priv->flags & RADEON_FAMILY_MASK) {
- case CHIP_RV770:
- case CHIP_RV730:
- case CHIP_RV740:
- gs_prim_buffer_depth = 384;
- break;
- case CHIP_RV710:
- gs_prim_buffer_depth = 128;
- break;
- default:
- break;
- }
-
- num_gs_verts_per_thread = dev_priv->r600_max_pipes * 16;
- vgt_gs_per_es = gs_prim_buffer_depth + num_gs_verts_per_thread;
- /* Max value for this is 256 */
- if (vgt_gs_per_es > 256)
- vgt_gs_per_es = 256;
-
- RADEON_WRITE(R600_VGT_ES_PER_GS, 128);
- RADEON_WRITE(R600_VGT_GS_PER_ES, vgt_gs_per_es);
- RADEON_WRITE(R600_VGT_GS_PER_VS, 2);
-
- /* more default values. 2D/3D driver should adjust as needed */
- RADEON_WRITE(R600_VGT_GS_VERTEX_REUSE, 16);
- RADEON_WRITE(R600_PA_SC_LINE_STIPPLE_STATE, 0);
- RADEON_WRITE(R600_VGT_STRMOUT_EN, 0);
- RADEON_WRITE(R600_SX_MISC, 0);
- RADEON_WRITE(R600_PA_SC_MODE_CNTL, 0);
- RADEON_WRITE(R700_PA_SC_EDGERULE, 0xaaaaaaaa);
- RADEON_WRITE(R600_PA_SC_AA_CONFIG, 0);
- RADEON_WRITE(R600_PA_SC_CLIPRECT_RULE, 0xffff);
- RADEON_WRITE(R600_PA_SC_LINE_STIPPLE, 0);
- RADEON_WRITE(R600_SPI_INPUT_Z, 0);
- RADEON_WRITE(R600_SPI_PS_IN_CONTROL_0, R600_NUM_INTERP(2));
- RADEON_WRITE(R600_CB_COLOR7_FRAG, 0);
-
- /* clear render buffer base addresses */
- RADEON_WRITE(R600_CB_COLOR0_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR1_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR2_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR3_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR4_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR5_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR6_BASE, 0);
- RADEON_WRITE(R600_CB_COLOR7_BASE, 0);
-
- RADEON_WRITE(R700_TCP_CNTL, 0);
-
- hdp_host_path_cntl = RADEON_READ(R600_HDP_HOST_PATH_CNTL);
- RADEON_WRITE(R600_HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
-
- RADEON_WRITE(R600_PA_SC_MULTI_CHIP_CNTL, 0);
-
- RADEON_WRITE(R600_PA_CL_ENHANCE, (R600_CLIP_VTX_REORDER_ENA |
- R600_NUM_CLIP_SEQ(3)));
-
-}
-
-static void r600_cp_init_ring_buffer(struct drm_device *dev,
- drm_radeon_private_t *dev_priv,
- struct drm_file *file_priv)
-{
- struct drm_radeon_master_private *master_priv;
- u32 ring_start;
- u64 rptr_addr;
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770))
- r700_gfx_init(dev, dev_priv);
- else
- r600_gfx_init(dev, dev_priv);
-
- RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
- RADEON_READ(R600_GRBM_SOFT_RESET);
- mdelay(15);
- RADEON_WRITE(R600_GRBM_SOFT_RESET, 0);
-
-
- /* Set ring buffer size */
-#ifdef __BIG_ENDIAN
- RADEON_WRITE(R600_CP_RB_CNTL,
- R600_BUF_SWAP_32BIT |
- R600_RB_NO_UPDATE |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#else
- RADEON_WRITE(R600_CP_RB_CNTL,
- RADEON_RB_NO_UPDATE |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#endif
-
- RADEON_WRITE(R600_CP_SEM_WAIT_TIMER, 0x0);
-
- /* Set the write pointer delay */
- RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);
-
-#ifdef __BIG_ENDIAN
- RADEON_WRITE(R600_CP_RB_CNTL,
- R600_BUF_SWAP_32BIT |
- R600_RB_NO_UPDATE |
- R600_RB_RPTR_WR_ENA |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#else
- RADEON_WRITE(R600_CP_RB_CNTL,
- R600_RB_NO_UPDATE |
- R600_RB_RPTR_WR_ENA |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#endif
-
- /* Initialize the ring buffer's read and write pointers */
- RADEON_WRITE(R600_CP_RB_RPTR_WR, 0);
- RADEON_WRITE(R600_CP_RB_WPTR, 0);
- SET_RING_HEAD(dev_priv, 0);
- dev_priv->ring.tail = 0;
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- rptr_addr = dev_priv->ring_rptr->offset
- - dev->agp->base +
- dev_priv->gart_vm_start;
- } else
-#endif
- {
- rptr_addr = dev_priv->ring_rptr->offset
- - ((unsigned long) dev->sg->virtual)
- + dev_priv->gart_vm_start;
- }
- RADEON_WRITE(R600_CP_RB_RPTR_ADDR, (rptr_addr & 0xfffffffc));
- RADEON_WRITE(R600_CP_RB_RPTR_ADDR_HI, upper_32_bits(rptr_addr));
-
-#ifdef __BIG_ENDIAN
- RADEON_WRITE(R600_CP_RB_CNTL,
- RADEON_BUF_SWAP_32BIT |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#else
- RADEON_WRITE(R600_CP_RB_CNTL,
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#endif
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- /* XXX */
- radeon_write_agp_base(dev_priv, dev->agp->base);
-
- /* XXX */
- radeon_write_agp_location(dev_priv,
- (((dev_priv->gart_vm_start - 1 +
- dev_priv->gart_size) & 0xffff0000) |
- (dev_priv->gart_vm_start >> 16)));
-
- ring_start = (dev_priv->cp_ring->offset
- - dev->agp->base
- + dev_priv->gart_vm_start);
- } else
-#endif
- ring_start = (dev_priv->cp_ring->offset
- - (unsigned long)dev->sg->virtual
- + dev_priv->gart_vm_start);
-
- RADEON_WRITE(R600_CP_RB_BASE, ring_start >> 8);
-
- RADEON_WRITE(R600_CP_ME_CNTL, 0xff);
-
- RADEON_WRITE(R600_CP_DEBUG, (1 << 27) | (1 << 28));
-
- /* Initialize the scratch register pointer. This will cause
- * the scratch register values to be written out to memory
- * whenever they are updated.
- *
- * We simply put this behind the ring read pointer, this works
- * with PCI GART as well as (whatever kind of) AGP GART
- */
- {
- u64 scratch_addr;
-
- scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR) & 0xFFFFFFFC;
- scratch_addr |= ((u64)RADEON_READ(R600_CP_RB_RPTR_ADDR_HI)) << 32;
- scratch_addr += R600_SCRATCH_REG_OFFSET;
- scratch_addr >>= 8;
- scratch_addr &= 0xffffffff;
-
- RADEON_WRITE(R600_SCRATCH_ADDR, (uint32_t)scratch_addr);
- }
-
- RADEON_WRITE(R600_SCRATCH_UMSK, 0x7);
-
- /* Turn on bus mastering */
- radeon_enable_bm(dev_priv);
-
- radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(0), 0);
- RADEON_WRITE(R600_LAST_FRAME_REG, 0);
-
- radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(1), 0);
- RADEON_WRITE(R600_LAST_DISPATCH_REG, 0);
-
- radeon_write_ring_rptr(dev_priv, R600_SCRATCHOFF(2), 0);
- RADEON_WRITE(R600_LAST_CLEAR_REG, 0);
-
- /* reset sarea copies of these */
- master_priv = file_priv->master->driver_priv;
- if (master_priv->sarea_priv) {
- master_priv->sarea_priv->last_frame = 0;
- master_priv->sarea_priv->last_dispatch = 0;
- master_priv->sarea_priv->last_clear = 0;
- }
-
- r600_do_wait_for_idle(dev_priv);
-
-}
-
-int r600_do_cleanup_cp(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- /* Make sure interrupts are disabled here because the uninstall ioctl
- * may not have been called from userspace and after dev_private
- * is freed, it's too late.
- */
- if (dev->irq_enabled)
- drm_irq_uninstall(dev);
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- if (dev_priv->cp_ring != NULL) {
- drm_legacy_ioremapfree(dev_priv->cp_ring, dev);
- dev_priv->cp_ring = NULL;
- }
- if (dev_priv->ring_rptr != NULL) {
- drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
- dev_priv->ring_rptr = NULL;
- }
- if (dev->agp_buffer_map != NULL) {
- drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
- dev->agp_buffer_map = NULL;
- }
- } else
-#endif
- {
-
- if (dev_priv->gart_info.bus_addr)
- r600_page_table_cleanup(dev, &dev_priv->gart_info);
-
- if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) {
- drm_legacy_ioremapfree(&dev_priv->gart_info.mapping, dev);
- dev_priv->gart_info.addr = NULL;
- }
- }
- /* only clear to the start of flags */
- memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags));
-
- return 0;
-}
-
-int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
- struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
-
- DRM_DEBUG("\n");
-
- mutex_init(&dev_priv->cs_mutex);
- r600_cs_legacy_init();
- /* if we require new memory map but we don't have it fail */
- if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
- DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
- DRM_DEBUG("Forcing AGP card to PCI mode\n");
- dev_priv->flags &= ~RADEON_IS_AGP;
- /* The writeback test succeeds, but when writeback is enabled,
- * the ring buffer read ptr update fails after first 128 bytes.
- */
- radeon_no_wb = 1;
- } else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
- && !init->is_pci) {
- DRM_DEBUG("Restoring AGP flag\n");
- dev_priv->flags |= RADEON_IS_AGP;
- }
-
- dev_priv->usec_timeout = init->usec_timeout;
- if (dev_priv->usec_timeout < 1 ||
- dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
- DRM_DEBUG("TIMEOUT problem!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- /* Enable vblank on CRTC1 for older X servers
- */
- dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
- dev_priv->do_boxes = 0;
- dev_priv->cp_mode = init->cp_mode;
-
- /* We don't support anything other than bus-mastering ring mode,
- * but the ring can be in either AGP or PCI space for the ring
- * read pointer.
- */
- if ((init->cp_mode != RADEON_CSQ_PRIBM_INDDIS) &&
- (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
- DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- switch (init->fb_bpp) {
- case 16:
- dev_priv->color_fmt = RADEON_COLOR_FORMAT_RGB565;
- break;
- case 32:
- default:
- dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888;
- break;
- }
- dev_priv->front_offset = init->front_offset;
- dev_priv->front_pitch = init->front_pitch;
- dev_priv->back_offset = init->back_offset;
- dev_priv->back_pitch = init->back_pitch;
-
- dev_priv->ring_offset = init->ring_offset;
- dev_priv->ring_rptr_offset = init->ring_rptr_offset;
- dev_priv->buffers_offset = init->buffers_offset;
- dev_priv->gart_textures_offset = init->gart_textures_offset;
-
- master_priv->sarea = drm_legacy_getsarea(dev);
- if (!master_priv->sarea) {
- DRM_ERROR("could not find sarea!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- dev_priv->cp_ring = drm_legacy_findmap(dev, init->ring_offset);
- if (!dev_priv->cp_ring) {
- DRM_ERROR("could not find cp ring region!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
- dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
- if (!dev_priv->ring_rptr) {
- DRM_ERROR("could not find ring read pointer!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
- dev->agp_buffer_token = init->buffers_offset;
- dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
- if (!dev->agp_buffer_map) {
- DRM_ERROR("could not find dma buffer region!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- if (init->gart_textures_offset) {
- dev_priv->gart_textures =
- drm_legacy_findmap(dev, init->gart_textures_offset);
- if (!dev_priv->gart_textures) {
- DRM_ERROR("could not find GART texture region!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
- }
-
-#if IS_ENABLED(CONFIG_AGP)
- /* XXX */
- if (dev_priv->flags & RADEON_IS_AGP) {
- drm_legacy_ioremap_wc(dev_priv->cp_ring, dev);
- drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
- drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
- if (!dev_priv->cp_ring->handle ||
- !dev_priv->ring_rptr->handle ||
- !dev->agp_buffer_map->handle) {
- DRM_ERROR("could not find ioremap agp regions!\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
- } else
-#endif
- {
- dev_priv->cp_ring->handle = (void *)(unsigned long)dev_priv->cp_ring->offset;
- dev_priv->ring_rptr->handle =
- (void *)(unsigned long)dev_priv->ring_rptr->offset;
- dev->agp_buffer_map->handle =
- (void *)(unsigned long)dev->agp_buffer_map->offset;
-
- DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
- dev_priv->cp_ring->handle);
- DRM_DEBUG("dev_priv->ring_rptr->handle %p\n",
- dev_priv->ring_rptr->handle);
- DRM_DEBUG("dev->agp_buffer_map->handle %p\n",
- dev->agp_buffer_map->handle);
- }
-
- dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 24;
- dev_priv->fb_size =
- (((radeon_read_fb_location(dev_priv) & 0xffff0000u) << 8) + 0x1000000)
- - dev_priv->fb_location;
-
- dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
- ((dev_priv->front_offset
- + dev_priv->fb_location) >> 10));
-
- dev_priv->back_pitch_offset = (((dev_priv->back_pitch / 64) << 22) |
- ((dev_priv->back_offset
- + dev_priv->fb_location) >> 10));
-
- dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch / 64) << 22) |
- ((dev_priv->depth_offset
- + dev_priv->fb_location) >> 10));
-
- dev_priv->gart_size = init->gart_size;
-
- /* New let's set the memory map ... */
- if (dev_priv->new_memmap) {
- u32 base = 0;
-
- DRM_INFO("Setting GART location based on new memory map\n");
-
- /* If using AGP, try to locate the AGP aperture at the same
- * location in the card and on the bus, though we have to
- * align it down.
- */
-#if IS_ENABLED(CONFIG_AGP)
- /* XXX */
- if (dev_priv->flags & RADEON_IS_AGP) {
- base = dev->agp->base;
- /* Check if valid */
- if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
- base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
- DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
- dev->agp->base);
- base = 0;
- }
- }
-#endif
- /* If not or if AGP is at 0 (Macs), try to put it elsewhere */
- if (base == 0) {
- base = dev_priv->fb_location + dev_priv->fb_size;
- if (base < dev_priv->fb_location ||
- ((base + dev_priv->gart_size) & 0xfffffffful) < base)
- base = dev_priv->fb_location
- - dev_priv->gart_size;
- }
- dev_priv->gart_vm_start = base & 0xffc00000u;
- if (dev_priv->gart_vm_start != base)
- DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
- base, dev_priv->gart_vm_start);
- }
-
-#if IS_ENABLED(CONFIG_AGP)
- /* XXX */
- if (dev_priv->flags & RADEON_IS_AGP)
- dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
- - dev->agp->base
- + dev_priv->gart_vm_start);
- else
-#endif
- dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
- - (unsigned long)dev->sg->virtual
- + dev_priv->gart_vm_start);
-
- DRM_DEBUG("fb 0x%08x size %d\n",
- (unsigned int) dev_priv->fb_location,
- (unsigned int) dev_priv->fb_size);
- DRM_DEBUG("dev_priv->gart_size %d\n", dev_priv->gart_size);
- DRM_DEBUG("dev_priv->gart_vm_start 0x%08x\n",
- (unsigned int) dev_priv->gart_vm_start);
- DRM_DEBUG("dev_priv->gart_buffers_offset 0x%08lx\n",
- dev_priv->gart_buffers_offset);
-
- dev_priv->ring.start = (u32 *) dev_priv->cp_ring->handle;
- dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
- + init->ring_size / sizeof(u32));
- dev_priv->ring.size = init->ring_size;
- dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
-
- dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
- dev_priv->ring.rptr_update_l2qw = order_base_2(/* init->rptr_update */ 4096 / 8);
-
- dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
- dev_priv->ring.fetch_size_l2ow = order_base_2(/* init->fetch_size */ 32 / 16);
-
- dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
-
- dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- /* XXX turn off pcie gart */
- } else
-#endif
- {
- dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
- /* if we have an offset set from userspace */
- if (!dev_priv->pcigart_offset_set) {
- DRM_ERROR("Need gart offset from userspace\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- DRM_DEBUG("Using gart offset 0x%08lx\n", dev_priv->pcigart_offset);
-
- dev_priv->gart_info.bus_addr =
- dev_priv->pcigart_offset + dev_priv->fb_location;
- dev_priv->gart_info.mapping.offset =
- dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
- dev_priv->gart_info.mapping.size =
- dev_priv->gart_info.table_size;
-
- drm_legacy_ioremap_wc(&dev_priv->gart_info.mapping, dev);
- if (!dev_priv->gart_info.mapping.handle) {
- DRM_ERROR("ioremap failed.\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- dev_priv->gart_info.addr =
- dev_priv->gart_info.mapping.handle;
-
- DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n",
- dev_priv->gart_info.addr,
- dev_priv->pcigart_offset);
-
- if (!r600_page_table_init(dev)) {
- DRM_ERROR("Failed to init GART table\n");
- r600_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770))
- r700_vm_init(dev);
- else
- r600_vm_init(dev);
- }
-
- if (!dev_priv->me_fw || !dev_priv->pfp_fw) {
- int err = r600_cp_init_microcode(dev_priv);
- if (err) {
- DRM_ERROR("Failed to load firmware!\n");
- r600_do_cleanup_cp(dev);
- return err;
- }
- }
- if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770))
- r700_cp_load_microcode(dev_priv);
- else
- r600_cp_load_microcode(dev_priv);
-
- r600_cp_init_ring_buffer(dev, dev_priv, file_priv);
-
- dev_priv->last_buf = 0;
-
- r600_do_engine_reset(dev);
- r600_test_writeback(dev_priv);
-
- return 0;
-}
-
-int r600_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- DRM_DEBUG("\n");
- if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)) {
- r700_vm_init(dev);
- r700_cp_load_microcode(dev_priv);
- } else {
- r600_vm_init(dev);
- r600_cp_load_microcode(dev_priv);
- }
- r600_cp_init_ring_buffer(dev, dev_priv, file_priv);
- r600_do_engine_reset(dev);
-
- return 0;
-}
-
-/* Wait for the CP to go idle.
- */
-int r600_do_cp_idle(drm_radeon_private_t *dev_priv)
-{
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(5);
- OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
- OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT);
- /* wait for 3D idle clean */
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1));
- OUT_RING((R600_WAIT_UNTIL - R600_SET_CONFIG_REG_OFFSET) >> 2);
- OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_3D_IDLECLEAN);
-
- ADVANCE_RING();
- COMMIT_RING();
-
- return r600_do_wait_for_idle(dev_priv);
-}
-
-/* Start the Command Processor.
- */
-void r600_do_cp_start(drm_radeon_private_t *dev_priv)
-{
- u32 cp_me;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(7);
- OUT_RING(CP_PACKET3(R600_IT_ME_INITIALIZE, 5));
- OUT_RING(0x00000001);
- if (((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV770))
- OUT_RING(0x00000003);
- else
- OUT_RING(0x00000000);
- OUT_RING((dev_priv->r600_max_hw_contexts - 1));
- OUT_RING(R600_ME_INITIALIZE_DEVICE_ID(1));
- OUT_RING(0x00000000);
- OUT_RING(0x00000000);
- ADVANCE_RING();
- COMMIT_RING();
-
- /* set the mux and reset the halt bit */
- cp_me = 0xff;
- RADEON_WRITE(R600_CP_ME_CNTL, cp_me);
-
- dev_priv->cp_running = 1;
-
-}
-
-void r600_do_cp_reset(drm_radeon_private_t *dev_priv)
-{
- u32 cur_read_ptr;
- DRM_DEBUG("\n");
-
- cur_read_ptr = RADEON_READ(R600_CP_RB_RPTR);
- RADEON_WRITE(R600_CP_RB_WPTR, cur_read_ptr);
- SET_RING_HEAD(dev_priv, cur_read_ptr);
- dev_priv->ring.tail = cur_read_ptr;
-}
-
-void r600_do_cp_stop(drm_radeon_private_t *dev_priv)
-{
- uint32_t cp_me;
-
- DRM_DEBUG("\n");
-
- cp_me = 0xff | R600_CP_ME_HALT;
-
- RADEON_WRITE(R600_CP_ME_CNTL, cp_me);
-
- dev_priv->cp_running = 0;
-}
-
-int r600_cp_dispatch_indirect(struct drm_device *dev,
- struct drm_buf *buf, int start, int end)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
-
- if (start != end) {
- unsigned long offset = (dev_priv->gart_buffers_offset
- + buf->offset + start);
- int dwords = (end - start + 3) / sizeof(u32);
-
- DRM_DEBUG("dwords:%d\n", dwords);
- DRM_DEBUG("offset 0x%lx\n", offset);
-
-
- /* Indirect buffer data must be a multiple of 16 dwords.
- * pad the data with a Type-2 CP packet.
- */
- while (dwords & 0xf) {
- u32 *data = (u32 *)
- ((char *)dev->agp_buffer_map->handle
- + buf->offset + start);
- data[dwords++] = RADEON_CP_PACKET2;
- }
-
- /* Fire off the indirect buffer */
- BEGIN_RING(4);
- OUT_RING(CP_PACKET3(R600_IT_INDIRECT_BUFFER, 2));
- OUT_RING((offset & 0xfffffffc));
- OUT_RING((upper_32_bits(offset) & 0xff));
- OUT_RING(dwords);
- ADVANCE_RING();
- }
-
- return 0;
-}
-
-void r600_cp_dispatch_swap(struct drm_device *dev, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_master *master = file_priv->master;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int i, cpp, src_pitch, dst_pitch;
- uint64_t src, dst;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- if (dev_priv->color_fmt == RADEON_COLOR_FORMAT_ARGB8888)
- cpp = 4;
- else
- cpp = 2;
-
- if (sarea_priv->pfCurrentPage == 0) {
- src_pitch = dev_priv->back_pitch;
- dst_pitch = dev_priv->front_pitch;
- src = dev_priv->back_offset + dev_priv->fb_location;
- dst = dev_priv->front_offset + dev_priv->fb_location;
- } else {
- src_pitch = dev_priv->front_pitch;
- dst_pitch = dev_priv->back_pitch;
- src = dev_priv->front_offset + dev_priv->fb_location;
- dst = dev_priv->back_offset + dev_priv->fb_location;
- }
-
- if (r600_prepare_blit_copy(dev, file_priv)) {
- DRM_ERROR("unable to allocate vertex buffer for swap buffer\n");
- return;
- }
- for (i = 0; i < nbox; i++) {
- int x = pbox[i].x1;
- int y = pbox[i].y1;
- int w = pbox[i].x2 - x;
- int h = pbox[i].y2 - y;
-
- DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
-
- r600_blit_swap(dev,
- src, dst,
- x, y, x, y, w, h,
- src_pitch, dst_pitch, cpp);
- }
- r600_done_blit_copy(dev);
-
- /* Increment the frame counter. The client-side 3D driver must
- * throttle the framerate by waiting for this value before
- * performing the swapbuffer ioctl.
- */
- sarea_priv->last_frame++;
-
- BEGIN_RING(3);
- R600_FRAME_AGE(sarea_priv->last_frame);
- ADVANCE_RING();
-}
-
-int r600_cp_dispatch_texture(struct drm_device *dev,
- struct drm_file *file_priv,
- drm_radeon_texture_t *tex,
- drm_radeon_tex_image_t *image)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_buf *buf;
- u32 *buffer;
- const u8 __user *data;
- unsigned int size, pass_size;
- u64 src_offset, dst_offset;
-
- if (!radeon_check_offset(dev_priv, tex->offset)) {
- DRM_ERROR("Invalid destination offset\n");
- return -EINVAL;
- }
-
- /* this might fail for zero-sized uploads - are those illegal? */
- if (!radeon_check_offset(dev_priv, tex->offset + tex->height * tex->pitch - 1)) {
- DRM_ERROR("Invalid final destination offset\n");
- return -EINVAL;
- }
-
- size = tex->height * tex->pitch;
-
- if (size == 0)
- return 0;
-
- dst_offset = tex->offset;
-
- if (r600_prepare_blit_copy(dev, file_priv)) {
- DRM_ERROR("unable to allocate vertex buffer for swap buffer\n");
- return -EAGAIN;
- }
- do {
- data = (const u8 __user *)image->data;
- pass_size = size;
-
- buf = radeon_freelist_get(dev);
- if (!buf) {
- DRM_DEBUG("EAGAIN\n");
- if (copy_to_user(tex->image, image, sizeof(*image)))
- return -EFAULT;
- return -EAGAIN;
- }
-
- if (pass_size > buf->total)
- pass_size = buf->total;
-
- /* Dispatch the indirect buffer.
- */
- buffer =
- (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
-
- if (copy_from_user(buffer, data, pass_size)) {
- DRM_ERROR("EFAULT on pad, %d bytes\n", pass_size);
- return -EFAULT;
- }
-
- buf->file_priv = file_priv;
- buf->used = pass_size;
- src_offset = dev_priv->gart_buffers_offset + buf->offset;
-
- r600_blit_copy(dev, src_offset, dst_offset, pass_size);
-
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
-
- /* Update the input parameters for next time */
- image->data = (const u8 __user *)image->data + pass_size;
- dst_offset += pass_size;
- size -= pass_size;
- } while (size > 0);
- r600_done_blit_copy(dev);
-
- return 0;
-}
-
-/*
- * Legacy cs ioctl
- */
-static u32 radeon_cs_id_get(struct drm_radeon_private *radeon)
-{
- /* FIXME: check if wrap affect last reported wrap & sequence */
- radeon->cs_id_scnt = (radeon->cs_id_scnt + 1) & 0x00FFFFFF;
- if (!radeon->cs_id_scnt) {
- /* increment wrap counter */
- radeon->cs_id_wcnt += 0x01000000;
- /* valid sequence counter start at 1 */
- radeon->cs_id_scnt = 1;
- }
- return (radeon->cs_id_scnt | radeon->cs_id_wcnt);
-}
-
-static void r600_cs_id_emit(drm_radeon_private_t *dev_priv, u32 *id)
-{
- RING_LOCALS;
-
- *id = radeon_cs_id_get(dev_priv);
-
- /* SCRATCH 2 */
- BEGIN_RING(3);
- R600_CLEAR_AGE(*id);
- ADVANCE_RING();
- COMMIT_RING();
-}
-
-static int r600_ib_get(struct drm_device *dev,
- struct drm_file *fpriv,
- struct drm_buf **buffer)
-{
- struct drm_buf *buf;
-
- *buffer = NULL;
- buf = radeon_freelist_get(dev);
- if (!buf) {
- return -EBUSY;
- }
- buf->file_priv = fpriv;
- *buffer = buf;
- return 0;
-}
-
-static void r600_ib_free(struct drm_device *dev, struct drm_buf *buf,
- struct drm_file *fpriv, int l, int r)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if (buf) {
- if (!r)
- r600_cp_dispatch_indirect(dev, buf, 0, l * 4);
- radeon_cp_discard_buffer(dev, fpriv->master, buf);
- COMMIT_RING();
- }
-}
-
-int r600_cs_legacy_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
-{
- struct drm_radeon_private *dev_priv = dev->dev_private;
- struct drm_radeon_cs *cs = data;
- struct drm_buf *buf;
- unsigned family;
- int l, r = 0;
- u32 *ib, cs_id = 0;
-
- if (dev_priv == NULL) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
- family = dev_priv->flags & RADEON_FAMILY_MASK;
- if (family < CHIP_R600) {
- DRM_ERROR("cs ioctl valid only for R6XX & R7XX in legacy mode\n");
- return -EINVAL;
- }
- mutex_lock(&dev_priv->cs_mutex);
- /* get ib */
- r = r600_ib_get(dev, fpriv, &buf);
- if (r) {
- DRM_ERROR("ib_get failed\n");
- goto out;
- }
- ib = dev->agp_buffer_map->handle + buf->offset;
- /* now parse command stream */
- r = r600_cs_legacy(dev, data, fpriv, family, ib, &l);
- if (r) {
- goto out;
- }
-
-out:
- r600_ib_free(dev, buf, fpriv, l, r);
- /* emit cs id sequence */
- r600_cs_id_emit(dev_priv, &cs_id);
- cs->cs_id = cs_id;
- mutex_unlock(&dev_priv->cs_mutex);
- return r;
-}
-
-void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size)
-{
- struct drm_radeon_private *dev_priv = dev->dev_private;
-
- *npipes = dev_priv->r600_npipes;
- *nbanks = dev_priv->r600_nbanks;
- *group_size = dev_priv->r600_group_size;
-}
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index acc1f99c84d9..2f36fa1576e0 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -2328,101 +2328,6 @@ int r600_cs_parse(struct radeon_cs_parser *p)
return 0;
}
-#ifdef CONFIG_DRM_RADEON_UMS
-
-/**
- * cs_parser_fini() - clean parser states
- * @parser: parser structure holding parsing context.
- * @error: error number
- *
- * If error is set than unvalidate buffer, otherwise just free memory
- * used by parsing context.
- **/
-static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error)
-{
- unsigned i;
-
- kfree(parser->relocs);
- for (i = 0; i < parser->nchunks; i++)
- drm_free_large(parser->chunks[i].kdata);
- kfree(parser->chunks);
- kfree(parser->chunks_array);
-}
-
-static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p)
-{
- if (p->chunk_relocs == NULL) {
- return 0;
- }
- p->relocs = kzalloc(sizeof(struct radeon_bo_list), GFP_KERNEL);
- if (p->relocs == NULL) {
- return -ENOMEM;
- }
- return 0;
-}
-
-int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
- unsigned family, u32 *ib, int *l)
-{
- struct radeon_cs_parser parser;
- struct radeon_cs_chunk *ib_chunk;
- struct r600_cs_track *track;
- int r;
-
- /* initialize tracker */
- track = kzalloc(sizeof(*track), GFP_KERNEL);
- if (track == NULL)
- return -ENOMEM;
- r600_cs_track_init(track);
- r600_cs_legacy_get_tiling_conf(dev, &track->npipes, &track->nbanks, &track->group_size);
- /* initialize parser */
- memset(&parser, 0, sizeof(struct radeon_cs_parser));
- parser.filp = filp;
- parser.dev = &dev->pdev->dev;
- parser.rdev = NULL;
- parser.family = family;
- parser.track = track;
- parser.ib.ptr = ib;
- r = radeon_cs_parser_init(&parser, data);
- if (r) {
- DRM_ERROR("Failed to initialize parser !\n");
- r600_cs_parser_fini(&parser, r);
- return r;
- }
- r = r600_cs_parser_relocs_legacy(&parser);
- if (r) {
- DRM_ERROR("Failed to parse relocation !\n");
- r600_cs_parser_fini(&parser, r);
- return r;
- }
- /* Copy the packet into the IB, the parser will read from the
- * input memory (cached) and write to the IB (which can be
- * uncached). */
- ib_chunk = parser.chunk_ib;
- parser.ib.length_dw = ib_chunk->length_dw;
- *l = parser.ib.length_dw;
- if (copy_from_user(ib, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) {
- r = -EFAULT;
- r600_cs_parser_fini(&parser, r);
- return r;
- }
- r = r600_cs_parse(&parser);
- if (r) {
- DRM_ERROR("Invalid command stream !\n");
- r600_cs_parser_fini(&parser, r);
- return r;
- }
- r600_cs_parser_fini(&parser, r);
- return r;
-}
-
-void r600_cs_legacy_init(void)
-{
- r600_nomm = 1;
-}
-
-#endif
-
/*
* DMA
*/
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 87db64983ea8..5ae6db98aa4d 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -268,6 +268,7 @@ struct radeon_clock {
uint32_t current_dispclk;
uint32_t dp_extclk;
uint32_t max_pixel_clock;
+ uint32_t gpupll_outputfreq;
};
/*
@@ -1889,7 +1890,7 @@ struct radeon_asic {
void (*pad_ib)(struct radeon_ib *ib);
} vm;
/* ring specific callbacks */
- struct radeon_asic_ring *ring[RADEON_NUM_RINGS];
+ const struct radeon_asic_ring *ring[RADEON_NUM_RINGS];
/* irqs */
struct {
int (*set)(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 1d4d4520a0ac..7d5a36dd5094 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -179,7 +179,7 @@ void radeon_agp_disable(struct radeon_device *rdev)
* ASIC
*/
-static struct radeon_asic_ring r100_gfx_ring = {
+static const struct radeon_asic_ring r100_gfx_ring = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r100_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
@@ -329,7 +329,7 @@ static struct radeon_asic r200_asic = {
},
};
-static struct radeon_asic_ring r300_gfx_ring = {
+static const struct radeon_asic_ring r300_gfx_ring = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
@@ -343,7 +343,7 @@ static struct radeon_asic_ring r300_gfx_ring = {
.set_wptr = &r100_gfx_set_wptr,
};
-static struct radeon_asic_ring rv515_gfx_ring = {
+static const struct radeon_asic_ring rv515_gfx_ring = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
@@ -901,7 +901,7 @@ static struct radeon_asic r520_asic = {
},
};
-static struct radeon_asic_ring r600_gfx_ring = {
+static const struct radeon_asic_ring r600_gfx_ring = {
.ib_execute = &r600_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
@@ -914,7 +914,7 @@ static struct radeon_asic_ring r600_gfx_ring = {
.set_wptr = &r600_gfx_set_wptr,
};
-static struct radeon_asic_ring r600_dma_ring = {
+static const struct radeon_asic_ring r600_dma_ring = {
.ib_execute = &r600_dma_ring_ib_execute,
.emit_fence = &r600_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
@@ -999,7 +999,7 @@ static struct radeon_asic r600_asic = {
},
};
-static struct radeon_asic_ring rv6xx_uvd_ring = {
+static const struct radeon_asic_ring rv6xx_uvd_ring = {
.ib_execute = &uvd_v1_0_ib_execute,
.emit_fence = &uvd_v1_0_fence_emit,
.emit_semaphore = &uvd_v1_0_semaphore_emit,
@@ -1198,7 +1198,7 @@ static struct radeon_asic rs780_asic = {
},
};
-static struct radeon_asic_ring rv770_uvd_ring = {
+static const struct radeon_asic_ring rv770_uvd_ring = {
.ib_execute = &uvd_v1_0_ib_execute,
.emit_fence = &uvd_v2_2_fence_emit,
.emit_semaphore = &uvd_v2_2_semaphore_emit,
@@ -1305,7 +1305,7 @@ static struct radeon_asic rv770_asic = {
},
};
-static struct radeon_asic_ring evergreen_gfx_ring = {
+static const struct radeon_asic_ring evergreen_gfx_ring = {
.ib_execute = &evergreen_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
@@ -1318,7 +1318,7 @@ static struct radeon_asic_ring evergreen_gfx_ring = {
.set_wptr = &r600_gfx_set_wptr,
};
-static struct radeon_asic_ring evergreen_dma_ring = {
+static const struct radeon_asic_ring evergreen_dma_ring = {
.ib_execute = &evergreen_dma_ring_ib_execute,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
@@ -1612,7 +1612,7 @@ static struct radeon_asic btc_asic = {
},
};
-static struct radeon_asic_ring cayman_gfx_ring = {
+static const struct radeon_asic_ring cayman_gfx_ring = {
.ib_execute = &cayman_ring_ib_execute,
.ib_parse = &evergreen_ib_parse,
.emit_fence = &cayman_fence_ring_emit,
@@ -1627,7 +1627,7 @@ static struct radeon_asic_ring cayman_gfx_ring = {
.set_wptr = &cayman_gfx_set_wptr,
};
-static struct radeon_asic_ring cayman_dma_ring = {
+static const struct radeon_asic_ring cayman_dma_ring = {
.ib_execute = &cayman_dma_ring_ib_execute,
.ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
@@ -1642,7 +1642,7 @@ static struct radeon_asic_ring cayman_dma_ring = {
.set_wptr = &cayman_dma_set_wptr
};
-static struct radeon_asic_ring cayman_uvd_ring = {
+static const struct radeon_asic_ring cayman_uvd_ring = {
.ib_execute = &uvd_v1_0_ib_execute,
.emit_fence = &uvd_v2_2_fence_emit,
.emit_semaphore = &uvd_v3_1_semaphore_emit,
@@ -1760,7 +1760,7 @@ static struct radeon_asic cayman_asic = {
},
};
-static struct radeon_asic_ring trinity_vce_ring = {
+static const struct radeon_asic_ring trinity_vce_ring = {
.ib_execute = &radeon_vce_ib_execute,
.emit_fence = &radeon_vce_fence_emit,
.emit_semaphore = &radeon_vce_semaphore_emit,
@@ -1881,7 +1881,7 @@ static struct radeon_asic trinity_asic = {
},
};
-static struct radeon_asic_ring si_gfx_ring = {
+static const struct radeon_asic_ring si_gfx_ring = {
.ib_execute = &si_ring_ib_execute,
.ib_parse = &si_ib_parse,
.emit_fence = &si_fence_ring_emit,
@@ -1896,7 +1896,7 @@ static struct radeon_asic_ring si_gfx_ring = {
.set_wptr = &cayman_gfx_set_wptr,
};
-static struct radeon_asic_ring si_dma_ring = {
+static const struct radeon_asic_ring si_dma_ring = {
.ib_execute = &cayman_dma_ring_ib_execute,
.ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
@@ -2023,7 +2023,7 @@ static struct radeon_asic si_asic = {
},
};
-static struct radeon_asic_ring ci_gfx_ring = {
+static const struct radeon_asic_ring ci_gfx_ring = {
.ib_execute = &cik_ring_ib_execute,
.ib_parse = &cik_ib_parse,
.emit_fence = &cik_fence_gfx_ring_emit,
@@ -2038,7 +2038,7 @@ static struct radeon_asic_ring ci_gfx_ring = {
.set_wptr = &cik_gfx_set_wptr,
};
-static struct radeon_asic_ring ci_cp_ring = {
+static const struct radeon_asic_ring ci_cp_ring = {
.ib_execute = &cik_ring_ib_execute,
.ib_parse = &cik_ib_parse,
.emit_fence = &cik_fence_compute_ring_emit,
@@ -2053,7 +2053,7 @@ static struct radeon_asic_ring ci_cp_ring = {
.set_wptr = &cik_compute_set_wptr,
};
-static struct radeon_asic_ring ci_dma_ring = {
+static const struct radeon_asic_ring ci_dma_ring = {
.ib_execute = &cik_sdma_ring_ib_execute,
.ib_parse = &cik_ib_parse,
.emit_fence = &cik_sdma_fence_ring_emit,
@@ -2068,7 +2068,7 @@ static struct radeon_asic_ring ci_dma_ring = {
.set_wptr = &cik_sdma_set_wptr,
};
-static struct radeon_asic_ring ci_vce_ring = {
+static const struct radeon_asic_ring ci_vce_ring = {
.ib_execute = &radeon_vce_ib_execute,
.emit_fence = &radeon_vce_fence_emit,
.emit_semaphore = &radeon_vce_semaphore_emit,
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 8f285244c839..08fc1b5effa8 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -437,7 +437,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
}
/* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
- if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) &&
+ if (((dev->pdev->device == 0x9802) ||
+ (dev->pdev->device == 0x9805) ||
+ (dev->pdev->device == 0x9806)) &&
(dev->pdev->subsystem_vendor == 0x1734) &&
(dev->pdev->subsystem_device == 0x11bd)) {
if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
@@ -448,14 +450,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
}
}
- /* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */
- if ((dev->pdev->device == 0x9805) &&
- (dev->pdev->subsystem_vendor == 0x1734) &&
- (dev->pdev->subsystem_device == 0x11bd)) {
- if (*connector_type == DRM_MODE_CONNECTOR_VGA)
- return false;
- }
-
return true;
}
@@ -1263,6 +1257,13 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
rdev->mode_info.firmware_flags =
le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
+ if (ASIC_IS_DCE8(rdev)) {
+ rdev->clock.gpupll_outputfreq =
+ le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq);
+ if (rdev->clock.gpupll_outputfreq == 0)
+ rdev->clock.gpupll_outputfreq = 360000; /* 3.6 GHz */
+ }
+
return true;
}
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
deleted file mode 100644
index 500287eff55d..000000000000
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ /dev/null
@@ -1,2243 +0,0 @@
-/* radeon_cp.c -- CP support for Radeon -*- linux-c -*- */
-/*
- * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
- * Copyright 2007 Advanced Micro Devices, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, 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
- * PRECISION INSIGHT 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:
- * Kevin E. Martin <martin@valinux.com>
- * Gareth Hughes <gareth@valinux.com>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-
-#include <linux/module.h>
-
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-#include "r300_reg.h"
-
-#define RADEON_FIFO_DEBUG 0
-
-/* Firmware Names */
-#define FIRMWARE_R100 "radeon/R100_cp.bin"
-#define FIRMWARE_R200 "radeon/R200_cp.bin"
-#define FIRMWARE_R300 "radeon/R300_cp.bin"
-#define FIRMWARE_R420 "radeon/R420_cp.bin"
-#define FIRMWARE_RS690 "radeon/RS690_cp.bin"
-#define FIRMWARE_RS600 "radeon/RS600_cp.bin"
-#define FIRMWARE_R520 "radeon/R520_cp.bin"
-
-MODULE_FIRMWARE(FIRMWARE_R100);
-MODULE_FIRMWARE(FIRMWARE_R200);
-MODULE_FIRMWARE(FIRMWARE_R300);
-MODULE_FIRMWARE(FIRMWARE_R420);
-MODULE_FIRMWARE(FIRMWARE_RS690);
-MODULE_FIRMWARE(FIRMWARE_RS600);
-MODULE_FIRMWARE(FIRMWARE_R520);
-
-static int radeon_do_cleanup_cp(struct drm_device * dev);
-static void radeon_do_cp_start(drm_radeon_private_t * dev_priv);
-
-u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off)
-{
- u32 val;
-
- if (dev_priv->flags & RADEON_IS_AGP) {
- val = DRM_READ32(dev_priv->ring_rptr, off);
- } else {
- val = *(((volatile u32 *)
- dev_priv->ring_rptr->handle) +
- (off / sizeof(u32)));
- val = le32_to_cpu(val);
- }
- return val;
-}
-
-u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv)
-{
- if (dev_priv->writeback_works)
- return radeon_read_ring_rptr(dev_priv, 0);
- else {
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return RADEON_READ(R600_CP_RB_RPTR);
- else
- return RADEON_READ(RADEON_CP_RB_RPTR);
- }
-}
-
-void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val)
-{
- if (dev_priv->flags & RADEON_IS_AGP)
- DRM_WRITE32(dev_priv->ring_rptr, off, val);
- else
- *(((volatile u32 *) dev_priv->ring_rptr->handle) +
- (off / sizeof(u32))) = cpu_to_le32(val);
-}
-
-void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val)
-{
- radeon_write_ring_rptr(dev_priv, 0, val);
-}
-
-u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index)
-{
- if (dev_priv->writeback_works) {
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return radeon_read_ring_rptr(dev_priv,
- R600_SCRATCHOFF(index));
- else
- return radeon_read_ring_rptr(dev_priv,
- RADEON_SCRATCHOFF(index));
- } else {
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return RADEON_READ(R600_SCRATCH_REG0 + 4*index);
- else
- return RADEON_READ(RADEON_SCRATCH_REG0 + 4*index);
- }
-}
-
-static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
-{
- u32 ret;
- RADEON_WRITE(R520_MC_IND_INDEX, 0x7f0000 | (addr & 0xff));
- ret = RADEON_READ(R520_MC_IND_DATA);
- RADEON_WRITE(R520_MC_IND_INDEX, 0);
- return ret;
-}
-
-static u32 RS480_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
-{
- u32 ret;
- RADEON_WRITE(RS480_NB_MC_INDEX, addr & 0xff);
- ret = RADEON_READ(RS480_NB_MC_DATA);
- RADEON_WRITE(RS480_NB_MC_INDEX, 0xff);
- return ret;
-}
-
-static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
-{
- u32 ret;
- RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
- ret = RADEON_READ(RS690_MC_DATA);
- RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_MASK);
- return ret;
-}
-
-static u32 RS600_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
-{
- u32 ret;
- RADEON_WRITE(RS600_MC_INDEX, ((addr & RS600_MC_ADDR_MASK) |
- RS600_MC_IND_CITF_ARB0));
- ret = RADEON_READ(RS600_MC_DATA);
- return ret;
-}
-
-static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
-{
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
- return RS690_READ_MCIND(dev_priv, addr);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- return RS600_READ_MCIND(dev_priv, addr);
- else
- return RS480_READ_MCIND(dev_priv, addr);
-}
-
-u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
-{
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
- return RADEON_READ(R700_MC_VM_FB_LOCATION);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return RADEON_READ(R600_MC_VM_FB_LOCATION);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
- return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
- else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
- return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- return RS600_READ_MCIND(dev_priv, RS600_MC_FB_LOCATION);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
- return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
- else
- return RADEON_READ(RADEON_MC_FB_LOCATION);
-}
-
-static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
-{
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
- RADEON_WRITE(R700_MC_VM_FB_LOCATION, fb_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- RADEON_WRITE(R600_MC_VM_FB_LOCATION, fb_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
- R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
- else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
- RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- RS600_WRITE_MCIND(RS600_MC_FB_LOCATION, fb_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
- R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
- else
- RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
-}
-
-void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
-{
- /*R6xx/R7xx: AGP_TOP and BOT are actually 18 bits each */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
- RADEON_WRITE(R700_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
- RADEON_WRITE(R700_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
- RADEON_WRITE(R600_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
- RADEON_WRITE(R600_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
- R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
- else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
- RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- RS600_WRITE_MCIND(RS600_MC_AGP_LOCATION, agp_loc);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
- R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
- else
- RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
-}
-
-void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
-{
- u32 agp_base_hi = upper_32_bits(agp_base);
- u32 agp_base_lo = agp_base & 0xffffffff;
- u32 r6xx_agp_base = (agp_base >> 22) & 0x3ffff;
-
- /* R6xx/R7xx must be aligned to a 4MB boundary */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
- RADEON_WRITE(R700_MC_VM_AGP_BASE, r6xx_agp_base);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- RADEON_WRITE(R600_MC_VM_AGP_BASE, r6xx_agp_base);
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
- R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
- R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
- RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
- RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
- RS600_WRITE_MCIND(RS600_AGP_BASE, agp_base_lo);
- RS600_WRITE_MCIND(RS600_AGP_BASE_2, agp_base_hi);
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
- R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
- R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
- RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
- RADEON_WRITE(RS480_AGP_BASE_2, agp_base_hi);
- } else {
- RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
- RADEON_WRITE(RADEON_AGP_BASE_2, agp_base_hi);
- }
-}
-
-void radeon_enable_bm(struct drm_radeon_private *dev_priv)
-{
- u32 tmp;
- /* Turn on bus mastering */
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
- /* rs600/rs690/rs740 */
- tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
- RADEON_WRITE(RADEON_BUS_CNTL, tmp);
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
- /* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
- tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
- RADEON_WRITE(RADEON_BUS_CNTL, tmp);
- } /* PCIE cards appears to not need this */
-}
-
-static int RADEON_READ_PLL(struct drm_device * dev, int addr)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f);
- return RADEON_READ(RADEON_CLOCK_CNTL_DATA);
-}
-
-static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
-{
- RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff);
- return RADEON_READ(RADEON_PCIE_DATA);
-}
-
-#if RADEON_FIFO_DEBUG
-static void radeon_status(drm_radeon_private_t * dev_priv)
-{
- printk("%s:\n", __func__);
- printk("RBBM_STATUS = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_RBBM_STATUS));
- printk("CP_RB_RTPR = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_CP_RB_RPTR));
- printk("CP_RB_WTPR = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_CP_RB_WPTR));
- printk("AIC_CNTL = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_AIC_CNTL));
- printk("AIC_STAT = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_AIC_STAT));
- printk("AIC_PT_BASE = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_AIC_PT_BASE));
- printk("TLB_ADDR = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_AIC_TLB_ADDR));
- printk("TLB_DATA = 0x%08x\n",
- (unsigned int)RADEON_READ(RADEON_AIC_TLB_DATA));
-}
-#endif
-
-/* ================================================================
- * Engine, FIFO control
- */
-
-static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
-{
- u32 tmp;
- int i;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {
- tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
- tmp |= RADEON_RB3D_DC_FLUSH_ALL;
- RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
- & RADEON_RB3D_DC_BUSY)) {
- return 0;
- }
- DRM_UDELAY(1);
- }
- } else {
- /* don't flush or purge cache here or lockup */
- return 0;
- }
-
-#if RADEON_FIFO_DEBUG
- DRM_ERROR("failed!\n");
- radeon_status(dev_priv);
-#endif
- return -EBUSY;
-}
-
-static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
-{
- int i;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- int slots = (RADEON_READ(RADEON_RBBM_STATUS)
- & RADEON_RBBM_FIFOCNT_MASK);
- if (slots >= entries)
- return 0;
- DRM_UDELAY(1);
- }
- DRM_DEBUG("wait for fifo failed status : 0x%08X 0x%08X\n",
- RADEON_READ(RADEON_RBBM_STATUS),
- RADEON_READ(R300_VAP_CNTL_STATUS));
-
-#if RADEON_FIFO_DEBUG
- DRM_ERROR("failed!\n");
- radeon_status(dev_priv);
-#endif
- return -EBUSY;
-}
-
-static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
-{
- int i, ret;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- ret = radeon_do_wait_for_fifo(dev_priv, 64);
- if (ret)
- return ret;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(RADEON_READ(RADEON_RBBM_STATUS)
- & RADEON_RBBM_ACTIVE)) {
- radeon_do_pixcache_flush(dev_priv);
- return 0;
- }
- DRM_UDELAY(1);
- }
- DRM_DEBUG("wait idle failed status : 0x%08X 0x%08X\n",
- RADEON_READ(RADEON_RBBM_STATUS),
- RADEON_READ(R300_VAP_CNTL_STATUS));
-
-#if RADEON_FIFO_DEBUG
- DRM_ERROR("failed!\n");
- radeon_status(dev_priv);
-#endif
- return -EBUSY;
-}
-
-static void radeon_init_pipes(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- uint32_t gb_tile_config, gb_pipe_sel = 0;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) {
- uint32_t z_pipe_sel = RADEON_READ(RV530_GB_PIPE_SELECT2);
- if ((z_pipe_sel & 3) == 3)
- dev_priv->num_z_pipes = 2;
- else
- dev_priv->num_z_pipes = 1;
- } else
- dev_priv->num_z_pipes = 1;
-
- /* RS4xx/RS6xx/R4xx/R5xx */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R420) {
- gb_pipe_sel = RADEON_READ(R400_GB_PIPE_SELECT);
- dev_priv->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
- /* SE cards have 1 pipe */
- if ((dev->pdev->device == 0x5e4c) ||
- (dev->pdev->device == 0x5e4f))
- dev_priv->num_gb_pipes = 1;
- } else {
- /* R3xx */
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300 &&
- dev->pdev->device != 0x4144) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350 &&
- dev->pdev->device != 0x4148)) {
- dev_priv->num_gb_pipes = 2;
- } else {
- /* RV3xx/R300 AD/R350 AH */
- dev_priv->num_gb_pipes = 1;
- }
- }
- DRM_INFO("Num pipes: %d\n", dev_priv->num_gb_pipes);
-
- gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16 /*| R300_SUBPIXEL_1_16*/);
-
- switch (dev_priv->num_gb_pipes) {
- case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break;
- case 3: gb_tile_config |= R300_PIPE_COUNT_R420_3P; break;
- case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break;
- default:
- case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
- RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
- RADEON_WRITE(R300_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
- }
- RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config);
- radeon_do_wait_for_idle(dev_priv);
- RADEON_WRITE(R300_DST_PIPE_CONFIG, RADEON_READ(R300_DST_PIPE_CONFIG) | R300_PIPE_AUTO_CONFIG);
- RADEON_WRITE(R300_RB2D_DSTCACHE_MODE, (RADEON_READ(R300_RB2D_DSTCACHE_MODE) |
- R300_DC_AUTOFLUSH_ENABLE |
- R300_DC_DC_DISABLE_IGNORE_PE));
-
-
-}
-
-/* ================================================================
- * CP control, initialization
- */
-
-/* Load the microcode for the CP */
-static int radeon_cp_init_microcode(drm_radeon_private_t *dev_priv)
-{
- struct platform_device *pdev;
- const char *fw_name = NULL;
- int err;
-
- DRM_DEBUG("\n");
-
- pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
- err = IS_ERR(pdev);
- if (err) {
- printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
- return -EINVAL;
- }
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R100) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV100) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV200) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS100) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS200)) {
- DRM_INFO("Loading R100 Microcode\n");
- fw_name = FIRMWARE_R100;
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R200) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV250) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV280) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS300)) {
- DRM_INFO("Loading R200 Microcode\n");
- fw_name = FIRMWARE_R200;
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
- DRM_INFO("Loading R300 Microcode\n");
- fw_name = FIRMWARE_R300;
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R423) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
- DRM_INFO("Loading R400 Microcode\n");
- fw_name = FIRMWARE_R420;
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
- DRM_INFO("Loading RS690/RS740 Microcode\n");
- fw_name = FIRMWARE_RS690;
- } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
- DRM_INFO("Loading RS600 Microcode\n");
- fw_name = FIRMWARE_RS600;
- } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R580) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV560) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV570)) {
- DRM_INFO("Loading R500 Microcode\n");
- fw_name = FIRMWARE_R520;
- }
-
- err = request_firmware(&dev_priv->me_fw, fw_name, &pdev->dev);
- platform_device_unregister(pdev);
- if (err) {
- printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n",
- fw_name);
- } else if (dev_priv->me_fw->size % 8) {
- printk(KERN_ERR
- "radeon_cp: Bogus length %zu in firmware \"%s\"\n",
- dev_priv->me_fw->size, fw_name);
- err = -EINVAL;
- release_firmware(dev_priv->me_fw);
- dev_priv->me_fw = NULL;
- }
- return err;
-}
-
-static void radeon_cp_load_microcode(drm_radeon_private_t *dev_priv)
-{
- const __be32 *fw_data;
- int i, size;
-
- radeon_do_wait_for_idle(dev_priv);
-
- if (dev_priv->me_fw) {
- size = dev_priv->me_fw->size / 4;
- fw_data = (const __be32 *)&dev_priv->me_fw->data[0];
- RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
- for (i = 0; i < size; i += 2) {
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
- be32_to_cpup(&fw_data[i]));
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
- be32_to_cpup(&fw_data[i + 1]));
- }
- }
-}
-
-/* Flush any pending commands to the CP. This should only be used just
- * prior to a wait for idle, as it informs the engine that the command
- * stream is ending.
- */
-static void radeon_do_cp_flush(drm_radeon_private_t * dev_priv)
-{
- DRM_DEBUG("\n");
-#if 0
- u32 tmp;
-
- tmp = RADEON_READ(RADEON_CP_RB_WPTR) | (1 << 31);
- RADEON_WRITE(RADEON_CP_RB_WPTR, tmp);
-#endif
-}
-
-/* Wait for the CP to go idle.
- */
-int radeon_do_cp_idle(drm_radeon_private_t * dev_priv)
-{
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(6);
-
- RADEON_PURGE_CACHE();
- RADEON_PURGE_ZCACHE();
- RADEON_WAIT_UNTIL_IDLE();
-
- ADVANCE_RING();
- COMMIT_RING();
-
- return radeon_do_wait_for_idle(dev_priv);
-}
-
-/* Start the Command Processor.
- */
-static void radeon_do_cp_start(drm_radeon_private_t * dev_priv)
-{
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- radeon_do_wait_for_idle(dev_priv);
-
- RADEON_WRITE(RADEON_CP_CSQ_CNTL, dev_priv->cp_mode);
-
- dev_priv->cp_running = 1;
-
- /* on r420, any DMA from CP to system memory while 2D is active
- * can cause a hang. workaround is to queue a CP RESYNC token
- */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) {
- BEGIN_RING(3);
- OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 1));
- OUT_RING(5); /* scratch reg 5 */
- OUT_RING(0xdeadbeef);
- ADVANCE_RING();
- COMMIT_RING();
- }
-
- BEGIN_RING(8);
- /* isync can only be written through cp on r5xx write it here */
- OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 0));
- OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D |
- RADEON_ISYNC_ANY3D_IDLE2D |
- RADEON_ISYNC_WAIT_IDLEGUI |
- RADEON_ISYNC_CPSCRATCH_IDLEGUI);
- RADEON_PURGE_CACHE();
- RADEON_PURGE_ZCACHE();
- RADEON_WAIT_UNTIL_IDLE();
- ADVANCE_RING();
- COMMIT_RING();
-
- dev_priv->track_flush |= RADEON_FLUSH_EMITED | RADEON_PURGE_EMITED;
-}
-
-/* Reset the Command Processor. This will not flush any pending
- * commands, so you must wait for the CP command stream to complete
- * before calling this routine.
- */
-static void radeon_do_cp_reset(drm_radeon_private_t * dev_priv)
-{
- u32 cur_read_ptr;
- DRM_DEBUG("\n");
-
- cur_read_ptr = RADEON_READ(RADEON_CP_RB_RPTR);
- RADEON_WRITE(RADEON_CP_RB_WPTR, cur_read_ptr);
- SET_RING_HEAD(dev_priv, cur_read_ptr);
- dev_priv->ring.tail = cur_read_ptr;
-}
-
-/* Stop the Command Processor. This will not flush any pending
- * commands, so you must flush the command stream and wait for the CP
- * to go idle before calling this routine.
- */
-static void radeon_do_cp_stop(drm_radeon_private_t * dev_priv)
-{
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- /* finish the pending CP_RESYNC token */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) {
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- OUT_RING(R300_RB3D_DC_FINISH);
- ADVANCE_RING();
- COMMIT_RING();
- radeon_do_wait_for_idle(dev_priv);
- }
-
- RADEON_WRITE(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS);
-
- dev_priv->cp_running = 0;
-}
-
-/* Reset the engine. This will stop the CP if it is running.
- */
-static int radeon_do_engine_reset(struct drm_device * dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- u32 clock_cntl_index = 0, mclk_cntl = 0, rbbm_soft_reset;
- DRM_DEBUG("\n");
-
- radeon_do_pixcache_flush(dev_priv);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
- /* may need something similar for newer chips */
- clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX);
- mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL);
-
- RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl |
- RADEON_FORCEON_MCLKA |
- RADEON_FORCEON_MCLKB |
- RADEON_FORCEON_YCLKA |
- RADEON_FORCEON_YCLKB |
- RADEON_FORCEON_MC |
- RADEON_FORCEON_AIC));
- }
-
- rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
-
- RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
- RADEON_SOFT_RESET_CP |
- RADEON_SOFT_RESET_HI |
- RADEON_SOFT_RESET_SE |
- RADEON_SOFT_RESET_RE |
- RADEON_SOFT_RESET_PP |
- RADEON_SOFT_RESET_E2 |
- RADEON_SOFT_RESET_RB));
- RADEON_READ(RADEON_RBBM_SOFT_RESET);
- RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
- ~(RADEON_SOFT_RESET_CP |
- RADEON_SOFT_RESET_HI |
- RADEON_SOFT_RESET_SE |
- RADEON_SOFT_RESET_RE |
- RADEON_SOFT_RESET_PP |
- RADEON_SOFT_RESET_E2 |
- RADEON_SOFT_RESET_RB)));
- RADEON_READ(RADEON_RBBM_SOFT_RESET);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
- RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl);
- RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
- RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
- }
-
- /* setup the raster pipes */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R300)
- radeon_init_pipes(dev);
-
- /* Reset the CP ring */
- radeon_do_cp_reset(dev_priv);
-
- /* The CP is no longer running after an engine reset */
- dev_priv->cp_running = 0;
-
- /* Reset any pending vertex, indirect buffers */
- radeon_freelist_reset(dev);
-
- return 0;
-}
-
-static void radeon_cp_init_ring_buffer(struct drm_device * dev,
- drm_radeon_private_t *dev_priv,
- struct drm_file *file_priv)
-{
- struct drm_radeon_master_private *master_priv;
- u32 ring_start, cur_read_ptr;
-
- /* Initialize the memory controller. With new memory map, the fb location
- * is not changed, it should have been properly initialized already. Part
- * of the problem is that the code below is bogus, assuming the GART is
- * always appended to the fb which is not necessarily the case
- */
- if (!dev_priv->new_memmap)
- radeon_write_fb_location(dev_priv,
- ((dev_priv->gart_vm_start - 1) & 0xffff0000)
- | (dev_priv->fb_location >> 16));
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- radeon_write_agp_base(dev_priv, dev->agp->base);
-
- radeon_write_agp_location(dev_priv,
- (((dev_priv->gart_vm_start - 1 +
- dev_priv->gart_size) & 0xffff0000) |
- (dev_priv->gart_vm_start >> 16)));
-
- ring_start = (dev_priv->cp_ring->offset
- - dev->agp->base
- + dev_priv->gart_vm_start);
- } else
-#endif
- ring_start = (dev_priv->cp_ring->offset
- - (unsigned long)dev->sg->virtual
- + dev_priv->gart_vm_start);
-
- RADEON_WRITE(RADEON_CP_RB_BASE, ring_start);
-
- /* Set the write pointer delay */
- RADEON_WRITE(RADEON_CP_RB_WPTR_DELAY, 0);
-
- /* Initialize the ring buffer's read and write pointers */
- cur_read_ptr = RADEON_READ(RADEON_CP_RB_RPTR);
- RADEON_WRITE(RADEON_CP_RB_WPTR, cur_read_ptr);
- SET_RING_HEAD(dev_priv, cur_read_ptr);
- dev_priv->ring.tail = cur_read_ptr;
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
- dev_priv->ring_rptr->offset
- - dev->agp->base + dev_priv->gart_vm_start);
- } else
-#endif
- {
- RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
- dev_priv->ring_rptr->offset
- - ((unsigned long) dev->sg->virtual)
- + dev_priv->gart_vm_start);
- }
-
- /* Set ring buffer size */
-#ifdef __BIG_ENDIAN
- RADEON_WRITE(RADEON_CP_RB_CNTL,
- RADEON_BUF_SWAP_32BIT |
- (dev_priv->ring.fetch_size_l2ow << 18) |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#else
- RADEON_WRITE(RADEON_CP_RB_CNTL,
- (dev_priv->ring.fetch_size_l2ow << 18) |
- (dev_priv->ring.rptr_update_l2qw << 8) |
- dev_priv->ring.size_l2qw);
-#endif
-
-
- /* Initialize the scratch register pointer. This will cause
- * the scratch register values to be written out to memory
- * whenever they are updated.
- *
- * We simply put this behind the ring read pointer, this works
- * with PCI GART as well as (whatever kind of) AGP GART
- */
- RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR)
- + RADEON_SCRATCH_REG_OFFSET);
-
- RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
-
- radeon_enable_bm(dev_priv);
-
- radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(0), 0);
- RADEON_WRITE(RADEON_LAST_FRAME_REG, 0);
-
- radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
- RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0);
-
- radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(2), 0);
- RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
-
- /* reset sarea copies of these */
- master_priv = file_priv->master->driver_priv;
- if (master_priv->sarea_priv) {
- master_priv->sarea_priv->last_frame = 0;
- master_priv->sarea_priv->last_dispatch = 0;
- master_priv->sarea_priv->last_clear = 0;
- }
-
- radeon_do_wait_for_idle(dev_priv);
-
- /* Sync everything up */
- RADEON_WRITE(RADEON_ISYNC_CNTL,
- (RADEON_ISYNC_ANY2D_IDLE3D |
- RADEON_ISYNC_ANY3D_IDLE2D |
- RADEON_ISYNC_WAIT_IDLEGUI |
- RADEON_ISYNC_CPSCRATCH_IDLEGUI));
-
-}
-
-static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
-{
- u32 tmp;
-
- /* Start with assuming that writeback doesn't work */
- dev_priv->writeback_works = 0;
-
- /* Writeback doesn't seem to work everywhere, test it here and possibly
- * enable it if it appears to work
- */
- radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
-
- RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
-
- for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
- u32 val;
-
- val = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
- if (val == 0xdeadbeef)
- break;
- DRM_UDELAY(1);
- }
-
- if (tmp < dev_priv->usec_timeout) {
- dev_priv->writeback_works = 1;
- DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
- } else {
- dev_priv->writeback_works = 0;
- DRM_INFO("writeback test failed\n");
- }
- if (radeon_no_wb == 1) {
- dev_priv->writeback_works = 0;
- DRM_INFO("writeback forced off\n");
- }
-
- if (!dev_priv->writeback_works) {
- /* Disable writeback to avoid unnecessary bus master transfer */
- RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) |
- RADEON_RB_NO_UPDATE);
- RADEON_WRITE(RADEON_SCRATCH_UMSK, 0);
- }
-}
-
-/* Enable or disable IGP GART on the chip */
-static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
-{
- u32 temp;
-
- if (on) {
- DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
- dev_priv->gart_vm_start,
- (long)dev_priv->gart_info.bus_addr,
- dev_priv->gart_size);
-
- temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
- IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
- RS690_BLOCK_GFX_D3_EN));
- else
- IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN);
-
- IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
- RS480_VA_SIZE_32MB));
-
- temp = IGP_READ_MCIND(dev_priv, RS480_GART_FEATURE_ID);
- IGP_WRITE_MCIND(RS480_GART_FEATURE_ID, (RS480_HANG_EN |
- RS480_TLB_ENABLE |
- RS480_GTW_LAC_EN |
- RS480_1LEVEL_GART));
-
- temp = dev_priv->gart_info.bus_addr & 0xfffff000;
- temp |= (upper_32_bits(dev_priv->gart_info.bus_addr) & 0xff) << 4;
- IGP_WRITE_MCIND(RS480_GART_BASE, temp);
-
- temp = IGP_READ_MCIND(dev_priv, RS480_AGP_MODE_CNTL);
- IGP_WRITE_MCIND(RS480_AGP_MODE_CNTL, ((1 << RS480_REQ_TYPE_SNOOP_SHIFT) |
- RS480_REQ_TYPE_SNOOP_DIS));
-
- radeon_write_agp_base(dev_priv, dev_priv->gart_vm_start);
-
- dev_priv->gart_size = 32*1024*1024;
- temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) &
- 0xffff0000) | (dev_priv->gart_vm_start >> 16));
-
- radeon_write_agp_location(dev_priv, temp);
-
- temp = IGP_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE);
- IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
- RS480_VA_SIZE_32MB));
-
- do {
- temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
- if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
- break;
- DRM_UDELAY(1);
- } while (1);
-
- IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL,
- RS480_GART_CACHE_INVALIDATE);
-
- do {
- temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
- if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
- break;
- DRM_UDELAY(1);
- } while (1);
-
- IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0);
- } else {
- IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
- }
-}
-
-/* Enable or disable IGP GART on the chip */
-static void rs600_set_igpgart(drm_radeon_private_t *dev_priv, int on)
-{
- u32 temp;
- int i;
-
- if (on) {
- DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
- dev_priv->gart_vm_start,
- (long)dev_priv->gart_info.bus_addr,
- dev_priv->gart_size);
-
- IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) |
- RS600_EFFECTIVE_L2_QUEUE_SIZE(6)));
-
- for (i = 0; i < 19; i++)
- IGP_WRITE_MCIND(RS600_MC_PT0_CLIENT0_CNTL + i,
- (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE |
- RS600_SYSTEM_ACCESS_MODE_IN_SYS |
- RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH |
- RS600_EFFECTIVE_L1_CACHE_SIZE(3) |
- RS600_ENABLE_FRAGMENT_PROCESSING |
- RS600_EFFECTIVE_L1_QUEUE_SIZE(3)));
-
- IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL, (RS600_ENABLE_PAGE_TABLE |
- RS600_PAGE_TABLE_TYPE_FLAT));
-
- /* disable all other contexts */
- for (i = 1; i < 8; i++)
- IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL + i, 0);
-
- /* setup the page table aperture */
- IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
- dev_priv->gart_info.bus_addr);
- IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR,
- dev_priv->gart_vm_start);
- IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR,
- (dev_priv->gart_vm_start + dev_priv->gart_size - 1));
- IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
-
- /* setup the system aperture */
- IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR,
- dev_priv->gart_vm_start);
- IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR,
- (dev_priv->gart_vm_start + dev_priv->gart_size - 1));
-
- /* enable page tables */
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
- IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (temp | RS600_ENABLE_PT));
-
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
- IGP_WRITE_MCIND(RS600_MC_CNTL1, (temp | RS600_ENABLE_PAGE_TABLES));
-
- /* invalidate the cache */
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
-
- temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
- IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
-
- temp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE;
- IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
-
- temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
- IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
-
- } else {
- IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, 0);
- temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
- temp &= ~RS600_ENABLE_PAGE_TABLES;
- IGP_WRITE_MCIND(RS600_MC_CNTL1, temp);
- }
-}
-
-static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
-{
- u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
- if (on) {
-
- DRM_DEBUG("programming pcie %08X %08lX %08X\n",
- dev_priv->gart_vm_start,
- (long)dev_priv->gart_info.bus_addr,
- dev_priv->gart_size);
- RADEON_WRITE_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO,
- dev_priv->gart_vm_start);
- RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_BASE,
- dev_priv->gart_info.bus_addr);
- RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_START_LO,
- dev_priv->gart_vm_start);
- RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_END_LO,
- dev_priv->gart_vm_start +
- dev_priv->gart_size - 1);
-
- radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */
-
- RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
- RADEON_PCIE_TX_GART_EN);
- } else {
- RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
- tmp & ~RADEON_PCIE_TX_GART_EN);
- }
-}
-
-/* Enable or disable PCI GART on the chip */
-static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
-{
- u32 tmp;
-
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740) ||
- (dev_priv->flags & RADEON_IS_IGPGART)) {
- radeon_set_igpgart(dev_priv, on);
- return;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
- rs600_set_igpgart(dev_priv, on);
- return;
- }
-
- if (dev_priv->flags & RADEON_IS_PCIE) {
- radeon_set_pciegart(dev_priv, on);
- return;
- }
-
- tmp = RADEON_READ(RADEON_AIC_CNTL);
-
- if (on) {
- RADEON_WRITE(RADEON_AIC_CNTL,
- tmp | RADEON_PCIGART_TRANSLATE_EN);
-
- /* set PCI GART page-table base address
- */
- RADEON_WRITE(RADEON_AIC_PT_BASE, dev_priv->gart_info.bus_addr);
-
- /* set address range for PCI address translate
- */
- RADEON_WRITE(RADEON_AIC_LO_ADDR, dev_priv->gart_vm_start);
- RADEON_WRITE(RADEON_AIC_HI_ADDR, dev_priv->gart_vm_start
- + dev_priv->gart_size - 1);
-
- /* Turn off AGP aperture -- is this required for PCI GART?
- */
- radeon_write_agp_location(dev_priv, 0xffffffc0);
- RADEON_WRITE(RADEON_AGP_COMMAND, 0); /* clear AGP_COMMAND */
- } else {
- RADEON_WRITE(RADEON_AIC_CNTL,
- tmp & ~RADEON_PCIGART_TRANSLATE_EN);
- }
-}
-
-static int radeon_setup_pcigart_surface(drm_radeon_private_t *dev_priv)
-{
- struct drm_ati_pcigart_info *gart_info = &dev_priv->gart_info;
- struct radeon_virt_surface *vp;
- int i;
-
- for (i = 0; i < RADEON_MAX_SURFACES * 2; i++) {
- if (!dev_priv->virt_surfaces[i].file_priv ||
- dev_priv->virt_surfaces[i].file_priv == PCIGART_FILE_PRIV)
- break;
- }
- if (i >= 2 * RADEON_MAX_SURFACES)
- return -ENOMEM;
- vp = &dev_priv->virt_surfaces[i];
-
- for (i = 0; i < RADEON_MAX_SURFACES; i++) {
- struct radeon_surface *sp = &dev_priv->surfaces[i];
- if (sp->refcount)
- continue;
-
- vp->surface_index = i;
- vp->lower = gart_info->bus_addr;
- vp->upper = vp->lower + gart_info->table_size;
- vp->flags = 0;
- vp->file_priv = PCIGART_FILE_PRIV;
-
- sp->refcount = 1;
- sp->lower = vp->lower;
- sp->upper = vp->upper;
- sp->flags = 0;
-
- RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, sp->flags);
- RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * i, sp->lower);
- RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * i, sp->upper);
- return 0;
- }
-
- return -ENOMEM;
-}
-
-static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
- struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
-
- DRM_DEBUG("\n");
-
- /* if we require new memory map but we don't have it fail */
- if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
- DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
- DRM_DEBUG("Forcing AGP card to PCI mode\n");
- dev_priv->flags &= ~RADEON_IS_AGP;
- } else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
- && !init->is_pci) {
- DRM_DEBUG("Restoring AGP flag\n");
- dev_priv->flags |= RADEON_IS_AGP;
- }
-
- if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
- DRM_ERROR("PCI GART memory not allocated!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- dev_priv->usec_timeout = init->usec_timeout;
- if (dev_priv->usec_timeout < 1 ||
- dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
- DRM_DEBUG("TIMEOUT problem!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- /* Enable vblank on CRTC1 for older X servers
- */
- dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
-
- switch(init->func) {
- case RADEON_INIT_R200_CP:
- dev_priv->microcode_version = UCODE_R200;
- break;
- case RADEON_INIT_R300_CP:
- dev_priv->microcode_version = UCODE_R300;
- break;
- default:
- dev_priv->microcode_version = UCODE_R100;
- }
-
- dev_priv->do_boxes = 0;
- dev_priv->cp_mode = init->cp_mode;
-
- /* We don't support anything other than bus-mastering ring mode,
- * but the ring can be in either AGP or PCI space for the ring
- * read pointer.
- */
- if ((init->cp_mode != RADEON_CSQ_PRIBM_INDDIS) &&
- (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
- DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- switch (init->fb_bpp) {
- case 16:
- dev_priv->color_fmt = RADEON_COLOR_FORMAT_RGB565;
- break;
- case 32:
- default:
- dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888;
- break;
- }
- dev_priv->front_offset = init->front_offset;
- dev_priv->front_pitch = init->front_pitch;
- dev_priv->back_offset = init->back_offset;
- dev_priv->back_pitch = init->back_pitch;
-
- switch (init->depth_bpp) {
- case 16:
- dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z;
- break;
- case 32:
- default:
- dev_priv->depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z;
- break;
- }
- dev_priv->depth_offset = init->depth_offset;
- dev_priv->depth_pitch = init->depth_pitch;
-
- /* Hardware state for depth clears. Remove this if/when we no
- * longer clear the depth buffer with a 3D rectangle. Hard-code
- * all values to prevent unwanted 3D state from slipping through
- * and screwing with the clear operation.
- */
- dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE |
- (dev_priv->color_fmt << 10) |
- (dev_priv->microcode_version ==
- UCODE_R100 ? RADEON_ZBLOCK16 : 0));
-
- dev_priv->depth_clear.rb3d_zstencilcntl =
- (dev_priv->depth_fmt |
- RADEON_Z_TEST_ALWAYS |
- RADEON_STENCIL_TEST_ALWAYS |
- RADEON_STENCIL_S_FAIL_REPLACE |
- RADEON_STENCIL_ZPASS_REPLACE |
- RADEON_STENCIL_ZFAIL_REPLACE | RADEON_Z_WRITE_ENABLE);
-
- dev_priv->depth_clear.se_cntl = (RADEON_FFACE_CULL_CW |
- RADEON_BFACE_SOLID |
- RADEON_FFACE_SOLID |
- RADEON_FLAT_SHADE_VTX_LAST |
- RADEON_DIFFUSE_SHADE_FLAT |
- RADEON_ALPHA_SHADE_FLAT |
- RADEON_SPECULAR_SHADE_FLAT |
- RADEON_FOG_SHADE_FLAT |
- RADEON_VTX_PIX_CENTER_OGL |
- RADEON_ROUND_MODE_TRUNC |
- RADEON_ROUND_PREC_8TH_PIX);
-
-
- dev_priv->ring_offset = init->ring_offset;
- dev_priv->ring_rptr_offset = init->ring_rptr_offset;
- dev_priv->buffers_offset = init->buffers_offset;
- dev_priv->gart_textures_offset = init->gart_textures_offset;
-
- master_priv->sarea = drm_legacy_getsarea(dev);
- if (!master_priv->sarea) {
- DRM_ERROR("could not find sarea!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- dev_priv->cp_ring = drm_legacy_findmap(dev, init->ring_offset);
- if (!dev_priv->cp_ring) {
- DRM_ERROR("could not find cp ring region!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
- dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
- if (!dev_priv->ring_rptr) {
- DRM_ERROR("could not find ring read pointer!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
- dev->agp_buffer_token = init->buffers_offset;
- dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
- if (!dev->agp_buffer_map) {
- DRM_ERROR("could not find dma buffer region!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
-
- if (init->gart_textures_offset) {
- dev_priv->gart_textures =
- drm_legacy_findmap(dev, init->gart_textures_offset);
- if (!dev_priv->gart_textures) {
- DRM_ERROR("could not find GART texture region!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
- }
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- drm_legacy_ioremap_wc(dev_priv->cp_ring, dev);
- drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
- drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
- if (!dev_priv->cp_ring->handle ||
- !dev_priv->ring_rptr->handle ||
- !dev->agp_buffer_map->handle) {
- DRM_ERROR("could not find ioremap agp regions!\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
- } else
-#endif
- {
- dev_priv->cp_ring->handle =
- (void *)(unsigned long)dev_priv->cp_ring->offset;
- dev_priv->ring_rptr->handle =
- (void *)(unsigned long)dev_priv->ring_rptr->offset;
- dev->agp_buffer_map->handle =
- (void *)(unsigned long)dev->agp_buffer_map->offset;
-
- DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
- dev_priv->cp_ring->handle);
- DRM_DEBUG("dev_priv->ring_rptr->handle %p\n",
- dev_priv->ring_rptr->handle);
- DRM_DEBUG("dev->agp_buffer_map->handle %p\n",
- dev->agp_buffer_map->handle);
- }
-
- dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16;
- dev_priv->fb_size =
- ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000)
- - dev_priv->fb_location;
-
- dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
- ((dev_priv->front_offset
- + dev_priv->fb_location) >> 10));
-
- dev_priv->back_pitch_offset = (((dev_priv->back_pitch / 64) << 22) |
- ((dev_priv->back_offset
- + dev_priv->fb_location) >> 10));
-
- dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch / 64) << 22) |
- ((dev_priv->depth_offset
- + dev_priv->fb_location) >> 10));
-
- dev_priv->gart_size = init->gart_size;
-
- /* New let's set the memory map ... */
- if (dev_priv->new_memmap) {
- u32 base = 0;
-
- DRM_INFO("Setting GART location based on new memory map\n");
-
- /* If using AGP, try to locate the AGP aperture at the same
- * location in the card and on the bus, though we have to
- * align it down.
- */
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- base = dev->agp->base;
- /* Check if valid */
- if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
- base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
- DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
- dev->agp->base);
- base = 0;
- }
- }
-#endif
- /* If not or if AGP is at 0 (Macs), try to put it elsewhere */
- if (base == 0) {
- base = dev_priv->fb_location + dev_priv->fb_size;
- if (base < dev_priv->fb_location ||
- ((base + dev_priv->gart_size) & 0xfffffffful) < base)
- base = dev_priv->fb_location
- - dev_priv->gart_size;
- }
- dev_priv->gart_vm_start = base & 0xffc00000u;
- if (dev_priv->gart_vm_start != base)
- DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
- base, dev_priv->gart_vm_start);
- } else {
- DRM_INFO("Setting GART location based on old memory map\n");
- dev_priv->gart_vm_start = dev_priv->fb_location +
- RADEON_READ(RADEON_CONFIG_APER_SIZE);
- }
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP)
- dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
- - dev->agp->base
- + dev_priv->gart_vm_start);
- else
-#endif
- dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
- - (unsigned long)dev->sg->virtual
- + dev_priv->gart_vm_start);
-
- DRM_DEBUG("dev_priv->gart_size %d\n", dev_priv->gart_size);
- DRM_DEBUG("dev_priv->gart_vm_start 0x%x\n", dev_priv->gart_vm_start);
- DRM_DEBUG("dev_priv->gart_buffers_offset 0x%lx\n",
- dev_priv->gart_buffers_offset);
-
- dev_priv->ring.start = (u32 *) dev_priv->cp_ring->handle;
- dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
- + init->ring_size / sizeof(u32));
- dev_priv->ring.size = init->ring_size;
- dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
-
- dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
- dev_priv->ring.rptr_update_l2qw = order_base_2( /* init->rptr_update */ 4096 / 8);
-
- dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
- dev_priv->ring.fetch_size_l2ow = order_base_2( /* init->fetch_size */ 32 / 16);
- dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
-
- dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- /* Turn off PCI GART */
- radeon_set_pcigart(dev_priv, 0);
- } else
-#endif
- {
- u32 sctrl;
- int ret;
-
- dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
- /* if we have an offset set from userspace */
- if (dev_priv->pcigart_offset_set) {
- dev_priv->gart_info.bus_addr =
- (resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location;
- dev_priv->gart_info.mapping.offset =
- dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
- dev_priv->gart_info.mapping.size =
- dev_priv->gart_info.table_size;
-
- drm_legacy_ioremap_wc(&dev_priv->gart_info.mapping, dev);
- dev_priv->gart_info.addr =
- dev_priv->gart_info.mapping.handle;
-
- if (dev_priv->flags & RADEON_IS_PCIE)
- dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE;
- else
- dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
- dev_priv->gart_info.gart_table_location =
- DRM_ATI_GART_FB;
-
- DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n",
- dev_priv->gart_info.addr,
- dev_priv->pcigart_offset);
- } else {
- if (dev_priv->flags & RADEON_IS_IGPGART)
- dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP;
- else
- dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
- dev_priv->gart_info.gart_table_location =
- DRM_ATI_GART_MAIN;
- dev_priv->gart_info.addr = NULL;
- dev_priv->gart_info.bus_addr = 0;
- if (dev_priv->flags & RADEON_IS_PCIE) {
- DRM_ERROR
- ("Cannot use PCI Express without GART in FB memory\n");
- radeon_do_cleanup_cp(dev);
- return -EINVAL;
- }
- }
-
- sctrl = RADEON_READ(RADEON_SURFACE_CNTL);
- RADEON_WRITE(RADEON_SURFACE_CNTL, 0);
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- ret = r600_page_table_init(dev);
- else
- ret = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
- RADEON_WRITE(RADEON_SURFACE_CNTL, sctrl);
-
- if (!ret) {
- DRM_ERROR("failed to init PCI GART!\n");
- radeon_do_cleanup_cp(dev);
- return -ENOMEM;
- }
-
- ret = radeon_setup_pcigart_surface(dev_priv);
- if (ret) {
- DRM_ERROR("failed to setup GART surface!\n");
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- r600_page_table_cleanup(dev, &dev_priv->gart_info);
- else
- drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info);
- radeon_do_cleanup_cp(dev);
- return ret;
- }
-
- /* Turn on PCI GART */
- radeon_set_pcigart(dev_priv, 1);
- }
-
- if (!dev_priv->me_fw) {
- int err = radeon_cp_init_microcode(dev_priv);
- if (err) {
- DRM_ERROR("Failed to load firmware!\n");
- radeon_do_cleanup_cp(dev);
- return err;
- }
- }
- radeon_cp_load_microcode(dev_priv);
- radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
-
- dev_priv->last_buf = 0;
-
- radeon_do_engine_reset(dev);
- radeon_test_writeback(dev_priv);
-
- return 0;
-}
-
-static int radeon_do_cleanup_cp(struct drm_device * dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- /* Make sure interrupts are disabled here because the uninstall ioctl
- * may not have been called from userspace and after dev_private
- * is freed, it's too late.
- */
- if (dev->irq_enabled)
- drm_irq_uninstall(dev);
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- if (dev_priv->cp_ring != NULL) {
- drm_legacy_ioremapfree(dev_priv->cp_ring, dev);
- dev_priv->cp_ring = NULL;
- }
- if (dev_priv->ring_rptr != NULL) {
- drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
- dev_priv->ring_rptr = NULL;
- }
- if (dev->agp_buffer_map != NULL) {
- drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
- dev->agp_buffer_map = NULL;
- }
- } else
-#endif
- {
-
- if (dev_priv->gart_info.bus_addr) {
- /* Turn off PCI GART */
- radeon_set_pcigart(dev_priv, 0);
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
- r600_page_table_cleanup(dev, &dev_priv->gart_info);
- else {
- if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
- DRM_ERROR("failed to cleanup PCI GART!\n");
- }
- }
-
- if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
- {
- drm_legacy_ioremapfree(&dev_priv->gart_info.mapping, dev);
- dev_priv->gart_info.addr = NULL;
- }
- }
- /* only clear to the start of flags */
- memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags));
-
- return 0;
-}
-
-/* This code will reinit the Radeon CP hardware after a resume from disc.
- * AFAIK, it would be very difficult to pickle the state at suspend time, so
- * here we make sure that all Radeon hardware initialisation is re-done without
- * affecting running applications.
- *
- * Charl P. Botha <http://cpbotha.net>
- */
-static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if (!dev_priv) {
- DRM_ERROR("Called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_DEBUG("Starting radeon_do_resume_cp()\n");
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->flags & RADEON_IS_AGP) {
- /* Turn off PCI GART */
- radeon_set_pcigart(dev_priv, 0);
- } else
-#endif
- {
- /* Turn on PCI GART */
- radeon_set_pcigart(dev_priv, 1);
- }
-
- radeon_cp_load_microcode(dev_priv);
- radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
-
- dev_priv->have_z_offset = 0;
- radeon_do_engine_reset(dev);
- radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
-
- DRM_DEBUG("radeon_do_resume_cp() complete\n");
-
- return 0;
-}
-
-int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_init_t *init = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (init->func == RADEON_INIT_R300_CP)
- r300_init_reg_flags(dev);
-
- switch (init->func) {
- case RADEON_INIT_CP:
- case RADEON_INIT_R200_CP:
- case RADEON_INIT_R300_CP:
- return radeon_do_init_cp(dev, init, file_priv);
- case RADEON_INIT_R600_CP:
- return r600_do_init_cp(dev, init, file_priv);
- case RADEON_CLEANUP_CP:
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return r600_do_cleanup_cp(dev);
- else
- return radeon_do_cleanup_cp(dev);
- }
-
- return -EINVAL;
-}
-
-int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (dev_priv->cp_running) {
- DRM_DEBUG("while CP running\n");
- return 0;
- }
- if (dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS) {
- DRM_DEBUG("called with bogus CP mode (%d)\n",
- dev_priv->cp_mode);
- return 0;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_do_cp_start(dev_priv);
- else
- radeon_do_cp_start(dev_priv);
-
- return 0;
-}
-
-/* Stop the CP. The engine must have been idled before calling this
- * routine.
- */
-int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_cp_stop_t *stop = data;
- int ret;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (!dev_priv->cp_running)
- return 0;
-
- /* Flush any pending CP commands. This ensures any outstanding
- * commands are exectuted by the engine before we turn it off.
- */
- if (stop->flush) {
- radeon_do_cp_flush(dev_priv);
- }
-
- /* If we fail to make the engine go idle, we return an error
- * code so that the DRM ioctl wrapper can try again.
- */
- if (stop->idle) {
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- ret = r600_do_cp_idle(dev_priv);
- else
- ret = radeon_do_cp_idle(dev_priv);
- if (ret)
- return ret;
- }
-
- /* Finally, we can turn off the CP. If the engine isn't idle,
- * we will get some dropped triangles as they won't be fully
- * rendered before the CP is shut down.
- */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_do_cp_stop(dev_priv);
- else
- radeon_do_cp_stop(dev_priv);
-
- /* Reset the engine */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_do_engine_reset(dev);
- else
- radeon_do_engine_reset(dev);
-
- return 0;
-}
-
-void radeon_do_release(struct drm_device * dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- int i, ret;
-
- if (dev_priv) {
- if (dev_priv->cp_running) {
- /* Stop the cp */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
- while ((ret = r600_do_cp_idle(dev_priv)) != 0) {
- DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
-#ifdef __linux__
- schedule();
-#else
- tsleep(&ret, PZERO, "rdnrel", 1);
-#endif
- }
- } else {
- while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
- DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
-#ifdef __linux__
- schedule();
-#else
- tsleep(&ret, PZERO, "rdnrel", 1);
-#endif
- }
- }
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
- r600_do_cp_stop(dev_priv);
- r600_do_engine_reset(dev);
- } else {
- radeon_do_cp_stop(dev_priv);
- radeon_do_engine_reset(dev);
- }
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) {
- /* Disable *all* interrupts */
- if (dev_priv->mmio) /* remove this after permanent addmaps */
- RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
-
- if (dev_priv->mmio) { /* remove all surfaces */
- for (i = 0; i < RADEON_MAX_SURFACES; i++) {
- RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, 0);
- RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND +
- 16 * i, 0);
- RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND +
- 16 * i, 0);
- }
- }
- }
-
- /* Free memory heap structures */
- radeon_mem_takedown(&(dev_priv->gart_heap));
- radeon_mem_takedown(&(dev_priv->fb_heap));
-
- /* deallocate kernel resources */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_do_cleanup_cp(dev);
- else
- radeon_do_cleanup_cp(dev);
- release_firmware(dev_priv->me_fw);
- dev_priv->me_fw = NULL;
- release_firmware(dev_priv->pfp_fw);
- dev_priv->pfp_fw = NULL;
- }
-}
-
-/* Just reset the CP ring. Called as part of an X Server engine reset.
- */
-int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (!dev_priv) {
- DRM_DEBUG("called before init done\n");
- return -EINVAL;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_do_cp_reset(dev_priv);
- else
- radeon_do_cp_reset(dev_priv);
-
- /* The CP is no longer running after an engine reset */
- dev_priv->cp_running = 0;
-
- return 0;
-}
-
-int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return r600_do_cp_idle(dev_priv);
- else
- return radeon_do_cp_idle(dev_priv);
-}
-
-/* Added by Charl P. Botha to call radeon_do_resume_cp().
- */
-int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return r600_do_resume_cp(dev, file_priv);
- else
- return radeon_do_resume_cp(dev, file_priv);
-}
-
-int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return r600_do_engine_reset(dev);
- else
- return radeon_do_engine_reset(dev);
-}
-
-/* ================================================================
- * Fullscreen mode
- */
-
-/* KW: Deprecated to say the least:
- */
-int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- return 0;
-}
-
-/* ================================================================
- * Freelist management
- */
-
-/* Original comment: FIXME: ROTATE_BUFS is a hack to cycle through
- * bufs until freelist code is used. Note this hides a problem with
- * the scratch register * (used to keep track of last buffer
- * completed) being written to before * the last buffer has actually
- * completed rendering.
- *
- * KW: It's also a good way to find free buffers quickly.
- *
- * KW: Ideally this loop wouldn't exist, and freelist_get wouldn't
- * sleep. However, bugs in older versions of radeon_accel.c mean that
- * we essentially have to do this, else old clients will break.
- *
- * However, it does leave open a potential deadlock where all the
- * buffers are held by other clients, which can't release them because
- * they can't get the lock.
- */
-
-struct drm_buf *radeon_freelist_get(struct drm_device * dev)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_buf_priv_t *buf_priv;
- struct drm_buf *buf;
- int i, t;
- int start;
-
- if (++dev_priv->last_buf >= dma->buf_count)
- dev_priv->last_buf = 0;
-
- start = dev_priv->last_buf;
-
- for (t = 0; t < dev_priv->usec_timeout; t++) {
- u32 done_age = GET_SCRATCH(dev_priv, 1);
- DRM_DEBUG("done_age = %d\n", done_age);
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[start];
- buf_priv = buf->dev_private;
- if (buf->file_priv == NULL || (buf->pending &&
- buf_priv->age <=
- done_age)) {
- dev_priv->stats.requested_bufs++;
- buf->pending = 0;
- return buf;
- }
- if (++start >= dma->buf_count)
- start = 0;
- }
-
- if (t) {
- DRM_UDELAY(1);
- dev_priv->stats.freelist_loops++;
- }
- }
-
- return NULL;
-}
-
-void radeon_freelist_reset(struct drm_device * dev)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_radeon_private_t *dev_priv = dev->dev_private;
- int i;
-
- dev_priv->last_buf = 0;
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
- buf_priv->age = 0;
- }
-}
-
-/* ================================================================
- * CP command submission
- */
-
-int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
-{
- drm_radeon_ring_buffer_t *ring = &dev_priv->ring;
- int i;
- u32 last_head = GET_RING_HEAD(dev_priv);
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- u32 head = GET_RING_HEAD(dev_priv);
-
- ring->space = (head - ring->tail) * sizeof(u32);
- if (ring->space <= 0)
- ring->space += ring->size;
- if (ring->space > n)
- return 0;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- if (head != last_head)
- i = 0;
- last_head = head;
-
- DRM_UDELAY(1);
- }
-
- /* FIXME: This return value is ignored in the BEGIN_RING macro! */
-#if RADEON_FIFO_DEBUG
- radeon_status(dev_priv);
- DRM_ERROR("failed!\n");
-#endif
- return -EBUSY;
-}
-
-static int radeon_cp_get_buffers(struct drm_device *dev,
- struct drm_file *file_priv,
- struct drm_dma * d)
-{
- int i;
- struct drm_buf *buf;
-
- for (i = d->granted_count; i < d->request_count; i++) {
- buf = radeon_freelist_get(dev);
- if (!buf)
- return -EBUSY; /* NOTE: broken client */
-
- buf->file_priv = file_priv;
-
- if (copy_to_user(&d->request_indices[i], &buf->idx,
- sizeof(buf->idx)))
- return -EFAULT;
- if (copy_to_user(&d->request_sizes[i], &buf->total,
- sizeof(buf->total)))
- return -EFAULT;
-
- d->granted_count++;
- }
- return 0;
-}
-
-int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- int ret = 0;
- struct drm_dma *d = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- /* Please don't send us buffers.
- */
- if (d->send_count != 0) {
- DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d->send_count);
- return -EINVAL;
- }
-
- /* We'll send you buffers.
- */
- if (d->request_count < 0 || d->request_count > dma->buf_count) {
- DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d->request_count, dma->buf_count);
- return -EINVAL;
- }
-
- d->granted_count = 0;
-
- if (d->request_count) {
- ret = radeon_cp_get_buffers(dev, file_priv, d);
- }
-
- return ret;
-}
-
-int radeon_driver_load(struct drm_device *dev, unsigned long flags)
-{
- drm_radeon_private_t *dev_priv;
- int ret = 0;
-
- dev_priv = kzalloc(sizeof(drm_radeon_private_t), GFP_KERNEL);
- if (dev_priv == NULL)
- return -ENOMEM;
-
- dev->dev_private = (void *)dev_priv;
- dev_priv->flags = flags;
-
- switch (flags & RADEON_FAMILY_MASK) {
- case CHIP_R100:
- case CHIP_RV200:
- case CHIP_R200:
- case CHIP_R300:
- case CHIP_R350:
- case CHIP_R420:
- case CHIP_R423:
- case CHIP_RV410:
- case CHIP_RV515:
- case CHIP_R520:
- case CHIP_RV570:
- case CHIP_R580:
- dev_priv->flags |= RADEON_HAS_HIERZ;
- break;
- default:
- /* all other chips have no hierarchical z buffer */
- break;
- }
-
- pci_set_master(dev->pdev);
-
- if (drm_pci_device_is_agp(dev))
- dev_priv->flags |= RADEON_IS_AGP;
- else if (pci_is_pcie(dev->pdev))
- dev_priv->flags |= RADEON_IS_PCIE;
- else
- dev_priv->flags |= RADEON_IS_PCI;
-
- ret = drm_legacy_addmap(dev, pci_resource_start(dev->pdev, 2),
- pci_resource_len(dev->pdev, 2), _DRM_REGISTERS,
- _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio);
- if (ret != 0)
- return ret;
-
- ret = drm_vblank_init(dev, 2);
- if (ret) {
- radeon_driver_unload(dev);
- return ret;
- }
-
- DRM_DEBUG("%s card detected\n",
- ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
- return ret;
-}
-
-int radeon_master_create(struct drm_device *dev, struct drm_master *master)
-{
- struct drm_radeon_master_private *master_priv;
- unsigned long sareapage;
- int ret;
-
- master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL);
- if (!master_priv)
- return -ENOMEM;
-
- /* prebuild the SAREA */
- sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
- ret = drm_legacy_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK,
- &master_priv->sarea);
- if (ret) {
- DRM_ERROR("SAREA setup failed\n");
- kfree(master_priv);
- return ret;
- }
- master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea);
- master_priv->sarea_priv->pfCurrentPage = 0;
-
- master->driver_priv = master_priv;
- return 0;
-}
-
-void radeon_master_destroy(struct drm_device *dev, struct drm_master *master)
-{
- struct drm_radeon_master_private *master_priv = master->driver_priv;
-
- if (!master_priv)
- return;
-
- if (master_priv->sarea_priv &&
- master_priv->sarea_priv->pfCurrentPage != 0)
- radeon_cp_dispatch_flip(dev, master);
-
- master_priv->sarea_priv = NULL;
- if (master_priv->sarea)
- drm_legacy_rmmap_locked(dev, master_priv->sarea);
-
- kfree(master_priv);
-
- master->driver_priv = NULL;
-}
-
-/* Create mappings for registers and framebuffer so userland doesn't necessarily
- * have to find them.
- */
-int radeon_driver_firstopen(struct drm_device *dev)
-{
- int ret;
- drm_local_map_t *map;
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
-
- dev_priv->fb_aper_offset = pci_resource_start(dev->pdev, 0);
- ret = drm_legacy_addmap(dev, dev_priv->fb_aper_offset,
- pci_resource_len(dev->pdev, 0),
- _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &map);
- if (ret != 0)
- return ret;
-
- return 0;
-}
-
-int radeon_driver_unload(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- DRM_DEBUG("\n");
-
- drm_legacy_rmmap(dev, dev_priv->mmio);
-
- kfree(dev_priv);
-
- dev->dev_private = NULL;
- return 0;
-}
-
-void radeon_commit_ring(drm_radeon_private_t *dev_priv)
-{
- int i;
- u32 *ring;
- int tail_aligned;
-
- /* check if the ring is padded out to 16-dword alignment */
-
- tail_aligned = dev_priv->ring.tail & (RADEON_RING_ALIGN-1);
- if (tail_aligned) {
- int num_p2 = RADEON_RING_ALIGN - tail_aligned;
-
- ring = dev_priv->ring.start;
- /* pad with some CP_PACKET2 */
- for (i = 0; i < num_p2; i++)
- ring[dev_priv->ring.tail + i] = CP_PACKET2();
-
- dev_priv->ring.tail += i;
-
- dev_priv->ring.space -= num_p2 * sizeof(u32);
- }
-
- dev_priv->ring.tail &= dev_priv->ring.tail_mask;
-
- mb();
- GET_RING_HEAD( dev_priv );
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
- RADEON_WRITE(R600_CP_RB_WPTR, dev_priv->ring.tail);
- /* read from PCI bus to ensure correct posting */
- RADEON_READ(R600_CP_RB_RPTR);
- } else {
- RADEON_WRITE(RADEON_CP_RB_WPTR, dev_priv->ring.tail);
- /* read from PCI bus to ensure correct posting */
- RADEON_READ(RADEON_CP_RB_RPTR);
- }
-}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index c566993a2ec3..902b59cebac5 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1150,7 +1150,7 @@ static void radeon_check_arguments(struct radeon_device *rdev)
}
if (radeon_vm_size < 1) {
- dev_warn(rdev->dev, "VM size (%d) to small, min is 1GB\n",
+ dev_warn(rdev->dev, "VM size (%d) too small, min is 1GB\n",
radeon_vm_size);
radeon_vm_size = 4;
}
@@ -1744,6 +1744,7 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
}
drm_kms_helper_poll_enable(dev);
+ drm_helper_hpd_irq_event(dev);
/* set the power state here in case we are a PX system or headless */
if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1eca0acac016..b3bb92368ae0 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1331,7 +1331,7 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = {
int
radeon_framebuffer_init(struct drm_device *dev,
struct radeon_framebuffer *rfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -1348,7 +1348,7 @@ radeon_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
radeon_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct radeon_framebuffer *radeon_fb;
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
index 744f5c49c664..df7a1719c841 100644
--- a/drivers/gpu/drm/radeon/radeon_dp_mst.c
+++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c
@@ -329,7 +329,7 @@ static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
drm_kms_helper_hotplug_event(dev);
}
-struct drm_dp_mst_topology_cbs mst_cbs = {
+const struct drm_dp_mst_topology_cbs mst_cbs = {
.add_connector = radeon_dp_add_mst_connector,
.register_connector = radeon_dp_register_mst_connector,
.destroy_connector = radeon_dp_destroy_mst_connector,
@@ -525,11 +525,17 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
drm_mode_set_crtcinfo(adjusted_mode, 0);
{
struct radeon_connector_atom_dig *dig_connector;
+ int ret;
dig_connector = mst_enc->connector->con_priv;
- dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
- dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
- dig_connector->dpcd);
+ ret = radeon_dp_get_dp_link_config(&mst_enc->connector->base,
+ dig_connector->dpcd, adjusted_mode->clock,
+ &dig_connector->dp_lane_count,
+ &dig_connector->dp_clock);
+ if (ret) {
+ dig_connector->dp_lane_count = 0;
+ dig_connector->dp_clock = 0;
+ }
DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
dig_connector->dp_lane_count, dig_connector->dp_clock);
}
@@ -641,7 +647,7 @@ radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector)
}
drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs,
- DRM_MODE_ENCODER_DPMST);
+ DRM_MODE_ENCODER_DPMST, NULL);
drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs);
mst_enc = radeon_encoder->enc_priv;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 5b6a6f5b3619..e266ffc520d2 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -291,88 +291,6 @@ static struct pci_device_id pciidlist[] = {
MODULE_DEVICE_TABLE(pci, pciidlist);
-#ifdef CONFIG_DRM_RADEON_UMS
-
-static int radeon_suspend(struct drm_device *dev, pm_message_t state)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return 0;
-
- /* Disable *all* interrupts */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
- RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
- RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
- return 0;
-}
-
-static int radeon_resume(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return 0;
-
- /* Restore interrupt registers */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
- RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
- RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
- return 0;
-}
-
-
-static const struct file_operations radeon_driver_old_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
- .read = drm_read,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = radeon_compat_ioctl,
-#endif
- .llseek = noop_llseek,
-};
-
-static struct drm_driver driver_old = {
- .driver_features =
- DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
- .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
- .load = radeon_driver_load,
- .firstopen = radeon_driver_firstopen,
- .open = radeon_driver_open,
- .preclose = radeon_driver_preclose,
- .postclose = radeon_driver_postclose,
- .lastclose = radeon_driver_lastclose,
- .set_busid = drm_pci_set_busid,
- .unload = radeon_driver_unload,
- .suspend = radeon_suspend,
- .resume = radeon_resume,
- .get_vblank_counter = radeon_get_vblank_counter,
- .enable_vblank = radeon_enable_vblank,
- .disable_vblank = radeon_disable_vblank,
- .master_create = radeon_master_create,
- .master_destroy = radeon_master_destroy,
- .irq_preinstall = radeon_driver_irq_preinstall,
- .irq_postinstall = radeon_driver_irq_postinstall,
- .irq_uninstall = radeon_driver_irq_uninstall,
- .irq_handler = radeon_driver_irq_handler,
- .ioctls = radeon_ioctls,
- .dma_ioctl = radeon_cp_buffers,
- .fops = &radeon_driver_old_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-#endif
-
static struct drm_driver kms_driver;
static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
@@ -619,13 +537,6 @@ static struct drm_driver kms_driver = {
static struct drm_driver *driver;
static struct pci_driver *pdriver;
-#ifdef CONFIG_DRM_RADEON_UMS
-static struct pci_driver radeon_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-#endif
-
static struct pci_driver radeon_kms_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
@@ -655,16 +566,8 @@ static int __init radeon_init(void)
radeon_register_atpx_handler();
} else {
-#ifdef CONFIG_DRM_RADEON_UMS
- DRM_INFO("radeon userspace modesetting enabled.\n");
- driver = &driver_old;
- pdriver = &radeon_pci_driver;
- driver->driver_features &= ~DRIVER_MODESET;
- driver->num_ioctls = radeon_max_ioctl;
-#else
DRM_ERROR("No UMS support in radeon module!\n");
return -EINVAL;
-#endif
}
radeon_kfd_init();
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index 0caafc7a6e17..afef2d9fccd8 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -119,2052 +119,4 @@
long radeon_drm_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
-/* The rest of the file is DEPRECATED! */
-#ifdef CONFIG_DRM_RADEON_UMS
-
-enum radeon_cp_microcode_version {
- UCODE_R100,
- UCODE_R200,
- UCODE_R300,
-};
-
-typedef struct drm_radeon_freelist {
- unsigned int age;
- struct drm_buf *buf;
- struct drm_radeon_freelist *next;
- struct drm_radeon_freelist *prev;
-} drm_radeon_freelist_t;
-
-typedef struct drm_radeon_ring_buffer {
- u32 *start;
- u32 *end;
- int size;
- int size_l2qw;
-
- int rptr_update; /* Double Words */
- int rptr_update_l2qw; /* log2 Quad Words */
-
- int fetch_size; /* Double Words */
- int fetch_size_l2ow; /* log2 Oct Words */
-
- u32 tail;
- u32 tail_mask;
- int space;
-
- int high_mark;
-} drm_radeon_ring_buffer_t;
-
-typedef struct drm_radeon_depth_clear_t {
- u32 rb3d_cntl;
- u32 rb3d_zstencilcntl;
- u32 se_cntl;
-} drm_radeon_depth_clear_t;
-
-struct drm_radeon_driver_file_fields {
- int64_t radeon_fb_delta;
-};
-
-struct mem_block {
- struct mem_block *next;
- struct mem_block *prev;
- int start;
- int size;
- struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
-};
-
-struct radeon_surface {
- int refcount;
- u32 lower;
- u32 upper;
- u32 flags;
-};
-
-struct radeon_virt_surface {
- int surface_index;
- u32 lower;
- u32 upper;
- u32 flags;
- struct drm_file *file_priv;
-#define PCIGART_FILE_PRIV ((void *) -1L)
-};
-
-#define RADEON_FLUSH_EMITED (1 << 0)
-#define RADEON_PURGE_EMITED (1 << 1)
-
-struct drm_radeon_master_private {
- drm_local_map_t *sarea;
- drm_radeon_sarea_t *sarea_priv;
-};
-
-typedef struct drm_radeon_private {
- drm_radeon_ring_buffer_t ring;
-
- u32 fb_location;
- u32 fb_size;
- int new_memmap;
-
- int gart_size;
- u32 gart_vm_start;
- unsigned long gart_buffers_offset;
-
- int cp_mode;
- int cp_running;
-
- drm_radeon_freelist_t *head;
- drm_radeon_freelist_t *tail;
- int last_buf;
- int writeback_works;
-
- int usec_timeout;
-
- int microcode_version;
-
- struct {
- u32 boxes;
- int freelist_timeouts;
- int freelist_loops;
- int requested_bufs;
- int last_frame_reads;
- int last_clear_reads;
- int clears;
- int texture_uploads;
- } stats;
-
- int do_boxes;
- int page_flipping;
-
- u32 color_fmt;
- unsigned int front_offset;
- unsigned int front_pitch;
- unsigned int back_offset;
- unsigned int back_pitch;
-
- u32 depth_fmt;
- unsigned int depth_offset;
- unsigned int depth_pitch;
-
- u32 front_pitch_offset;
- u32 back_pitch_offset;
- u32 depth_pitch_offset;
-
- drm_radeon_depth_clear_t depth_clear;
-
- unsigned long ring_offset;
- unsigned long ring_rptr_offset;
- unsigned long buffers_offset;
- unsigned long gart_textures_offset;
-
- drm_local_map_t *sarea;
- drm_local_map_t *cp_ring;
- drm_local_map_t *ring_rptr;
- drm_local_map_t *gart_textures;
-
- struct mem_block *gart_heap;
- struct mem_block *fb_heap;
-
- /* SW interrupt */
- wait_queue_head_t swi_queue;
- atomic_t swi_emitted;
- int vblank_crtc;
- uint32_t irq_enable_reg;
- uint32_t r500_disp_irq_reg;
-
- struct radeon_surface surfaces[RADEON_MAX_SURFACES];
- struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
-
- unsigned long pcigart_offset;
- unsigned int pcigart_offset_set;
- struct drm_ati_pcigart_info gart_info;
-
- u32 scratch_ages[5];
-
- int have_z_offset;
-
- /* starting from here on, data is preserved across an open */
- uint32_t flags; /* see radeon_chip_flags */
- resource_size_t fb_aper_offset;
-
- int num_gb_pipes;
- int num_z_pipes;
- int track_flush;
- drm_local_map_t *mmio;
-
- /* r6xx/r7xx pipe/shader config */
- int r600_max_pipes;
- int r600_max_tile_pipes;
- int r600_max_simds;
- int r600_max_backends;
- int r600_max_gprs;
- int r600_max_threads;
- int r600_max_stack_entries;
- int r600_max_hw_contexts;
- int r600_max_gs_threads;
- int r600_sx_max_export_size;
- int r600_sx_max_export_pos_size;
- int r600_sx_max_export_smx_size;
- int r600_sq_num_cf_insts;
- int r700_sx_num_of_sets;
- int r700_sc_prim_fifo_size;
- int r700_sc_hiz_tile_fifo_size;
- int r700_sc_earlyz_tile_fifo_fize;
- int r600_group_size;
- int r600_npipes;
- int r600_nbanks;
-
- struct mutex cs_mutex;
- u32 cs_id_scnt;
- u32 cs_id_wcnt;
- /* r6xx/r7xx drm blit vertex buffer */
- struct drm_buf *blit_vb;
-
- /* firmware */
- const struct firmware *me_fw, *pfp_fw;
-} drm_radeon_private_t;
-
-typedef struct drm_radeon_buf_priv {
- u32 age;
-} drm_radeon_buf_priv_t;
-
-struct drm_buffer;
-
-typedef struct drm_radeon_kcmd_buffer {
- int bufsz;
- struct drm_buffer *buffer;
- int nbox;
- struct drm_clip_rect __user *boxes;
-} drm_radeon_kcmd_buffer_t;
-
-extern int radeon_no_wb;
-extern struct drm_ioctl_desc radeon_ioctls[];
-extern int radeon_max_ioctl;
-
-extern u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv);
-extern void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val);
-
-#define GET_RING_HEAD(dev_priv) radeon_get_ring_head(dev_priv)
-#define SET_RING_HEAD(dev_priv, val) radeon_set_ring_head(dev_priv, val)
-
-/* Check whether the given hardware address is inside the framebuffer or the
- * GART area.
- */
-static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
- u64 off)
-{
- u32 fb_start = dev_priv->fb_location;
- u32 fb_end = fb_start + dev_priv->fb_size - 1;
- u32 gart_start = dev_priv->gart_vm_start;
- u32 gart_end = gart_start + dev_priv->gart_size - 1;
-
- return ((off >= fb_start && off <= fb_end) ||
- (off >= gart_start && off <= gart_end));
-}
-
-/* radeon_state.c */
-extern void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf);
-
- /* radeon_cp.c */
-extern int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);
-extern void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc);
-extern void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base);
-
-extern void radeon_freelist_reset(struct drm_device * dev);
-extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
-
-extern int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n);
-
-extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv);
-
-extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
-extern int radeon_presetup(struct drm_device *dev);
-extern int radeon_driver_postcleanup(struct drm_device *dev);
-
-extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern void radeon_mem_takedown(struct mem_block **heap);
-extern void radeon_mem_release(struct drm_file *file_priv,
- struct mem_block *heap);
-
-extern void radeon_enable_bm(struct drm_radeon_private *dev_priv);
-extern u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off);
-extern void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val);
-
- /* radeon_irq.c */
-extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
-extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
-
-extern void radeon_do_release(struct drm_device * dev);
-extern u32 radeon_get_vblank_counter(struct drm_device *dev, unsigned int pipe);
-extern int radeon_enable_vblank(struct drm_device *dev, unsigned int pipe);
-extern void radeon_disable_vblank(struct drm_device *dev, unsigned int pipe);
-extern irqreturn_t radeon_driver_irq_handler(int irq, void *arg);
-extern void radeon_driver_irq_preinstall(struct drm_device * dev);
-extern int radeon_driver_irq_postinstall(struct drm_device *dev);
-extern void radeon_driver_irq_uninstall(struct drm_device * dev);
-extern void radeon_enable_interrupt(struct drm_device *dev);
-extern int radeon_vblank_crtc_get(struct drm_device *dev);
-extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
-
-extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
-extern int radeon_driver_unload(struct drm_device *dev);
-extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(struct drm_device *dev,
- struct drm_file *file_priv);
-extern void radeon_driver_postclose(struct drm_device *dev,
- struct drm_file *file_priv);
-extern void radeon_driver_lastclose(struct drm_device * dev);
-extern int radeon_driver_open(struct drm_device *dev,
- struct drm_file *file_priv);
-extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg);
-
-extern int radeon_master_create(struct drm_device *dev, struct drm_master *master);
-extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master);
-extern void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master);
-/* r300_cmdbuf.c */
-extern void r300_init_reg_flags(struct drm_device *dev);
-
-extern int r300_do_cp_cmdbuf(struct drm_device *dev,
- struct drm_file *file_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf);
-
-/* r600_cp.c */
-extern int r600_do_engine_reset(struct drm_device *dev);
-extern int r600_do_cleanup_cp(struct drm_device *dev);
-extern int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
- struct drm_file *file_priv);
-extern int r600_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv);
-extern int r600_do_cp_idle(drm_radeon_private_t *dev_priv);
-extern void r600_do_cp_start(drm_radeon_private_t *dev_priv);
-extern void r600_do_cp_reset(drm_radeon_private_t *dev_priv);
-extern void r600_do_cp_stop(drm_radeon_private_t *dev_priv);
-extern int r600_cp_dispatch_indirect(struct drm_device *dev,
- struct drm_buf *buf, int start, int end);
-extern int r600_page_table_init(struct drm_device *dev);
-extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
-extern int r600_cs_legacy_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv);
-extern void r600_cp_dispatch_swap(struct drm_device *dev, struct drm_file *file_priv);
-extern int r600_cp_dispatch_texture(struct drm_device *dev,
- struct drm_file *file_priv,
- drm_radeon_texture_t *tex,
- drm_radeon_tex_image_t *image);
-/* r600_blit.c */
-extern int r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv);
-extern void r600_done_blit_copy(struct drm_device *dev);
-extern void r600_blit_copy(struct drm_device *dev,
- uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
- int size_bytes);
-extern void r600_blit_swap(struct drm_device *dev,
- uint64_t src_gpu_addr, uint64_t dst_gpu_addr,
- int sx, int sy, int dx, int dy,
- int w, int h, int src_pitch, int dst_pitch, int cpp);
-
-/* Flags for stats.boxes
- */
-#define RADEON_BOX_DMA_IDLE 0x1
-#define RADEON_BOX_RING_FULL 0x2
-#define RADEON_BOX_FLIP 0x4
-#define RADEON_BOX_WAIT_IDLE 0x8
-#define RADEON_BOX_TEXTURE_LOAD 0x10
-
-/* Register definitions, register access macros and drmAddMap constants
- * for Radeon kernel driver.
- */
-#define RADEON_MM_INDEX 0x0000
-#define RADEON_MM_DATA 0x0004
-
-#define RADEON_AGP_COMMAND 0x0f60
-#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config */
-# define RADEON_AGP_ENABLE (1<<8)
-#define RADEON_AUX_SCISSOR_CNTL 0x26f0
-# define RADEON_EXCLUSIVE_SCISSOR_0 (1 << 24)
-# define RADEON_EXCLUSIVE_SCISSOR_1 (1 << 25)
-# define RADEON_EXCLUSIVE_SCISSOR_2 (1 << 26)
-# define RADEON_SCISSOR_0_ENABLE (1 << 28)
-# define RADEON_SCISSOR_1_ENABLE (1 << 29)
-# define RADEON_SCISSOR_2_ENABLE (1 << 30)
-
-/*
- * PCIE radeons (rv370/rv380, rv410, r423/r430/r480, r5xx)
- * don't have an explicit bus mastering disable bit. It's handled
- * by the PCI D-states. PMI_BM_DIS disables D-state bus master
- * handling, not bus mastering itself.
- */
-#define RADEON_BUS_CNTL 0x0030
-/* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
-# define RADEON_BUS_MASTER_DIS (1 << 6)
-/* rs600/rs690/rs740 */
-# define RS600_BUS_MASTER_DIS (1 << 14)
-# define RS600_MSI_REARM (1 << 20)
-/* see RS400_MSI_REARM in AIC_CNTL for rs480 */
-
-#define RADEON_BUS_CNTL1 0x0034
-# define RADEON_PMI_BM_DIS (1 << 2)
-# define RADEON_PMI_INT_DIS (1 << 3)
-
-#define RV370_BUS_CNTL 0x004c
-# define RV370_PMI_BM_DIS (1 << 5)
-# define RV370_PMI_INT_DIS (1 << 6)
-
-#define RADEON_MSI_REARM_EN 0x0160
-/* rv370/rv380, rv410, r423/r430/r480, r5xx */
-# define RV370_MSI_REARM_EN (1 << 0)
-
-#define RADEON_CLOCK_CNTL_DATA 0x000c
-# define RADEON_PLL_WR_EN (1 << 7)
-#define RADEON_CLOCK_CNTL_INDEX 0x0008
-#define RADEON_CONFIG_APER_SIZE 0x0108
-#define RADEON_CONFIG_MEMSIZE 0x00f8
-#define RADEON_CRTC_OFFSET 0x0224
-#define RADEON_CRTC_OFFSET_CNTL 0x0228
-# define RADEON_CRTC_TILE_EN (1 << 15)
-# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16)
-#define RADEON_CRTC2_OFFSET 0x0324
-#define RADEON_CRTC2_OFFSET_CNTL 0x0328
-
-#define RADEON_PCIE_INDEX 0x0030
-#define RADEON_PCIE_DATA 0x0034
-#define RADEON_PCIE_TX_GART_CNTL 0x10
-# define RADEON_PCIE_TX_GART_EN (1 << 0)
-# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0 << 1)
-# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO (1 << 1)
-# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD (3 << 1)
-# define RADEON_PCIE_TX_GART_MODE_32_128_CACHE (0 << 3)
-# define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE (1 << 3)
-# define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN (1 << 5)
-# define RADEON_PCIE_TX_GART_INVALIDATE_TLB (1 << 8)
-#define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11
-#define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12
-#define RADEON_PCIE_TX_GART_BASE 0x13
-#define RADEON_PCIE_TX_GART_START_LO 0x14
-#define RADEON_PCIE_TX_GART_START_HI 0x15
-#define RADEON_PCIE_TX_GART_END_LO 0x16
-#define RADEON_PCIE_TX_GART_END_HI 0x17
-
-#define RS480_NB_MC_INDEX 0x168
-# define RS480_NB_MC_IND_WR_EN (1 << 8)
-#define RS480_NB_MC_DATA 0x16c
-
-#define RS690_MC_INDEX 0x78
-# define RS690_MC_INDEX_MASK 0x1ff
-# define RS690_MC_INDEX_WR_EN (1 << 9)
-# define RS690_MC_INDEX_WR_ACK 0x7f
-#define RS690_MC_DATA 0x7c
-
-/* MC indirect registers */
-#define RS480_MC_MISC_CNTL 0x18
-# define RS480_DISABLE_GTW (1 << 1)
-/* switch between MCIND GART and MM GART registers. 0 = mmgart, 1 = mcind gart */
-# define RS480_GART_INDEX_REG_EN (1 << 12)
-# define RS690_BLOCK_GFX_D3_EN (1 << 14)
-#define RS480_K8_FB_LOCATION 0x1e
-#define RS480_GART_FEATURE_ID 0x2b
-# define RS480_HANG_EN (1 << 11)
-# define RS480_TLB_ENABLE (1 << 18)
-# define RS480_P2P_ENABLE (1 << 19)
-# define RS480_GTW_LAC_EN (1 << 25)
-# define RS480_2LEVEL_GART (0 << 30)
-# define RS480_1LEVEL_GART (1 << 30)
-# define RS480_PDC_EN (1 << 31)
-#define RS480_GART_BASE 0x2c
-#define RS480_GART_CACHE_CNTRL 0x2e
-# define RS480_GART_CACHE_INVALIDATE (1 << 0) /* wait for it to clear */
-#define RS480_AGP_ADDRESS_SPACE_SIZE 0x38
-# define RS480_GART_EN (1 << 0)
-# define RS480_VA_SIZE_32MB (0 << 1)
-# define RS480_VA_SIZE_64MB (1 << 1)
-# define RS480_VA_SIZE_128MB (2 << 1)
-# define RS480_VA_SIZE_256MB (3 << 1)
-# define RS480_VA_SIZE_512MB (4 << 1)
-# define RS480_VA_SIZE_1GB (5 << 1)
-# define RS480_VA_SIZE_2GB (6 << 1)
-#define RS480_AGP_MODE_CNTL 0x39
-# define RS480_POST_GART_Q_SIZE (1 << 18)
-# define RS480_NONGART_SNOOP (1 << 19)
-# define RS480_AGP_RD_BUF_SIZE (1 << 20)
-# define RS480_REQ_TYPE_SNOOP_SHIFT 22
-# define RS480_REQ_TYPE_SNOOP_MASK 0x3
-# define RS480_REQ_TYPE_SNOOP_DIS (1 << 24)
-#define RS480_MC_MISC_UMA_CNTL 0x5f
-#define RS480_MC_MCLK_CNTL 0x7a
-#define RS480_MC_UMA_DUALCH_CNTL 0x86
-
-#define RS690_MC_FB_LOCATION 0x100
-#define RS690_MC_AGP_LOCATION 0x101
-#define RS690_MC_AGP_BASE 0x102
-#define RS690_MC_AGP_BASE_2 0x103
-
-#define RS600_MC_INDEX 0x70
-# define RS600_MC_ADDR_MASK 0xffff
-# define RS600_MC_IND_SEQ_RBS_0 (1 << 16)
-# define RS600_MC_IND_SEQ_RBS_1 (1 << 17)
-# define RS600_MC_IND_SEQ_RBS_2 (1 << 18)
-# define RS600_MC_IND_SEQ_RBS_3 (1 << 19)
-# define RS600_MC_IND_AIC_RBS (1 << 20)
-# define RS600_MC_IND_CITF_ARB0 (1 << 21)
-# define RS600_MC_IND_CITF_ARB1 (1 << 22)
-# define RS600_MC_IND_WR_EN (1 << 23)
-#define RS600_MC_DATA 0x74
-
-#define RS600_MC_STATUS 0x0
-# define RS600_MC_IDLE (1 << 1)
-#define RS600_MC_FB_LOCATION 0x4
-#define RS600_MC_AGP_LOCATION 0x5
-#define RS600_AGP_BASE 0x6
-#define RS600_AGP_BASE_2 0x7
-#define RS600_MC_CNTL1 0x9
-# define RS600_ENABLE_PAGE_TABLES (1 << 26)
-#define RS600_MC_PT0_CNTL 0x100
-# define RS600_ENABLE_PT (1 << 0)
-# define RS600_EFFECTIVE_L2_CACHE_SIZE(x) ((x) << 15)
-# define RS600_EFFECTIVE_L2_QUEUE_SIZE(x) ((x) << 21)
-# define RS600_INVALIDATE_ALL_L1_TLBS (1 << 28)
-# define RS600_INVALIDATE_L2_CACHE (1 << 29)
-#define RS600_MC_PT0_CONTEXT0_CNTL 0x102
-# define RS600_ENABLE_PAGE_TABLE (1 << 0)
-# define RS600_PAGE_TABLE_TYPE_FLAT (0 << 1)
-#define RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR 0x112
-#define RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR 0x114
-#define RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x11c
-#define RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR 0x12c
-#define RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR 0x13c
-#define RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR 0x14c
-#define RS600_MC_PT0_CLIENT0_CNTL 0x16c
-# define RS600_ENABLE_TRANSLATION_MODE_OVERRIDE (1 << 0)
-# define RS600_TRANSLATION_MODE_OVERRIDE (1 << 1)
-# define RS600_SYSTEM_ACCESS_MODE_MASK (3 << 8)
-# define RS600_SYSTEM_ACCESS_MODE_PA_ONLY (0 << 8)
-# define RS600_SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 8)
-# define RS600_SYSTEM_ACCESS_MODE_IN_SYS (2 << 8)
-# define RS600_SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 8)
-# define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH (0 << 10)
-# define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 10)
-# define RS600_EFFECTIVE_L1_CACHE_SIZE(x) ((x) << 11)
-# define RS600_ENABLE_FRAGMENT_PROCESSING (1 << 14)
-# define RS600_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
-# define RS600_INVALIDATE_L1_TLB (1 << 20)
-
-#define R520_MC_IND_INDEX 0x70
-#define R520_MC_IND_WR_EN (1 << 24)
-#define R520_MC_IND_DATA 0x74
-
-#define RV515_MC_FB_LOCATION 0x01
-#define RV515_MC_AGP_LOCATION 0x02
-#define RV515_MC_AGP_BASE 0x03
-#define RV515_MC_AGP_BASE_2 0x04
-
-#define R520_MC_FB_LOCATION 0x04
-#define R520_MC_AGP_LOCATION 0x05
-#define R520_MC_AGP_BASE 0x06
-#define R520_MC_AGP_BASE_2 0x07
-
-#define RADEON_MPP_TB_CONFIG 0x01c0
-#define RADEON_MEM_CNTL 0x0140
-#define RADEON_MEM_SDRAM_MODE_REG 0x0158
-#define RADEON_AGP_BASE_2 0x015c /* r200+ only */
-#define RS480_AGP_BASE_2 0x0164
-#define RADEON_AGP_BASE 0x0170
-
-/* pipe config regs */
-#define R400_GB_PIPE_SELECT 0x402c
-#define RV530_GB_PIPE_SELECT2 0x4124
-#define R500_DYN_SCLK_PWMEM_PIPE 0x000d /* PLL */
-#define R300_GB_TILE_CONFIG 0x4018
-# define R300_ENABLE_TILING (1 << 0)
-# define R300_PIPE_COUNT_RV350 (0 << 1)
-# define R300_PIPE_COUNT_R300 (3 << 1)
-# define R300_PIPE_COUNT_R420_3P (6 << 1)
-# define R300_PIPE_COUNT_R420 (7 << 1)
-# define R300_TILE_SIZE_8 (0 << 4)
-# define R300_TILE_SIZE_16 (1 << 4)
-# define R300_TILE_SIZE_32 (2 << 4)
-# define R300_SUBPIXEL_1_12 (0 << 16)
-# define R300_SUBPIXEL_1_16 (1 << 16)
-#define R300_DST_PIPE_CONFIG 0x170c
-# define R300_PIPE_AUTO_CONFIG (1 << 31)
-#define R300_RB2D_DSTCACHE_MODE 0x3428
-# define R300_DC_AUTOFLUSH_ENABLE (1 << 8)
-# define R300_DC_DC_DISABLE_IGNORE_PE (1 << 17)
-
-#define RADEON_RB3D_COLOROFFSET 0x1c40
-#define RADEON_RB3D_COLORPITCH 0x1c48
-
-#define RADEON_SRC_X_Y 0x1590
-
-#define RADEON_DP_GUI_MASTER_CNTL 0x146c
-# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
-# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
-# define RADEON_GMC_BRUSH_SOLID_COLOR (13 << 4)
-# define RADEON_GMC_BRUSH_NONE (15 << 4)
-# define RADEON_GMC_DST_16BPP (4 << 8)
-# define RADEON_GMC_DST_24BPP (5 << 8)
-# define RADEON_GMC_DST_32BPP (6 << 8)
-# define RADEON_GMC_DST_DATATYPE_SHIFT 8
-# define RADEON_GMC_SRC_DATATYPE_COLOR (3 << 12)
-# define RADEON_DP_SRC_SOURCE_MEMORY (2 << 24)
-# define RADEON_DP_SRC_SOURCE_HOST_DATA (3 << 24)
-# define RADEON_GMC_CLR_CMP_CNTL_DIS (1 << 28)
-# define RADEON_GMC_WR_MSK_DIS (1 << 30)
-# define RADEON_ROP3_S 0x00cc0000
-# define RADEON_ROP3_P 0x00f00000
-#define RADEON_DP_WRITE_MASK 0x16cc
-#define RADEON_SRC_PITCH_OFFSET 0x1428
-#define RADEON_DST_PITCH_OFFSET 0x142c
-#define RADEON_DST_PITCH_OFFSET_C 0x1c80
-# define RADEON_DST_TILE_LINEAR (0 << 30)
-# define RADEON_DST_TILE_MACRO (1 << 30)
-# define RADEON_DST_TILE_MICRO (2 << 30)
-# define RADEON_DST_TILE_BOTH (3 << 30)
-
-#define RADEON_SCRATCH_REG0 0x15e0
-#define RADEON_SCRATCH_REG1 0x15e4
-#define RADEON_SCRATCH_REG2 0x15e8
-#define RADEON_SCRATCH_REG3 0x15ec
-#define RADEON_SCRATCH_REG4 0x15f0
-#define RADEON_SCRATCH_REG5 0x15f4
-#define RADEON_SCRATCH_UMSK 0x0770
-#define RADEON_SCRATCH_ADDR 0x0774
-
-#define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x))
-
-extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index);
-
-#define GET_SCRATCH(dev_priv, x) radeon_get_scratch(dev_priv, x)
-
-#define R600_SCRATCH_REG0 0x8500
-#define R600_SCRATCH_REG1 0x8504
-#define R600_SCRATCH_REG2 0x8508
-#define R600_SCRATCH_REG3 0x850c
-#define R600_SCRATCH_REG4 0x8510
-#define R600_SCRATCH_REG5 0x8514
-#define R600_SCRATCH_REG6 0x8518
-#define R600_SCRATCH_REG7 0x851c
-#define R600_SCRATCH_UMSK 0x8540
-#define R600_SCRATCH_ADDR 0x8544
-
-#define R600_SCRATCHOFF(x) (R600_SCRATCH_REG_OFFSET + 4*(x))
-
-#define RADEON_GEN_INT_CNTL 0x0040
-# define RADEON_CRTC_VBLANK_MASK (1 << 0)
-# define RADEON_CRTC2_VBLANK_MASK (1 << 9)
-# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
-# define RADEON_SW_INT_ENABLE (1 << 25)
-
-#define RADEON_GEN_INT_STATUS 0x0044
-# define RADEON_CRTC_VBLANK_STAT (1 << 0)
-# define RADEON_CRTC_VBLANK_STAT_ACK (1 << 0)
-# define RADEON_CRTC2_VBLANK_STAT (1 << 9)
-# define RADEON_CRTC2_VBLANK_STAT_ACK (1 << 9)
-# define RADEON_GUI_IDLE_INT_TEST_ACK (1 << 19)
-# define RADEON_SW_INT_TEST (1 << 25)
-# define RADEON_SW_INT_TEST_ACK (1 << 25)
-# define RADEON_SW_INT_FIRE (1 << 26)
-# define R500_DISPLAY_INT_STATUS (1 << 0)
-
-#define RADEON_HOST_PATH_CNTL 0x0130
-# define RADEON_HDP_SOFT_RESET (1 << 26)
-# define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28)
-# define RADEON_HDP_WC_TIMEOUT_28BCLK (7 << 28)
-
-#define RADEON_ISYNC_CNTL 0x1724
-# define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0)
-# define RADEON_ISYNC_ANY3D_IDLE2D (1 << 1)
-# define RADEON_ISYNC_TRIG2D_IDLE3D (1 << 2)
-# define RADEON_ISYNC_TRIG3D_IDLE2D (1 << 3)
-# define RADEON_ISYNC_WAIT_IDLEGUI (1 << 4)
-# define RADEON_ISYNC_CPSCRATCH_IDLEGUI (1 << 5)
-
-#define RADEON_RBBM_GUICNTL 0x172c
-# define RADEON_HOST_DATA_SWAP_NONE (0 << 0)
-# define RADEON_HOST_DATA_SWAP_16BIT (1 << 0)
-# define RADEON_HOST_DATA_SWAP_32BIT (2 << 0)
-# define RADEON_HOST_DATA_SWAP_HDW (3 << 0)
-
-#define RADEON_MC_AGP_LOCATION 0x014c
-#define RADEON_MC_FB_LOCATION 0x0148
-#define RADEON_MCLK_CNTL 0x0012
-# define RADEON_FORCEON_MCLKA (1 << 16)
-# define RADEON_FORCEON_MCLKB (1 << 17)
-# define RADEON_FORCEON_YCLKA (1 << 18)
-# define RADEON_FORCEON_YCLKB (1 << 19)
-# define RADEON_FORCEON_MC (1 << 20)
-# define RADEON_FORCEON_AIC (1 << 21)
-
-#define RADEON_PP_BORDER_COLOR_0 0x1d40
-#define RADEON_PP_BORDER_COLOR_1 0x1d44
-#define RADEON_PP_BORDER_COLOR_2 0x1d48
-#define RADEON_PP_CNTL 0x1c38
-# define RADEON_SCISSOR_ENABLE (1 << 1)
-#define RADEON_PP_LUM_MATRIX 0x1d00
-#define RADEON_PP_MISC 0x1c14
-#define RADEON_PP_ROT_MATRIX_0 0x1d58
-#define RADEON_PP_TXFILTER_0 0x1c54
-#define RADEON_PP_TXOFFSET_0 0x1c5c
-#define RADEON_PP_TXFILTER_1 0x1c6c
-#define RADEON_PP_TXFILTER_2 0x1c84
-
-#define R300_RB2D_DSTCACHE_CTLSTAT 0x342c /* use R300_DSTCACHE_CTLSTAT */
-#define R300_DSTCACHE_CTLSTAT 0x1714
-# define R300_RB2D_DC_FLUSH (3 << 0)
-# define R300_RB2D_DC_FREE (3 << 2)
-# define R300_RB2D_DC_FLUSH_ALL 0xf
-# define R300_RB2D_DC_BUSY (1 << 31)
-#define RADEON_RB3D_CNTL 0x1c3c
-# define RADEON_ALPHA_BLEND_ENABLE (1 << 0)
-# define RADEON_PLANE_MASK_ENABLE (1 << 1)
-# define RADEON_DITHER_ENABLE (1 << 2)
-# define RADEON_ROUND_ENABLE (1 << 3)
-# define RADEON_SCALE_DITHER_ENABLE (1 << 4)
-# define RADEON_DITHER_INIT (1 << 5)
-# define RADEON_ROP_ENABLE (1 << 6)
-# define RADEON_STENCIL_ENABLE (1 << 7)
-# define RADEON_Z_ENABLE (1 << 8)
-# define RADEON_ZBLOCK16 (1 << 15)
-#define RADEON_RB3D_DEPTHOFFSET 0x1c24
-#define RADEON_RB3D_DEPTHCLEARVALUE 0x3230
-#define RADEON_RB3D_DEPTHPITCH 0x1c28
-#define RADEON_RB3D_PLANEMASK 0x1d84
-#define RADEON_RB3D_STENCILREFMASK 0x1d7c
-#define RADEON_RB3D_ZCACHE_MODE 0x3250
-#define RADEON_RB3D_ZCACHE_CTLSTAT 0x3254
-# define RADEON_RB3D_ZC_FLUSH (1 << 0)
-# define RADEON_RB3D_ZC_FREE (1 << 2)
-# define RADEON_RB3D_ZC_FLUSH_ALL 0x5
-# define RADEON_RB3D_ZC_BUSY (1 << 31)
-#define R300_ZB_ZCACHE_CTLSTAT 0x4f18
-# define R300_ZC_FLUSH (1 << 0)
-# define R300_ZC_FREE (1 << 1)
-# define R300_ZC_BUSY (1 << 31)
-#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c
-# define RADEON_RB3D_DC_FLUSH (3 << 0)
-# define RADEON_RB3D_DC_FREE (3 << 2)
-# define RADEON_RB3D_DC_FLUSH_ALL 0xf
-# define RADEON_RB3D_DC_BUSY (1 << 31)
-#define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c
-# define R300_RB3D_DC_FLUSH (2 << 0)
-# define R300_RB3D_DC_FREE (2 << 2)
-# define R300_RB3D_DC_FINISH (1 << 4)
-#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c
-# define RADEON_Z_TEST_MASK (7 << 4)
-# define RADEON_Z_TEST_ALWAYS (7 << 4)
-# define RADEON_Z_HIERARCHY_ENABLE (1 << 8)
-# define RADEON_STENCIL_TEST_ALWAYS (7 << 12)
-# define RADEON_STENCIL_S_FAIL_REPLACE (2 << 16)
-# define RADEON_STENCIL_ZPASS_REPLACE (2 << 20)
-# define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24)
-# define RADEON_Z_COMPRESSION_ENABLE (1 << 28)
-# define RADEON_FORCE_Z_DIRTY (1 << 29)
-# define RADEON_Z_WRITE_ENABLE (1 << 30)
-# define RADEON_Z_DECOMPRESSION_ENABLE (1 << 31)
-#define RADEON_RBBM_SOFT_RESET 0x00f0
-# define RADEON_SOFT_RESET_CP (1 << 0)
-# define RADEON_SOFT_RESET_HI (1 << 1)
-# define RADEON_SOFT_RESET_SE (1 << 2)
-# define RADEON_SOFT_RESET_RE (1 << 3)
-# define RADEON_SOFT_RESET_PP (1 << 4)
-# define RADEON_SOFT_RESET_E2 (1 << 5)
-# define RADEON_SOFT_RESET_RB (1 << 6)
-# define RADEON_SOFT_RESET_HDP (1 << 7)
-/*
- * 6:0 Available slots in the FIFO
- * 8 Host Interface active
- * 9 CP request active
- * 10 FIFO request active
- * 11 Host Interface retry active
- * 12 CP retry active
- * 13 FIFO retry active
- * 14 FIFO pipeline busy
- * 15 Event engine busy
- * 16 CP command stream busy
- * 17 2D engine busy
- * 18 2D portion of render backend busy
- * 20 3D setup engine busy
- * 26 GA engine busy
- * 27 CBA 2D engine busy
- * 31 2D engine busy or 3D engine busy or FIFO not empty or CP busy or
- * command stream queue not empty or Ring Buffer not empty
- */
-#define RADEON_RBBM_STATUS 0x0e40
-/* Same as the previous RADEON_RBBM_STATUS; this is a mirror of that register. */
-/* #define RADEON_RBBM_STATUS 0x1740 */
-/* bits 6:0 are dword slots available in the cmd fifo */
-# define RADEON_RBBM_FIFOCNT_MASK 0x007f
-# define RADEON_HIRQ_ON_RBB (1 << 8)
-# define RADEON_CPRQ_ON_RBB (1 << 9)
-# define RADEON_CFRQ_ON_RBB (1 << 10)
-# define RADEON_HIRQ_IN_RTBUF (1 << 11)
-# define RADEON_CPRQ_IN_RTBUF (1 << 12)
-# define RADEON_CFRQ_IN_RTBUF (1 << 13)
-# define RADEON_PIPE_BUSY (1 << 14)
-# define RADEON_ENG_EV_BUSY (1 << 15)
-# define RADEON_CP_CMDSTRM_BUSY (1 << 16)
-# define RADEON_E2_BUSY (1 << 17)
-# define RADEON_RB2D_BUSY (1 << 18)
-# define RADEON_RB3D_BUSY (1 << 19) /* not used on r300 */
-# define RADEON_VAP_BUSY (1 << 20)
-# define RADEON_RE_BUSY (1 << 21) /* not used on r300 */
-# define RADEON_TAM_BUSY (1 << 22) /* not used on r300 */
-# define RADEON_TDM_BUSY (1 << 23) /* not used on r300 */
-# define RADEON_PB_BUSY (1 << 24) /* not used on r300 */
-# define RADEON_TIM_BUSY (1 << 25) /* not used on r300 */
-# define RADEON_GA_BUSY (1 << 26)
-# define RADEON_CBA2D_BUSY (1 << 27)
-# define RADEON_RBBM_ACTIVE (1 << 31)
-#define RADEON_RE_LINE_PATTERN 0x1cd0
-#define RADEON_RE_MISC 0x26c4
-#define RADEON_RE_TOP_LEFT 0x26c0
-#define RADEON_RE_WIDTH_HEIGHT 0x1c44
-#define RADEON_RE_STIPPLE_ADDR 0x1cc8
-#define RADEON_RE_STIPPLE_DATA 0x1ccc
-
-#define RADEON_SCISSOR_TL_0 0x1cd8
-#define RADEON_SCISSOR_BR_0 0x1cdc
-#define RADEON_SCISSOR_TL_1 0x1ce0
-#define RADEON_SCISSOR_BR_1 0x1ce4
-#define RADEON_SCISSOR_TL_2 0x1ce8
-#define RADEON_SCISSOR_BR_2 0x1cec
-#define RADEON_SE_COORD_FMT 0x1c50
-#define RADEON_SE_CNTL 0x1c4c
-# define RADEON_FFACE_CULL_CW (0 << 0)
-# define RADEON_BFACE_SOLID (3 << 1)
-# define RADEON_FFACE_SOLID (3 << 3)
-# define RADEON_FLAT_SHADE_VTX_LAST (3 << 6)
-# define RADEON_DIFFUSE_SHADE_FLAT (1 << 8)
-# define RADEON_DIFFUSE_SHADE_GOURAUD (2 << 8)
-# define RADEON_ALPHA_SHADE_FLAT (1 << 10)
-# define RADEON_ALPHA_SHADE_GOURAUD (2 << 10)
-# define RADEON_SPECULAR_SHADE_FLAT (1 << 12)
-# define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12)
-# define RADEON_FOG_SHADE_FLAT (1 << 14)
-# define RADEON_FOG_SHADE_GOURAUD (2 << 14)
-# define RADEON_VPORT_XY_XFORM_ENABLE (1 << 24)
-# define RADEON_VPORT_Z_XFORM_ENABLE (1 << 25)
-# define RADEON_VTX_PIX_CENTER_OGL (1 << 27)
-# define RADEON_ROUND_MODE_TRUNC (0 << 28)
-# define RADEON_ROUND_PREC_8TH_PIX (1 << 30)
-#define RADEON_SE_CNTL_STATUS 0x2140
-#define RADEON_SE_LINE_WIDTH 0x1db8
-#define RADEON_SE_VPORT_XSCALE 0x1d98
-#define RADEON_SE_ZBIAS_FACTOR 0x1db0
-#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED 0x2210
-#define RADEON_SE_TCL_OUTPUT_VTX_FMT 0x2254
-#define RADEON_SE_TCL_VECTOR_INDX_REG 0x2200
-# define RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT 16
-# define RADEON_VEC_INDX_DWORD_COUNT_SHIFT 28
-#define RADEON_SE_TCL_VECTOR_DATA_REG 0x2204
-#define RADEON_SE_TCL_SCALAR_INDX_REG 0x2208
-# define RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT 16
-#define RADEON_SE_TCL_SCALAR_DATA_REG 0x220C
-#define RADEON_SURFACE_ACCESS_FLAGS 0x0bf8
-#define RADEON_SURFACE_ACCESS_CLR 0x0bfc
-#define RADEON_SURFACE_CNTL 0x0b00
-# define RADEON_SURF_TRANSLATION_DIS (1 << 8)
-# define RADEON_NONSURF_AP0_SWP_MASK (3 << 20)
-# define RADEON_NONSURF_AP0_SWP_LITTLE (0 << 20)
-# define RADEON_NONSURF_AP0_SWP_BIG16 (1 << 20)
-# define RADEON_NONSURF_AP0_SWP_BIG32 (2 << 20)
-# define RADEON_NONSURF_AP1_SWP_MASK (3 << 22)
-# define RADEON_NONSURF_AP1_SWP_LITTLE (0 << 22)
-# define RADEON_NONSURF_AP1_SWP_BIG16 (1 << 22)
-# define RADEON_NONSURF_AP1_SWP_BIG32 (2 << 22)
-#define RADEON_SURFACE0_INFO 0x0b0c
-# define RADEON_SURF_PITCHSEL_MASK (0x1ff << 0)
-# define RADEON_SURF_TILE_MODE_MASK (3 << 16)
-# define RADEON_SURF_TILE_MODE_MACRO (0 << 16)
-# define RADEON_SURF_TILE_MODE_MICRO (1 << 16)
-# define RADEON_SURF_TILE_MODE_32BIT_Z (2 << 16)
-# define RADEON_SURF_TILE_MODE_16BIT_Z (3 << 16)
-#define RADEON_SURFACE0_LOWER_BOUND 0x0b04
-#define RADEON_SURFACE0_UPPER_BOUND 0x0b08
-# define RADEON_SURF_ADDRESS_FIXED_MASK (0x3ff << 0)
-#define RADEON_SURFACE1_INFO 0x0b1c
-#define RADEON_SURFACE1_LOWER_BOUND 0x0b14
-#define RADEON_SURFACE1_UPPER_BOUND 0x0b18
-#define RADEON_SURFACE2_INFO 0x0b2c
-#define RADEON_SURFACE2_LOWER_BOUND 0x0b24
-#define RADEON_SURFACE2_UPPER_BOUND 0x0b28
-#define RADEON_SURFACE3_INFO 0x0b3c
-#define RADEON_SURFACE3_LOWER_BOUND 0x0b34
-#define RADEON_SURFACE3_UPPER_BOUND 0x0b38
-#define RADEON_SURFACE4_INFO 0x0b4c
-#define RADEON_SURFACE4_LOWER_BOUND 0x0b44
-#define RADEON_SURFACE4_UPPER_BOUND 0x0b48
-#define RADEON_SURFACE5_INFO 0x0b5c
-#define RADEON_SURFACE5_LOWER_BOUND 0x0b54
-#define RADEON_SURFACE5_UPPER_BOUND 0x0b58
-#define RADEON_SURFACE6_INFO 0x0b6c
-#define RADEON_SURFACE6_LOWER_BOUND 0x0b64
-#define RADEON_SURFACE6_UPPER_BOUND 0x0b68
-#define RADEON_SURFACE7_INFO 0x0b7c
-#define RADEON_SURFACE7_LOWER_BOUND 0x0b74
-#define RADEON_SURFACE7_UPPER_BOUND 0x0b78
-#define RADEON_SW_SEMAPHORE 0x013c
-
-#define RADEON_WAIT_UNTIL 0x1720
-# define RADEON_WAIT_CRTC_PFLIP (1 << 0)
-# define RADEON_WAIT_2D_IDLE (1 << 14)
-# define RADEON_WAIT_3D_IDLE (1 << 15)
-# define RADEON_WAIT_2D_IDLECLEAN (1 << 16)
-# define RADEON_WAIT_3D_IDLECLEAN (1 << 17)
-# define RADEON_WAIT_HOST_IDLECLEAN (1 << 18)
-
-#define RADEON_RB3D_ZMASKOFFSET 0x3234
-#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c
-# define RADEON_DEPTH_FORMAT_16BIT_INT_Z (0 << 0)
-# define RADEON_DEPTH_FORMAT_24BIT_INT_Z (2 << 0)
-
-/* CP registers */
-#define RADEON_CP_ME_RAM_ADDR 0x07d4
-#define RADEON_CP_ME_RAM_RADDR 0x07d8
-#define RADEON_CP_ME_RAM_DATAH 0x07dc
-#define RADEON_CP_ME_RAM_DATAL 0x07e0
-
-#define RADEON_CP_RB_BASE 0x0700
-#define RADEON_CP_RB_CNTL 0x0704
-# define RADEON_BUF_SWAP_32BIT (2 << 16)
-# define RADEON_RB_NO_UPDATE (1 << 27)
-# define RADEON_RB_RPTR_WR_ENA (1 << 31)
-#define RADEON_CP_RB_RPTR_ADDR 0x070c
-#define RADEON_CP_RB_RPTR 0x0710
-#define RADEON_CP_RB_WPTR 0x0714
-
-#define RADEON_CP_RB_WPTR_DELAY 0x0718
-# define RADEON_PRE_WRITE_TIMER_SHIFT 0
-# define RADEON_PRE_WRITE_LIMIT_SHIFT 23
-
-#define RADEON_CP_IB_BASE 0x0738
-
-#define RADEON_CP_CSQ_CNTL 0x0740
-# define RADEON_CSQ_CNT_PRIMARY_MASK (0xff << 0)
-# define RADEON_CSQ_PRIDIS_INDDIS (0 << 28)
-# define RADEON_CSQ_PRIPIO_INDDIS (1 << 28)
-# define RADEON_CSQ_PRIBM_INDDIS (2 << 28)
-# define RADEON_CSQ_PRIPIO_INDBM (3 << 28)
-# define RADEON_CSQ_PRIBM_INDBM (4 << 28)
-# define RADEON_CSQ_PRIPIO_INDPIO (15 << 28)
-
-#define R300_CP_RESYNC_ADDR 0x0778
-#define R300_CP_RESYNC_DATA 0x077c
-
-#define RADEON_AIC_CNTL 0x01d0
-# define RADEON_PCIGART_TRANSLATE_EN (1 << 0)
-# define RS400_MSI_REARM (1 << 3)
-#define RADEON_AIC_STAT 0x01d4
-#define RADEON_AIC_PT_BASE 0x01d8
-#define RADEON_AIC_LO_ADDR 0x01dc
-#define RADEON_AIC_HI_ADDR 0x01e0
-#define RADEON_AIC_TLB_ADDR 0x01e4
-#define RADEON_AIC_TLB_DATA 0x01e8
-
-/* CP command packets */
-#define RADEON_CP_PACKET0 0x00000000
-# define RADEON_ONE_REG_WR (1 << 15)
-#define RADEON_CP_PACKET1 0x40000000
-#define RADEON_CP_PACKET2 0x80000000
-#define RADEON_CP_PACKET3 0xC0000000
-# define RADEON_CP_NOP 0x00001000
-# define RADEON_CP_NEXT_CHAR 0x00001900
-# define RADEON_CP_PLY_NEXTSCAN 0x00001D00
-# define RADEON_CP_SET_SCISSORS 0x00001E00
- /* GEN_INDX_PRIM is unsupported starting with R300 */
-# define RADEON_3D_RNDR_GEN_INDX_PRIM 0x00002300
-# define RADEON_WAIT_FOR_IDLE 0x00002600
-# define RADEON_3D_DRAW_VBUF 0x00002800
-# define RADEON_3D_DRAW_IMMD 0x00002900
-# define RADEON_3D_DRAW_INDX 0x00002A00
-# define RADEON_CP_LOAD_PALETTE 0x00002C00
-# define RADEON_3D_LOAD_VBPNTR 0x00002F00
-# define RADEON_MPEG_IDCT_MACROBLOCK 0x00003000
-# define RADEON_MPEG_IDCT_MACROBLOCK_REV 0x00003100
-# define RADEON_3D_CLEAR_ZMASK 0x00003200
-# define RADEON_CP_INDX_BUFFER 0x00003300
-# define RADEON_CP_3D_DRAW_VBUF_2 0x00003400
-# define RADEON_CP_3D_DRAW_IMMD_2 0x00003500
-# define RADEON_CP_3D_DRAW_INDX_2 0x00003600
-# define RADEON_3D_CLEAR_HIZ 0x00003700
-# define RADEON_CP_3D_CLEAR_CMASK 0x00003802
-# define RADEON_CNTL_HOSTDATA_BLT 0x00009400
-# define RADEON_CNTL_PAINT_MULTI 0x00009A00
-# define RADEON_CNTL_BITBLT_MULTI 0x00009B00
-# define RADEON_CNTL_SET_SCISSORS 0xC0001E00
-
-# define R600_IT_INDIRECT_BUFFER_END 0x00001700
-# define R600_IT_SET_PREDICATION 0x00002000
-# define R600_IT_REG_RMW 0x00002100
-# define R600_IT_COND_EXEC 0x00002200
-# define R600_IT_PRED_EXEC 0x00002300
-# define R600_IT_START_3D_CMDBUF 0x00002400
-# define R600_IT_DRAW_INDEX_2 0x00002700
-# define R600_IT_CONTEXT_CONTROL 0x00002800
-# define R600_IT_DRAW_INDEX_IMMD_BE 0x00002900
-# define R600_IT_INDEX_TYPE 0x00002A00
-# define R600_IT_DRAW_INDEX 0x00002B00
-# define R600_IT_DRAW_INDEX_AUTO 0x00002D00
-# define R600_IT_DRAW_INDEX_IMMD 0x00002E00
-# define R600_IT_NUM_INSTANCES 0x00002F00
-# define R600_IT_STRMOUT_BUFFER_UPDATE 0x00003400
-# define R600_IT_INDIRECT_BUFFER_MP 0x00003800
-# define R600_IT_MEM_SEMAPHORE 0x00003900
-# define R600_IT_MPEG_INDEX 0x00003A00
-# define R600_IT_WAIT_REG_MEM 0x00003C00
-# define R600_IT_MEM_WRITE 0x00003D00
-# define R600_IT_INDIRECT_BUFFER 0x00003200
-# define R600_IT_SURFACE_SYNC 0x00004300
-# define R600_CB0_DEST_BASE_ENA (1 << 6)
-# define R600_TC_ACTION_ENA (1 << 23)
-# define R600_VC_ACTION_ENA (1 << 24)
-# define R600_CB_ACTION_ENA (1 << 25)
-# define R600_DB_ACTION_ENA (1 << 26)
-# define R600_SH_ACTION_ENA (1 << 27)
-# define R600_SMX_ACTION_ENA (1 << 28)
-# define R600_IT_ME_INITIALIZE 0x00004400
-# define R600_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
-# define R600_IT_COND_WRITE 0x00004500
-# define R600_IT_EVENT_WRITE 0x00004600
-# define R600_IT_EVENT_WRITE_EOP 0x00004700
-# define R600_IT_ONE_REG_WRITE 0x00005700
-# define R600_IT_SET_CONFIG_REG 0x00006800
-# define R600_SET_CONFIG_REG_OFFSET 0x00008000
-# define R600_SET_CONFIG_REG_END 0x0000ac00
-# define R600_IT_SET_CONTEXT_REG 0x00006900
-# define R600_SET_CONTEXT_REG_OFFSET 0x00028000
-# define R600_SET_CONTEXT_REG_END 0x00029000
-# define R600_IT_SET_ALU_CONST 0x00006A00
-# define R600_SET_ALU_CONST_OFFSET 0x00030000
-# define R600_SET_ALU_CONST_END 0x00032000
-# define R600_IT_SET_BOOL_CONST 0x00006B00
-# define R600_SET_BOOL_CONST_OFFSET 0x0003e380
-# define R600_SET_BOOL_CONST_END 0x00040000
-# define R600_IT_SET_LOOP_CONST 0x00006C00
-# define R600_SET_LOOP_CONST_OFFSET 0x0003e200
-# define R600_SET_LOOP_CONST_END 0x0003e380
-# define R600_IT_SET_RESOURCE 0x00006D00
-# define R600_SET_RESOURCE_OFFSET 0x00038000
-# define R600_SET_RESOURCE_END 0x0003c000
-# define R600_SQ_TEX_VTX_INVALID_TEXTURE 0x0
-# define R600_SQ_TEX_VTX_INVALID_BUFFER 0x1
-# define R600_SQ_TEX_VTX_VALID_TEXTURE 0x2
-# define R600_SQ_TEX_VTX_VALID_BUFFER 0x3
-# define R600_IT_SET_SAMPLER 0x00006E00
-# define R600_SET_SAMPLER_OFFSET 0x0003c000
-# define R600_SET_SAMPLER_END 0x0003cff0
-# define R600_IT_SET_CTL_CONST 0x00006F00
-# define R600_SET_CTL_CONST_OFFSET 0x0003cff0
-# define R600_SET_CTL_CONST_END 0x0003e200
-# define R600_IT_SURFACE_BASE_UPDATE 0x00007300
-
-#define RADEON_CP_PACKET_MASK 0xC0000000
-#define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000
-#define RADEON_CP_PACKET0_REG_MASK 0x000007ff
-#define RADEON_CP_PACKET1_REG0_MASK 0x000007ff
-#define RADEON_CP_PACKET1_REG1_MASK 0x003ff800
-
-#define RADEON_VTX_Z_PRESENT (1 << 31)
-#define RADEON_VTX_PKCOLOR_PRESENT (1 << 3)
-
-#define RADEON_PRIM_TYPE_NONE (0 << 0)
-#define RADEON_PRIM_TYPE_POINT (1 << 0)
-#define RADEON_PRIM_TYPE_LINE (2 << 0)
-#define RADEON_PRIM_TYPE_LINE_STRIP (3 << 0)
-#define RADEON_PRIM_TYPE_TRI_LIST (4 << 0)
-#define RADEON_PRIM_TYPE_TRI_FAN (5 << 0)
-#define RADEON_PRIM_TYPE_TRI_STRIP (6 << 0)
-#define RADEON_PRIM_TYPE_TRI_TYPE2 (7 << 0)
-#define RADEON_PRIM_TYPE_RECT_LIST (8 << 0)
-#define RADEON_PRIM_TYPE_3VRT_POINT_LIST (9 << 0)
-#define RADEON_PRIM_TYPE_3VRT_LINE_LIST (10 << 0)
-#define RADEON_PRIM_TYPE_MASK 0xf
-#define RADEON_PRIM_WALK_IND (1 << 4)
-#define RADEON_PRIM_WALK_LIST (2 << 4)
-#define RADEON_PRIM_WALK_RING (3 << 4)
-#define RADEON_COLOR_ORDER_BGRA (0 << 6)
-#define RADEON_COLOR_ORDER_RGBA (1 << 6)
-#define RADEON_MAOS_ENABLE (1 << 7)
-#define RADEON_VTX_FMT_R128_MODE (0 << 8)
-#define RADEON_VTX_FMT_RADEON_MODE (1 << 8)
-#define RADEON_NUM_VERTICES_SHIFT 16
-
-#define RADEON_COLOR_FORMAT_CI8 2
-#define RADEON_COLOR_FORMAT_ARGB1555 3
-#define RADEON_COLOR_FORMAT_RGB565 4
-#define RADEON_COLOR_FORMAT_ARGB8888 6
-#define RADEON_COLOR_FORMAT_RGB332 7
-#define RADEON_COLOR_FORMAT_RGB8 9
-#define RADEON_COLOR_FORMAT_ARGB4444 15
-
-#define RADEON_TXFORMAT_I8 0
-#define RADEON_TXFORMAT_AI88 1
-#define RADEON_TXFORMAT_RGB332 2
-#define RADEON_TXFORMAT_ARGB1555 3
-#define RADEON_TXFORMAT_RGB565 4
-#define RADEON_TXFORMAT_ARGB4444 5
-#define RADEON_TXFORMAT_ARGB8888 6
-#define RADEON_TXFORMAT_RGBA8888 7
-#define RADEON_TXFORMAT_Y8 8
-#define RADEON_TXFORMAT_VYUY422 10
-#define RADEON_TXFORMAT_YVYU422 11
-#define RADEON_TXFORMAT_DXT1 12
-#define RADEON_TXFORMAT_DXT23 14
-#define RADEON_TXFORMAT_DXT45 15
-
-#define R200_PP_TXCBLEND_0 0x2f00
-#define R200_PP_TXCBLEND_1 0x2f10
-#define R200_PP_TXCBLEND_2 0x2f20
-#define R200_PP_TXCBLEND_3 0x2f30
-#define R200_PP_TXCBLEND_4 0x2f40
-#define R200_PP_TXCBLEND_5 0x2f50
-#define R200_PP_TXCBLEND_6 0x2f60
-#define R200_PP_TXCBLEND_7 0x2f70
-#define R200_SE_TCL_LIGHT_MODEL_CTL_0 0x2268
-#define R200_PP_TFACTOR_0 0x2ee0
-#define R200_SE_VTX_FMT_0 0x2088
-#define R200_SE_VAP_CNTL 0x2080
-#define R200_SE_TCL_MATRIX_SEL_0 0x2230
-#define R200_SE_TCL_TEX_PROC_CTL_2 0x22a8
-#define R200_SE_TCL_UCP_VERT_BLEND_CTL 0x22c0
-#define R200_PP_TXFILTER_5 0x2ca0
-#define R200_PP_TXFILTER_4 0x2c80
-#define R200_PP_TXFILTER_3 0x2c60
-#define R200_PP_TXFILTER_2 0x2c40
-#define R200_PP_TXFILTER_1 0x2c20
-#define R200_PP_TXFILTER_0 0x2c00
-#define R200_PP_TXOFFSET_5 0x2d78
-#define R200_PP_TXOFFSET_4 0x2d60
-#define R200_PP_TXOFFSET_3 0x2d48
-#define R200_PP_TXOFFSET_2 0x2d30
-#define R200_PP_TXOFFSET_1 0x2d18
-#define R200_PP_TXOFFSET_0 0x2d00
-
-#define R200_PP_CUBIC_FACES_0 0x2c18
-#define R200_PP_CUBIC_FACES_1 0x2c38
-#define R200_PP_CUBIC_FACES_2 0x2c58
-#define R200_PP_CUBIC_FACES_3 0x2c78
-#define R200_PP_CUBIC_FACES_4 0x2c98
-#define R200_PP_CUBIC_FACES_5 0x2cb8
-#define R200_PP_CUBIC_OFFSET_F1_0 0x2d04
-#define R200_PP_CUBIC_OFFSET_F2_0 0x2d08
-#define R200_PP_CUBIC_OFFSET_F3_0 0x2d0c
-#define R200_PP_CUBIC_OFFSET_F4_0 0x2d10
-#define R200_PP_CUBIC_OFFSET_F5_0 0x2d14
-#define R200_PP_CUBIC_OFFSET_F1_1 0x2d1c
-#define R200_PP_CUBIC_OFFSET_F2_1 0x2d20
-#define R200_PP_CUBIC_OFFSET_F3_1 0x2d24
-#define R200_PP_CUBIC_OFFSET_F4_1 0x2d28
-#define R200_PP_CUBIC_OFFSET_F5_1 0x2d2c
-#define R200_PP_CUBIC_OFFSET_F1_2 0x2d34
-#define R200_PP_CUBIC_OFFSET_F2_2 0x2d38
-#define R200_PP_CUBIC_OFFSET_F3_2 0x2d3c
-#define R200_PP_CUBIC_OFFSET_F4_2 0x2d40
-#define R200_PP_CUBIC_OFFSET_F5_2 0x2d44
-#define R200_PP_CUBIC_OFFSET_F1_3 0x2d4c
-#define R200_PP_CUBIC_OFFSET_F2_3 0x2d50
-#define R200_PP_CUBIC_OFFSET_F3_3 0x2d54
-#define R200_PP_CUBIC_OFFSET_F4_3 0x2d58
-#define R200_PP_CUBIC_OFFSET_F5_3 0x2d5c
-#define R200_PP_CUBIC_OFFSET_F1_4 0x2d64
-#define R200_PP_CUBIC_OFFSET_F2_4 0x2d68
-#define R200_PP_CUBIC_OFFSET_F3_4 0x2d6c
-#define R200_PP_CUBIC_OFFSET_F4_4 0x2d70
-#define R200_PP_CUBIC_OFFSET_F5_4 0x2d74
-#define R200_PP_CUBIC_OFFSET_F1_5 0x2d7c
-#define R200_PP_CUBIC_OFFSET_F2_5 0x2d80
-#define R200_PP_CUBIC_OFFSET_F3_5 0x2d84
-#define R200_PP_CUBIC_OFFSET_F4_5 0x2d88
-#define R200_PP_CUBIC_OFFSET_F5_5 0x2d8c
-
-#define R200_RE_AUX_SCISSOR_CNTL 0x26f0
-#define R200_SE_VTE_CNTL 0x20b0
-#define R200_SE_TCL_OUTPUT_VTX_COMP_SEL 0x2250
-#define R200_PP_TAM_DEBUG3 0x2d9c
-#define R200_PP_CNTL_X 0x2cc4
-#define R200_SE_VAP_CNTL_STATUS 0x2140
-#define R200_RE_SCISSOR_TL_0 0x1cd8
-#define R200_RE_SCISSOR_TL_1 0x1ce0
-#define R200_RE_SCISSOR_TL_2 0x1ce8
-#define R200_RB3D_DEPTHXY_OFFSET 0x1d60
-#define R200_RE_AUX_SCISSOR_CNTL 0x26f0
-#define R200_SE_VTX_STATE_CNTL 0x2180
-#define R200_RE_POINTSIZE 0x2648
-#define R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0 0x2254
-
-#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */
-#define RADEON_PP_TEX_SIZE_1 0x1d0c
-#define RADEON_PP_TEX_SIZE_2 0x1d14
-
-#define RADEON_PP_CUBIC_FACES_0 0x1d24
-#define RADEON_PP_CUBIC_FACES_1 0x1d28
-#define RADEON_PP_CUBIC_FACES_2 0x1d2c
-#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */
-#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00
-#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14
-
-#define RADEON_SE_TCL_STATE_FLUSH 0x2284
-
-#define SE_VAP_CNTL__TCL_ENA_MASK 0x00000001
-#define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK 0x00010000
-#define SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT 0x00000012
-#define SE_VTE_CNTL__VTX_XY_FMT_MASK 0x00000100
-#define SE_VTE_CNTL__VTX_Z_FMT_MASK 0x00000200
-#define SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK 0x00000001
-#define SE_VTX_FMT_0__VTX_W0_PRESENT_MASK 0x00000002
-#define SE_VTX_FMT_0__VTX_COLOR_0_FMT__SHIFT 0x0000000b
-#define R200_3D_DRAW_IMMD_2 0xC0003500
-#define R200_SE_VTX_FMT_1 0x208c
-#define R200_RE_CNTL 0x1c50
-
-#define R200_RB3D_BLENDCOLOR 0x3218
-
-#define R200_SE_TCL_POINT_SPRITE_CNTL 0x22c4
-
-#define R200_PP_TRI_PERF 0x2cf8
-
-#define R200_PP_AFS_0 0x2f80
-#define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */
-
-#define R200_VAP_PVS_CNTL_1 0x22D0
-
-#define RADEON_CRTC_CRNT_FRAME 0x0214
-#define RADEON_CRTC2_CRNT_FRAME 0x0314
-
-#define R500_D1CRTC_STATUS 0x609c
-#define R500_D2CRTC_STATUS 0x689c
-#define R500_CRTC_V_BLANK (1<<0)
-
-#define R500_D1CRTC_FRAME_COUNT 0x60a4
-#define R500_D2CRTC_FRAME_COUNT 0x68a4
-
-#define R500_D1MODE_V_COUNTER 0x6530
-#define R500_D2MODE_V_COUNTER 0x6d30
-
-#define R500_D1MODE_VBLANK_STATUS 0x6534
-#define R500_D2MODE_VBLANK_STATUS 0x6d34
-#define R500_VBLANK_OCCURED (1<<0)
-#define R500_VBLANK_ACK (1<<4)
-#define R500_VBLANK_STAT (1<<12)
-#define R500_VBLANK_INT (1<<16)
-
-#define R500_DxMODE_INT_MASK 0x6540
-#define R500_D1MODE_INT_MASK (1<<0)
-#define R500_D2MODE_INT_MASK (1<<8)
-
-#define R500_DISP_INTERRUPT_STATUS 0x7edc
-#define R500_D1_VBLANK_INTERRUPT (1 << 4)
-#define R500_D2_VBLANK_INTERRUPT (1 << 5)
-
-/* R6xx/R7xx registers */
-#define R600_MC_VM_FB_LOCATION 0x2180
-#define R600_MC_VM_AGP_TOP 0x2184
-#define R600_MC_VM_AGP_BOT 0x2188
-#define R600_MC_VM_AGP_BASE 0x218c
-#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2190
-#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194
-#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198
-
-#define R700_MC_VM_FB_LOCATION 0x2024
-#define R700_MC_VM_AGP_TOP 0x2028
-#define R700_MC_VM_AGP_BOT 0x202c
-#define R700_MC_VM_AGP_BASE 0x2030
-#define R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034
-#define R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038
-#define R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203c
-
-#define R600_MCD_RD_A_CNTL 0x219c
-#define R600_MCD_RD_B_CNTL 0x21a0
-
-#define R600_MCD_WR_A_CNTL 0x21a4
-#define R600_MCD_WR_B_CNTL 0x21a8
-
-#define R600_MCD_RD_SYS_CNTL 0x2200
-#define R600_MCD_WR_SYS_CNTL 0x2214
-
-#define R600_MCD_RD_GFX_CNTL 0x21fc
-#define R600_MCD_RD_HDP_CNTL 0x2204
-#define R600_MCD_RD_PDMA_CNTL 0x2208
-#define R600_MCD_RD_SEM_CNTL 0x220c
-#define R600_MCD_WR_GFX_CNTL 0x2210
-#define R600_MCD_WR_HDP_CNTL 0x2218
-#define R600_MCD_WR_PDMA_CNTL 0x221c
-#define R600_MCD_WR_SEM_CNTL 0x2220
-
-# define R600_MCD_L1_TLB (1 << 0)
-# define R600_MCD_L1_FRAG_PROC (1 << 1)
-# define R600_MCD_L1_STRICT_ORDERING (1 << 2)
-
-# define R600_MCD_SYSTEM_ACCESS_MODE_MASK (3 << 6)
-# define R600_MCD_SYSTEM_ACCESS_MODE_PA_ONLY (0 << 6)
-# define R600_MCD_SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 6)
-# define R600_MCD_SYSTEM_ACCESS_MODE_IN_SYS (2 << 6)
-# define R600_MCD_SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 6)
-
-# define R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 8)
-# define R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 8)
-
-# define R600_MCD_SEMAPHORE_MODE (1 << 10)
-# define R600_MCD_WAIT_L2_QUERY (1 << 11)
-# define R600_MCD_EFFECTIVE_L1_TLB_SIZE(x) ((x) << 12)
-# define R600_MCD_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
-
-#define R700_MC_VM_MD_L1_TLB0_CNTL 0x2654
-#define R700_MC_VM_MD_L1_TLB1_CNTL 0x2658
-#define R700_MC_VM_MD_L1_TLB2_CNTL 0x265c
-
-#define R700_MC_VM_MB_L1_TLB0_CNTL 0x2234
-#define R700_MC_VM_MB_L1_TLB1_CNTL 0x2238
-#define R700_MC_VM_MB_L1_TLB2_CNTL 0x223c
-#define R700_MC_VM_MB_L1_TLB3_CNTL 0x2240
-
-# define R700_ENABLE_L1_TLB (1 << 0)
-# define R700_ENABLE_L1_FRAGMENT_PROCESSING (1 << 1)
-# define R700_SYSTEM_ACCESS_MODE_IN_SYS (2 << 3)
-# define R700_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 5)
-# define R700_EFFECTIVE_L1_TLB_SIZE(x) ((x) << 15)
-# define R700_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 18)
-
-#define R700_MC_ARB_RAMCFG 0x2760
-# define R700_NOOFBANK_SHIFT 0
-# define R700_NOOFBANK_MASK 0x3
-# define R700_NOOFRANK_SHIFT 2
-# define R700_NOOFRANK_MASK 0x1
-# define R700_NOOFROWS_SHIFT 3
-# define R700_NOOFROWS_MASK 0x7
-# define R700_NOOFCOLS_SHIFT 6
-# define R700_NOOFCOLS_MASK 0x3
-# define R700_CHANSIZE_SHIFT 8
-# define R700_CHANSIZE_MASK 0x1
-# define R700_BURSTLENGTH_SHIFT 9
-# define R700_BURSTLENGTH_MASK 0x1
-#define R600_RAMCFG 0x2408
-# define R600_NOOFBANK_SHIFT 0
-# define R600_NOOFBANK_MASK 0x1
-# define R600_NOOFRANK_SHIFT 1
-# define R600_NOOFRANK_MASK 0x1
-# define R600_NOOFROWS_SHIFT 2
-# define R600_NOOFROWS_MASK 0x7
-# define R600_NOOFCOLS_SHIFT 5
-# define R600_NOOFCOLS_MASK 0x3
-# define R600_CHANSIZE_SHIFT 7
-# define R600_CHANSIZE_MASK 0x1
-# define R600_BURSTLENGTH_SHIFT 8
-# define R600_BURSTLENGTH_MASK 0x1
-
-#define R600_VM_L2_CNTL 0x1400
-# define R600_VM_L2_CACHE_EN (1 << 0)
-# define R600_VM_L2_FRAG_PROC (1 << 1)
-# define R600_VM_ENABLE_PTE_CACHE_LRU_W (1 << 9)
-# define R600_VM_L2_CNTL_QUEUE_SIZE(x) ((x) << 13)
-# define R700_VM_L2_CNTL_QUEUE_SIZE(x) ((x) << 14)
-
-#define R600_VM_L2_CNTL2 0x1404
-# define R600_VM_L2_CNTL2_INVALIDATE_ALL_L1_TLBS (1 << 0)
-# define R600_VM_L2_CNTL2_INVALIDATE_L2_CACHE (1 << 1)
-#define R600_VM_L2_CNTL3 0x1408
-# define R600_VM_L2_CNTL3_BANK_SELECT_0(x) ((x) << 0)
-# define R600_VM_L2_CNTL3_BANK_SELECT_1(x) ((x) << 5)
-# define R600_VM_L2_CNTL3_CACHE_UPDATE_MODE(x) ((x) << 10)
-# define R700_VM_L2_CNTL3_BANK_SELECT(x) ((x) << 0)
-# define R700_VM_L2_CNTL3_CACHE_UPDATE_MODE(x) ((x) << 6)
-
-#define R600_VM_L2_STATUS 0x140c
-
-#define R600_VM_CONTEXT0_CNTL 0x1410
-# define R600_VM_ENABLE_CONTEXT (1 << 0)
-# define R600_VM_PAGE_TABLE_DEPTH_FLAT (0 << 1)
-
-#define R600_VM_CONTEXT0_CNTL2 0x1430
-#define R600_VM_CONTEXT0_REQUEST_RESPONSE 0x1470
-#define R600_VM_CONTEXT0_INVALIDATION_LOW_ADDR 0x1490
-#define R600_VM_CONTEXT0_INVALIDATION_HIGH_ADDR 0x14b0
-#define R600_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x1574
-#define R600_VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x1594
-#define R600_VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x15b4
-
-#define R700_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153c
-#define R700_VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155c
-#define R700_VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157c
-
-#define R600_HDP_HOST_PATH_CNTL 0x2c00
-
-#define R600_GRBM_CNTL 0x8000
-# define R600_GRBM_READ_TIMEOUT(x) ((x) << 0)
-
-#define R600_GRBM_STATUS 0x8010
-# define R600_CMDFIFO_AVAIL_MASK 0x1f
-# define R700_CMDFIFO_AVAIL_MASK 0xf
-# define R600_GUI_ACTIVE (1 << 31)
-#define R600_GRBM_STATUS2 0x8014
-#define R600_GRBM_SOFT_RESET 0x8020
-# define R600_SOFT_RESET_CP (1 << 0)
-#define R600_WAIT_UNTIL 0x8040
-
-#define R600_CP_SEM_WAIT_TIMER 0x85bc
-#define R600_CP_ME_CNTL 0x86d8
-# define R600_CP_ME_HALT (1 << 28)
-#define R600_CP_QUEUE_THRESHOLDS 0x8760
-# define R600_ROQ_IB1_START(x) ((x) << 0)
-# define R600_ROQ_IB2_START(x) ((x) << 8)
-#define R600_CP_MEQ_THRESHOLDS 0x8764
-# define R700_STQ_SPLIT(x) ((x) << 0)
-# define R600_MEQ_END(x) ((x) << 16)
-# define R600_ROQ_END(x) ((x) << 24)
-#define R600_CP_PERFMON_CNTL 0x87fc
-#define R600_CP_RB_BASE 0xc100
-#define R600_CP_RB_CNTL 0xc104
-# define R600_RB_BUFSZ(x) ((x) << 0)
-# define R600_RB_BLKSZ(x) ((x) << 8)
-# define R600_BUF_SWAP_32BIT (2 << 16)
-# define R600_RB_NO_UPDATE (1 << 27)
-# define R600_RB_RPTR_WR_ENA (1 << 31)
-#define R600_CP_RB_RPTR_WR 0xc108
-#define R600_CP_RB_RPTR_ADDR 0xc10c
-#define R600_CP_RB_RPTR_ADDR_HI 0xc110
-#define R600_CP_RB_WPTR 0xc114
-#define R600_CP_RB_WPTR_ADDR 0xc118
-#define R600_CP_RB_WPTR_ADDR_HI 0xc11c
-#define R600_CP_RB_RPTR 0x8700
-#define R600_CP_RB_WPTR_DELAY 0x8704
-#define R600_CP_PFP_UCODE_ADDR 0xc150
-#define R600_CP_PFP_UCODE_DATA 0xc154
-#define R600_CP_ME_RAM_RADDR 0xc158
-#define R600_CP_ME_RAM_WADDR 0xc15c
-#define R600_CP_ME_RAM_DATA 0xc160
-#define R600_CP_DEBUG 0xc1fc
-
-#define R600_PA_CL_ENHANCE 0x8a14
-# define R600_CLIP_VTX_REORDER_ENA (1 << 0)
-# define R600_NUM_CLIP_SEQ(x) ((x) << 1)
-#define R600_PA_SC_LINE_STIPPLE_STATE 0x8b10
-#define R600_PA_SC_MULTI_CHIP_CNTL 0x8b20
-#define R700_PA_SC_FORCE_EOV_MAX_CNTS 0x8b24
-# define R700_FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0)
-# define R700_FORCE_EOV_MAX_REZ_CNT(x) ((x) << 16)
-#define R600_PA_SC_AA_SAMPLE_LOCS_2S 0x8b40
-#define R600_PA_SC_AA_SAMPLE_LOCS_4S 0x8b44
-#define R600_PA_SC_AA_SAMPLE_LOCS_8S_WD0 0x8b48
-#define R600_PA_SC_AA_SAMPLE_LOCS_8S_WD1 0x8b4c
-# define R600_S0_X(x) ((x) << 0)
-# define R600_S0_Y(x) ((x) << 4)
-# define R600_S1_X(x) ((x) << 8)
-# define R600_S1_Y(x) ((x) << 12)
-# define R600_S2_X(x) ((x) << 16)
-# define R600_S2_Y(x) ((x) << 20)
-# define R600_S3_X(x) ((x) << 24)
-# define R600_S3_Y(x) ((x) << 28)
-# define R600_S4_X(x) ((x) << 0)
-# define R600_S4_Y(x) ((x) << 4)
-# define R600_S5_X(x) ((x) << 8)
-# define R600_S5_Y(x) ((x) << 12)
-# define R600_S6_X(x) ((x) << 16)
-# define R600_S6_Y(x) ((x) << 20)
-# define R600_S7_X(x) ((x) << 24)
-# define R600_S7_Y(x) ((x) << 28)
-#define R600_PA_SC_FIFO_SIZE 0x8bd0
-# define R600_SC_PRIM_FIFO_SIZE(x) ((x) << 0)
-# define R600_SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 8)
-# define R600_SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 16)
-#define R700_PA_SC_FIFO_SIZE_R7XX 0x8bcc
-# define R700_SC_PRIM_FIFO_SIZE(x) ((x) << 0)
-# define R700_SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 12)
-# define R700_SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 20)
-#define R600_PA_SC_ENHANCE 0x8bf0
-# define R600_FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0)
-# define R600_FORCE_EOV_MAX_TILE_CNT(x) ((x) << 12)
-#define R600_PA_SC_CLIPRECT_RULE 0x2820c
-#define R700_PA_SC_EDGERULE 0x28230
-#define R600_PA_SC_LINE_STIPPLE 0x28a0c
-#define R600_PA_SC_MODE_CNTL 0x28a4c
-#define R600_PA_SC_AA_CONFIG 0x28c04
-
-#define R600_SX_EXPORT_BUFFER_SIZES 0x900c
-# define R600_COLOR_BUFFER_SIZE(x) ((x) << 0)
-# define R600_POSITION_BUFFER_SIZE(x) ((x) << 8)
-# define R600_SMX_BUFFER_SIZE(x) ((x) << 16)
-#define R600_SX_DEBUG_1 0x9054
-# define R600_SMX_EVENT_RELEASE (1 << 0)
-# define R600_ENABLE_NEW_SMX_ADDRESS (1 << 16)
-#define R700_SX_DEBUG_1 0x9058
-# define R700_ENABLE_NEW_SMX_ADDRESS (1 << 16)
-#define R600_SX_MISC 0x28350
-
-#define R600_DB_DEBUG 0x9830
-# define R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE (1 << 31)
-#define R600_DB_WATERMARKS 0x9838
-# define R600_DEPTH_FREE(x) ((x) << 0)
-# define R600_DEPTH_FLUSH(x) ((x) << 5)
-# define R600_DEPTH_PENDING_FREE(x) ((x) << 15)
-# define R600_DEPTH_CACHELINE_FREE(x) ((x) << 20)
-#define R700_DB_DEBUG3 0x98b0
-# define R700_DB_CLK_OFF_DELAY(x) ((x) << 11)
-#define RV700_DB_DEBUG4 0x9b8c
-# define RV700_DISABLE_TILE_COVERED_FOR_PS_ITER (1 << 6)
-
-#define R600_VGT_CACHE_INVALIDATION 0x88c4
-# define R600_CACHE_INVALIDATION(x) ((x) << 0)
-# define R600_VC_ONLY 0
-# define R600_TC_ONLY 1
-# define R600_VC_AND_TC 2
-# define R700_AUTO_INVLD_EN(x) ((x) << 6)
-# define R700_NO_AUTO 0
-# define R700_ES_AUTO 1
-# define R700_GS_AUTO 2
-# define R700_ES_AND_GS_AUTO 3
-#define R600_VGT_GS_PER_ES 0x88c8
-#define R600_VGT_ES_PER_GS 0x88cc
-#define R600_VGT_GS_PER_VS 0x88e8
-#define R600_VGT_GS_VERTEX_REUSE 0x88d4
-#define R600_VGT_NUM_INSTANCES 0x8974
-#define R600_VGT_STRMOUT_EN 0x28ab0
-#define R600_VGT_EVENT_INITIATOR 0x28a90
-# define R600_CACHE_FLUSH_AND_INV_EVENT (0x16 << 0)
-#define R600_VGT_VERTEX_REUSE_BLOCK_CNTL 0x28c58
-# define R600_VTX_REUSE_DEPTH_MASK 0xff
-#define R600_VGT_OUT_DEALLOC_CNTL 0x28c5c
-# define R600_DEALLOC_DIST_MASK 0x7f
-
-#define R600_CB_COLOR0_BASE 0x28040
-#define R600_CB_COLOR1_BASE 0x28044
-#define R600_CB_COLOR2_BASE 0x28048
-#define R600_CB_COLOR3_BASE 0x2804c
-#define R600_CB_COLOR4_BASE 0x28050
-#define R600_CB_COLOR5_BASE 0x28054
-#define R600_CB_COLOR6_BASE 0x28058
-#define R600_CB_COLOR7_BASE 0x2805c
-#define R600_CB_COLOR7_FRAG 0x280fc
-
-#define R600_CB_COLOR0_SIZE 0x28060
-#define R600_CB_COLOR0_VIEW 0x28080
-#define R600_CB_COLOR0_INFO 0x280a0
-#define R600_CB_COLOR0_TILE 0x280c0
-#define R600_CB_COLOR0_FRAG 0x280e0
-#define R600_CB_COLOR0_MASK 0x28100
-
-#define AVIVO_D1MODE_VLINE_START_END 0x6538
-#define AVIVO_D2MODE_VLINE_START_END 0x6d38
-#define R600_CP_COHER_BASE 0x85f8
-#define R600_DB_DEPTH_BASE 0x2800c
-#define R600_SQ_PGM_START_FS 0x28894
-#define R600_SQ_PGM_START_ES 0x28880
-#define R600_SQ_PGM_START_VS 0x28858
-#define R600_SQ_PGM_RESOURCES_VS 0x28868
-#define R600_SQ_PGM_CF_OFFSET_VS 0x288d0
-#define R600_SQ_PGM_START_GS 0x2886c
-#define R600_SQ_PGM_START_PS 0x28840
-#define R600_SQ_PGM_RESOURCES_PS 0x28850
-#define R600_SQ_PGM_EXPORTS_PS 0x28854
-#define R600_SQ_PGM_CF_OFFSET_PS 0x288cc
-#define R600_VGT_DMA_BASE 0x287e8
-#define R600_VGT_DMA_BASE_HI 0x287e4
-#define R600_VGT_STRMOUT_BASE_OFFSET_0 0x28b10
-#define R600_VGT_STRMOUT_BASE_OFFSET_1 0x28b14
-#define R600_VGT_STRMOUT_BASE_OFFSET_2 0x28b18
-#define R600_VGT_STRMOUT_BASE_OFFSET_3 0x28b1c
-#define R600_VGT_STRMOUT_BASE_OFFSET_HI_0 0x28b44
-#define R600_VGT_STRMOUT_BASE_OFFSET_HI_1 0x28b48
-#define R600_VGT_STRMOUT_BASE_OFFSET_HI_2 0x28b4c
-#define R600_VGT_STRMOUT_BASE_OFFSET_HI_3 0x28b50
-#define R600_VGT_STRMOUT_BUFFER_BASE_0 0x28ad8
-#define R600_VGT_STRMOUT_BUFFER_BASE_1 0x28ae8
-#define R600_VGT_STRMOUT_BUFFER_BASE_2 0x28af8
-#define R600_VGT_STRMOUT_BUFFER_BASE_3 0x28b08
-#define R600_VGT_STRMOUT_BUFFER_OFFSET_0 0x28adc
-#define R600_VGT_STRMOUT_BUFFER_OFFSET_1 0x28aec
-#define R600_VGT_STRMOUT_BUFFER_OFFSET_2 0x28afc
-#define R600_VGT_STRMOUT_BUFFER_OFFSET_3 0x28b0c
-
-#define R600_VGT_PRIMITIVE_TYPE 0x8958
-
-#define R600_PA_SC_SCREEN_SCISSOR_TL 0x28030
-#define R600_PA_SC_GENERIC_SCISSOR_TL 0x28240
-#define R600_PA_SC_WINDOW_SCISSOR_TL 0x28204
-
-#define R600_TC_CNTL 0x9608
-# define R600_TC_L2_SIZE(x) ((x) << 5)
-# define R600_L2_DISABLE_LATE_HIT (1 << 9)
-
-#define R600_ARB_POP 0x2418
-# define R600_ENABLE_TC128 (1 << 30)
-#define R600_ARB_GDEC_RD_CNTL 0x246c
-
-#define R600_TA_CNTL_AUX 0x9508
-# define R600_DISABLE_CUBE_WRAP (1 << 0)
-# define R600_DISABLE_CUBE_ANISO (1 << 1)
-# define R700_GETLOD_SELECT(x) ((x) << 2)
-# define R600_SYNC_GRADIENT (1 << 24)
-# define R600_SYNC_WALKER (1 << 25)
-# define R600_SYNC_ALIGNER (1 << 26)
-# define R600_BILINEAR_PRECISION_6_BIT (0 << 31)
-# define R600_BILINEAR_PRECISION_8_BIT (1 << 31)
-
-#define R700_TCP_CNTL 0x9610
-
-#define R600_SMX_DC_CTL0 0xa020
-# define R700_USE_HASH_FUNCTION (1 << 0)
-# define R700_CACHE_DEPTH(x) ((x) << 1)
-# define R700_FLUSH_ALL_ON_EVENT (1 << 10)
-# define R700_STALL_ON_EVENT (1 << 11)
-#define R700_SMX_EVENT_CTL 0xa02c
-# define R700_ES_FLUSH_CTL(x) ((x) << 0)
-# define R700_GS_FLUSH_CTL(x) ((x) << 3)
-# define R700_ACK_FLUSH_CTL(x) ((x) << 6)
-# define R700_SYNC_FLUSH_CTL (1 << 8)
-
-#define R600_SQ_CONFIG 0x8c00
-# define R600_VC_ENABLE (1 << 0)
-# define R600_EXPORT_SRC_C (1 << 1)
-# define R600_DX9_CONSTS (1 << 2)
-# define R600_ALU_INST_PREFER_VECTOR (1 << 3)
-# define R600_DX10_CLAMP (1 << 4)
-# define R600_CLAUSE_SEQ_PRIO(x) ((x) << 8)
-# define R600_PS_PRIO(x) ((x) << 24)
-# define R600_VS_PRIO(x) ((x) << 26)
-# define R600_GS_PRIO(x) ((x) << 28)
-# define R600_ES_PRIO(x) ((x) << 30)
-#define R600_SQ_GPR_RESOURCE_MGMT_1 0x8c04
-# define R600_NUM_PS_GPRS(x) ((x) << 0)
-# define R600_NUM_VS_GPRS(x) ((x) << 16)
-# define R700_DYN_GPR_ENABLE (1 << 27)
-# define R600_NUM_CLAUSE_TEMP_GPRS(x) ((x) << 28)
-#define R600_SQ_GPR_RESOURCE_MGMT_2 0x8c08
-# define R600_NUM_GS_GPRS(x) ((x) << 0)
-# define R600_NUM_ES_GPRS(x) ((x) << 16)
-#define R600_SQ_THREAD_RESOURCE_MGMT 0x8c0c
-# define R600_NUM_PS_THREADS(x) ((x) << 0)
-# define R600_NUM_VS_THREADS(x) ((x) << 8)
-# define R600_NUM_GS_THREADS(x) ((x) << 16)
-# define R600_NUM_ES_THREADS(x) ((x) << 24)
-#define R600_SQ_STACK_RESOURCE_MGMT_1 0x8c10
-# define R600_NUM_PS_STACK_ENTRIES(x) ((x) << 0)
-# define R600_NUM_VS_STACK_ENTRIES(x) ((x) << 16)
-#define R600_SQ_STACK_RESOURCE_MGMT_2 0x8c14
-# define R600_NUM_GS_STACK_ENTRIES(x) ((x) << 0)
-# define R600_NUM_ES_STACK_ENTRIES(x) ((x) << 16)
-#define R600_SQ_MS_FIFO_SIZES 0x8cf0
-# define R600_CACHE_FIFO_SIZE(x) ((x) << 0)
-# define R600_FETCH_FIFO_HIWATER(x) ((x) << 8)
-# define R600_DONE_FIFO_HIWATER(x) ((x) << 16)
-# define R600_ALU_UPDATE_FIFO_HIWATER(x) ((x) << 24)
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_0 0x8db0
-# define R700_SIMDA_RING0(x) ((x) << 0)
-# define R700_SIMDA_RING1(x) ((x) << 8)
-# define R700_SIMDB_RING0(x) ((x) << 16)
-# define R700_SIMDB_RING1(x) ((x) << 24)
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_1 0x8db4
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_2 0x8db8
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_3 0x8dbc
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_4 0x8dc0
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_5 0x8dc4
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_6 0x8dc8
-#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_7 0x8dcc
-
-#define R600_SPI_PS_IN_CONTROL_0 0x286cc
-# define R600_NUM_INTERP(x) ((x) << 0)
-# define R600_POSITION_ENA (1 << 8)
-# define R600_POSITION_CENTROID (1 << 9)
-# define R600_POSITION_ADDR(x) ((x) << 10)
-# define R600_PARAM_GEN(x) ((x) << 15)
-# define R600_PARAM_GEN_ADDR(x) ((x) << 19)
-# define R600_BARYC_SAMPLE_CNTL(x) ((x) << 26)
-# define R600_PERSP_GRADIENT_ENA (1 << 28)
-# define R600_LINEAR_GRADIENT_ENA (1 << 29)
-# define R600_POSITION_SAMPLE (1 << 30)
-# define R600_BARYC_AT_SAMPLE_ENA (1 << 31)
-#define R600_SPI_PS_IN_CONTROL_1 0x286d0
-# define R600_GEN_INDEX_PIX (1 << 0)
-# define R600_GEN_INDEX_PIX_ADDR(x) ((x) << 1)
-# define R600_FRONT_FACE_ENA (1 << 8)
-# define R600_FRONT_FACE_CHAN(x) ((x) << 9)
-# define R600_FRONT_FACE_ALL_BITS (1 << 11)
-# define R600_FRONT_FACE_ADDR(x) ((x) << 12)
-# define R600_FOG_ADDR(x) ((x) << 17)
-# define R600_FIXED_PT_POSITION_ENA (1 << 24)
-# define R600_FIXED_PT_POSITION_ADDR(x) ((x) << 25)
-# define R700_POSITION_ULC (1 << 30)
-#define R600_SPI_INPUT_Z 0x286d8
-
-#define R600_SPI_CONFIG_CNTL 0x9100
-# define R600_GPR_WRITE_PRIORITY(x) ((x) << 0)
-# define R600_DISABLE_INTERP_1 (1 << 5)
-#define R600_SPI_CONFIG_CNTL_1 0x913c
-# define R600_VTX_DONE_DELAY(x) ((x) << 0)
-# define R600_INTERP_ONE_PRIM_PER_ROW (1 << 4)
-
-#define R600_GB_TILING_CONFIG 0x98f0
-# define R600_PIPE_TILING(x) ((x) << 1)
-# define R600_BANK_TILING(x) ((x) << 4)
-# define R600_GROUP_SIZE(x) ((x) << 6)
-# define R600_ROW_TILING(x) ((x) << 8)
-# define R600_BANK_SWAPS(x) ((x) << 11)
-# define R600_SAMPLE_SPLIT(x) ((x) << 14)
-# define R600_BACKEND_MAP(x) ((x) << 16)
-#define R600_DCP_TILING_CONFIG 0x6ca0
-#define R600_HDP_TILING_CONFIG 0x2f3c
-
-#define R600_CC_RB_BACKEND_DISABLE 0x98f4
-#define R700_CC_SYS_RB_BACKEND_DISABLE 0x3f88
-# define R600_BACKEND_DISABLE(x) ((x) << 16)
-
-#define R600_CC_GC_SHADER_PIPE_CONFIG 0x8950
-#define R600_GC_USER_SHADER_PIPE_CONFIG 0x8954
-# define R600_INACTIVE_QD_PIPES(x) ((x) << 8)
-# define R600_INACTIVE_QD_PIPES_MASK (0xff << 8)
-# define R600_INACTIVE_SIMDS(x) ((x) << 16)
-# define R600_INACTIVE_SIMDS_MASK (0xff << 16)
-
-#define R700_CGTS_SYS_TCC_DISABLE 0x3f90
-#define R700_CGTS_USER_SYS_TCC_DISABLE 0x3f94
-#define R700_CGTS_TCC_DISABLE 0x9148
-#define R700_CGTS_USER_TCC_DISABLE 0x914c
-
-/* Constants */
-#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
-
-#define RADEON_LAST_FRAME_REG RADEON_SCRATCH_REG0
-#define RADEON_LAST_DISPATCH_REG RADEON_SCRATCH_REG1
-#define RADEON_LAST_CLEAR_REG RADEON_SCRATCH_REG2
-#define RADEON_LAST_SWI_REG RADEON_SCRATCH_REG3
-#define RADEON_LAST_DISPATCH 1
-
-#define R600_LAST_FRAME_REG R600_SCRATCH_REG0
-#define R600_LAST_DISPATCH_REG R600_SCRATCH_REG1
-#define R600_LAST_CLEAR_REG R600_SCRATCH_REG2
-#define R600_LAST_SWI_REG R600_SCRATCH_REG3
-
-#define RADEON_MAX_VB_AGE 0x7fffffff
-#define RADEON_MAX_VB_VERTS (0xffff)
-
-#define RADEON_RING_HIGH_MARK 128
-
-#define RADEON_PCIGART_TABLE_SIZE (32*1024)
-
-#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
-#define RADEON_WRITE(reg, val) \
-do { \
- if (reg < 0x10000) { \
- DRM_WRITE32(dev_priv->mmio, (reg), (val)); \
- } else { \
- DRM_WRITE32(dev_priv->mmio, RADEON_MM_INDEX, (reg)); \
- DRM_WRITE32(dev_priv->mmio, RADEON_MM_DATA, (val)); \
- } \
-} while (0)
-#define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
-#define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) )
-
-#define RADEON_WRITE_PLL(addr, val) \
-do { \
- RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, \
- ((addr) & 0x1f) | RADEON_PLL_WR_EN ); \
- RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, (val)); \
-} while (0)
-
-#define RADEON_WRITE_PCIE(addr, val) \
-do { \
- RADEON_WRITE8(RADEON_PCIE_INDEX, \
- ((addr) & 0xff)); \
- RADEON_WRITE(RADEON_PCIE_DATA, (val)); \
-} while (0)
-
-#define R500_WRITE_MCIND(addr, val) \
-do { \
- RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff)); \
- RADEON_WRITE(R520_MC_IND_DATA, (val)); \
- RADEON_WRITE(R520_MC_IND_INDEX, 0); \
-} while (0)
-
-#define RS480_WRITE_MCIND(addr, val) \
-do { \
- RADEON_WRITE(RS480_NB_MC_INDEX, \
- ((addr) & 0xff) | RS480_NB_MC_IND_WR_EN); \
- RADEON_WRITE(RS480_NB_MC_DATA, (val)); \
- RADEON_WRITE(RS480_NB_MC_INDEX, 0xff); \
-} while (0)
-
-#define RS690_WRITE_MCIND(addr, val) \
-do { \
- RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK)); \
- RADEON_WRITE(RS690_MC_DATA, val); \
- RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \
-} while (0)
-
-#define RS600_WRITE_MCIND(addr, val) \
-do { \
- RADEON_WRITE(RS600_MC_INDEX, RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 | ((addr) & RS600_MC_ADDR_MASK)); \
- RADEON_WRITE(RS600_MC_DATA, val); \
-} while (0)
-
-#define IGP_WRITE_MCIND(addr, val) \
-do { \
- if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || \
- ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) \
- RS690_WRITE_MCIND(addr, val); \
- else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) \
- RS600_WRITE_MCIND(addr, val); \
- else \
- RS480_WRITE_MCIND(addr, val); \
-} while (0)
-
-#define CP_PACKET0( reg, n ) \
- (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
-#define CP_PACKET0_TABLE( reg, n ) \
- (RADEON_CP_PACKET0 | RADEON_ONE_REG_WR | ((n) << 16) | ((reg) >> 2))
-#define CP_PACKET1( reg0, reg1 ) \
- (RADEON_CP_PACKET1 | (((reg1) >> 2) << 15) | ((reg0) >> 2))
-#define CP_PACKET2() \
- (RADEON_CP_PACKET2)
-#define CP_PACKET3( pkt, n ) \
- (RADEON_CP_PACKET3 | (pkt) | ((n) << 16))
-
-/* ================================================================
- * Engine control helper macros
- */
-
-#define RADEON_WAIT_UNTIL_2D_IDLE() do { \
- OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \
- OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \
- RADEON_WAIT_HOST_IDLECLEAN) ); \
-} while (0)
-
-#define RADEON_WAIT_UNTIL_3D_IDLE() do { \
- OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \
- OUT_RING( (RADEON_WAIT_3D_IDLECLEAN | \
- RADEON_WAIT_HOST_IDLECLEAN) ); \
-} while (0)
-
-#define RADEON_WAIT_UNTIL_IDLE() do { \
- OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \
- OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \
- RADEON_WAIT_3D_IDLECLEAN | \
- RADEON_WAIT_HOST_IDLECLEAN) ); \
-} while (0)
-
-#define RADEON_WAIT_UNTIL_PAGE_FLIPPED() do { \
- OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \
- OUT_RING( RADEON_WAIT_CRTC_PFLIP ); \
-} while (0)
-
-#define RADEON_FLUSH_CACHE() do { \
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
- OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \
- OUT_RING(RADEON_RB3D_DC_FLUSH); \
- } else { \
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \
- OUT_RING(R300_RB3D_DC_FLUSH); \
- } \
-} while (0)
-
-#define RADEON_PURGE_CACHE() do { \
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
- OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \
- OUT_RING(RADEON_RB3D_DC_FLUSH | RADEON_RB3D_DC_FREE); \
- } else { \
- OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \
- OUT_RING(R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); \
- } \
-} while (0)
-
-#define RADEON_FLUSH_ZCACHE() do { \
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
- OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \
- OUT_RING(RADEON_RB3D_ZC_FLUSH); \
- } else { \
- OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); \
- OUT_RING(R300_ZC_FLUSH); \
- } \
-} while (0)
-
-#define RADEON_PURGE_ZCACHE() do { \
- if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
- OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \
- OUT_RING(RADEON_RB3D_ZC_FLUSH | RADEON_RB3D_ZC_FREE); \
- } else { \
- OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); \
- OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); \
- } \
-} while (0)
-
-/* ================================================================
- * Misc helper macros
- */
-
-/* Perfbox functionality only.
- */
-#define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \
-do { \
- if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) { \
- u32 head = GET_RING_HEAD( dev_priv ); \
- if (head == dev_priv->ring.tail) \
- dev_priv->stats.boxes |= RADEON_BOX_DMA_IDLE; \
- } \
-} while (0)
-
-#define VB_AGE_TEST_WITH_RETURN( dev_priv ) \
-do { \
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \
- if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \
- int __ret; \
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) \
- __ret = r600_do_cp_idle(dev_priv); \
- else \
- __ret = radeon_do_cp_idle(dev_priv); \
- if ( __ret ) return __ret; \
- sarea_priv->last_dispatch = 0; \
- radeon_freelist_reset( dev ); \
- } \
-} while (0)
-
-#define RADEON_DISPATCH_AGE( age ) do { \
- OUT_RING( CP_PACKET0( RADEON_LAST_DISPATCH_REG, 0 ) ); \
- OUT_RING( age ); \
-} while (0)
-
-#define RADEON_FRAME_AGE( age ) do { \
- OUT_RING( CP_PACKET0( RADEON_LAST_FRAME_REG, 0 ) ); \
- OUT_RING( age ); \
-} while (0)
-
-#define RADEON_CLEAR_AGE( age ) do { \
- OUT_RING( CP_PACKET0( RADEON_LAST_CLEAR_REG, 0 ) ); \
- OUT_RING( age ); \
-} while (0)
-
-#define R600_DISPATCH_AGE(age) do { \
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); \
- OUT_RING((R600_LAST_DISPATCH_REG - R600_SET_CONFIG_REG_OFFSET) >> 2); \
- OUT_RING(age); \
-} while (0)
-
-#define R600_FRAME_AGE(age) do { \
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); \
- OUT_RING((R600_LAST_FRAME_REG - R600_SET_CONFIG_REG_OFFSET) >> 2); \
- OUT_RING(age); \
-} while (0)
-
-#define R600_CLEAR_AGE(age) do { \
- OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); \
- OUT_RING((R600_LAST_CLEAR_REG - R600_SET_CONFIG_REG_OFFSET) >> 2); \
- OUT_RING(age); \
-} while (0)
-
-/* ================================================================
- * Ring control
- */
-
-#define RADEON_VERBOSE 0
-
-#define RING_LOCALS int write, _nr, _align_nr; unsigned int mask; u32 *ring;
-
-#define RADEON_RING_ALIGN 16
-
-#define BEGIN_RING( n ) do { \
- if ( RADEON_VERBOSE ) { \
- DRM_INFO( "BEGIN_RING( %d )\n", (n)); \
- } \
- _align_nr = RADEON_RING_ALIGN - ((dev_priv->ring.tail + n) & (RADEON_RING_ALIGN-1)); \
- _align_nr += n; \
- if (dev_priv->ring.space <= (_align_nr * sizeof(u32))) { \
- COMMIT_RING(); \
- radeon_wait_ring( dev_priv, _align_nr * sizeof(u32)); \
- } \
- _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
- ring = dev_priv->ring.start; \
- write = dev_priv->ring.tail; \
- mask = dev_priv->ring.tail_mask; \
-} while (0)
-
-#define ADVANCE_RING() do { \
- if ( RADEON_VERBOSE ) { \
- DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
- write, dev_priv->ring.tail ); \
- } \
- if (((dev_priv->ring.tail + _nr) & mask) != write) { \
- DRM_ERROR( \
- "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \
- ((dev_priv->ring.tail + _nr) & mask), \
- write, __LINE__); \
- } else \
- dev_priv->ring.tail = write; \
-} while (0)
-
-extern void radeon_commit_ring(drm_radeon_private_t *dev_priv);
-
-#define COMMIT_RING() do { \
- radeon_commit_ring(dev_priv); \
- } while(0)
-
-#define OUT_RING( x ) do { \
- if ( RADEON_VERBOSE ) { \
- DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \
- (unsigned int)(x), write ); \
- } \
- ring[write++] = (x); \
- write &= mask; \
-} while (0)
-
-#define OUT_RING_REG( reg, val ) do { \
- OUT_RING( CP_PACKET0( reg, 0 ) ); \
- OUT_RING( val ); \
-} while (0)
-
-#define OUT_RING_TABLE( tab, sz ) do { \
- int _size = (sz); \
- int *_tab = (int *)(tab); \
- \
- if (write + _size > mask) { \
- int _i = (mask+1) - write; \
- _size -= _i; \
- while (_i > 0 ) { \
- *(int *)(ring + write) = *_tab++; \
- write++; \
- _i--; \
- } \
- write = 0; \
- _tab += _i; \
- } \
- while (_size > 0) { \
- *(ring + write) = *_tab++; \
- write++; \
- _size--; \
- } \
- write &= mask; \
-} while (0)
-
-/**
- * Copy given number of dwords from drm buffer to the ring buffer.
- */
-#define OUT_RING_DRM_BUFFER(buf, sz) do { \
- int _size = (sz) * 4; \
- struct drm_buffer *_buf = (buf); \
- int _part_size; \
- while (_size > 0) { \
- _part_size = _size; \
- \
- if (write + _part_size/4 > mask) \
- _part_size = ((mask + 1) - write)*4; \
- \
- if (drm_buffer_index(_buf) + _part_size > PAGE_SIZE) \
- _part_size = PAGE_SIZE - drm_buffer_index(_buf);\
- \
- \
- \
- memcpy(ring + write, &_buf->data[drm_buffer_page(_buf)] \
- [drm_buffer_index(_buf)], _part_size); \
- \
- _size -= _part_size; \
- write = (write + _part_size/4) & mask; \
- drm_buffer_advance(_buf, _part_size); \
- } \
-} while (0)
-
-
-#endif /* CONFIG_DRM_RADEON_UMS */
-
#endif /* __RADEON_DRV_H__ */
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 26da2f4d7b4f..d2e628eea53d 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -44,7 +44,6 @@
struct radeon_fbdev {
struct drm_fb_helper helper;
struct radeon_framebuffer rfb;
- struct list_head fbdev_list;
struct radeon_device *rdev;
};
@@ -283,7 +282,7 @@ out_unref:
}
if (fb && ret) {
- drm_gem_object_unreference(gobj);
+ drm_gem_object_unreference_unlocked(gobj);
drm_framebuffer_unregister_private(fb);
drm_framebuffer_cleanup(fb);
kfree(fb);
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index df09ca7c4889..05815c47b246 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -130,7 +130,7 @@ int radeon_fence_emit(struct radeon_device *rdev,
struct radeon_fence **fence,
int ring)
{
- u64 seq = ++rdev->fence_drv[ring].sync_seq[ring];
+ u64 seq;
/* we are protected by the ring emission mutex */
*fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);
@@ -138,7 +138,7 @@ int radeon_fence_emit(struct radeon_device *rdev,
return -ENOMEM;
}
(*fence)->rdev = rdev;
- (*fence)->seq = seq;
+ (*fence)->seq = seq = ++rdev->fence_drv[ring].sync_seq[ring];
(*fence)->ring = ring;
(*fence)->is_vm_update = false;
fence_init(&(*fence)->base, &radeon_fence_ops,
diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c
deleted file mode 100644
index 688afb62f7c4..000000000000
--- a/drivers/gpu/drm/radeon/radeon_irq.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */
-/*
- * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * 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
- * PRECISION INSIGHT 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:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Michel D�zer <michel@daenzer.net>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-
-void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if (state)
- dev_priv->irq_enable_reg |= mask;
- else
- dev_priv->irq_enable_reg &= ~mask;
-
- if (dev->irq_enabled)
- RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
-}
-
-static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if (state)
- dev_priv->r500_disp_irq_reg |= mask;
- else
- dev_priv->r500_disp_irq_reg &= ~mask;
-
- if (dev->irq_enabled)
- RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
-}
-
-int radeon_enable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
- switch (pipe) {
- case 0:
- r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
- break;
- case 1:
- r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1);
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent crtc %u\n",
- pipe);
- return -EINVAL;
- }
- } else {
- switch (pipe) {
- case 0:
- radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
- break;
- case 1:
- radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent crtc %u\n",
- pipe);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-void radeon_disable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
- switch (pipe) {
- case 0:
- r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
- break;
- case 1:
- r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0);
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent crtc %u\n",
- pipe);
- break;
- }
- } else {
- switch (pipe) {
- case 0:
- radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
- break;
- case 1:
- radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent crtc %u\n",
- pipe);
- break;
- }
- }
-}
-
-static u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int)
-{
- u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS);
- u32 irq_mask = RADEON_SW_INT_TEST;
-
- *r500_disp_int = 0;
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
- /* vbl interrupts in a different place */
-
- if (irqs & R500_DISPLAY_INT_STATUS) {
- /* if a display interrupt */
- u32 disp_irq;
-
- disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS);
-
- *r500_disp_int = disp_irq;
- if (disp_irq & R500_D1_VBLANK_INTERRUPT)
- RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK);
- if (disp_irq & R500_D2_VBLANK_INTERRUPT)
- RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK);
- }
- irq_mask |= R500_DISPLAY_INT_STATUS;
- } else
- irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT;
-
- irqs &= irq_mask;
-
- if (irqs)
- RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
-
- return irqs;
-}
-
-/* Interrupts - Used for device synchronization and flushing in the
- * following circumstances:
- *
- * - Exclusive FB access with hw idle:
- * - Wait for GUI Idle (?) interrupt, then do normal flush.
- *
- * - Frame throttling, NV_fence:
- * - Drop marker irq's into command stream ahead of time.
- * - Wait on irq's with lock *not held*
- * - Check each for termination condition
- *
- * - Internally in cp_getbuffer, etc:
- * - as above, but wait with lock held???
- *
- * NOTE: These functions are misleadingly named -- the irq's aren't
- * tied to dma at all, this is just a hangover from dri prehistory.
- */
-
-irqreturn_t radeon_driver_irq_handler(int irq, void *arg)
-{
- struct drm_device *dev = (struct drm_device *) arg;
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- u32 stat;
- u32 r500_disp_int;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return IRQ_NONE;
-
- /* Only consider the bits we're interested in - others could be used
- * outside the DRM
- */
- stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
- if (!stat)
- return IRQ_NONE;
-
- stat &= dev_priv->irq_enable_reg;
-
- /* SW interrupt */
- if (stat & RADEON_SW_INT_TEST)
- wake_up(&dev_priv->swi_queue);
-
- /* VBLANK interrupt */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
- if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
- drm_handle_vblank(dev, 0);
- if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
- drm_handle_vblank(dev, 1);
- } else {
- if (stat & RADEON_CRTC_VBLANK_STAT)
- drm_handle_vblank(dev, 0);
- if (stat & RADEON_CRTC2_VBLANK_STAT)
- drm_handle_vblank(dev, 1);
- }
- return IRQ_HANDLED;
-}
-
-static int radeon_emit_irq(struct drm_device * dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- unsigned int ret;
- RING_LOCALS;
-
- atomic_inc(&dev_priv->swi_emitted);
- ret = atomic_read(&dev_priv->swi_emitted);
-
- BEGIN_RING(4);
- OUT_RING_REG(RADEON_LAST_SWI_REG, ret);
- OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE);
- ADVANCE_RING();
- COMMIT_RING();
-
- return ret;
-}
-
-static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
-{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- int ret = 0;
-
- if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr)
- return 0;
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * HZ,
- RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr);
-
- return ret;
-}
-
-u32 radeon_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- if (pipe > 1) {
- DRM_ERROR("Invalid crtc %u\n", pipe);
- return -EINVAL;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
- if (pipe == 0)
- return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
- else
- return RADEON_READ(R500_D2CRTC_FRAME_COUNT);
- } else {
- if (pipe == 0)
- return RADEON_READ(RADEON_CRTC_CRNT_FRAME);
- else
- return RADEON_READ(RADEON_CRTC2_CRNT_FRAME);
- }
-}
-
-/* Needs the lock as it touches the ring.
- */
-int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_emit_t *emit = data;
- int result;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return -EINVAL;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- result = radeon_emit_irq(dev);
-
- if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-/* Doesn't need the hardware lock.
- */
-int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_wait_t *irqwait = data;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return -EINVAL;
-
- return radeon_wait_irq(dev, irqwait->irq_seq);
-}
-
-/* drm_dma.h hooks
-*/
-void radeon_driver_irq_preinstall(struct drm_device * dev)
-{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- u32 dummy;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return;
-
- /* Disable *all* interrupts */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
- RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
- RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
-
- /* Clear bits if they're already high */
- radeon_acknowledge_irqs(dev_priv, &dummy);
-}
-
-int radeon_driver_irq_postinstall(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
-
- atomic_set(&dev_priv->swi_emitted, 0);
- init_waitqueue_head(&dev_priv->swi_queue);
-
- dev->max_vblank_count = 0x001fffff;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return 0;
-
- radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
-
- return 0;
-}
-
-void radeon_driver_irq_uninstall(struct drm_device * dev)
-{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- if (!dev_priv)
- return;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- return;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
- RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
- /* Disable *all* interrupts */
- RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
-}
-
-
-int radeon_vblank_crtc_get(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
-
- return dev_priv->vblank_crtc;
-}
-
-int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
-{
- drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
- if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
- DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
- return -EINVAL;
- }
- dev_priv->vblank_crtc = (unsigned int)value;
- return 0;
-}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index d290a8a09036..414953c46a38 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -748,19 +748,19 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
* radeon_get_vblank_counter_kms - get frame count
*
* @dev: drm dev pointer
- * @crtc: crtc to get the frame count from
+ * @pipe: crtc to get the frame count from
*
* Gets the frame count on the requested crtc (all asics).
* Returns frame count on success, -EINVAL on failure.
*/
-u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
+u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
{
int vpos, hpos, stat;
u32 count;
struct radeon_device *rdev = dev->dev_private;
- if (crtc < 0 || crtc >= rdev->num_crtc) {
- DRM_ERROR("Invalid crtc %d\n", crtc);
+ if (pipe >= rdev->num_crtc) {
+ DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
@@ -772,29 +772,29 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
* and start of vsync, so vpos >= 0 means to bump the hw frame counter
* result by 1 to give the proper appearance to caller.
*/
- if (rdev->mode_info.crtcs[crtc]) {
+ if (rdev->mode_info.crtcs[pipe]) {
/* Repeat readout if needed to provide stable result if
* we cross start of vsync during the queries.
*/
do {
- count = radeon_get_vblank_counter(rdev, crtc);
+ count = radeon_get_vblank_counter(rdev, pipe);
/* Ask radeon_get_crtc_scanoutpos to return vpos as
* distance to start of vblank, instead of regular
* vertical scanout pos.
*/
stat = radeon_get_crtc_scanoutpos(
- dev, crtc, GET_DISTANCE_TO_VBLANKSTART,
+ dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
&vpos, &hpos, NULL, NULL,
- &rdev->mode_info.crtcs[crtc]->base.hwmode);
- } while (count != radeon_get_vblank_counter(rdev, crtc));
+ &rdev->mode_info.crtcs[pipe]->base.hwmode);
+ } while (count != radeon_get_vblank_counter(rdev, pipe));
if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
}
else {
- DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
- crtc, vpos);
+ DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n",
+ pipe, vpos);
/* Bump counter if we are at >= leading edge of vblank,
* but before vsync where vpos would turn negative and
@@ -806,7 +806,7 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
}
else {
/* Fallback to use value as is. */
- count = radeon_get_vblank_counter(rdev, crtc);
+ count = radeon_get_vblank_counter(rdev, pipe);
DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
}
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 678b4386540d..32b338ff436b 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -25,6 +25,7 @@
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/radeon_drm.h>
#include <drm/drm_fixed.h>
#include "radeon.h"
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 30de43366eae..88dc973fb209 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -1772,7 +1772,8 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
encoder->possible_crtcs = 0x1;
- drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS);
+ drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs,
+ DRM_MODE_ENCODER_LVDS, NULL);
drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs);
if (rdev->is_atom_bios)
radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
@@ -1781,12 +1782,14 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_
radeon_encoder->rmx_type = RMX_FULL;
break;
case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
- drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs);
radeon_encoder->enc_priv = radeon_legacy_get_tmds_info(radeon_encoder);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
- drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, DRM_MODE_ENCODER_DAC);
+ drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs);
if (rdev->is_atom_bios)
radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder);
@@ -1794,7 +1797,8 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_
radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2:
- drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, DRM_MODE_ENCODER_TVDAC);
+ drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs,
+ DRM_MODE_ENCODER_TVDAC, NULL);
drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs);
if (rdev->is_atom_bios)
radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder);
@@ -1802,7 +1806,8 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_
radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder);
break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
- drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs);
if (!rdev->is_atom_bios)
radeon_encoder->enc_priv = radeon_legacy_get_ext_tmds_info(radeon_encoder);
diff --git a/drivers/gpu/drm/radeon/radeon_mem.c b/drivers/gpu/drm/radeon/radeon_mem.c
deleted file mode 100644
index 146d253f1131..000000000000
--- a/drivers/gpu/drm/radeon/radeon_mem.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */
-/*
- * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * 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
- * PRECISION INSIGHT 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:
- * Keith Whitwell <keith@tungstengraphics.com>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-
-/* Very simple allocator for GART memory, working on a static range
- * already mapped into each client's address space.
- */
-
-static struct mem_block *split_block(struct mem_block *p, int start, int size,
- struct drm_file *file_priv)
-{
- /* Maybe cut off the start of an existing block */
- if (start > p->start) {
- struct mem_block *newblock = kmalloc(sizeof(*newblock),
- GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start;
- newblock->size = p->size - (start - p->start);
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size -= newblock->size;
- p = newblock;
- }
-
- /* Maybe cut off the end of an existing block */
- if (size < p->size) {
- struct mem_block *newblock = kmalloc(sizeof(*newblock),
- GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start + size;
- newblock->size = p->size - size;
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size = size;
- }
-
- out:
- /* Our block is in the middle */
- p->file_priv = file_priv;
- return p;
-}
-
-static struct mem_block *alloc_block(struct mem_block *heap, int size,
- int align2, struct drm_file *file_priv)
-{
- struct mem_block *p;
- int mask = (1 << align2) - 1;
-
- list_for_each(p, heap) {
- int start = (p->start + mask) & ~mask;
- if (p->file_priv == NULL && start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
-
- return NULL;
-}
-
-static struct mem_block *find_block(struct mem_block *heap, int start)
-{
- struct mem_block *p;
-
- list_for_each(p, heap)
- if (p->start == start)
- return p;
-
- return NULL;
-}
-
-static void free_block(struct mem_block *p)
-{
- p->file_priv = NULL;
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- if (p->next->file_priv == NULL) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
-
- if (p->prev->file_priv == NULL) {
- struct mem_block *q = p->prev;
- q->size += p->size;
- q->next = p->next;
- q->next->prev = q;
- kfree(p);
- }
-}
-
-/* Initialize. How to check for an uninitialized heap?
- */
-static int init_heap(struct mem_block **heap, int start, int size)
-{
- struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
-
- if (!blocks)
- return -ENOMEM;
-
- *heap = kzalloc(sizeof(**heap), GFP_KERNEL);
- if (!*heap) {
- kfree(blocks);
- return -ENOMEM;
- }
-
- blocks->start = start;
- blocks->size = size;
- blocks->file_priv = NULL;
- blocks->next = blocks->prev = *heap;
-
- (*heap)->file_priv = (struct drm_file *) - 1;
- (*heap)->next = (*heap)->prev = blocks;
- return 0;
-}
-
-/* Free all blocks associated with the releasing file.
- */
-void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap)
-{
- struct mem_block *p;
-
- if (!heap || !heap->next)
- return;
-
- list_for_each(p, heap) {
- if (p->file_priv == file_priv)
- p->file_priv = NULL;
- }
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- list_for_each(p, heap) {
- while (p->file_priv == NULL && p->next->file_priv == NULL) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
- }
-}
-
-/* Shutdown.
- */
-void radeon_mem_takedown(struct mem_block **heap)
-{
- struct mem_block *p;
-
- if (!*heap)
- return;
-
- for (p = (*heap)->next; p != *heap;) {
- struct mem_block *q = p;
- p = p->next;
- kfree(q);
- }
-
- kfree(*heap);
- *heap = NULL;
-}
-
-/* IOCTL HANDLERS */
-
-static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region)
-{
- switch (region) {
- case RADEON_MEM_REGION_GART:
- return &dev_priv->gart_heap;
- case RADEON_MEM_REGION_FB:
- return &dev_priv->fb_heap;
- default:
- return NULL;
- }
-}
-
-int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_alloc_t *alloc = data;
- struct mem_block *block, **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, alloc->region);
- if (!heap || !*heap)
- return -EFAULT;
-
- /* Make things easier on ourselves: all allocations at least
- * 4k aligned.
- */
- if (alloc->alignment < 12)
- alloc->alignment = 12;
-
- block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
-
- if (!block)
- return -ENOMEM;
-
- if (copy_to_user(alloc->region_offset, &block->start,
- sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_free_t *memfree = data;
- struct mem_block *block, **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, memfree->region);
- if (!heap || !*heap)
- return -EFAULT;
-
- block = find_block(*heap, memfree->region_offset);
- if (!block)
- return -EFAULT;
-
- if (block->file_priv != file_priv)
- return -EPERM;
-
- free_block(block);
- return 0;
-}
-
-int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_init_heap_t *initheap = data;
- struct mem_block **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, initheap->region);
- if (!heap)
- return -EFAULT;
-
- if (*heap) {
- DRM_ERROR("heap already initialized?");
- return -EFAULT;
- }
-
- return init_heap(heap, initheap->start, initheap->size);
-}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index bba112628b47..bb75201a24ba 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -757,8 +757,10 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
struct drm_connector *connector);
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
- const u8 *dpcd);
+extern int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+ const u8 *dpcd,
+ unsigned pix_clock,
+ unsigned *dp_lanes, unsigned *dp_rate);
extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
u8 power_state);
extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
@@ -934,7 +936,7 @@ extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green
u16 *blue, int regno);
int radeon_framebuffer_init(struct drm_device *dev,
struct radeon_framebuffer *rfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 59abebd6b5dc..460c8f2989da 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -713,7 +713,7 @@ static struct attribute *hwmon_attributes[] = {
static umode_t hwmon_attributes_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct radeon_device *rdev = dev_get_drvdata(dev);
umode_t effective_mode = attr->mode;
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
deleted file mode 100644
index 15aee723db77..000000000000
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ /dev/null
@@ -1,3261 +0,0 @@
-/* radeon_state.c -- State support for Radeon -*- linux-c -*- */
-/*
- * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
- * 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
- * PRECISION INSIGHT 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:
- * Gareth Hughes <gareth@valinux.com>
- * Kevin E. Martin <martin@valinux.com>
- *
- * ------------------------ This file is DEPRECATED! -------------------------
- */
-
-#include <drm/drmP.h>
-#include <drm/radeon_drm.h>
-#include "radeon_drv.h"
-#include "drm_buffer.h"
-
-/* ================================================================
- * Helper functions for client state checking and fixup
- */
-
-static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
- dev_priv,
- struct drm_file * file_priv,
- u32 *offset)
-{
- u64 off = *offset;
- u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
- struct drm_radeon_driver_file_fields *radeon_priv;
-
- /* Hrm ... the story of the offset ... So this function converts
- * the various ideas of what userland clients might have for an
- * offset in the card address space into an offset into the card
- * address space :) So with a sane client, it should just keep
- * the value intact and just do some boundary checking. However,
- * not all clients are sane. Some older clients pass us 0 based
- * offsets relative to the start of the framebuffer and some may
- * assume the AGP aperture it appended to the framebuffer, so we
- * try to detect those cases and fix them up.
- *
- * Note: It might be a good idea here to make sure the offset lands
- * in some "allowed" area to protect things like the PCIE GART...
- */
-
- /* First, the best case, the offset already lands in either the
- * framebuffer or the GART mapped space
- */
- if (radeon_check_offset(dev_priv, off))
- return 0;
-
- /* Ok, that didn't happen... now check if we have a zero based
- * offset that fits in the framebuffer + gart space, apply the
- * magic offset we get from SETPARAM or calculated from fb_location
- */
- if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
- radeon_priv = file_priv->driver_priv;
- off += radeon_priv->radeon_fb_delta;
- }
-
- /* Finally, assume we aimed at a GART offset if beyond the fb */
- if (off > fb_end)
- off = off - fb_end - 1 + dev_priv->gart_vm_start;
-
- /* Now recheck and fail if out of bounds */
- if (radeon_check_offset(dev_priv, off)) {
- DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
- *offset = off;
- return 0;
- }
- return -EINVAL;
-}
-
-static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
- dev_priv,
- struct drm_file *file_priv,
- int id, struct drm_buffer *buf)
-{
- u32 *data;
- switch (id) {
-
- case RADEON_EMIT_PP_MISC:
- data = drm_buffer_pointer_to_dword(buf,
- (RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4);
-
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
- DRM_ERROR("Invalid depth buffer offset\n");
- return -EINVAL;
- }
- dev_priv->have_z_offset = 1;
- break;
-
- case RADEON_EMIT_PP_CNTL:
- data = drm_buffer_pointer_to_dword(buf,
- (RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4);
-
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
- DRM_ERROR("Invalid colour buffer offset\n");
- return -EINVAL;
- }
- break;
-
- case R200_EMIT_PP_TXOFFSET_0:
- case R200_EMIT_PP_TXOFFSET_1:
- case R200_EMIT_PP_TXOFFSET_2:
- case R200_EMIT_PP_TXOFFSET_3:
- case R200_EMIT_PP_TXOFFSET_4:
- case R200_EMIT_PP_TXOFFSET_5:
- data = drm_buffer_pointer_to_dword(buf, 0);
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
- DRM_ERROR("Invalid R200 texture offset\n");
- return -EINVAL;
- }
- break;
-
- case RADEON_EMIT_PP_TXFILTER_0:
- case RADEON_EMIT_PP_TXFILTER_1:
- case RADEON_EMIT_PP_TXFILTER_2:
- data = drm_buffer_pointer_to_dword(buf,
- (RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4);
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
- DRM_ERROR("Invalid R100 texture offset\n");
- return -EINVAL;
- }
- break;
-
- case R200_EMIT_PP_CUBIC_OFFSETS_0:
- case R200_EMIT_PP_CUBIC_OFFSETS_1:
- case R200_EMIT_PP_CUBIC_OFFSETS_2:
- case R200_EMIT_PP_CUBIC_OFFSETS_3:
- case R200_EMIT_PP_CUBIC_OFFSETS_4:
- case R200_EMIT_PP_CUBIC_OFFSETS_5:{
- int i;
- for (i = 0; i < 5; i++) {
- data = drm_buffer_pointer_to_dword(buf, i);
- if (radeon_check_and_fixup_offset(dev_priv,
- file_priv,
- data)) {
- DRM_ERROR
- ("Invalid R200 cubic texture offset\n");
- return -EINVAL;
- }
- }
- break;
- }
-
- case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
- case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
- case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
- int i;
- for (i = 0; i < 5; i++) {
- data = drm_buffer_pointer_to_dword(buf, i);
- if (radeon_check_and_fixup_offset(dev_priv,
- file_priv,
- data)) {
- DRM_ERROR
- ("Invalid R100 cubic texture offset\n");
- return -EINVAL;
- }
- }
- }
- break;
-
- case R200_EMIT_VAP_CTL:{
- RING_LOCALS;
- BEGIN_RING(2);
- OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
- ADVANCE_RING();
- }
- break;
-
- case RADEON_EMIT_RB3D_COLORPITCH:
- case RADEON_EMIT_RE_LINE_PATTERN:
- case RADEON_EMIT_SE_LINE_WIDTH:
- case RADEON_EMIT_PP_LUM_MATRIX:
- case RADEON_EMIT_PP_ROT_MATRIX_0:
- case RADEON_EMIT_RB3D_STENCILREFMASK:
- case RADEON_EMIT_SE_VPORT_XSCALE:
- case RADEON_EMIT_SE_CNTL:
- case RADEON_EMIT_SE_CNTL_STATUS:
- case RADEON_EMIT_RE_MISC:
- case RADEON_EMIT_PP_BORDER_COLOR_0:
- case RADEON_EMIT_PP_BORDER_COLOR_1:
- case RADEON_EMIT_PP_BORDER_COLOR_2:
- case RADEON_EMIT_SE_ZBIAS_FACTOR:
- case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
- case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
- case R200_EMIT_PP_TXCBLEND_0:
- case R200_EMIT_PP_TXCBLEND_1:
- case R200_EMIT_PP_TXCBLEND_2:
- case R200_EMIT_PP_TXCBLEND_3:
- case R200_EMIT_PP_TXCBLEND_4:
- case R200_EMIT_PP_TXCBLEND_5:
- case R200_EMIT_PP_TXCBLEND_6:
- case R200_EMIT_PP_TXCBLEND_7:
- case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
- case R200_EMIT_TFACTOR_0:
- case R200_EMIT_VTX_FMT_0:
- case R200_EMIT_MATRIX_SELECT_0:
- case R200_EMIT_TEX_PROC_CTL_2:
- case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
- case R200_EMIT_PP_TXFILTER_0:
- case R200_EMIT_PP_TXFILTER_1:
- case R200_EMIT_PP_TXFILTER_2:
- case R200_EMIT_PP_TXFILTER_3:
- case R200_EMIT_PP_TXFILTER_4:
- case R200_EMIT_PP_TXFILTER_5:
- case R200_EMIT_VTE_CNTL:
- case R200_EMIT_OUTPUT_VTX_COMP_SEL:
- case R200_EMIT_PP_TAM_DEBUG3:
- case R200_EMIT_PP_CNTL_X:
- case R200_EMIT_RB3D_DEPTHXY_OFFSET:
- case R200_EMIT_RE_AUX_SCISSOR_CNTL:
- case R200_EMIT_RE_SCISSOR_TL_0:
- case R200_EMIT_RE_SCISSOR_TL_1:
- case R200_EMIT_RE_SCISSOR_TL_2:
- case R200_EMIT_SE_VAP_CNTL_STATUS:
- case R200_EMIT_SE_VTX_STATE_CNTL:
- case R200_EMIT_RE_POINTSIZE:
- case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
- case R200_EMIT_PP_CUBIC_FACES_0:
- case R200_EMIT_PP_CUBIC_FACES_1:
- case R200_EMIT_PP_CUBIC_FACES_2:
- case R200_EMIT_PP_CUBIC_FACES_3:
- case R200_EMIT_PP_CUBIC_FACES_4:
- case R200_EMIT_PP_CUBIC_FACES_5:
- case RADEON_EMIT_PP_TEX_SIZE_0:
- case RADEON_EMIT_PP_TEX_SIZE_1:
- case RADEON_EMIT_PP_TEX_SIZE_2:
- case R200_EMIT_RB3D_BLENDCOLOR:
- case R200_EMIT_TCL_POINT_SPRITE_CNTL:
- case RADEON_EMIT_PP_CUBIC_FACES_0:
- case RADEON_EMIT_PP_CUBIC_FACES_1:
- case RADEON_EMIT_PP_CUBIC_FACES_2:
- case R200_EMIT_PP_TRI_PERF_CNTL:
- case R200_EMIT_PP_AFS_0:
- case R200_EMIT_PP_AFS_1:
- case R200_EMIT_ATF_TFACTOR:
- case R200_EMIT_PP_TXCTLALL_0:
- case R200_EMIT_PP_TXCTLALL_1:
- case R200_EMIT_PP_TXCTLALL_2:
- case R200_EMIT_PP_TXCTLALL_3:
- case R200_EMIT_PP_TXCTLALL_4:
- case R200_EMIT_PP_TXCTLALL_5:
- case R200_EMIT_VAP_PVS_CNTL:
- /* These packets don't contain memory offsets */
- break;
-
- default:
- DRM_ERROR("Unknown state packet ID %d\n", id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int radeon_check_and_fixup_packet3(drm_radeon_private_t *
- dev_priv,
- struct drm_file *file_priv,
- drm_radeon_kcmd_buffer_t *
- cmdbuf,
- unsigned int *cmdsz)
-{
- u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
- u32 offset, narrays;
- int count, i, k;
-
- count = ((*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16);
- *cmdsz = 2 + count;
-
- if ((*cmd & 0xc0000000) != RADEON_CP_PACKET3) {
- DRM_ERROR("Not a type 3 packet\n");
- return -EINVAL;
- }
-
- if (4 * *cmdsz > drm_buffer_unprocessed(cmdbuf->buffer)) {
- DRM_ERROR("Packet size larger than size of data provided\n");
- return -EINVAL;
- }
-
- switch (*cmd & 0xff00) {
- /* XXX Are there old drivers needing other packets? */
-
- case RADEON_3D_DRAW_IMMD:
- case RADEON_3D_DRAW_VBUF:
- case RADEON_3D_DRAW_INDX:
- case RADEON_WAIT_FOR_IDLE:
- case RADEON_CP_NOP:
- case RADEON_3D_CLEAR_ZMASK:
-/* case RADEON_CP_NEXT_CHAR:
- case RADEON_CP_PLY_NEXTSCAN:
- case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
- /* these packets are safe */
- break;
-
- case RADEON_CP_3D_DRAW_IMMD_2:
- case RADEON_CP_3D_DRAW_VBUF_2:
- case RADEON_CP_3D_DRAW_INDX_2:
- case RADEON_3D_CLEAR_HIZ:
- /* safe but r200 only */
- if (dev_priv->microcode_version != UCODE_R200) {
- DRM_ERROR("Invalid 3d packet for r100-class chip\n");
- return -EINVAL;
- }
- break;
-
- case RADEON_3D_LOAD_VBPNTR:
-
- if (count > 18) { /* 12 arrays max */
- DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
- count);
- return -EINVAL;
- }
-
- /* carefully check packet contents */
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
-
- narrays = *cmd & ~0xc000;
- k = 0;
- i = 2;
- while ((k < narrays) && (i < (count + 2))) {
- i++; /* skip attribute field */
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- cmd)) {
- DRM_ERROR
- ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
- k, i);
- return -EINVAL;
- }
- k++;
- i++;
- if (k == narrays)
- break;
- /* have one more to process, they come in pairs */
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
-
- if (radeon_check_and_fixup_offset(dev_priv,
- file_priv, cmd))
- {
- DRM_ERROR
- ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
- k, i);
- return -EINVAL;
- }
- k++;
- i++;
- }
- /* do the counts match what we expect ? */
- if ((k != narrays) || (i != (count + 2))) {
- DRM_ERROR
- ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
- k, i, narrays, count + 1);
- return -EINVAL;
- }
- break;
-
- case RADEON_3D_RNDR_GEN_INDX_PRIM:
- if (dev_priv->microcode_version != UCODE_R100) {
- DRM_ERROR("Invalid 3d packet for r200-class chip\n");
- return -EINVAL;
- }
-
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) {
- DRM_ERROR("Invalid rndr_gen_indx offset\n");
- return -EINVAL;
- }
- break;
-
- case RADEON_CP_INDX_BUFFER:
- if (dev_priv->microcode_version != UCODE_R200) {
- DRM_ERROR("Invalid 3d packet for r100-class chip\n");
- return -EINVAL;
- }
-
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
- if ((*cmd & 0x8000ffff) != 0x80000810) {
- DRM_ERROR("Invalid indx_buffer reg address %08X\n", *cmd);
- return -EINVAL;
- }
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) {
- DRM_ERROR("Invalid indx_buffer offset is %08X\n", *cmd);
- return -EINVAL;
- }
- break;
-
- case RADEON_CNTL_HOSTDATA_BLT:
- case RADEON_CNTL_PAINT_MULTI:
- case RADEON_CNTL_BITBLT_MULTI:
- /* MSB of opcode: next DWORD GUI_CNTL */
- cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
- if (*cmd & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
- | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
- offset = *cmd2 << 10;
- if (radeon_check_and_fixup_offset
- (dev_priv, file_priv, &offset)) {
- DRM_ERROR("Invalid first packet offset\n");
- return -EINVAL;
- }
- *cmd2 = (*cmd2 & 0xffc00000) | offset >> 10;
- }
-
- if ((*cmd & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
- (*cmd & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
- offset = *cmd3 << 10;
- if (radeon_check_and_fixup_offset
- (dev_priv, file_priv, &offset)) {
- DRM_ERROR("Invalid second packet offset\n");
- return -EINVAL;
- }
- *cmd3 = (*cmd3 & 0xffc00000) | offset >> 10;
- }
- break;
-
- default:
- DRM_ERROR("Invalid packet type %x\n", *cmd & 0xff00);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* ================================================================
- * CP hardware state programming functions
- */
-
-static void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
- struct drm_clip_rect * box)
-{
- RING_LOCALS;
-
- DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n",
- box->x1, box->y1, box->x2, box->y2);
-
- BEGIN_RING(4);
- OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
- OUT_RING((box->y1 << 16) | box->x1);
- OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
- OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
- ADVANCE_RING();
-}
-
-/* Emit 1.1 state
- */
-static int radeon_emit_state(drm_radeon_private_t * dev_priv,
- struct drm_file *file_priv,
- drm_radeon_context_regs_t * ctx,
- drm_radeon_texture_regs_t * tex,
- unsigned int dirty)
-{
- RING_LOCALS;
- DRM_DEBUG("dirty=0x%08x\n", dirty);
-
- if (dirty & RADEON_UPLOAD_CONTEXT) {
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &ctx->rb3d_depthoffset)) {
- DRM_ERROR("Invalid depth buffer offset\n");
- return -EINVAL;
- }
-
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &ctx->rb3d_coloroffset)) {
- DRM_ERROR("Invalid depth buffer offset\n");
- return -EINVAL;
- }
-
- BEGIN_RING(14);
- OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
- OUT_RING(ctx->pp_misc);
- OUT_RING(ctx->pp_fog_color);
- OUT_RING(ctx->re_solid_color);
- OUT_RING(ctx->rb3d_blendcntl);
- OUT_RING(ctx->rb3d_depthoffset);
- OUT_RING(ctx->rb3d_depthpitch);
- OUT_RING(ctx->rb3d_zstencilcntl);
- OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
- OUT_RING(ctx->pp_cntl);
- OUT_RING(ctx->rb3d_cntl);
- OUT_RING(ctx->rb3d_coloroffset);
- OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
- OUT_RING(ctx->rb3d_colorpitch);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_VERTFMT) {
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
- OUT_RING(ctx->se_coord_fmt);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_LINE) {
- BEGIN_RING(5);
- OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
- OUT_RING(ctx->re_line_pattern);
- OUT_RING(ctx->re_line_state);
- OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
- OUT_RING(ctx->se_line_width);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_BUMPMAP) {
- BEGIN_RING(5);
- OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
- OUT_RING(ctx->pp_lum_matrix);
- OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
- OUT_RING(ctx->pp_rot_matrix_0);
- OUT_RING(ctx->pp_rot_matrix_1);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_MASKS) {
- BEGIN_RING(4);
- OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
- OUT_RING(ctx->rb3d_stencilrefmask);
- OUT_RING(ctx->rb3d_ropcntl);
- OUT_RING(ctx->rb3d_planemask);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_VIEWPORT) {
- BEGIN_RING(7);
- OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
- OUT_RING(ctx->se_vport_xscale);
- OUT_RING(ctx->se_vport_xoffset);
- OUT_RING(ctx->se_vport_yscale);
- OUT_RING(ctx->se_vport_yoffset);
- OUT_RING(ctx->se_vport_zscale);
- OUT_RING(ctx->se_vport_zoffset);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_SETUP) {
- BEGIN_RING(4);
- OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
- OUT_RING(ctx->se_cntl);
- OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
- OUT_RING(ctx->se_cntl_status);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_MISC) {
- BEGIN_RING(2);
- OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
- OUT_RING(ctx->re_misc);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_TEX0) {
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &tex[0].pp_txoffset)) {
- DRM_ERROR("Invalid texture offset for unit 0\n");
- return -EINVAL;
- }
-
- BEGIN_RING(9);
- OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
- OUT_RING(tex[0].pp_txfilter);
- OUT_RING(tex[0].pp_txformat);
- OUT_RING(tex[0].pp_txoffset);
- OUT_RING(tex[0].pp_txcblend);
- OUT_RING(tex[0].pp_txablend);
- OUT_RING(tex[0].pp_tfactor);
- OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
- OUT_RING(tex[0].pp_border_color);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_TEX1) {
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &tex[1].pp_txoffset)) {
- DRM_ERROR("Invalid texture offset for unit 1\n");
- return -EINVAL;
- }
-
- BEGIN_RING(9);
- OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
- OUT_RING(tex[1].pp_txfilter);
- OUT_RING(tex[1].pp_txformat);
- OUT_RING(tex[1].pp_txoffset);
- OUT_RING(tex[1].pp_txcblend);
- OUT_RING(tex[1].pp_txablend);
- OUT_RING(tex[1].pp_tfactor);
- OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
- OUT_RING(tex[1].pp_border_color);
- ADVANCE_RING();
- }
-
- if (dirty & RADEON_UPLOAD_TEX2) {
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &tex[2].pp_txoffset)) {
- DRM_ERROR("Invalid texture offset for unit 2\n");
- return -EINVAL;
- }
-
- BEGIN_RING(9);
- OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
- OUT_RING(tex[2].pp_txfilter);
- OUT_RING(tex[2].pp_txformat);
- OUT_RING(tex[2].pp_txoffset);
- OUT_RING(tex[2].pp_txcblend);
- OUT_RING(tex[2].pp_txablend);
- OUT_RING(tex[2].pp_tfactor);
- OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
- OUT_RING(tex[2].pp_border_color);
- ADVANCE_RING();
- }
-
- return 0;
-}
-
-/* Emit 1.2 state
- */
-static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
- struct drm_file *file_priv,
- drm_radeon_state_t * state)
-{
- RING_LOCALS;
-
- if (state->dirty & RADEON_UPLOAD_ZBIAS) {
- BEGIN_RING(3);
- OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
- OUT_RING(state->context2.se_zbias_factor);
- OUT_RING(state->context2.se_zbias_constant);
- ADVANCE_RING();
- }
-
- return radeon_emit_state(dev_priv, file_priv, &state->context,
- state->tex, state->dirty);
-}
-
-/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
- * 1.3 cmdbuffers allow all previous state to be updated as well as
- * the tcl scalar and vector areas.
- */
-static struct {
- int start;
- int len;
- const char *name;
-} packet[RADEON_MAX_STATE_PACKETS] = {
- {RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
- {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
- {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
- {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
- {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
- {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
- {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
- {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
- {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
- {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
- {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
- {RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
- {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
- {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
- {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
- {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
- {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
- {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
- {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
- {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
- {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
- "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
- {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
- {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
- {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
- {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
- {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
- {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
- {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
- {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
- {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
- {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
- {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
- {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
- {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
- {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
- {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
- {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
- {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
- {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
- {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
- {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
- {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
- {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
- {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
- {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
- {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
- {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
- {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
- {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
- {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
- "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
- {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
- {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
- {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
- {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
- {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
- {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
- {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
- {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
- {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
- {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
- {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
- "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
- {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */
- {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
- {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
- {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
- {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
- {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
- {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
- {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
- {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
- {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
- {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
- {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
- {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
- {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
- {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
- {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
- {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
- {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
- {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
- {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
- {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
- {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
- {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
- {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
- {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */
- {R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
- {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
- {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
- {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
- {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
- {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
- {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
- {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
- {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
-};
-
-/* ================================================================
- * Performance monitoring functions
- */
-
-static void radeon_clear_box(drm_radeon_private_t * dev_priv,
- struct drm_radeon_master_private *master_priv,
- int x, int y, int w, int h, int r, int g, int b)
-{
- u32 color;
- RING_LOCALS;
-
- x += master_priv->sarea_priv->boxes[0].x1;
- y += master_priv->sarea_priv->boxes[0].y1;
-
- switch (dev_priv->color_fmt) {
- case RADEON_COLOR_FORMAT_RGB565:
- color = (((r & 0xf8) << 8) |
- ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
- break;
- case RADEON_COLOR_FORMAT_ARGB8888:
- default:
- color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
- break;
- }
-
- BEGIN_RING(4);
- RADEON_WAIT_UNTIL_3D_IDLE();
- OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
- OUT_RING(0xffffffff);
- ADVANCE_RING();
-
- BEGIN_RING(6);
-
- OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
- OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
- RADEON_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->color_fmt << 8) |
- RADEON_GMC_SRC_DATATYPE_COLOR |
- RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
-
- if (master_priv->sarea_priv->pfCurrentPage == 1) {
- OUT_RING(dev_priv->front_pitch_offset);
- } else {
- OUT_RING(dev_priv->back_pitch_offset);
- }
-
- OUT_RING(color);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
-}
-
-static void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv, struct drm_radeon_master_private *master_priv)
-{
- /* Collapse various things into a wait flag -- trying to
- * guess if userspase slept -- better just to have them tell us.
- */
- if (dev_priv->stats.last_frame_reads > 1 ||
- dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
- }
-
- if (dev_priv->stats.freelist_loops) {
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
- }
-
- /* Purple box for page flipping
- */
- if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
- radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255);
-
- /* Red box if we have to wait for idle at any point
- */
- if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
- radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0);
-
- /* Blue box: lost context?
- */
-
- /* Yellow box for texture swaps
- */
- if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
- radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0);
-
- /* Green box if hardware never idles (as far as we can tell)
- */
- if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
- radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0);
-
- /* Draw bars indicating number of buffers allocated
- * (not a great measure, easily confused)
- */
- if (dev_priv->stats.requested_bufs) {
- if (dev_priv->stats.requested_bufs > 100)
- dev_priv->stats.requested_bufs = 100;
-
- radeon_clear_box(dev_priv, master_priv, 4, 16,
- dev_priv->stats.requested_bufs, 4,
- 196, 128, 128);
- }
-
- memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
-
-}
-
-/* ================================================================
- * CP command dispatch functions
- */
-
-static void radeon_cp_dispatch_clear(struct drm_device * dev,
- struct drm_master *master,
- drm_radeon_clear_t * clear,
- drm_radeon_clear_rect_t * depth_boxes)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
- drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- unsigned int flags = clear->flags;
- u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
- int i;
- RING_LOCALS;
- DRM_DEBUG("flags = 0x%x\n", flags);
-
- dev_priv->stats.clears++;
-
- if (sarea_priv->pfCurrentPage == 1) {
- unsigned int tmp = flags;
-
- flags &= ~(RADEON_FRONT | RADEON_BACK);
- if (tmp & RADEON_FRONT)
- flags |= RADEON_BACK;
- if (tmp & RADEON_BACK)
- flags |= RADEON_FRONT;
- }
- if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
- if (!dev_priv->have_z_offset) {
- printk_once(KERN_ERR "radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
- flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
- }
- }
-
- if (flags & (RADEON_FRONT | RADEON_BACK)) {
-
- BEGIN_RING(4);
-
- /* Ensure the 3D stream is idle before doing a
- * 2D fill to clear the front or back buffer.
- */
- RADEON_WAIT_UNTIL_3D_IDLE();
-
- OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
- OUT_RING(clear->color_mask);
-
- ADVANCE_RING();
-
- /* Make sure we restore the 3D state next time.
- */
- sarea_priv->ctx_owner = 0;
-
- for (i = 0; i < nbox; i++) {
- int x = pbox[i].x1;
- int y = pbox[i].y1;
- int w = pbox[i].x2 - x;
- int h = pbox[i].y2 - y;
-
- DRM_DEBUG("%d,%d-%d,%d flags 0x%x\n",
- x, y, w, h, flags);
-
- if (flags & RADEON_FRONT) {
- BEGIN_RING(6);
-
- OUT_RING(CP_PACKET3
- (RADEON_CNTL_PAINT_MULTI, 4));
- OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
- RADEON_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->
- color_fmt << 8) |
- RADEON_GMC_SRC_DATATYPE_COLOR |
- RADEON_ROP3_P |
- RADEON_GMC_CLR_CMP_CNTL_DIS);
-
- OUT_RING(dev_priv->front_pitch_offset);
- OUT_RING(clear->clear_color);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
-
- if (flags & RADEON_BACK) {
- BEGIN_RING(6);
-
- OUT_RING(CP_PACKET3
- (RADEON_CNTL_PAINT_MULTI, 4));
- OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
- RADEON_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->
- color_fmt << 8) |
- RADEON_GMC_SRC_DATATYPE_COLOR |
- RADEON_ROP3_P |
- RADEON_GMC_CLR_CMP_CNTL_DIS);
-
- OUT_RING(dev_priv->back_pitch_offset);
- OUT_RING(clear->clear_color);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
- }
- }
-
- /* hyper z clear */
- /* no docs available, based on reverse engineering by Stephane Marchesin */
- if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
- && (flags & RADEON_CLEAR_FASTZ)) {
-
- int i;
- int depthpixperline =
- dev_priv->depth_fmt ==
- RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
- 2) : (dev_priv->
- depth_pitch / 4);
-
- u32 clearmask;
-
- u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
- ((clear->depth_mask & 0xff) << 24);
-
- /* Make sure we restore the 3D state next time.
- * we haven't touched any "normal" state - still need this?
- */
- sarea_priv->ctx_owner = 0;
-
- if ((dev_priv->flags & RADEON_HAS_HIERZ)
- && (flags & RADEON_USE_HIERZ)) {
- /* FIXME : reverse engineer that for Rx00 cards */
- /* FIXME : the mask supposedly contains low-res z values. So can't set
- just to the max (0xff? or actually 0x3fff?), need to take z clear
- value into account? */
- /* pattern seems to work for r100, though get slight
- rendering errors with glxgears. If hierz is not enabled for r100,
- only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
- other ones are ignored, and the same clear mask can be used. That's
- very different behaviour than R200 which needs different clear mask
- and different number of tiles to clear if hierz is enabled or not !?!
- */
- clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
- } else {
- /* clear mask : chooses the clearing pattern.
- rv250: could be used to clear only parts of macrotiles
- (but that would get really complicated...)?
- bit 0 and 1 (either or both of them ?!?!) are used to
- not clear tile (or maybe one of the bits indicates if the tile is
- compressed or not), bit 2 and 3 to not clear tile 1,...,.
- Pattern is as follows:
- | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
- bits -------------------------------------------------
- | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
- rv100: clearmask covers 2x8 4x1 tiles, but one clear still
- covers 256 pixels ?!?
- */
- clearmask = 0x0;
- }
-
- BEGIN_RING(8);
- RADEON_WAIT_UNTIL_2D_IDLE();
- OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
- tempRB3D_DEPTHCLEARVALUE);
- /* what offset is this exactly ? */
- OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
- /* need ctlstat, otherwise get some strange black flickering */
- OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
- RADEON_RB3D_ZC_FLUSH_ALL);
- ADVANCE_RING();
-
- for (i = 0; i < nbox; i++) {
- int tileoffset, nrtilesx, nrtilesy, j;
- /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
- if ((dev_priv->flags & RADEON_HAS_HIERZ)
- && !(dev_priv->microcode_version == UCODE_R200)) {
- /* FIXME : figure this out for r200 (when hierz is enabled). Or
- maybe r200 actually doesn't need to put the low-res z value into
- the tile cache like r100, but just needs to clear the hi-level z-buffer?
- Works for R100, both with hierz and without.
- R100 seems to operate on 2x1 8x8 tiles, but...
- odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
- problematic with resolutions which are not 64 pix aligned? */
- tileoffset =
- ((pbox[i].y1 >> 3) * depthpixperline +
- pbox[i].x1) >> 6;
- nrtilesx =
- ((pbox[i].x2 & ~63) -
- (pbox[i].x1 & ~63)) >> 4;
- nrtilesy =
- (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
- for (j = 0; j <= nrtilesy; j++) {
- BEGIN_RING(4);
- OUT_RING(CP_PACKET3
- (RADEON_3D_CLEAR_ZMASK, 2));
- /* first tile */
- OUT_RING(tileoffset * 8);
- /* the number of tiles to clear */
- OUT_RING(nrtilesx + 4);
- /* clear mask : chooses the clearing pattern. */
- OUT_RING(clearmask);
- ADVANCE_RING();
- tileoffset += depthpixperline >> 6;
- }
- } else if (dev_priv->microcode_version == UCODE_R200) {
- /* works for rv250. */
- /* find first macro tile (8x2 4x4 z-pixels on rv250) */
- tileoffset =
- ((pbox[i].y1 >> 3) * depthpixperline +
- pbox[i].x1) >> 5;
- nrtilesx =
- (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
- nrtilesy =
- (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
- for (j = 0; j <= nrtilesy; j++) {
- BEGIN_RING(4);
- OUT_RING(CP_PACKET3
- (RADEON_3D_CLEAR_ZMASK, 2));
- /* first tile */
- /* judging by the first tile offset needed, could possibly
- directly address/clear 4x4 tiles instead of 8x2 * 4x4
- macro tiles, though would still need clear mask for
- right/bottom if truly 4x4 granularity is desired ? */
- OUT_RING(tileoffset * 16);
- /* the number of tiles to clear */
- OUT_RING(nrtilesx + 1);
- /* clear mask : chooses the clearing pattern. */
- OUT_RING(clearmask);
- ADVANCE_RING();
- tileoffset += depthpixperline >> 5;
- }
- } else { /* rv 100 */
- /* rv100 might not need 64 pix alignment, who knows */
- /* offsets are, hmm, weird */
- tileoffset =
- ((pbox[i].y1 >> 4) * depthpixperline +
- pbox[i].x1) >> 6;
- nrtilesx =
- ((pbox[i].x2 & ~63) -
- (pbox[i].x1 & ~63)) >> 4;
- nrtilesy =
- (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
- for (j = 0; j <= nrtilesy; j++) {
- BEGIN_RING(4);
- OUT_RING(CP_PACKET3
- (RADEON_3D_CLEAR_ZMASK, 2));
- OUT_RING(tileoffset * 128);
- /* the number of tiles to clear */
- OUT_RING(nrtilesx + 4);
- /* clear mask : chooses the clearing pattern. */
- OUT_RING(clearmask);
- ADVANCE_RING();
- tileoffset += depthpixperline >> 6;
- }
- }
- }
-
- /* TODO don't always clear all hi-level z tiles */
- if ((dev_priv->flags & RADEON_HAS_HIERZ)
- && (dev_priv->microcode_version == UCODE_R200)
- && (flags & RADEON_USE_HIERZ))
- /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
- /* FIXME : the mask supposedly contains low-res z values. So can't set
- just to the max (0xff? or actually 0x3fff?), need to take z clear
- value into account? */
- {
- BEGIN_RING(4);
- OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
- OUT_RING(0x0); /* First tile */
- OUT_RING(0x3cc0);
- OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
- ADVANCE_RING();
- }
- }
-
- /* We have to clear the depth and/or stencil buffers by
- * rendering a quad into just those buffers. Thus, we have to
- * make sure the 3D engine is configured correctly.
- */
- else if ((dev_priv->microcode_version == UCODE_R200) &&
- (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
-
- int tempPP_CNTL;
- int tempRE_CNTL;
- int tempRB3D_CNTL;
- int tempRB3D_ZSTENCILCNTL;
- int tempRB3D_STENCILREFMASK;
- int tempRB3D_PLANEMASK;
- int tempSE_CNTL;
- int tempSE_VTE_CNTL;
- int tempSE_VTX_FMT_0;
- int tempSE_VTX_FMT_1;
- int tempSE_VAP_CNTL;
- int tempRE_AUX_SCISSOR_CNTL;
-
- tempPP_CNTL = 0;
- tempRE_CNTL = 0;
-
- tempRB3D_CNTL = depth_clear->rb3d_cntl;
-
- tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
- tempRB3D_STENCILREFMASK = 0x0;
-
- tempSE_CNTL = depth_clear->se_cntl;
-
- /* Disable TCL */
-
- tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */
- (0x9 <<
- SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
-
- tempRB3D_PLANEMASK = 0x0;
-
- tempRE_AUX_SCISSOR_CNTL = 0x0;
-
- tempSE_VTE_CNTL =
- SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
-
- /* Vertex format (X, Y, Z, W) */
- tempSE_VTX_FMT_0 =
- SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
- SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
- tempSE_VTX_FMT_1 = 0x0;
-
- /*
- * Depth buffer specific enables
- */
- if (flags & RADEON_DEPTH) {
- /* Enable depth buffer */
- tempRB3D_CNTL |= RADEON_Z_ENABLE;
- } else {
- /* Disable depth buffer */
- tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
- }
-
- /*
- * Stencil buffer specific enables
- */
- if (flags & RADEON_STENCIL) {
- tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
- tempRB3D_STENCILREFMASK = clear->depth_mask;
- } else {
- tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
- tempRB3D_STENCILREFMASK = 0x00000000;
- }
-
- if (flags & RADEON_USE_COMP_ZBUF) {
- tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
- RADEON_Z_DECOMPRESSION_ENABLE;
- }
- if (flags & RADEON_USE_HIERZ) {
- tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
- }
-
- BEGIN_RING(26);
- RADEON_WAIT_UNTIL_2D_IDLE();
-
- OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
- OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
- OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
- OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
- OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
- tempRB3D_STENCILREFMASK);
- OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
- OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
- OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
- OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
- OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
- OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
- OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
- ADVANCE_RING();
-
- /* Make sure we restore the 3D state next time.
- */
- sarea_priv->ctx_owner = 0;
-
- for (i = 0; i < nbox; i++) {
-
- /* Funny that this should be required --
- * sets top-left?
- */
- radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
-
- BEGIN_RING(14);
- OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
- OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
- RADEON_PRIM_WALK_RING |
- (3 << RADEON_NUM_VERTICES_SHIFT)));
- OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
- OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
- OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
- OUT_RING(0x3f800000);
- OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
- OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
- OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
- OUT_RING(0x3f800000);
- OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
- OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
- OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
- OUT_RING(0x3f800000);
- ADVANCE_RING();
- }
- } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
-
- int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
-
- rb3d_cntl = depth_clear->rb3d_cntl;
-
- if (flags & RADEON_DEPTH) {
- rb3d_cntl |= RADEON_Z_ENABLE;
- } else {
- rb3d_cntl &= ~RADEON_Z_ENABLE;
- }
-
- if (flags & RADEON_STENCIL) {
- rb3d_cntl |= RADEON_STENCIL_ENABLE;
- rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
- } else {
- rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
- rb3d_stencilrefmask = 0x00000000;
- }
-
- if (flags & RADEON_USE_COMP_ZBUF) {
- tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
- RADEON_Z_DECOMPRESSION_ENABLE;
- }
- if (flags & RADEON_USE_HIERZ) {
- tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
- }
-
- BEGIN_RING(13);
- RADEON_WAIT_UNTIL_2D_IDLE();
-
- OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
- OUT_RING(0x00000000);
- OUT_RING(rb3d_cntl);
-
- OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
- OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
- OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
- OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
- ADVANCE_RING();
-
- /* Make sure we restore the 3D state next time.
- */
- sarea_priv->ctx_owner = 0;
-
- for (i = 0; i < nbox; i++) {
-
- /* Funny that this should be required --
- * sets top-left?
- */
- radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
-
- BEGIN_RING(15);
-
- OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
- OUT_RING(RADEON_VTX_Z_PRESENT |
- RADEON_VTX_PKCOLOR_PRESENT);
- OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
- RADEON_PRIM_WALK_RING |
- RADEON_MAOS_ENABLE |
- RADEON_VTX_FMT_RADEON_MODE |
- (3 << RADEON_NUM_VERTICES_SHIFT)));
-
- OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
- OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
- OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
- OUT_RING(0x0);
-
- OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
- OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
- OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
- OUT_RING(0x0);
-
- OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
- OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
- OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
- OUT_RING(0x0);
-
- ADVANCE_RING();
- }
- }
-
- /* Increment the clear counter. The client-side 3D driver must
- * wait on this value before performing the clear ioctl. We
- * need this because the card's so damned fast...
- */
- sarea_priv->last_clear++;
-
- BEGIN_RING(4);
-
- RADEON_CLEAR_AGE(sarea_priv->last_clear);
- RADEON_WAIT_UNTIL_IDLE();
-
- ADVANCE_RING();
-}
-
-static void radeon_cp_dispatch_swap(struct drm_device *dev, struct drm_master *master)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- /* Do some trivial performance monitoring...
- */
- if (dev_priv->do_boxes)
- radeon_cp_performance_boxes(dev_priv, master_priv);
-
- /* Wait for the 3D stream to idle before dispatching the bitblt.
- * This will prevent data corruption between the two streams.
- */
- BEGIN_RING(2);
-
- RADEON_WAIT_UNTIL_3D_IDLE();
-
- ADVANCE_RING();
-
- for (i = 0; i < nbox; i++) {
- int x = pbox[i].x1;
- int y = pbox[i].y1;
- int w = pbox[i].x2 - x;
- int h = pbox[i].y2 - y;
-
- DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
-
- BEGIN_RING(9);
-
- OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
- OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
- RADEON_GMC_DST_PITCH_OFFSET_CNTL |
- RADEON_GMC_BRUSH_NONE |
- (dev_priv->color_fmt << 8) |
- RADEON_GMC_SRC_DATATYPE_COLOR |
- RADEON_ROP3_S |
- RADEON_DP_SRC_SOURCE_MEMORY |
- RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
-
- /* Make this work even if front & back are flipped:
- */
- OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
- if (sarea_priv->pfCurrentPage == 0) {
- OUT_RING(dev_priv->back_pitch_offset);
- OUT_RING(dev_priv->front_pitch_offset);
- } else {
- OUT_RING(dev_priv->front_pitch_offset);
- OUT_RING(dev_priv->back_pitch_offset);
- }
-
- OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
- OUT_RING((x << 16) | y);
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
-
- /* Increment the frame counter. The client-side 3D driver must
- * throttle the framerate by waiting for this value before
- * performing the swapbuffer ioctl.
- */
- sarea_priv->last_frame++;
-
- BEGIN_RING(4);
-
- RADEON_FRAME_AGE(sarea_priv->last_frame);
- RADEON_WAIT_UNTIL_2D_IDLE();
-
- ADVANCE_RING();
-}
-
-void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- struct drm_sarea *sarea = (struct drm_sarea *)master_priv->sarea->handle;
- int offset = (master_priv->sarea_priv->pfCurrentPage == 1)
- ? dev_priv->front_offset : dev_priv->back_offset;
- RING_LOCALS;
- DRM_DEBUG("pfCurrentPage=%d\n",
- master_priv->sarea_priv->pfCurrentPage);
-
- /* Do some trivial performance monitoring...
- */
- if (dev_priv->do_boxes) {
- dev_priv->stats.boxes |= RADEON_BOX_FLIP;
- radeon_cp_performance_boxes(dev_priv, master_priv);
- }
-
- /* Update the frame offsets for both CRTCs
- */
- BEGIN_RING(6);
-
- RADEON_WAIT_UNTIL_3D_IDLE();
- OUT_RING_REG(RADEON_CRTC_OFFSET,
- ((sarea->frame.y * dev_priv->front_pitch +
- sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
- + offset);
- OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base
- + offset);
-
- ADVANCE_RING();
-
- /* Increment the frame counter. The client-side 3D driver must
- * throttle the framerate by waiting for this value before
- * performing the swapbuffer ioctl.
- */
- master_priv->sarea_priv->last_frame++;
- master_priv->sarea_priv->pfCurrentPage =
- 1 - master_priv->sarea_priv->pfCurrentPage;
-
- BEGIN_RING(2);
-
- RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame);
-
- ADVANCE_RING();
-}
-
-static int bad_prim_vertex_nr(int primitive, int nr)
-{
- switch (primitive & RADEON_PRIM_TYPE_MASK) {
- case RADEON_PRIM_TYPE_NONE:
- case RADEON_PRIM_TYPE_POINT:
- return nr < 1;
- case RADEON_PRIM_TYPE_LINE:
- return (nr & 1) || nr == 0;
- case RADEON_PRIM_TYPE_LINE_STRIP:
- return nr < 2;
- case RADEON_PRIM_TYPE_TRI_LIST:
- case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
- case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
- case RADEON_PRIM_TYPE_RECT_LIST:
- return nr % 3 || nr == 0;
- case RADEON_PRIM_TYPE_TRI_FAN:
- case RADEON_PRIM_TYPE_TRI_STRIP:
- return nr < 3;
- default:
- return 1;
- }
-}
-
-typedef struct {
- unsigned int start;
- unsigned int finish;
- unsigned int prim;
- unsigned int numverts;
- unsigned int offset;
- unsigned int vc_format;
-} drm_radeon_tcl_prim_t;
-
-static void radeon_cp_dispatch_vertex(struct drm_device * dev,
- struct drm_file *file_priv,
- struct drm_buf * buf,
- drm_radeon_tcl_prim_t * prim)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
- int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
- int numverts = (int)prim->numverts;
- int nbox = sarea_priv->nbox;
- int i = 0;
- RING_LOCALS;
-
- DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
- prim->prim,
- prim->vc_format, prim->start, prim->finish, prim->numverts);
-
- if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
- DRM_ERROR("bad prim %x numverts %d\n",
- prim->prim, prim->numverts);
- return;
- }
-
- do {
- /* Emit the next cliprect */
- if (i < nbox) {
- radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
- }
-
- /* Emit the vertex buffer rendering commands */
- BEGIN_RING(5);
-
- OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
- OUT_RING(offset);
- OUT_RING(numverts);
- OUT_RING(prim->vc_format);
- OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
- RADEON_COLOR_ORDER_RGBA |
- RADEON_VTX_FMT_RADEON_MODE |
- (numverts << RADEON_NUM_VERTICES_SHIFT));
-
- ADVANCE_RING();
-
- i++;
- } while (i < nbox);
-}
-
-void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
- RING_LOCALS;
-
- buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
-
- /* Emit the vertex buffer age */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
- BEGIN_RING(3);
- R600_DISPATCH_AGE(buf_priv->age);
- ADVANCE_RING();
- } else {
- BEGIN_RING(2);
- RADEON_DISPATCH_AGE(buf_priv->age);
- ADVANCE_RING();
- }
-
- buf->pending = 1;
- buf->used = 0;
-}
-
-static void radeon_cp_dispatch_indirect(struct drm_device * dev,
- struct drm_buf * buf, int start, int end)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
- DRM_DEBUG("buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
-
- if (start != end) {
- int offset = (dev_priv->gart_buffers_offset
- + buf->offset + start);
- int dwords = (end - start + 3) / sizeof(u32);
-
- /* Indirect buffer data must be an even number of
- * dwords, so if we've been given an odd number we must
- * pad the data with a Type-2 CP packet.
- */
- if (dwords & 1) {
- u32 *data = (u32 *)
- ((char *)dev->agp_buffer_map->handle
- + buf->offset + start);
- data[dwords++] = RADEON_CP_PACKET2;
- }
-
- /* Fire off the indirect buffer */
- BEGIN_RING(3);
-
- OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
- OUT_RING(offset);
- OUT_RING(dwords);
-
- ADVANCE_RING();
- }
-}
-
-static void radeon_cp_dispatch_indices(struct drm_device *dev,
- struct drm_master *master,
- struct drm_buf * elt_buf,
- drm_radeon_tcl_prim_t * prim)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
- int offset = dev_priv->gart_buffers_offset + prim->offset;
- u32 *data;
- int dwords;
- int i = 0;
- int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
- int count = (prim->finish - start) / sizeof(u16);
- int nbox = sarea_priv->nbox;
-
- DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
- prim->prim,
- prim->vc_format,
- prim->start, prim->finish, prim->offset, prim->numverts);
-
- if (bad_prim_vertex_nr(prim->prim, count)) {
- DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
- return;
- }
-
- if (start >= prim->finish || (prim->start & 0x7)) {
- DRM_ERROR("buffer prim %d\n", prim->prim);
- return;
- }
-
- dwords = (prim->finish - prim->start + 3) / sizeof(u32);
-
- data = (u32 *) ((char *)dev->agp_buffer_map->handle +
- elt_buf->offset + prim->start);
-
- data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
- data[1] = offset;
- data[2] = prim->numverts;
- data[3] = prim->vc_format;
- data[4] = (prim->prim |
- RADEON_PRIM_WALK_IND |
- RADEON_COLOR_ORDER_RGBA |
- RADEON_VTX_FMT_RADEON_MODE |
- (count << RADEON_NUM_VERTICES_SHIFT));
-
- do {
- if (i < nbox)
- radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
-
- radeon_cp_dispatch_indirect(dev, elt_buf,
- prim->start, prim->finish);
-
- i++;
- } while (i < nbox);
-
-}
-
-#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
-
-static int radeon_cp_dispatch_texture(struct drm_device * dev,
- struct drm_file *file_priv,
- drm_radeon_texture_t * tex,
- drm_radeon_tex_image_t * image)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_buf *buf;
- u32 format;
- u32 *buffer;
- const u8 __user *data;
- unsigned int size, dwords, tex_width, blit_width, spitch;
- u32 height;
- int i;
- u32 texpitch, microtile;
- u32 offset, byte_offset;
- RING_LOCALS;
-
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
- DRM_ERROR("Invalid destination offset\n");
- return -EINVAL;
- }
-
- dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
-
- /* Flush the pixel cache. This ensures no pixel data gets mixed
- * up with the texture data from the host data blit, otherwise
- * part of the texture image may be corrupted.
- */
- BEGIN_RING(4);
- RADEON_FLUSH_CACHE();
- RADEON_WAIT_UNTIL_IDLE();
- ADVANCE_RING();
-
- /* The compiler won't optimize away a division by a variable,
- * even if the only legal values are powers of two. Thus, we'll
- * use a shift instead.
- */
- switch (tex->format) {
- case RADEON_TXFORMAT_ARGB8888:
- case RADEON_TXFORMAT_RGBA8888:
- format = RADEON_COLOR_FORMAT_ARGB8888;
- tex_width = tex->width * 4;
- blit_width = image->width * 4;
- break;
- case RADEON_TXFORMAT_AI88:
- case RADEON_TXFORMAT_ARGB1555:
- case RADEON_TXFORMAT_RGB565:
- case RADEON_TXFORMAT_ARGB4444:
- case RADEON_TXFORMAT_VYUY422:
- case RADEON_TXFORMAT_YVYU422:
- format = RADEON_COLOR_FORMAT_RGB565;
- tex_width = tex->width * 2;
- blit_width = image->width * 2;
- break;
- case RADEON_TXFORMAT_I8:
- case RADEON_TXFORMAT_RGB332:
- format = RADEON_COLOR_FORMAT_CI8;
- tex_width = tex->width * 1;
- blit_width = image->width * 1;
- break;
- default:
- DRM_ERROR("invalid texture format %d\n", tex->format);
- return -EINVAL;
- }
- spitch = blit_width >> 6;
- if (spitch == 0 && image->height > 1)
- return -EINVAL;
-
- texpitch = tex->pitch;
- if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
- microtile = 1;
- if (tex_width < 64) {
- texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
- /* we got tiled coordinates, untile them */
- image->x *= 2;
- }
- } else
- microtile = 0;
-
- /* this might fail for zero-sized uploads - are those illegal? */
- if (!radeon_check_offset(dev_priv, tex->offset + image->height *
- blit_width - 1)) {
- DRM_ERROR("Invalid final destination offset\n");
- return -EINVAL;
- }
-
- DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
-
- do {
- DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
- tex->offset >> 10, tex->pitch, tex->format,
- image->x, image->y, image->width, image->height);
-
- /* Make a copy of some parameters in case we have to
- * update them for a multi-pass texture blit.
- */
- height = image->height;
- data = (const u8 __user *)image->data;
-
- size = height * blit_width;
-
- if (size > RADEON_MAX_TEXTURE_SIZE) {
- height = RADEON_MAX_TEXTURE_SIZE / blit_width;
- size = height * blit_width;
- } else if (size < 4 && size > 0) {
- size = 4;
- } else if (size == 0) {
- return 0;
- }
-
- buf = radeon_freelist_get(dev);
- if (0 && !buf) {
- radeon_do_cp_idle(dev_priv);
- buf = radeon_freelist_get(dev);
- }
- if (!buf) {
- DRM_DEBUG("EAGAIN\n");
- if (copy_to_user(tex->image, image, sizeof(*image)))
- return -EFAULT;
- return -EAGAIN;
- }
-
- /* Dispatch the indirect buffer.
- */
- buffer =
- (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
- dwords = size / 4;
-
-#define RADEON_COPY_MT(_buf, _data, _width) \
- do { \
- if (copy_from_user(_buf, _data, (_width))) {\
- DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
- return -EFAULT; \
- } \
- } while(0)
-
- if (microtile) {
- /* texture micro tiling in use, minimum texture width is thus 16 bytes.
- however, we cannot use blitter directly for texture width < 64 bytes,
- since minimum tex pitch is 64 bytes and we need this to match
- the texture width, otherwise the blitter will tile it wrong.
- Thus, tiling manually in this case. Additionally, need to special
- case tex height = 1, since our actual image will have height 2
- and we need to ensure we don't read beyond the texture size
- from user space. */
- if (tex->height == 1) {
- if (tex_width >= 64 || tex_width <= 16) {
- RADEON_COPY_MT(buffer, data,
- (int)(tex_width * sizeof(u32)));
- } else if (tex_width == 32) {
- RADEON_COPY_MT(buffer, data, 16);
- RADEON_COPY_MT(buffer + 8,
- data + 16, 16);
- }
- } else if (tex_width >= 64 || tex_width == 16) {
- RADEON_COPY_MT(buffer, data,
- (int)(dwords * sizeof(u32)));
- } else if (tex_width < 16) {
- for (i = 0; i < tex->height; i++) {
- RADEON_COPY_MT(buffer, data, tex_width);
- buffer += 4;
- data += tex_width;
- }
- } else if (tex_width == 32) {
- /* TODO: make sure this works when not fitting in one buffer
- (i.e. 32bytes x 2048...) */
- for (i = 0; i < tex->height; i += 2) {
- RADEON_COPY_MT(buffer, data, 16);
- data += 16;
- RADEON_COPY_MT(buffer + 8, data, 16);
- data += 16;
- RADEON_COPY_MT(buffer + 4, data, 16);
- data += 16;
- RADEON_COPY_MT(buffer + 12, data, 16);
- data += 16;
- buffer += 16;
- }
- }
- } else {
- if (tex_width >= 32) {
- /* Texture image width is larger than the minimum, so we
- * can upload it directly.
- */
- RADEON_COPY_MT(buffer, data,
- (int)(dwords * sizeof(u32)));
- } else {
- /* Texture image width is less than the minimum, so we
- * need to pad out each image scanline to the minimum
- * width.
- */
- for (i = 0; i < tex->height; i++) {
- RADEON_COPY_MT(buffer, data, tex_width);
- buffer += 8;
- data += tex_width;
- }
- }
- }
-
-#undef RADEON_COPY_MT
- byte_offset = (image->y & ~2047) * blit_width;
- buf->file_priv = file_priv;
- buf->used = size;
- offset = dev_priv->gart_buffers_offset + buf->offset;
- BEGIN_RING(9);
- OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
- OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
- RADEON_GMC_DST_PITCH_OFFSET_CNTL |
- RADEON_GMC_BRUSH_NONE |
- (format << 8) |
- RADEON_GMC_SRC_DATATYPE_COLOR |
- RADEON_ROP3_S |
- RADEON_DP_SRC_SOURCE_MEMORY |
- RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
- OUT_RING((spitch << 22) | (offset >> 10));
- OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10)));
- OUT_RING(0);
- OUT_RING((image->x << 16) | (image->y % 2048));
- OUT_RING((image->width << 16) | height);
- RADEON_WAIT_UNTIL_2D_IDLE();
- ADVANCE_RING();
- COMMIT_RING();
-
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
-
- /* Update the input parameters for next time */
- image->y += height;
- image->height -= height;
- image->data = (const u8 __user *)image->data + size;
- } while (image->height > 0);
-
- /* Flush the pixel cache after the blit completes. This ensures
- * the texture data is written out to memory before rendering
- * continues.
- */
- BEGIN_RING(4);
- RADEON_FLUSH_CACHE();
- RADEON_WAIT_UNTIL_2D_IDLE();
- ADVANCE_RING();
- COMMIT_RING();
-
- return 0;
-}
-
-static void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(35);
-
- OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
- OUT_RING(0x00000000);
-
- OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
- for (i = 0; i < 32; i++) {
- OUT_RING(stipple[i]);
- }
-
- ADVANCE_RING();
-}
-
-static void radeon_apply_surface_regs(int surf_index,
- drm_radeon_private_t *dev_priv)
-{
- if (!dev_priv->mmio)
- return;
-
- radeon_do_cp_idle(dev_priv);
-
- RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
- dev_priv->surfaces[surf_index].flags);
- RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
- dev_priv->surfaces[surf_index].lower);
- RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
- dev_priv->surfaces[surf_index].upper);
-}
-
-/* Allocates a virtual surface
- * doesn't always allocate a real surface, will stretch an existing
- * surface when possible.
- *
- * Note that refcount can be at most 2, since during a free refcount=3
- * might mean we have to allocate a new surface which might not always
- * be available.
- * For example : we allocate three contiguous surfaces ABC. If B is
- * freed, we suddenly need two surfaces to store A and C, which might
- * not always be available.
- */
-static int alloc_surface(drm_radeon_surface_alloc_t *new,
- drm_radeon_private_t *dev_priv,
- struct drm_file *file_priv)
-{
- struct radeon_virt_surface *s;
- int i;
- int virt_surface_index;
- uint32_t new_upper, new_lower;
-
- new_lower = new->address;
- new_upper = new_lower + new->size - 1;
-
- /* sanity check */
- if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
- ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
- RADEON_SURF_ADDRESS_FIXED_MASK)
- || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
- return -1;
-
- /* make sure there is no overlap with existing surfaces */
- for (i = 0; i < RADEON_MAX_SURFACES; i++) {
- if ((dev_priv->surfaces[i].refcount != 0) &&
- (((new_lower >= dev_priv->surfaces[i].lower) &&
- (new_lower < dev_priv->surfaces[i].upper)) ||
- ((new_lower < dev_priv->surfaces[i].lower) &&
- (new_upper > dev_priv->surfaces[i].lower)))) {
- return -1;
- }
- }
-
- /* find a virtual surface */
- for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
- if (dev_priv->virt_surfaces[i].file_priv == NULL)
- break;
- if (i == 2 * RADEON_MAX_SURFACES) {
- return -1;
- }
- virt_surface_index = i;
-
- /* try to reuse an existing surface */
- for (i = 0; i < RADEON_MAX_SURFACES; i++) {
- /* extend before */
- if ((dev_priv->surfaces[i].refcount == 1) &&
- (new->flags == dev_priv->surfaces[i].flags) &&
- (new_upper + 1 == dev_priv->surfaces[i].lower)) {
- s = &(dev_priv->virt_surfaces[virt_surface_index]);
- s->surface_index = i;
- s->lower = new_lower;
- s->upper = new_upper;
- s->flags = new->flags;
- s->file_priv = file_priv;
- dev_priv->surfaces[i].refcount++;
- dev_priv->surfaces[i].lower = s->lower;
- radeon_apply_surface_regs(s->surface_index, dev_priv);
- return virt_surface_index;
- }
-
- /* extend after */
- if ((dev_priv->surfaces[i].refcount == 1) &&
- (new->flags == dev_priv->surfaces[i].flags) &&
- (new_lower == dev_priv->surfaces[i].upper + 1)) {
- s = &(dev_priv->virt_surfaces[virt_surface_index]);
- s->surface_index = i;
- s->lower = new_lower;
- s->upper = new_upper;
- s->flags = new->flags;
- s->file_priv = file_priv;
- dev_priv->surfaces[i].refcount++;
- dev_priv->surfaces[i].upper = s->upper;
- radeon_apply_surface_regs(s->surface_index, dev_priv);
- return virt_surface_index;
- }
- }
-
- /* okay, we need a new one */
- for (i = 0; i < RADEON_MAX_SURFACES; i++) {
- if (dev_priv->surfaces[i].refcount == 0) {
- s = &(dev_priv->virt_surfaces[virt_surface_index]);
- s->surface_index = i;
- s->lower = new_lower;
- s->upper = new_upper;
- s->flags = new->flags;
- s->file_priv = file_priv;
- dev_priv->surfaces[i].refcount = 1;
- dev_priv->surfaces[i].lower = s->lower;
- dev_priv->surfaces[i].upper = s->upper;
- dev_priv->surfaces[i].flags = s->flags;
- radeon_apply_surface_regs(s->surface_index, dev_priv);
- return virt_surface_index;
- }
- }
-
- /* we didn't find anything */
- return -1;
-}
-
-static int free_surface(struct drm_file *file_priv,
- drm_radeon_private_t * dev_priv,
- int lower)
-{
- struct radeon_virt_surface *s;
- int i;
- /* find the virtual surface */
- for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
- s = &(dev_priv->virt_surfaces[i]);
- if (s->file_priv) {
- if ((lower == s->lower) && (file_priv == s->file_priv))
- {
- if (dev_priv->surfaces[s->surface_index].
- lower == s->lower)
- dev_priv->surfaces[s->surface_index].
- lower = s->upper;
-
- if (dev_priv->surfaces[s->surface_index].
- upper == s->upper)
- dev_priv->surfaces[s->surface_index].
- upper = s->lower;
-
- dev_priv->surfaces[s->surface_index].refcount--;
- if (dev_priv->surfaces[s->surface_index].
- refcount == 0)
- dev_priv->surfaces[s->surface_index].
- flags = 0;
- s->file_priv = NULL;
- radeon_apply_surface_regs(s->surface_index,
- dev_priv);
- return 0;
- }
- }
- }
- return 1;
-}
-
-static void radeon_surfaces_release(struct drm_file *file_priv,
- drm_radeon_private_t * dev_priv)
-{
- int i;
- for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
- if (dev_priv->virt_surfaces[i].file_priv == file_priv)
- free_surface(file_priv, dev_priv,
- dev_priv->virt_surfaces[i].lower);
- }
-}
-
-/* ================================================================
- * IOCTL functions
- */
-static int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_surface_alloc_t *alloc = data;
-
- if (alloc_surface(alloc, dev_priv, file_priv) == -1)
- return -EINVAL;
- else
- return 0;
-}
-
-static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_surface_free_t *memfree = data;
-
- if (free_surface(file_priv, dev_priv, memfree->address))
- return -EINVAL;
- else
- return 0;
-}
-
-static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
- drm_radeon_clear_t *clear = data;
- drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
-
- if (copy_from_user(&depth_boxes, clear->depth_boxes,
- sarea_priv->nbox * sizeof(depth_boxes[0])))
- return -EFAULT;
-
- radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes);
-
- COMMIT_RING();
- return 0;
-}
-
-/* Not sure why this isn't set all the time:
- */
-static int radeon_do_init_pageflip(struct drm_device *dev, struct drm_master *master)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = master->driver_priv;
- RING_LOCALS;
-
- DRM_DEBUG("\n");
-
- BEGIN_RING(6);
- RADEON_WAIT_UNTIL_3D_IDLE();
- OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
- OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
- RADEON_CRTC_OFFSET_FLIP_CNTL);
- OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
- OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
- RADEON_CRTC_OFFSET_FLIP_CNTL);
- ADVANCE_RING();
-
- dev_priv->page_flipping = 1;
-
- if (master_priv->sarea_priv->pfCurrentPage != 1)
- master_priv->sarea_priv->pfCurrentPage = 0;
-
- return 0;
-}
-
-/* Swapping and flipping are different operations, need different ioctls.
- * They can & should be intermixed to support multiple 3d windows.
- */
-static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- if (!dev_priv->page_flipping)
- radeon_do_init_pageflip(dev, file_priv->master);
-
- radeon_cp_dispatch_flip(dev, file_priv->master);
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
-
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_cp_dispatch_swap(dev, file_priv);
- else
- radeon_cp_dispatch_swap(dev, file_priv->master);
- sarea_priv->ctx_owner = 0;
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_sarea_t *sarea_priv;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_radeon_vertex_t *vertex = data;
- drm_radeon_tcl_prim_t prim;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- sarea_priv = master_priv->sarea_priv;
-
- DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
- DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
-
- if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- vertex->idx, dma->buf_count - 1);
- return -EINVAL;
- }
- if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
- DRM_ERROR("buffer prim %d\n", vertex->prim);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf = dma->buflist[vertex->idx];
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex->idx);
- return -EINVAL;
- }
-
- /* Build up a prim_t record:
- */
- if (vertex->count) {
- buf->used = vertex->count; /* not used? */
-
- if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
- if (radeon_emit_state(dev_priv, file_priv,
- &sarea_priv->context_state,
- sarea_priv->tex_state,
- sarea_priv->dirty)) {
- DRM_ERROR("radeon_emit_state failed\n");
- return -EINVAL;
- }
-
- sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
- RADEON_UPLOAD_TEX1IMAGES |
- RADEON_UPLOAD_TEX2IMAGES |
- RADEON_REQUIRE_QUIESCENCE);
- }
-
- prim.start = 0;
- prim.finish = vertex->count; /* unused */
- prim.prim = vertex->prim;
- prim.numverts = vertex->count;
- prim.vc_format = sarea_priv->vc_format;
-
- radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim);
- }
-
- if (vertex->discard) {
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
- }
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_sarea_t *sarea_priv;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_radeon_indices_t *elts = data;
- drm_radeon_tcl_prim_t prim;
- int count;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- sarea_priv = master_priv->sarea_priv;
-
- DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
- DRM_CURRENTPID, elts->idx, elts->start, elts->end,
- elts->discard);
-
- if (elts->idx < 0 || elts->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- elts->idx, dma->buf_count - 1);
- return -EINVAL;
- }
- if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
- DRM_ERROR("buffer prim %d\n", elts->prim);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf = dma->buflist[elts->idx];
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", elts->idx);
- return -EINVAL;
- }
-
- count = (elts->end - elts->start) / sizeof(u16);
- elts->start -= RADEON_INDEX_PRIM_OFFSET;
-
- if (elts->start & 0x7) {
- DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
- return -EINVAL;
- }
- if (elts->start < buf->used) {
- DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
- return -EINVAL;
- }
-
- buf->used = elts->end;
-
- if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
- if (radeon_emit_state(dev_priv, file_priv,
- &sarea_priv->context_state,
- sarea_priv->tex_state,
- sarea_priv->dirty)) {
- DRM_ERROR("radeon_emit_state failed\n");
- return -EINVAL;
- }
-
- sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
- RADEON_UPLOAD_TEX1IMAGES |
- RADEON_UPLOAD_TEX2IMAGES |
- RADEON_REQUIRE_QUIESCENCE);
- }
-
- /* Build up a prim_t record:
- */
- prim.start = elts->start;
- prim.finish = elts->end;
- prim.prim = elts->prim;
- prim.offset = 0; /* offset from start of dma buffers */
- prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
- prim.vc_format = sarea_priv->vc_format;
-
- radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim);
- if (elts->discard) {
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
- }
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_texture_t *tex = data;
- drm_radeon_tex_image_t image;
- int ret;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (tex->image == NULL) {
- DRM_ERROR("null texture image!\n");
- return -EINVAL;
- }
-
- if (copy_from_user(&image,
- (drm_radeon_tex_image_t __user *) tex->image,
- sizeof(image)))
- return -EFAULT;
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image);
- else
- ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
-
- return ret;
-}
-
-static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_stipple_t *stipple = data;
- u32 mask[32];
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (copy_from_user(&mask, stipple->mask, 32 * sizeof(u32)))
- return -EFAULT;
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- radeon_cp_dispatch_stipple(dev, mask);
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_radeon_indirect_t *indirect = data;
- RING_LOCALS;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
- indirect->idx, indirect->start, indirect->end,
- indirect->discard);
-
- if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- indirect->idx, dma->buf_count - 1);
- return -EINVAL;
- }
-
- buf = dma->buflist[indirect->idx];
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", indirect->idx);
- return -EINVAL;
- }
-
- if (indirect->start < buf->used) {
- DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
- indirect->start, buf->used);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf->used = indirect->end;
-
- /* Dispatch the indirect buffer full of commands from the
- * X server. This is insecure and is thus only available to
- * privileged clients.
- */
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
- else {
- /* Wait for the 3D stream to idle before the indirect buffer
- * containing 2D acceleration commands is processed.
- */
- BEGIN_RING(2);
- RADEON_WAIT_UNTIL_3D_IDLE();
- ADVANCE_RING();
- radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
- }
-
- if (indirect->discard) {
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
- }
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_sarea_t *sarea_priv;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_radeon_vertex2_t *vertex = data;
- int i;
- unsigned char laststate;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- sarea_priv = master_priv->sarea_priv;
-
- DRM_DEBUG("pid=%d index=%d discard=%d\n",
- DRM_CURRENTPID, vertex->idx, vertex->discard);
-
- if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- vertex->idx, dma->buf_count - 1);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf = dma->buflist[vertex->idx];
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->file_priv);
- return -EINVAL;
- }
-
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex->idx);
- return -EINVAL;
- }
-
- if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
- return -EINVAL;
-
- for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) {
- drm_radeon_prim_t prim;
- drm_radeon_tcl_prim_t tclprim;
-
- if (copy_from_user(&prim, &vertex->prim[i], sizeof(prim)))
- return -EFAULT;
-
- if (prim.stateidx != laststate) {
- drm_radeon_state_t state;
-
- if (copy_from_user(&state,
- &vertex->state[prim.stateidx],
- sizeof(state)))
- return -EFAULT;
-
- if (radeon_emit_state2(dev_priv, file_priv, &state)) {
- DRM_ERROR("radeon_emit_state2 failed\n");
- return -EINVAL;
- }
-
- laststate = prim.stateidx;
- }
-
- tclprim.start = prim.start;
- tclprim.finish = prim.finish;
- tclprim.prim = prim.prim;
- tclprim.vc_format = prim.vc_format;
-
- if (prim.prim & RADEON_PRIM_WALK_IND) {
- tclprim.offset = prim.numverts * 64;
- tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
-
- radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim);
- } else {
- tclprim.numverts = prim.numverts;
- tclprim.offset = 0; /* not used */
-
- radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim);
- }
-
- if (sarea_priv->nbox == 1)
- sarea_priv->nbox = 0;
- }
-
- if (vertex->discard) {
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
- }
-
- COMMIT_RING();
- return 0;
-}
-
-static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
- struct drm_file *file_priv,
- drm_radeon_cmd_header_t header,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- int id = (int)header.packet.packet_id;
- int sz, reg;
- RING_LOCALS;
-
- if (id >= RADEON_MAX_STATE_PACKETS)
- return -EINVAL;
-
- sz = packet[id].len;
- reg = packet[id].start;
-
- if (sz * sizeof(u32) > drm_buffer_unprocessed(cmdbuf->buffer)) {
- DRM_ERROR("Packet size provided larger than data provided\n");
- return -EINVAL;
- }
-
- if (radeon_check_and_fixup_packets(dev_priv, file_priv, id,
- cmdbuf->buffer)) {
- DRM_ERROR("Packet verification failed\n");
- return -EINVAL;
- }
-
- BEGIN_RING(sz + 1);
- OUT_RING(CP_PACKET0(reg, (sz - 1)));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
-
- return 0;
-}
-
-static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
- drm_radeon_cmd_header_t header,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- int sz = header.scalars.count;
- int start = header.scalars.offset;
- int stride = header.scalars.stride;
- RING_LOCALS;
-
- BEGIN_RING(3 + sz);
- OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
- OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
- OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
- return 0;
-}
-
-/* God this is ugly
- */
-static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
- drm_radeon_cmd_header_t header,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- int sz = header.scalars.count;
- int start = ((unsigned int)header.scalars.offset) + 0x100;
- int stride = header.scalars.stride;
- RING_LOCALS;
-
- BEGIN_RING(3 + sz);
- OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
- OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
- OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
- return 0;
-}
-
-static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
- drm_radeon_cmd_header_t header,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- int sz = header.vectors.count;
- int start = header.vectors.offset;
- int stride = header.vectors.stride;
- RING_LOCALS;
-
- BEGIN_RING(5 + sz);
- OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
- OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
- OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
- OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
-
- return 0;
-}
-
-static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
- drm_radeon_cmd_header_t header,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- int sz = header.veclinear.count * 4;
- int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
- RING_LOCALS;
-
- if (!sz)
- return 0;
- if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
- return -EINVAL;
-
- BEGIN_RING(5 + sz);
- OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
- OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
- OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
- OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
- ADVANCE_RING();
-
- return 0;
-}
-
-static int radeon_emit_packet3(struct drm_device * dev,
- struct drm_file *file_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- unsigned int cmdsz;
- int ret;
- RING_LOCALS;
-
- DRM_DEBUG("\n");
-
- if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
- cmdbuf, &cmdsz))) {
- DRM_ERROR("Packet verification failed\n");
- return ret;
- }
-
- BEGIN_RING(cmdsz);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz);
- ADVANCE_RING();
-
- return 0;
-}
-
-static int radeon_emit_packet3_cliprect(struct drm_device *dev,
- struct drm_file *file_priv,
- drm_radeon_kcmd_buffer_t *cmdbuf,
- int orig_nbox)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_clip_rect box;
- unsigned int cmdsz;
- int ret;
- struct drm_clip_rect __user *boxes = cmdbuf->boxes;
- int i = 0;
- RING_LOCALS;
-
- DRM_DEBUG("\n");
-
- if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
- cmdbuf, &cmdsz))) {
- DRM_ERROR("Packet verification failed\n");
- return ret;
- }
-
- if (!orig_nbox)
- goto out;
-
- do {
- if (i < cmdbuf->nbox) {
- if (copy_from_user(&box, &boxes[i], sizeof(box)))
- return -EFAULT;
- /* FIXME The second and subsequent times round
- * this loop, send a WAIT_UNTIL_3D_IDLE before
- * calling emit_clip_rect(). This fixes a
- * lockup on fast machines when sending
- * several cliprects with a cmdbuf, as when
- * waving a 2D window over a 3D
- * window. Something in the commands from user
- * space seems to hang the card when they're
- * sent several times in a row. That would be
- * the correct place to fix it but this works
- * around it until I can figure that out - Tim
- * Smith */
- if (i) {
- BEGIN_RING(2);
- RADEON_WAIT_UNTIL_3D_IDLE();
- ADVANCE_RING();
- }
- radeon_emit_clip_rect(dev_priv, &box);
- }
-
- BEGIN_RING(cmdsz);
- OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz);
- ADVANCE_RING();
-
- } while (++i < cmdbuf->nbox);
- if (cmdbuf->nbox == 1)
- cmdbuf->nbox = 0;
-
- return 0;
- out:
- drm_buffer_advance(cmdbuf->buffer, cmdsz * 4);
- return 0;
-}
-
-static int radeon_emit_wait(struct drm_device * dev, int flags)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
-
- DRM_DEBUG("%x\n", flags);
- switch (flags) {
- case RADEON_WAIT_2D:
- BEGIN_RING(2);
- RADEON_WAIT_UNTIL_2D_IDLE();
- ADVANCE_RING();
- break;
- case RADEON_WAIT_3D:
- BEGIN_RING(2);
- RADEON_WAIT_UNTIL_3D_IDLE();
- ADVANCE_RING();
- break;
- case RADEON_WAIT_2D | RADEON_WAIT_3D:
- BEGIN_RING(2);
- RADEON_WAIT_UNTIL_IDLE();
- ADVANCE_RING();
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int radeon_cp_cmdbuf(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf = NULL;
- drm_radeon_cmd_header_t stack_header;
- int idx;
- drm_radeon_kcmd_buffer_t *cmdbuf = data;
- int orig_nbox;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) {
- return -EINVAL;
- }
-
- /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
- * races between checking values and using those values in other code,
- * and simply to avoid a lot of function calls to copy in data.
- */
- if (cmdbuf->bufsz != 0) {
- int rv;
- void __user *buffer = cmdbuf->buffer;
- rv = drm_buffer_alloc(&cmdbuf->buffer, cmdbuf->bufsz);
- if (rv)
- return rv;
- rv = drm_buffer_copy_from_user(cmdbuf->buffer, buffer,
- cmdbuf->bufsz);
- if (rv) {
- drm_buffer_free(cmdbuf->buffer);
- return rv;
- }
- } else
- goto done;
-
- orig_nbox = cmdbuf->nbox;
-
- if (dev_priv->microcode_version == UCODE_R300) {
- int temp;
- temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
-
- drm_buffer_free(cmdbuf->buffer);
-
- return temp;
- }
-
- /* microcode_version != r300 */
- while (drm_buffer_unprocessed(cmdbuf->buffer) >= sizeof(stack_header)) {
-
- drm_radeon_cmd_header_t *header;
- header = drm_buffer_read_object(cmdbuf->buffer,
- sizeof(stack_header), &stack_header);
-
- switch (header->header.cmd_type) {
- case RADEON_CMD_PACKET:
- DRM_DEBUG("RADEON_CMD_PACKET\n");
- if (radeon_emit_packets
- (dev_priv, file_priv, *header, cmdbuf)) {
- DRM_ERROR("radeon_emit_packets failed\n");
- goto err;
- }
- break;
-
- case RADEON_CMD_SCALARS:
- DRM_DEBUG("RADEON_CMD_SCALARS\n");
- if (radeon_emit_scalars(dev_priv, *header, cmdbuf)) {
- DRM_ERROR("radeon_emit_scalars failed\n");
- goto err;
- }
- break;
-
- case RADEON_CMD_VECTORS:
- DRM_DEBUG("RADEON_CMD_VECTORS\n");
- if (radeon_emit_vectors(dev_priv, *header, cmdbuf)) {
- DRM_ERROR("radeon_emit_vectors failed\n");
- goto err;
- }
- break;
-
- case RADEON_CMD_DMA_DISCARD:
- DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
- idx = header->dma.buf_idx;
- if (idx < 0 || idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- idx, dma->buf_count - 1);
- goto err;
- }
-
- buf = dma->buflist[idx];
- if (buf->file_priv != file_priv || buf->pending) {
- DRM_ERROR("bad buffer %p %p %d\n",
- buf->file_priv, file_priv,
- buf->pending);
- goto err;
- }
-
- radeon_cp_discard_buffer(dev, file_priv->master, buf);
- break;
-
- case RADEON_CMD_PACKET3:
- DRM_DEBUG("RADEON_CMD_PACKET3\n");
- if (radeon_emit_packet3(dev, file_priv, cmdbuf)) {
- DRM_ERROR("radeon_emit_packet3 failed\n");
- goto err;
- }
- break;
-
- case RADEON_CMD_PACKET3_CLIP:
- DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
- if (radeon_emit_packet3_cliprect
- (dev, file_priv, cmdbuf, orig_nbox)) {
- DRM_ERROR("radeon_emit_packet3_clip failed\n");
- goto err;
- }
- break;
-
- case RADEON_CMD_SCALARS2:
- DRM_DEBUG("RADEON_CMD_SCALARS2\n");
- if (radeon_emit_scalars2(dev_priv, *header, cmdbuf)) {
- DRM_ERROR("radeon_emit_scalars2 failed\n");
- goto err;
- }
- break;
-
- case RADEON_CMD_WAIT:
- DRM_DEBUG("RADEON_CMD_WAIT\n");
- if (radeon_emit_wait(dev, header->wait.flags)) {
- DRM_ERROR("radeon_emit_wait failed\n");
- goto err;
- }
- break;
- case RADEON_CMD_VECLINEAR:
- DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
- if (radeon_emit_veclinear(dev_priv, *header, cmdbuf)) {
- DRM_ERROR("radeon_emit_veclinear failed\n");
- goto err;
- }
- break;
-
- default:
- DRM_ERROR("bad cmd_type %d at byte %d\n",
- header->header.cmd_type,
- cmdbuf->buffer->iterator);
- goto err;
- }
- }
-
- drm_buffer_free(cmdbuf->buffer);
-
- done:
- DRM_DEBUG("DONE\n");
- COMMIT_RING();
- return 0;
-
- err:
- drm_buffer_free(cmdbuf->buffer);
- return -EINVAL;
-}
-
-static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_getparam_t *param = data;
- int value;
-
- DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
-
- switch (param->param) {
- case RADEON_PARAM_GART_BUFFER_OFFSET:
- value = dev_priv->gart_buffers_offset;
- break;
- case RADEON_PARAM_LAST_FRAME:
- dev_priv->stats.last_frame_reads++;
- value = GET_SCRATCH(dev_priv, 0);
- break;
- case RADEON_PARAM_LAST_DISPATCH:
- value = GET_SCRATCH(dev_priv, 1);
- break;
- case RADEON_PARAM_LAST_CLEAR:
- dev_priv->stats.last_clear_reads++;
- value = GET_SCRATCH(dev_priv, 2);
- break;
- case RADEON_PARAM_IRQ_NR:
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- value = 0;
- else
- value = dev->pdev->irq;
- break;
- case RADEON_PARAM_GART_BASE:
- value = dev_priv->gart_vm_start;
- break;
- case RADEON_PARAM_REGISTER_HANDLE:
- value = dev_priv->mmio->offset;
- break;
- case RADEON_PARAM_STATUS_HANDLE:
- value = dev_priv->ring_rptr_offset;
- break;
-#if BITS_PER_LONG == 32
- /*
- * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
- * pointer which can't fit into an int-sized variable. According to
- * Michel Dänzer, the ioctl() is only used on embedded platforms, so
- * not supporting it shouldn't be a problem. If the same functionality
- * is needed on 64-bit platforms, a new ioctl() would have to be added,
- * so backwards-compatibility for the embedded platforms can be
- * maintained. --davidm 4-Feb-2004.
- */
- case RADEON_PARAM_SAREA_HANDLE:
- /* The lock is the first dword in the sarea. */
- /* no users of this parameter */
- break;
-#endif
- case RADEON_PARAM_GART_TEX_HANDLE:
- value = dev_priv->gart_textures_offset;
- break;
- case RADEON_PARAM_SCRATCH_OFFSET:
- if (!dev_priv->writeback_works)
- return -EINVAL;
- if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
- value = R600_SCRATCH_REG_OFFSET;
- else
- value = RADEON_SCRATCH_REG_OFFSET;
- break;
- case RADEON_PARAM_CARD_TYPE:
- if (dev_priv->flags & RADEON_IS_PCIE)
- value = RADEON_CARD_PCIE;
- else if (dev_priv->flags & RADEON_IS_AGP)
- value = RADEON_CARD_AGP;
- else
- value = RADEON_CARD_PCI;
- break;
- case RADEON_PARAM_VBLANK_CRTC:
- value = radeon_vblank_crtc_get(dev);
- break;
- case RADEON_PARAM_FB_LOCATION:
- value = radeon_read_fb_location(dev_priv);
- break;
- case RADEON_PARAM_NUM_GB_PIPES:
- value = dev_priv->num_gb_pipes;
- break;
- case RADEON_PARAM_NUM_Z_PIPES:
- value = dev_priv->num_z_pipes;
- break;
- default:
- DRM_DEBUG("Invalid parameter %d\n", param->param);
- return -EINVAL;
- }
-
- if (copy_to_user(param->value, &value, sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
- drm_radeon_setparam_t *sp = data;
- struct drm_radeon_driver_file_fields *radeon_priv;
-
- switch (sp->param) {
- case RADEON_SETPARAM_FB_LOCATION:
- radeon_priv = file_priv->driver_priv;
- radeon_priv->radeon_fb_delta = dev_priv->fb_location -
- sp->value;
- break;
- case RADEON_SETPARAM_SWITCH_TILING:
- if (sp->value == 0) {
- DRM_DEBUG("color tiling disabled\n");
- dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
- dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->tiling_enabled = 0;
- } else if (sp->value == 1) {
- DRM_DEBUG("color tiling enabled\n");
- dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
- dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->tiling_enabled = 1;
- }
- break;
- case RADEON_SETPARAM_PCIGART_LOCATION:
- dev_priv->pcigart_offset = sp->value;
- dev_priv->pcigart_offset_set = 1;
- break;
- case RADEON_SETPARAM_NEW_MEMMAP:
- dev_priv->new_memmap = sp->value;
- break;
- case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
- dev_priv->gart_info.table_size = sp->value;
- if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
- dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
- break;
- case RADEON_SETPARAM_VBLANK_CRTC:
- return radeon_vblank_crtc_set(dev, sp->value);
- break;
- default:
- DRM_DEBUG("Invalid parameter %d\n", sp->param);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* When a client dies:
- * - Check for and clean up flipped page state
- * - Free any alloced GART memory.
- * - Free any alloced radeon surfaces.
- *
- * DRM infrastructure takes care of reclaiming dma buffers.
- */
-void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
-{
- if (dev->dev_private) {
- drm_radeon_private_t *dev_priv = dev->dev_private;
- dev_priv->page_flipping = 0;
- radeon_mem_release(file_priv, dev_priv->gart_heap);
- radeon_mem_release(file_priv, dev_priv->fb_heap);
- radeon_surfaces_release(file_priv, dev_priv);
- }
-}
-
-void radeon_driver_lastclose(struct drm_device *dev)
-{
- radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private);
- radeon_do_release(dev);
-}
-
-int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_radeon_driver_file_fields *radeon_priv;
-
- DRM_DEBUG("\n");
- radeon_priv = kmalloc(sizeof(*radeon_priv), GFP_KERNEL);
-
- if (!radeon_priv)
- return -ENOMEM;
-
- file_priv->driver_priv = radeon_priv;
-
- if (dev_priv)
- radeon_priv->radeon_fb_delta = dev_priv->fb_location;
- else
- radeon_priv->radeon_fb_delta = 0;
- return 0;
-}
-
-void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
-{
- struct drm_radeon_driver_file_fields *radeon_priv =
- file_priv->driver_priv;
-
- kfree(radeon_priv);
-}
-
-struct drm_ioctl_desc radeon_ioctls[] = {
- DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH)
-};
-
-int radeon_max_ioctl = ARRAY_SIZE(radeon_ioctls);
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index 48d97c040f49..3979632b9225 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -455,15 +455,15 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
if (soffset) {
/* make sure object fit at this offset */
- eoffset = soffset + size;
+ eoffset = soffset + size - 1;
if (soffset >= eoffset) {
r = -EINVAL;
goto error_unreserve;
}
last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
- if (last_pfn > rdev->vm_manager.max_pfn) {
- dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
+ if (last_pfn >= rdev->vm_manager.max_pfn) {
+ dev_err(rdev->dev, "va above limit (0x%08X >= 0x%08X)\n",
last_pfn, rdev->vm_manager.max_pfn);
r = -EINVAL;
goto error_unreserve;
@@ -478,7 +478,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
eoffset /= RADEON_GPU_PAGE_SIZE;
if (soffset || eoffset) {
struct interval_tree_node *it;
- it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1);
+ it = interval_tree_iter_first(&vm->va, soffset, eoffset);
if (it && it != &bo_va->it) {
struct radeon_bo_va *tmp;
tmp = container_of(it, struct radeon_bo_va, it);
@@ -518,7 +518,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
if (soffset || eoffset) {
spin_lock(&vm->status_lock);
bo_va->it.start = soffset;
- bo_va->it.last = eoffset - 1;
+ bo_va->it.last = eoffset;
list_add(&bo_va->vm_status, &vm->cleared);
spin_unlock(&vm->status_lock);
interval_tree_insert(&bo_va->it, &vm->va);
@@ -888,7 +888,7 @@ static void radeon_vm_fence_pts(struct radeon_vm *vm,
unsigned i;
start >>= radeon_vm_block_size;
- end >>= radeon_vm_block_size;
+ end = (end - 1) >> radeon_vm_block_size;
for (i = start; i <= end; ++i)
radeon_bo_fence(vm->page_tables[i].bo, fence, true);
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 4c4a7218a3bd..d1a7b58dd291 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -915,6 +915,11 @@
#define DCCG_AUDIO_DTO1_PHASE 0x05c0
#define DCCG_AUDIO_DTO1_MODULE 0x05c4
+#define DENTIST_DISPCLK_CNTL 0x0490
+# define DENTIST_DPREFCLK_WDIVIDER(x) (((x) & 0x7f) << 24)
+# define DENTIST_DPREFCLK_WDIVIDER_MASK (0x7f << 24)
+# define DENTIST_DPREFCLK_WDIVIDER_SHIFT 24
+
#define AFMT_AUDIO_SRC_CONTROL 0x713c
#define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0)
/* AFMT_AUDIO_SRC_SELECT
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 48cb19949ca3..88a4b706be16 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -613,7 +613,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc,
&rgrp->planes[index % 2].plane,
- NULL, &crtc_funcs);
+ NULL, &crtc_funcs, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index d0ae1e8009c6..c08700757feb 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -173,7 +173,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
goto done;
} else {
ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
- encoder_type);
+ encoder_type, NULL);
if (ret < 0)
goto done;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
index 96f2eb43713c..a37b6e2fe51a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
@@ -28,7 +28,7 @@ static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct rcar_du_connector *con = to_rcar_connector(connector);
struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
if (sfuncs->get_modes == NULL)
return 0;
@@ -41,7 +41,7 @@ static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector,
{
struct rcar_du_connector *con = to_rcar_connector(connector);
struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
if (sfuncs->mode_valid == NULL)
return MODE_OK;
@@ -66,7 +66,7 @@ rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
struct rcar_du_connector *con = to_rcar_connector(connector);
struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
if (sfuncs->detect == NULL)
return connector_status_unknown;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index 81da8419282b..2567efcbee36 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -35,7 +35,7 @@ struct rcar_du_hdmienc {
static void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
{
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
if (sfuncs->dpms)
sfuncs->dpms(encoder, DRM_MODE_DPMS_OFF);
@@ -50,7 +50,7 @@ static void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
static void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
{
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
if (hdmienc->renc->lvds)
rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
@@ -67,7 +67,7 @@ static int rcar_du_hdmienc_atomic_check(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
const struct drm_display_mode *mode = &crtc_state->mode;
@@ -89,7 +89,7 @@ static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
- struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
if (sfuncs->mode_set)
sfuncs->mode_set(encoder, mode, adjusted_mode);
@@ -151,7 +151,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
goto error;
ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
if (ret < 0)
goto error;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index ca12e8ca5552..43bce69d8560 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -136,7 +136,7 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
static struct drm_framebuffer *
rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct rcar_du_device *rcdu = dev->dev_private;
const struct rcar_du_format_info *format;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index ffa583712cd9..c3ed9522c0e1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -410,7 +410,8 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
&rcar_du_plane_funcs, formats,
- ARRAY_SIZE(formats), type);
+ ARRAY_SIZE(formats), type,
+ NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 35215f6867d3..85739859dffc 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -25,3 +25,13 @@ config ROCKCHIP_DW_HDMI
for the Synopsys DesignWare HDMI driver. If you want to
enable HDMI on RK3288 based SoC, you should selet this
option.
+
+config ROCKCHIP_DW_MIPI_DSI
+ tristate "Rockchip specific extensions for Synopsys DW MIPI DSI"
+ depends on DRM_ROCKCHIP
+ select DRM_MIPI_DSI
+ help
+ This selects support for Rockchip SoC specific extensions
+ for the Synopsys DesignWare HDMI driver. If you want to
+ enable MIPI DSI on RK3288 based SoC, you should selet this
+ option.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index f3d8a19c641f..d1dc0f7b01db 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -6,5 +6,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchip_drm_gem.o
obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
+obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
-obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o
+obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o \
+ rockchip_vop_reg.o
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
new file mode 100644
index 000000000000..7bfe243c6173
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -0,0 +1,1194 @@
+/*
+ * 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/regmap.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 GRF_SOC_CON6 0x025c
+#define DSI0_SEL_VOP_LIT (1 << 6)
+#define DSI1_SEL_VOP_LIT (1 << 9)
+
+#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_BURST_SYNC_PULSES 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)
+
+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 {
+ unsigned int max_data_lanes;
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+};
+
+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 *pllref_clk;
+ struct clk *pclk;
+
+ unsigned int lane_mbps; /* per lane */
+ u32 channel;
+ u32 lanes;
+ u32 format;
+ u16 input_div;
+ u16 feedback_div;
+ struct drm_display_mode *mode;
+
+ 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 dw_mipi_dsi *dsi)
+{
+ int refresh, two_frames;
+
+ refresh = drm_mode_vrefresh(dsi->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);
+}
+
+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) {
+ dev_err(dsi->dev,
+ "failed to get testdin for %dmbps lane clock\n",
+ dsi->lane_mbps);
+ return testdin;
+ }
+
+ dsi_write(dsi, DSI_PWR_UP, POWERUP);
+
+ 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, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
+ 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, 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, 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, 0x70, TLP_PROGRAM_EN | 0xf);
+ dw_mipi_dsi_phy_write(dsi, 0x71, THS_PRE_PROGRAM_EN | 0x55);
+ dw_mipi_dsi_phy_write(dsi, 0x72, THS_ZERO_PROGRAM_EN | 0xa);
+
+ dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
+ PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
+
+
+ ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
+ val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to wait for phy lock state\n");
+ return ret;
+ }
+
+ ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
+ val, val & STOP_STATE_CLK_LANE, 1000,
+ PHY_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(dsi->dev,
+ "failed to wait for phy clk lane stop state\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi)
+{
+ unsigned int bpp, 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;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ if (bpp < 0) {
+ dev_err(dsi->dev, "failed to get bpp for pixel format %d\n",
+ dsi->format);
+ return bpp;
+ }
+
+ mpclk = DIV_ROUND_UP(dsi->mode->clock, MSEC_PER_SEC);
+ if (mpclk) {
+ /* take 1 / 0.9, since mbps must big than bandwidth of RGB */
+ tmp = mpclk * (bpp / dsi->lanes) * 10 / 9;
+ if (tmp < max_mbps)
+ target_mbps = tmp;
+ else
+ dev_err(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;
+
+ for (i = 1; i < 6; 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) {
+ dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
+ device->lanes);
+ return -EINVAL;
+ }
+
+ if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ||
+ !(device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) {
+ dev_err(dsi->dev, "device mode is unsupported\n");
+ return -EINVAL;
+ }
+
+ dsi->lanes = device->lanes;
+ dsi->channel = device->channel;
+ dsi->format = device->format;
+ dsi->panel = of_drm_find_panel(device->dev.of_node);
+ if (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 int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val)
+{
+ int ret;
+
+ ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS,
+ val, !(val & GEN_CMD_FULL), 1000,
+ CMD_PKT_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to get available command FIFO\n");
+ return ret;
+ }
+
+ dsi_write(dsi, DSI_GEN_HDR, val);
+
+ ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS,
+ val, val & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY),
+ 1000, CMD_PKT_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(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 u16 *tx_buf = msg->tx_buf;
+ u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type);
+
+ if (msg->tx_len > 2) {
+ dev_err(dsi->dev, "too long tx buf length %zu for short write\n",
+ msg->tx_len);
+ return -EINVAL;
+ }
+
+ 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 u32 *tx_buf = msg->tx_buf;
+ int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret;
+ u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
+ u32 remainder = 0;
+
+ if (msg->tx_len < 3) {
+ dev_err(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) {
+ memcpy(&remainder, tx_buf, len);
+ dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
+ len = 0;
+ } else {
+ dsi_write(dsi, DSI_GEN_PLD_DATA, *tx_buf);
+ tx_buf++;
+ len -= pld_data_bytes;
+ }
+
+ ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS,
+ val, !(val & GEN_PLD_W_FULL), 1000,
+ CMD_PKT_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(dsi->dev,
+ "failed to get available write payload FIFO\n");
+ return ret;
+ }
+ }
+
+ return dw_mipi_dsi_gen_pkt_hdr_write(dsi, 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;
+
+ 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:
+ dev_err(dsi->dev, "unsupported message type\n");
+ 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 = VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER;
+
+ 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_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)
+{
+ 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(7));
+ dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
+}
+
+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_PVSYNC))
+ val |= VSYNC_ACTIVE_LOW;
+ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
+ 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_CMD_MODE_CFG, CMD_MODE_ALL_LP);
+ 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,
+ u32 hcomponent)
+{
+ u32 frac, lbcc;
+
+ lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
+
+ frac = lbcc % dsi->mode->clock;
+ lbcc = lbcc / dsi->mode->clock;
+ if (frac)
+ lbcc++;
+
+ return lbcc;
+}
+
+static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi)
+{
+ u32 htotal, hsa, hbp, lbcc;
+ struct drm_display_mode *mode = dsi->mode;
+
+ htotal = mode->htotal;
+ hsa = mode->hsync_end - mode->hsync_start;
+ hbp = mode->htotal - mode->hsync_end;
+
+ lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, htotal);
+ dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc);
+
+ lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, hsa);
+ dsi_write(dsi, DSI_VID_HSA_TIME, lbcc);
+
+ lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, hbp);
+ dsi_write(dsi, DSI_VID_HBP_TIME, lbcc);
+}
+
+static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi)
+{
+ u32 vactive, vsa, vfp, vbp;
+ struct drm_display_mode *mode = dsi->mode;
+
+ 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_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ int ret;
+
+ dsi->mode = adjusted_mode;
+
+ ret = dw_mipi_dsi_get_lane_bps(dsi);
+ if (ret < 0)
+ return;
+
+ if (clk_prepare_enable(dsi->pclk)) {
+ dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
+ return;
+ }
+
+ 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);
+ dw_mipi_dsi_vertical_timing_config(dsi);
+ dw_mipi_dsi_dphy_timing_config(dsi);
+ dw_mipi_dsi_dphy_interface_config(dsi);
+ dw_mipi_dsi_clear_err(dsi);
+ if (drm_panel_prepare(dsi->panel))
+ dev_err(dsi->dev, "failed to prepare panel\n");
+
+ clk_disable_unprepare(dsi->pclk);
+}
+
+static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+
+ drm_panel_disable(dsi->panel);
+
+ if (clk_prepare_enable(dsi->pclk)) {
+ dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
+ return;
+ }
+
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+ drm_panel_unprepare(dsi->panel);
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+
+ /*
+ * This is necessary to make sure the peripheral will be driven
+ * normally when the display is enabled again later.
+ */
+ msleep(120);
+
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+ dw_mipi_dsi_disable(dsi);
+ clk_disable_unprepare(dsi->pclk);
+}
+
+static bool dw_mipi_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
+{
+ struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ int mux = rockchip_drm_encoder_get_mux_id(dsi->dev->of_node, encoder);
+ u32 interface_pix_fmt;
+ u32 val;
+
+ if (clk_prepare_enable(dsi->pclk)) {
+ dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
+ return;
+ }
+
+ dw_mipi_dsi_phy_init(dsi);
+ dw_mipi_dsi_wait_for_two_frames(dsi);
+
+ dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+ drm_panel_enable(dsi->panel);
+
+ clk_disable_unprepare(dsi->pclk);
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ interface_pix_fmt = ROCKCHIP_OUT_MODE_P888;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ interface_pix_fmt = ROCKCHIP_OUT_MODE_P666;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ interface_pix_fmt = ROCKCHIP_OUT_MODE_P565;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_DSI,
+ interface_pix_fmt);
+
+ if (mux)
+ val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
+ else
+ val = DSI0_SEL_VOP_LIT << 16;
+
+ regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
+ dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
+}
+
+static struct drm_encoder_helper_funcs
+dw_mipi_dsi_encoder_helper_funcs = {
+ .mode_fixup = dw_mipi_dsi_encoder_mode_fixup,
+ .commit = dw_mipi_dsi_encoder_commit,
+ .mode_set = dw_mipi_dsi_encoder_mode_set,
+ .disable = dw_mipi_dsi_encoder_disable,
+};
+
+static 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 enum drm_mode_status dw_mipi_dsi_mode_valid(
+ struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_mipi_dsi *dsi = con_to_dsi(connector);
+
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (dsi->pdata->mode_valid)
+ mode_status = dsi->pdata->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
+static struct drm_encoder *dw_mipi_dsi_connector_best_encoder(
+ struct drm_connector *connector)
+{
+ struct dw_mipi_dsi *dsi = con_to_dsi(connector);
+
+ return &dsi->encoder;
+}
+
+static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
+ .get_modes = dw_mipi_dsi_connector_get_modes,
+ .mode_valid = dw_mipi_dsi_mode_valid,
+ .best_encoder = dw_mipi_dsi_connector_best_encoder,
+};
+
+static enum drm_connector_status
+dw_mipi_dsi_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dw_mipi_dsi_detect,
+ .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) {
+ dev_err(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_mode_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)) {
+ dev_err(dsi->dev, "Unable to get rockchip,grf\n");
+ return PTR_ERR(dsi->grf_regmap);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
+ struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /*
+ * The VID_PKT_SIZE field in the DSI_VID_PKT_CFG
+ * register is 11-bit.
+ */
+ if (mode->hdisplay > 0x7ff)
+ return MODE_BAD_HVALUE;
+
+ /*
+ * The V_ACTIVE_LINES field in the DSI_VTIMING_CFG
+ * register is 11-bit.
+ */
+ if (mode->vdisplay > 0x7ff)
+ return MODE_BAD_VVALUE;
+
+ return MODE_OK;
+}
+
+static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
+ .max_data_lanes = 4,
+ .mode_valid = rk3288_mipi_dsi_mode_valid,
+};
+
+static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
+ {
+ .compatible = "rockchip,rk3288-mipi-dsi",
+ .data = &rk3288_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 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;
+
+ ret = rockchip_mipi_parse_dt(dsi);
+ if (ret)
+ return ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ 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);
+ dev_err(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);
+ dev_err(dev, "Unable to get pclk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dsi->pllref_clk);
+ if (ret) {
+ dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
+ return ret;
+ }
+
+ ret = dw_mipi_dsi_register(drm, dsi);
+ if (ret) {
+ dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
+ goto err_pllref;
+ }
+
+ dev_set_drvdata(dev, dsi);
+
+ dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
+ dsi->dsi_host.dev = dev;
+ return mipi_dsi_host_register(&dsi->dsi_host);
+
+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);
+ 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;
+}
+
+static 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,
+ },
+};
+module_platform_driver(dw_mipi_dsi_driver);
+
+MODULE_DESCRIPTION("ROCKCHIP MIPI DSI host controller driver");
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 80d6fc8a5cee..c65ce8cb30d3 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -173,7 +173,7 @@ dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
return (valid) ? MODE_OK : MODE_BAD;
}
-static struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
+static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
@@ -195,12 +195,15 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
{
}
-static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
{
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
u32 val;
int mux;
+ rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
+ ROCKCHIP_OUT_MODE_AAAA);
+
mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
if (mux)
val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
@@ -212,17 +215,10 @@ static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
(mux) ? "LIT" : "BIG");
}
-static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
-{
- rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
- ROCKCHIP_OUT_MODE_AAAA);
-}
-
-static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
.mode_set = dw_hdmi_rockchip_encoder_mode_set,
- .prepare = dw_hdmi_rockchip_encoder_prepare,
- .commit = dw_hdmi_rockchip_encoder_commit,
+ .enable = dw_hdmi_rockchip_encoder_enable,
.disable = dw_hdmi_rockchip_encoder_disable,
};
@@ -295,7 +291,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
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);
+ DRM_MODE_ENCODER_TMDS, NULL);
return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index f22e1e1ee64a..8397d1b62ef9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -64,11 +64,11 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
}
EXPORT_SYMBOL_GPL(rockchip_drm_dma_detach_device);
-int rockchip_register_crtc_funcs(struct drm_device *dev,
- const struct rockchip_crtc_funcs *crtc_funcs,
- int pipe)
+int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
+ const struct rockchip_crtc_funcs *crtc_funcs)
{
- struct rockchip_drm_private *priv = dev->dev_private;
+ int pipe = drm_crtc_index(crtc);
+ struct rockchip_drm_private *priv = crtc->dev->dev_private;
if (pipe > ROCKCHIP_MAX_CRTC)
return -EINVAL;
@@ -79,9 +79,10 @@ int rockchip_register_crtc_funcs(struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(rockchip_register_crtc_funcs);
-void rockchip_unregister_crtc_funcs(struct drm_device *dev, int pipe)
+void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc)
{
- struct rockchip_drm_private *priv = dev->dev_private;
+ int pipe = drm_crtc_index(crtc);
+ struct rockchip_drm_private *priv = crtc->dev->dev_private;
if (pipe > ROCKCHIP_MAX_CRTC)
return;
@@ -139,6 +140,9 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
if (!private)
return -ENOMEM;
+ mutex_init(&private->commit.lock);
+ INIT_WORK(&private->commit.work, rockchip_drm_atomic_work);
+
drm_dev->dev_private = private;
drm_mode_config_init(drm_dev);
@@ -212,6 +216,8 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
*/
drm_dev->vblank_disable_allowed = true;
+ drm_mode_config_reset(drm_dev);
+
ret = rockchip_drm_fbdev_init(drm_dev);
if (ret)
goto err_vblank_cleanup;
@@ -275,7 +281,8 @@ const struct vm_operations_struct rockchip_drm_vm_ops = {
};
static struct drm_driver rockchip_drm_driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM |
+ DRIVER_PRIME | DRIVER_ATOMIC,
.load = rockchip_drm_load,
.unload = rockchip_drm_unload,
.lastclose = rockchip_drm_lastclose,
@@ -450,10 +457,6 @@ static int rockchip_drm_bind(struct device *dev)
if (!drm)
return -ENOMEM;
- ret = drm_dev_set_unique(drm, "%s", dev_name(dev));
- if (ret)
- goto err_free;
-
ret = drm_dev_register(drm, 0);
if (ret)
goto err_free;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index dc4e5f03ac79..bb8b076f1dbb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -18,6 +18,7 @@
#define _ROCKCHIP_DRM_DRV_H
#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem.h>
#include <linux/module.h>
@@ -38,6 +39,14 @@ struct drm_connector;
struct rockchip_crtc_funcs {
int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc);
+ void (*wait_for_update)(struct drm_crtc *crtc);
+};
+
+struct rockchip_atomic_commit {
+ struct work_struct work;
+ struct drm_atomic_state *state;
+ struct drm_device *dev;
+ struct mutex lock;
};
/*
@@ -50,12 +59,14 @@ struct rockchip_drm_private {
struct drm_fb_helper fbdev_helper;
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
+
+ struct rockchip_atomic_commit commit;
};
-int rockchip_register_crtc_funcs(struct drm_device *dev,
- const struct rockchip_crtc_funcs *crtc_funcs,
- int pipe);
-void rockchip_unregister_crtc_funcs(struct drm_device *dev, int pipe);
+void rockchip_drm_atomic_work(struct work_struct *work);
+int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
+ const struct rockchip_crtc_funcs *crtc_funcs);
+void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
int rockchip_drm_encoder_get_mux_id(struct device_node *node,
struct drm_encoder *encoder);
int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc, int connector_type,
@@ -64,5 +75,4 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *dev);
void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
-
#endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 002645bb5bbf..f7844883cb76 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <drm/drm.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
@@ -66,13 +67,13 @@ static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
rockchip_fb->obj[0], handle);
}
-static struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
+static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
.destroy = rockchip_drm_fb_destroy,
.create_handle = rockchip_drm_fb_create_handle,
};
static struct rockchip_drm_fb *
-rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd,
+rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **obj, unsigned int num_planes)
{
struct rockchip_drm_fb *rockchip_fb;
@@ -102,7 +103,7 @@ rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd,
static struct drm_framebuffer *
rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct rockchip_drm_fb *rockchip_fb;
struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
@@ -166,14 +167,136 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(fb_helper);
}
+static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc)
+{
+ struct rockchip_drm_private *priv = crtc->dev->dev_private;
+ int pipe = drm_crtc_index(crtc);
+ const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe];
+
+ if (crtc_funcs && crtc_funcs->wait_for_update)
+ crtc_funcs->wait_for_update(crtc);
+}
+
+static void
+rockchip_atomic_wait_for_complete(struct drm_atomic_state *old_state)
+{
+ struct drm_crtc_state *old_crtc_state;
+ struct drm_crtc *crtc;
+ int i, ret;
+
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ /* No one cares about the old state, so abuse it for tracking
+ * and store whether we hold a vblank reference (and should do a
+ * vblank wait) in the ->enable boolean.
+ */
+ old_crtc_state->enable = false;
+
+ if (!crtc->state->active)
+ continue;
+
+ ret = drm_crtc_vblank_get(crtc);
+ if (ret != 0)
+ continue;
+
+ old_crtc_state->enable = true;
+ }
+
+ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ if (!old_crtc_state->enable)
+ continue;
+
+ rockchip_crtc_wait_for_update(crtc);
+ drm_crtc_vblank_put(crtc);
+ }
+}
+
+static void
+rockchip_atomic_commit_complete(struct rockchip_atomic_commit *commit)
+{
+ struct drm_atomic_state *state = commit->state;
+ struct drm_device *dev = commit->dev;
+
+ /*
+ * TODO: do fence wait here.
+ */
+
+ /*
+ * Rockchip crtc support runtime PM, can't update display planes
+ * when crtc is disabled.
+ *
+ * drm_atomic_helper_commit comments detail that:
+ * For drivers supporting runtime PM the recommended sequence is
+ *
+ * drm_atomic_helper_commit_modeset_disables(dev, state);
+ *
+ * drm_atomic_helper_commit_modeset_enables(dev, state);
+ *
+ * drm_atomic_helper_commit_planes(dev, state, true);
+ *
+ * See the kerneldoc entries for these three functions for more details.
+ */
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state, true);
+
+ rockchip_atomic_wait_for_complete(state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+
+ drm_atomic_state_free(state);
+}
+
+void rockchip_drm_atomic_work(struct work_struct *work)
+{
+ struct rockchip_atomic_commit *commit = container_of(work,
+ struct rockchip_atomic_commit, work);
+
+ rockchip_atomic_commit_complete(commit);
+}
+
+int rockchip_drm_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ struct rockchip_drm_private *private = dev->dev_private;
+ struct rockchip_atomic_commit *commit = &private->commit;
+ int ret;
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ /* serialize outstanding asynchronous commits */
+ mutex_lock(&commit->lock);
+ flush_work(&commit->work);
+
+ drm_atomic_helper_swap_state(dev, state);
+
+ commit->dev = dev;
+ commit->state = state;
+
+ if (async)
+ schedule_work(&commit->work);
+ else
+ rockchip_atomic_commit_complete(commit);
+
+ mutex_unlock(&commit->lock);
+
+ return 0;
+}
+
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_user_fb_create,
.output_poll_changed = rockchip_drm_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = rockchip_drm_atomic_commit,
};
struct drm_framebuffer *
rockchip_drm_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
struct rockchip_drm_fb *rockchip_fb;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
index 09574d48226f..2fe47f1ee98f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
@@ -17,7 +17,7 @@
struct drm_framebuffer *
rockchip_drm_framebuffer_init(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 03c47eeadc81..46c2a8dfd8aa 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -14,6 +14,7 @@
#include <drm/drm.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
@@ -35,11 +36,6 @@
#include "rockchip_drm_fb.h"
#include "rockchip_drm_vop.h"
-#define VOP_REG(off, _mask, s) \
- {.offset = off, \
- .mask = _mask, \
- .shift = s,}
-
#define __REG_SET_RELAXED(x, off, mask, shift, v) \
vop_mask_write_relaxed(x, off, (mask) << shift, (v) << shift)
#define __REG_SET_NORMAL(x, off, mask, shift, v) \
@@ -47,14 +43,35 @@
#define REG_SET(x, base, reg, v, mode) \
__REG_SET_##mode(x, base + reg.offset, reg.mask, reg.shift, v)
+#define REG_SET_MASK(x, base, reg, v, mode) \
+ __REG_SET_##mode(x, base + reg.offset, reg.mask, reg.shift, v)
#define VOP_WIN_SET(x, win, name, v) \
REG_SET(x, win->base, win->phy->name, v, RELAXED)
#define VOP_SCL_SET(x, win, name, v) \
REG_SET(x, win->base, win->phy->scl->name, v, RELAXED)
+#define VOP_SCL_SET_EXT(x, win, name, v) \
+ REG_SET(x, win->base, win->phy->scl->ext->name, v, RELAXED)
#define VOP_CTRL_SET(x, name, v) \
REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL)
+#define VOP_INTR_GET(vop, name) \
+ vop_read_reg(vop, 0, &vop->data->ctrl->name)
+
+#define VOP_INTR_SET(vop, name, v) \
+ REG_SET(vop, 0, vop->data->intr->name, v, NORMAL)
+#define VOP_INTR_SET_TYPE(vop, name, type, v) \
+ do { \
+ int i, reg = 0; \
+ for (i = 0; i < vop->data->intr->nintrs; i++) { \
+ if (vop->data->intr->intrs[i] & type) \
+ reg |= (v) << i; \
+ } \
+ VOP_INTR_SET(vop, name, reg); \
+ } while (0)
+#define VOP_INTR_GET_TYPE(vop, name, type) \
+ vop_get_intr_type(vop, &vop->data->intr->name, type)
+
#define VOP_WIN_GET(x, win, name) \
vop_read_reg(x, win->base, &win->phy->name)
@@ -63,12 +80,15 @@
#define to_vop(x) container_of(x, struct vop, crtc)
#define to_vop_win(x) container_of(x, struct vop_win, base)
+#define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base)
-struct vop_win_state {
- struct list_head head;
- struct drm_framebuffer *fb;
+struct vop_plane_state {
+ struct drm_plane_state base;
+ int format;
+ struct drm_rect src;
+ struct drm_rect dest;
dma_addr_t yrgb_mst;
- struct drm_pending_vblank_event *event;
+ bool enable;
};
struct vop_win {
@@ -76,8 +96,7 @@ struct vop_win {
const struct vop_win_data *data;
struct vop *vop;
- struct list_head pending;
- struct vop_win_state *active;
+ struct vop_plane_state state;
};
struct vop {
@@ -86,13 +105,12 @@ struct vop {
struct drm_device *drm_dev;
bool is_enabled;
- int connector_type;
- int connector_out_mode;
-
/* mutex vsync_ work */
struct mutex vsync_mutex;
bool vsync_work_pending;
struct completion dsp_hold_completion;
+ struct completion wait_update_complete;
+ struct drm_pending_vblank_event *event;
const struct vop_data *data;
@@ -119,263 +137,9 @@ struct vop {
/* vop dclk reset */
struct reset_control *dclk_rst;
- int pipe;
-
struct vop_win win[];
};
-enum vop_data_format {
- VOP_FMT_ARGB8888 = 0,
- VOP_FMT_RGB888,
- VOP_FMT_RGB565,
- VOP_FMT_YUV420SP = 4,
- VOP_FMT_YUV422SP,
- VOP_FMT_YUV444SP,
-};
-
-struct vop_reg_data {
- uint32_t offset;
- uint32_t value;
-};
-
-struct vop_reg {
- uint32_t offset;
- uint32_t shift;
- uint32_t mask;
-};
-
-struct vop_ctrl {
- struct vop_reg standby;
- struct vop_reg data_blank;
- struct vop_reg gate_en;
- struct vop_reg mmu_en;
- struct vop_reg rgb_en;
- struct vop_reg edp_en;
- struct vop_reg hdmi_en;
- struct vop_reg mipi_en;
- struct vop_reg out_mode;
- struct vop_reg dither_down;
- struct vop_reg dither_up;
- struct vop_reg pin_pol;
-
- struct vop_reg htotal_pw;
- struct vop_reg hact_st_end;
- struct vop_reg vtotal_pw;
- struct vop_reg vact_st_end;
- struct vop_reg hpost_st_end;
- struct vop_reg vpost_st_end;
-};
-
-struct vop_scl_regs {
- struct vop_reg cbcr_vsd_mode;
- struct vop_reg cbcr_vsu_mode;
- struct vop_reg cbcr_hsd_mode;
- struct vop_reg cbcr_ver_scl_mode;
- struct vop_reg cbcr_hor_scl_mode;
- struct vop_reg yrgb_vsd_mode;
- struct vop_reg yrgb_vsu_mode;
- struct vop_reg yrgb_hsd_mode;
- struct vop_reg yrgb_ver_scl_mode;
- struct vop_reg yrgb_hor_scl_mode;
- struct vop_reg line_load_mode;
- struct vop_reg cbcr_axi_gather_num;
- struct vop_reg yrgb_axi_gather_num;
- struct vop_reg vsd_cbcr_gt2;
- struct vop_reg vsd_cbcr_gt4;
- struct vop_reg vsd_yrgb_gt2;
- struct vop_reg vsd_yrgb_gt4;
- struct vop_reg bic_coe_sel;
- struct vop_reg cbcr_axi_gather_en;
- struct vop_reg yrgb_axi_gather_en;
-
- struct vop_reg lb_mode;
- struct vop_reg scale_yrgb_x;
- struct vop_reg scale_yrgb_y;
- struct vop_reg scale_cbcr_x;
- struct vop_reg scale_cbcr_y;
-};
-
-struct vop_win_phy {
- const struct vop_scl_regs *scl;
- const uint32_t *data_formats;
- uint32_t nformats;
-
- struct vop_reg enable;
- struct vop_reg format;
- struct vop_reg rb_swap;
- struct vop_reg act_info;
- struct vop_reg dsp_info;
- struct vop_reg dsp_st;
- struct vop_reg yrgb_mst;
- struct vop_reg uv_mst;
- struct vop_reg yrgb_vir;
- struct vop_reg uv_vir;
-
- struct vop_reg dst_alpha_ctl;
- struct vop_reg src_alpha_ctl;
-};
-
-struct vop_win_data {
- uint32_t base;
- const struct vop_win_phy *phy;
- enum drm_plane_type type;
-};
-
-struct vop_data {
- const struct vop_reg_data *init_table;
- unsigned int table_size;
- const struct vop_ctrl *ctrl;
- const struct vop_win_data *win;
- unsigned int win_size;
-};
-
-static const uint32_t formats_01[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_XBGR8888,
- DRM_FORMAT_ABGR8888,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_BGR888,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_BGR565,
- DRM_FORMAT_NV12,
- DRM_FORMAT_NV16,
- DRM_FORMAT_NV24,
-};
-
-static const uint32_t formats_234[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_XBGR8888,
- DRM_FORMAT_ABGR8888,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_BGR888,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_BGR565,
-};
-
-static const struct vop_scl_regs win_full_scl = {
- .cbcr_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 31),
- .cbcr_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 30),
- .cbcr_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 28),
- .cbcr_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 26),
- .cbcr_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 24),
- .yrgb_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 23),
- .yrgb_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 22),
- .yrgb_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 20),
- .yrgb_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 18),
- .yrgb_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 16),
- .line_load_mode = VOP_REG(WIN0_CTRL1, 0x1, 15),
- .cbcr_axi_gather_num = VOP_REG(WIN0_CTRL1, 0x7, 12),
- .yrgb_axi_gather_num = VOP_REG(WIN0_CTRL1, 0xf, 8),
- .vsd_cbcr_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 7),
- .vsd_cbcr_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 6),
- .vsd_yrgb_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 5),
- .vsd_yrgb_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 4),
- .bic_coe_sel = VOP_REG(WIN0_CTRL1, 0x3, 2),
- .cbcr_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 1),
- .yrgb_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 0),
- .lb_mode = VOP_REG(WIN0_CTRL0, 0x7, 5),
- .scale_yrgb_x = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
- .scale_yrgb_y = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
- .scale_cbcr_x = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
- .scale_cbcr_y = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 16),
-};
-
-static const struct vop_win_phy win01_data = {
- .scl = &win_full_scl,
- .data_formats = formats_01,
- .nformats = ARRAY_SIZE(formats_01),
- .enable = VOP_REG(WIN0_CTRL0, 0x1, 0),
- .format = VOP_REG(WIN0_CTRL0, 0x7, 1),
- .rb_swap = VOP_REG(WIN0_CTRL0, 0x1, 12),
- .act_info = VOP_REG(WIN0_ACT_INFO, 0x1fff1fff, 0),
- .dsp_info = VOP_REG(WIN0_DSP_INFO, 0x0fff0fff, 0),
- .dsp_st = VOP_REG(WIN0_DSP_ST, 0x1fff1fff, 0),
- .yrgb_mst = VOP_REG(WIN0_YRGB_MST, 0xffffffff, 0),
- .uv_mst = VOP_REG(WIN0_CBR_MST, 0xffffffff, 0),
- .yrgb_vir = VOP_REG(WIN0_VIR, 0x3fff, 0),
- .uv_vir = VOP_REG(WIN0_VIR, 0x3fff, 16),
- .src_alpha_ctl = VOP_REG(WIN0_SRC_ALPHA_CTRL, 0xff, 0),
- .dst_alpha_ctl = VOP_REG(WIN0_DST_ALPHA_CTRL, 0xff, 0),
-};
-
-static const struct vop_win_phy win23_data = {
- .data_formats = formats_234,
- .nformats = ARRAY_SIZE(formats_234),
- .enable = VOP_REG(WIN2_CTRL0, 0x1, 0),
- .format = VOP_REG(WIN2_CTRL0, 0x7, 1),
- .rb_swap = VOP_REG(WIN2_CTRL0, 0x1, 12),
- .dsp_info = VOP_REG(WIN2_DSP_INFO0, 0x0fff0fff, 0),
- .dsp_st = VOP_REG(WIN2_DSP_ST0, 0x1fff1fff, 0),
- .yrgb_mst = VOP_REG(WIN2_MST0, 0xffffffff, 0),
- .yrgb_vir = VOP_REG(WIN2_VIR0_1, 0x1fff, 0),
- .src_alpha_ctl = VOP_REG(WIN2_SRC_ALPHA_CTRL, 0xff, 0),
- .dst_alpha_ctl = VOP_REG(WIN2_DST_ALPHA_CTRL, 0xff, 0),
-};
-
-static const struct vop_ctrl ctrl_data = {
- .standby = VOP_REG(SYS_CTRL, 0x1, 22),
- .gate_en = VOP_REG(SYS_CTRL, 0x1, 23),
- .mmu_en = VOP_REG(SYS_CTRL, 0x1, 20),
- .rgb_en = VOP_REG(SYS_CTRL, 0x1, 12),
- .hdmi_en = VOP_REG(SYS_CTRL, 0x1, 13),
- .edp_en = VOP_REG(SYS_CTRL, 0x1, 14),
- .mipi_en = VOP_REG(SYS_CTRL, 0x1, 15),
- .dither_down = VOP_REG(DSP_CTRL1, 0xf, 1),
- .dither_up = VOP_REG(DSP_CTRL1, 0x1, 6),
- .data_blank = VOP_REG(DSP_CTRL0, 0x1, 19),
- .out_mode = VOP_REG(DSP_CTRL0, 0xf, 0),
- .pin_pol = VOP_REG(DSP_CTRL0, 0xf, 4),
- .htotal_pw = VOP_REG(DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
- .hact_st_end = VOP_REG(DSP_HACT_ST_END, 0x1fff1fff, 0),
- .vtotal_pw = VOP_REG(DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
- .vact_st_end = VOP_REG(DSP_VACT_ST_END, 0x1fff1fff, 0),
- .hpost_st_end = VOP_REG(POST_DSP_HACT_INFO, 0x1fff1fff, 0),
- .vpost_st_end = VOP_REG(POST_DSP_VACT_INFO, 0x1fff1fff, 0),
-};
-
-static const struct vop_reg_data vop_init_reg_table[] = {
- {SYS_CTRL, 0x00c00000},
- {DSP_CTRL0, 0x00000000},
- {WIN0_CTRL0, 0x00000080},
- {WIN1_CTRL0, 0x00000080},
- /* TODO: Win2/3 support multiple area function, but we haven't found
- * a suitable way to use it yet, so let's just use them as other windows
- * with only area 0 enabled.
- */
- {WIN2_CTRL0, 0x00000010},
- {WIN3_CTRL0, 0x00000010},
-};
-
-/*
- * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
- * special support to get alpha blending working. For now, just use overlay
- * window 3 for the drm cursor.
- *
- */
-static const struct vop_win_data rk3288_vop_win_data[] = {
- { .base = 0x00, .phy = &win01_data, .type = DRM_PLANE_TYPE_PRIMARY },
- { .base = 0x40, .phy = &win01_data, .type = DRM_PLANE_TYPE_OVERLAY },
- { .base = 0x00, .phy = &win23_data, .type = DRM_PLANE_TYPE_OVERLAY },
- { .base = 0x50, .phy = &win23_data, .type = DRM_PLANE_TYPE_CURSOR },
-};
-
-static const struct vop_data rk3288_vop = {
- .init_table = vop_init_reg_table,
- .table_size = ARRAY_SIZE(vop_init_reg_table),
- .ctrl = &ctrl_data,
- .win = rk3288_vop_win_data,
- .win_size = ARRAY_SIZE(rk3288_vop_win_data),
-};
-
-static const struct of_device_id vop_driver_dt_match[] = {
- { .compatible = "rockchip,rk3288-vop",
- .data = &rk3288_vop },
- {},
-};
-MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
-
static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v)
{
writel(v, vop->regs + offset);
@@ -393,11 +157,6 @@ static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base,
return (vop_readl(vop, base + reg->offset) >> reg->shift) & reg->mask;
}
-static inline void vop_cfg_done(struct vop *vop)
-{
- writel(0x01, vop->regs + REG_CFG_DONE);
-}
-
static inline void vop_mask_write(struct vop *vop, uint32_t offset,
uint32_t mask, uint32_t v)
{
@@ -422,6 +181,25 @@ static inline void vop_mask_write_relaxed(struct vop *vop, uint32_t offset,
}
}
+static inline uint32_t vop_get_intr_type(struct vop *vop,
+ const struct vop_reg *reg, int type)
+{
+ uint32_t i, ret = 0;
+ uint32_t regs = vop_read_reg(vop, 0, reg);
+
+ for (i = 0; i < vop->data->intr->nintrs; i++) {
+ if ((type & vop->data->intr->intrs[i]) && (regs & 1 << i))
+ ret |= vop->data->intr->intrs[i];
+ }
+
+ return ret;
+}
+
+static inline void vop_cfg_done(struct vop *vop)
+{
+ VOP_CTRL_SET(vop, cfg_done, 1);
+}
+
static bool has_rb_swapped(uint32_t format)
{
switch (format) {
@@ -537,6 +315,20 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
return;
}
+ if (!win->phy->scl->ext) {
+ VOP_SCL_SET(vop, win, scale_yrgb_x,
+ scl_cal_scale2(src_w, dst_w));
+ VOP_SCL_SET(vop, win, scale_yrgb_y,
+ scl_cal_scale2(src_h, dst_h));
+ if (is_yuv) {
+ VOP_SCL_SET(vop, win, scale_cbcr_x,
+ scl_cal_scale2(src_w, dst_w));
+ VOP_SCL_SET(vop, win, scale_cbcr_y,
+ scl_cal_scale2(src_h, dst_h));
+ }
+ return;
+ }
+
yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
@@ -554,7 +346,7 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
lb_mode = scl_vop_cal_lb_mode(src_w, false);
}
- VOP_SCL_SET(vop, win, lb_mode, lb_mode);
+ VOP_SCL_SET_EXT(vop, win, lb_mode, lb_mode);
if (lb_mode == LB_RGB_3840X2) {
if (yrgb_ver_scl_mode != SCALE_NONE) {
DRM_ERROR("ERROR : not allow yrgb ver scale\n");
@@ -578,14 +370,14 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
false, vsu_mode, &vskiplines);
VOP_SCL_SET(vop, win, scale_yrgb_y, val);
- VOP_SCL_SET(vop, win, vsd_yrgb_gt4, vskiplines == 4);
- VOP_SCL_SET(vop, win, vsd_yrgb_gt2, vskiplines == 2);
+ VOP_SCL_SET_EXT(vop, win, vsd_yrgb_gt4, vskiplines == 4);
+ VOP_SCL_SET_EXT(vop, win, vsd_yrgb_gt2, vskiplines == 2);
- VOP_SCL_SET(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode);
- VOP_SCL_SET(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode);
- VOP_SCL_SET(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL);
- VOP_SCL_SET(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL);
- VOP_SCL_SET(vop, win, yrgb_vsu_mode, vsu_mode);
+ VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode);
+ VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode);
+ VOP_SCL_SET_EXT(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL);
+ VOP_SCL_SET_EXT(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL);
+ VOP_SCL_SET_EXT(vop, win, yrgb_vsu_mode, vsu_mode);
if (is_yuv) {
val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w,
dst_w, true, 0, NULL);
@@ -594,13 +386,13 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
dst_h, false, vsu_mode, &vskiplines);
VOP_SCL_SET(vop, win, scale_cbcr_y, val);
- VOP_SCL_SET(vop, win, vsd_cbcr_gt4, vskiplines == 4);
- VOP_SCL_SET(vop, win, vsd_cbcr_gt2, vskiplines == 2);
- VOP_SCL_SET(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode);
- VOP_SCL_SET(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode);
- VOP_SCL_SET(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL);
- VOP_SCL_SET(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL);
- VOP_SCL_SET(vop, win, cbcr_vsu_mode, vsu_mode);
+ VOP_SCL_SET_EXT(vop, win, vsd_cbcr_gt4, vskiplines == 4);
+ VOP_SCL_SET_EXT(vop, win, vsd_cbcr_gt2, vskiplines == 2);
+ VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode);
+ VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode);
+ VOP_SCL_SET_EXT(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL);
+ VOP_SCL_SET_EXT(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL);
+ VOP_SCL_SET_EXT(vop, win, cbcr_vsu_mode, vsu_mode);
}
}
@@ -613,8 +405,7 @@ static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
- DSP_HOLD_VALID_INTR_EN(1));
+ VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 1);
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
@@ -628,8 +419,7 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
- DSP_HOLD_VALID_INTR_EN(0));
+ VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 0);
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
@@ -692,7 +482,7 @@ static void vop_enable(struct drm_crtc *crtc)
enable_irq(vop->irq);
- drm_vblank_on(vop->drm_dev, vop->pipe);
+ drm_crtc_vblank_on(crtc);
return;
@@ -704,14 +494,14 @@ err_disable_hclk:
clk_disable(vop->hclk);
}
-static void vop_disable(struct drm_crtc *crtc)
+static void vop_crtc_disable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
if (!vop->is_enabled)
return;
- drm_vblank_off(crtc->dev, vop->pipe);
+ drm_crtc_vblank_off(crtc);
/*
* Vop standby will take effect at end of current frame,
@@ -748,224 +538,188 @@ static void vop_disable(struct drm_crtc *crtc)
pm_runtime_put(vop->dev);
}
-/*
- * Caller must hold vsync_mutex.
- */
-static struct drm_framebuffer *vop_win_last_pending_fb(struct vop_win *vop_win)
-{
- struct vop_win_state *last;
- struct vop_win_state *active = vop_win->active;
-
- if (list_empty(&vop_win->pending))
- return active ? active->fb : NULL;
-
- last = list_last_entry(&vop_win->pending, struct vop_win_state, head);
- return last ? last->fb : NULL;
-}
-
-/*
- * Caller must hold vsync_mutex.
- */
-static int vop_win_queue_fb(struct vop_win *vop_win,
- struct drm_framebuffer *fb, dma_addr_t yrgb_mst,
- struct drm_pending_vblank_event *event)
+static void vop_plane_destroy(struct drm_plane *plane)
{
- struct vop_win_state *state;
-
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
-
- state->fb = fb;
- state->yrgb_mst = yrgb_mst;
- state->event = event;
-
- list_add_tail(&state->head, &vop_win->pending);
-
- return 0;
+ drm_plane_cleanup(plane);
}
-static int vop_update_plane_event(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_pending_vblank_event *event)
+static int vop_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_framebuffer *fb = state->fb;
struct vop_win *vop_win = to_vop_win(plane);
+ struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
const struct vop_win_data *win = vop_win->data;
- struct vop *vop = to_vop(crtc);
- struct drm_gem_object *obj;
- struct rockchip_gem_object *rk_obj;
- struct drm_gem_object *uv_obj;
- struct rockchip_gem_object *rk_uv_obj;
- unsigned long offset;
- unsigned int actual_w;
- unsigned int actual_h;
- unsigned int dsp_stx;
- unsigned int dsp_sty;
- unsigned int y_vir_stride;
- unsigned int uv_vir_stride = 0;
- dma_addr_t yrgb_mst;
- dma_addr_t uv_mst = 0;
- enum vop_data_format format;
- uint32_t val;
- bool is_alpha;
- bool rb_swap;
- bool is_yuv;
bool visible;
int ret;
- struct drm_rect dest = {
- .x1 = crtc_x,
- .y1 = crtc_y,
- .x2 = crtc_x + crtc_w,
- .y2 = crtc_y + crtc_h,
- };
- struct drm_rect src = {
- /* 16.16 fixed point */
- .x1 = src_x,
- .y1 = src_y,
- .x2 = src_x + src_w,
- .y2 = src_y + src_h,
- };
- const struct drm_rect clip = {
- .x2 = crtc->mode.hdisplay,
- .y2 = crtc->mode.vdisplay,
- };
- bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY;
+ struct drm_rect *dest = &vop_plane_state->dest;
+ struct drm_rect *src = &vop_plane_state->src;
+ struct drm_rect clip;
int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
DRM_PLANE_HELPER_NO_SCALING;
int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
DRM_PLANE_HELPER_NO_SCALING;
- ret = drm_plane_helper_check_update(plane, crtc, fb,
- &src, &dest, &clip,
+ crtc = crtc ? crtc : plane->state->crtc;
+ /*
+ * Both crtc or plane->state->crtc can be null.
+ */
+ if (!crtc || !fb)
+ goto out_disable;
+ src->x1 = state->src_x;
+ src->y1 = state->src_y;
+ src->x2 = state->src_x + state->src_w;
+ src->y2 = state->src_y + state->src_h;
+ dest->x1 = state->crtc_x;
+ dest->y1 = state->crtc_y;
+ dest->x2 = state->crtc_x + state->crtc_w;
+ dest->y2 = state->crtc_y + state->crtc_h;
+
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc->mode.hdisplay;
+ clip.y2 = crtc->mode.vdisplay;
+
+ ret = drm_plane_helper_check_update(plane, crtc, state->fb,
+ src, dest, &clip,
min_scale,
max_scale,
- can_position, false, &visible);
+ true, true, &visible);
if (ret)
return ret;
if (!visible)
- return 0;
+ goto out_disable;
- is_alpha = is_alpha_support(fb->pixel_format);
- rb_swap = has_rb_swapped(fb->pixel_format);
- is_yuv = is_yuv_support(fb->pixel_format);
-
- format = vop_convert_format(fb->pixel_format);
- if (format < 0)
- return format;
+ vop_plane_state->format = vop_convert_format(fb->pixel_format);
+ if (vop_plane_state->format < 0)
+ return vop_plane_state->format;
- obj = rockchip_fb_get_gem_obj(fb, 0);
- if (!obj) {
- DRM_ERROR("fail to get rockchip gem object from framebuffer\n");
+ /*
+ * Src.x1 can be odd when do clip, but yuv plane start point
+ * need align with 2 pixel.
+ */
+ if (is_yuv_support(fb->pixel_format) && ((src->x1 >> 16) % 2))
return -EINVAL;
- }
- rk_obj = to_rockchip_obj(obj);
+ vop_plane_state->enable = true;
- if (is_yuv) {
- /*
- * Src.x1 can be odd when do clip, but yuv plane start point
- * need align with 2 pixel.
- */
- val = (src.x1 >> 16) % 2;
- src.x1 += val << 16;
- src.x2 += val << 16;
- }
+ return 0;
- actual_w = (src.x2 - src.x1) >> 16;
- actual_h = (src.y2 - src.y1) >> 16;
+out_disable:
+ vop_plane_state->enable = false;
+ return 0;
+}
- dsp_stx = dest.x1 + crtc->mode.htotal - crtc->mode.hsync_start;
- dsp_sty = dest.y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
+static void vop_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct vop_plane_state *vop_plane_state = to_vop_plane_state(old_state);
+ struct vop_win *vop_win = to_vop_win(plane);
+ const struct vop_win_data *win = vop_win->data;
+ struct vop *vop = to_vop(old_state->crtc);
- offset = (src.x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);
- offset += (src.y1 >> 16) * fb->pitches[0];
+ if (!old_state->crtc)
+ return;
- yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
- y_vir_stride = fb->pitches[0] >> 2;
+ spin_lock(&vop->reg_lock);
- if (is_yuv) {
- int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
- int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
- int bpp = drm_format_plane_cpp(fb->pixel_format, 1);
+ VOP_WIN_SET(vop, win, enable, 0);
- uv_obj = rockchip_fb_get_gem_obj(fb, 1);
- if (!uv_obj) {
- DRM_ERROR("fail to get uv object from framebuffer\n");
- return -EINVAL;
- }
- rk_uv_obj = to_rockchip_obj(uv_obj);
- uv_vir_stride = fb->pitches[1] >> 2;
+ spin_unlock(&vop->reg_lock);
- offset = (src.x1 >> 16) * bpp / hsub;
- offset += (src.y1 >> 16) * fb->pitches[1] / vsub;
+ vop_plane_state->enable = false;
+}
- uv_mst = rk_uv_obj->dma_addr + offset + fb->offsets[1];
- }
+static void vop_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_crtc *crtc = state->crtc;
+ struct vop_win *vop_win = to_vop_win(plane);
+ struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
+ const struct vop_win_data *win = vop_win->data;
+ struct vop *vop = to_vop(state->crtc);
+ struct drm_framebuffer *fb = state->fb;
+ unsigned int actual_w, actual_h;
+ unsigned int dsp_stx, dsp_sty;
+ uint32_t act_info, dsp_info, dsp_st;
+ struct drm_rect *src = &vop_plane_state->src;
+ struct drm_rect *dest = &vop_plane_state->dest;
+ struct drm_gem_object *obj, *uv_obj;
+ struct rockchip_gem_object *rk_obj, *rk_uv_obj;
+ unsigned long offset;
+ dma_addr_t dma_addr;
+ uint32_t val;
+ bool rb_swap;
/*
- * If this plane update changes the plane's framebuffer, (or more
- * precisely, if this update has a different framebuffer than the last
- * update), enqueue it so we can track when it completes.
- *
- * Only when we discover that this update has completed, can we
- * unreference any previous framebuffers.
+ * can't update plane when vop is disabled.
*/
- mutex_lock(&vop->vsync_mutex);
- if (fb != vop_win_last_pending_fb(vop_win)) {
- ret = drm_vblank_get(plane->dev, vop->pipe);
- if (ret) {
- DRM_ERROR("failed to get vblank, %d\n", ret);
- mutex_unlock(&vop->vsync_mutex);
- return ret;
- }
-
- drm_framebuffer_reference(fb);
+ if (!crtc)
+ return;
- ret = vop_win_queue_fb(vop_win, fb, yrgb_mst, event);
- if (ret) {
- drm_vblank_put(plane->dev, vop->pipe);
- mutex_unlock(&vop->vsync_mutex);
- return ret;
- }
+ if (WARN_ON(!vop->is_enabled))
+ return;
- vop->vsync_work_pending = true;
+ if (!vop_plane_state->enable) {
+ vop_plane_atomic_disable(plane, old_state);
+ return;
}
- mutex_unlock(&vop->vsync_mutex);
+
+ obj = rockchip_fb_get_gem_obj(fb, 0);
+ rk_obj = to_rockchip_obj(obj);
+
+ actual_w = drm_rect_width(src) >> 16;
+ actual_h = drm_rect_height(src) >> 16;
+ act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
+
+ dsp_info = (drm_rect_height(dest) - 1) << 16;
+ dsp_info |= (drm_rect_width(dest) - 1) & 0xffff;
+
+ dsp_stx = dest->x1 + crtc->mode.htotal - crtc->mode.hsync_start;
+ dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
+ dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
+
+ offset = (src->x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0);
+ offset += (src->y1 >> 16) * fb->pitches[0];
+ vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
spin_lock(&vop->reg_lock);
- VOP_WIN_SET(vop, win, format, format);
- VOP_WIN_SET(vop, win, yrgb_vir, y_vir_stride);
- VOP_WIN_SET(vop, win, yrgb_mst, yrgb_mst);
- if (is_yuv) {
- VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride);
- VOP_WIN_SET(vop, win, uv_mst, uv_mst);
+ VOP_WIN_SET(vop, win, format, vop_plane_state->format);
+ VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> 2);
+ VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
+ if (is_yuv_support(fb->pixel_format)) {
+ int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
+ int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
+ int bpp = drm_format_plane_cpp(fb->pixel_format, 1);
+
+ uv_obj = rockchip_fb_get_gem_obj(fb, 1);
+ rk_uv_obj = to_rockchip_obj(uv_obj);
+
+ offset = (src->x1 >> 16) * bpp / hsub;
+ offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
+
+ dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
+ VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> 2);
+ VOP_WIN_SET(vop, win, uv_mst, dma_addr);
}
if (win->phy->scl)
scl_vop_cal_scl_fac(vop, win, actual_w, actual_h,
- dest.x2 - dest.x1, dest.y2 - dest.y1,
+ drm_rect_width(dest), drm_rect_height(dest),
fb->pixel_format);
- val = (actual_h - 1) << 16;
- val |= (actual_w - 1) & 0xffff;
- VOP_WIN_SET(vop, win, act_info, val);
+ VOP_WIN_SET(vop, win, act_info, act_info);
+ VOP_WIN_SET(vop, win, dsp_info, dsp_info);
+ VOP_WIN_SET(vop, win, dsp_st, dsp_st);
- val = (dest.y2 - dest.y1 - 1) << 16;
- val |= (dest.x2 - dest.x1 - 1) & 0xffff;
- VOP_WIN_SET(vop, win, dsp_info, val);
- val = dsp_sty << 16;
- val |= dsp_stx & 0xffff;
- VOP_WIN_SET(vop, win, dsp_st, val);
+ rb_swap = has_rb_swapped(fb->pixel_format);
VOP_WIN_SET(vop, win, rb_swap, rb_swap);
- if (is_alpha) {
+ if (is_alpha_support(fb->pixel_format)) {
VOP_WIN_SET(vop, win, dst_alpha_ctl,
DST_FACTOR_M0(ALPHA_SRC_INVERSE));
val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) |
@@ -979,86 +733,70 @@ static int vop_update_plane_event(struct drm_plane *plane,
}
VOP_WIN_SET(vop, win, enable, 1);
-
- vop_cfg_done(vop);
spin_unlock(&vop->reg_lock);
-
- return 0;
}
-static int vop_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y, uint32_t src_w,
- uint32_t src_h)
-{
- return vop_update_plane_event(plane, crtc, fb, crtc_x, crtc_y, crtc_w,
- crtc_h, src_x, src_y, src_w, src_h,
- NULL);
-}
+static const struct drm_plane_helper_funcs plane_helper_funcs = {
+ .atomic_check = vop_plane_atomic_check,
+ .atomic_update = vop_plane_atomic_update,
+ .atomic_disable = vop_plane_atomic_disable,
+};
-static int vop_update_primary_plane(struct drm_crtc *crtc,
- struct drm_pending_vblank_event *event)
+void vop_atomic_plane_reset(struct drm_plane *plane)
{
- unsigned int crtc_w, crtc_h;
+ struct vop_plane_state *vop_plane_state =
+ to_vop_plane_state(plane->state);
- crtc_w = crtc->primary->fb->width - crtc->x;
- crtc_h = crtc->primary->fb->height - crtc->y;
+ if (plane->state && plane->state->fb)
+ drm_framebuffer_unreference(plane->state->fb);
- return vop_update_plane_event(crtc->primary, crtc, crtc->primary->fb,
- 0, 0, crtc_w, crtc_h, crtc->x << 16,
- crtc->y << 16, crtc_w << 16,
- crtc_h << 16, event);
+ kfree(vop_plane_state);
+ vop_plane_state = kzalloc(sizeof(*vop_plane_state), GFP_KERNEL);
+ if (!vop_plane_state)
+ return;
+
+ plane->state = &vop_plane_state->base;
+ plane->state->plane = plane;
}
-static int vop_disable_plane(struct drm_plane *plane)
+struct drm_plane_state *
+vop_atomic_plane_duplicate_state(struct drm_plane *plane)
{
- struct vop_win *vop_win = to_vop_win(plane);
- const struct vop_win_data *win = vop_win->data;
- struct vop *vop;
- int ret;
-
- if (!plane->crtc)
- return 0;
-
- vop = to_vop(plane->crtc);
+ struct vop_plane_state *old_vop_plane_state;
+ struct vop_plane_state *vop_plane_state;
- ret = drm_vblank_get(plane->dev, vop->pipe);
- if (ret) {
- DRM_ERROR("failed to get vblank, %d\n", ret);
- return ret;
- }
-
- mutex_lock(&vop->vsync_mutex);
-
- ret = vop_win_queue_fb(vop_win, NULL, 0, NULL);
- if (ret) {
- drm_vblank_put(plane->dev, vop->pipe);
- mutex_unlock(&vop->vsync_mutex);
- return ret;
- }
+ if (WARN_ON(!plane->state))
+ return NULL;
- vop->vsync_work_pending = true;
- mutex_unlock(&vop->vsync_mutex);
+ old_vop_plane_state = to_vop_plane_state(plane->state);
+ vop_plane_state = kmemdup(old_vop_plane_state,
+ sizeof(*vop_plane_state), GFP_KERNEL);
+ if (!vop_plane_state)
+ return NULL;
- spin_lock(&vop->reg_lock);
- VOP_WIN_SET(vop, win, enable, 0);
- vop_cfg_done(vop);
- spin_unlock(&vop->reg_lock);
+ __drm_atomic_helper_plane_duplicate_state(plane,
+ &vop_plane_state->base);
- return 0;
+ return &vop_plane_state->base;
}
-static void vop_plane_destroy(struct drm_plane *plane)
+static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
- vop_disable_plane(plane);
- drm_plane_cleanup(plane);
+ struct vop_plane_state *vop_state = to_vop_plane_state(state);
+
+ __drm_atomic_helper_plane_destroy_state(plane, state);
+
+ kfree(vop_state);
}
static const struct drm_plane_funcs vop_plane_funcs = {
- .update_plane = vop_update_plane,
- .disable_plane = vop_disable_plane,
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
.destroy = vop_plane_destroy,
+ .reset = vop_atomic_plane_reset,
+ .atomic_duplicate_state = vop_atomic_plane_duplicate_state,
+ .atomic_destroy_state = vop_atomic_plane_destroy_state,
};
int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc,
@@ -1067,8 +805,27 @@ int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc,
{
struct vop *vop = to_vop(crtc);
- vop->connector_type = connector_type;
- vop->connector_out_mode = out_mode;
+ if (WARN_ON(!vop->is_enabled))
+ return -EINVAL;
+
+ switch (connector_type) {
+ case DRM_MODE_CONNECTOR_LVDS:
+ VOP_CTRL_SET(vop, rgb_en, 1);
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ VOP_CTRL_SET(vop, edp_en, 1);
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ VOP_CTRL_SET(vop, hdmi_en, 1);
+ break;
+ case DRM_MODE_CONNECTOR_DSI:
+ VOP_CTRL_SET(vop, mipi_en, 1);
+ break;
+ default:
+ DRM_ERROR("unsupport connector_type[%d]\n", connector_type);
+ return -EINVAL;
+ };
+ VOP_CTRL_SET(vop, out_mode, out_mode);
return 0;
}
@@ -1079,12 +836,12 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
struct vop *vop = to_vop(crtc);
unsigned long flags;
- if (!vop->is_enabled)
+ if (WARN_ON(!vop->is_enabled))
return -EPERM;
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(1));
+ VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1);
spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -1096,76 +853,49 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
struct vop *vop = to_vop(crtc);
unsigned long flags;
- if (!vop->is_enabled)
+ if (WARN_ON(!vop->is_enabled))
return;
spin_lock_irqsave(&vop->irq_lock, flags);
- vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0));
+
+ VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
+
spin_unlock_irqrestore(&vop->irq_lock, flags);
}
-static const struct rockchip_crtc_funcs private_crtc_funcs = {
- .enable_vblank = vop_crtc_enable_vblank,
- .disable_vblank = vop_crtc_disable_vblank,
-};
-
-static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
{
- DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
+ struct vop *vop = to_vop(crtc);
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- vop_enable(crtc);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- vop_disable(crtc);
- break;
- default:
- DRM_DEBUG_KMS("unspecified mode %d\n", mode);
- break;
- }
+ reinit_completion(&vop->wait_update_complete);
+ WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100));
}
-static void vop_crtc_prepare(struct drm_crtc *crtc)
-{
- vop_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
-}
+static const struct rockchip_crtc_funcs private_crtc_funcs = {
+ .enable_vblank = vop_crtc_enable_vblank,
+ .disable_vblank = vop_crtc_disable_vblank,
+ .wait_for_update = vop_crtc_wait_for_update,
+};
static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ struct vop *vop = to_vop(crtc);
+
if (adjusted_mode->htotal == 0 || adjusted_mode->vtotal == 0)
return false;
- return true;
-}
-
-static int vop_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- int ret;
-
- crtc->x = x;
- crtc->y = y;
+ adjusted_mode->clock =
+ clk_round_rate(vop->dclk, mode->clock * 1000) / 1000;
- ret = vop_update_primary_plane(crtc, NULL);
- if (ret < 0) {
- DRM_ERROR("fail to update plane\n");
- return ret;
- }
-
- return 0;
+ return true;
}
-static int vop_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 *fb)
+static void vop_crtc_enable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
u16 hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
u16 hdisplay = adjusted_mode->hdisplay;
u16 htotal = adjusted_mode->htotal;
@@ -1176,32 +906,44 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start;
u16 vact_end = vact_st + vdisplay;
- int ret, ret_clk;
uint32_t val;
+ vop_enable(crtc);
/*
- * disable dclk to stop frame scan, so that we can safe config mode and
- * enable iommu.
+ * If dclk rate is zero, mean that scanout is stop,
+ * we don't need wait any more.
*/
- clk_disable(vop->dclk);
+ if (clk_get_rate(vop->dclk)) {
+ /*
+ * Rk3288 vop timing register is immediately, when configure
+ * display timing on display time, may cause tearing.
+ *
+ * Vop standby will take effect at end of current frame,
+ * if dsp hold valid irq happen, it means standby complete.
+ *
+ * mode set:
+ * standby and wait complete --> |----
+ * | display time
+ * |----
+ * |---> dsp hold irq
+ * configure display timing --> |
+ * standby exit |
+ * | new frame start.
+ */
- switch (vop->connector_type) {
- case DRM_MODE_CONNECTOR_LVDS:
- VOP_CTRL_SET(vop, rgb_en, 1);
- break;
- case DRM_MODE_CONNECTOR_eDP:
- VOP_CTRL_SET(vop, edp_en, 1);
- break;
- case DRM_MODE_CONNECTOR_HDMIA:
- VOP_CTRL_SET(vop, hdmi_en, 1);
- break;
- default:
- DRM_ERROR("unsupport connector_type[%d]\n",
- vop->connector_type);
- ret = -EINVAL;
- goto out;
- };
- VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
+ reinit_completion(&vop->dsp_hold_completion);
+ vop_dsp_hold_valid_irq_enable(vop);
+
+ spin_lock(&vop->reg_lock);
+
+ VOP_CTRL_SET(vop, standby, 1);
+
+ spin_unlock(&vop->reg_lock);
+
+ wait_for_completion(&vop->dsp_hold_completion);
+
+ vop_dsp_hold_valid_irq_disable(vop);
+ }
val = 0x8;
val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
@@ -1220,211 +962,119 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
VOP_CTRL_SET(vop, vact_st_end, val);
VOP_CTRL_SET(vop, vpost_st_end, val);
- ret = vop_crtc_mode_set_base(crtc, x, y, fb);
- if (ret)
- goto out;
-
- /*
- * reset dclk, take all mode config affect, so the clk would run in
- * correct frame.
- */
- reset_control_assert(vop->dclk_rst);
- usleep_range(10, 20);
- reset_control_deassert(vop->dclk_rst);
-
clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
-out:
- ret_clk = clk_enable(vop->dclk);
- if (ret_clk < 0) {
- dev_err(vop->dev, "failed to enable dclk - %d\n", ret_clk);
- return ret_clk;
- }
- return ret;
-}
-
-static void vop_crtc_commit(struct drm_crtc *crtc)
-{
+ VOP_CTRL_SET(vop, standby, 0);
}
-static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
- .dpms = vop_crtc_dpms,
- .prepare = vop_crtc_prepare,
- .mode_fixup = vop_crtc_mode_fixup,
- .mode_set = vop_crtc_mode_set,
- .mode_set_base = vop_crtc_mode_set_base,
- .commit = vop_crtc_commit,
-};
-
-static int vop_crtc_page_flip(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event,
- uint32_t page_flip_flags)
+static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
struct vop *vop = to_vop(crtc);
- struct drm_framebuffer *old_fb = crtc->primary->fb;
- int ret;
- /* when the page flip is requested, crtc should be on */
- if (!vop->is_enabled) {
- DRM_DEBUG("page flip request rejected because crtc is off.\n");
- return 0;
- }
+ if (WARN_ON(!vop->is_enabled))
+ return;
- crtc->primary->fb = fb;
+ spin_lock(&vop->reg_lock);
- ret = vop_update_primary_plane(crtc, event);
- if (ret)
- crtc->primary->fb = old_fb;
+ vop_cfg_done(vop);
- return ret;
+ spin_unlock(&vop->reg_lock);
}
-static void vop_win_state_complete(struct vop_win *vop_win,
- struct vop_win_state *state)
+static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
- struct vop *vop = vop_win->vop;
- struct drm_crtc *crtc = &vop->crtc;
- struct drm_device *drm = crtc->dev;
- unsigned long flags;
+ struct vop *vop = to_vop(crtc);
- if (state->event) {
- spin_lock_irqsave(&drm->event_lock, flags);
- drm_crtc_send_vblank_event(crtc, state->event);
- spin_unlock_irqrestore(&drm->event_lock, flags);
- }
+ if (crtc->state->event) {
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
- list_del(&state->head);
- drm_vblank_put(crtc->dev, vop->pipe);
+ vop->event = crtc->state->event;
+ crtc->state->event = NULL;
+ }
}
+static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
+ .enable = vop_crtc_enable,
+ .disable = vop_crtc_disable,
+ .mode_fixup = vop_crtc_mode_fixup,
+ .atomic_flush = vop_crtc_atomic_flush,
+ .atomic_begin = vop_crtc_atomic_begin,
+};
+
static void vop_crtc_destroy(struct drm_crtc *crtc)
{
drm_crtc_cleanup(crtc);
}
static const struct drm_crtc_funcs vop_crtc_funcs = {
- .set_config = drm_crtc_helper_set_config,
- .page_flip = vop_crtc_page_flip,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
.destroy = vop_crtc_destroy,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
};
-static bool vop_win_state_is_active(struct vop_win *vop_win,
- struct vop_win_state *state)
+static bool vop_win_pending_is_complete(struct vop_win *vop_win)
{
- bool active = false;
-
- if (state->fb) {
- dma_addr_t yrgb_mst;
-
- /* check yrgb_mst to tell if pending_fb is now front */
- yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);
-
- active = (yrgb_mst == state->yrgb_mst);
- } else {
- bool enabled;
-
- /* if enable bit is clear, plane is now disabled */
- enabled = VOP_WIN_GET(vop_win->vop, vop_win->data, enable);
-
- active = (enabled == 0);
- }
+ struct drm_plane *plane = &vop_win->base;
+ struct vop_plane_state *state = to_vop_plane_state(plane->state);
+ dma_addr_t yrgb_mst;
- return active;
-}
+ if (!state->enable)
+ return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
-static void vop_win_state_destroy(struct vop_win_state *state)
-{
- struct drm_framebuffer *fb = state->fb;
+ yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);
- if (fb)
- drm_framebuffer_unreference(fb);
-
- kfree(state);
+ return yrgb_mst == state->yrgb_mst;
}
-static void vop_win_update_state(struct vop_win *vop_win)
+static void vop_handle_vblank(struct vop *vop)
{
- struct vop_win_state *state, *n, *new_active = NULL;
-
- /* Check if any pending states are now active */
- list_for_each_entry(state, &vop_win->pending, head)
- if (vop_win_state_is_active(vop_win, state)) {
- new_active = state;
- break;
- }
-
- if (!new_active)
- return;
+ struct drm_device *drm = vop->drm_dev;
+ struct drm_crtc *crtc = &vop->crtc;
+ unsigned long flags;
+ int i;
- /*
- * Destroy any 'skipped' pending states - states that were queued
- * before the newly active state.
- */
- list_for_each_entry_safe(state, n, &vop_win->pending, head) {
- if (state == new_active)
- break;
- vop_win_state_complete(vop_win, state);
- vop_win_state_destroy(state);
+ for (i = 0; i < vop->data->win_size; i++) {
+ if (!vop_win_pending_is_complete(&vop->win[i]))
+ return;
}
- vop_win_state_complete(vop_win, new_active);
-
- if (vop_win->active)
- vop_win_state_destroy(vop_win->active);
- vop_win->active = new_active;
-}
-
-static bool vop_win_has_pending_state(struct vop_win *vop_win)
-{
- return !list_empty(&vop_win->pending);
-}
-
-static irqreturn_t vop_isr_thread(int irq, void *data)
-{
- struct vop *vop = data;
- const struct vop_data *vop_data = vop->data;
- unsigned int i;
-
- mutex_lock(&vop->vsync_mutex);
-
- if (!vop->vsync_work_pending)
- goto done;
+ if (vop->event) {
+ spin_lock_irqsave(&drm->event_lock, flags);
- vop->vsync_work_pending = false;
+ drm_crtc_send_vblank_event(crtc, vop->event);
+ drm_crtc_vblank_put(crtc);
+ vop->event = NULL;
- for (i = 0; i < vop_data->win_size; i++) {
- struct vop_win *vop_win = &vop->win[i];
-
- vop_win_update_state(vop_win);
- if (vop_win_has_pending_state(vop_win))
- vop->vsync_work_pending = true;
+ spin_unlock_irqrestore(&drm->event_lock, flags);
}
-
-done:
- mutex_unlock(&vop->vsync_mutex);
-
- return IRQ_HANDLED;
+ if (!completion_done(&vop->wait_update_complete))
+ complete(&vop->wait_update_complete);
}
static irqreturn_t vop_isr(int irq, void *data)
{
struct vop *vop = data;
- uint32_t intr0_reg, active_irqs;
+ struct drm_crtc *crtc = &vop->crtc;
+ uint32_t active_irqs;
unsigned long flags;
int ret = IRQ_NONE;
/*
- * INTR_CTRL0 register has interrupt status, enable and clear bits, we
+ * interrupt register has interrupt status, enable and clear bits, we
* must hold irq_lock to avoid a race with enable/disable_vblank().
*/
spin_lock_irqsave(&vop->irq_lock, flags);
- intr0_reg = vop_readl(vop, INTR_CTRL0);
- active_irqs = intr0_reg & INTR_MASK;
+
+ active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK);
/* Clear all active interrupt sources */
if (active_irqs)
- vop_writel(vop, INTR_CTRL0,
- intr0_reg | (active_irqs << INTR_CLR_SHIFT));
+ VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1);
+
spin_unlock_irqrestore(&vop->irq_lock, flags);
/* This is expected for vop iommu irqs, since the irq is shared */
@@ -1438,9 +1088,10 @@ static irqreturn_t vop_isr(int irq, void *data)
}
if (active_irqs & FS_INTR) {
- drm_handle_vblank(vop->drm_dev, vop->pipe);
+ drm_crtc_handle_vblank(crtc);
+ vop_handle_vblank(vop);
active_irqs &= ~FS_INTR;
- ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+ ret = IRQ_HANDLED;
}
/* Unhandled irqs are spurious. */
@@ -1478,13 +1129,14 @@ static int vop_create_crtc(struct vop *vop)
0, &vop_plane_funcs,
win_data->phy->data_formats,
win_data->phy->nformats,
- win_data->type);
+ win_data->type, NULL);
if (ret) {
DRM_ERROR("failed to initialize plane\n");
goto err_cleanup_planes;
}
plane = &vop_win->base;
+ drm_plane_helper_add(plane, &plane_helper_funcs);
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
primary = plane;
else if (plane->type == DRM_PLANE_TYPE_CURSOR)
@@ -1492,7 +1144,7 @@ static int vop_create_crtc(struct vop *vop)
}
ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
- &vop_crtc_funcs);
+ &vop_crtc_funcs, NULL);
if (ret)
return ret;
@@ -1515,11 +1167,12 @@ static int vop_create_crtc(struct vop *vop)
&vop_plane_funcs,
win_data->phy->data_formats,
win_data->phy->nformats,
- win_data->type);
+ win_data->type, NULL);
if (ret) {
DRM_ERROR("failed to initialize overlay plane\n");
goto err_cleanup_crtc;
}
+ drm_plane_helper_add(&vop_win->base, &plane_helper_funcs);
}
port = of_get_child_by_name(dev->of_node, "port");
@@ -1530,9 +1183,9 @@ static int vop_create_crtc(struct vop *vop)
}
init_completion(&vop->dsp_hold_completion);
+ init_completion(&vop->wait_update_complete);
crtc->port = port;
- vop->pipe = drm_crtc_index(crtc);
- rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);
+ rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);
return 0;
@@ -1548,7 +1201,7 @@ static void vop_destroy_crtc(struct vop *vop)
{
struct drm_crtc *crtc = &vop->crtc;
- rockchip_unregister_crtc_funcs(vop->drm_dev, vop->pipe);
+ rockchip_unregister_crtc_funcs(crtc);
of_node_put(crtc->port);
drm_crtc_cleanup(crtc);
}
@@ -1664,14 +1317,12 @@ static void vop_win_init(struct vop *vop)
vop_win->data = win_data;
vop_win->vop = vop;
- INIT_LIST_HEAD(&vop_win->pending);
}
}
static int vop_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id;
const struct vop_data *vop_data;
struct drm_device *drm_dev = data;
struct vop *vop;
@@ -1679,8 +1330,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
size_t alloc_size;
int ret, irq;
- of_id = of_match_device(vop_driver_dt_match, dev);
- vop_data = of_id->data;
+ vop_data = of_device_get_match_data(dev);
if (!vop_data)
return -ENODEV;
@@ -1725,8 +1375,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
mutex_init(&vop->vsync_mutex);
- ret = devm_request_threaded_irq(dev, vop->irq, vop_isr, vop_isr_thread,
- IRQF_SHARED, dev_name(dev), vop);
+ ret = devm_request_irq(dev, vop->irq, vop_isr,
+ IRQF_SHARED, dev_name(dev), vop);
if (ret)
return ret;
@@ -1749,42 +1399,8 @@ static void vop_unbind(struct device *dev, struct device *master, void *data)
vop_destroy_crtc(vop);
}
-static const struct component_ops vop_component_ops = {
+const struct component_ops vop_component_ops = {
.bind = vop_bind,
.unbind = vop_unbind,
};
-
-static int vop_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
-
- if (!dev->of_node) {
- dev_err(dev, "can't find vop devices\n");
- return -ENODEV;
- }
-
- return component_add(dev, &vop_component_ops);
-}
-
-static int vop_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &vop_component_ops);
-
- return 0;
-}
-
-struct platform_driver vop_platform_driver = {
- .probe = vop_probe,
- .remove = vop_remove,
- .driver = {
- .name = "rockchip-vop",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(vop_driver_dt_match),
- },
-};
-
-module_platform_driver(vop_platform_driver);
-
-MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
-MODULE_DESCRIPTION("ROCKCHIP VOP Driver");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_GPL(vop_component_ops);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index a2d4ddb896fa..071ff0be7a95 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -15,111 +15,125 @@
#ifndef _ROCKCHIP_DRM_VOP_H
#define _ROCKCHIP_DRM_VOP_H
-/* register definition */
-#define REG_CFG_DONE 0x0000
-#define VERSION_INFO 0x0004
-#define SYS_CTRL 0x0008
-#define SYS_CTRL1 0x000c
-#define DSP_CTRL0 0x0010
-#define DSP_CTRL1 0x0014
-#define DSP_BG 0x0018
-#define MCU_CTRL 0x001c
-#define INTR_CTRL0 0x0020
-#define INTR_CTRL1 0x0024
-#define WIN0_CTRL0 0x0030
-#define WIN0_CTRL1 0x0034
-#define WIN0_COLOR_KEY 0x0038
-#define WIN0_VIR 0x003c
-#define WIN0_YRGB_MST 0x0040
-#define WIN0_CBR_MST 0x0044
-#define WIN0_ACT_INFO 0x0048
-#define WIN0_DSP_INFO 0x004c
-#define WIN0_DSP_ST 0x0050
-#define WIN0_SCL_FACTOR_YRGB 0x0054
-#define WIN0_SCL_FACTOR_CBR 0x0058
-#define WIN0_SCL_OFFSET 0x005c
-#define WIN0_SRC_ALPHA_CTRL 0x0060
-#define WIN0_DST_ALPHA_CTRL 0x0064
-#define WIN0_FADING_CTRL 0x0068
-/* win1 register */
-#define WIN1_CTRL0 0x0070
-#define WIN1_CTRL1 0x0074
-#define WIN1_COLOR_KEY 0x0078
-#define WIN1_VIR 0x007c
-#define WIN1_YRGB_MST 0x0080
-#define WIN1_CBR_MST 0x0084
-#define WIN1_ACT_INFO 0x0088
-#define WIN1_DSP_INFO 0x008c
-#define WIN1_DSP_ST 0x0090
-#define WIN1_SCL_FACTOR_YRGB 0x0094
-#define WIN1_SCL_FACTOR_CBR 0x0098
-#define WIN1_SCL_OFFSET 0x009c
-#define WIN1_SRC_ALPHA_CTRL 0x00a0
-#define WIN1_DST_ALPHA_CTRL 0x00a4
-#define WIN1_FADING_CTRL 0x00a8
-/* win2 register */
-#define WIN2_CTRL0 0x00b0
-#define WIN2_CTRL1 0x00b4
-#define WIN2_VIR0_1 0x00b8
-#define WIN2_VIR2_3 0x00bc
-#define WIN2_MST0 0x00c0
-#define WIN2_DSP_INFO0 0x00c4
-#define WIN2_DSP_ST0 0x00c8
-#define WIN2_COLOR_KEY 0x00cc
-#define WIN2_MST1 0x00d0
-#define WIN2_DSP_INFO1 0x00d4
-#define WIN2_DSP_ST1 0x00d8
-#define WIN2_SRC_ALPHA_CTRL 0x00dc
-#define WIN2_MST2 0x00e0
-#define WIN2_DSP_INFO2 0x00e4
-#define WIN2_DSP_ST2 0x00e8
-#define WIN2_DST_ALPHA_CTRL 0x00ec
-#define WIN2_MST3 0x00f0
-#define WIN2_DSP_INFO3 0x00f4
-#define WIN2_DSP_ST3 0x00f8
-#define WIN2_FADING_CTRL 0x00fc
-/* win3 register */
-#define WIN3_CTRL0 0x0100
-#define WIN3_CTRL1 0x0104
-#define WIN3_VIR0_1 0x0108
-#define WIN3_VIR2_3 0x010c
-#define WIN3_MST0 0x0110
-#define WIN3_DSP_INFO0 0x0114
-#define WIN3_DSP_ST0 0x0118
-#define WIN3_COLOR_KEY 0x011c
-#define WIN3_MST1 0x0120
-#define WIN3_DSP_INFO1 0x0124
-#define WIN3_DSP_ST1 0x0128
-#define WIN3_SRC_ALPHA_CTRL 0x012c
-#define WIN3_MST2 0x0130
-#define WIN3_DSP_INFO2 0x0134
-#define WIN3_DSP_ST2 0x0138
-#define WIN3_DST_ALPHA_CTRL 0x013c
-#define WIN3_MST3 0x0140
-#define WIN3_DSP_INFO3 0x0144
-#define WIN3_DSP_ST3 0x0148
-#define WIN3_FADING_CTRL 0x014c
-/* hwc register */
-#define HWC_CTRL0 0x0150
-#define HWC_CTRL1 0x0154
-#define HWC_MST 0x0158
-#define HWC_DSP_ST 0x015c
-#define HWC_SRC_ALPHA_CTRL 0x0160
-#define HWC_DST_ALPHA_CTRL 0x0164
-#define HWC_FADING_CTRL 0x0168
-/* post process register */
-#define POST_DSP_HACT_INFO 0x0170
-#define POST_DSP_VACT_INFO 0x0174
-#define POST_SCL_FACTOR_YRGB 0x0178
-#define POST_SCL_CTRL 0x0180
-#define POST_DSP_VACT_INFO_F1 0x0184
-#define DSP_HTOTAL_HS_END 0x0188
-#define DSP_HACT_ST_END 0x018c
-#define DSP_VTOTAL_VS_END 0x0190
-#define DSP_VACT_ST_END 0x0194
-#define DSP_VS_ST_END_F1 0x0198
-#define DSP_VACT_ST_END_F1 0x019c
-/* register definition end */
+enum vop_data_format {
+ VOP_FMT_ARGB8888 = 0,
+ VOP_FMT_RGB888,
+ VOP_FMT_RGB565,
+ VOP_FMT_YUV420SP = 4,
+ VOP_FMT_YUV422SP,
+ VOP_FMT_YUV444SP,
+};
+
+struct vop_reg_data {
+ uint32_t offset;
+ uint32_t value;
+};
+
+struct vop_reg {
+ uint32_t offset;
+ uint32_t shift;
+ uint32_t mask;
+};
+
+struct vop_ctrl {
+ struct vop_reg standby;
+ struct vop_reg data_blank;
+ struct vop_reg gate_en;
+ struct vop_reg mmu_en;
+ struct vop_reg rgb_en;
+ struct vop_reg edp_en;
+ struct vop_reg hdmi_en;
+ struct vop_reg mipi_en;
+ struct vop_reg out_mode;
+ struct vop_reg dither_down;
+ struct vop_reg dither_up;
+ struct vop_reg pin_pol;
+
+ struct vop_reg htotal_pw;
+ struct vop_reg hact_st_end;
+ struct vop_reg vtotal_pw;
+ struct vop_reg vact_st_end;
+ struct vop_reg hpost_st_end;
+ struct vop_reg vpost_st_end;
+
+ struct vop_reg cfg_done;
+};
+
+struct vop_intr {
+ const int *intrs;
+ uint32_t nintrs;
+ struct vop_reg enable;
+ struct vop_reg clear;
+ struct vop_reg status;
+};
+
+struct vop_scl_extension {
+ struct vop_reg cbcr_vsd_mode;
+ struct vop_reg cbcr_vsu_mode;
+ struct vop_reg cbcr_hsd_mode;
+ struct vop_reg cbcr_ver_scl_mode;
+ struct vop_reg cbcr_hor_scl_mode;
+ struct vop_reg yrgb_vsd_mode;
+ struct vop_reg yrgb_vsu_mode;
+ struct vop_reg yrgb_hsd_mode;
+ struct vop_reg yrgb_ver_scl_mode;
+ struct vop_reg yrgb_hor_scl_mode;
+ struct vop_reg line_load_mode;
+ struct vop_reg cbcr_axi_gather_num;
+ struct vop_reg yrgb_axi_gather_num;
+ struct vop_reg vsd_cbcr_gt2;
+ struct vop_reg vsd_cbcr_gt4;
+ struct vop_reg vsd_yrgb_gt2;
+ struct vop_reg vsd_yrgb_gt4;
+ struct vop_reg bic_coe_sel;
+ struct vop_reg cbcr_axi_gather_en;
+ struct vop_reg yrgb_axi_gather_en;
+ struct vop_reg lb_mode;
+};
+
+struct vop_scl_regs {
+ const struct vop_scl_extension *ext;
+
+ struct vop_reg scale_yrgb_x;
+ struct vop_reg scale_yrgb_y;
+ struct vop_reg scale_cbcr_x;
+ struct vop_reg scale_cbcr_y;
+};
+
+struct vop_win_phy {
+ const struct vop_scl_regs *scl;
+ const uint32_t *data_formats;
+ uint32_t nformats;
+
+ struct vop_reg enable;
+ struct vop_reg format;
+ struct vop_reg rb_swap;
+ struct vop_reg act_info;
+ struct vop_reg dsp_info;
+ struct vop_reg dsp_st;
+ struct vop_reg yrgb_mst;
+ struct vop_reg uv_mst;
+ struct vop_reg yrgb_vir;
+ struct vop_reg uv_vir;
+
+ struct vop_reg dst_alpha_ctl;
+ struct vop_reg src_alpha_ctl;
+};
+
+struct vop_win_data {
+ uint32_t base;
+ const struct vop_win_phy *phy;
+ enum drm_plane_type type;
+};
+
+struct vop_data {
+ const struct vop_reg_data *init_table;
+ unsigned int table_size;
+ const struct vop_ctrl *ctrl;
+ const struct vop_intr *intr;
+ const struct vop_win_data *win;
+ unsigned int win_size;
+};
/* interrupt define */
#define DSP_HOLD_VALID_INTR (1 << 0)
@@ -233,6 +247,11 @@ static inline uint16_t scl_cal_scale(int src, int dst, int shift)
return ((src * 2 - 3) << (shift - 1)) / (dst - 1);
}
+static inline uint16_t scl_cal_scale2(int src, int dst)
+{
+ return ((src - 1) << 12) / (dst - 1);
+}
+
#define GET_SCL_FT_BILI_DN(src, dst) scl_cal_scale(src, dst, 12)
#define GET_SCL_FT_BILI_UP(src, dst) scl_cal_scale(src, dst, 16)
#define GET_SCL_FT_BIC(src, dst) scl_cal_scale(src, dst, 16)
@@ -286,4 +305,5 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
return lb_mode;
}
+extern const struct component_ops vop_component_ops;
#endif /* _ROCKCHIP_DRM_VOP_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
new file mode 100644
index 000000000000..3166b46a5893
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+
+#include <linux/kernel.h>
+#include <linux/component.h>
+
+#include "rockchip_drm_vop.h"
+#include "rockchip_vop_reg.h"
+
+#define VOP_REG(off, _mask, s) \
+ {.offset = off, \
+ .mask = _mask, \
+ .shift = s,}
+
+static const uint32_t formats_win_full[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV24,
+};
+
+static const uint32_t formats_win_lite[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR565,
+};
+
+static const struct vop_scl_extension rk3288_win_full_scl_ext = {
+ .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
+ .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
+ .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
+ .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
+ .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
+ .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
+ .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
+ .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
+ .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
+ .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
+ .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
+ .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
+ .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
+ .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
+ .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
+ .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
+ .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
+ .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
+ .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
+ .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
+ .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
+};
+
+static const struct vop_scl_regs rk3288_win_full_scl = {
+ .ext = &rk3288_win_full_scl_ext,
+ .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
+ .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
+ .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
+ .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
+};
+
+static const struct vop_win_phy rk3288_win01_data = {
+ .scl = &rk3288_win_full_scl,
+ .data_formats = formats_win_full,
+ .nformats = ARRAY_SIZE(formats_win_full),
+ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
+ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
+ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
+ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
+ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
+ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
+ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
+ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
+ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
+ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
+ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+};
+
+static const struct vop_win_phy rk3288_win23_data = {
+ .data_formats = formats_win_lite,
+ .nformats = ARRAY_SIZE(formats_win_lite),
+ .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
+ .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
+ .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
+ .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
+ .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
+ .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
+ .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
+ .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
+ .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
+};
+
+static const struct vop_ctrl rk3288_ctrl_data = {
+ .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22),
+ .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
+ .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
+ .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
+ .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),
+ .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
+ .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
+ .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
+ .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
+ .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
+ .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
+ .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
+ .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
+ .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
+ .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
+ .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
+ .cfg_done = VOP_REG(RK3288_REG_CFG_DONE, 0x1, 0),
+};
+
+static const struct vop_reg_data rk3288_init_reg_table[] = {
+ {RK3288_SYS_CTRL, 0x00c00000},
+ {RK3288_DSP_CTRL0, 0x00000000},
+ {RK3288_WIN0_CTRL0, 0x00000080},
+ {RK3288_WIN1_CTRL0, 0x00000080},
+ /* TODO: Win2/3 support multiple area function, but we haven't found
+ * a suitable way to use it yet, so let's just use them as other windows
+ * with only area 0 enabled.
+ */
+ {RK3288_WIN2_CTRL0, 0x00000010},
+ {RK3288_WIN3_CTRL0, 0x00000010},
+};
+
+/*
+ * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
+ * special support to get alpha blending working. For now, just use overlay
+ * window 3 for the drm cursor.
+ *
+ */
+static const struct vop_win_data rk3288_vop_win_data[] = {
+ { .base = 0x00, .phy = &rk3288_win01_data,
+ .type = DRM_PLANE_TYPE_PRIMARY },
+ { .base = 0x40, .phy = &rk3288_win01_data,
+ .type = DRM_PLANE_TYPE_OVERLAY },
+ { .base = 0x00, .phy = &rk3288_win23_data,
+ .type = DRM_PLANE_TYPE_OVERLAY },
+ { .base = 0x50, .phy = &rk3288_win23_data,
+ .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const int rk3288_vop_intrs[] = {
+ DSP_HOLD_VALID_INTR,
+ FS_INTR,
+ LINE_FLAG_INTR,
+ BUS_ERROR_INTR,
+};
+
+static const struct vop_intr rk3288_vop_intr = {
+ .intrs = rk3288_vop_intrs,
+ .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
+ .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
+ .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
+ .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
+};
+
+static const struct vop_data rk3288_vop = {
+ .init_table = rk3288_init_reg_table,
+ .table_size = ARRAY_SIZE(rk3288_init_reg_table),
+ .intr = &rk3288_vop_intr,
+ .ctrl = &rk3288_ctrl_data,
+ .win = rk3288_vop_win_data,
+ .win_size = ARRAY_SIZE(rk3288_vop_win_data),
+};
+
+static const struct vop_scl_regs rk3066_win_scl = {
+ .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
+ .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
+ .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
+ .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
+};
+
+static const struct vop_win_phy rk3036_win0_data = {
+ .scl = &rk3066_win_scl,
+ .data_formats = formats_win_full,
+ .nformats = ARRAY_SIZE(formats_win_full),
+ .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
+ .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
+ .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
+ .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
+ .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
+ .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
+ .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
+ .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
+ .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
+};
+
+static const struct vop_win_phy rk3036_win1_data = {
+ .data_formats = formats_win_lite,
+ .nformats = ARRAY_SIZE(formats_win_lite),
+ .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
+ .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
+ .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
+ .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
+ .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
+ .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
+ .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
+ .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
+};
+
+static const struct vop_win_data rk3036_vop_win_data[] = {
+ { .base = 0x00, .phy = &rk3036_win0_data,
+ .type = DRM_PLANE_TYPE_PRIMARY },
+ { .base = 0x00, .phy = &rk3036_win1_data,
+ .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const int rk3036_vop_intrs[] = {
+ DSP_HOLD_VALID_INTR,
+ FS_INTR,
+ LINE_FLAG_INTR,
+ BUS_ERROR_INTR,
+};
+
+static const struct vop_intr rk3036_intr = {
+ .intrs = rk3036_vop_intrs,
+ .nintrs = ARRAY_SIZE(rk3036_vop_intrs),
+ .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0),
+ .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4),
+ .clear = VOP_REG(RK3036_INT_STATUS, 0xf, 8),
+};
+
+static const struct vop_ctrl rk3036_ctrl_data = {
+ .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30),
+ .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
+ .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
+ .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
+ .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
+ .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
+ .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
+ .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0),
+};
+
+static const struct vop_reg_data rk3036_vop_init_reg_table[] = {
+ {RK3036_DSP_CTRL1, 0x00000000},
+};
+
+static const struct vop_data rk3036_vop = {
+ .init_table = rk3036_vop_init_reg_table,
+ .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
+ .ctrl = &rk3036_ctrl_data,
+ .intr = &rk3036_intr,
+ .win = rk3036_vop_win_data,
+ .win_size = ARRAY_SIZE(rk3036_vop_win_data),
+};
+
+static const struct of_device_id vop_driver_dt_match[] = {
+ { .compatible = "rockchip,rk3288-vop",
+ .data = &rk3288_vop },
+ { .compatible = "rockchip,rk3036-vop",
+ .data = &rk3036_vop },
+ {},
+};
+MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
+
+static int vop_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!dev->of_node) {
+ dev_err(dev, "can't find vop devices\n");
+ return -ENODEV;
+ }
+
+ return component_add(dev, &vop_component_ops);
+}
+
+static int vop_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &vop_component_ops);
+
+ return 0;
+}
+
+struct platform_driver vop_platform_driver = {
+ .probe = vop_probe,
+ .remove = vop_remove,
+ .driver = {
+ .name = "rockchip-vop",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(vop_driver_dt_match),
+ },
+};
+
+module_platform_driver(vop_platform_driver);
+
+MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
+MODULE_DESCRIPTION("ROCKCHIP VOP Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
new file mode 100644
index 000000000000..d4b46cba2f26
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:Mark Yao <mark.yao@rock-chips.com>
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_VOP_REG_H
+#define _ROCKCHIP_VOP_REG_H
+
+/* rk3288 register definition */
+#define RK3288_REG_CFG_DONE 0x0000
+#define RK3288_VERSION_INFO 0x0004
+#define RK3288_SYS_CTRL 0x0008
+#define RK3288_SYS_CTRL1 0x000c
+#define RK3288_DSP_CTRL0 0x0010
+#define RK3288_DSP_CTRL1 0x0014
+#define RK3288_DSP_BG 0x0018
+#define RK3288_MCU_CTRL 0x001c
+#define RK3288_INTR_CTRL0 0x0020
+#define RK3288_INTR_CTRL1 0x0024
+#define RK3288_WIN0_CTRL0 0x0030
+#define RK3288_WIN0_CTRL1 0x0034
+#define RK3288_WIN0_COLOR_KEY 0x0038
+#define RK3288_WIN0_VIR 0x003c
+#define RK3288_WIN0_YRGB_MST 0x0040
+#define RK3288_WIN0_CBR_MST 0x0044
+#define RK3288_WIN0_ACT_INFO 0x0048
+#define RK3288_WIN0_DSP_INFO 0x004c
+#define RK3288_WIN0_DSP_ST 0x0050
+#define RK3288_WIN0_SCL_FACTOR_YRGB 0x0054
+#define RK3288_WIN0_SCL_FACTOR_CBR 0x0058
+#define RK3288_WIN0_SCL_OFFSET 0x005c
+#define RK3288_WIN0_SRC_ALPHA_CTRL 0x0060
+#define RK3288_WIN0_DST_ALPHA_CTRL 0x0064
+#define RK3288_WIN0_FADING_CTRL 0x0068
+
+/* win1 register */
+#define RK3288_WIN1_CTRL0 0x0070
+#define RK3288_WIN1_CTRL1 0x0074
+#define RK3288_WIN1_COLOR_KEY 0x0078
+#define RK3288_WIN1_VIR 0x007c
+#define RK3288_WIN1_YRGB_MST 0x0080
+#define RK3288_WIN1_CBR_MST 0x0084
+#define RK3288_WIN1_ACT_INFO 0x0088
+#define RK3288_WIN1_DSP_INFO 0x008c
+#define RK3288_WIN1_DSP_ST 0x0090
+#define RK3288_WIN1_SCL_FACTOR_YRGB 0x0094
+#define RK3288_WIN1_SCL_FACTOR_CBR 0x0098
+#define RK3288_WIN1_SCL_OFFSET 0x009c
+#define RK3288_WIN1_SRC_ALPHA_CTRL 0x00a0
+#define RK3288_WIN1_DST_ALPHA_CTRL 0x00a4
+#define RK3288_WIN1_FADING_CTRL 0x00a8
+/* win2 register */
+#define RK3288_WIN2_CTRL0 0x00b0
+#define RK3288_WIN2_CTRL1 0x00b4
+#define RK3288_WIN2_VIR0_1 0x00b8
+#define RK3288_WIN2_VIR2_3 0x00bc
+#define RK3288_WIN2_MST0 0x00c0
+#define RK3288_WIN2_DSP_INFO0 0x00c4
+#define RK3288_WIN2_DSP_ST0 0x00c8
+#define RK3288_WIN2_COLOR_KEY 0x00cc
+#define RK3288_WIN2_MST1 0x00d0
+#define RK3288_WIN2_DSP_INFO1 0x00d4
+#define RK3288_WIN2_DSP_ST1 0x00d8
+#define RK3288_WIN2_SRC_ALPHA_CTRL 0x00dc
+#define RK3288_WIN2_MST2 0x00e0
+#define RK3288_WIN2_DSP_INFO2 0x00e4
+#define RK3288_WIN2_DSP_ST2 0x00e8
+#define RK3288_WIN2_DST_ALPHA_CTRL 0x00ec
+#define RK3288_WIN2_MST3 0x00f0
+#define RK3288_WIN2_DSP_INFO3 0x00f4
+#define RK3288_WIN2_DSP_ST3 0x00f8
+#define RK3288_WIN2_FADING_CTRL 0x00fc
+/* win3 register */
+#define RK3288_WIN3_CTRL0 0x0100
+#define RK3288_WIN3_CTRL1 0x0104
+#define RK3288_WIN3_VIR0_1 0x0108
+#define RK3288_WIN3_VIR2_3 0x010c
+#define RK3288_WIN3_MST0 0x0110
+#define RK3288_WIN3_DSP_INFO0 0x0114
+#define RK3288_WIN3_DSP_ST0 0x0118
+#define RK3288_WIN3_COLOR_KEY 0x011c
+#define RK3288_WIN3_MST1 0x0120
+#define RK3288_WIN3_DSP_INFO1 0x0124
+#define RK3288_WIN3_DSP_ST1 0x0128
+#define RK3288_WIN3_SRC_ALPHA_CTRL 0x012c
+#define RK3288_WIN3_MST2 0x0130
+#define RK3288_WIN3_DSP_INFO2 0x0134
+#define RK3288_WIN3_DSP_ST2 0x0138
+#define RK3288_WIN3_DST_ALPHA_CTRL 0x013c
+#define RK3288_WIN3_MST3 0x0140
+#define RK3288_WIN3_DSP_INFO3 0x0144
+#define RK3288_WIN3_DSP_ST3 0x0148
+#define RK3288_WIN3_FADING_CTRL 0x014c
+/* hwc register */
+#define RK3288_HWC_CTRL0 0x0150
+#define RK3288_HWC_CTRL1 0x0154
+#define RK3288_HWC_MST 0x0158
+#define RK3288_HWC_DSP_ST 0x015c
+#define RK3288_HWC_SRC_ALPHA_CTRL 0x0160
+#define RK3288_HWC_DST_ALPHA_CTRL 0x0164
+#define RK3288_HWC_FADING_CTRL 0x0168
+/* post process register */
+#define RK3288_POST_DSP_HACT_INFO 0x0170
+#define RK3288_POST_DSP_VACT_INFO 0x0174
+#define RK3288_POST_SCL_FACTOR_YRGB 0x0178
+#define RK3288_POST_SCL_CTRL 0x0180
+#define RK3288_POST_DSP_VACT_INFO_F1 0x0184
+#define RK3288_DSP_HTOTAL_HS_END 0x0188
+#define RK3288_DSP_HACT_ST_END 0x018c
+#define RK3288_DSP_VTOTAL_VS_END 0x0190
+#define RK3288_DSP_VACT_ST_END 0x0194
+#define RK3288_DSP_VS_ST_END_F1 0x0198
+#define RK3288_DSP_VACT_ST_END_F1 0x019c
+/* register definition end */
+
+/* rk3036 register definition */
+#define RK3036_SYS_CTRL 0x00
+#define RK3036_DSP_CTRL0 0x04
+#define RK3036_DSP_CTRL1 0x08
+#define RK3036_INT_STATUS 0x10
+#define RK3036_ALPHA_CTRL 0x14
+#define RK3036_WIN0_COLOR_KEY 0x18
+#define RK3036_WIN1_COLOR_KEY 0x1c
+#define RK3036_WIN0_YRGB_MST 0x20
+#define RK3036_WIN0_CBR_MST 0x24
+#define RK3036_WIN1_VIR 0x28
+#define RK3036_AXI_BUS_CTRL 0x2c
+#define RK3036_WIN0_VIR 0x30
+#define RK3036_WIN0_ACT_INFO 0x34
+#define RK3036_WIN0_DSP_INFO 0x38
+#define RK3036_WIN0_DSP_ST 0x3c
+#define RK3036_WIN0_SCL_FACTOR_YRGB 0x40
+#define RK3036_WIN0_SCL_FACTOR_CBR 0x44
+#define RK3036_WIN0_SCL_OFFSET 0x48
+#define RK3036_HWC_MST 0x58
+#define RK3036_HWC_DSP_ST 0x5c
+#define RK3036_DSP_HTOTAL_HS_END 0x6c
+#define RK3036_DSP_HACT_ST_END 0x70
+#define RK3036_DSP_VTOTAL_VS_END 0x74
+#define RK3036_DSP_VACT_ST_END 0x78
+#define RK3036_DSP_VS_ST_END_F1 0x7c
+#define RK3036_DSP_VACT_ST_END_F1 0x80
+#define RK3036_GATHER_TRANSFER 0x84
+#define RK3036_VERSION_INFO 0x94
+#define RK3036_REG_CFG_DONE 0x90
+#define RK3036_WIN1_MST 0xa0
+#define RK3036_WIN1_ACT_INFO 0xb4
+#define RK3036_WIN1_DSP_INFO 0xb8
+#define RK3036_WIN1_DSP_ST 0xbc
+#define RK3036_WIN1_SCL_FACTOR_YRGB 0xc0
+#define RK3036_WIN1_SCL_OFFSET 0xc8
+#define RK3036_BCSH_CTRL 0xd0
+#define RK3036_BCSH_COLOR_BAR 0xd4
+#define RK3036_BCSH_BCS 0xd8
+#define RK3036_BCSH_H 0xdc
+#define RK3036_WIN1_LUT_ADDR 0x400
+#define RK3036_HWC_LUT_ADDR 0x800
+/* rk3036 register definition end */
+
+#endif /* _ROCKCHIP_VOP_REG_H */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index e9272b0a8592..db0763794edc 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -613,7 +613,7 @@ int shmob_drm_encoder_create(struct shmob_drm_device *sdev)
encoder->possible_crtcs = 1;
ret = drm_encoder_init(sdev->ddev, encoder, &encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
if (ret < 0)
return ret;
@@ -739,8 +739,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
if (ret < 0)
goto err_backlight;
- connector->encoder = encoder;
-
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
drm_object_property_set_value(&connector->base,
sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
index aaf98ace4a90..388a0fc13564 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
@@ -104,7 +104,7 @@ const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc)
static struct drm_framebuffer *
shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
const struct shmob_drm_format_info *format;
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 3ae09dcd4fd8..de11c7cfb02f 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -367,7 +367,7 @@ int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
int res;
res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
- &sti_crtc_funcs);
+ &sti_crtc_funcs, NULL);
if (res) {
DRM_ERROR("Can't initialze CRTC\n");
return -EINVAL;
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index dd1032195051..807863106b8d 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -272,7 +272,7 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
&sti_plane_helpers_funcs,
cursor_supported_formats,
ARRAY_SIZE(cursor_supported_formats),
- DRM_PLANE_TYPE_CURSOR);
+ DRM_PLANE_TYPE_CURSOR, NULL);
if (res) {
DRM_ERROR("Failed to initialize universal plane\n");
goto err_plane;
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 1469987949d8..506b5626f3ed 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -160,6 +160,7 @@ static int sti_load(struct drm_device *dev, unsigned long flags)
drm_mode_config_reset(dev);
+ drm_helper_disable_unused_functions(dev);
drm_fbdev_cma_init(dev, 32,
dev->mode_config.num_crtc,
dev->mode_config.num_connector);
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index c85dc7d6b005..f9a1d92c9d95 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -630,7 +630,7 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
&sti_plane_helpers_funcs,
gdp_supported_formats,
ARRAY_SIZE(gdp_supported_formats),
- type);
+ type, NULL);
if (res) {
DRM_ERROR("Failed to initialize universal plane\n");
goto err;
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index d735daccd458..49cce833f2c8 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -543,8 +543,6 @@ static int sti_hda_connector_get_modes(struct drm_connector *connector)
count++;
}
- drm_mode_sort(&connector->modes);
-
return count;
}
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index ea0690bc77d5..43861b52261d 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -973,7 +973,7 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
&sti_plane_helpers_funcs,
hqvdp_supported_formats,
ARRAY_SIZE(hqvdp_supported_formats),
- DRM_PLANE_TYPE_OVERLAY);
+ DRM_PLANE_TYPE_OVERLAY, NULL);
if (res) {
DRM_ERROR("Failed to initialize universal plane\n");
return NULL;
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index c8a4c5dae2b6..f2afcf5438b8 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -512,7 +512,8 @@ sti_tvout_create_dvo_encoder(struct drm_device *dev,
drm_encoder->possible_clones = 1 << 0;
drm_encoder_init(dev, drm_encoder,
- &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS);
+ &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS,
+ NULL);
drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs);
@@ -564,7 +565,7 @@ static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev,
drm_encoder->possible_clones = 1 << 0;
drm_encoder_init(dev, drm_encoder,
- &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC);
+ &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL);
drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs);
@@ -613,7 +614,7 @@ static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev,
drm_encoder->possible_clones = 1 << 1;
drm_encoder_init(dev, drm_encoder,
- &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS);
+ &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index 74d9d621453d..63ebb154b9b5 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -16,18 +16,6 @@ config DRM_TEGRA
if DRM_TEGRA
-config DRM_TEGRA_FBDEV
- bool "Enable legacy fbdev support"
- select DRM_KMS_FB_HELPER
- select FB_SYS_FILLRECT
- select FB_SYS_COPYAREA
- select FB_SYS_IMAGEBLIT
- default y
- help
- Choose this option if you have a need for the legacy fbdev support.
- Note that this support also provides the Linux console on top of
- the Tegra modesetting driver.
-
config DRM_TEGRA_DEBUG
bool "NVIDIA Tegra DRM debug support"
help
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index e9f24a85a103..dde6f208c347 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -660,7 +660,8 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
&tegra_primary_plane_funcs, formats,
- num_formats, DRM_PLANE_TYPE_PRIMARY);
+ num_formats, DRM_PLANE_TYPE_PRIMARY,
+ NULL);
if (err < 0) {
kfree(plane);
return ERR_PTR(err);
@@ -827,7 +828,8 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
&tegra_cursor_plane_funcs, formats,
- num_formats, DRM_PLANE_TYPE_CURSOR);
+ num_formats, DRM_PLANE_TYPE_CURSOR,
+ NULL);
if (err < 0) {
kfree(plane);
return ERR_PTR(err);
@@ -890,7 +892,8 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
&tegra_overlay_plane_funcs, formats,
- num_formats, DRM_PLANE_TYPE_OVERLAY);
+ num_formats, DRM_PLANE_TYPE_OVERLAY,
+ NULL);
if (err < 0) {
kfree(plane);
return ERR_PTR(err);
@@ -1732,7 +1735,7 @@ static int tegra_dc_init(struct host1x_client *client)
}
err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
- &tegra_crtc_funcs);
+ &tegra_crtc_funcs, NULL);
if (err < 0)
goto cleanup;
@@ -1952,8 +1955,10 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
* cases where only a single display controller is used.
*/
for_each_matching_node(np, tegra_dc_of_match) {
- if (np == dc->dev->of_node)
+ if (np == dc->dev->of_node) {
+ of_node_put(np);
break;
+ }
value++;
}
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index 6aecb6647313..b24a0f14821a 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -436,7 +436,7 @@ struct platform_driver tegra_dpaux_driver = {
.remove = tegra_dpaux_remove,
};
-struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np)
+struct drm_dp_aux *drm_dp_aux_find_by_of_node(struct device_node *np)
{
struct tegra_dpaux *dpaux;
@@ -445,7 +445,7 @@ struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np)
list_for_each_entry(dpaux, &dpaux_list, list)
if (np == dpaux->dev->of_node) {
mutex_unlock(&dpaux_lock);
- return dpaux;
+ return &dpaux->aux;
}
mutex_unlock(&dpaux_lock);
@@ -453,8 +453,9 @@ struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np)
return NULL;
}
-int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
+int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output)
{
+ struct tegra_dpaux *dpaux = to_dpaux(aux);
unsigned long timeout;
int err;
@@ -470,7 +471,7 @@ int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
while (time_before(jiffies, timeout)) {
enum drm_connector_status status;
- status = tegra_dpaux_detect(dpaux);
+ status = drm_dp_aux_detect(aux);
if (status == connector_status_connected) {
enable_irq(dpaux->irq);
return 0;
@@ -482,8 +483,9 @@ int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
return -ETIMEDOUT;
}
-int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
+int drm_dp_aux_detach(struct drm_dp_aux *aux)
{
+ struct tegra_dpaux *dpaux = to_dpaux(aux);
unsigned long timeout;
int err;
@@ -498,7 +500,7 @@ int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
while (time_before(jiffies, timeout)) {
enum drm_connector_status status;
- status = tegra_dpaux_detect(dpaux);
+ status = drm_dp_aux_detect(aux);
if (status == connector_status_disconnected) {
dpaux->output = NULL;
return 0;
@@ -510,8 +512,9 @@ int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
return -ETIMEDOUT;
}
-enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux)
+enum drm_connector_status drm_dp_aux_detect(struct drm_dp_aux *aux)
{
+ struct tegra_dpaux *dpaux = to_dpaux(aux);
u32 value;
value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
@@ -522,8 +525,9 @@ enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux)
return connector_status_disconnected;
}
-int tegra_dpaux_enable(struct tegra_dpaux *dpaux)
+int drm_dp_aux_enable(struct drm_dp_aux *aux)
{
+ struct tegra_dpaux *dpaux = to_dpaux(aux);
u32 value;
value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) |
@@ -540,8 +544,9 @@ int tegra_dpaux_enable(struct tegra_dpaux *dpaux)
return 0;
}
-int tegra_dpaux_disable(struct tegra_dpaux *dpaux)
+int drm_dp_aux_disable(struct drm_dp_aux *aux)
{
+ struct tegra_dpaux *dpaux = to_dpaux(aux);
u32 value;
value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
@@ -551,11 +556,11 @@ int tegra_dpaux_disable(struct tegra_dpaux *dpaux)
return 0;
}
-int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding)
+int drm_dp_aux_prepare(struct drm_dp_aux *aux, u8 encoding)
{
int err;
- err = drm_dp_dpcd_writeb(&dpaux->aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
+ err = drm_dp_dpcd_writeb(aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
encoding);
if (err < 0)
return err;
@@ -563,15 +568,15 @@ int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding)
return 0;
}
-int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
- u8 pattern)
+int drm_dp_aux_train(struct drm_dp_aux *aux, struct drm_dp_link *link,
+ u8 pattern)
{
u8 tp = pattern & DP_TRAINING_PATTERN_MASK;
u8 status[DP_LINK_STATUS_SIZE], values[4];
unsigned int i;
int err;
- err = drm_dp_dpcd_writeb(&dpaux->aux, DP_TRAINING_PATTERN_SET, pattern);
+ err = drm_dp_dpcd_writeb(aux, DP_TRAINING_PATTERN_SET, pattern);
if (err < 0)
return err;
@@ -584,14 +589,14 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
DP_TRAIN_MAX_SWING_REACHED |
DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
- err = drm_dp_dpcd_write(&dpaux->aux, DP_TRAINING_LANE0_SET, values,
+ err = drm_dp_dpcd_write(aux, DP_TRAINING_LANE0_SET, values,
link->num_lanes);
if (err < 0)
return err;
usleep_range(500, 1000);
- err = drm_dp_dpcd_read_link_status(&dpaux->aux, status);
+ err = drm_dp_dpcd_read_link_status(aux, status);
if (err < 0)
return err;
@@ -609,11 +614,11 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
break;
default:
- dev_err(dpaux->dev, "unsupported training pattern %u\n", tp);
+ dev_err(aux->dev, "unsupported training pattern %u\n", tp);
return -EINVAL;
}
- err = drm_dp_dpcd_writeb(&dpaux->aux, DP_EDP_CONFIGURATION_SET, 0);
+ err = drm_dp_dpcd_writeb(aux, DP_EDP_CONFIGURATION_SET, 0);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 159ef515cab1..c5c856a0879d 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -106,7 +106,7 @@ static int tegra_atomic_commit(struct drm_device *drm,
static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
.fb_create = tegra_fb_create,
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
.output_poll_changed = tegra_fb_output_poll_changed,
#endif
.atomic_check = drm_atomic_helper_check,
@@ -137,8 +137,8 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
start = geometry->aperture_start;
end = geometry->aperture_end;
- DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n",
- start, end);
+ DRM_DEBUG_DRIVER("IOMMU aperture initialized (%#llx-%#llx)\n",
+ start, end);
drm_mm_init(&tegra->mm, start, end - start + 1);
}
@@ -260,7 +260,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
static void tegra_drm_lastclose(struct drm_device *drm)
{
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_drm *tegra = drm->dev_private;
tegra_fbdev_restore_mode(tegra->fbdev);
@@ -277,9 +277,7 @@ host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle)
if (!gem)
return NULL;
- mutex_lock(&drm->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&drm->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
bo = to_tegra_bo(gem);
return &bo->base;
@@ -473,7 +471,7 @@ static int tegra_gem_mmap(struct drm_device *drm, void *data,
args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
- drm_gem_object_unreference(gem);
+ drm_gem_object_unreference_unlocked(gem);
return 0;
}
@@ -683,7 +681,7 @@ static int tegra_gem_set_tiling(struct drm_device *drm, void *data,
bo->tiling.mode = mode;
bo->tiling.value = value;
- drm_gem_object_unreference(gem);
+ drm_gem_object_unreference_unlocked(gem);
return 0;
}
@@ -723,7 +721,7 @@ static int tegra_gem_get_tiling(struct drm_device *drm, void *data,
break;
}
- drm_gem_object_unreference(gem);
+ drm_gem_object_unreference_unlocked(gem);
return err;
}
@@ -748,7 +746,7 @@ static int tegra_gem_set_flags(struct drm_device *drm, void *data,
if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP)
bo->flags |= TEGRA_BO_BOTTOM_UP;
- drm_gem_object_unreference(gem);
+ drm_gem_object_unreference_unlocked(gem);
return 0;
}
@@ -770,7 +768,7 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data,
if (bo->flags & TEGRA_BO_BOTTOM_UP)
args->flags |= DRM_TEGRA_GEM_BOTTOM_UP;
- drm_gem_object_unreference(gem);
+ drm_gem_object_unreference_unlocked(gem);
return 0;
}
@@ -921,7 +919,8 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor)
#endif
static struct drm_driver tegra_drm_driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
+ DRIVER_ATOMIC,
.load = tegra_drm_load,
.unload = tegra_drm_unload,
.open = tegra_drm_open,
@@ -991,7 +990,6 @@ static int host1x_drm_probe(struct host1x_device *dev)
if (!drm)
return -ENOMEM;
- drm_dev_set_unique(drm, dev_name(&dev->dev));
dev_set_drvdata(&dev->dev, drm);
err = drm_dev_register(drm, 0);
@@ -1023,8 +1021,17 @@ static int host1x_drm_remove(struct host1x_device *dev)
static int host1x_drm_suspend(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
+ struct tegra_drm *tegra = drm->dev_private;
drm_kms_helper_poll_disable(drm);
+ tegra_drm_fb_suspend(drm);
+
+ tegra->state = drm_atomic_helper_suspend(drm);
+ if (IS_ERR(tegra->state)) {
+ tegra_drm_fb_resume(drm);
+ drm_kms_helper_poll_enable(drm);
+ return PTR_ERR(tegra->state);
+ }
return 0;
}
@@ -1032,7 +1039,10 @@ static int host1x_drm_suspend(struct device *dev)
static int host1x_drm_resume(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
+ struct tegra_drm *tegra = drm->dev_private;
+ drm_atomic_helper_resume(drm, tegra->state);
+ tegra_drm_fb_resume(drm);
drm_kms_helper_poll_enable(drm);
return 0;
@@ -1076,6 +1086,16 @@ static struct host1x_driver host1x_drm_driver = {
.subdevs = host1x_drm_subdevs,
};
+static struct platform_driver * const drivers[] = {
+ &tegra_dc_driver,
+ &tegra_hdmi_driver,
+ &tegra_dsi_driver,
+ &tegra_dpaux_driver,
+ &tegra_sor_driver,
+ &tegra_gr2d_driver,
+ &tegra_gr3d_driver,
+};
+
static int __init host1x_drm_init(void)
{
int err;
@@ -1084,48 +1104,12 @@ static int __init host1x_drm_init(void)
if (err < 0)
return err;
- err = platform_driver_register(&tegra_dc_driver);
+ err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (err < 0)
goto unregister_host1x;
- err = platform_driver_register(&tegra_dsi_driver);
- if (err < 0)
- goto unregister_dc;
-
- err = platform_driver_register(&tegra_sor_driver);
- if (err < 0)
- goto unregister_dsi;
-
- err = platform_driver_register(&tegra_hdmi_driver);
- if (err < 0)
- goto unregister_sor;
-
- err = platform_driver_register(&tegra_dpaux_driver);
- if (err < 0)
- goto unregister_hdmi;
-
- err = platform_driver_register(&tegra_gr2d_driver);
- if (err < 0)
- goto unregister_dpaux;
-
- err = platform_driver_register(&tegra_gr3d_driver);
- if (err < 0)
- goto unregister_gr2d;
-
return 0;
-unregister_gr2d:
- platform_driver_unregister(&tegra_gr2d_driver);
-unregister_dpaux:
- platform_driver_unregister(&tegra_dpaux_driver);
-unregister_hdmi:
- platform_driver_unregister(&tegra_hdmi_driver);
-unregister_sor:
- platform_driver_unregister(&tegra_sor_driver);
-unregister_dsi:
- platform_driver_unregister(&tegra_dsi_driver);
-unregister_dc:
- platform_driver_unregister(&tegra_dc_driver);
unregister_host1x:
host1x_driver_unregister(&host1x_drm_driver);
return err;
@@ -1134,13 +1118,7 @@ module_init(host1x_drm_init);
static void __exit host1x_drm_exit(void)
{
- platform_driver_unregister(&tegra_gr3d_driver);
- platform_driver_unregister(&tegra_gr2d_driver);
- platform_driver_unregister(&tegra_dpaux_driver);
- platform_driver_unregister(&tegra_hdmi_driver);
- platform_driver_unregister(&tegra_sor_driver);
- platform_driver_unregister(&tegra_dsi_driver);
- platform_driver_unregister(&tegra_dc_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
host1x_driver_unregister(&host1x_drm_driver);
}
module_exit(host1x_drm_exit);
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index ec49275ffb24..c088f2f67eda 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -30,7 +30,7 @@ struct tegra_fb {
unsigned int num_planes;
};
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_fbdev {
struct drm_fb_helper base;
struct tegra_fb *fb;
@@ -46,7 +46,7 @@ struct tegra_drm {
struct mutex clients_lock;
struct list_head clients;
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_fbdev *fbdev;
#endif
@@ -57,6 +57,8 @@ struct tegra_drm {
struct work_struct work;
struct mutex lock;
} commit;
+
+ struct drm_atomic_state *state;
};
struct tegra_drm_client;
@@ -247,18 +249,17 @@ void tegra_output_connector_destroy(struct drm_connector *connector);
void tegra_output_encoder_destroy(struct drm_encoder *encoder);
/* from dpaux.c */
-struct tegra_dpaux;
struct drm_dp_link;
-struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np);
-enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux);
-int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output);
-int tegra_dpaux_detach(struct tegra_dpaux *dpaux);
-int tegra_dpaux_enable(struct tegra_dpaux *dpaux);
-int tegra_dpaux_disable(struct tegra_dpaux *dpaux);
-int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding);
-int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
- u8 pattern);
+struct drm_dp_aux *drm_dp_aux_find_by_of_node(struct device_node *np);
+enum drm_connector_status drm_dp_aux_detect(struct drm_dp_aux *aux);
+int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output);
+int drm_dp_aux_detach(struct drm_dp_aux *aux);
+int drm_dp_aux_enable(struct drm_dp_aux *aux);
+int drm_dp_aux_disable(struct drm_dp_aux *aux);
+int drm_dp_aux_prepare(struct drm_dp_aux *aux, u8 encoding);
+int drm_dp_aux_train(struct drm_dp_aux *aux, struct drm_dp_link *link,
+ u8 pattern);
/* from fb.c */
struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
@@ -268,21 +269,23 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
struct tegra_bo_tiling *tiling);
struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
struct drm_file *file,
- struct drm_mode_fb_cmd2 *cmd);
+ const struct drm_mode_fb_cmd2 *cmd);
int tegra_drm_fb_prepare(struct drm_device *drm);
void tegra_drm_fb_free(struct drm_device *drm);
int tegra_drm_fb_init(struct drm_device *drm);
void tegra_drm_fb_exit(struct drm_device *drm);
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+void tegra_drm_fb_suspend(struct drm_device *drm);
+void tegra_drm_fb_resume(struct drm_device *drm);
+#ifdef CONFIG_DRM_FBDEV_EMULATION
void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
void tegra_fb_output_poll_changed(struct drm_device *drm);
#endif
extern struct platform_driver tegra_dc_driver;
-extern struct platform_driver tegra_dsi_driver;
-extern struct platform_driver tegra_sor_driver;
extern struct platform_driver tegra_hdmi_driver;
+extern struct platform_driver tegra_dsi_driver;
extern struct platform_driver tegra_dpaux_driver;
+extern struct platform_driver tegra_sor_driver;
extern struct platform_driver tegra_gr2d_driver;
extern struct platform_driver tegra_gr3d_driver;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index f0a138ef68ce..44e102799195 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -745,14 +745,13 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
static void tegra_dsi_connector_reset(struct drm_connector *connector)
{
- struct tegra_dsi_state *state;
-
- kfree(connector->state);
- connector->state = NULL;
+ struct tegra_dsi_state *state =
+ kzalloc(sizeof(*state), GFP_KERNEL);
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (state)
- connector->state = &state->base;
+ if (state) {
+ kfree(connector->state);
+ __drm_atomic_helper_connector_reset(connector, &state->base);
+ }
}
static struct drm_connector_state *
@@ -1023,7 +1022,7 @@ static int tegra_dsi_init(struct host1x_client *client)
drm_encoder_init(drm, &dsi->output.encoder,
&tegra_dsi_encoder_funcs,
- DRM_MODE_ENCODER_DSI);
+ DRM_MODE_ENCODER_DSI, NULL);
drm_encoder_helper_add(&dsi->output.encoder,
&tegra_dsi_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 1004075fd088..ca84de9ccb51 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -10,6 +10,8 @@
* published by the Free Software Foundation.
*/
+#include <linux/console.h>
+
#include "drm.h"
#include "gem.h"
@@ -18,7 +20,7 @@ static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb)
return container_of(fb, struct tegra_fb, base);
}
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper)
{
return container_of(helper, struct tegra_fbdev, base);
@@ -86,13 +88,13 @@ static int tegra_fb_create_handle(struct drm_framebuffer *framebuffer,
return drm_gem_handle_create(file, &fb->planes[0]->gem, handle);
}
-static struct drm_framebuffer_funcs tegra_fb_funcs = {
+static const struct drm_framebuffer_funcs tegra_fb_funcs = {
.destroy = tegra_fb_destroy,
.create_handle = tegra_fb_create_handle,
};
static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct tegra_bo **planes,
unsigned int num_planes)
{
@@ -131,7 +133,7 @@ static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm,
struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
struct drm_file *file,
- struct drm_mode_fb_cmd2 *cmd)
+ const struct drm_mode_fb_cmd2 *cmd)
{
unsigned int hsub, vsub, i;
struct tegra_bo *planes[4];
@@ -181,7 +183,7 @@ unreference:
return ERR_PTR(err);
}
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
static struct fb_ops tegra_fb_ops = {
.owner = THIS_MODULE,
.fb_fillrect = drm_fb_helper_sys_fillrect,
@@ -370,7 +372,7 @@ void tegra_fb_output_poll_changed(struct drm_device *drm)
int tegra_drm_fb_prepare(struct drm_device *drm)
{
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_drm *tegra = drm->dev_private;
tegra->fbdev = tegra_fbdev_create(drm);
@@ -383,7 +385,7 @@ int tegra_drm_fb_prepare(struct drm_device *drm)
void tegra_drm_fb_free(struct drm_device *drm)
{
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_drm *tegra = drm->dev_private;
tegra_fbdev_free(tegra->fbdev);
@@ -392,7 +394,7 @@ void tegra_drm_fb_free(struct drm_device *drm)
int tegra_drm_fb_init(struct drm_device *drm)
{
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_drm *tegra = drm->dev_private;
int err;
@@ -407,9 +409,31 @@ int tegra_drm_fb_init(struct drm_device *drm)
void tegra_drm_fb_exit(struct drm_device *drm)
{
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_drm *tegra = drm->dev_private;
tegra_fbdev_exit(tegra->fbdev);
#endif
}
+
+void tegra_drm_fb_suspend(struct drm_device *drm)
+{
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+ struct tegra_drm *tegra = drm->dev_private;
+
+ console_lock();
+ drm_fb_helper_set_suspend(&tegra->fbdev->base, 1);
+ console_unlock();
+#endif
+}
+
+void tegra_drm_fb_resume(struct drm_device *drm)
+{
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+ struct tegra_drm *tegra = drm->dev_private;
+
+ console_lock();
+ drm_fb_helper_set_suspend(&tegra->fbdev->base, 0);
+ console_unlock();
+#endif
+}
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 01e16e146bfe..33add93b4ed9 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -28,11 +28,8 @@ static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo)
static void tegra_bo_put(struct host1x_bo *bo)
{
struct tegra_bo *obj = host1x_to_tegra_bo(bo);
- struct drm_device *drm = obj->gem.dev;
- mutex_lock(&drm->struct_mutex);
- drm_gem_object_unreference(&obj->gem);
- mutex_unlock(&drm->struct_mutex);
+ drm_gem_object_unreference_unlocked(&obj->gem);
}
static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt)
@@ -72,11 +69,8 @@ static void tegra_bo_kunmap(struct host1x_bo *bo, unsigned int page,
static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo)
{
struct tegra_bo *obj = host1x_to_tegra_bo(bo);
- struct drm_device *drm = obj->gem.dev;
- mutex_lock(&drm->struct_mutex);
drm_gem_object_reference(&obj->gem);
- mutex_unlock(&drm->struct_mutex);
return bo;
}
@@ -408,12 +402,9 @@ int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm,
struct drm_gem_object *gem;
struct tegra_bo *bo;
- mutex_lock(&drm->struct_mutex);
-
gem = drm_gem_object_lookup(drm, file, handle);
if (!gem) {
dev_err(drm->dev, "failed to lookup GEM object\n");
- mutex_unlock(&drm->struct_mutex);
return -EINVAL;
}
@@ -421,9 +412,7 @@ int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm,
*offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
- drm_gem_object_unreference(gem);
-
- mutex_unlock(&drm->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
return 0;
}
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index 52b32cbd9de6..b7ef4929e347 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -1320,7 +1320,7 @@ static int tegra_hdmi_init(struct host1x_client *client)
hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF;
drm_encoder_init(drm, &hdmi->output.encoder, &tegra_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(&hdmi->output.encoder,
&tegra_hdmi_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index bc9735b4ad60..e246334e0252 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -287,7 +287,7 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
output->connector.dpms = DRM_MODE_DPMS_OFF;
drm_encoder_init(drm, &output->encoder, &tegra_rgb_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
drm_encoder_helper_add(&output->encoder,
&tegra_rgb_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 3eff7cf75d25..757c6e8603af 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -173,7 +173,7 @@ struct tegra_sor {
struct clk *clk_dp;
struct clk *clk;
- struct tegra_dpaux *dpaux;
+ struct drm_dp_aux *aux;
struct drm_info_list *debugfs_files;
struct drm_minor *minor;
@@ -273,7 +273,7 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0);
tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
- err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B);
+ err = drm_dp_aux_prepare(sor->aux, DP_SET_ANSI_8B10B);
if (err < 0)
return err;
@@ -288,7 +288,7 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
pattern = DP_TRAINING_PATTERN_1;
- err = tegra_dpaux_train(sor->dpaux, link, pattern);
+ err = drm_dp_aux_train(sor->aux, link, pattern);
if (err < 0)
return err;
@@ -309,7 +309,7 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2;
- err = tegra_dpaux_train(sor->dpaux, link, pattern);
+ err = drm_dp_aux_train(sor->aux, link, pattern);
if (err < 0)
return err;
@@ -324,7 +324,7 @@ static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
pattern = DP_TRAINING_PATTERN_DISABLE;
- err = tegra_dpaux_train(sor->dpaux, link, pattern);
+ err = drm_dp_aux_train(sor->aux, link, pattern);
if (err < 0)
return err;
@@ -1044,8 +1044,8 @@ tegra_sor_connector_detect(struct drm_connector *connector, bool force)
struct tegra_output *output = connector_to_output(connector);
struct tegra_sor *sor = to_sor(output);
- if (sor->dpaux)
- return tegra_dpaux_detect(sor->dpaux);
+ if (sor->aux)
+ return drm_dp_aux_detect(sor->aux);
return tegra_output_connector_detect(connector, force);
}
@@ -1066,13 +1066,13 @@ static int tegra_sor_connector_get_modes(struct drm_connector *connector)
struct tegra_sor *sor = to_sor(output);
int err;
- if (sor->dpaux)
- tegra_dpaux_enable(sor->dpaux);
+ if (sor->aux)
+ drm_dp_aux_enable(sor->aux);
err = tegra_output_connector_get_modes(connector);
- if (sor->dpaux)
- tegra_dpaux_disable(sor->dpaux);
+ if (sor->aux)
+ drm_dp_aux_disable(sor->aux);
return err;
}
@@ -1128,8 +1128,8 @@ static void tegra_sor_edp_disable(struct drm_encoder *encoder)
if (err < 0)
dev_err(sor->dev, "failed to power down SOR: %d\n", err);
- if (sor->dpaux) {
- err = tegra_dpaux_disable(sor->dpaux);
+ if (sor->aux) {
+ err = drm_dp_aux_disable(sor->aux);
if (err < 0)
dev_err(sor->dev, "failed to disable DP: %d\n", err);
}
@@ -1196,7 +1196,7 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
struct tegra_sor *sor = to_sor(output);
struct tegra_sor_config config;
struct drm_dp_link link;
- struct drm_dp_aux *aux;
+ u8 rate, lanes;
int err = 0;
u32 value;
@@ -1209,20 +1209,14 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
if (output->panel)
drm_panel_prepare(output->panel);
- /* FIXME: properly convert to struct drm_dp_aux */
- aux = (struct drm_dp_aux *)sor->dpaux;
-
- if (sor->dpaux) {
- err = tegra_dpaux_enable(sor->dpaux);
- if (err < 0)
- dev_err(sor->dev, "failed to enable DP: %d\n", err);
+ err = drm_dp_aux_enable(sor->aux);
+ if (err < 0)
+ dev_err(sor->dev, "failed to enable DP: %d\n", err);
- err = drm_dp_link_probe(aux, &link);
- if (err < 0) {
- dev_err(sor->dev, "failed to probe eDP link: %d\n",
- err);
- return;
- }
+ err = drm_dp_link_probe(sor->aux, &link);
+ if (err < 0) {
+ dev_err(sor->dev, "failed to probe eDP link: %d\n", err);
+ return;
}
err = clk_set_parent(sor->clk, sor->clk_safe);
@@ -1434,60 +1428,51 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
value |= SOR_DP_PADCTL_PAD_CAL_PD;
tegra_sor_writel(sor, value, SOR_DP_PADCTL0);
- if (sor->dpaux) {
- u8 rate, lanes;
-
- err = drm_dp_link_probe(aux, &link);
- if (err < 0)
- dev_err(sor->dev, "failed to probe eDP link: %d\n",
- err);
+ err = drm_dp_link_probe(sor->aux, &link);
+ if (err < 0)
+ dev_err(sor->dev, "failed to probe eDP link: %d\n", err);
- err = drm_dp_link_power_up(aux, &link);
- if (err < 0)
- dev_err(sor->dev, "failed to power up eDP link: %d\n",
- err);
+ err = drm_dp_link_power_up(sor->aux, &link);
+ if (err < 0)
+ dev_err(sor->dev, "failed to power up eDP link: %d\n", err);
- err = drm_dp_link_configure(aux, &link);
- if (err < 0)
- dev_err(sor->dev, "failed to configure eDP link: %d\n",
- err);
+ err = drm_dp_link_configure(sor->aux, &link);
+ if (err < 0)
+ dev_err(sor->dev, "failed to configure eDP link: %d\n", err);
- rate = drm_dp_link_rate_to_bw_code(link.rate);
- lanes = link.num_lanes;
+ rate = drm_dp_link_rate_to_bw_code(link.rate);
+ lanes = link.num_lanes;
- value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
- value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
- value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate);
- tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
+ value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
+ value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
+ value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate);
+ tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
- value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
- value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
- value |= SOR_DP_LINKCTL_LANE_COUNT(lanes);
+ value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
+ value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
+ value |= SOR_DP_LINKCTL_LANE_COUNT(lanes);
- if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
- value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
+ if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
+ value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
- tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
+ tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
- /* disable training pattern generator */
+ /* disable training pattern generator */
- for (i = 0; i < link.num_lanes; i++) {
- unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
- SOR_DP_TPG_SCRAMBLER_GALIOS |
- SOR_DP_TPG_PATTERN_NONE;
- value = (value << 8) | lane;
- }
+ for (i = 0; i < link.num_lanes; i++) {
+ unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
+ SOR_DP_TPG_SCRAMBLER_GALIOS |
+ SOR_DP_TPG_PATTERN_NONE;
+ value = (value << 8) | lane;
+ }
- tegra_sor_writel(sor, value, SOR_DP_TPG);
+ tegra_sor_writel(sor, value, SOR_DP_TPG);
- err = tegra_sor_dp_train_fast(sor, &link);
- if (err < 0) {
- dev_err(sor->dev, "DP fast link training failed: %d\n",
- err);
- }
+ err = tegra_sor_dp_train_fast(sor, &link);
+ if (err < 0)
+ dev_err(sor->dev, "DP fast link training failed: %d\n", err);
- dev_dbg(sor->dev, "fast link training succeeded\n");
- }
+ dev_dbg(sor->dev, "fast link training succeeded\n");
err = tegra_sor_power_up(sor, 250);
if (err < 0)
@@ -1961,9 +1946,9 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
/* production settings */
settings = tegra_sor_hdmi_find_settings(sor, mode->clock * 1000);
- if (IS_ERR(settings)) {
- dev_err(sor->dev, "no settings for pixel clock %d Hz: %ld\n",
- mode->clock * 1000, PTR_ERR(settings));
+ if (!settings) {
+ dev_err(sor->dev, "no settings for pixel clock %d Hz\n",
+ mode->clock * 1000);
return;
}
@@ -2148,7 +2133,7 @@ static int tegra_sor_init(struct host1x_client *client)
int encoder = DRM_MODE_ENCODER_NONE;
int err;
- if (!sor->dpaux) {
+ if (!sor->aux) {
if (sor->soc->supports_hdmi) {
connector = DRM_MODE_CONNECTOR_HDMIA;
encoder = DRM_MODE_ENCODER_TMDS;
@@ -2178,7 +2163,7 @@ static int tegra_sor_init(struct host1x_client *client)
sor->output.connector.dpms = DRM_MODE_DPMS_OFF;
drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs,
- encoder);
+ encoder, NULL);
drm_encoder_helper_add(&sor->output.encoder, helpers);
drm_mode_connector_attach_encoder(&sor->output.connector,
@@ -2199,8 +2184,8 @@ static int tegra_sor_init(struct host1x_client *client)
dev_err(sor->dev, "debugfs setup failed: %d\n", err);
}
- if (sor->dpaux) {
- err = tegra_dpaux_attach(sor->dpaux, &sor->output);
+ if (sor->aux) {
+ err = drm_dp_aux_attach(sor->aux, &sor->output);
if (err < 0) {
dev_err(sor->dev, "failed to attach DP: %d\n", err);
return err;
@@ -2249,8 +2234,8 @@ static int tegra_sor_exit(struct host1x_client *client)
tegra_output_exit(&sor->output);
- if (sor->dpaux) {
- err = tegra_dpaux_detach(sor->dpaux);
+ if (sor->aux) {
+ err = drm_dp_aux_detach(sor->aux);
if (err < 0) {
dev_err(sor->dev, "failed to detach DP: %d\n", err);
return err;
@@ -2399,14 +2384,14 @@ static int tegra_sor_probe(struct platform_device *pdev)
np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0);
if (np) {
- sor->dpaux = tegra_dpaux_find_by_of_node(np);
+ sor->aux = drm_dp_aux_find_by_of_node(np);
of_node_put(np);
- if (!sor->dpaux)
+ if (!sor->aux)
return -EPROBE_DEFER;
}
- if (!sor->dpaux) {
+ if (!sor->aux) {
if (sor->soc->supports_hdmi) {
sor->ops = &tegra_sor_hdmi_ops;
} else if (sor->soc->supports_lvds) {
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 876cad58b1f9..d7f5b897c6c5 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -46,7 +46,7 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod)
static struct of_device_id tilcdc_of_match[];
static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
- struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
{
return drm_fb_cma_create(dev, file_priv, mode_cmd);
}
@@ -294,6 +294,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
break;
}
+ drm_helper_disable_unused_functions(dev);
priv->fbdev = drm_fbdev_cma_init(dev, bpp,
dev->mode_config.num_crtc,
dev->mode_config.num_connector);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index 0af8bed7ce1e..4dda6e2f464b 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -128,7 +128,7 @@ static struct drm_encoder *panel_encoder_create(struct drm_device *dev,
encoder->possible_crtcs = 1;
ret = drm_encoder_init(dev, encoder, &panel_encoder_funcs,
- DRM_MODE_ENCODER_LVDS);
+ DRM_MODE_ENCODER_LVDS, NULL);
if (ret < 0)
goto fail;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
index 354c47ca6374..5052a8af7ecb 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
@@ -138,7 +138,7 @@ static struct drm_encoder *tfp410_encoder_create(struct drm_device *dev,
encoder->possible_crtcs = 1;
ret = drm_encoder_init(dev, encoder, &tfp410_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
if (ret < 0)
goto fail;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 745e996d2dbc..4cbf26555093 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -176,7 +176,7 @@ void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
list_add_tail(&bo->lru, &man->lru);
kref_get(&bo->list_kref);
- if (bo->ttm != NULL) {
+ if (bo->ttm && !(bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) {
list_add_tail(&bo->swap, &bo->glob->swap_lru);
kref_get(&bo->list_kref);
}
@@ -228,6 +228,27 @@ void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo)
}
EXPORT_SYMBOL(ttm_bo_del_sub_from_lru);
+void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo)
+{
+ struct ttm_bo_device *bdev = bo->bdev;
+ struct ttm_mem_type_manager *man;
+
+ lockdep_assert_held(&bo->resv->lock.base);
+
+ if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT) {
+ list_del_init(&bo->swap);
+ list_del_init(&bo->lru);
+
+ } else {
+ if (bo->ttm && !(bo->ttm->page_flags & TTM_PAGE_FLAG_SG))
+ list_move_tail(&bo->swap, &bo->glob->swap_lru);
+
+ man = &bdev->man[bo->mem.mem_type];
+ list_move_tail(&bo->lru, &man->lru);
+ }
+}
+EXPORT_SYMBOL(ttm_bo_move_to_lru_tail);
+
/*
* Call bo->mutex locked.
*/
@@ -1170,9 +1191,15 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
if (likely(!ret))
ret = ttm_bo_validate(bo, placement, interruptible, false);
- if (!resv)
+ if (!resv) {
ttm_bo_unreserve(bo);
+ } else if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
+ spin_lock(&bo->glob->lru_lock);
+ ttm_bo_add_to_lru(bo);
+ spin_unlock(&bo->glob->lru_lock);
+ }
+
if (unlikely(ret))
ttm_bo_unref(&bo);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 8fb7213277cc..06d26dc438b2 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -35,6 +35,7 @@
#include <ttm/ttm_placement.h>
#include <drm/drm_vma_manager.h>
#include <linux/mm.h>
+#include <linux/pfn_t.h>
#include <linux/rbtree.h>
#include <linux/module.h>
#include <linux/uaccess.h>
@@ -229,7 +230,8 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
}
if (vma->vm_flags & VM_MIXEDMAP)
- ret = vm_insert_mixed(&cvma, address, pfn);
+ ret = vm_insert_mixed(&cvma, address,
+ __pfn_to_pfn_t(pfn, PFN_DEV));
else
ret = vm_insert_pfn(&cvma, address, pfn);
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index 0110d95522f3..4709b54c204c 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -122,13 +122,13 @@ static void udl_connector_destroy(struct drm_connector *connector)
kfree(connector);
}
-static struct drm_connector_helper_funcs udl_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs udl_connector_helper_funcs = {
.get_modes = udl_get_modes,
.mode_valid = udl_mode_valid,
.best_encoder = udl_best_single_encoder,
};
-static struct drm_connector_funcs udl_connector_funcs = {
+static const struct drm_connector_funcs udl_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = udl_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 80adbac82bde..4a064efcea58 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -108,7 +108,7 @@ void udl_fbdev_unplug(struct drm_device *dev);
struct drm_framebuffer *
udl_fb_user_fb_create(struct drm_device *dev,
struct drm_file *file,
- struct drm_mode_fb_cmd2 *mode_cmd);
+ const struct drm_mode_fb_cmd2 *mode_cmd);
int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
const char *front, char **urb_buf_ptr,
diff --git a/drivers/gpu/drm/udl/udl_encoder.c b/drivers/gpu/drm/udl/udl_encoder.c
index 4052c4656498..a181a647fcf9 100644
--- a/drivers/gpu/drm/udl/udl_encoder.c
+++ b/drivers/gpu/drm/udl/udl_encoder.c
@@ -73,7 +73,8 @@ struct drm_encoder *udl_encoder_init(struct drm_device *dev)
if (!encoder)
return NULL;
- drm_encoder_init(dev, encoder, &udl_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(dev, encoder, &udl_enc_funcs, DRM_MODE_ENCODER_TMDS,
+ NULL);
drm_encoder_helper_add(encoder, &udl_helper_funcs);
encoder->possible_crtcs = 1;
return encoder;
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 62c7b1dafaa4..200419d4d43c 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -33,7 +33,6 @@ module_param(fb_defio, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
struct udl_fbdev {
struct drm_fb_helper helper;
struct udl_framebuffer ufb;
- struct list_head fbdev_list;
int fb_count;
};
@@ -456,7 +455,7 @@ static const struct drm_framebuffer_funcs udlfb_funcs = {
static int
udl_framebuffer_init(struct drm_device *dev,
struct udl_framebuffer *ufb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct udl_gem_object *obj)
{
int ret;
@@ -624,7 +623,7 @@ void udl_fbdev_unplug(struct drm_device *dev)
struct drm_framebuffer *
udl_fb_user_fb_create(struct drm_device *dev,
struct drm_file *file,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct udl_framebuffer *ufb;
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 677190a65e82..160ef2a08b89 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -400,7 +400,7 @@ static void udl_crtc_commit(struct drm_crtc *crtc)
udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}
-static struct drm_crtc_helper_funcs udl_helper_funcs = {
+static const struct drm_crtc_helper_funcs udl_helper_funcs = {
.dpms = udl_crtc_dpms,
.mode_fixup = udl_crtc_mode_fixup,
.mode_set = udl_crtc_mode_set,
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index 32b4f9cd8f52..4c6a99f0398c 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -8,10 +8,19 @@ vc4-y := \
vc4_crtc.o \
vc4_drv.o \
vc4_kms.o \
+ vc4_gem.o \
vc4_hdmi.o \
vc4_hvs.o \
- vc4_plane.o
+ vc4_irq.o \
+ vc4_plane.o \
+ vc4_render_cl.o \
+ vc4_trace_points.o \
+ vc4_v3d.o \
+ vc4_validate.o \
+ vc4_validate_shaders.o
vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
obj-$(CONFIG_DRM_VC4) += vc4.o
+
+CFLAGS_vc4_trace_points.o := -I$(src)
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index ab9f5108ae1a..18dfe3ec9a62 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -12,19 +12,236 @@
* access to system memory with no MMU in between. To support it, we
* use the GEM CMA helper functions to allocate contiguous ranges of
* physical memory for our BOs.
+ *
+ * Since the CMA allocator is very slow, we keep a cache of recently
+ * freed BOs around so that the kernel's allocation of objects for 3D
+ * rendering can return quickly.
*/
#include "vc4_drv.h"
+#include "uapi/drm/vc4_drm.h"
+
+static void vc4_bo_stats_dump(struct vc4_dev *vc4)
+{
+ DRM_INFO("num bos allocated: %d\n",
+ vc4->bo_stats.num_allocated);
+ DRM_INFO("size bos allocated: %dkb\n",
+ vc4->bo_stats.size_allocated / 1024);
+ DRM_INFO("num bos used: %d\n",
+ vc4->bo_stats.num_allocated - vc4->bo_stats.num_cached);
+ DRM_INFO("size bos used: %dkb\n",
+ (vc4->bo_stats.size_allocated -
+ vc4->bo_stats.size_cached) / 1024);
+ DRM_INFO("num bos cached: %d\n",
+ vc4->bo_stats.num_cached);
+ DRM_INFO("size bos cached: %dkb\n",
+ vc4->bo_stats.size_cached / 1024);
+}
+
+#ifdef CONFIG_DEBUG_FS
+int vc4_bo_stats_debugfs(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 vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_bo_stats stats;
+
+ /* Take a snapshot of the current stats with the lock held. */
+ mutex_lock(&vc4->bo_lock);
+ stats = vc4->bo_stats;
+ mutex_unlock(&vc4->bo_lock);
+
+ seq_printf(m, "num bos allocated: %d\n",
+ stats.num_allocated);
+ seq_printf(m, "size bos allocated: %dkb\n",
+ stats.size_allocated / 1024);
+ seq_printf(m, "num bos used: %d\n",
+ stats.num_allocated - stats.num_cached);
+ seq_printf(m, "size bos used: %dkb\n",
+ (stats.size_allocated - stats.size_cached) / 1024);
+ seq_printf(m, "num bos cached: %d\n",
+ stats.num_cached);
+ seq_printf(m, "size bos cached: %dkb\n",
+ stats.size_cached / 1024);
+
+ return 0;
+}
+#endif
+
+static uint32_t bo_page_index(size_t size)
+{
+ return (size / PAGE_SIZE) - 1;
+}
+
+/* Must be called with bo_lock held. */
+static void vc4_bo_destroy(struct vc4_bo *bo)
+{
+ struct drm_gem_object *obj = &bo->base.base;
+ struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
+
+ if (bo->validated_shader) {
+ kfree(bo->validated_shader->texture_samples);
+ kfree(bo->validated_shader);
+ bo->validated_shader = NULL;
+ }
+
+ vc4->bo_stats.num_allocated--;
+ vc4->bo_stats.size_allocated -= obj->size;
+ drm_gem_cma_free_object(obj);
+}
+
+/* Must be called with bo_lock held. */
+static void vc4_bo_remove_from_cache(struct vc4_bo *bo)
+{
+ struct drm_gem_object *obj = &bo->base.base;
+ struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
+
+ vc4->bo_stats.num_cached--;
+ vc4->bo_stats.size_cached -= obj->size;
+
+ list_del(&bo->unref_head);
+ list_del(&bo->size_head);
+}
+
+static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
+ size_t size)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t page_index = bo_page_index(size);
+
+ if (vc4->bo_cache.size_list_size <= page_index) {
+ uint32_t new_size = max(vc4->bo_cache.size_list_size * 2,
+ page_index + 1);
+ struct list_head *new_list;
+ uint32_t i;
+
+ new_list = kmalloc_array(new_size, sizeof(struct list_head),
+ GFP_KERNEL);
+ if (!new_list)
+ return NULL;
+
+ /* Rebase the old cached BO lists to their new list
+ * head locations.
+ */
+ for (i = 0; i < vc4->bo_cache.size_list_size; i++) {
+ struct list_head *old_list =
+ &vc4->bo_cache.size_list[i];
+
+ if (list_empty(old_list))
+ INIT_LIST_HEAD(&new_list[i]);
+ else
+ list_replace(old_list, &new_list[i]);
+ }
+ /* And initialize the brand new BO list heads. */
+ for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
+ INIT_LIST_HEAD(&new_list[i]);
+
+ kfree(vc4->bo_cache.size_list);
+ vc4->bo_cache.size_list = new_list;
+ vc4->bo_cache.size_list_size = new_size;
+ }
+
+ return &vc4->bo_cache.size_list[page_index];
+}
+
+void vc4_bo_cache_purge(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ mutex_lock(&vc4->bo_lock);
+ while (!list_empty(&vc4->bo_cache.time_list)) {
+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
+ struct vc4_bo, unref_head);
+ vc4_bo_remove_from_cache(bo);
+ vc4_bo_destroy(bo);
+ }
+ mutex_unlock(&vc4->bo_lock);
+}
+
+static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,
+ uint32_t size)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t page_index = bo_page_index(size);
+ struct vc4_bo *bo = NULL;
+
+ size = roundup(size, PAGE_SIZE);
+
+ mutex_lock(&vc4->bo_lock);
+ if (page_index >= vc4->bo_cache.size_list_size)
+ goto out;
-struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size)
+ if (list_empty(&vc4->bo_cache.size_list[page_index]))
+ goto out;
+
+ bo = list_first_entry(&vc4->bo_cache.size_list[page_index],
+ struct vc4_bo, size_head);
+ vc4_bo_remove_from_cache(bo);
+ kref_init(&bo->base.base.refcount);
+
+out:
+ mutex_unlock(&vc4->bo_lock);
+ return bo;
+}
+
+/**
+ * vc4_gem_create_object - Implementation of driver->gem_create_object.
+ *
+ * This lets the CMA helpers allocate object structs for us, and keep
+ * our BO stats correct.
+ */
+struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_bo *bo;
+
+ bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+ if (!bo)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&vc4->bo_lock);
+ vc4->bo_stats.num_allocated++;
+ vc4->bo_stats.size_allocated += size;
+ mutex_unlock(&vc4->bo_lock);
+
+ return &bo->base.base;
+}
+
+struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
+ bool from_cache)
+{
+ size_t size = roundup(unaligned_size, PAGE_SIZE);
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_gem_cma_object *cma_obj;
- cma_obj = drm_gem_cma_create(dev, size);
- if (IS_ERR(cma_obj))
+ if (size == 0)
return NULL;
- else
- return to_vc4_bo(&cma_obj->base);
+
+ /* First, try to get a vc4_bo from the kernel BO cache. */
+ if (from_cache) {
+ struct vc4_bo *bo = vc4_bo_get_from_cache(dev, size);
+
+ if (bo)
+ return bo;
+ }
+
+ cma_obj = drm_gem_cma_create(dev, size);
+ if (IS_ERR(cma_obj)) {
+ /*
+ * If we've run out of CMA memory, kill the cache of
+ * CMA allocations we've got laying around and try again.
+ */
+ vc4_bo_cache_purge(dev);
+
+ cma_obj = drm_gem_cma_create(dev, size);
+ if (IS_ERR(cma_obj)) {
+ DRM_ERROR("Failed to allocate from CMA:\n");
+ vc4_bo_stats_dump(vc4);
+ return NULL;
+ }
+ }
+
+ return to_vc4_bo(&cma_obj->base);
}
int vc4_dumb_create(struct drm_file *file_priv,
@@ -41,7 +258,191 @@ int vc4_dumb_create(struct drm_file *file_priv,
if (args->size < args->pitch * args->height)
args->size = args->pitch * args->height;
- bo = vc4_bo_create(dev, roundup(args->size, PAGE_SIZE));
+ bo = vc4_bo_create(dev, args->size, false);
+ if (!bo)
+ return -ENOMEM;
+
+ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
+ drm_gem_object_unreference_unlocked(&bo->base.base);
+
+ return ret;
+}
+
+/* Must be called with bo_lock held. */
+static void vc4_bo_cache_free_old(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
+
+ while (!list_empty(&vc4->bo_cache.time_list)) {
+ struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
+ struct vc4_bo, unref_head);
+ if (time_before(expire_time, bo->free_time)) {
+ mod_timer(&vc4->bo_cache.time_timer,
+ round_jiffies_up(jiffies +
+ msecs_to_jiffies(1000)));
+ return;
+ }
+
+ vc4_bo_remove_from_cache(bo);
+ vc4_bo_destroy(bo);
+ }
+}
+
+/* Called on the last userspace/kernel unreference of the BO. Returns
+ * it to the BO cache if possible, otherwise frees it.
+ *
+ * Note that this is called with the struct_mutex held.
+ */
+void vc4_free_object(struct drm_gem_object *gem_bo)
+{
+ struct drm_device *dev = gem_bo->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_bo *bo = to_vc4_bo(gem_bo);
+ struct list_head *cache_list;
+
+ mutex_lock(&vc4->bo_lock);
+ /* If the object references someone else's memory, we can't cache it.
+ */
+ if (gem_bo->import_attach) {
+ vc4_bo_destroy(bo);
+ goto out;
+ }
+
+ /* Don't cache if it was publicly named. */
+ if (gem_bo->name) {
+ vc4_bo_destroy(bo);
+ goto out;
+ }
+
+ cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
+ if (!cache_list) {
+ vc4_bo_destroy(bo);
+ goto out;
+ }
+
+ if (bo->validated_shader) {
+ kfree(bo->validated_shader->texture_samples);
+ kfree(bo->validated_shader);
+ bo->validated_shader = NULL;
+ }
+
+ bo->free_time = jiffies;
+ list_add(&bo->size_head, cache_list);
+ list_add(&bo->unref_head, &vc4->bo_cache.time_list);
+
+ vc4->bo_stats.num_cached++;
+ vc4->bo_stats.size_cached += gem_bo->size;
+
+ vc4_bo_cache_free_old(dev);
+
+out:
+ mutex_unlock(&vc4->bo_lock);
+}
+
+static void vc4_bo_cache_time_work(struct work_struct *work)
+{
+ struct vc4_dev *vc4 =
+ container_of(work, struct vc4_dev, bo_cache.time_work);
+ struct drm_device *dev = vc4->dev;
+
+ mutex_lock(&vc4->bo_lock);
+ vc4_bo_cache_free_old(dev);
+ mutex_unlock(&vc4->bo_lock);
+}
+
+static void vc4_bo_cache_time_timer(unsigned long data)
+{
+ struct drm_device *dev = (struct drm_device *)data;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ schedule_work(&vc4->bo_cache.time_work);
+}
+
+struct dma_buf *
+vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
+{
+ struct vc4_bo *bo = to_vc4_bo(obj);
+
+ if (bo->validated_shader) {
+ DRM_ERROR("Attempting to export shader BO\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return drm_gem_prime_export(dev, obj, flags);
+}
+
+int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_gem_object *gem_obj;
+ struct vc4_bo *bo;
+ int ret;
+
+ ret = drm_gem_mmap(filp, vma);
+ if (ret)
+ return ret;
+
+ gem_obj = vma->vm_private_data;
+ bo = to_vc4_bo(gem_obj);
+
+ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
+ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
+ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
+ * the whole buffer.
+ */
+ vma->vm_flags &= ~VM_PFNMAP;
+ vma->vm_pgoff = 0;
+
+ ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma,
+ bo->base.vaddr, bo->base.paddr,
+ vma->vm_end - vma->vm_start);
+ if (ret)
+ drm_gem_vm_close(vma);
+
+ return ret;
+}
+
+int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+ struct vc4_bo *bo = to_vc4_bo(obj);
+
+ if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
+ DRM_ERROR("mmaping of shader BOs for writing not allowed.\n");
+ return -EINVAL;
+ }
+
+ return drm_gem_cma_prime_mmap(obj, vma);
+}
+
+void *vc4_prime_vmap(struct drm_gem_object *obj)
+{
+ struct vc4_bo *bo = to_vc4_bo(obj);
+
+ if (bo->validated_shader) {
+ DRM_ERROR("mmaping of shader BOs not allowed.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return drm_gem_cma_prime_vmap(obj);
+}
+
+int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_create_bo *args = data;
+ struct vc4_bo *bo = NULL;
+ int ret;
+
+ /*
+ * We can't allocate from the BO cache, because the BOs don't
+ * get zeroed, and that might leak data between users.
+ */
+ bo = vc4_bo_create(dev, args->size, false);
if (!bo)
return -ENOMEM;
@@ -50,3 +451,107 @@ int vc4_dumb_create(struct drm_file *file_priv,
return ret;
}
+
+int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_mmap_bo *args = data;
+ struct drm_gem_object *gem_obj;
+
+ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+
+ /* The mmap offset was set up at BO allocation time. */
+ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
+
+ drm_gem_object_unreference_unlocked(gem_obj);
+ return 0;
+}
+
+int
+vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_create_shader_bo *args = data;
+ struct vc4_bo *bo = NULL;
+ int ret;
+
+ if (args->size == 0)
+ return -EINVAL;
+
+ if (args->size % sizeof(u64) != 0)
+ return -EINVAL;
+
+ if (args->flags != 0) {
+ DRM_INFO("Unknown flags set: 0x%08x\n", args->flags);
+ return -EINVAL;
+ }
+
+ if (args->pad != 0) {
+ DRM_INFO("Pad set: 0x%08x\n", args->pad);
+ return -EINVAL;
+ }
+
+ bo = vc4_bo_create(dev, args->size, true);
+ if (!bo)
+ return -ENOMEM;
+
+ ret = copy_from_user(bo->base.vaddr,
+ (void __user *)(uintptr_t)args->data,
+ args->size);
+ if (ret != 0)
+ goto fail;
+ /* Clear the rest of the memory from allocating from the BO
+ * cache.
+ */
+ memset(bo->base.vaddr + args->size, 0,
+ bo->base.base.size - args->size);
+
+ bo->validated_shader = vc4_validate_shader(&bo->base);
+ if (!bo->validated_shader) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* We have to create the handle after validation, to avoid
+ * races for users to do doing things like mmap the shader BO.
+ */
+ ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
+
+ fail:
+ drm_gem_object_unreference_unlocked(&bo->base.base);
+
+ return ret;
+}
+
+void vc4_bo_cache_init(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ mutex_init(&vc4->bo_lock);
+
+ INIT_LIST_HEAD(&vc4->bo_cache.time_list);
+
+ INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work);
+ setup_timer(&vc4->bo_cache.time_timer,
+ vc4_bo_cache_time_timer,
+ (unsigned long)dev);
+}
+
+void vc4_bo_cache_destroy(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ del_timer(&vc4->bo_cache.time_timer);
+ cancel_work_sync(&vc4->bo_cache.time_work);
+
+ vc4_bo_cache_purge(dev);
+
+ if (vc4->bo_stats.num_allocated) {
+ DRM_ERROR("Destroying BO cache while BOs still allocated:\n");
+ vc4_bo_stats_dump(vc4);
+ }
+}
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 265064c62d49..018145e0b87d 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -35,6 +35,7 @@
#include "drm_atomic_helper.h"
#include "drm_crtc_helper.h"
#include "linux/clk.h"
+#include "drm_fb_cma_helper.h"
#include "linux/component.h"
#include "linux/of_device.h"
#include "vc4_drv.h"
@@ -327,7 +328,7 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
/* The pixelvalve can only feed one encoder (and encoders are
* 1:1 with connectors.)
*/
- if (drm_atomic_connectors_for_crtc(state->state, crtc) > 1)
+ if (hweight32(state->connector_mask) > 1)
return -EINVAL;
drm_atomic_crtc_state_for_each_plane(plane, state) {
@@ -476,10 +477,106 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
return ret;
}
+struct vc4_async_flip_state {
+ struct drm_crtc *crtc;
+ struct drm_framebuffer *fb;
+ struct drm_pending_vblank_event *event;
+
+ struct vc4_seqno_cb cb;
+};
+
+/* Called when the V3D execution for the BO being flipped to is done, so that
+ * we can actually update the plane's address to point to it.
+ */
+static void
+vc4_async_page_flip_complete(struct vc4_seqno_cb *cb)
+{
+ struct vc4_async_flip_state *flip_state =
+ container_of(cb, struct vc4_async_flip_state, cb);
+ struct drm_crtc *crtc = flip_state->crtc;
+ struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_plane *plane = crtc->primary;
+
+ vc4_plane_async_set_fb(plane, flip_state->fb);
+ if (flip_state->event) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ drm_crtc_send_vblank_event(crtc, flip_state->event);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+
+ drm_framebuffer_unreference(flip_state->fb);
+ kfree(flip_state);
+
+ up(&vc4->async_modeset);
+}
+
+/* Implements async (non-vblank-synced) page flips.
+ *
+ * The page flip ioctl needs to return immediately, so we grab the
+ * modeset semaphore on the pipe, and queue the address update for
+ * when V3D is done with the BO being flipped to.
+ */
+static int vc4_async_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t flags)
+{
+ struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_plane *plane = crtc->primary;
+ int ret = 0;
+ struct vc4_async_flip_state *flip_state;
+ struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
+ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
+
+ flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
+ if (!flip_state)
+ return -ENOMEM;
+
+ drm_framebuffer_reference(fb);
+ flip_state->fb = fb;
+ flip_state->crtc = crtc;
+ flip_state->event = event;
+
+ /* Make sure all other async modesetes have landed. */
+ ret = down_interruptible(&vc4->async_modeset);
+ if (ret) {
+ kfree(flip_state);
+ return ret;
+ }
+
+ /* Immediately update the plane's legacy fb pointer, so that later
+ * modeset prep sees the state that will be present when the semaphore
+ * is released.
+ */
+ drm_atomic_set_fb_for_plane(plane->state, fb);
+ plane->fb = fb;
+
+ vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno,
+ vc4_async_page_flip_complete);
+
+ /* Driver takes ownership of state on successful async commit. */
+ return 0;
+}
+
+static int vc4_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t flags)
+{
+ if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+ return vc4_async_page_flip(crtc, fb, event, flags);
+ else
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags);
+}
+
static const struct drm_crtc_funcs vc4_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.destroy = vc4_crtc_destroy,
- .page_flip = drm_atomic_helper_page_flip,
+ .page_flip = vc4_page_flip,
.set_property = NULL,
.cursor_set = NULL, /* handled by drm_mode_cursor_universal */
.cursor_move = NULL, /* handled by drm_mode_cursor_universal */
@@ -606,7 +703,7 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
}
drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane,
- &vc4_crtc_funcs);
+ &vc4_crtc_funcs, NULL);
drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
primary_plane->crtc = crtc;
cursor_plane->crtc = crtc;
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index 4297b0a5b74e..d76ad10b07fd 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -16,11 +16,14 @@
#include "vc4_regs.h"
static const struct drm_info_list vc4_debugfs_list[] = {
+ {"bo_stats", vc4_bo_stats_debugfs, 0},
{"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
{"hvs_regs", vc4_hvs_debugfs_regs, 0},
{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
{"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2},
+ {"v3d_ident", vc4_v3d_debugfs_ident, 0},
+ {"v3d_regs", vc4_v3d_debugfs_regs, 0},
};
#define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index d5db9e0f3b73..f1655fff8425 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include "drm_fb_cma_helper.h"
+#include "uapi/drm/vc4_drm.h"
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -63,7 +64,7 @@ static const struct file_operations vc4_drm_fops = {
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
- .mmap = drm_gem_cma_mmap,
+ .mmap = vc4_mmap,
.poll = drm_poll,
.read = drm_read,
#ifdef CONFIG_COMPAT
@@ -73,16 +74,30 @@ static const struct file_operations vc4_drm_fops = {
};
static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
+ DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_WAIT_SEQNO, vc4_wait_seqno_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl,
+ DRM_ROOT_ONLY),
};
static struct drm_driver vc4_drm_driver = {
.driver_features = (DRIVER_MODESET |
DRIVER_ATOMIC |
DRIVER_GEM |
+ DRIVER_HAVE_IRQ |
DRIVER_PRIME),
.lastclose = vc4_lastclose,
.preclose = vc4_drm_preclose,
+ .irq_handler = vc4_irq,
+ .irq_preinstall = vc4_irq_preinstall,
+ .irq_postinstall = vc4_irq_postinstall,
+ .irq_uninstall = vc4_irq_uninstall,
+
.enable_vblank = vc4_enable_vblank,
.disable_vblank = vc4_disable_vblank,
.get_vblank_counter = drm_vblank_count,
@@ -92,18 +107,19 @@ static struct drm_driver vc4_drm_driver = {
.debugfs_cleanup = vc4_debugfs_cleanup,
#endif
- .gem_free_object = drm_gem_cma_free_object,
+ .gem_create_object = vc4_create_object,
+ .gem_free_object = vc4_free_object,
.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_export = vc4_prime_export,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
- .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vmap = vc4_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
- .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .gem_prime_mmap = vc4_prime_mmap,
.dumb_create = vc4_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
@@ -168,15 +184,17 @@ static int vc4_drm_bind(struct device *dev)
vc4->dev = drm;
drm->dev_private = vc4;
- drm_dev_set_unique(drm, dev_name(dev));
+ vc4_bo_cache_init(drm);
drm_mode_config_init(drm);
if (ret)
goto unref;
+ vc4_gem_init(drm);
+
ret = component_bind_all(dev, drm);
if (ret)
- goto unref;
+ goto gem_destroy;
ret = drm_dev_register(drm, 0);
if (ret < 0)
@@ -200,8 +218,11 @@ unregister:
drm_dev_unregister(drm);
unbind_all:
component_unbind_all(dev, drm);
+gem_destroy:
+ vc4_gem_destroy(drm);
unref:
drm_dev_unref(drm);
+ vc4_bo_cache_destroy(drm);
return ret;
}
@@ -228,6 +249,7 @@ static struct platform_driver *const component_drivers[] = {
&vc4_hdmi_driver,
&vc4_crtc_driver,
&vc4_hvs_driver,
+ &vc4_v3d_driver,
};
static int vc4_platform_drm_probe(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index fd8319fa682e..080865ec2bae 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -15,8 +15,89 @@ struct vc4_dev {
struct vc4_hdmi *hdmi;
struct vc4_hvs *hvs;
struct vc4_crtc *crtc[3];
+ struct vc4_v3d *v3d;
struct drm_fbdev_cma *fbdev;
+
+ struct vc4_hang_state *hang_state;
+
+ /* The kernel-space BO cache. Tracks buffers that have been
+ * unreferenced by all other users (refcounts of 0!) but not
+ * yet freed, so we can do cheap allocations.
+ */
+ struct vc4_bo_cache {
+ /* Array of list heads for entries in the BO cache,
+ * based on number of pages, so we can do O(1) lookups
+ * in the cache when allocating.
+ */
+ struct list_head *size_list;
+ uint32_t size_list_size;
+
+ /* List of all BOs in the cache, ordered by age, so we
+ * can do O(1) lookups when trying to free old
+ * buffers.
+ */
+ struct list_head time_list;
+ struct work_struct time_work;
+ struct timer_list time_timer;
+ } bo_cache;
+
+ struct vc4_bo_stats {
+ u32 num_allocated;
+ u32 size_allocated;
+ u32 num_cached;
+ u32 size_cached;
+ } bo_stats;
+
+ /* Protects bo_cache and the BO stats. */
+ struct mutex bo_lock;
+
+ /* Sequence number for the last job queued in job_list.
+ * Starts at 0 (no jobs emitted).
+ */
+ uint64_t emit_seqno;
+
+ /* Sequence number for the last completed job on the GPU.
+ * Starts at 0 (no jobs completed).
+ */
+ uint64_t finished_seqno;
+
+ /* List of all struct vc4_exec_info for jobs to be executed.
+ * The first job in the list is the one currently programmed
+ * into ct0ca/ct1ca for execution.
+ */
+ struct list_head job_list;
+ /* List of the finished vc4_exec_infos waiting to be freed by
+ * job_done_work.
+ */
+ struct list_head job_done_list;
+ /* Spinlock used to synchronize the job_list and seqno
+ * accesses between the IRQ handler and GEM ioctls.
+ */
+ spinlock_t job_lock;
+ wait_queue_head_t job_wait_queue;
+ struct work_struct job_done_work;
+
+ /* List of struct vc4_seqno_cb for callbacks to be made from a
+ * workqueue when the given seqno is passed.
+ */
+ struct list_head seqno_cb_list;
+
+ /* The binner overflow memory that's currently set up in
+ * BPOA/BPOS registers. When overflow occurs and a new one is
+ * allocated, the previous one will be moved to
+ * vc4->current_exec's free list.
+ */
+ struct vc4_bo *overflow_mem;
+ struct work_struct overflow_mem_work;
+
+ struct {
+ uint32_t last_ct0ca, last_ct1ca;
+ struct timer_list timer;
+ struct work_struct reset_work;
+ } hangcheck;
+
+ struct semaphore async_modeset;
};
static inline struct vc4_dev *
@@ -27,6 +108,25 @@ to_vc4_dev(struct drm_device *dev)
struct vc4_bo {
struct drm_gem_cma_object base;
+
+ /* seqno of the last job to render to this BO. */
+ uint64_t seqno;
+
+ /* List entry for the BO's position in either
+ * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
+ */
+ struct list_head unref_head;
+
+ /* Time in jiffies when the BO was put in vc4->bo_cache. */
+ unsigned long free_time;
+
+ /* List entry for the BO's position in vc4_dev->bo_cache.size_list */
+ struct list_head size_head;
+
+ /* Struct for shader validation state, if created by
+ * DRM_IOCTL_VC4_CREATE_SHADER_BO.
+ */
+ struct vc4_validated_shader_info *validated_shader;
};
static inline struct vc4_bo *
@@ -35,6 +135,17 @@ to_vc4_bo(struct drm_gem_object *bo)
return (struct vc4_bo *)bo;
}
+struct vc4_seqno_cb {
+ struct work_struct work;
+ uint64_t seqno;
+ void (*func)(struct vc4_seqno_cb *cb);
+};
+
+struct vc4_v3d {
+ struct platform_device *pdev;
+ void __iomem *regs;
+};
+
struct vc4_hvs {
struct platform_device *pdev;
void __iomem *regs;
@@ -72,9 +183,142 @@ to_vc4_encoder(struct drm_encoder *encoder)
return container_of(encoder, struct vc4_encoder, base);
}
+#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
+#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
#define HVS_READ(offset) readl(vc4->hvs->regs + offset)
#define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset)
+struct vc4_exec_info {
+ /* Sequence number for this bin/render job. */
+ uint64_t seqno;
+
+ /* Kernel-space copy of the ioctl arguments */
+ struct drm_vc4_submit_cl *args;
+
+ /* This is the array of BOs that were looked up at the start of exec.
+ * Command validation will use indices into this array.
+ */
+ struct drm_gem_cma_object **bo;
+ uint32_t bo_count;
+
+ /* Pointers for our position in vc4->job_list */
+ struct list_head head;
+
+ /* List of other BOs used in the job that need to be released
+ * once the job is complete.
+ */
+ struct list_head unref_list;
+
+ /* Current unvalidated indices into @bo loaded by the non-hardware
+ * VC4_PACKET_GEM_HANDLES.
+ */
+ uint32_t bo_index[2];
+
+ /* This is the BO where we store the validated command lists, shader
+ * records, and uniforms.
+ */
+ struct drm_gem_cma_object *exec_bo;
+
+ /**
+ * This tracks the per-shader-record state (packet 64) that
+ * determines the length of the shader record and the offset
+ * it's expected to be found at. It gets read in from the
+ * command lists.
+ */
+ struct vc4_shader_state {
+ uint32_t addr;
+ /* Maximum vertex index referenced by any primitive using this
+ * shader state.
+ */
+ uint32_t max_index;
+ } *shader_state;
+
+ /** How many shader states the user declared they were using. */
+ uint32_t shader_state_size;
+ /** How many shader state records the validator has seen. */
+ uint32_t shader_state_count;
+
+ bool found_tile_binning_mode_config_packet;
+ bool found_start_tile_binning_packet;
+ bool found_increment_semaphore_packet;
+ bool found_flush;
+ uint8_t bin_tiles_x, bin_tiles_y;
+ struct drm_gem_cma_object *tile_bo;
+ uint32_t tile_alloc_offset;
+
+ /**
+ * Computed addresses pointing into exec_bo where we start the
+ * bin thread (ct0) and render thread (ct1).
+ */
+ uint32_t ct0ca, ct0ea;
+ uint32_t ct1ca, ct1ea;
+
+ /* Pointer to the unvalidated bin CL (if present). */
+ void *bin_u;
+
+ /* Pointers to the shader recs. These paddr gets incremented as CL
+ * packets are relocated in validate_gl_shader_state, and the vaddrs
+ * (u and v) get incremented and size decremented as the shader recs
+ * themselves are validated.
+ */
+ void *shader_rec_u;
+ void *shader_rec_v;
+ uint32_t shader_rec_p;
+ uint32_t shader_rec_size;
+
+ /* Pointers to the uniform data. These pointers are incremented, and
+ * size decremented, as each batch of uniforms is uploaded.
+ */
+ void *uniforms_u;
+ void *uniforms_v;
+ uint32_t uniforms_p;
+ uint32_t uniforms_size;
+};
+
+static inline struct vc4_exec_info *
+vc4_first_job(struct vc4_dev *vc4)
+{
+ if (list_empty(&vc4->job_list))
+ return NULL;
+ return list_first_entry(&vc4->job_list, struct vc4_exec_info, head);
+}
+
+/**
+ * struct vc4_texture_sample_info - saves the offsets into the UBO for texture
+ * setup parameters.
+ *
+ * This will be used at draw time to relocate the reference to the texture
+ * contents in p0, and validate that the offset combined with
+ * width/height/stride/etc. from p1 and p2/p3 doesn't sample outside the BO.
+ * Note that the hardware treats unprovided config parameters as 0, so not all
+ * of them need to be set up for every texure sample, and we'll store ~0 as
+ * the offset to mark the unused ones.
+ *
+ * See the VC4 3D architecture guide page 41 ("Texture and Memory Lookup Unit
+ * Setup") for definitions of the texture parameters.
+ */
+struct vc4_texture_sample_info {
+ bool is_direct;
+ uint32_t p_offset[4];
+};
+
+/**
+ * struct vc4_validated_shader_info - information about validated shaders that
+ * needs to be used from command list validation.
+ *
+ * For a given shader, each time a shader state record references it, we need
+ * to verify that the shader doesn't read more uniforms than the shader state
+ * record's uniform BO pointer can provide, and we need to apply relocations
+ * and validate the shader state record's uniforms that define the texture
+ * samples.
+ */
+struct vc4_validated_shader_info {
+ uint32_t uniforms_size;
+ uint32_t uniforms_src_size;
+ uint32_t num_texture_samples;
+ struct vc4_texture_sample_info *texture_samples;
+};
+
/**
* _wait_for - magic (register) wait macro
*
@@ -104,13 +348,29 @@ to_vc4_encoder(struct drm_encoder *encoder)
#define wait_for(COND, MS) _wait_for(COND, MS, 1)
/* vc4_bo.c */
+struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size);
void vc4_free_object(struct drm_gem_object *gem_obj);
-struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size);
+struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size,
+ bool from_cache);
int vc4_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
struct dma_buf *vc4_prime_export(struct drm_device *dev,
struct drm_gem_object *obj, int flags);
+int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
+int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+void *vc4_prime_vmap(struct drm_gem_object *obj);
+void vc4_bo_cache_init(struct drm_device *dev);
+void vc4_bo_cache_destroy(struct drm_device *dev);
+int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
/* vc4_crtc.c */
extern struct platform_driver vc4_crtc_driver;
@@ -126,10 +386,34 @@ void vc4_debugfs_cleanup(struct drm_minor *minor);
/* vc4_drv.c */
void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index);
+/* vc4_gem.c */
+void vc4_gem_init(struct drm_device *dev);
+void vc4_gem_destroy(struct drm_device *dev);
+int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+void vc4_submit_next_job(struct drm_device *dev);
+int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno,
+ uint64_t timeout_ns, bool interruptible);
+void vc4_job_handle_completed(struct vc4_dev *vc4);
+int vc4_queue_seqno_cb(struct drm_device *dev,
+ struct vc4_seqno_cb *cb, uint64_t seqno,
+ void (*func)(struct vc4_seqno_cb *cb));
+
/* vc4_hdmi.c */
extern struct platform_driver vc4_hdmi_driver;
int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
+/* vc4_irq.c */
+irqreturn_t vc4_irq(int irq, void *arg);
+void vc4_irq_preinstall(struct drm_device *dev);
+int vc4_irq_postinstall(struct drm_device *dev);
+void vc4_irq_uninstall(struct drm_device *dev);
+void vc4_irq_reset(struct drm_device *dev);
+
/* vc4_hvs.c */
extern struct platform_driver vc4_hvs_driver;
void vc4_hvs_dump_state(struct drm_device *dev);
@@ -143,3 +427,35 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
enum drm_plane_type type);
u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist);
u32 vc4_plane_dlist_size(struct drm_plane_state *state);
+void vc4_plane_async_set_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb);
+
+/* vc4_v3d.c */
+extern struct platform_driver vc4_v3d_driver;
+int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
+int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
+int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
+
+/* vc4_validate.c */
+int
+vc4_validate_bin_cl(struct drm_device *dev,
+ void *validated,
+ void *unvalidated,
+ struct vc4_exec_info *exec);
+
+int
+vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec);
+
+struct drm_gem_cma_object *vc4_use_bo(struct vc4_exec_info *exec,
+ uint32_t hindex);
+
+int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec);
+
+bool vc4_check_tex_size(struct vc4_exec_info *exec,
+ struct drm_gem_cma_object *fbo,
+ uint32_t offset, uint8_t tiling_format,
+ uint32_t width, uint32_t height, uint8_t cpp);
+
+/* vc4_validate_shader.c */
+struct vc4_validated_shader_info *
+vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
new file mode 100644
index 000000000000..48ce30a6f4b5
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -0,0 +1,866 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include "uapi/drm/vc4_drm.h"
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+#include "vc4_trace.h"
+
+static void
+vc4_queue_hangcheck(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ mod_timer(&vc4->hangcheck.timer,
+ round_jiffies_up(jiffies + msecs_to_jiffies(100)));
+}
+
+struct vc4_hang_state {
+ struct drm_vc4_get_hang_state user_state;
+
+ u32 bo_count;
+ struct drm_gem_object **bo;
+};
+
+static void
+vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state)
+{
+ unsigned int i;
+
+ mutex_lock(&dev->struct_mutex);
+ for (i = 0; i < state->user_state.bo_count; i++)
+ drm_gem_object_unreference(state->bo[i]);
+ mutex_unlock(&dev->struct_mutex);
+
+ kfree(state);
+}
+
+int
+vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_get_hang_state *get_state = data;
+ struct drm_vc4_get_hang_state_bo *bo_state;
+ struct vc4_hang_state *kernel_state;
+ struct drm_vc4_get_hang_state *state;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long irqflags;
+ u32 i;
+ int ret = 0;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ kernel_state = vc4->hang_state;
+ if (!kernel_state) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return -ENOENT;
+ }
+ state = &kernel_state->user_state;
+
+ /* If the user's array isn't big enough, just return the
+ * required array size.
+ */
+ if (get_state->bo_count < state->bo_count) {
+ get_state->bo_count = state->bo_count;
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return 0;
+ }
+
+ vc4->hang_state = NULL;
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
+ /* Save the user's BO pointer, so we don't stomp it with the memcpy. */
+ state->bo = get_state->bo;
+ memcpy(get_state, state, sizeof(*state));
+
+ bo_state = kcalloc(state->bo_count, sizeof(*bo_state), GFP_KERNEL);
+ if (!bo_state) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ for (i = 0; i < state->bo_count; i++) {
+ struct vc4_bo *vc4_bo = to_vc4_bo(kernel_state->bo[i]);
+ u32 handle;
+
+ ret = drm_gem_handle_create(file_priv, kernel_state->bo[i],
+ &handle);
+
+ if (ret) {
+ state->bo_count = i - 1;
+ goto err;
+ }
+ bo_state[i].handle = handle;
+ bo_state[i].paddr = vc4_bo->base.paddr;
+ bo_state[i].size = vc4_bo->base.base.size;
+ }
+
+ if (copy_to_user((void __user *)(uintptr_t)get_state->bo,
+ bo_state,
+ state->bo_count * sizeof(*bo_state)))
+ ret = -EFAULT;
+
+ kfree(bo_state);
+
+err_free:
+
+ vc4_free_hang_state(dev, kernel_state);
+
+err:
+ return ret;
+}
+
+static void
+vc4_save_hang_state(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_vc4_get_hang_state *state;
+ struct vc4_hang_state *kernel_state;
+ struct vc4_exec_info *exec;
+ struct vc4_bo *bo;
+ unsigned long irqflags;
+ unsigned int i, unref_list_count;
+
+ kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL);
+ if (!kernel_state)
+ return;
+
+ state = &kernel_state->user_state;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ exec = vc4_first_job(vc4);
+ if (!exec) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return;
+ }
+
+ unref_list_count = 0;
+ list_for_each_entry(bo, &exec->unref_list, unref_head)
+ unref_list_count++;
+
+ state->bo_count = exec->bo_count + unref_list_count;
+ kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo),
+ GFP_ATOMIC);
+ if (!kernel_state->bo) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return;
+ }
+
+ for (i = 0; i < exec->bo_count; i++) {
+ drm_gem_object_reference(&exec->bo[i]->base);
+ kernel_state->bo[i] = &exec->bo[i]->base;
+ }
+
+ list_for_each_entry(bo, &exec->unref_list, unref_head) {
+ drm_gem_object_reference(&bo->base.base);
+ kernel_state->bo[i] = &bo->base.base;
+ i++;
+ }
+
+ state->start_bin = exec->ct0ca;
+ state->start_render = exec->ct1ca;
+
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
+ state->ct0ca = V3D_READ(V3D_CTNCA(0));
+ state->ct0ea = V3D_READ(V3D_CTNEA(0));
+
+ state->ct1ca = V3D_READ(V3D_CTNCA(1));
+ state->ct1ea = V3D_READ(V3D_CTNEA(1));
+
+ state->ct0cs = V3D_READ(V3D_CTNCS(0));
+ state->ct1cs = V3D_READ(V3D_CTNCS(1));
+
+ state->ct0ra0 = V3D_READ(V3D_CT00RA0);
+ state->ct1ra0 = V3D_READ(V3D_CT01RA0);
+
+ state->bpca = V3D_READ(V3D_BPCA);
+ state->bpcs = V3D_READ(V3D_BPCS);
+ state->bpoa = V3D_READ(V3D_BPOA);
+ state->bpos = V3D_READ(V3D_BPOS);
+
+ state->vpmbase = V3D_READ(V3D_VPMBASE);
+
+ state->dbge = V3D_READ(V3D_DBGE);
+ state->fdbgo = V3D_READ(V3D_FDBGO);
+ state->fdbgb = V3D_READ(V3D_FDBGB);
+ state->fdbgr = V3D_READ(V3D_FDBGR);
+ state->fdbgs = V3D_READ(V3D_FDBGS);
+ state->errstat = V3D_READ(V3D_ERRSTAT);
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ if (vc4->hang_state) {
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ vc4_free_hang_state(dev, kernel_state);
+ } else {
+ vc4->hang_state = kernel_state;
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ }
+}
+
+static void
+vc4_reset(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ DRM_INFO("Resetting GPU.\n");
+ vc4_v3d_set_power(vc4, false);
+ vc4_v3d_set_power(vc4, true);
+
+ vc4_irq_reset(dev);
+
+ /* Rearm the hangcheck -- another job might have been waiting
+ * for our hung one to get kicked off, and vc4_irq_reset()
+ * would have started it.
+ */
+ vc4_queue_hangcheck(dev);
+}
+
+static void
+vc4_reset_work(struct work_struct *work)
+{
+ struct vc4_dev *vc4 =
+ container_of(work, struct vc4_dev, hangcheck.reset_work);
+
+ vc4_save_hang_state(vc4->dev);
+
+ vc4_reset(vc4->dev);
+}
+
+static void
+vc4_hangcheck_elapsed(unsigned long data)
+{
+ struct drm_device *dev = (struct drm_device *)data;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t ct0ca, ct1ca;
+
+ /* If idle, we can stop watching for hangs. */
+ if (list_empty(&vc4->job_list))
+ return;
+
+ ct0ca = V3D_READ(V3D_CTNCA(0));
+ ct1ca = V3D_READ(V3D_CTNCA(1));
+
+ /* If we've made any progress in execution, rearm the timer
+ * and wait.
+ */
+ if (ct0ca != vc4->hangcheck.last_ct0ca ||
+ ct1ca != vc4->hangcheck.last_ct1ca) {
+ vc4->hangcheck.last_ct0ca = ct0ca;
+ vc4->hangcheck.last_ct1ca = ct1ca;
+ vc4_queue_hangcheck(dev);
+ return;
+ }
+
+ /* We've gone too long with no progress, reset. This has to
+ * be done from a work struct, since resetting can sleep and
+ * this timer hook isn't allowed to.
+ */
+ schedule_work(&vc4->hangcheck.reset_work);
+}
+
+static void
+submit_cl(struct drm_device *dev, uint32_t thread, uint32_t start, uint32_t end)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ /* Set the current and end address of the control list.
+ * Writing the end register is what starts the job.
+ */
+ V3D_WRITE(V3D_CTNCA(thread), start);
+ V3D_WRITE(V3D_CTNEA(thread), end);
+}
+
+int
+vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns,
+ bool interruptible)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret = 0;
+ unsigned long timeout_expire;
+ DEFINE_WAIT(wait);
+
+ if (vc4->finished_seqno >= seqno)
+ return 0;
+
+ if (timeout_ns == 0)
+ return -ETIME;
+
+ timeout_expire = jiffies + nsecs_to_jiffies(timeout_ns);
+
+ trace_vc4_wait_for_seqno_begin(dev, seqno, timeout_ns);
+ for (;;) {
+ prepare_to_wait(&vc4->job_wait_queue, &wait,
+ interruptible ? TASK_INTERRUPTIBLE :
+ TASK_UNINTERRUPTIBLE);
+
+ if (interruptible && signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ if (vc4->finished_seqno >= seqno)
+ break;
+
+ if (timeout_ns != ~0ull) {
+ if (time_after_eq(jiffies, timeout_expire)) {
+ ret = -ETIME;
+ break;
+ }
+ schedule_timeout(timeout_expire - jiffies);
+ } else {
+ schedule();
+ }
+ }
+
+ finish_wait(&vc4->job_wait_queue, &wait);
+ trace_vc4_wait_for_seqno_end(dev, seqno);
+
+ if (ret && ret != -ERESTARTSYS) {
+ DRM_ERROR("timeout waiting for render thread idle\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+vc4_flush_caches(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ /* Flush the GPU L2 caches. These caches sit on top of system
+ * L3 (the 128kb or so shared with the CPU), and are
+ * non-allocating in the L3.
+ */
+ V3D_WRITE(V3D_L2CACTL,
+ V3D_L2CACTL_L2CCLR);
+
+ V3D_WRITE(V3D_SLCACTL,
+ VC4_SET_FIELD(0xf, V3D_SLCACTL_T1CC) |
+ VC4_SET_FIELD(0xf, V3D_SLCACTL_T0CC) |
+ VC4_SET_FIELD(0xf, V3D_SLCACTL_UCC) |
+ VC4_SET_FIELD(0xf, V3D_SLCACTL_ICC));
+}
+
+/* Sets the registers for the next job to be actually be executed in
+ * the hardware.
+ *
+ * The job_lock should be held during this.
+ */
+void
+vc4_submit_next_job(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_exec_info *exec = vc4_first_job(vc4);
+
+ if (!exec)
+ return;
+
+ vc4_flush_caches(dev);
+
+ /* Disable the binner's pre-loaded overflow memory address */
+ V3D_WRITE(V3D_BPOA, 0);
+ V3D_WRITE(V3D_BPOS, 0);
+
+ if (exec->ct0ca != exec->ct0ea)
+ submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
+ submit_cl(dev, 1, exec->ct1ca, exec->ct1ea);
+}
+
+static void
+vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
+{
+ struct vc4_bo *bo;
+ unsigned i;
+
+ for (i = 0; i < exec->bo_count; i++) {
+ bo = to_vc4_bo(&exec->bo[i]->base);
+ bo->seqno = seqno;
+ }
+
+ list_for_each_entry(bo, &exec->unref_list, unref_head) {
+ bo->seqno = seqno;
+ }
+}
+
+/* Queues a struct vc4_exec_info for execution. If no job is
+ * currently executing, then submits it.
+ *
+ * Unlike most GPUs, our hardware only handles one command list at a
+ * time. To queue multiple jobs at once, we'd need to edit the
+ * previous command list to have a jump to the new one at the end, and
+ * then bump the end address. That's a change for a later date,
+ * though.
+ */
+static void
+vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint64_t seqno;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+
+ seqno = ++vc4->emit_seqno;
+ exec->seqno = seqno;
+ vc4_update_bo_seqnos(exec, seqno);
+
+ list_add_tail(&exec->head, &vc4->job_list);
+
+ /* If no job was executing, kick ours off. Otherwise, it'll
+ * get started when the previous job's frame done interrupt
+ * occurs.
+ */
+ if (vc4_first_job(vc4) == exec) {
+ vc4_submit_next_job(dev);
+ vc4_queue_hangcheck(dev);
+ }
+
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+}
+
+/**
+ * Looks up a bunch of GEM handles for BOs and stores the array for
+ * use in the command validator that actually writes relocated
+ * addresses pointing to them.
+ */
+static int
+vc4_cl_lookup_bos(struct drm_device *dev,
+ struct drm_file *file_priv,
+ struct vc4_exec_info *exec)
+{
+ struct drm_vc4_submit_cl *args = exec->args;
+ uint32_t *handles;
+ int ret = 0;
+ int i;
+
+ exec->bo_count = args->bo_handle_count;
+
+ if (!exec->bo_count) {
+ /* See comment on bo_index for why we have to check
+ * this.
+ */
+ DRM_ERROR("Rendering requires BOs to validate\n");
+ return -EINVAL;
+ }
+
+ exec->bo = kcalloc(exec->bo_count, sizeof(struct drm_gem_cma_object *),
+ GFP_KERNEL);
+ if (!exec->bo) {
+ DRM_ERROR("Failed to allocate validated BO pointers\n");
+ return -ENOMEM;
+ }
+
+ handles = drm_malloc_ab(exec->bo_count, sizeof(uint32_t));
+ if (!handles) {
+ DRM_ERROR("Failed to allocate incoming GEM handles\n");
+ goto fail;
+ }
+
+ ret = copy_from_user(handles,
+ (void __user *)(uintptr_t)args->bo_handles,
+ exec->bo_count * sizeof(uint32_t));
+ if (ret) {
+ DRM_ERROR("Failed to copy in GEM handles\n");
+ goto fail;
+ }
+
+ spin_lock(&file_priv->table_lock);
+ for (i = 0; i < exec->bo_count; i++) {
+ struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
+ handles[i]);
+ if (!bo) {
+ DRM_ERROR("Failed to look up GEM BO %d: %d\n",
+ i, handles[i]);
+ ret = -EINVAL;
+ spin_unlock(&file_priv->table_lock);
+ goto fail;
+ }
+ drm_gem_object_reference(bo);
+ exec->bo[i] = (struct drm_gem_cma_object *)bo;
+ }
+ spin_unlock(&file_priv->table_lock);
+
+fail:
+ kfree(handles);
+ return 0;
+}
+
+static int
+vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
+{
+ struct drm_vc4_submit_cl *args = exec->args;
+ void *temp = NULL;
+ void *bin;
+ int ret = 0;
+ uint32_t bin_offset = 0;
+ uint32_t shader_rec_offset = roundup(bin_offset + args->bin_cl_size,
+ 16);
+ uint32_t uniforms_offset = shader_rec_offset + args->shader_rec_size;
+ uint32_t exec_size = uniforms_offset + args->uniforms_size;
+ uint32_t temp_size = exec_size + (sizeof(struct vc4_shader_state) *
+ args->shader_rec_count);
+ struct vc4_bo *bo;
+
+ if (uniforms_offset < shader_rec_offset ||
+ exec_size < uniforms_offset ||
+ args->shader_rec_count >= (UINT_MAX /
+ sizeof(struct vc4_shader_state)) ||
+ temp_size < exec_size) {
+ DRM_ERROR("overflow in exec arguments\n");
+ goto fail;
+ }
+
+ /* Allocate space where we'll store the copied in user command lists
+ * and shader records.
+ *
+ * We don't just copy directly into the BOs because we need to
+ * read the contents back for validation, and I think the
+ * bo->vaddr is uncached access.
+ */
+ temp = kmalloc(temp_size, GFP_KERNEL);
+ if (!temp) {
+ DRM_ERROR("Failed to allocate storage for copying "
+ "in bin/render CLs.\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ bin = temp + bin_offset;
+ exec->shader_rec_u = temp + shader_rec_offset;
+ exec->uniforms_u = temp + uniforms_offset;
+ exec->shader_state = temp + exec_size;
+ exec->shader_state_size = args->shader_rec_count;
+
+ if (copy_from_user(bin,
+ (void __user *)(uintptr_t)args->bin_cl,
+ args->bin_cl_size)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ if (copy_from_user(exec->shader_rec_u,
+ (void __user *)(uintptr_t)args->shader_rec,
+ args->shader_rec_size)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ if (copy_from_user(exec->uniforms_u,
+ (void __user *)(uintptr_t)args->uniforms,
+ args->uniforms_size)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ bo = vc4_bo_create(dev, exec_size, true);
+ if (!bo) {
+ DRM_ERROR("Couldn't allocate BO for binning\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ exec->exec_bo = &bo->base;
+
+ list_add_tail(&to_vc4_bo(&exec->exec_bo->base)->unref_head,
+ &exec->unref_list);
+
+ exec->ct0ca = exec->exec_bo->paddr + bin_offset;
+
+ exec->bin_u = bin;
+
+ exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset;
+ exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset;
+ exec->shader_rec_size = args->shader_rec_size;
+
+ exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset;
+ exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset;
+ exec->uniforms_size = args->uniforms_size;
+
+ ret = vc4_validate_bin_cl(dev,
+ exec->exec_bo->vaddr + bin_offset,
+ bin,
+ exec);
+ if (ret)
+ goto fail;
+
+ ret = vc4_validate_shader_recs(dev, exec);
+
+fail:
+ kfree(temp);
+ return ret;
+}
+
+static void
+vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
+{
+ unsigned i;
+
+ /* Need the struct lock for drm_gem_object_unreference(). */
+ mutex_lock(&dev->struct_mutex);
+ if (exec->bo) {
+ for (i = 0; i < exec->bo_count; i++)
+ drm_gem_object_unreference(&exec->bo[i]->base);
+ kfree(exec->bo);
+ }
+
+ while (!list_empty(&exec->unref_list)) {
+ struct vc4_bo *bo = list_first_entry(&exec->unref_list,
+ struct vc4_bo, unref_head);
+ list_del(&bo->unref_head);
+ drm_gem_object_unreference(&bo->base.base);
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ kfree(exec);
+}
+
+void
+vc4_job_handle_completed(struct vc4_dev *vc4)
+{
+ unsigned long irqflags;
+ struct vc4_seqno_cb *cb, *cb_temp;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ while (!list_empty(&vc4->job_done_list)) {
+ struct vc4_exec_info *exec =
+ list_first_entry(&vc4->job_done_list,
+ struct vc4_exec_info, head);
+ list_del(&exec->head);
+
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ vc4_complete_exec(vc4->dev, exec);
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ }
+
+ list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
+ if (cb->seqno <= vc4->finished_seqno) {
+ list_del_init(&cb->work.entry);
+ schedule_work(&cb->work);
+ }
+ }
+
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+}
+
+static void vc4_seqno_cb_work(struct work_struct *work)
+{
+ struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work);
+
+ cb->func(cb);
+}
+
+int vc4_queue_seqno_cb(struct drm_device *dev,
+ struct vc4_seqno_cb *cb, uint64_t seqno,
+ void (*func)(struct vc4_seqno_cb *cb))
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret = 0;
+ unsigned long irqflags;
+
+ cb->func = func;
+ INIT_WORK(&cb->work, vc4_seqno_cb_work);
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ if (seqno > vc4->finished_seqno) {
+ cb->seqno = seqno;
+ list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
+ } else {
+ schedule_work(&cb->work);
+ }
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
+ return ret;
+}
+
+/* Scheduled when any job has been completed, this walks the list of
+ * jobs that had completed and unrefs their BOs and frees their exec
+ * structs.
+ */
+static void
+vc4_job_done_work(struct work_struct *work)
+{
+ struct vc4_dev *vc4 =
+ container_of(work, struct vc4_dev, job_done_work);
+
+ vc4_job_handle_completed(vc4);
+}
+
+static int
+vc4_wait_for_seqno_ioctl_helper(struct drm_device *dev,
+ uint64_t seqno,
+ uint64_t *timeout_ns)
+{
+ unsigned long start = jiffies;
+ int ret = vc4_wait_for_seqno(dev, seqno, *timeout_ns, true);
+
+ if ((ret == -EINTR || ret == -ERESTARTSYS) && *timeout_ns != ~0ull) {
+ uint64_t delta = jiffies_to_nsecs(jiffies - start);
+
+ if (*timeout_ns >= delta)
+ *timeout_ns -= delta;
+ }
+
+ return ret;
+}
+
+int
+vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_wait_seqno *args = data;
+
+ return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno,
+ &args->timeout_ns);
+}
+
+int
+vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ int ret;
+ struct drm_vc4_wait_bo *args = data;
+ struct drm_gem_object *gem_obj;
+ struct vc4_bo *bo;
+
+ gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+ bo = to_vc4_bo(gem_obj);
+
+ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno,
+ &args->timeout_ns);
+
+ drm_gem_object_unreference_unlocked(gem_obj);
+ return ret;
+}
+
+/**
+ * Submits a command list to the VC4.
+ *
+ * This is what is called batchbuffer emitting on other hardware.
+ */
+int
+vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_vc4_submit_cl *args = data;
+ struct vc4_exec_info *exec;
+ int ret;
+
+ if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
+ DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
+ return -EINVAL;
+ }
+
+ exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
+ if (!exec) {
+ DRM_ERROR("malloc failure on exec struct\n");
+ return -ENOMEM;
+ }
+
+ exec->args = args;
+ INIT_LIST_HEAD(&exec->unref_list);
+
+ ret = vc4_cl_lookup_bos(dev, file_priv, exec);
+ if (ret)
+ goto fail;
+
+ if (exec->args->bin_cl_size != 0) {
+ ret = vc4_get_bcl(dev, exec);
+ if (ret)
+ goto fail;
+ } else {
+ exec->ct0ca = 0;
+ exec->ct0ea = 0;
+ }
+
+ ret = vc4_get_rcl(dev, exec);
+ if (ret)
+ goto fail;
+
+ /* Clear this out of the struct we'll be putting in the queue,
+ * since it's part of our stack.
+ */
+ exec->args = NULL;
+
+ vc4_queue_submit(dev, exec);
+
+ /* Return the seqno for our job. */
+ args->seqno = vc4->emit_seqno;
+
+ return 0;
+
+fail:
+ vc4_complete_exec(vc4->dev, exec);
+
+ return ret;
+}
+
+void
+vc4_gem_init(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ INIT_LIST_HEAD(&vc4->job_list);
+ INIT_LIST_HEAD(&vc4->job_done_list);
+ INIT_LIST_HEAD(&vc4->seqno_cb_list);
+ spin_lock_init(&vc4->job_lock);
+
+ INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work);
+ setup_timer(&vc4->hangcheck.timer,
+ vc4_hangcheck_elapsed,
+ (unsigned long)dev);
+
+ INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
+}
+
+void
+vc4_gem_destroy(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ /* Waiting for exec to finish would need to be done before
+ * unregistering V3D.
+ */
+ WARN_ON(vc4->emit_seqno != vc4->finished_seqno);
+
+ /* V3D should already have disabled its interrupt and cleared
+ * the overflow allocation registers. Now free the object.
+ */
+ if (vc4->overflow_mem) {
+ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
+ vc4->overflow_mem = NULL;
+ }
+
+ vc4_bo_cache_destroy(dev);
+
+ if (vc4->hang_state)
+ vc4_free_hang_state(dev, vc4->hang_state);
+}
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index da9a36d6e1d1..c69c0460196b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -519,7 +519,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0);
drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs);
hdmi->connector = vc4_hdmi_connector_init(drm, hdmi->encoder);
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
new file mode 100644
index 000000000000..b68060e758db
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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.
+ */
+
+/** DOC: Interrupt management for the V3D engine.
+ *
+ * We have an interrupt status register (V3D_INTCTL) which reports
+ * interrupts, and where writing 1 bits clears those interrupts.
+ * There are also a pair of interrupt registers
+ * (V3D_INTENA/V3D_INTDIS) where writing a 1 to their bits enables or
+ * disables that specific interrupt, and 0s written are ignored
+ * (reading either one returns the set of enabled interrupts).
+ *
+ * When we take a render frame interrupt, we need to wake the
+ * processes waiting for some frame to be done, and get the next frame
+ * submitted ASAP (so the hardware doesn't sit idle when there's work
+ * to do).
+ *
+ * When we take the binner out of memory interrupt, we need to
+ * allocate some new memory and pass it to the binner so that the
+ * current job can make progress.
+ */
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \
+ V3D_INT_FRDONE)
+
+DECLARE_WAIT_QUEUE_HEAD(render_wait);
+
+static void
+vc4_overflow_mem_work(struct work_struct *work)
+{
+ struct vc4_dev *vc4 =
+ container_of(work, struct vc4_dev, overflow_mem_work);
+ struct drm_device *dev = vc4->dev;
+ struct vc4_bo *bo;
+
+ bo = vc4_bo_create(dev, 256 * 1024, true);
+ if (!bo) {
+ DRM_ERROR("Couldn't allocate binner overflow mem\n");
+ return;
+ }
+
+ /* If there's a job executing currently, then our previous
+ * overflow allocation is getting used in that job and we need
+ * to queue it to be released when the job is done. But if no
+ * job is executing at all, then we can free the old overflow
+ * object direcctly.
+ *
+ * No lock necessary for this pointer since we're the only
+ * ones that update the pointer, and our workqueue won't
+ * reenter.
+ */
+ if (vc4->overflow_mem) {
+ struct vc4_exec_info *current_exec;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ current_exec = vc4_first_job(vc4);
+ if (current_exec) {
+ vc4->overflow_mem->seqno = vc4->finished_seqno + 1;
+ list_add_tail(&vc4->overflow_mem->unref_head,
+ &current_exec->unref_list);
+ vc4->overflow_mem = NULL;
+ }
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ }
+
+ if (vc4->overflow_mem)
+ drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base);
+ vc4->overflow_mem = bo;
+
+ V3D_WRITE(V3D_BPOA, bo->base.paddr);
+ V3D_WRITE(V3D_BPOS, bo->base.base.size);
+ V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM);
+ V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
+}
+
+static void
+vc4_irq_finish_job(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_exec_info *exec = vc4_first_job(vc4);
+
+ if (!exec)
+ return;
+
+ vc4->finished_seqno++;
+ list_move_tail(&exec->head, &vc4->job_done_list);
+ vc4_submit_next_job(dev);
+
+ wake_up_all(&vc4->job_wait_queue);
+ schedule_work(&vc4->job_done_work);
+}
+
+irqreturn_t
+vc4_irq(int irq, void *arg)
+{
+ struct drm_device *dev = arg;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t intctl;
+ irqreturn_t status = IRQ_NONE;
+
+ barrier();
+ intctl = V3D_READ(V3D_INTCTL);
+
+ /* Acknowledge the interrupts we're handling here. The render
+ * frame done interrupt will be cleared, while OUTOMEM will
+ * stay high until the underlying cause is cleared.
+ */
+ V3D_WRITE(V3D_INTCTL, intctl);
+
+ if (intctl & V3D_INT_OUTOMEM) {
+ /* Disable OUTOMEM until the work is done. */
+ V3D_WRITE(V3D_INTDIS, V3D_INT_OUTOMEM);
+ schedule_work(&vc4->overflow_mem_work);
+ status = IRQ_HANDLED;
+ }
+
+ if (intctl & V3D_INT_FRDONE) {
+ spin_lock(&vc4->job_lock);
+ vc4_irq_finish_job(dev);
+ spin_unlock(&vc4->job_lock);
+ status = IRQ_HANDLED;
+ }
+
+ return status;
+}
+
+void
+vc4_irq_preinstall(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ init_waitqueue_head(&vc4->job_wait_queue);
+ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
+
+ /* Clear any pending interrupts someone might have left around
+ * for us.
+ */
+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
+}
+
+int
+vc4_irq_postinstall(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ /* Enable both the render done and out of memory interrupts. */
+ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
+
+ return 0;
+}
+
+void
+vc4_irq_uninstall(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ /* Disable sending interrupts for our driver's IRQs. */
+ V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
+
+ /* Clear any pending interrupts we might have left. */
+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
+
+ cancel_work_sync(&vc4->overflow_mem_work);
+}
+
+/** Reinitializes interrupt registers when a GPU reset is performed. */
+void vc4_irq_reset(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ unsigned long irqflags;
+
+ /* Acknowledge any stale IRQs. */
+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
+
+ /*
+ * Turn all our interrupts on. Binner out of memory is the
+ * only one we expect to trigger at this point, since we've
+ * just come from poweron and haven't supplied any overflow
+ * memory yet.
+ */
+ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
+
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ vc4_irq_finish_job(dev);
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+}
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 2e5597d10cc6..f95f2df5f8d1 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -15,6 +15,7 @@
*/
#include "drm_crtc.h"
+#include "drm_atomic.h"
#include "drm_atomic_helper.h"
#include "drm_crtc_helper.h"
#include "drm_plane_helper.h"
@@ -29,10 +30,152 @@ static void vc4_output_poll_changed(struct drm_device *dev)
drm_fbdev_cma_hotplug_event(vc4->fbdev);
}
+struct vc4_commit {
+ struct drm_device *dev;
+ struct drm_atomic_state *state;
+ struct vc4_seqno_cb cb;
+};
+
+static void
+vc4_atomic_complete_commit(struct vc4_commit *c)
+{
+ struct drm_atomic_state *state = c->state;
+ struct drm_device *dev = state->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state, false);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+
+ drm_atomic_state_free(state);
+
+ up(&vc4->async_modeset);
+
+ kfree(c);
+}
+
+static void
+vc4_atomic_complete_commit_seqno_cb(struct vc4_seqno_cb *cb)
+{
+ struct vc4_commit *c = container_of(cb, struct vc4_commit, cb);
+
+ vc4_atomic_complete_commit(c);
+}
+
+static struct vc4_commit *commit_init(struct drm_atomic_state *state)
+{
+ struct vc4_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
+
+ if (!c)
+ return NULL;
+ c->dev = state->dev;
+ c->state = state;
+
+ return c;
+}
+
+/**
+ * vc4_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a with drm_atomic_helper_check() pre-validated state
+ * object. This can still fail when e.g. the framebuffer reservation fails. For
+ * now this doesn't implement asynchronous commits.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+static int vc4_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret;
+ int i;
+ uint64_t wait_seqno = 0;
+ struct vc4_commit *c;
+
+ c = commit_init(state);
+ if (!c)
+ return -ENOMEM;
+
+ /* Make sure that any outstanding modesets have finished. */
+ ret = down_interruptible(&vc4->async_modeset);
+ if (ret) {
+ kfree(c);
+ return ret;
+ }
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret) {
+ kfree(c);
+ up(&vc4->async_modeset);
+ return ret;
+ }
+
+ for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+ struct drm_plane *plane = state->planes[i];
+ struct drm_plane_state *new_state = state->plane_states[i];
+
+ if (!plane)
+ continue;
+
+ if ((plane->state->fb != new_state->fb) && new_state->fb) {
+ struct drm_gem_cma_object *cma_bo =
+ drm_fb_cma_get_gem_obj(new_state->fb, 0);
+ struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
+
+ wait_seqno = max(bo->seqno, wait_seqno);
+ }
+ }
+
+ /*
+ * This is the point of no return - everything below never fails except
+ * when the hw goes bonghits. Which means we can commit the new state on
+ * the software side now.
+ */
+
+ drm_atomic_helper_swap_state(dev, state);
+
+ /*
+ * Everything below can be run asynchronously without the need to grab
+ * any modeset locks at all under one condition: It must be guaranteed
+ * that the asynchronous work has either been cancelled (if the driver
+ * supports it, which at least requires that the framebuffers get
+ * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+ * before the new state gets committed on the software side with
+ * drm_atomic_helper_swap_state().
+ *
+ * This scheme allows new atomic state updates to be prepared and
+ * checked in parallel to the asynchronous completion of the previous
+ * update. Which is important since compositors need to figure out the
+ * composition of the next frame right after having submitted the
+ * current layout.
+ */
+
+ if (async) {
+ vc4_queue_seqno_cb(dev, &c->cb, wait_seqno,
+ vc4_atomic_complete_commit_seqno_cb);
+ } else {
+ vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false);
+ vc4_atomic_complete_commit(c);
+ }
+
+ return 0;
+}
+
static const struct drm_mode_config_funcs vc4_mode_funcs = {
.output_poll_changed = vc4_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
+ .atomic_commit = vc4_atomic_commit,
.fb_create = drm_fb_cma_create,
};
@@ -41,6 +184,8 @@ int vc4_kms_load(struct drm_device *dev)
struct vc4_dev *vc4 = to_vc4_dev(dev);
int ret;
+ sema_init(&vc4->async_modeset, 1);
+
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
@@ -51,6 +196,8 @@ int vc4_kms_load(struct drm_device *dev)
dev->mode_config.max_height = 2048;
dev->mode_config.funcs = &vc4_mode_funcs;
dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+
dev->vblank_disable_allowed = true;
drm_mode_config_reset(dev);
diff --git a/drivers/gpu/drm/vc4/vc4_packet.h b/drivers/gpu/drm/vc4/vc4_packet.h
new file mode 100644
index 000000000000..0f31cc06500f
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_packet.h
@@ -0,0 +1,399 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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.
+ */
+
+#ifndef VC4_PACKET_H
+#define VC4_PACKET_H
+
+#include "vc4_regs.h" /* for VC4_MASK, VC4_GET_FIELD, VC4_SET_FIELD */
+
+enum vc4_packet {
+ VC4_PACKET_HALT = 0,
+ VC4_PACKET_NOP = 1,
+
+ VC4_PACKET_FLUSH = 4,
+ VC4_PACKET_FLUSH_ALL = 5,
+ VC4_PACKET_START_TILE_BINNING = 6,
+ VC4_PACKET_INCREMENT_SEMAPHORE = 7,
+ VC4_PACKET_WAIT_ON_SEMAPHORE = 8,
+
+ VC4_PACKET_BRANCH = 16,
+ VC4_PACKET_BRANCH_TO_SUB_LIST = 17,
+
+ VC4_PACKET_STORE_MS_TILE_BUFFER = 24,
+ VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25,
+ VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26,
+ VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27,
+ VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28,
+ VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29,
+
+ VC4_PACKET_GL_INDEXED_PRIMITIVE = 32,
+ VC4_PACKET_GL_ARRAY_PRIMITIVE = 33,
+
+ VC4_PACKET_COMPRESSED_PRIMITIVE = 48,
+ VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49,
+
+ VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56,
+
+ VC4_PACKET_GL_SHADER_STATE = 64,
+ VC4_PACKET_NV_SHADER_STATE = 65,
+ VC4_PACKET_VG_SHADER_STATE = 66,
+
+ VC4_PACKET_CONFIGURATION_BITS = 96,
+ VC4_PACKET_FLAT_SHADE_FLAGS = 97,
+ VC4_PACKET_POINT_SIZE = 98,
+ VC4_PACKET_LINE_WIDTH = 99,
+ VC4_PACKET_RHT_X_BOUNDARY = 100,
+ VC4_PACKET_DEPTH_OFFSET = 101,
+ VC4_PACKET_CLIP_WINDOW = 102,
+ VC4_PACKET_VIEWPORT_OFFSET = 103,
+ VC4_PACKET_Z_CLIPPING = 104,
+ VC4_PACKET_CLIPPER_XY_SCALING = 105,
+ VC4_PACKET_CLIPPER_Z_SCALING = 106,
+
+ VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112,
+ VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113,
+ VC4_PACKET_CLEAR_COLORS = 114,
+ VC4_PACKET_TILE_COORDINATES = 115,
+
+ /* Not an actual hardware packet -- this is what we use to put
+ * references to GEM bos in the command stream, since we need the u32
+ * int the actual address packet in order to store the offset from the
+ * start of the BO.
+ */
+ VC4_PACKET_GEM_HANDLES = 254,
+} __attribute__ ((__packed__));
+
+#define VC4_PACKET_HALT_SIZE 1
+#define VC4_PACKET_NOP_SIZE 1
+#define VC4_PACKET_FLUSH_SIZE 1
+#define VC4_PACKET_FLUSH_ALL_SIZE 1
+#define VC4_PACKET_START_TILE_BINNING_SIZE 1
+#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE 1
+#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE 1
+#define VC4_PACKET_BRANCH_SIZE 5
+#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE 5
+#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE 1
+#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE 1
+#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE 5
+#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE 5
+#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE 7
+#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE 7
+#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE 14
+#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE 10
+#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE 1
+#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE 1
+#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE 2
+#define VC4_PACKET_GL_SHADER_STATE_SIZE 5
+#define VC4_PACKET_NV_SHADER_STATE_SIZE 5
+#define VC4_PACKET_VG_SHADER_STATE_SIZE 5
+#define VC4_PACKET_CONFIGURATION_BITS_SIZE 4
+#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE 5
+#define VC4_PACKET_POINT_SIZE_SIZE 5
+#define VC4_PACKET_LINE_WIDTH_SIZE 5
+#define VC4_PACKET_RHT_X_BOUNDARY_SIZE 3
+#define VC4_PACKET_DEPTH_OFFSET_SIZE 5
+#define VC4_PACKET_CLIP_WINDOW_SIZE 9
+#define VC4_PACKET_VIEWPORT_OFFSET_SIZE 5
+#define VC4_PACKET_Z_CLIPPING_SIZE 9
+#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE 9
+#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE 9
+#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE 16
+#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE 11
+#define VC4_PACKET_CLEAR_COLORS_SIZE 14
+#define VC4_PACKET_TILE_COORDINATES_SIZE 3
+#define VC4_PACKET_GEM_HANDLES_SIZE 9
+
+/* Number of multisamples supported. */
+#define VC4_MAX_SAMPLES 4
+/* Size of a full resolution color or Z tile buffer load/store. */
+#define VC4_TILE_BUFFER_SIZE (64 * 64 * 4)
+
+/** @{
+ * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_TILE_RENDERING_MODE_CONFIG.
+*/
+#define VC4_TILING_FORMAT_LINEAR 0
+#define VC4_TILING_FORMAT_T 1
+#define VC4_TILING_FORMAT_LT 2
+/** @} */
+
+/** @{
+ *
+ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
+ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
+ */
+#define VC4_LOADSTORE_FULL_RES_EOF BIT(3)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0)
+
+/** @{
+ *
+ * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and
+ * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER.
+ */
+#define VC4_LOADSTORE_FULL_RES_EOF BIT(3)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL BIT(2)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS BIT(1)
+#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR BIT(0)
+
+/** @{
+ *
+ * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address)
+ */
+
+#define VC4_LOADSTORE_TILE_BUFFER_EOF BIT(3)
+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK BIT(2)
+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS BIT(1)
+#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR BIT(0)
+
+/** @} */
+
+/** @{
+ *
+ * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
+ */
+#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR BIT(15)
+#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR BIT(14)
+#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR BIT(13)
+#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP BIT(12)
+
+#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8)
+#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8
+#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888 0
+#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER 1
+#define VC4_LOADSTORE_TILE_BUFFER_BGR565 2
+/** @} */
+
+/** @{
+ *
+ * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and
+ * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL
+ */
+#define VC4_STORE_TILE_BUFFER_MODE_MASK VC4_MASK(7, 6)
+#define VC4_STORE_TILE_BUFFER_MODE_SHIFT 6
+#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0 (0 << 6)
+#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4 (1 << 6)
+#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16 (2 << 6)
+
+/** The values of the field are VC4_TILING_FORMAT_* */
+#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK VC4_MASK(5, 4)
+#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT 4
+
+#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK VC4_MASK(2, 0)
+#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT 0
+#define VC4_LOADSTORE_TILE_BUFFER_NONE 0
+#define VC4_LOADSTORE_TILE_BUFFER_COLOR 1
+#define VC4_LOADSTORE_TILE_BUFFER_ZS 2
+#define VC4_LOADSTORE_TILE_BUFFER_Z 3
+#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK 4
+#define VC4_LOADSTORE_TILE_BUFFER_FULL 5
+/** @} */
+
+#define VC4_INDEX_BUFFER_U8 (0 << 4)
+#define VC4_INDEX_BUFFER_U16 (1 << 4)
+
+/* This flag is only present in NV shader state. */
+#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS BIT(3)
+#define VC4_SHADER_FLAG_ENABLE_CLIPPING BIT(2)
+#define VC4_SHADER_FLAG_VS_POINT_SIZE BIT(1)
+#define VC4_SHADER_FLAG_FS_SINGLE_THREAD BIT(0)
+
+/** @{ byte 2 of config bits. */
+#define VC4_CONFIG_BITS_EARLY_Z_UPDATE BIT(1)
+#define VC4_CONFIG_BITS_EARLY_Z BIT(0)
+/** @} */
+
+/** @{ byte 1 of config bits. */
+#define VC4_CONFIG_BITS_Z_UPDATE BIT(7)
+/** same values in this 3-bit field as PIPE_FUNC_* */
+#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4
+#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE BIT(3)
+
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1)
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1)
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1)
+#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1)
+
+#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT BIT(0)
+/** @} */
+
+/** @{ byte 0 of config bits. */
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6)
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6)
+#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6)
+
+#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES BIT(4)
+#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET BIT(3)
+#define VC4_CONFIG_BITS_CW_PRIMITIVES BIT(2)
+#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK BIT(1)
+#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT BIT(0)
+/** @} */
+
+/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */
+#define VC4_BIN_CONFIG_DB_NON_MS BIT(7)
+
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5)
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 0
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64 1
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128 2
+#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256 3
+
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK VC4_MASK(4, 3)
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32 0
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64 1
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2
+#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3
+
+#define VC4_BIN_CONFIG_AUTO_INIT_TSDA BIT(2)
+#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT BIT(1)
+#define VC4_BIN_CONFIG_MS_MODE_4X BIT(0)
+/** @} */
+
+/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */
+#define VC4_RENDER_CONFIG_DB_NON_MS BIT(12)
+#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE BIT(11)
+#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G BIT(10)
+#define VC4_RENDER_CONFIG_COVERAGE_MODE BIT(9)
+#define VC4_RENDER_CONFIG_ENABLE_VG_MASK BIT(8)
+
+/** The values of the field are VC4_TILING_FORMAT_* */
+#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6)
+#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT 6
+
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X (0 << 4)
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X (1 << 4)
+#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X (2 << 4)
+
+#define VC4_RENDER_CONFIG_FORMAT_MASK VC4_MASK(3, 2)
+#define VC4_RENDER_CONFIG_FORMAT_SHIFT 2
+#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED 0
+#define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1
+#define VC4_RENDER_CONFIG_FORMAT_BGR565 2
+
+#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT BIT(1)
+#define VC4_RENDER_CONFIG_MS_MODE_4X BIT(0)
+
+#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4)
+#define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS (0 << 0)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES (1 << 0)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES (2 << 0)
+#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0)
+
+enum vc4_texture_data_type {
+ VC4_TEXTURE_TYPE_RGBA8888 = 0,
+ VC4_TEXTURE_TYPE_RGBX8888 = 1,
+ VC4_TEXTURE_TYPE_RGBA4444 = 2,
+ VC4_TEXTURE_TYPE_RGBA5551 = 3,
+ VC4_TEXTURE_TYPE_RGB565 = 4,
+ VC4_TEXTURE_TYPE_LUMINANCE = 5,
+ VC4_TEXTURE_TYPE_ALPHA = 6,
+ VC4_TEXTURE_TYPE_LUMALPHA = 7,
+ VC4_TEXTURE_TYPE_ETC1 = 8,
+ VC4_TEXTURE_TYPE_S16F = 9,
+ VC4_TEXTURE_TYPE_S8 = 10,
+ VC4_TEXTURE_TYPE_S16 = 11,
+ VC4_TEXTURE_TYPE_BW1 = 12,
+ VC4_TEXTURE_TYPE_A4 = 13,
+ VC4_TEXTURE_TYPE_A1 = 14,
+ VC4_TEXTURE_TYPE_RGBA64 = 15,
+ VC4_TEXTURE_TYPE_RGBA32R = 16,
+ VC4_TEXTURE_TYPE_YUV422R = 17,
+};
+
+#define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12)
+#define VC4_TEX_P0_OFFSET_SHIFT 12
+#define VC4_TEX_P0_CSWIZ_MASK VC4_MASK(11, 10)
+#define VC4_TEX_P0_CSWIZ_SHIFT 10
+#define VC4_TEX_P0_CMMODE_MASK VC4_MASK(9, 9)
+#define VC4_TEX_P0_CMMODE_SHIFT 9
+#define VC4_TEX_P0_FLIPY_MASK VC4_MASK(8, 8)
+#define VC4_TEX_P0_FLIPY_SHIFT 8
+#define VC4_TEX_P0_TYPE_MASK VC4_MASK(7, 4)
+#define VC4_TEX_P0_TYPE_SHIFT 4
+#define VC4_TEX_P0_MIPLVLS_MASK VC4_MASK(3, 0)
+#define VC4_TEX_P0_MIPLVLS_SHIFT 0
+
+#define VC4_TEX_P1_TYPE4_MASK VC4_MASK(31, 31)
+#define VC4_TEX_P1_TYPE4_SHIFT 31
+#define VC4_TEX_P1_HEIGHT_MASK VC4_MASK(30, 20)
+#define VC4_TEX_P1_HEIGHT_SHIFT 20
+#define VC4_TEX_P1_ETCFLIP_MASK VC4_MASK(19, 19)
+#define VC4_TEX_P1_ETCFLIP_SHIFT 19
+#define VC4_TEX_P1_WIDTH_MASK VC4_MASK(18, 8)
+#define VC4_TEX_P1_WIDTH_SHIFT 8
+
+#define VC4_TEX_P1_MAGFILT_MASK VC4_MASK(7, 7)
+#define VC4_TEX_P1_MAGFILT_SHIFT 7
+# define VC4_TEX_P1_MAGFILT_LINEAR 0
+# define VC4_TEX_P1_MAGFILT_NEAREST 1
+
+#define VC4_TEX_P1_MINFILT_MASK VC4_MASK(6, 4)
+#define VC4_TEX_P1_MINFILT_SHIFT 4
+# define VC4_TEX_P1_MINFILT_LINEAR 0
+# define VC4_TEX_P1_MINFILT_NEAREST 1
+# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR 2
+# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN 3
+# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR 4
+# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN 5
+
+#define VC4_TEX_P1_WRAP_T_MASK VC4_MASK(3, 2)
+#define VC4_TEX_P1_WRAP_T_SHIFT 2
+#define VC4_TEX_P1_WRAP_S_MASK VC4_MASK(1, 0)
+#define VC4_TEX_P1_WRAP_S_SHIFT 0
+# define VC4_TEX_P1_WRAP_REPEAT 0
+# define VC4_TEX_P1_WRAP_CLAMP 1
+# define VC4_TEX_P1_WRAP_MIRROR 2
+# define VC4_TEX_P1_WRAP_BORDER 3
+
+#define VC4_TEX_P2_PTYPE_MASK VC4_MASK(31, 30)
+#define VC4_TEX_P2_PTYPE_SHIFT 30
+# define VC4_TEX_P2_PTYPE_IGNORED 0
+# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE 1
+# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS 2
+# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS 3
+
+/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */
+#define VC4_TEX_P2_CMST_MASK VC4_MASK(29, 12)
+#define VC4_TEX_P2_CMST_SHIFT 12
+#define VC4_TEX_P2_BSLOD_MASK VC4_MASK(0, 0)
+#define VC4_TEX_P2_BSLOD_SHIFT 0
+
+/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */
+#define VC4_TEX_P2_CHEIGHT_MASK VC4_MASK(22, 12)
+#define VC4_TEX_P2_CHEIGHT_SHIFT 12
+#define VC4_TEX_P2_CWIDTH_MASK VC4_MASK(10, 0)
+#define VC4_TEX_P2_CWIDTH_SHIFT 0
+
+/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */
+#define VC4_TEX_P2_CYOFF_MASK VC4_MASK(22, 12)
+#define VC4_TEX_P2_CYOFF_SHIFT 12
+#define VC4_TEX_P2_CXOFF_MASK VC4_MASK(10, 0)
+#define VC4_TEX_P2_CXOFF_SHIFT 0
+
+#endif /* VC4_PACKET_H */
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 887f3caad0be..0addbad15832 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -29,6 +29,14 @@ struct vc4_plane_state {
u32 *dlist;
u32 dlist_size; /* Number of dwords in allocated for the display list */
u32 dlist_count; /* Number of used dwords in the display list. */
+
+ /* Offset in the dlist to pointer word 0. */
+ u32 pw0_offset;
+
+ /* Offset where the plane's dlist was last stored in the
+ hardware at vc4_crtc_atomic_flush() time.
+ */
+ u32 *hw_dlist;
};
static inline struct vc4_plane_state *
@@ -207,6 +215,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
/* Position Word 3: Context. Written by the HVS. */
vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+ vc4_state->pw0_offset = vc4_state->dlist_count;
+
/* Pointer Word 0: RGB / Y Pointer */
vc4_dlist_write(vc4_state, bo->paddr + offset);
@@ -258,6 +268,8 @@ u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist)
struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
int i;
+ vc4_state->hw_dlist = dlist;
+
/* Can't memcpy_toio() because it needs to be 32-bit writes. */
for (i = 0; i < vc4_state->dlist_count; i++)
writel(vc4_state->dlist[i], &dlist[i]);
@@ -272,6 +284,34 @@ u32 vc4_plane_dlist_size(struct drm_plane_state *state)
return vc4_state->dlist_count;
}
+/* Updates the plane to immediately (well, once the FIFO needs
+ * refilling) scan out from at a new framebuffer.
+ */
+void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
+{
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ uint32_t addr;
+
+ /* We're skipping the address adjustment for negative origin,
+ * because this is only called on the primary plane.
+ */
+ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
+ addr = bo->paddr + fb->offsets[0];
+
+ /* Write the new address into the hardware immediately. The
+ * scanout will start from this address as soon as the FIFO
+ * needs to refill with pixels.
+ */
+ writel(addr, &vc4_state->hw_dlist[vc4_state->pw0_offset]);
+
+ /* Also update the CPU-side dlist copy, so that any later
+ * atomic updates that don't do a new modeset on our plane
+ * also use our updated address.
+ */
+ vc4_state->dlist[vc4_state->pw0_offset] = addr;
+}
+
static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
.prepare_fb = NULL,
.cleanup_fb = NULL,
@@ -317,7 +357,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
ret = drm_universal_plane_init(dev, plane, 0xff,
&vc4_plane_funcs,
formats, ARRAY_SIZE(formats),
- type);
+ type, NULL);
drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
diff --git a/drivers/gpu/drm/vc4/vc4_qpu_defines.h b/drivers/gpu/drm/vc4/vc4_qpu_defines.h
new file mode 100644
index 000000000000..d5c2f3c85ebb
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_qpu_defines.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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.
+ */
+
+#ifndef VC4_QPU_DEFINES_H
+#define VC4_QPU_DEFINES_H
+
+enum qpu_op_add {
+ QPU_A_NOP,
+ QPU_A_FADD,
+ QPU_A_FSUB,
+ QPU_A_FMIN,
+ QPU_A_FMAX,
+ QPU_A_FMINABS,
+ QPU_A_FMAXABS,
+ QPU_A_FTOI,
+ QPU_A_ITOF,
+ QPU_A_ADD = 12,
+ QPU_A_SUB,
+ QPU_A_SHR,
+ QPU_A_ASR,
+ QPU_A_ROR,
+ QPU_A_SHL,
+ QPU_A_MIN,
+ QPU_A_MAX,
+ QPU_A_AND,
+ QPU_A_OR,
+ QPU_A_XOR,
+ QPU_A_NOT,
+ QPU_A_CLZ,
+ QPU_A_V8ADDS = 30,
+ QPU_A_V8SUBS = 31,
+};
+
+enum qpu_op_mul {
+ QPU_M_NOP,
+ QPU_M_FMUL,
+ QPU_M_MUL24,
+ QPU_M_V8MULD,
+ QPU_M_V8MIN,
+ QPU_M_V8MAX,
+ QPU_M_V8ADDS,
+ QPU_M_V8SUBS,
+};
+
+enum qpu_raddr {
+ QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */
+ /* 0-31 are the plain regfile a or b fields */
+ QPU_R_UNIF = 32,
+ QPU_R_VARY = 35,
+ QPU_R_ELEM_QPU = 38,
+ QPU_R_NOP,
+ QPU_R_XY_PIXEL_COORD = 41,
+ QPU_R_MS_REV_FLAGS = 41,
+ QPU_R_VPM = 48,
+ QPU_R_VPM_LD_BUSY,
+ QPU_R_VPM_LD_WAIT,
+ QPU_R_MUTEX_ACQUIRE,
+};
+
+enum qpu_waddr {
+ /* 0-31 are the plain regfile a or b fields */
+ QPU_W_ACC0 = 32, /* aka r0 */
+ QPU_W_ACC1,
+ QPU_W_ACC2,
+ QPU_W_ACC3,
+ QPU_W_TMU_NOSWAP,
+ QPU_W_ACC5,
+ QPU_W_HOST_INT,
+ QPU_W_NOP,
+ QPU_W_UNIFORMS_ADDRESS,
+ QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */
+ QPU_W_MS_FLAGS = 42,
+ QPU_W_REV_FLAG = 42,
+ QPU_W_TLB_STENCIL_SETUP = 43,
+ QPU_W_TLB_Z,
+ QPU_W_TLB_COLOR_MS,
+ QPU_W_TLB_COLOR_ALL,
+ QPU_W_TLB_ALPHA_MASK,
+ QPU_W_VPM,
+ QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */
+ QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */
+ QPU_W_MUTEX_RELEASE,
+ QPU_W_SFU_RECIP,
+ QPU_W_SFU_RECIPSQRT,
+ QPU_W_SFU_EXP,
+ QPU_W_SFU_LOG,
+ QPU_W_TMU0_S,
+ QPU_W_TMU0_T,
+ QPU_W_TMU0_R,
+ QPU_W_TMU0_B,
+ QPU_W_TMU1_S,
+ QPU_W_TMU1_T,
+ QPU_W_TMU1_R,
+ QPU_W_TMU1_B,
+};
+
+enum qpu_sig_bits {
+ QPU_SIG_SW_BREAKPOINT,
+ QPU_SIG_NONE,
+ QPU_SIG_THREAD_SWITCH,
+ QPU_SIG_PROG_END,
+ QPU_SIG_WAIT_FOR_SCOREBOARD,
+ QPU_SIG_SCOREBOARD_UNLOCK,
+ QPU_SIG_LAST_THREAD_SWITCH,
+ QPU_SIG_COVERAGE_LOAD,
+ QPU_SIG_COLOR_LOAD,
+ QPU_SIG_COLOR_LOAD_END,
+ QPU_SIG_LOAD_TMU0,
+ QPU_SIG_LOAD_TMU1,
+ QPU_SIG_ALPHA_MASK_LOAD,
+ QPU_SIG_SMALL_IMM,
+ QPU_SIG_LOAD_IMM,
+ QPU_SIG_BRANCH
+};
+
+enum qpu_mux {
+ /* hardware mux values */
+ QPU_MUX_R0,
+ QPU_MUX_R1,
+ QPU_MUX_R2,
+ QPU_MUX_R3,
+ QPU_MUX_R4,
+ QPU_MUX_R5,
+ QPU_MUX_A,
+ QPU_MUX_B,
+
+ /* non-hardware mux values */
+ QPU_MUX_IMM,
+};
+
+enum qpu_cond {
+ QPU_COND_NEVER,
+ QPU_COND_ALWAYS,
+ QPU_COND_ZS,
+ QPU_COND_ZC,
+ QPU_COND_NS,
+ QPU_COND_NC,
+ QPU_COND_CS,
+ QPU_COND_CC,
+};
+
+enum qpu_pack_mul {
+ QPU_PACK_MUL_NOP,
+ /* replicated to each 8 bits of the 32-bit dst. */
+ QPU_PACK_MUL_8888 = 3,
+ QPU_PACK_MUL_8A,
+ QPU_PACK_MUL_8B,
+ QPU_PACK_MUL_8C,
+ QPU_PACK_MUL_8D,
+};
+
+enum qpu_pack_a {
+ QPU_PACK_A_NOP,
+ /* convert to 16 bit float if float input, or to int16. */
+ QPU_PACK_A_16A,
+ QPU_PACK_A_16B,
+ /* replicated to each 8 bits of the 32-bit dst. */
+ QPU_PACK_A_8888,
+ /* Convert to 8-bit unsigned int. */
+ QPU_PACK_A_8A,
+ QPU_PACK_A_8B,
+ QPU_PACK_A_8C,
+ QPU_PACK_A_8D,
+
+ /* Saturating variants of the previous instructions. */
+ QPU_PACK_A_32_SAT, /* int-only */
+ QPU_PACK_A_16A_SAT, /* int or float */
+ QPU_PACK_A_16B_SAT,
+ QPU_PACK_A_8888_SAT,
+ QPU_PACK_A_8A_SAT,
+ QPU_PACK_A_8B_SAT,
+ QPU_PACK_A_8C_SAT,
+ QPU_PACK_A_8D_SAT,
+};
+
+enum qpu_unpack_r4 {
+ QPU_UNPACK_R4_NOP,
+ QPU_UNPACK_R4_F16A_TO_F32,
+ QPU_UNPACK_R4_F16B_TO_F32,
+ QPU_UNPACK_R4_8D_REP,
+ QPU_UNPACK_R4_8A,
+ QPU_UNPACK_R4_8B,
+ QPU_UNPACK_R4_8C,
+ QPU_UNPACK_R4_8D,
+};
+
+#define QPU_MASK(high, low) \
+ ((((uint64_t)1 << ((high) - (low) + 1)) - 1) << (low))
+
+#define QPU_GET_FIELD(word, field) \
+ ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
+
+#define QPU_SIG_SHIFT 60
+#define QPU_SIG_MASK QPU_MASK(63, 60)
+
+#define QPU_UNPACK_SHIFT 57
+#define QPU_UNPACK_MASK QPU_MASK(59, 57)
+
+/**
+ * If set, the pack field means PACK_MUL or R4 packing, instead of normal
+ * regfile a packing.
+ */
+#define QPU_PM ((uint64_t)1 << 56)
+
+#define QPU_PACK_SHIFT 52
+#define QPU_PACK_MASK QPU_MASK(55, 52)
+
+#define QPU_COND_ADD_SHIFT 49
+#define QPU_COND_ADD_MASK QPU_MASK(51, 49)
+#define QPU_COND_MUL_SHIFT 46
+#define QPU_COND_MUL_MASK QPU_MASK(48, 46)
+
+#define QPU_SF ((uint64_t)1 << 45)
+
+#define QPU_WADDR_ADD_SHIFT 38
+#define QPU_WADDR_ADD_MASK QPU_MASK(43, 38)
+#define QPU_WADDR_MUL_SHIFT 32
+#define QPU_WADDR_MUL_MASK QPU_MASK(37, 32)
+
+#define QPU_OP_MUL_SHIFT 29
+#define QPU_OP_MUL_MASK QPU_MASK(31, 29)
+
+#define QPU_RADDR_A_SHIFT 18
+#define QPU_RADDR_A_MASK QPU_MASK(23, 18)
+#define QPU_RADDR_B_SHIFT 12
+#define QPU_RADDR_B_MASK QPU_MASK(17, 12)
+#define QPU_SMALL_IMM_SHIFT 12
+#define QPU_SMALL_IMM_MASK QPU_MASK(17, 12)
+
+#define QPU_ADD_A_SHIFT 9
+#define QPU_ADD_A_MASK QPU_MASK(11, 9)
+#define QPU_ADD_B_SHIFT 6
+#define QPU_ADD_B_MASK QPU_MASK(8, 6)
+#define QPU_MUL_A_SHIFT 3
+#define QPU_MUL_A_MASK QPU_MASK(5, 3)
+#define QPU_MUL_B_SHIFT 0
+#define QPU_MUL_B_MASK QPU_MASK(2, 0)
+
+#define QPU_WS ((uint64_t)1 << 44)
+
+#define QPU_OP_ADD_SHIFT 24
+#define QPU_OP_ADD_MASK QPU_MASK(28, 24)
+
+#endif /* VC4_QPU_DEFINES_H */
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 9e4e904c668e..4e52a0a88551 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -154,7 +154,7 @@
#define V3D_PCTRS14 0x006f4
#define V3D_PCTR15 0x006f8
#define V3D_PCTRS15 0x006fc
-#define V3D_BGE 0x00f00
+#define V3D_DBGE 0x00f00
#define V3D_FDBGO 0x00f04
#define V3D_FDBGB 0x00f08
#define V3D_FDBGR 0x00f0c
diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c
new file mode 100644
index 000000000000..8a2a312e2c1b
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright © 2014-2015 Broadcom
+ *
+ * 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.
+ */
+
+/**
+ * DOC: Render command list generation
+ *
+ * In the VC4 driver, render command list generation is performed by the
+ * kernel instead of userspace. We do this because validating a
+ * user-submitted command list is hard to get right and has high CPU overhead,
+ * while the number of valid configurations for render command lists is
+ * actually fairly low.
+ */
+
+#include "uapi/drm/vc4_drm.h"
+#include "vc4_drv.h"
+#include "vc4_packet.h"
+
+struct vc4_rcl_setup {
+ struct drm_gem_cma_object *color_read;
+ struct drm_gem_cma_object *color_write;
+ struct drm_gem_cma_object *zs_read;
+ struct drm_gem_cma_object *zs_write;
+ struct drm_gem_cma_object *msaa_color_write;
+ struct drm_gem_cma_object *msaa_zs_write;
+
+ struct drm_gem_cma_object *rcl;
+ u32 next_offset;
+};
+
+static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
+{
+ *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val;
+ setup->next_offset += 1;
+}
+
+static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val)
+{
+ *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val;
+ setup->next_offset += 2;
+}
+
+static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val)
+{
+ *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val;
+ setup->next_offset += 4;
+}
+
+/*
+ * Emits a no-op STORE_TILE_BUFFER_GENERAL.
+ *
+ * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of
+ * some sort before another load is triggered.
+ */
+static void vc4_store_before_load(struct vc4_rcl_setup *setup)
+{
+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
+ rcl_u16(setup,
+ VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE,
+ VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
+ VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR |
+ VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR |
+ VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR);
+ rcl_u32(setup, 0); /* no address, since we're in None mode */
+}
+
+/*
+ * Calculates the physical address of the start of a tile in a RCL surface.
+ *
+ * Unlike the other load/store packets,
+ * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile
+ * coordinates packet, and instead just store to the address given.
+ */
+static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec,
+ struct drm_gem_cma_object *bo,
+ struct drm_vc4_submit_rcl_surface *surf,
+ uint8_t x, uint8_t y)
+{
+ return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE *
+ (DIV_ROUND_UP(exec->args->width, 32) * y + x);
+}
+
+/*
+ * Emits a PACKET_TILE_COORDINATES if one isn't already pending.
+ *
+ * The tile coordinates packet triggers a pending load if there is one, are
+ * used for clipping during rendering, and determine where loads/stores happen
+ * relative to their base address.
+ */
+static void vc4_tile_coordinates(struct vc4_rcl_setup *setup,
+ uint32_t x, uint32_t y)
+{
+ rcl_u8(setup, VC4_PACKET_TILE_COORDINATES);
+ rcl_u8(setup, x);
+ rcl_u8(setup, y);
+}
+
+static void emit_tile(struct vc4_exec_info *exec,
+ struct vc4_rcl_setup *setup,
+ uint8_t x, uint8_t y, bool first, bool last)
+{
+ struct drm_vc4_submit_cl *args = exec->args;
+ bool has_bin = args->bin_cl_size != 0;
+
+ /* Note that the load doesn't actually occur until the
+ * tile coords packet is processed, and only one load
+ * may be outstanding at a time.
+ */
+ if (setup->color_read) {
+ if (args->color_read.flags &
+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
+ rcl_u32(setup,
+ vc4_full_res_offset(exec, setup->color_read,
+ &args->color_read, x, y) |
+ VC4_LOADSTORE_FULL_RES_DISABLE_ZS);
+ } else {
+ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
+ rcl_u16(setup, args->color_read.bits);
+ rcl_u32(setup, setup->color_read->paddr +
+ args->color_read.offset);
+ }
+ }
+
+ if (setup->zs_read) {
+ if (args->zs_read.flags &
+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+ rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
+ rcl_u32(setup,
+ vc4_full_res_offset(exec, setup->zs_read,
+ &args->zs_read, x, y) |
+ VC4_LOADSTORE_FULL_RES_DISABLE_COLOR);
+ } else {
+ if (setup->color_read) {
+ /* Exec previous load. */
+ vc4_tile_coordinates(setup, x, y);
+ vc4_store_before_load(setup);
+ }
+
+ rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
+ rcl_u16(setup, args->zs_read.bits);
+ rcl_u32(setup, setup->zs_read->paddr +
+ args->zs_read.offset);
+ }
+ }
+
+ /* Clipping depends on tile coordinates having been
+ * emitted, so we always need one here.
+ */
+ vc4_tile_coordinates(setup, x, y);
+
+ /* Wait for the binner before jumping to the first
+ * tile's lists.
+ */
+ if (first && has_bin)
+ rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE);
+
+ if (has_bin) {
+ rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST);
+ rcl_u32(setup, (exec->tile_bo->paddr +
+ exec->tile_alloc_offset +
+ (y * exec->bin_tiles_x + x) * 32));
+ }
+
+ if (setup->msaa_color_write) {
+ bool last_tile_write = (!setup->msaa_zs_write &&
+ !setup->zs_write &&
+ !setup->color_write);
+ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS;
+
+ if (!last_tile_write)
+ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
+ else if (last)
+ bits |= VC4_LOADSTORE_FULL_RES_EOF;
+ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
+ rcl_u32(setup,
+ vc4_full_res_offset(exec, setup->msaa_color_write,
+ &args->msaa_color_write, x, y) |
+ bits);
+ }
+
+ if (setup->msaa_zs_write) {
+ bool last_tile_write = (!setup->zs_write &&
+ !setup->color_write);
+ uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR;
+
+ if (setup->msaa_color_write)
+ vc4_tile_coordinates(setup, x, y);
+ if (!last_tile_write)
+ bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
+ else if (last)
+ bits |= VC4_LOADSTORE_FULL_RES_EOF;
+ rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
+ rcl_u32(setup,
+ vc4_full_res_offset(exec, setup->msaa_zs_write,
+ &args->msaa_zs_write, x, y) |
+ bits);
+ }
+
+ if (setup->zs_write) {
+ bool last_tile_write = !setup->color_write;
+
+ if (setup->msaa_color_write || setup->msaa_zs_write)
+ vc4_tile_coordinates(setup, x, y);
+
+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
+ rcl_u16(setup, args->zs_write.bits |
+ (last_tile_write ?
+ 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR));
+ rcl_u32(setup,
+ (setup->zs_write->paddr + args->zs_write.offset) |
+ ((last && last_tile_write) ?
+ VC4_LOADSTORE_TILE_BUFFER_EOF : 0));
+ }
+
+ if (setup->color_write) {
+ if (setup->msaa_color_write || setup->msaa_zs_write ||
+ setup->zs_write) {
+ vc4_tile_coordinates(setup, x, y);
+ }
+
+ if (last)
+ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF);
+ else
+ rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER);
+ }
+}
+
+static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
+ struct vc4_rcl_setup *setup)
+{
+ struct drm_vc4_submit_cl *args = exec->args;
+ bool has_bin = args->bin_cl_size != 0;
+ uint8_t min_x_tile = args->min_x_tile;
+ uint8_t min_y_tile = args->min_y_tile;
+ uint8_t max_x_tile = args->max_x_tile;
+ uint8_t max_y_tile = args->max_y_tile;
+ uint8_t xtiles = max_x_tile - min_x_tile + 1;
+ uint8_t ytiles = max_y_tile - min_y_tile + 1;
+ uint8_t x, y;
+ uint32_t size, loop_body_size;
+
+ size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE;
+ loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE;
+
+ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
+ size += VC4_PACKET_CLEAR_COLORS_SIZE +
+ VC4_PACKET_TILE_COORDINATES_SIZE +
+ VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
+ }
+
+ if (setup->color_read) {
+ if (args->color_read.flags &
+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
+ } else {
+ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
+ }
+ }
+ if (setup->zs_read) {
+ if (args->zs_read.flags &
+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+ loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
+ } else {
+ if (setup->color_read &&
+ !(args->color_read.flags &
+ VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) {
+ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
+ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
+ }
+ loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
+ }
+ }
+
+ if (has_bin) {
+ size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE;
+ loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE;
+ }
+
+ if (setup->msaa_color_write)
+ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
+ if (setup->msaa_zs_write)
+ loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
+
+ if (setup->zs_write)
+ loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
+ if (setup->color_write)
+ loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE;
+
+ /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */
+ loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE *
+ ((setup->msaa_color_write != NULL) +
+ (setup->msaa_zs_write != NULL) +
+ (setup->color_write != NULL) +
+ (setup->zs_write != NULL) - 1);
+
+ size += xtiles * ytiles * loop_body_size;
+
+ setup->rcl = &vc4_bo_create(dev, size, true)->base;
+ if (!setup->rcl)
+ return -ENOMEM;
+ list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
+ &exec->unref_list);
+
+ rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
+ rcl_u32(setup,
+ (setup->color_write ? (setup->color_write->paddr +
+ args->color_write.offset) :
+ 0));
+ rcl_u16(setup, args->width);
+ rcl_u16(setup, args->height);
+ rcl_u16(setup, args->color_write.bits);
+
+ /* The tile buffer gets cleared when the previous tile is stored. If
+ * the clear values changed between frames, then the tile buffer has
+ * stale clear values in it, so we have to do a store in None mode (no
+ * writes) so that we trigger the tile buffer clear.
+ */
+ if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
+ rcl_u8(setup, VC4_PACKET_CLEAR_COLORS);
+ rcl_u32(setup, args->clear_color[0]);
+ rcl_u32(setup, args->clear_color[1]);
+ rcl_u32(setup, args->clear_z);
+ rcl_u8(setup, args->clear_s);
+
+ vc4_tile_coordinates(setup, 0, 0);
+
+ rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
+ rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE);
+ rcl_u32(setup, 0); /* no address, since we're in None mode */
+ }
+
+ for (y = min_y_tile; y <= max_y_tile; y++) {
+ for (x = min_x_tile; x <= max_x_tile; x++) {
+ bool first = (x == min_x_tile && y == min_y_tile);
+ bool last = (x == max_x_tile && y == max_y_tile);
+
+ emit_tile(exec, setup, x, y, first, last);
+ }
+ }
+
+ BUG_ON(setup->next_offset != size);
+ exec->ct1ca = setup->rcl->paddr;
+ exec->ct1ea = setup->rcl->paddr + setup->next_offset;
+
+ return 0;
+}
+
+static int vc4_full_res_bounds_check(struct vc4_exec_info *exec,
+ struct drm_gem_cma_object *obj,
+ struct drm_vc4_submit_rcl_surface *surf)
+{
+ struct drm_vc4_submit_cl *args = exec->args;
+ u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32);
+
+ if (surf->offset > obj->base.size) {
+ DRM_ERROR("surface offset %d > BO size %zd\n",
+ surf->offset, obj->base.size);
+ return -EINVAL;
+ }
+
+ if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE <
+ render_tiles_stride * args->max_y_tile + args->max_x_tile) {
+ DRM_ERROR("MSAA tile %d, %d out of bounds "
+ "(bo size %zd, offset %d).\n",
+ args->max_x_tile, args->max_y_tile,
+ obj->base.size,
+ surf->offset);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
+ struct drm_gem_cma_object **obj,
+ struct drm_vc4_submit_rcl_surface *surf)
+{
+ if (surf->flags != 0 || surf->bits != 0) {
+ DRM_ERROR("MSAA surface had nonzero flags/bits\n");
+ return -EINVAL;
+ }
+
+ if (surf->hindex == ~0)
+ return 0;
+
+ *obj = vc4_use_bo(exec, surf->hindex);
+ if (!*obj)
+ return -EINVAL;
+
+ if (surf->offset & 0xf) {
+ DRM_ERROR("MSAA write must be 16b aligned.\n");
+ return -EINVAL;
+ }
+
+ return vc4_full_res_bounds_check(exec, *obj, surf);
+}
+
+static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
+ struct drm_gem_cma_object **obj,
+ struct drm_vc4_submit_rcl_surface *surf)
+{
+ uint8_t tiling = VC4_GET_FIELD(surf->bits,
+ VC4_LOADSTORE_TILE_BUFFER_TILING);
+ uint8_t buffer = VC4_GET_FIELD(surf->bits,
+ VC4_LOADSTORE_TILE_BUFFER_BUFFER);
+ uint8_t format = VC4_GET_FIELD(surf->bits,
+ VC4_LOADSTORE_TILE_BUFFER_FORMAT);
+ int cpp;
+ int ret;
+
+ if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+ DRM_ERROR("Extra flags set\n");
+ return -EINVAL;
+ }
+
+ if (surf->hindex == ~0)
+ return 0;
+
+ *obj = vc4_use_bo(exec, surf->hindex);
+ if (!*obj)
+ return -EINVAL;
+
+ if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
+ if (surf == &exec->args->zs_write) {
+ DRM_ERROR("general zs write may not be a full-res.\n");
+ return -EINVAL;
+ }
+
+ if (surf->bits != 0) {
+ DRM_ERROR("load/store general bits set with "
+ "full res load/store.\n");
+ return -EINVAL;
+ }
+
+ ret = vc4_full_res_bounds_check(exec, *obj, surf);
+ if (!ret)
+ return ret;
+
+ return 0;
+ }
+
+ if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK |
+ VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK |
+ VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) {
+ DRM_ERROR("Unknown bits in load/store: 0x%04x\n",
+ surf->bits);
+ return -EINVAL;
+ }
+
+ if (tiling > VC4_TILING_FORMAT_LT) {
+ DRM_ERROR("Bad tiling format\n");
+ return -EINVAL;
+ }
+
+ if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) {
+ if (format != 0) {
+ DRM_ERROR("No color format should be set for ZS\n");
+ return -EINVAL;
+ }
+ cpp = 4;
+ } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) {
+ switch (format) {
+ case VC4_LOADSTORE_TILE_BUFFER_BGR565:
+ case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER:
+ cpp = 2;
+ break;
+ case VC4_LOADSTORE_TILE_BUFFER_RGBA8888:
+ cpp = 4;
+ break;
+ default:
+ DRM_ERROR("Bad tile buffer format\n");
+ return -EINVAL;
+ }
+ } else {
+ DRM_ERROR("Bad load/store buffer %d.\n", buffer);
+ return -EINVAL;
+ }
+
+ if (surf->offset & 0xf) {
+ DRM_ERROR("load/store buffer must be 16b aligned.\n");
+ return -EINVAL;
+ }
+
+ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
+ exec->args->width, exec->args->height, cpp)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
+ struct vc4_rcl_setup *setup,
+ struct drm_gem_cma_object **obj,
+ struct drm_vc4_submit_rcl_surface *surf)
+{
+ uint8_t tiling = VC4_GET_FIELD(surf->bits,
+ VC4_RENDER_CONFIG_MEMORY_FORMAT);
+ uint8_t format = VC4_GET_FIELD(surf->bits,
+ VC4_RENDER_CONFIG_FORMAT);
+ int cpp;
+
+ if (surf->flags != 0) {
+ DRM_ERROR("No flags supported on render config.\n");
+ return -EINVAL;
+ }
+
+ if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK |
+ VC4_RENDER_CONFIG_FORMAT_MASK |
+ VC4_RENDER_CONFIG_MS_MODE_4X |
+ VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) {
+ DRM_ERROR("Unknown bits in render config: 0x%04x\n",
+ surf->bits);
+ return -EINVAL;
+ }
+
+ if (surf->hindex == ~0)
+ return 0;
+
+ *obj = vc4_use_bo(exec, surf->hindex);
+ if (!*obj)
+ return -EINVAL;
+
+ if (tiling > VC4_TILING_FORMAT_LT) {
+ DRM_ERROR("Bad tiling format\n");
+ return -EINVAL;
+ }
+
+ switch (format) {
+ case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED:
+ case VC4_RENDER_CONFIG_FORMAT_BGR565:
+ cpp = 2;
+ break;
+ case VC4_RENDER_CONFIG_FORMAT_RGBA8888:
+ cpp = 4;
+ break;
+ default:
+ DRM_ERROR("Bad tile buffer format\n");
+ return -EINVAL;
+ }
+
+ if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
+ exec->args->width, exec->args->height, cpp)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
+{
+ struct vc4_rcl_setup setup = {0};
+ struct drm_vc4_submit_cl *args = exec->args;
+ bool has_bin = args->bin_cl_size != 0;
+ int ret;
+
+ if (args->min_x_tile > args->max_x_tile ||
+ args->min_y_tile > args->max_y_tile) {
+ DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n",
+ args->min_x_tile, args->min_y_tile,
+ args->max_x_tile, args->max_y_tile);
+ return -EINVAL;
+ }
+
+ if (has_bin &&
+ (args->max_x_tile > exec->bin_tiles_x ||
+ args->max_y_tile > exec->bin_tiles_y)) {
+ DRM_ERROR("Render tiles (%d,%d) outside of bin config "
+ "(%d,%d)\n",
+ args->max_x_tile, args->max_y_tile,
+ exec->bin_tiles_x, exec->bin_tiles_y);
+ return -EINVAL;
+ }
+
+ ret = vc4_rcl_render_config_surface_setup(exec, &setup,
+ &setup.color_write,
+ &args->color_write);
+ if (ret)
+ return ret;
+
+ ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
+ if (ret)
+ return ret;
+
+ ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
+ if (ret)
+ return ret;
+
+ ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
+ if (ret)
+ return ret;
+
+ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write,
+ &args->msaa_color_write);
+ if (ret)
+ return ret;
+
+ ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write,
+ &args->msaa_zs_write);
+ if (ret)
+ return ret;
+
+ /* We shouldn't even have the job submitted to us if there's no
+ * surface to write out.
+ */
+ if (!setup.color_write && !setup.zs_write &&
+ !setup.msaa_color_write && !setup.msaa_zs_write) {
+ DRM_ERROR("RCL requires color or Z/S write\n");
+ return -EINVAL;
+ }
+
+ return vc4_create_rcl_bo(dev, exec, &setup);
+}
diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h
new file mode 100644
index 000000000000..ad7b1ea720c2
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_trace.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 Broadcom
+ *
+ * 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.
+ */
+
+#if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VC4_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vc4
+#define TRACE_INCLUDE_FILE vc4_trace
+
+TRACE_EVENT(vc4_wait_for_seqno_begin,
+ TP_PROTO(struct drm_device *dev, uint64_t seqno, uint64_t timeout),
+ TP_ARGS(dev, seqno, timeout),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(u64, seqno)
+ __field(u64, timeout)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->seqno = seqno;
+ __entry->timeout = timeout;
+ ),
+
+ TP_printk("dev=%u, seqno=%llu, timeout=%llu",
+ __entry->dev, __entry->seqno, __entry->timeout)
+);
+
+TRACE_EVENT(vc4_wait_for_seqno_end,
+ 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)
+);
+
+#endif /* _VC4_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/arch/arm/mach-orion5x/include/mach/hardware.h b/drivers/gpu/drm/vc4/vc4_trace_points.c
index 395735482473..e6278f25716b 100644
--- a/arch/arm/mach-orion5x/include/mach/hardware.h
+++ b/drivers/gpu/drm/vc4/vc4_trace_points.c
@@ -1,14 +1,14 @@
/*
- * arch/arm/mach-orion5x/include/mach/hardware.h
+ * Copyright (C) 2015 Broadcom
*
* 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 __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include "orion5x.h"
+#include "vc4_drv.h"
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "vc4_trace.h"
#endif
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
new file mode 100644
index 000000000000..424d515ffcda
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "linux/component.h"
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+#ifdef CONFIG_DEBUG_FS
+#define REGDEF(reg) { reg, #reg }
+static const struct {
+ uint32_t reg;
+ const char *name;
+} vc4_reg_defs[] = {
+ REGDEF(V3D_IDENT0),
+ REGDEF(V3D_IDENT1),
+ REGDEF(V3D_IDENT2),
+ REGDEF(V3D_SCRATCH),
+ REGDEF(V3D_L2CACTL),
+ REGDEF(V3D_SLCACTL),
+ REGDEF(V3D_INTCTL),
+ REGDEF(V3D_INTENA),
+ REGDEF(V3D_INTDIS),
+ REGDEF(V3D_CT0CS),
+ REGDEF(V3D_CT1CS),
+ REGDEF(V3D_CT0EA),
+ REGDEF(V3D_CT1EA),
+ REGDEF(V3D_CT0CA),
+ REGDEF(V3D_CT1CA),
+ REGDEF(V3D_CT00RA0),
+ REGDEF(V3D_CT01RA0),
+ REGDEF(V3D_CT0LC),
+ REGDEF(V3D_CT1LC),
+ REGDEF(V3D_CT0PC),
+ REGDEF(V3D_CT1PC),
+ REGDEF(V3D_PCS),
+ REGDEF(V3D_BFC),
+ REGDEF(V3D_RFC),
+ REGDEF(V3D_BPCA),
+ REGDEF(V3D_BPCS),
+ REGDEF(V3D_BPOA),
+ REGDEF(V3D_BPOS),
+ REGDEF(V3D_BXCF),
+ REGDEF(V3D_SQRSV0),
+ REGDEF(V3D_SQRSV1),
+ REGDEF(V3D_SQCNTL),
+ REGDEF(V3D_SRQPC),
+ REGDEF(V3D_SRQUA),
+ REGDEF(V3D_SRQUL),
+ REGDEF(V3D_SRQCS),
+ REGDEF(V3D_VPACNTL),
+ REGDEF(V3D_VPMBASE),
+ REGDEF(V3D_PCTRC),
+ REGDEF(V3D_PCTRE),
+ REGDEF(V3D_PCTR0),
+ REGDEF(V3D_PCTRS0),
+ REGDEF(V3D_PCTR1),
+ REGDEF(V3D_PCTRS1),
+ REGDEF(V3D_PCTR2),
+ REGDEF(V3D_PCTRS2),
+ REGDEF(V3D_PCTR3),
+ REGDEF(V3D_PCTRS3),
+ REGDEF(V3D_PCTR4),
+ REGDEF(V3D_PCTRS4),
+ REGDEF(V3D_PCTR5),
+ REGDEF(V3D_PCTRS5),
+ REGDEF(V3D_PCTR6),
+ REGDEF(V3D_PCTRS6),
+ REGDEF(V3D_PCTR7),
+ REGDEF(V3D_PCTRS7),
+ REGDEF(V3D_PCTR8),
+ REGDEF(V3D_PCTRS8),
+ REGDEF(V3D_PCTR9),
+ REGDEF(V3D_PCTRS9),
+ REGDEF(V3D_PCTR10),
+ REGDEF(V3D_PCTRS10),
+ REGDEF(V3D_PCTR11),
+ REGDEF(V3D_PCTRS11),
+ REGDEF(V3D_PCTR12),
+ REGDEF(V3D_PCTRS12),
+ REGDEF(V3D_PCTR13),
+ REGDEF(V3D_PCTRS13),
+ REGDEF(V3D_PCTR14),
+ REGDEF(V3D_PCTRS14),
+ REGDEF(V3D_PCTR15),
+ REGDEF(V3D_PCTRS15),
+ REGDEF(V3D_DBGE),
+ REGDEF(V3D_FDBGO),
+ REGDEF(V3D_FDBGB),
+ REGDEF(V3D_FDBGR),
+ REGDEF(V3D_FDBGS),
+ REGDEF(V3D_ERRSTAT),
+};
+
+int vc4_v3d_debugfs_regs(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 vc4_dev *vc4 = to_vc4_dev(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vc4_reg_defs); i++) {
+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
+ vc4_reg_defs[i].name, vc4_reg_defs[i].reg,
+ V3D_READ(vc4_reg_defs[i].reg));
+ }
+
+ return 0;
+}
+
+int vc4_v3d_debugfs_ident(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 vc4_dev *vc4 = to_vc4_dev(dev);
+ uint32_t ident1 = V3D_READ(V3D_IDENT1);
+ uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC);
+ uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS);
+ uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS);
+
+ seq_printf(m, "Revision: %d\n",
+ VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
+ seq_printf(m, "Slices: %d\n", nslc);
+ seq_printf(m, "TMUs: %d\n", nslc * tups);
+ seq_printf(m, "QPUs: %d\n", nslc * qups);
+ seq_printf(m, "Semaphores: %d\n",
+ VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
+
+ return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/*
+ * Asks the firmware to turn on power to the V3D engine.
+ *
+ * This may be doable with just the clocks interface, though this
+ * packet does some other register setup from the firmware, too.
+ */
+int
+vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
+{
+ if (on)
+ return pm_generic_poweroff(&vc4->v3d->pdev->dev);
+ else
+ return pm_generic_resume(&vc4->v3d->pdev->dev);
+}
+
+static void vc4_v3d_init_hw(struct drm_device *dev)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+ /* Take all the memory that would have been reserved for user
+ * QPU programs, since we don't have an interface for running
+ * them, anyway.
+ */
+ V3D_WRITE(V3D_VPMBASE, 0);
+}
+
+static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_v3d *v3d = NULL;
+ int ret;
+
+ v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL);
+ if (!v3d)
+ return -ENOMEM;
+
+ v3d->pdev = pdev;
+
+ v3d->regs = vc4_ioremap_regs(pdev, 0);
+ if (IS_ERR(v3d->regs))
+ return PTR_ERR(v3d->regs);
+
+ vc4->v3d = v3d;
+
+ if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
+ DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
+ V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0);
+ return -EINVAL;
+ }
+
+ /* Reset the binner overflow address/size at setup, to be sure
+ * we don't reuse an old one.
+ */
+ V3D_WRITE(V3D_BPOA, 0);
+ V3D_WRITE(V3D_BPOS, 0);
+
+ vc4_v3d_init_hw(drm);
+
+ ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
+ if (ret) {
+ DRM_ERROR("Failed to install IRQ handler\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void vc4_v3d_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+
+ drm_irq_uninstall(drm);
+
+ /* Disable the binner's overflow memory address, so the next
+ * driver probe (if any) doesn't try to reuse our old
+ * allocation.
+ */
+ V3D_WRITE(V3D_BPOA, 0);
+ V3D_WRITE(V3D_BPOS, 0);
+
+ vc4->v3d = NULL;
+}
+
+static const struct component_ops vc4_v3d_ops = {
+ .bind = vc4_v3d_bind,
+ .unbind = vc4_v3d_unbind,
+};
+
+static int vc4_v3d_dev_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &vc4_v3d_ops);
+}
+
+static int vc4_v3d_dev_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &vc4_v3d_ops);
+ return 0;
+}
+
+static const struct of_device_id vc4_v3d_dt_match[] = {
+ { .compatible = "brcm,vc4-v3d" },
+ {}
+};
+
+struct platform_driver vc4_v3d_driver = {
+ .probe = vc4_v3d_dev_probe,
+ .remove = vc4_v3d_dev_remove,
+ .driver = {
+ .name = "vc4_v3d",
+ .of_match_table = vc4_v3d_dt_match,
+ },
+};
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
new file mode 100644
index 000000000000..e26d9f6face3
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -0,0 +1,900 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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.
+ */
+
+/**
+ * Command list validator for VC4.
+ *
+ * The VC4 has no IOMMU between it and system memory. So, a user with
+ * access to execute command lists could escalate privilege by
+ * overwriting system memory (drawing to it as a framebuffer) or
+ * reading system memory it shouldn't (reading it as a texture, or
+ * uniform data, or vertex data).
+ *
+ * This validates command lists to ensure that all accesses are within
+ * the bounds of the GEM objects referenced. It explicitly whitelists
+ * packets, and looks at the offsets in any address fields to make
+ * sure they're constrained within the BOs they reference.
+ *
+ * Note that because of the validation that's happening anyway, this
+ * is where GEM relocation processing happens.
+ */
+
+#include "uapi/drm/vc4_drm.h"
+#include "vc4_drv.h"
+#include "vc4_packet.h"
+
+#define VALIDATE_ARGS \
+ struct vc4_exec_info *exec, \
+ void *validated, \
+ void *untrusted
+
+/** Return the width in pixels of a 64-byte microtile. */
+static uint32_t
+utile_width(int cpp)
+{
+ switch (cpp) {
+ case 1:
+ case 2:
+ return 8;
+ case 4:
+ return 4;
+ case 8:
+ return 2;
+ default:
+ DRM_ERROR("unknown cpp: %d\n", cpp);
+ return 1;
+ }
+}
+
+/** Return the height in pixels of a 64-byte microtile. */
+static uint32_t
+utile_height(int cpp)
+{
+ switch (cpp) {
+ case 1:
+ return 8;
+ case 2:
+ case 4:
+ case 8:
+ return 4;
+ default:
+ DRM_ERROR("unknown cpp: %d\n", cpp);
+ return 1;
+ }
+}
+
+/**
+ * The texture unit decides what tiling format a particular miplevel is using
+ * this function, so we lay out our miptrees accordingly.
+ */
+static bool
+size_is_lt(uint32_t width, uint32_t height, int cpp)
+{
+ return (width <= 4 * utile_width(cpp) ||
+ height <= 4 * utile_height(cpp));
+}
+
+struct drm_gem_cma_object *
+vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex)
+{
+ struct drm_gem_cma_object *obj;
+ struct vc4_bo *bo;
+
+ if (hindex >= exec->bo_count) {
+ DRM_ERROR("BO index %d greater than BO count %d\n",
+ hindex, exec->bo_count);
+ return NULL;
+ }
+ obj = exec->bo[hindex];
+ bo = to_vc4_bo(&obj->base);
+
+ if (bo->validated_shader) {
+ DRM_ERROR("Trying to use shader BO as something other than "
+ "a shader\n");
+ return NULL;
+ }
+
+ return obj;
+}
+
+static struct drm_gem_cma_object *
+vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index)
+{
+ return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]);
+}
+
+static bool
+validate_bin_pos(struct vc4_exec_info *exec, void *untrusted, uint32_t pos)
+{
+ /* Note that the untrusted pointer passed to these functions is
+ * incremented past the packet byte.
+ */
+ return (untrusted - 1 == exec->bin_u + pos);
+}
+
+static uint32_t
+gl_shader_rec_size(uint32_t pointer_bits)
+{
+ uint32_t attribute_count = pointer_bits & 7;
+ bool extended = pointer_bits & 8;
+
+ if (attribute_count == 0)
+ attribute_count = 8;
+
+ if (extended)
+ return 100 + attribute_count * 4;
+ else
+ return 36 + attribute_count * 8;
+}
+
+bool
+vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo,
+ uint32_t offset, uint8_t tiling_format,
+ uint32_t width, uint32_t height, uint8_t cpp)
+{
+ uint32_t aligned_width, aligned_height, stride, size;
+ uint32_t utile_w = utile_width(cpp);
+ uint32_t utile_h = utile_height(cpp);
+
+ /* The shaded vertex format stores signed 12.4 fixed point
+ * (-2048,2047) offsets from the viewport center, so we should
+ * never have a render target larger than 4096. The texture
+ * unit can only sample from 2048x2048, so it's even more
+ * restricted. This lets us avoid worrying about overflow in
+ * our math.
+ */
+ if (width > 4096 || height > 4096) {
+ DRM_ERROR("Surface dimesions (%d,%d) too large", width, height);
+ return false;
+ }
+
+ switch (tiling_format) {
+ case VC4_TILING_FORMAT_LINEAR:
+ aligned_width = round_up(width, utile_w);
+ aligned_height = height;
+ break;
+ case VC4_TILING_FORMAT_T:
+ aligned_width = round_up(width, utile_w * 8);
+ aligned_height = round_up(height, utile_h * 8);
+ break;
+ case VC4_TILING_FORMAT_LT:
+ aligned_width = round_up(width, utile_w);
+ aligned_height = round_up(height, utile_h);
+ break;
+ default:
+ DRM_ERROR("buffer tiling %d unsupported\n", tiling_format);
+ return false;
+ }
+
+ stride = aligned_width * cpp;
+ size = stride * aligned_height;
+
+ if (size + offset < size ||
+ size + offset > fbo->base.size) {
+ DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n",
+ width, height,
+ aligned_width, aligned_height,
+ size, offset, fbo->base.size);
+ return false;
+ }
+
+ return true;
+}
+
+static int
+validate_flush(VALIDATE_ARGS)
+{
+ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 1)) {
+ DRM_ERROR("Bin CL must end with VC4_PACKET_FLUSH\n");
+ return -EINVAL;
+ }
+ exec->found_flush = true;
+
+ return 0;
+}
+
+static int
+validate_start_tile_binning(VALIDATE_ARGS)
+{
+ if (exec->found_start_tile_binning_packet) {
+ DRM_ERROR("Duplicate VC4_PACKET_START_TILE_BINNING\n");
+ return -EINVAL;
+ }
+ exec->found_start_tile_binning_packet = true;
+
+ if (!exec->found_tile_binning_mode_config_packet) {
+ DRM_ERROR("missing VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+validate_increment_semaphore(VALIDATE_ARGS)
+{
+ if (!validate_bin_pos(exec, untrusted, exec->args->bin_cl_size - 2)) {
+ DRM_ERROR("Bin CL must end with "
+ "VC4_PACKET_INCREMENT_SEMAPHORE\n");
+ return -EINVAL;
+ }
+ exec->found_increment_semaphore_packet = true;
+
+ return 0;
+}
+
+static int
+validate_indexed_prim_list(VALIDATE_ARGS)
+{
+ struct drm_gem_cma_object *ib;
+ uint32_t length = *(uint32_t *)(untrusted + 1);
+ uint32_t offset = *(uint32_t *)(untrusted + 5);
+ uint32_t max_index = *(uint32_t *)(untrusted + 9);
+ uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;
+ struct vc4_shader_state *shader_state;
+
+ /* Check overflow condition */
+ if (exec->shader_state_count == 0) {
+ DRM_ERROR("shader state must precede primitives\n");
+ return -EINVAL;
+ }
+ shader_state = &exec->shader_state[exec->shader_state_count - 1];
+
+ if (max_index > shader_state->max_index)
+ shader_state->max_index = max_index;
+
+ ib = vc4_use_handle(exec, 0);
+ if (!ib)
+ return -EINVAL;
+
+ if (offset > ib->base.size ||
+ (ib->base.size - offset) / index_size < length) {
+ DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n",
+ offset, length, index_size, ib->base.size);
+ return -EINVAL;
+ }
+
+ *(uint32_t *)(validated + 5) = ib->paddr + offset;
+
+ return 0;
+}
+
+static int
+validate_gl_array_primitive(VALIDATE_ARGS)
+{
+ uint32_t length = *(uint32_t *)(untrusted + 1);
+ uint32_t base_index = *(uint32_t *)(untrusted + 5);
+ uint32_t max_index;
+ struct vc4_shader_state *shader_state;
+
+ /* Check overflow condition */
+ if (exec->shader_state_count == 0) {
+ DRM_ERROR("shader state must precede primitives\n");
+ return -EINVAL;
+ }
+ shader_state = &exec->shader_state[exec->shader_state_count - 1];
+
+ if (length + base_index < length) {
+ DRM_ERROR("primitive vertex count overflow\n");
+ return -EINVAL;
+ }
+ max_index = length + base_index - 1;
+
+ if (max_index > shader_state->max_index)
+ shader_state->max_index = max_index;
+
+ return 0;
+}
+
+static int
+validate_gl_shader_state(VALIDATE_ARGS)
+{
+ uint32_t i = exec->shader_state_count++;
+
+ if (i >= exec->shader_state_size) {
+ DRM_ERROR("More requests for shader states than declared\n");
+ return -EINVAL;
+ }
+
+ exec->shader_state[i].addr = *(uint32_t *)untrusted;
+ exec->shader_state[i].max_index = 0;
+
+ if (exec->shader_state[i].addr & ~0xf) {
+ DRM_ERROR("high bits set in GL shader rec reference\n");
+ return -EINVAL;
+ }
+
+ *(uint32_t *)validated = (exec->shader_rec_p +
+ exec->shader_state[i].addr);
+
+ exec->shader_rec_p +=
+ roundup(gl_shader_rec_size(exec->shader_state[i].addr), 16);
+
+ return 0;
+}
+
+static int
+validate_tile_binning_config(VALIDATE_ARGS)
+{
+ struct drm_device *dev = exec->exec_bo->base.dev;
+ struct vc4_bo *tile_bo;
+ uint8_t flags;
+ uint32_t tile_state_size, tile_alloc_size;
+ uint32_t tile_count;
+
+ if (exec->found_tile_binning_mode_config_packet) {
+ DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n");
+ return -EINVAL;
+ }
+ exec->found_tile_binning_mode_config_packet = true;
+
+ exec->bin_tiles_x = *(uint8_t *)(untrusted + 12);
+ exec->bin_tiles_y = *(uint8_t *)(untrusted + 13);
+ tile_count = exec->bin_tiles_x * exec->bin_tiles_y;
+ flags = *(uint8_t *)(untrusted + 14);
+
+ if (exec->bin_tiles_x == 0 ||
+ exec->bin_tiles_y == 0) {
+ DRM_ERROR("Tile binning config of %dx%d too small\n",
+ exec->bin_tiles_x, exec->bin_tiles_y);
+ return -EINVAL;
+ }
+
+ if (flags & (VC4_BIN_CONFIG_DB_NON_MS |
+ VC4_BIN_CONFIG_TILE_BUFFER_64BIT)) {
+ DRM_ERROR("unsupported binning config flags 0x%02x\n", flags);
+ return -EINVAL;
+ }
+
+ /* The tile state data array is 48 bytes per tile, and we put it at
+ * the start of a BO containing both it and the tile alloc.
+ */
+ tile_state_size = 48 * tile_count;
+
+ /* Since the tile alloc array will follow us, align. */
+ exec->tile_alloc_offset = roundup(tile_state_size, 4096);
+
+ *(uint8_t *)(validated + 14) =
+ ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |
+ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) |
+ VC4_BIN_CONFIG_AUTO_INIT_TSDA |
+ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32,
+ VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) |
+ VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128,
+ VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE));
+
+ /* Initial block size. */
+ tile_alloc_size = 32 * tile_count;
+
+ /*
+ * The initial allocation gets rounded to the next 256 bytes before
+ * the hardware starts fulfilling further allocations.
+ */
+ tile_alloc_size = roundup(tile_alloc_size, 256);
+
+ /* Add space for the extra allocations. This is what gets used first,
+ * before overflow memory. It must have at least 4096 bytes, but we
+ * want to avoid overflow memory usage if possible.
+ */
+ tile_alloc_size += 1024 * 1024;
+
+ tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size,
+ true);
+ exec->tile_bo = &tile_bo->base;
+ if (!exec->tile_bo)
+ return -ENOMEM;
+ list_add_tail(&tile_bo->unref_head, &exec->unref_list);
+
+ /* tile alloc address. */
+ *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr +
+ exec->tile_alloc_offset);
+ /* tile alloc size. */
+ *(uint32_t *)(validated + 4) = tile_alloc_size;
+ /* tile state address. */
+ *(uint32_t *)(validated + 8) = exec->tile_bo->paddr;
+
+ return 0;
+}
+
+static int
+validate_gem_handles(VALIDATE_ARGS)
+{
+ memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index));
+ return 0;
+}
+
+#define VC4_DEFINE_PACKET(packet, func) \
+ [packet] = { packet ## _SIZE, #packet, func }
+
+static const struct cmd_info {
+ uint16_t len;
+ const char *name;
+ int (*func)(struct vc4_exec_info *exec, void *validated,
+ void *untrusted);
+} cmd_info[] = {
+ VC4_DEFINE_PACKET(VC4_PACKET_HALT, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_NOP, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, validate_flush),
+ VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING,
+ validate_start_tile_binning),
+ VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE,
+ validate_increment_semaphore),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE,
+ validate_indexed_prim_list),
+ VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE,
+ validate_gl_array_primitive),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, NULL),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, validate_gl_shader_state),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, NULL),
+ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, NULL),
+ /* Note: The docs say this was also 105, but it was 106 in the
+ * initial userland code drop.
+ */
+ VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, NULL),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG,
+ validate_tile_binning_config),
+
+ VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, validate_gem_handles),
+};
+
+int
+vc4_validate_bin_cl(struct drm_device *dev,
+ void *validated,
+ void *unvalidated,
+ struct vc4_exec_info *exec)
+{
+ uint32_t len = exec->args->bin_cl_size;
+ uint32_t dst_offset = 0;
+ uint32_t src_offset = 0;
+
+ while (src_offset < len) {
+ void *dst_pkt = validated + dst_offset;
+ void *src_pkt = unvalidated + src_offset;
+ u8 cmd = *(uint8_t *)src_pkt;
+ const struct cmd_info *info;
+
+ if (cmd >= ARRAY_SIZE(cmd_info)) {
+ DRM_ERROR("0x%08x: packet %d out of bounds\n",
+ src_offset, cmd);
+ return -EINVAL;
+ }
+
+ info = &cmd_info[cmd];
+ if (!info->name) {
+ DRM_ERROR("0x%08x: packet %d invalid\n",
+ src_offset, cmd);
+ return -EINVAL;
+ }
+
+ if (src_offset + info->len > len) {
+ DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x "
+ "exceeds bounds (0x%08x)\n",
+ src_offset, cmd, info->name, info->len,
+ src_offset + len);
+ return -EINVAL;
+ }
+
+ if (cmd != VC4_PACKET_GEM_HANDLES)
+ memcpy(dst_pkt, src_pkt, info->len);
+
+ if (info->func && info->func(exec,
+ dst_pkt + 1,
+ src_pkt + 1)) {
+ DRM_ERROR("0x%08x: packet %d (%s) failed to validate\n",
+ src_offset, cmd, info->name);
+ return -EINVAL;
+ }
+
+ src_offset += info->len;
+ /* GEM handle loading doesn't produce HW packets. */
+ if (cmd != VC4_PACKET_GEM_HANDLES)
+ dst_offset += info->len;
+
+ /* When the CL hits halt, it'll stop reading anything else. */
+ if (cmd == VC4_PACKET_HALT)
+ break;
+ }
+
+ exec->ct0ea = exec->ct0ca + dst_offset;
+
+ if (!exec->found_start_tile_binning_packet) {
+ DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n");
+ return -EINVAL;
+ }
+
+ /* The bin CL must be ended with INCREMENT_SEMAPHORE and FLUSH. The
+ * semaphore is used to trigger the render CL to start up, and the
+ * FLUSH is what caps the bin lists with
+ * VC4_PACKET_RETURN_FROM_SUB_LIST (so they jump back to the main
+ * render CL when they get called to) and actually triggers the queued
+ * semaphore increment.
+ */
+ if (!exec->found_increment_semaphore_packet || !exec->found_flush) {
+ DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE + "
+ "VC4_PACKET_FLUSH\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool
+reloc_tex(struct vc4_exec_info *exec,
+ void *uniform_data_u,
+ struct vc4_texture_sample_info *sample,
+ uint32_t texture_handle_index)
+
+{
+ struct drm_gem_cma_object *tex;
+ uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
+ uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]);
+ uint32_t p2 = (sample->p_offset[2] != ~0 ?
+ *(uint32_t *)(uniform_data_u + sample->p_offset[2]) : 0);
+ uint32_t p3 = (sample->p_offset[3] != ~0 ?
+ *(uint32_t *)(uniform_data_u + sample->p_offset[3]) : 0);
+ uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0];
+ uint32_t offset = p0 & VC4_TEX_P0_OFFSET_MASK;
+ uint32_t miplevels = VC4_GET_FIELD(p0, VC4_TEX_P0_MIPLVLS);
+ uint32_t width = VC4_GET_FIELD(p1, VC4_TEX_P1_WIDTH);
+ uint32_t height = VC4_GET_FIELD(p1, VC4_TEX_P1_HEIGHT);
+ uint32_t cpp, tiling_format, utile_w, utile_h;
+ uint32_t i;
+ uint32_t cube_map_stride = 0;
+ enum vc4_texture_data_type type;
+
+ tex = vc4_use_bo(exec, texture_handle_index);
+ if (!tex)
+ return false;
+
+ if (sample->is_direct) {
+ uint32_t remaining_size = tex->base.size - p0;
+
+ if (p0 > tex->base.size - 4) {
+ DRM_ERROR("UBO offset greater than UBO size\n");
+ goto fail;
+ }
+ if (p1 > remaining_size - 4) {
+ DRM_ERROR("UBO clamp would allow reads "
+ "outside of UBO\n");
+ goto fail;
+ }
+ *validated_p0 = tex->paddr + p0;
+ return true;
+ }
+
+ if (width == 0)
+ width = 2048;
+ if (height == 0)
+ height = 2048;
+
+ if (p0 & VC4_TEX_P0_CMMODE_MASK) {
+ if (VC4_GET_FIELD(p2, VC4_TEX_P2_PTYPE) ==
+ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE)
+ cube_map_stride = p2 & VC4_TEX_P2_CMST_MASK;
+ if (VC4_GET_FIELD(p3, VC4_TEX_P2_PTYPE) ==
+ VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE) {
+ if (cube_map_stride) {
+ DRM_ERROR("Cube map stride set twice\n");
+ goto fail;
+ }
+
+ cube_map_stride = p3 & VC4_TEX_P2_CMST_MASK;
+ }
+ if (!cube_map_stride) {
+ DRM_ERROR("Cube map stride not set\n");
+ goto fail;
+ }
+ }
+
+ type = (VC4_GET_FIELD(p0, VC4_TEX_P0_TYPE) |
+ (VC4_GET_FIELD(p1, VC4_TEX_P1_TYPE4) << 4));
+
+ switch (type) {
+ case VC4_TEXTURE_TYPE_RGBA8888:
+ case VC4_TEXTURE_TYPE_RGBX8888:
+ case VC4_TEXTURE_TYPE_RGBA32R:
+ cpp = 4;
+ break;
+ case VC4_TEXTURE_TYPE_RGBA4444:
+ case VC4_TEXTURE_TYPE_RGBA5551:
+ case VC4_TEXTURE_TYPE_RGB565:
+ case VC4_TEXTURE_TYPE_LUMALPHA:
+ case VC4_TEXTURE_TYPE_S16F:
+ case VC4_TEXTURE_TYPE_S16:
+ cpp = 2;
+ break;
+ case VC4_TEXTURE_TYPE_LUMINANCE:
+ case VC4_TEXTURE_TYPE_ALPHA:
+ case VC4_TEXTURE_TYPE_S8:
+ cpp = 1;
+ break;
+ case VC4_TEXTURE_TYPE_ETC1:
+ case VC4_TEXTURE_TYPE_BW1:
+ case VC4_TEXTURE_TYPE_A4:
+ case VC4_TEXTURE_TYPE_A1:
+ case VC4_TEXTURE_TYPE_RGBA64:
+ case VC4_TEXTURE_TYPE_YUV422R:
+ default:
+ DRM_ERROR("Texture format %d unsupported\n", type);
+ goto fail;
+ }
+ utile_w = utile_width(cpp);
+ utile_h = utile_height(cpp);
+
+ if (type == VC4_TEXTURE_TYPE_RGBA32R) {
+ tiling_format = VC4_TILING_FORMAT_LINEAR;
+ } else {
+ if (size_is_lt(width, height, cpp))
+ tiling_format = VC4_TILING_FORMAT_LT;
+ else
+ tiling_format = VC4_TILING_FORMAT_T;
+ }
+
+ if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5,
+ tiling_format, width, height, cpp)) {
+ goto fail;
+ }
+
+ /* The mipmap levels are stored before the base of the texture. Make
+ * sure there is actually space in the BO.
+ */
+ for (i = 1; i <= miplevels; i++) {
+ uint32_t level_width = max(width >> i, 1u);
+ uint32_t level_height = max(height >> i, 1u);
+ uint32_t aligned_width, aligned_height;
+ uint32_t level_size;
+
+ /* Once the levels get small enough, they drop from T to LT. */
+ if (tiling_format == VC4_TILING_FORMAT_T &&
+ size_is_lt(level_width, level_height, cpp)) {
+ tiling_format = VC4_TILING_FORMAT_LT;
+ }
+
+ switch (tiling_format) {
+ case VC4_TILING_FORMAT_T:
+ aligned_width = round_up(level_width, utile_w * 8);
+ aligned_height = round_up(level_height, utile_h * 8);
+ break;
+ case VC4_TILING_FORMAT_LT:
+ aligned_width = round_up(level_width, utile_w);
+ aligned_height = round_up(level_height, utile_h);
+ break;
+ default:
+ aligned_width = round_up(level_width, utile_w);
+ aligned_height = level_height;
+ break;
+ }
+
+ level_size = aligned_width * cpp * aligned_height;
+
+ if (offset < level_size) {
+ DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db "
+ "overflowed buffer bounds (offset %d)\n",
+ i, level_width, level_height,
+ aligned_width, aligned_height,
+ level_size, offset);
+ goto fail;
+ }
+
+ offset -= level_size;
+ }
+
+ *validated_p0 = tex->paddr + p0;
+
+ return true;
+ fail:
+ DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
+ DRM_INFO("Texture p1 at %d: 0x%08x\n", sample->p_offset[1], p1);
+ DRM_INFO("Texture p2 at %d: 0x%08x\n", sample->p_offset[2], p2);
+ DRM_INFO("Texture p3 at %d: 0x%08x\n", sample->p_offset[3], p3);
+ return false;
+}
+
+static int
+validate_gl_shader_rec(struct drm_device *dev,
+ struct vc4_exec_info *exec,
+ struct vc4_shader_state *state)
+{
+ uint32_t *src_handles;
+ void *pkt_u, *pkt_v;
+ static const uint32_t shader_reloc_offsets[] = {
+ 4, /* fs */
+ 16, /* vs */
+ 28, /* cs */
+ };
+ uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets);
+ struct drm_gem_cma_object *bo[shader_reloc_count + 8];
+ uint32_t nr_attributes, nr_relocs, packet_size;
+ int i;
+
+ nr_attributes = state->addr & 0x7;
+ if (nr_attributes == 0)
+ nr_attributes = 8;
+ packet_size = gl_shader_rec_size(state->addr);
+
+ nr_relocs = ARRAY_SIZE(shader_reloc_offsets) + nr_attributes;
+ if (nr_relocs * 4 > exec->shader_rec_size) {
+ DRM_ERROR("overflowed shader recs reading %d handles "
+ "from %d bytes left\n",
+ nr_relocs, exec->shader_rec_size);
+ return -EINVAL;
+ }
+ src_handles = exec->shader_rec_u;
+ exec->shader_rec_u += nr_relocs * 4;
+ exec->shader_rec_size -= nr_relocs * 4;
+
+ if (packet_size > exec->shader_rec_size) {
+ DRM_ERROR("overflowed shader recs copying %db packet "
+ "from %d bytes left\n",
+ packet_size, exec->shader_rec_size);
+ return -EINVAL;
+ }
+ pkt_u = exec->shader_rec_u;
+ pkt_v = exec->shader_rec_v;
+ memcpy(pkt_v, pkt_u, packet_size);
+ exec->shader_rec_u += packet_size;
+ /* Shader recs have to be aligned to 16 bytes (due to the attribute
+ * flags being in the low bytes), so round the next validated shader
+ * rec address up. This should be safe, since we've got so many
+ * relocations in a shader rec packet.
+ */
+ BUG_ON(roundup(packet_size, 16) - packet_size > nr_relocs * 4);
+ exec->shader_rec_v += roundup(packet_size, 16);
+ exec->shader_rec_size -= packet_size;
+
+ if (!(*(uint16_t *)pkt_u & VC4_SHADER_FLAG_FS_SINGLE_THREAD)) {
+ DRM_ERROR("Multi-threaded fragment shaders not supported.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < shader_reloc_count; i++) {
+ if (src_handles[i] > exec->bo_count) {
+ DRM_ERROR("Shader handle %d too big\n", src_handles[i]);
+ return -EINVAL;
+ }
+
+ bo[i] = exec->bo[src_handles[i]];
+ if (!bo[i])
+ return -EINVAL;
+ }
+ for (i = shader_reloc_count; i < nr_relocs; i++) {
+ bo[i] = vc4_use_bo(exec, src_handles[i]);
+ if (!bo[i])
+ return -EINVAL;
+ }
+
+ for (i = 0; i < shader_reloc_count; i++) {
+ struct vc4_validated_shader_info *validated_shader;
+ uint32_t o = shader_reloc_offsets[i];
+ uint32_t src_offset = *(uint32_t *)(pkt_u + o);
+ uint32_t *texture_handles_u;
+ void *uniform_data_u;
+ uint32_t tex;
+
+ *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset;
+
+ if (src_offset != 0) {
+ DRM_ERROR("Shaders must be at offset 0 of "
+ "the BO.\n");
+ return -EINVAL;
+ }
+
+ validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader;
+ if (!validated_shader)
+ return -EINVAL;
+
+ if (validated_shader->uniforms_src_size >
+ exec->uniforms_size) {
+ DRM_ERROR("Uniforms src buffer overflow\n");
+ return -EINVAL;
+ }
+
+ texture_handles_u = exec->uniforms_u;
+ uniform_data_u = (texture_handles_u +
+ validated_shader->num_texture_samples);
+
+ memcpy(exec->uniforms_v, uniform_data_u,
+ validated_shader->uniforms_size);
+
+ for (tex = 0;
+ tex < validated_shader->num_texture_samples;
+ tex++) {
+ if (!reloc_tex(exec,
+ uniform_data_u,
+ &validated_shader->texture_samples[tex],
+ texture_handles_u[tex])) {
+ return -EINVAL;
+ }
+ }
+
+ *(uint32_t *)(pkt_v + o + 4) = exec->uniforms_p;
+
+ exec->uniforms_u += validated_shader->uniforms_src_size;
+ exec->uniforms_v += validated_shader->uniforms_size;
+ exec->uniforms_p += validated_shader->uniforms_size;
+ }
+
+ for (i = 0; i < nr_attributes; i++) {
+ struct drm_gem_cma_object *vbo =
+ bo[ARRAY_SIZE(shader_reloc_offsets) + i];
+ uint32_t o = 36 + i * 8;
+ uint32_t offset = *(uint32_t *)(pkt_u + o + 0);
+ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;
+ uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
+ uint32_t max_index;
+
+ if (state->addr & 0x8)
+ stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
+
+ if (vbo->base.size < offset ||
+ vbo->base.size - offset < attr_size) {
+ DRM_ERROR("BO offset overflow (%d + %d > %zu)\n",
+ offset, attr_size, vbo->base.size);
+ return -EINVAL;
+ }
+
+ if (stride != 0) {
+ max_index = ((vbo->base.size - offset - attr_size) /
+ stride);
+ if (state->max_index > max_index) {
+ DRM_ERROR("primitives use index %d out of "
+ "supplied %d\n",
+ state->max_index, max_index);
+ return -EINVAL;
+ }
+ }
+
+ *(uint32_t *)(pkt_v + o) = vbo->paddr + offset;
+ }
+
+ return 0;
+}
+
+int
+vc4_validate_shader_recs(struct drm_device *dev,
+ struct vc4_exec_info *exec)
+{
+ uint32_t i;
+ int ret = 0;
+
+ for (i = 0; i < exec->shader_state_count; i++) {
+ ret = validate_gl_shader_rec(dev, exec, &exec->shader_state[i]);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
new file mode 100644
index 000000000000..f67124b4c534
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright © 2014 Broadcom
+ *
+ * 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.
+ */
+
+/**
+ * DOC: Shader validator for VC4.
+ *
+ * The VC4 has no IOMMU between it and system memory, so a user with
+ * access to execute shaders could escalate privilege by overwriting
+ * system memory (using the VPM write address register in the
+ * general-purpose DMA mode) or reading system memory it shouldn't
+ * (reading it as a texture, or uniform data, or vertex data).
+ *
+ * This walks over a shader BO, ensuring that its accesses are
+ * appropriately bounded, and recording how many texture accesses are
+ * made and where so that we can do relocations for them in the
+ * uniform stream.
+ */
+
+#include "vc4_drv.h"
+#include "vc4_qpu_defines.h"
+
+struct vc4_shader_validation_state {
+ struct vc4_texture_sample_info tmu_setup[2];
+ int tmu_write_count[2];
+
+ /* For registers that were last written to by a MIN instruction with
+ * one argument being a uniform, the address of the uniform.
+ * Otherwise, ~0.
+ *
+ * This is used for the validation of direct address memory reads.
+ */
+ uint32_t live_min_clamp_offsets[32 + 32 + 4];
+ bool live_max_clamp_regs[32 + 32 + 4];
+};
+
+static uint32_t
+waddr_to_live_reg_index(uint32_t waddr, bool is_b)
+{
+ if (waddr < 32) {
+ if (is_b)
+ return 32 + waddr;
+ else
+ return waddr;
+ } else if (waddr <= QPU_W_ACC3) {
+ return 64 + waddr - QPU_W_ACC0;
+ } else {
+ return ~0;
+ }
+}
+
+static uint32_t
+raddr_add_a_to_live_reg_index(uint64_t inst)
+{
+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
+ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
+
+ if (add_a == QPU_MUX_A)
+ return raddr_a;
+ else if (add_a == QPU_MUX_B && sig != QPU_SIG_SMALL_IMM)
+ return 32 + raddr_b;
+ else if (add_a <= QPU_MUX_R3)
+ return 64 + add_a;
+ else
+ return ~0;
+}
+
+static bool
+is_tmu_submit(uint32_t waddr)
+{
+ return (waddr == QPU_W_TMU0_S ||
+ waddr == QPU_W_TMU1_S);
+}
+
+static bool
+is_tmu_write(uint32_t waddr)
+{
+ return (waddr >= QPU_W_TMU0_S &&
+ waddr <= QPU_W_TMU1_B);
+}
+
+static bool
+record_texture_sample(struct vc4_validated_shader_info *validated_shader,
+ struct vc4_shader_validation_state *validation_state,
+ int tmu)
+{
+ uint32_t s = validated_shader->num_texture_samples;
+ int i;
+ struct vc4_texture_sample_info *temp_samples;
+
+ temp_samples = krealloc(validated_shader->texture_samples,
+ (s + 1) * sizeof(*temp_samples),
+ GFP_KERNEL);
+ if (!temp_samples)
+ return false;
+
+ memcpy(&temp_samples[s],
+ &validation_state->tmu_setup[tmu],
+ sizeof(*temp_samples));
+
+ validated_shader->num_texture_samples = s + 1;
+ validated_shader->texture_samples = temp_samples;
+
+ for (i = 0; i < 4; i++)
+ validation_state->tmu_setup[tmu].p_offset[i] = ~0;
+
+ return true;
+}
+
+static bool
+check_tmu_write(uint64_t inst,
+ struct vc4_validated_shader_info *validated_shader,
+ struct vc4_shader_validation_state *validation_state,
+ bool is_mul)
+{
+ uint32_t waddr = (is_mul ?
+ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
+ QPU_GET_FIELD(inst, QPU_WADDR_ADD));
+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
+ int tmu = waddr > QPU_W_TMU0_B;
+ bool submit = is_tmu_submit(waddr);
+ bool is_direct = submit && validation_state->tmu_write_count[tmu] == 0;
+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
+
+ if (is_direct) {
+ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
+ uint32_t clamp_reg, clamp_offset;
+
+ if (sig == QPU_SIG_SMALL_IMM) {
+ DRM_ERROR("direct TMU read used small immediate\n");
+ return false;
+ }
+
+ /* Make sure that this texture load is an add of the base
+ * address of the UBO to a clamped offset within the UBO.
+ */
+ if (is_mul ||
+ QPU_GET_FIELD(inst, QPU_OP_ADD) != QPU_A_ADD) {
+ DRM_ERROR("direct TMU load wasn't an add\n");
+ return false;
+ }
+
+ /* We assert that the the clamped address is the first
+ * argument, and the UBO base address is the second argument.
+ * This is arbitrary, but simpler than supporting flipping the
+ * two either way.
+ */
+ clamp_reg = raddr_add_a_to_live_reg_index(inst);
+ if (clamp_reg == ~0) {
+ DRM_ERROR("direct TMU load wasn't clamped\n");
+ return false;
+ }
+
+ clamp_offset = validation_state->live_min_clamp_offsets[clamp_reg];
+ if (clamp_offset == ~0) {
+ DRM_ERROR("direct TMU load wasn't clamped\n");
+ return false;
+ }
+
+ /* Store the clamp value's offset in p1 (see reloc_tex() in
+ * vc4_validate.c).
+ */
+ validation_state->tmu_setup[tmu].p_offset[1] =
+ clamp_offset;
+
+ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
+ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF)) {
+ DRM_ERROR("direct TMU load didn't add to a uniform\n");
+ return false;
+ }
+
+ validation_state->tmu_setup[tmu].is_direct = true;
+ } else {
+ if (raddr_a == QPU_R_UNIF || (sig != QPU_SIG_SMALL_IMM &&
+ raddr_b == QPU_R_UNIF)) {
+ DRM_ERROR("uniform read in the same instruction as "
+ "texture setup.\n");
+ return false;
+ }
+ }
+
+ if (validation_state->tmu_write_count[tmu] >= 4) {
+ DRM_ERROR("TMU%d got too many parameters before dispatch\n",
+ tmu);
+ return false;
+ }
+ validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] =
+ validated_shader->uniforms_size;
+ validation_state->tmu_write_count[tmu]++;
+ /* Since direct uses a RADDR uniform reference, it will get counted in
+ * check_instruction_reads()
+ */
+ if (!is_direct)
+ validated_shader->uniforms_size += 4;
+
+ if (submit) {
+ if (!record_texture_sample(validated_shader,
+ validation_state, tmu)) {
+ return false;
+ }
+
+ validation_state->tmu_write_count[tmu] = 0;
+ }
+
+ return true;
+}
+
+static bool
+check_reg_write(uint64_t inst,
+ struct vc4_validated_shader_info *validated_shader,
+ struct vc4_shader_validation_state *validation_state,
+ bool is_mul)
+{
+ uint32_t waddr = (is_mul ?
+ QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
+ QPU_GET_FIELD(inst, QPU_WADDR_ADD));
+
+ switch (waddr) {
+ case QPU_W_UNIFORMS_ADDRESS:
+ /* XXX: We'll probably need to support this for reladdr, but
+ * it's definitely a security-related one.
+ */
+ DRM_ERROR("uniforms address load unsupported\n");
+ return false;
+
+ case QPU_W_TLB_COLOR_MS:
+ case QPU_W_TLB_COLOR_ALL:
+ case QPU_W_TLB_Z:
+ /* These only interact with the tile buffer, not main memory,
+ * so they're safe.
+ */
+ return true;
+
+ case QPU_W_TMU0_S:
+ case QPU_W_TMU0_T:
+ case QPU_W_TMU0_R:
+ case QPU_W_TMU0_B:
+ case QPU_W_TMU1_S:
+ case QPU_W_TMU1_T:
+ case QPU_W_TMU1_R:
+ case QPU_W_TMU1_B:
+ return check_tmu_write(inst, validated_shader, validation_state,
+ is_mul);
+
+ case QPU_W_HOST_INT:
+ case QPU_W_TMU_NOSWAP:
+ case QPU_W_TLB_ALPHA_MASK:
+ case QPU_W_MUTEX_RELEASE:
+ /* XXX: I haven't thought about these, so don't support them
+ * for now.
+ */
+ DRM_ERROR("Unsupported waddr %d\n", waddr);
+ return false;
+
+ case QPU_W_VPM_ADDR:
+ DRM_ERROR("General VPM DMA unsupported\n");
+ return false;
+
+ case QPU_W_VPM:
+ case QPU_W_VPMVCD_SETUP:
+ /* We allow VPM setup in general, even including VPM DMA
+ * configuration setup, because the (unsafe) DMA can only be
+ * triggered by QPU_W_VPM_ADDR writes.
+ */
+ return true;
+
+ case QPU_W_TLB_STENCIL_SETUP:
+ return true;
+ }
+
+ return true;
+}
+
+static void
+track_live_clamps(uint64_t inst,
+ struct vc4_validated_shader_info *validated_shader,
+ struct vc4_shader_validation_state *validation_state)
+{
+ uint32_t op_add = QPU_GET_FIELD(inst, QPU_OP_ADD);
+ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
+ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
+ uint32_t cond_add = QPU_GET_FIELD(inst, QPU_COND_ADD);
+ uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
+ uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
+ bool ws = inst & QPU_WS;
+ uint32_t lri_add_a, lri_add, lri_mul;
+ bool add_a_is_min_0;
+
+ /* Check whether OP_ADD's A argumennt comes from a live MAX(x, 0),
+ * before we clear previous live state.
+ */
+ lri_add_a = raddr_add_a_to_live_reg_index(inst);
+ add_a_is_min_0 = (lri_add_a != ~0 &&
+ validation_state->live_max_clamp_regs[lri_add_a]);
+
+ /* Clear live state for registers written by our instruction. */
+ lri_add = waddr_to_live_reg_index(waddr_add, ws);
+ lri_mul = waddr_to_live_reg_index(waddr_mul, !ws);
+ if (lri_mul != ~0) {
+ validation_state->live_max_clamp_regs[lri_mul] = false;
+ validation_state->live_min_clamp_offsets[lri_mul] = ~0;
+ }
+ if (lri_add != ~0) {
+ validation_state->live_max_clamp_regs[lri_add] = false;
+ validation_state->live_min_clamp_offsets[lri_add] = ~0;
+ } else {
+ /* Nothing further to do for live tracking, since only ADDs
+ * generate new live clamp registers.
+ */
+ return;
+ }
+
+ /* Now, handle remaining live clamp tracking for the ADD operation. */
+
+ if (cond_add != QPU_COND_ALWAYS)
+ return;
+
+ if (op_add == QPU_A_MAX) {
+ /* Track live clamps of a value to a minimum of 0 (in either
+ * arg).
+ */
+ if (sig != QPU_SIG_SMALL_IMM || raddr_b != 0 ||
+ (add_a != QPU_MUX_B && add_b != QPU_MUX_B)) {
+ return;
+ }
+
+ validation_state->live_max_clamp_regs[lri_add] = true;
+ } else if (op_add == QPU_A_MIN) {
+ /* Track live clamps of a value clamped to a minimum of 0 and
+ * a maximum of some uniform's offset.
+ */
+ if (!add_a_is_min_0)
+ return;
+
+ if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
+ !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF &&
+ sig != QPU_SIG_SMALL_IMM)) {
+ return;
+ }
+
+ validation_state->live_min_clamp_offsets[lri_add] =
+ validated_shader->uniforms_size;
+ }
+}
+
+static bool
+check_instruction_writes(uint64_t inst,
+ struct vc4_validated_shader_info *validated_shader,
+ struct vc4_shader_validation_state *validation_state)
+{
+ uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
+ uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
+ bool ok;
+
+ if (is_tmu_write(waddr_add) && is_tmu_write(waddr_mul)) {
+ DRM_ERROR("ADD and MUL both set up textures\n");
+ return false;
+ }
+
+ ok = (check_reg_write(inst, validated_shader, validation_state,
+ false) &&
+ check_reg_write(inst, validated_shader, validation_state,
+ true));
+
+ track_live_clamps(inst, validated_shader, validation_state);
+
+ return ok;
+}
+
+static bool
+check_instruction_reads(uint64_t inst,
+ struct vc4_validated_shader_info *validated_shader)
+{
+ uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
+ uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
+
+ if (raddr_a == QPU_R_UNIF ||
+ (raddr_b == QPU_R_UNIF && sig != QPU_SIG_SMALL_IMM)) {
+ /* This can't overflow the uint32_t, because we're reading 8
+ * bytes of instruction to increment by 4 here, so we'd
+ * already be OOM.
+ */
+ validated_shader->uniforms_size += 4;
+ }
+
+ return true;
+}
+
+struct vc4_validated_shader_info *
+vc4_validate_shader(struct drm_gem_cma_object *shader_obj)
+{
+ bool found_shader_end = false;
+ int shader_end_ip = 0;
+ uint32_t ip, max_ip;
+ uint64_t *shader;
+ struct vc4_validated_shader_info *validated_shader;
+ struct vc4_shader_validation_state validation_state;
+ int i;
+
+ memset(&validation_state, 0, sizeof(validation_state));
+
+ for (i = 0; i < 8; i++)
+ validation_state.tmu_setup[i / 4].p_offset[i % 4] = ~0;
+ for (i = 0; i < ARRAY_SIZE(validation_state.live_min_clamp_offsets); i++)
+ validation_state.live_min_clamp_offsets[i] = ~0;
+
+ shader = shader_obj->vaddr;
+ max_ip = shader_obj->base.size / sizeof(uint64_t);
+
+ validated_shader = kcalloc(1, sizeof(*validated_shader), GFP_KERNEL);
+ if (!validated_shader)
+ return NULL;
+
+ for (ip = 0; ip < max_ip; ip++) {
+ uint64_t inst = shader[ip];
+ uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
+
+ switch (sig) {
+ case QPU_SIG_NONE:
+ case QPU_SIG_WAIT_FOR_SCOREBOARD:
+ case QPU_SIG_SCOREBOARD_UNLOCK:
+ case QPU_SIG_COLOR_LOAD:
+ case QPU_SIG_LOAD_TMU0:
+ case QPU_SIG_LOAD_TMU1:
+ case QPU_SIG_PROG_END:
+ case QPU_SIG_SMALL_IMM:
+ if (!check_instruction_writes(inst, validated_shader,
+ &validation_state)) {
+ DRM_ERROR("Bad write at ip %d\n", ip);
+ goto fail;
+ }
+
+ if (!check_instruction_reads(inst, validated_shader))
+ goto fail;
+
+ if (sig == QPU_SIG_PROG_END) {
+ found_shader_end = true;
+ shader_end_ip = ip;
+ }
+
+ break;
+
+ case QPU_SIG_LOAD_IMM:
+ if (!check_instruction_writes(inst, validated_shader,
+ &validation_state)) {
+ DRM_ERROR("Bad LOAD_IMM write at ip %d\n", ip);
+ goto fail;
+ }
+ break;
+
+ default:
+ DRM_ERROR("Unsupported QPU signal %d at "
+ "instruction %d\n", sig, ip);
+ goto fail;
+ }
+
+ /* There are two delay slots after program end is signaled
+ * that are still executed, then we're finished.
+ */
+ if (found_shader_end && ip == shader_end_ip + 2)
+ break;
+ }
+
+ if (ip == max_ip) {
+ DRM_ERROR("shader failed to terminate before "
+ "shader BO end at %zd\n",
+ shader_obj->base.size);
+ goto fail;
+ }
+
+ /* Again, no chance of integer overflow here because the worst case
+ * scenario is 8 bytes of uniforms plus handles per 8-byte
+ * instruction.
+ */
+ validated_shader->uniforms_src_size =
+ (validated_shader->uniforms_size +
+ 4 * validated_shader->num_texture_samples);
+
+ return validated_shader;
+
+fail:
+ if (validated_shader) {
+ kfree(validated_shader->texture_samples);
+ kfree(validated_shader);
+ }
+ return NULL;
+}
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 578fe0a9324c..a165f03eaa79 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -215,7 +215,7 @@ static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = {
int
virtio_gpu_framebuffer_init(struct drm_device *dev,
struct virtio_gpu_framebuffer *vgfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
@@ -374,16 +374,6 @@ static const struct drm_connector_helper_funcs virtio_gpu_conn_helper_funcs = {
.best_encoder = virtio_gpu_best_encoder,
};
-static void virtio_gpu_conn_save(struct drm_connector *connector)
-{
- DRM_DEBUG("\n");
-}
-
-static void virtio_gpu_conn_restore(struct drm_connector *connector)
-{
- DRM_DEBUG("\n");
-}
-
static enum drm_connector_status virtio_gpu_conn_detect(
struct drm_connector *connector,
bool force)
@@ -409,10 +399,8 @@ static void virtio_gpu_conn_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs virtio_gpu_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
- .save = virtio_gpu_conn_save,
- .restore = virtio_gpu_conn_restore,
.detect = virtio_gpu_conn_detect,
- .fill_modes = drm_helper_probe_single_connector_modes_nomerge,
+ .fill_modes = drm_helper_probe_single_connector_modes,
.destroy = virtio_gpu_conn_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -443,7 +431,7 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index)
if (IS_ERR(plane))
return PTR_ERR(plane);
drm_crtc_init_with_planes(dev, crtc, plane, NULL,
- &virtio_gpu_crtc_funcs);
+ &virtio_gpu_crtc_funcs, NULL);
drm_mode_crtc_set_gamma_size(crtc, 256);
drm_crtc_helper_add(crtc, &virtio_gpu_crtc_helper_funcs);
plane->crtc = crtc;
@@ -453,7 +441,7 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index)
drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs);
drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs,
- DRM_MODE_ENCODER_VIRTUAL);
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
drm_encoder_helper_add(encoder, &virtio_gpu_enc_helper_funcs);
encoder->possible_crtcs = 1 << index;
@@ -465,7 +453,7 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index)
static struct drm_framebuffer *
virtio_gpu_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj = NULL;
struct virtio_gpu_framebuffer *virtio_gpu_fb;
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 79f0abe69b64..8f486f4c7023 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -328,7 +328,7 @@ void virtio_gpu_dequeue_fence_func(struct work_struct *work);
/* virtio_gpu_display.c */
int virtio_gpu_framebuffer_init(struct drm_device *dev,
struct virtio_gpu_framebuffer *vgfb,
- struct drm_mode_fb_cmd2 *mode_cmd,
+ const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index 6a81e084593b..2242a80866a9 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -32,7 +32,6 @@
struct virtio_gpu_fbdev {
struct drm_fb_helper helper;
struct virtio_gpu_framebuffer vgfb;
- struct list_head fbdev_list;
struct virtio_gpu_device *vgdev;
struct delayed_work work;
};
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 06496a128162..4150873d432e 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -130,7 +130,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
static vq_callback_t *callbacks[] = {
virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack
};
- static const char *names[] = { "control", "cursor" };
+ static const char * const names[] = { "control", "cursor" };
struct virtio_gpu_device *vgdev;
/* this will expand later */
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index 4a74129c5708..572fb351feab 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -107,7 +107,7 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
&virtio_gpu_plane_funcs,
virtio_gpu_formats,
ARRAY_SIZE(virtio_gpu_formats),
- DRM_PLANE_TYPE_PRIMARY);
+ DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret)
goto err_plane_init;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
index 6377e8151000..67cebb23c940 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
@@ -247,7 +247,7 @@ static void __vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header)
{
struct vmw_cmdbuf_man *man = header->man;
- BUG_ON(!spin_is_locked(&man->lock));
+ lockdep_assert_held_once(&man->lock);
if (header->inline_space) {
vmw_cmdbuf_header_inline_free(header);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 9b4bb9e74d73..b221a8c40282 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -508,7 +508,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
}
-static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
+static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
.destroy = vmw_framebuffer_surface_destroy,
.dirty = vmw_framebuffer_surface_dirty,
};
@@ -685,7 +685,7 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
return ret;
}
-static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
+static const struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
.destroy = vmw_framebuffer_dmabuf_destroy,
.dirty = vmw_framebuffer_dmabuf_dirty,
};
@@ -763,21 +763,25 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev,
uint32_t format;
struct drm_vmw_size content_base_size;
struct vmw_resource *res;
+ unsigned int bytes_pp;
int ret;
switch (mode_cmd->depth) {
case 32:
case 24:
format = SVGA3D_X8R8G8B8;
+ bytes_pp = 4;
break;
case 16:
case 15:
format = SVGA3D_R5G6B5;
+ bytes_pp = 2;
break;
case 8:
format = SVGA3D_P8;
+ bytes_pp = 1;
break;
default:
@@ -785,7 +789,7 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev,
return -EINVAL;
}
- content_base_size.width = mode_cmd->width;
+ content_base_size.width = mode_cmd->pitch / bytes_pp;
content_base_size.height = mode_cmd->height;
content_base_size.depth = 1;
@@ -968,7 +972,7 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd2)
+ const struct drm_mode_fb_cmd2 *mode_cmd2)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
@@ -1369,14 +1373,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
return 0;
}
-void vmw_du_crtc_save(struct drm_crtc *crtc)
-{
-}
-
-void vmw_du_crtc_restore(struct drm_crtc *crtc)
-{
-}
-
void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
u16 *r, u16 *g, u16 *b,
uint32_t start, uint32_t size)
@@ -1398,14 +1394,6 @@ int vmw_du_connector_dpms(struct drm_connector *connector, int mode)
return 0;
}
-void vmw_du_connector_save(struct drm_connector *connector)
-{
-}
-
-void vmw_du_connector_restore(struct drm_connector *connector)
-{
-}
-
enum drm_connector_status
vmw_du_connector_detect(struct drm_connector *connector, bool force)
{
@@ -1592,7 +1580,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
drm_mode_probed_add(connector, mode);
}
- drm_mode_connector_list_update(connector, true);
+ drm_mode_connector_list_update(connector);
/* Move the prefered mode first, help apps pick the right mode. */
drm_mode_sort(&connector->modes);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 52caecb4502e..b6fa44fe8929 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -294,9 +294,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
return vmw_ldu_commit_list(dev_priv);
}
-static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
- .save = vmw_du_crtc_save,
- .restore = vmw_du_crtc_restore,
+static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
.cursor_set2 = vmw_du_crtc_cursor_set2,
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
@@ -314,7 +312,7 @@ static void vmw_ldu_encoder_destroy(struct drm_encoder *encoder)
vmw_ldu_destroy(vmw_encoder_to_ldu(encoder));
}
-static struct drm_encoder_funcs vmw_legacy_encoder_funcs = {
+static const struct drm_encoder_funcs vmw_legacy_encoder_funcs = {
.destroy = vmw_ldu_encoder_destroy,
};
@@ -327,10 +325,8 @@ static void vmw_ldu_connector_destroy(struct drm_connector *connector)
vmw_ldu_destroy(vmw_connector_to_ldu(connector));
}
-static struct drm_connector_funcs vmw_legacy_connector_funcs = {
+static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
.dpms = vmw_du_connector_dpms,
- .save = vmw_du_connector_save,
- .restore = vmw_du_connector_restore,
.detect = vmw_du_connector_detect,
.fill_modes = vmw_du_connector_fill_modes,
.set_property = vmw_du_connector_set_property,
@@ -367,7 +363,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
connector->status = vmw_du_connector_detect(connector, true);
drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
- DRM_MODE_ENCODER_VIRTUAL);
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
drm_mode_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << unit);
encoder->possible_clones = 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 13926ff192e3..db082bea8daf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -530,9 +530,7 @@ out_no_fence:
return ret;
}
-static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
- .save = vmw_du_crtc_save,
- .restore = vmw_du_crtc_restore,
+static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.cursor_set2 = vmw_du_crtc_cursor_set2,
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
@@ -550,7 +548,7 @@ static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
vmw_sou_destroy(vmw_encoder_to_sou(encoder));
}
-static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
+static const struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
.destroy = vmw_sou_encoder_destroy,
};
@@ -563,12 +561,8 @@ static void vmw_sou_connector_destroy(struct drm_connector *connector)
vmw_sou_destroy(vmw_connector_to_sou(connector));
}
-static struct drm_connector_funcs vmw_sou_connector_funcs = {
+static const struct drm_connector_funcs vmw_sou_connector_funcs = {
.dpms = vmw_du_connector_dpms,
- .save = vmw_du_connector_save,
- .restore = vmw_du_connector_restore,
- .detect = vmw_du_connector_detect,
- .fill_modes = vmw_du_connector_fill_modes,
.set_property = vmw_du_connector_set_property,
.destroy = vmw_sou_connector_destroy,
};
@@ -603,7 +597,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
connector->status = vmw_du_connector_detect(connector, true);
drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
- DRM_MODE_ENCODER_VIRTUAL);
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
drm_mode_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << unit);
encoder->possible_clones = 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index f823fc3efed7..4ef5ffd7189d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1040,9 +1040,7 @@ out_finish:
/*
* Screen Target CRTC dispatch table
*/
-static struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
- .save = vmw_du_crtc_save,
- .restore = vmw_du_crtc_restore,
+static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
.cursor_set2 = vmw_du_crtc_cursor_set2,
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
@@ -1072,7 +1070,7 @@ static void vmw_stdu_encoder_destroy(struct drm_encoder *encoder)
vmw_stdu_destroy(vmw_encoder_to_stdu(encoder));
}
-static struct drm_encoder_funcs vmw_stdu_encoder_funcs = {
+static const struct drm_encoder_funcs vmw_stdu_encoder_funcs = {
.destroy = vmw_stdu_encoder_destroy,
};
@@ -1099,10 +1097,8 @@ static void vmw_stdu_connector_destroy(struct drm_connector *connector)
-static struct drm_connector_funcs vmw_stdu_connector_funcs = {
+static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
.dpms = vmw_du_connector_dpms,
- .save = vmw_du_connector_save,
- .restore = vmw_du_connector_restore,
.detect = vmw_du_connector_detect,
.fill_modes = vmw_du_connector_fill_modes,
.set_property = vmw_du_connector_set_property,
@@ -1149,7 +1145,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
connector->status = vmw_du_connector_detect(connector, false);
drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs,
- DRM_MODE_ENCODER_VIRTUAL);
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
drm_mode_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << unit);
encoder->possible_clones = 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 7d620e82e000..c2a721a8cef9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -771,7 +771,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
}
srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets),
GFP_KERNEL);
- if (unlikely(srf->sizes == NULL)) {
+ if (unlikely(srf->offsets == NULL)) {
ret = -ENOMEM;
goto out_no_offsets;
}
@@ -815,11 +815,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
srf->sizes[0].height == 64 &&
srf->format == SVGA3D_A8R8G8B8) {
- srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL);
- /* clear the image */
- if (srf->snooper.image) {
- memset(srf->snooper.image, 0x00, 64 * 64 * 4);
- } else {
+ srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL);
+ if (!srf->snooper.image) {
DRM_ERROR("Failed to allocate cursor_image\n");
ret = -ENOMEM;
goto out_no_copy;
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
index c1189f004441..a1d9974cfcb5 100644
--- a/drivers/gpu/host1x/Makefile
+++ b/drivers/gpu/host1x/Makefile
@@ -10,6 +10,7 @@ host1x-y = \
mipi.o \
hw/host1x01.o \
hw/host1x02.o \
- hw/host1x04.o
+ hw/host1x04.o \
+ hw/host1x05.o
obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index 4a99c6416e6a..da462afcb225 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -538,6 +538,8 @@ EXPORT_SYMBOL(host1x_driver_register_full);
void host1x_driver_unregister(struct host1x_driver *driver)
{
+ driver_unregister(&driver->driver);
+
mutex_lock(&drivers_lock);
list_del_init(&driver->list);
mutex_unlock(&drivers_lock);
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 53d3d1d45b48..314bf3718cc7 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -35,6 +35,7 @@
#include "hw/host1x01.h"
#include "hw/host1x02.h"
#include "hw/host1x04.h"
+#include "hw/host1x05.h"
void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
{
@@ -87,7 +88,17 @@ static const struct host1x_info host1x04_info = {
.sync_offset = 0x2100,
};
+static const struct host1x_info host1x05_info = {
+ .nb_channels = 14,
+ .nb_pts = 192,
+ .nb_mlocks = 16,
+ .nb_bases = 64,
+ .init = host1x05_init,
+ .sync_offset = 0x2100,
+};
+
static struct of_device_id host1x_of_match[] = {
+ { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
{ .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
{ .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
{ .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
@@ -212,6 +223,11 @@ static struct platform_driver tegra_host1x_driver = {
.remove = host1x_remove,
};
+static struct platform_driver * const drivers[] = {
+ &tegra_host1x_driver,
+ &tegra_mipi_driver,
+};
+
static int __init tegra_host1x_init(void)
{
int err;
@@ -220,28 +236,17 @@ static int __init tegra_host1x_init(void)
if (err < 0)
return err;
- err = platform_driver_register(&tegra_host1x_driver);
- if (err < 0)
- goto unregister_bus;
-
- err = platform_driver_register(&tegra_mipi_driver);
+ err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (err < 0)
- goto unregister_host1x;
+ bus_unregister(&host1x_bus_type);
- return 0;
-
-unregister_host1x:
- platform_driver_unregister(&tegra_host1x_driver);
-unregister_bus:
- bus_unregister(&host1x_bus_type);
return err;
}
module_init(tegra_host1x_init);
static void __exit tegra_host1x_exit(void)
{
- platform_driver_unregister(&tegra_mipi_driver);
- platform_driver_unregister(&tegra_host1x_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
bus_unregister(&host1x_bus_type);
}
module_exit(tegra_host1x_exit);
diff --git a/drivers/gpu/host1x/hw/host1x05.c b/drivers/gpu/host1x/hw/host1x05.c
new file mode 100644
index 000000000000..047097ce3bad
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x05.c
@@ -0,0 +1,42 @@
+/*
+ * Host1x init for Tegra210 SoCs
+ *
+ * Copyright (c) 2015 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 "host1x05.h"
+#include "host1x05_hardware.h"
+
+/* include code */
+#include "cdma_hw.c"
+#include "channel_hw.c"
+#include "debug_hw.c"
+#include "intr_hw.c"
+#include "syncpt_hw.c"
+
+#include "../dev.h"
+
+int host1x05_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/host1x05.h b/drivers/gpu/host1x/hw/host1x05.h
new file mode 100644
index 000000000000..a306d9c05cd5
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x05.h
@@ -0,0 +1,26 @@
+/*
+ * Host1x init for Tegra210 SoCs
+ *
+ * Copyright (c) 2015 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_HOST1X05_H
+#define HOST1X_HOST1X05_H
+
+struct host1x;
+
+int host1x05_init(struct host1x *host);
+
+#endif
diff --git a/drivers/gpu/host1x/hw/host1x05_hardware.h b/drivers/gpu/host1x/hw/host1x05_hardware.h
new file mode 100644
index 000000000000..2937ebb6be11
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x05_hardware.h
@@ -0,0 +1,142 @@
+/*
+ * Tegra host1x Register Offsets for Tegra210
+ *
+ * Copyright (c) 2015 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_HOST1X05_HARDWARE_H
+#define __HOST1X_HOST1X05_HARDWARE_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#include "hw_host1x05_channel.h"
+#include "hw_host1x05_sync.h"
+#include "hw_host1x05_uclass.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
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_channel.h b/drivers/gpu/host1x/hw/hw_host1x05_channel.h
new file mode 100644
index 000000000000..fce6e2c1ff4c
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x05_channel.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015 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_HOST1X05_CHANNEL_H
+#define HOST1X_HW_HOST1X05_CHANNEL_H
+
+static inline u32 host1x_channel_fifostat_r(void)
+{
+ return 0x0;
+}
+#define HOST1X_CHANNEL_FIFOSTAT \
+ host1x_channel_fifostat_r()
+static inline u32 host1x_channel_fifostat_cfempty_v(u32 r)
+{
+ return (r >> 11) & 0x1;
+}
+#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \
+ host1x_channel_fifostat_cfempty_v(r)
+static inline u32 host1x_channel_dmastart_r(void)
+{
+ return 0x14;
+}
+#define HOST1X_CHANNEL_DMASTART \
+ host1x_channel_dmastart_r()
+static inline u32 host1x_channel_dmaput_r(void)
+{
+ return 0x18;
+}
+#define HOST1X_CHANNEL_DMAPUT \
+ host1x_channel_dmaput_r()
+static inline u32 host1x_channel_dmaget_r(void)
+{
+ return 0x1c;
+}
+#define HOST1X_CHANNEL_DMAGET \
+ host1x_channel_dmaget_r()
+static inline u32 host1x_channel_dmaend_r(void)
+{
+ return 0x20;
+}
+#define HOST1X_CHANNEL_DMAEND \
+ host1x_channel_dmaend_r()
+static inline u32 host1x_channel_dmactrl_r(void)
+{
+ return 0x24;
+}
+#define HOST1X_CHANNEL_DMACTRL \
+ host1x_channel_dmactrl_r()
+static inline u32 host1x_channel_dmactrl_dmastop(void)
+{
+ return 1 << 0;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP \
+ host1x_channel_dmactrl_dmastop()
+static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r)
+{
+ return (r >> 0) & 0x1;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \
+ host1x_channel_dmactrl_dmastop_v(r)
+static inline u32 host1x_channel_dmactrl_dmagetrst(void)
+{
+ return 1 << 1;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMAGETRST \
+ host1x_channel_dmactrl_dmagetrst()
+static inline u32 host1x_channel_dmactrl_dmainitget(void)
+{
+ return 1 << 2;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \
+ host1x_channel_dmactrl_dmainitget()
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_sync.h b/drivers/gpu/host1x/hw/hw_host1x05_sync.h
new file mode 100644
index 000000000000..ca10eee5045c
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x05_sync.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2015 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_HOST1X05_SYNC_H
+#define HOST1X_HW_HOST1X05_SYNC_H
+
+#define REGISTER_STRIDE 4
+
+static inline u32 host1x_sync_syncpt_r(unsigned int id)
+{
+ return 0xf80 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT(id) \
+ host1x_sync_syncpt_r(id)
+static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id)
+{
+ return 0xe80 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \
+ host1x_sync_syncpt_thresh_cpu0_int_status_r(id)
+static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id)
+{
+ return 0xf00 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \
+ host1x_sync_syncpt_thresh_int_disable_r(id)
+static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id)
+{
+ return 0xf20 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \
+ host1x_sync_syncpt_thresh_int_enable_cpu0_r(id)
+static inline u32 host1x_sync_cf_setup_r(unsigned int channel)
+{
+ return 0xc00 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CF_SETUP(channel) \
+ host1x_sync_cf_setup_r(channel)
+static inline u32 host1x_sync_cf_setup_base_v(u32 r)
+{
+ return (r >> 0) & 0x3ff;
+}
+#define HOST1X_SYNC_CF_SETUP_BASE_V(r) \
+ host1x_sync_cf_setup_base_v(r)
+static inline u32 host1x_sync_cf_setup_limit_v(u32 r)
+{
+ return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \
+ host1x_sync_cf_setup_limit_v(r)
+static inline u32 host1x_sync_cmdproc_stop_r(void)
+{
+ return 0xac;
+}
+#define HOST1X_SYNC_CMDPROC_STOP \
+ host1x_sync_cmdproc_stop_r()
+static inline u32 host1x_sync_ch_teardown_r(void)
+{
+ return 0xb0;
+}
+#define HOST1X_SYNC_CH_TEARDOWN \
+ host1x_sync_ch_teardown_r()
+static inline u32 host1x_sync_usec_clk_r(void)
+{
+ return 0x1a4;
+}
+#define HOST1X_SYNC_USEC_CLK \
+ host1x_sync_usec_clk_r()
+static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void)
+{
+ return 0x1a8;
+}
+#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \
+ host1x_sync_ctxsw_timeout_cfg_r()
+static inline u32 host1x_sync_ip_busy_timeout_r(void)
+{
+ return 0x1bc;
+}
+#define HOST1X_SYNC_IP_BUSY_TIMEOUT \
+ host1x_sync_ip_busy_timeout_r()
+static inline u32 host1x_sync_mlock_owner_r(unsigned int id)
+{
+ return 0x340 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_MLOCK_OWNER(id) \
+ host1x_sync_mlock_owner_r(id)
+static inline u32 host1x_sync_mlock_owner_chid_v(u32 r)
+{
+ return (r >> 8) & 0xf;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CHID_V(v) \
+ host1x_sync_mlock_owner_chid_v(v)
+static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r)
+{
+ return (r >> 1) & 0x1;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \
+ host1x_sync_mlock_owner_cpu_owns_v(r)
+static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r)
+{
+ return (r >> 0) & 0x1;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \
+ host1x_sync_mlock_owner_ch_owns_v(r)
+static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id)
+{
+ return 0x1380 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \
+ host1x_sync_syncpt_int_thresh_r(id)
+static inline u32 host1x_sync_syncpt_base_r(unsigned int id)
+{
+ return 0x600 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_BASE(id) \
+ host1x_sync_syncpt_base_r(id)
+static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id)
+{
+ return 0xf60 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \
+ host1x_sync_syncpt_cpu_incr_r(id)
+static inline u32 host1x_sync_cbread_r(unsigned int channel)
+{
+ return 0xc80 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CBREAD(channel) \
+ host1x_sync_cbread_r(channel)
+static inline u32 host1x_sync_cfpeek_ctrl_r(void)
+{
+ return 0x74c;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL \
+ host1x_sync_cfpeek_ctrl_r()
+static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v)
+{
+ return (v & 0x3ff) << 0;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \
+ host1x_sync_cfpeek_ctrl_addr_f(v)
+static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v)
+{
+ return (v & 0xf) << 16;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \
+ host1x_sync_cfpeek_ctrl_channr_f(v)
+static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v)
+{
+ return (v & 0x1) << 31;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \
+ host1x_sync_cfpeek_ctrl_ena_f(v)
+static inline u32 host1x_sync_cfpeek_read_r(void)
+{
+ return 0x750;
+}
+#define HOST1X_SYNC_CFPEEK_READ \
+ host1x_sync_cfpeek_read_r()
+static inline u32 host1x_sync_cfpeek_ptrs_r(void)
+{
+ return 0x754;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS \
+ host1x_sync_cfpeek_ptrs_r()
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r)
+{
+ return (r >> 0) & 0x3ff;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \
+ host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r)
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r)
+{
+ return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \
+ host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r)
+static inline u32 host1x_sync_cbstat_r(unsigned int channel)
+{
+ return 0xcc0 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CBSTAT(channel) \
+ host1x_sync_cbstat_r(channel)
+static inline u32 host1x_sync_cbstat_cboffset_v(u32 r)
+{
+ return (r >> 0) & 0xffff;
+}
+#define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \
+ host1x_sync_cbstat_cboffset_v(r)
+static inline u32 host1x_sync_cbstat_cbclass_v(u32 r)
+{
+ return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \
+ host1x_sync_cbstat_cbclass_v(r)
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_uclass.h b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h
new file mode 100644
index 000000000000..0c411da6bc41
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 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_HOST1X05_UCLASS_H
+#define HOST1X_HW_HOST1X05_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) << 8;
+}
+#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/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 7b95ed2fb49b..665ab9fd0e01 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -64,7 +64,7 @@
* for the inactive GPU.) Also, muxes are often used to cut power to the
* discrete GPU while it is not used.
*
- * DRM drivers register GPUs with vga_switcheroo, these are heretoforth called
+ * DRM drivers register GPUs with vga_switcheroo, these are henceforth called
* clients. The mux is called the handler. Muxless machines also register a
* handler to control the power state of the discrete GPU, its ->switchto
* callback is a no-op for obvious reasons. The discrete GPU is often equipped
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c6f7a694f67a..7e89288b1537 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -625,7 +625,7 @@ static void hid_close_report(struct hid_device *device)
static void hid_device_release(struct device *dev)
{
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
hid_close_report(hid);
kfree(hid->dev_rdesc);
@@ -1571,8 +1571,8 @@ read_report_descriptor(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct device *dev = kobj_to_dev(kobj);
+ struct hid_device *hdev = to_hid_device(dev);
if (off >= hdev->rsize)
return 0;
@@ -1589,7 +1589,7 @@ static ssize_t
show_country(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
return sprintf(buf, "%02x\n", hdev->country & 0xff);
}
@@ -1691,11 +1691,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
hid_warn(hdev,
"can't create sysfs country code attribute err: %d\n", ret);
- ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
- if (ret)
- hid_warn(hdev,
- "can't create sysfs report descriptor attribute err: %d\n", ret);
-
hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
buf, bus, hdev->version >> 8, hdev->version & 0xff,
type, hdev->name, hdev->phys);
@@ -1707,7 +1702,6 @@ EXPORT_SYMBOL_GPL(hid_connect);
void hid_disconnect(struct hid_device *hdev)
{
device_remove_file(&hdev->dev, &dev_attr_country);
- device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hdev);
if (hdev->claimed & HID_CLAIMED_HIDDEV)
@@ -1902,6 +1896,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
@@ -2076,7 +2071,7 @@ struct hid_dynid {
static ssize_t store_new_id(struct device_driver *drv, const char *buf,
size_t count)
{
- struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+ struct hid_driver *hdrv = to_hid_driver(drv);
struct hid_dynid *dynid;
__u32 bus, vendor, product;
unsigned long driver_data = 0;
@@ -2138,17 +2133,16 @@ static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
static int hid_bus_match(struct device *dev, struct device_driver *drv)
{
- struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_driver *hdrv = to_hid_driver(drv);
+ struct hid_device *hdev = to_hid_device(dev);
return hid_match_device(hdev, hdrv) != NULL;
}
static int hid_device_probe(struct device *dev)
{
- struct hid_driver *hdrv = container_of(dev->driver,
- struct hid_driver, driver);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_driver *hdrv = to_hid_driver(dev->driver);
+ struct hid_device *hdev = to_hid_device(dev);
const struct hid_device_id *id;
int ret = 0;
@@ -2190,7 +2184,7 @@ unlock_driver_lock:
static int hid_device_remove(struct device *dev)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct hid_driver *hdrv;
int ret = 0;
@@ -2223,12 +2217,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
char *buf)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- int len;
-
- len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
- hdev->bus, hdev->group, hdev->vendor, hdev->product);
- return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+ return scnprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+ hdev->bus, hdev->group, hdev->vendor, hdev->product);
}
static DEVICE_ATTR_RO(modalias);
@@ -2236,11 +2227,19 @@ static struct attribute *hid_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL,
};
-ATTRIBUTE_GROUPS(hid_dev);
+static struct bin_attribute *hid_dev_bin_attrs[] = {
+ &dev_bin_attr_report_desc,
+ NULL
+};
+static const struct attribute_group hid_dev_group = {
+ .attrs = hid_dev_attrs,
+ .bin_attrs = hid_dev_bin_attrs,
+};
+__ATTRIBUTE_GROUPS(hid_dev);
static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
hdev->bus, hdev->vendor, hdev->product))
@@ -2408,6 +2407,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454_V2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
@@ -2660,6 +2660,7 @@ struct hid_device *hid_allocate_device(void)
device_initialize(&hdev->dev);
hdev->dev.release = hid_device_release;
hdev->dev.bus = &hid_bus_type;
+ device_enable_async_suspend(&hdev->dev);
hid_close_report(hdev);
diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c
index bcefb9ebb026..58551964ce86 100644
--- a/drivers/hid/hid-corsair.c
+++ b/drivers/hid/hid-corsair.c
@@ -655,18 +655,7 @@ static struct hid_driver corsair_driver = {
.input_mapping = corsair_input_mapping,
};
-static int __init corsair_init(void)
-{
- return hid_register_driver(&corsair_driver);
-}
-
-static void corsair_exit(void)
-{
- hid_unregister_driver(&corsair_driver);
-}
-
-module_init(corsair_init);
-module_exit(corsair_exit);
+module_hid_driver(corsair_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Clement Vuchener");
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 7afc3fcc122c..086d8a507157 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -24,7 +24,7 @@
* http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/hid.h>
#include <linux/i2c.h>
#include <linux/module.h>
@@ -169,8 +169,7 @@ MODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask");
static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct cp2112_device *dev = container_of(chip, struct cp2112_device,
- gc);
+ struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 buf[5];
int ret;
@@ -198,8 +197,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct cp2112_device *dev = container_of(chip, struct cp2112_device,
- gc);
+ struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 buf[3];
int ret;
@@ -216,8 +214,7 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct cp2112_device *dev = container_of(chip, struct cp2112_device,
- gc);
+ struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 buf[2];
int ret;
@@ -235,8 +232,7 @@ static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
static int cp2112_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct cp2112_device *dev = container_of(chip, struct cp2112_device,
- gc);
+ struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 buf[5];
int ret;
@@ -807,7 +803,7 @@ static ssize_t name##_store(struct device *kdev, \
struct device_attribute *attr, const char *buf, \
size_t count) \
{ \
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+ struct hid_device *hdev = to_hid_device(kdev); \
struct cp2112_usb_config_report cfg; \
int ret = cp2112_get_usb_config(hdev, &cfg); \
if (ret) \
@@ -822,7 +818,7 @@ static ssize_t name##_store(struct device *kdev, \
static ssize_t name##_show(struct device *kdev, \
struct device_attribute *attr, char *buf) \
{ \
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+ struct hid_device *hdev = to_hid_device(kdev); \
struct cp2112_usb_config_report cfg; \
int ret = cp2112_get_usb_config(hdev, &cfg); \
if (ret) \
@@ -887,7 +883,7 @@ static ssize_t pstr_store(struct device *kdev,
struct device_attribute *kattr, const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(kdev);
struct cp2112_pstring_attribute *attr =
container_of(kattr, struct cp2112_pstring_attribute, attr);
struct cp2112_string_report report;
@@ -918,7 +914,7 @@ static ssize_t pstr_store(struct device *kdev,
static ssize_t pstr_show(struct device *kdev,
struct device_attribute *kattr, char *buf)
{
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(kdev);
struct cp2112_pstring_attribute *attr =
container_of(kattr, struct cp2112_pstring_attribute, attr);
struct cp2112_string_report report;
@@ -1104,9 +1100,9 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->gc.base = -1;
dev->gc.ngpio = 8;
dev->gc.can_sleep = 1;
- dev->gc.dev = &hdev->dev;
+ dev->gc.parent = &hdev->dev;
- ret = gpiochip_add(&dev->gc);
+ ret = gpiochip_add_data(&dev->gc, dev);
if (ret < 0) {
hid_err(hdev, "error registering gpio chip\n");
goto err_free_i2c;
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 2886b645ced7..acfb522a432a 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -659,13 +659,13 @@ EXPORT_SYMBOL_GPL(hid_dump_device);
/* enqueue string to 'events' ring buffer */
void hid_debug_event(struct hid_device *hdev, char *buf)
{
- int i;
+ unsigned i;
struct hid_debug_list *list;
unsigned long flags;
spin_lock_irqsave(&hdev->debug_list_lock, flags);
list_for_each_entry(list, &hdev->debug_list, node) {
- for (i = 0; i < strlen(buf); i++)
+ for (i = 0; buf[i]; i++)
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
buf[i];
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c
index 0d6f135e266c..a298fbd8db6b 100644
--- a/drivers/hid/hid-gt683r.c
+++ b/drivers/hid/hid-gt683r.c
@@ -70,7 +70,7 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev,
{
int i;
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct gt683r_led *led = hid_get_drvdata(hdev);
for (i = 0; i < GT683R_LED_COUNT; i++) {
@@ -89,8 +89,7 @@ static ssize_t mode_show(struct device *dev,
char *buf)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev->parent,
- struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev->parent);
struct gt683r_led *led = hid_get_drvdata(hdev);
if (led->mode == GT683R_LED_NORMAL)
@@ -108,8 +107,7 @@ static ssize_t mode_store(struct device *dev,
const char *buf, size_t count)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev->parent,
- struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev->parent);
struct gt683r_led *led = hid_get_drvdata(hdev);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 8b78a7f1f779..b6ff6e78ac54 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -510,6 +510,7 @@
#define USB_VENDOR_ID_ITE 0x048d
#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386
#define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350
+#define USB_DEVICE_ID_ITE_LENOVO_YOGA900 0x8396
#define USB_VENDOR_ID_JABRA 0x0b0e
#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
@@ -615,6 +616,7 @@
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f
+#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
@@ -664,6 +666,7 @@
#define USB_DEVICE_ID_PICOLCD 0xc002
#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002
#define USB_DEVICE_ID_PICK16F1454 0x0042
+#define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7
#define USB_VENDOR_ID_MICROSOFT 0x045e
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 2ba6bf69b7d0..bcfaf32d9e5e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -303,6 +303,7 @@ static enum power_supply_property hidinput_battery_props[] = {
#define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
+#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -320,6 +321,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
+ USB_DEVICE_ID_ELECOM_BM084),
+ HID_BATTERY_QUIRK_IGNORE },
{}
};
@@ -408,6 +412,14 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (dev->battery != NULL)
goto out; /* already initialized? */
+ quirks = find_battery_quirk(dev);
+
+ hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
+ dev->bus, dev->vendor, dev->product, dev->version, quirks);
+
+ if (quirks & HID_BATTERY_QUIRK_IGNORE)
+ goto out;
+
psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
if (psy_desc == NULL)
goto out;
@@ -424,11 +436,6 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
psy_desc->use_for_apm = 0;
psy_desc->get_property = hidinput_get_battery_property;
- quirks = find_battery_quirk(dev);
-
- hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
- dev->bus, dev->vendor, dev->product, dev->version, quirks);
-
min = field->logical_minimum;
max = field->logical_maximum;
@@ -960,6 +967,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
case HID_UP_LOGIVENDOR:
+ /* intentional fallback */
+ case HID_UP_LOGIVENDOR2:
+ /* intentional fallback */
+ case HID_UP_LOGIVENDOR3:
goto ignore;
case HID_UP_PID:
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 8979f1fd5208..0125e356bd8d 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -220,7 +220,7 @@ static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock);
@@ -231,7 +231,7 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
int value;
@@ -250,7 +250,7 @@ static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -262,7 +262,7 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
int value;
@@ -387,7 +387,7 @@ static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
@@ -398,7 +398,7 @@ static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -417,7 +417,7 @@ static ssize_t attr_dragging_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
@@ -428,7 +428,7 @@ static ssize_t attr_dragging_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -447,7 +447,7 @@ static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
@@ -458,7 +458,7 @@ static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -477,7 +477,7 @@ static ssize_t attr_select_right_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
@@ -488,7 +488,7 @@ static ssize_t attr_select_right_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -507,7 +507,7 @@ static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -519,7 +519,7 @@ static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -536,7 +536,7 @@ static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -548,7 +548,7 @@ static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -609,7 +609,7 @@ static enum led_brightness lenovo_led_brightness_get_tpkbd(
struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int led_nr = 0;
@@ -625,7 +625,7 @@ static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
struct hid_report *report;
int led_nr = 0;
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index fbddcb37ae98..af3a8ec8a746 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -33,8 +33,6 @@
#include "hid-lg4ff.h"
#include "hid-ids.h"
-#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
-
#define LG4FF_MMODE_IS_MULTIMODE 0
#define LG4FF_MMODE_SWITCHED 1
#define LG4FF_MMODE_NOT_MULTIMODE 2
@@ -1020,7 +1018,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct lg_drv_data *drv_data = hid_get_drvdata(hid);
struct lg4ff_device_entry *entry;
int i, state = 0;
@@ -1055,7 +1053,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct lg_drv_data *drv_data = hid_get_drvdata(hid);
struct lg4ff_device_entry *entry;
int i, value = 0;
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 5fd97860aec4..bd2ab476c65e 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -40,18 +40,22 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11
+#define REPORT_ID_HIDPP_VERY_LONG 0x12
#define HIDPP_REPORT_SHORT_LENGTH 7
#define HIDPP_REPORT_LONG_LENGTH 20
+#define HIDPP_REPORT_VERY_LONG_LENGTH 64
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
#define HIDPP_QUIRK_CLASS_K400 BIT(2)
+#define HIDPP_QUIRK_CLASS_G920 BIT(3)
/* bits 2..20 are reserved for classes */
#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21)
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
+#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
#define HIDPP_QUIRK_DELAYED_INIT (HIDPP_QUIRK_NO_HIDINPUT | \
HIDPP_QUIRK_CONNECT_EVENTS)
@@ -81,13 +85,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
struct fap {
u8 feature_index;
u8 funcindex_clientid;
- u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+ u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
struct rap {
u8 sub_id;
u8 reg_address;
- u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+ u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
struct hidpp_report {
@@ -144,8 +148,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
static int __hidpp_send_report(struct hid_device *hdev,
struct hidpp_report *hidpp_report)
{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
int fields_count, ret;
+ hidpp = hid_get_drvdata(hdev);
+
switch (hidpp_report->report_id) {
case REPORT_ID_HIDPP_SHORT:
fields_count = HIDPP_REPORT_SHORT_LENGTH;
@@ -153,6 +160,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
case REPORT_ID_HIDPP_LONG:
fields_count = HIDPP_REPORT_LONG_LENGTH;
break;
+ case REPORT_ID_HIDPP_VERY_LONG:
+ fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
+ break;
default:
return -ENODEV;
}
@@ -163,9 +173,13 @@ static int __hidpp_send_report(struct hid_device *hdev,
*/
hidpp_report->device_index = 0xff;
- ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
- (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
- HID_REQ_SET_REPORT);
+ if (hidpp->quirks & HIDPP_QUIRK_FORCE_OUTPUT_REPORTS) {
+ ret = hid_hw_output_report(hdev, (u8 *)hidpp_report, fields_count);
+ } else {
+ ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
+ (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
+ HID_REQ_SET_REPORT);
+ }
return ret == fields_count ? 0 : -1;
}
@@ -217,8 +231,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
goto exit;
}
- if (response->report_id == REPORT_ID_HIDPP_LONG &&
- response->fap.feature_index == HIDPP20_ERROR) {
+ if ((response->report_id == REPORT_ID_HIDPP_LONG ||
+ response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
+ response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1];
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit;
@@ -243,7 +258,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
if (!message)
return -ENOMEM;
- message->report_id = REPORT_ID_HIDPP_LONG;
+
+ if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
+ message->report_id = REPORT_ID_HIDPP_VERY_LONG;
+ else
+ message->report_id = REPORT_ID_HIDPP_LONG;
message->fap.feature_index = feat_index;
message->fap.funcindex_clientid = funcindex_clientid;
memcpy(&message->fap.params, params, param_count);
@@ -258,13 +277,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
struct hidpp_report *response)
{
struct hidpp_report *message;
- int ret;
+ int ret, max_count;
- if ((report_id != REPORT_ID_HIDPP_SHORT) &&
- (report_id != REPORT_ID_HIDPP_LONG))
+ switch (report_id) {
+ case REPORT_ID_HIDPP_SHORT:
+ max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_LONG:
+ max_count = HIDPP_REPORT_LONG_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_VERY_LONG:
+ max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+ break;
+ default:
return -EINVAL;
+ }
- if (param_count > sizeof(message->rap.params))
+ if (param_count > max_count)
return -EINVAL;
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
@@ -508,10 +537,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
if (ret)
return ret;
- if (response.report_id == REPORT_ID_HIDPP_LONG)
+ switch (response.report_id) {
+ case REPORT_ID_HIDPP_VERY_LONG:
+ count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_LONG:
count = HIDPP_REPORT_LONG_LENGTH - 4;
- else
+ break;
+ case REPORT_ID_HIDPP_SHORT:
count = HIDPP_REPORT_SHORT_LENGTH - 4;
+ break;
+ default:
+ return -EPROTO;
+ }
if (len_buf < count)
count = len_buf;
@@ -1257,6 +1295,131 @@ static int k400_connect(struct hid_device *hdev, bool connected)
return k400_disable_tap_to_click(hidpp);
}
+/* ------------------------------------------------------------------------- */
+/* Logitech G920 Driving Force Racing Wheel for Xbox One */
+/* ------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123
+
+/* Using session ID = 1 */
+#define CMD_G920_FORCE_GET_APERTURE 0x51
+#define CMD_G920_FORCE_SET_APERTURE 0x61
+
+struct g920_private_data {
+ u8 force_feature;
+ u16 range;
+};
+
+static ssize_t g920_range_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hid);
+ struct g920_private_data *pdata;
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->range);
+}
+
+static ssize_t g920_range_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hid);
+ struct g920_private_data *pdata;
+ struct hidpp_report response;
+ u8 params[2];
+ int ret;
+ u16 range = simple_strtoul(buf, NULL, 10);
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ if (range < 180)
+ range = 180;
+ else if (range > 900)
+ range = 900;
+
+ params[0] = range >> 8;
+ params[1] = range & 0x00FF;
+
+ ret = hidpp_send_fap_command_sync(hidpp, pdata->force_feature,
+ CMD_G920_FORCE_SET_APERTURE, params, 2, &response);
+ if (ret)
+ return ret;
+
+ pdata->range = range;
+ return count;
+}
+
+static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, g920_range_show, g920_range_store);
+
+static int g920_allocate(struct hid_device *hdev)
+{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ struct g920_private_data *pdata;
+
+ pdata = devm_kzalloc(&hdev->dev, sizeof(struct g920_private_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ hidpp->private_data = pdata;
+
+ return 0;
+}
+
+static int g920_get_config(struct hidpp_device *hidpp)
+{
+ struct g920_private_data *pdata = hidpp->private_data;
+ struct hidpp_report response;
+ u8 feature_type;
+ u8 feature_index;
+ int ret;
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hidpp->hid_dev, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ /* Find feature and store for later use */
+ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
+ &feature_index, &feature_type);
+ if (ret)
+ return ret;
+
+ pdata->force_feature = feature_index;
+
+ /* Read current Range */
+ ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_G920_FORCE_GET_APERTURE, NULL, 0, &response);
+ if (ret > 0) {
+ hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+ __func__, ret);
+ return -EPROTO;
+ }
+ if (ret)
+ return ret;
+
+ pdata->range = get_unaligned_be16(&response.fap.params[0]);
+
+ /* Create sysfs interface */
+ ret = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
+ if (ret)
+ hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d\n", ret);
+
+ return 0;
+}
+
/* -------------------------------------------------------------------------- */
/* Generic HID++ devices */
/* -------------------------------------------------------------------------- */
@@ -1276,6 +1439,25 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
+static int hidpp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+
+ /* Ensure that Logitech G920 is not given a default fuzz/flat value */
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ if (usage->type == EV_ABS && (usage->code == ABS_X ||
+ usage->code == ABS_Y || usage->code == ABS_Z ||
+ usage->code == ABS_RZ)) {
+ field->application = HID_GD_MULTIAXIS;
+ }
+ }
+
+ return 0;
+}
+
+
static void hidpp_populate_input(struct hidpp_device *hidpp,
struct input_dev *input, bool origin_is_hid_core)
{
@@ -1347,6 +1529,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
/* Generic HID++ processing. */
switch (data[0]) {
+ case REPORT_ID_HIDPP_VERY_LONG:
+ if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
+ hid_err(hdev, "received hid++ report of bad size (%d)",
+ size);
+ return 1;
+ }
+ ret = hidpp_raw_hidpp_event(hidpp, data, size);
+ break;
case REPORT_ID_HIDPP_LONG:
if (size != HIDPP_REPORT_LONG_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)",
@@ -1393,10 +1583,12 @@ static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
else
name = hidpp_get_device_name(hidpp);
- if (!name)
+ if (!name) {
hid_err(hdev, "unable to retrieve the name of the device");
- else
+ } else {
+ dbg_hid("HID++: Got name: %s\n", name);
snprintf(hdev->name, sizeof(hdev->name), "%s", name);
+ }
kfree(name);
}
@@ -1547,6 +1739,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = k400_allocate(hdev);
if (ret)
goto allocate_fail;
+ } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ ret = g920_allocate(hdev);
+ if (ret)
+ goto allocate_fail;
}
INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1559,6 +1755,25 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto hid_parse_fail;
}
+ if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
+ connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto hid_hw_start_fail;
+ }
+ ret = hid_hw_open(hdev);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
+ __func__, ret);
+ hid_hw_stop(hdev);
+ goto hid_hw_start_fail;
+ }
+ }
+
+
/* Allow incoming packets */
hid_device_io_start(hdev);
@@ -1567,8 +1782,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!connected) {
ret = -ENODEV;
hid_err(hdev, "Device not connected");
- hid_device_io_stop(hdev);
- goto hid_parse_fail;
+ goto hid_hw_open_failed;
}
hid_info(hdev, "HID++ %u.%u device connected.\n",
@@ -1581,19 +1795,22 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
ret = wtp_get_config(hidpp);
if (ret)
- goto hid_parse_fail;
+ goto hid_hw_open_failed;
+ } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+ ret = g920_get_config(hidpp);
+ if (ret)
+ goto hid_hw_open_failed;
}
/* Block incoming packets */
hid_device_io_stop(hdev);
- if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
- connect_mask &= ~HID_CONNECT_HIDINPUT;
-
- ret = hid_hw_start(hdev, connect_mask);
- if (ret) {
- hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
- goto hid_hw_start_fail;
+ if (!(hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
+ goto hid_hw_start_fail;
+ }
}
if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
@@ -1605,6 +1822,13 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
+hid_hw_open_failed:
+ hid_device_io_stop(hdev);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ device_remove_file(&hdev->dev, &dev_attr_range);
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+ }
hid_hw_start_fail:
hid_parse_fail:
cancel_work_sync(&hidpp->work);
@@ -1618,9 +1842,13 @@ static void hidpp_remove(struct hid_device *hdev)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ device_remove_file(&hdev->dev, &dev_attr_range);
+ hid_hw_close(hdev);
+ }
+ hid_hw_stop(hdev);
cancel_work_sync(&hidpp->work);
mutex_destroy(&hidpp->send_mutex);
- hid_hw_stop(hdev);
}
static const struct hid_device_id hidpp_devices[] = {
@@ -1648,6 +1876,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
+ .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
{}
};
@@ -1661,6 +1892,7 @@ static struct hid_driver hidpp_driver = {
.raw_event = hidpp_raw_event,
.input_configured = hidpp_input_configured,
.input_mapping = hidpp_input_mapping,
+ .input_mapped = hidpp_input_mapped,
};
module_hid_driver(hidpp_driver);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 3d664d01305e..296d4991560e 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -272,7 +272,7 @@ static ssize_t mt_show_quirks(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct mt_device *td = hid_get_drvdata(hdev);
return sprintf(buf, "%u\n", td->mtclass.quirks);
@@ -282,7 +282,7 @@ static ssize_t mt_set_quirks(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct mt_device *td = hid_get_drvdata(hdev);
unsigned long val;
@@ -357,8 +357,19 @@ static void mt_feature_mapping(struct hid_device *hdev,
break;
}
- td->inputmode = field->report->id;
- td->inputmode_index = usage->usage_index;
+ if (td->inputmode < 0) {
+ td->inputmode = field->report->id;
+ td->inputmode_index = usage->usage_index;
+ } else {
+ /*
+ * Some elan panels wrongly declare 2 input mode
+ * features, and silently ignore when we set the
+ * value in the second field. Skip the second feature
+ * and hope for the best.
+ */
+ dev_info(&hdev->dev,
+ "Ignoring the extra HID_DG_INPUTMODE\n");
+ }
break;
case HID_DG_CONTACTMAX:
@@ -486,6 +497,11 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
mt_store_field(usage, td, hi);
return 1;
case HID_DG_CONFIDENCE:
+ if (cls->name == MT_CLS_WIN_8 &&
+ field->application == HID_DG_TOUCHPAD) {
+ cls->quirks &= ~MT_QUIRK_ALWAYS_VALID;
+ cls->quirks |= MT_QUIRK_VALID_IS_CONFIDENCE;
+ }
mt_store_field(usage, td, hi);
return 1;
case HID_DG_TIPSWITCH:
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 756d1ef9bd99..1b0084d4af2e 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -173,7 +173,7 @@ static ssize_t show_phys_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_physical_width);
@@ -185,7 +185,7 @@ static ssize_t show_phys_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_physical_height);
@@ -197,7 +197,7 @@ static ssize_t show_log_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_logical_width);
@@ -209,7 +209,7 @@ static ssize_t show_log_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_logical_height);
@@ -221,7 +221,7 @@ static ssize_t show_min_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->min_width *
@@ -233,7 +233,7 @@ static ssize_t set_min_width(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -256,7 +256,7 @@ static ssize_t show_min_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->min_height *
@@ -268,7 +268,7 @@ static ssize_t set_min_height(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -292,7 +292,7 @@ static ssize_t show_activate_slack(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->activate_slack);
@@ -302,7 +302,7 @@ static ssize_t set_activate_slack(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -325,7 +325,7 @@ static ssize_t show_activation_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->activation_width *
@@ -337,7 +337,7 @@ static ssize_t set_activation_width(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -361,7 +361,7 @@ static ssize_t show_activation_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->activation_height *
@@ -373,7 +373,7 @@ static ssize_t set_activation_height(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -397,7 +397,7 @@ static ssize_t show_deactivate_slack(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", -nd->deactivate_slack);
@@ -407,7 +407,7 @@ static ssize_t set_deactivate_slack(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c
index e994f9c29012..a802b4f49c7b 100644
--- a/drivers/hid/hid-picolcd_leds.c
+++ b/drivers/hid/hid-picolcd_leds.c
@@ -66,7 +66,7 @@ static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
int i, state = 0;
dev = led_cdev->dev->parent;
- hdev = container_of(dev, struct hid_device, dev);
+ hdev = to_hid_device(dev);
data = hid_get_drvdata(hdev);
if (!data)
return;
@@ -93,7 +93,7 @@ static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_c
int i, value = 0;
dev = led_cdev->dev->parent;
- hdev = container_of(dev, struct hid_device, dev);
+ hdev = to_hid_device(dev);
data = hid_get_drvdata(hdev);
for (i = 0; i < 8; i++)
if (led_cdev == data->led[i]) {
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 3a207c0ac0e3..f095bf8a3aa9 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -103,7 +103,7 @@ MODULE_PARM_DESC(enable, "Enable for the PC-MIDI virtual audio driver");
static ssize_t show_channel(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel);
@@ -116,7 +116,7 @@ static ssize_t show_channel(struct device *dev,
static ssize_t store_channel(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
unsigned channel = 0;
@@ -140,7 +140,7 @@ static struct device_attribute *sysfs_device_attr_channel = {
static ssize_t show_sustain(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain);
@@ -153,7 +153,7 @@ static ssize_t show_sustain(struct device *dev,
static ssize_t store_sustain(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
unsigned sustain = 0;
@@ -179,7 +179,7 @@ static struct device_attribute *sysfs_device_attr_sustain = {
static ssize_t show_octave(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave);
@@ -192,7 +192,7 @@ static ssize_t show_octave(struct device *dev,
static ssize_t store_octave(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
int octave = 0;
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index 1948208fe038..329c5d1270f9 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -191,8 +191,7 @@ static ssize_t arvo_sysfs_write(struct file *fp,
struct kobject *kobj, void const *buf,
loff_t off, size_t count, size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -211,8 +210,7 @@ static ssize_t arvo_sysfs_read(struct file *fp,
struct kobject *kobj, void *buf, loff_t off,
size_t count, size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c
index 02e28e9f4ea7..8155ac5fede2 100644
--- a/drivers/hid/hid-roccat-common.c
+++ b/drivers/hid/hid-roccat-common.c
@@ -134,8 +134,7 @@ ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -158,8 +157,7 @@ ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index bc62ed91e451..02db537f8f3e 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -121,8 +121,7 @@ static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -144,8 +143,7 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index c29265055ac1..bf4675a27396 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -269,8 +269,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_settings))
@@ -294,8 +293,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0, difference, old_profile;
@@ -332,8 +330,7 @@ static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,
static ssize_t kone_sysfs_read_profilex(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_profile))
@@ -353,8 +350,7 @@ static ssize_t kone_sysfs_read_profilex(struct file *fp,
static ssize_t kone_sysfs_write_profilex(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
struct kone_profile *profile;
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 5e99fcdc71b9..09e8fc72aa1d 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -87,8 +87,7 @@ static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -113,8 +112,7 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -193,8 +191,7 @@ static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -212,8 +209,7 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index 966047711fbf..43617fb28b87 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -128,8 +128,7 @@ static ssize_t kovaplus_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -154,8 +153,7 @@ static ssize_t kovaplus_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -221,8 +219,7 @@ static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -240,8 +237,7 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c
index 65e2e76bf2fe..ac1a7313e259 100644
--- a/drivers/hid/hid-roccat-lua.c
+++ b/drivers/hid/hid-roccat-lua.c
@@ -30,7 +30,7 @@ static ssize_t lua_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -52,7 +52,7 @@ static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 47d7e74231e5..b30aa7b82bf8 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -90,8 +90,7 @@ static ssize_t pyra_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -116,8 +115,7 @@ static ssize_t pyra_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -191,8 +189,7 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -210,8 +207,7 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -248,8 +244,7 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 92870cdb52d9..3d5ba5b51af3 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -218,7 +218,8 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
goto done_proc;
}
- remaining_bytes = do_div(buffer_size, sizeof(__s32));
+ remaining_bytes = buffer_size % sizeof(__s32);
+ buffer_size = buffer_size / sizeof(__s32);
if (buffer_size) {
for (i = 0; i < buffer_size; ++i) {
hid_set_field(report->field[field_index], i,
@@ -794,6 +795,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
USB_DEVICE_ID_ITE_LENOVO_YOGA2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
+ USB_DEVICE_ID_ITE_LENOVO_YOGA900),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
HID_ANY_ID) },
{ }
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 774cd2210566..9b8db0e0ef1c 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1028,6 +1028,7 @@ struct sony_sc {
struct led_classdev *leds[MAX_LEDS];
unsigned long quirks;
struct work_struct state_worker;
+ void(*send_output_report)(struct sony_sc*);
struct power_supply *battery;
struct power_supply_desc battery_desc;
int device_id;
@@ -1044,6 +1045,7 @@ struct sony_sc {
__u8 battery_charging;
__u8 battery_capacity;
__u8 led_state[MAX_LEDS];
+ __u8 resume_led_state[MAX_LEDS];
__u8 led_delay_on[MAX_LEDS];
__u8 led_delay_off[MAX_LEDS];
__u8 led_count;
@@ -1137,11 +1139,11 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* the gyroscope values to corresponding axes so we need a
* modified one.
*/
- if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && *rsize == 467) {
+ if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n");
rdesc = dualshock4_usb_rdesc;
*rsize = sizeof(dualshock4_usb_rdesc);
- } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && *rsize == 357) {
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n");
rdesc = dualshock4_bt_rdesc;
*rsize = sizeof(dualshock4_bt_rdesc);
@@ -1549,7 +1551,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
enum led_brightness value)
{
struct device *dev = led->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *drv_data;
int n;
@@ -1591,7 +1593,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
{
struct device *dev = led->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *drv_data;
int n;
@@ -1614,7 +1616,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
unsigned long *delay_off)
{
struct device *dev = led->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
__u8 new_on, new_off;
@@ -1789,7 +1791,7 @@ error_leds:
return ret;
}
-static void sixaxis_state_worker(struct work_struct *work)
+static void sixaxis_send_output_report(struct sony_sc *sc)
{
static const union sixaxis_output_report_01 default_report = {
.buf = {
@@ -1803,7 +1805,6 @@ static void sixaxis_state_worker(struct work_struct *work)
0x00, 0x00, 0x00, 0x00, 0x00
}
};
- struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct sixaxis_output_report *report =
(struct sixaxis_output_report *)sc->output_report_dmabuf;
int n;
@@ -1846,9 +1847,8 @@ static void sixaxis_state_worker(struct work_struct *work)
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
-static void dualshock4_state_worker(struct work_struct *work)
+static void dualshock4_send_output_report(struct sony_sc *sc)
{
- struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct hid_device *hdev = sc->hdev;
__u8 *buf = sc->output_report_dmabuf;
int offset;
@@ -1893,9 +1893,8 @@ static void dualshock4_state_worker(struct work_struct *work)
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
-static void motion_state_worker(struct work_struct *work)
+static void motion_send_output_report(struct sony_sc *sc)
{
- struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct hid_device *hdev = sc->hdev;
struct motion_output_report_02 *report =
(struct motion_output_report_02 *)sc->output_report_dmabuf;
@@ -1914,6 +1913,18 @@ static void motion_state_worker(struct work_struct *work)
hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE);
}
+static inline void sony_send_output_report(struct sony_sc *sc)
+{
+ if (sc->send_output_report)
+ sc->send_output_report(sc);
+}
+
+static void sony_state_worker(struct work_struct *work)
+{
+ struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
+ sc->send_output_report(sc);
+}
+
static int sony_allocate_output_report(struct sony_sc *sc)
{
if ((sc->quirks & SIXAXIS_CONTROLLER) ||
@@ -2241,11 +2252,13 @@ static void sony_release_device_id(struct sony_sc *sc)
}
}
-static inline void sony_init_work(struct sony_sc *sc,
- void (*worker)(struct work_struct *))
+static inline void sony_init_output_report(struct sony_sc *sc,
+ void(*send_output_report)(struct sony_sc*))
{
+ sc->send_output_report = send_output_report;
+
if (!sc->worker_initialized)
- INIT_WORK(&sc->state_worker, worker);
+ INIT_WORK(&sc->state_worker, sony_state_worker);
sc->worker_initialized = 1;
}
@@ -2319,7 +2332,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
ret = sixaxis_set_operational_usb(hdev);
- sony_init_work(sc, sixaxis_state_worker);
+ sony_init_output_report(sc, sixaxis_send_output_report);
} else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) ||
(sc->quirks & NAVIGATION_CONTROLLER_BT)) {
/*
@@ -2328,7 +2341,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
ret = sixaxis_set_operational_bt(hdev);
- sony_init_work(sc, sixaxis_state_worker);
+ sony_init_output_report(sc, sixaxis_send_output_report);
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
/*
@@ -2343,9 +2356,9 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
- sony_init_work(sc, dualshock4_state_worker);
+ sony_init_output_report(sc, dualshock4_send_output_report);
} else if (sc->quirks & MOTION_CONTROLLER) {
- sony_init_work(sc, motion_state_worker);
+ sony_init_output_report(sc, motion_send_output_report);
} else {
ret = 0;
}
@@ -2421,6 +2434,56 @@ static void sony_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
}
+#ifdef CONFIG_PM
+
+static int sony_suspend(struct hid_device *hdev, pm_message_t message)
+{
+ /*
+ * On suspend save the current LED state,
+ * stop running force-feedback and blank the LEDS.
+ */
+ if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+#ifdef CONFIG_SONY_FF
+ sc->left = sc->right = 0;
+#endif
+
+ memcpy(sc->resume_led_state, sc->led_state,
+ sizeof(sc->resume_led_state));
+ memset(sc->led_state, 0, sizeof(sc->led_state));
+
+ sony_send_output_report(sc);
+ }
+
+ return 0;
+}
+
+static int sony_resume(struct hid_device *hdev)
+{
+ /* Restore the state of controller LEDs on resume */
+ if (SONY_LED_SUPPORT) {
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+ memcpy(sc->led_state, sc->resume_led_state,
+ sizeof(sc->led_state));
+
+ /*
+ * The Sixaxis and navigation controllers on USB need to be
+ * reinitialized on resume or they won't behave properly.
+ */
+ if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
+ (sc->quirks & NAVIGATION_CONTROLLER_USB))
+ sixaxis_set_operational_usb(sc->hdev);
+
+ sony_set_leds(sc);
+ }
+
+ return 0;
+}
+
+#endif
+
static const struct hid_device_id sony_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB },
@@ -2470,7 +2533,13 @@ static struct hid_driver sony_driver = {
.probe = sony_probe,
.remove = sony_remove,
.report_fixup = sony_report_fixup,
- .raw_event = sony_raw_event
+ .raw_event = sony_raw_event,
+
+#ifdef CONFIG_PM
+ .suspend = sony_suspend,
+ .resume = sony_resume,
+ .reset_resume = sony_resume,
+#endif
};
static int __init sony_init(void)
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
index 3edd4ac36494..ec18768b124a 100644
--- a/drivers/hid/hid-steelseries.c
+++ b/drivers/hid/hid-steelseries.c
@@ -141,7 +141,7 @@ static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cd
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
if (!drv_data) {
@@ -160,7 +160,7 @@ static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cd
static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data;
drv_data = hid_get_drvdata(hid);
@@ -177,7 +177,7 @@ static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
int i, state = 0;
@@ -205,7 +205,7 @@ static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data;
int i, value = 0;
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 05e23c417d50..4390eee2ce84 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -296,14 +296,12 @@ static const struct wiimod_ops wiimod_battery = {
static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
{
- struct wiimote_data *wdata;
struct device *dev = led_dev->dev->parent;
+ struct wiimote_data *wdata = dev_to_wii(dev);
int i;
unsigned long flags;
bool value = false;
- wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev) {
spin_lock_irqsave(&wdata->state.lock, flags);
@@ -319,14 +317,12 @@ static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
static void wiimod_led_set(struct led_classdev *led_dev,
enum led_brightness value)
{
- struct wiimote_data *wdata;
struct device *dev = led_dev->dev->parent;
+ struct wiimote_data *wdata = dev_to_wii(dev);
int i;
unsigned long flags;
__u8 state, flag;
- wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev) {
flag = WIIPROTO_FLAG_LED(i + 1);
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 875694d43e4d..510ca77fe14e 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -256,8 +256,7 @@ enum wiiproto_reqs {
WIIPROTO_REQ_MAX
};
-#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
- dev))
+#define dev_to_wii(pdev) hid_get_drvdata(to_hid_device(pdev))
void __wiimote_schedule(struct wiimote_data *wdata);
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 10bd8e6e4c9c..b9216938a718 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -151,6 +151,7 @@ struct i2c_hid {
struct i2c_hid_platform_data pdata;
bool irq_wake_enabled;
+ struct mutex reset_lock;
};
static int __i2c_hid_command(struct i2c_client *client,
@@ -356,9 +357,16 @@ static int i2c_hid_hwreset(struct i2c_client *client)
i2c_hid_dbg(ihid, "%s\n", __func__);
+ /*
+ * This prevents sending feature reports while the device is
+ * being reset. Otherwise we may lose the reset complete
+ * interrupt.
+ */
+ mutex_lock(&ihid->reset_lock);
+
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret)
- return ret;
+ goto out_unlock;
i2c_hid_dbg(ihid, "resetting...\n");
@@ -366,10 +374,11 @@ static int i2c_hid_hwreset(struct i2c_client *client)
if (ret) {
dev_err(&client->dev, "failed to reset device.\n");
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
- return ret;
}
- return 0;
+out_unlock:
+ mutex_unlock(&ihid->reset_lock);
+ return ret;
}
static void i2c_hid_get_input(struct i2c_hid *ihid)
@@ -587,12 +596,15 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type, bool use_data)
{
struct i2c_client *client = hid->driver_data;
+ struct i2c_hid *ihid = i2c_get_clientdata(client);
int report_id = buf[0];
int ret;
if (report_type == HID_INPUT_REPORT)
return -EINVAL;
+ mutex_lock(&ihid->reset_lock);
+
if (report_id) {
buf++;
count--;
@@ -605,6 +617,8 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
if (report_id && ret >= 0)
ret++; /* add report_id to the number of transfered bytes */
+ mutex_unlock(&ihid->reset_lock);
+
return ret;
}
@@ -990,6 +1004,7 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
init_waitqueue_head(&ihid->wait);
+ mutex_init(&ihid->reset_lock);
/* we need to allocate the command buffer without knowing the maximum
* size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the
@@ -1184,7 +1199,6 @@ MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table);
static struct i2c_driver i2c_hid_driver = {
.driver = {
.name = "i2c_hid",
- .owner = THIS_MODULE,
.pm = &i2c_hid_pm,
.acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
.of_match_table = of_match_ptr(i2c_hid_of_match),
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 36712e9f56c2..ad71160b9ea4 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -274,10 +274,10 @@ static void hid_irq_in(struct urb *urb)
switch (urb->status) {
case 0: /* success */
- usbhid_mark_busy(usbhid);
usbhid->retry_delay = 0;
if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open)
break;
+ usbhid_mark_busy(usbhid);
if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
hid_input_report(urb->context, HID_INPUT_REPORT,
urb->transfer_buffer,
@@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb)
struct usbhid_device *usbhid = hid->driver_data;
int unplug = 0, status = urb->status;
- spin_lock(&usbhid->lock);
-
switch (status) {
case 0: /* success */
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
@@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb)
hid_warn(urb->dev, "ctrl urb status %d received\n", status);
}
+ spin_lock(&usbhid->lock);
+
if (unplug) {
usbhid->ctrltail = usbhid->ctrlhead;
} else {
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 807922b49aa4..fa47d666cfcf 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -96,7 +96,7 @@ struct usbhid_device {
};
#define hid_to_usb_dev(hid_dev) \
- container_of(hid_dev->dev.parent->parent, struct usb_device, dev)
+ to_usb_device(hid_dev->dev.parent->parent)
#endif
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index e06af5b9f59e..5cb21dd91094 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -686,7 +686,7 @@ out:
static ssize_t wacom_led_select_store(struct device *dev, int set_id,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
unsigned int id;
int err;
@@ -714,7 +714,7 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+ struct hid_device *hdev = to_hid_device(dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
return scnprintf(buf, PAGE_SIZE, "%d\n", \
wacom->led.select[SET_ID]); \
@@ -750,7 +750,7 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
static ssize_t wacom_##name##_luminance_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+ struct hid_device *hdev = to_hid_device(dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
\
return wacom_luminance_store(wacom, &wacom->led.field, \
@@ -773,7 +773,7 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum);
static ssize_t wacom_button_image_store(struct device *dev, int button_id,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
int err;
unsigned len;
@@ -1097,7 +1097,7 @@ static ssize_t wacom_show_speed(struct device *dev,
struct device_attribute
*attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed);
@@ -1107,7 +1107,7 @@ static ssize_t wacom_store_speed(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
u8 new_speed;
@@ -1130,8 +1130,8 @@ static ssize_t wacom_show_remote_mode(struct kobject *kobj,
struct kobj_attribute *kattr,
char *buf, int index)
{
- struct device *dev = container_of(kobj->parent, struct device, kobj);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct device *dev = kobj_to_dev(kobj->parent);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
u8 mode;
@@ -1241,8 +1241,8 @@ static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
const char *buf, size_t count)
{
unsigned char selector = 0;
- struct device *dev = container_of(kobj->parent, struct device, kobj);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct device *dev = kobj_to_dev(kobj->parent);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
int err;
@@ -1353,8 +1353,7 @@ static void wacom_clean_inputs(struct wacom *wacom)
else
input_free_device(wacom->wacom_wac.pad_input);
}
- if (wacom->remote_dir)
- kobject_put(wacom->remote_dir);
+ kobject_put(wacom->remote_dir);
wacom->wacom_wac.pen_input = NULL;
wacom->wacom_wac.touch_input = NULL;
wacom->wacom_wac.pad_input = NULL;
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 01a4f05c1642..99ef77fcfb80 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -34,6 +34,9 @@
*/
#define WACOM_CONTACT_AREA_SCALE 2607
+static void wacom_report_numbered_buttons(struct input_dev *input_dev,
+ int button_count, int mask);
+
/*
* Percent of battery capacity for Graphire.
* 8th value means AC online and show 100% capacity.
@@ -436,16 +439,142 @@ exit:
static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ struct wacom_features *features = &wacom_wac->features;
struct hid_report *r;
struct hid_report_enum *re;
re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]);
- r = re->report_id_hash[WACOM_REPORT_INTUOSREAD];
+ if (features->type == INTUOSHT2)
+ r = re->report_id_hash[WACOM_REPORT_INTUOSHT2_ID];
+ else
+ r = re->report_id_hash[WACOM_REPORT_INTUOS_ID1];
if (r) {
hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
}
}
+static int wacom_intuos_pad(struct wacom_wac *wacom)
+{
+ struct wacom_features *features = &wacom->features;
+ unsigned char *data = wacom->data;
+ struct input_dev *input = wacom->pad_input;
+ int i;
+ int buttons = 0, nbuttons = features->numbered_buttons;
+ int keys = 0, nkeys = 0;
+ int ring1 = 0, ring2 = 0;
+ int strip1 = 0, strip2 = 0;
+ bool prox = false;
+
+ /* pad packets. Works as a second tool and is always in prox */
+ if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
+ data[0] == WACOM_REPORT_CINTIQPAD))
+ return 0;
+
+ if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+ buttons = (data[3] << 1) | (data[2] & 0x01);
+ ring1 = data[1];
+ } else if (features->type == DTK) {
+ buttons = data[6];
+ } else if (features->type == WACOM_13HD) {
+ buttons = (data[4] << 1) | (data[3] & 0x01);
+ } else if (features->type == WACOM_24HD) {
+ buttons = (data[8] << 8) | data[6];
+ ring1 = data[1];
+ ring2 = data[2];
+
+ /*
+ * Three "buttons" are available on the 24HD which are
+ * physically implemented as a touchstrip. Each button
+ * is approximately 3 bits wide with a 2 bit spacing.
+ * The raw touchstrip bits are stored at:
+ * ((data[3] & 0x1f) << 8) | data[4])
+ */
+ nkeys = 3;
+ keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
+ ((data[4] & 0xE0) ? 1<<1 : 0) |
+ ((data[4] & 0x07) ? 1<<0 : 0);
+ } else if (features->type == WACOM_27QHD) {
+ nkeys = 3;
+ keys = data[2] & 0x07;
+
+ input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
+ input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
+ input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+ } else if (features->type == CINTIQ_HYBRID) {
+ /*
+ * Do not send hardware buttons under Android. They
+ * are already sent to the system through GPIO (and
+ * have different meaning).
+ *
+ * d-pad right -> data[4] & 0x10
+ * d-pad up -> data[4] & 0x20
+ * d-pad left -> data[4] & 0x40
+ * d-pad down -> data[4] & 0x80
+ * d-pad center -> data[3] & 0x01
+ */
+ buttons = (data[4] << 1) | (data[3] & 0x01);
+ } else if (features->type == CINTIQ_COMPANION_2) {
+ /* d-pad right -> data[4] & 0x10
+ * d-pad up -> data[4] & 0x20
+ * d-pad left -> data[4] & 0x40
+ * d-pad down -> data[4] & 0x80
+ * d-pad center -> data[3] & 0x01
+ */
+ buttons = ((data[2] >> 4) << 7) |
+ ((data[1] & 0x04) << 6) |
+ ((data[2] & 0x0F) << 2) |
+ (data[1] & 0x03);
+ } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
+ /*
+ * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
+ * addition to the mechanical switch. Switch data is
+ * stored in data[4], capacitive data in data[5].
+ *
+ * Touch ring mode switch (data[3]) has no capacitive sensor
+ */
+ buttons = (data[4] << 1) | (data[3] & 0x01);
+ ring1 = data[2];
+ } else {
+ if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
+ buttons = (data[8] << 10) | ((data[7] & 0x01) << 9) |
+ (data[6] << 1) | (data[5] & 0x01);
+
+ if (features->type == WACOM_22HD) {
+ nkeys = 3;
+ keys = data[9] & 0x07;
+ }
+ } else {
+ buttons = ((data[6] & 0x10) << 10) |
+ ((data[5] & 0x10) << 9) |
+ ((data[6] & 0x0F) << 4) |
+ (data[5] & 0x0F);
+ }
+ strip1 = ((data[1] & 0x1f) << 8) | data[2];
+ strip2 = ((data[3] & 0x1f) << 8) | data[4];
+ }
+
+ prox = (buttons & ~(~0 << nbuttons)) | (keys & ~(~0 << nkeys)) |
+ (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
+
+ wacom_report_numbered_buttons(input, nbuttons, buttons);
+
+ for (i = 0; i < nkeys; i++)
+ input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
+
+ input_report_abs(input, ABS_RX, strip1);
+ input_report_abs(input, ABS_RY, strip2);
+
+ input_report_abs(input, ABS_WHEEL, (ring1 & 0x80) ? (ring1 & 0x7f) : 0);
+ input_report_abs(input, ABS_THROTTLE, (ring2 & 0x80) ? (ring2 & 0x7f) : 0);
+
+ input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+ input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+ input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+ return 1;
+}
+
static int wacom_intuos_inout(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
@@ -755,19 +884,40 @@ static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
return 0;
}
-static void wacom_intuos_general(struct wacom_wac *wacom)
+static int wacom_intuos_general(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
- unsigned int t;
+ int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
+ unsigned char type = (data[1] >> 1) & 0x0F;
+ unsigned int x, y, distance, t;
- /* general pen packet */
- if ((data[1] & 0xb8) == 0xa0) {
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- if (features->pressure_max == 2047) {
- t = (t << 1) | (data[1] & 1);
- }
+ if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_CINTIQ &&
+ data[0] != WACOM_REPORT_INTUOS_PEN)
+ return 0;
+
+ x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
+ y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1);
+ distance = data[9] >> 2;
+ if (features->type < INTUOS3S) {
+ x >>= 1;
+ y >>= 1;
+ distance >>= 1;
+ }
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_DISTANCE, distance);
+
+ switch (type) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ /* general pen packet */
+ t = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1);
+ if (features->pressure_max < 2047)
+ t >>= 1;
input_report_abs(input, ABS_PRESSURE, t);
if (features->type != INTUOSHT2) {
input_report_abs(input, ABS_TILT_X,
@@ -777,29 +927,112 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
input_report_key(input, BTN_STYLUS, data[1] & 2);
input_report_key(input, BTN_STYLUS2, data[1] & 4);
input_report_key(input, BTN_TOUCH, t > 10);
- }
+ break;
- /* airbrush second packet */
- if ((data[1] & 0xbc) == 0xb4) {
+ case 0x0a:
+ /* airbrush second packet */
input_report_abs(input, ABS_WHEEL,
(data[6] << 2) | ((data[7] >> 6) & 3));
input_report_abs(input, ABS_TILT_X,
(((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+ break;
+
+ case 0x05:
+ /* Rotation packet */
+ if (features->type >= INTUOS3S) {
+ /* I3 marker pen rotation */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+ ((t-1) / 2 + 450)) : (450 - t / 2) ;
+ input_report_abs(input, ABS_Z, t);
+ } else {
+ /* 4D mouse 2nd packet */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
+ ((t - 1) / 2) : -t / 2);
+ }
+ break;
+
+ case 0x04:
+ /* 4D mouse 1st packet */
+ input_report_key(input, BTN_LEFT, data[8] & 0x01);
+ input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(input, BTN_RIGHT, data[8] & 0x04);
+
+ input_report_key(input, BTN_SIDE, data[8] & 0x20);
+ input_report_key(input, BTN_EXTRA, data[8] & 0x10);
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+ break;
+
+ case 0x06:
+ /* I4 mouse */
+ input_report_key(input, BTN_LEFT, data[6] & 0x01);
+ input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
+ input_report_key(input, BTN_RIGHT, data[6] & 0x04);
+ input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
+ - ((data[7] & 0x40) >> 6));
+ input_report_key(input, BTN_SIDE, data[6] & 0x08);
+ input_report_key(input, BTN_EXTRA, data[6] & 0x10);
+
+ input_report_abs(input, ABS_TILT_X,
+ (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
+ input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+ break;
+
+ case 0x08:
+ if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+ /* 2D mouse packet */
+ input_report_key(input, BTN_LEFT, data[8] & 0x04);
+ input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
+ input_report_key(input, BTN_RIGHT, data[8] & 0x10);
+ input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
+ - ((data[8] & 0x02) >> 1));
+
+ /* I3 2D mouse side buttons */
+ if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
+ input_report_key(input, BTN_SIDE, data[8] & 0x40);
+ input_report_key(input, BTN_EXTRA, data[8] & 0x20);
+ }
+ }
+ else if (wacom->tool[idx] == BTN_TOOL_LENS) {
+ /* Lens cursor packets */
+ input_report_key(input, BTN_LEFT, data[8] & 0x01);
+ input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(input, BTN_RIGHT, data[8] & 0x04);
+ input_report_key(input, BTN_SIDE, data[8] & 0x10);
+ input_report_key(input, BTN_EXTRA, data[8] & 0x08);
+ }
+ break;
+
+ case 0x07:
+ case 0x09:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ /* unhandled */
+ break;
}
+
+ input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
+ input_report_key(input, wacom->tool[idx], 1);
+ input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ wacom->reporting_data = true;
+ return 2;
}
static int wacom_intuos_irq(struct wacom_wac *wacom)
{
- struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
- unsigned int t;
- int idx = 0, result;
+ int result;
if (data[0] != WACOM_REPORT_PENABLED &&
- data[0] != WACOM_REPORT_INTUOSREAD &&
- data[0] != WACOM_REPORT_INTUOSWRITE &&
+ data[0] != WACOM_REPORT_INTUOS_ID1 &&
+ data[0] != WACOM_REPORT_INTUOS_ID2 &&
data[0] != WACOM_REPORT_INTUOSPAD &&
data[0] != WACOM_REPORT_INTUOS_PEN &&
data[0] != WACOM_REPORT_CINTIQ &&
@@ -810,339 +1043,22 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 0;
}
- /* tool number */
- if (features->type == INTUOS)
- idx = data[1] & 0x01;
-
- /* pad packets. Works as a second tool and is always in prox */
- if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
- data[0] == WACOM_REPORT_CINTIQPAD) {
- input = wacom->pad_input;
- if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
- input_report_key(input, BTN_0, (data[2] & 0x01));
- input_report_key(input, BTN_1, (data[3] & 0x01));
- input_report_key(input, BTN_2, (data[3] & 0x02));
- input_report_key(input, BTN_3, (data[3] & 0x04));
- input_report_key(input, BTN_4, (data[3] & 0x08));
- input_report_key(input, BTN_5, (data[3] & 0x10));
- input_report_key(input, BTN_6, (data[3] & 0x20));
- if (data[1] & 0x80) {
- input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
- } else {
- /* Out of proximity, clear wheel value. */
- input_report_abs(input, ABS_WHEEL, 0);
- }
- if (features->type != INTUOS4S) {
- input_report_key(input, BTN_7, (data[3] & 0x40));
- input_report_key(input, BTN_8, (data[3] & 0x80));
- }
- if (data[1] | (data[2] & 0x01) | data[3]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == DTK) {
- input_report_key(input, BTN_0, (data[6] & 0x01));
- input_report_key(input, BTN_1, (data[6] & 0x02));
- input_report_key(input, BTN_2, (data[6] & 0x04));
- input_report_key(input, BTN_3, (data[6] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x10));
- input_report_key(input, BTN_5, (data[6] & 0x20));
- if (data[6] & 0x3f) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == WACOM_13HD) {
- input_report_key(input, BTN_0, (data[3] & 0x01));
- input_report_key(input, BTN_1, (data[4] & 0x01));
- input_report_key(input, BTN_2, (data[4] & 0x02));
- input_report_key(input, BTN_3, (data[4] & 0x04));
- input_report_key(input, BTN_4, (data[4] & 0x08));
- input_report_key(input, BTN_5, (data[4] & 0x10));
- input_report_key(input, BTN_6, (data[4] & 0x20));
- input_report_key(input, BTN_7, (data[4] & 0x40));
- input_report_key(input, BTN_8, (data[4] & 0x80));
- if ((data[3] & 0x01) | data[4]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == WACOM_24HD) {
- input_report_key(input, BTN_0, (data[6] & 0x01));
- input_report_key(input, BTN_1, (data[6] & 0x02));
- input_report_key(input, BTN_2, (data[6] & 0x04));
- input_report_key(input, BTN_3, (data[6] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x10));
- input_report_key(input, BTN_5, (data[6] & 0x20));
- input_report_key(input, BTN_6, (data[6] & 0x40));
- input_report_key(input, BTN_7, (data[6] & 0x80));
- input_report_key(input, BTN_8, (data[8] & 0x01));
- input_report_key(input, BTN_9, (data[8] & 0x02));
- input_report_key(input, BTN_A, (data[8] & 0x04));
- input_report_key(input, BTN_B, (data[8] & 0x08));
- input_report_key(input, BTN_C, (data[8] & 0x10));
- input_report_key(input, BTN_X, (data[8] & 0x20));
- input_report_key(input, BTN_Y, (data[8] & 0x40));
- input_report_key(input, BTN_Z, (data[8] & 0x80));
-
- /*
- * Three "buttons" are available on the 24HD which are
- * physically implemented as a touchstrip. Each button
- * is approximately 3 bits wide with a 2 bit spacing.
- * The raw touchstrip bits are stored at:
- * ((data[3] & 0x1f) << 8) | data[4])
- */
- input_report_key(input, KEY_PROG1, data[4] & 0x07);
- input_report_key(input, KEY_PROG2, data[4] & 0xE0);
- input_report_key(input, KEY_PROG3, data[3] & 0x1C);
-
- if (data[1] & 0x80) {
- input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
- } else {
- /* Out of proximity, clear wheel value. */
- input_report_abs(input, ABS_WHEEL, 0);
- }
-
- if (data[2] & 0x80) {
- input_report_abs(input, ABS_THROTTLE, (data[2] & 0x7f));
- } else {
- /* Out of proximity, clear second wheel value. */
- input_report_abs(input, ABS_THROTTLE, 0);
- }
-
- if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == WACOM_27QHD) {
- input_report_key(input, KEY_PROG1, data[2] & 0x01);
- input_report_key(input, KEY_PROG2, data[2] & 0x02);
- input_report_key(input, KEY_PROG3, data[2] & 0x04);
-
- input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
- input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
- input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
- if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == CINTIQ_HYBRID) {
- /*
- * Do not send hardware buttons under Android. They
- * are already sent to the system through GPIO (and
- * have different meaning).
- */
- input_report_key(input, BTN_1, (data[4] & 0x01));
- input_report_key(input, BTN_2, (data[4] & 0x02));
- input_report_key(input, BTN_3, (data[4] & 0x04));
- input_report_key(input, BTN_4, (data[4] & 0x08));
-
- input_report_key(input, BTN_5, (data[4] & 0x10)); /* Right */
- input_report_key(input, BTN_6, (data[4] & 0x20)); /* Up */
- input_report_key(input, BTN_7, (data[4] & 0x40)); /* Left */
- input_report_key(input, BTN_8, (data[4] & 0x80)); /* Down */
- input_report_key(input, BTN_0, (data[3] & 0x01)); /* Center */
-
- if (data[4] | (data[3] & 0x01)) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
-
- } else if (features->type == CINTIQ_COMPANION_2) {
- input_report_key(input, BTN_1, (data[1] & 0x02));
- input_report_key(input, BTN_2, (data[2] & 0x01));
- input_report_key(input, BTN_3, (data[2] & 0x02));
- input_report_key(input, BTN_4, (data[2] & 0x04));
- input_report_key(input, BTN_5, (data[2] & 0x08));
- input_report_key(input, BTN_6, (data[1] & 0x04));
-
- input_report_key(input, BTN_7, (data[2] & 0x10)); /* Right */
- input_report_key(input, BTN_8, (data[2] & 0x20)); /* Up */
- input_report_key(input, BTN_9, (data[2] & 0x40)); /* Left */
- input_report_key(input, BTN_A, (data[2] & 0x80)); /* Down */
- input_report_key(input, BTN_0, (data[1] & 0x01)); /* Center */
-
- if (data[2] | (data[1] & 0x07)) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
-
- } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
- int i;
-
- /* Touch ring mode switch has no capacitive sensor */
- input_report_key(input, BTN_0, (data[3] & 0x01));
-
- /*
- * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
- * addition to the mechanical switch. Switch data is
- * stored in data[4], capacitive data in data[5].
- */
- for (i = 0; i < 8; i++)
- input_report_key(input, BTN_1 + i, data[4] & (1 << i));
-
- if (data[2] & 0x80) {
- input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
- } else {
- /* Out of proximity, clear wheel value. */
- input_report_abs(input, ABS_WHEEL, 0);
- }
-
- if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else {
- if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
- input_report_key(input, BTN_0, (data[5] & 0x01));
- input_report_key(input, BTN_1, (data[6] & 0x01));
- input_report_key(input, BTN_2, (data[6] & 0x02));
- input_report_key(input, BTN_3, (data[6] & 0x04));
- input_report_key(input, BTN_4, (data[6] & 0x08));
- input_report_key(input, BTN_5, (data[6] & 0x10));
- input_report_key(input, BTN_6, (data[6] & 0x20));
- input_report_key(input, BTN_7, (data[6] & 0x40));
- input_report_key(input, BTN_8, (data[6] & 0x80));
- input_report_key(input, BTN_9, (data[7] & 0x01));
- input_report_key(input, BTN_A, (data[8] & 0x01));
- input_report_key(input, BTN_B, (data[8] & 0x02));
- input_report_key(input, BTN_C, (data[8] & 0x04));
- input_report_key(input, BTN_X, (data[8] & 0x08));
- input_report_key(input, BTN_Y, (data[8] & 0x10));
- input_report_key(input, BTN_Z, (data[8] & 0x20));
- input_report_key(input, BTN_BASE, (data[8] & 0x40));
- input_report_key(input, BTN_BASE2, (data[8] & 0x80));
-
- if (features->type == WACOM_22HD) {
- input_report_key(input, KEY_PROG1, data[9] & 0x01);
- input_report_key(input, KEY_PROG2, data[9] & 0x02);
- input_report_key(input, KEY_PROG3, data[9] & 0x04);
- }
- } else {
- input_report_key(input, BTN_0, (data[5] & 0x01));
- input_report_key(input, BTN_1, (data[5] & 0x02));
- input_report_key(input, BTN_2, (data[5] & 0x04));
- input_report_key(input, BTN_3, (data[5] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x01));
- input_report_key(input, BTN_5, (data[6] & 0x02));
- input_report_key(input, BTN_6, (data[6] & 0x04));
- input_report_key(input, BTN_7, (data[6] & 0x08));
- input_report_key(input, BTN_8, (data[5] & 0x10));
- input_report_key(input, BTN_9, (data[6] & 0x10));
- }
- input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
- input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
- if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) |
- data[2] | (data[3] & 0x1f) | data[4] | data[8] |
- (data[7] & 0x01)) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- }
- return 1;
- }
+ /* process pad events */
+ result = wacom_intuos_pad(wacom);
+ if (result)
+ return result;
/* process in/out prox events */
result = wacom_intuos_inout(wacom);
if (result)
- return result - 1;
-
- if (features->type >= INTUOS3S) {
- input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
- input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
- input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
- } else {
- input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
- input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
- input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
- }
+ return result - 1;
/* process general packets */
- wacom_intuos_general(wacom);
-
- /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
- if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
-
- if (data[1] & 0x02) {
- /* Rotation packet */
- if (features->type >= INTUOS3S) {
- /* I3 marker pen rotation */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
- ((t-1) / 2 + 450)) : (450 - t / 2) ;
- input_report_abs(input, ABS_Z, t);
- } else {
- /* 4D mouse rotation packet */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
- ((t - 1) / 2) : -t / 2);
- }
-
- } else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
- /* 4D mouse packet */
- input_report_key(input, BTN_LEFT, data[8] & 0x01);
- input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(input, BTN_RIGHT, data[8] & 0x04);
-
- input_report_key(input, BTN_SIDE, data[8] & 0x20);
- input_report_key(input, BTN_EXTRA, data[8] & 0x10);
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
- } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
- /* I4 mouse */
- if (features->type >= INTUOS4S && features->type <= INTUOSPL) {
- input_report_key(input, BTN_LEFT, data[6] & 0x01);
- input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
- input_report_key(input, BTN_RIGHT, data[6] & 0x04);
- input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
- - ((data[7] & 0x40) >> 6));
- input_report_key(input, BTN_SIDE, data[6] & 0x08);
- input_report_key(input, BTN_EXTRA, data[6] & 0x10);
-
- input_report_abs(input, ABS_TILT_X,
- (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
- input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
- } else {
- /* 2D mouse packet */
- input_report_key(input, BTN_LEFT, data[8] & 0x04);
- input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
- input_report_key(input, BTN_RIGHT, data[8] & 0x10);
- input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
- - ((data[8] & 0x02) >> 1));
-
- /* I3 2D mouse side buttons */
- if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
- input_report_key(input, BTN_SIDE, data[8] & 0x40);
- input_report_key(input, BTN_EXTRA, data[8] & 0x20);
- }
- }
- } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
- features->type == INTUOS4L || features->type == INTUOS5L ||
- features->type == INTUOSPL) &&
- wacom->tool[idx] == BTN_TOOL_LENS) {
- /* Lens cursor packets */
- input_report_key(input, BTN_LEFT, data[8] & 0x01);
- input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(input, BTN_RIGHT, data[8] & 0x04);
- input_report_key(input, BTN_SIDE, data[8] & 0x10);
- input_report_key(input, BTN_EXTRA, data[8] & 0x08);
- }
- }
+ result = wacom_intuos_general(wacom);
+ if (result)
+ return result - 1;
- input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
- input_report_key(input, wacom->tool[idx], 1);
- input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- wacom->reporting_data = true;
- return 1;
+ return 0;
}
static int int_dist(int x1, int y1, int x2, int y2)
@@ -2509,7 +2425,7 @@ void wacom_setup_device_quirks(struct wacom *wacom)
features->quirks |= WACOM_QUIRK_BATTERY;
/* quirk for bamboo touch with 2 low res touches */
- if (features->type == BAMBOO_PT &&
+ if ((features->type == BAMBOO_PT || features->type == BAMBOO_TOUCH) &&
features->pktlen == WACOM_PKGLEN_BBTOUCH) {
features->x_max <<= 5;
features->y_max <<= 5;
@@ -2806,6 +2722,19 @@ static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
__set_bit(BTN_BASE + (i-16), input_dev->keybit);
}
+static void wacom_report_numbered_buttons(struct input_dev *input_dev,
+ int button_count, int mask)
+{
+ int i;
+
+ for (i = 0; i < button_count && i < 10; i++)
+ input_report_key(input_dev, BTN_0 + i, mask & (1 << i));
+ for (i = 10; i < button_count && i < 16; i++)
+ input_report_key(input_dev, BTN_A + (i-10), mask & (1 << i));
+ for (i = 16; i < button_count && i < 18; i++)
+ input_report_key(input_dev, BTN_BASE + (i-16), mask & (1 << i));
+}
+
int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 877c24a5df94..25baa7f29599 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -47,8 +47,8 @@
/* wacom data packet report IDs */
#define WACOM_REPORT_PENABLED 2
#define WACOM_REPORT_PENABLED_BT 3
-#define WACOM_REPORT_INTUOSREAD 5
-#define WACOM_REPORT_INTUOSWRITE 6
+#define WACOM_REPORT_INTUOS_ID1 5
+#define WACOM_REPORT_INTUOS_ID2 6
#define WACOM_REPORT_INTUOSPAD 12
#define WACOM_REPORT_INTUOS5PAD 3
#define WACOM_REPORT_DTUSPAD 21
@@ -70,6 +70,7 @@
#define WACOM_REPORT_DEVICE_LIST 16
#define WACOM_REPORT_INTUOS_PEN 16
#define WACOM_REPORT_REMOTE 17
+#define WACOM_REPORT_INTUOSHT2_ID 8
/* device quirks */
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
diff --git a/drivers/hsi/controllers/omap_ssi.c b/drivers/hsi/controllers/omap_ssi.c
index f6d3100b7a32..27b91f14ba7a 100644
--- a/drivers/hsi/controllers/omap_ssi.c
+++ b/drivers/hsi/controllers/omap_ssi.c
@@ -323,11 +323,10 @@ static int __init ssi_add_controller(struct hsi_controller *ssi,
return -ENOMEM;
}
- ssi->id = ida_simple_get(&platform_omap_ssi_ida, 0, 0, GFP_KERNEL);
- if (ssi->id < 0) {
- err = ssi->id;
+ err = ida_simple_get(&platform_omap_ssi_ida, 0, 0, GFP_KERNEL);
+ if (err < 0)
goto out_err;
- }
+ ssi->id = err;
ssi->owner = THIS_MODULE;
ssi->device.parent = &pd->dev;
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 02e66032ae73..e80a66e20998 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -1147,13 +1147,13 @@ static int __init ssi_port_probe(struct platform_device *pd)
goto error;
}
- cawake_gpio = of_get_named_gpio(np, "ti,ssi-cawake-gpio", 0);
- if (cawake_gpio < 0) {
+ err = of_get_named_gpio(np, "ti,ssi-cawake-gpio", 0);
+ if (err < 0) {
dev_err(&pd->dev, "DT data is missing cawake gpio (err=%d)\n",
- cawake_gpio);
- err = -ENODEV;
+ err);
goto error;
}
+ cawake_gpio = err;
err = devm_gpio_request_one(&port->device, cawake_gpio, GPIOF_DIR_IN,
"cawake");
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index c4dcab048cb8..1161d68a1863 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -28,6 +28,7 @@
#include <linux/module.h>
#include <linux/hyperv.h>
#include <linux/uio.h>
+#include <linux/interrupt.h>
#include "hyperv_vmbus.h"
@@ -496,8 +497,33 @@ static void reset_channel_cb(void *arg)
static int vmbus_close_internal(struct vmbus_channel *channel)
{
struct vmbus_channel_close_channel *msg;
+ struct tasklet_struct *tasklet;
int ret;
+ /*
+ * process_chn_event(), running in the tasklet, can race
+ * with vmbus_close_internal() in the case of SMP guest, e.g., when
+ * the former is accessing channel->inbound.ring_buffer, the latter
+ * could be freeing the ring_buffer pages.
+ *
+ * To resolve the race, we can serialize them by disabling the
+ * tasklet when the latter is running here.
+ */
+ tasklet = hv_context.event_dpc[channel->target_cpu];
+ tasklet_disable(tasklet);
+
+ /*
+ * In case a device driver's probe() fails (e.g.,
+ * util_probe() -> vmbus_open() returns -ENOMEM) and the device is
+ * rescinded later (e.g., we dynamically disble an Integrated Service
+ * in Hyper-V Manager), the driver's remove() invokes vmbus_close():
+ * here we should skip most of the below cleanup work.
+ */
+ if (channel->state != CHANNEL_OPENED_STATE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */
@@ -525,7 +551,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to post the close msg,
* it is perhaps better to leak memory.
*/
- return ret;
+ goto out;
}
/* Tear down the gpadl for the channel's ring buffer */
@@ -538,7 +564,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to teardown gpadl,
* it is perhaps better to leak memory.
*/
- return ret;
+ goto out;
}
}
@@ -549,12 +575,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
- /*
- * If the channel has been rescinded; process device removal.
- */
- if (channel->rescind)
- hv_process_channel_removal(channel,
- channel->offermsg.child_relid);
+out:
+ tasklet_enable(tasklet);
+
return ret;
}
@@ -630,10 +653,19 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
* on the ring. We will not signal if more data is
* to be placed.
*
+ * Based on the channel signal state, we will decide
+ * which signaling policy will be applied.
+ *
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
*/
+
+ if (channel->signal_policy)
+ signal = true;
+ else
+ kick_q = true;
+
if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel);
@@ -733,10 +765,19 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
* on the ring. We will not signal if more data is
* to be placed.
*
+ * Based on the channel signal state, we will decide
+ * which signaling policy will be applied.
+ *
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
*/
+
+ if (channel->signal_policy)
+ signal = true;
+ else
+ kick_q = true;
+
if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel);
@@ -881,46 +922,29 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
*
* Mainly used by Hyper-V drivers.
*/
-int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
- u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
+static inline int
+__vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len, u64 *requestid,
+ bool raw)
{
- struct vmpacket_descriptor desc;
- u32 packetlen;
- u32 userlen;
int ret;
bool signal = false;
- *buffer_actual_len = 0;
- *requestid = 0;
-
-
- ret = hv_ringbuffer_peek(&channel->inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0)
- return 0;
-
- packetlen = desc.len8 << 3;
- userlen = packetlen - (desc.offset8 << 3);
-
- *buffer_actual_len = userlen;
-
- if (userlen > bufferlen) {
-
- pr_err("Buffer too small - got %d needs %d\n",
- bufferlen, userlen);
- return -ETOOSMALL;
- }
-
- *requestid = desc.trans_id;
-
- /* Copy over the packet to the user buffer */
- ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
- (desc.offset8 << 3), &signal);
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen,
+ buffer_actual_len, requestid, &signal, raw);
if (signal)
vmbus_setevent(channel);
- return 0;
+ return ret;
+}
+
+int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len,
+ u64 *requestid)
+{
+ return __vmbus_recvpacket(channel, buffer, bufferlen,
+ buffer_actual_len, requestid, false);
}
EXPORT_SYMBOL(vmbus_recvpacket);
@@ -931,37 +955,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u32 *buffer_actual_len,
u64 *requestid)
{
- struct vmpacket_descriptor desc;
- u32 packetlen;
- int ret;
- bool signal = false;
-
- *buffer_actual_len = 0;
- *requestid = 0;
-
-
- ret = hv_ringbuffer_peek(&channel->inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0)
- return 0;
-
-
- packetlen = desc.len8 << 3;
-
- *buffer_actual_len = packetlen;
-
- if (packetlen > bufferlen)
- return -ENOBUFS;
-
- *requestid = desc.trans_id;
-
- /* Copy over the entire packet to the user buffer */
- ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0,
- &signal);
-
- if (signal)
- vmbus_setevent(channel);
-
- return ret;
+ return __vmbus_recvpacket(channel, buffer, bufferlen,
+ buffer_actual_len, requestid, true);
}
EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 652afd11a9ef..1c1ad47042c5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -177,19 +177,24 @@ static void percpu_channel_deq(void *arg)
}
-void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+static void vmbus_release_relid(u32 relid)
{
struct vmbus_channel_relid_released msg;
- unsigned long flags;
- struct vmbus_channel *primary_channel;
memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
msg.child_relid = relid;
msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+}
- if (channel == NULL)
- return;
+void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+{
+ unsigned long flags;
+ struct vmbus_channel *primary_channel;
+
+ vmbus_release_relid(relid);
+
+ BUG_ON(!channel->rescind);
if (channel->target_cpu != get_cpu()) {
put_cpu();
@@ -201,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
}
if (channel->primary_channel == NULL) {
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_del(&channel->listentry);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
primary_channel = channel;
} else {
@@ -230,9 +235,7 @@ void vmbus_free_channels(void)
list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) {
- /* if we don't set rescind to true, vmbus_close_internal()
- * won't invoke hv_process_channel_removal().
- */
+ /* hv_process_channel_removal() needs this */
channel->rescind = true;
vmbus_device_unregister(channel->device_obj);
@@ -250,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
unsigned long flags;
/* Make sure this is a new offer */
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (!uuid_le_cmp(channel->offermsg.offer.if_type,
@@ -266,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
list_add_tail(&newchannel->listentry,
&vmbus_connection.chn_list);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
if (!fnew) {
/*
@@ -336,9 +339,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
return;
err_deq_chan:
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ vmbus_release_relid(newchannel->offermsg.child_relid);
+
+ mutex_lock(&vmbus_connection.channel_mutex);
list_del(&newchannel->listentry);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
@@ -356,8 +361,10 @@ err_free_chan:
enum {
IDE = 0,
SCSI,
+ FC,
NIC,
ND_NIC,
+ PCIE,
MAX_PERF_CHN,
};
@@ -371,10 +378,14 @@ static const struct hv_vmbus_device_id hp_devs[] = {
{ HV_IDE_GUID, },
/* Storage - SCSI */
{ HV_SCSI_GUID, },
+ /* Storage - FC */
+ { HV_SYNTHFC_GUID, },
/* Network */
{ HV_NIC_GUID, },
/* NetworkDirect Guest RDMA */
{ HV_ND_GUID, },
+ /* PCI Express Pass Through */
+ { HV_PCIE_GUID, },
};
@@ -405,8 +416,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
struct cpumask *alloced_mask;
for (i = IDE; i < MAX_PERF_CHN; i++) {
- if (!memcmp(type_guid->b, hp_devs[i].guid,
- sizeof(uuid_le))) {
+ if (!uuid_le_cmp(*type_guid, hp_devs[i].guid)) {
perf_chn = true;
break;
}
@@ -585,7 +595,11 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
channel = relid2channel(rescind->child_relid);
if (channel == NULL) {
- hv_process_channel_removal(NULL, rescind->child_relid);
+ /*
+ * This is very impossible, because in
+ * vmbus_process_offer(), we have already invoked
+ * vmbus_release_relid() on error.
+ */
return;
}
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 4fc2e8836e60..3dc5a9c7fad6 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -83,10 +83,13 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
- if (version >= VERSION_WIN8_1) {
- msg->target_vcpu = hv_context.vp_index[get_cpu()];
- put_cpu();
- }
+ /*
+ * We want all channel messages to be delivered on CPU 0.
+ * This has been the behavior pre-win8. This is not
+ * perf issue and having all channel messages delivered on CPU 0
+ * would be ok.
+ */
+ msg->target_vcpu = 0;
/*
* Add to list before we send the request since we may
@@ -146,7 +149,7 @@ int vmbus_connect(void)
spin_lock_init(&vmbus_connection.channelmsg_lock);
INIT_LIST_HEAD(&vmbus_connection.chn_list);
- spin_lock_init(&vmbus_connection.channel_lock);
+ mutex_init(&vmbus_connection.channel_mutex);
/*
* Setup the vmbus event connection for channel interrupt
@@ -282,11 +285,10 @@ struct vmbus_channel *relid2channel(u32 relid)
{
struct vmbus_channel *channel;
struct vmbus_channel *found_channel = NULL;
- unsigned long flags;
struct list_head *cur, *tmp;
struct vmbus_channel *cur_sc;
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (channel->offermsg.child_relid == relid) {
found_channel = channel;
@@ -305,7 +307,7 @@ struct vmbus_channel *relid2channel(u32 relid)
}
}
}
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
return found_channel;
}
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 6341be8739ae..11bca51ef5ff 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -89,9 +89,9 @@ static int query_hypervisor_info(void)
}
/*
- * do_hypercall- Invoke the specified hypercall
+ * hv_do_hypercall- Invoke the specified hypercall
*/
-static u64 do_hypercall(u64 control, void *input, void *output)
+u64 hv_do_hypercall(u64 control, void *input, void *output)
{
u64 input_address = (input) ? virt_to_phys(input) : 0;
u64 output_address = (output) ? virt_to_phys(output) : 0;
@@ -132,6 +132,7 @@ static u64 do_hypercall(u64 control, void *input, void *output)
return hv_status_lo | ((u64)hv_status_hi << 32);
#endif /* !x86_64 */
}
+EXPORT_SYMBOL_GPL(hv_do_hypercall);
#ifdef CONFIG_X86_64
static cycle_t read_hv_clock_tsc(struct clocksource *arg)
@@ -139,7 +140,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg)
cycle_t current_tick;
struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page;
- if (tsc_pg->tsc_sequence != -1) {
+ if (tsc_pg->tsc_sequence != 0) {
/*
* Use the tsc page to compute the value.
*/
@@ -161,7 +162,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg)
if (tsc_pg->tsc_sequence == sequence)
return current_tick;
- if (tsc_pg->tsc_sequence != -1)
+ if (tsc_pg->tsc_sequence != 0)
continue;
/*
* Fallback using MSR method.
@@ -192,9 +193,7 @@ int hv_init(void)
{
int max_leaf;
union hv_x64_msr_hypercall_contents hypercall_msr;
- union hv_x64_msr_hypercall_contents tsc_msr;
void *virtaddr = NULL;
- void *va_tsc = NULL;
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0,
@@ -240,6 +239,9 @@ int hv_init(void)
#ifdef CONFIG_X86_64
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
+ union hv_x64_msr_hypercall_contents tsc_msr;
+ void *va_tsc;
+
va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (!va_tsc)
goto cleanup;
@@ -315,7 +317,7 @@ int hv_post_message(union hv_connection_id connection_id,
{
struct hv_input_post_message *aligned_msg;
- u16 status;
+ u64 status;
if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
return -EMSGSIZE;
@@ -329,11 +331,10 @@ int hv_post_message(union hv_connection_id connection_id,
aligned_msg->payload_size = payload_size;
memcpy((void *)aligned_msg->payload, payload, payload_size);
- status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
- & 0xFFFF;
+ status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL);
put_cpu();
- return status;
+ return status & 0xFFFF;
}
@@ -343,13 +344,13 @@ int hv_post_message(union hv_connection_id connection_id,
*
* This involves a hypercall.
*/
-u16 hv_signal_event(void *con_id)
+int hv_signal_event(void *con_id)
{
- u16 status;
+ u64 status;
- status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0xFFFF);
+ status = hv_do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL);
- return status;
+ return status & 0xFFFF;
}
static int hv_ce_set_next_event(unsigned long delta,
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index db4b887b889d..c37a71e13de0 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -51,7 +51,6 @@ static struct {
struct hv_fcopy_hdr *fcopy_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
- void *fcopy_context; /* for the channel callback */
} fcopy_transaction;
static void fcopy_respond_to_host(int error);
@@ -67,6 +66,13 @@ static struct hvutil_transport *hvt;
*/
static int dm_reg_value;
+static void fcopy_poll_wrapper(void *channel)
+{
+ /* Transaction is finished, reset the state here to avoid races. */
+ fcopy_transaction.state = HVUTIL_READY;
+ hv_fcopy_onchannelcallback(channel);
+}
+
static void fcopy_timeout_func(struct work_struct *dummy)
{
/*
@@ -74,13 +80,7 @@ static void fcopy_timeout_func(struct work_struct *dummy)
* process the pending transaction.
*/
fcopy_respond_to_host(HV_E_FAIL);
-
- /* Transaction is finished, reset the state. */
- if (fcopy_transaction.state > HVUTIL_READY)
- fcopy_transaction.state = HVUTIL_READY;
-
- hv_poll_channel(fcopy_transaction.fcopy_context,
- hv_fcopy_onchannelcallback);
+ hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
}
static int fcopy_handle_handshake(u32 version)
@@ -108,9 +108,7 @@ static int fcopy_handle_handshake(u32 version)
return -EINVAL;
}
pr_debug("FCP: userspace daemon ver. %d registered\n", version);
- fcopy_transaction.state = HVUTIL_READY;
- hv_poll_channel(fcopy_transaction.fcopy_context,
- hv_fcopy_onchannelcallback);
+ hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
return 0;
}
@@ -227,15 +225,8 @@ void hv_fcopy_onchannelcallback(void *context)
int util_fw_version;
int fcopy_srv_version;
- if (fcopy_transaction.state > HVUTIL_READY) {
- /*
- * We will defer processing this callback once
- * the current transaction is complete.
- */
- fcopy_transaction.fcopy_context = context;
+ if (fcopy_transaction.state > HVUTIL_READY)
return;
- }
- fcopy_transaction.fcopy_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid);
@@ -275,7 +266,8 @@ void hv_fcopy_onchannelcallback(void *context)
* Send the information to the user-level daemon.
*/
schedule_work(&fcopy_send_work);
- schedule_delayed_work(&fcopy_timeout_work, 5*HZ);
+ schedule_delayed_work(&fcopy_timeout_work,
+ HV_UTIL_TIMEOUT * HZ);
return;
}
icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
@@ -304,9 +296,8 @@ static int fcopy_on_msg(void *msg, int len)
if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
fcopy_respond_to_host(*val);
- fcopy_transaction.state = HVUTIL_READY;
- hv_poll_channel(fcopy_transaction.fcopy_context,
- hv_fcopy_onchannelcallback);
+ hv_poll_channel(fcopy_transaction.recv_channel,
+ fcopy_poll_wrapper);
}
return 0;
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 74c38a9f34a6..d4ab81bcd515 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -66,7 +66,6 @@ static struct {
struct hv_kvp_msg *kvp_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
- void *kvp_context; /* for the channel callback */
} kvp_transaction;
/*
@@ -94,6 +93,13 @@ static struct hvutil_transport *hvt;
*/
#define HV_DRV_VERSION "3.1"
+static void kvp_poll_wrapper(void *channel)
+{
+ /* Transaction is finished, reset the state here to avoid races. */
+ kvp_transaction.state = HVUTIL_READY;
+ hv_kvp_onchannelcallback(channel);
+}
+
static void
kvp_register(int reg_value)
{
@@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy)
*/
kvp_respond_to_host(NULL, HV_E_FAIL);
- /* Transaction is finished, reset the state. */
- if (kvp_transaction.state > HVUTIL_READY)
- kvp_transaction.state = HVUTIL_READY;
-
- hv_poll_channel(kvp_transaction.kvp_context,
- hv_kvp_onchannelcallback);
+ hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
}
static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -153,7 +154,7 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
pr_debug("KVP: userspace daemon ver. %d registered\n",
KVP_OP_REGISTER);
kvp_register(dm_reg_value);
- kvp_transaction.state = HVUTIL_READY;
+ hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
return 0;
}
@@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len)
*/
if (cancel_delayed_work_sync(&kvp_timeout_work)) {
kvp_respond_to_host(message, error);
- kvp_transaction.state = HVUTIL_READY;
- hv_poll_channel(kvp_transaction.kvp_context,
- hv_kvp_onchannelcallback);
+ hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
}
return 0;
@@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context)
int util_fw_version;
int kvp_srv_version;
- if (kvp_transaction.state > HVUTIL_READY) {
- /*
- * We will defer processing this callback once
- * the current transaction is complete.
- */
- kvp_transaction.kvp_context = context;
+ if (kvp_transaction.state > HVUTIL_READY)
return;
- }
- kvp_transaction.kvp_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
&requestid);
@@ -668,7 +660,8 @@ void hv_kvp_onchannelcallback(void *context)
* user-mode not responding.
*/
schedule_work(&kvp_sendkey_work);
- schedule_delayed_work(&kvp_timeout_work, 5*HZ);
+ schedule_delayed_work(&kvp_timeout_work,
+ HV_UTIL_TIMEOUT * HZ);
return;
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 815405f2e777..67def4a831c8 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -53,7 +53,6 @@ static struct {
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
struct hv_vss_msg *msg; /* current message */
- void *vss_context; /* for the channel callback */
} vss_transaction;
@@ -74,6 +73,13 @@ static void vss_timeout_func(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
static DECLARE_WORK(vss_send_op_work, vss_send_op);
+static void vss_poll_wrapper(void *channel)
+{
+ /* Transaction is finished, reset the state here to avoid races. */
+ vss_transaction.state = HVUTIL_READY;
+ hv_vss_onchannelcallback(channel);
+}
+
/*
* Callback when data is received from user mode.
*/
@@ -86,12 +92,7 @@ static void vss_timeout_func(struct work_struct *dummy)
pr_warn("VSS: timeout waiting for daemon to reply\n");
vss_respond_to_host(HV_E_FAIL);
- /* Transaction is finished, reset the state. */
- if (vss_transaction.state > HVUTIL_READY)
- vss_transaction.state = HVUTIL_READY;
-
- hv_poll_channel(vss_transaction.vss_context,
- hv_vss_onchannelcallback);
+ hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
}
static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
@@ -112,7 +113,7 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
default:
return -EINVAL;
}
- vss_transaction.state = HVUTIL_READY;
+ hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value);
return 0;
}
@@ -138,9 +139,8 @@ static int vss_on_msg(void *msg, int len)
if (cancel_delayed_work_sync(&vss_timeout_work)) {
vss_respond_to_host(vss_msg->error);
/* Transaction is finished, reset the state. */
- vss_transaction.state = HVUTIL_READY;
- hv_poll_channel(vss_transaction.vss_context,
- hv_vss_onchannelcallback);
+ hv_poll_channel(vss_transaction.recv_channel,
+ vss_poll_wrapper);
}
} else {
/* This is a spurious call! */
@@ -238,15 +238,8 @@ void hv_vss_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
- if (vss_transaction.state > HVUTIL_READY) {
- /*
- * We will defer processing this callback once
- * the current transaction is complete.
- */
- vss_transaction.vss_context = context;
+ if (vss_transaction.state > HVUTIL_READY)
return;
- }
- vss_transaction.vss_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid);
@@ -338,6 +331,11 @@ static void vss_on_reset(void)
int
hv_vss_init(struct hv_util_service *srv)
{
+ if (vmbus_proto_version < VERSION_WIN8_1) {
+ pr_warn("Integration service 'Backup (volume snapshot)'"
+ " not supported on this host version.\n");
+ return -ENOTSUPP;
+ }
recv_buffer = srv->recv_buffer;
/*
diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c
index 6a9d80a5332d..4f42c0e20c20 100644
--- a/drivers/hv/hv_utils_transport.c
+++ b/drivers/hv/hv_utils_transport.c
@@ -27,11 +27,9 @@ static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list);
static void hvt_reset(struct hvutil_transport *hvt)
{
- mutex_lock(&hvt->outmsg_lock);
kfree(hvt->outmsg);
hvt->outmsg = NULL;
hvt->outmsg_len = 0;
- mutex_unlock(&hvt->outmsg_lock);
if (hvt->on_reset)
hvt->on_reset();
}
@@ -44,10 +42,17 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf,
hvt = container_of(file->f_op, struct hvutil_transport, fops);
- if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0))
+ if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0 ||
+ hvt->mode != HVUTIL_TRANSPORT_CHARDEV))
return -EINTR;
- mutex_lock(&hvt->outmsg_lock);
+ mutex_lock(&hvt->lock);
+
+ if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
+ ret = -EBADF;
+ goto out_unlock;
+ }
+
if (!hvt->outmsg) {
ret = -EAGAIN;
goto out_unlock;
@@ -68,7 +73,7 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf,
hvt->outmsg_len = 0;
out_unlock:
- mutex_unlock(&hvt->outmsg_lock);
+ mutex_unlock(&hvt->lock);
return ret;
}
@@ -77,19 +82,22 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf,
{
struct hvutil_transport *hvt;
u8 *inmsg;
+ int ret;
hvt = container_of(file->f_op, struct hvutil_transport, fops);
- inmsg = kzalloc(count, GFP_KERNEL);
- if (copy_from_user(inmsg, buf, count)) {
- kfree(inmsg);
- return -EFAULT;
- }
- if (hvt->on_msg(inmsg, count))
- return -EFAULT;
+ inmsg = memdup_user(buf, count);
+ if (IS_ERR(inmsg))
+ return PTR_ERR(inmsg);
+
+ if (hvt->mode == HVUTIL_TRANSPORT_DESTROY)
+ ret = -EBADF;
+ else
+ ret = hvt->on_msg(inmsg, count);
+
kfree(inmsg);
- return count;
+ return ret ? ret : count;
}
static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
@@ -99,6 +107,10 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
hvt = container_of(file->f_op, struct hvutil_transport, fops);
poll_wait(file, &hvt->outmsg_q, wait);
+
+ if (hvt->mode == HVUTIL_TRANSPORT_DESTROY)
+ return POLLERR | POLLHUP;
+
if (hvt->outmsg_len > 0)
return POLLIN | POLLRDNORM;
@@ -108,40 +120,68 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
static int hvt_op_open(struct inode *inode, struct file *file)
{
struct hvutil_transport *hvt;
+ int ret = 0;
+ bool issue_reset = false;
hvt = container_of(file->f_op, struct hvutil_transport, fops);
- /*
- * Switching to CHARDEV mode. We switch bach to INIT when device
- * gets released.
- */
- if (hvt->mode == HVUTIL_TRANSPORT_INIT)
+ mutex_lock(&hvt->lock);
+
+ if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
+ ret = -EBADF;
+ } else if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
+ /*
+ * Switching to CHARDEV mode. We switch bach to INIT when
+ * device gets released.
+ */
hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
+ }
else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
/*
* We're switching from netlink communication to using char
* device. Issue the reset first.
*/
- hvt_reset(hvt);
+ issue_reset = true;
hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
- } else
- return -EBUSY;
+ } else {
+ ret = -EBUSY;
+ }
- return 0;
+ if (issue_reset)
+ hvt_reset(hvt);
+
+ mutex_unlock(&hvt->lock);
+
+ return ret;
+}
+
+static void hvt_transport_free(struct hvutil_transport *hvt)
+{
+ misc_deregister(&hvt->mdev);
+ kfree(hvt->outmsg);
+ kfree(hvt);
}
static int hvt_op_release(struct inode *inode, struct file *file)
{
struct hvutil_transport *hvt;
+ int mode_old;
hvt = container_of(file->f_op, struct hvutil_transport, fops);
- hvt->mode = HVUTIL_TRANSPORT_INIT;
+ mutex_lock(&hvt->lock);
+ mode_old = hvt->mode;
+ if (hvt->mode != HVUTIL_TRANSPORT_DESTROY)
+ hvt->mode = HVUTIL_TRANSPORT_INIT;
/*
* Cleanup message buffers to avoid spurious messages when the daemon
* connects back.
*/
hvt_reset(hvt);
+ mutex_unlock(&hvt->lock);
+
+ if (mode_old == HVUTIL_TRANSPORT_DESTROY)
+ hvt_transport_free(hvt);
return 0;
}
@@ -168,6 +208,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
* Switching to NETLINK mode. Switching to CHARDEV happens when someone
* opens the device.
*/
+ mutex_lock(&hvt->lock);
if (hvt->mode == HVUTIL_TRANSPORT_INIT)
hvt->mode = HVUTIL_TRANSPORT_NETLINK;
@@ -175,6 +216,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
hvt_found->on_msg(msg->data, msg->len);
else
pr_warn("hvt_cn_callback: unexpected netlink message!\n");
+ mutex_unlock(&hvt->lock);
}
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
@@ -182,7 +224,8 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
struct cn_msg *cn_msg;
int ret = 0;
- if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
+ if (hvt->mode == HVUTIL_TRANSPORT_INIT ||
+ hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
return -EINVAL;
} else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
cn_msg = kzalloc(sizeof(*cn_msg) + len, GFP_ATOMIC);
@@ -197,18 +240,26 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
return ret;
}
/* HVUTIL_TRANSPORT_CHARDEV */
- mutex_lock(&hvt->outmsg_lock);
+ mutex_lock(&hvt->lock);
+ if (hvt->mode != HVUTIL_TRANSPORT_CHARDEV) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
if (hvt->outmsg) {
/* Previous message wasn't received */
ret = -EFAULT;
goto out_unlock;
}
hvt->outmsg = kzalloc(len, GFP_KERNEL);
- memcpy(hvt->outmsg, msg, len);
- hvt->outmsg_len = len;
- wake_up_interruptible(&hvt->outmsg_q);
+ if (hvt->outmsg) {
+ memcpy(hvt->outmsg, msg, len);
+ hvt->outmsg_len = len;
+ wake_up_interruptible(&hvt->outmsg_q);
+ } else
+ ret = -ENOMEM;
out_unlock:
- mutex_unlock(&hvt->outmsg_lock);
+ mutex_unlock(&hvt->lock);
return ret;
}
@@ -239,7 +290,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
hvt->mdev.fops = &hvt->fops;
init_waitqueue_head(&hvt->outmsg_q);
- mutex_init(&hvt->outmsg_lock);
+ mutex_init(&hvt->lock);
spin_lock(&hvt_list_lock);
list_add(&hvt->list, &hvt_list);
@@ -265,12 +316,25 @@ err_free_hvt:
void hvutil_transport_destroy(struct hvutil_transport *hvt)
{
+ int mode_old;
+
+ mutex_lock(&hvt->lock);
+ mode_old = hvt->mode;
+ hvt->mode = HVUTIL_TRANSPORT_DESTROY;
+ wake_up_interruptible(&hvt->outmsg_q);
+ mutex_unlock(&hvt->lock);
+
+ /*
+ * In case we were in 'chardev' mode we still have an open fd so we
+ * have to defer freeing the device. Netlink interface can be freed
+ * now.
+ */
spin_lock(&hvt_list_lock);
list_del(&hvt->list);
spin_unlock(&hvt_list_lock);
if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0)
cn_del_callback(&hvt->cn_id);
- misc_deregister(&hvt->mdev);
- kfree(hvt->outmsg);
- kfree(hvt);
+
+ if (mode_old != HVUTIL_TRANSPORT_CHARDEV)
+ hvt_transport_free(hvt);
}
diff --git a/drivers/hv/hv_utils_transport.h b/drivers/hv/hv_utils_transport.h
index 314c76ce1b07..06254a165a18 100644
--- a/drivers/hv/hv_utils_transport.h
+++ b/drivers/hv/hv_utils_transport.h
@@ -25,6 +25,7 @@ enum hvutil_transport_mode {
HVUTIL_TRANSPORT_INIT = 0,
HVUTIL_TRANSPORT_NETLINK,
HVUTIL_TRANSPORT_CHARDEV,
+ HVUTIL_TRANSPORT_DESTROY,
};
struct hvutil_transport {
@@ -38,7 +39,7 @@ struct hvutil_transport {
u8 *outmsg; /* message to the userspace */
int outmsg_len; /* its length */
wait_queue_head_t outmsg_q; /* poll/read wait queue */
- struct mutex outmsg_lock; /* protects outmsg */
+ struct mutex lock; /* protects struct members */
};
struct hvutil_transport *hvutil_transport_init(const char *name,
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 678663e2085f..4ebc796b4f33 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -31,6 +31,11 @@
#include <linux/hyperv.h>
/*
+ * Timeout for services such as KVP and fcopy.
+ */
+#define HV_UTIL_TIMEOUT 30
+
+/*
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
* is set by CPUID(HVCPUID_VERSION_FEATURES).
*/
@@ -496,7 +501,7 @@ extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size);
-extern u16 hv_signal_event(void *con_id);
+extern int hv_signal_event(void *con_id);
extern int hv_synic_alloc(void);
@@ -528,14 +533,9 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
struct kvec *kv_list,
u32 kv_count, bool *signal);
-int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
- u32 buflen);
-
-int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info,
- void *buffer,
- u32 buflen,
- u32 offset, bool *signal);
-
+int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
+ void *buffer, u32 buflen, u32 *buffer_actual_len,
+ u64 *requestid, bool *signal, bool raw);
void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info);
@@ -592,7 +592,7 @@ struct vmbus_connection {
/* List of channels */
struct list_head chn_list;
- spinlock_t channel_lock;
+ struct mutex channel_mutex;
struct workqueue_struct *work_queue;
};
@@ -673,11 +673,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel,
if (!channel)
return;
- if (channel->target_cpu != smp_processor_id())
- smp_call_function_single(channel->target_cpu,
- cb, channel, true);
- else
- cb(channel);
+ smp_call_function_single(channel->target_cpu, cb, channel, true);
}
enum hvutil_device_state {
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 70a1a9a22f87..b53702ce692f 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -112,9 +112,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz,
u32 read_loc = rbi->ring_buffer->read_index;
u32 pending_sz = rbi->ring_buffer->pending_send_sz;
- /*
- * If the other end is not blocked on write don't bother.
- */
+ /* If the other end is not blocked on write don't bother. */
if (pending_sz == 0)
return false;
@@ -128,12 +126,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz,
return false;
}
-/*
- * hv_get_next_write_location()
- *
- * Get the next write location for the specified ring buffer
- *
- */
+/* Get the next write location for the specified ring buffer. */
static inline u32
hv_get_next_write_location(struct hv_ring_buffer_info *ring_info)
{
@@ -142,12 +135,7 @@ hv_get_next_write_location(struct hv_ring_buffer_info *ring_info)
return next;
}
-/*
- * hv_set_next_write_location()
- *
- * Set the next write location for the specified ring buffer
- *
- */
+/* Set the next write location for the specified ring buffer. */
static inline void
hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
u32 next_write_location)
@@ -155,11 +143,7 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
ring_info->ring_buffer->write_index = next_write_location;
}
-/*
- * hv_get_next_read_location()
- *
- * Get the next read location for the specified ring buffer
- */
+/* Get the next read location for the specified ring buffer. */
static inline u32
hv_get_next_read_location(struct hv_ring_buffer_info *ring_info)
{
@@ -169,10 +153,8 @@ hv_get_next_read_location(struct hv_ring_buffer_info *ring_info)
}
/*
- * hv_get_next_readlocation_withoffset()
- *
* Get the next read location + offset for the specified ring buffer.
- * This allows the caller to skip
+ * This allows the caller to skip.
*/
static inline u32
hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
@@ -186,13 +168,7 @@ hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
return next;
}
-/*
- *
- * hv_set_next_read_location()
- *
- * Set the next read location for the specified ring buffer
- *
- */
+/* Set the next read location for the specified ring buffer. */
static inline void
hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
u32 next_read_location)
@@ -201,12 +177,7 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
}
-/*
- *
- * hv_get_ring_buffer()
- *
- * Get the start of the ring buffer
- */
+/* Get the start of the ring buffer. */
static inline void *
hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
{
@@ -214,25 +185,14 @@ hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
}
-/*
- *
- * hv_get_ring_buffersize()
- *
- * Get the size of the ring buffer
- */
+/* Get the size of the ring buffer. */
static inline u32
hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
{
return ring_info->ring_datasize;
}
-/*
- *
- * hv_get_ring_bufferindices()
- *
- * Get the read and write indices as u64 of the specified ring buffer
- *
- */
+/* Get the read and write indices as u64 of the specified ring buffer. */
static inline u64
hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
{
@@ -240,12 +200,8 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
}
/*
- *
- * hv_copyfrom_ringbuffer()
- *
* Helper routine to copy to source from ring buffer.
* Assume there is enough room. Handles wrap-around in src case only!!
- *
*/
static u32 hv_copyfrom_ringbuffer(
struct hv_ring_buffer_info *ring_info,
@@ -277,12 +233,8 @@ static u32 hv_copyfrom_ringbuffer(
/*
- *
- * hv_copyto_ringbuffer()
- *
* Helper routine to copy from source to ring buffer.
* Assume there is enough room. Handles wrap-around in dest case only!!
- *
*/
static u32 hv_copyto_ringbuffer(
struct hv_ring_buffer_info *ring_info,
@@ -308,13 +260,7 @@ static u32 hv_copyto_ringbuffer(
return start_write_offset;
}
-/*
- *
- * hv_ringbuffer_get_debuginfo()
- *
- * Get various debug metrics for the specified ring buffer
- *
- */
+/* Get various debug metrics for the specified ring buffer. */
void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info)
{
@@ -337,13 +283,7 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
}
}
-/*
- *
- * hv_ringbuffer_init()
- *
- *Initialize the ring buffer
- *
- */
+/* Initialize the ring buffer. */
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
void *buffer, u32 buflen)
{
@@ -356,9 +296,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
ring_info->ring_buffer->read_index =
ring_info->ring_buffer->write_index = 0;
- /*
- * Set the feature bit for enabling flow control.
- */
+ /* Set the feature bit for enabling flow control. */
ring_info->ring_buffer->feature_bits.value = 1;
ring_info->ring_size = buflen;
@@ -369,24 +307,12 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
return 0;
}
-/*
- *
- * hv_ringbuffer_cleanup()
- *
- * Cleanup the ring buffer
- *
- */
+/* Cleanup the ring buffer. */
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{
}
-/*
- *
- * hv_ringbuffer_write()
- *
- * Write to the ring buffer
- *
- */
+/* Write to the ring buffer. */
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
struct kvec *kv_list, u32 kv_count, bool *signal)
{
@@ -411,10 +337,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
-
- /* If there is only room for the packet, assume it is full. */
- /* Otherwise, the next time around, we think the ring buffer */
- /* is empty since the read index == write index */
+ /*
+ * If there is only room for the packet, assume it is full.
+ * Otherwise, the next time around, we think the ring buffer
+ * is empty since the read index == write index.
+ */
if (bytes_avail_towrite <= totalbytes_towrite) {
spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return -EAGAIN;
@@ -453,80 +380,59 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
return 0;
}
-
-/*
- *
- * hv_ringbuffer_peek()
- *
- * Read without advancing the read index
- *
- */
-int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
- void *Buffer, u32 buflen)
-{
- u32 bytes_avail_towrite;
- u32 bytes_avail_toread;
- u32 next_read_location = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&Inring_info->ring_lock, flags);
-
- hv_get_ringbuffer_availbytes(Inring_info,
- &bytes_avail_toread,
- &bytes_avail_towrite);
-
- /* Make sure there is something to read */
- if (bytes_avail_toread < buflen) {
-
- spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
-
- return -EAGAIN;
- }
-
- /* Convert to byte offset */
- next_read_location = hv_get_next_read_location(Inring_info);
-
- next_read_location = hv_copyfrom_ringbuffer(Inring_info,
- Buffer,
- buflen,
- next_read_location);
-
- spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
-
- return 0;
-}
-
-
-/*
- *
- * hv_ringbuffer_read()
- *
- * Read and advance the read index
- *
- */
-int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
- u32 buflen, u32 offset, bool *signal)
+int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
+ void *buffer, u32 buflen, u32 *buffer_actual_len,
+ u64 *requestid, bool *signal, bool raw)
{
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
u32 next_read_location = 0;
u64 prev_indices = 0;
unsigned long flags;
+ struct vmpacket_descriptor desc;
+ u32 offset;
+ u32 packetlen;
+ int ret = 0;
if (buflen <= 0)
return -EINVAL;
spin_lock_irqsave(&inring_info->ring_lock, flags);
+ *buffer_actual_len = 0;
+ *requestid = 0;
+
hv_get_ringbuffer_availbytes(inring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
/* Make sure there is something to read */
- if (bytes_avail_toread < buflen) {
- spin_unlock_irqrestore(&inring_info->ring_lock, flags);
+ if (bytes_avail_toread < sizeof(desc)) {
+ /*
+ * No error is set when there is even no header, drivers are
+ * supposed to analyze buffer_actual_len.
+ */
+ goto out_unlock;
+ }
- return -EAGAIN;
+ next_read_location = hv_get_next_read_location(inring_info);
+ next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
+ sizeof(desc),
+ next_read_location);
+
+ offset = raw ? 0 : (desc.offset8 << 3);
+ packetlen = (desc.len8 << 3) - offset;
+ *buffer_actual_len = packetlen;
+ *requestid = desc.trans_id;
+
+ if (bytes_avail_toread < packetlen + offset) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
+ if (packetlen > buflen) {
+ ret = -ENOBUFS;
+ goto out_unlock;
}
next_read_location =
@@ -534,7 +440,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
next_read_location = hv_copyfrom_ringbuffer(inring_info,
buffer,
- buflen,
+ packetlen,
next_read_location);
next_read_location = hv_copyfrom_ringbuffer(inring_info,
@@ -542,17 +448,19 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
sizeof(u64),
next_read_location);
- /* Make sure all reads are done before we update the read index since */
- /* the writer may start writing to the read area once the read index */
- /*is updated */
+ /*
+ * Make sure all reads are done before we update the read index since
+ * the writer may start writing to the read area once the read index
+ * is updated.
+ */
mb();
/* Update the read index */
hv_set_next_read_location(inring_info, next_read_location);
- spin_unlock_irqrestore(&inring_info->ring_lock, flags);
-
*signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info);
- return 0;
+out_unlock:
+ spin_unlock_irqrestore(&inring_info->ring_lock, flags);
+ return ret;
}
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index f19b6f7a467a..328e4c3808e0 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -47,7 +47,6 @@ static struct acpi_device *hv_acpi_dev;
static struct tasklet_struct msg_dpc;
static struct completion probe_event;
-static int irq;
static void hyperv_report_panic(struct pt_regs *regs)
@@ -531,9 +530,9 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
static const uuid_le null_guid;
-static inline bool is_null_guid(const __u8 *guid)
+static inline bool is_null_guid(const uuid_le *guid)
{
- if (memcmp(guid, &null_guid, sizeof(uuid_le)))
+ if (uuid_le_cmp(*guid, null_guid))
return false;
return true;
}
@@ -544,10 +543,10 @@ static inline bool is_null_guid(const __u8 *guid)
*/
static const struct hv_vmbus_device_id *hv_vmbus_get_id(
const struct hv_vmbus_device_id *id,
- const __u8 *guid)
+ const uuid_le *guid)
{
- for (; !is_null_guid(id->guid); id++)
- if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
+ for (; !is_null_guid(&id->guid); id++)
+ if (!uuid_le_cmp(id->guid, *guid))
return id;
return NULL;
@@ -563,7 +562,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
struct hv_driver *drv = drv_to_hv_drv(driver);
struct hv_device *hv_dev = device_to_hv_device(device);
- if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b))
+ if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type))
return 1;
return 0;
@@ -580,7 +579,7 @@ static int vmbus_probe(struct device *child_device)
struct hv_device *dev = device_to_hv_device(child_device);
const struct hv_vmbus_device_id *dev_id;
- dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b);
+ dev_id = hv_vmbus_get_id(drv->id_table, &dev->dev_type);
if (drv->probe) {
ret = drv->probe(dev, dev_id);
if (ret != 0)
@@ -602,23 +601,11 @@ static int vmbus_remove(struct device *child_device)
{
struct hv_driver *drv;
struct hv_device *dev = device_to_hv_device(child_device);
- u32 relid = dev->channel->offermsg.child_relid;
if (child_device->driver) {
drv = drv_to_hv_drv(child_device->driver);
if (drv->remove)
drv->remove(dev);
- else {
- hv_process_channel_removal(dev->channel, relid);
- pr_err("remove not set for driver %s\n",
- dev_name(child_device));
- }
- } else {
- /*
- * We don't have a driver for this device; deal with the
- * rescind message by removing the channel.
- */
- hv_process_channel_removal(dev->channel, relid);
}
return 0;
@@ -653,7 +640,10 @@ static void vmbus_shutdown(struct device *child_device)
static void vmbus_device_release(struct device *device)
{
struct hv_device *hv_dev = device_to_hv_device(device);
+ struct vmbus_channel *channel = hv_dev->channel;
+ hv_process_channel_removal(channel,
+ channel->offermsg.child_relid);
kfree(hv_dev);
}
@@ -835,10 +825,9 @@ static void vmbus_isr(void)
* Here, we
* - initialize the vmbus driver context
* - invoke the vmbus hv main init routine
- * - get the irq resource
* - retrieve the channel offers
*/
-static int vmbus_bus_init(int irq)
+static int vmbus_bus_init(void)
{
int ret;
@@ -867,7 +856,7 @@ static int vmbus_bus_init(int irq)
on_each_cpu(hv_synic_init, NULL, 1);
ret = vmbus_connect();
if (ret)
- goto err_alloc;
+ goto err_connect;
if (vmbus_proto_version > VERSION_WIN7)
cpu_hotplug_disable();
@@ -885,6 +874,8 @@ static int vmbus_bus_init(int irq)
return 0;
+err_connect:
+ on_each_cpu(hv_synic_cleanup, NULL, 1);
err_alloc:
hv_synic_free();
hv_remove_vmbus_irq();
@@ -1031,9 +1022,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
struct resource **prev_res = NULL;
switch (res->type) {
- case ACPI_RESOURCE_TYPE_IRQ:
- irq = res->data.irq.interrupts[0];
- return AE_OK;
/*
* "Address" descriptors are for bus windows. Ignore
@@ -1075,12 +1063,28 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
new_res->start = start;
new_res->end = end;
+ /*
+ * Stick ranges from higher in address space at the front of the list.
+ * If two ranges are adjacent, merge them.
+ */
do {
if (!*old_res) {
*old_res = new_res;
break;
}
+ if (((*old_res)->end + 1) == new_res->start) {
+ (*old_res)->end = new_res->end;
+ kfree(new_res);
+ break;
+ }
+
+ if ((*old_res)->start == new_res->end + 1) {
+ (*old_res)->start = new_res->start;
+ kfree(new_res);
+ break;
+ }
+
if ((*old_res)->end < new_res->start) {
new_res->sibling = *old_res;
if (prev_res)
@@ -1191,6 +1195,23 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
}
EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
+/**
+ * vmbus_cpu_number_to_vp_number() - Map CPU to VP.
+ * @cpu_number: CPU number in Linux terms
+ *
+ * This function returns the mapping between the Linux processor
+ * number and the hypervisor's virtual processor number, useful
+ * in making hypercalls and such that talk about specific
+ * processors.
+ *
+ * Return: Virtual processor number in Hyper-V terms
+ */
+int vmbus_cpu_number_to_vp_number(int cpu_number)
+{
+ return hv_context.vp_index[cpu_number];
+}
+EXPORT_SYMBOL_GPL(vmbus_cpu_number_to_vp_number);
+
static int vmbus_acpi_add(struct acpi_device *device)
{
acpi_status result;
@@ -1275,7 +1296,7 @@ static int __init hv_acpi_init(void)
init_completion(&probe_event);
/*
- * Get irq resources first.
+ * Get ACPI resources first.
*/
ret = acpi_bus_register_driver(&vmbus_acpi_driver);
@@ -1288,12 +1309,7 @@ static int __init hv_acpi_init(void)
goto cleanup;
}
- if (irq <= 0) {
- ret = -ENODEV;
- goto cleanup;
- }
-
- ret = vmbus_bus_init(irq);
+ ret = vmbus_bus_init();
if (ret)
goto cleanup;
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index 738681983284..68c350c704fb 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -30,7 +30,6 @@
#include <linux/watchdog.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
-#include <linux/kref.h>
#include <linux/slab.h>
#include "sch56xx-common.h"
@@ -67,7 +66,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
struct sch56xx_watchdog_data {
u16 addr;
struct mutex *io_lock;
- struct kref kref;
struct watchdog_info wdinfo;
struct watchdog_device wddev;
u8 watchdog_preset;
@@ -258,15 +256,6 @@ EXPORT_SYMBOL(sch56xx_read_virtual_reg12);
* Watchdog routines
*/
-/* Release our data struct when we're unregistered *and*
- all references to our watchdog device are released */
-static void watchdog_release_resources(struct kref *r)
-{
- struct sch56xx_watchdog_data *data =
- container_of(r, struct sch56xx_watchdog_data, kref);
- kfree(data);
-}
-
static int watchdog_set_timeout(struct watchdog_device *wddev,
unsigned int timeout)
{
@@ -395,28 +384,12 @@ static int watchdog_stop(struct watchdog_device *wddev)
return 0;
}
-static void watchdog_ref(struct watchdog_device *wddev)
-{
- struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
-
- kref_get(&data->kref);
-}
-
-static void watchdog_unref(struct watchdog_device *wddev)
-{
- struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
-
- kref_put(&data->kref, watchdog_release_resources);
-}
-
static const struct watchdog_ops watchdog_ops = {
.owner = THIS_MODULE,
.start = watchdog_start,
.stop = watchdog_stop,
.ping = watchdog_trigger,
.set_timeout = watchdog_set_timeout,
- .ref = watchdog_ref,
- .unref = watchdog_unref,
};
struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
@@ -448,7 +421,6 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
data->addr = addr;
data->io_lock = io_lock;
- kref_init(&data->kref);
strlcpy(data->wdinfo.identity, "sch56xx watchdog",
sizeof(data->wdinfo.identity));
@@ -494,8 +466,7 @@ EXPORT_SYMBOL(sch56xx_watchdog_register);
void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
{
watchdog_unregister_device(&data->wddev);
- kref_put(&data->kref, watchdog_release_resources);
- /* Don't touch data after this it may have been free-ed! */
+ kfree(data);
}
EXPORT_SYMBOL(sch56xx_watchdog_unregister);
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 6c8921140f02..c85935f3525a 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -8,7 +8,7 @@ menuconfig CORESIGHT
This framework provides a kernel interface for the CoreSight debug
and trace drivers to register themselves with. It's intended to build
a topological view of the CoreSight components based on a DT
- specification and configure the right serie of components when a
+ specification and configure the right series of components when a
trace source gets enabled.
if CORESIGHT
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index e25492137d8b..93738dfbf631 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -548,7 +548,7 @@ static int coresight_name_match(struct device *dev, void *data)
to_match = data;
i_csdev = to_coresight_device(dev);
- if (!strcmp(to_match, dev_name(&i_csdev->dev)))
+ if (to_match && !strcmp(to_match, dev_name(&i_csdev->dev)))
return 1;
return 0;
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 899bede81b31..9d233bbde5e1 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -617,6 +617,10 @@ const struct i2c_algorithm i2c_bit_algo = {
};
EXPORT_SYMBOL(i2c_bit_algo);
+const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
+ .flags = I2C_AQ_NO_CLK_STRETCH,
+};
+
/*
* registering functions to load algorithms at runtime
*/
@@ -635,6 +639,8 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
/* register new adapter to i2c module... */
adap->algo = &i2c_bit_algo;
adap->retries = 3;
+ if (bit_adap->getscl == NULL)
+ adap->quirks = &i2c_bit_quirk_no_clk_stretch;
ret = add_adapter(adap);
if (ret < 0)
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7b0aa82ea38b..0299dfa746a3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -516,7 +516,7 @@ config I2C_EFM32
config I2C_EG20T
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
- depends on PCI && (X86_32 || COMPILE_TEST)
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
This driver is for PCH(Platform controller Hub) I2C of EG20T which
is an IOH(Input/Output Hub) for x86 embedded processor.
@@ -532,6 +532,7 @@ config I2C_EG20T
config I2C_EMEV2
tristate "EMMA Mobile series I2C adapter"
depends on HAVE_CLK
+ select I2C_SLAVE
help
If you say yes to this option, support will be included for the
I2C interface on the Renesas Electronics EM/EV family of processors.
@@ -963,11 +964,11 @@ config I2C_XILINX
will be called xilinx_i2c.
config I2C_XLR
- tristate "XLR I2C support"
- depends on CPU_XLR
+ tristate "Netlogic XLR and Sigma Designs I2C support"
+ depends on CPU_XLR || ARCH_TANGOX
help
This driver enables support for the on-chip I2C interface of
- the Netlogic XLR/XLS MIPS processors.
+ the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
This driver can also be built as a module. If so, the module
will be called i2c-xlr.
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 10835d1f559b..921d32bfcda8 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -64,6 +64,8 @@
#define AT91_TWI_IADR 0x000c /* Internal Address Register */
#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
+#define AT91_TWI_CWGR_HOLD_MAX 0x1f
+#define AT91_TWI_CWGR_HOLD(x) (((x) & AT91_TWI_CWGR_HOLD_MAX) << 24)
#define AT91_TWI_SR 0x0020 /* Status Register */
#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */
@@ -110,6 +112,7 @@ struct at91_twi_pdata {
unsigned clk_offset;
bool has_unre_flag;
bool has_alt_cmd;
+ bool has_hold_field;
struct at_dma_slave dma_slave;
};
@@ -187,10 +190,11 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev)
*/
static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
{
- int ckdiv, cdiv, div;
+ int ckdiv, cdiv, div, hold = 0;
struct at91_twi_pdata *pdata = dev->pdata;
int offset = pdata->clk_offset;
int max_ckdiv = pdata->clk_max_div;
+ u32 twd_hold_time_ns = 0;
div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
2 * twi_clk) - offset);
@@ -204,8 +208,33 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
cdiv = 255;
}
- dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
- dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+ if (pdata->has_hold_field) {
+ of_property_read_u32(dev->dev->of_node, "i2c-sda-hold-time-ns",
+ &twd_hold_time_ns);
+
+ /*
+ * hold time = HOLD + 3 x T_peripheral_clock
+ * Use clk rate in kHz to prevent overflows when computing
+ * hold.
+ */
+ hold = DIV_ROUND_UP(twd_hold_time_ns
+ * (clk_get_rate(dev->clk) / 1000), 1000000);
+ hold -= 3;
+ if (hold < 0)
+ hold = 0;
+ if (hold > AT91_TWI_CWGR_HOLD_MAX) {
+ dev_warn(dev->dev,
+ "HOLD field set to its maximum value (%d instead of %d)\n",
+ AT91_TWI_CWGR_HOLD_MAX, hold);
+ hold = AT91_TWI_CWGR_HOLD_MAX;
+ }
+ }
+
+ dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
+ | AT91_TWI_CWGR_HOLD(hold);
+
+ dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns)\n",
+ cdiv, ckdiv, hold, twd_hold_time_ns);
}
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
@@ -797,6 +826,7 @@ static struct at91_twi_pdata at91rm9200_config = {
.clk_offset = 3,
.has_unre_flag = true,
.has_alt_cmd = false,
+ .has_hold_field = false,
};
static struct at91_twi_pdata at91sam9261_config = {
@@ -804,6 +834,7 @@ static struct at91_twi_pdata at91sam9261_config = {
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
+ .has_hold_field = false,
};
static struct at91_twi_pdata at91sam9260_config = {
@@ -811,6 +842,7 @@ static struct at91_twi_pdata at91sam9260_config = {
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
+ .has_hold_field = false,
};
static struct at91_twi_pdata at91sam9g20_config = {
@@ -818,6 +850,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
+ .has_hold_field = false,
};
static struct at91_twi_pdata at91sam9g10_config = {
@@ -825,6 +858,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
+ .has_hold_field = false,
};
static const struct platform_device_id at91_twi_devtypes[] = {
@@ -854,6 +888,15 @@ static struct at91_twi_pdata at91sam9x5_config = {
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static struct at91_twi_pdata sama5d4_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = true,
};
static struct at91_twi_pdata sama5d2_config = {
@@ -861,6 +904,7 @@ static struct at91_twi_pdata sama5d2_config = {
.clk_offset = 4,
.has_unre_flag = true,
.has_alt_cmd = true,
+ .has_hold_field = true,
};
static const struct of_device_id atmel_twi_dt_ids[] = {
@@ -883,6 +927,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
.compatible = "atmel,at91sam9x5-i2c",
.data = &at91sam9x5_config,
}, {
+ .compatible = "atmel,sama5d4-i2c",
+ .data = &sama5d4_config,
+ }, {
.compatible = "atmel,sama5d2-i2c",
.data = &sama5d2_config,
}, {
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 3032b89ac60b..818b051d25e6 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -222,6 +222,15 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
.functionality = bcm2835_i2c_func,
};
+/*
+ * This HW was reported to have problems with clock stretching:
+ * http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html
+ * https://www.raspberrypi.org/forums/viewtopic.php?p=146272
+ */
+static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
+ .flags = I2C_AQ_NO_CLK_STRETCH,
+};
+
static int bcm2835_i2c_probe(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev;
@@ -293,6 +302,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
adap->algo = &bcm2835_i2c_algo;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
+ adap->quirks = &bcm2835_i2c_quirks;
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 8e9637eea512..3711df1d4526 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -25,13 +25,16 @@
#include <linux/version.h>
#define N_DATA_REGS 8
-#define N_DATA_BYTES (N_DATA_REGS * 4)
-/* BSC count register field definitions */
-#define BSC_CNT_REG1_MASK 0x0000003f
-#define BSC_CNT_REG1_SHIFT 0
-#define BSC_CNT_REG2_MASK 0x00000fc0
-#define BSC_CNT_REG2_SHIFT 6
+/*
+ * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register
+ * size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per
+ * data register whereas STB SoCs use 4 byte per data register transfer,
+ * account for this difference in total count per transaction and mask to
+ * use.
+ */
+#define BSC_CNT_REG1_MASK(nb) (nb == 1 ? GENMASK(3, 0) : GENMASK(5, 0))
+#define BSC_CNT_REG1_SHIFT 0
/* BSC CTL register field definitions */
#define BSC_CTL_REG_DTF_MASK 0x00000003
@@ -41,7 +44,7 @@
#define BSC_CTL_REG_INT_EN_SHIFT 6
#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080
-/* BSC_IIC_ENABLE r/w enable and interrupt field defintions */
+/* BSC_IIC_ENABLE r/w enable and interrupt field definitions */
#define BSC_IIC_EN_RESTART_MASK 0x00000040
#define BSC_IIC_EN_NOSTART_MASK 0x00000020
#define BSC_IIC_EN_NOSTOP_MASK 0x00000010
@@ -169,6 +172,7 @@ struct brcmstb_i2c_dev {
struct completion done;
bool is_suspended;
u32 clk_freq_hz;
+ int data_regsz;
};
/* register accessors for both be and le cpu arch */
@@ -186,6 +190,16 @@ struct brcmstb_i2c_dev {
#define bsc_writel(_dev, _val, _reg) \
__bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg))
+static inline int brcmstb_i2c_get_xfersz(struct brcmstb_i2c_dev *dev)
+{
+ return (N_DATA_REGS * dev->data_regsz);
+}
+
+static inline int brcmstb_i2c_get_data_regsz(struct brcmstb_i2c_dev *dev)
+{
+ return dev->data_regsz;
+}
+
static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev,
bool int_en)
{
@@ -323,14 +337,16 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
u8 *buf, unsigned int len,
struct i2c_msg *pmsg)
{
- int cnt, byte, rc;
+ int cnt, byte, i, rc;
enum bsc_xfer_cmd cmd;
u32 ctl_reg;
struct bsc_regs *pi2creg = dev->bsc_regmap;
int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
+ int data_regsz = brcmstb_i2c_get_data_regsz(dev);
+ int xfersz = brcmstb_i2c_get_xfersz(dev);
/* see if the transaction needs to check NACK conditions */
- if (no_ack || len <= N_DATA_BYTES) {
+ if (no_ack || len <= xfersz) {
cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
: CMD_WR_NOACK;
pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
@@ -348,20 +364,22 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK;
/* set the read/write length */
- bsc_writel(dev, BSC_CNT_REG1_MASK & (len << BSC_CNT_REG1_SHIFT),
- cnt_reg);
+ bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) &
+ (len << BSC_CNT_REG1_SHIFT), cnt_reg);
/* Write data into data_in register */
+
if (cmd == CMD_WR || cmd == CMD_WR_NOACK) {
- for (cnt = 0; cnt < len; cnt += 4) {
+ for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
u32 word = 0;
- for (byte = 0; byte < 4; byte++) {
- word >>= 8;
+ for (byte = 0; byte < data_regsz; byte++) {
+ word >>= BITS_PER_BYTE;
if ((cnt + byte) < len)
- word |= buf[cnt + byte] << 24;
+ word |= buf[cnt + byte] <<
+ (BITS_PER_BYTE * (data_regsz - 1));
}
- bsc_writel(dev, word, data_in[cnt >> 2]);
+ bsc_writel(dev, word, data_in[i]);
}
}
@@ -373,14 +391,15 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
return rc;
}
+ /* Read data from data_out register */
if (cmd == CMD_RD || cmd == CMD_RD_NOACK) {
- for (cnt = 0; cnt < len; cnt += 4) {
- u32 data = bsc_readl(dev, data_out[cnt >> 2]);
+ for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
+ u32 data = bsc_readl(dev, data_out[i]);
- for (byte = 0; byte < 4 &&
+ for (byte = 0; byte < data_regsz &&
(byte + cnt) < len; byte++) {
buf[cnt + byte] = data & 0xff;
- data >>= 8;
+ data >>= BITS_PER_BYTE;
}
}
}
@@ -448,6 +467,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
int bytes_to_xfer;
u8 *tmp_buf;
int len = 0;
+ int xfersz = brcmstb_i2c_get_xfersz(dev);
if (dev->is_suspended)
return -EBUSY;
@@ -482,9 +502,9 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
/* Perform data transfer */
while (len) {
- bytes_to_xfer = min(len, N_DATA_BYTES);
+ bytes_to_xfer = min(len, xfersz);
- if (len <= N_DATA_BYTES && i == (num - 1))
+ if (len <= xfersz && i == (num - 1))
brcmstb_set_i2c_start_stop(dev,
~(COND_START_STOP));
@@ -542,8 +562,12 @@ static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev)
static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev)
{
- /* 4 byte data register */
- dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK;
+ if (brcmstb_i2c_get_data_regsz(dev) == sizeof(u32))
+ /* set 4 byte data in/out xfers */
+ dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK;
+ else
+ dev->bsc_regmap->ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK;
+
bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg);
/* set bus speed */
brcmstb_i2c_set_bus_speed(dev);
@@ -608,6 +632,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
dev->clk_freq_hz = bsc_clk[0].hz;
}
+ /* set the data in/out register size for compatible SoCs */
+ if (of_device_is_compatible(dev->device->of_node,
+ "brcmstb,brcmper-i2c"))
+ dev->data_regsz = sizeof(u8);
+ else
+ dev->data_regsz = sizeof(u32);
+
brcmstb_i2c_set_bsc_reg_defaults(dev);
/* Add the i2c adapter */
@@ -674,6 +705,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend,
static const struct of_device_id brcmstb_i2c_of_match[] = {
{.compatible = "brcm,brcmstb-i2c"},
+ {.compatible = "brcm,brcmper-i2c"},
{},
};
MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match);
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 84deed6571bd..6b08d1607b7a 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/pm_runtime.h>
/* Register offsets for the I2C device. */
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
@@ -96,6 +97,8 @@
CDNS_I2C_IXR_COMP)
#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
+/* timeout for pm runtime autosuspend */
+#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
#define CDNS_I2C_FIFO_DEPTH 16
/* FIFO depth at which the DATA interrupt occurs */
@@ -128,7 +131,6 @@
* @xfer_done: Transfer complete status
* @p_send_buf: Pointer to transmit buffer
* @p_recv_buf: Pointer to receive buffer
- * @suspended: Flag holding the device's PM status
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer
@@ -141,6 +143,7 @@
* @quirks: flag for broken hold bit usage in r1p10
*/
struct cdns_i2c {
+ struct device *dev;
void __iomem *membase;
struct i2c_adapter adap;
struct i2c_msg *p_msg;
@@ -148,7 +151,6 @@ struct cdns_i2c {
struct completion xfer_done;
unsigned char *p_send_buf;
unsigned char *p_recv_buf;
- u8 suspended;
unsigned int send_count;
unsigned int recv_count;
unsigned int curr_recv_count;
@@ -569,9 +571,14 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
struct cdns_i2c *id = adap->algo_data;
bool hold_quirk;
+ ret = pm_runtime_get_sync(id->dev);
+ if (ret < 0)
+ return ret;
/* Check if the bus is free */
- if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA)
- return -EAGAIN;
+ if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
+ ret = -EAGAIN;
+ goto out;
+ }
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
/*
@@ -590,7 +597,8 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
if (msgs[count].flags & I2C_M_RD) {
dev_warn(adap->dev.parent,
"Can't do repeated start after a receive message\n");
- return -EOPNOTSUPP;
+ ret = -EOPNOTSUPP;
+ goto out;
}
}
id->bus_hold_flag = 1;
@@ -608,20 +616,26 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
ret = cdns_i2c_process_msg(id, msgs, adap);
if (ret)
- return ret;
+ goto out;
/* Report the other error interrupts to application */
if (id->err_status) {
cdns_i2c_master_reset(adap);
- if (id->err_status & CDNS_I2C_IXR_NACK)
- return -ENXIO;
-
- return -EIO;
+ if (id->err_status & CDNS_I2C_IXR_NACK) {
+ ret = -ENXIO;
+ goto out;
+ }
+ ret = -EIO;
+ goto out;
}
}
- return num;
+ ret = num;
+out:
+ pm_runtime_mark_last_busy(id->dev);
+ pm_runtime_put_autosuspend(id->dev);
+ return ret;
}
/**
@@ -760,7 +774,7 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
struct clk_notifier_data *ndata = data;
struct cdns_i2c *id = to_cdns_i2c(nb);
- if (id->suspended)
+ if (pm_runtime_suspended(id->dev))
return NOTIFY_OK;
switch (event) {
@@ -808,14 +822,12 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
*
* Return: 0 always
*/
-static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
+static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev = container_of(_dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
clk_disable(xi2c->clk);
- xi2c->suspended = 1;
return 0;
}
@@ -828,26 +840,25 @@ static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
*
* Return: 0 on success and error value on error
*/
-static int __maybe_unused cdns_i2c_resume(struct device *_dev)
+static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
{
- struct platform_device *pdev = container_of(_dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
int ret;
ret = clk_enable(xi2c->clk);
if (ret) {
- dev_err(_dev, "Cannot enable clock.\n");
+ dev_err(dev, "Cannot enable clock.\n");
return ret;
}
- xi2c->suspended = 0;
-
return 0;
}
-static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend,
- cdns_i2c_resume);
+static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
+ cdns_i2c_runtime_resume, NULL)
+};
static const struct cdns_platform_data r1p10_i2c_def = {
.quirks = CDNS_I2C_BROKEN_HOLD_BIT,
@@ -881,6 +892,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (!id)
return -ENOMEM;
+ id->dev = &pdev->dev;
platform_set_drvdata(pdev, id);
match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node);
@@ -913,10 +925,14 @@ static int cdns_i2c_probe(struct platform_device *pdev)
return PTR_ERR(id->clk);
}
ret = clk_prepare_enable(id->clk);
- if (ret) {
+ if (ret)
dev_err(&pdev->dev, "Unable to enable clock.\n");
- return ret;
- }
+
+ pm_runtime_enable(id->dev);
+ pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(id->dev);
+ pm_runtime_set_active(id->dev);
+
id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
@@ -966,6 +982,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
err_clk_dis:
clk_disable_unprepare(id->clk);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return ret;
}
@@ -984,6 +1002,7 @@ static int cdns_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&id->adap);
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
clk_disable_unprepare(id->clk);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index de7fbbb374cd..ba9732c236c5 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -271,6 +271,17 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
enable ? "en" : "dis");
}
+static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
+{
+ /*
+ * Clock is not necessary if we got LCNT/HCNT values directly from
+ * the platform code.
+ */
+ if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
+ return 0;
+ return dev->get_clk_rate_khz(dev);
+}
+
/**
* i2c_dw_init() - initialize the designware i2c master hardware
* @dev: device private data
@@ -281,7 +292,6 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
*/
int i2c_dw_init(struct dw_i2c_dev *dev)
{
- u32 input_clock_khz;
u32 hcnt, lcnt;
u32 reg;
u32 sda_falling_time, scl_falling_time;
@@ -295,8 +305,6 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
}
}
- input_clock_khz = dev->get_clk_rate_khz(dev);
-
reg = dw_readl(dev, DW_IC_COMP_TYPE);
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
/* Configure register endianess access */
@@ -325,12 +333,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt;
} else {
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
4700, /* tLOW = 4.7 us */
scl_falling_time,
0); /* No offset */
@@ -344,12 +352,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
} else {
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
1300, /* tLOW = 1.3 us */
scl_falling_time,
0); /* No offset */
@@ -860,6 +868,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
snprintf(adap->name, sizeof(adap->name),
"Synopsys DesignWare I2C adapter");
+ adap->retries = 3;
adap->algo = &i2c_dw_algo;
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index 1543d35d228d..7368be000c96 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -162,7 +162,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
#ifdef CONFIG_PM
static int i2c_dw_pci_suspend(struct device *dev)
{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
i2c_dw_disable(pci_get_drvdata(pdev));
return 0;
@@ -170,7 +170,7 @@ static int i2c_dw_pci_suspend(struct device *dev)
static int i2c_dw_pci_resume(struct device *dev)
{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
return i2c_dw_init(pci_get_drvdata(pdev));
}
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index bf72ae740fc1..438f1b4964c0 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -123,6 +123,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "80860F41", 0 },
{ "808622C1", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
+ { "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ }
};
@@ -134,6 +135,18 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
}
#endif
+static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
+{
+ if (IS_ERR(i_dev->clk))
+ return PTR_ERR(i_dev->clk);
+
+ if (prepare)
+ return clk_prepare_enable(i_dev->clk);
+
+ clk_disable_unprepare(i_dev->clk);
+ return 0;
+}
+
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -206,16 +219,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
dev->clk = devm_clk_get(&pdev->dev, NULL);
- dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
- if (IS_ERR(dev->clk))
- return PTR_ERR(dev->clk);
- clk_prepare_enable(dev->clk);
+ if (!i2c_dw_plat_prepare_clk(dev, true)) {
+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
- if (!dev->sda_hold_time && ht) {
- u32 ic_clk = dev->get_clk_rate_khz(dev);
-
- dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
- 1000000);
+ if (!dev->sda_hold_time && ht)
+ dev->sda_hold_time = div_u64(
+ (u64)dev->get_clk_rate_khz(dev) * ht + 500000,
+ 1000000);
}
if (!dev->tx_fifo_depth) {
@@ -297,7 +307,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
i2c_dw_disable(i_dev);
- clk_disable_unprepare(i_dev->clk);
+ i2c_dw_plat_prepare_clk(i_dev, false);
return 0;
}
@@ -307,7 +317,7 @@ static int dw_i2c_plat_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
- clk_prepare_enable(i_dev->clk);
+ i2c_dw_plat_prepare_clk(i_dev, true);
if (!i_dev->pm_runtime_disabled)
i2c_dw_init(i_dev);
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 76e699f9ed97..137125b5eae7 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -795,6 +795,7 @@ static int pch_i2c_probe(struct pci_dev *pdev,
/* base_addr + offset; */
adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
+ pch_adap->dev.of_node = pdev->dev.of_node;
pch_adap->dev.parent = &pdev->dev;
pch_i2c_init(&adap_info->pch_data[i]);
diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c
index 192ef6b50c79..96bb4e749012 100644
--- a/drivers/i2c/busses/i2c-emev2.c
+++ b/drivers/i2c/busses/i2c-emev2.c
@@ -71,6 +71,7 @@ struct em_i2c_device {
struct i2c_adapter adap;
struct completion msg_done;
struct clk *sclk;
+ struct i2c_client *slave;
};
static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
@@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
return num;
}
+static bool em_i2c_slave_irq(struct em_i2c_device *priv)
+{
+ u8 status, value;
+ enum i2c_slave_event event;
+ int ret;
+
+ if (!priv->slave)
+ return false;
+
+ status = readb(priv->base + I2C_OFS_IICSE0);
+
+ /* Extension code, do not participate */
+ if (status & I2C_BIT_EXC0) {
+ em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+ return true;
+ }
+
+ /* Stop detected, we don't know if it's for slave or master */
+ if (status & I2C_BIT_SPD0) {
+ /* Notify slave device */
+ i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
+ /* Pretend we did not handle the interrupt */
+ return false;
+ }
+
+ /* Only handle interrupts addressed to us */
+ if (!(status & I2C_BIT_COI0))
+ return false;
+
+ /* Enable stop interrupts */
+ em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0);
+
+ /* Transmission or Reception */
+ if (status & I2C_BIT_TRC0) {
+ if (status & I2C_BIT_ACKD0) {
+ /* 9 bit interrupt mode */
+ em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0);
+
+ /* Send data */
+ event = status & I2C_BIT_STD0 ?
+ I2C_SLAVE_READ_REQUESTED :
+ I2C_SLAVE_READ_PROCESSED;
+ i2c_slave_event(priv->slave, event, &value);
+ writeb(value, priv->base + I2C_OFS_IIC0);
+ } else {
+ /* NACK, stop transmitting */
+ em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+ }
+ } else {
+ /* 8 bit interrupt mode */
+ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0,
+ I2C_OFS_IICC0);
+ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0,
+ I2C_OFS_IICC0);
+
+ if (status & I2C_BIT_STD0) {
+ i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED,
+ &value);
+ } else {
+ /* Recv data */
+ value = readb(priv->base + I2C_OFS_IIC0);
+ ret = i2c_slave_event(priv->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &value);
+ if (ret < 0)
+ em_clear_set_bit(priv, I2C_BIT_ACKE0, 0,
+ I2C_OFS_IICC0);
+ }
+ }
+
+ return true;
+}
+
static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id)
{
struct em_i2c_device *priv = dev_id;
+ if (em_i2c_slave_irq(priv))
+ return IRQ_HANDLED;
+
complete(&priv->msg_done);
+
return IRQ_HANDLED;
}
static u32 em_i2c_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
+}
+
+static int em_i2c_reg_slave(struct i2c_client *slave)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+ if (priv->slave)
+ return -EBUSY;
+
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ priv->slave = slave;
+
+ /* Set slave address */
+ writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0);
+
+ return 0;
+}
+
+static int em_i2c_unreg_slave(struct i2c_client *slave)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+ WARN_ON(!priv->slave);
+
+ writeb(0, priv->base + I2C_OFS_SVA0);
+
+ priv->slave = NULL;
+
+ return 0;
}
static struct i2c_algorithm em_i2c_algo = {
.master_xfer = em_i2c_xfer,
.functionality = em_i2c_func,
+ .reg_slave = em_i2c_reg_slave,
+ .unreg_slave = em_i2c_unreg_slave,
};
static int em_i2c_probe(struct platform_device *pdev)
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index ab492301581a..b6c080334297 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -99,7 +99,7 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
#endif
/* Bus timings (in ns) for bit-banging */
-static struct i2c_timings {
+static struct ibm_iic_timings {
unsigned int hd_sta;
unsigned int su_sto;
unsigned int low;
@@ -241,7 +241,7 @@ static int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask)
static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
{
volatile struct iic_regs __iomem *iic = dev->vaddr;
- const struct i2c_timings* t = &timings[dev->fast_mode ? 1 : 0];
+ const struct ibm_iic_timings *t = &timings[dev->fast_mode ? 1 : 0];
u8 mask, v, sda;
int i, res;
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index 3795fe130ef2..379ef9c31664 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -151,10 +151,11 @@
#define INT_FIFO_EMPTYING BIT(12)
#define INT_TRANSACTION_DONE BIT(15)
#define INT_SLAVE_EVENT BIT(16)
+#define INT_MASTER_HALTED BIT(17)
#define INT_TIMING BIT(18)
+#define INT_STOP_DETECTED BIT(19)
#define INT_FIFO_FULL_FILLING (INT_FIFO_FULL | INT_FIFO_FILLING)
-#define INT_FIFO_EMPTY_EMPTYING (INT_FIFO_EMPTY | INT_FIFO_EMPTYING)
/* Level interrupts need clearing after handling instead of before */
#define INT_LEVEL 0x01e00
@@ -177,7 +178,8 @@
INT_FIFO_FULL | \
INT_FIFO_FILLING | \
INT_FIFO_EMPTY | \
- INT_FIFO_EMPTYING)
+ INT_MASTER_HALTED | \
+ INT_STOP_DETECTED)
#define INT_ENABLE_MASK_WAITSTOP (INT_SLAVE_EVENT | \
INT_ADDR_ACK_ERR | \
@@ -511,7 +513,17 @@ static void img_i2c_soft_reset(struct img_i2c *i2c)
SCB_CONTROL_CLK_ENABLE | SCB_CONTROL_SOFT_RESET);
}
-/* enable or release transaction halt for control of repeated starts */
+/*
+ * Enable or release transaction halt for control of repeated starts.
+ * In version 3.3 of the IP when transaction halt is set, an interrupt
+ * will be generated after each byte of a transfer instead of after
+ * every transfer but before the stop bit.
+ * Due to this behaviour we have to be careful that every time we
+ * release the transaction halt we have to re-enable it straight away
+ * so that we only process a single byte, not doing so will result in
+ * all remaining bytes been processed and a stop bit being issued,
+ * which will prevent us having a repeated start.
+ */
static void img_i2c_transaction_halt(struct img_i2c *i2c, bool t_halt)
{
u32 val;
@@ -580,7 +592,6 @@ static void img_i2c_read(struct img_i2c *i2c)
img_i2c_writel(i2c, SCB_READ_ADDR_REG, i2c->msg.addr);
img_i2c_writel(i2c, SCB_READ_COUNT_REG, i2c->msg.len);
- img_i2c_transaction_halt(i2c, false);
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
}
@@ -594,7 +605,6 @@ static void img_i2c_write(struct img_i2c *i2c)
img_i2c_writel(i2c, SCB_WRITE_ADDR_REG, i2c->msg.addr);
img_i2c_writel(i2c, SCB_WRITE_COUNT_REG, i2c->msg.len);
- img_i2c_transaction_halt(i2c, false);
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
img_i2c_write_fifo(i2c);
@@ -750,7 +760,9 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
next_cmd = CMD_RET_ACK;
break;
case CMD_RET_ACK:
- if (i2c->line_status & LINESTAT_ACK_DET) {
+ if (i2c->line_status & LINESTAT_ACK_DET ||
+ (i2c->line_status & LINESTAT_NACK_DET &&
+ i2c->msg.flags & I2C_M_IGNORE_NAK)) {
if (i2c->msg.len == 0) {
next_cmd = CMD_GEN_STOP;
} else if (i2c->msg.flags & I2C_M_RD) {
@@ -858,34 +870,42 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c,
/* Enable transaction halt on start bit */
if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) {
- img_i2c_transaction_halt(i2c, true);
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
/* we're no longer interested in the slave event */
i2c->int_enable &= ~INT_SLAVE_EVENT;
}
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
+ if (int_status & INT_STOP_DETECTED) {
+ /* Drain remaining data in FIFO and complete transaction */
+ if (i2c->msg.flags & I2C_M_RD)
+ img_i2c_read_fifo(i2c);
+ return ISR_COMPLETE(0);
+ }
+
if (i2c->msg.flags & I2C_M_RD) {
- if (int_status & INT_FIFO_FULL_FILLING) {
+ if (int_status & (INT_FIFO_FULL_FILLING | INT_MASTER_HALTED)) {
img_i2c_read_fifo(i2c);
if (i2c->msg.len == 0)
return ISR_WAITSTOP;
}
} else {
- if (int_status & INT_FIFO_EMPTY_EMPTYING) {
- /*
- * The write fifo empty indicates that we're in the
- * last byte so it's safe to start a new write
- * transaction without losing any bytes from the
- * previous one.
- * see 2.3.7 Repeated Start Transactions.
- */
+ if (int_status & (INT_FIFO_EMPTY | INT_MASTER_HALTED)) {
if ((int_status & INT_FIFO_EMPTY) &&
i2c->msg.len == 0)
return ISR_WAITSTOP;
img_i2c_write_fifo(i2c);
}
}
+ if (int_status & INT_MASTER_HALTED) {
+ /*
+ * Release and then enable transaction halt, to
+ * allow only a single byte to proceed.
+ */
+ img_i2c_transaction_halt(i2c, false);
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+ }
return 0;
}
@@ -1017,20 +1037,23 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
return -EIO;
for (i = 0; i < num; i++) {
- if (likely(msgs[i].len))
- continue;
/*
* 0 byte reads are not possible because the slave could try
* and pull the data line low, preventing a stop bit.
*/
- if (unlikely(msgs[i].flags & I2C_M_RD))
+ if (!msgs[i].len && msgs[i].flags & I2C_M_RD)
return -EIO;
/*
* 0 byte writes are possible and used for probing, but we
* cannot do them in automatic mode, so use atomic mode
* instead.
+ *
+ * Also, the I2C_M_IGNORE_NAK mode can only be implemented
+ * in atomic mode.
*/
- atomic = true;
+ if (!msgs[i].len ||
+ (msgs[i].flags & I2C_M_IGNORE_NAK))
+ atomic = true;
}
ret = clk_prepare_enable(i2c->scb_clk);
@@ -1069,12 +1092,31 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
- if (atomic)
+ if (atomic) {
img_i2c_atomic_start(i2c);
- else if (msg->flags & I2C_M_RD)
- img_i2c_read(i2c);
- else
- img_i2c_write(i2c);
+ } else {
+ /*
+ * Enable transaction halt if not the last message in
+ * the queue so that we can control repeated starts.
+ */
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+
+ if (msg->flags & I2C_M_RD)
+ img_i2c_read(i2c);
+ else
+ img_i2c_write(i2c);
+
+ /*
+ * Release and then enable transaction halt, to
+ * allow only a single byte to proceed.
+ * This doesn't have an effect on the initial transfer
+ * but will allow the following transfers to start
+ * processing if the previous transfer was marked as
+ * complete while the i2c block was halted.
+ */
+ img_i2c_transaction_halt(i2c, false);
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+ }
spin_unlock_irqrestore(&i2c->lock, flags);
time_left = wait_for_completion_timeout(&i2c->msg_complete,
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d4d853680ae4..a2b132cef717 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -29,9 +29,6 @@
*
*/
-/** Includes *******************************************************************
-*******************************************************************************/
-
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -53,12 +50,10 @@
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/sched.h>
#include <linux/slab.h>
-/** Defines ********************************************************************
-*******************************************************************************/
-
/* This will be the driver name the kernel reports */
#define DRIVER_NAME "imx-i2c"
@@ -120,8 +115,7 @@
#define I2CR_IEN_OPCODE_0 0x0
#define I2CR_IEN_OPCODE_1 I2CR_IEN
-/** Variables ******************************************************************
-*******************************************************************************/
+#define I2C_PM_TIMEOUT 10 /* ms */
/*
* sorted list of clock divider, register value pairs
@@ -346,7 +340,7 @@ fail_tx:
dma_release_channel(dma->chan_tx);
fail_al:
devm_kfree(dev, dma);
- dev_info(dev, "can't use DMA\n");
+ dev_info(dev, "can't use DMA, using PIO instead.\n");
}
static void i2c_imx_dma_callback(void *arg)
@@ -393,6 +387,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
return 0;
err_submit:
+ dmaengine_terminate_all(dma->chan_using);
err_desc:
dma_unmap_single(chan_dev, dma->dma_buf,
dma->dma_len, dma->dma_data_dir);
@@ -416,9 +411,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
dma->chan_using = NULL;
}
-/** Functions for IMX I2C adapter driver ***************************************
-*******************************************************************************/
-
static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
{
unsigned long orig_jiffies = jiffies;
@@ -527,9 +519,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
i2c_imx_set_clk(i2c_imx);
- result = clk_prepare_enable(i2c_imx->clk);
- if (result)
- return result;
imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
/* Enable I2C controller */
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
@@ -582,7 +571,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
/* Disable I2C controller */
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- clk_disable_unprepare(i2c_imx->clk);
}
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
@@ -901,6 +889,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+ if (result < 0)
+ goto out;
+
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx);
if (result) {
@@ -964,6 +956,10 @@ fail0:
/* Stop I2C transfer */
i2c_imx_stop(i2c_imx);
+ pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
+
+out:
dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
(result < 0) ? "error" : "success msg",
(result < 0) ? result : num);
@@ -997,10 +993,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio");
- rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
- "sda-gpios", 0, NULL);
- rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
- "scl-gpios", 0, NULL);
+ rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
+ rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
if (!gpio_is_valid(rinfo->sda_gpio) ||
!gpio_is_valid(rinfo->scl_gpio) ||
@@ -1083,7 +1077,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
ret = clk_prepare_enable(i2c_imx->clk);
if (ret) {
- dev_err(&pdev->dev, "can't enable I2C clock\n");
+ dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret);
return ret;
}
@@ -1107,6 +1101,18 @@ static int i2c_imx_probe(struct platform_device *pdev)
/* Set up adapter data */
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
+ /* Set up platform driver data */
+ platform_set_drvdata(pdev, i2c_imx);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto rpm_disable;
+
/* Set up clock divider */
i2c_imx->bitrate = IMX_I2C_BIT_RATE;
ret = of_property_read_u32(pdev->dev.of_node,
@@ -1125,12 +1131,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
if (ret < 0) {
dev_err(&pdev->dev, "registration failed\n");
- goto clk_disable;
+ goto rpm_disable;
}
- /* Set up platform driver data */
- platform_set_drvdata(pdev, i2c_imx);
- clk_disable_unprepare(i2c_imx->clk);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
@@ -1143,6 +1148,12 @@ static int i2c_imx_probe(struct platform_device *pdev)
return 0; /* Return OK */
+rpm_disable:
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+
clk_disable:
clk_disable_unprepare(i2c_imx->clk);
return ret;
@@ -1151,6 +1162,11 @@ clk_disable:
static int i2c_imx_remove(struct platform_device *pdev)
{
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ return ret;
/* remove adapter */
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
@@ -1165,17 +1181,54 @@ static int i2c_imx_remove(struct platform_device *pdev)
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
+ clk_disable_unprepare(i2c_imx->clk);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_imx_runtime_suspend(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(i2c_imx->clk);
+
return 0;
}
+static int i2c_imx_runtime_resume(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(i2c_imx->clk);
+ if (ret)
+ dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
+
+ return ret;
+}
+
+static const struct dev_pm_ops i2c_imx_pm_ops = {
+ SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
+ i2c_imx_runtime_resume, NULL)
+};
+#define I2C_IMX_PM_OPS (&i2c_imx_pm_ops)
+#else
+#define I2C_IMX_PM_OPS NULL
+#endif /* CONFIG_PM */
+
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove = i2c_imx_remove,
- .driver = {
- .name = DRIVER_NAME,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = I2C_IMX_PM_OPS,
.of_match_table = i2c_imx_dt_ids,
},
- .id_table = imx_i2c_devtype,
+ .id_table = imx_i2c_devtype,
};
static int __init i2c_adap_imx_init(void)
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 9b867169142f..aec8e6ce38a4 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -132,6 +132,7 @@ struct mtk_i2c_compatible {
unsigned char pmic_i2c: 1;
unsigned char dcm: 1;
unsigned char auto_restart: 1;
+ unsigned char aux_len_reg: 1;
};
struct mtk_i2c {
@@ -153,6 +154,8 @@ struct mtk_i2c {
enum mtk_trans_op op;
u16 timing_reg;
u16 high_speed_reg;
+ unsigned char auto_restart;
+ bool ignore_restart_irq;
const struct mtk_i2c_compatible *dev_comp;
};
@@ -178,6 +181,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 0,
+ .aux_len_reg = 0,
};
static const struct mtk_i2c_compatible mt6589_compat = {
@@ -185,6 +189,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
.pmic_i2c = 1,
.dcm = 0,
.auto_restart = 0,
+ .aux_len_reg = 0,
};
static const struct mtk_i2c_compatible mt8173_compat = {
@@ -192,6 +197,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 1,
+ .aux_len_reg = 1,
};
static const struct of_device_id mtk_i2c_of_match[] = {
@@ -373,7 +379,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
i2c->irq_stat = 0;
- if (i2c->dev_comp->auto_restart)
+ if (i2c->auto_restart)
restart_flag = I2C_RS_TRANSFER;
reinit_completion(&i2c->msg_complete);
@@ -411,8 +417,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
/* Set transfer and transaction len */
if (i2c->op == I2C_MASTER_WRRD) {
- writew(msgs->len | ((msgs + 1)->len) << 8,
- i2c->base + OFFSET_TRANSFER_LEN);
+ if (i2c->dev_comp->aux_len_reg) {
+ writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
+ writew((msgs + 1)->len, i2c->base +
+ OFFSET_TRANSFER_LEN_AUX);
+ } else {
+ writew(msgs->len | ((msgs + 1)->len) << 8,
+ i2c->base + OFFSET_TRANSFER_LEN);
+ }
writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
} else {
writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
@@ -461,7 +473,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
- if (!i2c->dev_comp->auto_restart) {
+ if (!i2c->auto_restart) {
start_reg = I2C_TRANSAC_START;
} else {
start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
@@ -518,6 +530,24 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
if (ret)
return ret;
+ i2c->auto_restart = i2c->dev_comp->auto_restart;
+
+ /* checking if we can skip restart and optimize using WRRD mode */
+ if (i2c->auto_restart && num == 2) {
+ if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+ msgs[0].addr == msgs[1].addr) {
+ i2c->auto_restart = 0;
+ }
+ }
+
+ if (i2c->auto_restart && num >= 2 && i2c->speed_hz > MAX_FS_MODE_SPEED)
+ /* ignore the first restart irq after the master code,
+ * otherwise the first transfer will be discarded.
+ */
+ i2c->ignore_restart_irq = true;
+ else
+ i2c->ignore_restart_irq = false;
+
while (left_num--) {
if (!msgs->buf) {
dev_dbg(i2c->dev, "data buffer is NULL.\n");
@@ -530,7 +560,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
else
i2c->op = I2C_MASTER_WR;
- if (!i2c->dev_comp->auto_restart) {
+ if (!i2c->auto_restart) {
if (num > 1) {
/* combined two messages into one transaction */
i2c->op = I2C_MASTER_WRRD;
@@ -559,7 +589,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
u16 restart_flag = 0;
u16 intr_stat;
- if (i2c->dev_comp->auto_restart)
+ if (i2c->auto_restart)
restart_flag = I2C_RS_TRANSFER;
intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
@@ -571,8 +601,16 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
* i2c->irq_stat need keep the two interrupt value.
*/
i2c->irq_stat |= intr_stat;
- if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
- complete(&i2c->msg_complete);
+
+ if (i2c->ignore_restart_irq && (i2c->irq_stat & restart_flag)) {
+ i2c->ignore_restart_irq = false;
+ i2c->irq_stat = 0;
+ writew(I2C_RS_MUL_CNFG | I2C_RS_MUL_TRIG | I2C_TRANSAC_START,
+ i2c->base + OFFSET_START);
+ } else {
+ if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
+ complete(&i2c->msg_complete);
+ }
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 630bce68bf38..e04598595073 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -23,6 +23,9 @@
Note: we assume there can only be one device, with one or more
SMBus interfaces.
+ The device can register multiple i2c_adapters (up to PIIX4_MAX_ADAPTERS).
+ For devices supporting multiple ports the i2c_adapter should provide
+ an i2c_algorithm to access them.
*/
#include <linux/module.h>
@@ -37,6 +40,7 @@
#include <linux/dmi.h>
#include <linux/acpi.h>
#include <linux/io.h>
+#include <linux/mutex.h>
/* PIIX4 SMBus address offsets */
@@ -75,6 +79,16 @@
#define PIIX4_WORD_DATA 0x0C
#define PIIX4_BLOCK_DATA 0x14
+/* Multi-port constants */
+#define PIIX4_MAX_ADAPTERS 4
+
+/* SB800 constants */
+#define SB800_PIIX4_SMB_IDX 0xcd6
+
+/* SB800 port is selected by bits 2:1 of the smb_en register (0x2c) */
+#define SB800_PIIX4_PORT_IDX 0x2c
+#define SB800_PIIX4_PORT_IDX_MASK 0x06
+
/* insmod parameters */
/* If force is set to anything different from 0, we forcibly enable the
@@ -122,8 +136,19 @@ static const struct dmi_system_id piix4_dmi_ibm[] = {
{ },
};
+/* SB800 globals */
+static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = {
+ "SDA0", "SDA2", "SDA3", "SDA4"
+};
+static const char *piix4_aux_port_name_sb800 = "SDA1";
+
struct i2c_piix4_adapdata {
unsigned short smba;
+
+ /* SB800 */
+ bool sb800_main;
+ unsigned short port;
+ struct mutex *mutex;
};
static int piix4_setup(struct pci_dev *PIIX4_dev,
@@ -229,7 +254,6 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id, u8 aux)
{
unsigned short piix4_smba;
- unsigned short smba_idx = 0xcd6;
u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status;
u8 i2ccfg, i2ccfg_offset = 0x10;
@@ -251,16 +275,10 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
else
smb_en = (aux) ? 0x28 : 0x2c;
- if (!request_region(smba_idx, 2, "smba_idx")) {
- dev_err(&PIIX4_dev->dev, "SMBus base address index region "
- "0x%x already in use!\n", smba_idx);
- return -EBUSY;
- }
- outb_p(smb_en, smba_idx);
- smba_en_lo = inb_p(smba_idx + 1);
- outb_p(smb_en + 1, smba_idx);
- smba_en_hi = inb_p(smba_idx + 1);
- release_region(smba_idx, 2);
+ outb_p(smb_en, SB800_PIIX4_SMB_IDX);
+ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
if (!smb_en) {
smb_en_status = smba_en_lo & 0x10;
@@ -483,7 +501,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EINVAL;
outb_p(len, SMBHSTDAT0);
- i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
for (i = 1; i <= len; i++)
outb_p(data->block[i], SMBBLKDAT);
}
@@ -516,7 +534,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
data->block[0] = inb_p(SMBHSTDAT0);
if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
- i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
for (i = 1; i <= data->block[0]; i++)
data->block[i] = inb_p(SMBBLKDAT);
break;
@@ -524,6 +542,43 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
return 0;
}
+/*
+ * Handles access to multiple SMBus ports on the SB800.
+ * The port is selected by bits 2:1 of the smb_en register (0x2c).
+ * Returns negative errno on error.
+ *
+ * Note: The selected port must be returned to the initial selection to avoid
+ * problems on certain systems.
+ */
+static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+ u8 smba_en_lo;
+ u8 port;
+ int retval;
+
+ mutex_lock(adapdata->mutex);
+
+ outb_p(SB800_PIIX4_PORT_IDX, SB800_PIIX4_SMB_IDX);
+ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+ port = adapdata->port;
+ if ((smba_en_lo & SB800_PIIX4_PORT_IDX_MASK) != (port << 1))
+ outb_p((smba_en_lo & ~SB800_PIIX4_PORT_IDX_MASK) | (port << 1),
+ SB800_PIIX4_SMB_IDX + 1);
+
+ retval = piix4_access(adap, addr, flags, read_write,
+ command, size, data);
+
+ outb_p(smba_en_lo, SB800_PIIX4_SMB_IDX + 1);
+
+ mutex_unlock(adapdata->mutex);
+
+ return retval;
+}
+
static u32 piix4_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
@@ -536,6 +591,11 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = piix4_func,
};
+static const struct i2c_algorithm piix4_smbus_algorithm_sb800 = {
+ .smbus_xfer = piix4_access_sb800,
+ .functionality = piix4_func,
+};
+
static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
@@ -561,11 +621,11 @@ static const struct pci_device_id piix4_ids[] = {
MODULE_DEVICE_TABLE (pci, piix4_ids);
-static struct i2c_adapter *piix4_main_adapter;
+static struct i2c_adapter *piix4_main_adapters[PIIX4_MAX_ADAPTERS];
static struct i2c_adapter *piix4_aux_adapter;
static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
- struct i2c_adapter **padap)
+ const char *name, struct i2c_adapter **padap)
{
struct i2c_adapter *adap;
struct i2c_piix4_adapdata *adapdata;
@@ -594,7 +654,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
adap->dev.parent = &dev->dev;
snprintf(adap->name, sizeof(adap->name),
- "SMBus PIIX4 adapter at %04x", smba);
+ "SMBus PIIX4 adapter %s at %04x", name, smba);
i2c_set_adapdata(adap, adapdata);
@@ -611,6 +671,54 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
return 0;
}
+static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba)
+{
+ struct mutex *mutex;
+ struct i2c_piix4_adapdata *adapdata;
+ int port;
+ int retval;
+
+ mutex = kzalloc(sizeof(*mutex), GFP_KERNEL);
+ if (mutex == NULL)
+ return -ENOMEM;
+
+ mutex_init(mutex);
+
+ for (port = 0; port < PIIX4_MAX_ADAPTERS; port++) {
+ retval = piix4_add_adapter(dev, smba,
+ piix4_main_port_names_sb800[port],
+ &piix4_main_adapters[port]);
+ if (retval < 0)
+ goto error;
+
+ piix4_main_adapters[port]->algo = &piix4_smbus_algorithm_sb800;
+
+ adapdata = i2c_get_adapdata(piix4_main_adapters[port]);
+ adapdata->sb800_main = true;
+ adapdata->port = port;
+ adapdata->mutex = mutex;
+ }
+
+ return retval;
+
+error:
+ dev_err(&dev->dev,
+ "Error setting up SB800 adapters. Unregistering!\n");
+ while (--port >= 0) {
+ adapdata = i2c_get_adapdata(piix4_main_adapters[port]);
+ if (adapdata->smba) {
+ i2c_del_adapter(piix4_main_adapters[port]);
+ kfree(adapdata);
+ kfree(piix4_main_adapters[port]);
+ piix4_main_adapters[port] = NULL;
+ }
+ }
+
+ kfree(mutex);
+
+ return retval;
+}
+
static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
@@ -618,20 +726,41 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
if ((dev->vendor == PCI_VENDOR_ID_ATI &&
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
dev->revision >= 0x40) ||
- dev->vendor == PCI_VENDOR_ID_AMD)
+ dev->vendor == PCI_VENDOR_ID_AMD) {
+ if (!request_region(SB800_PIIX4_SMB_IDX, 2, "smba_idx")) {
+ dev_err(&dev->dev,
+ "SMBus base address index region 0x%x already in use!\n",
+ SB800_PIIX4_SMB_IDX);
+ return -EBUSY;
+ }
+
/* base address location etc changed in SB800 */
retval = piix4_setup_sb800(dev, id, 0);
- else
- retval = piix4_setup(dev, id);
+ if (retval < 0) {
+ release_region(SB800_PIIX4_SMB_IDX, 2);
+ return retval;
+ }
- /* If no main SMBus found, give up */
- if (retval < 0)
- return retval;
+ /*
+ * Try to register multiplexed main SMBus adapter,
+ * give up if we can't
+ */
+ retval = piix4_add_adapters_sb800(dev, retval);
+ if (retval < 0) {
+ release_region(SB800_PIIX4_SMB_IDX, 2);
+ return retval;
+ }
+ } else {
+ retval = piix4_setup(dev, id);
+ if (retval < 0)
+ return retval;
- /* Try to register main SMBus adapter, give up if we can't */
- retval = piix4_add_adapter(dev, retval, &piix4_main_adapter);
- if (retval < 0)
- return retval;
+ /* Try to register main SMBus adapter, give up if we can't */
+ retval = piix4_add_adapter(dev, retval, "main",
+ &piix4_main_adapters[0]);
+ if (retval < 0)
+ return retval;
+ }
/* Check for auxiliary SMBus on some AMD chipsets */
retval = -ENODEV;
@@ -654,7 +783,8 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval > 0) {
/* Try to add the aux adapter if it exists,
* piix4_add_adapter will clean up if this fails */
- piix4_add_adapter(dev, retval, &piix4_aux_adapter);
+ piix4_add_adapter(dev, retval, piix4_aux_port_name_sb800,
+ &piix4_aux_adapter);
}
return 0;
@@ -666,7 +796,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
if (adapdata->smba) {
i2c_del_adapter(adap);
- release_region(adapdata->smba, SMBIOSIZE);
+ if (adapdata->port == 0) {
+ release_region(adapdata->smba, SMBIOSIZE);
+ if (adapdata->sb800_main) {
+ kfree(adapdata->mutex);
+ release_region(SB800_PIIX4_SMB_IDX, 2);
+ }
+ }
kfree(adapdata);
kfree(adap);
}
@@ -674,9 +810,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
static void piix4_remove(struct pci_dev *dev)
{
- if (piix4_main_adapter) {
- piix4_adap_remove(piix4_main_adapter);
- piix4_main_adapter = NULL;
+ int port = PIIX4_MAX_ADAPTERS;
+
+ while (--port >= 0) {
+ if (piix4_main_adapters[port]) {
+ piix4_adap_remove(piix4_main_adapters[port]);
+ piix4_main_adapters[port] = NULL;
+ }
}
if (piix4_aux_adapter) {
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 599c0d7bd906..1abeadc8ab79 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -1,7 +1,8 @@
/*
* Driver for the Renesas RCar I2C unit
*
- * Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright (C) 2011-2015 Renesas Electronics Corporation
*
* Copyright (C) 2012-14 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
@@ -9,9 +10,6 @@
* This file is based on the drivers/i2c/busses/i2c-sh7760.c
* (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
*
- * This file used out-of-tree driver i2c-rcar.c
- * Copyright (C) 2011-2012 Renesas Electronics Corporation
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
@@ -33,7 +31,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
/* register offsets */
#define ICSCR 0x00 /* slave ctrl */
@@ -84,6 +81,7 @@
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
+#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF)
#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB)
#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE)
@@ -94,10 +92,13 @@
#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0xFF)
#define ID_LAST_MSG (1 << 0)
-#define ID_IOERROR (1 << 1)
+#define ID_FIRST_MSG (1 << 1)
#define ID_DONE (1 << 2)
#define ID_ARBLOST (1 << 3)
#define ID_NACK (1 << 4)
+/* persistent flags */
+#define ID_P_PM_BLOCKED (1 << 31)
+#define ID_P_MASK ID_P_PM_BLOCKED
enum rcar_i2c_type {
I2C_RCAR_GEN1,
@@ -108,10 +109,10 @@ enum rcar_i2c_type {
struct rcar_i2c_priv {
void __iomem *io;
struct i2c_adapter adap;
- struct i2c_msg *msg;
+ struct i2c_msg *msg;
+ int msgs_left;
struct clk *clk;
- spinlock_t lock;
wait_queue_head_t wait;
int pos;
@@ -124,9 +125,6 @@ struct rcar_i2c_priv {
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
#define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD)
-#define rcar_i2c_flags_set(p, f) ((p)->flags |= (f))
-#define rcar_i2c_flags_has(p, f) ((p)->flags & (f))
-
#define LOOP_TIMEOUT 1024
@@ -144,9 +142,10 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
{
/* reset master mode */
rcar_i2c_write(priv, ICMIER, 0);
- rcar_i2c_write(priv, ICMCR, 0);
+ rcar_i2c_write(priv, ICMCR, MDBS);
rcar_i2c_write(priv, ICMSR, 0);
- rcar_i2c_write(priv, ICMAR, 0);
+ /* start clock */
+ rcar_i2c_write(priv, ICCCR, priv->icccr);
}
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
@@ -163,15 +162,17 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
return -EBUSY;
}
-static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
- u32 bus_speed,
- struct device *dev)
+static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
{
- u32 scgd, cdf;
- u32 round, ick;
- u32 scl;
- u32 cdf_width;
+ u32 scgd, cdf, round, ick, sum, scl, cdf_width;
unsigned long rate;
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+
+ /* Fall back to previously used values if not supplied */
+ t->bus_freq_hz = t->bus_freq_hz ?: 100000;
+ t->scl_fall_ns = t->scl_fall_ns ?: 35;
+ t->scl_rise_ns = t->scl_rise_ns ?: 200;
+ t->scl_int_delay_ns = t->scl_int_delay_ns ?: 50;
switch (priv->devtype) {
case I2C_RCAR_GEN1:
@@ -195,9 +196,9 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
* SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
*
* ick : I2C internal clock < 20 MHz
- * ticf : I2C SCL falling time = 35 ns here
- * tr : I2C SCL rising time = 200 ns here
- * intd : LSI internal delay = 50 ns here
+ * ticf : I2C SCL falling time
+ * tr : I2C SCL rising time
+ * intd : LSI internal delay
* clkp : peripheral_clk
* F[] : integer up-valuation
*/
@@ -213,12 +214,12 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
* it is impossible to calculate large scale
* number on u32. separate it
*
- * F[(ticf + tr + intd) * ick]
- * = F[(35 + 200 + 50)ns * ick]
- * = F[285 * ick / 1000000000]
- * = F[(ick / 1000000) * 285 / 1000]
+ * F[(ticf + tr + intd) * ick] with sum = (ticf + tr + intd)
+ * = F[sum * ick / 1000000000]
+ * = F[(ick / 1000000) * sum / 1000]
*/
- round = (ick + 500000) / 1000000 * 285;
+ sum = t->scl_fall_ns + t->scl_rise_ns + t->scl_int_delay_ns;
+ round = (ick + 500000) / 1000000 * sum;
round = (round + 500) / 1000;
/*
@@ -235,7 +236,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
*/
for (scgd = 0; scgd < 0x40; scgd++) {
scl = ick / (20 + (scgd * 8) + round);
- if (scl <= bus_speed)
+ if (scl <= t->bus_freq_hz)
goto scgd_find;
}
dev_err(dev, "it is impossible to calculate best SCL\n");
@@ -243,11 +244,9 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
scgd_find:
dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
- scl, bus_speed, clk_get_rate(priv->clk), round, cdf, scgd);
+ scl, t->bus_freq_hz, clk_get_rate(priv->clk), round, cdf, scgd);
- /*
- * keep icccr value
- */
+ /* keep icccr value */
priv->icccr = scgd << cdf_width | cdf;
return 0;
@@ -257,33 +256,44 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
{
int read = !!rcar_i2c_is_recv(priv);
+ priv->pos = 0;
+ if (priv->msgs_left == 1)
+ priv->flags |= ID_LAST_MSG;
+
rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
- rcar_i2c_write(priv, ICMSR, 0);
- rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ /*
+ * We don't have a testcase but the HW engineers say that the write order
+ * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
+ * it didn't cause a drawback for me, let's rather be safe than sorry.
+ */
+ if (priv->flags & ID_FIRST_MSG) {
+ rcar_i2c_write(priv, ICMSR, 0);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ } else {
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ rcar_i2c_write(priv, ICMSR, 0);
+ }
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
}
+static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
+{
+ priv->msg++;
+ priv->msgs_left--;
+ priv->flags &= ID_P_MASK;
+ rcar_i2c_prepare_msg(priv);
+}
+
/*
* interrupt functions
*/
-static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
+static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
{
struct i2c_msg *msg = priv->msg;
- /*
- * FIXME
- * sometimes, unknown interrupt happened.
- * Do nothing
- */
+ /* FIXME: sometimes, unknown interrupt happened. Do nothing */
if (!(msr & MDE))
- return 0;
-
- /*
- * If address transfer phase finished,
- * goto data phase.
- */
- if (msr & MAT)
- rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
+ return;
if (priv->pos < msg->len) {
/*
@@ -305,67 +315,50 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
* [ICRXTX] -> [SHIFT] -> [I2C bus]
*/
- if (priv->flags & ID_LAST_MSG)
+ if (priv->flags & ID_LAST_MSG) {
/*
* If current msg is the _LAST_ msg,
* prepare stop condition here.
* ID_DONE will be set on STOP irq.
*/
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
- else
- /*
- * If current msg is _NOT_ last msg,
- * it doesn't call stop phase.
- * thus, there is no STOP irq.
- * return ID_DONE here.
- */
- return ID_DONE;
+ } else {
+ rcar_i2c_next_msg(priv);
+ return;
+ }
}
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
-
- return 0;
}
-static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
+static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
{
struct i2c_msg *msg = priv->msg;
- /*
- * FIXME
- * sometimes, unknown interrupt happened.
- * Do nothing
- */
+ /* FIXME: sometimes, unknown interrupt happened. Do nothing */
if (!(msr & MDR))
- return 0;
+ return;
if (msr & MAT) {
- /*
- * Address transfer phase finished,
- * but, there is no data at this point.
- * Do nothing.
- */
+ /* Address transfer phase finished, but no data at this point. */
} else if (priv->pos < msg->len) {
- /*
- * get received data
- */
+ /* get received data */
msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
priv->pos++;
}
/*
- * If next received data is the _LAST_,
- * go to STOP phase,
- * otherwise, go to DATA phase.
+ * If next received data is the _LAST_, go to STOP phase. Might be
+ * overwritten by REP START when setting up a new msg. Not elegant
+ * but the only stable sequence for REP START I have found so far.
*/
if (priv->pos + 1 >= msg->len)
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
- else
- rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
-
- rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
- return 0;
+ if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
+ rcar_i2c_next_msg(priv);
+ else
+ rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
}
static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
@@ -426,62 +419,57 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
{
struct rcar_i2c_priv *priv = ptr;
- irqreturn_t result = IRQ_HANDLED;
- u32 msr;
-
- /*-------------- spin lock -----------------*/
- spin_lock(&priv->lock);
+ u32 msr, val;
- if (rcar_i2c_slave_irq(priv))
- goto exit;
+ /* Clear START or STOP as soon as we can */
+ val = rcar_i2c_read(priv, ICMCR);
+ rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
msr = rcar_i2c_read(priv, ICMSR);
/* Only handle interrupts that are currently enabled */
msr &= rcar_i2c_read(priv, ICMIER);
if (!msr) {
- result = IRQ_NONE;
- goto exit;
+ if (rcar_i2c_slave_irq(priv))
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
}
/* Arbitration lost */
if (msr & MAL) {
- rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
+ priv->flags |= ID_DONE | ID_ARBLOST;
goto out;
}
/* Nack */
if (msr & MNR) {
- /* go to stop phase */
- rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
+ /* HW automatically sends STOP after received NACK */
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
- rcar_i2c_flags_set(priv, ID_NACK);
+ priv->flags |= ID_NACK;
goto out;
}
/* Stop */
if (msr & MST) {
- rcar_i2c_flags_set(priv, ID_DONE);
+ priv->msgs_left--; /* The last message also made it */
+ priv->flags |= ID_DONE;
goto out;
}
if (rcar_i2c_is_recv(priv))
- rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
+ rcar_i2c_irq_recv(priv, msr);
else
- rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr));
+ rcar_i2c_irq_send(priv, msr);
out:
- if (rcar_i2c_flags_has(priv, ID_DONE)) {
+ if (priv->flags & ID_DONE) {
rcar_i2c_write(priv, ICMIER, 0);
rcar_i2c_write(priv, ICMSR, 0);
wake_up(&priv->wait);
}
-exit:
- spin_unlock(&priv->lock);
- /*-------------- spin unlock -----------------*/
-
- return result;
+ return IRQ_HANDLED;
}
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
@@ -490,22 +478,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
struct device *dev = rcar_i2c_priv_to_dev(priv);
- unsigned long flags;
int i, ret;
- long timeout;
+ long time_left;
pm_runtime_get_sync(dev);
- /*-------------- spin lock -----------------*/
- spin_lock_irqsave(&priv->lock, flags);
-
- rcar_i2c_init(priv);
- /* start clock */
- rcar_i2c_write(priv, ICCCR, priv->icccr);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- /*-------------- spin unlock -----------------*/
-
ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;
@@ -514,48 +491,27 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
/* This HW can't send STOP after address phase */
if (msgs[i].len == 0) {
ret = -EOPNOTSUPP;
- break;
- }
-
- /*-------------- spin lock -----------------*/
- spin_lock_irqsave(&priv->lock, flags);
-
- /* init each data */
- priv->msg = &msgs[i];
- priv->pos = 0;
- priv->flags = 0;
- if (i == num - 1)
- rcar_i2c_flags_set(priv, ID_LAST_MSG);
-
- rcar_i2c_prepare_msg(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- /*-------------- spin unlock -----------------*/
-
- timeout = wait_event_timeout(priv->wait,
- rcar_i2c_flags_has(priv, ID_DONE),
- adap->timeout);
- if (!timeout) {
- ret = -ETIMEDOUT;
- break;
- }
-
- if (rcar_i2c_flags_has(priv, ID_NACK)) {
- ret = -ENXIO;
- break;
- }
-
- if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
- ret = -EAGAIN;
- break;
- }
-
- if (rcar_i2c_flags_has(priv, ID_IOERROR)) {
- ret = -EIO;
- break;
+ goto out;
}
+ }
- ret = i + 1; /* The number of transfer */
+ /* init first message */
+ priv->msg = msgs;
+ priv->msgs_left = num;
+ priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
+ rcar_i2c_prepare_msg(priv);
+
+ time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
+ num * adap->timeout);
+ if (!time_left) {
+ rcar_i2c_init(priv);
+ ret = -ETIMEDOUT;
+ } else if (priv->flags & ID_NACK) {
+ ret = -ENXIO;
+ } else if (priv->flags & ID_ARBLOST) {
+ ret = -EAGAIN;
+ } else {
+ ret = num - priv->msgs_left; /* The number of transfer */
}
out:
pm_runtime_put(dev);
@@ -637,7 +593,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
struct i2c_adapter *adap;
struct resource *res;
struct device *dev = &pdev->dev;
- u32 bus_speed;
+ struct i2c_timings i2c_t;
int irq, ret;
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
@@ -650,23 +606,13 @@ static int rcar_i2c_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
}
- bus_speed = 100000; /* default 100 kHz */
- of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
-
- priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
-
- ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
- if (ret < 0)
- return ret;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
- irq = platform_get_irq(pdev, 0);
+ priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
init_waitqueue_head(&priv->wait);
- spin_lock_init(&priv->lock);
adap = &priv->adap;
adap->nr = pdev->id;
@@ -678,26 +624,47 @@ static int rcar_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, priv);
strlcpy(adap->name, pdev->name, sizeof(adap->name));
- ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0,
- dev_name(dev), priv);
+ i2c_parse_fw_timings(dev, &i2c_t, false);
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ ret = rcar_i2c_clock_calculate(priv, &i2c_t);
+ if (ret < 0)
+ goto out_pm_put;
+
+ rcar_i2c_init(priv);
+
+ /* Don't suspend when multi-master to keep arbitration working */
+ if (of_property_read_bool(dev->of_node, "multi-master"))
+ priv->flags |= ID_P_PM_BLOCKED;
+ else
+ pm_runtime_put(dev);
+
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv);
if (ret < 0) {
dev_err(dev, "cannot get irq %d\n", irq);
- return ret;
+ goto out_pm_disable;
}
- pm_runtime_enable(dev);
platform_set_drvdata(pdev, priv);
ret = i2c_add_numbered_adapter(adap);
if (ret < 0) {
dev_err(dev, "reg adap failed: %d\n", ret);
- pm_runtime_disable(dev);
- return ret;
+ goto out_pm_disable;
}
dev_info(dev, "probed\n");
return 0;
+
+ out_pm_put:
+ pm_runtime_put(dev);
+ out_pm_disable:
+ pm_runtime_disable(dev);
+ return ret;
}
static int rcar_i2c_remove(struct platform_device *pdev)
@@ -706,6 +673,8 @@ static int rcar_i2c_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
i2c_del_adapter(&priv->adap);
+ if (priv->flags & ID_P_PM_BLOCKED)
+ pm_runtime_put(dev);
pm_runtime_disable(dev);
return 0;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 5df819610d52..362a6de54833 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -784,7 +784,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
int retry;
int ret;
- pm_runtime_get_sync(&adap->dev);
ret = clk_enable(i2c->clk);
if (ret)
return ret;
@@ -795,7 +794,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
if (ret != -EAGAIN) {
clk_disable(i2c->clk);
- pm_runtime_put(&adap->dev);
return ret;
}
@@ -805,7 +803,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
}
clk_disable(i2c->clk);
- pm_runtime_put(&adap->dev);
return -EREMOTEIO;
}
@@ -1256,8 +1253,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return ret;
}
- pm_runtime_enable(&i2c->adap.dev);
-
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
return 0;
}
@@ -1273,7 +1268,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
clk_unprepare(i2c->clk);
- pm_runtime_disable(&i2c->adap.dev);
pm_runtime_disable(&pdev->dev);
s3c24xx_i2c_deregister_cpufreq(i2c);
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 25020ec777c9..6ee77159ac57 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -708,8 +708,7 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
#ifdef CONFIG_PM_SLEEP
static int st_i2c_suspend(struct device *dev)
{
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
if (i2c_dev->busy)
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
index 4c7fc2d47014..210ca82f8aa0 100644
--- a/drivers/i2c/busses/i2c-taos-evm.c
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -130,7 +130,13 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
return 0;
} else {
if (p[0] == 'x') {
- data->byte = simple_strtol(p + 1, NULL, 16);
+ /*
+ * Voluntarily dropping error code of kstrtou8 since all
+ * error code that it could return are invalid according
+ * to Documentation/i2c/fault-codes.
+ */
+ if (kstrtou8(p + 1, 16, &data->byte))
+ return -EPROTO;
return 0;
}
}
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index e8d03bcfe3e0..f3e5ff8522f0 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -466,6 +466,11 @@ static int uniphier_fi2c_clk_init(struct device *dev,
if (of_property_read_u32(np, "clock-frequency", &bus_speed))
bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
+ if (!bus_speed) {
+ dev_err(dev, "clock-freqyency should not be zero\n");
+ return -EINVAL;
+ }
+
if (bus_speed > UNIPHIER_FI2C_MAX_SPEED)
bus_speed = UNIPHIER_FI2C_MAX_SPEED;
@@ -481,6 +486,10 @@ static int uniphier_fi2c_clk_init(struct device *dev,
return ret;
clk_rate = clk_get_rate(priv->clk);
+ if (!clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ return -EINVAL;
+ }
uniphier_fi2c_reset(priv);
@@ -531,7 +540,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
ret = uniphier_fi2c_clk_init(dev, priv);
if (ret)
- return ret;
+ goto err;
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
pdev->name, priv);
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index e3c3861c3325..1f4f3f53819c 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -327,6 +327,11 @@ static int uniphier_i2c_clk_init(struct device *dev,
if (of_property_read_u32(np, "clock-frequency", &bus_speed))
bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
+ if (!bus_speed) {
+ dev_err(dev, "clock-freqyency should not be zero\n");
+ return -EINVAL;
+ }
+
if (bus_speed > UNIPHIER_I2C_MAX_SPEED)
bus_speed = UNIPHIER_I2C_MAX_SPEED;
@@ -342,6 +347,10 @@ static int uniphier_i2c_clk_init(struct device *dev,
return ret;
clk_rate = clk_get_rate(priv->clk);
+ if (!clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ return -EINVAL;
+ }
uniphier_i2c_reset(priv, true);
@@ -388,7 +397,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
ret = uniphier_i2c_clk_init(dev, priv);
if (ret)
- return ret;
+ goto err;
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
priv);
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 0b20449e48cf..6efd20095d5d 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -70,7 +70,7 @@ struct xiic_i2c {
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *tx_msg;
- spinlock_t lock;
+ struct mutex lock;
unsigned int tx_pos;
unsigned int nmsgs;
enum xilinx_i2c_state state;
@@ -369,7 +369,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
* To find which interrupts are pending; AND interrupts pending with
* interrupts masked.
*/
- spin_lock(&i2c->lock);
+ mutex_lock(&i2c->lock);
isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
pend = isr & ier;
@@ -497,7 +497,7 @@ out:
dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
- spin_unlock(&i2c->lock);
+ mutex_unlock(&i2c->lock);
return IRQ_HANDLED;
}
@@ -662,10 +662,10 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
static void xiic_start_xfer(struct xiic_i2c *i2c)
{
- spin_lock(&i2c->lock);
+ mutex_lock(&i2c->lock);
xiic_reinit(i2c);
__xiic_start_xfer(i2c);
- spin_unlock(&i2c->lock);
+ mutex_unlock(&i2c->lock);
}
static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
@@ -745,7 +745,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
i2c->adap.dev.parent = &pdev->dev;
i2c->adap.dev.of_node = pdev->dev.of_node;
- spin_lock_init(&i2c->lock);
+ mutex_init(&i2c->lock);
init_waitqueue_head(&i2c->wait);
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
index 8b36bcfd952d..613c3a4f2c51 100644
--- a/drivers/i2c/busses/i2c-xlr.c
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -17,6 +17,10 @@
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
/* XLR I2C REGISTERS */
#define XLR_I2C_CFG 0x00
@@ -30,6 +34,10 @@
#define XLR_I2C_BYTECNT 0x08
#define XLR_I2C_HDSTATIM 0x09
+/* Sigma Designs additional registers */
+#define XLR_I2C_INT_EN 0x09
+#define XLR_I2C_INT_STAT 0x0a
+
/* XLR I2C REGISTERS FLAGS */
#define XLR_I2C_BUS_BUSY 0x01
#define XLR_I2C_SDOEMPTY 0x02
@@ -63,11 +71,98 @@ static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg)
return __raw_readl(base + reg);
}
+#define XLR_I2C_FLAG_IRQ 1
+
+struct xlr_i2c_config {
+ u32 flags; /* optional feature support */
+ u32 status_busy; /* value of STATUS[0] when busy */
+ u32 cfg_extra; /* extra CFG bits to set */
+};
+
struct xlr_i2c_private {
struct i2c_adapter adap;
u32 __iomem *iobase;
+ int irq;
+ int pos;
+ struct i2c_msg *msg;
+ const struct xlr_i2c_config *cfg;
+ wait_queue_head_t wait;
+ struct clk *clk;
};
+static int xlr_i2c_busy(struct xlr_i2c_private *priv, u32 status)
+{
+ return (status & XLR_I2C_BUS_BUSY) == priv->cfg->status_busy;
+}
+
+static int xlr_i2c_idle(struct xlr_i2c_private *priv)
+{
+ return !xlr_i2c_busy(priv, xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS));
+}
+
+static int xlr_i2c_wait(struct xlr_i2c_private *priv, unsigned long timeout)
+{
+ int status;
+ int t;
+
+ t = wait_event_timeout(priv->wait, xlr_i2c_idle(priv),
+ msecs_to_jiffies(timeout));
+ if (!t)
+ return -ETIMEDOUT;
+
+ status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+ return status & XLR_I2C_ACK_ERR ? -EIO : 0;
+}
+
+static void xlr_i2c_tx_irq(struct xlr_i2c_private *priv, u32 status)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ if (status & XLR_I2C_SDOEMPTY)
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT,
+ msg->buf[priv->pos++]);
+}
+
+static void xlr_i2c_rx_irq(struct xlr_i2c_private *priv, u32 status)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ if (status & XLR_I2C_RXRDY)
+ msg->buf[priv->pos++] =
+ xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
+}
+
+static irqreturn_t xlr_i2c_irq(int irq, void *dev_id)
+{
+ struct xlr_i2c_private *priv = dev_id;
+ struct i2c_msg *msg = priv->msg;
+ u32 int_stat, status;
+
+ int_stat = xlr_i2c_rdreg(priv->iobase, XLR_I2C_INT_STAT);
+ if (!int_stat)
+ return IRQ_NONE;
+
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, int_stat);
+
+ if (!msg)
+ return IRQ_HANDLED;
+
+ status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+ if (priv->pos < msg->len) {
+ if (msg->flags & I2C_M_RD)
+ xlr_i2c_rx_irq(priv, status);
+ else
+ xlr_i2c_tx_irq(priv, status);
+ }
+
+ if (!xlr_i2c_busy(priv, status))
+ wake_up(&priv->wait);
+
+ return IRQ_HANDLED;
+}
+
static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
u8 *buf, u16 addr)
{
@@ -75,37 +170,48 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
unsigned long timeout, stoptime, checktime;
u32 i2c_status;
int pos, timedout;
- u8 offset, byte;
+ u8 offset;
+ u32 xfer;
+
+ if (!len)
+ return -EOPNOTSUPP;
offset = buf[0];
xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
- xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
- xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
+ XLR_I2C_CFG_ADDR | priv->cfg->cfg_extra);
timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
stoptime = jiffies + timeout;
timedout = 0;
- pos = 1;
-retry:
+
if (len == 1) {
- xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
- XLR_I2C_STARTXFR_ND);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+ xfer = XLR_I2C_STARTXFR_ND;
+ pos = 1;
} else {
- xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]);
- xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
- XLR_I2C_STARTXFR_WR);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 2);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[1]);
+ xfer = XLR_I2C_STARTXFR_WR;
+ pos = 2;
}
+ priv->pos = pos;
+
+retry:
+ /* retry can only happen on the first byte */
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, xfer);
+
+ if (priv->irq > 0)
+ return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len);
+
while (!timedout) {
checktime = jiffies;
i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
- if (i2c_status & XLR_I2C_SDOEMPTY) {
- pos++;
- /* need to do a empty dataout after the last byte */
- byte = (pos < len) ? buf[pos] : 0;
- xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte);
+ if ((i2c_status & XLR_I2C_SDOEMPTY) && pos < len) {
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos++]);
/* reset timeout on successful xmit */
stoptime = jiffies + timeout;
@@ -121,7 +227,7 @@ retry:
if (i2c_status & XLR_I2C_ACK_ERR)
return -EIO;
- if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len)
+ if (!xlr_i2c_busy(priv, i2c_status) && pos >= len)
return 0;
}
dev_err(&adap->dev, "I2C transmit timeout\n");
@@ -134,12 +240,17 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
u32 i2c_status;
unsigned long timeout, stoptime, checktime;
int nbytes, timedout;
- u8 byte;
- xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
- xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len);
+ if (!len)
+ return -EOPNOTSUPP;
+
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
+ XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+ priv->pos = 0;
+
timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
stoptime = jiffies + timeout;
timedout = 0;
@@ -147,18 +258,18 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
retry:
xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
+ if (priv->irq > 0)
+ return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len);
+
while (!timedout) {
checktime = jiffies;
i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
if (i2c_status & XLR_I2C_RXRDY) {
- if (nbytes > len)
+ if (nbytes >= len)
return -EIO; /* should not happen */
- /* we need to do a dummy datain when nbytes == len */
- byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
- if (nbytes < len)
- buf[nbytes] = byte;
- nbytes++;
+ buf[nbytes++] =
+ xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
/* reset timeout on successful read */
stoptime = jiffies + timeout;
@@ -174,7 +285,7 @@ retry:
if (i2c_status & XLR_I2C_ACK_ERR)
return -EIO;
- if ((i2c_status & XLR_I2C_BUS_BUSY) == 0)
+ if (!xlr_i2c_busy(priv, i2c_status))
return 0;
}
@@ -190,8 +301,17 @@ static int xlr_i2c_xfer(struct i2c_adapter *adap,
int ret = 0;
struct xlr_i2c_private *priv = i2c_get_adapdata(adap);
+ ret = clk_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ if (priv->irq)
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0xf);
+
+
for (i = 0; ret == 0 && i < num; i++) {
msg = &msgs[i];
+ priv->msg = msg;
if (msg->flags & I2C_M_RD)
ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0],
msg->addr);
@@ -200,13 +320,19 @@ static int xlr_i2c_xfer(struct i2c_adapter *adap,
msg->addr);
}
+ if (priv->irq)
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0);
+
+ clk_disable(priv->clk);
+ priv->msg = NULL;
+
return (ret != 0) ? ret : num;
}
static u32 xlr_func(struct i2c_adapter *adap)
{
/* Emulate SMBUS over I2C */
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+ return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C;
}
static struct i2c_algorithm xlr_i2c_algo = {
@@ -214,22 +340,89 @@ static struct i2c_algorithm xlr_i2c_algo = {
.functionality = xlr_func,
};
+static const struct xlr_i2c_config xlr_i2c_config_default = {
+ .status_busy = XLR_I2C_BUS_BUSY,
+ .cfg_extra = 0,
+};
+
+static const struct xlr_i2c_config xlr_i2c_config_tangox = {
+ .flags = XLR_I2C_FLAG_IRQ,
+ .status_busy = 0,
+ .cfg_extra = 1 << 8,
+};
+
+static const struct of_device_id xlr_i2c_dt_ids[] = {
+ {
+ .compatible = "sigma,smp8642-i2c",
+ .data = &xlr_i2c_config_tangox,
+ },
+ { }
+};
+
static int xlr_i2c_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match;
struct xlr_i2c_private *priv;
struct resource *res;
+ struct clk *clk;
+ unsigned long clk_rate;
+ unsigned long clk_div;
+ u32 busfreq;
+ int irq;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ match = of_match_device(xlr_i2c_dt_ids, &pdev->dev);
+ if (match)
+ priv->cfg = match->data;
+ else
+ priv->cfg = &xlr_i2c_config_default;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->iobase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->iobase))
return PTR_ERR(priv->iobase);
+ irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0 && (priv->cfg->flags & XLR_I2C_FLAG_IRQ)) {
+ priv->irq = irq;
+
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, 0xf);
+
+ ret = devm_request_irq(&pdev->dev, priv->irq, xlr_i2c_irq,
+ IRQF_SHARED, dev_name(&pdev->dev),
+ priv);
+ if (ret)
+ return ret;
+
+ init_waitqueue_head(&priv->wait);
+ }
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &busfreq))
+ busfreq = 100000;
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(clk)) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(clk);
+ clk_div = DIV_ROUND_UP(clk_rate, 2 * busfreq);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_CLKDIV, clk_div);
+
+ clk_disable(clk);
+ priv->clk = clk;
+ }
+
priv->adap.dev.parent = &pdev->dev;
+ priv->adap.dev.of_node = pdev->dev.of_node;
priv->adap.owner = THIS_MODULE;
priv->adap.algo_data = priv;
priv->adap.algo = &xlr_i2c_algo;
@@ -255,6 +448,8 @@ static int xlr_i2c_remove(struct platform_device *pdev)
priv = platform_get_drvdata(pdev);
i2c_del_adapter(&priv->adap);
+ clk_unprepare(priv->clk);
+
return 0;
}
@@ -263,6 +458,7 @@ static struct platform_driver xlr_i2c_driver = {
.remove = xlr_i2c_remove,
.driver = {
.name = "xlr-i2cbus",
+ .of_match_table = xlr_i2c_dt_ids,
},
};
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index ba8eb087f224..ffe715d346d8 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -53,6 +53,7 @@
#include <linux/jump_label.h>
#include <asm/uaccess.h>
#include <linux/err.h>
+#include <linux/property.h>
#include "i2c-core.h"
@@ -1563,6 +1564,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev);
+ pm_runtime_enable(&adap->dev);
#ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
@@ -1817,6 +1819,8 @@ void i2c_del_adapter(struct i2c_adapter *adap)
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+ pm_runtime_disable(&adap->dev);
+
/* wait until all references to the device are gone
*
* FIXME: This is old code and should ideally be replaced by an
@@ -1839,6 +1843,58 @@ void i2c_del_adapter(struct i2c_adapter *adap)
}
EXPORT_SYMBOL(i2c_del_adapter);
+/**
+ * i2c_parse_fw_timings - get I2C related timing parameters from firmware
+ * @dev: The device to scan for I2C timing properties
+ * @t: the i2c_timings struct to be filled with values
+ * @use_defaults: bool to use sane defaults derived from the I2C specification
+ * when properties are not found, otherwise use 0
+ *
+ * Scan the device for the generic I2C properties describing timing parameters
+ * for the signal and fill the given struct with the results. If a property was
+ * not found and use_defaults was true, then maximum timings are assumed which
+ * are derived from the I2C specification. If use_defaults is not used, the
+ * results will be 0, so drivers can apply their own defaults later. The latter
+ * is mainly intended for avoiding regressions of existing drivers which want
+ * to switch to this function. New drivers almost always should use the defaults.
+ */
+
+void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults)
+{
+ int ret;
+
+ memset(t, 0, sizeof(*t));
+
+ ret = device_property_read_u32(dev, "clock-frequency", &t->bus_freq_hz);
+ if (ret && use_defaults)
+ t->bus_freq_hz = 100000;
+
+ ret = device_property_read_u32(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns);
+ if (ret && use_defaults) {
+ if (t->bus_freq_hz <= 100000)
+ t->scl_rise_ns = 1000;
+ else if (t->bus_freq_hz <= 400000)
+ t->scl_rise_ns = 300;
+ else
+ t->scl_rise_ns = 120;
+ }
+
+ ret = device_property_read_u32(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns);
+ if (ret && use_defaults) {
+ if (t->bus_freq_hz <= 400000)
+ t->scl_fall_ns = 300;
+ else
+ t->scl_fall_ns = 120;
+ }
+
+ device_property_read_u32(dev, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns);
+
+ ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns);
+ if (ret && use_defaults)
+ t->sda_fall_ns = t->scl_fall_ns;
+}
+EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
+
/* ------------------------------------------------------------------------- */
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
index c3da53e7bb2b..86aa88aeb3a6 100644
--- a/drivers/ide/ide-scan-pci.c
+++ b/drivers/ide/ide-scan-pci.c
@@ -107,5 +107,4 @@ static int __init ide_scan_pcibus(void)
return 0;
}
-
-module_init(ide_scan_pcibus);
+device_initcall(ide_scan_pcibus);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index f086ef387475..d127ace6aa57 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -178,17 +178,17 @@ MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp)
{
- int a, b, i, j = 1;
+ unsigned int a, b, i, j = 1;
unsigned int *dev_param_mask = (unsigned int *)kp->arg;
/* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */
- if (sscanf(s, "%d.%d:%d", &a, &b, &j) != 3 &&
- sscanf(s, "%d.%d", &a, &b) != 2)
+ if (sscanf(s, "%u.%u:%u", &a, &b, &j) != 3 &&
+ sscanf(s, "%u.%u", &a, &b) != 2)
return -EINVAL;
i = a * MAX_DRIVES + b;
- if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1)
+ if (i >= MAX_HWIFS * MAX_DRIVES || j > 1)
return -EINVAL;
if (j)
@@ -246,17 +246,17 @@ static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES];
static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
{
- int a, b, c = 0, h = 0, s = 0, i, j = 1;
+ unsigned int a, b, c = 0, h = 0, s = 0, i, j = 1;
/* controller . device (0 or 1) : Cylinders , Heads , Sectors */
/* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */
- if (sscanf(str, "%d.%d:%d,%d,%d", &a, &b, &c, &h, &s) != 5 &&
- sscanf(str, "%d.%d:%d", &a, &b, &j) != 3)
+ if (sscanf(str, "%u.%u:%u,%u,%u", &a, &b, &c, &h, &s) != 5 &&
+ sscanf(str, "%u.%u:%u", &a, &b, &j) != 3)
return -EINVAL;
i = a * MAX_DRIVES + b;
- if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1)
+ if (i >= MAX_HWIFS * MAX_DRIVES || j > 1)
return -EINVAL;
if (c > INT_MAX || h > 255 || s > 255)
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
index f01ba4606be0..04029d18a696 100644
--- a/drivers/ide/it821x.c
+++ b/drivers/ide/it821x.c
@@ -508,7 +508,7 @@ static void it821x_quirkproc(ide_drive_t *drive)
}
-static struct ide_dma_ops it821x_pass_through_dma_ops = {
+static const struct ide_dma_ops it821x_pass_through_dma_ops = {
.dma_host_set = ide_dma_host_set,
.dma_setup = ide_dma_setup,
.dma_start = it821x_dma_start,
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
index 0069f6ce74cf..d550b379b0f1 100644
--- a/drivers/ide/trm290.c
+++ b/drivers/ide/trm290.c
@@ -314,7 +314,7 @@ static const struct ide_tp_ops trm290_tp_ops = {
.output_data = ide_output_data,
};
-static struct ide_dma_ops trm290_dma_ops = {
+static const struct ide_dma_ops trm290_dma_ops = {
.dma_host_set = trm290_dma_host_set,
.dma_setup = trm290_dma_setup,
.dma_start = trm290_dma_start,
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 66792e707d74..505e921f0b19 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -22,6 +22,14 @@ if IIO_BUFFER
source "drivers/iio/buffer/Kconfig"
endif # IIO_BUFFER
+config IIO_CONFIGFS
+ tristate "Enable IIO configuration via configfs"
+ select CONFIGFS_FS
+ help
+ This allows configuring various IIO bits through configfs
+ (e.g. software triggers). For more info see
+ Documentation/iio/iio_configfs.txt.
+
config IIO_TRIGGER
bool "Enable triggered sampling support"
help
@@ -38,6 +46,14 @@ config IIO_CONSUMERS_PER_TRIGGER
This value controls the maximum number of consumers that a
given trigger may handle. Default is 2.
+config IIO_SW_TRIGGER
+ tristate "Enable software triggers support"
+ select IIO_CONFIGFS
+ help
+ Provides IIO core support for software triggers. A software
+ trigger can be created via configfs or directly by a driver
+ using the API provided.
+
config IIO_TRIGGERED_EVENT
tristate
select IIO_TRIGGER
@@ -50,8 +66,10 @@ source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/chemical/Kconfig"
source "drivers/iio/common/Kconfig"
source "drivers/iio/dac/Kconfig"
+source "drivers/iio/dummy/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig"
+source "drivers/iio/health/Kconfig"
source "drivers/iio/humidity/Kconfig"
source "drivers/iio/imu/Kconfig"
source "drivers/iio/light/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index aeca7269fe44..20f649073462 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -7,6 +7,8 @@ industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
+obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
obj-y += accel/
@@ -16,8 +18,10 @@ obj-y += buffer/
obj-y += chemical/
obj-y += common/
obj-y += dac/
+obj-y += dummy/
obj-y += gyro/
obj-y += frequency/
+obj-y += health/
obj-y += humidity/
obj-y += imu/
obj-y += light/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 969428dd6329..edc29b173f6c 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -64,7 +64,7 @@ config IIO_ST_ACCEL_3AXIS
help
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
- LIS331DLH, LSM303DL, LSM303DLM, LSM330.
+ LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12.
This driver can also be built as a module. If so, these modules
will be created:
@@ -107,6 +107,35 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
+config MMA7455
+ tristate
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+
+config MMA7455_I2C
+ tristate "Freescale MMA7455L/MMA7456L Accelerometer I2C Driver"
+ depends on I2C
+ select MMA7455
+ select REGMAP_I2C
+ help
+ Say yes here to build support for the Freescale MMA7455L and
+ MMA7456L 3-axis accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mma7455_i2c.
+
+config MMA7455_SPI
+ tristate "Freescale MMA7455L/MMA7456L Accelerometer SPI Driver"
+ depends on SPI_MASTER
+ select MMA7455
+ select REGMAP_SPI
+ help
+ Say yes here to build support for the Freescale MMA7455L and
+ MMA7456L 3-axis accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mma7455_spi.
+
config MMA8452
tristate "Freescale MMA8452Q and similar Accelerometers Driver"
depends on I2C
@@ -158,6 +187,17 @@ config MXC4005
To compile this driver as a module, choose M. The module will be
called mxc4005.
+config MXC6255
+ tristate "Memsic MXC6255 Orientation Sensing Accelerometer Driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say yes here to build support for the Memsic MXC6255 Orientation
+ Sensing Accelerometer Driver.
+
+ To compile this driver as a module, choose M here: the module will be
+ called mxc6255.
+
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 7925f166e6e9..71b6794de885 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -10,6 +10,11 @@ obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
+
+obj-$(CONFIG_MMA7455) += mma7455_core.o
+obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o
+obj-$(CONFIG_MMA7455_SPI) += mma7455_spi.o
+
obj-$(CONFIG_MMA8452) += mma8452.o
obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o
@@ -17,6 +22,7 @@ obj-$(CONFIG_MMA9551) += mma9551.o
obj-$(CONFIG_MMA9553) += mma9553.o
obj-$(CONFIG_MXC4005) += mxc4005.o
+obj-$(CONFIG_MXC6255) += mxc6255.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 2d33f1e821db..c73331f7782b 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -1623,24 +1623,22 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
}
}
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(dev, "Unable to register iio device\n");
- goto err_trigger_unregister;
- }
-
ret = pm_runtime_set_active(dev);
if (ret)
- goto err_iio_unregister;
+ goto err_trigger_unregister;
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(dev, "Unable to register iio device\n");
+ goto err_trigger_unregister;
+ }
+
return 0;
-err_iio_unregister:
- iio_device_unregister(indio_dev);
err_trigger_unregister:
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
err_buffer_cleanup:
@@ -1655,12 +1653,12 @@ int bmc150_accel_core_remove(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(data->dev);
pm_runtime_set_suspended(data->dev);
pm_runtime_put_noidle(data->dev);
- iio_device_unregister(indio_dev);
-
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
iio_triggered_buffer_cleanup(indio_dev);
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 18c1b06684c1..edec1d099e91 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1264,25 +1264,23 @@ static int kxcjk1013_probe(struct i2c_client *client,
goto err_trigger_unregister;
}
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "unable to register iio device\n");
- goto err_buffer_cleanup;
- }
-
ret = pm_runtime_set_active(&client->dev);
if (ret)
- goto err_iio_unregister;
+ goto err_buffer_cleanup;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
KXCJK1013_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto err_buffer_cleanup;
+ }
+
return 0;
-err_iio_unregister:
- iio_device_unregister(indio_dev);
err_buffer_cleanup:
if (data->dready_trig)
iio_triggered_buffer_cleanup(indio_dev);
@@ -1302,12 +1300,12 @@ static int kxcjk1013_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct kxcjk1013_data *data = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
- iio_device_unregister(indio_dev);
-
if (data->dready_trig) {
iio_triggered_buffer_cleanup(indio_dev);
iio_trigger_unregister(data->dready_trig);
diff --git a/drivers/iio/accel/mma7455.h b/drivers/iio/accel/mma7455.h
new file mode 100644
index 000000000000..2b1152c53d4f
--- /dev/null
+++ b/drivers/iio/accel/mma7455.h
@@ -0,0 +1,19 @@
+/*
+ * IIO accel driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@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.
+ */
+
+#ifndef __MMA7455_H
+#define __MMA7455_H
+
+extern const struct regmap_config mma7455_core_regmap;
+
+int mma7455_core_probe(struct device *dev, struct regmap *regmap,
+ const char *name);
+int mma7455_core_remove(struct device *dev);
+
+#endif
diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c
new file mode 100644
index 000000000000..c633cc2c0789
--- /dev/null
+++ b/drivers/iio/accel/mma7455_core.c
@@ -0,0 +1,311 @@
+/*
+ * IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@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.
+ *
+ * UNSUPPORTED hardware features:
+ * - 8-bit mode with different scales
+ * - INT1/INT2 interrupts
+ * - Offset calibration
+ * - Events
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mma7455.h"
+
+#define MMA7455_REG_XOUTL 0x00
+#define MMA7455_REG_XOUTH 0x01
+#define MMA7455_REG_YOUTL 0x02
+#define MMA7455_REG_YOUTH 0x03
+#define MMA7455_REG_ZOUTL 0x04
+#define MMA7455_REG_ZOUTH 0x05
+#define MMA7455_REG_STATUS 0x09
+#define MMA7455_STATUS_DRDY BIT(0)
+#define MMA7455_REG_WHOAMI 0x0f
+#define MMA7455_WHOAMI_ID 0x55
+#define MMA7455_REG_MCTL 0x16
+#define MMA7455_MCTL_MODE_STANDBY 0x00
+#define MMA7455_MCTL_MODE_MEASURE 0x01
+#define MMA7455_REG_CTL1 0x18
+#define MMA7455_CTL1_DFBW_MASK BIT(7)
+#define MMA7455_CTL1_DFBW_125HZ BIT(7)
+#define MMA7455_CTL1_DFBW_62_5HZ 0
+#define MMA7455_REG_TW 0x1e
+
+/*
+ * When MMA7455 is used in 10-bit it has a fullscale of -8g
+ * corresponding to raw value -512. The userspace interface
+ * uses m/s^2 and we declare micro units.
+ * So scale factor is given by:
+ * g * 8 * 1e6 / 512 = 153228.90625, with g = 9.80665
+ */
+#define MMA7455_10BIT_SCALE 153229
+
+struct mma7455_data {
+ struct regmap *regmap;
+ struct device *dev;
+};
+
+static int mma7455_drdy(struct mma7455_data *mma7455)
+{
+ unsigned int reg;
+ int tries = 3;
+ int ret;
+
+ while (tries-- > 0) {
+ ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, &reg);
+ if (ret)
+ return ret;
+
+ if (reg & MMA7455_STATUS_DRDY)
+ return 0;
+
+ msleep(20);
+ }
+
+ dev_warn(mma7455->dev, "data not ready\n");
+
+ return -EIO;
+}
+
+static irqreturn_t mma7455_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct mma7455_data *mma7455 = iio_priv(indio_dev);
+ u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
+ int ret;
+
+ ret = mma7455_drdy(mma7455);
+ if (ret)
+ goto done;
+
+ ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
+ sizeof(__le16) * 3);
+ if (ret)
+ goto done;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int mma7455_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mma7455_data *mma7455 = iio_priv(indio_dev);
+ unsigned int reg;
+ __le16 data;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ ret = mma7455_drdy(mma7455);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(mma7455->regmap, chan->address, &data,
+ sizeof(data));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(le16_to_cpu(data), 9);
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = MMA7455_10BIT_SCALE;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, &reg);
+ if (ret)
+ return ret;
+
+ if (reg & MMA7455_CTL1_DFBW_MASK)
+ *val = 250;
+ else
+ *val = 125;
+
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static int mma7455_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mma7455_data *mma7455 = iio_priv(indio_dev);
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val == 250 && val2 == 0)
+ i = MMA7455_CTL1_DFBW_125HZ;
+ else if (val == 125 && val2 == 0)
+ i = MMA7455_CTL1_DFBW_62_5HZ;
+ else
+ return -EINVAL;
+
+ return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1,
+ MMA7455_CTL1_DFBW_MASK, i);
+
+ case IIO_CHAN_INFO_SCALE:
+ /* In 10-bit mode there is only one scale available */
+ if (val == 0 && val2 == MMA7455_10BIT_SCALE)
+ return 0;
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_CONST_ATTR(sampling_frequency_available, "125 250");
+
+static struct attribute *mma7455_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group mma7455_group = {
+ .attrs = mma7455_attributes,
+};
+
+static const struct iio_info mma7455_info = {
+ .attrs = &mma7455_group,
+ .read_raw = mma7455_read_raw,
+ .write_raw = mma7455_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define MMA7455_CHANNEL(axis, idx) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .address = MMA7455_REG_##axis##OUTL,\
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = idx, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 10, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+}
+
+static const struct iio_chan_spec mma7455_channels[] = {
+ MMA7455_CHANNEL(X, 0),
+ MMA7455_CHANNEL(Y, 1),
+ MMA7455_CHANNEL(Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const unsigned long mma7455_scan_masks[] = {0x7, 0};
+
+const struct regmap_config mma7455_core_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MMA7455_REG_TW,
+};
+EXPORT_SYMBOL_GPL(mma7455_core_regmap);
+
+int mma7455_core_probe(struct device *dev, struct regmap *regmap,
+ const char *name)
+{
+ struct mma7455_data *mma7455;
+ struct iio_dev *indio_dev;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(regmap, MMA7455_REG_WHOAMI, &reg);
+ if (ret) {
+ dev_err(dev, "unable to read reg\n");
+ return ret;
+ }
+
+ if (reg != MMA7455_WHOAMI_ID) {
+ dev_err(dev, "device id mismatch\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*mma7455));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, indio_dev);
+ mma7455 = iio_priv(indio_dev);
+ mma7455->regmap = regmap;
+ mma7455->dev = dev;
+
+ indio_dev->info = &mma7455_info;
+ indio_dev->name = name;
+ indio_dev->dev.parent = dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = mma7455_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mma7455_channels);
+ indio_dev->available_scan_masks = mma7455_scan_masks;
+
+ regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
+ MMA7455_MCTL_MODE_MEASURE);
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ mma7455_trigger_handler, NULL);
+ if (ret) {
+ dev_err(dev, "unable to setup triggered buffer\n");
+ return ret;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "unable to register device\n");
+ iio_triggered_buffer_cleanup(indio_dev);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mma7455_core_probe);
+
+int mma7455_core_remove(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct mma7455_data *mma7455 = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+
+ regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
+ MMA7455_MCTL_MODE_STANDBY);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mma7455_core_remove);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c
new file mode 100644
index 000000000000..3cab5fb4a3c4
--- /dev/null
+++ b/drivers/iio/accel/mma7455_i2c.c
@@ -0,0 +1,56 @@
+/*
+ * IIO accel I2C driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mma7455.h"
+
+static int mma7455_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ const char *name = NULL;
+
+ regmap = devm_regmap_init_i2c(i2c, &mma7455_core_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ if (id)
+ name = id->name;
+
+ return mma7455_core_probe(&i2c->dev, regmap, name);
+}
+
+static int mma7455_i2c_remove(struct i2c_client *i2c)
+{
+ return mma7455_core_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id mma7455_i2c_ids[] = {
+ { "mma7455", 0 },
+ { "mma7456", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids);
+
+static struct i2c_driver mma7455_i2c_driver = {
+ .probe = mma7455_i2c_probe,
+ .remove = mma7455_i2c_remove,
+ .id_table = mma7455_i2c_ids,
+ .driver = {
+ .name = "mma7455-i2c",
+ },
+};
+module_i2c_driver(mma7455_i2c_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c
new file mode 100644
index 000000000000..79df8f27cf99
--- /dev/null
+++ b/drivers/iio/accel/mma7455_spi.c
@@ -0,0 +1,52 @@
+/*
+ * IIO accel SPI driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@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.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "mma7455.h"
+
+static int mma7455_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &mma7455_core_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return mma7455_core_probe(&spi->dev, regmap, id->name);
+}
+
+static int mma7455_spi_remove(struct spi_device *spi)
+{
+ return mma7455_core_remove(&spi->dev);
+}
+
+static const struct spi_device_id mma7455_spi_ids[] = {
+ { "mma7455", 0 },
+ { "mma7456", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, mma7455_spi_ids);
+
+static struct spi_driver mma7455_spi_driver = {
+ .probe = mma7455_spi_probe,
+ .remove = mma7455_spi_remove,
+ .id_table = mma7455_spi_ids,
+ .driver = {
+ .name = "mma7455-spi",
+ },
+};
+module_spi_driver(mma7455_spi_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 1eccc2dcf14c..ccc632a7cf01 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -29,6 +29,7 @@
#include <linux/iio/events.h>
#include <linux/delay.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
@@ -57,7 +58,6 @@
#define MMA8452_FF_MT_COUNT 0x18
#define MMA8452_TRANSIENT_CFG 0x1d
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
-#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
#define MMA8452_TRANSIENT_SRC 0x1e
#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
@@ -143,6 +143,13 @@ struct mma_chip_info {
u8 ev_count;
};
+enum {
+ idx_x,
+ idx_y,
+ idx_z,
+ idx_ts,
+};
+
static int mma8452_drdy(struct mma8452_data *data)
{
int tries = 150;
@@ -816,31 +823,31 @@ static struct attribute_group mma8452_event_attribute_group = {
}
static const struct iio_chan_spec mma8452_channels[] = {
- MMA8452_CHANNEL(X, 0, 12),
- MMA8452_CHANNEL(Y, 1, 12),
- MMA8452_CHANNEL(Z, 2, 12),
- IIO_CHAN_SOFT_TIMESTAMP(3),
+ MMA8452_CHANNEL(X, idx_x, 12),
+ MMA8452_CHANNEL(Y, idx_y, 12),
+ MMA8452_CHANNEL(Z, idx_z, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
static const struct iio_chan_spec mma8453_channels[] = {
- MMA8452_CHANNEL(X, 0, 10),
- MMA8452_CHANNEL(Y, 1, 10),
- MMA8452_CHANNEL(Z, 2, 10),
- IIO_CHAN_SOFT_TIMESTAMP(3),
+ MMA8452_CHANNEL(X, idx_x, 10),
+ MMA8452_CHANNEL(Y, idx_y, 10),
+ MMA8452_CHANNEL(Z, idx_z, 10),
+ IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
static const struct iio_chan_spec mma8652_channels[] = {
- MMA8652_CHANNEL(X, 0, 12),
- MMA8652_CHANNEL(Y, 1, 12),
- MMA8652_CHANNEL(Z, 2, 12),
- IIO_CHAN_SOFT_TIMESTAMP(3),
+ MMA8652_CHANNEL(X, idx_x, 12),
+ MMA8652_CHANNEL(Y, idx_y, 12),
+ MMA8652_CHANNEL(Z, idx_z, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
static const struct iio_chan_spec mma8653_channels[] = {
- MMA8652_CHANNEL(X, 0, 10),
- MMA8652_CHANNEL(Y, 1, 10),
- MMA8652_CHANNEL(Z, 2, 10),
- IIO_CHAN_SOFT_TIMESTAMP(3),
+ MMA8652_CHANNEL(X, idx_x, 10),
+ MMA8652_CHANNEL(Y, idx_y, 10),
+ MMA8652_CHANNEL(Z, idx_z, 10),
+ IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
enum {
@@ -1130,13 +1137,21 @@ static int mma8452_probe(struct i2c_client *client,
MMA8452_INT_FF_MT;
int enabled_interrupts = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT;
+ int irq2;
- /* Assume wired to INT1 pin */
- ret = i2c_smbus_write_byte_data(client,
- MMA8452_CTRL_REG5,
- supported_interrupts);
- if (ret < 0)
- return ret;
+ irq2 = of_irq_get_byname(client->dev.of_node, "INT2");
+
+ if (irq2 == client->irq) {
+ dev_dbg(&client->dev, "using interrupt line INT2\n");
+ } else {
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8452_CTRL_REG5,
+ supported_interrupts);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "using interrupt line INT1\n");
+ }
ret = i2c_smbus_write_byte_data(client,
MMA8452_CTRL_REG4,
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 7db7cc0bf362..d899a4d4307f 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -495,25 +495,23 @@ static int mma9551_probe(struct i2c_client *client,
if (ret < 0)
goto out_poweroff;
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "unable to register iio device\n");
- goto out_poweroff;
- }
-
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
- goto out_iio_unregister;
+ goto out_poweroff;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
MMA9551_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto out_poweroff;
+ }
+
return 0;
-out_iio_unregister:
- iio_device_unregister(indio_dev);
out_poweroff:
mma9551_set_device_state(client, false);
@@ -525,11 +523,12 @@ static int mma9551_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma9551_data *data = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
- iio_device_unregister(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 9408ef3add58..fa7d36217c4b 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1133,27 +1133,24 @@ static int mma9553_probe(struct i2c_client *client,
}
}
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "unable to register iio device\n");
- goto out_poweroff;
- }
-
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
- goto out_iio_unregister;
+ goto out_poweroff;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
MMA9551_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto out_poweroff;
+ }
+ dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
return 0;
-out_iio_unregister:
- iio_device_unregister(indio_dev);
out_poweroff:
mma9551_set_device_state(client, false);
return ret;
@@ -1164,11 +1161,12 @@ static int mma9553_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma9553_data *data = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
- iio_device_unregister(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
new file mode 100644
index 000000000000..97ccde722e7b
--- /dev/null
+++ b/drivers/iio/accel/mxc6255.c
@@ -0,0 +1,198 @@
+/*
+ * MXC6255 - MEMSIC orientation sensing accelerometer
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for MXC6255 (7-bit I2C slave address 0x15).
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/iio/iio.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/iio/sysfs.h>
+
+#define MXC6255_DRV_NAME "mxc6255"
+#define MXC6255_REGMAP_NAME "mxc6255_regmap"
+
+#define MXC6255_REG_XOUT 0x00
+#define MXC6255_REG_YOUT 0x01
+#define MXC6255_REG_CHIP_ID 0x08
+
+#define MXC6255_CHIP_ID 0x05
+
+/*
+ * MXC6255 has only one measurement range: +/- 2G.
+ * The acceleration output is an 8-bit value.
+ *
+ * Scale is calculated as follows:
+ * (2 + 2) * 9.80665 / (2^8 - 1) = 0.153829
+ *
+ * Scale value for +/- 2G measurement range
+ */
+#define MXC6255_SCALE 153829
+
+enum mxc6255_axis {
+ AXIS_X,
+ AXIS_Y,
+};
+
+struct mxc6255_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
+static int mxc6255_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mxc6255_data *data = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(data->regmap, chan->address, &reg);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Error reading reg %lu\n", chan->address);
+ return ret;
+ }
+
+ *val = sign_extend32(reg, 7);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = MXC6255_SCALE;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mxc6255_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = mxc6255_read_raw,
+};
+
+#define MXC6255_CHANNEL(_axis, reg) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .address = reg, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec mxc6255_channels[] = {
+ MXC6255_CHANNEL(X, MXC6255_REG_XOUT),
+ MXC6255_CHANNEL(Y, MXC6255_REG_YOUT),
+};
+
+static bool mxc6255_is_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MXC6255_REG_XOUT:
+ case MXC6255_REG_YOUT:
+ case MXC6255_REG_CHIP_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config mxc6255_regmap_config = {
+ .name = MXC6255_REGMAP_NAME,
+
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .readable_reg = mxc6255_is_readable_reg,
+};
+
+static int mxc6255_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mxc6255_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ unsigned int chip_id;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &mxc6255_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Error initializing regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->regmap = regmap;
+
+ indio_dev->name = MXC6255_DRV_NAME;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = mxc6255_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mxc6255_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mxc6255_info;
+
+ ret = regmap_read(data->regmap, MXC6255_REG_CHIP_ID, &chip_id);
+ if (ret < 0) {
+ dev_err(&client->dev, "Error reading chip id %d\n", ret);
+ return ret;
+ }
+
+ if (chip_id != MXC6255_CHIP_ID) {
+ dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
+ return -ENODEV;
+ }
+
+ dev_dbg(&client->dev, "Chip id %x\n", chip_id);
+
+ ret = devm_iio_device_register(&client->dev, indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not register IIO device\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct acpi_device_id mxc6255_acpi_match[] = {
+ {"MXC6255", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
+
+static const struct i2c_device_id mxc6255_id[] = {
+ {"mxc6255", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mxc6255_id);
+
+static struct i2c_driver mxc6255_driver = {
+ .driver = {
+ .name = MXC6255_DRV_NAME,
+ .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
+ },
+ .probe = mxc6255_probe,
+ .id_table = mxc6255_id,
+};
+
+module_i2c_driver(mxc6255_driver);
+
+MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
+MODULE_DESCRIPTION("MEMSIC MXC6255 orientation sensing accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 468f21fa2950..5d4a1897b293 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -27,6 +27,7 @@
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel"
+#define LIS2DH12_ACCEL_DEV_NAME "lis2dh12_accel"
/**
* struct st_sensors_platform_data - default accel platform data
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 197a08b4e2f3..70f042797f15 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -232,6 +232,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
[3] = LSM330DL_ACCEL_DEV_NAME,
[4] = LSM330DLC_ACCEL_DEV_NAME,
[5] = LSM303AGR_ACCEL_DEV_NAME,
+ [6] = LIS2DH12_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 8b9cc84fd44f..294a32f89367 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -72,6 +72,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lsm303agr-accel",
.data = LSM303AGR_ACCEL_DEV_NAME,
},
+ {
+ .compatible = "st,lis2dh12-accel",
+ .data = LIS2DH12_ACCEL_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -121,6 +125,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
+ { LIS2DH12_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index f71b0d391272..fcd5847a3fd3 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -58,6 +58,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
+ { LIS2DH12_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 7868c744fd4b..605ff42c4631 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -194,6 +194,25 @@ config HI8435
This driver can also be built as a module. If so, the module will be
called hi8435.
+config INA2XX_ADC
+ tristate "Texas Instruments INA2xx Power Monitors IIO driver"
+ depends on I2C && !SENSORS_INA2XX
+ select REGMAP_I2C
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Say yes here to build support for TI INA2xx family of Power Monitors.
+ This driver is mutually exclusive with the HWMON version.
+
+config IMX7D_ADC
+ tristate "IMX7D ADC driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ help
+ Say yes here to build support for IMX7D ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called imx7d_adc.
+
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
@@ -275,6 +294,14 @@ config NAU7802
To compile this driver as a module, choose M here: the
module will be called nau7802.
+config PALMAS_GPADC
+ tristate "TI Palmas General Purpose ADC"
+ depends on MFD_PALMAS
+ help
+ Palmas series pmic chip by Texas Instruments (twl6035/6037)
+ is used in smartphones and tablets and supports a 16 channel
+ general purpose ADC.
+
config QCOM_SPMI_IADC
tristate "Qualcomm SPMI PMIC current ADC"
depends on SPMI
@@ -324,15 +351,25 @@ config TI_ADC081C
called ti-adc081c.
config TI_ADC128S052
- tristate "Texas Instruments ADC128S052/ADC122S021"
+ tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI
help
- If you say yes here you get support for Texas Instruments ADC128S052
- and ADC122S021 chips.
+ If you say yes here you get support for Texas Instruments ADC128S052,
+ ADC122S021 and ADC124S021 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
+config TI_ADS8688
+ tristate "Texas Instruments ADS8688"
+ depends on SPI && OF
+ help
+ If you say yes here you get support for Texas Instruments ADS8684 and
+ and ADS8688 ADC chips
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads8688.
+
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 99b37a963a1e..6435780e9b71 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_HI8435) += hi8435.o
+obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
+obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
@@ -27,11 +29,13 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
+obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
+obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index 4d960d3b93c0..7b07bb651671 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -478,10 +478,9 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
*val2 = st->
scale_avail[(st->conf >> 8) & 0x7][1];
return IIO_VAL_INT_PLUS_NANO;
- } else {
- /* 1170mV / 2^23 * 6 */
- scale_uv = (1170ULL * 1000000000ULL * 6ULL);
}
+ /* 1170mV / 2^23 * 6 */
+ scale_uv = (1170ULL * 1000000000ULL * 6ULL);
break;
case IIO_TEMP:
/* 1170mV / 0.81 mV/C / 2^23 */
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 7b40925dd4ff..f284cd6a93d6 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -742,7 +742,7 @@ static int at91_adc_of_get_resolution(struct at91_adc_state *st,
return count;
}
- resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL);
+ resolutions = kmalloc_array(count, sizeof(*resolutions), GFP_KERNEL);
if (!resolutions)
return -ENOMEM;
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 3a2dbb3b4926..c15756d7bf7f 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -35,6 +35,7 @@
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/err.h>
+#include <linux/input.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
@@ -42,12 +43,18 @@
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <linux/platform_data/touchscreen-s3c2410.h>
+
/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
+#define ADC_V1_TSC(x) ((x) + 0x04)
#define ADC_V1_DLY(x) ((x) + 0x08)
#define ADC_V1_DATX(x) ((x) + 0x0C)
+#define ADC_V1_DATY(x) ((x) + 0x10)
+#define ADC_V1_UPDN(x) ((x) + 0x14)
#define ADC_V1_INTCLR(x) ((x) + 0x18)
#define ADC_V1_MUX(x) ((x) + 0x1c)
+#define ADC_V1_CLRINTPNDNUP(x) ((x) + 0x20)
/* S3C2410 ADC registers definitions */
#define ADC_S3C2410_MUX(x) ((x) + 0x18)
@@ -71,6 +78,30 @@
#define ADC_S3C2410_DATX_MASK 0x3FF
#define ADC_S3C2416_CON_RES_SEL (1u << 3)
+/* touch screen always uses channel 0 */
+#define ADC_S3C2410_MUX_TS 0
+
+/* ADCTSC Register Bits */
+#define ADC_S3C2443_TSC_UD_SEN (1u << 8)
+#define ADC_S3C2410_TSC_YM_SEN (1u << 7)
+#define ADC_S3C2410_TSC_YP_SEN (1u << 6)
+#define ADC_S3C2410_TSC_XM_SEN (1u << 5)
+#define ADC_S3C2410_TSC_XP_SEN (1u << 4)
+#define ADC_S3C2410_TSC_PULL_UP_DISABLE (1u << 3)
+#define ADC_S3C2410_TSC_AUTO_PST (1u << 2)
+#define ADC_S3C2410_TSC_XY_PST(x) (((x) & 0x3) << 0)
+
+#define ADC_TSC_WAIT4INT (ADC_S3C2410_TSC_YM_SEN | \
+ ADC_S3C2410_TSC_YP_SEN | \
+ ADC_S3C2410_TSC_XP_SEN | \
+ ADC_S3C2410_TSC_XY_PST(3))
+
+#define ADC_TSC_AUTOPST (ADC_S3C2410_TSC_YM_SEN | \
+ ADC_S3C2410_TSC_YP_SEN | \
+ ADC_S3C2410_TSC_XP_SEN | \
+ ADC_S3C2410_TSC_AUTO_PST | \
+ ADC_S3C2410_TSC_XY_PST(0))
+
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
@@ -88,7 +119,9 @@
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
#define ADC_CON_EN_START_MASK (0x3 << 0)
+#define ADC_DATX_PRESSED (1u << 15)
#define ADC_DATX_MASK 0xFFF
+#define ADC_DATY_MASK 0xFFF
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
@@ -98,17 +131,24 @@
struct exynos_adc {
struct exynos_adc_data *data;
struct device *dev;
+ struct input_dev *input;
void __iomem *regs;
struct regmap *pmu_map;
struct clk *clk;
struct clk *sclk;
unsigned int irq;
+ unsigned int tsirq;
+ unsigned int delay;
struct regulator *vdd;
struct completion completion;
u32 value;
unsigned int version;
+
+ bool read_ts;
+ u32 ts_x;
+ u32 ts_y;
};
struct exynos_adc_data {
@@ -197,6 +237,9 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info)
/* Enable 12-bit ADC resolution */
con1 |= ADC_V1_CON_RES;
writel(con1, ADC_V1_CON(info->regs));
+
+ /* set touchscreen delay */
+ writel(info->delay, ADC_V1_DLY(info->regs));
}
static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
@@ -480,8 +523,8 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
if (info->data->start_conv)
info->data->start_conv(info, chan->address);
- timeout = wait_for_completion_timeout
- (&info->completion, EXYNOS_ADC_TIMEOUT);
+ timeout = wait_for_completion_timeout(&info->completion,
+ EXYNOS_ADC_TIMEOUT);
if (timeout == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
if (info->data->init_hw)
@@ -498,13 +541,55 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
return ret;
}
+static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y)
+{
+ struct exynos_adc *info = iio_priv(indio_dev);
+ unsigned long timeout;
+ int ret;
+
+ mutex_lock(&indio_dev->mlock);
+ info->read_ts = true;
+
+ reinit_completion(&info->completion);
+
+ writel(ADC_S3C2410_TSC_PULL_UP_DISABLE | ADC_TSC_AUTOPST,
+ ADC_V1_TSC(info->regs));
+
+ /* Select the ts channel to be used and Trigger conversion */
+ info->data->start_conv(info, ADC_S3C2410_MUX_TS);
+
+ timeout = wait_for_completion_timeout(&info->completion,
+ EXYNOS_ADC_TIMEOUT);
+ if (timeout == 0) {
+ dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
+ if (info->data->init_hw)
+ info->data->init_hw(info);
+ ret = -ETIMEDOUT;
+ } else {
+ *x = info->ts_x;
+ *y = info->ts_y;
+ ret = 0;
+ }
+
+ info->read_ts = false;
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
u32 mask = info->data->mask;
/* Read value */
- info->value = readl(ADC_V1_DATX(info->regs)) & mask;
+ if (info->read_ts) {
+ info->ts_x = readl(ADC_V1_DATX(info->regs));
+ info->ts_y = readl(ADC_V1_DATY(info->regs));
+ writel(ADC_TSC_WAIT4INT | ADC_S3C2443_TSC_UD_SEN, ADC_V1_TSC(info->regs));
+ } else {
+ info->value = readl(ADC_V1_DATX(info->regs)) & mask;
+ }
/* clear irq */
if (info->data->clear_irq)
@@ -515,6 +600,46 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * Here we (ab)use a threaded interrupt handler to stay running
+ * for as long as the touchscreen remains pressed, we report
+ * a new event with the latest data and then sleep until the
+ * next timer tick. This mirrors the behavior of the old
+ * driver, with much less code.
+ */
+static irqreturn_t exynos_ts_isr(int irq, void *dev_id)
+{
+ struct exynos_adc *info = dev_id;
+ struct iio_dev *dev = dev_get_drvdata(info->dev);
+ u32 x, y;
+ bool pressed;
+ int ret;
+
+ while (info->input->users) {
+ ret = exynos_read_s3c64xx_ts(dev, &x, &y);
+ if (ret == -ETIMEDOUT)
+ break;
+
+ pressed = x & y & ADC_DATX_PRESSED;
+ if (!pressed) {
+ input_report_key(info->input, BTN_TOUCH, 0);
+ input_sync(info->input);
+ break;
+ }
+
+ input_report_abs(info->input, ABS_X, x & ADC_DATX_MASK);
+ input_report_abs(info->input, ABS_Y, y & ADC_DATY_MASK);
+ input_report_key(info->input, BTN_TOUCH, 1);
+ input_sync(info->input);
+
+ msleep(1);
+ };
+
+ writel(0, ADC_V1_CLRINTPNDNUP(info->regs));
+
+ return IRQ_HANDLED;
+}
+
static int exynos_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
@@ -566,18 +691,72 @@ static int exynos_adc_remove_devices(struct device *dev, void *c)
return 0;
}
+static int exynos_adc_ts_open(struct input_dev *dev)
+{
+ struct exynos_adc *info = input_get_drvdata(dev);
+
+ enable_irq(info->tsirq);
+
+ return 0;
+}
+
+static void exynos_adc_ts_close(struct input_dev *dev)
+{
+ struct exynos_adc *info = input_get_drvdata(dev);
+
+ disable_irq(info->tsirq);
+}
+
+static int exynos_adc_ts_init(struct exynos_adc *info)
+{
+ int ret;
+
+ if (info->tsirq <= 0)
+ return -ENODEV;
+
+ info->input = input_allocate_device();
+ if (!info->input)
+ return -ENOMEM;
+
+ info->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ info->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(info->input, ABS_X, 0, 0x3FF, 0, 0);
+ input_set_abs_params(info->input, ABS_Y, 0, 0x3FF, 0, 0);
+
+ info->input->name = "S3C24xx TouchScreen";
+ info->input->id.bustype = BUS_HOST;
+ info->input->open = exynos_adc_ts_open;
+ info->input->close = exynos_adc_ts_close;
+
+ input_set_drvdata(info->input, info);
+
+ ret = input_register_device(info->input);
+ if (ret) {
+ input_free_device(info->input);
+ return ret;
+ }
+
+ disable_irq(info->tsirq);
+ ret = request_threaded_irq(info->tsirq, NULL, exynos_ts_isr,
+ IRQF_ONESHOT, "touchscreen", info);
+ if (ret)
+ input_unregister_device(info->input);
+
+ return ret;
+}
+
static int exynos_adc_probe(struct platform_device *pdev)
{
struct exynos_adc *info = NULL;
struct device_node *np = pdev->dev.of_node;
+ struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = NULL;
struct resource *mem;
+ bool has_ts = false;
int ret = -ENODEV;
int irq;
- if (!np)
- return ret;
-
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
@@ -613,8 +792,14 @@ static int exynos_adc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "no irq resource?\n");
return irq;
}
-
info->irq = irq;
+
+ irq = platform_get_irq(pdev, 1);
+ if (irq == -EPROBE_DEFER)
+ return irq;
+
+ info->tsirq = irq;
+
info->dev = &pdev->dev;
init_completion(&info->completion);
@@ -680,6 +865,22 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (info->data->init_hw)
info->data->init_hw(info);
+ /* leave out any TS related code if unreachable */
+ if (IS_REACHABLE(CONFIG_INPUT)) {
+ has_ts = of_property_read_bool(pdev->dev.of_node,
+ "has-touchscreen") || pdata;
+ }
+
+ if (pdata)
+ info->delay = pdata->delay;
+ else
+ info->delay = 10000;
+
+ if (has_ts)
+ ret = exynos_adc_ts_init(info);
+ if (ret)
+ goto err_iio;
+
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed adding child nodes\n");
@@ -691,6 +892,11 @@ static int exynos_adc_probe(struct platform_device *pdev)
err_of_populate:
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
+ if (has_ts) {
+ input_unregister_device(info->input);
+ free_irq(info->tsirq, info);
+ }
+err_iio:
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
@@ -710,6 +916,10 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
+ if (IS_REACHABLE(CONFIG_INPUT)) {
+ free_irq(info->tsirq, info);
+ input_unregister_device(info->input);
+ }
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
new file mode 100644
index 000000000000..e2241ee94783
--- /dev/null
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -0,0 +1,609 @@
+/*
+ * Freescale i.MX7D ADC driver
+ *
+ * Copyright (C) 2015 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/sysfs.h>
+
+/* ADC register */
+#define IMX7D_REG_ADC_CH_A_CFG1 0x00
+#define IMX7D_REG_ADC_CH_A_CFG2 0x10
+#define IMX7D_REG_ADC_CH_B_CFG1 0x20
+#define IMX7D_REG_ADC_CH_B_CFG2 0x30
+#define IMX7D_REG_ADC_CH_C_CFG1 0x40
+#define IMX7D_REG_ADC_CH_C_CFG2 0x50
+#define IMX7D_REG_ADC_CH_D_CFG1 0x60
+#define IMX7D_REG_ADC_CH_D_CFG2 0x70
+#define IMX7D_REG_ADC_CH_SW_CFG 0x80
+#define IMX7D_REG_ADC_TIMER_UNIT 0x90
+#define IMX7D_REG_ADC_DMA_FIFO 0xa0
+#define IMX7D_REG_ADC_FIFO_STATUS 0xb0
+#define IMX7D_REG_ADC_INT_SIG_EN 0xc0
+#define IMX7D_REG_ADC_INT_EN 0xd0
+#define IMX7D_REG_ADC_INT_STATUS 0xe0
+#define IMX7D_REG_ADC_CHA_B_CNV_RSLT 0xf0
+#define IMX7D_REG_ADC_CHC_D_CNV_RSLT 0x100
+#define IMX7D_REG_ADC_CH_SW_CNV_RSLT 0x110
+#define IMX7D_REG_ADC_DMA_FIFO_DAT 0x120
+#define IMX7D_REG_ADC_ADC_CFG 0x130
+
+#define IMX7D_REG_ADC_CHANNEL_CFG2_BASE 0x10
+#define IMX7D_EACH_CHANNEL_REG_OFFSET 0x20
+
+#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN (0x1 << 31)
+#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE BIT(30)
+#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN BIT(29)
+#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_SEL(x) ((x) << 24)
+
+#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_4 (0x0 << 12)
+#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_8 (0x1 << 12)
+#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_16 (0x2 << 12)
+#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_32 (0x3 << 12)
+
+#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_4 (0x0 << 29)
+#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_8 (0x1 << 29)
+#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_16 (0x2 << 29)
+#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_32 (0x3 << 29)
+#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_64 (0x4 << 29)
+#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_128 (0x5 << 29)
+
+#define IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN BIT(31)
+#define IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN BIT(1)
+#define IMX7D_REG_ADC_ADC_CFG_ADC_EN BIT(0)
+
+#define IMX7D_REG_ADC_INT_CHA_COV_INT_EN BIT(8)
+#define IMX7D_REG_ADC_INT_CHB_COV_INT_EN BIT(9)
+#define IMX7D_REG_ADC_INT_CHC_COV_INT_EN BIT(10)
+#define IMX7D_REG_ADC_INT_CHD_COV_INT_EN BIT(11)
+#define IMX7D_REG_ADC_INT_CHANNEL_INT_EN \
+ (IMX7D_REG_ADC_INT_CHA_COV_INT_EN | \
+ IMX7D_REG_ADC_INT_CHB_COV_INT_EN | \
+ IMX7D_REG_ADC_INT_CHC_COV_INT_EN | \
+ IMX7D_REG_ADC_INT_CHD_COV_INT_EN)
+#define IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS 0xf00
+#define IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT 0xf0000
+
+#define IMX7D_ADC_TIMEOUT msecs_to_jiffies(100)
+
+enum imx7d_adc_clk_pre_div {
+ IMX7D_ADC_ANALOG_CLK_PRE_DIV_4,
+ IMX7D_ADC_ANALOG_CLK_PRE_DIV_8,
+ IMX7D_ADC_ANALOG_CLK_PRE_DIV_16,
+ IMX7D_ADC_ANALOG_CLK_PRE_DIV_32,
+ IMX7D_ADC_ANALOG_CLK_PRE_DIV_64,
+ IMX7D_ADC_ANALOG_CLK_PRE_DIV_128,
+};
+
+enum imx7d_adc_average_num {
+ IMX7D_ADC_AVERAGE_NUM_4,
+ IMX7D_ADC_AVERAGE_NUM_8,
+ IMX7D_ADC_AVERAGE_NUM_16,
+ IMX7D_ADC_AVERAGE_NUM_32,
+};
+
+struct imx7d_adc_feature {
+ enum imx7d_adc_clk_pre_div clk_pre_div;
+ enum imx7d_adc_average_num avg_num;
+
+ u32 core_time_unit; /* impact the sample rate */
+
+ bool average_en;
+};
+
+struct imx7d_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+
+ u32 vref_uv;
+ u32 value;
+ u32 channel;
+ u32 pre_div_num;
+
+ struct regulator *vref;
+ struct imx7d_adc_feature adc_feature;
+
+ struct completion completion;
+};
+
+struct imx7d_adc_analogue_core_clk {
+ u32 pre_div;
+ u32 reg_config;
+};
+
+#define IMX7D_ADC_ANALOGUE_CLK_CONFIG(_pre_div, _reg_conf) { \
+ .pre_div = (_pre_div), \
+ .reg_config = (_reg_conf), \
+}
+
+static const struct imx7d_adc_analogue_core_clk imx7d_adc_analogue_clk[] = {
+ IMX7D_ADC_ANALOGUE_CLK_CONFIG(4, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_4),
+ IMX7D_ADC_ANALOGUE_CLK_CONFIG(8, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_8),
+ IMX7D_ADC_ANALOGUE_CLK_CONFIG(16, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_16),
+ IMX7D_ADC_ANALOGUE_CLK_CONFIG(32, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_32),
+ IMX7D_ADC_ANALOGUE_CLK_CONFIG(64, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_64),
+ IMX7D_ADC_ANALOGUE_CLK_CONFIG(128, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_128),
+};
+
+#define IMX7D_ADC_CHAN(_idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec imx7d_adc_iio_channels[] = {
+ IMX7D_ADC_CHAN(0),
+ IMX7D_ADC_CHAN(1),
+ IMX7D_ADC_CHAN(2),
+ IMX7D_ADC_CHAN(3),
+ IMX7D_ADC_CHAN(4),
+ IMX7D_ADC_CHAN(5),
+ IMX7D_ADC_CHAN(6),
+ IMX7D_ADC_CHAN(7),
+ IMX7D_ADC_CHAN(8),
+ IMX7D_ADC_CHAN(9),
+ IMX7D_ADC_CHAN(10),
+ IMX7D_ADC_CHAN(11),
+ IMX7D_ADC_CHAN(12),
+ IMX7D_ADC_CHAN(13),
+ IMX7D_ADC_CHAN(14),
+ IMX7D_ADC_CHAN(15),
+};
+
+static const u32 imx7d_adc_average_num[] = {
+ IMX7D_REG_ADC_CH_CFG2_AVG_NUM_4,
+ IMX7D_REG_ADC_CH_CFG2_AVG_NUM_8,
+ IMX7D_REG_ADC_CH_CFG2_AVG_NUM_16,
+ IMX7D_REG_ADC_CH_CFG2_AVG_NUM_32,
+};
+
+static void imx7d_adc_feature_config(struct imx7d_adc *info)
+{
+ info->adc_feature.clk_pre_div = IMX7D_ADC_ANALOG_CLK_PRE_DIV_4;
+ info->adc_feature.avg_num = IMX7D_ADC_AVERAGE_NUM_32;
+ info->adc_feature.core_time_unit = 1;
+ info->adc_feature.average_en = true;
+}
+
+static void imx7d_adc_sample_rate_set(struct imx7d_adc *info)
+{
+ struct imx7d_adc_feature *adc_feature = &info->adc_feature;
+ struct imx7d_adc_analogue_core_clk adc_analogure_clk;
+ u32 i;
+ u32 tmp_cfg1;
+ u32 sample_rate = 0;
+
+ /*
+ * Before sample set, disable channel A,B,C,D. Here we
+ * clear the bit 31 of register REG_ADC_CH_A\B\C\D_CFG1.
+ */
+ for (i = 0; i < 4; i++) {
+ tmp_cfg1 =
+ readl(info->regs + i * IMX7D_EACH_CHANNEL_REG_OFFSET);
+ tmp_cfg1 &= ~IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN;
+ writel(tmp_cfg1,
+ info->regs + i * IMX7D_EACH_CHANNEL_REG_OFFSET);
+ }
+
+ adc_analogure_clk = imx7d_adc_analogue_clk[adc_feature->clk_pre_div];
+ sample_rate |= adc_analogure_clk.reg_config;
+ info->pre_div_num = adc_analogure_clk.pre_div;
+
+ sample_rate |= adc_feature->core_time_unit;
+ writel(sample_rate, info->regs + IMX7D_REG_ADC_TIMER_UNIT);
+}
+
+static void imx7d_adc_hw_init(struct imx7d_adc *info)
+{
+ u32 cfg;
+
+ /* power up and enable adc analogue core */
+ cfg = readl(info->regs + IMX7D_REG_ADC_ADC_CFG);
+ cfg &= ~(IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN |
+ IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN);
+ cfg |= IMX7D_REG_ADC_ADC_CFG_ADC_EN;
+ writel(cfg, info->regs + IMX7D_REG_ADC_ADC_CFG);
+
+ /* enable channel A,B,C,D interrupt */
+ writel(IMX7D_REG_ADC_INT_CHANNEL_INT_EN,
+ info->regs + IMX7D_REG_ADC_INT_SIG_EN);
+ writel(IMX7D_REG_ADC_INT_CHANNEL_INT_EN,
+ info->regs + IMX7D_REG_ADC_INT_EN);
+
+ imx7d_adc_sample_rate_set(info);
+}
+
+static void imx7d_adc_channel_set(struct imx7d_adc *info)
+{
+ u32 cfg1 = 0;
+ u32 cfg2;
+ u32 channel;
+
+ channel = info->channel;
+
+ /* the channel choose single conversion, and enable average mode */
+ cfg1 |= (IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN |
+ IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE);
+ if (info->adc_feature.average_en)
+ cfg1 |= IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN;
+
+ /*
+ * physical channel 0 chose logical channel A
+ * physical channel 1 chose logical channel B
+ * physical channel 2 chose logical channel C
+ * physical channel 3 chose logical channel D
+ */
+ cfg1 |= IMX7D_REG_ADC_CH_CFG1_CHANNEL_SEL(channel);
+
+ /*
+ * read register REG_ADC_CH_A\B\C\D_CFG2, according to the
+ * channel chosen
+ */
+ cfg2 = readl(info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel +
+ IMX7D_REG_ADC_CHANNEL_CFG2_BASE);
+
+ cfg2 |= imx7d_adc_average_num[info->adc_feature.avg_num];
+
+ /*
+ * write the register REG_ADC_CH_A\B\C\D_CFG2, according to
+ * the channel chosen
+ */
+ writel(cfg2, info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel +
+ IMX7D_REG_ADC_CHANNEL_CFG2_BASE);
+ writel(cfg1, info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel);
+}
+
+static u32 imx7d_adc_get_sample_rate(struct imx7d_adc *info)
+{
+ /* input clock is always 24MHz */
+ u32 input_clk = 24000000;
+ u32 analogue_core_clk;
+ u32 core_time_unit = info->adc_feature.core_time_unit;
+ u32 tmp;
+
+ analogue_core_clk = input_clk / info->pre_div_num;
+ tmp = (core_time_unit + 1) * 6;
+
+ return analogue_core_clk / tmp;
+}
+
+static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct imx7d_adc *info = iio_priv(indio_dev);
+
+ u32 channel;
+ long ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ reinit_completion(&info->completion);
+
+ channel = chan->channel & 0x03;
+ info->channel = channel;
+ imx7d_adc_channel_set(info);
+
+ ret = wait_for_completion_interruptible_timeout
+ (&info->completion, IMX7D_ADC_TIMEOUT);
+ if (ret == 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+
+ *val = info->value;
+ mutex_unlock(&indio_dev->mlock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ info->vref_uv = regulator_get_voltage(info->vref);
+ *val = info->vref_uv / 1000;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = imx7d_adc_get_sample_rate(info);
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx7d_adc_read_data(struct imx7d_adc *info)
+{
+ u32 channel;
+ u32 value;
+
+ channel = info->channel & 0x03;
+
+ /*
+ * channel A and B conversion result share one register,
+ * bit[27~16] is the channel B conversion result,
+ * bit[11~0] is the channel A conversion result.
+ * channel C and D is the same.
+ */
+ if (channel < 2)
+ value = readl(info->regs + IMX7D_REG_ADC_CHA_B_CNV_RSLT);
+ else
+ value = readl(info->regs + IMX7D_REG_ADC_CHC_D_CNV_RSLT);
+ if (channel & 0x1) /* channel B or D */
+ value = (value >> 16) & 0xFFF;
+ else /* channel A or C */
+ value &= 0xFFF;
+
+ return value;
+}
+
+static irqreturn_t imx7d_adc_isr(int irq, void *dev_id)
+{
+ struct imx7d_adc *info = (struct imx7d_adc *)dev_id;
+ int status;
+
+ status = readl(info->regs + IMX7D_REG_ADC_INT_STATUS);
+ if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS) {
+ info->value = imx7d_adc_read_data(info);
+ complete(&info->completion);
+
+ /*
+ * The register IMX7D_REG_ADC_INT_STATUS can't clear
+ * itself after read operation, need software to write
+ * 0 to the related bit. Here we clear the channel A/B/C/D
+ * conversion finished flag.
+ */
+ status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS;
+ writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS);
+ }
+
+ /*
+ * If the channel A/B/C/D conversion timeout, report it and clear these
+ * timeout flags.
+ */
+ if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT) {
+ pr_err("%s: ADC got conversion time out interrupt: 0x%08x\n",
+ dev_name(info->dev), status);
+ status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT;
+ writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int imx7d_adc_reg_access(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct imx7d_adc *info = iio_priv(indio_dev);
+
+ if (!readval || reg % 4 || reg > IMX7D_REG_ADC_ADC_CFG)
+ return -EINVAL;
+
+ *readval = readl(info->regs + reg);
+
+ return 0;
+}
+
+static const struct iio_info imx7d_adc_iio_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &imx7d_adc_read_raw,
+ .debugfs_reg_access = &imx7d_adc_reg_access,
+};
+
+static const struct of_device_id imx7d_adc_match[] = {
+ { .compatible = "fsl,imx7d-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx7d_adc_match);
+
+static void imx7d_adc_power_down(struct imx7d_adc *info)
+{
+ u32 adc_cfg;
+
+ adc_cfg = readl(info->regs + IMX7D_REG_ADC_ADC_CFG);
+ adc_cfg |= IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN |
+ IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN;
+ adc_cfg &= ~IMX7D_REG_ADC_ADC_CFG_ADC_EN;
+ writel(adc_cfg, info->regs + IMX7D_REG_ADC_ADC_CFG);
+}
+
+static int imx7d_adc_probe(struct platform_device *pdev)
+{
+ struct imx7d_adc *info;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "Failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ info = iio_priv(indio_dev);
+ info->dev = &pdev->dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ info->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(info->regs)) {
+ ret = PTR_ERR(info->regs);
+ dev_err(&pdev->dev,
+ "Failed to remap adc memory, err = %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No irq resource?\n");
+ return irq;
+ }
+
+ info->clk = devm_clk_get(&pdev->dev, "adc");
+ if (IS_ERR(info->clk)) {
+ ret = PTR_ERR(info->clk);
+ dev_err(&pdev->dev, "Failed getting clock, err = %d\n", ret);
+ return ret;
+ }
+
+ info->vref = devm_regulator_get(&pdev->dev, "vref");
+ if (IS_ERR(info->vref)) {
+ ret = PTR_ERR(info->vref);
+ dev_err(&pdev->dev,
+ "Failed getting reference voltage, err = %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(info->vref);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Can't enable adc reference top voltage, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&info->completion);
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &imx7d_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = imx7d_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels);
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the clock.\n");
+ goto error_adc_clk_enable;
+ }
+
+ ret = devm_request_irq(info->dev, irq,
+ imx7d_adc_isr, 0,
+ dev_name(&pdev->dev), info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed requesting irq, irq = %d\n", irq);
+ goto error_iio_device_register;
+ }
+
+ imx7d_adc_feature_config(info);
+ imx7d_adc_hw_init(info);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ imx7d_adc_power_down(info);
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto error_iio_device_register;
+ }
+
+ return 0;
+
+error_iio_device_register:
+ clk_disable_unprepare(info->clk);
+error_adc_clk_enable:
+ regulator_disable(info->vref);
+
+ return ret;
+}
+
+static int imx7d_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct imx7d_adc *info = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ imx7d_adc_power_down(info);
+
+ clk_disable_unprepare(info->clk);
+ regulator_disable(info->vref);
+
+ return 0;
+}
+
+static int __maybe_unused imx7d_adc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx7d_adc *info = iio_priv(indio_dev);
+
+ imx7d_adc_power_down(info);
+
+ clk_disable_unprepare(info->clk);
+ regulator_disable(info->vref);
+
+ return 0;
+}
+
+static int __maybe_unused imx7d_adc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx7d_adc *info = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(info->vref);
+ if (ret) {
+ dev_err(info->dev,
+ "Can't enable adc reference top voltage, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret) {
+ dev_err(info->dev,
+ "Could not prepare or enable clock.\n");
+ regulator_disable(info->vref);
+ return ret;
+ }
+
+ imx7d_adc_hw_init(info);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(imx7d_adc_pm_ops, imx7d_adc_suspend, imx7d_adc_resume);
+
+static struct platform_driver imx7d_adc_driver = {
+ .probe = imx7d_adc_probe,
+ .remove = imx7d_adc_remove,
+ .driver = {
+ .name = "imx7d_adc",
+ .of_match_table = imx7d_adc_match,
+ .pm = &imx7d_adc_pm_ops,
+ },
+};
+
+module_platform_driver(imx7d_adc_driver);
+
+MODULE_AUTHOR("Haibo Chen <haibo.chen@freescale.com>");
+MODULE_DESCRIPTION("Freeacale IMX7D ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
new file mode 100644
index 000000000000..d803e5018a42
--- /dev/null
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -0,0 +1,745 @@
+/*
+ * INA2XX Current and Power Monitors
+ *
+ * Copyright 2015 Baylibre SAS.
+ *
+ * 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.
+ *
+ * Based on linux/drivers/iio/adc/ad7291.c
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Based on linux/drivers/hwmon/ina2xx.c
+ * Copyright 2012 Lothar Felten <l-felten@ti.com>
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * IIO driver for INA219-220-226-230-231
+ *
+ * Configurable 7-bit I2C slave address from 0x40 to 0x4F
+ */
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/ina2xx.h>
+
+#include <linux/util_macros.h>
+
+/* INA2XX registers definition */
+#define INA2XX_CONFIG 0x00
+#define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE 0x02 /* readonly */
+#define INA2XX_POWER 0x03 /* readonly */
+#define INA2XX_CURRENT 0x04 /* readonly */
+#define INA2XX_CALIBRATION 0x05
+
+#define INA226_ALERT_MASK 0x06
+#define INA266_CVRF BIT(3)
+
+#define INA2XX_MAX_REGISTERS 8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
+#define INA226_CONFIG_DEFAULT 0x4327
+#define INA226_DEFAULT_AVG 4
+#define INA226_DEFAULT_IT 1110
+
+#define INA2XX_RSHUNT_DEFAULT 10000
+
+/*
+ * bit mask for reading the averaging setting in the configuration register
+ * FIXME: use regmap_fields.
+ */
+#define INA2XX_MODE_MASK GENMASK(3, 0)
+
+#define INA226_AVG_MASK GENMASK(11, 9)
+#define INA226_SHIFT_AVG(val) ((val) << 9)
+
+/* Integration time for VBus */
+#define INA226_ITB_MASK GENMASK(8, 6)
+#define INA226_SHIFT_ITB(val) ((val) << 6)
+
+/* Integration time for VShunt */
+#define INA226_ITS_MASK GENMASK(5, 3)
+#define INA226_SHIFT_ITS(val) ((val) << 3)
+
+/* Cosmetic macro giving the sampling period for a full P=UxI cycle */
+#define SAMPLING_PERIOD(c) ((c->int_time_vbus + c->int_time_vshunt) \
+ * c->avg)
+
+static bool ina2xx_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return (reg == INA2XX_CONFIG) || (reg > INA2XX_CURRENT);
+}
+
+static bool ina2xx_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return (reg != INA2XX_CONFIG);
+}
+
+static inline bool is_signed_reg(unsigned int reg)
+{
+ return (reg == INA2XX_SHUNT_VOLTAGE) || (reg == INA2XX_CURRENT);
+}
+
+static const struct regmap_config ina2xx_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = INA2XX_MAX_REGISTERS,
+ .writeable_reg = ina2xx_is_writeable_reg,
+ .volatile_reg = ina2xx_is_volatile_reg,
+};
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_config {
+ u16 config_default;
+ int calibration_factor;
+ int shunt_div;
+ int bus_voltage_shift;
+ int bus_voltage_lsb; /* uV */
+ int power_lsb; /* uW */
+};
+
+struct ina2xx_chip_info {
+ struct regmap *regmap;
+ struct task_struct *task;
+ const struct ina2xx_config *config;
+ struct mutex state_lock;
+ unsigned int shunt_resistor;
+ int avg;
+ s64 prev_ns; /* track buffer capture time, check for underruns*/
+ int int_time_vbus; /* Bus voltage integration time uS */
+ int int_time_vshunt; /* Shunt voltage integration time uS */
+ bool allow_async_readout;
+};
+
+static const struct ina2xx_config ina2xx_config[] = {
+ [ina219] = {
+ .config_default = INA219_CONFIG_DEFAULT,
+ .calibration_factor = 40960000,
+ .shunt_div = 100,
+ .bus_voltage_shift = 3,
+ .bus_voltage_lsb = 4000,
+ .power_lsb = 20000,
+ },
+ [ina226] = {
+ .config_default = INA226_CONFIG_DEFAULT,
+ .calibration_factor = 5120000,
+ .shunt_div = 400,
+ .bus_voltage_shift = 0,
+ .bus_voltage_lsb = 1250,
+ .power_lsb = 25000,
+ },
+};
+
+static int ina2xx_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+ unsigned int regval;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(chip->regmap, chan->address, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (is_signed_reg(chan->address))
+ *val = (s16) regval;
+ else
+ *val = regval;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = chip->avg;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_INT_TIME:
+ *val = 0;
+ if (chan->address == INA2XX_SHUNT_VOLTAGE)
+ *val2 = chip->int_time_vshunt;
+ else
+ *val2 = chip->int_time_vbus;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ /*
+ * Sample freq is read only, it is a consequence of
+ * 1/AVG*(CT_bus+CT_shunt).
+ */
+ *val = DIV_ROUND_CLOSEST(1000000, SAMPLING_PERIOD(chip));
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->address) {
+ case INA2XX_SHUNT_VOLTAGE:
+ /* processed (mV) = raw*1000/shunt_div */
+ *val2 = chip->config->shunt_div;
+ *val = 1000;
+ return IIO_VAL_FRACTIONAL;
+
+ case INA2XX_BUS_VOLTAGE:
+ /* processed (mV) = raw*lsb (uV) / (1000 << shift) */
+ *val = chip->config->bus_voltage_lsb;
+ *val2 = 1000 << chip->config->bus_voltage_shift;
+ return IIO_VAL_FRACTIONAL;
+
+ case INA2XX_POWER:
+ /* processed (mW) = raw*lsb (uW) / 1000 */
+ *val = chip->config->power_lsb;
+ *val2 = 1000;
+ return IIO_VAL_FRACTIONAL;
+
+ case INA2XX_CURRENT:
+ /* processed (mA) = raw (mA) */
+ *val = 1;
+ return IIO_VAL_INT;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Available averaging rates for ina226. The indices correspond with
+ * the bit values expected by the chip (according to the ina226 datasheet,
+ * table 3 AVG bit settings, found at
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ */
+static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
+
+static int ina226_set_average(struct ina2xx_chip_info *chip, unsigned int val,
+ unsigned int *config)
+{
+ int bits;
+
+ if (val > 1024 || val < 1)
+ return -EINVAL;
+
+ bits = find_closest(val, ina226_avg_tab,
+ ARRAY_SIZE(ina226_avg_tab));
+
+ chip->avg = ina226_avg_tab[bits];
+
+ *config &= ~INA226_AVG_MASK;
+ *config |= INA226_SHIFT_AVG(bits) & INA226_AVG_MASK;
+
+ return 0;
+}
+
+/* Conversion times in uS */
+static const int ina226_conv_time_tab[] = { 140, 204, 332, 588, 1100,
+ 2116, 4156, 8244 };
+
+static int ina226_set_int_time_vbus(struct ina2xx_chip_info *chip,
+ unsigned int val_us, unsigned int *config)
+{
+ int bits;
+
+ if (val_us > 8244 || val_us < 140)
+ return -EINVAL;
+
+ bits = find_closest(val_us, ina226_conv_time_tab,
+ ARRAY_SIZE(ina226_conv_time_tab));
+
+ chip->int_time_vbus = ina226_conv_time_tab[bits];
+
+ *config &= ~INA226_ITB_MASK;
+ *config |= INA226_SHIFT_ITB(bits) & INA226_ITB_MASK;
+
+ return 0;
+}
+
+static int ina226_set_int_time_vshunt(struct ina2xx_chip_info *chip,
+ unsigned int val_us, unsigned int *config)
+{
+ int bits;
+
+ if (val_us > 8244 || val_us < 140)
+ return -EINVAL;
+
+ bits = find_closest(val_us, ina226_conv_time_tab,
+ ARRAY_SIZE(ina226_conv_time_tab));
+
+ chip->int_time_vshunt = ina226_conv_time_tab[bits];
+
+ *config &= ~INA226_ITS_MASK;
+ *config |= INA226_SHIFT_ITS(bits) & INA226_ITS_MASK;
+
+ return 0;
+}
+
+static int ina2xx_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+ int ret;
+ unsigned int config, tmp;
+
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ mutex_lock(&chip->state_lock);
+
+ ret = regmap_read(chip->regmap, INA2XX_CONFIG, &config);
+ if (ret < 0)
+ goto _err;
+
+ tmp = config;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = ina226_set_average(chip, val, &tmp);
+ break;
+
+ case IIO_CHAN_INFO_INT_TIME:
+ if (chan->address == INA2XX_SHUNT_VOLTAGE)
+ ret = ina226_set_int_time_vshunt(chip, val2, &tmp);
+ else
+ ret = ina226_set_int_time_vbus(chip, val2, &tmp);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (!ret && (tmp != config))
+ ret = regmap_write(chip->regmap, INA2XX_CONFIG, tmp);
+_err:
+ mutex_unlock(&chip->state_lock);
+
+ return ret;
+}
+
+
+static ssize_t ina2xx_allow_async_readout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
+
+ return sprintf(buf, "%d\n", chip->allow_async_readout);
+}
+
+static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
+ bool val;
+ int ret;
+
+ ret = strtobool((const char *) buf, &val);
+ if (ret)
+ return ret;
+
+ chip->allow_async_readout = val;
+
+ return len;
+}
+
+static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
+{
+ if (val <= 0 || val > chip->config->calibration_factor)
+ return -EINVAL;
+
+ chip->shunt_resistor = val;
+ return 0;
+}
+
+static ssize_t ina2xx_shunt_resistor_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
+
+ return sprintf(buf, "%d\n", chip->shunt_resistor);
+}
+
+static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul((const char *) buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = set_shunt_resistor(chip, val);
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+#define INA2XX_CHAN(_type, _index, _address) { \
+ .type = (_type), \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
+ | BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .scan_index = (_index), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+/*
+ * Sampling Freq is a consequence of the integration times of
+ * the Voltage channels.
+ */
+#define INA2XX_CHAN_VOLTAGE(_index, _address) { \
+ .type = IIO_VOLTAGE, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_INT_TIME), \
+ .scan_index = (_index), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ } \
+}
+
+static const struct iio_chan_spec ina2xx_channels[] = {
+ INA2XX_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE),
+ INA2XX_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE),
+ INA2XX_CHAN(IIO_POWER, 2, INA2XX_POWER),
+ INA2XX_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static int ina2xx_work_buffer(struct iio_dev *indio_dev)
+{
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+ unsigned short data[8];
+ int bit, ret, i = 0;
+ unsigned long buffer_us, elapsed_us;
+ s64 time_a, time_b;
+ unsigned int alert;
+
+ time_a = iio_get_time_ns();
+
+ /*
+ * Because the timer thread and the chip conversion clock
+ * are asynchronous, the period difference will eventually
+ * result in reading V[k-1] again, or skip V[k] at time Tk.
+ * In order to resync the timer with the conversion process
+ * we check the ConVersionReadyFlag.
+ * On hardware that supports using the ALERT pin to toggle a
+ * GPIO a triggered buffer could be used instead.
+ * For now, we pay for that extra read of the ALERT register
+ */
+ if (!chip->allow_async_readout)
+ do {
+ ret = regmap_read(chip->regmap, INA226_ALERT_MASK,
+ &alert);
+ if (ret < 0)
+ return ret;
+
+ alert &= INA266_CVRF;
+ trace_printk("Conversion ready: %d\n", !!alert);
+
+ } while (!alert);
+
+ /*
+ * Single register reads: bulk_read will not work with ina226
+ * as there is no auto-increment of the address register for
+ * data length longer than 16bits.
+ */
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ unsigned int val;
+
+ ret = regmap_read(chip->regmap,
+ INA2XX_SHUNT_VOLTAGE + bit, &val);
+ if (ret < 0)
+ return ret;
+
+ data[i++] = val;
+ }
+
+ time_b = iio_get_time_ns();
+
+ iio_push_to_buffers_with_timestamp(indio_dev,
+ (unsigned int *)data, time_a);
+
+ buffer_us = (unsigned long)(time_b - time_a) / 1000;
+ elapsed_us = (unsigned long)(time_a - chip->prev_ns) / 1000;
+
+ trace_printk("uS: elapsed: %lu, buf: %lu\n", elapsed_us, buffer_us);
+
+ chip->prev_ns = time_a;
+
+ return buffer_us;
+};
+
+static int ina2xx_capture_thread(void *data)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)data;
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+ unsigned int sampling_us = SAMPLING_PERIOD(chip);
+ int buffer_us;
+
+ /*
+ * Poll a bit faster than the chip internal Fs, in case
+ * we wish to sync with the conversion ready flag.
+ */
+ if (!chip->allow_async_readout)
+ sampling_us -= 200;
+
+ do {
+ buffer_us = ina2xx_work_buffer(indio_dev);
+ if (buffer_us < 0)
+ return buffer_us;
+
+ if (sampling_us > buffer_us)
+ udelay(sampling_us - buffer_us);
+
+ } while (!kthread_should_stop());
+
+ return 0;
+}
+
+static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
+{
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+ unsigned int sampling_us = SAMPLING_PERIOD(chip);
+
+ trace_printk("Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n",
+ (unsigned int)(*indio_dev->active_scan_mask),
+ 1000000/sampling_us, chip->avg);
+
+ trace_printk("Expected work period: %u us\n", sampling_us);
+ trace_printk("Async readout mode: %d\n", chip->allow_async_readout);
+
+ chip->prev_ns = iio_get_time_ns();
+
+ chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
+ "%s:%d-%uus", indio_dev->name, indio_dev->id,
+ sampling_us);
+
+ return PTR_ERR_OR_ZERO(chip->task);
+}
+
+static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
+{
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+
+ if (chip->task) {
+ kthread_stop(chip->task);
+ chip->task = NULL;
+ }
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ina2xx_setup_ops = {
+ .postenable = &ina2xx_buffer_enable,
+ .predisable = &ina2xx_buffer_disable,
+};
+
+static int ina2xx_debug_reg(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval, unsigned *readval)
+{
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+
+ if (!readval)
+ return regmap_write(chip->regmap, reg, writeval);
+
+ return regmap_read(chip->regmap, reg, readval);
+}
+
+/* Possible integration times for vshunt and vbus */
+static IIO_CONST_ATTR_INT_TIME_AVAIL \
+ ("0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244");
+
+static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR,
+ ina2xx_allow_async_readout_show,
+ ina2xx_allow_async_readout_store, 0);
+
+static IIO_DEVICE_ATTR(in_shunt_resistor, S_IRUGO | S_IWUSR,
+ ina2xx_shunt_resistor_show,
+ ina2xx_shunt_resistor_store, 0);
+
+static struct attribute *ina2xx_attributes[] = {
+ &iio_dev_attr_in_allow_async_readout.dev_attr.attr,
+ &iio_const_attr_integration_time_available.dev_attr.attr,
+ &iio_dev_attr_in_shunt_resistor.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ina2xx_attribute_group = {
+ .attrs = ina2xx_attributes,
+};
+
+static const struct iio_info ina2xx_info = {
+ .debugfs_reg_access = &ina2xx_debug_reg,
+ .read_raw = &ina2xx_read_raw,
+ .write_raw = &ina2xx_write_raw,
+ .attrs = &ina2xx_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+/* Initialize the configuration and calibration registers. */
+static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
+{
+ u16 regval;
+ int ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
+
+ if (ret < 0)
+ return ret;
+ /*
+ * Set current LSB to 1mA, shunt is in uOhms
+ * (equation 13 in datasheet). We hardcode a Current_LSB
+ * of 1.0 x10-6. The only remaining parameter is RShunt.
+ * There is no need to expose the CALIBRATION register
+ * to the user for now.
+ */
+ regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
+ chip->shunt_resistor);
+
+ return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
+}
+
+static int ina2xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ina2xx_chip_info *chip;
+ struct iio_dev *indio_dev;
+ struct iio_buffer *buffer;
+ int ret;
+ unsigned int val;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = iio_priv(indio_dev);
+
+ chip->config = &ina2xx_config[id->driver_data];
+
+ if (of_property_read_u32(client->dev.of_node,
+ "shunt-resistor", &val) < 0) {
+ struct ina2xx_platform_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ if (pdata)
+ val = pdata->shunt_uohms;
+ else
+ val = INA2XX_RSHUNT_DEFAULT;
+ }
+
+ ret = set_shunt_resistor(chip, val);
+ if (ret)
+ return ret;
+
+ mutex_init(&chip->state_lock);
+
+ /* This is only used for device removal purposes. */
+ i2c_set_clientdata(client, indio_dev);
+
+ indio_dev->name = id->name;
+ indio_dev->channels = ina2xx_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &ina2xx_info;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+
+ chip->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ dev_err(&client->dev, "failed to allocate register map\n");
+ return PTR_ERR(chip->regmap);
+ }
+
+ /* Patch the current config register with default. */
+ val = chip->config->config_default;
+
+ if (id->driver_data == ina226) {
+ ina226_set_average(chip, INA226_DEFAULT_AVG, &val);
+ ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val);
+ ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val);
+ }
+
+ ret = ina2xx_init(chip, val);
+ if (ret < 0) {
+ dev_err(&client->dev, "error configuring the device: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ buffer = devm_iio_kfifo_allocate(&indio_dev->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ indio_dev->setup_ops = &ina2xx_setup_ops;
+
+ iio_device_attach_buffer(indio_dev, buffer);
+
+ return iio_device_register(indio_dev);
+}
+
+
+static int ina2xx_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct ina2xx_chip_info *chip = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ /* Powerdown */
+ return regmap_update_bits(chip->regmap, INA2XX_CONFIG,
+ INA2XX_MODE_MASK, 0);
+}
+
+
+static const struct i2c_device_id ina2xx_id[] = {
+ {"ina219", ina219},
+ {"ina220", ina219},
+ {"ina226", ina226},
+ {"ina230", ina226},
+ {"ina231", ina226},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ },
+ .probe = ina2xx_probe,
+ .remove = ina2xx_remove,
+ .id_table = ina2xx_id,
+};
+
+module_i2c_driver(ina2xx_driver);
+
+MODULE_AUTHOR("Marc Titinger <marc.titinger@baylibre.com>");
+MODULE_DESCRIPTION("Texas Instruments INA2XX ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index 8569c8e1f4b2..d1c05f6eed18 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -354,6 +354,7 @@ static int mcp320x_remove(struct spi_device *spi)
#if defined(CONFIG_OF)
static const struct of_device_id mcp320x_dt_ids[] = {
+ /* NOTE: The use of compatibles with no vendor prefix is deprecated. */
{
.compatible = "mcp3001",
.data = &mcp320x_chip_infos[mcp3001],
@@ -382,6 +383,33 @@ static const struct of_device_id mcp320x_dt_ids[] = {
.compatible = "mcp3301",
.data = &mcp320x_chip_infos[mcp3301],
}, {
+ .compatible = "microchip,mcp3001",
+ .data = &mcp320x_chip_infos[mcp3001],
+ }, {
+ .compatible = "microchip,mcp3002",
+ .data = &mcp320x_chip_infos[mcp3002],
+ }, {
+ .compatible = "microchip,mcp3004",
+ .data = &mcp320x_chip_infos[mcp3004],
+ }, {
+ .compatible = "microchip,mcp3008",
+ .data = &mcp320x_chip_infos[mcp3008],
+ }, {
+ .compatible = "microchip,mcp3201",
+ .data = &mcp320x_chip_infos[mcp3201],
+ }, {
+ .compatible = "microchip,mcp3202",
+ .data = &mcp320x_chip_infos[mcp3202],
+ }, {
+ .compatible = "microchip,mcp3204",
+ .data = &mcp320x_chip_infos[mcp3204],
+ }, {
+ .compatible = "microchip,mcp3208",
+ .data = &mcp320x_chip_infos[mcp3208],
+ }, {
+ .compatible = "microchip,mcp3301",
+ .data = &mcp320x_chip_infos[mcp3301],
+ }, {
}
};
MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index 3555122008b4..6eca7aea8a37 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -305,6 +305,10 @@ static const struct attribute_group mcp3422_attribute_group = {
.attrs = mcp3422_attributes,
};
+static const struct iio_chan_spec mcp3421_channels[] = {
+ MCP3422_CHAN(0),
+};
+
static const struct iio_chan_spec mcp3422_channels[] = {
MCP3422_CHAN(0),
MCP3422_CHAN(1),
@@ -352,6 +356,10 @@ static int mcp3422_probe(struct i2c_client *client,
indio_dev->info = &mcp3422_info;
switch (adc->id) {
+ case 1:
+ indio_dev->channels = mcp3421_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels);
+ break;
case 2:
case 3:
case 6:
@@ -383,6 +391,7 @@ static int mcp3422_probe(struct i2c_client *client,
}
static const struct i2c_device_id mcp3422_id[] = {
+ { "mcp3421", 1 },
{ "mcp3422", 2 },
{ "mcp3423", 3 },
{ "mcp3424", 4 },
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
new file mode 100644
index 000000000000..f42eb8a7d21f
--- /dev/null
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -0,0 +1,859 @@
+/*
+ * palmas-adc.c -- TI PALMAS GPADC.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * Author: Pradeep Goudagunta <pgoudagunta@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mfd/palmas.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+#define MOD_NAME "palmas-gpadc"
+#define PALMAS_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(5000))
+#define PALMAS_TO_BE_CALCULATED 0
+#define PALMAS_GPADC_TRIMINVALID -1
+
+struct palmas_gpadc_info {
+/* calibration codes and regs */
+ int x1; /* lower ideal code */
+ int x2; /* higher ideal code */
+ int v1; /* expected lower volt reading */
+ int v2; /* expected higher volt reading */
+ u8 trim1_reg; /* register number for lower trim */
+ u8 trim2_reg; /* register number for upper trim */
+ int gain; /* calculated from above (after reading trim regs) */
+ int offset; /* calculated from above (after reading trim regs) */
+ int gain_error; /* calculated from above (after reading trim regs) */
+ bool is_uncalibrated; /* if channel has calibration data */
+};
+
+#define PALMAS_ADC_INFO(_chan, _x1, _x2, _v1, _v2, _t1, _t2, _is_uncalibrated) \
+ [PALMAS_ADC_CH_##_chan] = { \
+ .x1 = _x1, \
+ .x2 = _x2, \
+ .v1 = _v1, \
+ .v2 = _v2, \
+ .gain = PALMAS_TO_BE_CALCULATED, \
+ .offset = PALMAS_TO_BE_CALCULATED, \
+ .gain_error = PALMAS_TO_BE_CALCULATED, \
+ .trim1_reg = PALMAS_GPADC_TRIM##_t1, \
+ .trim2_reg = PALMAS_GPADC_TRIM##_t2, \
+ .is_uncalibrated = _is_uncalibrated \
+ }
+
+static struct palmas_gpadc_info palmas_gpadc_info[] = {
+ PALMAS_ADC_INFO(IN0, 2064, 3112, 630, 950, 1, 2, false),
+ PALMAS_ADC_INFO(IN1, 2064, 3112, 630, 950, 1, 2, false),
+ PALMAS_ADC_INFO(IN2, 2064, 3112, 1260, 1900, 3, 4, false),
+ PALMAS_ADC_INFO(IN3, 2064, 3112, 630, 950, 1, 2, false),
+ PALMAS_ADC_INFO(IN4, 2064, 3112, 630, 950, 1, 2, false),
+ PALMAS_ADC_INFO(IN5, 2064, 3112, 630, 950, 1, 2, false),
+ PALMAS_ADC_INFO(IN6, 2064, 3112, 2520, 3800, 5, 6, false),
+ PALMAS_ADC_INFO(IN7, 2064, 3112, 2520, 3800, 7, 8, false),
+ PALMAS_ADC_INFO(IN8, 2064, 3112, 3150, 4750, 9, 10, false),
+ PALMAS_ADC_INFO(IN9, 2064, 3112, 5670, 8550, 11, 12, false),
+ PALMAS_ADC_INFO(IN10, 2064, 3112, 3465, 5225, 13, 14, false),
+ PALMAS_ADC_INFO(IN11, 0, 0, 0, 0, INVALID, INVALID, true),
+ PALMAS_ADC_INFO(IN12, 0, 0, 0, 0, INVALID, INVALID, true),
+ PALMAS_ADC_INFO(IN13, 0, 0, 0, 0, INVALID, INVALID, true),
+ PALMAS_ADC_INFO(IN14, 2064, 3112, 3645, 5225, 15, 16, false),
+ PALMAS_ADC_INFO(IN15, 0, 0, 0, 0, INVALID, INVALID, true),
+};
+
+/**
+ * struct palmas_gpadc - the palmas_gpadc structure
+ * @ch0_current: channel 0 current source setting
+ * 0: 0 uA
+ * 1: 5 uA
+ * 2: 15 uA
+ * 3: 20 uA
+ * @ch3_current: channel 0 current source setting
+ * 0: 0 uA
+ * 1: 10 uA
+ * 2: 400 uA
+ * 3: 800 uA
+ * @extended_delay: enable the gpadc extended delay mode
+ * @auto_conversion_period: define the auto_conversion_period
+ *
+ * This is the palmas_gpadc structure to store run-time information
+ * and pointers for this driver instance.
+ */
+
+struct palmas_gpadc {
+ struct device *dev;
+ struct palmas *palmas;
+ u8 ch0_current;
+ u8 ch3_current;
+ bool extended_delay;
+ int irq;
+ int irq_auto_0;
+ int irq_auto_1;
+ struct palmas_gpadc_info *adc_info;
+ struct completion conv_completion;
+ struct palmas_adc_wakeup_property wakeup1_data;
+ struct palmas_adc_wakeup_property wakeup2_data;
+ bool wakeup1_enable;
+ bool wakeup2_enable;
+ int auto_conversion_period;
+};
+
+/*
+ * GPADC lock issue in AUTO mode.
+ * Impact: In AUTO mode, GPADC conversion can be locked after disabling AUTO
+ * mode feature.
+ * Details:
+ * When the AUTO mode is the only conversion mode enabled, if the AUTO
+ * mode feature is disabled with bit GPADC_AUTO_CTRL. AUTO_CONV1_EN = 0
+ * or bit GPADC_AUTO_CTRL. AUTO_CONV0_EN = 0 during a conversion, the
+ * conversion mechanism can be seen as locked meaning that all following
+ * conversion will give 0 as a result. Bit GPADC_STATUS.GPADC_AVAILABLE
+ * will stay at 0 meaning that GPADC is busy. An RT conversion can unlock
+ * the GPADC.
+ *
+ * Workaround(s):
+ * To avoid the lock mechanism, the workaround to follow before any stop
+ * conversion request is:
+ * Force the GPADC state machine to be ON by using the GPADC_CTRL1.
+ * GPADC_FORCE bit = 1
+ * Shutdown the GPADC AUTO conversion using
+ * GPADC_AUTO_CTRL.SHUTDOWN_CONV[01] = 0.
+ * After 100us, force the GPADC state machine to be OFF by using the
+ * GPADC_CTRL1. GPADC_FORCE bit = 0
+ */
+
+static int palmas_disable_auto_conversion(struct palmas_gpadc *adc)
+{
+ int ret;
+
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_CTRL1,
+ PALMAS_GPADC_CTRL1_GPADC_FORCE,
+ PALMAS_GPADC_CTRL1_GPADC_FORCE);
+ if (ret < 0) {
+ dev_err(adc->dev, "GPADC_CTRL1 update failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_CTRL,
+ PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 |
+ PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0,
+ 0);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_CTRL update failed: %d\n", ret);
+ return ret;
+ }
+
+ udelay(100);
+
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_CTRL1,
+ PALMAS_GPADC_CTRL1_GPADC_FORCE, 0);
+ if (ret < 0)
+ dev_err(adc->dev, "GPADC_CTRL1 update failed: %d\n", ret);
+
+ return ret;
+}
+
+static irqreturn_t palmas_gpadc_irq(int irq, void *data)
+{
+ struct palmas_gpadc *adc = data;
+
+ complete(&adc->conv_completion);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data)
+{
+ struct palmas_gpadc *adc = data;
+
+ dev_dbg(adc->dev, "Threshold interrupt %d occurs\n", irq);
+ palmas_disable_auto_conversion(adc);
+
+ return IRQ_HANDLED;
+}
+
+static int palmas_gpadc_start_mask_interrupt(struct palmas_gpadc *adc,
+ bool mask)
+{
+ int ret;
+
+ if (!mask)
+ ret = palmas_update_bits(adc->palmas, PALMAS_INTERRUPT_BASE,
+ PALMAS_INT3_MASK,
+ PALMAS_INT3_MASK_GPADC_EOC_SW, 0);
+ else
+ ret = palmas_update_bits(adc->palmas, PALMAS_INTERRUPT_BASE,
+ PALMAS_INT3_MASK,
+ PALMAS_INT3_MASK_GPADC_EOC_SW,
+ PALMAS_INT3_MASK_GPADC_EOC_SW);
+ if (ret < 0)
+ dev_err(adc->dev, "GPADC INT MASK update failed: %d\n", ret);
+
+ return ret;
+}
+
+static int palmas_gpadc_enable(struct palmas_gpadc *adc, int adc_chan,
+ int enable)
+{
+ unsigned int mask, val;
+ int ret;
+
+ if (enable) {
+ val = (adc->extended_delay
+ << PALMAS_GPADC_RT_CTRL_EXTEND_DELAY_SHIFT);
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_RT_CTRL,
+ PALMAS_GPADC_RT_CTRL_EXTEND_DELAY, val);
+ if (ret < 0) {
+ dev_err(adc->dev, "RT_CTRL update failed: %d\n", ret);
+ return ret;
+ }
+
+ mask = (PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK |
+ PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK |
+ PALMAS_GPADC_CTRL1_GPADC_FORCE);
+ val = (adc->ch0_current
+ << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT);
+ val |= (adc->ch3_current
+ << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT);
+ val |= PALMAS_GPADC_CTRL1_GPADC_FORCE;
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_CTRL1, mask, val);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "Failed to update current setting: %d\n", ret);
+ return ret;
+ }
+
+ mask = (PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_MASK |
+ PALMAS_GPADC_SW_SELECT_SW_CONV_EN);
+ val = (adc_chan | PALMAS_GPADC_SW_SELECT_SW_CONV_EN);
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_SW_SELECT, mask, val);
+ if (ret < 0) {
+ dev_err(adc->dev, "SW_SELECT update failed: %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_SW_SELECT, 0);
+ if (ret < 0)
+ dev_err(adc->dev, "SW_SELECT write failed: %d\n", ret);
+
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_CTRL1,
+ PALMAS_GPADC_CTRL1_GPADC_FORCE, 0);
+ if (ret < 0) {
+ dev_err(adc->dev, "CTRL1 update failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int palmas_gpadc_read_prepare(struct palmas_gpadc *adc, int adc_chan)
+{
+ int ret;
+
+ ret = palmas_gpadc_enable(adc, adc_chan, true);
+ if (ret < 0)
+ return ret;
+
+ return palmas_gpadc_start_mask_interrupt(adc, 0);
+}
+
+static void palmas_gpadc_read_done(struct palmas_gpadc *adc, int adc_chan)
+{
+ palmas_gpadc_start_mask_interrupt(adc, 1);
+ palmas_gpadc_enable(adc, adc_chan, false);
+}
+
+static int palmas_gpadc_calibrate(struct palmas_gpadc *adc, int adc_chan)
+{
+ int k;
+ int d1;
+ int d2;
+ int ret;
+ int gain;
+ int x1 = adc->adc_info[adc_chan].x1;
+ int x2 = adc->adc_info[adc_chan].x2;
+ int v1 = adc->adc_info[adc_chan].v1;
+ int v2 = adc->adc_info[adc_chan].v2;
+
+ ret = palmas_read(adc->palmas, PALMAS_TRIM_GPADC_BASE,
+ adc->adc_info[adc_chan].trim1_reg, &d1);
+ if (ret < 0) {
+ dev_err(adc->dev, "TRIM read failed: %d\n", ret);
+ goto scrub;
+ }
+
+ ret = palmas_read(adc->palmas, PALMAS_TRIM_GPADC_BASE,
+ adc->adc_info[adc_chan].trim2_reg, &d2);
+ if (ret < 0) {
+ dev_err(adc->dev, "TRIM read failed: %d\n", ret);
+ goto scrub;
+ }
+
+ /* gain error calculation */
+ k = (1000 + (1000 * (d2 - d1)) / (x2 - x1));
+
+ /* gain calculation */
+ gain = ((v2 - v1) * 1000) / (x2 - x1);
+
+ adc->adc_info[adc_chan].gain_error = k;
+ adc->adc_info[adc_chan].gain = gain;
+ /* offset Calculation */
+ adc->adc_info[adc_chan].offset = (d1 * 1000) - ((k - 1000) * x1);
+
+scrub:
+ return ret;
+}
+
+static int palmas_gpadc_start_conversion(struct palmas_gpadc *adc, int adc_chan)
+{
+ unsigned int val;
+ int ret;
+
+ init_completion(&adc->conv_completion);
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_SW_SELECT,
+ PALMAS_GPADC_SW_SELECT_SW_START_CONV0,
+ PALMAS_GPADC_SW_SELECT_SW_START_CONV0);
+ if (ret < 0) {
+ dev_err(adc->dev, "SELECT_SW_START write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&adc->conv_completion,
+ PALMAS_ADC_CONVERSION_TIMEOUT);
+ if (ret == 0) {
+ dev_err(adc->dev, "conversion not completed\n");
+ return -ETIMEDOUT;
+ }
+
+ ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_SW_CONV0_LSB, &val, 2);
+ if (ret < 0) {
+ dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = val & 0xFFF;
+
+ return ret;
+}
+
+static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc,
+ int adc_chan, int val)
+{
+ if (!adc->adc_info[adc_chan].is_uncalibrated)
+ val = (val*1000 - adc->adc_info[adc_chan].offset) /
+ adc->adc_info[adc_chan].gain_error;
+
+ if (val < 0) {
+ dev_err(adc->dev, "Mismatch with calibration\n");
+ return 0;
+ }
+
+ val = (val * adc->adc_info[adc_chan].gain) / 1000;
+
+ return val;
+}
+
+static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+ struct palmas_gpadc *adc = iio_priv(indio_dev);
+ int adc_chan = chan->channel;
+ int ret = 0;
+
+ if (adc_chan > PALMAS_ADC_CH_MAX)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = palmas_gpadc_read_prepare(adc, adc_chan);
+ if (ret < 0)
+ goto out;
+
+ ret = palmas_gpadc_start_conversion(adc, adc_chan);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "ADC start conversion failed\n");
+ goto out;
+ }
+
+ if (mask == IIO_CHAN_INFO_PROCESSED)
+ ret = palmas_gpadc_get_calibrated_code(
+ adc, adc_chan, ret);
+
+ *val = ret;
+
+ ret = IIO_VAL_INT;
+ goto out;
+ }
+
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+
+out:
+ palmas_gpadc_read_done(adc, adc_chan);
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static const struct iio_info palmas_gpadc_iio_info = {
+ .read_raw = palmas_gpadc_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define PALMAS_ADC_CHAN_IIO(chan, _type, chan_info) \
+{ \
+ .datasheet_name = PALMAS_DATASHEET_NAME(chan), \
+ .type = _type, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(chan_info), \
+ .indexed = 1, \
+ .channel = PALMAS_ADC_CH_##chan, \
+}
+
+static const struct iio_chan_spec palmas_gpadc_iio_channel[] = {
+ PALMAS_ADC_CHAN_IIO(IN0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN1, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ PALMAS_ADC_CHAN_IIO(IN2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN3, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ PALMAS_ADC_CHAN_IIO(IN4, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN12, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ PALMAS_ADC_CHAN_IIO(IN13, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ PALMAS_ADC_CHAN_IIO(IN14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ PALMAS_ADC_CHAN_IIO(IN15, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+};
+
+static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev,
+ struct palmas_gpadc_platform_data **gpadc_pdata)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct palmas_gpadc_platform_data *gp_data;
+ int ret;
+ u32 pval;
+
+ gp_data = devm_kzalloc(&pdev->dev, sizeof(*gp_data), GFP_KERNEL);
+ if (!gp_data)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "ti,channel0-current-microamp", &pval);
+ if (!ret)
+ gp_data->ch0_current = pval;
+
+ ret = of_property_read_u32(np, "ti,channel3-current-microamp", &pval);
+ if (!ret)
+ gp_data->ch3_current = pval;
+
+ gp_data->extended_delay = of_property_read_bool(np,
+ "ti,enable-extended-delay");
+
+ *gpadc_pdata = gp_data;
+
+ return 0;
+}
+
+static int palmas_gpadc_probe(struct platform_device *pdev)
+{
+ struct palmas_gpadc *adc;
+ struct palmas_platform_data *pdata;
+ struct palmas_gpadc_platform_data *gpadc_pdata = NULL;
+ struct iio_dev *indio_dev;
+ int ret, i;
+
+ pdata = dev_get_platdata(pdev->dev.parent);
+
+ if (pdata && pdata->gpadc_pdata)
+ gpadc_pdata = pdata->gpadc_pdata;
+
+ if (!gpadc_pdata && pdev->dev.of_node) {
+ ret = palmas_gpadc_get_adc_dt_data(pdev, &gpadc_pdata);
+ if (ret < 0)
+ return ret;
+ }
+ if (!gpadc_pdata)
+ return -EINVAL;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "iio_device_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ adc = iio_priv(indio_dev);
+ adc->dev = &pdev->dev;
+ adc->palmas = dev_get_drvdata(pdev->dev.parent);
+ adc->adc_info = palmas_gpadc_info;
+ init_completion(&adc->conv_completion);
+ dev_set_drvdata(&pdev->dev, indio_dev);
+
+ adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms;
+ adc->irq = palmas_irq_get_virq(adc->palmas, PALMAS_GPADC_EOC_SW_IRQ);
+ if (adc->irq < 0) {
+ dev_err(adc->dev,
+ "get virq failed: %d\n", adc->irq);
+ ret = adc->irq;
+ goto out;
+ }
+ ret = request_threaded_irq(adc->irq, NULL,
+ palmas_gpadc_irq,
+ IRQF_ONESHOT | IRQF_EARLY_RESUME, dev_name(adc->dev),
+ adc);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "request irq %d failed: %d\n", adc->irq, ret);
+ goto out;
+ }
+
+ if (gpadc_pdata->adc_wakeup1_data) {
+ memcpy(&adc->wakeup1_data, gpadc_pdata->adc_wakeup1_data,
+ sizeof(adc->wakeup1_data));
+ adc->wakeup1_enable = true;
+ adc->irq_auto_0 = platform_get_irq(pdev, 1);
+ ret = request_threaded_irq(adc->irq_auto_0, NULL,
+ palmas_gpadc_irq_auto,
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "palmas-adc-auto-0", adc);
+ if (ret < 0) {
+ dev_err(adc->dev, "request auto0 irq %d failed: %d\n",
+ adc->irq_auto_0, ret);
+ goto out_irq_free;
+ }
+ }
+
+ if (gpadc_pdata->adc_wakeup2_data) {
+ memcpy(&adc->wakeup2_data, gpadc_pdata->adc_wakeup2_data,
+ sizeof(adc->wakeup2_data));
+ adc->wakeup2_enable = true;
+ adc->irq_auto_1 = platform_get_irq(pdev, 2);
+ ret = request_threaded_irq(adc->irq_auto_1, NULL,
+ palmas_gpadc_irq_auto,
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "palmas-adc-auto-1", adc);
+ if (ret < 0) {
+ dev_err(adc->dev, "request auto1 irq %d failed: %d\n",
+ adc->irq_auto_1, ret);
+ goto out_irq_auto0_free;
+ }
+ }
+
+ /* set the current source 0 (value 0/5/15/20 uA => 0..3) */
+ if (gpadc_pdata->ch0_current <= 1)
+ adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_0;
+ else if (gpadc_pdata->ch0_current <= 5)
+ adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_5;
+ else if (gpadc_pdata->ch0_current <= 15)
+ adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_15;
+ else
+ adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_20;
+
+ /* set the current source 3 (value 0/10/400/800 uA => 0..3) */
+ if (gpadc_pdata->ch3_current <= 1)
+ adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_0;
+ else if (gpadc_pdata->ch3_current <= 10)
+ adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_10;
+ else if (gpadc_pdata->ch3_current <= 400)
+ adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_400;
+ else
+ adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_800;
+
+ adc->extended_delay = gpadc_pdata->extended_delay;
+
+ indio_dev->name = MOD_NAME;
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &palmas_gpadc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = palmas_gpadc_iio_channel;
+ indio_dev->num_channels = ARRAY_SIZE(palmas_gpadc_iio_channel);
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(adc->dev, "iio_device_register() failed: %d\n", ret);
+ goto out_irq_auto1_free;
+ }
+
+ device_set_wakeup_capable(&pdev->dev, 1);
+ for (i = 0; i < PALMAS_ADC_CH_MAX; i++) {
+ if (!(adc->adc_info[i].is_uncalibrated))
+ palmas_gpadc_calibrate(adc, i);
+ }
+
+ if (adc->wakeup1_enable || adc->wakeup2_enable)
+ device_wakeup_enable(&pdev->dev);
+
+ return 0;
+
+out_irq_auto1_free:
+ if (gpadc_pdata->adc_wakeup2_data)
+ free_irq(adc->irq_auto_1, adc);
+out_irq_auto0_free:
+ if (gpadc_pdata->adc_wakeup1_data)
+ free_irq(adc->irq_auto_0, adc);
+out_irq_free:
+ free_irq(adc->irq, adc);
+out:
+ return ret;
+}
+
+static int palmas_gpadc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(&pdev->dev);
+ struct palmas_gpadc *adc = iio_priv(indio_dev);
+
+ if (adc->wakeup1_enable || adc->wakeup2_enable)
+ device_wakeup_disable(&pdev->dev);
+ iio_device_unregister(indio_dev);
+ free_irq(adc->irq, adc);
+ if (adc->wakeup1_enable)
+ free_irq(adc->irq_auto_0, adc);
+ if (adc->wakeup2_enable)
+ free_irq(adc->irq_auto_1, adc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc)
+{
+ int adc_period, conv;
+ int i;
+ int ch0 = 0, ch1 = 0;
+ int thres;
+ int ret;
+
+ adc_period = adc->auto_conversion_period;
+ for (i = 0; i < 16; ++i) {
+ if (((1000 * (1 << i)) / 32) < adc_period)
+ continue;
+ }
+ if (i > 0)
+ i--;
+ adc_period = i;
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_CTRL,
+ PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK,
+ adc_period);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
+ return ret;
+ }
+
+ conv = 0;
+ if (adc->wakeup1_enable) {
+ int polarity;
+
+ ch0 = adc->wakeup1_data.adc_channel_number;
+ conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN;
+ if (adc->wakeup1_data.adc_high_threshold > 0) {
+ thres = adc->wakeup1_data.adc_high_threshold;
+ polarity = 0;
+ } else {
+ thres = adc->wakeup1_data.adc_low_threshold;
+ polarity = PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL;
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV0_LSB, thres & 0xFF);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV0_LSB write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV0_MSB,
+ ((thres >> 8) & 0xF) | polarity);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV0_MSB write failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (adc->wakeup2_enable) {
+ int polarity;
+
+ ch1 = adc->wakeup2_data.adc_channel_number;
+ conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN;
+ if (adc->wakeup2_data.adc_high_threshold > 0) {
+ thres = adc->wakeup2_data.adc_high_threshold;
+ polarity = 0;
+ } else {
+ thres = adc->wakeup2_data.adc_low_threshold;
+ polarity = PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL;
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV1_LSB, thres & 0xFF);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV1_LSB write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV1_MSB,
+ ((thres >> 8) & 0xF) | polarity);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV1_MSB write failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_SELECT, (ch1 << 4) | ch0);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_CTRL,
+ PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN |
+ PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN, conv);
+ if (ret < 0)
+ dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
+
+ return ret;
+}
+
+static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc)
+{
+ int ret;
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_SELECT, 0);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_disable_auto_conversion(adc);
+ if (ret < 0)
+ dev_err(adc->dev, "Disable auto conversion failed: %d\n", ret);
+
+ return ret;
+}
+
+static int palmas_gpadc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct palmas_gpadc *adc = iio_priv(indio_dev);
+ int wakeup = adc->wakeup1_enable || adc->wakeup2_enable;
+ int ret;
+
+ if (!device_may_wakeup(dev) || !wakeup)
+ return 0;
+
+ ret = palmas_adc_wakeup_configure(adc);
+ if (ret < 0)
+ return ret;
+
+ if (adc->wakeup1_enable)
+ enable_irq_wake(adc->irq_auto_0);
+
+ if (adc->wakeup2_enable)
+ enable_irq_wake(adc->irq_auto_1);
+
+ return 0;
+}
+
+static int palmas_gpadc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct palmas_gpadc *adc = iio_priv(indio_dev);
+ int wakeup = adc->wakeup1_enable || adc->wakeup2_enable;
+ int ret;
+
+ if (!device_may_wakeup(dev) || !wakeup)
+ return 0;
+
+ ret = palmas_adc_wakeup_reset(adc);
+ if (ret < 0)
+ return ret;
+
+ if (adc->wakeup1_enable)
+ disable_irq_wake(adc->irq_auto_0);
+
+ if (adc->wakeup2_enable)
+ disable_irq_wake(adc->irq_auto_1);
+
+ return 0;
+};
+#endif
+
+static const struct dev_pm_ops palmas_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(palmas_gpadc_suspend,
+ palmas_gpadc_resume)
+};
+
+static const struct of_device_id of_palmas_gpadc_match_tbl[] = {
+ { .compatible = "ti,palmas-gpadc", },
+ { /* end */ }
+};
+MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl);
+
+static struct platform_driver palmas_gpadc_driver = {
+ .probe = palmas_gpadc_probe,
+ .remove = palmas_gpadc_remove,
+ .driver = {
+ .name = MOD_NAME,
+ .pm = &palmas_pm_ops,
+ .of_match_table = of_palmas_gpadc_match_tbl,
+ },
+};
+
+static int __init palmas_gpadc_init(void)
+{
+ return platform_driver_register(&palmas_gpadc_driver);
+}
+module_init(palmas_gpadc_init);
+
+static void __exit palmas_gpadc_exit(void)
+{
+ platform_driver_unregister(&palmas_gpadc_driver);
+}
+module_exit(palmas_gpadc_exit);
+
+MODULE_DESCRIPTION("palmas GPADC driver");
+MODULE_AUTHOR("Pradeep Goudagunta<pgoudagunta@nvidia.com>");
+MODULE_ALIAS("platform:palmas-gpadc");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index ff6f7f63c8d9..bc58867d6e8d 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -1,10 +1,11 @@
/*
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
- * Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip.
+ * Driver for Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip.
* Datasheets can be found here:
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
* http://www.ti.com/lit/ds/symlink/adc122s021.pdf
+ * http://www.ti.com/lit/ds/symlink/adc124s021.pdf
*
* 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
@@ -114,9 +115,17 @@ static const struct iio_chan_spec adc122s021_channels[] = {
ADC128_VOLTAGE_CHANNEL(1),
};
+static const struct iio_chan_spec adc124s021_channels[] = {
+ ADC128_VOLTAGE_CHANNEL(0),
+ ADC128_VOLTAGE_CHANNEL(1),
+ ADC128_VOLTAGE_CHANNEL(2),
+ ADC128_VOLTAGE_CHANNEL(3),
+};
+
static const struct adc128_configuration adc128_config[] = {
{ adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
{ adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
+ { adc124s021_channels, ARRAY_SIZE(adc124s021_channels) },
};
static const struct iio_info adc128_info = {
@@ -177,6 +186,7 @@ static int adc128_remove(struct spi_device *spi)
static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc128s052", },
{ .compatible = "ti,adc122s021", },
+ { .compatible = "ti,adc124s021", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
@@ -184,6 +194,7 @@ MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0}, /* index into adc128_config */
{ "adc122s021", 1},
+ { "adc124s021", 2},
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
new file mode 100644
index 000000000000..03e907028cb6
--- /dev/null
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2015 Prevas A/S
+ *
+ * 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>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define ADS8688_CMD_REG(x) (x << 8)
+#define ADS8688_CMD_REG_NOOP 0x00
+#define ADS8688_CMD_REG_RST 0x85
+#define ADS8688_CMD_REG_MAN_CH(chan) (0xC0 | (4 * chan))
+#define ADS8688_CMD_DONT_CARE_BITS 16
+
+#define ADS8688_PROG_REG(x) (x << 9)
+#define ADS8688_PROG_REG_RANGE_CH(chan) (0x05 + chan)
+#define ADS8688_PROG_WR_BIT BIT(8)
+#define ADS8688_PROG_DONT_CARE_BITS 8
+
+#define ADS8688_REG_PLUSMINUS25VREF 0
+#define ADS8688_REG_PLUSMINUS125VREF 1
+#define ADS8688_REG_PLUSMINUS0625VREF 2
+#define ADS8688_REG_PLUS25VREF 5
+#define ADS8688_REG_PLUS125VREF 6
+
+#define ADS8688_VREF_MV 4096
+#define ADS8688_REALBITS 16
+
+/*
+ * enum ads8688_range - ADS8688 reference voltage range
+ * @ADS8688_PLUSMINUS25VREF: Device is configured for input range ±2.5 * VREF
+ * @ADS8688_PLUSMINUS125VREF: Device is configured for input range ±1.25 * VREF
+ * @ADS8688_PLUSMINUS0625VREF: Device is configured for input range ±0.625 * VREF
+ * @ADS8688_PLUS25VREF: Device is configured for input range 0 - 2.5 * VREF
+ * @ADS8688_PLUS125VREF: Device is configured for input range 0 - 1.25 * VREF
+ */
+enum ads8688_range {
+ ADS8688_PLUSMINUS25VREF,
+ ADS8688_PLUSMINUS125VREF,
+ ADS8688_PLUSMINUS0625VREF,
+ ADS8688_PLUS25VREF,
+ ADS8688_PLUS125VREF,
+};
+
+struct ads8688_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+struct ads8688_state {
+ struct mutex lock;
+ const struct ads8688_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned int vref_mv;
+ enum ads8688_range range[8];
+ union {
+ __be32 d32;
+ u8 d8[4];
+ } data[2] ____cacheline_aligned;
+};
+
+enum ads8688_id {
+ ID_ADS8684,
+ ID_ADS8688,
+};
+
+struct ads8688_ranges {
+ enum ads8688_range range;
+ unsigned int scale;
+ int offset;
+ u8 reg;
+};
+
+static const struct ads8688_ranges ads8688_range_def[5] = {
+ {
+ .range = ADS8688_PLUSMINUS25VREF,
+ .scale = 76295,
+ .offset = -(1 << (ADS8688_REALBITS - 1)),
+ .reg = ADS8688_REG_PLUSMINUS25VREF,
+ }, {
+ .range = ADS8688_PLUSMINUS125VREF,
+ .scale = 38148,
+ .offset = -(1 << (ADS8688_REALBITS - 1)),
+ .reg = ADS8688_REG_PLUSMINUS125VREF,
+ }, {
+ .range = ADS8688_PLUSMINUS0625VREF,
+ .scale = 19074,
+ .offset = -(1 << (ADS8688_REALBITS - 1)),
+ .reg = ADS8688_REG_PLUSMINUS0625VREF,
+ }, {
+ .range = ADS8688_PLUS25VREF,
+ .scale = 38148,
+ .offset = 0,
+ .reg = ADS8688_REG_PLUS25VREF,
+ }, {
+ .range = ADS8688_PLUS125VREF,
+ .scale = 19074,
+ .offset = 0,
+ .reg = ADS8688_REG_PLUS125VREF,
+ }
+};
+
+static ssize_t ads8688_show_scales(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ads8688_state *st = iio_priv(dev_to_iio_dev(dev));
+
+ return sprintf(buf, "0.%09u 0.%09u 0.%09u\n",
+ ads8688_range_def[0].scale * st->vref_mv,
+ ads8688_range_def[1].scale * st->vref_mv,
+ ads8688_range_def[2].scale * st->vref_mv);
+}
+
+static ssize_t ads8688_show_offsets(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d %d\n", ads8688_range_def[0].offset,
+ ads8688_range_def[3].offset);
+}
+
+static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
+ ads8688_show_scales, NULL, 0);
+static IIO_DEVICE_ATTR(in_voltage_offset_available, S_IRUGO,
+ ads8688_show_offsets, NULL, 0);
+
+static struct attribute *ads8688_attributes[] = {
+ &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
+ &iio_dev_attr_in_voltage_offset_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ads8688_attribute_group = {
+ .attrs = ads8688_attributes,
+};
+
+#define ADS8688_CHAN(index) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
+ | BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
+}
+
+static const struct iio_chan_spec ads8684_channels[] = {
+ ADS8688_CHAN(0),
+ ADS8688_CHAN(1),
+ ADS8688_CHAN(2),
+ ADS8688_CHAN(3),
+};
+
+static const struct iio_chan_spec ads8688_channels[] = {
+ ADS8688_CHAN(0),
+ ADS8688_CHAN(1),
+ ADS8688_CHAN(2),
+ ADS8688_CHAN(3),
+ ADS8688_CHAN(4),
+ ADS8688_CHAN(5),
+ ADS8688_CHAN(6),
+ ADS8688_CHAN(7),
+};
+
+static int ads8688_prog_write(struct iio_dev *indio_dev, unsigned int addr,
+ unsigned int val)
+{
+ struct ads8688_state *st = iio_priv(indio_dev);
+ u32 tmp;
+
+ tmp = ADS8688_PROG_REG(addr) | ADS8688_PROG_WR_BIT | val;
+ tmp <<= ADS8688_PROG_DONT_CARE_BITS;
+ st->data[0].d32 = cpu_to_be32(tmp);
+
+ return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ads8688_reset(struct iio_dev *indio_dev)
+{
+ struct ads8688_state *st = iio_priv(indio_dev);
+ u32 tmp;
+
+ tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_RST);
+ tmp <<= ADS8688_CMD_DONT_CARE_BITS;
+ st->data[0].d32 = cpu_to_be32(tmp);
+
+ return spi_write(st->spi, &st->data[0].d8[0], 4);
+}
+
+static int ads8688_read(struct iio_dev *indio_dev, unsigned int chan)
+{
+ struct ads8688_state *st = iio_priv(indio_dev);
+ int ret;
+ u32 tmp;
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->data[0].d8[0],
+ .len = 4,
+ .cs_change = 1,
+ }, {
+ .tx_buf = &st->data[1].d8[0],
+ .rx_buf = &st->data[1].d8[0],
+ .len = 4,
+ },
+ };
+
+ tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_MAN_CH(chan));
+ tmp <<= ADS8688_CMD_DONT_CARE_BITS;
+ st->data[0].d32 = cpu_to_be32(tmp);
+
+ tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_NOOP);
+ tmp <<= ADS8688_CMD_DONT_CARE_BITS;
+ st->data[1].d32 = cpu_to_be32(tmp);
+
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
+ if (ret < 0)
+ return ret;
+
+ return be32_to_cpu(st->data[1].d32) & 0xffff;
+}
+
+static int ads8688_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long m)
+{
+ int ret, offset;
+ unsigned long scale_mv;
+
+ struct ads8688_state *st = iio_priv(indio_dev);
+
+ mutex_lock(&st->lock);
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ads8688_read(indio_dev, chan->channel);
+ mutex_unlock(&st->lock);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ scale_mv = st->vref_mv;
+ scale_mv *= ads8688_range_def[st->range[chan->channel]].scale;
+ *val = 0;
+ *val2 = scale_mv;
+ mutex_unlock(&st->lock);
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ offset = ads8688_range_def[st->range[chan->channel]].offset;
+ *val = offset;
+ mutex_unlock(&st->lock);
+ return IIO_VAL_INT;
+ }
+ mutex_unlock(&st->lock);
+
+ return -EINVAL;
+}
+
+static int ads8688_write_reg_range(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ enum ads8688_range range)
+{
+ unsigned int tmp;
+ int ret;
+
+ tmp = ADS8688_PROG_REG_RANGE_CH(chan->channel);
+ ret = ads8688_prog_write(indio_dev, tmp, range);
+
+ return ret;
+}
+
+static int ads8688_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ads8688_state *st = iio_priv(indio_dev);
+ unsigned int scale = 0;
+ int ret = -EINVAL, i, offset = 0;
+
+ mutex_lock(&st->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ /* If the offset is 0 the ±2.5 * VREF mode is not available */
+ offset = ads8688_range_def[st->range[chan->channel]].offset;
+ if (offset == 0 && val2 == ads8688_range_def[0].scale * st->vref_mv) {
+ mutex_unlock(&st->lock);
+ return -EINVAL;
+ }
+
+ /* Lookup new mode */
+ for (i = 0; i < ARRAY_SIZE(ads8688_range_def); i++)
+ if (val2 == ads8688_range_def[i].scale * st->vref_mv &&
+ offset == ads8688_range_def[i].offset) {
+ ret = ads8688_write_reg_range(indio_dev, chan,
+ ads8688_range_def[i].reg);
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ /*
+ * There are only two available offsets:
+ * 0 and -(1 << (ADS8688_REALBITS - 1))
+ */
+ if (!(ads8688_range_def[0].offset == val ||
+ ads8688_range_def[3].offset == val)) {
+ mutex_unlock(&st->lock);
+ return -EINVAL;
+ }
+
+ /*
+ * If the device are in ±2.5 * VREF mode, it's not allowed to
+ * switch to a mode where the offset is 0
+ */
+ if (val == 0 &&
+ st->range[chan->channel] == ADS8688_PLUSMINUS25VREF) {
+ mutex_unlock(&st->lock);
+ return -EINVAL;
+ }
+
+ scale = ads8688_range_def[st->range[chan->channel]].scale;
+
+ /* Lookup new mode */
+ for (i = 0; i < ARRAY_SIZE(ads8688_range_def); i++)
+ if (val == ads8688_range_def[i].offset &&
+ scale == ads8688_range_def[i].scale) {
+ ret = ads8688_write_reg_range(indio_dev, chan,
+ ads8688_range_def[i].reg);
+ break;
+ }
+ break;
+ }
+
+ if (!ret)
+ st->range[chan->channel] = ads8688_range_def[i].range;
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ads8688_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info ads8688_info = {
+ .read_raw = &ads8688_read_raw,
+ .write_raw = &ads8688_write_raw,
+ .write_raw_get_fmt = &ads8688_write_raw_get_fmt,
+ .attrs = &ads8688_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static const struct ads8688_chip_info ads8688_chip_info_tbl[] = {
+ [ID_ADS8684] = {
+ .channels = ads8684_channels,
+ .num_channels = ARRAY_SIZE(ads8684_channels),
+ },
+ [ID_ADS8688] = {
+ .channels = ads8688_channels,
+ .num_channels = ARRAY_SIZE(ads8688_channels),
+ },
+};
+
+static int ads8688_probe(struct spi_device *spi)
+{
+ struct ads8688_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->reg = devm_regulator_get_optional(&spi->dev, "vref");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(st->reg);
+ if (ret < 0)
+ goto error_out;
+
+ st->vref_mv = ret / 1000;
+ } else {
+ /* Use internal reference */
+ st->vref_mv = ADS8688_VREF_MV;
+ }
+
+ st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ spi->mode = SPI_MODE_1;
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->info = &ads8688_info;
+
+ ads8688_reset(indio_dev);
+
+ mutex_init(&st->lock);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_out;
+
+ return 0;
+
+error_out:
+ if (!IS_ERR_OR_NULL(st->reg))
+ regulator_disable(st->reg);
+
+ return ret;
+}
+
+static int ads8688_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ads8688_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ if (!IS_ERR_OR_NULL(st->reg))
+ regulator_disable(st->reg);
+
+ return 0;
+}
+
+static const struct spi_device_id ads8688_id[] = {
+ {"ads8684", ID_ADS8684},
+ {"ads8688", ID_ADS8688},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ads8688_id);
+
+static const struct of_device_id ads8688_of_match[] = {
+ { .compatible = "ti,ads8684" },
+ { .compatible = "ti,ads8688" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads8688_of_match);
+
+static struct spi_driver ads8688_driver = {
+ .driver = {
+ .name = "ads8688",
+ .owner = THIS_MODULE,
+ },
+ .probe = ads8688_probe,
+ .remove = ads8688_remove,
+ .id_table = ads8688_id,
+};
+module_spi_driver(ads8688_driver);
+
+MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>");
+MODULE_DESCRIPTION("Texas Instruments ADS8688 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index 02e636a1c49a..0a6beb3d99cb 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -803,7 +803,7 @@ err:
return ret;
}
-static struct iio_buffer_setup_ops xadc_buffer_ops = {
+static const struct iio_buffer_setup_ops xadc_buffer_ops = {
.preenable = &xadc_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
diff --git a/drivers/iio/buffer/Kconfig b/drivers/iio/buffer/Kconfig
index 0a7b2fd3699b..4ffd3db7817f 100644
--- a/drivers/iio/buffer/Kconfig
+++ b/drivers/iio/buffer/Kconfig
@@ -9,6 +9,26 @@ config IIO_BUFFER_CB
Should be selected by any drivers that do in-kernel push
usage. That is, those where the data is pushed to the consumer.
+config IIO_BUFFER_DMA
+ tristate
+ help
+ Provides the generic IIO DMA buffer infrastructure that can be used by
+ drivers for devices with DMA support to implement the IIO buffer.
+
+ Should be selected by drivers that want to use the generic DMA buffer
+ infrastructure.
+
+config IIO_BUFFER_DMAENGINE
+ tristate
+ select IIO_BUFFER_DMA
+ help
+ Provides a bonding of the generic IIO DMA buffer infrastructure with the
+ DMAengine framework. This can be used by converter drivers with a DMA port
+ connected to an external DMA controller which is supported by the
+ DMAengine framework.
+
+ Should be selected by drivers that want to use this functionality.
+
config IIO_KFIFO_BUF
tristate "Industrial I/O buffering based on kfifo"
help
diff --git a/drivers/iio/buffer/Makefile b/drivers/iio/buffer/Makefile
index 4d193b9a9123..85beaae831ae 100644
--- a/drivers/iio/buffer/Makefile
+++ b/drivers/iio/buffer/Makefile
@@ -4,5 +4,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
+obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o
+obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c
new file mode 100644
index 000000000000..212cbedc7abb
--- /dev/null
+++ b/drivers/iio/buffer/industrialio-buffer-dma.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2013-2015 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/sizes.h>
+
+/*
+ * For DMA buffers the storage is sub-divided into so called blocks. Each block
+ * has its own memory buffer. The size of the block is the granularity at which
+ * memory is exchanged between the hardware and the application. Increasing the
+ * basic unit of data exchange from one sample to one block decreases the
+ * management overhead that is associated with each sample. E.g. if we say the
+ * management overhead for one exchange is x and the unit of exchange is one
+ * sample the overhead will be x for each sample. Whereas when using a block
+ * which contains n samples the overhead per sample is reduced to x/n. This
+ * allows to achieve much higher samplerates than what can be sustained with
+ * the one sample approach.
+ *
+ * Blocks are exchanged between the DMA controller and the application via the
+ * means of two queues. The incoming queue and the outgoing queue. Blocks on the
+ * incoming queue are waiting for the DMA controller to pick them up and fill
+ * them with data. Block on the outgoing queue have been filled with data and
+ * are waiting for the application to dequeue them and read the data.
+ *
+ * A block can be in one of the following states:
+ * * Owned by the application. In this state the application can read data from
+ * the block.
+ * * On the incoming list: Blocks on the incoming list are queued up to be
+ * processed by the DMA controller.
+ * * Owned by the DMA controller: The DMA controller is processing the block
+ * and filling it with data.
+ * * On the outgoing list: Blocks on the outgoing list have been successfully
+ * processed by the DMA controller and contain data. They can be dequeued by
+ * the application.
+ * * Dead: A block that is dead has been marked as to be freed. It might still
+ * be owned by either the application or the DMA controller at the moment.
+ * But once they are done processing it instead of going to either the
+ * incoming or outgoing queue the block will be freed.
+ *
+ * In addition to this blocks are reference counted and the memory associated
+ * with both the block structure as well as the storage memory for the block
+ * will be freed when the last reference to the block is dropped. This means a
+ * block must not be accessed without holding a reference.
+ *
+ * The iio_dma_buffer implementation provides a generic infrastructure for
+ * managing the blocks.
+ *
+ * A driver for a specific piece of hardware that has DMA capabilities need to
+ * implement the submit() callback from the iio_dma_buffer_ops structure. This
+ * callback is supposed to initiate the DMA transfer copying data from the
+ * converter to the memory region of the block. Once the DMA transfer has been
+ * completed the driver must call iio_dma_buffer_block_done() for the completed
+ * block.
+ *
+ * Prior to this it must set the bytes_used field of the block contains
+ * the actual number of bytes in the buffer. Typically this will be equal to the
+ * size of the block, but if the DMA hardware has certain alignment requirements
+ * for the transfer length it might choose to use less than the full size. In
+ * either case it is expected that bytes_used is a multiple of the bytes per
+ * datum, i.e. the block must not contain partial samples.
+ *
+ * The driver must call iio_dma_buffer_block_done() for each block it has
+ * received through its submit_block() callback, even if it does not actually
+ * perform a DMA transfer for the block, e.g. because the buffer was disabled
+ * before the block transfer was started. In this case it should set bytes_used
+ * to 0.
+ *
+ * In addition it is recommended that a driver implements the abort() callback.
+ * It will be called when the buffer is disabled and can be used to cancel
+ * pending and stop active transfers.
+ *
+ * The specific driver implementation should use the default callback
+ * implementations provided by this module for the iio_buffer_access_funcs
+ * struct. It may overload some callbacks with custom variants if the hardware
+ * has special requirements that are not handled by the generic functions. If a
+ * driver chooses to overload a callback it has to ensure that the generic
+ * callback is called from within the custom callback.
+ */
+
+static void iio_buffer_block_release(struct kref *kref)
+{
+ struct iio_dma_buffer_block *block = container_of(kref,
+ struct iio_dma_buffer_block, kref);
+
+ WARN_ON(block->state != IIO_BLOCK_STATE_DEAD);
+
+ dma_free_coherent(block->queue->dev, PAGE_ALIGN(block->size),
+ block->vaddr, block->phys_addr);
+
+ iio_buffer_put(&block->queue->buffer);
+ kfree(block);
+}
+
+static void iio_buffer_block_get(struct iio_dma_buffer_block *block)
+{
+ kref_get(&block->kref);
+}
+
+static void iio_buffer_block_put(struct iio_dma_buffer_block *block)
+{
+ kref_put(&block->kref, iio_buffer_block_release);
+}
+
+/*
+ * dma_free_coherent can sleep, hence we need to take some special care to be
+ * able to drop a reference from an atomic context.
+ */
+static LIST_HEAD(iio_dma_buffer_dead_blocks);
+static DEFINE_SPINLOCK(iio_dma_buffer_dead_blocks_lock);
+
+static void iio_dma_buffer_cleanup_worker(struct work_struct *work)
+{
+ struct iio_dma_buffer_block *block, *_block;
+ LIST_HEAD(block_list);
+
+ spin_lock_irq(&iio_dma_buffer_dead_blocks_lock);
+ list_splice_tail_init(&iio_dma_buffer_dead_blocks, &block_list);
+ spin_unlock_irq(&iio_dma_buffer_dead_blocks_lock);
+
+ list_for_each_entry_safe(block, _block, &block_list, head)
+ iio_buffer_block_release(&block->kref);
+}
+static DECLARE_WORK(iio_dma_buffer_cleanup_work, iio_dma_buffer_cleanup_worker);
+
+static void iio_buffer_block_release_atomic(struct kref *kref)
+{
+ struct iio_dma_buffer_block *block;
+ unsigned long flags;
+
+ block = container_of(kref, struct iio_dma_buffer_block, kref);
+
+ spin_lock_irqsave(&iio_dma_buffer_dead_blocks_lock, flags);
+ list_add_tail(&block->head, &iio_dma_buffer_dead_blocks);
+ spin_unlock_irqrestore(&iio_dma_buffer_dead_blocks_lock, flags);
+
+ schedule_work(&iio_dma_buffer_cleanup_work);
+}
+
+/*
+ * Version of iio_buffer_block_put() that can be called from atomic context
+ */
+static void iio_buffer_block_put_atomic(struct iio_dma_buffer_block *block)
+{
+ kref_put(&block->kref, iio_buffer_block_release_atomic);
+}
+
+static struct iio_dma_buffer_queue *iio_buffer_to_queue(struct iio_buffer *buf)
+{
+ return container_of(buf, struct iio_dma_buffer_queue, buffer);
+}
+
+static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
+ struct iio_dma_buffer_queue *queue, size_t size)
+{
+ struct iio_dma_buffer_block *block;
+
+ block = kzalloc(sizeof(*block), GFP_KERNEL);
+ if (!block)
+ return NULL;
+
+ block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size),
+ &block->phys_addr, GFP_KERNEL);
+ if (!block->vaddr) {
+ kfree(block);
+ return NULL;
+ }
+
+ block->size = size;
+ block->state = IIO_BLOCK_STATE_DEQUEUED;
+ block->queue = queue;
+ INIT_LIST_HEAD(&block->head);
+ kref_init(&block->kref);
+
+ iio_buffer_get(&queue->buffer);
+
+ return block;
+}
+
+static void _iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
+{
+ struct iio_dma_buffer_queue *queue = block->queue;
+
+ /*
+ * The buffer has already been freed by the application, just drop the
+ * reference.
+ */
+ if (block->state != IIO_BLOCK_STATE_DEAD) {
+ block->state = IIO_BLOCK_STATE_DONE;
+ list_add_tail(&block->head, &queue->outgoing);
+ }
+}
+
+/**
+ * iio_dma_buffer_block_done() - Indicate that a block has been completed
+ * @block: The completed block
+ *
+ * Should be called when the DMA controller has finished handling the block to
+ * pass back ownership of the block to the queue.
+ */
+void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
+{
+ struct iio_dma_buffer_queue *queue = block->queue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->list_lock, flags);
+ _iio_dma_buffer_block_done(block);
+ spin_unlock_irqrestore(&queue->list_lock, flags);
+
+ iio_buffer_block_put_atomic(block);
+ wake_up_interruptible_poll(&queue->buffer.pollq, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done);
+
+/**
+ * iio_dma_buffer_block_list_abort() - Indicate that a list block has been
+ * aborted
+ * @queue: Queue for which to complete blocks.
+ * @list: List of aborted blocks. All blocks in this list must be from @queue.
+ *
+ * Typically called from the abort() callback after the DMA controller has been
+ * stopped. This will set bytes_used to 0 for each block in the list and then
+ * hand the blocks back to the queue.
+ */
+void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue,
+ struct list_head *list)
+{
+ struct iio_dma_buffer_block *block, *_block;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->list_lock, flags);
+ list_for_each_entry_safe(block, _block, list, head) {
+ list_del(&block->head);
+ block->bytes_used = 0;
+ _iio_dma_buffer_block_done(block);
+ iio_buffer_block_put_atomic(block);
+ }
+ spin_unlock_irqrestore(&queue->list_lock, flags);
+
+ wake_up_interruptible_poll(&queue->buffer.pollq, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort);
+
+static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block)
+{
+ /*
+ * If the core owns the block it can be re-used. This should be the
+ * default case when enabling the buffer, unless the DMA controller does
+ * not support abort and has not given back the block yet.
+ */
+ switch (block->state) {
+ case IIO_BLOCK_STATE_DEQUEUED:
+ case IIO_BLOCK_STATE_QUEUED:
+ case IIO_BLOCK_STATE_DONE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * iio_dma_buffer_request_update() - DMA buffer request_update callback
+ * @buffer: The buffer which to request an update
+ *
+ * Should be used as the iio_dma_buffer_request_update() callback for
+ * iio_buffer_access_ops struct for DMA buffers.
+ */
+int iio_dma_buffer_request_update(struct iio_buffer *buffer)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+ struct iio_dma_buffer_block *block;
+ bool try_reuse = false;
+ size_t size;
+ int ret = 0;
+ int i;
+
+ /*
+ * Split the buffer into two even parts. This is used as a double
+ * buffering scheme with usually one block at a time being used by the
+ * DMA and the other one by the application.
+ */
+ size = DIV_ROUND_UP(queue->buffer.bytes_per_datum *
+ queue->buffer.length, 2);
+
+ mutex_lock(&queue->lock);
+
+ /* Allocations are page aligned */
+ if (PAGE_ALIGN(queue->fileio.block_size) == PAGE_ALIGN(size))
+ try_reuse = true;
+
+ queue->fileio.block_size = size;
+ queue->fileio.active_block = NULL;
+
+ spin_lock_irq(&queue->list_lock);
+ for (i = 0; i < 2; i++) {
+ block = queue->fileio.blocks[i];
+
+ /* If we can't re-use it free it */
+ if (block && (!iio_dma_block_reusable(block) || !try_reuse))
+ block->state = IIO_BLOCK_STATE_DEAD;
+ }
+
+ /*
+ * At this point all blocks are either owned by the core or marked as
+ * dead. This means we can reset the lists without having to fear
+ * corrution.
+ */
+ INIT_LIST_HEAD(&queue->outgoing);
+ spin_unlock_irq(&queue->list_lock);
+
+ INIT_LIST_HEAD(&queue->incoming);
+
+ for (i = 0; i < 2; i++) {
+ if (queue->fileio.blocks[i]) {
+ block = queue->fileio.blocks[i];
+ if (block->state == IIO_BLOCK_STATE_DEAD) {
+ /* Could not reuse it */
+ iio_buffer_block_put(block);
+ block = NULL;
+ } else {
+ block->size = size;
+ }
+ } else {
+ block = NULL;
+ }
+
+ if (!block) {
+ block = iio_dma_buffer_alloc_block(queue, size);
+ if (!block) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+ queue->fileio.blocks[i] = block;
+ }
+
+ block->state = IIO_BLOCK_STATE_QUEUED;
+ list_add_tail(&block->head, &queue->incoming);
+ }
+
+out_unlock:
+ mutex_unlock(&queue->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_request_update);
+
+static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue,
+ struct iio_dma_buffer_block *block)
+{
+ int ret;
+
+ /*
+ * If the hardware has already been removed we put the block into
+ * limbo. It will neither be on the incoming nor outgoing list, nor will
+ * it ever complete. It will just wait to be freed eventually.
+ */
+ if (!queue->ops)
+ return;
+
+ block->state = IIO_BLOCK_STATE_ACTIVE;
+ iio_buffer_block_get(block);
+ ret = queue->ops->submit(queue, block);
+ if (ret) {
+ /*
+ * This is a bit of a problem and there is not much we can do
+ * other then wait for the buffer to be disabled and re-enabled
+ * and try again. But it should not really happen unless we run
+ * out of memory or something similar.
+ *
+ * TODO: Implement support in the IIO core to allow buffers to
+ * notify consumers that something went wrong and the buffer
+ * should be disabled.
+ */
+ iio_buffer_block_put(block);
+ }
+}
+
+/**
+ * iio_dma_buffer_enable() - Enable DMA buffer
+ * @buffer: IIO buffer to enable
+ * @indio_dev: IIO device the buffer is attached to
+ *
+ * Needs to be called when the device that the buffer is attached to starts
+ * sampling. Typically should be the iio_buffer_access_ops enable callback.
+ *
+ * This will allocate the DMA buffers and start the DMA transfers.
+ */
+int iio_dma_buffer_enable(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+ struct iio_dma_buffer_block *block, *_block;
+
+ mutex_lock(&queue->lock);
+ queue->active = true;
+ list_for_each_entry_safe(block, _block, &queue->incoming, head) {
+ list_del(&block->head);
+ iio_dma_buffer_submit_block(queue, block);
+ }
+ mutex_unlock(&queue->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_enable);
+
+/**
+ * iio_dma_buffer_disable() - Disable DMA buffer
+ * @buffer: IIO DMA buffer to disable
+ * @indio_dev: IIO device the buffer is attached to
+ *
+ * Needs to be called when the device that the buffer is attached to stops
+ * sampling. Typically should be the iio_buffer_access_ops disable callback.
+ */
+int iio_dma_buffer_disable(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+
+ mutex_lock(&queue->lock);
+ queue->active = false;
+
+ if (queue->ops && queue->ops->abort)
+ queue->ops->abort(queue);
+ mutex_unlock(&queue->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_disable);
+
+static void iio_dma_buffer_enqueue(struct iio_dma_buffer_queue *queue,
+ struct iio_dma_buffer_block *block)
+{
+ if (block->state == IIO_BLOCK_STATE_DEAD) {
+ iio_buffer_block_put(block);
+ } else if (queue->active) {
+ iio_dma_buffer_submit_block(queue, block);
+ } else {
+ block->state = IIO_BLOCK_STATE_QUEUED;
+ list_add_tail(&block->head, &queue->incoming);
+ }
+}
+
+static struct iio_dma_buffer_block *iio_dma_buffer_dequeue(
+ struct iio_dma_buffer_queue *queue)
+{
+ struct iio_dma_buffer_block *block;
+
+ spin_lock_irq(&queue->list_lock);
+ block = list_first_entry_or_null(&queue->outgoing, struct
+ iio_dma_buffer_block, head);
+ if (block != NULL) {
+ list_del(&block->head);
+ block->state = IIO_BLOCK_STATE_DEQUEUED;
+ }
+ spin_unlock_irq(&queue->list_lock);
+
+ return block;
+}
+
+/**
+ * iio_dma_buffer_read() - DMA buffer read callback
+ * @buffer: Buffer to read form
+ * @n: Number of bytes to read
+ * @user_buffer: Userspace buffer to copy the data to
+ *
+ * Should be used as the read_first_n callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n,
+ char __user *user_buffer)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+ struct iio_dma_buffer_block *block;
+ int ret;
+
+ if (n < buffer->bytes_per_datum)
+ return -EINVAL;
+
+ mutex_lock(&queue->lock);
+
+ if (!queue->fileio.active_block) {
+ block = iio_dma_buffer_dequeue(queue);
+ if (block == NULL) {
+ ret = 0;
+ goto out_unlock;
+ }
+ queue->fileio.pos = 0;
+ queue->fileio.active_block = block;
+ } else {
+ block = queue->fileio.active_block;
+ }
+
+ n = rounddown(n, buffer->bytes_per_datum);
+ if (n > block->bytes_used - queue->fileio.pos)
+ n = block->bytes_used - queue->fileio.pos;
+
+ if (copy_to_user(user_buffer, block->vaddr + queue->fileio.pos, n)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ queue->fileio.pos += n;
+
+ if (queue->fileio.pos == block->bytes_used) {
+ queue->fileio.active_block = NULL;
+ iio_dma_buffer_enqueue(queue, block);
+ }
+
+ ret = n;
+
+out_unlock:
+ mutex_unlock(&queue->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_read);
+
+/**
+ * iio_dma_buffer_data_available() - DMA buffer data_available callback
+ * @buf: Buffer to check for data availability
+ *
+ * Should be used as the data_available callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+size_t iio_dma_buffer_data_available(struct iio_buffer *buf)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buf);
+ struct iio_dma_buffer_block *block;
+ size_t data_available = 0;
+
+ /*
+ * For counting the available bytes we'll use the size of the block not
+ * the number of actual bytes available in the block. Otherwise it is
+ * possible that we end up with a value that is lower than the watermark
+ * but won't increase since all blocks are in use.
+ */
+
+ mutex_lock(&queue->lock);
+ if (queue->fileio.active_block)
+ data_available += queue->fileio.active_block->size;
+
+ spin_lock_irq(&queue->list_lock);
+ list_for_each_entry(block, &queue->outgoing, head)
+ data_available += block->size;
+ spin_unlock_irq(&queue->list_lock);
+ mutex_unlock(&queue->lock);
+
+ return data_available;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_data_available);
+
+/**
+ * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback
+ * @buffer: Buffer to set the bytes-per-datum for
+ * @bpd: The new bytes-per-datum value
+ *
+ * Should be used as the set_bytes_per_datum callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd)
+{
+ buffer->bytes_per_datum = bpd;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_set_bytes_per_datum);
+
+/**
+ * iio_dma_buffer_set_length - DMA buffer set_length callback
+ * @buffer: Buffer to set the length for
+ * @length: The new buffer length
+ *
+ * Should be used as the set_length callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+int iio_dma_buffer_set_length(struct iio_buffer *buffer, int length)
+{
+ /* Avoid an invalid state */
+ if (length < 2)
+ length = 2;
+ buffer->length = length;
+ buffer->watermark = length / 2;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_set_length);
+
+/**
+ * iio_dma_buffer_init() - Initialize DMA buffer queue
+ * @queue: Buffer to initialize
+ * @dev: DMA device
+ * @ops: DMA buffer queue callback operations
+ *
+ * The DMA device will be used by the queue to do DMA memory allocations. So it
+ * should refer to the device that will perform the DMA to ensure that
+ * allocations are done from a memory region that can be accessed by the device.
+ */
+int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue,
+ struct device *dev, const struct iio_dma_buffer_ops *ops)
+{
+ iio_buffer_init(&queue->buffer);
+ queue->buffer.length = PAGE_SIZE;
+ queue->buffer.watermark = queue->buffer.length / 2;
+ queue->dev = dev;
+ queue->ops = ops;
+
+ INIT_LIST_HEAD(&queue->incoming);
+ INIT_LIST_HEAD(&queue->outgoing);
+
+ mutex_init(&queue->lock);
+ spin_lock_init(&queue->list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_init);
+
+/**
+ * iio_dma_buffer_exit() - Cleanup DMA buffer queue
+ * @queue: Buffer to cleanup
+ *
+ * After this function has completed it is safe to free any resources that are
+ * associated with the buffer and are accessed inside the callback operations.
+ */
+void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue)
+{
+ unsigned int i;
+
+ mutex_lock(&queue->lock);
+
+ spin_lock_irq(&queue->list_lock);
+ for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+ if (!queue->fileio.blocks[i])
+ continue;
+ queue->fileio.blocks[i]->state = IIO_BLOCK_STATE_DEAD;
+ }
+ INIT_LIST_HEAD(&queue->outgoing);
+ spin_unlock_irq(&queue->list_lock);
+
+ INIT_LIST_HEAD(&queue->incoming);
+
+ for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+ if (!queue->fileio.blocks[i])
+ continue;
+ iio_buffer_block_put(queue->fileio.blocks[i]);
+ queue->fileio.blocks[i] = NULL;
+ }
+ queue->fileio.active_block = NULL;
+ queue->ops = NULL;
+
+ mutex_unlock(&queue->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_exit);
+
+/**
+ * iio_dma_buffer_release() - Release final buffer resources
+ * @queue: Buffer to release
+ *
+ * Frees resources that can't yet be freed in iio_dma_buffer_exit(). Should be
+ * called in the buffers release callback implementation right before freeing
+ * the memory associated with the buffer.
+ */
+void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue)
+{
+ mutex_destroy(&queue->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_release);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("DMA buffer for the IIO framework");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
new file mode 100644
index 000000000000..ebdb838d3a1c
--- /dev/null
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2014-2015 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dma.h>
+#include <linux/iio/buffer-dmaengine.h>
+
+/*
+ * The IIO DMAengine buffer combines the generic IIO DMA buffer infrastructure
+ * with the DMAengine framework. The generic IIO DMA buffer infrastructure is
+ * used to manage the buffer memory and implement the IIO buffer operations
+ * while the DMAengine framework is used to perform the DMA transfers. Combined
+ * this results in a device independent fully functional DMA buffer
+ * implementation that can be used by device drivers for peripherals which are
+ * connected to a DMA controller which has a DMAengine driver implementation.
+ */
+
+struct dmaengine_buffer {
+ struct iio_dma_buffer_queue queue;
+
+ struct dma_chan *chan;
+ struct list_head active;
+
+ size_t align;
+ size_t max_size;
+};
+
+static struct dmaengine_buffer *iio_buffer_to_dmaengine_buffer(
+ struct iio_buffer *buffer)
+{
+ return container_of(buffer, struct dmaengine_buffer, queue.buffer);
+}
+
+static void iio_dmaengine_buffer_block_done(void *data)
+{
+ struct iio_dma_buffer_block *block = data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&block->queue->list_lock, flags);
+ list_del(&block->head);
+ spin_unlock_irqrestore(&block->queue->list_lock, flags);
+ iio_dma_buffer_block_done(block);
+}
+
+static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
+ struct iio_dma_buffer_block *block)
+{
+ struct dmaengine_buffer *dmaengine_buffer =
+ iio_buffer_to_dmaengine_buffer(&queue->buffer);
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+
+ block->bytes_used = min(block->size, dmaengine_buffer->max_size);
+ block->bytes_used = rounddown(block->bytes_used,
+ dmaengine_buffer->align);
+
+ desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
+ block->phys_addr, block->bytes_used, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->callback = iio_dmaengine_buffer_block_done;
+ desc->callback_param = block;
+
+ cookie = dmaengine_submit(desc);
+ if (dma_submit_error(cookie))
+ return dma_submit_error(cookie);
+
+ spin_lock_irq(&dmaengine_buffer->queue.list_lock);
+ list_add_tail(&block->head, &dmaengine_buffer->active);
+ spin_unlock_irq(&dmaengine_buffer->queue.list_lock);
+
+ dma_async_issue_pending(dmaengine_buffer->chan);
+
+ return 0;
+}
+
+static void iio_dmaengine_buffer_abort(struct iio_dma_buffer_queue *queue)
+{
+ struct dmaengine_buffer *dmaengine_buffer =
+ iio_buffer_to_dmaengine_buffer(&queue->buffer);
+
+ dmaengine_terminate_all(dmaengine_buffer->chan);
+ /* FIXME: There is a slight chance of a race condition here.
+ * dmaengine_terminate_all() does not guarantee that all transfer
+ * callbacks have finished running. Need to introduce a
+ * dmaengine_terminate_all_sync().
+ */
+ iio_dma_buffer_block_list_abort(queue, &dmaengine_buffer->active);
+}
+
+static void iio_dmaengine_buffer_release(struct iio_buffer *buf)
+{
+ struct dmaengine_buffer *dmaengine_buffer =
+ iio_buffer_to_dmaengine_buffer(buf);
+
+ iio_dma_buffer_release(&dmaengine_buffer->queue);
+ kfree(dmaengine_buffer);
+}
+
+static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
+ .read_first_n = iio_dma_buffer_read,
+ .set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum,
+ .set_length = iio_dma_buffer_set_length,
+ .request_update = iio_dma_buffer_request_update,
+ .enable = iio_dma_buffer_enable,
+ .disable = iio_dma_buffer_disable,
+ .data_available = iio_dma_buffer_data_available,
+ .release = iio_dmaengine_buffer_release,
+
+ .modes = INDIO_BUFFER_HARDWARE,
+ .flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK,
+};
+
+static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = {
+ .submit = iio_dmaengine_buffer_submit_block,
+ .abort = iio_dmaengine_buffer_abort,
+};
+
+/**
+ * iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
+ * @dev: Parent device for the buffer
+ * @channel: DMA channel name, typically "rx".
+ *
+ * This allocates a new IIO buffer which internally uses the DMAengine framework
+ * to perform its transfers. The parent device will be used to request the DMA
+ * channel.
+ *
+ * Once done using the buffer iio_dmaengine_buffer_free() should be used to
+ * release it.
+ */
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+ const char *channel)
+{
+ struct dmaengine_buffer *dmaengine_buffer;
+ unsigned int width, src_width, dest_width;
+ struct dma_slave_caps caps;
+ struct dma_chan *chan;
+ int ret;
+
+ dmaengine_buffer = kzalloc(sizeof(*dmaengine_buffer), GFP_KERNEL);
+ if (!dmaengine_buffer)
+ return ERR_PTR(-ENOMEM);
+
+ chan = dma_request_slave_channel_reason(dev, channel);
+ if (IS_ERR(chan)) {
+ ret = PTR_ERR(chan);
+ goto err_free;
+ }
+
+ ret = dma_get_slave_caps(chan, &caps);
+ if (ret < 0)
+ goto err_free;
+
+ /* Needs to be aligned to the maximum of the minimums */
+ if (caps.src_addr_widths)
+ src_width = __ffs(caps.src_addr_widths);
+ else
+ src_width = 1;
+ if (caps.dst_addr_widths)
+ dest_width = __ffs(caps.dst_addr_widths);
+ else
+ dest_width = 1;
+ width = max(src_width, dest_width);
+
+ INIT_LIST_HEAD(&dmaengine_buffer->active);
+ dmaengine_buffer->chan = chan;
+ dmaengine_buffer->align = width;
+ dmaengine_buffer->max_size = dma_get_max_seg_size(chan->device->dev);
+
+ iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev,
+ &iio_dmaengine_default_ops);
+
+ dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops;
+
+ return &dmaengine_buffer->queue.buffer;
+
+err_free:
+ kfree(dmaengine_buffer);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(iio_dmaengine_buffer_alloc);
+
+/**
+ * iio_dmaengine_buffer_free() - Free dmaengine buffer
+ * @buffer: Buffer to free
+ *
+ * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc().
+ */
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
+{
+ struct dmaengine_buffer *dmaengine_buffer =
+ iio_buffer_to_dmaengine_buffer(buffer);
+
+ iio_dma_buffer_exit(&dmaengine_buffer->queue);
+ dma_release_channel(dmaengine_buffer->chan);
+
+ iio_buffer_put(buffer);
+}
+EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free);
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index 3061b7299f0f..f16de61be46d 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -4,6 +4,14 @@
menu "Chemical Sensors"
+config IAQCORE
+ tristate "AMS iAQ-Core VOC sensors"
+ depends on I2C
+ help
+ Say Y here to build I2C interface support for the AMS
+ iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
+ sensors
+
config VZ89X
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 7292f2ded587..167861fadfab 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -3,4 +3,5 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_VZ89X) += vz89x.o
diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c
new file mode 100644
index 000000000000..41a8e6f2e31d
--- /dev/null
+++ b/drivers/iio/chemical/ams-iaq-core.c
@@ -0,0 +1,200 @@
+/*
+ * ams-iaq-core.c - Support for AMS iAQ-Core VOC sensors
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+
+#define AMS_IAQCORE_DATA_SIZE 9
+
+#define AMS_IAQCORE_VOC_CO2_IDX 0
+#define AMS_IAQCORE_VOC_RESISTANCE_IDX 1
+#define AMS_IAQCORE_VOC_TVOC_IDX 2
+
+struct ams_iaqcore_reading {
+ __be16 co2_ppm;
+ u8 status;
+ __be32 resistance;
+ __be16 voc_ppb;
+} __attribute__((__packed__));
+
+struct ams_iaqcore_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ unsigned long last_update;
+
+ struct ams_iaqcore_reading buffer;
+};
+
+static const struct iio_chan_spec ams_iaqcore_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_CO2,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .address = AMS_IAQCORE_VOC_CO2_IDX,
+ },
+ {
+ .type = IIO_RESISTANCE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .address = AMS_IAQCORE_VOC_RESISTANCE_IDX,
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .address = AMS_IAQCORE_VOC_TVOC_IDX,
+ },
+};
+
+static int ams_iaqcore_read_measurement(struct ams_iaqcore_data *data)
+{
+ struct i2c_client *client = data->client;
+ int ret;
+
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = client->flags | I2C_M_RD,
+ .len = AMS_IAQCORE_DATA_SIZE,
+ .buf = (char *) &data->buffer,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return (ret == AMS_IAQCORE_DATA_SIZE) ? 0 : ret;
+}
+
+static int ams_iaqcore_get_measurement(struct ams_iaqcore_data *data)
+{
+ int ret;
+
+ /* sensor can only be polled once a second max per datasheet */
+ if (!time_after(jiffies, data->last_update + HZ))
+ return 0;
+
+ ret = ams_iaqcore_read_measurement(data);
+ if (ret < 0)
+ return ret;
+
+ data->last_update = jiffies;
+
+ return 0;
+}
+
+static int ams_iaqcore_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct ams_iaqcore_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (mask != IIO_CHAN_INFO_PROCESSED)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ ret = ams_iaqcore_get_measurement(data);
+
+ if (ret)
+ goto err_out;
+
+ switch (chan->address) {
+ case AMS_IAQCORE_VOC_CO2_IDX:
+ *val = 0;
+ *val2 = be16_to_cpu(data->buffer.co2_ppm);
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case AMS_IAQCORE_VOC_RESISTANCE_IDX:
+ *val = be32_to_cpu(data->buffer.resistance);
+ ret = IIO_VAL_INT;
+ break;
+ case AMS_IAQCORE_VOC_TVOC_IDX:
+ *val = 0;
+ *val2 = be16_to_cpu(data->buffer.voc_ppb);
+ ret = IIO_VAL_INT_PLUS_NANO;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+err_out:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static const struct iio_info ams_iaqcore_info = {
+ .read_raw = ams_iaqcore_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int ams_iaqcore_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct ams_iaqcore_data *data;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ /* so initial reading will complete */
+ data->last_update = jiffies - HZ;
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &ams_iaqcore_info,
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ indio_dev->channels = ams_iaqcore_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ams_iaqcore_channels);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ams_iaqcore_id[] = {
+ { "ams-iaq-core", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id);
+
+static const struct of_device_id ams_iaqcore_dt_ids[] = {
+ { .compatible = "ams,iaq-core" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ams_iaqcore_dt_ids);
+
+static struct i2c_driver ams_iaqcore_driver = {
+ .driver = {
+ .name = "ams-iaq-core",
+ .of_match_table = of_match_ptr(ams_iaqcore_dt_ids),
+ },
+ .probe = ams_iaqcore_probe,
+ .id_table = ams_iaqcore_id,
+};
+module_i2c_driver(ams_iaqcore_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("AMS iAQ-Core VOC sensors");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index 11e59a5a5112..b8b804923230 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -34,8 +34,9 @@
struct vz89x_data {
struct i2c_client *client;
struct mutex lock;
- unsigned long last_update;
+ int (*xfer)(struct vz89x_data *data, u8 cmd);
+ unsigned long last_update;
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
};
@@ -100,27 +101,60 @@ static int vz89x_measurement_is_valid(struct vz89x_data *data)
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
}
-static int vz89x_get_measurement(struct vz89x_data *data)
+static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{
+ struct i2c_client *client = data->client;
+ struct i2c_msg msg[2];
int ret;
- int i;
+ u8 buf[3] = { cmd, 0, 0};
- /* sensor can only be polled once a second max per datasheet */
- if (!time_after(jiffies, data->last_update + HZ))
- return 0;
+ msg[0].addr = client->addr;
+ msg[0].flags = client->flags;
+ msg[0].len = 3;
+ msg[0].buf = (char *) &buf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = client->flags | I2C_M_RD;
+ msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
+ msg[1].buf = (char *) &data->buffer;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
- ret = i2c_smbus_write_word_data(data->client,
- VZ89X_REG_MEASUREMENT, 0);
+ return (ret == 2) ? 0 : ret;
+}
+
+static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
+{
+ struct i2c_client *client = data->client;
+ int ret;
+ int i;
+
+ ret = i2c_smbus_write_word_data(client, cmd, 0);
if (ret < 0)
return ret;
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
- ret = i2c_smbus_read_byte(data->client);
+ ret = i2c_smbus_read_byte(client);
if (ret < 0)
return ret;
data->buffer[i] = ret;
}
+ return 0;
+}
+
+static int vz89x_get_measurement(struct vz89x_data *data)
+{
+ int ret;
+
+ /* sensor can only be polled once a second max per datasheet */
+ if (!time_after(jiffies, data->last_update + HZ))
+ return 0;
+
+ ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
+ if (ret < 0)
+ return ret;
+
ret = vz89x_measurement_is_valid(data);
if (ret)
return -EAGAIN;
@@ -204,15 +238,19 @@ static int vz89x_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
struct vz89x_data *data;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BYTE))
- return -ENODEV;
-
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
-
data = iio_priv(indio_dev);
+
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ data->xfer = vz89x_i2c_xfer;
+ else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
+ data->xfer = vz89x_smbus_xfer;
+ else
+ return -ENOTSUPP;
+
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->last_update = jiffies - HZ;
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 25258e2c1a82..8447c31e27f2 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -18,9 +18,6 @@
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
-
-#define ST_SENSORS_WAI_ADDRESS 0x0f
-
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig
new file mode 100644
index 000000000000..71805ced1aae
--- /dev/null
+++ b/drivers/iio/dummy/Kconfig
@@ -0,0 +1,36 @@
+#
+# Industrial I/O subsystem Dummy Driver configuration
+#
+menu "IIO dummy driver"
+ depends on IIO
+
+config IIO_DUMMY_EVGEN
+ select IRQ_WORK
+ tristate
+
+config IIO_SIMPLE_DUMMY
+ tristate "An example driver with no hardware requirements"
+ help
+ Driver intended mainly as documentation for how to write
+ a driver. May also be useful for testing userspace code
+ without hardware.
+
+if IIO_SIMPLE_DUMMY
+
+config IIO_SIMPLE_DUMMY_EVENTS
+ bool "Event generation support"
+ select IIO_DUMMY_EVGEN
+ help
+ Add some dummy events to the simple dummy driver.
+
+config IIO_SIMPLE_DUMMY_BUFFER
+ bool "Buffered capture support"
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_KFIFO_BUF
+ help
+ Add buffered data capture to the simple dummy driver.
+
+endif # IIO_SIMPLE_DUMMY
+
+endmenu
diff --git a/drivers/iio/dummy/Makefile b/drivers/iio/dummy/Makefile
new file mode 100644
index 000000000000..0765e93d7804
--- /dev/null
+++ b/drivers/iio/dummy/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the IIO Dummy Driver
+#
+
+obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
+iio_dummy-y := iio_simple_dummy.o
+iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o
+iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
+
+obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/iio/dummy/iio_dummy_evgen.c
index 9e83f348df51..9e83f348df51 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/iio/dummy/iio_dummy_evgen.c
diff --git a/drivers/staging/iio/iio_dummy_evgen.h b/drivers/iio/dummy/iio_dummy_evgen.h
index d044b946e74a..d044b946e74a 100644
--- a/drivers/staging/iio/iio_dummy_evgen.h
+++ b/drivers/iio/dummy/iio_dummy_evgen.h
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c
index 43fe4ba7d0dc..43fe4ba7d0dc 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/iio/dummy/iio_simple_dummy.c
diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/iio/dummy/iio_simple_dummy.h
index b9069a180672..b9069a180672 100644
--- a/drivers/staging/iio/iio_simple_dummy.h
+++ b/drivers/iio/dummy/iio_simple_dummy.h
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c
index cf44a6f79431..cf44a6f79431 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c
index 6eb600ff7056..6eb600ff7056 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/iio/dummy/iio_simple_dummy_events.c
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index f8d1c2210066..b04faf93e1bc 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -435,7 +435,9 @@ static int adis16136_initial_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- sscanf(indio_dev->name, "adis%u\n", &device_id);
+ ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+ if (ret != 1)
+ return -EINVAL;
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 02ff789852a0..bbce3b09ac45 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -1077,25 +1077,23 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
goto err_trigger_unregister;
}
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(dev, "unable to register iio device\n");
- goto err_buffer_cleanup;
- }
-
ret = pm_runtime_set_active(dev);
if (ret)
- goto err_iio_unregister;
+ goto err_buffer_cleanup;
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev,
BMG160_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(dev, "unable to register iio device\n");
+ goto err_buffer_cleanup;
+ }
+
return 0;
-err_iio_unregister:
- iio_device_unregister(indio_dev);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister:
@@ -1113,11 +1111,12 @@ void bmg160_core_remove(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmg160_data *data = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
- iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (data->dready_trig) {
diff --git a/drivers/iio/health/Kconfig b/drivers/iio/health/Kconfig
new file mode 100644
index 000000000000..a647679da805
--- /dev/null
+++ b/drivers/iio/health/Kconfig
@@ -0,0 +1,21 @@
+#
+# Health sensors
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Health sensors"
+
+config MAX30100
+ tristate "MAX30100 heart rate and pulse oximeter sensor"
+ depends on I2C
+ select REGMAP_I2C
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Say Y here to build I2C interface support for the Maxim
+ MAX30100 heart rate, and pulse oximeter sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called max30100.
+
+endmenu
diff --git a/drivers/iio/health/Makefile b/drivers/iio/health/Makefile
new file mode 100644
index 000000000000..7c475d7faad8
--- /dev/null
+++ b/drivers/iio/health/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for IIO Health sensors
+#
+
+# When adding new entries keep the list in alphabetical order
+
+obj-$(CONFIG_MAX30100) += max30100.o
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
new file mode 100644
index 000000000000..9d1c81f91dd7
--- /dev/null
+++ b/drivers/iio/health/max30100.c
@@ -0,0 +1,453 @@
+/*
+ * max30100.c - Support for MAX30100 heart rate and pulse oximeter sensor
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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.
+ *
+ * TODO: allow LED current and pulse length controls via device tree properties
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#define MAX30100_REGMAP_NAME "max30100_regmap"
+#define MAX30100_DRV_NAME "max30100"
+
+#define MAX30100_REG_INT_STATUS 0x00
+#define MAX30100_REG_INT_STATUS_PWR_RDY BIT(0)
+#define MAX30100_REG_INT_STATUS_SPO2_RDY BIT(4)
+#define MAX30100_REG_INT_STATUS_HR_RDY BIT(5)
+#define MAX30100_REG_INT_STATUS_FIFO_RDY BIT(7)
+
+#define MAX30100_REG_INT_ENABLE 0x01
+#define MAX30100_REG_INT_ENABLE_SPO2_EN BIT(0)
+#define MAX30100_REG_INT_ENABLE_HR_EN BIT(1)
+#define MAX30100_REG_INT_ENABLE_FIFO_EN BIT(3)
+#define MAX30100_REG_INT_ENABLE_MASK 0xf0
+#define MAX30100_REG_INT_ENABLE_MASK_SHIFT 4
+
+#define MAX30100_REG_FIFO_WR_PTR 0x02
+#define MAX30100_REG_FIFO_OVR_CTR 0x03
+#define MAX30100_REG_FIFO_RD_PTR 0x04
+#define MAX30100_REG_FIFO_DATA 0x05
+#define MAX30100_REG_FIFO_DATA_ENTRY_COUNT 16
+#define MAX30100_REG_FIFO_DATA_ENTRY_LEN 4
+
+#define MAX30100_REG_MODE_CONFIG 0x06
+#define MAX30100_REG_MODE_CONFIG_MODE_SPO2_EN BIT(0)
+#define MAX30100_REG_MODE_CONFIG_MODE_HR_EN BIT(1)
+#define MAX30100_REG_MODE_CONFIG_MODE_MASK 0x03
+#define MAX30100_REG_MODE_CONFIG_TEMP_EN BIT(3)
+#define MAX30100_REG_MODE_CONFIG_PWR BIT(7)
+
+#define MAX30100_REG_SPO2_CONFIG 0x07
+#define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2)
+#define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6)
+#define MAX30100_REG_SPO2_CONFIG_1600US 0x3
+
+#define MAX30100_REG_LED_CONFIG 0x09
+#define MAX30100_REG_LED_CONFIG_RED_LED_SHIFT 4
+
+#define MAX30100_REG_LED_CONFIG_24MA 0x07
+#define MAX30100_REG_LED_CONFIG_50MA 0x0f
+
+#define MAX30100_REG_TEMP_INTEGER 0x16
+#define MAX30100_REG_TEMP_FRACTION 0x17
+
+struct max30100_data {
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct mutex lock;
+ struct regmap *regmap;
+
+ __be16 buffer[2]; /* 2 16-bit channels */
+};
+
+static bool max30100_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX30100_REG_INT_STATUS:
+ case MAX30100_REG_MODE_CONFIG:
+ case MAX30100_REG_FIFO_WR_PTR:
+ case MAX30100_REG_FIFO_OVR_CTR:
+ case MAX30100_REG_FIFO_RD_PTR:
+ case MAX30100_REG_FIFO_DATA:
+ case MAX30100_REG_TEMP_INTEGER:
+ case MAX30100_REG_TEMP_FRACTION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config max30100_regmap_config = {
+ .name = MAX30100_REGMAP_NAME,
+
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = MAX30100_REG_TEMP_FRACTION,
+ .cache_type = REGCACHE_FLAT,
+
+ .volatile_reg = max30100_is_volatile_reg,
+};
+
+static const unsigned long max30100_scan_masks[] = {0x3, 0};
+
+static const struct iio_chan_spec max30100_channels[] = {
+ {
+ .type = IIO_INTENSITY,
+ .channel2 = IIO_MOD_LIGHT_IR,
+ .modified = 1,
+
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ },
+ {
+ .type = IIO_INTENSITY,
+ .channel2 = IIO_MOD_LIGHT_RED,
+ .modified = 1,
+
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = -1,
+ },
+};
+
+static int max30100_set_powermode(struct max30100_data *data, bool state)
+{
+ return regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
+ MAX30100_REG_MODE_CONFIG_PWR,
+ state ? 0 : MAX30100_REG_MODE_CONFIG_PWR);
+}
+
+static int max30100_clear_fifo(struct max30100_data *data)
+{
+ int ret;
+
+ ret = regmap_write(data->regmap, MAX30100_REG_FIFO_WR_PTR, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, MAX30100_REG_FIFO_OVR_CTR, 0);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, MAX30100_REG_FIFO_RD_PTR, 0);
+}
+
+static int max30100_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct max30100_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = max30100_set_powermode(data, true);
+ if (ret)
+ return ret;
+
+ return max30100_clear_fifo(data);
+}
+
+static int max30100_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct max30100_data *data = iio_priv(indio_dev);
+
+ return max30100_set_powermode(data, false);
+}
+
+static const struct iio_buffer_setup_ops max30100_buffer_setup_ops = {
+ .postenable = max30100_buffer_postenable,
+ .predisable = max30100_buffer_predisable,
+};
+
+static inline int max30100_fifo_count(struct max30100_data *data)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(data->regmap, MAX30100_REG_INT_STATUS, &val);
+ if (ret)
+ return ret;
+
+ /* FIFO is almost full */
+ if (val & MAX30100_REG_INT_STATUS_FIFO_RDY)
+ return MAX30100_REG_FIFO_DATA_ENTRY_COUNT - 1;
+
+ return 0;
+}
+
+static int max30100_read_measurement(struct max30100_data *data)
+{
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(data->client,
+ MAX30100_REG_FIFO_DATA,
+ MAX30100_REG_FIFO_DATA_ENTRY_LEN,
+ (u8 *) &data->buffer);
+
+ return (ret == MAX30100_REG_FIFO_DATA_ENTRY_LEN) ? 0 : ret;
+}
+
+static irqreturn_t max30100_interrupt_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct max30100_data *data = iio_priv(indio_dev);
+ int ret, cnt = 0;
+
+ mutex_lock(&data->lock);
+
+ while (cnt-- || (cnt = max30100_fifo_count(data) > 0)) {
+ ret = max30100_read_measurement(data);
+ if (ret)
+ break;
+
+ iio_push_to_buffers(data->indio_dev, data->buffer);
+ }
+
+ mutex_unlock(&data->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int max30100_chip_init(struct max30100_data *data)
+{
+ int ret;
+
+ /* RED IR LED = 24mA, IR LED = 50mA */
+ ret = regmap_write(data->regmap, MAX30100_REG_LED_CONFIG,
+ (MAX30100_REG_LED_CONFIG_24MA <<
+ MAX30100_REG_LED_CONFIG_RED_LED_SHIFT) |
+ MAX30100_REG_LED_CONFIG_50MA);
+ if (ret)
+ return ret;
+
+ /* enable hi-res SPO2 readings at 100Hz */
+ ret = regmap_write(data->regmap, MAX30100_REG_SPO2_CONFIG,
+ MAX30100_REG_SPO2_CONFIG_HI_RES_EN |
+ MAX30100_REG_SPO2_CONFIG_100HZ);
+ if (ret)
+ return ret;
+
+ /* enable SPO2 mode */
+ ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
+ MAX30100_REG_MODE_CONFIG_MODE_MASK,
+ MAX30100_REG_MODE_CONFIG_MODE_HR_EN |
+ MAX30100_REG_MODE_CONFIG_MODE_SPO2_EN);
+ if (ret)
+ return ret;
+
+ /* enable FIFO interrupt */
+ return regmap_update_bits(data->regmap, MAX30100_REG_INT_ENABLE,
+ MAX30100_REG_INT_ENABLE_MASK,
+ MAX30100_REG_INT_ENABLE_FIFO_EN
+ << MAX30100_REG_INT_ENABLE_MASK_SHIFT);
+}
+
+static int max30100_read_temp(struct max30100_data *data, int *val)
+{
+ int ret;
+ unsigned int reg;
+
+ ret = regmap_read(data->regmap, MAX30100_REG_TEMP_INTEGER, &reg);
+ if (ret < 0)
+ return ret;
+ *val = reg << 4;
+
+ ret = regmap_read(data->regmap, MAX30100_REG_TEMP_FRACTION, &reg);
+ if (ret < 0)
+ return ret;
+
+ *val |= reg & 0xf;
+ *val = sign_extend32(*val, 11);
+
+ return 0;
+}
+
+static int max30100_get_temp(struct max30100_data *data, int *val)
+{
+ int ret;
+
+ /* start acquisition */
+ ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
+ MAX30100_REG_MODE_CONFIG_TEMP_EN,
+ MAX30100_REG_MODE_CONFIG_TEMP_EN);
+ if (ret)
+ return ret;
+
+ usleep_range(35000, 50000);
+
+ return max30100_read_temp(data, val);
+}
+
+static int max30100_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max30100_data *data = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ /*
+ * Temperature reading can only be acquired while engine
+ * is running
+ */
+ mutex_lock(&indio_dev->mlock);
+
+ if (!iio_buffer_enabled(indio_dev))
+ ret = -EAGAIN;
+ else {
+ ret = max30100_get_temp(data, val);
+ if (!ret)
+ ret = IIO_VAL_INT;
+
+ }
+
+ mutex_unlock(&indio_dev->mlock);
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1; /* 0.0625 */
+ *val2 = 16;
+ ret = IIO_VAL_FRACTIONAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct iio_info max30100_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = max30100_read_raw,
+};
+
+static int max30100_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max30100_data *data;
+ struct iio_buffer *buffer;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ buffer = devm_iio_kfifo_allocate(&client->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(indio_dev, buffer);
+
+ indio_dev->name = MAX30100_DRV_NAME;
+ indio_dev->channels = max30100_channels;
+ indio_dev->info = &max30100_info;
+ indio_dev->num_channels = ARRAY_SIZE(max30100_channels);
+ indio_dev->available_scan_masks = max30100_scan_masks;
+ indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
+ indio_dev->setup_ops = &max30100_buffer_setup_ops;
+
+ data = iio_priv(indio_dev);
+ data->indio_dev = indio_dev;
+ data->client = client;
+
+ mutex_init(&data->lock);
+ i2c_set_clientdata(client, indio_dev);
+
+ data->regmap = devm_regmap_init_i2c(client, &max30100_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(&client->dev, "regmap initialization failed.\n");
+ return PTR_ERR(data->regmap);
+ }
+ max30100_set_powermode(data, false);
+
+ ret = max30100_chip_init(data);
+ if (ret)
+ return ret;
+
+ if (client->irq <= 0) {
+ dev_err(&client->dev, "no valid irq defined\n");
+ return -EINVAL;
+ }
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, max30100_interrupt_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "max30100_irq", indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+ return ret;
+ }
+
+ return iio_device_register(indio_dev);
+}
+
+static int max30100_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct max30100_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ max30100_set_powermode(data, false);
+
+ return 0;
+}
+
+static const struct i2c_device_id max30100_id[] = {
+ { "max30100", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, max30100_id);
+
+static const struct of_device_id max30100_dt_ids[] = {
+ { .compatible = "maxim,max30100" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max30100_dt_ids);
+
+static struct i2c_driver max30100_driver = {
+ .driver = {
+ .name = MAX30100_DRV_NAME,
+ .of_match_table = of_match_ptr(max30100_dt_ids),
+ },
+ .probe = max30100_probe,
+ .remove = max30100_remove,
+ .id_table = max30100_id,
+};
+module_i2c_driver(max30100_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("MAX30100 heart rate and pulse oximeter sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index 0618f831ecd4..fb7c0dbed51c 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -288,7 +288,11 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
if (ret)
goto err_ret;
- sscanf(indio_dev->name, "adis%u\n", &device_id);
+ ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto err_ret;
+ }
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 2485b88ee1b6..8cf84d3488b2 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -765,7 +765,9 @@ static int adis16480_initial_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- sscanf(indio_dev->name, "adis%u\n", &device_id);
+ ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+ if (ret != 1)
+ return -EINVAL;
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index dbf5e9936635..e5306b4e020e 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1390,6 +1390,14 @@ static int kmx61_probe(struct i2c_client *client,
}
}
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret < 0)
+ goto err_buffer_cleanup_mag;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
ret = iio_device_register(data->acc_indio_dev);
if (ret < 0) {
dev_err(&client->dev, "Failed to register acc iio device\n");
@@ -1402,18 +1410,8 @@ static int kmx61_probe(struct i2c_client *client,
goto err_iio_unregister_acc;
}
- ret = pm_runtime_set_active(&client->dev);
- if (ret < 0)
- goto err_iio_unregister_mag;
-
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
- pm_runtime_use_autosuspend(&client->dev);
-
return 0;
-err_iio_unregister_mag:
- iio_device_unregister(data->mag_indio_dev);
err_iio_unregister_acc:
iio_device_unregister(data->acc_indio_dev);
err_buffer_cleanup_mag:
@@ -1437,13 +1435,13 @@ static int kmx61_remove(struct i2c_client *client)
{
struct kmx61_data *data = i2c_get_clientdata(client);
+ iio_device_unregister(data->acc_indio_dev);
+ iio_device_unregister(data->mag_indio_dev);
+
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
- iio_device_unregister(data->acc_indio_dev);
- iio_device_unregister(data->mag_indio_dev);
-
if (client->irq > 0) {
iio_triggered_buffer_cleanup(data->acc_indio_dev);
iio_triggered_buffer_cleanup(data->mag_indio_dev);
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 0f6f63b20263..139ae916225f 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -193,7 +193,8 @@ void iio_buffer_init(struct iio_buffer *buffer)
INIT_LIST_HEAD(&buffer->buffer_list);
init_waitqueue_head(&buffer->pollq);
kref_init(&buffer->ref);
- buffer->watermark = 1;
+ if (!buffer->watermark)
+ buffer->watermark = 1;
}
EXPORT_SYMBOL(iio_buffer_init);
@@ -567,6 +568,22 @@ static void iio_buffer_deactivate_all(struct iio_dev *indio_dev)
iio_buffer_deactivate(buffer);
}
+static int iio_buffer_enable(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev)
+{
+ if (!buffer->access->enable)
+ return 0;
+ return buffer->access->enable(buffer, indio_dev);
+}
+
+static int iio_buffer_disable(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev)
+{
+ if (!buffer->access->disable)
+ return 0;
+ return buffer->access->disable(buffer, indio_dev);
+}
+
static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
struct iio_buffer *buffer)
{
@@ -610,6 +627,7 @@ static void iio_free_scan_mask(struct iio_dev *indio_dev,
struct iio_device_config {
unsigned int mode;
+ unsigned int watermark;
const unsigned long *scan_mask;
unsigned int scan_bytes;
bool scan_timestamp;
@@ -642,10 +660,14 @@ static int iio_verify_update(struct iio_dev *indio_dev,
if (buffer == remove_buffer)
continue;
modes &= buffer->access->modes;
+ config->watermark = min(config->watermark, buffer->watermark);
}
- if (insert_buffer)
+ if (insert_buffer) {
modes &= insert_buffer->access->modes;
+ config->watermark = min(config->watermark,
+ insert_buffer->watermark);
+ }
/* Definitely possible for devices to support both of these. */
if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
@@ -713,6 +735,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
static int iio_enable_buffers(struct iio_dev *indio_dev,
struct iio_device_config *config)
{
+ struct iio_buffer *buffer;
int ret;
indio_dev->active_scan_mask = config->scan_mask;
@@ -743,6 +766,16 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
}
}
+ if (indio_dev->info->hwfifo_set_watermark)
+ indio_dev->info->hwfifo_set_watermark(indio_dev,
+ config->watermark);
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_enable(buffer, indio_dev);
+ if (ret)
+ goto err_disable_buffers;
+ }
+
indio_dev->currentmode = config->mode;
if (indio_dev->setup_ops->postenable) {
@@ -750,12 +783,16 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
if (ret) {
dev_dbg(&indio_dev->dev,
"Buffer not started: postenable failed (%d)\n", ret);
- goto err_run_postdisable;
+ goto err_disable_buffers;
}
}
return 0;
+err_disable_buffers:
+ list_for_each_entry_continue_reverse(buffer, &indio_dev->buffer_list,
+ buffer_list)
+ iio_buffer_disable(buffer, indio_dev);
err_run_postdisable:
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable)
@@ -768,6 +805,7 @@ err_undo_config:
static int iio_disable_buffers(struct iio_dev *indio_dev)
{
+ struct iio_buffer *buffer;
int ret = 0;
int ret2;
@@ -788,6 +826,12 @@ static int iio_disable_buffers(struct iio_dev *indio_dev)
ret = ret2;
}
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret2 = iio_buffer_disable(buffer, indio_dev);
+ if (ret2 && !ret)
+ ret = ret2;
+ }
+
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable) {
@@ -974,9 +1018,6 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
}
buffer->watermark = val;
-
- if (indio_dev->info->hwfifo_set_watermark)
- indio_dev->info->hwfifo_set_watermark(indio_dev, val);
out:
mutex_unlock(&indio_dev->mlock);
@@ -991,6 +1032,8 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
iio_buffer_show_enable, iio_buffer_store_enable);
static DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR,
iio_buffer_show_watermark, iio_buffer_store_watermark);
+static struct device_attribute dev_attr_watermark_ro = __ATTR(watermark,
+ S_IRUGO, iio_buffer_show_watermark, NULL);
static struct attribute *iio_buffer_attrs[] = {
&dev_attr_length.attr,
@@ -1033,6 +1076,9 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
if (!buffer->access->set_length)
attr[0] = &dev_attr_length_ro.attr;
+ if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK)
+ attr[2] = &dev_attr_watermark_ro.attr;
+
if (buffer->attrs)
memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
sizeof(struct attribute *) * attrcount);
diff --git a/drivers/iio/industrialio-configfs.c b/drivers/iio/industrialio-configfs.c
new file mode 100644
index 000000000000..45ce2bc47180
--- /dev/null
+++ b/drivers/iio/industrialio-configfs.c
@@ -0,0 +1,51 @@
+/*
+ * Industrial I/O configfs bits
+ *
+ * Copyright (c) 2015 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 published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/configfs.h>
+
+static struct config_item_type iio_root_group_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+struct configfs_subsystem iio_configfs_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "iio",
+ .ci_type = &iio_root_group_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(iio_configfs_subsys.su_mutex),
+};
+EXPORT_SYMBOL(iio_configfs_subsys);
+
+static int __init iio_configfs_init(void)
+{
+ config_group_init(&iio_configfs_subsys.su_group);
+
+ return configfs_register_subsystem(&iio_configfs_subsys);
+}
+module_init(iio_configfs_init);
+
+static void __exit iio_configfs_exit(void)
+{
+ configfs_unregister_subsystem(&iio_configfs_subsys);
+}
+module_exit(iio_configfs_exit);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("Industrial I/O configfs support");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 159ede61f793..af7cc1e65656 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -433,16 +433,15 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
scale_db = true;
case IIO_VAL_INT_PLUS_MICRO:
if (vals[1] < 0)
- return sprintf(buf, "-%ld.%06u%s\n", abs(vals[0]),
- -vals[1],
- scale_db ? " dB" : "");
+ return sprintf(buf, "-%d.%06u%s\n", abs(vals[0]),
+ -vals[1], scale_db ? " dB" : "");
else
return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1],
scale_db ? " dB" : "");
case IIO_VAL_INT_PLUS_NANO:
if (vals[1] < 0)
- return sprintf(buf, "-%ld.%09u\n", abs(vals[0]),
- -vals[1]);
+ return sprintf(buf, "-%d.%09u\n", abs(vals[0]),
+ -vals[1]);
else
return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
case IIO_VAL_FRACTIONAL:
@@ -470,6 +469,7 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
return 0;
}
}
+EXPORT_SYMBOL_GPL(iio_format_value);
static ssize_t iio_read_channel_info(struct device *dev,
struct device_attribute *attr,
@@ -512,6 +512,12 @@ int iio_str_to_fixpoint(const char *str, int fract_mult,
int i = 0, f = 0;
bool integer_part = true, negative = false;
+ if (fract_mult == 0) {
+ *fract = 0;
+
+ return kstrtoint(str, 0, integer);
+ }
+
if (str[0] == '-') {
negative = true;
str++;
@@ -571,6 +577,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
if (indio_dev->info->write_raw_get_fmt)
switch (indio_dev->info->write_raw_get_fmt(indio_dev,
this_attr->c, this_attr->address)) {
+ case IIO_VAL_INT:
+ fract_mult = 0;
+ break;
case IIO_VAL_INT_PLUS_MICRO:
fract_mult = 100000;
break;
diff --git a/drivers/iio/industrialio-sw-trigger.c b/drivers/iio/industrialio-sw-trigger.c
new file mode 100644
index 000000000000..311f9fe5aa34
--- /dev/null
+++ b/drivers/iio/industrialio-sw-trigger.c
@@ -0,0 +1,184 @@
+/*
+ * The Industrial I/O core, software trigger functions
+ *
+ * Copyright (c) 2015 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 published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <linux/iio/sw_trigger.h>
+#include <linux/iio/configfs.h>
+#include <linux/configfs.h>
+
+static struct config_group *iio_triggers_group;
+static struct config_item_type iio_trigger_type_group_type;
+
+static struct config_item_type iio_triggers_group_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static LIST_HEAD(iio_trigger_types_list);
+static DEFINE_MUTEX(iio_trigger_types_lock);
+
+static
+struct iio_sw_trigger_type *__iio_find_sw_trigger_type(const char *name,
+ unsigned len)
+{
+ struct iio_sw_trigger_type *t = NULL, *iter;
+
+ list_for_each_entry(iter, &iio_trigger_types_list, list)
+ if (!strcmp(iter->name, name)) {
+ t = iter;
+ break;
+ }
+
+ return t;
+}
+
+int iio_register_sw_trigger_type(struct iio_sw_trigger_type *t)
+{
+ struct iio_sw_trigger_type *iter;
+ int ret = 0;
+
+ mutex_lock(&iio_trigger_types_lock);
+ iter = __iio_find_sw_trigger_type(t->name, strlen(t->name));
+ if (iter)
+ ret = -EBUSY;
+ else
+ list_add_tail(&t->list, &iio_trigger_types_list);
+ mutex_unlock(&iio_trigger_types_lock);
+
+ if (ret)
+ return ret;
+
+ t->group = configfs_register_default_group(iio_triggers_group, t->name,
+ &iio_trigger_type_group_type);
+ if (IS_ERR(t->group))
+ ret = PTR_ERR(t->group);
+
+ return ret;
+}
+EXPORT_SYMBOL(iio_register_sw_trigger_type);
+
+void iio_unregister_sw_trigger_type(struct iio_sw_trigger_type *t)
+{
+ struct iio_sw_trigger_type *iter;
+
+ mutex_lock(&iio_trigger_types_lock);
+ iter = __iio_find_sw_trigger_type(t->name, strlen(t->name));
+ if (iter)
+ list_del(&t->list);
+ mutex_unlock(&iio_trigger_types_lock);
+
+ configfs_unregister_default_group(t->group);
+}
+EXPORT_SYMBOL(iio_unregister_sw_trigger_type);
+
+static
+struct iio_sw_trigger_type *iio_get_sw_trigger_type(const char *name)
+{
+ struct iio_sw_trigger_type *t;
+
+ mutex_lock(&iio_trigger_types_lock);
+ t = __iio_find_sw_trigger_type(name, strlen(name));
+ if (t && !try_module_get(t->owner))
+ t = NULL;
+ mutex_unlock(&iio_trigger_types_lock);
+
+ return t;
+}
+
+struct iio_sw_trigger *iio_sw_trigger_create(const char *type, const char *name)
+{
+ struct iio_sw_trigger *t;
+ struct iio_sw_trigger_type *tt;
+
+ tt = iio_get_sw_trigger_type(type);
+ if (!tt) {
+ pr_err("Invalid trigger type: %s\n", type);
+ return ERR_PTR(-EINVAL);
+ }
+ t = tt->ops->probe(name);
+ if (IS_ERR(t))
+ goto out_module_put;
+
+ t->trigger_type = tt;
+
+ return t;
+out_module_put:
+ module_put(tt->owner);
+ return t;
+}
+EXPORT_SYMBOL(iio_sw_trigger_create);
+
+void iio_sw_trigger_destroy(struct iio_sw_trigger *t)
+{
+ struct iio_sw_trigger_type *tt = t->trigger_type;
+
+ tt->ops->remove(t);
+ module_put(tt->owner);
+}
+EXPORT_SYMBOL(iio_sw_trigger_destroy);
+
+static struct config_group *trigger_make_group(struct config_group *group,
+ const char *name)
+{
+ struct iio_sw_trigger *t;
+
+ t = iio_sw_trigger_create(group->cg_item.ci_name, name);
+ if (IS_ERR(t))
+ return ERR_CAST(t);
+
+ config_item_set_name(&t->group.cg_item, "%s", name);
+
+ return &t->group;
+}
+
+static void trigger_drop_group(struct config_group *group,
+ struct config_item *item)
+{
+ struct iio_sw_trigger *t = to_iio_sw_trigger(item);
+
+ iio_sw_trigger_destroy(t);
+ config_item_put(item);
+}
+
+static struct configfs_group_operations trigger_ops = {
+ .make_group = &trigger_make_group,
+ .drop_item = &trigger_drop_group,
+};
+
+static struct config_item_type iio_trigger_type_group_type = {
+ .ct_group_ops = &trigger_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static int __init iio_sw_trigger_init(void)
+{
+ iio_triggers_group =
+ configfs_register_default_group(&iio_configfs_subsys.su_group,
+ "triggers",
+ &iio_triggers_group_type);
+ if (IS_ERR(iio_triggers_group))
+ return PTR_ERR(iio_triggers_group);
+ return 0;
+}
+module_init(iio_sw_trigger_init);
+
+static void __exit iio_sw_trigger_exit(void)
+{
+ configfs_unregister_default_group(iio_triggers_group);
+}
+module_exit(iio_sw_trigger_exit);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("Industrial I/O software triggers support");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index c8bad3cf891d..80fbbfd76faf 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -61,12 +61,10 @@ EXPORT_SYMBOL_GPL(iio_map_array_register);
int iio_map_array_unregister(struct iio_dev *indio_dev)
{
int ret = -ENODEV;
- struct iio_map_internal *mapi;
- struct list_head *pos, *tmp;
+ struct iio_map_internal *mapi, *next;
mutex_lock(&iio_map_list_lock);
- list_for_each_safe(pos, tmp, &iio_map_list) {
- mapi = list_entry(pos, struct iio_map_internal, l);
+ list_for_each_entry_safe(mapi, next, &iio_map_list, l) {
if (indio_dev == mapi->indio_dev) {
list_del(&mapi->l);
kfree(mapi);
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 076bc46fad03..e56937c40a18 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -743,8 +743,10 @@ static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
{
int ret;
- if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX)
+ if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) {
+ dev_err(&als->pdev->dev, "invalid resistor value\n");
return -EINVAL;
+ };
ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
if (ret) {
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index 45f7bde02bbf..76a9e12b46bc 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -381,17 +381,23 @@ static int pa12203001_probe(struct i2c_client *client,
return ret;
ret = pm_runtime_set_active(&client->dev);
- if (ret < 0) {
- pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
- return ret;
- }
+ if (ret < 0)
+ goto out_err;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
PA12203001_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- return iio_device_register(indio_dev);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
+ return ret;
}
static int pa12203001_remove(struct i2c_client *client)
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 4b75bb0998b3..7de0f397194b 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -507,34 +507,28 @@ static int rpr0521_probe(struct i2c_client *client,
dev_err(&client->dev, "rpr0521 chip init failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret < 0)
- return ret;
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
- goto err_iio_unregister;
+ return ret;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- return 0;
-
-err_iio_unregister:
- iio_device_unregister(indio_dev);
- return ret;
+ return iio_device_register(indio_dev);
}
static int rpr0521_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
- iio_device_unregister(indio_dev);
rpr0521_poweroff(iio_priv(indio_dev));
return 0;
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 49dab3cb3e23..45bc2f742f46 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -20,14 +20,21 @@
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/iio/sysfs.h>
#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#define US5182D_REG_CFG0 0x00
#define US5182D_CFG0_ONESHOT_EN BIT(6)
#define US5182D_CFG0_SHUTDOWN_EN BIT(7)
#define US5182D_CFG0_WORD_ENABLE BIT(0)
+#define US5182D_CFG0_PROX BIT(3)
+#define US5182D_CFG0_PX_IRQ BIT(2)
#define US5182D_REG_CFG1 0x01
#define US5182D_CFG1_ALS_RES16 BIT(4)
@@ -39,6 +46,7 @@
#define US5182D_REG_CFG3 0x03
#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5))
+#define US5182D_CFG3_INT_SOURCE_PX BIT(3)
#define US5182D_REG_CFG4 0x10
@@ -53,6 +61,13 @@
#define US5182D_REG_AUTO_LDARK_GAIN 0x29
#define US5182D_REG_AUTO_HDARK_GAIN 0x2a
+/* Thresholds for events: px low (0x08-l, 0x09-h), px high (0x0a-l 0x0b-h) */
+#define US5182D_REG_PXL_TH 0x08
+#define US5182D_REG_PXH_TH 0x0a
+
+#define US5182D_REG_PXL_TH_DEFAULT 1000
+#define US5182D_REG_PXH_TH_DEFAULT 30000
+
#define US5182D_OPMODE_ALS 0x01
#define US5182D_OPMODE_PX 0x02
#define US5182D_OPMODE_SHIFT 4
@@ -81,6 +96,9 @@
#define US5182D_READ_BYTE 1
#define US5182D_READ_WORD 2
#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */
+#define US5182D_SLEEP_MS 3000 /* ms */
+#define US5182D_PXH_TH_DISABLE 0xffff
+#define US5182D_PXL_TH_DISABLE 0x0000
/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,
@@ -99,6 +117,11 @@ enum mode {
US5182D_PX_ONLY
};
+enum pmode {
+ US5182D_CONTINUOUS,
+ US5182D_ONESHOT
+};
+
struct us5182d_data {
struct i2c_client *client;
struct mutex lock;
@@ -111,7 +134,19 @@ struct us5182d_data {
u8 upper_dark_gain;
u16 *us5182d_dark_ths;
+ u16 px_low_th;
+ u16 px_high_th;
+
+ int rising_en;
+ int falling_en;
+
u8 opmode;
+ u8 power_mode;
+
+ bool als_enabled;
+ bool px_enabled;
+
+ bool default_continuous;
};
static IIO_CONST_ATTR(in_illuminance_scale_available,
@@ -130,16 +165,30 @@ static const struct {
u8 reg;
u8 val;
} us5182d_regvals[] = {
- {US5182D_REG_CFG0, (US5182D_CFG0_SHUTDOWN_EN |
- US5182D_CFG0_WORD_ENABLE)},
+ {US5182D_REG_CFG0, US5182D_CFG0_WORD_ENABLE},
{US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
{US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
US5182D_CFG2_PXGAIN_DEFAULT)},
- {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100},
- {US5182D_REG_MODE_STORE, US5182D_STORE_MODE},
+ {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100 |
+ US5182D_CFG3_INT_SOURCE_PX},
{US5182D_REG_CFG4, 0x00},
};
+static const struct iio_event_spec us5182d_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
static const struct iio_chan_spec us5182d_channels[] = {
{
.type = IIO_LIGHT,
@@ -149,40 +198,39 @@ static const struct iio_chan_spec us5182d_channels[] = {
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .event_spec = us5182d_events,
+ .num_event_specs = ARRAY_SIZE(us5182d_events),
}
};
-static int us5182d_get_als(struct us5182d_data *data)
+static int us5182d_oneshot_en(struct us5182d_data *data)
{
int ret;
- unsigned long result;
- ret = i2c_smbus_read_word_data(data->client,
- US5182D_REG_ADL);
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
if (ret < 0)
return ret;
- result = ret * data->ga / US5182D_GA_RESOLUTION;
- if (result > 0xffff)
- result = 0xffff;
+ /*
+ * In oneshot mode the chip will power itself down after taking the
+ * required measurement.
+ */
+ ret = ret | US5182D_CFG0_ONESHOT_EN;
- return result;
+ return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
}
static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
{
int ret;
+ if (mode == data->opmode)
+ return 0;
+
ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
if (ret < 0)
return ret;
- /*
- * In oneshot mode the chip will power itself down after taking the
- * required measurement.
- */
- ret = ret | US5182D_CFG0_ONESHOT_EN;
-
/* update mode */
ret = ret & ~US5182D_OPMODE_MASK;
ret = ret | (mode << US5182D_OPMODE_SHIFT);
@@ -196,9 +244,6 @@ static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
if (ret < 0)
return ret;
- if (mode == data->opmode)
- return 0;
-
ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,
US5182D_STORE_MODE);
if (ret < 0)
@@ -210,6 +255,177 @@ static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
return 0;
}
+static int us5182d_als_enable(struct us5182d_data *data)
+{
+ int ret;
+ u8 mode;
+
+ if (data->power_mode == US5182D_ONESHOT) {
+ ret = us5182d_set_opmode(data, US5182D_ALS_ONLY);
+ if (ret < 0)
+ return ret;
+ data->px_enabled = false;
+ }
+
+ if (data->als_enabled)
+ return 0;
+
+ mode = data->px_enabled ? US5182D_ALS_PX : US5182D_ALS_ONLY;
+
+ ret = us5182d_set_opmode(data, mode);
+ if (ret < 0)
+ return ret;
+
+ data->als_enabled = true;
+
+ return 0;
+}
+
+static int us5182d_px_enable(struct us5182d_data *data)
+{
+ int ret;
+ u8 mode;
+
+ if (data->power_mode == US5182D_ONESHOT) {
+ ret = us5182d_set_opmode(data, US5182D_PX_ONLY);
+ if (ret < 0)
+ return ret;
+ data->als_enabled = false;
+ }
+
+ if (data->px_enabled)
+ return 0;
+
+ mode = data->als_enabled ? US5182D_ALS_PX : US5182D_PX_ONLY;
+
+ ret = us5182d_set_opmode(data, mode);
+ if (ret < 0)
+ return ret;
+
+ data->px_enabled = true;
+
+ return 0;
+}
+
+static int us5182d_get_als(struct us5182d_data *data)
+{
+ int ret;
+ unsigned long result;
+
+ ret = us5182d_als_enable(data);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_word_data(data->client,
+ US5182D_REG_ADL);
+ if (ret < 0)
+ return ret;
+
+ result = ret * data->ga / US5182D_GA_RESOLUTION;
+ if (result > 0xffff)
+ result = 0xffff;
+
+ return result;
+}
+
+static int us5182d_get_px(struct us5182d_data *data)
+{
+ int ret;
+
+ ret = us5182d_px_enable(data);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_read_word_data(data->client,
+ US5182D_REG_PDL);
+}
+
+static int us5182d_shutdown_en(struct us5182d_data *data, u8 state)
+{
+ int ret;
+
+ if (data->power_mode == US5182D_ONESHOT)
+ return 0;
+
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
+ if (ret < 0)
+ return ret;
+
+ ret = ret & ~US5182D_CFG0_SHUTDOWN_EN;
+ ret = ret | state;
+
+ ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
+ if (ret < 0)
+ return ret;
+
+ if (state & US5182D_CFG0_SHUTDOWN_EN) {
+ data->als_enabled = false;
+ data->px_enabled = false;
+ }
+
+ return ret;
+}
+
+
+static int us5182d_set_power_state(struct us5182d_data *data, bool on)
+{
+ int ret;
+
+ if (data->power_mode == US5182D_ONESHOT)
+ return 0;
+
+ if (on) {
+ ret = pm_runtime_get_sync(&data->client->dev);
+ if (ret < 0)
+ pm_runtime_put_noidle(&data->client->dev);
+ } else {
+ pm_runtime_mark_last_busy(&data->client->dev);
+ ret = pm_runtime_put_autosuspend(&data->client->dev);
+ }
+
+ return ret;
+}
+
+static int us5182d_read_value(struct us5182d_data *data,
+ struct iio_chan_spec const *chan)
+{
+ int ret, value;
+
+ mutex_lock(&data->lock);
+
+ if (data->power_mode == US5182D_ONESHOT) {
+ ret = us5182d_oneshot_en(data);
+ if (ret < 0)
+ goto out_err;
+ }
+
+ ret = us5182d_set_power_state(data, true);
+ if (ret < 0)
+ goto out_err;
+
+ if (chan->type == IIO_LIGHT)
+ ret = us5182d_get_als(data);
+ else
+ ret = us5182d_get_px(data);
+ if (ret < 0)
+ goto out_poweroff;
+
+ value = ret;
+
+ ret = us5182d_set_power_state(data, false);
+ if (ret < 0)
+ goto out_err;
+
+ mutex_unlock(&data->lock);
+ return value;
+
+out_poweroff:
+ us5182d_set_power_state(data, false);
+out_err:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
static int us5182d_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -219,53 +435,21 @@ static int us5182d_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- switch (chan->type) {
- case IIO_LIGHT:
- mutex_lock(&data->lock);
- ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS);
- if (ret < 0)
- goto out_err;
-
- ret = us5182d_get_als(data);
- if (ret < 0)
- goto out_err;
- mutex_unlock(&data->lock);
- *val = ret;
- return IIO_VAL_INT;
- case IIO_PROXIMITY:
- mutex_lock(&data->lock);
- ret = us5182d_set_opmode(data, US5182D_OPMODE_PX);
- if (ret < 0)
- goto out_err;
-
- ret = i2c_smbus_read_word_data(data->client,
- US5182D_REG_PDL);
- if (ret < 0)
- goto out_err;
- mutex_unlock(&data->lock);
- *val = ret;
- return IIO_VAL_INT;
- default:
- return -EINVAL;
- }
-
+ ret = us5182d_read_value(data, chan);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
if (ret < 0)
return ret;
-
*val = 0;
*val2 = us5182d_scales[ret & US5182D_AGAIN_MASK];
-
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
-
- return -EINVAL;
-out_err:
- mutex_unlock(&data->lock);
- return ret;
}
/**
@@ -343,11 +527,201 @@ static int us5182d_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int us5182d_setup_prox(struct iio_dev *indio_dev,
+ enum iio_event_direction dir, u16 val)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+
+ if (dir == IIO_EV_DIR_FALLING)
+ return i2c_smbus_write_word_data(data->client,
+ US5182D_REG_PXL_TH, val);
+ else if (dir == IIO_EV_DIR_RISING)
+ return i2c_smbus_write_word_data(data->client,
+ US5182D_REG_PXH_TH, val);
+
+ return 0;
+}
+
+static int us5182d_read_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info, int *val,
+ int *val2)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ mutex_lock(&data->lock);
+ *val = data->px_high_th;
+ mutex_unlock(&data->lock);
+ break;
+ case IIO_EV_DIR_FALLING:
+ mutex_lock(&data->lock);
+ *val = data->px_low_th;
+ mutex_unlock(&data->lock);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return IIO_VAL_INT;
+}
+
+static int us5182d_write_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info, int val,
+ int val2)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (val < 0 || val > USHRT_MAX || val2 != 0)
+ return -EINVAL;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ mutex_lock(&data->lock);
+ if (data->rising_en) {
+ ret = us5182d_setup_prox(indio_dev, dir, val);
+ if (ret < 0)
+ goto err;
+ }
+ data->px_high_th = val;
+ mutex_unlock(&data->lock);
+ break;
+ case IIO_EV_DIR_FALLING:
+ mutex_lock(&data->lock);
+ if (data->falling_en) {
+ ret = us5182d_setup_prox(indio_dev, dir, val);
+ if (ret < 0)
+ goto err;
+ }
+ data->px_low_th = val;
+ mutex_unlock(&data->lock);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+err:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int us5182d_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ mutex_lock(&data->lock);
+ ret = data->rising_en;
+ mutex_unlock(&data->lock);
+ break;
+ case IIO_EV_DIR_FALLING:
+ mutex_lock(&data->lock);
+ ret = data->falling_en;
+ mutex_unlock(&data->lock);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int us5182d_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int ret;
+ u16 new_th;
+
+ mutex_lock(&data->lock);
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ if (data->rising_en == state) {
+ mutex_unlock(&data->lock);
+ return 0;
+ }
+ new_th = US5182D_PXH_TH_DISABLE;
+ if (state) {
+ data->power_mode = US5182D_CONTINUOUS;
+ ret = us5182d_set_power_state(data, true);
+ if (ret < 0)
+ goto err;
+ ret = us5182d_px_enable(data);
+ if (ret < 0)
+ goto err_poweroff;
+ new_th = data->px_high_th;
+ }
+ ret = us5182d_setup_prox(indio_dev, dir, new_th);
+ if (ret < 0)
+ goto err_poweroff;
+ data->rising_en = state;
+ break;
+ case IIO_EV_DIR_FALLING:
+ if (data->falling_en == state) {
+ mutex_unlock(&data->lock);
+ return 0;
+ }
+ new_th = US5182D_PXL_TH_DISABLE;
+ if (state) {
+ data->power_mode = US5182D_CONTINUOUS;
+ ret = us5182d_set_power_state(data, true);
+ if (ret < 0)
+ goto err;
+ ret = us5182d_px_enable(data);
+ if (ret < 0)
+ goto err_poweroff;
+ new_th = data->px_low_th;
+ }
+ ret = us5182d_setup_prox(indio_dev, dir, new_th);
+ if (ret < 0)
+ goto err_poweroff;
+ data->falling_en = state;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!state) {
+ ret = us5182d_set_power_state(data, false);
+ if (ret < 0)
+ goto err;
+ }
+
+ if (!data->falling_en && !data->rising_en && !data->default_continuous)
+ data->power_mode = US5182D_ONESHOT;
+
+ mutex_unlock(&data->lock);
+ return 0;
+
+err_poweroff:
+ if (state)
+ us5182d_set_power_state(data, false);
+err:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
static const struct iio_info us5182d_info = {
.driver_module = THIS_MODULE,
.read_raw = us5182d_read_raw,
.write_raw = us5182d_write_raw,
.attrs = &us5182d_attr_group,
+ .read_event_value = &us5182d_read_thresh,
+ .write_event_value = &us5182d_write_thresh,
+ .read_event_config = &us5182d_read_event_config,
+ .write_event_config = &us5182d_write_event_config,
};
static int us5182d_reset(struct iio_dev *indio_dev)
@@ -368,6 +742,10 @@ static int us5182d_init(struct iio_dev *indio_dev)
return ret;
data->opmode = 0;
+ data->power_mode = US5182D_CONTINUOUS;
+ data->px_low_th = US5182D_REG_PXL_TH_DEFAULT;
+ data->px_high_th = US5182D_REG_PXH_TH_DEFAULT;
+
for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
ret = i2c_smbus_write_byte_data(data->client,
us5182d_regvals[i].reg,
@@ -376,7 +754,17 @@ static int us5182d_init(struct iio_dev *indio_dev)
return ret;
}
- return 0;
+ data->als_enabled = true;
+ data->px_enabled = true;
+
+ if (!data->default_continuous) {
+ ret = us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
+ if (ret < 0)
+ return ret;
+ data->power_mode = US5182D_ONESHOT;
+ }
+
+ return ret;
}
static void us5182d_get_platform_data(struct iio_dev *indio_dev)
@@ -399,6 +787,8 @@ static void us5182d_get_platform_data(struct iio_dev *indio_dev)
"upisemi,lower-dark-gain",
&data->lower_dark_gain))
data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;
+ data->default_continuous = device_property_read_bool(&data->client->dev,
+ "upisemi,continuous");
}
static int us5182d_dark_gain_config(struct iio_dev *indio_dev)
@@ -426,6 +816,33 @@ static int us5182d_dark_gain_config(struct iio_dev *indio_dev)
US5182D_REG_DARK_AUTO_EN_DEFAULT);
}
+static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct us5182d_data *data = iio_priv(indio_dev);
+ enum iio_event_direction dir;
+ int ret;
+ u64 ev;
+
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
+ return IRQ_HANDLED;
+ }
+
+ dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir);
+
+ iio_push_event(indio_dev, ev, iio_get_time_ns());
+
+ ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0,
+ ret & ~US5182D_CFG0_PX_IRQ);
+ if (ret < 0)
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
+
+ return IRQ_HANDLED;
+}
+
static int us5182d_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -457,6 +874,16 @@ static int us5182d_probe(struct i2c_client *client,
return (ret < 0) ? ret : -ENODEV;
}
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ us5182d_irq_thread_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "us5182d-irq", indio_dev);
+ if (ret < 0)
+ return ret;
+ } else
+ dev_warn(&client->dev, "no valid irq found\n");
+
us5182d_get_platform_data(indio_dev);
ret = us5182d_init(indio_dev);
if (ret < 0)
@@ -464,18 +891,73 @@ static int us5182d_probe(struct i2c_client *client,
ret = us5182d_dark_gain_config(indio_dev);
if (ret < 0)
- return ret;
+ goto out_err;
+
+ if (data->default_continuous) {
+ pm_runtime_set_active(&client->dev);
+ if (ret < 0)
+ goto out_err;
+ }
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev,
+ US5182D_SLEEP_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
+ return ret;
- return iio_device_register(indio_dev);
}
static int us5182d_remove(struct i2c_client *client)
{
+ struct us5182d_data *data = iio_priv(i2c_get_clientdata(client));
+
iio_device_unregister(i2c_get_clientdata(client));
- return i2c_smbus_write_byte_data(client, US5182D_REG_CFG0,
- US5182D_CFG0_SHUTDOWN_EN);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
+}
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
+static int us5182d_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct us5182d_data *data = iio_priv(indio_dev);
+
+ if (data->power_mode == US5182D_CONTINUOUS)
+ return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
+
+ return 0;
}
+static int us5182d_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct us5182d_data *data = iio_priv(indio_dev);
+
+ if (data->power_mode == US5182D_CONTINUOUS)
+ return us5182d_shutdown_en(data,
+ ~US5182D_CFG0_SHUTDOWN_EN & 0xff);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops us5182d_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(us5182d_suspend, us5182d_resume)
+ SET_RUNTIME_PM_OPS(us5182d_suspend, us5182d_resume, NULL)
+};
+
static const struct acpi_device_id us5182d_acpi_match[] = {
{ "USD5182", 0},
{}
@@ -493,6 +975,7 @@ MODULE_DEVICE_TABLE(i2c, us5182d_id);
static struct i2c_driver us5182d_driver = {
.driver = {
.name = US5182D_DRV_NAME,
+ .pm = &us5182d_pm_ops,
.acpi_match_table = ACPI_PTR(us5182d_acpi_match),
},
.probe = us5182d_probe,
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index 1615b23d7b2a..ffcb75ea64fb 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -928,27 +928,24 @@ static int bmc150_magn_probe(struct i2c_client *client,
goto err_free_irq;
}
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "unable to register iio device\n");
- goto err_buffer_cleanup;
- }
-
ret = pm_runtime_set_active(&client->dev);
if (ret)
- goto err_iio_unregister;
+ goto err_buffer_cleanup;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
BMC150_MAGN_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto err_buffer_cleanup;
+ }
+ dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
return 0;
-err_iio_unregister:
- iio_device_unregister(indio_dev);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_free_irq:
@@ -967,11 +964,12 @@ static int bmc150_magn_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct bmc150_magn_data *data = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
+
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
- iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (client->irq > 0)
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index e544fcfd5ced..93e29fb67fa0 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -13,7 +13,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * TODO: runtime pm, interrupt mode, and signal strength reporting
+ * TODO: interrupt mode, and signal strength reporting
*/
#include <linux/err.h>
@@ -21,6 +21,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
@@ -35,8 +36,11 @@
#define LIDAR_REG_STATUS_INVALID BIT(3)
#define LIDAR_REG_STATUS_READY BIT(0)
-#define LIDAR_REG_DATA_HBYTE 0x0f
-#define LIDAR_REG_DATA_LBYTE 0x10
+#define LIDAR_REG_DATA_HBYTE 0x0f
+#define LIDAR_REG_DATA_LBYTE 0x10
+#define LIDAR_REG_DATA_WORD_READ BIT(7)
+
+#define LIDAR_REG_PWR_CONTROL 0x65
#define LIDAR_DRV_NAME "lidar"
@@ -44,6 +48,9 @@ struct lidar_data {
struct iio_dev *indio_dev;
struct i2c_client *client;
+ int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
+ int i2c_enabled;
+
u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
};
@@ -62,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
};
-static int lidar_read_byte(struct lidar_data *data, int reg)
+static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
+{
+ struct i2c_client *client = data->client;
+ struct i2c_msg msg[2];
+ int ret;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = client->flags | I2C_M_STOP;
+ msg[0].len = 1;
+ msg[0].buf = (char *) &reg;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = client->flags | I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = (char *) val;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+
+ return (ret == 2) ? 0 : ret;
+}
+
+static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
{
struct i2c_client *client = data->client;
int ret;
@@ -72,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg)
* so in turn i2c_smbus_read_byte_data cannot be used
*/
- ret = i2c_smbus_write_byte(client, reg);
- if (ret < 0) {
- dev_err(&client->dev, "cannot write addr value");
- return ret;
+ while (len--) {
+ ret = i2c_smbus_write_byte(client, reg++);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot write addr value");
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot read data value");
+ return ret;
+ }
+
+ *(val++) = ret;
}
- ret = i2c_smbus_read_byte(client);
+ return 0;
+}
+
+static int lidar_read_byte(struct lidar_data *data, u8 reg)
+{
+ int ret;
+ u8 val;
+
+ ret = data->xfer(data, reg, &val, 1);
if (ret < 0)
- dev_err(&client->dev, "cannot read data value");
+ return ret;
- return ret;
+ return val;
}
static inline int lidar_write_control(struct lidar_data *data, int val)
@@ -90,24 +136,22 @@ static inline int lidar_write_control(struct lidar_data *data, int val)
return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val);
}
-static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
+static inline int lidar_write_power(struct lidar_data *data, int val)
{
- int ret;
- int val;
-
- ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
- if (ret < 0)
- return ret;
- val = ret << 8;
+ return i2c_smbus_write_byte_data(data->client,
+ LIDAR_REG_PWR_CONTROL, val);
+}
- ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
- if (ret < 0)
- return ret;
+static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
+{
+ int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
+ (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
+ (u8 *) reg, 2);
- val |= ret;
- *reg = val;
+ if (!ret)
+ *reg = be16_to_cpu(*reg);
- return 0;
+ return ret;
}
static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
@@ -116,6 +160,8 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
int tries = 10;
int ret;
+ pm_runtime_get_sync(&client->dev);
+
/* start sample */
ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
if (ret < 0) {
@@ -144,6 +190,8 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
}
ret = -EIO;
}
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
return ret;
}
@@ -221,6 +269,16 @@ static int lidar_probe(struct i2c_client *client,
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
+ data = iio_priv(indio_dev);
+
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ data->xfer = lidar_i2c_xfer;
+ data->i2c_enabled = 1;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
+ data->xfer = lidar_smbus_xfer;
+ else
+ return -ENOTSUPP;
indio_dev->info = &lidar_info;
indio_dev->name = LIDAR_DRV_NAME;
@@ -228,7 +286,6 @@ static int lidar_probe(struct i2c_client *client,
indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
- data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
@@ -243,6 +300,17 @@ static int lidar_probe(struct i2c_client *client,
if (ret)
goto error_unreg_buffer;
+ pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret)
+ goto error_unreg_buffer;
+ pm_runtime_enable(&client->dev);
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_idle(&client->dev);
+
return 0;
error_unreg_buffer:
@@ -258,6 +326,9 @@ static int lidar_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
return 0;
}
@@ -273,10 +344,38 @@ static const struct of_device_id lidar_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, lidar_dt_ids);
+#ifdef CONFIG_PM
+static int lidar_pm_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct lidar_data *data = iio_priv(indio_dev);
+
+ return lidar_write_power(data, 0x0f);
+}
+
+static int lidar_pm_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct lidar_data *data = iio_priv(indio_dev);
+ int ret = lidar_write_power(data, 0);
+
+ /* regulator and FPGA needs settling time */
+ usleep_range(15000, 20000);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops lidar_pm_ops = {
+ SET_RUNTIME_PM_OPS(lidar_pm_runtime_suspend,
+ lidar_pm_runtime_resume, NULL)
+};
+
static struct i2c_driver lidar_driver = {
.driver = {
.name = LIDAR_DRV_NAME,
.of_match_table = of_match_ptr(lidar_dt_ids),
+ .pm = &lidar_pm_ops,
},
.probe = lidar_probe,
.remove = lidar_remove,
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 79996123a71b..519e6772f6f5 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -5,6 +5,16 @@
menu "Triggers - standalone"
+config IIO_HRTIMER_TRIGGER
+ tristate "High resolution timer trigger"
+ depends on IIO_SW_TRIGGER
+ help
+ Provides a frequency based IIO trigger using high resolution
+ timers as interrupt source.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-trig-hrtimer.
+
config IIO_INTERRUPT_TRIGGER
tristate "Generic interrupt trigger"
help
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index 0694daecaf22..fe06eb564367 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -3,5 +3,7 @@
#
# When adding new entries keep the list in alphabetical order
+
+obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
new file mode 100644
index 000000000000..5e6d451febeb
--- /dev/null
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -0,0 +1,193 @@
+/**
+ * The industrial I/O periodic hrtimer trigger driver
+ *
+ * Copyright (C) Intuitive Aerial AB
+ * Written by Marten Svanfeldt, marten@intuitiveaerial.com
+ * Copyright (C) 2012, Analog Device Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (C) 2015, 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 published by
+ * the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/hrtimer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/sw_trigger.h>
+
+/* default sampling frequency - 100Hz */
+#define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100
+
+struct iio_hrtimer_info {
+ struct iio_sw_trigger swt;
+ struct hrtimer timer;
+ unsigned long sampling_frequency;
+ ktime_t period;
+};
+
+static struct config_item_type iio_hrtimer_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static
+ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_trigger *trig = to_iio_trigger(dev);
+ struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", info->sampling_frequency);
+}
+
+static
+ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_trigger *trig = to_iio_trigger(dev);
+ struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (!val || val > NSEC_PER_SEC)
+ return -EINVAL;
+
+ info->sampling_frequency = val;
+ info->period = ktime_set(0, NSEC_PER_SEC / val);
+
+ return len;
+}
+
+static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR,
+ iio_hrtimer_show_sampling_frequency,
+ iio_hrtimer_store_sampling_frequency);
+
+static struct attribute *iio_hrtimer_attrs[] = {
+ &dev_attr_sampling_frequency.attr,
+ NULL
+};
+
+static const struct attribute_group iio_hrtimer_attr_group = {
+ .attrs = iio_hrtimer_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_attr_groups[] = {
+ &iio_hrtimer_attr_group,
+ NULL
+};
+
+static enum hrtimer_restart iio_hrtimer_trig_handler(struct hrtimer *timer)
+{
+ struct iio_hrtimer_info *info;
+
+ info = container_of(timer, struct iio_hrtimer_info, timer);
+
+ hrtimer_forward_now(timer, info->period);
+ iio_trigger_poll(info->swt.trigger);
+
+ return HRTIMER_RESTART;
+}
+
+static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_hrtimer_info *trig_info;
+
+ trig_info = iio_trigger_get_drvdata(trig);
+
+ if (state)
+ hrtimer_start(&trig_info->timer, trig_info->period,
+ HRTIMER_MODE_REL);
+ else
+ hrtimer_cancel(&trig_info->timer);
+
+ return 0;
+}
+
+static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = iio_trig_hrtimer_set_state,
+};
+
+static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
+{
+ struct iio_hrtimer_info *trig_info;
+ int ret;
+
+ trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
+ if (!trig_info)
+ return ERR_PTR(-ENOMEM);
+
+ trig_info->swt.trigger = iio_trigger_alloc("%s", name);
+ if (!trig_info->swt.trigger) {
+ ret = -ENOMEM;
+ goto err_free_trig_info;
+ }
+
+ iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
+ trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops;
+ trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups;
+
+ hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ trig_info->timer.function = iio_hrtimer_trig_handler;
+
+ trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
+ trig_info->period = ktime_set(0, NSEC_PER_SEC /
+ trig_info->sampling_frequency);
+
+ ret = iio_trigger_register(trig_info->swt.trigger);
+ if (ret)
+ goto err_free_trigger;
+
+ iio_swt_group_init_type_name(&trig_info->swt, name, &iio_hrtimer_type);
+ return &trig_info->swt;
+err_free_trigger:
+ iio_trigger_free(trig_info->swt.trigger);
+err_free_trig_info:
+ kfree(trig_info);
+
+ return ERR_PTR(ret);
+}
+
+static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
+{
+ struct iio_hrtimer_info *trig_info;
+
+ trig_info = iio_trigger_get_drvdata(swt->trigger);
+
+ iio_trigger_unregister(swt->trigger);
+
+ /* cancel the timer after unreg to make sure no one rearms it */
+ hrtimer_cancel(&trig_info->timer);
+ iio_trigger_free(swt->trigger);
+ kfree(trig_info);
+
+ return 0;
+}
+
+static const struct iio_sw_trigger_ops iio_trig_hrtimer_ops = {
+ .probe = iio_trig_hrtimer_probe,
+ .remove = iio_trig_hrtimer_remove,
+};
+
+static struct iio_sw_trigger_type iio_trig_hrtimer = {
+ .name = "hrtimer",
+ .owner = THIS_MODULE,
+ .ops = &iio_trig_hrtimer_ops,
+};
+
+module_iio_sw_trigger_driver(iio_trig_hrtimer);
+
+MODULE_AUTHOR("Marten Svanfeldt <marten@intuitiveaerial.com>");
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("Periodic hrtimer trigger for the IIO subsystem");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index c9cffced00ca..326d07d823a5 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -449,7 +449,7 @@ static void act_open_req_arp_failure(void *handle, struct sk_buff *skb)
{
struct c4iw_ep *ep = handle;
- printk(KERN_ERR MOD "ARP failure duing connect\n");
+ printk(KERN_ERR MOD "ARP failure during connect\n");
kfree_skb(skb);
connect_reply_upcall(ep, -EHOSTUNREACH);
state_set(&ep->com, DEAD);
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 3dfd287256d6..92ddae101ecc 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -756,7 +756,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
int uninitialized_var(index);
int uninitialized_var(inlen);
int cqe_size;
- int irqn;
+ unsigned int irqn;
int eqn;
int err;
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 8a51c3b5d657..468c5e132563 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -350,7 +350,7 @@ isert_create_device_ib_res(struct isert_device *device)
dev_attr = &device->dev_attr;
ret = isert_query_device(device->ib_device, dev_attr);
if (ret)
- return ret;
+ goto out;
/* asign function handlers */
if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS &&
@@ -366,7 +366,7 @@ isert_create_device_ib_res(struct isert_device *device)
ret = isert_alloc_comps(device, dev_attr);
if (ret)
- return ret;
+ goto out;
device->pd = ib_alloc_pd(device->ib_device);
if (IS_ERR(device->pd)) {
@@ -384,6 +384,9 @@ isert_create_device_ib_res(struct isert_device *device)
out_cq:
isert_free_comps(device);
+out:
+ if (ret > 0)
+ ret = -EINVAL;
return ret;
}
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 2e2fe818ca9f..bc5470c43d26 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -2370,31 +2370,6 @@ static void srpt_release_channel_work(struct work_struct *w)
kfree(ch);
}
-static struct srpt_node_acl *__srpt_lookup_acl(struct srpt_port *sport,
- u8 i_port_id[16])
-{
- struct srpt_node_acl *nacl;
-
- list_for_each_entry(nacl, &sport->port_acl_list, list)
- if (memcmp(nacl->i_port_id, i_port_id,
- sizeof(nacl->i_port_id)) == 0)
- return nacl;
-
- return NULL;
-}
-
-static struct srpt_node_acl *srpt_lookup_acl(struct srpt_port *sport,
- u8 i_port_id[16])
-{
- struct srpt_node_acl *nacl;
-
- spin_lock_irq(&sport->port_acl_lock);
- nacl = __srpt_lookup_acl(sport, i_port_id);
- spin_unlock_irq(&sport->port_acl_lock);
-
- return nacl;
-}
-
/**
* srpt_cm_req_recv() - Process the event IB_CM_REQ_RECEIVED.
*
@@ -2412,10 +2387,10 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
struct srp_login_rej *rej;
struct ib_cm_rep_param *rep_param;
struct srpt_rdma_ch *ch, *tmp_ch;
- struct srpt_node_acl *nacl;
+ struct se_node_acl *se_acl;
u32 it_iu_len;
- int i;
- int ret = 0;
+ int i, ret = 0;
+ unsigned char *p;
WARN_ON_ONCE(irqs_disabled());
@@ -2565,33 +2540,47 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
" RTR failed (error code = %d)\n", ret);
goto destroy_ib;
}
+
/*
- * Use the initator port identifier as the session name.
+ * Use the initator port identifier as the session name, when
+ * checking against se_node_acl->initiatorname[] this can be
+ * with or without preceeding '0x'.
*/
snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx",
be64_to_cpu(*(__be64 *)ch->i_port_id),
be64_to_cpu(*(__be64 *)(ch->i_port_id + 8)));
pr_debug("registering session %s\n", ch->sess_name);
+ p = &ch->sess_name[0];
- nacl = srpt_lookup_acl(sport, ch->i_port_id);
- if (!nacl) {
- pr_info("Rejected login because no ACL has been"
- " configured yet for initiator %s.\n", ch->sess_name);
+ ch->sess = transport_init_session(TARGET_PROT_NORMAL);
+ if (IS_ERR(ch->sess)) {
rej->reason = cpu_to_be32(
- SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
+ SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+ pr_debug("Failed to create session\n");
goto destroy_ib;
}
- ch->sess = transport_init_session(TARGET_PROT_NORMAL);
- if (IS_ERR(ch->sess)) {
+try_again:
+ se_acl = core_tpg_get_initiator_node_acl(&sport->port_tpg_1, p);
+ if (!se_acl) {
+ pr_info("Rejected login because no ACL has been"
+ " configured yet for initiator %s.\n", ch->sess_name);
+ /*
+ * XXX: Hack to retry of ch->i_port_id without leading '0x'
+ */
+ if (p == &ch->sess_name[0]) {
+ p += 2;
+ goto try_again;
+ }
rej->reason = cpu_to_be32(
- SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
- pr_debug("Failed to create session\n");
- goto deregister_session;
+ SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
+ transport_free_session(ch->sess);
+ goto destroy_ib;
}
- ch->sess->se_node_acl = &nacl->nacl;
- transport_register_session(&sport->port_tpg_1, &nacl->nacl, ch->sess, ch);
+ ch->sess->se_node_acl = se_acl;
+
+ transport_register_session(&sport->port_tpg_1, se_acl, ch->sess, ch);
pr_debug("Establish connection sess=%p name=%s cm_id=%p\n", ch->sess,
ch->sess_name, ch->cm_id);
@@ -2635,8 +2624,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
release_channel:
srpt_set_ch_state(ch, CH_RELEASING);
transport_deregister_session_configfs(ch->sess);
-
-deregister_session:
transport_deregister_session(ch->sess);
ch->sess = NULL;
@@ -3273,8 +3260,6 @@ static void srpt_add_one(struct ib_device *device)
sport->port_attrib.srp_max_rsp_size = DEFAULT_MAX_RSP_SIZE;
sport->port_attrib.srp_sq_size = DEF_SRPT_SQ_SIZE;
INIT_WORK(&sport->work, srpt_refresh_port_work);
- INIT_LIST_HEAD(&sport->port_acl_list);
- spin_lock_init(&sport->port_acl_lock);
if (srpt_refresh_port(sport)) {
pr_err("MAD registration failed for %s-%d.\n",
@@ -3508,42 +3493,15 @@ out:
*/
static int srpt_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
{
- struct srpt_port *sport =
- container_of(se_nacl->se_tpg, struct srpt_port, port_tpg_1);
- struct srpt_node_acl *nacl =
- container_of(se_nacl, struct srpt_node_acl, nacl);
u8 i_port_id[16];
if (srpt_parse_i_port_id(i_port_id, name) < 0) {
pr_err("invalid initiator port ID %s\n", name);
return -EINVAL;
}
-
- memcpy(&nacl->i_port_id[0], &i_port_id[0], 16);
- nacl->sport = sport;
-
- spin_lock_irq(&sport->port_acl_lock);
- list_add_tail(&nacl->list, &sport->port_acl_list);
- spin_unlock_irq(&sport->port_acl_lock);
-
return 0;
}
-/*
- * configfs callback function invoked for
- * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id
- */
-static void srpt_cleanup_nodeacl(struct se_node_acl *se_nacl)
-{
- struct srpt_node_acl *nacl =
- container_of(se_nacl, struct srpt_node_acl, nacl);
- struct srpt_port *sport = nacl->sport;
-
- spin_lock_irq(&sport->port_acl_lock);
- list_del(&nacl->list);
- spin_unlock_irq(&sport->port_acl_lock);
-}
-
static ssize_t srpt_tpg_attrib_srp_max_rdma_size_show(struct config_item *item,
char *page)
{
@@ -3820,7 +3778,6 @@ static const struct target_core_fabric_ops srpt_template = {
.fabric_make_tpg = srpt_make_tpg,
.fabric_drop_tpg = srpt_drop_tpg,
.fabric_init_nodeacl = srpt_init_nodeacl,
- .fabric_cleanup_nodeacl = srpt_cleanup_nodeacl,
.tfc_wwn_attrs = srpt_wwn_attrs,
.tfc_tpg_base_attrs = srpt_tpg_attrs,
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h
index 5faad8acd789..5366e0a9fd6d 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.h
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.h
@@ -364,11 +364,9 @@ struct srpt_port {
u16 sm_lid;
u16 lid;
union ib_gid gid;
- spinlock_t port_acl_lock;
struct work_struct work;
struct se_portal_group port_tpg_1;
struct se_wwn port_wwn;
- struct list_head port_acl_list;
struct srpt_port_attrib port_attrib;
};
@@ -409,15 +407,9 @@ struct srpt_device {
/**
* struct srpt_node_acl - Per-initiator ACL data (managed via configfs).
* @nacl: Target core node ACL information.
- * @i_port_id: 128-bit SRP initiator port ID.
- * @sport: port information.
- * @list: Element of the per-HCA ACL list.
*/
struct srpt_node_acl {
struct se_node_acl nacl;
- u8 i_port_id[16];
- struct srpt_port *sport;
- struct list_head list;
};
#endif /* IB_SRPT_H */
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index bef317ff7352..b9f01bd1b7ef 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -96,7 +96,7 @@ struct gpio_keys_drvdata {
* Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type.
*/
-static inline int get_n_events_by_type(int type)
+static int get_n_events_by_type(int type)
{
BUG_ON(type != EV_SW && type != EV_KEY);
@@ -104,6 +104,22 @@ static inline int get_n_events_by_type(int type)
}
/**
+ * get_bm_events_by_type() - returns bitmap of supported events per @type
+ * @input: input device from which bitmap is retrieved
+ * @type: type of button (%EV_KEY, %EV_SW)
+ *
+ * Return value of this function can be used to allocate bitmap
+ * large enough to hold all bits for given type.
+ */
+static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
+ int type)
+{
+ BUG_ON(type != EV_SW && type != EV_KEY);
+
+ return (type == EV_KEY) ? dev->keybit : dev->swbit;
+}
+
+/**
* gpio_keys_disable_button() - disables given GPIO button
* @bdata: button data for button to be disabled
*
@@ -213,6 +229,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
const char *buf, unsigned int type)
{
int n_events = get_n_events_by_type(type);
+ const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
unsigned long *bits;
ssize_t error;
int i;
@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
goto out;
/* First validate */
+ if (!bitmap_subset(bits, bitmap, n_events)) {
+ error = -EINVAL;
+ goto out;
+ }
+
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
@@ -239,11 +261,6 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
}
}
- if (i == ddata->pdata->nbuttons) {
- error = -EINVAL;
- goto out;
- }
-
mutex_lock(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) {
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 7502e46165fa..e0d72c8c01e4 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data)
"pressed" : "released");
#else
key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
- if (key < 0) {
- printk(KERN_WARNING
- "omap-keypad: Spurious key event %d-%d\n",
- col, row);
- /* We scan again after a couple of seconds */
- spurious = 1;
- continue;
- }
if (!(kp_cur_group == (key & GROUP_MASK) ||
kp_cur_group == -1))
@@ -292,8 +284,8 @@ static int omap_kp_probe(struct platform_device *pdev)
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
/* get the irq and init timer*/
- tasklet_enable(&kp_tasklet);
kp_tasklet.data = (unsigned long) omap_kp;
+ tasklet_enable(&kp_tasklet);
ret = device_create_file(&pdev->dev, &dev_attr_enable);
if (ret < 0)
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index 1d0e61d7c131..b0d445390ee4 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -147,7 +147,7 @@ struct bma150_data {
* are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance.
*/
-static struct bma150_cfg default_cfg = {
+static const struct bma150_cfg default_cfg = {
.any_motion_int = 1,
.hg_int = 1,
.lg_int = 1,
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index 8eb697db82d0..bb863e062b03 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input);
schedule_delayed_work(&onkey->work, 0);
- dev_dbg(onkey->dev, "KEY_POWER pressed.\n");
+ dev_dbg(onkey->dev, "KEY_POWER long press.\n");
} else {
- input_report_key(onkey->input, KEY_SLEEP, 1);
+ input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input);
- input_report_key(onkey->input, KEY_SLEEP, 0);
+ input_report_key(onkey->input, KEY_POWER, 0);
input_sync(onkey->input);
- dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n");
+ dev_dbg(onkey->dev, "KEY_POWER short press.\n");
}
return IRQ_HANDLED;
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 6f997aa49183..4a5afc7fe96e 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = {
.shutdown = sparcspkr_shutdown,
};
+static struct platform_driver * const drivers[] = {
+ &bbc_beep_driver,
+ &grover_beep_driver,
+};
+
static int __init sparcspkr_init(void)
{
- int err = platform_driver_register(&bbc_beep_driver);
-
- if (!err) {
- err = platform_driver_register(&grover_beep_driver);
- if (err)
- platform_driver_unregister(&bbc_beep_driver);
- }
-
- return err;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit sparcspkr_exit(void)
{
- platform_driver_unregister(&bbc_beep_driver);
- platform_driver_unregister(&grover_beep_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(sparcspkr_init);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 5adbcedcb81c..4eb9e4d94f46 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev)
{
struct input_dev *dev = udev->dev;
- int error;
+ int error, nslot;
if (udev->state != UIST_SETUP_COMPLETE) {
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
return -EINVAL;
}
+ if (test_bit(ABS_MT_SLOT, dev->absbit)) {
+ nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
+ error = input_mt_init_slots(dev, nslot, 0);
+ if (error)
+ goto fail1;
+ } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
+ input_set_events_per_packet(dev, 60);
+ }
+
+ if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
+ printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
+ UINPUT_NAME);
+ error = -EINVAL;
+ goto fail1;
+ }
+
if (udev->ff_effects_max) {
error = input_ff_create(dev, udev->ff_effects_max);
if (error)
@@ -308,10 +324,35 @@ static int uinput_open(struct inode *inode, struct file *file)
return 0;
}
+static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
+ const struct input_absinfo *abs)
+{
+ int min, max;
+
+ min = abs->minimum;
+ max = abs->maximum;
+
+ if ((min != 0 || max != 0) && max <= min) {
+ printk(KERN_DEBUG
+ "%s: invalid abs[%02x] min:%d max:%d\n",
+ UINPUT_NAME, code, min, max);
+ return -EINVAL;
+ }
+
+ if (abs->flat > max - min) {
+ printk(KERN_DEBUG
+ "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
+ UINPUT_NAME, code, abs->flat, min, max);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int uinput_validate_absbits(struct input_dev *dev)
{
unsigned int cnt;
- int nslot;
+ int error;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
@@ -321,38 +362,12 @@ static int uinput_validate_absbits(struct input_dev *dev)
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
- int min, max;
-
- min = input_abs_get_min(dev, cnt);
- max = input_abs_get_max(dev, cnt);
-
- if ((min != 0 || max != 0) && max <= min) {
- printk(KERN_DEBUG
- "%s: invalid abs[%02x] min:%d max:%d\n",
- UINPUT_NAME, cnt,
- input_abs_get_min(dev, cnt),
- input_abs_get_max(dev, cnt));
+ if (!dev->absinfo)
return -EINVAL;
- }
- if (input_abs_get_flat(dev, cnt) >
- input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
- printk(KERN_DEBUG
- "%s: abs_flat #%02x out of range: %d "
- "(min:%d/max:%d)\n",
- UINPUT_NAME, cnt,
- input_abs_get_flat(dev, cnt),
- input_abs_get_min(dev, cnt),
- input_abs_get_max(dev, cnt));
- return -EINVAL;
- }
- }
-
- if (test_bit(ABS_MT_SLOT, dev->absbit)) {
- nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
- input_mt_init_slots(dev, nslot, 0);
- } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
- input_set_events_per_packet(dev, 60);
+ error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
+ if (error)
+ return error;
}
return 0;
@@ -370,8 +385,71 @@ static int uinput_allocate_device(struct uinput_device *udev)
return 0;
}
-static int uinput_setup_device(struct uinput_device *udev,
- const char __user *buffer, size_t count)
+static int uinput_dev_setup(struct uinput_device *udev,
+ struct uinput_setup __user *arg)
+{
+ struct uinput_setup setup;
+ struct input_dev *dev;
+
+ if (udev->state == UIST_CREATED)
+ return -EINVAL;
+
+ if (copy_from_user(&setup, arg, sizeof(setup)))
+ return -EFAULT;
+
+ if (!setup.name[0])
+ return -EINVAL;
+
+ dev = udev->dev;
+ dev->id = setup.id;
+ udev->ff_effects_max = setup.ff_effects_max;
+
+ kfree(dev->name);
+ dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
+ if (!dev->name)
+ return -ENOMEM;
+
+ udev->state = UIST_SETUP_COMPLETE;
+ return 0;
+}
+
+static int uinput_abs_setup(struct uinput_device *udev,
+ struct uinput_setup __user *arg, size_t size)
+{
+ struct uinput_abs_setup setup = {};
+ struct input_dev *dev;
+ int error;
+
+ if (size > sizeof(setup))
+ return -E2BIG;
+
+ if (udev->state == UIST_CREATED)
+ return -EINVAL;
+
+ if (copy_from_user(&setup, arg, size))
+ return -EFAULT;
+
+ if (setup.code > ABS_MAX)
+ return -ERANGE;
+
+ dev = udev->dev;
+
+ error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
+ if (error)
+ return error;
+
+ input_alloc_absinfo(dev);
+ if (!dev->absinfo)
+ return -ENOMEM;
+
+ set_bit(setup.code, dev->absbit);
+ dev->absinfo[setup.code] = setup.absinfo;
+ return 0;
+}
+
+/* legacy setup via write() */
+static int uinput_setup_device_legacy(struct uinput_device *udev,
+ const char __user *buffer, size_t count)
{
struct uinput_user_dev *user_dev;
struct input_dev *dev;
@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
retval = udev->state == UIST_CREATED ?
uinput_inject_events(udev, buffer, count) :
- uinput_setup_device(udev, buffer, count);
+ uinput_setup_device_legacy(udev, buffer, count);
mutex_unlock(&udev->mutex);
@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
uinput_destroy_device(udev);
goto out;
+ case UI_DEV_SETUP:
+ retval = uinput_dev_setup(udev, p);
+ goto out;
+
+ /* UI_ABS_SETUP is handled in the variable size ioctls */
+
case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX);
goto out;
@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size);
goto out;
+
+ case UI_ABS_SETUP & ~IOCSIZE_MASK:
+ retval = uinput_abs_setup(udev, p, size);
+ goto out;
}
retval = -EINVAL;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 41e6cb501e6a..936f07a4e35f 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -31,6 +31,7 @@
#define ALPS_CMD_NIBBLE_10 0x01f2
#define ALPS_REG_BASE_RUSHMORE 0xc2c0
+#define ALPS_REG_BASE_V7 0xc2c0
#define ALPS_REG_BASE_PINNACLE 0x0000
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
return 0;
}
-static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base)
+static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base)
{
int ret = -EIO, reg_val;
@@ -2128,15 +2129,12 @@ error:
static int alps_hw_init_v3(struct psmouse *psmouse)
{
+ struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val;
unsigned char param[4];
- reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
- if (reg_val == -EIO)
- goto error;
-
- if (reg_val == 0 &&
+ if ((priv->flags & ALPS_DUALPOINT) &&
alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
goto error;
@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+
+ if (alps_probe_trackstick_v3_v7(psmouse,
+ ALPS_REG_BASE_PINNACLE) < 0)
+ priv->flags &= ~ALPS_DUALPOINT;
+
break;
case ALPS_PROTO_V3_RUSHMORE:
@@ -2625,8 +2628,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->x_bits = 16;
priv->y_bits = 12;
- if (alps_probe_trackstick_v3(psmouse,
- ALPS_REG_BASE_RUSHMORE) < 0)
+ if (alps_probe_trackstick_v3_v7(psmouse,
+ ALPS_REG_BASE_RUSHMORE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse,
if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD;
+ if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0)
+ priv->flags &= ~ALPS_DUALPOINT;
+
break;
case ALPS_PROTO_V8:
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 537ebb0e193a..78f93cf68840 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0);
}
- input_mt_init_slots(dev, 2, 0);
+ input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
break;
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index 4d5576de81be..c8c6a8cc329d 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
return 0;
}
-static void focaltech_reset(struct psmouse *psmouse)
-{
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
- psmouse_reset(psmouse);
-}
-
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
/*
@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse)
return 0;
}
+static void focaltech_reset(struct psmouse *psmouse)
+{
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
+ psmouse_reset(psmouse);
+}
+
static void focaltech_disconnect(struct psmouse *psmouse)
{
focaltech_reset(psmouse);
@@ -456,14 +456,4 @@ fail:
kfree(priv);
return error;
}
-
-#else /* CONFIG_MOUSE_PS2_FOCALTECH */
-
-int focaltech_init(struct psmouse *psmouse)
-{
- focaltech_reset(psmouse);
-
- return 0;
-}
-
#endif /* CONFIG_MOUSE_PS2_FOCALTECH */
diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h
index ca61ebff373e..783b28e8e10b 100644
--- a/drivers/input/mouse/focaltech.h
+++ b/drivers/input/mouse/focaltech.h
@@ -18,6 +18,14 @@
#define _FOCALTECH_H
int focaltech_detect(struct psmouse *psmouse, bool set_properties);
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH
int focaltech_init(struct psmouse *psmouse);
+#else
+static inline int focaltech_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif
#endif
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 136e222e2a16..422da1cd9e76 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
* that support it.
*/
-int ps2pp_init(struct psmouse *psmouse, bool set_properties)
+int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
index 0c186f0282d9..bf629453e095 100644
--- a/drivers/input/mouse/logips2pp.h
+++ b/drivers/input/mouse/logips2pp.h
@@ -12,9 +12,9 @@
#define _LOGIPS2PP_H
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
-int ps2pp_init(struct psmouse *psmouse, bool set_properties);
+int ps2pp_detect(struct psmouse *psmouse, bool set_properties);
#else
-inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
+static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index ad18dab0ac47..b9e4ee34c132 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -119,6 +119,7 @@ struct psmouse_protocol {
enum psmouse_type type;
bool maxproto;
bool ignore_parity; /* Protocol should ignore parity errors from KBC */
+ bool try_passthru; /* Try protocol also on passthrough ports */
const char *name;
const char *alias;
int (*detect)(struct psmouse *, bool);
@@ -129,7 +130,6 @@ struct psmouse_protocol {
* psmouse_process_byte() analyzes the PS/2 data stream and reports
* relevant events to the input module once full packet has arrived.
*/
-
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
@@ -138,22 +138,16 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
if (psmouse->pktcnt < psmouse->pktsize)
return PSMOUSE_GOOD_DATA;
-/*
- * Full packet accumulated, process it
- */
+ /* Full packet accumulated, process it */
-/*
- * Scroll wheel on IntelliMice, scroll buttons on NetMice
- */
-
- if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
+ switch (psmouse->type) {
+ case PSMOUSE_IMPS:
+ /* IntelliMouse has scroll wheel */
input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
+ break;
-/*
- * Scroll wheel and buttons on IntelliMouse Explorer
- */
-
- if (psmouse->type == PSMOUSE_IMEX) {
+ case PSMOUSE_IMEX:
+ /* Scroll wheel and buttons on IntelliMouse Explorer */
switch (packet[3] & 0xC0) {
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
@@ -168,39 +162,42 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
break;
}
- }
+ break;
-/*
- * Extra buttons on Genius NewNet 3D
- */
+ case PSMOUSE_GENPS:
+ /* Report scroll buttons on NetMice */
+ input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
- if (psmouse->type == PSMOUSE_GENPS) {
+ /* Extra buttons on Genius NewNet 3D */
input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
- }
+ break;
-/*
- * Extra button on ThinkingMouse
- */
- if (psmouse->type == PSMOUSE_THINKPS) {
+ case PSMOUSE_THINKPS:
+ /* Extra button on ThinkingMouse */
input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
- /* Without this bit of weirdness moving up gives wildly high Y changes. */
+
+ /*
+ * Without this bit of weirdness moving up gives wildly
+ * high Y changes.
+ */
packet[1] |= (packet[0] & 0x40) << 1;
- }
+ break;
-/*
- * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first
- * byte.
- */
- if (psmouse->type == PSMOUSE_CORTRON) {
+ case PSMOUSE_CORTRON:
+ /*
+ * Cortron PS2 Trackball reports SIDE button in the
+ * 4th bit of the first byte.
+ */
input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
packet[0] |= 0x08;
- }
+ break;
-/*
- * Generic PS/2 Mouse
- */
+ default:
+ break;
+ }
+ /* Generic PS/2 Mouse */
input_report_key(dev, BTN_LEFT, packet[0] & 1);
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
@@ -222,7 +219,6 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
/*
* __psmouse_set_state() sets new psmouse state and resets all flags.
*/
-
static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
psmouse->state = new_state;
@@ -231,13 +227,11 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta
psmouse->last = jiffies;
}
-
/*
* psmouse_set_state() sets new psmouse state and resets all flags and
* counters while holding serio lock so fighting with interrupt handler
* is not a concern.
*/
-
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
serio_pause_rx(psmouse->ps2dev.serio);
@@ -249,7 +243,6 @@ void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
* psmouse_handle_byte() processes one byte of the input data stream
* by calling corresponding protocol handler.
*/
-
static int psmouse_handle_byte(struct psmouse *psmouse)
{
psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
@@ -292,7 +285,6 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
* psmouse_interrupt() handles incoming characters, either passing them
* for normal processing or gathering them as command response.
*/
-
static irqreturn_t psmouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
@@ -335,9 +327,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
psmouse->packet[psmouse->pktcnt++] = data;
-/*
- * Check if this is a new device announcement (0xAA 0x00)
- */
+
+ /* Check if this is a new device announcement (0xAA 0x00) */
if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
if (psmouse->pktcnt == 1) {
psmouse->last = jiffies;
@@ -351,9 +342,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
serio_reconnect(serio);
goto out;
}
-/*
- * Not a new device, try processing first byte normally
- */
+
+ /* Not a new device, try processing first byte normally */
psmouse->pktcnt = 1;
if (psmouse_handle_byte(psmouse))
goto out;
@@ -361,9 +351,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
psmouse->packet[psmouse->pktcnt++] = data;
}
-/*
- * See if we need to force resync because mouse was idle for too long
- */
+ /*
+ * See if we need to force resync because mouse was idle for
+ * too long.
+ */
if (psmouse->state == PSMOUSE_ACTIVATED &&
psmouse->pktcnt == 1 && psmouse->resync_time &&
time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
@@ -380,7 +371,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
return IRQ_HANDLED;
}
-
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech
@@ -404,7 +394,6 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
return 0;
}
-
/*
* psmouse_reset() resets the mouse into power-on state.
*/
@@ -424,7 +413,6 @@ int psmouse_reset(struct psmouse *psmouse)
/*
* Here we set the mouse resolution.
*/
-
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
@@ -441,7 +429,6 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
/*
* Here we set the mouse report rate.
*/
-
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
{
static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
@@ -457,7 +444,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
/*
* Here we set the mouse scaling.
*/
-
static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
{
ps2_command(&psmouse->ps2dev, NULL,
@@ -468,7 +454,6 @@ static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
/*
* psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
*/
-
static int psmouse_poll(struct psmouse *psmouse)
{
return ps2_command(&psmouse->ps2dev, psmouse->packet,
@@ -602,7 +587,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
if (param[0] != 4)
return -1;
-/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
+ /* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
param[0] = 200;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 80;
@@ -672,10 +657,10 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
if (!psmouse->name)
psmouse->name = "Mouse";
-/*
- * We have no way of figuring true number of buttons so let's
- * assume that the device has 3.
- */
+ /*
+ * We have no way of figuring true number of buttons so let's
+ * assume that the device has 3.
+ */
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
}
@@ -699,284 +684,6 @@ static int cortron_detect(struct psmouse *psmouse, bool set_properties)
return 0;
}
-/*
- * Apply default settings to the psmouse structure. Most of them will
- * be overridden by individual protocol initialization routines.
- */
-
-static void psmouse_apply_defaults(struct psmouse *psmouse)
-{
- struct input_dev *input_dev = psmouse->dev;
-
- memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
- memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
- memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
- memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
- memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
-
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(EV_REL, input_dev->evbit);
-
- __set_bit(BTN_LEFT, input_dev->keybit);
- __set_bit(BTN_RIGHT, input_dev->keybit);
-
- __set_bit(REL_X, input_dev->relbit);
- __set_bit(REL_Y, input_dev->relbit);
-
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
- psmouse->set_rate = psmouse_set_rate;
- psmouse->set_resolution = psmouse_set_resolution;
- psmouse->set_scale = psmouse_set_scale;
- psmouse->poll = psmouse_poll;
- psmouse->protocol_handler = psmouse_process_byte;
- psmouse->pktsize = 3;
- psmouse->reconnect = NULL;
- psmouse->disconnect = NULL;
- psmouse->cleanup = NULL;
- psmouse->pt_activate = NULL;
- psmouse->pt_deactivate = NULL;
-}
-
-/*
- * Apply default settings to the psmouse structure and call specified
- * protocol detection or initialization routine.
- */
-static int psmouse_do_detect(int (*detect)(struct psmouse *psmouse,
- bool set_properties),
- struct psmouse *psmouse, bool set_properties)
-{
- if (set_properties)
- psmouse_apply_defaults(psmouse);
-
- return detect(psmouse, set_properties);
-}
-
-/*
- * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
- * the mouse may have.
- */
-
-static int psmouse_extensions(struct psmouse *psmouse,
- unsigned int max_proto, bool set_properties)
-{
- bool synaptics_hardware = false;
-
-/* Always check for focaltech, this is safe as it uses pnp-id matching */
- if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) {
- if (max_proto > PSMOUSE_IMEX) {
- if (!set_properties || focaltech_init(psmouse) == 0) {
- if (IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH))
- return PSMOUSE_FOCALTECH;
- /*
- * Note that we need to also restrict
- * psmouse_max_proto so that psmouse_initialize()
- * does not try to reset rate and resolution,
- * because even that upsets the device.
- */
- psmouse_max_proto = PSMOUSE_PS2;
- return PSMOUSE_PS2;
- }
- }
- }
-
-/*
- * We always check for lifebook because it does not disturb mouse
- * (it only checks DMI information).
- */
- if (psmouse_do_detect(lifebook_detect, psmouse, set_properties) == 0) {
- if (max_proto > PSMOUSE_IMEX) {
- if (!set_properties || lifebook_init(psmouse) == 0)
- return PSMOUSE_LIFEBOOK;
- }
- }
-
- if (psmouse_do_detect(vmmouse_detect, psmouse, set_properties) == 0) {
- if (max_proto > PSMOUSE_IMEX) {
- if (!set_properties || vmmouse_init(psmouse) == 0)
- return PSMOUSE_VMMOUSE;
- }
- }
-
-/*
- * Try Kensington ThinkingMouse (we try first, because synaptics probe
- * upsets the thinkingmouse).
- */
-
- if (max_proto > PSMOUSE_IMEX &&
- psmouse_do_detect(thinking_detect, psmouse, set_properties) == 0) {
- return PSMOUSE_THINKPS;
- }
-
-/*
- * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
- * support is disabled in config - we need to know if it is synaptics so we
- * can reset it properly after probing for intellimouse.
- */
- if (max_proto > PSMOUSE_PS2 &&
- psmouse_do_detect(synaptics_detect, psmouse, set_properties) == 0) {
- synaptics_hardware = true;
-
- if (max_proto > PSMOUSE_IMEX) {
-/*
- * Try activating protocol, but check if support is enabled first, since
- * we try detecting Synaptics even when protocol is disabled.
- */
- if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) &&
- (!set_properties || synaptics_init(psmouse) == 0)) {
- return PSMOUSE_SYNAPTICS;
- }
-
-/*
- * Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
- * Unfortunately Logitech/Genius probes confuse some firmware versions so
- * we'll have to skip them.
- */
- max_proto = PSMOUSE_IMEX;
- }
-/*
- * Make sure that touchpad is in relative mode, gestures (taps) are enabled
- */
- synaptics_reset(psmouse);
- }
-
-/*
- * Try Cypress Trackpad.
- * Must try it before Finger Sensing Pad because Finger Sensing Pad probe
- * upsets some modules of Cypress Trackpads.
- */
- if (max_proto > PSMOUSE_IMEX &&
- cypress_detect(psmouse, set_properties) == 0) {
- if (IS_ENABLED(CONFIG_MOUSE_PS2_CYPRESS)) {
- if (cypress_init(psmouse) == 0)
- return PSMOUSE_CYPRESS;
-
- /*
- * Finger Sensing Pad probe upsets some modules of
- * Cypress Trackpad, must avoid Finger Sensing Pad
- * probe if Cypress Trackpad device detected.
- */
- return PSMOUSE_PS2;
- }
-
- max_proto = PSMOUSE_IMEX;
- }
-
-/*
- * Try ALPS TouchPad
- */
- if (max_proto > PSMOUSE_IMEX) {
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
- if (psmouse_do_detect(alps_detect,
- psmouse, set_properties) == 0) {
- if (!set_properties || alps_init(psmouse) == 0)
- return PSMOUSE_ALPS;
-/*
- * Init failed, try basic relative protocols
- */
- max_proto = PSMOUSE_IMEX;
- }
- }
-
-/*
- * Try OLPC HGPK touchpad.
- */
- if (max_proto > PSMOUSE_IMEX &&
- psmouse_do_detect(hgpk_detect, psmouse, set_properties) == 0) {
- if (!set_properties || hgpk_init(psmouse) == 0)
- return PSMOUSE_HGPK;
-/*
- * Init failed, try basic relative protocols
- */
- max_proto = PSMOUSE_IMEX;
- }
-
-/*
- * Try Elantech touchpad.
- */
- if (max_proto > PSMOUSE_IMEX &&
- psmouse_do_detect(elantech_detect, psmouse, set_properties) == 0) {
- if (!set_properties || elantech_init(psmouse) == 0)
- return PSMOUSE_ELANTECH;
-/*
- * Init failed, try basic relative protocols
- */
- max_proto = PSMOUSE_IMEX;
- }
-
- if (max_proto > PSMOUSE_IMEX) {
- if (psmouse_do_detect(genius_detect,
- psmouse, set_properties) == 0)
- return PSMOUSE_GENPS;
-
- if (psmouse_do_detect(ps2pp_init,
- psmouse, set_properties) == 0)
- return PSMOUSE_PS2PP;
-
- if (psmouse_do_detect(trackpoint_detect,
- psmouse, set_properties) == 0)
- return PSMOUSE_TRACKPOINT;
-
- if (psmouse_do_detect(touchkit_ps2_detect,
- psmouse, set_properties) == 0)
- return PSMOUSE_TOUCHKIT_PS2;
- }
-
-/*
- * Try Finger Sensing Pad. We do it here because its probe upsets
- * Trackpoint devices (causing TP_READ_ID command to time out).
- */
- if (max_proto > PSMOUSE_IMEX) {
- if (psmouse_do_detect(fsp_detect,
- psmouse, set_properties) == 0) {
- if (!set_properties || fsp_init(psmouse) == 0)
- return PSMOUSE_FSP;
-/*
- * Init failed, try basic relative protocols
- */
- max_proto = PSMOUSE_IMEX;
- }
- }
-
-/*
- * Reset to defaults in case the device got confused by extended
- * protocol probes. Note that we follow up with full reset because
- * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
- */
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
- psmouse_reset(psmouse);
-
- if (max_proto >= PSMOUSE_IMEX &&
- psmouse_do_detect(im_explorer_detect,
- psmouse, set_properties) == 0) {
- return PSMOUSE_IMEX;
- }
-
- if (max_proto >= PSMOUSE_IMPS &&
- psmouse_do_detect(intellimouse_detect,
- psmouse, set_properties) == 0) {
- return PSMOUSE_IMPS;
- }
-
-/*
- * Okay, all failed, we have a standard mouse here. The number of the buttons
- * is still a question, though. We assume 3.
- */
- psmouse_do_detect(ps2bare_detect, psmouse, set_properties);
-
- if (synaptics_hardware) {
-/*
- * We detected Synaptics hardware but it did not respond to IMPS/2 probes.
- * We need to reset the touchpad because if there is a track point on the
- * pass through port it could get disabled while probing for protocol
- * extensions.
- */
- psmouse_reset(psmouse);
- }
-
- return PSMOUSE_PS2;
-}
-
static const struct psmouse_protocol psmouse_protocols[] = {
{
.type = PSMOUSE_PS2,
@@ -985,13 +692,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = true,
.ignore_parity = true,
.detect = ps2bare_detect,
+ .try_passthru = true,
},
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
{
.type = PSMOUSE_PS2PP,
.name = "PS2++",
.alias = "logitech",
- .detect = ps2pp_init,
+ .detect = ps2pp_detect,
},
#endif
{
@@ -1022,6 +730,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = true,
.ignore_parity = true,
.detect = intellimouse_detect,
+ .try_passthru = true,
},
{
.type = PSMOUSE_IMEX,
@@ -1030,6 +739,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = true,
.ignore_parity = true,
.detect = im_explorer_detect,
+ .try_passthru = true,
},
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
{
@@ -1061,6 +771,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.type = PSMOUSE_LIFEBOOK,
.name = "LBPS/2",
.alias = "lifebook",
+ .detect = lifebook_detect,
.init = lifebook_init,
},
#endif
@@ -1070,6 +781,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.name = "TPPS/2",
.alias = "trackpoint",
.detect = trackpoint_detect,
+ .try_passthru = true,
},
#endif
#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
@@ -1138,7 +850,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
},
};
-static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+static const struct psmouse_protocol *__psmouse_protocol_by_type(enum psmouse_type type)
{
int i;
@@ -1146,6 +858,17 @@ static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type
if (psmouse_protocols[i].type == type)
return &psmouse_protocols[i];
+ return NULL;
+}
+
+static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+{
+ const struct psmouse_protocol *proto;
+
+ proto = __psmouse_protocol_by_type(type);
+ if (proto)
+ return proto;
+
WARN_ON(1);
return &psmouse_protocols[0];
}
@@ -1166,23 +889,288 @@ static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name,
return NULL;
}
+/*
+ * Apply default settings to the psmouse structure. Most of them will
+ * be overridden by individual protocol initialization routines.
+ */
+static void psmouse_apply_defaults(struct psmouse *psmouse)
+{
+ struct input_dev *input_dev = psmouse->dev;
+
+ memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
+ memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
+ memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
+ memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
+ memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_REL, input_dev->evbit);
+
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+ psmouse->set_rate = psmouse_set_rate;
+ psmouse->set_resolution = psmouse_set_resolution;
+ psmouse->set_scale = psmouse_set_scale;
+ psmouse->poll = psmouse_poll;
+ psmouse->protocol_handler = psmouse_process_byte;
+ psmouse->pktsize = 3;
+ psmouse->reconnect = NULL;
+ psmouse->disconnect = NULL;
+ psmouse->cleanup = NULL;
+ psmouse->pt_activate = NULL;
+ psmouse->pt_deactivate = NULL;
+}
+
+static bool psmouse_try_protocol(struct psmouse *psmouse,
+ enum psmouse_type type,
+ unsigned int *max_proto,
+ bool set_properties, bool init_allowed)
+{
+ const struct psmouse_protocol *proto;
+
+ proto = __psmouse_protocol_by_type(type);
+ if (!proto)
+ return false;
+
+ if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU &&
+ !proto->try_passthru) {
+ return false;
+ }
+
+ if (set_properties)
+ psmouse_apply_defaults(psmouse);
+
+ if (proto->detect(psmouse, set_properties) != 0)
+ return false;
+
+ if (set_properties && proto->init && init_allowed) {
+ if (proto->init(psmouse) != 0) {
+ /*
+ * We detected device, but init failed. Adjust
+ * max_proto so we only try standard protocols.
+ */
+ if (*max_proto > PSMOUSE_IMEX)
+ *max_proto = PSMOUSE_IMEX;
+
+ return false;
+ }
+ }
+
+ return true;
+}
/*
- * psmouse_probe() probes for a PS/2 mouse.
+ * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
+ * the mouse may have.
*/
+static int psmouse_extensions(struct psmouse *psmouse,
+ unsigned int max_proto, bool set_properties)
+{
+ bool synaptics_hardware = false;
+
+ /*
+ * Always check for focaltech, this is safe as it uses pnp-id
+ * matching.
+ */
+ if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH,
+ &max_proto, set_properties, false)) {
+ if (max_proto > PSMOUSE_IMEX &&
+ IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) &&
+ (!set_properties || focaltech_init(psmouse) == 0)) {
+ return PSMOUSE_FOCALTECH;
+ }
+ /*
+ * Restrict psmouse_max_proto so that psmouse_initialize()
+ * does not try to reset rate and resolution, because even
+ * that upsets the device.
+ * This also causes us to basically fall through to basic
+ * protocol detection, where we fully reset the mouse,
+ * and set it up as bare PS/2 protocol device.
+ */
+ psmouse_max_proto = max_proto = PSMOUSE_PS2;
+ }
+
+ /*
+ * We always check for LifeBook because it does not disturb mouse
+ * (it only checks DMI information).
+ */
+ if (psmouse_try_protocol(psmouse, PSMOUSE_LIFEBOOK, &max_proto,
+ set_properties, max_proto > PSMOUSE_IMEX))
+ return PSMOUSE_LIFEBOOK;
+ if (psmouse_try_protocol(psmouse, PSMOUSE_VMMOUSE, &max_proto,
+ set_properties, max_proto > PSMOUSE_IMEX))
+ return PSMOUSE_VMMOUSE;
+
+ /*
+ * Try Kensington ThinkingMouse (we try first, because Synaptics
+ * probe upsets the ThinkingMouse).
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_THINKPS, &max_proto,
+ set_properties, true)) {
+ return PSMOUSE_THINKPS;
+ }
+
+ /*
+ * Try Synaptics TouchPad. Note that probing is done even if
+ * Synaptics protocol support is disabled in config - we need to
+ * know if it is Synaptics so we can reset it properly after
+ * probing for IntelliMouse.
+ */
+ if (max_proto > PSMOUSE_PS2 &&
+ psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto,
+ set_properties, false)) {
+ synaptics_hardware = true;
+
+ if (max_proto > PSMOUSE_IMEX) {
+ /*
+ * Try activating protocol, but check if support is
+ * enabled first, since we try detecting Synaptics
+ * even when protocol is disabled.
+ */
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) &&
+ (!set_properties || synaptics_init(psmouse) == 0)) {
+ return PSMOUSE_SYNAPTICS;
+ }
+
+ /*
+ * Some Synaptics touchpads can emulate extended
+ * protocols (like IMPS/2). Unfortunately
+ * Logitech/Genius probes confuse some firmware
+ * versions so we'll have to skip them.
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
+
+ /*
+ * Make sure that touchpad is in relative mode, gestures
+ * (taps) are enabled.
+ */
+ synaptics_reset(psmouse);
+ }
+
+ /*
+ * Try Cypress Trackpad. We must try it before Finger Sensing Pad
+ * because Finger Sensing Pad probe upsets some modules of Cypress
+ * Trackpads.
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_CYPRESS, &max_proto,
+ set_properties, true)) {
+ return PSMOUSE_CYPRESS;
+ }
+
+ /* Try ALPS TouchPad */
+ if (max_proto > PSMOUSE_IMEX) {
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
+ if (psmouse_try_protocol(psmouse, PSMOUSE_ALPS,
+ &max_proto, set_properties, true))
+ return PSMOUSE_ALPS;
+ }
+
+ /* Try OLPC HGPK touchpad */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto,
+ set_properties, true)) {
+ return PSMOUSE_HGPK;
+ }
+
+ /* Try Elantech touchpad */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH,
+ &max_proto, set_properties, true)) {
+ return PSMOUSE_ELANTECH;
+ }
+
+ if (max_proto > PSMOUSE_IMEX) {
+ if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
+ &max_proto, set_properties, true))
+ return PSMOUSE_GENPS;
+
+ if (psmouse_try_protocol(psmouse, PSMOUSE_PS2PP,
+ &max_proto, set_properties, true))
+ return PSMOUSE_PS2PP;
+
+ if (psmouse_try_protocol(psmouse, PSMOUSE_TRACKPOINT,
+ &max_proto, set_properties, true))
+ return PSMOUSE_TRACKPOINT;
+
+ if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2,
+ &max_proto, set_properties, true))
+ return PSMOUSE_TOUCHKIT_PS2;
+ }
+
+ /*
+ * Try Finger Sensing Pad. We do it here because its probe upsets
+ * Trackpoint devices (causing TP_READ_ID command to time out).
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_FSP,
+ &max_proto, set_properties, true)) {
+ return PSMOUSE_FSP;
+ }
+
+ /*
+ * Reset to defaults in case the device got confused by extended
+ * protocol probes. Note that we follow up with full reset because
+ * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
+ */
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
+ psmouse_reset(psmouse);
+
+ if (max_proto >= PSMOUSE_IMEX &&
+ psmouse_try_protocol(psmouse, PSMOUSE_IMEX,
+ &max_proto, set_properties, true)) {
+ return PSMOUSE_IMEX;
+ }
+
+ if (max_proto >= PSMOUSE_IMPS &&
+ psmouse_try_protocol(psmouse, PSMOUSE_IMPS,
+ &max_proto, set_properties, true)) {
+ return PSMOUSE_IMPS;
+ }
+
+ /*
+ * Okay, all failed, we have a standard mouse here. The number of
+ * the buttons is still a question, though. We assume 3.
+ */
+ psmouse_try_protocol(psmouse, PSMOUSE_PS2,
+ &max_proto, set_properties, true);
+
+ if (synaptics_hardware) {
+ /*
+ * We detected Synaptics hardware but it did not respond to
+ * IMPS/2 probes. We need to reset the touchpad because if
+ * there is a track point on the pass through port it could
+ * get disabled while probing for protocol extensions.
+ */
+ psmouse_reset(psmouse);
+ }
+
+ return PSMOUSE_PS2;
+}
+
+/*
+ * psmouse_probe() probes for a PS/2 mouse.
+ */
static int psmouse_probe(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
-/*
- * First, we check if it's a mouse. It should send 0x00 or 0x03
- * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
- * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent
- * ID queries, probably due to a firmware bug.
- */
-
+ /*
+ * First, we check if it's a mouse. It should send 0x00 or 0x03 in
+ * case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+ * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and
+ * subsequent ID queries, probably due to a firmware bug.
+ */
param[0] = 0xa5;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
return -1;
@@ -1191,10 +1179,10 @@ static int psmouse_probe(struct psmouse *psmouse)
param[0] != 0x04 && param[0] != 0xff)
return -1;
-/*
- * Then we reset and disable the mouse so that it doesn't generate events.
- */
-
+ /*
+ * Then we reset and disable the mouse so that it doesn't generate
+ * events.
+ */
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
ps2dev->serio->phys);
@@ -1205,13 +1193,11 @@ static int psmouse_probe(struct psmouse *psmouse)
/*
* psmouse_initialize() initializes the mouse to a sane state.
*/
-
static void psmouse_initialize(struct psmouse *psmouse)
{
-/*
- * We set the mouse report rate, resolution and scaling.
- */
-
+ /*
+ * We set the mouse report rate, resolution and scaling.
+ */
if (psmouse_max_proto != PSMOUSE_PS2) {
psmouse->set_rate(psmouse, psmouse->rate);
psmouse->set_resolution(psmouse, psmouse->resolution);
@@ -1222,7 +1208,6 @@ static void psmouse_initialize(struct psmouse *psmouse)
/*
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
-
int psmouse_activate(struct psmouse *psmouse)
{
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
@@ -1236,10 +1221,9 @@ int psmouse_activate(struct psmouse *psmouse)
}
/*
- * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
- * reports from it unless we explicitly request it.
+ * psmouse_deactivate() puts the mouse into poll mode so that we don't get
+ * motion reports from it unless we explicitly request it.
*/
-
int psmouse_deactivate(struct psmouse *psmouse)
{
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
@@ -1252,11 +1236,9 @@ int psmouse_deactivate(struct psmouse *psmouse)
return 0;
}
-
/*
* psmouse_resync() attempts to re-validate current protocol.
*/
-
static void psmouse_resync(struct work_struct *work)
{
struct psmouse *parent = NULL, *psmouse =
@@ -1276,16 +1258,16 @@ static void psmouse_resync(struct work_struct *work)
psmouse_deactivate(parent);
}
-/*
- * Some mice don't ACK commands sent while they are in the middle of
- * transmitting motion packet. To avoid delay we use ps2_sendbyte()
- * instead of ps2_command() which would wait for 200ms for an ACK
- * that may never come.
- * As an additional quirk ALPS touchpads may not only forget to ACK
- * disable command but will stop reporting taps, so if we see that
- * mouse at least once ACKs disable we will do full reconnect if ACK
- * is missing.
- */
+ /*
+ * Some mice don't ACK commands sent while they are in the middle of
+ * transmitting motion packet. To avoid delay we use ps2_sendbyte()
+ * instead of ps2_command() which would wait for 200ms for an ACK
+ * that may never come.
+ * As an additional quirk ALPS touchpads may not only forget to ACK
+ * disable command but will stop reporting taps, so if we see that
+ * mouse at least once ACKs disable we will do full reconnect if ACK
+ * is missing.
+ */
psmouse->num_resyncs++;
if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
@@ -1294,13 +1276,13 @@ static void psmouse_resync(struct work_struct *work)
} else
psmouse->acks_disable_command = true;
-/*
- * Poll the mouse. If it was reset the packet will be shorter than
- * psmouse->pktsize and ps2_command will fail. We do not expect and
- * do not handle scenario when mouse "upgrades" its protocol while
- * disconnected since it would require additional delay. If we ever
- * see a mouse that does it we'll adjust the code.
- */
+ /*
+ * Poll the mouse. If it was reset the packet will be shorter than
+ * psmouse->pktsize and ps2_command will fail. We do not expect and
+ * do not handle scenario when mouse "upgrades" its protocol while
+ * disconnected since it would require additional delay. If we ever
+ * see a mouse that does it we'll adjust the code.
+ */
if (!failed) {
if (psmouse->poll(psmouse))
failed = true;
@@ -1317,11 +1299,12 @@ static void psmouse_resync(struct work_struct *work)
psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
}
}
-/*
- * Now try to enable mouse. We try to do that even if poll failed and also
- * repeat our attempts 5 times, otherwise we may be left out with disabled
- * mouse.
- */
+
+ /*
+ * Now try to enable mouse. We try to do that even if poll failed
+ * and also repeat our attempts 5 times, otherwise we may be left
+ * out with disabled mouse.
+ */
for (i = 0; i < 5; i++) {
if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
enabled = true;
@@ -1353,7 +1336,6 @@ static void psmouse_resync(struct work_struct *work)
/*
* psmouse_cleanup() resets the mouse into power-on state.
*/
-
static void psmouse_cleanup(struct serio *serio)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
@@ -1378,15 +1360,15 @@ static void psmouse_cleanup(struct serio *serio)
if (psmouse->cleanup)
psmouse->cleanup(psmouse);
-/*
- * Reset the mouse to defaults (bare PS/2 protocol).
- */
+ /*
+ * Reset the mouse to defaults (bare PS/2 protocol).
+ */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
-/*
- * Some boxes, such as HP nx7400, get terribly confused if mouse
- * is not fully enabled before suspending/shutting down.
- */
+ /*
+ * Some boxes, such as HP nx7400, get terribly confused if mouse
+ * is not fully enabled before suspending/shutting down.
+ */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
if (parent) {
@@ -1402,7 +1384,6 @@ static void psmouse_cleanup(struct serio *serio)
/*
* psmouse_disconnect() closes and frees.
*/
-
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse, *parent = NULL;
@@ -1602,7 +1583,6 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
goto out;
}
-
static int psmouse_reconnect(struct serio *serio)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c
index e74e5d6e5f9f..c948866edf87 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -412,16 +412,6 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
return 0;
}
-/*
- * Keyboard GUID
- * {f912ad6d-2b17-48ea-bd65-f927a61c7684}
- */
-#define HV_KBD_GUID \
- .guid = { \
- 0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48, \
- 0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 \
- }
-
static const struct hv_vmbus_device_id id_table[] = {
/* Keyboard guid */
{ HV_KBD_GUID, },
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index c11556563ef0..68f5f4a0f1e7 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -258,6 +258,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
},
},
{
+ /* Fujitsu Lifebook U745 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
+ },
+ },
+ {
/* Fujitsu T70H */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index ae33da7ab51f..66c62641b59a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX
To compile this driver as a module, choose M here: the
module will be called egalax_ts.
+config TOUCHSCREEN_EGALAX_SERIAL
+ tristate "EETI eGalax serial touchscreen"
+ select SERIO
+ help
+ Say Y here to enable support for serial connected EETI
+ eGalax touch panels.
+
+ To compile this driver as a module, choose M here: the
+ module will be called egalax_ts_serial.
+
config TOUCHSCREEN_FT6236
tristate "FT6236 I2C touchscreen"
depends on I2C
@@ -324,6 +334,7 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_GOODIX
tristate "Goodix I2C touchscreen"
depends on I2C
+ depends on GPIOLIB
help
Say Y here if you have the Goodix touchscreen (such as one
installed in Onda v975w tablets) connected to your
@@ -365,7 +376,7 @@ config TOUCHSCREEN_IPROC
config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410/generic touchscreen input driver"
depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
- select S3C_ADC
+ depends on S3C_ADC
help
Say Y here if you have the s3c2410 touchscreen.
@@ -927,6 +938,22 @@ config TOUCHSCREEN_TOUCHIT213
To compile this driver as a module, choose M here: the
module will be called touchit213.
+config TOUCHSCREEN_TS4800
+ tristate "TS-4800 touchscreen"
+ depends on HAS_IOMEM && OF
+ select MFD_SYSCON
+ select INPUT_POLLDEV
+ help
+ Say Y here if you have a touchscreen on a TS-4800 board.
+
+ On TS-4800, the touchscreen is not handled directly by Linux but by
+ a companion FPGA.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ts4800_ts.
+
config TOUCHSCREEN_TSC_SERIO
tristate "TSC-10/25/40 serial touchscreen support"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index cbaa6abb08da..968ff12e3132 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
+obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
@@ -68,6 +69,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_TS4800) += ts4800-ts.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o
obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index fec66ad80513..16b5cc2196f2 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -454,7 +454,7 @@ static int ad7879_gpio_add(struct ad7879 *ts,
ts->gc.ngpio = 1;
ts->gc.label = "AD7879-GPIO";
ts->gc.owner = THIS_MODULE;
- ts->gc.dev = ts->dev;
+ ts->gc.parent = ts->dev;
ret = gpiochip_add(&ts->gc);
if (ret)
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c
new file mode 100644
index 000000000000..657bbae608c8
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -0,0 +1,194 @@
+/*
+ * EETI Egalax serial touchscreen driver
+ *
+ * Copyright (c) 2015 Zoltán Böszörményi <zboszor@pr.hu>
+ *
+ * based on the
+ *
+ * Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
+ */
+
+/*
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+#define DRIVER_DESC "EETI Egalax serial touchscreen driver"
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define EGALAX_FORMAT_MAX_LENGTH 6
+#define EGALAX_FORMAT_START_BIT BIT(7)
+#define EGALAX_FORMAT_PRESSURE_BIT BIT(6)
+#define EGALAX_FORMAT_TOUCH_BIT BIT(0)
+#define EGALAX_FORMAT_RESOLUTION_MASK 0x06
+
+#define EGALAX_MIN_XC 0
+#define EGALAX_MAX_XC 0x4000
+#define EGALAX_MIN_YC 0
+#define EGALAX_MAX_YC 0x4000
+
+/*
+ * Per-touchscreen data.
+ */
+struct egalax {
+ struct input_dev *input;
+ struct serio *serio;
+ int idx;
+ u8 data[EGALAX_FORMAT_MAX_LENGTH];
+ char phys[32];
+};
+
+static void egalax_process_data(struct egalax *egalax)
+{
+ struct input_dev *dev = egalax->input;
+ u8 *data = egalax->data;
+ u16 x, y;
+ u8 shift;
+ u8 mask;
+
+ shift = 3 - ((data[0] & EGALAX_FORMAT_RESOLUTION_MASK) >> 1);
+ mask = 0xff >> (shift + 1);
+
+ x = (((u16)(data[1] & mask) << 7) | (data[2] & 0x7f)) << shift;
+ y = (((u16)(data[3] & mask) << 7) | (data[4] & 0x7f)) << shift;
+
+ input_report_key(dev, BTN_TOUCH, data[0] & EGALAX_FORMAT_TOUCH_BIT);
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_sync(dev);
+}
+
+static irqreturn_t egalax_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct egalax *egalax = serio_get_drvdata(serio);
+ int pkt_len;
+
+ egalax->data[egalax->idx++] = data;
+
+ if (likely(egalax->data[0] & EGALAX_FORMAT_START_BIT)) {
+ pkt_len = egalax->data[0] & EGALAX_FORMAT_PRESSURE_BIT ? 6 : 5;
+ if (pkt_len == egalax->idx) {
+ egalax_process_data(egalax);
+ egalax->idx = 0;
+ }
+ } else {
+ dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
+ egalax->data[0]);
+ egalax->idx = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * egalax_connect() is the routine that is called when someone adds a
+ * new serio device that supports egalax protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+static int egalax_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct egalax *egalax;
+ struct input_dev *input_dev;
+ int error;
+
+ egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!egalax || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ egalax->serio = serio;
+ egalax->input = input_dev;
+ snprintf(egalax->phys, sizeof(egalax->phys),
+ "%s/input0", serio->phys);
+
+ input_dev->name = "EETI eGalaxTouch Serial TouchScreen";
+ input_dev->phys = egalax->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_EGALAX;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0001;
+ input_dev->dev.parent = &serio->dev;
+
+ input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+ input_set_abs_params(input_dev, ABS_X,
+ EGALAX_MIN_XC, EGALAX_MAX_XC, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ EGALAX_MIN_YC, EGALAX_MAX_YC, 0, 0);
+
+ serio_set_drvdata(serio, egalax);
+
+ error = serio_open(serio, drv);
+ if (error)
+ goto err_reset_drvdata;
+
+ error = input_register_device(input_dev);
+ if (error)
+ goto err_close_serio;
+
+ return 0;
+
+err_close_serio:
+ serio_close(serio);
+err_reset_drvdata:
+ serio_set_drvdata(serio, NULL);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(egalax);
+ return error;
+}
+
+static void egalax_disconnect(struct serio *serio)
+{
+ struct egalax *egalax = serio_get_drvdata(serio);
+
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_unregister_device(egalax->input);
+ kfree(egalax);
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static const struct serio_device_id egalax_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_EGALAX,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, egalax_serio_ids);
+
+static struct serio_driver egalax_drv = {
+ .driver = {
+ .name = "egalax",
+ },
+ .description = DRIVER_DESC,
+ .id_table = egalax_serio_ids,
+ .interrupt = egalax_interrupt,
+ .connect = egalax_connect,
+ .disconnect = egalax_disconnect,
+};
+module_serio_driver(egalax_drv);
+
+MODULE_AUTHOR("Zoltán Böszörményi <zboszor@pr.hu>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 4d113c9e4b77..240b16f3ee97 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -2,6 +2,7 @@
* Driver for Goodix Touchscreens
*
* Copyright (c) 2014 Red Hat Inc.
+ * Copyright (c) 2015 K. Merker <merker@debian.org>
*
* This code is based on gt9xx.c authored by andrew@goodix.com:
*
@@ -16,6 +17,8 @@
#include <linux/kernel.h>
#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
@@ -33,11 +36,24 @@ struct goodix_ts_data {
struct input_dev *input_dev;
int abs_x_max;
int abs_y_max;
+ bool swapped_x_y;
+ bool inverted_x;
+ bool inverted_y;
unsigned int max_touch_num;
unsigned int int_trigger_type;
- bool rotated_screen;
+ int cfg_len;
+ struct gpio_desc *gpiod_int;
+ struct gpio_desc *gpiod_rst;
+ u16 id;
+ u16 version;
+ const char *cfg_name;
+ struct completion firmware_loading_complete;
+ unsigned long irq_flags;
};
+#define GOODIX_GPIO_INT_NAME "irq"
+#define GOODIX_GPIO_RST_NAME "reset"
+
#define GOODIX_MAX_HEIGHT 4096
#define GOODIX_MAX_WIDTH 4096
#define GOODIX_INT_TRIGGER 1
@@ -45,8 +61,13 @@ struct goodix_ts_data {
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_CONFIG_MAX_LENGTH 240
+#define GOODIX_CONFIG_911_LENGTH 186
+#define GOODIX_CONFIG_967_LENGTH 228
/* Register defines */
+#define GOODIX_REG_COMMAND 0x8040
+#define GOODIX_CMD_SCREEN_OFF 0x05
+
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
@@ -115,6 +136,63 @@ static int goodix_i2c_read(struct i2c_client *client,
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
}
+/**
+ * goodix_i2c_write - write data to a register of the i2c slave device.
+ *
+ * @client: i2c device.
+ * @reg: the register to write to.
+ * @buf: raw data buffer to write.
+ * @len: length of the buffer to write
+ */
+static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
+ unsigned len)
+{
+ u8 *addr_buf;
+ struct i2c_msg msg;
+ int ret;
+
+ addr_buf = kmalloc(len + 2, GFP_KERNEL);
+ if (!addr_buf)
+ return -ENOMEM;
+
+ addr_buf[0] = reg >> 8;
+ addr_buf[1] = reg & 0xFF;
+ memcpy(&addr_buf[2], buf, len);
+
+ msg.flags = 0;
+ msg.addr = client->addr;
+ msg.buf = addr_buf;
+ msg.len = len + 2;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ kfree(addr_buf);
+ return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
+}
+
+static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
+{
+ return goodix_i2c_write(client, reg, &value, sizeof(value));
+}
+
+static int goodix_get_cfg_len(u16 id)
+{
+ switch (id) {
+ case 911:
+ case 9271:
+ case 9110:
+ case 927:
+ case 928:
+ return GOODIX_CONFIG_911_LENGTH;
+
+ case 912:
+ case 967:
+ return GOODIX_CONFIG_967_LENGTH;
+
+ default:
+ return GOODIX_CONFIG_MAX_LENGTH;
+ }
+}
+
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{
int touch_num;
@@ -155,10 +233,13 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]);
- if (ts->rotated_screen) {
+ /* Inversions have to happen before axis swapping */
+ if (ts->inverted_x)
input_x = ts->abs_x_max - input_x;
+ if (ts->inverted_y)
input_y = ts->abs_y_max - input_y;
- }
+ if (ts->swapped_x_y)
+ swap(input_x, input_y);
input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
@@ -202,21 +283,195 @@ static void goodix_process_events(struct goodix_ts_data *ts)
*/
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
- static const u8 end_cmd[] = {
- GOODIX_READ_COOR_ADDR >> 8,
- GOODIX_READ_COOR_ADDR & 0xff,
- 0
- };
struct goodix_ts_data *ts = dev_id;
goodix_process_events(ts);
- if (i2c_master_send(ts->client, end_cmd, sizeof(end_cmd)) < 0)
+ if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)
dev_err(&ts->client->dev, "I2C write end_cmd error\n");
return IRQ_HANDLED;
}
+static void goodix_free_irq(struct goodix_ts_data *ts)
+{
+ devm_free_irq(&ts->client->dev, ts->client->irq, ts);
+}
+
+static int goodix_request_irq(struct goodix_ts_data *ts)
+{
+ return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
+ NULL, goodix_ts_irq_handler,
+ ts->irq_flags, ts->client->name, ts);
+}
+
+/**
+ * goodix_check_cfg - Checks if config fw is valid
+ *
+ * @ts: goodix_ts_data pointer
+ * @cfg: firmware config data
+ */
+static int goodix_check_cfg(struct goodix_ts_data *ts,
+ const struct firmware *cfg)
+{
+ int i, raw_cfg_len;
+ u8 check_sum = 0;
+
+ if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
+ dev_err(&ts->client->dev,
+ "The length of the config fw is not correct");
+ return -EINVAL;
+ }
+
+ raw_cfg_len = cfg->size - 2;
+ for (i = 0; i < raw_cfg_len; i++)
+ check_sum += cfg->data[i];
+ check_sum = (~check_sum) + 1;
+ if (check_sum != cfg->data[raw_cfg_len]) {
+ dev_err(&ts->client->dev,
+ "The checksum of the config fw is not correct");
+ return -EINVAL;
+ }
+
+ if (cfg->data[raw_cfg_len + 1] != 1) {
+ dev_err(&ts->client->dev,
+ "Config fw must have Config_Fresh register set");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * goodix_send_cfg - Write fw config to device
+ *
+ * @ts: goodix_ts_data pointer
+ * @cfg: config firmware to write to device
+ */
+static int goodix_send_cfg(struct goodix_ts_data *ts,
+ const struct firmware *cfg)
+{
+ int error;
+
+ error = goodix_check_cfg(ts, cfg);
+ if (error)
+ return error;
+
+ error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,
+ cfg->size);
+ if (error) {
+ dev_err(&ts->client->dev, "Failed to write config data: %d",
+ error);
+ return error;
+ }
+ dev_dbg(&ts->client->dev, "Config sent successfully.");
+
+ /* Let the firmware reconfigure itself, so sleep for 10ms */
+ usleep_range(10000, 11000);
+
+ return 0;
+}
+
+static int goodix_int_sync(struct goodix_ts_data *ts)
+{
+ int error;
+
+ error = gpiod_direction_output(ts->gpiod_int, 0);
+ if (error)
+ return error;
+
+ msleep(50); /* T5: 50ms */
+
+ error = gpiod_direction_input(ts->gpiod_int);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+/**
+ * goodix_reset - Reset device during power on
+ *
+ * @ts: goodix_ts_data pointer
+ */
+static int goodix_reset(struct goodix_ts_data *ts)
+{
+ int error;
+
+ /* begin select I2C slave addr */
+ error = gpiod_direction_output(ts->gpiod_rst, 0);
+ if (error)
+ return error;
+
+ msleep(20); /* T2: > 10ms */
+
+ /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+ error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);
+ if (error)
+ return error;
+
+ usleep_range(100, 2000); /* T3: > 100us */
+
+ error = gpiod_direction_output(ts->gpiod_rst, 1);
+ if (error)
+ return error;
+
+ usleep_range(6000, 10000); /* T4: > 5ms */
+
+ /* end select I2C slave addr */
+ error = gpiod_direction_input(ts->gpiod_rst);
+ if (error)
+ return error;
+
+ error = goodix_int_sync(ts);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+/**
+ * goodix_get_gpio_config - Get GPIO config from ACPI/DT
+ *
+ * @ts: goodix_ts_data pointer
+ */
+static int goodix_get_gpio_config(struct goodix_ts_data *ts)
+{
+ int error;
+ struct device *dev;
+ struct gpio_desc *gpiod;
+
+ if (!ts->client)
+ return -EINVAL;
+ dev = &ts->client->dev;
+
+ /* Get the interrupt GPIO pin number */
+ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ error = PTR_ERR(gpiod);
+ if (error != -EPROBE_DEFER)
+ dev_dbg(dev, "Failed to get %s GPIO: %d\n",
+ GOODIX_GPIO_INT_NAME, error);
+ return error;
+ }
+
+ ts->gpiod_int = gpiod;
+
+ /* Get the reset line GPIO pin number */
+ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ error = PTR_ERR(gpiod);
+ if (error != -EPROBE_DEFER)
+ dev_dbg(dev, "Failed to get %s GPIO: %d\n",
+ GOODIX_GPIO_RST_NAME, error);
+ return error;
+ }
+
+ ts->gpiod_rst = gpiod;
+
+ return 0;
+}
+
/**
* goodix_read_config - Read the embedded configuration of the panel
*
@@ -230,14 +485,15 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int error;
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
- config,
- GOODIX_CONFIG_MAX_LENGTH);
+ config, ts->cfg_len);
if (error) {
dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n",
error);
ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT;
+ if (ts->swapped_x_y)
+ swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
@@ -245,6 +501,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
+ if (ts->swapped_x_y)
+ swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
if (!ts->abs_x_max || !ts->abs_y_max || !ts->max_touch_num) {
@@ -252,42 +510,45 @@ static void goodix_read_config(struct goodix_ts_data *ts)
"Invalid config, using defaults\n");
ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT;
+ if (ts->swapped_x_y)
+ swap(ts->abs_x_max, ts->abs_y_max);
ts->max_touch_num = GOODIX_MAX_CONTACTS;
}
- ts->rotated_screen = dmi_check_system(rotated_screen);
- if (ts->rotated_screen)
+ if (dmi_check_system(rotated_screen)) {
+ ts->inverted_x = true;
+ ts->inverted_y = true;
dev_dbg(&ts->client->dev,
"Applying '180 degrees rotated screen' quirk\n");
+ }
}
/**
* goodix_read_version - Read goodix touchscreen version
*
- * @client: the i2c client
- * @version: output buffer containing the version on success
- * @id: output buffer containing the id on success
+ * @ts: our goodix_ts_data pointer
*/
-static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id)
+static int goodix_read_version(struct goodix_ts_data *ts)
{
int error;
u8 buf[6];
char id_str[5];
- error = goodix_i2c_read(client, GOODIX_REG_ID, buf, sizeof(buf));
+ error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
- dev_err(&client->dev, "read version failed: %d\n", error);
+ dev_err(&ts->client->dev, "read version failed: %d\n", error);
return error;
}
memcpy(id_str, buf, 4);
id_str[4] = 0;
- if (kstrtou16(id_str, 10, id))
- *id = 0x1001;
+ if (kstrtou16(id_str, 10, &ts->id))
+ ts->id = 0x1001;
- *version = get_unaligned_le16(&buf[4]);
+ ts->version = get_unaligned_le16(&buf[4]);
- dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version);
+ dev_info(&ts->client->dev, "ID %d, version: %04x\n", ts->id,
+ ts->version);
return 0;
}
@@ -321,13 +582,10 @@ static int goodix_i2c_test(struct i2c_client *client)
* goodix_request_input_dev - Allocate, populate and register the input device
*
* @ts: our goodix_ts_data pointer
- * @version: device firmware version
- * @id: device ID
*
* Must be called during probe
*/
-static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
- u16 id)
+static int goodix_request_input_dev(struct goodix_ts_data *ts)
{
int error;
@@ -351,8 +609,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
ts->input_dev->phys = "input/ts";
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0x0416;
- ts->input_dev->id.product = id;
- ts->input_dev->id.version = version;
+ ts->input_dev->id.product = ts->id;
+ ts->input_dev->id.version = ts->version;
error = input_register_device(ts->input_dev);
if (error) {
@@ -364,13 +622,75 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
return 0;
}
+/**
+ * goodix_configure_dev - Finish device initialization
+ *
+ * @ts: our goodix_ts_data pointer
+ *
+ * Must be called from probe to finish initialization of the device.
+ * Contains the common initialization code for both devices that
+ * declare gpio pins and devices that do not. It is either called
+ * directly from probe or from request_firmware_wait callback.
+ */
+static int goodix_configure_dev(struct goodix_ts_data *ts)
+{
+ int error;
+
+ ts->swapped_x_y = device_property_read_bool(&ts->client->dev,
+ "touchscreen-swapped-x-y");
+ ts->inverted_x = device_property_read_bool(&ts->client->dev,
+ "touchscreen-inverted-x");
+ ts->inverted_y = device_property_read_bool(&ts->client->dev,
+ "touchscreen-inverted-y");
+
+ goodix_read_config(ts);
+
+ error = goodix_request_input_dev(ts);
+ if (error)
+ return error;
+
+ ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
+ error = goodix_request_irq(ts);
+ if (error) {
+ dev_err(&ts->client->dev, "request IRQ failed: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+/**
+ * goodix_config_cb - Callback to finish device init
+ *
+ * @ts: our goodix_ts_data pointer
+ *
+ * request_firmware_wait callback that finishes
+ * initialization of the device.
+ */
+static void goodix_config_cb(const struct firmware *cfg, void *ctx)
+{
+ struct goodix_ts_data *ts = ctx;
+ int error;
+
+ if (cfg) {
+ /* send device configuration to the firmware */
+ error = goodix_send_cfg(ts, cfg);
+ if (error)
+ goto err_release_cfg;
+ }
+
+ goodix_configure_dev(ts);
+
+err_release_cfg:
+ release_firmware(cfg);
+ complete_all(&ts->firmware_loading_complete);
+}
+
static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct goodix_ts_data *ts;
- unsigned long irq_flags;
int error;
- u16 version_info, id_info;
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
@@ -385,6 +705,20 @@ static int goodix_ts_probe(struct i2c_client *client,
ts->client = client;
i2c_set_clientdata(client, ts);
+ init_completion(&ts->firmware_loading_complete);
+
+ error = goodix_get_gpio_config(ts);
+ if (error)
+ return error;
+
+ if (ts->gpiod_int && ts->gpiod_rst) {
+ /* reset the controller */
+ error = goodix_reset(ts);
+ if (error) {
+ dev_err(&client->dev, "Controller reset failed.\n");
+ return error;
+ }
+ }
error = goodix_i2c_test(client);
if (error) {
@@ -392,30 +726,125 @@ static int goodix_ts_probe(struct i2c_client *client,
return error;
}
- error = goodix_read_version(client, &version_info, &id_info);
+ error = goodix_read_version(ts);
if (error) {
dev_err(&client->dev, "Read version failed.\n");
return error;
}
- goodix_read_config(ts);
+ ts->cfg_len = goodix_get_cfg_len(ts->id);
+
+ if (ts->gpiod_int && ts->gpiod_rst) {
+ /* update device config */
+ ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
+ "goodix_%d_cfg.bin", ts->id);
+ if (!ts->cfg_name)
+ return -ENOMEM;
+
+ error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
+ &client->dev, GFP_KERNEL, ts,
+ goodix_config_cb);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to invoke firmware loader: %d\n",
+ error);
+ return error;
+ }
- error = goodix_request_input_dev(ts, version_info, id_info);
- if (error)
- return error;
+ return 0;
+ } else {
+ error = goodix_configure_dev(ts);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static int goodix_ts_remove(struct i2c_client *client)
+{
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->gpiod_int && ts->gpiod_rst)
+ wait_for_completion(&ts->firmware_loading_complete);
+
+ return 0;
+}
+
+static int __maybe_unused goodix_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ int error;
- irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
- error = devm_request_threaded_irq(&ts->client->dev, client->irq,
- NULL, goodix_ts_irq_handler,
- irq_flags, client->name, ts);
+ /* We need gpio pins to suspend/resume */
+ if (!ts->gpiod_int || !ts->gpiod_rst)
+ return 0;
+
+ wait_for_completion(&ts->firmware_loading_complete);
+
+ /* Free IRQ as IRQ pin is used as output in the suspend sequence */
+ goodix_free_irq(ts);
+
+ /* Output LOW on the INT pin for 5 ms */
+ error = gpiod_direction_output(ts->gpiod_int, 0);
if (error) {
- dev_err(&client->dev, "request IRQ failed: %d\n", error);
+ goodix_request_irq(ts);
return error;
}
+ usleep_range(5000, 6000);
+
+ error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
+ GOODIX_CMD_SCREEN_OFF);
+ if (error) {
+ dev_err(&ts->client->dev, "Screen off command failed\n");
+ gpiod_direction_input(ts->gpiod_int);
+ goodix_request_irq(ts);
+ return -EAGAIN;
+ }
+
+ /*
+ * The datasheet specifies that the interval between sending screen-off
+ * command and wake-up should be longer than 58 ms. To avoid waking up
+ * sooner, delay 58ms here.
+ */
+ msleep(58);
+ return 0;
+}
+
+static int __maybe_unused goodix_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ int error;
+
+ if (!ts->gpiod_int || !ts->gpiod_rst)
+ return 0;
+
+ /*
+ * Exit sleep mode by outputting HIGH level to INT pin
+ * for 2ms~5ms.
+ */
+ error = gpiod_direction_output(ts->gpiod_int, 1);
+ if (error)
+ return error;
+
+ usleep_range(2000, 5000);
+
+ error = goodix_int_sync(ts);
+ if (error)
+ return error;
+
+ error = goodix_request_irq(ts);
+ if (error)
+ return error;
+
return 0;
}
+static SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
+
static const struct i2c_device_id goodix_ts_id[] = {
{ "GDIX1001:00", 0 },
{ }
@@ -446,11 +875,13 @@ MODULE_DEVICE_TABLE(of, goodix_of_match);
static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe,
+ .remove = goodix_ts_remove,
.id_table = goodix_ts_id,
.driver = {
.name = "Goodix-TS",
.acpi_match_table = ACPI_PTR(goodix_acpi_match),
.of_match_table = of_match_ptr(goodix_of_match),
+ .pm = &goodix_pm_ops,
},
};
module_i2c_driver(goodix_ts_driver);
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c
index 23a354a392ae..0e3fc419a3cf 100644
--- a/drivers/input/touchscreen/pcap_ts.c
+++ b/drivers/input/touchscreen/pcap_ts.c
@@ -87,7 +87,7 @@ static void pcap_ts_read_xy(void *data, u16 res[2])
static void pcap_ts_work(struct work_struct *work)
{
- struct delayed_work *dw = container_of(work, struct delayed_work, work);
+ struct delayed_work *dw = to_delayed_work(work);
struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
u8 ch[2];
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 4b961ad9f0b5..09523a3d3f23 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -38,6 +38,8 @@ struct pixcir_i2c_ts_data {
struct input_dev *input;
struct gpio_desc *gpio_attb;
struct gpio_desc *gpio_reset;
+ struct gpio_desc *gpio_enable;
+ struct gpio_desc *gpio_wake;
const struct pixcir_i2c_chip_data *chip;
int max_fingers; /* Max fingers supported in this instance */
bool running;
@@ -208,6 +210,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
struct device *dev = &ts->client->dev;
int ret;
+ if (mode == PIXCIR_POWER_ACTIVE || mode == PIXCIR_POWER_IDLE) {
+ if (ts->gpio_wake)
+ gpiod_set_value_cansleep(ts->gpio_wake, 1);
+ }
+
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n",
@@ -228,6 +235,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
return ret;
}
+ if (mode == PIXCIR_POWER_HALT) {
+ if (ts->gpio_wake)
+ gpiod_set_value_cansleep(ts->gpio_wake, 0);
+ }
+
return 0;
}
@@ -302,6 +314,11 @@ static int pixcir_start(struct pixcir_i2c_ts_data *ts)
struct device *dev = &ts->client->dev;
int error;
+ if (ts->gpio_enable) {
+ gpiod_set_value_cansleep(ts->gpio_enable, 1);
+ msleep(100);
+ }
+
/* LEVEL_TOUCH interrupt with active low polarity */
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
if (error) {
@@ -343,6 +360,9 @@ static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
/* Wait till running ISR is complete */
synchronize_irq(ts->client->irq);
+ if (ts->gpio_enable)
+ gpiod_set_value_cansleep(ts->gpio_enable, 0);
+
return 0;
}
@@ -534,6 +554,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return error;
}
+ tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(tsdata->gpio_wake)) {
+ error = PTR_ERR(tsdata->gpio_wake);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get wake gpio: %d\n", error);
+ return error;
+ }
+
+ tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(tsdata->gpio_enable)) {
+ error = PTR_ERR(tsdata->gpio_enable);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get enable gpio: %d\n", error);
+ return error;
+ }
+
+ if (tsdata->gpio_enable)
+ msleep(100);
+
error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
index ba6024f93469..611156a2ef80 100644
--- a/drivers/input/touchscreen/rohm_bu21023.c
+++ b/drivers/input/touchscreen/rohm_bu21023.c
@@ -725,7 +725,7 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
break;
error = -EIO;
- } while (++retry >= FIRMWARE_RETRY_MAX);
+ } while (++retry <= FIRMWARE_RETRY_MAX);
out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 191a1b87895f..a21a07c3ab6d 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -273,8 +273,6 @@ static irqreturn_t titsc_irq(int irq, void *dev)
status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
if (status & IRQENB_HW_PEN) {
ts_dev->pen_down = true;
- titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
- titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
irqclr |= IRQENB_HW_PEN;
}
diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c
new file mode 100644
index 000000000000..3c3dd78303be
--- /dev/null
+++ b/drivers/input/touchscreen/ts4800-ts.c
@@ -0,0 +1,216 @@
+/*
+ * Touchscreen driver for the TS-4800 board
+ *
+ * Copyright (c) 2015 - Savoir-faire Linux
+ *
+ * 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/bitops.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* polling interval in ms */
+#define POLL_INTERVAL 3
+
+#define DEBOUNCE_COUNT 1
+
+/* sensor values are 12-bit wide */
+#define MAX_12BIT ((1 << 12) - 1)
+
+#define PENDOWN_MASK 0x1
+
+#define X_OFFSET 0x0
+#define Y_OFFSET 0x2
+
+struct ts4800_ts {
+ struct input_polled_dev *poll_dev;
+ struct device *dev;
+ char phys[32];
+
+ void __iomem *base;
+ struct regmap *regmap;
+ unsigned int reg;
+ unsigned int bit;
+
+ bool pendown;
+ int debounce;
+};
+
+static void ts4800_ts_open(struct input_polled_dev *dev)
+{
+ struct ts4800_ts *ts = dev->private;
+ int ret;
+
+ ts->pendown = false;
+ ts->debounce = DEBOUNCE_COUNT;
+
+ ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit);
+ if (ret)
+ dev_warn(ts->dev, "Failed to enable touchscreen\n");
+}
+
+static void ts4800_ts_close(struct input_polled_dev *dev)
+{
+ struct ts4800_ts *ts = dev->private;
+ int ret;
+
+ ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0);
+ if (ret)
+ dev_warn(ts->dev, "Failed to disable touchscreen\n");
+
+}
+
+static void ts4800_ts_poll(struct input_polled_dev *dev)
+{
+ struct input_dev *input_dev = dev->input;
+ struct ts4800_ts *ts = dev->private;
+ u16 last_x = readw(ts->base + X_OFFSET);
+ u16 last_y = readw(ts->base + Y_OFFSET);
+ bool pendown = last_x & PENDOWN_MASK;
+
+ if (pendown) {
+ if (ts->debounce) {
+ ts->debounce--;
+ return;
+ }
+
+ if (!ts->pendown) {
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ ts->pendown = true;
+ }
+
+ last_x = ((~last_x) >> 4) & MAX_12BIT;
+ last_y = ((~last_y) >> 4) & MAX_12BIT;
+
+ input_report_abs(input_dev, ABS_X, last_x);
+ input_report_abs(input_dev, ABS_Y, last_y);
+ input_sync(input_dev);
+ } else if (ts->pendown) {
+ ts->pendown = false;
+ ts->debounce = DEBOUNCE_COUNT;
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_sync(input_dev);
+ }
+}
+
+static int ts4800_parse_dt(struct platform_device *pdev,
+ struct ts4800_ts *ts)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *syscon_np;
+ u32 reg, bit;
+ int error;
+
+ syscon_np = of_parse_phandle(np, "syscon", 0);
+ if (!syscon_np) {
+ dev_err(dev, "no syscon property\n");
+ return -ENODEV;
+ }
+
+ error = of_property_read_u32_index(np, "syscon", 1, &reg);
+ if (error < 0) {
+ dev_err(dev, "no offset in syscon\n");
+ return error;
+ }
+
+ ts->reg = reg;
+
+ error = of_property_read_u32_index(np, "syscon", 2, &bit);
+ if (error < 0) {
+ dev_err(dev, "no bit in syscon\n");
+ return error;
+ }
+
+ ts->bit = BIT(bit);
+
+ ts->regmap = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(ts->regmap)) {
+ dev_err(dev, "cannot get parent's regmap\n");
+ return PTR_ERR(ts->regmap);
+ }
+
+ return 0;
+}
+
+static int ts4800_ts_probe(struct platform_device *pdev)
+{
+ struct input_polled_dev *poll_dev;
+ struct ts4800_ts *ts;
+ struct resource *res;
+ int error;
+
+ ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ error = ts4800_parse_dt(pdev, ts);
+ if (error)
+ return error;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ts->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ts->base))
+ return PTR_ERR(ts->base);
+
+ poll_dev = devm_input_allocate_polled_device(&pdev->dev);
+ if (!poll_dev)
+ return -ENOMEM;
+
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev));
+ ts->poll_dev = poll_dev;
+ ts->dev = &pdev->dev;
+
+ poll_dev->private = ts;
+ poll_dev->poll_interval = POLL_INTERVAL;
+ poll_dev->open = ts4800_ts_open;
+ poll_dev->close = ts4800_ts_close;
+ poll_dev->poll = ts4800_ts_poll;
+
+ poll_dev->input->name = "TS-4800 Touchscreen";
+ poll_dev->input->phys = ts->phys;
+
+ input_set_capability(poll_dev->input, EV_KEY, BTN_TOUCH);
+ input_set_abs_params(poll_dev->input, ABS_X, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(poll_dev->input, ABS_Y, 0, MAX_12BIT, 0, 0);
+
+ error = input_register_polled_device(poll_dev);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Unabled to register polled input device (%d)\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id ts4800_ts_of_match[] = {
+ { .compatible = "technologic,ts4800-ts", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ts4800_ts_of_match);
+
+static struct platform_driver ts4800_ts_driver = {
+ .driver = {
+ .name = "ts4800-ts",
+ .of_match_table = ts4800_ts_of_match,
+ },
+ .probe = ts4800_ts_probe,
+};
+module_platform_driver(ts4800_ts_driver);
+
+MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("TS-4800 Touchscreen Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ts4800_ts");
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 2792ca397dd0..bab3c6acf6a2 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -80,7 +80,8 @@ struct w8001_touch_query {
*/
struct w8001 {
- struct input_dev *dev;
+ struct input_dev *pen_dev;
+ struct input_dev *touch_dev;
struct serio *serio;
struct completion cmd_done;
int id;
@@ -95,7 +96,10 @@ struct w8001 {
u16 max_touch_y;
u16 max_pen_x;
u16 max_pen_y;
- char name[64];
+ char pen_name[64];
+ char touch_name[64];
+ int open_count;
+ struct mutex mutex;
};
static void parse_pen_data(u8 *data, struct w8001_coord *coord)
@@ -141,7 +145,7 @@ static void scale_touch_coordinates(struct w8001 *w8001,
static void parse_multi_touch(struct w8001 *w8001)
{
- struct input_dev *dev = w8001->dev;
+ struct input_dev *dev = w8001->touch_dev;
unsigned char *data = w8001->data;
unsigned int x, y;
int i;
@@ -151,7 +155,6 @@ static void parse_multi_touch(struct w8001 *w8001)
bool touch = data[0] & (1 << i);
input_mt_slot(dev, i);
- input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
if (touch) {
x = (data[6 * i + 1] << 7) | data[6 * i + 2];
y = (data[6 * i + 3] << 7) | data[6 * i + 4];
@@ -207,7 +210,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
{
- struct input_dev *dev = w8001->dev;
+ struct input_dev *dev = w8001->pen_dev;
/*
* We have 1 bit for proximity (rdy) and 3 bits for tip, side,
@@ -233,11 +236,6 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
break;
case BTN_TOOL_FINGER:
- input_report_key(dev, BTN_TOUCH, 0);
- input_report_key(dev, BTN_TOOL_FINGER, 0);
- input_sync(dev);
- /* fall through */
-
case KEY_RESERVED:
w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
break;
@@ -261,7 +259,7 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
{
- struct input_dev *dev = w8001->dev;
+ struct input_dev *dev = w8001->touch_dev;
unsigned int x = coord->x;
unsigned int y = coord->y;
@@ -271,7 +269,6 @@ static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_report_key(dev, BTN_TOUCH, coord->tsw);
- input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
input_sync(dev);
@@ -369,22 +366,36 @@ static int w8001_command(struct w8001 *w8001, unsigned char command,
static int w8001_open(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
+ int err;
- return w8001_command(w8001, W8001_CMD_START, false);
+ err = mutex_lock_interruptible(&w8001->mutex);
+ if (err)
+ return err;
+
+ if (w8001->open_count++ == 0) {
+ err = w8001_command(w8001, W8001_CMD_START, false);
+ if (err)
+ w8001->open_count--;
+ }
+
+ mutex_unlock(&w8001->mutex);
+ return err;
}
static void w8001_close(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
- w8001_command(w8001, W8001_CMD_STOP, false);
+ mutex_lock(&w8001->mutex);
+
+ if (--w8001->open_count == 0)
+ w8001_command(w8001, W8001_CMD_STOP, false);
+
+ mutex_unlock(&w8001->mutex);
}
-static int w8001_setup(struct w8001 *w8001)
+static int w8001_detect(struct w8001 *w8001)
{
- struct input_dev *dev = w8001->dev;
- struct w8001_coord coord;
- struct w8001_touch_query touch;
int error;
error = w8001_command(w8001, W8001_CMD_STOP, false);
@@ -393,105 +404,145 @@ static int w8001_setup(struct w8001 *w8001)
msleep(250); /* wait 250ms before querying the device */
- dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
+ return 0;
+}
- __set_bit(INPUT_PROP_DIRECT, dev->propbit);
+static int w8001_setup_pen(struct w8001 *w8001, char *basename,
+ size_t basename_sz)
+{
+ struct input_dev *dev = w8001->pen_dev;
+ struct w8001_coord coord;
+ int error;
/* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true);
- if (!error) {
- __set_bit(BTN_TOUCH, dev->keybit);
- __set_bit(BTN_TOOL_PEN, dev->keybit);
- __set_bit(BTN_TOOL_RUBBER, dev->keybit);
- __set_bit(BTN_STYLUS, dev->keybit);
- __set_bit(BTN_STYLUS2, dev->keybit);
-
- parse_pen_data(w8001->response, &coord);
- w8001->max_pen_x = coord.x;
- w8001->max_pen_y = coord.y;
-
- input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
- input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
- input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
- input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
- input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
- if (coord.tilt_x && coord.tilt_y) {
- input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
- input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
- }
- w8001->id = 0x90;
- strlcat(w8001->name, " Penabled", sizeof(w8001->name));
+ if (error)
+ return error;
+
+ __set_bit(EV_KEY, dev->evbit);
+ __set_bit(EV_ABS, dev->evbit);
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_PEN, dev->keybit);
+ __set_bit(BTN_TOOL_RUBBER, dev->keybit);
+ __set_bit(BTN_STYLUS, dev->keybit);
+ __set_bit(BTN_STYLUS2, dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, dev->propbit);
+
+ parse_pen_data(w8001->response, &coord);
+ w8001->max_pen_x = coord.x;
+ w8001->max_pen_y = coord.y;
+
+ input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+ input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
+ input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
+ input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
+ if (coord.tilt_x && coord.tilt_y) {
+ input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
+ input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
}
+ w8001->id = 0x90;
+ strlcat(basename, " Penabled", basename_sz);
+
+ return 0;
+}
+
+static int w8001_setup_touch(struct w8001 *w8001, char *basename,
+ size_t basename_sz)
+{
+ struct input_dev *dev = w8001->touch_dev;
+ struct w8001_touch_query touch;
+ int error;
+
+
/* Touch enabled? */
error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
-
+ if (error)
+ return error;
/*
* Some non-touch devices may reply to the touch query. But their
* second byte is empty, which indicates touch is not supported.
*/
- if (!error && w8001->response[1]) {
- __set_bit(BTN_TOUCH, dev->keybit);
- __set_bit(BTN_TOOL_FINGER, dev->keybit);
-
- parse_touchquery(w8001->response, &touch);
- w8001->max_touch_x = touch.x;
- w8001->max_touch_y = touch.y;
-
- if (w8001->max_pen_x && w8001->max_pen_y) {
- /* if pen is supported scale to pen maximum */
- touch.x = w8001->max_pen_x;
- touch.y = w8001->max_pen_y;
- touch.panel_res = W8001_PEN_RESOLUTION;
- }
+ if (!w8001->response[1])
+ return -ENXIO;
- input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
- input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
- input_abs_set_res(dev, ABS_X, touch.panel_res);
- input_abs_set_res(dev, ABS_Y, touch.panel_res);
-
- switch (touch.sensor_id) {
- case 0:
- case 2:
- w8001->pktlen = W8001_PKTLEN_TOUCH93;
- w8001->id = 0x93;
- strlcat(w8001->name, " 1FG", sizeof(w8001->name));
- break;
+ __set_bit(EV_KEY, dev->evbit);
+ __set_bit(EV_ABS, dev->evbit);
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, dev->propbit);
- case 1:
- case 3:
- case 4:
- w8001->pktlen = W8001_PKTLEN_TOUCH9A;
- strlcat(w8001->name, " 1FG", sizeof(w8001->name));
- w8001->id = 0x9a;
- break;
+ parse_touchquery(w8001->response, &touch);
+ w8001->max_touch_x = touch.x;
+ w8001->max_touch_y = touch.y;
- case 5:
- w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
-
- input_mt_init_slots(dev, 2, 0);
- input_set_abs_params(dev, ABS_MT_POSITION_X,
- 0, touch.x, 0, 0);
- input_set_abs_params(dev, ABS_MT_POSITION_Y,
- 0, touch.y, 0, 0);
- input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
- 0, MT_TOOL_MAX, 0, 0);
-
- strlcat(w8001->name, " 2FG", sizeof(w8001->name));
- if (w8001->max_pen_x && w8001->max_pen_y)
- w8001->id = 0xE3;
- else
- w8001->id = 0xE2;
- break;
- }
+ if (w8001->max_pen_x && w8001->max_pen_y) {
+ /* if pen is supported scale to pen maximum */
+ touch.x = w8001->max_pen_x;
+ touch.y = w8001->max_pen_y;
+ touch.panel_res = W8001_PEN_RESOLUTION;
+ }
+
+ input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
+ input_abs_set_res(dev, ABS_X, touch.panel_res);
+ input_abs_set_res(dev, ABS_Y, touch.panel_res);
+
+ switch (touch.sensor_id) {
+ case 0:
+ case 2:
+ w8001->pktlen = W8001_PKTLEN_TOUCH93;
+ w8001->id = 0x93;
+ strlcat(basename, " 1FG", basename_sz);
+ break;
+
+ case 1:
+ case 3:
+ case 4:
+ w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+ strlcat(basename, " 1FG", basename_sz);
+ w8001->id = 0x9a;
+ break;
+
+ case 5:
+ w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+
+ __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+ input_mt_init_slots(dev, 2, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_X,
+ 0, touch.x, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y,
+ 0, touch.y, 0, 0);
+
+ strlcat(basename, " 2FG", basename_sz);
+ if (w8001->max_pen_x && w8001->max_pen_y)
+ w8001->id = 0xE3;
+ else
+ w8001->id = 0xE2;
+ break;
}
- strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
+ strlcat(basename, " Touchscreen", basename_sz);
return 0;
}
+static void w8001_set_devdata(struct input_dev *dev, struct w8001 *w8001,
+ struct serio *serio)
+{
+ dev->phys = w8001->phys;
+ dev->id.bustype = BUS_RS232;
+ dev->id.product = w8001->id;
+ dev->id.vendor = 0x056a;
+ dev->id.version = 0x0100;
+ dev->open = w8001_open;
+ dev->close = w8001_close;
+
+ dev->dev.parent = &serio->dev;
+
+ input_set_drvdata(dev, w8001);
+}
+
/*
* w8001_disconnect() is the opposite of w8001_connect()
*/
@@ -502,7 +553,10 @@ static void w8001_disconnect(struct serio *serio)
serio_close(serio);
- input_unregister_device(w8001->dev);
+ if (w8001->pen_dev)
+ input_unregister_device(w8001->pen_dev);
+ if (w8001->touch_dev)
+ input_unregister_device(w8001->touch_dev);
kfree(w8001);
serio_set_drvdata(serio, NULL);
@@ -517,18 +571,23 @@ static void w8001_disconnect(struct serio *serio)
static int w8001_connect(struct serio *serio, struct serio_driver *drv)
{
struct w8001 *w8001;
- struct input_dev *input_dev;
- int err;
+ struct input_dev *input_dev_pen;
+ struct input_dev *input_dev_touch;
+ char basename[64];
+ int err, err_pen, err_touch;
w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!w8001 || !input_dev) {
+ input_dev_pen = input_allocate_device();
+ input_dev_touch = input_allocate_device();
+ if (!w8001 || !input_dev_pen || !input_dev_touch) {
err = -ENOMEM;
goto fail1;
}
w8001->serio = serio;
- w8001->dev = input_dev;
+ w8001->pen_dev = input_dev_pen;
+ w8001->touch_dev = input_dev_touch;
+ mutex_init(&w8001->mutex);
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
@@ -537,35 +596,67 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
if (err)
goto fail2;
- err = w8001_setup(w8001);
+ err = w8001_detect(w8001);
if (err)
goto fail3;
- input_dev->name = w8001->name;
- input_dev->phys = w8001->phys;
- input_dev->id.product = w8001->id;
- input_dev->id.bustype = BUS_RS232;
- input_dev->id.vendor = 0x056a;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &serio->dev;
+ /* For backwards-compatibility we compose the basename based on
+ * capabilities and then just append the tool type
+ */
+ strlcpy(basename, "Wacom Serial", sizeof(basename));
+
+ err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
+ err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
+ if (err_pen && err_touch) {
+ err = -ENXIO;
+ goto fail3;
+ }
+
+ if (!err_pen) {
+ strlcpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
+ strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
+ input_dev_pen->name = w8001->pen_name;
- input_dev->open = w8001_open;
- input_dev->close = w8001_close;
+ w8001_set_devdata(input_dev_pen, w8001, serio);
- input_set_drvdata(input_dev, w8001);
+ err = input_register_device(w8001->pen_dev);
+ if (err)
+ goto fail3;
+ } else {
+ input_free_device(input_dev_pen);
+ input_dev_pen = NULL;
+ w8001->pen_dev = NULL;
+ }
- err = input_register_device(w8001->dev);
- if (err)
- goto fail3;
+ if (!err_touch) {
+ strlcpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
+ strlcat(w8001->touch_name, " Finger",
+ sizeof(w8001->touch_name));
+ input_dev_touch->name = w8001->touch_name;
+
+ w8001_set_devdata(input_dev_touch, w8001, serio);
+
+ err = input_register_device(w8001->touch_dev);
+ if (err)
+ goto fail4;
+ } else {
+ input_free_device(input_dev_touch);
+ input_dev_touch = NULL;
+ w8001->touch_dev = NULL;
+ }
return 0;
+fail4:
+ if (w8001->pen_dev)
+ input_unregister_device(w8001->pen_dev);
fail3:
serio_close(serio);
fail2:
serio_set_drvdata(serio, NULL);
fail1:
- input_free_device(input_dev);
+ input_free_device(input_dev_pen);
+ input_free_device(input_dev_touch);
kfree(w8001);
return err;
}
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index b9094e9da537..a1e75cba18e0 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -263,81 +263,6 @@ config EXYNOS_IOMMU_DEBUG
Say N unless you need kernel log message for IOMMU debugging.
-config SHMOBILE_IPMMU
- bool
-
-config SHMOBILE_IPMMU_TLB
- bool
-
-config SHMOBILE_IOMMU
- bool "IOMMU for Renesas IPMMU/IPMMUI"
- default n
- depends on ARM && MMU
- depends on ARCH_SHMOBILE || COMPILE_TEST
- select IOMMU_API
- select ARM_DMA_USE_IOMMU
- select SHMOBILE_IPMMU
- select SHMOBILE_IPMMU_TLB
- help
- Support for Renesas IPMMU/IPMMUI. This option enables
- remapping of DMA memory accesses from all of the IP blocks
- on the ICB.
-
- Warning: Drivers (including userspace drivers of UIO
- devices) of the IP blocks on the ICB *must* use addresses
- allocated from the IPMMU (iova) for DMA with this option
- enabled.
-
- If unsure, say N.
-
-choice
- prompt "IPMMU/IPMMUI address space size"
- default SHMOBILE_IOMMU_ADDRSIZE_2048MB
- depends on SHMOBILE_IOMMU
- help
- This option sets IPMMU/IPMMUI address space size by
- adjusting the 1st level page table size. The page table size
- is calculated as follows:
-
- page table size = number of page table entries * 4 bytes
- number of page table entries = address space size / 1 MiB
-
- For example, when the address space size is 2048 MiB, the
- 1st level page table size is 8192 bytes.
-
- config SHMOBILE_IOMMU_ADDRSIZE_2048MB
- bool "2 GiB"
-
- config SHMOBILE_IOMMU_ADDRSIZE_1024MB
- bool "1 GiB"
-
- config SHMOBILE_IOMMU_ADDRSIZE_512MB
- bool "512 MiB"
-
- config SHMOBILE_IOMMU_ADDRSIZE_256MB
- bool "256 MiB"
-
- config SHMOBILE_IOMMU_ADDRSIZE_128MB
- bool "128 MiB"
-
- config SHMOBILE_IOMMU_ADDRSIZE_64MB
- bool "64 MiB"
-
- config SHMOBILE_IOMMU_ADDRSIZE_32MB
- bool "32 MiB"
-
-endchoice
-
-config SHMOBILE_IOMMU_L1SIZE
- int
- default 8192 if SHMOBILE_IOMMU_ADDRSIZE_2048MB
- default 4096 if SHMOBILE_IOMMU_ADDRSIZE_1024MB
- default 2048 if SHMOBILE_IOMMU_ADDRSIZE_512MB
- default 1024 if SHMOBILE_IOMMU_ADDRSIZE_256MB
- default 512 if SHMOBILE_IOMMU_ADDRSIZE_128MB
- default 256 if SHMOBILE_IOMMU_ADDRSIZE_64MB
- default 128 if SHMOBILE_IOMMU_ADDRSIZE_32MB
-
config IPMMU_VMSA
bool "Renesas VMSA-compatible IPMMU"
depends on ARM_LPAE
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 68faca02225d..42fc0c25cf1a 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -22,7 +22,5 @@ obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
-obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o
-obj-$(CONFIG_SHMOBILE_IPMMU) += shmobile-ipmmu.o
obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 8b2be1e7714f..539b0dea8034 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -35,6 +35,7 @@
#include <linux/msi.h>
#include <linux/dma-contiguous.h>
#include <linux/irqdomain.h>
+#include <linux/percpu.h>
#include <asm/irq_remapping.h>
#include <asm/io_apic.h>
#include <asm/apic.h>
@@ -114,6 +115,45 @@ struct kmem_cache *amd_iommu_irq_cache;
static void update_domain(struct protection_domain *domain);
static int protection_domain_init(struct protection_domain *domain);
+/*
+ * For dynamic growth the aperture size is split into ranges of 128MB of
+ * DMA address space each. This struct represents one such range.
+ */
+struct aperture_range {
+
+ spinlock_t bitmap_lock;
+
+ /* address allocation bitmap */
+ unsigned long *bitmap;
+ unsigned long offset;
+ unsigned long next_bit;
+
+ /*
+ * Array of PTE pages for the aperture. In this array we save all the
+ * leaf pages of the domain page table used for the aperture. This way
+ * we don't need to walk the page table to find a specific PTE. We can
+ * just calculate its address in constant time.
+ */
+ u64 *pte_pages[64];
+};
+
+/*
+ * Data container for a dma_ops specific protection domain
+ */
+struct dma_ops_domain {
+ /* generic protection domain information */
+ struct protection_domain domain;
+
+ /* size of the aperture for the mappings */
+ unsigned long aperture_size;
+
+ /* aperture index we start searching for free addresses */
+ u32 __percpu *next_index;
+
+ /* address space relevant data */
+ struct aperture_range *aperture[APERTURE_MAX_RANGES];
+};
+
/****************************************************************************
*
* Helper functions
@@ -1167,11 +1207,21 @@ static u64 *alloc_pte(struct protection_domain *domain,
end_lvl = PAGE_SIZE_LEVEL(page_size);
while (level > end_lvl) {
- if (!IOMMU_PTE_PRESENT(*pte)) {
+ u64 __pte, __npte;
+
+ __pte = *pte;
+
+ if (!IOMMU_PTE_PRESENT(__pte)) {
page = (u64 *)get_zeroed_page(gfp);
if (!page)
return NULL;
- *pte = PM_LEVEL_PDE(level, virt_to_phys(page));
+
+ __npte = PM_LEVEL_PDE(level, virt_to_phys(page));
+
+ if (cmpxchg64(pte, __pte, __npte)) {
+ free_page((unsigned long)page);
+ continue;
+ }
}
/* No level skipping support yet */
@@ -1376,8 +1426,10 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
bool populate, gfp_t gfp)
{
int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
- struct amd_iommu *iommu;
unsigned long i, old_size, pte_pgsize;
+ struct aperture_range *range;
+ struct amd_iommu *iommu;
+ unsigned long flags;
#ifdef CONFIG_IOMMU_STRESS
populate = false;
@@ -1386,15 +1438,17 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
if (index >= APERTURE_MAX_RANGES)
return -ENOMEM;
- dma_dom->aperture[index] = kzalloc(sizeof(struct aperture_range), gfp);
- if (!dma_dom->aperture[index])
+ range = kzalloc(sizeof(struct aperture_range), gfp);
+ if (!range)
return -ENOMEM;
- dma_dom->aperture[index]->bitmap = (void *)get_zeroed_page(gfp);
- if (!dma_dom->aperture[index]->bitmap)
+ range->bitmap = (void *)get_zeroed_page(gfp);
+ if (!range->bitmap)
goto out_free;
- dma_dom->aperture[index]->offset = dma_dom->aperture_size;
+ range->offset = dma_dom->aperture_size;
+
+ spin_lock_init(&range->bitmap_lock);
if (populate) {
unsigned long address = dma_dom->aperture_size;
@@ -1407,14 +1461,20 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
if (!pte)
goto out_free;
- dma_dom->aperture[index]->pte_pages[i] = pte_page;
+ range->pte_pages[i] = pte_page;
address += APERTURE_RANGE_SIZE / 64;
}
}
- old_size = dma_dom->aperture_size;
- dma_dom->aperture_size += APERTURE_RANGE_SIZE;
+ spin_lock_irqsave(&dma_dom->domain.lock, flags);
+
+ /* First take the bitmap_lock and then publish the range */
+ spin_lock(&range->bitmap_lock);
+
+ old_size = dma_dom->aperture_size;
+ dma_dom->aperture[index] = range;
+ dma_dom->aperture_size += APERTURE_RANGE_SIZE;
/* Reserve address range used for MSI messages */
if (old_size < MSI_ADDR_BASE_LO &&
@@ -1461,62 +1521,123 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
update_domain(&dma_dom->domain);
+ spin_unlock(&range->bitmap_lock);
+
+ spin_unlock_irqrestore(&dma_dom->domain.lock, flags);
+
return 0;
out_free:
update_domain(&dma_dom->domain);
- free_page((unsigned long)dma_dom->aperture[index]->bitmap);
+ free_page((unsigned long)range->bitmap);
- kfree(dma_dom->aperture[index]);
- dma_dom->aperture[index] = NULL;
+ kfree(range);
return -ENOMEM;
}
+static dma_addr_t dma_ops_aperture_alloc(struct dma_ops_domain *dom,
+ struct aperture_range *range,
+ unsigned long pages,
+ unsigned long dma_mask,
+ unsigned long boundary_size,
+ unsigned long align_mask,
+ bool trylock)
+{
+ unsigned long offset, limit, flags;
+ dma_addr_t address;
+ bool flush = false;
+
+ offset = range->offset >> PAGE_SHIFT;
+ limit = iommu_device_max_index(APERTURE_RANGE_PAGES, offset,
+ dma_mask >> PAGE_SHIFT);
+
+ if (trylock) {
+ if (!spin_trylock_irqsave(&range->bitmap_lock, flags))
+ return -1;
+ } else {
+ spin_lock_irqsave(&range->bitmap_lock, flags);
+ }
+
+ address = iommu_area_alloc(range->bitmap, limit, range->next_bit,
+ pages, offset, boundary_size, align_mask);
+ if (address == -1) {
+ /* Nothing found, retry one time */
+ address = iommu_area_alloc(range->bitmap, limit,
+ 0, pages, offset, boundary_size,
+ align_mask);
+ flush = true;
+ }
+
+ if (address != -1)
+ range->next_bit = address + pages;
+
+ spin_unlock_irqrestore(&range->bitmap_lock, flags);
+
+ if (flush) {
+ domain_flush_tlb(&dom->domain);
+ domain_flush_complete(&dom->domain);
+ }
+
+ return address;
+}
+
static unsigned long dma_ops_area_alloc(struct device *dev,
struct dma_ops_domain *dom,
unsigned int pages,
unsigned long align_mask,
- u64 dma_mask,
- unsigned long start)
+ u64 dma_mask)
{
- unsigned long next_bit = dom->next_address % APERTURE_RANGE_SIZE;
- int max_index = dom->aperture_size >> APERTURE_RANGE_SHIFT;
- int i = start >> APERTURE_RANGE_SHIFT;
unsigned long boundary_size, mask;
unsigned long address = -1;
- unsigned long limit;
+ bool first = true;
+ u32 start, i;
- next_bit >>= PAGE_SHIFT;
+ preempt_disable();
mask = dma_get_seg_boundary(dev);
+again:
+ start = this_cpu_read(*dom->next_index);
+
+ /* Sanity check - is it really necessary? */
+ if (unlikely(start > APERTURE_MAX_RANGES)) {
+ start = 0;
+ this_cpu_write(*dom->next_index, 0);
+ }
+
boundary_size = mask + 1 ? ALIGN(mask + 1, PAGE_SIZE) >> PAGE_SHIFT :
1UL << (BITS_PER_LONG - PAGE_SHIFT);
- for (;i < max_index; ++i) {
- unsigned long offset = dom->aperture[i]->offset >> PAGE_SHIFT;
+ for (i = 0; i < APERTURE_MAX_RANGES; ++i) {
+ struct aperture_range *range;
+ int index;
- if (dom->aperture[i]->offset >= dma_mask)
- break;
+ index = (start + i) % APERTURE_MAX_RANGES;
- limit = iommu_device_max_index(APERTURE_RANGE_PAGES, offset,
- dma_mask >> PAGE_SHIFT);
+ range = dom->aperture[index];
- address = iommu_area_alloc(dom->aperture[i]->bitmap,
- limit, next_bit, pages, 0,
- boundary_size, align_mask);
+ if (!range || range->offset >= dma_mask)
+ continue;
+
+ address = dma_ops_aperture_alloc(dom, range, pages,
+ dma_mask, boundary_size,
+ align_mask, first);
if (address != -1) {
- address = dom->aperture[i]->offset +
- (address << PAGE_SHIFT);
- dom->next_address = address + (pages << PAGE_SHIFT);
+ address = range->offset + (address << PAGE_SHIFT);
+ this_cpu_write(*dom->next_index, index);
break;
}
+ }
- next_bit = 0;
+ if (address == -1 && first) {
+ first = false;
+ goto again;
}
+ preempt_enable();
+
return address;
}
@@ -1526,21 +1647,14 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev,
unsigned long align_mask,
u64 dma_mask)
{
- unsigned long address;
-
-#ifdef CONFIG_IOMMU_STRESS
- dom->next_address = 0;
- dom->need_flush = true;
-#endif
+ unsigned long address = -1;
- address = dma_ops_area_alloc(dev, dom, pages, align_mask,
- dma_mask, dom->next_address);
+ while (address == -1) {
+ address = dma_ops_area_alloc(dev, dom, pages,
+ align_mask, dma_mask);
- if (address == -1) {
- dom->next_address = 0;
- address = dma_ops_area_alloc(dev, dom, pages, align_mask,
- dma_mask, 0);
- dom->need_flush = true;
+ if (address == -1 && alloc_new_range(dom, false, GFP_ATOMIC))
+ break;
}
if (unlikely(address == -1))
@@ -1562,6 +1676,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
{
unsigned i = address >> APERTURE_RANGE_SHIFT;
struct aperture_range *range = dom->aperture[i];
+ unsigned long flags;
BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL);
@@ -1570,12 +1685,18 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
return;
#endif
- if (address >= dom->next_address)
- dom->need_flush = true;
+ if (amd_iommu_unmap_flush) {
+ domain_flush_tlb(&dom->domain);
+ domain_flush_complete(&dom->domain);
+ }
address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
+ spin_lock_irqsave(&range->bitmap_lock, flags);
+ if (address + pages > range->next_bit)
+ range->next_bit = address + pages;
bitmap_clear(range->bitmap, address, pages);
+ spin_unlock_irqrestore(&range->bitmap_lock, flags);
}
@@ -1755,6 +1876,8 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
if (!dom)
return;
+ free_percpu(dom->next_index);
+
del_domain_from_list(&dom->domain);
free_pagetable(&dom->domain);
@@ -1769,6 +1892,23 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
kfree(dom);
}
+static int dma_ops_domain_alloc_apertures(struct dma_ops_domain *dma_dom,
+ int max_apertures)
+{
+ int ret, i, apertures;
+
+ apertures = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
+ ret = 0;
+
+ for (i = apertures; i < max_apertures; ++i) {
+ ret = alloc_new_range(dma_dom, false, GFP_KERNEL);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
/*
* Allocates a new protection domain usable for the dma_ops functions.
* It also initializes the page table and the address allocator data
@@ -1777,6 +1917,7 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
static struct dma_ops_domain *dma_ops_domain_alloc(void)
{
struct dma_ops_domain *dma_dom;
+ int cpu;
dma_dom = kzalloc(sizeof(struct dma_ops_domain), GFP_KERNEL);
if (!dma_dom)
@@ -1785,6 +1926,10 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void)
if (protection_domain_init(&dma_dom->domain))
goto free_dma_dom;
+ dma_dom->next_index = alloc_percpu(u32);
+ if (!dma_dom->next_index)
+ goto free_dma_dom;
+
dma_dom->domain.mode = PAGE_MODE_2_LEVEL;
dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL);
dma_dom->domain.flags = PD_DMA_OPS_MASK;
@@ -1792,8 +1937,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void)
if (!dma_dom->domain.pt_root)
goto free_dma_dom;
- dma_dom->need_flush = false;
-
add_domain_to_list(&dma_dom->domain);
if (alloc_new_range(dma_dom, true, GFP_KERNEL))
@@ -1804,8 +1947,9 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void)
* a valid dma-address. So we can use 0 as error value
*/
dma_dom->aperture[0]->bitmap[0] = 1;
- dma_dom->next_address = 0;
+ for_each_possible_cpu(cpu)
+ *per_cpu_ptr(dma_dom->next_index, cpu) = 0;
return dma_dom;
@@ -2328,7 +2472,7 @@ static dma_addr_t dma_ops_domain_map(struct dma_ops_domain *dom,
else if (direction == DMA_BIDIRECTIONAL)
__pte |= IOMMU_PTE_IR | IOMMU_PTE_IW;
- WARN_ON(*pte);
+ WARN_ON_ONCE(*pte);
*pte = __pte;
@@ -2357,7 +2501,7 @@ static void dma_ops_domain_unmap(struct dma_ops_domain *dom,
pte += PM_LEVEL_INDEX(0, address);
- WARN_ON(!*pte);
+ WARN_ON_ONCE(!*pte);
*pte = 0ULL;
}
@@ -2393,26 +2537,11 @@ static dma_addr_t __map_single(struct device *dev,
if (align)
align_mask = (1UL << get_order(size)) - 1;
-retry:
address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask,
dma_mask);
- if (unlikely(address == DMA_ERROR_CODE)) {
- /*
- * setting next_address here will let the address
- * allocator only scan the new allocated range in the
- * first run. This is a small optimization.
- */
- dma_dom->next_address = dma_dom->aperture_size;
- if (alloc_new_range(dma_dom, false, GFP_ATOMIC))
- goto out;
-
- /*
- * aperture was successfully enlarged by 128 MB, try
- * allocation again
- */
- goto retry;
- }
+ if (address == DMA_ERROR_CODE)
+ goto out;
start = address;
for (i = 0; i < pages; ++i) {
@@ -2427,11 +2556,10 @@ retry:
ADD_STATS_COUNTER(alloced_io_mem, size);
- if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) {
- domain_flush_tlb(&dma_dom->domain);
- dma_dom->need_flush = false;
- } else if (unlikely(amd_iommu_np_cache))
+ if (unlikely(amd_iommu_np_cache)) {
domain_flush_pages(&dma_dom->domain, address, size);
+ domain_flush_complete(&dma_dom->domain);
+ }
out:
return address;
@@ -2478,11 +2606,6 @@ static void __unmap_single(struct dma_ops_domain *dma_dom,
SUB_STATS_COUNTER(alloced_io_mem, size);
dma_ops_free_addresses(dma_dom, dma_addr, pages);
-
- if (amd_iommu_unmap_flush || dma_dom->need_flush) {
- domain_flush_pages(&dma_dom->domain, flush_addr, size);
- dma_dom->need_flush = false;
- }
}
/*
@@ -2493,11 +2616,9 @@ static dma_addr_t map_page(struct device *dev, struct page *page,
enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- unsigned long flags;
+ phys_addr_t paddr = page_to_phys(page) + offset;
struct protection_domain *domain;
- dma_addr_t addr;
u64 dma_mask;
- phys_addr_t paddr = page_to_phys(page) + offset;
INC_STATS_COUNTER(cnt_map_single);
@@ -2509,19 +2630,8 @@ static dma_addr_t map_page(struct device *dev, struct page *page,
dma_mask = *dev->dma_mask;
- spin_lock_irqsave(&domain->lock, flags);
-
- addr = __map_single(dev, domain->priv, paddr, size, dir, false,
+ return __map_single(dev, domain->priv, paddr, size, dir, false,
dma_mask);
- if (addr == DMA_ERROR_CODE)
- goto out;
-
- domain_flush_complete(domain);
-
-out:
- spin_unlock_irqrestore(&domain->lock, flags);
-
- return addr;
}
/*
@@ -2530,7 +2640,6 @@ out:
static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
- unsigned long flags;
struct protection_domain *domain;
INC_STATS_COUNTER(cnt_unmap_single);
@@ -2539,13 +2648,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
if (IS_ERR(domain))
return;
- spin_lock_irqsave(&domain->lock, flags);
-
__unmap_single(domain->priv, dma_addr, size, dir);
-
- domain_flush_complete(domain);
-
- spin_unlock_irqrestore(&domain->lock, flags);
}
/*
@@ -2556,7 +2659,6 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- unsigned long flags;
struct protection_domain *domain;
int i;
struct scatterlist *s;
@@ -2572,8 +2674,6 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
dma_mask = *dev->dma_mask;
- spin_lock_irqsave(&domain->lock, flags);
-
for_each_sg(sglist, s, nelems, i) {
paddr = sg_phys(s);
@@ -2588,12 +2688,8 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
goto unmap;
}
- domain_flush_complete(domain);
-
-out:
- spin_unlock_irqrestore(&domain->lock, flags);
-
return mapped_elems;
+
unmap:
for_each_sg(sglist, s, mapped_elems, i) {
if (s->dma_address)
@@ -2602,9 +2698,7 @@ unmap:
s->dma_address = s->dma_length = 0;
}
- mapped_elems = 0;
-
- goto out;
+ return 0;
}
/*
@@ -2615,7 +2709,6 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- unsigned long flags;
struct protection_domain *domain;
struct scatterlist *s;
int i;
@@ -2626,17 +2719,11 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
if (IS_ERR(domain))
return;
- spin_lock_irqsave(&domain->lock, flags);
-
for_each_sg(sglist, s, nelems, i) {
__unmap_single(domain->priv, s->dma_address,
s->dma_length, dir);
s->dma_address = s->dma_length = 0;
}
-
- domain_flush_complete(domain);
-
- spin_unlock_irqrestore(&domain->lock, flags);
}
/*
@@ -2648,7 +2735,6 @@ static void *alloc_coherent(struct device *dev, size_t size,
{
u64 dma_mask = dev->coherent_dma_mask;
struct protection_domain *domain;
- unsigned long flags;
struct page *page;
INC_STATS_COUNTER(cnt_alloc_coherent);
@@ -2680,19 +2766,11 @@ static void *alloc_coherent(struct device *dev, size_t size,
if (!dma_mask)
dma_mask = *dev->dma_mask;
- spin_lock_irqsave(&domain->lock, flags);
-
*dma_addr = __map_single(dev, domain->priv, page_to_phys(page),
size, DMA_BIDIRECTIONAL, true, dma_mask);
- if (*dma_addr == DMA_ERROR_CODE) {
- spin_unlock_irqrestore(&domain->lock, flags);
+ if (*dma_addr == DMA_ERROR_CODE)
goto out_free;
- }
-
- domain_flush_complete(domain);
-
- spin_unlock_irqrestore(&domain->lock, flags);
return page_address(page);
@@ -2712,7 +2790,6 @@ static void free_coherent(struct device *dev, size_t size,
struct dma_attrs *attrs)
{
struct protection_domain *domain;
- unsigned long flags;
struct page *page;
INC_STATS_COUNTER(cnt_free_coherent);
@@ -2724,14 +2801,8 @@ static void free_coherent(struct device *dev, size_t size,
if (IS_ERR(domain))
goto free_mem;
- spin_lock_irqsave(&domain->lock, flags);
-
__unmap_single(domain->priv, dma_addr, size, DMA_BIDIRECTIONAL);
- domain_flush_complete(domain);
-
- spin_unlock_irqrestore(&domain->lock, flags);
-
free_mem:
if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
__free_pages(page, get_order(size));
@@ -2746,14 +2817,43 @@ static int amd_iommu_dma_supported(struct device *dev, u64 mask)
return check_device(dev);
}
+static int set_dma_mask(struct device *dev, u64 mask)
+{
+ struct protection_domain *domain;
+ int max_apertures = 1;
+
+ domain = get_domain(dev);
+ if (IS_ERR(domain))
+ return PTR_ERR(domain);
+
+ if (mask == DMA_BIT_MASK(64))
+ max_apertures = 8;
+ else if (mask > DMA_BIT_MASK(32))
+ max_apertures = 4;
+
+ /*
+ * To prevent lock contention it doesn't make sense to allocate more
+ * apertures than online cpus
+ */
+ if (max_apertures > num_online_cpus())
+ max_apertures = num_online_cpus();
+
+ if (dma_ops_domain_alloc_apertures(domain->priv, max_apertures))
+ dev_err(dev, "Can't allocate %d iommu apertures\n",
+ max_apertures);
+
+ return 0;
+}
+
static struct dma_map_ops amd_iommu_dma_ops = {
- .alloc = alloc_coherent,
- .free = free_coherent,
- .map_page = map_page,
- .unmap_page = unmap_page,
- .map_sg = map_sg,
- .unmap_sg = unmap_sg,
- .dma_supported = amd_iommu_dma_supported,
+ .alloc = alloc_coherent,
+ .free = free_coherent,
+ .map_page = map_page,
+ .unmap_page = unmap_page,
+ .map_sg = map_sg,
+ .unmap_sg = unmap_sg,
+ .dma_supported = amd_iommu_dma_supported,
+ .set_dma_mask = set_dma_mask,
};
int __init amd_iommu_init_api(void)
@@ -3757,11 +3857,9 @@ static struct irq_domain *get_irq_domain(struct irq_alloc_info *info)
case X86_IRQ_ALLOC_TYPE_MSI:
case X86_IRQ_ALLOC_TYPE_MSIX:
devid = get_device_id(&info->msi_dev->dev);
- if (devid >= 0) {
- iommu = amd_iommu_rlookup_table[devid];
- if (iommu)
- return iommu->msi_domain;
- }
+ iommu = amd_iommu_rlookup_table[devid];
+ if (iommu)
+ return iommu->msi_domain;
break;
default:
break;
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index b08cf57bf455..9d32b20a5e9a 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -425,46 +425,6 @@ struct protection_domain {
};
/*
- * For dynamic growth the aperture size is split into ranges of 128MB of
- * DMA address space each. This struct represents one such range.
- */
-struct aperture_range {
-
- /* address allocation bitmap */
- unsigned long *bitmap;
-
- /*
- * Array of PTE pages for the aperture. In this array we save all the
- * leaf pages of the domain page table used for the aperture. This way
- * we don't need to walk the page table to find a specific PTE. We can
- * just calculate its address in constant time.
- */
- u64 *pte_pages[64];
-
- unsigned long offset;
-};
-
-/*
- * Data container for a dma_ops specific protection domain
- */
-struct dma_ops_domain {
- /* generic protection domain information */
- struct protection_domain domain;
-
- /* size of the aperture for the mappings */
- unsigned long aperture_size;
-
- /* address we start to search for free addresses */
- unsigned long next_address;
-
- /* address space relevant data */
- struct aperture_range *aperture[APERTURE_MAX_RANGES];
-
- /* This will be set to true when TLB needs to be flushed */
- bool need_flush;
-};
-
-/*
* Structure where we save information about one hardware AMD IOMMU in the
* system.
*/
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index 7caf2fa237f2..c865737326e1 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -432,7 +432,7 @@ static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
unbind_pasid(pasid_state);
}
-static struct mmu_notifier_ops iommu_mn = {
+static const struct mmu_notifier_ops iommu_mn = {
.release = mn_release,
.clear_flush_young = mn_clear_flush_young,
.invalidate_page = mn_invalidate_page,
@@ -513,43 +513,39 @@ static bool access_error(struct vm_area_struct *vma, struct fault *fault)
static void do_fault(struct work_struct *work)
{
struct fault *fault = container_of(work, struct fault, work);
- struct mm_struct *mm;
struct vm_area_struct *vma;
+ int ret = VM_FAULT_ERROR;
+ unsigned int flags = 0;
+ struct mm_struct *mm;
u64 address;
- int ret, write;
-
- write = !!(fault->flags & PPR_FAULT_WRITE);
mm = fault->state->mm;
address = fault->address;
+ if (fault->flags & PPR_FAULT_USER)
+ flags |= FAULT_FLAG_USER;
+ if (fault->flags & PPR_FAULT_WRITE)
+ flags |= FAULT_FLAG_WRITE;
+
down_read(&mm->mmap_sem);
vma = find_extend_vma(mm, address);
- if (!vma || address < vma->vm_start) {
+ if (!vma || address < vma->vm_start)
/* failed to get a vma in the right range */
- up_read(&mm->mmap_sem);
- handle_fault_error(fault);
goto out;
- }
/* Check if we have the right permissions on the vma */
- if (access_error(vma, fault)) {
- up_read(&mm->mmap_sem);
- handle_fault_error(fault);
+ if (access_error(vma, fault))
goto out;
- }
- ret = handle_mm_fault(mm, vma, address, write);
- if (ret & VM_FAULT_ERROR) {
- /* failed to service fault */
- up_read(&mm->mmap_sem);
- handle_fault_error(fault);
- goto out;
- }
+ ret = handle_mm_fault(mm, vma, address, flags);
+out:
up_read(&mm->mmap_sem);
-out:
+ if (ret & VM_FAULT_ERROR)
+ /* failed to service fault */
+ handle_fault_error(fault);
+
finish_pri_tag(fault->dev_state, fault->state, fault->tag);
put_pasid_state(fault->state);
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 4e5118a4cd30..20875341c865 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -40,7 +40,10 @@
#define IDR0_ST_LVL_SHIFT 27
#define IDR0_ST_LVL_MASK 0x3
#define IDR0_ST_LVL_2LVL (1 << IDR0_ST_LVL_SHIFT)
-#define IDR0_STALL_MODEL (3 << 24)
+#define IDR0_STALL_MODEL_SHIFT 24
+#define IDR0_STALL_MODEL_MASK 0x3
+#define IDR0_STALL_MODEL_STALL (0 << IDR0_STALL_MODEL_SHIFT)
+#define IDR0_STALL_MODEL_FORCE (2 << IDR0_STALL_MODEL_SHIFT)
#define IDR0_TTENDIAN_SHIFT 21
#define IDR0_TTENDIAN_MASK 0x3
#define IDR0_TTENDIAN_LE (2 << IDR0_TTENDIAN_SHIFT)
@@ -253,6 +256,9 @@
#define STRTAB_STE_1_STRW_EL2 2UL
#define STRTAB_STE_1_STRW_SHIFT 30
+#define STRTAB_STE_1_SHCFG_INCOMING 1UL
+#define STRTAB_STE_1_SHCFG_SHIFT 44
+
#define STRTAB_STE_2_S2VMID_SHIFT 0
#define STRTAB_STE_2_S2VMID_MASK 0xffffUL
#define STRTAB_STE_2_VTCR_SHIFT 32
@@ -378,7 +384,6 @@
#define PRIQ_0_SID_MASK 0xffffffffUL
#define PRIQ_0_SSID_SHIFT 32
#define PRIQ_0_SSID_MASK 0xfffffUL
-#define PRIQ_0_OF (1UL << 57)
#define PRIQ_0_PERM_PRIV (1UL << 58)
#define PRIQ_0_PERM_EXEC (1UL << 59)
#define PRIQ_0_PERM_READ (1UL << 60)
@@ -855,15 +860,17 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
};
dev_err(smmu->dev, "CMDQ error (cons 0x%08x): %s\n", cons,
- cerror_str[idx]);
+ idx < ARRAY_SIZE(cerror_str) ? cerror_str[idx] : "Unknown");
switch (idx) {
- case CMDQ_ERR_CERROR_ILL_IDX:
- break;
case CMDQ_ERR_CERROR_ABT_IDX:
dev_err(smmu->dev, "retrying command fetch\n");
case CMDQ_ERR_CERROR_NONE_IDX:
return;
+ case CMDQ_ERR_CERROR_ILL_IDX:
+ /* Fallthrough */
+ default:
+ break;
}
/*
@@ -1042,6 +1049,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
val |= disable_bypass ? STRTAB_STE_0_CFG_ABORT
: STRTAB_STE_0_CFG_BYPASS;
dst[0] = cpu_to_le64(val);
+ dst[1] = cpu_to_le64(STRTAB_STE_1_SHCFG_INCOMING
+ << STRTAB_STE_1_SHCFG_SHIFT);
dst[2] = 0; /* Nuke the VMID */
if (ste_live)
arm_smmu_sync_ste_for_sid(smmu, sid);
@@ -1056,12 +1065,14 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
STRTAB_STE_1_S1C_CACHE_WBRA
<< STRTAB_STE_1_S1COR_SHIFT |
STRTAB_STE_1_S1C_SH_ISH << STRTAB_STE_1_S1CSH_SHIFT |
- STRTAB_STE_1_S1STALLD |
#ifdef CONFIG_PCI_ATS
STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT |
#endif
STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT);
+ if (smmu->features & ARM_SMMU_FEAT_STALLS)
+ dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
+
val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK
<< STRTAB_STE_0_S1CTXPTR_SHIFT) |
STRTAB_STE_0_CFG_S1_TRANS;
@@ -1123,8 +1134,8 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
desc->span = STRTAB_SPLIT + 1;
- desc->l2ptr = dma_zalloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
- GFP_KERNEL);
+ desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!desc->l2ptr) {
dev_err(smmu->dev,
"failed to allocate l2 stream table for SID %u\n",
@@ -1250,50 +1261,50 @@ static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
{
- u32 gerror, gerrorn;
+ u32 gerror, gerrorn, active;
struct arm_smmu_device *smmu = dev;
gerror = readl_relaxed(smmu->base + ARM_SMMU_GERROR);
gerrorn = readl_relaxed(smmu->base + ARM_SMMU_GERRORN);
- gerror ^= gerrorn;
- if (!(gerror & GERROR_ERR_MASK))
+ active = gerror ^ gerrorn;
+ if (!(active & GERROR_ERR_MASK))
return IRQ_NONE; /* No errors pending */
dev_warn(smmu->dev,
"unexpected global error reported (0x%08x), this could be serious\n",
- gerror);
+ active);
- if (gerror & GERROR_SFM_ERR) {
+ if (active & GERROR_SFM_ERR) {
dev_err(smmu->dev, "device has entered Service Failure Mode!\n");
arm_smmu_device_disable(smmu);
}
- if (gerror & GERROR_MSI_GERROR_ABT_ERR)
+ if (active & GERROR_MSI_GERROR_ABT_ERR)
dev_warn(smmu->dev, "GERROR MSI write aborted\n");
- if (gerror & GERROR_MSI_PRIQ_ABT_ERR) {
+ if (active & GERROR_MSI_PRIQ_ABT_ERR) {
dev_warn(smmu->dev, "PRIQ MSI write aborted\n");
arm_smmu_priq_handler(irq, smmu->dev);
}
- if (gerror & GERROR_MSI_EVTQ_ABT_ERR) {
+ if (active & GERROR_MSI_EVTQ_ABT_ERR) {
dev_warn(smmu->dev, "EVTQ MSI write aborted\n");
arm_smmu_evtq_handler(irq, smmu->dev);
}
- if (gerror & GERROR_MSI_CMDQ_ABT_ERR) {
+ if (active & GERROR_MSI_CMDQ_ABT_ERR) {
dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
arm_smmu_cmdq_sync_handler(irq, smmu->dev);
}
- if (gerror & GERROR_PRIQ_ABT_ERR)
+ if (active & GERROR_PRIQ_ABT_ERR)
dev_err(smmu->dev, "PRIQ write aborted -- events may have been lost\n");
- if (gerror & GERROR_EVTQ_ABT_ERR)
+ if (active & GERROR_EVTQ_ABT_ERR)
dev_err(smmu->dev, "EVTQ write aborted -- events may have been lost\n");
- if (gerror & GERROR_CMDQ_ERR)
+ if (active & GERROR_CMDQ_ERR)
arm_smmu_cmdq_skip_err(smmu);
writel(gerror, smmu->base + ARM_SMMU_GERRORN);
@@ -1335,7 +1346,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
}
static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
- bool leaf, void *cookie)
+ size_t granule, bool leaf, void *cookie)
{
struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_device *smmu = smmu_domain->smmu;
@@ -1354,7 +1365,10 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid;
}
- arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+ do {
+ arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+ cmd.tlbi.addr += granule;
+ } while (size -= granule);
}
static struct iommu_gather_ops arm_smmu_gather_ops = {
@@ -1429,10 +1443,10 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
if (cfg->cdptr) {
- dma_free_coherent(smmu_domain->smmu->dev,
- CTXDESC_CD_DWORDS << 3,
- cfg->cdptr,
- cfg->cdptr_dma);
+ dmam_free_coherent(smmu_domain->smmu->dev,
+ CTXDESC_CD_DWORDS << 3,
+ cfg->cdptr,
+ cfg->cdptr_dma);
arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
}
@@ -1457,8 +1471,9 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
if (IS_ERR_VALUE(asid))
return asid;
- cfg->cdptr = dma_zalloc_coherent(smmu->dev, CTXDESC_CD_DWORDS << 3,
- &cfg->cdptr_dma, GFP_KERNEL);
+ cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_DWORDS << 3,
+ &cfg->cdptr_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!cfg->cdptr) {
dev_warn(smmu->dev, "failed to allocate context descriptor\n");
ret = -ENOMEM;
@@ -1804,13 +1819,13 @@ static int arm_smmu_add_device(struct device *dev)
smmu = arm_smmu_get_for_pci_dev(pdev);
if (!smmu) {
ret = -ENOENT;
- goto out_put_group;
+ goto out_remove_dev;
}
smmu_group = kzalloc(sizeof(*smmu_group), GFP_KERNEL);
if (!smmu_group) {
ret = -ENOMEM;
- goto out_put_group;
+ goto out_remove_dev;
}
smmu_group->ste.valid = true;
@@ -1826,20 +1841,20 @@ static int arm_smmu_add_device(struct device *dev)
for (i = 0; i < smmu_group->num_sids; ++i) {
/* If we already know about this SID, then we're done */
if (smmu_group->sids[i] == sid)
- return 0;
+ goto out_put_group;
}
/* Check the SID is in range of the SMMU and our stream table */
if (!arm_smmu_sid_in_range(smmu, sid)) {
ret = -ERANGE;
- goto out_put_group;
+ goto out_remove_dev;
}
/* Ensure l2 strtab is initialised */
if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
ret = arm_smmu_init_l2_strtab(smmu, sid);
if (ret)
- goto out_put_group;
+ goto out_remove_dev;
}
/* Resize the SID array for the group */
@@ -1849,16 +1864,20 @@ static int arm_smmu_add_device(struct device *dev)
if (!sids) {
smmu_group->num_sids--;
ret = -ENOMEM;
- goto out_put_group;
+ goto out_remove_dev;
}
/* Add the new SID */
sids[smmu_group->num_sids - 1] = sid;
smmu_group->sids = sids;
- return 0;
out_put_group:
iommu_group_put(group);
+ return 0;
+
+out_remove_dev:
+ iommu_group_remove_device(dev);
+ iommu_group_put(group);
return ret;
}
@@ -1937,7 +1956,7 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
{
size_t qsz = ((1 << q->max_n_shift) * dwords) << 3;
- q->base = dma_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);
+ q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);
if (!q->base) {
dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n",
qsz);
@@ -1957,23 +1976,6 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
return 0;
}
-static void arm_smmu_free_one_queue(struct arm_smmu_device *smmu,
- struct arm_smmu_queue *q)
-{
- size_t qsz = ((1 << q->max_n_shift) * q->ent_dwords) << 3;
-
- dma_free_coherent(smmu->dev, qsz, q->base, q->base_dma);
-}
-
-static void arm_smmu_free_queues(struct arm_smmu_device *smmu)
-{
- arm_smmu_free_one_queue(smmu, &smmu->cmdq.q);
- arm_smmu_free_one_queue(smmu, &smmu->evtq.q);
-
- if (smmu->features & ARM_SMMU_FEAT_PRI)
- arm_smmu_free_one_queue(smmu, &smmu->priq.q);
-}
-
static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
{
int ret;
@@ -1983,49 +1985,20 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD,
ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS);
if (ret)
- goto out;
+ return ret;
/* evtq */
ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD,
ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS);
if (ret)
- goto out_free_cmdq;
+ return ret;
/* priq */
if (!(smmu->features & ARM_SMMU_FEAT_PRI))
return 0;
- ret = arm_smmu_init_one_queue(smmu, &smmu->priq.q, ARM_SMMU_PRIQ_PROD,
- ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS);
- if (ret)
- goto out_free_evtq;
-
- return 0;
-
-out_free_evtq:
- arm_smmu_free_one_queue(smmu, &smmu->evtq.q);
-out_free_cmdq:
- arm_smmu_free_one_queue(smmu, &smmu->cmdq.q);
-out:
- return ret;
-}
-
-static void arm_smmu_free_l2_strtab(struct arm_smmu_device *smmu)
-{
- int i;
- size_t size;
- struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
-
- size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
- for (i = 0; i < cfg->num_l1_ents; ++i) {
- struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[i];
-
- if (!desc->l2ptr)
- continue;
-
- dma_free_coherent(smmu->dev, size, desc->l2ptr,
- desc->l2ptr_dma);
- }
+ return arm_smmu_init_one_queue(smmu, &smmu->priq.q, ARM_SMMU_PRIQ_PROD,
+ ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS);
}
static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
@@ -2054,7 +2027,6 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
void *strtab;
u64 reg;
u32 size, l1size;
- int ret;
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
/*
@@ -2077,8 +2049,8 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
size, smmu->sid_bits);
l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
- strtab = dma_zalloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
- GFP_KERNEL);
+ strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!strtab) {
dev_err(smmu->dev,
"failed to allocate l1 stream table (%u bytes)\n",
@@ -2095,13 +2067,7 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
<< STRTAB_BASE_CFG_SPLIT_SHIFT;
cfg->strtab_base_cfg = reg;
- ret = arm_smmu_init_l1_strtab(smmu);
- if (ret)
- dma_free_coherent(smmu->dev,
- l1size,
- strtab,
- cfg->strtab_dma);
- return ret;
+ return arm_smmu_init_l1_strtab(smmu);
}
static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
@@ -2112,8 +2078,8 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3);
- strtab = dma_zalloc_coherent(smmu->dev, size, &cfg->strtab_dma,
- GFP_KERNEL);
+ strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!strtab) {
dev_err(smmu->dev,
"failed to allocate linear stream table (%u bytes)\n",
@@ -2157,21 +2123,6 @@ static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
return 0;
}
-static void arm_smmu_free_strtab(struct arm_smmu_device *smmu)
-{
- struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
- u32 size = cfg->num_l1_ents;
-
- if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
- arm_smmu_free_l2_strtab(smmu);
- size *= STRTAB_L1_DESC_DWORDS << 3;
- } else {
- size *= STRTAB_STE_DWORDS * 3;
- }
-
- dma_free_coherent(smmu->dev, size, cfg->strtab, cfg->strtab_dma);
-}
-
static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
{
int ret;
@@ -2180,21 +2131,7 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
if (ret)
return ret;
- ret = arm_smmu_init_strtab(smmu);
- if (ret)
- goto out_free_queues;
-
- return 0;
-
-out_free_queues:
- arm_smmu_free_queues(smmu);
- return ret;
-}
-
-static void arm_smmu_free_structures(struct arm_smmu_device *smmu)
-{
- arm_smmu_free_strtab(smmu);
- arm_smmu_free_queues(smmu);
+ return arm_smmu_init_strtab(smmu);
}
static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,
@@ -2532,8 +2469,12 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
dev_warn(smmu->dev, "IDR0.COHACC overridden by dma-coherent property (%s)\n",
coherent ? "true" : "false");
- if (reg & IDR0_STALL_MODEL)
+ switch (reg & IDR0_STALL_MODEL_MASK << IDR0_STALL_MODEL_SHIFT) {
+ case IDR0_STALL_MODEL_STALL:
+ /* Fallthrough */
+ case IDR0_STALL_MODEL_FORCE:
smmu->features |= ARM_SMMU_FEAT_STALLS;
+ }
if (reg & IDR0_S1P)
smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
@@ -2699,15 +2640,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, smmu);
/* Reset the device */
- ret = arm_smmu_device_reset(smmu);
- if (ret)
- goto out_free_structures;
-
- return 0;
-
-out_free_structures:
- arm_smmu_free_structures(smmu);
- return ret;
+ return arm_smmu_device_reset(smmu);
}
static int arm_smmu_device_remove(struct platform_device *pdev)
@@ -2715,7 +2648,6 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
arm_smmu_device_disable(smmu);
- arm_smmu_free_structures(smmu);
return 0;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 47dc7a793f5c..59ee4b8a3236 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -582,7 +582,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
}
static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
- bool leaf, void *cookie)
+ size_t granule, bool leaf, void *cookie)
{
struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
@@ -597,12 +597,18 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) {
iova &= ~12UL;
iova |= ARM_SMMU_CB_ASID(cfg);
- writel_relaxed(iova, reg);
+ do {
+ writel_relaxed(iova, reg);
+ iova += granule;
+ } while (size -= granule);
#ifdef CONFIG_64BIT
} else {
iova >>= 12;
iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48;
- writeq_relaxed(iova, reg);
+ do {
+ writeq_relaxed(iova, reg);
+ iova += granule >> 12;
+ } while (size -= granule);
#endif
}
#ifdef CONFIG_64BIT
@@ -610,7 +616,11 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L :
ARM_SMMU_CB_S2_TLBIIPAS2;
- writeq_relaxed(iova >> 12, reg);
+ iova >>= 12;
+ do {
+ writeq_relaxed(iova, reg);
+ iova += granule >> 12;
+ } while (size -= granule);
#endif
} else {
reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID;
@@ -945,9 +955,7 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
free_irq(irq, domain);
}
- if (smmu_domain->pgtbl_ops)
- free_io_pgtable_ops(smmu_domain->pgtbl_ops);
-
+ free_io_pgtable_ops(smmu_domain->pgtbl_ops);
__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
}
@@ -1357,6 +1365,7 @@ static int arm_smmu_add_device(struct device *dev)
if (IS_ERR(group))
return PTR_ERR(group);
+ iommu_group_put(group);
return 0;
}
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 80e3c176008e..62a400c5ba06 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -1063,13 +1063,19 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
raw_spin_lock_init(&iommu->register_lock);
- drhd->iommu = iommu;
-
- if (intel_iommu_enabled)
+ if (intel_iommu_enabled) {
iommu->iommu_dev = iommu_device_create(NULL, iommu,
intel_iommu_groups,
"%s", iommu->name);
+ if (IS_ERR(iommu->iommu_dev)) {
+ err = PTR_ERR(iommu->iommu_dev);
+ goto err_unmap;
+ }
+ }
+
+ drhd->iommu = iommu;
+
return 0;
err_unmap:
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 7df97777662d..8bbcbfe7695c 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -38,9 +38,6 @@
#define io_pgtable_to_data(x) \
container_of((x), struct arm_lpae_io_pgtable, iop)
-#define io_pgtable_ops_to_pgtable(x) \
- container_of((x), struct io_pgtable, ops)
-
#define io_pgtable_ops_to_data(x) \
io_pgtable_to_data(io_pgtable_ops_to_pgtable(x))
@@ -58,8 +55,10 @@
((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1)) \
* (d)->bits_per_level) + (d)->pg_shift)
+#define ARM_LPAE_GRANULE(d) (1UL << (d)->pg_shift)
+
#define ARM_LPAE_PAGES_PER_PGD(d) \
- DIV_ROUND_UP((d)->pgd_size, 1UL << (d)->pg_shift)
+ DIV_ROUND_UP((d)->pgd_size, ARM_LPAE_GRANULE(d))
/*
* Calculate the index at level l used to map virtual address a using the
@@ -169,7 +168,7 @@
/* IOPTE accessors */
#define iopte_deref(pte,d) \
(__va((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1) \
- & ~((1ULL << (d)->pg_shift) - 1)))
+ & ~(ARM_LPAE_GRANULE(d) - 1ULL)))
#define iopte_type(pte,l) \
(((pte) >> ARM_LPAE_PTE_TYPE_SHIFT) & ARM_LPAE_PTE_TYPE_MASK)
@@ -326,7 +325,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
/* Grab a pointer to the next level */
pte = *ptep;
if (!pte) {
- cptep = __arm_lpae_alloc_pages(1UL << data->pg_shift,
+ cptep = __arm_lpae_alloc_pages(ARM_LPAE_GRANULE(data),
GFP_ATOMIC, cfg);
if (!cptep)
return -ENOMEM;
@@ -405,17 +404,18 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
arm_lpae_iopte *start, *end;
unsigned long table_size;
- /* Only leaf entries at the last level */
- if (lvl == ARM_LPAE_MAX_LEVELS - 1)
- return;
-
if (lvl == ARM_LPAE_START_LVL(data))
table_size = data->pgd_size;
else
- table_size = 1UL << data->pg_shift;
+ table_size = ARM_LPAE_GRANULE(data);
start = ptep;
- end = (void *)ptep + table_size;
+
+ /* Only leaf entries at the last level */
+ if (lvl == ARM_LPAE_MAX_LEVELS - 1)
+ end = ptep;
+ else
+ end = (void *)ptep + table_size;
while (ptep != end) {
arm_lpae_iopte pte = *ptep++;
@@ -473,7 +473,7 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
__arm_lpae_set_pte(ptep, table, cfg);
iova &= ~(blk_size - 1);
- cfg->tlb->tlb_add_flush(iova, blk_size, true, data->iop.cookie);
+ cfg->tlb->tlb_add_flush(iova, blk_size, blk_size, true, data->iop.cookie);
return size;
}
@@ -486,11 +486,13 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
void *cookie = data->iop.cookie;
size_t blk_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
+ /* Something went horribly wrong and we ran out of page table */
+ if (WARN_ON(lvl == ARM_LPAE_MAX_LEVELS))
+ return 0;
+
ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);
pte = *ptep;
-
- /* Something went horribly wrong and we ran out of page table */
- if (WARN_ON(!pte || (lvl == ARM_LPAE_MAX_LEVELS)))
+ if (WARN_ON(!pte))
return 0;
/* If the size matches this level, we're in the right place */
@@ -499,12 +501,13 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
if (!iopte_leaf(pte, lvl)) {
/* Also flush any partial walks */
- tlb->tlb_add_flush(iova, size, false, cookie);
+ tlb->tlb_add_flush(iova, size, ARM_LPAE_GRANULE(data),
+ false, cookie);
tlb->tlb_sync(cookie);
ptep = iopte_deref(pte, data);
__arm_lpae_free_pgtable(data, lvl + 1, ptep);
} else {
- tlb->tlb_add_flush(iova, size, true, cookie);
+ tlb->tlb_add_flush(iova, size, size, true, cookie);
}
return size;
@@ -570,7 +573,7 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
return 0;
found_translation:
- iova &= ((1 << data->pg_shift) - 1);
+ iova &= (ARM_LPAE_GRANULE(data) - 1);
return ((phys_addr_t)iopte_to_pfn(pte,data) << data->pg_shift) | iova;
}
@@ -668,7 +671,7 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
(ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
(ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
- switch (1 << data->pg_shift) {
+ switch (ARM_LPAE_GRANULE(data)) {
case SZ_4K:
reg |= ARM_LPAE_TCR_TG0_4K;
break;
@@ -769,7 +772,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
sl = ARM_LPAE_START_LVL(data);
- switch (1 << data->pg_shift) {
+ switch (ARM_LPAE_GRANULE(data)) {
case SZ_4K:
reg |= ARM_LPAE_TCR_TG0_4K;
sl++; /* SL0 format is different for 4K granule size */
@@ -889,8 +892,8 @@ static void dummy_tlb_flush_all(void *cookie)
WARN_ON(cookie != cfg_cookie);
}
-static void dummy_tlb_add_flush(unsigned long iova, size_t size, bool leaf,
- void *cookie)
+static void dummy_tlb_add_flush(unsigned long iova, size_t size,
+ size_t granule, bool leaf, void *cookie)
{
WARN_ON(cookie != cfg_cookie);
WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index ac9e2341a633..36673c83de58 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -26,8 +26,8 @@ enum io_pgtable_fmt {
*/
struct iommu_gather_ops {
void (*tlb_flush_all)(void *cookie);
- void (*tlb_add_flush)(unsigned long iova, size_t size, bool leaf,
- void *cookie);
+ void (*tlb_add_flush)(unsigned long iova, size_t size, size_t granule,
+ bool leaf, void *cookie);
void (*tlb_sync)(void *cookie);
};
@@ -131,6 +131,8 @@ struct io_pgtable {
struct io_pgtable_ops ops;
};
+#define io_pgtable_ops_to_pgtable(x) container_of((x), struct io_pgtable, ops)
+
/**
* struct io_pgtable_init_fns - Alloc/free a set of page tables for a
* particular format.
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index dfb868e2d129..2fdbac67a77f 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -277,8 +277,8 @@ static void ipmmu_tlb_flush_all(void *cookie)
ipmmu_tlb_invalidate(domain);
}
-static void ipmmu_tlb_add_flush(unsigned long iova, size_t size, bool leaf,
- void *cookie)
+static void ipmmu_tlb_add_flush(unsigned long iova, size_t size,
+ size_t granule, bool leaf, void *cookie)
{
/* The hardware doesn't support selective TLB flush. */
}
diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c
index b6d01f97e537..4b09e815accf 100644
--- a/drivers/iommu/msm_iommu_dev.c
+++ b/drivers/iommu/msm_iommu_dev.c
@@ -359,30 +359,19 @@ static struct platform_driver msm_iommu_ctx_driver = {
.remove = msm_iommu_ctx_remove,
};
+static struct platform_driver * const drivers[] = {
+ &msm_iommu_driver,
+ &msm_iommu_ctx_driver,
+};
+
static int __init msm_iommu_driver_init(void)
{
- int ret;
- ret = platform_driver_register(&msm_iommu_driver);
- if (ret != 0) {
- pr_err("Failed to register IOMMU driver\n");
- goto error;
- }
-
- ret = platform_driver_register(&msm_iommu_ctx_driver);
- if (ret != 0) {
- platform_driver_unregister(&msm_iommu_driver);
- pr_err("Failed to register IOMMU context driver\n");
- goto error;
- }
-
-error:
- return ret;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit msm_iommu_driver_exit(void)
{
- platform_driver_unregister(&msm_iommu_ctx_driver);
- platform_driver_unregister(&msm_iommu_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(msm_iommu_driver_init);
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index 471ee36b9c6e..a04d491cf431 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -49,7 +49,7 @@ static bool s390_iommu_capable(enum iommu_cap cap)
}
}
-struct iommu_domain *s390_domain_alloc(unsigned domain_type)
+static struct iommu_domain *s390_domain_alloc(unsigned domain_type)
{
struct s390_domain *s390_domain;
@@ -73,7 +73,7 @@ struct iommu_domain *s390_domain_alloc(unsigned domain_type)
return &s390_domain->domain;
}
-void s390_domain_free(struct iommu_domain *domain)
+static void s390_domain_free(struct iommu_domain *domain)
{
struct s390_domain *s390_domain = to_s390_domain(domain);
diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c
deleted file mode 100644
index a0287519a1d4..000000000000
--- a/drivers/iommu/shmobile-iommu.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * IOMMU for IPMMU/IPMMUI
- * Copyright (C) 2012 Hideki EIRAKU
- *
- * 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.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/iommu.h>
-#include <linux/platform_device.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-#include <asm/dma-iommu.h>
-#include "shmobile-ipmmu.h"
-
-#define L1_SIZE CONFIG_SHMOBILE_IOMMU_L1SIZE
-#define L1_LEN (L1_SIZE / 4)
-#define L1_ALIGN L1_SIZE
-#define L2_SIZE SZ_1K
-#define L2_LEN (L2_SIZE / 4)
-#define L2_ALIGN L2_SIZE
-
-struct shmobile_iommu_domain_pgtable {
- uint32_t *pgtable;
- dma_addr_t handle;
-};
-
-struct shmobile_iommu_archdata {
- struct list_head attached_list;
- struct dma_iommu_mapping *iommu_mapping;
- spinlock_t attach_lock;
- struct shmobile_iommu_domain *attached;
- int num_attached_devices;
- struct shmobile_ipmmu *ipmmu;
-};
-
-struct shmobile_iommu_domain {
- struct shmobile_iommu_domain_pgtable l1, l2[L1_LEN];
- spinlock_t map_lock;
- spinlock_t attached_list_lock;
- struct list_head attached_list;
- struct iommu_domain domain;
-};
-
-static struct shmobile_iommu_archdata *ipmmu_archdata;
-static struct kmem_cache *l1cache, *l2cache;
-
-static struct shmobile_iommu_domain *to_sh_domain(struct iommu_domain *dom)
-{
- return container_of(dom, struct shmobile_iommu_domain, domain);
-}
-
-static int pgtable_alloc(struct shmobile_iommu_domain_pgtable *pgtable,
- struct kmem_cache *cache, size_t size)
-{
- pgtable->pgtable = kmem_cache_zalloc(cache, GFP_ATOMIC);
- if (!pgtable->pgtable)
- return -ENOMEM;
- pgtable->handle = dma_map_single(NULL, pgtable->pgtable, size,
- DMA_TO_DEVICE);
- return 0;
-}
-
-static void pgtable_free(struct shmobile_iommu_domain_pgtable *pgtable,
- struct kmem_cache *cache, size_t size)
-{
- dma_unmap_single(NULL, pgtable->handle, size, DMA_TO_DEVICE);
- kmem_cache_free(cache, pgtable->pgtable);
-}
-
-static uint32_t pgtable_read(struct shmobile_iommu_domain_pgtable *pgtable,
- unsigned int index)
-{
- return pgtable->pgtable[index];
-}
-
-static void pgtable_write(struct shmobile_iommu_domain_pgtable *pgtable,
- unsigned int index, unsigned int count, uint32_t val)
-{
- unsigned int i;
-
- for (i = 0; i < count; i++)
- pgtable->pgtable[index + i] = val;
- dma_sync_single_for_device(NULL, pgtable->handle + index * sizeof(val),
- sizeof(val) * count, DMA_TO_DEVICE);
-}
-
-static struct iommu_domain *shmobile_iommu_domain_alloc(unsigned type)
-{
- struct shmobile_iommu_domain *sh_domain;
- int i, ret;
-
- if (type != IOMMU_DOMAIN_UNMANAGED)
- return NULL;
-
- sh_domain = kzalloc(sizeof(*sh_domain), GFP_KERNEL);
- if (!sh_domain)
- return NULL;
- ret = pgtable_alloc(&sh_domain->l1, l1cache, L1_SIZE);
- if (ret < 0) {
- kfree(sh_domain);
- return NULL;
- }
- for (i = 0; i < L1_LEN; i++)
- sh_domain->l2[i].pgtable = NULL;
- spin_lock_init(&sh_domain->map_lock);
- spin_lock_init(&sh_domain->attached_list_lock);
- INIT_LIST_HEAD(&sh_domain->attached_list);
- return &sh_domain->domain;
-}
-
-static void shmobile_iommu_domain_free(struct iommu_domain *domain)
-{
- struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
- int i;
-
- for (i = 0; i < L1_LEN; i++) {
- if (sh_domain->l2[i].pgtable)
- pgtable_free(&sh_domain->l2[i], l2cache, L2_SIZE);
- }
- pgtable_free(&sh_domain->l1, l1cache, L1_SIZE);
- kfree(sh_domain);
-}
-
-static int shmobile_iommu_attach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- struct shmobile_iommu_archdata *archdata = dev->archdata.iommu;
- struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
- int ret = -EBUSY;
-
- if (!archdata)
- return -ENODEV;
- spin_lock(&sh_domain->attached_list_lock);
- spin_lock(&archdata->attach_lock);
- if (archdata->attached != sh_domain) {
- if (archdata->attached)
- goto err;
- ipmmu_tlb_set(archdata->ipmmu, sh_domain->l1.handle, L1_SIZE,
- 0);
- ipmmu_tlb_flush(archdata->ipmmu);
- archdata->attached = sh_domain;
- archdata->num_attached_devices = 0;
- list_add(&archdata->attached_list, &sh_domain->attached_list);
- }
- archdata->num_attached_devices++;
- ret = 0;
-err:
- spin_unlock(&archdata->attach_lock);
- spin_unlock(&sh_domain->attached_list_lock);
- return ret;
-}
-
-static void shmobile_iommu_detach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- struct shmobile_iommu_archdata *archdata = dev->archdata.iommu;
- struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
-
- if (!archdata)
- return;
- spin_lock(&sh_domain->attached_list_lock);
- spin_lock(&archdata->attach_lock);
- archdata->num_attached_devices--;
- if (!archdata->num_attached_devices) {
- ipmmu_tlb_set(archdata->ipmmu, 0, 0, 0);
- ipmmu_tlb_flush(archdata->ipmmu);
- archdata->attached = NULL;
- list_del(&archdata->attached_list);
- }
- spin_unlock(&archdata->attach_lock);
- spin_unlock(&sh_domain->attached_list_lock);
-}
-
-static void domain_tlb_flush(struct shmobile_iommu_domain *sh_domain)
-{
- struct shmobile_iommu_archdata *archdata;
-
- spin_lock(&sh_domain->attached_list_lock);
- list_for_each_entry(archdata, &sh_domain->attached_list, attached_list)
- ipmmu_tlb_flush(archdata->ipmmu);
- spin_unlock(&sh_domain->attached_list_lock);
-}
-
-static int l2alloc(struct shmobile_iommu_domain *sh_domain,
- unsigned int l1index)
-{
- int ret;
-
- if (!sh_domain->l2[l1index].pgtable) {
- ret = pgtable_alloc(&sh_domain->l2[l1index], l2cache, L2_SIZE);
- if (ret < 0)
- return ret;
- }
- pgtable_write(&sh_domain->l1, l1index, 1,
- sh_domain->l2[l1index].handle | 0x1);
- return 0;
-}
-
-static void l2realfree(struct shmobile_iommu_domain_pgtable *l2)
-{
- if (l2->pgtable)
- pgtable_free(l2, l2cache, L2_SIZE);
-}
-
-static void l2free(struct shmobile_iommu_domain *sh_domain,
- unsigned int l1index,
- struct shmobile_iommu_domain_pgtable *l2)
-{
- pgtable_write(&sh_domain->l1, l1index, 1, 0);
- if (sh_domain->l2[l1index].pgtable) {
- *l2 = sh_domain->l2[l1index];
- sh_domain->l2[l1index].pgtable = NULL;
- }
-}
-
-static int shmobile_iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot)
-{
- struct shmobile_iommu_domain_pgtable l2 = { .pgtable = NULL };
- struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
- unsigned int l1index, l2index;
- int ret;
-
- l1index = iova >> 20;
- switch (size) {
- case SZ_4K:
- l2index = (iova >> 12) & 0xff;
- spin_lock(&sh_domain->map_lock);
- ret = l2alloc(sh_domain, l1index);
- if (!ret)
- pgtable_write(&sh_domain->l2[l1index], l2index, 1,
- paddr | 0xff2);
- spin_unlock(&sh_domain->map_lock);
- break;
- case SZ_64K:
- l2index = (iova >> 12) & 0xf0;
- spin_lock(&sh_domain->map_lock);
- ret = l2alloc(sh_domain, l1index);
- if (!ret)
- pgtable_write(&sh_domain->l2[l1index], l2index, 0x10,
- paddr | 0xff1);
- spin_unlock(&sh_domain->map_lock);
- break;
- case SZ_1M:
- spin_lock(&sh_domain->map_lock);
- l2free(sh_domain, l1index, &l2);
- pgtable_write(&sh_domain->l1, l1index, 1, paddr | 0xc02);
- spin_unlock(&sh_domain->map_lock);
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
- if (!ret)
- domain_tlb_flush(sh_domain);
- l2realfree(&l2);
- return ret;
-}
-
-static size_t shmobile_iommu_unmap(struct iommu_domain *domain,
- unsigned long iova, size_t size)
-{
- struct shmobile_iommu_domain_pgtable l2 = { .pgtable = NULL };
- struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
- unsigned int l1index, l2index;
- uint32_t l2entry = 0;
- size_t ret = 0;
-
- l1index = iova >> 20;
- if (!(iova & 0xfffff) && size >= SZ_1M) {
- spin_lock(&sh_domain->map_lock);
- l2free(sh_domain, l1index, &l2);
- spin_unlock(&sh_domain->map_lock);
- ret = SZ_1M;
- goto done;
- }
- l2index = (iova >> 12) & 0xff;
- spin_lock(&sh_domain->map_lock);
- if (sh_domain->l2[l1index].pgtable)
- l2entry = pgtable_read(&sh_domain->l2[l1index], l2index);
- switch (l2entry & 3) {
- case 1:
- if (l2index & 0xf)
- break;
- pgtable_write(&sh_domain->l2[l1index], l2index, 0x10, 0);
- ret = SZ_64K;
- break;
- case 2:
- pgtable_write(&sh_domain->l2[l1index], l2index, 1, 0);
- ret = SZ_4K;
- break;
- }
- spin_unlock(&sh_domain->map_lock);
-done:
- if (ret)
- domain_tlb_flush(sh_domain);
- l2realfree(&l2);
- return ret;
-}
-
-static phys_addr_t shmobile_iommu_iova_to_phys(struct iommu_domain *domain,
- dma_addr_t iova)
-{
- struct shmobile_iommu_domain *sh_domain = to_sh_domain(domain);
- uint32_t l1entry = 0, l2entry = 0;
- unsigned int l1index, l2index;
-
- l1index = iova >> 20;
- l2index = (iova >> 12) & 0xff;
- spin_lock(&sh_domain->map_lock);
- if (sh_domain->l2[l1index].pgtable)
- l2entry = pgtable_read(&sh_domain->l2[l1index], l2index);
- else
- l1entry = pgtable_read(&sh_domain->l1, l1index);
- spin_unlock(&sh_domain->map_lock);
- switch (l2entry & 3) {
- case 1:
- return (l2entry & ~0xffff) | (iova & 0xffff);
- case 2:
- return (l2entry & ~0xfff) | (iova & 0xfff);
- default:
- if ((l1entry & 3) == 2)
- return (l1entry & ~0xfffff) | (iova & 0xfffff);
- return 0;
- }
-}
-
-static int find_dev_name(struct shmobile_ipmmu *ipmmu, const char *dev_name)
-{
- unsigned int i, n = ipmmu->num_dev_names;
-
- for (i = 0; i < n; i++) {
- if (strcmp(ipmmu->dev_names[i], dev_name) == 0)
- return 1;
- }
- return 0;
-}
-
-static int shmobile_iommu_add_device(struct device *dev)
-{
- struct shmobile_iommu_archdata *archdata = ipmmu_archdata;
- struct dma_iommu_mapping *mapping;
-
- if (!find_dev_name(archdata->ipmmu, dev_name(dev)))
- return 0;
- mapping = archdata->iommu_mapping;
- if (!mapping) {
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
- L1_LEN << 20);
- if (IS_ERR(mapping))
- return PTR_ERR(mapping);
- archdata->iommu_mapping = mapping;
- }
- dev->archdata.iommu = archdata;
- if (arm_iommu_attach_device(dev, mapping))
- pr_err("arm_iommu_attach_device failed\n");
- return 0;
-}
-
-static const struct iommu_ops shmobile_iommu_ops = {
- .domain_alloc = shmobile_iommu_domain_alloc,
- .domain_free = shmobile_iommu_domain_free,
- .attach_dev = shmobile_iommu_attach_device,
- .detach_dev = shmobile_iommu_detach_device,
- .map = shmobile_iommu_map,
- .unmap = shmobile_iommu_unmap,
- .map_sg = default_iommu_map_sg,
- .iova_to_phys = shmobile_iommu_iova_to_phys,
- .add_device = shmobile_iommu_add_device,
- .pgsize_bitmap = SZ_1M | SZ_64K | SZ_4K,
-};
-
-int ipmmu_iommu_init(struct shmobile_ipmmu *ipmmu)
-{
- static struct shmobile_iommu_archdata *archdata;
-
- l1cache = kmem_cache_create("shmobile-iommu-pgtable1", L1_SIZE,
- L1_ALIGN, SLAB_HWCACHE_ALIGN, NULL);
- if (!l1cache)
- return -ENOMEM;
- l2cache = kmem_cache_create("shmobile-iommu-pgtable2", L2_SIZE,
- L2_ALIGN, SLAB_HWCACHE_ALIGN, NULL);
- if (!l2cache) {
- kmem_cache_destroy(l1cache);
- return -ENOMEM;
- }
- archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
- if (!archdata) {
- kmem_cache_destroy(l1cache);
- kmem_cache_destroy(l2cache);
- return -ENOMEM;
- }
- spin_lock_init(&archdata->attach_lock);
- archdata->ipmmu = ipmmu;
- ipmmu_archdata = archdata;
- bus_set_iommu(&platform_bus_type, &shmobile_iommu_ops);
- return 0;
-}
diff --git a/drivers/iommu/shmobile-ipmmu.c b/drivers/iommu/shmobile-ipmmu.c
deleted file mode 100644
index 951651a9746b..000000000000
--- a/drivers/iommu/shmobile-ipmmu.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * IPMMU/IPMMUI
- * Copyright (C) 2012 Hideki EIRAKU
- *
- * 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.
- */
-
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/platform_data/sh_ipmmu.h>
-#include "shmobile-ipmmu.h"
-
-#define IMCTR1 0x000
-#define IMCTR2 0x004
-#define IMASID 0x010
-#define IMTTBR 0x014
-#define IMTTBCR 0x018
-
-#define IMCTR1_TLBEN (1 << 0)
-#define IMCTR1_FLUSH (1 << 1)
-
-static void ipmmu_reg_write(struct shmobile_ipmmu *ipmmu, unsigned long reg_off,
- unsigned long data)
-{
- iowrite32(data, ipmmu->ipmmu_base + reg_off);
-}
-
-void ipmmu_tlb_flush(struct shmobile_ipmmu *ipmmu)
-{
- if (!ipmmu)
- return;
-
- spin_lock(&ipmmu->flush_lock);
- if (ipmmu->tlb_enabled)
- ipmmu_reg_write(ipmmu, IMCTR1, IMCTR1_FLUSH | IMCTR1_TLBEN);
- else
- ipmmu_reg_write(ipmmu, IMCTR1, IMCTR1_FLUSH);
- spin_unlock(&ipmmu->flush_lock);
-}
-
-void ipmmu_tlb_set(struct shmobile_ipmmu *ipmmu, unsigned long phys, int size,
- int asid)
-{
- if (!ipmmu)
- return;
-
- spin_lock(&ipmmu->flush_lock);
- switch (size) {
- default:
- ipmmu->tlb_enabled = 0;
- break;
- case 0x2000:
- ipmmu_reg_write(ipmmu, IMTTBCR, 1);
- ipmmu->tlb_enabled = 1;
- break;
- case 0x1000:
- ipmmu_reg_write(ipmmu, IMTTBCR, 2);
- ipmmu->tlb_enabled = 1;
- break;
- case 0x800:
- ipmmu_reg_write(ipmmu, IMTTBCR, 3);
- ipmmu->tlb_enabled = 1;
- break;
- case 0x400:
- ipmmu_reg_write(ipmmu, IMTTBCR, 4);
- ipmmu->tlb_enabled = 1;
- break;
- case 0x200:
- ipmmu_reg_write(ipmmu, IMTTBCR, 5);
- ipmmu->tlb_enabled = 1;
- break;
- case 0x100:
- ipmmu_reg_write(ipmmu, IMTTBCR, 6);
- ipmmu->tlb_enabled = 1;
- break;
- case 0x80:
- ipmmu_reg_write(ipmmu, IMTTBCR, 7);
- ipmmu->tlb_enabled = 1;
- break;
- }
- ipmmu_reg_write(ipmmu, IMTTBR, phys);
- ipmmu_reg_write(ipmmu, IMASID, asid);
- spin_unlock(&ipmmu->flush_lock);
-}
-
-static int ipmmu_probe(struct platform_device *pdev)
-{
- struct shmobile_ipmmu *ipmmu;
- struct resource *res;
- struct shmobile_ipmmu_platform_data *pdata = pdev->dev.platform_data;
-
- ipmmu = devm_kzalloc(&pdev->dev, sizeof(*ipmmu), GFP_KERNEL);
- if (!ipmmu) {
- dev_err(&pdev->dev, "cannot allocate device data\n");
- return -ENOMEM;
- }
- spin_lock_init(&ipmmu->flush_lock);
- ipmmu->dev = &pdev->dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ipmmu->ipmmu_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ipmmu->ipmmu_base))
- return PTR_ERR(ipmmu->ipmmu_base);
-
- ipmmu->dev_names = pdata->dev_names;
- ipmmu->num_dev_names = pdata->num_dev_names;
- platform_set_drvdata(pdev, ipmmu);
- ipmmu_reg_write(ipmmu, IMCTR1, 0x0); /* disable TLB */
- ipmmu_reg_write(ipmmu, IMCTR2, 0x0); /* disable PMB */
- return ipmmu_iommu_init(ipmmu);
-}
-
-static struct platform_driver ipmmu_driver = {
- .probe = ipmmu_probe,
- .driver = {
- .name = "ipmmu",
- },
-};
-
-static int __init ipmmu_init(void)
-{
- return platform_driver_register(&ipmmu_driver);
-}
-subsys_initcall(ipmmu_init);
diff --git a/drivers/iommu/shmobile-ipmmu.h b/drivers/iommu/shmobile-ipmmu.h
deleted file mode 100644
index 9524743ca1fb..000000000000
--- a/drivers/iommu/shmobile-ipmmu.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* shmobile-ipmmu.h
- *
- * Copyright (C) 2012 Hideki EIRAKU
- *
- * 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.
- */
-
-#ifndef __SHMOBILE_IPMMU_H__
-#define __SHMOBILE_IPMMU_H__
-
-struct shmobile_ipmmu {
- struct device *dev;
- void __iomem *ipmmu_base;
- int tlb_enabled;
- spinlock_t flush_lock;
- const char * const *dev_names;
- unsigned int num_dev_names;
-};
-
-#ifdef CONFIG_SHMOBILE_IPMMU_TLB
-void ipmmu_tlb_flush(struct shmobile_ipmmu *ipmmu);
-void ipmmu_tlb_set(struct shmobile_ipmmu *ipmmu, unsigned long phys, int size,
- int asid);
-int ipmmu_iommu_init(struct shmobile_ipmmu *ipmmu);
-#else
-static inline int ipmmu_iommu_init(struct shmobile_ipmmu *ipmmu)
-{
- return -EINVAL;
-}
-#endif
-
-#endif /* __SHMOBILE_IPMMU_H__ */
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index cadf104e3074..598ab3f0e0ac 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -210,12 +210,7 @@ int __init fpga_irq_of_init(struct device_node *node,
parent_irq = -1;
}
-#ifdef CONFIG_ARCH_VERSATILE
- fpga_irq_init(base, node->name, IRQ_SIC_START, parent_irq, valid_mask,
- node);
-#else
fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
-#endif
writel(clear_mask, base + IRQ_ENABLE_CLEAR);
writel(clear_mask, base + FIQ_ENABLE_CLEAR);
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 17c63ec9fb9e..e3d3b1aaa9e0 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -242,7 +242,7 @@ static void pca9532_input_work(struct work_struct *work)
#ifdef CONFIG_LEDS_PCA9532_GPIO
static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
{
- struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+ struct pca9532_data *data = gpiochip_get_data(gc);
struct pca9532_led *led = &data->leds[offset];
if (led->type == PCA9532_TYPE_GPIO)
@@ -253,7 +253,7 @@ static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
{
- struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+ struct pca9532_data *data = gpiochip_get_data(gc);
struct pca9532_led *led = &data->leds[offset];
if (val)
@@ -266,7 +266,7 @@ static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int va
static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
{
- struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+ struct pca9532_data *data = gpiochip_get_data(gc);
unsigned char reg;
reg = i2c_smbus_read_byte_data(data->client, PCA9532_REG_INPUT(offset));
@@ -315,7 +315,7 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
}
#ifdef CONFIG_LEDS_PCA9532_GPIO
- if (data->gpio.dev)
+ if (data->gpio.parent)
gpiochip_remove(&data->gpio);
#endif
@@ -409,13 +409,13 @@ static int pca9532_configure(struct i2c_client *client,
data->gpio.can_sleep = 1;
data->gpio.base = pdata->gpio_base;
data->gpio.ngpio = data->chip_info->num_leds;
- data->gpio.dev = &client->dev;
+ data->gpio.parent = &client->dev;
data->gpio.owner = THIS_MODULE;
- err = gpiochip_add(&data->gpio);
+ err = gpiochip_add_data(&data->gpio, data);
if (err) {
/* Use data->gpio.dev as a flag for freeing gpiochip */
- data->gpio.dev = NULL;
+ data->gpio.parent = NULL;
dev_warn(&client->dev, "could not add gpiochip\n");
} else {
dev_info(&client->dev, "gpios %i...%i\n",
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index edbecc4ca2da..c548ea10f0f0 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -603,7 +603,7 @@ static int tca6507_blink_set(struct led_classdev *led_cdev,
static void tca6507_gpio_set_value(struct gpio_chip *gc,
unsigned offset, int val)
{
- struct tca6507_chip *tca = container_of(gc, struct tca6507_chip, gpio);
+ struct tca6507_chip *tca = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&tca->lock, flags);
@@ -651,11 +651,11 @@ static int tca6507_probe_gpios(struct i2c_client *client,
tca->gpio.owner = THIS_MODULE;
tca->gpio.direction_output = tca6507_gpio_direction_output;
tca->gpio.set = tca6507_gpio_set_value;
- tca->gpio.dev = &client->dev;
+ tca->gpio.parent = &client->dev;
#ifdef CONFIG_OF_GPIO
tca->gpio.of_node = of_node_get(client->dev.of_node);
#endif
- err = gpiochip_add(&tca->gpio);
+ err = gpiochip_add_data(&tca->gpio, tca);
if (err) {
tca->gpio.ngpio = 0;
return err;
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 312ffd3d0017..9e385b38debf 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -22,7 +22,8 @@
unsigned long switcher_addr;
struct page **lg_switcher_pages;
-static struct vm_struct *switcher_vma;
+static struct vm_struct *switcher_text_vma;
+static struct vm_struct *switcher_stacks_vma;
/* This One Big lock protects all inter-guest data structures. */
DEFINE_MUTEX(lguest_lock);
@@ -83,54 +84,80 @@ static __init int map_switcher(void)
}
/*
+ * Copy in the compiled-in Switcher code (from x86/switcher_32.S).
+ * It goes in the first page, which we map in momentarily.
+ */
+ memcpy(kmap(lg_switcher_pages[0]), start_switcher_text,
+ end_switcher_text - start_switcher_text);
+ kunmap(lg_switcher_pages[0]);
+
+ /*
* We place the Switcher underneath the fixmap area, which is the
* highest virtual address we can get. This is important, since we
* tell the Guest it can't access this memory, so we want its ceiling
* as high as possible.
*/
- switcher_addr = FIXADDR_START - (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE;
+ switcher_addr = FIXADDR_START - TOTAL_SWITCHER_PAGES*PAGE_SIZE;
/*
- * Now we reserve the "virtual memory area" we want. We might
- * not get it in theory, but in practice it's worked so far.
- * The end address needs +1 because __get_vm_area allocates an
- * extra guard page, so we need space for that.
+ * Now we reserve the "virtual memory area"s we want. We might
+ * not get them in theory, but in practice it's worked so far.
+ *
+ * We want the switcher text to be read-only and executable, and
+ * the stacks to be read-write and non-executable.
*/
- switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
- VM_ALLOC, switcher_addr, switcher_addr
- + (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE);
- if (!switcher_vma) {
+ switcher_text_vma = __get_vm_area(PAGE_SIZE, VM_ALLOC|VM_NO_GUARD,
+ switcher_addr,
+ switcher_addr + PAGE_SIZE);
+
+ if (!switcher_text_vma) {
err = -ENOMEM;
printk("lguest: could not map switcher pages high\n");
goto free_pages;
}
+ switcher_stacks_vma = __get_vm_area(SWITCHER_STACK_PAGES * PAGE_SIZE,
+ VM_ALLOC|VM_NO_GUARD,
+ switcher_addr + PAGE_SIZE,
+ switcher_addr + TOTAL_SWITCHER_PAGES * PAGE_SIZE);
+ if (!switcher_stacks_vma) {
+ err = -ENOMEM;
+ printk("lguest: could not map switcher pages high\n");
+ goto free_text_vma;
+ }
+
/*
* This code actually sets up the pages we've allocated to appear at
* switcher_addr. map_vm_area() takes the vma we allocated above, the
- * kind of pages we're mapping (kernel pages), and a pointer to our
- * array of struct pages.
+ * kind of pages we're mapping (kernel text pages and kernel writable
+ * pages respectively), and a pointer to our array of struct pages.
*/
- err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, lg_switcher_pages);
+ err = map_vm_area(switcher_text_vma, PAGE_KERNEL_RX, lg_switcher_pages);
+ if (err) {
+ printk("lguest: text map_vm_area failed: %i\n", err);
+ goto free_vmas;
+ }
+
+ err = map_vm_area(switcher_stacks_vma, PAGE_KERNEL,
+ lg_switcher_pages + SWITCHER_TEXT_PAGES);
if (err) {
- printk("lguest: map_vm_area failed: %i\n", err);
- goto free_vma;
+ printk("lguest: stacks map_vm_area failed: %i\n", err);
+ goto free_vmas;
}
/*
* Now the Switcher is mapped at the right address, we can't fail!
- * Copy in the compiled-in Switcher code (from x86/switcher_32.S).
*/
- memcpy(switcher_vma->addr, start_switcher_text,
- end_switcher_text - start_switcher_text);
-
printk(KERN_INFO "lguest: mapped switcher at %p\n",
- switcher_vma->addr);
+ switcher_text_vma->addr);
/* And we succeeded... */
return 0;
-free_vma:
- vunmap(switcher_vma->addr);
+free_vmas:
+ /* Undoes map_vm_area and __get_vm_area */
+ vunmap(switcher_stacks_vma->addr);
+free_text_vma:
+ vunmap(switcher_text_vma->addr);
free_pages:
i = TOTAL_SWITCHER_PAGES;
free_some_pages:
@@ -148,7 +175,8 @@ static void unmap_switcher(void)
unsigned int i;
/* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */
- vunmap(switcher_vma->addr);
+ vunmap(switcher_text_vma->addr);
+ vunmap(switcher_stacks_vma->addr);
/* Now we just need to free the pages we copied the switcher into */
for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
__free_pages(lg_switcher_pages[i], 0);
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 048901a1111a..caaec654d7ea 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -582,6 +582,7 @@ static struct of_device_id rackmeter_match[] = {
{ .name = "i2s" },
{ }
};
+MODULE_DEVICE_TABLE(of, rackmeter_match);
static struct macio_driver rackmeter_driver = {
.driver = {
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index f9512bfa6c3c..01ee736fe0ef 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -425,8 +425,9 @@ static int __init via_pmu_start(void)
gpio_irq = irq_of_parse_and_map(gpio_node, 0);
if (gpio_irq != NO_IRQ) {
- if (request_irq(gpio_irq, gpio1_interrupt, IRQF_TIMER,
- "GPIO1 ADB", (void *)0))
+ if (request_irq(gpio_irq, gpio1_interrupt,
+ IRQF_NO_SUSPEND, "GPIO1 ADB",
+ (void *)0))
printk(KERN_ERR "pmu: can't get irq %d"
" (GPIO1)\n", gpio_irq);
else
diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c
index 4835817c5365..2394cfe892b6 100644
--- a/drivers/mailbox/mailbox-sti.c
+++ b/drivers/mailbox/mailbox-sti.c
@@ -384,7 +384,7 @@ static struct mbox_chan *sti_mbox_xlate(struct mbox_controller *mbox,
return chan;
}
-static struct mbox_chan_ops sti_mbox_ops = {
+static const struct mbox_chan_ops sti_mbox_ops = {
.startup = sti_mbox_startup_chan,
.shutdown = sti_mbox_shutdown_chan,
.send_data = sti_mbox_send_data,
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index d6a1126d85ce..0ded8e97751d 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -48,13 +48,29 @@ struct resync_info {
#define MD_CLUSTER_SUSPEND_READ_BALANCING 2
#define MD_CLUSTER_BEGIN_JOIN_CLUSTER 3
+/* Lock the send communication. This is done through
+ * bit manipulation as opposed to a mutex in order to
+ * accomodate lock and hold. See next comment.
+ */
+#define MD_CLUSTER_SEND_LOCK 4
+/* If cluster operations (such as adding a disk) must lock the
+ * communication channel, so as to perform extra operations
+ * (update metadata) and no other operation is allowed on the
+ * MD. Token needs to be locked and held until the operation
+ * completes witha md_update_sb(), which would eventually release
+ * the lock.
+ */
+#define MD_CLUSTER_SEND_LOCKED_ALREADY 5
+
struct md_cluster_info {
/* dlm lock space and resources for clustered raid. */
dlm_lockspace_t *lockspace;
int slot_number;
struct completion completion;
+ struct mutex recv_mutex;
struct dlm_lock_resource *bitmap_lockres;
+ struct dlm_lock_resource **other_bitmap_lockres;
struct dlm_lock_resource *resync_lockres;
struct list_head suspend_list;
spinlock_t suspend_lock;
@@ -67,6 +83,7 @@ struct md_cluster_info {
struct dlm_lock_resource *no_new_dev_lockres;
struct md_thread *recv_thread;
struct completion newdisk_completion;
+ wait_queue_head_t wait;
unsigned long state;
};
@@ -431,8 +448,10 @@ static void process_add_new_disk(struct mddev *mddev, struct cluster_msg *cmsg)
static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
- md_reload_sb(mddev, le32_to_cpu(msg->raid_slot));
+ mddev->good_device_nr = le32_to_cpu(msg->raid_slot);
+ set_bit(MD_RELOAD_SB, &mddev->flags);
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
+ md_wakeup_thread(mddev->thread);
}
static void process_remove_disk(struct mddev *mddev, struct cluster_msg *msg)
@@ -440,8 +459,11 @@ static void process_remove_disk(struct mddev *mddev, struct cluster_msg *msg)
struct md_rdev *rdev = md_find_rdev_nr_rcu(mddev,
le32_to_cpu(msg->raid_slot));
- if (rdev)
- md_kick_rdev_from_array(rdev);
+ if (rdev) {
+ set_bit(ClusterRemove, &rdev->flags);
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+ }
else
pr_warn("%s: %d Could not find disk(%d) to REMOVE\n",
__func__, __LINE__, le32_to_cpu(msg->raid_slot));
@@ -502,9 +524,11 @@ static void recv_daemon(struct md_thread *thread)
struct cluster_msg msg;
int ret;
+ mutex_lock(&cinfo->recv_mutex);
/*get CR on Message*/
if (dlm_lock_sync(message_lockres, DLM_LOCK_CR)) {
pr_err("md/raid1:failed to get CR on MESSAGE\n");
+ mutex_unlock(&cinfo->recv_mutex);
return;
}
@@ -528,33 +552,45 @@ static void recv_daemon(struct md_thread *thread)
ret = dlm_unlock_sync(message_lockres);
if (unlikely(ret != 0))
pr_info("unlock msg failed return %d\n", ret);
+ mutex_unlock(&cinfo->recv_mutex);
}
-/* lock_comm()
+/* lock_token()
* Takes the lock on the TOKEN lock resource so no other
* node can communicate while the operation is underway.
- * If called again, and the TOKEN lock is alread in EX mode
- * return success. However, care must be taken that unlock_comm()
- * is called only once.
*/
-static int lock_comm(struct md_cluster_info *cinfo)
+static int lock_token(struct md_cluster_info *cinfo)
{
int error;
- if (cinfo->token_lockres->mode == DLM_LOCK_EX)
- return 0;
-
error = dlm_lock_sync(cinfo->token_lockres, DLM_LOCK_EX);
if (error)
pr_err("md-cluster(%s:%d): failed to get EX on TOKEN (%d)\n",
__func__, __LINE__, error);
+
+ /* Lock the receive sequence */
+ mutex_lock(&cinfo->recv_mutex);
return error;
}
+/* lock_comm()
+ * Sets the MD_CLUSTER_SEND_LOCK bit to lock the send channel.
+ */
+static int lock_comm(struct md_cluster_info *cinfo)
+{
+ wait_event(cinfo->wait,
+ !test_and_set_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state));
+
+ return lock_token(cinfo);
+}
+
static void unlock_comm(struct md_cluster_info *cinfo)
{
WARN_ON(cinfo->token_lockres->mode != DLM_LOCK_EX);
+ mutex_unlock(&cinfo->recv_mutex);
dlm_unlock_sync(cinfo->token_lockres);
+ clear_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state);
+ wake_up(&cinfo->wait);
}
/* __sendmsg()
@@ -707,6 +743,8 @@ static int join(struct mddev *mddev, int nodes)
spin_lock_init(&cinfo->suspend_lock);
init_completion(&cinfo->completion);
set_bit(MD_CLUSTER_BEGIN_JOIN_CLUSTER, &cinfo->state);
+ init_waitqueue_head(&cinfo->wait);
+ mutex_init(&cinfo->recv_mutex);
mddev->cluster_info = cinfo;
@@ -800,6 +838,7 @@ static void resync_bitmap(struct mddev *mddev)
__func__, __LINE__, err);
}
+static void unlock_all_bitmaps(struct mddev *mddev);
static int leave(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
@@ -820,6 +859,7 @@ static int leave(struct mddev *mddev)
lockres_free(cinfo->ack_lockres);
lockres_free(cinfo->no_new_dev_lockres);
lockres_free(cinfo->bitmap_lockres);
+ unlock_all_bitmaps(mddev);
dlm_release_lockspace(cinfo->lockspace, 2);
return 0;
}
@@ -835,9 +875,25 @@ static int slot_number(struct mddev *mddev)
return cinfo->slot_number - 1;
}
+/*
+ * Check if the communication is already locked, else lock the communication
+ * channel.
+ * If it is already locked, token is in EX mode, and hence lock_token()
+ * should not be called.
+ */
static int metadata_update_start(struct mddev *mddev)
{
- return lock_comm(mddev->cluster_info);
+ struct md_cluster_info *cinfo = mddev->cluster_info;
+
+ wait_event(cinfo->wait,
+ !test_and_set_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state) ||
+ test_and_clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state));
+
+ /* If token is already locked, return 0 */
+ if (cinfo->token_lockres->mode == DLM_LOCK_EX)
+ return 0;
+
+ return lock_token(cinfo);
}
static int metadata_update_finish(struct mddev *mddev)
@@ -862,6 +918,7 @@ static int metadata_update_finish(struct mddev *mddev)
ret = __sendmsg(cinfo, &cmsg);
} else
pr_warn("md-cluster: No good device id found to send\n");
+ clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
unlock_comm(cinfo);
return ret;
}
@@ -869,6 +926,7 @@ static int metadata_update_finish(struct mddev *mddev)
static void metadata_update_cancel(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
+ clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
unlock_comm(cinfo);
}
@@ -882,8 +940,16 @@ static int resync_start(struct mddev *mddev)
static int resync_info_update(struct mddev *mddev, sector_t lo, sector_t hi)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
+ struct resync_info ri;
struct cluster_msg cmsg = {0};
+ /* do not send zero again, if we have sent before */
+ if (hi == 0) {
+ memcpy(&ri, cinfo->bitmap_lockres->lksb.sb_lvbptr, sizeof(struct resync_info));
+ if (le64_to_cpu(ri.hi) == 0)
+ return 0;
+ }
+
add_resync_info(cinfo->bitmap_lockres, lo, hi);
/* Re-acquire the lock to refresh LVB */
dlm_lock_sync(cinfo->bitmap_lockres, DLM_LOCK_PW);
@@ -954,14 +1020,30 @@ static int add_new_disk(struct mddev *mddev, struct md_rdev *rdev)
ret = -ENOENT;
if (ret)
unlock_comm(cinfo);
- else
+ else {
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
+ /* Since MD_CHANGE_DEVS will be set in add_bound_rdev which
+ * will run soon after add_new_disk, the below path will be
+ * invoked:
+ * md_wakeup_thread(mddev->thread)
+ * -> conf->thread (raid1d)
+ * -> md_check_recovery -> md_update_sb
+ * -> metadata_update_start/finish
+ * MD_CLUSTER_SEND_LOCKED_ALREADY will be cleared eventually.
+ *
+ * For other failure cases, metadata_update_cancel and
+ * add_new_disk_cancel also clear below bit as well.
+ * */
+ set_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
+ wake_up(&cinfo->wait);
+ }
return ret;
}
static void add_new_disk_cancel(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
+ clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
unlock_comm(cinfo);
}
@@ -986,7 +1068,59 @@ static int remove_disk(struct mddev *mddev, struct md_rdev *rdev)
struct md_cluster_info *cinfo = mddev->cluster_info;
cmsg.type = cpu_to_le32(REMOVE);
cmsg.raid_slot = cpu_to_le32(rdev->desc_nr);
- return __sendmsg(cinfo, &cmsg);
+ return sendmsg(cinfo, &cmsg);
+}
+
+static int lock_all_bitmaps(struct mddev *mddev)
+{
+ int slot, my_slot, ret, held = 1, i = 0;
+ char str[64];
+ struct md_cluster_info *cinfo = mddev->cluster_info;
+
+ cinfo->other_bitmap_lockres = kzalloc((mddev->bitmap_info.nodes - 1) *
+ sizeof(struct dlm_lock_resource *),
+ GFP_KERNEL);
+ if (!cinfo->other_bitmap_lockres) {
+ pr_err("md: can't alloc mem for other bitmap locks\n");
+ return 0;
+ }
+
+ my_slot = slot_number(mddev);
+ for (slot = 0; slot < mddev->bitmap_info.nodes; slot++) {
+ if (slot == my_slot)
+ continue;
+
+ memset(str, '\0', 64);
+ snprintf(str, 64, "bitmap%04d", slot);
+ cinfo->other_bitmap_lockres[i] = lockres_init(mddev, str, NULL, 1);
+ if (!cinfo->other_bitmap_lockres[i])
+ return -ENOMEM;
+
+ cinfo->other_bitmap_lockres[i]->flags |= DLM_LKF_NOQUEUE;
+ ret = dlm_lock_sync(cinfo->other_bitmap_lockres[i], DLM_LOCK_PW);
+ if (ret)
+ held = -1;
+ i++;
+ }
+
+ return held;
+}
+
+static void unlock_all_bitmaps(struct mddev *mddev)
+{
+ struct md_cluster_info *cinfo = mddev->cluster_info;
+ int i;
+
+ /* release other node's bitmap lock if they are existed */
+ if (cinfo->other_bitmap_lockres) {
+ for (i = 0; i < mddev->bitmap_info.nodes - 1; i++) {
+ if (cinfo->other_bitmap_lockres[i]) {
+ dlm_unlock_sync(cinfo->other_bitmap_lockres[i]);
+ lockres_free(cinfo->other_bitmap_lockres[i]);
+ }
+ }
+ kfree(cinfo->other_bitmap_lockres);
+ }
}
static int gather_bitmaps(struct md_rdev *rdev)
@@ -1034,6 +1168,8 @@ static struct md_cluster_operations cluster_ops = {
.new_disk_ack = new_disk_ack,
.remove_disk = remove_disk,
.gather_bitmaps = gather_bitmaps,
+ .lock_all_bitmaps = lock_all_bitmaps,
+ .unlock_all_bitmaps = unlock_all_bitmaps,
};
static int __init cluster_init(void)
diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h
index e75ea2613184..45ce6c97d8bd 100644
--- a/drivers/md/md-cluster.h
+++ b/drivers/md/md-cluster.h
@@ -24,6 +24,8 @@ struct md_cluster_operations {
int (*new_disk_ack)(struct mddev *mddev, bool ack);
int (*remove_disk)(struct mddev *mddev, struct md_rdev *rdev);
int (*gather_bitmaps)(struct md_rdev *rdev);
+ int (*lock_all_bitmaps)(struct mddev *mddev);
+ void (*unlock_all_bitmaps)(struct mddev *mddev);
};
#endif /* _MD_CLUSTER_H */
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 61aacab424cf..e55e6cf9ec17 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -34,6 +34,7 @@
#include <linux/kthread.h>
#include <linux/blkdev.h>
+#include <linux/badblocks.h>
#include <linux/sysctl.h>
#include <linux/seq_file.h>
#include <linux/fs.h>
@@ -205,15 +206,6 @@ void md_new_event(struct mddev *mddev)
}
EXPORT_SYMBOL_GPL(md_new_event);
-/* Alternate version that can be called from interrupts
- * when calling sysfs_notify isn't needed.
- */
-static void md_new_event_inintr(struct mddev *mddev)
-{
- atomic_inc(&md_event_count);
- wake_up(&md_event_waiters);
-}
-
/*
* Enables to iterate over all existing md arrays
* all_mddevs_lock protects this list.
@@ -259,8 +251,7 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
blk_queue_split(q, &bio, q->bio_split);
- if (mddev == NULL || mddev->pers == NULL
- || !mddev->ready) {
+ if (mddev == NULL || mddev->pers == NULL) {
bio_io_error(bio);
return BLK_QC_T_NONE;
}
@@ -710,8 +701,7 @@ void md_rdev_clear(struct md_rdev *rdev)
put_page(rdev->bb_page);
rdev->bb_page = NULL;
}
- kfree(rdev->badblocks.page);
- rdev->badblocks.page = NULL;
+ badblocks_exit(&rdev->badblocks);
}
EXPORT_SYMBOL_GPL(md_rdev_clear);
@@ -1026,8 +1016,9 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
* (not needed for Linear and RAID0 as metadata doesn't
* record this size)
*/
- if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
- rdev->sectors = (2ULL << 32) - 2;
+ if (IS_ENABLED(CONFIG_LBDAF) && (u64)rdev->sectors >= (2ULL << 32) &&
+ sb->level >= 1)
+ rdev->sectors = (sector_t)(2ULL << 32) - 2;
if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
/* "this cannot possibly happen" ... */
@@ -1199,13 +1190,13 @@ static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev)
memcpy(&sb->set_uuid2, mddev->uuid+8, 4);
memcpy(&sb->set_uuid3, mddev->uuid+12,4);
- sb->ctime = mddev->ctime;
+ sb->ctime = clamp_t(time64_t, mddev->ctime, 0, U32_MAX);
sb->level = mddev->level;
sb->size = mddev->dev_sectors / 2;
sb->raid_disks = mddev->raid_disks;
sb->md_minor = mddev->md_minor;
sb->not_persistent = 0;
- sb->utime = mddev->utime;
+ sb->utime = clamp_t(time64_t, mddev->utime, 0, U32_MAX);
sb->state = 0;
sb->events_hi = (mddev->events>>32);
sb->events_lo = (u32)mddev->events;
@@ -1320,8 +1311,9 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
/* Limit to 4TB as metadata cannot record more than that.
* 4TB == 2^32 KB, or 2*2^32 sectors.
*/
- if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
- num_sectors = (2ULL << 32) - 2;
+ if (IS_ENABLED(CONFIG_LBDAF) && (u64)num_sectors >= (2ULL << 32) &&
+ rdev->mddev->level >= 1)
+ num_sectors = (sector_t)(2ULL << 32) - 2;
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
@@ -1361,8 +1353,6 @@ static __le32 calc_sb_1_csum(struct mdp_superblock_1 *sb)
return cpu_to_le32(csum);
}
-static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
- int acknowledged);
static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_version)
{
struct mdp_superblock_1 *sb;
@@ -1487,8 +1477,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
count <<= sb->bblog_shift;
if (bb + 1 == 0)
break;
- if (md_set_badblocks(&rdev->badblocks,
- sector, count, 1) == 0)
+ if (badblocks_set(&rdev->badblocks, sector, count, 1))
return -EINVAL;
}
} else if (sb->bblog_offset != 0)
@@ -1545,8 +1534,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->patch_version = 0;
mddev->external = 0;
mddev->chunk_sectors = le32_to_cpu(sb->chunksize);
- mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
- mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
+ mddev->ctime = le64_to_cpu(sb->ctime);
+ mddev->utime = le64_to_cpu(sb->utime);
mddev->level = le32_to_cpu(sb->level);
mddev->clevel[0] = 0;
mddev->layout = le32_to_cpu(sb->layout);
@@ -1605,6 +1594,11 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_chunk_sectors = mddev->chunk_sectors;
}
+ if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL) {
+ set_bit(MD_HAS_JOURNAL, &mddev->flags);
+ if (mddev->recovery_cp == MaxSector)
+ set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
+ }
} else if (mddev->pers == NULL) {
/* Insist of good event counter while assembling, except for
* spares (which don't need an event count) */
@@ -1651,8 +1645,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
}
set_bit(Journal, &rdev->flags);
rdev->journal_tail = le64_to_cpu(sb->journal_tail);
- if (mddev->recovery_cp == MaxSector)
- set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
rdev->raid_disk = 0;
break;
default:
@@ -1672,8 +1664,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
set_bit(WriteMostly, &rdev->flags);
if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT)
set_bit(Replacement, &rdev->flags);
- if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL)
- set_bit(MD_HAS_JOURNAL, &mddev->flags);
} else /* MULTIPATH are always insync */
set_bit(In_sync, &rdev->flags);
@@ -2017,28 +2007,32 @@ int md_integrity_register(struct mddev *mddev)
}
EXPORT_SYMBOL(md_integrity_register);
-/* Disable data integrity if non-capable/non-matching disk is being added */
-void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
+/*
+ * Attempt to add an rdev, but only if it is consistent with the current
+ * integrity profile
+ */
+int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
{
struct blk_integrity *bi_rdev;
struct blk_integrity *bi_mddev;
+ char name[BDEVNAME_SIZE];
if (!mddev->gendisk)
- return;
+ return 0;
bi_rdev = bdev_get_integrity(rdev->bdev);
bi_mddev = blk_get_integrity(mddev->gendisk);
if (!bi_mddev) /* nothing to do */
- return;
- if (rdev->raid_disk < 0) /* skip spares */
- return;
- if (bi_rdev && blk_integrity_compare(mddev->gendisk,
- rdev->bdev->bd_disk) >= 0)
- return;
- WARN_ON_ONCE(!mddev->suspended);
- printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev));
- blk_integrity_unregister(mddev->gendisk);
+ return 0;
+
+ if (blk_integrity_compare(mddev->gendisk, rdev->bdev->bd_disk) != 0) {
+ printk(KERN_NOTICE "%s: incompatible integrity profile for %s\n",
+ mdname(mddev), bdevname(rdev->bdev, name));
+ return -ENXIO;
+ }
+
+ return 0;
}
EXPORT_SYMBOL(md_integrity_add_rdev);
@@ -2053,8 +2047,9 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
return -EEXIST;
/* make sure rdev->sectors exceeds mddev->dev_sectors */
- if (rdev->sectors && (mddev->dev_sectors == 0 ||
- rdev->sectors < mddev->dev_sectors)) {
+ if (!test_bit(Journal, &rdev->flags) &&
+ rdev->sectors &&
+ (mddev->dev_sectors == 0 || rdev->sectors < mddev->dev_sectors)) {
if (mddev->pers) {
/* Cannot change size, so fail
* If mddev->level <= 0, then we don't care
@@ -2085,7 +2080,8 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
}
}
rcu_read_unlock();
- if (mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
+ if (!test_bit(Journal, &rdev->flags) &&
+ mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
printk(KERN_WARNING "md: %s: array is limited to %d devices\n",
mdname(mddev), mddev->max_disks);
return -EBUSY;
@@ -2320,7 +2316,7 @@ repeat:
rdev_for_each(rdev, mddev) {
if (rdev->badblocks.changed) {
rdev->badblocks.changed = 0;
- md_ack_all_badblocks(&rdev->badblocks);
+ ack_all_badblocks(&rdev->badblocks);
md_error(mddev, rdev);
}
clear_bit(Blocked, &rdev->flags);
@@ -2334,7 +2330,7 @@ repeat:
spin_lock(&mddev->lock);
- mddev->utime = get_seconds();
+ mddev->utime = ktime_get_real_seconds();
if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
force_change = 1;
@@ -2446,7 +2442,7 @@ repeat:
clear_bit(Blocked, &rdev->flags);
if (any_badblocks_changed)
- md_ack_all_badblocks(&rdev->badblocks);
+ ack_all_badblocks(&rdev->badblocks);
clear_bit(BlockedBadBlocks, &rdev->flags);
wake_up(&rdev->blocked_wait);
}
@@ -2460,15 +2456,20 @@ static int add_bound_rdev(struct md_rdev *rdev)
{
struct mddev *mddev = rdev->mddev;
int err = 0;
+ bool add_journal = test_bit(Journal, &rdev->flags);
- if (!mddev->pers->hot_remove_disk) {
+ if (!mddev->pers->hot_remove_disk || add_journal) {
/* If there is hot_add_disk but no hot_remove_disk
* then added disks for geometry changes,
* and should be added immediately.
*/
super_types[mddev->major_version].
validate_super(mddev, rdev);
+ if (add_journal)
+ mddev_suspend(mddev);
err = mddev->pers->hot_add_disk(mddev, rdev);
+ if (add_journal)
+ mddev_resume(mddev);
if (err) {
unbind_rdev_from_array(rdev);
export_rdev(rdev);
@@ -3054,11 +3055,17 @@ static ssize_t recovery_start_store(struct md_rdev *rdev, const char *buf, size_
static struct rdev_sysfs_entry rdev_recovery_start =
__ATTR(recovery_start, S_IRUGO|S_IWUSR, recovery_start_show, recovery_start_store);
-static ssize_t
-badblocks_show(struct badblocks *bb, char *page, int unack);
-static ssize_t
-badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack);
-
+/* sysfs access to bad-blocks list.
+ * We present two files.
+ * 'bad-blocks' lists sector numbers and lengths of ranges that
+ * are recorded as bad. The list is truncated to fit within
+ * the one-page limit of sysfs.
+ * Writing "sector length" to this file adds an acknowledged
+ * bad block list.
+ * 'unacknowledged-bad-blocks' lists bad blocks that have not yet
+ * been acknowledged. Writing to this file adds bad blocks
+ * without acknowledging them. This is largely for testing.
+ */
static ssize_t bb_show(struct md_rdev *rdev, char *page)
{
return badblocks_show(&rdev->badblocks, page, 0);
@@ -3173,14 +3180,7 @@ int md_rdev_init(struct md_rdev *rdev)
* This reserves the space even on arrays where it cannot
* be used - I wonder if that matters
*/
- rdev->badblocks.count = 0;
- rdev->badblocks.shift = -1; /* disabled until explicitly enabled */
- rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
- seqlock_init(&rdev->badblocks.lock);
- if (rdev->badblocks.page == NULL)
- return -ENOMEM;
-
- return 0;
+ return badblocks_init(&rdev->badblocks, 0);
}
EXPORT_SYMBOL_GPL(md_rdev_init);
/*
@@ -5303,7 +5303,6 @@ int md_run(struct mddev *mddev)
smp_wmb();
spin_lock(&mddev->lock);
mddev->pers = pers;
- mddev->ready = 1;
spin_unlock(&mddev->lock);
rdev_for_each(rdev, mddev)
if (rdev->raid_disk >= 0)
@@ -5503,7 +5502,6 @@ static void __md_stop(struct mddev *mddev)
/* Ensure ->event_work is done */
flush_workqueue(md_misc_wq);
spin_lock(&mddev->lock);
- mddev->ready = 0;
mddev->pers = NULL;
spin_unlock(&mddev->lock);
pers->free(mddev, mddev->private);
@@ -5841,7 +5839,7 @@ static int get_array_info(struct mddev *mddev, void __user *arg)
info.major_version = mddev->major_version;
info.minor_version = mddev->minor_version;
info.patch_version = MD_PATCHLEVEL_VERSION;
- info.ctime = mddev->ctime;
+ info.ctime = clamp_t(time64_t, mddev->ctime, 0, U32_MAX);
info.level = mddev->level;
info.size = mddev->dev_sectors / 2;
if (info.size != mddev->dev_sectors / 2) /* overflow */
@@ -5851,7 +5849,7 @@ static int get_array_info(struct mddev *mddev, void __user *arg)
info.md_minor = mddev->md_minor;
info.not_persistent= !mddev->persistent;
- info.utime = mddev->utime;
+ info.utime = clamp_t(time64_t, mddev->utime, 0, U32_MAX);
info.state = 0;
if (mddev->in_sync)
info.state = (1<<MD_SB_CLEAN);
@@ -6042,8 +6040,23 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info)
else
clear_bit(WriteMostly, &rdev->flags);
- if (info->state & (1<<MD_DISK_JOURNAL))
+ if (info->state & (1<<MD_DISK_JOURNAL)) {
+ struct md_rdev *rdev2;
+ bool has_journal = false;
+
+ /* make sure no existing journal disk */
+ rdev_for_each(rdev2, mddev) {
+ if (test_bit(Journal, &rdev2->flags)) {
+ has_journal = true;
+ break;
+ }
+ }
+ if (has_journal) {
+ export_rdev(rdev);
+ return -EBUSY;
+ }
set_bit(Journal, &rdev->flags);
+ }
/*
* check whether the device shows up in other nodes
*/
@@ -6134,15 +6147,11 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev)
{
char b[BDEVNAME_SIZE];
struct md_rdev *rdev;
- int ret = -1;
rdev = find_rdev(mddev, dev);
if (!rdev)
return -ENXIO;
- if (mddev_is_clustered(mddev))
- ret = md_cluster_ops->metadata_update_start(mddev);
-
if (rdev->raid_disk < 0)
goto kick_rdev;
@@ -6153,7 +6162,7 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev)
goto busy;
kick_rdev:
- if (mddev_is_clustered(mddev) && ret == 0)
+ if (mddev_is_clustered(mddev))
md_cluster_ops->remove_disk(mddev, rdev);
md_kick_rdev_from_array(rdev);
@@ -6162,9 +6171,6 @@ kick_rdev:
return 0;
busy:
- if (mddev_is_clustered(mddev) && ret == 0)
- md_cluster_ops->metadata_update_cancel(mddev);
-
printk(KERN_WARNING "md: cannot remove active disk %s from %s ...\n",
bdevname(rdev->bdev,b), mdname(mddev));
return -EBUSY;
@@ -6358,13 +6364,13 @@ static int set_array_info(struct mddev *mddev, mdu_array_info_t *info)
/* ensure mddev_put doesn't delete this now that there
* is some minimal configuration.
*/
- mddev->ctime = get_seconds();
+ mddev->ctime = ktime_get_real_seconds();
return 0;
}
mddev->major_version = MD_MAJOR_VERSION;
mddev->minor_version = MD_MINOR_VERSION;
mddev->patch_version = MD_PATCHLEVEL_VERSION;
- mddev->ctime = get_seconds();
+ mddev->ctime = ktime_get_real_seconds();
mddev->level = info->level;
mddev->clevel[0] = 0;
@@ -6606,6 +6612,19 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
rv = -EINVAL;
goto err;
}
+ if (mddev->bitmap_info.nodes) {
+ /* hold PW on all the bitmap lock */
+ if (md_cluster_ops->lock_all_bitmaps(mddev) <= 0) {
+ printk("md: can't change bitmap to none since the"
+ " array is in use by more than one node\n");
+ rv = -EPERM;
+ md_cluster_ops->unlock_all_bitmaps(mddev);
+ goto err;
+ }
+
+ mddev->bitmap_info.nodes = 0;
+ md_cluster_ops->leave(mddev);
+ }
mddev->pers->quiesce(mddev, 1);
bitmap_destroy(mddev);
mddev->pers->quiesce(mddev, 0);
@@ -7184,7 +7203,7 @@ void md_error(struct mddev *mddev, struct md_rdev *rdev)
md_wakeup_thread(mddev->thread);
if (mddev->event_work.func)
queue_work(md_misc_wq, &mddev->event_work);
- md_new_event_inintr(mddev);
+ md_new_event(mddev);
}
EXPORT_SYMBOL(md_error);
@@ -7708,7 +7727,7 @@ EXPORT_SYMBOL(md_write_end);
* attempting a GFP_KERNEL allocation while holding the mddev lock.
* Must be called with mddev_lock held.
*
- * In the ->external case MD_CHANGE_CLEAN can not be cleared until mddev->lock
+ * In the ->external case MD_CHANGE_PENDING can not be cleared until mddev->lock
* is dropped, so return -EAGAIN after notifying userspace.
*/
int md_allow_write(struct mddev *mddev)
@@ -8173,19 +8192,20 @@ static int remove_and_add_spares(struct mddev *mddev,
continue;
if (test_bit(Faulty, &rdev->flags))
continue;
- if (test_bit(Journal, &rdev->flags))
- continue;
- if (mddev->ro &&
- ! (rdev->saved_raid_disk >= 0 &&
- !test_bit(Bitmap_sync, &rdev->flags)))
- continue;
+ if (!test_bit(Journal, &rdev->flags)) {
+ if (mddev->ro &&
+ ! (rdev->saved_raid_disk >= 0 &&
+ !test_bit(Bitmap_sync, &rdev->flags)))
+ continue;
- rdev->recovery_offset = 0;
+ rdev->recovery_offset = 0;
+ }
if (mddev->pers->
hot_add_disk(mddev, rdev) == 0) {
if (sysfs_link_rdev(mddev, rdev))
/* failure here is OK */;
- spares++;
+ if (!test_bit(Journal, &rdev->flags))
+ spares++;
md_new_event(mddev);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
}
@@ -8280,6 +8300,7 @@ void md_check_recovery(struct mddev *mddev)
(mddev->flags & MD_UPDATE_SB_FLAGS & ~ (1<<MD_CHANGE_PENDING)) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
+ test_bit(MD_RELOAD_SB, &mddev->flags) ||
(mddev->external == 0 && mddev->safemode == 1) ||
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
&& !mddev->in_sync && mddev->recovery_cp == MaxSector)
@@ -8318,6 +8339,21 @@ void md_check_recovery(struct mddev *mddev)
goto unlock;
}
+ if (mddev_is_clustered(mddev)) {
+ struct md_rdev *rdev;
+ /* kick the device if another node issued a
+ * remove disk.
+ */
+ rdev_for_each(rdev, mddev) {
+ if (test_and_clear_bit(ClusterRemove, &rdev->flags) &&
+ rdev->raid_disk < 0)
+ md_kick_rdev_from_array(rdev);
+ }
+
+ if (test_and_clear_bit(MD_RELOAD_SB, &mddev->flags))
+ md_reload_sb(mddev, mddev->good_device_nr);
+ }
+
if (!mddev->external) {
int did_change = 0;
spin_lock(&mddev->lock);
@@ -8489,254 +8525,9 @@ void md_finish_reshape(struct mddev *mddev)
}
EXPORT_SYMBOL(md_finish_reshape);
-/* Bad block management.
- * We can record which blocks on each device are 'bad' and so just
- * fail those blocks, or that stripe, rather than the whole device.
- * Entries in the bad-block table are 64bits wide. This comprises:
- * Length of bad-range, in sectors: 0-511 for lengths 1-512
- * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
- * A 'shift' can be set so that larger blocks are tracked and
- * consequently larger devices can be covered.
- * 'Acknowledged' flag - 1 bit. - the most significant bit.
- *
- * Locking of the bad-block table uses a seqlock so md_is_badblock
- * might need to retry if it is very unlucky.
- * We will sometimes want to check for bad blocks in a bi_end_io function,
- * so we use the write_seqlock_irq variant.
- *
- * When looking for a bad block we specify a range and want to
- * know if any block in the range is bad. So we binary-search
- * to the last range that starts at-or-before the given endpoint,
- * (or "before the sector after the target range")
- * then see if it ends after the given start.
- * We return
- * 0 if there are no known bad blocks in the range
- * 1 if there are known bad block which are all acknowledged
- * -1 if there are bad blocks which have not yet been acknowledged in metadata.
- * plus the start/length of the first bad section we overlap.
- */
-int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
- sector_t *first_bad, int *bad_sectors)
-{
- int hi;
- int lo;
- u64 *p = bb->page;
- int rv;
- sector_t target = s + sectors;
- unsigned seq;
-
- if (bb->shift > 0) {
- /* round the start down, and the end up */
- s >>= bb->shift;
- target += (1<<bb->shift) - 1;
- target >>= bb->shift;
- sectors = target - s;
- }
- /* 'target' is now the first block after the bad range */
-
-retry:
- seq = read_seqbegin(&bb->lock);
- lo = 0;
- rv = 0;
- hi = bb->count;
-
- /* Binary search between lo and hi for 'target'
- * i.e. for the last range that starts before 'target'
- */
- /* INVARIANT: ranges before 'lo' and at-or-after 'hi'
- * are known not to be the last range before target.
- * VARIANT: hi-lo is the number of possible
- * ranges, and decreases until it reaches 1
- */
- while (hi - lo > 1) {
- int mid = (lo + hi) / 2;
- sector_t a = BB_OFFSET(p[mid]);
- if (a < target)
- /* This could still be the one, earlier ranges
- * could not. */
- lo = mid;
- else
- /* This and later ranges are definitely out. */
- hi = mid;
- }
- /* 'lo' might be the last that started before target, but 'hi' isn't */
- if (hi > lo) {
- /* need to check all range that end after 's' to see if
- * any are unacknowledged.
- */
- while (lo >= 0 &&
- BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
- if (BB_OFFSET(p[lo]) < target) {
- /* starts before the end, and finishes after
- * the start, so they must overlap
- */
- if (rv != -1 && BB_ACK(p[lo]))
- rv = 1;
- else
- rv = -1;
- *first_bad = BB_OFFSET(p[lo]);
- *bad_sectors = BB_LEN(p[lo]);
- }
- lo--;
- }
- }
-
- if (read_seqretry(&bb->lock, seq))
- goto retry;
-
- return rv;
-}
-EXPORT_SYMBOL_GPL(md_is_badblock);
-
-/*
- * Add a range of bad blocks to the table.
- * This might extend the table, or might contract it
- * if two adjacent ranges can be merged.
- * We binary-search to find the 'insertion' point, then
- * decide how best to handle it.
- */
-static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
- int acknowledged)
-{
- u64 *p;
- int lo, hi;
- int rv = 1;
- unsigned long flags;
-
- if (bb->shift < 0)
- /* badblocks are disabled */
- return 0;
-
- if (bb->shift) {
- /* round the start down, and the end up */
- sector_t next = s + sectors;
- s >>= bb->shift;
- next += (1<<bb->shift) - 1;
- next >>= bb->shift;
- sectors = next - s;
- }
-
- write_seqlock_irqsave(&bb->lock, flags);
-
- p = bb->page;
- lo = 0;
- hi = bb->count;
- /* Find the last range that starts at-or-before 's' */
- while (hi - lo > 1) {
- int mid = (lo + hi) / 2;
- sector_t a = BB_OFFSET(p[mid]);
- if (a <= s)
- lo = mid;
- else
- hi = mid;
- }
- if (hi > lo && BB_OFFSET(p[lo]) > s)
- hi = lo;
-
- if (hi > lo) {
- /* we found a range that might merge with the start
- * of our new range
- */
- sector_t a = BB_OFFSET(p[lo]);
- sector_t e = a + BB_LEN(p[lo]);
- int ack = BB_ACK(p[lo]);
- if (e >= s) {
- /* Yes, we can merge with a previous range */
- if (s == a && s + sectors >= e)
- /* new range covers old */
- ack = acknowledged;
- else
- ack = ack && acknowledged;
-
- if (e < s + sectors)
- e = s + sectors;
- if (e - a <= BB_MAX_LEN) {
- p[lo] = BB_MAKE(a, e-a, ack);
- s = e;
- } else {
- /* does not all fit in one range,
- * make p[lo] maximal
- */
- if (BB_LEN(p[lo]) != BB_MAX_LEN)
- p[lo] = BB_MAKE(a, BB_MAX_LEN, ack);
- s = a + BB_MAX_LEN;
- }
- sectors = e - s;
- }
- }
- if (sectors && hi < bb->count) {
- /* 'hi' points to the first range that starts after 's'.
- * Maybe we can merge with the start of that range */
- sector_t a = BB_OFFSET(p[hi]);
- sector_t e = a + BB_LEN(p[hi]);
- int ack = BB_ACK(p[hi]);
- if (a <= s + sectors) {
- /* merging is possible */
- if (e <= s + sectors) {
- /* full overlap */
- e = s + sectors;
- ack = acknowledged;
- } else
- ack = ack && acknowledged;
-
- a = s;
- if (e - a <= BB_MAX_LEN) {
- p[hi] = BB_MAKE(a, e-a, ack);
- s = e;
- } else {
- p[hi] = BB_MAKE(a, BB_MAX_LEN, ack);
- s = a + BB_MAX_LEN;
- }
- sectors = e - s;
- lo = hi;
- hi++;
- }
- }
- if (sectors == 0 && hi < bb->count) {
- /* we might be able to combine lo and hi */
- /* Note: 's' is at the end of 'lo' */
- sector_t a = BB_OFFSET(p[hi]);
- int lolen = BB_LEN(p[lo]);
- int hilen = BB_LEN(p[hi]);
- int newlen = lolen + hilen - (s - a);
- if (s >= a && newlen < BB_MAX_LEN) {
- /* yes, we can combine them */
- int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]);
- p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack);
- memmove(p + hi, p + hi + 1,
- (bb->count - hi - 1) * 8);
- bb->count--;
- }
- }
- while (sectors) {
- /* didn't merge (it all).
- * Need to add a range just before 'hi' */
- if (bb->count >= MD_MAX_BADBLOCKS) {
- /* No room for more */
- rv = 0;
- break;
- } else {
- int this_sectors = sectors;
- memmove(p + hi + 1, p + hi,
- (bb->count - hi) * 8);
- bb->count++;
-
- if (this_sectors > BB_MAX_LEN)
- this_sectors = BB_MAX_LEN;
- p[hi] = BB_MAKE(s, this_sectors, acknowledged);
- sectors -= this_sectors;
- s += this_sectors;
- }
- }
-
- bb->changed = 1;
- if (!acknowledged)
- bb->unacked_exist = 1;
- write_sequnlock_irqrestore(&bb->lock, flags);
-
- return rv;
-}
+/* Bad block management */
+/* Returns 1 on success, 0 on failure */
int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
int is_new)
{
@@ -8745,114 +8536,19 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
s += rdev->new_data_offset;
else
s += rdev->data_offset;
- rv = md_set_badblocks(&rdev->badblocks,
- s, sectors, 0);
- if (rv) {
+ rv = badblocks_set(&rdev->badblocks, s, sectors, 0);
+ if (rv == 0) {
/* Make sure they get written out promptly */
sysfs_notify_dirent_safe(rdev->sysfs_state);
set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
set_bit(MD_CHANGE_PENDING, &rdev->mddev->flags);
md_wakeup_thread(rdev->mddev->thread);
- }
- return rv;
+ return 1;
+ } else
+ return 0;
}
EXPORT_SYMBOL_GPL(rdev_set_badblocks);
-/*
- * Remove a range of bad blocks from the table.
- * This may involve extending the table if we spilt a region,
- * but it must not fail. So if the table becomes full, we just
- * drop the remove request.
- */
-static int md_clear_badblocks(struct badblocks *bb, sector_t s, int sectors)
-{
- u64 *p;
- int lo, hi;
- sector_t target = s + sectors;
- int rv = 0;
-
- if (bb->shift > 0) {
- /* When clearing we round the start up and the end down.
- * This should not matter as the shift should align with
- * the block size and no rounding should ever be needed.
- * However it is better the think a block is bad when it
- * isn't than to think a block is not bad when it is.
- */
- s += (1<<bb->shift) - 1;
- s >>= bb->shift;
- target >>= bb->shift;
- sectors = target - s;
- }
-
- write_seqlock_irq(&bb->lock);
-
- p = bb->page;
- lo = 0;
- hi = bb->count;
- /* Find the last range that starts before 'target' */
- while (hi - lo > 1) {
- int mid = (lo + hi) / 2;
- sector_t a = BB_OFFSET(p[mid]);
- if (a < target)
- lo = mid;
- else
- hi = mid;
- }
- if (hi > lo) {
- /* p[lo] is the last range that could overlap the
- * current range. Earlier ranges could also overlap,
- * but only this one can overlap the end of the range.
- */
- if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) {
- /* Partial overlap, leave the tail of this range */
- int ack = BB_ACK(p[lo]);
- sector_t a = BB_OFFSET(p[lo]);
- sector_t end = a + BB_LEN(p[lo]);
-
- if (a < s) {
- /* we need to split this range */
- if (bb->count >= MD_MAX_BADBLOCKS) {
- rv = -ENOSPC;
- goto out;
- }
- memmove(p+lo+1, p+lo, (bb->count - lo) * 8);
- bb->count++;
- p[lo] = BB_MAKE(a, s-a, ack);
- lo++;
- }
- p[lo] = BB_MAKE(target, end - target, ack);
- /* there is no longer an overlap */
- hi = lo;
- lo--;
- }
- while (lo >= 0 &&
- BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
- /* This range does overlap */
- if (BB_OFFSET(p[lo]) < s) {
- /* Keep the early parts of this range. */
- int ack = BB_ACK(p[lo]);
- sector_t start = BB_OFFSET(p[lo]);
- p[lo] = BB_MAKE(start, s - start, ack);
- /* now low doesn't overlap, so.. */
- break;
- }
- lo--;
- }
- /* 'lo' is strictly before, 'hi' is strictly after,
- * anything between needs to be discarded
- */
- if (hi - lo > 1) {
- memmove(p+lo+1, p+hi, (bb->count - hi) * 8);
- bb->count -= (hi - lo - 1);
- }
- }
-
- bb->changed = 1;
-out:
- write_sequnlock_irq(&bb->lock);
- return rv;
-}
-
int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
int is_new)
{
@@ -8860,133 +8556,11 @@ int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
s += rdev->new_data_offset;
else
s += rdev->data_offset;
- return md_clear_badblocks(&rdev->badblocks,
+ return badblocks_clear(&rdev->badblocks,
s, sectors);
}
EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
-/*
- * Acknowledge all bad blocks in a list.
- * This only succeeds if ->changed is clear. It is used by
- * in-kernel metadata updates
- */
-void md_ack_all_badblocks(struct badblocks *bb)
-{
- if (bb->page == NULL || bb->changed)
- /* no point even trying */
- return;
- write_seqlock_irq(&bb->lock);
-
- if (bb->changed == 0 && bb->unacked_exist) {
- u64 *p = bb->page;
- int i;
- for (i = 0; i < bb->count ; i++) {
- if (!BB_ACK(p[i])) {
- sector_t start = BB_OFFSET(p[i]);
- int len = BB_LEN(p[i]);
- p[i] = BB_MAKE(start, len, 1);
- }
- }
- bb->unacked_exist = 0;
- }
- write_sequnlock_irq(&bb->lock);
-}
-EXPORT_SYMBOL_GPL(md_ack_all_badblocks);
-
-/* sysfs access to bad-blocks list.
- * We present two files.
- * 'bad-blocks' lists sector numbers and lengths of ranges that
- * are recorded as bad. The list is truncated to fit within
- * the one-page limit of sysfs.
- * Writing "sector length" to this file adds an acknowledged
- * bad block list.
- * 'unacknowledged-bad-blocks' lists bad blocks that have not yet
- * been acknowledged. Writing to this file adds bad blocks
- * without acknowledging them. This is largely for testing.
- */
-
-static ssize_t
-badblocks_show(struct badblocks *bb, char *page, int unack)
-{
- size_t len;
- int i;
- u64 *p = bb->page;
- unsigned seq;
-
- if (bb->shift < 0)
- return 0;
-
-retry:
- seq = read_seqbegin(&bb->lock);
-
- len = 0;
- i = 0;
-
- while (len < PAGE_SIZE && i < bb->count) {
- sector_t s = BB_OFFSET(p[i]);
- unsigned int length = BB_LEN(p[i]);
- int ack = BB_ACK(p[i]);
- i++;
-
- if (unack && ack)
- continue;
-
- len += snprintf(page+len, PAGE_SIZE-len, "%llu %u\n",
- (unsigned long long)s << bb->shift,
- length << bb->shift);
- }
- if (unack && len == 0)
- bb->unacked_exist = 0;
-
- if (read_seqretry(&bb->lock, seq))
- goto retry;
-
- return len;
-}
-
-#define DO_DEBUG 1
-
-static ssize_t
-badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack)
-{
- unsigned long long sector;
- int length;
- char newline;
-#ifdef DO_DEBUG
- /* Allow clearing via sysfs *only* for testing/debugging.
- * Normally only a successful write may clear a badblock
- */
- int clear = 0;
- if (page[0] == '-') {
- clear = 1;
- page++;
- }
-#endif /* DO_DEBUG */
-
- switch (sscanf(page, "%llu %d%c", &sector, &length, &newline)) {
- case 3:
- if (newline != '\n')
- return -EINVAL;
- case 2:
- if (length <= 0)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
-#ifdef DO_DEBUG
- if (clear) {
- md_clear_badblocks(bb, sector, length);
- return len;
- }
-#endif /* DO_DEBUG */
- if (md_set_badblocks(bb, sector, length, !unack))
- return len;
- else
- return -ENOSPC;
-}
-
static int md_notify_reboot(struct notifier_block *this,
unsigned long code, void *x)
{
@@ -9101,7 +8675,6 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
ret = remove_and_add_spares(mddev, rdev2);
pr_info("Activated spare: %s\n",
bdevname(rdev2->bdev,b));
- continue;
}
/* device faulty
* We just want to do the minimum to mark the disk
diff --git a/drivers/md/md.h b/drivers/md/md.h
index ca0b643fe3c1..b5c4be73e6e4 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -17,6 +17,7 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
+#include <linux/badblocks.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/mm.h>
@@ -28,13 +29,6 @@
#define MaxSector (~(sector_t)0)
-/* Bad block numbers are stored sorted in a single page.
- * 64bits is used for each block or extent.
- * 54 bits are sector number, 9 bits are extent size,
- * 1 bit is an 'acknowledged' flag.
- */
-#define MD_MAX_BADBLOCKS (PAGE_SIZE/8)
-
/*
* MD's 'extended' device
*/
@@ -117,22 +111,7 @@ struct md_rdev {
struct kernfs_node *sysfs_state; /* handle for 'state'
* sysfs entry */
- struct badblocks {
- int count; /* count of bad blocks */
- int unacked_exist; /* there probably are unacknowledged
- * bad blocks. This is only cleared
- * when a read discovers none
- */
- int shift; /* shift from sectors to block size
- * a -ve shift means badblocks are
- * disabled.*/
- u64 *page; /* badblock list */
- int changed;
- seqlock_t lock;
-
- sector_t sector;
- sector_t size; /* in sectors */
- } badblocks;
+ struct badblocks badblocks;
};
enum flag_bits {
Faulty, /* device is known to have a fault */
@@ -183,24 +162,14 @@ enum flag_bits {
* Usually, this device should be faster
* than other devices in the array
*/
+ ClusterRemove,
};
-#define BB_LEN_MASK (0x00000000000001FFULL)
-#define BB_OFFSET_MASK (0x7FFFFFFFFFFFFE00ULL)
-#define BB_ACK_MASK (0x8000000000000000ULL)
-#define BB_MAX_LEN 512
-#define BB_OFFSET(x) (((x) & BB_OFFSET_MASK) >> 9)
-#define BB_LEN(x) (((x) & BB_LEN_MASK) + 1)
-#define BB_ACK(x) (!!((x) & BB_ACK_MASK))
-#define BB_MAKE(a, l, ack) (((a)<<9) | ((l)-1) | ((u64)(!!(ack)) << 63))
-
-extern int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
- sector_t *first_bad, int *bad_sectors);
static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
sector_t *first_bad, int *bad_sectors)
{
if (unlikely(rdev->badblocks.count)) {
- int rv = md_is_badblock(&rdev->badblocks, rdev->data_offset + s,
+ int rv = badblocks_check(&rdev->badblocks, rdev->data_offset + s,
sectors,
first_bad, bad_sectors);
if (rv)
@@ -213,8 +182,6 @@ extern int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
int is_new);
extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
int is_new);
-extern void md_ack_all_badblocks(struct badblocks *bb);
-
struct md_cluster_info;
struct mddev {
@@ -234,6 +201,9 @@ struct mddev {
*/
#define MD_JOURNAL_CLEAN 5 /* A raid with journal is already clean */
#define MD_HAS_JOURNAL 6 /* The raid array has journal feature set */
+#define MD_RELOAD_SB 7 /* Reload the superblock because another node
+ * updated it.
+ */
int suspended;
atomic_t active_io;
@@ -242,8 +212,6 @@ struct mddev {
* are happening, so run/
* takeover/stop are not safe
*/
- int ready; /* See when safe to pass
- * IO requests down */
struct gendisk *gendisk;
struct kobject kobj;
@@ -260,7 +228,7 @@ struct mddev {
* managed externally */
char metadata_type[17]; /* externally set*/
int chunk_sectors;
- time_t ctime, utime;
+ time64_t ctime, utime;
int level, layout;
char clevel[16];
int raid_disks;
@@ -464,6 +432,7 @@ struct mddev {
struct work_struct event_work; /* used by dm to report failure event */
void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
struct md_cluster_info *cluster_info;
+ unsigned int good_device_nr; /* good device num within cluster raid */
};
static inline int __must_check mddev_lock(struct mddev *mddev)
@@ -657,7 +626,7 @@ extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev);
-extern void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev);
+extern int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
extern void mddev_init(struct mddev *mddev);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 7331a80d89f1..0a72ab6e6c20 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -257,6 +257,9 @@ static int multipath_add_disk(struct mddev *mddev, struct md_rdev *rdev)
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
+ err = md_integrity_add_rdev(rdev, mddev);
+ if (err)
+ break;
spin_lock_irq(&conf->device_lock);
mddev->degraded--;
rdev->raid_disk = path;
@@ -264,9 +267,6 @@ static int multipath_add_disk(struct mddev *mddev, struct md_rdev *rdev)
spin_unlock_irq(&conf->device_lock);
rcu_assign_pointer(p->rdev, rdev);
err = 0;
- mddev_suspend(mddev);
- md_integrity_add_rdev(rdev, mddev);
- mddev_resume(mddev);
break;
}
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index f8e5db0cb5aa..2ea12c6bf659 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -549,13 +549,13 @@ static void *raid0_takeover_raid10(struct mddev *mddev)
* - all mirrors must be already degraded
*/
if (mddev->layout != ((1 << 8) + 2)) {
- printk(KERN_ERR "md/raid0:%s:: Raid0 cannot takover layout: 0x%x\n",
+ printk(KERN_ERR "md/raid0:%s:: Raid0 cannot takeover layout: 0x%x\n",
mdname(mddev),
mddev->layout);
return ERR_PTR(-EINVAL);
}
if (mddev->raid_disks & 1) {
- printk(KERN_ERR "md/raid0:%s: Raid0 cannot takover Raid10 with odd disk number.\n",
+ printk(KERN_ERR "md/raid0:%s: Raid0 cannot takeover Raid10 with odd disk number.\n",
mdname(mddev));
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index e2169ff6e0f0..c4b913409226 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1589,6 +1589,9 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
if (mddev->recovery_disabled == conf->recovery_disabled)
return -EBUSY;
+ if (md_integrity_add_rdev(rdev, mddev))
+ return -ENXIO;
+
if (rdev->raid_disk >= 0)
first = last = rdev->raid_disk;
@@ -1632,9 +1635,6 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
break;
}
}
- mddev_suspend(mddev);
- md_integrity_add_rdev(rdev, mddev);
- mddev_resume(mddev);
if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
print_conf(conf);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 84e597e1c489..ce959b4ae4df 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1698,6 +1698,9 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
if (rdev->saved_raid_disk < 0 && !_enough(conf, 1, -1))
return -EINVAL;
+ if (md_integrity_add_rdev(rdev, mddev))
+ return -ENXIO;
+
if (rdev->raid_disk >= 0)
first = last = rdev->raid_disk;
@@ -1739,9 +1742,6 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
rcu_assign_pointer(p->rdev, rdev);
break;
}
- mddev_suspend(mddev);
- md_integrity_add_rdev(rdev, mddev);
- mddev_resume(mddev);
if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
index b887e04d7e5c..9531f5f05b93 100644
--- a/drivers/md/raid5-cache.c
+++ b/drivers/md/raid5-cache.c
@@ -34,6 +34,12 @@
#define RECLAIM_MAX_FREE_SPACE (10 * 1024 * 1024 * 2) /* sector */
#define RECLAIM_MAX_FREE_SPACE_SHIFT (2)
+/*
+ * We only need 2 bios per I/O unit to make progress, but ensure we
+ * have a few more available to not get too tight.
+ */
+#define R5L_POOL_SIZE 4
+
struct r5l_log {
struct md_rdev *rdev;
@@ -69,7 +75,12 @@ struct r5l_log {
struct list_head finished_ios; /* io_units which settle down in log disk */
struct bio flush_bio;
+ struct list_head no_mem_stripes; /* pending stripes, -ENOMEM */
+
struct kmem_cache *io_kc;
+ mempool_t *io_pool;
+ struct bio_set *bs;
+ mempool_t *meta_pool;
struct md_thread *reclaim_thread;
unsigned long reclaim_target; /* number of space that need to be
@@ -150,27 +161,6 @@ static bool r5l_has_free_space(struct r5l_log *log, sector_t size)
return log->device_size > used_size + size;
}
-static void r5l_free_io_unit(struct r5l_log *log, struct r5l_io_unit *io)
-{
- __free_page(io->meta_page);
- kmem_cache_free(log->io_kc, io);
-}
-
-static void r5l_move_io_unit_list(struct list_head *from, struct list_head *to,
- enum r5l_io_unit_state state)
-{
- struct r5l_io_unit *io;
-
- while (!list_empty(from)) {
- io = list_first_entry(from, struct r5l_io_unit, log_sibling);
- /* don't change list order */
- if (io->state >= state)
- list_move_tail(&io->log_sibling, to);
- else
- break;
- }
-}
-
static void __r5l_set_io_unit_state(struct r5l_io_unit *io,
enum r5l_io_unit_state state)
{
@@ -206,6 +196,20 @@ static void r5l_log_run_stripes(struct r5l_log *log)
}
}
+static void r5l_move_to_end_ios(struct r5l_log *log)
+{
+ struct r5l_io_unit *io, *next;
+
+ assert_spin_locked(&log->io_list_lock);
+
+ list_for_each_entry_safe(io, next, &log->running_ios, log_sibling) {
+ /* don't change list order */
+ if (io->state < IO_UNIT_IO_END)
+ break;
+ list_move_tail(&io->log_sibling, &log->io_end_ios);
+ }
+}
+
static void r5l_log_endio(struct bio *bio)
{
struct r5l_io_unit *io = bio->bi_private;
@@ -216,12 +220,12 @@ static void r5l_log_endio(struct bio *bio)
md_error(log->rdev->mddev, log->rdev);
bio_put(bio);
+ mempool_free(io->meta_page, log->meta_pool);
spin_lock_irqsave(&log->io_list_lock, flags);
__r5l_set_io_unit_state(io, IO_UNIT_IO_END);
if (log->need_cache_flush)
- r5l_move_io_unit_list(&log->running_ios, &log->io_end_ios,
- IO_UNIT_IO_END);
+ r5l_move_to_end_ios(log);
else
r5l_log_run_stripes(log);
spin_unlock_irqrestore(&log->io_list_lock, flags);
@@ -255,7 +259,7 @@ static void r5l_submit_current_io(struct r5l_log *log)
static struct bio *r5l_bio_alloc(struct r5l_log *log)
{
- struct bio *bio = bio_kmalloc(GFP_NOIO | __GFP_NOFAIL, BIO_MAX_PAGES);
+ struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, log->bs);
bio->bi_rw = WRITE;
bio->bi_bdev = log->rdev->bdev;
@@ -286,15 +290,19 @@ static struct r5l_io_unit *r5l_new_meta(struct r5l_log *log)
struct r5l_io_unit *io;
struct r5l_meta_block *block;
- /* We can't handle memory allocate failure so far */
- io = kmem_cache_zalloc(log->io_kc, GFP_NOIO | __GFP_NOFAIL);
+ io = mempool_alloc(log->io_pool, GFP_ATOMIC);
+ if (!io)
+ return NULL;
+ memset(io, 0, sizeof(*io));
+
io->log = log;
INIT_LIST_HEAD(&io->log_sibling);
INIT_LIST_HEAD(&io->stripe_list);
io->state = IO_UNIT_RUNNING;
- io->meta_page = alloc_page(GFP_NOIO | __GFP_NOFAIL | __GFP_ZERO);
+ io->meta_page = mempool_alloc(log->meta_pool, GFP_NOIO);
block = page_address(io->meta_page);
+ clear_page(block);
block->magic = cpu_to_le32(R5LOG_MAGIC);
block->version = R5LOG_VERSION;
block->seq = cpu_to_le64(log->seq);
@@ -324,8 +332,12 @@ static int r5l_get_meta(struct r5l_log *log, unsigned int payload_size)
log->current_io->meta_offset + payload_size > PAGE_SIZE)
r5l_submit_current_io(log);
- if (!log->current_io)
+ if (!log->current_io) {
log->current_io = r5l_new_meta(log);
+ if (!log->current_io)
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -370,11 +382,12 @@ static void r5l_append_payload_page(struct r5l_log *log, struct page *page)
r5_reserve_log_entry(log, io);
}
-static void r5l_log_stripe(struct r5l_log *log, struct stripe_head *sh,
+static int r5l_log_stripe(struct r5l_log *log, struct stripe_head *sh,
int data_pages, int parity_pages)
{
int i;
int meta_size;
+ int ret;
struct r5l_io_unit *io;
meta_size =
@@ -383,7 +396,10 @@ static void r5l_log_stripe(struct r5l_log *log, struct stripe_head *sh,
sizeof(struct r5l_payload_data_parity) +
sizeof(__le32) * parity_pages;
- r5l_get_meta(log, meta_size);
+ ret = r5l_get_meta(log, meta_size);
+ if (ret)
+ return ret;
+
io = log->current_io;
for (i = 0; i < sh->disks; i++) {
@@ -413,6 +429,8 @@ static void r5l_log_stripe(struct r5l_log *log, struct stripe_head *sh,
list_add_tail(&sh->log_list, &io->stripe_list);
atomic_inc(&io->pending_stripe);
sh->log_io = io;
+
+ return 0;
}
static void r5l_wake_reclaim(struct r5l_log *log, sector_t space);
@@ -427,6 +445,7 @@ int r5l_write_stripe(struct r5l_log *log, struct stripe_head *sh)
int meta_size;
int reserve;
int i;
+ int ret = 0;
if (!log)
return -EAGAIN;
@@ -475,17 +494,22 @@ int r5l_write_stripe(struct r5l_log *log, struct stripe_head *sh)
mutex_lock(&log->io_mutex);
/* meta + data */
reserve = (1 + write_disks) << (PAGE_SHIFT - 9);
- if (r5l_has_free_space(log, reserve))
- r5l_log_stripe(log, sh, data_pages, parity_pages);
- else {
+ if (!r5l_has_free_space(log, reserve)) {
spin_lock(&log->no_space_stripes_lock);
list_add_tail(&sh->log_list, &log->no_space_stripes);
spin_unlock(&log->no_space_stripes_lock);
r5l_wake_reclaim(log, reserve);
+ } else {
+ ret = r5l_log_stripe(log, sh, data_pages, parity_pages);
+ if (ret) {
+ spin_lock_irq(&log->io_list_lock);
+ list_add_tail(&sh->log_list, &log->no_mem_stripes);
+ spin_unlock_irq(&log->io_list_lock);
+ }
}
- mutex_unlock(&log->io_mutex);
+ mutex_unlock(&log->io_mutex);
return 0;
}
@@ -538,6 +562,21 @@ static sector_t r5l_reclaimable_space(struct r5l_log *log)
log->next_checkpoint);
}
+static void r5l_run_no_mem_stripe(struct r5l_log *log)
+{
+ struct stripe_head *sh;
+
+ assert_spin_locked(&log->io_list_lock);
+
+ if (!list_empty(&log->no_mem_stripes)) {
+ sh = list_first_entry(&log->no_mem_stripes,
+ struct stripe_head, log_list);
+ list_del_init(&sh->log_list);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ raid5_release_stripe(sh);
+ }
+}
+
static bool r5l_complete_finished_ios(struct r5l_log *log)
{
struct r5l_io_unit *io, *next;
@@ -554,7 +593,8 @@ static bool r5l_complete_finished_ios(struct r5l_log *log)
log->next_cp_seq = io->seq;
list_del(&io->log_sibling);
- r5l_free_io_unit(log, io);
+ mempool_free(io, log->io_pool);
+ r5l_run_no_mem_stripe(log);
found = true;
}
@@ -787,6 +827,13 @@ void r5l_quiesce(struct r5l_log *log, int state)
return;
if (state == 0) {
log->in_teardown = 0;
+ /*
+ * This is a special case for hotadd. In suspend, the array has
+ * no journal. In resume, journal is initialized as well as the
+ * reclaim thread.
+ */
+ if (log->reclaim_thread)
+ return;
log->reclaim_thread = md_register_thread(r5l_reclaim_thread,
log->rdev->mddev, "reclaim");
} else if (state == 1) {
@@ -806,10 +853,18 @@ void r5l_quiesce(struct r5l_log *log, int state)
bool r5l_log_disk_error(struct r5conf *conf)
{
+ struct r5l_log *log;
+ bool ret;
/* don't allow write if journal disk is missing */
- if (!conf->log)
- return test_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
- return test_bit(Faulty, &conf->log->rdev->flags);
+ rcu_read_lock();
+ log = rcu_dereference(conf->log);
+
+ if (!log)
+ ret = test_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
+ else
+ ret = test_bit(Faulty, &log->rdev->flags);
+ rcu_read_unlock();
+ return ret;
}
struct r5l_recovery_ctx {
@@ -1160,23 +1215,45 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
if (!log->io_kc)
goto io_kc;
+ log->io_pool = mempool_create_slab_pool(R5L_POOL_SIZE, log->io_kc);
+ if (!log->io_pool)
+ goto io_pool;
+
+ log->bs = bioset_create(R5L_POOL_SIZE, 0);
+ if (!log->bs)
+ goto io_bs;
+
+ log->meta_pool = mempool_create_page_pool(R5L_POOL_SIZE, 0);
+ if (!log->meta_pool)
+ goto out_mempool;
+
log->reclaim_thread = md_register_thread(r5l_reclaim_thread,
log->rdev->mddev, "reclaim");
if (!log->reclaim_thread)
goto reclaim_thread;
init_waitqueue_head(&log->iounit_wait);
+ INIT_LIST_HEAD(&log->no_mem_stripes);
+
INIT_LIST_HEAD(&log->no_space_stripes);
spin_lock_init(&log->no_space_stripes_lock);
if (r5l_load_log(log))
goto error;
- conf->log = log;
+ rcu_assign_pointer(conf->log, log);
+ set_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
return 0;
+
error:
md_unregister_thread(&log->reclaim_thread);
reclaim_thread:
+ mempool_destroy(log->meta_pool);
+out_mempool:
+ bioset_free(log->bs);
+io_bs:
+ mempool_destroy(log->io_pool);
+io_pool:
kmem_cache_destroy(log->io_kc);
io_kc:
kfree(log);
@@ -1186,6 +1263,9 @@ io_kc:
void r5l_exit_log(struct r5l_log *log)
{
md_unregister_thread(&log->reclaim_thread);
+ mempool_destroy(log->meta_pool);
+ bioset_free(log->bs);
+ mempool_destroy(log->io_pool);
kmem_cache_destroy(log->io_kc);
kfree(log);
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 704ef7fcfbf8..a086014dcd49 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -772,8 +772,6 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
int hash;
int dd_idx;
- if (!stripe_can_batch(sh))
- return;
/* Don't cross chunks, so stripe pd_idx/qd_idx is the same */
tmp_sec = sh->sector;
if (!sector_div(tmp_sec, conf->chunk_sectors))
@@ -7141,14 +7139,19 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
struct disk_info *p = conf->disks + number;
print_raid5_conf(conf);
- if (test_bit(Journal, &rdev->flags)) {
+ if (test_bit(Journal, &rdev->flags) && conf->log) {
+ struct r5l_log *log;
/*
- * journal disk is not removable, but we need give a chance to
- * update superblock of other disks. Otherwise journal disk
- * will be considered as 'fresh'
+ * we can't wait pending write here, as this is called in
+ * raid5d, wait will deadlock.
*/
- set_bit(MD_CHANGE_DEVS, &mddev->flags);
- return -EINVAL;
+ if (atomic_read(&mddev->writes_pending))
+ return -EBUSY;
+ log = conf->log;
+ conf->log = NULL;
+ synchronize_rcu();
+ r5l_exit_log(log);
+ return 0;
}
if (rdev == p->rdev)
rdevp = &p->rdev;
@@ -7212,8 +7215,21 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
int first = 0;
int last = conf->raid_disks - 1;
- if (test_bit(Journal, &rdev->flags))
- return -EINVAL;
+ if (test_bit(Journal, &rdev->flags)) {
+ char b[BDEVNAME_SIZE];
+ if (conf->log)
+ return -EBUSY;
+
+ rdev->raid_disk = 0;
+ /*
+ * The array is in readonly mode if journal is missing, so no
+ * write requests running. We should be safe
+ */
+ r5l_init_log(conf, rdev);
+ printk(KERN_INFO"md/raid:%s: using device %s as journal\n",
+ mdname(mddev), bdevname(rdev->bdev, b));
+ return 0;
+ }
if (mddev->recovery_disabled == conf->recovery_disabled)
return -EBUSY;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 9264ea73b3be..a8518fb3bca7 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -97,7 +97,6 @@ config MEDIA_CONTROLLER
config MEDIA_CONTROLLER_DVB
bool "Enable Media controller for DVB (EXPERIMENTAL)"
depends on MEDIA_CONTROLLER
- depends on BROKEN
---help---
Enable the media controller API support for DVB.
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index d5837be3e8cf..ea2f3bf7368b 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -502,7 +502,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuf
/* check if overlay is running */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
if (vv->video_fh != fh) {
- DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
+ DEB_D("refusing to change framebuffer information while overlay is active in another open\n");
return -EBUSY;
}
}
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index f4305ae800f4..d31f468830cf 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -617,6 +617,7 @@ static void smsdvb_media_device_unregister(struct smsdvb_client_t *client)
if (!coredev->media_dev)
return;
media_device_unregister(coredev->media_dev);
+ media_device_cleanup(coredev->media_dev);
kfree(coredev->media_dev);
coredev->media_dev = NULL;
#endif
@@ -1183,7 +1184,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
if (smsdvb_debugfs_create(client) < 0)
pr_info("failed to create debugfs node\n");
- dvb_create_media_graph(&client->adapter);
+ rc = dvb_create_media_graph(&client->adapter, true);
+ if (rc < 0) {
+ pr_err("dvb_create_media_graph failed %d\n", rc);
+ goto client_error;
+ }
pr_info("DVB interface registered.\n");
return 0;
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index ea9abde902e9..a168cbe1c998 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -1244,9 +1244,9 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
}
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
- DVB_DEVICE_DEMUX);
+ DVB_DEVICE_DEMUX, dmxdev->filternum);
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
- dmxdev, DVB_DEVICE_DVR);
+ dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index fb66184dc9b6..f82cd1ff4f3a 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -1695,7 +1695,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
pubca->private = ca;
/* register the DVB device */
- ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
+ ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA, 0);
if (ret)
goto free_slot_info;
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index b64f33776b74..40080645341e 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -622,7 +622,7 @@ static int dvb_enable_media_tuner(struct dvb_frontend *fe)
struct media_device *mdev = adapter->mdev;
struct media_entity *entity, *source;
struct media_link *link, *found_link = NULL;
- int i, ret, n_links = 0, active_links = 0;
+ int ret, n_links = 0, active_links = 0;
fepriv->pipe_start_entity = NULL;
@@ -632,8 +632,7 @@ static int dvb_enable_media_tuner(struct dvb_frontend *fe)
entity = fepriv->dvbdev->entity;
fepriv->pipe_start_entity = entity;
- for (i = 0; i < entity->num_links; i++) {
- link = &entity->links[i];
+ list_for_each_entry(link, &entity->links, list) {
if (link->sink->entity == entity) {
found_link = link;
n_links++;
@@ -659,13 +658,11 @@ static int dvb_enable_media_tuner(struct dvb_frontend *fe)
source = found_link->source->entity;
fepriv->pipe_start_entity = source;
- for (i = 0; i < source->num_links; i++) {
+ list_for_each_entry(link, &source->links, list) {
struct media_entity *sink;
int flags = 0;
- link = &source->links[i];
sink = link->sink->entity;
-
if (sink == entity)
flags = MEDIA_LNK_FL_ENABLED;
@@ -2762,7 +2759,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
fe->dvb->num, fe->id, fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
- fe, DVB_DEVICE_FRONTEND);
+ fe, DVB_DEVICE_FRONTEND, 0);
/*
* Initialize the cache to the proper values according with the
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index ce4332e80a91..ce6a711b42d4 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -1502,6 +1502,6 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
dvbnet->state[i] = 0;
return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
- dvbnet, DVB_DEVICE_NET);
+ dvbnet, DVB_DEVICE_NET, 0);
}
EXPORT_SYMBOL(dvb_net_init);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 13bb57f0457f..560450a0b32a 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -34,6 +34,9 @@
#include <linux/mutex.h>
#include "dvbdev.h"
+/* Due to enum tuner_pad_index */
+#include <media/tuner.h>
+
static DEFINE_MUTEX(dvbdev_mutex);
static int dvbdev_debug;
@@ -180,102 +183,255 @@ skip:
return -ENFILE;
}
-static void dvb_register_media_device(struct dvb_device *dvbdev,
- int type, int minor)
+static void dvb_media_device_free(struct dvb_device *dvbdev)
{
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
- int ret = 0, npads;
+ if (dvbdev->entity) {
+ media_device_unregister_entity(dvbdev->entity);
+ kfree(dvbdev->entity);
+ kfree(dvbdev->pads);
+ dvbdev->entity = NULL;
+ dvbdev->pads = NULL;
+ }
- if (!dvbdev->adapter->mdev)
- return;
+ if (dvbdev->tsout_entity) {
+ int i;
- dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
- if (!dvbdev->entity)
- return;
+ for (i = 0; i < dvbdev->tsout_num_entities; i++) {
+ media_device_unregister_entity(&dvbdev->tsout_entity[i]);
+ kfree(dvbdev->tsout_entity[i].name);
+ }
+ kfree(dvbdev->tsout_entity);
+ kfree(dvbdev->tsout_pads);
+ dvbdev->tsout_entity = NULL;
+ dvbdev->tsout_pads = NULL;
- dvbdev->entity->info.dev.major = DVB_MAJOR;
- dvbdev->entity->info.dev.minor = minor;
- dvbdev->entity->name = dvbdev->name;
+ dvbdev->tsout_num_entities = 0;
+ }
+
+ if (dvbdev->intf_devnode) {
+ media_devnode_remove(dvbdev->intf_devnode);
+ dvbdev->intf_devnode = NULL;
+ }
+
+ if (dvbdev->adapter->conn) {
+ media_device_unregister_entity(dvbdev->adapter->conn);
+ dvbdev->adapter->conn = NULL;
+ kfree(dvbdev->adapter->conn_pads);
+ dvbdev->adapter->conn_pads = NULL;
+ }
+#endif
+}
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
+ const char *name, int npads)
+{
+ int i, ret = 0;
+
+ dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
+ GFP_KERNEL);
+ if (!dvbdev->tsout_pads)
+ return -ENOMEM;
+
+ dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity),
+ GFP_KERNEL);
+ if (!dvbdev->tsout_entity)
+ return -ENOMEM;
+
+ dvbdev->tsout_num_entities = npads;
+
+ for (i = 0; i < npads; i++) {
+ struct media_pad *pads = &dvbdev->tsout_pads[i];
+ struct media_entity *entity = &dvbdev->tsout_entity[i];
+
+ entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
+ if (!entity->name)
+ return -ENOMEM;
+
+ entity->function = MEDIA_ENT_F_IO_DTV;
+ pads->flags = MEDIA_PAD_FL_SINK;
+
+ ret = media_entity_pads_init(entity, 1, pads);
+ if (ret < 0)
+ return ret;
+
+ ret = media_device_register_entity(dvbdev->adapter->mdev,
+ entity);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+#define DEMUX_TSOUT "demux-tsout"
+#define DVR_TSOUT "dvr-tsout"
+
+static int dvb_create_media_entity(struct dvb_device *dvbdev,
+ int type, int demux_sink_pads)
+{
+ int i, ret, npads;
switch (type) {
- case DVB_DEVICE_CA:
- case DVB_DEVICE_DEMUX:
case DVB_DEVICE_FRONTEND:
npads = 2;
break;
- case DVB_DEVICE_NET:
- npads = 0;
+ case DVB_DEVICE_DVR:
+ ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
+ demux_sink_pads);
+ return ret;
+ case DVB_DEVICE_DEMUX:
+ npads = 1 + demux_sink_pads;
+ ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
+ demux_sink_pads);
+ if (ret < 0)
+ return ret;
+ break;
+ case DVB_DEVICE_CA:
+ npads = 2;
break;
+ case DVB_DEVICE_NET:
+ /*
+ * We should be creating entities for the MPE/ULE
+ * decapsulation hardware (or software implementation).
+ *
+ * However, the number of for the MPE/ULE decaps may not be
+ * fixed. As we don't have yet dynamic support for PADs at
+ * the Media Controller, let's not create the decap
+ * entities yet.
+ */
+ return 0;
default:
- npads = 1;
+ return 0;
}
+ dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
+ if (!dvbdev->entity)
+ return -ENOMEM;
+
+ dvbdev->entity->name = dvbdev->name;
+
if (npads) {
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
GFP_KERNEL);
- if (!dvbdev->pads) {
- kfree(dvbdev->entity);
- return;
- }
+ if (!dvbdev->pads)
+ return -ENOMEM;
}
switch (type) {
case DVB_DEVICE_FRONTEND:
- dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE;
+ dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
break;
case DVB_DEVICE_DEMUX:
- dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX;
- dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
- dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
- break;
- case DVB_DEVICE_DVR:
- dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR;
+ dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ for (i = 1; i < npads; i++)
+ dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE;
break;
case DVB_DEVICE_CA:
- dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA;
+ dvbdev->entity->function = MEDIA_ENT_F_DTV_CA;
dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
break;
- case DVB_DEVICE_NET:
- dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET;
- break;
default:
+ /* Should never happen, as the first switch prevents it */
kfree(dvbdev->entity);
+ kfree(dvbdev->pads);
dvbdev->entity = NULL;
- return;
+ dvbdev->pads = NULL;
+ return 0;
}
- if (npads)
- ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0);
- if (!ret)
- ret = media_device_register_entity(dvbdev->adapter->mdev,
- dvbdev->entity);
- if (ret < 0) {
- printk(KERN_ERR
- "%s: media_device_register_entity failed for %s\n",
- __func__, dvbdev->entity->name);
- kfree(dvbdev->pads);
- kfree(dvbdev->entity);
- dvbdev->entity = NULL;
- return;
+ if (npads) {
+ ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads);
+ if (ret)
+ return ret;
}
+ ret = media_device_register_entity(dvbdev->adapter->mdev,
+ dvbdev->entity);
+ if (ret)
+ return (ret);
- printk(KERN_DEBUG "%s: media device '%s' registered.\n",
+ printk(KERN_DEBUG "%s: media entity '%s' registered.\n",
__func__, dvbdev->entity->name);
+
+ return 0;
+}
+#endif
+
+static int dvb_register_media_device(struct dvb_device *dvbdev,
+ int type, int minor,
+ unsigned demux_sink_pads)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ struct media_link *link;
+ u32 intf_type;
+ int ret;
+
+ if (!dvbdev->adapter->mdev)
+ return 0;
+
+ ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads);
+ if (ret)
+ return ret;
+
+ switch (type) {
+ case DVB_DEVICE_FRONTEND:
+ intf_type = MEDIA_INTF_T_DVB_FE;
+ break;
+ case DVB_DEVICE_DEMUX:
+ intf_type = MEDIA_INTF_T_DVB_DEMUX;
+ break;
+ case DVB_DEVICE_DVR:
+ intf_type = MEDIA_INTF_T_DVB_DVR;
+ break;
+ case DVB_DEVICE_CA:
+ intf_type = MEDIA_INTF_T_DVB_CA;
+ break;
+ case DVB_DEVICE_NET:
+ intf_type = MEDIA_INTF_T_DVB_NET;
+ break;
+ default:
+ return 0;
+ }
+
+ dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev,
+ intf_type, 0,
+ DVB_MAJOR, minor);
+
+ if (!dvbdev->intf_devnode)
+ return -ENOMEM;
+
+ /*
+ * Create the "obvious" link, e. g. the ones that represent
+ * a direct association between an interface and an entity.
+ * Other links should be created elsewhere, like:
+ * DVB FE intf -> tuner
+ * DVB demux intf -> dvr
+ */
+
+ if (!dvbdev->entity)
+ return 0;
+
+ link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
#endif
+ return 0;
}
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
- const struct dvb_device *template, void *priv, int type)
+ const struct dvb_device *template, void *priv, int type,
+ int demux_sink_pads)
{
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
struct device *clsdev;
int minor;
- int id;
+ int id, ret;
mutex_lock(&dvbdev_register_lock);
@@ -286,7 +442,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
return -ENFILE;
}
- *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
+ *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
if (!dvbdev){
mutex_unlock(&dvbdev_register_lock);
@@ -335,6 +491,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvb_minors[minor] = dvbdev;
up_write(&minor_rwsem);
+ ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: dvb_register_media_device failed to create the mediagraph\n",
+ __func__);
+
+ dvb_media_device_free(dvbdev);
+ kfree(dvbdevfops);
+ kfree(dvbdev);
+ up_write(&minor_rwsem);
+ mutex_unlock(&dvbdev_register_lock);
+ return ret;
+ }
+
mutex_unlock(&dvbdev_register_lock);
clsdev = device_create(dvb_class, adap->device,
@@ -348,8 +518,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor);
- dvb_register_media_device(dvbdev, type, minor);
-
return 0;
}
EXPORT_SYMBOL(dvb_register_device);
@@ -364,15 +532,9 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
dvb_minors[dvbdev->minor] = NULL;
up_write(&minor_rwsem);
- device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
+ dvb_media_device_free(dvbdev);
-#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
- if (dvbdev->entity) {
- media_device_unregister_entity(dvbdev->entity);
- kfree(dvbdev->entity);
- kfree(dvbdev->pads);
- }
-#endif
+ device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head);
kfree (dvbdev->fops);
@@ -382,46 +544,212 @@ EXPORT_SYMBOL(dvb_unregister_device);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-void dvb_create_media_graph(struct dvb_adapter *adap)
+
+static int dvb_create_io_intf_links(struct dvb_adapter *adap,
+ struct media_interface *intf,
+ char *name)
+{
+ struct media_device *mdev = adap->mdev;
+ struct media_entity *entity;
+ struct media_link *link;
+
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function == MEDIA_ENT_F_IO_DTV) {
+ if (strncmp(entity->name, name, strlen(name)))
+ continue;
+ link = media_create_intf_link(entity, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+int dvb_create_media_graph(struct dvb_adapter *adap,
+ bool create_rf_connector)
{
struct media_device *mdev = adap->mdev;
- struct media_entity *entity, *tuner = NULL, *fe = NULL;
- struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL;
+ struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn;
+ struct media_entity *demux = NULL, *ca = NULL;
+ struct media_link *link;
+ struct media_interface *intf;
+ unsigned demux_pad = 0;
+ unsigned dvr_pad = 0;
+ unsigned ntuner = 0, ndemod = 0;
+ int ret;
+ static const char *connector_name = "Television";
if (!mdev)
- return;
+ return 0;
media_device_for_each_entity(entity, mdev) {
- switch (entity->type) {
- case MEDIA_ENT_T_V4L2_SUBDEV_TUNER:
+ switch (entity->function) {
+ case MEDIA_ENT_F_TUNER:
tuner = entity;
+ ntuner++;
break;
- case MEDIA_ENT_T_DEVNODE_DVB_FE:
- fe = entity;
+ case MEDIA_ENT_F_DTV_DEMOD:
+ demod = entity;
+ ndemod++;
break;
- case MEDIA_ENT_T_DEVNODE_DVB_DEMUX:
+ case MEDIA_ENT_F_TS_DEMUX:
demux = entity;
break;
- case MEDIA_ENT_T_DEVNODE_DVB_DVR:
- dvr = entity;
- break;
- case MEDIA_ENT_T_DEVNODE_DVB_CA:
+ case MEDIA_ENT_F_DTV_CA:
ca = entity;
break;
}
}
- if (tuner && fe)
- media_entity_create_link(tuner, 0, fe, 0, 0);
+ /*
+ * Prepare to signalize to media_create_pad_links() that multiple
+ * entities of the same type exists and a 1:n or n:1 links need to be
+ * created.
+ * NOTE: if both tuner and demod have multiple instances, it is up
+ * to the caller driver to create such links.
+ */
+ if (ntuner > 1)
+ tuner = NULL;
+ if (ndemod > 1)
+ demod = NULL;
+
+ if (create_rf_connector) {
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn)
+ return -ENOMEM;
+ adap->conn = conn;
+
+ adap->conn_pads = kcalloc(1, sizeof(*adap->conn_pads),
+ GFP_KERNEL);
+ if (!adap->conn_pads)
+ return -ENOMEM;
+
+ conn->flags = MEDIA_ENT_FL_CONNECTOR;
+ conn->function = MEDIA_ENT_F_CONN_RF;
+ conn->name = connector_name;
+ adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(conn, 1, adap->conn_pads);
+ if (ret)
+ return ret;
+
+ ret = media_device_register_entity(mdev, conn);
+ if (ret)
+ return ret;
+
+ if (!ntuner)
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_CONN_RF,
+ conn, 0,
+ MEDIA_ENT_F_DTV_DEMOD,
+ demod, 0,
+ MEDIA_LNK_FL_ENABLED,
+ false);
+ else
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_CONN_RF,
+ conn, 0,
+ MEDIA_ENT_F_TUNER,
+ tuner, TUNER_PAD_RF_INPUT,
+ MEDIA_LNK_FL_ENABLED,
+ false);
+ if (ret)
+ return ret;
+ }
+
+ if (ntuner && ndemod) {
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_TUNER,
+ tuner, TUNER_PAD_IF_OUTPUT,
+ MEDIA_ENT_F_DTV_DEMOD,
+ demod, 0, MEDIA_LNK_FL_ENABLED,
+ false);
+ if (ret)
+ return ret;
+ }
+
+ if (ndemod && demux) {
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_DTV_DEMOD,
+ demod, 1,
+ MEDIA_ENT_F_TS_DEMUX,
+ demux, 0, MEDIA_LNK_FL_ENABLED,
+ false);
+ if (ret)
+ return -ENOMEM;
+ }
+ if (demux && ca) {
+ ret = media_create_pad_link(demux, 1, ca,
+ 0, MEDIA_LNK_FL_ENABLED);
+ if (!ret)
+ return -ENOMEM;
+ }
- if (fe && demux)
- media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED);
+ /* Create demux links for each ringbuffer/pad */
+ if (demux) {
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function == MEDIA_ENT_F_IO_DTV) {
+ if (!strncmp(entity->name, DVR_TSOUT,
+ strlen(DVR_TSOUT))) {
+ ret = media_create_pad_link(demux,
+ ++dvr_pad,
+ entity, 0, 0);
+ if (ret)
+ return ret;
+ }
+ if (!strncmp(entity->name, DEMUX_TSOUT,
+ strlen(DEMUX_TSOUT))) {
+ ret = media_create_pad_link(demux,
+ ++demux_pad,
+ entity, 0, 0);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ }
- if (demux && dvr)
- media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED);
+ /* Create interface links for FE->tuner, DVR->demux and CA->ca */
+ media_device_for_each_intf(intf, mdev) {
+ if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
+ link = media_create_intf_link(ca, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
- if (demux && ca)
- media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED);
+ if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
+ link = media_create_intf_link(tuner, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+#if 0
+ /*
+ * Indirect link - let's not create yet, as we don't know how
+ * to handle indirect links, nor if this will
+ * actually be needed.
+ */
+ if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
+ link = media_create_intf_link(demux, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+#endif
+ if (intf->type == MEDIA_INTF_T_DVB_DVR) {
+ ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT);
+ if (ret)
+ return ret;
+ }
+ if (intf->type == MEDIA_INTF_T_DVB_DEMUX) {
+ ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
}
EXPORT_SYMBOL_GPL(dvb_create_media_graph);
#endif
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index 1069a776bbdb..4aff7bd3dea8 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -75,6 +75,9 @@ struct dvb_frontend;
* used.
* @mdev: pointer to struct media_device, used when the media
* controller is used.
+ * @conn: RF connector. Used only if the device has no separate
+ * tuner.
+ * @conn_pads: pointer to struct media_pad associated with @conn;
*/
struct dvb_adapter {
int num;
@@ -94,6 +97,8 @@ struct dvb_adapter {
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct media_device *mdev;
+ struct media_entity *conn;
+ struct media_pad *conn_pads;
#endif
};
@@ -120,6 +125,11 @@ struct dvb_adapter {
* @entity: pointer to struct media_entity associated with the device node
* @pads: pointer to struct media_pad associated with @entity;
* @priv: private data
+ * @intf_devnode: Pointer to media_intf_devnode. Used by the dvbdev core to
+ * store the MC device node interface
+ * @tsout_num_entities: Number of Transport Stream output entities
+ * @tsout_entity: array with MC entities associated to each TS output node
+ * @tsout_pads: array with the source pads for each @tsout_entity
*
* This structure is used by the DVB core (frontend, CA, net, demux) in
* order to create the device nodes. Usually, driver should not initialize
@@ -148,8 +158,11 @@ struct dvb_device {
const char *name;
/* Allocated and filled inside dvbdev.c */
- struct media_entity *entity;
- struct media_pad *pads;
+ struct media_intf_devnode *intf_devnode;
+
+ unsigned tsout_num_entities;
+ struct media_entity *entity, *tsout_entity;
+ struct media_pad *pads, *tsout_pads;
#endif
void *priv;
@@ -185,14 +198,18 @@ int dvb_unregister_adapter(struct dvb_adapter *adap);
* stored
* @template: Template used to create &pdvbdev;
* @priv: private data
- * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
- * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
+ * @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
+ * %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
+ * %DVB_DEVICE_NET
+ * @demux_sink_pads: Number of demux outputs, to be used to create the TS
+ * outputs via the Media Controller.
*/
int dvb_register_device(struct dvb_adapter *adap,
struct dvb_device **pdvbdev,
const struct dvb_device *template,
void *priv,
- int type);
+ int type,
+ int demux_sink_pads);
/**
* dvb_unregister_device - Unregisters a DVB device
@@ -202,16 +219,43 @@ int dvb_register_device(struct dvb_adapter *adap,
void dvb_unregister_device(struct dvb_device *dvbdev);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-void dvb_create_media_graph(struct dvb_adapter *adap);
+/**
+ * dvb_create_media_graph - Creates media graph for the Digital TV part of the
+ * device.
+ *
+ * @adap: pointer to struct dvb_adapter
+ * @create_rf_connector: if true, it creates the RF connector too
+ *
+ * This function checks all DVB-related functions at the media controller
+ * entities and creates the needed links for the media graph. It is
+ * capable of working with multiple tuners or multiple frontends, but it
+ * won't create links if the device has multiple tuners and multiple frontends
+ * or if the device has multiple muxes. In such case, the caller driver should
+ * manually create the remaining links.
+ */
+__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
+ bool create_rf_connector);
+
static inline void dvb_register_media_controller(struct dvb_adapter *adap,
struct media_device *mdev)
{
adap->mdev = mdev;
}
+static inline struct media_device
+*dvb_get_media_controller(struct dvb_adapter *adap)
+{
+ return adap->mdev;
+}
#else
-static inline void dvb_create_media_graph(struct dvb_adapter *adap) {}
+static inline
+int dvb_create_media_graph(struct dvb_adapter *adap,
+ bool create_rf_connector)
+{
+ return 0;
+};
#define dvb_register_media_controller(a, b) {}
+#define dvb_get_media_controller(a) NULL
#endif
int dvb_generic_open (struct inode *inode, struct file *file);
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index c8f13d8370e5..73612c5353d1 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -730,6 +730,9 @@ static int au8522_probe(struct i2c_client *client,
struct v4l2_ctrl_handler *hdl;
struct v4l2_subdev *sd;
int instance;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int ret;
+#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter,
@@ -758,6 +761,20 @@ static int au8522_probe(struct i2c_client *client,
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &au8522_ops);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+
+ state->pads[AU8522_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[AU8522_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
+
+ ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
+ state->pads);
+ if (ret < 0) {
+ v4l_info(client, "failed to initialize media entity!\n");
+ return ret;
+ }
+#endif
hdl = &state->hdl;
v4l2_ctrl_handler_init(hdl, 4);
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
index ee330c61aa61..404a0cb0ed8d 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -39,6 +39,14 @@
#define AU8522_DIGITAL_MODE 1
#define AU8522_SUSPEND_MODE 2
+enum au8522_media_pads {
+ AU8522_PAD_INPUT,
+ AU8522_PAD_VID_OUT,
+ AU8522_PAD_VBI_OUT,
+
+ AU8522_NUM_PADS
+};
+
struct au8522_state {
struct i2c_client *c;
struct i2c_adapter *i2c;
@@ -68,6 +76,10 @@ struct au8522_state {
u32 id;
u32 rev;
struct v4l2_ctrl_handler hdl;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_pad pads[AU8522_NUM_PADS];
+#endif
};
/* These are routines shared by both the VSB/QAM demodulator and the analog
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index def6d21d1445..24a457d9d803 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -722,7 +722,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
#ifdef CONFIG_GPIOLIB
/* add GPIOs */
priv->gpio_chip.label = KBUILD_MODNAME;
- priv->gpio_chip.dev = &priv->i2c->dev;
+ priv->gpio_chip.parent = &priv->i2c->dev;
priv->gpio_chip.owner = THIS_MODULE;
priv->gpio_chip.direction_output =
cxd2820r_gpio_direction_output;
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index feeeb70d841e..ce73a5ec6036 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -685,7 +685,7 @@ static int m88ds3103_init(struct dvb_frontend *fe)
/* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, &client->dev);
if (ret) {
- dev_err(&client->dev, "firmare file '%s' not found\n", fw_file);
+ dev_err(&client->dev, "firmware file '%s' not found\n", fw_file);
goto err;
}
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 1cf6e52e0105..2b93241d4bc1 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -541,7 +541,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
&offset, block_count);
if (ret < 0) {
dev_err(&state->i2c->dev,
- "%s: firmare could not be uploaded\n",
+ "%s: firmware could not be uploaded\n",
KBUILD_MODNAME);
goto error;
}
@@ -565,7 +565,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
if (len != offset) {
dev_err(&state->i2c->dev,
- "%s: firmare len mismatch %04x != %04x\n",
+ "%s: firmware len mismatch %04x != %04x\n",
KBUILD_MODNAME, len, offset);
ret = -EINVAL;
goto error;
diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c
index e63f582378bf..edbb30fdd9d9 100644
--- a/drivers/media/firewire/firedtv-ci.c
+++ b/drivers/media/firewire/firedtv-ci.c
@@ -241,7 +241,7 @@ int fdtv_ca_register(struct firedtv *fdtv)
return -EFAULT;
err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
- &fdtv_ca, fdtv, DVB_DEVICE_CA);
+ &fdtv_ca, fdtv, DVB_DEVICE_CA, 0);
if (stat.ca_application_info == 0)
dev_err(fdtv->device, "CaApplicationInfo is not set\n");
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 0494a7896aa2..788967dadd29 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -1158,7 +1158,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
state->rgb_quantization_range_ctrl->is_private = true;
state->pad.flags = MEDIA_PAD_FL_SINK;
- err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+ err = media_entity_pads_init(&sd->entity, 1, &state->pad);
if (err)
goto err_hdl;
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index f00745bbe471..7e9cbf757e95 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -512,11 +512,11 @@ static int adp1653_probe(struct i2c_client *client,
if (ret)
goto free_and_quit;
- ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+ ret = media_entity_pads_init(&flash->subdev.entity, 0, NULL);
if (ret < 0)
goto free_and_quit;
- flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+ flash->subdev.entity.function = MEDIA_ENT_F_FLASH;
return 0;
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 3c3c4bfe3866..ff57c1dcb8af 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1213,8 +1213,8 @@ static int adv7180_probe(struct i2c_client *client,
goto err_unregister_vpp_client;
state->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
- ret = media_entity_init(&sd->entity, 1, &state->pad, 0);
+ sd->entity.flags |= MEDIA_ENT_F_ATV_DECODER;
+ ret = media_entity_pads_init(&sd->entity, 1, &state->pad);
if (ret)
goto err_free_ctrl;
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index eeb2cd823c4d..471fd23b5c5c 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -1482,7 +1482,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
state->rgb_quantization_range_ctrl->is_private = true;
state->pad.flags = MEDIA_PAD_FL_SINK;
- err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+ err = media_entity_pads_init(&sd->entity, 1, &state->pad);
if (err)
goto err_hdl;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 745286225655..f8dd7505b529 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -3208,8 +3208,8 @@ static int adv76xx_probe(struct i2c_client *client,
state->pads[i].flags = MEDIA_PAD_FL_SINK;
state->pads[state->source_pad].flags = MEDIA_PAD_FL_SOURCE;
- err = media_entity_init(&sd->entity, state->source_pad + 1,
- state->pads, 0);
+ err = media_entity_pads_init(&sd->entity, state->source_pad + 1,
+ state->pads);
if (err)
goto err_work_queues;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 69378e4914b6..5fbb788e7b59 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -3309,7 +3309,7 @@ static int adv7842_probe(struct i2c_client *client,
adv7842_delayed_work_enable_hotplug);
state->pad.flags = MEDIA_PAD_FL_SOURCE;
- err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+ err = media_entity_pads_init(&sd->entity, 1, &state->pad);
if (err)
goto err_work_queues;
diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
index 29a2e7034aa6..2e90e4094b79 100644
--- a/drivers/media/i2c/as3645a.c
+++ b/drivers/media/i2c/as3645a.c
@@ -827,11 +827,11 @@ static int as3645a_probe(struct i2c_client *client,
if (ret < 0)
goto done;
- ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+ ret = media_entity_pads_init(&flash->subdev.entity, 0, NULL);
if (ret < 0)
goto done;
- flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+ flash->subdev.entity.function = MEDIA_ENT_F_FLASH;
mutex_init(&flash->power_lock);
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index f2e2c34ddbbd..07a3e7173144 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -5211,10 +5211,10 @@ static int cx25840_probe(struct i2c_client *client,
state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
state->pads[CX25840_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+ sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
- ret = media_entity_init(&sd->entity, ARRAY_SIZE(state->pads),
- state->pads, 0);
+ ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
+ state->pads);
if (ret < 0) {
v4l_info(client, "failed to initialize media entity!\n");
return ret;
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index 19ecb8801064..251a2aaf98c3 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -365,10 +365,10 @@ static int lm3560_subdev_init(struct lm3560_flash *flash,
rval = lm3560_init_controls(flash, led_no);
if (rval)
goto err_out;
- rval = media_entity_init(&flash->subdev_led[led_no].entity, 0, NULL, 0);
+ rval = media_entity_pads_init(&flash->subdev_led[led_no].entity, 0, NULL);
if (rval < 0)
goto err_out;
- flash->subdev_led[led_no].entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+ flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH;
return rval;
diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c
index 7fbe6ff1c4f4..7e9967af36ec 100644
--- a/drivers/media/i2c/lm3646.c
+++ b/drivers/media/i2c/lm3646.c
@@ -282,10 +282,10 @@ static int lm3646_subdev_init(struct lm3646_flash *flash)
rval = lm3646_init_controls(flash);
if (rval)
goto err_out;
- rval = media_entity_init(&flash->subdev_led.entity, 0, NULL, 0);
+ rval = media_entity_pads_init(&flash->subdev_led.entity, 0, NULL);
if (rval < 0)
goto err_out;
- flash->subdev_led.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+ flash->subdev_led.entity.function = MEDIA_ENT_F_FLASH;
return rval;
err_out:
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index f8993933416e..acb804bceccb 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -975,10 +975,10 @@ static int m5mols_probe(struct i2c_client *client,
sd->internal_ops = &m5mols_subdev_internal_ops;
info->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+ ret = media_entity_pads_init(&sd->entity, 1, &info->pad);
if (ret < 0)
return ret;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
init_waitqueue_head(&info->irq_waitq);
mutex_init(&info->lock);
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 101cb26f9330..da076796999e 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -799,7 +799,7 @@ static int mt9m032_probe(struct i2c_client *client,
sensor->subdev.ctrl_handler = &sensor->ctrls;
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0);
+ ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
if (ret < 0)
goto error_ctrl;
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index a3da0e977d0b..237737fec09c 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -1112,7 +1112,7 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0);
+ ret = media_entity_pads_init(&mt9p031->subdev.entity, 1, &mt9p031->pad);
if (ret < 0)
goto done;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index b28fdff1d310..702d562f8e39 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -933,7 +933,7 @@ static int mt9t001_probe(struct i2c_client *client,
mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&mt9t001->subdev.entity, 1, &mt9t001->pad, 0);
+ ret = media_entity_pads_init(&mt9t001->subdev.entity, 1, &mt9t001->pad);
done:
if (ret < 0) {
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 1dbbd23fdfb0..2e1d116a64e7 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -1046,7 +1046,7 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+ ret = media_entity_pads_init(&mt9v032->subdev.entity, 1, &mt9v032->pad);
if (ret < 0)
goto err;
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 69e4f3031d8b..30cb90b88d75 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -779,8 +779,8 @@ static int noon010_probe(struct i2c_client *client,
goto np_err;
info->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &info->pad);
if (ret < 0)
goto np_err;
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index 82c7ac1cc88e..02b9a3440557 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -1445,8 +1445,8 @@ static int ov2659_probe(struct i2c_client *client,
#if defined(CONFIG_MEDIA_CONTROLLER)
ov2659->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, 1, &ov2659->pad, 0);
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov2659->pad);
if (ret < 0) {
v4l2_ctrl_handler_free(&ov2659->ctrls);
return ret;
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 9fe9006474b2..a0b3c9bde53d 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1500,8 +1500,8 @@ static int ov965x_probe(struct i2c_client *client,
return ret;
ov965x->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, 1, &ov965x->pad, 0);
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov965x->pad);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 25f5e79dc9bc..57b3d27993a4 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1482,11 +1482,11 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd)
return ret;
}
- ret = media_entity_create_link(&state->sensor_sd.entity,
+ ret = media_create_pad_link(&state->sensor_sd.entity,
S5C73M3_ISP_PAD, &state->oif_sd.entity, OIF_ISP_PAD,
MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
- ret = media_entity_create_link(&state->sensor_sd.entity,
+ ret = media_create_pad_link(&state->sensor_sd.entity,
S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD,
MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
@@ -1688,10 +1688,10 @@ static int s5c73m3_probe(struct i2c_client *client,
state->sensor_pads[S5C73M3_JPEG_PAD].flags = MEDIA_PAD_FL_SOURCE;
state->sensor_pads[S5C73M3_ISP_PAD].flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
- ret = media_entity_init(&sd->entity, S5C73M3_NUM_PADS,
- state->sensor_pads, 0);
+ ret = media_entity_pads_init(&sd->entity, S5C73M3_NUM_PADS,
+ state->sensor_pads);
if (ret < 0)
return ret;
@@ -1704,10 +1704,10 @@ static int s5c73m3_probe(struct i2c_client *client,
state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK;
state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK;
state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE;
- oif_sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ oif_sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
- ret = media_entity_init(&oif_sd->entity, OIF_NUM_PADS,
- state->oif_pads, 0);
+ ret = media_entity_pads_init(&oif_sd->entity, OIF_NUM_PADS,
+ state->oif_pads);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index 6757aca2cdab..8a0f22da590f 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -961,8 +961,8 @@ static int s5k4ecgx_probe(struct i2c_client *client,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
priv->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, 1, &priv->pad, 0);
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
if (ret)
return ret;
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 774e0d0c94cb..fc3a5a8e6c9c 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -408,7 +408,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
static inline bool s5k5baf_is_cis_subdev(struct v4l2_subdev *sd)
{
- return sd->entity.type == MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ return sd->entity.function == MEDIA_ENT_F_CAM_SENSOR;
}
static inline struct s5k5baf *to_s5k5baf(struct v4l2_subdev *sd)
@@ -1756,7 +1756,7 @@ static int s5k5baf_registered(struct v4l2_subdev *sd)
v4l2_err(sd, "failed to register subdev %s\n",
state->cis_sd.name);
else
- ret = media_entity_create_link(&state->cis_sd.entity, PAD_CIS,
+ ret = media_create_pad_link(&state->cis_sd.entity, PAD_CIS,
&state->sd.entity, PAD_CIS,
MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
@@ -1904,8 +1904,8 @@ static int s5k5baf_configure_subdevs(struct s5k5baf *state,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
state->cis_pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, NUM_CIS_PADS, &state->cis_pad, 0);
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, NUM_CIS_PADS, &state->cis_pad);
if (ret < 0)
goto err;
@@ -1919,8 +1919,8 @@ static int s5k5baf_configure_subdevs(struct s5k5baf *state,
state->pads[PAD_CIS].flags = MEDIA_PAD_FL_SINK;
state->pads[PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
- ret = media_entity_init(&sd->entity, NUM_ISP_PADS, state->pads, 0);
+ sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ ret = media_entity_pads_init(&sd->entity, NUM_ISP_PADS, state->pads);
if (!ret)
return 0;
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index b1b1574dfb95..b9e43ffa5085 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -333,7 +333,7 @@ static int s5k6a3_probe(struct i2c_client *client,
sensor->format.height = S5K6A3_DEFAULT_HEIGHT;
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0);
+ ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 60aaff7190d2..faee11383cb7 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -1577,8 +1577,8 @@ static int s5k6aa_probe(struct i2c_client *client,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
- ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0);
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &s5k6aa->pad);
if (ret)
return ret;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index fb39dfd55e75..a215efe7a8ba 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -2487,31 +2487,31 @@ static int smiapp_register_subdevs(struct smiapp_sensor *sensor)
if (!last)
continue;
- rval = media_entity_init(&this->sd.entity,
- this->npads, this->pads, 0);
+ rval = media_entity_pads_init(&this->sd.entity,
+ this->npads, this->pads);
if (rval) {
dev_err(&client->dev,
- "media_entity_init failed\n");
+ "media_entity_pads_init failed\n");
return rval;
}
- rval = media_entity_create_link(&this->sd.entity,
- this->source_pad,
- &last->sd.entity,
- last->sink_pad,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
+ rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+ &this->sd);
if (rval) {
dev_err(&client->dev,
- "media_entity_create_link failed\n");
+ "v4l2_device_register_subdev failed\n");
return rval;
}
- rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
- &this->sd);
+ rval = media_create_pad_link(&this->sd.entity,
+ this->source_pad,
+ &last->sd.entity,
+ last->sink_pad,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
if (rval) {
dev_err(&client->dev,
- "v4l2_device_register_subdev failed\n");
+ "media_create_pad_link failed\n");
return rval;
}
}
@@ -2763,7 +2763,7 @@ static int smiapp_init(struct smiapp_sensor *sensor)
dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
- sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
/* final steps */
smiapp_read_frame_fmt(sensor);
@@ -3077,8 +3077,8 @@ static int smiapp_probe(struct i2c_client *client,
sensor->src->sensor = sensor;
sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
- rval = media_entity_init(&sensor->src->sd.entity, 2,
- sensor->src->pads, 0);
+ rval = media_entity_pads_init(&sensor->src->sd.entity, 2,
+ sensor->src->pads);
if (rval < 0)
return rval;
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 77b801152ea5..3397eb99c67b 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1889,7 +1889,7 @@ static int tc358743_probe(struct i2c_client *client,
}
state->pad.flags = MEDIA_PAD_FL_SOURCE;
- err = media_entity_init(&sd->entity, 1, &state->pad, 0);
+ err = media_entity_pads_init(&sd->entity, 1, &state->pad);
if (err < 0)
goto err_hdl;
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index b5dba5b7ce3a..7fa5f1e4fe37 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -1095,9 +1095,9 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
#if defined(CONFIG_MEDIA_CONTROLLER)
decoder->pad.flags = MEDIA_PAD_FL_SOURCE;
decoder->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- decoder->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+ decoder->sd.entity.flags |= MEDIA_ENT_F_ATV_DECODER;
- ret = media_entity_init(&decoder->sd.entity, 1, &decoder->pad, 0);
+ ret = media_entity_pads_init(&decoder->sd.entity, 1, &decoder->pad);
if (ret < 0) {
v4l2_err(sd, "%s decoder driver failed to register !!\n",
sd->name);
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 772a3043ae3b..83c79fa5f61d 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -1012,9 +1012,9 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
#if defined(CONFIG_MEDIA_CONTROLLER)
device->pad.flags = MEDIA_PAD_FL_SOURCE;
device->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- device->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+ device->sd.entity.flags |= MEDIA_ENT_F_ATV_DECODER;
- error = media_entity_init(&device->sd.entity, 1, &device->pad, 0);
+ error = media_entity_pads_init(&device->sd.entity, 1, &device->pad);
if (error < 0)
return error;
#endif
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 7b39440192d6..7dae0ac0f3ae 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -22,14 +22,18 @@
#include <linux/compat.h>
#include <linux/export.h>
+#include <linux/idr.h>
#include <linux/ioctl.h>
#include <linux/media.h>
+#include <linux/slab.h>
#include <linux/types.h>
#include <media/media-device.h>
#include <media/media-devnode.h>
#include <media/media-entity.h>
+#ifdef CONFIG_MEDIA_CONTROLLER
+
/* -----------------------------------------------------------------------------
* Userspace API
*/
@@ -75,8 +79,8 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id)
spin_lock(&mdev->lock);
media_device_for_each_entity(entity, mdev) {
- if ((entity->id == id && !next) ||
- (entity->id > id && next)) {
+ if (((media_entity_id(entity) == id) && !next) ||
+ ((media_entity_id(entity) > id) && next)) {
spin_unlock(&mdev->lock);
return entity;
}
@@ -102,13 +106,13 @@ static long media_device_enum_entities(struct media_device *mdev,
if (ent == NULL)
return -EINVAL;
- u_ent.id = ent->id;
+ u_ent.id = media_entity_id(ent);
if (ent->name)
strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
- u_ent.type = ent->type;
- u_ent.revision = ent->revision;
+ u_ent.type = ent->function;
+ u_ent.revision = 0; /* Unused */
u_ent.flags = ent->flags;
- u_ent.group_id = ent->group_id;
+ u_ent.group_id = 0; /* Unused */
u_ent.pads = ent->num_pads;
u_ent.links = ent->num_links - ent->num_backlinks;
memcpy(&u_ent.raw, &ent->info, sizeof(ent->info));
@@ -120,7 +124,7 @@ static long media_device_enum_entities(struct media_device *mdev,
static void media_device_kpad_to_upad(const struct media_pad *kpad,
struct media_pad_desc *upad)
{
- upad->entity = kpad->entity->id;
+ upad->entity = media_entity_id(kpad->entity);
upad->index = kpad->index;
upad->flags = kpad->flags;
}
@@ -148,25 +152,25 @@ static long __media_device_enum_links(struct media_device *mdev,
}
if (links->links) {
- struct media_link_desc __user *ulink;
- unsigned int l;
+ struct media_link *link;
+ struct media_link_desc __user *ulink_desc = links->links;
- for (l = 0, ulink = links->links; l < entity->num_links; l++) {
- struct media_link_desc link;
+ list_for_each_entry(link, &entity->links, list) {
+ struct media_link_desc klink_desc;
/* Ignore backlinks. */
- if (entity->links[l].source->entity != entity)
+ if (link->source->entity != entity)
continue;
-
- memset(&link, 0, sizeof(link));
- media_device_kpad_to_upad(entity->links[l].source,
- &link.source);
- media_device_kpad_to_upad(entity->links[l].sink,
- &link.sink);
- link.flags = entity->links[l].flags;
- if (copy_to_user(ulink, &link, sizeof(*ulink)))
+ memset(&klink_desc, 0, sizeof(klink_desc));
+ media_device_kpad_to_upad(link->source,
+ &klink_desc.source);
+ media_device_kpad_to_upad(link->sink,
+ &klink_desc.sink);
+ klink_desc.flags = link->flags;
+ if (copy_to_user(ulink_desc, &klink_desc,
+ sizeof(*ulink_desc)))
return -EFAULT;
- ulink++;
+ ulink_desc++;
}
}
@@ -230,6 +234,164 @@ static long media_device_setup_link(struct media_device *mdev,
return ret;
}
+#if 0 /* Let's postpone it to Kernel 4.6 */
+static long __media_device_get_topology(struct media_device *mdev,
+ struct media_v2_topology *topo)
+{
+ struct media_entity *entity;
+ struct media_interface *intf;
+ struct media_pad *pad;
+ struct media_link *link;
+ struct media_v2_entity kentity, *uentity;
+ struct media_v2_interface kintf, *uintf;
+ struct media_v2_pad kpad, *upad;
+ struct media_v2_link klink, *ulink;
+ unsigned int i;
+ int ret = 0;
+
+ topo->topology_version = mdev->topology_version;
+
+ /* Get entities and number of entities */
+ i = 0;
+ uentity = media_get_uptr(topo->ptr_entities);
+ media_device_for_each_entity(entity, mdev) {
+ i++;
+ if (ret || !uentity)
+ continue;
+
+ if (i > topo->num_entities) {
+ ret = -ENOSPC;
+ continue;
+ }
+
+ /* Copy fields to userspace struct if not error */
+ memset(&kentity, 0, sizeof(kentity));
+ kentity.id = entity->graph_obj.id;
+ kentity.function = entity->function;
+ strncpy(kentity.name, entity->name,
+ sizeof(kentity.name));
+
+ if (copy_to_user(uentity, &kentity, sizeof(kentity)))
+ ret = -EFAULT;
+ uentity++;
+ }
+ topo->num_entities = i;
+
+ /* Get interfaces and number of interfaces */
+ i = 0;
+ uintf = media_get_uptr(topo->ptr_interfaces);
+ media_device_for_each_intf(intf, mdev) {
+ i++;
+ if (ret || !uintf)
+ continue;
+
+ if (i > topo->num_interfaces) {
+ ret = -ENOSPC;
+ continue;
+ }
+
+ memset(&kintf, 0, sizeof(kintf));
+
+ /* Copy intf fields to userspace struct */
+ kintf.id = intf->graph_obj.id;
+ kintf.intf_type = intf->type;
+ kintf.flags = intf->flags;
+
+ if (media_type(&intf->graph_obj) == MEDIA_GRAPH_INTF_DEVNODE) {
+ struct media_intf_devnode *devnode;
+
+ devnode = intf_to_devnode(intf);
+
+ kintf.devnode.major = devnode->major;
+ kintf.devnode.minor = devnode->minor;
+ }
+
+ if (copy_to_user(uintf, &kintf, sizeof(kintf)))
+ ret = -EFAULT;
+ uintf++;
+ }
+ topo->num_interfaces = i;
+
+ /* Get pads and number of pads */
+ i = 0;
+ upad = media_get_uptr(topo->ptr_pads);
+ media_device_for_each_pad(pad, mdev) {
+ i++;
+ if (ret || !upad)
+ continue;
+
+ if (i > topo->num_pads) {
+ ret = -ENOSPC;
+ continue;
+ }
+
+ memset(&kpad, 0, sizeof(kpad));
+
+ /* Copy pad fields to userspace struct */
+ kpad.id = pad->graph_obj.id;
+ kpad.entity_id = pad->entity->graph_obj.id;
+ kpad.flags = pad->flags;
+
+ if (copy_to_user(upad, &kpad, sizeof(kpad)))
+ ret = -EFAULT;
+ upad++;
+ }
+ topo->num_pads = i;
+
+ /* Get links and number of links */
+ i = 0;
+ ulink = media_get_uptr(topo->ptr_links);
+ media_device_for_each_link(link, mdev) {
+ if (link->is_backlink)
+ continue;
+
+ i++;
+
+ if (ret || !ulink)
+ continue;
+
+ if (i > topo->num_links) {
+ ret = -ENOSPC;
+ continue;
+ }
+
+ memset(&klink, 0, sizeof(klink));
+
+ /* Copy link fields to userspace struct */
+ klink.id = link->graph_obj.id;
+ klink.source_id = link->gobj0->id;
+ klink.sink_id = link->gobj1->id;
+ klink.flags = link->flags;
+
+ if (copy_to_user(ulink, &klink, sizeof(klink)))
+ ret = -EFAULT;
+ ulink++;
+ }
+ topo->num_links = i;
+
+ return ret;
+}
+
+static long media_device_get_topology(struct media_device *mdev,
+ struct media_v2_topology __user *utopo)
+{
+ struct media_v2_topology ktopo;
+ int ret;
+
+ if (copy_from_user(&ktopo, utopo, sizeof(ktopo)))
+ return -EFAULT;
+
+ ret = __media_device_get_topology(mdev, &ktopo);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user(utopo, &ktopo, sizeof(*utopo)))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
static long media_device_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -262,6 +424,14 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
mutex_unlock(&dev->graph_mutex);
break;
+#if 0 /* Let's postpone it to Kernel 4.6 */
+ case MEDIA_IOC_G_TOPOLOGY:
+ mutex_lock(&dev->graph_mutex);
+ ret = media_device_get_topology(dev,
+ (struct media_v2_topology __user *)arg);
+ mutex_unlock(&dev->graph_mutex);
+ break;
+#endif
default:
ret = -ENOIOCTLCMD;
}
@@ -310,6 +480,9 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
case MEDIA_IOC_DEVICE_INFO:
case MEDIA_IOC_ENUM_ENTITIES:
case MEDIA_IOC_SETUP_LINK:
+#if 0 /* Let's postpone it to Kernel 4.6 */
+ case MEDIA_IOC_G_TOPOLOGY:
+#endif
return media_device_ioctl(filp, cmd, arg);
case MEDIA_IOC_ENUM_LINKS32:
@@ -357,10 +530,107 @@ static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
static void media_device_release(struct media_devnode *mdev)
{
+ dev_dbg(mdev->parent, "Media device released\n");
+}
+
+/**
+ * media_device_register_entity - Register an entity with a media device
+ * @mdev: The media device
+ * @entity: The entity
+ */
+int __must_check media_device_register_entity(struct media_device *mdev,
+ struct media_entity *entity)
+{
+ unsigned int i;
+ int ret;
+
+ if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN ||
+ entity->function == MEDIA_ENT_F_UNKNOWN)
+ dev_warn(mdev->dev,
+ "Entity type for entity %s was not initialized!\n",
+ entity->name);
+
+ /* Warn if we apparently re-register an entity */
+ WARN_ON(entity->graph_obj.mdev != NULL);
+ entity->graph_obj.mdev = mdev;
+ INIT_LIST_HEAD(&entity->links);
+ entity->num_links = 0;
+ entity->num_backlinks = 0;
+
+ if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL))
+ return -ENOMEM;
+
+ spin_lock(&mdev->lock);
+
+ ret = ida_get_new_above(&mdev->entity_internal_idx, 1,
+ &entity->internal_idx);
+ if (ret < 0) {
+ spin_unlock(&mdev->lock);
+ return ret;
+ }
+
+ mdev->entity_internal_idx_max =
+ max(mdev->entity_internal_idx_max, entity->internal_idx);
+
+ /* Initialize media_gobj embedded at the entity */
+ media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj);
+
+ /* Initialize objects at the pads */
+ for (i = 0; i < entity->num_pads; i++)
+ media_gobj_create(mdev, MEDIA_GRAPH_PAD,
+ &entity->pads[i].graph_obj);
+
+ spin_unlock(&mdev->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register_entity);
+
+static void __media_device_unregister_entity(struct media_entity *entity)
+{
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_link *link, *tmp;
+ struct media_interface *intf;
+ unsigned int i;
+
+ ida_simple_remove(&mdev->entity_internal_idx, entity->internal_idx);
+
+ /* Remove all interface links pointing to this entity */
+ list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
+ list_for_each_entry_safe(link, tmp, &intf->links, list) {
+ if (link->entity == entity)
+ __media_remove_intf_link(link);
+ }
+ }
+
+ /* Remove all data links that belong to this entity */
+ __media_entity_remove_links(entity);
+
+ /* Remove all pads that belong to this entity */
+ for (i = 0; i < entity->num_pads; i++)
+ media_gobj_destroy(&entity->pads[i].graph_obj);
+
+ /* Remove the entity */
+ media_gobj_destroy(&entity->graph_obj);
+
+ entity->graph_obj.mdev = NULL;
}
+void media_device_unregister_entity(struct media_entity *entity)
+{
+ struct media_device *mdev = entity->graph_obj.mdev;
+
+ if (mdev == NULL)
+ return;
+
+ spin_lock(&mdev->lock);
+ __media_device_unregister_entity(entity);
+ spin_unlock(&mdev->lock);
+}
+EXPORT_SYMBOL_GPL(media_device_unregister_entity);
+
/**
- * media_device_register - register a media device
+ * media_device_init() - initialize a media device
* @mdev: The media device
*
* The caller is responsible for initializing the media device before
@@ -369,23 +639,41 @@ static void media_device_release(struct media_devnode *mdev)
* - dev must point to the parent device
* - model must be filled with the device model name
*/
-int __must_check __media_device_register(struct media_device *mdev,
- struct module *owner)
+void media_device_init(struct media_device *mdev)
{
- int ret;
-
- if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
- return -EINVAL;
-
- mdev->entity_id = 1;
INIT_LIST_HEAD(&mdev->entities);
+ INIT_LIST_HEAD(&mdev->interfaces);
+ INIT_LIST_HEAD(&mdev->pads);
+ INIT_LIST_HEAD(&mdev->links);
spin_lock_init(&mdev->lock);
mutex_init(&mdev->graph_mutex);
+ ida_init(&mdev->entity_internal_idx);
+
+ dev_dbg(mdev->dev, "Media device initialized\n");
+}
+EXPORT_SYMBOL_GPL(media_device_init);
+
+void media_device_cleanup(struct media_device *mdev)
+{
+ ida_destroy(&mdev->entity_internal_idx);
+ mdev->entity_internal_idx_max = 0;
+ mutex_destroy(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_device_cleanup);
+
+int __must_check __media_device_register(struct media_device *mdev,
+ struct module *owner)
+{
+ int ret;
/* Register the device node. */
mdev->devnode.fops = &media_device_fops;
mdev->devnode.parent = mdev->dev;
mdev->devnode.release = media_device_release;
+
+ /* Set version 0 to indicate user-space that the graph is static */
+ mdev->topology_version = 0;
+
ret = media_devnode_register(&mdev->devnode, owner);
if (ret < 0)
return ret;
@@ -396,69 +684,74 @@ int __must_check __media_device_register(struct media_device *mdev,
return ret;
}
+ dev_dbg(mdev->dev, "Media device registered\n");
+
return 0;
}
EXPORT_SYMBOL_GPL(__media_device_register);
-/**
- * media_device_unregister - unregister a media device
- * @mdev: The media device
- *
- */
void media_device_unregister(struct media_device *mdev)
{
struct media_entity *entity;
struct media_entity *next;
+ struct media_interface *intf, *tmp_intf;
- list_for_each_entry_safe(entity, next, &mdev->entities, list)
- media_device_unregister_entity(entity);
+ if (mdev == NULL)
+ return;
+
+ spin_lock(&mdev->lock);
+
+ /* Check if mdev was ever registered at all */
+ if (!media_devnode_is_registered(&mdev->devnode)) {
+ spin_unlock(&mdev->lock);
+ return;
+ }
+
+ /* Remove all entities from the media device */
+ list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list)
+ __media_device_unregister_entity(entity);
+
+ /* Remove all interfaces from the media device */
+ list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces,
+ graph_obj.list) {
+ __media_remove_intf_links(intf);
+ media_gobj_destroy(&intf->graph_obj);
+ kfree(intf);
+ }
+
+ spin_unlock(&mdev->lock);
device_remove_file(&mdev->devnode.dev, &dev_attr_model);
media_devnode_unregister(&mdev->devnode);
+
+ dev_dbg(mdev->dev, "Media device unregistered\n");
}
EXPORT_SYMBOL_GPL(media_device_unregister);
-/**
- * media_device_register_entity - Register an entity with a media device
- * @mdev: The media device
- * @entity: The entity
- */
-int __must_check media_device_register_entity(struct media_device *mdev,
- struct media_entity *entity)
+static void media_device_release_devres(struct device *dev, void *res)
{
- /* Warn if we apparently re-register an entity */
- WARN_ON(entity->parent != NULL);
- entity->parent = mdev;
-
- spin_lock(&mdev->lock);
- if (entity->id == 0)
- entity->id = mdev->entity_id++;
- else
- mdev->entity_id = max(entity->id + 1, mdev->entity_id);
- list_add_tail(&entity->list, &mdev->entities);
- spin_unlock(&mdev->lock);
-
- return 0;
}
-EXPORT_SYMBOL_GPL(media_device_register_entity);
-/**
- * media_device_unregister_entity - Unregister an entity
- * @entity: The entity
- *
- * If the entity has never been registered this function will return
- * immediately.
- */
-void media_device_unregister_entity(struct media_entity *entity)
+struct media_device *media_device_get_devres(struct device *dev)
{
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev;
- if (mdev == NULL)
- return;
+ mdev = devres_find(dev, media_device_release_devres, NULL, NULL);
+ if (mdev)
+ return mdev;
- spin_lock(&mdev->lock);
- list_del(&entity->list);
- spin_unlock(&mdev->lock);
- entity->parent = NULL;
+ mdev = devres_alloc(media_device_release_devres,
+ sizeof(struct media_device), GFP_KERNEL);
+ if (!mdev)
+ return NULL;
+ return devres_get(dev, mdev, NULL, NULL);
}
-EXPORT_SYMBOL_GPL(media_device_unregister_entity);
+EXPORT_SYMBOL_GPL(media_device_get_devres);
+
+struct media_device *media_device_find_devres(struct device *dev)
+{
+ return devres_find(dev, media_device_release_devres, NULL, NULL);
+}
+EXPORT_SYMBOL_GPL(media_device_find_devres);
+
+#endif /* CONFIG_MEDIA_CONTROLLER */
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index ebf9626e5ae5..cea35bf20011 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -217,20 +217,6 @@ static const struct file_operations media_devnode_fops = {
.llseek = no_llseek,
};
-/**
- * media_devnode_register - register a media device node
- * @mdev: media device node structure we want to register
- *
- * The registration code assigns minor numbers and registers the new device node
- * with the kernel. An error is returned if no free minor number can be found,
- * or if the registration of the device node fails.
- *
- * Zero is returned on success.
- *
- * Note that if the media_devnode_register call fails, the release() callback of
- * the media_devnode structure is *not* called, so the caller is responsible for
- * freeing any data.
- */
int __must_check media_devnode_register(struct media_devnode *mdev,
struct module *owner)
{
@@ -285,16 +271,6 @@ error:
return ret;
}
-/**
- * media_devnode_unregister - unregister a media device node
- * @mdev: the device node to unregister
- *
- * This unregisters the passed device. Future open calls will be met with
- * errors.
- *
- * This function can safely be called if the device node has never been
- * registered or has already been unregistered.
- */
void media_devnode_unregister(struct media_devnode *mdev)
{
/* Check if mdev was ever registered at all */
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 767fe55ba08e..e89d85a7d31b 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -26,65 +26,198 @@
#include <media/media-entity.h>
#include <media/media-device.h>
+static inline const char *gobj_type(enum media_gobj_type type)
+{
+ switch (type) {
+ case MEDIA_GRAPH_ENTITY:
+ return "entity";
+ case MEDIA_GRAPH_PAD:
+ return "pad";
+ case MEDIA_GRAPH_LINK:
+ return "link";
+ case MEDIA_GRAPH_INTF_DEVNODE:
+ return "intf-devnode";
+ default:
+ return "unknown";
+ }
+}
+
+static inline const char *intf_type(struct media_interface *intf)
+{
+ switch (intf->type) {
+ case MEDIA_INTF_T_DVB_FE:
+ return "frontend";
+ case MEDIA_INTF_T_DVB_DEMUX:
+ return "demux";
+ case MEDIA_INTF_T_DVB_DVR:
+ return "DVR";
+ case MEDIA_INTF_T_DVB_CA:
+ return "CA";
+ case MEDIA_INTF_T_DVB_NET:
+ return "dvbnet";
+ case MEDIA_INTF_T_V4L_VIDEO:
+ return "video";
+ case MEDIA_INTF_T_V4L_VBI:
+ return "vbi";
+ case MEDIA_INTF_T_V4L_RADIO:
+ return "radio";
+ case MEDIA_INTF_T_V4L_SUBDEV:
+ return "v4l2-subdev";
+ case MEDIA_INTF_T_V4L_SWRADIO:
+ return "swradio";
+ default:
+ return "unknown-intf";
+ }
+};
+
+__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
+ int idx_max)
+{
+ ent_enum->bmap = kcalloc(DIV_ROUND_UP(idx_max, BITS_PER_LONG),
+ sizeof(long), GFP_KERNEL);
+ if (!ent_enum->bmap)
+ return -ENOMEM;
+
+ bitmap_zero(ent_enum->bmap, idx_max);
+ ent_enum->idx_max = idx_max;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__media_entity_enum_init);
+
+void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
+{
+ kfree(ent_enum->bmap);
+}
+EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
+
/**
- * media_entity_init - Initialize a media entity
- *
- * @num_pads: Total number of sink and source pads.
- * @extra_links: Initial estimate of the number of extra links.
- * @pads: Array of 'num_pads' pads.
- *
- * The total number of pads is an intrinsic property of entities known by the
- * entity driver, while the total number of links depends on hardware design
- * and is an extrinsic property unknown to the entity driver. However, in most
- * use cases the entity driver can guess the number of links which can safely
- * be assumed to be equal to or larger than the number of pads.
- *
- * For those reasons the links array can be preallocated based on the entity
- * driver guess and will be reallocated later if extra links need to be
- * created.
+ * dev_dbg_obj - Prints in debug mode a change on some object
*
- * This function allocates a links array with enough space to hold at least
- * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will
- * be set to the number of allocated elements.
+ * @event_name: Name of the event to report. Could be __func__
+ * @gobj: Pointer to the object
*
- * The pads array is managed by the entity driver and passed to
- * media_entity_init() where its pointer will be stored in the entity structure.
+ * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
+ * won't produce any code.
*/
-int
-media_entity_init(struct media_entity *entity, u16 num_pads,
- struct media_pad *pads, u16 extra_links)
+static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj)
{
- struct media_link *links;
- unsigned int max_links = num_pads + extra_links;
- unsigned int i;
+#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
+ switch (media_type(gobj)) {
+ case MEDIA_GRAPH_ENTITY:
+ dev_dbg(gobj->mdev->dev,
+ "%s id %u: entity '%s'\n",
+ event_name, media_id(gobj),
+ gobj_to_entity(gobj)->name);
+ break;
+ case MEDIA_GRAPH_LINK:
+ {
+ struct media_link *link = gobj_to_link(gobj);
+
+ dev_dbg(gobj->mdev->dev,
+ "%s id %u: %s link id %u ==> id %u\n",
+ event_name, media_id(gobj),
+ media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
+ "data" : "interface",
+ media_id(link->gobj0),
+ media_id(link->gobj1));
+ break;
+ }
+ case MEDIA_GRAPH_PAD:
+ {
+ struct media_pad *pad = gobj_to_pad(gobj);
+
+ dev_dbg(gobj->mdev->dev,
+ "%s id %u: %s%spad '%s':%d\n",
+ event_name, media_id(gobj),
+ pad->flags & MEDIA_PAD_FL_SINK ? "sink " : "",
+ pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
+ pad->entity->name, pad->index);
+ break;
+ }
+ case MEDIA_GRAPH_INTF_DEVNODE:
+ {
+ struct media_interface *intf = gobj_to_intf(gobj);
+ struct media_intf_devnode *devnode = intf_to_devnode(intf);
+
+ dev_dbg(gobj->mdev->dev,
+ "%s id %u: intf_devnode %s - major: %d, minor: %d\n",
+ event_name, media_id(gobj),
+ intf_type(intf),
+ devnode->major, devnode->minor);
+ break;
+ }
+ }
+#endif
+}
- links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL);
- if (links == NULL)
- return -ENOMEM;
+void media_gobj_create(struct media_device *mdev,
+ enum media_gobj_type type,
+ struct media_gobj *gobj)
+{
+ BUG_ON(!mdev);
+
+ gobj->mdev = mdev;
+
+ /* Create a per-type unique object ID */
+ gobj->id = media_gobj_gen_id(type, ++mdev->id);
+
+ switch (type) {
+ case MEDIA_GRAPH_ENTITY:
+ list_add_tail(&gobj->list, &mdev->entities);
+ break;
+ case MEDIA_GRAPH_PAD:
+ list_add_tail(&gobj->list, &mdev->pads);
+ break;
+ case MEDIA_GRAPH_LINK:
+ list_add_tail(&gobj->list, &mdev->links);
+ break;
+ case MEDIA_GRAPH_INTF_DEVNODE:
+ list_add_tail(&gobj->list, &mdev->interfaces);
+ break;
+ }
+
+ mdev->topology_version++;
+
+ dev_dbg_obj(__func__, gobj);
+}
+
+void media_gobj_destroy(struct media_gobj *gobj)
+{
+ dev_dbg_obj(__func__, gobj);
+
+ gobj->mdev->topology_version++;
+
+ /* Remove the object from mdev list */
+ list_del(&gobj->list);
+}
+
+int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads)
+{
+ struct media_device *mdev = entity->graph_obj.mdev;
+ unsigned int i;
- entity->group_id = 0;
- entity->max_links = max_links;
- entity->num_links = 0;
- entity->num_backlinks = 0;
entity->num_pads = num_pads;
entity->pads = pads;
- entity->links = links;
+
+ if (mdev)
+ spin_lock(&mdev->lock);
for (i = 0; i < num_pads; i++) {
pads[i].entity = entity;
pads[i].index = i;
+ if (mdev)
+ media_gobj_create(mdev, MEDIA_GRAPH_PAD,
+ &entity->pads[i].graph_obj);
}
- return 0;
-}
-EXPORT_SYMBOL_GPL(media_entity_init);
+ if (mdev)
+ spin_unlock(&mdev->lock);
-void
-media_entity_cleanup(struct media_entity *entity)
-{
- kfree(entity->links);
+ return 0;
}
-EXPORT_SYMBOL_GPL(media_entity_cleanup);
+EXPORT_SYMBOL_GPL(media_entity_pads_init);
/* -----------------------------------------------------------------------------
* Graph traversal
@@ -108,7 +241,7 @@ static void stack_push(struct media_entity_graph *graph,
return;
}
graph->top++;
- graph->stack[graph->top].link = 0;
+ graph->stack[graph->top].link = entity->links.next;
graph->stack[graph->top].entity = entity;
}
@@ -125,43 +258,51 @@ static struct media_entity *stack_pop(struct media_entity_graph *graph)
#define link_top(en) ((en)->stack[(en)->top].link)
#define stack_top(en) ((en)->stack[(en)->top].entity)
+/*
+ * TODO: Get rid of this.
+ */
+#define MEDIA_ENTITY_MAX_PADS 512
+
/**
- * media_entity_graph_walk_start - Start walking the media graph at a given entity
+ * media_entity_graph_walk_init - Allocate resources for graph walk
* @graph: Media graph structure that will be used to walk the graph
- * @entity: Starting entity
+ * @mdev: Media device
*
- * This function initializes the graph traversal structure to walk the entities
- * graph starting at the given entity. The traversal structure must not be
- * modified by the caller during graph traversal. When done the structure can
- * safely be freed.
+ * Reserve resources for graph walk in media device's current
+ * state. The memory must be released using
+ * media_entity_graph_walk_free().
+ *
+ * Returns error on failure, zero on success.
*/
+__must_check int media_entity_graph_walk_init(
+ struct media_entity_graph *graph, struct media_device *mdev)
+{
+ return media_entity_enum_init(&graph->ent_enum, mdev);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_walk_init);
+
+/**
+ * media_entity_graph_walk_cleanup - Release resources related to graph walking
+ * @graph: Media graph structure that was used to walk the graph
+ */
+void media_entity_graph_walk_cleanup(struct media_entity_graph *graph)
+{
+ media_entity_enum_cleanup(&graph->ent_enum);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_walk_cleanup);
+
void media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity)
{
+ media_entity_enum_zero(&graph->ent_enum);
+ media_entity_enum_set(&graph->ent_enum, entity);
+
graph->top = 0;
graph->stack[graph->top].entity = NULL;
- bitmap_zero(graph->entities, MEDIA_ENTITY_ENUM_MAX_ID);
-
- if (WARN_ON(entity->id >= MEDIA_ENTITY_ENUM_MAX_ID))
- return;
-
- __set_bit(entity->id, graph->entities);
stack_push(graph, entity);
}
EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
-/**
- * media_entity_graph_walk_next - Get the next entity in the graph
- * @graph: Media graph structure
- *
- * Perform a depth-first traversal of the given media entities graph.
- *
- * The graph structure must have been previously initialized with a call to
- * media_entity_graph_walk_start().
- *
- * Return the next entity in the graph or NULL if the whole graph have been
- * traversed.
- */
struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph)
{
@@ -173,30 +314,30 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
* top of the stack until no more entities on the level can be
* found.
*/
- while (link_top(graph) < stack_top(graph)->num_links) {
+ while (link_top(graph) != &stack_top(graph)->links) {
struct media_entity *entity = stack_top(graph);
- struct media_link *link = &entity->links[link_top(graph)];
+ struct media_link *link;
struct media_entity *next;
+ link = list_entry(link_top(graph), typeof(*link), list);
+
/* The link is not enabled so we do not follow. */
if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
- link_top(graph)++;
+ link_top(graph) = link_top(graph)->next;
continue;
}
/* Get the entity in the other end of the link . */
next = media_entity_other(entity, link);
- if (WARN_ON(next->id >= MEDIA_ENTITY_ENUM_MAX_ID))
- return NULL;
/* Has the entity already been visited? */
- if (__test_and_set_bit(next->id, graph->entities)) {
- link_top(graph)++;
+ if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
+ link_top(graph) = link_top(graph)->next;
continue;
}
/* Push the new entity to stack and start over. */
- link_top(graph)++;
+ link_top(graph) = link_top(graph)->next;
stack_push(graph, next);
}
@@ -208,39 +349,36 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
* Pipeline management
*/
-/**
- * media_entity_pipeline_start - Mark a pipeline as streaming
- * @entity: Starting entity
- * @pipe: Media pipeline to be assigned to all entities in the pipeline.
- *
- * Mark all entities connected to a given entity through enabled links, either
- * directly or indirectly, as streaming. The given pipeline object is assigned to
- * every entity in the pipeline and stored in the media_entity pipe field.
- *
- * Calls to this function can be nested, in which case the same number of
- * media_entity_pipeline_stop() calls will be required to stop streaming. The
- * pipeline pointer must be identical for all nested calls to
- * media_entity_pipeline_start().
- */
__must_check int media_entity_pipeline_start(struct media_entity *entity,
struct media_pipeline *pipe)
{
- struct media_device *mdev = entity->parent;
- struct media_entity_graph graph;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_entity_graph *graph = &pipe->graph;
struct media_entity *entity_err = entity;
+ struct media_link *link;
int ret;
mutex_lock(&mdev->graph_mutex);
- media_entity_graph_walk_start(&graph, entity);
+ if (!pipe->streaming_count++) {
+ ret = media_entity_graph_walk_init(&pipe->graph, mdev);
+ if (ret)
+ goto error_graph_walk_start;
+ }
+
+ media_entity_graph_walk_start(&pipe->graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
+ while ((entity = media_entity_graph_walk_next(graph))) {
DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
- unsigned int i;
entity->stream_count++;
- WARN_ON(entity->pipe && entity->pipe != pipe);
+
+ if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
+ ret = -EBUSY;
+ goto error;
+ }
+
entity->pipe = pipe;
/* Already streaming --- no need to check. */
@@ -253,8 +391,7 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
bitmap_zero(active, entity->num_pads);
bitmap_fill(has_no_links, entity->num_pads);
- for (i = 0; i < entity->num_links; i++) {
- struct media_link *link = &entity->links[i];
+ list_for_each_entry(link, &entity->links, list) {
struct media_pad *pad = link->sink->entity == entity
? link->sink : link->source;
@@ -280,7 +417,7 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
ret = entity->ops->link_validate(link);
if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(entity->parent->dev,
+ dev_dbg(entity->graph_obj.mdev->dev,
"link validation failed for \"%s\":%u -> \"%s\":%u, error %d\n",
link->source->entity->name,
link->source->index,
@@ -294,7 +431,7 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
if (!bitmap_full(active, entity->num_pads)) {
ret = -EPIPE;
- dev_dbg(entity->parent->dev,
+ dev_dbg(entity->graph_obj.mdev->dev,
"\"%s\":%u must be connected by an enabled link\n",
entity->name,
(unsigned)find_first_zero_bit(
@@ -312,9 +449,9 @@ error:
* Link validation on graph failed. We revert what we did and
* return the error.
*/
- media_entity_graph_walk_start(&graph, entity_err);
+ media_entity_graph_walk_start(graph, entity_err);
- while ((entity_err = media_entity_graph_walk_next(&graph))) {
+ while ((entity_err = media_entity_graph_walk_next(graph))) {
entity_err->stream_count--;
if (entity_err->stream_count == 0)
entity_err->pipe = NULL;
@@ -327,39 +464,36 @@ error:
break;
}
+error_graph_walk_start:
+ if (!--pipe->streaming_count)
+ media_entity_graph_walk_cleanup(graph);
+
mutex_unlock(&mdev->graph_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
-/**
- * media_entity_pipeline_stop - Mark a pipeline as not streaming
- * @entity: Starting entity
- *
- * Mark all entities connected to a given entity through enabled links, either
- * directly or indirectly, as not streaming. The media_entity pipe field is
- * reset to NULL.
- *
- * If multiple calls to media_entity_pipeline_start() have been made, the same
- * number of calls to this function are required to mark the pipeline as not
- * streaming.
- */
void media_entity_pipeline_stop(struct media_entity *entity)
{
- struct media_device *mdev = entity->parent;
- struct media_entity_graph graph;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_entity_graph *graph = &entity->pipe->graph;
+ struct media_pipeline *pipe = entity->pipe;
mutex_lock(&mdev->graph_mutex);
- media_entity_graph_walk_start(&graph, entity);
+ WARN_ON(!pipe->streaming_count);
+ media_entity_graph_walk_start(graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
+ while ((entity = media_entity_graph_walk_next(graph))) {
entity->stream_count--;
if (entity->stream_count == 0)
entity->pipe = NULL;
}
+ if (!--pipe->streaming_count)
+ media_entity_graph_walk_cleanup(graph);
+
mutex_unlock(&mdev->graph_mutex);
}
EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
@@ -368,44 +502,26 @@ EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
* Module use count
*/
-/*
- * media_entity_get - Get a reference to the parent module
- * @entity: The entity
- *
- * Get a reference to the parent media device module.
- *
- * The function will return immediately if @entity is NULL.
- *
- * Return a pointer to the entity on success or NULL on failure.
- */
struct media_entity *media_entity_get(struct media_entity *entity)
{
if (entity == NULL)
return NULL;
- if (entity->parent->dev &&
- !try_module_get(entity->parent->dev->driver->owner))
+ if (entity->graph_obj.mdev->dev &&
+ !try_module_get(entity->graph_obj.mdev->dev->driver->owner))
return NULL;
return entity;
}
EXPORT_SYMBOL_GPL(media_entity_get);
-/*
- * media_entity_put - Release the reference to the parent module
- * @entity: The entity
- *
- * Release the reference count acquired by media_entity_get().
- *
- * The function will return immediately if @entity is NULL.
- */
void media_entity_put(struct media_entity *entity)
{
if (entity == NULL)
return;
- if (entity->parent->dev)
- module_put(entity->parent->dev->driver->owner);
+ if (entity->graph_obj.mdev->dev)
+ module_put(entity->graph_obj.mdev->dev->driver->owner);
}
EXPORT_SYMBOL_GPL(media_entity_put);
@@ -413,29 +529,52 @@ EXPORT_SYMBOL_GPL(media_entity_put);
* Links management
*/
-static struct media_link *media_entity_add_link(struct media_entity *entity)
+static struct media_link *media_add_link(struct list_head *head)
{
- if (entity->num_links >= entity->max_links) {
- struct media_link *links = entity->links;
- unsigned int max_links = entity->max_links + 2;
- unsigned int i;
+ struct media_link *link;
+
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (link == NULL)
+ return NULL;
- links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
- if (links == NULL)
- return NULL;
+ list_add_tail(&link->list, head);
- for (i = 0; i < entity->num_links; i++)
- links[i].reverse->reverse = &links[i];
+ return link;
+}
- entity->max_links = max_links;
- entity->links = links;
- }
+static void __media_entity_remove_link(struct media_entity *entity,
+ struct media_link *link)
+{
+ struct media_link *rlink, *tmp;
+ struct media_entity *remote;
+
+ if (link->source->entity == entity)
+ remote = link->sink->entity;
+ else
+ remote = link->source->entity;
- return &entity->links[entity->num_links++];
+ list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
+ if (rlink != link->reverse)
+ continue;
+
+ if (link->source->entity == entity)
+ remote->num_backlinks--;
+
+ /* Remove the remote link */
+ list_del(&rlink->list);
+ media_gobj_destroy(&rlink->graph_obj);
+ kfree(rlink);
+
+ if (--remote->num_links == 0)
+ break;
+ }
+ list_del(&link->list);
+ media_gobj_destroy(&link->graph_obj);
+ kfree(link);
}
int
-media_entity_create_link(struct media_entity *source, u16 source_pad,
+media_create_pad_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags)
{
struct media_link *link;
@@ -445,68 +584,118 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
BUG_ON(source_pad >= source->num_pads);
BUG_ON(sink_pad >= sink->num_pads);
- link = media_entity_add_link(source);
+ link = media_add_link(&source->links);
if (link == NULL)
return -ENOMEM;
link->source = &source->pads[source_pad];
link->sink = &sink->pads[sink_pad];
- link->flags = flags;
+ link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
+
+ /* Initialize graph object embedded at the new link */
+ media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
+ &link->graph_obj);
/* Create the backlink. Backlinks are used to help graph traversal and
* are not reported to userspace.
*/
- backlink = media_entity_add_link(sink);
+ backlink = media_add_link(&sink->links);
if (backlink == NULL) {
- source->num_links--;
+ __media_entity_remove_link(source, link);
return -ENOMEM;
}
backlink->source = &source->pads[source_pad];
backlink->sink = &sink->pads[sink_pad];
backlink->flags = flags;
+ backlink->is_backlink = true;
+
+ /* Initialize graph object embedded at the new link */
+ media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
+ &backlink->graph_obj);
link->reverse = backlink;
backlink->reverse = link;
sink->num_backlinks++;
+ sink->num_links++;
+ source->num_links++;
return 0;
}
-EXPORT_SYMBOL_GPL(media_entity_create_link);
-
-void __media_entity_remove_links(struct media_entity *entity)
+EXPORT_SYMBOL_GPL(media_create_pad_link);
+
+int media_create_pad_links(const struct media_device *mdev,
+ const u32 source_function,
+ struct media_entity *source,
+ const u16 source_pad,
+ const u32 sink_function,
+ struct media_entity *sink,
+ const u16 sink_pad,
+ u32 flags,
+ const bool allow_both_undefined)
{
- unsigned int i;
-
- for (i = 0; i < entity->num_links; i++) {
- struct media_link *link = &entity->links[i];
- struct media_entity *remote;
- unsigned int r = 0;
-
- if (link->source->entity == entity)
- remote = link->sink->entity;
- else
- remote = link->source->entity;
-
- while (r < remote->num_links) {
- struct media_link *rlink = &remote->links[r];
+ struct media_entity *entity;
+ unsigned function;
+ int ret;
- if (rlink != link->reverse) {
- r++;
+ /* Trivial case: 1:1 relation */
+ if (source && sink)
+ return media_create_pad_link(source, source_pad,
+ sink, sink_pad, flags);
+
+ /* Worse case scenario: n:n relation */
+ if (!source && !sink) {
+ if (!allow_both_undefined)
+ return 0;
+ media_device_for_each_entity(source, mdev) {
+ if (source->function != source_function)
continue;
+ media_device_for_each_entity(sink, mdev) {
+ if (sink->function != sink_function)
+ continue;
+ ret = media_create_pad_link(source, source_pad,
+ sink, sink_pad,
+ flags);
+ if (ret)
+ return ret;
+ flags &= ~(MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
}
+ }
+ return 0;
+ }
- if (link->source->entity == entity)
- remote->num_backlinks--;
+ /* Handle 1:n and n:1 cases */
+ if (source)
+ function = sink_function;
+ else
+ function = source_function;
- if (--remote->num_links == 0)
- break;
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function != function)
+ continue;
- /* Insert last entry in place of the dropped link. */
- *rlink = remote->links[remote->num_links];
- }
+ if (source)
+ ret = media_create_pad_link(source, source_pad,
+ entity, sink_pad, flags);
+ else
+ ret = media_create_pad_link(entity, source_pad,
+ sink, sink_pad, flags);
+ if (ret)
+ return ret;
+ flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
}
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_create_pad_links);
+
+void __media_entity_remove_links(struct media_entity *entity)
+{
+ struct media_link *link, *tmp;
+
+ list_for_each_entry_safe(link, tmp, &entity->links, list)
+ __media_entity_remove_link(entity, link);
entity->num_links = 0;
entity->num_backlinks = 0;
@@ -515,13 +704,15 @@ EXPORT_SYMBOL_GPL(__media_entity_remove_links);
void media_entity_remove_links(struct media_entity *entity)
{
+ struct media_device *mdev = entity->graph_obj.mdev;
+
/* Do nothing if the entity is not registered. */
- if (entity->parent == NULL)
+ if (mdev == NULL)
return;
- mutex_lock(&entity->parent->graph_mutex);
+ spin_lock(&mdev->lock);
__media_entity_remove_links(entity);
- mutex_unlock(&entity->parent->graph_mutex);
+ spin_unlock(&mdev->lock);
}
EXPORT_SYMBOL_GPL(media_entity_remove_links);
@@ -549,20 +740,6 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
return 0;
}
-/**
- * __media_entity_setup_link - Configure a media link
- * @link: The link being configured
- * @flags: Link configuration flags
- *
- * The bulk of link setup is handled by the two entities connected through the
- * link. This function notifies both entities of the link configuration change.
- *
- * If the link is immutable or if the current and new configuration are
- * identical, return immediately.
- *
- * The user is expected to hold link->source->parent->mutex. If not,
- * media_entity_setup_link() should be used instead.
- */
int __media_entity_setup_link(struct media_link *link, u32 flags)
{
const u32 mask = MEDIA_LNK_FL_ENABLED;
@@ -590,7 +767,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
(source->stream_count || sink->stream_count))
return -EBUSY;
- mdev = source->parent;
+ mdev = source->graph_obj.mdev;
if (mdev->link_notify) {
ret = mdev->link_notify(link, flags,
@@ -611,31 +788,20 @@ int media_entity_setup_link(struct media_link *link, u32 flags)
{
int ret;
- mutex_lock(&link->source->entity->parent->graph_mutex);
+ mutex_lock(&link->graph_obj.mdev->graph_mutex);
ret = __media_entity_setup_link(link, flags);
- mutex_unlock(&link->source->entity->parent->graph_mutex);
+ mutex_unlock(&link->graph_obj.mdev->graph_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(media_entity_setup_link);
-/**
- * media_entity_find_link - Find a link between two pads
- * @source: Source pad
- * @sink: Sink pad
- *
- * Return a pointer to the link between the two entities. If no such link
- * exists, return NULL.
- */
struct media_link *
media_entity_find_link(struct media_pad *source, struct media_pad *sink)
{
struct media_link *link;
- unsigned int i;
-
- for (i = 0; i < source->entity->num_links; ++i) {
- link = &source->entity->links[i];
+ list_for_each_entry(link, &source->entity->links, list) {
if (link->source->entity == source->entity &&
link->source->index == source->index &&
link->sink->entity == sink->entity &&
@@ -647,23 +813,11 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink)
}
EXPORT_SYMBOL_GPL(media_entity_find_link);
-/**
- * media_entity_remote_pad - Find the pad at the remote end of a link
- * @pad: Pad at the local end of the link
- *
- * Search for a remote pad connected to the given pad by iterating over all
- * links originating or terminating at that pad until an enabled link is found.
- *
- * Return a pointer to the pad at the remote end of the first found enabled
- * link, or NULL if no enabled link has been found.
- */
struct media_pad *media_entity_remote_pad(struct media_pad *pad)
{
- unsigned int i;
-
- for (i = 0; i < pad->entity->num_links; i++) {
- struct media_link *link = &pad->entity->links[i];
+ struct media_link *link;
+ list_for_each_entry(link, &pad->entity->links, list) {
if (!(link->flags & MEDIA_LNK_FL_ENABLED))
continue;
@@ -678,3 +832,113 @@ struct media_pad *media_entity_remote_pad(struct media_pad *pad)
}
EXPORT_SYMBOL_GPL(media_entity_remote_pad);
+
+static void media_interface_init(struct media_device *mdev,
+ struct media_interface *intf,
+ u32 gobj_type,
+ u32 intf_type, u32 flags)
+{
+ intf->type = intf_type;
+ intf->flags = flags;
+ INIT_LIST_HEAD(&intf->links);
+
+ media_gobj_create(mdev, gobj_type, &intf->graph_obj);
+}
+
+/* Functions related to the media interface via device nodes */
+
+struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
+ u32 type, u32 flags,
+ u32 major, u32 minor)
+{
+ struct media_intf_devnode *devnode;
+
+ devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
+ if (!devnode)
+ return NULL;
+
+ devnode->major = major;
+ devnode->minor = minor;
+
+ media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
+ type, flags);
+
+ return devnode;
+}
+EXPORT_SYMBOL_GPL(media_devnode_create);
+
+void media_devnode_remove(struct media_intf_devnode *devnode)
+{
+ media_remove_intf_links(&devnode->intf);
+ media_gobj_destroy(&devnode->intf.graph_obj);
+ kfree(devnode);
+}
+EXPORT_SYMBOL_GPL(media_devnode_remove);
+
+struct media_link *media_create_intf_link(struct media_entity *entity,
+ struct media_interface *intf,
+ u32 flags)
+{
+ struct media_link *link;
+
+ link = media_add_link(&intf->links);
+ if (link == NULL)
+ return NULL;
+
+ link->intf = intf;
+ link->entity = entity;
+ link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
+
+ /* Initialize graph object embedded at the new link */
+ media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
+ &link->graph_obj);
+
+ return link;
+}
+EXPORT_SYMBOL_GPL(media_create_intf_link);
+
+void __media_remove_intf_link(struct media_link *link)
+{
+ list_del(&link->list);
+ media_gobj_destroy(&link->graph_obj);
+ kfree(link);
+}
+EXPORT_SYMBOL_GPL(__media_remove_intf_link);
+
+void media_remove_intf_link(struct media_link *link)
+{
+ struct media_device *mdev = link->graph_obj.mdev;
+
+ /* Do nothing if the intf is not registered. */
+ if (mdev == NULL)
+ return;
+
+ spin_lock(&mdev->lock);
+ __media_remove_intf_link(link);
+ spin_unlock(&mdev->lock);
+}
+EXPORT_SYMBOL_GPL(media_remove_intf_link);
+
+void __media_remove_intf_links(struct media_interface *intf)
+{
+ struct media_link *link, *tmp;
+
+ list_for_each_entry_safe(link, tmp, &intf->links, list)
+ __media_remove_intf_link(link);
+
+}
+EXPORT_SYMBOL_GPL(__media_remove_intf_links);
+
+void media_remove_intf_links(struct media_interface *intf)
+{
+ struct media_device *mdev = intf->graph_obj.mdev;
+
+ /* Do nothing if the intf is not registered. */
+ if (mdev == NULL)
+ return;
+
+ spin_lock(&mdev->lock);
+ __media_remove_intf_links(intf);
+ spin_unlock(&mdev->lock);
+}
+EXPORT_SYMBOL_GPL(media_remove_intf_links);
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
index c5cc14ef8347..da8b414fd824 100644
--- a/drivers/media/pci/bt8xx/dst_ca.c
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -705,7 +705,8 @@ struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_
struct dvb_device *dvbdev;
dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
- if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
+ if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst,
+ DVB_DEVICE_CA, 0) == 0) {
dst->dst_ca = dvbdev;
return dst->dst_ca;
}
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index fba5b40a869c..9d5b314142f1 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -1065,7 +1065,7 @@ static int ddb_ci_attach(struct ddb_port *port)
port->en, 0, 1);
ret = dvb_register_device(&port->output->adap, &port->output->dev,
&dvbdev_ci, (void *) port->output,
- DVB_DEVICE_SEC);
+ DVB_DEVICE_SEC, 0);
return ret;
}
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
index 81e1a5e26efb..525ebfefeee8 100644
--- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
@@ -387,7 +387,7 @@ static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev,
vb2_dvb_alloc_frontend(
&ndev->frontends[num], 3) == NULL) {
dev_dbg(&ndev->pci_dev->dev,
- "%s(): unable to to alllocate vb2_dvb_frontend\n",
+ "%s(): unable to allocate vb2_dvb_frontend\n",
__func__);
return -ENOMEM;
}
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 1b92d836a564..4e924e2d1638 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -1513,7 +1513,7 @@ static int init_channel(struct ngene_channel *chan)
set_transfer(&chan->dev->channel[2], 1);
dvb_register_device(adapter, &chan->ci_dev,
&ngene_dvbdev_ci, (void *) chan,
- DVB_DEVICE_SEC);
+ DVB_DEVICE_SEC, 0);
if (!chan->ci_dev)
goto err;
}
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 5e18b6796ed9..a69dc6a0752b 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -1358,7 +1358,7 @@ static int av7110_register(struct av7110 *av7110)
#ifdef CONFIG_DVB_AV7110_OSD
dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev,
- &dvbdev_osd, av7110, DVB_DEVICE_OSD);
+ &dvbdev_osd, av7110, DVB_DEVICE_OSD, 0);
#endif
dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index 6fc748e22017..26c5696c193b 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -1594,10 +1594,10 @@ int av7110_av_register(struct av7110 *av7110)
memset(&av7110->video_size, 0, sizeof (video_size_t));
dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,
- &dvbdev_video, av7110, DVB_DEVICE_VIDEO);
+ &dvbdev_video, av7110, DVB_DEVICE_VIDEO, 0);
dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev,
- &dvbdev_audio, av7110, DVB_DEVICE_AUDIO);
+ &dvbdev_audio, av7110, DVB_DEVICE_AUDIO, 0);
return 0;
}
diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c
index bc4c65ffd4b9..96a130fb4595 100644
--- a/drivers/media/pci/ttpci/av7110_ca.c
+++ b/drivers/media/pci/ttpci/av7110_ca.c
@@ -378,7 +378,7 @@ static struct dvb_device dvbdev_ca = {
int av7110_ca_register(struct av7110 *av7110)
{
return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev,
- &dvbdev_ca, av7110, DVB_DEVICE_CA);
+ &dvbdev_ca, av7110, DVB_DEVICE_CA, 0);
}
void av7110_ca_unregister(struct av7110 *av7110)
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
index b6716c57b5db..b90f5bb15517 100644
--- a/drivers/media/platform/exynos4-is/common.c
+++ b/drivers/media/platform/exynos4-is/common.c
@@ -22,8 +22,7 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity)
while (pad->flags & MEDIA_PAD_FL_SINK) {
/* source pad */
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
sd = media_entity_to_v4l2_subdev(pad->entity);
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 0d549a6c8a13..bf47d3b9cbe7 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -1136,8 +1136,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
}
}
- if (src_pad == NULL ||
- media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!src_pad || !is_media_entity_v4l2_subdev(src_pad->entity))
break;
/* Don't call FIMC subdev operation to avoid nested locking */
@@ -1392,7 +1391,7 @@ static int fimc_link_setup(struct media_entity *entity,
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct v4l2_subdev *sensor;
- if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!is_media_entity_v4l2_subdev(remote->entity))
return -EINVAL;
if (WARN_ON(fimc == NULL))
@@ -1800,7 +1799,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
vid_cap->wb_fmt.code = fmt->mbus_code;
vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
+ ret = media_entity_pads_init(&vfd->entity, 1, &vid_cap->vd_pad);
if (ret)
goto err_free_ctx;
@@ -1892,8 +1891,8 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK;
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK;
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
- fimc->vid_cap.sd_pads, 0);
+ ret = media_entity_pads_init(&sd->entity, FIMC_SD_PADS_NUM,
+ fimc->vid_cap.sd_pads);
if (ret)
return ret;
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index 0dd22ec66694..bf9261eb57a1 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -287,7 +287,7 @@ static int isp_video_open(struct file *file)
goto rel_fh;
if (v4l2_fh_is_singular_file(file)) {
- mutex_lock(&me->parent->graph_mutex);
+ mutex_lock(&me->graph_obj.mdev->graph_mutex);
ret = fimc_pipeline_call(ve, open, me, true);
@@ -295,7 +295,7 @@ static int isp_video_open(struct file *file)
if (ret == 0)
me->use_count++;
- mutex_unlock(&me->parent->graph_mutex);
+ mutex_unlock(&me->graph_obj.mdev->graph_mutex);
}
if (!ret)
goto unlock;
@@ -311,7 +311,7 @@ static int isp_video_release(struct file *file)
struct fimc_isp *isp = video_drvdata(file);
struct fimc_is_video *ivc = &isp->video_capture;
struct media_entity *entity = &ivc->ve.vdev.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
mutex_lock(&isp->video_lock);
@@ -466,8 +466,7 @@ static int isp_video_pipeline_validate(struct fimc_isp *isp)
/* Retrieve format at the source pad */
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
sd = media_entity_to_v4l2_subdev(pad->entity);
@@ -617,7 +616,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp,
vdev->lock = &isp->video_lock;
iv->pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&vdev->entity, 1, &iv->pad, 0);
+ ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 5d78f5716f3b..293b807020c4 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -708,8 +708,8 @@ int fimc_isp_subdev_create(struct fimc_isp *isp)
isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE;
isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, FIMC_ISP_SD_PADS_NUM,
- isp->subdev_pads, 0);
+ ret = media_entity_pads_init(&sd->entity, FIMC_ISP_SD_PADS_NUM,
+ isp->subdev_pads);
if (ret)
return ret;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 639ee710499e..e85649147dc8 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -494,7 +494,7 @@ static int fimc_lite_open(struct file *file)
atomic_read(&fimc->out_path) != FIMC_IO_DMA)
goto unlock;
- mutex_lock(&me->parent->graph_mutex);
+ mutex_lock(&me->graph_obj.mdev->graph_mutex);
ret = fimc_pipeline_call(&fimc->ve, open, me, true);
@@ -502,7 +502,7 @@ static int fimc_lite_open(struct file *file)
if (ret == 0)
me->use_count++;
- mutex_unlock(&me->parent->graph_mutex);
+ mutex_unlock(&me->graph_obj.mdev->graph_mutex);
if (!ret) {
fimc_lite_clear_event_counters(fimc);
@@ -535,9 +535,9 @@ static int fimc_lite_release(struct file *file)
fimc_pipeline_call(&fimc->ve, close);
clear_bit(ST_FLITE_IN_USE, &fimc->state);
- mutex_lock(&entity->parent->graph_mutex);
+ mutex_lock(&entity->graph_obj.mdev->graph_mutex);
entity->use_count--;
- mutex_unlock(&entity->parent->graph_mutex);
+ mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
}
_vb2_fop_release(file, NULL);
@@ -808,8 +808,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
}
/* Retrieve format at the source pad */
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
sd = media_entity_to_v4l2_subdev(pad->entity);
@@ -982,7 +981,6 @@ static int fimc_lite_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
- unsigned int remote_ent_type = media_entity_type(remote->entity);
int ret = 0;
if (WARN_ON(fimc == NULL))
@@ -994,7 +992,7 @@ static int fimc_lite_link_setup(struct media_entity *entity,
switch (local->index) {
case FLITE_SD_PAD_SINK:
- if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) {
+ if (!is_media_entity_v4l2_subdev(remote->entity)) {
ret = -EINVAL;
break;
}
@@ -1012,7 +1010,7 @@ static int fimc_lite_link_setup(struct media_entity *entity,
case FLITE_SD_PAD_SOURCE_DMA:
if (!(flags & MEDIA_LNK_FL_ENABLED))
atomic_set(&fimc->out_path, FIMC_IO_NONE);
- else if (remote_ent_type == MEDIA_ENT_T_DEVNODE)
+ else if (is_media_entity_v4l2_io(remote->entity))
atomic_set(&fimc->out_path, FIMC_IO_DMA);
else
ret = -EINVAL;
@@ -1021,7 +1019,7 @@ static int fimc_lite_link_setup(struct media_entity *entity,
case FLITE_SD_PAD_SOURCE_ISP:
if (!(flags & MEDIA_LNK_FL_ENABLED))
atomic_set(&fimc->out_path, FIMC_IO_NONE);
- else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
+ else if (is_media_entity_v4l2_subdev(remote->entity))
atomic_set(&fimc->out_path, FIMC_IO_ISP);
else
ret = -EINVAL;
@@ -1316,7 +1314,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
return ret;
fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
+ ret = media_entity_pads_init(&vfd->entity, 1, &fimc->vd_pad);
if (ret < 0)
return ret;
@@ -1430,8 +1428,8 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
fimc->subdev_pads[FLITE_SD_PAD_SOURCE_DMA].flags = MEDIA_PAD_FL_SOURCE;
fimc->subdev_pads[FLITE_SD_PAD_SOURCE_ISP].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, FLITE_SD_PADS_NUM,
- fimc->subdev_pads, 0);
+ ret = media_entity_pads_init(&sd->entity, FLITE_SD_PADS_NUM,
+ fimc->subdev_pads);
if (ret)
return ret;
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 5aa857c7b631..55ec4c99d484 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -739,7 +739,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc,
return PTR_ERR(fimc->m2m.m2m_dev);
}
- ret = media_entity_init(&vfd->entity, 0, NULL, 0);
+ ret = media_entity_pads_init(&vfd->entity, 0, NULL);
if (ret)
goto err_me;
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 9481ce3201a2..f3b2dd30ec77 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -88,8 +88,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
break;
}
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
sd = media_entity_to_v4l2_subdev(pad->entity);
@@ -729,7 +728,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;
sink = &fmd->fimc[i]->vid_cap.subdev.entity;
- ret = media_entity_create_link(source, pad, sink,
+ ret = media_create_pad_link(source, pad, sink,
FIMC_SD_PAD_SINK_CAM, flags);
if (ret)
return ret;
@@ -749,7 +748,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
continue;
sink = &fmd->fimc_lite[i]->subdev.entity;
- ret = media_entity_create_link(source, pad, sink,
+ ret = media_create_pad_link(source, pad, sink,
FLITE_SD_PAD_SINK, 0);
if (ret)
return ret;
@@ -781,13 +780,13 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
source = &fimc->subdev.entity;
sink = &fimc->ve.vdev.entity;
/* FIMC-LITE's subdev and video node */
- ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
+ ret = media_create_pad_link(source, FLITE_SD_PAD_SOURCE_DMA,
sink, 0, 0);
if (ret)
break;
/* Link from FIMC-LITE to IS-ISP subdev */
sink = &fmd->fimc_is->isp.subdev.entity;
- ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP,
+ ret = media_create_pad_link(source, FLITE_SD_PAD_SOURCE_ISP,
sink, 0, 0);
if (ret)
break;
@@ -811,7 +810,7 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
/* Link from FIMC-IS-ISP subdev to FIMC */
sink = &fmd->fimc[i]->vid_cap.subdev.entity;
- ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO,
+ ret = media_create_pad_link(source, FIMC_ISP_SD_PAD_SRC_FIFO,
sink, FIMC_SD_PAD_SINK_FIFO, 0);
if (ret)
return ret;
@@ -824,7 +823,7 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
if (sink->num_pads == 0)
return 0;
- return media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_DMA,
+ return media_create_pad_link(source, FIMC_ISP_SD_PAD_SRC_DMA,
sink, 0, 0);
}
@@ -873,7 +872,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
return -EINVAL;
pad = sensor->entity.num_pads - 1;
- ret = media_entity_create_link(&sensor->entity, pad,
+ ret = media_create_pad_link(&sensor->entity, pad,
&csis->entity, CSIS_PAD_SINK,
MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
@@ -927,7 +926,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
source = &fmd->fimc[i]->vid_cap.subdev.entity;
sink = &fmd->fimc[i]->vid_cap.ve.vdev.entity;
- ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+ ret = media_create_pad_link(source, FIMC_SD_PAD_SOURCE,
sink, 0, flags);
if (ret)
break;
@@ -1046,11 +1045,11 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
return ret;
}
-/* Locking: called with entity->parent->graph_mutex mutex held. */
-static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
+/* Locking: called with entity->graph_obj.mdev->graph_mutex mutex held. */
+static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
+ struct media_entity_graph *graph)
{
struct media_entity *entity_err = entity;
- struct media_entity_graph graph;
int ret;
/*
@@ -1059,10 +1058,10 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
* through active links. This is needed as we cannot power on/off the
* subdevs in random order.
*/
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ while ((entity = media_entity_graph_walk_next(graph))) {
+ if (!is_media_entity_v4l2_io(entity))
continue;
ret = __fimc_md_modify_pipeline(entity, enable);
@@ -1072,11 +1071,12 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
}
return 0;
- err:
- media_entity_graph_walk_start(&graph, entity_err);
- while ((entity_err = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(entity_err) != MEDIA_ENT_T_DEVNODE)
+err:
+ media_entity_graph_walk_start(graph, entity_err);
+
+ while ((entity_err = media_entity_graph_walk_next(graph))) {
+ if (!is_media_entity_v4l2_io(entity_err))
continue;
__fimc_md_modify_pipeline(entity_err, !enable);
@@ -1091,21 +1091,29 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
unsigned int notification)
{
+ struct media_entity_graph *graph =
+ &container_of(link->graph_obj.mdev, struct fimc_md,
+ media_dev)->link_setup_graph;
struct media_entity *sink = link->sink->entity;
int ret = 0;
/* Before link disconnection */
if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
+ ret = media_entity_graph_walk_init(graph,
+ link->graph_obj.mdev);
+ if (ret)
+ return ret;
if (!(flags & MEDIA_LNK_FL_ENABLED))
- ret = __fimc_md_modify_pipelines(sink, false);
+ ret = __fimc_md_modify_pipelines(sink, false, graph);
#if 0
else
/* TODO: Link state change validation */
#endif
/* After link activation */
- } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
- (link->flags & MEDIA_LNK_FL_ENABLED)) {
- ret = __fimc_md_modify_pipelines(sink, true);
+ } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH) {
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ ret = __fimc_md_modify_pipelines(sink, true, graph);
+ media_entity_graph_walk_cleanup(graph);
}
return ret ? -EPIPE : 0;
@@ -1314,7 +1322,10 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
unlock:
mutex_unlock(&fmd->media_dev.graph_mutex);
- return ret;
+ if (ret < 0)
+ return ret;
+
+ return media_device_register(&fmd->media_dev);
}
static int fimc_md_probe(struct platform_device *pdev)
@@ -1345,18 +1356,14 @@ static int fimc_md_probe(struct platform_device *pdev)
fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
fmd->user_subdev_api = true;
+ media_device_init(&fmd->media_dev);
+
ret = v4l2_device_register(dev, &fmd->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
return ret;
}
- ret = media_device_register(&fmd->media_dev);
- if (ret < 0) {
- v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
- goto err_v4l2_dev;
- }
-
ret = fimc_md_get_clocks(fmd);
if (ret)
goto err_md;
@@ -1425,8 +1432,7 @@ err_clk:
err_m_ent:
fimc_md_unregister_entities(fmd);
err_md:
- media_device_unregister(&fmd->media_dev);
-err_v4l2_dev:
+ media_device_cleanup(&fmd->media_dev);
v4l2_device_unregister(&fmd->v4l2_dev);
return ret;
}
@@ -1446,6 +1452,7 @@ static int fimc_md_remove(struct platform_device *pdev)
fimc_md_unregister_entities(fmd);
fimc_md_pipelines_free(fmd);
media_device_unregister(&fmd->media_dev);
+ media_device_cleanup(&fmd->media_dev);
fimc_md_put_clocks(fmd);
return 0;
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index 93a96126929b..ed122cb2dd74 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -154,6 +154,7 @@ struct fimc_md {
bool user_subdev_api;
spinlock_t slock;
struct list_head pipelines;
+ struct media_entity_graph link_setup_graph;
};
static inline
@@ -164,8 +165,8 @@ struct fimc_sensor_info *source_to_sensor_info(struct fimc_source_info *si)
static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
{
- return me->parent == NULL ? NULL :
- container_of(me->parent, struct fimc_md, media_dev);
+ return me->graph_obj.mdev == NULL ? NULL :
+ container_of(me->graph_obj.mdev, struct fimc_md, media_dev);
}
static inline struct fimc_md *notifier_to_fimc_md(struct v4l2_async_notifier *n)
@@ -175,12 +176,12 @@ static inline struct fimc_md *notifier_to_fimc_md(struct v4l2_async_notifier *n)
static inline void fimc_md_graph_lock(struct exynos_video_entity *ve)
{
- mutex_lock(&ve->vdev.entity.parent->graph_mutex);
+ mutex_lock(&ve->vdev.entity.graph_obj.mdev->graph_mutex);
}
static inline void fimc_md_graph_unlock(struct exynos_video_entity *ve)
{
- mutex_unlock(&ve->vdev.entity.parent->graph_mutex);
+ mutex_unlock(&ve->vdev.entity.graph_obj.mdev->graph_mutex);
}
int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index ff5dabf24694..ac5e50e595be 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -866,8 +866,8 @@ static int s5pcsis_probe(struct platform_device *pdev)
state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&state->sd.entity,
- CSIS_PADS_NUM, state->pads, 0);
+ ret = media_entity_pads_init(&state->sd.entity,
+ CSIS_PADS_NUM, state->pads);
if (ret < 0)
goto e_clkdis;
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 217d613b0fe7..e8e2db181a7a 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -5,9 +5,9 @@ config VIDEO_OMAP2_VOUT
tristate "OMAP2/OMAP3 V4L2-Display driver"
depends on MMU
depends on ARCH_OMAP2 || ARCH_OMAP3
+ depends on FB_OMAP2
select VIDEOBUF_GEN
select VIDEOBUF_DMA_CONTIG
- select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
select FRAME_VECTOR
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 56e683b19a73..0bcfa553c1aa 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -683,15 +683,15 @@ static irqreturn_t isp_isr(int irq, void *_isp)
*
* Return the total number of users of all video device nodes in the pipeline.
*/
-static int isp_pipeline_pm_use_count(struct media_entity *entity)
+static int isp_pipeline_pm_use_count(struct media_entity *entity,
+ struct media_entity_graph *graph)
{
- struct media_entity_graph graph;
int use = 0;
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+ while ((entity = media_entity_graph_walk_next(graph))) {
+ if (is_media_entity_v4l2_io(entity))
use += entity->use_count;
}
@@ -714,7 +714,7 @@ static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
struct v4l2_subdev *subdev;
int ret;
- subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+ subdev = is_media_entity_v4l2_subdev(entity)
? media_entity_to_v4l2_subdev(entity) : NULL;
if (entity->use_count == 0 && change > 0 && subdev != NULL) {
@@ -742,29 +742,29 @@ static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
*
* Return 0 on success or a negative error code on failure.
*/
-static int isp_pipeline_pm_power(struct media_entity *entity, int change)
+static int isp_pipeline_pm_power(struct media_entity *entity, int change,
+ struct media_entity_graph *graph)
{
- struct media_entity_graph graph;
struct media_entity *first = entity;
int ret = 0;
if (!change)
return 0;
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while (!ret && (entity = media_entity_graph_walk_next(&graph)))
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ while (!ret && (entity = media_entity_graph_walk_next(graph)))
+ if (is_media_entity_v4l2_subdev(entity))
ret = isp_pipeline_pm_power_one(entity, change);
if (!ret)
- return 0;
+ return ret;
- media_entity_graph_walk_start(&graph, first);
+ media_entity_graph_walk_start(graph, first);
- while ((first = media_entity_graph_walk_next(&graph))
+ while ((first = media_entity_graph_walk_next(graph))
&& first != entity)
- if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+ if (is_media_entity_v4l2_subdev(first))
isp_pipeline_pm_power_one(first, -change);
return ret;
@@ -782,23 +782,24 @@ static int isp_pipeline_pm_power(struct media_entity *entity, int change)
* off is assumed to never fail. No failure can occur when the use parameter is
* set to 0.
*/
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use,
+ struct media_entity_graph *graph)
{
int change = use ? 1 : -1;
int ret;
- mutex_lock(&entity->parent->graph_mutex);
+ mutex_lock(&entity->graph_obj.mdev->graph_mutex);
/* Apply use count to node. */
entity->use_count += change;
WARN_ON(entity->use_count < 0);
/* Apply power change to connected non-nodes. */
- ret = isp_pipeline_pm_power(entity, change);
+ ret = isp_pipeline_pm_power(entity, change, graph);
if (ret < 0)
entity->use_count -= change;
- mutex_unlock(&entity->parent->graph_mutex);
+ mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
return ret;
}
@@ -820,35 +821,49 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
unsigned int notification)
{
+ struct media_entity_graph *graph =
+ &container_of(link->graph_obj.mdev, struct isp_device,
+ media_dev)->pm_count_graph;
struct media_entity *source = link->source->entity;
struct media_entity *sink = link->sink->entity;
- int source_use = isp_pipeline_pm_use_count(source);
- int sink_use = isp_pipeline_pm_use_count(sink);
- int ret;
+ int source_use;
+ int sink_use;
+ int ret = 0;
+
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
+ ret = media_entity_graph_walk_init(graph,
+ link->graph_obj.mdev);
+ if (ret)
+ return ret;
+ }
+
+ source_use = isp_pipeline_pm_use_count(source, graph);
+ sink_use = isp_pipeline_pm_use_count(sink, graph);
if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
!(flags & MEDIA_LNK_FL_ENABLED)) {
/* Powering off entities is assumed to never fail. */
- isp_pipeline_pm_power(source, -sink_use);
- isp_pipeline_pm_power(sink, -source_use);
+ isp_pipeline_pm_power(source, -sink_use, graph);
+ isp_pipeline_pm_power(sink, -source_use, graph);
return 0;
}
if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
(flags & MEDIA_LNK_FL_ENABLED)) {
- ret = isp_pipeline_pm_power(source, sink_use);
+ ret = isp_pipeline_pm_power(source, sink_use, graph);
if (ret < 0)
return ret;
- ret = isp_pipeline_pm_power(sink, source_use);
+ ret = isp_pipeline_pm_power(sink, source_use, graph);
if (ret < 0)
- isp_pipeline_pm_power(source, -sink_use);
-
- return ret;
+ isp_pipeline_pm_power(source, -sink_use, graph);
}
- return 0;
+ if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH)
+ media_entity_graph_walk_cleanup(graph);
+
+ return ret;
}
/* -----------------------------------------------------------------------------
@@ -881,7 +896,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
* starting entities if the pipeline won't start anyway (those entities
* would then likely fail to stop, making the problem worse).
*/
- if (pipe->entities & isp->crashed)
+ if (media_entity_enum_intersects(&pipe->ent_enum, &isp->crashed))
return -EIO;
spin_lock_irqsave(&pipe->lock, flags);
@@ -897,8 +912,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
break;
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -987,8 +1001,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
break;
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -1028,7 +1041,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
isp->stop_failure = true;
if (subdev == &isp->isp_prev.subdev)
- isp->crashed |= 1U << subdev->entity.id;
+ media_entity_enum_set(&isp->crashed,
+ &subdev->entity);
failure = -ETIMEDOUT;
}
}
@@ -1234,7 +1248,7 @@ static int isp_reset(struct isp_device *isp)
}
isp->stop_failure = false;
- isp->crashed = 0;
+ media_entity_enum_zero(&isp->crashed);
return 0;
}
@@ -1645,7 +1659,8 @@ static void __omap3isp_put(struct isp_device *isp, bool save_ctx)
/* Reset the ISP if an entity has failed to stop. This is the
* only way to recover from such conditions.
*/
- if (isp->crashed || isp->stop_failure)
+ if (!media_entity_enum_empty(&isp->crashed) ||
+ isp->stop_failure)
isp_reset(isp);
isp_disable_clocks(isp);
}
@@ -1792,6 +1807,7 @@ static void isp_unregister_entities(struct isp_device *isp)
v4l2_device_unregister(&isp->v4l2_dev);
media_device_unregister(&isp->media_dev);
+ media_device_cleanup(&isp->media_dev);
}
static int isp_link_entity(
@@ -1862,7 +1878,7 @@ static int isp_link_entity(
return -EINVAL;
}
- return media_entity_create_link(entity, i, input, pad, flags);
+ return media_create_pad_link(entity, i, input, pad, flags);
}
static int isp_register_entities(struct isp_device *isp)
@@ -1874,12 +1890,7 @@ static int isp_register_entities(struct isp_device *isp)
sizeof(isp->media_dev.model));
isp->media_dev.hw_revision = isp->revision;
isp->media_dev.link_notify = isp_pipeline_link_notify;
- ret = media_device_register(&isp->media_dev);
- if (ret < 0) {
- dev_err(isp->dev, "%s: Media device registration failed (%d)\n",
- __func__, ret);
- return ret;
- }
+ media_device_init(&isp->media_dev);
isp->v4l2_dev.mdev = &isp->media_dev;
ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
@@ -1930,6 +1941,118 @@ done:
return ret;
}
+/*
+ * isp_create_links() - Create links for internal and external ISP entities
+ * @isp : Pointer to ISP device
+ *
+ * This function creates all links between ISP internal and external entities.
+ *
+ * Return: A negative error code on failure or zero on success. Possible error
+ * codes are those returned by media_create_pad_link().
+ */
+static int isp_create_links(struct isp_device *isp)
+{
+ int ret;
+
+ /* Create links between entities and video nodes. */
+ ret = media_create_pad_link(
+ &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+ &isp->isp_csi2a.video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccp2.video_in.video.entity, 0,
+ &isp->isp_ccp2.subdev.entity, CCP2_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+ &isp->isp_ccdc.video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_prev.video_in.video.entity, 0,
+ &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+ &isp->isp_prev.video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_res.video_in.video.entity, 0,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_res.subdev.entity, RESZ_PAD_SOURCE,
+ &isp->isp_res.video_out.video.entity, 0, 0);
+
+ if (ret < 0)
+ return ret;
+
+ /* Create links between entities. */
+ ret = media_create_pad_link(
+ &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_aewb.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_af.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+ &isp->isp_hist.subdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static void isp_cleanup_modules(struct isp_device *isp)
{
omap3isp_h3a_aewb_cleanup(isp);
@@ -2000,62 +2123,8 @@ static int isp_initialize_modules(struct isp_device *isp)
goto error_h3a_af;
}
- /* Connect the submodules. */
- ret = media_entity_create_link(
- &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
- &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
- &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_aewb.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_af.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
- &isp->isp_hist.subdev.entity, 0,
- MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap3isp_h3a_af_cleanup(isp);
error_h3a_af:
omap3isp_h3a_aewb_cleanup(isp);
error_h3a_aewb:
@@ -2149,6 +2218,8 @@ static int isp_remove(struct platform_device *pdev)
isp_detach_iommu(isp);
__omap3isp_put(isp, false);
+ media_entity_enum_cleanup(&isp->crashed);
+
return 0;
}
@@ -2278,28 +2349,43 @@ static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
{
- struct isp_device *isp = container_of(async, struct isp_device,
- notifier);
struct isp_async_subdev *isd =
container_of(asd, struct isp_async_subdev, asd);
- int ret;
-
- ret = isp_link_entity(isp, &subdev->entity, isd->bus.interface);
- if (ret < 0)
- return ret;
isd->sd = subdev;
isd->sd->host_priv = &isd->bus;
- return ret;
+ return 0;
}
static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
{
struct isp_device *isp = container_of(async, struct isp_device,
notifier);
+ struct v4l2_device *v4l2_dev = &isp->v4l2_dev;
+ struct v4l2_subdev *sd;
+ struct isp_bus_cfg *bus;
+ int ret;
+
+ ret = media_entity_enum_init(&isp->crashed, &isp->media_dev);
+ if (ret)
+ return ret;
- return v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+ list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
+ /* Only try to link entities whose interface was set on bound */
+ if (sd->host_priv) {
+ bus = (struct isp_bus_cfg *)sd->host_priv;
+ ret = isp_link_entity(isp, &sd->entity, bus->interface);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+ if (ret < 0)
+ return ret;
+
+ return media_device_register(&isp->media_dev);
}
/*
@@ -2465,6 +2551,10 @@ static int isp_probe(struct platform_device *pdev)
if (ret < 0)
goto error_modules;
+ ret = isp_create_links(isp);
+ if (ret < 0)
+ goto error_register_entities;
+
isp->notifier.bound = isp_subdev_notifier_bound;
isp->notifier.complete = isp_subdev_notifier_complete;
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index 5acc2e6511a5..49b7f71ac968 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -17,6 +17,7 @@
#ifndef OMAP3_ISP_CORE_H
#define OMAP3_ISP_CORE_H
+#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <linux/clk-provider.h>
@@ -152,7 +153,7 @@ struct isp_xclk {
* @stat_lock: Spinlock for handling statistics
* @isp_mutex: Mutex for serializing requests to ISP.
* @stop_failure: Indicates that an entity failed to stop.
- * @crashed: Bitmask of crashed entities (indexed by entity ID)
+ * @crashed: Crashed ent_enum
* @has_context: Context has been saved at least once and can be restored.
* @ref_count: Reference count for handling multiple ISP requests.
* @cam_ick: Pointer to camera interface clock structure.
@@ -176,6 +177,7 @@ struct isp_device {
struct v4l2_device v4l2_dev;
struct v4l2_async_notifier notifier;
struct media_device media_dev;
+ struct media_entity_graph pm_count_graph;
struct device *dev;
u32 revision;
@@ -194,7 +196,7 @@ struct isp_device {
spinlock_t stat_lock; /* common lock for statistic drivers */
struct mutex isp_mutex; /* For handling ref_count field */
bool stop_failure;
- u32 crashed;
+ struct media_entity_enum crashed;
int has_context;
int ref_count;
unsigned int autoidle;
@@ -265,7 +267,8 @@ void omap3isp_subclk_enable(struct isp_device *isp,
void omap3isp_subclk_disable(struct isp_device *isp,
enum isp_subclk_resource res);
-int omap3isp_pipeline_pm_use(struct media_entity *entity, int use);
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use,
+ struct media_entity_graph *graph);
int omap3isp_register_entities(struct platform_device *pdev,
struct v4l2_device *v4l2_dev);
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index a6a61cce43dd..bb3974c98e37 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1608,7 +1608,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
/* Wait for the CCDC to become idle. */
if (ccdc_sbl_wait_idle(ccdc, 1000)) {
dev_info(isp->dev, "CCDC won't become idle!\n");
- isp->crashed |= 1U << ccdc->subdev.entity.id;
+ media_entity_enum_set(&isp->crashed, &ccdc->subdev.entity);
omap3isp_pipeline_cancel_stream(pipe);
return 0;
}
@@ -2513,9 +2513,14 @@ static int ccdc_link_setup(struct media_entity *entity,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
struct isp_device *isp = to_isp_device(ccdc);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case CCDC_PAD_SINK | 2 << 16:
/* Read from the sensor (parallel interface), CCP2, CSI2a or
* CSI2c.
*/
@@ -2543,7 +2548,7 @@ static int ccdc_link_setup(struct media_entity *entity,
* Revisit this when it will be implemented, and return -EBUSY for now.
*/
- case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+ case CCDC_PAD_SOURCE_VP | 2 << 16:
/* Write to preview engine, histogram and H3A. When none of
* those links are active, the video port can be disabled.
*/
@@ -2556,7 +2561,7 @@ static int ccdc_link_setup(struct media_entity *entity,
}
break;
- case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
+ case CCDC_PAD_SOURCE_OF:
/* Write to memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
@@ -2567,7 +2572,7 @@ static int ccdc_link_setup(struct media_entity *entity,
}
break;
- case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
+ case CCDC_PAD_SOURCE_OF | 2 << 16:
/* Write to resizer */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
@@ -2650,7 +2655,7 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &ccdc_media_ops;
- ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, CCDC_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -2664,19 +2669,11 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
if (ret < 0)
- goto error_video;
-
- /* Connect the CCDC subdev to the video node. */
- ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
- &ccdc->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
+ goto error;
return 0;
-error_link:
- omap3isp_video_cleanup(&ccdc->video_out);
-error_video:
+error:
media_entity_cleanup(me);
return ret;
}
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index 38e6a974c5b1..ca095238510d 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -956,9 +956,14 @@ static int ccp2_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case CCP2_PAD_SINK:
/* read from memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ccp2->input == CCP2_INPUT_SENSOR)
@@ -970,7 +975,7 @@ static int ccp2_link_setup(struct media_entity *entity,
}
break;
- case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ case CCP2_PAD_SINK | 2 << 16:
/* read from sensor/phy */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ccp2->input == CCP2_INPUT_MEMORY)
@@ -981,7 +986,7 @@ static int ccp2_link_setup(struct media_entity *entity,
ccp2->input = CCP2_INPUT_NONE;
} break;
- case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case CCP2_PAD_SOURCE | 2 << 16:
/* write to video port/ccdc */
if (flags & MEDIA_LNK_FL_ENABLED)
ccp2->output = CCP2_OUTPUT_CCDC;
@@ -1071,7 +1076,7 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &ccp2_media_ops;
- ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, CCP2_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -1097,19 +1102,11 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
ret = omap3isp_video_init(&ccp2->video_in, "CCP2");
if (ret < 0)
- goto error_video;
-
- /* Connect the video node to the ccp2 subdev. */
- ret = media_entity_create_link(&ccp2->video_in.video.entity, 0,
- &ccp2->subdev.entity, CCP2_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
+ goto error;
return 0;
-error_link:
- omap3isp_video_cleanup(&ccp2->video_in);
-error_video:
+error:
media_entity_cleanup(&ccp2->subdev.entity);
return ret;
}
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index a78338d012b4..f75a1be29d84 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -1144,14 +1144,19 @@ static int csi2_link_setup(struct media_entity *entity,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
+ unsigned int index = local->index;
/*
* The ISP core doesn't support pipelines with multiple video outputs.
* Revisit this when it will be implemented, and return -EBUSY for now.
*/
- switch (local->index | media_entity_type(remote->entity)) {
- case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case CSI2_PAD_SOURCE:
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->output & ~CSI2_OUTPUT_MEMORY)
return -EBUSY;
@@ -1161,7 +1166,7 @@ static int csi2_link_setup(struct media_entity *entity,
}
break;
- case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case CSI2_PAD_SOURCE | 2 << 16:
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->output & ~CSI2_OUTPUT_CCDC)
return -EBUSY;
@@ -1245,7 +1250,7 @@ static int csi2_init_entities(struct isp_csi2_device *csi2)
| MEDIA_PAD_FL_MUST_CONNECT;
me->ops = &csi2_media_ops;
- ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -1264,16 +1269,8 @@ static int csi2_init_entities(struct isp_csi2_device *csi2)
if (ret < 0)
goto error_video;
- /* Connect the CSI2 subdev to the video node. */
- ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
- &csi2->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap3isp_video_cleanup(&csi2->video_out);
error_video:
media_entity_cleanup(&csi2->subdev.entity);
return ret;
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 13803270d104..84a96670e2e7 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -2144,9 +2144,14 @@ static int preview_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case PREV_PAD_SINK:
/* read from memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (prev->input == PREVIEW_INPUT_CCDC)
@@ -2158,7 +2163,7 @@ static int preview_link_setup(struct media_entity *entity,
}
break;
- case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ case PREV_PAD_SINK | 2 << 16:
/* read from ccdc */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (prev->input == PREVIEW_INPUT_MEMORY)
@@ -2175,7 +2180,7 @@ static int preview_link_setup(struct media_entity *entity,
* Revisit this when it will be implemented, and return -EBUSY for now.
*/
- case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ case PREV_PAD_SOURCE:
/* write to memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
@@ -2186,7 +2191,7 @@ static int preview_link_setup(struct media_entity *entity,
}
break;
- case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case PREV_PAD_SOURCE | 2 << 16:
/* write to resizer */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
@@ -2282,7 +2287,7 @@ static int preview_init_entities(struct isp_prev_device *prev)
pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &preview_media_ops;
- ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, PREV_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -2311,21 +2316,8 @@ static int preview_init_entities(struct isp_prev_device *prev)
if (ret < 0)
goto error_video_out;
- /* Connect the video nodes to the previewer subdev. */
- ret = media_entity_create_link(&prev->video_in.video.entity, 0,
- &prev->subdev.entity, PREV_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
- &prev->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap3isp_video_cleanup(&prev->video_out);
error_video_out:
omap3isp_video_cleanup(&prev->video_in);
error_video_in:
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 7cfb43dc0ffd..0b6a87508584 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -1623,9 +1623,14 @@ static int resizer_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case RESZ_PAD_SINK:
/* read from memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (res->input == RESIZER_INPUT_VP)
@@ -1637,7 +1642,7 @@ static int resizer_link_setup(struct media_entity *entity,
}
break;
- case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ case RESZ_PAD_SINK | 2 << 16:
/* read from ccdc or previewer */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (res->input == RESIZER_INPUT_MEMORY)
@@ -1649,7 +1654,7 @@ static int resizer_link_setup(struct media_entity *entity,
}
break;
- case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ case RESZ_PAD_SOURCE:
/* resizer always write to memory */
break;
@@ -1728,7 +1733,7 @@ static int resizer_init_entities(struct isp_res_device *res)
pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &resizer_media_ops;
- ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, RESZ_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -1755,21 +1760,8 @@ static int resizer_init_entities(struct isp_res_device *res)
res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
- /* Connect the video nodes to the resizer subdev. */
- ret = media_entity_create_link(&res->video_in.video.entity, 0,
- &res->subdev.entity, RESZ_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
- &res->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap3isp_video_cleanup(&res->video_out);
error_video_out:
omap3isp_video_cleanup(&res->video_in);
error_video_in:
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index 94d4c295d3d0..1b9217d3b1b6 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -1028,7 +1028,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name,
stat->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
me->ops = NULL;
- return media_entity_init(me, 1, &stat->pad, 0);
+ return media_entity_pads_init(me, 1, &stat->pad);
}
int omap3isp_stat_init(struct ispstat *stat, const char *name,
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index ecadca3e945b..994dfc0813f6 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -210,8 +210,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
remote = media_entity_remote_pad(&video->pad);
- if (remote == NULL ||
- media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
if (pad)
@@ -226,16 +225,23 @@ static int isp_video_get_graph_data(struct isp_video *video,
{
struct media_entity_graph graph;
struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
struct isp_video *far_end = NULL;
+ int ret;
mutex_lock(&mdev->graph_mutex);
+ ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
struct isp_video *__video;
- pipe->entities |= 1 << entity->id;
+ media_entity_enum_set(&pipe->ent_enum, entity);
if (far_end != NULL)
continue;
@@ -243,7 +249,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
if (entity == &video->video.entity)
continue;
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ if (!is_media_entity_v4l2_io(entity))
continue;
__video = to_isp_video(media_entity_to_video_device(entity));
@@ -253,6 +259,8 @@ static int isp_video_get_graph_data(struct isp_video *video,
mutex_unlock(&mdev->graph_mutex);
+ media_entity_graph_walk_cleanup(&graph);
+
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
pipe->input = far_end;
pipe->output = video;
@@ -900,7 +908,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
for (i = 0; i < ARRAY_SIZE(ents); i++) {
/* Is the entity part of the pipeline? */
- if (!(pipe->entities & (1 << ents[i]->id)))
+ if (!media_entity_enum_test(&pipe->ent_enum, ents[i]))
continue;
/* ISP entities have always sink pad == 0. Find source. */
@@ -918,7 +926,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
return -EINVAL;
}
- if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!is_media_entity_v4l2_subdev(source))
return 0;
pipe->external = media_entity_to_v4l2_subdev(source);
@@ -952,7 +960,8 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
pipe->external_rate = ctrl.value64;
- if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
+ if (media_entity_enum_test(&pipe->ent_enum,
+ &isp->isp_ccdc.subdev.entity)) {
unsigned int rate = UINT_MAX;
/*
* Check that maximum allowed CCDC pixel rate isn't
@@ -1018,7 +1027,9 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
pipe = video->video.entity.pipe
? to_isp_pipeline(&video->video.entity) : &video->pipe;
- pipe->entities = 0;
+ ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
+ if (ret)
+ goto err_enum_init;
/* TODO: Implement PM QoS */
pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
@@ -1092,6 +1103,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
}
mutex_unlock(&video->stream_lock);
+
return 0;
err_set_stream:
@@ -1112,7 +1124,11 @@ err_pipeline_start:
INIT_LIST_HEAD(&video->dmaqueue);
video->queue = NULL;
+ media_entity_enum_cleanup(&pipe->ent_enum);
+
+err_enum_init:
mutex_unlock(&video->stream_lock);
+
return ret;
}
@@ -1164,6 +1180,8 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
/* TODO: Implement PM QoS */
media_entity_pipeline_stop(&video->video.entity);
+ media_entity_enum_cleanup(&pipe->ent_enum);
+
done:
mutex_unlock(&video->stream_lock);
return 0;
@@ -1243,7 +1261,12 @@ static int isp_video_open(struct file *file)
goto done;
}
- ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
+ ret = media_entity_graph_walk_init(&handle->graph,
+ &video->isp->media_dev);
+ if (ret)
+ goto done;
+
+ ret = omap3isp_pipeline_pm_use(&video->video.entity, 1, &handle->graph);
if (ret < 0) {
omap3isp_put(video->isp);
goto done;
@@ -1274,6 +1297,7 @@ static int isp_video_open(struct file *file)
done:
if (ret < 0) {
v4l2_fh_del(&handle->vfh);
+ media_entity_graph_walk_cleanup(&handle->graph);
kfree(handle);
}
@@ -1293,7 +1317,8 @@ static int isp_video_release(struct file *file)
vb2_queue_release(&handle->queue);
mutex_unlock(&video->queue_lock);
- omap3isp_pipeline_pm_use(&video->video.entity, 0);
+ omap3isp_pipeline_pm_use(&video->video.entity, 0, &handle->graph);
+ media_entity_graph_walk_cleanup(&handle->graph);
/* Release the file handle. */
v4l2_fh_del(vfh);
@@ -1367,7 +1392,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
if (IS_ERR(video->alloc_ctx))
return PTR_ERR(video->alloc_ctx);
- ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+ ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
if (ret < 0) {
vb2_dma_contig_cleanup_ctx(video->alloc_ctx);
return ret;
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
index bcf0e0acc8f3..156429878d64 100644
--- a/drivers/media/platform/omap3isp/ispvideo.h
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -80,7 +80,7 @@ enum isp_pipeline_state {
* struct isp_pipeline - An ISP hardware pipeline
* @field: The field being processed by the pipeline
* @error: A hardware error occurred during capture
- * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
+ * @ent_enum: Entities in the pipeline
*/
struct isp_pipeline {
struct media_pipeline pipe;
@@ -89,7 +89,7 @@ struct isp_pipeline {
enum isp_pipeline_stream_state stream_state;
struct isp_video *input;
struct isp_video *output;
- u32 entities;
+ struct media_entity_enum ent_enum;
unsigned long l3_ick;
unsigned int max_rate;
enum v4l2_field field;
@@ -189,6 +189,7 @@ struct isp_video_fh {
struct vb2_queue queue;
struct v4l2_format format;
struct v4l2_fract timeperframe;
+ struct media_entity_graph graph;
};
#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh)
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index ec3abbed87d9..bd060ef5d1e1 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -822,7 +822,7 @@ static int camif_pipeline_validate(struct camif_dev *camif)
/* Retrieve format at the sensor subdev source pad */
pad = media_entity_remote_pad(&camif->pads[0]);
- if (!pad || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
return -EPIPE;
src_fmt.pad = pad->index;
@@ -1144,7 +1144,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
goto err_vd_rel;
vp->pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&vfd->entity, 1, &vp->pad, 0);
+ ret = media_entity_pads_init(&vfd->entity, 1, &vp->pad);
if (ret)
goto err_vd_rel;
@@ -1559,8 +1559,8 @@ int s3c_camif_create_subdev(struct camif_dev *camif)
camif->pads[CAMIF_SD_PAD_SOURCE_C].flags = MEDIA_PAD_FL_SOURCE;
camif->pads[CAMIF_SD_PAD_SOURCE_P].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, CAMIF_SD_PADS_NUM,
- camif->pads, 0);
+ ret = media_entity_pads_init(&sd->entity, CAMIF_SD_PADS_NUM,
+ camif->pads);
if (ret)
return ret;
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index 1ba9bb08f5da..0b44b9accf50 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -263,7 +263,7 @@ static int camif_create_media_links(struct camif_dev *camif)
{
int i, ret;
- ret = media_entity_create_link(&camif->sensor.sd->entity, 0,
+ ret = media_create_pad_link(&camif->sensor.sd->entity, 0,
&camif->subdev.entity, CAMIF_SD_PAD_SINK,
MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
@@ -271,7 +271,7 @@ static int camif_create_media_links(struct camif_dev *camif)
return ret;
for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) {
- ret = media_entity_create_link(&camif->subdev.entity, i,
+ ret = media_create_pad_link(&camif->subdev.entity, i,
&camif->vp[i - 1].vdev.entity, 0,
MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
@@ -305,7 +305,7 @@ static void camif_unregister_media_entities(struct camif_dev *camif)
/*
* Media device
*/
-static int camif_media_dev_register(struct camif_dev *camif)
+static int camif_media_dev_init(struct camif_dev *camif)
{
struct media_device *md = &camif->media_dev;
struct v4l2_device *v4l2_dev = &camif->v4l2_dev;
@@ -324,14 +324,12 @@ static int camif_media_dev_register(struct camif_dev *camif)
strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name));
v4l2_dev->mdev = md;
+ media_device_init(md);
+
ret = v4l2_device_register(camif->dev, v4l2_dev);
if (ret < 0)
return ret;
- ret = media_device_register(md);
- if (ret < 0)
- v4l2_device_unregister(v4l2_dev);
-
return ret;
}
@@ -483,7 +481,7 @@ static int s3c_camif_probe(struct platform_device *pdev)
goto err_alloc;
}
- ret = camif_media_dev_register(camif);
+ ret = camif_media_dev_init(camif);
if (ret < 0)
goto err_mdev;
@@ -510,6 +508,11 @@ static int s3c_camif_probe(struct platform_device *pdev)
goto err_unlock;
mutex_unlock(&camif->media_dev.graph_mutex);
+
+ ret = media_device_register(&camif->media_dev);
+ if (ret < 0)
+ goto err_sens;
+
pm_runtime_put(dev);
return 0;
@@ -518,6 +521,7 @@ err_unlock:
err_sens:
v4l2_device_unregister(&camif->v4l2_dev);
media_device_unregister(&camif->media_dev);
+ media_device_cleanup(&camif->media_dev);
camif_unregister_media_entities(camif);
err_mdev:
vb2_dma_contig_cleanup_ctx(camif->alloc_ctx);
@@ -539,6 +543,7 @@ static int s3c_camif_remove(struct platform_device *pdev)
struct s3c_camif_plat_data *pdata = &camif->pdata;
media_device_unregister(&camif->media_dev);
+ media_device_cleanup(&camif->media_dev);
camif_unregister_media_entities(camif);
v4l2_device_unregister(&camif->v4l2_dev);
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 4e61886384e3..42dff9d020af 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -101,7 +101,7 @@ static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink)
if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
continue;
- ret = media_entity_create_link(&source->subdev.entity,
+ ret = media_create_pad_link(&source->subdev.entity,
source->source_pad,
entity, pad, flags);
if (ret < 0)
@@ -127,6 +127,7 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1)
v4l2_device_unregister(&vsp1->v4l2_dev);
media_device_unregister(&vsp1->media_dev);
+ media_device_cleanup(&vsp1->media_dev);
}
static int vsp1_create_entities(struct vsp1_device *vsp1)
@@ -141,12 +142,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
dev_name(mdev->dev));
- ret = media_device_register(mdev);
- if (ret < 0) {
- dev_err(vsp1->dev, "media device registration failed (%d)\n",
- ret);
- return ret;
- }
+ media_device_init(mdev);
vdev->mdev = mdev;
ret = v4l2_device_register(vsp1->dev, vdev);
@@ -250,34 +246,44 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
}
- /* Create links. */
+ /* Register all subdevs. */
list_for_each_entry(entity, &vsp1->entities, list_dev) {
- if (entity->type == VSP1_ENTITY_LIF ||
- entity->type == VSP1_ENTITY_RPF)
- continue;
-
- ret = vsp1_create_links(vsp1, entity);
+ ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
+ &entity->subdev);
if (ret < 0)
goto done;
}
+ /* Create links. */
+ list_for_each_entry(entity, &vsp1->entities, list_dev) {
+ if (entity->type == VSP1_ENTITY_LIF) {
+ ret = vsp1_wpf_create_links(vsp1, entity);
+ if (ret < 0)
+ goto done;
+ } else if (entity->type == VSP1_ENTITY_RPF) {
+ ret = vsp1_rpf_create_links(vsp1, entity);
+ if (ret < 0)
+ goto done;
+ } else {
+ ret = vsp1_create_links(vsp1, entity);
+ if (ret < 0)
+ goto done;
+ }
+ }
+
if (vsp1->pdata.features & VSP1_HAS_LIF) {
- ret = media_entity_create_link(
+ ret = media_create_pad_link(
&vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE,
&vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0);
if (ret < 0)
return ret;
}
- /* Register all subdevs. */
- list_for_each_entry(entity, &vsp1->entities, list_dev) {
- ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
- &entity->subdev);
- if (ret < 0)
- goto done;
- }
-
ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
+ if (ret < 0)
+ goto done;
+
+ ret = media_device_register(mdev);
done:
if (ret < 0)
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index fd95a75b04f4..d7308530952f 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -219,8 +219,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
/* Initialize the media entity. */
- return media_entity_init(&entity->subdev.entity, num_pads,
- entity->pads, 0);
+ return media_entity_pads_init(&entity->subdev.entity, num_pads,
+ entity->pads);
}
void vsp1_entity_destroy(struct vsp1_entity *entity)
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index cd5248a9a271..924538223d3e 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -277,18 +277,29 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
rpf->entity.video = video;
- /* Connect the video device to the RPF. */
- ret = media_entity_create_link(&rpf->video.video.entity, 0,
- &rpf->entity.subdev.entity,
- RWPF_PAD_SINK,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (ret < 0)
- goto error;
-
return rpf;
error:
vsp1_entity_destroy(&rpf->entity);
return ERR_PTR(ret);
}
+
+/*
+ * vsp1_rpf_create_links() - RPF pads links creation
+ * @vsp1: Pointer to VSP1 device
+ * @entity: Pointer to VSP1 entity
+ *
+ * return negative error code or zero on success
+ */
+int vsp1_rpf_create_links(struct vsp1_device *vsp1,
+ struct vsp1_entity *entity)
+{
+ struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
+
+ /* Connect the video device to the RPF. */
+ return media_create_pad_link(&rpf->video.video.entity, 0,
+ &rpf->entity.subdev.entity,
+ RWPF_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index f452dce1a931..731d36e5258d 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -50,6 +50,11 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
+int vsp1_rpf_create_links(struct vsp1_device *vsp1,
+ struct vsp1_entity *entity);
+int vsp1_wpf_create_links(struct vsp1_device *vsp1,
+ struct vsp1_entity *entity);
+
int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 45eb65fa23db..637d0d6f79fb 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -160,8 +160,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad)
struct media_pad *remote;
remote = media_entity_remote_pad(local);
- if (remote == NULL ||
- media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
if (pad)
@@ -283,24 +282,35 @@ static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe,
struct vsp1_rwpf *output)
{
struct vsp1_entity *entity;
- unsigned int entities = 0;
+ struct media_entity_enum ent_enum;
struct media_pad *pad;
+ int rval;
bool bru_found = false;
input->location.left = 0;
input->location.top = 0;
+ rval = media_entity_enum_init(
+ &ent_enum, input->entity.pads[RWPF_PAD_SOURCE].graph_obj.mdev);
+ if (rval)
+ return rval;
+
pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
while (1) {
- if (pad == NULL)
- return -EPIPE;
+ if (pad == NULL) {
+ rval = -EPIPE;
+ goto out;
+ }
/* We've reached a video node, that shouldn't have happened. */
- if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- return -EPIPE;
+ if (!is_media_entity_v4l2_subdev(pad->entity)) {
+ rval = -EPIPE;
+ goto out;
+ }
- entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
+ entity = to_vsp1_entity(
+ media_entity_to_v4l2_subdev(pad->entity));
/* A BRU is present in the pipeline, store the compose rectangle
* location in the input RPF for use when configuring the RPF.
@@ -323,15 +333,18 @@ static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe,
break;
/* Ensure the branch has no loop. */
- if (entities & (1 << entity->subdev.entity.id))
- return -EPIPE;
-
- entities |= 1 << entity->subdev.entity.id;
+ if (media_entity_enum_test_and_set(&ent_enum,
+ &entity->subdev.entity)) {
+ rval = -EPIPE;
+ goto out;
+ }
/* UDS can't be chained. */
if (entity->type == VSP1_ENTITY_UDS) {
- if (pipe->uds)
- return -EPIPE;
+ if (pipe->uds) {
+ rval = -EPIPE;
+ goto out;
+ }
pipe->uds = entity;
pipe->uds_input = bru_found ? pipe->bru
@@ -349,9 +362,12 @@ static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe,
/* The last entity must be the output WPF. */
if (entity != &output->entity)
- return -EPIPE;
+ rval = -EPIPE;
- return 0;
+out:
+ media_entity_enum_cleanup(&ent_enum);
+
+ return rval;
}
static void __vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
@@ -380,13 +396,19 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
{
struct media_entity_graph graph;
struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
unsigned int i;
int ret;
mutex_lock(&mdev->graph_mutex);
/* Walk the graph to locate the entities and video nodes. */
+ ret = media_entity_graph_walk_init(&graph, mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
@@ -394,7 +416,7 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
struct vsp1_rwpf *rwpf;
struct vsp1_entity *e;
- if (media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) {
+ if (is_media_entity_v4l2_io(entity)) {
pipe->num_video++;
continue;
}
@@ -420,6 +442,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
mutex_unlock(&mdev->graph_mutex);
+ media_entity_graph_walk_cleanup(&graph);
+
/* We need one output and at least one input. */
if (pipe->num_inputs == 0 || !pipe->output) {
ret = -EPIPE;
@@ -663,7 +687,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]);
while (pad) {
- if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!is_media_entity_v4l2_subdev(pad->entity))
break;
entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
@@ -1193,7 +1217,7 @@ int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf)
video->pipe.state = VSP1_PIPELINE_STOPPED;
/* Initialize the media entity... */
- ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+ ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 95b62f4f77e7..cbf514a6582d 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -220,7 +220,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
struct v4l2_subdev *subdev;
struct vsp1_video *video;
struct vsp1_rwpf *wpf;
- unsigned int flags;
int ret;
wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
@@ -276,20 +275,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
goto error;
wpf->entity.video = video;
-
- /* Connect the video device to the WPF. All connections are immutable
- * except for the WPF0 source link if a LIF is present.
- */
- flags = MEDIA_LNK_FL_ENABLED;
- if (!(vsp1->pdata.features & VSP1_HAS_LIF) || index != 0)
- flags |= MEDIA_LNK_FL_IMMUTABLE;
-
- ret = media_entity_create_link(&wpf->entity.subdev.entity,
- RWPF_PAD_SOURCE,
- &wpf->video.video.entity, 0, flags);
- if (ret < 0)
- goto error;
-
wpf->entity.sink = &wpf->video.video.entity;
return wpf;
@@ -298,3 +283,28 @@ error:
vsp1_entity_destroy(&wpf->entity);
return ERR_PTR(ret);
}
+
+/*
+ * vsp1_wpf_create_links() - RPF pads links creation
+ * @vsp1: Pointer to VSP1 device
+ * @entity: Pointer to VSP1 entity
+ *
+ * return negative error code or zero on success
+ */
+int vsp1_wpf_create_links(struct vsp1_device *vsp1,
+ struct vsp1_entity *entity)
+{
+ struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+ unsigned int flags;
+
+ /* Connect the video device to the WPF. All connections are immutable
+ * except for the WPF0 source link if a LIF is present.
+ */
+ flags = MEDIA_LNK_FL_ENABLED;
+ if (!(vsp1->pdata.features & VSP1_HAS_LIF) || entity->index != 0)
+ flags |= MEDIA_LNK_FL_IMMUTABLE;
+
+ return media_create_pad_link(&wpf->entity.subdev.entity,
+ RWPF_PAD_SOURCE,
+ &wpf->video.video.entity, 0, flags);
+}
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 722758f33924..7f6898b13cac 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -49,8 +49,7 @@ xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
struct media_pad *remote;
remote = media_entity_remote_pad(local);
- if (remote == NULL ||
- media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
if (pad)
@@ -113,8 +112,7 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
break;
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -181,19 +179,26 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
{
struct media_entity_graph graph;
struct media_entity *entity = &start->video.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
unsigned int num_inputs = 0;
unsigned int num_outputs = 0;
+ int ret;
mutex_lock(&mdev->graph_mutex);
/* Walk the graph to locate the video nodes. */
+ ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
struct xvip_dma *dma;
- if (entity->type != MEDIA_ENT_T_DEVNODE_V4L)
+ if (entity->function != MEDIA_ENT_F_IO_V4L)
continue;
dma = to_xvip_dma(media_entity_to_video_device(entity));
@@ -208,6 +213,8 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
mutex_unlock(&mdev->graph_mutex);
+ media_entity_graph_walk_cleanup(&graph);
+
/* We need exactly one output and zero or one input. */
if (num_outputs != 1 || num_inputs > 1)
return -EPIPE;
@@ -677,7 +684,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0);
+ ret = media_entity_pads_init(&dma->video.entity, 1, &dma->pad);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index 8bd7e3736019..2ec1f6c4b274 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -838,7 +838,7 @@ static int xtpg_probe(struct platform_device *pdev)
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
subdev->entity.ops = &xtpg_media_ops;
- ret = media_entity_init(&subdev->entity, xtpg->npads, xtpg->pads, 0);
+ ret = media_entity_pads_init(&subdev->entity, xtpg->npads, xtpg->pads);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index b9bf24fefa5a..e795a4501e8b 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -156,7 +156,7 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
local->name, local_pad->index,
remote->name, remote_pad->index);
- ret = media_entity_create_link(local, local_pad->index,
+ ret = media_create_pad_link(local, local_pad->index,
remote, remote_pad->index,
link_flags);
if (ret < 0) {
@@ -270,7 +270,7 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
source->name, source_pad->index,
sink->name, sink_pad->index);
- ret = media_entity_create_link(source, source_pad->index,
+ ret = media_create_pad_link(source, source_pad->index,
sink, sink_pad->index,
link_flags);
if (ret < 0) {
@@ -311,7 +311,7 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
if (ret < 0)
dev_err(xdev->dev, "failed to register subdev nodes\n");
- return ret;
+ return media_device_register(&xdev->media_dev);
}
static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
@@ -573,6 +573,7 @@ static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev)
{
v4l2_device_unregister(&xdev->v4l2_dev);
media_device_unregister(&xdev->media_dev);
+ media_device_cleanup(&xdev->media_dev);
}
static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev)
@@ -584,19 +585,14 @@ static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev)
sizeof(xdev->media_dev.model));
xdev->media_dev.hw_revision = 0;
- ret = media_device_register(&xdev->media_dev);
- if (ret < 0) {
- dev_err(xdev->dev, "media device registration failed (%d)\n",
- ret);
- return ret;
- }
+ media_device_init(&xdev->media_dev);
xdev->v4l2_dev.mdev = &xdev->media_dev;
ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev);
if (ret < 0) {
dev_err(xdev->dev, "V4L2 device registration failed (%d)\n",
ret);
- media_device_unregister(&xdev->media_dev);
+ media_device_cleanup(&xdev->media_dev);
return ret;
}
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index 6b469e8c4c6e..ca861aea68a5 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -228,6 +228,10 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev)
"au8522", 0x8e >> 1, NULL);
if (sd == NULL)
pr_err("analog subdev registration failed\n");
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (sd)
+ dev->decoder = &sd->entity;
+#endif
}
/* Setup tuners */
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 0934024fb89d..9e29e70a78d7 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -27,6 +27,9 @@
#include <media/v4l2-common.h>
#include <linux/mutex.h>
+/* Due to enum tuner_pad_index */
+#include <media/tuner.h>
+
/*
* 1 = General debug messages
* 2 = USB handling
@@ -127,8 +130,23 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
return status;
}
+static void au0828_unregister_media_device(struct au0828_dev *dev)
+{
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (dev->media_dev) {
+ media_device_unregister(dev->media_dev);
+ media_device_cleanup(dev->media_dev);
+ kfree(dev->media_dev);
+ dev->media_dev = NULL;
+ }
+#endif
+}
+
static void au0828_usb_release(struct au0828_dev *dev)
{
+ au0828_unregister_media_device(dev);
+
/* I2C */
au0828_i2c_unregister(dev);
@@ -136,6 +154,20 @@ static void au0828_usb_release(struct au0828_dev *dev)
}
#ifdef CONFIG_VIDEO_AU0828_V4L2
+
+static void au0828_usb_v4l2_media_release(struct au0828_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int i;
+
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
+ return;
+ media_device_unregister_entity(&dev->input_ent[i]);
+ }
+#endif
+}
+
static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
{
struct au0828_dev *dev =
@@ -143,6 +175,7 @@ static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
v4l2_device_unregister(&dev->v4l2_dev);
+ au0828_usb_v4l2_media_release(dev);
au0828_usb_release(dev);
}
#endif
@@ -174,12 +207,123 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
au0828_analog_unregister(dev);
v4l2_device_disconnect(&dev->v4l2_dev);
v4l2_device_put(&dev->v4l2_dev);
+ /*
+ * No need to call au0828_usb_release() if V4L2 is enabled,
+ * as this is already called via au0828_usb_v4l2_release()
+ */
return;
}
#endif
au0828_usb_release(dev);
}
+static int au0828_media_device_init(struct au0828_dev *dev,
+ struct usb_device *udev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev;
+
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ mdev->dev = &udev->dev;
+
+ if (!dev->board.name)
+ strlcpy(mdev->model, "unknown au0828", sizeof(mdev->model));
+ else
+ strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
+ if (udev->serial)
+ strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ strcpy(mdev->bus_info, udev->devpath);
+ mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ mdev->driver_version = LINUX_VERSION_CODE;
+
+ media_device_init(mdev);
+
+ dev->media_dev = mdev;
+#endif
+ return 0;
+}
+
+
+static int au0828_create_media_graph(struct au0828_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *entity;
+ struct media_entity *tuner = NULL, *decoder = NULL;
+ int i, ret;
+
+ if (!mdev)
+ return 0;
+
+ media_device_for_each_entity(entity, mdev) {
+ switch (entity->function) {
+ case MEDIA_ENT_F_TUNER:
+ tuner = entity;
+ break;
+ case MEDIA_ENT_F_ATV_DECODER:
+ decoder = entity;
+ break;
+ }
+ }
+
+ /* Analog setup, using tuner as a link */
+
+ /* Something bad happened! */
+ if (!decoder)
+ return -EINVAL;
+
+ if (tuner) {
+ ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT,
+ decoder, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+ ret = media_create_pad_link(decoder, 1, &dev->vdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ ret = media_create_pad_link(decoder, 2, &dev->vbi_dev.entity, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+
+ if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
+ break;
+
+ switch (AUVI_INPUT(i).type) {
+ case AU0828_VMUX_CABLE:
+ case AU0828_VMUX_TELEVISION:
+ case AU0828_VMUX_DVB:
+ if (!tuner)
+ break;
+
+ ret = media_create_pad_link(ent, 0, tuner,
+ TUNER_PAD_RF_INPUT,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ break;
+ case AU0828_VMUX_COMPOSITE:
+ case AU0828_VMUX_SVIDEO:
+ default: /* AU0828_VMUX_DEBUG */
+ /* FIXME: fix the decoder PAD */
+ ret = media_create_pad_link(ent, 0, decoder, 0, 0);
+ if (ret)
+ return ret;
+ break;
+ }
+ }
+#endif
+ return 0;
+}
+
static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -224,11 +368,23 @@ static int au0828_usb_probe(struct usb_interface *interface,
dev->boardnr = id->driver_info;
dev->board = au0828_boards[dev->boardnr];
+ /* Initialize the media controller */
+ retval = au0828_media_device_init(dev, usbdev);
+ if (retval) {
+ pr_err("%s() au0828_media_device_init failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return retval;
+ }
#ifdef CONFIG_VIDEO_AU0828_V4L2
dev->v4l2_dev.release = au0828_usb_v4l2_release;
/* Create the v4l2_device */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->v4l2_dev.mdev = dev->media_dev;
+#endif
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
pr_err("%s() v4l2_device_register failed\n",
@@ -287,6 +443,21 @@ static int au0828_usb_probe(struct usb_interface *interface,
mutex_unlock(&dev->lock);
+ retval = au0828_create_media_graph(dev);
+ if (retval) {
+ pr_err("%s() au0282_dev_register failed to create graph\n",
+ __func__);
+ goto done;
+ }
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ retval = media_device_register(dev->media_dev);
+#endif
+
+done:
+ if (retval < 0)
+ au0828_usb_disconnect(interface);
+
return retval;
}
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index c267d76f5b3c..94363a3ba400 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -415,6 +415,11 @@ static int dvb_register(struct au0828_dev *dev)
result);
goto fail_adapter;
}
+
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ dvb->adapter.mdev = dev->media_dev;
+#endif
+
dvb->adapter.priv = dev;
/* register frontend */
@@ -480,8 +485,15 @@ static int dvb_register(struct au0828_dev *dev)
dvb->start_count = 0;
dvb->stop_count = 0;
+
+ result = dvb_create_media_graph(&dvb->adapter, false);
+ if (result < 0)
+ goto fail_create_graph;
+
return 0;
+fail_create_graph:
+ dvb_net_release(&dvb->net);
fail_fe_conn:
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
fail_fe_mem:
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 0a725a161dd6..8c54fd21022e 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -638,6 +638,64 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
return rc;
}
+static int au0828_enable_analog_tuner(struct au0828_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *source;
+ struct media_link *link, *found_link = NULL;
+ int ret, active_links = 0;
+
+ if (!mdev || !dev->decoder)
+ return 0;
+
+ /*
+ * This will find the tuner that is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be
+ * using an analog input instead of the tuner. However, as we can't
+ * do DVB streaming while the DMA engine is being used for V4L2,
+ * this should be enough for the actual needs.
+ */
+ list_for_each_entry(link, &dev->decoder->links, list) {
+ if (link->sink->entity == dev->decoder) {
+ found_link = link;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ break;
+ }
+ }
+
+ if (active_links == 1 || !found_link)
+ return 0;
+
+ source = found_link->source->entity;
+ list_for_each_entry(link, &source->links, list) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ sink = link->sink->entity;
+
+ if (sink == dev->decoder)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ pr_err(
+ "Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ } else
+ au0828_isocdbg(
+ "link %s->%s was %s\n",
+ source->name, sink->name,
+ flags ? "ENABLED" : "disabled");
+ }
+#endif
+ return 0;
+}
+
static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
@@ -650,6 +708,8 @@ static int queue_setup(struct vb2_queue *vq,
*nplanes = 1;
sizes[0] = size;
+ au0828_enable_analog_tuner(dev);
+
return 0;
}
@@ -1735,6 +1795,69 @@ static int au0828_vb2_setup(struct au0828_dev *dev)
return 0;
}
+static void au0828_analog_create_entities(struct au0828_dev *dev)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ static const char * const inames[] = {
+ [AU0828_VMUX_COMPOSITE] = "Composite",
+ [AU0828_VMUX_SVIDEO] = "S-Video",
+ [AU0828_VMUX_CABLE] = "Cable TV",
+ [AU0828_VMUX_TELEVISION] = "Television",
+ [AU0828_VMUX_DVB] = "DVB",
+ [AU0828_VMUX_DEBUG] = "tv debug"
+ };
+ int ret, i;
+
+ /* Initialize Video and VBI pads */
+ dev->video_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
+ if (ret < 0)
+ pr_err("failed to initialize video media entity!\n");
+
+ dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
+ if (ret < 0)
+ pr_err("failed to initialize vbi media entity!\n");
+
+ /* Create entities for each input connector */
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+
+ if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
+ break;
+
+ ent->name = inames[AUVI_INPUT(i).type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ switch (AUVI_INPUT(i).type) {
+ case AU0828_VMUX_COMPOSITE:
+ ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case AU0828_VMUX_SVIDEO:
+ ent->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ case AU0828_VMUX_CABLE:
+ case AU0828_VMUX_TELEVISION:
+ case AU0828_VMUX_DVB:
+ ent->function = MEDIA_ENT_F_CONN_RF;
+ break;
+ default: /* AU0828_VMUX_DEBUG */
+ ent->function = MEDIA_ENT_F_CONN_TEST;
+ break;
+ }
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+#endif
+}
+
/**************************************************************************/
int au0828_analog_register(struct au0828_dev *dev,
@@ -1823,6 +1946,9 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock;
strcpy(dev->vbi_dev.name, "au0828a vbi");
+ /* Init entities at the Media Controller */
+ au0828_analog_create_entities(dev);
+
/* initialize videobuf2 stuff */
retval = au0828_vb2_setup(dev);
if (retval != 0) {
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 60b59391ea2a..8276072bc55a 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -33,6 +33,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
+#include <media/media-device.h>
/* DVB */
#include "demux.h"
@@ -93,7 +94,6 @@ struct au0828_board {
unsigned char has_ir_i2c:1;
unsigned char has_analog:1;
struct au0828_input input[AU0828_MAX_INPUT];
-
};
struct au0828_dvb {
@@ -276,6 +276,14 @@ struct au0828_dev {
/* Preallocated transfer digital transfer buffers */
char *dig_transfer_buffer[URB_COUNT];
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *media_dev;
+ struct media_pad video_pad, vbi_pad;
+ struct media_entity *decoder;
+ struct media_entity input_ent[AU0828_MAX_INPUT];
+ struct media_pad input_pad[AU0828_MAX_INPUT];
+#endif
};
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 89dc695c696e..620b83d03f75 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -1172,6 +1172,7 @@ static void cx231xx_unregister_media_device(struct cx231xx *dev)
#ifdef CONFIG_MEDIA_CONTROLLER
if (dev->media_dev) {
media_device_unregister(dev->media_dev);
+ media_device_cleanup(dev->media_dev);
kfree(dev->media_dev);
dev->media_dev = NULL;
}
@@ -1185,8 +1186,6 @@ static void cx231xx_unregister_media_device(struct cx231xx *dev)
*/
void cx231xx_release_resources(struct cx231xx *dev)
{
- cx231xx_unregister_media_device(dev);
-
cx231xx_release_analog_resources(dev);
cx231xx_remove_from_devlist(dev);
@@ -1199,22 +1198,23 @@ void cx231xx_release_resources(struct cx231xx *dev)
/* delete v4l2 device */
v4l2_device_unregister(&dev->v4l2_dev);
+ cx231xx_unregister_media_device(dev);
+
usb_put_dev(dev->udev);
/* Mark device as unused */
clear_bit(dev->devno, &cx231xx_devused);
}
-static void cx231xx_media_device_register(struct cx231xx *dev,
- struct usb_device *udev)
+static int cx231xx_media_device_init(struct cx231xx *dev,
+ struct usb_device *udev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device *mdev;
- int ret;
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev)
- return;
+ return -ENOMEM;
mdev->dev = dev->dev;
strlcpy(mdev->model, dev->board.name, sizeof(mdev->model));
@@ -1224,35 +1224,30 @@ static void cx231xx_media_device_register(struct cx231xx *dev,
mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
mdev->driver_version = LINUX_VERSION_CODE;
- ret = media_device_register(mdev);
- if (ret) {
- dev_err(dev->dev,
- "Couldn't create a media device. Error: %d\n",
- ret);
- kfree(mdev);
- return;
- }
+ media_device_init(mdev);
dev->media_dev = mdev;
#endif
+ return 0;
}
-static void cx231xx_create_media_graph(struct cx231xx *dev)
+static int cx231xx_create_media_graph(struct cx231xx *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device *mdev = dev->media_dev;
struct media_entity *entity;
struct media_entity *tuner = NULL, *decoder = NULL;
+ int ret;
if (!mdev)
- return;
+ return 0;
media_device_for_each_entity(entity, mdev) {
- switch (entity->type) {
- case MEDIA_ENT_T_V4L2_SUBDEV_TUNER:
+ switch (entity->function) {
+ case MEDIA_ENT_F_TUNER:
tuner = entity;
break;
- case MEDIA_ENT_T_V4L2_SUBDEV_DECODER:
+ case MEDIA_ENT_F_ATV_DECODER:
decoder = entity;
break;
}
@@ -1261,16 +1256,24 @@ static void cx231xx_create_media_graph(struct cx231xx *dev)
/* Analog setup, using tuner as a link */
if (!decoder)
- return;
+ return 0;
- if (tuner)
- media_entity_create_link(tuner, 0, decoder, 0,
- MEDIA_LNK_FL_ENABLED);
- media_entity_create_link(decoder, 1, &dev->vdev.entity, 0,
- MEDIA_LNK_FL_ENABLED);
- media_entity_create_link(decoder, 2, &dev->vbi_dev.entity, 0,
- MEDIA_LNK_FL_ENABLED);
+ if (tuner) {
+ ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT, decoder, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret < 0)
+ return ret;
+ }
+ ret = media_create_pad_link(decoder, 1, &dev->vdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret < 0)
+ return ret;
+ ret = media_create_pad_link(decoder, 2, &dev->vbi_dev.entity, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret < 0)
+ return ret;
#endif
+ return 0;
}
/*
@@ -1660,8 +1663,12 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- /* Register the media controller */
- cx231xx_media_device_register(dev, udev);
+ /* Initialize the media controller */
+ retval = cx231xx_media_device_init(dev, udev);
+ if (retval) {
+ dev_err(d, "cx231xx_media_device_init failed\n");
+ goto err_media_init;
+ }
/* Create v4l2 device */
#ifdef CONFIG_MEDIA_CONTROLLER
@@ -1732,9 +1739,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* load other modules required */
request_modules(dev);
- cx231xx_create_media_graph(dev);
+ retval = cx231xx_create_media_graph(dev);
+ if (retval < 0)
+ goto done;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ retval = media_device_register(dev->media_dev);
+#endif
+
+done:
+ if (retval < 0)
+ cx231xx_release_resources(dev);
+ return retval;
- return 0;
err_video_alt:
/* cx231xx_uninit_dev: */
cx231xx_close_extension(dev);
@@ -1746,6 +1763,8 @@ err_video_alt:
err_init:
v4l2_device_unregister(&dev->v4l2_dev);
err_v4l2:
+ cx231xx_unregister_media_device(dev);
+err_media_init:
usb_set_intfdata(interface, NULL);
err_if:
usb_put_dev(udev);
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index e3594b9fab4a..b8d5b2be9293 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -551,10 +551,14 @@ static int register_dvb(struct cx231xx_dvb *dvb,
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
- dvb_create_media_graph(&dvb->adapter);
+ result = dvb_create_media_graph(&dvb->adapter, false);
+ if (result < 0)
+ goto fail_create_graph;
return 0;
+fail_create_graph:
+ dvb_net_release(&dvb->net);
fail_fe_conn:
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
fail_fe_mem:
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index a70850fe6235..9b88cd8127ac 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -106,7 +106,7 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
struct media_device *mdev = dev->media_dev;
struct media_entity *entity, *decoder = NULL, *source;
struct media_link *link, *found_link = NULL;
- int i, ret, active_links = 0;
+ int ret, active_links = 0;
if (!mdev)
return 0;
@@ -119,7 +119,7 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
* this should be enough for the actual needs.
*/
media_device_for_each_entity(entity, mdev) {
- if (entity->type == MEDIA_ENT_T_V4L2_SUBDEV_DECODER) {
+ if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
decoder = entity;
break;
}
@@ -127,8 +127,7 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
if (!decoder)
return 0;
- for (i = 0; i < decoder->num_links; i++) {
- link = &decoder->links[i];
+ list_for_each_entry(link, &decoder->links, list) {
if (link->sink->entity == decoder) {
found_link = link;
if (link->flags & MEDIA_LNK_FL_ENABLED)
@@ -141,11 +140,10 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev)
return 0;
source = found_link->source->entity;
- for (i = 0; i < source->num_links; i++) {
+ list_for_each_entry(link, &source->links, list) {
struct media_entity *sink;
int flags = 0;
- link = &source->links[i];
sink = link->sink->entity;
if (sink == entity)
@@ -2177,7 +2175,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video");
#if defined(CONFIG_MEDIA_CONTROLLER)
dev->video_pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&dev->vdev.entity, 1, &dev->video_pad, 0);
+ ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
if (ret < 0)
dev_err(dev->dev, "failed to initialize video media entity!\n");
#endif
@@ -2204,7 +2202,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
#if defined(CONFIG_MEDIA_CONTROLLER)
dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad, 0);
+ ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
if (ret < 0)
dev_err(dev->dev, "failed to initialize vbi media entity!\n");
#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index f5df9eaba04f..f0565bf3673e 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -400,17 +400,16 @@ skip_feed_stop:
return ret;
}
-static void dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap)
+static int dvb_usbv2_media_device_init(struct dvb_usb_adapter *adap)
{
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
struct media_device *mdev;
struct dvb_usb_device *d = adap_to_d(adap);
struct usb_device *udev = d->udev;
- int ret;
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev)
- return;
+ return -ENOMEM;
mdev->dev = &udev->dev;
strlcpy(mdev->model, d->name, sizeof(mdev->model));
@@ -420,19 +419,21 @@ static void dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap)
mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
mdev->driver_version = LINUX_VERSION_CODE;
- ret = media_device_register(mdev);
- if (ret) {
- dev_err(&d->udev->dev,
- "Couldn't create a media device. Error: %d\n",
- ret);
- kfree(mdev);
- return;
- }
+ media_device_init(mdev);
dvb_register_media_controller(&adap->dvb_adap, mdev);
dev_info(&d->udev->dev, "media controller created\n");
+#endif
+ return 0;
+}
+static int dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ return media_device_register(adap->dvb_adap.mdev);
+#else
+ return 0;
#endif
}
@@ -444,6 +445,7 @@ static void dvb_usbv2_media_device_unregister(struct dvb_usb_adapter *adap)
return;
media_device_unregister(adap->dvb_adap.mdev);
+ media_device_cleanup(adap->dvb_adap.mdev);
kfree(adap->dvb_adap.mdev);
adap->dvb_adap.mdev = NULL;
@@ -467,7 +469,12 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
adap->dvb_adap.priv = adap;
- dvb_usbv2_media_device_register(adap);
+ ret = dvb_usbv2_media_device_init(adap);
+ if (ret < 0) {
+ dev_dbg(&d->udev->dev, "%s: dvb_usbv2_media_device_init() failed=%d\n",
+ __func__, ret);
+ goto err_dvb_register_mc;
+ }
if (d->props->read_mac_address) {
ret = d->props->read_mac_address(adap,
@@ -518,6 +525,7 @@ err_dvb_dmxdev_init:
dvb_dmx_release(&adap->demux);
err_dvb_dmx_init:
dvb_usbv2_media_device_unregister(adap);
+err_dvb_register_mc:
dvb_unregister_adapter(&adap->dvb_adap);
err_dvb_register_adapter:
adap->dvb_adap.priv = NULL;
@@ -534,7 +542,6 @@ static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
adap->demux.dmx.close(&adap->demux.dmx);
dvb_dmxdev_release(&adap->dmxdev);
dvb_dmx_release(&adap->demux);
- dvb_usbv2_media_device_unregister(adap);
dvb_unregister_adapter(&adap->dvb_adap);
}
@@ -698,9 +705,13 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
}
}
- dvb_create_media_graph(&adap->dvb_adap);
+ ret = dvb_create_media_graph(&adap->dvb_adap, true);
+ if (ret < 0)
+ goto err_dvb_unregister_frontend;
- return 0;
+ ret = dvb_usbv2_media_device_register(adap);
+
+ return ret;
err_dvb_unregister_frontend:
for (i = count_registered - 1; i >= 0; i--)
@@ -840,6 +851,7 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
+ dvb_usbv2_media_device_unregister(&d->adapter[i]);
}
}
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index 1710f9038d75..b669deccc34c 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -10,6 +10,7 @@
#include <linux/vmalloc.h>
#include <linux/i2c.h>
+#include <media/tuner.h>
#include "mxl111sf.h"
#include "mxl111sf-reg.h"
@@ -868,6 +869,10 @@ static struct mxl111sf_tuner_config mxl_tuner_config = {
static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
{
struct mxl111sf_state *state = adap_to_priv(adap);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ struct media_device *mdev = dvb_get_media_controller(&adap->dvb_adap);
+ int ret;
+#endif
int i;
pr_debug("%s()\n", __func__);
@@ -879,6 +884,21 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength;
}
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ state->tuner.function = MEDIA_ENT_F_TUNER;
+ state->tuner.name = "mxl111sf tuner";
+ state->tuner_pads[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->tuner_pads[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&state->tuner,
+ TUNER_NUM_PADS, state->tuner_pads);
+ if (ret)
+ return ret;
+
+ ret = media_device_register_entity(mdev, &state->tuner);
+ if (ret)
+ return ret;
+#endif
return 0;
}
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
index ee70df1f1e94..846260e0eec0 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -17,6 +17,7 @@
#define DVB_USB_LOG_PREFIX "mxl111sf"
#include "dvb_usb.h"
#include <media/tveeprom.h>
+#include <media/media-entity.h>
#define MXL_EP1_REG_READ 1
#define MXL_EP2_REG_WRITE 2
@@ -85,6 +86,10 @@ struct mxl111sf_state {
struct mutex fe_lock;
u8 num_frontends;
struct mxl111sf_adap_state adap_state[3];
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ struct media_entity tuner;
+ struct media_pad tuner_pads[2];
+#endif
};
int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
index 8a260c854653..9ddfcab268be 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -95,17 +95,16 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
return dvb_usb_ctrl_feed(dvbdmxfeed, 0);
}
-static void dvb_usb_media_device_register(struct dvb_usb_adapter *adap)
+static int dvb_usb_media_device_init(struct dvb_usb_adapter *adap)
{
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
struct media_device *mdev;
struct dvb_usb_device *d = adap->dev;
struct usb_device *udev = d->udev;
- int ret;
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev)
- return;
+ return -ENOMEM;
mdev->dev = &udev->dev;
strlcpy(mdev->model, d->desc->name, sizeof(mdev->model));
@@ -115,18 +114,22 @@ static void dvb_usb_media_device_register(struct dvb_usb_adapter *adap)
mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
mdev->driver_version = LINUX_VERSION_CODE;
- ret = media_device_register(mdev);
- if (ret) {
- dev_err(&d->udev->dev,
- "Couldn't create a media device. Error: %d\n",
- ret);
- kfree(mdev);
- return;
- }
+ media_device_init(mdev);
+
dvb_register_media_controller(&adap->dvb_adap, mdev);
dev_info(&d->udev->dev, "media controller created\n");
#endif
+ return 0;
+}
+
+static int dvb_usb_media_device_register(struct dvb_usb_adapter *adap)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ return media_device_register(adap->dvb_adap.mdev);
+#else
+ return 0;
+#endif
}
static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap)
@@ -136,6 +139,7 @@ static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap)
return;
media_device_unregister(adap->dvb_adap.mdev);
+ media_device_cleanup(adap->dvb_adap.mdev);
kfree(adap->dvb_adap.mdev);
adap->dvb_adap.mdev = NULL;
#endif
@@ -154,7 +158,11 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
}
adap->dvb_adap.priv = adap;
- dvb_usb_media_device_register(adap);
+ ret = dvb_usb_media_device_init(adap);
+ if (ret < 0) {
+ deb_info("dvb_usb_media_device_init failed: error %d", ret);
+ goto err_mc;
+ }
if (adap->dev->props.read_mac_address) {
if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0)
@@ -204,6 +212,7 @@ err_dmx_dev:
dvb_dmx_release(&adap->demux);
err_dmx:
dvb_usb_media_device_unregister(adap);
+err_mc:
dvb_unregister_adapter(&adap->dvb_adap);
err:
return ret;
@@ -318,10 +327,16 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
adap->num_frontends_initialized++;
}
+ if (ret)
+ return ret;
- dvb_create_media_graph(&adap->dvb_adap);
+ ret = dvb_create_media_graph(&adap->dvb_adap, true);
+ if (ret)
+ return ret;
- return 0;
+ ret = dvb_usb_media_device_register(adap);
+
+ return ret;
}
int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index c945e4c2fbd4..8abbd3cc8eba 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -361,10 +361,11 @@ static void *siano_media_device_register(struct smsusb_device_t *dev,
mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
mdev->driver_version = LINUX_VERSION_CODE;
+ media_device_init(mdev);
+
ret = media_device_register(mdev);
if (ret) {
- pr_err("Couldn't create a media device. Error: %d\n",
- ret);
+ media_device_cleanup(mdev);
kfree(mdev);
return NULL;
}
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 39abbafad796..4e7148815a78 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1656,6 +1656,7 @@ static void uvc_delete(struct uvc_device *dev)
#ifdef CONFIG_MEDIA_CONTROLLER
if (media_devnode_is_registered(&dev->mdev.devnode))
media_device_unregister(&dev->mdev);
+ media_device_cleanup(&dev->mdev);
#endif
list_for_each_safe(p, n, &dev->chains) {
@@ -1906,7 +1907,7 @@ static int uvc_probe(struct usb_interface *intf,
"linux-uvc-devel mailing list.\n");
}
- /* Register the media and V4L2 devices. */
+ /* Initialize the media device and register the V4L2 device. */
#ifdef CONFIG_MEDIA_CONTROLLER
dev->mdev.dev = &intf->dev;
strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
@@ -1916,8 +1917,7 @@ static int uvc_probe(struct usb_interface *intf,
strcpy(dev->mdev.bus_info, udev->devpath);
dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
dev->mdev.driver_version = LINUX_VERSION_CODE;
- if (media_device_register(&dev->mdev) < 0)
- goto error;
+ media_device_init(&dev->mdev);
dev->vdev.mdev = &dev->mdev;
#endif
@@ -1936,6 +1936,11 @@ static int uvc_probe(struct usb_interface *intf,
if (uvc_register_chains(dev) < 0)
goto error;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ /* Register the media device node */
+ if (media_device_register(&dev->mdev) < 0)
+ goto error;
+#endif
/* Save our data pointer in the interface data. */
usb_set_intfdata(intf, dev);
diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index dc56a59ecadc..ac386bb547e6 100644
--- a/drivers/media/usb/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
@@ -19,12 +19,8 @@
#include "uvcvideo.h"
-/* ------------------------------------------------------------------------
- * Video subdevices registration and unregistration
- */
-
-static int uvc_mc_register_entity(struct uvc_video_chain *chain,
- struct uvc_entity *entity)
+static int uvc_mc_create_links(struct uvc_video_chain *chain,
+ struct uvc_entity *entity)
{
const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
struct media_entity *sink;
@@ -56,16 +52,13 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
continue;
remote_pad = remote->num_pads - 1;
- ret = media_entity_create_link(source, remote_pad,
+ ret = media_create_pad_link(source, remote_pad,
sink, i, flags);
if (ret < 0)
return ret;
}
- if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
- return 0;
-
- return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev);
+ return 0;
}
static struct v4l2_subdev_ops uvc_subdev_ops = {
@@ -79,7 +72,8 @@ void uvc_mc_cleanup_entity(struct uvc_entity *entity)
media_entity_cleanup(&entity->vdev->entity);
}
-static int uvc_mc_init_entity(struct uvc_entity *entity)
+static int uvc_mc_init_entity(struct uvc_video_chain *chain,
+ struct uvc_entity *entity)
{
int ret;
@@ -88,11 +82,17 @@ static int uvc_mc_init_entity(struct uvc_entity *entity)
strlcpy(entity->subdev.name, entity->name,
sizeof(entity->subdev.name));
- ret = media_entity_init(&entity->subdev.entity,
- entity->num_pads, entity->pads, 0);
+ ret = media_entity_pads_init(&entity->subdev.entity,
+ entity->num_pads, entity->pads);
+
+ if (ret < 0)
+ return ret;
+
+ ret = v4l2_device_register_subdev(&chain->dev->vdev,
+ &entity->subdev);
} else if (entity->vdev != NULL) {
- ret = media_entity_init(&entity->vdev->entity,
- entity->num_pads, entity->pads, 0);
+ ret = media_entity_pads_init(&entity->vdev->entity,
+ entity->num_pads, entity->pads);
if (entity->flags & UVC_ENTITY_FLAG_DEFAULT)
entity->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
} else
@@ -107,7 +107,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain)
int ret;
list_for_each_entry(entity, &chain->entities, chain) {
- ret = uvc_mc_init_entity(entity);
+ ret = uvc_mc_init_entity(chain, entity);
if (ret < 0) {
uvc_printk(KERN_INFO, "Failed to initialize entity for "
"entity %u\n", entity->id);
@@ -116,9 +116,9 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain)
}
list_for_each_entry(entity, &chain->entities, chain) {
- ret = uvc_mc_register_entity(chain, entity);
+ ret = uvc_mc_create_links(chain, entity);
if (ret < 0) {
- uvc_printk(KERN_INFO, "Failed to register entity for "
+ uvc_printk(KERN_INFO, "Failed to create links for "
"entity %u\n", entity->id);
return ret;
}
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 581e21ad6801..76496fd282aa 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -134,8 +134,9 @@ struct tuner {
unsigned int type; /* chip type id */
void *config;
const char *name;
+
#if defined(CONFIG_MEDIA_CONTROLLER)
- struct media_pad pad;
+ struct media_pad pad[TUNER_NUM_PADS];
#endif
};
@@ -695,11 +696,12 @@ static int tuner_probe(struct i2c_client *client,
/* Should be just before return */
register_client:
#if defined(CONFIG_MEDIA_CONTROLLER)
- t->pad.flags = MEDIA_PAD_FL_SOURCE;
- t->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_TUNER;
+ t->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ t->pad[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ t->sd.entity.function = MEDIA_ENT_F_TUNER;
t->sd.entity.name = t->name;
- ret = media_entity_init(&t->sd.entity, 1, &t->pad, 0);
+ ret = media_entity_pads_init(&t->sd.entity, TUNER_NUM_PADS, &t->pad[0]);
if (ret < 0) {
tuner_err("failed to initialize media entity!\n");
kfree(t);
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 6b1eaeddbdb3..d8e5994cccf1 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -194,9 +194,12 @@ static void v4l2_device_release(struct device *cd)
mutex_unlock(&videodev_lock);
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV)
- media_device_unregister_entity(&vdev->entity);
+ if (v4l2_dev->mdev) {
+ /* Remove interfaces and interface links */
+ media_devnode_remove(vdev->intf_devnode);
+ if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN)
+ media_device_unregister_entity(&vdev->entity);
+ }
#endif
/* Do not call v4l2_device_put if there is no release callback set.
@@ -723,6 +726,91 @@ static void determine_valid_ioctls(struct video_device *vdev)
BASE_VIDIOC_PRIVATE);
}
+static int video_register_media_controller(struct video_device *vdev, int type)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ u32 intf_type;
+ int ret;
+
+ if (!vdev->v4l2_dev->mdev)
+ return 0;
+
+ vdev->entity.function = MEDIA_ENT_F_UNKNOWN;
+
+ switch (type) {
+ case VFL_TYPE_GRABBER:
+ intf_type = MEDIA_INTF_T_V4L_VIDEO;
+ vdev->entity.function = MEDIA_ENT_F_IO_V4L;
+ break;
+ case VFL_TYPE_VBI:
+ intf_type = MEDIA_INTF_T_V4L_VBI;
+ vdev->entity.function = MEDIA_ENT_F_IO_VBI;
+ break;
+ case VFL_TYPE_SDR:
+ intf_type = MEDIA_INTF_T_V4L_SWRADIO;
+ vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO;
+ break;
+ case VFL_TYPE_RADIO:
+ intf_type = MEDIA_INTF_T_V4L_RADIO;
+ /*
+ * Radio doesn't have an entity at the V4L2 side to represent
+ * radio input or output. Instead, the audio input/output goes
+ * via either physical wires or ALSA.
+ */
+ break;
+ case VFL_TYPE_SUBDEV:
+ intf_type = MEDIA_INTF_T_V4L_SUBDEV;
+ /* Entity will be created via v4l2_device_register_subdev() */
+ break;
+ default:
+ return 0;
+ }
+
+ if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) {
+ vdev->entity.name = vdev->name;
+
+ /* Needed just for backward compatibility with legacy MC API */
+ vdev->entity.info.dev.major = VIDEO_MAJOR;
+ vdev->entity.info.dev.minor = vdev->minor;
+
+ ret = media_device_register_entity(vdev->v4l2_dev->mdev,
+ &vdev->entity);
+ if (ret < 0) {
+ printk(KERN_WARNING
+ "%s: media_device_register_entity failed\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ vdev->intf_devnode = media_devnode_create(vdev->v4l2_dev->mdev,
+ intf_type,
+ 0, VIDEO_MAJOR,
+ vdev->minor);
+ if (!vdev->intf_devnode) {
+ media_device_unregister_entity(&vdev->entity);
+ return -ENOMEM;
+ }
+
+ if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) {
+ struct media_link *link;
+
+ link = media_create_intf_link(&vdev->entity,
+ &vdev->intf_devnode->intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link) {
+ media_devnode_remove(vdev->intf_devnode);
+ media_device_unregister_entity(&vdev->entity);
+ return -ENOMEM;
+ }
+ }
+
+ /* FIXME: how to create the other interface links? */
+
+#endif
+ return 0;
+}
+
/**
* __video_register_device - register video4linux devices
* @vdev: video device structure we want to register
@@ -918,22 +1006,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
/* Increase v4l2_device refcount */
v4l2_device_get(vdev->v4l2_dev);
-#if defined(CONFIG_MEDIA_CONTROLLER)
/* Part 5: Register the entity. */
- if (vdev->v4l2_dev->mdev &&
- vdev->vfl_type != VFL_TYPE_SUBDEV) {
- vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
- vdev->entity.name = vdev->name;
- vdev->entity.info.dev.major = VIDEO_MAJOR;
- vdev->entity.info.dev.minor = vdev->minor;
- ret = media_device_register_entity(vdev->v4l2_dev->mdev,
- &vdev->entity);
- if (ret < 0)
- printk(KERN_WARNING
- "%s: media_device_register_entity failed\n",
- __func__);
- }
-#endif
+ ret = video_register_media_controller(vdev, type);
+
/* Part 6: Activate this minor. The char device can now be used. */
set_bit(V4L2_FL_REGISTERED, &vdev->flags);
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 7129e438f29e..06fa5f1b2cff 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -180,26 +180,26 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
return -ENODEV;
sd->v4l2_dev = v4l2_dev;
- if (sd->internal_ops && sd->internal_ops->registered) {
- err = sd->internal_ops->registered(sd);
- if (err)
- goto error_module;
- }
-
/* This just returns 0 if either of the two args is NULL */
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);
if (err)
- goto error_unregister;
+ goto error_module;
#if defined(CONFIG_MEDIA_CONTROLLER)
/* Register the entity. */
if (v4l2_dev->mdev) {
err = media_device_register_entity(v4l2_dev->mdev, entity);
if (err < 0)
- goto error_unregister;
+ goto error_module;
}
#endif
+ if (sd->internal_ops && sd->internal_ops->registered) {
+ err = sd->internal_ops->registered(sd);
+ if (err)
+ goto error_unregister;
+ }
+
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
spin_unlock(&v4l2_dev->lock);
@@ -207,8 +207,9 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
return 0;
error_unregister:
- if (sd->internal_ops && sd->internal_ops->unregistered)
- sd->internal_ops->unregistered(sd);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_device_unregister_entity(entity);
+#endif
error_module:
if (!sd->owner_v4l2_dev)
module_put(sd->owner);
@@ -258,6 +259,19 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
#if defined(CONFIG_MEDIA_CONTROLLER)
sd->entity.info.dev.major = VIDEO_MAJOR;
sd->entity.info.dev.minor = vdev->minor;
+
+ /* Interface is created by __video_register_device() */
+ if (vdev->v4l2_dev->mdev) {
+ struct media_link *link;
+
+ link = media_create_intf_link(&sd->entity,
+ &vdev->intf_devnode->intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link) {
+ err = -ENOMEM;
+ goto clean_up;
+ }
+ }
#endif
sd->devnode = vdev;
}
@@ -294,7 +308,10 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
#if defined(CONFIG_MEDIA_CONTROLLER)
if (v4l2_dev->mdev) {
- media_entity_remove_links(&sd->entity);
+ /*
+ * No need to explicitly remove links, as both pads and
+ * links are removed by the function below, in the right order
+ */
media_device_unregister_entity(&sd->entity);
}
#endif
diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c
index 5d673357f75f..fc5ff8b215f9 100644
--- a/drivers/media/v4l2-core/v4l2-flash-led-class.c
+++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c
@@ -651,11 +651,11 @@ struct v4l2_flash *v4l2_flash_init(
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
strlcpy(sd->name, config->dev_name, sizeof(sd->name));
- ret = media_entity_init(&sd->entity, 0, NULL, 0);
+ ret = media_entity_pads_init(&sd->entity, 0, NULL);
if (ret < 0)
return ERR_PTR(ret);
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+ sd->entity.function = MEDIA_ENT_F_FLASH;
ret = v4l2_flash_init_controls(v4l2_flash, config);
if (ret < 0)
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 83615b8fb46a..d63083803144 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -526,7 +526,7 @@ static int
v4l2_subdev_link_validate_get_format(struct media_pad *pad,
struct v4l2_subdev_format *fmt)
{
- if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) {
+ if (is_media_entity_v4l2_subdev(pad->entity)) {
struct v4l2_subdev *sd =
media_entity_to_v4l2_subdev(pad->entity);
@@ -535,9 +535,9 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
}
- WARN(pad->entity->type != MEDIA_ENT_T_DEVNODE_V4L,
+ WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
"Driver bug! Wrong media entity type 0x%08x, entity %s\n",
- pad->entity->type, pad->entity->name);
+ pad->entity->function, pad->entity->name);
return -EINVAL;
}
@@ -584,7 +584,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
sd->host_priv = NULL;
#if defined(CONFIG_MEDIA_CONTROLLER)
sd->entity.name = sd->name;
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
#endif
}
EXPORT_SYMBOL(v4l2_subdev_init);
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 21e7255e3d96..5a58e440f4a7 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1007,6 +1007,7 @@ static const struct tegra_smmu_soc tegra124_smmu_soc = {
.num_swgroups = ARRAY_SIZE(tegra124_swgroups),
.supports_round_robin_arbitration = true,
.supports_request_limit = true,
+ .num_tlb_lines = 32,
.num_asids = 128,
};
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c
index 63445ea6b0bf..3f24ecbe2576 100644
--- a/drivers/mfd/88pm80x.c
+++ b/drivers/mfd/88pm80x.c
@@ -135,7 +135,7 @@ EXPORT_SYMBOL_GPL(pm80x_deinit);
#ifdef CONFIG_PM_SLEEP
static int pm80x_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct pm80x_chip *chip = i2c_get_clientdata(client);
if (chip && chip->wu_flag)
@@ -147,7 +147,7 @@ static int pm80x_suspend(struct device *dev)
static int pm80x_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct pm80x_chip *chip = i2c_get_clientdata(client);
if (chip && chip->wu_flag)
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 3269a9990b24..25e1aafae60c 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -705,10 +705,12 @@ int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
chip->osc_status);
mutex_lock(&chip->osc_lock);
- /*Update voting status */
+ /* Update voting status */
chip->osc_vote &= ~(client);
- /* If reference group is off and this is the last client to release
- * - turn off */
+ /*
+ * If reference group is off and this is the last client to release
+ * - turn off
+ */
if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
(chip->osc_vote == REF_GP_NO_CLIENTS)) {
chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
@@ -1218,7 +1220,7 @@ static int pm860x_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int pm860x_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct pm860x_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
@@ -1228,7 +1230,7 @@ static int pm860x_suspend(struct device *dev)
static int pm860x_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct pm860x_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
@@ -1265,6 +1267,7 @@ static struct i2c_driver pm860x_driver = {
static int __init pm860x_i2c_init(void)
{
int ret;
+
ret = i2c_add_driver(&pm860x_driver);
if (ret != 0)
pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 4d92df6ef9fe..9ca66de0c1c1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -211,7 +211,7 @@ config MFD_DA9062
of the device.
config MFD_DA9063
- bool "Dialog Semiconductor DA9063 PMIC Support"
+ tristate "Dialog Semiconductor DA9063 PMIC Support"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -1370,24 +1370,30 @@ config MFD_ARIZONA
bool
config MFD_ARIZONA_I2C
- tristate "Wolfson Microelectronics Arizona platform with I2C"
+ tristate "Cirrus Logic/Wolfson Microelectronics Arizona platform with I2C"
select MFD_ARIZONA
select MFD_CORE
select REGMAP_I2C
depends on I2C
help
- Support for the Wolfson Microelectronics Arizona platform audio SoC
- core functionality controlled via I2C.
+ Support for the Cirrus Logic/Wolfson Microelectronics Arizona platform
+ audio SoC core functionality controlled via I2C.
config MFD_ARIZONA_SPI
- tristate "Wolfson Microelectronics Arizona platform with SPI"
+ tristate "Cirrus Logic/Wolfson Microelectronics Arizona platform with SPI"
select MFD_ARIZONA
select MFD_CORE
select REGMAP_SPI
depends on SPI_MASTER
help
- Support for the Wolfson Microelectronics Arizona platform audio SoC
- core functionality controlled via I2C.
+ Support for the Cirrus Logic/Wolfson Microelectronics Arizona platform
+ audio SoC core functionality controlled via I2C.
+
+config MFD_CS47L24
+ bool "Cirrus Logic CS47L24 and WM1831"
+ depends on MFD_ARIZONA
+ help
+ Support for Cirrus Logic CS47L24 and WM1831 low power audio SoC
config MFD_WM5102
bool "Wolfson Microelectronics WM5102"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a8b76b81b467..0f230a6103f8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -51,6 +51,9 @@ endif
ifeq ($(CONFIG_MFD_WM8998),y)
obj-$(CONFIG_MFD_ARIZONA) += wm8998-tables.o
endif
+ifeq ($(CONFIG_MFD_CS47L24),y)
+obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o
+endif
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
wm831x-objs += wm831x-auxadc.o
@@ -61,7 +64,8 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
-obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o
+wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o
+obj-$(CONFIG_MFD_WM8994) += wm8994.o
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
index 29b6a2d4ac72..3ba19a45f199 100644
--- a/drivers/mfd/aat2870-core.c
+++ b/drivers/mfd/aat2870-core.c
@@ -373,11 +373,8 @@ static int aat2870_i2c_probe(struct i2c_client *client,
aat2870 = devm_kzalloc(&client->dev, sizeof(struct aat2870_data),
GFP_KERNEL);
- if (!aat2870) {
- dev_err(&client->dev,
- "Failed to allocate memory for aat2870\n");
+ if (!aat2870)
return -ENOMEM;
- }
aat2870->dev = &client->dev;
dev_set_drvdata(aat2870->dev, aat2870);
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index f0afb44271f8..6a5a98806cb8 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -381,9 +381,11 @@ static int ab3100_event_registers_startup_state_get(struct device *dev,
u8 *event)
{
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
+
if (!ab3100->startup_events_read)
return -EAGAIN; /* Try again later */
memcpy(event, ab3100->startup_events, 3);
+
return 0;
}
@@ -858,10 +860,8 @@ static int ab3100_probe(struct i2c_client *client,
int i;
ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL);
- if (!ab3100) {
- dev_err(&client->dev, "could not allocate AB3100 device\n");
+ if (!ab3100)
return -ENOMEM;
- }
/* Initialize data structure */
mutex_init(&ab3100->access_mutex);
@@ -883,20 +883,17 @@ static int ab3100_probe(struct i2c_client *client,
for (i = 0; ids[i].id != 0x0; i++) {
if (ids[i].id == ab3100->chip_id) {
- if (ids[i].name != NULL) {
- snprintf(&ab3100->chip_name[0],
- sizeof(ab3100->chip_name) - 1,
- "AB3100 %s",
- ids[i].name);
+ if (ids[i].name)
break;
- } else {
- dev_err(&client->dev,
- "AB3000 is not supported\n");
- goto exit_no_detect;
- }
+
+ dev_err(&client->dev, "AB3000 is not supported\n");
+ goto exit_no_detect;
}
}
+ snprintf(&ab3100->chip_name[0],
+ sizeof(ab3100->chip_name) - 1, "AB3100 %s", ids[i].name);
+
if (ids[i].id == 0x0) {
dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n",
ab3100->chip_id);
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c
index f391c5fee1b0..55b207a4b336 100644
--- a/drivers/mfd/ab3100-otp.c
+++ b/drivers/mfd/ab3100-otp.c
@@ -188,10 +188,9 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
int i;
otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL);
- if (!otp) {
- dev_err(&pdev->dev, "could not allocate AB3100 OTP device\n");
+ if (!otp)
return -ENOMEM;
- }
+
otp->dev = &pdev->dev;
/* Replace platform data coming in with a local struct */
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index fefbe4cfa61d..f3d689176fc2 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -113,7 +113,7 @@
#define AB8500_SWITCH_OFF_STATUS 0x00
#define AB8500_TURN_ON_STATUS 0x00
-#define AB8505_TURN_ON_STATUS_2 0x04
+#define AB8505_TURN_ON_STATUS_2 0x04
#define AB8500_CH_USBCH_STAT1_REG 0x02
#define VBUS_DET_DBNC100 0x02
@@ -211,7 +211,7 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
/*
* Put the u8 bank and u8 register together into a an u16.
* The bank on higher 8 bits and register in lower 8 bits.
- * */
+ */
u16 addr = ((u16)bank) << 8 | reg;
dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
@@ -243,8 +243,6 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
u8 reg, u8 *value)
{
int ret;
- /* put the u8 bank and u8 reg together into a an u16.
- * bank on higher 8 bits and reg in lower */
u16 addr = ((u16)bank) << 8 | reg;
mutex_lock(&ab8500->lock);
@@ -278,8 +276,6 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
int ret;
- /* put the u8 bank and u8 reg together into a an u16.
- * bank on higher 8 bits and reg in lower */
u16 addr = ((u16)bank) << 8 | reg;
mutex_lock(&ab8500->lock);
@@ -449,12 +445,12 @@ static void update_latch_offset(u8 *offset, int i)
{
/* Fix inconsistent ITFromLatch25 bit mapping... */
if (unlikely(*offset == 17))
- *offset = 24;
+ *offset = 24;
/* Fix inconsistent ab8540 bit mapping... */
if (unlikely(*offset == 16))
- *offset = 25;
+ *offset = 25;
if ((i == 3) && (*offset >= 24))
- *offset += 2;
+ *offset += 2;
}
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
@@ -590,12 +586,12 @@ static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
/* If ->irq_base is zero this will give a linear mapping */
ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node,
- num_irqs, 0,
- &ab8500_irq_ops, ab8500);
+ num_irqs, 0,
+ &ab8500_irq_ops, ab8500);
if (!ab8500->domain) {
dev_err(ab8500->dev, "Failed to create irqdomain\n");
- return -ENOSYS;
+ return -ENODEV;
}
return 0;
@@ -609,442 +605,28 @@ int ab8500_suspend(struct ab8500 *ab8500)
return 0;
}
-static struct resource ab8500_gpadc_resources[] = {
- {
- .name = "HW_CONV_END",
- .start = AB8500_INT_GP_HW_ADC_CONV_END,
- .end = AB8500_INT_GP_HW_ADC_CONV_END,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "SW_CONV_END",
- .start = AB8500_INT_GP_SW_ADC_CONV_END,
- .end = AB8500_INT_GP_SW_ADC_CONV_END,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8505_gpadc_resources[] = {
- {
- .name = "SW_CONV_END",
- .start = AB8500_INT_GP_SW_ADC_CONV_END,
- .end = AB8500_INT_GP_SW_ADC_CONV_END,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_rtc_resources[] = {
- {
- .name = "60S",
- .start = AB8500_INT_RTC_60S,
- .end = AB8500_INT_RTC_60S,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ALARM",
- .start = AB8500_INT_RTC_ALARM,
- .end = AB8500_INT_RTC_ALARM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8540_rtc_resources[] = {
- {
- .name = "1S",
- .start = AB8540_INT_RTC_1S,
- .end = AB8540_INT_RTC_1S,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ALARM",
- .start = AB8500_INT_RTC_ALARM,
- .end = AB8500_INT_RTC_ALARM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_poweronkey_db_resources[] = {
- {
- .name = "ONKEY_DBF",
- .start = AB8500_INT_PON_KEY1DB_F,
- .end = AB8500_INT_PON_KEY1DB_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ONKEY_DBR",
- .start = AB8500_INT_PON_KEY1DB_R,
- .end = AB8500_INT_PON_KEY1DB_R,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_av_acc_detect_resources[] = {
- {
- .name = "ACC_DETECT_1DB_F",
- .start = AB8500_INT_ACC_DETECT_1DB_F,
- .end = AB8500_INT_ACC_DETECT_1DB_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ACC_DETECT_1DB_R",
- .start = AB8500_INT_ACC_DETECT_1DB_R,
- .end = AB8500_INT_ACC_DETECT_1DB_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ACC_DETECT_21DB_F",
- .start = AB8500_INT_ACC_DETECT_21DB_F,
- .end = AB8500_INT_ACC_DETECT_21DB_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ACC_DETECT_21DB_R",
- .start = AB8500_INT_ACC_DETECT_21DB_R,
- .end = AB8500_INT_ACC_DETECT_21DB_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ACC_DETECT_22DB_F",
- .start = AB8500_INT_ACC_DETECT_22DB_F,
- .end = AB8500_INT_ACC_DETECT_22DB_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ACC_DETECT_22DB_R",
- .start = AB8500_INT_ACC_DETECT_22DB_R,
- .end = AB8500_INT_ACC_DETECT_22DB_R,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_charger_resources[] = {
- {
- .name = "MAIN_CH_UNPLUG_DET",
- .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
- .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "MAIN_CHARGE_PLUG_DET",
- .start = AB8500_INT_MAIN_CH_PLUG_DET,
- .end = AB8500_INT_MAIN_CH_PLUG_DET,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_DET_R",
- .start = AB8500_INT_VBUS_DET_R,
- .end = AB8500_INT_VBUS_DET_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_DET_F",
- .start = AB8500_INT_VBUS_DET_F,
- .end = AB8500_INT_VBUS_DET_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_LINK_STATUS",
- .start = AB8500_INT_USB_LINK_STATUS,
- .end = AB8500_INT_USB_LINK_STATUS,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_OVV",
- .start = AB8500_INT_VBUS_OVV,
- .end = AB8500_INT_VBUS_OVV,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_CH_TH_PROT_R",
- .start = AB8500_INT_USB_CH_TH_PROT_R,
- .end = AB8500_INT_USB_CH_TH_PROT_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_CH_TH_PROT_F",
- .start = AB8500_INT_USB_CH_TH_PROT_F,
- .end = AB8500_INT_USB_CH_TH_PROT_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "MAIN_EXT_CH_NOT_OK",
- .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
- .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "MAIN_CH_TH_PROT_R",
- .start = AB8500_INT_MAIN_CH_TH_PROT_R,
- .end = AB8500_INT_MAIN_CH_TH_PROT_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "MAIN_CH_TH_PROT_F",
- .start = AB8500_INT_MAIN_CH_TH_PROT_F,
- .end = AB8500_INT_MAIN_CH_TH_PROT_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_CHARGER_NOT_OKR",
- .start = AB8500_INT_USB_CHARGER_NOT_OKR,
- .end = AB8500_INT_USB_CHARGER_NOT_OKR,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CH_WD_EXP",
- .start = AB8500_INT_CH_WD_EXP,
- .end = AB8500_INT_CH_WD_EXP,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_CH_DROP_END",
- .start = AB8500_INT_VBUS_CH_DROP_END,
- .end = AB8500_INT_VBUS_CH_DROP_END,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_btemp_resources[] = {
- {
- .name = "BAT_CTRL_INDB",
- .start = AB8500_INT_BAT_CTRL_INDB,
- .end = AB8500_INT_BAT_CTRL_INDB,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BTEMP_LOW",
- .start = AB8500_INT_BTEMP_LOW,
- .end = AB8500_INT_BTEMP_LOW,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BTEMP_HIGH",
- .start = AB8500_INT_BTEMP_HIGH,
- .end = AB8500_INT_BTEMP_HIGH,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BTEMP_LOW_MEDIUM",
- .start = AB8500_INT_BTEMP_LOW_MEDIUM,
- .end = AB8500_INT_BTEMP_LOW_MEDIUM,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BTEMP_MEDIUM_HIGH",
- .start = AB8500_INT_BTEMP_MEDIUM_HIGH,
- .end = AB8500_INT_BTEMP_MEDIUM_HIGH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_fg_resources[] = {
- {
- .name = "NCONV_ACCU",
- .start = AB8500_INT_CCN_CONV_ACC,
- .end = AB8500_INT_CCN_CONV_ACC,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATT_OVV",
- .start = AB8500_INT_BATT_OVV,
- .end = AB8500_INT_BATT_OVV,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "LOW_BAT_F",
- .start = AB8500_INT_LOW_BAT_F,
- .end = AB8500_INT_LOW_BAT_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "LOW_BAT_R",
- .start = AB8500_INT_LOW_BAT_R,
- .end = AB8500_INT_LOW_BAT_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CC_INT_CALIB",
- .start = AB8500_INT_CC_INT_CALIB,
- .end = AB8500_INT_CC_INT_CALIB,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "CCEOC",
- .start = AB8500_INT_CCEOC,
- .end = AB8500_INT_CCEOC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_chargalg_resources[] = {};
-
-#ifdef CONFIG_DEBUG_FS
-static struct resource ab8500_debug_resources[] = {
- {
- .name = "IRQ_AB8500",
- /*
- * Number will be filled in. NOTE: this is deliberately
- * not flagged as an IRQ in ordet to avoid remapping using
- * the irqdomain in the MFD core, so that this IRQ passes
- * unremapped to the debug code.
- */
- },
- {
- .name = "IRQ_FIRST",
- .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
- .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "IRQ_LAST",
- .start = AB8500_INT_XTAL32K_KO,
- .end = AB8500_INT_XTAL32K_KO,
- .flags = IORESOURCE_IRQ,
- },
-};
-#endif
-
-static struct resource ab8500_usb_resources[] = {
- {
- .name = "ID_WAKEUP_R",
- .start = AB8500_INT_ID_WAKEUP_R,
- .end = AB8500_INT_ID_WAKEUP_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ID_WAKEUP_F",
- .start = AB8500_INT_ID_WAKEUP_F,
- .end = AB8500_INT_ID_WAKEUP_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_DET_F",
- .start = AB8500_INT_VBUS_DET_F,
- .end = AB8500_INT_VBUS_DET_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_DET_R",
- .start = AB8500_INT_VBUS_DET_R,
- .end = AB8500_INT_VBUS_DET_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_LINK_STATUS",
- .start = AB8500_INT_USB_LINK_STATUS,
- .end = AB8500_INT_USB_LINK_STATUS,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_ADP_PROBE_PLUG",
- .start = AB8500_INT_ADP_PROBE_PLUG,
- .end = AB8500_INT_ADP_PROBE_PLUG,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_ADP_PROBE_UNPLUG",
- .start = AB8500_INT_ADP_PROBE_UNPLUG,
- .end = AB8500_INT_ADP_PROBE_UNPLUG,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8505_iddet_resources[] = {
- {
- .name = "KeyDeglitch",
- .start = AB8505_INT_KEYDEGLITCH,
- .end = AB8505_INT_KEYDEGLITCH,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "KP",
- .start = AB8505_INT_KP,
- .end = AB8505_INT_KP,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "IKP",
- .start = AB8505_INT_IKP,
- .end = AB8505_INT_IKP,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "IKR",
- .start = AB8505_INT_IKR,
- .end = AB8505_INT_IKR,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "KeyStuck",
- .start = AB8505_INT_KEYSTUCK,
- .end = AB8505_INT_KEYSTUCK,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_DET_R",
- .start = AB8500_INT_VBUS_DET_R,
- .end = AB8500_INT_VBUS_DET_R,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "VBUS_DET_F",
- .start = AB8500_INT_VBUS_DET_F,
- .end = AB8500_INT_VBUS_DET_F,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ID_DET_PLUGR",
- .start = AB8500_INT_ID_DET_PLUGR,
- .end = AB8500_INT_ID_DET_PLUGR,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ID_DET_PLUGF",
- .start = AB8500_INT_ID_DET_PLUGF,
- .end = AB8500_INT_ID_DET_PLUGF,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource ab8500_temp_resources[] = {
- {
- .name = "ABX500_TEMP_WARM",
- .start = AB8500_INT_TEMP_WARM,
- .end = AB8500_INT_TEMP_WARM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
static const struct mfd_cell ab8500_bm_devs[] = {
{
.name = "ab8500-charger",
.of_compatible = "stericsson,ab8500-charger",
- .num_resources = ARRAY_SIZE(ab8500_charger_resources),
- .resources = ab8500_charger_resources,
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
},
{
.name = "ab8500-btemp",
.of_compatible = "stericsson,ab8500-btemp",
- .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
- .resources = ab8500_btemp_resources,
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
},
{
.name = "ab8500-fg",
.of_compatible = "stericsson,ab8500-fg",
- .num_resources = ARRAY_SIZE(ab8500_fg_resources),
- .resources = ab8500_fg_resources,
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
},
{
.name = "ab8500-chargalg",
.of_compatible = "stericsson,ab8500-chargalg",
- .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
- .resources = ab8500_chargalg_resources,
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
},
@@ -1055,8 +637,6 @@ static const struct mfd_cell ab8500_devs[] = {
{
.name = "ab8500-debug",
.of_compatible = "stericsson,ab8500-debug",
- .num_resources = ARRAY_SIZE(ab8500_debug_resources),
- .resources = ab8500_debug_resources,
},
#endif
{
@@ -1078,27 +658,19 @@ static const struct mfd_cell ab8500_devs[] = {
{
.name = "ab8500-gpadc",
.of_compatible = "stericsson,ab8500-gpadc",
- .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
- .resources = ab8500_gpadc_resources,
},
{
.name = "ab8500-rtc",
.of_compatible = "stericsson,ab8500-rtc",
- .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
- .resources = ab8500_rtc_resources,
},
{
.name = "ab8500-acc-det",
.of_compatible = "stericsson,ab8500-acc-det",
- .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
- .resources = ab8500_av_acc_detect_resources,
},
{
.name = "ab8500-poweron-key",
.of_compatible = "stericsson,ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
},
{
.name = "ab8500-pwm",
@@ -1126,14 +698,10 @@ static const struct mfd_cell ab8500_devs[] = {
{
.name = "abx500-temp",
.of_compatible = "stericsson,abx500-temp",
- .num_resources = ARRAY_SIZE(ab8500_temp_resources),
- .resources = ab8500_temp_resources,
},
{
.name = "ab8500-usb",
.of_compatible = "stericsson,ab8500-usb",
- .num_resources = ARRAY_SIZE(ab8500_usb_resources),
- .resources = ab8500_usb_resources,
},
{
.name = "ab8500-codec",
@@ -1145,8 +713,6 @@ static const struct mfd_cell ab9540_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
- .num_resources = ARRAY_SIZE(ab8500_debug_resources),
- .resources = ab8500_debug_resources,
},
#endif
{
@@ -1165,23 +731,15 @@ static const struct mfd_cell ab9540_devs[] = {
{
.name = "ab8500-gpadc",
.of_compatible = "stericsson,ab8500-gpadc",
- .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
- .resources = ab8500_gpadc_resources,
},
{
.name = "ab8500-rtc",
- .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
- .resources = ab8500_rtc_resources,
},
{
.name = "ab8500-acc-det",
- .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
- .resources = ab8500_av_acc_detect_resources,
},
{
.name = "ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
},
{
.name = "ab8500-pwm",
@@ -1189,8 +747,6 @@ static const struct mfd_cell ab9540_devs[] = {
},
{
.name = "abx500-temp",
- .num_resources = ARRAY_SIZE(ab8500_temp_resources),
- .resources = ab8500_temp_resources,
},
{
.name = "pinctrl-ab9540",
@@ -1198,16 +754,12 @@ static const struct mfd_cell ab9540_devs[] = {
},
{
.name = "ab9540-usb",
- .num_resources = ARRAY_SIZE(ab8500_usb_resources),
- .resources = ab8500_usb_resources,
},
{
.name = "ab9540-codec",
},
{
.name = "ab-iddet",
- .num_resources = ARRAY_SIZE(ab8505_iddet_resources),
- .resources = ab8505_iddet_resources,
},
};
@@ -1216,8 +768,6 @@ static const struct mfd_cell ab8505_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
- .num_resources = ARRAY_SIZE(ab8500_debug_resources),
- .resources = ab8500_debug_resources,
},
#endif
{
@@ -1233,23 +783,15 @@ static const struct mfd_cell ab8505_devs[] = {
{
.name = "ab8500-gpadc",
.of_compatible = "stericsson,ab8500-gpadc",
- .num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
- .resources = ab8505_gpadc_resources,
},
{
.name = "ab8500-rtc",
- .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
- .resources = ab8500_rtc_resources,
},
{
.name = "ab8500-acc-det",
- .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
- .resources = ab8500_av_acc_detect_resources,
},
{
.name = "ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
},
{
.name = "ab8500-pwm",
@@ -1260,16 +802,12 @@ static const struct mfd_cell ab8505_devs[] = {
},
{
.name = "ab8500-usb",
- .num_resources = ARRAY_SIZE(ab8500_usb_resources),
- .resources = ab8500_usb_resources,
},
{
.name = "ab8500-codec",
},
{
.name = "ab-iddet",
- .num_resources = ARRAY_SIZE(ab8505_iddet_resources),
- .resources = ab8505_iddet_resources,
},
};
@@ -1277,8 +815,6 @@ static const struct mfd_cell ab8540_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
- .num_resources = ARRAY_SIZE(ab8500_debug_resources),
- .resources = ab8500_debug_resources,
},
#endif
{
@@ -1297,18 +833,12 @@ static const struct mfd_cell ab8540_devs[] = {
{
.name = "ab8500-gpadc",
.of_compatible = "stericsson,ab8500-gpadc",
- .num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
- .resources = ab8505_gpadc_resources,
},
{
.name = "ab8500-acc-det",
- .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
- .resources = ab8500_av_acc_detect_resources,
},
{
.name = "ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
},
{
.name = "ab8500-pwm",
@@ -1316,24 +846,18 @@ static const struct mfd_cell ab8540_devs[] = {
},
{
.name = "abx500-temp",
- .num_resources = ARRAY_SIZE(ab8500_temp_resources),
- .resources = ab8500_temp_resources,
},
{
.name = "pinctrl-ab8540",
},
{
.name = "ab8540-usb",
- .num_resources = ARRAY_SIZE(ab8500_usb_resources),
- .resources = ab8500_usb_resources,
},
{
.name = "ab8540-codec",
},
{
.name = "ab-iddet",
- .num_resources = ARRAY_SIZE(ab8505_iddet_resources),
- .resources = ab8505_iddet_resources,
},
};
@@ -1341,8 +865,6 @@ static const struct mfd_cell ab8540_cut1_devs[] = {
{
.name = "ab8500-rtc",
.of_compatible = "stericsson,ab8500-rtc",
- .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
- .resources = ab8500_rtc_resources,
},
};
@@ -1350,8 +872,6 @@ static const struct mfd_cell ab8540_cut2_devs[] = {
{
.name = "ab8540-rtc",
.of_compatible = "stericsson,ab8540-rtc",
- .num_resources = ARRAY_SIZE(ab8540_rtc_resources),
- .resources = ab8540_rtc_resources,
},
};
@@ -1549,7 +1069,7 @@ static struct attribute_group ab9540_attr_group = {
static int ab8500_probe(struct platform_device *pdev)
{
- static const char *switch_off_status[] = {
+ static const char * const switch_off_status[] = {
"Swoff bit programming",
"Thermal protection activation",
"Vbat lower then BattOk falling threshold",
@@ -1558,7 +1078,7 @@ static int ab8500_probe(struct platform_device *pdev)
"Battery level lower than power on reset threshold",
"Power on key 1 pressed longer than 10 seconds",
"DB8500 thermal shutdown"};
- static const char *turn_on_status[] = {
+ static const char * const turn_on_status[] = {
"Battery rising (Vbat)",
"Power On Key 1 dbF",
"Power On Key 2 dbF",
@@ -1750,12 +1270,6 @@ static int ab8500_probe(struct platform_device *pdev)
if (ret)
return ret;
-#ifdef CONFIG_DEBUG_FS
- /* Pass to debugfs */
- ab8500_debug_resources[0].start = ab8500->irq;
- ab8500_debug_resources[0].end = ab8500->irq;
-#endif
-
if (is_ab9540(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 0236cd7cdce4..69d9fffe5b5c 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -242,8 +242,10 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
.first = 0x40,
.last = 0x44,
},
- /* 0x80-0x8B is SIM registers and should
- * not be accessed from here */
+ /*
+ * 0x80-0x8B are SIM registers and should
+ * not be accessed from here
+ */
},
},
[AB8500_USB] = {
@@ -587,8 +589,10 @@ static struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
.first = 0x40,
.last = 0x48,
},
- /* 0x80-0x8B is SIM registers and should
- * not be accessed from here */
+ /*
+ * 0x80-0x8B are SIM registers and should
+ * not be accessed from here
+ */
},
},
[AB8500_USB] = {
@@ -1306,8 +1310,10 @@ static int ab8500_registers_print(struct device *dev, u32 bank,
if (s) {
seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n",
bank, reg, value);
- /* Error is not returned here since
- * the output is wanted in any case */
+ /*
+ * Error is not returned here since
+ * the output is wanted in any case
+ */
if (seq_has_overflowed(s))
return 0;
} else {
@@ -2740,10 +2746,9 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
*cfg = loc;
#ifdef ABB_HWREG_DEBUG
- pr_warn("HWREG request: %s, %s,\n"
- " addr=0x%08X, mask=0x%X, shift=%d" "value=0x%X\n",
- (write) ? "write" : "read",
- REG_FMT_DEC(cfg) ? "decimal" : "hexa",
+ pr_warn("HWREG request: %s, %s,\n", (write) ? "write" : "read",
+ REG_FMT_DEC(cfg) ? "decimal" : "hexa");
+ pr_warn(" addr=0x%08X, mask=0x%X, shift=%d" "value=0x%X\n",
cfg->addr, cfg->mask, cfg->shift, val);
#endif
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index c51c1b188d64..97dcadc8fa8b 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -49,61 +49,61 @@
* OTP register offsets
* Bank : 0x15
*/
-#define AB8500_GPADC_CAL_1 0x0F
-#define AB8500_GPADC_CAL_2 0x10
-#define AB8500_GPADC_CAL_3 0x11
-#define AB8500_GPADC_CAL_4 0x12
-#define AB8500_GPADC_CAL_5 0x13
-#define AB8500_GPADC_CAL_6 0x14
-#define AB8500_GPADC_CAL_7 0x15
+#define AB8500_GPADC_CAL_1 0x0F
+#define AB8500_GPADC_CAL_2 0x10
+#define AB8500_GPADC_CAL_3 0x11
+#define AB8500_GPADC_CAL_4 0x12
+#define AB8500_GPADC_CAL_5 0x13
+#define AB8500_GPADC_CAL_6 0x14
+#define AB8500_GPADC_CAL_7 0x15
/* New calibration for 8540 */
#define AB8540_GPADC_OTP4_REG_7 0x38
#define AB8540_GPADC_OTP4_REG_6 0x39
#define AB8540_GPADC_OTP4_REG_5 0x3A
/* gpadc constants */
-#define EN_VINTCORE12 0x04
-#define EN_VTVOUT 0x02
-#define EN_GPADC 0x01
-#define DIS_GPADC 0x00
-#define AVG_1 0x00
-#define AVG_4 0x20
-#define AVG_8 0x40
-#define AVG_16 0x60
-#define ADC_SW_CONV 0x04
-#define EN_ICHAR 0x80
-#define BTEMP_PULL_UP 0x08
-#define EN_BUF 0x40
-#define DIS_ZERO 0x00
-#define GPADC_BUSY 0x01
-#define EN_FALLING 0x10
-#define EN_TRIG_EDGE 0x02
-#define EN_VBIAS_XTAL_TEMP 0x02
+#define EN_VINTCORE12 0x04
+#define EN_VTVOUT 0x02
+#define EN_GPADC 0x01
+#define DIS_GPADC 0x00
+#define AVG_1 0x00
+#define AVG_4 0x20
+#define AVG_8 0x40
+#define AVG_16 0x60
+#define ADC_SW_CONV 0x04
+#define EN_ICHAR 0x80
+#define BTEMP_PULL_UP 0x08
+#define EN_BUF 0x40
+#define DIS_ZERO 0x00
+#define GPADC_BUSY 0x01
+#define EN_FALLING 0x10
+#define EN_TRIG_EDGE 0x02
+#define EN_VBIAS_XTAL_TEMP 0x02
/* GPADC constants from AB8500 spec, UM0836 */
-#define ADC_RESOLUTION 1024
-#define ADC_CH_BTEMP_MIN 0
-#define ADC_CH_BTEMP_MAX 1350
-#define ADC_CH_DIETEMP_MIN 0
-#define ADC_CH_DIETEMP_MAX 1350
-#define ADC_CH_CHG_V_MIN 0
-#define ADC_CH_CHG_V_MAX 20030
-#define ADC_CH_ACCDET2_MIN 0
-#define ADC_CH_ACCDET2_MAX 2500
-#define ADC_CH_VBAT_MIN 2300
-#define ADC_CH_VBAT_MAX 4800
-#define ADC_CH_CHG_I_MIN 0
-#define ADC_CH_CHG_I_MAX 1500
-#define ADC_CH_BKBAT_MIN 0
-#define ADC_CH_BKBAT_MAX 3200
+#define ADC_RESOLUTION 1024
+#define ADC_CH_BTEMP_MIN 0
+#define ADC_CH_BTEMP_MAX 1350
+#define ADC_CH_DIETEMP_MIN 0
+#define ADC_CH_DIETEMP_MAX 1350
+#define ADC_CH_CHG_V_MIN 0
+#define ADC_CH_CHG_V_MAX 20030
+#define ADC_CH_ACCDET2_MIN 0
+#define ADC_CH_ACCDET2_MAX 2500
+#define ADC_CH_VBAT_MIN 2300
+#define ADC_CH_VBAT_MAX 4800
+#define ADC_CH_CHG_I_MIN 0
+#define ADC_CH_CHG_I_MAX 1500
+#define ADC_CH_BKBAT_MIN 0
+#define ADC_CH_BKBAT_MAX 3200
/* GPADC constants from AB8540 spec */
-#define ADC_CH_IBAT_MIN (-6000) /* mA range measured by ADC for ibat*/
-#define ADC_CH_IBAT_MAX 6000
-#define ADC_CH_IBAT_MIN_V (-60) /* mV range measured by ADC for ibat*/
-#define ADC_CH_IBAT_MAX_V 60
-#define IBAT_VDROP_L (-56) /* mV */
-#define IBAT_VDROP_H 56
+#define ADC_CH_IBAT_MIN (-6000) /* mA range measured by ADC for ibat */
+#define ADC_CH_IBAT_MAX 6000
+#define ADC_CH_IBAT_MIN_V (-60) /* mV range measured by ADC for ibat */
+#define ADC_CH_IBAT_MAX_V 60
+#define IBAT_VDROP_L (-56) /* mV */
+#define IBAT_VDROP_H 56
/* This is used to not lose precision when dividing to get gain and offset */
#define CALIB_SCALE 1000
@@ -179,7 +179,7 @@ struct ab8500_gpadc *ab8500_gpadc_get(char *name)
list_for_each_entry(gpadc, &ab8500_gpadc_list, node) {
if (!strcmp(name, dev_name(gpadc->dev)))
- return gpadc;
+ return gpadc;
}
return ERR_PTR(-ENOENT);
@@ -315,11 +315,12 @@ int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample,
trig_edge, trig_timer, conv_type);
-/* On failure retry a second time */
+
+ /* On failure retry a second time */
if (ad_value < 0)
ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample,
trig_edge, trig_timer, conv_type);
-if (ad_value < 0) {
+ if (ad_value < 0) {
dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n",
channel);
return ad_value;
@@ -327,8 +328,9 @@ if (ad_value < 0) {
voltage = ab8500_gpadc_ad_to_voltage(gpadc, channel, ad_value);
if (voltage < 0)
- dev_err(gpadc->dev, "GPADC to voltage conversion failed ch:"
- " %d AD: 0x%x\n", channel, ad_value);
+ dev_err(gpadc->dev,
+ "GPADC to voltage conversion failed ch: %d AD: 0x%x\n",
+ channel, ad_value);
return voltage;
}
@@ -348,10 +350,9 @@ EXPORT_SYMBOL(ab8500_gpadc_sw_hw_convert);
int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type)
{
- int raw_data;
- raw_data = ab8500_gpadc_double_read_raw(gpadc, channel,
- avg_sample, trig_edge, trig_timer, conv_type, NULL);
- return raw_data;
+ return ab8500_gpadc_double_read_raw(gpadc, channel, avg_sample,
+ trig_edge, trig_timer, conv_type,
+ NULL);
}
int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
@@ -388,7 +389,7 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
goto out;
if (!(val & GPADC_BUSY))
break;
- msleep(10);
+ msleep(20);
} while (++looplimit < 10);
if (looplimit >= 10 && (val & GPADC_BUSY)) {
dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
@@ -421,8 +422,7 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
val_reg1 |= EN_TRIG_EDGE;
if (trig_edge)
val_reg1 |= EN_FALLING;
- }
- else
+ } else
ret = abx500_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val);
if (ret < 0) {
@@ -449,7 +449,7 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
* remove when hardware will be availible
*/
delay_min = 1000; /* Delay in micro seconds */
- delay_max = 10000; /* large range to optimise sleep mode */
+ delay_max = 10000; /* large range optimises sleepmode */
break;
}
/* Intentional fallthrough */
@@ -785,9 +785,10 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
<< CALIB_SHIFT_IBAT)
/ (ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V);
- gpadc->cal_data[ADC_INPUT_IBAT].gain = V_gain * V2A_gain;
- gpadc->cal_data[ADC_INPUT_IBAT].offset = V_offset *
- V2A_gain + V2A_offset;
+ gpadc->cal_data[ADC_INPUT_IBAT].gain =
+ V_gain * V2A_gain;
+ gpadc->cal_data[ADC_INPUT_IBAT].offset =
+ V_offset * V2A_gain + V2A_offset;
} else {
gpadc->cal_data[ADC_INPUT_IBAT].gain = 0;
}
@@ -923,11 +924,10 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
int ret = 0;
struct ab8500_gpadc *gpadc;
- gpadc = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_gpadc), GFP_KERNEL);
- if (!gpadc) {
- dev_err(&pdev->dev, "Error: No memory\n");
+ gpadc = devm_kzalloc(&pdev->dev,
+ sizeof(struct ab8500_gpadc), GFP_KERNEL);
+ if (!gpadc)
return -ENOMEM;
- }
gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END");
if (gpadc->irq_sw < 0)
@@ -1072,18 +1072,19 @@ void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
*vmain_h = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi;
*btemp_l = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo;
*btemp_h = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi;
- *vbat_l = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo;
- *vbat_h = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi;
- *ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
- *ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
- return ;
+ *vbat_l = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo;
+ *vbat_h = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi;
+ *ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
+ *ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
}
subsys_initcall_sync(ab8500_gpadc_init);
module_exit(ab8500_gpadc_exit);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson,"
- "M'boumba Cedric Madianga");
+MODULE_AUTHOR("Arun R Murthy");
+MODULE_AUTHOR("Daniel Willerud");
+MODULE_AUTHOR("Johan Palsson");
+MODULE_AUTHOR("M'boumba Cedric Madianga");
MODULE_ALIAS("platform:ab8500_gpadc");
MODULE_DESCRIPTION("AB8500 GPADC driver");
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 0d1825696153..b9f0010309f9 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -27,7 +27,7 @@ static void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
- static char *pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
+ static const char * const pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
int i;
bool charger_present = false;
union power_supply_propval val;
@@ -68,10 +68,9 @@ static void ab8500_power_off(void)
ret = power_supply_get_property(psy,
POWER_SUPPLY_PROP_TECHNOLOGY, &val);
if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
- printk(KERN_INFO
- "Charger \"%s\" is connected with known battery."
- " Rebooting.\n",
- pss[i]);
+ pr_info("Charger '%s' is connected with known battery",
+ pss[i]);
+ pr_info(" - Rebooting.\n");
machine_restart("charging");
}
power_supply_put(psy);
@@ -161,8 +160,8 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev)
pdata->initial_req_buf_config[j]);
if (ret < 0) {
dev_err(&pdev->dev,
- "unable to set sysClkReq%dRfClkBuf: "
- "%d\n", j + 1, ret);
+ "Can't set sysClkReq%dRfClkBuf: %d\n",
+ j + 1, ret);
}
}
}
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
index ae88654595dc..d817f202da5b 100644
--- a/drivers/mfd/adp5520.c
+++ b/drivers/mfd/adp5520.c
@@ -9,10 +9,10 @@
*
* Derived from da903x:
* Copyright (C) 2008 Compulab, Ltd.
- * Mike Rapoport <mike@compulab.co.il>
+ * Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
- * Eric Miao <eric.miao@marvell.com>
+ * Eric Miao <eric.miao@marvell.com>
*
* Licensed under the GPL-2 or later.
*/
@@ -355,7 +355,7 @@ static struct i2c_driver adp5520_driver = {
},
.probe = adp5520_probe,
.remove = adp5520_remove,
- .id_table = adp5520_id,
+ .id_table = adp5520_id,
};
module_i2c_driver(adp5520_driver);
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index d474732cc65c..5319f252790b 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -238,7 +238,7 @@ static int arizona_poll_reg(struct arizona *arizona,
if ((val & mask) == target)
return 0;
- msleep(1);
+ usleep_range(1000, 5000);
}
dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val);
@@ -279,14 +279,14 @@ static void arizona_disable_reset(struct arizona *arizona)
case WM5110:
case WM8280:
/* Meet requirements for minimum reset duration */
- msleep(5);
+ usleep_range(5000, 10000);
break;
default:
break;
}
gpio_set_value_cansleep(arizona->pdata.reset, 1);
- msleep(1);
+ usleep_range(1000, 5000);
}
}
@@ -598,6 +598,12 @@ static int arizona_runtime_resume(struct device *dev)
goto err;
}
break;
+ case WM1831:
+ case CS47L24:
+ ret = arizona_wait_for_boot(arizona);
+ if (ret != 0)
+ goto err;
+ break;
default:
ret = arizona_wait_for_boot(arizona);
if (ret != 0)
@@ -682,6 +688,9 @@ static int arizona_runtime_suspend(struct device *dev)
}
}
break;
+ case WM1831:
+ case CS47L24:
+ break;
default:
jd_active = arizona_is_jack_det_active(arizona);
if (jd_active < 0)
@@ -852,6 +861,16 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
count++;
}
+ count = 0;
+ of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop,
+ cur, val) {
+ if (count == ARRAY_SIZE(pdata->out_mono))
+ break;
+
+ pdata->out_mono[count] = !!val;
+ count++;
+ }
+
return 0;
}
@@ -862,6 +881,8 @@ const struct of_device_id arizona_of_match[] = {
{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
{ .compatible = "wlf,wm8998", .data = (void *)WM8998 },
{ .compatible = "wlf,wm1814", .data = (void *)WM1814 },
+ { .compatible = "wlf,wm1831", .data = (void *)WM1831 },
+ { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 },
{},
};
EXPORT_SYMBOL_GPL(arizona_of_match);
@@ -919,6 +940,23 @@ static const struct mfd_cell wm5110_devs[] = {
},
};
+static const char * const cs47l24_supplies[] = {
+ "MICVDD",
+ "CPVDD",
+ "SPKVDD",
+};
+
+static const struct mfd_cell cs47l24_devs[] = {
+ { .name = "arizona-gpio" },
+ { .name = "arizona-haptics" },
+ { .name = "arizona-pwm" },
+ {
+ .name = "cs47l24-codec",
+ .parent_supplies = cs47l24_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l24_supplies),
+ },
+};
+
static const char * const wm8997_supplies[] = {
"MICVDD",
"DBVDD2",
@@ -963,7 +1001,7 @@ static const struct mfd_cell wm8998_devs[] = {
int arizona_dev_init(struct arizona *arizona)
{
struct device *dev = arizona->dev;
- const char *type_name;
+ const char *type_name = NULL;
unsigned int reg, val, mask;
int (*apply_patch)(struct arizona *) = NULL;
const struct mfd_cell *subdevs = NULL;
@@ -987,6 +1025,8 @@ int arizona_dev_init(struct arizona *arizona)
case WM8997:
case WM8998:
case WM1814:
+ case WM1831:
+ case CS47L24:
for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
arizona->core_supplies[i].supply
= wm5102_core_supplies[i];
@@ -1001,11 +1041,18 @@ int arizona_dev_init(struct arizona *arizona)
/* Mark DCVDD as external, LDO1 driver will clear if internal */
arizona->external_dcvdd = true;
- ret = mfd_add_devices(arizona->dev, -1, early_devs,
- ARRAY_SIZE(early_devs), NULL, 0, NULL);
- if (ret != 0) {
- dev_err(dev, "Failed to add early children: %d\n", ret);
- return ret;
+ switch (arizona->type) {
+ case WM1831:
+ case CS47L24:
+ break; /* No LDO1 regulator */
+ default:
+ ret = mfd_add_devices(arizona->dev, -1, early_devs,
+ ARRAY_SIZE(early_devs), NULL, 0, NULL);
+ if (ret != 0) {
+ dev_err(dev, "Failed to add early children: %d\n", ret);
+ return ret;
+ }
+ break;
}
ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
@@ -1069,6 +1116,7 @@ int arizona_dev_init(struct arizona *arizona)
case 0x5102:
case 0x5110:
case 0x6349:
+ case 0x6363:
case 0x8997:
break;
default:
@@ -1084,7 +1132,7 @@ int arizona_dev_init(struct arizona *arizona)
goto err_reset;
}
- msleep(1);
+ usleep_range(1000, 5000);
}
/* Ensure device startup is complete */
@@ -1167,6 +1215,30 @@ int arizona_dev_init(struct arizona *arizona)
n_subdevs = ARRAY_SIZE(wm5110_devs);
}
break;
+ case 0x6363:
+ if (IS_ENABLED(CONFIG_MFD_CS47L24)) {
+ switch (arizona->type) {
+ case CS47L24:
+ type_name = "CS47L24";
+ break;
+
+ case WM1831:
+ type_name = "WM1831";
+ break;
+
+ default:
+ dev_warn(arizona->dev,
+ "CS47L24 registered as %d\n",
+ arizona->type);
+ arizona->type = CS47L24;
+ break;
+ }
+
+ apply_patch = cs47l24_patch;
+ subdevs = cs47l24_devs;
+ n_subdevs = ARRAY_SIZE(cs47l24_devs);
+ }
+ break;
case 0x8997:
if (IS_ENABLED(CONFIG_MFD_WM8997)) {
type_name = "WM8997";
diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c
index 4e3afd1861fc..5fe12961cfe5 100644
--- a/drivers/mfd/arizona-i2c.c
+++ b/drivers/mfd/arizona-i2c.c
@@ -88,7 +88,9 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
static int arizona_i2c_remove(struct i2c_client *i2c)
{
struct arizona *arizona = dev_get_drvdata(&i2c->dev);
+
arizona_dev_exit(arizona);
+
return 0;
}
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index 3d425e93ce84..5fef014920a3 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -30,11 +30,13 @@ static int arizona_map_irq(struct arizona *arizona, int irq)
{
int ret;
- ret = regmap_irq_get_virq(arizona->aod_irq_chip, irq);
- if (ret < 0)
- ret = regmap_irq_get_virq(arizona->irq_chip, irq);
+ if (arizona->aod_irq_chip) {
+ ret = regmap_irq_get_virq(arizona->aod_irq_chip, irq);
+ if (ret >= 0)
+ return ret;
+ }
- return ret;
+ return regmap_irq_get_virq(arizona->irq_chip, irq);
}
int arizona_request_irq(struct arizona *arizona, int irq, char *name,
@@ -107,8 +109,8 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
do {
poll = false;
- /* Always handle the AoD domain */
- handle_nested_irq(irq_find_mapping(arizona->virq, 0));
+ if (arizona->aod_irq_chip)
+ handle_nested_irq(irq_find_mapping(arizona->virq, 0));
/*
* Check if one of the main interrupts is asserted and only
@@ -219,6 +221,15 @@ int arizona_irq_init(struct arizona *arizona)
arizona->ctrlif_error = false;
break;
#endif
+#ifdef CONFIG_MFD_CS47L24
+ case WM1831:
+ case CS47L24:
+ aod = NULL;
+ irq = &cs47l24_irq;
+
+ arizona->ctrlif_error = false;
+ break;
+#endif
#ifdef CONFIG_MFD_WM8997
case WM8997:
aod = &wm8997_aod;
@@ -291,13 +302,16 @@ int arizona_irq_init(struct arizona *arizona)
goto err;
}
- ret = regmap_add_irq_chip(arizona->regmap,
- irq_create_mapping(arizona->virq, 0),
- IRQF_ONESHOT, 0, aod,
- &arizona->aod_irq_chip);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret);
- goto err_domain;
+ if (aod) {
+ ret = regmap_add_irq_chip(arizona->regmap,
+ irq_create_mapping(arizona->virq, 0),
+ IRQF_ONESHOT, 0, aod,
+ &arizona->aod_irq_chip);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to add AOD IRQs: %d\n", ret);
+ goto err;
+ }
}
ret = regmap_add_irq_chip(arizona->regmap,
@@ -309,30 +323,6 @@ int arizona_irq_init(struct arizona *arizona)
goto err_aod;
}
- /* Make sure the boot done IRQ is unmasked for resumes */
- i = arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE);
- ret = request_threaded_irq(i, NULL, arizona_boot_done, IRQF_ONESHOT,
- "Boot done", arizona);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
- arizona->irq, ret);
- goto err_boot_done;
- }
-
- /* Handle control interface errors in the core */
- if (arizona->ctrlif_error) {
- i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR);
- ret = request_threaded_irq(i, NULL, arizona_ctrlif_err,
- IRQF_ONESHOT,
- "Control interface error", arizona);
- if (ret != 0) {
- dev_err(arizona->dev,
- "Failed to request CTRLIF_ERR %d: %d\n",
- arizona->irq, ret);
- goto err_ctrlif;
- }
- }
-
/* Used to emulate edge trigger and to work around broken pinmux */
if (arizona->pdata.irq_gpio) {
if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) {
@@ -362,21 +352,42 @@ int arizona_irq_init(struct arizona *arizona)
goto err_main_irq;
}
+ /* Make sure the boot done IRQ is unmasked for resumes */
+ i = arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE);
+ ret = request_threaded_irq(i, NULL, arizona_boot_done, IRQF_ONESHOT,
+ "Boot done", arizona);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
+ arizona->irq, ret);
+ goto err_boot_done;
+ }
+
+ /* Handle control interface errors in the core */
+ if (arizona->ctrlif_error) {
+ i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR);
+ ret = request_threaded_irq(i, NULL, arizona_ctrlif_err,
+ IRQF_ONESHOT,
+ "Control interface error", arizona);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to request CTRLIF_ERR %d: %d\n",
+ arizona->irq, ret);
+ goto err_ctrlif;
+ }
+ }
+
return 0;
-err_main_irq:
- if (arizona->ctrlif_error)
- free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR),
- arizona);
err_ctrlif:
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
err_boot_done:
+ free_irq(arizona->irq, arizona);
+err_main_irq:
regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
arizona->irq_chip);
err_aod:
regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
arizona->aod_irq_chip);
-err_domain:
err:
return ret;
}
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index befbc89bfd34..5c1ccdeb9b70 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -46,6 +46,11 @@ static int arizona_spi_probe(struct spi_device *spi)
if (IS_ENABLED(CONFIG_MFD_WM5110))
regmap_config = &wm5110_spi_regmap;
break;
+ case WM1831:
+ case CS47L24:
+ if (IS_ENABLED(CONFIG_MFD_CS47L24))
+ regmap_config = &cs47l24_spi_regmap;
+ break;
default:
dev_err(&spi->dev, "Unknown device type %ld\n", type);
return -EINVAL;
@@ -89,6 +94,8 @@ static const struct spi_device_id arizona_spi_ids[] = {
{ "wm5102", WM5102 },
{ "wm5110", WM5110 },
{ "wm8280", WM8280 },
+ { "wm1831", WM1831 },
+ { "cs47l24", CS47L24 },
{ },
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h
index 3af12e938f57..198e9cea77f9 100644
--- a/drivers/mfd/arizona.h
+++ b/drivers/mfd/arizona.h
@@ -25,6 +25,8 @@ extern const struct regmap_config wm5102_spi_regmap;
extern const struct regmap_config wm5110_i2c_regmap;
extern const struct regmap_config wm5110_spi_regmap;
+extern const struct regmap_config cs47l24_spi_regmap;
+
extern const struct regmap_config wm8997_i2c_regmap;
extern const struct regmap_config wm8998_i2c_regmap;
@@ -40,6 +42,8 @@ extern const struct regmap_irq_chip wm5110_aod;
extern const struct regmap_irq_chip wm5110_irq;
extern const struct regmap_irq_chip wm5110_revd_irq;
+extern const struct regmap_irq_chip cs47l24_irq;
+
extern const struct regmap_irq_chip wm8997_aod;
extern const struct regmap_irq_chip wm8997_irq;
diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c
index d001f7e238f5..94d67a6e1eb7 100644
--- a/drivers/mfd/as3711.c
+++ b/drivers/mfd/as3711.c
@@ -136,17 +136,13 @@ static int as3711_i2c_probe(struct i2c_client *client,
} else {
pdata = devm_kzalloc(&client->dev,
sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&client->dev, "Failed to allocate pdata\n");
+ if (!pdata)
return -ENOMEM;
- }
}
as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
- if (!as3711) {
- dev_err(&client->dev, "Memory allocation failed\n");
+ if (!as3711)
return -ENOMEM;
- }
as3711->dev = &client->dev;
i2c_set_clientdata(client, as3711);
@@ -157,7 +153,8 @@ static int as3711_i2c_probe(struct i2c_client *client,
as3711->regmap = devm_regmap_init_i2c(client, &as3711_regmap_config);
if (IS_ERR(as3711->regmap)) {
ret = PTR_ERR(as3711->regmap);
- dev_err(&client->dev, "regmap initialization failed: %d\n", ret);
+ dev_err(&client->dev,
+ "regmap initialization failed: %d\n", ret);
return ret;
}
@@ -172,12 +169,19 @@ static int as3711_i2c_probe(struct i2c_client *client,
return -ENODEV;
dev_info(as3711->dev, "AS3711 detected: %x:%x\n", id1, id2);
- /* We can reuse as3711_subdevs[], it will be copied in mfd_add_devices() */
+ /*
+ * We can reuse as3711_subdevs[],
+ * it will be copied in mfd_add_devices()
+ */
if (pdata) {
- as3711_subdevs[AS3711_REGULATOR].platform_data = &pdata->regulator;
- as3711_subdevs[AS3711_REGULATOR].pdata_size = sizeof(pdata->regulator);
- as3711_subdevs[AS3711_BACKLIGHT].platform_data = &pdata->backlight;
- as3711_subdevs[AS3711_BACKLIGHT].pdata_size = sizeof(pdata->backlight);
+ as3711_subdevs[AS3711_REGULATOR].platform_data =
+ &pdata->regulator;
+ as3711_subdevs[AS3711_REGULATOR].pdata_size =
+ sizeof(pdata->regulator);
+ as3711_subdevs[AS3711_BACKLIGHT].platform_data =
+ &pdata->backlight;
+ as3711_subdevs[AS3711_BACKLIGHT].pdata_size =
+ sizeof(pdata->backlight);
} else {
as3711_subdevs[AS3711_REGULATOR].platform_data = NULL;
as3711_subdevs[AS3711_REGULATOR].pdata_size = 0;
diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c
index 924ea90494ae..e1f597f97f86 100644
--- a/drivers/mfd/as3722.c
+++ b/drivers/mfd/as3722.c
@@ -405,6 +405,8 @@ static int as3722_i2c_probe(struct i2c_client *i2c,
goto scrub;
}
+ device_init_wakeup(as3722->dev, true);
+
dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
return 0;
@@ -422,6 +424,29 @@ static int as3722_i2c_remove(struct i2c_client *i2c)
return 0;
}
+static int __maybe_unused as3722_i2c_suspend(struct device *dev)
+{
+ struct as3722 *as3722 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(as3722->chip_irq);
+ disable_irq(as3722->chip_irq);
+
+ return 0;
+}
+
+static int __maybe_unused as3722_i2c_resume(struct device *dev)
+{
+ struct as3722 *as3722 = dev_get_drvdata(dev);
+
+ enable_irq(as3722->chip_irq);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(as3722->chip_irq);
+
+ return 0;
+}
+
static const struct of_device_id as3722_of_match[] = {
{ .compatible = "ams,as3722", },
{},
@@ -434,10 +459,15 @@ static const struct i2c_device_id as3722_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
+static const struct dev_pm_ops as3722_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(as3722_i2c_suspend, as3722_i2c_resume)
+};
+
static struct i2c_driver as3722_i2c_driver = {
.driver = {
.name = "as3722",
.of_match_table = as3722_of_match,
+ .pm = &as3722_pm_ops,
},
.probe = as3722_i2c_probe,
.remove = as3722_i2c_remove,
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index a726f01e3b02..4dca6bc61f5b 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -167,7 +167,6 @@ static void asic3_irq_demux(struct irq_desc *desc)
base = ASIC3_GPIO_A_BASE
+ bank * ASIC3_GPIO_BASE_INCR;
-
spin_lock_irqsave(&asic->lock, flags);
istat = asic3_read_register(asic,
base +
@@ -502,7 +501,8 @@ static int asic3_gpio_get(struct gpio_chip *chip,
return -EINVAL;
}
- return asic3_read_register(asic, gpio_base + ASIC3_GPIO_STATUS) & mask;
+ return !!(asic3_read_register(asic,
+ gpio_base + ASIC3_GPIO_STATUS) & mask);
}
static void asic3_gpio_set(struct gpio_chip *chip,
@@ -536,8 +536,6 @@ static void asic3_gpio_set(struct gpio_chip *chip,
asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg);
spin_unlock_irqrestore(&asic->lock, flags);
-
- return;
}
static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -665,18 +663,18 @@ static int ds1wm_enable(struct platform_device *pdev)
asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]);
- msleep(1);
+ usleep_range(1000, 5000);
/* Reset and enable DS1WM */
asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET),
ASIC3_EXTCF_OWM_RESET, 1);
- msleep(1);
+ usleep_range(1000, 5000);
asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET),
ASIC3_EXTCF_OWM_RESET, 0);
- msleep(1);
+ usleep_range(1000, 5000);
asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
ASIC3_EXTCF_OWM_EN, 1);
- msleep(1);
+ usleep_range(1000, 5000);
return 0;
}
@@ -757,7 +755,7 @@ static int asic3_mmc_enable(struct platform_device *pdev)
* when HCLK is stopped.
*/
asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
- msleep(1);
+ usleep_range(1000, 5000);
/* HCLK 24.576 MHz, BCLK 12.288 MHz: */
asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL),
@@ -765,7 +763,7 @@ static int asic3_mmc_enable(struct platform_device *pdev)
asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]);
asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]);
- msleep(1);
+ usleep_range(1000, 5000);
asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
ASIC3_EXTCF_SD_MEM_ENABLE, 1);
@@ -841,7 +839,7 @@ static int asic3_leds_suspend(struct platform_device *pdev)
struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
while (asic3_gpio_get(&asic->gpio, ASIC3_GPIO(C, cell->id)) != 0)
- msleep(1);
+ usleep_range(1000, 5000);
asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]);
@@ -900,8 +898,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
/* MMC */
if (mem_sdio) {
- asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
- mem_sdio->start,
+ asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >>
+ asic->bus_shift) + mem_sdio->start,
ASIC3_SD_CONFIG_SIZE >> asic->bus_shift);
if (!asic->tmio_cnf) {
ret = -ENOMEM;
@@ -962,10 +960,8 @@ static int __init asic3_probe(struct platform_device *pdev)
asic = devm_kzalloc(&pdev->dev,
sizeof(struct asic3), GFP_KERNEL);
- if (asic == NULL) {
- printk(KERN_ERR "kzalloc failed\n");
+ if (!asic)
return -ENOMEM;
- }
spin_lock_init(&asic->lock);
platform_set_drvdata(pdev, asic);
@@ -1074,7 +1070,9 @@ static struct platform_driver asic3_device_driver = {
static int __init asic3_init(void)
{
int retval = 0;
+
retval = platform_driver_probe(&asic3_device_driver, asic3_probe);
+
return retval;
}
diff --git a/drivers/mfd/cros_ec_i2c.c b/drivers/mfd/cros_ec_i2c.c
index 56a466469664..9f70de1e4c70 100644
--- a/drivers/mfd/cros_ec_i2c.c
+++ b/drivers/mfd/cros_ec_i2c.c
@@ -292,7 +292,7 @@ static int cros_ec_i2c_probe(struct i2c_client *client,
struct cros_ec_device *ec_dev = NULL;
int err;
- ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
+ ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
if (!ec_dev)
return -ENOMEM;
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index 6a0f6ec67c6b..ebe9b9477cb2 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -113,7 +113,7 @@ static int terminate_request(struct cros_ec_device *ec_dev)
trans.delay_usecs = ec_spi->end_of_msg_delay;
spi_message_add_tail(&trans, &msg);
- ret = spi_sync(ec_spi->spi, &msg);
+ ret = spi_sync_locked(ec_spi->spi, &msg);
/* Reset end-of-response timer */
ec_spi->last_transfer_ns = ktime_get_ns();
@@ -147,7 +147,7 @@ static int receive_n_bytes(struct cros_ec_device *ec_dev, u8 *buf, int n)
spi_message_init(&msg);
spi_message_add_tail(&trans, &msg);
- ret = spi_sync(ec_spi->spi, &msg);
+ ret = spi_sync_locked(ec_spi->spi, &msg);
if (ret < 0)
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
@@ -175,7 +175,7 @@ static int cros_ec_spi_receive_packet(struct cros_ec_device *ec_dev,
unsigned long deadline;
int todo;
- BUG_ON(EC_MSG_PREAMBLE_COUNT > ec_dev->din_size);
+ BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT);
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
@@ -283,7 +283,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
unsigned long deadline;
int todo;
- BUG_ON(EC_MSG_PREAMBLE_COUNT > ec_dev->din_size);
+ BUG_ON(ec_dev->din_size < EC_MSG_PREAMBLE_COUNT);
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
@@ -391,10 +391,10 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
}
rx_buf = kzalloc(len, GFP_KERNEL);
- if (!rx_buf) {
- ret = -ENOMEM;
- goto exit;
- }
+ if (!rx_buf)
+ return -ENOMEM;
+
+ spi_bus_lock(ec_spi->spi->master);
/*
* Leave a gap between CS assertion and clocking of data to allow the
@@ -414,7 +414,7 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
trans.len = len;
trans.cs_change = 1;
spi_message_add_tail(&trans, &msg);
- ret = spi_sync(ec_spi->spi, &msg);
+ ret = spi_sync_locked(ec_spi->spi, &msg);
/* Get the response */
if (!ret) {
@@ -440,6 +440,9 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
}
final_ret = terminate_request(ec_dev);
+
+ spi_bus_unlock(ec_spi->spi->master);
+
if (!ret)
ret = final_ret;
if (ret < 0)
@@ -520,10 +523,10 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
}
rx_buf = kzalloc(len, GFP_KERNEL);
- if (!rx_buf) {
- ret = -ENOMEM;
- goto exit;
- }
+ if (!rx_buf)
+ return -ENOMEM;
+
+ spi_bus_lock(ec_spi->spi->master);
/* Transmit phase - send our message */
debug_packet(ec_dev->dev, "out", ec_dev->dout, len);
@@ -534,7 +537,7 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
trans.cs_change = 1;
spi_message_init(&msg);
spi_message_add_tail(&trans, &msg);
- ret = spi_sync(ec_spi->spi, &msg);
+ ret = spi_sync_locked(ec_spi->spi, &msg);
/* Get the response */
if (!ret) {
@@ -560,6 +563,9 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
}
final_ret = terminate_request(ec_dev);
+
+ spi_bus_unlock(ec_spi->spi->master);
+
if (!ret)
ret = final_ret;
if (ret < 0)
diff --git a/drivers/mfd/cs47l24-tables.c b/drivers/mfd/cs47l24-tables.c
new file mode 100644
index 000000000000..870800657594
--- /dev/null
+++ b/drivers/mfd/cs47l24-tables.c
@@ -0,0 +1,1629 @@
+/*
+ * Data tables for CS47L24 codec
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.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/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+#include <linux/device.h>
+
+#include "arizona.h"
+
+#define CS47L24_NUM_ISR 5
+
+static const struct reg_sequence cs47l24_reva_patch[] = {
+ { 0x80, 0x3 },
+ { 0x27C, 0x0010 },
+ { 0x221, 0x0070 },
+ { 0x80, 0x0 },
+};
+
+int cs47l24_patch(struct arizona *arizona)
+{
+ return regmap_register_patch(arizona->regmap,
+ cs47l24_reva_patch,
+ ARRAY_SIZE(cs47l24_reva_patch));
+}
+EXPORT_SYMBOL_GPL(cs47l24_patch);
+
+static const struct regmap_irq cs47l24_irqs[ARIZONA_NUM_IRQ] = {
+ [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 },
+ [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 },
+
+ [ARIZONA_IRQ_DSP3_RAM_RDY] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP3_RAM_RDY_EINT1
+ },
+ [ARIZONA_IRQ_DSP2_RAM_RDY] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP2_RAM_RDY_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ8] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ8_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ7] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ7_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ6] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ6_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ5] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ5_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ4] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ4_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ3] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ3_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ2] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ2_EINT1
+ },
+ [ARIZONA_IRQ_DSP_IRQ1] = {
+ .reg_offset = 1, .mask = ARIZONA_DSP_IRQ1_EINT1
+ },
+
+ [ARIZONA_IRQ_SPK_OVERHEAT_WARN] = {
+ .reg_offset = 2, .mask = ARIZONA_SPK_OVERHEAT_WARN_EINT1
+ },
+ [ARIZONA_IRQ_SPK_OVERHEAT] = {
+ .reg_offset = 2, .mask = ARIZONA_SPK_OVERHEAT_EINT1
+ },
+ [ARIZONA_IRQ_WSEQ_DONE] = {
+ .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1
+ },
+ [ARIZONA_IRQ_DRC2_SIG_DET] = {
+ .reg_offset = 2, .mask = ARIZONA_DRC2_SIG_DET_EINT1
+ },
+ [ARIZONA_IRQ_DRC1_SIG_DET] = {
+ .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1
+ },
+ [ARIZONA_IRQ_ASRC2_LOCK] = {
+ .reg_offset = 2, .mask = ARIZONA_ASRC2_LOCK_EINT1
+ },
+ [ARIZONA_IRQ_ASRC1_LOCK] = {
+ .reg_offset = 2, .mask = ARIZONA_ASRC1_LOCK_EINT1
+ },
+ [ARIZONA_IRQ_UNDERCLOCKED] = {
+ .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1
+ },
+ [ARIZONA_IRQ_OVERCLOCKED] = {
+ .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1
+ },
+ [ARIZONA_IRQ_FLL2_LOCK] = {
+ .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1
+ },
+ [ARIZONA_IRQ_FLL1_LOCK] = {
+ .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1
+ },
+ [ARIZONA_IRQ_CLKGEN_ERR] = {
+ .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1
+ },
+ [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = {
+ .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1
+ },
+
+ [ARIZONA_IRQ_CTRLIF_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_CTRLIF_ERR_EINT1
+ },
+ [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_MIXER_DROPPED_SAMPLE_EINT1
+ },
+ [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_ASYNC_CLK_ENA_LOW_EINT1
+ },
+ [ARIZONA_IRQ_SYSCLK_ENA_LOW] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_SYSCLK_ENA_LOW_EINT1
+ },
+ [ARIZONA_IRQ_ISRC1_CFG_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_ISRC1_CFG_ERR_EINT1
+ },
+ [ARIZONA_IRQ_ISRC2_CFG_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_ISRC2_CFG_ERR_EINT1
+ },
+ [ARIZONA_IRQ_ISRC3_CFG_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_V2_ISRC3_CFG_ERR_EINT1
+ },
+ [ARIZONA_IRQ_HP1R_DONE] = {
+ .reg_offset = 3, .mask = ARIZONA_HP1R_DONE_EINT1
+ },
+ [ARIZONA_IRQ_HP1L_DONE] = {
+ .reg_offset = 3, .mask = ARIZONA_HP1L_DONE_EINT1
+ },
+
+ [ARIZONA_IRQ_BOOT_DONE] = {
+ .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1
+ },
+ [ARIZONA_IRQ_ASRC_CFG_ERR] = {
+ .reg_offset = 4, .mask = ARIZONA_V2_ASRC_CFG_ERR_EINT1
+ },
+ [ARIZONA_IRQ_FLL2_CLOCK_OK] = {
+ .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1
+ },
+ [ARIZONA_IRQ_FLL1_CLOCK_OK] = {
+ .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1
+ },
+
+ [ARIZONA_IRQ_DSP_SHARED_WR_COLL] = {
+ .reg_offset = 5, .mask = ARIZONA_DSP_SHARED_WR_COLL_EINT1
+ },
+ [ARIZONA_IRQ_SPK_SHUTDOWN] = {
+ .reg_offset = 5, .mask = ARIZONA_SPK_SHUTDOWN_EINT1
+ },
+ [ARIZONA_IRQ_SPK1R_SHORT] = {
+ .reg_offset = 5, .mask = ARIZONA_SPK1R_SHORT_EINT1
+ },
+ [ARIZONA_IRQ_SPK1L_SHORT] = {
+ .reg_offset = 5, .mask = ARIZONA_SPK1L_SHORT_EINT1
+ },
+ [ARIZONA_IRQ_HP1R_SC_POS] = {
+ .reg_offset = 5, .mask = ARIZONA_HP1R_SC_POS_EINT1
+ },
+ [ARIZONA_IRQ_HP1L_SC_POS] = {
+ .reg_offset = 5, .mask = ARIZONA_HP1L_SC_POS_EINT1
+ },
+};
+
+const struct regmap_irq_chip cs47l24_irq = {
+ .name = "cs47l24 IRQ",
+ .status_base = ARIZONA_INTERRUPT_STATUS_1,
+ .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK,
+ .ack_base = ARIZONA_INTERRUPT_STATUS_1,
+ .num_regs = 6,
+ .irqs = cs47l24_irqs,
+ .num_irqs = ARRAY_SIZE(cs47l24_irqs),
+};
+EXPORT_SYMBOL_GPL(cs47l24_irq);
+
+static const struct reg_default cs47l24_reg_default[] = {
+ { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */
+ { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */
+ { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */
+ { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */
+ { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */
+ { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */
+ { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */
+ { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */
+ { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */
+ { 0x00000041, 0x0000 }, /* R65 - Sequence control */
+ { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */
+ { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
+ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
+ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
+ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
+ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
+ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
+ { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */
+ { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */
+ { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */
+ { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */
+ { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */
+ { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */
+ { 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */
+ { 0x00000101, 0x0504 }, /* R257 - System Clock 1 */
+ { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */
+ { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */
+ { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */
+ { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */
+ { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */
+ { 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */
+ { 0x00000149, 0x0000 }, /* R329 - Output system clock */
+ { 0x0000014A, 0x0000 }, /* R330 - Output async clock */
+ { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */
+ { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */
+ { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */
+ { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */
+ { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */
+ { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */
+ { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */
+ { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */
+ { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */
+ { 0x00000175, 0x0006 }, /* R373 - FLL1 Control 5 */
+ { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
+ { 0x00000177, 0x0281 }, /* R375 - FLL1 Loop Filter Test 1 */
+ { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */
+ { 0x00000179, 0x0000 }, /* R376 - FLL1 Control 7 */
+ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
+ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
+ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
+ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */
+ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */
+ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */
+ { 0x00000187, 0x0001 }, /* R390 - FLL1 Synchroniser 7 */
+ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */
+ { 0x0000018A, 0x000C }, /* R394 - FLL1 GPIO Clock */
+ { 0x00000191, 0x0002 }, /* R401 - FLL2 Control 1 */
+ { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */
+ { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */
+ { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */
+ { 0x00000195, 0x000C }, /* R405 - FLL2 Control 5 */
+ { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
+ { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */
+ { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */
+ { 0x00000199, 0x0000 }, /* R408 - FLL2 Control 7 */
+ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
+ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
+ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
+ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */
+ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */
+ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */
+ { 0x000001A7, 0x0001 }, /* R422 - FLL2 Synchroniser 7 */
+ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */
+ { 0x000001AA, 0x000C }, /* R426 - FLL2 GPIO Clock */
+ { 0x00000218, 0x00E6 }, /* R536 - Mic Bias Ctrl 1 */
+ { 0x00000219, 0x00E6 }, /* R537 - Mic Bias Ctrl 2 */
+ { 0x00000300, 0x0000 }, /* R768 - Input Enables */
+ { 0x00000308, 0x0000 }, /* R776 - Input Rate */
+ { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */
+ { 0x0000030C, 0x0002 }, /* R780 - HPF Control */
+ { 0x00000310, 0x2000 }, /* R784 - IN1L Control */
+ { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */
+ { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */
+ { 0x00000314, 0x0000 }, /* R788 - IN1R Control */
+ { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */
+ { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */
+ { 0x00000318, 0x2000 }, /* R792 - IN2L Control */
+ { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */
+ { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */
+ { 0x0000031C, 0x0000 }, /* R796 - IN2R Control */
+ { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */
+ { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */
+ { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
+ { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */
+ { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */
+ { 0x00000410, 0x0080 }, /* R1040 - Output Path Config 1L */
+ { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */
+ { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */
+ { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */
+ { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */
+ { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */
+ { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */
+ { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */
+ { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */
+ { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */
+ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
+ { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */
+ { 0x000004A0, 0x3480 }, /* R1184 - HP1 Short Circuit Ctrl */
+ { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */
+ { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */
+ { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
+ { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */
+ { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */
+ { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */
+ { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */
+ { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */
+ { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */
+ { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */
+ { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */
+ { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */
+ { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */
+ { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */
+ { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */
+ { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */
+ { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */
+ { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */
+ { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */
+ { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */
+ { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */
+ { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */
+ { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */
+ { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */
+ { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */
+ { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */
+ { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */
+ { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */
+ { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
+ { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */
+ { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */
+ { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */
+ { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */
+ { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
+ { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
+ { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
+ { 0x0000054B, 0x0002 }, /* R1355 - AIF2 Frame Ctrl 5 */
+ { 0x0000054C, 0x0003 }, /* R1356 - AIF2 Frame Ctrl 6 */
+ { 0x0000054D, 0x0004 }, /* R1357 - AIF2 Frame Ctrl 7 */
+ { 0x0000054E, 0x0005 }, /* R1358 - AIF2 Frame Ctrl 8 */
+ { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
+ { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
+ { 0x00000553, 0x0002 }, /* R1363 - AIF2 Frame Ctrl 13 */
+ { 0x00000554, 0x0003 }, /* R1364 - AIF2 Frame Ctrl 14 */
+ { 0x00000555, 0x0004 }, /* R1365 - AIF2 Frame Ctrl 15 */
+ { 0x00000556, 0x0005 }, /* R1366 - AIF2 Frame Ctrl 16 */
+ { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
+ { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
+ { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
+ { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */
+ { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */
+ { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */
+ { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */
+ { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */
+ { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */
+ { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */
+ { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */
+ { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */
+ { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */
+ { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */
+ { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */
+ { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */
+ { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */
+ { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */
+ { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */
+ { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */
+ { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */
+ { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */
+ { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */
+ { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */
+ { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */
+ { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */
+ { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */
+ { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */
+ { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */
+ { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */
+ { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */
+ { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */
+ { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */
+ { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */
+ { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */
+ { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */
+ { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */
+ { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */
+ { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */
+ { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */
+ { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */
+ { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */
+ { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */
+ { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */
+ { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */
+ { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */
+ { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */
+ { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */
+ { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */
+ { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */
+ { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */
+ { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */
+ { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */
+ { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */
+ { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */
+ { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */
+ { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */
+ { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */
+ { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */
+ { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */
+ { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */
+ { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */
+ { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */
+ { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */
+ { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */
+ { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */
+ { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */
+ { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */
+ { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */
+ { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */
+ { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */
+ { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */
+ { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */
+ { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */
+ { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */
+ { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */
+ { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */
+ { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */
+ { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */
+ { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */
+ { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */
+ { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */
+ { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */
+ { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */
+ { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */
+ { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */
+ { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */
+ { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */
+ { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */
+ { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */
+ { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */
+ { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */
+ { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */
+ { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */
+ { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */
+ { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */
+ { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */
+ { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */
+ { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */
+ { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */
+ { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */
+ { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */
+ { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */
+ { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */
+ { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */
+ { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */
+ { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */
+ { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */
+ { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */
+ { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */
+ { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */
+ { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */
+ { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */
+ { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */
+ { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */
+ { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */
+ { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */
+ { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */
+ { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */
+ { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */
+ { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */
+ { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */
+ { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */
+ { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */
+ { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */
+ { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */
+ { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */
+ { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */
+ { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */
+ { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */
+ { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */
+ { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */
+ { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */
+ { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */
+ { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */
+ { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */
+ { 0x00000750, 0x0000 }, /* R1872 - AIF2TX3MIX Input 1 Source */
+ { 0x00000751, 0x0080 }, /* R1873 - AIF2TX3MIX Input 1 Volume */
+ { 0x00000752, 0x0000 }, /* R1874 - AIF2TX3MIX Input 2 Source */
+ { 0x00000753, 0x0080 }, /* R1875 - AIF2TX3MIX Input 2 Volume */
+ { 0x00000754, 0x0000 }, /* R1876 - AIF2TX3MIX Input 3 Source */
+ { 0x00000755, 0x0080 }, /* R1877 - AIF2TX3MIX Input 3 Volume */
+ { 0x00000756, 0x0000 }, /* R1878 - AIF2TX3MIX Input 4 Source */
+ { 0x00000757, 0x0080 }, /* R1879 - AIF2TX3MIX Input 4 Volume */
+ { 0x00000758, 0x0000 }, /* R1880 - AIF2TX4MIX Input 1 Source */
+ { 0x00000759, 0x0080 }, /* R1881 - AIF2TX4MIX Input 1 Volume */
+ { 0x0000075A, 0x0000 }, /* R1882 - AIF2TX4MIX Input 2 Source */
+ { 0x0000075B, 0x0080 }, /* R1883 - AIF2TX4MIX Input 2 Volume */
+ { 0x0000075C, 0x0000 }, /* R1884 - AIF2TX4MIX Input 3 Source */
+ { 0x0000075D, 0x0080 }, /* R1885 - AIF2TX4MIX Input 3 Volume */
+ { 0x0000075E, 0x0000 }, /* R1886 - AIF2TX4MIX Input 4 Source */
+ { 0x0000075F, 0x0080 }, /* R1887 - AIF2TX4MIX Input 4 Volume */
+ { 0x00000760, 0x0000 }, /* R1888 - AIF2TX5MIX Input 1 Source */
+ { 0x00000761, 0x0080 }, /* R1889 - AIF2TX5MIX Input 1 Volume */
+ { 0x00000762, 0x0000 }, /* R1890 - AIF2TX5MIX Input 2 Source */
+ { 0x00000763, 0x0080 }, /* R1891 - AIF2TX5MIX Input 2 Volume */
+ { 0x00000764, 0x0000 }, /* R1892 - AIF2TX5MIX Input 3 Source */
+ { 0x00000765, 0x0080 }, /* R1893 - AIF2TX5MIX Input 3 Volume */
+ { 0x00000766, 0x0000 }, /* R1894 - AIF2TX5MIX Input 4 Source */
+ { 0x00000767, 0x0080 }, /* R1895 - AIF2TX5MIX Input 4 Volume */
+ { 0x00000768, 0x0000 }, /* R1896 - AIF2TX6MIX Input 1 Source */
+ { 0x00000769, 0x0080 }, /* R1897 - AIF2TX6MIX Input 1 Volume */
+ { 0x0000076A, 0x0000 }, /* R1898 - AIF2TX6MIX Input 2 Source */
+ { 0x0000076B, 0x0080 }, /* R1899 - AIF2TX6MIX Input 2 Volume */
+ { 0x0000076C, 0x0000 }, /* R1900 - AIF2TX6MIX Input 3 Source */
+ { 0x0000076D, 0x0080 }, /* R1901 - AIF2TX6MIX Input 3 Volume */
+ { 0x0000076E, 0x0000 }, /* R1902 - AIF2TX6MIX Input 4 Source */
+ { 0x0000076F, 0x0080 }, /* R1903 - AIF2TX6MIX Input 4 Volume */
+ { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */
+ { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */
+ { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */
+ { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */
+ { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */
+ { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */
+ { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */
+ { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */
+ { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */
+ { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */
+ { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */
+ { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */
+ { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */
+ { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */
+ { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */
+ { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */
+ { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */
+ { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */
+ { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */
+ { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */
+ { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */
+ { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */
+ { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */
+ { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */
+ { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */
+ { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */
+ { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */
+ { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */
+ { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */
+ { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */
+ { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */
+ { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */
+ { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */
+ { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */
+ { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */
+ { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */
+ { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */
+ { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */
+ { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */
+ { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */
+ { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */
+ { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */
+ { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */
+ { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */
+ { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */
+ { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */
+ { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */
+ { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */
+ { 0x000008D0, 0x0000 }, /* R2256 - DRC2LMIX Input 1 Source */
+ { 0x000008D1, 0x0080 }, /* R2257 - DRC2LMIX Input 1 Volume */
+ { 0x000008D2, 0x0000 }, /* R2258 - DRC2LMIX Input 2 Source */
+ { 0x000008D3, 0x0080 }, /* R2259 - DRC2LMIX Input 2 Volume */
+ { 0x000008D4, 0x0000 }, /* R2260 - DRC2LMIX Input 3 Source */
+ { 0x000008D5, 0x0080 }, /* R2261 - DRC2LMIX Input 3 Volume */
+ { 0x000008D6, 0x0000 }, /* R2262 - DRC2LMIX Input 4 Source */
+ { 0x000008D7, 0x0080 }, /* R2263 - DRC2LMIX Input 4 Volume */
+ { 0x000008D8, 0x0000 }, /* R2264 - DRC2RMIX Input 1 Source */
+ { 0x000008D9, 0x0080 }, /* R2265 - DRC2RMIX Input 1 Volume */
+ { 0x000008DA, 0x0000 }, /* R2266 - DRC2RMIX Input 2 Source */
+ { 0x000008DB, 0x0080 }, /* R2267 - DRC2RMIX Input 2 Volume */
+ { 0x000008DC, 0x0000 }, /* R2268 - DRC2RMIX Input 3 Source */
+ { 0x000008DD, 0x0080 }, /* R2269 - DRC2RMIX Input 3 Volume */
+ { 0x000008DE, 0x0000 }, /* R2270 - DRC2RMIX Input 4 Source */
+ { 0x000008DF, 0x0080 }, /* R2271 - DRC2RMIX Input 4 Volume */
+ { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */
+ { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */
+ { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */
+ { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */
+ { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */
+ { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */
+ { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */
+ { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */
+ { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */
+ { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */
+ { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */
+ { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */
+ { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */
+ { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */
+ { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */
+ { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */
+ { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */
+ { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */
+ { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */
+ { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */
+ { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */
+ { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */
+ { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */
+ { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */
+ { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */
+ { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */
+ { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */
+ { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */
+ { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */
+ { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */
+ { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */
+ { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */
+ { 0x00000980, 0x0000 }, /* R2432 - DSP2LMIX Input 1 Source */
+ { 0x00000981, 0x0080 }, /* R2433 - DSP2LMIX Input 1 Volume */
+ { 0x00000982, 0x0000 }, /* R2434 - DSP2LMIX Input 2 Source */
+ { 0x00000983, 0x0080 }, /* R2435 - DSP2LMIX Input 2 Volume */
+ { 0x00000984, 0x0000 }, /* R2436 - DSP2LMIX Input 3 Source */
+ { 0x00000985, 0x0080 }, /* R2437 - DSP2LMIX Input 3 Volume */
+ { 0x00000986, 0x0000 }, /* R2438 - DSP2LMIX Input 4 Source */
+ { 0x00000987, 0x0080 }, /* R2439 - DSP2LMIX Input 4 Volume */
+ { 0x00000988, 0x0000 }, /* R2440 - DSP2RMIX Input 1 Source */
+ { 0x00000989, 0x0080 }, /* R2441 - DSP2RMIX Input 1 Volume */
+ { 0x0000098A, 0x0000 }, /* R2442 - DSP2RMIX Input 2 Source */
+ { 0x0000098B, 0x0080 }, /* R2443 - DSP2RMIX Input 2 Volume */
+ { 0x0000098C, 0x0000 }, /* R2444 - DSP2RMIX Input 3 Source */
+ { 0x0000098D, 0x0080 }, /* R2445 - DSP2RMIX Input 3 Volume */
+ { 0x0000098E, 0x0000 }, /* R2446 - DSP2RMIX Input 4 Source */
+ { 0x0000098F, 0x0080 }, /* R2447 - DSP2RMIX Input 4 Volume */
+ { 0x00000990, 0x0000 }, /* R2448 - DSP2AUX1MIX Input 1 Source */
+ { 0x00000998, 0x0000 }, /* R2456 - DSP2AUX2MIX Input 1 Source */
+ { 0x000009A0, 0x0000 }, /* R2464 - DSP2AUX3MIX Input 1 Source */
+ { 0x000009A8, 0x0000 }, /* R2472 - DSP2AUX4MIX Input 1 Source */
+ { 0x000009B0, 0x0000 }, /* R2480 - DSP2AUX5MIX Input 1 Source */
+ { 0x000009B8, 0x0000 }, /* R2488 - DSP2AUX6MIX Input 1 Source */
+ { 0x000009C0, 0x0000 }, /* R2496 - DSP3LMIX Input 1 Source */
+ { 0x000009C1, 0x0080 }, /* R2497 - DSP3LMIX Input 1 Volume */
+ { 0x000009C2, 0x0000 }, /* R2498 - DSP3LMIX Input 2 Source */
+ { 0x000009C3, 0x0080 }, /* R2499 - DSP3LMIX Input 2 Volume */
+ { 0x000009C4, 0x0000 }, /* R2500 - DSP3LMIX Input 3 Source */
+ { 0x000009C5, 0x0080 }, /* R2501 - DSP3LMIX Input 3 Volume */
+ { 0x000009C6, 0x0000 }, /* R2502 - DSP3LMIX Input 4 Source */
+ { 0x000009C7, 0x0080 }, /* R2503 - DSP3LMIX Input 4 Volume */
+ { 0x000009C8, 0x0000 }, /* R2504 - DSP3RMIX Input 1 Source */
+ { 0x000009C9, 0x0080 }, /* R2505 - DSP3RMIX Input 1 Volume */
+ { 0x000009CA, 0x0000 }, /* R2506 - DSP3RMIX Input 2 Source */
+ { 0x000009CB, 0x0080 }, /* R2507 - DSP3RMIX Input 2 Volume */
+ { 0x000009CC, 0x0000 }, /* R2508 - DSP3RMIX Input 3 Source */
+ { 0x000009CD, 0x0080 }, /* R2509 - DSP3RMIX Input 3 Volume */
+ { 0x000009CE, 0x0000 }, /* R2510 - DSP3RMIX Input 4 Source */
+ { 0x000009CF, 0x0080 }, /* R2511 - DSP3RMIX Input 4 Volume */
+ { 0x000009D0, 0x0000 }, /* R2512 - DSP3AUX1MIX Input 1 Source */
+ { 0x000009D8, 0x0000 }, /* R2520 - DSP3AUX2MIX Input 1 Source */
+ { 0x000009E0, 0x0000 }, /* R2528 - DSP3AUX3MIX Input 1 Source */
+ { 0x000009E8, 0x0000 }, /* R2536 - DSP3AUX4MIX Input 1 Source */
+ { 0x000009F0, 0x0000 }, /* R2544 - DSP3AUX5MIX Input 1 Source */
+ { 0x000009F8, 0x0000 }, /* R2552 - DSP3AUX6MIX Input 1 Source */
+ { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */
+ { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */
+ { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */
+ { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */
+ { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */
+ { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */
+ { 0x00000B10, 0x0000 }, /* R2832 - ISRC1DEC3MIX Input 1 Source */
+ { 0x00000B18, 0x0000 }, /* R2840 - ISRC1DEC4MIX Input 1 Source */
+ { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */
+ { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */
+ { 0x00000B30, 0x0000 }, /* R2864 - ISRC1INT3MIX Input 1 Source */
+ { 0x00000B38, 0x0000 }, /* R2872 - ISRC1INT4MIX Input 1 Source */
+ { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */
+ { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */
+ { 0x00000B50, 0x0000 }, /* R2896 - ISRC2DEC3MIX Input 1 Source */
+ { 0x00000B58, 0x0000 }, /* R2904 - ISRC2DEC4MIX Input 1 Source */
+ { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */
+ { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */
+ { 0x00000B70, 0x0000 }, /* R2928 - ISRC2INT3MIX Input 1 Source */
+ { 0x00000B78, 0x0000 }, /* R2936 - ISRC2INT4MIX Input 1 Source */
+ { 0x00000B80, 0x0000 }, /* R2944 - ISRC3DEC1MIX Input 1 Source */
+ { 0x00000B88, 0x0000 }, /* R2952 - ISRC3DEC2MIX Input 1 Source */
+ { 0x00000B90, 0x0000 }, /* R2960 - ISRC3DEC3MIX Input 1 Source */
+ { 0x00000B98, 0x0000 }, /* R2968 - ISRC3DEC4MIX Input 1 Source */
+ { 0x00000BA0, 0x0000 }, /* R2976 - ISRC3INT1MIX Input 1 Source */
+ { 0x00000BA8, 0x0000 }, /* R2984 - ISRC3INT2MIX Input 1 Source */
+ { 0x00000BB0, 0x0000 }, /* R2992 - ISRC3INT3MIX Input 1 Source */
+ { 0x00000BB8, 0x0000 }, /* R3000 - ISRC3INT4MIX Input 1 Source */
+ { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */
+ { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */
+ { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */
+ { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */
+ { 0x00000C20, 0x0002 }, /* R3104 - Misc Pad Ctrl 1 */
+ { 0x00000C21, 0x8001 }, /* R3105 - Misc Pad Ctrl 2 */
+ { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */
+ { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
+ { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
+ { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */
+ { 0x00000C30, 0x0404 }, /* R3120 - Misc Pad Ctrl 7 */
+ { 0x00000C32, 0x0404 }, /* R3122 - Misc Pad Ctrl 9 */
+ { 0x00000C33, 0x0404 }, /* R3123 - Misc Pad Ctrl 10 */
+ { 0x00000C34, 0x0404 }, /* R3124 - Misc Pad Ctrl 11 */
+ { 0x00000C35, 0x0404 }, /* R3125 - Misc Pad Ctrl 12 */
+ { 0x00000C36, 0x0400 }, /* R3126 - Misc Pad Ctrl 13 */
+ { 0x00000C37, 0x0404 }, /* R3127 - Misc Pad Ctrl 14 */
+ { 0x00000C39, 0x0400 }, /* R3129 - Misc Pad Ctrl 16 */
+ { 0x00000D08, 0x0007 }, /* R3336 - Interrupt Status 1 Mask */
+ { 0x00000D09, 0x06FF }, /* R3337 - Interrupt Status 2 Mask */
+ { 0x00000D0A, 0xCFEF }, /* R3338 - Interrupt Status 3 Mask */
+ { 0x00000D0B, 0xFFC3 }, /* R3339 - Interrupt Status 4 Mask */
+ { 0x00000D0C, 0x000B }, /* R3340 - Interrupt Status 5 Mask */
+ { 0x00000D0D, 0xD005 }, /* R3341 - Interrupt Status 6 Mask */
+ { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */
+ { 0x00000D18, 0x0007 }, /* R3352 - IRQ2 Status 1 Mask */
+ { 0x00000D19, 0x06FF }, /* R3353 - IRQ2 Status 2 Mask */
+ { 0x00000D1A, 0xCFEF }, /* R3354 - IRQ2 Status 3 Mask */
+ { 0x00000D1B, 0xFFC3 }, /* R3355 - IRQ2 Status 4 Mask */
+ { 0x00000D1C, 0x000B }, /* R3356 - IRQ2 Status 5 Mask */
+ { 0x00000D1D, 0xD005 }, /* R3357 - IRQ2 Status 6 Mask */
+ { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */
+ { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */
+ { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */
+ { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */
+ { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */
+ { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */
+ { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */
+ { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */
+ { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */
+ { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */
+ { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */
+ { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */
+ { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */
+ { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */
+ { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */
+ { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */
+ { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */
+ { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */
+ { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */
+ { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */
+ { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */
+ { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */
+ { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */
+ { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */
+ { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */
+ { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */
+ { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */
+ { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */
+ { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */
+ { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */
+ { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */
+ { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */
+ { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */
+ { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */
+ { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */
+ { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */
+ { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */
+ { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */
+ { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */
+ { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */
+ { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */
+ { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */
+ { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */
+ { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */
+ { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */
+ { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */
+ { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */
+ { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */
+ { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */
+ { 0x00000E89, 0x0018 }, /* R3721 - DRC2 ctrl1 */
+ { 0x00000E8A, 0x0933 }, /* R3722 - DRC2 ctrl2 */
+ { 0x00000E8B, 0x0018 }, /* R3723 - DRC2 ctrl3 */
+ { 0x00000E8C, 0x0000 }, /* R3724 - DRC2 ctrl4 */
+ { 0x00000E8D, 0x0000 }, /* R3725 - DRC2 ctrl5 */
+ { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */
+ { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */
+ { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */
+ { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */
+ { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */
+ { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */
+ { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */
+ { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
+ { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */
+ { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */
+ { 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */
+ { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
+ { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
+ { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
+ { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */
+ { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */
+ { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */
+ { 0x00000EF6, 0x0000 }, /* R3830 - ISRC 3 CTRL 1 */
+ { 0x00000EF7, 0x0000 }, /* R3831 - ISRC 3 CTRL 2 */
+ { 0x00000EF8, 0x0000 }, /* R3832 - ISRC 3 CTRL 3 */
+ { 0x00001200, 0x0010 }, /* R4608 - DSP2 Control 1 */
+ { 0x00001300, 0x0010 }, /* R4864 - DSP3 Control 1 */
+};
+
+static bool cs47l24_is_adsp_memory(unsigned int reg)
+{
+ switch (reg) {
+ case 0x200000 ... 0x205fff: /* DSP2 PM */
+ case 0x280000 ... 0x281fff: /* DSP2 ZM */
+ case 0x290000 ... 0x2a7fff: /* DSP2 XM */
+ case 0x2a8000 ... 0x2b3fff: /* DSP2 YM */
+ case 0x300000 ... 0x308fff: /* DSP3 PM */
+ case 0x380000 ... 0x381fff: /* DSP3 ZM */
+ case 0x390000 ... 0x3a7fff: /* DSP3 XM */
+ case 0x3a8000 ... 0x3b3fff: /* DSP3 YM */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ARIZONA_SOFTWARE_RESET:
+ case ARIZONA_DEVICE_REVISION:
+ case ARIZONA_CTRL_IF_SPI_CFG_1:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_0:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_1:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_2:
+ case ARIZONA_TONE_GENERATOR_1:
+ case ARIZONA_TONE_GENERATOR_2:
+ case ARIZONA_TONE_GENERATOR_3:
+ case ARIZONA_TONE_GENERATOR_4:
+ case ARIZONA_TONE_GENERATOR_5:
+ case ARIZONA_PWM_DRIVE_1:
+ case ARIZONA_PWM_DRIVE_2:
+ case ARIZONA_PWM_DRIVE_3:
+ case ARIZONA_SEQUENCE_CONTROL:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+ case ARIZONA_COMFORT_NOISE_GENERATOR:
+ case ARIZONA_HAPTICS_CONTROL_1:
+ case ARIZONA_HAPTICS_CONTROL_2:
+ case ARIZONA_HAPTICS_PHASE_1_INTENSITY:
+ case ARIZONA_HAPTICS_PHASE_1_DURATION:
+ case ARIZONA_HAPTICS_PHASE_2_INTENSITY:
+ case ARIZONA_HAPTICS_PHASE_2_DURATION:
+ case ARIZONA_HAPTICS_PHASE_3_INTENSITY:
+ case ARIZONA_HAPTICS_PHASE_3_DURATION:
+ case ARIZONA_HAPTICS_STATUS:
+ case ARIZONA_CLOCK_32K_1:
+ case ARIZONA_SYSTEM_CLOCK_1:
+ case ARIZONA_SAMPLE_RATE_1:
+ case ARIZONA_SAMPLE_RATE_2:
+ case ARIZONA_SAMPLE_RATE_3:
+ case ARIZONA_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_SAMPLE_RATE_2_STATUS:
+ case ARIZONA_SAMPLE_RATE_3_STATUS:
+ case ARIZONA_ASYNC_CLOCK_1:
+ case ARIZONA_ASYNC_SAMPLE_RATE_1:
+ case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_ASYNC_SAMPLE_RATE_2:
+ case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS:
+ case ARIZONA_OUTPUT_SYSTEM_CLOCK:
+ case ARIZONA_OUTPUT_ASYNC_CLOCK:
+ case ARIZONA_RATE_ESTIMATOR_1:
+ case ARIZONA_RATE_ESTIMATOR_2:
+ case ARIZONA_RATE_ESTIMATOR_3:
+ case ARIZONA_RATE_ESTIMATOR_4:
+ case ARIZONA_RATE_ESTIMATOR_5:
+ case ARIZONA_FLL1_CONTROL_1:
+ case ARIZONA_FLL1_CONTROL_2:
+ case ARIZONA_FLL1_CONTROL_3:
+ case ARIZONA_FLL1_CONTROL_4:
+ case ARIZONA_FLL1_CONTROL_5:
+ case ARIZONA_FLL1_CONTROL_6:
+ case ARIZONA_FLL1_CONTROL_7:
+ case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
+ case ARIZONA_FLL1_NCO_TEST_0:
+ case ARIZONA_FLL1_SYNCHRONISER_1:
+ case ARIZONA_FLL1_SYNCHRONISER_2:
+ case ARIZONA_FLL1_SYNCHRONISER_3:
+ case ARIZONA_FLL1_SYNCHRONISER_4:
+ case ARIZONA_FLL1_SYNCHRONISER_5:
+ case ARIZONA_FLL1_SYNCHRONISER_6:
+ case ARIZONA_FLL1_SYNCHRONISER_7:
+ case ARIZONA_FLL1_SPREAD_SPECTRUM:
+ case ARIZONA_FLL1_GPIO_CLOCK:
+ case ARIZONA_FLL2_CONTROL_1:
+ case ARIZONA_FLL2_CONTROL_2:
+ case ARIZONA_FLL2_CONTROL_3:
+ case ARIZONA_FLL2_CONTROL_4:
+ case ARIZONA_FLL2_CONTROL_5:
+ case ARIZONA_FLL2_CONTROL_6:
+ case ARIZONA_FLL2_CONTROL_7:
+ case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
+ case ARIZONA_FLL2_NCO_TEST_0:
+ case ARIZONA_FLL2_SYNCHRONISER_1:
+ case ARIZONA_FLL2_SYNCHRONISER_2:
+ case ARIZONA_FLL2_SYNCHRONISER_3:
+ case ARIZONA_FLL2_SYNCHRONISER_4:
+ case ARIZONA_FLL2_SYNCHRONISER_5:
+ case ARIZONA_FLL2_SYNCHRONISER_6:
+ case ARIZONA_FLL2_SYNCHRONISER_7:
+ case ARIZONA_FLL2_SPREAD_SPECTRUM:
+ case ARIZONA_FLL2_GPIO_CLOCK:
+ case ARIZONA_MIC_BIAS_CTRL_1:
+ case ARIZONA_MIC_BIAS_CTRL_2:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
+ case ARIZONA_INPUT_ENABLES:
+ case ARIZONA_INPUT_ENABLES_STATUS:
+ case ARIZONA_INPUT_RATE:
+ case ARIZONA_INPUT_VOLUME_RAMP:
+ case ARIZONA_HPF_CONTROL:
+ case ARIZONA_IN1L_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_1L:
+ case ARIZONA_DMIC1L_CONTROL:
+ case ARIZONA_IN1R_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_1R:
+ case ARIZONA_DMIC1R_CONTROL:
+ case ARIZONA_IN2L_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+ case ARIZONA_DMIC2L_CONTROL:
+ case ARIZONA_IN2R_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_2R:
+ case ARIZONA_DMIC2R_CONTROL:
+ case ARIZONA_OUTPUT_ENABLES_1:
+ case ARIZONA_OUTPUT_STATUS_1:
+ case ARIZONA_RAW_OUTPUT_STATUS_1:
+ case ARIZONA_OUTPUT_RATE_1:
+ case ARIZONA_OUTPUT_VOLUME_RAMP:
+ case ARIZONA_OUTPUT_PATH_CONFIG_1L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_1L:
+ case ARIZONA_DAC_VOLUME_LIMIT_1L:
+ case ARIZONA_NOISE_GATE_SELECT_1L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_1R:
+ case ARIZONA_DAC_VOLUME_LIMIT_1R:
+ case ARIZONA_NOISE_GATE_SELECT_1R:
+ case ARIZONA_DAC_DIGITAL_VOLUME_4L:
+ case ARIZONA_OUT_VOLUME_4L:
+ case ARIZONA_NOISE_GATE_SELECT_4L:
+ case ARIZONA_DAC_AEC_CONTROL_1:
+ case ARIZONA_NOISE_GATE_CONTROL:
+ case ARIZONA_HP1_SHORT_CIRCUIT_CTRL:
+ case ARIZONA_AIF1_BCLK_CTRL:
+ case ARIZONA_AIF1_TX_PIN_CTRL:
+ case ARIZONA_AIF1_RX_PIN_CTRL:
+ case ARIZONA_AIF1_RATE_CTRL:
+ case ARIZONA_AIF1_FORMAT:
+ case ARIZONA_AIF1_RX_BCLK_RATE:
+ case ARIZONA_AIF1_FRAME_CTRL_1:
+ case ARIZONA_AIF1_FRAME_CTRL_2:
+ case ARIZONA_AIF1_FRAME_CTRL_3:
+ case ARIZONA_AIF1_FRAME_CTRL_4:
+ case ARIZONA_AIF1_FRAME_CTRL_5:
+ case ARIZONA_AIF1_FRAME_CTRL_6:
+ case ARIZONA_AIF1_FRAME_CTRL_7:
+ case ARIZONA_AIF1_FRAME_CTRL_8:
+ case ARIZONA_AIF1_FRAME_CTRL_9:
+ case ARIZONA_AIF1_FRAME_CTRL_10:
+ case ARIZONA_AIF1_FRAME_CTRL_11:
+ case ARIZONA_AIF1_FRAME_CTRL_12:
+ case ARIZONA_AIF1_FRAME_CTRL_13:
+ case ARIZONA_AIF1_FRAME_CTRL_14:
+ case ARIZONA_AIF1_FRAME_CTRL_15:
+ case ARIZONA_AIF1_FRAME_CTRL_16:
+ case ARIZONA_AIF1_FRAME_CTRL_17:
+ case ARIZONA_AIF1_FRAME_CTRL_18:
+ case ARIZONA_AIF1_TX_ENABLES:
+ case ARIZONA_AIF1_RX_ENABLES:
+ case ARIZONA_AIF2_BCLK_CTRL:
+ case ARIZONA_AIF2_TX_PIN_CTRL:
+ case ARIZONA_AIF2_RX_PIN_CTRL:
+ case ARIZONA_AIF2_RATE_CTRL:
+ case ARIZONA_AIF2_FORMAT:
+ case ARIZONA_AIF2_RX_BCLK_RATE:
+ case ARIZONA_AIF2_FRAME_CTRL_1:
+ case ARIZONA_AIF2_FRAME_CTRL_2:
+ case ARIZONA_AIF2_FRAME_CTRL_3:
+ case ARIZONA_AIF2_FRAME_CTRL_4:
+ case ARIZONA_AIF2_FRAME_CTRL_5:
+ case ARIZONA_AIF2_FRAME_CTRL_6:
+ case ARIZONA_AIF2_FRAME_CTRL_7:
+ case ARIZONA_AIF2_FRAME_CTRL_8:
+ case ARIZONA_AIF2_FRAME_CTRL_11:
+ case ARIZONA_AIF2_FRAME_CTRL_12:
+ case ARIZONA_AIF2_FRAME_CTRL_13:
+ case ARIZONA_AIF2_FRAME_CTRL_14:
+ case ARIZONA_AIF2_FRAME_CTRL_15:
+ case ARIZONA_AIF2_FRAME_CTRL_16:
+ case ARIZONA_AIF2_TX_ENABLES:
+ case ARIZONA_AIF2_RX_ENABLES:
+ case ARIZONA_AIF3_BCLK_CTRL:
+ case ARIZONA_AIF3_TX_PIN_CTRL:
+ case ARIZONA_AIF3_RX_PIN_CTRL:
+ case ARIZONA_AIF3_RATE_CTRL:
+ case ARIZONA_AIF3_FORMAT:
+ case ARIZONA_AIF3_RX_BCLK_RATE:
+ case ARIZONA_AIF3_FRAME_CTRL_1:
+ case ARIZONA_AIF3_FRAME_CTRL_2:
+ case ARIZONA_AIF3_FRAME_CTRL_3:
+ case ARIZONA_AIF3_FRAME_CTRL_4:
+ case ARIZONA_AIF3_FRAME_CTRL_11:
+ case ARIZONA_AIF3_FRAME_CTRL_12:
+ case ARIZONA_AIF3_TX_ENABLES:
+ case ARIZONA_AIF3_RX_ENABLES:
+ case ARIZONA_PWM1MIX_INPUT_1_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_1_VOLUME:
+ case ARIZONA_PWM1MIX_INPUT_2_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_2_VOLUME:
+ case ARIZONA_PWM1MIX_INPUT_3_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_3_VOLUME:
+ case ARIZONA_PWM1MIX_INPUT_4_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_4_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_1_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_1_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_2_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_2_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_3_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_3_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_4_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_1_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_1_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_2_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_2_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_3_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_3_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_4_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_4_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_1_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_1_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_2_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_2_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_3_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_3_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_4_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_4_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_1_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_1_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_2_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_2_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_3_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_3_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_4_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_4_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_1_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_1_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_2_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_2_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_3_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_3_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_4_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_4_VOLUME:
+ case ARIZONA_DRC2LMIX_INPUT_1_SOURCE:
+ case ARIZONA_DRC2LMIX_INPUT_1_VOLUME:
+ case ARIZONA_DRC2LMIX_INPUT_2_SOURCE:
+ case ARIZONA_DRC2LMIX_INPUT_2_VOLUME:
+ case ARIZONA_DRC2LMIX_INPUT_3_SOURCE:
+ case ARIZONA_DRC2LMIX_INPUT_3_VOLUME:
+ case ARIZONA_DRC2LMIX_INPUT_4_SOURCE:
+ case ARIZONA_DRC2LMIX_INPUT_4_VOLUME:
+ case ARIZONA_DRC2RMIX_INPUT_1_SOURCE:
+ case ARIZONA_DRC2RMIX_INPUT_1_VOLUME:
+ case ARIZONA_DRC2RMIX_INPUT_2_SOURCE:
+ case ARIZONA_DRC2RMIX_INPUT_2_VOLUME:
+ case ARIZONA_DRC2RMIX_INPUT_3_SOURCE:
+ case ARIZONA_DRC2RMIX_INPUT_3_VOLUME:
+ case ARIZONA_DRC2RMIX_INPUT_4_SOURCE:
+ case ARIZONA_DRC2RMIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_4_VOLUME:
+ case ARIZONA_DSP2LMIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2LMIX_INPUT_1_VOLUME:
+ case ARIZONA_DSP2LMIX_INPUT_2_SOURCE:
+ case ARIZONA_DSP2LMIX_INPUT_2_VOLUME:
+ case ARIZONA_DSP2LMIX_INPUT_3_SOURCE:
+ case ARIZONA_DSP2LMIX_INPUT_3_VOLUME:
+ case ARIZONA_DSP2LMIX_INPUT_4_SOURCE:
+ case ARIZONA_DSP2LMIX_INPUT_4_VOLUME:
+ case ARIZONA_DSP2RMIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2RMIX_INPUT_1_VOLUME:
+ case ARIZONA_DSP2RMIX_INPUT_2_SOURCE:
+ case ARIZONA_DSP2RMIX_INPUT_2_VOLUME:
+ case ARIZONA_DSP2RMIX_INPUT_3_SOURCE:
+ case ARIZONA_DSP2RMIX_INPUT_3_VOLUME:
+ case ARIZONA_DSP2RMIX_INPUT_4_SOURCE:
+ case ARIZONA_DSP2RMIX_INPUT_4_VOLUME:
+ case ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2AUX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2AUX3MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2AUX4MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2AUX5MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP2AUX6MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3LMIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3LMIX_INPUT_1_VOLUME:
+ case ARIZONA_DSP3LMIX_INPUT_2_SOURCE:
+ case ARIZONA_DSP3LMIX_INPUT_2_VOLUME:
+ case ARIZONA_DSP3LMIX_INPUT_3_SOURCE:
+ case ARIZONA_DSP3LMIX_INPUT_3_VOLUME:
+ case ARIZONA_DSP3LMIX_INPUT_4_SOURCE:
+ case ARIZONA_DSP3LMIX_INPUT_4_VOLUME:
+ case ARIZONA_DSP3RMIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3RMIX_INPUT_1_VOLUME:
+ case ARIZONA_DSP3RMIX_INPUT_2_SOURCE:
+ case ARIZONA_DSP3RMIX_INPUT_2_VOLUME:
+ case ARIZONA_DSP3RMIX_INPUT_3_SOURCE:
+ case ARIZONA_DSP3RMIX_INPUT_3_VOLUME:
+ case ARIZONA_DSP3RMIX_INPUT_4_SOURCE:
+ case ARIZONA_DSP3RMIX_INPUT_4_VOLUME:
+ case ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3AUX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3AUX3MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3AUX4MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3AUX5MIX_INPUT_1_SOURCE:
+ case ARIZONA_DSP3AUX6MIX_INPUT_1_SOURCE:
+ case ARIZONA_ASRC1LMIX_INPUT_1_SOURCE:
+ case ARIZONA_ASRC1RMIX_INPUT_1_SOURCE:
+ case ARIZONA_ASRC2LMIX_INPUT_1_SOURCE:
+ case ARIZONA_ASRC2RMIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE:
+ case ARIZONA_GPIO1_CTRL:
+ case ARIZONA_GPIO2_CTRL:
+ case ARIZONA_IRQ_CTRL_1:
+ case ARIZONA_GPIO_DEBOUNCE_CONFIG:
+ case ARIZONA_MISC_PAD_CTRL_1:
+ case ARIZONA_MISC_PAD_CTRL_2:
+ case ARIZONA_MISC_PAD_CTRL_3:
+ case ARIZONA_MISC_PAD_CTRL_4:
+ case ARIZONA_MISC_PAD_CTRL_5:
+ case ARIZONA_MISC_PAD_CTRL_6:
+ case ARIZONA_MISC_PAD_CTRL_7:
+ case ARIZONA_MISC_PAD_CTRL_9:
+ case ARIZONA_MISC_PAD_CTRL_10:
+ case ARIZONA_MISC_PAD_CTRL_11:
+ case ARIZONA_MISC_PAD_CTRL_12:
+ case ARIZONA_MISC_PAD_CTRL_13:
+ case ARIZONA_MISC_PAD_CTRL_14:
+ case ARIZONA_MISC_PAD_CTRL_16:
+ case ARIZONA_INTERRUPT_STATUS_1:
+ case ARIZONA_INTERRUPT_STATUS_2:
+ case ARIZONA_INTERRUPT_STATUS_3:
+ case ARIZONA_INTERRUPT_STATUS_4:
+ case ARIZONA_INTERRUPT_STATUS_5:
+ case ARIZONA_INTERRUPT_STATUS_6:
+ case ARIZONA_INTERRUPT_STATUS_1_MASK:
+ case ARIZONA_INTERRUPT_STATUS_2_MASK:
+ case ARIZONA_INTERRUPT_STATUS_3_MASK:
+ case ARIZONA_INTERRUPT_STATUS_4_MASK:
+ case ARIZONA_INTERRUPT_STATUS_5_MASK:
+ case ARIZONA_INTERRUPT_STATUS_6_MASK:
+ case ARIZONA_INTERRUPT_CONTROL:
+ case ARIZONA_IRQ2_STATUS_1:
+ case ARIZONA_IRQ2_STATUS_2:
+ case ARIZONA_IRQ2_STATUS_3:
+ case ARIZONA_IRQ2_STATUS_4:
+ case ARIZONA_IRQ2_STATUS_5:
+ case ARIZONA_IRQ2_STATUS_6:
+ case ARIZONA_IRQ2_STATUS_1_MASK:
+ case ARIZONA_IRQ2_STATUS_2_MASK:
+ case ARIZONA_IRQ2_STATUS_3_MASK:
+ case ARIZONA_IRQ2_STATUS_4_MASK:
+ case ARIZONA_IRQ2_STATUS_5_MASK:
+ case ARIZONA_IRQ2_STATUS_6_MASK:
+ case ARIZONA_IRQ2_CONTROL:
+ case ARIZONA_INTERRUPT_RAW_STATUS_2:
+ case ARIZONA_INTERRUPT_RAW_STATUS_3:
+ case ARIZONA_INTERRUPT_RAW_STATUS_4:
+ case ARIZONA_INTERRUPT_RAW_STATUS_5:
+ case ARIZONA_INTERRUPT_RAW_STATUS_6:
+ case ARIZONA_INTERRUPT_RAW_STATUS_7:
+ case ARIZONA_INTERRUPT_RAW_STATUS_8:
+ case ARIZONA_INTERRUPT_RAW_STATUS_9:
+ case ARIZONA_IRQ_PIN_STATUS:
+ case ARIZONA_FX_CTRL1:
+ case ARIZONA_FX_CTRL2:
+ case ARIZONA_EQ1_1:
+ case ARIZONA_EQ1_2:
+ case ARIZONA_EQ1_3:
+ case ARIZONA_EQ1_4:
+ case ARIZONA_EQ1_5:
+ case ARIZONA_EQ1_6:
+ case ARIZONA_EQ1_7:
+ case ARIZONA_EQ1_8:
+ case ARIZONA_EQ1_9:
+ case ARIZONA_EQ1_10:
+ case ARIZONA_EQ1_11:
+ case ARIZONA_EQ1_12:
+ case ARIZONA_EQ1_13:
+ case ARIZONA_EQ1_14:
+ case ARIZONA_EQ1_15:
+ case ARIZONA_EQ1_16:
+ case ARIZONA_EQ1_17:
+ case ARIZONA_EQ1_18:
+ case ARIZONA_EQ1_19:
+ case ARIZONA_EQ1_20:
+ case ARIZONA_EQ1_21:
+ case ARIZONA_EQ2_1:
+ case ARIZONA_EQ2_2:
+ case ARIZONA_EQ2_3:
+ case ARIZONA_EQ2_4:
+ case ARIZONA_EQ2_5:
+ case ARIZONA_EQ2_6:
+ case ARIZONA_EQ2_7:
+ case ARIZONA_EQ2_8:
+ case ARIZONA_EQ2_9:
+ case ARIZONA_EQ2_10:
+ case ARIZONA_EQ2_11:
+ case ARIZONA_EQ2_12:
+ case ARIZONA_EQ2_13:
+ case ARIZONA_EQ2_14:
+ case ARIZONA_EQ2_15:
+ case ARIZONA_EQ2_16:
+ case ARIZONA_EQ2_17:
+ case ARIZONA_EQ2_18:
+ case ARIZONA_EQ2_19:
+ case ARIZONA_EQ2_20:
+ case ARIZONA_EQ2_21:
+ case ARIZONA_DRC1_CTRL1:
+ case ARIZONA_DRC1_CTRL2:
+ case ARIZONA_DRC1_CTRL3:
+ case ARIZONA_DRC1_CTRL4:
+ case ARIZONA_DRC1_CTRL5:
+ case ARIZONA_DRC2_CTRL1:
+ case ARIZONA_DRC2_CTRL2:
+ case ARIZONA_DRC2_CTRL3:
+ case ARIZONA_DRC2_CTRL4:
+ case ARIZONA_DRC2_CTRL5:
+ case ARIZONA_HPLPF1_1:
+ case ARIZONA_HPLPF1_2:
+ case ARIZONA_HPLPF2_1:
+ case ARIZONA_HPLPF2_2:
+ case ARIZONA_HPLPF3_1:
+ case ARIZONA_HPLPF3_2:
+ case ARIZONA_HPLPF4_1:
+ case ARIZONA_HPLPF4_2:
+ case ARIZONA_ASRC_ENABLE:
+ case ARIZONA_ASRC_STATUS:
+ case ARIZONA_ASRC_RATE1:
+ case ARIZONA_ASRC_RATE2:
+ case ARIZONA_ISRC_1_CTRL_1:
+ case ARIZONA_ISRC_1_CTRL_2:
+ case ARIZONA_ISRC_1_CTRL_3:
+ case ARIZONA_ISRC_2_CTRL_1:
+ case ARIZONA_ISRC_2_CTRL_2:
+ case ARIZONA_ISRC_2_CTRL_3:
+ case ARIZONA_ISRC_3_CTRL_1:
+ case ARIZONA_ISRC_3_CTRL_2:
+ case ARIZONA_ISRC_3_CTRL_3:
+ case ARIZONA_DSP2_CONTROL_1:
+ case ARIZONA_DSP2_CLOCKING_1:
+ case ARIZONA_DSP2_STATUS_1:
+ case ARIZONA_DSP2_STATUS_2:
+ case ARIZONA_DSP2_STATUS_3:
+ case ARIZONA_DSP2_STATUS_4:
+ case ARIZONA_DSP2_WDMA_BUFFER_1:
+ case ARIZONA_DSP2_WDMA_BUFFER_2:
+ case ARIZONA_DSP2_WDMA_BUFFER_3:
+ case ARIZONA_DSP2_WDMA_BUFFER_4:
+ case ARIZONA_DSP2_WDMA_BUFFER_5:
+ case ARIZONA_DSP2_WDMA_BUFFER_6:
+ case ARIZONA_DSP2_WDMA_BUFFER_7:
+ case ARIZONA_DSP2_WDMA_BUFFER_8:
+ case ARIZONA_DSP2_RDMA_BUFFER_1:
+ case ARIZONA_DSP2_RDMA_BUFFER_2:
+ case ARIZONA_DSP2_RDMA_BUFFER_3:
+ case ARIZONA_DSP2_RDMA_BUFFER_4:
+ case ARIZONA_DSP2_RDMA_BUFFER_5:
+ case ARIZONA_DSP2_RDMA_BUFFER_6:
+ case ARIZONA_DSP2_WDMA_CONFIG_1:
+ case ARIZONA_DSP2_WDMA_CONFIG_2:
+ case ARIZONA_DSP2_WDMA_OFFSET_1:
+ case ARIZONA_DSP2_RDMA_CONFIG_1:
+ case ARIZONA_DSP2_RDMA_OFFSET_1:
+ case ARIZONA_DSP2_EXTERNAL_START_SELECT_1:
+ case ARIZONA_DSP2_SCRATCH_0:
+ case ARIZONA_DSP2_SCRATCH_1:
+ case ARIZONA_DSP2_SCRATCH_2:
+ case ARIZONA_DSP2_SCRATCH_3:
+ case ARIZONA_DSP3_CONTROL_1:
+ case ARIZONA_DSP3_CLOCKING_1:
+ case ARIZONA_DSP3_STATUS_1:
+ case ARIZONA_DSP3_STATUS_2:
+ case ARIZONA_DSP3_STATUS_3:
+ case ARIZONA_DSP3_STATUS_4:
+ case ARIZONA_DSP3_WDMA_BUFFER_1:
+ case ARIZONA_DSP3_WDMA_BUFFER_2:
+ case ARIZONA_DSP3_WDMA_BUFFER_3:
+ case ARIZONA_DSP3_WDMA_BUFFER_4:
+ case ARIZONA_DSP3_WDMA_BUFFER_5:
+ case ARIZONA_DSP3_WDMA_BUFFER_6:
+ case ARIZONA_DSP3_WDMA_BUFFER_7:
+ case ARIZONA_DSP3_WDMA_BUFFER_8:
+ case ARIZONA_DSP3_RDMA_BUFFER_1:
+ case ARIZONA_DSP3_RDMA_BUFFER_2:
+ case ARIZONA_DSP3_RDMA_BUFFER_3:
+ case ARIZONA_DSP3_RDMA_BUFFER_4:
+ case ARIZONA_DSP3_RDMA_BUFFER_5:
+ case ARIZONA_DSP3_RDMA_BUFFER_6:
+ case ARIZONA_DSP3_WDMA_CONFIG_1:
+ case ARIZONA_DSP3_WDMA_CONFIG_2:
+ case ARIZONA_DSP3_WDMA_OFFSET_1:
+ case ARIZONA_DSP3_RDMA_CONFIG_1:
+ case ARIZONA_DSP3_RDMA_OFFSET_1:
+ case ARIZONA_DSP3_EXTERNAL_START_SELECT_1:
+ case ARIZONA_DSP3_SCRATCH_0:
+ case ARIZONA_DSP3_SCRATCH_1:
+ case ARIZONA_DSP3_SCRATCH_2:
+ case ARIZONA_DSP3_SCRATCH_3:
+ return true;
+ default:
+ return cs47l24_is_adsp_memory(reg);
+ }
+}
+
+static bool cs47l24_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ARIZONA_SOFTWARE_RESET:
+ case ARIZONA_DEVICE_REVISION:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_0:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_1:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_2:
+ case ARIZONA_HAPTICS_STATUS:
+ case ARIZONA_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_SAMPLE_RATE_2_STATUS:
+ case ARIZONA_SAMPLE_RATE_3_STATUS:
+ case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
+ case ARIZONA_INPUT_ENABLES_STATUS:
+ case ARIZONA_OUTPUT_STATUS_1:
+ case ARIZONA_RAW_OUTPUT_STATUS_1:
+ case ARIZONA_INTERRUPT_STATUS_1:
+ case ARIZONA_INTERRUPT_STATUS_2:
+ case ARIZONA_INTERRUPT_STATUS_3:
+ case ARIZONA_INTERRUPT_STATUS_4:
+ case ARIZONA_INTERRUPT_STATUS_5:
+ case ARIZONA_INTERRUPT_STATUS_6:
+ case ARIZONA_IRQ2_STATUS_1:
+ case ARIZONA_IRQ2_STATUS_2:
+ case ARIZONA_IRQ2_STATUS_3:
+ case ARIZONA_IRQ2_STATUS_4:
+ case ARIZONA_IRQ2_STATUS_5:
+ case ARIZONA_IRQ2_STATUS_6:
+ case ARIZONA_INTERRUPT_RAW_STATUS_2:
+ case ARIZONA_INTERRUPT_RAW_STATUS_3:
+ case ARIZONA_INTERRUPT_RAW_STATUS_4:
+ case ARIZONA_INTERRUPT_RAW_STATUS_5:
+ case ARIZONA_INTERRUPT_RAW_STATUS_6:
+ case ARIZONA_INTERRUPT_RAW_STATUS_7:
+ case ARIZONA_INTERRUPT_RAW_STATUS_8:
+ case ARIZONA_INTERRUPT_RAW_STATUS_9:
+ case ARIZONA_IRQ_PIN_STATUS:
+ case ARIZONA_FX_CTRL2:
+ case ARIZONA_ASRC_STATUS:
+ case ARIZONA_DSP2_STATUS_1:
+ case ARIZONA_DSP2_STATUS_2:
+ case ARIZONA_DSP2_STATUS_3:
+ case ARIZONA_DSP2_STATUS_4:
+ case ARIZONA_DSP2_WDMA_BUFFER_1:
+ case ARIZONA_DSP2_WDMA_BUFFER_2:
+ case ARIZONA_DSP2_WDMA_BUFFER_3:
+ case ARIZONA_DSP2_WDMA_BUFFER_4:
+ case ARIZONA_DSP2_WDMA_BUFFER_5:
+ case ARIZONA_DSP2_WDMA_BUFFER_6:
+ case ARIZONA_DSP2_WDMA_BUFFER_7:
+ case ARIZONA_DSP2_WDMA_BUFFER_8:
+ case ARIZONA_DSP2_RDMA_BUFFER_1:
+ case ARIZONA_DSP2_RDMA_BUFFER_2:
+ case ARIZONA_DSP2_RDMA_BUFFER_3:
+ case ARIZONA_DSP2_RDMA_BUFFER_4:
+ case ARIZONA_DSP2_RDMA_BUFFER_5:
+ case ARIZONA_DSP2_RDMA_BUFFER_6:
+ case ARIZONA_DSP2_WDMA_CONFIG_1:
+ case ARIZONA_DSP2_WDMA_CONFIG_2:
+ case ARIZONA_DSP2_WDMA_OFFSET_1:
+ case ARIZONA_DSP2_RDMA_CONFIG_1:
+ case ARIZONA_DSP2_RDMA_OFFSET_1:
+ case ARIZONA_DSP2_EXTERNAL_START_SELECT_1:
+ case ARIZONA_DSP2_SCRATCH_0:
+ case ARIZONA_DSP2_SCRATCH_1:
+ case ARIZONA_DSP2_SCRATCH_2:
+ case ARIZONA_DSP2_SCRATCH_3:
+ case ARIZONA_DSP2_CLOCKING_1:
+ case ARIZONA_DSP3_STATUS_1:
+ case ARIZONA_DSP3_STATUS_2:
+ case ARIZONA_DSP3_STATUS_3:
+ case ARIZONA_DSP3_STATUS_4:
+ case ARIZONA_DSP3_WDMA_BUFFER_1:
+ case ARIZONA_DSP3_WDMA_BUFFER_2:
+ case ARIZONA_DSP3_WDMA_BUFFER_3:
+ case ARIZONA_DSP3_WDMA_BUFFER_4:
+ case ARIZONA_DSP3_WDMA_BUFFER_5:
+ case ARIZONA_DSP3_WDMA_BUFFER_6:
+ case ARIZONA_DSP3_WDMA_BUFFER_7:
+ case ARIZONA_DSP3_WDMA_BUFFER_8:
+ case ARIZONA_DSP3_RDMA_BUFFER_1:
+ case ARIZONA_DSP3_RDMA_BUFFER_2:
+ case ARIZONA_DSP3_RDMA_BUFFER_3:
+ case ARIZONA_DSP3_RDMA_BUFFER_4:
+ case ARIZONA_DSP3_RDMA_BUFFER_5:
+ case ARIZONA_DSP3_RDMA_BUFFER_6:
+ case ARIZONA_DSP3_WDMA_CONFIG_1:
+ case ARIZONA_DSP3_WDMA_CONFIG_2:
+ case ARIZONA_DSP3_WDMA_OFFSET_1:
+ case ARIZONA_DSP3_RDMA_CONFIG_1:
+ case ARIZONA_DSP3_RDMA_OFFSET_1:
+ case ARIZONA_DSP3_EXTERNAL_START_SELECT_1:
+ case ARIZONA_DSP3_SCRATCH_0:
+ case ARIZONA_DSP3_SCRATCH_1:
+ case ARIZONA_DSP3_SCRATCH_2:
+ case ARIZONA_DSP3_SCRATCH_3:
+ case ARIZONA_DSP3_CLOCKING_1:
+ return true;
+ default:
+ return cs47l24_is_adsp_memory(reg);
+ }
+}
+
+#define CS47L24_MAX_REGISTER 0x3b3fff
+
+const struct regmap_config cs47l24_spi_regmap = {
+ .reg_bits = 32,
+ .pad_bits = 16,
+ .val_bits = 16,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = CS47L24_MAX_REGISTER,
+ .readable_reg = cs47l24_readable_register,
+ .volatile_reg = cs47l24_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = cs47l24_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs47l24_reg_default),
+};
+EXPORT_SYMBOL_GPL(cs47l24_spi_regmap);
+
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
index be91cb5d6e78..f9d277ff4aaf 100644
--- a/drivers/mfd/cs5535-mfd.c
+++ b/drivers/mfd/cs5535-mfd.c
@@ -60,6 +60,7 @@ static int cs5535_mfd_res_enable(struct platform_device *pdev)
static int cs5535_mfd_res_disable(struct platform_device *pdev)
{
struct resource *res;
+
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res) {
dev_err(&pdev->dev, "can't fetch device resource info\n");
@@ -114,7 +115,10 @@ static struct mfd_cell cs5535_mfd_cells[] = {
#ifdef CONFIG_OLPC
static void cs5535_clone_olpc_cells(void)
{
- const char *acpi_clones[] = { "olpc-xo1-pm-acpi", "olpc-xo1-sci-acpi" };
+ static const char *acpi_clones[] = {
+ "olpc-xo1-pm-acpi",
+ "olpc-xo1-sci-acpi"
+ };
if (!machine_is_olpc())
return;
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index 37e4426ef061..09f367571c58 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -2,10 +2,10 @@
* Base driver for Dialog Semiconductor DA9030/DA9034
*
* Copyright (C) 2008 Compulab, Ltd.
- * Mike Rapoport <mike@compulab.co.il>
+ * Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
- * Eric Miao <eric.miao@marvell.com>
+ * Eric Miao <eric.miao@marvell.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
@@ -60,7 +60,7 @@ struct da903x_chip_ops {
struct da903x_chip {
struct i2c_client *client;
struct device *dev;
- struct da903x_chip_ops *ops;
+ const struct da903x_chip_ops *ops;
int type;
uint32_t events_mask;
@@ -424,7 +424,7 @@ static irqreturn_t da903x_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static struct da903x_chip_ops da903x_ops[] = {
+static const struct da903x_chip_ops da903x_ops[] = {
[0] = {
.init_chip = da9030_init_chip,
.unmask_events = da9030_unmask_events,
@@ -565,6 +565,6 @@ static void __exit da903x_exit(void)
module_exit(da903x_exit);
MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034");
-MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
- "Mike Rapoport <mike@compulab.co.il>");
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 2697ffb08009..578e881067a5 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -70,7 +70,7 @@ static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
case DA9053_BA:
case DA9053_BB:
/* A dummy read to a safe register address. */
- if (!i2c_safe_reg(reg))
+ if (!i2c_safe_reg(reg))
return regmap_read(da9052->regmap,
DA9052_PARK_REGISTER,
&val);
diff --git a/drivers/mfd/da9052-irq.c b/drivers/mfd/da9052-irq.c
index f4cb4613140b..cd4ca849ca44 100644
--- a/drivers/mfd/da9052-irq.c
+++ b/drivers/mfd/da9052-irq.c
@@ -283,7 +283,7 @@ regmap_err:
int da9052_irq_exit(struct da9052 *da9052)
{
- da9052_free_irq(da9052, DA9052_IRQ_ADC_EOM , da9052);
+ da9052_free_irq(da9052, DA9052_IRQ_ADC_EOM, da9052);
regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data);
return 0;
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index 9bbc642a7b9d..dff2f19296b8 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -47,11 +47,8 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
davinci_vc = devm_kzalloc(&pdev->dev,
sizeof(struct davinci_vc), GFP_KERNEL);
- if (!davinci_vc) {
- dev_dbg(&pdev->dev,
- "could not allocate memory for private data\n");
+ if (!davinci_vc)
return -ENOMEM;
- }
davinci_vc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(davinci_vc->clk)) {
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
index 4c826f78acd0..ec4438ed2faf 100644
--- a/drivers/mfd/dm355evm_msp.c
+++ b/drivers/mfd/dm355evm_msp.c
@@ -147,7 +147,7 @@ static int msp_gpio_get(struct gpio_chip *chip, unsigned offset)
return status;
if (reg == DM355EVM_MSP_LED)
msp_led_cache = status;
- return status & MSP_GPIO_MASK(offset);
+ return !!(status & MSP_GPIO_MASK(offset));
}
static int msp_gpio_out(struct gpio_chip *chip, unsigned offset, int value)
@@ -259,7 +259,7 @@ static int add_children(struct i2c_client *client)
int i;
/* GPIO-ish stuff */
- dm355evm_msp_gpio.dev = &client->dev;
+ dm355evm_msp_gpio.parent = &client->dev;
status = gpiochip_add(&dm355evm_msp_gpio);
if (status < 0)
return status;
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index 6ccaf90d98fd..c636b5f83cfb 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -163,7 +163,7 @@ static int egpio_get(struct gpio_chip *chip, unsigned offset)
value = egpio_readw(ei, reg);
pr_debug("readw(%p + %x) = %x\n",
ei->base_addr, reg << ei->bus_shift, value);
- return value & bit;
+ return !!(value & bit);
}
static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -321,7 +321,7 @@ static int __init egpio_probe(struct platform_device *pdev)
ei->chip[i].dev = &(pdev->dev);
chip = &(ei->chip[i].chip);
chip->label = "htc-egpio";
- chip->dev = &pdev->dev;
+ chip->parent = &pdev->dev;
chip->owner = THIS_MODULE;
chip->get = egpio_get;
chip->set = egpio_set;
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
index 0c6ff727b2ec..bd6b96d07ab8 100644
--- a/drivers/mfd/htc-i2cpld.c
+++ b/drivers/mfd/htc-i2cpld.c
@@ -429,7 +429,7 @@ static int htcpld_register_chip_gpio(
/* Setup the GPIO chips */
gpio_chip = &(chip->chip_out);
gpio_chip->label = "htcpld-out";
- gpio_chip->dev = dev;
+ gpio_chip->parent = dev;
gpio_chip->owner = THIS_MODULE;
gpio_chip->get = htcpld_chip_get;
gpio_chip->set = htcpld_chip_set;
@@ -440,7 +440,7 @@ static int htcpld_register_chip_gpio(
gpio_chip = &(chip->chip_in);
gpio_chip->label = "htcpld-in";
- gpio_chip->dev = dev;
+ gpio_chip->parent = dev;
gpio_chip->owner = THIS_MODULE;
gpio_chip->get = htcpld_chip_get;
gpio_chip->set = NULL;
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index b514f3cf140d..bd3aa4578346 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -55,6 +55,7 @@
* document number TBD : Coleto Creek
* document number TBD : Wildcat Point-LP
* document number TBD : 9 Series
+ * document number TBD : Lewisburg
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -213,6 +214,7 @@ enum lpc_chipsets {
LPC_COLETO, /* Coleto Creek */
LPC_WPT_LP, /* Wildcat Point-LP */
LPC_BRASWELL, /* Braswell SoC */
+ LPC_LEWISBURG, /* Lewisburg */
LPC_9S, /* 9 Series */
};
@@ -521,6 +523,10 @@ static struct lpc_ich_info lpc_chipset_info[] = {
.name = "Braswell SoC",
.iTCO_version = 3,
},
+ [LPC_LEWISBURG] = {
+ .name = "Lewisburg",
+ .iTCO_version = 2,
+ },
[LPC_9S] = {
.name = "9 Series",
.iTCO_version = 2,
@@ -757,6 +763,15 @@ static const struct pci_device_id lpc_ich_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9cc6), LPC_WPT_LP},
{ PCI_VDEVICE(INTEL, 0x9cc7), LPC_WPT_LP},
{ PCI_VDEVICE(INTEL, 0x9cc9), LPC_WPT_LP},
+ { PCI_VDEVICE(INTEL, 0xa1c1), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa1c2), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa1c3), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa1c4), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa1c5), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa1c6), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa1c7), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa242), LPC_LEWISBURG},
+ { PCI_VDEVICE(INTEL, 0xa243), LPC_LEWISBURG},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 56e216dedc91..2280b3fdcf68 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -495,7 +495,7 @@ MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
#ifdef CONFIG_PM_SLEEP
static int max14577_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max14577 *max14577 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
@@ -516,7 +516,7 @@ static int max14577_suspend(struct device *dev)
static int max14577_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max14577 *max14577 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index d19be64cd32b..d959ebbb2194 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -352,7 +352,7 @@ MODULE_DEVICE_TABLE(i2c, max77686_i2c_id);
#ifdef CONFIG_PM_SLEEP
static int max77686_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
@@ -374,7 +374,7 @@ static int max77686_suspend(struct device *dev)
static int max77686_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index 007f729e150b..b83b7a7da1ae 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -334,7 +334,7 @@ MODULE_DEVICE_TABLE(i2c, max77693_i2c_id);
static int max77693_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max77693_dev *max77693 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev)) {
@@ -347,7 +347,7 @@ static int max77693_suspend(struct device *dev)
static int max77693_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max77693_dev *max77693 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev)) {
diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
index 586098f1b233..7cfc95b49c5d 100644
--- a/drivers/mfd/max77843.c
+++ b/drivers/mfd/max77843.c
@@ -197,7 +197,7 @@ MODULE_DEVICE_TABLE(i2c, max77843_id);
static int __maybe_unused max77843_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max77693_dev *max77843 = i2c_get_clientdata(i2c);
disable_irq(max77843->irq);
@@ -209,7 +209,7 @@ static int __maybe_unused max77843_suspend(struct device *dev)
static int __maybe_unused max77843_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max77693_dev *max77843 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index b0fe8103e401..70443b161a5b 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -215,7 +215,7 @@ static int max8925_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int max8925_suspend(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct max8925_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
@@ -225,7 +225,7 @@ static int max8925_suspend(struct device *dev)
static int max8925_resume(struct device *dev)
{
- struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct max8925_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 156ed6f92aa3..f316348e3d98 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -437,7 +437,7 @@ static u8 max8997_dumpaddr_haptic[] = {
static int max8997_freeze(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
int i;
@@ -459,7 +459,7 @@ static int max8997_freeze(struct device *dev)
static int max8997_restore(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
int i;
@@ -481,7 +481,7 @@ static int max8997_restore(struct device *dev)
static int max8997_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
@@ -491,7 +491,7 @@ static int max8997_suspend(struct device *dev)
static int max8997_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index a7afe3bf27fc..ab28b29400f6 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -274,7 +274,7 @@ MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
static int max8998_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
@@ -284,7 +284,7 @@ static int max8998_suspend(struct device *dev)
static int max8998_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
@@ -344,7 +344,7 @@ static struct max8998_reg_dump max8998_dump[] = {
/* Save registers before hibernation */
static int max8998_freeze(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
int i;
for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
@@ -357,7 +357,7 @@ static int max8998_freeze(struct device *dev)
/* Restore registers after hibernation */
static int max8998_restore(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
int i;
for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 3f9f4c874d2a..d7f54e492aa6 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -383,16 +383,16 @@ static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
if (!np)
return -ENODEV;
- if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
+ if (of_property_read_bool(np, "fsl,mc13xxx-uses-adc"))
mc13xxx->flags |= MC13XXX_USE_ADC;
- if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
+ if (of_property_read_bool(np, "fsl,mc13xxx-uses-codec"))
mc13xxx->flags |= MC13XXX_USE_CODEC;
- if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
+ if (of_property_read_bool(np, "fsl,mc13xxx-uses-rtc"))
mc13xxx->flags |= MC13XXX_USE_RTC;
- if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
+ if (of_property_read_bool(np, "fsl,mc13xxx-uses-touch"))
mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
return 0;
diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c
index af6ac1c4b45c..8653e8b9bb4f 100644
--- a/drivers/mfd/qcom-spmi-pmic.c
+++ b/drivers/mfd/qcom-spmi-pmic.c
@@ -127,7 +127,9 @@ static int pmic_spmi_probe(struct spmi_device *sdev)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- pmic_spmi_show_revid(regmap, &sdev->dev);
+ /* Only the first slave id for a PMIC contains this information */
+ if (sdev->usid % 2 == 0)
+ pmic_spmi_show_revid(regmap, &sdev->dev);
return of_platform_populate(root, NULL, NULL, &sdev->dev);
}
diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c
index 207a3bd68559..1be47ad6441b 100644
--- a/drivers/mfd/qcom_rpm.c
+++ b/drivers/mfd/qcom_rpm.c
@@ -495,6 +495,8 @@ static int qcom_rpm_probe(struct platform_device *pdev)
}
match = of_match_device(qcom_rpm_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
rpm->data = match->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 989076d6cb83..400e1d7d8d08 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -29,6 +29,7 @@
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
+#include <linux/mfd/samsung/s2mps15.h>
#include <linux/mfd/samsung/s2mpu02.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
@@ -67,7 +68,7 @@ static const struct mfd_cell s5m8767_devs[] = {
static const struct mfd_cell s2mps11_devs[] = {
{
- .name = "s2mps11-pmic",
+ .name = "s2mps11-regulator",
}, {
.name = "s2mps14-rtc",
}, {
@@ -77,7 +78,7 @@ static const struct mfd_cell s2mps11_devs[] = {
};
static const struct mfd_cell s2mps13_devs[] = {
- { .name = "s2mps13-pmic", },
+ { .name = "s2mps13-regulator", },
{ .name = "s2mps13-rtc", },
{
.name = "s2mps13-clk",
@@ -87,7 +88,7 @@ static const struct mfd_cell s2mps13_devs[] = {
static const struct mfd_cell s2mps14_devs[] = {
{
- .name = "s2mps14-pmic",
+ .name = "s2mps14-regulator",
}, {
.name = "s2mps14-rtc",
}, {
@@ -96,6 +97,17 @@ static const struct mfd_cell s2mps14_devs[] = {
}
};
+static const struct mfd_cell s2mps15_devs[] = {
+ {
+ .name = "s2mps15-regulator",
+ }, {
+ .name = "s2mps15-rtc",
+ }, {
+ .name = "s2mps13-clk",
+ .of_compatible = "samsung,s2mps13-clk",
+ },
+};
+
static const struct mfd_cell s2mpa01_devs[] = {
{
.name = "s2mpa01-pmic",
@@ -104,7 +116,7 @@ static const struct mfd_cell s2mpa01_devs[] = {
static const struct mfd_cell s2mpu02_devs[] = {
{
- .name = "s2mpu02-pmic",
+ .name = "s2mpu02-regulator",
},
};
@@ -122,6 +134,9 @@ static const struct of_device_id sec_dt_match[] = {
.compatible = "samsung,s2mps14-pmic",
.data = (void *)S2MPS14X,
}, {
+ .compatible = "samsung,s2mps15-pmic",
+ .data = (void *)S2MPS15X,
+ }, {
.compatible = "samsung,s2mpa01-pmic",
.data = (void *)S2MPA01,
}, {
@@ -223,6 +238,15 @@ static const struct regmap_config s2mps14_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static const struct regmap_config s2mps15_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS15_REG_LDODSCH4,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static const struct regmap_config s2mpu02_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -384,6 +408,9 @@ static int sec_pmic_probe(struct i2c_client *i2c,
case S2MPS14X:
regmap = &s2mps14_regmap_config;
break;
+ case S2MPS15X:
+ regmap = &s2mps15_regmap_config;
+ break;
case S5M8763X:
regmap = &s5m8763_regmap_config;
break;
@@ -442,6 +469,10 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_devs = s2mps14_devs;
num_sec_devs = ARRAY_SIZE(s2mps14_devs);
break;
+ case S2MPS15X:
+ sec_devs = s2mps15_devs;
+ num_sec_devs = ARRAY_SIZE(s2mps15_devs);
+ break;
case S2MPU02:
sec_devs = s2mpu02_devs;
num_sec_devs = ARRAY_SIZE(s2mpu02_devs);
@@ -505,7 +536,7 @@ static void sec_pmic_shutdown(struct i2c_client *i2c)
#ifdef CONFIG_PM_SLEEP
static int sec_pmic_suspend(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
@@ -526,7 +557,7 @@ static int sec_pmic_suspend(struct device *dev)
static int sec_pmic_resume(struct device *dev)
{
- struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *i2c = to_i2c_client(dev);
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev))
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index 806fa8dbb22d..d77de431cc50 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -407,6 +407,11 @@ static const struct regmap_irq_chip s2mps14_irq_chip = {
S2MPS1X_IRQ_CHIP_COMMON_DATA,
};
+static const struct regmap_irq_chip s2mps15_irq_chip = {
+ .name = "s2mps15",
+ S2MPS1X_IRQ_CHIP_COMMON_DATA,
+};
+
static const struct regmap_irq_chip s2mpu02_irq_chip = {
.name = "s2mpu02",
.irqs = s2mpu02_irqs,
@@ -466,6 +471,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
case S2MPS14X:
sec_irq_chip = &s2mps14_irq_chip;
break;
+ case S2MPS15X:
+ sec_irq_chip = &s2mps15_irq_chip;
+ break;
case S2MPU02:
sec_irq_chip = &s2mpu02_irq_chip;
break;
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c
index b3e5c6f45105..9292202039ee 100644
--- a/drivers/mfd/sta2x11-mfd.c
+++ b/drivers/mfd/sta2x11-mfd.c
@@ -372,12 +372,6 @@ static struct platform_driver sta2x11_sctl_platform_driver = {
.probe = sta2x11_sctl_probe,
};
-static int __init sta2x11_sctl_init(void)
-{
- pr_info("%s\n", __func__);
- return platform_driver_register(&sta2x11_sctl_platform_driver);
-}
-
static struct platform_driver sta2x11_platform_driver = {
.driver = {
.name = STA2X11_MFD_APBREG_NAME,
@@ -385,12 +379,6 @@ static struct platform_driver sta2x11_platform_driver = {
.probe = sta2x11_apbreg_probe,
};
-static int __init sta2x11_apbreg_init(void)
-{
- pr_info("%s\n", __func__);
- return platform_driver_register(&sta2x11_platform_driver);
-}
-
static struct platform_driver sta2x11_apb_soc_regs_platform_driver = {
.driver = {
.name = STA2X11_MFD_APB_SOC_REGS_NAME,
@@ -398,12 +386,6 @@ static struct platform_driver sta2x11_apb_soc_regs_platform_driver = {
.probe = sta2x11_apb_soc_regs_probe,
};
-static int __init sta2x11_apb_soc_regs_init(void)
-{
- pr_info("%s\n", __func__);
- return platform_driver_register(&sta2x11_apb_soc_regs_platform_driver);
-}
-
static struct platform_driver sta2x11_scr_platform_driver = {
.driver = {
.name = STA2X11_MFD_SCR_NAME,
@@ -411,13 +393,18 @@ static struct platform_driver sta2x11_scr_platform_driver = {
.probe = sta2x11_scr_probe,
};
-static int __init sta2x11_scr_init(void)
+static struct platform_driver * const drivers[] = {
+ &sta2x11_platform_driver,
+ &sta2x11_sctl_platform_driver,
+ &sta2x11_apb_soc_regs_platform_driver,
+ &sta2x11_scr_platform_driver,
+};
+
+static int __init sta2x11_drivers_init(void)
{
- pr_info("%s\n", __func__);
- return platform_driver_register(&sta2x11_scr_platform_driver);
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
-
/*
* What follows are the PCI devices that host the above pdevs.
* Each logic block is 4kB and they are all consecutive: we use this info.
@@ -664,10 +651,7 @@ static int __init sta2x11_mfd_init(void)
* prepares platform drivers very early and probe the PCI device later,
* but before other PCI devices.
*/
-subsys_initcall(sta2x11_apbreg_init);
-subsys_initcall(sta2x11_sctl_init);
-subsys_initcall(sta2x11_apb_soc_regs_init);
-subsys_initcall(sta2x11_scr_init);
+subsys_initcall(sta2x11_drivers_init);
rootfs_initcall(sta2x11_mfd_init);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 176bf0fa2685..b7aabeefab07 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -47,6 +47,7 @@ static struct syscon *of_syscon_register(struct device_node *np)
struct syscon *syscon;
struct regmap *regmap;
void __iomem *base;
+ u32 reg_io_width;
int ret;
struct regmap_config syscon_config = syscon_regmap_config;
@@ -69,6 +70,18 @@ static struct syscon *of_syscon_register(struct device_node *np)
else if (of_property_read_bool(np, "little-endian"))
syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
+ /*
+ * search for reg-io-width property in DT. If it is not provided,
+ * default to 4 bytes. regmap_init_mmio will return an error if values
+ * are invalid so there is no need to check them here.
+ */
+ ret = of_property_read_u32(np, "reg-io-width", &reg_io_width);
+ if (ret)
+ reg_io_width = 4;
+
+ syscon_config.reg_stride = reg_io_width;
+ syscon_config.val_bits = reg_io_width * 8;
+
regmap = regmap_init_mmio(NULL, base, &syscon_config);
if (IS_ERR(regmap)) {
pr_err("regmap init failed\n");
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 8c84a513016b..1ecbfa40d1b3 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -437,8 +437,8 @@ static int tc6393xb_gpio_get(struct gpio_chip *chip,
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
/* XXX: does dsr also represent inputs? */
- return tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8))
- & TC_GPIO_BIT(offset);
+ return !!(tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8))
+ & TC_GPIO_BIT(offset));
}
static void __tc6393xb_gpio_set(struct gpio_chip *chip,
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index 448f0a182dc4..83e615ed100a 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -499,11 +499,11 @@ static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset)
if (offset < 4) {
value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
if (value < 0)
- return 0;
+ return value;
if (value & (1 << (offset + 4))) /* output */
return !(value & (1 << offset));
else /* input */
- return (value & (1 << offset));
+ return !!(value & (1 << offset));
}
/* REVISIT we *could* report LED1/nPG and LED2 state ... */
@@ -638,7 +638,7 @@ static int tps65010_probe(struct i2c_client *client,
tps->outmask = board->outmask;
tps->chip.label = client->name;
- tps->chip.dev = &client->dev;
+ tps->chip.parent = &client->dev;
tps->chip.owner = THIS_MODULE;
tps->chip.set = tps65010_gpio_set;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index f691d7ecad52..bcafe1ecd71c 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -133,7 +133,7 @@ static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
val = ucb1x00_reg_read(ucb, UCB_IO_DATA);
ucb1x00_disable(ucb);
- return val & (1 << offset);
+ return !!(val & (1 << offset));
}
static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -570,7 +570,7 @@ static int ucb1x00_probe(struct mcp *mcp)
if (pdata && pdata->gpio_base) {
ucb->gpio.label = dev_name(&ucb->dev);
- ucb->gpio.dev = &ucb->dev;
+ ucb->gpio.parent = &ucb->dev;
ucb->gpio.owner = THIS_MODULE;
ucb->gpio.base = pdata->gpio_base;
ucb->gpio.ngpio = 10;
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index 3e628df9280c..855c0204f09a 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -11,7 +11,7 @@
* Copyright (C) 2012 ARM Limited
*/
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mfd/core.h>
@@ -164,7 +164,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
{
struct resource *mem;
void __iomem *base;
- struct bgpio_chip *mmc_gpio_chip;
+ struct gpio_chip *mmc_gpio_chip;
int master;
u32 dt_hbi;
@@ -201,8 +201,8 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
return -ENOMEM;
bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
NULL, NULL, NULL, NULL, 0);
- mmc_gpio_chip->gc.ngpio = 2;
- gpiochip_add(&mmc_gpio_chip->gc);
+ mmc_gpio_chip->ngpio = 2;
+ gpiochip_add(mmc_gpio_chip);
return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
vexpress_sysreg_cells,
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index 2bb2d0467a92..c18e11f42b3f 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -762,9 +762,9 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */
{ 0x00000210, 0x0184 }, /* R528 - LDO1 Control 1 */
{ 0x00000213, 0x03E4 }, /* R531 - LDO2 Control 1 */
- { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
- { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
- { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
+ { 0x00000218, 0x00E6 }, /* R536 - Mic Bias Ctrl 1 */
+ { 0x00000219, 0x00E6 }, /* R537 - Mic Bias Ctrl 2 */
+ { 0x0000021A, 0x00E6 }, /* R538 - Mic Bias Ctrl 3 */
{ 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
{ 0x0000029B, 0x0028 }, /* R667 - Headphone Detect 1 */
{ 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */
diff --git a/drivers/mfd/wm831x-otp.c b/drivers/mfd/wm831x-otp.c
index b90f3e06b6c9..ebac0027f8e0 100644
--- a/drivers/mfd/wm831x-otp.c
+++ b/drivers/mfd/wm831x-otp.c
@@ -47,20 +47,14 @@ static ssize_t wm831x_unique_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct wm831x *wm831x = dev_get_drvdata(dev);
- int i, rval;
+ int rval;
char id[WM831X_UNIQUE_ID_LEN];
- ssize_t ret = 0;
rval = wm831x_unique_id_read(wm831x, id);
if (rval < 0)
return 0;
- for (i = 0; i < WM831X_UNIQUE_ID_LEN; i++)
- ret += sprintf(&buf[ret], "%02x", buf[i]);
-
- ret += sprintf(&buf[ret], "\n");
-
- return ret;
+ return sprintf(buf, "%*phN\n", WM831X_UNIQUE_ID_LEN, id);
}
static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL);
diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile
index 6982f603fadc..be2ac5ce349f 100644
--- a/drivers/misc/cxl/Makefile
+++ b/drivers/misc/cxl/Makefile
@@ -1,4 +1,5 @@
-ccflags-y := -Werror -Wno-unused-const-variable
+ccflags-y := $(call cc-disable-warning, unused-const-variable)
+ccflags-$(CONFIG_PPC_WERROR) += -Werror
cxl-y += main.o file.o irq.o fault.o native.o
cxl-y += context.o sysfs.o debugfs.o pci.o trace.o
diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c
index 103baf0e0c5b..ea3eeb7011e1 100644
--- a/drivers/misc/cxl/api.c
+++ b/drivers/misc/cxl/api.c
@@ -25,7 +25,6 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
afu = cxl_pci_to_afu(dev);
- get_device(&afu->dev);
ctx = cxl_context_alloc();
if (IS_ERR(ctx)) {
rc = PTR_ERR(ctx);
@@ -61,7 +60,6 @@ err_mapping:
err_ctx:
kfree(ctx);
err_dev:
- put_device(&afu->dev);
return ERR_PTR(rc);
}
EXPORT_SYMBOL_GPL(cxl_dev_context_init);
@@ -87,8 +85,6 @@ int cxl_release_context(struct cxl_context *ctx)
if (ctx->status >= STARTED)
return -EBUSY;
- put_device(&ctx->afu->dev);
-
cxl_context_free(ctx);
return 0;
@@ -176,7 +172,7 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
if (task) {
ctx->pid = get_task_pid(task, PIDTYPE_PID);
- get_pid(ctx->pid);
+ ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID);
kernel = false;
}
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
index 2faa1270d085..262b88eac414 100644
--- a/drivers/misc/cxl/context.c
+++ b/drivers/misc/cxl/context.c
@@ -42,7 +42,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
spin_lock_init(&ctx->sste_lock);
ctx->afu = afu;
ctx->master = master;
- ctx->pid = NULL; /* Set in start work ioctl */
+ ctx->pid = ctx->glpid = NULL; /* Set in start work ioctl */
mutex_init(&ctx->mapping_lock);
ctx->mapping = mapping;
@@ -97,6 +97,12 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
ctx->pe = i;
ctx->elem = &ctx->afu->spa[i];
ctx->pe_inserted = false;
+
+ /*
+ * take a ref on the afu so that it stays alive at-least till
+ * this context is reclaimed inside reclaim_ctx.
+ */
+ cxl_afu_get(afu);
return 0;
}
@@ -211,7 +217,11 @@ int __detach_context(struct cxl_context *ctx)
WARN_ON(cxl_detach_process(ctx) &&
cxl_adapter_link_ok(ctx->afu->adapter));
flush_work(&ctx->fault_work); /* Only needed for dedicated process */
+
+ /* release the reference to the group leader and mm handling pid */
put_pid(ctx->pid);
+ put_pid(ctx->glpid);
+
cxl_ctx_put();
return 0;
}
@@ -278,6 +288,9 @@ static void reclaim_ctx(struct rcu_head *rcu)
if (ctx->irq_bitmap)
kfree(ctx->irq_bitmap);
+ /* Drop ref to the afu device taken during cxl_context_init */
+ cxl_afu_put(ctx->afu);
+
kfree(ctx);
}
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index 0cfb9c129f27..a521bc72cec2 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -403,6 +403,18 @@ struct cxl_afu {
bool enabled;
};
+/* AFU refcount management */
+static inline struct cxl_afu *cxl_afu_get(struct cxl_afu *afu)
+{
+
+ return (get_device(&afu->dev) == NULL) ? NULL : afu;
+}
+
+static inline void cxl_afu_put(struct cxl_afu *afu)
+{
+ put_device(&afu->dev);
+}
+
struct cxl_irq_name {
struct list_head list;
@@ -433,6 +445,9 @@ struct cxl_context {
unsigned int sst_size, sst_lru;
wait_queue_head_t wq;
+ /* pid of the group leader associated with the pid */
+ struct pid *glpid;
+ /* use mm context associated with this pid for ds faults */
struct pid *pid;
spinlock_t lock; /* Protects pending_irq_mask, pending_fault and fault_addr */
/* Only used in PR mode */
diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c
index 25a5418c55cb..81c3f75b7330 100644
--- a/drivers/misc/cxl/fault.c
+++ b/drivers/misc/cxl/fault.c
@@ -166,13 +166,92 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
cxl_ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
}
+/*
+ * Returns the mm_struct corresponding to the context ctx via ctx->pid
+ * In case the task has exited we use the task group leader accessible
+ * via ctx->glpid to find the next task in the thread group that has a
+ * valid mm_struct associated with it. If a task with valid mm_struct
+ * is found the ctx->pid is updated to use the task struct for subsequent
+ * translations. In case no valid mm_struct is found in the task group to
+ * service the fault a NULL is returned.
+ */
+static struct mm_struct *get_mem_context(struct cxl_context *ctx)
+{
+ struct task_struct *task = NULL;
+ struct mm_struct *mm = NULL;
+ struct pid *old_pid = ctx->pid;
+
+ if (old_pid == NULL) {
+ pr_warn("%s: Invalid context for pe=%d\n",
+ __func__, ctx->pe);
+ return NULL;
+ }
+
+ task = get_pid_task(old_pid, PIDTYPE_PID);
+
+ /*
+ * pid_alive may look racy but this saves us from costly
+ * get_task_mm when the task is a zombie. In worst case
+ * we may think a task is alive, which is about to die
+ * but get_task_mm will return NULL.
+ */
+ if (task != NULL && pid_alive(task))
+ mm = get_task_mm(task);
+
+ /* release the task struct that was taken earlier */
+ if (task)
+ put_task_struct(task);
+ else
+ pr_devel("%s: Context owning pid=%i for pe=%i dead\n",
+ __func__, pid_nr(old_pid), ctx->pe);
+
+ /*
+ * If we couldn't find the mm context then use the group
+ * leader to iterate over the task group and find a task
+ * that gives us mm_struct.
+ */
+ if (unlikely(mm == NULL && ctx->glpid != NULL)) {
+
+ rcu_read_lock();
+ task = pid_task(ctx->glpid, PIDTYPE_PID);
+ if (task)
+ do {
+ mm = get_task_mm(task);
+ if (mm) {
+ ctx->pid = get_task_pid(task,
+ PIDTYPE_PID);
+ break;
+ }
+ task = next_thread(task);
+ } while (task && !thread_group_leader(task));
+ rcu_read_unlock();
+
+ /* check if we switched pid */
+ if (ctx->pid != old_pid) {
+ if (mm)
+ pr_devel("%s:pe=%i switch pid %i->%i\n",
+ __func__, ctx->pe, pid_nr(old_pid),
+ pid_nr(ctx->pid));
+ else
+ pr_devel("%s:Cannot find mm for pid=%i\n",
+ __func__, pid_nr(old_pid));
+
+ /* drop the reference to older pid */
+ put_pid(old_pid);
+ }
+ }
+
+ return mm;
+}
+
+
+
void cxl_handle_fault(struct work_struct *fault_work)
{
struct cxl_context *ctx =
container_of(fault_work, struct cxl_context, fault_work);
u64 dsisr = ctx->dsisr;
u64 dar = ctx->dar;
- struct task_struct *task = NULL;
struct mm_struct *mm = NULL;
if (cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An) != dsisr ||
@@ -195,17 +274,17 @@ void cxl_handle_fault(struct work_struct *fault_work)
"DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar);
if (!ctx->kernel) {
- if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
- pr_devel("cxl_handle_fault unable to get task %i\n",
- pid_nr(ctx->pid));
+
+ mm = get_mem_context(ctx);
+ /* indicates all the thread in task group have exited */
+ if (mm == NULL) {
+ pr_devel("%s: unable to get mm for pe=%d pid=%i\n",
+ __func__, ctx->pe, pid_nr(ctx->pid));
cxl_ack_ae(ctx);
return;
- }
- if (!(mm = get_task_mm(task))) {
- pr_devel("cxl_handle_fault unable to get mm %i\n",
- pid_nr(ctx->pid));
- cxl_ack_ae(ctx);
- goto out;
+ } else {
+ pr_devel("Handling page fault for pe=%d pid=%i\n",
+ ctx->pe, pid_nr(ctx->pid));
}
}
@@ -218,33 +297,22 @@ void cxl_handle_fault(struct work_struct *fault_work)
if (mm)
mmput(mm);
-out:
- if (task)
- put_task_struct(task);
}
static void cxl_prefault_one(struct cxl_context *ctx, u64 ea)
{
- int rc;
- struct task_struct *task;
struct mm_struct *mm;
- if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
- pr_devel("cxl_prefault_one unable to get task %i\n",
- pid_nr(ctx->pid));
- return;
- }
- if (!(mm = get_task_mm(task))) {
+ mm = get_mem_context(ctx);
+ if (mm == NULL) {
pr_devel("cxl_prefault_one unable to get mm %i\n",
pid_nr(ctx->pid));
- put_task_struct(task);
return;
}
- rc = cxl_fault_segment(ctx, mm, ea);
+ cxl_fault_segment(ctx, mm, ea);
mmput(mm);
- put_task_struct(task);
}
static u64 next_segment(u64 ea, u64 vsid)
@@ -263,18 +331,13 @@ static void cxl_prefault_vma(struct cxl_context *ctx)
struct copro_slb slb;
struct vm_area_struct *vma;
int rc;
- struct task_struct *task;
struct mm_struct *mm;
- if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
- pr_devel("cxl_prefault_vma unable to get task %i\n",
- pid_nr(ctx->pid));
- return;
- }
- if (!(mm = get_task_mm(task))) {
+ mm = get_mem_context(ctx);
+ if (mm == NULL) {
pr_devel("cxl_prefault_vm unable to get mm %i\n",
pid_nr(ctx->pid));
- goto out1;
+ return;
}
down_read(&mm->mmap_sem);
@@ -295,8 +358,6 @@ static void cxl_prefault_vma(struct cxl_context *ctx)
up_read(&mm->mmap_sem);
mmput(mm);
-out1:
- put_task_struct(task);
}
void cxl_prefault(struct cxl_context *ctx, u64 wed)
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index 7ccd2998be92..783337d22f36 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -67,7 +67,13 @@ static int __afu_open(struct inode *inode, struct file *file, bool master)
spin_unlock(&adapter->afu_list_lock);
goto err_put_adapter;
}
- get_device(&afu->dev);
+
+ /*
+ * taking a ref to the afu so that it doesn't go away
+ * for rest of the function. This ref is released before
+ * we return.
+ */
+ cxl_afu_get(afu);
spin_unlock(&adapter->afu_list_lock);
if (!afu->current_mode)
@@ -90,13 +96,12 @@ static int __afu_open(struct inode *inode, struct file *file, bool master)
file->private_data = ctx;
cxl_ctx_get();
- /* Our ref on the AFU will now hold the adapter */
- put_device(&adapter->dev);
-
- return 0;
+ /* indicate success */
+ rc = 0;
err_put_afu:
- put_device(&afu->dev);
+ /* release the ref taken earlier */
+ cxl_afu_put(afu);
err_put_adapter:
put_device(&adapter->dev);
return rc;
@@ -131,8 +136,6 @@ int afu_release(struct inode *inode, struct file *file)
mutex_unlock(&ctx->mapping_lock);
}
- put_device(&ctx->afu->dev);
-
/*
* At this this point all bottom halfs have finished and we should be
* getting no more IRQs from the hardware for this context. Once it's
@@ -198,8 +201,12 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
* where a process (master, some daemon, etc) has opened the chardev on
* behalf of another process, so the AFU's mm gets bound to the process
* that performs this ioctl and not the process that opened the file.
+ * Also we grab the PID of the group leader so that if the task that
+ * has performed the attach operation exits the mm context of the
+ * process is still accessible.
*/
- ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
+ ctx->pid = get_task_pid(current, PIDTYPE_PID);
+ ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID);
trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 85761d7eb333..4c1903f781fc 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -138,6 +138,7 @@ static const struct pci_device_id cxl_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x04cf), },
+ { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0601), },
{ PCI_DEVICE_CLASS(0x120000, ~0), },
{ }
diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c
index c241e15cacb1..cbd4331fb45c 100644
--- a/drivers/misc/cxl/vphb.c
+++ b/drivers/misc/cxl/vphb.c
@@ -203,7 +203,7 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
mask <<= shift;
val <<= shift;
- v = (in_le32(ioaddr) & ~mask) || (val & mask);
+ v = (in_le32(ioaddr) & ~mask) | (val & mask);
out_le32(ioaddr, v);
return PCIBIOS_SUCCESSFUL;
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index 9b083448814d..5bd127727d8e 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -211,7 +211,7 @@ void ibmasmfs_unregister(void);
void ibmasmfs_add_sp(struct service_processor *sp);
/* uart */
-#ifdef CONFIG_SERIAL_8250
+#if IS_ENABLED(CONFIG_SERIAL_8250)
void ibmasm_register_uart(struct service_processor *sp);
void ibmasm_unregister_uart(struct service_processor *sp);
#else
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index b2f2486b3d75..677d0362f334 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -657,7 +657,9 @@ out:
* @file: pointer to file structure
* @band: band bitmap
*
- * Return: poll mask
+ * Return: negative on error,
+ * 0 if it did no changes,
+ * and positive a process was added or deleted
*/
static int mei_fasync(int fd, struct file *file, int band)
{
@@ -665,7 +667,7 @@ static int mei_fasync(int fd, struct file *file, int band)
struct mei_cl *cl = file->private_data;
if (!mei_cl_is_connected(cl))
- return POLLERR;
+ return -ENODEV;
return fasync_helper(fd, file, band, &cl->ev_async);
}
diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c
index e486a0c26267..f6ed57d3125c 100644
--- a/drivers/misc/mic/card/mic_virtio.c
+++ b/drivers/misc/mic/card/mic_virtio.c
@@ -311,7 +311,7 @@ unmap:
static int mic_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
struct mic_vdev *mvdev = to_micvdev(vdev);
struct mic_device_ctrl __iomem *dc = mvdev->dc;
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index a36ebdae2388..851ccd9ac868 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/types.h>
-#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
@@ -2439,6 +2438,23 @@ static int atmci_configure_dma(struct atmel_mci *host)
{
host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev,
"rxtx");
+
+ if (PTR_ERR(host->dma.chan) == -ENODEV) {
+ struct mci_platform_data *pdata = host->pdev->dev.platform_data;
+ dma_cap_mask_t mask;
+
+ if (!pdata->dma_filter)
+ return -ENODEV;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->dma.chan = dma_request_channel(mask, pdata->dma_filter,
+ pdata->dma_slave);
+ if (!host->dma.chan)
+ host->dma.chan = ERR_PTR(-ENODEV);
+ }
+
if (IS_ERR(host->dma.chan))
return PTR_ERR(host->dma.chan);
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index a03ad2951c7b..42cc953309f1 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -112,7 +112,7 @@ config MTD_CMDLINE_PARTS
config MTD_AFS_PARTS
tristate "ARM Firmware Suite partition parsing"
- depends on ARM
+ depends on (ARM || ARM64)
---help---
The ARM Firmware Suite allows the user to divide flash devices into
multiple 'images'. Each such image has a header containing its name
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c
index 96a33e3f7b00..d61b7edfc938 100644
--- a/drivers/mtd/afs.c
+++ b/drivers/mtd/afs.c
@@ -34,7 +34,9 @@
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-struct footer_struct {
+#define AFSV1_FOOTER_MAGIC 0xA0FFFF9F
+
+struct footer_v1 {
u32 image_info_base; /* Address of first word of ImageFooter */
u32 image_start; /* Start of area reserved by this footer */
u32 signature; /* 'Magic' number proves it's a footer */
@@ -42,7 +44,7 @@ struct footer_struct {
u32 checksum; /* Just this structure */
};
-struct image_info_struct {
+struct image_info_v1 {
u32 bootFlags; /* Boot flags, compression etc. */
u32 imageNumber; /* Unique number, selects for boot etc. */
u32 loadAddress; /* Address program should be loaded to */
@@ -67,10 +69,10 @@ static u32 word_sum(void *words, int num)
}
static int
-afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
- u_int off, u_int mask)
+afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
+ u_int off, u_int mask)
{
- struct footer_struct fs;
+ struct footer_v1 fs;
u_int ptr = off + mtd->erasesize - sizeof(fs);
size_t sz;
int ret;
@@ -85,25 +87,23 @@ afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
return ret;
}
- ret = 1;
-
/*
* Does it contain the magic number?
*/
- if (fs.signature != 0xa0ffff9f)
- ret = 0;
+ if (fs.signature != AFSV1_FOOTER_MAGIC)
+ return 0;
/*
* Check the checksum.
*/
if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
- ret = 0;
+ return 0;
/*
* Don't touch the SIB.
*/
if (fs.type == 2)
- ret = 0;
+ return 0;
*iis_start = fs.image_info_base & mask;
*img_start = fs.image_start & mask;
@@ -113,20 +113,20 @@ afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
* be located after the footer structure.
*/
if (*iis_start >= ptr)
- ret = 0;
+ return 0;
/*
* Check the start of this image. The image
* data can not be located after this block.
*/
if (*img_start > off)
- ret = 0;
+ return 0;
- return ret;
+ return 1;
}
static int
-afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
+afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr)
{
size_t sz;
int ret, i;
@@ -162,7 +162,7 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
}
static int parse_afs_partitions(struct mtd_info *mtd,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct mtd_partition *parts;
@@ -182,24 +182,23 @@ static int parse_afs_partitions(struct mtd_info *mtd,
* the strings.
*/
for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
- struct image_info_struct iis;
+ struct image_info_v1 iis;
u_int iis_ptr, img_ptr;
- ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
- if (ret < 0)
- break;
- if (ret == 0)
- continue;
-
- ret = afs_read_iis(mtd, &iis, iis_ptr);
+ ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask);
if (ret < 0)
break;
- if (ret == 0)
- continue;
-
- sz += sizeof(struct mtd_partition);
- sz += strlen(iis.name) + 1;
- idx += 1;
+ if (ret) {
+ ret = afs_read_iis_v1(mtd, &iis, iis_ptr);
+ if (ret < 0)
+ break;
+ if (ret == 0)
+ continue;
+
+ sz += sizeof(struct mtd_partition);
+ sz += strlen(iis.name) + 1;
+ idx += 1;
+ }
}
if (!sz)
@@ -215,18 +214,18 @@ static int parse_afs_partitions(struct mtd_info *mtd,
* Identify the partitions
*/
for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
- struct image_info_struct iis;
+ struct image_info_v1 iis;
u_int iis_ptr, img_ptr;
/* Read the footer. */
- ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
+ ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask);
if (ret < 0)
break;
if (ret == 0)
continue;
/* Read the image info block */
- ret = afs_read_iis(mtd, &iis, iis_ptr);
+ ret = afs_read_iis_v1(mtd, &iis, iis_ptr);
if (ret < 0)
break;
if (ret == 0)
@@ -257,25 +256,10 @@ static int parse_afs_partitions(struct mtd_info *mtd,
}
static struct mtd_part_parser afs_parser = {
- .owner = THIS_MODULE,
.parse_fn = parse_afs_partitions,
.name = "afs",
};
-
-static int __init afs_parser_init(void)
-{
- register_mtd_parser(&afs_parser);
- return 0;
-}
-
-static void __exit afs_parser_exit(void)
-{
- deregister_mtd_parser(&afs_parser);
-}
-
-module_init(afs_parser_init);
-module_exit(afs_parser_exit);
-
+module_mtd_part_parser(afs_parser);
MODULE_AUTHOR("ARM Ltd");
MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c
index 7c9172ad2621..90575deff0ae 100644
--- a/drivers/mtd/ar7part.c
+++ b/drivers/mtd/ar7part.c
@@ -43,7 +43,7 @@ struct ar7_bin_rec {
};
static int create_mtd_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct ar7_bin_rec header;
@@ -132,24 +132,10 @@ static int create_mtd_partitions(struct mtd_info *master,
}
static struct mtd_part_parser ar7_parser = {
- .owner = THIS_MODULE,
.parse_fn = create_mtd_partitions,
.name = "ar7part",
};
-
-static int __init ar7_parser_init(void)
-{
- register_mtd_parser(&ar7_parser);
- return 0;
-}
-
-static void __exit ar7_parser_exit(void)
-{
- deregister_mtd_parser(&ar7_parser);
-}
-
-module_init(ar7_parser_init);
-module_exit(ar7_parser_exit);
+module_mtd_part_parser(ar7_parser);
MODULE_LICENSE("GPL");
MODULE_AUTHOR( "Felix Fietkau <nbd@openwrt.org>, "
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c
index c0720c1ee4c9..8282f47bcf5d 100644
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -82,7 +82,7 @@ out_default:
}
static int bcm47xxpart_parse(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct mtd_partition *parts;
@@ -313,24 +313,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
};
static struct mtd_part_parser bcm47xxpart_mtd_parser = {
- .owner = THIS_MODULE,
.parse_fn = bcm47xxpart_parse,
.name = "bcm47xxpart",
};
-
-static int __init bcm47xxpart_init(void)
-{
- register_mtd_parser(&bcm47xxpart_mtd_parser);
- return 0;
-}
-
-static void __exit bcm47xxpart_exit(void)
-{
- deregister_mtd_parser(&bcm47xxpart_mtd_parser);
-}
-
-module_init(bcm47xxpart_init);
-module_exit(bcm47xxpart_exit);
+module_mtd_part_parser(bcm47xxpart_mtd_parser);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MTD partitioning for BCM47XX flash memories");
diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c
index b2443f7031c9..440936998593 100644
--- a/drivers/mtd/bcm63xxpart.c
+++ b/drivers/mtd/bcm63xxpart.c
@@ -68,7 +68,7 @@ static int bcm63xx_detect_cfe(struct mtd_info *master)
}
static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
/* CFE, NVRAM and global Linux are always present */
@@ -214,24 +214,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
};
static struct mtd_part_parser bcm63xx_cfe_parser = {
- .owner = THIS_MODULE,
.parse_fn = bcm63xx_parse_cfe_partitions,
.name = "bcm63xxpart",
};
-
-static int __init bcm63xx_cfe_parser_init(void)
-{
- register_mtd_parser(&bcm63xx_cfe_parser);
- return 0;
-}
-
-static void __exit bcm63xx_cfe_parser_exit(void)
-{
- deregister_mtd_parser(&bcm63xx_cfe_parser);
-}
-
-module_init(bcm63xx_cfe_parser_init);
-module_exit(bcm63xx_cfe_parser_exit);
+module_mtd_part_parser(bcm63xx_cfe_parser);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 54479c481a7a..3b3dabce58de 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -67,6 +67,10 @@ endchoice
config MTD_CFI_GEOMETRY
bool "Specific CFI Flash geometry selection"
depends on MTD_CFI_ADV_OPTIONS
+ select MTD_MAP_BANK_WIDTH_1 if !(MTD_MAP_BANK_WIDTH_2 || \
+ MTD_MAP_BANK_WIDTH_4 || MTD_MAP_BANK_WIDTH_8 || \
+ MTD_MAP_BANK_WIDTH_16 || MTD_MAP_BANK_WIDTH_32)
+ select MTD_CFI_I1 if !(MTD_CFI_I2 || MTD_CFI_I4 || MTD_CFI_I8)
help
This option does not affect the code directly, but will enable
some other configuration options which would allow you to reduce
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 286b97a304cf..5e1b68cbcd0a 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -596,7 +596,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
mtd->size = devsize * cfi->numchips;
mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
- mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
+ mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info)
* mtd->numeraseregions, GFP_KERNEL);
if (!mtd->eraseregions)
goto setup_err;
@@ -614,6 +614,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
+ if (!mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap)
+ goto setup_err;
}
offset += (ersize * ernum);
}
@@ -650,6 +652,10 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
return mtd;
setup_err:
+ if (mtd->eraseregions)
+ for (i=0; i<cfi->cfiq->NumEraseRegions; i++)
+ for (j=0; j<cfi->numchips; j++)
+ kfree(mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap);
kfree(mtd->eraseregions);
kfree(mtd);
kfree(cfi->cmdset_priv);
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index c3624eb571d1..9dca881bb378 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -615,11 +615,9 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
int j = (cfi->cfiq->NumEraseRegions-1)-i;
- __u32 swap;
- swap = cfi->cfiq->EraseRegionInfo[i];
- cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
- cfi->cfiq->EraseRegionInfo[j] = swap;
+ swap(cfi->cfiq->EraseRegionInfo[i],
+ cfi->cfiq->EraseRegionInfo[j]);
}
}
/* Set the default CFI lock/unlock addresses */
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 08f62987cc37..fbd5affc0acf 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -304,7 +304,7 @@ static int mtdpart_setup_real(char *s)
* the first one in the chain if a NULL mtd_id is passed in.
*/
static int parse_cmdline_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
unsigned long long offset;
@@ -382,7 +382,6 @@ static int __init mtdpart_setup(char *s)
__setup("mtdparts=", mtdpart_setup);
static struct mtd_part_parser cmdline_parser = {
- .owner = THIS_MODULE,
.parse_fn = parse_cmdline_partitions,
.name = "cmdlinepart",
};
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index fe9ceb7b5405..c9c3b7fa3051 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -152,22 +152,6 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
return 0;
}
-static int m25p80_erase(struct spi_nor *nor, loff_t offset)
-{
- struct m25p *flash = nor->priv;
-
- dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
- flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
-
- /* Set up command buffer. */
- flash->command[0] = nor->erase_opcode;
- m25p_addr2cmd(nor, offset, flash->command);
-
- spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
-
- return 0;
-}
-
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -175,12 +159,11 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)
*/
static int m25p_probe(struct spi_device *spi)
{
- struct mtd_part_parser_data ppdata;
struct flash_platform_data *data;
struct m25p *flash;
struct spi_nor *nor;
enum read_mode mode = SPI_NOR_NORMAL;
- char *flash_name = NULL;
+ char *flash_name;
int ret;
data = dev_get_platdata(&spi->dev);
@@ -194,12 +177,11 @@ static int m25p_probe(struct spi_device *spi)
/* install the hooks */
nor->read = m25p80_read;
nor->write = m25p80_write;
- nor->erase = m25p80_erase;
nor->write_reg = m25p80_write_reg;
nor->read_reg = m25p80_read_reg;
nor->dev = &spi->dev;
- nor->flash_node = spi->dev.of_node;
+ spi_nor_set_flash_node(nor, spi->dev.of_node);
nor->priv = flash;
spi_set_drvdata(spi, flash);
@@ -220,6 +202,8 @@ static int m25p_probe(struct spi_device *spi)
*/
if (data && data->type)
flash_name = data->type;
+ else if (!strcmp(spi->modalias, "spi-nor"))
+ flash_name = NULL; /* auto-detect */
else
flash_name = spi->modalias;
@@ -227,11 +211,8 @@ static int m25p_probe(struct spi_device *spi)
if (ret)
return ret;
- ppdata.of_node = spi->dev.of_node;
-
- return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
- data ? data->parts : NULL,
- data ? data->nr_parts : 0);
+ return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
+ data ? data->nr_parts : 0);
}
@@ -257,14 +238,21 @@ static int m25p_remove(struct spi_device *spi)
*/
static const struct spi_device_id m25p_ids[] = {
/*
+ * Allow non-DT platform devices to bind to the "spi-nor" modalias, and
+ * hack around the fact that the SPI core does not provide uevent
+ * matching for .of_match_table
+ */
+ {"spi-nor"},
+
+ /*
* Entries not used in DTs that should be safe to drop after replacing
- * them with "nor-jedec" in platform data.
+ * them with "spi-nor" in platform data.
*/
{"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
/*
- * Entries that were used in DTs without "nor-jedec" fallback and should
- * be kept for backward compatibility.
+ * Entries that were used in DTs without "jedec,spi-nor" fallback and
+ * should be kept for backward compatibility.
*/
{"at25df321a"}, {"at25df641"}, {"at26df081a"},
{"mr25h256"},
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index e4a88715a844..f9e9bd1cfaa0 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -624,7 +624,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
{
struct dataflash *priv;
struct mtd_info *device;
- struct mtd_part_parser_data ppdata;
struct flash_platform_data *pdata = dev_get_platdata(&spi->dev);
char *otp_tag = "";
int err = 0;
@@ -656,6 +655,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
device->priv = priv;
device->dev.parent = &spi->dev;
+ mtd_set_of_node(device, spi->dev.of_node);
if (revision >= 'c')
otp_tag = otp_setup(device, revision);
@@ -665,8 +665,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
pagesize, otp_tag);
spi_set_drvdata(spi, priv);
- ppdata.of_node = spi->dev.of_node;
- err = mtd_device_parse_register(device, NULL, &ppdata,
+ err = mtd_device_register(device,
pdata ? pdata->parts : NULL,
pdata ? pdata->nr_parts : 0);
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
index 64c7458344d4..dd5069876537 100644
--- a/drivers/mtd/devices/spear_smi.c
+++ b/drivers/mtd/devices/spear_smi.c
@@ -810,7 +810,6 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
u32 bank, struct device_node *np)
{
struct spear_smi *dev = platform_get_drvdata(pdev);
- struct mtd_part_parser_data ppdata = {};
struct spear_smi_flash_info *flash_info;
struct spear_smi_plat_data *pdata;
struct spear_snor_flash *flash;
@@ -855,6 +854,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
flash->mtd.name = flash_devices[flash_index].name;
flash->mtd.dev.parent = &pdev->dev;
+ mtd_set_of_node(&flash->mtd, np);
flash->mtd.type = MTD_NORFLASH;
flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
@@ -881,10 +881,8 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
count = flash_info->nr_partitions;
}
#endif
- ppdata.of_node = np;
- ret = mtd_device_parse_register(&flash->mtd, NULL, &ppdata, parts,
- count);
+ ret = mtd_device_register(&flash->mtd, parts, count);
if (ret) {
dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret);
return ret;
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
index 3060025c8af4..5454b4113589 100644
--- a/drivers/mtd/devices/st_spi_fsm.c
+++ b/drivers/mtd/devices/st_spi_fsm.c
@@ -2025,7 +2025,6 @@ boot_device_fail:
static int stfsm_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct mtd_part_parser_data ppdata;
struct flash_info *info;
struct resource *res;
struct stfsm *fsm;
@@ -2035,7 +2034,6 @@ static int stfsm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "No DT found\n");
return -EINVAL;
}
- ppdata.of_node = np;
fsm = devm_kzalloc(&pdev->dev, sizeof(*fsm), GFP_KERNEL);
if (!fsm)
@@ -2106,6 +2104,7 @@ static int stfsm_probe(struct platform_device *pdev)
fsm->mtd.name = info->name;
fsm->mtd.dev.parent = &pdev->dev;
+ mtd_set_of_node(&fsm->mtd, np);
fsm->mtd.type = MTD_NORFLASH;
fsm->mtd.writesize = 4;
fsm->mtd.writebufsize = fsm->mtd.writesize;
@@ -2124,7 +2123,7 @@ static int stfsm_probe(struct platform_device *pdev)
(long long)fsm->mtd.size, (long long)(fsm->mtd.size >> 20),
fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10));
- return mtd_device_parse_register(&fsm->mtd, NULL, &ppdata, NULL, 0);
+ return mtd_device_register(&fsm->mtd, NULL, 0);
}
static int stfsm_remove(struct platform_device *pdev)
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index dabf08450d0b..9fb3b0dcdac2 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -571,12 +571,8 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit,
/* Update the maps and usage stats*/
- i = xfer->EraseCount;
- xfer->EraseCount = eun->EraseCount;
- eun->EraseCount = i;
- i = xfer->Offset;
- xfer->Offset = eun->Offset;
- eun->Offset = i;
+ swap(xfer->EraseCount, eun->EraseCount);
+ swap(xfer->Offset, eun->Offset);
part->FreeTotal -= eun->Free;
part->FreeTotal += free;
eun->Free = free;
diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c
index 93852054977e..c8febb326fa6 100644
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -110,7 +110,6 @@ ltq_copy_to(struct map_info *map, unsigned long to,
static int
ltq_mtd_probe(struct platform_device *pdev)
{
- struct mtd_part_parser_data ppdata;
struct ltq_mtd *ltq_mtd;
struct cfi_private *cfi;
int err;
@@ -161,13 +160,13 @@ ltq_mtd_probe(struct platform_device *pdev)
}
ltq_mtd->mtd->dev.parent = &pdev->dev;
+ mtd_set_of_node(ltq_mtd->mtd, pdev->dev.of_node);
cfi = ltq_mtd->map->fldrv_priv;
cfi->addr_unlock1 ^= 1;
cfi->addr_unlock2 ^= 1;
- ppdata.of_node = pdev->dev.of_node;
- err = mtd_device_parse_register(ltq_mtd->mtd, NULL, &ppdata, NULL, 0);
+ err = mtd_device_register(ltq_mtd->mtd, NULL, 0);
if (err) {
dev_err(&pdev->dev, "failed to add partitions\n");
goto err_destroy;
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index e46b4e983666..70c453144f00 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -166,7 +166,6 @@ static int of_flash_probe(struct platform_device *dev)
int reg_tuple_size;
struct mtd_info **mtd_list = NULL;
resource_size_t res_size;
- struct mtd_part_parser_data ppdata;
bool map_indirect;
const char *mtd_name = NULL;
@@ -310,13 +309,14 @@ static int of_flash_probe(struct platform_device *dev)
if (err)
goto err_out;
- ppdata.of_node = dp;
+ 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, &ppdata,
+ mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
NULL, 0);
of_free_probes(part_probe_types);
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index ffa288474820..309625130b21 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -32,6 +32,7 @@
#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
+#include <linux/of.h>
#include <linux/proc_fs.h>
#include <linux/idr.h>
#include <linux/backing-dev.h>
@@ -445,6 +446,7 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->dev.devt = MTD_DEVT(i);
dev_set_name(&mtd->dev, "mtd%d", i);
dev_set_drvdata(&mtd->dev, mtd);
+ of_node_get(mtd_get_of_node(mtd));
error = device_register(&mtd->dev);
if (error)
goto fail_added;
@@ -467,6 +469,7 @@ int add_mtd_device(struct mtd_info *mtd)
return 0;
fail_added:
+ of_node_put(mtd_get_of_node(mtd));
idr_remove(&mtd_idr, i);
fail_locked:
mutex_unlock(&mtd_table_mutex);
@@ -508,6 +511,7 @@ int del_mtd_device(struct mtd_info *mtd)
device_unregister(&mtd->dev);
idr_remove(&mtd_idr, mtd->index);
+ of_node_put(mtd_get_of_node(mtd));
module_put(THIS_MODULE);
ret = 0;
@@ -519,9 +523,10 @@ out_error:
}
static int mtd_add_device_partitions(struct mtd_info *mtd,
- struct mtd_partition *real_parts,
- int nbparts)
+ struct mtd_partitions *parts)
{
+ const struct mtd_partition *real_parts = parts->parts;
+ int nbparts = parts->nr_parts;
int ret;
if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
@@ -590,29 +595,29 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
const struct mtd_partition *parts,
int nr_parts)
{
+ struct mtd_partitions parsed;
int ret;
- struct mtd_partition *real_parts = NULL;
mtd_set_dev_defaults(mtd);
- ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
- if (ret <= 0 && nr_parts && parts) {
- real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
- GFP_KERNEL);
- if (!real_parts)
- ret = -ENOMEM;
- else
- ret = nr_parts;
- }
- /* Didn't come up with either parsed OR fallback partitions */
- if (ret < 0) {
+ memset(&parsed, 0, sizeof(parsed));
+
+ ret = parse_mtd_partitions(mtd, types, &parsed, parser_data);
+ if ((ret < 0 || parsed.nr_parts == 0) && parts && nr_parts) {
+ /* Fall back to driver-provided partitions */
+ parsed = (struct mtd_partitions){
+ .parts = parts,
+ .nr_parts = nr_parts,
+ };
+ } else if (ret < 0) {
+ /* Didn't come up with parsed OR fallback partitions */
pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
ret);
/* Don't abort on errors; we can still use unpartitioned MTD */
- ret = 0;
+ memset(&parsed, 0, sizeof(parsed));
}
- ret = mtd_add_device_partitions(mtd, real_parts, ret);
+ ret = mtd_add_device_partitions(mtd, &parsed);
if (ret)
goto out;
@@ -632,7 +637,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
}
out:
- kfree(real_parts);
+ /* Cleanup any parsed partitions */
+ mtd_part_parser_cleanup(&parsed);
return ret;
}
EXPORT_SYMBOL_GPL(mtd_device_parse_register);
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
index 7b0353399a10..55fdb8e1fd2a 100644
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -10,10 +10,15 @@ int add_mtd_device(struct mtd_info *mtd);
int del_mtd_device(struct mtd_info *mtd);
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
+
+struct mtd_partitions;
+
int parse_mtd_partitions(struct mtd_info *master, const char * const *types,
- struct mtd_partition **pparts,
+ struct mtd_partitions *pparts,
struct mtd_part_parser_data *data);
+void mtd_part_parser_cleanup(struct mtd_partitions *parts);
+
int __init init_mtdchar(void);
void __exit cleanup_mtdchar(void);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index f8ba153f63bf..10bf304027dd 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -48,9 +48,12 @@ struct mtd_part {
/*
* Given a pointer to the MTD object in the mtd_part structure, we can retrieve
- * the pointer to that structure with this macro.
+ * the pointer to that structure.
*/
-#define PART(x) ((struct mtd_part *)(x))
+static inline struct mtd_part *mtd_to_part(const struct mtd_info *mtd)
+{
+ return container_of(mtd, struct mtd_part, mtd);
+}
/*
@@ -61,7 +64,7 @@ struct mtd_part {
static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
struct mtd_ecc_stats stats;
int res;
@@ -80,7 +83,7 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_point(part->master, from + part->offset, len,
retlen, virt, phys);
@@ -88,7 +91,7 @@ static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_unpoint(part->master, from + part->offset, len);
}
@@ -98,7 +101,7 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
unsigned long offset,
unsigned long flags)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
offset += part->offset;
return part->master->_get_unmapped_area(part->master, len, offset,
@@ -108,7 +111,7 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
static int part_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
int res;
if (from >= mtd->size)
@@ -146,7 +149,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_read_user_prot_reg(part->master, from, len,
retlen, buf);
}
@@ -154,7 +157,7 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
size_t *retlen, struct otp_info *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_get_user_prot_info(part->master, len, retlen,
buf);
}
@@ -162,7 +165,7 @@ static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_read_fact_prot_reg(part->master, from, len,
retlen, buf);
}
@@ -170,7 +173,7 @@ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
size_t *retlen, struct otp_info *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_get_fact_prot_info(part->master, len, retlen,
buf);
}
@@ -178,7 +181,7 @@ static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_write(part->master, to + part->offset, len,
retlen, buf);
}
@@ -186,7 +189,7 @@ static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_panic_write(part->master, to + part->offset, len,
retlen, buf);
}
@@ -194,7 +197,7 @@ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
static int part_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
if (to >= mtd->size)
return -EINVAL;
@@ -206,7 +209,7 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char *buf)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_write_user_prot_reg(part->master, from, len,
retlen, buf);
}
@@ -214,21 +217,21 @@ static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
size_t len)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_lock_user_prot_reg(part->master, from, len);
}
static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_writev(part->master, vecs, count,
to + part->offset, retlen);
}
static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
int ret;
instr->addr += part->offset;
@@ -244,7 +247,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
void mtd_erase_callback(struct erase_info *instr)
{
if (instr->mtd->_erase == part_erase) {
- struct mtd_part *part = PART(instr->mtd);
+ struct mtd_part *part = mtd_to_part(instr->mtd);
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
@@ -257,57 +260,57 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_lock(part->master, ofs + part->offset, len);
}
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_unlock(part->master, ofs + part->offset, len);
}
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_is_locked(part->master, ofs + part->offset, len);
}
static void part_sync(struct mtd_info *mtd)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
part->master->_sync(part->master);
}
static int part_suspend(struct mtd_info *mtd)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return part->master->_suspend(part->master);
}
static void part_resume(struct mtd_info *mtd)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
part->master->_resume(part->master);
}
static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
ofs += part->offset;
return part->master->_block_isreserved(part->master, ofs);
}
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
ofs += part->offset;
return part->master->_block_isbad(part->master, ofs);
}
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
int res;
ofs += part->offset;
@@ -558,7 +561,7 @@ static ssize_t mtd_partition_offset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- struct mtd_part *part = PART(mtd);
+ struct mtd_part *part = mtd_to_part(mtd);
return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset);
}
@@ -596,11 +599,10 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
if (length <= 0)
return -EINVAL;
+ memset(&part, 0, sizeof(part));
part.name = name;
part.size = length;
part.offset = offset;
- part.mask_flags = 0;
- part.ecclayout = NULL;
new = allocate_partition(master, &part, -1, offset);
if (IS_ERR(new))
@@ -685,7 +687,7 @@ int add_mtd_partitions(struct mtd_info *master,
static DEFINE_SPINLOCK(part_parser_lock);
static LIST_HEAD(part_parsers);
-static struct mtd_part_parser *get_partition_parser(const char *name)
+static struct mtd_part_parser *mtd_part_parser_get(const char *name)
{
struct mtd_part_parser *p, *ret = NULL;
@@ -702,15 +704,35 @@ static struct mtd_part_parser *get_partition_parser(const char *name)
return ret;
}
-#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
+static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
+{
+ module_put(p->owner);
+}
+
+/*
+ * Many partition parsers just expected the core to kfree() all their data in
+ * one chunk. Do that by default.
+ */
+static void mtd_part_parser_cleanup_default(const struct mtd_partition *pparts,
+ int nr_parts)
+{
+ kfree(pparts);
+}
-void register_mtd_parser(struct mtd_part_parser *p)
+int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner)
{
+ p->owner = owner;
+
+ if (!p->cleanup)
+ p->cleanup = &mtd_part_parser_cleanup_default;
+
spin_lock(&part_parser_lock);
list_add(&p->list, &part_parsers);
spin_unlock(&part_parser_lock);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(register_mtd_parser);
+EXPORT_SYMBOL_GPL(__register_mtd_parser);
void deregister_mtd_parser(struct mtd_part_parser *p)
{
@@ -734,7 +756,7 @@ static const char * const default_mtd_part_types[] = {
* parse_mtd_partitions - parse MTD partitions
* @master: the master partition (describes whole MTD device)
* @types: names of partition parsers to try or %NULL
- * @pparts: array of partitions found is returned here
+ * @pparts: info about partitions found is returned here
* @data: MTD partition parser-specific data
*
* This function tries to find partition on MTD device @master. It uses MTD
@@ -746,12 +768,13 @@ static const char * const default_mtd_part_types[] = {
*
* This function may return:
* o a negative error code in case of failure
- * o zero if no partitions were found
- * o a positive number of found partitions, in which case on exit @pparts will
- * point to an array containing this number of &struct mtd_info objects.
+ * o zero otherwise, and @pparts will describe the partitions, number of
+ * partitions, and the parser which parsed them. Caller must release
+ * resources with mtd_part_parser_cleanup() when finished with the returned
+ * data.
*/
int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
- struct mtd_partition **pparts,
+ struct mtd_partitions *pparts,
struct mtd_part_parser_data *data)
{
struct mtd_part_parser *parser;
@@ -762,22 +785,24 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
for ( ; *types; types++) {
pr_debug("%s: parsing partitions %s\n", master->name, *types);
- parser = get_partition_parser(*types);
+ parser = mtd_part_parser_get(*types);
if (!parser && !request_module("%s", *types))
- parser = get_partition_parser(*types);
+ parser = mtd_part_parser_get(*types);
pr_debug("%s: got parser %s\n", master->name,
parser ? parser->name : NULL);
if (!parser)
continue;
- ret = (*parser->parse_fn)(master, pparts, data);
+ ret = (*parser->parse_fn)(master, &pparts->parts, data);
pr_debug("%s: parser %s: %i\n",
master->name, parser->name, ret);
- put_partition_parser(parser);
if (ret > 0) {
printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
ret, parser->name, master->name);
- return ret;
+ pparts->nr_parts = ret;
+ pparts->parser = parser;
+ return 0;
}
+ mtd_part_parser_put(parser);
/*
* Stash the first error we see; only report it if no parser
* succeeds
@@ -788,6 +813,22 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
return err;
}
+void mtd_part_parser_cleanup(struct mtd_partitions *parts)
+{
+ const struct mtd_part_parser *parser;
+
+ if (!parts)
+ return;
+
+ parser = parts->parser;
+ if (parser) {
+ if (parser->cleanup)
+ parser->cleanup(parts->parts, parts->nr_parts);
+
+ mtd_part_parser_put(parser);
+ }
+}
+
int mtd_is_partition(const struct mtd_info *mtd)
{
struct mtd_part *part;
@@ -811,6 +852,6 @@ uint64_t mtd_get_device_size(const struct mtd_info *mtd)
if (!mtd_is_partition(mtd))
return mtd->size;
- return PART(mtd)->master->size;
+ return mtd_to_part(mtd)->master->size;
}
EXPORT_SYMBOL_GPL(mtd_get_device_size);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 289664089cf3..20f01b3ec23d 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -55,7 +55,7 @@ config MTD_NAND_DENALI_PCI
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
select MTD_NAND_DENALI
- depends on HAS_DMA && HAVE_CLK
+ depends on HAS_DMA && HAVE_CLK && OF
help
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
@@ -480,7 +480,7 @@ config MTD_NAND_MXC
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+ depends on SUPERH || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
help
@@ -519,6 +519,13 @@ config MTD_NAND_JZ4740
help
Enables support for NAND Flash on JZ4740 SoC based boards.
+config MTD_NAND_JZ4780
+ tristate "Support for NAND on JZ4780 SoC"
+ depends on MACH_JZ4780 && JZ4780_NEMC
+ help
+ Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
+ based boards, using the BCH controller for hardware error correction.
+
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 2c7f014b349e..9e3623308509 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
+obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 842f8fe91b56..68b58c85789c 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -64,8 +64,8 @@ static struct mtd_partition partition_info[] = {
static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
{
- struct nand_chip *this = mtd->priv;
- void __iomem *io_base = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
writew(0, io_base + OMAP_MPUIO_IO_CNTL);
writew(byte, this->IO_ADDR_W);
@@ -77,8 +77,8 @@ static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
static u_char ams_delta_read_byte(struct mtd_info *mtd)
{
u_char res;
- struct nand_chip *this = mtd->priv;
- void __iomem *io_base = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
ndelay(40);
@@ -183,22 +183,16 @@ static int ams_delta_init(struct platform_device *pdev)
return -ENXIO;
/* Allocate memory for MTD device structure and private data */
- ams_delta_mtd = kzalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip), GFP_KERNEL);
- if (!ams_delta_mtd) {
+ this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+ if (!this) {
printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
+ ams_delta_mtd = nand_to_mtd(this);
ams_delta_mtd->owner = THIS_MODULE;
- /* Get pointer to private data */
- this = (struct nand_chip *) (&ams_delta_mtd[1]);
-
- /* Link the private data with the MTD structure */
- ams_delta_mtd->priv = this;
-
/*
* Don't try to request the memory region from here,
* it should have been already requested from the
@@ -212,7 +206,7 @@ static int ams_delta_init(struct platform_device *pdev)
goto out_free;
}
- this->priv = io_base;
+ nand_set_controller_data(this, (void *)io_base);
/* Set address of NAND IO lines */
this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
@@ -256,7 +250,7 @@ out_gpio:
gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
iounmap(io_base);
out_free:
- kfree(ams_delta_mtd);
+ kfree(this);
out:
return err;
}
@@ -276,7 +270,7 @@ static int ams_delta_cleanup(struct platform_device *pdev)
iounmap(io_base);
/* Free the MTD device structure */
- kfree(ams_delta_mtd);
+ kfree(mtd_to_nand(ams_delta_mtd));
return 0;
}
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 583cdd9bb971..bddcf83d6859 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -116,7 +116,6 @@ static struct atmel_nfc nand_nfc;
struct atmel_nand_host {
struct nand_chip nand_chip;
- struct mtd_info mtd;
void __iomem *io_base;
dma_addr_t io_phys;
struct atmel_nand_data board;
@@ -128,7 +127,7 @@ struct atmel_nand_host {
struct atmel_nfc *nfc;
- struct atmel_nand_caps *caps;
+ const struct atmel_nand_caps *caps;
bool has_pmecc;
u8 pmecc_corr_cap;
u16 pmecc_sector_size;
@@ -182,8 +181,8 @@ static void atmel_nand_disable(struct atmel_nand_host *host)
*/
static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE)
@@ -205,8 +204,8 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
*/
static int atmel_nand_device_ready(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
return gpio_get_value(host->board.rdy_pin) ^
!!host->board.rdy_pin_active_low;
@@ -215,8 +214,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
/* Set up for hardware ready pin and enable pin. */
static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct atmel_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
int res = 0;
if (gpio_is_valid(host->board.rdy_pin)) {
@@ -267,8 +266,8 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
*/
static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
memcpy(buf, host->nfc->data_in_sram, len);
@@ -280,8 +279,8 @@ static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
memcpy(buf, host->nfc->data_in_sram, len);
@@ -293,14 +292,14 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
{
- struct nand_chip *nand_chip = mtd->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
__raw_writesb(nand_chip->IO_ADDR_W, buf, len);
}
static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
{
- struct nand_chip *nand_chip = mtd->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
__raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
}
@@ -317,8 +316,10 @@ static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
return -EINVAL;
if (bank) {
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+
/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
- if (host->mtd.writesize > 2048)
+ if (mtd->writesize > 2048)
return -EINVAL;
nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
} else {
@@ -352,8 +353,8 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
dma_addr_t dma_src_addr, dma_dst_addr, phys_addr;
struct dma_async_tx_descriptor *tx = NULL;
dma_cookie_t cookie;
- struct nand_chip *chip = mtd->priv;
- struct atmel_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
void *p = buf;
int err = -EIO;
enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
@@ -425,8 +426,8 @@ err_buf:
static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct atmel_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
if (use_dma && len > mtd->oobsize)
/* only use DMA for bigger than oob size: better performances */
@@ -441,8 +442,8 @@ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct atmel_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
if (use_dma && len > mtd->oobsize)
/* only use DMA for bigger than oob size: better performances */
@@ -533,8 +534,8 @@ static int pmecc_data_alloc(struct atmel_nand_host *host)
static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int i;
uint32_t value;
@@ -550,8 +551,8 @@ static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
static void pmecc_substitute(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int16_t __iomem *alpha_to = host->pmecc_alpha_to;
int16_t __iomem *index_of = host->pmecc_index_of;
int16_t *partial_syn = host->pmecc_partial_syn;
@@ -592,8 +593,8 @@ static void pmecc_substitute(struct mtd_info *mtd)
static void pmecc_get_sigma(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int16_t *lmu = host->pmecc_lmu;
int16_t *si = host->pmecc_si;
@@ -750,8 +751,8 @@ static void pmecc_get_sigma(struct mtd_info *mtd)
static int pmecc_err_location(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
unsigned long end_time;
const int cap = host->pmecc_corr_cap;
const int num = 2 * cap + 1;
@@ -802,8 +803,8 @@ static int pmecc_err_location(struct mtd_info *mtd)
static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
int sector_num, int extra_bytes, int err_nbr)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int i = 0;
int byte_pos, bit_pos, sector_size, pos;
uint32_t tmp;
@@ -848,8 +849,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
u8 *ecc)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int i, err_nbr;
uint8_t *buf_pos;
int max_bitflips = 0;
@@ -919,7 +920,7 @@ static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
{
- struct atmel_nand_host *host = chip->priv;
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
int eccsize = chip->ecc.size * chip->ecc.steps;
uint8_t *oob = chip->oob_poi;
uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -957,7 +958,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required,
int page)
{
- struct atmel_nand_host *host = chip->priv;
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
uint32_t *eccpos = chip->ecc.layout->eccpos;
int i, j;
unsigned long end_time;
@@ -992,8 +993,8 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
static void atmel_pmecc_core_init(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
uint32_t val = 0;
struct nand_ecclayout *ecc_layout;
@@ -1159,8 +1160,8 @@ static uint16_t *create_lookup_table(struct device *dev, int sector_size)
static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
struct atmel_nand_host *host)
{
- struct mtd_info *mtd = &host->mtd;
struct nand_chip *nand_chip = &host->nand_chip;
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct resource *regs, *regs_pmerr, *regs_rom;
uint16_t *galois_table;
int cap, sector_size, err_no;
@@ -1308,8 +1309,8 @@ err:
static int atmel_nand_calculate(struct mtd_info *mtd,
const u_char *dat, unsigned char *ecc_code)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
unsigned int ecc_value;
/* get the first 2 ECC bytes */
@@ -1355,7 +1356,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
* Workaround: Reset the parity registers before reading the
* actual data.
*/
- struct atmel_nand_host *host = chip->priv;
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
if (host->board.need_reset_workaround)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
@@ -1412,8 +1413,8 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
unsigned int ecc_status;
unsigned int ecc_word, ecc_bit;
@@ -1444,7 +1445,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
* We can't correct so many errors */
dev_dbg(host->dev, "atmel_nand : multiple errors detected."
" Unable to correct.\n");
- return -EIO;
+ return -EBADMSG;
}
/* if there's a single bit error : we can correct it */
@@ -1478,8 +1479,8 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
*/
static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (host->board.need_reset_workaround)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
@@ -1586,8 +1587,8 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
static int atmel_hw_nand_init_params(struct platform_device *pdev,
struct atmel_nand_host *host)
{
- struct mtd_info *mtd = &host->mtd;
struct nand_chip *nand_chip = &host->nand_chip;
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct resource *regs;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1771,8 +1772,8 @@ static int nfc_send_command(struct atmel_nand_host *host,
static int nfc_device_ready(struct mtd_info *mtd)
{
u32 status, mask;
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
status = nfc_read_status(host);
mask = nfc_readl(host->nfc->hsmc_regs, IMR);
@@ -1787,8 +1788,8 @@ static int nfc_device_ready(struct mtd_info *mtd)
static void nfc_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1)
nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
@@ -1799,7 +1800,7 @@ static void nfc_select_chip(struct mtd_info *mtd, int chip)
static int nfc_make_addr(struct mtd_info *mtd, int command, int column,
int page_addr, unsigned int *addr1234, unsigned int *cycle0)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int acycle = 0;
unsigned char addr_bytes[8];
@@ -1839,8 +1840,8 @@ static int nfc_make_addr(struct mtd_info *mtd, int command, int column,
static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd->priv;
- struct atmel_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
unsigned long timeout;
unsigned int nfc_addr_cmd = 0;
@@ -1966,7 +1967,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
{
int cfg, len;
int status = 0;
- struct atmel_nand_host *host = chip->priv;
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
void *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
/* Subpage write is not supported */
@@ -2026,8 +2027,8 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
static int nfc_sram_init(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct atmel_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct atmel_nand_host *host = nand_get_controller_data(chip);
int res = 0;
/* Initialize the NFC CFG register */
@@ -2093,7 +2094,6 @@ static int atmel_nand_probe(struct platform_device *pdev)
struct mtd_info *mtd;
struct nand_chip *nand_chip;
struct resource *mem;
- struct mtd_part_parser_data ppdata = {};
int res, irq;
/* Allocate memory for the device structure (and zero it) */
@@ -2113,10 +2113,11 @@ static int atmel_nand_probe(struct platform_device *pdev)
}
host->io_phys = (dma_addr_t)mem->start;
- mtd = &host->mtd;
nand_chip = &host->nand_chip;
+ mtd = nand_to_mtd(nand_chip);
host->dev = &pdev->dev;
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+ nand_set_flash_node(nand_chip, pdev->dev.of_node);
/* Only when CONFIG_OF is enabled of_node can be parsed */
res = atmel_of_init_port(host, pdev->dev.of_node);
if (res)
@@ -2126,8 +2127,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
sizeof(struct atmel_nand_data));
}
- nand_chip->priv = host; /* link the private data structures */
- mtd->priv = nand_chip;
+ /* link the private data structures */
+ nand_set_controller_data(nand_chip, host);
mtd->dev.parent = &pdev->dev;
/* Set address of NAND IO lines */
@@ -2259,9 +2260,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
}
mtd->name = "atmel_nand";
- ppdata.of_node = pdev->dev.of_node;
- res = mtd_device_parse_register(mtd, NULL, &ppdata,
- host->board.parts, host->board.num_parts);
+ res = mtd_device_register(mtd, host->board.parts,
+ host->board.num_parts);
if (!res)
return res;
@@ -2284,7 +2284,7 @@ err_nand_ioremap:
static int atmel_nand_remove(struct platform_device *pdev)
{
struct atmel_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
nand_release(mtd);
@@ -2304,11 +2304,11 @@ static int atmel_nand_remove(struct platform_device *pdev)
return 0;
}
-static struct atmel_nand_caps at91rm9200_caps = {
+static const struct atmel_nand_caps at91rm9200_caps = {
.pmecc_correct_erase_page = false,
};
-static struct atmel_nand_caps sama5d4_caps = {
+static const struct atmel_nand_caps sama5d4_caps = {
.pmecc_correct_erase_page = true,
};
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 08a130f63faf..341ea4904164 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -23,7 +23,6 @@
struct au1550nd_ctx {
- struct mtd_info info;
struct nand_chip chip;
int cs;
@@ -39,7 +38,7 @@ struct au1550nd_ctx {
*/
static u_char au_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
u_char ret = readb(this->IO_ADDR_R);
wmb(); /* drain writebuffer */
return ret;
@@ -54,7 +53,7 @@ static u_char au_read_byte(struct mtd_info *mtd)
*/
static void au_write_byte(struct mtd_info *mtd, u_char byte)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
writeb(byte, this->IO_ADDR_W);
wmb(); /* drain writebuffer */
}
@@ -67,7 +66,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte)
*/
static u_char au_read_byte16(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
wmb(); /* drain writebuffer */
return ret;
@@ -82,7 +81,7 @@ static u_char au_read_byte16(struct mtd_info *mtd)
*/
static void au_write_byte16(struct mtd_info *mtd, u_char byte)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
wmb(); /* drain writebuffer */
}
@@ -95,7 +94,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte)
*/
static u16 au_read_word(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
u16 ret = readw(this->IO_ADDR_R);
wmb(); /* drain writebuffer */
return ret;
@@ -112,7 +111,7 @@ static u16 au_read_word(struct mtd_info *mtd)
static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
for (i = 0; i < len; i++) {
writeb(buf[i], this->IO_ADDR_W);
@@ -131,7 +130,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
for (i = 0; i < len; i++) {
buf[i] = readb(this->IO_ADDR_R);
@@ -150,7 +149,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
u16 *p = (u16 *) buf;
len >>= 1;
@@ -172,7 +171,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
u16 *p = (u16 *) buf;
len >>= 1;
@@ -197,8 +196,9 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
{
- struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info);
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
+ chip);
switch (cmd) {
@@ -267,8 +267,9 @@ static void au1550_select_chip(struct mtd_info *mtd, int chip)
*/
static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
- struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info);
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
+ chip);
int ce_override = 0, i;
unsigned long flags = 0;
@@ -405,6 +406,7 @@ static int au1550nd_probe(struct platform_device *pdev)
struct au1550nd_platdata *pd;
struct au1550nd_ctx *ctx;
struct nand_chip *this;
+ struct mtd_info *mtd;
struct resource *r;
int ret, cs;
@@ -438,8 +440,8 @@ static int au1550nd_probe(struct platform_device *pdev)
}
this = &ctx->chip;
- ctx->info.priv = this;
- ctx->info.dev.parent = &pdev->dev;
+ mtd = nand_to_mtd(this);
+ mtd->dev.parent = &pdev->dev;
/* figure out which CS# r->start belongs to */
cs = find_nand_cs(r->start);
@@ -467,13 +469,13 @@ static int au1550nd_probe(struct platform_device *pdev)
this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
- ret = nand_scan(&ctx->info, 1);
+ ret = nand_scan(mtd, 1);
if (ret) {
dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
goto out3;
}
- mtd_device_register(&ctx->info, pd->parts, pd->num_parts);
+ mtd_device_register(mtd, pd->parts, pd->num_parts);
platform_set_drvdata(pdev, ctx);
@@ -493,7 +495,7 @@ static int au1550nd_remove(struct platform_device *pdev)
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nand_release(&ctx->info);
+ nand_release(nand_to_mtd(&ctx->chip));
iounmap(ctx->base);
release_mem_region(r->start, 0x1000);
kfree(ctx);
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
index c005a62330b1..8ea75710a854 100644
--- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
+++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
@@ -12,7 +12,6 @@ struct bcm47xxnflash {
struct bcma_drv_cc *cc;
struct nand_chip nand_chip;
- struct mtd_info mtd;
unsigned curr_command;
int curr_page_addr;
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c
index 9ba0c0f2cd9b..fb31429b70a9 100644
--- a/drivers/mtd/nand/bcm47xxnflash/main.c
+++ b/drivers/mtd/nand/bcm47xxnflash/main.c
@@ -27,15 +27,16 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
{
struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
struct bcm47xxnflash *b47n;
+ struct mtd_info *mtd;
int err = 0;
b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
if (!b47n)
return -ENOMEM;
- b47n->nand_chip.priv = b47n;
- b47n->mtd.dev.parent = &pdev->dev;
- b47n->mtd.priv = &b47n->nand_chip; /* Required */
+ nand_set_controller_data(&b47n->nand_chip, b47n);
+ mtd = nand_to_mtd(&b47n->nand_chip);
+ mtd->dev.parent = &pdev->dev;
b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
@@ -49,7 +50,9 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
return err;
}
- err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0);
+ platform_set_drvdata(pdev, b47n);
+
+ err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
if (err) {
pr_err("Failed to register MTD device: %d\n", err);
return err;
@@ -60,10 +63,9 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
static int bcm47xxnflash_remove(struct platform_device *pdev)
{
- struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+ struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
- if (nflash->mtd)
- mtd_device_unregister(nflash->mtd);
+ nand_release(nand_to_mtd(&nflash->nand_chip));
return 0;
}
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
index 592befc7ffa1..f1da4ea88f2c 100644
--- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
+++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
@@ -89,8 +89,8 @@ static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
int len)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
u32 ctlcode;
u32 *dest = (u32 *)buf;
@@ -139,8 +139,8 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
@@ -173,8 +173,8 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
u32 code = 0;
if (cmd == NAND_CMD_NONE)
@@ -199,8 +199,8 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
}
@@ -216,8 +216,8 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
unsigned command, int column,
int page_addr)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
int i;
@@ -312,8 +312,8 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 tmp = 0;
@@ -341,8 +341,8 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
switch (b47n->curr_command) {
case NAND_CMD_READ0:
@@ -357,8 +357,8 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
- struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
switch (b47n->curr_command) {
case NAND_CMD_SEQIN:
@@ -421,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
/* Scan NAND */
- err = nand_scan(&b47n->mtd, 1);
+ err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
if (err) {
pr_err("Could not scan NAND flash: %d\n", err);
goto exit;
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 61bd2160717c..7f6b30e615b7 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -142,7 +142,6 @@ static struct nand_ecclayout bootrom_ecclayout = {
struct bf5xx_nand_info {
/* mtd info */
struct nand_hw_control controller;
- struct mtd_info mtd;
struct nand_chip chip;
/* platform info */
@@ -160,7 +159,8 @@ struct bf5xx_nand_info {
*/
static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
{
- return container_of(mtd, struct bf5xx_nand_info, mtd);
+ return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
+ chip);
}
static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
@@ -252,7 +252,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
*/
if (hweight32(syndrome[0]) == 1) {
dev_err(info->device, "ECC data was incorrect!\n");
- return 1;
+ return -EBADMSG;
}
syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
@@ -285,7 +285,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
data = data ^ (0x1 << failing_bit);
*(dat + failing_byte) = data;
- return 0;
+ return 1;
}
/*
@@ -298,26 +298,34 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
dev_err(info->device,
"Please discard data, mark bad block\n");
- return 1;
+ return -EBADMSG;
}
static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct nand_chip *chip = mtd->priv;
- int ret;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret, bitflips = 0;
ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+ if (ret < 0)
+ return ret;
+
+ bitflips = ret;
/* If ecc size is 512, correct second 256 bytes */
if (chip->ecc.size == 512) {
dat += 256;
read_ecc += 3;
calc_ecc += 3;
- ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+ ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+ if (ret < 0)
+ return ret;
+
+ bitflips += ret;
}
- return ret;
+ return bitflips;
}
static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -329,7 +337,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
u16 ecc0, ecc1;
u32 code[2];
u8 *p;
@@ -466,7 +474,7 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
uint8_t *buf, int is_read)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
unsigned short val;
dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
@@ -532,7 +540,7 @@ static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
uint8_t *buf, int len)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
@@ -546,7 +554,7 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
@@ -660,7 +668,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
*/
static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
{
- struct mtd_info *mtd = &info->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&info->chip);
struct mtd_partition *parts = info->platform->partitions;
int nr = info->platform->nr_partitions;
@@ -675,7 +683,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
* and their partitions, then go through freeing the
* resources used
*/
- nand_release(&info->mtd);
+ nand_release(nand_to_mtd(&info->chip));
peripheral_free_list(bfin_nfc_pin_req);
bf5xx_nand_dma_remove(info);
@@ -685,7 +693,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
static int bf5xx_nand_scan(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
ret = nand_scan_ident(mtd, 1, NULL);
@@ -756,6 +764,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
/* initialise chip data struct */
chip = &info->chip;
+ mtd = nand_to_mtd(&info->chip);
if (plat->data_width)
chip->options |= NAND_BUSWIDTH_16;
@@ -772,7 +781,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
chip->cmd_ctrl = bf5xx_nand_hwcontrol;
chip->dev_ready = bf5xx_nand_devready;
- chip->priv = &info->mtd;
+ nand_set_controller_data(chip, mtd);
chip->controller = &info->controller;
chip->IO_ADDR_R = (void __iomem *) NFC_READ;
@@ -781,8 +790,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
chip->chip_delay = 0;
/* initialise mtd info data struct */
- mtd = &info->mtd;
- mtd->priv = chip;
mtd->dev.parent = &pdev->dev;
/* initialise the hardware */
diff --git a/drivers/mtd/nand/brcmnand/Makefile b/drivers/mtd/nand/brcmnand/Makefile
index 3b1fbfd27d4f..b28ffb59eb43 100644
--- a/drivers/mtd/nand/brcmnand/Makefile
+++ b/drivers/mtd/nand/brcmnand/Makefile
@@ -2,5 +2,6 @@
# more specific iproc_nand.o, for instance
obj-$(CONFIG_MTD_NAND_BRCMNAND) += iproc_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += bcm63138_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND) += bcm6368_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmstb_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
diff --git a/drivers/mtd/nand/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/brcmnand/bcm6368_nand.c
new file mode 100644
index 000000000000..34c91b0e1e69
--- /dev/null
+++ b/drivers/mtd/nand/brcmnand/bcm6368_nand.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 Simon Arlott
+ *
+ * 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.
+ *
+ * Derived from bcm63138_nand.c:
+ * Copyright © 2015 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ * Copyright 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c:
+ * Copyright 2000-2010 Broadcom Corporation
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "brcmnand.h"
+
+struct bcm6368_nand_soc {
+ struct brcmnand_soc soc;
+ void __iomem *base;
+};
+
+#define BCM6368_NAND_INT 0x00
+#define BCM6368_NAND_STATUS_SHIFT 0
+#define BCM6368_NAND_STATUS_MASK (0xfff << BCM6368_NAND_STATUS_SHIFT)
+#define BCM6368_NAND_ENABLE_SHIFT 16
+#define BCM6368_NAND_ENABLE_MASK (0xffff << BCM6368_NAND_ENABLE_SHIFT)
+#define BCM6368_NAND_BASE_ADDR0 0x04
+#define BCM6368_NAND_BASE_ADDR1 0x0c
+
+enum {
+ BCM6368_NP_READ = BIT(0),
+ BCM6368_BLOCK_ERASE = BIT(1),
+ BCM6368_COPY_BACK = BIT(2),
+ BCM6368_PAGE_PGM = BIT(3),
+ BCM6368_CTRL_READY = BIT(4),
+ BCM6368_DEV_RBPIN = BIT(5),
+ BCM6368_ECC_ERR_UNC = BIT(6),
+ BCM6368_ECC_ERR_CORR = BIT(7),
+};
+
+static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
+{
+ struct bcm6368_nand_soc *priv =
+ container_of(soc, struct bcm6368_nand_soc, soc);
+ void __iomem *mmio = priv->base + BCM6368_NAND_INT;
+ u32 val = brcmnand_readl(mmio);
+
+ if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
+ /* Ack interrupt */
+ val &= ~BCM6368_NAND_STATUS_MASK;
+ val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
+ brcmnand_writel(val, mmio);
+ return true;
+ }
+
+ return false;
+}
+
+static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
+{
+ struct bcm6368_nand_soc *priv =
+ container_of(soc, struct bcm6368_nand_soc, soc);
+ void __iomem *mmio = priv->base + BCM6368_NAND_INT;
+ u32 val = brcmnand_readl(mmio);
+
+ /* Don't ack any interrupts */
+ val &= ~BCM6368_NAND_STATUS_MASK;
+
+ if (en)
+ val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
+ else
+ val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
+
+ brcmnand_writel(val, mmio);
+}
+
+static int bcm6368_nand_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bcm6368_nand_soc *priv;
+ struct brcmnand_soc *soc;
+ struct resource *res;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ soc = &priv->soc;
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "nand-int-base");
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ soc->ctlrdy_ack = bcm6368_nand_intc_ack;
+ soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
+
+ /* Disable and ack all interrupts */
+ brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
+ brcmnand_writel(BCM6368_NAND_STATUS_MASK,
+ priv->base + BCM6368_NAND_INT);
+
+ return brcmnand_probe(pdev, soc);
+}
+
+static const struct of_device_id bcm6368_nand_of_match[] = {
+ { .compatible = "brcm,nand-bcm6368" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
+
+static struct platform_driver bcm6368_nand_driver = {
+ .probe = bcm6368_nand_probe,
+ .remove = brcmnand_remove,
+ .driver = {
+ .name = "bcm6368_nand",
+ .pm = &brcmnand_pm_ops,
+ .of_match_table = bcm6368_nand_of_match,
+ }
+};
+module_platform_driver(bcm6368_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Arlott");
+MODULE_DESCRIPTION("NAND driver for BCM6368");
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 12c6190c6e33..844fc07d22cd 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -122,6 +123,9 @@ struct brcmnand_controller {
/* Some SoCs provide custom interrupt status register(s) */
struct brcmnand_soc *soc;
+ /* Some SoCs have a gateable clock for the controller */
+ struct clk *clk;
+
int cmd_pending;
bool dma_pending;
struct completion done;
@@ -134,7 +138,7 @@ struct brcmnand_controller {
dma_addr_t dma_pa;
/* in-memory cache of the FLASH_CACHE, used only for some commands */
- u32 flash_cache[FC_WORDS];
+ u8 flash_cache[FC_BYTES];
/* Controller revision details */
const u16 *reg_offsets;
@@ -176,10 +180,8 @@ struct brcmnand_cfg {
struct brcmnand_host {
struct list_head node;
- struct device_node *of_node;
struct nand_chip chip;
- struct mtd_info mtd;
struct platform_device *pdev;
int cs;
@@ -874,8 +876,8 @@ static struct nand_ecclayout *brcmstb_choose_ecc_layout(
static void brcmnand_wp(struct mtd_info *mtd, int wp)
{
- struct nand_chip *chip = mtd->priv;
- struct brcmnand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
@@ -1040,8 +1042,8 @@ static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
{
- struct nand_chip *chip = mtd->priv;
- struct brcmnand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1075,7 +1077,7 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
enum brcmnand_llop_type type, u32 data,
bool last_op)
{
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
struct nand_chip *chip = &host->chip;
struct brcmnand_controller *ctrl = host->ctrl;
u32 tmp;
@@ -1114,8 +1116,8 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd->priv;
- struct brcmnand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
u64 addr = (u64)page_addr << chip->page_shift;
int native_cmd = 0;
@@ -1188,6 +1190,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
if (native_cmd == CMD_PARAMETER_READ ||
native_cmd == CMD_PARAMETER_CHANGE_COL) {
+ /* Copy flash cache word-wise */
+ u32 *flash_cache = (u32 *)ctrl->flash_cache;
int i;
brcmnand_soc_data_bus_prepare(ctrl->soc);
@@ -1197,7 +1201,11 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
* SECTOR_SIZE_1K may invalidate it
*/
for (i = 0; i < FC_WORDS; i++)
- ctrl->flash_cache[i] = brcmnand_read_fc(ctrl, i);
+ /*
+ * Flash cache is big endian for parameter pages, at
+ * least on STB SoCs
+ */
+ flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
brcmnand_soc_data_bus_unprepare(ctrl->soc);
@@ -1214,8 +1222,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct brcmnand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
uint8_t ret = 0;
int addr, offs;
@@ -1250,8 +1258,7 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
if (host->last_byte > 0 && offs == 0)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1);
- ret = ctrl->flash_cache[offs >> 2] >>
- (24 - ((offs & 0x03) << 3));
+ ret = ctrl->flash_cache[offs];
break;
case NAND_CMD_GET_FEATURES:
if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
@@ -1282,8 +1289,8 @@ static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
int len)
{
int i;
- struct nand_chip *chip = mtd->priv;
- struct brcmnand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
switch (host->last_cmd) {
case NAND_CMD_SET_FEATURES:
@@ -1393,13 +1400,15 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
u64 addr, unsigned int trans, u32 *buf,
u8 *oob, u64 *err_addr)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
int i, j, ret = 0;
/* Clear error addresses */
brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
+ brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
+ brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
(host->cs << 16) | ((addr >> 32) & 0xffff));
@@ -1454,7 +1463,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
u64 addr, unsigned int trans, u32 *buf, u8 *oob)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
u64 err_addr = 0;
int err;
@@ -1504,7 +1513,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
return brcmnand_read(mtd, chip, host->last_addr,
@@ -1514,7 +1523,7 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
int ret;
@@ -1536,7 +1545,7 @@ static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
brcmnand_set_ecc_enabled(host, 0);
brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
@@ -1546,20 +1555,10 @@ static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int brcmnand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t data_offs, uint32_t readlen,
- uint8_t *bufpoi, int page)
-{
- struct brcmnand_host *host = chip->priv;
-
- return brcmnand_read(mtd, chip, host->last_addr + data_offs,
- readlen >> FC_SHIFT, (u32 *)bufpoi, NULL);
-}
-
static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
u64 addr, const u32 *buf, u8 *oob)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
int status, ret = 0;
@@ -1630,7 +1629,7 @@ out:
static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL;
brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
@@ -1641,7 +1640,7 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL;
brcmnand_set_ecc_enabled(host, 0);
@@ -1660,7 +1659,7 @@ static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct brcmnand_host *host = chip->priv;
+ struct brcmnand_host *host = nand_get_controller_data(chip);
int ret;
brcmnand_set_ecc_enabled(host, 0);
@@ -1806,7 +1805,7 @@ static inline int get_blk_adr_bytes(u64 size, u32 writesize)
static int brcmnand_setup_dev(struct brcmnand_host *host)
{
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
struct nand_chip *chip = &host->chip;
struct brcmnand_controller *ctrl = host->ctrl;
struct brcmnand_cfg *cfg = &host->hwcfg;
@@ -1816,7 +1815,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
memset(cfg, 0, sizeof(*cfg));
- ret = of_property_read_u32(chip->flash_node,
+ ret = of_property_read_u32(nand_get_flash_node(chip),
"brcm,nand-oob-sector-size",
&oob_sector);
if (ret) {
@@ -1905,16 +1904,14 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
return 0;
}
-static int brcmnand_init_cs(struct brcmnand_host *host)
+static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
{
struct brcmnand_controller *ctrl = host->ctrl;
- struct device_node *dn = host->of_node;
struct platform_device *pdev = host->pdev;
struct mtd_info *mtd;
struct nand_chip *chip;
int ret;
u16 cfg_offs;
- struct mtd_part_parser_data ppdata = { .of_node = dn };
ret = of_property_read_u32(dn, "reg", &host->cs);
if (ret) {
@@ -1922,12 +1919,11 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
return -ENXIO;
}
- mtd = &host->mtd;
+ mtd = nand_to_mtd(&host->chip);
chip = &host->chip;
- chip->flash_node = dn;
- chip->priv = host;
- mtd->priv = chip;
+ nand_set_flash_node(chip, dn);
+ nand_set_controller_data(chip, host);
mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
host->cs);
mtd->owner = THIS_MODULE;
@@ -1945,7 +1941,6 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.read_page = brcmnand_read_page;
- chip->ecc.read_subpage = brcmnand_read_subpage;
chip->ecc.write_page = brcmnand_write_page;
chip->ecc.read_page_raw = brcmnand_read_page_raw;
chip->ecc.write_page_raw = brcmnand_write_page_raw;
@@ -1993,7 +1988,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
if (nand_scan_tail(mtd))
return -ENXIO;
- return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ return mtd_device_register(mtd, NULL, 0);
}
static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
@@ -2067,8 +2062,8 @@ static int brcmnand_resume(struct device *dev)
}
list_for_each_entry(host, &ctrl->host_list, node) {
- struct mtd_info *mtd = &host->mtd;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = &host->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
brcmnand_save_restore_cs_config(host, 1);
@@ -2134,10 +2129,24 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
if (IS_ERR(ctrl->nand_base))
return PTR_ERR(ctrl->nand_base);
+ /* Enable clock before using NAND registers */
+ ctrl->clk = devm_clk_get(dev, "nand");
+ if (!IS_ERR(ctrl->clk)) {
+ ret = clk_prepare_enable(ctrl->clk);
+ if (ret)
+ return ret;
+ } else {
+ ret = PTR_ERR(ctrl->clk);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ ctrl->clk = NULL;
+ }
+
/* Initialize NAND revision */
ret = brcmnand_revision_init(ctrl);
if (ret)
- return ret;
+ goto err;
/*
* Most chips have this cache at a fixed offset within 'nand' block.
@@ -2146,8 +2155,10 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
if (res) {
ctrl->nand_fc = devm_ioremap_resource(dev, res);
- if (IS_ERR(ctrl->nand_fc))
- return PTR_ERR(ctrl->nand_fc);
+ if (IS_ERR(ctrl->nand_fc)) {
+ ret = PTR_ERR(ctrl->nand_fc);
+ goto err;
+ }
} else {
ctrl->nand_fc = ctrl->nand_base +
ctrl->reg_offsets[BRCMNAND_FC_BASE];
@@ -2157,8 +2168,10 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
if (res) {
ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(ctrl->flash_dma_base))
- return PTR_ERR(ctrl->flash_dma_base);
+ if (IS_ERR(ctrl->flash_dma_base)) {
+ ret = PTR_ERR(ctrl->flash_dma_base);
+ goto err;
+ }
flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
@@ -2167,13 +2180,16 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
ctrl->dma_desc = dmam_alloc_coherent(dev,
sizeof(*ctrl->dma_desc),
&ctrl->dma_pa, GFP_KERNEL);
- if (!ctrl->dma_desc)
- return -ENOMEM;
+ if (!ctrl->dma_desc) {
+ ret = -ENOMEM;
+ goto err;
+ }
ctrl->dma_irq = platform_get_irq(pdev, 1);
if ((int)ctrl->dma_irq < 0) {
dev_err(dev, "missing FLASH_DMA IRQ\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
ret = devm_request_irq(dev, ctrl->dma_irq,
@@ -2182,7 +2198,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
if (ret < 0) {
dev_err(dev, "can't allocate IRQ %d: error %d\n",
ctrl->dma_irq, ret);
- return ret;
+ goto err;
}
dev_info(dev, "enabling FLASH_DMA\n");
@@ -2206,7 +2222,8 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
ctrl->irq = platform_get_irq(pdev, 0);
if ((int)ctrl->irq < 0) {
dev_err(dev, "no IRQ defined\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
/*
@@ -2230,7 +2247,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
if (ret < 0) {
dev_err(dev, "can't allocate IRQ %d: error %d\n",
ctrl->irq, ret);
- return ret;
+ goto err;
}
for_each_available_child_of_node(dn, child) {
@@ -2238,25 +2255,36 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
struct brcmnand_host *host;
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
- if (!host)
- return -ENOMEM;
+ if (!host) {
+ of_node_put(child);
+ ret = -ENOMEM;
+ goto err;
+ }
host->pdev = pdev;
host->ctrl = ctrl;
- host->of_node = child;
- ret = brcmnand_init_cs(host);
- if (ret)
+ ret = brcmnand_init_cs(host, child);
+ if (ret) {
+ devm_kfree(dev, host);
continue; /* Try all chip-selects */
+ }
list_add_tail(&host->node, &ctrl->host_list);
}
}
/* No chip-selects could initialize properly */
- if (list_empty(&ctrl->host_list))
- return -ENODEV;
+ if (list_empty(&ctrl->host_list)) {
+ ret = -ENODEV;
+ goto err;
+ }
return 0;
+
+err:
+ clk_disable_unprepare(ctrl->clk);
+ return ret;
+
}
EXPORT_SYMBOL_GPL(brcmnand_probe);
@@ -2266,7 +2294,9 @@ int brcmnand_remove(struct platform_device *pdev)
struct brcmnand_host *host;
list_for_each_entry(host, &ctrl->host_list, node)
- nand_release(&host->mtd);
+ nand_release(nand_to_mtd(&host->chip));
+
+ clk_disable_unprepare(ctrl->clk);
dev_set_drvdata(&pdev->dev, NULL);
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 9de78d2a2eb1..aa1a616b9fb6 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -101,7 +101,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
static int cafe_device_ready(struct mtd_info *mtd)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
@@ -117,7 +118,8 @@ static int cafe_device_ready(struct mtd_info *mtd)
static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
if (usedma)
memcpy(cafe->dmabuf + cafe->datalen, buf, len);
@@ -132,7 +134,8 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
if (usedma)
memcpy(buf, cafe->dmabuf + cafe->datalen, len);
@@ -146,7 +149,8 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static uint8_t cafe_read_byte(struct mtd_info *mtd)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
uint8_t d;
cafe_read_buf(mtd, &d, 1);
@@ -158,7 +162,8 @@ static uint8_t cafe_read_byte(struct mtd_info *mtd)
static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
int column, int page_addr)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
int adrbytes = 0;
uint32_t ctl1;
uint32_t doneint = 0x80000000;
@@ -313,7 +318,8 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
@@ -328,7 +334,8 @@ static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
static irqreturn_t cafe_nand_interrupt(int irq, void *id)
{
struct mtd_info *mtd = id;
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
if (!irqs)
@@ -377,7 +384,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
unsigned int max_bitflips = 0;
cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
@@ -519,7 +526,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
const uint8_t *buf, int oob_required,
int page)
{
- struct cafe_priv *cafe = mtd->priv;
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
chip->write_buf(mtd, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -598,13 +605,13 @@ static int cafe_nand_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
- if (!mtd)
+ cafe = kzalloc(sizeof(*cafe), GFP_KERNEL);
+ if (!cafe)
return -ENOMEM;
- cafe = (void *)(&mtd[1]);
+ mtd = nand_to_mtd(&cafe->nand);
mtd->dev.parent = &pdev->dev;
- mtd->priv = cafe;
+ nand_set_controller_data(&cafe->nand, cafe);
cafe->pdev = pdev;
cafe->mmio = pci_iomap(pdev, 0, 0);
@@ -784,7 +791,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
out_ior:
pci_iounmap(pdev, cafe->mmio);
out_free_mtd:
- kfree(mtd);
+ kfree(cafe);
out:
return err;
}
@@ -792,7 +799,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
static void cafe_nand_remove(struct pci_dev *pdev)
{
struct mtd_info *mtd = pci_get_drvdata(pdev);
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
@@ -804,7 +812,7 @@ static void cafe_nand_remove(struct pci_dev *pdev)
2112 + sizeof(struct nand_buffers) +
mtd->writesize + mtd->oobsize,
cafe->dmabuf, cafe->dmaaddr);
- kfree(mtd);
+ kfree(cafe);
}
static const struct pci_device_id cafe_nand_tbl[] = {
@@ -819,7 +827,8 @@ static int cafe_nand_resume(struct pci_dev *pdev)
{
uint32_t ctrl;
struct mtd_info *mtd = pci_get_drvdata(pdev);
- struct cafe_priv *cafe = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
/* Start off by resetting the NAND controller completely */
cafe_writel(cafe, 1, NAND_RESET);
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 66ec95e6ca6c..6f97ebba52c4 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -53,7 +53,7 @@ static struct mtd_partition partition_info[] = {
static u_char cmx270_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
return (readl(this->IO_ADDR_R) >> 16);
}
@@ -61,7 +61,7 @@ static u_char cmx270_read_byte(struct mtd_info *mtd)
static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
for (i=0; i<len; i++)
writel((*buf++ << 16), this->IO_ADDR_W);
@@ -70,7 +70,7 @@ static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
for (i=0; i<len; i++)
*buf++ = readl(this->IO_ADDR_R) >> 16;
@@ -94,7 +94,7 @@ static void nand_cs_off(void)
static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
unsigned int ctrl)
{
- struct nand_chip* this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
dsb();
@@ -160,10 +160,8 @@ static int __init cmx270_init(void)
gpio_direction_input(GPIO_NAND_RB);
/* Allocate memory for MTD device structure and private data */
- cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip),
- GFP_KERNEL);
- if (!cmx270_nand_mtd) {
+ this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+ if (!this) {
ret = -ENOMEM;
goto err_kzalloc;
}
@@ -175,12 +173,10 @@ static int __init cmx270_init(void)
goto err_ioremap;
}
- /* Get pointer to private data */
- this = (struct nand_chip *)(&cmx270_nand_mtd[1]);
+ cmx270_nand_mtd = nand_to_mtd(this);
/* Link the private data with the MTD structure */
cmx270_nand_mtd->owner = THIS_MODULE;
- cmx270_nand_mtd->priv = this;
/* insert callbacks */
this->IO_ADDR_R = cmx270_nand_io;
@@ -216,7 +212,7 @@ static int __init cmx270_init(void)
err_scan:
iounmap(cmx270_nand_io);
err_ioremap:
- kfree(cmx270_nand_mtd);
+ kfree(this);
err_kzalloc:
gpio_free(GPIO_NAND_RB);
err_gpio_request:
@@ -240,8 +236,7 @@ static void __exit cmx270_cleanup(void)
iounmap(cmx270_nand_io);
- /* Free the MTD device structure */
- kfree (cmx270_nand_mtd);
+ kfree(mtd_to_nand(cmx270_nand_mtd));
}
module_exit(cmx270_cleanup);
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index aec6045058c7..a65e4e0f57a1 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -97,7 +97,7 @@
static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
while (unlikely(len > 0x800)) {
memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
@@ -109,7 +109,7 @@ static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
while (unlikely(len > 0x800)) {
memcpy_toio(this->IO_ADDR_R, buf, 0x800);
@@ -121,13 +121,13 @@ static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
static unsigned char cs553x_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
return readb(this->IO_ADDR_R);
}
static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int i = 100000;
while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
@@ -140,7 +140,7 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
void __iomem *mmio_base = this->IO_ADDR_R;
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
@@ -152,7 +152,7 @@ static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
static int cs553x_device_ready(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
void __iomem *mmio_base = this->IO_ADDR_R;
unsigned char foo = readb(mmio_base + MM_NAND_STS);
@@ -161,7 +161,7 @@ static int cs553x_device_ready(struct mtd_info *mtd)
static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
void __iomem *mmio_base = this->IO_ADDR_R;
writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
@@ -170,7 +170,7 @@ static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
uint32_t ecc;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
void __iomem *mmio_base = this->IO_ADDR_R;
ecc = readl(mmio_base + MM_NAND_STS);
@@ -197,17 +197,15 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
}
/* Allocate memory for MTD device structure and private data */
- new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
- if (!new_mtd) {
+ this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+ if (!this) {
err = -ENOMEM;
goto out;
}
- /* Get pointer to private data */
- this = (struct nand_chip *)(&new_mtd[1]);
+ new_mtd = nand_to_mtd(this);
/* Link the private data with the MTD structure */
- new_mtd->priv = this;
new_mtd->owner = THIS_MODULE;
/* map physical address */
@@ -257,7 +255,7 @@ out_free:
out_ior:
iounmap(this->IO_ADDR_R);
out_mtd:
- kfree(new_mtd);
+ kfree(this);
out:
return err;
}
@@ -337,19 +335,19 @@ static void __exit cs553x_cleanup(void)
if (!mtd)
continue;
- this = cs553x_mtd[i]->priv;
+ this = mtd_to_nand(mtd);
mmio_base = this->IO_ADDR_R;
/* Release resources, unregister device */
- nand_release(cs553x_mtd[i]);
- kfree(cs553x_mtd[i]->name);
+ nand_release(mtd);
+ kfree(mtd->name);
cs553x_mtd[i] = NULL;
/* unmap physical address */
iounmap(mmio_base);
/* Free the MTD device structure */
- kfree(mtd);
+ kfree(this);
}
}
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index c72313d66cf6..8cb821b6686e 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -53,7 +53,6 @@
* outputs in a "wire-AND" configuration, with no per-chip signals.
*/
struct davinci_nand_info {
- struct mtd_info mtd;
struct nand_chip chip;
struct nand_ecclayout ecclayout;
@@ -80,8 +79,10 @@ struct davinci_nand_info {
static DEFINE_SPINLOCK(davinci_nand_lock);
static bool ecc4_busy;
-#define to_davinci_nand(m) container_of(m, struct davinci_nand_info, mtd)
-
+static inline struct davinci_nand_info *to_davinci_nand(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct davinci_nand_info, chip);
+}
static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
int offset)
@@ -106,7 +107,7 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
{
struct davinci_nand_info *info = to_davinci_nand(mtd);
uint32_t addr = info->current_cs;
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
/* Did the control lines change? */
if (ctrl & NAND_CTRL_CHANGE) {
@@ -192,7 +193,7 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
(read_ecc[2] << 16);
uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
@@ -206,7 +207,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
return 1;
} else {
- return -1;
+ return -EBADMSG;
}
} else if (!(diff & (diff - 1))) {
/* Single bit ECC error in the ECC itself,
@@ -214,7 +215,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
return 1;
} else {
/* Uncorrectable error */
- return -1;
+ return -EBADMSG;
}
}
@@ -316,14 +317,6 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
unsigned num_errors, corrected;
unsigned long timeo;
- /* All bytes 0xff? It's an erased page; ignore its ECC. */
- for (i = 0; i < 10; i++) {
- if (ecc_code[i] != 0xff)
- goto compare;
- }
- return 0;
-
-compare:
/* Unpack ten bytes into eight 10 bit values. We know we're
* little-endian, and use type punning for less shifting/masking.
*/
@@ -390,7 +383,7 @@ compare:
return 0;
case 1: /* five or more errors detected */
davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
- return -EIO;
+ return -EBADMSG;
case 2: /* error addresses computed */
case 3:
num_errors = 1 + ((fsr >> 16) & 0x03);
@@ -447,7 +440,7 @@ correct:
*/
static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
@@ -460,7 +453,7 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void nand_davinci_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
@@ -636,6 +629,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
int ret;
uint32_t val;
nand_ecc_modes_t ecc_mode;
+ struct mtd_info *mtd;
pdata = nand_davinci_get_pdata(pdev);
if (IS_ERR(pdata))
@@ -682,8 +676,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->base = base;
info->vaddr = vaddr;
- info->mtd.priv = &info->chip;
- info->mtd.dev.parent = &pdev->dev;
+ mtd = nand_to_mtd(&info->chip);
+ mtd->dev.parent = &pdev->dev;
+ nand_set_flash_node(&info->chip, pdev->dev.of_node);
info->chip.IO_ADDR_R = vaddr;
info->chip.IO_ADDR_W = vaddr;
@@ -746,6 +741,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->chip.ecc.correct = nand_davinci_correct_4bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
info->chip.ecc.bytes = 10;
+ info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
} else {
info->chip.ecc.calculate = nand_davinci_calculate_1bit;
info->chip.ecc.correct = nand_davinci_correct_1bit;
@@ -784,7 +780,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
spin_unlock_irq(&davinci_nand_lock);
/* Scan to find existence of the device(s) */
- ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL);
+ ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
goto err;
@@ -796,9 +792,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
* usable: 10 bytes are needed, not 6.
*/
if (pdata->ecc_bits == 4) {
- int chunks = info->mtd.writesize / 512;
+ int chunks = mtd->writesize / 512;
- if (!chunks || info->mtd.oobsize < 16) {
+ if (!chunks || mtd->oobsize < 16) {
dev_dbg(&pdev->dev, "too small\n");
ret = -EINVAL;
goto err;
@@ -810,8 +806,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
*/
if (chunks == 1) {
info->ecclayout = hwecc4_small;
- info->ecclayout.oobfree[1].length =
- info->mtd.oobsize - 16;
+ info->ecclayout.oobfree[1].length = mtd->oobsize - 16;
goto syndrome_done;
}
if (chunks == 4) {
@@ -832,20 +827,15 @@ syndrome_done:
info->chip.ecc.layout = &info->ecclayout;
}
- ret = nand_scan_tail(&info->mtd);
+ ret = nand_scan_tail(mtd);
if (ret < 0)
goto err;
if (pdata->parts)
- ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
+ ret = mtd_device_parse_register(mtd, NULL, NULL,
pdata->parts, pdata->nr_parts);
- else {
- struct mtd_part_parser_data ppdata;
-
- ppdata.of_node = pdev->dev.of_node;
- ret = mtd_device_parse_register(&info->mtd, NULL, &ppdata,
- NULL, 0);
- }
+ else
+ ret = mtd_device_register(mtd, NULL, 0);
if (ret < 0)
goto err;
@@ -875,7 +865,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock);
- nand_release(&info->mtd);
+ nand_release(nand_to_mtd(&info->chip));
clk_disable_unprepare(info->clk);
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 67eb2be0db87..30bf5f690f78 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -75,7 +75,10 @@ MODULE_PARM_DESC(onfi_timing_mode,
* this macro allows us to convert from an MTD structure to our own
* device context (denali) structure.
*/
-#define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd)
+static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
+}
/*
* These constants are defined by the driver to enable common driver
@@ -986,6 +989,8 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
* than one NAND connected.
*/
if (err_byte < ECC_SECTOR_SIZE) {
+ struct mtd_info *mtd =
+ nand_to_mtd(&denali->nand);
int offset;
offset = (err_sector *
@@ -995,7 +1000,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
err_device;
/* correct the ECC error */
buf[offset] ^= err_correction_value;
- denali->mtd.ecc_stats.corrected++;
+ mtd->ecc_stats.corrected++;
bitflips++;
}
} else {
@@ -1062,7 +1067,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
- size_t size = denali->mtd.writesize + denali->mtd.oobsize;
+ size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP |
INTR_STATUS__PROGRAM_FAIL;
@@ -1160,7 +1165,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
- size_t size = denali->mtd.writesize + denali->mtd.oobsize;
+ size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
@@ -1193,14 +1198,14 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
denali_enable_dma(denali, false);
if (check_erased_page) {
- read_oob_data(&denali->mtd, chip->oob_poi, denali->page);
+ read_oob_data(mtd, chip->oob_poi, denali->page);
/* check ECC failures that may have occurred on erased pages */
if (check_erased_page) {
- if (!is_erased(buf, denali->mtd.writesize))
- denali->mtd.ecc_stats.failed++;
- if (!is_erased(buf, denali->mtd.oobsize))
- denali->mtd.ecc_stats.failed++;
+ if (!is_erased(buf, mtd->writesize))
+ mtd->ecc_stats.failed++;
+ if (!is_erased(buf, mtd->oobsize))
+ mtd->ecc_stats.failed++;
}
}
return max_bitflips;
@@ -1211,7 +1216,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
- size_t size = denali->mtd.writesize + denali->mtd.oobsize;
+ size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
if (page != denali->page) {
@@ -1428,6 +1433,7 @@ static void denali_drv_init(struct denali_nand_info *denali)
int denali_init(struct denali_nand_info *denali)
{
+ struct mtd_info *mtd = nand_to_mtd(&denali->nand);
int ret;
if (denali->platform == INTEL_CE4100) {
@@ -1447,7 +1453,7 @@ int denali_init(struct denali_nand_info *denali)
if (!denali->buf.buf)
return -ENOMEM;
- denali->mtd.dev.parent = denali->dev;
+ mtd->dev.parent = denali->dev;
denali_hw_init(denali);
denali_drv_init(denali);
@@ -1463,8 +1469,7 @@ int denali_init(struct denali_nand_info *denali)
/* now that our ISR is registered, we can enable interrupts */
denali_set_intr_modes(denali, true);
- denali->mtd.name = "denali-nand";
- denali->mtd.priv = &denali->nand;
+ mtd->name = "denali-nand";
/* register the driver with the NAND core subsystem */
denali->nand.select_chip = denali_select_chip;
@@ -1477,7 +1482,7 @@ int denali_init(struct denali_nand_info *denali)
* this is the first stage in a two step process to register
* with the nand subsystem
*/
- if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) {
+ if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
ret = -ENXIO;
goto failed_req_irq;
}
@@ -1485,7 +1490,7 @@ int denali_init(struct denali_nand_info *denali)
/* allocate the right size buffer now */
devm_kfree(denali->dev, denali->buf.buf);
denali->buf.buf = devm_kzalloc(denali->dev,
- denali->mtd.writesize + denali->mtd.oobsize,
+ mtd->writesize + mtd->oobsize,
GFP_KERNEL);
if (!denali->buf.buf) {
ret = -ENOMEM;
@@ -1500,7 +1505,7 @@ int denali_init(struct denali_nand_info *denali)
}
denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
- denali->mtd.writesize + denali->mtd.oobsize,
+ mtd->writesize + mtd->oobsize,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
@@ -1521,10 +1526,10 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.bbt_erase_shift += (denali->devnum - 1);
denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
denali->nand.chip_shift += (denali->devnum - 1);
- denali->mtd.writesize <<= (denali->devnum - 1);
- denali->mtd.oobsize <<= (denali->devnum - 1);
- denali->mtd.erasesize <<= (denali->devnum - 1);
- denali->mtd.size = denali->nand.numchips * denali->nand.chipsize;
+ mtd->writesize <<= (denali->devnum - 1);
+ mtd->oobsize <<= (denali->devnum - 1);
+ mtd->erasesize <<= (denali->devnum - 1);
+ mtd->size = denali->nand.numchips * denali->nand.chipsize;
denali->bbtskipbytes *= denali->devnum;
/*
@@ -1551,16 +1556,16 @@ int denali_init(struct denali_nand_info *denali)
* SLC if possible.
* */
if (!nand_is_slc(&denali->nand) &&
- (denali->mtd.oobsize > (denali->bbtskipbytes +
- ECC_15BITS * (denali->mtd.writesize /
+ (mtd->oobsize > (denali->bbtskipbytes +
+ ECC_15BITS * (mtd->writesize /
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
denali->nand.ecc.strength = 15;
denali->nand.ecc.layout = &nand_15bit_oob;
denali->nand.ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
- } else if (denali->mtd.oobsize < (denali->bbtskipbytes +
- ECC_8BITS * (denali->mtd.writesize /
+ } else if (mtd->oobsize < (denali->bbtskipbytes +
+ ECC_8BITS * (mtd->writesize /
ECC_SECTOR_SIZE))) {
pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
goto failed_req_irq;
@@ -1574,11 +1579,11 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
denali->nand.ecc.layout->eccbytes *=
- denali->mtd.writesize / ECC_SECTOR_SIZE;
+ mtd->writesize / ECC_SECTOR_SIZE;
denali->nand.ecc.layout->oobfree[0].offset =
denali->bbtskipbytes + denali->nand.ecc.layout->eccbytes;
denali->nand.ecc.layout->oobfree[0].length =
- denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes -
+ mtd->oobsize - denali->nand.ecc.layout->eccbytes -
denali->bbtskipbytes;
/*
@@ -1586,7 +1591,7 @@ int denali_init(struct denali_nand_info *denali)
* contained by each nand chip. blksperchip will help driver to
* know how many blocks is taken by FW.
*/
- denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift;
+ denali->totalblks = mtd->size >> denali->nand.phys_erase_shift;
denali->blksperchip = denali->totalblks / denali->nand.numchips;
/* override the default read operations */
@@ -1599,12 +1604,12 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.ecc.write_oob = denali_write_oob;
denali->nand.erase = denali_erase;
- if (nand_scan_tail(&denali->mtd)) {
+ if (nand_scan_tail(mtd)) {
ret = -ENXIO;
goto failed_req_irq;
}
- ret = mtd_device_register(&denali->mtd, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
ret);
@@ -1622,9 +1627,17 @@ EXPORT_SYMBOL(denali_init);
/* driver exit point */
void denali_remove(struct denali_nand_info *denali)
{
+ struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+ /*
+ * Pre-compute DMA buffer size to avoid any problems in case
+ * nand_release() ever changes in a way that mtd->writesize and
+ * mtd->oobsize are not reliable after this call.
+ */
+ int bufsize = mtd->writesize + mtd->oobsize;
+
+ nand_release(mtd);
denali_irq_cleanup(denali->irq, denali);
- dma_unmap_single(denali->dev, denali->buf.dma_buf,
- denali->mtd.writesize + denali->mtd.oobsize,
+ dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize,
DMA_BIDIRECTIONAL);
}
EXPORT_SYMBOL(denali_remove);
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 4b12cd302819..e7ab4866a5da 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -450,7 +450,6 @@ struct nand_buf {
#define DT 3
struct denali_nand_info {
- struct mtd_info mtd;
struct nand_chip nand;
int flash_bank; /* currently selected chip */
int status;
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 0802158a3f75..f170f3c31b34 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -74,10 +74,6 @@ struct doc_priv {
int (*late_init)(struct mtd_info *mtd);
};
-/* This is the syndrome computed by the HW ecc generator upon reading an empty
- page, one with all 0xff for data and stored ecc code. */
-static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
-
/* This is the ecc value computed by the HW ecc generator upon writing an empty
page, one with all 0xff for data. */
static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
@@ -299,8 +295,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
if (debug)
@@ -311,8 +307,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
static u_char doc2000_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -326,8 +322,8 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
if (debug)
@@ -343,8 +339,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -358,8 +354,8 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -379,8 +375,8 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
uint16_t ret;
doc200x_select_chip(mtd, nr);
@@ -425,8 +421,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
static void __init doc2000_count_chips(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
uint16_t mfrid;
int i;
@@ -447,7 +443,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
{
- struct doc_priv *doc = this->priv;
+ struct doc_priv *doc = nand_get_controller_data(this);
int status;
@@ -461,8 +457,8 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
WriteDOC(datum, docptr, CDSNSlowIO);
@@ -472,8 +468,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
static u_char doc2001_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
//ReadDOC(docptr, CDSNSlowIO);
@@ -486,8 +482,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -499,8 +495,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -516,8 +512,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
static u_char doc2001plus_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -531,8 +527,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -549,8 +545,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -580,8 +576,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -607,8 +603,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
static void doc200x_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -638,8 +634,8 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
if (ctrl & NAND_CTRL_CHANGE) {
@@ -661,8 +657,8 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
/*
@@ -767,8 +763,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
static int doc200x_dev_ready(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
if (DoC_is_MillenniumPlus(doc)) {
@@ -807,8 +803,8 @@ static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
@@ -826,8 +822,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
@@ -846,8 +842,8 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
/* This code is only called on write */
static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
int emptymatch = 1;
@@ -907,12 +903,11 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
int i, ret = 0;
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
uint8_t calc_ecc[6];
volatile u_char dummy;
- int emptymatch = 1;
/* flush the pipeline */
if (DoC_is_2000(doc)) {
@@ -936,37 +931,9 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
else
calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
- if (calc_ecc[i] != empty_read_syndrome[i])
- emptymatch = 0;
- }
- /* If emptymatch=1, the read syndrome is consistent with an
- all-0xff data and stored ecc block. Check the stored ecc. */
- if (emptymatch) {
- for (i = 0; i < 6; i++) {
- if (read_ecc[i] == 0xff)
- continue;
- emptymatch = 0;
- break;
- }
}
- /* If emptymatch still =1, check the data block. */
- if (emptymatch) {
- /* Note: this somewhat expensive test should not be triggered
- often. It could be optimized away by examining the data in
- the readbuf routine, and remembering the result. */
- for (i = 0; i < 512; i++) {
- if (dat[i] == 0xff)
- continue;
- emptymatch = 0;
- break;
- }
- }
- /* If emptymatch still =1, this is almost certainly a freshly-
- erased block, in which case the ECC will not come out right.
- We'll suppress the error and tell the caller everything's
- OK. Because it is. */
- if (!emptymatch)
- ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
+
+ ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
if (ret > 0)
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
}
@@ -1007,8 +974,8 @@ static struct nand_ecclayout doc200x_oobinfo = {
mh1_page in the DOC private structure. */
static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
unsigned offs;
int ret;
size_t retlen;
@@ -1050,8 +1017,8 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
int ret = 0;
u_char *buf;
struct NFTLMediaHeader *mh;
@@ -1152,8 +1119,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
/* This is a stripped-down copy of the code in inftlmount.c */
static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
int ret = 0;
u_char *buf;
struct INFTLMediaHeader *mh;
@@ -1272,8 +1239,8 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
static int __init nftl_scan_bbt(struct mtd_info *mtd)
{
int ret, numparts;
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
struct mtd_partition parts[2];
memset((char *)parts, 0, sizeof(parts));
@@ -1307,8 +1274,8 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
static int __init inftl_scan_bbt(struct mtd_info *mtd)
{
int ret, numparts;
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
struct mtd_partition parts[5];
if (this->numchips > doc->chips_per_floor) {
@@ -1360,8 +1327,8 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
static inline int __init doc2000_init(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf;
@@ -1376,8 +1343,8 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
static inline int __init doc2001_init(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
this->read_byte = doc2001_read_byte;
this->write_buf = doc2001_writebuf;
@@ -1406,8 +1373,8 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
static inline int __init doc2001plus_init(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf;
@@ -1523,8 +1490,8 @@ static int __init doc_probe(unsigned long physadr)
for (mtd = doclist; mtd; mtd = doc->nextdoc) {
unsigned char oldval;
unsigned char newval;
- nand = mtd->priv;
- doc = nand->priv;
+ nand = mtd_to_nand(mtd);
+ doc = nand_get_controller_data(nand);
/* Use the alias resolution register to determine if this is
in fact the same DOC aliased to a new address. If writes
to one chip's alias resolution register change the value on
@@ -1556,23 +1523,22 @@ static int __init doc_probe(unsigned long physadr)
printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
- len = sizeof(struct mtd_info) +
- sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
- mtd = kzalloc(len, GFP_KERNEL);
- if (!mtd) {
+ len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
+ (2 * sizeof(struct nand_bbt_descr));
+ nand = kzalloc(len, GFP_KERNEL);
+ if (!nand) {
ret = -ENOMEM;
goto fail;
}
- nand = (struct nand_chip *) (mtd + 1);
+ mtd = nand_to_mtd(nand);
doc = (struct doc_priv *) (nand + 1);
nand->bbt_td = (struct nand_bbt_descr *) (doc + 1);
nand->bbt_md = nand->bbt_td + 1;
- mtd->priv = nand;
mtd->owner = THIS_MODULE;
- nand->priv = doc;
+ nand_set_controller_data(nand, doc);
nand->select_chip = doc200x_select_chip;
nand->cmd_ctrl = doc200x_hwcontrol;
nand->dev_ready = doc200x_dev_ready;
@@ -1587,6 +1553,7 @@ static int __init doc_probe(unsigned long physadr)
nand->ecc.size = 512;
nand->ecc.bytes = 6;
nand->ecc.strength = 2;
+ nand->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
nand->bbt_options = NAND_BBT_USE_FLASH;
/* Skip the automatic BBT scan so we can run it manually */
nand->options |= NAND_SKIP_BBTSCAN;
@@ -1615,7 +1582,7 @@ static int __init doc_probe(unsigned long physadr)
haven't yet added it. This is handled without incident by
mtd_device_unregister, as far as I can tell. */
nand_release(mtd);
- kfree(mtd);
+ kfree(nand);
goto fail;
}
@@ -1643,14 +1610,14 @@ static void release_nanddoc(void)
struct doc_priv *doc;
for (mtd = doclist; mtd; mtd = nextmtd) {
- nand = mtd->priv;
- doc = nand->priv;
+ nand = mtd_to_nand(mtd);
+ doc = nand_get_controller_data(nand);
nextmtd = doc->nextdoc;
nand_release(mtd);
iounmap(doc->virtadr);
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
- kfree(mtd);
+ kfree(nand);
}
}
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 408cf69b854b..df4165b02c62 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -242,7 +242,7 @@ static inline void write_nop(void __iomem *docptr)
static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
uint16_t *p = (uint16_t *) buf;
len >>= 1;
@@ -253,7 +253,7 @@ static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
uint16_t *p = (uint16_t *) buf;
len >>= 1;
@@ -297,7 +297,7 @@ static int poll_status(struct docg4_priv *doc)
static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
{
- struct docg4_priv *doc = nand->priv;
+ struct docg4_priv *doc = nand_get_controller_data(nand);
int status = NAND_STATUS_WP; /* inverse logic?? */
dev_dbg(doc->dev, "%s...\n", __func__);
@@ -318,8 +318,8 @@ static void docg4_select_chip(struct mtd_info *mtd, int chip)
* Select among multiple cascaded chips ("floors"). Multiple floors are
* not yet supported, so the only valid non-negative value is 0.
*/
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
@@ -337,8 +337,8 @@ static void reset(struct mtd_info *mtd)
{
/* full device reset */
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
@@ -375,8 +375,8 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
* Up to four bitflips can be corrected.
*/
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
int i, numerrs, errpos[4];
const uint8_t blank_read_hwecc[8] = {
@@ -464,8 +464,8 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
static uint8_t docg4_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
dev_dbg(doc->dev, "%s\n", __func__);
@@ -545,8 +545,8 @@ static int pageprog(struct mtd_info *mtd)
* internal buffer out to the flash array, or some such.
*/
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
int retval = 0;
@@ -582,8 +582,8 @@ static void sequence_reset(struct mtd_info *mtd)
{
/* common starting sequence for all operations */
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
@@ -599,8 +599,8 @@ static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
{
/* first step in reading a page */
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
dev_dbg(doc->dev,
@@ -626,8 +626,8 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
{
/* first step in writing a page */
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
dev_dbg(doc->dev,
@@ -691,8 +691,8 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
{
/* handle standard nand commands */
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
@@ -756,7 +756,7 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
uint8_t *buf, int page, bool use_ecc)
{
- struct docg4_priv *doc = nand->priv;
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
uint16_t status, edc_err, *buf16;
int bits_corrected = 0;
@@ -836,7 +836,7 @@ static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
int page)
{
- struct docg4_priv *doc = nand->priv;
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
uint16_t status;
@@ -874,8 +874,8 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
static int docg4_erase_block(struct mtd_info *mtd, int page)
{
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
uint16_t g4_page;
@@ -923,7 +923,7 @@ static int docg4_erase_block(struct mtd_info *mtd, int page)
static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, bool use_ecc)
{
- struct docg4_priv *doc = nand->priv;
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
uint8_t ecc_buf[8];
@@ -1003,7 +1003,7 @@ static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
*/
/* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
- struct docg4_priv *doc = nand->priv;
+ struct docg4_priv *doc = nand_get_controller_data(nand);
doc->oob_page = page;
memcpy(doc->oob_buf, nand->oob_poi, 16);
return 0;
@@ -1016,8 +1016,8 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
* update the memory-based bbt accordingly.
*/
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
uint8_t *buf;
int i, block;
@@ -1089,8 +1089,8 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
int ret, i;
uint8_t *buf;
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
struct nand_bbt_descr *bbtd = nand->badblock_pattern;
int page = (int)(ofs >> nand->page_shift);
uint32_t g4_addr = mtd_to_docg4_address(page, 0);
@@ -1202,8 +1202,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
* things as well, such as call nand_set_defaults().
*/
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
mtd->size = DOCG4_CHIP_SIZE;
mtd->name = "Msys_Diskonchip_G4";
@@ -1261,8 +1261,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
static int __init read_id_reg(struct mtd_info *mtd)
{
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr;
uint16_t id1, id2;
@@ -1305,17 +1305,16 @@ static int __init probe_docg4(struct platform_device *pdev)
return -EIO;
}
- len = sizeof(struct mtd_info) + sizeof(struct nand_chip) +
- sizeof(struct docg4_priv);
- mtd = kzalloc(len, GFP_KERNEL);
- if (mtd == NULL) {
+ len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
+ nand = kzalloc(len, GFP_KERNEL);
+ if (nand == NULL) {
retval = -ENOMEM;
- goto fail;
+ goto fail_unmap;
}
- nand = (struct nand_chip *) (mtd + 1);
+
+ mtd = nand_to_mtd(nand);
doc = (struct docg4_priv *) (nand + 1);
- mtd->priv = nand;
- nand->priv = doc;
+ nand_set_controller_data(nand, doc);
mtd->dev.parent = &pdev->dev;
doc->virtadr = virtadr;
doc->dev = dev;
@@ -1353,16 +1352,13 @@ static int __init probe_docg4(struct platform_device *pdev)
doc->mtd = mtd;
return 0;
- fail:
+fail:
+ nand_release(mtd); /* deletes partitions and mtd devices */
+ free_bch(doc->bch);
+ kfree(nand);
+
+fail_unmap:
iounmap(virtadr);
- if (mtd) {
- /* re-declarations avoid compiler warning */
- struct nand_chip *nand = mtd->priv;
- struct docg4_priv *doc = nand->priv;
- nand_release(mtd); /* deletes partitions and mtd devices */
- free_bch(doc->bch);
- kfree(mtd);
- }
return retval;
}
@@ -1372,7 +1368,7 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
struct docg4_priv *doc = platform_get_drvdata(pdev);
nand_release(doc->mtd);
free_bch(doc->bch);
- kfree(doc->mtd);
+ kfree(mtd_to_nand(doc->mtd));
iounmap(doc->virtadr);
return 0;
}
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index dcb1f7f4873f..059d5f7ec124 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -48,7 +48,6 @@
/* mtd information per set */
struct fsl_elbc_mtd {
- struct mtd_info mtd;
struct nand_chip chip;
struct fsl_lbc_ctrl *ctrl;
@@ -144,8 +143,8 @@ static struct nand_bbt_descr bbt_mirror_descr = {
*/
static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -195,8 +194,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
*/
static int fsl_elbc_run_command(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -268,7 +267,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
{
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -300,8 +299,8 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -525,8 +524,8 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
*/
static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -563,8 +562,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
*/
static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
/* If there are still bytes in the FCM, then use the next byte. */
@@ -580,8 +579,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
*/
static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int avail;
@@ -605,7 +604,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
*/
static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
if (elbc_fcm_ctrl->status != LTESR_CC)
@@ -619,8 +618,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
unsigned int al;
@@ -697,7 +696,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -742,12 +741,13 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct nand_chip *chip = &priv->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
/* Fill in fsl_elbc_mtd structure */
- priv->mtd.priv = chip;
- priv->mtd.dev.parent = priv->dev;
+ mtd->dev.parent = priv->dev;
+ nand_set_flash_node(chip, priv->dev->of_node);
/* set timeout to maximum */
priv->fmr = 15 << FMR_CWTO_SHIFT;
@@ -770,7 +770,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->controller = &elbc_fcm_ctrl->controller;
- chip->priv = priv;
+ nand_set_controller_data(chip, priv);
chip->ecc.read_page = fsl_elbc_read_page;
chip->ecc.write_page = fsl_elbc_write_page;
@@ -797,9 +797,11 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
{
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
- nand_release(&priv->mtd);
+ struct mtd_info *mtd = nand_to_mtd(&priv->chip);
- kfree(priv->mtd.name);
+ nand_release(mtd);
+
+ kfree(mtd->name);
if (priv->vbase)
iounmap(priv->vbase);
@@ -823,9 +825,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
int bank;
struct device *dev;
struct device_node *node = pdev->dev.of_node;
- struct mtd_part_parser_data ppdata;
+ struct mtd_info *mtd;
- ppdata.of_node = pdev->dev.of_node;
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
return -ENODEV;
lbc = fsl_lbc_ctrl_dev->regs;
@@ -887,8 +888,9 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
goto err;
}
- priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
- if (!priv->mtd.name) {
+ mtd = nand_to_mtd(&priv->chip);
+ mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
+ if (!nand_to_mtd(&priv->chip)->name) {
ret = -ENOMEM;
goto err;
}
@@ -897,21 +899,21 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
if (ret)
goto err;
- ret = nand_scan_ident(&priv->mtd, 1, NULL);
+ ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
goto err;
- ret = fsl_elbc_chip_init_tail(&priv->mtd);
+ ret = fsl_elbc_chip_init_tail(mtd);
if (ret)
goto err;
- ret = nand_scan_tail(&priv->mtd);
+ ret = nand_scan_tail(mtd);
if (ret)
goto err;
/* First look for RedBoot table or partitions on the command
* line, these take precedence over device tree information */
- mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata,
+ mtd_device_parse_register(mtd, part_probe_types, NULL,
NULL, 0);
printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 7f4ac8c19001..43f5a3a4873f 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -40,7 +40,6 @@ struct fsl_ifc_ctrl;
/* mtd information per set */
struct fsl_ifc_mtd {
- struct mtd_info mtd;
struct nand_chip chip;
struct fsl_ifc_ctrl *ctrl;
@@ -230,8 +229,8 @@ static struct nand_bbt_descr bbt_mirror_descr = {
*/
static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
int buf_num;
@@ -253,8 +252,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
u32 __iomem *mainarea = (u32 __iomem *)addr;
u8 __iomem *oob = addr + mtd->writesize;
@@ -292,8 +291,8 @@ static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
*/
static void fsl_ifc_run_command(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
@@ -370,7 +369,7 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
int oob,
struct mtd_info *mtd)
{
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
@@ -409,8 +408,8 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
/* cmdfunc send commands to the IFC NAND Machine */
static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
int column, int page_addr) {
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
@@ -624,8 +623,8 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
*/
static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
unsigned int bufsize = mtd->writesize + mtd->oobsize;
if (len <= 0) {
@@ -650,8 +649,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
*/
static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
unsigned int offset;
/*
@@ -673,8 +672,8 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
*/
static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
uint16_t data;
/*
@@ -696,8 +695,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
*/
static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
int avail;
if (len < 0) {
@@ -722,7 +721,7 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
*/
static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
u32 nand_fsr;
@@ -751,7 +750,7 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
@@ -782,8 +781,8 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
chip->numchips);
@@ -877,12 +876,13 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
struct nand_chip *chip = &priv->chip;
+ struct mtd_info *mtd = nand_to_mtd(&priv->chip);
struct nand_ecclayout *layout;
u32 csor;
/* Fill in fsl_ifc_mtd structure */
- priv->mtd.priv = chip;
- priv->mtd.dev.parent = priv->dev;
+ mtd->dev.parent = priv->dev;
+ nand_set_flash_node(chip, priv->dev->of_node);
/* fill in nand_chip structure */
/* set up function call table */
@@ -914,7 +914,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
}
chip->controller = &ifc_nand_ctrl->controller;
- chip->priv = priv;
+ nand_set_controller_data(chip, priv);
chip->ecc.read_page = fsl_ifc_read_page;
chip->ecc.write_page = fsl_ifc_write_page;
@@ -993,9 +993,11 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
{
- nand_release(&priv->mtd);
+ struct mtd_info *mtd = nand_to_mtd(&priv->chip);
- kfree(priv->mtd.name);
+ nand_release(mtd);
+
+ kfree(mtd->name);
if (priv->vbase)
iounmap(priv->vbase);
@@ -1030,9 +1032,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
int ret;
int bank;
struct device_node *node = dev->dev.of_node;
- struct mtd_part_parser_data ppdata;
+ struct mtd_info *mtd;
- ppdata.of_node = dev->dev.of_node;
if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
return -ENODEV;
ifc = fsl_ifc_ctrl_dev->regs;
@@ -1104,8 +1105,10 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
IFC_NAND_EVTER_INTR_FTOERIR_EN |
IFC_NAND_EVTER_INTR_WPERIR_EN,
&ifc->ifc_nand.nand_evter_intr_en);
- priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
- if (!priv->mtd.name) {
+
+ mtd = nand_to_mtd(&priv->chip);
+ mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
+ if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
@@ -1114,22 +1117,21 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
if (ret)
goto err;
- ret = nand_scan_ident(&priv->mtd, 1, NULL);
+ ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
goto err;
- ret = fsl_ifc_chip_init_tail(&priv->mtd);
+ ret = fsl_ifc_chip_init_tail(mtd);
if (ret)
goto err;
- ret = nand_scan_tail(&priv->mtd);
+ ret = nand_scan_tail(mtd);
if (ret)
goto err;
/* First look for RedBoot table or partitions on the command
* line, these take precedence over device tree information */
- mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata,
- NULL, 0);
+ mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0);
dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
(unsigned long long)res.start, priv->bank);
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index d326369980c4..cafd12de7276 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -31,7 +31,6 @@
struct fsl_upm_nand {
struct device *dev;
- struct mtd_info mtd;
struct nand_chip chip;
int last_ctrl;
struct mtd_partition *parts;
@@ -49,7 +48,8 @@ struct fsl_upm_nand {
static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
{
- return container_of(mtdinfo, struct fsl_upm_nand, mtd);
+ return container_of(mtd_to_nand(mtdinfo), struct fsl_upm_nand,
+ chip);
}
static int fun_chip_ready(struct mtd_info *mtd)
@@ -66,9 +66,10 @@ static int fun_chip_ready(struct mtd_info *mtd)
static void fun_wait_rnb(struct fsl_upm_nand *fun)
{
if (fun->rnb_gpio[fun->mchip_number] >= 0) {
+ struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int cnt = 1000000;
- while (--cnt && !fun_chip_ready(&fun->mtd))
+ while (--cnt && !fun_chip_ready(mtd))
cpu_relax();
if (!cnt)
dev_err(fun->dev, "tired waiting for RNB\n");
@@ -79,7 +80,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
u32 mar;
@@ -109,7 +110,7 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
if (mchip_nr == -1) {
@@ -157,9 +158,9 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
const struct device_node *upm_np,
const struct resource *io_res)
{
+ struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int ret;
struct device_node *flash_np;
- struct mtd_part_parser_data ppdata;
fun->chip.IO_ADDR_R = fun->io_base;
fun->chip.IO_ADDR_W = fun->io_base;
@@ -175,30 +176,29 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
if (fun->rnb_gpio[0] >= 0)
fun->chip.dev_ready = fun_chip_ready;
- fun->mtd.priv = &fun->chip;
- fun->mtd.dev.parent = fun->dev;
+ mtd->dev.parent = fun->dev;
flash_np = of_get_next_child(upm_np, NULL);
if (!flash_np)
return -ENODEV;
- fun->mtd.name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
- flash_np->name);
- if (!fun->mtd.name) {
+ nand_set_flash_node(&fun->chip, flash_np);
+ mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
+ flash_np->name);
+ if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
- ret = nand_scan(&fun->mtd, fun->mchip_count);
+ ret = nand_scan(mtd, fun->mchip_count);
if (ret)
goto err;
- ppdata.of_node = flash_np;
- ret = mtd_device_parse_register(&fun->mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
err:
of_node_put(flash_np);
if (ret)
- kfree(fun->mtd.name);
+ kfree(mtd->name);
return ret;
}
@@ -322,10 +322,11 @@ err1:
static int fun_remove(struct platform_device *ofdev)
{
struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
+ struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int i;
- nand_release(&fun->mtd);
- kfree(fun->mtd.name);
+ nand_release(mtd);
+ kfree(mtd->name);
for (i = 0; i < fun->mchip_count; i++) {
if (fun->rnb_gpio[i] < 0)
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 07af3dc7a4d2..1bdcd4fa26d4 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -299,7 +299,6 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {
*/
struct fsmc_nand_data {
u32 pid;
- struct mtd_info mtd;
struct nand_chip nand;
struct mtd_partition *partitions;
unsigned int nr_partitions;
@@ -326,13 +325,18 @@ struct fsmc_nand_data {
void (*select_chip)(uint32_t bank, uint32_t busw);
};
+static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
+}
+
/* Assert CS signal based on chipnr */
static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct fsmc_nand_data *host;
- host = container_of(mtd, struct fsmc_nand_data, mtd);
+ host = mtd_to_fsmc(mtd);
switch (chipnr) {
case -1:
@@ -358,9 +362,8 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
*/
static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
- struct fsmc_nand_data *host = container_of(mtd,
- struct fsmc_nand_data, mtd);
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
@@ -445,8 +448,7 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
*/
static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct fsmc_nand_data *host = container_of(mtd,
- struct fsmc_nand_data, mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
@@ -466,8 +468,7 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc)
{
- struct fsmc_nand_data *host = container_of(mtd,
- struct fsmc_nand_data, mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
uint32_t ecc_tmp;
@@ -517,8 +518,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc)
{
- struct fsmc_nand_data *host = container_of(mtd,
- struct fsmc_nand_data, mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
uint32_t ecc_tmp;
@@ -629,7 +629,7 @@ unmap_dma:
static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
int i;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
@@ -652,7 +652,7 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
@@ -674,9 +674,8 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
*/
static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct fsmc_nand_data *host;
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
- host = container_of(mtd, struct fsmc_nand_data, mtd);
dma_xfer(host, buf, len, DMA_FROM_DEVICE);
}
@@ -689,9 +688,8 @@ static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
int len)
{
- struct fsmc_nand_data *host;
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
- host = container_of(mtd, struct fsmc_nand_data, mtd);
dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
}
@@ -712,8 +710,7 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct fsmc_nand_data *host = container_of(mtd,
- struct fsmc_nand_data, mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
struct fsmc_eccplace *ecc_place = host->ecc_place;
int i, j, s, stat, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -782,9 +779,8 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc, uint8_t *calc_ecc)
{
- struct fsmc_nand_data *host = container_of(mtd,
- struct fsmc_nand_data, mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
uint32_t err_idx[8];
@@ -926,7 +922,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node __maybe_unused *np = pdev->dev.of_node;
- struct mtd_part_parser_data ppdata = {};
struct fsmc_nand_data *host;
struct mtd_info *mtd;
struct nand_chip *nand;
@@ -1012,12 +1007,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
init_completion(&host->dma_access_complete);
/* Link all private pointers */
- mtd = &host->mtd;
+ mtd = nand_to_mtd(&host->nand);
nand = &host->nand;
- mtd->priv = nand;
- nand->priv = host;
+ nand_set_controller_data(nand, host);
+ nand_set_flash_node(nand, np);
- host->mtd.dev.parent = &pdev->dev;
+ mtd->dev.parent = &pdev->dev;
nand->IO_ADDR_R = host->data_va;
nand->IO_ADDR_W = host->data_va;
nand->cmd_ctrl = fsmc_cmd_ctrl;
@@ -1033,7 +1028,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand->options = pdata->options;
nand->select_chip = fsmc_select_chip;
nand->badblockbits = 7;
- nand->flash_node = np;
+ nand_set_flash_node(nand, np);
if (pdata->width == FSMC_NAND_BW16)
nand->options |= NAND_BUSWIDTH_16;
@@ -1080,14 +1075,14 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Scan to find existence of the device
*/
- if (nand_scan_ident(&host->mtd, 1, NULL)) {
+ if (nand_scan_ident(mtd, 1, NULL)) {
ret = -ENXIO;
dev_err(&pdev->dev, "No NAND Device found!\n");
goto err_scan_ident;
}
if (AMBA_REV_BITS(host->pid) >= 8) {
- switch (host->mtd.oobsize) {
+ switch (mtd->oobsize) {
case 16:
nand->ecc.layout = &fsmc_ecc4_16_layout;
host->ecc_place = &fsmc_ecc4_sp_place;
@@ -1138,7 +1133,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* generated later in nand_bch_init() later.
*/
if (nand->ecc.mode != NAND_ECC_SOFT_BCH) {
- switch (host->mtd.oobsize) {
+ switch (mtd->oobsize) {
case 16:
nand->ecc.layout = &fsmc_ecc1_16_layout;
break;
@@ -1159,7 +1154,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
}
/* Second stage of scan to fill MTD data-structures */
- if (nand_scan_tail(&host->mtd)) {
+ if (nand_scan_tail(mtd)) {
ret = -ENXIO;
goto err_probe;
}
@@ -1174,10 +1169,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Check for partition info passed
*/
- host->mtd.name = "nand";
- ppdata.of_node = np;
- ret = mtd_device_parse_register(&host->mtd, NULL, &ppdata,
- host->partitions, host->nr_partitions);
+ mtd->name = "nand";
+ ret = mtd_device_register(mtd, host->partitions, host->nr_partitions);
if (ret)
goto err_probe;
@@ -1207,7 +1200,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
struct fsmc_nand_data *host = platform_get_drvdata(pdev);
if (host) {
- nand_release(&host->mtd);
+ nand_release(nand_to_mtd(&host->nand));
if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan);
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
index 9ab97f934c37..ded658fc7d73 100644
--- a/drivers/mtd/nand/gpio.c
+++ b/drivers/mtd/nand/gpio.c
@@ -35,12 +35,14 @@
struct gpiomtd {
void __iomem *io_sync;
- struct mtd_info mtd_info;
struct nand_chip nand_chip;
struct gpio_nand_platdata plat;
};
-#define gpio_nand_getpriv(x) container_of(x, struct gpiomtd, mtd_info)
+static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip);
+}
#ifdef CONFIG_ARM
@@ -195,7 +197,7 @@ static int gpio_nand_remove(struct platform_device *pdev)
{
struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
- nand_release(&gpiomtd->mtd_info);
+ nand_release(nand_to_mtd(&gpiomtd->nand_chip));
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
@@ -208,8 +210,8 @@ static int gpio_nand_probe(struct platform_device *pdev)
{
struct gpiomtd *gpiomtd;
struct nand_chip *chip;
+ struct mtd_info *mtd;
struct resource *res;
- struct mtd_part_parser_data ppdata = {};
int ret = 0;
if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
@@ -268,33 +270,31 @@ static int gpio_nand_probe(struct platform_device *pdev)
chip->dev_ready = gpio_nand_devready;
}
+ nand_set_flash_node(chip, pdev->dev.of_node);
chip->IO_ADDR_W = chip->IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT;
chip->options = gpiomtd->plat.options;
chip->chip_delay = gpiomtd->plat.chip_delay;
chip->cmd_ctrl = gpio_nand_cmd_ctrl;
- gpiomtd->mtd_info.priv = chip;
- gpiomtd->mtd_info.dev.parent = &pdev->dev;
+ mtd = nand_to_mtd(chip);
+ mtd->dev.parent = &pdev->dev;
platform_set_drvdata(pdev, gpiomtd);
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
- if (nand_scan(&gpiomtd->mtd_info, 1)) {
+ if (nand_scan(mtd, 1)) {
ret = -ENXIO;
goto err_wp;
}
if (gpiomtd->plat.adjust_parts)
- gpiomtd->plat.adjust_parts(&gpiomtd->plat,
- gpiomtd->mtd_info.size);
+ gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
- ppdata.of_node = pdev->dev.of_node;
- ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
- gpiomtd->plat.parts,
- gpiomtd->plat.num_parts);
+ ret = mtd_device_register(mtd, gpiomtd->plat.parts,
+ gpiomtd->plat.num_parts);
if (!ret)
return 0;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 43fa16b5f510..0f68a99fc4ad 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -919,7 +919,7 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
{
struct resources *r = &this->resources;
struct nand_chip *nand = &this->nand;
- struct mtd_info *mtd = &this->mtd;
+ struct mtd_info *mtd = nand_to_mtd(nand);
uint8_t *feature;
unsigned long rate;
int ret;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 2064adac1d17..235ddcb58f39 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -107,7 +107,7 @@ static irqreturn_t bch_irq(int irq, void *cookie)
static inline int get_ecc_strength(struct gpmi_nand_data *this)
{
struct bch_geometry *geo = &this->bch_geometry;
- struct mtd_info *mtd = &this->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&this->nand);
int ecc_strength;
ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
@@ -139,8 +139,8 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
{
struct bch_geometry *geo = &this->bch_geometry;
- struct mtd_info *mtd = &this->mtd;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = &this->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
unsigned int block_mark_bit_offset;
@@ -257,7 +257,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
static int legacy_set_geometry(struct gpmi_nand_data *this)
{
struct bch_geometry *geo = &this->bch_geometry;
- struct mtd_info *mtd = &this->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&this->nand);
unsigned int metadata_size;
unsigned int status_size;
unsigned int block_mark_bit_offset;
@@ -804,7 +804,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
{
struct bch_geometry *geo = &this->bch_geometry;
struct device *dev = this->dev;
- struct mtd_info *mtd = &this->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&this->nand);
/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
@@ -856,8 +856,8 @@ error_alloc:
static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
/*
@@ -890,16 +890,16 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
static int gpmi_dev_ready(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
return gpmi_is_ready(this, this->current_chip);
}
static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
if ((this->current_chip < 0) && (chipnr >= 0))
gpmi_begin(this);
@@ -911,8 +911,8 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "len is %d\n", len);
this->upper_buf = buf;
@@ -923,8 +923,8 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "len is %d\n", len);
this->upper_buf = (uint8_t *)buf;
@@ -935,8 +935,8 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
static uint8_t gpmi_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
uint8_t *buf = this->data_buffer_dma;
gpmi_read_buf(mtd, buf, 1);
@@ -994,7 +994,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct gpmi_nand_data *this = chip->priv;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
void *payload_virt;
dma_addr_t payload_phys;
@@ -1074,7 +1074,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offs, uint32_t len, uint8_t *buf, int page)
{
- struct gpmi_nand_data *this = chip->priv;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
void __iomem *bch_regs = this->resources.bch_regs;
struct bch_geometry old_geo = this->bch_geometry;
struct bch_geometry *geo = &this->bch_geometry;
@@ -1162,7 +1162,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page)
{
- struct gpmi_nand_data *this = chip->priv;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
const void *payload_virt;
dma_addr_t payload_phys;
@@ -1298,7 +1298,7 @@ exit_auxiliary:
static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct gpmi_nand_data *this = chip->priv;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "page number is %d\n", page);
/* clear the OOB buffer */
@@ -1359,7 +1359,7 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
- struct gpmi_nand_data *this = chip->priv;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
@@ -1448,7 +1448,7 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
const uint8_t *buf,
int oob_required, int page)
{
- struct gpmi_nand_data *this = chip->priv;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
@@ -1538,8 +1538,8 @@ static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *this = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret = 0;
uint8_t *block_mark;
int column, page, status, chipnr;
@@ -1600,8 +1600,8 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
{
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
struct device *dev = this->dev;
- struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int search_area_size_in_strides;
unsigned int stride;
unsigned int page;
@@ -1655,8 +1655,8 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
{
struct device *dev = this->dev;
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
- struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int block_size_in_pages;
unsigned int search_area_size_in_strides;
unsigned int search_area_size_in_pages;
@@ -1735,7 +1735,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
{
struct device *dev = this->dev;
struct nand_chip *chip = &this->nand;
- struct mtd_info *mtd = &this->mtd;
+ struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int block_count;
unsigned int block;
int chipnr;
@@ -1831,14 +1831,13 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
static void gpmi_nand_exit(struct gpmi_nand_data *this)
{
- nand_release(&this->mtd);
+ nand_release(nand_to_mtd(&this->nand));
gpmi_free_dma_buffer(this);
}
static int gpmi_init_last(struct gpmi_nand_data *this)
{
- struct mtd_info *mtd = &this->mtd;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = &this->nand;
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct bch_geometry *bch_geo = &this->bch_geometry;
int ret;
@@ -1886,21 +1885,20 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
static int gpmi_nand_init(struct gpmi_nand_data *this)
{
- struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand;
- struct mtd_part_parser_data ppdata = {};
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
/* init current chip */
this->current_chip = -1;
/* init the MTD data structures */
- mtd->priv = chip;
mtd->name = "gpmi-nand";
mtd->dev.parent = this->dev;
/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
- chip->priv = this;
+ nand_set_controller_data(chip, this);
+ nand_set_flash_node(chip, this->pdev->dev.of_node);
chip->select_chip = gpmi_select_chip;
chip->cmd_ctrl = gpmi_cmd_ctrl;
chip->dev_ready = gpmi_dev_ready;
@@ -1954,8 +1952,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
- ppdata.of_node = this->pdev->dev.of_node;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
if (ret)
goto err_out;
return 0;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index 544062f65020..4e49a1f5fa27 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -160,7 +160,6 @@ struct gpmi_nand_data {
/* MTD / NAND */
struct nand_chip nand;
- struct mtd_info mtd;
/* General-use Variables */
int current_chip;
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 0cb2e886937d..f8d37f36a81c 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -134,7 +134,6 @@
struct hinfc_host {
struct nand_chip chip;
- struct mtd_info mtd;
struct device *dev;
void __iomem *iobase;
void __iomem *mmio;
@@ -189,8 +188,8 @@ static void wait_controller_finished(struct hinfc_host *host)
static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
{
- struct mtd_info *mtd = &host->mtd;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = &host->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
unsigned long val;
int ret;
@@ -262,7 +261,7 @@ static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
{
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
if ((host->addr_value[0] == host->cache_addr_value[0]) &&
(host->addr_value[1] == host->cache_addr_value[1]))
@@ -357,8 +356,8 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
if (chipselect < 0)
return;
@@ -368,8 +367,8 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
if (host->command == NAND_CMD_STATUS)
return *(uint8_t *)(host->mmio);
@@ -384,8 +383,8 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
static u16 hisi_nfc_read_word(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
host->offset += 2;
return *(u16 *)(host->buffer + host->offset - 2);
@@ -394,8 +393,8 @@ static u16 hisi_nfc_read_word(struct mtd_info *mtd)
static void
hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
memcpy(host->buffer + host->offset, buf, len);
host->offset += len;
@@ -403,8 +402,8 @@ hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
memcpy(buf, host->buffer + host->offset, len);
host->offset += len;
@@ -412,8 +411,8 @@ static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void set_addr(struct mtd_info *mtd, int column, int page_addr)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
unsigned int command = host->command;
host->addr_cycle = 0;
@@ -448,8 +447,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
int page_addr)
{
- struct nand_chip *chip = mtd->priv;
- struct hinfc_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct hinfc_host *host = nand_get_controller_data(chip);
int is_cache_invalid = 1;
unsigned int flag = 0;
@@ -543,7 +542,7 @@ static irqreturn_t hinfc_irq_handle(int irq, void *devid)
static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
{
- struct hinfc_host *host = chip->priv;
+ struct hinfc_host *host = nand_get_controller_data(chip);
int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
int stat_1, stat_2;
@@ -575,7 +574,7 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct hinfc_host *host = chip->priv;
+ struct hinfc_host *host = nand_get_controller_data(chip);
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -643,7 +642,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
int size, strength, ecc_bits;
struct device *dev = host->dev;
struct nand_chip *chip = &host->chip;
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct device_node *np = host->dev->of_node;
size = of_get_nand_ecc_step_size(np);
@@ -704,7 +703,6 @@ static int hisi_nfc_probe(struct platform_device *pdev)
struct mtd_info *mtd;
struct resource *res;
struct device_node *np = dev->of_node;
- struct mtd_part_parser_data ppdata;
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host)
@@ -713,7 +711,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
chip = &host->chip;
- mtd = &host->mtd;
+ mtd = nand_to_mtd(chip);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -737,11 +735,11 @@ static int hisi_nfc_probe(struct platform_device *pdev)
goto err_res;
}
- mtd->priv = chip;
mtd->name = "hisi_nand";
mtd->dev.parent = &pdev->dev;
- chip->priv = host;
+ nand_set_controller_data(chip, host);
+ nand_set_flash_node(chip, np);
chip->cmdfunc = hisi_nfc_cmdfunc;
chip->select_chip = hisi_nfc_select_chip;
chip->read_byte = hisi_nfc_read_byte;
@@ -805,8 +803,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
goto err_res;
}
- ppdata.of_node = np;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "Err MTD partition=%d\n", ret);
goto err_mtd;
@@ -823,7 +820,7 @@ err_res:
static int hisi_nfc_remove(struct platform_device *pdev)
{
struct hinfc_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
nand_release(mtd);
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5a99a93ed025..b19d2a9a5eb9 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -59,7 +59,6 @@
#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
struct jz_nand {
- struct mtd_info mtd;
struct nand_chip chip;
void __iomem *base;
struct resource *mem;
@@ -76,13 +75,13 @@ struct jz_nand {
static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
{
- return container_of(mtd, struct jz_nand, mtd);
+ return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
}
static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
{
struct jz_nand *nand = mtd_to_jz_nand(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
uint32_t ctrl;
int banknr;
@@ -104,7 +103,7 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
struct jz_nand *nand = mtd_to_jz_nand(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
uint32_t reg;
void __iomem *bank_base = nand->bank_base[nand->selected_bank];
@@ -225,24 +224,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
uint32_t t;
unsigned int timeout = 1000;
- t = read_ecc[0];
-
- if (t == 0xff) {
- for (i = 1; i < 9; ++i)
- t &= read_ecc[i];
-
- t &= dat[0];
- t &= dat[nand->chip.ecc.size / 2];
- t &= dat[nand->chip.ecc.size - 1];
-
- if (t == 0xff) {
- for (i = 1; i < nand->chip.ecc.size - 1; ++i)
- t &= dat[i];
- if (t == 0xff)
- return 0;
- }
- }
-
for (i = 0; i < 9; ++i)
writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
@@ -255,7 +236,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
} while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
if (timeout == 0)
- return -1;
+ return -ETIMEDOUT;
reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
@@ -263,7 +244,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
if (status & JZ_NAND_STATUS_ERROR) {
if (status & JZ_NAND_STATUS_UNCOR_ERROR)
- return -1;
+ return -EBADMSG;
error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
@@ -334,8 +315,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
char gpio_name[9];
char res_name[6];
uint32_t ctrl;
- struct mtd_info *mtd = &nand->mtd;
struct nand_chip *chip = &nand->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
/* Request GPIO port. */
gpio = JZ_GPIO_MEM_CS0 + bank - 1;
@@ -432,9 +413,8 @@ static int jz_nand_probe(struct platform_device *pdev)
goto err_iounmap_mmio;
}
- mtd = &nand->mtd;
chip = &nand->chip;
- mtd->priv = chip;
+ mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
mtd->name = "jz4740-nand";
@@ -445,6 +425,7 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->ecc.size = 512;
chip->ecc.bytes = 9;
chip->ecc.strength = 4;
+ chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
if (pdata)
chip->ecc.layout = pdata->ecc_layout;
@@ -543,7 +524,7 @@ static int jz_nand_remove(struct platform_device *pdev)
struct jz_nand *nand = platform_get_drvdata(pdev);
size_t i;
- nand_release(&nand->mtd);
+ nand_release(nand_to_mtd(&nand->chip));
/* Deassert and disable all chips */
writel(0, nand->base + JZ_REG_NAND_CTRL);
diff --git a/drivers/mtd/nand/jz4780_bch.c b/drivers/mtd/nand/jz4780_bch.c
new file mode 100644
index 000000000000..755499c6650e
--- /dev/null
+++ b/drivers/mtd/nand/jz4780_bch.c
@@ -0,0 +1,381 @@
+/*
+ * JZ4780 BCH controller
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "jz4780_bch.h"
+
+#define BCH_BHCR 0x0
+#define BCH_BHCCR 0x8
+#define BCH_BHCNT 0xc
+#define BCH_BHDR 0x10
+#define BCH_BHPAR0 0x14
+#define BCH_BHERR0 0x84
+#define BCH_BHINT 0x184
+#define BCH_BHINTES 0x188
+#define BCH_BHINTEC 0x18c
+#define BCH_BHINTE 0x190
+
+#define BCH_BHCR_BSEL_SHIFT 4
+#define BCH_BHCR_BSEL_MASK (0x7f << BCH_BHCR_BSEL_SHIFT)
+#define BCH_BHCR_ENCE BIT(2)
+#define BCH_BHCR_INIT BIT(1)
+#define BCH_BHCR_BCHE BIT(0)
+
+#define BCH_BHCNT_PARITYSIZE_SHIFT 16
+#define BCH_BHCNT_PARITYSIZE_MASK (0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
+#define BCH_BHCNT_BLOCKSIZE_SHIFT 0
+#define BCH_BHCNT_BLOCKSIZE_MASK (0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
+
+#define BCH_BHERR_MASK_SHIFT 16
+#define BCH_BHERR_MASK_MASK (0xffff << BCH_BHERR_MASK_SHIFT)
+#define BCH_BHERR_INDEX_SHIFT 0
+#define BCH_BHERR_INDEX_MASK (0x7ff << BCH_BHERR_INDEX_SHIFT)
+
+#define BCH_BHINT_ERRC_SHIFT 24
+#define BCH_BHINT_ERRC_MASK (0x7f << BCH_BHINT_ERRC_SHIFT)
+#define BCH_BHINT_TERRC_SHIFT 16
+#define BCH_BHINT_TERRC_MASK (0x7f << BCH_BHINT_TERRC_SHIFT)
+#define BCH_BHINT_DECF BIT(3)
+#define BCH_BHINT_ENCF BIT(2)
+#define BCH_BHINT_UNCOR BIT(1)
+#define BCH_BHINT_ERR BIT(0)
+
+#define BCH_CLK_RATE (200 * 1000 * 1000)
+
+/* Timeout for BCH calculation/correction. */
+#define BCH_TIMEOUT_US 100000
+
+struct jz4780_bch {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+ struct mutex lock;
+};
+
+static void jz4780_bch_init(struct jz4780_bch *bch,
+ struct jz4780_bch_params *params, bool encode)
+{
+ u32 reg;
+
+ /* Clear interrupt status. */
+ writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+
+ /* Set up BCH count register. */
+ reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
+ reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
+ writel(reg, bch->base + BCH_BHCNT);
+
+ /* Initialise and enable BCH. */
+ reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
+ reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
+ if (encode)
+ reg |= BCH_BHCR_ENCE;
+ writel(reg, bch->base + BCH_BHCR);
+}
+
+static void jz4780_bch_disable(struct jz4780_bch *bch)
+{
+ writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+ writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
+}
+
+static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
+ size_t size)
+{
+ size_t size32 = size / sizeof(u32);
+ size_t size8 = size % sizeof(u32);
+ const u32 *src32;
+ const u8 *src8;
+
+ src32 = (const u32 *)buf;
+ while (size32--)
+ writel(*src32++, bch->base + BCH_BHDR);
+
+ src8 = (const u8 *)src32;
+ while (size8--)
+ writeb(*src8++, bch->base + BCH_BHDR);
+}
+
+static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
+ size_t size)
+{
+ size_t size32 = size / sizeof(u32);
+ size_t size8 = size % sizeof(u32);
+ u32 *dest32;
+ u8 *dest8;
+ u32 val, offset = 0;
+
+ dest32 = (u32 *)buf;
+ while (size32--) {
+ *dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
+ offset += sizeof(u32);
+ }
+
+ dest8 = (u8 *)dest32;
+ val = readl(bch->base + BCH_BHPAR0 + offset);
+ switch (size8) {
+ case 3:
+ dest8[2] = (val >> 16) & 0xff;
+ case 2:
+ dest8[1] = (val >> 8) & 0xff;
+ case 1:
+ dest8[0] = val & 0xff;
+ break;
+ }
+}
+
+static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
+ u32 *status)
+{
+ u32 reg;
+ int ret;
+
+ /*
+ * While we could use interrupts here and sleep until the operation
+ * completes, the controller works fairly quickly (usually a few
+ * microseconds) and so the overhead of sleeping until we get an
+ * interrupt quite noticeably decreases performance.
+ */
+ ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
+ (reg & irq) == irq, 0, BCH_TIMEOUT_US);
+ if (ret)
+ return false;
+
+ if (status)
+ *status = reg;
+
+ writel(reg, bch->base + BCH_BHINT);
+ return true;
+}
+
+/**
+ * jz4780_bch_calculate() - calculate ECC for a data buffer
+ * @bch: BCH device.
+ * @params: BCH parameters.
+ * @buf: input buffer with raw data.
+ * @ecc_code: output buffer with ECC.
+ *
+ * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
+ * controller.
+ */
+int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
+ const u8 *buf, u8 *ecc_code)
+{
+ int ret = 0;
+
+ mutex_lock(&bch->lock);
+ jz4780_bch_init(bch, params, true);
+ jz4780_bch_write_data(bch, buf, params->size);
+
+ if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
+ jz4780_bch_read_parity(bch, ecc_code, params->bytes);
+ } else {
+ dev_err(bch->dev, "timed out while calculating ECC\n");
+ ret = -ETIMEDOUT;
+ }
+
+ jz4780_bch_disable(bch);
+ mutex_unlock(&bch->lock);
+ return ret;
+}
+EXPORT_SYMBOL(jz4780_bch_calculate);
+
+/**
+ * jz4780_bch_correct() - detect and correct bit errors
+ * @bch: BCH device.
+ * @params: BCH parameters.
+ * @buf: raw data read from the chip.
+ * @ecc_code: ECC read from the chip.
+ *
+ * Given the raw data and the ECC read from the NAND device, detects and
+ * corrects errors in the data.
+ *
+ * Return: the number of bit errors corrected, -EBADMSG if there are too many
+ * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
+ */
+int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
+ u8 *buf, u8 *ecc_code)
+{
+ u32 reg, mask, index;
+ int i, ret, count;
+
+ mutex_lock(&bch->lock);
+
+ jz4780_bch_init(bch, params, false);
+ jz4780_bch_write_data(bch, buf, params->size);
+ jz4780_bch_write_data(bch, ecc_code, params->bytes);
+
+ if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
+ dev_err(bch->dev, "timed out while correcting data\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ if (reg & BCH_BHINT_UNCOR) {
+ dev_warn(bch->dev, "uncorrectable ECC error\n");
+ ret = -EBADMSG;
+ goto out;
+ }
+
+ /* Correct any detected errors. */
+ if (reg & BCH_BHINT_ERR) {
+ count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
+ ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
+
+ for (i = 0; i < count; i++) {
+ reg = readl(bch->base + BCH_BHERR0 + (i * 4));
+ mask = (reg & BCH_BHERR_MASK_MASK) >>
+ BCH_BHERR_MASK_SHIFT;
+ index = (reg & BCH_BHERR_INDEX_MASK) >>
+ BCH_BHERR_INDEX_SHIFT;
+ buf[(index * 2) + 0] ^= mask;
+ buf[(index * 2) + 1] ^= mask >> 8;
+ }
+ } else {
+ ret = 0;
+ }
+
+out:
+ jz4780_bch_disable(bch);
+ mutex_unlock(&bch->lock);
+ return ret;
+}
+EXPORT_SYMBOL(jz4780_bch_correct);
+
+/**
+ * jz4780_bch_get() - get the BCH controller device
+ * @np: BCH device tree node.
+ *
+ * Gets the BCH controller device from the specified device tree node. The
+ * device must be released with jz4780_bch_release() when it is no longer being
+ * used.
+ *
+ * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
+ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+ */
+static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
+{
+ struct platform_device *pdev;
+ struct jz4780_bch *bch;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev || !platform_get_drvdata(pdev))
+ return ERR_PTR(-EPROBE_DEFER);
+
+ get_device(&pdev->dev);
+
+ bch = platform_get_drvdata(pdev);
+ clk_prepare_enable(bch->clk);
+
+ bch->dev = &pdev->dev;
+ return bch;
+}
+
+/**
+ * of_jz4780_bch_get() - get the BCH controller from a DT node
+ * @of_node: the node that contains a bch-controller property.
+ *
+ * Get the bch-controller property from the given device tree
+ * node and pass it to jz4780_bch_get to do the work.
+ *
+ * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
+ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+ */
+struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
+{
+ struct jz4780_bch *bch = NULL;
+ struct device_node *np;
+
+ np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
+
+ if (np) {
+ bch = jz4780_bch_get(np);
+ of_node_put(np);
+ }
+ return bch;
+}
+EXPORT_SYMBOL(of_jz4780_bch_get);
+
+/**
+ * jz4780_bch_release() - release the BCH controller device
+ * @bch: BCH device.
+ */
+void jz4780_bch_release(struct jz4780_bch *bch)
+{
+ clk_disable_unprepare(bch->clk);
+ put_device(bch->dev);
+}
+EXPORT_SYMBOL(jz4780_bch_release);
+
+static int jz4780_bch_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct jz4780_bch *bch;
+ struct resource *res;
+
+ bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
+ if (!bch)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ bch->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(bch->base))
+ return PTR_ERR(bch->base);
+
+ jz4780_bch_disable(bch);
+
+ bch->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(bch->clk)) {
+ dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk));
+ return PTR_ERR(bch->clk);
+ }
+
+ clk_set_rate(bch->clk, BCH_CLK_RATE);
+
+ mutex_init(&bch->lock);
+
+ bch->dev = dev;
+ platform_set_drvdata(pdev, bch);
+
+ return 0;
+}
+
+static const struct of_device_id jz4780_bch_dt_match[] = {
+ { .compatible = "ingenic,jz4780-bch" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
+
+static struct platform_driver jz4780_bch_driver = {
+ .probe = jz4780_bch_probe,
+ .driver = {
+ .name = "jz4780-bch",
+ .of_match_table = of_match_ptr(jz4780_bch_dt_match),
+ },
+};
+module_platform_driver(jz4780_bch_driver);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harvey.hunt@imgtec.com>");
+MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/jz4780_bch.h b/drivers/mtd/nand/jz4780_bch.h
new file mode 100644
index 000000000000..bf4718088a3a
--- /dev/null
+++ b/drivers/mtd/nand/jz4780_bch.h
@@ -0,0 +1,43 @@
+/*
+ * JZ4780 BCH controller
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 __DRIVERS_MTD_NAND_JZ4780_BCH_H__
+#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
+
+#include <linux/types.h>
+
+struct device;
+struct device_node;
+struct jz4780_bch;
+
+/**
+ * struct jz4780_bch_params - BCH parameters
+ * @size: data bytes per ECC step.
+ * @bytes: ECC bytes per step.
+ * @strength: number of correctable bits per ECC step.
+ */
+struct jz4780_bch_params {
+ int size;
+ int bytes;
+ int strength;
+};
+
+int jz4780_bch_calculate(struct jz4780_bch *bch,
+ struct jz4780_bch_params *params,
+ const u8 *buf, u8 *ecc_code);
+int jz4780_bch_correct(struct jz4780_bch *bch,
+ struct jz4780_bch_params *params, u8 *buf,
+ u8 *ecc_code);
+
+void jz4780_bch_release(struct jz4780_bch *bch);
+struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
+
+#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
new file mode 100644
index 000000000000..e1c016c9d32d
--- /dev/null
+++ b/drivers/mtd/nand/jz4780_nand.c
@@ -0,0 +1,428 @@
+/*
+ * JZ4780 NAND driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_mtd.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/jz4780-nemc.h>
+
+#include "jz4780_bch.h"
+
+#define DRV_NAME "jz4780-nand"
+
+#define OFFSET_DATA 0x00000000
+#define OFFSET_CMD 0x00400000
+#define OFFSET_ADDR 0x00800000
+
+/* Command delay when there is no R/B pin. */
+#define RB_DELAY_US 100
+
+struct jz4780_nand_cs {
+ unsigned int bank;
+ void __iomem *base;
+};
+
+struct jz4780_nand_controller {
+ struct device *dev;
+ struct jz4780_bch *bch;
+ struct nand_hw_control controller;
+ unsigned int num_banks;
+ struct list_head chips;
+ int selected;
+ struct jz4780_nand_cs cs[];
+};
+
+struct jz4780_nand_chip {
+ struct nand_chip chip;
+ struct list_head chip_list;
+
+ struct nand_ecclayout ecclayout;
+
+ struct gpio_desc *busy_gpio;
+ struct gpio_desc *wp_gpio;
+ unsigned int reading: 1;
+};
+
+static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
+}
+
+static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
+{
+ return container_of(ctrl, struct jz4780_nand_controller, controller);
+}
+
+static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+ struct jz4780_nand_cs *cs;
+
+ /* Ensure the currently selected chip is deasserted. */
+ if (chipnr == -1 && nfc->selected >= 0) {
+ cs = &nfc->cs[nfc->selected];
+ jz4780_nemc_assert(nfc->dev, cs->bank, false);
+ }
+
+ nfc->selected = chipnr;
+}
+
+static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+ struct jz4780_nand_cs *cs;
+
+ if (WARN_ON(nfc->selected < 0))
+ return;
+
+ cs = &nfc->cs[nfc->selected];
+
+ jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_ALE)
+ writeb(cmd, cs->base + OFFSET_ADDR);
+ else if (ctrl & NAND_CLE)
+ writeb(cmd, cs->base + OFFSET_CMD);
+}
+
+static int jz4780_nand_dev_ready(struct mtd_info *mtd)
+{
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+
+ return !gpiod_get_value_cansleep(nand->busy_gpio);
+}
+
+static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+
+ nand->reading = (mode == NAND_ECC_READ);
+}
+
+static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
+ u8 *ecc_code)
+{
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+ struct jz4780_bch_params params;
+
+ /*
+ * Don't need to generate the ECC when reading, BCH does it for us as
+ * part of decoding/correction.
+ */
+ if (nand->reading)
+ return 0;
+
+ params.size = nand->chip.ecc.size;
+ params.bytes = nand->chip.ecc.bytes;
+ params.strength = nand->chip.ecc.strength;
+
+ return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
+}
+
+static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
+ u8 *read_ecc, u8 *calc_ecc)
+{
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+ struct jz4780_bch_params params;
+
+ params.size = nand->chip.ecc.size;
+ params.bytes = nand->chip.ecc.bytes;
+ params.strength = nand->chip.ecc.strength;
+
+ return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
+}
+
+static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
+{
+ struct nand_chip *chip = &nand->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
+ struct nand_ecclayout *layout = &nand->ecclayout;
+ u32 start, i;
+
+ chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) *
+ (chip->ecc.strength / 8);
+
+ switch (chip->ecc.mode) {
+ case NAND_ECC_HW:
+ if (!nfc->bch) {
+ dev_err(dev, "HW BCH selected, but BCH controller not found\n");
+ return -ENODEV;
+ }
+
+ chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
+ chip->ecc.calculate = jz4780_nand_ecc_calculate;
+ chip->ecc.correct = jz4780_nand_ecc_correct;
+ /* fall through */
+ case NAND_ECC_SOFT:
+ case NAND_ECC_SOFT_BCH:
+ dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
+ (nfc->bch) ? "hardware BCH" : "software ECC",
+ chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+ break;
+ case NAND_ECC_NONE:
+ dev_info(dev, "not using ECC\n");
+ break;
+ default:
+ dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
+ return -EINVAL;
+ }
+
+ /* The NAND core will generate the ECC layout for SW ECC */
+ if (chip->ecc.mode != NAND_ECC_HW)
+ return 0;
+
+ /* Generate ECC layout. ECC codes are right aligned in the OOB area. */
+ layout->eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
+
+ if (layout->eccbytes > mtd->oobsize - 2) {
+ dev_err(dev,
+ "invalid ECC config: required %d ECC bytes, but only %d are available",
+ layout->eccbytes, mtd->oobsize - 2);
+ return -EINVAL;
+ }
+
+ start = mtd->oobsize - layout->eccbytes;
+ for (i = 0; i < layout->eccbytes; i++)
+ layout->eccpos[i] = start + i;
+
+ layout->oobfree[0].offset = 2;
+ layout->oobfree[0].length = mtd->oobsize - layout->eccbytes - 2;
+
+ chip->ecc.layout = layout;
+ return 0;
+}
+
+static int jz4780_nand_init_chip(struct platform_device *pdev,
+ struct jz4780_nand_controller *nfc,
+ struct device_node *np,
+ unsigned int chipnr)
+{
+ struct device *dev = &pdev->dev;
+ struct jz4780_nand_chip *nand;
+ struct jz4780_nand_cs *cs;
+ struct resource *res;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ const __be32 *reg;
+ int ret = 0;
+
+ cs = &nfc->cs[chipnr];
+
+ reg = of_get_property(np, "reg", NULL);
+ if (!reg)
+ return -EINVAL;
+
+ cs->bank = be32_to_cpu(*reg);
+
+ jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
+ cs->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(cs->base))
+ return PTR_ERR(cs->base);
+
+ nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
+ if (!nand)
+ return -ENOMEM;
+
+ nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
+
+ if (IS_ERR(nand->busy_gpio)) {
+ ret = PTR_ERR(nand->busy_gpio);
+ dev_err(dev, "failed to request busy GPIO: %d\n", ret);
+ return ret;
+ } else if (nand->busy_gpio) {
+ nand->chip.dev_ready = jz4780_nand_dev_ready;
+ }
+
+ nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
+
+ if (IS_ERR(nand->wp_gpio)) {
+ ret = PTR_ERR(nand->wp_gpio);
+ dev_err(dev, "failed to request WP GPIO: %d\n", ret);
+ return ret;
+ }
+
+ chip = &nand->chip;
+ mtd = nand_to_mtd(chip);
+ mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
+ cs->bank);
+ if (!mtd->name)
+ return -ENOMEM;
+ mtd->dev.parent = dev;
+
+ chip->IO_ADDR_R = cs->base + OFFSET_DATA;
+ chip->IO_ADDR_W = cs->base + OFFSET_DATA;
+ chip->chip_delay = RB_DELAY_US;
+ chip->options = NAND_NO_SUBPAGE_WRITE;
+ chip->select_chip = jz4780_nand_select_chip;
+ chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->controller = &nfc->controller;
+ nand_set_flash_node(chip, np);
+
+ ret = nand_scan_ident(mtd, 1, NULL);
+ if (ret)
+ return ret;
+
+ ret = jz4780_nand_init_ecc(nand, dev);
+ if (ret)
+ return ret;
+
+ ret = nand_scan_tail(mtd);
+ if (ret)
+ return ret;
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ nand_release(mtd);
+ return ret;
+ }
+
+ list_add_tail(&nand->chip_list, &nfc->chips);
+
+ return 0;
+}
+
+static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
+{
+ struct jz4780_nand_chip *chip;
+
+ while (!list_empty(&nfc->chips)) {
+ chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
+ nand_release(nand_to_mtd(&chip->chip));
+ list_del(&chip->chip_list);
+ }
+}
+
+static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np;
+ int i = 0;
+ int ret;
+ int num_chips = of_get_child_count(dev->of_node);
+
+ if (num_chips > nfc->num_banks) {
+ dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks);
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(dev->of_node, np) {
+ ret = jz4780_nand_init_chip(pdev, nfc, np, i);
+ if (ret) {
+ jz4780_nand_cleanup_chips(nfc);
+ return ret;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+static int jz4780_nand_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ unsigned int num_banks;
+ struct jz4780_nand_controller *nfc;
+ int ret;
+
+ num_banks = jz4780_nemc_num_banks(dev);
+ if (num_banks == 0) {
+ dev_err(dev, "no banks found\n");
+ return -ENODEV;
+ }
+
+ nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
+ if (!nfc)
+ return -ENOMEM;
+
+ /*
+ * Check for BCH HW before we call nand_scan_ident, to prevent us from
+ * having to call it again if the BCH driver returns -EPROBE_DEFER.
+ */
+ nfc->bch = of_jz4780_bch_get(dev->of_node);
+ if (IS_ERR(nfc->bch))
+ return PTR_ERR(nfc->bch);
+
+ nfc->dev = dev;
+ nfc->num_banks = num_banks;
+
+ spin_lock_init(&nfc->controller.lock);
+ INIT_LIST_HEAD(&nfc->chips);
+ init_waitqueue_head(&nfc->controller.wq);
+
+ ret = jz4780_nand_init_chips(nfc, pdev);
+ if (ret) {
+ if (nfc->bch)
+ jz4780_bch_release(nfc->bch);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, nfc);
+ return 0;
+}
+
+static int jz4780_nand_remove(struct platform_device *pdev)
+{
+ struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev);
+
+ if (nfc->bch)
+ jz4780_bch_release(nfc->bch);
+
+ jz4780_nand_cleanup_chips(nfc);
+
+ return 0;
+}
+
+static const struct of_device_id jz4780_nand_dt_match[] = {
+ { .compatible = "ingenic,jz4780-nand" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match);
+
+static struct platform_driver jz4780_nand_driver = {
+ .probe = jz4780_nand_probe,
+ .remove = jz4780_nand_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(jz4780_nand_dt_match),
+ },
+};
+module_platform_driver(jz4780_nand_driver);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harvey.hunt@imgtec.com>");
+MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 347510978484..9bc435d72a86 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -173,7 +173,6 @@ struct lpc32xx_nand_host {
struct nand_chip nand_chip;
struct lpc32xx_mlc_platform_data *pdata;
struct clk *clk;
- struct mtd_info mtd;
void __iomem *io_base;
int irq;
struct lpc32xx_nand_cfg_mlc *ncfg;
@@ -275,8 +274,8 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct lpc32xx_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
@@ -291,8 +290,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
*/
static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct lpc32xx_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
if ((readb(MLC_ISR(host->io_base)) &
(MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
@@ -318,7 +317,7 @@ static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
goto exit;
@@ -338,7 +337,7 @@ exit:
static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
struct nand_chip *chip)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
goto exit;
@@ -389,8 +388,8 @@ static void lpc32xx_dma_complete_func(void *completion)
static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len,
enum dma_transfer_direction dir)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct dma_async_tx_descriptor *desc;
int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
int res;
@@ -431,7 +430,7 @@ out1:
static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int i, j;
uint8_t *oobbuf = chip->oob_poi;
uint32_t mlc_isr;
@@ -498,7 +497,7 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
const uint8_t *buf, int oob_required,
int page)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
const uint8_t *oobbuf = chip->oob_poi;
uint8_t *dma_buf = (uint8_t *)buf;
int res;
@@ -543,7 +542,7 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Read whole page - necessary with MLC controller! */
lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
@@ -566,7 +565,7 @@ static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
{
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
dma_cap_mask_t mask;
if (!host->pdata || !host->pdata->dma_filter) {
@@ -647,7 +646,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
struct nand_chip *nand_chip;
struct resource *rc;
int res;
- struct mtd_part_parser_data ppdata = {};
/* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
@@ -661,8 +659,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
host->io_base_phy = rc->start;
- mtd = &host->mtd;
nand_chip = &host->nand_chip;
+ mtd = nand_to_mtd(nand_chip);
if (pdev->dev.of_node)
host->ncfg = lpc32xx_parse_dt(&pdev->dev);
if (!host->ncfg) {
@@ -681,8 +679,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
host->pdata = dev_get_platdata(&pdev->dev);
- nand_chip->priv = host; /* link the private data structures */
- mtd->priv = nand_chip;
+ /* link the private data structures */
+ nand_set_controller_data(nand_chip, host);
+ nand_set_flash_node(nand_chip, pdev->dev.of_node);
mtd->dev.parent = &pdev->dev;
/* Get NAND clock */
@@ -786,9 +785,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
mtd->name = DRV_NAME;
- ppdata.of_node = pdev->dev.of_node;
- res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
- host->ncfg->num_parts);
+ res = mtd_device_register(mtd, host->ncfg->parts,
+ host->ncfg->num_parts);
if (!res)
return res;
@@ -815,7 +813,7 @@ err_exit1:
static int lpc32xx_nand_remove(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
nand_release(mtd);
free_irq(host->irq, host);
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 4f3d4eb17da0..3b8f3735f3e8 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -204,7 +204,6 @@ struct lpc32xx_nand_host {
struct nand_chip nand_chip;
struct lpc32xx_slc_platform_data *pdata;
struct clk *clk;
- struct mtd_info mtd;
void __iomem *io_base;
struct lpc32xx_nand_cfg_slc *ncfg;
@@ -260,8 +259,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
uint32_t tmp;
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Does CE state need to be changed? */
tmp = readl(SLC_CFG(host->io_base));
@@ -284,8 +283,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
*/
static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int rdy = 0;
if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
@@ -339,8 +338,8 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
*/
static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
return (uint8_t)readl(SLC_DATA(host->io_base));
}
@@ -350,8 +349,8 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
*/
static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Direct device read with no ECC */
while (len-- > 0)
@@ -363,8 +362,8 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
*/
static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Direct device write with no ECC */
while (len-- > 0)
@@ -428,8 +427,8 @@ static void lpc32xx_dma_complete_func(void *completion)
static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
void *mem, int len, enum dma_transfer_direction dir)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct dma_async_tx_descriptor *desc;
int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
int res;
@@ -488,8 +487,8 @@ out1:
static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
int read)
{
- struct nand_chip *chip = mtd->priv;
- struct lpc32xx_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int i, status = 0;
unsigned long timeout;
int res;
@@ -604,7 +603,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int stat, i, status;
uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
@@ -666,7 +665,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
const uint8_t *buf,
int oob_required, int page)
{
- struct lpc32xx_nand_host *host = chip->priv;
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
int error;
@@ -703,7 +702,7 @@ static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
{
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
dma_cap_mask_t mask;
if (!host->pdata || !host->pdata->dma_filter) {
@@ -763,7 +762,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
struct mtd_info *mtd;
struct nand_chip *chip;
struct resource *rc;
- struct mtd_part_parser_data ppdata = {};
int res;
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -800,10 +798,10 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
host->pdata = dev_get_platdata(&pdev->dev);
- mtd = &host->mtd;
chip = &host->nand_chip;
- chip->priv = host;
- mtd->priv = chip;
+ mtd = nand_to_mtd(chip);
+ nand_set_controller_data(chip, host);
+ nand_set_flash_node(chip, pdev->dev.of_node);
mtd->owner = THIS_MODULE;
mtd->dev.parent = &pdev->dev;
@@ -908,9 +906,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
mtd->name = "nxp_lpc3220_slc";
- ppdata.of_node = pdev->dev.of_node;
- res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
- host->ncfg->num_parts);
+ res = mtd_device_register(mtd, host->ncfg->parts,
+ host->ncfg->num_parts);
if (!res)
return res;
@@ -933,7 +930,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
{
uint32_t tmp;
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
nand_release(mtd);
dma_release_channel(host->dma_chan);
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index d6bbde4a5331..6b93e899d4e9 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -118,7 +118,6 @@
#define NFC_TIMEOUT (HZ / 10) /* 1/10 s */
struct mpc5121_nfc_prv {
- struct mtd_info mtd;
struct nand_chip chip;
int irq;
void __iomem *regs;
@@ -135,8 +134,8 @@ static void mpc5121_nfc_done(struct mtd_info *mtd);
/* Read NFC register */
static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
return in_be16(prv->regs + reg);
}
@@ -144,8 +143,8 @@ static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
/* Write NFC register */
static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
out_be16(prv->regs + reg, val);
}
@@ -214,8 +213,8 @@ static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
{
struct mtd_info *mtd = data;
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
wake_up(&prv->irq_waitq);
@@ -226,8 +225,8 @@ static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
/* Wait for operation complete */
static void mpc5121_nfc_done(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
int rv;
if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
@@ -246,7 +245,7 @@ static void mpc5121_nfc_done(struct mtd_info *mtd)
/* Do address cycle(s) */
static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
u32 pagemask = chip->pagemask;
if (column != -1) {
@@ -281,8 +280,8 @@ static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
/* Init external chip select logic on ADS5121 board */
static int ads5121_chipselect_init(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
struct device_node *dn;
dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
@@ -303,8 +302,8 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
/* Control chips select signal on ADS5121 board */
static void ads5121_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *nand = mtd->priv;
- struct mpc5121_nfc_prv *prv = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
u8 v;
v = in_8(prv->csreg);
@@ -333,8 +332,8 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
int column, int page)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
prv->column = (column >= 0) ? column : 0;
prv->spareonly = 0;
@@ -406,8 +405,8 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
u8 *buffer, uint size, int wr)
{
- struct nand_chip *nand = mtd->priv;
- struct mpc5121_nfc_prv *prv = nand->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
uint o, s, sbsize, blksize;
/*
@@ -458,8 +457,8 @@ static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
int wr)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
uint c = prv->column;
uint l;
@@ -536,8 +535,8 @@ static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
*/
static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
struct mpc512x_reset_module *rm;
struct device_node *rmnode;
uint rcw_pagesize = 0;
@@ -615,8 +614,8 @@ out:
/* Free driver resources */
static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct mpc5121_nfc_prv *prv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
if (prv->clk)
clk_disable_unprepare(prv->clk);
@@ -639,7 +638,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
int resettime = 0;
int retval = 0;
int rev, len;
- struct mtd_part_parser_data ppdata;
/*
* Check SoC revision. This driver supports only NFC
@@ -655,12 +653,12 @@ static int mpc5121_nfc_probe(struct platform_device *op)
if (!prv)
return -ENOMEM;
- mtd = &prv->mtd;
chip = &prv->chip;
+ mtd = nand_to_mtd(chip);
- mtd->priv = chip;
mtd->dev.parent = dev;
- chip->priv = prv;
+ nand_set_controller_data(chip, prv);
+ nand_set_flash_node(chip, dn);
prv->dev = dev;
/* Read NFC configuration from Reset Config Word */
@@ -703,7 +701,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
mtd->name = "MPC5121 NAND";
- ppdata.of_node = dn;
chip->dev_ready = mpc5121_nfc_dev_ready;
chip->cmdfunc = mpc5121_nfc_command;
chip->read_byte = mpc5121_nfc_read_byte;
@@ -815,7 +812,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
dev_set_drvdata(dev, mtd);
/* Register device in MTD */
- retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ retval = mtd_device_register(mtd, NULL, 0);
if (retval) {
dev_err(dev, "Error adding MTD device!\n");
goto error;
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 136e73a3e07e..854c832597aa 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -173,7 +173,6 @@ struct mxc_nand_devtype_data {
};
struct mxc_nand_host {
- struct mtd_info mtd;
struct nand_chip nand;
struct device *dev;
@@ -532,8 +531,8 @@ static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islas
static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint32_t tmp;
tmp = readl(NFC_V3_CONFIG1);
@@ -548,8 +547,8 @@ static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
/* NANDFC buffer 0 is used for page read/write */
writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
@@ -562,8 +561,8 @@ static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int bufs, i;
if (mtd->writesize > 512)
@@ -663,8 +662,8 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
/*
* 1-Bit errors are automatically corrected in HW. No need for
@@ -675,7 +674,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
- return -1;
+ return -EBADMSG;
}
return 0;
@@ -684,8 +683,8 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u32 ecc_stat, err;
int no_subpages = 1;
int ret = 0;
@@ -702,7 +701,7 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
err = ecc_stat & ecc_bit_mask;
if (err > err_limit) {
printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
- return -1;
+ return -EBADMSG;
} else {
ret += err;
}
@@ -722,8 +721,8 @@ static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
static u_char mxc_nand_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint8_t ret;
/* Check for status request */
@@ -746,8 +745,8 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint16_t ret;
ret = *(uint16_t *)(host->data_buf + host->buf_start);
@@ -762,8 +761,8 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
static void mxc_nand_write_buf(struct mtd_info *mtd,
const u_char *buf, int len)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u16 col = host->buf_start;
int n = mtd->oobsize + mtd->writesize - col;
@@ -780,8 +779,8 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
*/
static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u16 col = host->buf_start;
int n = mtd->oobsize + mtd->writesize - col;
@@ -796,8 +795,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
* deselect of the NAND chip */
static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1) {
/* Disable the NFC clock */
@@ -817,8 +816,8 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1) {
/* Disable the NFC clock */
@@ -850,8 +849,8 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
*/
static void copy_spare(struct mtd_info *mtd, bool bfrom)
{
- struct nand_chip *this = mtd->priv;
- struct mxc_nand_host *host = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(this);
u16 i, oob_chunk_size;
u16 num_chunks = mtd->writesize / 512;
@@ -893,8 +892,8 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom)
*/
static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
/* Write out column address, if necessary */
if (column != -1) {
@@ -979,8 +978,8 @@ static void ecc_8bit_layout_4k(struct nand_ecclayout *layout)
static void preset_v1(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint16_t config1 = 0;
if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
@@ -1007,8 +1006,8 @@ static void preset_v1(struct mtd_info *mtd)
static void preset_v2(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint16_t config1 = 0;
config1 |= NFC_V2_CONFIG1_FP_INT;
@@ -1053,8 +1052,8 @@ static void preset_v2(struct mtd_info *mtd)
static void preset_v3(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct mxc_nand_host *host = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
uint32_t config2, config3;
int i, addr_phases;
@@ -1067,8 +1066,7 @@ static void preset_v3(struct mtd_info *mtd)
/* Blocks to be unlocked */
for (i = 0; i < NAND_MAX_CHIPS; i++)
- writel(0x0 | (0xffff << 16),
- NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
+ writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
writel(0, NFC_V3_IPC);
@@ -1125,8 +1123,8 @@ static void preset_v3(struct mtd_info *mtd)
static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
int column, int page_addr)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct mxc_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
command, column, page_addr);
@@ -1515,15 +1513,15 @@ static int mxcnd_probe(struct platform_device *pdev)
host->dev = &pdev->dev;
/* structures must be linked */
this = &host->nand;
- mtd = &host->mtd;
- mtd->priv = this;
+ mtd = nand_to_mtd(this);
mtd->dev.parent = &pdev->dev;
mtd->name = DRIVER_NAME;
/* 50 us command delay time */
this->chip_delay = 5;
- this->priv = host;
+ nand_set_controller_data(this, host);
+ nand_set_flash_node(this, pdev->dev.of_node),
this->dev_ready = mxc_nand_dev_ready;
this->cmdfunc = mxc_nand_command;
this->read_byte = mxc_nand_read_byte;
@@ -1683,9 +1681,7 @@ static int mxcnd_probe(struct platform_device *pdev)
/* Register the partitions */
mtd_device_parse_register(mtd, part_probes,
- &(struct mtd_part_parser_data){
- .of_node = pdev->dev.of_node,
- },
+ NULL,
host->pdata.parts,
host->pdata.nr_parts);
@@ -1704,7 +1700,7 @@ static int mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
- nand_release(&host->mtd);
+ nand_release(nand_to_mtd(&host->nand));
if (host->clk_act)
clk_disable_unprepare(host->clk);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ece544efccc3..f2c8ff398d6c 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -106,7 +106,7 @@ DEFINE_LED_TRIGGER(nand_led_trigger);
static int check_offs_len(struct mtd_info *mtd,
loff_t ofs, uint64_t len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret = 0;
/* Start address must align on block boundary */
@@ -132,7 +132,7 @@ static int check_offs_len(struct mtd_info *mtd,
*/
static void nand_release_device(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
/* Release the controller and the chip */
spin_lock(&chip->controller->lock);
@@ -150,7 +150,7 @@ static void nand_release_device(struct mtd_info *mtd)
*/
static uint8_t nand_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
return readb(chip->IO_ADDR_R);
}
@@ -163,7 +163,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
*/
static uint8_t nand_read_byte16(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
}
@@ -175,7 +175,7 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)
*/
static u16 nand_read_word(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
return readw(chip->IO_ADDR_R);
}
@@ -188,7 +188,7 @@ static u16 nand_read_word(struct mtd_info *mtd)
*/
static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
switch (chipnr) {
case -1:
@@ -211,7 +211,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
*/
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
chip->write_buf(mtd, &byte, 1);
}
@@ -225,7 +225,7 @@ static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
*/
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
uint16_t word = byte;
/*
@@ -257,7 +257,7 @@ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
*/
static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
iowrite8_rep(chip->IO_ADDR_W, buf, len);
}
@@ -272,7 +272,7 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
*/
static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
ioread8_rep(chip->IO_ADDR_R, buf, len);
}
@@ -287,7 +287,7 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
*/
static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
u16 *p = (u16 *) buf;
iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
@@ -303,7 +303,7 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
*/
static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
u16 *p = (u16 *) buf;
ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
@@ -320,7 +320,7 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
{
int page, chipnr, res = 0, i = 0;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
u16 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
@@ -380,7 +380,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
*/
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct mtd_oob_ops ops;
uint8_t buf[2] = { 0, 0 };
int ret = 0, res, i = 0;
@@ -430,7 +430,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
*/
static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int res, ret = 0;
if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
@@ -471,7 +471,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
*/
static int nand_check_wp(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
/* Broken xD cards report WP despite being writable */
if (chip->options & NAND_BROKEN_XD)
@@ -491,7 +491,7 @@ static int nand_check_wp(struct mtd_info *mtd)
*/
static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (!chip->bbt)
return 0;
@@ -512,7 +512,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
int allowbbt)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (!chip->bbt)
return chip->block_bad(mtd, ofs, getchip);
@@ -531,7 +531,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
*/
static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int i;
/* Wait for the device to get ready */
@@ -551,7 +551,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
*/
void nand_wait_ready(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
unsigned long timeo = 400;
if (in_interrupt() || oops_in_progress)
@@ -582,7 +582,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
*/
static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
{
- register struct nand_chip *chip = mtd->priv;
+ register struct nand_chip *chip = mtd_to_nand(mtd);
timeo = jiffies + msecs_to_jiffies(timeo);
do {
@@ -605,7 +605,7 @@ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
static void nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
- register struct nand_chip *chip = mtd->priv;
+ register struct nand_chip *chip = mtd_to_nand(mtd);
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
/* Write out the command to the device */
@@ -708,7 +708,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
- register struct nand_chip *chip = mtd->priv;
+ register struct nand_chip *chip = mtd_to_nand(mtd);
/* Emulate NAND_CMD_READOOB */
if (command == NAND_CMD_READOOB) {
@@ -832,7 +832,7 @@ static void panic_nand_get_device(struct nand_chip *chip,
static int
nand_get_device(struct mtd_info *mtd, int new_state)
{
- struct nand_chip *chip = mtd->priv;
+ 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);
@@ -952,7 +952,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
{
int ret = 0;
int status, page;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
/* Submit address of first page to unlock */
page = ofs >> chip->page_shift;
@@ -987,7 +987,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret = 0;
int chipnr;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
pr_debug("%s: start = 0x%012llx, len = %llu\n",
__func__, (unsigned long long)ofs, len);
@@ -1050,7 +1050,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret = 0;
int chipnr, status, page;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
pr_debug("%s: start = 0x%012llx, len = %llu\n",
__func__, (unsigned long long)ofs, len);
@@ -1426,6 +1426,16 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
stat = chip->ecc.correct(mtd, p,
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
+ if (stat == -EBADMSG &&
+ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+ /* check for empty pages with bitflips */
+ stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
+ &chip->buffers->ecccode[i],
+ chip->ecc.bytes,
+ NULL, 0,
+ chip->ecc.strength);
+ }
+
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -1475,6 +1485,15 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat == -EBADMSG &&
+ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+ /* check for empty pages with bitflips */
+ stat = nand_check_erased_ecc_chunk(p, eccsize,
+ &ecc_code[i], eccbytes,
+ NULL, 0,
+ chip->ecc.strength);
+ }
+
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -1527,6 +1546,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+ if (stat == -EBADMSG &&
+ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+ /* check for empty pages with bitflips */
+ stat = nand_check_erased_ecc_chunk(p, eccsize,
+ &ecc_code[i], eccbytes,
+ NULL, 0,
+ chip->ecc.strength);
+ }
+
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -1554,6 +1582,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
+ int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
unsigned int max_bitflips = 0;
@@ -1573,19 +1602,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, oob, eccbytes);
stat = chip->ecc.correct(mtd, p, oob, NULL);
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- mtd->ecc_stats.corrected += stat;
- max_bitflips = max_t(unsigned int, max_bitflips, stat);
- }
-
oob += eccbytes;
if (chip->ecc.postpad) {
chip->read_buf(mtd, oob, chip->ecc.postpad);
oob += chip->ecc.postpad;
}
+
+ if (stat == -EBADMSG &&
+ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+ /* check for empty pages with bitflips */
+ stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
+ oob - eccpadbytes,
+ eccpadbytes,
+ NULL, 0,
+ chip->ecc.strength);
+ }
+
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+ mtd->ecc_stats.corrected += stat;
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ }
}
/* Calculate remaining oob bytes */
@@ -1655,7 +1694,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
*/
static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
pr_debug("setting READ RETRY mode %d\n", retry_mode);
@@ -1680,7 +1719,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
int chipnr, page, realpage, col, bytes, aligned, oob_required;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret = 0;
uint32_t readlen = ops->len;
uint32_t oobreadlen = ops->ooblen;
@@ -2024,7 +2063,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
int page, realpage, chipnr;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct mtd_ecc_stats stats;
int readlen = ops->ooblen;
int len;
@@ -2472,7 +2511,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
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->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
/*
* Initialise to all 0xFF, to avoid the possibility of left over OOB
@@ -2532,7 +2571,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
int chipnr, realpage, page, blockmask, column;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
uint32_t writelen = ops->len;
uint32_t oobwritelen = ops->ooblen;
@@ -2662,7 +2701,7 @@ err_out:
static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct mtd_oob_ops ops;
int ret;
@@ -2722,7 +2761,7 @@ 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->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen);
@@ -2847,7 +2886,7 @@ out:
*/
static int single_erase(struct mtd_info *mtd, int page)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
/* Send commands to erase a block */
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
@@ -2879,7 +2918,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt)
{
int page, status, pages_per_block, ret, chipnr;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
@@ -3094,7 +3133,7 @@ static int nand_suspend(struct mtd_info *mtd)
*/
static void nand_resume(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (chip->state == FL_PM_SUSPENDED)
nand_release_device(mtd);
@@ -3266,7 +3305,7 @@ ext_out:
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
@@ -3937,11 +3976,14 @@ ident_done:
return type;
}
-static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
- struct device_node *dn)
+static int nand_dt_init(struct nand_chip *chip)
{
+ struct device_node *dn = nand_get_flash_node(chip);
int ecc_mode, ecc_strength, ecc_step;
+ if (!dn)
+ return 0;
+
if (of_get_nand_bus_width(dn) == 16)
chip->options |= NAND_BUSWIDTH_16;
@@ -3985,15 +4027,16 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *table)
{
int i, nand_maf_id, nand_dev_id;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_flash_dev *type;
int ret;
- if (chip->flash_node) {
- ret = nand_dt_init(mtd, chip, chip->flash_node);
- if (ret)
- return ret;
- }
+ ret = nand_dt_init(chip);
+ if (ret)
+ return ret;
+
+ if (!mtd->name && mtd->dev.parent)
+ mtd->name = dev_name(mtd->dev.parent);
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
@@ -4053,7 +4096,7 @@ EXPORT_SYMBOL(nand_scan_ident);
*/
static bool nand_ecc_strength_good(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int corr, ds_corr;
@@ -4082,7 +4125,7 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
int nand_scan_tail(struct mtd_info *mtd)
{
int i;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct nand_buffers *nbuf;
@@ -4166,7 +4209,7 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc->write_oob = nand_write_oob_std;
if (!ecc->read_subpage)
ecc->read_subpage = nand_read_subpage;
- if (!ecc->write_subpage)
+ if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
ecc->write_subpage = nand_write_subpage_hwecc;
case NAND_ECC_HW_SYNDROME:
@@ -4426,7 +4469,7 @@ EXPORT_SYMBOL(nand_scan);
*/
void nand_release(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index b1d4f813aedc..4b6a7085b442 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -172,7 +172,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
struct nand_bbt_descr *td, int offs)
{
int res, ret = 0, i, j, act = 0;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
size_t retlen, len, totlen;
loff_t from;
int bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -263,7 +263,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
*/
static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int res = 0, i;
if (td->options & NAND_BBT_PERCHIP) {
@@ -388,7 +388,7 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
@@ -454,7 +454,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *bd, int chip)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int i, numblocks, numpages;
int startblock;
loff_t from;
@@ -523,7 +523,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
*/
static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int i, chips;
int startblock, block, dir;
int scanlen = mtd->writesize + mtd->oobsize;
@@ -618,7 +618,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
int chipsel)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
struct erase_info einfo;
int i, res, chip = 0;
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
@@ -819,7 +819,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
*/
static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
return create_bbt(mtd, this->buffers->databuf, bd, -1);
}
@@ -838,7 +838,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
{
int i, chips, writeops, create, chipsel, res, res2;
- struct nand_chip *this = mtd->priv;
+ 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;
@@ -962,7 +962,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
*/
static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int i, j, chips, block, nrblocks, update;
uint8_t oldval;
@@ -1022,7 +1022,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
*/
static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
u32 pattern_len;
u32 bits;
u32 table_size;
@@ -1074,7 +1074,7 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
*/
static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int len, res;
uint8_t *buf;
struct nand_bbt_descr *td = this->bbt_td;
@@ -1147,7 +1147,7 @@ err:
*/
static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int len, res = 0;
int chip, chipsel;
uint8_t *buf;
@@ -1281,7 +1281,7 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
*/
int nand_default_bbt(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int ret;
/* Is a flash based bad block table requested? */
@@ -1317,7 +1317,7 @@ int nand_default_bbt(struct mtd_info *mtd)
*/
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int block;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1332,7 +1332,7 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
*/
int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int block, res;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1359,7 +1359,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
*/
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
int block, ret = 0;
block = (int)(offs >> this->bbt_erase_shift);
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 3803e0bba23b..a87c1b628dfc 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -52,7 +52,7 @@ struct nand_bch_control {
int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
unsigned char *code)
{
- const struct nand_chip *chip = mtd->priv;
+ const struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int i;
@@ -79,7 +79,7 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- const struct nand_chip *chip = mtd->priv;
+ const struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int *errloc = nbc->errloc;
int i, count;
@@ -98,7 +98,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
}
} else if (count < 0) {
printk(KERN_ERR "ecc unrecoverable error\n");
- count = -1;
+ count = -EBADMSG;
}
return count;
}
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index 97c4c0216c90..d1770b066396 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -424,7 +424,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
unsigned char *code)
{
__nand_calculate_ecc(buf,
- ((struct nand_chip *)mtd->priv)->ecc.size, code);
+ mtd_to_nand(mtd)->ecc.size, code);
return 0;
}
@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf,
return 1; /* error in ECC data; no action needed */
pr_err("%s: uncorrectable ECC error\n", __func__);
- return -1;
+ return -EBADMSG;
}
EXPORT_SYMBOL(__nand_correct_data);
@@ -524,7 +524,7 @@ int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
return __nand_correct_data(buf, read_ecc, calc_ecc,
- ((struct nand_chip *)mtd->priv)->ecc.size);
+ mtd_to_nand(mtd)->ecc.size);
}
EXPORT_SYMBOL(nand_correct_data);
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index b16d70aafd9e..1fd519503bb1 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -666,8 +666,8 @@ static char *get_partition_name(int i)
*/
static int init_nandsim(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct nandsim *ns = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
int i, ret = 0;
uint64_t remains;
uint64_t next_offset;
@@ -1908,7 +1908,8 @@ static void switch_state(struct nandsim *ns)
static u_char ns_nand_read_byte(struct mtd_info *mtd)
{
- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
u_char outb = 0x00;
/* Sanity and correctness checks */
@@ -1969,7 +1970,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
{
- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
if (!ns->lines.ce) {
@@ -2123,7 +2125,8 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
{
- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
@@ -2141,7 +2144,7 @@ static int ns_device_ready(struct mtd_info *mtd)
static uint16_t ns_nand_read_word(struct mtd_info *mtd)
{
- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
NS_DBG("read_word\n");
@@ -2150,7 +2153,8 @@ static uint16_t ns_nand_read_word(struct mtd_info *mtd)
static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
/* Check that chip is expecting data input */
if (!(ns->state & STATE_DATAIN_MASK)) {
@@ -2177,7 +2181,8 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
if (!ns->lines.ce) {
@@ -2198,7 +2203,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
int i;
for (i = 0; i < len; i++)
- buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd);
+ buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
return;
}
@@ -2236,16 +2241,15 @@ static int __init ns_init_module(void)
}
/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
- nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
- + sizeof(struct nandsim), GFP_KERNEL);
- if (!nsmtd) {
+ chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
+ GFP_KERNEL);
+ if (!chip) {
NS_ERR("unable to allocate core structures.\n");
return -ENOMEM;
}
- chip = (struct nand_chip *)(nsmtd + 1);
- nsmtd->priv = (void *)chip;
+ nsmtd = nand_to_mtd(chip);
nand = (struct nandsim *)(chip + 1);
- chip->priv = (void *)nand;
+ nand_set_controller_data(chip, (void *)nand);
/*
* Register simulator's callbacks.
@@ -2392,7 +2396,7 @@ err_exit:
for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
kfree(nand->partitions[i].name);
error:
- kfree(nsmtd);
+ kfree(chip);
free_lists();
return retval;
@@ -2405,7 +2409,8 @@ module_init(ns_init_module);
*/
static void __exit ns_cleanup_module(void)
{
- struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
+ struct nand_chip *chip = mtd_to_nand(nsmtd);
+ struct nandsim *ns = nand_get_controller_data(chip);
int i;
nandsim_debugfs_remove(ns);
@@ -2413,7 +2418,7 @@ static void __exit ns_cleanup_module(void)
nand_release(nsmtd); /* Unregister driver */
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
kfree(ns->partitions[i].name);
- kfree(nsmtd); /* Free other structures */
+ kfree(mtd_to_nand(nsmtd)); /* Free other structures */
free_lists();
}
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 4f0d62f9d22c..218c789ca7ab 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -37,7 +37,6 @@
struct ndfc_controller {
struct platform_device *ofdev;
void __iomem *ndfcbase;
- struct mtd_info mtd;
struct nand_chip chip;
int chip_select;
struct nand_hw_control ndfc_control;
@@ -48,8 +47,8 @@ static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
static void ndfc_select_chip(struct mtd_info *mtd, int chip)
{
uint32_t ccr;
- struct nand_chip *nchip = mtd->priv;
- struct ndfc_controller *ndfc = nchip->priv;
+ struct nand_chip *nchip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
@@ -62,8 +61,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(chip);
if (cmd == NAND_CMD_NONE)
return;
@@ -76,8 +75,8 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
static int ndfc_ready(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(chip);
return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
@@ -85,8 +84,8 @@ static int ndfc_ready(struct mtd_info *mtd)
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
{
uint32_t ccr;
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(chip);
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
@@ -97,8 +96,8 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
static int ndfc_calculate_ecc(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code)
{
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t ecc;
uint8_t *p = (uint8_t *)&ecc;
@@ -121,8 +120,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
*/
static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
@@ -131,8 +130,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
@@ -147,7 +146,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
{
struct device_node *flash_np;
struct nand_chip *chip = &ndfc->chip;
- struct mtd_part_parser_data ppdata;
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
@@ -166,33 +165,32 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
- chip->priv = ndfc;
+ nand_set_controller_data(chip, ndfc);
- ndfc->mtd.priv = chip;
- ndfc->mtd.dev.parent = &ndfc->ofdev->dev;
+ mtd->dev.parent = &ndfc->ofdev->dev;
flash_np = of_get_next_child(node, NULL);
if (!flash_np)
return -ENODEV;
+ nand_set_flash_node(chip, flash_np);
- ppdata.of_node = flash_np;
- ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s",
- dev_name(&ndfc->ofdev->dev), flash_np->name);
- if (!ndfc->mtd.name) {
+ mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
+ flash_np->name);
+ if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
- ret = nand_scan(&ndfc->mtd, 1);
+ ret = nand_scan(mtd, 1);
if (ret)
goto err;
- ret = mtd_device_parse_register(&ndfc->mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
err:
of_node_put(flash_np);
if (ret)
- kfree(ndfc->mtd.name);
+ kfree(mtd->name);
return ret;
}
@@ -259,9 +257,10 @@ static int ndfc_probe(struct platform_device *ofdev)
static int ndfc_remove(struct platform_device *ofdev)
{
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
+ struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
- nand_release(&ndfc->mtd);
- kfree(ndfc->mtd.name);
+ nand_release(mtd);
+ kfree(mtd->name);
return 0;
}
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
index f0687f71fbd8..220ddfcf29f5 100644
--- a/drivers/mtd/nand/nuc900_nand.c
+++ b/drivers/mtd/nand/nuc900_nand.c
@@ -55,13 +55,17 @@
__raw_writel((val), (dev)->reg + REG_SMADDR)
struct nuc900_nand {
- struct mtd_info mtd;
struct nand_chip chip;
void __iomem *reg;
struct clk *clk;
spinlock_t lock;
};
+static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
+}
+
static const struct mtd_partition partitions[] = {
{
.name = "NAND FS 0",
@@ -78,9 +82,7 @@ static const struct mtd_partition partitions[] = {
static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
{
unsigned char ret;
- struct nuc900_nand *nand;
-
- nand = container_of(mtd, struct nuc900_nand, mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(mtd);
ret = (unsigned char)read_data_reg(nand);
@@ -91,9 +93,7 @@ static void nuc900_nand_read_buf(struct mtd_info *mtd,
unsigned char *buf, int len)
{
int i;
- struct nuc900_nand *nand;
-
- nand = container_of(mtd, struct nuc900_nand, mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(mtd);
for (i = 0; i < len; i++)
buf[i] = (unsigned char)read_data_reg(nand);
@@ -103,9 +103,7 @@ static void nuc900_nand_write_buf(struct mtd_info *mtd,
const unsigned char *buf, int len)
{
int i;
- struct nuc900_nand *nand;
-
- nand = container_of(mtd, struct nuc900_nand, mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(mtd);
for (i = 0; i < len; i++)
write_data_reg(nand, buf[i]);
@@ -124,11 +122,9 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
static int nuc900_nand_devready(struct mtd_info *mtd)
{
- struct nuc900_nand *nand;
+ struct nuc900_nand *nand = mtd_to_nuc900(mtd);
int ready;
- nand = container_of(mtd, struct nuc900_nand, mtd);
-
ready = (nuc900_check_rb(nand)) ? 1 : 0;
return ready;
}
@@ -136,10 +132,8 @@ static int nuc900_nand_devready(struct mtd_info *mtd)
static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
- register struct nand_chip *chip = mtd->priv;
- struct nuc900_nand *nand;
-
- nand = container_of(mtd, struct nuc900_nand, mtd);
+ register struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(mtd);
if (command == NAND_CMD_READOOB) {
column += mtd->writesize;
@@ -241,6 +235,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand;
struct nand_chip *chip;
+ struct mtd_info *mtd;
struct resource *res;
nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
@@ -248,9 +243,9 @@ static int nuc900_nand_probe(struct platform_device *pdev)
if (!nuc900_nand)
return -ENOMEM;
chip = &(nuc900_nand->chip);
+ mtd = nand_to_mtd(chip);
- nuc900_nand->mtd.priv = chip;
- nuc900_nand->mtd.dev.parent = &pdev->dev;
+ mtd->dev.parent = &pdev->dev;
spin_lock_init(&nuc900_nand->lock);
nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
@@ -274,11 +269,10 @@ static int nuc900_nand_probe(struct platform_device *pdev)
nuc900_nand_enable(nuc900_nand);
- if (nand_scan(&(nuc900_nand->mtd), 1))
+ if (nand_scan(mtd, 1))
return -ENXIO;
- mtd_device_register(&(nuc900_nand->mtd), partitions,
- ARRAY_SIZE(partitions));
+ mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
platform_set_drvdata(pdev, nuc900_nand);
@@ -289,7 +283,7 @@ static int nuc900_nand_remove(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
- nand_release(&nuc900_nand->mtd);
+ nand_release(nand_to_mtd(&nuc900_nand->chip));
clk_disable(nuc900_nand->clk);
return 0;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 93f664cd1c90..c553f78ab83f 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -152,7 +152,6 @@ static struct nand_hw_control omap_gpmc_controller = {
struct omap_nand_info {
struct omap_nand_platform_data *pdata;
- struct mtd_info mtd;
struct nand_chip nand;
struct platform_device *pdev;
@@ -177,6 +176,11 @@ struct omap_nand_info {
struct device_node *of_node;
};
+static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct omap_nand_info, nand);
+}
+
/**
* omap_prefetch_enable - configures and starts prefetch transfer
* @cs: cs (chip select) number
@@ -247,8 +251,7 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
*/
static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
@@ -270,7 +273,7 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
*/
static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
ioread8_rep(nand->IO_ADDR_R, buf, len);
}
@@ -283,8 +286,7 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
*/
static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
u_char *p = (u_char *)buf;
u32 status = 0;
@@ -306,7 +308,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
*/
static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
}
@@ -319,8 +321,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
*/
static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
u16 *p = (u16 *) buf;
u32 status = 0;
/* FIXME try bursts of writesw() or DMA ... */
@@ -344,8 +345,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
*/
static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
uint32_t r_count = 0;
int ret = 0;
u32 *p = (u32 *)buf;
@@ -392,8 +392,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
static void omap_write_buf_pref(struct mtd_info *mtd,
const u_char *buf, int len)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
uint32_t w_count = 0;
int i = 0, ret = 0;
u16 *p = (u16 *)buf;
@@ -458,8 +457,7 @@ static void omap_nand_dma_callback(void *data)
static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
unsigned int len, int is_write)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
struct dma_async_tx_descriptor *tx;
enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
DMA_FROM_DEVICE;
@@ -623,8 +621,7 @@ done:
*/
static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
int ret = 0;
if (len <= mtd->oobsize) {
@@ -671,8 +668,7 @@ out_copy:
static void omap_write_buf_irq_pref(struct mtd_info *mtd,
const u_char *buf, int len)
{
- struct omap_nand_info *info = container_of(mtd,
- struct omap_nand_info, mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
int ret = 0;
unsigned long tim, limit;
u32 val;
@@ -830,12 +826,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
case 1:
/* Uncorrectable error */
pr_debug("ECC UNCORRECTED_ERROR 1\n");
- return -1;
+ return -EBADMSG;
case 11:
/* UN-Correctable error */
pr_debug("ECC UNCORRECTED_ERROR B\n");
- return -1;
+ return -EBADMSG;
case 12:
/* Correctable error */
@@ -865,7 +861,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
return 0;
}
pr_debug("UNCORRECTED_ERROR default\n");
- return -1;
+ return -EBADMSG;
}
}
@@ -886,8 +882,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
int blockCnt = 0, i = 0, ret = 0;
int stat = 0;
@@ -928,8 +923,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
{
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
u32 val;
val = readl(info->reg.gpmc_ecc_config);
@@ -953,9 +947,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
*/
static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
- struct nand_chip *chip = mtd->priv;
+ struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct nand_chip *chip = mtd_to_nand(mtd);
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
u32 val;
@@ -1001,9 +994,8 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
*/
static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
- struct nand_chip *this = mtd->priv;
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
unsigned long timeo = jiffies;
int status, state = this->state;
@@ -1031,8 +1023,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
static int omap_dev_ready(struct mtd_info *mtd)
{
unsigned int val = 0;
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
val = readl(info->reg.gpmc_status);
@@ -1058,10 +1049,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
{
unsigned int bch_type;
unsigned int dev_width, nsectors;
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
enum omap_ecc ecc_opt = info->ecc_opt;
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
u32 val, wr_mode;
unsigned int ecc_size1, ecc_size0;
@@ -1162,8 +1152,7 @@ static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_calc)
{
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
int eccbytes = info->nand.ecc.bytes;
struct gpmc_nand_regs *gpmc_regs = &info->reg;
u8 *ecc_code;
@@ -1334,8 +1323,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
u_char *read_ecc, u_char *calc_ecc)
{
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
int eccsteps = info->nand.ecc.steps;
int i , j, stat = 0;
@@ -1663,7 +1651,6 @@ static int omap_nand_probe(struct platform_device *pdev)
unsigned sig;
unsigned oob_index;
struct resource *res;
- struct mtd_part_parser_data ppdata = {};
pdata = dev_get_platdata(&pdev->dev);
if (pdata == NULL) {
@@ -1683,11 +1670,11 @@ static int omap_nand_probe(struct platform_device *pdev)
info->reg = pdata->reg;
info->of_node = pdata->of_node;
info->ecc_opt = pdata->ecc_opt;
- mtd = &info->mtd;
- mtd->priv = &info->nand;
- mtd->dev.parent = &pdev->dev;
nand_chip = &info->nand;
+ mtd = nand_to_mtd(nand_chip);
+ mtd->dev.parent = &pdev->dev;
nand_chip->ecc.priv = NULL;
+ nand_set_flash_node(nand_chip, pdata->of_node);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
@@ -1909,7 +1896,7 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
err = elm_config(info->elm_dev, BCH4_ECC,
- info->mtd.writesize / nand_chip->ecc.size,
+ mtd->writesize / nand_chip->ecc.size,
nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error;
@@ -1963,7 +1950,7 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.write_page = omap_write_page_bch;
err = elm_config(info->elm_dev, BCH8_ECC,
- info->mtd.writesize / nand_chip->ecc.size,
+ mtd->writesize / nand_chip->ecc.size,
nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error;
@@ -1993,7 +1980,7 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.write_page = omap_write_page_bch;
err = elm_config(info->elm_dev, BCH16_ECC,
- info->mtd.writesize / nand_chip->ecc.size,
+ mtd->writesize / nand_chip->ecc.size,
nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error;
@@ -2037,9 +2024,7 @@ scan_tail:
goto return_error;
}
- ppdata.of_node = pdata->of_node;
- mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts,
- pdata->nr_parts);
+ mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
platform_set_drvdata(pdev, mtd);
@@ -2058,9 +2043,8 @@ return_error:
static int omap_nand_remove(struct platform_device *pdev)
{
struct mtd_info *mtd = platform_get_drvdata(pdev);
- struct nand_chip *nand_chip = mtd->priv;
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
if (nand_chip->ecc.priv) {
nand_bch_free(nand_chip->ecc.priv);
nand_chip->ecc.priv = NULL;
diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c
index 235ec7992b4c..a3f32f939cc1 100644
--- a/drivers/mtd/nand/omap_elm.c
+++ b/drivers/mtd/nand/omap_elm.c
@@ -414,7 +414,7 @@ static int elm_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
pdev->name, info);
if (ret) {
- dev_err(&pdev->dev, "failure requesting irq %i\n", irq->start);
+ dev_err(&pdev->dev, "failure requesting %pr\n", irq);
return ret;
}
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index ee83749fb1d3..d4614bfbfed6 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -25,8 +25,8 @@
static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *nc = mtd->priv;
- struct orion_nand_data *board = nc->priv;
+ struct nand_chip *nc = mtd_to_nand(mtd);
+ struct orion_nand_data *board = nand_get_controller_data(nc);
u32 offs;
if (cmd == NAND_CMD_NONE)
@@ -47,7 +47,7 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
void __iomem *io_base = chip->IO_ADDR_R;
uint64_t *buf64;
int i = 0;
@@ -76,7 +76,6 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static int __init orion_nand_probe(struct platform_device *pdev)
{
struct mtd_info *mtd;
- struct mtd_part_parser_data ppdata = {};
struct nand_chip *nc;
struct orion_nand_data *board;
struct resource *res;
@@ -86,11 +85,11 @@ static int __init orion_nand_probe(struct platform_device *pdev)
u32 val = 0;
nc = devm_kzalloc(&pdev->dev,
- sizeof(struct nand_chip) + sizeof(struct mtd_info),
+ sizeof(struct nand_chip),
GFP_KERNEL);
if (!nc)
return -ENOMEM;
- mtd = (struct mtd_info *)(nc + 1);
+ mtd = nand_to_mtd(nc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
io_base = devm_ioremap_resource(&pdev->dev, res);
@@ -123,10 +122,10 @@ static int __init orion_nand_probe(struct platform_device *pdev)
board = dev_get_platdata(&pdev->dev);
}
- mtd->priv = nc;
mtd->dev.parent = &pdev->dev;
- nc->priv = board;
+ nand_set_controller_data(nc, board);
+ nand_set_flash_node(nc, pdev->dev.of_node);
nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
nc->cmd_ctrl = orion_nand_cmd_ctrl;
nc->read_buf = orion_nand_read_buf;
@@ -161,9 +160,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
}
mtd->name = "orion_nand";
- ppdata.of_node = pdev->dev.of_node;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata,
- board->parts, board->nr_parts);
+ ret = mtd_device_register(mtd, board->parts, board->nr_parts);
if (ret) {
nand_release(mtd);
goto no_dev;
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index 83cf021b9651..3ab53ca53cca 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -45,7 +45,7 @@ static const char driver_name[] = "pasemi-nand";
static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
while (len > 0x800) {
memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
@@ -57,7 +57,7 @@ static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
while (len > 0x800) {
memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
@@ -70,7 +70,7 @@ static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (cmd == NAND_CMD_NONE)
return;
@@ -110,20 +110,17 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
pr_debug("pasemi_nand at %pR\n", &res);
/* Allocate memory for MTD device structure and private data */
- pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) +
- sizeof(struct nand_chip), GFP_KERNEL);
- if (!pasemi_nand_mtd) {
+ chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+ if (!chip) {
printk(KERN_WARNING
"Unable to allocate PASEMI NAND MTD device structure\n");
err = -ENOMEM;
goto out;
}
- /* Get pointer to private data */
- chip = (struct nand_chip *)&pasemi_nand_mtd[1];
+ pasemi_nand_mtd = nand_to_mtd(chip);
/* Link the private data with the MTD structure */
- pasemi_nand_mtd->priv = chip;
pasemi_nand_mtd->dev.parent = &ofdev->dev;
chip->IO_ADDR_R = of_iomap(np, 0);
@@ -180,7 +177,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
out_ior:
iounmap(chip->IO_ADDR_R);
out_mtd:
- kfree(pasemi_nand_mtd);
+ kfree(chip);
out:
return err;
}
@@ -192,7 +189,7 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
if (!pasemi_nand_mtd)
return 0;
- chip = pasemi_nand_mtd->priv;
+ chip = mtd_to_nand(pasemi_nand_mtd);
/* Release resources, unregister device */
nand_release(pasemi_nand_mtd);
@@ -202,7 +199,7 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
iounmap(chip->IO_ADDR_R);
/* Free the MTD device structure */
- kfree(pasemi_nand_mtd);
+ kfree(chip);
pasemi_nand_mtd = NULL;
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 65b9dbbe6d6a..a0e26dea1424 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -20,7 +20,6 @@
struct plat_nand_data {
struct nand_chip chip;
- struct mtd_info mtd;
void __iomem *io_base;
};
@@ -30,8 +29,8 @@ struct plat_nand_data {
static int plat_nand_probe(struct platform_device *pdev)
{
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
- struct mtd_part_parser_data ppdata;
struct plat_nand_data *data;
+ struct mtd_info *mtd;
struct resource *res;
const char **part_types;
int err = 0;
@@ -57,9 +56,9 @@ static int plat_nand_probe(struct platform_device *pdev)
if (IS_ERR(data->io_base))
return PTR_ERR(data->io_base);
- data->chip.priv = &data;
- data->mtd.priv = &data->chip;
- data->mtd.dev.parent = &pdev->dev;
+ nand_set_flash_node(&data->chip, pdev->dev.of_node);
+ mtd = nand_to_mtd(&data->chip);
+ mtd->dev.parent = &pdev->dev;
data->chip.IO_ADDR_R = data->io_base;
data->chip.IO_ADDR_W = data->io_base;
@@ -87,22 +86,21 @@ static int plat_nand_probe(struct platform_device *pdev)
}
/* Scan to find existence of the device */
- if (nand_scan(&data->mtd, pdata->chip.nr_chips)) {
+ if (nand_scan(mtd, pdata->chip.nr_chips)) {
err = -ENXIO;
goto out;
}
part_types = pdata->chip.part_probe_types;
- ppdata.of_node = pdev->dev.of_node;
- err = mtd_device_parse_register(&data->mtd, part_types, &ppdata,
+ err = mtd_device_parse_register(mtd, part_types, NULL,
pdata->chip.partitions,
pdata->chip.nr_partitions);
if (!err)
return err;
- nand_release(&data->mtd);
+ nand_release(mtd);
out:
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
@@ -117,7 +115,7 @@ static int plat_nand_remove(struct platform_device *pdev)
struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
- nand_release(&data->mtd);
+ nand_release(nand_to_mtd(&data->chip));
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index e453ae9a17fa..86fc245dc71a 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -30,11 +30,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mtd.h>
-
-#if defined(CONFIG_ARM) && (defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP))
-#define ARCH_HAS_DMA
-#endif
-
#include <linux/platform_data/mtd-nand-pxa3xx.h>
#define CHIP_DELAY_TIMEOUT msecs_to_jiffies(200)
@@ -172,7 +167,6 @@ enum pxa3xx_nand_variant {
struct pxa3xx_nand_host {
struct nand_chip chip;
- struct mtd_info *mtd;
void *info_data;
/* page size of attached chip */
@@ -455,14 +449,15 @@ static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
struct nand_chip *chip = &host->chip;
struct pxa3xx_nand_info *info = host->info_data;
const struct pxa3xx_nand_flash *f = NULL;
+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
int i, id, ntypes;
ntypes = ARRAY_SIZE(builtin_flash_types);
- chip->cmdfunc(host->mtd, NAND_CMD_READID, 0x00, -1);
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- id = chip->read_byte(host->mtd);
- id |= chip->read_byte(host->mtd) << 0x8;
+ id = chip->read_byte(mtd);
+ id |= chip->read_byte(mtd) << 0x8;
for (i = 0; i < ntypes; i++) {
f = &builtin_flash_types[i];
@@ -895,7 +890,7 @@ static void set_command_address(struct pxa3xx_nand_info *info,
static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
{
struct pxa3xx_nand_host *host = info->host[info->cs];
- struct mtd_info *mtd = host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->chip);
/* reset data and oob column point to handle data */
info->buf_start = 0;
@@ -948,7 +943,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
struct mtd_info *mtd;
host = info->host[info->cs];
- mtd = host->mtd;
+ mtd = nand_to_mtd(&host->chip);
addr_cycle = 0;
exec_cmd = 1;
@@ -1118,7 +1113,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
int column, int page_addr)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
int exec_cmd;
@@ -1166,7 +1162,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
const unsigned command,
int column, int page_addr)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
int exec_cmd, ext_cmd_type;
@@ -1286,7 +1283,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required,
int page)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
chip->read_buf(mtd, buf, mtd->writesize);
@@ -1312,7 +1309,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
char retval = 0xFF;
@@ -1325,7 +1323,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
u16 retval = 0xFFFF;
@@ -1338,7 +1337,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
@@ -1349,7 +1349,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
@@ -1364,7 +1365,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
if (info->need_wait) {
@@ -1387,37 +1389,53 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
return NAND_STATUS_READY;
}
-static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info)
+static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
{
+ struct pxa3xx_nand_host *host = info->host[info->cs];
struct platform_device *pdev = info->pdev;
struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct pxa3xx_nand_host *host = info->host[info->cs];
- struct mtd_info *mtd = host->mtd;
- struct nand_chip *chip = mtd->priv;
+ const struct nand_sdr_timings *timings;
- /* configure default flash values */
+ /* Configure default flash values */
+ info->chunk_size = PAGE_CHUNK_SIZE;
info->reg_ndcr = 0x0; /* enable all interrupts */
info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
- info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+ info->reg_ndcr |= NDCR_SPARE_EN;
+
+ /* use the common timing to make a try */
+ timings = onfi_async_timing_mode_to_sdr_timings(0);
+ if (IS_ERR(timings))
+ return PTR_ERR(timings);
+
+ pxa3xx_nand_set_sdr_timing(host, timings);
+ return 0;
+}
+
+static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info)
+{
+ struct pxa3xx_nand_host *host = info->host[info->cs];
+ struct nand_chip *chip = &host->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
-
- return 0;
}
-static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
+static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
{
+ struct platform_device *pdev = info->pdev;
+ struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
uint32_t ndcr = nand_readl(info, NDCR);
/* Set an initial chunk size */
info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
info->reg_ndcr = ndcr &
~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
+ info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
- return 0;
}
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
@@ -1483,32 +1501,6 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
kfree(info->data_buff);
}
-static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host)
-{
- struct pxa3xx_nand_info *info = host->info_data;
- struct mtd_info *mtd;
- struct nand_chip *chip;
- const struct nand_sdr_timings *timings;
- int ret;
-
- mtd = info->host[info->cs]->mtd;
- chip = mtd->priv;
-
- /* use the common timing to make a try */
- timings = onfi_async_timing_mode_to_sdr_timings(0);
- if (IS_ERR(timings))
- return PTR_ERR(timings);
-
- pxa3xx_nand_set_sdr_timing(host, timings);
-
- chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
- ret = chip->waitfunc(mtd, chip);
- if (ret & NAND_STATUS_FAIL)
- return -ENODEV;
-
- return 0;
-}
-
static int pxa_ecc_init(struct pxa3xx_nand_info *info,
struct nand_ecc_ctrl *ecc,
int strength, int ecc_stepsize, int page_size)
@@ -1580,34 +1572,22 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
static int pxa3xx_nand_scan(struct mtd_info *mtd)
{
- struct pxa3xx_nand_host *host = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
struct platform_device *pdev = info->pdev;
struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct nand_chip *chip = mtd->priv;
int ret;
uint16_t ecc_strength, ecc_step;
- if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
- goto KEEP_CONFIG;
-
- /* Set a default chunk size */
- info->chunk_size = 512;
-
- ret = pxa3xx_nand_config_flash(info);
- if (ret)
- return ret;
-
- ret = pxa3xx_nand_sensing(host);
- if (ret) {
- dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
- info->cs);
-
- return ret;
+ if (pdata->keep_config) {
+ pxa3xx_nand_detect_config(info);
+ } else {
+ ret = pxa3xx_nand_config_ident(info);
+ if (ret)
+ return ret;
}
-KEEP_CONFIG:
- info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
if (info->reg_ndcr & NDCR_DWIDTH_M)
chip->options |= NAND_BUSWIDTH_16;
@@ -1692,11 +1672,16 @@ KEEP_CONFIG:
host->row_addr_cycles = 3;
else
host->row_addr_cycles = 2;
+
+ if (!pdata->keep_config)
+ pxa3xx_nand_config_tail(info);
+
return nand_scan_tail(mtd);
}
static int alloc_nand_resource(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct pxa3xx_nand_platform_data *pdata;
struct pxa3xx_nand_info *info;
struct pxa3xx_nand_host *host;
@@ -1708,24 +1693,27 @@ static int alloc_nand_resource(struct platform_device *pdev)
pdata = dev_get_platdata(&pdev->dev);
if (pdata->num_cs <= 0)
return -ENODEV;
- info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
- sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev,
+ sizeof(*info) + sizeof(*host) * pdata->num_cs,
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
info->pdev = pdev;
info->variant = pxa3xx_nand_get_variant(pdev);
for (cs = 0; cs < pdata->num_cs; cs++) {
- mtd = (void *)&info[1] + (sizeof(*mtd) + sizeof(*host)) * cs;
- chip = (struct nand_chip *)(&mtd[1]);
- host = (struct pxa3xx_nand_host *)chip;
+ host = (void *)&info[1] + sizeof(*host) * cs;
+ chip = &host->chip;
+ nand_set_controller_data(chip, host);
+ mtd = nand_to_mtd(chip);
info->host[cs] = host;
- host->mtd = mtd;
host->cs = cs;
host->info_data = info;
- mtd->priv = host;
mtd->dev.parent = &pdev->dev;
+ /* FIXME: all chips use the same device tree partitions */
+ nand_set_flash_node(chip, np);
+ nand_set_controller_data(chip, host);
chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
chip->ecc.write_page = pxa3xx_nand_write_page_hwecc;
chip->controller = &info->controller;
@@ -1845,7 +1833,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
clk_disable_unprepare(info->clk);
for (cs = 0; cs < pdata->num_cs; cs++)
- nand_release(info->host[cs]->mtd);
+ nand_release(nand_to_mtd(&info->host[cs]->chip));
return 0;
}
@@ -1886,7 +1874,6 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
static int pxa3xx_nand_probe(struct platform_device *pdev)
{
struct pxa3xx_nand_platform_data *pdata;
- struct mtd_part_parser_data ppdata = {};
struct pxa3xx_nand_info *info;
int ret, cs, probe_success, dma_available;
@@ -1917,7 +1904,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
info = platform_get_drvdata(pdev);
probe_success = 0;
for (cs = 0; cs < pdata->num_cs; cs++) {
- struct mtd_info *mtd = info->host[cs]->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
/*
* The mtd name matches the one used in 'mtdparts' kernel
@@ -1933,10 +1920,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
continue;
}
- ppdata.of_node = pdev->dev.of_node;
- ret = mtd_device_parse_register(mtd, NULL,
- &ppdata, pdata->parts[cs],
- pdata->nr_parts[cs]);
+ ret = mtd_device_register(mtd, pdata->parts[cs],
+ pdata->nr_parts[cs]);
if (!ret)
probe_success = 1;
}
@@ -1959,12 +1944,18 @@ static int pxa3xx_nand_suspend(struct device *dev)
return -EAGAIN;
}
+ clk_disable(info->clk);
return 0;
}
static int pxa3xx_nand_resume(struct device *dev)
{
struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(info->clk);
+ if (ret < 0)
+ return ret;
/* We don't want to handle interrupt without calling mtd routine */
disable_int(info, NDCR_INT_MASK);
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c
index d8bb2be327f1..fc9287af4614 100644
--- a/drivers/mtd/nand/r852.c
+++ b/drivers/mtd/nand/r852.c
@@ -64,8 +64,8 @@ static inline void r852_write_reg_dword(struct r852_device *dev,
/* returns pointer to our private structure */
static inline struct r852_device *r852_get_dev(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- return chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ return nand_get_controller_data(chip);
}
@@ -361,7 +361,7 @@ static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
*/
static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
- struct r852_device *dev = chip->priv;
+ struct r852_device *dev = nand_get_controller_data(chip);
unsigned long timeout;
int status;
@@ -477,7 +477,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
if (dev->dma_error) {
dev->dma_error = 0;
- return -1;
+ return -EIO;
}
r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
@@ -491,7 +491,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
/* ecc uncorrectable error */
if (ecc_status & R852_ECC_FAIL) {
dbg("ecc: unrecoverable error, in half %d", i);
- error = -1;
+ error = -EBADMSG;
goto exit;
}
@@ -634,25 +634,21 @@ static void r852_update_media_status(struct r852_device *dev)
*/
static int r852_register_nand_device(struct r852_device *dev)
{
- dev->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
-
- if (!dev->mtd)
- goto error1;
+ struct mtd_info *mtd = nand_to_mtd(dev->chip);
WARN_ON(dev->card_registred);
- dev->mtd->priv = dev->chip;
- dev->mtd->dev.parent = &dev->pci_dev->dev;
+ mtd->dev.parent = &dev->pci_dev->dev;
if (dev->readonly)
dev->chip->options |= NAND_ROM;
r852_engine_enable(dev);
- if (sm_register_device(dev->mtd, dev->sm))
- goto error2;
+ if (sm_register_device(mtd, dev->sm))
+ goto error1;
- if (device_create_file(&dev->mtd->dev, &dev_attr_media_type)) {
+ if (device_create_file(&mtd->dev, &dev_attr_media_type)) {
message("can't create media type sysfs attribute");
goto error3;
}
@@ -660,9 +656,7 @@ static int r852_register_nand_device(struct r852_device *dev)
dev->card_registred = 1;
return 0;
error3:
- nand_release(dev->mtd);
-error2:
- kfree(dev->mtd);
+ nand_release(mtd);
error1:
/* Force card redetect */
dev->card_detected = 0;
@@ -675,15 +669,15 @@ error1:
static void r852_unregister_nand_device(struct r852_device *dev)
{
+ struct mtd_info *mtd = nand_to_mtd(dev->chip);
+
if (!dev->card_registred)
return;
- device_remove_file(&dev->mtd->dev, &dev_attr_media_type);
- nand_release(dev->mtd);
+ device_remove_file(&mtd->dev, &dev_attr_media_type);
+ nand_release(mtd);
r852_engine_disable(dev);
dev->card_registred = 0;
- kfree(dev->mtd);
- dev->mtd = NULL;
}
/* Card state updater */
@@ -885,7 +879,7 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
if (!dev)
goto error5;
- chip->priv = dev;
+ nand_set_controller_data(chip, dev);
dev->chip = chip;
dev->pci_dev = pci_dev;
pci_set_drvdata(pci_dev, dev);
@@ -980,7 +974,6 @@ static void r852_remove(struct pci_dev *pci_dev)
/* Stop interrupts */
r852_disable_irqs(dev);
- synchronize_irq(dev->irq);
free_irq(dev->irq, dev);
/* Cleanup */
@@ -1032,6 +1025,7 @@ static int r852_suspend(struct device *device)
static int r852_resume(struct device *device)
{
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
+ struct mtd_info *mtd = nand_to_mtd(dev->chip);
r852_disable_irqs(dev);
r852_card_update_present(dev);
@@ -1051,9 +1045,9 @@ static int r852_resume(struct device *device)
/* Otherwise, initialize the card */
if (dev->card_registred) {
r852_engine_enable(dev);
- dev->chip->select_chip(dev->mtd, 0);
- dev->chip->cmdfunc(dev->mtd, NAND_CMD_RESET, -1, -1);
- dev->chip->select_chip(dev->mtd, -1);
+ dev->chip->select_chip(mtd, 0);
+ dev->chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ dev->chip->select_chip(mtd, -1);
}
/* Program card detection IRQ */
diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h
index e6a21d9d22c6..d042ddb71a8b 100644
--- a/drivers/mtd/nand/r852.h
+++ b/drivers/mtd/nand/r852.h
@@ -108,7 +108,6 @@
struct r852_device {
void __iomem *mmio; /* mmio */
- struct mtd_info *mtd; /* mtd backpointer */
struct nand_chip *chip; /* nand chip backpointer */
struct pci_dev *pci_dev; /* pci backpointer */
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 05105cadd0db..01ac74fa3b95 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -104,7 +104,6 @@ struct s3c2410_nand_info;
* @scan_res: The result from calling nand_scan_ident().
*/
struct s3c2410_nand_mtd {
- struct mtd_info mtd;
struct nand_chip chip;
struct s3c2410_nand_set *set;
struct s3c2410_nand_info *info;
@@ -168,7 +167,8 @@ struct s3c2410_nand_info {
static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
{
- return container_of(mtd, struct s3c2410_nand_mtd, mtd);
+ return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
+ chip);
}
static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
@@ -382,10 +382,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
{
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long cur;
- nmtd = this->priv;
+ nmtd = nand_get_controller_data(this);
info = nmtd->info;
if (chip != -1)
@@ -634,7 +634,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
readsb(this->IO_ADDR_R, buf, len);
}
@@ -656,7 +656,7 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
int len)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
writesb(this->IO_ADDR_W, buf, len);
}
@@ -745,7 +745,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
- nand_release(&ptr->mtd);
+ nand_release(nand_to_mtd(&ptr->chip));
}
}
@@ -762,9 +762,11 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
struct s3c2410_nand_set *set)
{
if (set) {
- mtd->mtd.name = set->name;
+ struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
- return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
+ mtdinfo->name = set->name;
+
+ return mtd_device_parse_register(mtdinfo, NULL, NULL,
set->partitions, set->nr_partitions);
}
@@ -792,7 +794,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
chip->chip_delay = 50;
- chip->priv = nmtd;
+ nand_set_controller_data(chip, nmtd);
chip->options = set->options;
chip->controller = &info->controller;
@@ -831,7 +833,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->IO_ADDR_R = chip->IO_ADDR_W;
nmtd->info = info;
- nmtd->mtd.priv = chip;
nmtd->set = set;
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
@@ -1012,19 +1013,21 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
nmtd = info->mtds;
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
+ struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
+
pr_debug("initialising set %d (%p, info %p)\n",
setno, nmtd, info);
- nmtd->mtd.dev.parent = &pdev->dev;
+ mtd->dev.parent = &pdev->dev;
s3c2410_nand_init_chip(info, nmtd, sets);
- nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
+ nmtd->scan_res = nand_scan_ident(mtd,
(sets) ? sets->nr_chips : 1,
NULL);
if (nmtd->scan_res == 0) {
s3c2410_nand_update_chip(info, nmtd);
- nand_scan_tail(&nmtd->mtd);
+ nand_scan_tail(mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
}
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index bcba1a924c75..4814402902f9 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -160,7 +160,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
memset(&cfg, 0, sizeof(cfg));
cfg.direction = DMA_MEM_TO_DEV;
- cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
+ cfg.dst_addr = flctl->fifo;
cfg.src_addr = 0;
ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
if (ret < 0)
@@ -176,7 +176,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
cfg.direction = DMA_DEV_TO_MEM;
cfg.dst_addr = 0;
- cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
+ cfg.src_addr = flctl->fifo;
ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
if (ret < 0)
goto err;
@@ -607,13 +607,13 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
case FL_REPAIRABLE:
dev_info(&flctl->pdev->dev,
"applied ecc on page 0x%x", page_addr);
- flctl->mtd.ecc_stats.corrected++;
+ mtd->ecc_stats.corrected++;
break;
case FL_ERROR:
dev_warn(&flctl->pdev->dev,
"page 0x%x contains corrupted data\n",
page_addr);
- flctl->mtd.ecc_stats.failed++;
+ mtd->ecc_stats.failed++;
break;
default:
;
@@ -1086,7 +1086,6 @@ static int flctl_probe(struct platform_device *pdev)
struct sh_flctl_platform_data *pdata;
int ret;
int irq;
- struct mtd_part_parser_data ppdata = {};
flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
if (!flctl)
@@ -1096,6 +1095,7 @@ static int flctl_probe(struct platform_device *pdev)
flctl->reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(flctl->reg))
return PTR_ERR(flctl->reg);
+ flctl->fifo = res->start + 0x24; /* FLDTFIFO */
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -1121,9 +1121,9 @@ static int flctl_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, flctl);
- flctl_mtd = &flctl->mtd;
nand = &flctl->chip;
- flctl_mtd->priv = nand;
+ flctl_mtd = nand_to_mtd(nand);
+ nand_set_flash_node(nand, pdev->dev.of_node);
flctl_mtd->dev.parent = &pdev->dev;
flctl->pdev = pdev;
flctl->hwecc = pdata->has_hwecc;
@@ -1163,9 +1163,7 @@ static int flctl_probe(struct platform_device *pdev)
if (ret)
goto err_chip;
- ppdata.of_node = pdev->dev.of_node;
- ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts,
- pdata->nr_parts);
+ ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
return 0;
@@ -1180,7 +1178,7 @@ static int flctl_remove(struct platform_device *pdev)
struct sh_flctl *flctl = platform_get_drvdata(pdev);
flctl_release_dma(flctl);
- nand_release(&flctl->mtd);
+ nand_release(nand_to_mtd(&flctl->chip));
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 082b6009736d..b7d1b55a160b 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -29,13 +29,15 @@
#include <asm/mach-types.h>
struct sharpsl_nand {
- struct mtd_info mtd;
struct nand_chip chip;
void __iomem *io;
};
-#define mtd_to_sharpsl(_mtd) container_of(_mtd, struct sharpsl_nand, mtd)
+static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
+}
/* register offset */
#define ECCLPLB 0x00 /* line parity 7 - 0 bit */
@@ -66,7 +68,7 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char bits = ctrl & 0x07;
@@ -109,6 +111,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
static int sharpsl_nand_probe(struct platform_device *pdev)
{
struct nand_chip *this;
+ struct mtd_info *mtd;
struct resource *r;
int err = 0;
struct sharpsl_nand *sharpsl;
@@ -143,8 +146,8 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
this = (struct nand_chip *)(&sharpsl->chip);
/* Link the private data with the MTD structure */
- sharpsl->mtd.priv = this;
- sharpsl->mtd.dev.parent = &pdev->dev;
+ mtd = nand_to_mtd(this);
+ mtd->dev.parent = &pdev->dev;
platform_set_drvdata(pdev, sharpsl);
@@ -173,14 +176,14 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
this->ecc.correct = nand_correct_data;
/* Scan to find existence of the device */
- err = nand_scan(&sharpsl->mtd, 1);
+ err = nand_scan(mtd, 1);
if (err)
goto err_scan;
/* Register the partitions */
- sharpsl->mtd.name = "sharpsl-nand";
+ mtd->name = "sharpsl-nand";
- err = mtd_device_parse_register(&sharpsl->mtd, NULL, NULL,
+ err = mtd_device_parse_register(mtd, NULL, NULL,
data->partitions, data->nr_partitions);
if (err)
goto err_add;
@@ -189,7 +192,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
return 0;
err_add:
- nand_release(&sharpsl->mtd);
+ nand_release(mtd);
err_scan:
iounmap(sharpsl->io);
@@ -207,7 +210,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
/* Release resources, unregister device */
- nand_release(&sharpsl->mtd);
+ nand_release(nand_to_mtd(&sharpsl->chip));
iounmap(sharpsl->io);
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c
index e06b5e5d3287..c514740f9a83 100644
--- a/drivers/mtd/nand/sm_common.c
+++ b/drivers/mtd/nand/sm_common.c
@@ -102,7 +102,7 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
int sm_register_device(struct mtd_info *mtd, int smartmedia)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
chip->options |= NAND_SKIP_BBTSCAN;
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index b94f53427f0f..e3305f9dd6fb 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -30,7 +30,6 @@
struct socrates_nand_host {
struct nand_chip nand_chip;
- struct mtd_info mtd;
void __iomem *io_base;
struct device *dev;
};
@@ -45,8 +44,8 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
- struct socrates_nand_host *host = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(this);
for (i = 0; i < len; i++) {
out_be32(host->io_base, FPGA_NAND_ENABLE |
@@ -64,8 +63,8 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
- struct nand_chip *this = mtd->priv;
- struct socrates_nand_host *host = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(this);
uint32_t val;
val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;
@@ -105,8 +104,8 @@ static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct socrates_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
uint32_t val;
if (cmd == NAND_CMD_NONE)
@@ -130,8 +129,8 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
*/
static int socrates_nand_device_ready(struct mtd_info *mtd)
{
- struct nand_chip *nand_chip = mtd->priv;
- struct socrates_nand_host *host = nand_chip->priv;
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
if (in_be32(host->io_base) & FPGA_NAND_BUSY)
return 0; /* busy */
@@ -147,7 +146,6 @@ static int socrates_nand_probe(struct platform_device *ofdev)
struct mtd_info *mtd;
struct nand_chip *nand_chip;
int res;
- struct mtd_part_parser_data ppdata;
/* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
@@ -160,15 +158,15 @@ static int socrates_nand_probe(struct platform_device *ofdev)
return -EIO;
}
- mtd = &host->mtd;
nand_chip = &host->nand_chip;
+ mtd = nand_to_mtd(nand_chip);
host->dev = &ofdev->dev;
- nand_chip->priv = host; /* link the private data structures */
- mtd->priv = nand_chip;
+ /* link the private data structures */
+ nand_set_controller_data(nand_chip, host);
+ nand_set_flash_node(nand_chip, ofdev->dev.of_node);
mtd->name = "socrates_nand";
mtd->dev.parent = &ofdev->dev;
- ppdata.of_node = ofdev->dev.of_node;
/*should never be accessed directly */
nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
@@ -200,7 +198,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
goto out;
}
- res = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ res = mtd_device_register(mtd, NULL, 0);
if (!res)
return res;
@@ -217,7 +215,7 @@ out:
static int socrates_nand_remove(struct platform_device *ofdev)
{
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
- struct mtd_info *mtd = &host->mtd;
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
nand_release(mtd);
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 824711845c44..51e10a35fe08 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -234,7 +234,6 @@ struct sunxi_nand_hw_ecc {
struct sunxi_nand_chip {
struct list_head node;
struct nand_chip nand;
- struct mtd_info mtd;
unsigned long clk_rate;
u32 timing_cfg;
u32 timing_ctl;
@@ -350,7 +349,7 @@ static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_rb *rb;
@@ -388,7 +387,7 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_chip_sel *sel;
@@ -433,7 +432,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -466,7 +465,7 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
int len)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -507,7 +506,7 @@ static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
unsigned int ctrl)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -541,7 +540,7 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
u32 ecc_ctl;
@@ -556,7 +555,7 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
@@ -577,7 +576,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
int *cur_off,
unsigned int *max_bitflips)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct nand_ecc_ctrl *ecc = &nand->ecc;
u32 status;
@@ -638,7 +637,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
u8 *oob, int *cur_off)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &nand->ecc;
int offset = ((ecc->bytes + 4) * ecc->steps);
int len = mtd->oobsize - offset;
@@ -665,7 +664,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
const u8 *oob, int oob_off,
int *cur_off)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct nand_ecc_ctrl *ecc = &nand->ecc;
int ret;
@@ -702,7 +701,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
u8 *oob, int *cur_off)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &nand->ecc;
int offset = ((ecc->bytes + 4) * ecc->steps);
int len = mtd->oobsize - offset;
@@ -991,6 +990,7 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
struct device_node *np)
{
+ struct mtd_info *mtd = nand_to_mtd(&chip->nand);
const struct nand_sdr_timings *timings;
int ret;
int mode;
@@ -1008,12 +1008,11 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
feature[0] = mode;
for (i = 0; i < chip->nsels; i++) {
- chip->nand.select_chip(&chip->mtd, i);
- ret = chip->nand.onfi_set_features(&chip->mtd,
- &chip->nand,
+ chip->nand.select_chip(mtd, i);
+ ret = chip->nand.onfi_set_features(mtd, &chip->nand,
ONFI_FEATURE_ADDR_TIMING_MODE,
feature);
- chip->nand.select_chip(&chip->mtd, -1);
+ chip->nand.select_chip(mtd, -1);
if (ret)
return ret;
}
@@ -1031,7 +1030,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
struct device_node *np)
{
static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_hw_ecc *data;
@@ -1189,7 +1188,7 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
struct device_node *np)
{
- struct nand_chip *nand = mtd->priv;
+ struct nand_chip *nand = mtd_to_nand(mtd);
int ret;
if (!ecc->size) {
@@ -1232,7 +1231,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
{
const struct nand_sdr_timings *timings;
struct sunxi_nand_chip *chip;
- struct mtd_part_parser_data ppdata;
struct mtd_info *mtd;
struct nand_chip *nand;
int nsels;
@@ -1330,16 +1328,15 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
* in the DT.
*/
nand->ecc.mode = NAND_ECC_HW;
- nand->flash_node = np;
+ nand_set_flash_node(nand, np);
nand->select_chip = sunxi_nfc_select_chip;
nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
nand->read_buf = sunxi_nfc_read_buf;
nand->write_buf = sunxi_nfc_write_buf;
nand->read_byte = sunxi_nfc_read_byte;
- mtd = &chip->mtd;
+ mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
- mtd->priv = nand;
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
@@ -1366,8 +1363,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
return ret;
}
- ppdata.of_node = np;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
nand_release(mtd);
@@ -1393,8 +1389,10 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
for_each_child_of_node(np, nand_np) {
ret = sunxi_nand_chip_init(dev, nfc, nand_np);
- if (ret)
+ if (ret) {
+ of_node_put(nand_np);
return ret;
+ }
}
return 0;
@@ -1407,7 +1405,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
node);
- nand_release(&chip->mtd);
+ nand_release(nand_to_mtd(&chip->nand));
sunxi_nand_ecc_cleanup(&chip->nand.ecc);
list_del(&chip->node);
}
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index befddf0776e4..08b30549ec0a 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -103,7 +103,6 @@
/*--------------------------------------------------------------------------*/
struct tmio_nand {
- struct mtd_info mtd;
struct nand_chip chip;
struct platform_device *dev;
@@ -119,7 +118,10 @@ struct tmio_nand {
unsigned read_good:1;
};
-#define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd)
+static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
+}
/*--------------------------------------------------------------------------*/
@@ -128,7 +130,7 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct tmio_nand *tmio = mtd_to_tmio(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
if (ctrl & NAND_CTRL_CHANGE) {
u8 mode;
@@ -378,9 +380,8 @@ static int tmio_probe(struct platform_device *dev)
tmio->dev = dev;
platform_set_drvdata(dev, tmio);
- mtd = &tmio->mtd;
nand_chip = &tmio->chip;
- mtd->priv = nand_chip;
+ mtd = nand_to_mtd(nand_chip);
mtd->name = "tmio-nand";
mtd->dev.parent = &dev->dev;
@@ -456,7 +457,7 @@ static int tmio_remove(struct platform_device *dev)
{
struct tmio_nand *tmio = platform_get_drvdata(dev);
- nand_release(&tmio->mtd);
+ nand_release(nand_to_mtd(&tmio->chip));
tmio_hw_stop(dev, tmio);
return 0;
}
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 8572519b8441..04d63f56baa4 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -63,7 +63,6 @@
struct txx9ndfmc_priv {
struct platform_device *dev;
struct nand_chip chip;
- struct mtd_info mtd;
int cs;
const char *mtdname;
};
@@ -79,8 +78,8 @@ struct txx9ndfmc_drvdata {
static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
- struct txx9ndfmc_priv *txx9_priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
return txx9_priv->dev;
}
@@ -135,8 +134,8 @@ static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
- struct txx9ndfmc_priv *txx9_priv = chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
struct platform_device *dev = txx9_priv->dev;
struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@@ -175,7 +174,7 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
uint8_t *ecc_code)
{
struct platform_device *dev = mtd_to_platdev(mtd);
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int eccbytes;
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -195,7 +194,7 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int eccsize;
int corrected = 0;
int stat;
@@ -257,7 +256,7 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
{
- struct nand_chip *chip = mtd->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
ret = nand_scan_ident(mtd, 1, NULL);
@@ -322,11 +321,9 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
if (!txx9_priv)
continue;
chip = &txx9_priv->chip;
- mtd = &txx9_priv->mtd;
+ mtd = nand_to_mtd(chip);
mtd->dev.parent = &dev->dev;
- mtd->priv = chip;
-
chip->read_byte = txx9ndfmc_read_byte;
chip->read_buf = txx9ndfmc_read_buf;
chip->write_buf = txx9ndfmc_write_buf;
@@ -343,7 +340,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
chip->chip_delay = 100;
chip->controller = &drvdata->hw_control;
- chip->priv = txx9_priv;
+ nand_set_controller_data(chip, txx9_priv);
txx9_priv->dev = dev;
if (plat->ch_mask != 1) {
@@ -391,8 +388,8 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
if (!mtd)
continue;
- chip = mtd->priv;
- txx9_priv = chip->priv;
+ chip = mtd_to_nand(mtd);
+ txx9_priv = nand_get_controller_data(chip);
nand_release(mtd);
kfree(txx9_priv->mtdname);
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 8805d6325579..034420f313d5 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -156,7 +156,6 @@ enum vf610_nfc_variant {
};
struct vf610_nfc {
- struct mtd_info mtd;
struct nand_chip chip;
struct device *dev;
void __iomem *regs;
@@ -171,7 +170,10 @@ struct vf610_nfc {
u32 ecc_mode;
};
-#define mtd_to_nfc(_mtd) container_of(_mtd, struct vf610_nfc, mtd)
+static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
+{
+ return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
+}
static struct nand_ecclayout vf610_nfc_ecc45 = {
.eccbytes = 45,
@@ -674,10 +676,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
return -ENOMEM;
nfc->dev = &pdev->dev;
- mtd = &nfc->mtd;
chip = &nfc->chip;
+ mtd = nand_to_mtd(chip);
- mtd->priv = chip;
mtd->owner = THIS_MODULE;
mtd->dev.parent = nfc->dev;
mtd->name = DRV_NAME;
@@ -707,18 +708,18 @@ static int vf610_nfc_probe(struct platform_device *pdev)
for_each_available_child_of_node(nfc->dev->of_node, child) {
if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
- if (chip->flash_node) {
+ if (nand_get_flash_node(chip)) {
dev_err(nfc->dev,
"Only one NAND chip supported!\n");
err = -EINVAL;
goto error;
}
- chip->flash_node = child;
+ nand_set_flash_node(chip, child);
}
}
- if (!chip->flash_node) {
+ if (!nand_get_flash_node(chip)) {
dev_err(nfc->dev, "NAND chip sub-node missing!\n");
err = -ENODEV;
goto err_clk;
@@ -811,14 +812,10 @@ static int vf610_nfc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mtd);
/* Register device in MTD */
- return mtd_device_parse_register(mtd, NULL,
- &(struct mtd_part_parser_data){
- .of_node = chip->flash_node,
- },
- NULL, 0);
+ return mtd_device_register(mtd, NULL, 0);
error:
- of_node_put(chip->flash_node);
+ of_node_put(nand_get_flash_node(chip));
err_clk:
clk_disable_unprepare(nfc->clk);
return err;
diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c
index 3b28db458ea0..0cf0ac07a8c2 100644
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -89,7 +89,7 @@ static void xway_select_chip(struct mtd_info *mtd, int chip)
static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
unsigned long flags;
@@ -118,7 +118,7 @@ static int xway_dev_ready(struct mtd_info *mtd)
static unsigned char xway_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
unsigned long flags;
int ret;
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 9ed6038e47d2..ede407d6e106 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -26,9 +26,10 @@ static bool node_has_compatible(struct device_node *pp)
}
static int parse_ofpart_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
+ struct mtd_partition *parts;
struct device_node *mtd_node;
struct device_node *ofpart_node;
const char *partname;
@@ -37,10 +38,8 @@ static int parse_ofpart_partitions(struct mtd_info *master,
bool dedicated = true;
- if (!data)
- return 0;
-
- mtd_node = data->of_node;
+ /* Pull of_node from the master device node */
+ mtd_node = mtd_get_of_node(master);
if (!mtd_node)
return 0;
@@ -72,8 +71,8 @@ static int parse_ofpart_partitions(struct mtd_info *master,
if (nr_parts == 0)
return 0;
- *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
- if (!*pparts)
+ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+ if (!parts)
return -ENOMEM;
i = 0;
@@ -107,19 +106,19 @@ static int parse_ofpart_partitions(struct mtd_info *master,
goto ofpart_fail;
}
- (*pparts)[i].offset = of_read_number(reg, a_cells);
- (*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
+ parts[i].offset = of_read_number(reg, a_cells);
+ parts[i].size = of_read_number(reg + a_cells, s_cells);
partname = of_get_property(pp, "label", &len);
if (!partname)
partname = of_get_property(pp, "name", &len);
- (*pparts)[i].name = partname;
+ parts[i].name = partname;
if (of_get_property(pp, "read-only", &len))
- (*pparts)[i].mask_flags |= MTD_WRITEABLE;
+ parts[i].mask_flags |= MTD_WRITEABLE;
if (of_get_property(pp, "lock", &len))
- (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
+ parts[i].mask_flags |= MTD_POWERUP_LOCK;
i++;
}
@@ -127,6 +126,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
if (!nr_parts)
goto ofpart_none;
+ *pparts = parts;
return nr_parts;
ofpart_fail:
@@ -135,21 +135,20 @@ ofpart_fail:
ret = -EINVAL;
ofpart_none:
of_node_put(pp);
- kfree(*pparts);
- *pparts = NULL;
+ kfree(parts);
return ret;
}
static struct mtd_part_parser ofpart_parser = {
- .owner = THIS_MODULE,
.parse_fn = parse_ofpart_partitions,
.name = "ofpart",
};
static int parse_ofoldpart_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
+ struct mtd_partition *parts;
struct device_node *dp;
int i, plen, nr_parts;
const struct {
@@ -157,10 +156,8 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
} *part;
const char *names;
- if (!data)
- return 0;
-
- dp = data->of_node;
+ /* Pull of_node from the master device node */
+ dp = mtd_get_of_node(master);
if (!dp)
return 0;
@@ -173,37 +170,37 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
nr_parts = plen / sizeof(part[0]);
- *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
- if (!*pparts)
+ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+ if (!parts)
return -ENOMEM;
names = of_get_property(dp, "partition-names", &plen);
for (i = 0; i < nr_parts; i++) {
- (*pparts)[i].offset = be32_to_cpu(part->offset);
- (*pparts)[i].size = be32_to_cpu(part->len) & ~1;
+ parts[i].offset = be32_to_cpu(part->offset);
+ parts[i].size = be32_to_cpu(part->len) & ~1;
/* bit 0 set signifies read only partition */
if (be32_to_cpu(part->len) & 1)
- (*pparts)[i].mask_flags = MTD_WRITEABLE;
+ parts[i].mask_flags = MTD_WRITEABLE;
if (names && (plen > 0)) {
int len = strlen(names) + 1;
- (*pparts)[i].name = names;
+ parts[i].name = names;
plen -= len;
names += len;
} else {
- (*pparts)[i].name = "unnamed";
+ parts[i].name = "unnamed";
}
part++;
}
+ *pparts = parts;
return nr_parts;
}
static struct mtd_part_parser ofoldpart_parser = {
- .owner = THIS_MODULE,
.parse_fn = parse_ofoldpart_partitions,
.name = "ofoldpart",
};
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 3e0285696227..0aacf125938b 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -614,7 +614,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
struct onenand_chip *this;
int r;
struct resource *res;
- struct mtd_part_parser_data ppdata = {};
pdata = dev_get_platdata(&pdev->dev);
if (pdata == NULL) {
@@ -713,6 +712,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
c->mtd.priv = &c->onenand;
c->mtd.dev.parent = &pdev->dev;
+ mtd_set_of_node(&c->mtd, pdata->of_node);
this = &c->onenand;
if (c->dma_channel >= 0) {
@@ -743,10 +743,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
if ((r = onenand_scan(&c->mtd, 1)) < 0)
goto err_release_regulator;
- ppdata.of_node = pdata->of_node;
- r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
- pdata ? pdata->parts : NULL,
- pdata ? pdata->nr_parts : 0);
+ r = mtd_device_register(&c->mtd, pdata ? pdata->parts : NULL,
+ pdata ? pdata->nr_parts : 0);
if (r)
goto err_release_onenand;
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 5da911ebdf49..7623ac5fc586 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -57,7 +57,7 @@ static inline int redboot_checksum(struct fis_image_desc *img)
}
static int parse_redboot_partitions(struct mtd_info *master,
- struct mtd_partition **pparts,
+ const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
int nrparts = 0;
@@ -290,28 +290,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
static struct mtd_part_parser redboot_parser = {
- .owner = THIS_MODULE,
.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");
-
-static int __init redboot_parser_init(void)
-{
- register_mtd_parser(&redboot_parser);
- return 0;
-}
-
-static void __exit redboot_parser_exit(void)
-{
- deregister_mtd_parser(&redboot_parser);
-}
-
-module_init(redboot_parser_init);
-module_exit(redboot_parser_exit);
-
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/sm_ftl.c b/drivers/mtd/sm_ftl.c
index c23184a47fc4..b096f8bb05ba 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -206,9 +206,10 @@ static loff_t sm_mkoffset(struct sm_ftl *ftl, int zone, int block, int boffset)
}
/* Breaks offset into parts */
-static void sm_break_offset(struct sm_ftl *ftl, loff_t offset,
+static void sm_break_offset(struct sm_ftl *ftl, loff_t loffset,
int *zone, int *block, int *boffset)
{
+ u64 offset = loffset;
*boffset = do_div(offset, ftl->block_size);
*block = do_div(offset, ftl->max_lba);
*zone = offset >= ftl->zone_count ? -1 : offset;
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 2fe2a7e90fa9..0dc927540b3d 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -7,6 +7,13 @@ menuconfig MTD_SPI_NOR
if MTD_SPI_NOR
+config MTD_MT81xx_NOR
+ tristate "Mediatek MT81xx SPI NOR flash controller"
+ help
+ This enables access to SPI NOR flash, using MT81xx SPI NOR flash
+ controller. This controller does not support generic SPI BUS, it only
+ supports SPI NOR Flash.
+
config MTD_SPI_NOR_USE_4K_SECTORS
bool "Use small 4096 B erase sectors"
default y
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index e53333ef8582..0bf3a7f81675 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
+obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 7b10ed413983..54640f1eb3a1 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -269,7 +269,7 @@ struct fsl_qspi {
struct clk *clk, *clk_en;
struct device *dev;
struct completion c;
- struct fsl_qspi_devtype_data *devtype_data;
+ const struct fsl_qspi_devtype_data *devtype_data;
u32 nor_size;
u32 nor_num;
u32 clk_rate;
@@ -927,15 +927,12 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
static int fsl_qspi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct mtd_part_parser_data ppdata;
struct device *dev = &pdev->dev;
struct fsl_qspi *q;
struct resource *res;
struct spi_nor *nor;
struct mtd_info *mtd;
int ret, i = 0;
- const struct of_device_id *of_id =
- of_match_device(fsl_qspi_dt_ids, &pdev->dev);
q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
if (!q)
@@ -946,7 +943,9 @@ static int fsl_qspi_probe(struct platform_device *pdev)
return -ENODEV;
q->dev = dev;
- q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data;
+ q->devtype_data = of_device_get_match_data(dev);
+ if (!q->devtype_data)
+ return -ENODEV;
platform_set_drvdata(pdev, q);
/* find the resources */
@@ -1013,7 +1012,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
mtd = &nor->mtd;
nor->dev = dev;
- nor->flash_node = np;
+ spi_nor_set_flash_node(nor, np);
nor->priv = q;
/* fill the hooks */
@@ -1038,8 +1037,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
if (ret)
goto mutex_failed;
- ppdata.of_node = np;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
if (ret)
goto mutex_failed;
diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c
new file mode 100644
index 000000000000..d5f850d035bb
--- /dev/null
+++ b/drivers/mtd/spi-nor/mtk-quadspi.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Bayi Cheng <bayi.cheng@mediatek.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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+
+#define MTK_NOR_CMD_REG 0x00
+#define MTK_NOR_CNT_REG 0x04
+#define MTK_NOR_RDSR_REG 0x08
+#define MTK_NOR_RDATA_REG 0x0c
+#define MTK_NOR_RADR0_REG 0x10
+#define MTK_NOR_RADR1_REG 0x14
+#define MTK_NOR_RADR2_REG 0x18
+#define MTK_NOR_WDATA_REG 0x1c
+#define MTK_NOR_PRGDATA0_REG 0x20
+#define MTK_NOR_PRGDATA1_REG 0x24
+#define MTK_NOR_PRGDATA2_REG 0x28
+#define MTK_NOR_PRGDATA3_REG 0x2c
+#define MTK_NOR_PRGDATA4_REG 0x30
+#define MTK_NOR_PRGDATA5_REG 0x34
+#define MTK_NOR_SHREG0_REG 0x38
+#define MTK_NOR_SHREG1_REG 0x3c
+#define MTK_NOR_SHREG2_REG 0x40
+#define MTK_NOR_SHREG3_REG 0x44
+#define MTK_NOR_SHREG4_REG 0x48
+#define MTK_NOR_SHREG5_REG 0x4c
+#define MTK_NOR_SHREG6_REG 0x50
+#define MTK_NOR_SHREG7_REG 0x54
+#define MTK_NOR_SHREG8_REG 0x58
+#define MTK_NOR_SHREG9_REG 0x5c
+#define MTK_NOR_CFG1_REG 0x60
+#define MTK_NOR_CFG2_REG 0x64
+#define MTK_NOR_CFG3_REG 0x68
+#define MTK_NOR_STATUS0_REG 0x70
+#define MTK_NOR_STATUS1_REG 0x74
+#define MTK_NOR_STATUS2_REG 0x78
+#define MTK_NOR_STATUS3_REG 0x7c
+#define MTK_NOR_FLHCFG_REG 0x84
+#define MTK_NOR_TIME_REG 0x94
+#define MTK_NOR_PP_DATA_REG 0x98
+#define MTK_NOR_PREBUF_STUS_REG 0x9c
+#define MTK_NOR_DELSEL0_REG 0xa0
+#define MTK_NOR_DELSEL1_REG 0xa4
+#define MTK_NOR_INTRSTUS_REG 0xa8
+#define MTK_NOR_INTREN_REG 0xac
+#define MTK_NOR_CHKSUM_CTL_REG 0xb8
+#define MTK_NOR_CHKSUM_REG 0xbc
+#define MTK_NOR_CMD2_REG 0xc0
+#define MTK_NOR_WRPROT_REG 0xc4
+#define MTK_NOR_RADR3_REG 0xc8
+#define MTK_NOR_DUAL_REG 0xcc
+#define MTK_NOR_DELSEL2_REG 0xd0
+#define MTK_NOR_DELSEL3_REG 0xd4
+#define MTK_NOR_DELSEL4_REG 0xd8
+
+/* commands for mtk nor controller */
+#define MTK_NOR_READ_CMD 0x0
+#define MTK_NOR_RDSR_CMD 0x2
+#define MTK_NOR_PRG_CMD 0x4
+#define MTK_NOR_WR_CMD 0x10
+#define MTK_NOR_PIO_WR_CMD 0x90
+#define MTK_NOR_WRSR_CMD 0x20
+#define MTK_NOR_PIO_READ_CMD 0x81
+#define MTK_NOR_WR_BUF_ENABLE 0x1
+#define MTK_NOR_WR_BUF_DISABLE 0x0
+#define MTK_NOR_ENABLE_SF_CMD 0x30
+#define MTK_NOR_DUAD_ADDR_EN 0x8
+#define MTK_NOR_QUAD_READ_EN 0x4
+#define MTK_NOR_DUAL_ADDR_EN 0x2
+#define MTK_NOR_DUAL_READ_EN 0x1
+#define MTK_NOR_DUAL_DISABLE 0x0
+#define MTK_NOR_FAST_READ 0x1
+
+#define SFLASH_WRBUF_SIZE 128
+
+/* Can shift up to 48 bits (6 bytes) of TX/RX */
+#define MTK_NOR_MAX_RX_TX_SHIFT 6
+/* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */
+#define MTK_NOR_MAX_SHIFT 7
+
+/* Helpers for accessing the program data / shift data registers */
+#define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n))
+#define MTK_NOR_SHREG(n) (MTK_NOR_SHREG0_REG + 4 * (n))
+
+struct mt8173_nor {
+ struct spi_nor nor;
+ struct device *dev;
+ void __iomem *base; /* nor flash base address */
+ struct clk *spi_clk;
+ struct clk *nor_clk;
+};
+
+static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
+{
+ struct spi_nor *nor = &mt8173_nor->nor;
+
+ switch (nor->flash_read) {
+ case SPI_NOR_FAST:
+ writeb(nor->read_opcode, mt8173_nor->base +
+ MTK_NOR_PRGDATA3_REG);
+ writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
+ MTK_NOR_CFG1_REG);
+ break;
+ case SPI_NOR_DUAL:
+ writeb(nor->read_opcode, mt8173_nor->base +
+ MTK_NOR_PRGDATA3_REG);
+ writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
+ MTK_NOR_DUAL_REG);
+ break;
+ case SPI_NOR_QUAD:
+ writeb(nor->read_opcode, mt8173_nor->base +
+ MTK_NOR_PRGDATA4_REG);
+ writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
+ MTK_NOR_DUAL_REG);
+ break;
+ default:
+ writeb(MTK_NOR_DUAL_DISABLE, mt8173_nor->base +
+ MTK_NOR_DUAL_REG);
+ break;
+ }
+}
+
+static int mt8173_nor_execute_cmd(struct mt8173_nor *mt8173_nor, u8 cmdval)
+{
+ int reg;
+ u8 val = cmdval & 0x1f;
+
+ writeb(cmdval, mt8173_nor->base + MTK_NOR_CMD_REG);
+ return readl_poll_timeout(mt8173_nor->base + MTK_NOR_CMD_REG, reg,
+ !(reg & val), 100, 10000);
+}
+
+static int mt8173_nor_do_tx_rx(struct mt8173_nor *mt8173_nor, u8 op,
+ u8 *tx, int txlen, u8 *rx, int rxlen)
+{
+ int len = 1 + txlen + rxlen;
+ int i, ret, idx;
+
+ if (len > MTK_NOR_MAX_SHIFT)
+ return -EINVAL;
+
+ writeb(len * 8, mt8173_nor->base + MTK_NOR_CNT_REG);
+
+ /* start at PRGDATA5, go down to PRGDATA0 */
+ idx = MTK_NOR_MAX_RX_TX_SHIFT - 1;
+
+ /* opcode */
+ writeb(op, mt8173_nor->base + MTK_NOR_PRG_REG(idx));
+ idx--;
+
+ /* program TX data */
+ for (i = 0; i < txlen; i++, idx--)
+ writeb(tx[i], mt8173_nor->base + MTK_NOR_PRG_REG(idx));
+
+ /* clear out rest of TX registers */
+ while (idx >= 0) {
+ writeb(0, mt8173_nor->base + MTK_NOR_PRG_REG(idx));
+ idx--;
+ }
+
+ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PRG_CMD);
+ if (ret)
+ return ret;
+
+ /* restart at first RX byte */
+ idx = rxlen - 1;
+
+ /* read out RX data */
+ for (i = 0; i < rxlen; i++, idx--)
+ rx[i] = readb(mt8173_nor->base + MTK_NOR_SHREG(idx));
+
+ return 0;
+}
+
+/* Do a WRSR (Write Status Register) command */
+static int mt8173_nor_wr_sr(struct mt8173_nor *mt8173_nor, u8 sr)
+{
+ writeb(sr, mt8173_nor->base + MTK_NOR_PRGDATA5_REG);
+ writeb(8, mt8173_nor->base + MTK_NOR_CNT_REG);
+ return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WRSR_CMD);
+}
+
+static int mt8173_nor_write_buffer_enable(struct mt8173_nor *mt8173_nor)
+{
+ u8 reg;
+
+ /* the bit0 of MTK_NOR_CFG2_REG is pre-fetch buffer
+ * 0: pre-fetch buffer use for read
+ * 1: pre-fetch buffer use for page program
+ */
+ writel(MTK_NOR_WR_BUF_ENABLE, mt8173_nor->base + MTK_NOR_CFG2_REG);
+ return readb_poll_timeout(mt8173_nor->base + MTK_NOR_CFG2_REG, reg,
+ 0x01 == (reg & 0x01), 100, 10000);
+}
+
+static int mt8173_nor_write_buffer_disable(struct mt8173_nor *mt8173_nor)
+{
+ u8 reg;
+
+ writel(MTK_NOR_WR_BUF_DISABLE, mt8173_nor->base + MTK_NOR_CFG2_REG);
+ return readb_poll_timeout(mt8173_nor->base + MTK_NOR_CFG2_REG, reg,
+ MTK_NOR_WR_BUF_DISABLE == (reg & 0x1), 100,
+ 10000);
+}
+
+static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR0_REG + i * 4);
+ addr >>= 8;
+ }
+ /* Last register is non-contiguous */
+ writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR3_REG);
+}
+
+static int mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length,
+ size_t *retlen, u_char *buffer)
+{
+ int i, ret;
+ int addr = (int)from;
+ u8 *buf = (u8 *)buffer;
+ struct mt8173_nor *mt8173_nor = nor->priv;
+
+ /* set mode for fast read mode ,dual mode or quad mode */
+ mt8173_nor_set_read_mode(mt8173_nor);
+ mt8173_nor_set_addr(mt8173_nor, addr);
+
+ for (i = 0; i < length; i++, (*retlen)++) {
+ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_READ_CMD);
+ if (ret < 0)
+ return ret;
+ buf[i] = readb(mt8173_nor->base + MTK_NOR_RDATA_REG);
+ }
+ return 0;
+}
+
+static int mt8173_nor_write_single_byte(struct mt8173_nor *mt8173_nor,
+ int addr, int length, u8 *data)
+{
+ int i, ret;
+
+ mt8173_nor_set_addr(mt8173_nor, addr);
+
+ for (i = 0; i < length; i++) {
+ writeb(*data++, mt8173_nor->base + MTK_NOR_WDATA_REG);
+ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_WR_CMD);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int mt8173_nor_write_buffer(struct mt8173_nor *mt8173_nor, int addr,
+ const u8 *buf)
+{
+ int i, bufidx, data;
+
+ mt8173_nor_set_addr(mt8173_nor, addr);
+
+ bufidx = 0;
+ for (i = 0; i < SFLASH_WRBUF_SIZE; i += 4) {
+ data = buf[bufidx + 3]<<24 | buf[bufidx + 2]<<16 |
+ buf[bufidx + 1]<<8 | buf[bufidx];
+ bufidx += 4;
+ writel(data, mt8173_nor->base + MTK_NOR_PP_DATA_REG);
+ }
+ return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WR_CMD);
+}
+
+static void mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ int ret;
+ struct mt8173_nor *mt8173_nor = nor->priv;
+
+ ret = mt8173_nor_write_buffer_enable(mt8173_nor);
+ if (ret < 0)
+ dev_warn(mt8173_nor->dev, "write buffer enable failed!\n");
+
+ while (len >= SFLASH_WRBUF_SIZE) {
+ ret = mt8173_nor_write_buffer(mt8173_nor, to, buf);
+ if (ret < 0)
+ dev_err(mt8173_nor->dev, "write buffer failed!\n");
+ len -= SFLASH_WRBUF_SIZE;
+ to += SFLASH_WRBUF_SIZE;
+ buf += SFLASH_WRBUF_SIZE;
+ (*retlen) += SFLASH_WRBUF_SIZE;
+ }
+ ret = mt8173_nor_write_buffer_disable(mt8173_nor);
+ if (ret < 0)
+ dev_warn(mt8173_nor->dev, "write buffer disable failed!\n");
+
+ if (len) {
+ ret = mt8173_nor_write_single_byte(mt8173_nor, to, (int)len,
+ (u8 *)buf);
+ if (ret < 0)
+ dev_err(mt8173_nor->dev, "write single byte failed!\n");
+ (*retlen) += len;
+ }
+}
+
+static int mt8173_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+ int ret;
+ struct mt8173_nor *mt8173_nor = nor->priv;
+
+ switch (opcode) {
+ case SPINOR_OP_RDSR:
+ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_RDSR_CMD);
+ if (ret < 0)
+ return ret;
+ if (len == 1)
+ *buf = readb(mt8173_nor->base + MTK_NOR_RDSR_REG);
+ else
+ dev_err(mt8173_nor->dev, "len should be 1 for read status!\n");
+ break;
+ default:
+ ret = mt8173_nor_do_tx_rx(mt8173_nor, opcode, NULL, 0, buf, len);
+ break;
+ }
+ return ret;
+}
+
+static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+ int len)
+{
+ int ret;
+ struct mt8173_nor *mt8173_nor = nor->priv;
+
+ switch (opcode) {
+ case SPINOR_OP_WRSR:
+ /* We only handle 1 byte */
+ ret = mt8173_nor_wr_sr(mt8173_nor, *buf);
+ break;
+ default:
+ ret = mt8173_nor_do_tx_rx(mt8173_nor, opcode, buf, len, NULL, 0);
+ if (ret)
+ dev_warn(mt8173_nor->dev, "write reg failure!\n");
+ break;
+ }
+ return ret;
+}
+
+static int __init mtk_nor_init(struct mt8173_nor *mt8173_nor,
+ struct device_node *flash_node)
+{
+ int ret;
+ struct spi_nor *nor;
+
+ /* initialize controller to accept commands */
+ writel(MTK_NOR_ENABLE_SF_CMD, mt8173_nor->base + MTK_NOR_WRPROT_REG);
+
+ nor = &mt8173_nor->nor;
+ nor->dev = mt8173_nor->dev;
+ nor->priv = mt8173_nor;
+ spi_nor_set_flash_node(nor, flash_node);
+
+ /* fill the hooks to spi nor */
+ nor->read = mt8173_nor_read;
+ nor->read_reg = mt8173_nor_read_reg;
+ nor->write = mt8173_nor_write;
+ nor->write_reg = mt8173_nor_write_reg;
+ nor->mtd.name = "mtk_nor";
+ /* initialized with NULL */
+ ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
+ if (ret)
+ return ret;
+
+ return mtd_device_register(&nor->mtd, NULL, 0);
+}
+
+static int mtk_nor_drv_probe(struct platform_device *pdev)
+{
+ struct device_node *flash_np;
+ struct resource *res;
+ int ret;
+ struct mt8173_nor *mt8173_nor;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "No DT found\n");
+ return -EINVAL;
+ }
+
+ mt8173_nor = devm_kzalloc(&pdev->dev, sizeof(*mt8173_nor), GFP_KERNEL);
+ if (!mt8173_nor)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, mt8173_nor);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mt8173_nor->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mt8173_nor->base))
+ return PTR_ERR(mt8173_nor->base);
+
+ mt8173_nor->spi_clk = devm_clk_get(&pdev->dev, "spi");
+ if (IS_ERR(mt8173_nor->spi_clk))
+ return PTR_ERR(mt8173_nor->spi_clk);
+
+ mt8173_nor->nor_clk = devm_clk_get(&pdev->dev, "sf");
+ if (IS_ERR(mt8173_nor->nor_clk))
+ return PTR_ERR(mt8173_nor->nor_clk);
+
+ mt8173_nor->dev = &pdev->dev;
+ ret = clk_prepare_enable(mt8173_nor->spi_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(mt8173_nor->nor_clk);
+ if (ret) {
+ clk_disable_unprepare(mt8173_nor->spi_clk);
+ return ret;
+ }
+ /* only support one attached flash */
+ flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
+ if (!flash_np) {
+ dev_err(&pdev->dev, "no SPI flash device to configure\n");
+ ret = -ENODEV;
+ goto nor_free;
+ }
+ ret = mtk_nor_init(mt8173_nor, flash_np);
+
+nor_free:
+ if (ret) {
+ clk_disable_unprepare(mt8173_nor->spi_clk);
+ clk_disable_unprepare(mt8173_nor->nor_clk);
+ }
+ return ret;
+}
+
+static int mtk_nor_drv_remove(struct platform_device *pdev)
+{
+ struct mt8173_nor *mt8173_nor = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(mt8173_nor->spi_clk);
+ clk_disable_unprepare(mt8173_nor->nor_clk);
+ return 0;
+}
+
+static const struct of_device_id mtk_nor_of_ids[] = {
+ { .compatible = "mediatek,mt8173-nor"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_nor_of_ids);
+
+static struct platform_driver mtk_nor_driver = {
+ .probe = mtk_nor_drv_probe,
+ .remove = mtk_nor_drv_remove,
+ .driver = {
+ .name = "mtk-nor",
+ .of_match_table = mtk_nor_of_ids,
+ },
+};
+
+module_platform_driver(mtk_nor_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek SPI NOR Flash Driver");
diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
index 9e82098ae644..ae428cb0e04b 100644
--- a/drivers/mtd/spi-nor/nxp-spifi.c
+++ b/drivers/mtd/spi-nor/nxp-spifi.c
@@ -271,7 +271,6 @@ static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
struct device_node *np)
{
- struct mtd_part_parser_data ppdata;
enum read_mode flash_read;
u32 ctrl, property;
u16 mode = 0;
@@ -330,7 +329,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
writel(ctrl, spifi->io_base + SPIFI_CTRL);
spifi->nor.dev = spifi->dev;
- spifi->nor.flash_node = np;
+ spi_nor_set_flash_node(&spifi->nor, np);
spifi->nor.priv = spifi;
spifi->nor.read = nxp_spifi_read;
spifi->nor.write = nxp_spifi_write;
@@ -361,8 +360,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
return ret;
}
- ppdata.of_node = np;
- ret = mtd_device_parse_register(&spifi->nor.mtd, NULL, &ppdata, NULL, 0);
+ ret = mtd_device_register(&spifi->nor.mtd, NULL, 0);
if (ret) {
dev_err(spifi->dev, "mtd device parse failed\n");
return ret;
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 32477c4eb421..ed0c19c558b5 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -38,6 +38,7 @@
#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
#define SPI_NOR_MAX_ID_LEN 6
+#define SPI_NOR_MAX_ADDR_WIDTH 4
struct flash_info {
char *name;
@@ -313,6 +314,29 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
}
/*
+ * Initiate the erasure of a single sector
+ */
+static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
+{
+ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
+ int i;
+
+ if (nor->erase)
+ return nor->erase(nor, addr);
+
+ /*
+ * Default implementation, if driver doesn't have a specialized HW
+ * control
+ */
+ for (i = nor->addr_width - 1; i >= 0; i--) {
+ buf[i] = addr & 0xff;
+ addr >>= 8;
+ }
+
+ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
+}
+
+/*
* Erase an address range on the nor chip. The address range may extend
* one or more erase sectors. Return an error is there is a problem erasing.
*/
@@ -371,10 +395,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
while (len) {
write_enable(nor);
- if (nor->erase(nor, addr)) {
- ret = -EIO;
+ ret = spi_nor_erase_sector(nor, addr);
+ if (ret)
goto erase_err;
- }
addr += mtd->erasesize;
len -= mtd->erasesize;
@@ -387,17 +410,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
write_disable(nor);
+erase_err:
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
- instr->state = MTD_ERASE_DONE;
+ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
mtd_erase_callback(instr);
return ret;
-
-erase_err:
- spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
- instr->state = MTD_ERASE_FAILED;
- return ret;
}
static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
@@ -459,11 +478,14 @@ static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
struct mtd_info *mtd = &nor->mtd;
- u8 status_old, status_new;
+ int status_old, status_new;
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
u8 shift = ffs(mask) - 1, pow, val;
+ int ret;
status_old = read_sr(nor);
+ if (status_old < 0)
+ return status_old;
/* SPI NOR always locks to the end */
if (ofs + len != mtd->size) {
@@ -498,7 +520,10 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
return -EINVAL;
write_enable(nor);
- return write_sr(nor, status_new);
+ ret = write_sr(nor, status_new);
+ if (ret)
+ return ret;
+ return spi_nor_wait_till_ready(nor);
}
/*
@@ -509,11 +534,14 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
struct mtd_info *mtd = &nor->mtd;
- uint8_t status_old, status_new;
+ int status_old, status_new;
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
u8 shift = ffs(mask) - 1, pow, val;
+ int ret;
status_old = read_sr(nor);
+ if (status_old < 0)
+ return status_old;
/* Cannot unlock; would unlock larger region than requested */
if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
@@ -546,7 +574,10 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
return -EINVAL;
write_enable(nor);
- return write_sr(nor, status_new);
+ ret = write_sr(nor, status_new);
+ if (ret)
+ return ret;
+ return spi_nor_wait_till_ready(nor);
}
/*
@@ -715,9 +746,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
{ "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
- { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
+ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
+ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
{ "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) },
@@ -856,7 +887,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
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);
+ dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
return ERR_PTR(tmp);
}
@@ -867,7 +898,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
return &spi_nor_ids[tmp];
}
}
- dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
+ dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
id[0], id[1], id[2]);
return ERR_PTR(-ENODEV);
}
@@ -1013,6 +1044,8 @@ static int macronix_quad_enable(struct spi_nor *nor)
int ret, val;
val = read_sr(nor);
+ if (val < 0)
+ return val;
write_enable(nor);
write_sr(nor, val | SR_QUAD_EN_MX);
@@ -1138,7 +1171,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
static int spi_nor_check(struct spi_nor *nor)
{
if (!nor->dev || !nor->read || !nor->write ||
- !nor->read_reg || !nor->write_reg || !nor->erase) {
+ !nor->read_reg || !nor->write_reg) {
pr_err("spi-nor: please fill all the necessary fields!\n");
return -EINVAL;
}
@@ -1151,7 +1184,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
const struct flash_info *info = NULL;
struct device *dev = nor->dev;
struct mtd_info *mtd = &nor->mtd;
- struct device_node *np = nor->flash_node;
+ struct device_node *np = spi_nor_get_flash_node(nor);
int ret;
int i;
@@ -1338,6 +1371,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
nor->addr_width = 3;
}
+ if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
+ dev_err(dev, "address width is too large: %u\n",
+ nor->addr_width);
+ return -EINVAL;
+ }
+
nor->read_dummy = spi_nor_read_dummy_cycles(nor);
dev_info(dev, "%s (%lld Kbytes)\n", info->name,
diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c
index ba1890d5632c..ff1e0565b020 100644
--- a/drivers/mtd/tests/pagetest.c
+++ b/drivers/mtd/tests/pagetest.c
@@ -127,13 +127,12 @@ static int crosstest(void)
unsigned char *pp1, *pp2, *pp3, *pp4;
pr_info("crosstest\n");
- pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
+ pp1 = kzalloc(pgsize * 4, GFP_KERNEL);
if (!pp1)
return -ENOMEM;
pp2 = pp1 + pgsize;
pp3 = pp2 + pgsize;
pp4 = pp3 + pgsize;
- memset(pp1, 0, pgsize * 4);
addr0 = 0;
for (i = 0; i < ebcnt && bbt[i]; ++i)
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 1c5f3b273e6a..79e1a0282163 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -2459,8 +2459,13 @@ boomerang_interrupt(int irq, void *dev_id)
struct sk_buff *skb = vp->tx_skbuff[entry];
#if DO_ZEROCOPY
int i;
- for (i=0; i<=skb_shinfo(skb)->nr_frags; i++)
- pci_unmap_single(VORTEX_PCI(vp),
+ pci_unmap_single(VORTEX_PCI(vp),
+ le32_to_cpu(vp->tx_ring[entry].frag[0].addr),
+ le32_to_cpu(vp->tx_ring[entry].frag[0].length),
+ PCI_DMA_TODEVICE);
+
+ for (i=1; i<=skb_shinfo(skb)->nr_frags; i++)
+ pci_unmap_page(VORTEX_PCI(vp),
le32_to_cpu(vp->tx_ring[entry].frag[i].addr),
le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF,
PCI_DMA_TODEVICE);
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index c7798d360512..06f6cffdfaf5 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -466,6 +466,11 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
len -= ETH_FCS_LEN;
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+ if (unlikely(!skb)) {
+ bgmac_err(bgmac, "build_skb failed\n");
+ put_page(virt_to_head_page(buf));
+ break;
+ }
skb_put(skb, BGMAC_RX_FRAME_OFFSET +
BGMAC_RX_BUF_OFFSET + len);
skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 21a0cfc3e7ec..771cc267f217 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -542,39 +542,50 @@ bnad_cq_drop_packet(struct bnad *bnad, struct bna_rcb *rcb,
}
static void
-bnad_cq_setup_skb_frags(struct bna_rcb *rcb, struct sk_buff *skb,
- u32 sop_ci, u32 nvecs, u32 last_fraglen)
+bnad_cq_setup_skb_frags(struct bna_ccb *ccb, struct sk_buff *skb, u32 nvecs)
{
+ struct bna_rcb *rcb;
struct bnad *bnad;
- u32 ci, vec, len, totlen = 0;
struct bnad_rx_unmap_q *unmap_q;
- struct bnad_rx_unmap *unmap;
+ struct bna_cq_entry *cq, *cmpl;
+ u32 ci, pi, totlen = 0;
+
+ cq = ccb->sw_q;
+ pi = ccb->producer_index;
+ cmpl = &cq[pi];
+ rcb = bna_is_small_rxq(cmpl->rxq_id) ? ccb->rcb[1] : ccb->rcb[0];
unmap_q = rcb->unmap_q;
bnad = rcb->bnad;
+ ci = rcb->consumer_index;
/* prefetch header */
- prefetch(page_address(unmap_q->unmap[sop_ci].page) +
- unmap_q->unmap[sop_ci].page_offset);
+ prefetch(page_address(unmap_q->unmap[ci].page) +
+ unmap_q->unmap[ci].page_offset);
+
+ while (nvecs--) {
+ struct bnad_rx_unmap *unmap;
+ u32 len;
- for (vec = 1, ci = sop_ci; vec <= nvecs; vec++) {
unmap = &unmap_q->unmap[ci];
BNA_QE_INDX_INC(ci, rcb->q_depth);
dma_unmap_page(&bnad->pcidev->dev,
- dma_unmap_addr(&unmap->vector, dma_addr),
- unmap->vector.len, DMA_FROM_DEVICE);
+ dma_unmap_addr(&unmap->vector, dma_addr),
+ unmap->vector.len, DMA_FROM_DEVICE);
- len = (vec == nvecs) ?
- last_fraglen : unmap->vector.len;
+ len = ntohs(cmpl->length);
skb->truesize += unmap->vector.len;
totlen += len;
skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
- unmap->page, unmap->page_offset, len);
+ unmap->page, unmap->page_offset, len);
unmap->page = NULL;
unmap->vector.len = 0;
+
+ BNA_QE_INDX_INC(pi, ccb->q_depth);
+ cmpl = &cq[pi];
}
skb->len += totlen;
@@ -704,7 +715,7 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type))
bnad_cq_setup_skb(bnad, skb, unmap, len);
else
- bnad_cq_setup_skb_frags(rcb, skb, sop_ci, nvecs, len);
+ bnad_cq_setup_skb_frags(ccb, skb, nvecs);
rcb->rxq->rx_packets++;
rcb->rxq->rx_bytes += totlen;
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index c56347536f6b..9d9984a87d42 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -1040,6 +1040,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
/* close possible race with dev_close */
if (unlikely(!netif_running(dev))) {
queue_writel(queue, IDR, -1);
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, -1);
break;
}
@@ -1561,6 +1563,8 @@ static void macb_reset_hw(struct macb *bp)
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
queue_writel(queue, IDR, -1);
queue_readl(queue, ISR);
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, -1);
}
}
diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
index 6b1261c0b1c2..7c92eb854925 100644
--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
@@ -1434,7 +1434,6 @@ struct fman_mac *dtsec_config(struct fman_mac_params *params)
dtsec->tbiphy = of_phy_find_device(params->internal_phy_node);
if (!dtsec->tbiphy) {
pr_err("of_phy_find_device (TBI PHY) failed\n");
- put_device(&dtsec->tbiphy->mdio.dev);
goto err_dtsec_drv_param;
}
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 622005abf859..f3c63dce1e30 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -29,7 +29,7 @@
#include <asm/io.h>
#if IS_ENABLED(CONFIG_UCC_GETH)
-#include <asm/ucc.h> /* for ucc_set_qe_mux_mii_mng() */
+#include <soc/fsl/qe/ucc.h>
#endif
#include "gianfar.h"
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index cbddbe2d0429..5bf1ade28315 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -40,10 +40,10 @@
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
-#include <asm/ucc.h>
-#include <asm/ucc_fast.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/ucc.h>
+#include <soc/fsl/qe/ucc_fast.h>
#include <asm/machdep.h>
#include "ucc_geth.h"
diff --git a/drivers/net/ethernet/freescale/ucc_geth.h b/drivers/net/ethernet/freescale/ucc_geth.h
index 75f337163ce3..5da19b440a6a 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.h
+++ b/drivers/net/ethernet/freescale/ucc_geth.h
@@ -22,11 +22,11 @@
#include <linux/list.h>
#include <linux/if_ether.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
-#include <asm/ucc.h>
-#include <asm/ucc_fast.h>
+#include <soc/fsl/qe/ucc.h>
+#include <soc/fsl/qe/ucc_fast.h>
#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
#define DRV_NAME "ucc_geth"
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index 253f8ed0537a..0c4afe95ef54 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -500,8 +500,10 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
while (cnt && !last) {
buf = priv->rx_buf[priv->rx_head];
skb = build_skb(buf, priv->rx_buf_size);
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
net_dbg_ratelimited("build_skb failed\n");
+ goto refill;
+ }
dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head],
RX_BUF_SIZE, DMA_FROM_DEVICE);
@@ -528,6 +530,7 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
rx++;
}
+refill:
buf = netdev_alloc_frag(priv->rx_buf_size);
if (!buf)
goto done;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index d2263c72bd8a..12188807468c 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -369,8 +369,17 @@ int hns_rcb_common_init_hw(struct rcb_common_cb *rcb_common)
dsaf_write_dev(rcb_common, RCB_COM_CFG_ENDIAN_REG,
HNS_RCB_COMMON_ENDIAN);
- dsaf_write_dev(rcb_common, RCB_COM_CFG_FNA_REG, 0x0);
- dsaf_write_dev(rcb_common, RCB_COM_CFG_FA_REG, 0x1);
+ if (AE_IS_VER1(rcb_common->dsaf_dev->dsaf_ver)) {
+ dsaf_write_dev(rcb_common, RCB_COM_CFG_FNA_REG, 0x0);
+ dsaf_write_dev(rcb_common, RCB_COM_CFG_FA_REG, 0x1);
+ } else {
+ dsaf_set_dev_bit(rcb_common, RCBV2_COM_CFG_USER_REG,
+ RCB_COM_CFG_FNA_B, false);
+ dsaf_set_dev_bit(rcb_common, RCBV2_COM_CFG_USER_REG,
+ RCB_COM_CFG_FA_B, true);
+ dsaf_set_dev_bit(rcb_common, RCBV2_COM_CFG_TSO_MODE_REG,
+ RCB_COM_TSO_MODE_B, HNS_TSO_MODE_8BD_32K);
+ }
return 0;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h
index 29041b18741a..81fe9f849973 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h
@@ -54,6 +54,9 @@ struct rcb_common_cb;
#define HNS_DUMP_REG_NUM 500
#define HNS_STATIC_REG_NUM 12
+#define HNS_TSO_MODE_8BD_32K 1
+#define HNS_TSO_MDOE_4BD_16K 0
+
enum rcb_int_flag {
RCB_INT_FLAG_TX = 0x1,
RCB_INT_FLAG_RX = (0x1 << 1),
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index 5d1b746e141d..f0c4f9b09d5b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -363,6 +363,8 @@
#define RCB_COM_CFG_FA_REG 0x3C
#define RCB_COM_CFG_PKT_TC_BP_REG 0x40
#define RCB_COM_CFG_PPE_TNL_CLKEN_REG 0x44
+#define RCBV2_COM_CFG_USER_REG 0x30
+#define RCBV2_COM_CFG_TSO_MODE_REG 0x50
#define RCB_COM_INTMSK_TX_PKT_REG 0x3A0
#define RCB_COM_RINT_TX_PKT_REG 0x3A8
@@ -860,6 +862,9 @@
#define PPE_COMMON_CNT_CLR_CE_B 0
#define PPE_COMMON_CNT_CLR_SNAP_EN_B 1
+#define RCB_COM_TSO_MODE_B 0
+#define RCB_COM_CFG_FNA_B 1
+#define RCB_COM_CFG_FA_B 0
#define GMAC_DUPLEX_TYPE_B 0
diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
index 58c96c412fe8..765ddb3dcd1a 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -458,7 +458,7 @@ static int hns_mdio_probe(struct platform_device *pdev)
}
mdio_dev->subctrl_vbase =
- syscon_node_to_regmap(of_parse_phandle(np, "subctrl_vbase", 0));
+ syscon_node_to_regmap(of_parse_phandle(np, "subctrl-vbase", 0));
if (IS_ERR(mdio_dev->subctrl_vbase)) {
dev_warn(&pdev->dev, "no syscon hisilicon,peri-c-subctrl\n");
mdio_dev->subctrl_vbase = NULL;
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index a0bbb6b9f5aa..94da913b151d 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -1239,7 +1239,7 @@ static int i40evf_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
- dev_err(&adapter->pdev->dev, "Cannot confiure RSS, command %d pending\n",
+ dev_err(&adapter->pdev->dev, "Cannot configure RSS, command %d pending\n",
adapter->current_op);
return -EBUSY;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 5c74a734f158..c56d91a2812b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -752,7 +752,7 @@ static int mlx5e_create_cq(struct mlx5e_channel *c,
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5_core_cq *mcq = &cq->mcq;
int eqn_not_used;
- int irqn;
+ unsigned int irqn;
int err;
u32 i;
@@ -806,7 +806,7 @@ static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
void *in;
void *cqc;
int inlen;
- int irqn_not_used;
+ unsigned int irqn_not_used;
int eqn;
int err;
@@ -1517,7 +1517,7 @@ static int mlx5e_create_drop_cq(struct mlx5e_priv *priv,
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5_core_cq *mcq = &cq->mcq;
int eqn_not_used;
- int irqn;
+ unsigned int irqn;
int err;
err = mlx5_cqwq_create(mdev, &param->wq, param->cqc, &cq->wq,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 67676cf0d507..b37749a3730e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -585,7 +585,8 @@ static void mlx5_irq_clear_affinity_hints(struct mlx5_core_dev *mdev)
mlx5_irq_clear_affinity_hint(mdev, i);
}
-int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn)
+int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn,
+ unsigned int *irqn)
{
struct mlx5_eq_table *table = &dev->priv.eq_table;
struct mlx5_eq *eq, *n;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index ffe894e6d287..45479ef5bcf4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -1015,6 +1015,7 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev,
case SWITCHDEV_OBJ_ID_PORT_MDB:
err = mlxsw_sp_port_mdb_del(mlxsw_sp_port,
SWITCHDEV_OBJ_PORT_MDB(obj));
+ break;
default:
err = -EOPNOTSUPP;
break;
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index eb9230e2092f..63aca9f847e1 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -7,7 +7,7 @@ config NET_VENDOR_SMSC
default y
depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \
ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \
- PCMCIA || SUPERH || XTENSA
+ PCMCIA || SUPERH || XTENSA || H8300
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -38,7 +38,7 @@ config SMC91X
select MII
depends on !OF || GPIOLIB
depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \
- M32R || MIPS || MN10300 || NIOS2 || SUPERH || XTENSA
+ M32R || MIPS || MN10300 || NIOS2 || SUPERH || XTENSA || H8300
---help---
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
index a3c129e1e40a..1a55c7976df0 100644
--- a/drivers/net/ethernet/smsc/smc91x.h
+++ b/drivers/net/ethernet/smsc/smc91x.h
@@ -172,6 +172,17 @@ static inline void mcf_outsw(void *a, unsigned char *p, int l)
#define SMC_IRQ_FLAGS 0
+#elif defined(CONFIG_H8300)
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 0
+#define SMC_CAN_USE_32BIT 0
+#define SMC_NOWAIT 0
+
+#define SMC_inb(a, r) ioread8((a) + (r))
+#define SMC_outb(v, a, r) iowrite8(v, (a) + (r))
+#define SMC_insb(a, r, p, l) ioread8_rep((a) + (r), p, l)
+#define SMC_outsb(a, r, p, l) iowrite8_rep((a) + (r), p, l)
+
#else
/*
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 8a8f6fb2880d..2174ec937b4d 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -20,10 +20,21 @@
#include <linux/gpio/consumer.h>
#define AT803X_INTR_ENABLE 0x12
+#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
+#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
+#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
+#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
+#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
+#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
+#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
+#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
+#define AT803X_INTR_ENABLE_WOL BIT(0)
+
#define AT803X_INTR_STATUS 0x13
+
#define AT803X_SMART_SPEED 0x14
#define AT803X_LED_CONTROL 0x18
-#define AT803X_WOL_ENABLE 0x01
+
#define AT803X_DEVICE_ADDR 0x03
#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
@@ -31,13 +42,15 @@
#define AT803X_MMD_ACCESS_CONTROL 0x0D
#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
#define AT803X_FUNC_DATA 0x4003
-#define AT803X_INER 0x0012
-#define AT803X_INER_INIT 0xec00
-#define AT803X_INSR 0x0013
+
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
-#define AT803X_DEBUG_SYSTEM_MODE_CTRL 0x05
-#define AT803X_DEBUG_RGMII_TX_CLK_DLY BIT(8)
+
+#define AT803X_DEBUG_REG_0 0x00
+#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
+
+#define AT803X_DEBUG_REG_5 0x05
+#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
@@ -61,6 +74,46 @@ struct at803x_context {
u16 led_control;
};
+static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
+{
+ int ret;
+
+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
+ if (ret < 0)
+ return ret;
+
+ return phy_read(phydev, AT803X_DEBUG_DATA);
+}
+
+static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
+ u16 clear, u16 set)
+{
+ u16 val;
+ int ret;
+
+ ret = at803x_debug_reg_read(phydev, reg);
+ if (ret < 0)
+ return ret;
+
+ val = ret & 0xffff;
+ val &= ~clear;
+ val |= set;
+
+ return phy_write(phydev, AT803X_DEBUG_DATA, val);
+}
+
+static inline int at803x_enable_rx_delay(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
+ AT803X_DEBUG_RX_CLK_DLY_EN);
+}
+
+static inline int at803x_enable_tx_delay(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
+ AT803X_DEBUG_TX_CLK_DLY_EN);
+}
+
/* save relevant PHY registers to private copy */
static void at803x_context_save(struct phy_device *phydev,
struct at803x_context *context)
@@ -119,14 +172,14 @@ static int at803x_set_wol(struct phy_device *phydev,
}
value = phy_read(phydev, AT803X_INTR_ENABLE);
- value |= AT803X_WOL_ENABLE;
+ value |= AT803X_INTR_ENABLE_WOL;
ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
if (ret)
return ret;
value = phy_read(phydev, AT803X_INTR_STATUS);
} else {
value = phy_read(phydev, AT803X_INTR_ENABLE);
- value &= (~AT803X_WOL_ENABLE);
+ value &= (~AT803X_INTR_ENABLE_WOL);
ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
if (ret)
return ret;
@@ -145,7 +198,7 @@ static void at803x_get_wol(struct phy_device *phydev,
wol->wolopts = 0;
value = phy_read(phydev, AT803X_INTR_ENABLE);
- if (value & AT803X_WOL_ENABLE)
+ if (value & AT803X_INTR_ENABLE_WOL)
wol->wolopts |= WAKE_MAGIC;
}
@@ -157,7 +210,7 @@ static int at803x_suspend(struct phy_device *phydev)
mutex_lock(&phydev->lock);
value = phy_read(phydev, AT803X_INTR_ENABLE);
- wol_enabled = value & AT803X_WOL_ENABLE;
+ wol_enabled = value & AT803X_INTR_ENABLE_WOL;
value = phy_read(phydev, MII_BMCR);
@@ -217,14 +270,17 @@ static int at803x_config_init(struct phy_device *phydev)
if (ret < 0)
return ret;
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
- ret = phy_write(phydev, AT803X_DEBUG_ADDR,
- AT803X_DEBUG_SYSTEM_MODE_CTRL);
- if (ret)
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ ret = at803x_enable_rx_delay(phydev);
+ if (ret < 0)
return ret;
- ret = phy_write(phydev, AT803X_DEBUG_DATA,
- AT803X_DEBUG_RGMII_TX_CLK_DLY);
- if (ret)
+ }
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ ret = at803x_enable_tx_delay(phydev);
+ if (ret < 0)
return ret;
}
@@ -235,7 +291,7 @@ static int at803x_ack_interrupt(struct phy_device *phydev)
{
int err;
- err = phy_read(phydev, AT803X_INSR);
+ err = phy_read(phydev, AT803X_INTR_STATUS);
return (err < 0) ? err : 0;
}
@@ -245,13 +301,19 @@ static int at803x_config_intr(struct phy_device *phydev)
int err;
int value;
- value = phy_read(phydev, AT803X_INER);
+ value = phy_read(phydev, AT803X_INTR_ENABLE);
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
+ value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
+ value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
+ value |= AT803X_INTR_ENABLE_LINK_FAIL;
+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
- err = phy_write(phydev, AT803X_INER,
- value | AT803X_INER_INIT);
+ err = phy_write(phydev, AT803X_INTR_ENABLE, value);
+ }
else
- err = phy_write(phydev, AT803X_INER, 0);
+ err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
return err;
}
@@ -322,7 +384,7 @@ static struct phy_driver at803x_driver[] = {
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
- .features = PHY_GBIT_FEATURES,
+ .features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 903737adfc01..bad3f005faee 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -901,6 +901,11 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
phydev->state = PHY_READY;
+ /* Initial carrier state is off as the phy is about to be
+ * (re)initialized.
+ */
+ netif_carrier_off(phydev->attached_dev);
+
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 2528331de193..718ceeab4dbc 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1872,10 +1872,10 @@ static int team_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
struct team *team = netdev_priv(dev);
struct team_port *port;
- rcu_read_lock();
- list_for_each_entry_rcu(port, &team->port_list, list)
+ mutex_lock(&team->lock);
+ list_for_each_entry(port, &team->port_list, list)
vlan_vid_del(port->dev, proto, vid);
- rcu_read_unlock();
+ mutex_unlock(&team->lock);
return 0;
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index cd39025d2abf..1bc5e93d2a34 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -571,8 +571,10 @@ static int x25_asy_open_tty(struct tty_struct *tty)
/* Perform the low-level X.25 async init */
err = x25_asy_open(sl->dev);
- if (err)
+ if (err) {
+ x25_asy_free(sl);
return err;
+ }
/* Done. We have linked the TTY line to a channel. */
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h
index b610ea5caae8..c9223e9e962f 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.h
+++ b/drivers/net/wireless/ath/ath10k/thermal.h
@@ -36,7 +36,7 @@ struct ath10k_thermal {
int temperature;
};
-#ifdef CONFIG_THERMAL
+#if IS_REACHABLE(CONFIG_THERMAL)
int ath10k_thermal_register(struct ath10k *ar);
void ath10k_thermal_unregister(struct ath10k *ar);
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
index ef06f57a7a0e..d3c9f0d52ae3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -47,8 +47,7 @@ static const char BRCM_ ## fw_nvram_name ## _FIRMWARE_NAME[] = \
BRCMF_FW_DEFAULT_PATH fw; \
static const char BRCM_ ## fw_nvram_name ## _NVRAM_NAME[] = \
BRCMF_FW_DEFAULT_PATH nvram; \
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw); \
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH nvram)
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw);
#define BRCMF_FW_DEF(fw_name, fw) \
static const char BRCM_ ## fw_name ## _FIRMWARE_NAME[] = \
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c
index 07a4c644fb9b..e9cef9de9ed8 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c
@@ -901,7 +901,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
min(abs(delta_g),
- (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+ (s32) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
if (delta_g < 0)
/*
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index e7bd63eb2876..f5231a2dd2ac 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -615,6 +615,7 @@ err_tx_unbind:
queue->tx_irq = 0;
err_unmap:
xenvif_unmap_frontend_rings(queue);
+ netif_napi_del(&queue->napi);
err:
module_put(THIS_MODULE);
return err;
@@ -684,22 +685,16 @@ void xenvif_deinit_queue(struct xenvif_queue *queue)
void xenvif_free(struct xenvif *vif)
{
- struct xenvif_queue *queue = NULL;
+ struct xenvif_queue *queues = vif->queues;
unsigned int num_queues = vif->num_queues;
unsigned int queue_index;
unregister_netdev(vif->dev);
-
- for (queue_index = 0; queue_index < num_queues; ++queue_index) {
- queue = &vif->queues[queue_index];
- xenvif_deinit_queue(queue);
- }
-
- vfree(vif->queues);
- vif->queues = NULL;
- vif->num_queues = 0;
-
free_netdev(vif->dev);
+ for (queue_index = 0; queue_index < num_queues; ++queue_index)
+ xenvif_deinit_queue(&queues[queue_index]);
+ vfree(queues);
+
module_put(THIS_MODULE);
}
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 1049c34e7d43..61b97c34bb3b 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -149,20 +149,19 @@ static inline pending_ring_idx_t pending_index(unsigned i)
return i & (MAX_PENDING_REQS-1);
}
-static int xenvif_rx_ring_slots_needed(struct xenvif *vif)
-{
- if (vif->gso_mask)
- return DIV_ROUND_UP(vif->dev->gso_max_size, XEN_PAGE_SIZE) + 1;
- else
- return DIV_ROUND_UP(vif->dev->mtu, XEN_PAGE_SIZE);
-}
-
static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
{
RING_IDX prod, cons;
+ struct sk_buff *skb;
int needed;
- needed = xenvif_rx_ring_slots_needed(queue->vif);
+ skb = skb_peek(&queue->rx_queue);
+ if (!skb)
+ return false;
+
+ needed = DIV_ROUND_UP(skb->len, XEN_PAGE_SIZE);
+ if (skb_is_gso(skb))
+ needed++;
do {
prod = queue->rx.sring->req_prod;
@@ -2005,8 +2004,7 @@ static bool xenvif_rx_queue_ready(struct xenvif_queue *queue)
static bool xenvif_have_rx_work(struct xenvif_queue *queue)
{
- return (!skb_queue_empty(&queue->rx_queue)
- && xenvif_rx_ring_slots_available(queue))
+ return xenvif_rx_ring_slots_available(queue)
|| (queue->vif->stall_timeout &&
(xenvif_rx_queue_stalled(queue)
|| xenvif_rx_queue_ready(queue)))
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 82c49bb87055..2e2832b83c93 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -11,6 +11,7 @@
* General Public License for more details.
*/
#include <linux/libnvdimm.h>
+#include <linux/badblocks.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/blkdev.h>
@@ -325,6 +326,7 @@ struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
if (!nvdimm_bus)
return NULL;
INIT_LIST_HEAD(&nvdimm_bus->list);
+ INIT_LIST_HEAD(&nvdimm_bus->poison_list);
init_waitqueue_head(&nvdimm_bus->probe_wait);
nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
mutex_init(&nvdimm_bus->reconfig_mutex);
@@ -359,6 +361,172 @@ struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
}
EXPORT_SYMBOL_GPL(__nvdimm_bus_register);
+static void set_badblock(struct badblocks *bb, sector_t s, int num)
+{
+ dev_dbg(bb->dev, "Found a poison range (0x%llx, 0x%llx)\n",
+ (u64) s * 512, (u64) num * 512);
+ /* this isn't an error as the hardware will still throw an exception */
+ if (badblocks_set(bb, s, num, 1))
+ dev_info_once(bb->dev, "%s: failed for sector %llx\n",
+ __func__, (u64) s);
+}
+
+/**
+ * __add_badblock_range() - Convert a physical address range to bad sectors
+ * @bb: badblocks instance to populate
+ * @ns_offset: namespace offset where the error range begins (in bytes)
+ * @len: number of bytes of poison to be added
+ *
+ * This assumes that the range provided with (ns_offset, len) is within
+ * the bounds of physical addresses for this namespace, i.e. lies in the
+ * interval [ns_start, ns_start + ns_size)
+ */
+static void __add_badblock_range(struct badblocks *bb, u64 ns_offset, u64 len)
+{
+ const unsigned int sector_size = 512;
+ sector_t start_sector;
+ u64 num_sectors;
+ u32 rem;
+
+ start_sector = div_u64(ns_offset, sector_size);
+ num_sectors = div_u64_rem(len, sector_size, &rem);
+ if (rem)
+ num_sectors++;
+
+ if (unlikely(num_sectors > (u64)INT_MAX)) {
+ u64 remaining = num_sectors;
+ sector_t s = start_sector;
+
+ while (remaining) {
+ int done = min_t(u64, remaining, INT_MAX);
+
+ set_badblock(bb, s, done);
+ remaining -= done;
+ s += done;
+ }
+ } else
+ set_badblock(bb, start_sector, num_sectors);
+}
+
+/**
+ * nvdimm_namespace_add_poison() - Convert a list of poison ranges to badblocks
+ * @ndns: the namespace containing poison ranges
+ * @bb: badblocks instance to populate
+ * @offset: offset at the start of the namespace before 'sector 0'
+ *
+ * The poison list generated during NFIT initialization may contain multiple,
+ * possibly overlapping ranges in the SPA (System Physical Address) space.
+ * Compare each of these ranges to the namespace currently being initialized,
+ * and add badblocks to the gendisk for all matching sub-ranges
+ */
+void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
+ struct badblocks *bb, resource_size_t offset)
+{
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+ struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
+ struct nvdimm_bus *nvdimm_bus;
+ struct list_head *poison_list;
+ u64 ns_start, ns_end, ns_size;
+ struct nd_poison *pl;
+
+ ns_size = nvdimm_namespace_capacity(ndns) - offset;
+ ns_start = nsio->res.start + offset;
+ ns_end = nsio->res.end;
+
+ nvdimm_bus = to_nvdimm_bus(nd_region->dev.parent);
+ poison_list = &nvdimm_bus->poison_list;
+ if (list_empty(poison_list))
+ return;
+
+ list_for_each_entry(pl, poison_list, list) {
+ u64 pl_end = pl->start + pl->length - 1;
+
+ /* Discard intervals with no intersection */
+ if (pl_end < ns_start)
+ continue;
+ if (pl->start > ns_end)
+ continue;
+ /* Deal with any overlap after start of the namespace */
+ if (pl->start >= ns_start) {
+ u64 start = pl->start;
+ u64 len;
+
+ if (pl_end <= ns_end)
+ len = pl->length;
+ else
+ len = ns_start + ns_size - pl->start;
+ __add_badblock_range(bb, start - ns_start, len);
+ continue;
+ }
+ /* Deal with overlap for poison starting before the namespace */
+ if (pl->start < ns_start) {
+ u64 len;
+
+ if (pl_end < ns_end)
+ len = pl->start + pl->length - ns_start;
+ else
+ len = ns_size;
+ __add_badblock_range(bb, 0, len);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(nvdimm_namespace_add_poison);
+
+static int __add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
+{
+ struct nd_poison *pl;
+
+ pl = kzalloc(sizeof(*pl), GFP_KERNEL);
+ if (!pl)
+ return -ENOMEM;
+
+ pl->start = addr;
+ pl->length = length;
+ list_add_tail(&pl->list, &nvdimm_bus->poison_list);
+
+ return 0;
+}
+
+int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
+{
+ struct nd_poison *pl;
+
+ if (list_empty(&nvdimm_bus->poison_list))
+ return __add_poison(nvdimm_bus, addr, length);
+
+ /*
+ * There is a chance this is a duplicate, check for those first.
+ * This will be the common case as ARS_STATUS returns all known
+ * errors in the SPA space, and we can't query it per region
+ */
+ list_for_each_entry(pl, &nvdimm_bus->poison_list, list)
+ if (pl->start == addr) {
+ /* If length has changed, update this list entry */
+ if (pl->length != length)
+ pl->length = length;
+ return 0;
+ }
+
+ /*
+ * If not a duplicate or a simple length update, add the entry as is,
+ * as any overlapping ranges will get resolved when the list is consumed
+ * and converted to badblocks
+ */
+ return __add_poison(nvdimm_bus, addr, length);
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
+
+static void free_poison_list(struct list_head *poison_list)
+{
+ struct nd_poison *pl, *next;
+
+ list_for_each_entry_safe(pl, next, poison_list, list) {
+ list_del(&pl->list);
+ kfree(pl);
+ }
+ list_del_init(poison_list);
+}
+
static int child_unregister(struct device *dev, void *data)
{
/*
@@ -385,6 +553,7 @@ void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
nd_synchronize();
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
+ free_poison_list(&nvdimm_bus->poison_list);
nvdimm_bus_destroy_ndctl(nvdimm_bus);
device_unregister(&nvdimm_bus->dev);
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 0955b2cb10fe..8ebfcaae3f5a 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -77,6 +77,59 @@ static bool is_namespace_io(struct device *dev)
return dev ? dev->type == &namespace_io_device_type : false;
}
+static int is_uuid_busy(struct device *dev, void *data)
+{
+ u8 *uuid1 = data, *uuid2 = NULL;
+
+ if (is_namespace_pmem(dev)) {
+ struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
+
+ uuid2 = nspm->uuid;
+ } else if (is_namespace_blk(dev)) {
+ struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
+
+ uuid2 = nsblk->uuid;
+ } else if (is_nd_btt(dev)) {
+ struct nd_btt *nd_btt = to_nd_btt(dev);
+
+ uuid2 = nd_btt->uuid;
+ } else if (is_nd_pfn(dev)) {
+ struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+
+ uuid2 = nd_pfn->uuid;
+ }
+
+ if (uuid2 && memcmp(uuid1, uuid2, NSLABEL_UUID_LEN) == 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int is_namespace_uuid_busy(struct device *dev, void *data)
+{
+ if (is_nd_pmem(dev) || is_nd_blk(dev))
+ return device_for_each_child(dev, data, is_uuid_busy);
+ return 0;
+}
+
+/**
+ * nd_is_uuid_unique - verify that no other namespace has @uuid
+ * @dev: any device on a nvdimm_bus
+ * @uuid: uuid to check
+ */
+bool nd_is_uuid_unique(struct device *dev, u8 *uuid)
+{
+ struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
+
+ if (!nvdimm_bus)
+ return false;
+ WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm_bus->dev));
+ if (device_for_each_child(&nvdimm_bus->dev, uuid,
+ is_namespace_uuid_busy) != 0)
+ return false;
+ return true;
+}
+
bool pmem_should_map_pages(struct device *dev)
{
struct nd_region *nd_region = to_nd_region(dev->parent);
@@ -104,20 +157,10 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
const char *suffix = NULL;
- if (ndns->claim) {
- if (is_nd_btt(ndns->claim))
- suffix = "s";
- else if (is_nd_pfn(ndns->claim))
- suffix = "m";
- else
- dev_WARN_ONCE(&ndns->dev, 1,
- "unknown claim type by %s\n",
- dev_name(ndns->claim));
- }
+ if (ndns->claim && is_nd_btt(ndns->claim))
+ suffix = "s";
if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) {
- if (!suffix && pmem_should_map_pages(&ndns->dev))
- suffix = "m";
sprintf(name, "pmem%d%s", nd_region->id, suffix ? suffix : "");
} else if (is_namespace_blk(&ndns->dev)) {
struct nd_namespace_blk *nsblk;
@@ -791,6 +834,15 @@ static void nd_namespace_pmem_set_size(struct nd_region *nd_region,
res->end = nd_region->ndr_start + size - 1;
}
+static bool uuid_not_set(const u8 *uuid, struct device *dev, const char *where)
+{
+ if (!uuid) {
+ dev_dbg(dev, "%s: uuid not set\n", where);
+ return true;
+ }
+ return false;
+}
+
static ssize_t __size_store(struct device *dev, unsigned long long val)
{
resource_size_t allocated = 0, available = 0;
@@ -820,8 +872,12 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
* We need a uuid for the allocation-label and dimm(s) on which
* to store the label.
*/
- if (!uuid || nd_region->ndr_mappings == 0)
+ if (uuid_not_set(uuid, dev, __func__))
return -ENXIO;
+ if (nd_region->ndr_mappings == 0) {
+ dev_dbg(dev, "%s: not associated with dimm(s)\n", __func__);
+ return -ENXIO;
+ }
div_u64_rem(val, SZ_4K * nd_region->ndr_mappings, &remainder);
if (remainder) {
@@ -1211,6 +1267,29 @@ static ssize_t holder_show(struct device *dev,
}
static DEVICE_ATTR_RO(holder);
+static ssize_t mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_namespace_common *ndns = to_ndns(dev);
+ struct device *claim;
+ char *mode;
+ ssize_t rc;
+
+ device_lock(dev);
+ claim = ndns->claim;
+ if (pmem_should_map_pages(dev) || (claim && is_nd_pfn(claim)))
+ mode = "memory";
+ else if (claim && is_nd_btt(claim))
+ mode = "safe";
+ else
+ mode = "raw";
+ rc = sprintf(buf, "%s\n", mode);
+ device_unlock(dev);
+
+ return rc;
+}
+static DEVICE_ATTR_RO(mode);
+
static ssize_t force_raw_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
@@ -1234,6 +1313,7 @@ static DEVICE_ATTR_RW(force_raw);
static struct attribute *nd_namespace_attributes[] = {
&dev_attr_nstype.attr,
&dev_attr_size.attr,
+ &dev_attr_mode.attr,
&dev_attr_uuid.attr,
&dev_attr_holder.attr,
&dev_attr_resource.attr,
@@ -1267,7 +1347,8 @@ static umode_t namespace_visible(struct kobject *kobj,
if (a == &dev_attr_nstype.attr || a == &dev_attr_size.attr
|| a == &dev_attr_holder.attr
- || a == &dev_attr_force_raw.attr)
+ || a == &dev_attr_force_raw.attr
+ || a == &dev_attr_mode.attr)
return a->mode;
return 0;
@@ -1343,14 +1424,19 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev)
struct nd_namespace_pmem *nspm;
nspm = to_nd_namespace_pmem(&ndns->dev);
- if (!nspm->uuid) {
- dev_dbg(&ndns->dev, "%s: uuid not set\n", __func__);
+ if (uuid_not_set(nspm->uuid, &ndns->dev, __func__))
return ERR_PTR(-ENODEV);
- }
} else if (is_namespace_blk(&ndns->dev)) {
struct nd_namespace_blk *nsblk;
nsblk = to_nd_namespace_blk(&ndns->dev);
+ if (uuid_not_set(nsblk->uuid, &ndns->dev, __func__))
+ return ERR_PTR(-ENODEV);
+ if (!nsblk->lbasize) {
+ dev_dbg(&ndns->dev, "%s: sector size not set\n",
+ __func__);
+ return ERR_PTR(-ENODEV);
+ }
if (!nd_namespace_blk_validate(nsblk))
return ERR_PTR(-ENODEV);
}
@@ -1689,6 +1775,18 @@ void nd_region_create_blk_seed(struct nd_region *nd_region)
nd_device_register(nd_region->ns_seed);
}
+void nd_region_create_pfn_seed(struct nd_region *nd_region)
+{
+ WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
+ nd_region->pfn_seed = nd_pfn_create(nd_region);
+ /*
+ * Seed creation failures are not fatal, provisioning is simply
+ * disabled until memory becomes available
+ */
+ if (!nd_region->pfn_seed)
+ dev_err(&nd_region->dev, "failed to create pfn namespace\n");
+}
+
void nd_region_create_btt_seed(struct nd_region *nd_region)
{
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 159aed532042..1d1500f3d8b5 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -30,6 +30,7 @@ struct nvdimm_bus {
struct list_head list;
struct device dev;
int id, probe_active;
+ struct list_head poison_list;
struct mutex reconfig_mutex;
};
@@ -52,6 +53,7 @@ void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev);
struct nd_region;
void nd_region_create_blk_seed(struct nd_region *nd_region);
void nd_region_create_btt_seed(struct nd_region *nd_region);
+void nd_region_create_pfn_seed(struct nd_region *nd_region);
void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev);
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 417e521d299c..ba1633b9da31 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -29,13 +29,12 @@ enum {
ND_MAX_LANES = 256,
SECTOR_SHIFT = 9,
INT_LBASIZE_ALIGNMENT = 64,
-#if IS_ENABLED(CONFIG_NVDIMM_PFN)
- ND_PFN_ALIGN = PAGES_PER_SECTION * PAGE_SIZE,
- ND_PFN_MASK = ND_PFN_ALIGN - 1,
-#else
- ND_PFN_ALIGN = 0,
- ND_PFN_MASK = 0,
-#endif
+};
+
+struct nd_poison {
+ u64 start;
+ u64 length;
+ struct list_head list;
};
struct nvdimm_drvdata {
@@ -153,6 +152,7 @@ struct nd_pfn {
int id;
u8 *uuid;
struct device dev;
+ unsigned long align;
unsigned long npfns;
enum nd_pfn_mode mode;
struct nd_pfn_sb *pfn_sb;
@@ -262,6 +262,8 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns);
int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns);
const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
char *name);
+void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
+ struct badblocks *bb, resource_size_t offset);
int nd_blk_region_init(struct nd_region *nd_region);
void __nd_iostat_start(struct bio *bio, unsigned long *start);
static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 71805a1aa0f3..0cc9048b86e2 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -83,8 +83,7 @@ static ssize_t mode_store(struct device *dev,
if (strncmp(buf, "pmem\n", n) == 0
|| strncmp(buf, "pmem", n) == 0) {
- /* TODO: allocate from PMEM support */
- rc = -ENOTTY;
+ nd_pfn->mode = PFN_MODE_PMEM;
} else if (strncmp(buf, "ram\n", n) == 0
|| strncmp(buf, "ram", n) == 0)
nd_pfn->mode = PFN_MODE_RAM;
@@ -103,6 +102,52 @@ static ssize_t mode_store(struct device *dev,
}
static DEVICE_ATTR_RW(mode);
+static ssize_t align_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+
+ return sprintf(buf, "%lx\n", nd_pfn->align);
+}
+
+static ssize_t __align_store(struct nd_pfn *nd_pfn, const char *buf)
+{
+ unsigned long val;
+ int rc;
+
+ rc = kstrtoul(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ if (!is_power_of_2(val) || val < PAGE_SIZE || val > SZ_1G)
+ return -EINVAL;
+
+ if (nd_pfn->dev.driver)
+ return -EBUSY;
+ else
+ nd_pfn->align = val;
+
+ return 0;
+}
+
+static ssize_t align_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+ ssize_t rc;
+
+ device_lock(dev);
+ nvdimm_bus_lock(dev);
+ rc = __align_store(nd_pfn, buf);
+ dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__,
+ rc, buf, buf[len - 1] == '\n' ? "" : "\n");
+ nvdimm_bus_unlock(dev);
+ device_unlock(dev);
+
+ return rc ? rc : len;
+}
+static DEVICE_ATTR_RW(align);
+
static ssize_t uuid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -164,6 +209,7 @@ static struct attribute *nd_pfn_attributes[] = {
&dev_attr_mode.attr,
&dev_attr_namespace.attr,
&dev_attr_uuid.attr,
+ &dev_attr_align.attr,
NULL,
};
@@ -179,7 +225,6 @@ static const struct attribute_group *nd_pfn_attribute_groups[] = {
};
static struct device *__nd_pfn_create(struct nd_region *nd_region,
- u8 *uuid, enum nd_pfn_mode mode,
struct nd_namespace_common *ndns)
{
struct nd_pfn *nd_pfn;
@@ -199,10 +244,8 @@ static struct device *__nd_pfn_create(struct nd_region *nd_region,
return NULL;
}
- nd_pfn->mode = mode;
- if (uuid)
- uuid = kmemdup(uuid, 16, GFP_KERNEL);
- nd_pfn->uuid = uuid;
+ nd_pfn->mode = PFN_MODE_NONE;
+ nd_pfn->align = HPAGE_SIZE;
dev = &nd_pfn->dev;
dev_set_name(dev, "pfn%d.%d", nd_region->id, nd_pfn->id);
dev->parent = &nd_region->dev;
@@ -220,8 +263,7 @@ static struct device *__nd_pfn_create(struct nd_region *nd_region,
struct device *nd_pfn_create(struct nd_region *nd_region)
{
- struct device *dev = __nd_pfn_create(nd_region, NULL, PFN_MODE_NONE,
- NULL);
+ struct device *dev = __nd_pfn_create(nd_region, NULL);
if (dev)
__nd_device_register(dev);
@@ -230,10 +272,11 @@ struct device *nd_pfn_create(struct nd_region *nd_region)
int nd_pfn_validate(struct nd_pfn *nd_pfn)
{
- struct nd_namespace_common *ndns = nd_pfn->ndns;
- struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
- struct nd_namespace_io *nsio;
u64 checksum, offset;
+ struct nd_namespace_io *nsio;
+ struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+ struct nd_namespace_common *ndns = nd_pfn->ndns;
+ const u8 *parent_uuid = nd_dev_to_uuid(&ndns->dev);
if (!pfn_sb || !ndns)
return -ENODEV;
@@ -241,10 +284,6 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
if (!is_nd_pmem(nd_pfn->dev.parent))
return -ENODEV;
- /* section alignment for simple hotplug */
- if (nvdimm_namespace_capacity(ndns) < ND_PFN_ALIGN)
- return -ENODEV;
-
if (nvdimm_read_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb)))
return -ENXIO;
@@ -257,6 +296,9 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
return -ENODEV;
pfn_sb->checksum = cpu_to_le64(checksum);
+ if (memcmp(pfn_sb->parent_uuid, parent_uuid, 16) != 0)
+ return -ENODEV;
+
switch (le32_to_cpu(pfn_sb->mode)) {
case PFN_MODE_RAM:
break;
@@ -278,6 +320,12 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
return -EINVAL;
}
+ if (nd_pfn->align > nvdimm_namespace_capacity(ndns)) {
+ dev_err(&nd_pfn->dev, "alignment: %lx exceeds capacity %llx\n",
+ nd_pfn->align, nvdimm_namespace_capacity(ndns));
+ return -EINVAL;
+ }
+
/*
* These warnings are verbose because they can only trigger in
* the case where the physical address alignment of the
@@ -286,17 +334,19 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
*/
offset = le64_to_cpu(pfn_sb->dataoff);
nsio = to_nd_namespace_io(&ndns->dev);
- if (nsio->res.start & ND_PFN_MASK) {
- dev_err(&nd_pfn->dev,
- "init failed: %s not section aligned\n",
- dev_name(&ndns->dev));
- return -EBUSY;
- } else if (offset >= resource_size(&nsio->res)) {
+ if (offset >= resource_size(&nsio->res)) {
dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n",
dev_name(&ndns->dev));
return -EBUSY;
}
+ nd_pfn->align = 1UL << ilog2(offset);
+ if (!is_power_of_2(offset) || offset < PAGE_SIZE) {
+ dev_err(&nd_pfn->dev, "bad offset: %#llx dax disabled\n",
+ offset);
+ return -ENXIO;
+ }
+
return 0;
}
EXPORT_SYMBOL(nd_pfn_validate);
@@ -313,7 +363,7 @@ int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata)
return -ENODEV;
nvdimm_bus_lock(&ndns->dev);
- dev = __nd_pfn_create(nd_region, NULL, PFN_MODE_NONE, ndns);
+ dev = __nd_pfn_create(nd_region, ndns);
nvdimm_bus_unlock(&ndns->dev);
if (!dev)
return -ENOMEM;
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 8ee79893d2f5..7edf31671dab 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -21,9 +21,11 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/memory_hotplug.h>
#include <linux/moduleparam.h>
+#include <linux/badblocks.h>
+#include <linux/memremap.h>
#include <linux/vmalloc.h>
+#include <linux/pfn_t.h>
#include <linux/slab.h>
#include <linux/pmem.h>
#include <linux/nd.h>
@@ -39,13 +41,28 @@ struct pmem_device {
phys_addr_t phys_addr;
/* when non-zero this device is hosting a 'pfn' instance */
phys_addr_t data_offset;
+ unsigned long pfn_flags;
void __pmem *virt_addr;
size_t size;
+ struct badblocks bb;
};
static int pmem_major;
-static void pmem_do_bvec(struct pmem_device *pmem, struct page *page,
+static bool is_bad_pmem(struct badblocks *bb, sector_t sector, unsigned int len)
+{
+ if (bb->count) {
+ sector_t first_bad;
+ int num_bad;
+
+ return !!badblocks_check(bb, sector, len / 512, &first_bad,
+ &num_bad);
+ }
+
+ return false;
+}
+
+static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
unsigned int len, unsigned int off, int rw,
sector_t sector)
{
@@ -54,6 +71,8 @@ static void pmem_do_bvec(struct pmem_device *pmem, struct page *page,
void __pmem *pmem_addr = pmem->virt_addr + pmem_off;
if (rw == READ) {
+ if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
+ return -EIO;
memcpy_from_pmem(mem + off, pmem_addr, len);
flush_dcache_page(page);
} else {
@@ -62,10 +81,12 @@ static void pmem_do_bvec(struct pmem_device *pmem, struct page *page,
}
kunmap_atomic(mem);
+ return 0;
}
static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
{
+ int rc = 0;
bool do_acct;
unsigned long start;
struct bio_vec bvec;
@@ -74,9 +95,15 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
struct pmem_device *pmem = bdev->bd_disk->private_data;
do_acct = nd_iostat_start(bio, &start);
- bio_for_each_segment(bvec, bio, iter)
- pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len, bvec.bv_offset,
- bio_data_dir(bio), iter.bi_sector);
+ bio_for_each_segment(bvec, bio, iter) {
+ rc = pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len,
+ bvec.bv_offset, bio_data_dir(bio),
+ iter.bi_sector);
+ if (rc) {
+ bio->bi_error = rc;
+ break;
+ }
+ }
if (do_acct)
nd_iostat_end(bio, start);
@@ -91,23 +118,32 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
struct page *page, int rw)
{
struct pmem_device *pmem = bdev->bd_disk->private_data;
+ int rc;
- pmem_do_bvec(pmem, page, PAGE_CACHE_SIZE, 0, rw, sector);
+ rc = pmem_do_bvec(pmem, page, PAGE_CACHE_SIZE, 0, rw, sector);
if (rw & WRITE)
wmb_pmem();
- page_endio(page, rw & WRITE, 0);
- return 0;
+ /*
+ * The ->rw_page interface is subtle and tricky. The core
+ * retries on any error, so we can only invoke page_endio() in
+ * the successful completion case. Otherwise, we'll see crashes
+ * caused by double completion.
+ */
+ if (rc == 0)
+ page_endio(page, rw & WRITE, 0);
+
+ return rc;
}
static long pmem_direct_access(struct block_device *bdev, sector_t sector,
- void __pmem **kaddr, unsigned long *pfn)
+ void __pmem **kaddr, pfn_t *pfn)
{
struct pmem_device *pmem = bdev->bd_disk->private_data;
resource_size_t offset = sector * 512 + pmem->data_offset;
*kaddr = pmem->virt_addr + offset;
- *pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT;
+ *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
return pmem->size - offset;
}
@@ -123,6 +159,7 @@ static struct pmem_device *pmem_alloc(struct device *dev,
struct resource *res, int id)
{
struct pmem_device *pmem;
+ struct request_queue *q;
pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
if (!pmem)
@@ -140,16 +177,26 @@ static struct pmem_device *pmem_alloc(struct device *dev,
return ERR_PTR(-EBUSY);
}
- if (pmem_should_map_pages(dev))
- pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res);
- else
+ q = blk_alloc_queue_node(GFP_KERNEL, dev_to_node(dev));
+ if (!q)
+ return ERR_PTR(-ENOMEM);
+
+ pmem->pfn_flags = PFN_DEV;
+ if (pmem_should_map_pages(dev)) {
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res,
+ &q->q_usage_counter, NULL);
+ pmem->pfn_flags |= PFN_MAP;
+ } else
pmem->virt_addr = (void __pmem *) devm_memremap(dev,
pmem->phys_addr, pmem->size,
ARCH_MEMREMAP_PMEM);
- if (IS_ERR(pmem->virt_addr))
+ if (IS_ERR(pmem->virt_addr)) {
+ blk_cleanup_queue(q);
return (void __force *) pmem->virt_addr;
+ }
+ pmem->pmem_queue = q;
return pmem;
}
@@ -169,10 +216,6 @@ static int pmem_attach_disk(struct device *dev,
int nid = dev_to_node(dev);
struct gendisk *disk;
- pmem->pmem_queue = blk_alloc_queue_node(GFP_KERNEL, nid);
- if (!pmem->pmem_queue)
- return -ENOMEM;
-
blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE);
blk_queue_max_hw_sectors(pmem->pmem_queue, UINT_MAX);
@@ -195,7 +238,12 @@ static int pmem_attach_disk(struct device *dev,
disk->driverfs_dev = dev;
set_capacity(disk, (pmem->size - pmem->data_offset) / 512);
pmem->pmem_disk = disk;
+ devm_exit_badblocks(dev, &pmem->bb);
+ if (devm_init_badblocks(dev, &pmem->bb))
+ return -ENOMEM;
+ nvdimm_namespace_add_poison(ndns, &pmem->bb, pmem->data_offset);
+ disk->bb = &pmem->bb;
add_disk(disk);
revalidate_disk(disk);
@@ -212,9 +260,13 @@ static int pmem_rw_bytes(struct nd_namespace_common *ndns,
return -EFAULT;
}
- if (rw == READ)
+ if (rw == READ) {
+ unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
+
+ if (unlikely(is_bad_pmem(&pmem->bb, offset / 512, sz_align)))
+ return -EIO;
memcpy_from_pmem(buf, pmem->virt_addr + offset, size);
- else {
+ } else {
memcpy_to_pmem(pmem->virt_addr + offset, buf, size);
wmb_pmem();
}
@@ -238,14 +290,11 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
nd_pfn->pfn_sb = pfn_sb;
rc = nd_pfn_validate(nd_pfn);
- if (rc == 0 || rc == -EBUSY)
+ if (rc == -ENODEV)
+ /* no info block, do init */;
+ else
return rc;
- /* section alignment for simple hotplug */
- if (nvdimm_namespace_capacity(ndns) < ND_PFN_ALIGN
- || pmem->phys_addr & ND_PFN_MASK)
- return -ENODEV;
-
nd_region = to_nd_region(nd_pfn->dev.parent);
if (nd_region->ro) {
dev_info(&nd_pfn->dev,
@@ -263,9 +312,9 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
* ->direct_access() to those that are included in the memmap.
*/
if (nd_pfn->mode == PFN_MODE_PMEM)
- offset = ALIGN(SZ_8K + 64 * npfns, PMD_SIZE);
+ offset = ALIGN(SZ_8K + 64 * npfns, nd_pfn->align);
else if (nd_pfn->mode == PFN_MODE_RAM)
- offset = SZ_8K;
+ offset = ALIGN(SZ_8K, nd_pfn->align);
else
goto err;
@@ -275,6 +324,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
pfn_sb->npfns = cpu_to_le64(npfns);
memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
+ memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1);
checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
pfn_sb->checksum = cpu_to_le64(checksum);
@@ -311,12 +361,17 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
struct device *dev = &nd_pfn->dev;
- struct vmem_altmap *altmap;
struct nd_region *nd_region;
+ struct vmem_altmap *altmap;
struct nd_pfn_sb *pfn_sb;
struct pmem_device *pmem;
+ struct request_queue *q;
phys_addr_t offset;
int rc;
+ struct vmem_altmap __altmap = {
+ .base_pfn = __phys_to_pfn(nsio->res.start),
+ .reserve = __phys_to_pfn(SZ_8K),
+ };
if (!nd_pfn->uuid || !nd_pfn->ndns)
return -ENODEV;
@@ -326,24 +381,25 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
if (rc)
return rc;
- if (PAGE_SIZE != SZ_4K) {
- dev_err(dev, "only supported on systems with 4K PAGE_SIZE\n");
- return -ENXIO;
- }
- if (nsio->res.start & ND_PFN_MASK) {
- dev_err(dev, "%s not memory hotplug section aligned\n",
- dev_name(&ndns->dev));
- return -ENXIO;
- }
-
pfn_sb = nd_pfn->pfn_sb;
offset = le64_to_cpu(pfn_sb->dataoff);
nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
if (nd_pfn->mode == PFN_MODE_RAM) {
- if (offset != SZ_8K)
+ if (offset < SZ_8K)
return -EINVAL;
nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
altmap = NULL;
+ } else if (nd_pfn->mode == PFN_MODE_PMEM) {
+ nd_pfn->npfns = (resource_size(&nsio->res) - offset)
+ / PAGE_SIZE;
+ if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
+ dev_info(&nd_pfn->dev,
+ "number of pfns truncated from %lld to %ld\n",
+ le64_to_cpu(nd_pfn->pfn_sb->npfns),
+ nd_pfn->npfns);
+ altmap = & __altmap;
+ altmap->free = __phys_to_pfn(offset - SZ_8K);
+ altmap->alloc = 0;
} else {
rc = -ENXIO;
goto err;
@@ -351,8 +407,11 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
/* establish pfn range for lookup, and switch to direct map */
pmem = dev_get_drvdata(dev);
+ q = pmem->pmem_queue;
devm_memunmap(dev, (void __force *) pmem->virt_addr);
- pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res);
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res,
+ &q->q_usage_counter, altmap);
+ pmem->pfn_flags |= PFN_MAP;
if (IS_ERR(pmem->virt_addr)) {
rc = PTR_ERR(pmem->virt_addr);
goto err;
@@ -389,20 +448,26 @@ static int nd_pmem_probe(struct device *dev)
pmem->ndns = ndns;
dev_set_drvdata(dev, pmem);
ndns->rw_bytes = pmem_rw_bytes;
+ if (devm_init_badblocks(dev, &pmem->bb))
+ return -ENOMEM;
+ nvdimm_namespace_add_poison(ndns, &pmem->bb, 0);
- if (is_nd_btt(dev))
+ if (is_nd_btt(dev)) {
+ /* btt allocates its own request_queue */
+ blk_cleanup_queue(pmem->pmem_queue);
+ pmem->pmem_queue = NULL;
return nvdimm_namespace_attach_btt(ndns);
+ }
if (is_nd_pfn(dev))
return nvdimm_namespace_attach_pfn(ndns);
- if (nd_btt_probe(ndns, pmem) == 0) {
- /* we'll come back as btt-pmem */
- return -ENXIO;
- }
-
- if (nd_pfn_probe(ndns, pmem) == 0) {
- /* we'll come back as pfn-pmem */
+ if (nd_btt_probe(ndns, pmem) == 0 || nd_pfn_probe(ndns, pmem) == 0) {
+ /*
+ * We'll come back as either btt-pmem, or pfn-pmem, so
+ * drop the queue allocation for now.
+ */
+ blk_cleanup_queue(pmem->pmem_queue);
return -ENXIO;
}
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 529f3f02e7b2..139bf71ca549 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -134,62 +134,6 @@ int nd_region_to_nstype(struct nd_region *nd_region)
}
EXPORT_SYMBOL(nd_region_to_nstype);
-static int is_uuid_busy(struct device *dev, void *data)
-{
- struct nd_region *nd_region = to_nd_region(dev->parent);
- u8 *uuid = data;
-
- switch (nd_region_to_nstype(nd_region)) {
- case ND_DEVICE_NAMESPACE_PMEM: {
- struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
-
- if (!nspm->uuid)
- break;
- if (memcmp(uuid, nspm->uuid, NSLABEL_UUID_LEN) == 0)
- return -EBUSY;
- break;
- }
- case ND_DEVICE_NAMESPACE_BLK: {
- struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
-
- if (!nsblk->uuid)
- break;
- if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) == 0)
- return -EBUSY;
- break;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-static int is_namespace_uuid_busy(struct device *dev, void *data)
-{
- if (is_nd_pmem(dev) || is_nd_blk(dev))
- return device_for_each_child(dev, data, is_uuid_busy);
- return 0;
-}
-
-/**
- * nd_is_uuid_unique - verify that no other namespace has @uuid
- * @dev: any device on a nvdimm_bus
- * @uuid: uuid to check
- */
-bool nd_is_uuid_unique(struct device *dev, u8 *uuid)
-{
- struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
-
- if (!nvdimm_bus)
- return false;
- WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm_bus->dev));
- if (device_for_each_child(&nvdimm_bus->dev, uuid,
- is_namespace_uuid_busy) != 0)
- return false;
- return true;
-}
-
static ssize_t size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -406,6 +350,9 @@ static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n)
struct nd_interleave_set *nd_set = nd_region->nd_set;
int type = nd_region_to_nstype(nd_region);
+ if (!is_nd_pmem(dev) && a == &dev_attr_pfn_seed.attr)
+ return 0;
+
if (a != &dev_attr_set_cookie.attr
&& a != &dev_attr_available_size.attr)
return a->mode;
@@ -487,6 +434,13 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
nd_region_create_blk_seed(nd_region);
nvdimm_bus_unlock(dev);
}
+ if (is_nd_pfn(dev) && probe) {
+ nd_region = to_nd_region(dev->parent);
+ nvdimm_bus_lock(dev);
+ if (nd_region->pfn_seed == dev)
+ nd_region_create_pfn_seed(nd_region);
+ nvdimm_bus_unlock(dev);
+ }
}
void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev)
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 15f2acb4d5cd..1af54ea20e7b 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -471,7 +471,7 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
struct bio *bio = rqd->bio;
struct nvme_nvm_command *cmd;
- rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0);
+ rq = blk_mq_alloc_request(q, bio_rw(bio), 0);
if (IS_ERR(rq))
return -ENOMEM;
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 0c67b57be83c..f5c0e2613c7c 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1041,7 +1041,7 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
struct request *req;
int ret;
- req = blk_mq_alloc_request(q, write, GFP_KERNEL, false);
+ req = blk_mq_alloc_request(q, write, 0);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -1094,7 +1094,8 @@ static int nvme_submit_async_admin_req(struct nvme_dev *dev)
struct nvme_cmd_info *cmd_info;
struct request *req;
- req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_ATOMIC, true);
+ req = blk_mq_alloc_request(dev->admin_q, WRITE,
+ BLK_MQ_REQ_NOWAIT | BLK_MQ_REQ_RESERVED);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -1119,7 +1120,7 @@ static int nvme_submit_admin_async_cmd(struct nvme_dev *dev,
struct request *req;
struct nvme_cmd_info *cmd_rq;
- req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_KERNEL, false);
+ req = blk_mq_alloc_request(dev->admin_q, WRITE, 0);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -1320,8 +1321,8 @@ static void nvme_abort_req(struct request *req)
if (!dev->abort_limit)
return;
- abort_req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_ATOMIC,
- false);
+ abort_req = blk_mq_alloc_request(dev->admin_q, WRITE,
+ BLK_MQ_REQ_NOWAIT);
if (IS_ERR(abort_req))
return;
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 9582c5703b3c..91a469d55b8f 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -597,7 +597,7 @@ static u64 __of_translate_address(struct device_node *dev,
pbus = of_match_bus(parent);
pbus->count_cells(dev, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ pr_err("prom_parse: Bad cell count for %s\n",
of_node_full_name(dev));
break;
}
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 53826b84e0ec..c647bd1b6903 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -646,6 +646,7 @@ void of_changeset_init(struct of_changeset *ocs)
memset(ocs, 0, sizeof(*ocs));
INIT_LIST_HEAD(&ocs->entries);
}
+EXPORT_SYMBOL_GPL(of_changeset_init);
/**
* of_changeset_destroy - Destroy a changeset
@@ -662,20 +663,9 @@ void of_changeset_destroy(struct of_changeset *ocs)
list_for_each_entry_safe_reverse(ce, cen, &ocs->entries, node)
__of_changeset_entry_destroy(ce);
}
+EXPORT_SYMBOL_GPL(of_changeset_destroy);
-/**
- * of_changeset_apply - Applies a changeset
- *
- * @ocs: changeset pointer
- *
- * Applies a changeset to the live tree.
- * Any side-effects of live tree state changes are applied here on
- * sucess, like creation/destruction of devices and side-effects
- * like creation of sysfs properties and directories.
- * Returns 0 on success, a negative error value in case of an error.
- * On error the partially applied effects are reverted.
- */
-int of_changeset_apply(struct of_changeset *ocs)
+int __of_changeset_apply(struct of_changeset *ocs)
{
struct of_changeset_entry *ce;
int ret;
@@ -704,17 +694,30 @@ int of_changeset_apply(struct of_changeset *ocs)
}
/**
- * of_changeset_revert - Reverts an applied changeset
+ * of_changeset_apply - Applies a changeset
*
* @ocs: changeset pointer
*
- * Reverts a changeset returning the state of the tree to what it
- * was before the application.
- * Any side-effects like creation/destruction of devices and
- * removal of sysfs properties and directories are applied.
+ * Applies a changeset to the live tree.
+ * Any side-effects of live tree state changes are applied here on
+ * success, like creation/destruction of devices and side-effects
+ * like creation of sysfs properties and directories.
* Returns 0 on success, a negative error value in case of an error.
+ * On error the partially applied effects are reverted.
*/
-int of_changeset_revert(struct of_changeset *ocs)
+int of_changeset_apply(struct of_changeset *ocs)
+{
+ int ret;
+
+ mutex_lock(&of_mutex);
+ ret = __of_changeset_apply(ocs);
+ mutex_unlock(&of_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_changeset_apply);
+
+int __of_changeset_revert(struct of_changeset *ocs)
{
struct of_changeset_entry *ce;
int ret;
@@ -742,6 +745,29 @@ int of_changeset_revert(struct of_changeset *ocs)
}
/**
+ * of_changeset_revert - Reverts an applied changeset
+ *
+ * @ocs: changeset pointer
+ *
+ * Reverts a changeset returning the state of the tree to what it
+ * was before the application.
+ * Any side-effects like creation/destruction of devices and
+ * removal of sysfs properties and directories are applied.
+ * Returns 0 on success, a negative error value in case of an error.
+ */
+int of_changeset_revert(struct of_changeset *ocs)
+{
+ int ret;
+
+ mutex_lock(&of_mutex);
+ ret = __of_changeset_revert(ocs);
+ mutex_unlock(&of_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_changeset_revert);
+
+/**
* of_changeset_action - Perform a changeset action
*
* @ocs: changeset pointer
@@ -779,3 +805,4 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
list_add_tail(&ce->node, &ocs->entries);
return 0;
}
+EXPORT_SYMBOL_GPL(of_changeset_action);
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 4fa916dffc91..706e3ff67f8b 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -473,6 +473,7 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
struct of_intc_desc {
struct list_head list;
+ of_irq_init_cb_t irq_init_cb;
struct device_node *dev;
struct device_node *interrupt_parent;
};
@@ -486,6 +487,7 @@ struct of_intc_desc {
*/
void __init of_irq_init(const struct of_device_id *matches)
{
+ const struct of_device_id *match;
struct device_node *np, *parent = NULL;
struct of_intc_desc *desc, *temp_desc;
struct list_head intc_desc_list, intc_parent_list;
@@ -493,10 +495,15 @@ void __init of_irq_init(const struct of_device_id *matches)
INIT_LIST_HEAD(&intc_desc_list);
INIT_LIST_HEAD(&intc_parent_list);
- for_each_matching_node(np, matches) {
+ for_each_matching_node_and_match(np, matches, &match) {
if (!of_find_property(np, "interrupt-controller", NULL) ||
!of_device_is_available(np))
continue;
+
+ if (WARN(!match->data, "of_irq_init: no init function for %s\n",
+ match->compatible))
+ continue;
+
/*
* Here, we allocate and populate an of_intc_desc with the node
* pointer, interrupt-parent device_node etc.
@@ -507,6 +514,7 @@ void __init of_irq_init(const struct of_device_id *matches)
goto err;
}
+ desc->irq_init_cb = match->data;
desc->dev = of_node_get(np);
desc->interrupt_parent = of_irq_find_parent(np);
if (desc->interrupt_parent == np)
@@ -526,27 +534,18 @@ void __init of_irq_init(const struct of_device_id *matches)
* The assumption is that NULL parent means a root controller.
*/
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
- const struct of_device_id *match;
int ret;
- of_irq_init_cb_t irq_init_cb;
if (desc->interrupt_parent != parent)
continue;
list_del(&desc->list);
- match = of_match_node(matches, desc->dev);
- if (WARN(!match->data,
- "of_irq_init: no init function for %s\n",
- match->compatible)) {
- kfree(desc);
- continue;
- }
- pr_debug("of_irq_init: init %s @ %p, parent %p\n",
- match->compatible,
+ pr_debug("of_irq_init: init %s (%p), parent %p\n",
+ desc->dev->full_name,
desc->dev, desc->interrupt_parent);
- irq_init_cb = (of_irq_init_cb_t)match->data;
- ret = irq_init_cb(desc->dev, desc->interrupt_parent);
+ ret = desc->irq_init_cb(desc->dev,
+ desc->interrupt_parent);
if (ret) {
kfree(desc);
continue;
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 8e882e706cd8..829469faeb23 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -45,6 +45,8 @@ static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
extern int of_property_notify(int action, struct device_node *np,
struct property *prop, struct property *old_prop);
extern void of_node_release(struct kobject *kobj);
+extern int __of_changeset_apply(struct of_changeset *ocs);
+extern int __of_changeset_revert(struct of_changeset *ocs);
#else /* CONFIG_OF_DYNAMIC */
static inline int of_property_notify(int action, struct device_node *np,
struct property *prop, struct property *old_prop)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 54e5af9d7377..82250815e9a5 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -379,9 +379,9 @@ int of_overlay_create(struct device_node *tree)
}
/* apply the changeset */
- err = of_changeset_apply(&ov->cset);
+ err = __of_changeset_apply(&ov->cset);
if (err) {
- pr_err("%s: of_changeset_apply() failed for tree@%s\n",
+ pr_err("%s: __of_changeset_apply() failed for tree@%s\n",
__func__, tree->full_name);
goto err_revert_overlay;
}
@@ -511,7 +511,7 @@ int of_overlay_destroy(int id)
list_del(&ov->node);
- of_changeset_revert(&ov->cset);
+ __of_changeset_revert(&ov->cset);
of_free_overlay_info(ov);
idr_remove(&ov_idr, id);
of_changeset_destroy(&ov->cset);
@@ -542,7 +542,7 @@ int of_overlay_destroy_all(void)
/* the tail of list is guaranteed to be safe to remove */
list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
list_del(&ov->node);
- of_changeset_revert(&ov->cset);
+ __of_changeset_revert(&ov->cset);
of_free_overlay_info(ov);
idr_remove(&ov_idr, ov->id);
kfree(ov);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index af98343614d8..8d103e4968be 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -31,6 +31,7 @@ const struct of_device_id of_default_bus_match_table[] = {
#endif /* CONFIG_ARM_AMBA */
{} /* Empty terminated list */
};
+EXPORT_SYMBOL(of_default_bus_match_table);
static int of_dev_node_match(struct device *dev, void *data)
{
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e16ea5717b7f..979b6e415cea 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -530,18 +530,14 @@ static void __init of_unittest_changeset(void)
unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
- mutex_lock(&of_mutex);
unittest(!of_changeset_apply(&chgset), "apply failed\n");
- mutex_unlock(&of_mutex);
/* Make sure node names are constructed correctly */
unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
"'%s' not added\n", n21->full_name);
of_node_put(np);
- mutex_lock(&of_mutex);
unittest(!of_changeset_revert(&chgset), "revert failed\n");
- mutex_unlock(&of_mutex);
of_changeset_destroy(&chgset);
#endif
@@ -757,6 +753,11 @@ static void __init of_unittest_match_node(void)
}
}
+static struct resource test_bus_res = {
+ .start = 0xfffffff8,
+ .end = 0xfffffff9,
+ .flags = IORESOURCE_MEM,
+};
static const struct platform_device_info test_bus_info = {
.name = "unittest-bus",
};
@@ -800,6 +801,15 @@ static void __init of_unittest_platform_populate(void)
return;
test_bus->dev.of_node = np;
+ /*
+ * Add a dummy resource to the test bus node after it is
+ * registered to catch problems with un-inserted resources. The
+ * DT code doesn't insert the resources, and it has caused the
+ * kernel to oops in the past. This makes sure the same bug
+ * doesn't crop up again.
+ */
+ platform_device_add_resources(test_bus, &test_bus_res, 1);
+
of_platform_populate(np, match, NULL, &test_bus->dev);
for_each_child_of_node(np, child) {
for_each_child_of_node(child, grandchild)
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index a0580afe1713..1133b5cc88ca 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -599,8 +599,10 @@ dino_fixup_bus(struct pci_bus *bus)
** P2PB's only have 2 BARs, no IRQs.
** I'd like to just ignore them for now.
*/
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pcibios_init_bridge(dev);
continue;
+ }
/* null out the ROM resource if there is one (we don't
* care about an expansion rom on parisc, since it
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 42844c2bc065..2ec2aef4d211 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -790,8 +790,10 @@ lba_fixup_bus(struct pci_bus *bus)
/*
** P2PB's have no IRQs. ignore them.
*/
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pcibios_init_bridge(dev);
continue;
+ }
/* Adjust INTERRUPT_LINE for this dev */
iosapic_fixup_irq(ldev->iosapic_obj, dev);
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 5ce5ef211bdb..3308427ed9f7 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -1,6 +1,6 @@
/*
* Parallel-port resource manager code.
- *
+ *
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
@@ -54,16 +54,16 @@ static LIST_HEAD(drivers);
static DEFINE_MUTEX(registration_lock);
/* What you can do to a port that's gone away.. */
-static void dead_write_lines (struct parport *p, unsigned char b){}
-static unsigned char dead_read_lines (struct parport *p) { return 0; }
-static unsigned char dead_frob_lines (struct parport *p, unsigned char b,
+static void dead_write_lines(struct parport *p, unsigned char b){}
+static unsigned char dead_read_lines(struct parport *p) { return 0; }
+static unsigned char dead_frob_lines(struct parport *p, unsigned char b,
unsigned char c) { return 0; }
-static void dead_onearg (struct parport *p){}
-static void dead_initstate (struct pardevice *d, struct parport_state *s) { }
-static void dead_state (struct parport *p, struct parport_state *s) { }
-static size_t dead_write (struct parport *p, const void *b, size_t l, int f)
+static void dead_onearg(struct parport *p){}
+static void dead_initstate(struct pardevice *d, struct parport_state *s) { }
+static void dead_state(struct parport *p, struct parport_state *s) { }
+static size_t dead_write(struct parport *p, const void *b, size_t l, int f)
{ return 0; }
-static size_t dead_read (struct parport *p, void *b, size_t l, int f)
+static size_t dead_read(struct parport *p, void *b, size_t l, int f)
{ return 0; }
static struct parport_operations dead_ops = {
.write_data = dead_write_lines, /* data */
@@ -93,7 +93,7 @@ static struct parport_operations dead_ops = {
.ecp_write_data = dead_write, /* ecp */
.ecp_read_data = dead_read,
.ecp_write_addr = dead_write,
-
+
.compat_write_data = dead_write, /* compat */
.nibble_read_data = dead_read, /* nibble */
.byte_read_data = dead_read, /* byte */
@@ -148,7 +148,7 @@ void parport_bus_exit(void)
/*
* iterates through all the drivers registered with the bus and sends the port
* details to the match_port callback of the driver, so that the driver can
- * know about the new port that just regsitered with the bus and decide if it
+ * know about the new port that just registered with the bus and decide if it
* wants to use this new port.
*/
static int driver_check(struct device_driver *dev_drv, void *_port)
@@ -194,7 +194,7 @@ static void detach_driver_chain(struct parport *port)
struct parport_driver *drv;
/* caller has exclusive registration_lock */
list_for_each_entry(drv, &drivers, list)
- drv->detach (port);
+ drv->detach(port);
/*
* call the detach function of the drivers registered in
@@ -205,11 +205,13 @@ static void detach_driver_chain(struct parport *port)
}
/* Ask kmod for some lowlevel drivers. */
-static void get_lowlevel_driver (void)
+static void get_lowlevel_driver(void)
{
- /* There is no actual module called this: you should set
- * up an alias for modutils. */
- request_module ("parport_lowlevel");
+ /*
+ * There is no actual module called this: you should set
+ * up an alias for modutils.
+ */
+ request_module("parport_lowlevel");
}
/*
@@ -265,7 +267,7 @@ int __parport_register_driver(struct parport_driver *drv, struct module *owner,
const char *mod_name)
{
if (list_empty(&portlist))
- get_lowlevel_driver ();
+ get_lowlevel_driver();
if (drv->devmodel) {
/* using device model */
@@ -328,7 +330,7 @@ static int port_detach(struct device *dev, void *_drv)
* finished by the time this function returns.
**/
-void parport_unregister_driver (struct parport_driver *drv)
+void parport_unregister_driver(struct parport_driver *drv)
{
struct parport *port;
@@ -343,6 +345,7 @@ void parport_unregister_driver (struct parport_driver *drv)
}
mutex_unlock(&registration_lock);
}
+EXPORT_SYMBOL(parport_unregister_driver);
static void free_port(struct device *dev)
{
@@ -372,12 +375,13 @@ static void free_port(struct device *dev)
* until the matching parport_put_port() call.
**/
-struct parport *parport_get_port (struct parport *port)
+struct parport *parport_get_port(struct parport *port)
{
struct device *dev = get_device(&port->bus_dev);
return to_parport_dev(dev);
}
+EXPORT_SYMBOL(parport_get_port);
void parport_del_port(struct parport *port)
{
@@ -394,10 +398,11 @@ EXPORT_SYMBOL(parport_del_port);
* zero (port is no longer used), free_port is called.
**/
-void parport_put_port (struct parport *port)
+void parport_put_port(struct parport *port)
{
put_device(&port->bus_dev);
}
+EXPORT_SYMBOL(parport_put_port);
/**
* parport_register_port - register a parallel port
@@ -439,10 +444,8 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
int ret;
tmp = kzalloc(sizeof(struct parport), GFP_KERNEL);
- if (!tmp) {
- printk(KERN_WARNING "parport: memory squeeze\n");
+ if (!tmp)
return NULL;
- }
/* Init our structure */
tmp->base = base;
@@ -450,12 +453,12 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
tmp->dma = dma;
tmp->muxport = tmp->daisy = tmp->muxsel = -1;
tmp->modes = 0;
- INIT_LIST_HEAD(&tmp->list);
+ INIT_LIST_HEAD(&tmp->list);
tmp->devices = tmp->cad = NULL;
tmp->flags = 0;
tmp->ops = ops;
tmp->physport = tmp;
- memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
+ memset(tmp->probe_info, 0, 5 * sizeof(struct parport_device_info));
rwlock_init(&tmp->cad_lock);
spin_lock_init(&tmp->waitlist_lock);
spin_lock_init(&tmp->pardevice_lock);
@@ -463,12 +466,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
sema_init(&tmp->ieee1284.irq, 0);
tmp->spintime = parport_default_spintime;
- atomic_set (&tmp->ref_count, 1);
+ atomic_set(&tmp->ref_count, 1);
INIT_LIST_HEAD(&tmp->full_list);
name = kmalloc(15, GFP_KERNEL);
if (!name) {
- printk(KERN_ERR "parport: memory squeeze\n");
kfree(tmp);
return NULL;
}
@@ -508,6 +510,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
return tmp;
}
+EXPORT_SYMBOL(parport_register_port);
/**
* parport_announce_port - tell device drivers about a parallel port
@@ -521,7 +524,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
* functions will be called, with @port as the parameter.
**/
-void parport_announce_port (struct parport *port)
+void parport_announce_port(struct parport *port)
{
int i;
@@ -531,9 +534,8 @@ void parport_announce_port (struct parport *port)
#endif
if (!port->dev)
- printk(KERN_WARNING "%s: fix this legacy "
- "no-device port driver!\n",
- port->name);
+ printk(KERN_WARNING "%s: fix this legacy no-device port driver!\n",
+ port->name);
parport_proc_register(port);
mutex_lock(&registration_lock);
@@ -547,7 +549,7 @@ void parport_announce_port (struct parport *port)
spin_unlock_irq(&parportlist_lock);
/* Let drivers know that new port(s) has arrived. */
- attach_driver_chain (port);
+ attach_driver_chain(port);
for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1];
if (slave)
@@ -555,6 +557,7 @@ void parport_announce_port (struct parport *port)
}
mutex_unlock(&registration_lock);
}
+EXPORT_SYMBOL(parport_announce_port);
/**
* parport_remove_port - deregister a parallel port
@@ -582,7 +585,7 @@ void parport_remove_port(struct parport *port)
mutex_lock(&registration_lock);
/* Spread the word. */
- detach_driver_chain (port);
+ detach_driver_chain(port);
#ifdef CONFIG_PARPORT_1284
/* Forget the IEEE1284.3 topology of the port. */
@@ -616,6 +619,7 @@ void parport_remove_port(struct parport *port)
parport_put_port(slave);
}
}
+EXPORT_SYMBOL(parport_remove_port);
/**
* parport_register_device - register a device on a parallel port
@@ -689,14 +693,14 @@ void parport_remove_port(struct parport *port)
struct pardevice *
parport_register_device(struct parport *port, const char *name,
int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(void *),
+ void (*irq_func)(void *),
int flags, void *handle)
{
struct pardevice *tmp;
if (port->physport->flags & PARPORT_FLAG_EXCL) {
/* An exclusive device is registered. */
- printk (KERN_DEBUG "%s: no more devices allowed\n",
+ printk(KERN_DEBUG "%s: no more devices allowed\n",
port->name);
return NULL;
}
@@ -722,28 +726,24 @@ parport_register_device(struct parport *port, const char *name,
}
}
- /* We up our own module reference count, and that of the port
- on which a device is to be registered, to ensure that
- neither of us gets unloaded while we sleep in (e.g.)
- kmalloc.
- */
- if (!try_module_get(port->ops->owner)) {
+ /*
+ * We up our own module reference count, and that of the port
+ * on which a device is to be registered, to ensure that
+ * neither of us gets unloaded while we sleep in (e.g.)
+ * kmalloc.
+ */
+ if (!try_module_get(port->ops->owner))
return NULL;
- }
-
- parport_get_port (port);
+
+ parport_get_port(port);
tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
- if (tmp == NULL) {
- printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
+ if (!tmp)
goto out;
- }
tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
- if (tmp->state == NULL) {
- printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
+ if (!tmp->state)
goto out_free_pardevice;
- }
tmp->name = name;
tmp->port = port;
@@ -767,19 +767,21 @@ parport_register_device(struct parport *port, const char *name,
if (flags & PARPORT_DEV_EXCL) {
if (port->physport->devices) {
- spin_unlock (&port->physport->pardevice_lock);
- printk (KERN_DEBUG
- "%s: cannot grant exclusive access for "
- "device %s\n", port->name, name);
+ spin_unlock(&port->physport->pardevice_lock);
+ printk(KERN_DEBUG
+ "%s: cannot grant exclusive access for device %s\n",
+ port->name, name);
goto out_free_all;
}
port->flags |= PARPORT_FLAG_EXCL;
}
tmp->next = port->physport->devices;
- wmb(); /* Make sure that tmp->next is written before it's
- added to the list; see comments marked 'no locking
- required' */
+ wmb(); /*
+ * Make sure that tmp->next is written before it's
+ * added to the list; see comments marked 'no locking
+ * required'
+ */
if (port->physport->devices)
port->physport->devices->prev = tmp;
port->physport->devices = tmp;
@@ -805,11 +807,12 @@ parport_register_device(struct parport *port, const char *name,
out_free_pardevice:
kfree(tmp);
out:
- parport_put_port (port);
+ parport_put_port(port);
module_put(port->ops->owner);
return NULL;
}
+EXPORT_SYMBOL(parport_register_device);
static void free_pardevice(struct device *dev)
{
@@ -968,7 +971,7 @@ void parport_unregister_device(struct pardevice *dev)
struct parport *port;
#ifdef PARPORT_PARANOID
- if (dev == NULL) {
+ if (!dev) {
printk(KERN_ERR "parport_unregister_device: passed NULL\n");
return;
}
@@ -985,7 +988,7 @@ void parport_unregister_device(struct pardevice *dev)
if (port->cad == dev) {
printk(KERN_DEBUG "%s: %s forgot to release port\n",
port->name, dev->name);
- parport_release (dev);
+ parport_release(dev);
}
spin_lock(&port->pardevice_lock);
@@ -1001,8 +1004,10 @@ void parport_unregister_device(struct pardevice *dev)
spin_unlock(&port->pardevice_lock);
- /* Make sure we haven't left any pointers around in the wait
- * list. */
+ /*
+ * Make sure we haven't left any pointers around in the wait
+ * list.
+ */
spin_lock_irq(&port->waitlist_lock);
if (dev->waitprev || dev->waitnext || port->waithead == dev) {
if (dev->waitprev)
@@ -1023,8 +1028,9 @@ void parport_unregister_device(struct pardevice *dev)
kfree(dev);
module_put(port->ops->owner);
- parport_put_port (port);
+ parport_put_port(port);
}
+EXPORT_SYMBOL(parport_unregister_device);
/**
* parport_find_number - find a parallel port by number
@@ -1038,23 +1044,24 @@ void parport_unregister_device(struct pardevice *dev)
* gives you, use parport_put_port().
*/
-struct parport *parport_find_number (int number)
+struct parport *parport_find_number(int number)
{
struct parport *port, *result = NULL;
if (list_empty(&portlist))
- get_lowlevel_driver ();
+ get_lowlevel_driver();
- spin_lock (&parportlist_lock);
+ spin_lock(&parportlist_lock);
list_for_each_entry(port, &portlist, list) {
if (port->number == number) {
- result = parport_get_port (port);
+ result = parport_get_port(port);
break;
}
}
- spin_unlock (&parportlist_lock);
+ spin_unlock(&parportlist_lock);
return result;
}
+EXPORT_SYMBOL(parport_find_number);
/**
* parport_find_base - find a parallel port by base address
@@ -1068,23 +1075,24 @@ struct parport *parport_find_number (int number)
* gives you, use parport_put_port().
*/
-struct parport *parport_find_base (unsigned long base)
+struct parport *parport_find_base(unsigned long base)
{
struct parport *port, *result = NULL;
if (list_empty(&portlist))
- get_lowlevel_driver ();
+ get_lowlevel_driver();
- spin_lock (&parportlist_lock);
+ spin_lock(&parportlist_lock);
list_for_each_entry(port, &portlist, list) {
if (port->base == base) {
- result = parport_get_port (port);
+ result = parport_get_port(port);
break;
}
}
- spin_unlock (&parportlist_lock);
+ spin_unlock(&parportlist_lock);
return result;
}
+EXPORT_SYMBOL(parport_find_base);
/**
* parport_claim - claim access to a parallel port device
@@ -1111,8 +1119,9 @@ int parport_claim(struct pardevice *dev)
}
/* Preempt any current device */
- write_lock_irqsave (&port->cad_lock, flags);
- if ((oldcad = port->cad) != NULL) {
+ write_lock_irqsave(&port->cad_lock, flags);
+ oldcad = port->cad;
+ if (oldcad) {
if (oldcad->preempt) {
if (oldcad->preempt(oldcad->private))
goto blocked;
@@ -1121,8 +1130,10 @@ int parport_claim(struct pardevice *dev)
goto blocked;
if (port->cad != oldcad) {
- /* I think we'll actually deadlock rather than
- get here, but just in case.. */
+ /*
+ * I think we'll actually deadlock rather than
+ * get here, but just in case..
+ */
printk(KERN_WARNING
"%s: %s released port when preempted!\n",
port->name, oldcad->name);
@@ -1136,7 +1147,7 @@ int parport_claim(struct pardevice *dev)
dev->waiting = 0;
/* Take ourselves out of the wait list again. */
- spin_lock_irq (&port->waitlist_lock);
+ spin_lock_irq(&port->waitlist_lock);
if (dev->waitprev)
dev->waitprev->waitnext = dev->waitnext;
else
@@ -1145,7 +1156,7 @@ int parport_claim(struct pardevice *dev)
dev->waitnext->waitprev = dev->waitprev;
else
port->waittail = dev->waitprev;
- spin_unlock_irq (&port->waitlist_lock);
+ spin_unlock_irq(&port->waitlist_lock);
dev->waitprev = dev->waitnext = NULL;
}
@@ -1162,7 +1173,7 @@ int parport_claim(struct pardevice *dev)
/* If it's a daisy chain device, select it. */
if (dev->daisy >= 0) {
/* This could be lazier. */
- if (!parport_daisy_select (port, dev->daisy,
+ if (!parport_daisy_select(port, dev->daisy,
IEEE1284_MODE_COMPAT))
port->daisy = dev->daisy;
}
@@ -1175,13 +1186,15 @@ int parport_claim(struct pardevice *dev)
return 0;
blocked:
- /* If this is the first time we tried to claim the port, register an
- interest. This is only allowed for devices sleeping in
- parport_claim_or_block(), or those with a wakeup function. */
+ /*
+ * If this is the first time we tried to claim the port, register an
+ * interest. This is only allowed for devices sleeping in
+ * parport_claim_or_block(), or those with a wakeup function.
+ */
/* The cad_lock is still held for writing here */
if (dev->waiting & 2 || dev->wakeup) {
- spin_lock (&port->waitlist_lock);
+ spin_lock(&port->waitlist_lock);
if (test_and_set_bit(0, &dev->waiting) == 0) {
/* First add ourselves to the end of the wait list. */
dev->waitnext = NULL;
@@ -1192,11 +1205,12 @@ blocked:
} else
port->waithead = port->waittail = dev;
}
- spin_unlock (&port->waitlist_lock);
+ spin_unlock(&port->waitlist_lock);
}
- write_unlock_irqrestore (&port->cad_lock, flags);
+ write_unlock_irqrestore(&port->cad_lock, flags);
return -EAGAIN;
}
+EXPORT_SYMBOL(parport_claim);
/**
* parport_claim_or_block - claim access to a parallel port device
@@ -1212,8 +1226,10 @@ int parport_claim_or_block(struct pardevice *dev)
{
int r;
- /* Signal to parport_claim() that we can wait even without a
- wakeup function. */
+ /*
+ * Signal to parport_claim() that we can wait even without a
+ * wakeup function.
+ */
dev->waiting = 2;
/* Try to claim the port. If this fails, we need to sleep. */
@@ -1231,14 +1247,15 @@ int parport_claim_or_block(struct pardevice *dev)
* See also parport_release()
*/
- /* If dev->waiting is clear now, an interrupt
- gave us the port and we would deadlock if we slept. */
+ /*
+ * If dev->waiting is clear now, an interrupt
+ * gave us the port and we would deadlock if we slept.
+ */
if (dev->waiting) {
wait_event_interruptible(dev->wait_q,
!dev->waiting);
- if (signal_pending (current)) {
+ if (signal_pending(current))
return -EINTR;
- }
r = 1;
} else {
r = 0;
@@ -1250,15 +1267,15 @@ int parport_claim_or_block(struct pardevice *dev)
#ifdef PARPORT_DEBUG_SHARING
if (dev->port->physport->cad != dev)
- printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
- "but %s owns port!\n", dev->name,
- dev->port->physport->cad ?
+ printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n",
+ dev->name, dev->port->physport->cad ?
dev->port->physport->cad->name:"nobody");
#endif
}
dev->waiting = 0;
return r;
}
+EXPORT_SYMBOL(parport_claim_or_block);
/**
* parport_release - give up access to a parallel port device
@@ -1278,9 +1295,9 @@ void parport_release(struct pardevice *dev)
/* Make sure that dev is the current device */
write_lock_irqsave(&port->cad_lock, flags);
if (port->cad != dev) {
- write_unlock_irqrestore (&port->cad_lock, flags);
- printk(KERN_WARNING "%s: %s tried to release parport "
- "when not owner\n", port->name, dev->name);
+ write_unlock_irqrestore(&port->cad_lock, flags);
+ printk(KERN_WARNING "%s: %s tried to release parport when not owner\n",
+ port->name, dev->name);
return;
}
@@ -1293,7 +1310,7 @@ void parport_release(struct pardevice *dev)
/* If this is a daisy device, deselect it. */
if (dev->daisy >= 0) {
- parport_daisy_deselect_all (port);
+ parport_daisy_deselect_all(port);
port->daisy = -1;
}
#endif
@@ -1304,8 +1321,10 @@ void parport_release(struct pardevice *dev)
/* Save control registers */
port->ops->save_state(port, dev->state);
- /* If anybody is waiting, find out who's been there longest and
- then wake them up. (Note: no locking required) */
+ /*
+ * If anybody is waiting, find out who's been there longest and
+ * then wake them up. (Note: no locking required)
+ */
/* !!! LOCKING IS NEEDED HERE */
for (pd = port->waithead; pd; pd = pd->waitnext) {
if (pd->waiting & 2) { /* sleeping in claim_or_block */
@@ -1322,14 +1341,17 @@ void parport_release(struct pardevice *dev)
}
}
- /* Nobody was waiting, so walk the list to see if anyone is
- interested in being woken up. (Note: no locking required) */
+ /*
+ * Nobody was waiting, so walk the list to see if anyone is
+ * interested in being woken up. (Note: no locking required)
+ */
/* !!! LOCKING IS NEEDED HERE */
- for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
+ for (pd = port->devices; !port->cad && pd; pd = pd->next) {
if (pd->wakeup && pd != dev)
pd->wakeup(pd->private);
}
}
+EXPORT_SYMBOL(parport_release);
irqreturn_t parport_irq_handler(int irq, void *dev_id)
{
@@ -1339,22 +1361,6 @@ irqreturn_t parport_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-
-/* Exported symbols for modules. */
-
-EXPORT_SYMBOL(parport_claim);
-EXPORT_SYMBOL(parport_claim_or_block);
-EXPORT_SYMBOL(parport_release);
-EXPORT_SYMBOL(parport_register_port);
-EXPORT_SYMBOL(parport_announce_port);
-EXPORT_SYMBOL(parport_remove_port);
-EXPORT_SYMBOL(parport_unregister_driver);
-EXPORT_SYMBOL(parport_register_device);
-EXPORT_SYMBOL(parport_unregister_device);
-EXPORT_SYMBOL(parport_get_port);
-EXPORT_SYMBOL(parport_put_port);
-EXPORT_SYMBOL(parport_find_number);
-EXPORT_SYMBOL(parport_find_base);
EXPORT_SYMBOL(parport_irq_handler);
MODULE_LICENSE("GPL");
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 7e327309cf69..c2dd52ea4198 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3405,7 +3405,9 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
return 0;
}
-#include "../gpu/drm/i915/i915_reg.h"
+#define SOUTH_CHICKEN2 0xc2004
+#define PCH_PP_STATUS 0xc7200
+#define PCH_PP_CONTROL 0xc7204
#define MSG_CTL 0x45010
#define NSDE_PWR_STATE 0xd0100
#define IGD_OPERATION_TIMEOUT 10000 /* set timeout 10 seconds */
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 03cb3ea2d2c0..e7e117d5dbbe 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -118,6 +118,13 @@ config PHY_RCAR_GEN2
help
Support for USB PHY found on Renesas R-Car generation 2 SoCs.
+config PHY_RCAR_GEN3_USB2
+ tristate "Renesas R-Car generation 3 USB 2.0 PHY driver"
+ depends on OF && ARCH_SHMOBILE
+ select GENERIC_PHY
+ help
+ Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs.
+
config OMAP_CONTROL_PHY
tristate "OMAP CONTROL PHY Driver"
depends on ARCH_OMAP2PLUS || COMPILE_TEST
@@ -215,6 +222,15 @@ config PHY_MT65XX_USB3
for mt65xx SoCs. it supports two usb2.0 ports and
one usb3.0 port.
+config PHY_HI6220_USB
+ tristate "hi6220 USB PHY support"
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support the HISILICON HI6220 USB PHY.
+
+ To compile this driver as a module, choose M here.
+
config PHY_SUN4I_USB
tristate "Allwinner sunxi SoC USB PHY driver"
depends on ARCH_SUNXI && HAS_IOMEM && OF
@@ -374,11 +390,11 @@ config PHY_TUSB1210
config PHY_BRCMSTB_SATA
tristate "Broadcom STB SATA PHY driver"
- depends on ARCH_BRCMSTB
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC
depends on OF
select GENERIC_PHY
help
- Enable this to support the SATA3 PHY on 28nm Broadcom STB SoCs.
+ Enable this to support the SATA3 PHY on 28nm or 40nm Broadcom STB SoCs.
Likely useful only with CONFIG_SATA_BRCMSTB enabled.
config PHY_CYGNUS_PCIE
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 075db1a81aa5..c80f09df3bb8 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -17,12 +17,14 @@ obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
+obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o
obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
+obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o
obj-$(CONFIG_PHY_MT65XX_USB3) += phy-mt65xx-usb3.o
obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o
diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
index 797ba17c404f..2017751ede26 100644
--- a/drivers/phy/phy-berlin-usb.c
+++ b/drivers/phy/phy-berlin-usb.c
@@ -9,11 +9,9 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -195,7 +193,6 @@ static int phy_berlin_usb_probe(struct platform_device *pdev)
return PTR_ERR(phy);
}
- platform_set_drvdata(pdev, priv);
phy_set_drvdata(phy, priv);
phy_provider =
diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c
index cd9dba820566..a23172ff40e3 100644
--- a/drivers/phy/phy-brcmstb-sata.c
+++ b/drivers/phy/phy-brcmstb-sata.c
@@ -26,13 +26,21 @@
#define SATA_MDIO_BANK_OFFSET 0x23c
#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4)
-#define SATA_MDIO_REG_SPACE_SIZE 0x1000
-#define SATA_MDIO_REG_LENGTH 0x1f00
#define MAX_PORTS 2
/* Register offset between PHYs in PCB space */
-#define SATA_MDIO_REG_SPACE_SIZE 0x1000
+#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000
+
+/* The older SATA PHY registers duplicated per port registers within the map,
+ * rather than having a separate map per port.
+ */
+#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10
+
+enum brcm_sata_phy_version {
+ BRCM_SATA_PHY_28NM,
+ BRCM_SATA_PHY_40NM,
+};
struct brcm_sata_port {
int portnum;
@@ -44,11 +52,12 @@ struct brcm_sata_port {
struct brcm_sata_phy {
struct device *dev;
void __iomem *phy_base;
+ enum brcm_sata_phy_version version;
struct brcm_sata_port phys[MAX_PORTS];
};
-enum sata_mdio_phy_regs_28nm {
+enum sata_mdio_phy_regs {
PLL_REG_BANK_0 = 0x50,
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
@@ -66,8 +75,16 @@ enum sata_mdio_phy_regs_28nm {
static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port)
{
struct brcm_sata_phy *priv = port->phy_priv;
+ u32 offset = 0;
+
+ if (priv->version == BRCM_SATA_PHY_28NM)
+ offset = SATA_MDIO_REG_28NM_SPACE_SIZE;
+ else if (priv->version == BRCM_SATA_PHY_40NM)
+ offset = SATA_MDIO_REG_40NM_SPACE_SIZE;
+ else
+ dev_err(priv->dev, "invalid phy version\n");
- return priv->phy_base + (port->portnum * SATA_MDIO_REG_SPACE_SIZE);
+ return priv->phy_base + (port->portnum * offset);
}
static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs,
@@ -86,7 +103,7 @@ static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs,
#define FMAX_VAL_DEFAULT 0x3df
#define FMAX_VAL_SSC 0x83
-static void brcm_sata_cfg_ssc_28nm(struct brcm_sata_port *port)
+static void brcm_sata_cfg_ssc(struct brcm_sata_port *port)
{
void __iomem *base = brcm_sata_phy_base(port);
struct brcm_sata_phy *priv = port->phy_priv;
@@ -117,18 +134,21 @@ static int brcm_sata_phy_init(struct phy *phy)
{
struct brcm_sata_port *port = phy_get_drvdata(phy);
- brcm_sata_cfg_ssc_28nm(port);
+ brcm_sata_cfg_ssc(port);
return 0;
}
-static const struct phy_ops phy_ops_28nm = {
+static const struct phy_ops phy_ops = {
.init = brcm_sata_phy_init,
.owner = THIS_MODULE,
};
static const struct of_device_id brcm_sata_phy_of_match[] = {
- { .compatible = "brcm,bcm7445-sata-phy" },
+ { .compatible = "brcm,bcm7445-sata-phy",
+ .data = (void *)BRCM_SATA_PHY_28NM },
+ { .compatible = "brcm,bcm7425-sata-phy",
+ .data = (void *)BRCM_SATA_PHY_40NM },
{},
};
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
@@ -137,6 +157,7 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dn = dev->of_node, *child;
+ const struct of_device_id *of_id;
struct brcm_sata_phy *priv;
struct resource *res;
struct phy_provider *provider;
@@ -156,6 +177,12 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(priv->phy_base))
return PTR_ERR(priv->phy_base);
+ of_id = of_match_node(brcm_sata_phy_of_match, dn);
+ if (of_id)
+ priv->version = (enum brcm_sata_phy_version)of_id->data;
+ else
+ priv->version = BRCM_SATA_PHY_28NM;
+
for_each_available_child_of_node(dn, child) {
unsigned int id;
struct brcm_sata_port *port;
@@ -181,7 +208,7 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
port = &priv->phys[id];
port->portnum = id;
port->phy_priv = priv;
- port->phy = devm_phy_create(dev, child, &phy_ops_28nm);
+ port->phy = devm_phy_create(dev, child, &phy_ops);
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
if (IS_ERR(port->phy)) {
dev_err(dev, "failed to create PHY\n");
diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c
new file mode 100644
index 000000000000..b2141cbd4cf6
--- /dev/null
+++ b/drivers/phy/phy-hi6220-usb.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+
+#define SC_PERIPH_CTRL4 0x00c
+
+#define CTRL4_PICO_SIDDQ BIT(6)
+#define CTRL4_PICO_OGDISABLE BIT(8)
+#define CTRL4_PICO_VBUSVLDEXT BIT(10)
+#define CTRL4_PICO_VBUSVLDEXTSEL BIT(11)
+#define CTRL4_OTG_PHY_SEL BIT(21)
+
+#define SC_PERIPH_CTRL5 0x010
+
+#define CTRL5_USBOTG_RES_SEL BIT(3)
+#define CTRL5_PICOPHY_ACAENB BIT(4)
+#define CTRL5_PICOPHY_BC_MODE BIT(5)
+#define CTRL5_PICOPHY_CHRGSEL BIT(6)
+#define CTRL5_PICOPHY_VDATSRCEND BIT(7)
+#define CTRL5_PICOPHY_VDATDETENB BIT(8)
+#define CTRL5_PICOPHY_DCDENB BIT(9)
+#define CTRL5_PICOPHY_IDDIG BIT(10)
+
+#define SC_PERIPH_CTRL8 0x018
+#define SC_PERIPH_RSTEN0 0x300
+#define SC_PERIPH_RSTDIS0 0x304
+
+#define RST0_USBOTG_BUS BIT(4)
+#define RST0_POR_PICOPHY BIT(5)
+#define RST0_USBOTG BIT(6)
+#define RST0_USBOTG_32K BIT(7)
+
+#define EYE_PATTERN_PARA 0x7053348c
+
+struct hi6220_priv {
+ struct regmap *reg;
+ struct device *dev;
+};
+
+static void hi6220_phy_init(struct hi6220_priv *priv)
+{
+ struct regmap *reg = priv->reg;
+ u32 val, mask;
+
+ val = RST0_USBOTG_BUS | RST0_POR_PICOPHY |
+ RST0_USBOTG | RST0_USBOTG_32K;
+ mask = val;
+ regmap_update_bits(reg, SC_PERIPH_RSTEN0, mask, val);
+ regmap_update_bits(reg, SC_PERIPH_RSTDIS0, mask, val);
+}
+
+static int hi6220_phy_setup(struct hi6220_priv *priv, bool on)
+{
+ struct regmap *reg = priv->reg;
+ u32 val, mask;
+ int ret;
+
+ if (on) {
+ val = CTRL5_USBOTG_RES_SEL | CTRL5_PICOPHY_ACAENB;
+ mask = val | CTRL5_PICOPHY_BC_MODE;
+ ret = regmap_update_bits(reg, SC_PERIPH_CTRL5, mask, val);
+ if (ret)
+ goto out;
+
+ val = CTRL4_PICO_VBUSVLDEXT | CTRL4_PICO_VBUSVLDEXTSEL |
+ CTRL4_OTG_PHY_SEL;
+ mask = val | CTRL4_PICO_SIDDQ | CTRL4_PICO_OGDISABLE;
+ ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val);
+ if (ret)
+ goto out;
+
+ ret = regmap_write(reg, SC_PERIPH_CTRL8, EYE_PATTERN_PARA);
+ if (ret)
+ goto out;
+ } else {
+ val = CTRL4_PICO_SIDDQ;
+ mask = val;
+ ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val);
+ if (ret)
+ goto out;
+ }
+
+ return 0;
+out:
+ dev_err(priv->dev, "failed to setup phy ret: %d\n", ret);
+ return ret;
+}
+
+static int hi6220_phy_start(struct phy *phy)
+{
+ struct hi6220_priv *priv = phy_get_drvdata(phy);
+
+ return hi6220_phy_setup(priv, true);
+}
+
+static int hi6220_phy_exit(struct phy *phy)
+{
+ struct hi6220_priv *priv = phy_get_drvdata(phy);
+
+ return hi6220_phy_setup(priv, false);
+}
+
+static struct phy_ops hi6220_phy_ops = {
+ .init = hi6220_phy_start,
+ .exit = hi6220_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int hi6220_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct phy *phy;
+ struct hi6220_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->reg = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "hisilicon,peripheral-syscon");
+ if (IS_ERR(priv->reg)) {
+ dev_err(dev, "no hisilicon,peripheral-syscon\n");
+ return PTR_ERR(priv->reg);
+ }
+
+ hi6220_phy_init(priv);
+
+ phy = devm_phy_create(dev, NULL, &hi6220_phy_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ phy_set_drvdata(phy, priv);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id hi6220_phy_of_match[] = {
+ {.compatible = "hisilicon,hi6220-usb-phy",},
+ { },
+};
+MODULE_DEVICE_TABLE(of, hi6220_phy_of_match);
+
+static struct platform_driver hi6220_phy_driver = {
+ .probe = hi6220_phy_probe,
+ .driver = {
+ .name = "hi6220-usb-phy",
+ .of_match_table = hi6220_phy_of_match,
+ }
+};
+module_platform_driver(hi6220_phy_driver);
+
+MODULE_DESCRIPTION("HISILICON HI6220 USB PHY driver");
+MODULE_ALIAS("platform:hi6220-usb-phy");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c
index e427c3b788ff..c0e7b4b0cf5c 100644
--- a/drivers/phy/phy-mt65xx-usb3.c
+++ b/drivers/phy/phy-mt65xx-usb3.c
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
@@ -27,6 +28,7 @@
* relative to USB3_SIF2_BASE base address
*/
#define SSUSB_SIFSLV_SPLLC 0x0000
+#define SSUSB_SIFSLV_U2FREQ 0x0100
/* offsets of sub-segment in each port registers */
#define SSUSB_SIFSLV_U2PHY_COM_BASE 0x0000
@@ -41,6 +43,7 @@
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
#define U3P_USBPHYACR5 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0014)
+#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
@@ -49,6 +52,8 @@
#define PA6_RG_U2_ISO_EN BIT(31)
#define PA6_RG_U2_BC11_SW_EN BIT(23)
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
+#define PA6_RG_U2_SQTH GENMASK(3, 0)
+#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
#define U3P_U2PHYACR4 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0020)
#define P2C_RG_USB20_GPIO_CTL BIT(9)
@@ -111,6 +116,24 @@
#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
+#define U3P_U2FREQ_FMCR0 (SSUSB_SIFSLV_U2FREQ + 0x00)
+#define P2F_RG_MONCLK_SEL GENMASK(27, 26)
+#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
+#define P2F_RG_FREQDET_EN BIT(24)
+#define P2F_RG_CYCLECNT GENMASK(23, 0)
+#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
+
+#define U3P_U2FREQ_VALUE (SSUSB_SIFSLV_U2FREQ + 0x0c)
+
+#define U3P_U2FREQ_FMMONR1 (SSUSB_SIFSLV_U2FREQ + 0x10)
+#define P2F_USB_FM_VALID BIT(0)
+#define P2F_RG_FRCK_EN BIT(8)
+
+#define U3P_REF_CLK 26 /* MHZ */
+#define U3P_SLEW_RATE_COEF 28
+#define U3P_SR_COEF_DIVISOR 1000
+#define U3P_FM_DET_CYCLE_CNT 1024
+
struct mt65xx_phy_instance {
struct phy *phy;
void __iomem *port_base;
@@ -126,6 +149,77 @@ struct mt65xx_u3phy {
int nphys;
};
+static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
+ struct mt65xx_phy_instance *instance)
+{
+ void __iomem *sif_base = u3phy->sif_base;
+ int calibration_val;
+ int fm_out;
+ u32 tmp;
+
+ /* enable USB ring oscillator */
+ tmp = readl(instance->port_base + U3P_USBPHYACR5);
+ tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
+ writel(tmp, instance->port_base + U3P_USBPHYACR5);
+ udelay(1);
+
+ /*enable free run clock */
+ tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
+ tmp |= P2F_RG_FRCK_EN;
+ writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
+
+ /* set cycle count as 1024, and select u2 channel */
+ tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
+ tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
+ tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
+ tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index);
+ writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
+
+ /* enable frequency meter */
+ tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
+ tmp |= P2F_RG_FREQDET_EN;
+ writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
+
+ /* ignore return value */
+ readl_poll_timeout(sif_base + U3P_U2FREQ_FMMONR1, tmp,
+ (tmp & P2F_USB_FM_VALID), 10, 200);
+
+ fm_out = readl(sif_base + U3P_U2FREQ_VALUE);
+
+ /* disable frequency meter */
+ tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
+ tmp &= ~P2F_RG_FREQDET_EN;
+ writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
+
+ /*disable free run clock */
+ tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
+ tmp &= ~P2F_RG_FRCK_EN;
+ writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
+
+ if (fm_out) {
+ /* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
+ tmp = U3P_FM_DET_CYCLE_CNT * U3P_REF_CLK * U3P_SLEW_RATE_COEF;
+ tmp /= fm_out;
+ calibration_val = DIV_ROUND_CLOSEST(tmp, U3P_SR_COEF_DIVISOR);
+ } else {
+ /* if FM detection fail, set default value */
+ calibration_val = 4;
+ }
+ dev_dbg(u3phy->dev, "phy:%d, fm_out:%d, calib:%d\n",
+ instance->index, fm_out, calibration_val);
+
+ /* set HS slew rate */
+ tmp = readl(instance->port_base + U3P_USBPHYACR5);
+ tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
+ tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
+ writel(tmp, instance->port_base + U3P_USBPHYACR5);
+
+ /* disable USB ring oscillator */
+ tmp = readl(instance->port_base + U3P_USBPHYACR5);
+ tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
+ writel(tmp, instance->port_base + U3P_USBPHYACR5);
+}
+
static void phy_instance_init(struct mt65xx_u3phy *u3phy,
struct mt65xx_phy_instance *instance)
{
@@ -165,9 +259,10 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
writel(tmp, port_base + U3P_U2PHYDTM0);
}
- /* DP/DM BC1.1 path Disable */
tmp = readl(port_base + U3P_USBPHYACR6);
- tmp &= ~PA6_RG_U2_BC11_SW_EN;
+ tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
+ tmp &= ~PA6_RG_U2_SQTH;
+ tmp |= PA6_RG_U2_SQTH_VAL(2);
writel(tmp, port_base + U3P_USBPHYACR6);
tmp = readl(port_base + U3P_U3PHYA_DA_REG0);
@@ -223,9 +318,9 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
- /* [mt8173]disable Change 100uA current from SSUSB */
+ /* [mt8173]switch 100uA current to SSUSB */
tmp = readl(port_base + U3P_USBPHYACR5);
- tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
+ tmp |= PA5_RG_U2_HS_100U_U3_EN;
writel(tmp, port_base + U3P_USBPHYACR5);
}
@@ -270,7 +365,7 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
writel(tmp, port_base + U3P_USBPHYACR6);
if (!index) {
- /* (also disable)Change 100uA current switch to USB2.0 */
+ /* switch 100uA current back to USB2.0 */
tmp = readl(port_base + U3P_USBPHYACR5);
tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
writel(tmp, port_base + U3P_USBPHYACR5);
@@ -340,6 +435,7 @@ static int mt65xx_phy_power_on(struct phy *phy)
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
phy_instance_power_on(u3phy, instance);
+ hs_slew_rate_calibrate(u3phy, instance);
return 0;
}
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 0fe80589ffbe..c134989052f5 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -29,6 +29,8 @@
#include <linux/delay.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/phy/phy.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <linux/of_platform.h>
#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
@@ -97,22 +99,38 @@ static int omap_usb_set_peripheral(struct usb_otg *otg,
return 0;
}
+static int omap_usb_phy_power(struct omap_usb *phy, int on)
+{
+ u32 val;
+ int ret;
+
+ if (!phy->syscon_phy_power) {
+ omap_control_phy_power(phy->control_dev, on);
+ return 0;
+ }
+
+ if (on)
+ val = phy->power_on;
+ else
+ val = phy->power_off;
+
+ ret = regmap_update_bits(phy->syscon_phy_power, phy->power_reg,
+ phy->mask, val);
+ return ret;
+}
+
static int omap_usb_power_off(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
- omap_control_phy_power(phy->control_dev, 0);
-
- return 0;
+ return omap_usb_phy_power(phy, false);
}
static int omap_usb_power_on(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
- omap_control_phy_power(phy->control_dev, 1);
-
- return 0;
+ return omap_usb_phy_power(phy, true);
}
static int omap_usb_init(struct phy *x)
@@ -147,21 +165,38 @@ static const struct phy_ops ops = {
static const struct usb_phy_data omap_usb2_data = {
.label = "omap_usb2",
.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
+ .mask = OMAP_DEV_PHY_PD,
+ .power_off = OMAP_DEV_PHY_PD,
};
static const struct usb_phy_data omap5_usb2_data = {
.label = "omap5_usb2",
.flags = 0,
+ .mask = OMAP_DEV_PHY_PD,
+ .power_off = OMAP_DEV_PHY_PD,
};
static const struct usb_phy_data dra7x_usb2_data = {
.label = "dra7x_usb2",
.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+ .mask = OMAP_DEV_PHY_PD,
+ .power_off = OMAP_DEV_PHY_PD,
+};
+
+static const struct usb_phy_data dra7x_usb2_phy2_data = {
+ .label = "dra7x_usb2_phy2",
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+ .mask = OMAP_USB2_PHY_PD,
+ .power_off = OMAP_USB2_PHY_PD,
};
static const struct usb_phy_data am437x_usb2_data = {
.label = "am437x_usb2",
.flags = 0,
+ .mask = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD |
+ AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
+ .power_on = AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
+ .power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
};
static const struct of_device_id omap_usb2_id_table[] = {
@@ -178,6 +213,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
.data = &dra7x_usb2_data,
},
{
+ .compatible = "ti,dra7x-usb2-phy2",
+ .data = &dra7x_usb2_phy2_data,
+ },
+ {
.compatible = "ti,am437x-usb2",
.data = &am437x_usb2_data,
},
@@ -219,6 +258,9 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy->phy.label = phy_data->label;
phy->phy.otg = otg;
phy->phy.type = USB_PHY_TYPE_USB2;
+ phy->mask = phy_data->mask;
+ phy->power_on = phy_data->power_on;
+ phy->power_off = phy_data->power_off;
if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -228,21 +270,36 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
}
- control_node = of_parse_phandle(node, "ctrl-module", 0);
- if (!control_node) {
- dev_err(&pdev->dev, "Failed to get control device phandle\n");
- return -EINVAL;
- }
+ phy->syscon_phy_power = syscon_regmap_lookup_by_phandle(node,
+ "syscon-phy-power");
+ if (IS_ERR(phy->syscon_phy_power)) {
+ dev_dbg(&pdev->dev,
+ "can't get syscon-phy-power, using control device\n");
+ phy->syscon_phy_power = NULL;
+
+ control_node = of_parse_phandle(node, "ctrl-module", 0);
+ if (!control_node) {
+ dev_err(&pdev->dev,
+ "Failed to get control device phandle\n");
+ return -EINVAL;
+ }
- control_pdev = of_find_device_by_node(control_node);
- if (!control_pdev) {
- dev_err(&pdev->dev, "Failed to get control device\n");
- return -EINVAL;
+ control_pdev = of_find_device_by_node(control_node);
+ if (!control_pdev) {
+ dev_err(&pdev->dev, "Failed to get control device\n");
+ return -EINVAL;
+ }
+ phy->control_dev = &control_pdev->dev;
+ } else {
+ if (of_property_read_u32_index(node,
+ "syscon-phy-power", 1,
+ &phy->power_reg)) {
+ dev_err(&pdev->dev,
+ "couldn't get power reg. offset\n");
+ return -EINVAL;
+ }
}
- phy->control_dev = &control_pdev->dev;
- omap_control_phy_power(phy->control_dev, 0);
-
otg->set_host = omap_usb_set_host;
otg->set_peripheral = omap_usb_set_peripheral;
if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
@@ -261,6 +318,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
}
phy_set_drvdata(generic_phy, phy);
+ omap_usb_power_off(generic_phy);
phy_provider = devm_of_phy_provider_register(phy->dev,
of_phy_simple_xlate);
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
new file mode 100644
index 000000000000..ef332ef4abc7
--- /dev/null
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -0,0 +1,378 @@
+/*
+ * Renesas R-Car Gen3 for USB2.0 PHY driver
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This is based on the phy-rcar-gen2 driver:
+ * Copyright (C) 2014 Renesas Solutions Corp.
+ * Copyright (C) 2014 Cogent Embedded, Inc.
+ *
+ * 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/******* USB2.0 Host registers (original offset is +0x200) *******/
+#define USB2_INT_ENABLE 0x000
+#define USB2_USBCTR 0x00c
+#define USB2_SPD_RSM_TIMSET 0x10c
+#define USB2_OC_TIMSET 0x110
+#define USB2_COMMCTRL 0x600
+#define USB2_OBINTSTA 0x604
+#define USB2_OBINTEN 0x608
+#define USB2_VBCTRL 0x60c
+#define USB2_LINECTRL1 0x610
+#define USB2_ADPCTRL 0x630
+
+/* INT_ENABLE */
+#define USB2_INT_ENABLE_UCOM_INTEN BIT(3)
+#define USB2_INT_ENABLE_USBH_INTB_EN BIT(2)
+#define USB2_INT_ENABLE_USBH_INTA_EN BIT(1)
+#define USB2_INT_ENABLE_INIT (USB2_INT_ENABLE_UCOM_INTEN | \
+ USB2_INT_ENABLE_USBH_INTB_EN | \
+ USB2_INT_ENABLE_USBH_INTA_EN)
+
+/* USBCTR */
+#define USB2_USBCTR_DIRPD BIT(2)
+#define USB2_USBCTR_PLL_RST BIT(1)
+
+/* SPD_RSM_TIMSET */
+#define USB2_SPD_RSM_TIMSET_INIT 0x014e029b
+
+/* OC_TIMSET */
+#define USB2_OC_TIMSET_INIT 0x000209ab
+
+/* COMMCTRL */
+#define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */
+
+/* OBINTSTA and OBINTEN */
+#define USB2_OBINT_SESSVLDCHG BIT(12)
+#define USB2_OBINT_IDDIGCHG BIT(11)
+#define USB2_OBINT_BITS (USB2_OBINT_SESSVLDCHG | \
+ USB2_OBINT_IDDIGCHG)
+
+/* VBCTRL */
+#define USB2_VBCTRL_DRVVBUSSEL BIT(8)
+
+/* LINECTRL1 */
+#define USB2_LINECTRL1_DPRPD_EN BIT(19)
+#define USB2_LINECTRL1_DP_RPD BIT(18)
+#define USB2_LINECTRL1_DMRPD_EN BIT(17)
+#define USB2_LINECTRL1_DM_RPD BIT(16)
+
+/* ADPCTRL */
+#define USB2_ADPCTRL_OTGSESSVLD BIT(20)
+#define USB2_ADPCTRL_IDDIG BIT(19)
+#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
+#define USB2_ADPCTRL_DRVVBUS BIT(4)
+
+/******* HSUSB registers (original offset is +0x100) *******/
+#define HSUSB_LPSTS 0x02
+#define HSUSB_UGCTRL2 0x84
+
+/* Low Power Status register (LPSTS) */
+#define HSUSB_LPSTS_SUSPM 0x4000
+
+/* USB General control register 2 (UGCTRL2) */
+#define HSUSB_UGCTRL2_MASK 0x00000031 /* bit[31:6] should be 0 */
+#define HSUSB_UGCTRL2_USB0SEL 0x00000030
+#define HSUSB_UGCTRL2_USB0SEL_HOST 0x00000010
+#define HSUSB_UGCTRL2_USB0SEL_HS_USB 0x00000020
+#define HSUSB_UGCTRL2_USB0SEL_OTG 0x00000030
+
+struct rcar_gen3_data {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+struct rcar_gen3_chan {
+ struct rcar_gen3_data usb2;
+ struct rcar_gen3_data hsusb;
+ struct phy *phy;
+};
+
+static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
+{
+ void __iomem *usb2_base = ch->usb2.base;
+ u32 val = readl(usb2_base + USB2_COMMCTRL);
+
+ dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host);
+ if (host)
+ val &= ~USB2_COMMCTRL_OTG_PERI;
+ else
+ val |= USB2_COMMCTRL_OTG_PERI;
+ writel(val, usb2_base + USB2_COMMCTRL);
+}
+
+static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
+{
+ void __iomem *usb2_base = ch->usb2.base;
+ u32 val = readl(usb2_base + USB2_LINECTRL1);
+
+ dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm);
+ val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
+ if (dp)
+ val |= USB2_LINECTRL1_DP_RPD;
+ if (dm)
+ val |= USB2_LINECTRL1_DM_RPD;
+ writel(val, usb2_base + USB2_LINECTRL1);
+}
+
+static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
+{
+ void __iomem *usb2_base = ch->usb2.base;
+ u32 val = readl(usb2_base + USB2_ADPCTRL);
+
+ dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus);
+ if (vbus)
+ val |= USB2_ADPCTRL_DRVVBUS;
+ else
+ val &= ~USB2_ADPCTRL_DRVVBUS;
+ writel(val, usb2_base + USB2_ADPCTRL);
+}
+
+static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
+{
+ rcar_gen3_set_linectrl(ch, 1, 1);
+ rcar_gen3_set_host_mode(ch, 1);
+ rcar_gen3_enable_vbus_ctrl(ch, 1);
+}
+
+static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
+{
+ rcar_gen3_set_linectrl(ch, 0, 1);
+ rcar_gen3_set_host_mode(ch, 0);
+ rcar_gen3_enable_vbus_ctrl(ch, 0);
+}
+
+static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
+{
+ return !!(readl(ch->usb2.base + USB2_ADPCTRL) &
+ USB2_ADPCTRL_OTGSESSVLD);
+}
+
+static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
+{
+ return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
+}
+
+static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
+{
+ bool is_host = true;
+
+ /* B-device? */
+ if (rcar_gen3_check_id(ch) && rcar_gen3_check_vbus(ch))
+ is_host = false;
+
+ if (is_host)
+ rcar_gen3_init_for_host(ch);
+ else
+ rcar_gen3_init_for_peri(ch);
+}
+
+static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
+{
+ void __iomem *usb2_base = ch->usb2.base;
+ u32 val;
+
+ val = readl(usb2_base + USB2_VBCTRL);
+ writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
+ writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
+ val = readl(usb2_base + USB2_OBINTEN);
+ writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
+ val = readl(usb2_base + USB2_ADPCTRL);
+ writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
+ val = readl(usb2_base + USB2_LINECTRL1);
+ rcar_gen3_set_linectrl(ch, 0, 0);
+ writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN,
+ usb2_base + USB2_LINECTRL1);
+
+ rcar_gen3_device_recognition(ch);
+}
+
+static int rcar_gen3_phy_usb2_init(struct phy *p)
+{
+ struct rcar_gen3_chan *channel = phy_get_drvdata(p);
+ void __iomem *usb2_base = channel->usb2.base;
+ void __iomem *hsusb_base = channel->hsusb.base;
+ u32 val;
+
+ /* Initialize USB2 part */
+ writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
+ writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
+ writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
+
+ /* Initialize HSUSB part */
+ if (hsusb_base) {
+ val = readl(hsusb_base + HSUSB_UGCTRL2);
+ val = (val & ~HSUSB_UGCTRL2_USB0SEL) |
+ HSUSB_UGCTRL2_USB0SEL_OTG;
+ writel(val & HSUSB_UGCTRL2_MASK, hsusb_base + HSUSB_UGCTRL2);
+
+ /* Initialize otg part */
+ rcar_gen3_init_otg(channel);
+ }
+
+ return 0;
+}
+
+static int rcar_gen3_phy_usb2_exit(struct phy *p)
+{
+ struct rcar_gen3_chan *channel = phy_get_drvdata(p);
+
+ writel(0, channel->usb2.base + USB2_INT_ENABLE);
+
+ return 0;
+}
+
+static int rcar_gen3_phy_usb2_power_on(struct phy *p)
+{
+ struct rcar_gen3_chan *channel = phy_get_drvdata(p);
+ void __iomem *usb2_base = channel->usb2.base;
+ void __iomem *hsusb_base = channel->hsusb.base;
+ u32 val;
+
+ val = readl(usb2_base + USB2_USBCTR);
+ val |= USB2_USBCTR_PLL_RST;
+ writel(val, usb2_base + USB2_USBCTR);
+ val &= ~USB2_USBCTR_PLL_RST;
+ writel(val, usb2_base + USB2_USBCTR);
+
+ /*
+ * TODO: To reduce power consuming, this driver should set the SUSPM
+ * after the PHY detects ID pin as peripheral.
+ */
+ if (hsusb_base) {
+ /* Power on HSUSB PHY */
+ val = readw(hsusb_base + HSUSB_LPSTS);
+ val |= HSUSB_LPSTS_SUSPM;
+ writew(val, hsusb_base + HSUSB_LPSTS);
+ }
+
+ return 0;
+}
+
+static int rcar_gen3_phy_usb2_power_off(struct phy *p)
+{
+ struct rcar_gen3_chan *channel = phy_get_drvdata(p);
+ void __iomem *hsusb_base = channel->hsusb.base;
+ u32 val;
+
+ if (hsusb_base) {
+ /* Power off HSUSB PHY */
+ val = readw(hsusb_base + HSUSB_LPSTS);
+ val &= ~HSUSB_LPSTS_SUSPM;
+ writew(val, hsusb_base + HSUSB_LPSTS);
+ }
+
+ return 0;
+}
+
+static struct phy_ops rcar_gen3_phy_usb2_ops = {
+ .init = rcar_gen3_phy_usb2_init,
+ .exit = rcar_gen3_phy_usb2_exit,
+ .power_on = rcar_gen3_phy_usb2_power_on,
+ .power_off = rcar_gen3_phy_usb2_power_off,
+ .owner = THIS_MODULE,
+};
+
+static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
+{
+ struct rcar_gen3_chan *ch = _ch;
+ void __iomem *usb2_base = ch->usb2.base;
+ u32 status = readl(usb2_base + USB2_OBINTSTA);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (status & USB2_OBINT_BITS) {
+ dev_vdbg(&ch->phy->dev, "%s: %08x\n", __func__, status);
+ writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
+ rcar_gen3_device_recognition(ch);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
+ { .compatible = "renesas,usb2-phy-r8a7795" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
+
+static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rcar_gen3_chan *channel;
+ struct phy_provider *provider;
+ struct resource *res;
+
+ if (!dev->of_node) {
+ dev_err(dev, "This driver needs device tree\n");
+ return -EINVAL;
+ }
+
+ channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL);
+ if (!channel)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usb2_host");
+ channel->usb2.base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(channel->usb2.base))
+ return PTR_ERR(channel->usb2.base);
+
+ /* "hsusb" memory resource is optional */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsusb");
+
+ /* To avoid error message by devm_ioremap_resource() */
+ if (res) {
+ int irq;
+
+ channel->hsusb.base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(channel->hsusb.base))
+ channel->hsusb.base = NULL;
+ /* call request_irq for OTG */
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0)
+ irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
+ IRQF_SHARED, dev_name(dev),
+ channel);
+ if (irq < 0)
+ dev_err(dev, "No irq handler (%d)\n", irq);
+ }
+
+ /* devm_phy_create() will call pm_runtime_enable(dev); */
+ channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
+ if (IS_ERR(channel->phy)) {
+ dev_err(dev, "Failed to create USB2 PHY\n");
+ return PTR_ERR(channel->phy);
+ }
+
+ phy_set_drvdata(channel->phy, channel);
+
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(provider))
+ dev_err(dev, "Failed to register PHY provider\n");
+
+ return PTR_ERR_OR_ZERO(provider);
+}
+
+static struct platform_driver rcar_gen3_phy_usb2_driver = {
+ .driver = {
+ .name = "phy_rcar_gen3_usb2",
+ .of_match_table = rcar_gen3_phy_usb2_match_table,
+ },
+ .probe = rcar_gen3_phy_usb2_probe,
+};
+module_platform_driver(rcar_gen3_phy_usb2_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY");
+MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c
index 62c43c435194..33a80eba1cb4 100644
--- a/drivers/phy/phy-rockchip-usb.c
+++ b/drivers/phy/phy-rockchip-usb.c
@@ -15,12 +15,14 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -36,120 +38,281 @@
#define SIDDQ_ON BIT(13)
#define SIDDQ_OFF (0 << 13)
+struct rockchip_usb_phys {
+ int reg;
+ const char *pll_name;
+};
+
+struct rockchip_usb_phy_pdata {
+ struct rockchip_usb_phys *phys;
+};
+
+struct rockchip_usb_phy_base {
+ struct device *dev;
+ struct regmap *reg_base;
+ const struct rockchip_usb_phy_pdata *pdata;
+};
+
struct rockchip_usb_phy {
+ struct rockchip_usb_phy_base *base;
+ struct device_node *np;
unsigned int reg_offset;
- struct regmap *reg_base;
struct clk *clk;
+ struct clk *clk480m;
+ struct clk_hw clk480m_hw;
struct phy *phy;
};
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
bool siddq)
{
- return regmap_write(phy->reg_base, phy->reg_offset,
+ return regmap_write(phy->base->reg_base, phy->reg_offset,
SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
}
-static int rockchip_usb_phy_power_off(struct phy *_phy)
+static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
{
- struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
- int ret = 0;
+ return 480000000;
+}
+
+static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
+{
+ struct rockchip_usb_phy *phy = container_of(hw,
+ struct rockchip_usb_phy,
+ clk480m_hw);
/* Power down usb phy analog blocks by set siddq 1 */
- ret = rockchip_usb_phy_power(phy, 1);
- if (ret)
- return ret;
+ rockchip_usb_phy_power(phy, 1);
+}
- clk_disable_unprepare(phy->clk);
+static int rockchip_usb_phy480m_enable(struct clk_hw *hw)
+{
+ struct rockchip_usb_phy *phy = container_of(hw,
+ struct rockchip_usb_phy,
+ clk480m_hw);
- return 0;
+ /* Power up usb phy analog blocks by set siddq 0 */
+ return rockchip_usb_phy_power(phy, 0);
}
-static int rockchip_usb_phy_power_on(struct phy *_phy)
+static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
{
- struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
- int ret = 0;
+ struct rockchip_usb_phy *phy = container_of(hw,
+ struct rockchip_usb_phy,
+ clk480m_hw);
+ int ret;
+ u32 val;
- ret = clk_prepare_enable(phy->clk);
- if (ret)
+ ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val);
+ if (ret < 0)
return ret;
- /* Power up usb phy analog blocks by set siddq 0 */
- ret = rockchip_usb_phy_power(phy, 0);
- if (ret) {
- clk_disable_unprepare(phy->clk);
- return ret;
- }
+ return (val & SIDDQ_ON) ? 0 : 1;
+}
+
+static const struct clk_ops rockchip_usb_phy480m_ops = {
+ .enable = rockchip_usb_phy480m_enable,
+ .disable = rockchip_usb_phy480m_disable,
+ .is_enabled = rockchip_usb_phy480m_is_enabled,
+ .recalc_rate = rockchip_usb_phy480m_recalc_rate,
+};
+
+static int rockchip_usb_phy_power_off(struct phy *_phy)
+{
+ struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+
+ clk_disable_unprepare(phy->clk480m);
return 0;
}
+static int rockchip_usb_phy_power_on(struct phy *_phy)
+{
+ struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+
+ return clk_prepare_enable(phy->clk480m);
+}
+
static const struct phy_ops ops = {
.power_on = rockchip_usb_phy_power_on,
.power_off = rockchip_usb_phy_power_off,
.owner = THIS_MODULE,
};
-static int rockchip_usb_phy_probe(struct platform_device *pdev)
+static void rockchip_usb_phy_action(void *data)
+{
+ struct rockchip_usb_phy *rk_phy = data;
+
+ of_clk_del_provider(rk_phy->np);
+ clk_unregister(rk_phy->clk480m);
+
+ if (rk_phy->clk)
+ clk_put(rk_phy->clk);
+}
+
+static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
+ struct device_node *child)
{
- struct device *dev = &pdev->dev;
struct rockchip_usb_phy *rk_phy;
- struct phy_provider *phy_provider;
- struct device_node *child;
- struct regmap *grf;
unsigned int reg_offset;
- int err;
+ const char *clk_name;
+ struct clk_init_data init;
+ int err, i;
- grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
- if (IS_ERR(grf)) {
- dev_err(&pdev->dev, "Missing rockchip,grf property\n");
- return PTR_ERR(grf);
+ rk_phy = devm_kzalloc(base->dev, sizeof(*rk_phy), GFP_KERNEL);
+ if (!rk_phy)
+ return -ENOMEM;
+
+ rk_phy->base = base;
+ rk_phy->np = child;
+
+ if (of_property_read_u32(child, "reg", &reg_offset)) {
+ dev_err(base->dev, "missing reg property in node %s\n",
+ child->name);
+ return -EINVAL;
}
- for_each_available_child_of_node(dev->of_node, child) {
- rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
- if (!rk_phy) {
- err = -ENOMEM;
- goto put_child;
- }
+ rk_phy->reg_offset = reg_offset;
+
+ rk_phy->clk = of_clk_get_by_name(child, "phyclk");
+ if (IS_ERR(rk_phy->clk))
+ rk_phy->clk = NULL;
- if (of_property_read_u32(child, "reg", &reg_offset)) {
- dev_err(dev, "missing reg property in node %s\n",
- child->name);
- err = -EINVAL;
- goto put_child;
+ i = 0;
+ init.name = NULL;
+ while (base->pdata->phys[i].reg) {
+ if (base->pdata->phys[i].reg == reg_offset) {
+ init.name = base->pdata->phys[i].pll_name;
+ break;
}
+ i++;
+ }
- rk_phy->reg_offset = reg_offset;
- rk_phy->reg_base = grf;
+ if (!init.name) {
+ dev_err(base->dev, "phy data not found\n");
+ return -EINVAL;
+ }
- rk_phy->clk = of_clk_get_by_name(child, "phyclk");
- if (IS_ERR(rk_phy->clk))
- rk_phy->clk = NULL;
+ if (rk_phy->clk) {
+ clk_name = __clk_get_name(rk_phy->clk);
+ init.flags = 0;
+ init.parent_names = &clk_name;
+ init.num_parents = 1;
+ } else {
+ init.flags = CLK_IS_ROOT;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ }
- rk_phy->phy = devm_phy_create(dev, child, &ops);
- if (IS_ERR(rk_phy->phy)) {
- dev_err(dev, "failed to create PHY\n");
- err = PTR_ERR(rk_phy->phy);
- goto put_child;
- }
- phy_set_drvdata(rk_phy->phy, rk_phy);
+ init.ops = &rockchip_usb_phy480m_ops;
+ rk_phy->clk480m_hw.init = &init;
- /* only power up usb phy when it use, so disable it when init*/
- err = rockchip_usb_phy_power(rk_phy, 1);
- if (err)
- goto put_child;
+ rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
+ if (IS_ERR(rk_phy->clk480m)) {
+ err = PTR_ERR(rk_phy->clk480m);
+ goto err_clk;
+ }
+
+ err = of_clk_add_provider(child, of_clk_src_simple_get,
+ rk_phy->clk480m);
+ if (err < 0)
+ goto err_clk_prov;
+
+ err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy);
+ if (err)
+ goto err_devm_action;
+
+ rk_phy->phy = devm_phy_create(base->dev, child, &ops);
+ if (IS_ERR(rk_phy->phy)) {
+ dev_err(base->dev, "failed to create PHY\n");
+ return PTR_ERR(rk_phy->phy);
+ }
+ phy_set_drvdata(rk_phy->phy, rk_phy);
+
+ /* only power up usb phy when it use, so disable it when init*/
+ return rockchip_usb_phy_power(rk_phy, 1);
+
+err_devm_action:
+ of_clk_del_provider(child);
+err_clk_prov:
+ clk_unregister(rk_phy->clk480m);
+err_clk:
+ if (rk_phy->clk)
+ clk_put(rk_phy->clk);
+ return err;
+}
+
+static const struct rockchip_usb_phy_pdata rk3066a_pdata = {
+ .phys = (struct rockchip_usb_phys[]){
+ { .reg = 0x17c, .pll_name = "sclk_otgphy0_480m" },
+ { .reg = 0x188, .pll_name = "sclk_otgphy1_480m" },
+ { /* sentinel */ }
+ },
+};
+
+static const struct rockchip_usb_phy_pdata rk3188_pdata = {
+ .phys = (struct rockchip_usb_phys[]){
+ { .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" },
+ { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
+ { /* sentinel */ }
+ },
+};
+
+static const struct rockchip_usb_phy_pdata rk3288_pdata = {
+ .phys = (struct rockchip_usb_phys[]){
+ { .reg = 0x320, .pll_name = "sclk_otgphy0_480m" },
+ { .reg = 0x334, .pll_name = "sclk_otgphy1_480m" },
+ { .reg = 0x348, .pll_name = "sclk_otgphy2_480m" },
+ { /* sentinel */ }
+ },
+};
+
+static int rockchip_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rockchip_usb_phy_base *phy_base;
+ struct phy_provider *phy_provider;
+ const struct of_device_id *match;
+ struct device_node *child;
+ int err;
+
+ phy_base = devm_kzalloc(dev, sizeof(*phy_base), GFP_KERNEL);
+ if (!phy_base)
+ return -ENOMEM;
+
+ match = of_match_device(dev->driver->of_match_table, dev);
+ if (!match || !match->data) {
+ dev_err(dev, "missing phy data\n");
+ return -EINVAL;
+ }
+
+ phy_base->pdata = match->data;
+
+ phy_base->dev = dev;
+ phy_base->reg_base = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "rockchip,grf");
+ if (IS_ERR(phy_base->reg_base)) {
+ dev_err(&pdev->dev, "Missing rockchip,grf property\n");
+ return PTR_ERR(phy_base->reg_base);
+ }
+
+ for_each_available_child_of_node(dev->of_node, child) {
+ err = rockchip_usb_phy_init(phy_base, child);
+ if (err) {
+ of_node_put(child);
+ return err;
+ }
}
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
-put_child:
- of_node_put(child);
- return err;
}
static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
- { .compatible = "rockchip,rk3288-usb-phy" },
+ { .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata },
+ { .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata },
+ { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
{}
};
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index b12964b70625..bae54f7a1f48 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -32,6 +32,7 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-sun4i-usb.h>
@@ -46,6 +47,9 @@
#define REG_PHYBIST 0x08
#define REG_PHYTUNE 0x0c
#define REG_PHYCTL_A33 0x10
+#define REG_PHY_UNK_H3 0x20
+
+#define REG_PMU_UNK_H3 0x10
#define PHYCTL_DATA BIT(7)
@@ -79,7 +83,7 @@
#define PHY_DISCON_TH_SEL 0x2a
#define PHY_SQUELCH_DETECT 0x3c
-#define MAX_PHYS 3
+#define MAX_PHYS 4
/*
* Note do not raise the debounce time, we must report Vusb high within 100ms
@@ -88,12 +92,24 @@
#define DEBOUNCE_TIME msecs_to_jiffies(50)
#define POLL_TIME msecs_to_jiffies(250)
+enum sun4i_usb_phy_type {
+ sun4i_a10_phy,
+ sun8i_a33_phy,
+ sun8i_h3_phy,
+};
+
+struct sun4i_usb_phy_cfg {
+ int num_phys;
+ enum sun4i_usb_phy_type type;
+ u32 disc_thresh;
+ u8 phyctl_offset;
+ bool dedicated_clocks;
+};
+
struct sun4i_usb_phy_data {
void __iomem *base;
+ const struct sun4i_usb_phy_cfg *cfg;
struct mutex mutex;
- int num_phys;
- u32 disc_thresh;
- bool has_a33_phyctl;
struct sun4i_usb_phy {
struct phy *phy;
void __iomem *pmu;
@@ -159,17 +175,14 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
{
struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
u32 temp, usbc_bit = BIT(phy->index * 2);
- void *phyctl;
+ void *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
int i;
mutex_lock(&phy_data->mutex);
- if (phy_data->has_a33_phyctl) {
- phyctl = phy_data->base + REG_PHYCTL_A33;
+ if (phy_data->cfg->type == sun8i_a33_phy) {
/* A33 needs us to set phyctl to 0 explicitly */
writel(0, phyctl);
- } else {
- phyctl = phy_data->base + REG_PHYCTL_A10;
}
for (i = 0; i < len; i++) {
@@ -230,6 +243,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
int ret;
+ u32 val;
ret = clk_prepare_enable(phy->clk);
if (ret)
@@ -241,15 +255,26 @@ static int sun4i_usb_phy_init(struct phy *_phy)
return ret;
}
- /* Enable USB 45 Ohm resistor calibration */
- if (phy->index == 0)
- sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
+ if (data->cfg->type == sun8i_h3_phy) {
+ if (phy->index == 0) {
+ val = readl(data->base + REG_PHY_UNK_H3);
+ writel(val & ~1, data->base + REG_PHY_UNK_H3);
+ }
- /* Adjust PHY's magnitude and rate */
- sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+ val = readl(phy->pmu + REG_PMU_UNK_H3);
+ writel(val & ~2, phy->pmu + REG_PMU_UNK_H3);
+ } else {
+ /* Enable USB 45 Ohm resistor calibration */
+ if (phy->index == 0)
+ sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
- /* Disconnect threshold adjustment */
- sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->disc_thresh, 2);
+ /* Adjust PHY's magnitude and rate */
+ sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+
+ /* Disconnect threshold adjustment */
+ sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
+ data->cfg->disc_thresh, 2);
+ }
sun4i_usb_phy_passby(phy, 1);
@@ -476,7 +501,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev,
{
struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
- if (args->args[0] >= data->num_phys)
+ if (args->args[0] >= data->cfg->num_phys)
return ERR_PTR(-ENODEV);
return data->phys[args->args[0]].phy;
@@ -511,7 +536,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
- bool dedicated_clocks;
struct resource *res;
int i, ret;
@@ -522,29 +546,9 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
mutex_init(&data->mutex);
INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan);
dev_set_drvdata(dev, data);
-
- if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
- of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
- of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
- data->num_phys = 2;
- else
- data->num_phys = 3;
-
- if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
- of_device_is_compatible(np, "allwinner,sun7i-a20-usb-phy"))
- data->disc_thresh = 2;
- else
- data->disc_thresh = 3;
-
- if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") ||
- of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
- of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
- dedicated_clocks = true;
- else
- dedicated_clocks = false;
-
- if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
- data->has_a33_phyctl = true;
+ data->cfg = of_device_get_match_data(dev);
+ if (!data->cfg)
+ return -EINVAL;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
data->base = devm_ioremap_resource(dev, res);
@@ -590,7 +594,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
}
}
- for (i = 0; i < data->num_phys; i++) {
+ for (i = 0; i < data->cfg->num_phys; i++) {
struct sun4i_usb_phy *phy = data->phys + i;
char name[16];
@@ -602,7 +606,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
phy->vbus = NULL;
}
- if (dedicated_clocks)
+ if (data->cfg->dedicated_clocks)
snprintf(name, sizeof(name), "usb%d_phy", i);
else
strlcpy(name, "usb_phy", sizeof(name));
@@ -689,13 +693,69 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return 0;
}
+static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
+ .num_phys = 3,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
+ .num_phys = 2,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 2,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
+ .num_phys = 3,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
+ .num_phys = 3,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 2,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = false,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
+ .num_phys = 2,
+ .type = sun4i_a10_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
+ .num_phys = 2,
+ .type = sun8i_a33_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
+ .num_phys = 4,
+ .type = sun8i_h3_phy,
+ .disc_thresh = 3,
+ .dedicated_clocks = true,
+};
+
static const struct of_device_id sun4i_usb_phy_of_match[] = {
- { .compatible = "allwinner,sun4i-a10-usb-phy" },
- { .compatible = "allwinner,sun5i-a13-usb-phy" },
- { .compatible = "allwinner,sun6i-a31-usb-phy" },
- { .compatible = "allwinner,sun7i-a20-usb-phy" },
- { .compatible = "allwinner,sun8i-a23-usb-phy" },
- { .compatible = "allwinner,sun8i-a33-usb-phy" },
+ { .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
+ { .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
+ { .compatible = "allwinner,sun6i-a31-usb-phy", .data = &sun6i_a31_cfg },
+ { .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
+ { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
+ { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
+ { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
{ },
};
MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 93bc1120af12..0a477d24cf76 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -56,6 +56,18 @@
#define SATA_PLL_SOFT_RESET BIT(18)
+#define PIPE3_PHY_PWRCTL_CLK_CMD_MASK 0x003FC000
+#define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14
+
+#define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK 0xFFC00000
+#define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22
+
+#define PIPE3_PHY_TX_RX_POWERON 0x3
+#define PIPE3_PHY_TX_RX_POWEROFF 0x0
+
+#define PCIE_PCS_MASK 0xFF0000
+#define PCIE_PCS_DELAY_COUNT_SHIFT 0x10
+
/*
* This is an Empirical value that works, need to confirm the actual
* value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
@@ -86,8 +98,12 @@ struct ti_pipe3 {
struct clk *refclk;
struct clk *div_clk;
struct pipe3_dpll_map *dpll_map;
+ struct regmap *phy_power_syscon; /* ctrl. reg. acces */
+ struct regmap *pcs_syscon; /* ctrl. reg. acces */
struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */
unsigned int dpll_reset_reg; /* reg. index within syscon */
+ unsigned int power_reg; /* power reg. index within syscon */
+ unsigned int pcie_pcs_reg; /* pcs reg. index in syscon */
bool sata_refclk_enabled;
};
@@ -144,20 +160,49 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy);
static int ti_pipe3_power_off(struct phy *x)
{
+ u32 val;
+ int ret;
struct ti_pipe3 *phy = phy_get_drvdata(x);
- omap_control_phy_power(phy->control_dev, 0);
+ if (!phy->phy_power_syscon) {
+ omap_control_phy_power(phy->control_dev, 0);
+ return 0;
+ }
- return 0;
+ val = PIPE3_PHY_TX_RX_POWEROFF << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+
+ ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg,
+ PIPE3_PHY_PWRCTL_CLK_CMD_MASK, val);
+ return ret;
}
static int ti_pipe3_power_on(struct phy *x)
{
+ u32 val;
+ u32 mask;
+ int ret;
+ unsigned long rate;
struct ti_pipe3 *phy = phy_get_drvdata(x);
- omap_control_phy_power(phy->control_dev, 1);
+ if (!phy->phy_power_syscon) {
+ omap_control_phy_power(phy->control_dev, 1);
+ return 0;
+ }
- return 0;
+ rate = clk_get_rate(phy->sys_clk);
+ if (!rate) {
+ dev_err(phy->dev, "Invalid clock rate\n");
+ return -EINVAL;
+ }
+ rate = rate / 1000000;
+ mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK;
+ val = PIPE3_PHY_TX_RX_POWERON << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+ val |= rate << OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
+
+ ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg,
+ mask, val);
+ return ret;
}
static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
@@ -229,8 +274,15 @@ static int ti_pipe3_init(struct phy *x)
* 18-1804.
*/
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) {
- omap_control_pcie_pcs(phy->control_dev, 0x96);
- return 0;
+ if (!phy->pcs_syscon) {
+ omap_control_pcie_pcs(phy->control_dev, 0x96);
+ return 0;
+ }
+
+ val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT;
+ ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg,
+ PCIE_PCS_MASK, val);
+ return ret;
}
/* Bring it out of IDLE if it is IDLE */
@@ -308,51 +360,15 @@ static const struct phy_ops ops = {
static const struct of_device_id ti_pipe3_id_table[];
-static int ti_pipe3_probe(struct platform_device *pdev)
+static int ti_pipe3_get_clk(struct ti_pipe3 *phy)
{
- struct ti_pipe3 *phy;
- struct phy *generic_phy;
- struct phy_provider *phy_provider;
- struct resource *res;
- struct device_node *node = pdev->dev.of_node;
- struct device_node *control_node;
- struct platform_device *control_pdev;
- const struct of_device_id *match;
struct clk *clk;
+ struct device *dev = phy->dev;
+ struct device_node *node = dev->of_node;
- phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
- if (!phy)
- return -ENOMEM;
-
- phy->dev = &pdev->dev;
-
- if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
- match = of_match_device(ti_pipe3_id_table, &pdev->dev);
- if (!match)
- return -EINVAL;
-
- phy->dpll_map = (struct pipe3_dpll_map *)match->data;
- if (!phy->dpll_map) {
- dev_err(&pdev->dev, "no DPLL data\n");
- return -EINVAL;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "pll_ctrl");
- phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(phy->pll_ctrl_base))
- return PTR_ERR(phy->pll_ctrl_base);
-
- phy->sys_clk = devm_clk_get(phy->dev, "sysclk");
- if (IS_ERR(phy->sys_clk)) {
- dev_err(&pdev->dev, "unable to get sysclk\n");
- return -EINVAL;
- }
- }
-
- phy->refclk = devm_clk_get(phy->dev, "refclk");
+ phy->refclk = devm_clk_get(dev, "refclk");
if (IS_ERR(phy->refclk)) {
- dev_err(&pdev->dev, "unable to get refclk\n");
+ dev_err(dev, "unable to get refclk\n");
/* older DTBs have missing refclk in SATA PHY
* so don't bail out in case of SATA PHY.
*/
@@ -361,80 +377,194 @@ static int ti_pipe3_probe(struct platform_device *pdev)
}
if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
- phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
+ phy->wkupclk = devm_clk_get(dev, "wkupclk");
if (IS_ERR(phy->wkupclk)) {
- dev_err(&pdev->dev, "unable to get wkupclk\n");
+ dev_err(dev, "unable to get wkupclk\n");
return PTR_ERR(phy->wkupclk);
}
} else {
phy->wkupclk = ERR_PTR(-ENODEV);
- phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
- "syscon-pllreset");
- if (IS_ERR(phy->dpll_reset_syscon)) {
- dev_info(&pdev->dev,
- "can't get syscon-pllreset, sata dpll won't idle\n");
- phy->dpll_reset_syscon = NULL;
- } else {
- if (of_property_read_u32_index(node,
- "syscon-pllreset", 1,
- &phy->dpll_reset_reg)) {
- dev_err(&pdev->dev,
- "couldn't get pllreset reg. offset\n");
- return -EINVAL;
- }
+ }
+
+ if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie") ||
+ phy->phy_power_syscon) {
+ phy->sys_clk = devm_clk_get(dev, "sysclk");
+ if (IS_ERR(phy->sys_clk)) {
+ dev_err(dev, "unable to get sysclk\n");
+ return -EINVAL;
}
}
if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
-
- clk = devm_clk_get(phy->dev, "dpll_ref");
+ clk = devm_clk_get(dev, "dpll_ref");
if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "unable to get dpll ref clk\n");
+ dev_err(dev, "unable to get dpll ref clk\n");
return PTR_ERR(clk);
}
clk_set_rate(clk, 1500000000);
- clk = devm_clk_get(phy->dev, "dpll_ref_m2");
+ clk = devm_clk_get(dev, "dpll_ref_m2");
if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "unable to get dpll ref m2 clk\n");
+ dev_err(dev, "unable to get dpll ref m2 clk\n");
return PTR_ERR(clk);
}
clk_set_rate(clk, 100000000);
- clk = devm_clk_get(phy->dev, "phy-div");
+ clk = devm_clk_get(dev, "phy-div");
if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "unable to get phy-div clk\n");
+ dev_err(dev, "unable to get phy-div clk\n");
return PTR_ERR(clk);
}
clk_set_rate(clk, 100000000);
- phy->div_clk = devm_clk_get(phy->dev, "div-clk");
+ phy->div_clk = devm_clk_get(dev, "div-clk");
if (IS_ERR(phy->div_clk)) {
- dev_err(&pdev->dev, "unable to get div-clk\n");
+ dev_err(dev, "unable to get div-clk\n");
return PTR_ERR(phy->div_clk);
}
} else {
phy->div_clk = ERR_PTR(-ENODEV);
}
- control_node = of_parse_phandle(node, "ctrl-module", 0);
- if (!control_node) {
- dev_err(&pdev->dev, "Failed to get control device phandle\n");
- return -EINVAL;
+ return 0;
+}
+
+static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy)
+{
+ struct device *dev = phy->dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *control_node;
+ struct platform_device *control_pdev;
+
+ phy->phy_power_syscon = syscon_regmap_lookup_by_phandle(node,
+ "syscon-phy-power");
+ if (IS_ERR(phy->phy_power_syscon)) {
+ dev_dbg(dev,
+ "can't get syscon-phy-power, using control device\n");
+ phy->phy_power_syscon = NULL;
+ } else {
+ if (of_property_read_u32_index(node,
+ "syscon-phy-power", 1,
+ &phy->power_reg)) {
+ dev_err(dev, "couldn't get power reg. offset\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!phy->phy_power_syscon) {
+ control_node = of_parse_phandle(node, "ctrl-module", 0);
+ if (!control_node) {
+ dev_err(dev, "Failed to get control device phandle\n");
+ return -EINVAL;
+ }
+
+ control_pdev = of_find_device_by_node(control_node);
+ if (!control_pdev) {
+ dev_err(dev, "Failed to get control device\n");
+ return -EINVAL;
+ }
+
+ phy->control_dev = &control_pdev->dev;
+ }
+
+ if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
+ phy->pcs_syscon = syscon_regmap_lookup_by_phandle(node,
+ "syscon-pcs");
+ if (IS_ERR(phy->pcs_syscon)) {
+ dev_dbg(dev,
+ "can't get syscon-pcs, using omap control\n");
+ phy->pcs_syscon = NULL;
+ } else {
+ if (of_property_read_u32_index(node,
+ "syscon-pcs", 1,
+ &phy->pcie_pcs_reg)) {
+ dev_err(dev,
+ "couldn't get pcie pcs reg. offset\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+ phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
+ "syscon-pllreset");
+ if (IS_ERR(phy->dpll_reset_syscon)) {
+ dev_info(dev,
+ "can't get syscon-pllreset, sata dpll won't idle\n");
+ phy->dpll_reset_syscon = NULL;
+ } else {
+ if (of_property_read_u32_index(node,
+ "syscon-pllreset", 1,
+ &phy->dpll_reset_reg)) {
+ dev_err(dev,
+ "couldn't get pllreset reg. offset\n");
+ return -EINVAL;
+ }
+ }
}
- control_pdev = of_find_device_by_node(control_node);
- if (!control_pdev) {
- dev_err(&pdev->dev, "Failed to get control device\n");
+ return 0;
+}
+
+static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy)
+{
+ struct resource *res;
+ const struct of_device_id *match;
+ struct device *dev = phy->dev;
+ struct device_node *node = dev->of_node;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (of_device_is_compatible(node, "ti,phy-pipe3-pcie"))
+ return 0;
+
+ match = of_match_device(ti_pipe3_id_table, dev);
+ if (!match)
+ return -EINVAL;
+
+ phy->dpll_map = (struct pipe3_dpll_map *)match->data;
+ if (!phy->dpll_map) {
+ dev_err(dev, "no DPLL data\n");
return -EINVAL;
}
- phy->control_dev = &control_pdev->dev;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "pll_ctrl");
+ phy->pll_ctrl_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(phy->pll_ctrl_base))
+ return PTR_ERR(phy->pll_ctrl_base);
+
+ return 0;
+}
- omap_control_phy_power(phy->control_dev, 0);
+static int ti_pipe3_probe(struct platform_device *pdev)
+{
+ struct ti_pipe3 *phy;
+ struct phy *generic_phy;
+ struct phy_provider *phy_provider;
+ struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->dev = dev;
+
+ ret = ti_pipe3_get_pll_base(phy);
+ if (ret)
+ return ret;
+
+ ret = ti_pipe3_get_sysctrl(phy);
+ if (ret)
+ return ret;
+
+ ret = ti_pipe3_get_clk(phy);
+ if (ret)
+ return ret;
platform_set_drvdata(pdev, phy);
- pm_runtime_enable(phy->dev);
+ pm_runtime_enable(dev);
/*
* Prevent auto-disable of refclk for SATA PHY due to Errata i783
@@ -446,13 +576,15 @@ static int ti_pipe3_probe(struct platform_device *pdev)
}
}
- generic_phy = devm_phy_create(phy->dev, NULL, &ops);
+ generic_phy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(generic_phy))
return PTR_ERR(generic_phy);
phy_set_drvdata(generic_phy, phy);
- phy_provider = devm_of_phy_provider_register(phy->dev,
- of_phy_simple_xlate);
+
+ ti_pipe3_power_off(generic_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 3a707dd14238..4a3fc6e59f8e 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -34,7 +34,7 @@
#include <linux/usb/otg.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
-#include <linux/usb/musb-omap.h>
+#include <linux/usb/musb.h>
#include <linux/usb/ulpi.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/consumer.h>
@@ -148,10 +148,10 @@
* If VBUS is valid or ID is ground, then we know a
* cable is present and we need to be runtime-enabled
*/
-static inline bool cable_present(enum omap_musb_vbus_id_status stat)
+static inline bool cable_present(enum musb_vbus_id_status stat)
{
- return stat == OMAP_MUSB_VBUS_VALID ||
- stat == OMAP_MUSB_ID_GROUND;
+ return stat == MUSB_VBUS_VALID ||
+ stat == MUSB_ID_GROUND;
}
struct twl4030_usb {
@@ -170,7 +170,7 @@ struct twl4030_usb {
enum twl4030_usb_mode usb_mode;
int irq;
- enum omap_musb_vbus_id_status linkstat;
+ enum musb_vbus_id_status linkstat;
bool vbus_supplied;
struct delayed_work id_workaround_work;
@@ -276,11 +276,11 @@ static bool twl4030_is_driving_vbus(struct twl4030_usb *twl)
return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false;
}
-static enum omap_musb_vbus_id_status
+static enum musb_vbus_id_status
twl4030_usb_linkstat(struct twl4030_usb *twl)
{
int status;
- enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN;
+ enum musb_vbus_id_status linkstat = MUSB_UNKNOWN;
twl->vbus_supplied = false;
@@ -306,14 +306,14 @@ static enum omap_musb_vbus_id_status
}
if (status & BIT(2))
- linkstat = OMAP_MUSB_ID_GROUND;
+ linkstat = MUSB_ID_GROUND;
else if (status & BIT(7))
- linkstat = OMAP_MUSB_VBUS_VALID;
+ linkstat = MUSB_VBUS_VALID;
else
- linkstat = OMAP_MUSB_VBUS_OFF;
+ linkstat = MUSB_VBUS_OFF;
} else {
- if (twl->linkstat != OMAP_MUSB_UNKNOWN)
- linkstat = OMAP_MUSB_VBUS_OFF;
+ if (twl->linkstat != MUSB_UNKNOWN)
+ linkstat = MUSB_VBUS_OFF;
}
dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
@@ -535,7 +535,7 @@ static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
struct twl4030_usb *twl = _twl;
- enum omap_musb_vbus_id_status status;
+ enum musb_vbus_id_status status;
bool status_changed = false;
status = twl4030_usb_linkstat(twl);
@@ -567,11 +567,11 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev);
}
- omap_musb_mailbox(status);
+ musb_mailbox(status);
}
/* don't schedule during sleep - irq works right then */
- if (status == OMAP_MUSB_ID_GROUND && pm_runtime_active(twl->dev)) {
+ if (status == MUSB_ID_GROUND && pm_runtime_active(twl->dev)) {
cancel_delayed_work(&twl->id_workaround_work);
schedule_delayed_work(&twl->id_workaround_work, HZ);
}
@@ -670,7 +670,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl->dev = &pdev->dev;
twl->irq = platform_get_irq(pdev, 0);
twl->vbus_supplied = false;
- twl->linkstat = OMAP_MUSB_UNKNOWN;
+ twl->linkstat = MUSB_UNKNOWN;
twl->phy.dev = twl->dev;
twl->phy.label = "twl4030";
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 75b0d8c8f058..0f5997ceb494 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -23,7 +23,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -337,14 +337,14 @@ static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
return bcm2835_gpio_get_bit(pc, GPLEV0, offset);
}
static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
}
@@ -358,7 +358,7 @@ static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
return irq_linear_revmap(pc->irq_domain, offset);
}
@@ -964,7 +964,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(pc->base);
pc->gpio_chip = bcm2835_gpio_chip;
- pc->gpio_chip.dev = dev;
+ pc->gpio_chip.parent = dev;
pc->gpio_chip.of_node = np;
pc->irq_domain = irq_domain_add_linear(np, BCM2835_NUM_GPIOS,
@@ -1021,7 +1021,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
}
}
- err = gpiochip_add(&pc->gpio_chip);
+ err = gpiochip_add_data(&pc->gpio_chip, pc);
if (err) {
dev_err(dev, "could not add GPIO chip\n");
return err;
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index 314591a4609b..3b2ac8f771ed 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -694,7 +694,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
gc->ngpio = ngpios;
chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
gc->label = dev_name(dev);
- gc->dev = dev;
+ gc->parent = dev;
gc->of_node = dev->of_node;
gc->request = iproc_gpio_request;
gc->free = iproc_gpio_free;
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
index 725c36f917f9..ac900435dc39 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
@@ -18,7 +18,7 @@
* through the interaction with the NSP IOMUX controller.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
@@ -81,11 +81,6 @@ enum base_type {
IO_CTRL
};
-static inline struct nsp_gpio *to_nsp_gpio(struct gpio_chip *gc)
-{
- return container_of(gc, struct nsp_gpio, gc);
-}
-
/*
* Mapping from PINCONF pins to GPIO pins is 1-to-1
*/
@@ -297,7 +292,7 @@ static void nsp_gpio_free(struct gpio_chip *gc, unsigned offset)
static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
{
- struct nsp_gpio *chip = to_nsp_gpio(gc);
+ struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -311,7 +306,7 @@ static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
int val)
{
- struct nsp_gpio *chip = to_nsp_gpio(gc);
+ struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -325,7 +320,7 @@ static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
static void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
{
- struct nsp_gpio *chip = to_nsp_gpio(gc);
+ struct nsp_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -337,14 +332,14 @@ static void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
static int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
- struct nsp_gpio *chip = to_nsp_gpio(gc);
+ struct nsp_gpio *chip = gpiochip_get_data(gc);
return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio));
}
static int nsp_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct nsp_gpio *chip = to_nsp_gpio(gc);
+ struct nsp_gpio *chip = gpiochip_get_data(gc);
return irq_linear_revmap(chip->irq_domain, offset);
}
@@ -669,7 +664,7 @@ static int nsp_gpio_probe(struct platform_device *pdev)
gc->can_sleep = false;
gc->ngpio = val;
gc->label = dev_name(dev);
- gc->dev = dev;
+ gc->parent = dev;
gc->of_node = dev->of_node;
gc->request = nsp_gpio_request;
gc->free = nsp_gpio_free;
@@ -714,7 +709,7 @@ static int nsp_gpio_probe(struct platform_device *pdev)
writel(val, (chip->base + NSP_CHIP_A_INT_MASK));
}
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, chip);
if (ret < 0) {
dev_err(dev, "unable to add GPIO chip\n");
return ret;
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index b59ce75b1947..21b79a446d5a 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -20,7 +20,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
@@ -147,12 +147,10 @@ struct byt_gpio {
struct byt_gpio_pin_context *saved_context;
};
-#define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
-
static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
int reg)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
u32 reg_offset;
if (reg == BYT_INT_STAT_REG)
@@ -193,7 +191,7 @@ static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset)
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
u32 value, gpio_mux;
unsigned long flags;
@@ -229,7 +227,7 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
byt_gpio_clear_triggering(vg, offset);
pm_runtime_put(&vg->pdev->dev);
@@ -237,7 +235,7 @@ static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
static int byt_irq_type(struct irq_data *d, unsigned type)
{
- struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d));
+ struct byt_gpio *vg = gpiochip_get_data(irq_data_get_irq_chip_data(d));
u32 offset = irqd_to_hwirq(d);
u32 value;
unsigned long flags;
@@ -273,7 +271,7 @@ static int byt_irq_type(struct irq_data *d, unsigned type)
static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
{
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -281,12 +279,12 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
val = readl(reg);
raw_spin_unlock_irqrestore(&vg->lock, flags);
- return val & BYT_LEVEL;
+ return !!(val & BYT_LEVEL);
}
static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
unsigned long flags;
u32 old_val;
@@ -305,7 +303,7 @@ static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
unsigned long flags;
u32 value;
@@ -324,7 +322,7 @@ static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int byt_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG);
void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
unsigned long flags;
@@ -356,7 +354,7 @@ static int byt_gpio_direction_output(struct gpio_chip *chip,
static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct byt_gpio *vg = to_byt_gpio(chip);
+ struct byt_gpio *vg = gpiochip_get_data(chip);
int i;
u32 conf0, val, offs;
@@ -428,7 +426,7 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
static void byt_gpio_irq_handler(struct irq_desc *desc)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
- struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
+ struct byt_gpio *vg = gpiochip_get_data(irq_desc_get_handler_data(desc));
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, pin;
void __iomem *reg;
@@ -450,7 +448,7 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
static void byt_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct byt_gpio *vg = to_byt_gpio(gc);
+ struct byt_gpio *vg = gpiochip_get_data(gc);
unsigned offset = irqd_to_hwirq(d);
void __iomem *reg;
@@ -463,7 +461,7 @@ static void byt_irq_ack(struct irq_data *d)
static void byt_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct byt_gpio *vg = to_byt_gpio(gc);
+ struct byt_gpio *vg = gpiochip_get_data(gc);
unsigned offset = irqd_to_hwirq(d);
unsigned long flags;
void __iomem *reg;
@@ -498,7 +496,7 @@ static void byt_irq_unmask(struct irq_data *d)
static void byt_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct byt_gpio *vg = to_byt_gpio(gc);
+ struct byt_gpio *vg = gpiochip_get_data(gc);
byt_gpio_clear_triggering(vg, irqd_to_hwirq(d));
}
@@ -598,14 +596,14 @@ static int byt_gpio_probe(struct platform_device *pdev)
gc->dbg_show = byt_gpio_dbg_show;
gc->base = -1;
gc->can_sleep = false;
- gc->dev = dev;
+ gc->parent = dev;
#ifdef CONFIG_PM_SLEEP
vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio,
sizeof(*vg->saved_context), GFP_KERNEL);
#endif
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, vg);
if (ret) {
dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
return ret;
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 84936bae6e5e..4251e0747a3a 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -181,8 +181,6 @@ struct chv_pinctrl {
struct chv_pin_context *saved_pin_context;
};
-#define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip)
-
#define ALTERNATE_FUNCTION(p, m, i) \
{ \
.pin = (p), \
@@ -1157,7 +1155,7 @@ static unsigned chv_gpio_offset_to_pin(struct chv_pinctrl *pctrl,
static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
int pin = chv_gpio_offset_to_pin(pctrl, offset);
unsigned long flags;
u32 ctrl0, cfg;
@@ -1176,7 +1174,7 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned pin = chv_gpio_offset_to_pin(pctrl, offset);
unsigned long flags;
void __iomem *reg;
@@ -1199,7 +1197,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned pin = chv_gpio_offset_to_pin(pctrl, offset);
u32 ctrl0, direction;
unsigned long flags;
@@ -1240,7 +1238,7 @@ static const struct gpio_chip chv_gpio_chip = {
static void chv_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
u32 intr_line;
@@ -1257,7 +1255,7 @@ static void chv_gpio_irq_ack(struct irq_data *d)
static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
u32 value, intr_line;
unsigned long flags;
@@ -1302,7 +1300,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
*/
if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned offset = irqd_to_hwirq(d);
int pin = chv_gpio_offset_to_pin(pctrl, offset);
irq_flow_handler_t handler;
@@ -1334,7 +1332,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned offset = irqd_to_hwirq(d);
int pin = chv_gpio_offset_to_pin(pctrl, offset);
unsigned long flags;
@@ -1407,7 +1405,7 @@ static struct irq_chip chv_gpio_irqchip = {
static void chv_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long pending;
u32 intr_line;
@@ -1436,10 +1434,10 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
chip->ngpio = pctrl->community->ngpios;
chip->label = dev_name(pctrl->dev);
- chip->dev = pctrl->dev;
+ chip->parent = pctrl->dev;
chip->base = -1;
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "Failed to register gpiochip\n");
return ret;
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 26f6b6ffea5b..c0f5586218c4 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -103,7 +103,6 @@ struct intel_pinctrl {
struct intel_pinctrl_context context;
};
-#define gpiochip_to_pinctrl(c) container_of(c, struct intel_pinctrl, chip)
#define pin_to_padno(c, p) ((p) - (c)->pin_base)
static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl,
@@ -596,7 +595,7 @@ static const struct pinctrl_desc intel_pinctrl_desc = {
static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
void __iomem *reg;
reg = intel_get_padcfg(pctrl, offset, PADCFG0);
@@ -608,7 +607,7 @@ static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
void __iomem *reg;
reg = intel_get_padcfg(pctrl, offset, PADCFG0);
@@ -652,7 +651,7 @@ static const struct gpio_chip intel_gpio_chip = {
static void intel_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
const struct intel_community *community;
unsigned pin = irqd_to_hwirq(d);
@@ -673,7 +672,7 @@ static void intel_gpio_irq_ack(struct irq_data *d)
static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
const struct intel_community *community;
unsigned pin = irqd_to_hwirq(d);
unsigned long flags;
@@ -713,7 +712,7 @@ static void intel_gpio_irq_unmask(struct irq_data *d)
static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned pin = irqd_to_hwirq(d);
unsigned long flags;
void __iomem *reg;
@@ -767,7 +766,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
const struct intel_community *community;
unsigned pin = irqd_to_hwirq(d);
unsigned padno, gpp, gpp_offset;
@@ -872,10 +871,10 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
pctrl->chip.ngpio = pctrl->soc->npins;
pctrl->chip.label = dev_name(pctrl->dev);
- pctrl->chip.dev = pctrl->dev;
+ pctrl->chip.parent = pctrl->dev;
pctrl->chip.base = -1;
- ret = gpiochip_add(&pctrl->chip);
+ ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "failed to register gpiochip\n");
return ret;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index e22cbaf9f9cf..16d48a4ed225 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -95,7 +95,7 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
unsigned int reg_addr;
unsigned int bit;
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dout_offset;
bit = BIT(offset & 0xf);
@@ -750,7 +750,7 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
unsigned int bit;
unsigned int read_val = 0;
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
@@ -763,7 +763,7 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
unsigned int reg_addr;
unsigned int bit;
unsigned int read_val = 0;
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
reg_addr = mtk_get_port(pctl, offset) +
pctl->devdata->din_offset;
@@ -776,7 +776,7 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
const struct mtk_desc_pin *pin;
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
int irq;
pin = pctl->devdata->pins + offset;
@@ -944,7 +944,7 @@ static void mtk_eint_unmask(struct irq_data *d)
static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
unsigned debounce)
{
- struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct mtk_pinctrl *pctl = dev_get_drvdata(chip->parent);
int eint_num, virq, eint_offset;
unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256};
@@ -1353,10 +1353,10 @@ int mtk_pctrl_init(struct platform_device *pdev,
*pctl->chip = mtk_gpio_chip;
pctl->chip->ngpio = pctl->devdata->npins;
pctl->chip->label = dev_name(&pdev->dev);
- pctl->chip->dev = &pdev->dev;
+ pctl->chip->parent = &pdev->dev;
pctl->chip->base = -1;
- ret = gpiochip_add(pctl->chip);
+ ret = gpiochip_add_data(pctl->chip, pctl);
if (ret) {
ret = -EINVAL;
goto pctrl_error;
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 84943e4cff09..50cab27c64d4 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -448,11 +448,6 @@ static const struct pinconf_ops meson_pinconf_ops = {
.is_generic = true,
};
-static inline struct meson_domain *to_meson_domain(struct gpio_chip *chip)
-{
- return container_of(chip, struct meson_domain, chip);
-}
-
static int meson_gpio_request(struct gpio_chip *chip, unsigned gpio)
{
return pinctrl_request_gpio(chip->base + gpio);
@@ -460,14 +455,14 @@ static int meson_gpio_request(struct gpio_chip *chip, unsigned gpio)
static void meson_gpio_free(struct gpio_chip *chip, unsigned gpio)
{
- struct meson_domain *domain = to_meson_domain(chip);
+ struct meson_domain *domain = gpiochip_get_data(chip);
pinctrl_free_gpio(domain->data->pin_base + gpio);
}
static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
- struct meson_domain *domain = to_meson_domain(chip);
+ struct meson_domain *domain = gpiochip_get_data(chip);
unsigned int reg, bit, pin;
struct meson_bank *bank;
int ret;
@@ -485,7 +480,7 @@ static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct meson_domain *domain = to_meson_domain(chip);
+ struct meson_domain *domain = gpiochip_get_data(chip);
unsigned int reg, bit, pin;
struct meson_bank *bank;
int ret;
@@ -507,7 +502,7 @@ static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{
- struct meson_domain *domain = to_meson_domain(chip);
+ struct meson_domain *domain = gpiochip_get_data(chip);
unsigned int reg, bit, pin;
struct meson_bank *bank;
int ret;
@@ -524,7 +519,7 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
- struct meson_domain *domain = to_meson_domain(chip);
+ struct meson_domain *domain = gpiochip_get_data(chip);
unsigned int reg, bit, val, pin;
struct meson_bank *bank;
int ret;
@@ -562,7 +557,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
domain = &pc->domains[i];
domain->chip.label = domain->data->name;
- domain->chip.dev = pc->dev;
+ domain->chip.parent = pc->dev;
domain->chip.request = meson_gpio_request;
domain->chip.free = meson_gpio_free;
domain->chip.direction_input = meson_gpio_direction_input;
@@ -575,7 +570,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
domain->chip.of_node = domain->of_node;
domain->chip.of_gpio_n_cells = 2;
- ret = gpiochip_add(&domain->chip);
+ ret = gpiochip_add_data(&domain->chip, domain);
if (ret) {
dev_err(pc->dev, "can't add gpio chip %s\n",
domain->data->name);
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index b59fbb4b1fb1..085e60106ec2 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -109,19 +109,10 @@ struct abx500_pinctrl {
int irq_cluster_size;
};
-/**
- * to_abx500_pinctrl() - get the pointer to abx500_pinctrl
- * @chip: Member of the structure abx500_pinctrl
- */
-static inline struct abx500_pinctrl *to_abx500_pinctrl(struct gpio_chip *chip)
-{
- return container_of(chip, struct abx500_pinctrl, chip);
-}
-
static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
unsigned offset, bool *bit)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
u8 pos = offset % 8;
u8 val;
int ret;
@@ -143,7 +134,7 @@ static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
unsigned offset, int val)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
u8 pos = offset % 8;
int ret;
@@ -164,7 +155,7 @@ static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
*/
static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
bool bit;
bool is_out;
u8 gpio_offset = offset - 1;
@@ -192,7 +183,7 @@ out:
static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
int ret;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
@@ -272,7 +263,7 @@ out:
static bool abx500_pullud_supported(struct gpio_chip *chip, unsigned gpio)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
struct pullud *pullud = pct->soc->pullud;
return (pullud &&
@@ -284,7 +275,7 @@ static int abx500_gpio_direction_output(struct gpio_chip *chip,
unsigned offset,
int val)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
unsigned gpio;
int ret;
@@ -332,7 +323,7 @@ static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
/* The AB8500 GPIO numbers are off by one */
int gpio = offset + 1;
int hwirq;
@@ -634,7 +625,7 @@ static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
unsigned i;
unsigned gpio = chip->base;
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct abx500_pinctrl *pct = gpiochip_get_data(chip);
struct pinctrl_dev *pctldev = pct->pctldev;
for (i = 0; i < chip->ngpio; i++, gpio++) {
@@ -986,7 +977,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
param = pinconf_to_config_param(configs[i]);
argument = pinconf_to_config_argument(configs[i]);
- dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+ dev_dbg(chip->parent, "pin %d [%#lx]: %s %s\n",
pin, configs[i],
(param == PIN_CONFIG_OUTPUT) ? "output " : "input",
(param == PIN_CONFIG_OUTPUT) ?
@@ -1077,7 +1068,8 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
break;
default:
- dev_err(chip->dev, "illegal configuration requested\n");
+ dev_err(chip->parent,
+ "illegal configuration requested\n");
}
} /* for each config */
out:
@@ -1172,7 +1164,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
pct->dev = &pdev->dev;
pct->parent = dev_get_drvdata(pdev->dev.parent);
pct->chip = abx500gpio_chip;
- pct->chip.dev = &pdev->dev;
+ pct->chip.parent = &pdev->dev;
pct->chip.base = -1; /* Dynamic allocation */
match = of_match_device(abx500_gpio_match, &pdev->dev);
@@ -1210,7 +1202,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
pct->irq_cluster = pct->soc->gpio_irq_cluster;
pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
- ret = gpiochip_add(&pct->chip);
+ ret = gpiochip_add_data(&pct->chip, pct);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
return ret;
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index eebfae0c9b7c..352406108fa0 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -438,7 +438,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
nmk_chip->addr + NMK_GPIO_FIMSC);
}
- dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
+ dev_dbg(nmk_chip->chip.parent, "%d: clearing interrupt mask\n", gpio);
}
static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value)
@@ -646,7 +646,7 @@ static inline int nmk_gpio_get_bitmask(int gpio)
static void nmk_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
clk_enable(nmk_chip->clk);
writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
@@ -863,7 +863,7 @@ static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status)
static void nmk_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
- struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
u32 status;
clk_enable(nmk_chip->clk);
@@ -876,7 +876,7 @@ static void nmk_gpio_irq_handler(struct irq_desc *desc)
static void nmk_gpio_latent_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
- struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
u32 status = nmk_chip->get_latent_status(nmk_chip->bank);
__nmk_gpio_irq_handler(desc, status);
@@ -886,8 +886,7 @@ static void nmk_gpio_latent_irq_handler(struct irq_desc *desc)
static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
{
- struct nmk_gpio_chip *nmk_chip =
- container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
clk_enable(nmk_chip->clk);
@@ -900,8 +899,7 @@ static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
{
- struct nmk_gpio_chip *nmk_chip =
- container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
u32 bit = 1 << offset;
int value;
@@ -917,8 +915,7 @@ static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
int val)
{
- struct nmk_gpio_chip *nmk_chip =
- container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
clk_enable(nmk_chip->clk);
@@ -930,8 +927,7 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
int val)
{
- struct nmk_gpio_chip *nmk_chip =
- container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
clk_enable(nmk_chip->clk);
@@ -951,8 +947,7 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s,
unsigned offset, unsigned gpio)
{
const char *label = gpiochip_is_requested(chip, offset);
- struct nmk_gpio_chip *nmk_chip =
- container_of(chip, struct nmk_gpio_chip, chip);
+ struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
int mode;
bool is_out;
bool data_out;
@@ -1188,7 +1183,7 @@ static struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np,
chip->base = id * NMK_GPIO_PER_CHIP;
chip->ngpio = NMK_GPIO_PER_CHIP;
chip->label = dev_name(&gpio_pdev->dev);
- chip->dev = &gpio_pdev->dev;
+ chip->parent = &gpio_pdev->dev;
res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
@@ -1278,7 +1273,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
clk_disable(nmk_chip->clk);
chip->of_node = np;
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, nmk_chip);
if (ret)
return ret;
@@ -1789,7 +1784,7 @@ static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
return -EINVAL;
}
chip = range->gc;
- nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ nmk_chip = gpiochip_get_data(chip);
dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
@@ -1890,7 +1885,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
if (slpm_val)
val = slpm_val - 1;
- dev_dbg(nmk_chip->chip.dev,
+ dev_dbg(nmk_chip->chip.parent,
"pin %d: sleep pull %s, dir %s, val %s\n",
pin,
slpm_pull ? pullnames[pull] : "same",
@@ -1899,7 +1894,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
slpm_val ? (val ? "high" : "low") : "same");
}
- dev_dbg(nmk_chip->chip.dev,
+ dev_dbg(nmk_chip->chip.parent,
"pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
pin, cfg, pullnames[pull], slpmnames[slpm],
output ? "output " : "input",
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
index 8e9e8eab59ba..ecb57635a37e 100644
--- a/drivers/pinctrl/pinctrl-adi2.c
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -636,7 +636,7 @@ static int adi_pinmux_set(struct pinctrl_dev *pctldev, unsigned func_id,
if (range == NULL) /* should not happen */
return -ENODEV;
- port = container_of(range->gc, struct gpio_port, chip);
+ port = gpiochip_get_data(range->gc);
spin_lock_irqsave(&port->lock, flags);
@@ -684,7 +684,7 @@ static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
unsigned long flags;
u8 offset;
- port = container_of(range->gc, struct gpio_port, chip);
+ port = gpiochip_get_data(range->gc);
offset = pin_to_offset(range, pin);
spin_lock_irqsave(&port->lock, flags);
@@ -718,7 +718,7 @@ static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
struct gpio_port *port;
unsigned long flags;
- port = container_of(chip, struct gpio_port, chip);
+ port = gpiochip_get_data(chip);
spin_lock_irqsave(&port->lock, flags);
@@ -733,7 +733,7 @@ static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+ struct gpio_port *port = gpiochip_get_data(chip);
struct gpio_port_t *regs = port->regs;
unsigned long flags;
@@ -750,7 +750,7 @@ static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+ struct gpio_port *port = gpiochip_get_data(chip);
struct gpio_port_t *regs = port->regs;
unsigned long flags;
@@ -770,7 +770,7 @@ static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+ struct gpio_port *port = gpiochip_get_data(chip);
struct gpio_port_t *regs = port->regs;
unsigned long flags;
int ret;
@@ -786,7 +786,7 @@ static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+ struct gpio_port *port = gpiochip_get_data(chip);
if (port->irq_base >= 0)
return irq_find_mapping(port->domain, offset);
@@ -994,7 +994,7 @@ static int adi_gpio_probe(struct platform_device *pdev)
port->chip.ngpio = port->width;
gpio = port->chip.base + port->width;
- ret = gpiochip_add(&port->chip);
+ ret = gpiochip_add_data(&port->chip, port);
if (ret) {
dev_err(&pdev->dev, "Fail to add GPIO chip.\n");
goto out_remove_domain;
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 3318f1d6193c..657449431301 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -35,16 +35,11 @@
#include "pinctrl-utils.h"
#include "pinctrl-amd.h"
-static inline struct amd_gpio *to_amd_gpio(struct gpio_chip *gc)
-{
- return container_of(gc, struct amd_gpio, gc);
-}
-
static int amd_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
unsigned long flags;
u32 pin_reg;
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + offset * 4);
@@ -71,7 +66,7 @@ static int amd_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
{
u32 pin_reg;
unsigned long flags;
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + offset * 4);
@@ -90,7 +85,7 @@ static int amd_gpio_get_value(struct gpio_chip *gc, unsigned offset)
{
u32 pin_reg;
unsigned long flags;
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + offset * 4);
@@ -103,7 +98,7 @@ static void amd_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value)
{
u32 pin_reg;
unsigned long flags;
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + offset * 4);
@@ -122,7 +117,7 @@ static int amd_gpio_set_debounce(struct gpio_chip *gc, unsigned offset,
u32 pin_reg;
int ret = 0;
unsigned long flags;
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + offset * 4);
@@ -186,7 +181,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
u32 pin_reg;
unsigned long flags;
unsigned int bank, i, pin_num;
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
char *level_trig;
char *active_level;
@@ -327,7 +322,7 @@ static void amd_gpio_irq_enable(struct irq_data *d)
u32 pin_reg;
unsigned long flags;
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -351,7 +346,7 @@ static void amd_gpio_irq_disable(struct irq_data *d)
u32 pin_reg;
unsigned long flags;
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -366,7 +361,7 @@ static void amd_gpio_irq_mask(struct irq_data *d)
u32 pin_reg;
unsigned long flags;
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -380,7 +375,7 @@ static void amd_gpio_irq_unmask(struct irq_data *d)
u32 pin_reg;
unsigned long flags;
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -394,7 +389,7 @@ static void amd_gpio_irq_eoi(struct irq_data *d)
u32 reg;
unsigned long flags;
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
reg = readl(gpio_dev->base + WAKE_INT_MASTER_REG);
@@ -409,7 +404,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type)
u32 pin_reg;
unsigned long flags;
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -504,7 +499,7 @@ static void amd_gpio_irq_handler(struct irq_desc *desc)
unsigned long flags;
struct irq_chip *chip = irq_desc_get_chip(desc);
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
chained_irq_enter(chip, desc);
/*enable GPIO interrupt again*/
@@ -778,7 +773,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
gpio_dev->gc.base = 0;
gpio_dev->gc.label = pdev->name;
gpio_dev->gc.owner = THIS_MODULE;
- gpio_dev->gc.dev = &pdev->dev;
+ gpio_dev->gc.parent = &pdev->dev;
gpio_dev->gc.ngpio = TOTAL_NUMBER_OF_PINS;
#if defined(CONFIG_OF_GPIO)
gpio_dev->gc.of_node = pdev->dev.of_node;
@@ -795,7 +790,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
return PTR_ERR(gpio_dev->pctrl);
}
- ret = gpiochip_add(&gpio_dev->gc);
+ ret = gpiochip_add_data(&gpio_dev->gc, gpio_dev);
if (ret)
goto out1;
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index 56af28b95a44..e844fdc6d3a8 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -436,14 +436,9 @@ static struct pinctrl_desc as3722_pinctrl_desc = {
.owner = THIS_MODULE,
};
-static inline struct as3722_pctrl_info *to_as_pci(struct gpio_chip *chip)
-{
- return container_of(chip, struct as3722_pctrl_info, gpio_chip);
-}
-
static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct as3722_pctrl_info *as_pci = to_as_pci(chip);
+ struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
struct as3722 *as3722 = as_pci->as3722;
int ret;
u32 reg;
@@ -491,7 +486,7 @@ static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)
static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct as3722_pctrl_info *as_pci = to_as_pci(chip);
+ struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
struct as3722 *as3722 = as_pci->as3722;
int en_invert;
u32 val;
@@ -531,7 +526,7 @@ static int as3722_gpio_direction_output(struct gpio_chip *chip,
static int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct as3722_pctrl_info *as_pci = to_as_pci(chip);
+ struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
return as3722_irq_get_virq(as_pci->as3722, offset);
}
@@ -582,9 +577,9 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
}
as_pci->gpio_chip = as3722_gpio_chip;
- as_pci->gpio_chip.dev = &pdev->dev;
+ as_pci->gpio_chip.parent = &pdev->dev;
as_pci->gpio_chip.of_node = pdev->dev.parent->of_node;
- ret = gpiochip_add(&as_pci->gpio_chip);
+ ret = gpiochip_add_data(&as_pci->gpio_chip, as_pci);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't register gpiochip, %d\n", ret);
goto fail_chip_add;
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index d5bdcebc6aa6..ee69db6ae1c7 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -15,6 +15,8 @@
*/
#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+/* FIXME: needed for gpio_to_irq(), get rid of this */
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -290,7 +292,7 @@ static void atmel_gpio_irq_handler(struct irq_desc *desc)
static int atmel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+ struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
struct atmel_pin *pin = atmel_pioctrl->pins[offset];
unsigned reg;
@@ -305,7 +307,7 @@ static int atmel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int atmel_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+ struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
struct atmel_pin *pin = atmel_pioctrl->pins[offset];
unsigned reg;
@@ -317,7 +319,7 @@ static int atmel_gpio_get(struct gpio_chip *chip, unsigned offset)
static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+ struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
struct atmel_pin *pin = atmel_pioctrl->pins[offset];
unsigned reg;
@@ -336,7 +338,7 @@ static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+ struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
struct atmel_pin *pin = atmel_pioctrl->pins[offset];
atmel_gpio_write(atmel_pioctrl, pin->bank,
@@ -346,7 +348,7 @@ static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+ struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
return irq_find_mapping(atmel_pioctrl->irq_domain, offset);
}
@@ -972,7 +974,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
atmel_pioctrl->gpio_chip->of_node = dev->of_node;
atmel_pioctrl->gpio_chip->ngpio = atmel_pioctrl->npins;
atmel_pioctrl->gpio_chip->label = dev_name(dev);
- atmel_pioctrl->gpio_chip->dev = dev;
+ atmel_pioctrl->gpio_chip->parent = dev;
atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names;
atmel_pioctrl->pm_wakeup_sources = devm_kzalloc(dev,
@@ -1040,7 +1042,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
goto pinctrl_register_error;
}
- ret = gpiochip_add(atmel_pioctrl->gpio_chip);
+ ret = gpiochip_add_data(atmel_pioctrl->gpio_chip, atmel_pioctrl);
if (ret) {
dev_err(dev, "failed to add gpiochip\n");
goto gpiochip_add_error;
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 47b625b1b789..523b6b794d1f 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -45,8 +45,6 @@ struct at91_gpio_chip {
struct at91_pinctrl_mux_ops *ops; /* ops */
};
-#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
-
static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
static int gpio_banks;
@@ -811,7 +809,7 @@ static int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
return -EINVAL;
}
chip = range->gc;
- at91_chip = container_of(chip, struct at91_gpio_chip, chip);
+ at91_chip = gpiochip_get_data(chip);
dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
@@ -1282,7 +1280,7 @@ static int at91_pinctrl_remove(struct platform_device *pdev)
static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
u32 osr;
@@ -1293,7 +1291,7 @@ static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
@@ -1303,7 +1301,7 @@ static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
u32 pdsr;
@@ -1315,7 +1313,7 @@ static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
int val)
{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
@@ -1325,7 +1323,7 @@ static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
static void at91_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
#define BITS_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))
@@ -1340,7 +1338,7 @@ static void at91_gpio_set_multiple(struct gpio_chip *chip,
static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int val)
{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
@@ -1355,7 +1353,7 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
enum at91_mux mode;
int i;
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
void __iomem *pio = at91_gpio->regbase;
for (i = 0; i < chip->ngpio; i++) {
@@ -1570,9 +1568,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc);
- struct at91_gpio_chip *at91_gpio = container_of(gpio_chip,
- struct at91_gpio_chip, chip);
-
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(gpio_chip);
void __iomem *pio = at91_gpio->regbase;
unsigned long isr;
int n;
@@ -1648,7 +1644,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
return 0;
}
- prev = container_of(gpiochip_prev, struct at91_gpio_chip, chip);
+ prev = gpiochip_get_data(gpiochip_prev);
/* we can only have 2 banks before */
for (i = 0; i < 2; i++) {
@@ -1750,7 +1746,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
chip = &at91_chip->chip;
chip->of_node = np;
chip->label = dev_name(&pdev->dev);
- chip->dev = &pdev->dev;
+ chip->parent = &pdev->dev;
chip->owner = THIS_MODULE;
chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
@@ -1783,7 +1779,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
range->npins = chip->ngpio;
range->gc = chip;
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, at91_chip);
if (ret)
goto gpiochip_add_err;
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 813eb7c771ec..cf7788df0f95 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -208,25 +208,16 @@ bs335_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
}
};
-/**
- * to_u300_gpio() - get the pointer to u300_gpio
- * @chip: the gpio chip member of the structure u300_gpio
- */
-static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct u300_gpio, chip);
-}
-
static int u300_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
- return readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset);
+ return !!(readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset));
}
static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -243,7 +234,7 @@ static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -259,7 +250,7 @@ static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
unsigned long flags;
u32 oldmode;
u32 val;
@@ -290,7 +281,7 @@ int u300_gpio_config_get(struct gpio_chip *chip,
unsigned offset,
unsigned long *config)
{
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
enum pin_config_param param = (enum pin_config_param) *config;
bool biasmode;
u32 drmode;
@@ -348,7 +339,7 @@ int u300_gpio_config_get(struct gpio_chip *chip,
int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
enum pin_config_param param)
{
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -429,7 +420,7 @@ static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset)
static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
int offset = d->hwirq;
u32 val;
@@ -466,7 +457,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
static void u300_gpio_irq_enable(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
int offset = d->hwirq;
u32 val;
@@ -483,7 +474,7 @@ static void u300_gpio_irq_enable(struct irq_data *d)
static void u300_gpio_irq_disable(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
int offset = d->hwirq;
u32 val;
unsigned long flags;
@@ -506,7 +497,7 @@ static void u300_gpio_irq_handler(struct irq_desc *desc)
unsigned int irq = irq_desc_get_irq(desc);
struct irq_chip *parent_chip = irq_desc_get_chip(desc);
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
- struct u300_gpio *gpio = to_u300_gpio(chip);
+ struct u300_gpio *gpio = gpiochip_get_data(chip);
struct u300_gpio_port *port = &gpio->ports[irq - chip->base];
int pinoffset = port->number << 3; /* get the right stride */
unsigned long val;
@@ -637,7 +628,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
gpio->chip = u300_gpio_chip;
gpio->chip.ngpio = U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT;
- gpio->chip.dev = &pdev->dev;
+ gpio->chip.parent = &pdev->dev;
gpio->chip.base = 0;
gpio->dev = &pdev->dev;
@@ -684,7 +675,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
gpio->chip.of_node = pdev->dev.of_node;
#endif
- err = gpiochip_add(&gpio->chip);
+ err = gpiochip_add_data(&gpio->chip, gpio);
if (err) {
dev_err(gpio->dev, "unable to add gpiochip: %d\n", err);
goto err_no_chip;
diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c
index 38a7799f8257..f1343d6ca823 100644
--- a/drivers/pinctrl/pinctrl-digicolor.c
+++ b/drivers/pinctrl/pinctrl-digicolor.c
@@ -171,7 +171,7 @@ static struct pinmux_ops dc_pmxops = {
static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
- struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+ struct dc_pinmap *pmap = gpiochip_get_data(chip);
int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
int bit_off = gpio % PINS_PER_COLLECTION;
u8 drive;
@@ -191,7 +191,7 @@ static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value);
static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+ struct dc_pinmap *pmap = gpiochip_get_data(chip);
int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
int bit_off = gpio % PINS_PER_COLLECTION;
u8 drive;
@@ -210,7 +210,7 @@ static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
- struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+ struct dc_pinmap *pmap = gpiochip_get_data(chip);
int reg_off = GP_INPUT(gpio/PINS_PER_COLLECTION);
int bit_off = gpio % PINS_PER_COLLECTION;
u8 input;
@@ -222,7 +222,7 @@ static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio)
static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{
- struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+ struct dc_pinmap *pmap = gpiochip_get_data(chip);
int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION);
int bit_off = gpio % PINS_PER_COLLECTION;
u8 output;
@@ -244,7 +244,7 @@ static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np)
int ret;
chip->label = DRIVER_NAME;
- chip->dev = pmap->dev;
+ chip->parent = pmap->dev;
chip->request = gpiochip_generic_request;
chip->free = gpiochip_generic_free;
chip->direction_input = dc_gpio_direction_input;
@@ -258,7 +258,7 @@ static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np)
spin_lock_init(&pmap->lock);
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, pmap);
if (ret < 0)
return ret;
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
index 85c9046c690e..856f736cb1a6 100644
--- a/drivers/pinctrl/pinctrl-pistachio.c
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -842,14 +842,9 @@ static inline void pctl_writel(struct pistachio_pinctrl *pctl, u32 val, u32 reg)
writel(val, pctl->base + reg);
}
-static inline struct pistachio_gpio_bank *gc_to_bank(struct gpio_chip *gc)
-{
- return container_of(gc, struct pistachio_gpio_bank, gpio_chip);
-}
-
static inline struct pistachio_gpio_bank *irqd_to_bank(struct irq_data *d)
{
- return gc_to_bank(irq_data_get_irq_chip_data(d));
+ return gpiochip_get_data(irq_data_get_irq_chip_data(d));
}
static inline u32 gpio_readl(struct pistachio_gpio_bank *bank, u32 reg)
@@ -992,7 +987,7 @@ static int pistachio_pinmux_enable(struct pinctrl_dev *pctldev,
range = pinctrl_find_gpio_range_from_pin(pctl->pctldev, pg->pin);
if (range)
- gpio_disable(gc_to_bank(range->gc), pg->pin - range->pin_base);
+ gpio_disable(gpiochip_get_data(range->gc), pg->pin - range->pin_base);
return 0;
}
@@ -1173,14 +1168,14 @@ static struct pinctrl_desc pistachio_pinctrl_desc = {
static int pistachio_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+ struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
return !(gpio_readl(bank, GPIO_OUTPUT_EN) & BIT(offset));
}
static int pistachio_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+ struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
u32 reg;
if (gpio_readl(bank, GPIO_OUTPUT_EN) & BIT(offset))
@@ -1194,7 +1189,7 @@ static int pistachio_gpio_get(struct gpio_chip *chip, unsigned offset)
static void pistachio_gpio_set(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+ struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
gpio_mask_writel(bank, GPIO_OUTPUT, offset, !!value);
}
@@ -1202,7 +1197,7 @@ static void pistachio_gpio_set(struct gpio_chip *chip, unsigned offset,
static int pistachio_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+ struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
gpio_mask_writel(bank, GPIO_OUTPUT_EN, offset, 0);
gpio_enable(bank, offset);
@@ -1213,7 +1208,7 @@ static int pistachio_gpio_direction_input(struct gpio_chip *chip,
static int pistachio_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+ struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
pistachio_gpio_set(chip, offset, value);
gpio_mask_writel(bank, GPIO_OUTPUT_EN, offset, 1);
@@ -1303,7 +1298,7 @@ static int pistachio_gpio_irq_set_type(struct irq_data *data, unsigned int type)
static void pistachio_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct pistachio_gpio_bank *bank = gc_to_bank(gc);
+ struct pistachio_gpio_bank *bank = gpiochip_get_data(gc);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long pending;
unsigned int pin;
@@ -1388,9 +1383,9 @@ static int pistachio_gpio_register(struct pistachio_pinctrl *pctl)
bank->pctl = pctl;
bank->base = pctl->base + GPIO_BANK_BASE(i);
- bank->gpio_chip.dev = pctl->dev;
+ bank->gpio_chip.parent = pctl->dev;
bank->gpio_chip.of_node = child;
- ret = gpiochip_add(&bank->gpio_chip);
+ ret = gpiochip_add_data(&bank->gpio_chip, bank);
if (ret < 0) {
dev_err(pctl->dev, "Failed to add GPIO chip %u: %d\n",
i, ret);
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 91288265e856..183545a068ad 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -224,11 +224,6 @@ static struct regmap_config rockchip_regmap_config = {
.reg_stride = 4,
};
-static inline struct rockchip_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
-{
- return container_of(gc, struct rockchip_pin_bank, gpio_chip);
-}
-
static const inline struct rockchip_pin_group *pinctrl_name_to_group(
const struct rockchip_pinctrl *info,
const char *name)
@@ -973,7 +968,7 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
unsigned long flags;
u32 data;
- bank = gc_to_pin_bank(chip);
+ bank = gpiochip_get_data(chip);
ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
if (ret < 0)
@@ -1413,7 +1408,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
- struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+ struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
unsigned long flags;
u32 data;
@@ -1437,7 +1432,7 @@ static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
*/
static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+ struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
u32 data;
clk_enable(bank->clk);
@@ -1476,7 +1471,7 @@ static int rockchip_gpio_direction_output(struct gpio_chip *gc,
*/
static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+ struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
unsigned int virq;
if (!bank->domain)
@@ -1791,11 +1786,11 @@ static int rockchip_gpiolib_register(struct platform_device *pdev,
gc = &bank->gpio_chip;
gc->base = bank->pin_base;
gc->ngpio = bank->nr_pins;
- gc->dev = &pdev->dev;
+ gc->parent = &pdev->dev;
gc->of_node = bank->of_node;
gc->label = bank->name;
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, bank);
if (ret) {
dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
gc->label, ret);
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index b58d3f29148a..fac844a85cb4 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -203,9 +203,6 @@
#define gpio_range_to_bank(chip) \
container_of(chip, struct st_gpio_bank, range)
-#define gpio_chip_to_bank(chip) \
- container_of(chip, struct st_gpio_bank, gpio_chip)
-
#define pc_to_bank(pc) \
container_of(pc, struct st_gpio_bank, pc)
@@ -744,14 +741,14 @@ static void st_gpio_direction(struct st_gpio_bank *bank,
static int st_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+ struct st_gpio_bank *bank = gpiochip_get_data(chip);
return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset));
}
static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+ struct st_gpio_bank *bank = gpiochip_get_data(chip);
__st_gpio_set(bank, offset, value);
}
@@ -765,7 +762,7 @@ static int st_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int st_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+ struct st_gpio_bank *bank = gpiochip_get_data(chip);
__st_gpio_set(bank, offset, value);
pinctrl_gpio_direction_output(chip->base + offset);
@@ -775,7 +772,7 @@ static int st_gpio_direction_output(struct gpio_chip *chip,
static int st_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+ struct st_gpio_bank *bank = gpiochip_get_data(chip);
struct st_pio_control pc = bank->pc;
unsigned long config;
unsigned int direction = 0;
@@ -1325,7 +1322,7 @@ static int st_pctl_parse_functions(struct device_node *np,
static void st_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+ struct st_gpio_bank *bank = gpiochip_get_data(gc);
writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK);
}
@@ -1333,7 +1330,7 @@ static void st_gpio_irq_mask(struct irq_data *d)
static void st_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+ struct st_gpio_bank *bank = gpiochip_get_data(gc);
writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
}
@@ -1341,7 +1338,7 @@ static void st_gpio_irq_unmask(struct irq_data *d)
static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+ struct st_gpio_bank *bank = gpiochip_get_data(gc);
unsigned long flags;
int comp, pin = d->hwirq;
u32 val;
@@ -1455,7 +1452,7 @@ static void st_gpio_irq_handler(struct irq_desc *desc)
/* interrupt dedicated per bank */
struct irq_chip *chip = irq_desc_get_chip(desc);
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+ struct st_gpio_bank *bank = gpiochip_get_data(gc);
chained_irq_enter(chip, desc);
__gpio_irq_handler(bank);
@@ -1522,7 +1519,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.of_node = np;
- bank->gpio_chip.dev = dev;
+ bank->gpio_chip.parent = dev;
spin_lock_init(&bank->lock);
of_property_read_string(np, "st,bank-name", &range->name);
@@ -1532,7 +1529,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
range->pin_base = range->base = range->id * ST_GPIO_PINS_PER_BANK;
range->npins = bank->gpio_chip.ngpio;
range->gc = &bank->gpio_chip;
- err = gpiochip_add(&bank->gpio_chip);
+ err = gpiochip_add_data(&bank->gpio_chip, bank);
if (err) {
dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num);
return err;
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index 7db74699fda4..412c6b78140a 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -1535,7 +1535,7 @@ static struct ltq_pinmux_info xway_info = {
/* --------- gpio_chip related code --------- */
static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
{
- struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
if (val)
gpio_setbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin));
@@ -1545,14 +1545,14 @@ static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
static int xway_gpio_get(struct gpio_chip *chip, unsigned int pin)
{
- struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
- return gpio_getbit(info->membase[0], GPIO_IN(pin), PORT_PIN(pin));
+ return !!gpio_getbit(info->membase[0], GPIO_IN(pin), PORT_PIN(pin));
}
static int xway_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
{
- struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
gpio_clearbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
@@ -1561,7 +1561,7 @@ static int xway_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
{
- struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
if (PORT(pin) == PORT3)
gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin));
@@ -1708,7 +1708,7 @@ static int pinmux_xway_probe(struct platform_device *pdev)
xway_pctrl_desc.pins = xway_info.pads;
/* load the gpio chip */
- xway_chip.dev = &pdev->dev;
+ xway_chip.parent = &pdev->dev;
ret = gpiochip_add(&xway_chip);
if (ret) {
dev_err(&pdev->dev, "Failed to register gpio chip\n");
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 146264a41ec8..8777cf083eef 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -69,11 +69,6 @@ struct msm_pinctrl {
void __iomem *regs;
};
-static inline struct msm_pinctrl *to_msm_pinctrl(struct gpio_chip *gc)
-{
- return container_of(gc, struct msm_pinctrl, chip);
-}
-
static int msm_get_groups_count(struct pinctrl_dev *pctldev)
{
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -381,7 +376,7 @@ static struct pinctrl_desc msm_pinctrl_desc = {
static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
const struct msm_pingroup *g;
- struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -401,7 +396,7 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
const struct msm_pingroup *g;
- struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -428,7 +423,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
{
const struct msm_pingroup *g;
- struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
u32 val;
g = &pctrl->soc->groups[offset];
@@ -440,7 +435,7 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
const struct msm_pingroup *g;
- struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
u32 val;
@@ -468,7 +463,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
unsigned gpio)
{
const struct msm_pingroup *g;
- struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned func;
int is_out;
int drive;
@@ -567,7 +562,7 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl,
static void msm_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
u32 val;
@@ -588,7 +583,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
static void msm_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
u32 val;
@@ -613,7 +608,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
static void msm_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
u32 val;
@@ -638,7 +633,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_pingroup *g;
unsigned long flags;
u32 val;
@@ -732,7 +727,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -757,7 +752,7 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
const struct msm_pingroup *g;
- struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
struct irq_chip *chip = irq_desc_get_chip(desc);
int irq_pin;
int handled = 0;
@@ -800,11 +795,11 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
chip->base = 0;
chip->ngpio = ngpio;
chip->label = dev_name(pctrl->dev);
- chip->dev = pctrl->dev;
+ chip->parent = pctrl->dev;
chip->owner = THIS_MODULE;
chip->of_node = pctrl->dev->of_node;
- ret = gpiochip_add(&pctrl->chip);
+ ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "Failed register gpiochip\n");
return ret;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 77f6a5cb1008..4e12ded3c773 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -159,11 +159,6 @@ static const char *const pmic_gpio_functions[] = {
PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4,
};
-static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip)
-{
- return container_of(chip, struct pmic_gpio_state, chip);
-};
-
static int pmic_gpio_read(struct pmic_gpio_state *state,
struct pmic_gpio_pad *pad, unsigned int addr)
{
@@ -496,7 +491,7 @@ static const struct pinconf_ops pmic_gpio_pinconf_ops = {
static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
- struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
unsigned long config;
config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
@@ -507,7 +502,7 @@ static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
static int pmic_gpio_direction_output(struct gpio_chip *chip,
unsigned pin, int val)
{
- struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
unsigned long config;
config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
@@ -517,7 +512,7 @@ static int pmic_gpio_direction_output(struct gpio_chip *chip,
static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
{
- struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
struct pmic_gpio_pad *pad;
int ret;
@@ -534,12 +529,12 @@ static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
}
- return pad->out_value;
+ return !!pad->out_value;
}
static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
{
- struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
unsigned long config;
config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
@@ -562,7 +557,7 @@ static int pmic_gpio_of_xlate(struct gpio_chip *chip,
static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
{
- struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
struct pmic_gpio_pad *pad;
pad = state->ctrl->desc->pins[pin].drv_data;
@@ -572,7 +567,7 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
unsigned i;
for (i = 0; i < chip->ngpio; i++) {
@@ -762,7 +757,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
}
state->chip = pmic_gpio_gpio_template;
- state->chip.dev = dev;
+ state->chip.parent = dev;
state->chip.base = -1;
state->chip.ngpio = npins;
state->chip.label = dev_name(dev);
@@ -773,7 +768,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
if (IS_ERR(state->ctrl))
return PTR_ERR(state->ctrl);
- ret = gpiochip_add(&state->chip);
+ ret = gpiochip_add_data(&state->chip, state);
if (ret) {
dev_err(state->dev, "can't add gpio chip\n");
goto err_chip;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 2df4f29175ae..2f18323571a6 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -179,11 +179,6 @@ static const char *const pmic_mpp_functions[] = {
"digital", "analog", "sink"
};
-static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip)
-{
- return container_of(chip, struct pmic_mpp_state, chip);
-};
-
static int pmic_mpp_read(struct pmic_mpp_state *state,
struct pmic_mpp_pad *pad, unsigned int addr)
{
@@ -557,7 +552,7 @@ static const struct pinconf_ops pmic_mpp_pinconf_ops = {
static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin)
{
- struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_state *state = gpiochip_get_data(chip);
unsigned long config;
config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
@@ -568,7 +563,7 @@ static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin)
static int pmic_mpp_direction_output(struct gpio_chip *chip,
unsigned pin, int val)
{
- struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_state *state = gpiochip_get_data(chip);
unsigned long config;
config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
@@ -578,7 +573,7 @@ static int pmic_mpp_direction_output(struct gpio_chip *chip,
static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin)
{
- struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_state *state = gpiochip_get_data(chip);
struct pmic_mpp_pad *pad;
int ret;
@@ -592,12 +587,12 @@ static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin)
pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
}
- return pad->out_value;
+ return !!pad->out_value;
}
static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value)
{
- struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_state *state = gpiochip_get_data(chip);
unsigned long config;
config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
@@ -620,7 +615,7 @@ static int pmic_mpp_of_xlate(struct gpio_chip *chip,
static int pmic_mpp_to_irq(struct gpio_chip *chip, unsigned pin)
{
- struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_state *state = gpiochip_get_data(chip);
struct pmic_mpp_pad *pad;
pad = state->ctrl->desc->pins[pin].drv_data;
@@ -630,7 +625,7 @@ static int pmic_mpp_to_irq(struct gpio_chip *chip, unsigned pin)
static void pmic_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
- struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_state *state = gpiochip_get_data(chip);
unsigned i;
for (i = 0; i < chip->ngpio; i++) {
@@ -865,7 +860,7 @@ static int pmic_mpp_probe(struct platform_device *pdev)
}
state->chip = pmic_mpp_gpio_template;
- state->chip.dev = dev;
+ state->chip.parent = dev;
state->chip.base = -1;
state->chip.ngpio = npins;
state->chip.label = dev_name(dev);
@@ -876,7 +871,7 @@ static int pmic_mpp_probe(struct platform_device *pdev)
if (IS_ERR(state->ctrl))
return PTR_ERR(state->ctrl);
- ret = gpiochip_add(&state->chip);
+ ret = gpiochip_add_data(&state->chip, state);
if (ret) {
dev_err(state->dev, "can't add gpio chip\n");
goto err_chip;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index e51176ec83d2..cd8580d9741d 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -444,7 +444,7 @@ static struct pinctrl_desc pm8xxx_pinctrl_desc = {
static int pm8xxx_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+ struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
u8 val;
@@ -460,7 +460,7 @@ static int pm8xxx_gpio_direction_output(struct gpio_chip *chip,
unsigned offset,
int value)
{
- struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+ struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
u8 val;
@@ -478,7 +478,7 @@ static int pm8xxx_gpio_direction_output(struct gpio_chip *chip,
static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+ struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
bool state;
int ret;
@@ -496,7 +496,7 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
static void pm8xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+ struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
u8 val;
@@ -525,7 +525,7 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip,
static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+ struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
return pin->irq;
@@ -540,7 +540,7 @@ static void pm8xxx_gpio_dbg_show_one(struct seq_file *s,
unsigned offset,
unsigned gpio)
{
- struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+ struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
static const char * const modes[] = {
@@ -737,12 +737,12 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
pctrl->chip = pm8xxx_gpio_template;
pctrl->chip.base = -1;
- pctrl->chip.dev = &pdev->dev;
+ pctrl->chip.parent = &pdev->dev;
pctrl->chip.of_node = pdev->dev.of_node;
pctrl->chip.of_gpio_n_cells = 2;
pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.ngpio = pctrl->npins;
- ret = gpiochip_add(&pctrl->chip);
+ ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
dev_err(&pdev->dev, "failed register gpiochip\n");
goto unregister_pinctrl;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
index e9f01de51e18..54a5402a9079 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
@@ -449,7 +449,7 @@ static struct pinctrl_desc pm8xxx_pinctrl_desc = {
static int pm8xxx_mpp_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+ struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
switch (pin->mode) {
@@ -473,7 +473,7 @@ static int pm8xxx_mpp_direction_output(struct gpio_chip *chip,
unsigned offset,
int value)
{
- struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+ struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
switch (pin->mode) {
@@ -497,13 +497,13 @@ static int pm8xxx_mpp_direction_output(struct gpio_chip *chip,
static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset)
{
- struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+ struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
bool state;
int ret;
if (!pin->input)
- return pin->output_value;
+ return !!pin->output_value;
ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state);
if (!ret)
@@ -514,7 +514,7 @@ static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset)
static void pm8xxx_mpp_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+ struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
pin->output_value = !!value;
@@ -538,7 +538,7 @@ static int pm8xxx_mpp_of_xlate(struct gpio_chip *chip,
static int pm8xxx_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+ struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
return pin->irq;
@@ -553,7 +553,7 @@ static void pm8xxx_mpp_dbg_show_one(struct seq_file *s,
unsigned offset,
unsigned gpio)
{
- struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+ struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
static const char * const aout_lvls[] = {
@@ -828,12 +828,12 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev)
pctrl->chip = pm8xxx_mpp_template;
pctrl->chip.base = -1;
- pctrl->chip.dev = &pdev->dev;
+ pctrl->chip.parent = &pdev->dev;
pctrl->chip.of_node = pdev->dev.of_node;
pctrl->chip.of_gpio_n_cells = 2;
pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.ngpio = pctrl->npins;
- ret = gpiochip_add(&pctrl->chip);
+ ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
dev_err(&pdev->dev, "failed register gpiochip\n");
goto unregister_pinctrl;
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 16e2293cc2bc..051b5bf701a8 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -176,7 +176,8 @@ static int exynos_irq_request_resources(struct irq_data *irqd)
ret = gpiochip_lock_as_irq(&bank->gpio_chip, irqd->hwirq);
if (ret) {
- dev_err(bank->gpio_chip.dev, "unable to lock pin %s-%lu IRQ\n",
+ dev_err(bank->gpio_chip.parent,
+ "unable to lock pin %s-%lu IRQ\n",
bank->name, irqd->hwirq);
return ret;
}
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
index 82dc109f7ed4..00ab63abf1d9 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
@@ -15,7 +15,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -539,7 +539,7 @@ static const struct pinconf_ops exynos5440_pinconf_ops = {
/* gpiolib gpio_set callback function */
static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
- struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+ struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
void __iomem *base = priv->reg_base;
u32 data;
@@ -553,7 +553,7 @@ static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value
/* gpiolib gpio_get callback function */
static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+ struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
void __iomem *base = priv->reg_base;
u32 data;
@@ -566,7 +566,7 @@ static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset)
/* gpiolib gpio_direction_input callback function */
static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
- struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+ struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
void __iomem *base = priv->reg_base;
u32 data;
@@ -586,7 +586,7 @@ static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset
static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+ struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
void __iomem *base = priv->reg_base;
u32 data;
@@ -607,7 +607,7 @@ static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offse
/* gpiolib gpio_to_irq callback function */
static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+ struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
unsigned int virq;
if (offset < 16 || offset > 23)
@@ -817,7 +817,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
priv->gc = gc;
gc->base = 0;
gc->ngpio = EXYNOS5440_MAX_PINS;
- gc->dev = &pdev->dev;
+ gc->parent = &pdev->dev;
gc->set = exynos5440_gpio_set;
gc->get = exynos5440_gpio_get;
gc->direction_input = exynos5440_gpio_direction_input;
@@ -825,7 +825,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
gc->to_irq = exynos5440_gpio_to_irq;
gc->label = "gpiolib-exynos5440";
gc->owner = THIS_MODULE;
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, priv);
if (ret) {
dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
"code: %d\n", gc->label, ret);
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 48294e7449a4..f67b1e958589 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -50,11 +50,6 @@ static LIST_HEAD(drvdata_list);
static unsigned int pin_base;
-static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
-{
- return container_of(gc, struct samsung_pin_bank, gpio_chip);
-}
-
static int samsung_get_group_count(struct pinctrl_dev *pctldev)
{
struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
@@ -522,7 +517,7 @@ static const struct pinconf_ops samsung_pinconf_ops = {
/* gpiolib gpio_set callback function */
static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
- struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+ struct samsung_pin_bank *bank = gpiochip_get_data(gc);
const struct samsung_pin_bank_type *type = bank->type;
unsigned long flags;
void __iomem *reg;
@@ -546,7 +541,7 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
{
void __iomem *reg;
u32 data;
- struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+ struct samsung_pin_bank *bank = gpiochip_get_data(gc);
const struct samsung_pin_bank_type *type = bank->type;
reg = bank->drvdata->virt_base + bank->pctl_offset;
@@ -571,7 +566,7 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
u32 data, mask, shift;
unsigned long flags;
- bank = gc_to_pin_bank(gc);
+ bank = gpiochip_get_data(gc);
type = bank->type;
drvdata = bank->drvdata;
@@ -619,7 +614,7 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
*/
static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
- struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+ struct samsung_pin_bank *bank = gpiochip_get_data(gc);
unsigned int virq;
if (!bank->irq_domain)
@@ -914,11 +909,11 @@ static int samsung_gpiolib_register(struct platform_device *pdev,
gc = &bank->gpio_chip;
gc->base = drvdata->pin_base + bank->pin_base;
gc->ngpio = bank->nr_pins;
- gc->dev = &pdev->dev;
+ gc->parent = &pdev->dev;
gc->of_node = bank->of_node;
gc->label = bank->name;
- ret = gpiochip_add(gc);
+ ret = gpiochip_add_data(gc, bank);
if (ret) {
dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
gc->label, ret);
diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index db3f09aa8993..a6681b8b17c3 100644
--- a/drivers/pinctrl/sh-pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -38,14 +38,10 @@ struct sh_pfc_chip {
struct sh_pfc_gpio_pin *pins;
};
-static struct sh_pfc_chip *gpio_to_pfc_chip(struct gpio_chip *gc)
-{
- return container_of(gc, struct sh_pfc_chip, gpio_chip);
-}
-
static struct sh_pfc *gpio_to_pfc(struct gpio_chip *gc)
{
- return gpio_to_pfc_chip(gc)->pfc;
+ struct sh_pfc_chip *chip = gpiochip_get_data(gc);
+ return chip->pfc;
}
static void gpio_get_data_reg(struct sh_pfc_chip *chip, unsigned int offset,
@@ -178,14 +174,14 @@ static int gpio_pin_direction_input(struct gpio_chip *gc, unsigned offset)
static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
- gpio_pin_set_value(gpio_to_pfc_chip(gc), offset, value);
+ gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
return pinctrl_gpio_direction_output(offset);
}
static int gpio_pin_get(struct gpio_chip *gc, unsigned offset)
{
- struct sh_pfc_chip *chip = gpio_to_pfc_chip(gc);
+ struct sh_pfc_chip *chip = gpiochip_get_data(gc);
struct sh_pfc_gpio_data_reg *reg;
unsigned int bit;
unsigned int pos;
@@ -199,7 +195,7 @@ static int gpio_pin_get(struct gpio_chip *gc, unsigned offset)
static void gpio_pin_set(struct gpio_chip *gc, unsigned offset, int value)
{
- gpio_pin_set_value(gpio_to_pfc_chip(gc), offset, value);
+ gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
}
static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -246,7 +242,7 @@ static int gpio_pin_setup(struct sh_pfc_chip *chip)
gc->to_irq = gpio_pin_to_irq;
gc->label = pfc->info->name;
- gc->dev = pfc->dev;
+ gc->parent = pfc->dev;
gc->owner = THIS_MODULE;
gc->base = 0;
gc->ngpio = pfc->nr_gpio_pins;
@@ -322,7 +318,7 @@ sh_pfc_add_gpiochip(struct sh_pfc *pfc, int(*setup)(struct sh_pfc_chip *),
if (ret < 0)
return ERR_PTR(ret);
- ret = gpiochip_add(&chip->gpio_chip);
+ ret = gpiochip_add_data(&chip->gpio_chip, chip);
if (unlikely(ret < 0))
return ERR_PTR(ret);
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 053d98e33944..beb024c31a5d 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -358,11 +358,6 @@ struct atlas7_gpio_chip {
struct atlas7_gpio_bank banks[0];
};
-static inline struct atlas7_gpio_chip *to_atlas7_gpio(struct gpio_chip *gc)
-{
- return container_of(gc, struct atlas7_gpio_chip, chip);
-}
-
/**
* @dev: a pointer back to containing device
* @virtbase: the offset to the controller in virtual memory
@@ -5642,7 +5637,7 @@ static int __atlas7_gpio_to_pin(struct atlas7_gpio_chip *a7gc, u32 gpio)
static void atlas7_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
struct atlas7_gpio_bank *bank;
void __iomem *ctrl_reg;
u32 val, pin_in_bank;
@@ -5680,7 +5675,7 @@ static void __atlas7_gpio_irq_mask(struct atlas7_gpio_chip *a7gc, int idx)
static void atlas7_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&a7gc->lock, flags);
@@ -5693,7 +5688,7 @@ static void atlas7_gpio_irq_mask(struct irq_data *d)
static void atlas7_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
struct atlas7_gpio_bank *bank;
void __iomem *ctrl_reg;
u32 val, pin_in_bank;
@@ -5717,7 +5712,7 @@ static int atlas7_gpio_irq_type(struct irq_data *d,
unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
struct atlas7_gpio_bank *bank;
void __iomem *ctrl_reg;
u32 val, pin_in_bank;
@@ -5786,7 +5781,7 @@ static struct irq_chip atlas7_gpio_irq_chip = {
static void atlas7_gpio_handle_irq(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
struct atlas7_gpio_bank *bank = NULL;
u32 status, ctrl;
int pin_in_bank = 0, idx;
@@ -5854,7 +5849,7 @@ static void __atlas7_gpio_set_input(struct atlas7_gpio_chip *a7gc,
static int atlas7_gpio_request(struct gpio_chip *chip,
unsigned int gpio)
{
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
int ret;
unsigned long flags;
@@ -5882,7 +5877,7 @@ static int atlas7_gpio_request(struct gpio_chip *chip,
static void atlas7_gpio_free(struct gpio_chip *chip,
unsigned int gpio)
{
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&a7gc->lock, flags);
@@ -5898,7 +5893,7 @@ static void atlas7_gpio_free(struct gpio_chip *chip,
static int atlas7_gpio_direction_input(struct gpio_chip *chip,
unsigned int gpio)
{
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&a7gc->lock, flags);
@@ -5935,7 +5930,7 @@ static void __atlas7_gpio_set_output(struct atlas7_gpio_chip *a7gc,
static int atlas7_gpio_direction_output(struct gpio_chip *chip,
unsigned int gpio, int value)
{
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&a7gc->lock, flags);
@@ -5950,7 +5945,7 @@ static int atlas7_gpio_direction_output(struct gpio_chip *chip,
static int atlas7_gpio_get_value(struct gpio_chip *chip,
unsigned int gpio)
{
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
struct atlas7_gpio_bank *bank;
u32 val, pin_in_bank;
unsigned long flags;
@@ -5970,7 +5965,7 @@ static int atlas7_gpio_get_value(struct gpio_chip *chip,
static void atlas7_gpio_set_value(struct gpio_chip *chip,
unsigned int gpio, int value)
{
- struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
struct atlas7_gpio_bank *bank;
void __iomem *ctrl_reg;
u32 ctrl, pin_in_bank;
@@ -6054,10 +6049,10 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
chip->label = kstrdup(np->name, GFP_KERNEL);
chip->of_node = np;
chip->of_gpio_n_cells = 2;
- chip->dev = &pdev->dev;
+ chip->parent = &pdev->dev;
/* Add gpio chip to system */
- ret = gpiochip_add(chip);
+ ret = gpiochip_add_data(chip, a7gc);
if (ret) {
dev_err(&pdev->dev,
"%s: error in probe function with status %d\n",
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index edf40df05ec0..762c0c9c1278 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -403,11 +403,6 @@ static int __init sirfsoc_pinmux_init(void)
}
arch_initcall(sirfsoc_pinmux_init);
-static inline struct sirfsoc_gpio_chip *to_sirfsoc_gpio(struct gpio_chip *gc)
-{
- return container_of(gc, struct sirfsoc_gpio_chip, chip.gc);
-}
-
static inline struct sirfsoc_gpio_bank *
sirfsoc_gpio_to_bank(struct sirfsoc_gpio_chip *sgpio, unsigned int offset)
{
@@ -422,7 +417,7 @@ static inline int sirfsoc_gpio_to_bankoff(unsigned int offset)
static void sirfsoc_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
int idx = sirfsoc_gpio_to_bankoff(d->hwirq);
u32 val, offset;
@@ -461,7 +456,7 @@ static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_chip *sgpio,
static void sirfsoc_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
__sirfsoc_gpio_irq_mask(sgpio, bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
@@ -470,7 +465,7 @@ static void sirfsoc_gpio_irq_mask(struct irq_data *d)
static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
int idx = sirfsoc_gpio_to_bankoff(d->hwirq);
u32 val, offset;
@@ -491,7 +486,7 @@ static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
int idx = sirfsoc_gpio_to_bankoff(d->hwirq);
u32 val, offset;
@@ -553,7 +548,7 @@ static void sirfsoc_gpio_handle_irq(struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
struct sirfsoc_gpio_bank *bank;
u32 status, ctrl;
int idx = 0;
@@ -611,7 +606,7 @@ static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_chip *sgpio,
static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
unsigned long flags;
@@ -634,7 +629,7 @@ static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
unsigned long flags;
@@ -650,7 +645,7 @@ static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, gpio);
int idx = sirfsoc_gpio_to_bankoff(gpio);
unsigned long flags;
@@ -693,7 +688,7 @@ static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_chip *sgpio,
static int sirfsoc_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, gpio);
int idx = sirfsoc_gpio_to_bankoff(gpio);
u32 offset;
@@ -712,7 +707,7 @@ static int sirfsoc_gpio_direction_output(struct gpio_chip *chip,
static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
{
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
u32 val;
unsigned long flags;
@@ -729,7 +724,7 @@ static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+ struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
u32 ctrl;
unsigned long flags;
@@ -815,10 +810,10 @@ static int sirfsoc_gpio_probe(struct device_node *np)
sgpio->chip.gc.of_node = np;
sgpio->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
sgpio->chip.gc.of_gpio_n_cells = 2;
- sgpio->chip.gc.dev = &pdev->dev;
+ sgpio->chip.gc.parent = &pdev->dev;
sgpio->chip.regs = regs;
- err = gpiochip_add(&sgpio->chip.gc);
+ err = gpiochip_add_data(&sgpio->chip.gc, sgpio);
if (err) {
dev_err(&pdev->dev, "%s: error in probe function with status %d\n",
np->full_name, err);
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
index 1f0af250dbb5..4c9b863f8267 100644
--- a/drivers/pinctrl/spear/pinctrl-plgpio.c
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -107,7 +107,7 @@ static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg)
/* gpio framework specific routines */
static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(chip);
unsigned long flags;
/* get correct offset for "offset" pin */
@@ -127,7 +127,7 @@ static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(chip);
unsigned long flags;
unsigned dir_offset = offset, wdata_offset = offset, tmp;
@@ -159,7 +159,7 @@ static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
{
- struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(chip);
if (offset >= chip->ngpio)
return -EINVAL;
@@ -176,7 +176,7 @@ static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
{
- struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(chip);
if (offset >= chip->ngpio)
return;
@@ -196,7 +196,7 @@ static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
static int plgpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(chip);
int gpio = chip->base + offset;
unsigned long flags;
int ret = 0;
@@ -248,7 +248,7 @@ err0:
static void plgpio_free(struct gpio_chip *chip, unsigned offset)
{
- struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(chip);
int gpio = chip->base + offset;
unsigned long flags;
@@ -280,7 +280,7 @@ disable_clk:
static void plgpio_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(gc);
int offset = d->hwirq;
unsigned long flags;
@@ -299,7 +299,7 @@ static void plgpio_irq_disable(struct irq_data *d)
static void plgpio_irq_enable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(gc);
int offset = d->hwirq;
unsigned long flags;
@@ -318,7 +318,7 @@ static void plgpio_irq_enable(struct irq_data *d)
static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(gc);
int offset = d->hwirq;
void __iomem *reg_off;
unsigned int supported_type = 0, val;
@@ -359,7 +359,7 @@ static struct irq_chip plgpio_irqchip = {
static void plgpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+ struct plgpio *plgpio = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
int regs_count, count, pin, offset, i = 0;
unsigned long pending;
@@ -561,7 +561,7 @@ static int plgpio_probe(struct platform_device *pdev)
plgpio->chip.get = plgpio_get_value;
plgpio->chip.set = plgpio_set_value;
plgpio->chip.label = dev_name(&pdev->dev);
- plgpio->chip.dev = &pdev->dev;
+ plgpio->chip.parent = &pdev->dev;
plgpio->chip.owner = THIS_MODULE;
plgpio->chip.of_node = pdev->dev.of_node;
@@ -573,7 +573,7 @@ static int plgpio_probe(struct platform_device *pdev)
}
}
- ret = gpiochip_add(&plgpio->chip);
+ ret = gpiochip_add_data(&plgpio->chip, plgpio);
if (ret) {
dev_err(&pdev->dev, "unable to add gpio chip\n");
goto unprepare_clk;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index dead97daca35..7a2465f5e71e 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -12,7 +12,7 @@
#include <linux/io.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/module.h>
@@ -454,7 +454,7 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
u32 reg = sunxi_data_reg(offset);
u8 index = sunxi_data_offset(offset);
u32 set_mux = pctl->desc->irq_read_needs_mux &&
@@ -469,13 +469,13 @@ static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
if (set_mux)
sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
- return val;
+ return !!val;
}
static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
u32 reg = sunxi_data_reg(offset);
u8 index = sunxi_data_offset(offset);
unsigned long flags;
@@ -522,7 +522,7 @@ static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
struct sunxi_desc_function *desc;
unsigned pinnum = pctl->desc->pin_base + offset;
unsigned irqnum;
@@ -536,7 +536,7 @@ static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum;
- dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+ dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n",
chip->label, offset + chip->base, irqnum);
return irq_find_mapping(pctl->domain, irqnum);
@@ -959,10 +959,10 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
pctl->desc->pin_base;
pctl->chip->label = dev_name(&pdev->dev);
- pctl->chip->dev = &pdev->dev;
+ pctl->chip->parent = &pdev->dev;
pctl->chip->base = pctl->desc->pin_base;
- ret = gpiochip_add(pctl->chip);
+ ret = gpiochip_add_data(pctl->chip, pctl);
if (ret)
goto pinctrl_error;
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index fb22d3f62480..5c261bf5542f 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -14,7 +14,7 @@
*/
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -488,7 +488,7 @@ static struct pinctrl_desc wmt_desc = {
static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+ struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
u32 bank = WMT_BANK_FROM_PIN(offset);
u32 bit = WMT_BIT_FROM_PIN(offset);
u32 reg_dir = data->banks[bank].reg_dir;
@@ -503,7 +503,7 @@ static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
{
- struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+ struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
u32 bank = WMT_BANK_FROM_PIN(offset);
u32 bit = WMT_BIT_FROM_PIN(offset);
u32 reg_data_in = data->banks[bank].reg_data_in;
@@ -519,7 +519,7 @@ static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
int val)
{
- struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+ struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
u32 bank = WMT_BANK_FROM_PIN(offset);
u32 bit = WMT_BIT_FROM_PIN(offset);
u32 reg_data_out = data->banks[bank].reg_data_out;
@@ -575,7 +575,7 @@ int wmt_pinctrl_probe(struct platform_device *pdev,
wmt_desc.npins = data->npins;
data->gpio_chip = wmt_gpio_chip;
- data->gpio_chip.dev = &pdev->dev;
+ data->gpio_chip.parent = &pdev->dev;
data->gpio_chip.of_node = pdev->dev.of_node;
data->gpio_chip.ngpio = data->nbanks * 32;
@@ -589,7 +589,7 @@ int wmt_pinctrl_probe(struct platform_device *pdev,
return PTR_ERR(data->pctl_dev);
}
- err = gpiochip_add(&data->gpio_chip);
+ err = gpiochip_add_data(&data->gpio_chip, data);
if (err) {
dev_err(&pdev->dev, "could not add GPIO chip\n");
goto fail_gpio;
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 1089eaa02b00..69f93a576e45 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -587,6 +587,20 @@ config EEEPC_WMI
If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M
here.
+config ASUS_WIRELESS
+ tristate "Asus Wireless Radio Control Driver"
+ depends on ACPI
+ depends on INPUT
+ ---help---
+ The Asus Wireless Radio Control handles the airplane mode hotkey
+ present on some Asus laptops.
+
+ Say Y or M here if you have an ASUS notebook with an airplane mode
+ hotkey.
+
+ If you choose to compile this driver as a module the module will be
+ called asus-wireless.
+
config ACPI_WMI
tristate "WMI"
depends on ACPI
@@ -641,6 +655,7 @@ config ACPI_TOSHIBA
depends on INPUT
depends on SERIO_I8042 || SERIO_I8042 = n
depends on ACPI_VIDEO || ACPI_VIDEO = n
+ depends on RFKILL || RFKILL = n
select INPUT_POLLDEV
select INPUT_SPARSEKMAP
---help---
@@ -731,6 +746,18 @@ config ACPI_CMPC
keys as input device, backlight device, tablet and accelerometer
devices.
+config INTEL_HID_EVENT
+ tristate "INTEL HID Event"
+ depends on ACPI
+ depends on INPUT
+ select INPUT_SPARSEKMAP
+ help
+ This driver provides support for the Intel HID Event hotkey interface.
+ Some laptops require this driver for hotkey support.
+
+ To compile this driver as a module, choose M here: the module will
+ be called intel_hid.
+
config INTEL_SCU_IPC
bool "Intel SCU IPC Support"
depends on X86_INTEL_MID
@@ -940,8 +967,25 @@ config INTEL_PMC_IPC
with other entities in the CPU.
config SURFACE_PRO3_BUTTON
- tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3 tablet"
+ tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
depends on ACPI && INPUT
---help---
- This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3 tablet.
+ This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
+
+config INTEL_PUNIT_IPC
+ tristate "Intel P-Unit IPC Driver"
+ ---help---
+ This driver provides support for Intel P-Unit Mailbox IPC mechanism,
+ which is used to bridge the communications between kernel and P-Unit.
+
+config INTEL_TELEMETRY
+ tristate "Intel SoC Telemetry Driver"
+ default n
+ depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64
+ ---help---
+ This driver provides interfaces to configure and use
+ telemetry for INTEL SoC from APL onwards. It is also
+ used to get various SoC events and parameters
+ directly via debugfs files. Various tools may use
+ this interface for SoC state monitoring.
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 3ca78a3eb6f8..40574e7390f3 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
+obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o
obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
+obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
@@ -62,3 +64,7 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
+obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
+obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
+ intel_telemetry_pltdrv.o \
+ intel_telemetry_debugfs.o
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 976efeb3f2ba..f236250ac106 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -3,6 +3,7 @@
*
* Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
* Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
+ * Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
*
* 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
@@ -26,6 +27,24 @@
#include <acpi/video.h>
#include <asm/io.h>
+/**
+ * DOC: Overview
+ *
+ * :1: http://www.latticesemi.com/en/Products/FPGAandCPLD/LatticeXP2.aspx
+ * :2: http://www.renesas.com/products/mpumcu/h8s/h8s2100/h8s2113/index.jsp
+ *
+ * gmux is a microcontroller built into the MacBook Pro to support dual GPUs:
+ * A {1}[Lattice XP2] on pre-retinas, a {2}[Renesas R4F2113] on retinas.
+ *
+ * (The MacPro6,1 2013 also has a gmux, however it is unclear why since it has
+ * dual GPUs but no built-in display.)
+ *
+ * gmux is connected to the LPC bus of the southbridge. Its I/O ports are
+ * accessed differently depending on the microcontroller: Driver functions
+ * to access a pre-retina gmux are infixed `_pio_`, those for a retina gmux
+ * are infixed `_index_`.
+ */
+
struct apple_gmux_data {
unsigned long iostart;
unsigned long iolen;
@@ -247,6 +266,20 @@ static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
return false;
}
+/**
+ * DOC: Backlight control
+ *
+ * :3: http://www.ti.com/lit/ds/symlink/lp8543.pdf
+ * :4: http://www.ti.com/lit/ds/symlink/lp8545.pdf
+ *
+ * On single GPU MacBooks, the PWM signal for the backlight is generated by
+ * the GPU. On dual GPU MacBook Pros by contrast, either GPU may be suspended
+ * to conserve energy. Hence the PWM signal needs to be generated by a separate
+ * backlight driver which is controlled by gmux. The earliest generation
+ * MBP5 2008/09 uses a {3}[TI LP8543] backlight driver. All newer models
+ * use a {4}[TI LP8545].
+ */
+
static int gmux_get_brightness(struct backlight_device *bd)
{
struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -273,6 +306,68 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
};
+/**
+ * DOC: Graphics mux
+ *
+ * :5: http://pimg-fpiw.uspto.gov/fdd/07/870/086/0.pdf
+ * :6: http://www.nxp.com/documents/data_sheet/CBTL06141.pdf
+ * :7: http://www.ti.com/lit/ds/symlink/hd3ss212.pdf
+ * :8: https://www.pericom.com/assets/Datasheets/PI3VDP12412.pdf
+ * :9: http://www.ti.com/lit/ds/symlink/sn74lv4066a.pdf
+ * :10: http://pdf.datasheetarchive.com/indexerfiles/Datasheets-SW16/DSASW00308511.pdf
+ * :11: http://www.ti.com/lit/ds/symlink/ts3ds10224.pdf
+ *
+ * On pre-retinas, the LVDS outputs of both GPUs feed into gmux which muxes
+ * either of them to the panel. One of the tricks gmux has up its sleeve is
+ * to lengthen the blanking interval of its output during a switch to
+ * synchronize it with the GPU switched to. This allows for a flicker-free
+ * switch that is imperceptible by the user ({5}[US 8,687,007 B2]).
+ *
+ * On retinas, muxing is no longer done by gmux itself, but by a separate
+ * chip which is controlled by gmux. The chip is triple sourced, it is
+ * either an {6}[NXP CBTL06142], {7}[TI HD3SS212] or {8}[Pericom PI3VDP12412].
+ * The panel is driven with eDP instead of LVDS since the pixel clock
+ * required for retina resolution exceeds LVDS' limits.
+ *
+ * Pre-retinas are able to switch the panel's DDC pins separately.
+ * This is handled by a {9}[TI SN74LV4066A] which is controlled by gmux.
+ * The inactive GPU can thus probe the panel's EDID without switching over
+ * the entire panel. Retinas lack this functionality as the chips used for
+ * eDP muxing are incapable of switching the AUX channel separately (see
+ * the linked data sheets, Pericom would be capable but this is unused).
+ * However the retina panel has the NO_AUX_HANDSHAKE_LINK_TRAINING bit set
+ * in its DPCD, allowing the inactive GPU to skip the AUX handshake and
+ * set up the output with link parameters pre-calibrated by the active GPU.
+ *
+ * The external DP port is only fully switchable on the first two unibody
+ * MacBook Pro generations, MBP5 2008/09 and MBP6 2010. This is done by an
+ * {6}[NXP CBTL06141] which is controlled by gmux. It's the predecessor of the
+ * eDP mux on retinas, the difference being support for 2.7 versus 5.4 Gbit/s.
+ *
+ * The following MacBook Pro generations replaced the external DP port with a
+ * combined DP/Thunderbolt port and lost the ability to switch it between GPUs,
+ * connecting it either to the discrete GPU or the Thunderbolt controller.
+ * Oddly enough, while the full port is no longer switchable, AUX and HPD
+ * are still switchable by way of an {10}[NXP CBTL03062] (on pre-retinas
+ * MBP8 2011 and MBP9 2012) or two {11}[TI TS3DS10224] (on retinas) under the
+ * control of gmux. Since the integrated GPU is missing the main link,
+ * external displays appear to it as phantoms which fail to link-train.
+ *
+ * gmux receives the HPD signal of all display connectors and sends an
+ * interrupt on hotplug. On generations which cannot switch external ports,
+ * the discrete GPU can then be woken to drive the newly connected display.
+ * The ability to switch AUX on these generations could be used to improve
+ * reliability of hotplug detection by having the integrated GPU poll the
+ * ports while the discrete GPU is asleep, but currently we do not make use
+ * of this feature.
+ *
+ * gmux' initial switch state on bootup is user configurable via the EFI
+ * variable `gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9` (5th byte,
+ * 1 = IGD, 0 = DIS). Based on this setting, the EFI firmware tells gmux to
+ * switch the panel and the external DP connector and allocates a framebuffer
+ * for the selected GPU.
+ */
+
static int gmux_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD) {
@@ -288,6 +383,14 @@ static int gmux_switchto(enum vga_switcheroo_client_id id)
return 0;
}
+/**
+ * DOC: Power control
+ *
+ * gmux is able to cut power to the discrete GPU. It automatically takes care
+ * of the correct sequence to tear down and bring up the power rails for
+ * core voltage, VRAM and PCIe.
+ */
+
static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
enum vga_switcheroo_state state)
{
@@ -352,6 +455,16 @@ static const struct vga_switcheroo_handler gmux_handler = {
.get_client_id = gmux_get_client_id,
};
+/**
+ * DOC: Interrupt
+ *
+ * gmux is also connected to a GPIO pin of the southbridge and thereby is able
+ * to trigger an ACPI GPE. On the MBP5 2008/09 it's GPIO pin 22 of the Nvidia
+ * MCP79, on all following generations it's GPIO pin 6 of the Intel PCH.
+ * The GPE merely signals that an interrupt occurred, the actual type of event
+ * is identified by reading a gmux register.
+ */
+
static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
{
gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
@@ -588,18 +701,20 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
gmux_data->gpe = -1;
}
+ apple_gmux_data = gmux_data;
+ init_completion(&gmux_data->powerchange_done);
+ gmux_enable_interrupts(gmux_data);
+
if (vga_switcheroo_register_handler(&gmux_handler)) {
ret = -ENODEV;
goto err_register_handler;
}
- init_completion(&gmux_data->powerchange_done);
- apple_gmux_data = gmux_data;
- gmux_enable_interrupts(gmux_data);
-
return 0;
err_register_handler:
+ gmux_disable_interrupts(gmux_data);
+ apple_gmux_data = NULL;
if (gmux_data->gpe >= 0)
acpi_disable_gpe(NULL, gmux_data->gpe);
err_enable_gpe:
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
new file mode 100644
index 000000000000..9ec721e26532
--- /dev/null
+++ b/drivers/platform/x86/asus-wireless.c
@@ -0,0 +1,84 @@
+/*
+ * Asus Wireless Radio Control Driver
+ *
+ * Copyright (C) 2015-2016 Endless Mobile, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/pci_ids.h>
+
+struct asus_wireless_data {
+ struct input_dev *idev;
+};
+
+static void asus_wireless_notify(struct acpi_device *adev, u32 event)
+{
+ struct asus_wireless_data *data = acpi_driver_data(adev);
+
+ dev_dbg(&adev->dev, "event=%#x\n", event);
+ if (event != 0x88) {
+ dev_notice(&adev->dev, "Unknown ASHS event: %#x\n", event);
+ return;
+ }
+ input_report_key(data->idev, KEY_RFKILL, 1);
+ input_report_key(data->idev, KEY_RFKILL, 0);
+ input_sync(data->idev);
+}
+
+static int asus_wireless_add(struct acpi_device *adev)
+{
+ struct asus_wireless_data *data;
+
+ data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ adev->driver_data = data;
+
+ data->idev = devm_input_allocate_device(&adev->dev);
+ if (!data->idev)
+ return -ENOMEM;
+ data->idev->name = "Asus Wireless Radio Control";
+ data->idev->phys = "asus-wireless/input0";
+ data->idev->id.bustype = BUS_HOST;
+ data->idev->id.vendor = PCI_VENDOR_ID_ASUSTEK;
+ set_bit(EV_KEY, data->idev->evbit);
+ set_bit(KEY_RFKILL, data->idev->keybit);
+ return input_register_device(data->idev);
+}
+
+static int asus_wireless_remove(struct acpi_device *adev)
+{
+ return 0;
+}
+
+static const struct acpi_device_id device_ids[] = {
+ {"ATK4001", 0},
+ {"ATK4002", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, device_ids);
+
+static struct acpi_driver asus_wireless_driver = {
+ .name = "Asus Wireless Radio Control Driver",
+ .class = "hotkey",
+ .ids = device_ids,
+ .ops = {
+ .add = asus_wireless_add,
+ .remove = asus_wireless_remove,
+ .notify = asus_wireless_notify,
+ },
+};
+module_acpi_driver(asus_wireless_driver);
+
+MODULE_DESCRIPTION("Asus Wireless Radio Control Driver");
+MODULE_AUTHOR("João Paulo Rechi Vita <jprvita@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index f96f7b865267..a96630d52346 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -56,9 +56,6 @@ MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>, "
MODULE_DESCRIPTION("Asus Generic WMI Driver");
MODULE_LICENSE("GPL");
-#define to_platform_driver(drv) \
- (container_of((drv), struct platform_driver, driver))
-
#define to_asus_wmi_driver(pdrv) \
(container_of((pdrv), struct asus_wmi_driver, platform_driver))
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index cb8a9c2a3a1f..368e193c2741 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -2,6 +2,7 @@
* Dell WMI hotkeys
*
* Copyright (C) 2008 Red Hat <mjg@redhat.com>
+ * Copyright (C) 2014-2015 Pali Rohár <pali.rohar@gmail.com>
*
* Portions based on wistron_btns.c:
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -38,12 +39,17 @@
#include <acpi/video.h>
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
+MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
MODULE_LICENSE("GPL");
#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
+#define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
+
+static u32 dell_wmi_interface_version;
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
+MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID);
/*
* Certain keys are flagged as KE_IGNORE. All of these are either
@@ -116,28 +122,48 @@ struct dell_bios_hotkey_table {
static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
+/* Uninitialized entries here are KEY_RESERVED == 0. */
static const u16 bios_to_linux_keycode[256] __initconst = {
-
- KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
- KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
- KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE,
- KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD,
- KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN,
- KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE,
- KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN,
- KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2,
- KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
- KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_MICMUTE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PROG3
+ [0] = KEY_MEDIA,
+ [1] = KEY_NEXTSONG,
+ [2] = KEY_PLAYPAUSE,
+ [3] = KEY_PREVIOUSSONG,
+ [4] = KEY_STOPCD,
+ [5] = KEY_UNKNOWN,
+ [6] = KEY_UNKNOWN,
+ [7] = KEY_UNKNOWN,
+ [8] = KEY_WWW,
+ [9] = KEY_UNKNOWN,
+ [10] = KEY_VOLUMEDOWN,
+ [11] = KEY_MUTE,
+ [12] = KEY_VOLUMEUP,
+ [13] = KEY_UNKNOWN,
+ [14] = KEY_BATTERY,
+ [15] = KEY_EJECTCD,
+ [16] = KEY_UNKNOWN,
+ [17] = KEY_SLEEP,
+ [18] = KEY_PROG1,
+ [19] = KEY_BRIGHTNESSDOWN,
+ [20] = KEY_BRIGHTNESSUP,
+ [21] = KEY_UNKNOWN,
+ [22] = KEY_KBDILLUMTOGGLE,
+ [23] = KEY_UNKNOWN,
+ [24] = KEY_SWITCHVIDEOMODE,
+ [25] = KEY_UNKNOWN,
+ [26] = KEY_UNKNOWN,
+ [27] = KEY_SWITCHVIDEOMODE,
+ [28] = KEY_UNKNOWN,
+ [29] = KEY_UNKNOWN,
+ [30] = KEY_PROG2,
+ [31] = KEY_UNKNOWN,
+ [32] = KEY_UNKNOWN,
+ [33] = KEY_UNKNOWN,
+ [34] = KEY_UNKNOWN,
+ [35] = KEY_UNKNOWN,
+ [36] = KEY_UNKNOWN,
+ [37] = KEY_UNKNOWN,
+ [38] = KEY_MICMUTE,
+ [255] = KEY_PROG3,
};
static struct input_dev *dell_wmi_input_dev;
@@ -149,7 +175,8 @@ static void dell_wmi_process_key(int reported_key)
key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
reported_key);
if (!key) {
- pr_info("Unknown key %x pressed\n", reported_key);
+ pr_info("Unknown key with scancode 0x%x pressed\n",
+ reported_key);
return;
}
@@ -210,6 +237,22 @@ static void dell_wmi_notify(u32 value, void *context)
buffer_end = buffer_entry + buffer_size;
+ /*
+ * BIOS/ACPI on devices with WMI interface version 0 does not clear
+ * buffer before filling it. So next time when BIOS/ACPI send WMI event
+ * which is smaller as previous then it contains garbage in buffer from
+ * previous event.
+ *
+ * BIOS/ACPI on devices with WMI interface version 1 clears buffer and
+ * sometimes send more events in buffer at one call.
+ *
+ * So to prevent reading garbage from buffer we will process only first
+ * one event on devices with WMI interface version 0.
+ */
+ if (dell_wmi_interface_version == 0 && buffer_entry < buffer_end)
+ if (buffer_end > buffer_entry + buffer_entry[0] + 1)
+ buffer_end = buffer_entry + buffer_entry[0] + 1;
+
while (buffer_entry < buffer_end) {
len = buffer_entry[0];
@@ -308,9 +351,23 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
for (i = 0; i < hotkey_num; i++) {
const struct dell_bios_keymap_entry *bios_entry =
&dell_bios_hotkey_table->keymap[i];
- u16 keycode = bios_entry->keycode < 256 ?
- bios_to_linux_keycode[bios_entry->keycode] :
- KEY_RESERVED;
+
+ /* Uninitialized entries are 0 aka KEY_RESERVED. */
+ u16 keycode = (bios_entry->keycode <
+ ARRAY_SIZE(bios_to_linux_keycode)) ?
+ bios_to_linux_keycode[bios_entry->keycode] :
+ KEY_RESERVED;
+
+ /*
+ * Log if we find an entry in the DMI table that we don't
+ * understand. If this happens, we should figure out what
+ * the entry means and add it to bios_to_linux_keycode.
+ */
+ if (keycode == KEY_RESERVED) {
+ pr_info("firmware scancode 0x%x maps to unrecognized keycode 0x%x\n",
+ bios_entry->scancode, bios_entry->keycode);
+ continue;
+ }
if (keycode == KEY_KBDILLUMTOGGLE)
keymap[i].type = KE_IGNORE;
@@ -386,16 +443,87 @@ static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
}
}
+/*
+ * Descriptor buffer is 128 byte long and contains:
+ *
+ * Name Offset Length Value
+ * Vendor Signature 0 4 "DELL"
+ * Object Signature 4 4 " WMI"
+ * WMI Interface Version 8 4 <version>
+ * WMI buffer length 12 4 4096
+ */
+static int __init dell_wmi_check_descriptor_buffer(void)
+{
+ struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+ u32 *buffer;
+
+ status = wmi_query_block(DELL_DESCRIPTOR_GUID, 0, &out);
+ if (ACPI_FAILURE(status)) {
+ pr_err("Cannot read Dell descriptor buffer - %d\n", status);
+ return status;
+ }
+
+ obj = (union acpi_object *)out.pointer;
+ if (!obj) {
+ pr_err("Dell descriptor buffer is empty\n");
+ return -EINVAL;
+ }
+
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ pr_err("Cannot read Dell descriptor buffer\n");
+ kfree(obj);
+ return -EINVAL;
+ }
+
+ if (obj->buffer.length != 128) {
+ pr_err("Dell descriptor buffer has invalid length (%d)\n",
+ obj->buffer.length);
+ if (obj->buffer.length < 16) {
+ kfree(obj);
+ return -EINVAL;
+ }
+ }
+
+ buffer = (u32 *)obj->buffer.pointer;
+
+ if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720)
+ pr_warn("Dell descriptor buffer has invalid signature (%*ph)\n",
+ 8, buffer);
+
+ if (buffer[2] != 0 && buffer[2] != 1)
+ pr_warn("Dell descriptor buffer has unknown version (%d)\n",
+ buffer[2]);
+
+ if (buffer[3] != 4096)
+ pr_warn("Dell descriptor buffer has invalid buffer length (%d)\n",
+ buffer[3]);
+
+ dell_wmi_interface_version = buffer[2];
+
+ pr_info("Detected Dell WMI interface version %u\n",
+ dell_wmi_interface_version);
+
+ kfree(obj);
+ return 0;
+}
+
static int __init dell_wmi_init(void)
{
int err;
acpi_status status;
- if (!wmi_has_guid(DELL_EVENT_GUID)) {
- pr_warn("No known WMI GUID found\n");
+ if (!wmi_has_guid(DELL_EVENT_GUID) ||
+ !wmi_has_guid(DELL_DESCRIPTOR_GUID)) {
+ pr_warn("Dell WMI GUID were not found\n");
return -ENODEV;
}
+ err = dell_wmi_check_descriptor_buffer();
+ if (err)
+ return err;
+
dmi_walk(find_hk_type, NULL);
err = dell_wmi_input_setup();
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index a313dfc0245f..d28db0e793df 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -865,6 +865,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
+ .ident = "Lenovo ideapad Y700-17ISK",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
+ },
+ },
+ {
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
new file mode 100644
index 000000000000..20f0ad9bb9f3
--- /dev/null
+++ b/drivers/platform/x86/intel-hid.c
@@ -0,0 +1,289 @@
+/*
+ * Intel HID event driver for Windows 8
+ *
+ * Copyright (C) 2015 Alex Hung <alex.hung@canonical.com>
+ * Copyright (C) 2015 Andrew Lutomirski <luto@kernel.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Hung");
+
+static const struct acpi_device_id intel_hid_ids[] = {
+ {"INT33D5", 0},
+ {"", 0},
+};
+
+/* In theory, these are HID usages. */
+static const struct key_entry intel_hid_keymap[] = {
+ /* 1: LSuper (Page 0x07, usage 0xE3) -- unclear what to do */
+ /* 2: Toggle SW_ROTATE_LOCK -- easy to implement if seen in wild */
+ { KE_KEY, 3, { KEY_NUMLOCK } },
+ { KE_KEY, 4, { KEY_HOME } },
+ { KE_KEY, 5, { KEY_END } },
+ { KE_KEY, 6, { KEY_PAGEUP } },
+ { KE_KEY, 4, { KEY_PAGEDOWN } },
+ { KE_KEY, 4, { KEY_HOME } },
+ { KE_KEY, 8, { KEY_RFKILL } },
+ { KE_KEY, 9, { KEY_POWER } },
+ { KE_KEY, 11, { KEY_SLEEP } },
+ /* 13 has two different meanings in the spec -- ignore it. */
+ { KE_KEY, 14, { KEY_STOPCD } },
+ { KE_KEY, 15, { KEY_PLAYPAUSE } },
+ { KE_KEY, 16, { KEY_MUTE } },
+ { KE_KEY, 17, { KEY_VOLUMEUP } },
+ { KE_KEY, 18, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 19, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 20, { KEY_BRIGHTNESSDOWN } },
+ /* 27: wake -- needs special handling */
+ { KE_END },
+};
+
+struct intel_hid_priv {
+ struct input_dev *input_dev;
+};
+
+static int intel_hid_set_enable(struct device *device, int enable)
+{
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list args = { 1, &arg0 };
+ acpi_status status;
+
+ arg0.integer.value = enable;
+ status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL);
+ if (!ACPI_SUCCESS(status)) {
+ dev_warn(device, "failed to %sable hotkeys\n",
+ enable ? "en" : "dis");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int intel_hid_pl_suspend_handler(struct device *device)
+{
+ intel_hid_set_enable(device, 0);
+ return 0;
+}
+
+static int intel_hid_pl_resume_handler(struct device *device)
+{
+ intel_hid_set_enable(device, 1);
+ return 0;
+}
+
+static const struct dev_pm_ops intel_hid_pl_pm_ops = {
+ .suspend = intel_hid_pl_suspend_handler,
+ .resume = intel_hid_pl_resume_handler,
+};
+
+static int intel_hid_input_setup(struct platform_device *device)
+{
+ struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+ int ret;
+
+ priv->input_dev = input_allocate_device();
+ if (!priv->input_dev)
+ return -ENOMEM;
+
+ ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL);
+ if (ret)
+ goto err_free_device;
+
+ priv->input_dev->dev.parent = &device->dev;
+ priv->input_dev->name = "Intel HID events";
+ priv->input_dev->id.bustype = BUS_HOST;
+ set_bit(KEY_RFKILL, priv->input_dev->keybit);
+
+ ret = input_register_device(priv->input_dev);
+ if (ret)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ input_free_device(priv->input_dev);
+ return ret;
+}
+
+static void intel_hid_input_destroy(struct platform_device *device)
+{
+ struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+
+ input_unregister_device(priv->input_dev);
+}
+
+static void notify_handler(acpi_handle handle, u32 event, void *context)
+{
+ struct platform_device *device = context;
+ struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+ unsigned long long ev_index;
+ acpi_status status;
+
+ /* The platform spec only defines one event code: 0xC0. */
+ if (event != 0xc0) {
+ dev_warn(&device->dev, "received unknown event (0x%x)\n",
+ event);
+ return;
+ }
+
+ status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index);
+ if (!ACPI_SUCCESS(status)) {
+ dev_warn(&device->dev, "failed to get event index\n");
+ return;
+ }
+
+ if (!sparse_keymap_report_event(priv->input_dev, ev_index, 1, true))
+ dev_info(&device->dev, "unknown event index 0x%llx\n",
+ ev_index);
+}
+
+static int intel_hid_probe(struct platform_device *device)
+{
+ acpi_handle handle = ACPI_HANDLE(&device->dev);
+ struct intel_hid_priv *priv;
+ unsigned long long mode;
+ acpi_status status;
+ int err;
+
+ status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode);
+ if (!ACPI_SUCCESS(status)) {
+ dev_warn(&device->dev, "failed to read mode\n");
+ return -ENODEV;
+ }
+
+ if (mode != 0) {
+ /*
+ * This driver only implements "simple" mode. There appear
+ * to be no other modes, but we should be paranoid and check
+ * for compatibility.
+ */
+ dev_info(&device->dev, "platform is not in simple mode\n");
+ return -ENODEV;
+ }
+
+ priv = devm_kzalloc(&device->dev,
+ sizeof(struct intel_hid_priv *), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ dev_set_drvdata(&device->dev, priv);
+
+ err = intel_hid_input_setup(device);
+ if (err) {
+ pr_err("Failed to setup Intel HID hotkeys\n");
+ return err;
+ }
+
+ status = acpi_install_notify_handler(handle,
+ ACPI_DEVICE_NOTIFY,
+ notify_handler,
+ device);
+ if (ACPI_FAILURE(status)) {
+ err = -EBUSY;
+ goto err_remove_input;
+ }
+
+ err = intel_hid_set_enable(&device->dev, 1);
+ if (err)
+ goto err_remove_notify;
+
+ return 0;
+
+err_remove_notify:
+ acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
+
+err_remove_input:
+ intel_hid_input_destroy(device);
+
+ return err;
+}
+
+static int intel_hid_remove(struct platform_device *device)
+{
+ acpi_handle handle = ACPI_HANDLE(&device->dev);
+
+ acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
+ intel_hid_input_destroy(device);
+ intel_hid_set_enable(&device->dev, 0);
+ acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
+
+ /*
+ * Even if we failed to shut off the event stream, we can still
+ * safely detach from the device.
+ */
+ return 0;
+}
+
+static struct platform_driver intel_hid_pl_driver = {
+ .driver = {
+ .name = "intel-hid",
+ .acpi_match_table = intel_hid_ids,
+ .pm = &intel_hid_pl_pm_ops,
+ },
+ .probe = intel_hid_probe,
+ .remove = intel_hid_remove,
+};
+MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
+
+/*
+ * Unfortunately, some laptops provide a _HID="INT33D5" device with
+ * _CID="PNP0C02". This causes the pnpacpi scan driver to claim the
+ * ACPI node, so no platform device will be created. The pnpacpi
+ * driver rejects this device in subsequent processing, so no physical
+ * node is created at all.
+ *
+ * As a workaround until the ACPI core figures out how to handle
+ * this corner case, manually ask the ACPI platform device code to
+ * claim the ACPI node.
+ */
+static acpi_status __init
+check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ const struct acpi_device_id *ids = context;
+ struct acpi_device *dev;
+
+ if (acpi_bus_get_device(handle, &dev) != 0)
+ return AE_OK;
+
+ if (acpi_match_device_ids(dev, ids) == 0)
+ if (acpi_create_platform_device(dev))
+ dev_info(&dev->dev,
+ "intel-hid: created platform device\n");
+
+ return AE_OK;
+}
+
+static int __init intel_hid_init(void)
+{
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, check_acpi_dev, NULL,
+ (void *)intel_hid_ids, NULL);
+
+ return platform_driver_register(&intel_hid_pl_driver);
+}
+module_init(intel_hid_init);
+
+static void __exit intel_hid_exit(void)
+{
+ platform_driver_unregister(&intel_hid_pl_driver);
+}
+module_exit(intel_hid_exit);
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index 28b2a12bb26d..092519e37de6 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -68,8 +68,13 @@
#define PLAT_RESOURCE_IPC_INDEX 0
#define PLAT_RESOURCE_IPC_SIZE 0x1000
#define PLAT_RESOURCE_GCR_SIZE 0x1000
-#define PLAT_RESOURCE_PUNIT_DATA_INDEX 1
-#define PLAT_RESOURCE_PUNIT_INTER_INDEX 2
+#define PLAT_RESOURCE_BIOS_DATA_INDEX 1
+#define PLAT_RESOURCE_BIOS_IFACE_INDEX 2
+#define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3
+#define PLAT_RESOURCE_ISP_DATA_INDEX 4
+#define PLAT_RESOURCE_ISP_IFACE_INDEX 5
+#define PLAT_RESOURCE_GTD_DATA_INDEX 6
+#define PLAT_RESOURCE_GTD_IFACE_INDEX 7
#define PLAT_RESOURCE_ACPI_IO_INDEX 0
/*
@@ -84,6 +89,10 @@
#define TCO_BASE_OFFSET 0x60
#define TCO_REGS_SIZE 16
#define PUNIT_DEVICE_NAME "intel_punit_ipc"
+#define TELEMETRY_DEVICE_NAME "intel_telemetry"
+#define TELEM_SSRAM_SIZE 240
+#define TELEM_PMC_SSRAM_OFFSET 0x1B00
+#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00
static const int iTCO_version = 3;
@@ -105,11 +114,15 @@ static struct intel_pmc_ipc_dev {
int gcr_size;
/* punit */
- resource_size_t punit_base;
- int punit_size;
- resource_size_t punit_base2;
- int punit_size2;
struct platform_device *punit_dev;
+
+ /* Telemetry */
+ resource_size_t telem_pmc_ssram_base;
+ resource_size_t telem_punit_ssram_base;
+ int telem_pmc_ssram_size;
+ int telem_punit_ssram_size;
+ u8 telem_res_inval;
+ struct platform_device *telemetry_dev;
} ipcdev;
static char *ipc_err_sources[] = {
@@ -444,9 +457,22 @@ static const struct attribute_group intel_ipc_group = {
.attrs = intel_ipc_attrs,
};
-#define PUNIT_RESOURCE_INTER 1
-static struct resource punit_res[] = {
- /* Punit */
+static struct resource punit_res_array[] = {
+ /* Punit BIOS */
+ {
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_MEM,
+ },
+ /* Punit ISP */
+ {
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_MEM,
+ },
+ /* Punit GTD */
{
.flags = IORESOURCE_MEM,
},
@@ -478,10 +504,21 @@ static struct itco_wdt_platform_data tco_info = {
.version = 3,
};
+#define TELEMETRY_RESOURCE_PUNIT_SSRAM 0
+#define TELEMETRY_RESOURCE_PMC_SSRAM 1
+static struct resource telemetry_res[] = {
+ /*Telemetry*/
+ {
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_MEM,
+ },
+};
+
static int ipc_create_punit_device(void)
{
struct platform_device *pdev;
- struct resource *res;
int ret;
pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1);
@@ -491,17 +528,8 @@ static int ipc_create_punit_device(void)
}
pdev->dev.parent = ipcdev.dev;
-
- res = punit_res;
- res->start = ipcdev.punit_base;
- res->end = res->start + ipcdev.punit_size - 1;
-
- res = punit_res + PUNIT_RESOURCE_INTER;
- res->start = ipcdev.punit_base2;
- res->end = res->start + ipcdev.punit_size2 - 1;
-
- ret = platform_device_add_resources(pdev, punit_res,
- ARRAY_SIZE(punit_res));
+ ret = platform_device_add_resources(pdev, punit_res_array,
+ ARRAY_SIZE(punit_res_array));
if (ret) {
dev_err(ipcdev.dev, "Failed to add platform punit resources\n");
goto err;
@@ -571,6 +599,51 @@ err:
return ret;
}
+static int ipc_create_telemetry_device(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ int ret;
+
+ pdev = platform_device_alloc(TELEMETRY_DEVICE_NAME, -1);
+ if (!pdev) {
+ dev_err(ipcdev.dev,
+ "Failed to allocate telemetry platform device\n");
+ return -ENOMEM;
+ }
+
+ pdev->dev.parent = ipcdev.dev;
+
+ res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM;
+ res->start = ipcdev.telem_punit_ssram_base;
+ res->end = res->start + ipcdev.telem_punit_ssram_size - 1;
+
+ res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM;
+ res->start = ipcdev.telem_pmc_ssram_base;
+ res->end = res->start + ipcdev.telem_pmc_ssram_size - 1;
+
+ ret = platform_device_add_resources(pdev, telemetry_res,
+ ARRAY_SIZE(telemetry_res));
+ if (ret) {
+ dev_err(ipcdev.dev,
+ "Failed to add telemetry platform resources\n");
+ goto err;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(ipcdev.dev,
+ "Failed to add telemetry platform device\n");
+ goto err;
+ }
+ ipcdev.telemetry_dev = pdev;
+
+ return 0;
+err:
+ platform_device_put(pdev);
+ return ret;
+}
+
static int ipc_create_pmc_devices(void)
{
int ret;
@@ -585,12 +658,20 @@ static int ipc_create_pmc_devices(void)
dev_err(ipcdev.dev, "Failed to add punit platform device\n");
platform_device_unregister(ipcdev.tco_dev);
}
+
+ if (!ipcdev.telem_res_inval) {
+ ret = ipc_create_telemetry_device();
+ if (ret)
+ dev_warn(ipcdev.dev,
+ "Failed to add telemetry platform device\n");
+ }
+
return ret;
}
static int ipc_plat_get_res(struct platform_device *pdev)
{
- struct resource *res;
+ struct resource *res, *punit_res;
void __iomem *addr;
int size;
@@ -603,32 +684,68 @@ static int ipc_plat_get_res(struct platform_device *pdev)
size = resource_size(res);
ipcdev.acpi_io_base = res->start;
ipcdev.acpi_io_size = size;
- dev_info(&pdev->dev, "io res: %llx %x\n",
- (long long)res->start, (int)resource_size(res));
+ dev_info(&pdev->dev, "io res: %pR\n", res);
+ /* This is index 0 to cover BIOS data register */
+ punit_res = punit_res_array;
res = platform_get_resource(pdev, IORESOURCE_MEM,
- PLAT_RESOURCE_PUNIT_DATA_INDEX);
+ PLAT_RESOURCE_BIOS_DATA_INDEX);
if (!res) {
- dev_err(&pdev->dev, "Failed to get punit resource\n");
+ dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
return -ENXIO;
}
- size = resource_size(res);
- ipcdev.punit_base = res->start;
- ipcdev.punit_size = size;
- dev_info(&pdev->dev, "punit data res: %llx %x\n",
- (long long)res->start, (int)resource_size(res));
+ *punit_res = *res;
+ dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
res = platform_get_resource(pdev, IORESOURCE_MEM,
- PLAT_RESOURCE_PUNIT_INTER_INDEX);
+ PLAT_RESOURCE_BIOS_IFACE_INDEX);
if (!res) {
- dev_err(&pdev->dev, "Failed to get punit inter resource\n");
+ dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
return -ENXIO;
}
- size = resource_size(res);
- ipcdev.punit_base2 = res->start;
- ipcdev.punit_size2 = size;
- dev_info(&pdev->dev, "punit interface res: %llx %x\n",
- (long long)res->start, (int)resource_size(res));
+ /* This is index 1 to cover BIOS interface register */
+ *++punit_res = *res;
+ dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM,
+ PLAT_RESOURCE_ISP_DATA_INDEX);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get res of punit ISP data\n");
+ return -ENXIO;
+ }
+ /* This is index 2 to cover ISP data register */
+ *++punit_res = *res;
+ dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM,
+ PLAT_RESOURCE_ISP_IFACE_INDEX);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get res of punit ISP iface\n");
+ return -ENXIO;
+ }
+ /* This is index 3 to cover ISP interface register */
+ *++punit_res = *res;
+ dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM,
+ PLAT_RESOURCE_GTD_DATA_INDEX);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get res of punit GTD data\n");
+ return -ENXIO;
+ }
+ /* This is index 4 to cover GTD data register */
+ *++punit_res = *res;
+ dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM,
+ PLAT_RESOURCE_GTD_IFACE_INDEX);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get res of punit GTD iface\n");
+ return -ENXIO;
+ }
+ /* This is index 5 to cover GTD interface register */
+ *++punit_res = *res;
+ dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_IPC_INDEX);
@@ -651,8 +768,23 @@ static int ipc_plat_get_res(struct platform_device *pdev)
ipcdev.gcr_base = res->start + size;
ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
- dev_info(&pdev->dev, "ipc res: %llx %x\n",
- (long long)res->start, (int)resource_size(res));
+ dev_info(&pdev->dev, "ipc res: %pR\n", res);
+
+ ipcdev.telem_res_inval = 0;
+ res = platform_get_resource(pdev, IORESOURCE_MEM,
+ PLAT_RESOURCE_TELEM_SSRAM_INDEX);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n");
+ ipcdev.telem_res_inval = 1;
+ } else {
+ ipcdev.telem_punit_ssram_base = res->start +
+ TELEM_PUNIT_SSRAM_OFFSET;
+ ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE;
+ ipcdev.telem_pmc_ssram_base = res->start +
+ TELEM_PMC_SSRAM_OFFSET;
+ ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE;
+ dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res);
+ }
return 0;
}
@@ -711,6 +843,7 @@ err_sys:
err_irq:
platform_device_unregister(ipcdev.tco_dev);
platform_device_unregister(ipcdev.punit_dev);
+ platform_device_unregister(ipcdev.telemetry_dev);
err_device:
iounmap(ipcdev.ipc_base);
res = platform_get_resource(pdev, IORESOURCE_MEM,
@@ -728,6 +861,7 @@ static int ipc_plat_remove(struct platform_device *pdev)
free_irq(ipcdev.irq, &ipcdev);
platform_device_unregister(ipcdev.tco_dev);
platform_device_unregister(ipcdev.punit_dev);
+ platform_device_unregister(ipcdev.telemetry_dev);
iounmap(ipcdev.ipc_base);
res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_IPC_INDEX);
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index 709f0afdafa8..0e73fd10ba72 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -274,11 +274,11 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
pg->chip.base = pdata->gpio_base;
pg->chip.ngpio = NUM_GPIO;
pg->chip.can_sleep = 1;
- pg->chip.dev = dev;
+ pg->chip.parent = dev;
mutex_init(&pg->buslock);
- pg->chip.dev = dev;
+ pg->chip.parent = dev;
retval = gpiochip_add(&pg->chip);
if (retval) {
pr_err("Can not add pmic gpio chip\n");
diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
new file mode 100644
index 000000000000..bd875409a02d
--- /dev/null
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -0,0 +1,342 @@
+/*
+ * Driver for the Intel P-Unit Mailbox IPC mechanism
+ *
+ * (C) Copyright 2015 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
+ * published by the Free Software Foundation.
+ *
+ * The heart of the P-Unit is the Foxton microcontroller and its firmware,
+ * which provide mailbox interface for power management usage.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/intel_punit_ipc.h>
+
+/* IPC Mailbox registers */
+#define OFFSET_DATA_LOW 0x0
+#define OFFSET_DATA_HIGH 0x4
+/* bit field of interface register */
+#define CMD_RUN BIT(31)
+#define CMD_ERRCODE_MASK GENMASK(7, 0)
+#define CMD_PARA1_SHIFT 8
+#define CMD_PARA2_SHIFT 16
+
+#define CMD_TIMEOUT_SECONDS 1
+
+enum {
+ BASE_DATA = 0,
+ BASE_IFACE,
+ BASE_MAX,
+};
+
+typedef struct {
+ struct device *dev;
+ struct mutex lock;
+ int irq;
+ struct completion cmd_complete;
+ /* base of interface and data registers */
+ void __iomem *base[RESERVED_IPC][BASE_MAX];
+ IPC_TYPE type;
+} IPC_DEV;
+
+static IPC_DEV *punit_ipcdev;
+
+static inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+ return readl(ipcdev->base[type][BASE_IFACE]);
+}
+
+static inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd)
+{
+ writel(cmd, ipcdev->base[type][BASE_IFACE]);
+}
+
+static inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+ return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
+}
+
+static inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+ return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
+}
+
+static inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
+{
+ writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
+}
+
+static inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
+{
+ writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
+}
+
+static const char *ipc_err_string(int error)
+{
+ if (error == IPC_PUNIT_ERR_SUCCESS)
+ return "no error";
+ else if (error == IPC_PUNIT_ERR_INVALID_CMD)
+ return "invalid command";
+ else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER)
+ return "invalid parameter";
+ else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT)
+ return "command timeout";
+ else if (error == IPC_PUNIT_ERR_CMD_LOCKED)
+ return "command locked";
+ else if (error == IPC_PUNIT_ERR_INVALID_VR_ID)
+ return "invalid vr id";
+ else if (error == IPC_PUNIT_ERR_VR_ERR)
+ return "vr error";
+ else
+ return "unknown error";
+}
+
+static int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type)
+{
+ int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC;
+ int errcode;
+ int status;
+
+ if (ipcdev->irq) {
+ if (!wait_for_completion_timeout(&ipcdev->cmd_complete,
+ CMD_TIMEOUT_SECONDS * HZ)) {
+ dev_err(ipcdev->dev, "IPC timed out\n");
+ return -ETIMEDOUT;
+ }
+ } else {
+ while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops)
+ udelay(1);
+ if (!loops) {
+ dev_err(ipcdev->dev, "IPC timed out\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ status = ipc_read_status(ipcdev, type);
+ errcode = status & CMD_ERRCODE_MASK;
+ if (errcode) {
+ dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n",
+ ipc_err_string(errcode), status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * intel_punit_ipc_simple_command() - Simple IPC command
+ * @cmd: IPC command code.
+ * @para1: First 8bit parameter, set 0 if not used.
+ * @para2: Second 8bit parameter, set 0 if not used.
+ *
+ * Send a IPC command to P-Unit when there is no data transaction
+ *
+ * Return: IPC error code or 0 on success.
+ */
+int intel_punit_ipc_simple_command(int cmd, int para1, int para2)
+{
+ IPC_DEV *ipcdev = punit_ipcdev;
+ IPC_TYPE type;
+ u32 val;
+ int ret;
+
+ mutex_lock(&ipcdev->lock);
+
+ reinit_completion(&ipcdev->cmd_complete);
+ type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
+
+ val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
+ val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
+ ipc_write_cmd(ipcdev, type, val);
+ ret = intel_punit_ipc_check_status(ipcdev, type);
+
+ mutex_unlock(&ipcdev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(intel_punit_ipc_simple_command);
+
+/**
+ * intel_punit_ipc_command() - IPC command with data and pointers
+ * @cmd: IPC command code.
+ * @para1: First 8bit parameter, set 0 if not used.
+ * @para2: Second 8bit parameter, set 0 if not used.
+ * @in: Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD.
+ * @out: Output data.
+ *
+ * Send a IPC command to P-Unit with data transaction
+ *
+ * Return: IPC error code or 0 on success.
+ */
+int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out)
+{
+ IPC_DEV *ipcdev = punit_ipcdev;
+ IPC_TYPE type;
+ u32 val;
+ int ret;
+
+ mutex_lock(&ipcdev->lock);
+
+ reinit_completion(&ipcdev->cmd_complete);
+ type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
+
+ if (in) {
+ ipc_write_data_low(ipcdev, type, *in);
+ if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
+ ipc_write_data_high(ipcdev, type, *++in);
+ }
+
+ val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
+ val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
+ ipc_write_cmd(ipcdev, type, val);
+
+ ret = intel_punit_ipc_check_status(ipcdev, type);
+ if (ret)
+ goto out;
+
+ if (out) {
+ *out = ipc_read_data_low(ipcdev, type);
+ if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
+ *++out = ipc_read_data_high(ipcdev, type);
+ }
+
+out:
+ mutex_unlock(&ipcdev->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(intel_punit_ipc_command);
+
+static irqreturn_t intel_punit_ioc(int irq, void *dev_id)
+{
+ IPC_DEV *ipcdev = dev_id;
+
+ complete(&ipcdev->cmd_complete);
+ return IRQ_HANDLED;
+}
+
+static int intel_punit_get_bars(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+ punit_ipcdev->base[BIOS_IPC][BASE_DATA] = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+ punit_ipcdev->base[BIOS_IPC][BASE_IFACE] = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+ punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+ punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+ punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+ punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
+
+ return 0;
+}
+
+static int intel_punit_ipc_probe(struct platform_device *pdev)
+{
+ int irq, ret;
+
+ punit_ipcdev = devm_kzalloc(&pdev->dev,
+ sizeof(*punit_ipcdev), GFP_KERNEL);
+ if (!punit_ipcdev)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, punit_ipcdev);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ punit_ipcdev->irq = 0;
+ dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n");
+ } else {
+ ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc,
+ IRQF_NO_SUSPEND, "intel_punit_ipc",
+ &punit_ipcdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", irq);
+ return ret;
+ }
+ punit_ipcdev->irq = irq;
+ }
+
+ ret = intel_punit_get_bars(pdev);
+ if (ret)
+ goto out;
+
+ punit_ipcdev->dev = &pdev->dev;
+ mutex_init(&punit_ipcdev->lock);
+ init_completion(&punit_ipcdev->cmd_complete);
+
+out:
+ return ret;
+}
+
+static int intel_punit_ipc_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct acpi_device_id punit_ipc_acpi_ids[] = {
+ { "INT34D4", 0 },
+ { }
+};
+
+static struct platform_driver intel_punit_ipc_driver = {
+ .probe = intel_punit_ipc_probe,
+ .remove = intel_punit_ipc_remove,
+ .driver = {
+ .name = "intel_punit_ipc",
+ .acpi_match_table = ACPI_PTR(punit_ipc_acpi_ids),
+ },
+};
+
+static int __init intel_punit_ipc_init(void)
+{
+ return platform_driver_register(&intel_punit_ipc_driver);
+}
+
+static void __exit intel_punit_ipc_exit(void)
+{
+ platform_driver_unregister(&intel_punit_ipc_driver);
+}
+
+MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
+MODULE_DESCRIPTION("Intel P-Unit IPC driver");
+MODULE_LICENSE("GPL v2");
+
+/* Some modules are dependent on this, so init earlier */
+fs_initcall(intel_punit_ipc_init);
+module_exit(intel_punit_ipc_exit);
diff --git a/drivers/platform/x86/intel_telemetry_core.c b/drivers/platform/x86/intel_telemetry_core.c
new file mode 100644
index 000000000000..a695a436a1c3
--- /dev/null
+++ b/drivers/platform/x86/intel_telemetry_core.c
@@ -0,0 +1,464 @@
+/*
+ * Intel SoC Core Telemetry Driver
+ * Copyright (C) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * Telemetry Framework provides platform related PM and performance statistics.
+ * This file provides the core telemetry API implementation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/intel_telemetry.h>
+
+#define DRIVER_NAME "intel_telemetry_core"
+
+struct telemetry_core_config {
+ struct telemetry_plt_config *plt_config;
+ struct telemetry_core_ops *telem_ops;
+};
+
+static struct telemetry_core_config telm_core_conf;
+
+static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig,
+ struct telemetry_evtconfig ioss_evtconfig)
+{
+ return 0;
+}
+
+static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period)
+{
+ return 0;
+}
+
+static int telemetry_def_get_sampling_period(u8 *pss_min_period,
+ u8 *pss_max_period,
+ u8 *ioss_min_period,
+ u8 *ioss_max_period)
+{
+ return 0;
+}
+
+static int telemetry_def_get_eventconfig(
+ struct telemetry_evtconfig *pss_evtconfig,
+ struct telemetry_evtconfig *ioss_evtconfig,
+ int pss_len, int ioss_len)
+{
+ return 0;
+}
+
+static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 *verbosity)
+{
+ return 0;
+}
+
+
+static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 verbosity)
+{
+ return 0;
+}
+
+static int telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog,
+ int len, int log_all_evts)
+{
+ return 0;
+}
+
+static int telemetry_def_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog,
+ int len, int log_all_evts)
+{
+ return 0;
+}
+
+static int telemetry_def_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+ u32 *pss_evtmap, u32 *ioss_evtmap)
+{
+ return 0;
+}
+
+static int telemetry_def_reset_events(void)
+{
+ return 0;
+}
+
+static struct telemetry_core_ops telm_defpltops = {
+ .set_sampling_period = telemetry_def_set_sampling_period,
+ .get_sampling_period = telemetry_def_get_sampling_period,
+ .get_trace_verbosity = telemetry_def_get_trace_verbosity,
+ .set_trace_verbosity = telemetry_def_set_trace_verbosity,
+ .raw_read_eventlog = telemetry_def_raw_read_eventlog,
+ .get_eventconfig = telemetry_def_get_eventconfig,
+ .read_eventlog = telemetry_def_read_eventlog,
+ .update_events = telemetry_def_update_events,
+ .reset_events = telemetry_def_reset_events,
+ .add_events = telemetry_def_add_events,
+};
+
+/**
+ * telemetry_update_events() - Update telemetry Configuration
+ * @pss_evtconfig: PSS related config. No change if num_evts = 0.
+ * @pss_evtconfig: IOSS related config. No change if num_evts = 0.
+ *
+ * This API updates the IOSS & PSS Telemetry configuration. Old config
+ * is overwritten. Call telemetry_reset_events when logging is over
+ * All sample period values should be in the form of:
+ * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig,
+ struct telemetry_evtconfig ioss_evtconfig)
+{
+ return telm_core_conf.telem_ops->update_events(pss_evtconfig,
+ ioss_evtconfig);
+}
+EXPORT_SYMBOL_GPL(telemetry_update_events);
+
+
+/**
+ * telemetry_set_sampling_period() - Sets the IOSS & PSS sampling period
+ * @pss_period: placeholder for PSS Period to be set.
+ * Set to 0 if not required to be updated
+ * @ioss_period: placeholder for IOSS Period to be set
+ * Set to 0 if not required to be updated
+ *
+ * All values should be in the form of:
+ * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period)
+{
+ return telm_core_conf.telem_ops->set_sampling_period(pss_period,
+ ioss_period);
+}
+EXPORT_SYMBOL_GPL(telemetry_set_sampling_period);
+
+/**
+ * telemetry_get_sampling_period() - Get IOSS & PSS min & max sampling period
+ * @pss_min_period: placeholder for PSS Min Period supported
+ * @pss_max_period: placeholder for PSS Max Period supported
+ * @ioss_min_period: placeholder for IOSS Min Period supported
+ * @ioss_max_period: placeholder for IOSS Max Period supported
+ *
+ * All values should be in the form of:
+ * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period,
+ u8 *ioss_min_period, u8 *ioss_max_period)
+{
+ return telm_core_conf.telem_ops->get_sampling_period(pss_min_period,
+ pss_max_period,
+ ioss_min_period,
+ ioss_max_period);
+}
+EXPORT_SYMBOL_GPL(telemetry_get_sampling_period);
+
+
+/**
+ * telemetry_reset_events() - Restore the IOSS & PSS configuration to default
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_reset_events(void)
+{
+ return telm_core_conf.telem_ops->reset_events();
+}
+EXPORT_SYMBOL_GPL(telemetry_reset_events);
+
+/**
+ * telemetry_get_eventconfig() - Returns the pss and ioss events enabled
+ * @pss_evtconfig: Pointer to PSS related configuration.
+ * @pss_evtconfig: Pointer to IOSS related configuration.
+ * @pss_len: Number of u32 elements allocated for pss_evtconfig array
+ * @ioss_len: Number of u32 elements allocated for ioss_evtconfig array
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_evtconfig,
+ struct telemetry_evtconfig *ioss_evtconfig,
+ int pss_len, int ioss_len)
+{
+ return telm_core_conf.telem_ops->get_eventconfig(pss_evtconfig,
+ ioss_evtconfig,
+ pss_len, ioss_len);
+}
+EXPORT_SYMBOL_GPL(telemetry_get_eventconfig);
+
+/**
+ * telemetry_add_events() - Add IOSS & PSS configuration to existing settings.
+ * @num_pss_evts: Number of PSS Events (<29) in pss_evtmap. Can be 0.
+ * @num_ioss_evts: Number of IOSS Events (<29) in ioss_evtmap. Can be 0.
+ * @pss_evtmap: Array of PSS Event-IDs to Enable
+ * @ioss_evtmap: Array of PSS Event-IDs to Enable
+ *
+ * Events are appended to Old Configuration. In case of total events > 28, it
+ * returns error. Call telemetry_reset_events to reset after eventlog done
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+ u32 *pss_evtmap, u32 *ioss_evtmap)
+{
+ return telm_core_conf.telem_ops->add_events(num_pss_evts,
+ num_ioss_evts, pss_evtmap,
+ ioss_evtmap);
+}
+EXPORT_SYMBOL_GPL(telemetry_add_events);
+
+/**
+ * telemetry_read_events() - Fetches samples as specified by evtlog.telem_evt_id
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog: Array of telemetry_evtlog structs to fill data
+ * evtlog.telem_evt_id specifies the ids to read
+ * @len: Length of array of evtlog
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_read_events(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len)
+{
+ return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog,
+ len, 0);
+}
+EXPORT_SYMBOL_GPL(telemetry_read_events);
+
+/**
+ * telemetry_raw_read_events() - Fetch samples specified by evtlog.telem_evt_id
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog: Array of telemetry_evtlog structs to fill data
+ * evtlog.telem_evt_id specifies the ids to read
+ * @len: Length of array of evtlog
+ *
+ * The caller must take care of locking in this case.
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_raw_read_events(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len)
+{
+ return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog,
+ len, 0);
+}
+EXPORT_SYMBOL_GPL(telemetry_raw_read_events);
+
+/**
+ * telemetry_read_eventlog() - Fetch the Telemetry log from PSS or IOSS
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog: Array of telemetry_evtlog structs to fill data
+ * @len: Length of array of evtlog
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len)
+{
+ return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog,
+ len, 1);
+}
+EXPORT_SYMBOL_GPL(telemetry_read_eventlog);
+
+/**
+ * telemetry_raw_read_eventlog() - Fetch the Telemetry log from PSS or IOSS
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @evtlog: Array of telemetry_evtlog structs to fill data
+ * @len: Length of array of evtlog
+ *
+ * The caller must take care of locking in this case.
+ *
+ * Return: number of eventlogs read for success, < 0 for failure
+ */
+int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len)
+{
+ return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog,
+ len, 1);
+}
+EXPORT_SYMBOL_GPL(telemetry_raw_read_eventlog);
+
+
+/**
+ * telemetry_get_trace_verbosity() - Get the IOSS & PSS Trace verbosity
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @verbosity: Pointer to return Verbosity
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 *verbosity)
+{
+ return telm_core_conf.telem_ops->get_trace_verbosity(telem_unit,
+ verbosity);
+}
+EXPORT_SYMBOL_GPL(telemetry_get_trace_verbosity);
+
+
+/**
+ * telemetry_set_trace_verbosity() - Update the IOSS & PSS Trace verbosity
+ * @telem_unit: Specify whether IOSS or PSS Read
+ * @verbosity: Verbosity to set
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, u32 verbosity)
+{
+ return telm_core_conf.telem_ops->set_trace_verbosity(telem_unit,
+ verbosity);
+}
+EXPORT_SYMBOL_GPL(telemetry_set_trace_verbosity);
+
+/**
+ * telemetry_set_pltdata() - Set the platform specific Data
+ * @ops: Pointer to ops structure
+ * @pltconfig: Platform config data
+ *
+ * Usage by other than telemetry pltdrv module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_set_pltdata(struct telemetry_core_ops *ops,
+ struct telemetry_plt_config *pltconfig)
+{
+ if (ops)
+ telm_core_conf.telem_ops = ops;
+
+ if (pltconfig)
+ telm_core_conf.plt_config = pltconfig;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(telemetry_set_pltdata);
+
+/**
+ * telemetry_clear_pltdata() - Clear the platform specific Data
+ *
+ * Usage by other than telemetry pltdrv module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_clear_pltdata(void)
+{
+ telm_core_conf.telem_ops = &telm_defpltops;
+ telm_core_conf.plt_config = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(telemetry_clear_pltdata);
+
+/**
+ * telemetry_pltconfig_valid() - Checkif platform config is valid
+ *
+ * Usage by other than telemetry module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_pltconfig_valid(void)
+{
+ if (telm_core_conf.plt_config)
+ return 0;
+
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(telemetry_pltconfig_valid);
+
+static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit,
+ const char **name, int len)
+{
+ struct telemetry_unit_config psscfg;
+ int i;
+
+ if (!telm_core_conf.plt_config)
+ return -EINVAL;
+
+ psscfg = telm_core_conf.plt_config->pss_config;
+
+ if (len > psscfg.ssram_evts_used)
+ len = psscfg.ssram_evts_used;
+
+ for (i = 0; i < len; i++)
+ name[i] = psscfg.telem_evts[i].name;
+
+ return 0;
+}
+
+static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit,
+ const char **name, int len)
+{
+ struct telemetry_unit_config iosscfg;
+ int i;
+
+ if (!(telm_core_conf.plt_config))
+ return -EINVAL;
+
+ iosscfg = telm_core_conf.plt_config->ioss_config;
+
+ if (len > iosscfg.ssram_evts_used)
+ len = iosscfg.ssram_evts_used;
+
+ for (i = 0; i < len; i++)
+ name[i] = iosscfg.telem_evts[i].name;
+
+ return 0;
+
+}
+
+/**
+ * telemetry_get_evtname() - Checkif platform config is valid
+ * @telem_unit: Telemetry Unit to check
+ * @name: Array of character pointers to contain name
+ * @len: length of array name provided by user
+ *
+ * Usage by other than telemetry debugfs module is invalid
+ *
+ * Return: 0 success, < 0 for failure
+ */
+int telemetry_get_evtname(enum telemetry_unit telem_unit,
+ const char **name, int len)
+{
+ int ret = -EINVAL;
+
+ if (telem_unit == TELEM_PSS)
+ ret = telemetry_get_pssevtname(telem_unit, name, len);
+
+ else if (telem_unit == TELEM_IOSS)
+ ret = telemetry_get_iossevtname(telem_unit, name, len);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(telemetry_get_evtname);
+
+static int __init telemetry_module_init(void)
+{
+ pr_info(pr_fmt(DRIVER_NAME) " Init\n");
+
+ telm_core_conf.telem_ops = &telm_defpltops;
+ return 0;
+}
+
+static void __exit telemetry_module_exit(void)
+{
+}
+
+module_init(telemetry_module_init);
+module_exit(telemetry_module_exit);
+
+MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
+MODULE_DESCRIPTION("Intel SoC Telemetry Interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
new file mode 100644
index 000000000000..5b31d1548c07
--- /dev/null
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -0,0 +1,1030 @@
+/*
+ * Intel SOC Telemetry debugfs Driver: Currently supports APL
+ * Copyright (c) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * This file provides the debugfs interfaces for telemetry.
+ * /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters
+ * /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters
+ * /sys/kernel/debug/telemetry/soc_states: Shows SoC State
+ * /sys/kernel/debug/telemetry/pss_trace_verbosity: Read and Change Tracing
+ * Verbosity via firmware
+ * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing
+ * Verbosity via firmware
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/pci.h>
+#include <linux/suspend.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel_pmc_ipc.h>
+#include <asm/intel_punit_ipc.h>
+#include <asm/intel_telemetry.h>
+
+#define DRIVER_NAME "telemetry_soc_debugfs"
+#define DRIVER_VERSION "1.0.0"
+
+/* ApolloLake SoC Event-IDs */
+#define TELEM_APL_PSS_PSTATES_ID 0x2802
+#define TELEM_APL_PSS_IDLE_ID 0x2806
+#define TELEM_APL_PCS_IDLE_BLOCKED_ID 0x2C00
+#define TELEM_APL_PCS_S0IX_BLOCKED_ID 0x2C01
+#define TELEM_APL_PSS_WAKEUP_ID 0x2C02
+#define TELEM_APL_PSS_LTR_BLOCKING_ID 0x2C03
+
+#define TELEM_APL_S0IX_TOTAL_OCC_ID 0x4000
+#define TELEM_APL_S0IX_SHLW_OCC_ID 0x4001
+#define TELEM_APL_S0IX_DEEP_OCC_ID 0x4002
+#define TELEM_APL_S0IX_TOTAL_RES_ID 0x4800
+#define TELEM_APL_S0IX_SHLW_RES_ID 0x4801
+#define TELEM_APL_S0IX_DEEP_RES_ID 0x4802
+#define TELEM_APL_D0IX_ID 0x581A
+#define TELEM_APL_D3_ID 0x5819
+#define TELEM_APL_PG_ID 0x5818
+
+#define TELEM_INFO_SRAMEVTS_MASK 0xFF00
+#define TELEM_INFO_SRAMEVTS_SHIFT 0x8
+#define TELEM_SSRAM_READ_TIMEOUT 10
+
+#define TELEM_MASK_BIT 1
+#define TELEM_MASK_BYTE 0xFF
+#define BYTES_PER_LONG 8
+#define TELEM_APL_MASK_PCS_STATE 0xF
+
+/* Max events in bitmap to check for */
+#define TELEM_PSS_IDLE_EVTS 25
+#define TELEM_PSS_IDLE_BLOCKED_EVTS 20
+#define TELEM_PSS_S0IX_BLOCKED_EVTS 20
+#define TELEM_PSS_S0IX_WAKEUP_EVTS 20
+#define TELEM_PSS_LTR_BLOCKING_EVTS 20
+#define TELEM_IOSS_DX_D0IX_EVTS 25
+#define TELEM_IOSS_PG_EVTS 30
+
+#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0]))
+
+#define TELEM_DEBUGFS_CPU(model, data) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data}
+
+#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \
+ if (evtlog[index].telem_evtid == (EVTID)) { \
+ for (idx = 0; idx < (EVTNUM); idx++) \
+ (BUF)[idx] = ((EVTLOG) >> (EVTDAT)[idx].bit_pos) & \
+ (MASK); \
+ continue; \
+ } \
+}
+
+#define TELEM_CHECK_AND_PARSE_CTRS(EVTID, CTR) { \
+ if (evtlog[index].telem_evtid == (EVTID)) { \
+ (CTR) = evtlog[index].telem_evtlog; \
+ continue; \
+ } \
+}
+
+static u8 suspend_prep_ok;
+static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp;
+static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
+
+struct telemetry_susp_stats {
+ u32 shlw_swake_ctr;
+ u32 deep_swake_ctr;
+ u64 shlw_swake_res;
+ u64 deep_swake_res;
+ u32 shlw_ctr;
+ u32 deep_ctr;
+ u64 shlw_res;
+ u64 deep_res;
+};
+
+/* Bitmap definitions for default counters in APL */
+struct telem_pss_idle_stateinfo {
+ const char *name;
+ u32 bit_pos;
+};
+
+static struct telem_pss_idle_stateinfo telem_apl_pss_idle_data[] = {
+ {"IA_CORE0_C1E", 0},
+ {"IA_CORE1_C1E", 1},
+ {"IA_CORE2_C1E", 2},
+ {"IA_CORE3_C1E", 3},
+ {"IA_CORE0_C6", 16},
+ {"IA_CORE1_C6", 17},
+ {"IA_CORE2_C6", 18},
+ {"IA_CORE3_C6", 19},
+ {"IA_MODULE0_C7", 32},
+ {"IA_MODULE1_C7", 33},
+ {"GT_RC6", 40},
+ {"IUNIT_PROCESSING_IDLE", 41},
+ {"FAR_MEM_IDLE", 43},
+ {"DISPLAY_IDLE", 44},
+ {"IUNIT_INPUT_SYSTEM_IDLE", 45},
+ {"PCS_STATUS", 60},
+};
+
+struct telem_pcs_blkd_info {
+ const char *name;
+ u32 bit_pos;
+};
+
+static struct telem_pcs_blkd_info telem_apl_pcs_idle_blkd_data[] = {
+ {"COMPUTE", 0},
+ {"MISC", 8},
+ {"MODULE_ACTIONS_PENDING", 16},
+ {"LTR", 24},
+ {"DISPLAY_WAKE", 32},
+ {"ISP_WAKE", 40},
+ {"PSF0_ACTIVE", 48},
+};
+
+static struct telem_pcs_blkd_info telem_apl_pcs_s0ix_blkd_data[] = {
+ {"LTR", 0},
+ {"IRTL", 8},
+ {"WAKE_DEADLINE_PENDING", 16},
+ {"DISPLAY", 24},
+ {"ISP", 32},
+ {"CORE", 40},
+ {"PMC", 48},
+ {"MISC", 56},
+};
+
+struct telem_pss_ltr_info {
+ const char *name;
+ u32 bit_pos;
+};
+
+static struct telem_pss_ltr_info telem_apl_pss_ltr_data[] = {
+ {"CORE_ACTIVE", 0},
+ {"MEM_UP", 8},
+ {"DFX", 16},
+ {"DFX_FORCE_LTR", 24},
+ {"DISPLAY", 32},
+ {"ISP", 40},
+ {"SOUTH", 48},
+};
+
+struct telem_pss_wakeup_info {
+ const char *name;
+ u32 bit_pos;
+};
+
+static struct telem_pss_wakeup_info telem_apl_pss_wakeup[] = {
+ {"IP_IDLE", 0},
+ {"DISPLAY_WAKE", 8},
+ {"VOLTAGE_REG_INT", 16},
+ {"DROWSY_TIMER (HOTPLUG)", 24},
+ {"CORE_WAKE", 32},
+ {"MISC_S0IX", 40},
+ {"MISC_ABORT", 56},
+};
+
+struct telem_ioss_d0ix_stateinfo {
+ const char *name;
+ u32 bit_pos;
+};
+
+static struct telem_ioss_d0ix_stateinfo telem_apl_ioss_d0ix_data[] = {
+ {"CSE", 0},
+ {"SCC2", 1},
+ {"GMM", 2},
+ {"XDCI", 3},
+ {"XHCI", 4},
+ {"ISH", 5},
+ {"AVS", 6},
+ {"PCIE0P1", 7},
+ {"PECI0P0", 8},
+ {"LPSS", 9},
+ {"SCC", 10},
+ {"PWM", 11},
+ {"PCIE1_P3", 12},
+ {"PCIE1_P2", 13},
+ {"PCIE1_P1", 14},
+ {"PCIE1_P0", 15},
+ {"CNV", 16},
+ {"SATA", 17},
+ {"PRTC", 18},
+};
+
+struct telem_ioss_pg_info {
+ const char *name;
+ u32 bit_pos;
+};
+
+static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = {
+ {"LPSS", 0},
+ {"SCC", 1},
+ {"P2SB", 2},
+ {"SCC2", 3},
+ {"GMM", 4},
+ {"PCIE0", 5},
+ {"XDCI", 6},
+ {"xHCI", 7},
+ {"CSE", 8},
+ {"SPI", 9},
+ {"AVSPGD4", 10},
+ {"AVSPGD3", 11},
+ {"AVSPGD2", 12},
+ {"AVSPGD1", 13},
+ {"ISH", 14},
+ {"EXI", 15},
+ {"NPKVRC", 16},
+ {"NPKVNN", 17},
+ {"CUNIT", 18},
+ {"FUSE_CTRL", 19},
+ {"PCIE1", 20},
+ {"CNV", 21},
+ {"LPC", 22},
+ {"SATA", 23},
+ {"SMB", 24},
+ {"PRTC", 25},
+};
+
+
+struct telemetry_debugfs_conf {
+ struct telemetry_susp_stats suspend_stats;
+ struct dentry *telemetry_dbg_dir;
+
+ /* Bitmap Data */
+ struct telem_ioss_d0ix_stateinfo *ioss_d0ix_data;
+ struct telem_pss_idle_stateinfo *pss_idle_data;
+ struct telem_pcs_blkd_info *pcs_idle_blkd_data;
+ struct telem_pcs_blkd_info *pcs_s0ix_blkd_data;
+ struct telem_pss_wakeup_info *pss_wakeup;
+ struct telem_pss_ltr_info *pss_ltr_data;
+ struct telem_ioss_pg_info *ioss_pg_data;
+ u8 pcs_idle_blkd_evts;
+ u8 pcs_s0ix_blkd_evts;
+ u8 pss_wakeup_evts;
+ u8 pss_idle_evts;
+ u8 pss_ltr_evts;
+ u8 ioss_d0ix_evts;
+ u8 ioss_pg_evts;
+
+ /* IDs */
+ u16 pss_ltr_blocking_id;
+ u16 pcs_idle_blkd_id;
+ u16 pcs_s0ix_blkd_id;
+ u16 s0ix_total_occ_id;
+ u16 s0ix_shlw_occ_id;
+ u16 s0ix_deep_occ_id;
+ u16 s0ix_total_res_id;
+ u16 s0ix_shlw_res_id;
+ u16 s0ix_deep_res_id;
+ u16 pss_wakeup_id;
+ u16 ioss_d0ix_id;
+ u16 pstates_id;
+ u16 pss_idle_id;
+ u16 ioss_d3_id;
+ u16 ioss_pg_id;
+};
+
+static struct telemetry_debugfs_conf *debugfs_conf;
+
+static struct telemetry_debugfs_conf telem_apl_debugfs_conf = {
+ .pss_idle_data = telem_apl_pss_idle_data,
+ .pcs_idle_blkd_data = telem_apl_pcs_idle_blkd_data,
+ .pcs_s0ix_blkd_data = telem_apl_pcs_s0ix_blkd_data,
+ .pss_ltr_data = telem_apl_pss_ltr_data,
+ .pss_wakeup = telem_apl_pss_wakeup,
+ .ioss_d0ix_data = telem_apl_ioss_d0ix_data,
+ .ioss_pg_data = telem_apl_ioss_pg_data,
+
+ .pss_idle_evts = TELEM_EVT_LEN(telem_apl_pss_idle_data),
+ .pcs_idle_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_idle_blkd_data),
+ .pcs_s0ix_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_s0ix_blkd_data),
+ .pss_ltr_evts = TELEM_EVT_LEN(telem_apl_pss_ltr_data),
+ .pss_wakeup_evts = TELEM_EVT_LEN(telem_apl_pss_wakeup),
+ .ioss_d0ix_evts = TELEM_EVT_LEN(telem_apl_ioss_d0ix_data),
+ .ioss_pg_evts = TELEM_EVT_LEN(telem_apl_ioss_pg_data),
+
+ .pstates_id = TELEM_APL_PSS_PSTATES_ID,
+ .pss_idle_id = TELEM_APL_PSS_IDLE_ID,
+ .pcs_idle_blkd_id = TELEM_APL_PCS_IDLE_BLOCKED_ID,
+ .pcs_s0ix_blkd_id = TELEM_APL_PCS_S0IX_BLOCKED_ID,
+ .pss_wakeup_id = TELEM_APL_PSS_WAKEUP_ID,
+ .pss_ltr_blocking_id = TELEM_APL_PSS_LTR_BLOCKING_ID,
+ .s0ix_total_occ_id = TELEM_APL_S0IX_TOTAL_OCC_ID,
+ .s0ix_shlw_occ_id = TELEM_APL_S0IX_SHLW_OCC_ID,
+ .s0ix_deep_occ_id = TELEM_APL_S0IX_DEEP_OCC_ID,
+ .s0ix_total_res_id = TELEM_APL_S0IX_TOTAL_RES_ID,
+ .s0ix_shlw_res_id = TELEM_APL_S0IX_SHLW_RES_ID,
+ .s0ix_deep_res_id = TELEM_APL_S0IX_DEEP_RES_ID,
+ .ioss_d0ix_id = TELEM_APL_D0IX_ID,
+ .ioss_d3_id = TELEM_APL_D3_ID,
+ .ioss_pg_id = TELEM_APL_PG_ID,
+};
+
+static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = {
+ TELEM_DEBUGFS_CPU(0x5c, telem_apl_debugfs_conf),
+ {}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids);
+
+static int telemetry_debugfs_check_evts(void)
+{
+ if ((debugfs_conf->pss_idle_evts > TELEM_PSS_IDLE_EVTS) ||
+ (debugfs_conf->pcs_idle_blkd_evts > TELEM_PSS_IDLE_BLOCKED_EVTS) ||
+ (debugfs_conf->pcs_s0ix_blkd_evts > TELEM_PSS_S0IX_BLOCKED_EVTS) ||
+ (debugfs_conf->pss_ltr_evts > TELEM_PSS_LTR_BLOCKING_EVTS) ||
+ (debugfs_conf->pss_wakeup_evts > TELEM_PSS_S0IX_WAKEUP_EVTS) ||
+ (debugfs_conf->ioss_d0ix_evts > TELEM_IOSS_DX_D0IX_EVTS) ||
+ (debugfs_conf->ioss_pg_evts > TELEM_IOSS_PG_EVTS))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int telem_pss_states_show(struct seq_file *s, void *unused)
+{
+ struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ struct telemetry_debugfs_conf *conf = debugfs_conf;
+ const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ u32 pcs_idle_blkd[TELEM_PSS_IDLE_BLOCKED_EVTS],
+ pcs_s0ix_blkd[TELEM_PSS_S0IX_BLOCKED_EVTS],
+ pss_s0ix_wakeup[TELEM_PSS_S0IX_WAKEUP_EVTS],
+ pss_ltr_blkd[TELEM_PSS_LTR_BLOCKING_EVTS],
+ pss_idle[TELEM_PSS_IDLE_EVTS];
+ int index, idx, ret, err = 0;
+ u64 pstates = 0;
+
+ ret = telemetry_read_eventlog(TELEM_PSS, evtlog,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (ret < 0)
+ return ret;
+
+ err = telemetry_get_evtname(TELEM_PSS, name,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (err < 0)
+ return err;
+
+ seq_puts(s, "\n----------------------------------------------------\n");
+ seq_puts(s, "\tPSS TELEM EVENTLOG (Residency = field/19.2 us\n");
+ seq_puts(s, "----------------------------------------------------\n");
+ for (index = 0; index < ret; index++) {
+ seq_printf(s, "%-32s %llu\n",
+ name[index], evtlog[index].telem_evtlog);
+
+ /* Fetch PSS IDLE State */
+ if (evtlog[index].telem_evtid == conf->pss_idle_id) {
+ pss_idle[conf->pss_idle_evts - 1] =
+ (evtlog[index].telem_evtlog >>
+ conf->pss_idle_data[conf->pss_idle_evts - 1].bit_pos) &
+ TELEM_APL_MASK_PCS_STATE;
+ }
+
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id,
+ conf->pss_idle_evts - 1,
+ pss_idle, evtlog[index].telem_evtlog,
+ conf->pss_idle_data, TELEM_MASK_BIT);
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_idle_blkd_id,
+ conf->pcs_idle_blkd_evts,
+ pcs_idle_blkd,
+ evtlog[index].telem_evtlog,
+ conf->pcs_idle_blkd_data,
+ TELEM_MASK_BYTE);
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->pcs_s0ix_blkd_id,
+ conf->pcs_s0ix_blkd_evts,
+ pcs_s0ix_blkd,
+ evtlog[index].telem_evtlog,
+ conf->pcs_s0ix_blkd_data,
+ TELEM_MASK_BYTE);
+
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id,
+ conf->pss_wakeup_evts,
+ pss_s0ix_wakeup,
+ evtlog[index].telem_evtlog,
+ conf->pss_wakeup, TELEM_MASK_BYTE);
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->pss_ltr_blocking_id,
+ conf->pss_ltr_evts, pss_ltr_blkd,
+ evtlog[index].telem_evtlog,
+ conf->pss_ltr_data, TELEM_MASK_BYTE);
+
+ if (evtlog[index].telem_evtid == debugfs_conf->pstates_id)
+ pstates = evtlog[index].telem_evtlog;
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "PStates\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Domain\t\t\t\tFreq(Mhz)\n");
+ seq_printf(s, " IA\t\t\t\t %llu\n GT\t\t\t\t %llu\n",
+ (pstates & TELEM_MASK_BYTE)*100,
+ ((pstates >> 8) & TELEM_MASK_BYTE)*50/3);
+
+ seq_printf(s, " IUNIT\t\t\t\t %llu\n SA\t\t\t\t %llu\n",
+ ((pstates >> 16) & TELEM_MASK_BYTE)*25,
+ ((pstates >> 24) & TELEM_MASK_BYTE)*50/3);
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "PSS IDLE Status\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Device\t\t\t\t\tIDLE\n");
+ for (index = 0; index < debugfs_conf->pss_idle_evts; index++) {
+ seq_printf(s, "%-32s\t%u\n",
+ debugfs_conf->pss_idle_data[index].name,
+ pss_idle[index]);
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "PSS Idle blkd Status (~1ms saturating bucket)\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Blocker\t\t\t\t\tCount\n");
+ for (index = 0; index < debugfs_conf->pcs_idle_blkd_evts; index++) {
+ seq_printf(s, "%-32s\t%u\n",
+ debugfs_conf->pcs_idle_blkd_data[index].name,
+ pcs_idle_blkd[index]);
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "PSS S0ix blkd Status (~1ms saturating bucket)\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Blocker\t\t\t\t\tCount\n");
+ for (index = 0; index < debugfs_conf->pcs_s0ix_blkd_evts; index++) {
+ seq_printf(s, "%-32s\t%u\n",
+ debugfs_conf->pcs_s0ix_blkd_data[index].name,
+ pcs_s0ix_blkd[index]);
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "LTR Blocking Status (~1ms saturating bucket)\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Blocker\t\t\t\t\tCount\n");
+ for (index = 0; index < debugfs_conf->pss_ltr_evts; index++) {
+ seq_printf(s, "%-32s\t%u\n",
+ debugfs_conf->pss_ltr_data[index].name,
+ pss_s0ix_wakeup[index]);
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "Wakes Status (~1ms saturating bucket)\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Wakes\t\t\t\t\tCount\n");
+ for (index = 0; index < debugfs_conf->pss_wakeup_evts; index++) {
+ seq_printf(s, "%-32s\t%u\n",
+ debugfs_conf->pss_wakeup[index].name,
+ pss_ltr_blkd[index]);
+ }
+
+ 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,
+};
+
+
+static int telem_ioss_states_show(struct seq_file *s, void *unused)
+{
+ struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ const char *name[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ int index, ret, err;
+
+ ret = telemetry_read_eventlog(TELEM_IOSS, evtlog,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (ret < 0)
+ return ret;
+
+ err = telemetry_get_evtname(TELEM_IOSS, name,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (err < 0)
+ return err;
+
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "\tI0SS TELEMETRY EVENTLOG\n");
+ seq_puts(s, "--------------------------------------\n");
+ for (index = 0; index < ret; index++) {
+ seq_printf(s, "%-32s 0x%llx\n",
+ name[index], evtlog[index].telem_evtlog);
+ }
+
+ 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,
+};
+
+static int telem_soc_states_show(struct seq_file *s, void *unused)
+{
+ u32 d3_sts[TELEM_IOSS_DX_D0IX_EVTS], d0ix_sts[TELEM_IOSS_DX_D0IX_EVTS];
+ u32 pg_sts[TELEM_IOSS_PG_EVTS], pss_idle[TELEM_PSS_IDLE_EVTS];
+ struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ u32 s0ix_total_ctr = 0, s0ix_shlw_ctr = 0, s0ix_deep_ctr = 0;
+ u64 s0ix_total_res = 0, s0ix_shlw_res = 0, s0ix_deep_res = 0;
+ struct telemetry_debugfs_conf *conf = debugfs_conf;
+ struct pci_dev *dev = NULL;
+ int index, idx, ret;
+ u32 d3_state;
+ u16 pmcsr;
+
+ ret = telemetry_read_eventlog(TELEM_IOSS, evtlog,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (ret < 0)
+ return ret;
+
+ for (index = 0; index < ret; index++) {
+ TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d3_id,
+ conf->ioss_d0ix_evts,
+ d3_sts, evtlog[index].telem_evtlog,
+ conf->ioss_d0ix_data,
+ TELEM_MASK_BIT);
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_pg_id, conf->ioss_pg_evts,
+ pg_sts, evtlog[index].telem_evtlog,
+ conf->ioss_pg_data, TELEM_MASK_BIT);
+
+ TELEM_CHECK_AND_PARSE_EVTS(conf->ioss_d0ix_id,
+ conf->ioss_d0ix_evts,
+ d0ix_sts, evtlog[index].telem_evtlog,
+ conf->ioss_d0ix_data,
+ TELEM_MASK_BIT);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_occ_id,
+ s0ix_total_ctr);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id,
+ s0ix_shlw_ctr);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id,
+ s0ix_deep_ctr);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_total_res_id,
+ s0ix_total_res);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id,
+ s0ix_shlw_res);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id,
+ s0ix_deep_res);
+ }
+
+ seq_puts(s, "\n---------------------------------------------------\n");
+ seq_puts(s, "S0IX Type\t\t\t Occurrence\t\t Residency(us)\n");
+ seq_puts(s, "---------------------------------------------------\n");
+
+ seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n",
+ s0ix_shlw_ctr -
+ conf->suspend_stats.shlw_ctr -
+ conf->suspend_stats.shlw_swake_ctr,
+ (u64)((s0ix_shlw_res -
+ conf->suspend_stats.shlw_res -
+ conf->suspend_stats.shlw_swake_res)*10/192));
+
+ seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n",
+ s0ix_deep_ctr -
+ conf->suspend_stats.deep_ctr -
+ conf->suspend_stats.deep_swake_ctr,
+ (u64)((s0ix_deep_res -
+ conf->suspend_stats.deep_res -
+ conf->suspend_stats.deep_swake_res)*10/192));
+
+ seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n",
+ conf->suspend_stats.shlw_ctr,
+ (u64)(conf->suspend_stats.shlw_res*10)/192);
+
+ seq_printf(s, "Suspend(With S0ixDeep)\t\t %10u\t %10llu\n",
+ conf->suspend_stats.deep_ctr,
+ (u64)(conf->suspend_stats.deep_res*10)/192);
+
+ seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n",
+ conf->suspend_stats.shlw_swake_ctr +
+ conf->suspend_stats.deep_swake_ctr,
+ (u64)((conf->suspend_stats.shlw_swake_res +
+ conf->suspend_stats.deep_swake_res)*10/192));
+
+ seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr,
+ (u64)(s0ix_total_res*10/192));
+ seq_puts(s, "\n-------------------------------------------------\n");
+ seq_puts(s, "\t\tDEVICE STATES\n");
+ seq_puts(s, "-------------------------------------------------\n");
+
+ for_each_pci_dev(dev) {
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ d3_state = ((pmcsr & PCI_PM_CTRL_STATE_MASK) ==
+ (__force int)PCI_D3hot) ? 1 : 0;
+
+ seq_printf(s, "pci %04x %04X %s %20.20s: ",
+ dev->vendor, dev->device, dev_name(&dev->dev),
+ dev_driver_string(&dev->dev));
+ seq_printf(s, " d3:%x\n", d3_state);
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "D3/D0i3 Status\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Block\t\t D3\t D0i3\n");
+ for (index = 0; index < conf->ioss_d0ix_evts; index++) {
+ seq_printf(s, "%-10s\t %u\t %u\n",
+ conf->ioss_d0ix_data[index].name,
+ d3_sts[index], d0ix_sts[index]);
+ }
+
+ seq_puts(s, "\n--------------------------------------\n");
+ seq_puts(s, "South Complex PowerGate Status\n");
+ seq_puts(s, "--------------------------------------\n");
+ seq_puts(s, "Device\t\t PG\n");
+ for (index = 0; index < conf->ioss_pg_evts; index++) {
+ seq_printf(s, "%-10s\t %u\n",
+ conf->ioss_pg_data[index].name,
+ pg_sts[index]);
+ }
+
+ evtlog->telem_evtid = conf->pss_idle_id;
+ ret = telemetry_read_events(TELEM_PSS, evtlog, 1);
+ if (ret < 0)
+ return ret;
+
+ seq_puts(s, "\n-----------------------------------------\n");
+ seq_puts(s, "North Idle Status\n");
+ seq_puts(s, "-----------------------------------------\n");
+ for (idx = 0; idx < conf->pss_idle_evts - 1; idx++) {
+ pss_idle[idx] = (evtlog->telem_evtlog >>
+ conf->pss_idle_data[idx].bit_pos) &
+ TELEM_MASK_BIT;
+ }
+
+ pss_idle[idx] = (evtlog->telem_evtlog >>
+ conf->pss_idle_data[idx].bit_pos) &
+ TELEM_APL_MASK_PCS_STATE;
+
+ for (index = 0; index < conf->pss_idle_evts; index++) {
+ seq_printf(s, "%-30s %u\n",
+ conf->pss_idle_data[index].name,
+ pss_idle[index]);
+ }
+
+ seq_puts(s, "\nPCS_STATUS Code\n");
+ seq_puts(s, "0:C0 1:C1 2:C1_DN_WT_DEV 3:C2 4:C2_WT_DE_MEM_UP\n");
+ seq_puts(s, "5:C2_WT_DE_MEM_DOWN 6:C2_UP_WT_DEV 7:C2_DN 8:C2_VOA\n");
+ seq_puts(s, "9:C2_VOA_UP 10:S0IX_PRE 11:S0IX\n");
+
+ 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,
+};
+
+static int telem_pss_trc_verb_show(struct seq_file *s, void *unused)
+{
+ u32 verbosity;
+ int err;
+
+ err = telemetry_get_trace_verbosity(TELEM_PSS, &verbosity);
+ if (err) {
+ pr_err("Get PSS Trace Verbosity Failed with Error %d\n", err);
+ return -EFAULT;
+ }
+
+ seq_printf(s, "PSS Trace Verbosity %u\n", verbosity);
+ return 0;
+}
+
+static ssize_t telem_pss_trc_verb_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ u32 verbosity;
+ int err;
+
+ if (kstrtou32_from_user(userbuf, count, 0, &verbosity))
+ return -EFAULT;
+
+ err = telemetry_set_trace_verbosity(TELEM_PSS, verbosity);
+ if (err) {
+ pr_err("Changing PSS Trace Verbosity Failed. Error %d\n", err);
+ count = err;
+ }
+
+ return count;
+}
+
+static int telem_pss_trc_verb_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, telem_pss_trc_verb_show, inode->i_private);
+}
+
+static const struct file_operations telem_pss_trc_verb_ops = {
+ .open = telem_pss_trc_verb_open,
+ .read = seq_read,
+ .write = telem_pss_trc_verb_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused)
+{
+ u32 verbosity;
+ int err;
+
+ err = telemetry_get_trace_verbosity(TELEM_IOSS, &verbosity);
+ if (err) {
+ pr_err("Get IOSS Trace Verbosity Failed with Error %d\n", err);
+ return -EFAULT;
+ }
+
+ seq_printf(s, "IOSS Trace Verbosity %u\n", verbosity);
+ return 0;
+}
+
+static ssize_t telem_ioss_trc_verb_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ u32 verbosity;
+ int err;
+
+ if (kstrtou32_from_user(userbuf, count, 0, &verbosity))
+ return -EFAULT;
+
+ err = telemetry_set_trace_verbosity(TELEM_IOSS, verbosity);
+ if (err) {
+ pr_err("Changing IOSS Trace Verbosity Failed. Error %d\n", err);
+ count = err;
+ }
+
+ return count;
+}
+
+static int telem_ioss_trc_verb_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, telem_ioss_trc_verb_show, inode->i_private);
+}
+
+static const struct file_operations telem_ioss_trc_verb_ops = {
+ .open = telem_ioss_trc_verb_open,
+ .read = seq_read,
+ .write = telem_ioss_trc_verb_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int pm_suspend_prep_cb(void)
+{
+ struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ struct telemetry_debugfs_conf *conf = debugfs_conf;
+ int ret, index;
+
+ ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (ret < 0) {
+ suspend_prep_ok = 0;
+ goto out;
+ }
+
+ for (index = 0; index < ret; index++) {
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id,
+ suspend_shlw_ctr_temp);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id,
+ suspend_deep_ctr_temp);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id,
+ suspend_shlw_res_temp);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id,
+ suspend_deep_res_temp);
+ }
+ suspend_prep_ok = 1;
+out:
+ return NOTIFY_OK;
+}
+
+static int pm_suspend_exit_cb(void)
+{
+ struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
+ static u32 suspend_shlw_ctr_exit, suspend_deep_ctr_exit;
+ static u64 suspend_shlw_res_exit, suspend_deep_res_exit;
+ struct telemetry_debugfs_conf *conf = debugfs_conf;
+ int ret, index;
+
+ if (!suspend_prep_ok)
+ goto out;
+
+ ret = telemetry_raw_read_eventlog(TELEM_IOSS, evtlog,
+ TELEM_MAX_OS_ALLOCATED_EVENTS);
+ if (ret < 0)
+ goto out;
+
+ for (index = 0; index < ret; index++) {
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_occ_id,
+ suspend_shlw_ctr_exit);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_occ_id,
+ suspend_deep_ctr_exit);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_shlw_res_id,
+ suspend_shlw_res_exit);
+
+ TELEM_CHECK_AND_PARSE_CTRS(conf->s0ix_deep_res_id,
+ suspend_deep_res_exit);
+ }
+
+ if ((suspend_shlw_ctr_exit < suspend_shlw_ctr_temp) ||
+ (suspend_deep_ctr_exit < suspend_deep_ctr_temp) ||
+ (suspend_shlw_res_exit < suspend_shlw_res_temp) ||
+ (suspend_deep_res_exit < suspend_deep_res_temp)) {
+ pr_err("Wrong s0ix counters detected\n");
+ goto out;
+ }
+
+ suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp;
+ suspend_deep_ctr_exit -= suspend_deep_ctr_temp;
+ suspend_shlw_res_exit -= suspend_shlw_res_temp;
+ suspend_deep_res_exit -= suspend_deep_res_temp;
+
+ if (suspend_shlw_ctr_exit == 1) {
+ conf->suspend_stats.shlw_ctr +=
+ suspend_shlw_ctr_exit;
+
+ conf->suspend_stats.shlw_res +=
+ suspend_shlw_res_exit;
+ }
+ /* Shallow Wakes Case */
+ else if (suspend_shlw_ctr_exit > 1) {
+ conf->suspend_stats.shlw_swake_ctr +=
+ suspend_shlw_ctr_exit;
+
+ conf->suspend_stats.shlw_swake_res +=
+ suspend_shlw_res_exit;
+ }
+
+ if (suspend_deep_ctr_exit == 1) {
+ conf->suspend_stats.deep_ctr +=
+ suspend_deep_ctr_exit;
+
+ conf->suspend_stats.deep_res +=
+ suspend_deep_res_exit;
+ }
+
+ /* Shallow Wakes Case */
+ else if (suspend_deep_ctr_exit > 1) {
+ conf->suspend_stats.deep_swake_ctr +=
+ suspend_deep_ctr_exit;
+
+ conf->suspend_stats.deep_swake_res +=
+ suspend_deep_res_exit;
+ }
+
+out:
+ suspend_prep_ok = 0;
+ return NOTIFY_OK;
+}
+
+static int pm_notification(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ return pm_suspend_prep_cb();
+ case PM_POST_SUSPEND:
+ return pm_suspend_exit_cb();
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block pm_notifier = {
+ .notifier_call = pm_notification,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static int __init telemetry_debugfs_init(void)
+{
+ const struct x86_cpu_id *id;
+ int err = -ENOMEM;
+ struct dentry *f;
+
+ /* Only APL supported for now */
+ id = x86_match_cpu(telemetry_debugfs_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ debugfs_conf = (struct telemetry_debugfs_conf *)id->driver_data;
+
+ err = telemetry_pltconfig_valid();
+ if (err < 0)
+ return -ENODEV;
+
+ err = telemetry_debugfs_check_evts();
+ if (err < 0)
+ return -EINVAL;
+
+
+#ifdef CONFIG_PM_SLEEP
+ register_pm_notifier(&pm_notifier);
+#endif /* CONFIG_PM_SLEEP */
+
+ debugfs_conf->telemetry_dbg_dir = debugfs_create_dir("telemetry", NULL);
+ if (!debugfs_conf->telemetry_dbg_dir)
+ return -ENOMEM;
+
+ f = debugfs_create_file("pss_info", S_IFREG | S_IRUGO,
+ debugfs_conf->telemetry_dbg_dir, NULL,
+ &telem_pss_ops);
+ if (!f) {
+ pr_err("pss_sample_info debugfs register failed\n");
+ goto out;
+ }
+
+ f = debugfs_create_file("ioss_info", S_IFREG | S_IRUGO,
+ debugfs_conf->telemetry_dbg_dir, NULL,
+ &telem_ioss_ops);
+ if (!f) {
+ pr_err("ioss_sample_info debugfs register failed\n");
+ goto out;
+ }
+
+ f = debugfs_create_file("soc_states", S_IFREG | S_IRUGO,
+ debugfs_conf->telemetry_dbg_dir,
+ NULL, &telem_socstate_ops);
+ if (!f) {
+ pr_err("ioss_sample_info debugfs register failed\n");
+ goto out;
+ }
+
+ f = debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO,
+ debugfs_conf->telemetry_dbg_dir, NULL,
+ &telem_pss_trc_verb_ops);
+ if (!f) {
+ pr_err("pss_trace_verbosity debugfs register failed\n");
+ goto out;
+ }
+
+ f = debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO,
+ debugfs_conf->telemetry_dbg_dir, NULL,
+ &telem_ioss_trc_verb_ops);
+ if (!f) {
+ pr_err("ioss_trace_verbosity debugfs register failed\n");
+ goto out;
+ }
+
+ return 0;
+
+out:
+ debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir);
+ debugfs_conf->telemetry_dbg_dir = NULL;
+
+ return err;
+}
+
+static void __exit telemetry_debugfs_exit(void)
+{
+ debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir);
+ debugfs_conf->telemetry_dbg_dir = NULL;
+}
+
+late_initcall(telemetry_debugfs_init);
+module_exit(telemetry_debugfs_exit);
+
+MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
+MODULE_DESCRIPTION("Intel SoC Telemetry debugfs Interface");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
new file mode 100644
index 000000000000..f97019b0106f
--- /dev/null
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -0,0 +1,1206 @@
+/*
+ * Intel SOC Telemetry Platform Driver: Currently supports APL
+ * Copyright (c) 2015, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * This file provides the platform specific telemetry implementation for APL.
+ * It used the PUNIT and PMC IPC interfaces for configuring the counters.
+ * The accumulated results are fetched from SRAM.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/pci.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel_pmc_ipc.h>
+#include <asm/intel_punit_ipc.h>
+#include <asm/intel_telemetry.h>
+
+#define DRIVER_NAME "intel_telemetry"
+#define DRIVER_VERSION "1.0.0"
+
+#define TELEM_TRC_VERBOSITY_MASK 0x3
+
+#define TELEM_MIN_PERIOD(x) ((x) & 0x7F0000)
+#define TELEM_MAX_PERIOD(x) ((x) & 0x7F000000)
+#define TELEM_SAMPLE_PERIOD_INVALID(x) ((x) & (BIT(7)))
+#define TELEM_CLEAR_SAMPLE_PERIOD(x) ((x) &= ~0x7F)
+
+#define TELEM_SAMPLING_DEFAULT_PERIOD 0xD
+
+#define TELEM_MAX_EVENTS_SRAM 28
+#define TELEM_MAX_OS_ALLOCATED_EVENTS 20
+#define TELEM_SSRAM_STARTTIME_OFFSET 8
+#define TELEM_SSRAM_EVTLOG_OFFSET 16
+
+#define IOSS_TELEM_EVENT_READ 0x0
+#define IOSS_TELEM_EVENT_WRITE 0x1
+#define IOSS_TELEM_INFO_READ 0x2
+#define IOSS_TELEM_TRACE_CTL_READ 0x5
+#define IOSS_TELEM_TRACE_CTL_WRITE 0x6
+#define IOSS_TELEM_EVENT_CTL_READ 0x7
+#define IOSS_TELEM_EVENT_CTL_WRITE 0x8
+#define IOSS_TELEM_EVT_CTRL_WRITE_SIZE 0x4
+#define IOSS_TELEM_READ_WORD 0x1
+#define IOSS_TELEM_WRITE_FOURBYTES 0x4
+#define IOSS_TELEM_EVT_WRITE_SIZE 0x3
+
+#define TELEM_INFO_SRAMEVTS_MASK 0xFF00
+#define TELEM_INFO_SRAMEVTS_SHIFT 0x8
+#define TELEM_SSRAM_READ_TIMEOUT 10
+
+#define TELEM_INFO_NENABLES_MASK 0xFF
+#define TELEM_EVENT_ENABLE 0x8000
+
+#define TELEM_MASK_BIT 1
+#define TELEM_MASK_BYTE 0xFF
+#define BYTES_PER_LONG 8
+#define TELEM_MASK_PCS_STATE 0xF
+
+#define TELEM_DISABLE(x) ((x) &= ~(BIT(31)))
+#define TELEM_CLEAR_EVENTS(x) ((x) |= (BIT(30)))
+#define TELEM_ENABLE_SRAM_EVT_TRACE(x) ((x) &= ~(BIT(30) | BIT(24)))
+#define TELEM_ENABLE_PERIODIC(x) ((x) |= (BIT(23) | BIT(31) | BIT(7)))
+#define TELEM_EXTRACT_VERBOSITY(x, y) ((y) = (((x) >> 27) & 0x3))
+#define TELEM_CLEAR_VERBOSITY_BITS(x) ((x) &= ~(BIT(27) | BIT(28)))
+#define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27))
+
+#define TELEM_CPU(model, data) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data }
+
+enum telemetry_action {
+ TELEM_UPDATE = 0,
+ TELEM_ADD,
+ TELEM_RESET,
+ TELEM_ACTION_NONE
+};
+
+struct telem_ssram_region {
+ u64 timestamp;
+ u64 start_time;
+ u64 events[TELEM_MAX_EVENTS_SRAM];
+};
+
+static struct telemetry_plt_config *telm_conf;
+
+/*
+ * The following counters are programmed by default during setup.
+ * Only 20 allocated to kernel driver
+ */
+static struct telemetry_evtmap
+ telemetry_apl_ioss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
+ {"SOC_S0IX_TOTAL_RES", 0x4800},
+ {"SOC_S0IX_TOTAL_OCC", 0x4000},
+ {"SOC_S0IX_SHALLOW_RES", 0x4801},
+ {"SOC_S0IX_SHALLOW_OCC", 0x4001},
+ {"SOC_S0IX_DEEP_RES", 0x4802},
+ {"SOC_S0IX_DEEP_OCC", 0x4002},
+ {"PMC_POWER_GATE", 0x5818},
+ {"PMC_D3_STATES", 0x5819},
+ {"PMC_D0I3_STATES", 0x581A},
+ {"PMC_S0IX_WAKE_REASON_GPIO", 0x6000},
+ {"PMC_S0IX_WAKE_REASON_TIMER", 0x6001},
+ {"PMC_S0IX_WAKE_REASON_VNNREQ", 0x6002},
+ {"PMC_S0IX_WAKE_REASON_LOWPOWER", 0x6003},
+ {"PMC_S0IX_WAKE_REASON_EXTERNAL", 0x6004},
+ {"PMC_S0IX_WAKE_REASON_MISC", 0x6005},
+ {"PMC_S0IX_BLOCKING_IPS_D3_D0I3", 0x6006},
+ {"PMC_S0IX_BLOCKING_IPS_PG", 0x6007},
+ {"PMC_S0IX_BLOCKING_MISC_IPS_PG", 0x6008},
+ {"PMC_S0IX_BLOCK_IPS_VNN_REQ", 0x6009},
+ {"PMC_S0IX_BLOCK_IPS_CLOCKS", 0x600B},
+};
+
+
+static struct telemetry_evtmap
+ telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
+ {"IA_CORE0_C6_RES", 0x0400},
+ {"IA_CORE0_C6_CTR", 0x0000},
+ {"IA_MODULE0_C7_RES", 0x0410},
+ {"IA_MODULE0_C7_CTR", 0x000E},
+ {"IA_C0_RES", 0x0805},
+ {"PCS_LTR", 0x2801},
+ {"PSTATES", 0x2802},
+ {"SOC_S0I3_RES", 0x0409},
+ {"SOC_S0I3_CTR", 0x000A},
+ {"PCS_S0I3_CTR", 0x0009},
+ {"PCS_C1E_RES", 0x041A},
+ {"PCS_IDLE_STATUS", 0x2806},
+ {"IA_PERF_LIMITS", 0x280B},
+ {"GT_PERF_LIMITS", 0x280C},
+ {"PCS_WAKEUP_S0IX_CTR", 0x0030},
+ {"PCS_IDLE_BLOCKED", 0x2C00},
+ {"PCS_S0IX_BLOCKED", 0x2C01},
+ {"PCS_S0IX_WAKE_REASONS", 0x2C02},
+ {"PCS_LTR_BLOCKING", 0x2C03},
+ {"PC2_AND_MEM_SHALLOW_IDLE_RES", 0x1D40},
+};
+
+/* APL specific Data */
+static struct telemetry_plt_config telem_apl_config = {
+ .pss_config = {
+ .telem_evts = telemetry_apl_pss_default_events,
+ },
+ .ioss_config = {
+ .telem_evts = telemetry_apl_ioss_default_events,
+ },
+};
+
+static const struct x86_cpu_id telemetry_cpu_ids[] = {
+ TELEM_CPU(0x5c, telem_apl_config),
+ {}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids);
+
+static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
+ struct telemetry_unit_config **unit_config)
+{
+ if (telem_unit == TELEM_PSS)
+ *unit_config = &(telm_conf->pss_config);
+ else if (telem_unit == TELEM_IOSS)
+ *unit_config = &(telm_conf->ioss_config);
+ else
+ return -EINVAL;
+
+ return 0;
+
+}
+
+static int telemetry_check_evtid(enum telemetry_unit telem_unit,
+ u32 *evtmap, u8 len,
+ enum telemetry_action action)
+{
+ struct telemetry_unit_config *unit_config;
+ int ret;
+
+ ret = telem_get_unitconfig(telem_unit, &unit_config);
+ if (ret < 0)
+ return ret;
+
+ switch (action) {
+ case TELEM_RESET:
+ if (len > TELEM_MAX_EVENTS_SRAM)
+ return -EINVAL;
+
+ break;
+
+ case TELEM_UPDATE:
+ if (len > TELEM_MAX_EVENTS_SRAM)
+ return -EINVAL;
+
+ if ((len > 0) && (evtmap == NULL))
+ return -EINVAL;
+
+ break;
+
+ case TELEM_ADD:
+ if ((len + unit_config->ssram_evts_used) >
+ TELEM_MAX_EVENTS_SRAM)
+ return -EINVAL;
+
+ if ((len > 0) && (evtmap == NULL))
+ return -EINVAL;
+
+ break;
+
+ default:
+ pr_err("Unknown Telemetry action Specified %d\n", action);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
+{
+ u32 write_buf;
+ int ret;
+
+ write_buf = evt_id | TELEM_EVENT_ENABLE;
+ write_buf <<= BITS_PER_BYTE;
+ write_buf |= index;
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf,
+ IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0);
+
+ return ret;
+}
+
+static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
+{
+ u32 write_buf;
+ int ret;
+
+ write_buf = evt_id | TELEM_EVENT_ENABLE;
+ ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
+ index, 0, &write_buf, NULL);
+
+ return ret;
+}
+
+static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
+ enum telemetry_action action)
+{
+ u8 num_ioss_evts, ioss_period;
+ int ret, index, idx;
+ u32 *ioss_evtmap;
+ u32 telem_ctrl;
+
+ num_ioss_evts = evtconfig.num_evts;
+ ioss_period = evtconfig.period;
+ ioss_evtmap = evtconfig.evtmap;
+
+ /* Get telemetry EVENT CTL */
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
+ &telem_ctrl, IOSS_TELEM_READ_WORD);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Read Failed\n");
+ return ret;
+ }
+
+ /* Disable Telemetry */
+ TELEM_DISABLE(telem_ctrl);
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_WRITE,
+ (u8 *)&telem_ctrl,
+ IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+ NULL, 0);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+ return ret;
+ }
+
+
+ /* Reset Everything */
+ if (action == TELEM_RESET) {
+ /* Clear All Events */
+ TELEM_CLEAR_EVENTS(telem_ctrl);
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_WRITE,
+ (u8 *)&telem_ctrl,
+ IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+ NULL, 0);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+ return ret;
+ }
+ telm_conf->ioss_config.ssram_evts_used = 0;
+
+ /* Configure Events */
+ for (idx = 0; idx < num_ioss_evts; idx++) {
+ if (telemetry_plt_config_ioss_event(
+ telm_conf->ioss_config.telem_evts[idx].evt_id,
+ idx)) {
+ pr_err("IOSS TELEM_RESET Fail for data: %x\n",
+ telm_conf->ioss_config.telem_evts[idx].evt_id);
+ continue;
+ }
+ telm_conf->ioss_config.ssram_evts_used++;
+ }
+ }
+
+ /* Re-Configure Everything */
+ if (action == TELEM_UPDATE) {
+ /* Clear All Events */
+ TELEM_CLEAR_EVENTS(telem_ctrl);
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_WRITE,
+ (u8 *)&telem_ctrl,
+ IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+ NULL, 0);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+ return ret;
+ }
+ telm_conf->ioss_config.ssram_evts_used = 0;
+
+ /* Configure Events */
+ for (index = 0; index < num_ioss_evts; index++) {
+ telm_conf->ioss_config.telem_evts[index].evt_id =
+ ioss_evtmap[index];
+
+ if (telemetry_plt_config_ioss_event(
+ telm_conf->ioss_config.telem_evts[index].evt_id,
+ index)) {
+ pr_err("IOSS TELEM_UPDATE Fail for Evt%x\n",
+ ioss_evtmap[index]);
+ continue;
+ }
+ telm_conf->ioss_config.ssram_evts_used++;
+ }
+ }
+
+ /* Add some Events */
+ if (action == TELEM_ADD) {
+ /* Configure Events */
+ for (index = telm_conf->ioss_config.ssram_evts_used, idx = 0;
+ idx < num_ioss_evts; index++, idx++) {
+ telm_conf->ioss_config.telem_evts[index].evt_id =
+ ioss_evtmap[idx];
+
+ if (telemetry_plt_config_ioss_event(
+ telm_conf->ioss_config.telem_evts[index].evt_id,
+ index)) {
+ pr_err("IOSS TELEM_ADD Fail for Event %x\n",
+ ioss_evtmap[idx]);
+ continue;
+ }
+ telm_conf->ioss_config.ssram_evts_used++;
+ }
+ }
+
+ /* Enable Periodic Telemetry Events and enable SRAM trace */
+ TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+ TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+ TELEM_ENABLE_PERIODIC(telem_ctrl);
+ telem_ctrl |= ioss_period;
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_WRITE,
+ (u8 *)&telem_ctrl,
+ IOSS_TELEM_EVT_CTRL_WRITE_SIZE, NULL, 0);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
+ return ret;
+ }
+
+ telm_conf->ioss_config.curr_period = ioss_period;
+
+ return 0;
+}
+
+
+static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
+ enum telemetry_action action)
+{
+ u8 num_pss_evts, pss_period;
+ int ret, index, idx;
+ u32 *pss_evtmap;
+ u32 telem_ctrl;
+
+ num_pss_evts = evtconfig.num_evts;
+ pss_period = evtconfig.period;
+ pss_evtmap = evtconfig.evtmap;
+
+ /* PSS Config */
+ /* Get telemetry EVENT CTL */
+ ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+ 0, 0, NULL, &telem_ctrl);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Read Failed\n");
+ return ret;
+ }
+
+ /* Disable Telemetry */
+ TELEM_DISABLE(telem_ctrl);
+ ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+ 0, 0, &telem_ctrl, NULL);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+ return ret;
+ }
+
+ /* Reset Everything */
+ if (action == TELEM_RESET) {
+ /* Clear All Events */
+ TELEM_CLEAR_EVENTS(telem_ctrl);
+
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+ 0, 0, &telem_ctrl, NULL);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+ return ret;
+ }
+ telm_conf->pss_config.ssram_evts_used = 0;
+ /* Configure Events */
+ for (idx = 0; idx < num_pss_evts; idx++) {
+ if (telemetry_plt_config_pss_event(
+ telm_conf->pss_config.telem_evts[idx].evt_id,
+ idx)) {
+ pr_err("PSS TELEM_RESET Fail for Event %x\n",
+ telm_conf->pss_config.telem_evts[idx].evt_id);
+ continue;
+ }
+ telm_conf->pss_config.ssram_evts_used++;
+ }
+ }
+
+ /* Re-Configure Everything */
+ if (action == TELEM_UPDATE) {
+ /* Clear All Events */
+ TELEM_CLEAR_EVENTS(telem_ctrl);
+
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+ 0, 0, &telem_ctrl, NULL);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+ return ret;
+ }
+ telm_conf->pss_config.ssram_evts_used = 0;
+
+ /* Configure Events */
+ for (index = 0; index < num_pss_evts; index++) {
+ telm_conf->pss_config.telem_evts[index].evt_id =
+ pss_evtmap[index];
+
+ if (telemetry_plt_config_pss_event(
+ telm_conf->pss_config.telem_evts[index].evt_id,
+ index)) {
+ pr_err("PSS TELEM_UPDATE Fail for Event %x\n",
+ pss_evtmap[index]);
+ continue;
+ }
+ telm_conf->pss_config.ssram_evts_used++;
+ }
+ }
+
+ /* Add some Events */
+ if (action == TELEM_ADD) {
+ /* Configure Events */
+ for (index = telm_conf->pss_config.ssram_evts_used, idx = 0;
+ idx < num_pss_evts; index++, idx++) {
+
+ telm_conf->pss_config.telem_evts[index].evt_id =
+ pss_evtmap[idx];
+
+ if (telemetry_plt_config_pss_event(
+ telm_conf->pss_config.telem_evts[index].evt_id,
+ index)) {
+ pr_err("PSS TELEM_ADD Fail for Event %x\n",
+ pss_evtmap[idx]);
+ continue;
+ }
+ telm_conf->pss_config.ssram_evts_used++;
+ }
+ }
+
+ /* Enable Periodic Telemetry Events and enable SRAM trace */
+ TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+ TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+ TELEM_ENABLE_PERIODIC(telem_ctrl);
+ telem_ctrl |= pss_period;
+
+ ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+ 0, 0, &telem_ctrl, NULL);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
+ return ret;
+ }
+
+ telm_conf->pss_config.curr_period = pss_period;
+
+ return 0;
+}
+
+static int telemetry_setup_evtconfig(struct telemetry_evtconfig pss_evtconfig,
+ struct telemetry_evtconfig ioss_evtconfig,
+ enum telemetry_action action)
+{
+ int ret;
+
+ mutex_lock(&(telm_conf->telem_lock));
+
+ if ((action == TELEM_UPDATE) && (telm_conf->telem_in_use)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = telemetry_check_evtid(TELEM_PSS, pss_evtconfig.evtmap,
+ pss_evtconfig.num_evts, action);
+ if (ret)
+ goto out;
+
+ ret = telemetry_check_evtid(TELEM_IOSS, ioss_evtconfig.evtmap,
+ ioss_evtconfig.num_evts, action);
+ if (ret)
+ goto out;
+
+ if (ioss_evtconfig.num_evts) {
+ ret = telemetry_setup_iossevtconfig(ioss_evtconfig, action);
+ if (ret)
+ goto out;
+ }
+
+ if (pss_evtconfig.num_evts) {
+ ret = telemetry_setup_pssevtconfig(pss_evtconfig, action);
+ if (ret)
+ goto out;
+ }
+
+ if ((action == TELEM_UPDATE) || (action == TELEM_ADD))
+ telm_conf->telem_in_use = true;
+ else
+ telm_conf->telem_in_use = false;
+
+out:
+ mutex_unlock(&(telm_conf->telem_lock));
+ return ret;
+}
+
+static int telemetry_setup(struct platform_device *pdev)
+{
+ struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig;
+ u32 read_buf, events, event_regs;
+ int ret;
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, IOSS_TELEM_INFO_READ,
+ NULL, 0, &read_buf, IOSS_TELEM_READ_WORD);
+ if (ret) {
+ dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n");
+ return ret;
+ }
+
+ /* Get telemetry Info */
+ events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >>
+ TELEM_INFO_SRAMEVTS_SHIFT;
+ event_regs = read_buf & TELEM_INFO_NENABLES_MASK;
+ if ((events < TELEM_MAX_EVENTS_SRAM) ||
+ (event_regs < TELEM_MAX_EVENTS_SRAM)) {
+ dev_err(&pdev->dev, "IOSS:Insufficient Space for SRAM Trace\n");
+ dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n",
+ events, event_regs);
+ return -ENOMEM;
+ }
+
+ telm_conf->ioss_config.min_period = TELEM_MIN_PERIOD(read_buf);
+ telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf);
+
+ /* PUNIT Mailbox Setup */
+ ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0,
+ NULL, &read_buf);
+ if (ret) {
+ dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n");
+ return ret;
+ }
+
+ /* Get telemetry Info */
+ events = (read_buf & TELEM_INFO_SRAMEVTS_MASK) >>
+ TELEM_INFO_SRAMEVTS_SHIFT;
+ event_regs = read_buf & TELEM_INFO_SRAMEVTS_MASK;
+ if ((events < TELEM_MAX_EVENTS_SRAM) ||
+ (event_regs < TELEM_MAX_EVENTS_SRAM)) {
+ dev_err(&pdev->dev, "PSS:Insufficient Space for SRAM Trace\n");
+ dev_err(&pdev->dev, "SRAM Events %d; Event Regs %d\n",
+ events, event_regs);
+ return -ENOMEM;
+ }
+
+ telm_conf->pss_config.min_period = TELEM_MIN_PERIOD(read_buf);
+ telm_conf->pss_config.max_period = TELEM_MAX_PERIOD(read_buf);
+
+ pss_evtconfig.evtmap = NULL;
+ pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+ pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+ ioss_evtconfig.evtmap = NULL;
+ ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+ ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+ ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+ TELEM_RESET);
+ if (ret) {
+ dev_err(&pdev->dev, "TELEMTRY Setup Failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig,
+ struct telemetry_evtconfig ioss_evtconfig)
+{
+ int ret;
+
+ if ((pss_evtconfig.num_evts > 0) &&
+ (TELEM_SAMPLE_PERIOD_INVALID(pss_evtconfig.period))) {
+ pr_err("PSS Sampling Period Out of Range\n");
+ return -EINVAL;
+ }
+
+ if ((ioss_evtconfig.num_evts > 0) &&
+ (TELEM_SAMPLE_PERIOD_INVALID(ioss_evtconfig.period))) {
+ pr_err("IOSS Sampling Period Out of Range\n");
+ return -EINVAL;
+ }
+
+ ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+ TELEM_UPDATE);
+ if (ret)
+ pr_err("TELEMTRY Config Failed\n");
+
+ return ret;
+}
+
+
+static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
+{
+ u32 telem_ctrl = 0;
+ int ret;
+
+ mutex_lock(&(telm_conf->telem_lock));
+ if (ioss_period) {
+ if (TELEM_SAMPLE_PERIOD_INVALID(ioss_period)) {
+ pr_err("IOSS Sampling Period Out of Range\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get telemetry EVENT CTL */
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
+ &telem_ctrl, IOSS_TELEM_READ_WORD);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Read Failed\n");
+ goto out;
+ }
+
+ /* Disable Telemetry */
+ TELEM_DISABLE(telem_ctrl);
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_WRITE,
+ (u8 *)&telem_ctrl,
+ IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+ NULL, 0);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
+ goto out;
+ }
+
+ /* Enable Periodic Telemetry Events and enable SRAM trace */
+ TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+ TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+ TELEM_ENABLE_PERIODIC(telem_ctrl);
+ telem_ctrl |= ioss_period;
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_EVENT_CTL_WRITE,
+ (u8 *)&telem_ctrl,
+ IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
+ NULL, 0);
+ if (ret) {
+ pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
+ goto out;
+ }
+ telm_conf->ioss_config.curr_period = ioss_period;
+ }
+
+ if (pss_period) {
+ if (TELEM_SAMPLE_PERIOD_INVALID(pss_period)) {
+ pr_err("PSS Sampling Period Out of Range\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get telemetry EVENT CTL */
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+ 0, 0, NULL, &telem_ctrl);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Read Failed\n");
+ goto out;
+ }
+
+ /* Disable Telemetry */
+ TELEM_DISABLE(telem_ctrl);
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+ 0, 0, &telem_ctrl, NULL);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
+ goto out;
+ }
+
+ /* Enable Periodic Telemetry Events and enable SRAM trace */
+ TELEM_CLEAR_SAMPLE_PERIOD(telem_ctrl);
+ TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
+ TELEM_ENABLE_PERIODIC(telem_ctrl);
+ telem_ctrl |= pss_period;
+
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+ 0, 0, &telem_ctrl, NULL);
+ if (ret) {
+ pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
+ goto out;
+ }
+ telm_conf->pss_config.curr_period = pss_period;
+ }
+
+out:
+ mutex_unlock(&(telm_conf->telem_lock));
+ return ret;
+}
+
+
+static int telemetry_plt_get_sampling_period(u8 *pss_min_period,
+ u8 *pss_max_period,
+ u8 *ioss_min_period,
+ u8 *ioss_max_period)
+{
+ *pss_min_period = telm_conf->pss_config.min_period;
+ *pss_max_period = telm_conf->pss_config.max_period;
+ *ioss_min_period = telm_conf->ioss_config.min_period;
+ *ioss_max_period = telm_conf->ioss_config.max_period;
+
+ return 0;
+}
+
+
+static int telemetry_plt_reset_events(void)
+{
+ struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig;
+ int ret;
+
+ pss_evtconfig.evtmap = NULL;
+ pss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+ pss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+ ioss_evtconfig.evtmap = NULL;
+ ioss_evtconfig.num_evts = TELEM_MAX_OS_ALLOCATED_EVENTS;
+ ioss_evtconfig.period = TELEM_SAMPLING_DEFAULT_PERIOD;
+
+ ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+ TELEM_RESET);
+ if (ret)
+ pr_err("TELEMTRY Reset Failed\n");
+
+ return ret;
+}
+
+
+static int telemetry_plt_get_eventconfig(struct telemetry_evtconfig *pss_config,
+ struct telemetry_evtconfig *ioss_config,
+ int pss_len, int ioss_len)
+{
+ u32 *pss_evtmap, *ioss_evtmap;
+ u32 index;
+
+ pss_evtmap = pss_config->evtmap;
+ ioss_evtmap = ioss_config->evtmap;
+
+ mutex_lock(&(telm_conf->telem_lock));
+ pss_config->num_evts = telm_conf->pss_config.ssram_evts_used;
+ ioss_config->num_evts = telm_conf->ioss_config.ssram_evts_used;
+
+ pss_config->period = telm_conf->pss_config.curr_period;
+ ioss_config->period = telm_conf->ioss_config.curr_period;
+
+ if ((pss_len < telm_conf->pss_config.ssram_evts_used) ||
+ (ioss_len < telm_conf->ioss_config.ssram_evts_used)) {
+ mutex_unlock(&(telm_conf->telem_lock));
+ return -EINVAL;
+ }
+
+ for (index = 0; index < telm_conf->pss_config.ssram_evts_used;
+ index++) {
+ pss_evtmap[index] =
+ telm_conf->pss_config.telem_evts[index].evt_id;
+ }
+
+ for (index = 0; index < telm_conf->ioss_config.ssram_evts_used;
+ index++) {
+ ioss_evtmap[index] =
+ telm_conf->ioss_config.telem_evts[index].evt_id;
+ }
+
+ mutex_unlock(&(telm_conf->telem_lock));
+ return 0;
+}
+
+
+static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts,
+ u32 *pss_evtmap, u32 *ioss_evtmap)
+{
+ struct telemetry_evtconfig pss_evtconfig, ioss_evtconfig;
+ int ret;
+
+ pss_evtconfig.evtmap = pss_evtmap;
+ pss_evtconfig.num_evts = num_pss_evts;
+ pss_evtconfig.period = telm_conf->pss_config.curr_period;
+
+ ioss_evtconfig.evtmap = ioss_evtmap;
+ ioss_evtconfig.num_evts = num_ioss_evts;
+ ioss_evtconfig.period = telm_conf->ioss_config.curr_period;
+
+ ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
+ TELEM_ADD);
+ if (ret)
+ pr_err("TELEMTRY ADD Failed\n");
+
+ return ret;
+}
+
+static int telem_evtlog_read(enum telemetry_unit telem_unit,
+ struct telem_ssram_region *ssram_region, u8 len)
+{
+ struct telemetry_unit_config *unit_config;
+ u64 timestamp_prev, timestamp_next;
+ int ret, index, timeout = 0;
+
+ ret = telem_get_unitconfig(telem_unit, &unit_config);
+ if (ret < 0)
+ return ret;
+
+ if (len > unit_config->ssram_evts_used)
+ len = unit_config->ssram_evts_used;
+
+ do {
+ timestamp_prev = readq(unit_config->regmap);
+ if (!timestamp_prev) {
+ pr_err("Ssram under update. Please Try Later\n");
+ return -EBUSY;
+ }
+
+ ssram_region->start_time = readq(unit_config->regmap +
+ TELEM_SSRAM_STARTTIME_OFFSET);
+
+ for (index = 0; index < len; index++) {
+ ssram_region->events[index] =
+ readq(unit_config->regmap + TELEM_SSRAM_EVTLOG_OFFSET +
+ BYTES_PER_LONG*index);
+ }
+
+ timestamp_next = readq(unit_config->regmap);
+ if (!timestamp_next) {
+ pr_err("Ssram under update. Please Try Later\n");
+ return -EBUSY;
+ }
+
+ if (timeout++ > TELEM_SSRAM_READ_TIMEOUT) {
+ pr_err("Timeout while reading Events\n");
+ return -EBUSY;
+ }
+
+ } while (timestamp_prev != timestamp_next);
+
+ ssram_region->timestamp = timestamp_next;
+
+ return len;
+}
+
+static int telemetry_plt_raw_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog,
+ int len, int log_all_evts)
+{
+ int index, idx1, ret, readlen = len;
+ struct telem_ssram_region ssram_region;
+ struct telemetry_evtmap *evtmap;
+
+ switch (telem_unit) {
+ case TELEM_PSS:
+ evtmap = telm_conf->pss_config.telem_evts;
+ break;
+
+ case TELEM_IOSS:
+ evtmap = telm_conf->ioss_config.telem_evts;
+ break;
+
+ default:
+ pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit);
+ return -EINVAL;
+ }
+
+ if (!log_all_evts)
+ readlen = TELEM_MAX_EVENTS_SRAM;
+
+ ret = telem_evtlog_read(telem_unit, &ssram_region, readlen);
+ if (ret < 0)
+ return ret;
+
+ /* Invalid evt-id array specified via length mismatch */
+ if ((!log_all_evts) && (len > ret))
+ return -EINVAL;
+
+ if (log_all_evts)
+ for (index = 0; index < ret; index++) {
+ evtlog[index].telem_evtlog = ssram_region.events[index];
+ evtlog[index].telem_evtid = evtmap[index].evt_id;
+ }
+ else
+ for (index = 0, readlen = 0; (index < ret) && (readlen < len);
+ index++) {
+ for (idx1 = 0; idx1 < len; idx1++) {
+ /* Elements matched */
+ if (evtmap[index].evt_id ==
+ evtlog[idx1].telem_evtid) {
+ evtlog[idx1].telem_evtlog =
+ ssram_region.events[index];
+ readlen++;
+
+ break;
+ }
+ }
+ }
+
+ return readlen;
+}
+
+static int telemetry_plt_read_eventlog(enum telemetry_unit telem_unit,
+ struct telemetry_evtlog *evtlog, int len, int log_all_evts)
+{
+ int ret;
+
+ mutex_lock(&(telm_conf->telem_lock));
+ ret = telemetry_plt_raw_read_eventlog(telem_unit, evtlog,
+ len, log_all_evts);
+ mutex_unlock(&(telm_conf->telem_lock));
+
+ return ret;
+}
+
+static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 *verbosity)
+{
+ u32 temp = 0;
+ int ret;
+
+ if (verbosity == NULL)
+ return -EINVAL;
+
+ mutex_lock(&(telm_conf->telem_trace_lock));
+ switch (telem_unit) {
+ case TELEM_PSS:
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
+ 0, 0, NULL, &temp);
+ if (ret) {
+ pr_err("PSS TRACE_CTRL Read Failed\n");
+ goto out;
+ }
+
+ break;
+
+ case TELEM_IOSS:
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
+ IOSS_TELEM_READ_WORD);
+ if (ret) {
+ pr_err("IOSS TRACE_CTL Read Failed\n");
+ goto out;
+ }
+
+ break;
+
+ default:
+ pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit);
+ ret = -EINVAL;
+ break;
+ }
+ TELEM_EXTRACT_VERBOSITY(temp, *verbosity);
+
+out:
+ mutex_unlock(&(telm_conf->telem_trace_lock));
+ return ret;
+}
+
+static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
+ u32 verbosity)
+{
+ u32 temp = 0;
+ int ret;
+
+ verbosity &= TELEM_TRC_VERBOSITY_MASK;
+
+ mutex_lock(&(telm_conf->telem_trace_lock));
+ switch (telem_unit) {
+ case TELEM_PSS:
+ ret = intel_punit_ipc_command(
+ IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL,
+ 0, 0, &verbosity, NULL);
+ if (ret) {
+ pr_err("PSS TRACE_CTRL Verbosity Set Failed\n");
+ goto out;
+ }
+ break;
+
+ case TELEM_IOSS:
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
+ IOSS_TELEM_READ_WORD);
+ if (ret) {
+ pr_err("IOSS TRACE_CTL Read Failed\n");
+ goto out;
+ }
+
+ TELEM_CLEAR_VERBOSITY_BITS(temp);
+ TELEM_SET_VERBOSITY_BITS(temp, verbosity);
+
+ ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
+ IOSS_TELEM_TRACE_CTL_WRITE, (u8 *)&temp,
+ IOSS_TELEM_WRITE_FOURBYTES, NULL, 0);
+ if (ret) {
+ pr_err("IOSS TRACE_CTL Verbosity Set Failed\n");
+ goto out;
+ }
+ break;
+
+ default:
+ pr_err("Unknown Telemetry Unit Specified %d\n", telem_unit);
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ mutex_unlock(&(telm_conf->telem_trace_lock));
+ return ret;
+}
+
+static struct telemetry_core_ops telm_pltops = {
+ .get_trace_verbosity = telemetry_plt_get_trace_verbosity,
+ .set_trace_verbosity = telemetry_plt_set_trace_verbosity,
+ .set_sampling_period = telemetry_plt_set_sampling_period,
+ .get_sampling_period = telemetry_plt_get_sampling_period,
+ .raw_read_eventlog = telemetry_plt_raw_read_eventlog,
+ .get_eventconfig = telemetry_plt_get_eventconfig,
+ .update_events = telemetry_plt_update_events,
+ .read_eventlog = telemetry_plt_read_eventlog,
+ .reset_events = telemetry_plt_reset_events,
+ .add_events = telemetry_plt_add_events,
+};
+
+static int telemetry_pltdrv_probe(struct platform_device *pdev)
+{
+ struct resource *res0 = NULL, *res1 = NULL;
+ const struct x86_cpu_id *id;
+ int size, ret = -ENOMEM;
+
+ id = x86_match_cpu(telemetry_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ telm_conf = (struct telemetry_plt_config *)id->driver_data;
+
+ res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ size = resource_size(res0);
+ if (!devm_request_mem_region(&pdev->dev, res0->start, size,
+ pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ telm_conf->pss_config.ssram_base_addr = res0->start;
+ telm_conf->pss_config.ssram_size = size;
+
+ res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res1) {
+ ret = -EINVAL;
+ goto out;
+ }
+ size = resource_size(res1);
+ if (!devm_request_mem_region(&pdev->dev, res1->start, size,
+ pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ telm_conf->ioss_config.ssram_base_addr = res1->start;
+ telm_conf->ioss_config.ssram_size = size;
+
+ telm_conf->pss_config.regmap = ioremap_nocache(
+ telm_conf->pss_config.ssram_base_addr,
+ telm_conf->pss_config.ssram_size);
+ if (!telm_conf->pss_config.regmap) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ telm_conf->ioss_config.regmap = ioremap_nocache(
+ telm_conf->ioss_config.ssram_base_addr,
+ telm_conf->ioss_config.ssram_size);
+ if (!telm_conf->ioss_config.regmap) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mutex_init(&telm_conf->telem_lock);
+ mutex_init(&telm_conf->telem_trace_lock);
+
+ ret = telemetry_setup(pdev);
+ if (ret)
+ goto out;
+
+ ret = telemetry_set_pltdata(&telm_pltops, telm_conf);
+ if (ret) {
+ dev_err(&pdev->dev, "TELEMTRY Set Pltops Failed.\n");
+ goto out;
+ }
+
+ return 0;
+
+out:
+ if (res0)
+ release_mem_region(res0->start, resource_size(res0));
+ if (res1)
+ release_mem_region(res1->start, resource_size(res1));
+ if (telm_conf->pss_config.regmap)
+ iounmap(telm_conf->pss_config.regmap);
+ if (telm_conf->ioss_config.regmap)
+ iounmap(telm_conf->ioss_config.regmap);
+ dev_err(&pdev->dev, "TELEMTRY Setup Failed.\n");
+
+ return ret;
+}
+
+static int telemetry_pltdrv_remove(struct platform_device *pdev)
+{
+ telemetry_clear_pltdata();
+ iounmap(telm_conf->pss_config.regmap);
+ iounmap(telm_conf->ioss_config.regmap);
+
+ return 0;
+}
+
+static struct platform_driver telemetry_soc_driver = {
+ .probe = telemetry_pltdrv_probe,
+ .remove = telemetry_pltdrv_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init telemetry_module_init(void)
+{
+ pr_info(DRIVER_NAME ": version %s loaded\n", DRIVER_VERSION);
+ return platform_driver_register(&telemetry_soc_driver);
+}
+
+static void __exit telemetry_module_exit(void)
+{
+ platform_driver_unregister(&telemetry_soc_driver);
+}
+
+device_initcall(telemetry_module_init);
+module_exit(telemetry_module_exit);
+
+MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
+MODULE_DESCRIPTION("Intel SoC Telemetry Platform Driver");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index f73c29558cd3..e9caa347a9bf 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1393,6 +1393,7 @@ static void sony_nc_function_setup(struct acpi_device *device,
case 0x0143:
case 0x014b:
case 0x014c:
+ case 0x0153:
case 0x0163:
result = sony_nc_kbd_backlight_setup(pf_device, handle);
if (result)
@@ -1490,6 +1491,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
case 0x0143:
case 0x014b:
case 0x014c:
+ case 0x0153:
case 0x0163:
sony_nc_kbd_backlight_cleanup(pd, handle);
break;
@@ -1773,6 +1775,7 @@ struct kbd_backlight {
unsigned int base;
unsigned int mode;
unsigned int timeout;
+ unsigned int has_timeout;
struct device_attribute mode_attr;
struct device_attribute timeout_attr;
};
@@ -1877,6 +1880,8 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
unsigned int handle)
{
int result;
+ int probe_base = 0;
+ int ctl_base = 0;
int ret = 0;
if (kbdbl_ctl) {
@@ -1885,11 +1890,25 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
return -EBUSY;
}
- /* verify the kbd backlight presence, these handles are not used for
- * keyboard backlight only
+ /* verify the kbd backlight presence, some of these handles are not used
+ * for keyboard backlight only
*/
- ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100,
- &result);
+ switch (handle) {
+ case 0x0153:
+ probe_base = 0x0;
+ ctl_base = 0x0;
+ break;
+ case 0x0137:
+ probe_base = 0x0B00;
+ ctl_base = 0x0C00;
+ break;
+ default:
+ probe_base = 0x0100;
+ ctl_base = 0x4000;
+ break;
+ }
+
+ ret = sony_call_snc_handle(handle, probe_base, &result);
if (ret)
return ret;
@@ -1906,10 +1925,9 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
kbdbl_ctl->mode = kbd_backlight;
kbdbl_ctl->timeout = kbd_backlight_timeout;
kbdbl_ctl->handle = handle;
- if (handle == 0x0137)
- kbdbl_ctl->base = 0x0C00;
- else
- kbdbl_ctl->base = 0x4000;
+ kbdbl_ctl->base = ctl_base;
+ /* Some models do not allow timeout control */
+ kbdbl_ctl->has_timeout = handle != 0x0153;
sysfs_attr_init(&kbdbl_ctl->mode_attr.attr);
kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
@@ -1917,22 +1935,28 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
- sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
- kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
- kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
- kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
- kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
-
ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
if (ret)
goto outkzalloc;
- ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
- if (ret)
- goto outmode;
-
__sony_nc_kbd_backlight_mode_set(kbdbl_ctl->mode);
- __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout);
+
+ if (kbdbl_ctl->has_timeout) {
+ sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
+ kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
+ kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
+ kbdbl_ctl->timeout_attr.show =
+ sony_nc_kbd_backlight_timeout_show;
+ kbdbl_ctl->timeout_attr.store =
+ sony_nc_kbd_backlight_timeout_store;
+
+ ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
+ if (ret)
+ goto outmode;
+
+ __sony_nc_kbd_backlight_timeout_set(kbdbl_ctl->timeout);
+ }
+
return 0;
@@ -1949,7 +1973,8 @@ static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
{
if (kbdbl_ctl && handle == kbdbl_ctl->handle) {
device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
- device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
+ if (kbdbl_ctl->has_timeout)
+ device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
kfree(kbdbl_ctl);
kbdbl_ctl = NULL;
}
diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
index f7dade3fd2ab..700e0fa0eec2 100644
--- a/drivers/platform/x86/surfacepro3_button.c
+++ b/drivers/platform/x86/surfacepro3_button.c
@@ -1,6 +1,6 @@
/*
* power/home/volume button support for
- * Microsoft Surface Pro 3 tablet.
+ * Microsoft Surface Pro 3/4 tablet.
*
* Copyright (c) 2015 Intel Corporation.
* All rights reserved.
@@ -19,9 +19,10 @@
#include <linux/acpi.h>
#include <acpi/button.h>
-#define SURFACE_BUTTON_HID "MSHW0028"
+#define SURFACE_PRO3_BUTTON_HID "MSHW0028"
+#define SURFACE_PRO4_BUTTON_HID "MSHW0040"
#define SURFACE_BUTTON_OBJ_NAME "VGBI"
-#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3 Buttons"
+#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
#define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
#define SURFACE_BUTTON_NOTIFY_RELEASE_POWER 0xc7
@@ -54,7 +55,8 @@ MODULE_LICENSE("GPL v2");
* acpi_driver.
*/
static const struct acpi_device_id surface_button_device_ids[] = {
- {SURFACE_BUTTON_HID, 0},
+ {SURFACE_PRO3_BUTTON_HID, 0},
+ {SURFACE_PRO4_BUTTON_HID, 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, surface_button_device_ids);
@@ -109,7 +111,7 @@ static void surface_button_notify(struct acpi_device *device, u32 event)
break;
}
input = button->input;
- if (KEY_RESERVED == key_code)
+ if (key_code == KEY_RESERVED)
return;
if (pressed)
pm_wakeup_event(&device->dev, 0);
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c
index 89aa976f0ab2..65b0a4845ddd 100644
--- a/drivers/platform/x86/tc1100-wmi.c
+++ b/drivers/platform/x86/tc1100-wmi.c
@@ -52,7 +52,9 @@ struct tc1100_data {
u32 jogdial;
};
+#ifdef CONFIG_PM
static struct tc1100_data suspend_data;
+#endif
/* --------------------------------------------------------------------------
Device Management
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 0bed4733c4f0..a268a7abf8ab 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -303,6 +303,7 @@ static struct {
u32 hotkey_mask:1;
u32 hotkey_wlsw:1;
u32 hotkey_tablet:1;
+ u32 kbdlight:1;
u32 light:1;
u32 light_status:1;
u32 bright_acpimode:1;
@@ -4986,6 +4987,207 @@ static struct ibm_struct video_driver_data = {
#endif /* CONFIG_THINKPAD_ACPI_VIDEO */
/*************************************************************************
+ * Keyboard backlight subdriver
+ */
+
+static int kbdlight_set_level(int level)
+{
+ if (!hkey_handle)
+ return -ENXIO;
+
+ if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level))
+ return -EIO;
+
+ return 0;
+}
+
+static int kbdlight_get_level(void)
+{
+ int status = 0;
+
+ if (!hkey_handle)
+ return -ENXIO;
+
+ if (!acpi_evalf(hkey_handle, &status, "MLCG", "dd", 0))
+ return -EIO;
+
+ if (status < 0)
+ return status;
+
+ return status & 0x3;
+}
+
+static bool kbdlight_is_supported(void)
+{
+ int status = 0;
+
+ if (!hkey_handle)
+ return false;
+
+ if (!acpi_has_method(hkey_handle, "MLCG")) {
+ vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG is unavailable\n");
+ return false;
+ }
+
+ if (!acpi_evalf(hkey_handle, &status, "MLCG", "qdd", 0)) {
+ vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG failed\n");
+ return false;
+ }
+
+ if (status < 0) {
+ vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG err: %d\n", status);
+ return false;
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG returned 0x%x\n", status);
+ /*
+ * Guessed test for keyboard backlight:
+ *
+ * Machines with backlight keyboard return:
+ * b010100000010000000XX - ThinkPad X1 Carbon 3rd
+ * b110100010010000000XX - ThinkPad x230
+ * b010100000010000000XX - ThinkPad x240
+ * b010100000010000000XX - ThinkPad W541
+ * (XX is current backlight level)
+ *
+ * Machines without backlight keyboard return:
+ * b10100001000000000000 - ThinkPad x230
+ * b10110001000000000000 - ThinkPad E430
+ * b00000000000000000000 - ThinkPad E450
+ *
+ * Candidate BITs for detection test (XOR):
+ * b01000000001000000000
+ * ^
+ */
+ return status & BIT(9);
+}
+
+static void kbdlight_set_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ kbdlight_set_level(data->new_state);
+}
+
+static void kbdlight_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(led_cdev,
+ struct tpacpi_led_classdev,
+ led_classdev);
+ data->new_state = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev)
+{
+ int level;
+
+ level = kbdlight_get_level();
+ if (level < 0)
+ return 0;
+
+ return level;
+}
+
+static struct tpacpi_led_classdev tpacpi_led_kbdlight = {
+ .led_classdev = {
+ .name = "tpacpi::kbd_backlight",
+ .max_brightness = 2,
+ .brightness_set = &kbdlight_sysfs_set,
+ .brightness_get = &kbdlight_sysfs_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ }
+};
+
+static int __init kbdlight_init(struct ibm_init_struct *iibm)
+{
+ int rc;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing kbdlight subdriver\n");
+
+ TPACPI_ACPIHANDLE_INIT(hkey);
+ INIT_WORK(&tpacpi_led_kbdlight.work, kbdlight_set_worker);
+
+ if (!kbdlight_is_supported()) {
+ tp_features.kbdlight = 0;
+ vdbg_printk(TPACPI_DBG_INIT, "kbdlight is unsupported\n");
+ return 1;
+ }
+
+ tp_features.kbdlight = 1;
+
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_led_kbdlight.led_classdev);
+ if (rc < 0) {
+ tp_features.kbdlight = 0;
+ return rc;
+ }
+
+ return 0;
+}
+
+static void kbdlight_exit(void)
+{
+ if (tp_features.kbdlight)
+ led_classdev_unregister(&tpacpi_led_kbdlight.led_classdev);
+ flush_workqueue(tpacpi_wq);
+}
+
+static int kbdlight_read(struct seq_file *m)
+{
+ int level;
+
+ if (!tp_features.kbdlight) {
+ seq_printf(m, "status:\t\tnot supported\n");
+ } else {
+ level = kbdlight_get_level();
+ if (level < 0)
+ seq_printf(m, "status:\t\terror %d\n", level);
+ else
+ seq_printf(m, "status:\t\t%d\n", level);
+ seq_printf(m, "commands:\t0, 1, 2\n");
+ }
+
+ return 0;
+}
+
+static int kbdlight_write(char *buf)
+{
+ char *cmd;
+ int level = -1;
+
+ if (!tp_features.kbdlight)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "0") == 0)
+ level = 0;
+ else if (strlencmp(cmd, "1") == 0)
+ level = 1;
+ else if (strlencmp(cmd, "2") == 0)
+ level = 2;
+ else
+ return -EINVAL;
+ }
+
+ if (level == -1)
+ return -EINVAL;
+
+ return kbdlight_set_level(level);
+}
+
+static struct ibm_struct kbdlight_driver_data = {
+ .name = "kbdlight",
+ .read = kbdlight_read,
+ .write = kbdlight_write,
+ .exit = kbdlight_exit,
+};
+
+/*************************************************************************
* Light (thinklight) subdriver
*/
@@ -9207,6 +9409,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
},
#endif
{
+ .init = kbdlight_init,
+ .data = &kbdlight_driver_data,
+ },
+ {
.init = light_init,
.data = &light_driver_data,
},
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index c01302989ee4..73833079bac8 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -51,6 +51,7 @@
#include <linux/dmi.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
+#include <linux/rfkill.h>
#include <linux/toshiba.h>
#include <acpi/video.h>
@@ -114,6 +115,7 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT 0x001c
#define HCI_HOTKEY_EVENT 0x001e
#define HCI_LCD_BRIGHTNESS 0x002a
+#define HCI_WIRELESS 0x0056
#define HCI_ACCELEROMETER 0x006d
#define HCI_KBD_ILLUMINATION 0x0095
#define HCI_ECO_MODE 0x0097
@@ -148,6 +150,10 @@ MODULE_LICENSE("GPL");
#define SCI_KBD_MODE_ON 0x8
#define SCI_KBD_MODE_OFF 0x10
#define SCI_KBD_TIME_MAX 0x3c001a
+#define HCI_WIRELESS_STATUS 0x1
+#define HCI_WIRELESS_WWAN 0x3
+#define HCI_WIRELESS_WWAN_STATUS 0x2000
+#define HCI_WIRELESS_WWAN_POWER 0x4000
#define SCI_USB_CHARGE_MODE_MASK 0xff
#define SCI_USB_CHARGE_DISABLED 0x00
#define SCI_USB_CHARGE_ALTERNATE 0x09
@@ -169,6 +175,7 @@ struct toshiba_acpi_dev {
struct led_classdev kbd_led;
struct led_classdev eco_led;
struct miscdevice miscdev;
+ struct rfkill *wwan_rfk;
int force_fan;
int last_key_event;
@@ -197,12 +204,15 @@ struct toshiba_acpi_dev {
unsigned int kbd_function_keys_supported:1;
unsigned int panel_power_on_supported:1;
unsigned int usb_three_supported:1;
+ unsigned int wwan_supported:1;
unsigned int sysfs_created:1;
unsigned int special_functions;
+ bool kbd_event_generated;
bool kbd_led_registered;
bool illumination_led_registered;
bool eco_led_registered;
+ bool killswitch;
};
static struct toshiba_acpi_dev *toshiba_acpi;
@@ -516,6 +526,7 @@ static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
dev->kbd_illum_supported = 0;
dev->kbd_led_registered = false;
+ dev->kbd_event_generated = false;
if (!sci_open(dev))
return;
@@ -1085,6 +1096,104 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev,
return -EIO;
}
+/* Wireless status (RFKill, WLAN, BT, WWAN) */
+static int toshiba_wireless_status(struct toshiba_acpi_dev *dev)
+{
+ u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ in[3] = HCI_WIRELESS_STATUS;
+ status = tci_raw(dev, in, out);
+
+ if (ACPI_FAILURE(status)) {
+ pr_err("ACPI call to get Wireless status failed\n");
+ return -EIO;
+ }
+
+ if (out[0] == TOS_NOT_SUPPORTED)
+ return -ENODEV;
+
+ if (out[0] != TOS_SUCCESS)
+ return -EIO;
+
+ dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS);
+
+ return 0;
+}
+
+/* WWAN */
+static void toshiba_wwan_available(struct toshiba_acpi_dev *dev)
+{
+ u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ dev->wwan_supported = 0;
+
+ /*
+ * WWAN support can be queried by setting the in[3] value to
+ * HCI_WIRELESS_WWAN (0x03).
+ *
+ * If supported, out[0] contains TOS_SUCCESS and out[2] contains
+ * HCI_WIRELESS_WWAN_STATUS (0x2000).
+ *
+ * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300)
+ * or TOS_NOT_SUPPORTED (0x8000).
+ */
+ in[3] = HCI_WIRELESS_WWAN;
+ status = tci_raw(dev, in, out);
+
+ if (ACPI_FAILURE(status)) {
+ pr_err("ACPI call to get WWAN status failed\n");
+ return;
+ }
+
+ if (out[0] != TOS_SUCCESS)
+ return;
+
+ dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS);
+}
+
+static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state)
+{
+ u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ in[3] = HCI_WIRELESS_WWAN_STATUS;
+ status = tci_raw(dev, in, out);
+
+ if (ACPI_FAILURE(status)) {
+ pr_err("ACPI call to set WWAN status failed\n");
+ return -EIO;
+ }
+
+ if (out[0] == TOS_NOT_SUPPORTED)
+ return -ENODEV;
+
+ if (out[0] != TOS_SUCCESS)
+ return -EIO;
+
+ /*
+ * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to
+ * (de)activate the device, but some others need the
+ * HCI_WIRELESS_WWAN_POWER call as well.
+ */
+ in[3] = HCI_WIRELESS_WWAN_POWER;
+ status = tci_raw(dev, in, out);
+
+ if (ACPI_FAILURE(status)) {
+ pr_err("ACPI call to set WWAN power failed\n");
+ return -EIO;
+ }
+
+ if (out[0] == TOS_NOT_SUPPORTED)
+ return -ENODEV;
+
+ return out[0] == TOS_SUCCESS ? 0 : -EIO;
+}
+
/* Transflective Backlight */
static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
{
@@ -1535,6 +1644,11 @@ static const struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};
+/* Keyboard backlight work */
+static void toshiba_acpi_kbd_bl_work(struct work_struct *work);
+
+static DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work);
+
/*
* Sysfs files
*/
@@ -1634,6 +1748,24 @@ static ssize_t kbd_backlight_mode_store(struct device *dev,
return ret;
toshiba->kbd_mode = mode;
+
+ /*
+ * Some laptop models with the second generation backlit
+ * keyboard (type 2) do not generate the keyboard backlight
+ * changed event (0x92), and thus, the driver will never update
+ * the sysfs entries.
+ *
+ * The event is generated right when changing the keyboard
+ * backlight mode and the *notify function will set the
+ * kbd_event_generated to true.
+ *
+ * In case the event is not generated, schedule the keyboard
+ * backlight work to update the sysfs entries and emulate the
+ * event via genetlink.
+ */
+ if (toshiba->kbd_type == 2 &&
+ !toshiba_acpi->kbd_event_generated)
+ schedule_work(&kbd_bl_work);
}
return count;
@@ -2166,6 +2298,21 @@ static struct attribute_group toshiba_attr_group = {
.attrs = toshiba_attributes,
};
+static void toshiba_acpi_kbd_bl_work(struct work_struct *work)
+{
+ struct acpi_device *acpi_dev = toshiba_acpi->acpi_dev;
+
+ /* Update the sysfs entries */
+ if (sysfs_update_group(&acpi_dev->dev.kobj,
+ &toshiba_attr_group))
+ pr_err("Unable to update sysfs entries\n");
+
+ /* Emulate the keyboard backlight event */
+ acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
+ dev_name(&acpi_dev->dev),
+ 0x92, 0);
+}
+
/*
* Misc device
*/
@@ -2242,6 +2389,67 @@ static const struct file_operations toshiba_acpi_fops = {
};
/*
+ * WWAN RFKill handlers
+ */
+static int toshiba_acpi_wwan_set_block(void *data, bool blocked)
+{
+ struct toshiba_acpi_dev *dev = data;
+ int ret;
+
+ ret = toshiba_wireless_status(dev);
+ if (ret)
+ return ret;
+
+ if (!dev->killswitch)
+ return 0;
+
+ return toshiba_wwan_set(dev, !blocked);
+}
+
+static void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data)
+{
+ struct toshiba_acpi_dev *dev = data;
+
+ if (toshiba_wireless_status(dev))
+ return;
+
+ rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
+}
+
+static const struct rfkill_ops wwan_rfk_ops = {
+ .set_block = toshiba_acpi_wwan_set_block,
+ .poll = toshiba_acpi_wwan_poll,
+};
+
+static int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev)
+{
+ int ret = toshiba_wireless_status(dev);
+
+ if (ret)
+ return ret;
+
+ dev->wwan_rfk = rfkill_alloc("Toshiba WWAN",
+ &dev->acpi_dev->dev,
+ RFKILL_TYPE_WWAN,
+ &wwan_rfk_ops,
+ dev);
+ if (!dev->wwan_rfk) {
+ pr_err("Unable to allocate WWAN rfkill device\n");
+ return -ENOMEM;
+ }
+
+ rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
+
+ ret = rfkill_register(dev->wwan_rfk);
+ if (ret) {
+ pr_err("Unable to register WWAN rfkill device\n");
+ rfkill_destroy(dev->wwan_rfk);
+ }
+
+ return ret;
+}
+
+/*
* Hotkeys
*/
static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
@@ -2484,6 +2692,14 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
brightness = __get_lcd_brightness(dev);
if (brightness < 0)
return 0;
+ /*
+ * If transflective backlight is supported and the brightness is zero
+ * (lowest brightness level), the set_lcd_brightness function will
+ * activate the transflective backlight, making the LCD appear to be
+ * turned off, simply increment the brightness level to avoid that.
+ */
+ if (dev->tr_backlight_supported && brightness == 0)
+ brightness++;
ret = set_lcd_brightness(dev, brightness);
if (ret) {
pr_debug("Backlight method is read-only, disabling backlight support\n");
@@ -2561,6 +2777,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
pr_cont(" panel-power-on");
if (dev->usb_three_supported)
pr_cont(" usb3");
+ if (dev->wwan_supported)
+ pr_cont(" wwan");
pr_cont("\n");
}
@@ -2598,6 +2816,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
if (dev->eco_led_registered)
led_classdev_unregister(&dev->eco_led);
+ if (dev->wwan_rfk) {
+ rfkill_unregister(dev->wwan_rfk);
+ rfkill_destroy(dev->wwan_rfk);
+ }
+
if (toshiba_acpi)
toshiba_acpi = NULL;
@@ -2736,6 +2959,10 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
ret = get_fan_status(dev, &dummy);
dev->fan_supported = !ret;
+ toshiba_wwan_available(dev);
+ if (dev->wwan_supported)
+ toshiba_acpi_setup_wwan_rfkill(dev);
+
print_supported_features(dev);
ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
@@ -2760,7 +2987,6 @@ error:
static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
{
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
- int ret;
switch (event) {
case 0x80: /* Hotkeys and some system events */
@@ -2790,10 +3016,10 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
pr_info("SATA power event received %x\n", event);
break;
case 0x92: /* Keyboard backlight mode changed */
+ toshiba_acpi->kbd_event_generated = true;
/* Update sysfs entries */
- ret = sysfs_update_group(&acpi_dev->dev.kobj,
- &toshiba_attr_group);
- if (ret)
+ if (sysfs_update_group(&acpi_dev->dev.kobj,
+ &toshiba_attr_group))
pr_err("Unable to update sysfs entries\n");
break;
case 0x85: /* Unknown */
@@ -2808,7 +3034,8 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
dev_name(&acpi_dev->dev),
- event, 0);
+ event, (event == 0x80) ?
+ dev->last_key_event : 0);
}
#ifdef CONFIG_PM_SLEEP
@@ -2832,12 +3059,15 @@ static int toshiba_acpi_resume(struct device *device)
struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
if (dev->hotkey_dev) {
- int error = toshiba_acpi_enable_hotkeys(dev);
-
- if (error)
+ if (toshiba_acpi_enable_hotkeys(dev))
pr_info("Unable to re-enable hotkeys\n");
}
+ if (dev->wwan_rfk) {
+ if (!toshiba_wireless_status(dev))
+ rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
+ }
+
return 0;
}
#endif
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index c5e45089ac51..5db495dd018e 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -78,7 +78,7 @@ static int toshiba_bluetooth_present(acpi_handle handle)
*/
result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present);
if (ACPI_FAILURE(result)) {
- pr_err("ACPI call to query Bluetooth presence failed");
+ pr_err("ACPI call to query Bluetooth presence failed\n");
return -ENXIO;
} else if (!bt_present) {
pr_info("Bluetooth device not present\n");
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 237d7aa73e8c..1ddd13cc0c07 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -160,22 +160,16 @@ config BATTERY_SBS
config BATTERY_BQ27XXX
tristate "BQ27xxx battery driver"
help
- Say Y here to enable support for batteries with BQ27xxx (I2C/HDQ) chips.
+ Say Y here to enable support for batteries with BQ27xxx chips.
config BATTERY_BQ27XXX_I2C
- bool "BQ27xxx I2C support"
+ tristate "BQ27xxx I2C support"
depends on BATTERY_BQ27XXX
depends on I2C
default y
help
- Say Y here to enable support for batteries with BQ27xxx (I2C) chips.
-
-config BATTERY_BQ27XXX_PLATFORM
- bool "BQ27xxx HDQ support"
- depends on BATTERY_BQ27XXX
- default y
- help
- Say Y here to enable support for batteries with BQ27xxx (HDQ) chips.
+ Say Y here to enable support for batteries with BQ27xxx chips
+ connected over an I2C bus.
config BATTERY_DA9030
tristate "DA9030 battery driver"
@@ -508,8 +502,7 @@ config AXP20X_POWER
This driver provides support for the power supply features of
AXP20x PMIC.
-source "drivers/power/reset/Kconfig"
-
endif # POWER_SUPPLY
+source "drivers/power/reset/Kconfig"
source "drivers/power/avs/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b656638f8b39..0e4eab55f8d7 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o
+obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c
index 4afd76848bce..27e89536689a 100644
--- a/drivers/power/bq2415x_charger.c
+++ b/drivers/power/bq2415x_charger.c
@@ -1704,7 +1704,7 @@ error_4:
error_3:
bq2415x_power_supply_exit(bq);
error_2:
- if (bq && bq->notify_node)
+ if (bq)
of_node_put(bq->notify_node);
kfree(name);
error_1:
@@ -1724,9 +1724,7 @@ static int bq2415x_remove(struct i2c_client *client)
if (bq->nb.notifier_call)
power_supply_unreg_notifier(&bq->nb);
- if (bq->notify_node)
- of_node_put(bq->notify_node);
-
+ of_node_put(bq->notify_node);
bq2415x_sysfs_exit(bq);
bq2415x_power_supply_exit(bq);
diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c
index 880233ce9343..6b027a418943 100644
--- a/drivers/power/bq27xxx_battery.c
+++ b/drivers/power/bq27xxx_battery.c
@@ -45,11 +45,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
-#include <linux/idr.h>
-#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <asm/unaligned.h>
#include <linux/power/bq27xxx_battery.h>
@@ -78,11 +74,6 @@
#define BQ27XXX_POWER_CONSTANT (29200) /* 29.2 µV^2 * 1000 */
#define BQ27XXX_CURRENT_CONSTANT (3570) /* 3.57 µV * 1000 */
-struct bq27xxx_device_info;
-struct bq27xxx_access_methods {
- int (*read)(struct bq27xxx_device_info *di, u8 reg, bool single);
-};
-
#define INVALID_REG_ADDR 0xff
/*
@@ -110,40 +101,6 @@ enum bq27xxx_reg_index {
BQ27XXX_REG_AP, /* Average Power */
};
-struct bq27xxx_reg_cache {
- int temperature;
- int time_to_empty;
- int time_to_empty_avg;
- int time_to_full;
- int charge_full;
- int cycle_count;
- int capacity;
- int energy;
- int flags;
- int power_avg;
- int health;
-};
-
-struct bq27xxx_device_info {
- struct device *dev;
- int id;
- enum bq27xxx_chip chip;
-
- struct bq27xxx_reg_cache cache;
- int charge_design_full;
-
- unsigned long last_update;
- struct delayed_work work;
-
- struct power_supply *bat;
-
- struct bq27xxx_access_methods bus;
-
- struct mutex lock;
-
- u8 *regs;
-};
-
/* Register mappings */
static u8 bq27000_regs[] = {
0x00, /* CONTROL */
@@ -198,10 +155,10 @@ static u8 bq27500_regs[] = {
INVALID_REG_ADDR, /* TTECP - NA */
0x0c, /* NAC */
0x12, /* LMD(FCC) */
- 0x1e, /* CYCT */
+ 0x2a, /* CYCT */
INVALID_REG_ADDR, /* AE - NA */
- 0x20, /* SOC(RSOC) */
- 0x2e, /* DCAP(ILMD) */
+ 0x2c, /* SOC(RSOC) */
+ 0x3c, /* DCAP(ILMD) */
INVALID_REG_ADDR, /* AP - NA */
};
@@ -242,7 +199,7 @@ static u8 bq27541_regs[] = {
INVALID_REG_ADDR, /* AE - NA */
0x2c, /* SOC(RSOC) */
0x3c, /* DCAP */
- 0x76, /* AP */
+ 0x24, /* AP */
};
static u8 bq27545_regs[] = {
@@ -471,7 +428,10 @@ static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di)
{
int soc;
- soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
+ if (di->chip == BQ27000 || di->chip == BQ27010)
+ soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true);
+ else
+ soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
if (soc < 0)
dev_dbg(di->dev, "error reading State-of-Charge\n");
@@ -536,7 +496,10 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di)
{
int dcap;
- dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
+ if (di->chip == BQ27000 || di->chip == BQ27010)
+ dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true);
+ else
+ dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
if (dcap < 0) {
dev_dbg(di->dev, "error reading initial last measured discharge\n");
@@ -544,7 +507,7 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di)
}
if (di->chip == BQ27000 || di->chip == BQ27010)
- dcap *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
+ dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
else
dcap *= 1000;
@@ -710,7 +673,7 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
return POWER_SUPPLY_HEALTH_GOOD;
}
-static void bq27xxx_battery_update(struct bq27xxx_device_info *di)
+void bq27xxx_battery_update(struct bq27xxx_device_info *di)
{
struct bq27xxx_reg_cache cache = {0, };
bool has_ci_flag = di->chip == BQ27000 || di->chip == BQ27010;
@@ -722,7 +685,7 @@ static void bq27xxx_battery_update(struct bq27xxx_device_info *di)
if (cache.flags >= 0) {
cache.temperature = bq27xxx_battery_read_temperature(di);
if (has_ci_flag && (cache.flags & BQ27000_FLAG_CI)) {
- dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
+ dev_info_once(di->dev, "battery is not calibrated! ignoring capacity values\n");
cache.capacity = -ENODATA;
cache.energy = -ENODATA;
cache.time_to_empty = -ENODATA;
@@ -761,6 +724,7 @@ static void bq27xxx_battery_update(struct bq27xxx_device_info *di)
di->last_update = jiffies;
}
+EXPORT_SYMBOL_GPL(bq27xxx_battery_update);
static void bq27xxx_battery_poll(struct work_struct *work)
{
@@ -991,32 +955,30 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
schedule_delayed_work(&di->work, 0);
}
-static int bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
- const char *name)
+int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
{
- int ret;
struct power_supply_desc *psy_desc;
struct power_supply_config psy_cfg = { .drv_data = di, };
+ INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
+ mutex_init(&di->lock);
+ di->regs = bq27xxx_regs[di->chip];
+
psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
if (!psy_desc)
return -ENOMEM;
- psy_desc->name = name;
+ psy_desc->name = di->name;
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
psy_desc->properties = bq27xxx_battery_props[di->chip].props;
psy_desc->num_properties = bq27xxx_battery_props[di->chip].size;
psy_desc->get_property = bq27xxx_battery_get_property;
psy_desc->external_power_changed = bq27xxx_external_power_changed;
- INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
- mutex_init(&di->lock);
-
di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg);
if (IS_ERR(di->bat)) {
- ret = PTR_ERR(di->bat);
- dev_err(di->dev, "failed to register battery: %d\n", ret);
- return ret;
+ dev_err(di->dev, "failed to register battery\n");
+ return PTR_ERR(di->bat);
}
dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
@@ -1025,8 +987,9 @@ static int bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
return 0;
}
+EXPORT_SYMBOL_GPL(bq27xxx_battery_setup);
-static void bq27xxx_powersupply_unregister(struct bq27xxx_device_info *di)
+void bq27xxx_battery_teardown(struct bq27xxx_device_info *di)
{
/*
* power_supply_unregister call bq27xxx_battery_get_property which
@@ -1042,192 +1005,7 @@ static void bq27xxx_powersupply_unregister(struct bq27xxx_device_info *di)
mutex_destroy(&di->lock);
}
-
-/* i2c specific code */
-#ifdef CONFIG_BATTERY_BQ27XXX_I2C
-
-/* If the system has several batteries we need a different name for each
- * of them...
- */
-static DEFINE_IDR(battery_id);
-static DEFINE_MUTEX(battery_mutex);
-
-static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data)
-{
- struct bq27xxx_device_info *di = data;
-
- bq27xxx_battery_update(di);
-
- return IRQ_HANDLED;
-}
-
-static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
- bool single)
-{
- struct i2c_client *client = to_i2c_client(di->dev);
- struct i2c_msg msg[2];
- unsigned char data[2];
- int ret;
-
- if (!client->adapter)
- return -ENODEV;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].buf = &reg;
- msg[0].len = sizeof(reg);
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = data;
- if (single)
- msg[1].len = 1;
- else
- msg[1].len = 2;
-
- ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
- if (ret < 0)
- return ret;
-
- if (!single)
- ret = get_unaligned_le16(data);
- else
- ret = data[0];
-
- return ret;
-}
-
-static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- char *name;
- struct bq27xxx_device_info *di;
- int num;
- int retval = 0;
-
- /* Get new ID for the new battery device */
- mutex_lock(&battery_mutex);
- num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
- mutex_unlock(&battery_mutex);
- if (num < 0)
- return num;
-
- name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num);
- if (!name) {
- retval = -ENOMEM;
- goto batt_failed;
- }
-
- di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
- if (!di) {
- retval = -ENOMEM;
- goto batt_failed;
- }
-
- di->id = num;
- di->dev = &client->dev;
- di->chip = id->driver_data;
- di->bus.read = &bq27xxx_battery_i2c_read;
- di->regs = bq27xxx_regs[di->chip];
-
- retval = bq27xxx_powersupply_init(di, name);
- if (retval)
- goto batt_failed;
-
- /* Schedule a polling after about 1 min */
- schedule_delayed_work(&di->work, 60 * HZ);
-
- i2c_set_clientdata(client, di);
-
- if (client->irq) {
- retval = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, bq27xxx_battery_irq_handler_thread,
- IRQF_ONESHOT,
- name, di);
- if (retval) {
- dev_err(&client->dev,
- "Unable to register IRQ %d error %d\n",
- client->irq, retval);
- return retval;
- }
- }
-
- return 0;
-
-batt_failed:
- mutex_lock(&battery_mutex);
- idr_remove(&battery_id, num);
- mutex_unlock(&battery_mutex);
-
- return retval;
-}
-
-static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
-{
- struct bq27xxx_device_info *di = i2c_get_clientdata(client);
-
- bq27xxx_powersupply_unregister(di);
-
- mutex_lock(&battery_mutex);
- idr_remove(&battery_id, di->id);
- mutex_unlock(&battery_mutex);
-
- return 0;
-}
-
-static const struct i2c_device_id bq27xxx_id[] = {
- { "bq27200", BQ27000 },
- { "bq27210", BQ27010 },
- { "bq27500", BQ27500 },
- { "bq27510", BQ27500 },
- { "bq27520", BQ27500 },
- { "bq27530", BQ27530 },
- { "bq27531", BQ27530 },
- { "bq27541", BQ27541 },
- { "bq27542", BQ27541 },
- { "bq27546", BQ27541 },
- { "bq27742", BQ27541 },
- { "bq27545", BQ27545 },
- { "bq27421", BQ27421 },
- { "bq27425", BQ27421 },
- { "bq27441", BQ27421 },
- { "bq27621", BQ27421 },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, bq27xxx_id);
-
-static struct i2c_driver bq27xxx_battery_i2c_driver = {
- .driver = {
- .name = "bq27xxx-battery",
- },
- .probe = bq27xxx_battery_i2c_probe,
- .remove = bq27xxx_battery_i2c_remove,
- .id_table = bq27xxx_id,
-};
-
-static inline int bq27xxx_battery_i2c_init(void)
-{
- int ret = i2c_add_driver(&bq27xxx_battery_i2c_driver);
-
- if (ret)
- pr_err("Unable to register BQ27xxx i2c driver\n");
-
- return ret;
-}
-
-static inline void bq27xxx_battery_i2c_exit(void)
-{
- i2c_del_driver(&bq27xxx_battery_i2c_driver);
-}
-
-#else
-
-static inline int bq27xxx_battery_i2c_init(void) { return 0; }
-static inline void bq27xxx_battery_i2c_exit(void) {};
-
-#endif
-
-/* platform specific code */
-#ifdef CONFIG_BATTERY_BQ27XXX_PLATFORM
+EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown);
static int bq27xxx_battery_platform_read(struct bq27xxx_device_info *di, u8 reg,
bool single)
@@ -1267,7 +1045,6 @@ static int bq27xxx_battery_platform_probe(struct platform_device *pdev)
{
struct bq27xxx_device_info *di;
struct bq27xxx_platform_data *pdata = pdev->dev.platform_data;
- const char *name;
if (!pdata) {
dev_err(&pdev->dev, "no platform_data supplied\n");
@@ -1292,83 +1069,36 @@ static int bq27xxx_battery_platform_probe(struct platform_device *pdev)
di->dev = &pdev->dev;
di->chip = pdata->chip;
- di->regs = bq27xxx_regs[di->chip];
-
- name = pdata->name ?: dev_name(&pdev->dev);
- di->bus.read = &bq27xxx_battery_platform_read;
+ di->name = pdata->name ?: dev_name(&pdev->dev);
+ di->bus.read = bq27xxx_battery_platform_read;
- return bq27xxx_powersupply_init(di, name);
+ return bq27xxx_battery_setup(di);
}
static int bq27xxx_battery_platform_remove(struct platform_device *pdev)
{
struct bq27xxx_device_info *di = platform_get_drvdata(pdev);
- bq27xxx_powersupply_unregister(di);
+ bq27xxx_battery_teardown(di);
return 0;
}
+static const struct platform_device_id bq27xxx_battery_platform_id_table[] = {
+ { "bq27000-battery", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, bq27xxx_battery_platform_id_table);
+
static struct platform_driver bq27xxx_battery_platform_driver = {
.probe = bq27xxx_battery_platform_probe,
.remove = bq27xxx_battery_platform_remove,
.driver = {
.name = "bq27000-battery",
},
+ .id_table = bq27xxx_battery_platform_id_table,
};
-
-static inline int bq27xxx_battery_platform_init(void)
-{
- int ret = platform_driver_register(&bq27xxx_battery_platform_driver);
-
- if (ret)
- pr_err("Unable to register BQ27xxx platform driver\n");
-
- return ret;
-}
-
-static inline void bq27xxx_battery_platform_exit(void)
-{
- platform_driver_unregister(&bq27xxx_battery_platform_driver);
-}
-
-#else
-
-static inline int bq27xxx_battery_platform_init(void) { return 0; }
-static inline void bq27xxx_battery_platform_exit(void) {};
-
-#endif
-
-/*
- * Module stuff
- */
-
-static int __init bq27xxx_battery_init(void)
-{
- int ret;
-
- ret = bq27xxx_battery_i2c_init();
- if (ret)
- return ret;
-
- ret = bq27xxx_battery_platform_init();
- if (ret)
- bq27xxx_battery_i2c_exit();
-
- return ret;
-}
-module_init(bq27xxx_battery_init);
-
-static void __exit bq27xxx_battery_exit(void)
-{
- bq27xxx_battery_platform_exit();
- bq27xxx_battery_i2c_exit();
-}
-module_exit(bq27xxx_battery_exit);
-
-#ifdef CONFIG_BATTERY_BQ27XXX_PLATFORM
-MODULE_ALIAS("platform:bq27000-battery");
-#endif
+module_platform_driver(bq27xxx_battery_platform_driver);
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("BQ27xxx battery monitor driver");
diff --git a/drivers/power/bq27xxx_battery_i2c.c b/drivers/power/bq27xxx_battery_i2c.c
new file mode 100644
index 000000000000..9429e66be096
--- /dev/null
+++ b/drivers/power/bq27xxx_battery_i2c.c
@@ -0,0 +1,150 @@
+/*
+ * SCI Reset driver for Keystone based devices
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ * Andrew F. Davis <afd@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 "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/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+
+#include <linux/power/bq27xxx_battery.h>
+
+static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data)
+{
+ struct bq27xxx_device_info *di = data;
+
+ bq27xxx_battery_update(di);
+
+ return IRQ_HANDLED;
+}
+
+static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
+ bool single)
+{
+ struct i2c_client *client = to_i2c_client(di->dev);
+ struct i2c_msg msg[2];
+ unsigned char data[2];
+ int ret;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].buf = &reg;
+ msg[0].len = sizeof(reg);
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = data;
+ if (single)
+ msg[1].len = 1;
+ else
+ msg[1].len = 2;
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret < 0)
+ return ret;
+
+ if (!single)
+ ret = get_unaligned_le16(data);
+ else
+ ret = data[0];
+
+ return ret;
+}
+
+static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bq27xxx_device_info *di;
+ int ret;
+
+ di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
+ if (!di)
+ return -ENOMEM;
+
+ di->dev = &client->dev;
+ di->chip = id->driver_data;
+ di->name = id->name;
+ di->bus.read = bq27xxx_battery_i2c_read;
+
+ ret = bq27xxx_battery_setup(di);
+ if (ret)
+ return ret;
+
+ /* Schedule a polling after about 1 min */
+ schedule_delayed_work(&di->work, 60 * HZ);
+
+ i2c_set_clientdata(client, di);
+
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, bq27xxx_battery_irq_handler_thread,
+ IRQF_ONESHOT,
+ di->name, di);
+ if (ret) {
+ dev_err(&client->dev,
+ "Unable to register IRQ %d error %d\n",
+ client->irq, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
+{
+ struct bq27xxx_device_info *di = i2c_get_clientdata(client);
+
+ bq27xxx_battery_teardown(di);
+
+ return 0;
+}
+
+static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
+ { "bq27200", BQ27000 },
+ { "bq27210", BQ27010 },
+ { "bq27500", BQ27500 },
+ { "bq27510", BQ27500 },
+ { "bq27520", BQ27500 },
+ { "bq27530", BQ27530 },
+ { "bq27531", BQ27530 },
+ { "bq27541", BQ27541 },
+ { "bq27542", BQ27541 },
+ { "bq27546", BQ27541 },
+ { "bq27742", BQ27541 },
+ { "bq27545", BQ27545 },
+ { "bq27421", BQ27421 },
+ { "bq27425", BQ27421 },
+ { "bq27441", BQ27421 },
+ { "bq27621", BQ27421 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
+
+static struct i2c_driver bq27xxx_battery_i2c_driver = {
+ .driver = {
+ .name = "bq27xxx-battery",
+ },
+ .probe = bq27xxx_battery_i2c_probe,
+ .remove = bq27xxx_battery_i2c_remove,
+ .id_table = bq27xxx_i2c_id_table,
+};
+module_i2c_driver(bq27xxx_battery_i2c_driver);
+
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("BQ27xxx battery monitor i2c driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index ed4d756d21e4..a1b7e0592245 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -59,7 +59,7 @@ struct ds278x_info {
struct i2c_client *client;
struct power_supply *battery;
struct power_supply_desc battery_desc;
- struct ds278x_battery_ops *ops;
+ const struct ds278x_battery_ops *ops;
struct delayed_work bat_work;
int id;
int rsns;
@@ -361,7 +361,7 @@ enum ds278x_num_id {
DS2786,
};
-static struct ds278x_battery_ops ds278x_ops[] = {
+static const struct ds278x_battery_ops ds278x_ops[] = {
[DS2782] = {
.get_battery_current = ds2782_get_current,
.get_battery_voltage = ds2782_get_voltage,
diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c
index fedc5818fab7..edb36bf781b0 100644
--- a/drivers/power/generic-adc-battery.c
+++ b/drivers/power/generic-adc-battery.c
@@ -206,7 +206,7 @@ static void gab_work(struct work_struct *work)
bool is_plugged;
int status;
- delayed_work = container_of(work, struct delayed_work, work);
+ delayed_work = to_delayed_work(work);
adc_bat = container_of(delayed_work, struct gab, bat_work);
pdata = adc_bat->pdata;
status = adc_bat->status;
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index f2a7d970388f..46a292aa182d 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -76,7 +76,7 @@ static inline int isp1704_read(struct isp1704_charger *isp, u32 reg)
return usb_phy_io_read(isp->phy, reg);
}
-static inline int isp1704_write(struct isp1704_charger *isp, u32 val, u32 reg)
+static inline int isp1704_write(struct isp1704_charger *isp, u32 reg, u32 val)
{
return usb_phy_io_write(isp->phy, val, reg);
}
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c
index 6d39d52040d4..17876caf31e5 100644
--- a/drivers/power/max8903_charger.c
+++ b/drivers/power/max8903_charger.c
@@ -291,10 +291,10 @@ static int max8903_probe(struct platform_device *pdev)
if (pdata->dc_valid) {
ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->dok),
- NULL, max8903_dcin,
- IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING,
- "MAX8903 DC IN", data);
+ NULL, max8903_dcin,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "MAX8903 DC IN", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for DC (%d)\n",
gpio_to_irq(pdata->dok), ret);
@@ -304,10 +304,10 @@ static int max8903_probe(struct platform_device *pdev)
if (pdata->usb_valid) {
ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->uok),
- NULL, max8903_usbin,
- IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING,
- "MAX8903 USB IN", data);
+ NULL, max8903_usbin,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "MAX8903 USB IN", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for USB (%d)\n",
gpio_to_irq(pdata->uok), ret);
@@ -317,10 +317,10 @@ static int max8903_probe(struct platform_device *pdev)
if (pdata->flt) {
ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt),
- NULL, max8903_fault,
- IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING,
- "MAX8903 Fault", data);
+ NULL, max8903_fault,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "MAX8903 Fault", data);
if (ret) {
dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
gpio_to_irq(pdata->flt), ret);
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 3f6b5dd7c3d4..1b5d450586d1 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -198,6 +198,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
at91_ramc_base[idx] = of_iomap(np, 0);
if (!at91_ramc_base[idx]) {
dev_err(&pdev->dev, "Could not map ram controller address\n");
+ of_node_put(np);
return -ENODEV;
}
idx++;
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
index 83c42ea88f2b..57246cdbd042 100644
--- a/drivers/power/test_power.c
+++ b/drivers/power/test_power.c
@@ -301,6 +301,8 @@ static int map_get_value(struct battery_property_map *map, const char *key,
buf[MAX_KEYLENGTH-1] = '\0';
cr = strnlen(buf, MAX_KEYLENGTH) - 1;
+ if (cr < 0)
+ return def_val;
if (buf[cr] == '\n')
buf[cr] = '\0';
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8df0b0e62976..8155e80dd3f8 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -274,6 +274,15 @@ config REGULATOR_ISL6271A
help
This driver supports ISL6271A voltage regulator chip.
+config REGULATOR_LM363X
+ tristate "TI LM363X voltage regulators"
+ depends on MFD_TI_LMU
+ help
+ This driver supports LM3631 and LM3632 voltage regulators for
+ the LCD bias.
+ One boost output voltage is configurable and always on.
+ Other LDOs are used for the display module.
+
config REGULATOR_LP3971
tristate "National Semiconductors LP3971 PMIC regulator driver"
depends on I2C
@@ -446,6 +455,7 @@ config REGULATOR_MC13892
config REGULATOR_MT6311
tristate "MediaTek MT6311 PMIC"
depends on I2C
+ select REGMAP_I2C
help
Say y here to select this option to enable the power regulator of
MediaTek MT6311 PMIC.
@@ -504,6 +514,22 @@ config REGULATOR_PFUZE100
Say y here to support the regulators found on the Freescale
PFUZE100/PFUZE200 PMIC.
+config REGULATOR_PV88060
+ tristate "Powerventure Semiconductor PV88060 regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the voltage regulators and convertors
+ PV88060
+
+config REGULATOR_PV88090
+ tristate "Powerventure Semiconductor PV88090 regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the voltage regulators and convertors
+ on PV88090
+
config REGULATOR_PWM
tristate "PWM voltage regulator"
depends on PWM
@@ -588,10 +614,10 @@ config REGULATOR_S2MPA01
via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
config REGULATOR_S2MPS11
- tristate "Samsung S2MPS11/S2MPS13/S2MPS14/S2MPU02 voltage regulator"
+ tristate "Samsung S2MPS11/13/14/15/S2MPU02 voltage regulator"
depends on MFD_SEC_CORE
help
- This driver supports a Samsung S2MPS11/S2MPS13/S2MPS14/S2MPU02 voltage
+ This driver supports a Samsung S2MPS11/13/14/15/S2MPU02 voltage
output regulator via I2C bus. The chip is comprised of high efficient
Buck converters including Dual-Phase Buck converter, Buck-Boost
converter, various LDOs.
@@ -680,6 +706,13 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
+config REGULATOR_TPS65086
+ tristate "TI TPS65086 Power regulators"
+ depends on MFD_TPS65086
+ help
+ This driver provides support for the voltage regulators on
+ TI TPS65086 PMICs.
+
config REGULATOR_TPS65090
tristate "TI TPS65090 Power regulator"
depends on MFD_TPS65090
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0f8174913c17..980b1943fa81 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
+obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@@ -66,6 +67,8 @@ obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
+obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
+obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o
obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
@@ -85,6 +88,7 @@ obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65086) += tps65086-regulator.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 35de22fdb7a0..f2e1a39ce0f3 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -27,8 +27,8 @@
#define AXP20X_IO_ENABLED 0x03
#define AXP20X_IO_DISABLED 0x07
-#define AXP22X_IO_ENABLED 0x04
-#define AXP22X_IO_DISABLED 0x03
+#define AXP22X_IO_ENABLED 0x03
+#define AXP22X_IO_DISABLED 0x04
#define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
#define AXP20X_WORKMODE_DCDC3_MASK BIT(1)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 73b7683355cd..744c9889f88d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -132,24 +132,24 @@ static bool have_full_constraints(void)
return has_full_constraints || of_have_populated_dt();
}
+static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
+{
+ if (rdev && rdev->supply)
+ return rdev->supply->rdev;
+
+ return NULL;
+}
+
/**
* regulator_lock_supply - lock a regulator and its supplies
* @rdev: regulator source
*/
static void regulator_lock_supply(struct regulator_dev *rdev)
{
- struct regulator *supply;
- int i = 0;
-
- while (1) {
- mutex_lock_nested(&rdev->mutex, i++);
- supply = rdev->supply;
-
- if (!rdev->supply)
- return;
+ int i;
- rdev = supply->rdev;
- }
+ for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
+ mutex_lock_nested(&rdev->mutex, i);
}
/**
@@ -2368,7 +2368,6 @@ static void regulator_disable_work(struct work_struct *work)
int regulator_disable_deferred(struct regulator *regulator, int ms)
{
struct regulator_dev *rdev = regulator->rdev;
- int ret;
if (regulator->always_on)
return 0;
@@ -2380,13 +2379,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
rdev->deferred_disables++;
mutex_unlock(&rdev->mutex);
- ret = queue_delayed_work(system_power_efficient_wq,
- &rdev->disable_work,
- msecs_to_jiffies(ms));
- if (ret < 0)
- return ret;
- else
- return 0;
+ queue_delayed_work(system_power_efficient_wq, &rdev->disable_work,
+ msecs_to_jiffies(ms));
+ return 0;
}
EXPORT_SYMBOL_GPL(regulator_disable_deferred);
@@ -3451,8 +3446,10 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = NULL;
for (i = 0; i < num_consumers; i++) {
- consumers[i].consumer = regulator_get(dev,
- consumers[i].supply);
+ consumers[i].consumer = _regulator_get(dev,
+ consumers[i].supply,
+ false,
+ !consumers[i].optional);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
dev_err(dev, "Failed to get supply '%s': %d\n",
@@ -3708,7 +3705,7 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
struct device *dev = kobj_to_dev(kobj);
- struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev);
+ struct regulator_dev *rdev = dev_to_rdev(dev);
const struct regulator_ops *ops = rdev->desc->ops;
umode_t mode = attr->mode;
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index affa1b191314..33e8f3b8d2bd 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -257,7 +257,7 @@ static const struct regulator_linear_range da9034_ldo12_ranges[] = {
REGULATOR_LINEAR_RANGE(2700000, 8, 15, 50000),
};
-static struct regulator_ops da903x_regulator_ldo_ops = {
+static const struct regulator_ops da903x_regulator_ldo_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
@@ -268,7 +268,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
};
/* NOTE: this is dedicated for the insane DA9030 LDO14 */
-static struct regulator_ops da9030_regulator_ldo14_ops = {
+static const struct regulator_ops da9030_regulator_ldo14_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = da9030_list_ldo14_voltage,
@@ -279,7 +279,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
};
/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */
-static struct regulator_ops da9030_regulator_ldo1_15_ops = {
+static const struct regulator_ops da9030_regulator_ldo1_15_ops = {
.set_voltage_sel = da9030_set_ldo1_15_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
@@ -289,7 +289,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = {
.is_enabled = da903x_is_enabled,
};
-static struct regulator_ops da9034_regulator_dvc_ops = {
+static const struct regulator_ops da9034_regulator_dvc_ops = {
.set_voltage_sel = da9034_set_dvc_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
@@ -300,7 +300,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
};
/* NOTE: this is dedicated for the insane LDO12 */
-static struct regulator_ops da9034_regulator_ldo12_ops = {
+static const struct regulator_ops da9034_regulator_ldo12_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear_range,
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 12a25b40e473..1050cb77561a 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -265,7 +265,7 @@ static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
return ret;
}
-static struct regulator_ops da9052_dcdc_ops = {
+static const struct regulator_ops da9052_dcdc_ops = {
.get_current_limit = da9052_dcdc_get_current_limit,
.set_current_limit = da9052_dcdc_set_current_limit,
@@ -279,7 +279,7 @@ static struct regulator_ops da9052_dcdc_ops = {
.disable = regulator_disable_regmap,
};
-static struct regulator_ops da9052_ldo_ops = {
+static const struct regulator_ops da9052_ldo_ops = {
.list_voltage = da9052_list_voltage,
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index cafdafbffcaf..d029c941a1e1 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -324,7 +324,7 @@ static int da9055_suspend_disable(struct regulator_dev *rdev)
return 0;
}
-static struct regulator_ops da9055_buck_ops = {
+static const struct regulator_ops da9055_buck_ops = {
.get_mode = da9055_buck_get_mode,
.set_mode = da9055_buck_set_mode,
@@ -345,7 +345,7 @@ static struct regulator_ops da9055_buck_ops = {
.set_suspend_mode = da9055_buck_set_mode,
};
-static struct regulator_ops da9055_ldo_ops = {
+static const struct regulator_ops da9055_ldo_ops = {
.get_mode = da9055_ldo_get_mode,
.set_mode = da9055_ldo_set_mode,
diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c
index 5638fe8d759d..0638c8b40521 100644
--- a/drivers/regulator/da9062-regulator.c
+++ b/drivers/regulator/da9062-regulator.c
@@ -371,7 +371,7 @@ static int da9062_ldo_set_suspend_mode(struct regulator_dev *rdev,
return regmap_field_write(regl->suspend_sleep, val);
}
-static struct regulator_ops da9062_buck_ops = {
+static const struct regulator_ops da9062_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@@ -389,7 +389,7 @@ static struct regulator_ops da9062_buck_ops = {
.set_suspend_mode = da9062_buck_set_suspend_mode,
};
-static struct regulator_ops da9062_ldo_ops = {
+static const struct regulator_ops da9062_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
index 536e931eb921..ed9e7e96f877 100644
--- a/drivers/regulator/da9063-regulator.c
+++ b/drivers/regulator/da9063-regulator.c
@@ -427,7 +427,7 @@ static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode
return regmap_field_write(regl->suspend_sleep, val);
}
-static struct regulator_ops da9063_buck_ops = {
+static const struct regulator_ops da9063_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@@ -445,7 +445,7 @@ static struct regulator_ops da9063_buck_ops = {
.set_suspend_mode = da9063_buck_set_suspend_mode,
};
-static struct regulator_ops da9063_ldo_ops = {
+static const struct regulator_ops da9063_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
index b3517830edb6..8b3cc9f0cd64 100644
--- a/drivers/regulator/da9210-regulator.c
+++ b/drivers/regulator/da9210-regulator.c
@@ -46,7 +46,7 @@ static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
int max_uA);
static int da9210_get_current_limit(struct regulator_dev *rdev);
-static struct regulator_ops da9210_buck_ops = {
+static const struct regulator_ops da9210_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index 04ef65b7eb3d..236abf473db5 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -219,7 +219,7 @@ static int da9211_get_current_limit(struct regulator_dev *rdev)
return current_limits[data];
}
-static struct regulator_ops da9211_buck_ops = {
+static const struct regulator_ops da9211_buck_ops = {
.get_mode = da9211_buck_get_mode,
.set_mode = da9211_buck_set_mode,
.enable = regulator_enable_regmap,
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 6ec1d400adae..6ad8ab4c578d 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -164,8 +164,11 @@ int devm_regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = NULL;
for (i = 0; i < num_consumers; i++) {
- consumers[i].consumer = devm_regulator_get(dev,
- consumers[i].supply);
+ consumers[i].consumer = _devm_regulator_get(dev,
+ consumers[i].supply,
+ consumers[i].optional ?
+ OPTIONAL_GET :
+ NORMAL_GET);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
dev_err(dev, "Failed to get supply '%s': %d\n",
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
new file mode 100644
index 000000000000..f53e63301a20
--- /dev/null
+++ b/drivers/regulator/lm363x-regulator.c
@@ -0,0 +1,291 @@
+/*
+ * TI LM363X Regulator Driver
+ *
+ * Copyright 2015 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@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/err.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/* LM3631 */
+#define LM3631_BOOST_VSEL_MAX 0x25
+#define LM3631_LDO_VSEL_MAX 0x28
+#define LM3631_CONT_VSEL_MAX 0x03
+#define LM3631_VBOOST_MIN 4500000
+#define LM3631_VCONT_MIN 1800000
+#define LM3631_VLDO_MIN 4000000
+#define ENABLE_TIME_USEC 1000
+
+/* LM3632 */
+#define LM3632_BOOST_VSEL_MAX 0x26
+#define LM3632_LDO_VSEL_MAX 0x29
+#define LM3632_VBOOST_MIN 4500000
+#define LM3632_VLDO_MIN 4000000
+
+/* Common */
+#define LM363X_STEP_50mV 50000
+#define LM363X_STEP_500mV 500000
+
+static const int ldo_cont_enable_time[] = {
+ 0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
+};
+
+static int lm363x_regulator_enable_time(struct regulator_dev *rdev)
+{
+ enum lm363x_regulator_id id = rdev_get_id(rdev);
+ u8 val, addr, mask;
+
+ switch (id) {
+ case LM3631_LDO_CONT:
+ addr = LM3631_REG_ENTIME_VCONT;
+ mask = LM3631_ENTIME_CONT_MASK;
+ break;
+ case LM3631_LDO_OREF:
+ addr = LM3631_REG_ENTIME_VOREF;
+ mask = LM3631_ENTIME_MASK;
+ break;
+ case LM3631_LDO_POS:
+ addr = LM3631_REG_ENTIME_VPOS;
+ mask = LM3631_ENTIME_MASK;
+ break;
+ case LM3631_LDO_NEG:
+ addr = LM3631_REG_ENTIME_VNEG;
+ mask = LM3631_ENTIME_MASK;
+ break;
+ default:
+ return 0;
+ }
+
+ if (regmap_read(rdev->regmap, addr, (unsigned int *)&val))
+ return -EINVAL;
+
+ val = (val & mask) >> LM3631_ENTIME_SHIFT;
+
+ if (id == LM3631_LDO_CONT)
+ return ldo_cont_enable_time[val];
+ else
+ return ENABLE_TIME_USEC * val;
+}
+
+static struct regulator_ops lm363x_boost_voltage_table_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops lm363x_regulator_voltage_table_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lm363x_regulator_enable_time,
+};
+
+static const struct regulator_desc lm363x_regulator_desc[] = {
+ /* LM3631 */
+ {
+ .name = "vboost",
+ .of_match = "vboost",
+ .id = LM3631_BOOST,
+ .ops = &lm363x_boost_voltage_table_ops,
+ .n_voltages = LM3631_BOOST_VSEL_MAX + 1,
+ .min_uV = LM3631_VBOOST_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_BOOST,
+ .vsel_mask = LM3631_VOUT_MASK,
+ },
+ {
+ .name = "ldo_cont",
+ .of_match = "vcont",
+ .id = LM3631_LDO_CONT,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM3631_CONT_VSEL_MAX + 1,
+ .min_uV = LM3631_VCONT_MIN,
+ .uV_step = LM363X_STEP_500mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_CONT,
+ .vsel_mask = LM3631_VOUT_CONT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL2,
+ .enable_mask = LM3631_EN_CONT_MASK,
+ },
+ {
+ .name = "ldo_oref",
+ .of_match = "voref",
+ .id = LM3631_LDO_OREF,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM3631_LDO_VSEL_MAX + 1,
+ .min_uV = LM3631_VLDO_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_OREF,
+ .vsel_mask = LM3631_VOUT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL1,
+ .enable_mask = LM3631_EN_OREF_MASK,
+ },
+ {
+ .name = "ldo_vpos",
+ .of_match = "vpos",
+ .id = LM3631_LDO_POS,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM3631_LDO_VSEL_MAX + 1,
+ .min_uV = LM3631_VLDO_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_POS,
+ .vsel_mask = LM3631_VOUT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL1,
+ .enable_mask = LM3631_EN_VPOS_MASK,
+ },
+ {
+ .name = "ldo_vneg",
+ .of_match = "vneg",
+ .id = LM3631_LDO_NEG,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM3631_LDO_VSEL_MAX + 1,
+ .min_uV = LM3631_VLDO_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_NEG,
+ .vsel_mask = LM3631_VOUT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL1,
+ .enable_mask = LM3631_EN_VNEG_MASK,
+ },
+ /* LM3632 */
+ {
+ .name = "vboost",
+ .of_match = "vboost",
+ .id = LM3632_BOOST,
+ .ops = &lm363x_boost_voltage_table_ops,
+ .n_voltages = LM3632_BOOST_VSEL_MAX + 1,
+ .min_uV = LM3632_VBOOST_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3632_REG_VOUT_BOOST,
+ .vsel_mask = LM3632_VOUT_MASK,
+ },
+ {
+ .name = "ldo_vpos",
+ .of_match = "vpos",
+ .id = LM3632_LDO_POS,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM3632_LDO_VSEL_MAX + 1,
+ .min_uV = LM3632_VLDO_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3632_REG_VOUT_POS,
+ .vsel_mask = LM3632_VOUT_MASK,
+ .enable_reg = LM3632_REG_BIAS_CONFIG,
+ .enable_mask = LM3632_EN_VPOS_MASK,
+ },
+ {
+ .name = "ldo_vneg",
+ .of_match = "vneg",
+ .id = LM3632_LDO_NEG,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM3632_LDO_VSEL_MAX + 1,
+ .min_uV = LM3632_VLDO_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3632_REG_VOUT_NEG,
+ .vsel_mask = LM3632_VOUT_MASK,
+ .enable_reg = LM3632_REG_BIAS_CONFIG,
+ .enable_mask = LM3632_EN_VNEG_MASK,
+ },
+};
+
+static int lm363x_regulator_of_get_enable_gpio(struct device_node *np, int id)
+{
+ /*
+ * Check LCM_EN1/2_GPIO is configured.
+ * Those pins are used for enabling VPOS/VNEG LDOs.
+ */
+ switch (id) {
+ case LM3632_LDO_POS:
+ return of_get_named_gpio(np, "ti,lcm-en1-gpio", 0);
+ case LM3632_LDO_NEG:
+ return of_get_named_gpio(np, "ti,lcm-en2-gpio", 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lm363x_regulator_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct regmap *regmap = lmu->regmap;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ struct device *dev = &pdev->dev;
+ int id = pdev->id;
+ int ret, ena_gpio;
+
+ cfg.dev = dev;
+ cfg.regmap = regmap;
+
+ /*
+ * LM3632 LDOs can be controlled by external pin.
+ * Register update is required if the pin is used.
+ */
+ ena_gpio = lm363x_regulator_of_get_enable_gpio(dev->of_node, id);
+ if (gpio_is_valid(ena_gpio)) {
+ cfg.ena_gpio = ena_gpio;
+ cfg.ena_gpio_flags = GPIOF_OUT_INIT_LOW;
+
+ ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG,
+ LM3632_EXT_EN_MASK,
+ LM3632_EXT_EN_MASK);
+ if (ret) {
+ dev_err(dev, "External pin err: %d\n", ret);
+ return ret;
+ }
+ }
+
+ rdev = devm_regulator_register(dev, &lm363x_regulator_desc[id], &cfg);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "[%d] regulator register err: %d\n", id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver lm363x_regulator_driver = {
+ .probe = lm363x_regulator_probe,
+ .driver = {
+ .name = "lm363x-regulator",
+ },
+};
+
+module_platform_driver(lm363x_regulator_driver);
+
+MODULE_DESCRIPTION("TI LM363X Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lm363x-regulator");
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index e5af07208f9d..19d758486553 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -108,7 +108,6 @@ struct lp872x {
struct lp872x_platform_data *pdata;
int num_regulators;
enum lp872x_dvs_state dvs_pin;
- int dvs_gpio;
};
/* LP8720/LP8725 shared voltage table for LDOs */
@@ -520,6 +519,7 @@ static struct regulator_ops lp8725_buck_ops = {
static struct regulator_desc lp8720_regulator_desc[] = {
{
.name = "ldo1",
+ .of_match = of_match_ptr("ldo1"),
.id = LP8720_ID_LDO1,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -533,6 +533,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo2",
+ .of_match = of_match_ptr("ldo2"),
.id = LP8720_ID_LDO2,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -546,6 +547,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo3",
+ .of_match = of_match_ptr("ldo3"),
.id = LP8720_ID_LDO3,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -559,6 +561,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo4",
+ .of_match = of_match_ptr("ldo4"),
.id = LP8720_ID_LDO4,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp8720_ldo4_vtbl),
@@ -572,6 +575,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo5",
+ .of_match = of_match_ptr("ldo5"),
.id = LP8720_ID_LDO5,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -585,6 +589,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "buck",
+ .of_match = of_match_ptr("buck"),
.id = LP8720_ID_BUCK,
.ops = &lp8720_buck_ops,
.n_voltages = ARRAY_SIZE(lp8720_buck_vtbl),
@@ -599,6 +604,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
static struct regulator_desc lp8725_regulator_desc[] = {
{
.name = "ldo1",
+ .of_match = of_match_ptr("ldo1"),
.id = LP8725_ID_LDO1,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -612,6 +618,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo2",
+ .of_match = of_match_ptr("ldo2"),
.id = LP8725_ID_LDO2,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -625,6 +632,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo3",
+ .of_match = of_match_ptr("ldo3"),
.id = LP8725_ID_LDO3,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -638,6 +646,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo4",
+ .of_match = of_match_ptr("ldo4"),
.id = LP8725_ID_LDO4,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -651,6 +660,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo5",
+ .of_match = of_match_ptr("ldo5"),
.id = LP8725_ID_LDO5,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@@ -664,6 +674,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "lilo1",
+ .of_match = of_match_ptr("lilo1"),
.id = LP8725_ID_LILO1,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
@@ -677,6 +688,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "lilo2",
+ .of_match = of_match_ptr("lilo2"),
.id = LP8725_ID_LILO2,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
@@ -690,6 +702,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "buck1",
+ .of_match = of_match_ptr("buck1"),
.id = LP8725_ID_BUCK1,
.ops = &lp8725_buck_ops,
.n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
@@ -701,6 +714,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "buck2",
+ .of_match = of_match_ptr("buck2"),
.id = LP8725_ID_BUCK2,
.ops = &lp8725_buck_ops,
.n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
@@ -737,7 +751,6 @@ static int lp872x_init_dvs(struct lp872x *lp)
}
lp->dvs_pin = pinstate;
- lp->dvs_gpio = gpio;
return 0;
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
index a97bed90d39b..ec46290b647e 100644
--- a/drivers/regulator/lp8788-buck.c
+++ b/drivers/regulator/lp8788-buck.c
@@ -344,7 +344,7 @@ static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
}
-static struct regulator_ops lp8788_buck12_ops = {
+static const struct regulator_ops lp8788_buck12_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = lp8788_buck12_set_voltage_sel,
@@ -357,7 +357,7 @@ static struct regulator_ops lp8788_buck12_ops = {
.get_mode = lp8788_buck_get_mode,
};
-static struct regulator_ops lp8788_buck34_ops = {
+static const struct regulator_ops lp8788_buck34_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index 9f22d079c8cc..cbfd35873575 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -170,7 +170,7 @@ static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
return ENABLE_TIME_USEC * val;
}
-static struct regulator_ops lp8788_ldo_voltage_table_ops = {
+static const struct regulator_ops lp8788_ldo_voltage_table_ops = {
.list_voltage = regulator_list_voltage_table,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -180,7 +180,7 @@ static struct regulator_ops lp8788_ldo_voltage_table_ops = {
.enable_time = lp8788_ldo_enable_time,
};
-static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
+static const struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
.list_voltage = regulator_list_voltage_linear,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -613,22 +613,20 @@ static struct platform_driver lp8788_aldo_driver = {
},
};
+static struct platform_driver * const drivers[] = {
+ &lp8788_dldo_driver,
+ &lp8788_aldo_driver,
+};
+
static int __init lp8788_ldo_init(void)
{
- int ret;
-
- ret = platform_driver_register(&lp8788_dldo_driver);
- if (ret)
- return ret;
-
- return platform_driver_register(&lp8788_aldo_driver);
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(lp8788_ldo_init);
static void __exit lp8788_ldo_exit(void)
{
- platform_driver_unregister(&lp8788_aldo_driver);
- platform_driver_unregister(&lp8788_dldo_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(lp8788_ldo_exit);
diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c
index 02c4e5feca8e..0495716fd35f 100644
--- a/drivers/regulator/mt6311-regulator.c
+++ b/drivers/regulator/mt6311-regulator.c
@@ -30,6 +30,7 @@ static const struct regmap_config mt6311_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MT6311_FQMTR_CON4,
+ .cache_type = REGCACHE_RBTREE,
};
/* Default limits measured in millivolts and milliamps */
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 8217613807d3..6efc7ee8aea3 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -612,6 +612,18 @@ static struct regulator_ops palmas_ops_ldo = {
.map_voltage = regulator_map_voltage_linear,
};
+static struct regulator_ops palmas_ops_ldo9 = {
+ .is_enabled = palmas_is_enabled_ldo,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_bypass = regulator_set_bypass_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
+};
+
static struct regulator_ops palmas_ops_ext_control_ldo = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -639,6 +651,19 @@ static struct regulator_ops tps65917_ops_ldo = {
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
+static struct regulator_ops tps65917_ops_ldo_1_2 = {
+ .is_enabled = palmas_is_enabled_ldo,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_bypass = regulator_set_bypass_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
+};
+
static int palmas_regulator_config_external(struct palmas *palmas, int id,
struct palmas_reg_init *reg_init)
{
@@ -915,6 +940,13 @@ static int palmas_ldo_registration(struct palmas_pmic *pmic,
if (pdata && pdata->ldo6_vibrator &&
(id == PALMAS_REG_LDO6))
desc->enable_time = 2000;
+
+ if (id == PALMAS_REG_LDO9) {
+ desc->ops = &palmas_ops_ldo9;
+ desc->bypass_reg = desc->enable_reg;
+ desc->bypass_mask =
+ PALMAS_LDO9_CTRL_LDO_BYPASS_EN;
+ }
} else {
if (!ddata->has_regen3 && id == PALMAS_REG_REGEN3)
continue;
@@ -1019,6 +1051,13 @@ static int tps65917_ldo_registration(struct palmas_pmic *pmic,
* It is of the order of ~60mV/uS.
*/
desc->ramp_delay = 2500;
+ if (id == TPS65917_REG_LDO1 ||
+ id == TPS65917_REG_LDO2) {
+ desc->ops = &tps65917_ops_ldo_1_2;
+ desc->bypass_reg = desc->enable_reg;
+ desc->bypass_mask =
+ TPS65917_LDO1_CTRL_BYPASS_EN;
+ }
} else {
desc->n_voltages = 1;
if (reg_init && reg_init->roof_floor)
diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c
new file mode 100644
index 000000000000..094376c8de4b
--- /dev/null
+++ b/drivers/regulator/pv88060-regulator.c
@@ -0,0 +1,437 @@
+/*
+ * pv88060-regulator.c - Regulator device driver for PV88060
+ * Copyright (C) 2015 Powerventure Semiconductor 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.
+ *
+ * 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/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include "pv88060-regulator.h"
+
+#define PV88060_MAX_REGULATORS 14
+
+/* PV88060 REGULATOR IDs */
+enum {
+ /* BUCKs */
+ PV88060_ID_BUCK1,
+
+ /* LDOs */
+ PV88060_ID_LDO1,
+ PV88060_ID_LDO2,
+ PV88060_ID_LDO3,
+ PV88060_ID_LDO4,
+ PV88060_ID_LDO5,
+ PV88060_ID_LDO6,
+ PV88060_ID_LDO7,
+
+ /* SWTs */
+ PV88060_ID_SW1,
+ PV88060_ID_SW2,
+ PV88060_ID_SW3,
+ PV88060_ID_SW4,
+ PV88060_ID_SW5,
+ PV88060_ID_SW6,
+};
+
+struct pv88060_regulator {
+ struct regulator_desc desc;
+ /* Current limiting */
+ unsigned n_current_limits;
+ const int *current_limits;
+ unsigned int limit_mask;
+ unsigned int conf; /* buck configuration register */
+};
+
+struct pv88060 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator_dev *rdev[PV88060_MAX_REGULATORS];
+};
+
+static const struct regmap_config pv88060_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+/* Current limits array (in uA) for BUCK1
+ * Entry indexes corresponds to register values.
+ */
+
+static const int pv88060_buck1_limits[] = {
+ 1496000, 2393000, 3291000, 4189000
+};
+
+static unsigned int pv88060_buck_get_mode(struct regulator_dev *rdev)
+{
+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret, mode = 0;
+
+ ret = regmap_read(rdev->regmap, info->conf, &data);
+ if (ret < 0)
+ return ret;
+
+ switch (data & PV88060_BUCK_MODE_MASK) {
+ case PV88060_BUCK_MODE_SYNC:
+ mode = REGULATOR_MODE_FAST;
+ break;
+ case PV88060_BUCK_MODE_AUTO:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case PV88060_BUCK_MODE_SLEEP:
+ mode = REGULATOR_MODE_STANDBY;
+ break;
+ }
+
+ return mode;
+}
+
+static int pv88060_buck_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);
+ int val = 0;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = PV88060_BUCK_MODE_SYNC;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = PV88060_BUCK_MODE_AUTO;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val = PV88060_BUCK_MODE_SLEEP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(rdev->regmap, info->conf,
+ PV88060_BUCK_MODE_MASK, val);
+}
+
+static int pv88060_set_current_limit(struct regulator_dev *rdev, int min,
+ int max)
+{
+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);
+ int i;
+
+ /* search for closest to maximum */
+ for (i = info->n_current_limits; i >= 0; i--) {
+ if (min <= info->current_limits[i]
+ && max >= info->current_limits[i]) {
+ return regmap_update_bits(rdev->regmap,
+ info->conf,
+ info->limit_mask,
+ i << PV88060_BUCK_ILIM_SHIFT);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int pv88060_get_current_limit(struct regulator_dev *rdev)
+{
+ struct pv88060_regulator *info = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->conf, &data);
+ if (ret < 0)
+ return ret;
+
+ data = (data & info->limit_mask) >> PV88060_BUCK_ILIM_SHIFT;
+ return info->current_limits[data];
+}
+
+static struct regulator_ops pv88060_buck_ops = {
+ .get_mode = pv88060_buck_get_mode,
+ .set_mode = pv88060_buck_set_mode,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_current_limit = pv88060_set_current_limit,
+ .get_current_limit = pv88060_get_current_limit,
+};
+
+static struct regulator_ops pv88060_ldo_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PV88060_BUCK(chip, regl_name, min, step, max, limits_array) \
+{\
+ .desc = {\
+ .id = chip##_ID_##regl_name,\
+ .name = __stringify(chip##_##regl_name),\
+ .of_match = of_match_ptr(#regl_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &pv88060_buck_ops,\
+ .min_uV = min,\
+ .uV_step = step,\
+ .n_voltages = ((max) - (min))/(step) + 1,\
+ .enable_reg = PV88060_REG_##regl_name##_CONF0,\
+ .enable_mask = PV88060_BUCK_EN, \
+ .vsel_reg = PV88060_REG_##regl_name##_CONF0,\
+ .vsel_mask = PV88060_VBUCK_MASK,\
+ },\
+ .current_limits = limits_array,\
+ .n_current_limits = ARRAY_SIZE(limits_array),\
+ .limit_mask = PV88060_BUCK_ILIM_MASK, \
+ .conf = PV88060_REG_##regl_name##_CONF1,\
+}
+
+#define PV88060_LDO(chip, regl_name, min, step, max) \
+{\
+ .desc = {\
+ .id = chip##_ID_##regl_name,\
+ .name = __stringify(chip##_##regl_name),\
+ .of_match = of_match_ptr(#regl_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &pv88060_ldo_ops,\
+ .min_uV = min, \
+ .uV_step = step, \
+ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \
+ .enable_reg = PV88060_REG_##regl_name##_CONF, \
+ .enable_mask = PV88060_LDO_EN, \
+ .vsel_reg = PV88060_REG_##regl_name##_CONF, \
+ .vsel_mask = PV88060_VLDO_MASK, \
+ },\
+}
+
+#define PV88060_SW(chip, regl_name, max) \
+{\
+ .desc = {\
+ .id = chip##_ID_##regl_name,\
+ .name = __stringify(chip##_##regl_name),\
+ .of_match = of_match_ptr(#regl_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &pv88060_ldo_ops,\
+ .min_uV = max,\
+ .uV_step = 0,\
+ .n_voltages = 1,\
+ .enable_reg = PV88060_REG_##regl_name##_CONF,\
+ .enable_mask = PV88060_SW_EN,\
+ },\
+}
+
+static const struct pv88060_regulator pv88060_regulator_info[] = {
+ PV88060_BUCK(PV88060, BUCK1, 2800000, 12500, 4387500,
+ pv88060_buck1_limits),
+ PV88060_LDO(PV88060, LDO1, 1200000, 50000, 3350000),
+ PV88060_LDO(PV88060, LDO2, 1200000, 50000, 3350000),
+ PV88060_LDO(PV88060, LDO3, 1200000, 50000, 3350000),
+ PV88060_LDO(PV88060, LDO4, 1200000, 50000, 3350000),
+ PV88060_LDO(PV88060, LDO5, 1200000, 50000, 3350000),
+ PV88060_LDO(PV88060, LDO6, 1200000, 50000, 3350000),
+ PV88060_LDO(PV88060, LDO7, 1200000, 50000, 3350000),
+ PV88060_SW(PV88060, SW1, 5000000),
+ PV88060_SW(PV88060, SW2, 5000000),
+ PV88060_SW(PV88060, SW3, 5000000),
+ PV88060_SW(PV88060, SW4, 5000000),
+ PV88060_SW(PV88060, SW5, 5000000),
+ PV88060_SW(PV88060, SW6, 5000000),
+};
+
+static irqreturn_t pv88060_irq_handler(int irq, void *data)
+{
+ struct pv88060 *chip = data;
+ int i, reg_val, err, ret = IRQ_NONE;
+
+ err = regmap_read(chip->regmap, PV88060_REG_EVENT_A, &reg_val);
+ if (err < 0)
+ goto error_i2c;
+
+ if (reg_val & PV88060_E_VDD_FLT) {
+ for (i = 0; i < PV88060_MAX_REGULATORS; i++) {
+ if (chip->rdev[i] != NULL) {
+ regulator_notifier_call_chain(chip->rdev[i],
+ REGULATOR_EVENT_UNDER_VOLTAGE,
+ NULL);
+ }
+ }
+
+ err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
+ PV88060_E_VDD_FLT, PV88060_E_VDD_FLT);
+ if (err < 0)
+ goto error_i2c;
+
+ ret = IRQ_HANDLED;
+ }
+
+ if (reg_val & PV88060_E_OVER_TEMP) {
+ for (i = 0; i < PV88060_MAX_REGULATORS; i++) {
+ if (chip->rdev[i] != NULL) {
+ regulator_notifier_call_chain(chip->rdev[i],
+ REGULATOR_EVENT_OVER_TEMP,
+ NULL);
+ }
+ }
+
+ err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
+ PV88060_E_OVER_TEMP, PV88060_E_OVER_TEMP);
+ if (err < 0)
+ goto error_i2c;
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+
+error_i2c:
+ dev_err(chip->dev, "I2C error : %d\n", err);
+ return IRQ_NONE;
+}
+
+/*
+ * I2C driver interface functions
+ */
+static int pv88060_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
+ struct pv88060 *chip;
+ struct regulator_config config = { };
+ int error, i, ret = 0;
+
+ chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88060), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &i2c->dev;
+ chip->regmap = devm_regmap_init_i2c(i2c, &pv88060_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(chip->dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ i2c_set_clientdata(i2c, chip);
+
+ if (i2c->irq != 0) {
+ ret = regmap_write(chip->regmap, PV88060_REG_MASK_A, 0xFF);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to mask A reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_write(chip->regmap, PV88060_REG_MASK_B, 0xFF);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to mask B reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_write(chip->regmap, PV88060_REG_MASK_C, 0xFF);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to mask C reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+ pv88060_irq_handler,
+ IRQF_TRIGGER_LOW|IRQF_ONESHOT,
+ "pv88060", chip);
+ if (ret != 0) {
+ dev_err(chip->dev, "Failed to request IRQ: %d\n",
+ i2c->irq);
+ return ret;
+ }
+
+ ret = regmap_update_bits(chip->regmap, PV88060_REG_MASK_A,
+ PV88060_M_VDD_FLT | PV88060_M_OVER_TEMP, 0);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to update mask reg: %d\n", ret);
+ return ret;
+ }
+
+ } else {
+ dev_warn(chip->dev, "No IRQ configured\n");
+ }
+
+ config.dev = chip->dev;
+ config.regmap = chip->regmap;
+
+ for (i = 0; i < PV88060_MAX_REGULATORS; i++) {
+ if (init_data)
+ config.init_data = &init_data[i];
+
+ config.driver_data = (void *)&pv88060_regulator_info[i];
+ chip->rdev[i] = devm_regulator_register(chip->dev,
+ &pv88060_regulator_info[i].desc, &config);
+ if (IS_ERR(chip->rdev[i])) {
+ dev_err(chip->dev,
+ "Failed to register PV88060 regulator\n");
+ return PTR_ERR(chip->rdev[i]);
+ }
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id pv88060_i2c_id[] = {
+ {"pv88060", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, pv88060_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pv88060_dt_ids[] = {
+ { .compatible = "pvs,pv88060", .data = &pv88060_i2c_id[0] },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pv88060_dt_ids);
+#endif
+
+static struct i2c_driver pv88060_regulator_driver = {
+ .driver = {
+ .name = "pv88060",
+ .of_match_table = of_match_ptr(pv88060_dt_ids),
+ },
+ .probe = pv88060_i2c_probe,
+ .id_table = pv88060_i2c_id,
+};
+
+module_i2c_driver(pv88060_regulator_driver);
+
+MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88060");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pv88060-regulator.h b/drivers/regulator/pv88060-regulator.h
new file mode 100644
index 000000000000..02ca9203a172
--- /dev/null
+++ b/drivers/regulator/pv88060-regulator.h
@@ -0,0 +1,69 @@
+/*
+ * pv88060-regulator.h - Regulator definitions for PV88060
+ * Copyright (C) 2015 Powerventure Semiconductor 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.
+ *
+ * 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 __PV88060_REGISTERS_H__
+#define __PV88060_REGISTERS_H__
+
+/* System Control and Event Registers */
+#define PV88060_REG_EVENT_A 0x04
+#define PV88060_REG_MASK_A 0x08
+#define PV88060_REG_MASK_B 0x09
+#define PV88060_REG_MASK_C 0x0A
+
+/* Regulator Registers */
+#define PV88060_REG_BUCK1_CONF0 0x1B
+#define PV88060_REG_BUCK1_CONF1 0x1C
+#define PV88060_REG_LDO1_CONF 0x1D
+#define PV88060_REG_LDO2_CONF 0x1E
+#define PV88060_REG_LDO3_CONF 0x1F
+#define PV88060_REG_LDO4_CONF 0x20
+#define PV88060_REG_LDO5_CONF 0x21
+#define PV88060_REG_LDO6_CONF 0x22
+#define PV88060_REG_LDO7_CONF 0x23
+
+#define PV88060_REG_SW1_CONF 0x3B
+#define PV88060_REG_SW2_CONF 0x3C
+#define PV88060_REG_SW3_CONF 0x3D
+#define PV88060_REG_SW4_CONF 0x3E
+#define PV88060_REG_SW5_CONF 0x3F
+#define PV88060_REG_SW6_CONF 0x40
+
+/* PV88060_REG_EVENT_A (addr=0x04) */
+#define PV88060_E_VDD_FLT 0x01
+#define PV88060_E_OVER_TEMP 0x02
+
+/* PV88060_REG_MASK_A (addr=0x08) */
+#define PV88060_M_VDD_FLT 0x01
+#define PV88060_M_OVER_TEMP 0x02
+
+/* PV88060_REG_BUCK1_CONF0 (addr=0x1B) */
+#define PV88060_BUCK_EN 0x80
+#define PV88060_VBUCK_MASK 0x7F
+/* PV88060_REG_LDO1/2/3/4/5/6/7_CONT */
+#define PV88060_LDO_EN 0x40
+#define PV88060_VLDO_MASK 0x3F
+/* PV88060_REG_SW1/2/3/4/5_CONF */
+#define PV88060_SW_EN 0x80
+
+/* PV88060_REG_BUCK1_CONF1 (addr=0x1C) */
+#define PV88060_BUCK_ILIM_SHIFT 2
+#define PV88060_BUCK_ILIM_MASK 0x0C
+#define PV88060_BUCK_MODE_SHIFT 0
+#define PV88060_BUCK_MODE_MASK 0x03
+#define PV88060_BUCK_MODE_SLEEP 0x00
+#define PV88060_BUCK_MODE_AUTO 0x01
+#define PV88060_BUCK_MODE_SYNC 0x02
+
+#endif /* __PV88060_REGISTERS_H__ */
diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c
new file mode 100644
index 000000000000..ac15f31b5fe0
--- /dev/null
+++ b/drivers/regulator/pv88090-regulator.c
@@ -0,0 +1,458 @@
+/*
+ * pv88090-regulator.c - Regulator device driver for PV88090
+ * Copyright (C) 2015 Powerventure Semiconductor 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.
+ *
+ * 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/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include "pv88090-regulator.h"
+
+#define PV88090_MAX_REGULATORS 5
+
+/* PV88090 REGULATOR IDs */
+enum {
+ /* BUCKs */
+ PV88090_ID_BUCK1,
+ PV88090_ID_BUCK2,
+ PV88090_ID_BUCK3,
+
+ /* LDOs */
+ PV88090_ID_LDO1,
+ PV88090_ID_LDO2,
+};
+
+struct pv88090_regulator {
+ struct regulator_desc desc;
+ /* Current limiting */
+ unsigned n_current_limits;
+ const int *current_limits;
+ unsigned int limit_mask;
+ unsigned int conf;
+ unsigned int conf2;
+};
+
+struct pv88090 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator_dev *rdev[PV88090_MAX_REGULATORS];
+};
+
+struct pv88090_buck_voltage {
+ int min_uV;
+ int max_uV;
+ int uV_step;
+};
+
+static const struct regmap_config pv88090_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
+ * Entry indexes corresponds to register values.
+ */
+
+static const int pv88090_buck1_limits[] = {
+ 220000, 440000, 660000, 880000, 1100000, 1320000, 1540000, 1760000,
+ 1980000, 2200000, 2420000, 2640000, 2860000, 3080000, 3300000, 3520000,
+ 3740000, 3960000, 4180000, 4400000, 4620000, 4840000, 5060000, 5280000,
+ 5500000, 5720000, 5940000, 6160000, 6380000, 6600000, 6820000, 7040000
+};
+
+static const int pv88090_buck23_limits[] = {
+ 1496000, 2393000, 3291000, 4189000
+};
+
+static const struct pv88090_buck_voltage pv88090_buck_vol[3] = {
+ {
+ .min_uV = 600000,
+ .max_uV = 1393750,
+ .uV_step = 6250,
+ },
+
+ {
+ .min_uV = 1400000,
+ .max_uV = 2193750,
+ .uV_step = 6250,
+ },
+ {
+ .min_uV = 1250000,
+ .max_uV = 2837500,
+ .uV_step = 12500,
+ },
+};
+
+static unsigned int pv88090_buck_get_mode(struct regulator_dev *rdev)
+{
+ struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret, mode = 0;
+
+ ret = regmap_read(rdev->regmap, info->conf, &data);
+ if (ret < 0)
+ return ret;
+
+ switch (data & PV88090_BUCK1_MODE_MASK) {
+ case PV88090_BUCK_MODE_SYNC:
+ mode = REGULATOR_MODE_FAST;
+ break;
+ case PV88090_BUCK_MODE_AUTO:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case PV88090_BUCK_MODE_SLEEP:
+ mode = REGULATOR_MODE_STANDBY;
+ break;
+ }
+
+ return mode;
+}
+
+static int pv88090_buck_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+ int val = 0;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = PV88090_BUCK_MODE_SYNC;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = PV88090_BUCK_MODE_AUTO;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val = PV88090_BUCK_MODE_SLEEP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(rdev->regmap, info->conf,
+ PV88090_BUCK1_MODE_MASK, val);
+}
+
+static int pv88090_set_current_limit(struct regulator_dev *rdev, int min,
+ int max)
+{
+ struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+ int i;
+
+ /* search for closest to maximum */
+ for (i = info->n_current_limits; i >= 0; i--) {
+ if (min <= info->current_limits[i]
+ && max >= info->current_limits[i]) {
+ return regmap_update_bits(rdev->regmap,
+ info->conf,
+ info->limit_mask,
+ i << PV88090_BUCK1_ILIM_SHIFT);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int pv88090_get_current_limit(struct regulator_dev *rdev)
+{
+ struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->conf, &data);
+ if (ret < 0)
+ return ret;
+
+ data = (data & info->limit_mask) >> PV88090_BUCK1_ILIM_SHIFT;
+ return info->current_limits[data];
+}
+
+static struct regulator_ops pv88090_buck_ops = {
+ .get_mode = pv88090_buck_get_mode,
+ .set_mode = pv88090_buck_set_mode,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_current_limit = pv88090_set_current_limit,
+ .get_current_limit = pv88090_get_current_limit,
+};
+
+static struct regulator_ops pv88090_ldo_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PV88090_BUCK(chip, regl_name, min, step, max, limits_array) \
+{\
+ .desc = {\
+ .id = chip##_ID_##regl_name,\
+ .name = __stringify(chip##_##regl_name),\
+ .of_match = of_match_ptr(#regl_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &pv88090_buck_ops,\
+ .min_uV = min, \
+ .uV_step = step, \
+ .n_voltages = ((max) - (min))/(step) + 1, \
+ .enable_reg = PV88090_REG_##regl_name##_CONF0, \
+ .enable_mask = PV88090_##regl_name##_EN, \
+ .vsel_reg = PV88090_REG_##regl_name##_CONF0, \
+ .vsel_mask = PV88090_V##regl_name##_MASK, \
+ },\
+ .current_limits = limits_array, \
+ .n_current_limits = ARRAY_SIZE(limits_array), \
+ .limit_mask = PV88090_##regl_name##_ILIM_MASK, \
+ .conf = PV88090_REG_##regl_name##_CONF1, \
+ .conf2 = PV88090_REG_##regl_name##_CONF2, \
+}
+
+#define PV88090_LDO(chip, regl_name, min, step, max) \
+{\
+ .desc = {\
+ .id = chip##_ID_##regl_name,\
+ .name = __stringify(chip##_##regl_name),\
+ .of_match = of_match_ptr(#regl_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &pv88090_ldo_ops,\
+ .min_uV = min, \
+ .uV_step = step, \
+ .n_voltages = ((max) - (min))/(step) + 1, \
+ .enable_reg = PV88090_REG_##regl_name##_CONT, \
+ .enable_mask = PV88090_##regl_name##_EN, \
+ .vsel_reg = PV88090_REG_##regl_name##_CONT, \
+ .vsel_mask = PV88090_V##regl_name##_MASK, \
+ },\
+}
+
+static struct pv88090_regulator pv88090_regulator_info[] = {
+ PV88090_BUCK(PV88090, BUCK1, 600000, 6250, 1393750,
+ pv88090_buck1_limits),
+ PV88090_BUCK(PV88090, BUCK2, 600000, 6250, 1393750,
+ pv88090_buck23_limits),
+ PV88090_BUCK(PV88090, BUCK3, 600000, 6250, 1393750,
+ pv88090_buck23_limits),
+ PV88090_LDO(PV88090, LDO1, 1200000, 50000, 4350000),
+ PV88090_LDO(PV88090, LDO2, 650000, 25000, 2225000),
+};
+
+static irqreturn_t pv88090_irq_handler(int irq, void *data)
+{
+ struct pv88090 *chip = data;
+ int i, reg_val, err, ret = IRQ_NONE;
+
+ err = regmap_read(chip->regmap, PV88090_REG_EVENT_A, &reg_val);
+ if (err < 0)
+ goto error_i2c;
+
+ if (reg_val & PV88090_E_VDD_FLT) {
+ for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
+ if (chip->rdev[i] != NULL) {
+ regulator_notifier_call_chain(chip->rdev[i],
+ REGULATOR_EVENT_UNDER_VOLTAGE,
+ NULL);
+ }
+ }
+
+ err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
+ PV88090_E_VDD_FLT, PV88090_E_VDD_FLT);
+ if (err < 0)
+ goto error_i2c;
+
+ ret = IRQ_HANDLED;
+ }
+
+ if (reg_val & PV88090_E_OVER_TEMP) {
+ for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
+ if (chip->rdev[i] != NULL) {
+ regulator_notifier_call_chain(chip->rdev[i],
+ REGULATOR_EVENT_OVER_TEMP,
+ NULL);
+ }
+ }
+
+ err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
+ PV88090_E_OVER_TEMP, PV88090_E_OVER_TEMP);
+ if (err < 0)
+ goto error_i2c;
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+
+error_i2c:
+ dev_err(chip->dev, "I2C error : %d\n", err);
+ return IRQ_NONE;
+}
+
+/*
+ * I2C driver interface functions
+ */
+static int pv88090_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
+ struct pv88090 *chip;
+ struct regulator_config config = { };
+ int error, i, ret = 0;
+ unsigned int conf2, range, index;
+
+ chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88090), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &i2c->dev;
+ chip->regmap = devm_regmap_init_i2c(i2c, &pv88090_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(chip->dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ i2c_set_clientdata(i2c, chip);
+
+ if (i2c->irq != 0) {
+ ret = regmap_write(chip->regmap, PV88090_REG_MASK_A, 0xFF);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to mask A reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_write(chip->regmap, PV88090_REG_MASK_B, 0xFF);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to mask B reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+ pv88090_irq_handler,
+ IRQF_TRIGGER_LOW|IRQF_ONESHOT,
+ "pv88090", chip);
+ if (ret != 0) {
+ dev_err(chip->dev, "Failed to request IRQ: %d\n",
+ i2c->irq);
+ return ret;
+ }
+
+ ret = regmap_update_bits(chip->regmap, PV88090_REG_MASK_A,
+ PV88090_M_VDD_FLT | PV88090_M_OVER_TEMP, 0);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to update mask reg: %d\n", ret);
+ return ret;
+ }
+
+ } else {
+ dev_warn(chip->dev, "No IRQ configured\n");
+ }
+
+ config.dev = chip->dev;
+ config.regmap = chip->regmap;
+
+ for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
+ if (init_data)
+ config.init_data = &init_data[i];
+
+ if (i == PV88090_ID_BUCK2 || i == PV88090_ID_BUCK3) {
+ ret = regmap_read(chip->regmap,
+ pv88090_regulator_info[i].conf2, &conf2);
+ if (ret < 0)
+ return ret;
+
+ conf2 = (conf2 >> PV88090_BUCK_VDAC_RANGE_SHIFT) &
+ PV88090_BUCK_VDAC_RANGE_MASK;
+
+ ret = regmap_read(chip->regmap,
+ PV88090_REG_BUCK_FOLD_RANGE, &range);
+ if (ret < 0)
+ return ret;
+
+ range = (range >>
+ (PV88080_BUCK_VRANGE_GAIN_SHIFT + i - 1)) &
+ PV88080_BUCK_VRANGE_GAIN_MASK;
+ index = ((range << 1) | conf2);
+
+ pv88090_regulator_info[i].desc.min_uV
+ = pv88090_buck_vol[index].min_uV;
+ pv88090_regulator_info[i].desc.uV_step
+ = pv88090_buck_vol[index].uV_step;
+ pv88090_regulator_info[i].desc.n_voltages
+ = ((pv88090_buck_vol[index].max_uV)
+ - (pv88090_buck_vol[index].min_uV))
+ /(pv88090_buck_vol[index].uV_step) + 1;
+ }
+
+ config.driver_data = (void *)&pv88090_regulator_info[i];
+ chip->rdev[i] = devm_regulator_register(chip->dev,
+ &pv88090_regulator_info[i].desc, &config);
+ if (IS_ERR(chip->rdev[i])) {
+ dev_err(chip->dev,
+ "Failed to register PV88090 regulator\n");
+ return PTR_ERR(chip->rdev[i]);
+ }
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id pv88090_i2c_id[] = {
+ {"pv88090", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pv88090_dt_ids[] = {
+ { .compatible = "pvs,pv88090", .data = &pv88090_i2c_id[0] },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pv88090_dt_ids);
+#endif
+
+static struct i2c_driver pv88090_regulator_driver = {
+ .driver = {
+ .name = "pv88090",
+ .of_match_table = of_match_ptr(pv88090_dt_ids),
+ },
+ .probe = pv88090_i2c_probe,
+ .id_table = pv88090_i2c_id,
+};
+
+module_i2c_driver(pv88090_regulator_driver);
+
+MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88090");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pv88090-regulator.h b/drivers/regulator/pv88090-regulator.h
new file mode 100644
index 000000000000..d7aca8d8266d
--- /dev/null
+++ b/drivers/regulator/pv88090-regulator.h
@@ -0,0 +1,98 @@
+/*
+ * pv88090-regulator.h - Regulator definitions for PV88090
+ * Copyright (C) 2015 Powerventure Semiconductor 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.
+ *
+ * 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 __PV88090_REGISTERS_H__
+#define __PV88090_REGISTERS_H__
+
+/* System Control and Event Registers */
+#define PV88090_REG_EVENT_A 0x03
+#define PV88090_REG_MASK_A 0x06
+#define PV88090_REG_MASK_B 0x07
+
+/* Regulator Registers */
+#define PV88090_REG_BUCK1_CONF0 0x18
+#define PV88090_REG_BUCK1_CONF1 0x19
+#define PV88090_REG_BUCK1_CONF2 0x1a
+#define PV88090_REG_BUCK2_CONF0 0x1b
+#define PV88090_REG_BUCK2_CONF1 0x1c
+#define PV88090_REG_BUCK2_CONF2 0x58
+#define PV88090_REG_BUCK3_CONF0 0x1d
+#define PV88090_REG_BUCK3_CONF1 0x1e
+#define PV88090_REG_BUCK3_CONF2 0x5c
+
+#define PV88090_REG_LDO1_CONT 0x1f
+#define PV88090_REG_LDO2_CONT 0x20
+#define PV88090_REG_LDO3_CONT 0x21
+#define PV88090_REG_BUCK_FOLD_RANGE 0x61
+
+/* PV88090_REG_EVENT_A (addr=0x03) */
+#define PV88090_E_VDD_FLT 0x01
+#define PV88090_E_OVER_TEMP 0x02
+
+/* PV88090_REG_MASK_A (addr=0x06) */
+#define PV88090_M_VDD_FLT 0x01
+#define PV88090_M_OVER_TEMP 0x02
+
+/* PV88090_REG_BUCK1_CONF0 (addr=0x18) */
+#define PV88090_BUCK1_EN 0x80
+#define PV88090_VBUCK1_MASK 0x7F
+/* PV88090_REG_BUCK2_CONF0 (addr=0x1b) */
+#define PV88090_BUCK2_EN 0x80
+#define PV88090_VBUCK2_MASK 0x7F
+/* PV88090_REG_BUCK3_CONF0 (addr=0x1d) */
+#define PV88090_BUCK3_EN 0x80
+#define PV88090_VBUCK3_MASK 0x7F
+/* PV88090_REG_LDO1_CONT (addr=0x1f) */
+#define PV88090_LDO1_EN 0x40
+#define PV88090_VLDO1_MASK 0x3F
+/* PV88090_REG_LDO2_CONT (addr=0x20) */
+#define PV88090_LDO2_EN 0x40
+#define PV88090_VLDO2_MASK 0x3F
+
+/* PV88090_REG_BUCK1_CONF1 (addr=0x19) */
+#define PV88090_BUCK1_ILIM_SHIFT 2
+#define PV88090_BUCK1_ILIM_MASK 0x7C
+#define PV88090_BUCK1_MODE_MASK 0x03
+
+/* PV88090_REG_BUCK2_CONF1 (addr=0x1c) */
+#define PV88090_BUCK2_ILIM_SHIFT 2
+#define PV88090_BUCK2_ILIM_MASK 0x0C
+#define PV88090_BUCK2_MODE_MASK 0x03
+
+/* PV88090_REG_BUCK3_CONF1 (addr=0x1e) */
+#define PV88090_BUCK3_ILIM_SHIFT 2
+#define PV88090_BUCK3_ILIM_MASK 0x0C
+#define PV88090_BUCK3_MODE_MASK 0x03
+
+#define PV88090_BUCK_MODE_SLEEP 0x00
+#define PV88090_BUCK_MODE_AUTO 0x01
+#define PV88090_BUCK_MODE_SYNC 0x02
+
+/* PV88090_REG_BUCK2_CONF2 (addr=0x58) */
+/* PV88090_REG_BUCK3_CONF2 (addr=0x5c) */
+#define PV88090_BUCK_VDAC_RANGE_SHIFT 7
+#define PV88090_BUCK_VDAC_RANGE_MASK 0x01
+
+#define PV88090_BUCK_VDAC_RANGE_1 0x00
+#define PV88090_BUCK_VDAC_RANGE_2 0x01
+
+/* PV88090_REG_BUCK_FOLD_RANGE (addr=0x61) */
+#define PV88080_BUCK_VRANGE_GAIN_SHIFT 3
+#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
+
+#define PV88080_BUCK_VRANGE_GAIN_1 0x00
+#define PV88080_BUCK_VRANGE_GAIN_2 0x01
+
+#endif /* __PV88090_REGISTERS_H__ */
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index 6fa0c7d13290..56a17ec5b5ef 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -153,6 +153,49 @@ static const struct regulator_ops rpm_switch_ops = {
.is_enabled = rpm_reg_is_enabled,
};
+static const struct regulator_desc pma8084_hfsmps = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
+ REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 159,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_ftsmps = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
+ REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 340,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_pldo = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(750000, 0, 30, 25000),
+ REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 100,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_nldo = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 64,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_switch = {
+ .ops = &rpm_switch_ops,
+};
+
static const struct regulator_desc pm8x41_hfsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500),
@@ -211,6 +254,43 @@ static const struct regulator_desc pm8941_switch = {
.ops = &rpm_switch_ops,
};
+static const struct regulator_desc pm8916_pldo = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(750000, 0, 208, 12500),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 209,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8916_nldo = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(375000, 0, 93, 12500),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 94,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8916_buck_lvo_smps = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
+ REGULATOR_LINEAR_RANGE(750000, 96, 127, 25000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 128,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8916_buck_hvo_smps = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1550000, 0, 31, 25000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 32,
+ .ops = &rpm_smps_ldo_ops,
+};
+
struct rpm_regulator_data {
const char *name;
u32 type;
@@ -231,6 +311,32 @@ static const struct rpm_regulator_data rpm_pm8841_regulators[] = {
{}
};
+static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
+ { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" },
+ { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_lvo_smps, "vdd_s2" },
+ { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8916_buck_lvo_smps, "vdd_s3" },
+ { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8916_buck_hvo_smps, "vdd_s4" },
+ { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8916_nldo, "vdd_l1_l2_l3" },
+ { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8916_nldo, "vdd_l1_l2_l3" },
+ { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8916_nldo, "vdd_l1_l2_l3" },
+ { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8916_pldo, "vdd_l4_l5_l6" },
+ { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8916_pldo, "vdd_l4_l5_l6" },
+ { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8916_pldo, "vdd_l4_l5_l6" },
+ { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8916_pldo, "vdd_l7" },
+ { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
+ { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
+ { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+ {}
+};
+
static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
@@ -272,9 +378,62 @@ static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
{}
};
+static const struct rpm_regulator_data rpm_pma8084_regulators[] = {
+ { "s1", QCOM_SMD_RPM_SMPA, 1, &pma8084_ftsmps, "vdd_s1" },
+ { "s2", QCOM_SMD_RPM_SMPA, 2, &pma8084_ftsmps, "vdd_s2" },
+ { "s3", QCOM_SMD_RPM_SMPA, 3, &pma8084_hfsmps, "vdd_s3" },
+ { "s4", QCOM_SMD_RPM_SMPA, 4, &pma8084_hfsmps, "vdd_s4" },
+ { "s5", QCOM_SMD_RPM_SMPA, 5, &pma8084_hfsmps, "vdd_s5" },
+ { "s6", QCOM_SMD_RPM_SMPA, 6, &pma8084_ftsmps, "vdd_s6" },
+ { "s7", QCOM_SMD_RPM_SMPA, 7, &pma8084_ftsmps, "vdd_s7" },
+ { "s8", QCOM_SMD_RPM_SMPA, 8, &pma8084_ftsmps, "vdd_s8" },
+ { "s9", QCOM_SMD_RPM_SMPA, 9, &pma8084_ftsmps, "vdd_s9" },
+ { "s10", QCOM_SMD_RPM_SMPA, 10, &pma8084_ftsmps, "vdd_s10" },
+ { "s11", QCOM_SMD_RPM_SMPA, 11, &pma8084_ftsmps, "vdd_s11" },
+ { "s12", QCOM_SMD_RPM_SMPA, 12, &pma8084_ftsmps, "vdd_s12" },
+
+ { "l1", QCOM_SMD_RPM_LDOA, 1, &pma8084_nldo, "vdd_l1_l11" },
+ { "l2", QCOM_SMD_RPM_LDOA, 2, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+ { "l3", QCOM_SMD_RPM_LDOA, 3, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+ { "l4", QCOM_SMD_RPM_LDOA, 4, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+ { "l5", QCOM_SMD_RPM_LDOA, 5, &pma8084_pldo, "vdd_l5_l7" },
+ { "l6", QCOM_SMD_RPM_LDOA, 6, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+ { "l7", QCOM_SMD_RPM_LDOA, 7, &pma8084_pldo, "vdd_l5_l7" },
+ { "l8", QCOM_SMD_RPM_LDOA, 8, &pma8084_pldo, "vdd_l8" },
+ { "l9", QCOM_SMD_RPM_LDOA, 9, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+ { "l10", QCOM_SMD_RPM_LDOA, 10, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+ { "l11", QCOM_SMD_RPM_LDOA, 11, &pma8084_nldo, "vdd_l1_l11" },
+ { "l12", QCOM_SMD_RPM_LDOA, 12, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+ { "l13", QCOM_SMD_RPM_LDOA, 13, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+ { "l14", QCOM_SMD_RPM_LDOA, 14, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+ { "l15", QCOM_SMD_RPM_LDOA, 15, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+ { "l16", QCOM_SMD_RPM_LDOA, 16, &pma8084_pldo, "vdd_l16_l25" },
+ { "l17", QCOM_SMD_RPM_LDOA, 17, &pma8084_pldo, "vdd_l17" },
+ { "l18", QCOM_SMD_RPM_LDOA, 18, &pma8084_pldo, "vdd_l18" },
+ { "l19", QCOM_SMD_RPM_LDOA, 19, &pma8084_pldo, "vdd_l19" },
+ { "l20", QCOM_SMD_RPM_LDOA, 20, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+ { "l21", QCOM_SMD_RPM_LDOA, 21, &pma8084_pldo, "vdd_l21" },
+ { "l22", QCOM_SMD_RPM_LDOA, 22, &pma8084_pldo, "vdd_l22" },
+ { "l23", QCOM_SMD_RPM_LDOA, 23, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+ { "l24", QCOM_SMD_RPM_LDOA, 24, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+ { "l25", QCOM_SMD_RPM_LDOA, 25, &pma8084_pldo, "vdd_l16_l25" },
+ { "l26", QCOM_SMD_RPM_LDOA, 26, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+ { "l27", QCOM_SMD_RPM_LDOA, 27, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+
+ { "lvs1", QCOM_SMD_RPM_VSA, 1, &pma8084_switch },
+ { "lvs2", QCOM_SMD_RPM_VSA, 2, &pma8084_switch },
+ { "lvs3", QCOM_SMD_RPM_VSA, 3, &pma8084_switch },
+ { "lvs4", QCOM_SMD_RPM_VSA, 4, &pma8084_switch },
+ { "5vs1", QCOM_SMD_RPM_VSA, 5, &pma8084_switch },
+
+ {}
+};
+
static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
+ { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
{ .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
+ { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
{}
};
MODULE_DEVICE_TABLE(of, rpm_of_match);
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 72fc3c32db49..3242ffc0cb25 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -32,6 +32,7 @@
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
+#include <linux/mfd/samsung/s2mps15.h>
#include <linux/mfd/samsung/s2mpu02.h>
/* The highest number of possible regulators for supported devices. */
@@ -661,6 +662,133 @@ static const struct regulator_desc s2mps14_regulators[] = {
S2MPS14_BUCK1235_START_SEL),
};
+static struct regulator_ops s2mps15_reg_ldo_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static struct regulator_ops s2mps15_reg_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+#define regulator_desc_s2mps15_ldo(num, range) { \
+ .name = "LDO"#num, \
+ .id = S2MPS15_LDO##num, \
+ .ops = &s2mps15_reg_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .linear_ranges = range, \
+ .n_linear_ranges = ARRAY_SIZE(range), \
+ .n_voltages = S2MPS15_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS15_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS15_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS15_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS15_ENABLE_MASK \
+}
+
+#define regulator_desc_s2mps15_buck(num, range) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS15_BUCK##num, \
+ .ops = &s2mps15_reg_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .linear_ranges = range, \
+ .n_linear_ranges = ARRAY_SIZE(range), \
+ .ramp_delay = 12500, \
+ .n_voltages = S2MPS15_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPS15_REG_B1CTRL2 + ((num - 1) * 2), \
+ .vsel_mask = S2MPS15_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS15_REG_B1CTRL1 + ((num - 1) * 2), \
+ .enable_mask = S2MPS15_ENABLE_MASK \
+}
+
+/* voltage range for s2mps15 LDO 3, 5, 15, 16, 18, 20, 23 and 27 */
+static const struct regulator_linear_range s2mps15_ldo_voltage_ranges1[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0xc, 0x38, 25000),
+};
+
+/* voltage range for s2mps15 LDO 2, 6, 14, 17, 19, 21, 24 and 25 */
+static const struct regulator_linear_range s2mps15_ldo_voltage_ranges2[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x0, 0x3f, 25000),
+};
+
+/* voltage range for s2mps15 LDO 4, 11, 12, 13, 22 and 26 */
+static const struct regulator_linear_range s2mps15_ldo_voltage_ranges3[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x0, 0x34, 12500),
+};
+
+/* voltage range for s2mps15 LDO 7, 8, 9 and 10 */
+static const struct regulator_linear_range s2mps15_ldo_voltage_ranges4[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0xc, 0x18, 25000),
+};
+
+/* voltage range for s2mps15 LDO 1 */
+static const struct regulator_linear_range s2mps15_ldo_voltage_ranges5[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x0, 0x20, 12500),
+};
+
+/* voltage range for s2mps15 BUCK 1, 2, 3, 4, 5, 6 and 7 */
+static const struct regulator_linear_range s2mps15_buck_voltage_ranges1[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x20, 0xb0, 6250),
+};
+
+/* voltage range for s2mps15 BUCK 8, 9 and 10 */
+static const struct regulator_linear_range s2mps15_buck_voltage_ranges2[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0x20, 0xc0, 12500),
+};
+
+static const struct regulator_desc s2mps15_regulators[] = {
+ regulator_desc_s2mps15_ldo(1, s2mps15_ldo_voltage_ranges5),
+ regulator_desc_s2mps15_ldo(2, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(3, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(4, s2mps15_ldo_voltage_ranges3),
+ regulator_desc_s2mps15_ldo(5, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(6, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(7, s2mps15_ldo_voltage_ranges4),
+ regulator_desc_s2mps15_ldo(8, s2mps15_ldo_voltage_ranges4),
+ regulator_desc_s2mps15_ldo(9, s2mps15_ldo_voltage_ranges4),
+ regulator_desc_s2mps15_ldo(10, s2mps15_ldo_voltage_ranges4),
+ regulator_desc_s2mps15_ldo(11, s2mps15_ldo_voltage_ranges3),
+ regulator_desc_s2mps15_ldo(12, s2mps15_ldo_voltage_ranges3),
+ regulator_desc_s2mps15_ldo(13, s2mps15_ldo_voltage_ranges3),
+ regulator_desc_s2mps15_ldo(14, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(15, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(16, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(17, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(18, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(19, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(20, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(21, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(22, s2mps15_ldo_voltage_ranges3),
+ regulator_desc_s2mps15_ldo(23, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_ldo(24, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(25, s2mps15_ldo_voltage_ranges2),
+ regulator_desc_s2mps15_ldo(26, s2mps15_ldo_voltage_ranges3),
+ regulator_desc_s2mps15_ldo(27, s2mps15_ldo_voltage_ranges1),
+ regulator_desc_s2mps15_buck(1, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(2, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(3, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(4, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(5, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(6, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(7, s2mps15_buck_voltage_ranges1),
+ regulator_desc_s2mps15_buck(8, s2mps15_buck_voltage_ranges2),
+ regulator_desc_s2mps15_buck(9, s2mps15_buck_voltage_ranges2),
+ regulator_desc_s2mps15_buck(10, s2mps15_buck_voltage_ranges2),
+};
+
static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
struct regulator_dev *rdev)
{
@@ -974,6 +1102,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
regulators = s2mps14_regulators;
BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
break;
+ case S2MPS15X:
+ s2mps11->rdev_num = ARRAY_SIZE(s2mps15_regulators);
+ regulators = s2mps15_regulators;
+ break;
case S2MPU02:
s2mps11->rdev_num = ARRAY_SIZE(s2mpu02_regulators);
regulators = s2mpu02_regulators;
@@ -1067,10 +1199,11 @@ out:
}
static const struct platform_device_id s2mps11_pmic_id[] = {
- { "s2mps11-pmic", S2MPS11X},
- { "s2mps13-pmic", S2MPS13X},
- { "s2mps14-pmic", S2MPS14X},
- { "s2mpu02-pmic", S2MPU02},
+ { "s2mps11-regulator", S2MPS11X},
+ { "s2mps13-regulator", S2MPS13X},
+ { "s2mps14-regulator", S2MPS14X},
+ { "s2mps15-regulator", S2MPS15X},
+ { "s2mpu02-regulator", S2MPU02},
{ },
};
MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
@@ -1097,5 +1230,5 @@ module_exit(s2mps11_pmic_exit);
/* Module information */
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14/S2MPU02 Regulator Driver");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14/S2MPS15/S2MPU02 Regulator Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
index ddc4f10e268a..584ef3dedca6 100644
--- a/drivers/regulator/tps6105x-regulator.c
+++ b/drivers/regulator/tps6105x-regulator.c
@@ -27,90 +27,12 @@ static const unsigned int tps6105x_voltages[] = {
5000000, /* There is an additional 5V */
};
-static int tps6105x_regulator_enable(struct regulator_dev *rdev)
-{
- struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
- int ret;
-
- /* Activate voltage mode */
- ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
- TPS6105X_REG0_MODE_MASK,
- TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int tps6105x_regulator_disable(struct regulator_dev *rdev)
-{
- struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
- int ret;
-
- /* Set into shutdown mode */
- ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
- TPS6105X_REG0_MODE_MASK,
- TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
-{
- struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
- unsigned int regval;
- int ret;
-
- ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
- if (ret)
- return ret;
- regval &= TPS6105X_REG0_MODE_MASK;
- regval >>= TPS6105X_REG0_MODE_SHIFT;
-
- if (regval == TPS6105X_REG0_MODE_VOLTAGE)
- return 1;
-
- return 0;
-}
-
-static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
- unsigned int regval;
- int ret;
-
- ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
- if (ret)
- return ret;
-
- regval &= TPS6105X_REG0_VOLTAGE_MASK;
- regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
- return (int) regval;
-}
-
-static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
- unsigned selector)
-{
- struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
- int ret;
-
- ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
- TPS6105X_REG0_VOLTAGE_MASK,
- selector << TPS6105X_REG0_VOLTAGE_SHIFT);
- if (ret)
- return ret;
-
- return 0;
-}
-
static struct regulator_ops tps6105x_regulator_ops = {
- .enable = tps6105x_regulator_enable,
- .disable = tps6105x_regulator_disable,
- .is_enabled = tps6105x_regulator_is_enabled,
- .get_voltage_sel = tps6105x_regulator_get_voltage_sel,
- .set_voltage_sel = tps6105x_regulator_set_voltage_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_table,
};
@@ -122,6 +44,12 @@ static const struct regulator_desc tps6105x_regulator_desc = {
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(tps6105x_voltages),
.volt_table = tps6105x_voltages,
+ .vsel_reg = TPS6105X_REG_0,
+ .vsel_mask = TPS6105X_REG0_VOLTAGE_MASK,
+ .enable_reg = TPS6105X_REG_0,
+ .enable_mask = TPS6105X_REG0_MODE_MASK,
+ .enable_val = TPS6105X_REG0_MODE_VOLTAGE <<
+ TPS6105X_REG0_MODE_SHIFT,
};
/*
@@ -144,6 +72,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)
config.dev = &tps6105x->client->dev;
config.init_data = pdata->regulator_data;
config.driver_data = tps6105x;
+ config.regmap = tps6105x->regmap;
/* Register regulator with framework */
tps6105x->regulator = devm_regulator_register(&pdev->dev,
diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c
new file mode 100644
index 000000000000..33f389d583ef
--- /dev/null
+++ b/drivers/regulator/tps65086-regulator.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Author: Andrew F. Davis <afd@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 "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 TPS65912 driver
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+
+#include <linux/mfd/tps65086.h>
+
+enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
+ LDOA2, LDOA3, SWA1, SWB1, SWB2, VTT };
+
+#define TPS65086_REGULATOR(_name, _of, _id, _nv, _vr, _vm, _er, _em, _lr, _dr, _dm) \
+ [_id] = { \
+ .desc = { \
+ .name = _name, \
+ .of_match = of_match_ptr(_of), \
+ .regulators_node = "regulators", \
+ .of_parse_cb = tps65086_of_parse_cb, \
+ .id = _id, \
+ .ops = &reg_ops, \
+ .n_voltages = _nv, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = _vr, \
+ .vsel_mask = _vm, \
+ .enable_reg = _er, \
+ .enable_mask = _em, \
+ .volt_table = NULL, \
+ .linear_ranges = _lr, \
+ .n_linear_ranges = ARRAY_SIZE(_lr), \
+ }, \
+ .decay_reg = _dr, \
+ .decay_mask = _dm, \
+ }
+
+#define TPS65086_SWITCH(_name, _of, _id, _er, _em) \
+ [_id] = { \
+ .desc = { \
+ .name = _name, \
+ .of_match = of_match_ptr(_of), \
+ .regulators_node = "regulators", \
+ .of_parse_cb = tps65086_of_parse_cb, \
+ .id = _id, \
+ .ops = &switch_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .enable_reg = _er, \
+ .enable_mask = _em, \
+ }, \
+ }
+
+struct tps65086_regulator {
+ struct regulator_desc desc;
+ unsigned int decay_reg;
+ unsigned int decay_mask;
+};
+
+static const struct regulator_linear_range tps65086_buck126_10mv_ranges[] = {
+ REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
+ REGULATOR_LINEAR_RANGE(410000, 0x1, 0x7F, 10000),
+};
+
+static const struct regulator_linear_range tps65086_buck126_25mv_ranges[] = {
+ REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
+ REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x18, 0),
+ REGULATOR_LINEAR_RANGE(1025000, 0x19, 0x7F, 25000),
+};
+
+static const struct regulator_linear_range tps65086_buck345_ranges[] = {
+ REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
+ REGULATOR_LINEAR_RANGE(425000, 0x1, 0x7F, 25000),
+};
+
+static const struct regulator_linear_range tps65086_ldoa1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000),
+ REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xA, 100000),
+ REGULATOR_LINEAR_RANGE(2700000, 0xB, 0xD, 150000),
+ REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0),
+};
+
+static const struct regulator_linear_range tps65086_ldoa23_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x0, 0xD, 50000),
+ REGULATOR_LINEAR_RANGE(1400000, 0xE, 0xF, 100000),
+};
+
+/* Operations permitted on regulators */
+static struct regulator_ops reg_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+};
+
+/* Operations permitted on load switches */
+static struct regulator_ops switch_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static int tps65086_of_parse_cb(struct device_node *dev,
+ const struct regulator_desc *desc,
+ struct regulator_config *config);
+
+static struct tps65086_regulator regulators[] = {
+ TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
+ tps65086_buck126_10mv_ranges, TPS65086_BUCK1CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
+ tps65086_buck126_10mv_ranges, TPS65086_BUCK2CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
+ tps65086_buck345_ranges, TPS65086_BUCK3DECAY,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
+ BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
+ tps65086_buck345_ranges, TPS65086_BUCK4VID,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
+ BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
+ tps65086_buck345_ranges, TPS65086_BUCK5CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
+ BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
+ tps65086_buck126_10mv_ranges, TPS65086_BUCK6CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
+ VDOA1_VID_MASK, TPS65086_LDOA1CTRL, BIT(0),
+ tps65086_ldoa1_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
+ VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
+ VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
+ TPS65086_SWITCH("SWB1", "swa2", SWB1, TPS65086_SWVTT_EN, BIT(6)),
+ TPS65086_SWITCH("SWB2", "swa3", SWB2, TPS65086_SWVTT_EN, BIT(7)),
+ TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
+};
+
+static inline bool has_25mv_mode(int id)
+{
+ switch (id) {
+ case BUCK1:
+ case BUCK2:
+ case BUCK6:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int tps65086_of_parse_cb(struct device_node *dev,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ int ret;
+
+ /* Check for 25mV step mode */
+ if (has_25mv_mode(desc->id) &&
+ of_property_read_bool(config->of_node, "ti,regulator-step-size-25mv")) {
+ regulators[desc->id].desc.linear_ranges =
+ tps65086_buck126_25mv_ranges;
+ regulators[desc->id].desc.n_linear_ranges =
+ ARRAY_SIZE(tps65086_buck126_25mv_ranges);
+ }
+
+ /* Check for decay mode */
+ if (desc->id <= BUCK6 && of_property_read_bool(config->of_node, "ti,regulator-decay")) {
+ ret = regmap_write_bits(config->regmap,
+ regulators[desc->id].decay_reg,
+ regulators[desc->id].decay_mask,
+ regulators[desc->id].decay_mask);
+ if (ret) {
+ dev_err(config->dev, "Error setting decay\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int tps65086_regulator_probe(struct platform_device *pdev)
+{
+ struct tps65086 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ int i;
+
+ platform_set_drvdata(pdev, tps);
+
+ config.dev = &pdev->dev;
+ config.dev->of_node = tps->dev->of_node;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+
+ for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[i].desc,
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id tps65086_regulator_id_table[] = {
+ { "tps65086-regulator", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65086_regulator_id_table);
+
+static struct platform_driver tps65086_regulator_driver = {
+ .driver = {
+ .name = "tps65086-regulator",
+ },
+ .probe = tps65086_regulator_probe,
+ .id_table = tps65086_regulator_id_table,
+};
+module_platform_driver(tps65086_regulator_driver);
+
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("TPS65086 Regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
index a02c1b961039..a5e5634eeb9e 100644
--- a/drivers/regulator/tps65218-regulator.c
+++ b/drivers/regulator/tps65218-regulator.c
@@ -27,19 +27,22 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65218.h>
-enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
+enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
+ DCDC5, DCDC6, LDO1, LS3 };
-#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, \
- _lr, _nlr, _delay, _fuv) \
+#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
+ _cr, _cm, _lr, _nlr, _delay, _fuv) \
{ \
.name = _name, \
.id = _id, \
.ops = &_ops, \
.n_voltages = _n, \
- .type = REGULATOR_VOLTAGE, \
+ .type = _type, \
.owner = THIS_MODULE, \
.vsel_reg = _vr, \
.vsel_mask = _vm, \
+ .csel_reg = _cr, \
+ .csel_mask = _cm, \
.enable_reg = _er, \
.enable_mask = _em, \
.volt_table = NULL, \
@@ -80,6 +83,7 @@ static struct tps_info tps65218_pmic_regs[] = {
TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
+ TPS65218_INFO(LS3, "LS3", -1, -1),
};
#define TPS65218_OF_MATCH(comp, label) \
@@ -96,6 +100,7 @@ static const struct of_device_id tps65218_of_match[] = {
TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
+ TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
{ }
};
MODULE_DEVICE_TABLE(of, tps65218_of_match);
@@ -175,6 +180,68 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
.map_voltage = regulator_map_voltage_linear_range,
};
+static const int ls3_currents[] = { 100, 200, 500, 1000 };
+
+static int tps65218_pmic_set_input_current_lim(struct regulator_dev *dev,
+ int lim_uA)
+{
+ unsigned int index = 0;
+ unsigned int num_currents = ARRAY_SIZE(ls3_currents);
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+
+ while (index < num_currents && ls3_currents[index] != lim_uA)
+ index++;
+
+ if (index == num_currents)
+ return -EINVAL;
+
+ return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
+ index << 2, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_set_current_limit(struct regulator_dev *dev,
+ int min_uA, int max_uA)
+{
+ int index = 0;
+ unsigned int num_currents = ARRAY_SIZE(ls3_currents);
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+
+ while (index < num_currents && ls3_currents[index] < max_uA)
+ index++;
+
+ index--;
+
+ if (index < 0 || ls3_currents[index] < min_uA)
+ return -EINVAL;
+
+ return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
+ index << 2, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
+{
+ int retval;
+ unsigned int index;
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+
+ retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
+ if (retval < 0)
+ return retval;
+
+ index = (index & dev->desc->csel_mask) >> 2;
+
+ return ls3_currents[index];
+}
+
+static struct regulator_ops tps65218_ls3_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+ .set_input_current_limit = tps65218_pmic_set_input_current_lim,
+ .set_current_limit = tps65218_pmic_set_current_limit,
+ .get_current_limit = tps65218_pmic_get_current_limit,
+};
+
/* Operations permitted on DCDC5, DCDC6 */
static struct regulator_ops tps65218_dcdc56_pmic_ops = {
.is_enabled = regulator_is_enabled_regmap,
@@ -183,36 +250,46 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
};
static const struct regulator_desc regulators[] = {
- TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64,
- TPS65218_REG_CONTROL_DCDC1,
- TPS65218_CONTROL_DCDC1_MASK,
- TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN,
- dcdc1_dcdc2_ranges, 2, 4000, 0),
- TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
- TPS65218_REG_CONTROL_DCDC2,
- TPS65218_CONTROL_DCDC2_MASK,
- TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN,
- dcdc1_dcdc2_ranges, 2, 4000, 0),
- TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
- 64, TPS65218_REG_CONTROL_DCDC3,
+ TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
+ tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
+ TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
+ 2, 4000, 0),
+ TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
+ tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
+ TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
+ 2, 4000, 0),
+ TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
+ tps65218_ldo1_dcdc34_ops, 64,
+ TPS65218_REG_CONTROL_DCDC3,
TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
- TPS65218_ENABLE1_DC3_EN, ldo1_dcdc3_ranges, 2, 0, 0),
- TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
- 53, TPS65218_REG_CONTROL_DCDC4,
- TPS65218_CONTROL_DCDC4_MASK,
- TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN,
- dcdc4_ranges, 2, 0, 0),
- TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
- 1, -1, -1, TPS65218_REG_ENABLE1,
- TPS65218_ENABLE1_DC5_EN, NULL, 0, 0, 1000000),
- TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
- 1, -1, -1, TPS65218_REG_ENABLE1,
- TPS65218_ENABLE1_DC6_EN, NULL, 0, 0, 1800000),
- TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
+ TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
+ 0, 0),
+ TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
+ tps65218_ldo1_dcdc34_ops, 53,
+ TPS65218_REG_CONTROL_DCDC4,
+ TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
+ 0, 0),
+ TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
+ tps65218_dcdc56_pmic_ops, 1, -1, -1,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
+ NULL, 0, 0, 1000000),
+ TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
+ tps65218_dcdc56_pmic_ops, 1, -1, -1,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
+ NULL, 0, 0, 1800000),
+ TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
+ tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_LDO1,
TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
- TPS65218_ENABLE2_LDO1_EN, ldo1_dcdc3_ranges,
+ TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
2, 0, 0),
+ TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
+ tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
+ TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
+ TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0),
};
static int tps65218_regulator_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 8cbb82ceec40..5a5bc4bb08d2 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -365,7 +365,7 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
return wm831x_dcdc_ilim[val];
}
-static struct regulator_ops wm831x_buckv_ops = {
+static const struct regulator_ops wm831x_buckv_ops = {
.set_voltage_sel = wm831x_buckv_set_voltage_sel,
.get_voltage_sel = wm831x_buckv_get_voltage_sel,
.list_voltage = wm831x_buckv_list_voltage,
@@ -585,7 +585,7 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel);
}
-static struct regulator_ops wm831x_buckp_ops = {
+static const struct regulator_ops wm831x_buckp_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@@ -725,7 +725,7 @@ static int wm831x_boostp_get_status(struct regulator_dev *rdev)
return REGULATOR_STATUS_OFF;
}
-static struct regulator_ops wm831x_boostp_ops = {
+static const struct regulator_ops wm831x_boostp_ops = {
.get_status = wm831x_boostp_get_status,
.is_enabled = regulator_is_enabled_regmap,
@@ -818,7 +818,7 @@ static struct platform_driver wm831x_boostp_driver = {
#define WM831X_EPE_BASE 6
-static struct regulator_ops wm831x_epe_ops = {
+static const struct regulator_ops wm831x_epe_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -884,35 +884,22 @@ static struct platform_driver wm831x_epe_driver = {
},
};
+static struct platform_driver * const drivers[] = {
+ &wm831x_buckv_driver,
+ &wm831x_buckp_driver,
+ &wm831x_boostp_driver,
+ &wm831x_epe_driver,
+};
+
static int __init wm831x_dcdc_init(void)
{
- int ret;
- ret = platform_driver_register(&wm831x_buckv_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x BUCKV driver: %d\n", ret);
-
- ret = platform_driver_register(&wm831x_buckp_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x BUCKP driver: %d\n", ret);
-
- ret = platform_driver_register(&wm831x_boostp_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x BOOST driver: %d\n", ret);
-
- ret = platform_driver_register(&wm831x_epe_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x EPE driver: %d\n", ret);
-
- return 0;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(wm831x_dcdc_init);
static void __exit wm831x_dcdc_exit(void)
{
- platform_driver_unregister(&wm831x_epe_driver);
- platform_driver_unregister(&wm831x_boostp_driver);
- platform_driver_unregister(&wm831x_buckp_driver);
- platform_driver_unregister(&wm831x_buckv_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(wm831x_dcdc_exit);
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 1442828fcd9a..6dd891d7eee3 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -128,7 +128,7 @@ static int wm831x_isink_get_current(struct regulator_dev *rdev)
return wm831x_isinkv_values[ret];
}
-static struct regulator_ops wm831x_isink_ops = {
+static const struct regulator_ops wm831x_isink_ops = {
.is_enabled = wm831x_isink_is_enabled,
.enable = wm831x_isink_enable,
.disable = wm831x_isink_disable,
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 5a7b65e8a529..e4a6f888484e 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -198,7 +198,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
}
-static struct regulator_ops wm831x_gp_ldo_ops = {
+static const struct regulator_ops wm831x_gp_ldo_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -409,7 +409,7 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
return regulator_mode_to_status(ret);
}
-static struct regulator_ops wm831x_aldo_ops = {
+static const struct regulator_ops wm831x_aldo_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -557,7 +557,7 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
return REGULATOR_STATUS_OFF;
}
-static struct regulator_ops wm831x_alive_ldo_ops = {
+static const struct regulator_ops wm831x_alive_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -653,32 +653,21 @@ static struct platform_driver wm831x_alive_ldo_driver = {
},
};
+static struct platform_driver * const drivers[] = {
+ &wm831x_gp_ldo_driver,
+ &wm831x_aldo_driver,
+ &wm831x_alive_ldo_driver,
+};
+
static int __init wm831x_ldo_init(void)
{
- int ret;
-
- ret = platform_driver_register(&wm831x_gp_ldo_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x GP LDO driver: %d\n", ret);
-
- ret = platform_driver_register(&wm831x_aldo_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x ALDO driver: %d\n", ret);
-
- ret = platform_driver_register(&wm831x_alive_ldo_driver);
- if (ret != 0)
- pr_err("Failed to register WM831x alive LDO driver: %d\n",
- ret);
-
- return 0;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(wm831x_ldo_init);
static void __exit wm831x_ldo_exit(void)
{
- platform_driver_unregister(&wm831x_alive_ldo_driver);
- platform_driver_unregister(&wm831x_aldo_driver);
- platform_driver_unregister(&wm831x_gp_ldo_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(wm831x_ldo_exit);
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 95f6b040186e..da9106bd2109 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -941,7 +941,7 @@ static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
return mode;
}
-static struct regulator_ops wm8350_dcdc_ops = {
+static const struct regulator_ops wm8350_dcdc_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@@ -958,7 +958,7 @@ static struct regulator_ops wm8350_dcdc_ops = {
.set_suspend_mode = wm8350_dcdc_set_suspend_mode,
};
-static struct regulator_ops wm8350_dcdc2_5_ops = {
+static const struct regulator_ops wm8350_dcdc2_5_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@@ -966,7 +966,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
};
-static struct regulator_ops wm8350_ldo_ops = {
+static const struct regulator_ops wm8350_ldo_ops = {
.map_voltage = regulator_map_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -980,7 +980,7 @@ static struct regulator_ops wm8350_ldo_ops = {
.set_suspend_disable = wm8350_ldo_set_suspend_disable,
};
-static struct regulator_ops wm8350_isink_ops = {
+static const struct regulator_ops wm8350_isink_ops = {
.set_current_limit = wm8350_isink_set_current,
.get_current_limit = wm8350_isink_get_current,
.enable = wm8350_isink_enable,
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 82d829000851..fb1837657b64 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -24,7 +24,7 @@ static const struct regulator_linear_range wm8400_ldo_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),
};
-static struct regulator_ops wm8400_ldo_ops = {
+static const struct regulator_ops wm8400_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -106,7 +106,7 @@ static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
return REGULATOR_MODE_NORMAL;
}
-static struct regulator_ops wm8400_dcdc_ops = {
+static const struct regulator_ops wm8400_dcdc_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 750e0bd61f9f..7a4ce6df4f22 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -36,7 +36,7 @@ struct wm8994_ldo {
#define WM8994_LDO1_MAX_SELECTOR 0x7
#define WM8994_LDO2_MAX_SELECTOR 0x3
-static struct regulator_ops wm8994_ldo1_ops = {
+static const struct regulator_ops wm8994_ldo1_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -69,7 +69,7 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
}
}
-static struct regulator_ops wm8994_ldo2_ops = {
+static const struct regulator_ops wm8994_ldo2_ops = {
.list_voltage = wm8994_ldo2_list_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index e1a10232a943..e44872fb9e5e 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -147,7 +147,7 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev)
static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
struct rproc *rproc = vdev_to_rproc(vdev);
int i, ret;
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 0615f50a14cd..df37212a5cbd 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER
If unsure, say no.
source "drivers/reset/sti/Kconfig"
+source "drivers/reset/hisilicon/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 85d5904e5480..4d7178e46afa 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,8 +1,9 @@
-obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-y += core.o
obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-$(CONFIG_ARCH_STI) += sti/
+obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o
obj-$(CONFIG_ATH79) += reset-ath79.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 7955e00d04d4..87376638948d 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -30,7 +30,6 @@ static LIST_HEAD(reset_controller_list);
*/
struct reset_control {
struct reset_controller_dev *rcdev;
- struct device *dev;
unsigned int id;
};
@@ -95,7 +94,7 @@ int reset_control_reset(struct reset_control *rstc)
if (rstc->rcdev->ops->reset)
return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
- return -ENOSYS;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(reset_control_reset);
@@ -108,7 +107,7 @@ int reset_control_assert(struct reset_control *rstc)
if (rstc->rcdev->ops->assert)
return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
- return -ENOSYS;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(reset_control_assert);
@@ -121,7 +120,7 @@ int reset_control_deassert(struct reset_control *rstc)
if (rstc->rcdev->ops->deassert)
return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
- return -ENOSYS;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(reset_control_deassert);
@@ -136,32 +135,29 @@ int reset_control_status(struct reset_control *rstc)
if (rstc->rcdev->ops->status)
return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
- return -ENOSYS;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(reset_control_status);
/**
- * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
+ * controller by index.
* @node: device to be reset by the controller
- * @id: reset line name
+ * @index: index of the reset controller
*
- * Returns a struct reset_control or IS_ERR() condition containing errno.
- *
- * Use of id names is optional.
+ * This is to be used to perform a list of resets for a device or power domain
+ * in whatever order. Returns a struct reset_control or IS_ERR() condition
+ * containing errno.
*/
-struct reset_control *of_reset_control_get(struct device_node *node,
- const char *id)
+struct reset_control *of_reset_control_get_by_index(struct device_node *node,
+ int index)
{
struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
struct reset_controller_dev *r, *rcdev;
struct of_phandle_args args;
- int index = 0;
int rstc_id;
int ret;
- if (id)
- index = of_property_match_string(node,
- "reset-names", id);
ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
index, &args);
if (ret)
@@ -202,6 +198,30 @@ struct reset_control *of_reset_control_get(struct device_node *node,
return rstc;
}
+EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
+
+/**
+ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+struct reset_control *of_reset_control_get(struct device_node *node,
+ const char *id)
+{
+ int index = 0;
+
+ if (id) {
+ index = of_property_match_string(node,
+ "reset-names", id);
+ if (index < 0)
+ return ERR_PTR(-ENOENT);
+ }
+ return of_reset_control_get_by_index(node, index);
+}
EXPORT_SYMBOL_GPL(of_reset_control_get);
/**
@@ -215,16 +235,10 @@ EXPORT_SYMBOL_GPL(of_reset_control_get);
*/
struct reset_control *reset_control_get(struct device *dev, const char *id)
{
- struct reset_control *rstc;
-
if (!dev)
return ERR_PTR(-EINVAL);
- rstc = of_reset_control_get(dev->of_node, id);
- if (!IS_ERR(rstc))
- rstc->dev = dev;
-
- return rstc;
+ return of_reset_control_get(dev->of_node, id);
}
EXPORT_SYMBOL_GPL(reset_control_get);
diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig
new file mode 100644
index 000000000000..26bf95a83a8e
--- /dev/null
+++ b/drivers/reset/hisilicon/Kconfig
@@ -0,0 +1,5 @@
+config COMMON_RESET_HI6220
+ tristate "Hi6220 Reset Driver"
+ depends on (ARCH_HISI && RESET_CONTROLLER)
+ help
+ Build the Hisilicon Hi6220 reset driver.
diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile
new file mode 100644
index 000000000000..c932f86e2f10
--- /dev/null
+++ b/drivers/reset/hisilicon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o
diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c
new file mode 100644
index 000000000000..7787a9b1cc67
--- /dev/null
+++ b/drivers/reset/hisilicon/hi6220_reset.c
@@ -0,0 +1,109 @@
+/*
+ * Hisilicon Hi6220 reset controller driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Feng Chen <puck.chen@hisilicon.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/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/reset-controller.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+
+#define ASSERT_OFFSET 0x300
+#define DEASSERT_OFFSET 0x304
+#define MAX_INDEX 0x509
+
+#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
+
+struct hi6220_reset_data {
+ void __iomem *assert_base;
+ void __iomem *deassert_base;
+ struct reset_controller_dev rc_dev;
+};
+
+static int hi6220_reset_assert(struct reset_controller_dev *rc_dev,
+ unsigned long idx)
+{
+ struct hi6220_reset_data *data = to_reset_data(rc_dev);
+
+ int bank = idx >> 8;
+ int offset = idx & 0xff;
+
+ writel(BIT(offset), data->assert_base + (bank * 0x10));
+
+ return 0;
+}
+
+static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev,
+ unsigned long idx)
+{
+ struct hi6220_reset_data *data = to_reset_data(rc_dev);
+
+ int bank = idx >> 8;
+ int offset = idx & 0xff;
+
+ writel(BIT(offset), data->deassert_base + (bank * 0x10));
+
+ return 0;
+}
+
+static struct reset_control_ops hi6220_reset_ops = {
+ .assert = hi6220_reset_assert,
+ .deassert = hi6220_reset_deassert,
+};
+
+static int hi6220_reset_probe(struct platform_device *pdev)
+{
+ struct hi6220_reset_data *data;
+ struct resource *res;
+ void __iomem *src_base;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ src_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(src_base))
+ return PTR_ERR(src_base);
+
+ data->assert_base = src_base + ASSERT_OFFSET;
+ data->deassert_base = src_base + DEASSERT_OFFSET;
+ data->rc_dev.nr_resets = MAX_INDEX;
+ data->rc_dev.ops = &hi6220_reset_ops;
+ data->rc_dev.of_node = pdev->dev.of_node;
+
+ reset_controller_register(&data->rc_dev);
+
+ return 0;
+}
+
+static const struct of_device_id hi6220_reset_match[] = {
+ { .compatible = "hisilicon,hi6220-sysctrl" },
+ { },
+};
+
+static struct platform_driver hi6220_reset_driver = {
+ .probe = hi6220_reset_probe,
+ .driver = {
+ .name = "reset-hi6220",
+ .of_match_table = hi6220_reset_match,
+ },
+};
+
+static int __init hi6220_reset_init(void)
+{
+ return platform_driver_register(&hi6220_reset_driver);
+}
+
+postcore_initcall(hi6220_reset_init);
diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c
index 9aaf646ece55..692fc890e94b 100644
--- a/drivers/reset/reset-ath79.c
+++ b/drivers/reset/reset-ath79.c
@@ -15,13 +15,17 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
+#include <linux/reboot.h>
struct ath79_reset {
struct reset_controller_dev rcdev;
+ struct notifier_block restart_nb;
void __iomem *base;
spinlock_t lock;
};
+#define FULL_CHIP_RESET 24
+
static int ath79_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
@@ -72,10 +76,22 @@ static struct reset_control_ops ath79_reset_ops = {
.status = ath79_reset_status,
};
+static int ath79_reset_restart_handler(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct ath79_reset *ath79_reset =
+ container_of(nb, struct ath79_reset, restart_nb);
+
+ ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET);
+
+ return NOTIFY_DONE;
+}
+
static int ath79_reset_probe(struct platform_device *pdev)
{
struct ath79_reset *ath79_reset;
struct resource *res;
+ int err;
ath79_reset = devm_kzalloc(&pdev->dev,
sizeof(*ath79_reset), GFP_KERNEL);
@@ -96,13 +112,25 @@ static int ath79_reset_probe(struct platform_device *pdev)
ath79_reset->rcdev.of_reset_n_cells = 1;
ath79_reset->rcdev.nr_resets = 32;
- return reset_controller_register(&ath79_reset->rcdev);
+ err = reset_controller_register(&ath79_reset->rcdev);
+ if (err)
+ return err;
+
+ ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler;
+ ath79_reset->restart_nb.priority = 128;
+
+ err = register_restart_handler(&ath79_reset->restart_nb);
+ if (err)
+ dev_warn(&pdev->dev, "Failed to register restart handler\n");
+
+ return 0;
}
static int ath79_reset_remove(struct platform_device *pdev)
{
struct ath79_reset *ath79_reset = platform_get_drvdata(pdev);
+ unregister_restart_handler(&ath79_reset->restart_nb);
reset_controller_unregister(&ath79_reset->rcdev);
return 0;
diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c
index 3c922d37255c..970b1ad60293 100644
--- a/drivers/reset/reset-berlin.c
+++ b/drivers/reset/reset-berlin.c
@@ -87,9 +87,7 @@ static int berlin2_reset_probe(struct platform_device *pdev)
priv->rcdev.of_reset_n_cells = 2;
priv->rcdev.of_xlate = berlin_reset_xlate;
- reset_controller_register(&priv->rcdev);
-
- return 0;
+ return reset_controller_register(&priv->rcdev);
}
static const struct of_device_id berlin_reset_dt_match[] = {
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index 1a6c5d66c83b..b7d773d9248c 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -133,9 +133,8 @@ static int socfpga_reset_probe(struct platform_device *pdev)
data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG;
data->rcdev.ops = &socfpga_reset_ops;
data->rcdev.of_node = pdev->dev.of_node;
- reset_controller_register(&data->rcdev);
- return 0;
+ return reset_controller_register(&data->rcdev);
}
static int socfpga_reset_remove(struct platform_device *pdev)
diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c
index 3d95c87160b3..8d41a18da17f 100644
--- a/drivers/reset/reset-sunxi.c
+++ b/drivers/reset/reset-sunxi.c
@@ -108,9 +108,8 @@ static int sunxi_reset_init(struct device_node *np)
data->rcdev.nr_resets = size * 32;
data->rcdev.ops = &sunxi_reset_ops;
data->rcdev.of_node = np;
- reset_controller_register(&data->rcdev);
- return 0;
+ return reset_controller_register(&data->rcdev);
err_alloc:
kfree(data);
@@ -122,7 +121,7 @@ err_alloc:
* our system, before we can even think of using a regular device
* driver for it.
*/
-static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = {
+static const struct of_device_id sunxi_early_reset_dt_ids[] __initconst = {
{ .compatible = "allwinner,sun6i-a31-ahb1-reset", },
{ /* sentinel */ },
};
diff --git a/drivers/reset/reset-zynq.c b/drivers/reset/reset-zynq.c
index 89318a5d5bd7..c6b3cd8b40ad 100644
--- a/drivers/reset/reset-zynq.c
+++ b/drivers/reset/reset-zynq.c
@@ -121,9 +121,8 @@ static int zynq_reset_probe(struct platform_device *pdev)
priv->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_LONG;
priv->rcdev.ops = &zynq_reset_ops;
priv->rcdev.of_node = pdev->dev.of_node;
- reset_controller_register(&priv->rcdev);
- return 0;
+ return reset_controller_register(&priv->rcdev);
}
static int zynq_reset_remove(struct platform_device *pdev)
diff --git a/drivers/reset/sti/reset-stih407.c b/drivers/reset/sti/reset-stih407.c
index 827eb3dae47d..6fb22af990c0 100644
--- a/drivers/reset/sti/reset-stih407.c
+++ b/drivers/reset/sti/reset-stih407.c
@@ -52,6 +52,7 @@ static const struct syscfg_reset_channel_data stih407_powerdowns[] = {
};
/* Reset Generator control 0/1 */
+#define SYSCFG_5128 0x200
#define SYSCFG_5131 0x20c
#define SYSCFG_5132 0x210
@@ -96,6 +97,10 @@ static const struct syscfg_reset_channel_data stih407_softresets[] = {
[STIH407_ERAM_HVA_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 1),
[STIH407_LPM_SOFTRESET] = STIH407_SRST_SBC(SYSCFG_4002, 2),
[STIH407_KEYSCAN_SOFTRESET] = STIH407_SRST_LPM(LPM_SYSCFG_1, 8),
+ [STIH407_ST231_AUD_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 26),
+ [STIH407_ST231_DMU_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 27),
+ [STIH407_ST231_GP0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 28),
+ [STIH407_ST231_GP1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5128, 2),
};
/* PicoPHY reset/control */
diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c
index a145cc066d4a..1600cc7557f5 100644
--- a/drivers/reset/sti/reset-syscfg.c
+++ b/drivers/reset/sti/reset-syscfg.c
@@ -103,17 +103,42 @@ static int syscfg_reset_deassert(struct reset_controller_dev *rcdev,
static int syscfg_reset_dev(struct reset_controller_dev *rcdev,
unsigned long idx)
{
- int err = syscfg_reset_assert(rcdev, idx);
+ int err;
+
+ err = syscfg_reset_assert(rcdev, idx);
if (err)
return err;
return syscfg_reset_deassert(rcdev, idx);
}
+static int syscfg_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev);
+ const struct syscfg_reset_channel *ch;
+ u32 ret_val = 0;
+ int err;
+
+ if (idx >= rcdev->nr_resets)
+ return -EINVAL;
+
+ ch = &rst->channels[idx];
+ if (ch->ack)
+ err = regmap_field_read(ch->ack, &ret_val);
+ else
+ err = regmap_field_read(ch->reset, &ret_val);
+ if (err)
+ return err;
+
+ return rst->active_low ? !ret_val : !!ret_val;
+}
+
static struct reset_control_ops syscfg_reset_ops = {
.reset = syscfg_reset_dev,
.assert = syscfg_reset_assert,
.deassert = syscfg_reset_deassert,
+ .status = syscfg_reset_status,
};
static int syscfg_reset_controller_register(struct device *dev,
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 73354ee27877..1fcd27c1f183 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -945,7 +945,7 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
static int rpmsg_probe(struct virtio_device *vdev)
{
vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done };
- const char *names[] = { "input", "output" };
+ static const char * const names[] = { "input", "output" };
struct virtqueue *vqs[2];
struct virtproc_info *vrp;
void *bufs_va;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2a524244afec..376322f71fd5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -558,6 +558,16 @@ config RTC_DRV_FM3130
This driver can also be built as a module. If so the module
will be called rtc-fm3130.
+config RTC_DRV_RX8010
+ tristate "Epson RX8010SJ"
+ depends on I2C
+ help
+ If you say yes here you get support for the Epson RX8010SJ RTC
+ chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rx8010.
+
config RTC_DRV_RX8581
tristate "Epson RX-8581"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 231f76451615..62d61b26ca7e 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
+obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index afea84c7a155..d41bbcd653f6 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -27,10 +27,28 @@
#define ABX8XX_REG_YR 0x06
#define ABX8XX_REG_WD 0x07
+#define ABX8XX_REG_AHTH 0x08
+#define ABX8XX_REG_ASC 0x09
+#define ABX8XX_REG_AMN 0x0a
+#define ABX8XX_REG_AHR 0x0b
+#define ABX8XX_REG_ADA 0x0c
+#define ABX8XX_REG_AMO 0x0d
+#define ABX8XX_REG_AWD 0x0e
+
+#define ABX8XX_REG_STATUS 0x0f
+#define ABX8XX_STATUS_AF BIT(2)
+
#define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(0)
+#define ABX8XX_CTRL_ARST BIT(2)
#define ABX8XX_CTRL_12_24 BIT(6)
+#define ABX8XX_REG_IRQ 0x12
+#define ABX8XX_IRQ_AIE BIT(2)
+#define ABX8XX_IRQ_IM_1_4 (0x3 << 5)
+
+#define ABX8XX_REG_CD_TIMER_CTL 0x18
+
#define ABX8XX_REG_CFG_KEY 0x1f
#define ABX8XX_CFG_KEY_MISC 0x9d
@@ -63,8 +81,6 @@ static struct abx80x_cap abx80x_caps[] = {
[ABX80X] = {.pn = 0}
};
-static struct i2c_driver abx80x_driver;
-
static int abx80x_enable_trickle_charger(struct i2c_client *client,
u8 trickle_cfg)
{
@@ -148,9 +164,111 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
return 0;
}
+static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
+{
+ struct i2c_client *client = dev_id;
+ struct rtc_device *rtc = i2c_get_clientdata(client);
+ int status;
+
+ status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
+ if (status < 0)
+ return IRQ_NONE;
+
+ if (status & ABX8XX_STATUS_AF)
+ rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
+
+ i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char buf[7];
+
+ int irq_mask, err;
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ASC,
+ sizeof(buf), buf);
+ if (err)
+ return err;
+
+ irq_mask = i2c_smbus_read_byte_data(client, ABX8XX_REG_IRQ);
+ if (irq_mask < 0)
+ return irq_mask;
+
+ t->time.tm_sec = bcd2bin(buf[0] & 0x7F);
+ t->time.tm_min = bcd2bin(buf[1] & 0x7F);
+ t->time.tm_hour = bcd2bin(buf[2] & 0x3F);
+ t->time.tm_mday = bcd2bin(buf[3] & 0x3F);
+ t->time.tm_mon = bcd2bin(buf[4] & 0x1F) - 1;
+ t->time.tm_wday = buf[5] & 0x7;
+
+ t->enabled = !!(irq_mask & ABX8XX_IRQ_AIE);
+ t->pending = (buf[6] & ABX8XX_STATUS_AF) && t->enabled;
+
+ return err;
+}
+
+static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 alarm[6];
+ int err;
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ alarm[0] = 0x0;
+ alarm[1] = bin2bcd(t->time.tm_sec);
+ alarm[2] = bin2bcd(t->time.tm_min);
+ alarm[3] = bin2bcd(t->time.tm_hour);
+ alarm[4] = bin2bcd(t->time.tm_mday);
+ alarm[5] = bin2bcd(t->time.tm_mon + 1);
+
+ err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_AHTH,
+ sizeof(alarm), alarm);
+ if (err < 0) {
+ dev_err(&client->dev, "Unable to write alarm registers\n");
+ return -EIO;
+ }
+
+ if (t->enabled) {
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
+ (ABX8XX_IRQ_IM_1_4 |
+ ABX8XX_IRQ_AIE));
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int err;
+
+ if (enabled)
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
+ (ABX8XX_IRQ_IM_1_4 |
+ ABX8XX_IRQ_AIE));
+ else
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
+ ABX8XX_IRQ_IM_1_4);
+ return err;
+}
+
static const struct rtc_class_ops abx80x_rtc_ops = {
.read_time = abx80x_rtc_read_time,
.set_time = abx80x_rtc_set_time,
+ .read_alarm = abx80x_read_alarm,
+ .set_alarm = abx80x_set_alarm,
+ .alarm_irq_enable = abx80x_alarm_irq_enable,
};
static int abx80x_dt_trickle_cfg(struct device_node *np)
@@ -225,7 +343,8 @@ static int abx80x_probe(struct i2c_client *client,
}
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1,
- ((data & ~ABX8XX_CTRL_12_24) |
+ ((data & ~(ABX8XX_CTRL_12_24 |
+ ABX8XX_CTRL_ARST)) |
ABX8XX_CTRL_WRITE));
if (err < 0) {
dev_err(&client->dev, "Unable to write control register\n");
@@ -260,7 +379,12 @@ static int abx80x_probe(struct i2c_client *client,
abx80x_enable_trickle_charger(client, trickle_cfg);
}
- rtc = devm_rtc_device_register(&client->dev, abx80x_driver.driver.name,
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CD_TIMER_CTL,
+ BIT(2));
+ if (err)
+ return err;
+
+ rtc = devm_rtc_device_register(&client->dev, "abx8xx",
&abx80x_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
@@ -268,6 +392,19 @@ static int abx80x_probe(struct i2c_client *client,
i2c_set_clientdata(client, rtc);
+ if (client->irq > 0) {
+ dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
+ err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ abx80x_handle_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ "abx8xx",
+ client);
+ if (err) {
+ dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
+ client->irq = 0;
+ }
+ }
+
return 0;
}
@@ -286,6 +423,7 @@ static const struct i2c_device_id abx80x_id[] = {
{ "ab1803", AB1803 },
{ "ab1804", AB1804 },
{ "ab1805", AB1805 },
+ { "rv1805", AB1805 },
{ }
};
MODULE_DEVICE_TABLE(i2c, abx80x_id);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 8f7034ba7d9e..84fb541038be 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -725,7 +725,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
rtc_cmos_int_handler = cmos_interrupt;
retval = request_irq(rtc_irq, rtc_cmos_int_handler,
- 0, dev_name(&cmos_rtc.rtc->dev),
+ IRQF_SHARED, dev_name(&cmos_rtc.rtc->dev),
cmos_rtc.rtc);
if (retval < 0) {
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
index d6c853bbfa9f..f85cae240f12 100644
--- a/drivers/rtc/rtc-da9063.c
+++ b/drivers/rtc/rtc-da9063.c
@@ -191,24 +191,13 @@ static void da9063_tm_to_data(struct rtc_time *tm, u8 *data,
{
const struct da9063_compatible_rtc_regmap *config = rtc->config;
- data[RTC_SEC] &= ~config->rtc_count_sec_mask;
- data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask;
-
- data[RTC_MIN] &= ~config->rtc_count_min_mask;
- data[RTC_MIN] |= tm->tm_min & config->rtc_count_min_mask;
-
- data[RTC_HOUR] &= ~config->rtc_count_hour_mask;
- data[RTC_HOUR] |= tm->tm_hour & config->rtc_count_hour_mask;
-
- data[RTC_DAY] &= ~config->rtc_count_day_mask;
- data[RTC_DAY] |= tm->tm_mday & config->rtc_count_day_mask;
-
- data[RTC_MONTH] &= ~config->rtc_count_month_mask;
- data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) &
+ data[RTC_SEC] = tm->tm_sec & config->rtc_count_sec_mask;
+ data[RTC_MIN] = tm->tm_min & config->rtc_count_min_mask;
+ data[RTC_HOUR] = tm->tm_hour & config->rtc_count_hour_mask;
+ data[RTC_DAY] = tm->tm_mday & config->rtc_count_day_mask;
+ data[RTC_MONTH] = MONTHS_TO_DA9063(tm->tm_mon) &
config->rtc_count_month_mask;
-
- data[RTC_YEAR] &= ~config->rtc_count_year_mask;
- data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) &
+ data[RTC_YEAR] = YEARS_TO_DA9063(tm->tm_year) &
config->rtc_count_year_mask;
}
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 85706a9f82c9..f39691eea736 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -186,9 +186,7 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time)
if (status < 0)
return status;
- dev_vdbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
- "read", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6]);
+ dev_vdbg(dev, "%s: %3ph, %4ph\n", "read", &buf[0], &buf[3]);
/* Decode the registers */
time->tm_sec = bcd2bin(buf[DS1305_SEC]);
@@ -232,9 +230,7 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time)
*bp++ = bin2bcd(time->tm_mon + 1);
*bp++ = bin2bcd(time->tm_year - 100);
- dev_dbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
- "write", buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7]);
+ dev_dbg(dev, "%s: %3ph, %4ph\n", "write", &buf[1], &buf[4]);
/* use write-then-read since dma from stack is nonportable */
return spi_write_then_read(ds1305->spi, buf, sizeof(buf),
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index aa705bb4748c..cf685f67b391 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -460,13 +460,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return -EIO;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
- "alarm read",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6], ds1307->regs[7],
- ds1307->regs[8]);
+ dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read",
+ &ds1307->regs[0], &ds1307->regs[4], &ds1307->regs[7]);
/*
* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
@@ -522,12 +517,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
control = ds1307->regs[7];
status = ds1307->regs[8];
- dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
- "alarm set (old status)",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6], control, status);
+ dev_dbg(dev, "%s: %4ph, %3ph, %02x %02x\n", "alarm set (old status)",
+ &ds1307->regs[0], &ds1307->regs[4], control, status);
/* set ALARM1, using 24 hour and day-of-month modes */
buf[0] = bin2bcd(t->time.tm_sec);
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 05a51ef52703..535050fc5e9f 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -853,7 +853,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
"Periodic Rate\t: %s\n"
"SQW Freq\t: %s\n"
#ifdef CONFIG_RTC_DS1685_PROC_REGS
- "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
+ "Serial #\t: %8phC\n"
"Register Status\t:\n"
" Ctrl A\t: UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n"
"\t\t: %s\n"
@@ -872,7 +872,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
" Ctrl 4B\t: ABE E32k CS RCE PRS RIE WIE KSE\n"
"\t\t: %s\n",
#else
- "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ "Serial #\t: %8phC\n",
#endif
model,
((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"),
@@ -888,7 +888,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
(!((ctrl4b & RTC_CTRL_4B_E32K)) ?
ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"),
#ifdef CONFIG_RTC_DS1685_PROC_REGS
- ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7],
+ ssn,
ds1685_rtc_print_regs(ctrla, bits[0]),
ds1685_rtc_print_regs(ctrlb, bits[1]),
ds1685_rtc_print_regs(ctrlc, bits[2]),
@@ -896,7 +896,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
ds1685_rtc_print_regs(ctrl4a, bits[4]),
ds1685_rtc_print_regs(ctrl4b, bits[5]));
#else
- ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7]);
+ ssn);
#endif
return 0;
}
@@ -1114,7 +1114,7 @@ ds1685_rtc_sysfs_battery_show(struct device *dev,
ctrld = rtc->read(rtc, RTC_CTRL_D);
- return snprintf(buf, 13, "%s\n",
+ return sprintf(buf, "%s\n",
(ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A");
}
static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL);
@@ -1137,7 +1137,7 @@ ds1685_rtc_sysfs_auxbatt_show(struct device *dev,
ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
ds1685_rtc_switch_to_bank0(rtc);
- return snprintf(buf, 13, "%s\n",
+ return sprintf(buf, "%s\n",
(ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A");
}
static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL);
@@ -1160,11 +1160,7 @@ ds1685_rtc_sysfs_serial_show(struct device *dev,
ds1685_rtc_get_ssn(rtc, ssn);
ds1685_rtc_switch_to_bank0(rtc);
- return snprintf(buf, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5],
- ssn[6], ssn[7]);
-
- return 0;
+ return sprintf(buf, "%8phC\n", ssn);
}
static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL);
@@ -1287,7 +1283,7 @@ ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev,
tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit;
ds1685_rtc_switch_to_bank0(rtc);
- return snprintf(buf, 2, "%d\n", (tmp ? 1 : 0));
+ return sprintf(buf, "%d\n", (tmp ? 1 : 0));
}
/**
@@ -1623,7 +1619,7 @@ ds1685_rtc_sysfs_time_regs_show(struct device *dev,
tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask,
bin_reg_info->mask);
- return snprintf(buf, 4, "%d\n", tmp);
+ return sprintf(buf, "%d\n", tmp);
}
/**
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index 7885edd3d507..16310fe79d76 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -48,7 +48,7 @@ struct ds2404_gpio {
struct ds2404 {
struct ds2404_gpio *gpio;
- struct ds2404_chip_ops *ops;
+ const struct ds2404_chip_ops *ops;
struct rtc_device *rtc;
};
@@ -95,7 +95,7 @@ static void ds2404_gpio_unmap(struct ds2404 *chip)
gpio_free(ds2404_gpio[i].gpio);
}
-static struct ds2404_chip_ops ds2404_gpio_ops = {
+static const struct ds2404_chip_ops ds2404_gpio_ops = {
.map_io = ds2404_gpio_map,
.unmap_io = ds2404_gpio_unmap,
};
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index 3806961b4348..96d38609d803 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -191,11 +191,69 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
return status == EFI_SUCCESS ? 0 : -EINVAL;
}
+static int efi_procfs(struct device *dev, struct seq_file *seq)
+{
+ efi_time_t eft, alm;
+ efi_time_cap_t cap;
+ efi_bool_t enabled, pending;
+
+ memset(&eft, 0, sizeof(eft));
+ memset(&alm, 0, sizeof(alm));
+ memset(&cap, 0, sizeof(cap));
+
+ efi.get_time(&eft, &cap);
+ efi.get_wakeup_time(&enabled, &pending, &alm);
+
+ seq_printf(seq,
+ "Time\t\t: %u:%u:%u.%09u\n"
+ "Date\t\t: %u-%u-%u\n"
+ "Daylight\t: %u\n",
+ eft.hour, eft.minute, eft.second, eft.nanosecond,
+ eft.year, eft.month, eft.day,
+ eft.daylight);
+
+ if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+ seq_puts(seq, "Timezone\t: unspecified\n");
+ else
+ /* XXX fixme: convert to string? */
+ seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
+
+ seq_printf(seq,
+ "Alarm Time\t: %u:%u:%u.%09u\n"
+ "Alarm Date\t: %u-%u-%u\n"
+ "Alarm Daylight\t: %u\n"
+ "Enabled\t\t: %s\n"
+ "Pending\t\t: %s\n",
+ alm.hour, alm.minute, alm.second, alm.nanosecond,
+ alm.year, alm.month, alm.day,
+ alm.daylight,
+ enabled == 1 ? "yes" : "no",
+ pending == 1 ? "yes" : "no");
+
+ if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+ seq_puts(seq, "Timezone\t: unspecified\n");
+ else
+ /* XXX fixme: convert to string? */
+ seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
+
+ /*
+ * now prints the capabilities
+ */
+ seq_printf(seq,
+ "Resolution\t: %u\n"
+ "Accuracy\t: %u\n"
+ "SetstoZero\t: %u\n",
+ cap.resolution, cap.accuracy, cap.sets_to_zero);
+
+ return 0;
+}
+
static const struct rtc_class_ops efi_rtc_ops = {
- .read_time = efi_read_time,
- .set_time = efi_set_time,
- .read_alarm = efi_read_alarm,
- .set_alarm = efi_set_alarm,
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+ .proc = efi_procfs,
};
static int __init efi_rtc_probe(struct platform_device *dev)
diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c
index e84184647d15..f46b6d46a51b 100644
--- a/drivers/rtc/rtc-gemini.c
+++ b/drivers/rtc/rtc-gemini.c
@@ -156,7 +156,6 @@ static int gemini_rtc_remove(struct platform_device *pdev)
struct gemini_rtc *rtc = platform_get_drvdata(pdev);
rtc_device_unregister(rtc->rtc_dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 7bffd7f0e306..8d8049bdfaf6 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -303,7 +303,7 @@ static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr)
sec = readl(imxdi->ioaddr + DTCMR);
if (sec != 0)
dev_warn(&imxdi->pdev->dev,
- "The security violation has happend at %u seconds\n",
+ "The security violation has happened at %u seconds\n",
sec);
/*
* the timer cannot be set/modified if
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index f923f7324788..887871c3d526 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -205,7 +205,7 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
u32 tmp;
rtcirq = platform_get_irq(pdev, 0);
- if (rtcirq < 0 || rtcirq >= NR_IRQS) {
+ if (rtcirq < 0) {
dev_warn(&pdev->dev, "Can't get interrupt resource\n");
rtcirq = -1;
}
diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c
index df39ce02a99d..9c18d6fd8107 100644
--- a/drivers/rtc/rtc-opal.c
+++ b/drivers/rtc/rtc-opal.c
@@ -40,7 +40,7 @@ static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm)
tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff);
tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff);
- GregorianDay(tm);
+ tm->tm_wday = -1;
}
static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms)
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index e7ebcc0b7e59..988566caaaa6 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -219,6 +219,17 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 regs[8];
int err;
+ /*
+ * The hardware can only store values between 0 and 99 in it's YEAR
+ * register (with 99 overflowing to 0 on increment).
+ * After 2100-02-28 we could start interpreting the year to be in the
+ * interval [2100, 2199], but there is no path to switch in a smooth way
+ * because the chip handles YEAR=0x00 (and the out-of-spec
+ * YEAR=0xa0) as a leap year, but 2100 isn't.
+ */
+ if (tm->tm_year < 100 || tm->tm_year >= 200)
+ return -EINVAL;
+
err = pcf8523_stop_rtc(client);
if (err < 0)
return err;
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index ffa69e1c9245..31e7e23cc5be 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -112,19 +112,21 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
int ret;
struct rtc_device *rtc = PDE_DATA(inode);
- if (!try_module_get(THIS_MODULE))
+ if (!try_module_get(rtc->owner))
return -ENODEV;
ret = single_open(file, rtc_proc_show, rtc);
if (ret)
- module_put(THIS_MODULE);
+ module_put(rtc->owner);
return ret;
}
static int rtc_proc_release(struct inode *inode, struct file *file)
{
int res = single_release(inode, file);
- module_put(THIS_MODULE);
+ struct rtc_device *rtc = PDE_DATA(inode);
+
+ module_put(rtc->owner);
return res;
}
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index e7329e21bfe3..7155c0816aa6 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -61,7 +61,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
struct i2c_client *client = dev_id;
struct rv8803_data *rv8803 = i2c_get_clientdata(client);
unsigned long events = 0;
- u8 flags;
+ int flags;
spin_lock(&rv8803->flags_lock);
@@ -502,6 +502,7 @@ static int rv8803_remove(struct i2c_client *client)
static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", 0 },
+ { "rx8900", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rv8803_id);
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
new file mode 100644
index 000000000000..772d221ec2d9
--- /dev/null
+++ b/drivers/rtc/rtc-rx8010.c
@@ -0,0 +1,523 @@
+/*
+ * Driver for the Epson RTC module RX-8010 SJ
+ *
+ * Copyright(C) Timesys Corporation 2015
+ * Copyright(C) General Electric Company 2015
+ *
+ * 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/bcd.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+#define RX8010_SEC 0x10
+#define RX8010_MIN 0x11
+#define RX8010_HOUR 0x12
+#define RX8010_WDAY 0x13
+#define RX8010_MDAY 0x14
+#define RX8010_MONTH 0x15
+#define RX8010_YEAR 0x16
+#define RX8010_YEAR 0x16
+#define RX8010_RESV17 0x17
+#define RX8010_ALMIN 0x18
+#define RX8010_ALHOUR 0x19
+#define RX8010_ALWDAY 0x1A
+#define RX8010_TCOUNT0 0x1B
+#define RX8010_TCOUNT1 0x1C
+#define RX8010_EXT 0x1D
+#define RX8010_FLAG 0x1E
+#define RX8010_CTRL 0x1F
+/* 0x20 to 0x2F are user registers */
+#define RX8010_RESV30 0x30
+#define RX8010_RESV31 0x32
+#define RX8010_IRQ 0x32
+
+#define RX8010_EXT_WADA BIT(3)
+
+#define RX8010_FLAG_VLF BIT(1)
+#define RX8010_FLAG_AF BIT(3)
+#define RX8010_FLAG_TF BIT(4)
+#define RX8010_FLAG_UF BIT(5)
+
+#define RX8010_CTRL_AIE BIT(3)
+#define RX8010_CTRL_UIE BIT(5)
+#define RX8010_CTRL_STOP BIT(6)
+#define RX8010_CTRL_TEST BIT(7)
+
+#define RX8010_ALARM_AE BIT(7)
+
+static const struct i2c_device_id rx8010_id[] = {
+ { "rx8010", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rx8010_id);
+
+struct rx8010_data {
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ u8 ctrlreg;
+ spinlock_t flags_lock;
+};
+
+static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
+{
+ struct i2c_client *client = dev_id;
+ struct rx8010_data *rx8010 = i2c_get_clientdata(client);
+ int flagreg;
+
+ spin_lock(&rx8010->flags_lock);
+
+ flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
+
+ if (flagreg <= 0) {
+ spin_unlock(&rx8010->flags_lock);
+ return IRQ_NONE;
+ }
+
+ if (flagreg & RX8010_FLAG_VLF)
+ dev_warn(&client->dev, "Frequency stop detected\n");
+
+ if (flagreg & RX8010_FLAG_TF) {
+ flagreg &= ~RX8010_FLAG_TF;
+ rtc_update_irq(rx8010->rtc, 1, RTC_PF | RTC_IRQF);
+ }
+
+ if (flagreg & RX8010_FLAG_AF) {
+ flagreg &= ~RX8010_FLAG_AF;
+ rtc_update_irq(rx8010->rtc, 1, RTC_AF | RTC_IRQF);
+ }
+
+ if (flagreg & RX8010_FLAG_UF) {
+ flagreg &= ~RX8010_FLAG_UF;
+ rtc_update_irq(rx8010->rtc, 1, RTC_UF | RTC_IRQF);
+ }
+
+ i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);
+
+ spin_unlock(&rx8010->flags_lock);
+ return IRQ_HANDLED;
+}
+
+static int rx8010_get_time(struct device *dev, struct rtc_time *dt)
+{
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ u8 date[7];
+ int flagreg;
+ int err;
+
+ flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
+ if (flagreg < 0)
+ return flagreg;
+
+ if (flagreg & RX8010_FLAG_VLF) {
+ dev_warn(dev, "Frequency stop detected\n");
+ return -EINVAL;
+ }
+
+ err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_SEC,
+ 7, date);
+ if (err != 7)
+ return err < 0 ? err : -EIO;
+
+ dt->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);
+ dt->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);
+ dt->tm_hour = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
+ dt->tm_mday = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
+ dt->tm_mon = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f) - 1;
+ dt->tm_year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]) + 100;
+ dt->tm_wday = ffs(date[RX8010_WDAY - RX8010_SEC] & 0x7f);
+
+ return rtc_valid_tm(dt);
+}
+
+static int rx8010_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ u8 date[7];
+ int ctrl, flagreg;
+ int ret;
+ unsigned long irqflags;
+
+ if ((dt->tm_year < 100) || (dt->tm_year > 199))
+ return -EINVAL;
+
+ /* set STOP bit before changing clock/calendar */
+ ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+ rx8010->ctrlreg = ctrl | RX8010_CTRL_STOP;
+ ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (ret < 0)
+ return ret;
+
+ date[RX8010_SEC - RX8010_SEC] = bin2bcd(dt->tm_sec);
+ date[RX8010_MIN - RX8010_SEC] = bin2bcd(dt->tm_min);
+ date[RX8010_HOUR - RX8010_SEC] = bin2bcd(dt->tm_hour);
+ date[RX8010_MDAY - RX8010_SEC] = bin2bcd(dt->tm_mday);
+ date[RX8010_MONTH - RX8010_SEC] = bin2bcd(dt->tm_mon + 1);
+ date[RX8010_YEAR - RX8010_SEC] = bin2bcd(dt->tm_year - 100);
+ date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday);
+
+ ret = i2c_smbus_write_i2c_block_data(rx8010->client,
+ RX8010_SEC, 7, date);
+ if (ret < 0)
+ return ret;
+
+ /* clear STOP bit after changing clock/calendar */
+ ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+ rx8010->ctrlreg = ctrl & ~RX8010_CTRL_STOP;
+ ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&rx8010->flags_lock, irqflags);
+
+ flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
+ if (flagreg < 0) {
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ return flagreg;
+ }
+
+ if (flagreg & RX8010_FLAG_VLF)
+ ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG,
+ flagreg & ~RX8010_FLAG_VLF);
+
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+
+ return 0;
+}
+
+static int rx8010_init_client(struct i2c_client *client)
+{
+ struct rx8010_data *rx8010 = i2c_get_clientdata(client);
+ u8 ctrl[2];
+ int need_clear = 0, err = 0;
+
+ /* Initialize reserved registers as specified in datasheet */
+ err = i2c_smbus_write_byte_data(client, RX8010_RESV17, 0xD8);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(client, RX8010_RESV30, 0x00);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(client, RX8010_RESV31, 0x08);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(client, RX8010_IRQ, 0x00);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_FLAG,
+ 2, ctrl);
+ if (err != 2)
+ return err < 0 ? err : -EIO;
+
+ if (ctrl[0] & RX8010_FLAG_VLF)
+ dev_warn(&client->dev, "Frequency stop was detected\n");
+
+ if (ctrl[0] & RX8010_FLAG_AF) {
+ dev_warn(&client->dev, "Alarm was detected\n");
+ need_clear = 1;
+ }
+
+ if (ctrl[0] & RX8010_FLAG_TF)
+ need_clear = 1;
+
+ if (ctrl[0] & RX8010_FLAG_UF)
+ need_clear = 1;
+
+ if (need_clear) {
+ ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF);
+ err = i2c_smbus_write_byte_data(client, RX8010_FLAG, ctrl[0]);
+ if (err < 0)
+ return err;
+ }
+
+ rx8010->ctrlreg = (ctrl[1] & ~RX8010_CTRL_TEST);
+
+ return err;
+}
+
+static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ struct i2c_client *client = rx8010->client;
+ u8 alarmvals[3];
+ int flagreg;
+ int err;
+
+ err = i2c_smbus_read_i2c_block_data(client, RX8010_ALMIN, 3, alarmvals);
+ if (err != 3)
+ return err < 0 ? err : -EIO;
+
+ flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
+ if (flagreg < 0)
+ return flagreg;
+
+ t->time.tm_sec = 0;
+ t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
+ t->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
+
+ if (alarmvals[2] & RX8010_ALARM_AE)
+ t->time.tm_mday = -1;
+ else
+ t->time.tm_mday = bcd2bin(alarmvals[2] & 0x7f);
+
+ t->time.tm_wday = -1;
+ t->time.tm_mon = -1;
+ t->time.tm_year = -1;
+
+ t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
+ t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
+
+ return err;
+}
+
+static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ u8 alarmvals[3];
+ int extreg, flagreg;
+ int err;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&rx8010->flags_lock, irqflags);
+ flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
+ if (flagreg < 0) {
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ return flagreg;
+ }
+
+ if (rx8010->ctrlreg & (RX8010_CTRL_AIE | RX8010_CTRL_UIE)) {
+ rx8010->ctrlreg &= ~(RX8010_CTRL_AIE | RX8010_CTRL_UIE);
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (err < 0) {
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ return err;
+ }
+ }
+
+ flagreg &= ~RX8010_FLAG_AF;
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg);
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ if (err < 0)
+ return err;
+
+ alarmvals[0] = bin2bcd(t->time.tm_min);
+ alarmvals[1] = bin2bcd(t->time.tm_hour);
+ alarmvals[2] = bin2bcd(t->time.tm_mday);
+
+ err = i2c_smbus_write_i2c_block_data(rx8010->client, RX8010_ALMIN,
+ 2, alarmvals);
+ if (err < 0)
+ return err;
+
+ extreg = i2c_smbus_read_byte_data(client, RX8010_EXT);
+ if (extreg < 0)
+ return extreg;
+
+ extreg |= RX8010_EXT_WADA;
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_EXT, extreg);
+ if (err < 0)
+ return err;
+
+ if (alarmvals[2] == 0)
+ alarmvals[2] |= RX8010_ALARM_AE;
+
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_ALWDAY,
+ alarmvals[2]);
+ if (err < 0)
+ return err;
+
+ if (t->enabled) {
+ if (rx8010->rtc->uie_rtctimer.enabled)
+ rx8010->ctrlreg |= RX8010_CTRL_UIE;
+ if (rx8010->rtc->aie_timer.enabled)
+ rx8010->ctrlreg |=
+ (RX8010_CTRL_AIE | RX8010_CTRL_UIE);
+
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rx8010_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ int flagreg;
+ u8 ctrl;
+ int err;
+
+ ctrl = rx8010->ctrlreg;
+
+ if (enabled) {
+ if (rx8010->rtc->uie_rtctimer.enabled)
+ ctrl |= RX8010_CTRL_UIE;
+ if (rx8010->rtc->aie_timer.enabled)
+ ctrl |= (RX8010_CTRL_AIE | RX8010_CTRL_UIE);
+ } else {
+ if (!rx8010->rtc->uie_rtctimer.enabled)
+ ctrl &= ~RX8010_CTRL_UIE;
+ if (!rx8010->rtc->aie_timer.enabled)
+ ctrl &= ~RX8010_CTRL_AIE;
+ }
+
+ flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
+ if (flagreg < 0)
+ return flagreg;
+
+ flagreg &= ~RX8010_FLAG_AF;
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg);
+ if (err < 0)
+ return err;
+
+ if (ctrl != rx8010->ctrlreg) {
+ rx8010->ctrlreg = ctrl;
+ err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ int ret, tmp;
+ int flagreg;
+ unsigned long irqflags;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
+ if (flagreg < 0)
+ return flagreg;
+
+ tmp = !!(flagreg & RX8010_FLAG_VLF);
+ if (copy_to_user((void __user *)arg, &tmp, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+
+ case RTC_VL_CLR:
+ spin_lock_irqsave(&rx8010->flags_lock, irqflags);
+ flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
+ if (flagreg < 0) {
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ return flagreg;
+ }
+
+ flagreg &= ~RX8010_FLAG_VLF;
+ ret = i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static struct rtc_class_ops rx8010_rtc_ops = {
+ .read_time = rx8010_get_time,
+ .set_time = rx8010_set_time,
+ .ioctl = rx8010_ioctl,
+};
+
+static int rx8010_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct rx8010_data *rx8010;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_I2C_BLOCK)) {
+ dev_err(&adapter->dev, "doesn't support required functionality\n");
+ return -EIO;
+ }
+
+ rx8010 = devm_kzalloc(&client->dev, sizeof(struct rx8010_data),
+ GFP_KERNEL);
+ if (!rx8010)
+ return -ENOMEM;
+
+ rx8010->client = client;
+ i2c_set_clientdata(client, rx8010);
+
+ spin_lock_init(&rx8010->flags_lock);
+
+ err = rx8010_init_client(client);
+ if (err)
+ return err;
+
+ if (client->irq > 0) {
+ dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
+ err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ rx8010_irq_1_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "rx8010", client);
+
+ if (err) {
+ dev_err(&client->dev, "unable to request IRQ\n");
+ client->irq = 0;
+ } else {
+ rx8010_rtc_ops.read_alarm = rx8010_read_alarm;
+ rx8010_rtc_ops.set_alarm = rx8010_set_alarm;
+ rx8010_rtc_ops.alarm_irq_enable = rx8010_alarm_irq_enable;
+ }
+ }
+
+ rx8010->rtc = devm_rtc_device_register(&client->dev, client->name,
+ &rx8010_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rx8010->rtc)) {
+ dev_err(&client->dev, "unable to register the class device\n");
+ return PTR_ERR(rx8010->rtc);
+ }
+
+ rx8010->rtc->max_user_freq = 1;
+
+ return err;
+}
+
+static struct i2c_driver rx8010_driver = {
+ .driver = {
+ .name = "rtc-rx8010",
+ },
+ .probe = rx8010_probe,
+ .id_table = rx8010_id,
+};
+
+module_i2c_driver(rx8010_driver);
+
+MODULE_AUTHOR("Akshay Bhat <akshay.bhat@timesys.com>");
+MODULE_DESCRIPTION("Epson RX8010SJ RTC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index f2504b4eef34..7407d7394bb4 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -38,7 +38,22 @@
*/
#define UDR_READ_RETRY_CNT 5
-/* Registers used by the driver which are different between chipsets. */
+/*
+ * Registers used by the driver which are different between chipsets.
+ *
+ * Operations like read time and write alarm/time require updating
+ * specific fields in UDR register. These fields usually are auto-cleared
+ * (with some exceptions).
+ *
+ * Table of operations per device:
+ *
+ * Device | Write time | Read time | Write alarm
+ * =================================================
+ * S5M8767 | UDR + TIME | | UDR
+ * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR
+ * S2MPS13 | WUDR | RUDR | WUDR + AUDR
+ * S2MPS15 | WUDR | RUDR | AUDR
+ */
struct s5m_rtc_reg_config {
/* Number of registers used for setting time/alarm0/alarm1 */
unsigned int regs_count;
@@ -55,9 +70,16 @@ struct s5m_rtc_reg_config {
* will enable update of time or alarm register. Then it will be
* auto-cleared after successful update.
*/
- unsigned int rtc_udr_update;
- /* Mask for UDR field in 'rtc_udr_update' register */
- unsigned int rtc_udr_mask;
+ unsigned int udr_update;
+ /* Auto-cleared mask in UDR field for writing time and alarm */
+ unsigned int autoclear_udr_mask;
+ /*
+ * Masks in UDR field for time and alarm operations.
+ * The read time mask can be 0. Rest should not.
+ */
+ unsigned int read_time_udr_mask;
+ unsigned int write_time_udr_mask;
+ unsigned int write_alarm_udr_mask;
};
/* Register map for S5M8763 and S5M8767 */
@@ -67,22 +89,56 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = {
.ctrl = S5M_ALARM1_CONF,
.alarm0 = S5M_ALARM0_SEC,
.alarm1 = S5M_ALARM1_SEC,
- .rtc_udr_update = S5M_RTC_UDR_CON,
- .rtc_udr_mask = S5M_RTC_UDR_MASK,
+ .udr_update = S5M_RTC_UDR_CON,
+ .autoclear_udr_mask = S5M_RTC_UDR_MASK,
+ .read_time_udr_mask = 0, /* Not needed */
+ .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK,
+ .write_alarm_udr_mask = S5M_RTC_UDR_MASK,
+};
+
+/* Register map for S2MPS13 */
+static const struct s5m_rtc_reg_config s2mps13_rtc_regs = {
+ .regs_count = 7,
+ .time = S2MPS_RTC_SEC,
+ .ctrl = S2MPS_RTC_CTRL,
+ .alarm0 = S2MPS_ALARM0_SEC,
+ .alarm1 = S2MPS_ALARM1_SEC,
+ .udr_update = S2MPS_RTC_UDR_CON,
+ .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK,
+ .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
+ .write_time_udr_mask = S2MPS_RTC_WUDR_MASK,
+ .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK,
+};
+
+/* Register map for S2MPS11/14 */
+static const struct s5m_rtc_reg_config s2mps14_rtc_regs = {
+ .regs_count = 7,
+ .time = S2MPS_RTC_SEC,
+ .ctrl = S2MPS_RTC_CTRL,
+ .alarm0 = S2MPS_ALARM0_SEC,
+ .alarm1 = S2MPS_ALARM1_SEC,
+ .udr_update = S2MPS_RTC_UDR_CON,
+ .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK,
+ .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
+ .write_time_udr_mask = S2MPS_RTC_WUDR_MASK,
+ .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK,
};
/*
- * Register map for S2MPS14.
- * It may be also suitable for S2MPS11 but this was not tested.
+ * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits
+ * are swapped.
*/
-static const struct s5m_rtc_reg_config s2mps_rtc_regs = {
+static const struct s5m_rtc_reg_config s2mps15_rtc_regs = {
.regs_count = 7,
.time = S2MPS_RTC_SEC,
.ctrl = S2MPS_RTC_CTRL,
.alarm0 = S2MPS_ALARM0_SEC,
.alarm1 = S2MPS_ALARM1_SEC,
- .rtc_udr_update = S2MPS_RTC_UDR_CON,
- .rtc_udr_mask = S2MPS_RTC_WUDR_MASK,
+ .udr_update = S2MPS_RTC_UDR_CON,
+ .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK,
+ .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
+ .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK,
+ .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK,
};
struct s5m_rtc_info {
@@ -166,9 +222,8 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
unsigned int data;
do {
- ret = regmap_read(info->regmap, info->regs->rtc_udr_update,
- &data);
- } while (--retry && (data & info->regs->rtc_udr_mask) && !ret);
+ ret = regmap_read(info->regmap, info->regs->udr_update, &data);
+ } while (--retry && (data & info->regs->autoclear_udr_mask) && !ret);
if (!retry)
dev_err(info->dev, "waiting for UDR update, reached max number of retries\n");
@@ -188,6 +243,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
val &= S5M_ALARM0_STATUS;
break;
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2,
@@ -213,17 +269,15 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
int ret;
unsigned int data;
- ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data);
+ ret = regmap_read(info->regmap, info->regs->udr_update, &data);
if (ret < 0) {
dev_err(info->dev, "failed to read update reg(%d)\n", ret);
return ret;
}
- data |= info->regs->rtc_udr_mask;
- if (info->device_type == S5M8763X || info->device_type == S5M8767X)
- data |= S5M_RTC_TIME_EN_MASK;
+ data |= info->regs->write_time_udr_mask;
- ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);
+ ret = regmap_write(info->regmap, info->regs->udr_update, data);
if (ret < 0) {
dev_err(info->dev, "failed to write update reg(%d)\n", ret);
return ret;
@@ -239,30 +293,29 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
int ret;
unsigned int data;
- ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data);
+ ret = regmap_read(info->regmap, info->regs->udr_update, &data);
if (ret < 0) {
dev_err(info->dev, "%s: fail to read update reg(%d)\n",
__func__, ret);
return ret;
}
- data |= info->regs->rtc_udr_mask;
+ data |= info->regs->write_alarm_udr_mask;
switch (info->device_type) {
case S5M8763X:
case S5M8767X:
data &= ~S5M_RTC_TIME_EN_MASK;
break;
+ case S2MPS15X:
case S2MPS14X:
- data |= S2MPS_RTC_RUDR_MASK;
- break;
case S2MPS13X:
- data |= S2MPS13_RTC_AUDR_MASK;
+ /* No exceptions needed */
break;
default:
return -EINVAL;
}
- ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);
+ ret = regmap_write(info->regmap, info->regs->udr_update, data);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write update reg(%d)\n",
__func__, ret);
@@ -273,7 +326,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
/* On S2MPS13 the AUDR is not auto-cleared */
if (info->device_type == S2MPS13X)
- regmap_update_bits(info->regmap, info->regs->rtc_udr_update,
+ regmap_update_bits(info->regmap, info->regs->udr_update,
S2MPS13_RTC_AUDR_MASK, 0);
return ret;
@@ -317,10 +370,11 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
u8 data[info->regs->regs_count];
int ret;
- if (info->device_type == S2MPS14X || info->device_type == S2MPS13X) {
+ if (info->regs->read_time_udr_mask) {
ret = regmap_update_bits(info->regmap,
- info->regs->rtc_udr_update,
- S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK);
+ info->regs->udr_update,
+ info->regs->read_time_udr_mask,
+ info->regs->read_time_udr_mask);
if (ret) {
dev_err(dev,
"Failed to prepare registers for time reading: %d\n",
@@ -339,6 +393,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
break;
case S5M8767X:
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode);
@@ -366,6 +421,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
s5m8763_tm_to_data(tm, data);
break;
case S5M8767X:
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
ret = s5m8767_tm_to_data(tm, data);
@@ -414,6 +470,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
break;
case S5M8767X:
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
@@ -463,6 +520,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
break;
case S5M8767X:
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
for (i = 0; i < info->regs->regs_count; i++)
@@ -508,6 +566,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
break;
case S5M8767X:
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
data[RTC_SEC] |= ALARM_ENABLE_MASK;
@@ -548,6 +607,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
break;
case S5M8767X:
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
s5m8767_tm_to_data(&alrm->time, data);
@@ -631,6 +691,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2);
break;
+ case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
@@ -679,10 +740,19 @@ static int s5m_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
switch (platform_get_device_id(pdev)->driver_data) {
+ case S2MPS15X:
+ regmap_cfg = &s2mps14_rtc_regmap_config;
+ info->regs = &s2mps15_rtc_regs;
+ alarm_irq = S2MPS14_IRQ_RTCA0;
+ break;
case S2MPS14X:
+ regmap_cfg = &s2mps14_rtc_regmap_config;
+ info->regs = &s2mps14_rtc_regs;
+ alarm_irq = S2MPS14_IRQ_RTCA0;
+ break;
case S2MPS13X:
regmap_cfg = &s2mps14_rtc_regmap_config;
- info->regs = &s2mps_rtc_regs;
+ info->regs = &s2mps13_rtc_regs;
alarm_irq = S2MPS14_IRQ_RTCA0;
break;
case S5M8763X:
@@ -805,6 +875,7 @@ static const struct platform_device_id s5m_rtc_id[] = {
{ "s5m-rtc", S5M8767X },
{ "s2mps13-rtc", S2MPS13X },
{ "s2mps14-rtc", S2MPS14X },
+ { "s2mps15-rtc", S2MPS15X },
{ },
};
MODULE_DEVICE_TABLE(platform, s5m_rtc_id);
diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c
index 52543ae37c98..abada609ddc7 100644
--- a/drivers/rtc/rtc-sunxi.c
+++ b/drivers/rtc/rtc-sunxi.c
@@ -133,7 +133,7 @@ struct sunxi_rtc_data_year {
unsigned char leap_shift; /* bit shift to get the leap year */
};
-static struct sunxi_rtc_data_year data_year_param[] = {
+static const struct sunxi_rtc_data_year data_year_param[] = {
[0] = {
.min = 2010,
.max = 2073,
@@ -151,7 +151,7 @@ static struct sunxi_rtc_data_year data_year_param[] = {
struct sunxi_rtc_dev {
struct rtc_device *rtc;
struct device *dev;
- struct sunxi_rtc_data_year *data_year;
+ const struct sunxi_rtc_data_year *data_year;
void __iomem *base;
int irq;
};
@@ -175,7 +175,7 @@ static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id)
return IRQ_NONE;
}
-static void sunxi_rtc_setaie(int to, struct sunxi_rtc_dev *chip)
+static void sunxi_rtc_setaie(unsigned int to, struct sunxi_rtc_dev *chip)
{
u32 alrm_val = 0;
u32 alrm_irq_val = 0;
@@ -343,7 +343,7 @@ static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm)
struct sunxi_rtc_dev *chip = dev_get_drvdata(dev);
u32 date = 0;
u32 time = 0;
- int year;
+ unsigned int year;
/*
* the input rtc_tm->tm_year is the offset relative to 1900. We use
@@ -353,8 +353,8 @@ static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm)
year = rtc_tm->tm_year + 1900;
if (year < chip->data_year->min || year > chip->data_year->max) {
- dev_err(dev, "rtc only supports year in range %d - %d\n",
- chip->data_year->min, chip->data_year->max);
+ dev_err(dev, "rtc only supports year in range %u - %u\n",
+ chip->data_year->min, chip->data_year->max);
return -EINVAL;
}
@@ -436,7 +436,6 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
{
struct sunxi_rtc_dev *chip;
struct resource *res;
- const struct of_device_id *of_id;
int ret;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
@@ -463,12 +462,11 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
return ret;
}
- of_id = of_match_device(sunxi_rtc_dt_ids, &pdev->dev);
- if (!of_id) {
+ chip->data_year = of_device_get_match_data(&pdev->dev);
+ if (!chip->data_year) {
dev_err(&pdev->dev, "Unable to setup RTC data\n");
return -ENODEV;
}
- chip->data_year = (struct sunxi_rtc_data_year *) of_id->data;
/* clear the alarm count value */
writel(0, chip->base + SUNXI_ALRM_DHMS);
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 7273855ed02e..463e286064ab 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -91,7 +91,12 @@ max_user_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
struct rtc_device *rtc = to_rtc_device(dev);
- unsigned long val = simple_strtoul(buf, NULL, 0);
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 0, &val);
+ if (err)
+ return err;
if (val >= 4096 || val == 0)
return -EINVAL;
@@ -175,7 +180,9 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
} else
adjust = 1;
}
- alarm = simple_strtoul(buf_ptr, NULL, 0);
+ retval = kstrtoul(buf_ptr, 0, &alarm);
+ if (retval)
+ return retval;
if (adjust) {
alarm += now;
}
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index f9f97098c254..7a0436329d6c 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -57,7 +57,7 @@ struct v3020 {
/* GPIO access */
struct gpio *gpio;
- struct v3020_chip_ops *ops;
+ const struct v3020_chip_ops *ops;
struct rtc_device *rtc;
};
@@ -95,7 +95,7 @@ static unsigned char v3020_mmio_read_bit(struct v3020 *chip)
return !!(readl(chip->ioaddress) & (1 << chip->leftshift));
}
-static struct v3020_chip_ops v3020_mmio_ops = {
+static const struct v3020_chip_ops v3020_mmio_ops = {
.map_io = v3020_mmio_map,
.unmap_io = v3020_mmio_unmap,
.read_bit = v3020_mmio_read_bit,
@@ -158,7 +158,7 @@ static unsigned char v3020_gpio_read_bit(struct v3020 *chip)
return bit;
}
-static struct v3020_chip_ops v3020_gpio_ops = {
+static const struct v3020_chip_ops v3020_gpio_ops = {
.map_io = v3020_gpio_map,
.unmap_io = v3020_gpio_unmap,
.read_bit = v3020_gpio_read_bit,
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index a263c10359e1..41605dac8309 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2556,8 +2556,12 @@ static void __dasd_process_request_queue(struct dasd_block *block)
return;
}
- /* if device ist stopped do not fetch new requests */
- if (basedev->stopped)
+ /*
+ * if device is stopped do not fetch new requests
+ * except failfast is active which will let requests fail
+ * immediately in __dasd_block_start_head()
+ */
+ if (basedev->stopped && !(basedev->features & DASD_FEATURE_FAILFAST))
return;
/* Now we try to fetch requests from the request queue */
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 94a8f4ab57bc..ce7b70181740 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -17,6 +17,7 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/pfn_t.h>
#include <asm/extmem.h>
#include <asm/io.h>
@@ -30,7 +31,7 @@ static void dcssblk_release(struct gendisk *disk, fmode_t mode);
static blk_qc_t dcssblk_make_request(struct request_queue *q,
struct bio *bio);
static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
- void __pmem **kaddr, unsigned long *pfn);
+ void __pmem **kaddr, pfn_t *pfn);
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
@@ -883,20 +884,18 @@ fail:
static long
dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
- void __pmem **kaddr, unsigned long *pfn)
+ void __pmem **kaddr, pfn_t *pfn)
{
struct dcssblk_dev_info *dev_info;
unsigned long offset, dev_sz;
- void *addr;
dev_info = bdev->bd_disk->private_data;
if (!dev_info)
return -ENODEV;
dev_sz = dev_info->end - dev_info->start;
offset = secnum * 512;
- addr = (void *) (dev_info->start + offset);
- *pfn = virt_to_phys(addr) >> PAGE_SHIFT;
- *kaddr = (void __pmem *) addr;
+ *kaddr = (void __pmem *) (dev_info->start + offset);
+ *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV);
return dev_sz - offset;
}
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index eaca3e006301..b3f1c458905f 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -78,19 +78,6 @@ config SCLP_VT220_CONSOLE
Include support for using an IBM SCLP VT220-compatible terminal as a
Linux system console.
-config SCLP_CPI
- def_tristate m
- prompt "Control-Program Identification"
- depends on S390
- help
- This option enables the hardware console interface for system
- identification. This is commonly used for workload management and
- gives you a nice name for the system on the service element.
- Please select this option as a module since built-in operation is
- completely untested.
- You should only select this option if you know what you are doing,
- need this feature and intend to run your kernel in LPAR.
-
config SCLP_ASYNC
def_tristate m
prompt "Support for Call Home via Asynchronous SCLP Records"
@@ -125,6 +112,14 @@ config HMC_DRV
transfer cache size from it's default value 0.5MB to N bytes. If N
is zero, then no caching is performed.
+config SCLP_OFB
+ def_bool n
+ prompt "Support for Open-for-Business SCLP Event"
+ depends on S390
+ help
+ This option enables the Open-for-Business interface to the s390
+ Service Element.
+
config S390_TAPE
def_tristate m
prompt "S/390 tape device support"
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 6fa9364d1c07..dd2f7c832e5e 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_TN3215) += con3215.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
-obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o
obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
@@ -30,9 +29,7 @@ obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
obj-$(CONFIG_MONREADER) += monreader.o
obj-$(CONFIG_MONWRITER) += monwriter.o
obj-$(CONFIG_S390_VMUR) += vmur.o
-
-zcore_mod-objs := sclp_sdias.o zcore.o
-obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
+obj-$(CONFIG_CRASH_DUMP) += sclp_sdias.o zcore.o
hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o
obj-$(CONFIG_HMC_DRV) += hmcdrv.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 0fc3fe5fd5b8..7d82bbcb12df 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -922,6 +922,8 @@ static int __init con3215_init(void)
spin_lock_init(&raw3215_freelist_lock);
for (i = 0; i < NR_3215_REQ; i++) {
req = kzalloc(sizeof(struct raw3215_req), GFP_KERNEL | GFP_DMA);
+ if (!req)
+ return -ENOMEM;
req->next = raw3215_freelist;
raw3215_freelist = req;
}
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 7c511add5aa7..4d7a9badfede 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -606,6 +606,8 @@ con3270_init(void)
return PTR_ERR(rp);
condev = kzalloc(sizeof(struct con3270), GFP_KERNEL | GFP_DMA);
+ if (!condev)
+ return -ENOMEM;
condev->view.dev = rp;
condev->read = raw3270_request_alloc(0);
diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c
index d4b61d9088fb..8cb7d8fbadd6 100644
--- a/drivers/s390/char/hmcdrv_ftp.c
+++ b/drivers/s390/char/hmcdrv_ftp.c
@@ -37,7 +37,7 @@ struct hmcdrv_ftp_ops {
static enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len);
static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp);
-static struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */
+static const struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */
static DEFINE_MUTEX(hmcdrv_ftp_mutex); /* mutex for hmcdrv_ftp_funcs */
static unsigned hmcdrv_ftp_refcnt; /* start/shutdown reference counter */
@@ -290,13 +290,13 @@ ssize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset,
*/
int hmcdrv_ftp_startup(void)
{
- static struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = {
+ static const struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = {
.startup = diag_ftp_startup,
.shutdown = diag_ftp_shutdown,
.transfer = diag_ftp_cmd
};
- static struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = {
+ static const struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = {
.startup = sclp_ftp_startup,
.shutdown = sclp_ftp_shutdown,
.transfer = sclp_ftp_cmd
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index f58bf4c6c3ee..272898225dbb 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -579,9 +579,8 @@ sclp_sync_wait(void)
old_tick = local_tick_disable();
trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
- cr0_sync = cr0;
- cr0_sync &= 0xffff00a0;
- cr0_sync |= 0x00000200;
+ cr0_sync = cr0 & ~CR0_IRQ_SUBCLASS_MASK;
+ cr0_sync |= 1UL << (63 - 54);
__ctl_load(cr0_sync, 0, 0);
__arch_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 944156207477..2ced50ccca63 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -11,6 +11,8 @@
#include <linux/cpu.h>
#include <linux/device.h>
#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <asm/smp.h>
#include "sclp.h"
@@ -20,8 +22,22 @@ struct conf_mgm_data {
u8 ev_qualifier;
} __attribute__((packed));
+#define OFB_DATA_MAX 64
+
+struct sclp_ofb_evbuf {
+ struct evbuf_header header;
+ struct conf_mgm_data cm_data;
+ char ev_data[OFB_DATA_MAX];
+} __packed;
+
+struct sclp_ofb_sccb {
+ struct sccb_header header;
+ struct sclp_ofb_evbuf ofb_evbuf;
+} __packed;
+
#define EV_QUAL_CPU_CHANGE 1
#define EV_QUAL_CAP_CHANGE 3
+#define EV_QUAL_OPEN4BUSINESS 5
static struct work_struct sclp_cpu_capability_work;
static struct work_struct sclp_cpu_change_work;
@@ -63,15 +79,99 @@ static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
static struct sclp_register sclp_conf_register =
{
+#ifdef CONFIG_SCLP_OFB
+ .send_mask = EVTYP_CONFMGMDATA_MASK,
+#endif
.receive_mask = EVTYP_CONFMGMDATA_MASK,
.receiver_fn = sclp_conf_receiver_fn,
};
+#ifdef CONFIG_SCLP_OFB
+static int sclp_ofb_send_req(char *ev_data, size_t len)
+{
+ static DEFINE_MUTEX(send_mutex);
+ struct sclp_ofb_sccb *sccb;
+ int rc, response;
+
+ if (len > OFB_DATA_MAX)
+ return -EINVAL;
+ sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!sccb)
+ return -ENOMEM;
+ /* Setup SCCB for Control-Program Identification */
+ sccb->header.length = sizeof(struct sclp_ofb_sccb);
+ sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
+ sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
+ sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
+ memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);
+
+ if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
+ pr_warn("SCLP receiver did not register to receive "
+ "Configuration Management Data Events.\n");
+
+ mutex_lock(&send_mutex);
+ rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
+ mutex_unlock(&send_mutex);
+ if (rc)
+ goto out;
+ response = sccb->header.response_code;
+ if (response != 0x0020) {
+ pr_err("Open for Business request failed with response code "
+ "0x%04x\n", response);
+ rc = -EIO;
+ }
+out:
+ free_page((unsigned long)sccb);
+ return rc;
+}
+
+static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ int rc;
+
+ rc = sclp_ofb_send_req(buf, count);
+ return rc ?: count;
+}
+
+static struct bin_attribute ofb_bin_attr = {
+ .attr = {
+ .name = "event_data",
+ .mode = S_IWUSR,
+ },
+ .write = sysfs_ofb_data_write,
+};
+#endif
+
+static int __init sclp_ofb_setup(void)
+{
+#ifdef CONFIG_SCLP_OFB
+ struct kset *ofb_kset;
+ int rc;
+
+ ofb_kset = kset_create_and_add("ofb", NULL, firmware_kobj);
+ if (!ofb_kset)
+ return -ENOMEM;
+ rc = sysfs_create_bin_file(&ofb_kset->kobj, &ofb_bin_attr);
+ if (rc) {
+ kset_unregister(ofb_kset);
+ return rc;
+ }
+#endif
+ return 0;
+}
+
static int __init sclp_conf_init(void)
{
+ int rc;
+
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
- return sclp_register(&sclp_conf_register);
+ rc = sclp_register(&sclp_conf_register);
+ if (rc)
+ return rc;
+ return sclp_ofb_setup();
}
__initcall(sclp_conf_init);
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
deleted file mode 100644
index d70d8c20229c..000000000000
--- a/drivers/s390/char/sclp_cpi.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SCLP control programm identification
- *
- * Copyright IBM Corp. 2001, 2007
- * Author(s): Martin Peschke <mpeschke@de.ibm.com>
- * Michael Ernst <mernst@de.ibm.com>
- */
-
-#include <linux/kmod.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/version.h>
-#include "sclp_cpi_sys.h"
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Identify this operating system instance "
- "to the System z hardware");
-MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, "
- "Michael Ernst <mernst@de.ibm.com>");
-
-static char *system_name = "";
-static char *sysplex_name = "";
-
-module_param(system_name, charp, 0);
-MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
-module_param(sysplex_name, charp, 0);
-MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
-
-static int __init cpi_module_init(void)
-{
- return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
- LINUX_VERSION_CODE);
-}
-
-static void __exit cpi_module_exit(void)
-{
-}
-
-module_init(cpi_module_init);
-module_exit(cpi_module_exit);
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3339b862ec17..5043ecfa1fbc 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -28,13 +28,12 @@
#include <asm/processor.h>
#include <asm/irqflags.h>
#include <asm/checksum.h>
+#include <asm/os_info.h>
#include <asm/switch_to.h>
#include "sclp.h"
#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
-#define TO_USER 1
-#define TO_KERNEL 0
#define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */
enum arch_id {
@@ -42,241 +41,93 @@ enum arch_id {
ARCH_S390X = 1,
};
-/* dump system info */
-
-struct sys_info {
- enum arch_id arch;
- unsigned long sa_base;
- u32 sa_size;
- int cpu_map[NR_CPUS];
- unsigned long mem_size;
- struct save_area lc_mask;
-};
-
struct ipib_info {
unsigned long ipib;
u32 checksum;
} __attribute__((packed));
-static struct sys_info sys_info;
static struct debug_info *zcore_dbf;
static int hsa_available;
static struct dentry *zcore_dir;
-static struct dentry *zcore_file;
static struct dentry *zcore_memmap_file;
static struct dentry *zcore_reipl_file;
static struct dentry *zcore_hsa_file;
static struct ipl_parameter_block *ipl_block;
+static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
+
/*
- * Copy memory from HSA to kernel or user memory (not reentrant):
+ * Copy memory from HSA to user memory (not reentrant):
*
- * @dest: Kernel or user buffer where memory should be copied to
+ * @dest: User buffer where memory should be copied to
* @src: Start address within HSA where data should be copied
* @count: Size of buffer, which should be copied
- * @mode: Either TO_KERNEL or TO_USER
*/
-int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
+int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
{
- int offs, blk_num;
- static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+ unsigned long offset, bytes;
if (!hsa_available)
return -ENODATA;
- if (count == 0)
- return 0;
- /* copy first block */
- offs = 0;
- if ((src % PAGE_SIZE) != 0) {
- blk_num = src / PAGE_SIZE + 2;
- if (sclp_sdias_copy(buf, blk_num, 1)) {
+ while (count) {
+ if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
TRACE("sclp_sdias_copy() failed\n");
return -EIO;
}
- offs = min((PAGE_SIZE - (src % PAGE_SIZE)), count);
- if (mode == TO_USER) {
- if (copy_to_user((__force __user void*) dest,
- buf + (src % PAGE_SIZE), offs))
- return -EFAULT;
- } else
- memcpy(dest, buf + (src % PAGE_SIZE), offs);
- }
- if (offs == count)
- goto out;
-
- /* copy middle */
- for (; (offs + PAGE_SIZE) <= count; offs += PAGE_SIZE) {
- blk_num = (src + offs) / PAGE_SIZE + 2;
- if (sclp_sdias_copy(buf, blk_num, 1)) {
- TRACE("sclp_sdias_copy() failed\n");
- return -EIO;
- }
- if (mode == TO_USER) {
- if (copy_to_user((__force __user void*) dest + offs,
- buf, PAGE_SIZE))
- return -EFAULT;
- } else
- memcpy(dest + offs, buf, PAGE_SIZE);
- }
- if (offs == count)
- goto out;
-
- /* copy last block */
- blk_num = (src + offs) / PAGE_SIZE + 2;
- if (sclp_sdias_copy(buf, blk_num, 1)) {
- TRACE("sclp_sdias_copy() failed\n");
- return -EIO;
- }
- if (mode == TO_USER) {
- if (copy_to_user((__force __user void*) dest + offs, buf,
- count - offs))
+ offset = src % PAGE_SIZE;
+ bytes = min(PAGE_SIZE - offset, count);
+ if (copy_to_user(dest, hsa_buf + offset, bytes))
return -EFAULT;
- } else
- memcpy(dest + offs, buf, count - offs);
-out:
- return 0;
-}
-
-static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
-{
- return memcpy_hsa((void __force *) dest, src, count, TO_USER);
-}
-
-static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
-{
- return memcpy_hsa(dest, src, count, TO_KERNEL);
-}
-
-static int __init init_cpu_info(enum arch_id arch)
-{
- struct save_area_ext *sa_ext;
-
- /* get info for boot cpu from lowcore, stored in the HSA */
-
- sa_ext = dump_save_areas.areas[0];
- if (!sa_ext)
- return -ENOMEM;
- if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base,
- sys_info.sa_size) < 0) {
- TRACE("could not copy from HSA\n");
- kfree(sa_ext);
- return -EIO;
+ src += bytes;
+ dest += bytes;
+ count -= bytes;
}
- if (MACHINE_HAS_VX)
- save_vx_regs_safe(sa_ext->vx_regs);
return 0;
}
-static DEFINE_MUTEX(zcore_mutex);
-
-#define DUMP_VERSION 0x5
-#define DUMP_MAGIC 0xa8190173618f23fdULL
-#define DUMP_ARCH_S390X 2
-#define DUMP_ARCH_S390 1
-#define HEADER_SIZE 4096
-
-/* dump header dumped according to s390 crash dump format */
-
-struct zcore_header {
- u64 magic;
- u32 version;
- u32 header_size;
- u32 dump_level;
- u32 page_size;
- u64 mem_size;
- u64 mem_start;
- u64 mem_end;
- u32 num_pages;
- u32 pad1;
- u64 tod;
- struct cpuid cpu_id;
- u32 arch_id;
- u32 volnr;
- u32 build_arch;
- u64 rmem_size;
- u8 mvdump;
- u16 cpu_cnt;
- u16 real_cpu_cnt;
- u8 end_pad1[0x200-0x061];
- u64 mvdump_sign;
- u64 mvdump_zipl_time;
- u8 end_pad2[0x800-0x210];
- u32 lc_vec[512];
-} __attribute__((packed,__aligned__(16)));
-
-static struct zcore_header zcore_header = {
- .magic = DUMP_MAGIC,
- .version = DUMP_VERSION,
- .header_size = 4096,
- .dump_level = 0,
- .page_size = PAGE_SIZE,
- .mem_start = 0,
- .build_arch = DUMP_ARCH_S390X,
-};
-
/*
- * Copy lowcore info to buffer. Use map in order to copy only register parts.
+ * Copy memory from HSA to kernel memory (not reentrant):
*
- * @buf: User buffer
- * @sa: Pointer to save area
- * @sa_off: Offset in save area to copy
- * @len: Number of bytes to copy
+ * @dest: Kernel or user buffer where memory should be copied to
+ * @src: Start address within HSA where data should be copied
+ * @count: Size of buffer, which should be copied
*/
-static int copy_lc(void __user *buf, void *sa, int sa_off, int len)
+int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
{
- int i;
- char *lc_mask = (char*)&sys_info.lc_mask;
+ unsigned long offset, bytes;
- for (i = 0; i < len; i++) {
- if (!lc_mask[i + sa_off])
- continue;
- if (copy_to_user(buf + i, sa + sa_off + i, 1))
- return -EFAULT;
+ if (!hsa_available)
+ return -ENODATA;
+
+ while (count) {
+ if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
+ TRACE("sclp_sdias_copy() failed\n");
+ return -EIO;
+ }
+ offset = src % PAGE_SIZE;
+ bytes = min(PAGE_SIZE - offset, count);
+ memcpy(dest, hsa_buf + offset, bytes);
+ src += bytes;
+ dest += bytes;
+ count -= bytes;
}
return 0;
}
-/*
- * Copy lowcores info to memory, if necessary
- *
- * @buf: User buffer
- * @addr: Start address of buffer in dump memory
- * @count: Size of buffer
- */
-static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
+static int __init init_cpu_info(void)
{
- unsigned long end;
- int i;
-
- if (count == 0)
- return 0;
+ struct save_area *sa;
- end = start + count;
- for (i = 0; i < dump_save_areas.count; i++) {
- unsigned long cp_start, cp_end; /* copy range */
- unsigned long sa_start, sa_end; /* save area range */
- unsigned long prefix;
- unsigned long sa_off, len, buf_off;
- struct save_area *save_area = &dump_save_areas.areas[i]->sa;
-
- prefix = save_area->pref_reg;
- sa_start = prefix + sys_info.sa_base;
- sa_end = prefix + sys_info.sa_base + sys_info.sa_size;
-
- if ((end < sa_start) || (start > sa_end))
- continue;
- cp_start = max(start, sa_start);
- cp_end = min(end, sa_end);
-
- buf_off = cp_start - start;
- sa_off = cp_start - sa_start;
- len = cp_end - cp_start;
-
- TRACE("copy_lc for: %lx\n", start);
- if (copy_lc(buf + buf_off, save_area, sa_off, len))
- return -EFAULT;
+ /* get info for boot cpu from lowcore, stored in the HSA */
+ sa = save_area_boot_cpu();
+ if (!sa)
+ return -ENOMEM;
+ if (memcpy_hsa_kernel(hsa_buf, __LC_FPREGS_SAVE_AREA, 512) < 0) {
+ TRACE("could not copy from HSA\n");
+ return -EIO;
}
+ save_area_add_regs(sa, hsa_buf); /* vx registers are saved in smp.c */
return 0;
}
@@ -289,115 +140,6 @@ static void release_hsa(void)
hsa_available = 0;
}
-/*
- * Read routine for zcore character device
- * First 4K are dump header
- * Next 32MB are HSA Memory
- * Rest is read from absolute Memory
- */
-static ssize_t zcore_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- unsigned long mem_start; /* Start address in memory */
- size_t mem_offs; /* Offset in dump memory */
- size_t hdr_count; /* Size of header part of output buffer */
- size_t size;
- int rc;
-
- mutex_lock(&zcore_mutex);
-
- if (*ppos > (sys_info.mem_size + HEADER_SIZE)) {
- rc = -EINVAL;
- goto fail;
- }
-
- count = min(count, (size_t) (sys_info.mem_size + HEADER_SIZE - *ppos));
-
- /* Copy dump header */
- if (*ppos < HEADER_SIZE) {
- size = min(count, (size_t) (HEADER_SIZE - *ppos));
- if (copy_to_user(buf, &zcore_header + *ppos, size)) {
- rc = -EFAULT;
- goto fail;
- }
- hdr_count = size;
- mem_start = 0;
- } else {
- hdr_count = 0;
- mem_start = *ppos - HEADER_SIZE;
- }
-
- mem_offs = 0;
-
- /* Copy from HSA data */
- if (*ppos < sclp.hsa_size + HEADER_SIZE) {
- size = min((count - hdr_count),
- (size_t) (sclp.hsa_size - mem_start));
- rc = memcpy_hsa_user(buf + hdr_count, mem_start, size);
- if (rc)
- goto fail;
-
- mem_offs += size;
- }
-
- /* Copy from real mem */
- size = count - mem_offs - hdr_count;
- rc = copy_to_user_real(buf + hdr_count + mem_offs,
- (void *) mem_start + mem_offs, size);
- if (rc)
- goto fail;
-
- /*
- * Since s390 dump analysis tools like lcrash or crash
- * expect register sets in the prefix pages of the cpus,
- * we copy them into the read buffer, if necessary.
- * buf + hdr_count: Start of memory part of output buffer
- * mem_start: Start memory address to copy from
- * count - hdr_count: Size of memory area to copy
- */
- if (zcore_add_lc(buf + hdr_count, mem_start, count - hdr_count)) {
- rc = -EFAULT;
- goto fail;
- }
- *ppos += count;
-fail:
- mutex_unlock(&zcore_mutex);
- return (rc < 0) ? rc : count;
-}
-
-static int zcore_open(struct inode *inode, struct file *filp)
-{
- if (!hsa_available)
- return -ENODATA;
- else
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static int zcore_release(struct inode *inode, struct file *filep)
-{
- if (hsa_available)
- release_hsa();
- return 0;
-}
-
-static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
-{
- loff_t rc;
-
- mutex_lock(&zcore_mutex);
- rc = no_seek_end_llseek(file, offset, orig);
- mutex_unlock(&zcore_mutex);
- return rc;
-}
-
-static const struct file_operations zcore_fops = {
- .owner = THIS_MODULE,
- .llseek = zcore_lseek,
- .read = zcore_read,
- .open = zcore_open,
- .release = zcore_release,
-};
-
static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -501,50 +243,6 @@ static const struct file_operations zcore_hsa_fops = {
.llseek = no_llseek,
};
-static void __init set_lc_mask(struct save_area *map)
-{
- memset(&map->fp_regs, 0xff, sizeof(map->fp_regs));
- memset(&map->gp_regs, 0xff, sizeof(map->gp_regs));
- memset(&map->psw, 0xff, sizeof(map->psw));
- memset(&map->pref_reg, 0xff, sizeof(map->pref_reg));
- memset(&map->fp_ctrl_reg, 0xff, sizeof(map->fp_ctrl_reg));
- memset(&map->tod_reg, 0xff, sizeof(map->tod_reg));
- memset(&map->timer, 0xff, sizeof(map->timer));
- memset(&map->clk_cmp, 0xff, sizeof(map->clk_cmp));
- memset(&map->acc_regs, 0xff, sizeof(map->acc_regs));
- memset(&map->ctrl_regs, 0xff, sizeof(map->ctrl_regs));
-}
-
-/*
- * Initialize dump globals for a given architecture
- */
-static int __init sys_info_init(enum arch_id arch, unsigned long mem_end)
-{
- int rc;
-
- switch (arch) {
- case ARCH_S390X:
- pr_alert("DETECTED 'S390X (64 bit) OS'\n");
- break;
- case ARCH_S390:
- pr_alert("DETECTED 'S390 (32 bit) OS'\n");
- break;
- default:
- pr_alert("0x%x is an unknown architecture.\n",arch);
- return -EINVAL;
- }
- sys_info.sa_base = SAVE_AREA_BASE;
- sys_info.sa_size = sizeof(struct save_area);
- sys_info.arch = arch;
- set_lc_mask(&sys_info.lc_mask);
- rc = init_cpu_info(arch);
- if (rc)
- return rc;
- sys_info.mem_size = mem_end;
-
- return 0;
-}
-
static int __init check_sdias(void)
{
if (!sclp.hsa_size) {
@@ -554,43 +252,6 @@ static int __init check_sdias(void)
return 0;
}
-static int __init get_mem_info(unsigned long *mem, unsigned long *end)
-{
- struct memblock_region *reg;
-
- for_each_memblock(memory, reg) {
- *mem += reg->size;
- *end = max_t(unsigned long, *end, reg->base + reg->size);
- }
- return 0;
-}
-
-static void __init zcore_header_init(int arch, struct zcore_header *hdr,
- unsigned long mem_size)
-{
- u32 prefix;
- int i;
-
- if (arch == ARCH_S390X)
- hdr->arch_id = DUMP_ARCH_S390X;
- else
- hdr->arch_id = DUMP_ARCH_S390;
- hdr->mem_size = mem_size;
- hdr->rmem_size = mem_size;
- hdr->mem_end = sys_info.mem_size;
- hdr->num_pages = mem_size / PAGE_SIZE;
- hdr->tod = get_tod_clock();
- get_cpu_id(&hdr->cpu_id);
- for (i = 0; i < dump_save_areas.count; i++) {
- prefix = dump_save_areas.areas[i]->sa.pref_reg;
- hdr->real_cpu_cnt++;
- if (!prefix)
- continue;
- hdr->lc_vec[hdr->cpu_cnt] = prefix;
- hdr->cpu_cnt++;
- }
-}
-
/*
* Provide IPL parameter information block from either HSA or memory
* for future reipl
@@ -623,11 +284,9 @@ static int __init zcore_reipl_init(void)
static int __init zcore_init(void)
{
- unsigned long mem_size, mem_end;
unsigned char arch;
int rc;
- mem_size = mem_end = 0;
if (ipl_info.type != IPL_TYPE_FCP_DUMP)
return -ENODATA;
if (OLDMEM_BASE)
@@ -661,14 +320,10 @@ static int __init zcore_init(void)
goto fail;
}
- rc = get_mem_info(&mem_size, &mem_end);
- if (rc)
- goto fail;
-
- rc = sys_info_init(arch, mem_end);
+ pr_alert("DETECTED 'S390X (64 bit) OS'\n");
+ rc = init_cpu_info();
if (rc)
goto fail;
- zcore_header_init(arch, &zcore_header, mem_size);
rc = zcore_reipl_init();
if (rc)
@@ -679,17 +334,11 @@ static int __init zcore_init(void)
rc = -ENOMEM;
goto fail;
}
- zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL,
- &zcore_fops);
- if (!zcore_file) {
- rc = -ENOMEM;
- goto fail_dir;
- }
zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir,
NULL, &zcore_memmap_fops);
if (!zcore_memmap_file) {
rc = -ENOMEM;
- goto fail_file;
+ goto fail_dir;
}
zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
NULL, &zcore_reipl_fops);
@@ -709,8 +358,6 @@ fail_reipl_file:
debugfs_remove(zcore_reipl_file);
fail_memmap_file:
debugfs_remove(zcore_memmap_file);
-fail_file:
- debugfs_remove(zcore_file);
fail_dir:
debugfs_remove(zcore_dir);
fail:
@@ -726,7 +373,6 @@ static void __exit zcore_exit(void)
debugfs_remove(zcore_hsa_file);
debugfs_remove(zcore_reipl_file);
debugfs_remove(zcore_memmap_file);
- debugfs_remove(zcore_file);
debugfs_remove(zcore_dir);
diag308(DIAG308_REL_HSA, NULL);
}
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index 8c4a386e97f6..3ab9aedeb84a 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -2,8 +2,11 @@
# Makefile for the S/390 common i/o drivers
#
+# The following is required for define_trace.h to find ./trace.h
+CFLAGS_trace.o := -I$(src)
+
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
- fcx.o itcw.o crw.o ccwreq.o
+ fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 56eb4ee4deba..99b5db469097 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -89,6 +89,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
set_cpu_flag(CIF_NOHZ_DELAY);
tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ trace_s390_cio_adapter_int(tpi_info);
head = &airq_lists[tpi_info->isc];
rcu_read_lock();
hlist_for_each_entry_rcu(airq, head, list)
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 213159dec89e..b6f12c2bb114 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -133,7 +133,7 @@ static int chsc_subchannel_prepare(struct subchannel *sch)
* since we don't have a way to clear the subchannel and
* cannot disable it with a request running.
*/
- cc = stsch_err(sch->schid, &schib);
+ cc = stsch(sch->schid, &schib);
if (!cc && scsw_stctl(&schib.scsw))
return -EAGAIN;
return 0;
@@ -185,8 +185,7 @@ static int __init chsc_init_dbfs(void)
debug_set_level(chsc_debug_log_id, 2);
return 0;
out:
- if (chsc_debug_msg_id)
- debug_unregister(chsc_debug_msg_id);
+ debug_unregister(chsc_debug_msg_id);
return -ENOMEM;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 690b8547e828..39a8ae54e9c1 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -41,6 +41,7 @@
#include "blacklist.h"
#include "cio_debug.h"
#include "chp.h"
+#include "trace.h"
debug_info_t *cio_debug_msg_id;
debug_info_t *cio_debug_trace_id;
@@ -76,12 +77,9 @@ static int __init cio_debug_init(void)
return 0;
out_unregister:
- if (cio_debug_msg_id)
- debug_unregister(cio_debug_msg_id);
- if (cio_debug_trace_id)
- debug_unregister(cio_debug_trace_id);
- if (cio_debug_crw_id)
- debug_unregister(cio_debug_crw_id);
+ debug_unregister(cio_debug_msg_id);
+ debug_unregister(cio_debug_trace_id);
+ debug_unregister(cio_debug_crw_id);
return -1;
}
@@ -348,18 +346,18 @@ int cio_commit_config(struct subchannel *sch)
struct schib schib;
struct irb irb;
- if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
for (retry = 0; retry < 5; retry++) {
/* copy desired changes to local schib */
cio_apply_config(sch, &schib);
- ccode = msch_err(sch->schid, &schib);
+ ccode = msch(sch->schid, &schib);
if (ccode < 0) /* -EIO if msch gets a program check. */
return ccode;
switch (ccode) {
case 0: /* successful */
- if (stsch_err(sch->schid, &schib) ||
+ if (stsch(sch->schid, &schib) ||
!css_sch_is_valid(&schib))
return -ENODEV;
if (cio_check_config(sch, &schib)) {
@@ -394,7 +392,7 @@ int cio_update_schib(struct subchannel *sch)
{
struct schib schib;
- if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
memcpy(&sch->schib, &schib, sizeof(schib));
@@ -503,7 +501,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
* If stsch gets an exception, it means the current subchannel set
* is not valid.
*/
- ccode = stsch_err(schid, &sch->schib);
+ ccode = stsch(schid, &sch->schib);
if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode;
goto out;
@@ -542,6 +540,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
set_cpu_flag(CIF_NOHZ_DELAY);
tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ trace_s390_cio_interrupt(tpi_info);
irb = this_cpu_ptr(&cio_irb);
sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
if (!sch) {
@@ -619,7 +618,7 @@ static int cio_test_for_console(struct subchannel_id schid, void *data)
{
struct schib schib;
- if (stsch_err(schid, &schib) != 0)
+ if (stsch(schid, &schib) != 0)
return -ENXIO;
if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
(schib.pmcw.dev == console_devno)) {
@@ -638,7 +637,7 @@ static int cio_get_console_sch_no(void)
if (console_irq != -1) {
/* VM provided us with the irq number of the console. */
schid.sch_no = console_irq;
- if (stsch_err(schid, &schib) != 0 ||
+ if (stsch(schid, &schib) != 0 ||
(schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
return -1;
console_devno = schib.pmcw.dev;
@@ -708,10 +707,10 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
cc = 0;
for (retry=0;retry<3;retry++) {
schib->pmcw.ena = 0;
- cc = msch_err(schid, schib);
+ cc = msch(schid, schib);
if (cc)
return (cc==3?-ENODEV:-EBUSY);
- if (stsch_err(schid, schib) || !css_sch_is_valid(schib))
+ if (stsch(schid, schib) || !css_sch_is_valid(schib))
return -ENODEV;
if (!schib->pmcw.ena)
return 0;
@@ -758,7 +757,7 @@ static int stsch_reset(struct subchannel_id schid, struct schib *addr)
pgm_check_occured = 0;
s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
- rc = stsch_err(schid, addr);
+ rc = stsch(schid, addr);
s390_base_pgm_handler_fn = NULL;
/* The program check handler could have changed pgm_check_occured. */
@@ -795,7 +794,7 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
/* No default clear strategy */
break;
}
- stsch_err(schid, &schib);
+ stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
out:
@@ -917,7 +916,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
{
struct subchannel_id uninitialized_var(schid);
- s390_reset_system(NULL, NULL, NULL);
+ s390_reset_system();
if (reipl_find_schid(devid, &schid) != 0)
panic("IPL Device not found\n");
do_reipl_asm(*((__u32*)&schid));
@@ -943,7 +942,7 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS))
return -ENODEV;
}
- if (stsch_err(schid, &schib))
+ if (stsch(schid, &schib))
return -ENODEV;
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
return -ENODEV;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index a01376ae1749..93de0b46b489 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -45,6 +45,18 @@ struct pmcw {
/* ... in an operand exception. */
} __attribute__ ((packed));
+/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */
+struct tpi_info {
+ struct subchannel_id schid;
+ u32 intparm;
+ u32 adapter_IO:1;
+ u32 :1;
+ u32 isc:3;
+ u32 :27;
+ u32 type:3;
+ u32 :12;
+} __packed __aligned(4);
+
/* Target SCHIB configuration. */
struct schib_config {
u64 mba;
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index 0f8a25f98b10..3d3cd402b376 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -14,6 +14,7 @@
#include <linux/wait.h>
#include <asm/crw.h>
#include <asm/ctl_reg.h>
+#include "ioasm.h"
static DEFINE_MUTEX(crw_handler_mutex);
static crw_handler_t crw_handlers[NR_RSCS];
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 489e703dc82d..3d2b20ee613f 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -390,7 +390,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Will be done on the slow path. */
return -EAGAIN;
}
- if (stsch_err(schid, &schib)) {
+ if (stsch(schid, &schib)) {
/* Subchannel is not provided. */
return -ENXIO;
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 92e03b42e661..8327d47e08b6 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -44,7 +44,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
private = to_io_private(sch);
orb = &private->orb;
- cc = stsch_err(sch->schid, &schib);
+ cc = stsch(sch->schid, &schib);
printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
"device information:\n", get_tod_clock());
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index b108f4a5c7dd..8975060af96c 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -169,49 +169,4 @@ struct ccw_device_private {
enum interruption_class int_class;
};
-static inline int rsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " rsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc", "memory");
- return ccode;
-}
-
-static inline int hsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " hsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
-static inline int xsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " .insn rre,0xb2760000,%1,0\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
#endif
diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c
new file mode 100644
index 000000000000..98984818618f
--- /dev/null
+++ b/drivers/s390/cio/ioasm.c
@@ -0,0 +1,224 @@
+/*
+ * Channel subsystem I/O instructions.
+ */
+
+#include <linux/export.h>
+
+#include <asm/chpid.h>
+#include <asm/schid.h>
+#include <asm/crw.h>
+
+#include "ioasm.h"
+#include "orb.h"
+#include "cio.h"
+
+int stsch(struct subchannel_id schid, struct schib *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " stsch 0(%3)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
+ trace_s390_cio_stsch(schid, addr, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(stsch);
+
+int msch(struct subchannel_id schid, struct schib *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " msch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc");
+ trace_s390_cio_msch(schid, addr, ccode);
+
+ return ccode;
+}
+
+int tsch(struct subchannel_id schid, struct irb *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " tsch 0(%3)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
+ trace_s390_cio_tsch(schid, addr, ccode);
+
+ return ccode;
+}
+
+int ssch(struct subchannel_id schid, union orb *addr)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " ssch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc", "memory");
+ trace_s390_cio_ssch(schid, addr, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(ssch);
+
+int csch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " csch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_csch(schid, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(csch);
+
+int tpi(struct tpi_info *addr)
+{
+ int ccode;
+
+ asm volatile(
+ " tpi 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode), "=m" (*addr)
+ : "a" (addr)
+ : "cc");
+ trace_s390_cio_tpi(addr, ccode);
+
+ return ccode;
+}
+
+int chsc(void *chsc_area)
+{
+ typedef struct { char _[4096]; } addr_type;
+ int cc;
+
+ asm volatile(
+ " .insn rre,0xb25f0000,%2,0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (cc), "=m" (*(addr_type *) chsc_area)
+ : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
+ : "cc");
+ trace_s390_cio_chsc(chsc_area, cc);
+
+ return cc;
+}
+EXPORT_SYMBOL(chsc);
+
+int rchp(struct chp_id chpid)
+{
+ register struct chp_id reg1 asm ("1") = chpid;
+ int ccode;
+
+ asm volatile(
+ " lr 1,%1\n"
+ " rchp\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
+ trace_s390_cio_rchp(chpid, ccode);
+
+ return ccode;
+}
+
+int rsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " rsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc", "memory");
+ trace_s390_cio_rsch(schid, ccode);
+
+ return ccode;
+}
+
+int hsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " hsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_hsch(schid, ccode);
+
+ return ccode;
+}
+
+int xsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " xsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_xsch(schid, ccode);
+
+ return ccode;
+}
+
+int stcrw(struct crw *crw)
+{
+ int ccode;
+
+ asm volatile(
+ " stcrw 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "=m" (*crw)
+ : "a" (crw)
+ : "cc");
+ trace_s390_cio_stcrw(crw, ccode);
+
+ return ccode;
+}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 4d80fc67a06b..b31ee6bff1e4 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -3,165 +3,26 @@
#include <asm/chpid.h>
#include <asm/schid.h>
+#include <asm/crw.h>
#include "orb.h"
#include "cio.h"
+#include "trace.h"
/*
- * TPI info structure
+ * Some S390 specific IO instructions
*/
-struct tpi_info {
- struct subchannel_id schid;
- __u32 intparm; /* interruption parameter */
- __u32 adapter_IO : 1;
- __u32 reserved2 : 1;
- __u32 isc : 3;
- __u32 reserved3 : 12;
- __u32 int_type : 3;
- __u32 reserved4 : 12;
-} __attribute__ ((packed));
-
-/*
- * Some S390 specific IO instructions as inline
- */
-
-static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " stsch 0(%3)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "+d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int msch(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode;
-
- asm volatile(
- " msch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
- return ccode;
-}
-
-static inline int msch_err(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " msch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
- return ccode;
-}
-
-static inline int tsch(struct subchannel_id schid, struct irb *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode;
-
- asm volatile(
- " tsch 0(%3)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int ssch(struct subchannel_id schid, union orb *addr)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " ssch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b, 1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc", "memory");
- return ccode;
-}
-
-static inline int csch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " csch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
-static inline int tpi(struct tpi_info *addr)
-{
- int ccode;
-
- asm volatile(
- " tpi 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int chsc(void *chsc_area)
-{
- typedef struct { char _[4096]; } addr_type;
- int cc;
-
- asm volatile(
- " .insn rre,0xb25f0000,%2,0\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (cc), "=m" (*(addr_type *) chsc_area)
- : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
- : "cc");
- return cc;
-}
-
-static inline int rchp(struct chp_id chpid)
-{
- register struct chp_id reg1 asm ("1") = chpid;
- int ccode;
-
- asm volatile(
- " lr 1,%1\n"
- " rchp\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
- return ccode;
-}
+int stsch(struct subchannel_id schid, struct schib *addr);
+int msch(struct subchannel_id schid, struct schib *addr);
+int tsch(struct subchannel_id schid, struct irb *addr);
+int ssch(struct subchannel_id schid, union orb *addr);
+int csch(struct subchannel_id schid);
+int tpi(struct tpi_info *addr);
+int chsc(void *chsc_area);
+int rchp(struct chp_id chpid);
+int rsch(struct subchannel_id schid);
+int hsch(struct subchannel_id schid);
+int xsch(struct subchannel_id schid);
+int stcrw(struct crw *crw);
#endif
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f1f3baa8e6e4..b6fc147f83d8 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -366,8 +366,6 @@ void qdio_debug_exit(void)
{
qdio_clear_dbf_list();
debugfs_remove(debugfs_root);
- if (qdio_dbf_setup)
- debug_unregister(qdio_dbf_setup);
- if (qdio_dbf_error)
- debug_unregister(qdio_dbf_error);
+ debug_unregister(qdio_dbf_setup);
+ debug_unregister(qdio_dbf_error);
}
diff --git a/drivers/s390/cio/trace.c b/drivers/s390/cio/trace.c
new file mode 100644
index 000000000000..8e706669ac8b
--- /dev/null
+++ b/drivers/s390/cio/trace.c
@@ -0,0 +1,24 @@
+/*
+ * Tracepoint definitions for s390_cio
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+ */
+
+#include <asm/crw.h>
+#include "cio.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_stsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_msch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_tsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_tpi);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_ssch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_csch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_hsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_xsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_rsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_rchp);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_chsc);
diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h
new file mode 100644
index 000000000000..5b807a09f21b
--- /dev/null
+++ b/drivers/s390/cio/trace.h
@@ -0,0 +1,363 @@
+/*
+ * Tracepoint header for the s390 Common I/O layer (CIO)
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <asm/crw.h>
+#include <uapi/asm/chpid.h>
+#include <uapi/asm/schid.h>
+#include "cio.h"
+#include "orb.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM s390
+
+#if !defined(_TRACE_S390_CIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_S390_CIO_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(s390_class_schib,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field(u16, devno)
+ __field_struct(struct schib, schib)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->devno = schib->pmcw.dev;
+ __entry->schib = *schib;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d ena=%d st=%d dnv=%d dev=%04x "
+ "lpm=0x%02x pnom=0x%02x lpum=0x%02x pim=0x%02x pam=0x%02x "
+ "pom=0x%02x chpids=%016llx",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ __entry->schib.pmcw.ena, __entry->schib.pmcw.st,
+ __entry->schib.pmcw.dnv, __entry->schib.pmcw.dev,
+ __entry->schib.pmcw.lpm, __entry->schib.pmcw.pnom,
+ __entry->schib.pmcw.lpum, __entry->schib.pmcw.pim,
+ __entry->schib.pmcw.pam, __entry->schib.pmcw.pom,
+ *((u64 *) __entry->schib.pmcw.chpid)
+ )
+);
+
+/**
+ * s390_cio_stsch - Store Subchannel instruction (STSCH) was performed
+ * @schid: Subchannel ID
+ * @schib: Subchannel-Information block
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schib, s390_cio_stsch,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc)
+);
+
+/**
+ * s390_cio_msch - Modify Subchannel instruction (MSCH) was performed
+ * @schid: Subchannel ID
+ * @schib: Subchannel-Information block
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schib, s390_cio_msch,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc)
+);
+
+/**
+ * s390_cio_tsch - Test Subchannel instruction (TSCH) was performed
+ * @schid: Subchannel ID
+ * @irb: Interruption-Response Block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_tsch,
+ TP_PROTO(struct subchannel_id schid, struct irb *irb, int cc),
+ TP_ARGS(schid, irb, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field_struct(struct irb, irb)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->irb = *irb;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d dcc=%d pno=%d fctl=0x%x actl=0x%x "
+ "stctl=0x%x dstat=0x%x cstat=0x%x",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ scsw_cc(&__entry->irb.scsw), scsw_pno(&__entry->irb.scsw),
+ scsw_fctl(&__entry->irb.scsw), scsw_actl(&__entry->irb.scsw),
+ scsw_stctl(&__entry->irb.scsw),
+ scsw_dstat(&__entry->irb.scsw), scsw_cstat(&__entry->irb.scsw)
+ )
+);
+
+/**
+ * s390_cio_tpi - Test Pending Interruption instruction (TPI) was performed
+ * @addr: Address of the I/O interruption code or %NULL
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_tpi,
+ TP_PROTO(struct tpi_info *addr, int cc),
+ TP_ARGS(addr, cc),
+ TP_STRUCT__entry(
+ __field(int, cc)
+ __field_struct(struct tpi_info, tpi_info)
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ ),
+ TP_fast_assign(
+ __entry->cc = cc;
+ if (cc != 0)
+ memset(&__entry->tpi_info, 0, sizeof(struct tpi_info));
+ else if (addr)
+ __entry->tpi_info = *addr;
+ else {
+ memcpy(&__entry->tpi_info, &S390_lowcore.subchannel_id,
+ sizeof(struct tpi_info));
+ }
+ __entry->cssid = __entry->tpi_info.schid.cssid;
+ __entry->ssid = __entry->tpi_info.schid.ssid;
+ __entry->schno = __entry->tpi_info.schid.sch_no;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d a=%d isc=%d type=%d",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ __entry->tpi_info.adapter_IO, __entry->tpi_info.isc,
+ __entry->tpi_info.type
+ )
+);
+
+/**
+ * s390_cio_ssch - Start Subchannel instruction (SSCH) was performed
+ * @schid: Subchannel ID
+ * @orb: Operation-Request Block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_ssch,
+ TP_PROTO(struct subchannel_id schid, union orb *orb, int cc),
+ TP_ARGS(schid, orb, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field_struct(union orb, orb)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->orb = *orb;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d", __entry->cssid, __entry->ssid,
+ __entry->schno, __entry->cc
+ )
+);
+
+DECLARE_EVENT_CLASS(s390_class_schid,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d", __entry->cssid, __entry->ssid,
+ __entry->schno, __entry->cc
+ )
+);
+
+/**
+ * s390_cio_csch - Clear Subchannel instruction (CSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_csch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_hsch - Halt Subchannel instruction (HSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_hsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_xsch - Cancel Subchannel instruction (XSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_xsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_rsch - Resume Subchannel instruction (RSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_rsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_rchp - Reset Channel Path (RCHP) instruction was performed
+ * @chpid: Channel-Path Identifier
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_rchp,
+ TP_PROTO(struct chp_id chpid, int cc),
+ TP_ARGS(chpid, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, id)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = chpid.cssid;
+ __entry->id = chpid.id;
+ __entry->cc = cc;
+ ),
+ TP_printk("chpid=%x.%02x cc=%d", __entry->cssid, __entry->id,
+ __entry->cc
+ )
+);
+
+#define CHSC_MAX_REQUEST_LEN 64
+#define CHSC_MAX_RESPONSE_LEN 64
+
+/**
+ * s390_cio_chsc - Channel Subsystem Call (CHSC) instruction was performed
+ * @chsc: CHSC block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_chsc,
+ TP_PROTO(struct chsc_header *chsc, int cc),
+ TP_ARGS(chsc, cc),
+ TP_STRUCT__entry(
+ __field(int, cc)
+ __field(u16, code)
+ __field(u16, rcode)
+ __array(u8, request, CHSC_MAX_REQUEST_LEN)
+ __array(u8, response, CHSC_MAX_RESPONSE_LEN)
+ ),
+ TP_fast_assign(
+ __entry->cc = cc;
+ __entry->code = chsc->code;
+ memcpy(&entry->request, chsc,
+ min_t(u16, chsc->length, CHSC_MAX_REQUEST_LEN));
+ chsc = (struct chsc_header *) ((char *) chsc + chsc->length);
+ __entry->rcode = chsc->code;
+ memcpy(&entry->response, chsc,
+ min_t(u16, chsc->length, CHSC_MAX_RESPONSE_LEN));
+ ),
+ TP_printk("code=0x%04x cc=%d rcode=0x%04x", __entry->code,
+ __entry->cc, __entry->rcode)
+);
+
+/**
+ * s390_cio_interrupt - An I/O interrupt occurred
+ * @tpi_info: Address of the I/O interruption code
+ */
+TRACE_EVENT(s390_cio_interrupt,
+ TP_PROTO(struct tpi_info *tpi_info),
+ TP_ARGS(tpi_info),
+ TP_STRUCT__entry(
+ __field_struct(struct tpi_info, tpi_info)
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ ),
+ TP_fast_assign(
+ __entry->tpi_info = *tpi_info;
+ __entry->cssid = __entry->tpi_info.schid.cssid;
+ __entry->ssid = __entry->tpi_info.schid.ssid;
+ __entry->schno = __entry->tpi_info.schid.sch_no;
+ ),
+ TP_printk("schid=%x.%x.%04x isc=%d type=%d",
+ __entry->cssid, __entry->ssid, __entry->schno,
+ __entry->tpi_info.isc, __entry->tpi_info.type
+ )
+);
+
+/**
+ * s390_cio_adapter_int - An adapter interrupt occurred
+ * @tpi_info: Address of the I/O interruption code
+ */
+TRACE_EVENT(s390_cio_adapter_int,
+ TP_PROTO(struct tpi_info *tpi_info),
+ TP_ARGS(tpi_info),
+ TP_STRUCT__entry(
+ __field_struct(struct tpi_info, tpi_info)
+ ),
+ TP_fast_assign(
+ __entry->tpi_info = *tpi_info;
+ ),
+ TP_printk("isc=%d", __entry->tpi_info.isc)
+);
+
+/**
+ * s390_cio_stcrw - Store Channel Report Word (STCRW) was performed
+ * @crw: Channel Report Word
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_stcrw,
+ TP_PROTO(struct crw *crw, int cc),
+ TP_ARGS(crw, cc),
+ TP_STRUCT__entry(
+ __field_struct(struct crw, crw)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->crw = *crw;
+ __entry->cc = cc;
+ ),
+ TP_printk("cc=%d slct=%d oflw=%d chn=%d rsc=%d anc=%d erc=0x%x "
+ "rsid=0x%x",
+ __entry->cc, __entry->crw.slct, __entry->crw.oflw,
+ __entry->crw.chn, __entry->crw.rsc, __entry->crw.anc,
+ __entry->crw.erc, __entry->crw.rsid
+ )
+);
+
+#endif /* _TRACE_S390_CIO_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 9f8fa42c062c..5d3d04c040c2 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1428,10 +1428,8 @@ int __init zcrypt_debug_init(void)
void zcrypt_debug_exit(void)
{
debugfs_remove(debugfs_root);
- if (zcrypt_dbf_common)
- debug_unregister(zcrypt_dbf_common);
- if (zcrypt_dbf_devices)
- debug_unregister(zcrypt_dbf_devices);
+ debug_unregister(zcrypt_dbf_common);
+ debug_unregister(zcrypt_dbf_devices);
}
/**
diff --git a/drivers/s390/virtio/kvm_virtio.c b/drivers/s390/virtio/kvm_virtio.c
index 53fb975c404b..1d060fd293a3 100644
--- a/drivers/s390/virtio/kvm_virtio.c
+++ b/drivers/s390/virtio/kvm_virtio.c
@@ -255,7 +255,7 @@ static void kvm_del_vqs(struct virtio_device *vdev)
static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
struct kvm_device *kdev = to_kvmdev(vdev);
int i;
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index 1b831598df7c..bf2d1300a957 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -635,7 +635,7 @@ out:
static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
unsigned long *indicatorp = NULL;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 64eed87d34a8..c1fe0d2f90ca 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -194,6 +194,7 @@ config CHR_DEV_SCH
config SCSI_ENCLOSURE
tristate "SCSI Enclosure Support"
depends on SCSI && ENCLOSURE_SERVICES
+ depends on m || SCSI_SAS_ATTRS != m
help
Enclosures are devices sitting on or in SCSI backplanes that
manage devices. If you have a disk cage, the chances are that
@@ -474,6 +475,7 @@ config SCSI_AACRAID
source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
+source "drivers/scsi/hisi_sas/Kconfig"
source "drivers/scsi/mvsas/Kconfig"
config SCSI_MVUMI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index c14bca4a9675..862ab4efad61 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -157,6 +157,7 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o
obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas/
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 3b6e5c67e853..76eaa38ffd6e 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1318,7 +1318,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
#if (defined(CONFIG_PM))
-void aac_release_resources(struct aac_dev *aac)
+static void aac_release_resources(struct aac_dev *aac)
{
int i;
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index df2e0e5367d2..d47b527b25dd 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -624,7 +624,7 @@ struct scb {
};
TAILQ_HEAD(scb_tailq, scb);
-LIST_HEAD(scb_list, scb);
+BSD_LIST_HEAD(scb_list, scb);
struct scb_data {
/*
@@ -1069,7 +1069,7 @@ struct ahd_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ BSD_LIST_HEAD(, scb) pending_scbs;
/*
* Current register window mode information.
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index c58fa33c6592..728193a42e6e 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -65,11 +65,6 @@
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahd
-/* Name space conflict with BSD queue macros */
-#ifdef LIST_HEAD
-#undef LIST_HEAD
-#endif
-
#include "cam.h"
#include "queue.h"
#include "scsi_message.h"
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index f695774645c1..4ce4e903a759 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -916,7 +916,7 @@ struct ahc_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ BSD_LIST_HEAD(, scb) pending_scbs;
/*
* Counting lock for deferring the release of additional
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index bc4cca92ff04..54c702864103 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -82,11 +82,6 @@
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahc
-/* Name space conflict with BSD queue macros */
-#ifdef LIST_HEAD
-#undef LIST_HEAD
-#endif
-
#include "cam.h"
#include "queue.h"
#include "scsi_message.h"
diff --git a/drivers/scsi/aic7xxx/queue.h b/drivers/scsi/aic7xxx/queue.h
index 8adf8003a164..ba602981f193 100644
--- a/drivers/scsi/aic7xxx/queue.h
+++ b/drivers/scsi/aic7xxx/queue.h
@@ -246,7 +246,7 @@ struct { \
/*
* List declarations.
*/
-#define LIST_HEAD(name, type) \
+#define BSD_LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
index 912e6b755f74..101072cab70f 100644
--- a/drivers/scsi/aic94xx/aic94xx_sas.h
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -327,46 +327,9 @@ struct scb_header {
#define LUN_SIZE 8
-/* See SAS spec, task IU
- */
-struct ssp_task_iu {
- u8 lun[LUN_SIZE]; /* BE */
- u16 _r_a;
- u8 tmf;
- u8 _r_b;
- __be16 tag; /* BE */
- u8 _r_c[14];
-} __attribute__ ((packed));
-
-/* See SAS spec, command IU
- */
-struct ssp_command_iu {
- u8 lun[LUN_SIZE];
- u8 _r_a;
- u8 efb_prio_attr; /* enable first burst, task prio & attr */
-#define EFB_MASK 0x80
-#define TASK_PRIO_MASK 0x78
-#define TASK_ATTR_MASK 0x07
-
- u8 _r_b;
- u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */
- union {
- u8 cdb[16];
- struct {
- __le64 long_cdb_addr; /* bus address, LE */
- __le32 long_cdb_size; /* LE */
- u8 _r_c[3];
- u8 eol_ds; /* eol:6,6, ds:5,4 */
- } long_cdb; /* sequencer extension */
- };
-} __attribute__ ((packed));
-
-struct xfer_rdy_iu {
- __be32 requested_offset; /* BE */
- __be32 write_data_len; /* BE */
- __be32 _r_a;
-} __attribute__ ((packed));
-
+#define EFB_MASK 0x80
+#define TASK_PRIO_MASK 0x78
+#define TASK_ATTR_MASK 0x07
/* ---------- SCB tasks ---------- */
/* This is both ssp_task and long_ssp_task
@@ -511,7 +474,7 @@ struct abort_task {
u8 proto_conn_rate;
__le32 _r_a;
struct ssp_frame_hdr ssp_frame;
- struct ssp_task_iu ssp_task;
+ struct ssp_tmf_iu ssp_task;
__le16 sister_scb;
__le16 conn_handle;
u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
@@ -549,7 +512,7 @@ struct clear_nexus {
u8 _r_b[3];
u8 conn_mask;
u8 _r_c[19];
- struct ssp_task_iu ssp_task; /* LUN and TAG */
+ struct ssp_tmf_iu ssp_task; /* LUN and TAG */
__le16 _r_d;
__le16 conn_handle;
__le64 _r_e;
@@ -562,7 +525,7 @@ struct initiate_ssp_tmf {
u8 proto_conn_rate;
__le32 _r_a;
struct ssp_frame_hdr ssp_frame;
- struct ssp_task_iu ssp_task;
+ struct ssp_tmf_iu ssp_task;
__le16 sister_scb;
__le16 conn_handle;
u8 flags; /* itnl override and suspend data tx */
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index 3bcaaac0ae4b..cf99f8cf4cdd 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -52,7 +52,7 @@ struct device_attribute;
#define ARCMSR_MAX_FREECCB_NUM 320
#define ARCMSR_MAX_OUTSTANDING_CMD 255
#endif
-#define ARCMSR_DRIVER_VERSION "v1.30.00.04-20140919"
+#define ARCMSR_DRIVER_VERSION "v1.30.00.22-20151126"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -74,6 +74,9 @@ struct device_attribute;
#ifndef PCI_DEVICE_ID_ARECA_1214
#define PCI_DEVICE_ID_ARECA_1214 0x1214
#endif
+#ifndef PCI_DEVICE_ID_ARECA_1203
+ #define PCI_DEVICE_ID_ARECA_1203 0x1203
+#endif
/*
**********************************************************************************
**
@@ -245,6 +248,12 @@ struct FIRMWARE_INFO
/* window of "instruction flags" from iop to driver */
#define ARCMSR_IOP2DRV_DOORBELL 0x00020408
#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL_1203 0x00021870
+#define ARCMSR_IOP2DRV_DOORBELL_MASK_1203 0x00021874
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL_1203 0x00021878
+#define ARCMSR_DRV2IOP_DOORBELL_MASK_1203 0x0002187C
/* ARECA FLAG LANGUAGE */
/* ioctl transfer */
#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001
@@ -288,6 +297,9 @@ struct FIRMWARE_INFO
#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00
/* iop message_rwbuffer for message command */
#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
+
+#define MEM_BASE0(x) (u32 __iomem *)((unsigned long)acb->mem_base0 + x)
+#define MEM_BASE1(x) (u32 __iomem *)((unsigned long)acb->mem_base1 + x)
/*
************************************************************************
** SPEC. for Areca HBC adapter
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 333db5953607..7640498964a5 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -114,6 +114,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -157,6 +158,8 @@ static struct pci_device_id arcmsr_device_id_table[] = {
.driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202),
.driver_data = ACB_ADAPTER_TYPE_B},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203),
+ .driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
.driver_data = ACB_ADAPTER_TYPE_A},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
@@ -495,6 +498,91 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
}
}
+static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
+{
+ bool rtn = true;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
+ struct pci_dev *pdev = acb->pdev;
+
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg;
+ acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
+ dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle2 = dma_coherent_handle;
+ acb->dma_coherent2 = dma_coherent;
+ reg = (struct MessageUnit_B *)dma_coherent;
+ acb->pmuB = reg;
+ if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) {
+ reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203);
+ reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203);
+ reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203);
+ reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203);
+ } else {
+ reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK);
+ }
+ reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER);
+ reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER);
+ reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_D: {
+ struct MessageUnit_D *reg;
+
+ acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
+ dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle2 = dma_coherent_handle;
+ acb->dma_coherent2 = dma_coherent;
+ reg = (struct MessageUnit_D *)dma_coherent;
+ acb->pmuD = reg;
+ reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID);
+ reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
+ reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
+ reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET);
+ reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST);
+ reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
+ reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
+ reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0);
+ reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1);
+ reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
+ reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
+ reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL);
+ reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL);
+ reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
+ reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
+ reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
+ reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
+ reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
+ reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
+ reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
+ reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
+ reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
+ reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
+ reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER);
+ reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER);
+ reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
+ }
+ break;
+ default:
+ break;
+ }
+ return rtn;
+}
+
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
@@ -739,9 +827,12 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if(!error){
goto pci_release_regs;
}
+ error = arcmsr_alloc_io_queue(acb);
+ if (!error)
+ goto unmap_pci_region;
error = arcmsr_get_firmware_spec(acb);
if(!error){
- goto unmap_pci_region;
+ goto free_hbb_mu;
}
error = arcmsr_alloc_ccb_pool(acb);
if(error){
@@ -2622,9 +2713,6 @@ static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb)
static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- struct pci_dev *pdev = acb->pdev;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
char *acb_device_map = acb->device_map;
@@ -2636,30 +2724,16 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
/*firm_version,21,84-99*/
int count;
- acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
- dma_coherent = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
- &dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent){
- printk(KERN_NOTICE
- "arcmsr%d: dma_alloc_coherent got error for hbb mu\n",
- acb->host->host_no);
- return false;
- }
- acb->dma_coherent_handle2 = dma_coherent_handle;
- acb->dma_coherent2 = dma_coherent;
- reg = (struct MessageUnit_B *)dma_coherent;
- acb->pmuB = reg;
- reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
- reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
- reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
- reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
- reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
- reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
- reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]); /*firm_model,15,60-67*/
iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]); /*firm_version,17,68-83*/
iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]); /*firm_version,21,84-99*/
+ arcmsr_wait_firmware_ready(acb);
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+ if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+ printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no);
+ return false;
+ }
writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
@@ -2694,15 +2768,15 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
acb->firm_model,
acb->firm_version);
- acb->signature = readl(&reg->message_rwbuffer[1]);
+ acb->signature = readl(&reg->message_rwbuffer[0]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+ acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
/*firm_ide_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
/*firm_ide_channels,4,16-19*/
@@ -2777,70 +2851,8 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
char __iomem *iop_firm_version;
char __iomem *iop_device_map;
u32 count;
- struct MessageUnit_D *reg;
- void *dma_coherent2;
- dma_addr_t dma_coherent_handle2;
- struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit_D *reg = acb->pmuD;
- acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
- dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
- &dma_coherent_handle2, GFP_KERNEL);
- if (!dma_coherent2) {
- pr_notice("DMA allocation failed...\n");
- return false;
- }
- memset(dma_coherent2, 0, acb->roundup_ccbsize);
- acb->dma_coherent_handle2 = dma_coherent_handle2;
- acb->dma_coherent2 = dma_coherent2;
- reg = (struct MessageUnit_D *)dma_coherent2;
- acb->pmuD = reg;
- reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID;
- reg->cpu_mem_config = acb->mem_base0 +
- ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION;
- reg->i2o_host_interrupt_mask = acb->mem_base0 +
- ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK;
- reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET;
- reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST;
- reg->host_int_status = acb->mem_base0 +
- ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS;
- reg->pcief0_int_enable = acb->mem_base0 +
- ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE;
- reg->inbound_msgaddr0 = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_MESSAGE0;
- reg->inbound_msgaddr1 = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_MESSAGE1;
- reg->outbound_msgaddr0 = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_MESSAGE0;
- reg->outbound_msgaddr1 = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_MESSAGE1;
- reg->inbound_doorbell = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_DOORBELL;
- reg->outbound_doorbell = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_DOORBELL;
- reg->outbound_doorbell_enable = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE;
- reg->inboundlist_base_low = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW;
- reg->inboundlist_base_high = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH;
- reg->inboundlist_write_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER;
- reg->outboundlist_base_low = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW;
- reg->outboundlist_base_high = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH;
- reg->outboundlist_copy_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER;
- reg->outboundlist_read_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER;
- reg->outboundlist_interrupt_cause = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE;
- reg->outboundlist_interrupt_enable = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE;
- reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER;
- reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER;
- reg->msgcode_rwbuffer = acb->mem_base0 +
- ARCMSR_ARC1214_MESSAGE_RWBUFFER;
iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
@@ -2855,8 +2867,6 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
pr_notice("arcmsr%d: wait get adapter firmware "
"miscellaneous data timeout\n", acb->host->host_no);
- dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
- acb->dma_coherent2, acb->dma_coherent_handle2);
return false;
}
count = 8;
@@ -2880,15 +2890,15 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
iop_device_map++;
count--;
}
- acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+ acb->signature = readl(&reg->msgcode_rwbuffer[0]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+ acb->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+ acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+ acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+ acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
/*firm_hd_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
@@ -3998,6 +4008,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1160:
case PCI_DEVICE_ID_ARECA_1170:
case PCI_DEVICE_ID_ARECA_1201:
+ case PCI_DEVICE_ID_ARECA_1203:
case PCI_DEVICE_ID_ARECA_1220:
case PCI_DEVICE_ID_ARECA_1230:
case PCI_DEVICE_ID_ARECA_1260:
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 05301bc752ee..8b52a9dbb9cf 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -41,77 +41,128 @@
static struct scsi_host_template atp870u_template;
static void send_s870(struct atp_unit *dev,unsigned char c);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
-static void tscam_885(void);
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode);
+
+static inline void atp_writeb_base(struct atp_unit *atp, u8 reg, u8 val)
+{
+ outb(val, atp->baseport + reg);
+}
+
+static inline void atp_writew_base(struct atp_unit *atp, u8 reg, u16 val)
+{
+ outw(val, atp->baseport + reg);
+}
+
+static inline void atp_writeb_io(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+ outb(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writew_io(struct atp_unit *atp, u8 channel, u8 reg, u16 val)
+{
+ outw(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writeb_pci(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+ outb(val, atp->pciport[channel] + reg);
+}
+
+static inline void atp_writel_pci(struct atp_unit *atp, u8 channel, u8 reg, u32 val)
+{
+ outl(val, atp->pciport[channel] + reg);
+}
+
+static inline u8 atp_readb_base(struct atp_unit *atp, u8 reg)
+{
+ return inb(atp->baseport + reg);
+}
+
+static inline u16 atp_readw_base(struct atp_unit *atp, u8 reg)
+{
+ return inw(atp->baseport + reg);
+}
+
+static inline u32 atp_readl_base(struct atp_unit *atp, u8 reg)
+{
+ return inl(atp->baseport + reg);
+}
+
+static inline u8 atp_readb_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inb(atp->ioport[channel] + reg);
+}
+
+static inline u16 atp_readw_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inw(atp->ioport[channel] + reg);
+}
+
+static inline u8 atp_readb_pci(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inb(atp->pciport[channel] + reg);
+}
+
+static inline bool is880(struct atp_unit *atp)
+{
+ return atp->pdev->device == ATP880_DEVID1 ||
+ atp->pdev->device == ATP880_DEVID2;
+}
+
+static inline bool is885(struct atp_unit *atp)
+{
+ return atp->pdev->device == ATP885_DEVID;
+}
static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
- unsigned short int tmpcip, id;
+ unsigned short int id;
unsigned char i, j, c, target_id, lun,cmdp;
unsigned char *prd;
struct scsi_cmnd *workreq;
- unsigned int workport, tmport, tmport1;
unsigned long adrcnt, k;
#ifdef ED_DBGP
unsigned long l;
#endif
- int errstus;
struct Scsi_Host *host = dev_id;
struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
for (c = 0; c < 2; c++) {
- tmport = dev->ioport[c] + 0x1f;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x80) != 0)
- {
- goto ch_sel;
- }
+ break;
dev->in_int[c] = 0;
}
- return IRQ_NONE;
-ch_sel:
+ if ((j & 0x80) == 0)
+ return IRQ_NONE;
#ifdef ED_DBGP
printk("atp870u_intr_handle enter\n");
#endif
dev->in_int[c] = 1;
- cmdp = inb(dev->ioport[c] + 0x10);
- workport = dev->ioport[c];
+ cmdp = atp_readb_io(dev, c, 0x10);
if (dev->working[c] != 0) {
- if (dev->dev_id == ATP885_DEVID) {
- tmport1 = workport + 0x16;
- if ((inb(tmport1) & 0x80) == 0)
- outb((inb(tmport1) | 0x80), tmport1);
+ if (is885(dev)) {
+ if ((atp_readb_io(dev, c, 0x16) & 0x80) == 0)
+ atp_writeb_io(dev, c, 0x16, (atp_readb_io(dev, c, 0x16) | 0x80));
}
- tmpcip = dev->pciport[c];
- if ((inb(tmpcip) & 0x08) != 0)
+ if ((atp_readb_pci(dev, c, 0x00) & 0x08) != 0)
{
- tmpcip += 0x2;
for (k=0; k < 1000; k++) {
- if ((inb(tmpcip) & 0x08) == 0) {
- goto stop_dma;
- }
- if ((inb(tmpcip) & 0x01) == 0) {
- goto stop_dma;
- }
+ if ((atp_readb_pci(dev, c, 2) & 0x08) == 0)
+ break;
+ if ((atp_readb_pci(dev, c, 2) & 0x01) == 0)
+ break;
}
}
-stop_dma:
- tmpcip = dev->pciport[c];
- outb(0x00, tmpcip);
- tmport -= 0x08;
+ atp_writeb_pci(dev, c, 0, 0x00);
- i = inb(tmport);
+ i = atp_readb_io(dev, c, 0x17);
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip += 2;
- outb(0x06, tmpcip);
- tmpcip -= 2;
- }
+ if (is885(dev))
+ atp_writeb_pci(dev, c, 2, 0x06);
- tmport -= 0x02;
- target_id = inb(tmport);
- tmport += 0x02;
+ target_id = atp_readb_io(dev, c, 0x15);
/*
* Remap wide devices onto id numbers
@@ -129,7 +180,7 @@ stop_dma:
}
dev->last_cmd[c] |= 0x40;
}
- if (dev->dev_id == ATP885_DEVID)
+ if (is885(dev))
dev->r1f[c][target_id] |= j;
#ifdef ED_DBGP
printk("atp870u_intr_handle status = %x\n",i);
@@ -138,12 +189,11 @@ stop_dma:
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- if (dev->dev_id == ATP885_DEVID) {
- tmport -= 0x05;
+ if (is885(dev)) {
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
if (dev->id[c][target_id].last_len != adrcnt)
{
k = dev->id[c][target_id].last_len;
@@ -152,7 +202,7 @@ stop_dma:
dev->id[c][target_id].last_len = adrcnt;
}
#ifdef ED_DBGP
- printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
+ printk("dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
#endif
}
@@ -160,11 +210,9 @@ stop_dma:
* Flip wide
*/
if (dev->wide_id[c] != 0) {
- tmport = workport + 0x1b;
- outb(0x01, tmport);
- while ((inb(tmport) & 0x01) != 0x01) {
- outb(0x01, tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
}
/*
* Issue more commands
@@ -185,37 +233,34 @@ stop_dma:
#ifdef ED_DBGP
printk("Status 0x85 return\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x40) {
dev->last_cmd[c] |= 0x40;
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x21) {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- tmport -= 0x05;
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
k = dev->id[c][target_id].last_len;
k -= adrcnt;
dev->id[c][target_id].tran_len = k;
dev->id[c][target_id].last_len = adrcnt;
- tmport -= 0x04;
- outb(0x41, tmport);
- tmport += 0x08;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
- if (dev->dev_id == ATP885_DEVID) {
+ if (is885(dev)) {
if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
if ((i == 0x4c) || (i == 0x8c))
i=0x48;
@@ -229,11 +274,9 @@ stop_dma:
printk(KERN_DEBUG "Device reselect\n");
#endif
lun = 0;
- tmport -= 0x07;
- if (cmdp == 0x44 || i==0x80) {
- tmport += 0x0d;
- lun = inb(tmport) & 0x07;
- } else {
+ if (cmdp == 0x44 || i == 0x80)
+ lun = atp_readb_io(dev, c, 0x1d) & 0x07;
+ else {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
@@ -241,49 +284,41 @@ stop_dma:
#ifdef ED_DBGP
printk("cmdp = 0x41\n");
#endif
- tmport += 0x02;
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
k = dev->id[c][target_id].last_len;
k -= adrcnt;
dev->id[c][target_id].tran_len = k;
dev->id[c][target_id].last_len = adrcnt;
- tmport += 0x04;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
} else {
#ifdef ED_DBGP
printk("cmdp != 0x41\n");
#endif
- outb(0x46, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x46);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x02;
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x12, 0x00);
+ atp_writeb_io(dev, c, 0x13, 0x00);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
}
if (dev->last_cmd[c] != 0xff) {
dev->last_cmd[c] |= 0x40;
}
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) & 0xfe;
- outb(j, dev->baseport + 0x29);
- tmport = workport + 0x16;
- } else {
- tmport = workport + 0x10;
- outb(0x45, tmport);
- tmport += 0x06;
- }
-
- target_id = inb(tmport);
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) & 0xfe;
+ atp_writeb_base(dev, 0x29, j);
+ } else
+ atp_writeb_io(dev, c, 0x10, 0x45);
+
+ target_id = atp_readb_io(dev, c, 0x16);
/*
* Remap wide identifiers
*/
@@ -292,10 +327,8 @@ stop_dma:
} else {
target_id &= 0x07;
}
- if (dev->dev_id == ATP885_DEVID) {
- tmport = workport + 0x10;
- outb(0x45, tmport);
- }
+ if (is885(dev))
+ atp_writeb_io(dev, c, 0x10, 0x45);
workreq = dev->id[c][target_id].curr_req;
#ifdef ED_DBGP
scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -304,18 +337,16 @@ stop_dma:
printk("\n");
#endif
- tmport = workport + 0x0f;
- outb(lun, tmport);
- tmport += 0x02;
- outb(dev->id[c][target_id].devsp, tmport++);
+ atp_writeb_io(dev, c, 0x0f, lun);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
adrcnt = dev->id[c][target_id].tran_len;
k = dev->id[c][target_id].last_len;
- outb(((unsigned char *) &k)[2], tmport++);
- outb(((unsigned char *) &k)[1], tmport++);
- outb(((unsigned char *) &k)[0], tmport++);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) &k)[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) &k)[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) &k)[0]);
#ifdef ED_DBGP
- printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));
+ printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, atp_readb_io(dev, c, 0x14), atp_readb_io(dev, c, 0x13), atp_readb_io(dev, c, 0x12));
#endif
/* Remap wide */
j = target_id;
@@ -324,35 +355,28 @@ stop_dma:
}
/* Add direction */
j |= dev->id[c][target_id].dirct;
- outb(j, tmport++);
- outb(0x80,tmport);
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x16, 0x80);
/* enable 32 bit fifo transfer */
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip = dev->pciport[c] + 1;
- i=inb(tmpcip) & 0xf3;
+ if (is885(dev)) {
+ i = atp_readb_pci(dev, c, 1) & 0xf3;
//j=workreq->cmnd[0];
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
i |= 0x0c;
}
- outb(i,tmpcip);
- } else if ((dev->dev_id == ATP880_DEVID1) ||
- (dev->dev_id == ATP880_DEVID2) ) {
- tmport = workport - 0x05;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0x3f), tmport);
- }
+ atp_writeb_pci(dev, c, 1, i);
+ } else if (is880(dev)) {
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+ else
+ atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
} else {
- tmport = workport + 0x3a;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0xf3), tmport);
- }
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+ else
+ atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
}
- tmport = workport + 0x1b;
j = 0;
id = 1;
id = id << target_id;
@@ -362,18 +386,16 @@ stop_dma:
if ((id & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- while ((inb(tmport) & 0x01) != j) {
- outb(j,tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, j);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j)
+ atp_writeb_io(dev, c, 0x1b, j);
if (dev->id[c][target_id].last_len == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("dev->id[c][target_id].last_len = 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
#ifdef ED_DBGP
printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
@@ -401,39 +423,33 @@ stop_dma:
}
}
}
- tmpcip = dev->pciport[c] + 0x04;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
+ atp_writel_pci(dev, c, 0x04, dev->id[c][target_id].prdaddr);
#ifdef ED_DBGP
printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
#endif
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip -= 0x04;
- } else {
- tmpcip -= 0x02;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip -= 0x02;
+ if (!is885(dev)) {
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
}
- tmport = workport + 0x18;
/*
* Check transfer direction
*/
if (dev->id[c][target_id].dirct != 0) {
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("status 0x80 return dirct != 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("status 0x80 return dirct = 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
/*
@@ -442,31 +458,22 @@ stop_dma:
workreq = dev->id[c][target_id].curr_req;
- if (i == 0x42) {
- if ((dev->last_cmd[c] & 0xf0) != 0x40)
- {
- dev->last_cmd[c] = 0xff;
- }
- errstus = 0x02;
- workreq->result = errstus;
- goto go_42;
- }
- if (i == 0x16) {
+ if (i == 0x42 || i == 0x16) {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- errstus = 0;
- tmport -= 0x08;
- errstus = inb(tmport);
- if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
- printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
- errstus = 0x02;
- }
- workreq->result = errstus;
-go_42:
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) | 0x01;
- outb(j, dev->baseport + 0x29);
+ if (i == 0x16) {
+ workreq->result = atp_readb_io(dev, c, 0x0f);
+ if (((dev->r1f[c][target_id] & 0x10) != 0) && is885(dev)) {
+ printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
+ workreq->result = 0x02;
+ }
+ } else
+ workreq->result = 0x02;
+
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) | 0x01;
+ atp_writeb_base(dev, 0x29, j);
}
/*
* Complete the command
@@ -488,11 +495,9 @@ go_42:
* Take it back wide
*/
if (dev->wide_id[c] != 0) {
- tmport = workport + 0x1b;
- outb(0x01, tmport);
- while ((inb(tmport) & 0x01) != 0x01) {
- outb(0x01, tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
}
/*
* If there is stuff to send and nothing going then send it
@@ -507,7 +512,7 @@ go_42:
}
spin_unlock_irqrestore(dev->host->host_lock, flags);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
@@ -517,84 +522,54 @@ go_42:
}
i &= 0x0f;
if (i == 0x09) {
- tmpcip += 4;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip = tmpcip - 2;
- tmport = workport + 0x10;
- outb(0x41, tmport);
- if (dev->dev_id == ATP885_DEVID) {
- tmport += 2;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ if (is885(dev)) {
k = dev->id[c][target_id].last_len;
- outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[0]), tmport);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x04;
} else {
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x08;
}
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x08) {
- tmpcip += 4;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip = tmpcip - 2;
- tmport = workport + 0x10;
- outb(0x41, tmport);
- if (dev->dev_id == ATP885_DEVID) {
- tmport += 2;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ if (is885(dev)) {
k = dev->id[c][target_id].last_len;
- outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++);
- } else {
- tmport += 5;
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
}
- outb((unsigned char) (inb(tmport) | 0x20), tmport);
+ atp_writeb_io(dev, c, 0x15, atp_readb_io(dev, c, 0x15) | 0x20);
dev->id[c][target_id].dirct = 0x20;
- tmport += 0x03;
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
dev->in_int[c] = 0;
- goto handled;
- }
- tmport -= 0x07;
- if (i == 0x0a) {
- outb(0x30, tmport);
- } else {
- outb(0x46, tmport);
+ return IRQ_HANDLED;
}
+ if (i == 0x0a)
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ else
+ atp_writeb_io(dev, c, 0x10, 0x46);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x02;
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- dev->in_int[c] = 0;
- goto handled;
- } else {
-// tmport = workport + 0x17;
-// inb(tmport);
-// dev->working[c] = 0;
- dev->in_int[c] = 0;
- goto handled;
+ atp_writeb_io(dev, c, 0x12, 0x00);
+ atp_writeb_io(dev, c, 0x13, 0x00);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
}
-
-handled:
-#ifdef ED_DBGP
- printk("atp870u_intr_handle exit\n");
-#endif
+ dev->in_int[c] = 0;
+
return IRQ_HANDLED;
}
/**
@@ -608,7 +583,7 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
void (*done) (struct scsi_cmnd *))
{
unsigned char c;
- unsigned int tmport,m;
+ unsigned int m;
struct atp_unit *dev;
struct Scsi_Host *host;
@@ -677,11 +652,10 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
return 0;
}
dev->quereq[c][dev->quend[c]] = req_p;
- tmport = dev->ioport[c] + 0x1c;
#ifdef ED_DBGP
- printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);
+ printk("dev->ioport[c] = %x atp_readb_io(dev, c, 0x1c) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],atp_readb_io(dev, c, 0x1c),c,dev->in_int[c],c,dev->in_snd[c]);
#endif
- if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
+ if ((atp_readb_io(dev, c, 0x1c) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
#ifdef ED_DBGP
printk("Call sent_s870(atp870u_queuecommand)\n");
#endif
@@ -706,14 +680,12 @@ static DEF_SCSI_QCMD(atp870u_queuecommand)
*/
static void send_s870(struct atp_unit *dev,unsigned char c)
{
- unsigned int tmport;
- struct scsi_cmnd *workreq;
+ struct scsi_cmnd *workreq = NULL;
unsigned int i;//,k;
unsigned char j, target_id;
unsigned char *prd;
- unsigned short int tmpcip, w;
+ unsigned short int w;
unsigned long l, bttl = 0;
- unsigned int workport;
unsigned long sg_count;
if (dev->in_snd[c] != 0) {
@@ -729,53 +701,42 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
dev->last_cmd[c] &= 0x0f;
workreq = dev->id[c][dev->last_cmd[c]].curr_req;
- if (workreq != NULL) { /* check NULL pointer */
- goto cmd_subp;
- }
- dev->last_cmd[c] = 0xff;
- if (dev->quhd[c] == dev->quend[c]) {
- dev->in_snd[c] = 0;
- return ;
+ if (!workreq) {
+ dev->last_cmd[c] = 0xff;
+ if (dev->quhd[c] == dev->quend[c]) {
+ dev->in_snd[c] = 0;
+ return;
+ }
}
}
- if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
- dev->in_snd[c] = 0;
- return ;
- }
- dev->working[c]++;
- j = dev->quhd[c];
- dev->quhd[c]++;
- if (dev->quhd[c] >= qcnt) {
- dev->quhd[c] = 0;
- }
- workreq = dev->quereq[c][dev->quhd[c]];
- if (dev->id[c][scmd_id(workreq)].curr_req == NULL) {
+ if (!workreq) {
+ if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
+ dev->in_snd[c] = 0;
+ return;
+ }
+ dev->working[c]++;
+ j = dev->quhd[c];
+ dev->quhd[c]++;
+ if (dev->quhd[c] >= qcnt)
+ dev->quhd[c] = 0;
+ workreq = dev->quereq[c][dev->quhd[c]];
+ if (dev->id[c][scmd_id(workreq)].curr_req != NULL) {
+ dev->quhd[c] = j;
+ dev->working[c]--;
+ dev->in_snd[c] = 0;
+ return;
+ }
dev->id[c][scmd_id(workreq)].curr_req = workreq;
dev->last_cmd[c] = scmd_id(workreq);
- goto cmd_subp;
- }
- dev->quhd[c] = j;
- dev->working[c]--;
- dev->in_snd[c] = 0;
- return;
-cmd_subp:
- workport = dev->ioport[c];
- tmport = workport + 0x1f;
- if ((inb(tmport) & 0xb0) != 0) {
- goto abortsnd;
- }
- tmport = workport + 0x1c;
- if (inb(tmport) == 0) {
- goto oktosend;
}
-abortsnd:
+ if ((atp_readb_io(dev, c, 0x1f) & 0xb0) != 0 || atp_readb_io(dev, c, 0x1c) != 0) {
#ifdef ED_DBGP
- printk("Abort to Send\n");
+ printk("Abort to Send\n");
#endif
- dev->last_cmd[c] |= 0x40;
- dev->in_snd[c] = 0;
- return;
-oktosend:
+ dev->last_cmd[c] |= 0x40;
+ dev->in_snd[c] = 0;
+ return;
+ }
#ifdef ED_DBGP
printk("OK to Send\n");
scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -786,9 +747,9 @@ oktosend:
#endif
l = scsi_bufflen(workreq);
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) & 0xfe;
- outb(j, dev->baseport + 0x29);
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) & 0xfe;
+ atp_writeb_base(dev, 0x29, j);
dev->r1f[c][scmd_id(workreq)] = 0;
}
@@ -800,7 +761,6 @@ oktosend:
l = 0;
}
- tmport = workport + 0x1b;
j = 0;
target_id = scmd_id(workreq);
@@ -812,9 +772,9 @@ oktosend:
if ((w & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- while ((inb(tmport) & 0x01) != j) {
- outb(j,tmport);
+ atp_writeb_io(dev, c, 0x1b, j);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j) {
+ atp_writeb_pci(dev, c, 0x1b, j);
#ifdef ED_DBGP
printk("send_s870 while loop 1\n");
#endif
@@ -823,24 +783,19 @@ oktosend:
* Write the command
*/
- tmport = workport;
- outb(workreq->cmd_len, tmport++);
- outb(0x2c, tmport++);
- if (dev->dev_id == ATP885_DEVID) {
- outb(0x7f, tmport++);
- } else {
- outb(0xcf, tmport++);
- }
- for (i = 0; i < workreq->cmd_len; i++) {
- outb(workreq->cmnd[i], tmport++);
- }
- tmport = workport + 0x0f;
- outb(workreq->device->lun, tmport);
- tmport += 0x02;
+ atp_writeb_io(dev, c, 0x00, workreq->cmd_len);
+ atp_writeb_io(dev, c, 0x01, 0x2c);
+ if (is885(dev))
+ atp_writeb_io(dev, c, 0x02, 0x7f);
+ else
+ atp_writeb_io(dev, c, 0x02, 0xcf);
+ for (i = 0; i < workreq->cmd_len; i++)
+ atp_writeb_io(dev, c, 0x03 + i, workreq->cmnd[i]);
+ atp_writeb_io(dev, c, 0x0f, workreq->device->lun);
/*
* Write the target
*/
- outb(dev->id[c][target_id].devsp, tmport++);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
#ifdef ED_DBGP
printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
#endif
@@ -849,9 +804,9 @@ oktosend:
/*
* Write transfer size
*/
- outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&l))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&l))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&l))[0]);
j = target_id;
dev->id[c][j].last_len = l;
dev->id[c][j].tran_len = 0;
@@ -867,29 +822,24 @@ oktosend:
/*
* Check transfer direction
*/
- if (workreq->sc_data_direction == DMA_TO_DEVICE) {
- outb((unsigned char) (j | 0x20), tmport++);
- } else {
- outb(j, tmport++);
- }
- outb((unsigned char) (inb(tmport) | 0x80), tmport);
- outb(0x80, tmport);
- tmport = workport + 0x1c;
+ if (workreq->sc_data_direction == DMA_TO_DEVICE)
+ atp_writeb_io(dev, c, 0x15, j | 0x20);
+ else
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x16, atp_readb_io(dev, c, 0x16) | 0x80);
+ atp_writeb_io(dev, c, 0x16, 0x80);
dev->id[c][target_id].dirct = 0;
if (l == 0) {
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
#ifdef ED_DBGP
printk("change SCSI_CMD_REG 0x08\n");
#endif
- outb(0x08, tmport);
- } else {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ } else
dev->last_cmd[c] |= 0x40;
- }
dev->in_snd[c] = 0;
return;
}
- tmpcip = dev->pciport[c];
prd = dev->id[c][target_id].prd_table;
dev->id[c][target_id].prd_pos = prd;
@@ -926,50 +876,37 @@ oktosend:
printk("2. bttl %x, l %x\n",bttl, l);
#endif
}
- tmpcip += 4;
#ifdef ED_DBGP
- printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
+ printk("send_s870: prdaddr_2 0x%8x target_id %d\n", dev->id[c][target_id].prdaddr,target_id);
#endif
dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip--;
- j=inb(tmpcip) & 0xf3;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ if (is885(dev)) {
+ j = atp_readb_pci(dev, c, 1) & 0xf3;
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
(workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
j |= 0x0c;
}
- outb(j,tmpcip);
- tmpcip--;
- } else if ((dev->dev_id == ATP880_DEVID1) ||
- (dev->dev_id == ATP880_DEVID2)) {
- tmpcip =tmpcip -2;
- tmport = workport - 0x05;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0x3f), tmport);
- }
+ atp_writeb_pci(dev, c, 1, j);
+ } else if (is880(dev)) {
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+ else
+ atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
} else {
- tmpcip =tmpcip -2;
- tmport = workport + 0x3a;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((inb(tmport) & 0xf3) | 0x08, tmport);
- } else {
- outb(inb(tmport) & 0xf3, tmport);
- }
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+ else
+ atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
}
- tmport = workport + 0x1c;
if(workreq->sc_data_direction == DMA_TO_DEVICE) {
dev->id[c][target_id].dirct = 0x20;
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
#ifdef ED_DBGP
printk( "start DMA(to target)\n");
#endif
@@ -979,10 +916,9 @@ oktosend:
dev->in_snd[c] = 0;
return;
}
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
#ifdef ED_DBGP
printk( "start DMA(to host)\n");
#endif
@@ -996,49 +932,40 @@ oktosend:
static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
{
- unsigned int tmport;
unsigned short int i, k;
unsigned char j;
- tmport = dev->ioport[0] + 0x1c;
- outw(*val, tmport);
-FUN_D7:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- k = inw(tmport);
+ k = atp_readw_io(dev, 0, 0x1c);
j = (unsigned char) (k >> 8);
- if ((k & 0x8000) != 0) { /* DB7 all release? */
- goto FUN_D7;
- }
+ if ((k & 0x8000) != 0) /* DB7 all release? */
+ i = 0;
}
*val |= 0x4000; /* assert DB6 */
- outw(*val, tmport);
+ atp_writew_io(dev, 0, 0x1c, *val);
*val &= 0xdfff; /* assert DB5 */
- outw(*val, tmport);
-FUN_D5:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */
- goto FUN_D5;
- }
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) != 0) /* DB5 all release? */
+ i = 0;
}
*val |= 0x8000; /* no DB4-0, assert DB7 */
*val &= 0xe0ff;
- outw(*val, tmport);
+ atp_writew_io(dev, 0, 0x1c, *val);
*val &= 0xbfff; /* release DB6 */
- outw(*val, tmport);
-FUN_D6:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */
- goto FUN_D6;
- }
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x4000) != 0) /* DB6 all release? */
+ i = 0;
}
return j;
}
-static void tscam(struct Scsi_Host *host)
+static void tscam(struct Scsi_Host *host, bool wide_chip, u8 scam_on)
{
- unsigned int tmport;
unsigned char i, j, k;
unsigned long n;
unsigned short int m, assignid_map, val;
@@ -1055,31 +982,28 @@ static void tscam(struct Scsi_Host *host)
}
*/
- tmport = dev->ioport[0] + 1;
- outb(0x08, tmport++);
- outb(0x7f, tmport);
- tmport = dev->ioport[0] + 0x11;
- outb(0x20, tmport);
+ atp_writeb_io(dev, 0, 1, 0x08);
+ atp_writeb_io(dev, 0, 2, 0x7f);
+ atp_writeb_io(dev, 0, 0x11, 0x20);
- if ((dev->scam_on & 0x40) == 0) {
+ if ((scam_on & 0x40) == 0) {
return;
}
m = 1;
m <<= dev->host_id[0];
j = 16;
- if (dev->chip_ver < 4) {
+ if (!wide_chip) {
m |= 0xff00;
j = 8;
}
assignid_map = m;
- tmport = dev->ioport[0] + 0x02;
- outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
+ atp_writeb_io(dev, 0, 0x02, 0x02); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+ atp_writeb_io(dev, 0, 0x03, 0);
+ atp_writeb_io(dev, 0, 0x04, 0);
+ atp_writeb_io(dev, 0, 0x05, 0);
+ atp_writeb_io(dev, 0, 0x06, 0);
+ atp_writeb_io(dev, 0, 0x07, 0);
+ atp_writeb_io(dev, 0, 0x08, 0);
for (i = 0; i < j; i++) {
m = 1;
@@ -1087,92 +1011,73 @@ static void tscam(struct Scsi_Host *host)
if ((m & assignid_map) != 0) {
continue;
}
- tmport = dev->ioport[0] + 0x0f;
- outb(0, tmport++);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
+ atp_writeb_io(dev, 0, 0x0f, 0);
+ atp_writeb_io(dev, 0, 0x12, 0);
+ atp_writeb_io(dev, 0, 0x13, 0);
+ atp_writeb_io(dev, 0, 0x14, 0);
if (i > 7) {
k = (i & 0x07) | 0x40;
} else {
k = i;
}
- outb(k, tmport++);
- tmport = dev->ioport[0] + 0x1b;
- if (dev->chip_ver == 4) {
- outb(0x01, tmport);
- } else {
- outb(0x00, tmport);
- }
-wait_rdyok:
- tmport = dev->ioport[0] + 0x18;
- outb(0x09, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
- tmport -= 0x08;
- k = inb(tmport);
- if (k != 0x16) {
- if ((k == 0x85) || (k == 0x42)) {
- continue;
- }
- tmport = dev->ioport[0] + 0x10;
- outb(0x41, tmport);
- goto wait_rdyok;
- }
+ atp_writeb_io(dev, 0, 0x15, k);
+ if (wide_chip)
+ atp_writeb_io(dev, 0, 0x1b, 0x01);
+ else
+ atp_writeb_io(dev, 0, 0x1b, 0x00);
+ do {
+ atp_writeb_io(dev, 0, 0x18, 0x09);
+
+ while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0x00)
+ cpu_relax();
+ k = atp_readb_io(dev, 0, 0x17);
+ if ((k == 0x85) || (k == 0x42))
+ break;
+ if (k != 0x16)
+ atp_writeb_io(dev, 0, 0x10, 0x41);
+ } while (k != 0x16);
+ if ((k == 0x85) || (k == 0x42))
+ continue;
assignid_map |= m;
}
- tmport = dev->ioport[0] + 0x02;
- outb(0x7f, tmport);
- tmport = dev->ioport[0] + 0x1b;
- outb(0x02, tmport);
+ atp_writeb_io(dev, 0, 0x02, 0x7f);
+ atp_writeb_io(dev, 0, 0x1b, 0x02);
- outb(0, 0x80);
+ udelay(2);
val = 0x0080; /* bsy */
- tmport = dev->ioport[0] + 0x1c;
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
val |= 0x0040; /* sel */
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
val |= 0x0004; /* msg */
- outw(val, tmport);
- inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2); /* 2 deskew delay(45ns*2=90ns) */
val &= 0x007f; /* no bsy */
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
mdelay(128);
val &= 0x00fb; /* after 1ms no msg */
- outw(val, tmport);
-wait_nomsg:
- if ((inb(tmport) & 0x04) != 0) {
- goto wait_nomsg;
- }
- outb(1, 0x80);
+ atp_writew_io(dev, 0, 0x1c, val);
+ while ((atp_readb_io(dev, 0, 0x1c) & 0x04) != 0)
+ ;
+ udelay(2);
udelay(100);
- for (n = 0; n < 0x30000; n++) {
- if ((inb(tmport) & 0x80) != 0) { /* bsy ? */
- goto wait_io;
- }
- }
- goto TCM_SYNC;
-wait_io:
- for (n = 0; n < 0x30000; n++) {
- if ((inb(tmport) & 0x81) == 0x0081) {
- goto wait_io1;
- }
- }
- goto TCM_SYNC;
-wait_io1:
- inb(0x80);
- val |= 0x8003; /* io,cd,db7 */
- outw(val, tmport);
- inb(0x80);
- val &= 0x00bf; /* no sel */
- outw(val, tmport);
- outb(2, 0x80);
-TCM_SYNC:
+ for (n = 0; n < 0x30000; n++)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x80) != 0) /* bsy ? */
+ break;
+ if (n < 0x30000)
+ for (n = 0; n < 0x30000; n++)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x81) == 0x0081) {
+ udelay(2);
+ val |= 0x8003; /* io,cd,db7 */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2);
+ val &= 0x00bf; /* no sel */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2);
+ break;
+ }
+ while (1) {
/*
* The funny division into multiple delays is to accomodate
* arches like ARM where udelay() multiplies its argument by
@@ -1183,55 +1088,48 @@ TCM_SYNC:
*/
mdelay(2);
udelay(48);
- if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */
- outw(0, tmport--);
- outb(0, tmport);
- tmport = dev->ioport[0] + 0x15;
- outb(0, tmport);
- tmport += 0x03;
- outb(0x09, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x80) == 0x00) { /* bsy ? */
+ atp_writew_io(dev, 0, 0x1c, 0);
+ atp_writeb_io(dev, 0, 0x1b, 0);
+ atp_writeb_io(dev, 0, 0x15, 0);
+ atp_writeb_io(dev, 0, 0x18, 0x09);
+ while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0)
cpu_relax();
- tmport -= 0x08;
- inb(tmport);
+ atp_readb_io(dev, 0, 0x17);
return;
}
val &= 0x00ff; /* synchronization */
val |= 0x3f00;
fun_scam(dev, &val);
- outb(3, 0x80);
+ udelay(2);
val &= 0x00ff; /* isolation */
val |= 0x2000;
fun_scam(dev, &val);
- outb(4, 0x80);
+ udelay(2);
i = 8;
j = 0;
-TCM_ID:
- if ((inw(tmport) & 0x2000) == 0) {
- goto TCM_ID;
- }
- outb(5, 0x80);
- val &= 0x00ff; /* get ID_STRING */
- val |= 0x2000;
- k = fun_scam(dev, &val);
- if ((k & 0x03) == 0) {
- goto TCM_5;
- }
- mbuf[j] <<= 0x01;
- mbuf[j] &= 0xfe;
- if ((k & 0x02) != 0) {
- mbuf[j] |= 0x01;
- }
- i--;
- if (i > 0) {
- goto TCM_ID;
+
+ while (1) {
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) == 0)
+ continue;
+ udelay(2);
+ val &= 0x00ff; /* get ID_STRING */
+ val |= 0x2000;
+ k = fun_scam(dev, &val);
+ if ((k & 0x03) == 0)
+ break;
+ mbuf[j] <<= 0x01;
+ mbuf[j] &= 0xfe;
+ if ((k & 0x02) != 0)
+ mbuf[j] |= 0x01;
+ i--;
+ if (i > 0)
+ continue;
+ j++;
+ i = 8;
}
- j++;
- i = 8;
- goto TCM_ID;
-TCM_5: /* isolation complete.. */
+ /* isolation complete.. */
/* mbuf[32]=0;
printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
i = 15;
@@ -1239,33 +1137,33 @@ TCM_5: /* isolation complete.. */
if ((j & 0x20) != 0) { /* bit5=1:ID up to 7 */
i = 7;
}
- if ((j & 0x06) == 0) { /* IDvalid? */
- goto G2Q5;
- }
- k = mbuf[1];
-small_id:
- m = 1;
- m <<= k;
- if ((m & assignid_map) == 0) {
- goto G2Q_QUIN;
- }
- if (k > 0) {
- k--;
- goto small_id;
- }
-G2Q5: /* srch from max acceptable ID# */
- k = i; /* max acceptable ID# */
-G2Q_LP:
- m = 1;
- m <<= k;
- if ((m & assignid_map) == 0) {
- goto G2Q_QUIN;
+ if ((j & 0x06) != 0) { /* IDvalid? */
+ k = mbuf[1];
+ while (1) {
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ break;
+ if (k > 0)
+ k--;
+ else
+ break;
+ }
}
- if (k > 0) {
- k--;
- goto G2Q_LP;
+ if ((m & assignid_map) != 0) { /* srch from max acceptable ID# */
+ k = i; /* max acceptable ID# */
+ while (1) {
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ break;
+ if (k > 0)
+ k--;
+ else
+ break;
+ }
}
-G2Q_QUIN: /* k=binID#, */
+ /* k=binID#, */
assignid_map |= m;
if (k < 8) {
quintet[0] = 0x38; /* 1st dft ID<8 */
@@ -1284,1227 +1182,6 @@ G2Q_QUIN: /* k=binID#, */
val |= m;
fun_scam(dev, &val);
- goto TCM_SYNC;
-
-}
-
-static void is870(struct atp_unit *dev, unsigned int wkport)
-{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
- static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
- static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
- static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
- static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
-
- tmport = wkport + 0x3a;
- outb((unsigned char) (inb(tmport) | 0x10), tmport);
-
- for (i = 0; i < 16; i++) {
- if ((dev->chip_ver != 4) && (i > 7)) {
- break;
- }
- m = 1;
- m = m << i;
- if ((m & dev->active_id[0]) != 0) {
- continue;
- }
- if (i == dev->host_id[0]) {
- printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
- continue;
- }
- tmport = wkport + 0x1b;
- if (dev->chip_ver == 4) {
- outb(0x01, tmport);
- } else {
- outb(0x00, tmport);
- }
- tmport = wkport + 1;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- j = i;
- if ((j & 0x08) != 0) {
- j = (j & 0x07) | 0x40;
- }
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- dev->active_id[0] |= m;
-
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x04;
- outb(0x00, tmport);
-
-phase_cmd:
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- tmport = wkport + 0x10;
- outb(0x41, tmport);
- goto phase_cmd;
- }
-sel_ok:
- tmport = wkport + 3;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- tmport = wkport + 0x1b;
- if (dev->chip_ver == 4)
- outb(0x00, tmport);
-
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- j = 0;
-rd_inq_data:
- k = inb(tmport);
- if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0) {
- goto rd_inq_data;
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x16) {
- goto inq_ok;
- }
- tmport = wkport + 0x10;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x16) {
- goto sel_ok;
- }
-inq_ok:
- mbuf[36] = 0;
- printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
- dev->id[0][i].devtype = mbuf[0];
- rmb = mbuf[1];
- n = mbuf[7];
- if (dev->chip_ver != 4) {
- goto not_wide;
- }
- if ((mbuf[7] & 0x60) == 0) {
- goto not_wide;
- }
- if ((dev->global_map[0] & 0x20) == 0) {
- goto not_wide;
- }
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 3;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_wide:
- j = 0;
- tmport = wkport + 0x14;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto try_wide;
- }
- continue;
-widep_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_in:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-widep_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto widep_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto widep_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto not_wide;
- }
- if (mbuf[1] != 0x02) {
- goto not_wide;
- }
- if (mbuf[2] != 0x03) {
- goto not_wide;
- }
- if (mbuf[3] != 0x01) {
- goto not_wide;
- }
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
-not_wide:
- if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
- goto set_sync;
- }
- continue;
-set_sync:
- tmport = wkport + 0x1b;
- j = 0;
- if ((m & dev->wide_id[0]) != 0) {
- j |= 0x01;
- }
- outb(j, tmport);
- tmport = wkport + 3;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_sync:
- j = 0;
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- if ((m & dev->wide_id[0]) != 0) {
- outb(synw[j++], tmport);
- } else {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synu[j++], tmport);
- } else {
- outb(synn[j++], tmport);
- }
- }
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto try_sync;
- }
- continue;
-phase_outs:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_ins:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-phase_ins1:
- j = inb(tmport);
- if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00) {
- goto phase_ins1;
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_cmds:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
-tar_dcons:
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- continue;
- }
- if (mbuf[0] != 0x01) {
- continue;
- }
- if (mbuf[1] != 0x03) {
- continue;
- }
- if (mbuf[4] == 0x00) {
- continue;
- }
- if (mbuf[3] > 0x64) {
- continue;
- }
- if (mbuf[4] > 0x0c) {
- mbuf[4] = 0x0c;
- }
- dev->id[0][i].devsp = mbuf[4];
- if ((mbuf[3] < 0x0d) && (rmb == 0)) {
- j = 0xa0;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x1a) {
- j = 0x20;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x33) {
- j = 0x40;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x4c) {
- j = 0x50;
- goto set_syn_ok;
- }
- j = 0x60;
-set_syn_ok:
- dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
- }
- tmport = wkport + 0x3a;
- outb((unsigned char) (inb(tmport) & 0xef), tmport);
-}
-
-static void is880(struct atp_unit *dev, unsigned int wkport)
-{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n, lvdmode;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
- static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
- static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
- static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
- static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
- static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
-
- lvdmode = inb(wkport + 0x3f) & 0x40;
-
- for (i = 0; i < 16; i++) {
- m = 1;
- m = m << i;
- if ((m & dev->active_id[0]) != 0) {
- continue;
- }
- if (i == dev->host_id[0]) {
- printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
- continue;
- }
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x41;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- j = i;
- if ((j & 0x08) != 0) {
- j = (j & 0x07) | 0x40;
- }
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- dev->active_id[0] |= m;
-
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
-
-phase_cmd:
- tmport = wkport + 0x58;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- tmport = wkport + 0x50;
- outb(0x41, tmport);
- goto phase_cmd;
- }
-sel_ok:
- tmport = wkport + 0x43;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- tmport = wkport + 0x5b;
- outb(0x00, tmport);
- tmport = wkport + 0x58;
- outb(0x08, tmport);
- tmport += 0x07;
- j = 0;
-rd_inq_data:
- k = inb(tmport);
- if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0) {
- goto rd_inq_data;
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x16) {
- goto inq_ok;
- }
- tmport = wkport + 0x50;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x16)
- goto sel_ok;
-
-inq_ok:
- mbuf[36] = 0;
- printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
- dev->id[0][i].devtype = mbuf[0];
- rmb = mbuf[1];
- n = mbuf[7];
- if ((mbuf[7] & 0x60) == 0) {
- goto not_wide;
- }
- if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
- goto not_wide;
- }
- if (lvdmode == 0) {
- goto chg_wide;
- }
- if (dev->sp[0][i] != 0x04) // force u2
- {
- goto chg_wide;
- }
-
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
-
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_u3:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(u3[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto try_u3;
- }
- continue;
-u3p_out:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto u3p_out;
- }
- continue;
-u3p_in:
- tmport = wkport + 0x54;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-u3p_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto u3p_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto u3p_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto u3p_out;
- }
- continue;
-u3p_cmd:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto u3p_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto chg_wide;
- }
- if (mbuf[1] != 0x06) {
- goto chg_wide;
- }
- if (mbuf[2] != 0x04) {
- goto chg_wide;
- }
- if (mbuf[3] == 0x09) {
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
- dev->id[0][i].devsp = 0xce;
- continue;
- }
-chg_wide:
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_wide:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto try_wide;
- }
- continue;
-widep_out:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_in:
- tmport = wkport + 0x54;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-widep_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto widep_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_cmd:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto widep_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto not_wide;
- }
- if (mbuf[1] != 0x02) {
- goto not_wide;
- }
- if (mbuf[2] != 0x03) {
- goto not_wide;
- }
- if (mbuf[3] != 0x01) {
- goto not_wide;
- }
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
-not_wide:
- if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
- m = 1;
- m = m << i;
- if ((dev->async[0] & m) != 0) {
- goto set_sync;
- }
- }
- continue;
-set_sync:
- if (dev->sp[0][i] == 0x02) {
- synu[4] = 0x0c;
- synuw[4] = 0x0c;
- } else {
- if (dev->sp[0][i] >= 0x03) {
- synu[4] = 0x0a;
- synuw[4] = 0x0a;
- }
- }
- tmport = wkport + 0x5b;
- j = 0;
- if ((m & dev->wide_id[0]) != 0) {
- j |= 0x01;
- }
- outb(j, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
- continue;
- }
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_sync:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- if ((m & dev->wide_id[0]) != 0) {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synuw[j++], tmport);
- } else {
- outb(synw[j++], tmport);
- }
- } else {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synu[j++], tmport);
- } else {
- outb(synn[j++], tmport);
- }
- }
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto try_sync;
- }
- continue;
-phase_outs:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_ins:
- tmport = wkport + 0x54;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-phase_ins1:
- j = inb(tmport);
- if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00) {
- goto phase_ins1;
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_cmds:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
-tar_dcons:
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- continue;
- }
- if (mbuf[0] != 0x01) {
- continue;
- }
- if (mbuf[1] != 0x03) {
- continue;
- }
- if (mbuf[4] == 0x00) {
- continue;
- }
- if (mbuf[3] > 0x64) {
- continue;
- }
- if (mbuf[4] > 0x0e) {
- mbuf[4] = 0x0e;
- }
- dev->id[0][i].devsp = mbuf[4];
- if (mbuf[3] < 0x0c) {
- j = 0xb0;
- goto set_syn_ok;
- }
- if ((mbuf[3] < 0x0d) && (rmb == 0)) {
- j = 0xa0;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x1a) {
- j = 0x20;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x33) {
- j = 0x40;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x4c) {
- j = 0x50;
- goto set_syn_ok;
- }
- j = 0x60;
-set_syn_ok:
- dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
}
}
@@ -2560,491 +1237,345 @@ static int atp870u_init_tables(struct Scsi_Host *host)
return 0;
}
-/* return non-zero on detection */
-static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void atp_set_host_id(struct atp_unit *atp, u8 c, u8 host_id)
{
- unsigned char k, m, c;
- unsigned long flags;
- unsigned int base_io, tmport, error,n;
- unsigned char host_id;
- struct Scsi_Host *shpnt = NULL;
- struct atp_unit *atpdev, *p;
- unsigned char setupdata[2][16];
- int count = 0;
+ atp_writeb_io(atp, c, 0, host_id | 0x08);
+ atp_writeb_io(atp, c, 0x18, 0);
+ while ((atp_readb_io(atp, c, 0x1f) & 0x80) == 0)
+ mdelay(1);
+ atp_readb_io(atp, c, 0x17);
+ atp_writeb_io(atp, c, 1, 8);
+ atp_writeb_io(atp, c, 2, 0x7f);
+ atp_writeb_io(atp, c, 0x11, 0x20);
+}
- atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
- if (!atpdev)
- return -ENOMEM;
+static void atp870_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, host_id;
+ u8 scam_on;
+ bool wide_chip =
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7610 &&
+ pdev->revision == 4) ||
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612UW) ||
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612SUW);
+
+ pci_read_config_byte(pdev, 0x49, &host_id);
+
+ dev_info(&pdev->dev, "ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+
+ atpdev->ioport[0] = shpnt->io_port;
+ atpdev->pciport[0] = shpnt->io_port + 0x20;
+ host_id &= 0x07;
+ atpdev->host_id[0] = host_id;
+ scam_on = atp_readb_pci(atpdev, 0, 2);
+ atpdev->global_map[0] = atp_readb_base(atpdev, 0x2d);
+ atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x2e);
+
+ if (atpdev->ultra_map[0] == 0) {
+ scam_on = 0x00;
+ atpdev->global_map[0] = 0x20;
+ atpdev->ultra_map[0] = 0xffff;
+ }
- if (pci_enable_device(pdev))
- goto err_eio;
+ if (pdev->revision > 0x07) /* check if atp876 chip */
+ atp_writeb_base(atpdev, 0x3e, 0x00); /* enable terminator */
+
+ k = (atp_readb_base(atpdev, 0x3a) & 0xf3) | 0x10;
+ atp_writeb_base(atpdev, 0x3a, k);
+ atp_writeb_base(atpdev, 0x3a, k & 0xdf);
+ mdelay(32);
+ atp_writeb_base(atpdev, 0x3a, k);
+ mdelay(32);
+ atp_set_host_id(atpdev, 0, host_id);
+
+ tscam(shpnt, wide_chip, scam_on);
+ atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) | 0x10);
+ atp_is(atpdev, 0, wide_chip, 0);
+ atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) & 0xef);
+ atp_writeb_base(atpdev, 0x3b, atp_readb_base(atpdev, 0x3b) | 0x20);
+ shpnt->max_id = wide_chip ? 16 : 8;
+ shpnt->this_id = host_id;
+}
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
- } else {
- printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
- goto err_eio;
- }
+static void atp880_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, m, host_id;
+ unsigned int n;
- /*
- * It's probably easier to weed out some revisions like
- * this than via the PCI device table
- */
- if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
- atpdev->chip_ver = pdev->revision;
- if (atpdev->chip_ver < 2)
- goto err_eio;
- }
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
- switch (ent->device) {
- case PCI_DEVICE_ID_ARTOP_AEC7612UW:
- case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
- case ATP880_DEVID1:
- case ATP880_DEVID2:
- case ATP885_DEVID:
- atpdev->chip_ver = 0x04;
- default:
- break;
- }
- base_io = pci_resource_start(pdev, 0);
- base_io &= 0xfffffff8;
-
- if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
- atpdev->chip_ver = pdev->revision;
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
-
- host_id = inb(base_io + 0x39);
- host_id >>= 0x04;
-
- printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
- " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atpdev->ioport[0] = base_io + 0x40;
- atpdev->pciport[0] = base_io + 0x28;
- atpdev->dev_id = ent->device;
- atpdev->host_id[0] = host_id;
-
- tmport = base_io + 0x22;
- atpdev->scam_on = inb(tmport);
- tmport += 0x13;
- atpdev->global_map[0] = inb(tmport);
- tmport += 0x07;
- atpdev->ultra_map[0] = inw(tmport);
-
- n = 0x3f09;
-next_fblk_880:
- if (n >= 0x4000)
- goto flash_ok_880;
+ atpdev->ioport[0] = shpnt->io_port + 0x40;
+ atpdev->pciport[0] = shpnt->io_port + 0x28;
+
+ host_id = atp_readb_base(atpdev, 0x39) >> 4;
+ dev_info(&pdev->dev, "ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+ atpdev->host_id[0] = host_id;
+
+ atpdev->global_map[0] = atp_readb_base(atpdev, 0x35);
+ atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x3c);
+
+ n = 0x3f09;
+ while (n < 0x4000) {
m = 0;
- outw(n, base_io + 0x34);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- if (inb(base_io + 0x30) == 0xff)
- goto flash_ok_880;
-
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ if (atp_readb_base(atpdev, 0x30) == 0xff)
+ break;
+
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
n += 0x0018;
- goto next_fblk_880;
-flash_ok_880:
- outw(0, base_io + 0x34);
- atpdev->ultra_map[0] = 0;
- atpdev->async[0] = 0;
+ }
+ atp_writew_base(atpdev, 0x34, 0);
+ atpdev->ultra_map[0] = 0;
+ atpdev->async[0] = 0;
+ for (k = 0; k < 16; k++) {
+ n = 1 << k;
+ if (atpdev->sp[0][k] > 1)
+ atpdev->ultra_map[0] |= n;
+ else
+ if (atpdev->sp[0][k] == 0)
+ atpdev->async[0] |= n;
+ }
+ atpdev->async[0] = ~(atpdev->async[0]);
+ atp_writeb_base(atpdev, 0x35, atpdev->global_map[0]);
+
+ k = atp_readb_base(atpdev, 0x38) & 0x80;
+ atp_writeb_base(atpdev, 0x38, k);
+ atp_writeb_base(atpdev, 0x3b, 0x20);
+ mdelay(32);
+ atp_writeb_base(atpdev, 0x3b, 0);
+ mdelay(32);
+ atp_readb_io(atpdev, 0, 0x1b);
+ atp_readb_io(atpdev, 0, 0x17);
+
+ atp_set_host_id(atpdev, 0, host_id);
+
+ tscam(shpnt, true, atp_readb_base(atpdev, 0x22));
+ atp_is(atpdev, 0, true, atp_readb_base(atpdev, 0x3f) & 0x40);
+ atp_writeb_base(atpdev, 0x38, 0xb0);
+ shpnt->max_id = 16;
+ shpnt->this_id = host_id;
+}
+
+static void atp885_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, m, c;
+ unsigned int n;
+ unsigned char setupdata[2][16];
+
+ dev_info(&pdev->dev, "ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+
+ atpdev->ioport[0] = shpnt->io_port + 0x80;
+ atpdev->ioport[1] = shpnt->io_port + 0xc0;
+ atpdev->pciport[0] = shpnt->io_port + 0x40;
+ atpdev->pciport[1] = shpnt->io_port + 0x50;
+
+ c = atp_readb_base(atpdev, 0x29);
+ atp_writeb_base(atpdev, 0x29, c | 0x04);
+
+ n = 0x1f80;
+ while (n < 0x2000) {
+ atp_writew_base(atpdev, 0x3c, n);
+ if (atp_readl_base(atpdev, 0x38) == 0xffffffff)
+ break;
+ for (m = 0; m < 2; m++) {
+ atpdev->global_map[m] = 0;
+ for (k = 0; k < 4; k++) {
+ atp_writew_base(atpdev, 0x3c, n++);
+ ((unsigned long *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38);
+ }
+ for (k = 0; k < 4; k++) {
+ atp_writew_base(atpdev, 0x3c, n++);
+ ((unsigned long *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38);
+ }
+ n += 8;
+ }
+ }
+ c = atp_readb_base(atpdev, 0x29);
+ atp_writeb_base(atpdev, 0x29, c & 0xfb);
+ for (c = 0; c < 2; c++) {
+ atpdev->ultra_map[c] = 0;
+ atpdev->async[c] = 0;
for (k = 0; k < 16; k++) {
- n = 1;
- n = n << k;
- if (atpdev->sp[0][k] > 1) {
- atpdev->ultra_map[0] |= n;
- } else {
- if (atpdev->sp[0][k] == 0)
- atpdev->async[0] |= n;
- }
- }
- atpdev->async[0] = ~(atpdev->async[0]);
- outb(atpdev->global_map[0], base_io + 0x35);
-
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
-
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(*atpdev));
- if (atp870u_init_tables(shpnt) < 0) {
- printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
- goto unregister;
- }
-
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
- goto free_tables;
- }
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- tmport = base_io + 0x38;
- k = inb(tmport) & 0x80;
- outb(k, tmport);
- tmport += 0x03;
- outb(0x20, tmport);
- mdelay(32);
- outb(0, tmport);
- mdelay(32);
- tmport = base_io + 0x5b;
- inb(tmport);
- tmport -= 0x04;
- inb(tmport);
- tmport = base_io + 0x40;
- outb((host_id | 0x08), tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
- mdelay(1);
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0x41;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x51;
- outb(0x20, tmport);
-
- tscam(shpnt);
- is880(p, base_io);
- tmport = base_io + 0x38;
- outb(0xb0, tmport);
- shpnt->max_id = 16;
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
- } else if (ent->device == ATP885_DEVID) {
- printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n"
- , base_io, pdev->irq);
-
- atpdev->pdev = pdev;
- atpdev->dev_id = ent->device;
- atpdev->baseport = base_io;
- atpdev->ioport[0] = base_io + 0x80;
- atpdev->ioport[1] = base_io + 0xc0;
- atpdev->pciport[0] = base_io + 0x40;
- atpdev->pciport[1] = base_io + 0x50;
-
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
-
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(struct atp_unit));
- if (atp870u_init_tables(shpnt) < 0)
- goto unregister;
-
-#ifdef ED_DBGP
- printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
-#endif
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
- goto free_tables;
+ n = 1 << k;
+ if (atpdev->sp[c][k] > 1)
+ atpdev->ultra_map[c] |= n;
+ else
+ if (atpdev->sp[c][k] == 0)
+ atpdev->async[c] |= n;
+ }
+ atpdev->async[c] = ~(atpdev->async[c]);
+
+ if (atpdev->global_map[c] == 0) {
+ k = setupdata[c][1];
+ if ((k & 0x40) != 0)
+ atpdev->global_map[c] |= 0x20;
+ k &= 0x07;
+ atpdev->global_map[c] |= k;
+ if ((setupdata[c][2] & 0x04) != 0)
+ atpdev->global_map[c] |= 0x08;
+ atpdev->host_id[c] = setupdata[c][0] & 0x07;
}
-
- spin_lock_irqsave(shpnt->host_lock, flags);
-
- c=inb(base_io + 0x29);
- outb((c | 0x04),base_io + 0x29);
-
- n=0x1f80;
-next_fblk_885:
- if (n >= 0x2000) {
- goto flash_ok_885;
- }
- outw(n,base_io + 0x3c);
- if (inl(base_io + 0x38) == 0xffffffff) {
- goto flash_ok_885;
- }
- for (m=0; m < 2; m++) {
- p->global_map[m]= 0;
- for (k=0; k < 4; k++) {
- outw(n++,base_io + 0x3c);
- ((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
- }
- for (k=0; k < 4; k++) {
- outw(n++,base_io + 0x3c);
- ((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
- }
- n += 8;
- }
- goto next_fblk_885;
-flash_ok_885:
-#ifdef ED_DBGP
- printk( "Flash Read OK\n");
-#endif
- c=inb(base_io + 0x29);
- outb((c & 0xfb),base_io + 0x29);
- for (c=0;c < 2;c++) {
- p->ultra_map[c]=0;
- p->async[c] = 0;
- for (k=0; k < 16; k++) {
- n=1;
- n = n << k;
- if (p->sp[c][k] > 1) {
- p->ultra_map[c] |= n;
- } else {
- if (p->sp[c][k] == 0) {
- p->async[c] |= n;
- }
- }
- }
- p->async[c] = ~(p->async[c]);
-
- if (p->global_map[c] == 0) {
- k=setupdata[c][1];
- if ((k & 0x40) != 0)
- p->global_map[c] |= 0x20;
- k &= 0x07;
- p->global_map[c] |= k;
- if ((setupdata[c][2] & 0x04) != 0)
- p->global_map[c] |= 0x08;
- p->host_id[c] = setupdata[c][0] & 0x07;
- }
- }
-
- k = inb(base_io + 0x28) & 0x8f;
- k |= 0x10;
- outb(k, base_io + 0x28);
- outb(0x80, base_io + 0x41);
- outb(0x80, base_io + 0x51);
- mdelay(100);
- outb(0, base_io + 0x41);
- outb(0, base_io + 0x51);
- mdelay(1000);
- inb(base_io + 0x9b);
- inb(base_io + 0x97);
- inb(base_io + 0xdb);
- inb(base_io + 0xd7);
- tmport = base_io + 0x80;
- k=p->host_id[0];
- if (k > 7)
- k = (k & 0x07) | 0x40;
- k |= 0x08;
- outb(k, tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0)
- cpu_relax();
-
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0x81;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x91;
- outb(0x20, tmport);
-
- tmport = base_io + 0xc0;
- k=p->host_id[1];
- if (k > 7)
- k = (k & 0x07) | 0x40;
- k |= 0x08;
- outb(k, tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0)
- cpu_relax();
+ }
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0xc1;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0xd1;
- outb(0x20, tmport);
-
- tscam_885();
- printk(KERN_INFO " Scanning Channel A SCSI Device ...\n");
- is885(p, base_io + 0x80, 0);
- printk(KERN_INFO " Scanning Channel B SCSI Device ...\n");
- is885(p, base_io + 0xc0, 1);
-
- k = inb(base_io + 0x28) & 0xcf;
- k |= 0xc0;
- outb(k, base_io + 0x28);
- k = inb(base_io + 0x1f) | 0x80;
- outb(k, base_io + 0x1f);
- k = inb(base_io + 0x29) | 0x01;
- outb(k, base_io + 0x29);
-#ifdef ED_DBGP
- //printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
-#endif
- shpnt->max_id = 16;
- shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
- shpnt->max_channel = 1;
- shpnt->this_id = p->host_id[0];
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0xff; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
-
- } else {
- error = pci_read_config_byte(pdev, 0x49, &host_id);
+ k = atp_readb_base(atpdev, 0x28) & 0x8f;
+ k |= 0x10;
+ atp_writeb_base(atpdev, 0x28, k);
+ atp_writeb_pci(atpdev, 0, 1, 0x80);
+ atp_writeb_pci(atpdev, 1, 1, 0x80);
+ mdelay(100);
+ atp_writeb_pci(atpdev, 0, 1, 0);
+ atp_writeb_pci(atpdev, 1, 1, 0);
+ mdelay(1000);
+ atp_readb_io(atpdev, 0, 0x1b);
+ atp_readb_io(atpdev, 0, 0x17);
+ atp_readb_io(atpdev, 1, 0x1b);
+ atp_readb_io(atpdev, 1, 0x17);
+
+ k = atpdev->host_id[0];
+ if (k > 7)
+ k = (k & 0x07) | 0x40;
+ atp_set_host_id(atpdev, 0, k);
+
+ k = atpdev->host_id[1];
+ if (k > 7)
+ k = (k & 0x07) | 0x40;
+ atp_set_host_id(atpdev, 1, k);
+
+ mdelay(600); /* this delay used to be called tscam_885() */
+ dev_info(&pdev->dev, "Scanning Channel A SCSI Device ...\n");
+ atp_is(atpdev, 0, true, atp_readb_io(atpdev, 0, 0x1b) >> 7);
+ atp_writeb_io(atpdev, 0, 0x16, 0x80);
+ dev_info(&pdev->dev, "Scanning Channel B SCSI Device ...\n");
+ atp_is(atpdev, 1, true, atp_readb_io(atpdev, 1, 0x1b) >> 7);
+ atp_writeb_io(atpdev, 1, 0x16, 0x80);
+ k = atp_readb_base(atpdev, 0x28) & 0xcf;
+ k |= 0xc0;
+ atp_writeb_base(atpdev, 0x28, k);
+ k = atp_readb_base(atpdev, 0x1f) | 0x80;
+ atp_writeb_base(atpdev, 0x1f, k);
+ k = atp_readb_base(atpdev, 0x29) | 0x01;
+ atp_writeb_base(atpdev, 0x29, k);
+ shpnt->max_id = 16;
+ shpnt->max_lun = (atpdev->global_map[0] & 0x07) + 1;
+ shpnt->max_channel = 1;
+ shpnt->this_id = atpdev->host_id[0];
+}
- printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
- "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+/* return non-zero on detection */
+static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct Scsi_Host *shpnt = NULL;
+ struct atp_unit *atpdev;
+ int err;
- atpdev->ioport[0] = base_io;
- atpdev->pciport[0] = base_io + 0x20;
- atpdev->dev_id = ent->device;
- host_id &= 0x07;
- atpdev->host_id[0] = host_id;
- tmport = base_io + 0x22;
- atpdev->scam_on = inb(tmport);
- tmport += 0x0b;
- atpdev->global_map[0] = inb(tmport++);
- atpdev->ultra_map[0] = inw(tmport);
+ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610 && pdev->revision < 2) {
+ dev_err(&pdev->dev, "ATP850S chips (AEC6710L/F cards) are not supported.\n");
+ return -ENODEV;
+ }
- if (atpdev->ultra_map[0] == 0) {
- atpdev->scam_on = 0x00;
- atpdev->global_map[0] = 0x20;
- atpdev->ultra_map[0] = 0xffff;
- }
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
+ err = -EIO;
+ goto disable_device;
+ }
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(*atpdev));
- if (atp870u_init_tables(shpnt) < 0)
- goto unregister;
-
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
- goto free_tables;
- }
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
- tmport = base_io + 0x3e;
- outb(0x00, tmport);
- }
-
- tmport = base_io + 0x3a;
- k = (inb(tmport) & 0xf3) | 0x10;
- outb(k, tmport);
- outb((k & 0xdf), tmport);
- mdelay(32);
- outb(k, tmport);
- mdelay(32);
- tmport = base_io;
- outb((host_id | 0x08), tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
- mdelay(1);
-
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 1;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x11;
- outb(0x20, tmport);
-
- tscam(shpnt);
- is870(p, base_io);
- tmport = base_io + 0x3a;
- outb((inb(tmport) & 0xef), tmport);
- tmport++;
- outb((inb(tmport) | 0x20), tmport);
- if (atpdev->chip_ver == 4)
- shpnt->max_id = 16;
- else
- shpnt->max_id = 8;
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
- }
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- if(ent->device==ATP885_DEVID) {
- if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
- if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- } else {
- if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- }
- count++;
- if (scsi_add_host(shpnt, &pdev->dev))
- goto scsi_add_fail;
- scsi_scan_host(shpnt);
-#ifdef ED_DBGP
- printk("atp870u_prob : exit\n");
-#endif
- return 0;
+ err = pci_request_regions(pdev, "atp870u");
+ if (err)
+ goto disable_device;
+ pci_set_master(pdev);
+
+ err = -ENOMEM;
+ shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+ if (!shpnt)
+ goto release_region;
+
+ atpdev = shost_priv(shpnt);
+
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
+ pci_set_drvdata(pdev, atpdev);
+
+ shpnt->io_port = pci_resource_start(pdev, 0);
+ shpnt->io_port &= 0xfffffff8;
+ shpnt->n_io_port = pci_resource_len(pdev, 0);
+ atpdev->baseport = shpnt->io_port;
+ shpnt->unique_id = shpnt->io_port;
+ shpnt->irq = pdev->irq;
+
+ err = atp870u_init_tables(shpnt);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate tables for Acard controller\n");
+ goto unregister;
+ }
-scsi_add_fail:
- printk("atp870u_prob:scsi_add_fail\n");
- if(ent->device==ATP885_DEVID) {
- release_region(base_io, 0xff);
- } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
- release_region(base_io, 0x60);
- } else {
- release_region(base_io, 0x40);
+ if (is880(atpdev))
+ atp880_init(shpnt);
+ else if (is885(atpdev))
+ atp885_init(shpnt);
+ else
+ atp870_init(shpnt);
+
+ err = request_irq(shpnt->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate IRQ %d.\n", shpnt->irq);
+ goto free_tables;
}
-request_io_fail:
- printk("atp870u_prob:request_io_fail\n");
- free_irq(pdev->irq, shpnt);
+
+ err = scsi_add_host(shpnt, &pdev->dev);
+ if (err)
+ goto scsi_add_fail;
+ scsi_scan_host(shpnt);
+
+ return 0;
+
+scsi_add_fail:
+ free_irq(shpnt->irq, shpnt);
free_tables:
- printk("atp870u_prob:free_table\n");
atp870u_free_tables(shpnt);
unregister:
- printk("atp870u_prob:unregister\n");
scsi_host_put(shpnt);
- return -1;
-err_eio:
- kfree(atpdev);
- return -EIO;
-err_nomem:
- kfree(atpdev);
- return -ENOMEM;
+release_region:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+fail:
+ return err;
}
/* The abort command does not leave the device in a clean state where
@@ -3055,7 +1586,6 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
{
unsigned char j, k, c;
struct scsi_cmnd *workrequ;
- unsigned int tmport;
struct atp_unit *dev;
struct Scsi_Host *host;
host = SCpnt->device->host;
@@ -3065,18 +1595,13 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
printk(" atp870u: abort Channel = %x \n", c);
printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
- tmport = dev->ioport[c];
for (j = 0; j < 0x18; j++) {
- printk(" r%2x=%2x", j, inb(tmport++));
+ printk(" r%2x=%2x", j, atp_readb_io(dev, c, j));
}
- tmport += 0x04;
- printk(" r1c=%2x", inb(tmport));
- tmport += 0x03;
- printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]);
- tmport= dev->pciport[c];
- printk(" d00=%2x", inb(tmport));
- tmport += 0x02;
- printk(" d02=%2x", inb(tmport));
+ printk(" r1c=%2x", atp_readb_io(dev, c, 0x1c));
+ printk(" r1f=%2x in_snd=%2x ", atp_readb_io(dev, c, 0x1f), dev->in_snd[c]);
+ printk(" d00=%2x", atp_readb_pci(dev, c, 0x00));
+ printk(" d02=%2x", atp_readb_pci(dev, c, 0x02));
for(j=0;j<16;j++) {
if (dev->id[c][j].curr_req != NULL) {
workrequ = dev->id[c][j].curr_req;
@@ -3136,12 +1661,10 @@ static void atp870u_remove (struct pci_dev *pdev)
scsi_remove_host(pshost);
- printk(KERN_INFO "free_irq : %d\n",pshost->irq);
free_irq(pshost->irq, pshost);
- release_region(pshost->io_port, pshost->n_io_port);
- printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
atp870u_free_tables(pshost);
- printk(KERN_INFO "scsi_host_put : %p\n",pshost);
scsi_host_put(pshost);
}
MODULE_LICENSE("GPL");
@@ -3185,52 +1708,26 @@ static struct pci_driver atp870u_driver = {
.remove = atp870u_remove,
};
-static int __init atp870u_init(void)
-{
-#ifdef ED_DBGP
- printk("atp870u_init: Entry\n");
-#endif
- return pci_register_driver(&atp870u_driver);
-}
-
-static void __exit atp870u_exit(void)
-{
-#ifdef ED_DBGP
- printk("atp870u_exit: Entry\n");
-#endif
- pci_unregister_driver(&atp870u_driver);
-}
-
-static void tscam_885(void)
-{
- unsigned char i;
-
- for (i = 0; i < 0x2; i++) {
- mdelay(300);
- }
- return;
-}
-
-
+module_pci_driver(atp870u_driver);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode)
{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n, lvdmode;
+ unsigned char i, j, k, rmb, n;
unsigned short int m;
static unsigned char mbuf[512];
- static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6};
- static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
- static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
- unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
- static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
- unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
- static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0};
- static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
-
- lvdmode=inb(wkport + 0x1b) >> 7;
+ static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
+ static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
+ static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+ unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+ static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+ static unsigned char synw_870[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
+ unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+ static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
+ static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
for (i = 0; i < 16; i++) {
+ if (!wide_chip && (i > 7))
+ break;
m = 1;
m = m << i;
if ((m & dev->active_id[c]) != 0) {
@@ -3240,192 +1737,172 @@ static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[c]);
continue;
}
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x01;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
-
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
+ atp_writeb_io(dev, c, 0x1b, wide_chip ? 0x01 : 0x00);
+ atp_writeb_io(dev, c, 1, 0x08);
+ atp_writeb_io(dev, c, 2, 0x7f);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
j = i;
if ((j & 0x08) != 0) {
j = (j & 0x07) | 0x40;
}
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
- while ((inb(tmport) & 0x80) == 0x00)
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
dev->active_id[c] |= m;
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ if (is885(dev) || is880(dev))
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ else /* result of is870() merge - is this a bug? */
+ atp_writeb_io(dev, c, 0x04, 0x00);
phase_cmd:
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
- tmport = wkport + 0x10;
- outb(0x41, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x41);
goto phase_cmd;
}
sel_ok:
- tmport = wkport + 0x03;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 3, inqd[0]);
+ atp_writeb_io(dev, c, 4, inqd[1]);
+ atp_writeb_io(dev, c, 5, inqd[2]);
+ atp_writeb_io(dev, c, 6, inqd[3]);
+ atp_writeb_io(dev, c, 7, inqd[4]);
+ atp_writeb_io(dev, c, 8, inqd[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, inqd[6]);
+ atp_writeb_io(dev, c, 0x14, inqd[7]);
+ atp_writeb_io(dev, c, 0x18, inqd[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
- tmport = wkport + 0x1b;
- outb(0x00, tmport);
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
+
+ if (wide_chip)
+ atp_writeb_io(dev, c, 0x1b, 0x00);
+
+ atp_writeb_io(dev, c, 0x18, 0x08);
j = 0;
rd_inq_data:
- k = inb(tmport);
+ k = atp_readb_io(dev, c, 0x1f);
if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
+ mbuf[j++] = atp_readb_io(dev, c, 0x19);
goto rd_inq_data;
}
if ((k & 0x80) == 0) {
goto rd_inq_data;
}
- tmport -= 0x08;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x16) {
goto inq_ok;
}
- tmport = wkport + 0x10;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x10, 0x46);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, 0);
+ atp_writeb_io(dev, c, 0x14, 0);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if (inb(tmport) != 0x16) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x16)
goto sel_ok;
- }
+
inq_ok:
mbuf[36] = 0;
- printk( KERN_INFO" ID: %2d %s\n", i, &mbuf[8]);
+ printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
dev->id[c][i].devtype = mbuf[0];
rmb = mbuf[1];
n = mbuf[7];
+ if (!wide_chip)
+ goto not_wide;
if ((mbuf[7] & 0x60) == 0) {
goto not_wide;
}
- if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
- goto not_wide;
+ if (is885(dev) || is880(dev)) {
+ if ((i < 8) && ((dev->global_map[c] & 0x20) == 0))
+ goto not_wide;
+ } else { /* result of is870() merge - is this a bug? */
+ if ((dev->global_map[c] & 0x20) == 0)
+ goto not_wide;
}
if (lvdmode == 0) {
- goto chg_wide;
- }
- if (dev->sp[c][i] != 0x04) { // force u2
- goto chg_wide;
- }
-
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ goto chg_wide;
+ }
+ if (dev->sp[c][i] != 0x04) // force u2
+ {
+ goto chg_wide;
+ }
+
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_u3:
j = 0;
- tmport = wkport + 0x14;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(u3[j++], tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x14, 0x09);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, u3[j++]);
cpu_relax();
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3437,19 +1914,13 @@ try_u3:
}
continue;
u3p_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, 0);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3461,25 +1932,19 @@ u3p_out:
}
continue;
u3p_in:
- tmport = wkport + 0x14;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x14, 0x09);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
u3p_in1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto u3p_in1;
}
if ((j & 0x80) == 0x00) {
goto u3p_in1;
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3491,16 +1956,13 @@ u3p_in1:
}
continue;
u3p_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport -= 0x08;
- j = inb(tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
if (j == 0x4e) {
goto u3p_out;
@@ -3527,54 +1989,44 @@ u3p_cmd:
continue;
}
chg_wide:
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_wide:
j = 0;
- tmport = wkport + 0x14;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x14, 0x05);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, wide[j++]);
cpu_relax();
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3586,19 +2038,13 @@ try_wide:
}
continue;
widep_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, 0);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3610,25 +2056,19 @@ widep_out:
}
continue;
widep_in:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x14, 0xff);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
widep_in1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto widep_in1;
}
if ((j & 0x80) == 0x00) {
goto widep_in1;
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3640,17 +2080,14 @@ widep_in1:
}
continue;
widep_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
if (j == 0x4e) {
goto widep_out;
@@ -3673,88 +2110,81 @@ widep_cmd:
m = m << i;
dev->wide_id[c] |= m;
not_wide:
- if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
- ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+ if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) || ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
m = 1;
m = m << i;
if ((dev->async[c] & m) != 0) {
- goto set_sync;
+ goto set_sync;
}
}
continue;
set_sync:
- if (dev->sp[c][i] == 0x02) {
- synu[4]=0x0c;
- synuw[4]=0x0c;
+ if ((!is885(dev) && !is880(dev)) || (dev->sp[c][i] == 0x02)) {
+ synu[4] = 0x0c;
+ synuw[4] = 0x0c;
} else {
- if (dev->sp[c][i] >= 0x03) {
- synu[4]=0x0a;
- synuw[4]=0x0a;
- }
+ if (dev->sp[c][i] >= 0x03) {
+ synu[4] = 0x0a;
+ synuw[4] = 0x0a;
+ }
}
- tmport = wkport + 0x1b;
j = 0;
if ((m & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x1b, j);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_sync:
j = 0;
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
+ atp_writeb_io(dev, c, 0x14, 0x06);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0) {
if ((m & dev->wide_id[c]) != 0) {
- if ((m & dev->ultra_map[c]) != 0) {
- outb(synuw[j++], tmport);
- } else {
- outb(synw[j++], tmport);
- }
+ if (is885(dev) || is880(dev)) {
+ if ((m & dev->ultra_map[c]) != 0) {
+ atp_writeb_io(dev, c, 0x19, synuw[j++]);
+ } else {
+ atp_writeb_io(dev, c, 0x19, synw[j++]);
+ }
+ } else
+ atp_writeb_io(dev, c, 0x19, synw_870[j++]);
} else {
if ((m & dev->ultra_map[c]) != 0) {
- outb(synu[j++], tmport);
+ atp_writeb_io(dev, c, 0x19, synu[j++]);
} else {
- outb(synn[j++], tmport);
+ atp_writeb_io(dev, c, 0x19, synn[j++]);
}
}
- tmport += 0x06;
}
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto phase_ins;
}
@@ -3766,19 +2196,13 @@ try_sync:
}
continue;
phase_outs:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0x00)
+ atp_writeb_io(dev, c, 0x19, 0x00);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x85) {
goto tar_dcons;
}
@@ -3794,26 +2218,25 @@ phase_outs:
}
continue;
phase_ins:
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ if (is885(dev) || is880(dev))
+ atp_writeb_io(dev, c, 0x14, 0x06);
+ else
+ atp_writeb_io(dev, c, 0x14, 0xff);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
phase_ins1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto phase_ins1;
}
if ((j & 0x80) == 0x00) {
goto phase_ins1;
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00);
- j = inb(tmport);
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x85) {
goto tar_dcons;
}
@@ -3829,18 +2252,15 @@ phase_ins1:
}
continue;
phase_cmds:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
tar_dcons:
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
continue;
}
@@ -3856,14 +2276,21 @@ tar_dcons:
if (mbuf[3] > 0x64) {
continue;
}
- if (mbuf[4] > 0x0e) {
- mbuf[4] = 0x0e;
+ if (is885(dev) || is880(dev)) {
+ if (mbuf[4] > 0x0e) {
+ mbuf[4] = 0x0e;
+ }
+ } else {
+ if (mbuf[4] > 0x0c) {
+ mbuf[4] = 0x0c;
+ }
}
dev->id[c][i].devsp = mbuf[4];
- if (mbuf[3] < 0x0c){
- j = 0xb0;
- goto set_syn_ok;
- }
+ if (is885(dev) || is880(dev))
+ if (mbuf[3] < 0x0c) {
+ j = 0xb0;
+ goto set_syn_ok;
+ }
if ((mbuf[3] < 0x0d) && (rmb == 0)) {
j = 0xa0;
goto set_syn_ok;
@@ -3881,16 +2308,10 @@ tar_dcons:
goto set_syn_ok;
}
j = 0x60;
- set_syn_ok:
+set_syn_ok:
dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
-#ifdef ED_DBGP
+#ifdef ED_DBGP
printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
#endif
}
- tmport = wkport + 0x16;
- outb(0x80, tmport);
}
-
-module_init(atp870u_init);
-module_exit(atp870u_exit);
-
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
index 5cf62566ad42..9b839b1e895a 100644
--- a/drivers/scsi/atp870u.h
+++ b/drivers/scsi/atp870u.h
@@ -26,22 +26,18 @@ struct atp_unit
unsigned long baseport;
unsigned long ioport[2];
unsigned long pciport[2];
- unsigned long irq;
unsigned char last_cmd[2];
unsigned char in_snd[2];
unsigned char in_int[2];
unsigned char quhd[2];
unsigned char quend[2];
unsigned char global_map[2];
- unsigned char chip_ver;
- unsigned char scam_on;
unsigned char host_id[2];
unsigned int working[2];
unsigned short wide_id[2];
unsigned short active_id[2];
unsigned short ultra_map[2];
unsigned short async[2];
- unsigned short dev_id;
unsigned char sp[2][16];
unsigned char r1f[2][16];
struct scsi_cmnd *quereq[2][qcnt];
diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h
index 4ad7e368bbc2..0e119d838e1b 100644
--- a/drivers/scsi/bfa/bfa.h
+++ b/drivers/scsi/bfa/bfa.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index e3f67b097a5c..2ea0db4b62a7 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h
index 91a8aa394db5..da9cf655be26 100644
--- a/drivers/scsi/bfa/bfa_cs.h
+++ b/drivers/scsi/bfa/bfa_cs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h
index 877b86dd2837..5dc3782d615b 100644
--- a/drivers/scsi/bfa/bfa_defs.h
+++ b/drivers/scsi/bfa/bfa_defs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h
index 06f0a163ca35..5815a904574d 100644
--- a/drivers/scsi/bfa/bfa_defs_fcs.h
+++ b/drivers/scsi/bfa/bfa_defs_fcs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index 638f441ffc38..e81707f938cb 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h
index 64069a0a3d0d..18b7304d6b0b 100644
--- a/drivers/scsi/bfa/bfa_fc.h
+++ b/drivers/scsi/bfa/bfa_fc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c
index dce787f6cca2..b8dadc9cc993 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.c
+++ b/drivers/scsi/bfa/bfa_fcbuild.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h
index 03c753d1e548..b109a8813401 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.h
+++ b/drivers/scsi/bfa/bfa_fcbuild.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index d7385d1d9c5a..20982e7cdd81 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h
index e693af6e5930..e93921dec347 100644
--- a/drivers/scsi/bfa/bfa_fcpim.h
+++ b/drivers/scsi/bfa/bfa_fcpim.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 0f19455951ec..1e7e139d71ea 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index 42bcb970445a..06dc215ea050 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -633,7 +634,7 @@ void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
/*
* HBA Attribute Block : BFA internal representation. Note : Some variable
- * sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based
+ * sizes have been trimmed to suit BFA For Ex : Model will be "QLogic ". Based
* on this the size has been reduced to 16 bytes from the standard's 64 bytes.
*/
struct bfa_fcs_fdmi_hba_attr_s {
diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c
index 6dc7926a3edd..4f089d76afb1 100644
--- a/drivers/scsi/bfa/bfa_fcs_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index ff75ef891755..7733ad5305d4 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -2653,7 +2654,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
strncpy(hba_attr->node_sym_name.symname,
port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
- strcpy(hba_attr->vendor_info, "BROCADE");
+ strcpy(hba_attr->vendor_info, "QLogic");
hba_attr->num_ports =
cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c
index 2035b0d64351..de50349a39ce 100644
--- a/drivers/scsi/bfa/bfa_fcs_rport.c
+++ b/drivers/scsi/bfa/bfa_fcs_rport.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index ea24d4c6e67a..c4a0c0eb88a5 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index 637527f48b40..b0ff378dece2 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 98f7e8cca52d..251e2ff8ff5f 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -2697,7 +2698,7 @@ bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
}
-#define BFA_MFG_NAME "Brocade"
+#define BFA_MFG_NAME "QLogic"
void
bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
struct bfa_adapter_attr_s *ad_attr)
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index a38aafa030b3..713745da44c6 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index 453c2f5b5561..f1b80da298c8 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index bd53150e4ee0..651a8fb93037 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index a14c784ff3fc..53135f21fa0e 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h
index 1c9baa68339b..da570c0b8275 100644
--- a/drivers/scsi/bfa/bfa_plog.h
+++ b/drivers/scsi/bfa/bfa_plog.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index 8ea7697deb9b..da1721e0d167 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h
index 2fcab6bc6280..26dc1bf14c85 100644
--- a/drivers/scsi/bfa/bfa_port.h
+++ b/drivers/scsi/bfa/bfa_port.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index 625225f31081..12de292175ef 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h
index ef07365991e7..ea2278bc78a8 100644
--- a/drivers/scsi/bfa/bfa_svc.h
+++ b/drivers/scsi/bfa/bfa_svc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index cc3b9d3d6d40..9d253cb83ee7 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -130,13 +131,9 @@ MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for "
"boot port. Otherwise 10 secs in RHEL4 & 0 for "
"[RHEL5, SLES10, ESX40] Range[>0]");
module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts "
- "for Brocade-415/425/815/825 cards, default=0, "
- " Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts for QLogic-415/425/815/825 cards, default=0 Range[false:0|true:1]");
module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts "
- "if possible for Brocade-1010/1020/804/1007/902/1741 "
- "cards, default=0, Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts if possible for QLogic-1010/1020/804/1007/902/1741 cards, default=0, Range[false:0|true:1]");
module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, "
"Range[false:0|true:1]");
@@ -838,8 +835,7 @@ bfad_drv_init(struct bfad_s *bfad)
printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n",
bfad->inst_no);
printk(KERN_WARNING
- "Not enough memory to attach all Brocade HBA ports, %s",
- "System may need more memory.\n");
+ "Not enough memory to attach all QLogic BR-series HBA ports. System may need more memory.\n");
return BFA_STATUS_FAILED;
}
@@ -1710,7 +1706,7 @@ bfad_init(void)
{
int error = 0;
- printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n",
+ pr_info("QLogic BR-series BFA FC/FCOE SCSI driver - version: %s\n",
BFAD_DRIVER_VERSION);
if (num_sgpgs > 0)
@@ -1817,6 +1813,6 @@ bfad_free_fwimg(void)
module_init(bfad_init);
module_exit(bfad_exit);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME);
-MODULE_AUTHOR("Brocade Communications Systems, Inc.");
+MODULE_DESCRIPTION("QLogic BR-series Fibre Channel HBA Driver" BFAD_PROTO_NAME);
+MODULE_AUTHOR("QLogic Corporation");
MODULE_VERSION(BFAD_DRIVER_VERSION);
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 40be670a1cbc..13db3b7bc873 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -750,65 +751,65 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
bfa_get_adapter_model(&bfad->bfa, model);
nports = bfa_get_nports(&bfad->bfa);
- if (!strcmp(model, "Brocade-425"))
+ if (!strcmp(model, "QLogic-425"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe dual port FC HBA");
- else if (!strcmp(model, "Brocade-825"))
+ "QLogic BR-series 4Gbps PCIe dual port FC HBA");
+ else if (!strcmp(model, "QLogic-825"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe dual port FC HBA");
- else if (!strcmp(model, "Brocade-42B"))
+ "QLogic BR-series 8Gbps PCIe dual port FC HBA");
+ else if (!strcmp(model, "QLogic-42B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe dual port FC HBA for HP");
- else if (!strcmp(model, "Brocade-82B"))
+ "QLogic BR-series 4Gbps PCIe dual port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-82B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe dual port FC HBA for HP");
- else if (!strcmp(model, "Brocade-1010"))
+ "QLogic BR-series 8Gbps PCIe dual port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-1010"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
- else if (!strcmp(model, "Brocade-1020"))
+ "QLogic BR-series 10Gbps single port CNA");
+ else if (!strcmp(model, "QLogic-1020"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
- else if (!strcmp(model, "Brocade-1007"))
+ "QLogic BR-series 10Gbps dual port CNA");
+ else if (!strcmp(model, "QLogic-1007"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps CNA for IBM Blade Center");
- else if (!strcmp(model, "Brocade-415"))
+ "QLogic BR-series 10Gbps CNA for IBM Blade Center");
+ else if (!strcmp(model, "QLogic-415"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe single port FC HBA");
- else if (!strcmp(model, "Brocade-815"))
+ "QLogic BR-series 4Gbps PCIe single port FC HBA");
+ else if (!strcmp(model, "QLogic-815"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe single port FC HBA");
- else if (!strcmp(model, "Brocade-41B"))
+ "QLogic BR-series 8Gbps PCIe single port FC HBA");
+ else if (!strcmp(model, "QLogic-41B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe single port FC HBA for HP");
- else if (!strcmp(model, "Brocade-81B"))
+ "QLogic BR-series 4Gbps PCIe single port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-81B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe single port FC HBA for HP");
- else if (!strcmp(model, "Brocade-804"))
+ "QLogic BR-series 8Gbps PCIe single port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-804"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps FC HBA for HP Bladesystem C-class");
- else if (!strcmp(model, "Brocade-1741"))
+ "QLogic BR-series 8Gbps FC HBA for HP Bladesystem C-class");
+ else if (!strcmp(model, "QLogic-1741"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps CNA for Dell M-Series Blade Servers");
- else if (strstr(model, "Brocade-1860")) {
+ "QLogic BR-series 10Gbps CNA for Dell M-Series Blade Servers");
+ else if (strstr(model, "QLogic-1860")) {
if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
+ "QLogic BR-series 10Gbps single port CNA");
else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA");
+ "QLogic BR-series 16Gbps PCIe single port FC HBA");
else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
+ "QLogic BR-series 10Gbps dual port CNA");
else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA");
- } else if (!strcmp(model, "Brocade-1867")) {
+ "QLogic BR-series 16Gbps PCIe dual port FC HBA");
+ } else if (!strcmp(model, "QLogic-1867")) {
if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA for IBM");
+ "QLogic BR-series 16Gbps PCIe single port FC HBA for IBM");
else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA for IBM");
+ "QLogic BR-series 16Gbps PCIe dual port FC HBA for IBM");
} else
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Invalid Model");
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index 023b9d42ad9a..d1ad0208dfe7 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h
index 90abef691585..917e140dfbcc 100644
--- a/drivers/scsi/bfa/bfad_bsg.h
+++ b/drivers/scsi/bfa/bfad_bsg.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index 74a307c0a240..8dcd8c70c7ee 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 8b97877d42cf..f9e862093a25 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -57,7 +58,7 @@
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "3.2.23.0"
+#define BFAD_DRIVER_VERSION "3.2.25.0"
#endif
#define BFAD_PROTO_NAME FCPI_NAME
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 299c6f80d460..6c805e13f8dd 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -185,7 +186,7 @@ bfad_im_info(struct Scsi_Host *shost)
memset(bfa_buf, 0, sizeof(bfa_buf));
snprintf(bfa_buf, sizeof(bfa_buf),
- "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s",
+ "QLogic BR-series FC/FCOE Adapter, hwpath: %s driver: %s",
bfad->pci_name, BFAD_DRIVER_VERSION);
return bfa_buf;
@@ -271,6 +272,19 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
cmnd->host_scribble = NULL;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ /*
+ * bfa_itnim can be NULL if the port gets disconnected and the bfa
+ * and fcs layers have cleaned up their nexus with the targets and
+ * the same has not been cleaned up by the shim
+ */
+ if (bfa_itnim == NULL) {
+ bfa_tskim_free(tskim);
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ "target reset, bfa_itnim is NULL\n");
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
memset(&scsilun, 0, sizeof(scsilun));
bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
@@ -326,6 +340,19 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
cmnd->SCp.ptr = (char *)&wq;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ /*
+ * bfa_itnim can be NULL if the port gets disconnected and the bfa
+ * and fcs layers have cleaned up their nexus with the targets and
+ * the same has not been cleaned up by the shim
+ */
+ if (bfa_itnim == NULL) {
+ bfa_tskim_free(tskim);
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ "lun reset, bfa_itnim is NULL\n");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
int_to_scsilun(cmnd->device->lun, &scsilun);
bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index f6c1023e502a..836fdc221edd 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h
index 9ef91f907dec..97600dcec649 100644
--- a/drivers/scsi/bfa/bfi.h
+++ b/drivers/scsi/bfa/bfi.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h
index 1a3fe5ad58fa..ae5bfe039fcc 100644
--- a/drivers/scsi/bfa/bfi_ms.h
+++ b/drivers/scsi/bfa/bfi_ms.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h
index 99133bcf53f9..fd5b87616e8b 100644
--- a/drivers/scsi/bfa/bfi_reg.h
+++ b/drivers/scsi/bfa/bfi_reg.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -16,7 +17,7 @@
*/
/*
- * bfi_reg.h ASIC register defines for all Brocade adapter ASICs
+ * bfi_reg.h ASIC register defines for all QLogic BR-series adapter ASICs
*/
#ifndef __BFI_REG_H__
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index c11cd193f896..5ada9268a450 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -165,6 +165,8 @@ struct afu {
struct sisl_host_map __iomem *host_map; /* MC host map */
struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */
+ struct kref mapcount;
+
ctx_hndl_t ctx_hndl; /* master's context handle */
u64 *hrrq_start;
u64 *hrrq_end;
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 1e5bf0ca81da..f6d90ce8f3b7 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -368,6 +368,7 @@ out:
no_room:
afu->read_room = true;
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
@@ -473,6 +474,16 @@ out:
return rc;
}
+static void afu_unmap(struct kref *ref)
+{
+ struct afu *afu = container_of(ref, struct afu, mapcount);
+
+ if (likely(afu->afu_map)) {
+ cxl_psa_unmap((void __iomem *)afu->afu_map);
+ afu->afu_map = NULL;
+ }
+}
+
/**
* cxlflash_driver_info() - information handler for this host driver
* @host: SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
ulong lock_flags;
short lflag = 0;
int rc = 0;
+ int kref_got = 0;
dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
"cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
goto out;
}
+ kref_get(&cfg->afu->mapcount);
+ kref_got = 1;
+
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.port_sel = port_sel;
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
}
out:
+ if (kref_got)
+ kref_put(&afu->mapcount, afu_unmap);
pr_devel("%s: returning rc=%d\n", __func__, rc);
return rc;
}
@@ -632,20 +649,36 @@ static void free_mem(struct cxlflash_cfg *cfg)
* @cfg: Internal structure associated with the host.
*
* Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ * - complete() will take care of commands we initiated (they'll be checked
+ * in as part of the cleanup that occurs after the completion)
+ *
+ * - cmd_checkin() will take care of entries that we did not initiate and that
+ * have not (and will not) complete because they are sitting on a [now stale]
+ * hardware queue
*/
static void stop_afu(struct cxlflash_cfg *cfg)
{
int i;
struct afu *afu = cfg->afu;
+ struct afu_cmd *cmd;
if (likely(afu)) {
- for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
- complete(&afu->cmd[i].cevent);
+ for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+ cmd = &afu->cmd[i];
+ complete(&cmd->cevent);
+ if (!atomic_read(&cmd->free))
+ cmd_checkin(cmd);
+ }
if (likely(afu->afu_map)) {
cxl_psa_unmap((void __iomem *)afu->afu_map);
afu->afu_map = NULL;
}
+ kref_put(&afu->mapcount, afu_unmap);
}
}
@@ -731,8 +764,8 @@ static void cxlflash_remove(struct pci_dev *pdev)
scsi_remove_host(cfg->host);
/* fall through */
case INIT_STATE_AFU:
- term_afu(cfg);
cancel_work_sync(&cfg->work_q);
+ term_afu(cfg);
case INIT_STATE_PCI:
pci_release_regions(cfg->dev);
pci_disable_device(pdev);
@@ -1108,7 +1141,7 @@ static const struct asyc_intr_info ainfo[] = {
{SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
{SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
{SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
- {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+ {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
{SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
{SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
{SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
@@ -1316,6 +1349,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
__func__, port);
cfg->lr_state = LINK_RESET_REQUIRED;
cfg->lr_port = port;
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
@@ -1336,6 +1370,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
if (info->action & SCAN_HOST) {
atomic_inc(&cfg->scan_host_needed);
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
}
@@ -1731,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
rc = -ENOMEM;
goto err1;
}
+ kref_init(&afu->mapcount);
/* No byte reverse on reading afu_version or string will be backwards */
reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,8 +1801,7 @@ out:
return rc;
err2:
- cxl_psa_unmap((void __iomem *)afu->afu_map);
- afu->afu_map = NULL;
+ kref_put(&afu->mapcount, afu_unmap);
err1:
term_mc(cfg, UNDO_START);
goto out;
@@ -2274,6 +2309,7 @@ static struct scsi_host_template driver_template = {
* Device dependent values
*/
static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS };
/*
* PCI device binding table
@@ -2281,6 +2317,8 @@ static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
static struct pci_device_id cxlflash_pci_table[] = {
{PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+ {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
{}
};
@@ -2339,6 +2377,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
scsi_scan_host(cfg->host);
+ kref_put(&afu->mapcount, afu_unmap);
}
/**
@@ -2585,8 +2624,7 @@ static struct pci_driver cxlflash_driver = {
*/
static int __init init_cxlflash(void)
{
- pr_info("%s: IBM Power CXL Flash Adapter: %s\n",
- __func__, CXLFLASH_DRIVER_DATE);
+ pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
cxlflash_list_init();
diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h
index 60324566c14f..0faed422c7f4 100644
--- a/drivers/scsi/cxlflash/main.h
+++ b/drivers/scsi/cxlflash/main.h
@@ -22,10 +22,9 @@
#define CXLFLASH_NAME "cxlflash"
#define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter"
-#define CXLFLASH_DRIVER_DATE "(August 13, 2015)"
-#define PCI_DEVICE_ID_IBM_CORSA 0x04F0
-#define CXLFLASH_SUBS_DEV_ID 0x04F0
+#define PCI_DEVICE_ID_IBM_CORSA 0x04F0
+#define PCI_DEVICE_ID_IBM_FLASH_GT 0x0600
/* Since there is only one target, make it 0 */
#define CXLFLASH_TARGET 0
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index cac2e6a50efd..f4020dbb55c3 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -1372,7 +1372,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
}
ctx = cxl_dev_context_init(cfg->dev);
- if (unlikely(IS_ERR_OR_NULL(ctx))) {
+ if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
@@ -1380,7 +1380,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
}
ctxid = cxl_process_element(ctx);
- if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+ if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
goto err2;
@@ -1500,7 +1500,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
struct afu *afu = cfg->afu;
ctx = cxl_dev_context_init(cfg->dev);
- if (unlikely(IS_ERR_OR_NULL(ctx))) {
+ if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
@@ -1508,7 +1508,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
}
ctxid = cxl_process_element(ctx);
- if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+ if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
goto err1;
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index a53f583e2d7b..50f8e9300770 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -1008,6 +1008,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
virt->last_lba = last_lba;
virt->rsrc_handle = rsrc_handle;
+ if (lli->port_sel == BOTH_PORTS)
+ virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
out:
if (likely(ctxi))
put_context(ctxi);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index cc2773b5de68..5a328bf81836 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -22,7 +22,9 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
@@ -58,8 +60,9 @@
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
-/* flags passed from user level */
+/* device handler flags */
#define ALUA_OPTIMIZE_STPG 1
+#define ALUA_RTPG_EXT_HDR_UNSUPP 2
struct alua_dh_data {
int group_id;
@@ -73,7 +76,6 @@ struct alua_dh_data {
int bufflen;
unsigned char transition_tmo;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
- int senselen;
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -83,7 +85,6 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_ALL 1
static char print_alua_state(int);
-static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
{
@@ -131,93 +132,47 @@ static struct request *get_alua_req(struct scsi_device *sdev,
}
/*
- * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
- * @sdev: sdev the command should be sent to
- */
-static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
-{
- struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
- goto done;
-
- /* Prepare the command. */
- rq->cmd[0] = INQUIRY;
- rq->cmd[1] = 1;
- rq->cmd[2] = 0x83;
- rq->cmd[4] = h->bufflen;
- rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
-
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: evpd inquiry failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
- blk_put_request(rq);
-done:
- return err;
-}
-
-/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
- bool rtpg_ext_hdr_req)
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
+ int err = 0;
rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
+ if (!rq) {
+ err = DRIVER_BUSY << 24;
goto done;
+ }
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
- if (rtpg_ext_hdr_req)
+ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
rq->cmd[1] = MI_REPORT_TARGET_PGS;
- rq->cmd[6] = (h->bufflen >> 24) & 0xff;
- rq->cmd[7] = (h->bufflen >> 16) & 0xff;
- rq->cmd[8] = (h->bufflen >> 8) & 0xff;
- rq->cmd[9] = h->bufflen & 0xff;
+ put_unaligned_be32(h->bufflen, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
+ rq->sense_len = 0;
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
+ blk_execute_rq(rq->q, NULL, rq, 1);
+ if (rq->errors)
+ err = rq->errors;
blk_put_request(rq);
done:
return err;
}
/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * stpg_endio - Evaluate SET TARGET GROUP STATES
* @sdev: the device to be evaluated
* @state: the new target group state
*
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
+ * Evaluate a SET TARGET GROUP STATES command response.
*/
static void stpg_endio(struct request *req, int error)
{
@@ -231,22 +186,21 @@ static void stpg_endio(struct request *req, int error)
goto done;
}
- if (req->sense_len > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err) {
- err = SCSI_DH_IO;
+ if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
+ /* ALUA state transition already in progress */
+ err = SCSI_DH_OK;
goto done;
}
- err = alua_check_sense(h->sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE) {
+ if (sense_hdr.sense_key == UNIT_ATTENTION) {
err = SCSI_DH_RETRY;
goto done;
}
- sdev_printk(KERN_INFO, h->sdev,
- "%s: stpg sense code: %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
+ sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
err = SCSI_DH_IO;
} else if (error)
err = SCSI_DH_IO;
@@ -284,8 +238,7 @@ static unsigned submit_stpg(struct alua_dh_data *h)
/* Prepare the data buffer */
memset(h->buff, 0, stpg_len);
h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
- h->buff[6] = (h->group_id >> 8) & 0xff;
- h->buff[7] = h->group_id & 0xff;
+ put_unaligned_be16(h->group_id, &h->buff[6]);
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
if (!rq)
@@ -294,15 +247,12 @@ static unsigned submit_stpg(struct alua_dh_data *h)
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
rq->cmd[1] = MO_SET_TARGET_PGS;
- rq->cmd[6] = (stpg_len >> 24) & 0xff;
- rq->cmd[7] = (stpg_len >> 16) & 0xff;
- rq->cmd[8] = (stpg_len >> 8) & 0xff;
- rq->cmd[9] = stpg_len & 0xff;
+ put_unaligned_be32(stpg_len, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
+ rq->sense_len = 0;
rq->end_io_data = h;
blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
@@ -316,12 +266,23 @@ static unsigned submit_stpg(struct alua_dh_data *h)
* Examine the TPGS setting of the sdev to find out if ALUA
* is supported.
*/
-static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_tpgs(struct scsi_device *sdev)
{
- int err = SCSI_DH_OK;
+ int tpgs = TPGS_MODE_NONE;
+
+ /*
+ * ALUA support for non-disk devices is fraught with
+ * difficulties, so disable it for now.
+ */
+ if (sdev->type != TYPE_DISK) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: disable for non-disk devices\n",
+ ALUA_DH_NAME);
+ return tpgs;
+ }
- h->tpgs = scsi_device_tpgs(sdev);
- switch (h->tpgs) {
+ tpgs = scsi_device_tpgs(sdev);
+ switch (tpgs) {
case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
sdev_printk(KERN_INFO, sdev,
"%s: supports implicit and explicit TPGS\n",
@@ -335,71 +296,34 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
ALUA_DH_NAME);
break;
- default:
- h->tpgs = TPGS_MODE_NONE;
+ case TPGS_MODE_NONE:
sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
ALUA_DH_NAME);
- err = SCSI_DH_DEV_UNSUPP;
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: unsupported TPGS setting %d\n",
+ ALUA_DH_NAME, tpgs);
+ tpgs = TPGS_MODE_NONE;
break;
}
- return err;
+ return tpgs;
}
/*
- * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
* @sdev: device to be checked
*
* Extract the relative target port and the target port group
* descriptor from the list of identificators.
*/
-static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int len;
- unsigned err;
- unsigned char *d;
-
- retry:
- err = submit_vpd_inquiry(sdev, h);
-
- if (err != SCSI_DH_OK)
- return err;
-
- /* Check if vpd page exceeds initial buffer */
- len = (h->buff[2] << 8) + h->buff[3] + 4;
- if (len > h->bufflen) {
- /* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
- sdev_printk(KERN_WARNING, sdev,
- "%s: kmalloc buffer failed\n",
- ALUA_DH_NAME);
- /* Temporary failure, bypass */
- return SCSI_DH_DEV_TEMP_BUSY;
- }
- goto retry;
- }
+ int rel_port = -1, group_id;
- /*
- * Now look for the correct descriptor.
- */
- d = h->buff + 4;
- while (d < h->buff + len) {
- switch (d[1] & 0xf) {
- case 0x4:
- /* Relative target port */
- h->rel_port = (d[6] << 8) + d[7];
- break;
- case 0x5:
- /* Target port group */
- h->group_id = (d[6] << 8) + d[7];
- break;
- default:
- break;
- }
- d += d[3] + 4;
- }
-
- if (h->group_id == -1) {
+ group_id = scsi_vpd_tpg_id(sdev, &rel_port);
+ if (group_id < 0) {
/*
* Internal error; TPGS supported but required
* VPD identification descriptors not present.
@@ -408,16 +332,16 @@ static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev,
"%s: No target port descriptors found\n",
ALUA_DH_NAME);
- h->state = TPGS_STATE_OPTIMIZED;
- h->tpgs = TPGS_MODE_NONE;
- err = SCSI_DH_DEV_UNSUPP;
- } else {
- sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ return SCSI_DH_DEV_UNSUPP;
}
+ h->state = TPGS_STATE_OPTIMIZED;
+ h->group_id = group_id;
- return err;
+ sdev_printk(KERN_INFO, sdev,
+ "%s: port group %02x rel port %02x\n",
+ ALUA_DH_NAME, h->group_id, h->rel_port);
+
+ return 0;
}
static char print_alua_state(int state)
@@ -452,28 +376,6 @@ static int alua_check_sense(struct scsi_device *sdev,
* LUN Not Accessible - ALUA state transition
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
- /*
- * LUN Not Accessible -- Target port in standby state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
- /*
- * LUN Not Accessible -- Target port in unavailable state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
- /*
- * LUN Not Ready -- Offline
- */
- return SUCCESS;
- if (sdev->allow_restart &&
- sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02)
- /*
- * if the device is not started, we need to wake
- * the error handler to start the motor
- */
- return FAILED;
break;
case UNIT_ATTENTION:
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
@@ -533,8 +435,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0;
unsigned char *ucp;
- unsigned err;
- bool rtpg_ext_hdr_req = 1;
+ unsigned err, retval;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
@@ -545,13 +446,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
-
- if (err == SCSI_DH_IO && h->senselen > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err)
+ retval = submit_rtpg(sdev, h);
+ if (retval) {
+ if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: rtpg failed, result %d\n",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_BUSY)
+ return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
+ }
/*
* submit_rtpg() has failed on existing arrays
@@ -561,27 +466,34 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (rtpg_ext_hdr_req == 1 &&
+ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- rtpg_ext_hdr_req = 0;
+ h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
-
- err = alua_check_sense(sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
+ /*
+ * Retry on ALUA state transition or if any
+ * UNIT ATTENTION occurred.
+ */
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ err = SCSI_DH_RETRY;
+ else if (sense_hdr.sense_key == UNIT_ATTENTION)
+ err = SCSI_DH_RETRY;
+ if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
goto retry;
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg sense code %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
- err = SCSI_DH_IO;
+ }
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ return SCSI_DH_IO;
}
- if (err != SCSI_DH_OK)
- return err;
- len = (h->buff[0] << 24) + (h->buff[1] << 16) +
- (h->buff[2] << 8) + h->buff[3] + 4;
+ len = get_unaligned_be32(&h->buff[0]) + 4;
if (len > h->bufflen) {
/* Resubmit with the correct length */
@@ -616,7 +528,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
k < len;
k += off, ucp += off) {
- if (h->group_id == (ucp[2] << 8) + ucp[3]) {
+ if (h->group_id == get_unaligned_be16(&ucp[2])) {
h->state = ucp[0] & 0x0f;
h->pref = ucp[0] >> 7;
valid_states = ucp[1];
@@ -674,13 +586,13 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
*/
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err;
+ int err = SCSI_DH_DEV_UNSUPP;
- err = alua_check_tpgs(sdev, h);
- if (err != SCSI_DH_OK)
+ h->tpgs = alua_check_tpgs(sdev);
+ if (h->tpgs == TPGS_MODE_NONE)
goto out;
- err = alua_vpd_inquiry(sdev, h);
+ err = alua_check_vpd(sdev, h);
if (err != SCSI_DH_OK)
goto out;
diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
new file mode 100644
index 000000000000..37a0c7156087
--- /dev/null
+++ b/drivers/scsi/hisi_sas/Kconfig
@@ -0,0 +1,6 @@
+config SCSI_HISI_SAS
+ tristate "HiSilicon SAS"
+ select SCSI_SAS_LIBSAS
+ select BLK_DEV_INTEGRITY
+ help
+ This driver supports HiSilicon's SAS HBA
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
new file mode 100644
index 000000000000..3e70eae81343
--- /dev/null
+++ b/drivers/scsi/hisi_sas/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
new file mode 100644
index 000000000000..5af2e4187f01
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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 _HISI_SAS_H_
+#define _HISI_SAS_H_
+
+#include <linux/dmapool.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <scsi/libsas.h>
+
+#define DRV_VERSION "v1.0"
+
+#define HISI_SAS_MAX_PHYS 9
+#define HISI_SAS_MAX_QUEUES 32
+#define HISI_SAS_QUEUE_SLOTS 512
+#define HISI_SAS_MAX_ITCT_ENTRIES 4096
+#define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
+#define HISI_SAS_COMMAND_ENTRIES 8192
+
+#define HISI_SAS_STATUS_BUF_SZ \
+ (sizeof(struct hisi_sas_err_record) + 1024)
+#define HISI_SAS_COMMAND_TABLE_SZ \
+ (((sizeof(union hisi_sas_command_table)+3)/4)*4)
+
+#define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
+#define HISI_SAS_MAX_SMP_RESP_SZ 1028
+
+struct hisi_hba;
+
+enum {
+ PORT_TYPE_SAS = (1U << 1),
+ PORT_TYPE_SATA = (1U << 0),
+};
+
+enum dev_status {
+ HISI_SAS_DEV_NORMAL,
+ HISI_SAS_DEV_EH,
+};
+
+enum hisi_sas_dev_type {
+ HISI_SAS_DEV_TYPE_STP = 0,
+ HISI_SAS_DEV_TYPE_SSP,
+ HISI_SAS_DEV_TYPE_SATA,
+};
+
+struct hisi_sas_phy {
+ struct hisi_hba *hisi_hba;
+ struct hisi_sas_port *port;
+ struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ struct timer_list timer;
+ struct work_struct phyup_ws;
+ u64 port_id; /* from hw */
+ u64 dev_sas_addr;
+ u64 phy_type;
+ u64 frame_rcvd_size;
+ u8 frame_rcvd[32];
+ u8 phy_attached;
+ u8 reserved[3];
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate;
+};
+
+struct hisi_sas_port {
+ struct asd_sas_port sas_port;
+ u8 port_attached;
+ u8 id; /* from hw */
+ struct list_head list;
+};
+
+struct hisi_sas_cq {
+ struct hisi_hba *hisi_hba;
+ int id;
+};
+
+struct hisi_sas_device {
+ enum sas_device_type dev_type;
+ struct hisi_hba *hisi_hba;
+ struct domain_device *sas_device;
+ u64 attached_phy;
+ u64 device_id;
+ u64 running_req;
+ u8 dev_status;
+};
+
+struct hisi_sas_slot {
+ struct list_head entry;
+ struct sas_task *task;
+ struct hisi_sas_port *port;
+ u64 n_elem;
+ int dlvry_queue;
+ int dlvry_queue_slot;
+ int cmplt_queue;
+ int cmplt_queue_slot;
+ int idx;
+ void *cmd_hdr;
+ dma_addr_t cmd_hdr_dma;
+ void *status_buffer;
+ dma_addr_t status_buffer_dma;
+ void *command_table;
+ dma_addr_t command_table_dma;
+ struct hisi_sas_sge_page *sge_page;
+ dma_addr_t sge_page_dma;
+};
+
+struct hisi_sas_tmf_task {
+ u8 tmf;
+ u16 tag_of_task_to_be_managed;
+};
+
+struct hisi_sas_hw {
+ int (*hw_init)(struct hisi_hba *hisi_hba);
+ void (*setup_itct)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *device);
+ void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
+ int (*get_free_slot)(struct hisi_hba *hisi_hba, int *q, int *s);
+ void (*start_delivery)(struct hisi_hba *hisi_hba);
+ int (*prep_ssp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf);
+ int (*prep_smp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot);
+ int (*slot_complete)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int abort);
+ void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*free_device)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *dev);
+ int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
+ int complete_hdr_size;
+};
+
+struct hisi_hba {
+ /* This must be the first element, used by SHOST_TO_SAS_HA */
+ struct sas_ha_struct *p;
+
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct regmap *ctrl;
+ u32 ctrl_reset_reg;
+ u32 ctrl_reset_sts_reg;
+ u32 ctrl_clock_ena_reg;
+ u8 sas_addr[SAS_ADDR_SIZE];
+
+ int n_phy;
+ int scan_finished;
+ spinlock_t lock;
+
+ struct timer_list timer;
+ struct workqueue_struct *wq;
+
+ int slot_index_count;
+ unsigned long *slot_index_tags;
+
+ /* SCSI/SAS glue */
+ struct sas_ha_struct sha;
+ struct Scsi_Host *shost;
+
+ struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS];
+ struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
+
+ int queue_count;
+ int queue;
+ struct hisi_sas_slot *slot_prep;
+
+ struct dma_pool *sge_page_pool;
+ struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES];
+ struct dma_pool *command_table_pool;
+ struct dma_pool *status_buffer_pool;
+ struct hisi_sas_cmd_hdr *cmd_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t cmd_hdr_dma[HISI_SAS_MAX_QUEUES];
+ void *complete_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t complete_hdr_dma[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_initial_fis *initial_fis;
+ dma_addr_t initial_fis_dma;
+ struct hisi_sas_itct *itct;
+ dma_addr_t itct_dma;
+ struct hisi_sas_iost *iost;
+ dma_addr_t iost_dma;
+ struct hisi_sas_breakpoint *breakpoint;
+ dma_addr_t breakpoint_dma;
+ struct hisi_sas_breakpoint *sata_breakpoint;
+ dma_addr_t sata_breakpoint_dma;
+ struct hisi_sas_slot *slot_info;
+ const struct hisi_sas_hw *hw; /* Low level hw interface */
+};
+
+/* Generic HW DMA host memory structures */
+/* Delivery queue header */
+struct hisi_sas_cmd_hdr {
+ /* dw0 */
+ __le32 dw0;
+
+ /* dw1 */
+ __le32 dw1;
+
+ /* dw2 */
+ __le32 dw2;
+
+ /* dw3 */
+ __le32 transfer_tags;
+
+ /* dw4 */
+ __le32 data_transfer_len;
+
+ /* dw5 */
+ __le32 first_burst_num;
+
+ /* dw6 */
+ __le32 sg_len;
+
+ /* dw7 */
+ __le32 dw7;
+
+ /* dw8-9 */
+ __le64 cmd_table_addr;
+
+ /* dw10-11 */
+ __le64 sts_buffer_addr;
+
+ /* dw12-13 */
+ __le64 prd_table_addr;
+
+ /* dw14-15 */
+ __le64 dif_prd_table_addr;
+};
+
+struct hisi_sas_itct {
+ __le64 qw0;
+ __le64 sas_addr;
+ __le64 qw2;
+ __le64 qw3;
+ __le64 qw4;
+ __le64 qw_sata_ncq0_3;
+ __le64 qw_sata_ncq7_4;
+ __le64 qw_sata_ncq11_8;
+ __le64 qw_sata_ncq15_12;
+ __le64 qw_sata_ncq19_16;
+ __le64 qw_sata_ncq23_20;
+ __le64 qw_sata_ncq27_24;
+ __le64 qw_sata_ncq31_28;
+ __le64 qw_non_ncq_iptt;
+ __le64 qw_rsvd0;
+ __le64 qw_rsvd1;
+};
+
+struct hisi_sas_iost {
+ __le64 qw0;
+ __le64 qw1;
+ __le64 qw2;
+ __le64 qw3;
+};
+
+struct hisi_sas_err_record {
+ /* dw0 */
+ __le32 dma_err_type;
+
+ /* dw1 */
+ __le32 trans_tx_fail_type;
+
+ /* dw2 */
+ __le32 trans_rx_fail_type;
+
+ /* dw3 */
+ u32 rsvd;
+};
+
+struct hisi_sas_initial_fis {
+ struct hisi_sas_err_record err_record;
+ struct dev_to_host_fis fis;
+ u32 rsvd[3];
+};
+
+struct hisi_sas_breakpoint {
+ u8 data[128]; /*io128 byte*/
+};
+
+struct hisi_sas_sge {
+ __le64 addr;
+ __le32 page_ctrl_0;
+ __le32 page_ctrl_1;
+ __le32 data_len;
+ __le32 data_off;
+};
+
+struct hisi_sas_command_table_smp {
+ u8 bytes[44];
+};
+
+struct hisi_sas_command_table_stp {
+ struct host_to_dev_fis command_fis;
+ u8 dummy[12];
+ u8 atapi_cdb[ATAPI_CDB_LEN];
+};
+
+#define HISI_SAS_SGE_PAGE_CNT SCSI_MAX_SG_SEGMENTS
+struct hisi_sas_sge_page {
+ struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
+};
+
+struct hisi_sas_command_table_ssp {
+ struct ssp_frame_hdr hdr;
+ union {
+ struct {
+ struct ssp_command_iu task;
+ u32 prot[6];
+ };
+ struct ssp_tmf_iu ssp_task;
+ struct xfer_rdy_iu xfer_rdy;
+ struct ssp_response_iu ssp_res;
+ } u;
+};
+
+union hisi_sas_command_table {
+ struct hisi_sas_command_table_ssp ssp;
+ struct hisi_sas_command_table_smp smp;
+ struct hisi_sas_command_table_stp stp;
+};
+extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+extern int hisi_sas_remove(struct platform_device *pdev);
+
+extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy);
+extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot);
+#endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
new file mode 100644
index 000000000000..99b1950d751c
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -0,0 +1,1358 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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 "hisi_sas.h"
+#define DRV_NAME "hisi_sas"
+
+#define DEV_IS_EXPANDER(type) \
+ ((type == SAS_EDGE_EXPANDER_DEVICE) || \
+ (type == SAS_FANOUT_EXPANDER_DEVICE))
+
+#define DEV_IS_GONE(dev) \
+ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
+
+static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+{
+ return device->port->ha->lldd_ha;
+}
+
+static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ clear_bit(slot_idx, bitmap);
+}
+
+static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ hisi_sas_slot_index_clear(hisi_hba, slot_idx);
+}
+
+static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ set_bit(slot_idx, bitmap);
+}
+
+static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, int *slot_idx)
+{
+ unsigned int index;
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ index = find_first_zero_bit(bitmap, hisi_hba->slot_index_count);
+ if (index >= hisi_hba->slot_index_count)
+ return -SAS_QUEUE_FULL;
+ hisi_sas_slot_index_set(hisi_hba, index);
+ *slot_idx = index;
+ return 0;
+}
+
+static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->slot_index_count; ++i)
+ hisi_sas_slot_index_clear(hisi_hba, i);
+}
+
+void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ if (!slot->task)
+ return;
+
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ dma_unmap_sg(dev, task->scatter, slot->n_elem,
+ task->data_dir);
+
+ if (slot->command_table)
+ dma_pool_free(hisi_hba->command_table_pool,
+ slot->command_table, slot->command_table_dma);
+
+ if (slot->status_buffer)
+ dma_pool_free(hisi_hba->status_buffer_pool,
+ slot->status_buffer, slot->status_buffer_dma);
+
+ if (slot->sge_page)
+ dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+ slot->sge_page_dma);
+
+ list_del_init(&slot->entry);
+ task->lldd_task = NULL;
+ slot->task = NULL;
+ slot->port = NULL;
+ hisi_sas_slot_index_free(hisi_hba, slot->idx);
+ memset(slot, 0, sizeof(*slot));
+}
+EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
+
+static int hisi_sas_task_prep_smp(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ return hisi_hba->hw->prep_smp(hisi_hba, slot);
+}
+
+static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf);
+}
+
+static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+ int is_tmf, struct hisi_sas_tmf_task *tmf,
+ int *pass)
+{
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_cmd_hdr *cmd_hdr_base;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+ if (!device->port) {
+ struct task_status_struct *ts = &task->task_status;
+
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ /*
+ * libsas will use dev->port, should
+ * not call task_done for sata
+ */
+ if (device->dev_type != SAS_SATA_DEV)
+ task->task_done(task);
+ return 0;
+ }
+
+ if (DEV_IS_GONE(sas_dev)) {
+ if (sas_dev)
+ dev_info(dev, "task prep: device %llu not ready\n",
+ sas_dev->device_id);
+ else
+ dev_info(dev, "task prep: device %016llx not ready\n",
+ SAS_ADDR(device->sas_addr));
+
+ rc = SAS_PHY_DOWN;
+ return rc;
+ }
+ port = device->port->lldd_port;
+ if (port && !port->port_attached && !tmf) {
+ if (sas_protocol_ata(task->task_proto)) {
+ struct task_status_struct *ts = &task->task_status;
+
+ dev_info(dev,
+ "task prep: SATA/STP port%d not attach device\n",
+ device->port->id);
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PHY_DOWN;
+ task->task_done(task);
+ } else {
+ struct task_status_struct *ts = &task->task_status;
+
+ dev_info(dev,
+ "task prep: SAS port%d does not attach device\n",
+ device->port->id);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ task->task_done(task);
+ }
+ return 0;
+ }
+
+ if (!sas_protocol_ata(task->task_proto)) {
+ if (task->num_scatter) {
+ n_elem = dma_map_sg(dev, task->scatter,
+ task->num_scatter, task->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto prep_out;
+ }
+ }
+ } else
+ n_elem = task->num_scatter;
+
+ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+ if (rc)
+ goto err_out;
+ rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
+ &dlvry_queue_slot);
+ if (rc)
+ goto err_out_tag;
+
+ slot = &hisi_hba->slot_info[slot_idx];
+ memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+ slot->idx = slot_idx;
+ slot->n_elem = n_elem;
+ slot->dlvry_queue = dlvry_queue;
+ slot->dlvry_queue_slot = dlvry_queue_slot;
+ cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+ slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
+ slot->task = task;
+ slot->port = port;
+ task->lldd_task = slot;
+
+ slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
+ GFP_ATOMIC,
+ &slot->status_buffer_dma);
+ if (!slot->status_buffer) {
+ rc = -ENOMEM;
+ goto err_out_slot_buf;
+ }
+ memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ);
+
+ slot->command_table = dma_pool_alloc(hisi_hba->command_table_pool,
+ GFP_ATOMIC,
+ &slot->command_table_dma);
+ if (!slot->command_table) {
+ rc = -ENOMEM;
+ goto err_out_status_buf;
+ }
+ memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ);
+ memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = hisi_sas_task_prep_smp(hisi_hba, slot);
+ break;
+ case SAS_PROTOCOL_SSP:
+ rc = hisi_sas_task_prep_ssp(hisi_hba, slot, is_tmf, tmf);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ default:
+ dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
+ task->task_proto);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc) {
+ dev_err(dev, "task prep: rc = 0x%x\n", rc);
+ if (slot->sge_page)
+ goto err_out_sge;
+ goto err_out_command_table;
+ }
+
+ list_add_tail(&slot->entry, &port->list);
+ spin_lock(&task->task_state_lock);
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&task->task_state_lock);
+
+ hisi_hba->slot_prep = slot;
+
+ sas_dev->running_req++;
+ ++(*pass);
+
+ return 0;
+
+err_out_sge:
+ dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+ slot->sge_page_dma);
+err_out_command_table:
+ dma_pool_free(hisi_hba->command_table_pool, slot->command_table,
+ slot->command_table_dma);
+err_out_status_buf:
+ dma_pool_free(hisi_hba->status_buffer_pool, slot->status_buffer,
+ slot->status_buffer_dma);
+err_out_slot_buf:
+ /* Nothing to be done */
+err_out_tag:
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
+err_out:
+ dev_err(dev, "task prep: failed[%d]!\n", rc);
+ if (!sas_protocol_ata(task->task_proto))
+ if (n_elem)
+ dma_unmap_sg(dev, task->scatter, n_elem,
+ task->data_dir);
+prep_out:
+ return rc;
+}
+
+static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+ int is_tmf, struct hisi_sas_tmf_task *tmf)
+{
+ u32 rc;
+ u32 pass = 0;
+ unsigned long flags;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ /* protect task_prep and start_delivery sequence */
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
+ if (rc)
+ dev_err(dev, "task exec: failed[%d]!\n", rc);
+
+ if (likely(pass))
+ hisi_hba->hw->start_delivery(hisi_hba);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ return rc;
+}
+
+static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha;
+
+ if (!phy->phy_attached)
+ return;
+
+ sas_ha = &hisi_hba->sha;
+ sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+
+ if (sas_phy->phy) {
+ struct sas_phy *sphy = sas_phy->phy;
+
+ sphy->negotiated_linkrate = sas_phy->linkrate;
+ sphy->minimum_linkrate = phy->minimum_linkrate;
+ sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sphy->maximum_linkrate = phy->maximum_linkrate;
+ }
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ struct sas_identify_frame *id;
+
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ /*Nothing*/
+ }
+
+ sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+ sas_ha->notify_port_event(sas_phy, PORTE_BYTES_DMAED);
+}
+
+static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
+{
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct hisi_sas_device *sas_dev = NULL;
+ int i;
+
+ spin_lock(&hisi_hba->lock);
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
+ hisi_hba->devices[i].device_id = i;
+ sas_dev = &hisi_hba->devices[i];
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ sas_dev->dev_type = device->dev_type;
+ sas_dev->hisi_hba = hisi_hba;
+ sas_dev->sas_device = device;
+ break;
+ }
+ }
+ spin_unlock(&hisi_hba->lock);
+
+ return sas_dev;
+}
+
+static int hisi_sas_dev_found(struct domain_device *device)
+{
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ sas_dev = hisi_sas_alloc_dev(device);
+ if (!sas_dev) {
+ dev_err(dev, "fail alloc dev: max support %d devices\n",
+ HISI_SAS_MAX_DEVICES);
+ return -EINVAL;
+ }
+
+ device->lldd_dev = sas_dev;
+ hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ int phy_no;
+ u8 phy_num = parent_dev->ex_dev.num_phys;
+ struct ex_phy *phy;
+
+ for (phy_no = 0; phy_no < phy_num; phy_no++) {
+ phy = &parent_dev->ex_dev.ex_phy[phy_no];
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(device->sas_addr)) {
+ sas_dev->attached_phy = phy_no;
+ break;
+ }
+ }
+
+ if (phy_no == phy_num) {
+ dev_info(dev, "dev found: no attached "
+ "dev:%016llx at ex:%016llx\n",
+ SAS_ADDR(device->sas_addr),
+ SAS_ADDR(parent_dev->sas_addr));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void hisi_sas_scan_start(struct Scsi_Host *shost)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; ++i)
+ hisi_sas_bytes_dmaed(hisi_hba, i);
+
+ hisi_hba->scan_finished = 1;
+}
+
+static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+
+ if (hisi_hba->scan_finished == 0)
+ return 0;
+
+ sas_drain_work(sha);
+ return 1;
+}
+
+static void hisi_sas_phyup_work(struct work_struct *work)
+{
+ struct hisi_sas_phy *phy =
+ container_of(work, struct hisi_sas_phy, phyup_ws);
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int phy_no = sas_phy->id;
+
+ hisi_hba->hw->sl_notify(hisi_hba, phy_no); /* This requires a sleep */
+ hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+}
+
+static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ phy->hisi_hba = hisi_hba;
+ phy->port = NULL;
+ init_timer(&phy->timer);
+ sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTOCOL_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+ sas_phy->id = phy_no;
+ sas_phy->sas_addr = &hisi_hba->sas_addr[0];
+ sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+ sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
+ sas_phy->lldd_phy = phy;
+
+ INIT_WORK(&phy->phyup_ws, hisi_sas_phyup_work);
+}
+
+static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct asd_sas_port *sas_port = sas_phy->port;
+ struct hisi_sas_port *port = &hisi_hba->port[sas_phy->id];
+ unsigned long flags;
+
+ if (!sas_port)
+ return;
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ port->port_attached = 1;
+ port->id = phy->port_id;
+ phy->port = port;
+ sas_port->lldd_port = port;
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+}
+
+static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no,
+ struct domain_device *device)
+{
+ struct hisi_sas_phy *phy;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot, *slot2;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ phy = &hisi_hba->phy[phy_no];
+ port = phy->port;
+ if (!port)
+ return;
+
+ list_for_each_entry_safe(slot, slot2, &port->list, entry) {
+ struct sas_task *task;
+
+ task = slot->task;
+ if (device && task->dev != device)
+ continue;
+
+ dev_info(dev, "Release slot [%d:%d], task [%p]:\n",
+ slot->dlvry_queue, slot->dlvry_queue_slot, task);
+ hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+ }
+}
+
+static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy)
+{
+ struct domain_device *device;
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct asd_sas_port *sas_port = sas_phy->port;
+
+ list_for_each_entry(device, &sas_port->dev_list, dev_list_node)
+ hisi_sas_do_release_task(phy->hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
+ struct domain_device *device)
+{
+ struct asd_sas_port *port = device->port;
+ struct asd_sas_phy *sas_phy;
+
+ list_for_each_entry(sas_phy, &port->phy_list, port_phy_el)
+ hisi_sas_do_release_task(hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_dev_gone(struct domain_device *device)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 dev_id = sas_dev->device_id;
+
+ dev_info(dev, "found dev[%lld:%x] is gone\n",
+ sas_dev->device_id, sas_dev->dev_type);
+
+ hisi_hba->hw->free_device(hisi_hba, sas_dev);
+ device->lldd_dev = NULL;
+ memset(sas_dev, 0, sizeof(*sas_dev));
+ sas_dev->device_id = dev_id;
+ sas_dev->dev_type = SAS_PHY_UNUSED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+}
+
+static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
+{
+ return hisi_sas_task_exec(task, gfp_flags, 0, NULL);
+}
+
+static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ int phy_no = sas_phy->id;
+
+ switch (func) {
+ case PHY_FUNC_HARD_RESET:
+ hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_LINK_RESET:
+ hisi_hba->hw->phy_enable(hisi_hba, phy_no);
+ hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_DISABLE:
+ hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_SET_LINK_RATE:
+ case PHY_FUNC_RELEASE_SPINUP_HOLD:
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static void hisi_sas_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->slow_task->timer))
+ return;
+ complete(&task->slow_task->completion);
+}
+
+static void hisi_sas_tmf_timedout(unsigned long data)
+{
+ struct sas_task *task = (struct sas_task *)data;
+
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ complete(&task->slow_task->completion);
+}
+
+#define TASK_TIMEOUT 20
+#define TASK_RETRY 3
+static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
+ void *parameter, u32 para_len,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct sas_task *task;
+ int res, retry;
+
+ for (retry = 0; retry < TASK_RETRY; retry++) {
+ task = sas_alloc_slow_task(GFP_KERNEL);
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = device;
+ task->task_proto = device->tproto;
+
+ memcpy(&task->ssp_task, parameter, para_len);
+ task->task_done = hisi_sas_task_done;
+
+ task->slow_task->timer.data = (unsigned long) task;
+ task->slow_task->timer.function = hisi_sas_tmf_timedout;
+ task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ;
+ add_timer(&task->slow_task->timer);
+
+ res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
+
+ if (res) {
+ del_timer(&task->slow_task->timer);
+ dev_err(dev, "abort tmf: executing internal task failed: %d\n",
+ res);
+ goto ex_err;
+ }
+
+ wait_for_completion(&task->slow_task->completion);
+ res = TMF_RESP_FUNC_FAILED;
+ /* Even TMF timed out, return direct. */
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ dev_err(dev, "abort tmf: TMF task[%d] timeout\n",
+ tmf->tag_of_task_to_be_managed);
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot =
+ task->lldd_task;
+
+ hisi_sas_slot_task_free(hisi_hba,
+ task, slot);
+ }
+
+ goto ex_err;
+ }
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAM_STAT_GOOD) {
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_UNDERRUN) {
+ /* no error, but return the number of bytes of
+ * underrun
+ */
+ dev_warn(dev, "abort tmf: task to dev %016llx "
+ "resp: 0x%x sts 0x%x underrun\n",
+ SAS_ADDR(device->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat);
+ res = task->task_status.residual;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_OVERRUN) {
+ dev_warn(dev, "abort tmf: blocked task error\n");
+ res = -EMSGSIZE;
+ break;
+ }
+
+ dev_warn(dev, "abort tmf: task to dev "
+ "%016llx resp: 0x%x status 0x%x\n",
+ SAS_ADDR(device->sas_addr), task->task_status.resp,
+ task->task_status.stat);
+ sas_free_task(task);
+ task = NULL;
+ }
+ex_err:
+ WARN_ON(retry == TASK_RETRY);
+ sas_free_task(task);
+ return res;
+}
+
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+ u8 *lun, struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_ssp_task ssp_task;
+
+ if (!(device->tproto & SAS_PROTOCOL_SSP))
+ return TMF_RESP_FUNC_ESUPP;
+
+ memcpy(ssp_task.LUN, lun, 8);
+
+ return hisi_sas_exec_internal_tmf_task(device, &ssp_task,
+ sizeof(ssp_task), tmf);
+}
+
+static int hisi_sas_abort_task(struct sas_task *task)
+{
+ struct scsi_lun lun;
+ struct hisi_sas_tmf_task tmf_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+
+ if (!sas_dev) {
+ dev_warn(dev, "Device has been removed\n");
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ sas_dev->dev_status = HISI_SAS_DEV_EH;
+ if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_ABORT_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
+ &tmf_task);
+
+ /* if successful, clear the task and callback forwards.*/
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot;
+
+ slot = &hisi_hba->slot_info
+ [tmf_task.tag_of_task_to_be_managed];
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
+ }
+
+ } else if (task->task_proto & SAS_PROTOCOL_SATA ||
+ task->task_proto & SAS_PROTOCOL_STP) {
+ if (task->dev->dev_type == SAS_SATA_DEV) {
+ struct hisi_slot_info *slot = task->lldd_task;
+
+ dev_notice(dev, "abort task: hba=%p task=%p slot=%p\n",
+ hisi_hba, task, slot);
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+
+ }
+
+out:
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+ dev_notice(dev, "abort task: rc=%d\n", rc);
+ return rc;
+}
+
+static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
+{
+ struct hisi_sas_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ tmf_task.tmf = TMF_ABORT_TASK_SET;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+ return rc;
+}
+
+static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct hisi_sas_tmf_task tmf_task;
+
+ tmf_task.tmf = TMF_CLEAR_ACA;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+ return rc;
+}
+
+static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
+{
+ struct sas_phy *phy = sas_get_local_phy(device);
+ int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
+ (device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
+ rc = sas_phy_reset(phy, reset_type);
+ sas_put_local_phy(phy);
+ msleep(2000);
+ return rc;
+}
+
+static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ if (sas_dev->dev_status != HISI_SAS_DEV_EH)
+ return TMF_RESP_FUNC_FAILED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+
+ rc = hisi_sas_debug_I_T_nexus_reset(device);
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_release_task(hisi_hba, device);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ return 0;
+}
+
+static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+{
+ struct hisi_sas_tmf_task tmf_task;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ tmf_task.tmf = TMF_LU_RESET;
+ sas_dev->dev_status = HISI_SAS_DEV_EH;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_release_task(hisi_hba, device);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
+
+ /* If failed, fall-through I_T_Nexus reset */
+ dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
+ sas_dev->device_id, rc);
+ return rc;
+}
+
+static int hisi_sas_query_task(struct sas_task *task)
+{
+ struct scsi_lun lun;
+ struct hisi_sas_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_QUERY_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ rc = hisi_sas_debug_issue_ssp_tmf(device,
+ lun.scsi_lun,
+ &tmf_task);
+ switch (rc) {
+ /* The task is still in Lun, release it then */
+ case TMF_RESP_FUNC_SUCC:
+ /* The task is not in Lun or failed, reset the phy */
+ case TMF_RESP_FUNC_FAILED:
+ case TMF_RESP_FUNC_COMPLETE:
+ break;
+ }
+ }
+ return rc;
+}
+
+static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
+{
+ hisi_sas_port_notify_formed(sas_phy);
+}
+
+static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy)
+{
+ hisi_sas_port_notify_deformed(sas_phy);
+}
+
+static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
+{
+ phy->phy_attached = 0;
+ phy->phy_type = 0;
+ phy->port = NULL;
+}
+
+void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+
+ if (rdy) {
+ /* Phy down but ready */
+ hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+ hisi_sas_port_notify_formed(sas_phy);
+ } else {
+ struct hisi_sas_port *port = phy->port;
+
+ /* Phy down and not ready */
+ sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+ sas_phy_disconnected(sas_phy);
+
+ if (port) {
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ int port_id = port->id;
+
+ if (!hisi_hba->hw->get_wideport_bitmap(hisi_hba,
+ port_id))
+ port->port_attached = 0;
+ } else if (phy->phy_type & PORT_TYPE_SATA)
+ port->port_attached = 0;
+ }
+ hisi_sas_phy_disconnected(phy);
+ }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
+
+static struct scsi_transport_template *hisi_sas_stt;
+
+static struct scsi_host_template hisi_sas_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .scan_finished = hisi_sas_scan_finished,
+ .scan_start = hisi_sas_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+};
+
+static struct sas_domain_function_template hisi_sas_transport_ops = {
+ .lldd_dev_found = hisi_sas_dev_found,
+ .lldd_dev_gone = hisi_sas_dev_gone,
+ .lldd_execute_task = hisi_sas_queue_command,
+ .lldd_control_phy = hisi_sas_control_phy,
+ .lldd_abort_task = hisi_sas_abort_task,
+ .lldd_abort_task_set = hisi_sas_abort_task_set,
+ .lldd_clear_aca = hisi_sas_clear_aca,
+ .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset,
+ .lldd_lu_reset = hisi_sas_lu_reset,
+ .lldd_query_task = hisi_sas_query_task,
+ .lldd_port_formed = hisi_sas_port_formed,
+ .lldd_port_deformed = hisi_sas_port_deformed,
+};
+
+static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+{
+ int i, s;
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+
+ spin_lock_init(&hisi_hba->lock);
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_init(hisi_hba, i);
+ hisi_hba->port[i].port_attached = 0;
+ hisi_hba->port[i].id = -1;
+ INIT_LIST_HEAD(&hisi_hba->port[i].list);
+ }
+
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED;
+ hisi_hba->devices[i].device_id = i;
+ hisi_hba->devices[i].dev_status = HISI_SAS_DEV_NORMAL;
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+
+ /* Completion queue structure */
+ cq->id = i;
+ cq->hisi_hba = hisi_hba;
+
+ /* Delivery queue */
+ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s,
+ &hisi_hba->cmd_hdr_dma[i], GFP_KERNEL);
+ if (!hisi_hba->cmd_hdr[i])
+ goto err_out;
+ memset(hisi_hba->cmd_hdr[i], 0, s);
+
+ /* Completion queue */
+ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ hisi_hba->complete_hdr[i] = dma_alloc_coherent(dev, s,
+ &hisi_hba->complete_hdr_dma[i], GFP_KERNEL);
+ if (!hisi_hba->complete_hdr[i])
+ goto err_out;
+ memset(hisi_hba->complete_hdr[i], 0, s);
+ }
+
+ s = HISI_SAS_STATUS_BUF_SZ;
+ hisi_hba->status_buffer_pool = dma_pool_create("status_buffer",
+ dev, s, 16, 0);
+ if (!hisi_hba->status_buffer_pool)
+ goto err_out;
+
+ s = HISI_SAS_COMMAND_TABLE_SZ;
+ hisi_hba->command_table_pool = dma_pool_create("command_table",
+ dev, s, 16, 0);
+ if (!hisi_hba->command_table_pool)
+ goto err_out;
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ hisi_hba->itct = dma_alloc_coherent(dev, s, &hisi_hba->itct_dma,
+ GFP_KERNEL);
+ if (!hisi_hba->itct)
+ goto err_out;
+
+ memset(hisi_hba->itct, 0, s);
+
+ hisi_hba->slot_info = devm_kcalloc(dev, HISI_SAS_COMMAND_ENTRIES,
+ sizeof(struct hisi_sas_slot),
+ GFP_KERNEL);
+ if (!hisi_hba->slot_info)
+ goto err_out;
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+ hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma,
+ GFP_KERNEL);
+ if (!hisi_hba->iost)
+ goto err_out;
+
+ memset(hisi_hba->iost, 0, s);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ hisi_hba->breakpoint = dma_alloc_coherent(dev, s,
+ &hisi_hba->breakpoint_dma, GFP_KERNEL);
+ if (!hisi_hba->breakpoint)
+ goto err_out;
+
+ memset(hisi_hba->breakpoint, 0, s);
+
+ hisi_hba->slot_index_count = HISI_SAS_COMMAND_ENTRIES;
+ s = hisi_hba->slot_index_count / sizeof(unsigned long);
+ hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
+ if (!hisi_hba->slot_index_tags)
+ goto err_out;
+
+ hisi_hba->sge_page_pool = dma_pool_create("status_sge", dev,
+ sizeof(struct hisi_sas_sge_page), 16, 0);
+ if (!hisi_hba->sge_page_pool)
+ goto err_out;
+
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ hisi_hba->initial_fis = dma_alloc_coherent(dev, s,
+ &hisi_hba->initial_fis_dma, GFP_KERNEL);
+ if (!hisi_hba->initial_fis)
+ goto err_out;
+ memset(hisi_hba->initial_fis, 0, s);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+ hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s,
+ &hisi_hba->sata_breakpoint_dma, GFP_KERNEL);
+ if (!hisi_hba->sata_breakpoint)
+ goto err_out;
+ memset(hisi_hba->sata_breakpoint, 0, s);
+
+ hisi_sas_slot_index_init(hisi_hba);
+
+ hisi_hba->wq = create_singlethread_workqueue(dev_name(dev));
+ if (!hisi_hba->wq) {
+ dev_err(dev, "sas_alloc: failed to create workqueue\n");
+ goto err_out;
+ }
+
+ return 0;
+err_out:
+ return -ENOMEM;
+}
+
+static void hisi_sas_free(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int i, s;
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ if (hisi_hba->cmd_hdr[i])
+ dma_free_coherent(dev, s,
+ hisi_hba->cmd_hdr[i],
+ hisi_hba->cmd_hdr_dma[i]);
+
+ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ if (hisi_hba->complete_hdr[i])
+ dma_free_coherent(dev, s,
+ hisi_hba->complete_hdr[i],
+ hisi_hba->complete_hdr_dma[i]);
+ }
+
+ dma_pool_destroy(hisi_hba->status_buffer_pool);
+ dma_pool_destroy(hisi_hba->command_table_pool);
+ dma_pool_destroy(hisi_hba->sge_page_pool);
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ if (hisi_hba->itct)
+ dma_free_coherent(dev, s,
+ hisi_hba->itct, hisi_hba->itct_dma);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+ if (hisi_hba->iost)
+ dma_free_coherent(dev, s,
+ hisi_hba->iost, hisi_hba->iost_dma);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ if (hisi_hba->breakpoint)
+ dma_free_coherent(dev, s,
+ hisi_hba->breakpoint,
+ hisi_hba->breakpoint_dma);
+
+
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ if (hisi_hba->initial_fis)
+ dma_free_coherent(dev, s,
+ hisi_hba->initial_fis,
+ hisi_hba->initial_fis_dma);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+ if (hisi_hba->sata_breakpoint)
+ dma_free_coherent(dev, s,
+ hisi_hba->sata_breakpoint,
+ hisi_hba->sata_breakpoint_dma);
+
+ if (hisi_hba->wq)
+ destroy_workqueue(hisi_hba->wq);
+}
+
+static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+{
+ struct resource *res;
+ struct Scsi_Host *shost;
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct property *sas_addr_prop;
+
+ shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
+ if (!shost)
+ goto err_out;
+ hisi_hba = shost_priv(shost);
+
+ hisi_hba->hw = hw;
+ hisi_hba->pdev = pdev;
+ hisi_hba->shost = shost;
+ SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+
+ init_timer(&hisi_hba->timer);
+
+ sas_addr_prop = of_find_property(np, "sas-addr", NULL);
+ if (!sas_addr_prop || (sas_addr_prop->length != SAS_ADDR_SIZE))
+ goto err_out;
+ memcpy(hisi_hba->sas_addr, sas_addr_prop->value, SAS_ADDR_SIZE);
+
+ if (of_property_read_u32(np, "ctrl-reset-reg",
+ &hisi_hba->ctrl_reset_reg))
+ goto err_out;
+
+ if (of_property_read_u32(np, "ctrl-reset-sts-reg",
+ &hisi_hba->ctrl_reset_sts_reg))
+ goto err_out;
+
+ if (of_property_read_u32(np, "ctrl-clock-ena-reg",
+ &hisi_hba->ctrl_clock_ena_reg))
+ goto err_out;
+
+ if (of_property_read_u32(np, "phy-count", &hisi_hba->n_phy))
+ goto err_out;
+
+ if (of_property_read_u32(np, "queue-count", &hisi_hba->queue_count))
+ goto err_out;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hisi_hba->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hisi_hba->regs))
+ goto err_out;
+
+ hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(
+ np, "hisilicon,sas-syscon");
+ if (IS_ERR(hisi_hba->ctrl))
+ goto err_out;
+
+ if (hisi_sas_alloc(hisi_hba, shost)) {
+ hisi_sas_free(hisi_hba);
+ goto err_out;
+ }
+
+ return shost;
+err_out:
+ dev_err(dev, "shost alloc failed\n");
+ return NULL;
+}
+
+static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ memcpy(&hisi_hba->phy[i].dev_sas_addr,
+ hisi_hba->sas_addr,
+ SAS_ADDR_SIZE);
+}
+
+int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+{
+ struct Scsi_Host *shost;
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+ struct asd_sas_phy **arr_phy;
+ struct asd_sas_port **arr_port;
+ struct sas_ha_struct *sha;
+ int rc, phy_nr, port_nr, i;
+
+ shost = hisi_sas_shost_alloc(pdev, hw);
+ if (!shost) {
+ rc = -ENOMEM;
+ goto err_out_ha;
+ }
+
+ sha = SHOST_TO_SAS_HA(shost);
+ hisi_hba = shost_priv(shost);
+ platform_set_drvdata(pdev, sha);
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+ dev_err(dev, "No usable DMA addressing method\n");
+ rc = -EIO;
+ goto err_out_ha;
+ }
+
+ phy_nr = port_nr = hisi_hba->n_phy;
+
+ arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
+ arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
+ if (!arr_phy || !arr_port)
+ return -ENOMEM;
+
+ sha->sas_phy = arr_phy;
+ sha->sas_port = arr_port;
+ sha->core.shost = shost;
+ sha->lldd_ha = hisi_hba;
+
+ shost->transportt = hisi_sas_stt;
+ shost->max_id = HISI_SAS_MAX_DEVICES;
+ shost->max_lun = ~0;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 16;
+ shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
+ shost->can_queue = HISI_SAS_COMMAND_ENTRIES;
+ shost->cmd_per_lun = HISI_SAS_COMMAND_ENTRIES;
+
+ sha->sas_ha_name = DRV_NAME;
+ sha->dev = &hisi_hba->pdev->dev;
+ sha->lldd_module = THIS_MODULE;
+ sha->sas_addr = &hisi_hba->sas_addr[0];
+ sha->num_phys = hisi_hba->n_phy;
+ sha->core.shost = hisi_hba->shost;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
+ sha->sas_port[i] = &hisi_hba->port[i].sas_port;
+ }
+
+ hisi_sas_init_add(hisi_hba);
+
+ rc = hisi_hba->hw->hw_init(hisi_hba);
+ if (rc)
+ goto err_out_ha;
+
+ rc = scsi_add_host(shost, &pdev->dev);
+ if (rc)
+ goto err_out_ha;
+
+ rc = sas_register_ha(sha);
+ if (rc)
+ goto err_out_register_ha;
+
+ scsi_scan_host(shost);
+
+ return 0;
+
+err_out_register_ha:
+ scsi_remove_host(shost);
+err_out_ha:
+ kfree(shost);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_probe);
+
+int hisi_sas_remove(struct platform_device *pdev)
+{
+ struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+ struct hisi_hba *hisi_hba = sha->lldd_ha;
+
+ scsi_remove_host(sha->core.shost);
+ sas_unregister_ha(sha);
+ sas_remove_host(sha->core.shost);
+
+ hisi_sas_free(hisi_hba);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_remove);
+
+static __init int hisi_sas_init(void)
+{
+ pr_info("hisi_sas: driver version %s\n", DRV_VERSION);
+
+ hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
+ if (!hisi_sas_stt)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static __exit void hisi_sas_exit(void)
+{
+ sas_release_transport(hisi_sas_stt);
+}
+
+module_init(hisi_sas_init);
+module_exit(hisi_sas_exit);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
new file mode 100644
index 000000000000..d54381149c0d
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -0,0 +1,1839 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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 "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v1_hw"
+
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO 0x8
+#define IOST_BASE_ADDR_HI 0xc
+#define ITCT_BASE_ADDR_LO 0x10
+#define ITCT_BASE_ADDR_HI 0x14
+#define BROKEN_MSG_ADDR_LO 0x18
+#define BROKEN_MSG_ADDR_HI 0x1c
+#define PHY_CONTEXT 0x20
+#define PHY_STATE 0x24
+#define PHY_PORT_NUM_MA 0x28
+#define PORT_STATE 0x2c
+#define PHY_CONN_RATE 0x30
+#define HGC_TRANS_TASK_CNT_LIMIT 0x38
+#define AXI_AHB_CLK_CFG 0x3c
+#define HGC_SAS_TXFAIL_RETRY_CTRL 0x84
+#define HGC_GET_ITV_TIME 0x90
+#define DEVICE_MSG_WORK_MODE 0x94
+#define I_T_NEXUS_LOSS_TIME 0xa0
+#define BUS_INACTIVE_LIMIT_TIME 0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME 0xac
+#define CFG_AGING_TIME 0xbc
+#define CFG_AGING_TIME_ITCT_REL_OFF 0
+#define CFG_AGING_TIME_ITCT_REL_MSK (0x1 << CFG_AGING_TIME_ITCT_REL_OFF)
+#define HGC_DFX_CFG2 0xc0
+#define FIS_LIST_BADDR_L 0xc4
+#define CFG_1US_TIMER_TRSH 0xcc
+#define CFG_SAS_CONFIG 0xd4
+#define HGC_IOST_ECC_ADDR 0x140
+#define HGC_IOST_ECC_ADDR_BAD_OFF 16
+#define HGC_IOST_ECC_ADDR_BAD_MSK (0x3ff << HGC_IOST_ECC_ADDR_BAD_OFF)
+#define HGC_DQ_ECC_ADDR 0x144
+#define HGC_DQ_ECC_ADDR_BAD_OFF 16
+#define HGC_DQ_ECC_ADDR_BAD_MSK (0xfff << HGC_DQ_ECC_ADDR_BAD_OFF)
+#define HGC_INVLD_DQE_INFO 0x148
+#define HGC_INVLD_DQE_INFO_DQ_OFF 0
+#define HGC_INVLD_DQE_INFO_DQ_MSK (0xffff << HGC_INVLD_DQE_INFO_DQ_OFF)
+#define HGC_INVLD_DQE_INFO_TYPE_OFF 16
+#define HGC_INVLD_DQE_INFO_TYPE_MSK (0x1 << HGC_INVLD_DQE_INFO_TYPE_OFF)
+#define HGC_INVLD_DQE_INFO_FORCE_OFF 17
+#define HGC_INVLD_DQE_INFO_FORCE_MSK (0x1 << HGC_INVLD_DQE_INFO_FORCE_OFF)
+#define HGC_INVLD_DQE_INFO_PHY_OFF 18
+#define HGC_INVLD_DQE_INFO_PHY_MSK (0x1 << HGC_INVLD_DQE_INFO_PHY_OFF)
+#define HGC_INVLD_DQE_INFO_ABORT_OFF 19
+#define HGC_INVLD_DQE_INFO_ABORT_MSK (0x1 << HGC_INVLD_DQE_INFO_ABORT_OFF)
+#define HGC_INVLD_DQE_INFO_IPTT_OF_OFF 20
+#define HGC_INVLD_DQE_INFO_IPTT_OF_MSK (0x1 << HGC_INVLD_DQE_INFO_IPTT_OF_OFF)
+#define HGC_INVLD_DQE_INFO_SSP_ERR_OFF 21
+#define HGC_INVLD_DQE_INFO_SSP_ERR_MSK (0x1 << HGC_INVLD_DQE_INFO_SSP_ERR_OFF)
+#define HGC_INVLD_DQE_INFO_OFL_OFF 22
+#define HGC_INVLD_DQE_INFO_OFL_MSK (0x1 << HGC_INVLD_DQE_INFO_OFL_OFF)
+#define HGC_ITCT_ECC_ADDR 0x150
+#define HGC_ITCT_ECC_ADDR_BAD_OFF 16
+#define HGC_ITCT_ECC_ADDR_BAD_MSK (0x3ff << HGC_ITCT_ECC_ADDR_BAD_OFF)
+#define HGC_AXI_FIFO_ERR_INFO 0x154
+#define INT_COAL_EN 0x1bc
+#define OQ_INT_COAL_TIME 0x1c0
+#define OQ_INT_COAL_CNT 0x1c4
+#define ENT_INT_COAL_TIME 0x1c8
+#define ENT_INT_COAL_CNT 0x1cc
+#define OQ_INT_SRC 0x1d0
+#define OQ_INT_SRC_MSK 0x1d4
+#define ENT_INT_SRC1 0x1d8
+#define ENT_INT_SRC2 0x1dc
+#define ENT_INT_SRC2_DQ_CFG_ERR_OFF 25
+#define ENT_INT_SRC2_DQ_CFG_ERR_MSK (0x1 << ENT_INT_SRC2_DQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_CQ_CFG_ERR_OFF 27
+#define ENT_INT_SRC2_CQ_CFG_ERR_MSK (0x1 << ENT_INT_SRC2_CQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_AXI_WRONG_INT_OFF 28
+#define ENT_INT_SRC2_AXI_WRONG_INT_MSK (0x1 << ENT_INT_SRC2_AXI_WRONG_INT_OFF)
+#define ENT_INT_SRC2_AXI_OVERLF_INT_OFF 29
+#define ENT_INT_SRC2_AXI_OVERLF_INT_MSK (0x1 << ENT_INT_SRC2_AXI_OVERLF_INT_OFF)
+#define ENT_INT_SRC_MSK1 0x1e0
+#define ENT_INT_SRC_MSK2 0x1e4
+#define SAS_ECC_INTR 0x1e8
+#define SAS_ECC_INTR_DQ_ECC1B_OFF 0
+#define SAS_ECC_INTR_DQ_ECC1B_MSK (0x1 << SAS_ECC_INTR_DQ_ECC1B_OFF)
+#define SAS_ECC_INTR_DQ_ECCBAD_OFF 1
+#define SAS_ECC_INTR_DQ_ECCBAD_MSK (0x1 << SAS_ECC_INTR_DQ_ECCBAD_OFF)
+#define SAS_ECC_INTR_IOST_ECC1B_OFF 2
+#define SAS_ECC_INTR_IOST_ECC1B_MSK (0x1 << SAS_ECC_INTR_IOST_ECC1B_OFF)
+#define SAS_ECC_INTR_IOST_ECCBAD_OFF 3
+#define SAS_ECC_INTR_IOST_ECCBAD_MSK (0x1 << SAS_ECC_INTR_IOST_ECCBAD_OFF)
+#define SAS_ECC_INTR_ITCT_ECC1B_OFF 4
+#define SAS_ECC_INTR_ITCT_ECC1B_MSK (0x1 << SAS_ECC_INTR_ITCT_ECC1B_OFF)
+#define SAS_ECC_INTR_ITCT_ECCBAD_OFF 5
+#define SAS_ECC_INTR_ITCT_ECCBAD_MSK (0x1 << SAS_ECC_INTR_ITCT_ECCBAD_OFF)
+#define SAS_ECC_INTR_MSK 0x1ec
+#define HGC_ERR_STAT_EN 0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH 0x268
+#define DLVRY_Q_0_WR_PTR 0x26c
+#define DLVRY_Q_0_RD_PTR 0x270
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH 0x4e8
+#define COMPL_Q_0_WR_PTR 0x4ec
+#define COMPL_Q_0_RD_PTR 0x4f0
+#define HGC_ECC_ERR 0x7d0
+
+/* phy registers need init */
+#define PORT_BASE (0x800)
+
+#define PHY_CFG (PORT_BASE + 0x0)
+#define PHY_CFG_ENA_OFF 0
+#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0xc)
+#define PROG_PHY_LINK_RATE_MAX_OFF 0
+#define PROG_PHY_LINK_RATE_MAX_MSK (0xf << PROG_PHY_LINK_RATE_MAX_OFF)
+#define PROG_PHY_LINK_RATE_MIN_OFF 4
+#define PROG_PHY_LINK_RATE_MIN_MSK (0xf << PROG_PHY_LINK_RATE_MIN_OFF)
+#define PROG_PHY_LINK_RATE_OOB_OFF 8
+#define PROG_PHY_LINK_RATE_OOB_MSK (0xf << PROG_PHY_LINK_RATE_OOB_OFF)
+#define PHY_CTRL (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF 0
+#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+#define PHY_RATE_NEGO (PORT_BASE + 0x30)
+#define PHY_PCN (PORT_BASE + 0x44)
+#define SL_TOUT_CFG (PORT_BASE + 0x8c)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF 0
+#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
+#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
+#define RX_IDAF_DWORD3 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4 (PORT_BASE + 0xd4)
+#define RX_IDAF_DWORD5 (PORT_BASE + 0xd8)
+#define RX_IDAF_DWORD6 (PORT_BASE + 0xdc)
+#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME (PORT_BASE + 0x12c)
+#define CON_CFG_DRIVER (PORT_BASE + 0x130)
+#define PHY_CONFIG2 (PORT_BASE + 0x1a8)
+#define PHY_CONFIG2_FORCE_TXDEEMPH_OFF 3
+#define PHY_CONFIG2_FORCE_TXDEEMPH_MSK (0x1 << PHY_CONFIG2_FORCE_TXDEEMPH_OFF)
+#define PHY_CONFIG2_TX_TRAIN_COMP_OFF 24
+#define PHY_CONFIG2_TX_TRAIN_COMP_MSK (0x1 << PHY_CONFIG2_TX_TRAIN_COMP_OFF)
+#define CHL_INT0 (PORT_BASE + 0x1b0)
+#define CHL_INT0_PHYCTRL_NOTRDY_OFF 0
+#define CHL_INT0_PHYCTRL_NOTRDY_MSK (0x1 << CHL_INT0_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT0_SN_FAIL_NGR_OFF 2
+#define CHL_INT0_SN_FAIL_NGR_MSK (0x1 << CHL_INT0_SN_FAIL_NGR_OFF)
+#define CHL_INT0_DWS_LOST_OFF 4
+#define CHL_INT0_DWS_LOST_MSK (0x1 << CHL_INT0_DWS_LOST_OFF)
+#define CHL_INT0_SL_IDAF_FAIL_OFF 10
+#define CHL_INT0_SL_IDAF_FAIL_MSK (0x1 << CHL_INT0_SL_IDAF_FAIL_OFF)
+#define CHL_INT0_ID_TIMEOUT_OFF 11
+#define CHL_INT0_ID_TIMEOUT_MSK (0x1 << CHL_INT0_ID_TIMEOUT_OFF)
+#define CHL_INT0_SL_OPAF_FAIL_OFF 12
+#define CHL_INT0_SL_OPAF_FAIL_MSK (0x1 << CHL_INT0_SL_OPAF_FAIL_OFF)
+#define CHL_INT0_SL_PS_FAIL_OFF 21
+#define CHL_INT0_SL_PS_FAIL_MSK (0x1 << CHL_INT0_SL_PS_FAIL_OFF)
+#define CHL_INT1 (PORT_BASE + 0x1b4)
+#define CHL_INT2 (PORT_BASE + 0x1b8)
+#define CHL_INT2_SL_RX_BC_ACK_OFF 2
+#define CHL_INT2_SL_RX_BC_ACK_MSK (0x1 << CHL_INT2_SL_RX_BC_ACK_OFF)
+#define CHL_INT2_SL_PHY_ENA_OFF 6
+#define CHL_INT2_SL_PHY_ENA_MSK (0x1 << CHL_INT2_SL_PHY_ENA_OFF)
+#define CHL_INT0_MSK (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF 0
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK (0x1 << CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT1_MSK (PORT_BASE + 0x1c0)
+#define CHL_INT2_MSK (PORT_BASE + 0x1c4)
+#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define DMA_TX_STATUS (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF 0
+#define DMA_TX_STATUS_BUSY_MSK (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF 0
+#define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define AXI_CFG 0x5100
+#define RESET_VALUE 0x7ffff
+
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF 5
+#define CMD_HDR_RESP_REPORT_MSK 0x20
+#define CMD_HDR_TLR_CTRL_OFF 6
+#define CMD_HDR_TLR_CTRL_MSK 0xc0
+#define CMD_HDR_PORT_OFF 17
+#define CMD_HDR_PORT_MSK 0xe0000
+#define CMD_HDR_PRIORITY_OFF 27
+#define CMD_HDR_PRIORITY_MSK 0x8000000
+#define CMD_HDR_MODE_OFF 28
+#define CMD_HDR_MODE_MSK 0x10000000
+#define CMD_HDR_CMD_OFF 29
+#define CMD_HDR_CMD_MSK 0xe0000000
+/* dw1 */
+#define CMD_HDR_VERIFY_DTL_OFF 10
+#define CMD_HDR_VERIFY_DTL_MSK 0x400
+#define CMD_HDR_SSP_FRAME_TYPE_OFF 13
+#define CMD_HDR_SSP_FRAME_TYPE_MSK 0xe000
+#define CMD_HDR_DEVICE_ID_OFF 16
+#define CMD_HDR_DEVICE_ID_MSK 0xffff0000
+/* dw2 */
+#define CMD_HDR_CFL_OFF 0
+#define CMD_HDR_CFL_MSK 0x1ff
+#define CMD_HDR_MRFL_OFF 15
+#define CMD_HDR_MRFL_MSK 0xff8000
+#define CMD_HDR_FIRST_BURST_OFF 25
+#define CMD_HDR_FIRST_BURST_MSK 0x2000000
+/* dw3 */
+#define CMD_HDR_IPTT_OFF 0
+#define CMD_HDR_IPTT_MSK 0xffff
+/* dw6 */
+#define CMD_HDR_DATA_SGL_LEN_OFF 16
+#define CMD_HDR_DATA_SGL_LEN_MSK 0xffff0000
+
+/* Completion header */
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_CMD_CMPLT_OFF 17
+#define CMPLT_HDR_CMD_CMPLT_MSK (0x1 << CMPLT_HDR_CMD_CMPLT_OFF)
+#define CMPLT_HDR_ERR_RCRD_XFRD_OFF 18
+#define CMPLT_HDR_ERR_RCRD_XFRD_MSK (0x1 << CMPLT_HDR_ERR_RCRD_XFRD_OFF)
+#define CMPLT_HDR_RSPNS_XFRD_OFF 19
+#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_IO_CFG_ERR_OFF 27
+#define CMPLT_HDR_IO_CFG_ERR_MSK (0x1 << CMPLT_HDR_IO_CFG_ERR_OFF)
+
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF 0
+#define ITCT_HDR_DEV_TYPE_MSK (0x3 << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF 2
+#define ITCT_HDR_VALID_MSK (0x1 << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_BREAK_REPLY_ENA_OFF 3
+#define ITCT_HDR_BREAK_REPLY_ENA_MSK (0x1 << ITCT_HDR_BREAK_REPLY_ENA_OFF)
+#define ITCT_HDR_AWT_CONTROL_OFF 4
+#define ITCT_HDR_AWT_CONTROL_MSK (0x1 << ITCT_HDR_AWT_CONTROL_OFF)
+#define ITCT_HDR_MAX_CONN_RATE_OFF 5
+#define ITCT_HDR_MAX_CONN_RATE_MSK (0xf << ITCT_HDR_MAX_CONN_RATE_OFF)
+#define ITCT_HDR_VALID_LINK_NUM_OFF 9
+#define ITCT_HDR_VALID_LINK_NUM_MSK (0xf << ITCT_HDR_VALID_LINK_NUM_OFF)
+#define ITCT_HDR_PORT_ID_OFF 13
+#define ITCT_HDR_PORT_ID_MSK (0x7 << ITCT_HDR_PORT_ID_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_OFF 16
+#define ITCT_HDR_SMP_TIMEOUT_MSK (0xffff << ITCT_HDR_SMP_TIMEOUT_OFF)
+#define ITCT_HDR_MAX_BURST_BYTES_OFF 16
+#define ITCT_HDR_MAX_BURST_BYTES_MSK (0xffffffff << \
+ ITCT_MAX_BURST_BYTES_OFF)
+/* qw1 */
+#define ITCT_HDR_MAX_SAS_ADDR_OFF 0
+#define ITCT_HDR_MAX_SAS_ADDR_MSK (0xffffffffffffffff << \
+ ITCT_HDR_MAX_SAS_ADDR_OFF)
+/* qw2 */
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_OFF 0
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_MSK (0xffff << \
+ ITCT_HDR_IT_NEXUS_LOSS_TL_OFF)
+#define ITCT_HDR_BUS_INACTIVE_TL_OFF 16
+#define ITCT_HDR_BUS_INACTIVE_TL_MSK (0xffff << \
+ ITCT_HDR_BUS_INACTIVE_TL_OFF)
+#define ITCT_HDR_MAX_CONN_TL_OFF 32
+#define ITCT_HDR_MAX_CONN_TL_MSK (0xffff << \
+ ITCT_HDR_MAX_CONN_TL_OFF)
+#define ITCT_HDR_REJ_OPEN_TL_OFF 48
+#define ITCT_HDR_REJ_OPEN_TL_MSK (0xffff << \
+ ITCT_REJ_OPEN_TL_OFF)
+
+/* Err record header */
+#define ERR_HDR_DMA_TX_ERR_TYPE_OFF 0
+#define ERR_HDR_DMA_TX_ERR_TYPE_MSK (0xffff << ERR_HDR_DMA_TX_ERR_TYPE_OFF)
+#define ERR_HDR_DMA_RX_ERR_TYPE_OFF 16
+#define ERR_HDR_DMA_RX_ERR_TYPE_MSK (0xffff << ERR_HDR_DMA_RX_ERR_TYPE_OFF)
+
+struct hisi_sas_complete_v1_hdr {
+ __le32 data;
+};
+
+enum {
+ HISI_SAS_PHY_BCAST_ACK = 0,
+ HISI_SAS_PHY_SL_PHY_ENABLED,
+ HISI_SAS_PHY_INT_ABNORMAL,
+ HISI_SAS_PHY_INT_NR
+};
+
+enum {
+ DMA_TX_ERR_BASE = 0x0,
+ DMA_RX_ERR_BASE = 0x100,
+ TRANS_TX_FAIL_BASE = 0x200,
+ TRANS_RX_FAIL_BASE = 0x300,
+
+ /* dma tx */
+ DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x0 */
+ DMA_TX_DIF_APP_ERR, /* 0x1 */
+ DMA_TX_DIF_RPP_ERR, /* 0x2 */
+ DMA_TX_AXI_BUS_ERR, /* 0x3 */
+ DMA_TX_DATA_SGL_OVERFLOW_ERR, /* 0x4 */
+ DMA_TX_DIF_SGL_OVERFLOW_ERR, /* 0x5 */
+ DMA_TX_UNEXP_XFER_RDY_ERR, /* 0x6 */
+ DMA_TX_XFER_RDY_OFFSET_ERR, /* 0x7 */
+ DMA_TX_DATA_UNDERFLOW_ERR, /* 0x8 */
+ DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR, /* 0x9 */
+
+ /* dma rx */
+ DMA_RX_BUFFER_ECC_ERR = DMA_RX_ERR_BASE, /* 0x100 */
+ DMA_RX_DIF_CRC_ERR, /* 0x101 */
+ DMA_RX_DIF_APP_ERR, /* 0x102 */
+ DMA_RX_DIF_RPP_ERR, /* 0x103 */
+ DMA_RX_RESP_BUFFER_OVERFLOW_ERR, /* 0x104 */
+ DMA_RX_AXI_BUS_ERR, /* 0x105 */
+ DMA_RX_DATA_SGL_OVERFLOW_ERR, /* 0x106 */
+ DMA_RX_DIF_SGL_OVERFLOW_ERR, /* 0x107 */
+ DMA_RX_DATA_OFFSET_ERR, /* 0x108 */
+ DMA_RX_UNEXP_RX_DATA_ERR, /* 0x109 */
+ DMA_RX_DATA_OVERFLOW_ERR, /* 0x10a */
+ DMA_RX_DATA_UNDERFLOW_ERR, /* 0x10b */
+ DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x10c */
+
+ /* trans tx */
+ TRANS_TX_RSVD0_ERR = TRANS_TX_FAIL_BASE, /* 0x200 */
+ TRANS_TX_PHY_NOT_ENABLE_ERR, /* 0x201 */
+ TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR, /* 0x202 */
+ TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR, /* 0x203 */
+ TRANS_TX_OPEN_REJCT_BY_OTHER_ERR, /* 0x204 */
+ TRANS_TX_RSVD1_ERR, /* 0x205 */
+ TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR, /* 0x206 */
+ TRANS_TX_OPEN_REJCT_STP_BUSY_ERR, /* 0x207 */
+ TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR, /* 0x208 */
+ TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR, /* 0x209 */
+ TRANS_TX_OPEN_REJCT_BAD_DEST_ERR, /* 0x20a */
+ TRANS_TX_OPEN_BREAK_RECEIVE_ERR, /* 0x20b */
+ TRANS_TX_LOW_PHY_POWER_ERR, /* 0x20c */
+ TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR, /* 0x20d */
+ TRANS_TX_OPEN_TIMEOUT_ERR, /* 0x20e */
+ TRANS_TX_OPEN_REJCT_NO_DEST_ERR, /* 0x20f */
+ TRANS_TX_OPEN_RETRY_ERR, /* 0x210 */
+ TRANS_TX_RSVD2_ERR, /* 0x211 */
+ TRANS_TX_BREAK_TIMEOUT_ERR, /* 0x212 */
+ TRANS_TX_BREAK_REQUEST_ERR, /* 0x213 */
+ TRANS_TX_BREAK_RECEIVE_ERR, /* 0x214 */
+ TRANS_TX_CLOSE_TIMEOUT_ERR, /* 0x215 */
+ TRANS_TX_CLOSE_NORMAL_ERR, /* 0x216 */
+ TRANS_TX_CLOSE_PHYRESET_ERR, /* 0x217 */
+ TRANS_TX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x218 */
+ TRANS_TX_WITH_CLOSE_COMINIT_ERR, /* 0x219 */
+ TRANS_TX_NAK_RECEIVE_ERR, /* 0x21a */
+ TRANS_TX_ACK_NAK_TIMEOUT_ERR, /* 0x21b */
+ TRANS_TX_CREDIT_TIMEOUT_ERR, /* 0x21c */
+ TRANS_TX_IPTT_CONFLICT_ERR, /* 0x21d */
+ TRANS_TX_TXFRM_TYPE_ERR, /* 0x21e */
+ TRANS_TX_TXSMP_LENGTH_ERR, /* 0x21f */
+
+ /* trans rx */
+ TRANS_RX_FRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x300 */
+ TRANS_RX_FRAME_DONE_ERR, /* 0x301 */
+ TRANS_RX_FRAME_ERRPRM_ERR, /* 0x302 */
+ TRANS_RX_FRAME_NO_CREDIT_ERR, /* 0x303 */
+ TRANS_RX_RSVD0_ERR, /* 0x304 */
+ TRANS_RX_FRAME_OVERRUN_ERR, /* 0x305 */
+ TRANS_RX_FRAME_NO_EOF_ERR, /* 0x306 */
+ TRANS_RX_LINK_BUF_OVERRUN_ERR, /* 0x307 */
+ TRANS_RX_BREAK_TIMEOUT_ERR, /* 0x308 */
+ TRANS_RX_BREAK_REQUEST_ERR, /* 0x309 */
+ TRANS_RX_BREAK_RECEIVE_ERR, /* 0x30a */
+ TRANS_RX_CLOSE_TIMEOUT_ERR, /* 0x30b */
+ TRANS_RX_CLOSE_NORMAL_ERR, /* 0x30c */
+ TRANS_RX_CLOSE_PHYRESET_ERR, /* 0x30d */
+ TRANS_RX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x30e */
+ TRANS_RX_WITH_CLOSE_COMINIT_ERR, /* 0x30f */
+ TRANS_RX_DATA_LENGTH0_ERR, /* 0x310 */
+ TRANS_RX_BAD_HASH_ERR, /* 0x311 */
+ TRANS_RX_XRDY_ZERO_ERR, /* 0x312 */
+ TRANS_RX_SSP_FRAME_LEN_ERR, /* 0x313 */
+ TRANS_RX_TRANS_RX_RSVD1_ERR, /* 0x314 */
+ TRANS_RX_NO_BALANCE_ERR, /* 0x315 */
+ TRANS_RX_TRANS_RX_RSVD2_ERR, /* 0x316 */
+ TRANS_RX_TRANS_RX_RSVD3_ERR, /* 0x317 */
+ TRANS_RX_BAD_FRAME_TYPE_ERR, /* 0x318 */
+ TRANS_RX_SMP_FRAME_LEN_ERR, /* 0x319 */
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x31a */
+};
+
+#define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS)
+#define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES)
+#define HISI_SAS_FATAL_INT_NR (2)
+
+#define HISI_SAS_MAX_INT_NR \
+ (HISI_SAS_PHY_MAX_INT_NR + HISI_SAS_CQ_MAX_INT_NR +\
+ HISI_SAS_FATAL_INT_NR)
+
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl(regs);
+}
+
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl_relaxed(regs);
+}
+
+static void hisi_sas_write32(struct hisi_hba *hisi_hba,
+ u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ writel(val, regs);
+}
+
+static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ writel(val, regs);
+}
+
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ return readl(regs);
+}
+
+static void config_phy_opt_mode_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_DC_OPT_MSK;
+ cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_tx_tfe_autoneg_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CONFIG2);
+
+ cfg &= ~PHY_CONFIG2_FORCE_TXDEEMPH_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CONFIG2, cfg);
+}
+
+static void config_id_frame_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct sas_identify_frame identify_frame;
+ u32 *identify_buffer;
+
+ memset(&identify_frame, 0, sizeof(identify_frame));
+ identify_frame.dev_type = SAS_END_DEVICE;
+ identify_frame.frame_type = 0;
+ identify_frame._un1 = 1;
+ identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+ identify_frame.target_bits = SAS_PROTOCOL_NONE;
+ memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ identify_frame.phy_id = phy_no;
+ identify_buffer = (u32 *)(&identify_frame);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+ __swab32(identify_buffer[0]));
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+ identify_buffer[2]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+ identify_buffer[1]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+ identify_buffer[4]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+ identify_buffer[3]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+ __swab32(identify_buffer[5]));
+}
+
+static void init_id_frame_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ config_id_frame_v1_hw(hisi_hba, i);
+}
+
+static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ struct domain_device *device = sas_dev->sas_device;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+
+ memset(itct, 0, sizeof(*itct));
+
+ /* qw0 */
+ qw0 = 0;
+ switch (sas_dev->dev_type) {
+ case SAS_END_DEVICE:
+ case SAS_EDGE_EXPANDER_DEVICE:
+ case SAS_FANOUT_EXPANDER_DEVICE:
+ qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ default:
+ dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+ sas_dev->dev_type);
+ }
+
+ qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+ (1 << ITCT_HDR_AWT_CONTROL_OFF) |
+ (device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) |
+ (1 << ITCT_HDR_VALID_LINK_NUM_OFF) |
+ (device->port->id << ITCT_HDR_PORT_ID_OFF));
+ itct->qw0 = cpu_to_le64(qw0);
+
+ /* qw1 */
+ memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+ itct->sas_addr = __swab64(itct->sas_addr);
+
+ /* qw2 */
+ itct->qw2 = cpu_to_le64((500 < ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
+ (0xff00 < ITCT_HDR_BUS_INACTIVE_TL_OFF) |
+ (0xff00 < ITCT_HDR_MAX_CONN_TL_OFF) |
+ (0xff00 < ITCT_HDR_REJ_OPEN_TL_OFF));
+}
+
+static void free_device_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ u64 dev_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u32 qw0, reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+
+ reg_val |= CFG_AGING_TIME_ITCT_REL_MSK;
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+ /* free itct */
+ udelay(1);
+ reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+ reg_val &= ~CFG_AGING_TIME_ITCT_REL_MSK;
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+ qw0 = cpu_to_le64(itct->qw0);
+ qw0 &= ~ITCT_HDR_VALID_MSK;
+ itct->qw0 = cpu_to_le64(qw0);
+}
+
+static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ unsigned long end_time;
+ u32 val;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 phy_ctrl = hisi_sas_phy_read32(hisi_hba, i, PHY_CTRL);
+
+ phy_ctrl |= PHY_CTRL_RESET_MSK;
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, phy_ctrl);
+ }
+ msleep(1); /* It is safe to wait for 50us */
+
+ /* Ensure DMA tx & rx idle */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 dma_tx_status, dma_rx_status;
+
+ end_time = jiffies + msecs_to_jiffies(1000);
+
+ while (1) {
+ dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_TX_STATUS);
+ dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_RX_STATUS);
+
+ if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
+ !(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+ }
+
+ /* Ensure axi bus idle */
+ end_time = jiffies + msecs_to_jiffies(1000);
+ while (1) {
+ u32 axi_status =
+ hisi_sas_read32(hisi_hba, AXI_CFG);
+
+ if (axi_status == 0)
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+
+ /* Apply reset and disable clock */
+ /* clk disable reg is offset by +4 bytes from clk enable reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (RESET_VALUE != (val & RESET_VALUE)) {
+ dev_err(dev, "Reset failed\n");
+ return -EIO;
+ }
+
+ /* De-reset and enable clock */
+ /* deassert rst reg is offset by +4 bytes from assert reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (val & RESET_VALUE) {
+ dev_err(dev, "De-reset failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void init_reg_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ /* Global registers init*/
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
+ (u32)((1ULL << hisi_hba->queue_count) - 1));
+ hisi_sas_write32(hisi_hba, HGC_TRANS_TASK_CNT_LIMIT, 0x11);
+ hisi_sas_write32(hisi_hba, DEVICE_MSG_WORK_MODE, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x1ff);
+ hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x401);
+ hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0x64);
+ hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x64);
+ hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x2710);
+ hisi_sas_write32(hisi_hba, REJECT_TO_OPEN_LIMIT_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x7a12);
+ hisi_sas_write32(hisi_hba, HGC_DFX_CFG2, 0x9c40);
+ hisi_sas_write32(hisi_hba, FIS_LIST_BADDR_L, 0x2);
+ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x186a0);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0xffffffff);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC_MSK, 0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0);
+ hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 0x2);
+ hisi_sas_write32(hisi_hba, CFG_SAS_CONFIG, 0x22000000);
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x88a);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CONFIG2, 0x7c080);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_RATE_NEGO, 0x415ee00);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_PCN, 0x80a80000);
+ hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0);
+ hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x13f0a);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 3);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 8);
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ /* Delivery queue */
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+
+ /* Completion queue */
+ hisi_sas_write32(hisi_hba,
+ COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+ }
+
+ /* itct */
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->itct_dma));
+
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->itct_dma));
+
+ /* iost */
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->iost_dma));
+
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->iost_dma));
+
+ /* breakpoint */
+ hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->breakpoint_dma));
+}
+
+static int hw_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc;
+
+ rc = reset_hw_v1_hw(hisi_hba);
+ if (rc) {
+ dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+ return rc;
+ }
+
+ msleep(100);
+ init_reg_v1_hw(hisi_hba);
+
+ init_id_frame_v1_hw(hisi_hba);
+
+ return 0;
+}
+
+static void enable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg |= PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void disable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ config_id_frame_v1_hw(hisi_hba, phy_no);
+ config_phy_opt_mode_v1_hw(hisi_hba, phy_no);
+ config_tx_tfe_autoneg_v1_hw(hisi_hba, phy_no);
+ enable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void stop_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ disable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ stop_phy_v1_hw(hisi_hba, phy_no);
+ msleep(100);
+ start_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v1_hw(unsigned long data)
+{
+ struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x12a);
+ start_phy_v1_hw(hisi_hba, i);
+ }
+}
+
+static void phys_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ struct timer_list *timer = &hisi_hba->timer;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
+ hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
+ }
+
+ setup_timer(timer, start_phys_v1_hw, (unsigned long)hisi_hba);
+ mod_timer(timer, jiffies + HZ);
+}
+
+static void sl_notify_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 sl_control;
+
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ msleep(1);
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
+static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+ int i, bitmap = 0;
+ u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+ bitmap |= 1 << i;
+
+ return bitmap;
+}
+
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 r, w;
+ int queue = hisi_hba->queue;
+
+ while (1) {
+ w = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+ if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+ queue = (queue + 1) % hisi_hba->queue_count;
+ if (queue == hisi_hba->queue) {
+ dev_warn(dev, "could not find free slot\n");
+ return -EAGAIN;
+ }
+ continue;
+ }
+ break;
+ }
+ hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+ *q = queue;
+ *s = w;
+ return 0;
+}
+
+static void start_delivery_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+ int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+ ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ struct hisi_sas_cmd_hdr *hdr,
+ struct scatterlist *scatter,
+ int n_elem)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct scatterlist *sg;
+ int i;
+
+ if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+ dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+ n_elem);
+ return -EINVAL;
+ }
+
+ slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+ &slot->sge_page_dma);
+ if (!slot->sge_page)
+ return -ENOMEM;
+
+ for_each_sg(scatter, sg, n_elem, i) {
+ struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+ entry->data_len = cpu_to_le32(sg_dma_len(sg));
+ entry->data_off = 0;
+ }
+
+ hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+ return 0;
+}
+
+static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ dma_addr_t req_dma_addr;
+ unsigned int req_len, resp_len;
+ int elem, rc;
+
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ /* req */
+ sg_req = &task->smp_task.smp_req;
+ elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+ req_dma_addr = sg_dma_address(sg_req);
+
+ /* resp */
+ sg_resp = &task->smp_task.smp_resp;
+ elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out_req;
+ }
+ resp_len = sg_dma_len(sg_resp);
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_resp;
+ }
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+ (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+ (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+ (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+ /* map itct entry */
+ hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF);
+
+ /* dw2 */
+ hdr->dw2 = cpu_to_le32((((req_len-4)/4) << CMD_HDR_CFL_OFF) |
+ (HISI_SAS_MAX_SMP_RESP_SZ/4 <<
+ CMD_HDR_MRFL_OFF));
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ return 0;
+
+err_out_resp:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+err_out_req:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ return rc;
+}
+
+static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port = slot->port;
+ struct sas_ssp_task *ssp_task = &task->ssp_task;
+ struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+ int has_data = 0, rc, priority = is_tmf;
+ u8 *buf_cmd, fburst = 0;
+ u32 dw1, dw2;
+
+ /* create header */
+ hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+ (0x2 << CMD_HDR_TLR_CTRL_OFF) |
+ (port->id << CMD_HDR_PORT_OFF) |
+ (priority << CMD_HDR_PRIORITY_OFF) |
+ (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+ (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+ dw1 = 1 << CMD_HDR_VERIFY_DTL_OFF;
+
+ if (is_tmf) {
+ dw1 |= 3 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ } else {
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ dw1 |= 2 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ has_data = 1;
+ break;
+ case DMA_FROM_DEVICE:
+ dw1 |= 1 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ has_data = 1;
+ break;
+ default:
+ dw1 |= 0 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ }
+ }
+
+ /* map itct entry */
+ dw1 |= sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ if (is_tmf) {
+ dw2 = ((sizeof(struct ssp_tmf_iu) +
+ sizeof(struct ssp_frame_hdr)+3)/4) <<
+ CMD_HDR_CFL_OFF;
+ } else {
+ dw2 = ((sizeof(struct ssp_command_iu) +
+ sizeof(struct ssp_frame_hdr)+3)/4) <<
+ CMD_HDR_CFL_OFF;
+ }
+
+ dw2 |= (HISI_SAS_MAX_SSP_RESP_SZ/4) << CMD_HDR_MRFL_OFF;
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ if (has_data) {
+ rc = prep_prd_sge_v1_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+ if (task->ssp_task.enable_first_burst) {
+ fburst = (1 << 7);
+ dw2 |= 1 << CMD_HDR_FIRST_BURST_OFF;
+ }
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
+ memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+ task->ssp_task.cmd->cmd_len);
+ } else {
+ buf_cmd[10] = tmf->tmf;
+ switch (tmf->tmf) {
+ case TMF_ABORT_TASK:
+ case TMF_QUERY_TASK:
+ buf_cmd[12] =
+ (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+ buf_cmd[13] =
+ tmf->tag_of_task_to_be_managed & 0xff;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* by default, task resp is complete */
+static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct hisi_sas_err_record *err_record = slot->status_buffer;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ int error = -1;
+ u32 dma_err_type = cpu_to_le32(err_record->dma_err_type);
+ u32 dma_tx_err_type = ((dma_err_type &
+ ERR_HDR_DMA_TX_ERR_TYPE_MSK)) >>
+ ERR_HDR_DMA_TX_ERR_TYPE_OFF;
+ u32 dma_rx_err_type = ((dma_err_type &
+ ERR_HDR_DMA_RX_ERR_TYPE_MSK)) >>
+ ERR_HDR_DMA_RX_ERR_TYPE_OFF;
+ u32 trans_tx_fail_type =
+ cpu_to_le32(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type =
+ cpu_to_le32(err_record->trans_rx_fail_type);
+
+ if (dma_tx_err_type) {
+ /* dma tx err */
+ error = ffs(dma_tx_err_type)
+ - 1 + DMA_TX_ERR_BASE;
+ } else if (dma_rx_err_type) {
+ /* dma rx err */
+ error = ffs(dma_rx_err_type)
+ - 1 + DMA_RX_ERR_BASE;
+ } else if (trans_tx_fail_type) {
+ /* trans tx err */
+ error = ffs(trans_tx_fail_type)
+ - 1 + TRANS_TX_FAIL_BASE;
+ } else if (trans_rx_fail_type) {
+ /* trans rx err */
+ error = ffs(trans_rx_fail_type)
+ - 1 + TRANS_RX_FAIL_BASE;
+ }
+
+ switch (error) {
+ case DMA_TX_DATA_UNDERFLOW_ERR:
+ case DMA_RX_DATA_UNDERFLOW_ERR:
+ {
+ ts->residual = 0;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+ case DMA_TX_DATA_SGL_OVERFLOW_ERR:
+ case DMA_TX_DIF_SGL_OVERFLOW_ERR:
+ case DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR:
+ case DMA_RX_DATA_OVERFLOW_ERR:
+ case TRANS_RX_FRAME_OVERRUN_ERR:
+ case TRANS_RX_LINK_BUF_OVERRUN_ERR:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ }
+ case TRANS_TX_PHY_NOT_ENABLE_ERR:
+ {
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR:
+ case TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR:
+ case TRANS_TX_OPEN_REJCT_BY_OTHER_ERR:
+ case TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR:
+ case TRANS_TX_OPEN_REJCT_STP_BUSY_ERR:
+ case TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR:
+ case TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR:
+ case TRANS_TX_OPEN_REJCT_BAD_DEST_ERR:
+ case TRANS_TX_OPEN_BREAK_RECEIVE_ERR:
+ case TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR:
+ case TRANS_TX_OPEN_REJCT_NO_DEST_ERR:
+ case TRANS_TX_OPEN_RETRY_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_TIMEOUT_ERR:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case TRANS_TX_NAK_RECEIVE_ERR:
+ case TRANS_TX_ACK_NAK_TIMEOUT_ERR:
+ {
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ }
+ default:
+ {
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+ }
+ }
+ break;
+ case SAS_PROTOCOL_SMP:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ dev_err(dev, "slot err: SATA/STP not supported");
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int abort)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+ struct hisi_sas_complete_v1_hdr *complete_queue =
+ (struct hisi_sas_complete_v1_hdr *)
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v1_hdr *complete_hdr;
+ u32 cmplt_hdr_data;
+
+ complete_hdr = &complete_queue[slot->cmplt_queue_slot];
+ cmplt_hdr_data = le32_to_cpu(complete_hdr->data);
+
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return -EINVAL;
+
+ ts = &task->task_status;
+ device = task->dev;
+ sas_dev = device->lldd_dev;
+
+ task->task_state_flags &=
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+
+ memset(ts, 0, sizeof(*ts));
+ ts->resp = SAS_TASK_COMPLETE;
+
+ if (unlikely(!sas_dev || abort)) {
+ if (!sas_dev)
+ dev_dbg(dev, "slot complete: port has not device\n");
+ ts->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
+ if (cmplt_hdr_data & CMPLT_HDR_IO_CFG_ERR_MSK) {
+ u32 info_reg = hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_DQ_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq IPTT err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_TYPE_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq type err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_FORCE_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq force phy err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_PHY_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq phy id err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_ABORT_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq abort flag err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_IPTT_OF_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq IPTT or ICT err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_SSP_ERR_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq SSP frame type err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_OFL_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq order frame len err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ goto out;
+ }
+
+ if (cmplt_hdr_data & CMPLT_HDR_ERR_RCRD_XFRD_MSK) {
+ if (!(cmplt_hdr_data & CMPLT_HDR_CMD_CMPLT_MSK) ||
+ !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK))
+ ts->stat = SAS_DATA_OVERRUN;
+ else
+ slot_err_v1_hw(hisi_hba, task, slot);
+
+ goto out;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ struct ssp_response_iu *iu = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+ sas_ssp_task_response(dev, task, iu);
+ break;
+ }
+ case SAS_PROTOCOL_SMP:
+ {
+ void *to;
+ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+
+ ts->stat = SAM_STAT_GOOD;
+ to = kmap_atomic(sg_page(sg_resp));
+
+ dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+ slot->status_buffer +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+ break;
+ }
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ dev_err(dev, "slot complete: SATA/STP not supported");
+ break;
+
+ default:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+
+ if (!slot->port->port_attached) {
+ dev_err(dev, "slot complete: port %d has removed\n",
+ slot->port->sas_port.id);
+ ts->stat = SAS_PHY_DOWN;
+ }
+
+out:
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ sts = ts->stat;
+
+ if (task->task_done)
+ task->task_done(task);
+
+ return sts;
+}
+
+/* Interrupts */
+static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int i, phy_no = sas_phy->id;
+ u32 irq_value, context, port_id, link_rate;
+ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+ struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+ if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
+ dev_dbg(dev, "phyup: irq_value = %x not set enable bit\n",
+ irq_value);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+ if (context & 1 << phy_no) {
+ dev_err(dev, "phyup: phy%d SATA attached equipment\n",
+ phy_no);
+ goto end;
+ }
+
+ port_id = (hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA) >> (4 * phy_no))
+ & 0xf;
+ if (port_id == 0xf) {
+ dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ for (i = 0; i < 6; i++) {
+ u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+ RX_IDAF_DWORD0 + (i * 4));
+ frame_rcvd[i] = __swab32(idaf);
+ }
+
+ /* Get the linkrate */
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ sas_phy->linkrate = link_rate;
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ memcpy(sas_phy->attached_sas_addr,
+ &id->sas_addr, SAS_ADDR_SIZE);
+ dev_info(dev, "phyup: phy%d link_rate=%d\n",
+ phy_no, link_rate);
+ phy->port_id = port_id;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->phy_type |= PORT_TYPE_SAS;
+ phy->phy_attached = 1;
+ phy->identify.device_type = id->dev_type;
+ phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
+ if (phy->identify.device_type == SAS_END_DEVICE)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != SAS_PHY_UNUSED)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SMP;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+ CHL_INT2_SL_PHY_ENA_MSK);
+
+ if (irq_value & CHL_INT2_SL_PHY_ENA_MSK) {
+ u32 chl_int0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+ chl_int0 &= ~CHL_INT0_PHYCTRL_NOTRDY_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, chl_int0);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3ce3ee);
+ }
+
+ return res;
+}
+
+static irqreturn_t int_bcast_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int phy_no = sas_phy->id;
+ u32 irq_value;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+
+ if (!(irq_value & CHL_INT2_SL_RX_BC_ACK_MSK)) {
+ dev_err(dev, "bcast: irq_value = %x not set enable bit",
+ irq_value);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ sha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+ CHL_INT2_SL_RX_BC_ACK_MSK);
+
+ return res;
+}
+
+static irqreturn_t int_abnormal_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ u32 irq_value, irq_mask_old;
+ int phy_no = sas_phy->id;
+
+ /* mask_int0 */
+ irq_mask_old = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3fffff);
+
+ /* read int0 */
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+ if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK) {
+ u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ hisi_sas_phy_down(hisi_hba, phy_no,
+ (phy_state & 1 << phy_no) ? 1 : 0);
+ }
+
+ if (irq_value & CHL_INT0_ID_TIMEOUT_MSK)
+ dev_dbg(dev, "abnormal: ID_TIMEOUT phy%d identify timeout\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_DWS_LOST_MSK)
+ dev_dbg(dev, "abnormal: DWS_LOST phy%d dws lost\n", phy_no);
+
+ if (irq_value & CHL_INT0_SN_FAIL_NGR_MSK)
+ dev_dbg(dev, "abnormal: SN_FAIL_NGR phy%d sn fail ngr\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_SL_IDAF_FAIL_MSK ||
+ irq_value & CHL_INT0_SL_OPAF_FAIL_MSK)
+ dev_dbg(dev, "abnormal: SL_ID/OPAF_FAIL phy%d check adr frm err\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_SL_PS_FAIL_OFF)
+ dev_dbg(dev, "abnormal: SL_PS_FAIL phy%d fail\n", phy_no);
+
+ /* write to zero */
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, irq_value);
+
+ if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK)
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+ 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+ else
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+ irq_mask_old);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_cq *cq = p;
+ struct hisi_hba *hisi_hba = cq->hisi_hba;
+ struct hisi_sas_slot *slot;
+ int queue = cq->id;
+ struct hisi_sas_complete_v1_hdr *complete_queue =
+ (struct hisi_sas_complete_v1_hdr *)
+ hisi_hba->complete_hdr[queue];
+ u32 irq_value, rd_point, wr_point;
+
+ irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
+
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+ rd_point = hisi_sas_read32(hisi_hba,
+ COMPL_Q_0_RD_PTR + (0x14 * queue));
+ wr_point = hisi_sas_read32(hisi_hba,
+ COMPL_Q_0_WR_PTR + (0x14 * queue));
+
+ while (rd_point != wr_point) {
+ struct hisi_sas_complete_v1_hdr *complete_hdr;
+ int idx;
+ u32 cmplt_hdr_data;
+
+ complete_hdr = &complete_queue[rd_point];
+ cmplt_hdr_data = cpu_to_le32(complete_hdr->data);
+ idx = (cmplt_hdr_data & CMPLT_HDR_IPTT_MSK) >>
+ CMPLT_HDR_IPTT_OFF;
+ slot = &hisi_hba->slot_info[idx];
+
+ /* The completion queue and queue slot index are not
+ * necessarily the same as the delivery queue and
+ * queue slot index.
+ */
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v1_hw(hisi_hba, slot, 0);
+
+ if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
+ rd_point = 0;
+ }
+
+ /* update rd_point */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_ecc_int_v1_hw(int irq, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 ecc_int = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal DQ 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_DQ_ECC_ADDR) &
+ HGC_DQ_ECC_ADDR_BAD_MSK) >>
+ HGC_DQ_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal DQ RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_IOST_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal IOST 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_IOST_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR) &
+ HGC_IOST_ECC_ADDR_BAD_MSK) >>
+ HGC_IOST_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal IOST RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_ITCT_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR) &
+ HGC_ITCT_ECC_ADDR_BAD_MSK) >>
+ HGC_ITCT_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal TCT RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_ITCT_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal ITCT 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR, ecc_int | 0x3f);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_axi_int_v1_hw(int irq, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 axi_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC2);
+ u32 axi_info = hisi_sas_read32(hisi_hba, HGC_AXI_FIFO_ERR_INFO);
+
+ if (axi_int & ENT_INT_SRC2_DQ_CFG_ERR_MSK)
+ panic("%s: Fatal DQ_CFG_ERR interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_CQ_CFG_ERR_MSK)
+ panic("%s: Fatal CQ_CFG_ERR interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_AXI_WRONG_INT_MSK)
+ panic("%s: Fatal AXI_WRONG_INT interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_AXI_OVERLF_INT_MSK)
+ panic("%s: Fatal AXI_OVERLF_INT incorrect interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, axi_int | 0x30000000);
+
+ return IRQ_HANDLED;
+}
+
+static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
+ int_bcast_v1_hw,
+ int_phyup_v1_hw,
+ int_abnormal_v1_hw
+};
+
+static irq_handler_t fatal_interrupts[HISI_SAS_MAX_QUEUES] = {
+ fatal_ecc_int_v1_hw,
+ fatal_axi_int_v1_hw
+};
+
+static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+ int i, j, irq, rc, idx;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+ idx = i * HISI_SAS_PHY_INT_NR;
+ for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev,
+ "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, phy_interrupts[j], 0,
+ DRV_NAME " phy", phy);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "phy interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+ }
+
+ idx = hisi_hba->n_phy * HISI_SAS_PHY_INT_NR;
+ for (i = 0; i < hisi_hba->queue_count; i++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev, "irq init: could not map cq interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, cq_interrupt_v1_hw, 0,
+ DRV_NAME " cq", &hisi_hba->cq[i]);
+ if (rc) {
+ dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ idx = (hisi_hba->n_phy * HISI_SAS_PHY_INT_NR) + hisi_hba->queue_count;
+ for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev, "irq init: could not map fatal interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
+ DRV_NAME " fatal", hisi_hba);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request fatal interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+static int interrupt_openall_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ /* Clear interrupt status */
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT0);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, val);
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT1);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, val);
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT2);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, val);
+
+ /* Unmask interrupt */
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, 0x3ce3ee);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x17fff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8000012a);
+
+ /* bypass chip bug mask abnormal intr */
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK,
+ 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+ }
+
+ return 0;
+}
+
+static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
+{
+ int rc;
+
+ rc = hw_init_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_init_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_openall_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ phys_init_v1_hw(hisi_hba);
+
+ return 0;
+}
+
+static const struct hisi_sas_hw hisi_sas_v1_hw = {
+ .hw_init = hisi_sas_v1_init,
+ .setup_itct = setup_itct_v1_hw,
+ .sl_notify = sl_notify_v1_hw,
+ .free_device = free_device_v1_hw,
+ .prep_smp = prep_smp_v1_hw,
+ .prep_ssp = prep_ssp_v1_hw,
+ .get_free_slot = get_free_slot_v1_hw,
+ .start_delivery = start_delivery_v1_hw,
+ .slot_complete = slot_complete_v1_hw,
+ .phy_enable = enable_phy_v1_hw,
+ .phy_disable = disable_phy_v1_hw,
+ .phy_hard_reset = phy_hard_reset_v1_hw,
+ .get_wideport_bitmap = get_wideport_bitmap_v1_hw,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v1_hdr),
+};
+
+static int hisi_sas_v1_probe(struct platform_device *pdev)
+{
+ return hisi_sas_probe(pdev, &hisi_sas_v1_hw);
+}
+
+static int hisi_sas_v1_remove(struct platform_device *pdev)
+{
+ return hisi_sas_remove(pdev);
+}
+
+static const struct of_device_id sas_v1_of_match[] = {
+ { .compatible = "hisilicon,hip05-sas-v1",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sas_v1_of_match);
+
+static struct platform_driver hisi_sas_v1_driver = {
+ .probe = hisi_sas_v1_probe,
+ .remove = hisi_sas_v1_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = sas_v1_of_match,
+ },
+};
+
+module_platform_driver(hisi_sas_v1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller v1 hw driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index a3860367b568..38ce0e308fbe 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -750,7 +750,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
}
#define MAX_PATHS 8
-
static ssize_t path_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -792,10 +791,8 @@ static ssize_t path_info_show(struct device *dev,
hdev->bus, hdev->target, hdev->lun,
scsi_device_type(hdev->devtype));
- if (hdev->external ||
- hdev->devtype == TYPE_RAID ||
- is_logical_device(hdev)) {
- output_len += snprintf(buf + output_len,
+ if (hdev->devtype == TYPE_RAID || is_logical_device(hdev)) {
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"%s\n", active);
continue;
@@ -808,29 +805,28 @@ static ssize_t path_info_show(struct device *dev,
phys_connector[0] = '0';
if (phys_connector[1] < '0')
phys_connector[1] = '0';
- if (hdev->phys_connector[i] > 0)
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"PORT: %.2s ",
phys_connector);
if (hdev->devtype == TYPE_DISK && hdev->expose_device) {
if (box == 0 || box == 0xFF) {
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"BAY: %hhu %s\n",
bay, active);
} else {
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"BOX: %hhu BAY: %hhu %s\n",
box, bay, active);
}
} else if (box != 0 && box != 0xFF) {
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len, "BOX: %hhu %s\n",
box, active);
} else
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len, "%s\n", active);
}
@@ -3191,6 +3187,87 @@ out:
return rc;
}
+/*
+ * get enclosure information
+ * struct ReportExtendedLUNdata *rlep - Used for BMIC drive number
+ * struct hpsa_scsi_dev_t *encl_dev - device entry for enclosure
+ * Uses id_physical_device to determine the box_index.
+ */
+static void hpsa_get_enclosure_info(struct ctlr_info *h,
+ unsigned char *scsi3addr,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
+ struct hpsa_scsi_dev_t *encl_dev)
+{
+ int rc = -1;
+ struct CommandList *c = NULL;
+ struct ErrorInfo *ei = NULL;
+ struct bmic_sense_storage_box_params *bssbp = NULL;
+ struct bmic_identify_physical_device *id_phys = NULL;
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+ u16 bmic_device_index = 0;
+
+ bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
+
+ if (bmic_device_index == 0xFF00)
+ goto out;
+
+ bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL);
+ if (!bssbp)
+ goto out;
+
+ id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+ if (!id_phys)
+ goto out;
+
+ rc = hpsa_bmic_id_physical_device(h, scsi3addr, bmic_device_index,
+ id_phys, sizeof(*id_phys));
+ if (rc) {
+ dev_warn(&h->pdev->dev, "%s: id_phys failed %d bdi[0x%x]\n",
+ __func__, encl_dev->external, bmic_device_index);
+ goto out;
+ }
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_SENSE_STORAGE_BOX_PARAMS, h, bssbp,
+ sizeof(*bssbp), 0, RAID_CTLR_LUNID, TYPE_CMD);
+
+ if (rc)
+ goto out;
+
+ if (id_phys->phys_connector[1] == 'E')
+ c->Request.CDB[5] = id_phys->box_index;
+ else
+ c->Request.CDB[5] = 0;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE,
+ NO_TIMEOUT);
+ if (rc)
+ goto out;
+
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ rc = -1;
+ goto out;
+ }
+
+ encl_dev->box[id_phys->active_path_number] = bssbp->phys_box_on_port;
+ memcpy(&encl_dev->phys_connector[id_phys->active_path_number],
+ bssbp->phys_connector, sizeof(bssbp->phys_connector));
+
+ rc = IO_OK;
+out:
+ kfree(bssbp);
+ kfree(id_phys);
+
+ if (c)
+ cmd_free(h, c);
+
+ if (rc != IO_OK)
+ hpsa_show_dev_msg(KERN_INFO, h, encl_dev,
+ "Error, could not get enclosure information\n");
+}
+
static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h,
unsigned char *scsi3addr)
{
@@ -4032,7 +4109,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
/* skip masked non-disk devices */
if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
- (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
+ (physdev_list->LUN[phys_dev_index].device_type != 0x06) &&
+ (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
continue;
/* Get device type, vendor, model, device id */
@@ -4116,7 +4194,12 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
break;
case TYPE_TAPE:
case TYPE_MEDIUM_CHANGER:
+ ncurrent++;
+ break;
case TYPE_ENCLOSURE:
+ hpsa_get_enclosure_info(h, lunaddrbytes,
+ physdev_list, phys_dev_index,
+ this_device);
ncurrent++;
break;
case TYPE_RAID:
@@ -6629,6 +6712,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0XFF;
break;
+ case BMIC_SENSE_STORAGE_BOX_PARAMS:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_STORAGE_BOX_PARAMS;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ break;
case BMIC_IDENTIFY_CONTROLLER:
c->Request.CDBLen = 10;
c->Request.type_attr_dir =
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index ae5beda1bdb5..fdd39fc0b199 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -400,7 +400,7 @@ struct offline_device_entry {
#define HPSA_PHYSICAL_DEVICE_BUS 0
#define HPSA_RAID_VOLUME_BUS 1
#define HPSA_EXTERNAL_RAID_VOLUME_BUS 2
-#define HPSA_HBA_BUS 3
+#define HPSA_HBA_BUS 0
/*
Send the command to the hardware
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index d92ef0d352b5..6a919ada96b3 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -291,6 +291,7 @@ struct SenseSubsystem_info {
#define BMIC_SENSE_DIAG_OPTIONS 0xF5
#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000
#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
+#define BMIC_SENSE_STORAGE_BOX_PARAMS 0x65
/* Command List Structure */
union SCSI3Addr {
@@ -842,5 +843,17 @@ struct bmic_sense_subsystem_info {
u8 pad[332];
};
+struct bmic_sense_storage_box_params {
+ u8 reserved[36];
+ u8 inquiry_valid;
+ u8 reserved_1[68];
+ u8 phys_box_on_port;
+ u8 reserved_2[22];
+ u16 connection_info;
+ u8 reserver_3[84];
+ u8 phys_connector[2];
+ u8 reserved_4[296];
+};
+
#pragma pack()
#endif /* HPSA_CMD_H */
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 6a926bae76b2..7a91cf3ff173 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -110,11 +110,6 @@
#define i91u_MAXQUEUE 2
#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
-#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
-#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
-#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
-#define I920_DEVICE_ID 0x0002 /* Initio's other product ID */
-
#ifdef DEBUG_i91u
static unsigned int i91u_debug = DEBUG_DEFAULT;
#endif
@@ -127,17 +122,6 @@ static int setup_debug = 0;
static void i91uSCBPost(u8 * pHcb, u8 * pScb);
-/* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] = {
- { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { }
-};
-MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
-
#define DEBUG_INTERRUPT 0
#define DEBUG_QUEUE 0
#define DEBUG_STATE 0
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index ceee9a3fd9e5..90a3ca5a4dbd 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -386,7 +386,6 @@ struct lpfc_vport {
uint32_t work_port_events; /* Timeout to be handled */
#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
-#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
#define WORKER_DELAYED_DISC_TMO 0x8 /* vport: delayed discovery */
#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
@@ -396,7 +395,6 @@ struct lpfc_vport {
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
- struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
struct timer_list delayed_disc_tmo;
@@ -405,6 +403,7 @@ struct lpfc_vport {
uint8_t load_flag;
#define FC_LOADING 0x1 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
+#define FC_ALLOW_FDMI 0x4 /* port is ready for FDMI requests */
/* Vport Config Parameters */
uint32_t cfg_scan_down;
uint32_t cfg_lun_queue_depth;
@@ -414,10 +413,6 @@ struct lpfc_vport {
uint32_t cfg_peer_port_login;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
- uint32_t cfg_fdmi_on;
-#define LPFC_FDMI_SUPPORT 1 /* bit 0 - FDMI supported? */
-#define LPFC_FDMI_REG_DELAY 2 /* bit 1 - 60 sec registration delay */
-#define LPFC_FDMI_ALL_ATTRIB 4 /* bit 2 - register ALL attributes? */
uint32_t cfg_discovery_threads;
uint32_t cfg_log_verbose;
uint32_t cfg_max_luns;
@@ -443,6 +438,10 @@ struct lpfc_vport {
unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
#define STATIC_VPORT 1
+
+ uint16_t fdmi_num_disc;
+ uint32_t fdmi_hba_mask;
+ uint32_t fdmi_port_mask;
};
struct hbq_s {
@@ -755,6 +754,11 @@ struct lpfc_hba {
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */
uint32_t cfg_enable_dss;
+ uint32_t cfg_fdmi_on;
+#define LPFC_FDMI_NO_SUPPORT 0 /* FDMI not supported */
+#define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */
+#define LPFC_FDMI_SMART_SAN 2 /* SmartSAN supported */
+ uint32_t cfg_enable_SmartSAN;
lpfc_vpd_t vpd; /* vital product data */
struct pci_dev *pcidev;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f6446d759d7f..343ae9482891 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -4572,19 +4572,27 @@ LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
255, "Identifies TYPE for additional ring configuration");
/*
-# lpfc_fdmi_on: controls FDMI support.
-# Set NOT Set
-# bit 0 = FDMI support no FDMI support
-# LPFC_FDMI_SUPPORT just turns basic support on/off
-# bit 1 = Register delay no register delay (60 seconds)
-# LPFC_FDMI_REG_DELAY 60 sec registration delay after FDMI login
-# bit 2 = All attributes Use a attribute subset
-# LPFC_FDMI_ALL_ATTRIB applies to both port and HBA attributes
-# Port attrutes subset: 1 thru 6 OR all: 1 thru 0xd 0x101 0x102 0x103
-# HBA attributes subset: 1 thru 0xb OR all: 1 thru 0xc
-# Value range [0,7]. Default value is 0.
+# lpfc_enable_SmartSAN: Sets up FDMI support for SmartSAN
+# 0 = SmartSAN functionality disabled (default)
+# 1 = SmartSAN functionality enabled
+# This parameter will override the value of lpfc_fdmi_on module parameter.
+# Value range is [0,1]. Default value is 0.
*/
-LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 7, "Enable FDMI support");
+LPFC_ATTR_R(enable_SmartSAN, 0, 0, 1, "Enable SmartSAN functionality");
+
+/*
+# lpfc_fdmi_on: Controls FDMI support.
+# 0 No FDMI support (default)
+# 1 Traditional FDMI support
+# 2 Smart SAN support
+# If lpfc_enable_SmartSAN is set 1, the driver sets lpfc_fdmi_on to value 2
+# overwriting the current value. If lpfc_enable_SmartSAN is set 0, the
+# driver uses the current value of lpfc_fdmi_on provided it has value 0 or 1.
+# A value of 2 with lpfc_enable_SmartSAN set to 0 causes the driver to
+# set lpfc_fdmi_on back to 1.
+# Value range [0,2]. Default value is 0.
+*/
+LPFC_ATTR_R(fdmi_on, 0, 0, 2, "Enable FDMI support");
/*
# Specifies the maximum number of ELS cmds we can have outstanding (for
@@ -4815,6 +4823,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_multi_ring_rctl,
&dev_attr_lpfc_multi_ring_type,
&dev_attr_lpfc_fdmi_on,
+ &dev_attr_lpfc_enable_SmartSAN,
&dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv,
&dev_attr_lpfc_fcf_failover_policy,
@@ -4887,7 +4896,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
&dev_attr_lpfc_first_burst_size,
- &dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_nport_evt_cnt,
&dev_attr_npiv_info,
@@ -5247,7 +5255,7 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
spin_lock_irq(shost->host_lock);
- if (lpfc_is_link_up(phba)) {
+ if ((lpfc_is_link_up(phba)) && (!(phba->hba_flag & HBA_FCOE_MODE))) {
switch(phba->fc_linkspeed) {
case LPFC_LINK_SPEED_1GHZ:
fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -5826,6 +5834,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
+ lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
+ lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -5846,6 +5856,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
phba->cfg_poll = 0;
else
phba->cfg_poll = lpfc_poll;
+
+ /* Ensure fdmi_on and enable_SmartSAN don't conflict */
+ if (phba->cfg_enable_SmartSAN) {
+ phba->cfg_fdmi_on = LPFC_FDMI_SMART_SAN;
+ } else {
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT;
+ }
+
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
@@ -5879,7 +5898,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
lpfc_use_adisc_init(vport, lpfc_use_adisc);
lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
- lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
lpfc_max_luns_init(vport, lpfc_max_luns);
lpfc_scan_down_init(vport, lpfc_scan_down);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index b0e6fe46448d..4e55b35180a4 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
void lpfc_retry_pport_discovery(struct lpfc_hba *);
void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
+void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -167,9 +168,8 @@ void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
-int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
-void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_timeout_handler(struct lpfc_vport *);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
+void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
void lpfc_delayed_disc_tmo(unsigned long);
void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 8fded1f7605f..79e261d2a0c8 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -48,15 +48,26 @@
#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
-/* FDMI Port Speed definitions */
-#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */
-#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */
-#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */
-#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */
-#define HBA_PORTSPEED_32GBIT 0x0040 /* 32 GBit/sec */
-#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */
+/* FDMI Port Speed definitions - FC-GS-7 */
+#define HBA_PORTSPEED_1GFC 0x00000001 /* 1G FC */
+#define HBA_PORTSPEED_2GFC 0x00000002 /* 2G FC */
+#define HBA_PORTSPEED_4GFC 0x00000008 /* 4G FC */
+#define HBA_PORTSPEED_10GFC 0x00000004 /* 10G FC */
+#define HBA_PORTSPEED_8GFC 0x00000010 /* 8G FC */
+#define HBA_PORTSPEED_16GFC 0x00000020 /* 16G FC */
+#define HBA_PORTSPEED_32GFC 0x00000040 /* 32G FC */
+#define HBA_PORTSPEED_20GFC 0x00000080 /* 20G FC */
+#define HBA_PORTSPEED_40GFC 0x00000100 /* 40G FC */
+#define HBA_PORTSPEED_128GFC 0x00000200 /* 128G FC */
+#define HBA_PORTSPEED_64GFC 0x00000400 /* 64G FC */
+#define HBA_PORTSPEED_256GFC 0x00000800 /* 256G FC */
+#define HBA_PORTSPEED_UNKNOWN 0x00008000 /* Unknown */
+#define HBA_PORTSPEED_10GE 0x00010000 /* 10G E */
+#define HBA_PORTSPEED_40GE 0x00020000 /* 40G E */
+#define HBA_PORTSPEED_100GE 0x00040000 /* 100G E */
+#define HBA_PORTSPEED_25GE 0x00080000 /* 25G E */
+#define HBA_PORTSPEED_50GE 0x00100000 /* 50G E */
+#define HBA_PORTSPEED_400GE 0x00200000 /* 400G E */
#define FOURBYTES 4
@@ -287,6 +298,17 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
return 0;
}
+/**
+ * lpfc_gen_req - Build and issue a GEN_REQUEST command to the SLI Layer
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @bmp: Pointer to BPL for SLI command
+ * @inp: Pointer to data buffer for response data.
+ * @outp: Pointer to data buffer that hold the CT command.
+ * @cmpl: completion routine to call when command completes
+ * @ndlp: Destination NPort nodelist entry
+ *
+ * This function as the final part for issuing a CT command.
+ */
static int
lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
@@ -311,7 +333,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
- icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
+ icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
if (usr_flg)
geniocb->context3 = NULL;
@@ -370,6 +392,16 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
return 0;
}
+/**
+ * lpfc_ct_cmd - Build and issue a CT command
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @inmp: Pointer to data buffer for response data.
+ * @bmp: Pointer to BPL for SLI command
+ * @ndlp: Destination NPort nodelist entry
+ * @cmpl: completion routine to call when command completes
+ *
+ * This function is called for issuing a CT command.
+ */
static int
lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
@@ -453,7 +485,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
Cnt -= 16; /* subtract length of CT header */
/* Loop through entire NameServer list of DIDs */
- while (Cnt >= sizeof (uint32_t)) {
+ while (Cnt >= sizeof(uint32_t)) {
/* Get next DID from NameServer List */
CTentry = *ctptr++;
Did = ((be32_to_cpu(CTentry)) & Mask_DID);
@@ -558,7 +590,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
}
if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
goto nsout1;
- Cnt -= sizeof (uint32_t);
+ Cnt -= sizeof(uint32_t);
}
ctptr = NULL;
@@ -1146,7 +1178,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
/* fill in BDEs for command */
/* Allocate buffer for command payload */
- mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!mp) {
rc=2;
goto ns_cmd_exit;
@@ -1160,7 +1192,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
}
/* Allocate buffer for Buffer ptr list */
- bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!bmp) {
rc=4;
goto ns_cmd_free_mpvirt;
@@ -1204,7 +1236,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
bpl->tus.w = le32_to_cpu(bpl->tus.w);
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
- memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
+ memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
CtReq->RevisionId.bits.InId = 0;
CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
@@ -1244,7 +1276,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cpu_to_be16(SLI_CTNS_RNN_ID);
CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
cmpl = lpfc_cmpl_ct_cmd_rnn_id;
break;
@@ -1264,7 +1296,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
CtReq->CommandResponse.bits.CmdRsp =
cpu_to_be16(SLI_CTNS_RSNN_NN);
memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
size = sizeof(CtReq->un.rsnn.symbname);
CtReq->un.rsnn.len =
lpfc_vport_symbolic_node_name(vport,
@@ -1319,20 +1351,29 @@ ns_cmd_exit:
return 1;
}
+/**
+ * lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to the command IOCBQ.
+ * @rspiocb: Pointer to the response IOCBQ.
+ *
+ * This function to handle the completion of a driver initiated FDMI
+ * CT command issued during discovery.
+ */
static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_dmabuf *inp = cmdiocb->context1;
struct lpfc_dmabuf *outp = cmdiocb->context2;
- struct lpfc_sli_ct_request *CTrsp = outp->virt;
struct lpfc_sli_ct_request *CTcmd = inp->virt;
- struct lpfc_nodelist *ndlp;
+ struct lpfc_sli_ct_request *CTrsp = outp->virt;
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
- struct lpfc_vport *vport = cmdiocb->vport;
IOCB_t *irsp = &rspiocb->iocb;
- uint32_t latt;
+ struct lpfc_nodelist *ndlp;
+ uint32_t latt, cmd, err;
latt = lpfc_els_chk_latt(vport);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1340,91 +1381,1115 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4], latt);
if (latt || irsp->ulpStatus) {
+
+ /* Look for a retryable error */
+ if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
+ case IOERR_SLI_ABORTED:
+ case IOERR_ABORT_IN_PROGRESS:
+ case IOERR_SEQUENCE_TIMEOUT:
+ case IOERR_ILLEGAL_FRAME:
+ case IOERR_NO_RESOURCES:
+ case IOERR_ILLEGAL_COMMAND:
+ cmdiocb->retry++;
+ if (cmdiocb->retry >= LPFC_FDMI_MAX_RETRY)
+ break;
+
+ /* Retry the same FDMI command */
+ err = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING,
+ cmdiocb, 0);
+ if (err == IOCB_ERROR)
+ break;
+ return;
+ default:
+ break;
+ }
+ }
+
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"0229 FDMI cmd %04x failed, latt = %d "
"ulpStatus: x%x, rid x%x\n",
be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
irsp->un.ulpWord[4]);
- goto fail_out;
}
+ lpfc_ct_free_iocb(phba, cmdiocb);
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
- goto fail_out;
+ return;
+ /* Check for a CT LS_RJT response */
+ cmd = be16_to_cpu(fdmi_cmd);
if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0220 FDMI rsp failed Data: x%x\n",
- be16_to_cpu(fdmi_cmd));
+ "0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
+
+ /* Should we fallback to FDMI-2 / FDMI-1 ? */
+ switch (cmd) {
+ case SLI_MGMT_RHBA:
+ if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+ }
+ return;
+
+ case SLI_MGMT_RPRT:
+ if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ /* Retry the same command */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ return;
+
+ case SLI_MGMT_RPA:
+ if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+ }
+ if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ /* Retry the same command */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ return;
+ }
}
-fail_out:
- lpfc_ct_free_iocb(phba, cmdiocb);
+ /*
+ * On success, need to cycle thru FDMI registration for discovery
+ * DHBA -> DPRT -> RHBA -> RPA (physical port)
+ * DPRT -> RPRT (vports)
+ */
+ switch (cmd) {
+ case SLI_MGMT_RHBA:
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
+ break;
+
+ case SLI_MGMT_DHBA:
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+ break;
+
+ case SLI_MGMT_DPRT:
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
+ else
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ break;
+ }
+ return;
}
-static void
-lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq *rspiocb)
+
+/**
+ * lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * Called from hbeat timeout routine to check if the number of discovered
+ * ports has changed. If so, re-register thar port Attribute.
+ */
+void
+lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
{
- struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_dmabuf *inp = cmdiocb->context1;
- struct lpfc_sli_ct_request *CTcmd = inp->virt;
- uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
+ uint16_t cnt;
+
+ if (!lpfc_is_link_up(phba))
+ return;
+
+ if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
+ return;
- lpfc_cmpl_ct_cmd_fdmi(phba, cmdiocb, rspiocb);
+ cnt = lpfc_find_map_node(vport);
+ if (cnt == vport->fdmi_num_disc)
+ return;
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
return;
- /*
- * Need to cycle thru FDMI registration for discovery
- * DHBA -> DPRT -> RHBA -> RPA
- */
- switch (be16_to_cpu(fdmi_cmd)) {
- case SLI_MGMT_RHBA:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
- break;
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
+ LPFC_FDMI_PORT_ATTR_num_disc);
+ } else {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
+ LPFC_FDMI_PORT_ATTR_num_disc);
+ }
+}
- case SLI_MGMT_DHBA:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
- break;
+/* Routines for all individual HBA attributes */
+int
+lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
- case SLI_MGMT_DPRT:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
- break;
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_NODENAME);
+ return size;
+}
+int
+lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString,
+ "Emulex Corporation",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->SerialNumber,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelName,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MODEL);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelDesc,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ lpfc_vpd_t *vp = &phba->vpd;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t i, j, incr, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ /* Convert JEDEC ID to ascii for hardware version */
+ incr = vp->rev.biuRev;
+ for (i = 0; i < 8; i++) {
+ j = (incr & 0xf);
+ if (j <= 9)
+ ae->un.AttrString[7 - i] =
+ (char)((uint8_t) 0x30 +
+ (uint8_t) j);
+ else
+ ae->un.AttrString[7 - i] =
+ (char)((uint8_t) 0x61 +
+ (uint8_t) (j - 10));
+ incr = (incr >> 4);
}
+ size = FOURBYTES + 8;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, lpfc_release_version,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ else
+ strncpy(ae->un.AttrString, phba->OptionROMVersion,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s",
+ init_utsname()->sysname,
+ init_utsname()->release,
+ init_utsname()->version);
+
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ ae->un.AttrInt = cpu_to_be32(LPFC_MAX_CT_SIZE);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ len = lpfc_vport_symbolic_node_name(vport,
+ ae->un.AttrString, 256);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Nothing is defined for this currently */
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO);
+ return size;
}
+int
+lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Each driver instance corresponds to a single port */
+ ae->un.AttrInt = cpu_to_be32(1);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fabric_nodename,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN);
+ return size;
+}
int
-lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
+lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Driver doesn't have access to this information */
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "EMULEX",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID);
+ return size;
+}
+
+/* Routines for all individual PORT attributes */
+int
+lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 32);
+
+ ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ size = FOURBYTES + 32;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ ae->un.AttrInt = 0;
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ if (phba->lmt & LMT_32Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
+ if (phba->lmt & LMT_10Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
+ if (phba->lmt & LMT_8Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
+ if (phba->lmt & LMT_4Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
+ if (phba->lmt & LMT_2Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
+ if (phba->lmt & LMT_1Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+ } else {
+ /* FCoE links support only one speed */
+ switch (phba->fc_linkspeed) {
+ case LPFC_ASYNC_LINK_SPEED_10GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_10GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_25GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_25GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_40GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_40GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_100GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_100GE;
+ break;
+ }
+ }
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_1GFC;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_2GFC;
+ break;
+ case LPFC_LINK_SPEED_4GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_4GFC;
+ break;
+ case LPFC_LINK_SPEED_8GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_8GFC;
+ break;
+ case LPFC_LINK_SPEED_10GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_10GFC;
+ break;
+ case LPFC_LINK_SPEED_16GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_16GFC;
+ break;
+ case LPFC_LINK_SPEED_32GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_32GFC;
+ break;
+ default:
+ ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+ break;
+ }
+ } else {
+ switch (phba->fc_linkspeed) {
+ case LPFC_ASYNC_LINK_SPEED_10GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_10GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_25GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_25GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_40GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_40GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_100GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_100GE;
+ break;
+ default:
+ ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct serv_parm *hsp;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ hsp = (struct serv_parm *)&vport->fc_sparam;
+ ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb) << 8) |
+ (uint32_t) hsp->cmn.bbRcvSizeLsb;
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString),
+ "/sys/class/scsi_host/host%d", shost->host_no);
+ len = strnlen((char *)ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
+ init_utsname()->nodename);
+
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_NODENAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP)
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT);
+ else
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fabric_portname,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 32);
+
+ ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ size = FOURBYTES + 32;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ /* Link Up - operational */
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ vport->fdmi_num_disc = lpfc_find_map_node(vport);
+ ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(vport->fc_myDID);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "Smart SAN Initiator",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ memcpy((((uint8_t *)&ae->un.AttrString) +
+ sizeof(struct lpfc_name)),
+ &vport->fc_sparam.portName, sizeof(struct lpfc_name));
+ size = FOURBYTES + (2 * sizeof(struct lpfc_name));
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_GUID);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "Smart SAN Version 1.0",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelName,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* SRIOV (type 3) is not supported */
+ if (vport->vpi)
+ ae->un.AttrInt = cpu_to_be32(2); /* NPIV */
+ else
+ ae->un.AttrInt = cpu_to_be32(1); /* Physical */
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_QOS);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY);
+ return size;
+}
+
+/* RHBA attribute jump table */
+int (*lpfc_fdmi_hba_action[])
+ (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+ /* Action routine Mask bit Attribute type */
+ lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
+ lpfc_fdmi_hba_attr_manufacturer, /* bit1 RHBA_MANUFACTURER */
+ lpfc_fdmi_hba_attr_sn, /* bit2 RHBA_SERIAL_NUMBER */
+ lpfc_fdmi_hba_attr_model, /* bit3 RHBA_MODEL */
+ lpfc_fdmi_hba_attr_description, /* bit4 RHBA_MODEL_DESCRIPTION */
+ lpfc_fdmi_hba_attr_hdw_ver, /* bit5 RHBA_HARDWARE_VERSION */
+ lpfc_fdmi_hba_attr_drvr_ver, /* bit6 RHBA_DRIVER_VERSION */
+ lpfc_fdmi_hba_attr_rom_ver, /* bit7 RHBA_OPTION_ROM_VERSION */
+ lpfc_fdmi_hba_attr_fmw_ver, /* bit8 RHBA_FIRMWARE_VERSION */
+ lpfc_fdmi_hba_attr_os_ver, /* bit9 RHBA_OS_NAME_VERSION */
+ lpfc_fdmi_hba_attr_ct_len, /* bit10 RHBA_MAX_CT_PAYLOAD_LEN */
+ lpfc_fdmi_hba_attr_symbolic_name, /* bit11 RHBA_SYM_NODENAME */
+ lpfc_fdmi_hba_attr_vendor_info, /* bit12 RHBA_VENDOR_INFO */
+ lpfc_fdmi_hba_attr_num_ports, /* bit13 RHBA_NUM_PORTS */
+ lpfc_fdmi_hba_attr_fabric_wwnn, /* bit14 RHBA_FABRIC_WWNN */
+ lpfc_fdmi_hba_attr_bios_ver, /* bit15 RHBA_BIOS_VERSION */
+ lpfc_fdmi_hba_attr_bios_state, /* bit16 RHBA_BIOS_STATE */
+ lpfc_fdmi_hba_attr_vendor_id, /* bit17 RHBA_VENDOR_ID */
+};
+
+/* RPA / RPRT attribute jump table */
+int (*lpfc_fdmi_port_action[])
+ (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+ /* Action routine Mask bit Attribute type */
+ lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
+ lpfc_fdmi_port_attr_support_speed, /* bit1 RPRT_SUPPORTED_SPEED */
+ lpfc_fdmi_port_attr_speed, /* bit2 RPRT_PORT_SPEED */
+ lpfc_fdmi_port_attr_max_frame, /* bit3 RPRT_MAX_FRAME_SIZE */
+ lpfc_fdmi_port_attr_os_devname, /* bit4 RPRT_OS_DEVICE_NAME */
+ lpfc_fdmi_port_attr_host_name, /* bit5 RPRT_HOST_NAME */
+ lpfc_fdmi_port_attr_wwnn, /* bit6 RPRT_NODENAME */
+ lpfc_fdmi_port_attr_wwpn, /* bit7 RPRT_PORTNAME */
+ lpfc_fdmi_port_attr_symbolic_name, /* bit8 RPRT_SYM_PORTNAME */
+ lpfc_fdmi_port_attr_port_type, /* bit9 RPRT_PORT_TYPE */
+ lpfc_fdmi_port_attr_class, /* bit10 RPRT_SUPPORTED_CLASS */
+ lpfc_fdmi_port_attr_fabric_wwpn, /* bit11 RPRT_FABRICNAME */
+ lpfc_fdmi_port_attr_active_fc4type, /* bit12 RPRT_ACTIVE_FC4_TYPES */
+ lpfc_fdmi_port_attr_port_state, /* bit13 RPRT_PORT_STATE */
+ lpfc_fdmi_port_attr_num_disc, /* bit14 RPRT_DISC_PORT */
+ lpfc_fdmi_port_attr_nportid, /* bit15 RPRT_PORT_ID */
+ lpfc_fdmi_smart_attr_service, /* bit16 RPRT_SMART_SERVICE */
+ lpfc_fdmi_smart_attr_guid, /* bit17 RPRT_SMART_GUID */
+ lpfc_fdmi_smart_attr_version, /* bit18 RPRT_SMART_VERSION */
+ lpfc_fdmi_smart_attr_model, /* bit19 RPRT_SMART_MODEL */
+ lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */
+ lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */
+ lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */
+};
+
+/**
+ * lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ int cmdcode, uint32_t new_mask)
{
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
+ uint32_t bit_pos;
uint32_t size;
uint32_t rsp_size;
+ uint32_t mask;
struct lpfc_fdmi_reg_hba *rh;
struct lpfc_fdmi_port_entry *pe;
struct lpfc_fdmi_reg_portattr *pab = NULL;
struct lpfc_fdmi_attr_block *ab = NULL;
- struct lpfc_fdmi_attr_entry *ae;
- struct lpfc_fdmi_attr_def *ad;
- void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
- struct lpfc_iocbq *);
+ int (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad);
+ void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
- if (ndlp == NULL) {
- ndlp = lpfc_findnode_did(vport, FDMI_DID);
- if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
- return 0;
- cmpl = lpfc_cmpl_ct_cmd_fdmi; /* cmd interface */
- } else {
- cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
- }
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+ return 0;
+
+ cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
/* fill in BDEs for command */
/* Allocate buffer for command payload */
@@ -1470,573 +2535,99 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
switch (cmdcode) {
case SLI_MGMT_RHAT:
case SLI_MGMT_RHBA:
- {
- lpfc_vpd_t *vp = &phba->vpd;
- uint32_t i, j, incr;
- int len = 0;
+ rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
+ /* HBA Identifier */
+ memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
- rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
- /* HBA Identifier */
- memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
+ if (cmdcode == SLI_MGMT_RHBA) {
+ /* Registered Port List */
+ /* One entry (port) per adapter */
+ rh->rpl.EntryCnt = cpu_to_be32(1);
+ memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName,
sizeof(struct lpfc_name));
- if (cmdcode == SLI_MGMT_RHBA) {
- /* Registered Port List */
- /* One entry (port) per adapter */
- rh->rpl.EntryCnt = cpu_to_be32(1);
- memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
-
- /* point to the HBA attribute block */
- size = 2 * sizeof(struct lpfc_name) +
- FOURBYTES;
- } else {
- size = sizeof(struct lpfc_name);
- }
- ab = (struct lpfc_fdmi_attr_block *)
- ((uint8_t *)rh + size);
- ab->EntryCnt = 0;
- size += FOURBYTES;
-
- /*
- * Point to beginning of first HBA attribute entry
- */
- /* #1 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RHBA_NODENAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
- sizeof(struct lpfc_name));
- ab->EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #2 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.Manufacturer));
- ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
- strncpy(ae->un.Manufacturer, "Emulex Corporation",
- sizeof(ae->un.Manufacturer));
- len = strnlen(ae->un.Manufacturer,
- sizeof(ae->un.Manufacturer));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #3 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.SerialNumber));
- ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
- strncpy(ae->un.SerialNumber, phba->SerialNumber,
- sizeof(ae->un.SerialNumber));
- len = strnlen(ae->un.SerialNumber,
- sizeof(ae->un.SerialNumber));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #4 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.Model));
- ad->AttrType = cpu_to_be16(RHBA_MODEL);
- strncpy(ae->un.Model, phba->ModelName,
- sizeof(ae->un.Model));
- len = strnlen(ae->un.Model, sizeof(ae->un.Model));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #5 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.ModelDescription));
- ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
- strncpy(ae->un.ModelDescription, phba->ModelDesc,
- sizeof(ae->un.ModelDescription));
- len = strnlen(ae->un.ModelDescription,
- sizeof(ae->un.ModelDescription));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 8) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #6 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, 8);
- ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 8);
- /* Convert JEDEC ID to ascii for hardware version */
- incr = vp->rev.biuRev;
- for (i = 0; i < 8; i++) {
- j = (incr & 0xf);
- if (j <= 9)
- ae->un.HardwareVersion[7 - i] =
- (char)((uint8_t)0x30 +
- (uint8_t)j);
- else
- ae->un.HardwareVersion[7 - i] =
- (char)((uint8_t)0x61 +
- (uint8_t)(j - 10));
- incr = (incr >> 4);
+ /* point to the HBA attribute block */
+ size = 2 * sizeof(struct lpfc_name) +
+ FOURBYTES;
+ } else {
+ size = sizeof(struct lpfc_name);
+ }
+ ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size);
+ ab->EntryCnt = 0;
+ size += FOURBYTES;
+ bit_pos = 0;
+ if (new_mask)
+ mask = new_mask;
+ else
+ mask = vport->fdmi_hba_mask;
+
+ /* Mask will dictate what attributes to build in the request */
+ while (mask) {
+ if (mask & 0x1) {
+ func = lpfc_fdmi_hba_action[bit_pos];
+ size += func(vport,
+ (struct lpfc_fdmi_attr_def *)
+ ((uint8_t *)rh + size));
+ ab->EntryCnt++;
+ if ((size + 256) >
+ (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+ goto hba_out;
}
- ab->EntryCnt++;
- size += FOURBYTES + 8;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #7 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.DriverVersion));
- ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
- strncpy(ae->un.DriverVersion, lpfc_release_version,
- sizeof(ae->un.DriverVersion));
- len = strnlen(ae->un.DriverVersion,
- sizeof(ae->un.DriverVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #8 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OptionROMVersion));
- ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
- strncpy(ae->un.OptionROMVersion, phba->OptionROMVersion,
- sizeof(ae->un.OptionROMVersion));
- len = strnlen(ae->un.OptionROMVersion,
- sizeof(ae->un.OptionROMVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #9 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FirmwareVersion));
- ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
- lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
- 1);
- len = strnlen(ae->un.FirmwareVersion,
- sizeof(ae->un.FirmwareVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #10 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OsNameVersion));
- ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
- snprintf(ae->un.OsNameVersion,
- sizeof(ae->un.OsNameVersion),
- "%s %s %s",
- init_utsname()->sysname,
- init_utsname()->release,
- init_utsname()->version);
- len = strnlen(ae->un.OsNameVersion,
- sizeof(ae->un.OsNameVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #11 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType =
- cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- ae->un.MaxCTPayloadLen = cpu_to_be32(LPFC_MAX_CT_SIZE);
- ab->EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /*
- * Currently switches don't seem to support the
- * following extended HBA attributes.
- */
- if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
- goto hba_out;
-
- /* #12 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.NodeSymName));
- ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
- len = lpfc_vport_symbolic_node_name(vport,
- ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
-hba_out:
- ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
- /* Total size */
- size = GID_REQUEST_SZ - 4 + size;
+ mask = mask >> 1;
+ bit_pos++;
}
+hba_out:
+ ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
+ /* Total size */
+ size = GID_REQUEST_SZ - 4 + size;
break;
case SLI_MGMT_RPRT:
case SLI_MGMT_RPA:
- {
- struct serv_parm *hsp;
- int len = 0;
-
- if (cmdcode == SLI_MGMT_RPRT) {
- rh = (struct lpfc_fdmi_reg_hba *)
- &CtReq->un.PortID;
- /* HBA Identifier */
- memcpy(&rh->hi.PortName,
- &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- pab = (struct lpfc_fdmi_reg_portattr *)
- &rh->rpl.EntryCnt;
- } else
- pab = (struct lpfc_fdmi_reg_portattr *)
- &CtReq->un.PortID;
- size = sizeof(struct lpfc_name) + FOURBYTES;
- memcpy((uint8_t *)&pab->PortName,
- (uint8_t *)&vport->fc_sparam.portName,
+ pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
+ if (cmdcode == SLI_MGMT_RPRT) {
+ rh = (struct lpfc_fdmi_reg_hba *)pab;
+ /* HBA Identifier */
+ memcpy(&rh->hi.PortName,
+ &phba->pport->fc_sparam.portName,
sizeof(struct lpfc_name));
- pab->ab.EntryCnt = 0;
-
- /* #1 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FC4Types));
- ad->AttrType =
- cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
- ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
- ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
- ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
- pab->ab.EntryCnt++;
- size += FOURBYTES + 32;
-
- /* #2 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- ae->un.SupportSpeed = 0;
- if (phba->lmt & LMT_32Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT;
- if (phba->lmt & LMT_16Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
- if (phba->lmt & LMT_10Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
- if (phba->lmt & LMT_8Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
- if (phba->lmt & LMT_4Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT;
- if (phba->lmt & LMT_2Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT;
- if (phba->lmt & LMT_1Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT;
- ae->un.SupportSpeed =
- cpu_to_be32(ae->un.SupportSpeed);
-
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-
- /* #3 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- switch (phba->fc_linkspeed) {
- case LPFC_LINK_SPEED_1GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
- break;
- case LPFC_LINK_SPEED_2GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
- break;
- case LPFC_LINK_SPEED_4GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
- break;
- case LPFC_LINK_SPEED_8GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
- break;
- case LPFC_LINK_SPEED_10GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
- break;
- case LPFC_LINK_SPEED_16GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
- break;
- case LPFC_LINK_SPEED_32GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_32GBIT;
- break;
- default:
- ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
- break;
- }
- ae->un.PortSpeed = cpu_to_be32(ae->un.PortSpeed);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-
- /* #4 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- hsp = (struct serv_parm *)&vport->fc_sparam;
- ae->un.MaxFrameSize =
- (((uint32_t)hsp->cmn.
- bbRcvSizeMsb) << 8) | (uint32_t)hsp->cmn.
- bbRcvSizeLsb;
- ae->un.MaxFrameSize =
- cpu_to_be32(ae->un.MaxFrameSize);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #5 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OsDeviceName));
- ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
- strncpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME,
- sizeof(ae->un.OsDeviceName));
- len = strnlen((char *)ae->un.OsDeviceName,
- sizeof(ae->un.OsDeviceName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #6 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.HostName));
- snprintf(ae->un.HostName, sizeof(ae->un.HostName), "%s",
- init_utsname()->nodename);
- ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
- len = strnlen(ae->un.HostName,
- sizeof(ae->un.HostName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen =
- cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
+ pab = (struct lpfc_fdmi_reg_portattr *)
+ ((uint8_t *)pab + sizeof(struct lpfc_name));
+ }
- /*
- * Currently switches don't seem to support the
- * following extended Port attributes.
- */
- if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
- goto port_out;
-
- /* #7 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_NODENAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #8 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.PortName, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #9 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.NodeSymName));
- ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
- len = lpfc_vport_symbolic_port_name(vport,
- ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #10 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
- ae->un.PortState = 0;
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #11 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
- ae->un.SupportClass =
- cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #12 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.FabricName, &vport->fabric_nodename,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #13 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FC4Types));
- ad->AttrType =
- cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
- ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
- ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
- ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
- pab->ab.EntryCnt++;
- size += FOURBYTES + 32;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #257 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
- ae->un.PortState = 0;
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #258 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
- ae->un.PortState = lpfc_find_map_node(vport);
- ae->un.PortState = cpu_to_be32(ae->un.PortState);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #259 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
- ae->un.PortId = cpu_to_be32(vport->fc_myDID);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-port_out:
- pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
- /* Total size */
- size = GID_REQUEST_SZ - 4 + size;
+ memcpy((uint8_t *)&pab->PortName,
+ (uint8_t *)&vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ size += sizeof(struct lpfc_name) + FOURBYTES;
+ pab->ab.EntryCnt = 0;
+ bit_pos = 0;
+ if (new_mask)
+ mask = new_mask;
+ else
+ mask = vport->fdmi_port_mask;
+
+ /* Mask will dictate what attributes to build in the request */
+ while (mask) {
+ if (mask & 0x1) {
+ func = lpfc_fdmi_port_action[bit_pos];
+ size += func(vport,
+ (struct lpfc_fdmi_attr_def *)
+ ((uint8_t *)pab + size));
+ pab->ab.EntryCnt++;
+ if ((size + 256) >
+ (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+ goto port_out;
+ }
+ mask = mask >> 1;
+ bit_pos++;
}
+port_out:
+ pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
+ /* Total size */
+ if (cmdcode == SLI_MGMT_RPRT)
+ size += sizeof(struct lpfc_name);
+ size = GID_REQUEST_SZ - 4 + size;
break;
case SLI_MGMT_GHAT:
@@ -2158,41 +2749,6 @@ lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
}
void
-lpfc_fdmi_tmo(unsigned long ptr)
-{
- struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
- struct lpfc_hba *phba = vport->phba;
- uint32_t tmo_posted;
- unsigned long iflag;
-
- spin_lock_irqsave(&vport->work_port_lock, iflag);
- tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
- if (!tmo_posted)
- vport->work_port_events |= WORKER_FDMI_TMO;
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
-
- if (!tmo_posted)
- lpfc_worker_wake_up(phba);
- return;
-}
-
-void
-lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
-{
- struct lpfc_nodelist *ndlp;
-
- ndlp = lpfc_findnode_did(vport, FDMI_DID);
- if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
- if (init_utsname()->nodename[0] != '\0')
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
- else
- mod_timer(&vport->fc_fdmitmo, jiffies +
- msecs_to_jiffies(1000 * 60));
- }
- return;
-}
-
-void
lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
{
struct lpfc_sli *psli = &phba->sli;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index b6fa257ea3e0..7f5abb8f52bc 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -455,9 +455,9 @@ int
lpfc_issue_reg_vfi(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
- LPFC_MBOXQ_t *mboxq;
+ LPFC_MBOXQ_t *mboxq = NULL;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *dmabuf;
+ struct lpfc_dmabuf *dmabuf = NULL;
int rc = 0;
/* move forward in case of SLI4 FC port loopback test and pt2pt mode */
@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
}
}
- dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!dmabuf) {
+ mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
rc = -ENOMEM;
goto fail;
}
- dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
- if (!dmabuf->virt) {
- rc = -ENOMEM;
- goto fail_free_dmabuf;
- }
- mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- rc = -ENOMEM;
- goto fail_free_coherent;
+ /* Supply CSP's only if we are fabric connect or pt-to-pt connect */
+ if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
+ dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!dmabuf) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+ if (!dmabuf->virt) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ memcpy(dmabuf->virt, &phba->fc_fabparam,
+ sizeof(struct serv_parm));
}
+
vport->port_state = LPFC_FABRIC_CFG_LINK;
- memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
- lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+ if (dmabuf)
+ lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+ else
+ lpfc_reg_vfi(mboxq, vport, 0);
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport;
@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
rc = -ENXIO;
- goto fail_free_mbox;
+ goto fail;
}
return 0;
-fail_free_mbox:
- mempool_free(mboxq, phba->mbox_mem_pool);
-fail_free_coherent:
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-fail_free_dmabuf:
- kfree(dmabuf);
fail:
+ if (mboxq)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ if (dmabuf) {
+ if (dmabuf->virt)
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
+
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0289 Issue Register VFI failed: Err %d\n", rc);
@@ -678,6 +688,21 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
sp->cmn.bbRcvSizeLsb;
fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ if (fabric_param_changed) {
+ /* Reset FDMI attribute masks based on config parameter */
+ if (phba->cfg_fdmi_on == LPFC_FDMI_NO_SUPPORT) {
+ vport->fdmi_hba_mask = 0;
+ vport->fdmi_port_mask = 0;
+ } else {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
+
+ }
memcpy(&vport->fabric_portname, &sp->portName,
sizeof(struct lpfc_name));
memcpy(&vport->fabric_nodename, &sp->nodeName,
@@ -711,9 +736,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* For FC we need to do some special processing because of the SLI
* Port's default settings of the Common Service Parameters.
*/
- if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
- if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+ if (fabric_param_changed)
lpfc_unregister_fcf_prep(phba);
/* This should just update the VFI CSPs*/
@@ -824,13 +850,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ vport->fc_flag |= FC_PT2PT;
spin_unlock_irq(shost->host_lock);
- phba->fc_edtov = FF_DEF_EDTOV;
- phba->fc_ratov = FF_DEF_RATOV;
+ /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
+ lpfc_unregister_fcf_prep(phba);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VFI_REGISTERED;
+ spin_unlock_irq(shost->host_lock);
+ phba->fc_topology_changed = 0;
+ }
+
rc = memcmp(&vport->fc_portname, &sp->portName,
sizeof(vport->fc_portname));
- memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (rc >= 0) {
/* This side will initiate the PLOGI */
@@ -839,38 +873,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_unlock_irq(shost->host_lock);
/*
- * N_Port ID cannot be 0, set our to LocalID the other
- * side will be RemoteID.
+ * N_Port ID cannot be 0, set our Id to LocalID
+ * the other side will be RemoteID.
*/
/* not equal */
if (rc)
vport->fc_myDID = PT2PT_LocalID;
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- lpfc_config_link(phba, mbox);
-
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto fail;
- }
-
- /*
- * For SLI4, the VFI/VPI are registered AFTER the
- * Nport with the higher WWPN sends the PLOGI with
- * an assigned NPortId.
- */
-
- /* not equal */
- if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
- lpfc_issue_reg_vfi(vport);
-
/* Decrement ndlp reference count indicating that ndlp can be
* safely released when other references to it are done.
*/
@@ -912,29 +922,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* If we are pt2pt with another NPort, force NPIV off! */
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
- spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_PT2PT;
- spin_unlock_irq(shost->host_lock);
- /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
- if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
- lpfc_unregister_fcf_prep(phba);
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
- /* The FC_VFI_REGISTERED flag will get clear in the cmpl
- * handler for unreg_vfi, but if we don't force the
- * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be
- * built with the update bit set instead of just the vp bit to
- * change the Nport ID. We need to have the vp set and the
- * Upd cleared on topology changes.
- */
- spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_VFI_REGISTERED;
- spin_unlock_irq(shost->host_lock);
- phba->fc_topology_changed = 0;
- lpfc_issue_reg_vfi(vport);
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto fail;
}
- /* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(vport);
return 0;
fail:
return -ENXIO;
@@ -1157,6 +1158,7 @@ flogifail:
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
spin_unlock_irq(&phba->hbalock);
+
lpfc_nlp_put(ndlp);
if (!lpfc_error_lost_link(irsp)) {
@@ -3792,14 +3794,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_nlp_set_state(vport, ndlp,
NLP_STE_REG_LOGIN_ISSUE);
}
+
+ ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
!= MBX_NOT_FINISHED)
goto out;
- else
- /* Decrement the ndlp reference count we
- * set for this failed mailbox command.
- */
- lpfc_nlp_put(ndlp);
+
+ /* Decrement the ndlp reference count we
+ * set for this failed mailbox command.
+ */
+ lpfc_nlp_put(ndlp);
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
/* ELS rsp: Cannot issue reg_login for <NPortid> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -3856,6 +3861,7 @@ out:
* the routine lpfc_els_free_iocb.
*/
cmdiocb->context1 = NULL;
+
}
lpfc_els_free_iocb(phba, cmdiocb);
@@ -3898,6 +3904,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
uint8_t *pcmd;
+ struct serv_parm *sp;
uint16_t cmdsize;
int rc;
ELS_PKT *els_pkt_ptr;
@@ -3927,6 +3934,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
"Issue ACC: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
+ case ELS_CMD_FLOGI:
case ELS_CMD_PLOGI:
cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
@@ -3944,10 +3952,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
- memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+ sp = (struct serv_parm *)pcmd;
+
+ if (flag == ELS_CMD_FLOGI) {
+ /* Copy the received service parameters back */
+ memcpy(sp, &phba->fc_fabparam,
+ sizeof(struct serv_parm));
+
+ /* Clear the F_Port bit */
+ sp->cmn.fPort = 0;
+
+ /* Mark all class service parameters as invalid */
+ sp->cls1.classValid = 0;
+ sp->cls2.classValid = 0;
+ sp->cls3.classValid = 0;
+ sp->cls4.classValid = 0;
+
+ /* Copy our worldwide names */
+ memcpy(&sp->portName, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ } else {
+ memcpy(pcmd, &vport->fc_sparam,
+ sizeof(struct serv_parm));
+ }
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
- "Issue ACC PLOGI: did:x%x flg:x%x",
+ "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PRLO:
@@ -4673,6 +4705,23 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
desc->length = cpu_to_be32(sizeof(desc->info));
}
+int
+lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
+{
+ if (bf_get(lpfc_read_link_stat_gec2, stat) == 0)
+ return 0;
+ desc->tag = cpu_to_be32(RDP_FEC_DESC_TAG);
+
+ desc->info.CorrectedBlocks =
+ cpu_to_be32(stat->fecCorrBlkCount);
+ desc->info.UncorrectableBlocks =
+ cpu_to_be32(stat->fecUncorrBlkCount);
+
+ desc->length = cpu_to_be32(sizeof(desc->info));
+
+ return sizeof(struct fc_fec_rdp_desc);
+}
+
void
lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
{
@@ -4681,26 +4730,26 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
desc->tag = cpu_to_be32(RDP_PORT_SPEED_DESC_TAG);
- switch (phba->sli4_hba.link_state.speed) {
- case LPFC_FC_LA_SPEED_1G:
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
rdp_speed = RDP_PS_1GB;
break;
- case LPFC_FC_LA_SPEED_2G:
+ case LPFC_LINK_SPEED_2GHZ:
rdp_speed = RDP_PS_2GB;
break;
- case LPFC_FC_LA_SPEED_4G:
+ case LPFC_LINK_SPEED_4GHZ:
rdp_speed = RDP_PS_4GB;
break;
- case LPFC_FC_LA_SPEED_8G:
+ case LPFC_LINK_SPEED_8GHZ:
rdp_speed = RDP_PS_8GB;
break;
- case LPFC_FC_LA_SPEED_10G:
+ case LPFC_LINK_SPEED_10GHZ:
rdp_speed = RDP_PS_10GB;
break;
- case LPFC_FC_LA_SPEED_16G:
+ case LPFC_LINK_SPEED_16GHZ:
rdp_speed = RDP_PS_16GB;
break;
- case LPFC_FC_LA_SPEED_32G:
+ case LPFC_LINK_SPEED_32GHZ:
rdp_speed = RDP_PS_32GB;
break;
default:
@@ -4778,15 +4827,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
struct lpfc_nodelist *ndlp = rdp_context->ndlp;
struct lpfc_vport *vport = ndlp->vport;
struct lpfc_iocbq *elsiocb;
+ struct ulp_bde64 *bpl;
IOCB_t *icmd;
uint8_t *pcmd;
struct ls_rjt *stat;
struct fc_rdp_res_frame *rdp_res;
uint32_t cmdsize;
- int rc;
+ int rc, fec_size;
if (status != SUCCESS)
goto error;
+
+ /* This will change once we know the true size of the RDP payload */
cmdsize = sizeof(struct fc_rdp_res_frame);
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize,
@@ -4823,10 +4875,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba);
lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc,
vport, ndlp);
- rdp_res->length = cpu_to_be32(RDP_DESC_PAYLOAD_SIZE);
-
+ fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc,
+ &rdp_context->link_stat);
+ rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE);
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ /* Now that we know the true size of the payload, update the BPL */
+ bpl = (struct ulp_bde64 *)
+ (((struct lpfc_dmabuf *)(elsiocb->context3))->virt);
+ bpl->tus.f.bdeSize = (fec_size + RDP_DESC_PAYLOAD_SIZE + 8);
+ bpl->tus.f.bdeFlags = 0;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
phba->fc_stat.elsXmitACC++;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR)
@@ -4956,13 +5016,12 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if (RDP_NPORT_ID_SIZE !=
be32_to_cpu(rdp_req->nport_id_desc.length))
goto rjt_logerr;
- rdp_context = kmalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
+ rdp_context = kzalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
if (!rdp_context) {
rjt_err = LSRJT_UNABLE_TPC;
goto error;
}
- memset(rdp_context, 0, sizeof(struct lpfc_rdp_context));
cmd = &cmdiocb->iocb;
rdp_context->ndlp = lpfc_nlp_get(ndlp);
rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id;
@@ -5739,7 +5798,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
IOCB_t *icmd = &cmdiocb->iocb;
struct serv_parm *sp;
LPFC_MBOXQ_t *mbox;
- struct ls_rjt stat;
uint32_t cmd, did;
int rc;
uint32_t fc_flag = 0;
@@ -5765,135 +5823,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1;
}
- if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
- /* For a FLOGI we accept, then if our portname is greater
- * then the remote portname we initiate Nport login.
- */
+ (void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1);
- rc = memcmp(&vport->fc_portname, &sp->portName,
- sizeof(struct lpfc_name));
- if (!rc) {
- if (phba->sli_rev < LPFC_SLI_REV4) {
- mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL);
- if (!mbox)
- return 1;
- lpfc_linkdown(phba);
- lpfc_init_link(phba, mbox,
- phba->cfg_topology,
- phba->cfg_link_speed);
- mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox,
- MBX_NOWAIT);
- lpfc_set_loopback_flag(phba);
- if (rc == MBX_NOT_FINISHED)
- mempool_free(mbox, phba->mbox_mem_pool);
- return 1;
- } else {
- /* abort the flogi coming back to ourselves
- * due to external loopback on the port.
- */
- lpfc_els_abort_flogi(phba);
- return 0;
- }
- } else if (rc > 0) { /* greater than */
- spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(shost->host_lock);
+ /*
+ * If our portname is greater than the remote portname,
+ * then we initiate Nport login.
+ */
- /* If we have the high WWPN we can assign our own
- * myDID; otherwise, we have to WAIT for a PLOGI
- * from the remote NPort to find out what it
- * will be.
- */
- vport->fc_myDID = PT2PT_LocalID;
- } else
- vport->fc_myDID = PT2PT_RemoteID;
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
- /*
- * The vport state should go to LPFC_FLOGI only
- * AFTER we issue a FLOGI, not receive one.
+ if (!rc) {
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ mbox = mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mbox)
+ return 1;
+ lpfc_linkdown(phba);
+ lpfc_init_link(phba, mbox,
+ phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ MBX_NOWAIT);
+ lpfc_set_loopback_flag(phba);
+ if (rc == MBX_NOT_FINISHED)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return 1;
+ }
+
+ /* abort the flogi coming back to ourselves
+ * due to external loopback on the port.
*/
+ lpfc_els_abort_flogi(phba);
+ return 0;
+
+ } else if (rc > 0) { /* greater than */
spin_lock_irq(shost->host_lock);
- fc_flag = vport->fc_flag;
- port_state = vport->port_state;
- vport->fc_flag |= FC_PT2PT;
- vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
spin_unlock_irq(shost->host_lock);
- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "3311 Rcv Flogi PS x%x new PS x%x "
- "fc_flag x%x new fc_flag x%x\n",
- port_state, vport->port_state,
- fc_flag, vport->fc_flag);
- /*
- * We temporarily set fc_myDID to make it look like we are
- * a Fabric. This is done just so we end up with the right
- * did / sid on the FLOGI ACC rsp.
+ /* If we have the high WWPN we can assign our own
+ * myDID; otherwise, we have to WAIT for a PLOGI
+ * from the remote NPort to find out what it
+ * will be.
*/
- did = vport->fc_myDID;
- vport->fc_myDID = Fabric_DID;
-
+ vport->fc_myDID = PT2PT_LocalID;
} else {
- /* Reject this request because invalid parameters */
- stat.un.b.lsRjtRsvd0 = 0;
- stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
- stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
- stat.un.b.vendorUnique = 0;
-
- /*
- * We temporarily set fc_myDID to make it look like we are
- * a Fabric. This is done just so we end up with the right
- * did / sid on the FLOGI LS_RJT rsp.
- */
- did = vport->fc_myDID;
- vport->fc_myDID = Fabric_DID;
-
- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
- NULL);
+ vport->fc_myDID = PT2PT_RemoteID;
+ }
- /* Now lets put fc_myDID back to what its supposed to be */
- vport->fc_myDID = did;
+ /*
+ * The vport state should go to LPFC_FLOGI only
+ * AFTER we issue a FLOGI, not receive one.
+ */
+ spin_lock_irq(shost->host_lock);
+ fc_flag = vport->fc_flag;
+ port_state = vport->port_state;
+ vport->fc_flag |= FC_PT2PT;
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "3311 Rcv Flogi PS x%x new PS x%x "
+ "fc_flag x%x new fc_flag x%x\n",
+ port_state, vport->port_state,
+ fc_flag, vport->fc_flag);
- return 1;
- }
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI ACC rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
- /* send our FLOGI first */
- if (vport->port_state < LPFC_FLOGI) {
- vport->fc_myDID = 0;
- lpfc_initial_flogi(vport);
- vport->fc_myDID = Fabric_DID;
- }
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
/* Send back ACC */
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
/* Now lets put fc_myDID back to what its supposed to be */
vport->fc_myDID = did;
- if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- lpfc_config_link(phba, mbox);
-
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto fail;
- }
- }
-
return 0;
-fail:
- return 1;
}
/**
@@ -7345,7 +7360,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* reject till our FLOGI completes */
if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
- (cmd != ELS_CMD_FLOGI)) {
+ (cmd != ELS_CMD_FLOGI)) {
rjt_err = LSRJT_UNABLE_TPC;
rjt_exp = LSEXP_NOTHING_MORE;
goto lsrjt;
@@ -7381,6 +7396,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
rjt_exp = LSEXP_NOTHING_MORE;
break;
}
+
if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -7730,6 +7746,35 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
+void
+lpfc_start_fdmi(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+
+ /* If this is the first time, allocate an ndlp and initialize
+ * it. Otherwise, make sure the node is enabled and then do the
+ * login.
+ */
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp) {
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (ndlp) {
+ lpfc_nlp_init(vport, ndlp, FDMI_DID);
+ ndlp->nlp_type |= NLP_FABRIC;
+ } else {
+ return;
+ }
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp))
+ ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE);
+
+ if (ndlp) {
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+ }
+}
+
/**
* lpfc_do_scr_ns_plogi - Issue a plogi to the name server for scr
* @phba: pointer to lpfc hba data structure.
@@ -7746,7 +7791,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
void
lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
- struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+ struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
/*
@@ -7804,32 +7849,9 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
return;
}
- if (vport->cfg_fdmi_on & LPFC_FDMI_SUPPORT) {
- /* If this is the first time, allocate an ndlp and initialize
- * it. Otherwise, make sure the node is enabled and then do the
- * login.
- */
- ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
- if (!ndlp_fdmi) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
- if (ndlp_fdmi) {
- lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
- } else
- return;
- }
- if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
- ndlp_fdmi = lpfc_enable_node(vport,
- ndlp_fdmi,
- NLP_STE_NPR_NODE);
-
- if (ndlp_fdmi) {
- lpfc_nlp_set_state(vport, ndlp_fdmi,
- NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
- }
- }
+ if ((phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) &&
+ (vport->load_flag & FC_ALLOW_FDMI))
+ lpfc_start_fdmi(vport);
}
/**
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index bfc2442dd74a..c37d72effbff 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -674,8 +674,6 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_mbox_timeout_handler(phba);
if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
lpfc_unblock_fabric_iocbs(phba);
- if (work_port_events & WORKER_FDMI_TMO)
- lpfc_fdmi_timeout_handler(vport);
if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
lpfc_ramp_down_queue_handler(phba);
if (work_port_events & WORKER_DELAYED_DISC_TMO)
@@ -1083,7 +1081,7 @@ out:
}
-static void
+void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
@@ -1113,8 +1111,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
+ if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport);
+ else if (vport->fc_flag & FC_PT2PT)
+ lpfc_disc_start(vport);
return;
out:
@@ -2963,8 +2963,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
out_free_mem:
mempool_free(mboxq, phba->mbox_mem_pool);
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
- kfree(dmabuf);
+ if (dmabuf) {
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
return;
}
@@ -3035,19 +3037,22 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
uint32_t fc_flags = 0;
spin_lock_irq(&phba->hbalock);
- switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
- case LPFC_LINK_SPEED_1GHZ:
- case LPFC_LINK_SPEED_2GHZ:
- case LPFC_LINK_SPEED_4GHZ:
- case LPFC_LINK_SPEED_8GHZ:
- case LPFC_LINK_SPEED_10GHZ:
- case LPFC_LINK_SPEED_16GHZ:
- case LPFC_LINK_SPEED_32GHZ:
- phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
- break;
- default:
- phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
- break;
+ phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
+
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+ case LPFC_LINK_SPEED_1GHZ:
+ case LPFC_LINK_SPEED_2GHZ:
+ case LPFC_LINK_SPEED_4GHZ:
+ case LPFC_LINK_SPEED_8GHZ:
+ case LPFC_LINK_SPEED_10GHZ:
+ case LPFC_LINK_SPEED_16GHZ:
+ case LPFC_LINK_SPEED_32GHZ:
+ break;
+ default:
+ phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
+ break;
+ }
}
if (phba->fc_topology &&
@@ -3448,10 +3453,10 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
spin_unlock_irq(shost->host_lock);
- } else
- /* Good status, call state machine */
- lpfc_disc_state_machine(vport, ndlp, pmb,
- NLP_EVT_CMPL_REG_LOGIN);
+ }
+
+ /* Call state machine */
+ lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -5550,15 +5555,15 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
ndlp->nlp_usg_map, ndlp);
/*
* Start issuing Fabric-Device Management Interface (FDMI) command to
- * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
- * fdmi-on=2 (supporting RPA/hostnmae)
+ * 0xfffffa (FDMI well known port).
+ * DHBA -> DPRT -> RHBA -> RPA (physical port)
+ * DPRT -> RPRT (vports)
*/
-
- if (vport->cfg_fdmi_on & LPFC_FDMI_REG_DELAY)
- mod_timer(&vport->fc_fdmitmo,
- jiffies + msecs_to_jiffies(1000 * 60));
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
else
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+
/* decrement the node reference count held for this callback
* function.
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 2cce88e967ce..dd20412c7e4c 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1097,6 +1097,18 @@ struct fc_rdp_port_name_desc {
};
+struct fc_rdp_fec_info {
+ uint32_t CorrectedBlocks;
+ uint32_t UncorrectableBlocks;
+};
+
+#define RDP_FEC_DESC_TAG 0x00010005
+struct fc_fec_rdp_desc {
+ uint32_t tag;
+ uint32_t length;
+ struct fc_rdp_fec_info info;
+};
+
struct fc_rdp_link_error_status_payload_info {
struct fc_link_status link_status; /* 24 bytes */
uint32_t port_type; /* bits 31-30 only */
@@ -1196,14 +1208,15 @@ struct fc_rdp_res_frame {
struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */
struct fc_rdp_port_name_desc diag_port_names_desc; /* Word 22-27 */
struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */
+ struct fc_fec_rdp_desc fec_desc; /* FC Word 34 - 37 */
};
#define RDP_DESC_PAYLOAD_SIZE (sizeof(struct fc_rdp_link_service_desc) \
- + sizeof(struct fc_rdp_sfp_desc) \
- + sizeof(struct fc_rdp_port_speed_desc) \
- + sizeof(struct fc_rdp_link_error_status_desc) \
- + (sizeof(struct fc_rdp_port_name_desc) * 2))
+ + sizeof(struct fc_rdp_sfp_desc) \
+ + sizeof(struct fc_rdp_port_speed_desc) \
+ + sizeof(struct fc_rdp_link_error_status_desc) \
+ + (sizeof(struct fc_rdp_port_name_desc) * 2))
/******** FDMI ********/
@@ -1233,31 +1246,10 @@ struct lpfc_fdmi_attr_def { /* Defined in TLV format */
/* Attribute Entry */
struct lpfc_fdmi_attr_entry {
union {
- uint32_t VendorSpecific;
- uint32_t SupportClass;
- uint32_t SupportSpeed;
- uint32_t PortSpeed;
- uint32_t MaxFrameSize;
- uint32_t MaxCTPayloadLen;
- uint32_t PortState;
- uint32_t PortId;
- struct lpfc_name NodeName;
- struct lpfc_name PortName;
- struct lpfc_name FabricName;
- uint8_t FC4Types[32];
- uint8_t Manufacturer[64];
- uint8_t SerialNumber[64];
- uint8_t Model[256];
- uint8_t ModelDescription[256];
- uint8_t HardwareVersion[256];
- uint8_t DriverVersion[256];
- uint8_t OptionROMVersion[256];
- uint8_t FirmwareVersion[256];
- uint8_t OsHostName[256];
- uint8_t NodeSymName[256];
- uint8_t OsDeviceName[256];
- uint8_t OsNameVersion[256];
- uint8_t HostName[256];
+ uint32_t AttrInt;
+ uint8_t AttrTypes[32];
+ uint8_t AttrString[256];
+ struct lpfc_name AttrWWN;
} un;
};
@@ -1327,6 +1319,8 @@ struct lpfc_fdmi_reg_portattr {
#define SLI_MGMT_DPRT 0x310 /* De-register Port */
#define SLI_MGMT_DPA 0x311 /* De-register Port attributes */
+#define LPFC_FDMI_MAX_RETRY 3 /* Max retries for a FDMI command */
+
/*
* HBA Attribute Types
*/
@@ -1342,6 +1336,39 @@ struct lpfc_fdmi_reg_portattr {
#define RHBA_OS_NAME_VERSION 0xa /* 4 to 256 byte ASCII string */
#define RHBA_MAX_CT_PAYLOAD_LEN 0xb /* 32-bit unsigned int */
#define RHBA_SYM_NODENAME 0xc /* 4 to 256 byte ASCII string */
+#define RHBA_VENDOR_INFO 0xd /* 32-bit unsigned int */
+#define RHBA_NUM_PORTS 0xe /* 32-bit unsigned int */
+#define RHBA_FABRIC_WWNN 0xf /* 8 byte WWNN */
+#define RHBA_BIOS_VERSION 0x10 /* 4 to 256 byte ASCII string */
+#define RHBA_BIOS_STATE 0x11 /* 32-bit unsigned int */
+#define RHBA_VENDOR_ID 0xe0 /* 8 byte ASCII string */
+
+/* Bit mask for all individual HBA attributes */
+#define LPFC_FDMI_HBA_ATTR_wwnn 0x00000001
+#define LPFC_FDMI_HBA_ATTR_manufacturer 0x00000002
+#define LPFC_FDMI_HBA_ATTR_sn 0x00000004
+#define LPFC_FDMI_HBA_ATTR_model 0x00000008
+#define LPFC_FDMI_HBA_ATTR_description 0x00000010
+#define LPFC_FDMI_HBA_ATTR_hdw_ver 0x00000020
+#define LPFC_FDMI_HBA_ATTR_drvr_ver 0x00000040
+#define LPFC_FDMI_HBA_ATTR_rom_ver 0x00000080
+#define LPFC_FDMI_HBA_ATTR_fmw_ver 0x00000100
+#define LPFC_FDMI_HBA_ATTR_os_ver 0x00000200
+#define LPFC_FDMI_HBA_ATTR_ct_len 0x00000400
+#define LPFC_FDMI_HBA_ATTR_symbolic_name 0x00000800
+#define LPFC_FDMI_HBA_ATTR_vendor_info 0x00001000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_num_ports 0x00002000
+#define LPFC_FDMI_HBA_ATTR_fabric_wwnn 0x00004000
+#define LPFC_FDMI_HBA_ATTR_bios_ver 0x00008000
+#define LPFC_FDMI_HBA_ATTR_bios_state 0x00010000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_vendor_id 0x00020000
+
+/* Bit mask for FDMI-1 defined HBA attributes */
+#define LPFC_FDMI1_HBA_ATTR 0x000007ff
+
+/* Bit mask for FDMI-2 defined HBA attributes */
+/* Skip vendor_info and bios_state */
+#define LPFC_FDMI2_HBA_ATTR 0x0002efff
/*
* Port Attrubute Types
@@ -1353,15 +1380,65 @@ struct lpfc_fdmi_reg_portattr {
#define RPRT_OS_DEVICE_NAME 0x5 /* 4 to 256 byte ASCII string */
#define RPRT_HOST_NAME 0x6 /* 4 to 256 byte ASCII string */
#define RPRT_NODENAME 0x7 /* 8 byte WWNN */
-#define RPRT_PORTNAME 0x8 /* 8 byte WWNN */
+#define RPRT_PORTNAME 0x8 /* 8 byte WWPN */
#define RPRT_SYM_PORTNAME 0x9 /* 4 to 256 byte ASCII string */
#define RPRT_PORT_TYPE 0xa /* 32-bit unsigned int */
#define RPRT_SUPPORTED_CLASS 0xb /* 32-bit unsigned int */
-#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWNN */
+#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWPN */
#define RPRT_ACTIVE_FC4_TYPES 0xd /* 32 byte binary array */
#define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */
#define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */
#define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */
+#define RPRT_SMART_SERVICE 0xf100 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_GUID 0xf101 /* 8 byte WWNN + 8 byte WWPN */
+#define RPRT_SMART_VERSION 0xf102 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_MODEL 0xf103 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_PORT_INFO 0xf104 /* 32-bit unsigned int */
+#define RPRT_SMART_QOS 0xf105 /* 32-bit unsigned int */
+#define RPRT_SMART_SECURITY 0xf106 /* 32-bit unsigned int */
+
+/* Bit mask for all individual PORT attributes */
+#define LPFC_FDMI_PORT_ATTR_fc4type 0x00000001
+#define LPFC_FDMI_PORT_ATTR_support_speed 0x00000002
+#define LPFC_FDMI_PORT_ATTR_speed 0x00000004
+#define LPFC_FDMI_PORT_ATTR_max_frame 0x00000008
+#define LPFC_FDMI_PORT_ATTR_os_devname 0x00000010
+#define LPFC_FDMI_PORT_ATTR_host_name 0x00000020
+#define LPFC_FDMI_PORT_ATTR_wwnn 0x00000040
+#define LPFC_FDMI_PORT_ATTR_wwpn 0x00000080
+#define LPFC_FDMI_PORT_ATTR_symbolic_name 0x00000100
+#define LPFC_FDMI_PORT_ATTR_port_type 0x00000200
+#define LPFC_FDMI_PORT_ATTR_class 0x00000400
+#define LPFC_FDMI_PORT_ATTR_fabric_wwpn 0x00000800
+#define LPFC_FDMI_PORT_ATTR_port_state 0x00001000
+#define LPFC_FDMI_PORT_ATTR_active_fc4type 0x00002000
+#define LPFC_FDMI_PORT_ATTR_num_disc 0x00004000
+#define LPFC_FDMI_PORT_ATTR_nportid 0x00008000
+#define LPFC_FDMI_SMART_ATTR_service 0x00010000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_guid 0x00020000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_version 0x00040000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_model 0x00080000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_port_info 0x00100000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_qos 0x00200000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_security 0x00400000 /* Vendor specific */
+
+/* Bit mask for FDMI-1 defined PORT attributes */
+#define LPFC_FDMI1_PORT_ATTR 0x0000003f
+
+/* Bit mask for FDMI-2 defined PORT attributes */
+#define LPFC_FDMI2_PORT_ATTR 0x0000ffff
+
+/* Bit mask for Smart SAN defined PORT attributes */
+#define LPFC_FDMI2_SMART_ATTR 0x007fffff
+
+/* Defines for PORT port state attribute */
+#define LPFC_FDMI_PORTSTATE_UNKNOWN 1
+#define LPFC_FDMI_PORTSTATE_ONLINE 2
+
+/* Defines for PORT port type attribute */
+#define LPFC_FDMI_PORTTYPE_UNKNOWN 0
+#define LPFC_FDMI_PORTTYPE_NPORT 1
+#define LPFC_FDMI_PORTTYPE_NLPORT 2
/*
* Begin HBA configuration parameters.
@@ -2498,10 +2575,38 @@ typedef struct {
/* Structure for MB Command READ_LINK_STAT (18) */
typedef struct {
- uint32_t rsvd1;
+ uint32_t word0;
+
+#define lpfc_read_link_stat_rec_SHIFT 0
+#define lpfc_read_link_stat_rec_MASK 0x1
+#define lpfc_read_link_stat_rec_WORD word0
+
+#define lpfc_read_link_stat_gec_SHIFT 1
+#define lpfc_read_link_stat_gec_MASK 0x1
+#define lpfc_read_link_stat_gec_WORD word0
+
+#define lpfc_read_link_stat_w02oftow23of_SHIFT 2
+#define lpfc_read_link_stat_w02oftow23of_MASK 0x3FFFFF
+#define lpfc_read_link_stat_w02oftow23of_WORD word0
+
+#define lpfc_read_link_stat_rsvd_SHIFT 24
+#define lpfc_read_link_stat_rsvd_MASK 0x1F
+#define lpfc_read_link_stat_rsvd_WORD word0
+
+#define lpfc_read_link_stat_gec2_SHIFT 29
+#define lpfc_read_link_stat_gec2_MASK 0x1
+#define lpfc_read_link_stat_gec2_WORD word0
+
+#define lpfc_read_link_stat_clrc_SHIFT 30
+#define lpfc_read_link_stat_clrc_MASK 0x1
+#define lpfc_read_link_stat_clrc_WORD word0
+
+#define lpfc_read_link_stat_clof_SHIFT 31
+#define lpfc_read_link_stat_clof_MASK 0x1
+#define lpfc_read_link_stat_clof_WORD word0
+
uint32_t linkFailureCnt;
uint32_t lossSyncCnt;
-
uint32_t lossSignalCnt;
uint32_t primSeqErrCnt;
uint32_t invalidXmitWord;
@@ -2509,6 +2614,19 @@ typedef struct {
uint32_t primSeqTimeout;
uint32_t elasticOverrun;
uint32_t arbTimeout;
+ uint32_t advRecBufCredit;
+ uint32_t curRecBufCredit;
+ uint32_t advTransBufCredit;
+ uint32_t curTransBufCredit;
+ uint32_t recEofCount;
+ uint32_t recEofdtiCount;
+ uint32_t recEofniCount;
+ uint32_t recSofcount;
+ uint32_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t recDrpXriCount;
+ uint32_t fecCorrBlkCount;
+ uint32_t fecUncorrBlkCount;
} READ_LNK_VAR;
/* Structure for MB Command REG_LOGIN (19) */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 33ec4fa39ccb..608f9415fb08 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -3317,6 +3317,7 @@ struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_SPEED_20GBPS 0x5
#define LPFC_ASYNC_LINK_SPEED_25GBPS 0x6
#define LPFC_ASYNC_LINK_SPEED_40GBPS 0x7
+#define LPFC_ASYNC_LINK_SPEED_100GBPS 0x8
#define lpfc_acqe_link_duplex_SHIFT 16
#define lpfc_acqe_link_duplex_MASK 0x000000FF
#define lpfc_acqe_link_duplex_WORD word0
@@ -3447,23 +3448,50 @@ struct lpfc_acqe_fc_la {
struct lpfc_acqe_misconfigured_event {
struct {
uint32_t word0;
-#define lpfc_sli_misconfigured_port0_SHIFT 0
-#define lpfc_sli_misconfigured_port0_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port0_WORD word0
-#define lpfc_sli_misconfigured_port1_SHIFT 8
-#define lpfc_sli_misconfigured_port1_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port1_WORD word0
-#define lpfc_sli_misconfigured_port2_SHIFT 16
-#define lpfc_sli_misconfigured_port2_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port2_WORD word0
-#define lpfc_sli_misconfigured_port3_SHIFT 24
-#define lpfc_sli_misconfigured_port3_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port3_WORD word0
+#define lpfc_sli_misconfigured_port0_state_SHIFT 0
+#define lpfc_sli_misconfigured_port0_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port0_state_WORD word0
+#define lpfc_sli_misconfigured_port1_state_SHIFT 8
+#define lpfc_sli_misconfigured_port1_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port1_state_WORD word0
+#define lpfc_sli_misconfigured_port2_state_SHIFT 16
+#define lpfc_sli_misconfigured_port2_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port2_state_WORD word0
+#define lpfc_sli_misconfigured_port3_state_SHIFT 24
+#define lpfc_sli_misconfigured_port3_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port3_state_WORD word0
+ uint32_t word1;
+#define lpfc_sli_misconfigured_port0_op_SHIFT 0
+#define lpfc_sli_misconfigured_port0_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port0_op_WORD word1
+#define lpfc_sli_misconfigured_port0_severity_SHIFT 1
+#define lpfc_sli_misconfigured_port0_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port0_severity_WORD word1
+#define lpfc_sli_misconfigured_port1_op_SHIFT 8
+#define lpfc_sli_misconfigured_port1_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port1_op_WORD word1
+#define lpfc_sli_misconfigured_port1_severity_SHIFT 9
+#define lpfc_sli_misconfigured_port1_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port1_severity_WORD word1
+#define lpfc_sli_misconfigured_port2_op_SHIFT 16
+#define lpfc_sli_misconfigured_port2_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port2_op_WORD word1
+#define lpfc_sli_misconfigured_port2_severity_SHIFT 17
+#define lpfc_sli_misconfigured_port2_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port2_severity_WORD word1
+#define lpfc_sli_misconfigured_port3_op_SHIFT 24
+#define lpfc_sli_misconfigured_port3_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port3_op_WORD word1
+#define lpfc_sli_misconfigured_port3_severity_SHIFT 25
+#define lpfc_sli_misconfigured_port3_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port3_severity_WORD word1
} theEvent;
#define LPFC_SLI_EVENT_STATUS_VALID 0x00
#define LPFC_SLI_EVENT_STATUS_NOT_PRESENT 0x01
#define LPFC_SLI_EVENT_STATUS_WRONG_TYPE 0x02
#define LPFC_SLI_EVENT_STATUS_UNSUPPORTED 0x03
+#define LPFC_SLI_EVENT_STATUS_UNQUALIFIED 0x04
+#define LPFC_SLI_EVENT_STATUS_UNCERTIFIED 0x05
};
struct lpfc_acqe_sli {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index db9446c612da..a544366a367e 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1184,8 +1184,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
lpfc_rcv_seq_check_edtov(vports[i]);
+ lpfc_fdmi_num_disc_check(vports[i]);
+ }
lpfc_destroy_vport_work_array(phba, vports);
if ((phba->link_state == LPFC_HBA_ERROR) ||
@@ -1290,6 +1292,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
jiffies +
msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
}
+ } else {
+ mod_timer(&phba->hb_tmofunc,
+ jiffies +
+ msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
}
}
@@ -2621,7 +2627,6 @@ void
lpfc_stop_vport_timers(struct lpfc_vport *vport)
{
del_timer_sync(&vport->els_tmofunc);
- del_timer_sync(&vport->fc_fdmitmo);
del_timer_sync(&vport->delayed_disc_tmo);
lpfc_can_disctmo(vport);
return;
@@ -3340,10 +3345,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
vport->fc_disctmo.function = lpfc_disc_timeout;
vport->fc_disctmo.data = (unsigned long)vport;
- init_timer(&vport->fc_fdmitmo);
- vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
- vport->fc_fdmitmo.data = (unsigned long)vport;
-
init_timer(&vport->els_tmofunc);
vport->els_tmofunc.function = lpfc_els_timeout;
vport->els_tmofunc.data = (unsigned long)vport;
@@ -3709,49 +3710,6 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
}
/**
- * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
- * @phba: pointer to lpfc hba data structure.
- * @acqe_link: pointer to the async link completion queue entry.
- *
- * This routine is to parse the SLI4 link-attention link speed and translate
- * it into the base driver's link-attention link speed coding.
- *
- * Return: Link-attention link speed in terms of base driver's coding.
- **/
-static uint8_t
-lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
- struct lpfc_acqe_link *acqe_link)
-{
- uint8_t link_speed;
-
- switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
- case LPFC_ASYNC_LINK_SPEED_ZERO:
- case LPFC_ASYNC_LINK_SPEED_10MBPS:
- case LPFC_ASYNC_LINK_SPEED_100MBPS:
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- case LPFC_ASYNC_LINK_SPEED_1GBPS:
- link_speed = LPFC_LINK_SPEED_1GHZ;
- break;
- case LPFC_ASYNC_LINK_SPEED_10GBPS:
- link_speed = LPFC_LINK_SPEED_10GHZ;
- break;
- case LPFC_ASYNC_LINK_SPEED_20GBPS:
- case LPFC_ASYNC_LINK_SPEED_25GBPS:
- case LPFC_ASYNC_LINK_SPEED_40GBPS:
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- default:
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0483 Invalid link-attention link speed: x%x\n",
- bf_get(lpfc_acqe_link_speed, acqe_link));
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- }
- return link_speed;
-}
-
-/**
* lpfc_sli_port_speed_get - Get sli3 link speed code to link speed
* @phba: pointer to lpfc hba data structure.
*
@@ -3767,27 +3725,35 @@ lpfc_sli_port_speed_get(struct lpfc_hba *phba)
if (!lpfc_is_link_up(phba))
return 0;
- switch (phba->fc_linkspeed) {
- case LPFC_LINK_SPEED_1GHZ:
- link_speed = 1000;
- break;
- case LPFC_LINK_SPEED_2GHZ:
- link_speed = 2000;
- break;
- case LPFC_LINK_SPEED_4GHZ:
- link_speed = 4000;
- break;
- case LPFC_LINK_SPEED_8GHZ:
- link_speed = 8000;
- break;
- case LPFC_LINK_SPEED_10GHZ:
- link_speed = 10000;
- break;
- case LPFC_LINK_SPEED_16GHZ:
- link_speed = 16000;
- break;
- default:
- link_speed = 0;
+ if (phba->sli_rev <= LPFC_SLI_REV3) {
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
+ link_speed = 1000;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ link_speed = 2000;
+ break;
+ case LPFC_LINK_SPEED_4GHZ:
+ link_speed = 4000;
+ break;
+ case LPFC_LINK_SPEED_8GHZ:
+ link_speed = 8000;
+ break;
+ case LPFC_LINK_SPEED_10GHZ:
+ link_speed = 10000;
+ break;
+ case LPFC_LINK_SPEED_16GHZ:
+ link_speed = 16000;
+ break;
+ default:
+ link_speed = 0;
+ }
+ } else {
+ if (phba->sli4_hba.link_state.logical_speed)
+ link_speed =
+ phba->sli4_hba.link_state.logical_speed;
+ else
+ link_speed = phba->sli4_hba.link_state.speed;
}
return link_speed;
}
@@ -3983,7 +3949,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
la->eventTag = acqe_link->event_tag;
bf_set(lpfc_mbx_read_top_att_type, la, att_type);
bf_set(lpfc_mbx_read_top_link_spd, la,
- lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
+ (bf_get(lpfc_acqe_link_speed, acqe_link)));
/* Fake the the following irrelvant fields */
bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
@@ -4113,22 +4079,18 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
char message[128];
uint8_t status;
uint8_t evt_type;
+ uint8_t operational = 0;
struct temp_event temp_event_data;
struct lpfc_acqe_misconfigured_event *misconfigured;
struct Scsi_Host *shost;
evt_type = bf_get(lpfc_trailer_type, acqe_sli);
- /* Special case Lancer */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
- LPFC_SLI_INTF_IF_TYPE_2) {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2901 Async SLI event - Event Data1:x%08x Event Data2:"
- "x%08x SLI Event Type:%d\n",
- acqe_sli->event_data1, acqe_sli->event_data2,
- evt_type);
- return;
- }
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2901 Async SLI event - Event Data1:x%08x Event Data2:"
+ "x%08x SLI Event Type:%d\n",
+ acqe_sli->event_data1, acqe_sli->event_data2,
+ evt_type);
port_name = phba->Port[0];
if (port_name == 0x00)
@@ -4174,29 +4136,46 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
/* fetch the status for this port */
switch (phba->sli4_hba.lnk_info.lnk_no) {
case LPFC_LINK_NUMBER_0:
- status = bf_get(lpfc_sli_misconfigured_port0,
+ status = bf_get(lpfc_sli_misconfigured_port0_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port0_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_1:
- status = bf_get(lpfc_sli_misconfigured_port1,
+ status = bf_get(lpfc_sli_misconfigured_port1_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port1_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_2:
- status = bf_get(lpfc_sli_misconfigured_port2,
+ status = bf_get(lpfc_sli_misconfigured_port2_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port2_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_3:
- status = bf_get(lpfc_sli_misconfigured_port3,
+ status = bf_get(lpfc_sli_misconfigured_port3_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port3_op,
&misconfigured->theEvent);
break;
default:
- status = ~LPFC_SLI_EVENT_STATUS_VALID;
- break;
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "3296 "
+ "LPFC_SLI_EVENT_TYPE_MISCONFIGURED "
+ "event: Invalid link %d",
+ phba->sli4_hba.lnk_info.lnk_no);
+ return;
}
+ /* Skip if optic state unchanged */
+ if (phba->sli4_hba.lnk_info.optic_state == status)
+ return;
+
switch (status) {
case LPFC_SLI_EVENT_STATUS_VALID:
- return; /* no message if the sfp is okay */
+ sprintf(message, "Physical Link is functional");
+ break;
case LPFC_SLI_EVENT_STATUS_NOT_PRESENT:
sprintf(message, "Optics faulted/incorrectly "
"installed/not installed - Reseat optics, "
@@ -4211,15 +4190,26 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
sprintf(message, "Incompatible optics - Replace with "
"compatible optics for card to function.");
break;
+ case LPFC_SLI_EVENT_STATUS_UNQUALIFIED:
+ sprintf(message, "Unqualified optics - Replace with "
+ "Avago optics for Warranty and Technical "
+ "Support - Link is%s operational",
+ (operational) ? "" : " not");
+ break;
+ case LPFC_SLI_EVENT_STATUS_UNCERTIFIED:
+ sprintf(message, "Uncertified optics - Replace with "
+ "Avago-certified optics to enable link "
+ "operation - Link is%s operational",
+ (operational) ? "" : " not");
+ break;
default:
/* firmware is reporting a status we don't know about */
sprintf(message, "Unknown event status x%02x", status);
break;
}
-
+ phba->sli4_hba.lnk_info.optic_state = status;
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "3176 Misconfigured Physical Port - "
- "Port Name %c %s\n", port_name, message);
+ "3176 Port Name %c %s\n", port_name, message);
break;
case LPFC_SLI_EVENT_TYPE_REMOTE_DPORT:
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -5293,6 +5283,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
+ /* initialize optic_state to 0xFF */
+ phba->sli4_hba.lnk_info.optic_state = 0xff;
+
/* Initialize the driver internal SLI layer lists. */
lpfc_sli_setup(phba);
lpfc_sli_queue_setup(phba);
@@ -6159,6 +6152,20 @@ lpfc_create_shost(struct lpfc_hba *phba)
/* Put reference to SCSI host to driver's device private data */
pci_set_drvdata(phba->pcidev, shost);
+ /*
+ * At this point we are fully registered with PSA. In addition,
+ * any initial discovery should be completed.
+ */
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
return 0;
}
@@ -8833,9 +8840,12 @@ found:
* already mapped to this phys_id.
*/
if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) {
- chann[saved_chann] =
- cpup->channel_id;
- saved_chann++;
+ if (saved_chann <=
+ LPFC_FCP_IO_CHAN_MAX) {
+ chann[saved_chann] =
+ cpup->channel_id;
+ saved_chann++;
+ }
goto out;
}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 3fa65338d3f5..4fb3581d4614 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -231,15 +231,13 @@ lpfc_mem_free(struct lpfc_hba *phba)
if (phba->lpfc_hbq_pool)
pci_pool_destroy(phba->lpfc_hbq_pool);
phba->lpfc_hbq_pool = NULL;
-
- if (phba->rrq_pool)
- mempool_destroy(phba->rrq_pool);
+ mempool_destroy(phba->rrq_pool);
phba->rrq_pool = NULL;
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
- if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+ if (phba->sli_rev == LPFC_SLI_REV4) {
mempool_destroy(phba->active_rrq_pool);
phba->active_rrq_pool = NULL;
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index ed9a2c80c4aa..193733e8c823 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t *lp;
IOCB_t *icmd;
struct serv_parm *sp;
+ uint32_t ed_tov;
LPFC_MBOXQ_t *mbox;
struct ls_rjt stat;
int rc;
memset(&stat, 0, sizeof (struct ls_rjt));
- if (vport->port_state <= LPFC_FDISC) {
- /* Before responding to PLOGI, check for pt2pt mode.
- * If we are pt2pt, with an outstanding FLOGI, abort
- * the FLOGI and resend it first.
- */
- if (vport->fc_flag & FC_PT2PT) {
- lpfc_els_abort_flogi(phba);
- if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
- /* If the other side is supposed to initiate
- * the PLOGI anyway, just ACC it now and
- * move on with discovery.
- */
- phba->fc_edtov = FF_DEF_EDTOV;
- phba->fc_ratov = FF_DEF_RATOV;
- /* Start discovery - this should just do
- CLEAR_LA */
- lpfc_disc_start(vport);
- } else
- lpfc_initial_flogi(vport);
- } else {
- stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
- stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
- ndlp, NULL);
- return 0;
- }
- }
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Check for Nport to NPort pt2pt protocol */
if ((vport->fc_flag & FC_PT2PT) &&
!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
/* rcv'ed PLOGI decides what our NPortId will be */
vport->fc_myDID = icmd->un.rcvels.parmRo;
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (mbox == NULL)
- goto out;
- lpfc_config_link(phba, mbox);
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto out;
+
+ ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+ if (sp->cmn.edtovResolution) {
+ /* E_D_TOV ticks are in nanoseconds */
+ ed_tov = (phba->fc_edtov + 999999) / 1000000;
}
+
/*
- * For SLI4, the VFI/VPI are registered AFTER the
- * Nport with the higher WWPN sends us a PLOGI with
- * our assigned NPortId.
+ * For pt-to-pt, use the larger EDTOV
+ * RATOV = 2 * EDTOV
*/
+ if (ed_tov > phba->fc_edtov)
+ phba->fc_edtov = ed_tov;
+ phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+ /* Issue config_link / reg_vfi to account for updated TOV's */
+
if (phba->sli_rev == LPFC_SLI_REV4)
lpfc_issue_reg_vfi(vport);
+ else {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox == NULL)
+ goto out;
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto out;
+ }
+ }
lpfc_can_disctmo(vport);
}
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
goto out;
@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
uint32_t *lp;
IOCB_t *irsp;
struct serv_parm *sp;
+ uint32_t ed_tov;
LPFC_MBOXQ_t *mbox;
+ int rc;
cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1094,18 +1086,63 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
+ if ((vport->fc_flag & FC_PT2PT) &&
+ (vport->fc_flag & FC_PT2PT_PLOGI)) {
+ ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+ if (sp->cmn.edtovResolution) {
+ /* E_D_TOV ticks are in nanoseconds */
+ ed_tov = (phba->fc_edtov + 999999) / 1000000;
+ }
+
+ /*
+ * Use the larger EDTOV
+ * RATOV = 2 * EDTOV for pt-to-pt
+ */
+ if (ed_tov > phba->fc_edtov)
+ phba->fc_edtov = ed_tov;
+ phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+ /* Issue config_link / reg_vfi to account for updated TOV's */
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ lpfc_issue_reg_vfi(vport);
+ } else {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0133 PLOGI: no memory "
+ "for config_link "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
+ goto out;
+ }
+
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto out;
+ }
+ }
+ }
+
+ lpfc_unreg_rpi(vport, ndlp);
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0133 PLOGI: no memory for reg_login "
- "Data: x%x x%x x%x x%x\n",
- ndlp->nlp_DID, ndlp->nlp_state,
- ndlp->nlp_flag, ndlp->nlp_rpi);
+ "0018 PLOGI: no memory for reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
}
- lpfc_unreg_rpi(vport, ndlp);
-
if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
(uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
switch (ndlp->nlp_DID) {
@@ -2299,6 +2336,9 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
if (vport->phba->sli_rev < LPFC_SLI_REV4)
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+ if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+ lpfc_unreg_rpi(vport, ndlp);
+ }
} else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
lpfc_drop_node(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 4679ed4444a7..152b3c8a5428 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -3676,6 +3676,7 @@ static void
lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
struct lpfc_iocbq *rsp_iocb)
{
+ struct lpfc_hba *phba = vport->phba;
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
@@ -3685,6 +3686,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
uint32_t *lp;
uint32_t host_status = DID_OK;
uint32_t rsplen = 0;
+ uint32_t fcpDl;
uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
@@ -3755,13 +3757,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
fcprsp->rspInfo3);
scsi_set_resid(cmnd, 0);
+ fcpDl = be32_to_cpu(fcpcmd->fcpDl);
if (resp_info & RESID_UNDER) {
scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
"9025 FCP Read Underrun, expected %d, "
"residual %d Data: x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
+ fcpDl,
scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
cmnd->underflow);
@@ -3777,7 +3780,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
LOG_FCP | LOG_FCP_ERROR,
"9026 FCP Read Check Error "
"and Underrun Data: x%x x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
+ fcpDl,
scsi_get_resid(cmnd), fcpi_parm,
cmnd->cmnd[0]);
scsi_set_resid(cmnd, scsi_bufflen(cmnd));
@@ -3812,13 +3815,25 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
* Check SLI validation that all the transfer was actually done
* (fcpi_parm should be zero). Apply check only to reads.
*/
- } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
+ } else if (fcpi_parm) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
- "9029 FCP Read Check Error Data: "
+ "9029 FCP %s Check Error xri x%x Data: "
"x%x x%x x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
- be32_to_cpu(fcprsp->rspResId),
+ ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ?
+ "Read" : "Write"),
+ ((phba->sli_rev == LPFC_SLI_REV4) ?
+ lpfc_cmd->cur_iocbq.sli4_xritag :
+ rsp_iocb->iocb.ulpContext),
+ fcpDl, be32_to_cpu(fcprsp->rspResId),
fcpi_parm, cmnd->cmnd[0], scsi_status);
+
+ /* There is some issue with the LPe12000 that causes it
+ * to miscalculate the fcpi_parm and falsely trip this
+ * recovery logic. Detect this case and don't error when true.
+ */
+ if (fcpi_parm > fcpDl)
+ goto out;
+
switch (scsi_status) {
case SAM_STAT_GOOD:
case SAM_STAT_CHECK_CONDITION:
@@ -3908,9 +3923,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
uint32_t logit = LOG_FCP;
/* Sanity check on return of outstanding command */
- if (!(lpfc_cmd->pCmd))
- return;
cmd = lpfc_cmd->pCmd;
+ if (!cmd)
+ return;
shost = cmd->device->host;
lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
@@ -4446,15 +4461,7 @@ lpfc_info(struct Scsi_Host *host)
phba->Port);
}
len = strlen(lpfcinfobuf);
- if (phba->sli_rev <= LPFC_SLI_REV3) {
- link_speed = lpfc_sli_port_speed_get(phba);
- } else {
- if (phba->sli4_hba.link_state.logical_speed)
- link_speed =
- phba->sli4_hba.link_state.logical_speed;
- else
- link_speed = phba->sli4_hba.link_state.speed;
- }
+ link_speed = lpfc_sli_port_speed_get(phba);
if (link_speed != 0)
snprintf(lpfcinfobuf + len, 384-len,
" Logical Link Speed: %d Mbps", link_speed);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f9585cdd8933..92dfd6a5178c 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -14842,10 +14842,12 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
struct lpfc_dmabuf *h_buf;
struct hbq_dmabuf *seq_dmabuf = NULL;
struct hbq_dmabuf *temp_dmabuf = NULL;
+ uint8_t found = 0;
INIT_LIST_HEAD(&dmabuf->dbuf.list);
dmabuf->time_stamp = jiffies;
new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+
/* Use the hdr_buf to find the sequence that this frame belongs to */
list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
temp_hdr = (struct fc_frame_header *)h_buf->virt;
@@ -14885,7 +14887,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
return seq_dmabuf;
}
/* find the correct place in the sequence to insert this frame */
- list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+ d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
+ while (!found) {
temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
/*
@@ -14895,9 +14898,17 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
if (be16_to_cpu(new_hdr->fh_seq_cnt) >
be16_to_cpu(temp_hdr->fh_seq_cnt)) {
list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
- return seq_dmabuf;
+ found = 1;
+ break;
}
+
+ if (&d_buf->list == &seq_dmabuf->dbuf.list)
+ break;
+ d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
}
+
+ if (found)
+ return seq_dmabuf;
return NULL;
}
@@ -16173,7 +16184,7 @@ fail_fcf_read:
}
/**
- * lpfc_check_next_fcf_pri
+ * lpfc_check_next_fcf_pri_level
* phba pointer to the lpfc_hba struct for this port.
* This routine is called from the lpfc_sli4_fcf_rr_next_index_get
* routine when the rr_bmask is empty. The FCF indecies are put into the
@@ -16329,8 +16340,12 @@ next_priority:
if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
- LPFC_FCF_FLOGI_FAILED)
+ LPFC_FCF_FLOGI_FAILED) {
+ if (list_is_singular(&phba->fcf.fcf_pri_list))
+ return LPFC_FCOE_FCF_NEXT_NONE;
+
goto next_priority;
+ }
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2845 Get next roundrobin failover FCF (x%x)\n",
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 1e916e16ce98..cd780c29495a 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -442,6 +442,7 @@ struct lpfc_sli4_lnk_info {
#define LPFC_LNK_GE 0x0 /* FCoE */
#define LPFC_LNK_FC 0x1 /* FC */
uint8_t lnk_no;
+ uint8_t optic_state;
};
#define LPFC_SLI4_HANDLER_CNT (LPFC_FCP_IO_CHAN_MAX+ \
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index ea53aa664759..4dc22562aaf1 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "11.0.0.0."
+#define LPFC_DRIVER_VERSION "11.0.0.10."
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 769012663a8f..b3f85def18cc 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -393,6 +393,14 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
+ /* At this point we are fully registered with SCSI Layer. */
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = phba->pport->fdmi_hba_mask;
+ vport->fdmi_port_mask = phba->pport->fdmi_port_mask;
+ }
+
/*
* In SLI4, the vpi must be activated before it can be used
* by the port.
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 11393ebf1a68..83658acddd58 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -2020,8 +2020,10 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
_base_free_irq(ioc);
_base_disable_msix(ioc);
- if (ioc->msix96_vector)
+ if (ioc->msix96_vector) {
kfree(ioc->replyPostRegisterIndex);
+ ioc->replyPostRegisterIndex = NULL;
+ }
if (ioc->chip_phys) {
iounmap(ioc->chip);
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
index 9270d15ff1a4..f6fc4a705924 100644
--- a/drivers/scsi/mvsas/mv_94xx.c
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -330,6 +330,51 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
}
+static void mvs_94xx_sgpio_init(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+ u32 tmp;
+
+ tmp = mr32(MVS_HST_CHIP_CONFIG);
+ tmp |= 0x100;
+ mw32(MVS_HST_CHIP_CONFIG, tmp);
+
+ mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT);
+
+ mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ 8 << MVS_SGPIO_CFG1_LOWA_SHIFT |
+ 8 << MVS_SGPIO_CFG1_HIA_SHIFT |
+ 4 << MVS_SGPIO_CFG1_LOWB_SHIFT |
+ 4 << MVS_SGPIO_CFG1_HIB_SHIFT |
+ 2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT |
+ 1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT
+ );
+
+ mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ (300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */
+ 66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/
+ );
+
+ mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ MVS_SGPIO_CFG0_ENABLE |
+ MVS_SGPIO_CFG0_BLINKA |
+ MVS_SGPIO_CFG0_BLINKB |
+ /* 3*4 data bits / PDU */
+ (12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT
+ );
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ DEFAULT_SGPIO_BITS);
+
+ mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ ((mvi->id * 4) + 3) << (8 * 3) |
+ ((mvi->id * 4) + 2) << (8 * 2) |
+ ((mvi->id * 4) + 1) << (8 * 1) |
+ ((mvi->id * 4) + 0) << (8 * 0));
+
+}
+
static int mvs_94xx_init(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
@@ -533,6 +578,8 @@ static int mvs_94xx_init(struct mvs_info *mvi)
/* Enable SRS interrupt */
mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+ mvs_94xx_sgpio_init(mvi);
+
return 0;
}
@@ -1005,6 +1052,92 @@ static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
}
+static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
+ u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data)
+{
+ int i;
+
+ switch (reg_type) {
+
+ case SAS_GPIO_REG_TX_GP:
+ if (reg_index == 0)
+ return -EINVAL;
+
+ if (reg_count > 1)
+ return -EINVAL;
+
+ if (reg_count == 0)
+ return 0;
+
+ /* maximum supported bits = hosts * 4 drives * 3 bits */
+ for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) {
+
+ /* select host */
+ struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)];
+
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+
+ int drive = (i/3) & (4-1); /* drive number on host */
+ u32 block = mr32(MVS_SGPIO_DCTRL +
+ MVS_SGPIO_HOST_OFFSET * mvi->id);
+
+
+ /*
+ * if bit is set then create a mask with the first
+ * bit of the drive set in the mask ...
+ */
+ u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
+ 1<<(24-drive*8) : 0;
+
+ /*
+ * ... and then shift it to the right position based
+ * on the led type (activity/id/fail)
+ */
+ switch (i%3) {
+ case 0: /* activity */
+ block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
+ << (24-drive*8));
+ /* hardwire activity bit to SOF */
+ block |= LED_BLINKA_SOF << (
+ MVS_SGPIO_DCTRL_ACT_SHIFT +
+ (24-drive*8));
+ break;
+ case 1: /* id */
+ block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
+ << (24-drive*8));
+ block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
+ break;
+ case 2: /* fail */
+ block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
+ << (24-drive*8));
+ block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
+ break;
+ }
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ block);
+
+ }
+
+ return reg_count;
+
+ case SAS_GPIO_REG_TX:
+ if (reg_index + reg_count > mvs_prv->n_host)
+ return -EINVAL;
+
+ for (i = 0; i < reg_count; i++) {
+ struct mvs_info *mvi = mvs_prv->mvi[i+reg_index];
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ be32_to_cpu(((u32 *) write_data)[i]));
+ }
+ return reg_count;
+ }
+ return -ENOSYS;
+}
+
const struct mvs_dispatch mvs_94xx_dispatch = {
"mv94xx",
mvs_94xx_init,
@@ -1057,5 +1190,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
mvs_94xx_fix_dma,
mvs_94xx_tune_interrupt,
mvs_94xx_non_spec_ncq_error,
+ mvs_94xx_gpio_write,
};
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
index 14e197497b46..578960803a00 100644
--- a/drivers/scsi/mvsas/mv_94xx.h
+++ b/drivers/scsi/mvsas/mv_94xx.h
@@ -38,6 +38,10 @@ enum VANIR_REVISION_ID {
VANIR_C2_REV = 0xC2,
};
+enum host_registers {
+ MVS_HST_CHIP_CONFIG = 0x10104, /* chip configuration */
+};
+
enum hw_registers {
MVS_GBL_CTL = 0x04, /* global control */
MVS_GBL_INT_STAT = 0x00, /* global irq status */
@@ -239,6 +243,73 @@ struct mvs_prd {
__le32 im_len;
} __attribute__ ((packed));
+enum sgpio_registers {
+ MVS_SGPIO_HOST_OFFSET = 0x100, /* offset between hosts */
+
+ MVS_SGPIO_CFG0 = 0xc200,
+ MVS_SGPIO_CFG0_ENABLE = (1 << 0), /* enable pins */
+ MVS_SGPIO_CFG0_BLINKB = (1 << 1), /* blink generators */
+ MVS_SGPIO_CFG0_BLINKA = (1 << 2),
+ MVS_SGPIO_CFG0_INVSCLK = (1 << 3), /* invert signal? */
+ MVS_SGPIO_CFG0_INVSLOAD = (1 << 4),
+ MVS_SGPIO_CFG0_INVSDOUT = (1 << 5),
+ MVS_SGPIO_CFG0_SLOAD_FALLEDGE = (1 << 6), /* rise/fall edge? */
+ MVS_SGPIO_CFG0_SDOUT_FALLEDGE = (1 << 7),
+ MVS_SGPIO_CFG0_SDIN_RISEEDGE = (1 << 8),
+ MVS_SGPIO_CFG0_MAN_BITLEN_SHIFT = 18, /* bits/frame manual mode */
+ MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT = 24, /* bits/frame auto mode */
+
+ MVS_SGPIO_CFG1 = 0xc204, /* blink timing register */
+ MVS_SGPIO_CFG1_LOWA_SHIFT = 0, /* A off time */
+ MVS_SGPIO_CFG1_HIA_SHIFT = 4, /* A on time */
+ MVS_SGPIO_CFG1_LOWB_SHIFT = 8, /* B off time */
+ MVS_SGPIO_CFG1_HIB_SHIFT = 12, /* B on time */
+ MVS_SGPIO_CFG1_MAXACTON_SHIFT = 16, /* max activity on time */
+
+ /* force activity off time */
+ MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT = 20,
+ /* stretch activity on time */
+ MVS_SGPIO_CFG1_STRCHACTON_SHIFT = 24,
+ /* stretch activiity off time */
+ MVS_SGPIO_CFG1_STRCHACTOFF_SHIFT = 28,
+
+
+ MVS_SGPIO_CFG2 = 0xc208, /* clock speed register */
+ MVS_SGPIO_CFG2_CLK_SHIFT = 0,
+ MVS_SGPIO_CFG2_BLINK_SHIFT = 20,
+
+ MVS_SGPIO_CTRL = 0xc20c, /* SDOUT/SDIN mode control */
+ MVS_SGPIO_CTRL_SDOUT_AUTO = 2,
+ MVS_SGPIO_CTRL_SDOUT_SHIFT = 2,
+
+ MVS_SGPIO_DSRC = 0xc220, /* map ODn bits to drives */
+
+ MVS_SGPIO_DCTRL = 0xc238,
+ MVS_SGPIO_DCTRL_ERR_SHIFT = 0,
+ MVS_SGPIO_DCTRL_LOC_SHIFT = 3,
+ MVS_SGPIO_DCTRL_ACT_SHIFT = 5,
+};
+
+enum sgpio_led_status {
+ LED_OFF = 0,
+ LED_ON = 1,
+ LED_BLINKA = 2,
+ LED_BLINKA_INV = 3,
+ LED_BLINKA_SOF = 4,
+ LED_BLINKA_EOF = 5,
+ LED_BLINKB = 6,
+ LED_BLINKB_INV = 7,
+};
+
+#define DEFAULT_SGPIO_BITS ((LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 3) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 2) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 1) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 0))
+
/*
* these registers are accessed through port vendor
* specific address/data registers
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 675e7fab0796..c7c250519c4b 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -84,6 +84,8 @@ static struct sas_domain_function_template mvs_transport_ops = {
.lldd_port_formed = mvs_port_formed,
.lldd_port_deformed = mvs_port_deformed,
+ .lldd_write_gpio = mvs_gpio_write,
+
};
static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 9c780740fb82..83cd3ea2df41 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -737,8 +737,8 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
mv_dprintk("device %016llx not ready.\n",
SAS_ADDR(dev->sas_addr));
- rc = SAS_PHY_DOWN;
- return rc;
+ rc = SAS_PHY_DOWN;
+ return rc;
}
tei.port = dev->port->lldd_port;
if (tei.port && !tei.port->port_attached && !tmf) {
@@ -2105,3 +2105,16 @@ int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
return 0;
}
+int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data)
+{
+ struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+ struct mvs_info *mvi = mvs_prv->mvi[0];
+
+ if (MVS_CHIP_DISP->gpio_write) {
+ return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
+ reg_index, reg_count, write_data);
+ }
+
+ return -ENOSYS;
+}
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index dc409c04747a..f9afd4cdd4c4 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -103,6 +103,7 @@ enum dev_reset {
};
struct mvs_info;
+struct mvs_prv_info;
struct mvs_dispatch {
char *name;
@@ -172,6 +173,8 @@ struct mvs_dispatch {
int buf_len, int from, void *prd);
void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
void (*non_spec_ncq_error)(struct mvs_info *mvi);
+ int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
+ u8 reg_index, u8 reg_count, u8 *write_data);
};
@@ -476,5 +479,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
+int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data);
#endif
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 0cccd6033feb..d8a2b5185f56 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -170,10 +170,7 @@ static int _osd_get_print_system_info(struct osd_dev *od,
/* FIXME: Where are the time utilities */
pFirst = get_attrs[a++].val_ptr;
- OSD_INFO("CLOCK [0x%02x%02x%02x%02x%02x%02x]\n",
- ((char *)pFirst)[0], ((char *)pFirst)[1],
- ((char *)pFirst)[2], ((char *)pFirst)[3],
- ((char *)pFirst)[4], ((char *)pFirst)[5]);
+ OSD_INFO("CLOCK [0x%6phN]\n", pFirst);
if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
unsigned len = get_attrs[a].len;
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig
index a0f732b138e4..10aa18ba05fd 100644
--- a/drivers/scsi/qla2xxx/Kconfig
+++ b/drivers/scsi/qla2xxx/Kconfig
@@ -18,9 +18,6 @@ config SCSI_QLA_FC
2322, 6322 ql2322_fw.bin
24xx, 54xx ql2400_fw.bin
25xx ql2500_fw.bin
- 2031 ql2600_fw.bin
- 8031 ql8300_fw.bin
- 27xx ql2700_fw.bin
Upon request, the driver caches the firmware image until
the driver is unloaded.
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6b942d9e5b74..6992ebc50c87 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -824,6 +824,41 @@ static struct bin_attribute sysfs_reset_attr = {
};
static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ int type;
+ int rval = 0;
+ port_id_t did;
+
+ type = simple_strtol(buf, NULL, 10);
+
+ did.b.domain = (type & 0x00ff0000) >> 16;
+ did.b.area = (type & 0x0000ff00) >> 8;
+ did.b.al_pa = (type & 0x000000ff);
+
+ ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+ did.b.domain, did.b.area, did.b.al_pa);
+
+ ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+ rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+ return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+ .attr = {
+ .name = "issue_logo",
+ .mode = S_IWUSR,
+ },
+ .size = 0,
+ .write = qla2x00_issue_logo,
+};
+
+static ssize_t
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -937,6 +972,7 @@ static struct sysfs_entry {
{ "vpd", &sysfs_vpd_attr, 1 },
{ "sfp", &sysfs_sfp_attr, 1 },
{ "reset", &sysfs_reset_attr, },
+ { "issue_logo", &sysfs_issue_logo_attr, },
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
{ NULL },
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34dc9a35670b..cd0d94ea7f74 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,25 +14,24 @@
* | Module Init and Probe | 0x017f | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e-0x0170 |
- * | Mailbox commands | 0x118d | 0x1115-0x1116 |
- * | | | 0x111a-0x111b |
+ * | Mailbox commands | 0x1192 | |
+ * | | | |
* | Device Discovery | 0x2016 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2099-0x20a4 |
- * | Queue Command and IO tracing | 0x3075 | 0x300b |
+ * | Queue Command and IO tracing | 0x3074 | 0x300b |
* | | | 0x3027-0x3028 |
* | | | 0x303d-0x3041 |
* | | | 0x302d,0x3033 |
* | | | 0x3036,0x3038 |
* | | | 0x303a |
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
- * | Async Events | 0x508a | 0x502b-0x502f |
- * | | | 0x5047 |
+ * | Async Events | 0x5089 | 0x502b-0x502f |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
* | | | 0x507b,0x505f |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e2 | 0x7018,0x702e |
+ * | User Space Interactions | 0x70e65 | 0x7018,0x702e |
* | | | 0x7020,0x7024 |
* | | | 0x7039,0x7045 |
* | | | 0x7073-0x7075 |
@@ -60,15 +59,11 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc00c | |
- * | Misc | 0xd300 | 0xd016-0xd017 |
- * | | | 0xd021,0xd024 |
- * | | | 0xd025,0xd029 |
- * | | | 0xd02a,0xd02e |
- * | | | 0xd031-0xd0ff |
+ * | Misc | 0xd301 | 0xd031-0xd0ff |
* | | | 0xd101-0xd1fe |
* | | | 0xd214-0xd2fe |
* | Target Mode | 0xe080 | |
- * | Target Mode Management | 0xf096 | 0xf002 |
+ * | Target Mode Management | 0xf09b | 0xf002 |
* | | | 0xf046-0xf049 |
* | Target Mode Task Management | 0x1000d | |
* ----------------------------------------------------------------------
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 388d79088b59..9872f3429e53 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
#define LOOP_DOWN_TIME 255 /* 240 */
#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30)
-#define DEFAULT_OUTSTANDING_COMMANDS 1024
+#define DEFAULT_OUTSTANDING_COMMANDS 4096
#define MIN_OUTSTANDING_COMMANDS 128
/* ISP request and response entry counts (37-65535) */
@@ -267,11 +267,13 @@
#define REQUEST_ENTRY_CNT_2200 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_83XX 8192 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX 4096 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT 32768 /* Entries for offload case */
struct req_que;
struct qla_tgt_sess;
@@ -309,6 +311,14 @@ struct srb_cmd {
/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
+struct els_logo_payload {
+ uint8_t opcode;
+ uint8_t rsvd[3];
+ uint8_t s_id[3];
+ uint8_t rsvd1[1];
+ uint8_t wwpn[WWN_SIZE];
+};
+
/*
* SRB extensions.
*/
@@ -322,6 +332,15 @@ struct srb_iocb {
uint16_t data[2];
} logio;
struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+ uint32_t flags;
+ uint32_t els_cmd;
+ struct completion comp;
+ struct els_logo_payload *els_logo_pyld;
+ dma_addr_t els_logo_pyld_dma;
+ } els_logo;
+ struct {
/*
* Values for flags field below are as
* defined in tsk_mgmt_entry struct
@@ -382,7 +401,7 @@ struct srb_iocb {
#define SRB_FXIOCB_DCMD 10
#define SRB_FXIOCB_BCMD 11
#define SRB_ABT_CMD 12
-
+#define SRB_ELS_DCMD 13
typedef struct srb {
atomic_t ref_count;
@@ -891,6 +910,7 @@ struct mbx_cmd_32 {
#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */
#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */
#define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34 /* Memory Offload ctrl/Stat*/
#define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */
#define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */
#define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */
@@ -2695,11 +2715,16 @@ struct isp_operations {
struct scsi_qla_host;
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
struct qla_msix_entry {
int have_irq;
uint32_t vector;
uint16_t entry;
struct rsp_que *rsp;
+ struct irq_affinity_notify irq_notify;
+ int cpuid;
};
#define WATCH_INTERVAL 1 /* number of seconds */
@@ -2910,12 +2935,15 @@ struct qlt_hw_data {
uint32_t num_qfull_cmds_dropped;
spinlock_t q_full_lock;
uint32_t leak_exchg_thresh_hold;
+ spinlock_t sess_lock;
+ int rspq_vector_cpuid;
+ spinlock_t atio_lock ____cacheline_aligned;
};
#define MAX_QFULL_CMDS_ALLOC 8192
#define Q_FULL_THRESH_HOLD_PERCENT 90
#define Q_FULL_THRESH_HOLD(ha) \
- ((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+ ((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
#define LEAK_EXCHG_THRESH_HOLD_PERCENT 75 /* 75 percent */
@@ -2962,10 +2990,12 @@ struct qla_hw_data {
uint32_t isp82xx_no_md_cap:1;
uint32_t host_shutting_down:1;
uint32_t idc_compl_status:1;
-
uint32_t mr_reset_hdlr_active:1;
uint32_t mr_intr_valid:1;
+
uint32_t fawwpn_enabled:1;
+ uint32_t exlogins_enabled:1;
+ uint32_t exchoffld_enabled:1;
/* 35 bits */
} flags;
@@ -3237,6 +3267,21 @@ struct qla_hw_data {
void *async_pd;
dma_addr_t async_pd_dma;
+#define ENABLE_EXTENDED_LOGIN BIT_7
+
+ /* Extended Logins */
+ void *exlogin_buf;
+ dma_addr_t exlogin_buf_dma;
+ int exlogin_size;
+
+#define ENABLE_EXCHANGE_OFFLD BIT_2
+
+ /* Exchange Offload */
+ void *exchoffld_buf;
+ dma_addr_t exchoffld_buf_dma;
+ int exchoffld_size;
+ int exchoffld_count;
+
void *swl;
/* These are used by mailbox operations. */
@@ -3279,8 +3324,14 @@ struct qla_hw_data {
#define RISC_START_ADDRESS_2100 0x1000
#define RISC_START_ADDRESS_2300 0x800
#define RISC_START_ADDRESS_2400 0x100000
- uint16_t fw_xcb_count;
- uint16_t fw_iocb_count;
+
+ uint16_t orig_fw_tgt_xcb_count;
+ uint16_t cur_fw_tgt_xcb_count;
+ uint16_t orig_fw_xcb_count;
+ uint16_t cur_fw_xcb_count;
+ uint16_t orig_fw_iocb_count;
+ uint16_t cur_fw_iocb_count;
+ uint16_t fw_max_fcf_count;
uint32_t fw_shared_ram_start;
uint32_t fw_shared_ram_end;
@@ -3323,6 +3374,9 @@ struct qla_hw_data {
uint32_t chain_offset;
struct dentry *dfs_dir;
struct dentry *dfs_fce;
+ struct dentry *dfs_tgt_counters;
+ struct dentry *dfs_fw_resource_cnt;
+
dma_addr_t fce_dma;
void *fce;
uint32_t fce_bufs;
@@ -3480,6 +3534,18 @@ struct qla_hw_data {
int allow_cna_fw_dump;
};
+struct qla_tgt_counters {
+ uint64_t qla_core_sbt_cmd;
+ uint64_t core_qla_que_buf;
+ uint64_t qla_core_ret_ctio;
+ uint64_t core_qla_snd_status;
+ uint64_t qla_core_ret_sta_ctio;
+ uint64_t core_qla_free_cmd;
+ uint64_t num_q_full_sent;
+ uint64_t num_alloc_iocb_failed;
+ uint64_t num_term_xchg_sent;
+};
+
/*
* Qlogic scsi host structure
*/
@@ -3595,6 +3661,10 @@ typedef struct scsi_qla_host {
atomic_t generation_tick;
/* Time when global fcport update has been scheduled */
int total_fcport_update_gen;
+ /* List of pending LOGOs, protected by tgt_mutex */
+ struct list_head logo_list;
+ /* List of pending PLOGI acks, protected by hw lock */
+ struct list_head plogi_ack_list;
uint32_t vp_abort_cnt;
@@ -3632,6 +3702,7 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
struct qla8044_reset_template reset_tmplt;
+ struct qla_tgt_counters tgt_counters;
} scsi_qla_host_t;
#define SET_VP_IDX 1
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 15cf074ffa3c..cd8b96a4b0dd 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,85 @@ static struct dentry *qla2x00_dfs_root;
static atomic_t qla2x00_dfs_root_count;
static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+ struct qla_hw_data *ha = vha->hw;
+
+ seq_puts(s, "FW Resource count\n\n");
+ seq_printf(s, "Original TGT exchg count[%d]\n",
+ ha->orig_fw_tgt_xcb_count);
+ seq_printf(s, "current TGT exchg count[%d]\n",
+ ha->cur_fw_tgt_xcb_count);
+ seq_printf(s, "original Initiator Exchange count[%d]\n",
+ ha->orig_fw_xcb_count);
+ seq_printf(s, "Current Initiator Exchange count[%d]\n",
+ ha->cur_fw_xcb_count);
+ seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+ seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+ seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+ seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+ return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+ .open = qla_dfs_fw_resource_cnt_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+
+ seq_puts(s, "Target Counters\n");
+ seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+ vha->tgt_counters.qla_core_sbt_cmd);
+ seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_sta_ctio);
+ seq_printf(s, "qla_core_ret_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_ctio);
+ seq_printf(s, "core_qla_que_buf = %lld\n",
+ vha->tgt_counters.core_qla_que_buf);
+ seq_printf(s, "core_qla_snd_status = %lld\n",
+ vha->tgt_counters.core_qla_snd_status);
+ seq_printf(s, "core_qla_free_cmd = %lld\n",
+ vha->tgt_counters.core_qla_free_cmd);
+ seq_printf(s, "num alloc iocb failed = %lld\n",
+ vha->tgt_counters.num_alloc_iocb_failed);
+ seq_printf(s, "num term exchange sent = %lld\n",
+ vha->tgt_counters.num_term_xchg_sent);
+ seq_printf(s, "num Q full sent = %lld\n",
+ vha->tgt_counters.num_q_full_sent);
+
+ return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+ .open = qla_dfs_tgt_counters_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
{
scsi_qla_host_t *vha = s->private;
@@ -146,6 +225,22 @@ create_dir:
atomic_inc(&qla2x00_dfs_root_count);
create_nodes:
+ ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+ S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
+ if (!ha->dfs_fw_resource_cnt) {
+ ql_log(ql_log_warn, vha, 0x00fd,
+ "Unable to create debugFS fw_resource_count node.\n");
+ goto out;
+ }
+
+ ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+ ha->dfs_dir, vha, &dfs_tgt_counters_ops);
+ if (!ha->dfs_tgt_counters) {
+ ql_log(ql_log_warn, vha, 0xd301,
+ "Unable to create debugFS tgt_counters node.\n");
+ goto out;
+ }
+
ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
&dfs_fce_ops);
if (!ha->dfs_fce) {
@@ -161,6 +256,17 @@ int
qla2x00_dfs_remove(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+
+ if (ha->dfs_fw_resource_cnt) {
+ debugfs_remove(ha->dfs_fw_resource_cnt);
+ ha->dfs_fw_resource_cnt = NULL;
+ }
+
+ if (ha->dfs_tgt_counters) {
+ debugfs_remove(ha->dfs_tgt_counters);
+ ha->dfs_tgt_counters = NULL;
+ }
+
if (ha->dfs_fce) {
debugfs_remove(ha->dfs_fce);
ha->dfs_fce = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 7686bfe9a4a9..0103e468e357 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,6 +44,8 @@ extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
+extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+
extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
@@ -117,6 +119,8 @@ extern int ql2xdontresethba;
extern uint64_t ql2xmaxlun;
extern int ql2xmdcapmask;
extern int ql2xmdenable;
+extern int ql2xexlogins;
+extern int ql2xexchoffld;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +139,10 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -323,8 +331,7 @@ extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
- uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -766,4 +773,11 @@ extern int qla8044_abort_isp(scsi_qla_host_t *);
extern int qla8044_check_fw_alive(struct scsi_qla_host *);
extern void qlt_host_reset_handler(struct qla_hw_data *ha);
+extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
+ uint16_t *);
+extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *, dma_addr_t);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
+
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 16a1935cc9c1..52a87657c7dd 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1766,10 +1766,10 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
(ql2xmultique_tag || ql2xmaxqueues > 1)))
req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
else {
- if (ha->fw_xcb_count <= ha->fw_iocb_count)
- req->num_outstanding_cmds = ha->fw_xcb_count;
+ if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
+ req->num_outstanding_cmds = ha->cur_fw_xcb_count;
else
- req->num_outstanding_cmds = ha->fw_iocb_count;
+ req->num_outstanding_cmds = ha->cur_fw_iocb_count;
}
req->outstanding_cmds = kzalloc(sizeof(srb_t *) *
@@ -1843,9 +1843,23 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init, vha, 0x00ca,
"Starting firmware.\n");
+ if (ql2xexlogins)
+ ha->flags.exlogins_enabled = 1;
+
+ if (ql2xexchoffld)
+ ha->flags.exchoffld_enabled = 1;
+
rval = qla2x00_execute_fw(vha, srisc_address);
/* Retrieve firmware information. */
if (rval == QLA_SUCCESS) {
+ rval = qla2x00_set_exlogins_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
+ rval = qla2x00_set_exchoffld_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
enable_82xx_npiv:
fw_major_version = ha->fw_major_version;
if (IS_P3P_TYPE(ha))
@@ -1864,9 +1878,7 @@ enable_82xx_npiv:
ha->max_npiv_vports =
MIN_MULTI_ID_FABRIC - 1;
}
- qla2x00_get_resource_cnts(vha, NULL,
- &ha->fw_xcb_count, NULL, &ha->fw_iocb_count,
- &ha->max_npiv_vports, NULL);
+ qla2x00_get_resource_cnts(vha);
/*
* Allocate the array of outstanding commands
@@ -2248,7 +2260,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
if (IS_FWI2_CAPABLE(ha)) {
mid_init_cb->options = cpu_to_le16(BIT_1);
mid_init_cb->init_cb.execution_throttle =
- cpu_to_le16(ha->fw_xcb_count);
+ cpu_to_le16(ha->cur_fw_xcb_count);
/* D-Port Status */
if (IS_DPORT_CAPABLE(ha))
mid_init_cb->init_cb.firmware_options_1 |=
@@ -3053,6 +3065,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
atomic_set(&vha->loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
+
+ /*
+ * Process any ATIO queue entries that came in
+ * while we weren't online.
+ */
+ if (qla_tgt_mode_enabled(vha)) {
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+ spin_lock_irqsave(&ha->tgt.atio_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(
+ &ha->tgt.atio_lock, flags);
+ } else {
+ spin_lock_irqsave(&ha->hardware_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
+ }
+ }
}
}
@@ -4907,7 +4939,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
- unsigned long flags;
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
@@ -4929,17 +4960,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
- vha->flags.online = 1;
-
- /*
- * Process any ATIO queue entries that came in
- * while we weren't online.
- */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla_tgt_mode_enabled(vha))
- qlt_24xx_process_atio_queue(vha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index fee9eb7c8a60..a6b7f1588aa4 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -258,6 +258,8 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
(sp->type == SRB_FXIOCB_DCMD))
init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+ if (sp->type == SRB_ELS_DCMD)
+ init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
}
static inline int
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c49df34e9b35..b41265a75ed5 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1868,6 +1868,7 @@ skip_cmd_array:
}
queuing_error:
+ vha->tgt_counters.num_alloc_iocb_failed++;
return pkt;
}
@@ -2010,6 +2011,190 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
}
static void
+qla2x00_els_dcmd_sp_free(void *ptr, void *data)
+{
+ struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ kfree(sp->fcport);
+
+ if (elsio->u.els_logo.els_logo_pyld)
+ dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+ elsio->u.els_logo.els_logo_pyld,
+ elsio->u.els_logo.els_logo_pyld_dma);
+
+ del_timer(&elsio->timer);
+ qla2x00_rel_sp(vha, sp);
+}
+
+static void
+qla2x00_els_dcmd_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags = 0;
+
+ ql_dbg(ql_dbg_io, vha, 0x3069,
+ "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
+ sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa);
+
+ /* Abort the exchange */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x3070,
+ "mbx abort_command failed.\n");
+ } else {
+ ql_dbg(ql_dbg_io, vha, 0x3071,
+ "mbx abort_command success.\n");
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+static void
+qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ fc_port_t *fcport = sp->fcport;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ struct scsi_qla_host *vha = fcport->vha;
+
+ ql_dbg(ql_dbg_io, vha, 0x3072,
+ "%s hdl=%x, portid=%02x%02x%02x done\n",
+ sp->name, sp->handle, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+int
+qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
+ port_id_t remote_did)
+{
+ srb_t *sp;
+ fc_port_t *fcport = NULL;
+ struct srb_iocb *elsio = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ struct els_logo_payload logo_pyld;
+ int rval = QLA_SUCCESS;
+
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ kfree(fcport);
+ ql_log(ql_log_info, vha, 0x70e6,
+ "SRB allocation failed\n");
+ return -ENOMEM;
+ }
+
+ elsio = &sp->u.iocb_cmd;
+ fcport->loop_id = 0xFFFF;
+ fcport->d_id.b.domain = remote_did.b.domain;
+ fcport->d_id.b.area = remote_did.b.area;
+ fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+ ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ sp->type = SRB_ELS_DCMD;
+ sp->name = "ELS_DCMD";
+ sp->fcport = fcport;
+ qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+ elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
+ sp->done = qla2x00_els_dcmd_sp_done;
+ sp->free = qla2x00_els_dcmd_sp_free;
+
+ elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
+ DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
+ GFP_KERNEL);
+
+ if (!elsio->u.els_logo.els_logo_pyld) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
+
+ elsio->u.els_logo.els_cmd = els_opcode;
+ logo_pyld.opcode = els_opcode;
+ logo_pyld.s_id[0] = vha->d_id.b.al_pa;
+ logo_pyld.s_id[1] = vha->d_id.b.area;
+ logo_pyld.s_id[2] = vha->d_id.b.domain;
+ host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
+ memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
+
+ memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
+ sizeof(struct els_logo_payload));
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_io, vha, 0x3074,
+ "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
+ sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ wait_for_completion(&elsio->u.els_logo.comp);
+
+ sp->free(vha, sp);
+ return rval;
+}
+
+static void
+qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ els_iocb->entry_type = ELS_IOCB_TYPE;
+ els_iocb->entry_count = 1;
+ els_iocb->sys_define = 0;
+ els_iocb->entry_status = 0;
+ els_iocb->handle = sp->handle;
+ els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ els_iocb->tx_dsd_count = 1;
+ els_iocb->vp_index = vha->vp_idx;
+ els_iocb->sof_type = EST_SOFI3;
+ els_iocb->rx_dsd_count = 0;
+ els_iocb->opcode = elsio->u.els_logo.els_cmd;
+
+ els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ els_iocb->control_flags = 0;
+
+ els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+ els_iocb->tx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+
+ els_iocb->rx_byte_count = 0;
+ els_iocb->rx_address[0] = 0;
+ els_iocb->rx_address[1] = 0;
+ els_iocb->rx_len = 0;
+
+ sp->fcport->vha->qla_stats.control_requests++;
+}
+
+static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
@@ -2623,6 +2808,9 @@ qla2x00_start_sp(srb_t *sp)
qlafx00_abort_iocb(sp, pkt) :
qla24xx_abort_iocb(sp, pkt);
break;
+ case SRB_ELS_DCMD:
+ qla24xx_els_logo_iocb(sp, pkt);
+ break;
default:
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ccf6a7f99024..d4d65eb0e9b4 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+ const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -1418,6 +1422,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
case SRB_CT_CMD:
type = "ct pass-through";
break;
+ case SRB_ELS_DCMD:
+ type = "Driver ELS logo";
+ ql_dbg(ql_dbg_user, vha, 0x5047,
+ "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
+ sp->done(vha, sp, 0);
+ return;
default:
ql_dbg(ql_dbg_user, vha, 0x503e,
"Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
@@ -2542,6 +2552,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
if (!vha->flags.online)
return;
+ if (rsp->msix->cpuid != smp_processor_id()) {
+ /* if kernel does not notify qla of IRQ's CPU change,
+ * then set it here.
+ */
+ rsp->msix->cpuid = smp_processor_id();
+ ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
+ }
+
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
@@ -2587,8 +2605,14 @@ process_err:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
case ABTS_RECV_24XX:
- /* ensure that the ATIO queue is empty */
- qlt_24xx_process_atio_queue(vha);
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ /* ensure that the ATIO queue is empty */
+ qlt_handle_abts_recv(vha, (response_t *)pkt);
+ break;
+ } else {
+ /* drop through */
+ qlt_24xx_process_atio_queue(vha, 1);
+ }
case ABTS_RESP_24XX:
case CTIO_TYPE7:
case NOTIFY_ACK_TYPE:
@@ -2755,13 +2779,22 @@ qla24xx_intr_handler(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
- case INTR_ATIO_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ case INTR_ATIO_QUE_UPDATE:{
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
break;
- case INTR_ATIO_RSP_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ }
+ case INTR_ATIO_RSP_QUE_UPDATE: {
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
qla24xx_process_response_queue(vha, rsp);
break;
+ }
default:
ql_dbg(ql_dbg_async, vha, 0x504f,
"Unrecognized interrupt type (%d).\n", stat * 0xff);
@@ -2920,13 +2953,22 @@ qla24xx_msix_default(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
- case INTR_ATIO_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ case INTR_ATIO_QUE_UPDATE:{
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
break;
- case INTR_ATIO_RSP_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ }
+ case INTR_ATIO_RSP_QUE_UPDATE: {
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
qla24xx_process_response_queue(vha, rsp);
break;
+ }
default:
ql_dbg(ql_dbg_async, vha, 0x5051,
"Unrecognized interrupt type (%d).\n", stat & 0xff);
@@ -2973,8 +3015,11 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
for (i = 0; i < ha->msix_count; i++) {
qentry = &ha->msix_entries[i];
- if (qentry->have_irq)
+ if (qentry->have_irq) {
+ /* un-register irq cpu affinity notification */
+ irq_set_affinity_notifier(qentry->vector, NULL);
free_irq(qentry->vector, qentry->rsp);
+ }
}
pci_disable_msix(ha->pdev);
kfree(ha->msix_entries);
@@ -3037,6 +3082,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
qentry->entry = entries[i].entry;
qentry->have_irq = 0;
qentry->rsp = NULL;
+ qentry->irq_notify.notify = qla_irq_affinity_notify;
+ qentry->irq_notify.release = qla_irq_affinity_release;
+ qentry->cpuid = -1;
}
/* Enable MSI-X vectors for the base queue */
@@ -3055,6 +3103,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
qentry->have_irq = 1;
qentry->rsp = rsp;
rsp->msix = qentry;
+
+ /* Register for CPU affinity notification. */
+ irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
+
+ /* Schedule work (ie. trigger a notification) to read cpu
+ * mask for this specific irq.
+ * kref_get is required because
+ * irq_affinity_notify() will do
+ * kref_put().
+ */
+ kref_get(&qentry->irq_notify.kref);
+ schedule_work(&qentry->irq_notify.work);
}
/*
@@ -3234,3 +3294,47 @@ int qla25xx_request_irq(struct rsp_que *rsp)
msix->rsp = rsp;
return ret;
}
+
+
+/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
+static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
+ const cpumask_t *mask)
+{
+ struct qla_msix_entry *e =
+ container_of(notify, struct qla_msix_entry, irq_notify);
+ struct qla_hw_data *ha;
+ struct scsi_qla_host *base_vha;
+
+ /* user is recommended to set mask to just 1 cpu */
+ e->cpuid = cpumask_first(mask);
+
+ ha = e->rsp->hw;
+ base_vha = pci_get_drvdata(ha->pdev);
+
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host %ld : vector %d cpu %d \n", __func__,
+ base_vha->host_no, e->vector, e->cpuid);
+
+ if (e->have_irq) {
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+ (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
+ ha->tgt.rspq_vector_cpuid = e->cpuid;
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host%ld: rspq vector %d cpu %d runtime change\n",
+ __func__, base_vha->host_no, e->vector, e->cpuid);
+ }
+ }
+}
+
+static void qla_irq_affinity_release(struct kref *ref)
+{
+ struct irq_affinity_notify *notify =
+ container_of(ref, struct irq_affinity_notify, kref);
+ struct qla_msix_entry *e =
+ container_of(notify, struct qla_msix_entry, irq_notify);
+ struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev);
+
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host%ld: vector %d cpu %d \n", __func__,
+ base_vha->host_no, e->vector, e->cpuid);
+}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index cb11e04be568..87e6758302f6 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -489,6 +489,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
EXTENDED_BB_CREDITS);
} else
mcp->mb[4] = 0;
+
+ if (ha->flags.exlogins_enabled)
+ mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
+
+ if (ha->flags.exchoffld_enabled)
+ mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
+
mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
mcp->in_mb |= MBX_1;
} else {
@@ -521,6 +528,226 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
}
/*
+ * qla_get_exlogin_status
+ * Get extended login status
+ * uses the memory offload control/status Mailbox
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * fwopt: firmware options
+ *
+ * Returns:
+ * qla2x00 local function status
+ *
+ * Context:
+ * Kernel context.
+ */
+#define FETCH_XLOGINS_STAT 0x8
+int
+qla_get_exlogin_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+ uint16_t *ex_logins_cnt)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118f,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = FETCH_XLOGINS_STAT;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_10|MBX_4|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1115, "Failed=%x.\n", rval);
+ } else {
+ *buf_sz = mcp->mb[4];
+ *ex_logins_cnt = mcp->mb[10];
+
+ ql_log(ql_log_info, vha, 0x1190,
+ "buffer size 0x%x, exchange login count=%d\n",
+ mcp->mb[4], mcp->mb[10]);
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1116,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_set_exlogin_mem_cfg
+ * set extended login memory configuration
+ * Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * buffer: buffer pointer
+ * phys_addr: physical address of buffer
+ * size: size of buffer
+ * TARGET_QUEUE_LOCK must be released
+ * ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ * qla2x00 local funxtion status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+#define CONFIG_XLOGINS_MEM 0x3
+int
+qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+ int configured_count;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a,
+ "Entered %s.\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = CONFIG_XLOGINS_MEM;
+ mcp->mb[2] = MSW(phys_addr);
+ mcp->mb[3] = LSW(phys_addr);
+ mcp->mb[6] = MSW(MSD(phys_addr));
+ mcp->mb[7] = LSW(MSD(phys_addr));
+ mcp->mb[8] = MSW(ha->exlogin_size);
+ mcp->mb[9] = LSW(ha->exlogin_size);
+ mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval);
+ } else {
+ configured_count = mcp->mb[11];
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_get_exchoffld_status
+ * Get exchange offload status
+ * uses the memory offload control/status Mailbox
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * fwopt: firmware options
+ *
+ * Returns:
+ * qla2x00 local function status
+ *
+ * Context:
+ * Kernel context.
+ */
+#define FETCH_XCHOFFLD_STAT 0x2
+int
+qla_get_exchoffld_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+ uint16_t *ex_logins_cnt)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1019,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = FETCH_XCHOFFLD_STAT;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_10|MBX_4|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1155, "Failed=%x.\n", rval);
+ } else {
+ *buf_sz = mcp->mb[4];
+ *ex_logins_cnt = mcp->mb[10];
+
+ ql_log(ql_log_info, vha, 0x118e,
+ "buffer size 0x%x, exchange offload count=%d\n",
+ mcp->mb[4], mcp->mb[10]);
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1156,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_set_exchoffld_mem_cfg
+ * Set exchange offload memory configuration
+ * Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * buffer: buffer pointer
+ * phys_addr: physical address of buffer
+ * size: size of buffer
+ * TARGET_QUEUE_LOCK must be released
+ * ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ * qla2x00 local funxtion status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+#define CONFIG_XCHOFFLD_MEM 0x3
+int
+qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1157,
+ "Entered %s.\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = CONFIG_XCHOFFLD_MEM;
+ mcp->mb[2] = MSW(phys_addr);
+ mcp->mb[3] = LSW(phys_addr);
+ mcp->mb[6] = MSW(MSD(phys_addr));
+ mcp->mb[7] = LSW(MSD(phys_addr));
+ mcp->mb[8] = MSW(ha->exlogin_size);
+ mcp->mb[9] = LSW(ha->exlogin_size);
+ mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ ql_dbg(ql_dbg_mbx, vha, 0x1158, "Failed=%x.\n", rval);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
* qla2x00_get_fw_version
* Get firmware version.
*
@@ -594,6 +821,16 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f,
"%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
__func__, mcp->mb[17], mcp->mb[16]);
+
+ if (ha->fw_attributes_h & 0x4)
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118d,
+ "%s: Firmware supports Extended Login 0x%x\n",
+ __func__, ha->fw_attributes_h);
+
+ if (ha->fw_attributes_h & 0x8)
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1191,
+ "%s: Firmware supports Exchange Offload 0x%x\n",
+ __func__, ha->fw_attributes_h);
}
if (IS_QLA27XX(ha)) {
@@ -2383,10 +2620,9 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
* Kernel context.
*/
int
-qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
- uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
- uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs)
+qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
{
+ struct qla_hw_data *ha = vha->hw;
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
@@ -2414,19 +2650,16 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
mcp->mb[11], mcp->mb[12]);
- if (cur_xchg_cnt)
- *cur_xchg_cnt = mcp->mb[3];
- if (orig_xchg_cnt)
- *orig_xchg_cnt = mcp->mb[6];
- if (cur_iocb_cnt)
- *cur_iocb_cnt = mcp->mb[7];
- if (orig_iocb_cnt)
- *orig_iocb_cnt = mcp->mb[10];
- if (vha->hw->flags.npiv_supported && max_npiv_vports)
- *max_npiv_vports = mcp->mb[11];
- if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
- IS_QLA27XX(vha->hw)) && max_fcfs)
- *max_fcfs = mcp->mb[12];
+ ha->orig_fw_tgt_xcb_count = mcp->mb[1];
+ ha->cur_fw_tgt_xcb_count = mcp->mb[2];
+ ha->cur_fw_xcb_count = mcp->mb[3];
+ ha->orig_fw_xcb_count = mcp->mb[6];
+ ha->cur_fw_iocb_count = mcp->mb[7];
+ ha->orig_fw_iocb_count = mcp->mb[10];
+ if (ha->flags.npiv_supported)
+ ha->max_npiv_vports = mcp->mb[11];
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ ha->fw_max_fcf_count = mcp->mb[12];
}
return (rval);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index bfa9a64c316b..f1788db43195 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -221,6 +221,18 @@ MODULE_PARM_DESC(ql2xmdenable,
"0 - MiniDump disabled. "
"1 (Default) - MiniDump enabled.");
+int ql2xexlogins = 0;
+module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexlogins,
+ "Number of extended Logins. "
+ "0 (Default)- Disabled.");
+
+int ql2xexchoffld = 0;
+module_param(ql2xexchoffld, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexchoffld,
+ "Number of exchanges to offload. "
+ "0 (Default)- Disabled.");
+
/*
* SCSI host template entry points
*/
@@ -2324,6 +2336,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->tgt.enable_class_2 = ql2xenableclass2;
INIT_LIST_HEAD(&ha->tgt.q_full_list);
spin_lock_init(&ha->tgt.q_full_lock);
+ spin_lock_init(&ha->tgt.sess_lock);
+ spin_lock_init(&ha->tgt.atio_lock);
+
/* Clear our data area */
ha->bars = bars;
@@ -2468,7 +2483,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_83XX;
- rsp_length = RESPONSE_ENTRY_CNT_2300;
+ rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2498,8 +2513,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->portnum = PCI_FUNC(ha->pdev->devfn);
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
- req_length = REQUEST_ENTRY_CNT_24XX;
- rsp_length = RESPONSE_ENTRY_CNT_2300;
+ req_length = REQUEST_ENTRY_CNT_83XX;
+ rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -3128,6 +3143,14 @@ qla2x00_remove_one(struct pci_dev *pdev)
base_vha->flags.online = 0;
+ /* free DMA memory */
+ if (ha->exlogin_buf)
+ qla2x00_free_exlogin_buffer(ha);
+
+ /* free DMA memory */
+ if (ha->exchoffld_buf)
+ qla2x00_free_exchoffld_buffer(ha);
+
qla2x00_destroy_deferred_work(ha);
qlt_remove_target(ha, base_vha);
@@ -3587,6 +3610,140 @@ fail:
return -ENOMEM;
}
+int
+qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint16_t size, max_cnt, temp;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Return if we don't need to alloacate any extended logins */
+ if (!ql2xexlogins)
+ return QLA_SUCCESS;
+
+ ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins);
+ max_cnt = 0;
+ rval = qla_get_exlogin_status(vha, &size, &max_cnt);
+ if (rval != QLA_SUCCESS) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd029,
+ "Failed to get exlogin status.\n");
+ return rval;
+ }
+
+ temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins;
+ ha->exlogin_size = (size * temp);
+ ql_log(ql_log_info, vha, 0xd024,
+ "EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n",
+ max_cnt, size, temp);
+
+ ql_log(ql_log_info, vha, 0xd025, "EXLOGIN: requested size=0x%x\n",
+ ha->exlogin_size);
+
+ /* Get consistent memory for extended logins */
+ ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev,
+ ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL);
+ if (!ha->exlogin_buf) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a,
+ "Failed to allocate memory for exlogin_buf_dma.\n");
+ return -ENOMEM;
+ }
+
+ /* Now configure the dma buffer */
+ rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0x00cf,
+ "Setup extended login buffer ****FAILED****.\n");
+ qla2x00_free_exlogin_buffer(ha);
+ }
+
+ return rval;
+}
+
+/*
+* qla2x00_free_exlogin_buffer
+*
+* Input:
+* ha = adapter block pointer
+*/
+void
+qla2x00_free_exlogin_buffer(struct qla_hw_data *ha)
+{
+ if (ha->exlogin_buf) {
+ dma_free_coherent(&ha->pdev->dev, ha->exlogin_size,
+ ha->exlogin_buf, ha->exlogin_buf_dma);
+ ha->exlogin_buf = NULL;
+ ha->exlogin_size = 0;
+ }
+}
+
+int
+qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint16_t size, max_cnt, temp;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Return if we don't need to alloacate any extended logins */
+ if (!ql2xexchoffld)
+ return QLA_SUCCESS;
+
+ ql_log(ql_log_info, vha, 0xd014,
+ "Exchange offload count: %d.\n", ql2xexlogins);
+
+ max_cnt = 0;
+ rval = qla_get_exchoffld_status(vha, &size, &max_cnt);
+ if (rval != QLA_SUCCESS) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd012,
+ "Failed to get exlogin status.\n");
+ return rval;
+ }
+
+ temp = (ql2xexchoffld > max_cnt) ? max_cnt : ql2xexchoffld;
+ ha->exchoffld_size = (size * temp);
+ ql_log(ql_log_info, vha, 0xd016,
+ "Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n",
+ max_cnt, size, temp);
+
+ ql_log(ql_log_info, vha, 0xd017,
+ "Exchange Buffers requested size = 0x%x\n", ha->exchoffld_size);
+
+ /* Get consistent memory for extended logins */
+ ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev,
+ ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL);
+ if (!ha->exchoffld_buf) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd013,
+ "Failed to allocate memory for exchoffld_buf_dma.\n");
+ return -ENOMEM;
+ }
+
+ /* Now configure the dma buffer */
+ rval = qla_set_exchoffld_mem_cfg(vha, ha->exchoffld_buf_dma);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0xd02e,
+ "Setup exchange offload buffer ****FAILED****.\n");
+ qla2x00_free_exchoffld_buffer(ha);
+ }
+
+ return rval;
+}
+
+/*
+* qla2x00_free_exchoffld_buffer
+*
+* Input:
+* ha = adapter block pointer
+*/
+void
+qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
+{
+ if (ha->exchoffld_buf) {
+ dma_free_coherent(&ha->pdev->dev, ha->exchoffld_size,
+ ha->exchoffld_buf, ha->exchoffld_buf_dma);
+ ha->exchoffld_buf = NULL;
+ ha->exchoffld_size = 0;
+ }
+}
+
/*
* qla2x00_free_fw_dump
* Frees fw dump stuff.
@@ -3766,6 +3923,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->list);
INIT_LIST_HEAD(&vha->qla_cmd_list);
INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
+ INIT_LIST_HEAD(&vha->logo_list);
+ INIT_LIST_HEAD(&vha->plogi_ack_list);
spin_lock_init(&vha->work_lock);
spin_lock_init(&vha->cmd_list_lock);
@@ -5843,6 +6002,3 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
MODULE_FIRMWARE(FW_FILE_ISP2322);
MODULE_FIRMWARE(FW_FILE_ISP24XX);
MODULE_FIRMWARE(FW_FILE_ISP25XX);
-MODULE_FIRMWARE(FW_FILE_ISP2031);
-MODULE_FIRMWARE(FW_FILE_ISP8031);
-MODULE_FIRMWARE(FW_FILE_ISP27XX);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 75514a15bea0..8075a4cdb45c 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -100,7 +100,7 @@ enum fcp_resp_rsp_codes {
*/
/* Predefs for callbacks handed to qla2xxx LLD */
static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha,
- struct atio_from_isp *pkt);
+ struct atio_from_isp *pkt, uint8_t);
static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
int fn, void *iocb, int flags);
@@ -118,10 +118,13 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha,
struct imm_ntfy_from_isp *ntfy,
uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+ struct imm_ntfy_from_isp *imm, int ha_locked);
/*
* Global Variables
*/
static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
+static struct kmem_cache *qla_tgt_plogi_cachep;
static mempool_t *qla_tgt_mgmt_cmd_mempool;
static struct workqueue_struct *qla_tgt_wq;
static DEFINE_MUTEX(qla_tgt_mutex);
@@ -226,8 +229,8 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
}
-static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
- struct atio_from_isp *atio)
+static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
+ struct atio_from_isp *atio, uint8_t ha_locked)
{
ql_dbg(ql_dbg_tgt, vha, 0xe072,
"%s: qla_target(%d): type %x ox_id %04x\n",
@@ -248,7 +251,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
atio->u.isp24.fcp_hdr.d_id[2]);
break;
}
- qlt_24xx_atio_pkt(host, atio);
+ qlt_24xx_atio_pkt(host, atio, ha_locked);
break;
}
@@ -271,7 +274,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
break;
}
}
- qlt_24xx_atio_pkt(host, atio);
+ qlt_24xx_atio_pkt(host, atio, ha_locked);
break;
}
@@ -282,7 +285,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
break;
}
- return;
+ return false;
}
void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
@@ -389,6 +392,131 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
}
+/*
+ * All qlt_plogi_ack_t operations are protected by hardware_lock
+ */
+
+/*
+ * This is a zero-base ref-counting solution, since hardware_lock
+ * guarantees that ref_count is not modified concurrently.
+ * Upon successful return content of iocb is undefined
+ */
+static qlt_plogi_ack_t *
+qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id,
+ struct imm_ntfy_from_isp *iocb)
+{
+ qlt_plogi_ack_t *pla;
+
+ list_for_each_entry(pla, &vha->plogi_ack_list, list) {
+ if (pla->id.b24 == id->b24) {
+ qlt_send_term_imm_notif(vha, &pla->iocb, 1);
+ pla->iocb = *iocb;
+ return pla;
+ }
+ }
+
+ pla = kmem_cache_zalloc(qla_tgt_plogi_cachep, GFP_ATOMIC);
+ if (!pla) {
+ ql_dbg(ql_dbg_async, vha, 0x5088,
+ "qla_target(%d): Allocation of plogi_ack failed\n",
+ vha->vp_idx);
+ return NULL;
+ }
+
+ pla->iocb = *iocb;
+ pla->id = *id;
+ list_add_tail(&pla->list, &vha->plogi_ack_list);
+
+ return pla;
+}
+
+static void qlt_plogi_ack_unref(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla)
+{
+ BUG_ON(!pla->ref_count);
+ pla->ref_count--;
+
+ if (pla->ref_count)
+ return;
+
+ ql_dbg(ql_dbg_async, vha, 0x5089,
+ "Sending PLOGI ACK to wwn %8phC s_id %02x:%02x:%02x loop_id %#04x"
+ " exch %#x ox_id %#x\n", pla->iocb.u.isp24.port_name,
+ pla->iocb.u.isp24.port_id[2], pla->iocb.u.isp24.port_id[1],
+ pla->iocb.u.isp24.port_id[0],
+ le16_to_cpu(pla->iocb.u.isp24.nport_handle),
+ pla->iocb.u.isp24.exchange_address, pla->iocb.ox_id);
+ qlt_send_notify_ack(vha, &pla->iocb, 0, 0, 0, 0, 0, 0);
+
+ list_del(&pla->list);
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+}
+
+static void
+qlt_plogi_ack_link(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla,
+ struct qla_tgt_sess *sess, qlt_plogi_link_t link)
+{
+ /* Inc ref_count first because link might already be pointing at pla */
+ pla->ref_count++;
+
+ if (sess->plogi_link[link])
+ qlt_plogi_ack_unref(vha, sess->plogi_link[link]);
+
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf097,
+ "Linking sess %p [%d] wwn %8phC with PLOGI ACK to wwn %8phC"
+ " s_id %02x:%02x:%02x, ref=%d\n", sess, link, sess->port_name,
+ pla->iocb.u.isp24.port_name, pla->iocb.u.isp24.port_id[2],
+ pla->iocb.u.isp24.port_id[1], pla->iocb.u.isp24.port_id[0],
+ pla->ref_count);
+
+ sess->plogi_link[link] = pla;
+}
+
+typedef struct {
+ /* These fields must be initialized by the caller */
+ port_id_t id;
+ /*
+ * number of cmds dropped while we were waiting for
+ * initiator to ack LOGO initialize to 1 if LOGO is
+ * triggered by a command, otherwise, to 0
+ */
+ int cmd_count;
+
+ /* These fields are used by callee */
+ struct list_head list;
+} qlt_port_logo_t;
+
+static void
+qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
+{
+ qlt_port_logo_t *tmp;
+ int res;
+
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+
+ list_for_each_entry(tmp, &vha->logo_list, list) {
+ if (tmp->id.b24 == logo->id.b24) {
+ tmp->cmd_count += logo->cmd_count;
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+ return;
+ }
+ }
+
+ list_add_tail(&logo->list, &vha->logo_list);
+
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+ res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
+
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+ list_del(&logo->list);
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf098,
+ "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
+ logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+ logo->cmd_count, res);
+}
+
static void qlt_free_session_done(struct work_struct *work)
{
struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +530,21 @@ static void qlt_free_session_done(struct work_struct *work)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
- " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+ " s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n",
__func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
sess->logout_on_delete, sess->keep_nport_handle,
- sess->plogi_ack_needed);
+ sess->send_els_logo);
BUG_ON(!tgt);
+ if (sess->send_els_logo) {
+ qlt_port_logo_t logo;
+ logo.id = sess->s_id;
+ logo.cmd_count = 0;
+ qlt_send_first_logo(vha, &logo);
+ }
+
if (sess->logout_on_delete) {
int rc;
@@ -455,9 +590,34 @@ static void qlt_free_session_done(struct work_struct *work)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (sess->plogi_ack_needed)
- qlt_send_notify_ack(vha, &sess->tm_iocb,
- 0, 0, 0, 0, 0, 0);
+ {
+ qlt_plogi_ack_t *own =
+ sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
+ qlt_plogi_ack_t *con =
+ sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
+
+ if (con) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf099,
+ "se_sess %p / sess %p port %8phC is gone,"
+ " %s (ref=%d), releasing PLOGI for %8phC (ref=%d)\n",
+ sess->se_sess, sess, sess->port_name,
+ own ? "releasing own PLOGI" :
+ "no own PLOGI pending",
+ own ? own->ref_count : -1,
+ con->iocb.u.isp24.port_name, con->ref_count);
+ qlt_plogi_ack_unref(vha, con);
+ } else {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09a,
+ "se_sess %p / sess %p port %8phC is gone, %s (ref=%d)\n",
+ sess->se_sess, sess, sess->port_name,
+ own ? "releasing own PLOGI" :
+ "no own PLOGI pending",
+ own ? own->ref_count : -1);
+ }
+
+ if (own)
+ qlt_plogi_ack_unref(vha, own);
+ }
list_del(&sess->sess_list_entry);
@@ -476,7 +636,7 @@ static void qlt_free_session_done(struct work_struct *work)
wake_up_all(&tgt->waitQ);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
void qlt_unreg_sess(struct qla_tgt_sess *sess)
{
struct scsi_qla_host *vha = sess->vha;
@@ -492,7 +652,7 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
}
EXPORT_SYMBOL(qlt_unreg_sess);
-/* ha->hardware_lock supposed to be held on entry */
+
static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
{
struct qla_hw_data *ha = vha->hw;
@@ -502,12 +662,15 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
int res = 0;
struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
struct atio_from_isp *a = (struct atio_from_isp *)iocb;
+ unsigned long flags;
loop_id = le16_to_cpu(n->u.isp24.nport_handle);
if (loop_id == 0xFFFF) {
/* Global event */
atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
#if 0 /* FIXME: do we need to choose a session here? */
if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
@@ -534,7 +697,9 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
sess = NULL;
#endif
} else {
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
ql_dbg(ql_dbg_tgt, vha, 0xe000,
@@ -556,7 +721,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
iocb, QLA24XX_MGMT_SEND_NACK);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
bool immediate)
{
@@ -600,7 +765,7 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
sess->expires - jiffies);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_clear_tgt_db(struct qla_tgt *tgt)
{
struct qla_tgt_sess *sess;
@@ -636,12 +801,12 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id,
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045,
"qla_target(%d): get_id_list() failed: %x\n",
vha->vp_idx, rc);
- res = -1;
+ res = -EBUSY;
goto out_free_id_list;
}
id_iter = (char *)gid_list;
- res = -1;
+ res = -ENOENT;
for (i = 0; i < entries; i++) {
struct gid_list_info *gid = (struct gid_list_info *)id_iter;
if ((gid->al_pa == s_id[2]) &&
@@ -660,7 +825,7 @@ out_free_id_list:
return res;
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_undelete_sess(struct qla_tgt_sess *sess)
{
BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
@@ -678,7 +843,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
struct qla_tgt_sess *sess;
unsigned long flags, elapsed;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
while (!list_empty(&tgt->del_sess_list)) {
sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
del_list_entry);
@@ -699,7 +864,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
break;
}
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -717,7 +882,7 @@ static struct qla_tgt_sess *qlt_create_sess(
unsigned char be_sid[3];
/* Check to avoid double sessions */
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_for_each_entry(sess, &vha->vha_tgt.qla_tgt->sess_list,
sess_list_entry) {
if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) {
@@ -732,7 +897,7 @@ static struct qla_tgt_sess *qlt_create_sess(
/* Cannot undelete at this point */
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
- spin_unlock_irqrestore(&ha->hardware_lock,
+ spin_unlock_irqrestore(&ha->tgt.sess_lock,
flags);
return NULL;
}
@@ -749,12 +914,12 @@ static struct qla_tgt_sess *qlt_create_sess(
qlt_do_generation_tick(vha, &sess->generation);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return sess;
}
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
sess = kzalloc(sizeof(*sess), GFP_KERNEL);
if (!sess) {
@@ -799,7 +964,7 @@ static struct qla_tgt_sess *qlt_create_sess(
}
/*
* Take an extra reference to ->sess_kref here to handle qla_tgt_sess
- * access across ->hardware_lock reaquire.
+ * access across ->tgt.sess_lock reaquire.
*/
kref_get(&sess->se_sess->sess_kref);
@@ -807,11 +972,11 @@ static struct qla_tgt_sess *qlt_create_sess(
BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
vha->vha_tgt.qla_tgt->sess_count++;
qlt_do_generation_tick(vha, &sess->generation);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
"qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
@@ -842,23 +1007,23 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
if (qla_ini_mode_enabled(vha))
return;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
}
sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_create_sess(vha, fcport, false);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
} else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
/* Point of no return */
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
} else {
kref_get(&sess->se_sess->sess_kref);
@@ -887,7 +1052,7 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
sess->local = 0;
}
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -899,6 +1064,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_tgt_sess *sess;
+ unsigned long flags;
if (!vha->hw->tgt.tgt_ops)
return;
@@ -906,15 +1072,19 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
if (!tgt)
return;
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
if (tgt->tgt_stop) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return;
}
sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
if (!sess) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return;
}
if (max_gen - sess->generation < 0) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
"Ignoring stale deletion request for se_sess %p / sess %p"
" for port %8phC, req_gen %d, sess_gen %d\n",
@@ -927,6 +1097,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
sess->local = 1;
qlt_schedule_sess_for_deletion(sess, false);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -984,10 +1155,10 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
* Lock is needed, because we still can get an incoming packet.
*/
mutex_lock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
tgt->tgt_stop = 1;
qlt_clear_tgt_db(tgt);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
mutex_unlock(&qla_tgt_mutex);
@@ -1040,7 +1211,7 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
mutex_lock(&vha->vha_tgt.tgt_mutex);
spin_lock_irqsave(&ha->hardware_lock, flags);
- while (tgt->irq_cmd_count != 0) {
+ while ((tgt->irq_cmd_count != 0) || (tgt->atio_irq_cmd_count != 0)) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
udelay(2);
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1309,7 +1480,7 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
if (tag == cmd->atio.u.isp24.exchange_addr) {
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
spin_unlock(&vha->cmd_list_lock);
return 1;
}
@@ -1351,7 +1522,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha,
cmd_lun = scsilun_to_int(
(struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
if (cmd_key == key && cmd_lun == lun)
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
}
spin_unlock(&vha->cmd_list_lock);
}
@@ -1435,6 +1606,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
uint32_t tag = abts->exchange_addr_to_abort;
uint8_t s_id[3];
int rc;
+ unsigned long flags;
if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053,
@@ -1462,6 +1634,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
s_id[1] = abts->fcp_hdr_le.s_id[1];
s_id[2] = abts->fcp_hdr_le.s_id[0];
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
if (!sess) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012,
@@ -1469,12 +1642,17 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
vha->vp_idx);
rc = qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts));
+
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (rc != 0) {
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED,
false);
}
return;
}
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
@@ -1560,15 +1738,15 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || mcmd->reset_count != ha->chip_reset) {
+ if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
ql_dbg(ql_dbg_async, vha, 0xe100,
- "RESET-TMR active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), mcmd->reset_count,
- ha->chip_reset);
+ "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ mcmd->reset_count, ha->chip_reset);
ha->tgt.tgt_ops->free_mcmd(mcmd);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
@@ -2510,17 +2688,22 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+ if (xmit_type == QLA_TGT_XMIT_STATUS)
+ vha->tgt_counters.core_qla_snd_status++;
+ else
+ vha->tgt_counters.core_qla_que_buf++;
+
+ if (!vha->flags.online || cmd->reset_count != ha->chip_reset) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_PROCESSED;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg(ql_dbg_async, vha, 0xe101,
- "RESET-RSP active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), cmd->reset_count,
- ha->chip_reset);
+ "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ cmd->reset_count, ha->chip_reset);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2651,18 +2834,18 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+ if (!vha->flags.online || (cmd->reset_count != ha->chip_reset) ||
(cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_NEED_DATA;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg(ql_dbg_async, vha, 0xe102,
- "RESET-XFR active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), cmd->reset_count,
- ha->chip_reset);
+ "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ cmd->reset_count, ha->chip_reset);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2957,12 +3140,13 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
ret = 1;
}
+ vha->tgt_counters.num_term_xchg_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
ctio24 = (struct ctio7_to_24xx *)pkt;
ctio24->entry_type = CTIO_TYPE7;
- ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED;
+ ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED;
ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
ctio24->vp_index = vha->vp_idx;
ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
@@ -3009,7 +3193,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
qlt_alloc_qfull_cmd(vha, atio, 0, 0);
done:
- if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
+ if (cmd && (!cmd->aborted ||
!cmd->cmd_sent_to_fw)) {
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
@@ -3028,7 +3212,7 @@ static void qlt_init_term_exchange(struct scsi_qla_host *vha)
struct qla_tgt_cmd *cmd, *tcmd;
vha->hw->tgt.leak_exchg_thresh_hold =
- (vha->hw->fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
+ (vha->hw->cur_fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
cmd = tcmd = NULL;
if (!list_empty(&vha->hw->tgt.q_full_list)) {
@@ -3058,7 +3242,7 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
ql_dbg(ql_dbg_tgt, vha, 0xe079,
"Chip reset due to exchange starvation: %d/%d.\n",
- total_leaked, vha->hw->fw_xcb_count);
+ total_leaked, vha->hw->cur_fw_xcb_count);
if (IS_P3P_TYPE(vha->hw))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -3080,7 +3264,7 @@ void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
"(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
se_cmd->tag);
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
cmd->cmd_flags |= BIT_6;
qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
@@ -3300,9 +3484,6 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
ha->tgt.tgt_ops->handle_data(cmd);
return;
- } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
- ql_dbg(ql_dbg_io, vha, 0xff02,
- "HOST-ABORT: handle=%d, state=ABORTED.\n", handle);
} else {
ql_dbg(ql_dbg_io, vha, 0xff03,
"HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
@@ -3398,13 +3579,26 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
case CTIO_PORT_LOGGED_OUT:
case CTIO_PORT_UNAVAILABLE:
+ {
+ int logged_out = (status & 0xFFFF);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
- "qla_target(%d): CTIO with PORT LOGGED "
- "OUT (29) or PORT UNAVAILABLE (28) status %x "
+ "qla_target(%d): CTIO with %s status %x "
"received (state %x, se_cmd %p)\n", vha->vp_idx,
+ (logged_out == CTIO_PORT_LOGGED_OUT) ?
+ "PORT LOGGED OUT" : "PORT UNAVAILABLE",
status, cmd->state, se_cmd);
- break;
+ if (logged_out && cmd->sess) {
+ /*
+ * Session is already logged out, but we need
+ * to notify initiator, who's not aware of this
+ */
+ cmd->sess->logout_on_delete = 0;
+ cmd->sess->send_els_logo = 1;
+ qlt_schedule_sess_for_deletion(cmd->sess, true);
+ }
+ break;
+ }
case CTIO_SRR_RECEIVED:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a,
"qla_target(%d): CTIO with SRR_RECEIVED"
@@ -3454,14 +3648,14 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
}
- /* "cmd->state == QLA_TGT_STATE_ABORTED" means
+ /* "cmd->aborted" means
* cmd is already aborted/terminated, we don't
* need to terminate again. The exchange is already
* cleaned up/freed at FW level. Just cleanup at driver
* level.
*/
if ((cmd->state != QLA_TGT_STATE_NEED_DATA) &&
- (cmd->state != QLA_TGT_STATE_ABORTED)) {
+ (!cmd->aborted)) {
cmd->cmd_flags |= BIT_13;
if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
return;
@@ -3479,7 +3673,7 @@ skip_term:
ha->tgt.tgt_ops->handle_data(cmd);
return;
- } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+ } else if (cmd->aborted) {
cmd->cmd_flags |= BIT_18;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
"Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
@@ -3491,7 +3685,7 @@ skip_term:
}
if (unlikely(status != CTIO_SUCCESS) &&
- (cmd->state != QLA_TGT_STATE_ABORTED)) {
+ !cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n");
dump_stack();
}
@@ -3553,7 +3747,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
if (tgt->tgt_stop)
goto out_term;
- if (cmd->state == QLA_TGT_STATE_ABORTED) {
+ if (cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
"cmd with tag %u is aborted\n",
cmd->atio.u.isp24.exchange_addr);
@@ -3589,9 +3783,9 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
/*
* Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
*/
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
@@ -3606,8 +3800,11 @@ out_term:
qlt_decr_num_pend_cmds(vha);
percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
- ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+ ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static void qlt_do_work(struct work_struct *work)
@@ -3692,10 +3889,8 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
goto out_term;
}
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has an extra creation ref. */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
if (!sess)
goto out_term;
@@ -3787,13 +3982,24 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
cmd->cmd_in_wq = 1;
cmd->cmd_flags |= BIT_0;
+ cmd->se_cmd.cpuid = -1;
spin_lock(&vha->cmd_list_lock);
list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
spin_unlock(&vha->cmd_list_lock);
INIT_WORK(&cmd->work, qlt_do_work);
- queue_work(qla_tgt_wq, &cmd->work);
+ if (ha->msix_count) {
+ cmd->se_cmd.cpuid = ha->tgt.rspq_vector_cpuid;
+ if (cmd->atio.u.isp24.fcp_cmnd.rddata)
+ queue_work_on(smp_processor_id(), qla_tgt_wq,
+ &cmd->work);
+ else
+ queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
+ &cmd->work);
+ } else {
+ queue_work(qla_tgt_wq, &cmd->work);
+ }
return 0;
}
@@ -3917,13 +4123,18 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
struct qla_tgt_sess *sess;
uint32_t lun, unpacked_lun;
int fn;
+ unsigned long flags;
tgt = vha->vha_tgt.qla_tgt;
lun = a->u.isp24.fcp_cmnd.lun;
fn = a->u.isp24.fcp_cmnd.task_mgmt_flags;
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
a->u.isp24.fcp_hdr.s_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
if (!sess) {
@@ -3987,10 +4198,14 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess;
int loop_id;
+ unsigned long flags;
loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (sess == NULL) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025,
"qla_target(%d): task abort for unexisting "
@@ -4022,15 +4237,6 @@ void qlt_logo_completion_handler(fc_port_t *fcport, int rc)
}
}
-static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
- struct imm_ntfy_from_isp *b)
-{
- struct imm_ntfy_from_isp tmp;
- memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
- memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
- memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
-}
-
/*
* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
*
@@ -4040,11 +4246,13 @@ static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
*/
static struct qla_tgt_sess *
qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
- port_id_t port_id, uint16_t loop_id)
+ port_id_t port_id, uint16_t loop_id, struct qla_tgt_sess **conflict_sess)
{
struct qla_tgt_sess *sess = NULL, *other_sess;
uint64_t other_wwn;
+ *conflict_sess = NULL;
+
list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
other_wwn = wwn_to_u64(other_sess->port_name);
@@ -4072,9 +4280,10 @@ qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
} else {
/*
* Another wwn used to have our s_id/loop_id
- * combo - kill the session, but don't log out
+ * kill the session, but don't free the loop_id
*/
- sess->logout_on_delete = 0;
+ other_sess->keep_nport_handle = 1;
+ *conflict_sess = other_sess;
qlt_schedule_sess_for_deletion(other_sess,
true);
}
@@ -4119,7 +4328,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
if (cmd_key == key) {
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
count++;
}
}
@@ -4136,12 +4345,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_hw_data *ha = vha->hw;
- struct qla_tgt_sess *sess = NULL;
+ struct qla_tgt_sess *sess = NULL, *conflict_sess = NULL;
uint64_t wwn;
port_id_t port_id;
uint16_t loop_id;
uint16_t wd3_lo;
int res = 0;
+ qlt_plogi_ack_t *pla;
+ unsigned long flags;
wwn = wwn_to_u64(iocb->u.isp24.port_name);
@@ -4165,27 +4376,20 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
/* Mark all stale commands in qla_tgt_wq for deletion */
abort_cmds_for_s_id(vha, &port_id);
- if (wwn)
+ if (wwn) {
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
sess = qlt_find_sess_invalidate_other(tgt, wwn,
- port_id, loop_id);
+ port_id, loop_id, &conflict_sess);
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+ }
- if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+ if (IS_SW_RESV_ADDR(port_id) || (!sess && !conflict_sess)) {
res = 1;
break;
}
- if (sess->plogi_ack_needed) {
- /*
- * Initiator sent another PLOGI before last PLOGI could
- * finish. Swap plogi iocbs and terminate old one
- * without acking, new one will get acked when session
- * deletion completes.
- */
- ql_log(ql_log_warn, sess->vha, 0xf094,
- "sess %p received double plogi.\n", sess);
-
- qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
-
+ pla = qlt_plogi_ack_find_add(vha, &port_id, iocb);
+ if (!pla) {
qlt_send_term_imm_notif(vha, iocb, 1);
res = 0;
@@ -4194,13 +4398,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
res = 0;
- /*
- * Save immediate Notif IOCB for Ack when sess is done
- * and being deleted.
- */
- memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
- sess->plogi_ack_needed = 1;
+ if (conflict_sess)
+ qlt_plogi_ack_link(vha, pla, conflict_sess,
+ QLT_PLOGI_LINK_CONFLICT);
+
+ if (!sess)
+ break;
+ qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
/*
* Under normal circumstances we want to release nport handle
* during LOGO process to avoid nport handle leaks inside FW.
@@ -4227,9 +4432,21 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
case ELS_PRLI:
wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
- if (wwn)
+ if (wwn) {
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
- loop_id);
+ loop_id, &conflict_sess);
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+ }
+
+ if (conflict_sess) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b,
+ "PRLI with conflicting sess %p port %8phC\n",
+ conflict_sess, conflict_sess->port_name);
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ res = 0;
+ break;
+ }
if (sess != NULL) {
if (sess->deleted) {
@@ -4899,9 +5116,12 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
struct qla_hw_data *ha = vha->hw;
request_t *pkt;
struct qla_tgt_sess *sess = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
atio->u.isp24.fcp_hdr.s_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
if (!sess) {
qlt_send_term_exchange(vha, NULL, atio, 1);
return 0;
@@ -4916,6 +5136,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
return -ENOMEM;
}
+ vha->tgt_counters.num_q_full_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
@@ -5129,11 +5350,12 @@ qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha,
/* ha->hardware_lock supposed to be held on entry */
/* called via callback from qla2xxx */
static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
- struct atio_from_isp *atio)
+ struct atio_from_isp *atio, uint8_t ha_locked)
{
struct qla_hw_data *ha = vha->hw;
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
int rc;
+ unsigned long flags;
if (unlikely(tgt == NULL)) {
ql_dbg(ql_dbg_io, vha, 0x3064,
@@ -5145,7 +5367,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
* Otherwise, some commands can stuck.
*/
- tgt->irq_cmd_count++;
+ tgt->atio_irq_cmd_count++;
switch (atio->u.raw.entry_type) {
case ATIO_TYPE7:
@@ -5155,7 +5377,11 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
"qla_target(%d): ATIO_TYPE7 "
"received with UNKNOWN exchange address, "
"sending QUEUE_FULL\n", vha->vp_idx);
+ if (!ha_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL);
+ if (!ha_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
break;
}
@@ -5164,7 +5390,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) {
rc = qlt_chk_qfull_thresh_hold(vha, atio);
if (rc != 0) {
- tgt->irq_cmd_count--;
+ tgt->atio_irq_cmd_count--;
return;
}
rc = qlt_handle_cmd_for_atio(vha, atio);
@@ -5173,11 +5399,20 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
}
if (unlikely(rc != 0)) {
if (rc == -ESRCH) {
+ if (!ha_locked)
+ spin_lock_irqsave
+ (&ha->hardware_lock, flags);
+
#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
qlt_send_busy(vha, atio, SAM_STAT_BUSY);
#else
qlt_send_term_exchange(vha, NULL, atio, 1);
#endif
+
+ if (!ha_locked)
+ spin_unlock_irqrestore
+ (&ha->hardware_lock, flags);
+
} else {
if (tgt->tgt_stop) {
ql_dbg(ql_dbg_tgt, vha, 0xe059,
@@ -5189,7 +5424,13 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
"qla_target(%d): Unable to send "
"command to target, sending BUSY "
"status.\n", vha->vp_idx);
+ if (!ha_locked)
+ spin_lock_irqsave(
+ &ha->hardware_lock, flags);
qlt_send_busy(vha, atio, SAM_STAT_BUSY);
+ if (!ha_locked)
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
}
}
}
@@ -5206,7 +5447,12 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
break;
}
ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO");
+
+ if (!ha_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio);
+ if (!ha_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
break;
}
@@ -5217,7 +5463,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
break;
}
- tgt->irq_cmd_count--;
+ tgt->atio_irq_cmd_count--;
}
/* ha->hardware_lock supposed to be held on entry */
@@ -5534,12 +5780,16 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha,
int rc, global_resets;
uint16_t loop_id = 0;
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+
retry:
global_resets =
atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
if (rc != 0) {
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
if ((s_id[0] == 0xFF) &&
(s_id[1] == 0xFC)) {
/*
@@ -5550,17 +5800,27 @@ retry:
"Unable to find initiator with S_ID %x:%x:%x",
s_id[0], s_id[1], s_id[2]);
} else
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071,
+ ql_log(ql_log_info, vha, 0xf071,
"qla_target(%d): Unable to find "
"initiator with S_ID %x:%x:%x",
vha->vp_idx, s_id[0], s_id[1],
s_id[2]);
+
+ if (rc == -ENOENT) {
+ qlt_port_logo_t logo;
+ sid_to_portid(s_id, &logo.id);
+ logo.cmd_count = 1;
+ qlt_send_first_logo(vha, &logo);
+ }
+
return NULL;
}
fcport = qlt_get_port_database(vha, loop_id);
- if (!fcport)
+ if (!fcport) {
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
return NULL;
+ }
if (global_resets !=
atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
@@ -5575,6 +5835,8 @@ retry:
sess = qlt_create_sess(vha, fcport, true);
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
kfree(fcport);
return sess;
}
@@ -5585,15 +5847,15 @@ static void qlt_abort_work(struct qla_tgt *tgt,
struct scsi_qla_host *vha = tgt->vha;
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess = NULL;
- unsigned long flags;
+ unsigned long flags = 0, flags2 = 0;
uint32_t be_s_id;
uint8_t s_id[3];
int rc;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
if (tgt->tgt_stop)
- goto out_term;
+ goto out_term2;
s_id[0] = prm->abts.fcp_hdr_le.s_id[2];
s_id[1] = prm->abts.fcp_hdr_le.s_id[1];
@@ -5602,41 +5864,47 @@ static void qlt_abort_work(struct qla_tgt *tgt,
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
(unsigned char *)&be_s_id);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has got an extra creation ref */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
if (!sess)
- goto out_term;
+ goto out_term2;
} else {
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
sess = NULL;
- goto out_term;
+ goto out_term2;
}
kref_get(&sess->se_sess->sess_kref);
}
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
if (tgt->tgt_stop)
goto out_term;
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
if (rc != 0)
goto out_term;
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
return;
+out_term2:
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
out_term:
qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
}
static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -5653,7 +5921,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
int fn;
void *iocb;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop)
goto out_term;
@@ -5661,14 +5929,12 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has got an extra creation ref */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (!sess)
goto out_term;
} else {
@@ -5690,14 +5956,14 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
goto out_term;
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
- qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
+ qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 0);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static void qlt_sess_work_fn(struct work_struct *work)
@@ -6002,6 +6268,7 @@ qlt_enable_vha(struct scsi_qla_host *vha)
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
unsigned long flags;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+ int rspq_ent = QLA83XX_RSPQ_MSIX_ENTRY_NUMBER;
if (!tgt) {
ql_dbg(ql_dbg_tgt, vha, 0xe069,
@@ -6020,6 +6287,17 @@ qlt_enable_vha(struct scsi_qla_host *vha)
qla24xx_disable_vp(vha);
qla24xx_enable_vp(vha);
} else {
+ if (ha->msix_entries) {
+ ql_dbg(ql_dbg_tgt, vha, 0xffff,
+ "%s: host%ld : vector %d cpu %d\n",
+ __func__, vha->host_no,
+ ha->msix_entries[rspq_ent].vector,
+ ha->msix_entries[rspq_ent].cpuid);
+
+ ha->tgt.rspq_vector_cpuid =
+ ha->msix_entries[rspq_ent].cpuid;
+ }
+
set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
qla2xxx_wake_dpc(base_vha);
qla2x00_wait_for_hba_online(base_vha);
@@ -6131,7 +6409,7 @@ qlt_init_atio_q_entries(struct scsi_qla_host *vha)
* @ha: SCSI driver HA context
*/
void
-qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
+qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
{
struct qla_hw_data *ha = vha->hw;
struct atio_from_isp *pkt;
@@ -6144,7 +6422,8 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr;
cnt = pkt->u.raw.entry_count;
- qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt);
+ qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt,
+ ha_locked);
for (i = 0; i < cnt; i++) {
ha->tgt.atio_ring_index++;
@@ -6265,10 +6544,21 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
{
struct qla_hw_data *ha = vha->hw;
+ if (!QLA_TGT_MODE_ENABLED())
+ return;
+
if (ha->tgt.node_name_set) {
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+ /* disable ZIO at start time. */
+ if (!vha->flags.init_done) {
+ uint32_t tmp;
+ tmp = le32_to_cpu(icb->firmware_options_2);
+ tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ icb->firmware_options_2 = cpu_to_le32(tmp);
+ }
}
void
@@ -6359,6 +6649,15 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+ /* disable ZIO at start time. */
+ if (!vha->flags.init_done) {
+ uint32_t tmp;
+ tmp = le32_to_cpu(icb->firmware_options_2);
+ tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ icb->firmware_options_2 = cpu_to_le32(tmp);
+ }
+
}
void
@@ -6428,16 +6727,59 @@ qla83xx_msix_atio_q(int irq, void *dev_id)
ha = rsp->hw;
vha = pci_get_drvdata(ha->pdev);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
- qlt_24xx_process_atio_queue(vha);
- qla24xx_process_response_queue(vha, rsp);
+ qlt_24xx_process_atio_queue(vha, 0);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
return IRQ_HANDLED;
}
+static void
+qlt_handle_abts_recv_work(struct work_struct *work)
+{
+ struct qla_tgt_sess_op *op = container_of(work,
+ struct qla_tgt_sess_op, work);
+ scsi_qla_host_t *vha = op->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags;
+
+ if (qla2x00_reset_active(vha) || (op->chip_reset != ha->chip_reset))
+ return;
+
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ qlt_response_pkt_all_vps(vha, (response_t *)&op->atio);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt)
+{
+ struct qla_tgt_sess_op *op;
+
+ op = kzalloc(sizeof(*op), GFP_ATOMIC);
+
+ if (!op) {
+ /* do not reach for ATIO queue here. This is best effort err
+ * recovery at this point.
+ */
+ qlt_response_pkt_all_vps(vha, pkt);
+ return;
+ }
+
+ memcpy(&op->atio, pkt, sizeof(*pkt));
+ op->vha = vha;
+ op->chip_reset = vha->hw->chip_reset;
+ INIT_WORK(&op->work, qlt_handle_abts_recv_work);
+ queue_work(qla_tgt_wq, &op->work);
+ return;
+}
+
int
qlt_mem_alloc(struct qla_hw_data *ha)
{
@@ -6532,13 +6874,25 @@ int __init qlt_init(void)
return -ENOMEM;
}
+ qla_tgt_plogi_cachep = kmem_cache_create("qla_tgt_plogi_cachep",
+ sizeof(qlt_plogi_ack_t),
+ __alignof__(qlt_plogi_ack_t),
+ 0, NULL);
+
+ if (!qla_tgt_plogi_cachep) {
+ ql_log(ql_log_fatal, NULL, 0xe06d,
+ "kmem_cache_create for qla_tgt_plogi_cachep failed\n");
+ ret = -ENOMEM;
+ goto out_mgmt_cmd_cachep;
+ }
+
qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
mempool_free_slab, qla_tgt_mgmt_cmd_cachep);
if (!qla_tgt_mgmt_cmd_mempool) {
ql_log(ql_log_fatal, NULL, 0xe06e,
"mempool_create for qla_tgt_mgmt_cmd_mempool failed\n");
ret = -ENOMEM;
- goto out_mgmt_cmd_cachep;
+ goto out_plogi_cachep;
}
qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0);
@@ -6555,6 +6909,8 @@ int __init qlt_init(void)
out_cmd_mempool:
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+out_plogi_cachep:
+ kmem_cache_destroy(qla_tgt_plogi_cachep);
out_mgmt_cmd_cachep:
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
return ret;
@@ -6567,5 +6923,6 @@ void qlt_exit(void)
destroy_workqueue(qla_tgt_wq);
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+ kmem_cache_destroy(qla_tgt_plogi_cachep);
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
}
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index bca584ae45b7..71b2865ba3c8 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -787,7 +787,7 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
#define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */
#define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */
#define QLA_TGT_STATE_PROCESSED 3 /* target done processing */
-#define QLA_TGT_STATE_ABORTED 4 /* Command aborted */
+
/* Special handles */
#define QLA_TGT_NULL_HANDLE 0
@@ -835,6 +835,7 @@ struct qla_tgt {
* HW lock.
*/
int irq_cmd_count;
+ int atio_irq_cmd_count;
int datasegs_per_cmd, datasegs_per_cont, sg_tablesize;
@@ -883,6 +884,7 @@ struct qla_tgt {
struct qla_tgt_sess_op {
struct scsi_qla_host *vha;
+ uint32_t chip_reset;
struct atio_from_isp atio;
struct work_struct work;
struct list_head cmd_list;
@@ -896,6 +898,19 @@ enum qla_sess_deletion {
QLA_SESS_DELETION_IN_PROGRESS = 2,
};
+typedef enum {
+ QLT_PLOGI_LINK_SAME_WWN,
+ QLT_PLOGI_LINK_CONFLICT,
+ QLT_PLOGI_LINK_MAX
+} qlt_plogi_link_t;
+
+typedef struct {
+ struct list_head list;
+ struct imm_ntfy_from_isp iocb;
+ port_id_t id;
+ int ref_count;
+} qlt_plogi_ack_t;
+
/*
* Equivilant to IT Nexus (Initiator-Target)
*/
@@ -907,8 +922,8 @@ struct qla_tgt_sess {
unsigned int deleted:2;
unsigned int local:1;
unsigned int logout_on_delete:1;
- unsigned int plogi_ack_needed:1;
unsigned int keep_nport_handle:1;
+ unsigned int send_els_logo:1;
unsigned char logout_completed;
@@ -925,9 +940,7 @@ struct qla_tgt_sess {
uint8_t port_name[WWN_SIZE];
struct work_struct free_work;
- union {
- struct imm_ntfy_from_isp tm_iocb;
- };
+ qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
};
struct qla_tgt_cmd {
@@ -949,6 +962,7 @@ struct qla_tgt_cmd {
unsigned int term_exchg:1;
unsigned int cmd_sent_to_fw:1;
unsigned int cmd_in_wq:1;
+ unsigned int aborted:1;
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
@@ -1120,6 +1134,14 @@ static inline uint32_t sid_to_key(const uint8_t *s_id)
return key;
}
+static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
+{
+ memset(p, 0, sizeof(*p));
+ p->b.domain = s_id[0];
+ p->b.area = s_id[1];
+ p->b.al_pa = s_id[2];
+}
+
/*
* Exported symbols from qla_target.c LLD logic used by qla2xxx code..
*/
@@ -1135,7 +1157,7 @@ extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *);
extern void qlt_init_atio_q_entries(struct scsi_qla_host *);
-extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *);
+extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *, uint8_t);
extern void qlt_24xx_config_rings(struct scsi_qla_host *);
extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *,
struct nvram_24xx *);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 81af294f15a7..faf0a126627f 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -284,6 +284,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
WARN_ON(cmd->cmd_flags & BIT_16);
+ cmd->vha->tgt_counters.qla_core_ret_sta_ctio++;
cmd->cmd_flags |= BIT_16;
transport_generic_free_cmd(&cmd->se_cmd, 0);
}
@@ -295,9 +296,10 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
*/
static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
{
+ cmd->vha->tgt_counters.core_qla_free_cmd++;
cmd->cmd_in_wq = 1;
INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
- queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+ queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
}
/*
@@ -342,9 +344,9 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess)
BUG_ON(!sess);
vha = sess->vha;
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
target_sess_cmd_list_set_waiting(se_sess);
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return 1;
}
@@ -358,9 +360,9 @@ static void tcm_qla2xxx_close_session(struct se_session *se_sess)
BUG_ON(!sess);
vha = sess->vha;
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
qlt_unreg_sess(sess);
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
@@ -454,6 +456,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
return -EINVAL;
}
+ cmd->vha->tgt_counters.qla_core_sbt_cmd++;
return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
cmd->unpacked_lun, data_length, fcp_task_attr,
data_dir, flags);
@@ -469,6 +472,7 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
*/
cmd->cmd_in_wq = 0;
cmd->cmd_flags |= BIT_11;
+ cmd->vha->tgt_counters.qla_core_ret_ctio++;
if (!cmd->write_data_transferred) {
/*
* Check if se_cmd has already been aborted via LUN_RESET, and
@@ -500,7 +504,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
cmd->cmd_flags |= BIT_10;
cmd->cmd_in_wq = 1;
INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
- queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+ queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
}
static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
@@ -643,7 +647,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *);
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess)
{
@@ -697,13 +701,13 @@ static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
if (!sess)
return;
- assert_spin_locked(&sess->vha->hw->hardware_lock);
+ assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
}
static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
{
- assert_spin_locked(&sess->vha->hw->hardware_lock);
+ assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
target_sess_cmd_list_set_waiting(sess->se_sess);
}
@@ -1077,7 +1081,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
scsi_qla_host_t *vha,
@@ -1116,7 +1120,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_set_sess_by_s_id(
struct tcm_qla2xxx_lport *lport,
@@ -1182,7 +1186,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
scsi_qla_host_t *vha,
@@ -1221,7 +1225,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_set_sess_by_loop_id(
struct tcm_qla2xxx_lport *lport,
@@ -1285,7 +1289,7 @@ static void tcm_qla2xxx_set_sess_by_loop_id(
}
/*
- * Should always be called with qla_hw_data->hardware_lock held.
+ * Should always be called with qla_hw_data->tgt.sess_lock held.
*/
static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport,
struct tcm_qla2xxx_nacl *nacl, struct qla_tgt_sess *sess)
@@ -1353,7 +1357,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
struct qla_tgt_sess *sess = qla_tgt_sess;
unsigned char port_name[36];
unsigned long flags;
- int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
+ int num_tags = (ha->cur_fw_xcb_count) ? ha->cur_fw_xcb_count :
TCM_QLA2XXX_DEFAULT_TAGS;
lport = vha->vha_tgt.target_lport_ptr;
@@ -1401,12 +1405,12 @@ static int tcm_qla2xxx_check_initiator_node_acl(
* And now setup the new se_nacl and session pointers into our HW lport
* mappings for fabric S_ID and LOOP_ID.
*/
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess,
qla_tgt_sess, s_id);
tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess,
qla_tgt_sess, loop_id);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
/*
* Finally register the new FC Nexus with TCM
*/
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d07fb653f5dc..b1bf42b93fcc 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -782,7 +782,7 @@ void scsi_attach_vpd(struct scsi_device *sdev)
int vpd_len = SCSI_VPD_PG_LEN;
int pg80_supported = 0;
int pg83_supported = 0;
- unsigned char *vpd_buf;
+ unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL;
if (sdev->skip_vpd_pages)
return;
@@ -828,8 +828,16 @@ retry_pg80:
kfree(vpd_buf);
goto retry_pg80;
}
+ mutex_lock(&sdev->inquiry_mutex);
+ orig_vpd_buf = sdev->vpd_pg80;
sdev->vpd_pg80_len = result;
- sdev->vpd_pg80 = vpd_buf;
+ rcu_assign_pointer(sdev->vpd_pg80, vpd_buf);
+ mutex_unlock(&sdev->inquiry_mutex);
+ synchronize_rcu();
+ if (orig_vpd_buf) {
+ kfree(orig_vpd_buf);
+ orig_vpd_buf = NULL;
+ }
vpd_len = SCSI_VPD_PG_LEN;
}
@@ -849,8 +857,14 @@ retry_pg83:
kfree(vpd_buf);
goto retry_pg83;
}
+ mutex_lock(&sdev->inquiry_mutex);
+ orig_vpd_buf = sdev->vpd_pg83;
sdev->vpd_pg83_len = result;
- sdev->vpd_pg83 = vpd_buf;
+ rcu_assign_pointer(sdev->vpd_pg83, vpd_buf);
+ mutex_unlock(&sdev->inquiry_mutex);
+ synchronize_rcu();
+ if (orig_vpd_buf)
+ kfree(orig_vpd_buf);
}
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index d09d60293c27..f3d69a98c725 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -129,7 +129,7 @@ static const char *scsi_debug_version_date = "20141022";
#define DEF_NO_LUN_0 0
#define DEF_NUM_PARTS 0
#define DEF_OPTS 0
-#define DEF_OPT_BLKS 64
+#define DEF_OPT_BLKS 1024
#define DEF_PHYSBLK_EXP 0
#define DEF_PTYPE 0
#define DEF_REMOVABLE false
@@ -679,7 +679,7 @@ static void *fake_store(unsigned long long lba)
static struct sd_dif_tuple *dif_store(sector_t sector)
{
- sector = do_div(sector, sdebug_store_sectors);
+ sector = sector_div(sector, sdebug_store_sectors);
return dif_storep + sector;
}
@@ -2781,7 +2781,7 @@ static unsigned long lba_to_map_index(sector_t lba)
lba += scsi_debug_unmap_granularity -
scsi_debug_unmap_alignment;
}
- do_div(lba, scsi_debug_unmap_granularity);
+ sector_div(lba, scsi_debug_unmap_granularity);
return lba;
}
@@ -4140,7 +4140,7 @@ MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
-MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
+MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
@@ -4847,10 +4847,10 @@ static int __init scsi_debug_init(void)
/* play around with geometry, don't waste too much on track 0 */
sdebug_heads = 8;
sdebug_sectors_per = 32;
- if (scsi_debug_dev_size_mb >= 16)
- sdebug_heads = 32;
- else if (scsi_debug_dev_size_mb >= 256)
+ if (scsi_debug_dev_size_mb >= 256)
sdebug_heads = 64;
+ else if (scsi_debug_dev_size_mb >= 16)
+ sdebug_heads = 32;
sdebug_cylinders_per = (unsigned long)sdebug_capacity /
(sdebug_sectors_per * sdebug_heads);
if (sdebug_cylinders_per >= 1024) {
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index e7649ed3f667..54d446c9f56e 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -153,76 +153,11 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev)
module_put(sdev->handler->module);
}
-/*
- * Functions for sysfs attribute 'dh_state'
- */
-static ssize_t
-store_dh_state(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_device_handler *scsi_dh;
- int err = -EINVAL;
-
- if (sdev->sdev_state == SDEV_CANCEL ||
- sdev->sdev_state == SDEV_DEL)
- return -ENODEV;
-
- if (!sdev->handler) {
- /*
- * Attach to a device handler
- */
- scsi_dh = scsi_dh_lookup(buf);
- if (!scsi_dh)
- return err;
- err = scsi_dh_handler_attach(sdev, scsi_dh);
- } else {
- if (!strncmp(buf, "detach", 6)) {
- /*
- * Detach from a device handler
- */
- sdev_printk(KERN_WARNING, sdev,
- "can't detach handler %s.\n",
- sdev->handler->name);
- err = -EINVAL;
- } else if (!strncmp(buf, "activate", 8)) {
- /*
- * Activate a device handler
- */
- if (sdev->handler->activate)
- err = sdev->handler->activate(sdev, NULL, NULL);
- else
- err = 0;
- }
- }
-
- return err<0?err:count;
-}
-
-static ssize_t
-show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
-
- if (!sdev->handler)
- return snprintf(buf, 20, "detached\n");
-
- return snprintf(buf, 20, "%s\n", sdev->handler->name);
-}
-
-static struct device_attribute scsi_dh_state_attr =
- __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
- store_dh_state);
-
int scsi_dh_add_device(struct scsi_device *sdev)
{
struct scsi_device_handler *devinfo = NULL;
const char *drv;
- int err;
-
- err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
- if (err)
- return err;
+ int err = 0;
drv = scsi_dh_find_driver(sdev);
if (drv)
@@ -238,11 +173,6 @@ void scsi_dh_release_device(struct scsi_device *sdev)
scsi_dh_handler_detach(sdev);
}
-void scsi_dh_remove_device(struct scsi_device *sdev)
-{
- device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
-}
-
/*
* scsi_register_device_handler - register a device handler personality
* module.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index dd8ad2a44510..fa6b2c4eb7a2 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -23,6 +23,7 @@
#include <linux/scatterlist.h>
#include <linux/blk-mq.h>
#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -3154,3 +3155,190 @@ void sdev_enable_disk_events(struct scsi_device *sdev)
atomic_dec(&sdev->disk_events_disable_depth);
}
EXPORT_SYMBOL(sdev_enable_disk_events);
+
+/**
+ * scsi_vpd_lun_id - return a unique device identification
+ * @sdev: SCSI device
+ * @id: buffer for the identification
+ * @id_len: length of the buffer
+ *
+ * Copies a unique device identification into @id based
+ * on the information in the VPD page 0x83 of the device.
+ * The string will be formatted as a SCSI name string.
+ *
+ * Returns the length of the identification or error on failure.
+ * If the identifier is longer than the supplied buffer the actual
+ * identifier length is returned and the buffer is not zero-padded.
+ */
+int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
+{
+ u8 cur_id_type = 0xff;
+ u8 cur_id_size = 0;
+ unsigned char *d, *cur_id_str;
+ unsigned char __rcu *vpd_pg83;
+ int id_size = -EINVAL;
+
+ rcu_read_lock();
+ vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+ if (!vpd_pg83) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+
+ /*
+ * Look for the correct descriptor.
+ * Order of preference for lun descriptor:
+ * - SCSI name string
+ * - NAA IEEE Registered Extended
+ * - EUI-64 based 16-byte
+ * - EUI-64 based 12-byte
+ * - NAA IEEE Registered
+ * - NAA IEEE Extended
+ * as longer descriptors reduce the likelyhood
+ * of identification clashes.
+ */
+
+ /* The id string must be at least 20 bytes + terminating NULL byte */
+ if (id_len < 21) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ memset(id, 0, id_len);
+ d = vpd_pg83 + 4;
+ while (d < vpd_pg83 + sdev->vpd_pg83_len) {
+ /* Skip designators not referring to the LUN */
+ if ((d[1] & 0x30) != 0x00)
+ goto next_desig;
+
+ switch (d[1] & 0xf) {
+ case 0x2:
+ /* EUI-64 */
+ if (cur_id_size > d[3])
+ break;
+ /* Prefer NAA IEEE Registered Extended */
+ if (cur_id_type == 0x3 &&
+ cur_id_size == d[3])
+ break;
+ cur_id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ switch (cur_id_size) {
+ case 8:
+ id_size = snprintf(id, id_len,
+ "eui.%8phN",
+ cur_id_str);
+ break;
+ case 12:
+ id_size = snprintf(id, id_len,
+ "eui.%12phN",
+ cur_id_str);
+ break;
+ case 16:
+ id_size = snprintf(id, id_len,
+ "eui.%16phN",
+ cur_id_str);
+ break;
+ default:
+ cur_id_size = 0;
+ break;
+ }
+ break;
+ case 0x3:
+ /* NAA */
+ if (cur_id_size > d[3])
+ break;
+ cur_id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ switch (cur_id_size) {
+ case 8:
+ id_size = snprintf(id, id_len,
+ "naa.%8phN",
+ cur_id_str);
+ break;
+ case 16:
+ id_size = snprintf(id, id_len,
+ "naa.%16phN",
+ cur_id_str);
+ break;
+ default:
+ cur_id_size = 0;
+ break;
+ }
+ break;
+ case 0x8:
+ /* SCSI name string */
+ if (cur_id_size + 4 > d[3])
+ break;
+ /* Prefer others for truncated descriptor */
+ if (cur_id_size && d[3] > id_len)
+ break;
+ cur_id_size = id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ if (cur_id_size >= id_len)
+ cur_id_size = id_len - 1;
+ memcpy(id, cur_id_str, cur_id_size);
+ /* Decrease priority for truncated descriptor */
+ if (cur_id_size != id_size)
+ cur_id_size = 6;
+ break;
+ default:
+ break;
+ }
+next_desig:
+ d += d[3] + 4;
+ }
+ rcu_read_unlock();
+
+ return id_size;
+}
+EXPORT_SYMBOL(scsi_vpd_lun_id);
+
+/*
+ * scsi_vpd_tpg_id - return a target port group identifier
+ * @sdev: SCSI device
+ *
+ * Returns the Target Port Group identifier from the information
+ * froom VPD page 0x83 of the device.
+ *
+ * Returns the identifier or error on failure.
+ */
+int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id)
+{
+ unsigned char *d;
+ unsigned char __rcu *vpd_pg83;
+ int group_id = -EAGAIN, rel_port = -1;
+
+ rcu_read_lock();
+ vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+ if (!vpd_pg83) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+
+ d = sdev->vpd_pg83 + 4;
+ while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
+ switch (d[1] & 0xf) {
+ case 0x4:
+ /* Relative target port */
+ rel_port = get_unaligned_be16(&d[6]);
+ break;
+ case 0x5:
+ /* Target port group */
+ group_id = get_unaligned_be16(&d[6]);
+ break;
+ default:
+ break;
+ }
+ d += d[3] + 4;
+ }
+ rcu_read_unlock();
+
+ if (group_id >= 0 && rel_id && rel_port != -1)
+ *rel_id = rel_port;
+
+ return group_id;
+}
+EXPORT_SYMBOL(scsi_vpd_tpg_id);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 4d01cdb1b348..27b4d0a6a01d 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -174,12 +174,11 @@ extern struct async_domain scsi_sd_probe_domain;
#ifdef CONFIG_SCSI_DH
int scsi_dh_add_device(struct scsi_device *sdev);
void scsi_dh_release_device(struct scsi_device *sdev);
-void scsi_dh_remove_device(struct scsi_device *sdev);
#else
static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
-static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
#endif
+static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
/*
* internal scsi timeout functions: for use by mid-layer and transport
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 054923e3393c..6a820668d442 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -236,6 +236,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
INIT_LIST_HEAD(&sdev->starved_entry);
INIT_LIST_HEAD(&sdev->event_list);
spin_lock_init(&sdev->list_lock);
+ mutex_init(&sdev->inquiry_mutex);
INIT_WORK(&sdev->event_work, scsi_evt_thread);
INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
@@ -1519,6 +1520,9 @@ EXPORT_SYMBOL(scsi_add_device);
void scsi_rescan_device(struct device *dev)
{
device_lock(dev);
+
+ scsi_attach_vpd(to_scsi_device(dev));
+
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 21930c9ac9cd..4f18a851e2c7 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -17,6 +17,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_driver.h>
@@ -760,11 +761,15 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \
{ \
struct device *dev = container_of(kobj, struct device, kobj); \
struct scsi_device *sdev = to_scsi_device(dev); \
+ int ret; \
if (!sdev->vpd_##_page) \
return -EINVAL; \
- return memory_read_from_buffer(buf, count, &off, \
- sdev->vpd_##_page, \
+ rcu_read_lock(); \
+ ret = memory_read_from_buffer(buf, count, &off, \
+ rcu_dereference(sdev->vpd_##_page), \
sdev->vpd_##_page##_len); \
+ rcu_read_unlock(); \
+ return ret; \
} \
static struct bin_attribute dev_attr_vpd_##_page = { \
.attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
@@ -901,6 +906,76 @@ static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
sdev_store_queue_depth);
static ssize_t
+sdev_show_wwid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ ssize_t count;
+
+ count = scsi_vpd_lun_id(sdev, buf, PAGE_SIZE);
+ if (count > 0) {
+ buf[count] = '\n';
+ count++;
+ }
+ return count;
+}
+static DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL);
+
+#ifdef CONFIG_SCSI_DH
+static ssize_t
+sdev_show_dh_state(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->handler)
+ return snprintf(buf, 20, "detached\n");
+
+ return snprintf(buf, 20, "%s\n", sdev->handler->name);
+}
+
+static ssize_t
+sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int err = -EINVAL;
+
+ if (sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
+ return -ENODEV;
+
+ if (!sdev->handler) {
+ /*
+ * Attach to a device handler
+ */
+ err = scsi_dh_attach(sdev->request_queue, buf);
+ } else if (!strncmp(buf, "activate", 8)) {
+ /*
+ * Activate a device handler
+ */
+ if (sdev->handler->activate)
+ err = sdev->handler->activate(sdev, NULL, NULL);
+ else
+ err = 0;
+ } else if (!strncmp(buf, "detach", 6)) {
+ /*
+ * Detach from a device handler
+ */
+ sdev_printk(KERN_WARNING, sdev,
+ "can't detach handler %s.\n",
+ sdev->handler->name);
+ err = -EINVAL;
+ }
+
+ return err < 0 ? err : count;
+}
+
+static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
+ sdev_store_dh_state);
+#endif
+
+static ssize_t
sdev_show_queue_ramp_up_period(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -969,6 +1044,10 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_queue_depth.attr,
&dev_attr_queue_type.attr,
+ &dev_attr_wwid.attr,
+#ifdef CONFIG_SCSI_DH
+ &dev_attr_dh_state.attr,
+#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
REF_EVT(inquiry_change_reported),
@@ -1058,11 +1137,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
error = scsi_dh_add_device(sdev);
- if (error) {
+ if (error)
+ /*
+ * device_handler is optional, so any error can be ignored
+ */
sdev_printk(KERN_INFO, sdev,
"failed to add device handler: %d\n", error);
- return error;
- }
device_enable_async_suspend(&sdev->sdev_dev);
error = device_add(&sdev->sdev_dev);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 24eaaf66af71..8a8822641b26 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2586,7 +2586,7 @@ fc_rport_final_delete(struct work_struct *work)
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
- put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_put(shost); /* for fc_host->rport list */
put_device(dev); /* for self-reference */
}
@@ -2650,7 +2650,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
- get_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_get(shost); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2685,7 +2685,7 @@ delete_rport:
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&rport->peers);
- put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_put(shost); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
kfree(rport);
@@ -3383,7 +3383,7 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
fc_host->npiv_vports_inuse++;
vport->number = fc_host->next_vport_number++;
list_add_tail(&vport->peers, &fc_host->vports);
- get_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_get(shost); /* for fc_host->vport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -3441,7 +3441,7 @@ delete_vport:
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&vport->peers);
- put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_put(shost); /* for fc_host->vport list */
fc_host->npiv_vports_inuse--;
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
@@ -3504,7 +3504,7 @@ fc_vport_terminate(struct fc_vport *vport)
vport->flags |= FC_VPORT_DELETED;
list_del(&vport->peers);
fc_host->npiv_vports_inuse--;
- put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_put(shost); /* for fc_host->vport list */
}
spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 30d26e345dcc..80520e2f0fa2 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -341,6 +341,22 @@ static int do_sas_phy_delete(struct device *dev, void *data)
}
/**
+ * is_sas_attached - check if device is SAS attached
+ * @sdev: scsi device to check
+ *
+ * returns true if the device is SAS attached
+ */
+int is_sas_attached(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = sdev->host;
+
+ return shost->transportt->host_attrs.ac.class ==
+ &sas_host_class.class;
+}
+EXPORT_SYMBOL(is_sas_attached);
+
+
+/**
* sas_remove_children - tear down a devices SAS data structures
* @dev: device belonging to the sas object
*
@@ -367,6 +383,20 @@ void sas_remove_host(struct Scsi_Host *shost)
EXPORT_SYMBOL(sas_remove_host);
/**
+ * sas_get_address - return the SAS address of the device
+ * @sdev: scsi device
+ *
+ * Returns the SAS address of the scsi device
+ */
+u64 sas_get_address(struct scsi_device *sdev)
+{
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+
+ return rdev->rphy.identify.sas_address;
+}
+EXPORT_SYMBOL(sas_get_address);
+
+/**
* sas_tlr_supported - checking TLR bit in vpd 0x90
* @sdev: scsi device struct
*
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 044d06410d4c..53ef1cb6418e 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -34,6 +34,8 @@
#include <scsi/scsi_driver.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_sas.h>
+
struct ses_device {
unsigned char *page1;
unsigned char *page1_types;
@@ -579,31 +581,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
static void ses_match_to_enclosure(struct enclosure_device *edev,
struct scsi_device *sdev)
{
- unsigned char *desc;
struct efd efd = {
.addr = 0,
};
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
- if (!sdev->vpd_pg83_len)
- return;
-
- desc = sdev->vpd_pg83 + 4;
- while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
- enum scsi_protocol proto = desc[0] >> 4;
- u8 code_set = desc[0] & 0x0f;
- u8 piv = desc[1] & 0x80;
- u8 assoc = (desc[1] & 0x30) >> 4;
- u8 type = desc[1] & 0x0f;
- u8 len = desc[3];
-
- if (piv && code_set == 1 && assoc == 1
- && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
- efd.addr = get_unaligned_be64(&desc[4]);
+ if (is_sas_attached(sdev))
+ efd.addr = sas_get_address(sdev);
- desc += len + 4;
- }
if (efd.addr) {
efd.dev = &sdev->sdev_gendev;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index b6486b5d8681..8c732c8de015 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -148,8 +148,6 @@ struct scsi_tape {
int tape_type;
int long_timeout; /* timeout for commands known to take long time */
- unsigned long max_pfn; /* the maximum page number reachable by the HBA */
-
/* Mode characteristics */
struct st_modedef modes[ST_NBR_MODES];
int current_mode;
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 3fba42ad9fb8..41c115c230d9 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -41,6 +41,7 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_fc.h>
/*
* All wire protocol details (storage protocol between the guest and the host)
@@ -92,9 +93,8 @@ enum vstor_packet_operation {
*/
struct hv_fc_wwn_packet {
- bool primary_active;
- u8 reserved1;
- u8 reserved2;
+ u8 primary_active;
+ u8 reserved1[3];
u8 primary_port_wwn[8];
u8 primary_node_wwn[8];
u8 secondary_port_wwn[8];
@@ -164,6 +164,26 @@ static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
*/
static int vmstor_proto_version;
+#define STORVSC_LOGGING_NONE 0
+#define STORVSC_LOGGING_ERROR 1
+#define STORVSC_LOGGING_WARN 2
+
+static int logging_level = STORVSC_LOGGING_ERROR;
+module_param(logging_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(logging_level,
+ "Logging level, 0 - None, 1 - Error (default), 2 - Warning.");
+
+static inline bool do_logging(int level)
+{
+ return logging_level >= level;
+}
+
+#define storvsc_log(dev, level, fmt, ...) \
+do { \
+ if (do_logging(level)) \
+ dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \
+} while (0)
+
struct vmscsi_win8_extension {
/*
* The following were added in Windows 8
@@ -378,6 +398,9 @@ static int storvsc_timeout = 180;
static int msft_blist_flags = BLIST_TRY_VPD_PAGES;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct scsi_transport_template *fc_transport_template;
+#endif
static void storvsc_on_channel_callback(void *context);
@@ -437,6 +460,11 @@ struct storvsc_device {
/* Used for vsc/vsp channel reset process */
struct storvsc_cmd_request init_request;
struct storvsc_cmd_request reset_request;
+ /*
+ * Currently active port and node names for FC devices.
+ */
+ u64 node_name;
+ u64 port_name;
};
struct hv_host_device {
@@ -676,29 +704,36 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns)
vmbus_are_subchannels_present(device->channel);
}
-static int storvsc_channel_init(struct hv_device *device)
+static void cache_wwn(struct storvsc_device *stor_device,
+ struct vstor_packet *vstor_packet)
{
- struct storvsc_device *stor_device;
- struct storvsc_cmd_request *request;
- struct vstor_packet *vstor_packet;
- int ret, t, i;
- int max_chns;
- bool process_sub_channels = false;
+ /*
+ * Cache the currently active port and node ww names.
+ */
+ if (vstor_packet->wwn_packet.primary_active) {
+ stor_device->node_name =
+ wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn);
+ stor_device->port_name =
+ wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn);
+ } else {
+ stor_device->node_name =
+ wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn);
+ stor_device->port_name =
+ wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn);
+ }
+}
- stor_device = get_out_stor_device(device);
- if (!stor_device)
- return -ENODEV;
- request = &stor_device->init_request;
+static int storvsc_execute_vstor_op(struct hv_device *device,
+ struct storvsc_cmd_request *request,
+ bool status_check)
+{
+ struct vstor_packet *vstor_packet;
+ int ret, t;
+
vstor_packet = &request->vstor_packet;
- /*
- * Now, initiate the vsc/vsp initialization protocol on the open
- * channel
- */
- memset(request, 0, sizeof(struct storvsc_cmd_request));
init_completion(&request->wait_event);
- vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
ret = vmbus_sendpacket(device->channel, vstor_packet,
@@ -708,27 +743,56 @@ static int storvsc_channel_init(struct hv_device *device)
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
- goto cleanup;
+ return ret;
t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ if (t == 0)
+ return -ETIMEDOUT;
+
+ if (!status_check)
+ return ret;
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ vstor_packet->status != 0)
+ return -EINVAL;
+
+ return ret;
+}
+
+static int storvsc_channel_init(struct hv_device *device, bool is_fc)
+{
+ struct storvsc_device *stor_device;
+ struct storvsc_cmd_request *request;
+ struct vstor_packet *vstor_packet;
+ int ret, i;
+ int max_chns;
+ bool process_sub_channels = false;
+ stor_device = get_out_stor_device(device);
+ if (!stor_device)
+ return -ENODEV;
+
+ request = &stor_device->init_request;
+ vstor_packet = &request->vstor_packet;
+
+ /*
+ * Now, initiate the vsc/vsp initialization protocol on the open
+ * channel
+ */
+ memset(request, 0, sizeof(struct storvsc_cmd_request));
+ vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+ ret = storvsc_execute_vstor_op(device, request, true);
+ if (ret)
+ return ret;
+ /*
+ * Query host supported protocol version.
+ */
for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
/* reuse the packet for version range supported */
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation =
VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
vstor_packet->version.major_minor =
vmstor_protocols[i].protocol_version;
@@ -737,26 +801,12 @@ static int storvsc_channel_init(struct hv_device *device)
* The revision number is only used in Windows; set it to 0.
*/
vstor_packet->version.revision = 0;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = storvsc_execute_vstor_op(device, request, false);
if (ret != 0)
- goto cleanup;
+ return ret;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO)
+ return -EINVAL;
if (vstor_packet->status == 0) {
vmstor_proto_version =
@@ -772,37 +822,15 @@ static int storvsc_channel_init(struct hv_device *device)
}
}
- if (vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (vstor_packet->status != 0)
+ return -EINVAL;
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
+ ret = storvsc_execute_vstor_op(device, request, true);
if (ret != 0)
- goto cleanup;
-
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ return ret;
/*
* Check to see if multi-channel support is there.
@@ -818,37 +846,34 @@ static int storvsc_channel_init(struct hv_device *device)
stor_device->max_transfer_bytes =
vstor_packet->storage_channel_properties.max_transfer_bytes;
- memset(vstor_packet, 0, sizeof(struct vstor_packet));
- vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (!is_fc)
+ goto done;
+ /*
+ * For FC devices retrieve FC HBA data.
+ */
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA;
+ ret = storvsc_execute_vstor_op(device, request, true);
if (ret != 0)
- goto cleanup;
+ return ret;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ /*
+ * Cache the currently active port and node ww names.
+ */
+ cache_wwn(stor_device, vstor_packet);
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+done:
+
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+ ret = storvsc_execute_vstor_op(device, request, true);
+ if (ret != 0)
+ return ret;
if (process_sub_channels)
handle_multichannel_storage(device, max_chns);
-
-cleanup:
return ret;
}
@@ -920,19 +945,16 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
}
-static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
+ struct storvsc_device *stor_dev)
{
struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
struct Scsi_Host *host;
- struct storvsc_device *stor_dev;
- struct hv_device *dev = host_dev->dev;
u32 payload_sz = cmd_request->payload_sz;
void *payload = cmd_request->payload;
- stor_dev = get_in_stor_device(dev);
host = stor_dev->host;
vm_srb = &cmd_request->vstor_packet.vm_srb;
@@ -941,7 +963,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
+ do_logging(STORVSC_LOGGING_ERROR))
scsi_print_sense_hdr(scmnd->device, "storvsc",
&sense_hdr);
}
@@ -961,14 +984,13 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
kfree(payload);
}
-static void storvsc_on_io_completion(struct hv_device *device,
+static void storvsc_on_io_completion(struct storvsc_device *stor_device,
struct vstor_packet *vstor_packet,
struct storvsc_cmd_request *request)
{
- struct storvsc_device *stor_device;
struct vstor_packet *stor_pkt;
+ struct hv_device *device = stor_device->device;
- stor_device = hv_get_drvdata(device);
stor_pkt = &request->vstor_packet;
/*
@@ -995,6 +1017,13 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.sense_info_length =
vstor_packet->vm_srb.sense_info_length;
+ if (vstor_packet->vm_srb.scsi_status != 0 ||
+ vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
+ storvsc_log(device, STORVSC_LOGGING_WARN,
+ "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+ stor_pkt->vm_srb.cdb[0],
+ vstor_packet->vm_srb.scsi_status,
+ vstor_packet->vm_srb.srb_status);
if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
@@ -1002,6 +1031,10 @@ static void storvsc_on_io_completion(struct hv_device *device,
SRB_STATUS_AUTOSENSE_VALID) {
/* autosense data available */
+ storvsc_log(device, STORVSC_LOGGING_WARN,
+ "stor pkt %p autosense data valid - len %d\n",
+ request, vstor_packet->vm_srb.sense_info_length);
+
memcpy(request->cmd->sense_buffer,
vstor_packet->vm_srb.sense_data,
vstor_packet->vm_srb.sense_info_length);
@@ -1012,7 +1045,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.data_transfer_length =
vstor_packet->vm_srb.data_transfer_length;
- storvsc_command_completion(request);
+ storvsc_command_completion(request, stor_device);
if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
stor_device->drain_notify)
@@ -1021,21 +1054,19 @@ static void storvsc_on_io_completion(struct hv_device *device,
}
-static void storvsc_on_receive(struct hv_device *device,
+static void storvsc_on_receive(struct storvsc_device *stor_device,
struct vstor_packet *vstor_packet,
struct storvsc_cmd_request *request)
{
struct storvsc_scan_work *work;
- struct storvsc_device *stor_device;
switch (vstor_packet->operation) {
case VSTOR_OPERATION_COMPLETE_IO:
- storvsc_on_io_completion(device, vstor_packet, request);
+ storvsc_on_io_completion(stor_device, vstor_packet, request);
break;
case VSTOR_OPERATION_REMOVE_DEVICE:
case VSTOR_OPERATION_ENUMERATE_BUS:
- stor_device = get_in_stor_device(device);
work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
if (!work)
return;
@@ -1045,6 +1076,13 @@ static void storvsc_on_receive(struct hv_device *device,
schedule_work(&work->work);
break;
+ case VSTOR_OPERATION_FCHBA_DATA:
+ cache_wwn(stor_device, vstor_packet);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_host_node_name(stor_device->host) = stor_device->node_name;
+ fc_host_port_name(stor_device->host) = stor_device->port_name;
+#endif
+ break;
default:
break;
}
@@ -1088,7 +1126,7 @@ static void storvsc_on_channel_callback(void *context)
vmscsi_size_delta));
complete(&request->wait_event);
} else {
- storvsc_on_receive(device,
+ storvsc_on_receive(stor_device,
(struct vstor_packet *)packet,
request);
}
@@ -1100,7 +1138,8 @@ static void storvsc_on_channel_callback(void *context)
return;
}
-static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
+ bool is_fc)
{
struct vmstorage_channel_properties props;
int ret;
@@ -1117,7 +1156,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
if (ret != 0)
return ret;
- ret = storvsc_channel_init(device);
+ ret = storvsc_channel_init(device, is_fc);
return ret;
}
@@ -1542,6 +1581,7 @@ static int storvsc_probe(struct hv_device *device,
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
+ bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
int target = 0;
struct storvsc_device *stor_device;
int max_luns_per_target;
@@ -1599,7 +1639,7 @@ static int storvsc_probe(struct hv_device *device,
hv_set_drvdata(device, stor_device);
stor_device->port_number = host->host_no;
- ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
+ ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
if (ret)
goto err_out1;
@@ -1611,6 +1651,9 @@ static int storvsc_probe(struct hv_device *device,
host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET;
host->max_id = STORVSC_FC_MAX_TARGETS;
host->max_channel = STORVSC_FC_MAX_CHANNELS - 1;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ host->transportt = fc_transport_template;
+#endif
break;
case SCSI_GUID:
@@ -1650,6 +1693,12 @@ static int storvsc_probe(struct hv_device *device,
goto err_out2;
}
}
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (host->transportt == fc_transport_template) {
+ fc_host_node_name(host) = stor_device->node_name;
+ fc_host_port_name(host) = stor_device->port_name;
+ }
+#endif
return 0;
err_out2:
@@ -1675,6 +1724,10 @@ static int storvsc_remove(struct hv_device *dev)
struct storvsc_device *stor_device = hv_get_drvdata(dev);
struct Scsi_Host *host = stor_device->host;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (host->transportt == fc_transport_template)
+ fc_remove_host(host);
+#endif
scsi_remove_host(host);
storvsc_dev_remove(dev);
scsi_host_put(host);
@@ -1689,8 +1742,16 @@ static struct hv_driver storvsc_drv = {
.remove = storvsc_remove,
};
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct fc_function_template fc_transport_functions = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+};
+#endif
+
static int __init storvsc_drv_init(void)
{
+ int ret;
/*
* Divide the ring buffer data size (which is 1 page less
@@ -1705,12 +1766,28 @@ static int __init storvsc_drv_init(void)
vmscsi_size_delta,
sizeof(u64)));
- return vmbus_driver_register(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_transport_template = fc_attach_transport(&fc_transport_functions);
+ if (!fc_transport_template)
+ return -ENODEV;
+#endif
+
+ ret = vmbus_driver_register(&storvsc_drv);
+
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (ret)
+ fc_release_transport(fc_transport_template);
+#endif
+
+ return ret;
}
static void __exit storvsc_drv_exit(void)
{
vmbus_driver_unregister(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_release_transport(fc_transport_template);
+#endif
}
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 9714f2a8b329..d2a7b127b05c 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -333,7 +333,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
- dev_err(dev, "Intialization failed\n");
+ dev_err(dev, "Initialization failed\n");
goto out_disable_rpm;
}
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 0f133c1817de..6164634aff18 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -349,9 +349,9 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
* Map all data buffers for a command into PCI space and
* setup the scatter/gather list if needed.
*/
-static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
- struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
- struct PVSCSIRingReqDesc *e)
+static int pvscsi_map_buffers(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
+ struct PVSCSIRingReqDesc *e)
{
unsigned count;
unsigned bufflen = scsi_bufflen(cmd);
@@ -360,18 +360,30 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
e->dataLen = bufflen;
e->dataAddr = 0;
if (bufflen == 0)
- return;
+ return 0;
sg = scsi_sglist(cmd);
count = scsi_sg_count(cmd);
if (count != 0) {
int segs = scsi_dma_map(cmd);
- if (segs > 1) {
+
+ if (segs == -ENOMEM) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map cmd sglist for DMA.\n");
+ return -ENOMEM;
+ } else if (segs > 1) {
pvscsi_create_sg(ctx, sg, segs);
e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
SGL_SIZE, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map ctx sglist for DMA.\n");
+ scsi_dma_unmap(cmd);
+ ctx->sglPA = 0;
+ return -ENOMEM;
+ }
e->dataAddr = ctx->sglPA;
} else
e->dataAddr = sg_dma_address(sg);
@@ -382,8 +394,15 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
*/
ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
cmd->sc_data_direction);
+ if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map direct data buffer for DMA.\n");
+ return -ENOMEM;
+ }
e->dataAddr = ctx->dataPA;
}
+
+ return 0;
}
static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
@@ -690,6 +709,12 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map sense buffer for DMA.\n");
+ ctx->sensePA = 0;
+ return -ENOMEM;
+ }
e->senseAddr = ctx->sensePA;
e->senseLen = SCSI_SENSE_BUFFERSIZE;
} else {
@@ -711,7 +736,15 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
else
e->flags = 0;
- pvscsi_map_buffers(adapter, ctx, cmd, e);
+ if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) {
+ if (cmd->sense_buffer) {
+ pci_unmap_single(adapter->dev, ctx->sensePA,
+ SCSI_SENSE_BUFFERSIZE,
+ PCI_DMA_FROMDEVICE);
+ ctx->sensePA = 0;
+ }
+ return -ENOMEM;
+ }
e->context = pvscsi_map_context(adapter, ctx);
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
index ee16f0c5c47d..12712c92f37a 100644
--- a/drivers/scsi/vmw_pvscsi.h
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -26,7 +26,7 @@
#include <linux/types.h>
-#define PVSCSI_DRIVER_VERSION_STRING "1.0.5.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING "1.0.6.0-k"
#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index be56b22ca941..92863e3818e5 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -469,6 +469,9 @@ void clk_enable_init_clocks(void)
unsigned long clk_get_rate(struct clk *clk)
{
+ if (!clk)
+ return 0;
+
return clk->rate;
}
EXPORT_SYMBOL_GPL(clk_get_rate);
@@ -478,6 +481,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
int ret = -EOPNOTSUPP;
unsigned long flags;
+ if (!clk)
+ return 0;
+
spin_lock_irqsave(&clock_lock, flags);
if (likely(clk->ops && clk->ops->set_rate)) {
@@ -535,12 +541,18 @@ EXPORT_SYMBOL_GPL(clk_set_parent);
struct clk *clk_get_parent(struct clk *clk)
{
+ if (!clk)
+ return NULL;
+
return clk->parent;
}
EXPORT_SYMBOL_GPL(clk_get_parent);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
+ if (!clk)
+ return 0;
+
if (likely(clk->ops && clk->ops->round_rate)) {
unsigned long flags, rounded;
@@ -555,94 +567,6 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL_GPL(clk_round_rate);
-long clk_round_parent(struct clk *clk, unsigned long target,
- unsigned long *best_freq, unsigned long *parent_freq,
- unsigned int div_min, unsigned int div_max)
-{
- struct cpufreq_frequency_table *freq, *best = NULL;
- unsigned long error = ULONG_MAX, freq_high, freq_low, div;
- struct clk *parent = clk_get_parent(clk);
-
- if (!parent) {
- *parent_freq = 0;
- *best_freq = clk_round_rate(clk, target);
- return abs(target - *best_freq);
- }
-
- cpufreq_for_each_valid_entry(freq, parent->freq_table) {
- if (unlikely(freq->frequency / target <= div_min - 1)) {
- unsigned long freq_max;
-
- freq_max = (freq->frequency + div_min / 2) / div_min;
- if (error > target - freq_max) {
- error = target - freq_max;
- best = freq;
- if (best_freq)
- *best_freq = freq_max;
- }
-
- pr_debug("too low freq %u, error %lu\n", freq->frequency,
- target - freq_max);
-
- if (!error)
- break;
-
- continue;
- }
-
- if (unlikely(freq->frequency / target >= div_max)) {
- unsigned long freq_min;
-
- freq_min = (freq->frequency + div_max / 2) / div_max;
- if (error > freq_min - target) {
- error = freq_min - target;
- best = freq;
- if (best_freq)
- *best_freq = freq_min;
- }
-
- pr_debug("too high freq %u, error %lu\n", freq->frequency,
- freq_min - target);
-
- if (!error)
- break;
-
- continue;
- }
-
- div = freq->frequency / target;
- freq_high = freq->frequency / div;
- freq_low = freq->frequency / (div + 1);
-
- if (freq_high - target < error) {
- error = freq_high - target;
- best = freq;
- if (best_freq)
- *best_freq = freq_high;
- }
-
- if (target - freq_low < error) {
- error = target - freq_low;
- best = freq;
- if (best_freq)
- *best_freq = freq_low;
- }
-
- pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
- freq->frequency, div, freq_high, div + 1, freq_low,
- *best_freq, best->frequency);
-
- if (!error)
- break;
- }
-
- if (parent_freq)
- *parent_freq = best->frequency;
-
- return error;
-}
-EXPORT_SYMBOL_GPL(clk_round_parent);
-
#ifdef CONFIG_PM
static void clks_core_resume(void)
{
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 4e853ed2c82b..fb2b3935b658 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,6 +1,8 @@
menu "SOC (System On Chip) specific Drivers"
+source "drivers/soc/bcm/Kconfig"
source "drivers/soc/brcmstb/Kconfig"
+source "drivers/soc/fsl/qe/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/rockchip/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index f2ba2e932ae1..2afdc74f7491 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -2,8 +2,11 @@
# Makefile for the Linux Kernel SOC specific device drivers.
#
+obj-y += bcm/
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
+obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
+obj-y += fsl/
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
obj-$(CONFIG_ARCH_QCOM) += qcom/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
new file mode 100644
index 000000000000..3066edea184d
--- /dev/null
+++ b/drivers/soc/bcm/Kconfig
@@ -0,0 +1,9 @@
+config RASPBERRYPI_POWER
+ bool "Raspberry Pi power domain driver"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on RASPBERRYPI_FIRMWARE=y
+ select PM_GENERIC_DOMAINS if PM
+ select PM_GENERIC_DOMAINS_OF if PM
+ help
+ This enables support for the RPi power domains which can be enabled
+ or disabled via the RPi firmware.
diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile
new file mode 100644
index 000000000000..63aa3eb23087
--- /dev/null
+++ b/drivers/soc/bcm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c
new file mode 100644
index 000000000000..fe96a8b956fb
--- /dev/null
+++ b/drivers/soc/bcm/raspberrypi-power.c
@@ -0,0 +1,247 @@
+/* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
+ *
+ * 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.
+ *
+ * Authors:
+ * Alexander Aring <aar@pengutronix.de>
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <dt-bindings/power/raspberrypi-power.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+/*
+ * Firmware indices for the old power domains interface. Only a few
+ * of them were actually implemented.
+ */
+#define RPI_OLD_POWER_DOMAIN_USB 3
+#define RPI_OLD_POWER_DOMAIN_V3D 10
+
+struct rpi_power_domain {
+ u32 domain;
+ bool enabled;
+ bool old_interface;
+ struct generic_pm_domain base;
+ struct rpi_firmware *fw;
+};
+
+struct rpi_power_domains {
+ bool has_new_interface;
+ struct genpd_onecell_data xlate;
+ struct rpi_firmware *fw;
+ struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT];
+};
+
+/*
+ * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and
+ * RPI_FIRMWARE_SET_DOMAIN_STATE
+ */
+struct rpi_power_domain_packet {
+ u32 domain;
+ u32 on;
+} __packet;
+
+/*
+ * Asks the firmware to enable or disable power on a specific power
+ * domain.
+ */
+static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on)
+{
+ struct rpi_power_domain_packet packet;
+
+ packet.domain = rpi_domain->domain;
+ packet.on = on;
+ return rpi_firmware_property(rpi_domain->fw,
+ rpi_domain->old_interface ?
+ RPI_FIRMWARE_SET_POWER_STATE :
+ RPI_FIRMWARE_SET_DOMAIN_STATE,
+ &packet, sizeof(packet));
+}
+
+static int rpi_domain_off(struct generic_pm_domain *domain)
+{
+ struct rpi_power_domain *rpi_domain =
+ container_of(domain, struct rpi_power_domain, base);
+
+ return rpi_firmware_set_power(rpi_domain, false);
+}
+
+static int rpi_domain_on(struct generic_pm_domain *domain)
+{
+ struct rpi_power_domain *rpi_domain =
+ container_of(domain, struct rpi_power_domain, base);
+
+ return rpi_firmware_set_power(rpi_domain, true);
+}
+
+static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
+ int xlate_index, const char *name)
+{
+ struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
+
+ dom->fw = rpi_domains->fw;
+
+ dom->base.name = name;
+ dom->base.power_on = rpi_domain_on;
+ dom->base.power_off = rpi_domain_off;
+
+ /*
+ * Treat all power domains as off at boot.
+ *
+ * The firmware itself may be keeping some domains on, but
+ * from Linux's perspective all we control is the refcounts
+ * that we give to the firmware, and we can't ask the firmware
+ * to turn off something that we haven't ourselves turned on.
+ */
+ pm_genpd_init(&dom->base, NULL, true);
+
+ rpi_domains->xlate.domains[xlate_index] = &dom->base;
+}
+
+static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains,
+ int xlate_index, const char *name)
+{
+ struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
+
+ if (!rpi_domains->has_new_interface)
+ return;
+
+ /* The DT binding index is the firmware's domain index minus one. */
+ dom->domain = xlate_index + 1;
+
+ rpi_common_init_power_domain(rpi_domains, xlate_index, name);
+}
+
+static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains,
+ int xlate_index, int domain,
+ const char *name)
+{
+ struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
+
+ dom->old_interface = true;
+ dom->domain = domain;
+
+ rpi_common_init_power_domain(rpi_domains, xlate_index, name);
+}
+
+/*
+ * Detects whether the firmware supports the new power domains interface.
+ *
+ * The firmware doesn't actually return an error on an unknown tag,
+ * and just skips over it, so we do the detection by putting an
+ * unexpected value in the return field and checking if it was
+ * unchanged.
+ */
+static bool
+rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
+{
+ struct rpi_power_domain_packet packet;
+ int ret;
+
+ packet.domain = RPI_POWER_DOMAIN_ARM;
+ packet.on = ~0;
+
+ ret = rpi_firmware_property(rpi_domains->fw,
+ RPI_FIRMWARE_GET_DOMAIN_STATE,
+ &packet, sizeof(packet));
+
+ return ret == 0 && packet.on != ~0;
+}
+
+static int rpi_power_probe(struct platform_device *pdev)
+{
+ struct device_node *fw_np;
+ struct device *dev = &pdev->dev;
+ struct rpi_power_domains *rpi_domains;
+
+ rpi_domains = devm_kzalloc(dev, sizeof(*rpi_domains), GFP_KERNEL);
+ if (!rpi_domains)
+ return -ENOMEM;
+
+ rpi_domains->xlate.domains =
+ devm_kzalloc(dev, sizeof(*rpi_domains->xlate.domains) *
+ RPI_POWER_DOMAIN_COUNT, GFP_KERNEL);
+ if (!rpi_domains->xlate.domains)
+ return -ENOMEM;
+
+ rpi_domains->xlate.num_domains = RPI_POWER_DOMAIN_COUNT;
+
+ fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+ if (!fw_np) {
+ dev_err(&pdev->dev, "no firmware node\n");
+ return -ENODEV;
+ }
+
+ rpi_domains->fw = rpi_firmware_get(fw_np);
+ of_node_put(fw_np);
+ if (!rpi_domains->fw)
+ return -EPROBE_DEFER;
+
+ rpi_domains->has_new_interface =
+ rpi_has_new_domain_support(rpi_domains);
+
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER,
+ "VIDEO_SCALER");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI");
+
+ /*
+ * Use the old firmware interface for USB power, so that we
+ * can turn it on even if the firmware hasn't been updated.
+ */
+ rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB,
+ RPI_OLD_POWER_DOMAIN_USB, "USB");
+
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER,
+ "TRANSPOSER");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP");
+ rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM");
+
+ of_genpd_add_provider_onecell(dev->of_node, &rpi_domains->xlate);
+
+ platform_set_drvdata(pdev, rpi_domains);
+
+ return 0;
+}
+
+static const struct of_device_id rpi_power_of_match[] = {
+ { .compatible = "raspberrypi,bcm2835-power", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_power_of_match);
+
+static struct platform_driver rpi_power_driver = {
+ .driver = {
+ .name = "raspberrypi-power",
+ .of_match_table = rpi_power_of_match,
+ },
+ .probe = rpi_power_probe,
+};
+builtin_platform_driver(rpi_power_driver);
+
+MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>");
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("Raspberry Pi power domain driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/dove/pmu.c b/drivers/soc/dove/pmu.c
index abd087917f80..039374e9fdc0 100644
--- a/drivers/soc/dove/pmu.c
+++ b/drivers/soc/dove/pmu.c
@@ -305,6 +305,49 @@ static int __init dove_init_pmu_irq(struct pmu_data *pmu, int irq)
return 0;
}
+int __init dove_init_pmu_legacy(const struct dove_pmu_initdata *initdata)
+{
+ const struct dove_pmu_domain_initdata *domain_initdata;
+ struct pmu_data *pmu;
+ int ret;
+
+ pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+
+ spin_lock_init(&pmu->lock);
+ pmu->pmc_base = initdata->pmc_base;
+ pmu->pmu_base = initdata->pmu_base;
+
+ pmu_reset_init(pmu);
+ for (domain_initdata = initdata->domains; domain_initdata->name;
+ domain_initdata++) {
+ struct pmu_domain *domain;
+
+ domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+ if (domain) {
+ domain->pmu = pmu;
+ domain->pwr_mask = domain_initdata->pwr_mask;
+ domain->rst_mask = domain_initdata->rst_mask;
+ domain->iso_mask = domain_initdata->iso_mask;
+ domain->base.name = domain_initdata->name;
+
+ __pmu_domain_register(domain, NULL);
+ }
+ }
+
+ ret = dove_init_pmu_irq(pmu, initdata->irq);
+ if (ret)
+ pr_err("dove_init_pmu_irq() failed: %d\n", ret);
+
+ if (pmu->irq_domain)
+ irq_domain_associate_many(pmu->irq_domain,
+ initdata->irq_domain_start,
+ 0, NR_PMU_IRQS);
+
+ return 0;
+}
+
/*
* pmu: power-manager@d0000 {
* compatible = "marvell,dove-pmu";
diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile
new file mode 100644
index 000000000000..203307fd92c1
--- /dev/null
+++ b/drivers/soc/fsl/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux Kernel SOC fsl specific device drivers
+#
+
+obj-$(CONFIG_QUICC_ENGINE) += qe/
+obj-$(CONFIG_CPM) += qe/
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 3c251993bacd..20978f2058a6 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -2,6 +2,17 @@
# QE Communication options
#
+config QUICC_ENGINE
+ bool "Freescale QUICC Engine (QE) Support"
+ depends on FSL_SOC && PPC32
+ select GENERIC_ALLOCATOR
+ select CRC32
+ help
+ The QUICC Engine (QE) is a new generation of communications
+ coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
+ Selecting this option means that you wish to build a kernel
+ for a machine with a QE coprocessor.
+
config UCC_SLOW
bool
default y if SERIAL_QE
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/drivers/soc/fsl/qe/Makefile
index f1855c185291..ffac5410c5c7 100644
--- a/arch/powerpc/sysdev/qe_lib/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -1,8 +1,8 @@
#
# Makefile for the linux ppc-specific parts of QE
#
-obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o
-
+obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
+obj-$(CONFIG_CPM) += qe_common.o
obj-$(CONFIG_UCC) += ucc.o
obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 521e67a49dc4..aa5c11acf212 100644
--- a/arch/powerpc/sysdev/qe_lib/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -21,7 +21,7 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/export.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
struct qe_gpio_chip {
struct of_mm_gpio_chip mm_gc;
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/drivers/soc/fsl/qe/qe.c
index c2518cdb7ddb..709fc63809e5 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -31,8 +31,8 @@
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
#include <asm/prom.h>
#include <asm/rheap.h>
@@ -671,6 +671,19 @@ unsigned int qe_get_num_of_snums(void)
}
EXPORT_SYMBOL(qe_get_num_of_snums);
+static int __init qe_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!np)
+ return -ENODEV;
+ qe_reset();
+ of_node_put(np);
+ return 0;
+}
+subsys_initcall(qe_init);
+
#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx)
static int qe_resume(struct platform_device *ofdev)
{
diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c
new file mode 100644
index 000000000000..419fa5b7be4d
--- /dev/null
+++ b/drivers/soc/fsl/qe/qe_common.c
@@ -0,0 +1,235 @@
+/*
+ * Common CPM code
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright 2007-2008,2010 Freescale Semiconductor, Inc.
+ *
+ * Some parts derived from commproc.c/cpm2_common.c, which is:
+ * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
+ * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <soc/fsl/qe/qe.h>
+
+static struct gen_pool *muram_pool;
+static spinlock_t cpm_muram_lock;
+static u8 __iomem *muram_vbase;
+static phys_addr_t muram_pbase;
+
+struct muram_block {
+ struct list_head head;
+ unsigned long start;
+ int size;
+};
+
+static LIST_HEAD(muram_block_list);
+
+/* max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define GENPOOL_OFFSET (4096 * 8)
+
+int cpm_muram_init(void)
+{
+ struct device_node *np;
+ struct resource r;
+ u32 zero[OF_MAX_ADDR_CELLS] = {};
+ resource_size_t max = 0;
+ int i = 0;
+ int ret = 0;
+
+ if (muram_pbase)
+ return 0;
+
+ spin_lock_init(&cpm_muram_lock);
+ np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data");
+ if (!np) {
+ /* try legacy bindings */
+ np = of_find_node_by_name(NULL, "data-only");
+ if (!np) {
+ pr_err("Cannot find CPM muram data node");
+ ret = -ENODEV;
+ goto out_muram;
+ }
+ }
+
+ muram_pool = gen_pool_create(0, -1);
+ muram_pbase = of_translate_address(np, zero);
+ if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) {
+ pr_err("Cannot translate zero through CPM muram node");
+ ret = -ENODEV;
+ goto out_pool;
+ }
+
+ while (of_address_to_resource(np, i++, &r) == 0) {
+ if (r.end > max)
+ max = r.end;
+ ret = gen_pool_add(muram_pool, r.start - muram_pbase +
+ GENPOOL_OFFSET, resource_size(&r), -1);
+ if (ret) {
+ pr_err("QE: couldn't add muram to pool!\n");
+ goto out_pool;
+ }
+ }
+
+ muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1);
+ if (!muram_vbase) {
+ pr_err("Cannot map QE muram");
+ ret = -ENOMEM;
+ goto out_pool;
+ }
+ goto out_muram;
+out_pool:
+ gen_pool_destroy(muram_pool);
+out_muram:
+ of_node_put(np);
+ return ret;
+}
+
+/*
+ * cpm_muram_alloc - allocate the requested size worth of multi-user ram
+ * @size: number of bytes to allocate
+ * @align: requested alignment, in bytes
+ *
+ * This function returns an offset into the muram area.
+ * Use cpm_dpram_addr() to get the virtual address of the area.
+ * Use cpm_muram_free() to free the allocation.
+ */
+unsigned long cpm_muram_alloc(unsigned long size, unsigned long align)
+{
+ unsigned long start;
+ unsigned long flags;
+ struct genpool_data_align muram_pool_data;
+
+ spin_lock_irqsave(&cpm_muram_lock, flags);
+ muram_pool_data.align = align;
+ start = cpm_muram_alloc_common(size, gen_pool_first_fit_align,
+ &muram_pool_data);
+ spin_unlock_irqrestore(&cpm_muram_lock, flags);
+ return start;
+}
+EXPORT_SYMBOL(cpm_muram_alloc);
+
+/**
+ * cpm_muram_free - free a chunk of multi-user ram
+ * @offset: The beginning of the chunk as returned by cpm_muram_alloc().
+ */
+int cpm_muram_free(unsigned long offset)
+{
+ unsigned long flags;
+ int size;
+ struct muram_block *tmp;
+
+ size = 0;
+ spin_lock_irqsave(&cpm_muram_lock, flags);
+ list_for_each_entry(tmp, &muram_block_list, head) {
+ if (tmp->start == offset) {
+ size = tmp->size;
+ list_del(&tmp->head);
+ kfree(tmp);
+ break;
+ }
+ }
+ gen_pool_free(muram_pool, offset + GENPOOL_OFFSET, size);
+ spin_unlock_irqrestore(&cpm_muram_lock, flags);
+ return size;
+}
+EXPORT_SYMBOL(cpm_muram_free);
+
+/*
+ * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram
+ * @offset: offset of allocation start address
+ * @size: number of bytes to allocate
+ * This function returns an offset into the muram area
+ * Use cpm_dpram_addr() to get the virtual address of the area.
+ * Use cpm_muram_free() to free the allocation.
+ */
+unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size)
+{
+ unsigned long start;
+ unsigned long flags;
+ struct genpool_data_fixed muram_pool_data_fixed;
+
+ spin_lock_irqsave(&cpm_muram_lock, flags);
+ muram_pool_data_fixed.offset = offset + GENPOOL_OFFSET;
+ start = cpm_muram_alloc_common(size, gen_pool_fixed_alloc,
+ &muram_pool_data_fixed);
+ spin_unlock_irqrestore(&cpm_muram_lock, flags);
+ return start;
+}
+EXPORT_SYMBOL(cpm_muram_alloc_fixed);
+
+/*
+ * cpm_muram_alloc_common - cpm_muram_alloc common code
+ * @size: number of bytes to allocate
+ * @algo: algorithm for alloc.
+ * @data: data for genalloc's algorithm.
+ *
+ * This function returns an offset into the muram area.
+ */
+unsigned long cpm_muram_alloc_common(unsigned long size, genpool_algo_t algo,
+ void *data)
+{
+ struct muram_block *entry;
+ unsigned long start;
+
+ start = gen_pool_alloc_algo(muram_pool, size, algo, data);
+ if (!start)
+ goto out2;
+ start = start - GENPOOL_OFFSET;
+ memset_io(cpm_muram_addr(start), 0, size);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ goto out1;
+ entry->start = start;
+ entry->size = size;
+ list_add(&entry->head, &muram_block_list);
+
+ return start;
+out1:
+ gen_pool_free(muram_pool, start, size);
+out2:
+ return (unsigned long)-ENOMEM;
+}
+
+/**
+ * cpm_muram_addr - turn a muram offset into a virtual address
+ * @offset: muram offset to convert
+ */
+void __iomem *cpm_muram_addr(unsigned long offset)
+{
+ return muram_vbase + offset;
+}
+EXPORT_SYMBOL(cpm_muram_addr);
+
+unsigned long cpm_muram_offset(void __iomem *addr)
+{
+ return addr - (void __iomem *)muram_vbase;
+}
+EXPORT_SYMBOL(cpm_muram_offset);
+
+/**
+ * cpm_muram_dma - turn a muram virtual address into a DMA address
+ * @offset: virtual address from cpm_muram_addr() to convert
+ */
+dma_addr_t cpm_muram_dma(void __iomem *addr)
+{
+ return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
+}
+EXPORT_SYMBOL(cpm_muram_dma);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/drivers/soc/fsl/qe/qe_ic.c
index ef36f16f9f6f..b77d01ff8330 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/drivers/soc/fsl/qe/qe_ic.c
@@ -14,6 +14,8 @@
* option) any later version.
*/
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -26,8 +28,7 @@
#include <linux/spinlock.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe_ic.h>
#include "qe_ic.h"
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/drivers/soc/fsl/qe/qe_ic.h
index efef7ab9b753..926a2ed42319 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.h
+++ b/drivers/soc/fsl/qe/qe_ic.h
@@ -1,5 +1,5 @@
/*
- * arch/powerpc/sysdev/qe_lib/qe_ic.h
+ * drivers/soc/fsl/qe/qe_ic.h
*
* QUICC ENGINE Interrupt Controller Header
*
@@ -16,7 +16,7 @@
#ifndef _POWERPC_SYSDEV_QE_IC_H
#define _POWERPC_SYSDEV_QE_IC_H
-#include <asm/qe_ic.h>
+#include <soc/fsl/qe/qe_ic.h>
#define NR_QE_IC_INTS 64
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/drivers/soc/fsl/qe/qe_io.c
index 7ea0174f6d3d..7ae59abc7863 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/drivers/soc/fsl/qe/qe_io.c
@@ -21,7 +21,7 @@
#include <linux/ioport.h>
#include <asm/io.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include <asm/prom.h>
#include <sysdev/fsl_soc.h>
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/drivers/soc/fsl/qe/ucc.c
index 621575b7e84a..b59d3358f9bd 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc.c
+++ b/drivers/soc/fsl/qe/ucc.c
@@ -21,9 +21,9 @@
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
-#include <asm/ucc.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/ucc.h>
int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
{
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 65aaf15032ae..a7689310fe40 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -21,11 +21,11 @@
#include <linux/export.h>
#include <asm/io.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
-#include <asm/ucc.h>
-#include <asm/ucc_fast.h>
+#include <soc/fsl/qe/ucc.h>
+#include <soc/fsl/qe/ucc_fast.h>
void ucc_fast_dump_regs(struct ucc_fast_private * uccf)
{
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/drivers/soc/fsl/qe/ucc_slow.c
index 5f91628209eb..9334bdbd9b30 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+++ b/drivers/soc/fsl/qe/ucc_slow.c
@@ -21,11 +21,11 @@
#include <linux/export.h>
#include <asm/io.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
-#include <asm/ucc.h>
-#include <asm/ucc_slow.h>
+#include <soc/fsl/qe/ucc.h>
+#include <soc/fsl/qe/ucc_slow.h>
u32 ucc_slow_get_qe_cr_subblock(int uccs_num)
{
diff --git a/arch/powerpc/sysdev/qe_lib/usb.c b/drivers/soc/fsl/qe/usb.c
index 27f23bd15eb6..111f7ab80f04 100644
--- a/arch/powerpc/sysdev/qe_lib/usb.c
+++ b/drivers/soc/fsl/qe/usb.c
@@ -17,8 +17,8 @@
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/io.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
int qe_usb_clock_set(enum qe_clock clk, int rate)
{
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 4d4203c896c4..0221387e5e27 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -15,12 +15,13 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/regmap.h>
#include <linux/soc/mediatek/infracfg.h>
+#include <linux/regulator/consumer.h>
#include <dt-bindings/power/mt8173-power.h>
#define SPM_VDE_PWR_CON 0x0210
@@ -179,6 +180,7 @@ struct scp_domain {
u32 sram_pdn_ack_bits;
u32 bus_prot_mask;
bool active_wakeup;
+ struct regulator *supply;
};
struct scp {
@@ -221,6 +223,12 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
int ret;
int i;
+ if (scpd->supply) {
+ ret = regulator_enable(scpd->supply);
+ if (ret)
+ return ret;
+ }
+
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
ret = clk_prepare_enable(scpd->clk[i]);
if (ret) {
@@ -299,6 +307,9 @@ err_pwr_ack:
clk_disable_unprepare(scpd->clk[i]);
}
err_clk:
+ if (scpd->supply)
+ regulator_disable(scpd->supply);
+
dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
return ret;
@@ -379,6 +390,9 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
clk_disable_unprepare(scpd->clk[i]);
+ if (scpd->supply)
+ regulator_disable(scpd->supply);
+
return 0;
out:
@@ -448,6 +462,19 @@ static int __init scpsys_probe(struct platform_device *pdev)
return PTR_ERR(scp->infracfg);
}
+ for (i = 0; i < NUM_DOMAINS; i++) {
+ struct scp_domain *scpd = &scp->domains[i];
+ const struct scp_domain_data *data = &scp_domain_data[i];
+
+ scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
+ if (IS_ERR(scpd->supply)) {
+ if (PTR_ERR(scpd->supply) == -ENODEV)
+ scpd->supply = NULL;
+ else
+ return PTR_ERR(scpd->supply);
+ }
+ }
+
pd_data->num_domains = NUM_DOMAINS;
for (i = 0; i < NUM_DOMAINS; i++) {
@@ -521,5 +548,4 @@ static struct platform_driver scpsys_drv = {
.of_match_table = of_match_ptr(of_scpsys_match_tbl),
},
};
-
-module_platform_driver_probe(scpsys_drv, scpsys_probe);
+builtin_platform_driver_probe(scpsys_drv, scpsys_probe);
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index eec76141d9b9..461b387d03cc 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -13,6 +13,7 @@ config QCOM_GSBI
config QCOM_PM
bool "Qualcomm Power Management"
depends on ARCH_QCOM && !ARM64
+ select ARM_CPU_SUSPEND
select QCOM_SCM
help
QCOM Platform specific power driver to manage cores and L2 low power
@@ -49,3 +50,29 @@ config QCOM_SMD_RPM
Say M here if you want to include support for the Qualcomm RPM as a
module. This will build a module called "qcom-smd-rpm".
+
+config QCOM_SMEM_STATE
+ bool
+
+config QCOM_SMP2P
+ tristate "Qualcomm Shared Memory Point to Point support"
+ depends on QCOM_SMEM
+ select QCOM_SMEM_STATE
+ help
+ Say yes here to support the Qualcomm Shared Memory Point to Point
+ protocol.
+
+config QCOM_SMSM
+ tristate "Qualcomm Shared Memory State Machine"
+ depends on QCOM_SMEM
+ select QCOM_SMEM_STATE
+ help
+ Say yes here to support the Qualcomm Shared Memory State Machine.
+ The state machine is represented by bits in shared memory.
+
+config QCOM_WCNSS_CTRL
+ tristate "Qualcomm WCNSS control driver"
+ depends on QCOM_SMD
+ help
+ Client driver for the WCNSS_CTRL SMD channel, used to download nv
+ firmware to a newly booted WCNSS chip.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 10a93d168e0e..fdd664edf0bd 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -3,3 +3,7 @@ obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_SMD) += smd.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) += smem.o
+obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
+obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
+obj-$(CONFIG_QCOM_SMSM) += smsm.o
+obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index 2969321e1b09..731fa066f712 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -219,6 +219,8 @@ static void qcom_smd_rpm_remove(struct qcom_smd_device *sdev)
}
static const struct of_device_id qcom_smd_rpm_of_match[] = {
+ { .compatible = "qcom,rpm-apq8084" },
+ { .compatible = "qcom,rpm-msm8916" },
{ .compatible = "qcom,rpm-msm8974" },
{}
};
diff --git a/drivers/soc/qcom/smem_state.c b/drivers/soc/qcom/smem_state.c
new file mode 100644
index 000000000000..54261decb369
--- /dev/null
+++ b/drivers/soc/qcom/smem_state.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem_state.h>
+
+static LIST_HEAD(smem_states);
+static DEFINE_MUTEX(list_lock);
+
+/**
+ * struct qcom_smem_state - state context
+ * @refcount: refcount for the state
+ * @orphan: boolean indicator that this state has been unregistered
+ * @list: entry in smem_states list
+ * @of_node: of_node to use for matching the state in DT
+ * @priv: implementation private data
+ * @ops: ops for the state
+ */
+struct qcom_smem_state {
+ struct kref refcount;
+ bool orphan;
+
+ struct list_head list;
+ struct device_node *of_node;
+
+ void *priv;
+
+ struct qcom_smem_state_ops ops;
+};
+
+/**
+ * qcom_smem_state_update_bits() - update the masked bits in state with value
+ * @state: state handle acquired by calling qcom_smem_state_get()
+ * @mask: bit mask for the change
+ * @value: new value for the masked bits
+ *
+ * Returns 0 on success, otherwise negative errno.
+ */
+int qcom_smem_state_update_bits(struct qcom_smem_state *state,
+ u32 mask,
+ u32 value)
+{
+ if (state->orphan)
+ return -ENXIO;
+
+ if (!state->ops.update_bits)
+ return -ENOTSUPP;
+
+ return state->ops.update_bits(state->priv, mask, value);
+}
+EXPORT_SYMBOL_GPL(qcom_smem_state_update_bits);
+
+static struct qcom_smem_state *of_node_to_state(struct device_node *np)
+{
+ struct qcom_smem_state *state;
+
+ mutex_lock(&list_lock);
+
+ list_for_each_entry(state, &smem_states, list) {
+ if (state->of_node == np) {
+ kref_get(&state->refcount);
+ goto unlock;
+ }
+ }
+ state = ERR_PTR(-EPROBE_DEFER);
+
+unlock:
+ mutex_unlock(&list_lock);
+
+ return state;
+}
+
+/**
+ * qcom_smem_state_get() - acquire handle to a state
+ * @dev: client device pointer
+ * @con_id: name of the state to lookup
+ * @bit: flags from the state reference, indicating which bit's affected
+ *
+ * Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() must be
+ * called to release the returned state handle.
+ */
+struct qcom_smem_state *qcom_smem_state_get(struct device *dev,
+ const char *con_id,
+ unsigned *bit)
+{
+ struct qcom_smem_state *state;
+ struct of_phandle_args args;
+ int index = 0;
+ int ret;
+
+ if (con_id) {
+ index = of_property_match_string(dev->of_node,
+ "qcom,state-names",
+ con_id);
+ if (index < 0) {
+ dev_err(dev, "missing qcom,state-names\n");
+ return ERR_PTR(index);
+ }
+ }
+
+ ret = of_parse_phandle_with_args(dev->of_node,
+ "qcom,state",
+ "#qcom,state-cells",
+ index,
+ &args);
+ if (ret) {
+ dev_err(dev, "failed to parse qcom,state property\n");
+ return ERR_PTR(ret);
+ }
+
+ if (args.args_count != 1) {
+ dev_err(dev, "invalid #qcom,state-cells\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ state = of_node_to_state(args.np);
+ if (IS_ERR(state))
+ goto put;
+
+ *bit = args.args[0];
+
+put:
+ of_node_put(args.np);
+ return state;
+}
+EXPORT_SYMBOL_GPL(qcom_smem_state_get);
+
+static void qcom_smem_state_release(struct kref *ref)
+{
+ struct qcom_smem_state *state = container_of(ref, struct qcom_smem_state, refcount);
+
+ list_del(&state->list);
+ kfree(state);
+}
+
+/**
+ * qcom_smem_state_put() - release state handle
+ * @state: state handle to be released
+ */
+void qcom_smem_state_put(struct qcom_smem_state *state)
+{
+ mutex_lock(&list_lock);
+ kref_put(&state->refcount, qcom_smem_state_release);
+ mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL_GPL(qcom_smem_state_put);
+
+/**
+ * qcom_smem_state_register() - register a new state
+ * @of_node: of_node used for matching client lookups
+ * @ops: implementation ops
+ * @priv: implementation specific private data
+ */
+struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node,
+ const struct qcom_smem_state_ops *ops,
+ void *priv)
+{
+ struct qcom_smem_state *state;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&state->refcount);
+
+ state->of_node = of_node;
+ state->ops = *ops;
+ state->priv = priv;
+
+ mutex_lock(&list_lock);
+ list_add(&state->list, &smem_states);
+ mutex_unlock(&list_lock);
+
+ return state;
+}
+EXPORT_SYMBOL_GPL(qcom_smem_state_register);
+
+/**
+ * qcom_smem_state_unregister() - unregister a registered state
+ * @state: state handle to be unregistered
+ */
+void qcom_smem_state_unregister(struct qcom_smem_state *state)
+{
+ state->orphan = true;
+ qcom_smem_state_put(state);
+}
+EXPORT_SYMBOL_GPL(qcom_smem_state_unregister);
diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
new file mode 100644
index 000000000000..f1eed7f9dd67
--- /dev/null
+++ b/drivers/soc/qcom/smp2p.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications AB.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+#include <linux/spinlock.h>
+
+/*
+ * The Shared Memory Point to Point (SMP2P) protocol facilitates communication
+ * of a single 32-bit value between two processors. Each value has a single
+ * writer (the local side) and a single reader (the remote side). Values are
+ * uniquely identified in the system by the directed edge (local processor ID
+ * to remote processor ID) and a string identifier.
+ *
+ * Each processor is responsible for creating the outgoing SMEM items and each
+ * item is writable by the local processor and readable by the remote
+ * processor. By using two separate SMEM items that are single-reader and
+ * single-writer, SMP2P does not require any remote locking mechanisms.
+ *
+ * The driver uses the Linux GPIO and interrupt framework to expose a virtual
+ * GPIO for each outbound entry and a virtual interrupt controller for each
+ * inbound entry.
+ */
+
+#define SMP2P_MAX_ENTRY 16
+#define SMP2P_MAX_ENTRY_NAME 16
+
+#define SMP2P_FEATURE_SSR_ACK 0x1
+
+#define SMP2P_MAGIC 0x504d5324
+
+/**
+ * struct smp2p_smem_item - in memory communication structure
+ * @magic: magic number
+ * @version: version - must be 1
+ * @features: features flag - currently unused
+ * @local_pid: processor id of sending end
+ * @remote_pid: processor id of receiving end
+ * @total_entries: number of entries - always SMP2P_MAX_ENTRY
+ * @valid_entries: number of allocated entries
+ * @flags:
+ * @entries: individual communication entries
+ * @name: name of the entry
+ * @value: content of the entry
+ */
+struct smp2p_smem_item {
+ u32 magic;
+ u8 version;
+ unsigned features:24;
+ u16 local_pid;
+ u16 remote_pid;
+ u16 total_entries;
+ u16 valid_entries;
+ u32 flags;
+
+ struct {
+ u8 name[SMP2P_MAX_ENTRY_NAME];
+ u32 value;
+ } entries[SMP2P_MAX_ENTRY];
+} __packed;
+
+/**
+ * struct smp2p_entry - driver context matching one entry
+ * @node: list entry to keep track of allocated entries
+ * @smp2p: reference to the device driver context
+ * @name: name of the entry, to match against smp2p_smem_item
+ * @value: pointer to smp2p_smem_item entry value
+ * @last_value: last handled value
+ * @domain: irq_domain for inbound entries
+ * @irq_enabled:bitmap to track enabled irq bits
+ * @irq_rising: bitmap to mark irq bits for rising detection
+ * @irq_falling:bitmap to mark irq bits for falling detection
+ * @state: smem state handle
+ * @lock: spinlock to protect read-modify-write of the value
+ */
+struct smp2p_entry {
+ struct list_head node;
+ struct qcom_smp2p *smp2p;
+
+ const char *name;
+ u32 *value;
+ u32 last_value;
+
+ struct irq_domain *domain;
+ DECLARE_BITMAP(irq_enabled, 32);
+ DECLARE_BITMAP(irq_rising, 32);
+ DECLARE_BITMAP(irq_falling, 32);
+
+ struct qcom_smem_state *state;
+
+ spinlock_t lock;
+};
+
+#define SMP2P_INBOUND 0
+#define SMP2P_OUTBOUND 1
+
+/**
+ * struct qcom_smp2p - device driver context
+ * @dev: device driver handle
+ * @in: pointer to the inbound smem item
+ * @smem_items: ids of the two smem items
+ * @valid_entries: already scanned inbound entries
+ * @local_pid: processor id of the inbound edge
+ * @remote_pid: processor id of the outbound edge
+ * @ipc_regmap: regmap for the outbound ipc
+ * @ipc_offset: offset within the regmap
+ * @ipc_bit: bit in regmap@offset to kick to signal remote processor
+ * @inbound: list of inbound entries
+ * @outbound: list of outbound entries
+ */
+struct qcom_smp2p {
+ struct device *dev;
+
+ struct smp2p_smem_item *in;
+ struct smp2p_smem_item *out;
+
+ unsigned smem_items[SMP2P_OUTBOUND + 1];
+
+ unsigned valid_entries;
+
+ unsigned local_pid;
+ unsigned remote_pid;
+
+ struct regmap *ipc_regmap;
+ int ipc_offset;
+ int ipc_bit;
+
+ struct list_head inbound;
+ struct list_head outbound;
+};
+
+static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
+{
+ /* Make sure any updated data is written before the kick */
+ wmb();
+ regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit));
+}
+
+/**
+ * qcom_smp2p_intr() - interrupt handler for incoming notifications
+ * @irq: unused
+ * @data: smp2p driver context
+ *
+ * Handle notifications from the remote side to handle newly allocated entries
+ * or any changes to the state bits of existing entries.
+ */
+static irqreturn_t qcom_smp2p_intr(int irq, void *data)
+{
+ struct smp2p_smem_item *in;
+ struct smp2p_entry *entry;
+ struct qcom_smp2p *smp2p = data;
+ unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND];
+ unsigned pid = smp2p->remote_pid;
+ size_t size;
+ int irq_pin;
+ u32 status;
+ char buf[SMP2P_MAX_ENTRY_NAME];
+ u32 val;
+ int i;
+
+ in = smp2p->in;
+
+ /* Acquire smem item, if not already found */
+ if (!in) {
+ in = qcom_smem_get(pid, smem_id, &size);
+ if (IS_ERR(in)) {
+ dev_err(smp2p->dev,
+ "Unable to acquire remote smp2p item\n");
+ return IRQ_HANDLED;
+ }
+
+ smp2p->in = in;
+ }
+
+ /* Match newly created entries */
+ for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
+ list_for_each_entry(entry, &smp2p->inbound, node) {
+ memcpy_fromio(buf, in->entries[i].name, sizeof(buf));
+ if (!strcmp(buf, entry->name)) {
+ entry->value = &in->entries[i].value;
+ break;
+ }
+ }
+ }
+ smp2p->valid_entries = i;
+
+ /* Fire interrupts based on any value changes */
+ list_for_each_entry(entry, &smp2p->inbound, node) {
+ /* Ignore entries not yet allocated by the remote side */
+ if (!entry->value)
+ continue;
+
+ val = readl(entry->value);
+
+ status = val ^ entry->last_value;
+ entry->last_value = val;
+
+ /* No changes of this entry? */
+ if (!status)
+ continue;
+
+ for_each_set_bit(i, entry->irq_enabled, 32) {
+ if (!(status & BIT(i)))
+ continue;
+
+ if ((val & BIT(i) && test_bit(i, entry->irq_rising)) ||
+ (!(val & BIT(i)) && test_bit(i, entry->irq_falling))) {
+ irq_pin = irq_find_mapping(entry->domain, i);
+ handle_nested_irq(irq_pin);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void smp2p_mask_irq(struct irq_data *irqd)
+{
+ struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+
+ clear_bit(irq, entry->irq_enabled);
+}
+
+static void smp2p_unmask_irq(struct irq_data *irqd)
+{
+ struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+
+ set_bit(irq, entry->irq_enabled);
+}
+
+static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type)
+{
+ struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+
+ if (!(type & IRQ_TYPE_EDGE_BOTH))
+ return -EINVAL;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ set_bit(irq, entry->irq_rising);
+ else
+ clear_bit(irq, entry->irq_rising);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ set_bit(irq, entry->irq_falling);
+ else
+ clear_bit(irq, entry->irq_falling);
+
+ return 0;
+}
+
+static struct irq_chip smp2p_irq_chip = {
+ .name = "smp2p",
+ .irq_mask = smp2p_mask_irq,
+ .irq_unmask = smp2p_unmask_irq,
+ .irq_set_type = smp2p_set_irq_type,
+};
+
+static int smp2p_irq_map(struct irq_domain *d,
+ unsigned int irq,
+ irq_hw_number_t hw)
+{
+ struct smp2p_entry *entry = d->host_data;
+
+ irq_set_chip_and_handler(irq, &smp2p_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, entry);
+ irq_set_nested_thread(irq, 1);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops smp2p_irq_ops = {
+ .map = smp2p_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p,
+ struct smp2p_entry *entry,
+ struct device_node *node)
+{
+ entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry);
+ if (!entry->domain) {
+ dev_err(smp2p->dev, "failed to add irq_domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int smp2p_update_bits(void *data, u32 mask, u32 value)
+{
+ struct smp2p_entry *entry = data;
+ u32 orig;
+ u32 val;
+
+ spin_lock(&entry->lock);
+ val = orig = readl(entry->value);
+ val &= ~mask;
+ val |= value;
+ writel(val, entry->value);
+ spin_unlock(&entry->lock);
+
+ if (val != orig)
+ qcom_smp2p_kick(entry->smp2p);
+
+ return 0;
+}
+
+static const struct qcom_smem_state_ops smp2p_state_ops = {
+ .update_bits = smp2p_update_bits,
+};
+
+static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p,
+ struct smp2p_entry *entry,
+ struct device_node *node)
+{
+ struct smp2p_smem_item *out = smp2p->out;
+ char buf[SMP2P_MAX_ENTRY_NAME] = {};
+
+ /* Allocate an entry from the smem item */
+ strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
+ memcpy_toio(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME);
+ out->valid_entries++;
+
+ /* Make the logical entry reference the physical value */
+ entry->value = &out->entries[out->valid_entries].value;
+
+ entry->state = qcom_smem_state_register(node, &smp2p_state_ops, entry);
+ if (IS_ERR(entry->state)) {
+ dev_err(smp2p->dev, "failed to register qcom_smem_state\n");
+ return PTR_ERR(entry->state);
+ }
+
+ return 0;
+}
+
+static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
+{
+ struct smp2p_smem_item *out;
+ unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND];
+ unsigned pid = smp2p->remote_pid;
+ int ret;
+
+ ret = qcom_smem_alloc(pid, smem_id, sizeof(*out));
+ if (ret < 0 && ret != -EEXIST) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(smp2p->dev,
+ "unable to allocate local smp2p item\n");
+ return ret;
+ }
+
+ out = qcom_smem_get(pid, smem_id, NULL);
+ if (IS_ERR(out)) {
+ dev_err(smp2p->dev, "Unable to acquire local smp2p item\n");
+ return PTR_ERR(out);
+ }
+
+ memset(out, 0, sizeof(*out));
+ out->magic = SMP2P_MAGIC;
+ out->local_pid = smp2p->local_pid;
+ out->remote_pid = smp2p->remote_pid;
+ out->total_entries = SMP2P_MAX_ENTRY;
+ out->valid_entries = 0;
+
+ /*
+ * Make sure the rest of the header is written before we validate the
+ * item by writing a valid version number.
+ */
+ wmb();
+ out->version = 1;
+
+ qcom_smp2p_kick(smp2p);
+
+ smp2p->out = out;
+
+ return 0;
+}
+
+static int smp2p_parse_ipc(struct qcom_smp2p *smp2p)
+{
+ struct device_node *syscon;
+ struct device *dev = smp2p->dev;
+ const char *key;
+ int ret;
+
+ syscon = of_parse_phandle(dev->of_node, "qcom,ipc", 0);
+ if (!syscon) {
+ dev_err(dev, "no qcom,ipc node\n");
+ return -ENODEV;
+ }
+
+ smp2p->ipc_regmap = syscon_node_to_regmap(syscon);
+ if (IS_ERR(smp2p->ipc_regmap))
+ return PTR_ERR(smp2p->ipc_regmap);
+
+ key = "qcom,ipc";
+ ret = of_property_read_u32_index(dev->of_node, key, 1, &smp2p->ipc_offset);
+ if (ret < 0) {
+ dev_err(dev, "no offset in %s\n", key);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(dev->of_node, key, 2, &smp2p->ipc_bit);
+ if (ret < 0) {
+ dev_err(dev, "no bit in %s\n", key);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qcom_smp2p_probe(struct platform_device *pdev)
+{
+ struct smp2p_entry *entry;
+ struct device_node *node;
+ struct qcom_smp2p *smp2p;
+ const char *key;
+ int irq;
+ int ret;
+
+ smp2p = devm_kzalloc(&pdev->dev, sizeof(*smp2p), GFP_KERNEL);
+ if (!smp2p)
+ return -ENOMEM;
+
+ smp2p->dev = &pdev->dev;
+ INIT_LIST_HEAD(&smp2p->inbound);
+ INIT_LIST_HEAD(&smp2p->outbound);
+
+ platform_set_drvdata(pdev, smp2p);
+
+ ret = smp2p_parse_ipc(smp2p);
+ if (ret)
+ return ret;
+
+ key = "qcom,smem";
+ ret = of_property_read_u32_array(pdev->dev.of_node, key,
+ smp2p->smem_items, 2);
+ if (ret)
+ return ret;
+
+ key = "qcom,local-pid";
+ ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->local_pid);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to read %s\n", key);
+ return -EINVAL;
+ }
+
+ key = "qcom,remote-pid";
+ ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->remote_pid);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to read %s\n", key);
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "unable to acquire smp2p interrupt\n");
+ return irq;
+ }
+
+ ret = qcom_smp2p_alloc_outbound_item(smp2p);
+ if (ret < 0)
+ return ret;
+
+ for_each_available_child_of_node(pdev->dev.of_node, node) {
+ entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ ret = -ENOMEM;
+ goto unwind_interfaces;
+ }
+
+ entry->smp2p = smp2p;
+ spin_lock_init(&entry->lock);
+
+ ret = of_property_read_string(node, "qcom,entry-name", &entry->name);
+ if (ret < 0)
+ goto unwind_interfaces;
+
+ if (of_property_read_bool(node, "interrupt-controller")) {
+ ret = qcom_smp2p_inbound_entry(smp2p, entry, node);
+ if (ret < 0)
+ goto unwind_interfaces;
+
+ list_add(&entry->node, &smp2p->inbound);
+ } else {
+ ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
+ if (ret < 0)
+ goto unwind_interfaces;
+
+ list_add(&entry->node, &smp2p->outbound);
+ }
+ }
+
+ /* Kick the outgoing edge after allocating entries */
+ qcom_smp2p_kick(smp2p);
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, qcom_smp2p_intr,
+ IRQF_ONESHOT,
+ "smp2p", (void *)smp2p);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request interrupt\n");
+ goto unwind_interfaces;
+ }
+
+
+ return 0;
+
+unwind_interfaces:
+ list_for_each_entry(entry, &smp2p->inbound, node)
+ irq_domain_remove(entry->domain);
+
+ list_for_each_entry(entry, &smp2p->outbound, node)
+ qcom_smem_state_unregister(entry->state);
+
+ smp2p->out->valid_entries = 0;
+
+ return ret;
+}
+
+static int qcom_smp2p_remove(struct platform_device *pdev)
+{
+ struct qcom_smp2p *smp2p = platform_get_drvdata(pdev);
+ struct smp2p_entry *entry;
+
+ list_for_each_entry(entry, &smp2p->inbound, node)
+ irq_domain_remove(entry->domain);
+
+ list_for_each_entry(entry, &smp2p->outbound, node)
+ qcom_smem_state_unregister(entry->state);
+
+ smp2p->out->valid_entries = 0;
+
+ return 0;
+}
+
+static const struct of_device_id qcom_smp2p_of_match[] = {
+ { .compatible = "qcom,smp2p" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match);
+
+static struct platform_driver qcom_smp2p_driver = {
+ .probe = qcom_smp2p_probe,
+ .remove = qcom_smp2p_remove,
+ .driver = {
+ .name = "qcom_smp2p",
+ .of_match_table = qcom_smp2p_of_match,
+ },
+};
+module_platform_driver(qcom_smp2p_driver);
+
+MODULE_DESCRIPTION("Qualcomm Shared Memory Point to Point driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c
new file mode 100644
index 000000000000..6b777af1bc19
--- /dev/null
+++ b/drivers/soc/qcom/smsm.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/regmap.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+/*
+ * This driver implements the Qualcomm Shared Memory State Machine, a mechanism
+ * for communicating single bit state information to remote processors.
+ *
+ * The implementation is based on two sections of shared memory; the first
+ * holding the state bits and the second holding a matrix of subscription bits.
+ *
+ * The state bits are structured in entries of 32 bits, each belonging to one
+ * system in the SoC. The entry belonging to the local system is considered
+ * read-write, while the rest should be considered read-only.
+ *
+ * The subscription matrix consists of N bitmaps per entry, denoting interest
+ * in updates of the entry for each of the N hosts. Upon updating a state bit
+ * each host's subscription bitmap should be queried and the remote system
+ * should be interrupted if they request so.
+ *
+ * The subscription matrix is laid out in entry-major order:
+ * entry0: [host0 ... hostN]
+ * .
+ * .
+ * entryM: [host0 ... hostN]
+ *
+ * A third, optional, shared memory region might contain information regarding
+ * the number of entries in the state bitmap as well as number of columns in
+ * the subscription matrix.
+ */
+
+/*
+ * Shared memory identifiers, used to acquire handles to respective memory
+ * region.
+ */
+#define SMEM_SMSM_SHARED_STATE 85
+#define SMEM_SMSM_CPU_INTR_MASK 333
+#define SMEM_SMSM_SIZE_INFO 419
+
+/*
+ * Default sizes, in case SMEM_SMSM_SIZE_INFO is not found.
+ */
+#define SMSM_DEFAULT_NUM_ENTRIES 8
+#define SMSM_DEFAULT_NUM_HOSTS 3
+
+struct smsm_entry;
+struct smsm_host;
+
+/**
+ * struct qcom_smsm - smsm driver context
+ * @dev: smsm device pointer
+ * @local_host: column in the subscription matrix representing this system
+ * @num_hosts: number of columns in the subscription matrix
+ * @num_entries: number of entries in the state map and rows in the subscription
+ * matrix
+ * @local_state: pointer to the local processor's state bits
+ * @subscription: pointer to local processor's row in subscription matrix
+ * @state: smem state handle
+ * @lock: spinlock for read-modify-write of the outgoing state
+ * @entries: context for each of the entries
+ * @hosts: context for each of the hosts
+ */
+struct qcom_smsm {
+ struct device *dev;
+
+ u32 local_host;
+
+ u32 num_hosts;
+ u32 num_entries;
+
+ u32 *local_state;
+ u32 *subscription;
+ struct qcom_smem_state *state;
+
+ spinlock_t lock;
+
+ struct smsm_entry *entries;
+ struct smsm_host *hosts;
+};
+
+/**
+ * struct smsm_entry - per remote processor entry context
+ * @smsm: back-reference to driver context
+ * @domain: IRQ domain for this entry, if representing a remote system
+ * @irq_enabled: bitmap of which state bits IRQs are enabled
+ * @irq_rising: bitmap tracking if rising bits should be propagated
+ * @irq_falling: bitmap tracking if falling bits should be propagated
+ * @last_value: snapshot of state bits last time the interrupts where propagated
+ * @remote_state: pointer to this entry's state bits
+ * @subscription: pointer to a row in the subscription matrix representing this
+ * entry
+ */
+struct smsm_entry {
+ struct qcom_smsm *smsm;
+
+ struct irq_domain *domain;
+ DECLARE_BITMAP(irq_enabled, 32);
+ DECLARE_BITMAP(irq_rising, 32);
+ DECLARE_BITMAP(irq_falling, 32);
+ u32 last_value;
+
+ u32 *remote_state;
+ u32 *subscription;
+};
+
+/**
+ * struct smsm_host - representation of a remote host
+ * @ipc_regmap: regmap for outgoing interrupt
+ * @ipc_offset: offset in @ipc_regmap for outgoing interrupt
+ * @ipc_bit: bit in @ipc_regmap + @ipc_offset for outgoing interrupt
+ */
+struct smsm_host {
+ struct regmap *ipc_regmap;
+ int ipc_offset;
+ int ipc_bit;
+};
+
+/**
+ * smsm_update_bits() - change bit in outgoing entry and inform subscribers
+ * @data: smsm context pointer
+ * @offset: bit in the entry
+ * @value: new value
+ *
+ * Used to set and clear the bits in the outgoing/local entry and inform
+ * subscribers about the change.
+ */
+static int smsm_update_bits(void *data, u32 mask, u32 value)
+{
+ struct qcom_smsm *smsm = data;
+ struct smsm_host *hostp;
+ unsigned long flags;
+ u32 changes;
+ u32 host;
+ u32 orig;
+ u32 val;
+
+ spin_lock_irqsave(&smsm->lock, flags);
+
+ /* Update the entry */
+ val = orig = readl(smsm->local_state);
+ val &= ~mask;
+ val |= value;
+
+ /* Don't signal if we didn't change the value */
+ changes = val ^ orig;
+ if (!changes) {
+ spin_unlock_irqrestore(&smsm->lock, flags);
+ goto done;
+ }
+
+ /* Write out the new value */
+ writel(val, smsm->local_state);
+ spin_unlock_irqrestore(&smsm->lock, flags);
+
+ /* Make sure the value update is ordered before any kicks */
+ wmb();
+
+ /* Iterate over all hosts to check whom wants a kick */
+ for (host = 0; host < smsm->num_hosts; host++) {
+ hostp = &smsm->hosts[host];
+
+ val = readl(smsm->subscription + host);
+ if (val & changes && hostp->ipc_regmap) {
+ regmap_write(hostp->ipc_regmap,
+ hostp->ipc_offset,
+ BIT(hostp->ipc_bit));
+ }
+ }
+
+done:
+ return 0;
+}
+
+static const struct qcom_smem_state_ops smsm_state_ops = {
+ .update_bits = smsm_update_bits,
+};
+
+/**
+ * smsm_intr() - cascading IRQ handler for SMSM
+ * @irq: unused
+ * @data: entry related to this IRQ
+ *
+ * This function cascades an incoming interrupt from a remote system, based on
+ * the state bits and configuration.
+ */
+static irqreturn_t smsm_intr(int irq, void *data)
+{
+ struct smsm_entry *entry = data;
+ unsigned i;
+ int irq_pin;
+ u32 changed;
+ u32 val;
+
+ val = readl(entry->remote_state);
+ changed = val ^ entry->last_value;
+ entry->last_value = val;
+
+ for_each_set_bit(i, entry->irq_enabled, 32) {
+ if (!(changed & BIT(i)))
+ continue;
+
+ if (val & BIT(i)) {
+ if (test_bit(i, entry->irq_rising)) {
+ irq_pin = irq_find_mapping(entry->domain, i);
+ handle_nested_irq(irq_pin);
+ }
+ } else {
+ if (test_bit(i, entry->irq_falling)) {
+ irq_pin = irq_find_mapping(entry->domain, i);
+ handle_nested_irq(irq_pin);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * smsm_mask_irq() - un-subscribe from cascades of IRQs of a certain staus bit
+ * @irqd: IRQ handle to be masked
+ *
+ * This un-subscribes the local CPU from interrupts upon changes to the defines
+ * status bit. The bit is also cleared from cascading.
+ */
+static void smsm_mask_irq(struct irq_data *irqd)
+{
+ struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+ struct qcom_smsm *smsm = entry->smsm;
+ u32 val;
+
+ if (entry->subscription) {
+ val = readl(entry->subscription + smsm->local_host);
+ val &= ~BIT(irq);
+ writel(val, entry->subscription + smsm->local_host);
+ }
+
+ clear_bit(irq, entry->irq_enabled);
+}
+
+/**
+ * smsm_unmask_irq() - subscribe to cascades of IRQs of a certain status bit
+ * @irqd: IRQ handle to be unmasked
+ *
+
+ * This subscribes the local CPU to interrupts upon changes to the defined
+ * status bit. The bit is also marked for cascading.
+
+ */
+static void smsm_unmask_irq(struct irq_data *irqd)
+{
+ struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+ struct qcom_smsm *smsm = entry->smsm;
+ u32 val;
+
+ set_bit(irq, entry->irq_enabled);
+
+ if (entry->subscription) {
+ val = readl(entry->subscription + smsm->local_host);
+ val |= BIT(irq);
+ writel(val, entry->subscription + smsm->local_host);
+ }
+}
+
+/**
+ * smsm_set_irq_type() - updates the requested IRQ type for the cascading
+ * @irqd: consumer interrupt handle
+ * @type: requested flags
+ */
+static int smsm_set_irq_type(struct irq_data *irqd, unsigned int type)
+{
+ struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+
+ if (!(type & IRQ_TYPE_EDGE_BOTH))
+ return -EINVAL;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ set_bit(irq, entry->irq_rising);
+ else
+ clear_bit(irq, entry->irq_rising);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ set_bit(irq, entry->irq_falling);
+ else
+ clear_bit(irq, entry->irq_falling);
+
+ return 0;
+}
+
+static struct irq_chip smsm_irq_chip = {
+ .name = "smsm",
+ .irq_mask = smsm_mask_irq,
+ .irq_unmask = smsm_unmask_irq,
+ .irq_set_type = smsm_set_irq_type,
+};
+
+/**
+ * smsm_irq_map() - sets up a mapping for a cascaded IRQ
+ * @d: IRQ domain representing an entry
+ * @irq: IRQ to set up
+ * @hw: unused
+ */
+static int smsm_irq_map(struct irq_domain *d,
+ unsigned int irq,
+ irq_hw_number_t hw)
+{
+ struct smsm_entry *entry = d->host_data;
+
+ irq_set_chip_and_handler(irq, &smsm_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, entry);
+ irq_set_nested_thread(irq, 1);
+
+ return 0;
+}
+
+static const struct irq_domain_ops smsm_irq_ops = {
+ .map = smsm_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+/**
+ * smsm_parse_ipc() - parses a qcom,ipc-%d device tree property
+ * @smsm: smsm driver context
+ * @host_id: index of the remote host to be resolved
+ *
+ * Parses device tree to acquire the information needed for sending the
+ * outgoing interrupts to a remote host - identified by @host_id.
+ */
+static int smsm_parse_ipc(struct qcom_smsm *smsm, unsigned host_id)
+{
+ struct device_node *syscon;
+ struct device_node *node = smsm->dev->of_node;
+ struct smsm_host *host = &smsm->hosts[host_id];
+ char key[16];
+ int ret;
+
+ snprintf(key, sizeof(key), "qcom,ipc-%d", host_id);
+ syscon = of_parse_phandle(node, key, 0);
+ if (!syscon)
+ return 0;
+
+ host->ipc_regmap = syscon_node_to_regmap(syscon);
+ if (IS_ERR(host->ipc_regmap))
+ return PTR_ERR(host->ipc_regmap);
+
+ ret = of_property_read_u32_index(node, key, 1, &host->ipc_offset);
+ if (ret < 0) {
+ dev_err(smsm->dev, "no offset in %s\n", key);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(node, key, 2, &host->ipc_bit);
+ if (ret < 0) {
+ dev_err(smsm->dev, "no bit in %s\n", key);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * smsm_inbound_entry() - parse DT and set up an entry representing a remote system
+ * @smsm: smsm driver context
+ * @entry: entry context to be set up
+ * @node: dt node containing the entry's properties
+ */
+static int smsm_inbound_entry(struct qcom_smsm *smsm,
+ struct smsm_entry *entry,
+ struct device_node *node)
+{
+ int ret;
+ int irq;
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ dev_err(smsm->dev, "failed to parse smsm interrupt\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_threaded_irq(smsm->dev, irq,
+ NULL, smsm_intr,
+ IRQF_ONESHOT,
+ "smsm", (void *)entry);
+ if (ret) {
+ dev_err(smsm->dev, "failed to request interrupt\n");
+ return ret;
+ }
+
+ entry->domain = irq_domain_add_linear(node, 32, &smsm_irq_ops, entry);
+ if (!entry->domain) {
+ dev_err(smsm->dev, "failed to add irq_domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * smsm_get_size_info() - parse the optional memory segment for sizes
+ * @smsm: smsm driver context
+ *
+ * Attempt to acquire the number of hosts and entries from the optional shared
+ * memory location. Not being able to find this segment should indicate that
+ * we're on a older system where these values was hard coded to
+ * SMSM_DEFAULT_NUM_ENTRIES and SMSM_DEFAULT_NUM_HOSTS.
+ *
+ * Returns 0 on success, negative errno on failure.
+ */
+static int smsm_get_size_info(struct qcom_smsm *smsm)
+{
+ size_t size;
+ struct {
+ u32 num_hosts;
+ u32 num_entries;
+ u32 reserved0;
+ u32 reserved1;
+ } *info;
+
+ info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size);
+ if (PTR_ERR(info) == -ENOENT || size != sizeof(*info)) {
+ dev_warn(smsm->dev, "no smsm size info, using defaults\n");
+ smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES;
+ smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS;
+ return 0;
+ } else if (IS_ERR(info)) {
+ dev_err(smsm->dev, "unable to retrieve smsm size info\n");
+ return PTR_ERR(info);
+ }
+
+ smsm->num_entries = info->num_entries;
+ smsm->num_hosts = info->num_hosts;
+
+ dev_dbg(smsm->dev,
+ "found custom size of smsm: %d entries %d hosts\n",
+ smsm->num_entries, smsm->num_hosts);
+
+ return 0;
+}
+
+static int qcom_smsm_probe(struct platform_device *pdev)
+{
+ struct device_node *local_node;
+ struct device_node *node;
+ struct smsm_entry *entry;
+ struct qcom_smsm *smsm;
+ u32 *intr_mask;
+ size_t size;
+ u32 *states;
+ u32 id;
+ int ret;
+
+ smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL);
+ if (!smsm)
+ return -ENOMEM;
+ smsm->dev = &pdev->dev;
+ spin_lock_init(&smsm->lock);
+
+ ret = smsm_get_size_info(smsm);
+ if (ret)
+ return ret;
+
+ smsm->entries = devm_kcalloc(&pdev->dev,
+ smsm->num_entries,
+ sizeof(struct smsm_entry),
+ GFP_KERNEL);
+ if (!smsm->entries)
+ return -ENOMEM;
+
+ smsm->hosts = devm_kcalloc(&pdev->dev,
+ smsm->num_hosts,
+ sizeof(struct smsm_host),
+ GFP_KERNEL);
+ if (!smsm->hosts)
+ return -ENOMEM;
+
+ local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,state-cells");
+ if (!local_node) {
+ dev_err(&pdev->dev, "no state entry\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32(pdev->dev.of_node,
+ "qcom,local-host",
+ &smsm->local_host);
+
+ /* Parse the host properties */
+ for (id = 0; id < smsm->num_hosts; id++) {
+ ret = smsm_parse_ipc(smsm, id);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Acquire the main SMSM state vector */
+ ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SHARED_STATE,
+ smsm->num_entries * sizeof(u32));
+ if (ret < 0 && ret != -EEXIST) {
+ dev_err(&pdev->dev, "unable to allocate shared state entry\n");
+ return ret;
+ }
+
+ states = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SHARED_STATE, NULL);
+ if (IS_ERR(states)) {
+ dev_err(&pdev->dev, "Unable to acquire shared state entry\n");
+ return PTR_ERR(states);
+ }
+
+ /* Acquire the list of interrupt mask vectors */
+ size = smsm->num_entries * smsm->num_hosts * sizeof(u32);
+ ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY, SMEM_SMSM_CPU_INTR_MASK, size);
+ if (ret < 0 && ret != -EEXIST) {
+ dev_err(&pdev->dev, "unable to allocate smsm interrupt mask\n");
+ return ret;
+ }
+
+ intr_mask = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_CPU_INTR_MASK, NULL);
+ if (IS_ERR(intr_mask)) {
+ dev_err(&pdev->dev, "unable to acquire shared memory interrupt mask\n");
+ return PTR_ERR(intr_mask);
+ }
+
+ /* Setup the reference to the local state bits */
+ smsm->local_state = states + smsm->local_host;
+ smsm->subscription = intr_mask + smsm->local_host * smsm->num_hosts;
+
+ /* Register the outgoing state */
+ smsm->state = qcom_smem_state_register(local_node, &smsm_state_ops, smsm);
+ if (IS_ERR(smsm->state)) {
+ dev_err(smsm->dev, "failed to register qcom_smem_state\n");
+ return PTR_ERR(smsm->state);
+ }
+
+ /* Register handlers for remote processor entries of interest. */
+ for_each_available_child_of_node(pdev->dev.of_node, node) {
+ if (!of_property_read_bool(node, "interrupt-controller"))
+ continue;
+
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id >= smsm->num_entries) {
+ dev_err(&pdev->dev, "invalid reg of entry\n");
+ if (!ret)
+ ret = -EINVAL;
+ goto unwind_interfaces;
+ }
+ entry = &smsm->entries[id];
+
+ entry->smsm = smsm;
+ entry->remote_state = states + id;
+
+ /* Setup subscription pointers and unsubscribe to any kicks */
+ entry->subscription = intr_mask + id * smsm->num_hosts;
+ writel(0, entry->subscription + smsm->local_host);
+
+ ret = smsm_inbound_entry(smsm, entry, node);
+ if (ret < 0)
+ goto unwind_interfaces;
+ }
+
+ platform_set_drvdata(pdev, smsm);
+
+ return 0;
+
+unwind_interfaces:
+ for (id = 0; id < smsm->num_entries; id++)
+ if (smsm->entries[id].domain)
+ irq_domain_remove(smsm->entries[id].domain);
+
+ qcom_smem_state_unregister(smsm->state);
+
+ return ret;
+}
+
+static int qcom_smsm_remove(struct platform_device *pdev)
+{
+ struct qcom_smsm *smsm = platform_get_drvdata(pdev);
+ unsigned id;
+
+ for (id = 0; id < smsm->num_entries; id++)
+ if (smsm->entries[id].domain)
+ irq_domain_remove(smsm->entries[id].domain);
+
+ qcom_smem_state_unregister(smsm->state);
+
+ return 0;
+}
+
+static const struct of_device_id qcom_smsm_of_match[] = {
+ { .compatible = "qcom,smsm" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
+
+static struct platform_driver qcom_smsm_driver = {
+ .probe = qcom_smsm_probe,
+ .remove = qcom_smsm_remove,
+ .driver = {
+ .name = "qcom-smsm",
+ .of_match_table = qcom_smsm_of_match,
+ },
+};
+module_platform_driver(qcom_smsm_driver);
+
+MODULE_DESCRIPTION("Qualcomm Shared Memory State Machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
new file mode 100644
index 000000000000..7a986f881d5c
--- /dev/null
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smd.h>
+
+#define WCNSS_REQUEST_TIMEOUT (5 * HZ)
+
+#define NV_FRAGMENT_SIZE 3072
+#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
+
+/**
+ * struct wcnss_ctrl - driver context
+ * @dev: device handle
+ * @channel: SMD channel handle
+ * @ack: completion for outstanding requests
+ * @ack_status: status of the outstanding request
+ * @download_nv_work: worker for uploading nv binary
+ */
+struct wcnss_ctrl {
+ struct device *dev;
+ struct qcom_smd_channel *channel;
+
+ struct completion ack;
+ int ack_status;
+
+ struct work_struct download_nv_work;
+};
+
+/* message types */
+enum {
+ WCNSS_VERSION_REQ = 0x01000000,
+ WCNSS_VERSION_RESP,
+ WCNSS_DOWNLOAD_NV_REQ,
+ WCNSS_DOWNLOAD_NV_RESP,
+ WCNSS_UPLOAD_CAL_REQ,
+ WCNSS_UPLOAD_CAL_RESP,
+ WCNSS_DOWNLOAD_CAL_REQ,
+ WCNSS_DOWNLOAD_CAL_RESP,
+};
+
+/**
+ * struct wcnss_msg_hdr - common packet header for requests and responses
+ * @type: packet message type
+ * @len: total length of the packet, including this header
+ */
+struct wcnss_msg_hdr {
+ u32 type;
+ u32 len;
+} __packed;
+
+/**
+ * struct wcnss_version_resp - version request response
+ * @hdr: common packet wcnss_msg_hdr header
+ */
+struct wcnss_version_resp {
+ struct wcnss_msg_hdr hdr;
+ u8 major;
+ u8 minor;
+ u8 version;
+ u8 revision;
+} __packed;
+
+/**
+ * struct wcnss_download_nv_req - firmware fragment request
+ * @hdr: common packet wcnss_msg_hdr header
+ * @seq: sequence number of this fragment
+ * @last: boolean indicator of this being the last fragment of the binary
+ * @frag_size: length of this fragment
+ * @fragment: fragment data
+ */
+struct wcnss_download_nv_req {
+ struct wcnss_msg_hdr hdr;
+ u16 seq;
+ u16 last;
+ u32 frag_size;
+ u8 fragment[];
+} __packed;
+
+/**
+ * struct wcnss_download_nv_resp - firmware download response
+ * @hdr: common packet wcnss_msg_hdr header
+ * @status: boolean to indicate success of the download
+ */
+struct wcnss_download_nv_resp {
+ struct wcnss_msg_hdr hdr;
+ u8 status;
+} __packed;
+
+/**
+ * wcnss_ctrl_smd_callback() - handler from SMD responses
+ * @qsdev: smd device handle
+ * @data: pointer to the incoming data packet
+ * @count: size of the incoming data packet
+ *
+ * Handles any incoming packets from the remote WCNSS_CTRL service.
+ */
+static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
+ const void *data,
+ size_t count)
+{
+ struct wcnss_ctrl *wcnss = dev_get_drvdata(&qsdev->dev);
+ const struct wcnss_download_nv_resp *nvresp;
+ const struct wcnss_version_resp *version;
+ const struct wcnss_msg_hdr *hdr = data;
+
+ switch (hdr->type) {
+ case WCNSS_VERSION_RESP:
+ if (count != sizeof(*version)) {
+ dev_err(wcnss->dev,
+ "invalid size of version response\n");
+ break;
+ }
+
+ version = data;
+ dev_info(wcnss->dev, "WCNSS Version %d.%d %d.%d\n",
+ version->major, version->minor,
+ version->version, version->revision);
+
+ schedule_work(&wcnss->download_nv_work);
+ break;
+ case WCNSS_DOWNLOAD_NV_RESP:
+ if (count != sizeof(*nvresp)) {
+ dev_err(wcnss->dev,
+ "invalid size of download response\n");
+ break;
+ }
+
+ nvresp = data;
+ wcnss->ack_status = nvresp->status;
+ complete(&wcnss->ack);
+ break;
+ default:
+ dev_info(wcnss->dev, "unknown message type %d\n", hdr->type);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * wcnss_request_version() - send a version request to WCNSS
+ * @wcnss: wcnss ctrl driver context
+ */
+static int wcnss_request_version(struct wcnss_ctrl *wcnss)
+{
+ struct wcnss_msg_hdr msg;
+
+ msg.type = WCNSS_VERSION_REQ;
+ msg.len = sizeof(msg);
+
+ return qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+}
+
+/**
+ * wcnss_download_nv() - send nv binary to WCNSS
+ * @work: work struct to acquire wcnss context
+ */
+static void wcnss_download_nv(struct work_struct *work)
+{
+ struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work);
+ struct wcnss_download_nv_req *req;
+ const struct firmware *fw;
+ const void *data;
+ ssize_t left;
+ int ret;
+
+ req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL);
+ if (!req)
+ return;
+
+ ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev);
+ if (ret) {
+ dev_err(wcnss->dev, "Failed to load nv file %s: %d\n",
+ NVBIN_FILE, ret);
+ goto free_req;
+ }
+
+ data = fw->data;
+ left = fw->size;
+
+ req->hdr.type = WCNSS_DOWNLOAD_NV_REQ;
+ req->hdr.len = sizeof(*req) + NV_FRAGMENT_SIZE;
+
+ req->last = 0;
+ req->frag_size = NV_FRAGMENT_SIZE;
+
+ req->seq = 0;
+ do {
+ if (left <= NV_FRAGMENT_SIZE) {
+ req->last = 1;
+ req->frag_size = left;
+ req->hdr.len = sizeof(*req) + left;
+ }
+
+ memcpy(req->fragment, data, req->frag_size);
+
+ ret = qcom_smd_send(wcnss->channel, req, req->hdr.len);
+ if (ret) {
+ dev_err(wcnss->dev, "failed to send smd packet\n");
+ goto release_fw;
+ }
+
+ /* Increment for next fragment */
+ req->seq++;
+
+ data += req->hdr.len;
+ left -= NV_FRAGMENT_SIZE;
+ } while (left > 0);
+
+ ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT);
+ if (!ret)
+ dev_err(wcnss->dev, "timeout waiting for nv upload ack\n");
+ else if (wcnss->ack_status != 1)
+ dev_err(wcnss->dev, "nv upload response failed err: %d\n",
+ wcnss->ack_status);
+
+release_fw:
+ release_firmware(fw);
+free_req:
+ kfree(req);
+}
+
+static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
+{
+ struct wcnss_ctrl *wcnss;
+
+ wcnss = devm_kzalloc(&sdev->dev, sizeof(*wcnss), GFP_KERNEL);
+ if (!wcnss)
+ return -ENOMEM;
+
+ wcnss->dev = &sdev->dev;
+ wcnss->channel = sdev->channel;
+
+ init_completion(&wcnss->ack);
+ INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv);
+
+ dev_set_drvdata(&sdev->dev, wcnss);
+
+ return wcnss_request_version(wcnss);
+}
+
+static const struct qcom_smd_id wcnss_ctrl_smd_match[] = {
+ { .name = "WCNSS_CTRL" },
+ {}
+};
+
+static struct qcom_smd_driver wcnss_ctrl_driver = {
+ .probe = wcnss_ctrl_probe,
+ .callback = wcnss_ctrl_smd_callback,
+ .smd_match_table = wcnss_ctrl_smd_match,
+ .driver = {
+ .name = "qcom_wcnss_ctrl",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_qcom_smd_driver(wcnss_ctrl_driver);
+
+MODULE_DESCRIPTION("Qualcomm WCNSS control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 7266b2165183..3557c5e32a93 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -28,4 +28,14 @@ config KEYSTONE_NAVIGATOR_DMA
If unsure, say N.
+config WKUP_M3_IPC
+ tristate "TI AMx3 Wkup-M3 IPC Driver"
+ depends on WKUP_M3_RPROC
+ depends on OMAP2PLUS_MBOX
+ help
+ TI AM33XX and AM43XX have a Cortex M3, the Wakeup M3, to handle
+ low power transitions. This IPC driver provides the necessary API
+ to communicate and use the Wakeup M3 for PM features like suspend
+ resume and boots it using wkup_m3_rproc driver.
+
endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 135bdad7a6de..48ff3a79634f 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
+obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index bc1b80ec6afe..1a7b5caa127b 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -389,7 +389,7 @@ static int of_channel_match_helper(struct device_node *np, const char *name,
*dma_instance = dma_node->name;
index = of_property_match_string(np, "ti,navigator-dma-names", name);
if (index < 0) {
- dev_err(kdev->dev, "No 'ti,navigator-dma-names' propery\n");
+ dev_err(kdev->dev, "No 'ti,navigator-dma-names' property\n");
return -ENODEV;
}
diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c
new file mode 100644
index 000000000000..8823cc81ae45
--- /dev/null
+++ b/drivers/soc/ti/wkup_m3_ipc.c
@@ -0,0 +1,508 @@
+/*
+ * AMx3 Wkup M3 IPC driver
+ *
+ * Copyright (C) 2015 Texas Instruments, Inc.
+ *
+ * Dave Gerlach <d-gerlach@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/err.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/omap-mailbox.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/suspend.h>
+#include <linux/wkup_m3_ipc.h>
+
+#define AM33XX_CTRL_IPC_REG_COUNT 0x8
+#define AM33XX_CTRL_IPC_REG_OFFSET(m) (0x4 + 4 * (m))
+
+/* AM33XX M3_TXEV_EOI register */
+#define AM33XX_CONTROL_M3_TXEV_EOI 0x00
+
+#define AM33XX_M3_TXEV_ACK (0x1 << 0)
+#define AM33XX_M3_TXEV_ENABLE (0x0 << 0)
+
+#define IPC_CMD_DS0 0x4
+#define IPC_CMD_STANDBY 0xc
+#define IPC_CMD_IDLE 0x10
+#define IPC_CMD_RESET 0xe
+#define DS_IPC_DEFAULT 0xffffffff
+#define M3_VERSION_UNKNOWN 0x0000ffff
+#define M3_BASELINE_VERSION 0x191
+#define M3_STATUS_RESP_MASK (0xffff << 16)
+#define M3_FW_VERSION_MASK 0xffff
+
+#define M3_STATE_UNKNOWN 0
+#define M3_STATE_RESET 1
+#define M3_STATE_INITED 2
+#define M3_STATE_MSG_FOR_LP 3
+#define M3_STATE_MSG_FOR_RESET 4
+
+static struct wkup_m3_ipc *m3_ipc_state;
+
+static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc)
+{
+ writel(AM33XX_M3_TXEV_ACK,
+ m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+static void am33xx_txev_enable(struct wkup_m3_ipc *m3_ipc)
+{
+ writel(AM33XX_M3_TXEV_ENABLE,
+ m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+static void wkup_m3_ctrl_ipc_write(struct wkup_m3_ipc *m3_ipc,
+ u32 val, int ipc_reg_num)
+{
+ if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT,
+ "ipc register operation out of range"))
+ return;
+
+ writel(val, m3_ipc->ipc_mem_base +
+ AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num));
+}
+
+static unsigned int wkup_m3_ctrl_ipc_read(struct wkup_m3_ipc *m3_ipc,
+ int ipc_reg_num)
+{
+ if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT,
+ "ipc register operation out of range"))
+ return 0;
+
+ return readl(m3_ipc->ipc_mem_base +
+ AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num));
+}
+
+static int wkup_m3_fw_version_read(struct wkup_m3_ipc *m3_ipc)
+{
+ int val;
+
+ val = wkup_m3_ctrl_ipc_read(m3_ipc, 2);
+
+ return val & M3_FW_VERSION_MASK;
+}
+
+static irqreturn_t wkup_m3_txev_handler(int irq, void *ipc_data)
+{
+ struct wkup_m3_ipc *m3_ipc = ipc_data;
+ struct device *dev = m3_ipc->dev;
+ int ver = 0;
+
+ am33xx_txev_eoi(m3_ipc);
+
+ switch (m3_ipc->state) {
+ case M3_STATE_RESET:
+ ver = wkup_m3_fw_version_read(m3_ipc);
+
+ if (ver == M3_VERSION_UNKNOWN ||
+ ver < M3_BASELINE_VERSION) {
+ dev_warn(dev, "CM3 Firmware Version %x not supported\n",
+ ver);
+ } else {
+ dev_info(dev, "CM3 Firmware Version = 0x%x\n", ver);
+ }
+
+ m3_ipc->state = M3_STATE_INITED;
+ complete(&m3_ipc->sync_complete);
+ break;
+ case M3_STATE_MSG_FOR_RESET:
+ m3_ipc->state = M3_STATE_INITED;
+ complete(&m3_ipc->sync_complete);
+ break;
+ case M3_STATE_MSG_FOR_LP:
+ complete(&m3_ipc->sync_complete);
+ break;
+ case M3_STATE_UNKNOWN:
+ dev_warn(dev, "Unknown CM3 State\n");
+ }
+
+ am33xx_txev_enable(m3_ipc);
+
+ return IRQ_HANDLED;
+}
+
+static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc)
+{
+ struct device *dev = m3_ipc->dev;
+ mbox_msg_t dummy_msg = 0;
+ int ret;
+
+ if (!m3_ipc->mbox) {
+ dev_err(dev,
+ "No IPC channel to communicate with wkup_m3!\n");
+ return -EIO;
+ }
+
+ /*
+ * Write a dummy message to the mailbox in order to trigger the RX
+ * interrupt to alert the M3 that data is available in the IPC
+ * registers. We must enable the IRQ here and disable it after in
+ * the RX callback to avoid multiple interrupts being received
+ * by the CM3.
+ */
+ ret = mbox_send_message(m3_ipc->mbox, &dummy_msg);
+ if (ret < 0) {
+ dev_err(dev, "%s: mbox_send_message() failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&m3_ipc->sync_complete,
+ msecs_to_jiffies(500));
+ if (!ret) {
+ dev_err(dev, "MPU<->CM3 sync failure\n");
+ m3_ipc->state = M3_STATE_UNKNOWN;
+ return -EIO;
+ }
+
+ mbox_client_txdone(m3_ipc->mbox, 0);
+ return 0;
+}
+
+static int wkup_m3_ping_noirq(struct wkup_m3_ipc *m3_ipc)
+{
+ struct device *dev = m3_ipc->dev;
+ mbox_msg_t dummy_msg = 0;
+ int ret;
+
+ if (!m3_ipc->mbox) {
+ dev_err(dev,
+ "No IPC channel to communicate with wkup_m3!\n");
+ return -EIO;
+ }
+
+ ret = mbox_send_message(m3_ipc->mbox, &dummy_msg);
+ if (ret < 0) {
+ dev_err(dev, "%s: mbox_send_message() failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ mbox_client_txdone(m3_ipc->mbox, 0);
+ return 0;
+}
+
+static int wkup_m3_is_available(struct wkup_m3_ipc *m3_ipc)
+{
+ return ((m3_ipc->state != M3_STATE_RESET) &&
+ (m3_ipc->state != M3_STATE_UNKNOWN));
+}
+
+/* Public functions */
+/**
+ * wkup_m3_set_mem_type - Pass wkup_m3 which type of memory is in use
+ * @mem_type: memory type value read directly from emif
+ *
+ * wkup_m3 must know what memory type is in use to properly suspend
+ * and resume.
+ */
+static void wkup_m3_set_mem_type(struct wkup_m3_ipc *m3_ipc, int mem_type)
+{
+ m3_ipc->mem_type = mem_type;
+}
+
+/**
+ * wkup_m3_set_resume_address - Pass wkup_m3 resume address
+ * @addr: Physical address from which resume code should execute
+ */
+static void wkup_m3_set_resume_address(struct wkup_m3_ipc *m3_ipc, void *addr)
+{
+ m3_ipc->resume_addr = (unsigned long)addr;
+}
+
+/**
+ * wkup_m3_request_pm_status - Retrieve wkup_m3 status code after suspend
+ *
+ * Returns code representing the status of a low power mode transition.
+ * 0 - Successful transition
+ * 1 - Failure to transition to low power state
+ */
+static int wkup_m3_request_pm_status(struct wkup_m3_ipc *m3_ipc)
+{
+ unsigned int i;
+ int val;
+
+ val = wkup_m3_ctrl_ipc_read(m3_ipc, 1);
+
+ i = M3_STATUS_RESP_MASK & val;
+ i >>= __ffs(M3_STATUS_RESP_MASK);
+
+ return i;
+}
+
+/**
+ * wkup_m3_prepare_low_power - Request preparation for transition to
+ * low power state
+ * @state: A kernel suspend state to enter, either MEM or STANDBY
+ *
+ * Returns 0 if preparation was successful, otherwise returns error code
+ */
+static int wkup_m3_prepare_low_power(struct wkup_m3_ipc *m3_ipc, int state)
+{
+ struct device *dev = m3_ipc->dev;
+ int m3_power_state;
+ int ret = 0;
+
+ if (!wkup_m3_is_available(m3_ipc))
+ return -ENODEV;
+
+ switch (state) {
+ case WKUP_M3_DEEPSLEEP:
+ m3_power_state = IPC_CMD_DS0;
+ break;
+ case WKUP_M3_STANDBY:
+ m3_power_state = IPC_CMD_STANDBY;
+ break;
+ case WKUP_M3_IDLE:
+ m3_power_state = IPC_CMD_IDLE;
+ break;
+ default:
+ return 1;
+ }
+
+ /* Program each required IPC register then write defaults to others */
+ wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->resume_addr, 0);
+ wkup_m3_ctrl_ipc_write(m3_ipc, m3_power_state, 1);
+ wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->mem_type, 4);
+
+ wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2);
+ wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 3);
+ wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 5);
+ wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 6);
+ wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 7);
+
+ m3_ipc->state = M3_STATE_MSG_FOR_LP;
+
+ if (state == WKUP_M3_IDLE)
+ ret = wkup_m3_ping_noirq(m3_ipc);
+ else
+ ret = wkup_m3_ping(m3_ipc);
+
+ if (ret) {
+ dev_err(dev, "Unable to ping CM3\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * wkup_m3_finish_low_power - Return m3 to reset state
+ *
+ * Returns 0 if reset was successful, otherwise returns error code
+ */
+static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc)
+{
+ struct device *dev = m3_ipc->dev;
+ int ret = 0;
+
+ if (!wkup_m3_is_available(m3_ipc))
+ return -ENODEV;
+
+ wkup_m3_ctrl_ipc_write(m3_ipc, IPC_CMD_RESET, 1);
+ wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2);
+
+ m3_ipc->state = M3_STATE_MSG_FOR_RESET;
+
+ ret = wkup_m3_ping(m3_ipc);
+ if (ret) {
+ dev_err(dev, "Unable to ping CM3\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct wkup_m3_ipc_ops ipc_ops = {
+ .set_mem_type = wkup_m3_set_mem_type,
+ .set_resume_address = wkup_m3_set_resume_address,
+ .prepare_low_power = wkup_m3_prepare_low_power,
+ .finish_low_power = wkup_m3_finish_low_power,
+ .request_pm_status = wkup_m3_request_pm_status,
+};
+
+/**
+ * wkup_m3_ipc_get - Return handle to wkup_m3_ipc
+ *
+ * Returns NULL if the wkup_m3 is not yet available, otherwise returns
+ * pointer to wkup_m3_ipc struct.
+ */
+struct wkup_m3_ipc *wkup_m3_ipc_get(void)
+{
+ if (m3_ipc_state)
+ get_device(m3_ipc_state->dev);
+ else
+ return NULL;
+
+ return m3_ipc_state;
+}
+EXPORT_SYMBOL_GPL(wkup_m3_ipc_get);
+
+/**
+ * wkup_m3_ipc_put - Free handle to wkup_m3_ipc returned from wkup_m3_ipc_get
+ * @m3_ipc: A pointer to wkup_m3_ipc struct returned by wkup_m3_ipc_get
+ */
+void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc)
+{
+ if (m3_ipc_state)
+ put_device(m3_ipc_state->dev);
+}
+EXPORT_SYMBOL_GPL(wkup_m3_ipc_put);
+
+static void wkup_m3_rproc_boot_thread(struct wkup_m3_ipc *m3_ipc)
+{
+ struct device *dev = m3_ipc->dev;
+ int ret;
+
+ wait_for_completion(&m3_ipc->rproc->firmware_loading_complete);
+
+ init_completion(&m3_ipc->sync_complete);
+
+ ret = rproc_boot(m3_ipc->rproc);
+ if (ret)
+ dev_err(dev, "rproc_boot failed\n");
+
+ do_exit(0);
+}
+
+static int wkup_m3_ipc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int irq, ret;
+ phandle rproc_phandle;
+ struct rproc *m3_rproc;
+ struct resource *res;
+ struct task_struct *task;
+ struct wkup_m3_ipc *m3_ipc;
+
+ m3_ipc = devm_kzalloc(dev, sizeof(*m3_ipc), GFP_KERNEL);
+ if (!m3_ipc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(m3_ipc->ipc_mem_base)) {
+ dev_err(dev, "could not ioremap ipc_mem\n");
+ return PTR_ERR(m3_ipc->ipc_mem_base);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(dev, irq, wkup_m3_txev_handler,
+ 0, "wkup_m3_txev", m3_ipc);
+ if (ret) {
+ dev_err(dev, "request_irq failed\n");
+ return ret;
+ }
+
+ m3_ipc->mbox_client.dev = dev;
+ m3_ipc->mbox_client.tx_done = NULL;
+ m3_ipc->mbox_client.tx_prepare = NULL;
+ m3_ipc->mbox_client.rx_callback = NULL;
+ m3_ipc->mbox_client.tx_block = false;
+ m3_ipc->mbox_client.knows_txdone = false;
+
+ m3_ipc->mbox = mbox_request_channel(&m3_ipc->mbox_client, 0);
+
+ if (IS_ERR(m3_ipc->mbox)) {
+ dev_err(dev, "IPC Request for A8->M3 Channel failed! %ld\n",
+ PTR_ERR(m3_ipc->mbox));
+ return PTR_ERR(m3_ipc->mbox);
+ }
+
+ if (of_property_read_u32(dev->of_node, "ti,rproc", &rproc_phandle)) {
+ dev_err(&pdev->dev, "could not get rproc phandle\n");
+ ret = -ENODEV;
+ goto err_free_mbox;
+ }
+
+ m3_rproc = rproc_get_by_phandle(rproc_phandle);
+ if (!m3_rproc) {
+ dev_err(&pdev->dev, "could not get rproc handle\n");
+ ret = -EPROBE_DEFER;
+ goto err_free_mbox;
+ }
+
+ m3_ipc->rproc = m3_rproc;
+ m3_ipc->dev = dev;
+ m3_ipc->state = M3_STATE_RESET;
+
+ m3_ipc->ops = &ipc_ops;
+
+ /*
+ * Wait for firmware loading completion in a thread so we
+ * can boot the wkup_m3 as soon as it's ready without holding
+ * up kernel boot
+ */
+ task = kthread_run((void *)wkup_m3_rproc_boot_thread, m3_ipc,
+ "wkup_m3_rproc_loader");
+
+ if (IS_ERR(task)) {
+ dev_err(dev, "can't create rproc_boot thread\n");
+ goto err_put_rproc;
+ }
+
+ m3_ipc_state = m3_ipc;
+
+ return 0;
+
+err_put_rproc:
+ rproc_put(m3_rproc);
+err_free_mbox:
+ mbox_free_channel(m3_ipc->mbox);
+ return ret;
+}
+
+static int wkup_m3_ipc_remove(struct platform_device *pdev)
+{
+ mbox_free_channel(m3_ipc_state->mbox);
+
+ rproc_shutdown(m3_ipc_state->rproc);
+ rproc_put(m3_ipc_state->rproc);
+
+ m3_ipc_state = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id wkup_m3_ipc_of_match[] = {
+ { .compatible = "ti,am3352-wkup-m3-ipc", },
+ { .compatible = "ti,am4372-wkup-m3-ipc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, wkup_m3_ipc_of_match);
+
+static struct platform_driver wkup_m3_ipc_driver = {
+ .probe = wkup_m3_ipc_probe,
+ .remove = wkup_m3_ipc_remove,
+ .driver = {
+ .name = "wkup_m3_ipc",
+ .of_match_table = wkup_m3_ipc_of_match,
+ },
+};
+
+module_platform_driver(wkup_m3_ipc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("wkup m3 remote processor ipc driver");
+MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
index e642c4540dda..c337764de867 100644
--- a/drivers/soc/versatile/soc-realview.c
+++ b/drivers/soc/versatile/soc-realview.c
@@ -36,6 +36,8 @@ static const char *realview_board_str(u32 id)
switch ((id >> 16) & 0xfff) {
case 0x0147:
return "HBI-0147";
+ case 0x0159:
+ return "HBI-0159";
default:
return "Unknown";
}
@@ -44,6 +46,8 @@ static const char *realview_board_str(u32 id)
static const char *realview_arch_str(u32 id)
{
switch ((id >> 8) & 0xf) {
+ case 0x04:
+ return "AHB";
case 0x05:
return "Multi-layer AXI";
default:
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8b9c2a38d1cc..77064160dd76 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -585,7 +585,7 @@ config SPI_TEGRA20_SLINK
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
- depends on PCI && (X86_32 || COMPILE_TEST)
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
SPI driver for the Topcliff PCH (Platform Controller Hub) SPI bus
used in some x86 embedded processors.
@@ -689,6 +689,15 @@ config SPI_SPIDEV
Note that this application programming interface is EXPERIMENTAL
and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
+config SPI_LOOPBACK_TEST
+ tristate "spi loopback test framework support"
+ depends on m
+ help
+ This enables the SPI loopback testing framework driver
+
+ primarily used for development of spi_master drivers
+ and to detect regressions
+
config SPI_TLE62X0
tristate "Infineon TLE62X0 (for power switching)"
depends on SYSFS
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 31fb7fb2a0b6..8991ffce6e12 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -8,6 +8,7 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
# config declarations into driver model code
obj-$(CONFIG_SPI_MASTER) += spi.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
+obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index bf9a610e5b89..fee747030ee6 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -207,6 +207,9 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
u8 clk_cfg, reg;
int i;
+ /* Default to lowest clock configuration */
+ clk_cfg = SPI_CLK_0_391MHZ;
+
/* Find the closest clock configuration */
for (i = 0; i < SPI_CLK_MASK; i++) {
if (t->speed_hz >= bcm63xx_spi_freq_table[i][0]) {
@@ -215,10 +218,6 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
}
}
- /* No matching configuration found, default to lowest */
- if (i == SPI_CLK_MASK)
- clk_cfg = SPI_CLK_0_391MHZ;
-
/* clear existing clock configuration bits of the register */
reg = bcm_spi_readb(bs, SPI_CLK_CFG);
reg &= ~SPI_CLK_MASK;
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index 9a95862986c8..22a31e4a1a11 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.c
@@ -27,7 +27,6 @@
#include <linux/mtd/partitions.h>
-
/*
* This uses SPI to talk with an "AVR Butterfly", which is a $US20 card
* with a battery powered AVR microcontroller and lots of goodies. You
@@ -37,7 +36,6 @@
* and use this custom parallel port cable.
*/
-
/* DATA output bits (pins 2..9 == D0..D7) */
#define butterfly_nreset (1 << 1) /* pin 3 */
@@ -52,14 +50,11 @@
/* CONTROL output bits */
#define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */
-
-
static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
{
return spi->controller_data;
}
-
struct butterfly {
/* REVISIT ... for now, this must be first */
struct spi_bitbang bitbang;
@@ -140,7 +135,6 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
}
-
/* we only needed to implement one mode here, and choose SPI_MODE_0 */
#define spidelay(X) do { } while (0)
@@ -149,9 +143,8 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
#include "spi-bitbang-txrx.h"
static u32
-butterfly_txrx_word_mode0(struct spi_device *spi,
- unsigned nsecs,
- u32 word, u8 bits)
+butterfly_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word,
+ u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
}
@@ -186,7 +179,6 @@ static struct flash_platform_data flash = {
.nr_parts = ARRAY_SIZE(partitions),
};
-
/* REVISIT remove this ugly global and its "only one" limitation */
static struct butterfly *butterfly;
@@ -197,6 +189,7 @@ static void butterfly_attach(struct parport *p)
struct butterfly *pp;
struct spi_master *master;
struct device *dev = p->physport->dev;
+ struct pardev_cb butterfly_cb;
if (butterfly || !dev)
return;
@@ -229,9 +222,9 @@ static void butterfly_attach(struct parport *p)
* parport hookup
*/
pp->port = p;
- pd = parport_register_device(p, "spi_butterfly",
- NULL, NULL, NULL,
- 0 /* FLAGS */, pp);
+ memset(&butterfly_cb, 0, sizeof(butterfly_cb));
+ butterfly_cb.private = pp;
+ pd = parport_register_dev_model(p, "spi_butterfly", &butterfly_cb, 0);
if (!pd) {
status = -ENOMEM;
goto clean0;
@@ -262,7 +255,6 @@ static void butterfly_attach(struct parport *p)
parport_write_data(pp->port, pp->lastbyte);
msleep(100);
-
/*
* Start SPI ... for now, hide that we're two physical busses.
*/
@@ -283,7 +275,7 @@ static void butterfly_attach(struct parport *p)
pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]);
if (pp->dataflash)
pr_debug("%s: dataflash at %s\n", p->name,
- dev_name(&pp->dataflash->dev));
+ dev_name(&pp->dataflash->dev));
pr_info("%s: AVR Butterfly\n", p->name);
butterfly = pp;
@@ -297,7 +289,7 @@ clean2:
clean1:
parport_unregister_device(pd);
clean0:
- (void) spi_master_put(pp->bitbang.master);
+ spi_master_put(pp->bitbang.master);
done:
pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
}
@@ -325,16 +317,16 @@ static void butterfly_detach(struct parport *p)
parport_release(pp->pd);
parport_unregister_device(pp->pd);
- (void) spi_master_put(pp->bitbang.master);
+ spi_master_put(pp->bitbang.master);
}
static struct parport_driver butterfly_driver = {
.name = "spi_butterfly",
- .attach = butterfly_attach,
+ .match_port = butterfly_attach,
.detach = butterfly_detach,
+ .devmodel = true,
};
-
static int __init butterfly_init(void)
{
return parport_register_driver(&butterfly_driver);
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 5a6749881ff9..121a4135b540 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -617,8 +617,7 @@ static int cdns_spi_remove(struct platform_device *pdev)
*/
static int __maybe_unused cdns_spi_suspend(struct device *dev)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct spi_master *master = platform_get_drvdata(pdev);
struct cdns_spi *xspi = spi_master_get_devdata(master);
@@ -641,8 +640,7 @@ static int __maybe_unused cdns_spi_suspend(struct device *dev)
*/
static int __maybe_unused cdns_spi_resume(struct device *dev)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct spi_master *master = platform_get_drvdata(pdev);
struct cdns_spi *xspi = spi_master_get_devdata(master);
int ret = 0;
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 7d3af3eacf57..fddb7a3be322 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -477,33 +477,33 @@ static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
struct device *sdev = dspi->bitbang.master->dev.parent;
if (int_status & SPIFLG_TIMEOUT_MASK) {
- dev_dbg(sdev, "SPI Time-out Error\n");
+ dev_err(sdev, "SPI Time-out Error\n");
return -ETIMEDOUT;
}
if (int_status & SPIFLG_DESYNC_MASK) {
- dev_dbg(sdev, "SPI Desynchronization Error\n");
+ dev_err(sdev, "SPI Desynchronization Error\n");
return -EIO;
}
if (int_status & SPIFLG_BITERR_MASK) {
- dev_dbg(sdev, "SPI Bit error\n");
+ dev_err(sdev, "SPI Bit error\n");
return -EIO;
}
if (dspi->version == SPI_VERSION_2) {
if (int_status & SPIFLG_DLEN_ERR_MASK) {
- dev_dbg(sdev, "SPI Data Length Error\n");
+ dev_err(sdev, "SPI Data Length Error\n");
return -EIO;
}
if (int_status & SPIFLG_PARERR_MASK) {
- dev_dbg(sdev, "SPI Parity Error\n");
+ dev_err(sdev, "SPI Parity Error\n");
return -EIO;
}
if (int_status & SPIFLG_OVRRUN_MASK) {
- dev_dbg(sdev, "SPI Data Overrun error\n");
+ dev_err(sdev, "SPI Data Overrun error\n");
return -EIO;
}
if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) {
- dev_dbg(sdev, "SPI Buffer Init Active\n");
+ dev_err(sdev, "SPI Buffer Init Active\n");
return -EBUSY;
}
}
@@ -703,7 +703,8 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
/* Wait for the transfer to complete */
if (spicfg->io_type != SPI_IO_TYPE_POLL) {
- wait_for_completion_interruptible(&(dspi->done));
+ if (wait_for_completion_timeout(&dspi->done, HZ) == 0)
+ errors = SPIFLG_TIMEOUT_MASK;
} else {
while (dspi->rcount > 0 || dspi->wcount > 0) {
errors = davinci_spi_process_events(dspi);
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index bb1052e748f2..9185f6c08459 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -283,7 +283,7 @@ static void mid_spi_dma_stop(struct dw_spi *dws)
}
}
-static struct dw_spi_dma_ops mid_dma_ops = {
+static const struct dw_spi_dma_ops mid_dma_ops = {
.dma_init = mid_spi_dma_init,
.dma_exit = mid_spi_dma_exit,
.dma_setup = mid_spi_dma_setup,
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 882cd6618cd5..c09bb745693a 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -425,7 +425,7 @@ static int dw_spi_setup(struct spi_device *spi)
chip->type = chip_info->type;
}
- chip->tmode = 0; /* Tx & Rx */
+ chip->tmode = SPI_TMOD_TR;
if (gpio_is_valid(spi->cs_gpio)) {
ret = gpio_direction_output(spi->cs_gpio,
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 35589a270468..61bc3cbab38d 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -130,7 +130,7 @@ struct dw_spi {
struct dma_chan *rxchan;
unsigned long dma_chan_busy;
dma_addr_t dma_addr; /* phy address of the Data register */
- struct dw_spi_dma_ops *dma_ops;
+ const struct dw_spi_dma_ops *dma_ops;
void *dma_tx;
void *dma_rx;
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index 896add8cfd3b..8f7b26ec181e 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -16,7 +16,7 @@
* option) any later version.
*/
#include <asm/cpm.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include <linux/dma-mapping.h>
#include <linux/fsl_devices.h>
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index c27124a5ec8e..7fd6a4c009d2 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -643,6 +643,11 @@ static int fsl_espi_runtime_resume(struct device *dev)
}
#endif
+static size_t fsl_espi_max_transfer_size(struct spi_device *spi)
+{
+ return SPCOM_TRANLEN_MAX;
+}
+
static struct spi_master * fsl_espi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
@@ -670,6 +675,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
master->cleanup = fsl_espi_cleanup;
master->transfer_one_message = fsl_espi_do_one_msg;
master->auto_runtime_pm = true;
+ master->max_transfer_size = fsl_espi_max_transfer_size;
mpc8xxx_spi = spi_master_get_devdata(master);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 0e5723ab47f0..d98c33cb64f9 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -104,9 +104,7 @@ struct spi_imx_data {
unsigned int dma_is_inited;
unsigned int dma_finished;
bool usedma;
- u32 rx_wml;
- u32 tx_wml;
- u32 rxt_wml;
+ u32 wml;
struct completion dma_rx_completion;
struct completion dma_tx_completion;
@@ -124,9 +122,14 @@ static inline int is_imx35_cspi(struct spi_imx_data *d)
return d->devtype_data->devtype == IMX35_CSPI;
}
+static inline int is_imx51_ecspi(struct spi_imx_data *d)
+{
+ return d->devtype_data->devtype == IMX51_ECSPI;
+}
+
static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d)
{
- return (d->devtype_data->devtype == IMX51_ECSPI) ? 64 : 8;
+ return is_imx51_ecspi(d) ? 64 : 8;
}
#define MXC_SPI_BUF_RX(type) \
@@ -201,9 +204,8 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
- if (spi_imx->dma_is_inited
- && transfer->len > spi_imx->rx_wml * sizeof(u32)
- && transfer->len > spi_imx->tx_wml * sizeof(u32))
+ if (spi_imx->dma_is_inited &&
+ transfer->len > spi_imx->wml * sizeof(u32))
return true;
return false;
}
@@ -244,6 +246,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3)
+#define MX51_ECSPI_TESTREG 0x20
+#define MX51_ECSPI_TESTREG_LBC BIT(31)
+
/* MX51 eCSPI */
static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
unsigned int *fres)
@@ -313,7 +318,7 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
{
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
- u32 clk = config->speed_hz, delay;
+ u32 clk = config->speed_hz, delay, reg;
/*
* The hardware seems to have a race condition when changing modes. The
@@ -351,7 +356,16 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
else
cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(config->cs);
+ /* CTRL register always go first to bring out controller from reset */
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+
+ reg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
+ if (config->mode & SPI_LOOP)
+ reg |= MX51_ECSPI_TESTREG_LBC;
+ else
+ reg &= ~MX51_ECSPI_TESTREG_LBC;
+ writel(reg, spi_imx->base + MX51_ECSPI_TESTREG);
+
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
/*
@@ -378,10 +392,9 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
if (spi_imx->dma_is_inited) {
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
- spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2;
- rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
- tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
- rxt_wml_cfg = spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
+ rx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
+ tx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
+ rxt_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK
& ~MX51_ECSPI_DMA_RX_WML_MASK
& ~MX51_ECSPI_DMA_RXT_WML_MASK)
@@ -832,18 +845,21 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
if (of_machine_is_compatible("fsl,imx6dl"))
return 0;
+ spi_imx->wml = spi_imx_get_fifosize(spi_imx) / 2;
+
/* Prepare for TX DMA: */
- master->dma_tx = dma_request_slave_channel(dev, "tx");
- if (!master->dma_tx) {
- dev_err(dev, "cannot get the TX DMA channel!\n");
- ret = -EINVAL;
+ master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
+ if (IS_ERR(master->dma_tx)) {
+ ret = PTR_ERR(master->dma_tx);
+ dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
+ master->dma_tx = NULL;
goto err;
}
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = res->start + MXC_CSPITXDATA;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config.dst_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
+ slave_config.dst_maxburst = spi_imx->wml;
ret = dmaengine_slave_config(master->dma_tx, &slave_config);
if (ret) {
dev_err(dev, "error in TX dma configuration.\n");
@@ -851,17 +867,18 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
}
/* Prepare for RX : */
- master->dma_rx = dma_request_slave_channel(dev, "rx");
- if (!master->dma_rx) {
- dev_dbg(dev, "cannot get the DMA channel.\n");
- ret = -EINVAL;
+ master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
+ if (IS_ERR(master->dma_rx)) {
+ ret = PTR_ERR(master->dma_rx);
+ dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
+ master->dma_rx = NULL;
goto err;
}
slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_addr = res->start + MXC_CSPIRXDATA;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config.src_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
+ slave_config.src_maxburst = spi_imx->wml;
ret = dmaengine_slave_config(master->dma_rx, &slave_config);
if (ret) {
dev_err(dev, "error in RX dma configuration.\n");
@@ -874,8 +891,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
master->max_dma_len = MAX_SDMA_BD_BYTES;
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
SPI_MASTER_MUST_TX;
- spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
- spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->dma_is_inited = 1;
return 0;
@@ -942,14 +957,22 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
/* Change RX_DMA_LENGTH trigger dma fetch tail data */
- left = transfer->len % spi_imx->rxt_wml;
+ left = transfer->len % spi_imx->wml;
if (left)
writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
spi_imx->base + MX51_ECSPI_DMA);
+ /*
+ * Set these order to avoid potential RX overflow. The overflow may
+ * happen if we enable SPI HW before starting RX DMA due to rescheduling
+ * for another task and/or interrupt.
+ * So RX DMA enabled first to make sure data would be read out from FIFO
+ * ASAP. TX DMA enabled next to start filling TX FIFO with new data.
+ * And finaly SPI HW enabled to start actual data transfer.
+ */
+ dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(master->dma_tx);
spi_imx->devtype_data->trigger(spi_imx);
- dma_async_issue_pending(master->dma_tx);
- dma_async_issue_pending(master->dma_rx);
/* Wait SDMA to finish the data transfer.*/
timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
IMX_DMA_TIMEOUT);
@@ -958,6 +981,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
dev_driver_string(&master->dev),
dev_name(&master->dev));
dmaengine_terminate_all(master->dma_tx);
+ dmaengine_terminate_all(master->dma_rx);
} else {
timeout = wait_for_completion_timeout(
&spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT);
@@ -968,8 +992,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
spi_imx->devtype_data->reset(spi_imx);
dmaengine_terminate_all(master->dma_rx);
}
+ dma &= ~MX51_ECSPI_DMA_RXT_WML_MASK;
writel(dma |
- spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
+ spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
spi_imx->base + MX51_ECSPI_DMA);
}
@@ -1117,6 +1142,9 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
+ spi_imx->devtype_data = of_id ? of_id->data :
+ (struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
+
for (i = 0; i < master->num_chipselect; i++) {
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
if (!gpio_is_valid(cs_gpio) && mxc_platform_info)
@@ -1142,12 +1170,11 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ if (is_imx51_ecspi(spi_imx))
+ spi_imx->bitbang.master->mode_bits |= SPI_LOOP;
init_completion(&spi_imx->xfer_done);
- spi_imx->devtype_data = of_id ? of_id->data :
- (struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi_imx->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(spi_imx->base)) {
@@ -1193,9 +1220,15 @@ static int spi_imx_probe(struct platform_device *pdev)
* Only validated on i.mx6 now, can remove the constrain if validated on
* other chips.
*/
- if (spi_imx->devtype_data == &imx51_ecspi_devtype_data
- && spi_imx_sdma_init(&pdev->dev, spi_imx, master, res))
- dev_err(&pdev->dev, "dma setup error,use pio instead\n");
+ if (is_imx51_ecspi(spi_imx)) {
+ ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master, res);
+ if (ret == -EPROBE_DEFER)
+ goto out_clk_put;
+
+ if (ret < 0)
+ dev_err(&pdev->dev, "dma setup error %d, use pio\n",
+ ret);
+ }
spi_imx->devtype_data->reset(spi_imx);
diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c
index ba72347cb99d..61ee0f4269ae 100644
--- a/drivers/spi/spi-lm70llp.c
+++ b/drivers/spi/spi-lm70llp.c
@@ -14,6 +14,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -23,11 +25,9 @@
#include <linux/sysfs.h>
#include <linux/workqueue.h>
-
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-
/*
* The LM70 communicates with a host processor using a 3-wire variant of
* the SPI/Microwire bus interface. This driver specifically supports an
@@ -88,7 +88,6 @@ struct spi_lm70llp {
/* REVISIT : ugly global ; provides "exclusive open" facility */
static struct spi_lm70llp *lm70llp;
-
/*-------------------------------------------------------------------*/
static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
@@ -122,12 +121,14 @@ static inline void assertCS(struct spi_lm70llp *pp)
static inline void clkHigh(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
+
parport_write_data(pp->port, data | SCLK);
}
static inline void clkLow(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
+
parport_write_data(pp->port, data & ~SCLK);
}
@@ -166,8 +167,10 @@ static inline void setmosi(struct spi_device *s, int is_on)
static inline int getmiso(struct spi_device *s)
{
struct spi_lm70llp *pp = spidev_to_pp(s);
- return ((SIO == (parport_read_status(pp->port) & SIO)) ? 0 : 1 );
+
+ return ((SIO == (parport_read_status(pp->port) & SIO)) ? 0 : 1);
}
+
/*--------------------------------------------------------------------*/
#include "spi-bitbang-txrx.h"
@@ -196,11 +199,10 @@ static void spi_lm70llp_attach(struct parport *p)
struct spi_lm70llp *pp;
struct spi_master *master;
int status;
+ struct pardev_cb lm70llp_cb;
if (lm70llp) {
- printk(KERN_WARNING
- "%s: spi_lm70llp instance already loaded. Aborting.\n",
- DRVNAME);
+ pr_warn("spi_lm70llp instance already loaded. Aborting.\n");
return;
}
@@ -227,9 +229,11 @@ static void spi_lm70llp_attach(struct parport *p)
* Parport hookup
*/
pp->port = p;
- pd = parport_register_device(p, DRVNAME,
- NULL, NULL, NULL,
- PARPORT_FLAG_EXCL, pp);
+ memset(&lm70llp_cb, 0, sizeof(lm70llp_cb));
+ lm70llp_cb.private = pp;
+ lm70llp_cb.flags = PARPORT_FLAG_EXCL;
+ pd = parport_register_dev_model(p, DRVNAME, &lm70llp_cb, 0);
+
if (!pd) {
status = -ENOMEM;
goto out_free_master;
@@ -245,9 +249,8 @@ static void spi_lm70llp_attach(struct parport *p)
*/
status = spi_bitbang_start(&pp->bitbang);
if (status < 0) {
- printk(KERN_WARNING
- "%s: spi_bitbang_start failed with status %d\n",
- DRVNAME, status);
+ dev_warn(&pd->dev, "spi_bitbang_start failed with status %d\n",
+ status);
goto out_off_and_release;
}
@@ -272,9 +275,9 @@ static void spi_lm70llp_attach(struct parport *p)
pp->spidev_lm70 = spi_new_device(pp->bitbang.master, &pp->info);
if (pp->spidev_lm70)
dev_dbg(&pp->spidev_lm70->dev, "spidev_lm70 at %s\n",
- dev_name(&pp->spidev_lm70->dev));
+ dev_name(&pp->spidev_lm70->dev));
else {
- printk(KERN_WARNING "%s: spi_new_device failed\n", DRVNAME);
+ dev_warn(&pd->dev, "spi_new_device failed\n");
status = -ENODEV;
goto out_bitbang_stop;
}
@@ -293,9 +296,9 @@ out_off_and_release:
out_parport_unreg:
parport_unregister_device(pd);
out_free_master:
- (void) spi_master_put(master);
+ spi_master_put(master);
out_fail:
- pr_info("%s: spi_lm70llp probe fail, status %d\n", DRVNAME, status);
+ pr_info("spi_lm70llp probe fail, status %d\n", status);
}
static void spi_lm70llp_detach(struct parport *p)
@@ -314,16 +317,16 @@ static void spi_lm70llp_detach(struct parport *p)
parport_release(pp->pd);
parport_unregister_device(pp->pd);
- (void) spi_master_put(pp->bitbang.master);
+ spi_master_put(pp->bitbang.master);
lm70llp = NULL;
}
-
static struct parport_driver spi_lm70llp_drv = {
.name = DRVNAME,
- .attach = spi_lm70llp_attach,
+ .match_port = spi_lm70llp_attach,
.detach = spi_lm70llp_detach,
+ .devmodel = true,
};
static int __init init_spi_lm70llp(void)
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
new file mode 100644
index 000000000000..894616f687b0
--- /dev/null
+++ b/drivers/spi/spi-loopback-test.c
@@ -0,0 +1,1005 @@
+/*
+ * linux/drivers/spi/spi-loopback-test.c
+ *
+ * (c) Martin Sperl <kernel@martin.sperl.org>
+ *
+ * Loopback test driver to test several typical spi_message conditions
+ * that a spi_master driver may encounter
+ * this can also get used for regression testing
+ *
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/printk.h>
+#include <linux/spi/spi.h>
+
+#include "spi-test.h"
+
+/* flag to only simulate transfers */
+int simulate_only;
+module_param(simulate_only, int, 0);
+MODULE_PARM_DESC(simulate_only, "if not 0 do not execute the spi message");
+
+/* dump spi messages */
+int dump_messages;
+module_param(dump_messages, int, 0);
+MODULE_PARM_DESC(dump_messages,
+ "=1 dump the basic spi_message_structure, " \
+ "=2 dump the spi_message_structure including data, " \
+ "=3 dump the spi_message structure before and after execution");
+/* the device is jumpered for loopback - enabling some rx_buf tests */
+int loopback;
+module_param(loopback, int, 0);
+MODULE_PARM_DESC(loopback,
+ "if set enable loopback mode, where the rx_buf " \
+ "is checked to match tx_buf after the spi_message " \
+ "is executed");
+
+/* run only a specific test */
+int run_only_test = -1;
+module_param(run_only_test, int, 0);
+MODULE_PARM_DESC(run_only_test,
+ "only run the test with this number (0-based !)");
+
+/* the actual tests to execute */
+static struct spi_test spi_tests[] = {
+ {
+ .description = "tx/rx-transfer - start of page",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_rx_align = ITERATE_ALIGN,
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ .rx_buf = RX(0),
+ },
+ },
+ },
+ {
+ .description = "tx/rx-transfer - crossing PAGE_SIZE",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_rx_align = ITERATE_ALIGN,
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(PAGE_SIZE - 4),
+ .rx_buf = RX(PAGE_SIZE - 4),
+ },
+ },
+ },
+ {
+ .description = "tx-transfer - only",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ },
+ },
+ },
+ {
+ .description = "rx-transfer - only",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_rx_align = ITERATE_ALIGN,
+ .transfers = {
+ {
+ .len = 1,
+ .rx_buf = RX(0),
+ },
+ },
+ },
+ {
+ .description = "two tx-transfers - alter both",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(0) | BIT(1),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ },
+ {
+ .len = 1,
+ /* this is why we cant use ITERATE_MAX_LEN */
+ .tx_buf = TX(SPI_TEST_MAX_SIZE_HALF),
+ },
+ },
+ },
+ {
+ .description = "two tx-transfers - alter first",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(1),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(64),
+ },
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ },
+ },
+ },
+ {
+ .description = "two tx-transfers - alter second",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(0),
+ .transfers = {
+ {
+ .len = 16,
+ .tx_buf = TX(0),
+ },
+ {
+ .len = 1,
+ .tx_buf = TX(64),
+ },
+ },
+ },
+ {
+ .description = "two transfers tx then rx - alter both",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(0) | BIT(1),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ },
+ {
+ .len = 1,
+ .rx_buf = RX(0),
+ },
+ },
+ },
+ {
+ .description = "two transfers tx then rx - alter tx",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(0),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ },
+ {
+ .len = 1,
+ .rx_buf = RX(0),
+ },
+ },
+ },
+ {
+ .description = "two transfers tx then rx - alter rx",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(1),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ },
+ {
+ .len = 1,
+ .rx_buf = RX(0),
+ },
+ },
+ },
+ {
+ .description = "two tx+rx transfers - alter both",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(0) | BIT(1),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ .rx_buf = RX(0),
+ },
+ {
+ .len = 1,
+ /* making sure we align without overwrite
+ * the reason we can not use ITERATE_MAX_LEN
+ */
+ .tx_buf = TX(SPI_TEST_MAX_SIZE_HALF),
+ .rx_buf = RX(SPI_TEST_MAX_SIZE_HALF),
+ },
+ },
+ },
+ {
+ .description = "two tx+rx transfers - alter first",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(0),
+ .transfers = {
+ {
+ .len = 1,
+ /* making sure we align without overwrite */
+ .tx_buf = TX(1024),
+ .rx_buf = RX(1024),
+ },
+ {
+ .len = 1,
+ /* making sure we align without overwrite */
+ .tx_buf = TX(0),
+ .rx_buf = RX(0),
+ },
+ },
+ },
+ {
+ .description = "two tx+rx transfers - alter second",
+ .fill_option = FILL_COUNT_8,
+ .iterate_len = { ITERATE_MAX_LEN },
+ .iterate_tx_align = ITERATE_ALIGN,
+ .iterate_transfer_mask = BIT(1),
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ .rx_buf = RX(0),
+ },
+ {
+ .len = 1,
+ /* making sure we align without overwrite */
+ .tx_buf = TX(1024),
+ .rx_buf = RX(1024),
+ },
+ },
+ },
+
+ { /* end of tests sequence */ }
+};
+
+static int spi_loopback_test_probe(struct spi_device *spi)
+{
+ int ret;
+
+ dev_info(&spi->dev, "Executing spi-loopback-tests\n");
+
+ ret = spi_test_run_tests(spi, spi_tests);
+
+ dev_info(&spi->dev, "Finished spi-loopback-tests with return: %i\n",
+ ret);
+
+ return ret;
+}
+
+/* non const match table to permit to change via a module parameter */
+static struct of_device_id spi_loopback_test_of_match[] = {
+ { .compatible = "linux,spi-loopback-test", },
+ { }
+};
+
+/* allow to override the compatible string via a module_parameter */
+module_param_string(compatible, spi_loopback_test_of_match[0].compatible,
+ sizeof(spi_loopback_test_of_match[0].compatible),
+ 0000);
+
+MODULE_DEVICE_TABLE(of, spi_loopback_test_of_match);
+
+static struct spi_driver spi_loopback_test_driver = {
+ .driver = {
+ .name = "spi-loopback-test",
+ .owner = THIS_MODULE,
+ .of_match_table = spi_loopback_test_of_match,
+ },
+ .probe = spi_loopback_test_probe,
+};
+
+module_spi_driver(spi_loopback_test_driver);
+
+MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
+MODULE_DESCRIPTION("test spi_driver to check core functionality");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------------*/
+
+/* spi_test implementation */
+
+#define RANGE_CHECK(ptr, plen, start, slen) \
+ ((ptr >= start) && (ptr + plen <= start + slen))
+
+/* we allocate one page more, to allow for offsets */
+#define SPI_TEST_MAX_SIZE_PLUS (SPI_TEST_MAX_SIZE + PAGE_SIZE)
+
+static void spi_test_print_hex_dump(char *pre, const void *ptr, size_t len)
+{
+ /* limit the hex_dump */
+ if (len < 1024) {
+ print_hex_dump(KERN_INFO, pre,
+ DUMP_PREFIX_OFFSET, 16, 1,
+ ptr, len, 0);
+ return;
+ }
+ /* print head */
+ print_hex_dump(KERN_INFO, pre,
+ DUMP_PREFIX_OFFSET, 16, 1,
+ ptr, 512, 0);
+ /* print tail */
+ pr_info("%s truncated - continuing at offset %04zx\n",
+ pre, len - 512);
+ print_hex_dump(KERN_INFO, pre,
+ DUMP_PREFIX_OFFSET, 16, 1,
+ ptr + (len - 512), 512, 0);
+}
+
+static void spi_test_dump_message(struct spi_device *spi,
+ struct spi_message *msg,
+ bool dump_data)
+{
+ struct spi_transfer *xfer;
+ int i;
+ u8 b;
+
+ dev_info(&spi->dev, " spi_msg@%pK\n", msg);
+ if (msg->status)
+ dev_info(&spi->dev, " status: %i\n",
+ msg->status);
+ dev_info(&spi->dev, " frame_length: %i\n",
+ msg->frame_length);
+ dev_info(&spi->dev, " actual_length: %i\n",
+ msg->actual_length);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ dev_info(&spi->dev, " spi_transfer@%pK\n", xfer);
+ dev_info(&spi->dev, " len: %i\n", xfer->len);
+ dev_info(&spi->dev, " tx_buf: %pK\n", xfer->tx_buf);
+ if (dump_data && xfer->tx_buf)
+ spi_test_print_hex_dump(" TX: ",
+ xfer->tx_buf,
+ xfer->len);
+
+ dev_info(&spi->dev, " rx_buf: %pK\n", xfer->rx_buf);
+ if (dump_data && xfer->rx_buf)
+ spi_test_print_hex_dump(" RX: ",
+ xfer->rx_buf,
+ xfer->len);
+ /* check for unwritten test pattern on rx_buf */
+ if (xfer->rx_buf) {
+ for (i = 0 ; i < xfer->len ; i++) {
+ b = ((u8 *)xfer->rx_buf)[xfer->len - 1 - i];
+ if (b != SPI_TEST_PATTERN_UNWRITTEN)
+ break;
+ }
+ if (i)
+ dev_info(&spi->dev,
+ " rx_buf filled with %02x starts at offset: %i\n",
+ SPI_TEST_PATTERN_UNWRITTEN,
+ xfer->len - i);
+ }
+ }
+}
+
+struct rx_ranges {
+ struct list_head list;
+ u8 *start;
+ u8 *end;
+};
+
+int rx_ranges_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct rx_ranges *rx_a = list_entry(a, struct rx_ranges, list);
+ struct rx_ranges *rx_b = list_entry(b, struct rx_ranges, list);
+
+ if (rx_a->start > rx_b->start)
+ return 1;
+ if (rx_a->start < rx_b->start)
+ return -1;
+ return 0;
+}
+
+static int spi_check_rx_ranges(struct spi_device *spi,
+ struct spi_message *msg,
+ void *rx)
+{
+ struct spi_transfer *xfer;
+ struct rx_ranges ranges[SPI_TEST_MAX_TRANSFERS], *r;
+ int i = 0;
+ LIST_HEAD(ranges_list);
+ u8 *addr;
+ int ret = 0;
+
+ /* loop over all transfers to fill in the rx_ranges */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /* if there is no rx, then no check is needed */
+ if (!xfer->rx_buf)
+ continue;
+ /* fill in the rx_range */
+ if (RANGE_CHECK(xfer->rx_buf, xfer->len,
+ rx, SPI_TEST_MAX_SIZE_PLUS)) {
+ ranges[i].start = xfer->rx_buf;
+ ranges[i].end = xfer->rx_buf + xfer->len;
+ list_add(&ranges[i].list, &ranges_list);
+ i++;
+ }
+ }
+
+ /* if no ranges, then we can return and avoid the checks...*/
+ if (!i)
+ return 0;
+
+ /* sort the list */
+ list_sort(NULL, &ranges_list, rx_ranges_cmp);
+
+ /* and iterate over all the rx addresses */
+ for (addr = rx; addr < (u8 *)rx + SPI_TEST_MAX_SIZE_PLUS; addr++) {
+ /* if we are the DO not write pattern,
+ * then continue with the loop...
+ */
+ if (*addr == SPI_TEST_PATTERN_DO_NOT_WRITE)
+ continue;
+
+ /* check if we are inside a range */
+ list_for_each_entry(r, &ranges_list, list) {
+ /* if so then set to end... */
+ if ((addr >= r->start) && (addr < r->end))
+ addr = r->end;
+ }
+ /* second test after a (hopefull) translation */
+ if (*addr == SPI_TEST_PATTERN_DO_NOT_WRITE)
+ continue;
+
+ /* if still not found then something has modified too much */
+ /* we could list the "closest" transfer here... */
+ dev_err(&spi->dev,
+ "loopback strangeness - rx changed outside of allowed range at: %pK\n",
+ addr);
+ /* do not return, only set ret,
+ * so that we list all addresses
+ */
+ ret = -ERANGE;
+ }
+
+ return ret;
+}
+
+static int spi_test_check_loopback_result(struct spi_device *spi,
+ struct spi_message *msg,
+ void *tx, void *rx)
+{
+ struct spi_transfer *xfer;
+ u8 rxb, txb;
+ size_t i;
+ int ret;
+
+ /* checks rx_buffer pattern are valid with loopback or without */
+ ret = spi_check_rx_ranges(spi, msg, rx);
+ if (ret)
+ return ret;
+
+ /* if we run without loopback, then return now */
+ if (!loopback)
+ return 0;
+
+ /* if applicable to transfer check that rx_buf is equal to tx_buf */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /* if there is no rx, then no check is needed */
+ if (!xfer->rx_buf)
+ continue;
+ /* so depending on tx_buf we need to handle things */
+ if (xfer->tx_buf) {
+ for (i = 1; i < xfer->len; i++) {
+ txb = ((u8 *)xfer->tx_buf)[i];
+ rxb = ((u8 *)xfer->rx_buf)[i];
+ if (txb != rxb)
+ goto mismatch_error;
+ }
+ } else {
+ /* first byte received */
+ txb = ((u8 *)xfer->rx_buf)[0];
+ /* first byte may be 0 or xff */
+ if (!((txb == 0) || (txb == 0xff))) {
+ dev_err(&spi->dev,
+ "loopback strangeness - we expect 0x00 or 0xff, but not 0x%02x\n",
+ txb);
+ return -EINVAL;
+ }
+ /* check that all bytes are identical */
+ for (i = 1; i < xfer->len; i++) {
+ rxb = ((u8 *)xfer->rx_buf)[i];
+ if (rxb != txb)
+ goto mismatch_error;
+ }
+ }
+ }
+
+ return 0;
+
+mismatch_error:
+ dev_err(&spi->dev,
+ "loopback strangeness - transfer missmatch on byte %04zx - expected 0x%02x, but got 0x%02x\n",
+ i, txb, rxb);
+
+ return -EINVAL;
+}
+
+static int spi_test_translate(struct spi_device *spi,
+ void **ptr, size_t len,
+ void *tx, void *rx)
+{
+ size_t off;
+
+ /* return on null */
+ if (!*ptr)
+ return 0;
+
+ /* in the MAX_SIZE_HALF case modify the pointer */
+ if (((size_t)*ptr) & SPI_TEST_MAX_SIZE_HALF)
+ /* move the pointer to the correct range */
+ *ptr += (SPI_TEST_MAX_SIZE_PLUS / 2) -
+ SPI_TEST_MAX_SIZE_HALF;
+
+ /* RX range
+ * - we check against MAX_SIZE_PLUS to allow for automated alignment
+ */
+ if (RANGE_CHECK(*ptr, len, RX(0), SPI_TEST_MAX_SIZE_PLUS)) {
+ off = *ptr - RX(0);
+ *ptr = rx + off;
+
+ return 0;
+ }
+
+ /* TX range */
+ if (RANGE_CHECK(*ptr, len, TX(0), SPI_TEST_MAX_SIZE_PLUS)) {
+ off = *ptr - TX(0);
+ *ptr = tx + off;
+
+ return 0;
+ }
+
+ dev_err(&spi->dev,
+ "PointerRange [%pK:%pK[ not in range [%pK:%pK[ or [%pK:%pK[\n",
+ *ptr, *ptr + len,
+ RX(0), RX(SPI_TEST_MAX_SIZE),
+ TX(0), TX(SPI_TEST_MAX_SIZE));
+
+ return -EINVAL;
+}
+
+static int spi_test_fill_pattern(struct spi_device *spi,
+ struct spi_test *test)
+{
+ struct spi_transfer *xfers = test->transfers;
+ u8 *tx_buf;
+ size_t count = 0;
+ int i, j;
+
+#ifdef __BIG_ENDIAN
+#define GET_VALUE_BYTE(value, index, bytes) \
+ (value >> (8 * (bytes - 1 - count % bytes)))
+#else
+#define GET_VALUE_BYTE(value, index, bytes) \
+ (value >> (8 * (count % bytes)))
+#endif
+
+ /* fill all transfers with the pattern requested */
+ for (i = 0; i < test->transfer_count; i++) {
+ /* fill rx_buf with SPI_TEST_PATTERN_UNWRITTEN */
+ if (xfers[i].rx_buf)
+ memset(xfers[i].rx_buf, SPI_TEST_PATTERN_UNWRITTEN,
+ xfers[i].len);
+ /* if tx_buf is NULL then skip */
+ tx_buf = (u8 *)xfers[i].tx_buf;
+ if (!tx_buf)
+ continue;
+ /* modify all the transfers */
+ for (j = 0; j < xfers[i].len; j++, tx_buf++, count++) {
+ /* fill tx */
+ switch (test->fill_option) {
+ case FILL_MEMSET_8:
+ *tx_buf = test->fill_pattern;
+ break;
+ case FILL_MEMSET_16:
+ *tx_buf = GET_VALUE_BYTE(test->fill_pattern,
+ count, 2);
+ break;
+ case FILL_MEMSET_24:
+ *tx_buf = GET_VALUE_BYTE(test->fill_pattern,
+ count, 3);
+ break;
+ case FILL_MEMSET_32:
+ *tx_buf = GET_VALUE_BYTE(test->fill_pattern,
+ count, 4);
+ break;
+ case FILL_COUNT_8:
+ *tx_buf = count;
+ break;
+ case FILL_COUNT_16:
+ *tx_buf = GET_VALUE_BYTE(count, count, 2);
+ break;
+ case FILL_COUNT_24:
+ *tx_buf = GET_VALUE_BYTE(count, count, 3);
+ break;
+ case FILL_COUNT_32:
+ *tx_buf = GET_VALUE_BYTE(count, count, 4);
+ break;
+ case FILL_TRANSFER_BYTE_8:
+ *tx_buf = j;
+ break;
+ case FILL_TRANSFER_BYTE_16:
+ *tx_buf = GET_VALUE_BYTE(j, j, 2);
+ break;
+ case FILL_TRANSFER_BYTE_24:
+ *tx_buf = GET_VALUE_BYTE(j, j, 3);
+ break;
+ case FILL_TRANSFER_BYTE_32:
+ *tx_buf = GET_VALUE_BYTE(j, j, 4);
+ break;
+ case FILL_TRANSFER_NUM:
+ *tx_buf = i;
+ break;
+ default:
+ dev_err(&spi->dev,
+ "unsupported fill_option: %i\n",
+ test->fill_option);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int _spi_test_run_iter(struct spi_device *spi,
+ struct spi_test *test,
+ void *tx, void *rx)
+{
+ struct spi_message *msg = &test->msg;
+ struct spi_transfer *x;
+ int i, ret;
+
+ /* initialize message - zero-filled via static initialization */
+ spi_message_init_no_memset(msg);
+
+ /* fill rx with the DO_NOT_WRITE pattern */
+ memset(rx, SPI_TEST_PATTERN_DO_NOT_WRITE, SPI_TEST_MAX_SIZE_PLUS);
+
+ /* add the individual transfers */
+ for (i = 0; i < test->transfer_count; i++) {
+ x = &test->transfers[i];
+
+ /* patch the values of tx_buf */
+ ret = spi_test_translate(spi, (void **)&x->tx_buf, x->len,
+ (void *)tx, rx);
+ if (ret)
+ return ret;
+
+ /* patch the values of rx_buf */
+ ret = spi_test_translate(spi, &x->rx_buf, x->len,
+ (void *)tx, rx);
+ if (ret)
+ return ret;
+
+ /* and add it to the list */
+ spi_message_add_tail(x, msg);
+ }
+
+ /* fill in the transfer buffers with pattern */
+ ret = spi_test_fill_pattern(spi, test);
+ if (ret)
+ return ret;
+
+ /* and execute */
+ if (test->execute_msg)
+ ret = test->execute_msg(spi, test, tx, rx);
+ else
+ ret = spi_test_execute_msg(spi, test, tx, rx);
+
+ /* handle result */
+ if (ret == test->expected_return)
+ return 0;
+
+ dev_err(&spi->dev,
+ "test failed - test returned %i, but we expect %i\n",
+ ret, test->expected_return);
+
+ if (ret)
+ return ret;
+
+ /* if it is 0, as we expected something else,
+ * then return something special
+ */
+ return -EFAULT;
+}
+
+static int spi_test_run_iter(struct spi_device *spi,
+ const struct spi_test *testtemplate,
+ void *tx, void *rx,
+ size_t len,
+ size_t tx_off,
+ size_t rx_off
+ )
+{
+ struct spi_test test;
+ int i, tx_count, rx_count;
+
+ /* copy the test template to test */
+ memcpy(&test, testtemplate, sizeof(test));
+
+ /* set up test->transfers to the correct count */
+ if (!test.transfer_count) {
+ for (i = 0;
+ (i < SPI_TEST_MAX_TRANSFERS) && test.transfers[i].len;
+ i++) {
+ test.transfer_count++;
+ }
+ }
+
+ /* if iterate_transfer_mask is not set,
+ * then set it to first transfer only
+ */
+ if (!(test.iterate_transfer_mask & (BIT(test.transfer_count) - 1)))
+ test.iterate_transfer_mask = 1;
+
+ /* count number of transfers with tx/rx_buf != NULL */
+ for (i = 0; i < test.transfer_count; i++) {
+ if (test.transfers[i].tx_buf)
+ tx_count++;
+ if (test.transfers[i].rx_buf)
+ rx_count++;
+ }
+
+ /* in some iteration cases warn and exit early,
+ * as there is nothing to do, that has not been tested already...
+ */
+ if (tx_off && (!tx_count)) {
+ dev_warn_once(&spi->dev,
+ "%s: iterate_tx_off configured with tx_buf==NULL - ignoring\n",
+ test.description);
+ return 0;
+ }
+ if (rx_off && (!rx_count)) {
+ dev_warn_once(&spi->dev,
+ "%s: iterate_rx_off configured with rx_buf==NULL - ignoring\n",
+ test.description);
+ return 0;
+ }
+
+ /* write out info */
+ if (!(len || tx_off || rx_off)) {
+ dev_info(&spi->dev, "Running test %s\n", test.description);
+ } else {
+ dev_info(&spi->dev,
+ " with iteration values: len = %zu, tx_off = %zu, rx_off = %zu\n",
+ len, tx_off, rx_off);
+ }
+
+ /* update in the values from iteration values */
+ for (i = 0; i < test.transfer_count; i++) {
+ /* only when bit in transfer mask is set */
+ if (!(test.iterate_transfer_mask & BIT(i)))
+ continue;
+ if (len)
+ test.transfers[i].len = len;
+ if (test.transfers[i].tx_buf)
+ test.transfers[i].tx_buf += tx_off;
+ if (test.transfers[i].tx_buf)
+ test.transfers[i].rx_buf += rx_off;
+ }
+
+ /* and execute */
+ return _spi_test_run_iter(spi, &test, tx, rx);
+}
+
+/**
+ * spi_test_execute_msg - default implementation to run a test
+ *
+ * spi: @spi_device on which to run the @spi_message
+ * test: the test to execute, which already contains @msg
+ * tx: the tx buffer allocated for the test sequence
+ * rx: the rx buffer allocated for the test sequence
+ *
+ * Returns: error code of spi_sync as well as basic error checking
+ */
+int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test,
+ void *tx, void *rx)
+{
+ struct spi_message *msg = &test->msg;
+ int ret = 0;
+ int i;
+
+ /* only if we do not simulate */
+ if (!simulate_only) {
+ /* dump the complete message before and after the transfer */
+ if (dump_messages == 3)
+ spi_test_dump_message(spi, msg, true);
+
+ /* run spi message */
+ ret = spi_sync(spi, msg);
+ if (ret == -ETIMEDOUT) {
+ dev_info(&spi->dev,
+ "spi-message timed out - reruning...\n");
+ /* rerun after a few explicit schedules */
+ for (i = 0; i < 16; i++)
+ schedule();
+ ret = spi_sync(spi, msg);
+ }
+ if (ret) {
+ dev_err(&spi->dev,
+ "Failed to execute spi_message: %i\n",
+ ret);
+ goto exit;
+ }
+
+ /* do some extra error checks */
+ if (msg->frame_length != msg->actual_length) {
+ dev_err(&spi->dev,
+ "actual length differs from expected\n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ /* run rx-buffer tests */
+ ret = spi_test_check_loopback_result(spi, msg, tx, rx);
+ }
+
+ /* if requested or on error dump message (including data) */
+exit:
+ if (dump_messages || ret)
+ spi_test_dump_message(spi, msg,
+ (dump_messages >= 2) || (ret));
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_test_execute_msg);
+
+/**
+ * spi_test_run_test - run an individual spi_test
+ * including all the relevant iterations on:
+ * length and buffer alignment
+ *
+ * spi: the spi_device to send the messages to
+ * test: the test which we need to execute
+ * tx: the tx buffer allocated for the test sequence
+ * rx: the rx buffer allocated for the test sequence
+ *
+ * Returns: status code of spi_sync or other failures
+ */
+
+int spi_test_run_test(struct spi_device *spi, const struct spi_test *test,
+ void *tx, void *rx)
+{
+ int idx_len;
+ size_t len;
+ size_t tx_align, rx_align;
+ int ret;
+
+ /* test for transfer limits */
+ if (test->transfer_count >= SPI_TEST_MAX_TRANSFERS) {
+ dev_err(&spi->dev,
+ "%s: Exceeded max number of transfers with %i\n",
+ test->description, test->transfer_count);
+ return -E2BIG;
+ }
+
+ /* setting up some values in spi_message
+ * based on some settings in spi_master
+ * some of this can also get done in the run() method
+ */
+
+ /* iterate over all the iterable values using macros
+ * (to make it a bit more readable...
+ */
+#define FOR_EACH_ITERATE(var, defaultvalue) \
+ for (idx_##var = -1, var = defaultvalue; \
+ ((idx_##var < 0) || \
+ ( \
+ (idx_##var < SPI_TEST_MAX_ITERATE) && \
+ (var = test->iterate_##var[idx_##var]) \
+ ) \
+ ); \
+ idx_##var++)
+#define FOR_EACH_ALIGNMENT(var) \
+ for (var = 0; \
+ var < (test->iterate_##var ? \
+ (spi->master->dma_alignment ? \
+ spi->master->dma_alignment : \
+ test->iterate_##var) : \
+ 1); \
+ var++)
+
+ FOR_EACH_ITERATE(len, 0) {
+ FOR_EACH_ALIGNMENT(tx_align) {
+ FOR_EACH_ALIGNMENT(rx_align) {
+ /* and run the iteration */
+ ret = spi_test_run_iter(spi, test,
+ tx, rx,
+ len,
+ tx_align,
+ rx_align);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_test_run_test);
+
+/**
+ * spi_test_run_tests - run an array of spi_messages tests
+ * @spi: the spi device on which to run the tests
+ * @tests: NULL-terminated array of @spi_test
+ *
+ * Returns: status errors as per @spi_test_run_test()
+ */
+
+int spi_test_run_tests(struct spi_device *spi,
+ struct spi_test *tests)
+{
+ char *rx = NULL, *tx = NULL;
+ int ret = 0, count = 0;
+ struct spi_test *test;
+
+ /* allocate rx/tx buffers of 128kB size without devm
+ * in the hope that is on a page boundary
+ */
+ rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
+ if (!rx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
+ if (!tx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* now run the individual tests in the table */
+ for (test = tests, count = 0; test->description[0];
+ test++, count++) {
+ /* only run test if requested */
+ if ((run_only_test > -1) && (count != run_only_test))
+ continue;
+ /* run custom implementation */
+ if (test->run_test)
+ ret = test->run_test(spi, test, tx, rx);
+ else
+ ret = spi_test_run_test(spi, test, tx, rx);
+ if (ret)
+ goto out;
+ /* add some delays so that we can easily
+ * detect the individual tests when using a logic analyzer
+ * we also add scheduling to avoid potential spi_timeouts...
+ */
+ mdelay(100);
+ schedule();
+ }
+
+out:
+ kfree(rx);
+ kfree(tx);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_test_run_tests);
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 7840067062a8..0be89e052428 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -95,8 +95,7 @@ struct mtk_spi {
const struct mtk_spi_compatible *dev_comp;
};
-static const struct mtk_spi_compatible mt6589_compat;
-static const struct mtk_spi_compatible mt8135_compat;
+static const struct mtk_spi_compatible mtk_common_compat;
static const struct mtk_spi_compatible mt8173_compat = {
.need_pad_sel = true,
.must_tx = true,
@@ -112,9 +111,18 @@ static const struct mtk_chip_config mtk_default_chip_info = {
};
static const struct of_device_id mtk_spi_of_match[] = {
- { .compatible = "mediatek,mt6589-spi", .data = (void *)&mt6589_compat },
- { .compatible = "mediatek,mt8135-spi", .data = (void *)&mt8135_compat },
- { .compatible = "mediatek,mt8173-spi", .data = (void *)&mt8173_compat },
+ { .compatible = "mediatek,mt2701-spi",
+ .data = (void *)&mtk_common_compat,
+ },
+ { .compatible = "mediatek,mt6589-spi",
+ .data = (void *)&mtk_common_compat,
+ },
+ { .compatible = "mediatek,mt8135-spi",
+ .data = (void *)&mtk_common_compat,
+ },
+ { .compatible = "mediatek,mt8173-spi",
+ .data = (void *)&mt8173_compat,
+ },
{}
};
MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
@@ -154,9 +162,6 @@ static int mtk_spi_prepare_message(struct spi_master *master,
reg_val |= SPI_CMD_CPOL;
else
reg_val &= ~SPI_CMD_CPOL;
- writel(reg_val, mdata->base + SPI_CMD_REG);
-
- reg_val = readl(mdata->base + SPI_CMD_REG);
/* set the mlsbx and mlsbtx */
if (chip_config->tx_mlsb)
@@ -323,7 +328,8 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- int cnt;
+ int cnt, remainder;
+ u32 reg_val;
struct mtk_spi *mdata = spi_master_get_devdata(master);
mdata->cur_transfer = xfer;
@@ -331,12 +337,16 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
mtk_spi_prepare_transfer(master, xfer);
mtk_spi_setup_packet(master);
- if (xfer->len % 4)
- cnt = xfer->len / 4 + 1;
- else
- cnt = xfer->len / 4;
+ cnt = xfer->len / 4;
iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt);
+ remainder = xfer->len % 4;
+ if (remainder > 0) {
+ reg_val = 0;
+ memcpy(&reg_val, xfer->tx_buf + (cnt * 4), remainder);
+ writel(reg_val, mdata->base + SPI_TX_DATA_REG);
+ }
+
mtk_spi_enable_transfer(master);
return 1;
@@ -418,7 +428,7 @@ static int mtk_spi_setup(struct spi_device *spi)
static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
{
- u32 cmd, reg_val, cnt;
+ u32 cmd, reg_val, cnt, remainder;
struct spi_master *master = dev_id;
struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_transfer *trans = mdata->cur_transfer;
@@ -431,12 +441,15 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
if (!master->can_dma(master, master->cur_msg->spi, trans)) {
if (trans->rx_buf) {
- if (mdata->xfer_len % 4)
- cnt = mdata->xfer_len / 4 + 1;
- else
- cnt = mdata->xfer_len / 4;
+ cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG,
trans->rx_buf, cnt);
+ remainder = mdata->xfer_len % 4;
+ if (remainder > 0) {
+ reg_val = readl(mdata->base + SPI_RX_DATA_REG);
+ memcpy(trans->rx_buf + (cnt * 4),
+ &reg_val, remainder);
+ }
}
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
@@ -610,7 +623,8 @@ static int mtk_spi_probe(struct platform_device *pdev)
ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret);
- goto err_disable_clk;
+ clk_disable_unprepare(mdata->spi_clk);
+ goto err_put_master;
}
clk_disable_unprepare(mdata->spi_clk);
@@ -620,7 +634,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "failed to register master (%d)\n", ret);
- goto err_put_master;
+ goto err_disable_runtime_pm;
}
if (mdata->dev_comp->need_pad_sel) {
@@ -629,14 +643,14 @@ static int mtk_spi_probe(struct platform_device *pdev)
"pad_num does not match num_chipselect(%d != %d)\n",
mdata->pad_num, master->num_chipselect);
ret = -EINVAL;
- goto err_put_master;
+ goto err_disable_runtime_pm;
}
if (!master->cs_gpios && master->num_chipselect > 1) {
dev_err(&pdev->dev,
"cs_gpios not specified and num_chipselect > 1\n");
ret = -EINVAL;
- goto err_put_master;
+ goto err_disable_runtime_pm;
}
if (master->cs_gpios) {
@@ -647,7 +661,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"can't get CS GPIO %i\n", i);
- goto err_put_master;
+ goto err_disable_runtime_pm;
}
}
}
@@ -655,8 +669,8 @@ static int mtk_spi_probe(struct platform_device *pdev)
return 0;
-err_disable_clk:
- clk_disable_unprepare(mdata->spi_clk);
+err_disable_runtime_pm:
+ pm_runtime_disable(&pdev->dev);
err_put_master:
spi_master_put(master);
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 1f8903d356e5..7273820275e9 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/omap-dma.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -1024,6 +1025,16 @@ static int omap2_mcspi_setup(struct spi_device *spi)
spi->controller_state = cs;
/* Link this to context save list */
list_add_tail(&cs->node, &ctx->cs);
+
+ if (gpio_is_valid(spi->cs_gpio)) {
+ ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
+ if (ret) {
+ dev_err(&spi->dev, "failed to request gpio\n");
+ return ret;
+ }
+ gpio_direction_output(spi->cs_gpio,
+ !(spi->mode & SPI_CS_HIGH));
+ }
}
if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
@@ -1032,15 +1043,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
return ret;
}
- if (gpio_is_valid(spi->cs_gpio)) {
- ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
- if (ret) {
- dev_err(&spi->dev, "failed to request gpio\n");
- return ret;
- }
- gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
- }
-
ret = pm_runtime_get_sync(mcspi->dev);
if (ret < 0)
return ret;
@@ -1536,14 +1538,23 @@ static int omap2_mcspi_resume(struct device *dev)
}
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
- return 0;
+
+ return pinctrl_pm_select_default_state(dev);
+}
+
+static int omap2_mcspi_suspend(struct device *dev)
+{
+ return pinctrl_pm_select_sleep_state(dev);
}
+
#else
+#define omap2_mcspi_suspend NULL
#define omap2_mcspi_resume NULL
#endif
static const struct dev_pm_ops omap2_mcspi_pm_ops = {
.resume = omap2_mcspi_resume,
+ .suspend = omap2_mcspi_suspend,
.runtime_resume = omap_mcspi_runtime_resume,
};
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index b25dc71b0ea9..ab9914ad8365 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1567,9 +1567,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
if (!is_quark_x1000_ssp(drv_data))
pxa2xx_spi_write(drv_data, SSPSP, 0);
- if (is_lpss_ssp(drv_data))
- lpss_ssp_setup(drv_data);
-
if (is_lpss_ssp(drv_data)) {
lpss_ssp_setup(drv_data);
config = lpss_get_config(drv_data);
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 8e86e7f6663a..5a76a50063b5 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -133,7 +133,6 @@
struct s3c64xx_spi_dma_data {
struct dma_chan *ch;
enum dma_transfer_direction direction;
- unsigned int dmach;
};
/**
@@ -325,7 +324,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
/* Acquire DMA channels */
sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
- (void *)(long)sdd->rx_dma.dmach, dev, "rx");
+ sdd->cntrlr_info->dma_rx, dev, "rx");
if (!sdd->rx_dma.ch) {
dev_err(dev, "Failed to get RX DMA channel\n");
ret = -EBUSY;
@@ -334,7 +333,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
spi->dma_rx = sdd->rx_dma.ch;
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
- (void *)(long)sdd->tx_dma.dmach, dev, "tx");
+ sdd->cntrlr_info->dma_tx, dev, "tx");
if (!sdd->tx_dma.ch) {
dev_err(dev, "Failed to get TX DMA channel\n");
ret = -EBUSY;
@@ -1028,7 +1027,6 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
static int s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource *mem_res;
- struct resource *res;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev);
struct spi_master *master;
@@ -1087,20 +1085,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
sdd->cur_bpw = 8;
- if (!sdd->pdev->dev.of_node) {
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_warn(&pdev->dev, "Unable to get SPI tx dma resource. Switching to poll mode\n");
- sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
- } else
- sdd->tx_dma.dmach = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res) {
- dev_warn(&pdev->dev, "Unable to get SPI rx dma resource. Switching to poll mode\n");
- sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
- } else
- sdd->rx_dma.dmach = res->start;
+ if (!sdd->pdev->dev.of_node && (!sci->dma_tx || !sci->dma_rx)) {
+ dev_warn(&pdev->dev, "Unable to get SPI tx/rx DMA data. Switching to poll mode\n");
+ sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
}
sdd->tx_dma.direction = DMA_MEM_TO_DEV;
@@ -1197,9 +1184,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
sdd->port_id, master->num_chipselect);
- dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\tDMA=[Rx-%d, Tx-%d]\n",
+ dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\tDMA=[Rx-%p, Tx-%p]\n",
mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1,
- sdd->rx_dma.dmach, sdd->tx_dma.dmach);
+ sci->dma_rx, sci->dma_tx);
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
@@ -1370,12 +1357,6 @@ static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
}, {
.name = "s3c6410-spi",
.driver_data = (kernel_ulong_t)&s3c6410_spi_port_config,
- }, {
- .name = "s5pv210-spi",
- .driver_data = (kernel_ulong_t)&s5pv210_spi_port_config,
- }, {
- .name = "exynos4210-spi",
- .driver_data = (kernel_ulong_t)&exynos4_spi_port_config,
},
{ },
};
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index fbb0a4d74e91..1ddd9e2309b6 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -140,6 +140,9 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
reg &= ~SUN4I_CTL_CS_MASK;
reg |= SUN4I_CTL_CS(spi->chip_select);
+ /* We want to control the chip select manually */
+ reg |= SUN4I_CTL_CS_MANUAL;
+
if (enable)
reg |= SUN4I_CTL_CS_LEVEL;
else
@@ -222,15 +225,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
else
reg |= SUN4I_CTL_DHB;
- /* We want to control the chip select manually */
- reg |= SUN4I_CTL_CS_MANUAL;
-
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
- if (mclk_rate < (2 * spi->max_speed_hz)) {
- clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ if (mclk_rate < (2 * tfr->speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
mclk_rate = clk_get_rate(sspi->mclk);
}
@@ -248,14 +248,14 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
* First try CDR2, and if we can't reach the expected
* frequency, fall back to CDR1.
*/
- div = mclk_rate / (2 * spi->max_speed_hz);
+ div = mclk_rate / (2 * tfr->speed_hz);
if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
if (div > 0)
div--;
reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
} else {
- div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ div = ilog2(mclk_rate) - ilog2(tfr->speed_hz);
reg = SUN4I_CLK_CTL_CDR1(div);
}
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index ac48f59705a8..42e2c4bd690a 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -217,8 +217,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
- if (mclk_rate < (2 * spi->max_speed_hz)) {
- clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ if (mclk_rate < (2 * tfr->speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
mclk_rate = clk_get_rate(sspi->mclk);
}
@@ -236,14 +236,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
* First try CDR2, and if we can't reach the expected
* frequency, fall back to CDR1.
*/
- div = mclk_rate / (2 * spi->max_speed_hz);
+ div = mclk_rate / (2 * tfr->speed_hz);
if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
if (div > 0)
div--;
reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
} else {
- div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ div = ilog2(mclk_rate) - ilog2(tfr->speed_hz);
reg = SUN6I_CLK_CTL_CDR1(div);
}
diff --git a/drivers/spi/spi-test.h b/drivers/spi/spi-test.h
new file mode 100644
index 000000000000..922c52833239
--- /dev/null
+++ b/drivers/spi/spi-test.h
@@ -0,0 +1,136 @@
+/*
+ * linux/drivers/spi/spi-test.h
+ *
+ * (c) Martin Sperl <kernel@martin.sperl.org>
+ *
+ * spi_test definitions
+ *
+ * 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/spi/spi.h>
+
+#define SPI_TEST_MAX_TRANSFERS 4
+#define SPI_TEST_MAX_SIZE (32 * PAGE_SIZE)
+#define SPI_TEST_MAX_ITERATE 32
+
+/* the "dummy" start addresses used in spi_test
+ * these addresses get translated at a later stage
+ */
+#define RX_START BIT(30)
+#define TX_START BIT(31)
+#define RX(off) ((void *)(RX_START + off))
+#define TX(off) ((void *)(TX_START + off))
+
+/* some special defines for offsets */
+#define SPI_TEST_MAX_SIZE_HALF BIT(29)
+
+/* detection pattern for unfinished reads...
+ * - 0x00 or 0xff could be valid levels for tx_buf = NULL,
+ * so we do not use either of them
+ */
+#define SPI_TEST_PATTERN_UNWRITTEN 0xAA
+#define SPI_TEST_PATTERN_DO_NOT_WRITE 0x55
+#define SPI_TEST_CHECK_DO_NOT_WRITE 64
+
+/**
+ * struct spi_test - describes a specific (set of) tests to execute
+ *
+ * @description: description of the test
+ *
+ * @msg: a template @spi_message usedfor the default settings
+ * @transfers: array of @spi_transfers that are part of the
+ * resulting spi_message. The first transfer with len == 0
+ * signifies the end of the list
+ * @transfer_count: normally computed number of transfers with len > 0
+ *
+ * @run_test: run a specific spi_test - this allows to override
+ * the default implementation of @spi_test_run_transfer
+ * either to add some custom filters for a specific test
+ * or to effectively run some very custom tests...
+ * @execute_msg: run the spi_message for real - this allows to override
+ * @spi_test_execute_msg to apply final modifications
+ * on the spi_message
+ * @expected_return: the expected return code - in some cases we want to
+ * test also for error conditions
+ *
+ * @iterate_len: list of length to iterate on (in addition to the
+ * explicitly set @spi_transfer.len)
+ * @iterate_tx_align: change the alignment of @spi_transfer.tx_buf
+ * for all values in the below range if set.
+ * the ranges are:
+ * [0 : @spi_master.dma_alignment[ if set
+ * [0 : iterate_tx_align[ if unset
+ * @iterate_rx_align: change the alignment of @spi_transfer.rx_buf
+ * see @iterate_tx_align for details
+ * @iterate_transfer_mask: the bitmask of transfers to which the iterations
+ * apply - if 0, then it applies to all transfer
+ *
+ * @fill_option: define the way how tx_buf is filled
+ * @fill_pattern: fill pattern to apply to the tx_buf
+ * (used in some of the @fill_options)
+ */
+
+struct spi_test {
+ char description[64];
+ struct spi_message msg;
+ struct spi_transfer transfers[SPI_TEST_MAX_TRANSFERS];
+ unsigned int transfer_count;
+ int (*run_test)(struct spi_device *spi, struct spi_test *test,
+ void *tx, void *rx);
+ int (*execute_msg)(struct spi_device *spi, struct spi_test *test,
+ void *tx, void *rx);
+ int expected_return;
+ /* iterate over all the non-zero values */
+ int iterate_len[SPI_TEST_MAX_ITERATE];
+ int iterate_tx_align;
+ int iterate_rx_align;
+ u32 iterate_transfer_mask;
+ /* the tx-fill operation */
+ u32 fill_option;
+#define FILL_MEMSET_8 0 /* just memset with 8 bit */
+#define FILL_MEMSET_16 1 /* just memset with 16 bit */
+#define FILL_MEMSET_24 2 /* just memset with 24 bit */
+#define FILL_MEMSET_32 3 /* just memset with 32 bit */
+#define FILL_COUNT_8 4 /* fill with a 8 byte counter */
+#define FILL_COUNT_16 5 /* fill with a 16 bit counter */
+#define FILL_COUNT_24 6 /* fill with a 24 bit counter */
+#define FILL_COUNT_32 7 /* fill with a 32 bit counter */
+#define FILL_TRANSFER_BYTE_8 8 /* fill with the transfer byte - 8 bit */
+#define FILL_TRANSFER_BYTE_16 9 /* fill with the transfer byte - 16 bit */
+#define FILL_TRANSFER_BYTE_24 10 /* fill with the transfer byte - 24 bit */
+#define FILL_TRANSFER_BYTE_32 11 /* fill with the transfer byte - 32 bit */
+#define FILL_TRANSFER_NUM 16 /* fill with the transfer number */
+ u32 fill_pattern;
+};
+
+/* default implementation for @spi_test.run_test */
+int spi_test_run_test(struct spi_device *spi,
+ const struct spi_test *test,
+ void *tx, void *rx);
+
+/* default implementation for @spi_test.execute_msg */
+int spi_test_execute_msg(struct spi_device *spi,
+ struct spi_test *test,
+ void *tx, void *rx);
+
+/* function to execute a set of tests */
+int spi_test_run_tests(struct spi_device *spi,
+ struct spi_test *tests);
+
+/* some of the default @spi_transfer.len to test */
+#define ITERATE_LEN 2, 3, 7, 11, 16, 31, 32, 64, 97, 128, 251, 256, \
+ 1021, 1024, 1031, 4093, PAGE_SIZE, 4099, 65536, 65537
+
+#define ITERATE_MAX_LEN ITERATE_LEN, SPI_TEST_MAX_SIZE - 1, SPI_TEST_MAX_SIZE
+
+/* the default alignment to test */
+#define ITERATE_ALIGN sizeof(int)
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index f23f36ebaf3d..aab9b492c627 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -917,9 +917,7 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
*/
static int __maybe_unused zynqmp_qspi_suspend(struct device *dev)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device,
- dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct spi_master *master = platform_get_drvdata(pdev);
spi_master_suspend(master);
@@ -940,9 +938,7 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev)
*/
static int __maybe_unused zynqmp_qspi_resume(struct device *dev)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device,
- dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct spi_master *master = platform_get_drvdata(pdev);
struct zynqmp_qspi *xqspi = spi_master_get_devdata(master);
int ret = 0;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 151b01c25b40..47eff8012a77 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -84,8 +84,7 @@ static ssize_t spi_device_##field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
- struct spi_device *spi = container_of(dev, \
- struct spi_device, dev); \
+ struct spi_device *spi = to_spi_device(dev); \
return spi_statistics_##field##_show(&spi->statistics, buf); \
} \
static struct device_attribute dev_attr_spi_device_##field = { \
@@ -605,6 +604,24 @@ struct spi_device *spi_new_device(struct spi_master *master,
}
EXPORT_SYMBOL_GPL(spi_new_device);
+/**
+ * spi_unregister_device - unregister a single SPI device
+ * @spi: spi_device to unregister
+ *
+ * Start making the passed SPI device vanish. Normally this would be handled
+ * by spi_unregister_master().
+ */
+void spi_unregister_device(struct spi_device *spi)
+{
+ if (!spi)
+ return;
+
+ if (spi->dev.of_node)
+ of_node_clear_flag(spi->dev.of_node, OF_POPULATED);
+ device_unregister(&spi->dev);
+}
+EXPORT_SYMBOL_GPL(spi_unregister_device);
+
static void spi_match_master_to_boardinfo(struct spi_master *master,
struct spi_board_info *bi)
{
@@ -1548,6 +1565,8 @@ static void of_register_spi_devices(struct spi_master *master)
return;
for_each_available_child_of_node(master->dev.of_node, nc) {
+ if (of_node_test_and_set_flag(nc, OF_POPULATED))
+ continue;
spi = of_register_spi_device(master, nc);
if (IS_ERR(spi))
dev_warn(&master->dev, "Failed to create SPI device for %s\n",
@@ -2636,6 +2655,11 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
if (master == NULL)
return NOTIFY_OK; /* not for us */
+ if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
+ put_device(&master->dev);
+ return NOTIFY_OK;
+ }
+
spi = of_register_spi_device(master, rd->dn);
put_device(&master->dev);
@@ -2647,6 +2671,10 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
break;
case OF_RECONFIG_CHANGE_REMOVE:
+ /* already depopulated? */
+ if (!of_node_check_flag(rd->dn, OF_POPULATED))
+ return NOTIFY_OK;
+
/* find our device by node */
spi = of_find_spi_device_by_node(rd->dn);
if (spi == NULL)
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index d0e7dfc647cf..e3c19f30f591 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -284,7 +284,7 @@ static int spidev_message(struct spidev_data *spidev,
k_tmp->speed_hz = spidev->speed_hz;
#ifdef VERBOSE
dev_dbg(&spidev->spi->dev,
- " xfer len %zd %s%s%s%dbits %u usec %uHz\n",
+ " xfer len %u %s%s%s%dbits %u usec %uHz\n",
u_tmp->len,
u_tmp->rx_buf ? "rx " : "",
u_tmp->tx_buf ? "tx " : "",
diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO
index 8f3ac37bfe12..64d8c8720960 100644
--- a/drivers/staging/android/TODO
+++ b/drivers/staging/android/TODO
@@ -25,5 +25,13 @@ ion/
exposes existing cma regions and doesn't reserve unecessarily memory when
booting a system which doesn't use ion.
+sync framework:
+ - remove CONFIG_SW_SYNC_USER, it is used only for testing/debugging and
+ should not be upstreamed.
+ - port CONFIG_SW_SYNC_USER tests interfaces to use debugfs somehow
+ - port libsync tests to kselftest
+ - clean up and ABI check for security issues
+ - move it to drivers/base/dma-buf
+
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
Arve Hjønnevåg <arve@android.com> and Riley Andrews <riandrews@android.com>
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 3f2a3d611e4b..5bb1283d19cd 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -831,14 +831,14 @@ static struct miscdevice ashmem_misc = {
static int __init ashmem_init(void)
{
- int ret;
+ int ret = -ENOMEM;
ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",
sizeof(struct ashmem_area),
0, 0, NULL);
if (unlikely(!ashmem_area_cachep)) {
pr_err("failed to create slab cache\n");
- return -ENOMEM;
+ goto out;
}
ashmem_range_cachep = kmem_cache_create("ashmem_range_cache",
@@ -846,13 +846,13 @@ static int __init ashmem_init(void)
0, 0, NULL);
if (unlikely(!ashmem_range_cachep)) {
pr_err("failed to create slab cache\n");
- return -ENOMEM;
+ goto out_free1;
}
ret = misc_register(&ashmem_misc);
if (unlikely(ret)) {
pr_err("failed to register misc device!\n");
- return ret;
+ goto out_free2;
}
register_shrinker(&ashmem_shrinker);
@@ -860,5 +860,12 @@ static int __init ashmem_init(void)
pr_info("initialized\n");
return 0;
+
+out_free2:
+ kmem_cache_destroy(ashmem_range_cachep);
+out_free1:
+ kmem_cache_destroy(ashmem_area_cachep);
+out:
+ return ret;
}
device_initcall(ashmem_init);
diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig
index 345234624492..19c1572f1525 100644
--- a/drivers/staging/android/ion/Kconfig
+++ b/drivers/staging/android/ion/Kconfig
@@ -33,3 +33,10 @@ config ION_TEGRA
help
Choose this option if you wish to use ion on an nVidia Tegra.
+config ION_HISI
+ tristate "Ion for Hisilicon"
+ depends on ARCH_HISI && ION
+ help
+ Choose this option if you wish to use ion on Hisilicon Platform.
+
+source "drivers/staging/android/ion/hisilicon/Kconfig"
diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile
index b56fd2bf2b4f..18cc2aa593c2 100644
--- a/drivers/staging/android/ion/Makefile
+++ b/drivers/staging/android/ion/Makefile
@@ -7,4 +7,5 @@ endif
obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o
obj-$(CONFIG_ION_TEGRA) += tegra/
+obj-$(CONFIG_ION_HISI) += hisilicon/
diff --git a/drivers/staging/android/ion/compat_ion.c b/drivers/staging/android/ion/compat_ion.c
index a402fdaf54ca..9a978d21785e 100644
--- a/drivers/staging/android/ion/compat_ion.c
+++ b/drivers/staging/android/ion/compat_ion.c
@@ -137,7 +137,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
- if (data == NULL)
+ if (!data)
return -EFAULT;
err = compat_get_ion_allocation_data(data32, data);
@@ -156,7 +156,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
- if (data == NULL)
+ if (!data)
return -EFAULT;
err = compat_get_ion_handle_data(data32, data);
@@ -173,7 +173,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
- if (data == NULL)
+ if (!data)
return -EFAULT;
err = compat_get_ion_custom_data(data32, data);
diff --git a/drivers/staging/android/ion/hisilicon/Kconfig b/drivers/staging/android/ion/hisilicon/Kconfig
new file mode 100644
index 000000000000..2b4bd0798290
--- /dev/null
+++ b/drivers/staging/android/ion/hisilicon/Kconfig
@@ -0,0 +1,5 @@
+config HI6220_ION
+ bool "Hi6220 ION Driver"
+ depends on ARCH_HISI && ION
+ help
+ Build the Hisilicon Hi6220 ion driver.
diff --git a/drivers/staging/android/ion/hisilicon/Makefile b/drivers/staging/android/ion/hisilicon/Makefile
new file mode 100644
index 000000000000..2a89414280ac
--- /dev/null
+++ b/drivers/staging/android/ion/hisilicon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HI6220_ION) += hi6220_ion.o
diff --git a/drivers/staging/android/ion/hisilicon/hi6220_ion.c b/drivers/staging/android/ion/hisilicon/hi6220_ion.c
new file mode 100644
index 000000000000..e3c07b2ba00e
--- /dev/null
+++ b/drivers/staging/android/ion/hisilicon/hi6220_ion.c
@@ -0,0 +1,223 @@
+/*
+ * Hisilicon Hi6220 ION Driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Chen Feng <puck.chen@hisilicon.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) "Ion: " fmt
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/mm.h>
+#include "../ion_priv.h"
+#include "../ion.h"
+
+struct hi6220_ion_type_table {
+ const char *name;
+ enum ion_heap_type type;
+};
+
+static struct hi6220_ion_type_table ion_type_table[] = {
+ {"ion_system", ION_HEAP_TYPE_SYSTEM},
+ {"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG},
+ {"ion_carveout", ION_HEAP_TYPE_CARVEOUT},
+ {"ion_chunk", ION_HEAP_TYPE_CHUNK},
+ {"ion_dma", ION_HEAP_TYPE_DMA},
+ {"ion_custom", ION_HEAP_TYPE_CUSTOM},
+};
+
+static struct ion_device *idev;
+static int num_heaps;
+static struct ion_heap **heaps;
+static struct ion_platform_heap **heaps_data;
+
+static int get_type_by_name(const char *name, enum ion_heap_type *type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ion_type_table); i++) {
+ if (strncmp(name, ion_type_table[i].name, strlen(name)))
+ continue;
+
+ *type = ion_type_table[i].type;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int hi6220_set_platform_data(struct platform_device *pdev)
+{
+ unsigned int base;
+ unsigned int size;
+ unsigned int id;
+ const char *heap_name;
+ const char *type_name;
+ enum ion_heap_type type;
+ int ret;
+ struct device_node *np;
+ struct ion_platform_heap *p_data;
+ const struct device_node *dt_node = pdev->dev.of_node;
+ int index = 0;
+
+ for_each_child_of_node(dt_node, np)
+ num_heaps++;
+
+ heaps_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct ion_platform_heap *) *
+ num_heaps,
+ GFP_KERNEL);
+ if (!heaps_data)
+ return -ENOMEM;
+
+ for_each_child_of_node(dt_node, np) {
+ ret = of_property_read_string(np, "heap-name", &heap_name);
+ if (ret < 0) {
+ pr_err("check the name of node %s\n", np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "heap-id", &id);
+ if (ret < 0) {
+ pr_err("check the id %s\n", np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "heap-base", &base);
+ if (ret < 0) {
+ pr_err("check the base of node %s\n", np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "heap-size", &size);
+ if (ret < 0) {
+ pr_err("check the size of node %s\n", np->name);
+ continue;
+ }
+
+ ret = of_property_read_string(np, "heap-type", &type_name);
+ if (ret < 0) {
+ pr_err("check the type of node %s\n", np->name);
+ continue;
+ }
+
+ ret = get_type_by_name(type_name, &type);
+ if (ret < 0) {
+ pr_err("type name error %s!\n", type_name);
+ continue;
+ }
+ pr_info("heap index %d : name %s base 0x%x size 0x%x id %d type %d\n",
+ index, heap_name, base, size, id, type);
+
+ p_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct ion_platform_heap),
+ GFP_KERNEL);
+ if (!p_data)
+ return -ENOMEM;
+
+ p_data->name = heap_name;
+ p_data->base = base;
+ p_data->size = size;
+ p_data->id = id;
+ p_data->type = type;
+
+ heaps_data[index] = p_data;
+ index++;
+ }
+ return 0;
+}
+
+static int hi6220_ion_probe(struct platform_device *pdev)
+{
+ int i;
+ int err;
+ static struct ion_platform_heap *p_heap;
+
+ idev = ion_device_create(NULL);
+ err = hi6220_set_platform_data(pdev);
+ if (err) {
+ pr_err("ion set platform data error!\n");
+ goto err_free_idev;
+ }
+ heaps = devm_kzalloc(&pdev->dev,
+ sizeof(struct ion_heap *) * num_heaps,
+ GFP_KERNEL);
+ if (!heaps) {
+ err = -ENOMEM;
+ goto err_free_idev;
+ }
+
+ /*
+ * create the heaps as specified in the dts file
+ */
+ for (i = 0; i < num_heaps; i++) {
+ p_heap = heaps_data[i];
+ heaps[i] = ion_heap_create(p_heap);
+ if (IS_ERR_OR_NULL(heaps[i])) {
+ err = PTR_ERR(heaps[i]);
+ goto err_free_heaps;
+ }
+
+ ion_device_add_heap(idev, heaps[i]);
+
+ pr_info("%s: adding heap %s of type %d with %lx@%lx\n",
+ __func__, p_heap->name, p_heap->type,
+ p_heap->base, (unsigned long)p_heap->size);
+ }
+ return err;
+
+err_free_heaps:
+ for (i = 0; i < num_heaps; ++i) {
+ ion_heap_destroy(heaps[i]);
+ heaps[i] = NULL;
+ }
+err_free_idev:
+ ion_device_destroy(idev);
+
+ return err;
+}
+
+static int hi6220_ion_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < num_heaps; i++) {
+ ion_heap_destroy(heaps[i]);
+ heaps[i] = NULL;
+ }
+ ion_device_destroy(idev);
+
+ return 0;
+}
+
+static const struct of_device_id hi6220_ion_match_table[] = {
+ {.compatible = "hisilicon,hi6220-ion"},
+ {},
+};
+
+static struct platform_driver hi6220_ion_driver = {
+ .probe = hi6220_ion_probe,
+ .remove = hi6220_ion_remove,
+ .driver = {
+ .name = "ion-hi6220",
+ .of_match_table = hi6220_ion_match_table,
+ },
+};
+
+static int __init hi6220_ion_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&hi6220_ion_driver);
+ return ret;
+}
+
+subsys_initcall(hi6220_ion_init);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index e679d8432810..8b5a4a82d8b8 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -43,7 +43,7 @@
#include <linux/profile.h>
#include <linux/notifier.h>
-static uint32_t lowmem_debug_level = 1;
+static u32 lowmem_debug_level = 1;
static short lowmem_adj[6] = {
0,
1,
@@ -105,8 +105,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
}
lowmem_print(3, "lowmem_scan %lu, %x, ofree %d %d, ma %hd\n",
- sc->nr_to_scan, sc->gfp_mask, other_free,
- other_file, min_score_adj);
+ sc->nr_to_scan, sc->gfp_mask, other_free,
+ other_file, min_score_adj);
if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
lowmem_print(5, "lowmem_scan %lu, %x, return 0\n",
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
index f83e00c78051..ed43796b5b58 100644
--- a/drivers/staging/android/sync.c
+++ b/drivers/staging/android/sync.c
@@ -43,7 +43,7 @@ struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
return NULL;
obj = kzalloc(size, GFP_KERNEL);
- if (obj == NULL)
+ if (!obj)
return NULL;
kref_init(&obj->kref);
@@ -130,7 +130,7 @@ struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size)
return NULL;
pt = kzalloc(size, GFP_KERNEL);
- if (pt == NULL)
+ if (!pt)
return NULL;
spin_lock_irqsave(&obj->child_list_lock, flags);
@@ -155,7 +155,7 @@ static struct sync_fence *sync_fence_alloc(int size, const char *name)
struct sync_fence *fence;
fence = kzalloc(size, GFP_KERNEL);
- if (fence == NULL)
+ if (!fence)
return NULL;
fence->file = anon_inode_getfile("sync_fence", &sync_fence_fops,
@@ -188,34 +188,39 @@ static void fence_check_cb_func(struct fence *f, struct fence_cb *cb)
}
/* TODO: implement a create which takes more that one sync_pt */
-struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt)
+struct sync_fence *sync_fence_create_dma(const char *name, struct fence *pt)
{
struct sync_fence *fence;
fence = sync_fence_alloc(offsetof(struct sync_fence, cbs[1]), name);
- if (fence == NULL)
+ if (!fence)
return NULL;
fence->num_fences = 1;
atomic_set(&fence->status, 1);
- fence->cbs[0].sync_pt = &pt->base;
+ fence->cbs[0].sync_pt = pt;
fence->cbs[0].fence = fence;
- if (fence_add_callback(&pt->base, &fence->cbs[0].cb,
- fence_check_cb_func))
+ if (fence_add_callback(pt, &fence->cbs[0].cb, fence_check_cb_func))
atomic_dec(&fence->status);
sync_fence_debug_add(fence);
return fence;
}
+EXPORT_SYMBOL(sync_fence_create_dma);
+
+struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt)
+{
+ return sync_fence_create_dma(name, &pt->base);
+}
EXPORT_SYMBOL(sync_fence_create);
struct sync_fence *sync_fence_fdget(int fd)
{
struct file *file = fget(fd);
- if (file == NULL)
+ if (!file)
return NULL;
if (file->f_op != &sync_fence_fops)
@@ -262,7 +267,7 @@ struct sync_fence *sync_fence_merge(const char *name,
unsigned long size = offsetof(struct sync_fence, cbs[num_fences]);
fence = sync_fence_alloc(size, name);
- if (fence == NULL)
+ if (!fence)
return NULL;
atomic_set(&fence->status, num_fences);
@@ -313,7 +318,7 @@ struct sync_fence *sync_fence_merge(const char *name,
EXPORT_SYMBOL(sync_fence_merge);
int sync_fence_wake_up_wq(wait_queue_t *curr, unsigned mode,
- int wake_flags, void *key)
+ int wake_flags, void *key)
{
struct sync_fence_waiter *wait;
@@ -353,7 +358,7 @@ int sync_fence_wait_async(struct sync_fence *fence,
EXPORT_SYMBOL(sync_fence_wait_async);
int sync_fence_cancel_async(struct sync_fence *fence,
- struct sync_fence_waiter *waiter)
+ struct sync_fence_waiter *waiter)
{
unsigned long flags;
int ret = 0;
@@ -519,12 +524,10 @@ static const struct fence_ops android_fence_ops = {
static void sync_fence_free(struct kref *kref)
{
struct sync_fence *fence = container_of(kref, struct sync_fence, kref);
- int i, status = atomic_read(&fence->status);
+ int i;
for (i = 0; i < fence->num_fences; ++i) {
- if (status)
- fence_remove_callback(fence->cbs[i].sync_pt,
- &fence->cbs[i].cb);
+ fence_remove_callback(fence->cbs[i].sync_pt, &fence->cbs[i].cb);
fence_put(fence->cbs[i].sync_pt);
}
@@ -583,14 +586,14 @@ static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg)
}
fence2 = sync_fence_fdget(data.fd2);
- if (fence2 == NULL) {
+ if (!fence2) {
err = -ENOENT;
goto err_put_fd;
}
data.name[sizeof(data.name) - 1] = '\0';
fence3 = sync_fence_merge(data.name, fence, fence2);
- if (fence3 == NULL) {
+ if (!fence3) {
err = -ENOMEM;
goto err_put_fence2;
}
@@ -666,7 +669,7 @@ static long sync_fence_ioctl_fence_info(struct sync_fence *fence,
size = 4096;
data = kzalloc(size, GFP_KERNEL);
- if (data == NULL)
+ if (!data)
return -ENOMEM;
strlcpy(data->name, fence->name, sizeof(data->name));
diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h
index 61f8a3aede96..afa0752275a7 100644
--- a/drivers/staging/android/sync.h
+++ b/drivers/staging/android/sync.h
@@ -254,6 +254,16 @@ void sync_pt_free(struct sync_pt *pt);
*/
struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt);
+/**
+ * sync_fence_create_dma() - creates a sync fence from dma-fence
+ * @name: name of fence to create
+ * @pt: dma-fence to add to the fence
+ *
+ * Creates a fence containg @pt. Once this is called, the fence takes
+ * ownership of @pt.
+ */
+struct sync_fence *sync_fence_create_dma(const char *name, struct fence *pt);
+
/*
* API for sync_fence consumers
*/
diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c
index 91ed2c4cff45..f45d13cdd42b 100644
--- a/drivers/staging/android/sync_debug.c
+++ b/drivers/staging/android/sync_debug.c
@@ -82,36 +82,42 @@ static const char *sync_status_str(int status)
return "error";
}
-static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
+static void sync_print_pt(struct seq_file *s, struct fence *pt, bool fence)
{
int status = 1;
- struct sync_timeline *parent = sync_pt_parent(pt);
- if (fence_is_signaled_locked(&pt->base))
- status = pt->base.status;
+ if (fence_is_signaled_locked(pt))
+ status = pt->status;
seq_printf(s, " %s%spt %s",
- fence ? parent->name : "",
+ fence && pt->ops->get_timeline_name ?
+ pt->ops->get_timeline_name(pt) : "",
fence ? "_" : "",
sync_status_str(status));
if (status <= 0) {
struct timespec64 ts64 =
- ktime_to_timespec64(pt->base.timestamp);
+ ktime_to_timespec64(pt->timestamp);
seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
}
- if (parent->ops->timeline_value_str &&
- parent->ops->pt_value_str) {
+ if ((!fence || pt->ops->timeline_value_str) &&
+ pt->ops->fence_value_str) {
char value[64];
+ bool success;
- parent->ops->pt_value_str(pt, value, sizeof(value));
- seq_printf(s, ": %s", value);
- if (fence) {
- parent->ops->timeline_value_str(parent, value,
- sizeof(value));
- seq_printf(s, " / %s", value);
+ pt->ops->fence_value_str(pt, value, sizeof(value));
+ success = strlen(value);
+
+ if (success)
+ seq_printf(s, ": %s", value);
+
+ if (success && fence) {
+ pt->ops->timeline_value_str(pt, value, sizeof(value));
+
+ if (strlen(value))
+ seq_printf(s, " / %s", value);
}
}
@@ -138,7 +144,7 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
list_for_each(pos, &obj->child_list_head) {
struct sync_pt *pt =
container_of(pos, struct sync_pt, child_list);
- sync_print_pt(s, pt, false);
+ sync_print_pt(s, &pt->base, false);
}
spin_unlock_irqrestore(&obj->child_list_lock, flags);
}
@@ -153,11 +159,7 @@ static void sync_print_fence(struct seq_file *s, struct sync_fence *fence)
sync_status_str(atomic_read(&fence->status)));
for (i = 0; i < fence->num_fences; ++i) {
- struct sync_pt *pt =
- container_of(fence->cbs[i].sync_pt,
- struct sync_pt, base);
-
- sync_print_pt(s, pt, true);
+ sync_print_pt(s, fence->cbs[i].sync_pt, true);
}
spin_lock_irqsave(&fence->wq.lock, flags);
diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c
index ce11726f1a6c..bcd9924d4631 100644
--- a/drivers/staging/android/timed_gpio.c
+++ b/drivers/staging/android/timed_gpio.c
@@ -25,7 +25,6 @@
#include "timed_output.h"
#include "timed_gpio.h"
-
struct timed_gpio_data {
struct timed_output_dev dev;
struct hrtimer timer;
@@ -76,8 +75,8 @@ static void gpio_enable(struct timed_output_dev *dev, int value)
value = data->max_timeout;
hrtimer_start(&data->timer,
- ktime_set(value / 1000, (value % 1000) * 1000000),
- HRTIMER_MODE_REL);
+ ktime_set(value / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
}
spin_unlock_irqrestore(&data->lock, flags);
@@ -94,8 +93,8 @@ static int timed_gpio_probe(struct platform_device *pdev)
return -EBUSY;
gpio_data = devm_kzalloc(&pdev->dev,
- sizeof(struct timed_gpio_data) * pdata->num_gpios,
- GFP_KERNEL);
+ sizeof(*gpio_data) * pdata->num_gpios,
+ GFP_KERNEL);
if (!gpio_data)
return -ENOMEM;
@@ -104,7 +103,7 @@ static int timed_gpio_probe(struct platform_device *pdev)
gpio_dat = &gpio_data[i];
hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
+ HRTIMER_MODE_REL);
gpio_dat->timer.function = gpio_timer_func;
spin_lock_init(&gpio_dat->lock);
diff --git a/drivers/staging/board/armadillo800eva.c b/drivers/staging/board/armadillo800eva.c
index 9c41652ee908..912c96b0536d 100644
--- a/drivers/staging/board/armadillo800eva.c
+++ b/drivers/staging/board/armadillo800eva.c
@@ -97,7 +97,7 @@ static const struct board_staging_dev armadillo800eva_devices[] __initconst = {
static void __init armadillo800eva_init(void)
{
- board_staging_gic_setup_xlate("arm,cortex-a9-gic", 32);
+ board_staging_gic_setup_xlate("arm,pl390", 32);
board_staging_register_devices(armadillo800eva_devices,
ARRAY_SIZE(armadillo800eva_devices));
}
diff --git a/drivers/staging/board/kzm9d.c b/drivers/staging/board/kzm9d.c
index 8d1eb09bc66e..05a6d434d307 100644
--- a/drivers/staging/board/kzm9d.c
+++ b/drivers/staging/board/kzm9d.c
@@ -11,7 +11,7 @@ static struct resource usbs1_res[] __initdata = {
static void __init kzm9d_init(void)
{
- board_staging_gic_setup_xlate("arm,cortex-a9-gic", 32);
+ board_staging_gic_setup_xlate("arm,pl390", 32);
if (!board_staging_dt_node_available(usbs1_res,
ARRAY_SIZE(usbs1_res))) {
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index ac0f01007abd..e7255f811611 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -737,15 +737,23 @@ config COMEDI_ADL_PCI9118
called adl_pci9118.
config COMEDI_ADV_PCI1710
- tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
+ tristate "Advantech PCI-171x and PCI-1731 support"
select COMEDI_8254
---help---
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
- PCI-1713, PCI-1720 and PCI-1731
+ PCI-1713 and PCI-1731
To compile this driver as a module, choose M here: the module will be
called adv_pci1710.
+config COMEDI_ADV_PCI1720
+ tristate "Advantech PCI-1720 support"
+ ---help---
+ Enable support for Advantech PCI-1720 Analog Output board.
+
+ To compile this driver as a module, choose M here: the module will be
+ called adv_pci1720.
+
config COMEDI_ADV_PCI1723
tristate "Advantech PCI-1723 support"
---help---
@@ -764,6 +772,14 @@ config COMEDI_ADV_PCI1724
To compile this driver as a module, choose M here: the module will be
called adv_pci1724.
+config COMEDI_ADV_PCI1760
+ tristate "Advantech PCI-1760 support"
+ ---help---
+ Enable support for Advantech PCI-1760 board.
+
+ To compile this driver as a module, choose M here: the module will be
+ called adv_pci1760.
+
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
select COMEDI_8254
@@ -771,8 +787,8 @@ config COMEDI_ADV_PCI_DIO
---help---
Enable support for Advantech PCI DIO cards
PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U,
- PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756,
- PCI-1760 and PCI-1762
+ PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756 and
+ PCI-1762
To compile this driver as a module, choose M here: the module will be
called adv_pci_dio.
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index 66edda190b75..83bd309d011b 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -1,20 +1,20 @@
/*
- include/comedi.h (installed as /usr/include/comedi.h)
- header file for comedi
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998-2001 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser 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/comedi.h (installed as /usr/include/comedi.h)
+ * header file for comedi
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998-2001 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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.
+ */
#ifndef _COMEDI_H
#define _COMEDI_H
@@ -28,9 +28,9 @@
#define COMEDI_MAJOR 98
/*
- maximum number of minor devices. This can be increased, although
- kernel structures are currently statically allocated, thus you
- don't want this to be much more than you actually use.
+ * maximum number of minor devices. This can be increased, although
+ * kernel structures are currently statically allocated, thus you
+ * don't want this to be much more than you actually use.
*/
#define COMEDI_NDEVICES 16
@@ -63,21 +63,21 @@
/* packs and unpacks a channel/range number */
#define CR_PACK(chan, rng, aref) \
- ((((aref)&0x3)<<24) | (((rng)&0xff)<<16) | (chan))
+ ((((aref) & 0x3) << 24) | (((rng) & 0xff) << 16) | (chan))
#define CR_PACK_FLAGS(chan, range, aref, flags) \
(CR_PACK(chan, range, aref) | ((flags) & CR_FLAGS_MASK))
-#define CR_CHAN(a) ((a)&0xffff)
-#define CR_RANGE(a) (((a)>>16)&0xff)
-#define CR_AREF(a) (((a)>>24)&0x03)
+#define CR_CHAN(a) ((a) & 0xffff)
+#define CR_RANGE(a) (((a) >> 16) & 0xff)
+#define CR_AREF(a) (((a) >> 24) & 0x03)
#define CR_FLAGS_MASK 0xfc000000
-#define CR_ALT_FILTER (1<<26)
+#define CR_ALT_FILTER (1 << 26)
#define CR_DITHER CR_ALT_FILTER
#define CR_DEGLITCH CR_ALT_FILTER
-#define CR_ALT_SOURCE (1<<27)
-#define CR_EDGE (1<<30)
-#define CR_INVERT (1<<31)
+#define CR_ALT_SOURCE (1 << 27)
+#define CR_EDGE (1 << 30)
+#define CR_INVERT (1 << 31)
#define AREF_GROUND 0x00 /* analog ref = analog ground */
#define AREF_COMMON 0x01 /* analog ref = analog common */
@@ -114,11 +114,11 @@
#define INSN_READ (0 | INSN_MASK_READ)
#define INSN_WRITE (1 | INSN_MASK_WRITE)
-#define INSN_BITS (2 | INSN_MASK_READ|INSN_MASK_WRITE)
-#define INSN_CONFIG (3 | INSN_MASK_READ|INSN_MASK_WRITE)
-#define INSN_GTOD (4 | INSN_MASK_READ|INSN_MASK_SPECIAL)
-#define INSN_WAIT (5 | INSN_MASK_WRITE|INSN_MASK_SPECIAL)
-#define INSN_INTTRIG (6 | INSN_MASK_WRITE|INSN_MASK_SPECIAL)
+#define INSN_BITS (2 | INSN_MASK_READ | INSN_MASK_WRITE)
+#define INSN_CONFIG (3 | INSN_MASK_READ | INSN_MASK_WRITE)
+#define INSN_GTOD (4 | INSN_MASK_READ | INSN_MASK_SPECIAL)
+#define INSN_WAIT (5 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
+#define INSN_INTTRIG (6 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
/* trigger flags */
/* These flags are used in comedi_trig structures */
@@ -279,7 +279,8 @@ enum configuration_ids {
INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */
/* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */
/* Get size in bytes of subdevice's on-board fifos used during
- * streaming input/output */
+ * streaming input/output
+ */
INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006,
INSN_CONFIG_SET_COUNTER_MODE = 4097,
/* INSN_CONFIG_8254_SET_MODE is deprecated */
@@ -292,7 +293,8 @@ enum configuration_ids {
INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */
INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */
/* sets H bridge: duty cycle and sign bit for a relay at the
- * same time */
+ * same time
+ */
INSN_CONFIG_PWM_SET_H_BRIDGE = 5003,
/* gets H bridge data: duty cycle and the sign bit */
INSN_CONFIG_PWM_GET_H_BRIDGE = 5004
@@ -502,13 +504,13 @@ struct comedi_bufinfo {
/* range stuff */
-#define __RANGE(a, b) ((((a)&0xffff)<<16)|((b)&0xffff))
+#define __RANGE(a, b) ((((a) & 0xffff) << 16) | ((b) & 0xffff))
-#define RANGE_OFFSET(a) (((a)>>16)&0xffff)
-#define RANGE_LENGTH(b) ((b)&0xffff)
+#define RANGE_OFFSET(a) (((a) >> 16) & 0xffff)
+#define RANGE_LENGTH(b) ((b) & 0xffff)
-#define RF_UNIT(flags) ((flags)&0xff)
-#define RF_EXTERNAL (1<<8)
+#define RF_UNIT(flags) ((flags) & 0xff)
+#define RF_EXTERNAL (1 << 8)
#define UNIT_volt 0
#define UNIT_mA 1
@@ -521,23 +523,22 @@ struct comedi_bufinfo {
/**********************************************************/
/*
- 8254 specific configuration.
-
- It supports two config commands:
-
- 0 ID: INSN_CONFIG_SET_COUNTER_MODE
- 1 8254 Mode
- I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
- OR'ed with:
- I8254_BCD, I8254_BINARY
-
- 0 ID: INSN_CONFIG_8254_READ_STATUS
- 1 <-- Status byte returned here.
- B7 = Output
- B6 = NULL Count
- B5 - B0 Current mode.
-
-*/
+ * 8254 specific configuration.
+ *
+ * It supports two config commands:
+ *
+ * 0 ID: INSN_CONFIG_SET_COUNTER_MODE
+ * 1 8254 Mode
+ * I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
+ * OR'ed with:
+ * I8254_BCD, I8254_BINARY
+ *
+ * 0 ID: INSN_CONFIG_8254_READ_STATUS
+ * 1 <-- Status byte returned here.
+ * B7 = Output
+ * B6 = NULL Count
+ * B5 - B0 Current mode.
+ */
enum i8254_mode {
I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */
@@ -545,18 +546,20 @@ enum i8254_mode {
I8254_MODE2 = (2 << 1), /* Rate generator */
I8254_MODE3 = (3 << 1), /* Square wave mode */
I8254_MODE4 = (4 << 1), /* Software triggered strobe */
- I8254_MODE5 = (5 << 1), /* Hardware triggered strobe
- * (retriggerable) */
- I8254_BCD = 1, /* use binary-coded decimal instead of binary
- * (pretty useless) */
+ /* Hardware triggered strobe (retriggerable) */
+ I8254_MODE5 = (5 << 1),
+ /* Use binary-coded decimal instead of binary (pretty useless) */
+ I8254_BCD = 1,
I8254_BINARY = 0
};
#define NI_USUAL_PFI_SELECT(x) (((x) < 10) ? (0x1 + (x)) : (0xb + (x)))
#define NI_USUAL_RTSI_SELECT(x) (((x) < 7) ? (0xb + (x)) : 0x1b)
-/* mode bits for NI general-purpose counters, set with
- * INSN_CONFIG_SET_COUNTER_MODE */
+/*
+ * mode bits for NI general-purpose counters, set with
+ * INSN_CONFIG_SET_COUNTER_MODE
+ */
#define NI_GPCT_COUNTING_MODE_SHIFT 16
#define NI_GPCT_INDEX_PHASE_BITSHIFT 20
#define NI_GPCT_COUNTING_DIRECTION_SHIFT 24
@@ -624,8 +627,10 @@ enum ni_gpct_mode_bits {
NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000
};
-/* Bits for setting a clock source with
- * INSN_CONFIG_SET_CLOCK_SRC when using NI general-purpose counters. */
+/*
+ * Bits for setting a clock source with
+ * INSN_CONFIG_SET_CLOCK_SRC when using NI general-purpose counters.
+ */
enum ni_gpct_clock_source_bits {
NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f,
NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0,
@@ -656,9 +661,11 @@ enum ni_gpct_clock_source_bits {
/* no pfi on NI 660x */
#define NI_GPCT_PFI_CLOCK_SRC_BITS(x) (0x20 + (x))
-/* Possibilities for setting a gate source with
-INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters.
-May be bitwise-or'd with CR_EDGE or CR_INVERT. */
+/*
+ * Possibilities for setting a gate source with
+ * INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters.
+ * May be bitwise-or'd with CR_EDGE or CR_INVERT.
+ */
enum ni_gpct_gate_select {
/* m-series gates */
NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0,
@@ -675,9 +682,11 @@ enum ni_gpct_gate_select {
/* more gates for 660x "second gate" */
NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201,
NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e,
- /* m-series "second gate" sources are unknown,
+ /*
+ * m-series "second gate" sources are unknown,
* we should add them here with an offset of 0x300 when
- * known. */
+ * known.
+ */
NI_GPCT_DISABLED_GATE_SELECT = 0x8000,
};
@@ -686,8 +695,10 @@ enum ni_gpct_gate_select {
#define NI_GPCT_PFI_GATE_SELECT(x) NI_USUAL_PFI_SELECT(x)
#define NI_GPCT_UP_DOWN_PIN_GATE_SELECT(x) (0x202 + (x))
-/* Possibilities for setting a source with
-INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters. */
+/*
+ * Possibilities for setting a source with
+ * INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters.
+ */
enum ni_gpct_other_index {
NI_GPCT_SOURCE_ENCODER_A,
NI_GPCT_SOURCE_ENCODER_B,
@@ -702,18 +713,24 @@ enum ni_gpct_other_select {
#define NI_GPCT_PFI_OTHER_SELECT(x) NI_USUAL_PFI_SELECT(x)
-/* start sources for ni general-purpose counters for use with
-INSN_CONFIG_ARM */
+/*
+ * start sources for ni general-purpose counters for use with
+ * INSN_CONFIG_ARM
+ */
enum ni_gpct_arm_source {
NI_GPCT_ARM_IMMEDIATE = 0x0,
- NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter
- * and the adjacent paired
- * counter simultaneously */
- /* NI doesn't document bits for selecting hardware arm triggers.
+ /*
+ * Start both the counter and the adjacent pared
+ * counter simultaneously
+ */
+ NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1,
+ /*
+ * NI doesn't document bits for selecting hardware arm triggers.
* If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least
* significant bits (3 bits for 660x or 5 bits for m-series)
* through to the hardware. This will at least allow someone to
- * figure out what the bits do later. */
+ * figure out what the bits do later.
+ */
NI_GPCT_ARM_UNKNOWN = 0x1000,
};
@@ -728,8 +745,10 @@ enum ni_gpct_filter_select {
NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6
};
-/* PFI digital filtering options for ni m-series for use with
- * INSN_CONFIG_FILTER. */
+/*
+ * PFI digital filtering options for ni m-series for use with
+ * INSN_CONFIG_FILTER.
+ */
enum ni_pfi_filter_select {
NI_PFI_FILTER_OFF = 0x0,
NI_PFI_FILTER_125ns = 0x1,
@@ -740,9 +759,11 @@ enum ni_pfi_filter_select {
/* master clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */
enum ni_mio_clock_source {
NI_MIO_INTERNAL_CLOCK = 0,
- NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use
- NI_MIO_PLL_RTSI_CLOCK() */
- /* the NI_MIO_PLL_* sources are m-series only */
+ /*
+ * Doesn't work for m-series, use NI_MIO_PLL_RTSI_CLOCK()
+ * the NI_MIO_PLL_* sources are m-series only
+ */
+ NI_MIO_RTSI_CLOCK = 1,
NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2,
NI_MIO_PLL_PXI10_CLOCK = 3,
NI_MIO_PLL_RTSI0_CLOCK = 4
@@ -750,9 +771,11 @@ enum ni_mio_clock_source {
#define NI_MIO_PLL_RTSI_CLOCK(x) (NI_MIO_PLL_RTSI0_CLOCK + (x))
-/* Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING.
- The numbers assigned are not arbitrary, they correspond to the bits required
- to program the board. */
+/*
+ * Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING.
+ * The numbers assigned are not arbitrary, they correspond to the bits required
+ * to program the board.
+ */
enum ni_rtsi_routing {
NI_RTSI_OUTPUT_ADR_START1 = 0,
NI_RTSI_OUTPUT_ADR_START2 = 1,
@@ -763,17 +786,19 @@ enum ni_rtsi_routing {
NI_RTSI_OUTPUT_G_GATE0 = 6,
NI_RTSI_OUTPUT_RGOUT0 = 7,
NI_RTSI_OUTPUT_RTSI_BRD_0 = 8,
- NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI
- * clock on line 7 */
+ /* Pre-m-series always have RTSI clock on line 7 */
+ NI_RTSI_OUTPUT_RTSI_OSC = 12
};
#define NI_RTSI_OUTPUT_RTSI_BRD(x) (NI_RTSI_OUTPUT_RTSI_BRD_0 + (x))
-/* Signals which can be routed to an NI PFI pin on an m-series board with
+/*
+ * Signals which can be routed to an NI PFI pin on an m-series board with
* INSN_CONFIG_SET_ROUTING. These numbers are also returned by
* INSN_CONFIG_GET_ROUTING on pre-m-series boards, even though their routing
* cannot be changed. The numbers assigned are not arbitrary, they correspond
- * to the bits required to program the board. */
+ * to the bits required to program the board.
+ */
enum ni_pfi_routing {
NI_PFI_OUTPUT_PFI_DEFAULT = 0,
NI_PFI_OUTPUT_AI_START1 = 1,
@@ -803,20 +828,24 @@ enum ni_pfi_routing {
#define NI_PFI_OUTPUT_RTSI(x) (NI_PFI_OUTPUT_RTSI0 + (x))
-/* Signals which can be routed to output on a NI PFI pin on a 660x board
- with INSN_CONFIG_SET_ROUTING. The numbers assigned are
- not arbitrary, they correspond to the bits required
- to program the board. Lines 0 to 7 can only be set to
- NI_660X_PFI_OUTPUT_DIO. Lines 32 to 39 can only be set to
- NI_660X_PFI_OUTPUT_COUNTER. */
+/*
+ * Signals which can be routed to output on a NI PFI pin on a 660x board
+ * with INSN_CONFIG_SET_ROUTING. The numbers assigned are
+ * not arbitrary, they correspond to the bits required
+ * to program the board. Lines 0 to 7 can only be set to
+ * NI_660X_PFI_OUTPUT_DIO. Lines 32 to 39 can only be set to
+ * NI_660X_PFI_OUTPUT_COUNTER.
+ */
enum ni_660x_pfi_routing {
NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */
NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */
};
-/* NI External Trigger lines. These values are not arbitrary, but are related
+/*
+ * NI External Trigger lines. These values are not arbitrary, but are related
* to the bits required to program the board (offset by 1 for historical
- * reasons). */
+ * reasons).
+ */
#define NI_EXT_PFI(x) (NI_USUAL_PFI_SELECT(x) - 1)
#define NI_EXT_RTSI(x) (NI_USUAL_RTSI_SELECT(x) - 1)
@@ -827,9 +856,11 @@ enum comedi_counter_status_flags {
COMEDI_COUNTER_TERMINAL_COUNT = 0x4,
};
-/* Clock sources for CDIO subdevice on NI m-series boards. Used as the
+/*
+ * Clock sources for CDIO subdevice on NI m-series boards. Used as the
* scan_begin_arg for a comedi_command. These sources may also be bitwise-or'd
- * with CR_INVERT to change polarity. */
+ * with CR_INVERT to change polarity.
+ */
enum ni_m_series_cdio_scan_begin_src {
NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0,
NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18,
@@ -846,38 +877,50 @@ enum ni_m_series_cdio_scan_begin_src {
#define NI_CDIO_SCAN_BEGIN_SRC_PFI(x) NI_USUAL_PFI_SELECT(x)
#define NI_CDIO_SCAN_BEGIN_SRC_RTSI(x) NI_USUAL_RTSI_SELECT(x)
-/* scan_begin_src for scan_begin_arg==TRIG_EXT with analog output command on NI
+/*
+ * scan_begin_src for scan_begin_arg==TRIG_EXT with analog output command on NI
* boards. These scan begin sources can also be bitwise-or'd with CR_INVERT to
- * change polarity. */
+ * change polarity.
+ */
#define NI_AO_SCAN_BEGIN_SRC_PFI(x) NI_USUAL_PFI_SELECT(x)
#define NI_AO_SCAN_BEGIN_SRC_RTSI(x) NI_USUAL_RTSI_SELECT(x)
-/* Bits for setting a clock source with
- * INSN_CONFIG_SET_CLOCK_SRC when using NI frequency output subdevice. */
+/*
+ * Bits for setting a clock source with
+ * INSN_CONFIG_SET_CLOCK_SRC when using NI frequency output subdevice.
+ */
enum ni_freq_out_clock_source_bits {
NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */
NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */
};
-/* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for
- * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */
+/*
+ * Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for
+ * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver).
+ */
enum amplc_dio_clock_source {
- AMPLC_DIO_CLK_CLKN, /* per channel external clock
- input/output pin (pin is only an
- input when clock source set to this
- value, otherwise it is an output) */
+ /*
+ * Per channel external clock
+ * input/output pin (pin is only an
+ * input when clock source set to this value,
+ * otherwise it is an output)
+ */
+ AMPLC_DIO_CLK_CLKN,
AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */
AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */
AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */
AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */
AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */
- AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel
- (for channel 0, preceding counter
- channel is channel 2 on preceding
- counter subdevice, for first counter
- subdevice, preceding counter
- subdevice is the last counter
- subdevice) */
+ /*
+ * Output of preceding counter channel
+ * (for channel 0, preceding counter
+ * channel is channel 2 on preceding
+ * counter subdevice, for first counter
+ * subdevice, preceding counter
+ * subdevice is the last counter
+ * subdevice)
+ */
+ AMPLC_DIO_CLK_OUTNM1,
AMPLC_DIO_CLK_EXT, /* per chip external input pin */
/* the following are "enhanced" clock sources for PCIe models */
AMPLC_DIO_CLK_VCC, /* clock input HIGH */
@@ -886,35 +929,39 @@ enum amplc_dio_clock_source {
AMPLC_DIO_CLK_20MHZ /* 20 MHz internal clock */
};
-/* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for
- * timer subdevice on some Amplicon DIO PCIe boards (amplc_dio200 driver). */
+/*
+ * Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for
+ * timer subdevice on some Amplicon DIO PCIe boards (amplc_dio200 driver).
+ */
enum amplc_dio_ts_clock_src {
AMPLC_DIO_TS_CLK_1GHZ, /* 1 ns period with 20 ns granularity */
AMPLC_DIO_TS_CLK_1MHZ, /* 1 us period */
AMPLC_DIO_TS_CLK_1KHZ /* 1 ms period */
};
-/* Values for setting a gate source with INSN_CONFIG_SET_GATE_SRC for
- * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */
+/*
+ * Values for setting a gate source with INSN_CONFIG_SET_GATE_SRC for
+ * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver).
+ */
enum amplc_dio_gate_source {
AMPLC_DIO_GAT_VCC, /* internal high logic level */
AMPLC_DIO_GAT_GND, /* internal low logic level */
AMPLC_DIO_GAT_GATN, /* per channel external gate input */
- AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel
- minus 2 (for channels 0 or 1,
- channel minus 2 is channel 1 or 2 on
- the preceding counter subdevice, for
- the first counter subdevice the
- preceding counter subdevice is the
- last counter subdevice) */
+ /*
+ * negated output of counter channel minus 2
+ * (for channels 0 or 1, channel minus 2 is channel 1 or 2 on
+ * the preceding counter subdevice, for the first counter subdevice
+ * the preceding counter subdevice is the last counter subdevice)
+ */
+ AMPLC_DIO_GAT_NOUTNM2,
AMPLC_DIO_GAT_RESERVED4,
AMPLC_DIO_GAT_RESERVED5,
AMPLC_DIO_GAT_RESERVED6,
AMPLC_DIO_GAT_RESERVED7,
/* the following are "enhanced" gate sources for PCIe models */
AMPLC_DIO_GAT_NGATN = 6, /* negated per channel gate input */
- AMPLC_DIO_GAT_OUTNM2, /* non-negated output of counter
- channel minus 2 */
+ /* non-negated output of counter channel minus 2 */
+ AMPLC_DIO_GAT_OUTNM2,
AMPLC_DIO_GAT_PAT_PRESENT, /* "pattern present" signal */
AMPLC_DIO_GAT_PAT_OCCURRED, /* "pattern occurred" latched */
AMPLC_DIO_GAT_PAT_GONE, /* "pattern gone away" latched */
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 7b4af519e17e..d57fadef47fc 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2303,11 +2303,13 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
{
struct comedi_subdevice *s;
struct comedi_async *async;
- int n, m, count = 0, retval = 0;
+ unsigned int n, m;
+ ssize_t count = 0;
+ int retval = 0;
DECLARE_WAITQUEUE(wait, current);
struct comedi_file *cfp = file->private_data;
struct comedi_device *dev = cfp->dev;
- bool on_wait_queue = false;
+ bool become_nonbusy = false;
bool attach_locked;
unsigned int old_detach_count;
@@ -2329,74 +2331,33 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
}
async = s->async;
-
- if (!s->busy || !nbytes)
- goto out;
- if (s->busy != file) {
- retval = -EACCES;
- goto out;
- }
- if (!(async->cmd.flags & CMDF_WRITE)) {
+ if (s->busy != file || !(async->cmd.flags & CMDF_WRITE)) {
retval = -EINVAL;
goto out;
}
add_wait_queue(&async->wait_head, &wait);
- on_wait_queue = true;
- while (nbytes > 0 && !retval) {
+ while (count == 0 && !retval) {
unsigned runflags;
+ unsigned int wp, n1, n2;
set_current_state(TASK_INTERRUPTIBLE);
runflags = comedi_get_subdevice_runflags(s);
if (!comedi_is_runflags_running(runflags)) {
- if (count == 0) {
- struct comedi_subdevice *new_s;
-
- if (comedi_is_runflags_in_error(runflags))
- retval = -EPIPE;
- else
- retval = 0;
- /*
- * To avoid deadlock, cannot acquire dev->mutex
- * while dev->attach_lock is held. Need to
- * remove task from the async wait queue before
- * releasing dev->attach_lock, as it might not
- * be valid afterwards.
- */
- remove_wait_queue(&async->wait_head, &wait);
- on_wait_queue = false;
- up_read(&dev->attach_lock);
- attach_locked = false;
- mutex_lock(&dev->mutex);
- /*
- * Become non-busy unless things have changed
- * behind our back. Checking dev->detach_count
- * is unchanged ought to be sufficient (unless
- * there have been 2**32 detaches in the
- * meantime!), but check the subdevice pointer
- * as well just in case.
- */
- new_s = comedi_file_write_subdevice(file);
- if (dev->attached &&
- old_detach_count == dev->detach_count &&
- s == new_s && new_s->async == async)
- do_become_nonbusy(dev, s);
- mutex_unlock(&dev->mutex);
- }
+ if (comedi_is_runflags_in_error(runflags))
+ retval = -EPIPE;
+ if (retval || nbytes)
+ become_nonbusy = true;
break;
}
+ if (nbytes == 0)
+ break;
- n = nbytes;
-
- m = n;
- if (async->buf_write_ptr + m > async->prealloc_bufsz)
- m = async->prealloc_bufsz - async->buf_write_ptr;
+ /* Allocate all free buffer space. */
comedi_buf_write_alloc(s, async->prealloc_bufsz);
- if (m > comedi_buf_write_n_allocated(s))
- m = comedi_buf_write_n_allocated(s);
- if (m < n)
- n = m;
+ m = comedi_buf_write_n_allocated(s);
+ n = min_t(size_t, m, nbytes);
if (n == 0) {
if (file->f_flags & O_NONBLOCK) {
@@ -2408,21 +2369,22 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
retval = -ERESTARTSYS;
break;
}
- if (!s->busy)
- break;
- if (s->busy != file) {
- retval = -EACCES;
- break;
- }
- if (!(async->cmd.flags & CMDF_WRITE)) {
+ if (s->busy != file ||
+ !(async->cmd.flags & CMDF_WRITE)) {
retval = -EINVAL;
break;
}
continue;
}
- m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
- buf, n);
+ wp = async->buf_write_ptr;
+ n1 = min(n, async->prealloc_bufsz - wp);
+ n2 = n - n1;
+ m = copy_from_user(async->prealloc_buf + wp, buf, n1);
+ if (m)
+ m += n2;
+ else if (n2)
+ m = copy_from_user(async->prealloc_buf, buf + n1, n2);
if (m) {
n -= m;
retval = -EFAULT;
@@ -2433,12 +2395,38 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
nbytes -= n;
buf += n;
- break; /* makes device work like a pipe */
}
-out:
- if (on_wait_queue)
- remove_wait_queue(&async->wait_head, &wait);
+ remove_wait_queue(&async->wait_head, &wait);
set_current_state(TASK_RUNNING);
+ if (become_nonbusy && count == 0) {
+ struct comedi_subdevice *new_s;
+
+ /*
+ * To avoid deadlock, cannot acquire dev->mutex
+ * while dev->attach_lock is held.
+ */
+ up_read(&dev->attach_lock);
+ attach_locked = false;
+ mutex_lock(&dev->mutex);
+ /*
+ * Check device hasn't become detached behind our back.
+ * Checking dev->detach_count is unchanged ought to be
+ * sufficient (unless there have been 2**32 detaches in the
+ * meantime!), but check the subdevice pointer as well just in
+ * case.
+ *
+ * Also check the subdevice is still in a suitable state to
+ * become non-busy in case it changed behind our back.
+ */
+ new_s = comedi_file_write_subdevice(file);
+ if (dev->attached && old_detach_count == dev->detach_count &&
+ s == new_s && new_s->async == async && s->busy == file &&
+ (async->cmd.flags & CMDF_WRITE) &&
+ !comedi_is_subdevice_running(s))
+ do_become_nonbusy(dev, s);
+ mutex_unlock(&dev->mutex);
+ }
+out:
if (attach_locked)
up_read(&dev->attach_lock);
diff --git a/drivers/staging/comedi/comedilib.h b/drivers/staging/comedi/comedilib.h
index 56baf852ecf5..f9b56396e161 100644
--- a/drivers/staging/comedi/comedilib.h
+++ b/drivers/staging/comedi/comedilib.h
@@ -1,20 +1,20 @@
/*
- linux/include/comedilib.h
- header file for kcomedilib
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998-2001 David A. Schleef <ds@schleef.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.
-*/
+ * comedilib.h
+ * Header file for kcomedilib
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998-2001 David A. Schleef <ds@schleef.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.
+ */
#ifndef _LINUX_COMEDILIB_H
#define _LINUX_COMEDILIB_H
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index c3b8f2d7611b..0c8cfa738727 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -78,8 +78,10 @@ obj-$(CONFIG_COMEDI_ADL_PCI8164) += adl_pci8164.o
obj-$(CONFIG_COMEDI_ADL_PCI9111) += adl_pci9111.o
obj-$(CONFIG_COMEDI_ADL_PCI9118) += adl_pci9118.o
obj-$(CONFIG_COMEDI_ADV_PCI1710) += adv_pci1710.o
+obj-$(CONFIG_COMEDI_ADV_PCI1720) += adv_pci1720.o
obj-$(CONFIG_COMEDI_ADV_PCI1723) += adv_pci1723.o
obj-$(CONFIG_COMEDI_ADV_PCI1724) += adv_pci1724.o
+obj-$(CONFIG_COMEDI_ADV_PCI1760) += adv_pci1760.o
obj-$(CONFIG_COMEDI_ADV_PCI_DIO) += adv_pci_dio.o
obj-$(CONFIG_COMEDI_AMPLC_DIO200_PCI) += amplc_dio200_pci.o
obj-$(CONFIG_COMEDI_AMPLC_PC236_PCI) += amplc_pci236.o
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 0dff1dbb53fb..4437ea3abe8d 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -603,10 +603,11 @@ static void pci9118_ai_munge(struct comedi_device *dev,
unsigned short *array = data;
unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes);
unsigned int i;
+ __be16 *barray = data;
for (i = 0; i < num_samples; i++) {
if (devpriv->usedma)
- array[i] = be16_to_cpu(array[i]);
+ array[i] = be16_to_cpu(barray[i]);
if (s->maxdata == 0xffff)
array[i] ^= 0x8000;
else
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 399c511cfe0a..2c1b6de30da8 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -11,8 +11,9 @@
* Driver: adv_pci1710
* Description: Comedi driver for Advantech PCI-1710 series boards
* Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711,
- * PCI-1713, PCI-1720, PCI-1731
+ * PCI-1713, PCI-1731
* Author: Michal Dobes <dobes@tesnet.cz>
+ * Updated: Fri, 29 Oct 2015 17:19:35 -0700
* Status: works
*
* Configuration options: not applicable, uses PCI auto config
@@ -40,7 +41,13 @@
#define PCI171X_AD_DATA_REG 0x00 /* R: A/D data */
#define PCI171X_SOFTTRG_REG 0x00 /* W: soft trigger for A/D */
#define PCI171X_RANGE_REG 0x02 /* W: A/D gain/range register */
+#define PCI171X_RANGE_DIFF BIT(5)
+#define PCI171X_RANGE_UNI BIT(4)
+#define PCI171X_RANGE_GAIN(x) (((x) & 0x7) << 0)
#define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */
+#define PCI171X_MUX_CHANH(x) (((x) & 0xf) << 8)
+#define PCI171X_MUX_CHANL(x) (((x) & 0xf) << 0)
+#define PCI171X_MUX_CHAN(x) (PCI171X_MUX_CHANH(x) | PCI171X_MUX_CHANL(x))
#define PCI171X_STATUS_REG 0x06 /* R: status register */
#define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */
#define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */
@@ -58,83 +65,58 @@
#define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */
#define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */
#define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */
+#define PCI171X_DAREF(c, r) (((r) & 0x3) << ((c) * 2))
+#define PCI171X_DAREF_MASK(c) PCI171X_DAREF((c), 0x3)
#define PCI171X_DI_REG 0x10 /* R: digital inputs */
#define PCI171X_DO_REG 0x10 /* W: digital outputs */
#define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */
-/*
- * PCI-1720 only has analog outputs and has a different
- * register map (dev->iobase)
- */
-#define PCI1720_DA_REG(x) (0x00 + ((x) * 2)) /* W: D/A registers */
-#define PCI1720_RANGE_REG 0x08 /* R/W: D/A range register */
-#define PCI1720_SYNC_REG 0x09 /* W: D/A synchronized output */
-#define PCI1720_SYNC_CTRL_REG 0x0f /* R/W: D/A synchronized control */
-#define PCI1720_SYNC_CTRL_SC0 BIT(0) /* set synchronous output mode */
-
-static const struct comedi_lrange range_pci1710_3 = {
+static const struct comedi_lrange pci1710_ai_range = {
9, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- BIP_RANGE(10),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
+ BIP_RANGE(5), /* gain 1 (0x00) */
+ BIP_RANGE(2.5), /* gain 2 (0x01) */
+ BIP_RANGE(1.25), /* gain 4 (0x02) */
+ BIP_RANGE(0.625), /* gain 8 (0x03) */
+ BIP_RANGE(10), /* gain 0.5 (0x04) */
+ UNI_RANGE(10), /* gain 1 (0x00 | UNI) */
+ UNI_RANGE(5), /* gain 2 (0x01 | UNI) */
+ UNI_RANGE(2.5), /* gain 4 (0x02 | UNI) */
+ UNI_RANGE(1.25) /* gain 8 (0x03 | UNI) */
}
};
-static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x10, 0x11, 0x12, 0x13 };
-
-static const struct comedi_lrange range_pci1710hg = {
+static const struct comedi_lrange pci1710hg_ai_range = {
12, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01)
+ BIP_RANGE(5), /* gain 1 (0x00) */
+ BIP_RANGE(0.5), /* gain 10 (0x01) */
+ BIP_RANGE(0.05), /* gain 100 (0x02) */
+ BIP_RANGE(0.005), /* gain 1000 (0x03) */
+ BIP_RANGE(10), /* gain 0.5 (0x04) */
+ BIP_RANGE(1), /* gain 5 (0x05) */
+ BIP_RANGE(0.1), /* gain 50 (0x06) */
+ BIP_RANGE(0.01), /* gain 500 (0x07) */
+ UNI_RANGE(10), /* gain 1 (0x00 | UNI) */
+ UNI_RANGE(1), /* gain 10 (0x01 | UNI) */
+ UNI_RANGE(0.1), /* gain 100 (0x02 | UNI) */
+ UNI_RANGE(0.01) /* gain 1000 (0x03 | UNI) */
}
};
-static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x10, 0x11,
- 0x12, 0x13 };
-
-static const struct comedi_lrange range_pci17x1 = {
+static const struct comedi_lrange pci1711_ai_range = {
5, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625)
- }
-};
-
-static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
-
-static const struct comedi_lrange pci1720_ao_range = {
- 4, {
- UNI_RANGE(5),
- UNI_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(10)
+ BIP_RANGE(10), /* gain 1 (0x00) */
+ BIP_RANGE(5), /* gain 2 (0x01) */
+ BIP_RANGE(2.5), /* gain 4 (0x02) */
+ BIP_RANGE(1.25), /* gain 8 (0x03) */
+ BIP_RANGE(0.625) /* gain 16 (0x04) */
}
};
static const struct comedi_lrange pci171x_ao_range = {
- 2, {
- UNI_RANGE(5),
- UNI_RANGE(10)
+ 3, {
+ UNI_RANGE(5), /* internal -5V ref */
+ UNI_RANGE(10), /* internal -10V ref */
+ RANGE_ext(0, 1) /* external -Vref (+/-10V max) */
}
};
@@ -143,82 +125,43 @@ enum pci1710_boardid {
BOARD_PCI1710HG,
BOARD_PCI1711,
BOARD_PCI1713,
- BOARD_PCI1720,
BOARD_PCI1731,
};
struct boardtype {
- const char *name; /* board name */
- int n_aichan; /* num of A/D chans */
- const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
- const char *rangecode_ai; /* range codes for programming */
+ const char *name;
+ const struct comedi_lrange *ai_range;
+ unsigned int is_pci1711:1;
unsigned int is_pci1713:1;
- unsigned int is_pci1720:1;
- unsigned int has_irq:1;
- unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
- unsigned int has_diff_ai:1;
unsigned int has_ao:1;
- unsigned int has_di_do:1;
- unsigned int has_counter:1;
};
static const struct boardtype boardtypes[] = {
[BOARD_PCI1710] = {
.name = "pci1710",
- .n_aichan = 16,
- .rangelist_ai = &range_pci1710_3,
- .rangecode_ai = range_codes_pci1710_3,
- .has_irq = 1,
- .has_large_fifo = 1,
- .has_diff_ai = 1,
+ .ai_range = &pci1710_ai_range,
.has_ao = 1,
- .has_di_do = 1,
- .has_counter = 1,
},
[BOARD_PCI1710HG] = {
.name = "pci1710hg",
- .n_aichan = 16,
- .rangelist_ai = &range_pci1710hg,
- .rangecode_ai = range_codes_pci1710hg,
- .has_irq = 1,
- .has_large_fifo = 1,
- .has_diff_ai = 1,
+ .ai_range = &pci1710hg_ai_range,
.has_ao = 1,
- .has_di_do = 1,
- .has_counter = 1,
},
[BOARD_PCI1711] = {
.name = "pci1711",
- .n_aichan = 16,
- .rangelist_ai = &range_pci17x1,
- .rangecode_ai = range_codes_pci17x1,
- .has_irq = 1,
+ .ai_range = &pci1711_ai_range,
+ .is_pci1711 = 1,
.has_ao = 1,
- .has_di_do = 1,
- .has_counter = 1,
},
[BOARD_PCI1713] = {
.name = "pci1713",
- .n_aichan = 32,
- .rangelist_ai = &range_pci1710_3,
- .rangecode_ai = range_codes_pci1710_3,
+ .ai_range = &pci1710_ai_range,
.is_pci1713 = 1,
- .has_irq = 1,
- .has_large_fifo = 1,
- .has_diff_ai = 1,
- },
- [BOARD_PCI1720] = {
- .name = "pci1720",
- .is_pci1720 = 1,
- .has_ao = 1,
},
[BOARD_PCI1731] = {
.name = "pci1731",
- .n_aichan = 16,
- .rangelist_ai = &range_pci17x1,
- .rangecode_ai = range_codes_pci17x1,
- .has_irq = 1,
- .has_di_do = 1,
+ .ai_range = &pci1711_ai_range,
+ .is_pci1711 = 1,
},
};
@@ -226,14 +169,15 @@ struct pci1710_private {
unsigned int max_samples;
unsigned int ctrl; /* control register value */
unsigned int ctrl_ext; /* used to switch from TRIG_EXT to TRIG_xxx */
- unsigned int mux_ext; /* used to set the channel interval to scan */
+ unsigned int mux_scan; /* used to set the channel interval to scan */
unsigned char ai_et;
unsigned int act_chanlist[32]; /* list of scanned channel */
unsigned char saved_seglen; /* len of the non-repeating chanlist */
unsigned char da_ranges; /* copy of D/A outpit range register */
+ unsigned char unipolar_gain; /* adjust for unipolar gain codes */
};
-static int pci171x_ai_check_chanlist(struct comedi_device *dev,
+static int pci1710_ai_check_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
@@ -299,13 +243,12 @@ static int pci171x_ai_check_chanlist(struct comedi_device *dev,
return 0;
}
-static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
+static void pci1710_ai_setup_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *chanlist,
unsigned int n_chan,
unsigned int seglen)
{
- const struct boardtype *board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
unsigned int first_chan = CR_CHAN(chanlist[0]);
unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
@@ -315,14 +258,18 @@ static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
unsigned int chan = CR_CHAN(chanlist[i]);
unsigned int range = CR_RANGE(chanlist[i]);
unsigned int aref = CR_AREF(chanlist[i]);
- unsigned int rangeval;
+ unsigned int rangeval = 0;
- rangeval = board->rangecode_ai[range];
if (aref == AREF_DIFF)
- rangeval |= 0x0020;
+ rangeval |= PCI171X_RANGE_DIFF;
+ if (comedi_range_is_unipolar(s, range)) {
+ rangeval |= PCI171X_RANGE_UNI;
+ range -= devpriv->unipolar_gain;
+ }
+ rangeval |= PCI171X_RANGE_GAIN(range);
/* select channel and set range */
- outw(chan | (chan << 8), dev->iobase + PCI171X_MUX_REG);
+ outw(PCI171X_MUX_CHAN(chan), dev->iobase + PCI171X_MUX_REG);
outw(rangeval, dev->iobase + PCI171X_RANGE_REG);
devpriv->act_chanlist[i] = chan;
@@ -331,11 +278,12 @@ static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
/* select channel interval to scan */
- devpriv->mux_ext = first_chan | (last_chan << 8);
- outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG);
+ devpriv->mux_scan = PCI171X_MUX_CHANL(first_chan) |
+ PCI171X_MUX_CHANH(last_chan);
+ outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG);
}
-static int pci171x_ai_eoc(struct comedi_device *dev,
+static int pci1710_ai_eoc(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned long context)
@@ -348,7 +296,7 @@ static int pci171x_ai_eoc(struct comedi_device *dev,
return -EBUSY;
}
-static int pci171x_ai_read_sample(struct comedi_device *dev,
+static int pci1710_ai_read_sample(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int cur_chan,
unsigned int *val)
@@ -377,7 +325,7 @@ static int pci171x_ai_read_sample(struct comedi_device *dev,
return 0;
}
-static int pci171x_ai_insn_read(struct comedi_device *dev,
+static int pci1710_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -386,13 +334,14 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
int ret = 0;
int i;
- devpriv->ctrl &= PCI171X_CTRL_CNT0;
- devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */
+ /* enable software trigger */
+ devpriv->ctrl |= PCI171X_CTRL_SW;
outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
+
outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
outb(0, dev->iobase + PCI171X_CLRINT_REG);
- pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
+ pci1710_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
for (i = 0; i < insn->n; i++) {
unsigned int val;
@@ -400,111 +349,40 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
/* start conversion */
outw(0, dev->iobase + PCI171X_SOFTTRG_REG);
- ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
+ ret = comedi_timeout(dev, s, insn, pci1710_ai_eoc, 0);
if (ret)
break;
- ret = pci171x_ai_read_sample(dev, s, 0, &val);
+ ret = pci1710_ai_read_sample(dev, s, 0, &val);
if (ret)
break;
data[i] = val;
}
+ /* disable software trigger */
+ devpriv->ctrl &= ~PCI171X_CTRL_SW;
+ outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
+
outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
outb(0, dev->iobase + PCI171X_CLRINT_REG);
return ret ? ret : insn->n;
}
-static int pci171x_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pci1710_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val = s->readback[chan];
- int i;
-
- devpriv->da_ranges &= ~(1 << (chan << 1));
- devpriv->da_ranges |= (range << (chan << 1));
- outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
-
- for (i = 0; i < insn->n; i++) {
- val = data[i];
- outw(val, dev->iobase + PCI171X_DA_REG(chan));
- }
-
- s->readback[chan] = val;
-
- return insn->n;
-}
-
-static int pci171x_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- data[1] = inw(dev->iobase + PCI171X_DI_REG);
-
- return insn->n;
-}
-
-static int pci171x_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (comedi_dio_update_state(s, data))
- outw(s->state, dev->iobase + PCI171X_DO_REG);
-
- data[1] = s->state;
-
- return insn->n;
-}
-
-static int pci1720_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pci1710_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val;
- int i;
-
- val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
- val |= (range << (chan << 1));
- if (val != devpriv->da_ranges) {
- outb(val, dev->iobase + PCI1720_RANGE_REG);
- devpriv->da_ranges = val;
- }
-
- val = s->readback[chan];
- for (i = 0; i < insn->n; i++) {
- val = data[i];
- outw(val, dev->iobase + PCI1720_DA_REG(chan));
- outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */
- }
-
- s->readback[chan] = val;
-
- return insn->n;
-}
-
-static int pci171x_ai_cancel(struct comedi_device *dev,
+static int pci1710_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pci1710_private *devpriv = dev->private;
- devpriv->ctrl &= PCI171X_CTRL_CNT0;
- devpriv->ctrl |= PCI171X_CTRL_SW;
- /* reset any operations */
+ /* disable A/D triggers and interrupt sources */
+ devpriv->ctrl &= PCI171X_CTRL_CNT0; /* preserve counter 0 clk src */
outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
+
+ /* disable pacer */
comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
+
+ /* clear A/D FIFO and any pending interrutps */
outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
outb(0, dev->iobase + PCI171X_CLRINT_REG);
@@ -535,7 +413,7 @@ static void pci1710_handle_every_sample(struct comedi_device *dev,
outb(0, dev->iobase + PCI171X_CLRINT_REG);
for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) {
- ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
+ ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
if (ret) {
s->async->events |= COMEDI_CB_ERROR;
break;
@@ -579,7 +457,7 @@ static void pci1710_handle_fifo(struct comedi_device *dev,
unsigned int val;
int ret;
- ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
+ ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
if (ret) {
s->async->events |= COMEDI_CB_ERROR;
break;
@@ -598,7 +476,7 @@ static void pci1710_handle_fifo(struct comedi_device *dev,
outb(0, dev->iobase + PCI171X_CLRINT_REG);
}
-static irqreturn_t interrupt_service_pci1710(int irq, void *d)
+static irqreturn_t pci1710_irq_handler(int irq, void *d)
{
struct comedi_device *dev = d;
struct pci1710_private *devpriv = dev->private;
@@ -624,7 +502,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
outb(0, dev->iobase + PCI171X_CLRINT_REG);
/* no sample on this interrupt; reset the channel interval */
- outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG);
+ outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG);
outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
return IRQ_HANDLED;
@@ -640,12 +518,12 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
return IRQ_HANDLED;
}
-static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+static int pci1710_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pci1710_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
+ pci1710_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
devpriv->saved_seglen);
outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
@@ -681,7 +559,7 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-static int pci171x_ai_cmdtest(struct comedi_device *dev,
+static int pci1710_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
@@ -745,7 +623,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
/* Step 5: check channel list */
- err |= pci171x_ai_check_chanlist(dev, s, cmd);
+ err |= pci1710_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -753,7 +631,55 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
return 0;
}
-static int pci171x_insn_counter_config(struct comedi_device *dev,
+static int pci1710_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pci1710_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val = s->readback[chan];
+ int i;
+
+ devpriv->da_ranges &= ~PCI171X_DAREF_MASK(chan);
+ devpriv->da_ranges |= PCI171X_DAREF(chan, range);
+ outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ outw(val, dev->iobase + PCI171X_DA_REG(chan));
+ }
+
+ s->readback[chan] = val;
+
+ return insn->n;
+}
+
+static int pci1710_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inw(dev->iobase + PCI171X_DI_REG);
+
+ return insn->n;
+}
+
+static int pci1710_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data))
+ outw(s->state, dev->iobase + PCI171X_DO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int pci1710_counter_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -780,7 +706,7 @@ static int pci171x_insn_counter_config(struct comedi_device *dev,
data[2] = 0;
} else {
data[1] = 0;
- data[2] = I8254_OSC_BASE_10MHZ;
+ data[2] = I8254_OSC_BASE_1MHZ;
}
break;
default:
@@ -790,56 +716,29 @@ static int pci171x_insn_counter_config(struct comedi_device *dev,
return insn->n;
}
-static int pci171x_reset(struct comedi_device *dev)
+static void pci1710_reset(struct comedi_device *dev)
{
const struct boardtype *board = dev->board_ptr;
- struct pci1710_private *devpriv = dev->private;
- /* Software trigger, CNT0=external */
- devpriv->ctrl = PCI171X_CTRL_SW | PCI171X_CTRL_CNT0;
- /* reset any operations */
- outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
+ /*
+ * Disable A/D triggers and interrupt sources, set counter 0
+ * to use internal 1 MHz clock.
+ */
+ outw(0, dev->iobase + PCI171X_CTRL_REG);
+
+ /* clear A/D FIFO and any pending interrutps */
outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
outb(0, dev->iobase + PCI171X_CLRINT_REG);
- devpriv->da_ranges = 0;
+
if (board->has_ao) {
/* set DACs to 0..5V and outputs to 0V */
- outb(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
+ outb(0, dev->iobase + PCI171X_DAREF_REG);
outw(0, dev->iobase + PCI171X_DA_REG(0));
outw(0, dev->iobase + PCI171X_DA_REG(1));
}
- outw(0, dev->iobase + PCI171X_DO_REG); /* digital outputs to 0 */
- outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
- outb(0, dev->iobase + PCI171X_CLRINT_REG);
- return 0;
-}
-
-static int pci1720_reset(struct comedi_device *dev)
-{
- struct pci1710_private *devpriv = dev->private;
- /* set synchronous output mode */
- outb(PCI1720_SYNC_CTRL_SC0, dev->iobase + PCI1720_SYNC_CTRL_REG);
- devpriv->da_ranges = 0xAA;
- /* set all ranges to +/-5V and outputs to 0V */
- outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE_REG);
- outw(0x0800, dev->iobase + PCI1720_DA_REG(0));
- outw(0x0800, dev->iobase + PCI1720_DA_REG(1));
- outw(0x0800, dev->iobase + PCI1720_DA_REG(2));
- outw(0x0800, dev->iobase + PCI1720_DA_REG(3));
- outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */
-
- return 0;
-}
-
-static int pci1710_reset(struct comedi_device *dev)
-{
- const struct boardtype *board = dev->board_ptr;
-
- if (board->is_pci1720)
- return pci1720_reset(dev);
-
- return pci171x_reset(dev);
+ /* set digital outputs to 0 */
+ outw(0, dev->iobase + PCI171X_DO_REG);
}
static int pci1710_auto_attach(struct comedi_device *dev,
@@ -850,6 +749,7 @@ static int pci1710_auto_attach(struct comedi_device *dev,
struct pci1710_private *devpriv;
struct comedi_subdevice *s;
int ret, subdev, n_subdevices;
+ int i;
if (context < ARRAY_SIZE(boardtypes))
board = &boardtypes[context];
@@ -872,15 +772,16 @@ static int pci1710_auto_attach(struct comedi_device *dev,
if (!dev->pacer)
return -ENOMEM;
- n_subdevices = 0;
- if (board->n_aichan)
- n_subdevices++;
+ n_subdevices = 1; /* all boards have analog inputs */
if (board->has_ao)
n_subdevices++;
- if (board->has_di_do)
- n_subdevices += 2;
- if (board->has_counter)
- n_subdevices++;
+ if (!board->is_pci1713) {
+ /*
+ * All other boards have digital inputs and outputs as
+ * well as a user counter.
+ */
+ n_subdevices += 3;
+ }
ret = comedi_alloc_subdevices(dev, n_subdevices);
if (ret)
@@ -888,8 +789,8 @@ static int pci1710_auto_attach(struct comedi_device *dev,
pci1710_reset(dev);
- if (board->has_irq && pcidev->irq) {
- ret = request_irq(pcidev->irq, interrupt_service_pci1710,
+ if (pcidev->irq) {
+ ret = request_irq(pcidev->irq, pci1710_irq_handler,
IRQF_SHARED, dev->board_name, dev);
if (ret == 0)
dev->irq = pcidev->irq;
@@ -897,109 +798,89 @@ static int pci1710_auto_attach(struct comedi_device *dev,
subdev = 0;
- if (board->n_aichan) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
- if (board->has_diff_ai)
- s->subdev_flags |= SDF_DIFF;
- s->n_chan = board->n_aichan;
- s->maxdata = 0x0fff;
- s->range_table = board->rangelist_ai;
- s->insn_read = pci171x_ai_insn_read;
- if (dev->irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = s->n_chan;
- s->do_cmdtest = pci171x_ai_cmdtest;
- s->do_cmd = pci171x_ai_cmd;
- s->cancel = pci171x_ai_cancel;
+ /* Analog Input subdevice */
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ if (!board->is_pci1711)
+ s->subdev_flags |= SDF_DIFF;
+ s->n_chan = board->is_pci1713 ? 32 : 16;
+ s->maxdata = 0x0fff;
+ s->range_table = board->ai_range;
+ s->insn_read = pci1710_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = pci1710_ai_cmdtest;
+ s->do_cmd = pci1710_ai_cmd;
+ s->cancel = pci1710_ai_cancel;
+ }
+
+ /* find the value needed to adjust for unipolar gain codes */
+ for (i = 0; i < s->range_table->length; i++) {
+ if (comedi_range_is_unipolar(s, i)) {
+ devpriv->unipolar_gain = i;
+ break;
}
- subdev++;
}
if (board->has_ao) {
- s = &dev->subdevices[subdev];
+ /* Analog Output subdevice */
+ s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = 2;
s->maxdata = 0x0fff;
- if (board->is_pci1720) {
- s->n_chan = 4;
- s->range_table = &pci1720_ao_range;
- s->insn_write = pci1720_ao_insn_write;
- } else {
- s->n_chan = 2;
- s->range_table = &pci171x_ao_range;
- s->insn_write = pci171x_ao_insn_write;
- }
+ s->range_table = &pci171x_ao_range;
+ s->insn_write = pci1710_ao_insn_write;
ret = comedi_alloc_subdev_readback(s);
if (ret)
return ret;
-
- /* initialize the readback values to match the board reset */
- if (board->is_pci1720) {
- int i;
-
- for (i = 0; i < s->n_chan; i++)
- s->readback[i] = 0x0800;
- }
-
- subdev++;
}
- if (board->has_di_do) {
- s = &dev->subdevices[subdev];
+ if (!board->is_pci1713) {
+ /* Digital Input subdevice */
+ s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = 16;
s->maxdata = 1;
s->range_table = &range_digital;
- s->insn_bits = pci171x_di_insn_bits;
- subdev++;
+ s->insn_bits = pci1710_di_insn_bits;
- s = &dev->subdevices[subdev];
+ /* Digital Output subdevice */
+ s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 16;
s->maxdata = 1;
s->range_table = &range_digital;
- s->insn_bits = pci171x_do_insn_bits;
- subdev++;
- }
+ s->insn_bits = pci1710_do_insn_bits;
- /* Counter subdevice (8254) */
- if (board->has_counter) {
- s = &dev->subdevices[subdev];
+ /* Counter subdevice (8254) */
+ s = &dev->subdevices[subdev++];
comedi_8254_subdevice_init(s, dev->pacer);
- dev->pacer->insn_config = pci171x_insn_counter_config;
+ dev->pacer->insn_config = pci1710_counter_insn_config;
/* counters 1 and 2 are used internally for the pacer */
comedi_8254_set_busy(dev->pacer, 1, true);
comedi_8254_set_busy(dev->pacer, 2, true);
-
- subdev++;
}
/* max_samples is half the FIFO size (2 bytes/sample) */
- devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
+ devpriv->max_samples = (board->is_pci1711) ? 512 : 2048;
return 0;
}
-static void pci1710_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- pci1710_reset(dev);
- comedi_pci_detach(dev);
-}
-
static struct comedi_driver adv_pci1710_driver = {
.driver_name = "adv_pci1710",
.module = THIS_MODULE,
.auto_attach = pci1710_auto_attach,
- .detach = pci1710_detach,
+ .detach = comedi_pci_detach,
};
static int adv_pci1710_pci_probe(struct pci_dev *dev,
@@ -1063,7 +944,6 @@ static const struct pci_device_id adv_pci1710_pci_table[] = {
},
{ PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
{ PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
- { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
{ PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/adv_pci1720.c b/drivers/staging/comedi/drivers/adv_pci1720.c
new file mode 100644
index 000000000000..4830a1c93d15
--- /dev/null
+++ b/drivers/staging/comedi/drivers/adv_pci1720.c
@@ -0,0 +1,195 @@
+/*
+ * COMEDI driver for Advantech PCI-1720U
+ * Copyright (c) 2015 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Separated from the adv_pci1710 driver written by:
+ * Michal Dobes <dobes@tesnet.cz>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.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.
+ */
+
+/*
+ * Driver: adv_pci1720
+ * Description: 4-channel Isolated D/A Output board
+ * Devices: [Advantech] PCI-7120U (adv_pci1720)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Fri, 29 Oct 2015 17:19:35 -0700
+ * Status: untested
+ *
+ * Configuration options: not applicable, uses PCI auto config
+ *
+ * The PCI-1720 has 4 isolated 12-bit analog output channels with multiple
+ * output ranges. It also has a BoardID switch to allow differentiating
+ * multiple boards in the system.
+ *
+ * The analog outputs can operate in two modes, immediate and synchronized.
+ * This driver currently does not support the synchronized output mode.
+ *
+ * Jumpers JP1 to JP4 are used to set the current sink ranges for each
+ * analog output channel. In order to use the current sink ranges, the
+ * unipolar 5V range must be used. The voltage output and sink output for
+ * each channel is available on the connector as separate pins.
+ *
+ * Jumper JP5 controls the "hot" reset state of the analog outputs.
+ * Depending on its setting, the analog outputs will either keep the
+ * last settings and output values or reset to the default state after
+ * a "hot" reset. The default state for all channels is uniploar 5V range
+ * and all the output values are 0V. To allow this feature to work, the
+ * analog outputs are not "reset" when the driver attaches.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include "../comedi_pci.h"
+
+/*
+ * PCI BAR2 Register map (dev->iobase)
+ */
+#define PCI1720_AO_LSB_REG(x) (0x00 + ((x) * 2))
+#define PCI1720_AO_MSB_REG(x) (0x01 + ((x) * 2))
+#define PCI1720_AO_RANGE_REG 0x08
+#define PCI1720_AO_RANGE(c, r) (((r) & 0x3) << ((c) * 2))
+#define PCI1720_AO_RANGE_MASK(c) PCI1720_AO_RANGE((c), 0x3)
+#define PCI1720_SYNC_REG 0x09
+#define PCI1720_SYNC_CTRL_REG 0x0f
+#define PCI1720_SYNC_CTRL_SC0 BIT(0)
+#define PCI1720_BOARDID_REG 0x14
+
+static const struct comedi_lrange pci1720_ao_range = {
+ 4, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10)
+ }
+};
+
+static int pci1720_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ /* set the channel range and polarity */
+ val = inb(dev->iobase + PCI1720_AO_RANGE_REG);
+ val &= ~PCI1720_AO_RANGE_MASK(chan);
+ val |= PCI1720_AO_RANGE(chan, range);
+ outb(val, dev->iobase + PCI1720_AO_RANGE_REG);
+
+ val = s->readback[chan];
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ outb(val & 0xff, dev->iobase + PCI1720_AO_LSB_REG(chan));
+ outb((val >> 8) & 0xff, dev->iobase + PCI1720_AO_MSB_REG(chan));
+
+ /* conversion time is 2us (500 kHz throughput) */
+ usleep_range(2, 100);
+ }
+
+ s->readback[chan] = val;
+
+ return insn->n;
+}
+
+static int pci1720_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCI1720_BOARDID_REG);
+
+ return insn->n;
+}
+
+static int pci1720_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct comedi_subdevice *s;
+ int ret;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+ dev->iobase = pci_resource_start(pcidev, 2);
+
+ ret = comedi_alloc_subdevices(dev, 2);
+ if (ret)
+ return ret;
+
+ /* Analog Output subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0x0fff;
+ s->range_table = &pci1720_ao_range;
+ s->insn_write = pci1720_ao_insn_write;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
+ /* Digital Input subdevice (BoardID SW1) */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci1720_di_insn_bits;
+
+ /* disable synchronized output, channels update when written */
+ outb(0, dev->iobase + PCI1720_SYNC_CTRL_REG);
+
+ return 0;
+}
+
+static struct comedi_driver adv_pci1720_driver = {
+ .driver_name = "adv_pci1720",
+ .module = THIS_MODULE,
+ .auto_attach = pci1720_auto_attach,
+ .detach = comedi_pci_detach,
+};
+
+static int adv_pci1720_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &adv_pci1720_driver,
+ id->driver_data);
+}
+
+static const struct pci_device_id adv_pci1720_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adv_pci1720_pci_table);
+
+static struct pci_driver adv_pci1720_pci_driver = {
+ .name = "adv_pci1720",
+ .id_table = adv_pci1720_pci_table,
+ .probe = adv_pci1720_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+module_comedi_pci_driver(adv_pci1720_driver, adv_pci1720_pci_driver);
+
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi driver for Advantech PCI-1720 Analog Output board");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci1760.c b/drivers/staging/comedi/drivers/adv_pci1760.c
new file mode 100644
index 000000000000..d7dd1e55e347
--- /dev/null
+++ b/drivers/staging/comedi/drivers/adv_pci1760.c
@@ -0,0 +1,432 @@
+/*
+ * COMEDI driver for the Advantech PCI-1760
+ * Copyright (C) 2015 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on the pci1760 support in the adv_pci_dio driver written by:
+ * Michal Dobes <dobes@tesnet.cz>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.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.
+ */
+
+/*
+ * Driver: adv_pci1760
+ * Description: Advantech PCI-1760 Relay & Isolated Digital Input Card
+ * Devices: [Advantech] PCI-1760 (adv_pci1760)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Fri, 13 Nov 2015 12:34:00 -0700
+ * Status: untested
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ */
+
+#include <linux/module.h>
+
+#include "../comedi_pci.h"
+
+/*
+ * PCI-1760 Register Map
+ *
+ * Outgoing Mailbox Bytes
+ * OMB3: Not used (must be 0)
+ * OMB2: The command code to the PCI-1760
+ * OMB1: The hi byte of the parameter for the command in OMB2
+ * OMB0: The lo byte of the parameter for the command in OMB2
+ *
+ * Incoming Mailbox Bytes
+ * IMB3: The Isolated Digital Input status (updated every 100us)
+ * IMB2: The current command (matches OMB2 when command is successful)
+ * IMB1: The hi byte of the feedback data for the command in OMB2
+ * IMB0: The lo byte of the feedback data for the command in OMB2
+ *
+ * Interrupt Control/Status
+ * INTCSR3: Not used (must be 0)
+ * INTCSR2: The interrupt status (read only)
+ * INTCSR1: Interrupt enable/disable
+ * INTCSR0: Not used (must be 0)
+ */
+#define PCI1760_OMB_REG(x) (0x0c + (x))
+#define PCI1760_IMB_REG(x) (0x1c + (x))
+#define PCI1760_INTCSR_REG(x) (0x38 + (x))
+#define PCI1760_INTCSR1_IRQ_ENA BIT(5)
+#define PCI1760_INTCSR2_OMB_IRQ BIT(0)
+#define PCI1760_INTCSR2_IMB_IRQ BIT(1)
+#define PCI1760_INTCSR2_IRQ_STATUS BIT(6)
+#define PCI1760_INTCSR2_IRQ_ASSERTED BIT(7)
+
+/* PCI-1760 command codes */
+#define PCI1760_CMD_CLR_IMB2 0x00 /* Clears IMB2 */
+#define PCI1760_CMD_SET_DO 0x01 /* Set output state */
+#define PCI1760_CMD_GET_DO 0x02 /* Read output status */
+#define PCI1760_CMD_GET_STATUS 0x03 /* Read current status */
+#define PCI1760_CMD_GET_FW_VER 0x0e /* Read firware version */
+#define PCI1760_CMD_GET_HW_VER 0x0f /* Read hardware version */
+#define PCI1760_CMD_SET_PWM_HI(x) (0x10 + (x) * 2) /* Set "hi" period */
+#define PCI1760_CMD_SET_PWM_LO(x) (0x11 + (x) * 2) /* Set "lo" period */
+#define PCI1760_CMD_SET_PWM_CNT(x) (0x14 + (x)) /* Set burst count */
+#define PCI1760_CMD_ENA_PWM 0x1f /* Enable PWM outputs */
+#define PCI1760_CMD_ENA_FILT 0x20 /* Enable input filter */
+#define PCI1760_CMD_ENA_PAT_MATCH 0x21 /* Enable input pattern match */
+#define PCI1760_CMD_SET_PAT_MATCH 0x22 /* Set input pattern match */
+#define PCI1760_CMD_ENA_RISE_EDGE 0x23 /* Enable input rising edge */
+#define PCI1760_CMD_ENA_FALL_EDGE 0x24 /* Enable input falling edge */
+#define PCI1760_CMD_ENA_CNT 0x28 /* Enable counter */
+#define PCI1760_CMD_RST_CNT 0x29 /* Reset counter */
+#define PCI1760_CMD_ENA_CNT_OFLOW 0x2a /* Enable counter overflow */
+#define PCI1760_CMD_ENA_CNT_MATCH 0x2b /* Enable counter match */
+#define PCI1760_CMD_SET_CNT_EDGE 0x2c /* Set counter edge */
+#define PCI1760_CMD_GET_CNT 0x2f /* Reads counter value */
+#define PCI1760_CMD_SET_HI_SAMP(x) (0x30 + (x)) /* Set "hi" sample time */
+#define PCI1760_CMD_SET_LO_SAMP(x) (0x38 + (x)) /* Set "lo" sample time */
+#define PCI1760_CMD_SET_CNT(x) (0x40 + (x)) /* Set counter reset val */
+#define PCI1760_CMD_SET_CNT_MATCH(x) (0x48 + (x)) /* Set counter match val */
+#define PCI1760_CMD_GET_INT_FLAGS 0x60 /* Read interrupt flags */
+#define PCI1760_CMD_GET_INT_FLAGS_MATCH BIT(0)
+#define PCI1760_CMD_GET_INT_FLAGS_COS BIT(1)
+#define PCI1760_CMD_GET_INT_FLAGS_OFLOW BIT(2)
+#define PCI1760_CMD_GET_OS 0x61 /* Read edge change flags */
+#define PCI1760_CMD_GET_CNT_STATUS 0x62 /* Read counter oflow/match */
+
+#define PCI1760_CMD_TIMEOUT 250 /* 250 usec timeout */
+#define PCI1760_CMD_RETRIES 3 /* limit number of retries */
+
+#define PCI1760_PWM_TIMEBASE 100000 /* 1 unit = 100 usec */
+
+static int pci1760_send_cmd(struct comedi_device *dev,
+ unsigned char cmd, unsigned short val)
+{
+ unsigned long timeout;
+
+ /* send the command and parameter */
+ outb(val & 0xff, dev->iobase + PCI1760_OMB_REG(0));
+ outb((val >> 8) & 0xff, dev->iobase + PCI1760_OMB_REG(1));
+ outb(cmd, dev->iobase + PCI1760_OMB_REG(2));
+ outb(0, dev->iobase + PCI1760_OMB_REG(3));
+
+ /* datasheet says to allow up to 250 usec for the command to complete */
+ timeout = jiffies + usecs_to_jiffies(PCI1760_CMD_TIMEOUT);
+ do {
+ if (inb(dev->iobase + PCI1760_IMB_REG(2)) == cmd) {
+ /* command success; return the feedback data */
+ return inb(dev->iobase + PCI1760_IMB_REG(0)) |
+ (inb(dev->iobase + PCI1760_IMB_REG(1)) << 8);
+ }
+ cpu_relax();
+ } while (time_before(jiffies, timeout));
+
+ return -EBUSY;
+}
+
+static int pci1760_cmd(struct comedi_device *dev,
+ unsigned char cmd, unsigned short val)
+{
+ int repeats;
+ int ret;
+
+ /* send PCI1760_CMD_CLR_IMB2 between identical commands */
+ if (inb(dev->iobase + PCI1760_IMB_REG(2)) == cmd) {
+ ret = pci1760_send_cmd(dev, PCI1760_CMD_CLR_IMB2, 0);
+ if (ret < 0) {
+ /* timeout? try it once more */
+ ret = pci1760_send_cmd(dev, PCI1760_CMD_CLR_IMB2, 0);
+ if (ret < 0)
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* datasheet says to keep retrying the command */
+ for (repeats = 0; repeats < PCI1760_CMD_RETRIES; repeats++) {
+ ret = pci1760_send_cmd(dev, cmd, val);
+ if (ret >= 0)
+ return ret;
+ }
+
+ /* command failed! */
+ return -ETIMEDOUT;
+}
+
+static int pci1760_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCI1760_IMB_REG(3));
+
+ return insn->n;
+}
+
+static int pci1760_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ int ret;
+
+ if (comedi_dio_update_state(s, data)) {
+ ret = pci1760_cmd(dev, PCI1760_CMD_SET_DO, s->state);
+ if (ret < 0)
+ return ret;
+ }
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int pci1760_pwm_ns_to_div(unsigned int flags, unsigned int ns)
+{
+ unsigned int divisor;
+
+ switch (flags) {
+ case CMDF_ROUND_NEAREST:
+ divisor = DIV_ROUND_CLOSEST(ns, PCI1760_PWM_TIMEBASE);
+ break;
+ case CMDF_ROUND_UP:
+ divisor = DIV_ROUND_UP(ns, PCI1760_PWM_TIMEBASE);
+ break;
+ case CMDF_ROUND_DOWN:
+ divisor = ns / PCI1760_PWM_TIMEBASE;
+ default:
+ return -EINVAL;
+ }
+
+ if (divisor < 1)
+ divisor = 1;
+ if (divisor > 0xffff)
+ divisor = 0xffff;
+
+ return divisor;
+}
+
+static int pci1760_pwm_enable(struct comedi_device *dev,
+ unsigned int chan, bool enable)
+{
+ int ret;
+
+ ret = pci1760_cmd(dev, PCI1760_CMD_GET_STATUS, PCI1760_CMD_ENA_PWM);
+ if (ret < 0)
+ return ret;
+
+ if (enable)
+ ret |= BIT(chan);
+ else
+ ret &= ~BIT(chan);
+
+ return pci1760_cmd(dev, PCI1760_CMD_ENA_PWM, ret);
+}
+
+static int pci1760_pwm_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int hi_div;
+ int lo_div;
+ int ret;
+
+ switch (data[0]) {
+ case INSN_CONFIG_ARM:
+ ret = pci1760_pwm_enable(dev, chan, false);
+ if (ret < 0)
+ return ret;
+
+ if (data[1] > 0xffff)
+ return -EINVAL;
+ ret = pci1760_cmd(dev, PCI1760_CMD_SET_PWM_CNT(chan), data[1]);
+ if (ret < 0)
+ return ret;
+
+ ret = pci1760_pwm_enable(dev, chan, true);
+ if (ret < 0)
+ return ret;
+ break;
+ case INSN_CONFIG_DISARM:
+ ret = pci1760_pwm_enable(dev, chan, false);
+ if (ret < 0)
+ return ret;
+ break;
+ case INSN_CONFIG_PWM_OUTPUT:
+ ret = pci1760_pwm_enable(dev, chan, false);
+ if (ret < 0)
+ return ret;
+
+ hi_div = pci1760_pwm_ns_to_div(data[1], data[2]);
+ lo_div = pci1760_pwm_ns_to_div(data[3], data[4]);
+ if (hi_div < 0 || lo_div < 0)
+ return -EINVAL;
+ if ((hi_div * PCI1760_PWM_TIMEBASE) != data[2] ||
+ (lo_div * PCI1760_PWM_TIMEBASE) != data[4]) {
+ data[2] = hi_div * PCI1760_PWM_TIMEBASE;
+ data[4] = lo_div * PCI1760_PWM_TIMEBASE;
+ return -EAGAIN;
+ }
+ ret = pci1760_cmd(dev, PCI1760_CMD_SET_PWM_HI(chan), hi_div);
+ if (ret < 0)
+ return ret;
+ ret = pci1760_cmd(dev, PCI1760_CMD_SET_PWM_LO(chan), lo_div);
+ if (ret < 0)
+ return ret;
+ break;
+ case INSN_CONFIG_GET_PWM_OUTPUT:
+ hi_div = pci1760_cmd(dev, PCI1760_CMD_GET_STATUS,
+ PCI1760_CMD_SET_PWM_HI(chan));
+ lo_div = pci1760_cmd(dev, PCI1760_CMD_GET_STATUS,
+ PCI1760_CMD_SET_PWM_LO(chan));
+ if (hi_div < 0 || lo_div < 0)
+ return -ETIMEDOUT;
+
+ data[1] = hi_div * PCI1760_PWM_TIMEBASE;
+ data[2] = lo_div * PCI1760_PWM_TIMEBASE;
+ break;
+ case INSN_CONFIG_GET_PWM_STATUS:
+ ret = pci1760_cmd(dev, PCI1760_CMD_GET_STATUS,
+ PCI1760_CMD_ENA_PWM);
+ if (ret < 0)
+ return ret;
+
+ data[1] = (ret & BIT(chan)) ? 1 : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return insn->n;
+}
+
+static void pci1760_reset(struct comedi_device *dev)
+{
+ int i;
+
+ /* disable interrupts (intcsr2 is read-only) */
+ outb(0, dev->iobase + PCI1760_INTCSR_REG(0));
+ outb(0, dev->iobase + PCI1760_INTCSR_REG(1));
+ outb(0, dev->iobase + PCI1760_INTCSR_REG(3));
+
+ /* disable counters */
+ pci1760_cmd(dev, PCI1760_CMD_ENA_CNT, 0);
+
+ /* disable overflow interrupts */
+ pci1760_cmd(dev, PCI1760_CMD_ENA_CNT_OFLOW, 0);
+
+ /* disable match */
+ pci1760_cmd(dev, PCI1760_CMD_ENA_CNT_MATCH, 0);
+
+ /* set match and counter reset values */
+ for (i = 0; i < 8; i++) {
+ pci1760_cmd(dev, PCI1760_CMD_SET_CNT_MATCH(i), 0x8000);
+ pci1760_cmd(dev, PCI1760_CMD_SET_CNT(i), 0x0000);
+ }
+
+ /* reset counters to reset values */
+ pci1760_cmd(dev, PCI1760_CMD_RST_CNT, 0xff);
+
+ /* set counter count edges */
+ pci1760_cmd(dev, PCI1760_CMD_SET_CNT_EDGE, 0);
+
+ /* disable input filters */
+ pci1760_cmd(dev, PCI1760_CMD_ENA_FILT, 0);
+
+ /* disable pattern matching */
+ pci1760_cmd(dev, PCI1760_CMD_ENA_PAT_MATCH, 0);
+
+ /* set pattern match value */
+ pci1760_cmd(dev, PCI1760_CMD_SET_PAT_MATCH, 0);
+}
+
+static int pci1760_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct comedi_subdevice *s;
+ int ret;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+ dev->iobase = pci_resource_start(pcidev, 0);
+
+ pci1760_reset(dev);
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
+
+ /* Digital Input subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci1760_di_insn_bits;
+
+ /* Digital Output subdevice */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci1760_do_insn_bits;
+
+ /* get the current state of the outputs */
+ ret = pci1760_cmd(dev, PCI1760_CMD_GET_DO, 0);
+ if (ret < 0)
+ return ret;
+ s->state = ret;
+
+ /* PWM subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_PWM;
+ s->subdev_flags = SDF_PWM_COUNTER;
+ s->n_chan = 2;
+ s->insn_config = pci1760_pwm_insn_config;
+
+ /* Counter subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_UNUSED;
+
+ return 0;
+}
+
+static struct comedi_driver pci1760_driver = {
+ .driver_name = "adv_pci1760",
+ .module = THIS_MODULE,
+ .auto_attach = pci1760_auto_attach,
+ .detach = comedi_pci_detach,
+};
+
+static int pci1760_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &pci1760_driver, id->driver_data);
+}
+
+static const struct pci_device_id pci1760_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, pci1760_pci_table);
+
+static struct pci_driver pci1760_pci_driver = {
+ .name = "adv_pci1760",
+ .id_table = pci1760_pci_table,
+ .probe = pci1760_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+module_comedi_pci_driver(pci1760_driver, pci1760_pci_driver);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi driver for Advantech PCI-1760");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index f1b3c5aa8d79..620cec13d74c 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -4,30 +4,21 @@
* Author: Michal Dobes <dobes@tesnet.cz>
*
* Hardware driver for Advantech PCI DIO cards.
-*/
-/*
-Driver: adv_pci_dio
-Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
- PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752,
- PCI-1753/E, PCI-1754, PCI-1756, PCI-1760, PCI-1762
-Author: Michal Dobes <dobes@tesnet.cz>
-Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
- PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
- PCI-1751, PCI-1752, PCI-1753,
- PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
- PCI-1760, PCI-1762
-Status: untested
-Updated: Mon, 09 Jan 2012 12:40:46 +0000
-
-This driver supports now only insn interface for DI/DO/DIO.
+ */
-Configuration options:
- [0] - PCI bus of device (optional)
- [1] - PCI slot of device (optional)
- If bus/slot is not specified, the first available PCI
- device will be used.
-
-*/
+/*
+ * Driver: adv_pci_dio
+ * Description: Advantech Digital I/O Cards
+ * Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
+ * PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
+ * PCI-1751, PCI-1752, PCI-1753, PCI-1753+PCI-1753E,
+ * PCI-1754, PCI-1756, PCI-1762
+ * Author: Michal Dobes <dobes@tesnet.cz>
+ * Updated: Mon, 09 Jan 2012 12:40:46 +0000
+ * Status: untested
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ */
#include <linux/module.h>
#include <linux/delay.h>
@@ -37,403 +28,199 @@ Configuration options:
#include "8255.h"
#include "comedi_8254.h"
-/* hardware types of the cards */
-enum hw_cards_id {
- TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
- TYPE_PCI1739,
- TYPE_PCI1750,
- TYPE_PCI1751,
- TYPE_PCI1752,
- TYPE_PCI1753, TYPE_PCI1753E,
- TYPE_PCI1754, TYPE_PCI1756,
- TYPE_PCI1760,
- TYPE_PCI1762
-};
-
-/* which I/O instructions to use */
-enum hw_io_access {
- IO_8b, IO_16b
-};
-
-#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
-#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
-#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per
- * card */
-
-#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
-
-/* Register offset definitions */
-/* Advantech PCI-1730/3/4 */
-#define PCI1730_IDI 0 /* R: Isolated digital input 0-15 */
-#define PCI1730_IDO 0 /* W: Isolated digital output 0-15 */
-#define PCI1730_DI 2 /* R: Digital input 0-15 */
-#define PCI1730_DO 2 /* W: Digital output 0-15 */
-#define PCI1733_IDI 0 /* R: Isolated digital input 0-31 */
-#define PCI1730_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
-#define PCI1730_3_INT_RF 0x0c /* R/W: set falling/raising edge for
- * interrupts */
-#define PCI1730_3_INT_CLR 0x10 /* R/W: clear interrupts */
-#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */
-#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */
-
-/* Advantech PCI-1735U */
-#define PCI1735_DI 0 /* R: Digital input 0-31 */
-#define PCI1735_DO 0 /* W: Digital output 0-31 */
-#define PCI1735_C8254 4 /* R/W: 8254 counter */
-#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */
-
-/* Advantech PCI-1736UP */
-#define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */
-#define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */
-#define PCI1736_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
-#define PCI1736_3_INT_RF 0x0c /* R/W: set falling/raising edge for
- * interrupts */
-#define PCI1736_3_INT_CLR 0x10 /* R/W: clear interrupts */
-#define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */
-#define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */
+/*
+ * Register offset definitions
+ */
-/* Advantech PCI-1739U */
-#define PCI1739_DIO 0 /* R/W: begin of 8255 registers block */
-#define PCI1739_ICR 32 /* W: Interrupt control register */
-#define PCI1739_ISR 32 /* R: Interrupt status register */
-#define PCI1739_BOARDID 8 /* R: Board I/D switch for 1739U */
+/* PCI-1730, PCI-1733, PCI-1736 interrupt control registers */
+#define PCI173X_INT_EN_REG 0x08 /* R/W: enable/disable */
+#define PCI173X_INT_RF_REG 0x0c /* R/W: falling/rising edge */
+#define PCI173X_INT_CLR_REG 0x10 /* R/W: clear */
-/* Advantech PCI-1750 */
-#define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */
-#define PCI1750_IDO 0 /* W: Isolated digital output 0-15 */
-#define PCI1750_ICR 32 /* W: Interrupt control register */
-#define PCI1750_ISR 32 /* R: Interrupt status register */
+/* PCI-1739U, PCI-1750, PCI1751 interrupt control registers */
+#define PCI1750_INT_REG 0x20 /* R/W: status/control */
-/* Advantech PCI-1751/3/3E */
-#define PCI1751_DIO 0 /* R/W: begin of 8255 registers block */
-#define PCI1751_CNT 24 /* R/W: begin of 8254 registers block */
-#define PCI1751_ICR 32 /* W: Interrupt control register */
-#define PCI1751_ISR 32 /* R: Interrupt status register */
-#define PCI1753_DIO 0 /* R/W: begin of 8255 registers block */
-#define PCI1753_ICR0 16 /* R/W: Interrupt control register group 0 */
-#define PCI1753_ICR1 17 /* R/W: Interrupt control register group 1 */
-#define PCI1753_ICR2 18 /* R/W: Interrupt control register group 2 */
-#define PCI1753_ICR3 19 /* R/W: Interrupt control register group 3 */
-#define PCI1753E_DIO 32 /* R/W: begin of 8255 registers block */
-#define PCI1753E_ICR0 48 /* R/W: Interrupt control register group 0 */
-#define PCI1753E_ICR1 49 /* R/W: Interrupt control register group 1 */
-#define PCI1753E_ICR2 50 /* R/W: Interrupt control register group 2 */
-#define PCI1753E_ICR3 51 /* R/W: Interrupt control register group 3 */
+/* PCI-1753, PCI-1753E interrupt control registers */
+#define PCI1753_INT_REG(x) (0x10 + (x)) /* R/W: control group 0 to 3 */
+#define PCI1753E_INT_REG(x) (0x30 + (x)) /* R/W: control group 0 to 3 */
-/* Advantech PCI-1752/4/6 */
-#define PCI1752_IDO 0 /* R/W: Digital output 0-31 */
-#define PCI1752_IDO2 4 /* R/W: Digital output 32-63 */
-#define PCI1754_IDI 0 /* R: Digital input 0-31 */
-#define PCI1754_IDI2 4 /* R: Digital input 32-64 */
-#define PCI1756_IDI 0 /* R: Digital input 0-31 */
-#define PCI1756_IDO 4 /* R/W: Digital output 0-31 */
-#define PCI1754_6_ICR0 0x08 /* R/W: Interrupt control register group 0 */
-#define PCI1754_6_ICR1 0x0a /* R/W: Interrupt control register group 1 */
-#define PCI1754_ICR2 0x0c /* R/W: Interrupt control register group 2 */
-#define PCI1754_ICR3 0x0e /* R/W: Interrupt control register group 3 */
-#define PCI1752_6_CFC 0x12 /* R/W: set/read channel freeze function */
-#define PCI175x_BOARDID 0x10 /* R: Board I/D switch for 1752/4/6 */
+/* PCI-1754, PCI-1756 interrupt control registers */
+#define PCI1754_INT_REG(x) (0x08 + (x) * 2) /* R/W: control group 0 to 3 */
-/* Advantech PCI-1762 registers */
-#define PCI1762_RO 0 /* R/W: Relays status/output */
-#define PCI1762_IDI 2 /* R: Isolated input status */
-#define PCI1762_BOARDID 4 /* R: Board I/D switch */
-#define PCI1762_ICR 6 /* W: Interrupt control register */
-#define PCI1762_ISR 6 /* R: Interrupt status register */
+/* PCI-1752, PCI-1756 special registers */
+#define PCI1752_CFC_REG 0x12 /* R/W: channel freeze function */
-/* Advantech PCI-1760 registers */
-#define OMB0 0x0c /* W: Mailbox outgoing registers */
-#define OMB1 0x0d
-#define OMB2 0x0e
-#define OMB3 0x0f
-#define IMB0 0x1c /* R: Mailbox incoming registers */
-#define IMB1 0x1d
-#define IMB2 0x1e
-#define IMB3 0x1f
-#define INTCSR0 0x38 /* R/W: Interrupt control registers */
-#define INTCSR1 0x39
-#define INTCSR2 0x3a
-#define INTCSR3 0x3b
+/* PCI-1762 interrupt control registers */
+#define PCI1762_INT_REG 0x06 /* R/W: status/control */
-/* PCI-1760 mailbox commands */
-#define CMD_ClearIMB2 0x00 /* Clear IMB2 status and return actual
- * DI status in IMB3 */
-#define CMD_SetRelaysOutput 0x01 /* Set relay output from OMB0 */
-#define CMD_GetRelaysStatus 0x02 /* Get relay status to IMB0 */
-#define CMD_ReadCurrentStatus 0x07 /* Read the current status of the
- * register in OMB0, result in IMB0 */
-#define CMD_ReadFirmwareVersion 0x0e /* Read the firmware ver., result in
- * IMB1.IMB0 */
-#define CMD_ReadHardwareVersion 0x0f /* Read the hardware ver., result in
- * IMB1.IMB0 */
-#define CMD_EnableIDIFilters 0x20 /* Enable IDI filters based on bits in
- * OMB0 */
-#define CMD_EnableIDIPatternMatch 0x21 /* Enable IDI pattern match based on
- * bits in OMB0 */
-#define CMD_SetIDIPatternMatch 0x22 /* Enable IDI pattern match based on
- * bits in OMB0 */
-#define CMD_EnableIDICounters 0x28 /* Enable IDI counters based on bits in
- * OMB0 */
-#define CMD_ResetIDICounters 0x29 /* Reset IDI counters based on bits in
- * OMB0 to its reset values */
-#define CMD_OverflowIDICounters 0x2a /* Enable IDI counters overflow
- * interrupts based on bits in OMB0 */
-#define CMD_MatchIntIDICounters 0x2b /* Enable IDI counters match value
- * interrupts based on bits in OMB0 */
-#define CMD_EdgeIDICounters 0x2c /* Set IDI up counters count edge (bit=0
- * - rising, =1 - falling) */
-#define CMD_GetIDICntCurValue 0x2f /* Read IDI{OMB0} up counter current
- * value */
-#define CMD_SetIDI0CntResetValue 0x40 /* Set IDI0 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI1CntResetValue 0x41 /* Set IDI1 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI2CntResetValue 0x42 /* Set IDI2 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI3CntResetValue 0x43 /* Set IDI3 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI4CntResetValue 0x44 /* Set IDI4 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI5CntResetValue 0x45 /* Set IDI5 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI6CntResetValue 0x46 /* Set IDI6 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI7CntResetValue 0x47 /* Set IDI7 Counter Reset Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI0CntMatchValue 0x48 /* Set IDI0 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI1CntMatchValue 0x49 /* Set IDI1 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI2CntMatchValue 0x4a /* Set IDI2 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI3CntMatchValue 0x4b /* Set IDI3 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI4CntMatchValue 0x4c /* Set IDI4 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI5CntMatchValue 0x4d /* Set IDI5 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI6CntMatchValue 0x4e /* Set IDI6 Counter Match Value
- * 256*OMB1+OMB0 */
-#define CMD_SetIDI7CntMatchValue 0x4f /* Set IDI7 Counter Match Value
- * 256*OMB1+OMB0 */
+/* maximum number of subdevice descriptions in the boardinfo */
+#define PCI_DIO_MAX_DI_SUBDEVS 2 /* 2 x 8/16/32 input channels max */
+#define PCI_DIO_MAX_DO_SUBDEVS 2 /* 2 x 8/16/32 output channels max */
+#define PCI_DIO_MAX_DIO_SUBDEVG 2 /* 2 x any number of 8255 devices max */
-#define OMBCMD_RETRY 0x03 /* 3 times try request before error */
+enum pci_dio_boardid {
+ TYPE_PCI1730,
+ TYPE_PCI1733,
+ TYPE_PCI1734,
+ TYPE_PCI1735,
+ TYPE_PCI1736,
+ TYPE_PCI1739,
+ TYPE_PCI1750,
+ TYPE_PCI1751,
+ TYPE_PCI1752,
+ TYPE_PCI1753,
+ TYPE_PCI1753E,
+ TYPE_PCI1754,
+ TYPE_PCI1756,
+ TYPE_PCI1762
+};
struct diosubd_data {
- int chans; /* num of chans */
- int addr; /* PCI address ofset */
- int regs; /* number of registers to read or 8255
- subdevices */
- unsigned int specflags; /* addon subdevice flags */
+ int chans; /* num of chans or 8255 devices */
+ unsigned long addr; /* PCI address ofset */
};
struct dio_boardtype {
const char *name; /* board name */
- int main_pci_region; /* main I/O PCI region */
- enum hw_cards_id cardtype;
int nsubdevs;
- struct diosubd_data sdi[MAX_DI_SUBDEVS]; /* DI chans */
- struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */
- struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */
- struct diosubd_data boardid; /* card supports board ID switch */
+ struct diosubd_data sdi[PCI_DIO_MAX_DI_SUBDEVS];
+ struct diosubd_data sdo[PCI_DIO_MAX_DO_SUBDEVS];
+ struct diosubd_data sdio[PCI_DIO_MAX_DIO_SUBDEVG];
+ unsigned long id_reg;
unsigned long timer_regbase;
- enum hw_io_access io_access;
+ unsigned int is_16bit:1;
};
static const struct dio_boardtype boardtypes[] = {
[TYPE_PCI1730] = {
.name = "pci1730",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1730,
.nsubdevs = 5,
- .sdi[0] = { 16, PCI1730_DI, 2, 0, },
- .sdi[1] = { 16, PCI1730_IDI, 2, 0, },
- .sdo[0] = { 16, PCI1730_DO, 2, 0, },
- .sdo[1] = { 16, PCI1730_IDO, 2, 0, },
- .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_8b,
+ .sdi[0] = { 16, 0x02, }, /* DI 0-15 */
+ .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */
+ .sdo[0] = { 16, 0x02, }, /* DO 0-15 */
+ .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
+ .id_reg = 0x04,
},
[TYPE_PCI1733] = {
.name = "pci1733",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1733,
.nsubdevs = 2,
- .sdi[1] = { 32, PCI1733_IDI, 4, 0, },
- .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_8b,
+ .sdi[1] = { 32, 0x00, }, /* ISO DI 0-31 */
+ .id_reg = 0x04,
},
[TYPE_PCI1734] = {
.name = "pci1734",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1734,
.nsubdevs = 2,
- .sdo[1] = { 32, PCI1734_IDO, 4, 0, },
- .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_8b,
+ .sdo[1] = { 32, 0x00, }, /* ISO DO 0-31 */
+ .id_reg = 0x04,
},
[TYPE_PCI1735] = {
.name = "pci1735",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1735,
.nsubdevs = 4,
- .sdi[0] = { 32, PCI1735_DI, 4, 0, },
- .sdo[0] = { 32, PCI1735_DO, 4, 0, },
- .boardid = { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, },
- .timer_regbase = PCI1735_C8254,
- .io_access = IO_8b,
+ .sdi[0] = { 32, 0x00, }, /* DI 0-31 */
+ .sdo[0] = { 32, 0x00, }, /* DO 0-31 */
+ .id_reg = 0x08,
+ .timer_regbase = 0x04,
},
[TYPE_PCI1736] = {
.name = "pci1736",
- .main_pci_region = PCI1736_MAINREG,
- .cardtype = TYPE_PCI1736,
.nsubdevs = 3,
- .sdi[1] = { 16, PCI1736_IDI, 2, 0, },
- .sdo[1] = { 16, PCI1736_IDO, 2, 0, },
- .boardid = { 4, PCI1736_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_8b,
+ .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */
+ .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
+ .id_reg = 0x04,
},
[TYPE_PCI1739] = {
.name = "pci1739",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1739,
- .nsubdevs = 2,
- .sdio[0] = { 48, PCI1739_DIO, 2, 0, },
- .io_access = IO_8b,
+ .nsubdevs = 3,
+ .sdio[0] = { 2, 0x00, }, /* 8255 DIO */
+ .id_reg = 0x08,
},
[TYPE_PCI1750] = {
.name = "pci1750",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1750,
.nsubdevs = 2,
- .sdi[1] = { 16, PCI1750_IDI, 2, 0, },
- .sdo[1] = { 16, PCI1750_IDO, 2, 0, },
- .io_access = IO_8b,
+ .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */
+ .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
},
[TYPE_PCI1751] = {
.name = "pci1751",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1751,
.nsubdevs = 3,
- .sdio[0] = { 48, PCI1751_DIO, 2, 0, },
- .timer_regbase = PCI1751_CNT,
- .io_access = IO_8b,
+ .sdio[0] = { 2, 0x00, }, /* 8255 DIO */
+ .timer_regbase = 0x18,
},
[TYPE_PCI1752] = {
.name = "pci1752",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1752,
.nsubdevs = 3,
- .sdo[0] = { 32, PCI1752_IDO, 2, 0, },
- .sdo[1] = { 32, PCI1752_IDO2, 2, 0, },
- .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_16b,
+ .sdo[0] = { 32, 0x00, }, /* DO 0-31 */
+ .sdo[1] = { 32, 0x04, }, /* DO 32-63 */
+ .id_reg = 0x10,
+ .is_16bit = 1,
},
[TYPE_PCI1753] = {
.name = "pci1753",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1753,
.nsubdevs = 4,
- .sdio[0] = { 96, PCI1753_DIO, 4, 0, },
- .io_access = IO_8b,
+ .sdio[0] = { 4, 0x00, }, /* 8255 DIO */
},
[TYPE_PCI1753E] = {
.name = "pci1753e",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1753E,
.nsubdevs = 8,
- .sdio[0] = { 96, PCI1753_DIO, 4, 0, },
- .sdio[1] = { 96, PCI1753E_DIO, 4, 0, },
- .io_access = IO_8b,
+ .sdio[0] = { 4, 0x00, }, /* 8255 DIO */
+ .sdio[1] = { 4, 0x20, }, /* 8255 DIO */
},
[TYPE_PCI1754] = {
.name = "pci1754",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1754,
.nsubdevs = 3,
- .sdi[0] = { 32, PCI1754_IDI, 2, 0, },
- .sdi[1] = { 32, PCI1754_IDI2, 2, 0, },
- .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_16b,
+ .sdi[0] = { 32, 0x00, }, /* DI 0-31 */
+ .sdi[1] = { 32, 0x04, }, /* DI 32-63 */
+ .id_reg = 0x10,
+ .is_16bit = 1,
},
[TYPE_PCI1756] = {
.name = "pci1756",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1756,
.nsubdevs = 3,
- .sdi[1] = { 32, PCI1756_IDI, 2, 0, },
- .sdo[1] = { 32, PCI1756_IDO, 2, 0, },
- .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_16b,
- },
- [TYPE_PCI1760] = {
- /* This card has its own 'attach' */
- .name = "pci1760",
- .main_pci_region = 0,
- .cardtype = TYPE_PCI1760,
- .nsubdevs = 4,
- .io_access = IO_8b,
+ .sdi[1] = { 32, 0x00, }, /* DI 0-31 */
+ .sdo[1] = { 32, 0x04, }, /* DO 0-31 */
+ .id_reg = 0x10,
+ .is_16bit = 1,
},
[TYPE_PCI1762] = {
.name = "pci1762",
- .main_pci_region = PCIDIO_MAINREG,
- .cardtype = TYPE_PCI1762,
.nsubdevs = 3,
- .sdi[1] = { 16, PCI1762_IDI, 1, 0, },
- .sdo[1] = { 16, PCI1762_RO, 1, 0, },
- .boardid = { 4, PCI1762_BOARDID, 1, SDF_INTERNAL, },
- .io_access = IO_16b,
+ .sdi[1] = { 16, 0x02, }, /* ISO DI 0-15 */
+ .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
+ .id_reg = 0x04,
+ .is_16bit = 1,
},
};
-struct pci_dio_private {
- char GlobalIrqEnabled; /* 1= any IRQ source is enabled */
- /* PCI-1760 specific data */
- unsigned char IDICntEnable; /* counter's counting enable status */
- unsigned char IDICntOverEnable; /* counter's overflow interrupts enable
- * status */
- unsigned char IDICntMatchEnable; /* counter's match interrupts
- * enable status */
- unsigned char IDICntEdge; /* counter's count edge value
- * (bit=0 - rising, =1 - falling) */
- unsigned short CntResValue[8]; /* counters' reset value */
- unsigned short CntMatchValue[8]; /* counters' match interrupt value */
- unsigned char IDIFiltersEn; /* IDI's digital filters enable status */
- unsigned char IDIPatMatchEn; /* IDI's pattern match enable status */
- unsigned char IDIPatMatchValue; /* IDI's pattern match value */
- unsigned short IDIFiltrLow[8]; /* IDI's filter value low signal */
- unsigned short IDIFiltrHigh[8]; /* IDI's filter value high signal */
-};
-
-/*
-==============================================================================
-*/
static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- const struct diosubd_data *d = (const struct diosubd_data *)s->private;
- int i;
+ unsigned long reg = (unsigned long)s->private;
+ unsigned long iobase = dev->iobase + reg;
- data[1] = 0;
- for (i = 0; i < d->regs; i++)
- data[1] |= inb(dev->iobase + d->addr + i) << (8 * i);
+ data[1] = inb(iobase);
+ if (s->n_chan > 8)
+ data[1] |= (inb(iobase + 1) << 8);
+ if (s->n_chan > 16)
+ data[1] |= (inb(iobase + 2) << 16);
+ if (s->n_chan > 24)
+ data[1] |= (inb(iobase + 3) << 24);
return insn->n;
}
-/*
-==============================================================================
-*/
static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- const struct diosubd_data *d = (const struct diosubd_data *)s->private;
- int i;
+ unsigned long reg = (unsigned long)s->private;
+ unsigned long iobase = dev->iobase + reg;
- data[1] = 0;
- for (i = 0; i < d->regs; i++)
- data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i);
+ data[1] = inw(iobase);
+ if (s->n_chan > 16)
+ data[1] |= (inw(iobase + 2) << 16);
return insn->n;
}
@@ -443,13 +230,17 @@ static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct diosubd_data *d = (const struct diosubd_data *)s->private;
- int i;
+ unsigned long reg = (unsigned long)s->private;
+ unsigned long iobase = dev->iobase + reg;
if (comedi_dio_update_state(s, data)) {
- for (i = 0; i < d->regs; i++)
- outb((s->state >> (8 * i)) & 0xff,
- dev->iobase + d->addr + i);
+ outb(s->state & 0xff, iobase);
+ if (s->n_chan > 8)
+ outb((s->state >> 8) & 0xff, iobase + 1);
+ if (s->n_chan > 16)
+ outb((s->state >> 16) & 0xff, iobase + 2);
+ if (s->n_chan > 24)
+ outb((s->state >> 24) & 0xff, iobase + 3);
}
data[1] = s->state;
@@ -462,13 +253,13 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct diosubd_data *d = (const struct diosubd_data *)s->private;
- int i;
+ unsigned long reg = (unsigned long)s->private;
+ unsigned long iobase = dev->iobase + reg;
if (comedi_dio_update_state(s, data)) {
- for (i = 0; i < d->regs; i++)
- outw((s->state >> (16 * i)) & 0xffff,
- dev->iobase + d->addr + 2 * i);
+ outw(s->state & 0xffff, iobase);
+ if (s->n_chan > 16)
+ outw((s->state >> 16) & 0xffff, iobase + 2);
}
data[1] = s->state;
@@ -476,510 +267,64 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
return insn->n;
}
-/*
-==============================================================================
-*/
-static int pci1760_unchecked_mbxrequest(struct comedi_device *dev,
- unsigned char *omb, unsigned char *imb,
- int repeats)
-{
- int cnt, tout, ok = 0;
-
- for (cnt = 0; cnt < repeats; cnt++) {
- outb(omb[0], dev->iobase + OMB0);
- outb(omb[1], dev->iobase + OMB1);
- outb(omb[2], dev->iobase + OMB2);
- outb(omb[3], dev->iobase + OMB3);
- for (tout = 0; tout < 251; tout++) {
- imb[2] = inb(dev->iobase + IMB2);
- if (imb[2] == omb[2]) {
- imb[0] = inb(dev->iobase + IMB0);
- imb[1] = inb(dev->iobase + IMB1);
- imb[3] = inb(dev->iobase + IMB3);
- ok = 1;
- break;
- }
- udelay(1);
- }
- if (ok)
- return 0;
- }
-
- dev_err(dev->class_dev, "PCI-1760 mailbox request timeout!\n");
- return -ETIME;
-}
-
-static int pci1760_clear_imb2(struct comedi_device *dev)
-{
- unsigned char omb[4] = { 0x0, 0x0, CMD_ClearIMB2, 0x0 };
- unsigned char imb[4];
- /* check if imb2 is already clear */
- if (inb(dev->iobase + IMB2) == CMD_ClearIMB2)
- return 0;
- return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
-}
-
-static int pci1760_mbxrequest(struct comedi_device *dev,
- unsigned char *omb, unsigned char *imb)
-{
- if (omb[2] == CMD_ClearIMB2) {
- dev_err(dev->class_dev,
- "bug! this function should not be used for CMD_ClearIMB2 command\n");
- return -EINVAL;
- }
- if (inb(dev->iobase + IMB2) == omb[2]) {
- int retval;
-
- retval = pci1760_clear_imb2(dev);
- if (retval < 0)
- return retval;
- }
- return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY);
-}
-
-/*
-==============================================================================
-*/
-static int pci1760_insn_bits_di(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int pci_dio_reset(struct comedi_device *dev, unsigned long cardtype)
{
- data[1] = inb(dev->iobase + IMB3);
+ /* disable channel freeze function on the PCI-1752/1756 boards */
+ if (cardtype == TYPE_PCI1752 || cardtype == TYPE_PCI1756)
+ outw(0, dev->iobase + PCI1752_CFC_REG);
- return insn->n;
-}
-
-static int pci1760_insn_bits_do(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- int ret;
- unsigned char omb[4] = {
- 0x00,
- 0x00,
- CMD_SetRelaysOutput,
- 0x00
- };
- unsigned char imb[4];
-
- if (comedi_dio_update_state(s, data)) {
- omb[0] = s->state;
- ret = pci1760_mbxrequest(dev, omb, imb);
- if (!ret)
- return ret;
- }
-
- data[1] = s->state;
-
- return insn->n;
-}
-
-/*
-==============================================================================
-*/
-static int pci1760_insn_cnt_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int ret, n;
- unsigned char omb[4] = {
- CR_CHAN(insn->chanspec) & 0x07,
- 0x00,
- CMD_GetIDICntCurValue,
- 0x00
- };
- unsigned char imb[4];
-
- for (n = 0; n < insn->n; n++) {
- ret = pci1760_mbxrequest(dev, omb, imb);
- if (!ret)
- return ret;
- data[n] = (imb[1] << 8) + imb[0];
- }
-
- return n;
-}
-
-/*
-==============================================================================
-*/
-static int pci1760_insn_cnt_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci_dio_private *devpriv = dev->private;
- int ret;
- unsigned char chan = CR_CHAN(insn->chanspec) & 0x07;
- unsigned char bitmask = 1 << chan;
- unsigned char omb[4] = {
- data[0] & 0xff,
- (data[0] >> 8) & 0xff,
- CMD_SetIDI0CntResetValue + chan,
- 0x00
- };
- unsigned char imb[4];
-
- /* Set reset value if different */
- if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) {
- ret = pci1760_mbxrequest(dev, omb, imb);
- if (!ret)
- return ret;
- devpriv->CntResValue[chan] = data[0] & 0xffff;
- }
-
- omb[0] = bitmask; /* reset counter to it reset value */
- omb[2] = CMD_ResetIDICounters;
- ret = pci1760_mbxrequest(dev, omb, imb);
- if (!ret)
- return ret;
-
- /* start counter if it don't run */
- if (!(bitmask & devpriv->IDICntEnable)) {
- omb[0] = bitmask;
- omb[2] = CMD_EnableIDICounters;
- ret = pci1760_mbxrequest(dev, omb, imb);
- if (!ret)
- return ret;
- devpriv->IDICntEnable |= bitmask;
- }
- return 1;
-}
-
-/*
-==============================================================================
-*/
-static int pci1760_reset(struct comedi_device *dev)
-{
- struct pci_dio_private *devpriv = dev->private;
- int i;
- unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 };
- unsigned char imb[4];
-
- outb(0, dev->iobase + INTCSR0); /* disable IRQ */
- outb(0, dev->iobase + INTCSR1);
- outb(0, dev->iobase + INTCSR2);
- outb(0, dev->iobase + INTCSR3);
- devpriv->GlobalIrqEnabled = 0;
-
- omb[0] = 0x00;
- omb[2] = CMD_SetRelaysOutput; /* reset relay outputs */
- pci1760_mbxrequest(dev, omb, imb);
-
- omb[0] = 0x00;
- omb[2] = CMD_EnableIDICounters; /* disable IDI up counters */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDICntEnable = 0;
-
- omb[0] = 0x00;
- omb[2] = CMD_OverflowIDICounters; /* disable counters overflow
- * interrupts */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDICntOverEnable = 0;
-
- omb[0] = 0x00;
- omb[2] = CMD_MatchIntIDICounters; /* disable counters match value
- * interrupts */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDICntMatchEnable = 0;
-
- omb[0] = 0x00;
- omb[1] = 0x80;
- for (i = 0; i < 8; i++) { /* set IDI up counters match value */
- omb[2] = CMD_SetIDI0CntMatchValue + i;
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->CntMatchValue[i] = 0x8000;
- }
-
- omb[0] = 0x00;
- omb[1] = 0x00;
- for (i = 0; i < 8; i++) { /* set IDI up counters reset value */
- omb[2] = CMD_SetIDI0CntResetValue + i;
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->CntResValue[i] = 0x0000;
- }
-
- omb[0] = 0xff;
- omb[2] = CMD_ResetIDICounters; /* reset IDI up counters to reset
- * values */
- pci1760_mbxrequest(dev, omb, imb);
-
- omb[0] = 0x00;
- omb[2] = CMD_EdgeIDICounters; /* set IDI up counters count edge */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDICntEdge = 0x00;
-
- omb[0] = 0x00;
- omb[2] = CMD_EnableIDIFilters; /* disable all digital in filters */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDIFiltersEn = 0x00;
-
- omb[0] = 0x00;
- omb[2] = CMD_EnableIDIPatternMatch; /* disable pattern matching */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDIPatMatchEn = 0x00;
-
- omb[0] = 0x00;
- omb[2] = CMD_SetIDIPatternMatch; /* set pattern match value */
- pci1760_mbxrequest(dev, omb, imb);
- devpriv->IDIPatMatchValue = 0x00;
-
- return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci_dio_reset(struct comedi_device *dev)
-{
- const struct dio_boardtype *board = dev->board_ptr;
-
- switch (board->cardtype) {
+ /* disable and clear interrupts */
+ switch (cardtype) {
case TYPE_PCI1730:
- outb(0, dev->iobase + PCI1730_DO); /* clear outputs */
- outb(0, dev->iobase + PCI1730_DO + 1);
- outb(0, dev->iobase + PCI1730_IDO);
- outb(0, dev->iobase + PCI1730_IDO + 1);
- /* fallthrough */
case TYPE_PCI1733:
- /* disable interrupts */
- outb(0, dev->iobase + PCI1730_3_INT_EN);
- /* clear interrupts */
- outb(0x0f, dev->iobase + PCI1730_3_INT_CLR);
- /* set rising edge trigger */
- outb(0, dev->iobase + PCI1730_3_INT_RF);
- break;
- case TYPE_PCI1734:
- outb(0, dev->iobase + PCI1734_IDO); /* clear outputs */
- outb(0, dev->iobase + PCI1734_IDO + 1);
- outb(0, dev->iobase + PCI1734_IDO + 2);
- outb(0, dev->iobase + PCI1734_IDO + 3);
- break;
- case TYPE_PCI1735:
- outb(0, dev->iobase + PCI1735_DO); /* clear outputs */
- outb(0, dev->iobase + PCI1735_DO + 1);
- outb(0, dev->iobase + PCI1735_DO + 2);
- outb(0, dev->iobase + PCI1735_DO + 3);
- break;
-
case TYPE_PCI1736:
- outb(0, dev->iobase + PCI1736_IDO);
- outb(0, dev->iobase + PCI1736_IDO + 1);
- /* disable interrupts */
- outb(0, dev->iobase + PCI1736_3_INT_EN);
- /* clear interrupts */
- outb(0x0f, dev->iobase + PCI1736_3_INT_CLR);
- /* set rising edge trigger */
- outb(0, dev->iobase + PCI1736_3_INT_RF);
+ outb(0, dev->iobase + PCI173X_INT_EN_REG);
+ outb(0x0f, dev->iobase + PCI173X_INT_CLR_REG);
+ outb(0, dev->iobase + PCI173X_INT_RF_REG);
break;
-
case TYPE_PCI1739:
- /* disable & clear interrupts */
- outb(0x88, dev->iobase + PCI1739_ICR);
- break;
-
case TYPE_PCI1750:
case TYPE_PCI1751:
- /* disable & clear interrupts */
- outb(0x88, dev->iobase + PCI1750_ICR);
- break;
- case TYPE_PCI1752:
- outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze
- * function */
- outw(0, dev->iobase + PCI1752_IDO); /* clear outputs */
- outw(0, dev->iobase + PCI1752_IDO + 2);
- outw(0, dev->iobase + PCI1752_IDO2);
- outw(0, dev->iobase + PCI1752_IDO2 + 2);
+ outb(0x88, dev->iobase + PCI1750_INT_REG);
break;
- case TYPE_PCI1753E:
- outb(0x88, dev->iobase + PCI1753E_ICR0); /* disable & clear
- * interrupts */
- outb(0x80, dev->iobase + PCI1753E_ICR1);
- outb(0x80, dev->iobase + PCI1753E_ICR2);
- outb(0x80, dev->iobase + PCI1753E_ICR3);
- /* fallthrough */
case TYPE_PCI1753:
- outb(0x88, dev->iobase + PCI1753_ICR0); /* disable & clear
- * interrupts */
- outb(0x80, dev->iobase + PCI1753_ICR1);
- outb(0x80, dev->iobase + PCI1753_ICR2);
- outb(0x80, dev->iobase + PCI1753_ICR3);
+ case TYPE_PCI1753E:
+ outb(0x88, dev->iobase + PCI1753_INT_REG(0));
+ outb(0x80, dev->iobase + PCI1753_INT_REG(1));
+ outb(0x80, dev->iobase + PCI1753_INT_REG(2));
+ outb(0x80, dev->iobase + PCI1753_INT_REG(3));
+ if (cardtype == TYPE_PCI1753E) {
+ outb(0x88, dev->iobase + PCI1753E_INT_REG(0));
+ outb(0x80, dev->iobase + PCI1753E_INT_REG(1));
+ outb(0x80, dev->iobase + PCI1753E_INT_REG(2));
+ outb(0x80, dev->iobase + PCI1753E_INT_REG(3));
+ }
break;
case TYPE_PCI1754:
- outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear
- * interrupts */
- outw(0x08, dev->iobase + PCI1754_6_ICR1);
- outw(0x08, dev->iobase + PCI1754_ICR2);
- outw(0x08, dev->iobase + PCI1754_ICR3);
- break;
case TYPE_PCI1756:
- outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze
- * function */
- outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear
- * interrupts */
- outw(0x08, dev->iobase + PCI1754_6_ICR1);
- outw(0, dev->iobase + PCI1756_IDO); /* clear outputs */
- outw(0, dev->iobase + PCI1756_IDO + 2);
- break;
- case TYPE_PCI1760:
- pci1760_reset(dev);
+ outw(0x08, dev->iobase + PCI1754_INT_REG(0));
+ outw(0x08, dev->iobase + PCI1754_INT_REG(1));
+ if (cardtype == TYPE_PCI1754) {
+ outw(0x08, dev->iobase + PCI1754_INT_REG(2));
+ outw(0x08, dev->iobase + PCI1754_INT_REG(3));
+ }
break;
case TYPE_PCI1762:
- outw(0x0101, dev->iobase + PCI1762_ICR); /* disable & clear
- * interrupts */
- break;
- }
-
- return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci1760_attach(struct comedi_device *dev)
-{
- struct comedi_subdevice *s;
-
- s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->len_chanlist = 8;
- s->range_table = &range_digital;
- s->insn_bits = pci1760_insn_bits_di;
-
- s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->len_chanlist = 8;
- s->range_table = &range_digital;
- s->state = 0;
- s->insn_bits = pci1760_insn_bits_do;
-
- s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_TIMER;
- s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL;
- s->n_chan = 2;
- s->maxdata = 0xffffffff;
- s->len_chanlist = 2;
-/* s->insn_config=pci1760_insn_pwm_cfg; */
-
- s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 0xffff;
- s->len_chanlist = 8;
- s->insn_read = pci1760_insn_cnt_read;
- s->insn_write = pci1760_insn_cnt_write;
-/* s->insn_config=pci1760_insn_cnt_cfg; */
-
- return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci_dio_add_di(struct comedi_device *dev,
- struct comedi_subdevice *s,
- const struct diosubd_data *d)
-{
- const struct dio_boardtype *board = dev->board_ptr;
-
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE | d->specflags;
- if (d->chans > 16)
- s->subdev_flags |= SDF_LSAMPL;
- s->n_chan = d->chans;
- s->maxdata = 1;
- s->len_chanlist = d->chans;
- s->range_table = &range_digital;
- switch (board->io_access) {
- case IO_8b:
- s->insn_bits = pci_dio_insn_bits_di_b;
- break;
- case IO_16b:
- s->insn_bits = pci_dio_insn_bits_di_w;
- break;
- }
- s->private = (void *)d;
-
- return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci_dio_add_do(struct comedi_device *dev,
- struct comedi_subdevice *s,
- const struct diosubd_data *d)
-{
- const struct dio_boardtype *board = dev->board_ptr;
-
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- if (d->chans > 16)
- s->subdev_flags |= SDF_LSAMPL;
- s->n_chan = d->chans;
- s->maxdata = 1;
- s->len_chanlist = d->chans;
- s->range_table = &range_digital;
- s->state = 0;
- switch (board->io_access) {
- case IO_8b:
- s->insn_bits = pci_dio_insn_bits_do_b;
+ outw(0x0101, dev->iobase + PCI1762_INT_REG);
break;
- case IO_16b:
- s->insn_bits = pci_dio_insn_bits_do_w;
+ default:
break;
}
- s->private = (void *)d;
return 0;
}
-static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
- unsigned long cardtype)
-{
- /*
- * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
- * board available. Need to enable PCI device and request the main
- * registers PCI BAR temporarily to perform the test.
- */
- if (cardtype != TYPE_PCI1753)
- return cardtype;
- if (pci_enable_device(pcidev) < 0)
- return cardtype;
- if (pci_request_region(pcidev, PCIDIO_MAINREG, "adv_pci_dio") == 0) {
- /*
- * This test is based on Advantech's "advdaq" driver source
- * (which declares its module licence as "GPL" although the
- * driver source does not include a "COPYING" file).
- */
- unsigned long reg =
- pci_resource_start(pcidev, PCIDIO_MAINREG) + 53;
-
- outb(0x05, reg);
- if ((inb(reg) & 0x07) == 0x02) {
- outb(0x02, reg);
- if ((inb(reg) & 0x07) == 0x05)
- cardtype = TYPE_PCI1753E;
- }
- pci_release_region(pcidev, PCIDIO_MAINREG);
- }
- pci_disable_device(pcidev);
- return cardtype;
-}
-
static int pci_dio_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct dio_boardtype *board = NULL;
- struct pci_dio_private *devpriv;
+ const struct diosubd_data *d;
struct comedi_subdevice *s;
int ret, subdev, i, j;
@@ -990,54 +335,93 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
dev->board_ptr = board;
dev->board_name = board->name;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_pci_enable(dev);
if (ret)
return ret;
- dev->iobase = pci_resource_start(pcidev, board->main_pci_region);
+ if (context == TYPE_PCI1736)
+ dev->iobase = pci_resource_start(pcidev, 0);
+ else
+ dev->iobase = pci_resource_start(pcidev, 2);
+
+ pci_dio_reset(dev, context);
ret = comedi_alloc_subdevices(dev, board->nsubdevs);
if (ret)
return ret;
subdev = 0;
- for (i = 0; i < MAX_DI_SUBDEVS; i++)
- if (board->sdi[i].chans) {
- s = &dev->subdevices[subdev];
- pci_dio_add_di(dev, s, &board->sdi[i]);
- subdev++;
+ for (i = 0; i < PCI_DIO_MAX_DI_SUBDEVS; i++) {
+ d = &board->sdi[i];
+ if (d->chans) {
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = d->chans;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = board->is_16bit
+ ? pci_dio_insn_bits_di_w
+ : pci_dio_insn_bits_di_b;
+ s->private = (void *)d->addr;
}
+ }
- for (i = 0; i < MAX_DO_SUBDEVS; i++)
- if (board->sdo[i].chans) {
- s = &dev->subdevices[subdev];
- pci_dio_add_do(dev, s, &board->sdo[i]);
- subdev++;
+ for (i = 0; i < PCI_DIO_MAX_DO_SUBDEVS; i++) {
+ d = &board->sdo[i];
+ if (d->chans) {
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = d->chans;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = board->is_16bit
+ ? pci_dio_insn_bits_do_w
+ : pci_dio_insn_bits_do_b;
+ s->private = (void *)d->addr;
+
+ /* reset all outputs to 0 */
+ if (board->is_16bit) {
+ outw(0, dev->iobase + d->addr);
+ if (s->n_chan > 16)
+ outw(0, dev->iobase + d->addr + 2);
+ } else {
+ outb(0, dev->iobase + d->addr);
+ if (s->n_chan > 8)
+ outb(0, dev->iobase + d->addr + 1);
+ if (s->n_chan > 16)
+ outb(0, dev->iobase + d->addr + 2);
+ if (s->n_chan > 24)
+ outb(0, dev->iobase + d->addr + 3);
+ }
}
+ }
- for (i = 0; i < MAX_DIO_SUBDEVG; i++)
- for (j = 0; j < board->sdio[i].regs; j++) {
- s = &dev->subdevices[subdev];
+ for (i = 0; i < PCI_DIO_MAX_DIO_SUBDEVG; i++) {
+ d = &board->sdio[i];
+ for (j = 0; j < d->chans; j++) {
+ s = &dev->subdevices[subdev++];
ret = subdev_8255_init(dev, s, NULL,
- board->sdio[i].addr +
- j * I8255_SIZE);
+ d->addr + j * I8255_SIZE);
if (ret)
return ret;
- subdev++;
}
+ }
- if (board->boardid.chans) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DI;
- pci_dio_add_di(dev, s, &board->boardid);
- subdev++;
+ if (board->id_reg) {
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = board->is_16bit ? pci_dio_insn_bits_di_w
+ : pci_dio_insn_bits_di_b;
+ s->private = (void *)board->id_reg;
}
if (board->timer_regbase) {
- s = &dev->subdevices[subdev];
+ s = &dev->subdevices[subdev++];
dev->pacer = comedi_8254_init(dev->iobase +
board->timer_regbase,
@@ -1046,32 +430,50 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
return -ENOMEM;
comedi_8254_subdevice_init(s, dev->pacer);
-
- subdev++;
}
- if (board->cardtype == TYPE_PCI1760)
- pci1760_attach(dev);
-
- pci_dio_reset(dev);
-
return 0;
}
-static void pci_dio_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- pci_dio_reset(dev);
- comedi_pci_detach(dev);
-}
-
static struct comedi_driver adv_pci_dio_driver = {
.driver_name = "adv_pci_dio",
.module = THIS_MODULE,
.auto_attach = pci_dio_auto_attach,
- .detach = pci_dio_detach,
+ .detach = comedi_pci_detach,
};
+static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
+ unsigned long cardtype)
+{
+ /*
+ * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
+ * board available. Need to enable PCI device and request the main
+ * registers PCI BAR temporarily to perform the test.
+ */
+ if (cardtype != TYPE_PCI1753)
+ return cardtype;
+ if (pci_enable_device(pcidev) < 0)
+ return cardtype;
+ if (pci_request_region(pcidev, 2, "adv_pci_dio") == 0) {
+ /*
+ * This test is based on Advantech's "advdaq" driver source
+ * (which declares its module licence as "GPL" although the
+ * driver source does not include a "COPYING" file).
+ */
+ unsigned long reg = pci_resource_start(pcidev, 2) + 53;
+
+ outb(0x05, reg);
+ if ((inb(reg) & 0x07) == 0x02) {
+ outb(0x02, reg);
+ if ((inb(reg) & 0x07) == 0x05)
+ cardtype = TYPE_PCI1753E;
+ }
+ pci_release_region(pcidev, 2);
+ }
+ pci_disable_device(pcidev);
+ return cardtype;
+}
+
static int adv_pci_dio_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
@@ -1094,7 +496,6 @@ static const struct pci_device_id adv_pci_dio_pci_table[] = {
{ PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 },
{ PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 },
{ PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 },
- { PCI_VDEVICE(ADVANTECH, 0x1760), TYPE_PCI1760 },
{ PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 },
{ 0 }
};
@@ -1109,5 +510,5 @@ static struct pci_driver adv_pci_dio_pci_driver = {
module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Advantech Digital I/O Cards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index b2f7679a0116..cac011fdd375 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -1022,14 +1022,17 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
irq = pci_dev->irq;
/* Allocate buffer to hold values for AO channel scan. */
- devpriv->ao_scan_vals = kmalloc(sizeof(devpriv->ao_scan_vals[0]) *
- board->ao_chans, GFP_KERNEL);
+ devpriv->ao_scan_vals = kmalloc_array(board->ao_chans,
+ sizeof(devpriv->ao_scan_vals[0]),
+ GFP_KERNEL);
if (!devpriv->ao_scan_vals)
return -ENOMEM;
/* Allocate buffer to hold AO channel scan order. */
- devpriv->ao_scan_order = kmalloc(sizeof(devpriv->ao_scan_order[0]) *
- board->ao_chans, GFP_KERNEL);
+ devpriv->ao_scan_order =
+ kmalloc_array(board->ao_chans,
+ sizeof(devpriv->ao_scan_order[0]),
+ GFP_KERNEL);
if (!devpriv->ao_scan_order)
return -ENOMEM;
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index b00a36a5cb36..ccb37d1f0f8e 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -51,13 +51,13 @@
/* DAC registers */
#define CB_DDA_DA_CTRL_REG 0x00 /* D/A Control Register */
-#define CB_DDA_DA_CTRL_SU (1 << 0) /* Simultaneous update */
-#define CB_DDA_DA_CTRL_EN (1 << 1) /* Enable specified DAC */
+#define CB_DDA_DA_CTRL_SU BIT(0) /* Simultaneous update */
+#define CB_DDA_DA_CTRL_EN BIT(1) /* Enable specified DAC */
#define CB_DDA_DA_CTRL_DAC(x) ((x) << 2) /* Specify DAC channel */
#define CB_DDA_DA_CTRL_RANGE2V5 (0 << 6) /* 2.5V range */
#define CB_DDA_DA_CTRL_RANGE5V (2 << 6) /* 5V range */
#define CB_DDA_DA_CTRL_RANGE10V (3 << 6) /* 10V range */
-#define CB_DDA_DA_CTRL_UNIP (1 << 8) /* Unipolar range */
+#define CB_DDA_DA_CTRL_UNIP BIT(8) /* Unipolar range */
#define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */
/* write bits */
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 15a4093efda1..1bf8ddc6f07c 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -75,8 +75,8 @@
#define PARPORT_DATA_REG 0x00
#define PARPORT_STATUS_REG 0x01
#define PARPORT_CTRL_REG 0x02
-#define PARPORT_CTRL_IRQ_ENA (1 << 4)
-#define PARPORT_CTRL_BIDIR_ENA (1 << 5)
+#define PARPORT_CTRL_IRQ_ENA BIT(4)
+#define PARPORT_CTRL_BIDIR_ENA BIT(5)
static int parport_data_reg_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 056bca9c67d5..fd8e0b76f764 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -801,9 +801,10 @@ static void das16_ai_munge(struct comedi_device *dev,
unsigned short *data = array;
unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes);
unsigned int i;
+ __le16 *buf = array;
for (i = 0; i < num_samples; i++) {
- data[i] = le16_to_cpu(data[i]);
+ data[i] = le16_to_cpu(buf[i]);
if (s->maxdata == 0x0fff)
data[i] >>= 4;
data[i] &= s->maxdata;
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 62a817e4cd64..84c62e256094 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -42,24 +42,24 @@
#define NI6527_DO_REG(x) (0x03 + (x))
#define NI6527_ID_REG 0x06
#define NI6527_CLR_REG 0x07
-#define NI6527_CLR_EDGE (1 << 3)
-#define NI6527_CLR_OVERFLOW (1 << 2)
-#define NI6527_CLR_FILT (1 << 1)
-#define NI6527_CLR_INTERVAL (1 << 0)
+#define NI6527_CLR_EDGE BIT(3)
+#define NI6527_CLR_OVERFLOW BIT(2)
+#define NI6527_CLR_FILT BIT(1)
+#define NI6527_CLR_INTERVAL BIT(0)
#define NI6527_CLR_IRQS (NI6527_CLR_EDGE | NI6527_CLR_OVERFLOW)
#define NI6527_CLR_RESET_FILT (NI6527_CLR_FILT | NI6527_CLR_INTERVAL)
#define NI6527_FILT_INTERVAL_REG(x) (0x08 + (x))
#define NI6527_FILT_ENA_REG(x) (0x0c + (x))
#define NI6527_STATUS_REG 0x14
-#define NI6527_STATUS_IRQ (1 << 2)
-#define NI6527_STATUS_OVERFLOW (1 << 1)
-#define NI6527_STATUS_EDGE (1 << 0)
+#define NI6527_STATUS_IRQ BIT(2)
+#define NI6527_STATUS_OVERFLOW BIT(1)
+#define NI6527_STATUS_EDGE BIT(0)
#define NI6527_CTRL_REG 0x15
-#define NI6527_CTRL_FALLING (1 << 4)
-#define NI6527_CTRL_RISING (1 << 3)
-#define NI6527_CTRL_IRQ (1 << 2)
-#define NI6527_CTRL_OVERFLOW (1 << 1)
-#define NI6527_CTRL_EDGE (1 << 0)
+#define NI6527_CTRL_FALLING BIT(4)
+#define NI6527_CTRL_RISING BIT(3)
+#define NI6527_CTRL_IRQ BIT(2)
+#define NI6527_CTRL_OVERFLOW BIT(1)
+#define NI6527_CTRL_EDGE BIT(0)
#define NI6527_CTRL_DISABLE_IRQS 0
#define NI6527_CTRL_ENABLE_IRQS (NI6527_CTRL_FALLING | \
NI6527_CTRL_RISING | \
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 800d57426070..251117be1205 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -68,25 +68,25 @@
/* Non-recurring Registers (8-bit except where noted) */
#define NI_65XX_ID_REG 0x00
#define NI_65XX_CLR_REG 0x01
-#define NI_65XX_CLR_WDOG_INT (1 << 6)
-#define NI_65XX_CLR_WDOG_PING (1 << 5)
-#define NI_65XX_CLR_WDOG_EXP (1 << 4)
-#define NI_65XX_CLR_EDGE_INT (1 << 3)
-#define NI_65XX_CLR_OVERFLOW_INT (1 << 2)
+#define NI_65XX_CLR_WDOG_INT BIT(6)
+#define NI_65XX_CLR_WDOG_PING BIT(5)
+#define NI_65XX_CLR_WDOG_EXP BIT(4)
+#define NI_65XX_CLR_EDGE_INT BIT(3)
+#define NI_65XX_CLR_OVERFLOW_INT BIT(2)
#define NI_65XX_STATUS_REG 0x02
-#define NI_65XX_STATUS_WDOG_INT (1 << 5)
-#define NI_65XX_STATUS_FALL_EDGE (1 << 4)
-#define NI_65XX_STATUS_RISE_EDGE (1 << 3)
-#define NI_65XX_STATUS_INT (1 << 2)
-#define NI_65XX_STATUS_OVERFLOW_INT (1 << 1)
-#define NI_65XX_STATUS_EDGE_INT (1 << 0)
+#define NI_65XX_STATUS_WDOG_INT BIT(5)
+#define NI_65XX_STATUS_FALL_EDGE BIT(4)
+#define NI_65XX_STATUS_RISE_EDGE BIT(3)
+#define NI_65XX_STATUS_INT BIT(2)
+#define NI_65XX_STATUS_OVERFLOW_INT BIT(1)
+#define NI_65XX_STATUS_EDGE_INT BIT(0)
#define NI_65XX_CTRL_REG 0x03
-#define NI_65XX_CTRL_WDOG_ENA (1 << 5)
-#define NI_65XX_CTRL_FALL_EDGE_ENA (1 << 4)
-#define NI_65XX_CTRL_RISE_EDGE_ENA (1 << 3)
-#define NI_65XX_CTRL_INT_ENA (1 << 2)
-#define NI_65XX_CTRL_OVERFLOW_ENA (1 << 1)
-#define NI_65XX_CTRL_EDGE_ENA (1 << 0)
+#define NI_65XX_CTRL_WDOG_ENA BIT(5)
+#define NI_65XX_CTRL_FALL_EDGE_ENA BIT(4)
+#define NI_65XX_CTRL_RISE_EDGE_ENA BIT(3)
+#define NI_65XX_CTRL_INT_ENA BIT(2)
+#define NI_65XX_CTRL_OVERFLOW_ENA BIT(1)
+#define NI_65XX_CTRL_EDGE_ENA BIT(0)
#define NI_65XX_REV_REG 0x04 /* 32-bit */
#define NI_65XX_FILTER_REG 0x08 /* 32-bit */
#define NI_65XX_RTSI_ROUTE_REG 0x0c /* 16-bit */
@@ -94,24 +94,24 @@
#define NI_65XX_RTSI_WDOG_REG 0x10 /* 16-bit */
#define NI_65XX_RTSI_TRIG_REG 0x12 /* 16-bit */
#define NI_65XX_AUTO_CLK_SEL_REG 0x14 /* PXI-6528 only */
-#define NI_65XX_AUTO_CLK_SEL_STATUS (1 << 1)
-#define NI_65XX_AUTO_CLK_SEL_DISABLE (1 << 0)
+#define NI_65XX_AUTO_CLK_SEL_STATUS BIT(1)
+#define NI_65XX_AUTO_CLK_SEL_DISABLE BIT(0)
#define NI_65XX_WDOG_CTRL_REG 0x15
-#define NI_65XX_WDOG_CTRL_ENA (1 << 0)
+#define NI_65XX_WDOG_CTRL_ENA BIT(0)
#define NI_65XX_RTSI_CFG_REG 0x16
-#define NI_65XX_RTSI_CFG_RISE_SENSE (1 << 2)
-#define NI_65XX_RTSI_CFG_FALL_SENSE (1 << 1)
-#define NI_65XX_RTSI_CFG_SYNC_DETECT (1 << 0)
+#define NI_65XX_RTSI_CFG_RISE_SENSE BIT(2)
+#define NI_65XX_RTSI_CFG_FALL_SENSE BIT(1)
+#define NI_65XX_RTSI_CFG_SYNC_DETECT BIT(0)
#define NI_65XX_WDOG_STATUS_REG 0x17
-#define NI_65XX_WDOG_STATUS_EXP (1 << 0)
+#define NI_65XX_WDOG_STATUS_EXP BIT(0)
#define NI_65XX_WDOG_INTERVAL_REG 0x18 /* 32-bit */
/* Recurring port registers (8-bit) */
#define NI_65XX_PORT(x) ((x) * 0x10)
#define NI_65XX_IO_DATA_REG(x) (0x40 + NI_65XX_PORT(x))
#define NI_65XX_IO_SEL_REG(x) (0x41 + NI_65XX_PORT(x))
-#define NI_65XX_IO_SEL_OUTPUT (0 << 0)
-#define NI_65XX_IO_SEL_INPUT (1 << 0)
+#define NI_65XX_IO_SEL_OUTPUT 0
+#define NI_65XX_IO_SEL_INPUT BIT(0)
#define NI_65XX_RISE_EDGE_ENA_REG(x) (0x42 + NI_65XX_PORT(x))
#define NI_65XX_FALL_EDGE_ENA_REG(x) (0x43 + NI_65XX_PORT(x))
#define NI_65XX_FILTER_ENA(x) (0x44 + NI_65XX_PORT(x))
@@ -613,7 +613,7 @@ static int ni_65xx_intr_insn_config(struct comedi_device *dev,
/* ripped from mite.h and mite_setup2() to avoid mite dependency */
#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */
-#define WENAB (1 << 7) /* window enable */
+#define WENAB BIT(7) /* window enable */
static int ni_65xx_mite_init(struct pci_dev *pcidev)
{
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index f4c580f65a89..3e72718801a9 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -214,8 +214,9 @@ static int ni_670x_auto_attach(struct comedi_device *dev,
if (s->n_chan == 32) {
const struct comedi_lrange **range_table_list;
- range_table_list = kmalloc(sizeof(struct comedi_lrange *) * 32,
- GFP_KERNEL);
+ range_table_list = kmalloc_array(32,
+ sizeof(struct comedi_lrange *),
+ GFP_KERNEL);
if (!range_table_list)
return -ENOMEM;
s->range_table_list = range_table_list;
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 6cc304a4c59b..5e8130a7d670 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -579,48 +579,54 @@ static inline unsigned ni_stc_dma_channel_select_bitfield(unsigned channel)
return 0;
}
-/* negative channel means no channel */
-static inline void ni_set_ai_dma_channel(struct comedi_device *dev, int channel)
+static inline void ni_set_ai_dma_channel(struct comedi_device *dev,
+ unsigned channel)
{
- unsigned bits = 0;
-
- if (channel >= 0)
- bits = ni_stc_dma_channel_select_bitfield(channel);
+ unsigned bits = ni_stc_dma_channel_select_bitfield(channel);
ni_set_bitfield(dev, NI_E_DMA_AI_AO_SEL_REG,
NI_E_DMA_AI_SEL_MASK, NI_E_DMA_AI_SEL(bits));
}
-/* negative channel means no channel */
-static inline void ni_set_ao_dma_channel(struct comedi_device *dev, int channel)
+static inline void ni_set_ai_dma_no_channel(struct comedi_device *dev)
{
- unsigned bits = 0;
+ ni_set_bitfield(dev, NI_E_DMA_AI_AO_SEL_REG, NI_E_DMA_AI_SEL_MASK, 0);
+}
- if (channel >= 0)
- bits = ni_stc_dma_channel_select_bitfield(channel);
+static inline void ni_set_ao_dma_channel(struct comedi_device *dev,
+ unsigned channel)
+{
+ unsigned bits = ni_stc_dma_channel_select_bitfield(channel);
ni_set_bitfield(dev, NI_E_DMA_AI_AO_SEL_REG,
NI_E_DMA_AO_SEL_MASK, NI_E_DMA_AO_SEL(bits));
}
-/* negative channel means no channel */
+static inline void ni_set_ao_dma_no_channel(struct comedi_device *dev)
+{
+ ni_set_bitfield(dev, NI_E_DMA_AI_AO_SEL_REG, NI_E_DMA_AO_SEL_MASK, 0);
+}
+
static inline void ni_set_gpct_dma_channel(struct comedi_device *dev,
unsigned gpct_index,
- int channel)
+ unsigned channel)
{
- unsigned bits = 0;
-
- if (channel >= 0)
- bits = ni_stc_dma_channel_select_bitfield(channel);
+ unsigned bits = ni_stc_dma_channel_select_bitfield(channel);
ni_set_bitfield(dev, NI_E_DMA_G0_G1_SEL_REG,
NI_E_DMA_G0_G1_SEL_MASK(gpct_index),
NI_E_DMA_G0_G1_SEL(gpct_index, bits));
}
-/* negative mite_channel means no channel */
+static inline void ni_set_gpct_dma_no_channel(struct comedi_device *dev,
+ unsigned gpct_index)
+{
+ ni_set_bitfield(dev, NI_E_DMA_G0_G1_SEL_REG,
+ NI_E_DMA_G0_G1_SEL_MASK(gpct_index), 0);
+}
+
static inline void ni_set_cdo_dma_channel(struct comedi_device *dev,
- int mite_channel)
+ unsigned mite_channel)
{
struct ni_private *devpriv = dev->private;
unsigned long flags;
@@ -628,16 +634,26 @@ static inline void ni_set_cdo_dma_channel(struct comedi_device *dev,
spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
devpriv->cdio_dma_select_reg &= ~NI_M_CDIO_DMA_SEL_CDO_MASK;
- if (mite_channel >= 0) {
- /*
- * XXX just guessing ni_stc_dma_channel_select_bitfield()
- * returns the right bits, under the assumption the cdio dma
- * selection works just like ai/ao/gpct.
- * Definitely works for dma channels 0 and 1.
- */
- bits = ni_stc_dma_channel_select_bitfield(mite_channel);
- devpriv->cdio_dma_select_reg |= NI_M_CDIO_DMA_SEL_CDO(bits);
- }
+ /*
+ * XXX just guessing ni_stc_dma_channel_select_bitfield()
+ * returns the right bits, under the assumption the cdio dma
+ * selection works just like ai/ao/gpct.
+ * Definitely works for dma channels 0 and 1.
+ */
+ bits = ni_stc_dma_channel_select_bitfield(mite_channel);
+ devpriv->cdio_dma_select_reg |= NI_M_CDIO_DMA_SEL_CDO(bits);
+ ni_writeb(dev, devpriv->cdio_dma_select_reg, NI_M_CDIO_DMA_SEL_REG);
+ mmiowb();
+ spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+static inline void ni_set_cdo_dma_no_channel(struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+ devpriv->cdio_dma_select_reg &= ~NI_M_CDIO_DMA_SEL_CDO_MASK;
ni_writeb(dev, devpriv->cdio_dma_select_reg, NI_M_CDIO_DMA_SEL_REG);
mmiowb();
spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
@@ -745,7 +761,7 @@ static void ni_release_ai_mite_channel(struct comedi_device *dev)
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ai_mite_chan) {
- ni_set_ai_dma_channel(dev, -1);
+ ni_set_ai_dma_no_channel(dev);
mite_release_channel(devpriv->ai_mite_chan);
devpriv->ai_mite_chan = NULL;
}
@@ -761,7 +777,7 @@ static void ni_release_ao_mite_channel(struct comedi_device *dev)
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ao_mite_chan) {
- ni_set_ao_dma_channel(dev, -1);
+ ni_set_ao_dma_no_channel(dev);
mite_release_channel(devpriv->ao_mite_chan);
devpriv->ao_mite_chan = NULL;
}
@@ -781,7 +797,7 @@ static void ni_release_gpct_mite_channel(struct comedi_device *dev,
struct mite_channel *mite_chan =
devpriv->counter_dev->counters[gpct_index].mite_chan;
- ni_set_gpct_dma_channel(dev, gpct_index, -1);
+ ni_set_gpct_dma_no_channel(dev, gpct_index);
ni_tio_set_mite_channel(&devpriv->
counter_dev->counters[gpct_index],
NULL);
@@ -799,7 +815,7 @@ static void ni_release_cdo_mite_channel(struct comedi_device *dev)
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->cdo_mite_chan) {
- ni_set_cdo_dma_channel(dev, -1);
+ ni_set_cdo_dma_no_channel(dev);
mite_release_channel(devpriv->cdo_mite_chan);
devpriv->cdo_mite_chan = NULL;
}
@@ -1516,13 +1532,17 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned short *array = data;
unsigned int *larray = data;
unsigned int i;
+#ifdef PCIDMA
+ __le16 *barray = data;
+ __le32 *blarray = data;
+#endif
for (i = 0; i < nsamples; i++) {
#ifdef PCIDMA
if (s->subdev_flags & SDF_LSAMPL)
- larray[i] = le32_to_cpu(larray[i]);
+ larray[i] = le32_to_cpu(blarray[i]);
else
- array[i] = le16_to_cpu(array[i]);
+ array[i] = le16_to_cpu(barray[i]);
#endif
if (s->subdev_flags & SDF_LSAMPL)
larray[i] += devpriv->ai_offset[chan_index];
@@ -2574,6 +2594,9 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int nsamples = comedi_bytes_to_samples(s, num_bytes);
unsigned short *array = data;
unsigned int i;
+#ifdef PCIDMA
+ __le16 buf, *barray = data;
+#endif
for (i = 0; i < nsamples; i++) {
unsigned int range = CR_RANGE(cmd->chanlist[chan_index]);
@@ -2586,10 +2609,11 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
if (comedi_range_is_bipolar(s, range))
val = comedi_offset_munge(s, val);
#ifdef PCIDMA
- val = cpu_to_le16(val);
-#endif
+ buf = cpu_to_le16(val);
+ barray[i] = buf;
+#else
array[i] = val;
-
+#endif
chan_index++;
chan_index %= cmd->chanlist_len;
}
diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h
index 25706531b885..f5cd6d5004bd 100644
--- a/drivers/staging/comedi/drivers/plx9080.h
+++ b/drivers/staging/comedi/drivers/plx9080.h
@@ -1,4 +1,5 @@
-/* plx9080.h
+/*
+ * plx9080.h
*
* Copyright (C) 2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net>
*
@@ -33,8 +34,10 @@ struct plx_dma_desc {
__le32 local_start_addr;
/* transfer_size is in bytes, only first 23 bits of register are used */
__le32 transfer_size;
- /* address of next descriptor (quad word aligned), plus some
- * additional bits (see PLX_DMA0_DESCRIPTOR_REG) */
+ /*
+ * address of next descriptor (quad word aligned), plus some
+ * additional bits (see PLX_DMA0_DESCRIPTOR_REG)
+ */
__le32 next;
};
@@ -46,23 +49,31 @@ struct plx_dma_desc {
**
**********************************************************************/
-#define PLX_LAS0RNG_REG 0x0000 /* L, Local Addr Space 0 Range Register */
-#define PLX_LAS1RNG_REG 0x00f0 /* L, Local Addr Space 1 Range Register */
+/* L, Local Addr Space 0 Range Register */
+#define PLX_LAS0RNG_REG 0x0000
+/* L, Local Addr Space 1 Range Register */
+#define PLX_LAS1RNG_REG 0x00f0
#define LRNG_IO 0x00000001 /* Map to: 1=I/O, 0=Mem */
#define LRNG_ANY32 0x00000000 /* Locate anywhere in 32 bit */
#define LRNG_LT1MB 0x00000002 /* Locate in 1st meg */
#define LRNG_ANY64 0x00000004 /* Locate anywhere in 64 bit */
-#define LRNG_MEM_MASK 0xfffffff0 /* bits that specify range for memory io */
-#define LRNG_IO_MASK 0xfffffffa /* bits that specify range for normal io */
-
-#define PLX_LAS0MAP_REG 0x0004 /* L, Local Addr Space 0 Remap Register */
-#define PLX_LAS1MAP_REG 0x00f4 /* L, Local Addr Space 1 Remap Register */
+/* bits that specify range for memory io */
+#define LRNG_MEM_MASK 0xfffffff0
+/* bits that specify range for normal io */
+#define LRNG_IO_MASK 0xfffffffa
+/* L, Local Addr Space 0 Remap Register */
+#define PLX_LAS0MAP_REG 0x0004
+/* L, Local Addr Space 1 Remap Register */
+#define PLX_LAS1MAP_REG 0x00f4
#define LMAP_EN 0x00000001 /* Enable slave decode */
-#define LMAP_MEM_MASK 0xfffffff0 /* bits that specify decode for memory io */
-#define LMAP_IO_MASK 0xfffffffa /* bits that specify decode bits for normal io */
+/* bits that specify decode for memory io */
+#define LMAP_MEM_MASK 0xfffffff0
+/* bits that specify decode bits for normal io */
+#define LMAP_IO_MASK 0xfffffffa
-/* Mode/Arbitration Register.
-*/
+/*
+ * Mode/Arbitration Register.
+ */
#define PLX_MARB_REG 0x8 /* L, Local Arbitration Register */
#define PLX_DMAARB_REG 0xac
enum marb_bits {
@@ -72,35 +83,45 @@ enum marb_bits {
MARB_LPEN = 0x00020000, /* Pause Timer Enable */
MARB_BREQ = 0x00040000, /* Local Bus BREQ Enable */
MARB_DMA_PRIORITY_MASK = 0x00180000,
- MARB_LBDS_GIVE_UP_BUS_MODE = 0x00200000, /* local bus direct slave give up bus mode */
- MARB_DS_LLOCK_ENABLE = 0x00400000, /* direct slave LLOCKo# enable */
+ /* local bus direct slave give up bus mode */
+ MARB_LBDS_GIVE_UP_BUS_MODE = 0x00200000,
+ /* direct slave LLOCKo# enable */
+ MARB_DS_LLOCK_ENABLE = 0x00400000,
MARB_PCI_REQUEST_MODE = 0x00800000,
MARB_PCIv21_MODE = 0x01000000, /* pci specification v2.1 mode */
MARB_PCI_READ_NO_WRITE_MODE = 0x02000000,
MARB_PCI_READ_WITH_WRITE_FLUSH_MODE = 0x04000000,
- MARB_GATE_TIMER_WITH_BREQ = 0x08000000, /* gate local bus latency timer with BREQ */
+ /* gate local bus latency timer with BREQ */
+ MARB_GATE_TIMER_WITH_BREQ = 0x08000000,
MARB_PCI_READ_NO_FLUSH_MODE = 0x10000000,
MARB_USE_SUBSYSTEM_IDS = 0x20000000,
};
#define PLX_BIGEND_REG 0xc
enum bigend_bits {
- BIGEND_CONFIG = 0x1, /* use big endian ordering for configuration register accesses */
+ /* use big endian ordering for configuration register accesses */
+ BIGEND_CONFIG = 0x1,
BIGEND_DIRECT_MASTER = 0x2,
BIGEND_DIRECT_SLAVE_LOCAL0 = 0x4,
BIGEND_ROM = 0x8,
- BIGEND_BYTE_LANE = 0x10, /* use byte lane consisting of most significant bits instead of least significant */
+ /*
+ * use byte lane consisting of most significant bits instead of
+ * least significant
+ */
+ BIGEND_BYTE_LANE = 0x10,
BIGEND_DIRECT_SLAVE_LOCAL1 = 0x20,
BIGEND_DMA1 = 0x40,
BIGEND_DMA0 = 0x80,
};
-/* Note: The Expansion ROM stuff is only relevant to the PC environment.
+/*
+** Note: The Expansion ROM stuff is only relevant to the PC environment.
** This expansion ROM code is executed by the host CPU at boot time.
** For this reason no bit definitions are provided here.
-*/
+ */
#define PLX_ROMRNG_REG 0x0010 /* L, Expn ROM Space Range Register */
-#define PLX_ROMMAP_REG 0x0014 /* L, Local Addr Space Range Register */
+/* L, Local Addr Space Range Register */
+#define PLX_ROMMAP_REG 0x0014
#define PLX_REGION0_REG 0x0018 /* L, Local Bus Region 0 Descriptor */
#define RGN_WIDTH 0x00000002 /* Local bus width bits */
@@ -190,7 +211,8 @@ enum bigend_bits {
#define ICS_TA_DMA0 0x02000000 /* Target Abort - DMA #0 */
#define ICS_TA_DMA1 0x04000000 /* Target Abort - DMA #1 */
#define ICS_TA_RA 0x08000000 /* Target Abort - Retry Timeout */
-#define ICS_MBIA(x) (0x10000000 << ((x) & 0x3)) /* mailbox x is active */
+/* mailbox x is active */
+#define ICS_MBIA(x) (0x10000000 << ((x) & 0x3))
#define PLX_CONTROL_REG 0x006C /* L, EEPROM Cntl & PCI Cmd Codes */
#define CTL_RDMA 0x0000000E /* DMA Read Command */
@@ -221,28 +243,38 @@ enum bigend_bits {
#define PLX_EN_BTERM_BIT 0x80 /* enable BTERM# input */
#define PLX_DMA_LOCAL_BURST_EN_BIT 0x100 /* enable local burst mode */
#define PLX_EN_CHAIN_BIT 0x200 /* enables chaining */
-#define PLX_EN_DMA_DONE_INTR_BIT 0x400 /* enables interrupt on dma done */
-#define PLX_LOCAL_ADDR_CONST_BIT 0x800 /* hold local address constant (don't increment) */
-#define PLX_DEMAND_MODE_BIT 0x1000 /* enables demand-mode for dma transfer */
+/* enables interrupt on dma done */
+#define PLX_EN_DMA_DONE_INTR_BIT 0x400
+/* hold local address constant (don't increment) */
+#define PLX_LOCAL_ADDR_CONST_BIT 0x800
+/* enables demand-mode for dma transfer */
+#define PLX_DEMAND_MODE_BIT 0x1000
#define PLX_EOT_ENABLE_BIT 0x4000
#define PLX_STOP_MODE_BIT 0x8000
-#define PLX_DMA_INTR_PCI_BIT 0x20000 /* routes dma interrupt to pci bus (instead of local bus) */
+/* routes dma interrupt to pci bus (instead of local bus) */
+#define PLX_DMA_INTR_PCI_BIT 0x20000
-#define PLX_DMA0_PCI_ADDRESS_REG 0x84 /* pci address that dma transfers start at */
+/* pci address that dma transfers start at */
+#define PLX_DMA0_PCI_ADDRESS_REG 0x84
#define PLX_DMA1_PCI_ADDRESS_REG 0x98
-#define PLX_DMA0_LOCAL_ADDRESS_REG 0x88 /* local address that dma transfers start at */
+/* local address that dma transfers start at */
+#define PLX_DMA0_LOCAL_ADDRESS_REG 0x88
#define PLX_DMA1_LOCAL_ADDRESS_REG 0x9c
-#define PLX_DMA0_TRANSFER_SIZE_REG 0x8c /* number of bytes to transfer (first 23 bits) */
+/* number of bytes to transfer (first 23 bits) */
+#define PLX_DMA0_TRANSFER_SIZE_REG 0x8c
#define PLX_DMA1_TRANSFER_SIZE_REG 0xa0
#define PLX_DMA0_DESCRIPTOR_REG 0x90 /* descriptor pointer register */
#define PLX_DMA1_DESCRIPTOR_REG 0xa4
-#define PLX_DESC_IN_PCI_BIT 0x1 /* descriptor is located in pci space (not local space) */
+/* descriptor is located in pci space (not local space) */
+#define PLX_DESC_IN_PCI_BIT 0x1
#define PLX_END_OF_CHAIN_BIT 0x2 /* end of chain bit */
-#define PLX_INTR_TERM_COUNT 0x4 /* interrupt when this descriptor's transfer is finished */
-#define PLX_XFER_LOCAL_TO_PCI 0x8 /* transfer from local to pci bus (not pci to local) */
+/* interrupt when this descriptor's transfer is finished */
+#define PLX_INTR_TERM_COUNT 0x4
+/* transfer from local to pci bus (not pci to local) */
+#define PLX_XFER_LOCAL_TO_PCI 0x8
#define PLX_DMA0_CS_REG 0xa8 /* command status register */
#define PLX_DMA1_CS_REG 0xa9
@@ -288,10 +320,11 @@ enum bigend_bits {
#define MBX_STS_PCIRESET 0x00000100 /* Host issued PCI reset request */
#define MBX_STS_BUSY 0x00000080 /* PUTS is in progress */
#define MBX_STS_ERROR 0x00000040 /* PUTS has failed */
-#define MBX_STS_RESERVED 0x000000c0 /* Undefined -> status in transition.
- We are in process of changing
- bits; we SET Error bit before
- RESET of Busy bit */
+/*
+ * Undefined -> status in transition. We are in process of changing bits;
+ * we SET Error bit before RESET of Busy bit
+ */
+#define MBX_STS_RESERVED 0x000000c0
#define MBX_RESERVED_5 0x00000020 /* FYI: reserved/unused bit */
#define MBX_RESERVED_4 0x00000010 /* FYI: reserved/unused bit */
@@ -320,12 +353,12 @@ enum bigend_bits {
#define MBX_CMD_BSWAP_0 0x8c000000 /* use scheme 0 */
#define MBX_CMD_BSWAP_1 0x8c000001 /* use scheme 1 */
-#define MBX_CMD_SETHMS 0x8d000000 /* setup host memory access window
- size */
-#define MBX_CMD_SETHBA 0x8e000000 /* setup host memory access base
- address */
-#define MBX_CMD_MGO 0x8f000000 /* perform memory setup and continue
- (IE. Done) */
+/* setup host memory access window size */
+#define MBX_CMD_SETHMS 0x8d000000
+/* setup host memory access base address */
+#define MBX_CMD_SETHBA 0x8e000000
+/* perform memory setup and continue (IE. Done) */
+#define MBX_CMD_MGO 0x8f000000
#define MBX_CMD_NOOP 0xFF000000 /* dummy, illegal command */
/*****************************************/
@@ -348,7 +381,8 @@ enum bigend_bits {
/***************************************/
#define MBX_BTYPE_MASK 0x0000ffff /* PUTS Board Type Register */
-#define MBX_BTYPE_FAMILY_MASK 0x0000ff00 /* PUTS Board Family Register */
+/* PUTS Board Family Register */
+#define MBX_BTYPE_FAMILY_MASK 0x0000ff00
#define MBX_BTYPE_SUBTYPE_MASK 0x000000ff /* PUTS Board Subtype */
#define MBX_BTYPE_PLX9060 0x00000100 /* PLX family type */
@@ -378,12 +412,12 @@ enum bigend_bits {
/* system allocates this many bytes for address mapping mailbox space */
#define MBX_ADDR_SPACE_360 0x80 /* wanXL100s/200/400 */
-#define MBX_ADDR_MASK_360 (MBX_ADDR_SPACE_360-1)
+#define MBX_ADDR_MASK_360 (MBX_ADDR_SPACE_360 - 1)
static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel)
{
void __iomem *dma_cs_addr;
- uint8_t dma_status;
+ u8 dma_status;
const int timeout = 10000;
unsigned int i;
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index d70c97947627..c80527db9c19 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
#include "../comedidev.h"
-#include <asm/byteorder.h>
/*
* Register I/O map
@@ -84,7 +83,92 @@
#define S526_GPCT_LSB_REG(x) (0x12 + ((x) * 8))
#define S526_GPCT_MSB_REG(x) (0x14 + ((x) * 8))
#define S526_GPCT_MODE_REG(x) (0x16 + ((x) * 8))
+#define S526_GPCT_MODE_COUT_SRC(x) ((x) << 0)
+#define S526_GPCT_MODE_COUT_SRC_MASK S526_GPCT_MODE_COUT_SRC(0x1)
+#define S526_GPCT_MODE_COUT_SRC_RCAP S526_GPCT_MODE_COUT_SRC(0)
+#define S526_GPCT_MODE_COUT_SRC_RTGL S526_GPCT_MODE_COUT_SRC(1)
+#define S526_GPCT_MODE_COUT_POL(x) ((x) << 1)
+#define S526_GPCT_MODE_COUT_POL_MASK S526_GPCT_MODE_COUT_POL(0x1)
+#define S526_GPCT_MODE_COUT_POL_NORM S526_GPCT_MODE_COUT_POL(0)
+#define S526_GPCT_MODE_COUT_POL_INV S526_GPCT_MODE_COUT_POL(1)
+#define S526_GPCT_MODE_AUTOLOAD(x) ((x) << 2)
+#define S526_GPCT_MODE_AUTOLOAD_MASK S526_GPCT_MODE_AUTOLOAD(0x7)
+#define S526_GPCT_MODE_AUTOLOAD_NONE S526_GPCT_MODE_AUTOLOAD(0)
+/* these 3 bits can be OR'ed */
+#define S526_GPCT_MODE_AUTOLOAD_RO S526_GPCT_MODE_AUTOLOAD(0x1)
+#define S526_GPCT_MODE_AUTOLOAD_IXFALL S526_GPCT_MODE_AUTOLOAD(0x2)
+#define S526_GPCT_MODE_AUTOLOAD_IXRISE S526_GPCT_MODE_AUTOLOAD(0x4)
+#define S526_GPCT_MODE_HWCTEN_SRC(x) ((x) << 5)
+#define S526_GPCT_MODE_HWCTEN_SRC_MASK S526_GPCT_MODE_HWCTEN_SRC(0x3)
+#define S526_GPCT_MODE_HWCTEN_SRC_CEN S526_GPCT_MODE_HWCTEN_SRC(0)
+#define S526_GPCT_MODE_HWCTEN_SRC_IX S526_GPCT_MODE_HWCTEN_SRC(1)
+#define S526_GPCT_MODE_HWCTEN_SRC_IXRF S526_GPCT_MODE_HWCTEN_SRC(2)
+#define S526_GPCT_MODE_HWCTEN_SRC_NRCAP S526_GPCT_MODE_HWCTEN_SRC(3)
+#define S526_GPCT_MODE_CTEN_CTRL(x) ((x) << 7)
+#define S526_GPCT_MODE_CTEN_CTRL_MASK S526_GPCT_MODE_CTEN_CTRL(0x3)
+#define S526_GPCT_MODE_CTEN_CTRL_DIS S526_GPCT_MODE_CTEN_CTRL(0)
+#define S526_GPCT_MODE_CTEN_CTRL_ENA S526_GPCT_MODE_CTEN_CTRL(1)
+#define S526_GPCT_MODE_CTEN_CTRL_HW S526_GPCT_MODE_CTEN_CTRL(2)
+#define S526_GPCT_MODE_CTEN_CTRL_INVHW S526_GPCT_MODE_CTEN_CTRL(3)
+#define S526_GPCT_MODE_CLK_SRC(x) ((x) << 9)
+#define S526_GPCT_MODE_CLK_SRC_MASK S526_GPCT_MODE_CLK_SRC(0x3)
+/* if count direction control set to quadrature */
+#define S526_GPCT_MODE_CLK_SRC_QUADX1 S526_GPCT_MODE_CLK_SRC(0)
+#define S526_GPCT_MODE_CLK_SRC_QUADX2 S526_GPCT_MODE_CLK_SRC(1)
+#define S526_GPCT_MODE_CLK_SRC_QUADX4 S526_GPCT_MODE_CLK_SRC(2)
+#define S526_GPCT_MODE_CLK_SRC_QUADX4_ S526_GPCT_MODE_CLK_SRC(3)
+/* if count direction control set to software control */
+#define S526_GPCT_MODE_CLK_SRC_ARISE S526_GPCT_MODE_CLK_SRC(0)
+#define S526_GPCT_MODE_CLK_SRC_AFALL S526_GPCT_MODE_CLK_SRC(1)
+#define S526_GPCT_MODE_CLK_SRC_INT S526_GPCT_MODE_CLK_SRC(2)
+#define S526_GPCT_MODE_CLK_SRC_INTHALF S526_GPCT_MODE_CLK_SRC(3)
+#define S526_GPCT_MODE_CT_DIR(x) ((x) << 11)
+#define S526_GPCT_MODE_CT_DIR_MASK S526_GPCT_MODE_CT_DIR(0x1)
+/* if count direction control set to software control */
+#define S526_GPCT_MODE_CT_DIR_UP S526_GPCT_MODE_CT_DIR(0)
+#define S526_GPCT_MODE_CT_DIR_DOWN S526_GPCT_MODE_CT_DIR(1)
+#define S526_GPCT_MODE_CTDIR_CTRL(x) ((x) << 12)
+#define S526_GPCT_MODE_CTDIR_CTRL_MASK S526_GPCT_MODE_CTDIR_CTRL(0x1)
+#define S526_GPCT_MODE_CTDIR_CTRL_QUAD S526_GPCT_MODE_CTDIR_CTRL(0)
+#define S526_GPCT_MODE_CTDIR_CTRL_SOFT S526_GPCT_MODE_CTDIR_CTRL(1)
+#define S526_GPCT_MODE_LATCH_CTRL(x) ((x) << 13)
+#define S526_GPCT_MODE_LATCH_CTRL_MASK S526_GPCT_MODE_LATCH_CTRL(0x1)
+#define S526_GPCT_MODE_LATCH_CTRL_READ S526_GPCT_MODE_LATCH_CTRL(0)
+#define S526_GPCT_MODE_LATCH_CTRL_EVENT S526_GPCT_MODE_LATCH_CTRL(1)
+#define S526_GPCT_MODE_PR_SELECT(x) ((x) << 14)
+#define S526_GPCT_MODE_PR_SELECT_MASK S526_GPCT_MODE_PR_SELECT(0x1)
+#define S526_GPCT_MODE_PR_SELECT_PR0 S526_GPCT_MODE_PR_SELECT(0)
+#define S526_GPCT_MODE_PR_SELECT_PR1 S526_GPCT_MODE_PR_SELECT(1)
+/* Control/Status - R = readable, W = writeable, C = write 1 to clear */
#define S526_GPCT_CTRL_REG(x) (0x18 + ((x) * 8))
+#define S526_GPCT_CTRL_EV_STATUS(x) ((x) << 0) /* RC */
+#define S526_GPCT_CTRL_EV_STATUS_MASK S526_GPCT_EV_STATUS(0xf)
+#define S526_GPCT_CTRL_EV_STATUS_NONE S526_GPCT_EV_STATUS(0)
+/* these 4 bits can be OR'ed */
+#define S526_GPCT_CTRL_EV_STATUS_ECAP S526_GPCT_EV_STATUS(0x1)
+#define S526_GPCT_CTRL_EV_STATUS_ICAPN S526_GPCT_EV_STATUS(0x2)
+#define S526_GPCT_CTRL_EV_STATUS_ICAPP S526_GPCT_EV_STATUS(0x4)
+#define S526_GPCT_CTRL_EV_STATUS_RCAP S526_GPCT_EV_STATUS(0x8)
+#define S526_GPCT_CTRL_COUT_STATUS BIT(4) /* R */
+#define S526_GPCT_CTRL_INDEX_STATUS BIT(5) /* R */
+#define S525_GPCT_CTRL_INTEN(x) ((x) << 6) /* W */
+#define S525_GPCT_CTRL_INTEN_MASK S526_GPCT_CTRL_INTEN(0xf)
+#define S525_GPCT_CTRL_INTEN_NONE S526_GPCT_CTRL_INTEN(0)
+/* these 4 bits can be OR'ed */
+#define S525_GPCT_CTRL_INTEN_ERROR S526_GPCT_CTRL_INTEN(0x1)
+#define S525_GPCT_CTRL_INTEN_IXFALL S526_GPCT_CTRL_INTEN(0x2)
+#define S525_GPCT_CTRL_INTEN_IXRISE S526_GPCT_CTRL_INTEN(0x4)
+#define S525_GPCT_CTRL_INTEN_RO S526_GPCT_CTRL_INTEN(0x8)
+#define S525_GPCT_CTRL_LATCH_SEL(x) ((x) << 10) /* W */
+#define S525_GPCT_CTRL_LATCH_SEL_MASK S526_GPCT_CTRL_LATCH_SEL(0x7)
+#define S525_GPCT_CTRL_LATCH_SEL_NONE S526_GPCT_CTRL_LATCH_SEL(0)
+/* these 3 bits can be OR'ed */
+#define S525_GPCT_CTRL_LATCH_SEL_IXFALL S526_GPCT_CTRL_LATCH_SEL(0x1)
+#define S525_GPCT_CTRL_LATCH_SEL_IXRISE S526_GPCT_CTRL_LATCH_SEL(0x2)
+#define S525_GPCT_CTRL_LATCH_SEL_ITIMER S526_GPCT_CTRL_LATCH_SEL(0x4)
+#define S525_GPCT_CTRL_CT_ARM BIT(13) /* W */
+#define S525_GPCT_CTRL_CT_LOAD BIT(14) /* W */
+#define S526_GPCT_CTRL_CT_RESET BIT(15) /* W */
#define S526_EEPROM_DATA_REG 0x32
#define S526_EEPROM_CTRL_REG 0x34
#define S526_EEPROM_CTRL_ADDR(x) (((x) & 0x3f) << 3)
@@ -92,41 +176,6 @@
#define S526_EEPROM_CTRL_READ S526_EEPROM_CTRL(2)
#define S526_EEPROM_CTRL_START BIT(0)
-struct counter_mode_register_t {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned short coutSource:1;
- unsigned short coutPolarity:1;
- unsigned short autoLoadResetRcap:3;
- unsigned short hwCtEnableSource:2;
- unsigned short ctEnableCtrl:2;
- unsigned short clockSource:2;
- unsigned short countDir:1;
- unsigned short countDirCtrl:1;
- unsigned short outputRegLatchCtrl:1;
- unsigned short preloadRegSel:1;
- unsigned short reserved:1;
- #elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned short reserved:1;
- unsigned short preloadRegSel:1;
- unsigned short outputRegLatchCtrl:1;
- unsigned short countDirCtrl:1;
- unsigned short countDir:1;
- unsigned short clockSource:2;
- unsigned short ctEnableCtrl:2;
- unsigned short hwCtEnableSource:2;
- unsigned short autoLoadResetRcap:3;
- unsigned short coutPolarity:1;
- unsigned short coutSource:1;
-#else
-#error Unknown bit field order
-#endif
-};
-
-union cmReg {
- struct counter_mode_register_t reg;
- unsigned short value;
-};
-
struct s526_private {
unsigned int gpct_config[4];
unsigned short ai_ctrl;
@@ -174,7 +223,6 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
struct s526_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int val;
- union cmReg cmReg;
/*
* Check what type of Counter the user requested
@@ -192,28 +240,31 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
#if 1
/* Set Counter Mode Register */
- cmReg.value = data[1] & 0xffff;
- outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan));
+ val = data[1] & 0xffff;
+ outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
/* Reset the counter if it is software preload */
- if (cmReg.reg.autoLoadResetRcap == 0) {
+ if ((val & S526_GPCT_MODE_AUTOLOAD_MASK) ==
+ S526_GPCT_MODE_AUTOLOAD_NONE) {
/* Reset the counter */
- outw(0x8000, dev->iobase + S526_GPCT_CTRL_REG(chan));
- /* Load the counter from PR0
- * outw(0x4000, dev->iobase + S526_GPCT_CTRL_REG(chan));
+ outw(S526_GPCT_CTRL_CT_RESET,
+ dev->iobase + S526_GPCT_CTRL_REG(chan));
+ /*
+ * Load the counter from PR0
+ * outw(S526_GPCT_CTRL_CT_LOAD,
+ * dev->iobase + S526_GPCT_CTRL_REG(chan));
*/
}
#else
- /* 0 quadrature, 1 software control */
- cmReg.reg.countDirCtrl = 0;
+ val = S526_GPCT_MODE_CTDIR_CTRL_QUAD;
/* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */
if (data[1] == GPCT_X2)
- cmReg.reg.clockSource = 1;
+ val |= S526_GPCT_MODE_CLK_SRC_QUADX2;
else if (data[1] == GPCT_X4)
- cmReg.reg.clockSource = 2;
+ val |= S526_GPCT_MODE_CLK_SRC_QUADX4;
else
- cmReg.reg.clockSource = 0;
+ val |= S526_GPCT_MODE_CLK_SRC_QUADX1;
/* When to take into account the indexpulse: */
/*
@@ -224,13 +275,14 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
* }
*/
/* Take into account the index pulse? */
- if (data[3] == GPCT_RESET_COUNTER_ON_INDEX)
+ if (data[3] == GPCT_RESET_COUNTER_ON_INDEX) {
/* Auto load with INDEX^ */
- cmReg.reg.autoLoadResetRcap = 4;
+ val |= S526_GPCT_MODE_AUTOLOAD_IXRISE;
+ }
/* Set Counter Mode Register */
- cmReg.value = data[1] & 0xffff;
- outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan));
+ val = data[1] & 0xffff;
+ outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
/* Load the pre-load register */
s526_gpct_write(dev, chan, data[2]);
@@ -241,11 +293,14 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
dev->iobase + S526_GPCT_CTRL_REG(chan));
/* Reset the counter if it is software preload */
- if (cmReg.reg.autoLoadResetRcap == 0) {
+ if ((val & S526_GPCT_MODE_AUTOLOAD_MASK) ==
+ S526_GPCT_MODE_AUTOLOAD_NONE) {
/* Reset the counter */
- outw(0x8000, dev->iobase + S526_GPCT_CTRL_REG(chan));
+ outw(S526_GPCT_CTRL_CT_RESET,
+ dev->iobase + S526_GPCT_CTRL_REG(chan));
/* Load the counter from PR0 */
- outw(0x4000, dev->iobase + S526_GPCT_CTRL_REG(chan));
+ outw(S526_GPCT_CTRL_CT_LOAD,
+ dev->iobase + S526_GPCT_CTRL_REG(chan));
}
#endif
break;
@@ -261,17 +316,21 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
devpriv->gpct_config[chan] = data[0];
/* Set Counter Mode Register */
- cmReg.value = data[1] & 0xffff;
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan));
+ val = data[1] & 0xffff;
+ /* Select PR0 */
+ val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
+ val |= S526_GPCT_MODE_PR_SELECT_PR0;
+ outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
/* Load the pre-load register 0 */
s526_gpct_write(dev, chan, data[2]);
/* Set Counter Mode Register */
- cmReg.value = data[1] & 0xffff;
- cmReg.reg.preloadRegSel = 1; /* PR1 */
- outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan));
+ val = data[1] & 0xffff;
+ /* Select PR1 */
+ val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
+ val |= S526_GPCT_MODE_PR_SELECT_PR1;
+ outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
/* Load the pre-load register 1 */
s526_gpct_write(dev, chan, data[3]);
@@ -294,17 +353,21 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
devpriv->gpct_config[chan] = data[0];
/* Set Counter Mode Register */
- cmReg.value = data[1] & 0xffff;
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan));
+ val = data[1] & 0xffff;
+ /* Select PR0 */
+ val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
+ val |= S526_GPCT_MODE_PR_SELECT_PR0;
+ outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
/* Load the pre-load register 0 */
s526_gpct_write(dev, chan, data[2]);
/* Set Counter Mode Register */
- cmReg.value = data[1] & 0xffff;
- cmReg.reg.preloadRegSel = 1; /* PR1 */
- outw(cmReg.value, dev->iobase + S526_GPCT_MODE_REG(chan));
+ val = data[1] & 0xffff;
+ /* Select PR1 */
+ val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
+ val |= S526_GPCT_MODE_PR_SELECT_PR1;
+ outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
/* Load the pre-load register 1 */
s526_gpct_write(dev, chan, data[3]);
diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c
index 75040daa40ce..72f0aaa6911f 100644
--- a/drivers/staging/dgnc/dgnc_cls.c
+++ b/drivers/staging/dgnc/dgnc_cls.c
@@ -934,7 +934,7 @@ static void cls_flush_uart_write(struct channel_t *ch)
writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
&ch->ch_cls_uart->isr_fcr);
- udelay(10);
+ usleep_range(10, 20);
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
}
diff --git a/drivers/staging/dgnc/dgnc_neo.c b/drivers/staging/dgnc/dgnc_neo.c
index 8106f5234bf5..39c76e78e56a 100644
--- a/drivers/staging/dgnc/dgnc_neo.c
+++ b/drivers/staging/dgnc/dgnc_neo.c
@@ -1108,9 +1108,9 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
* On the other hand, if the UART IS in FIFO mode, then ask
* the UART to give us an approximation of data it has RX'ed.
*/
- if (!(ch->ch_flags & CH_FIFO_ENABLED))
+ if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
total = 0;
- else {
+ } else {
total = readb(&ch->ch_neo_uart->rfifo);
/*
@@ -1628,7 +1628,7 @@ static void neo_uart_init(struct channel_t *ch)
/* Clear out UART and FIFO */
readb(&ch->ch_neo_uart->txrx);
- writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+ writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
readb(&ch->ch_neo_uart->lsr);
readb(&ch->ch_neo_uart->msr);
@@ -1779,8 +1779,8 @@ static void neo_vpd(struct dgnc_board *brd)
/* Store the VPD into our buffer */
for (i = 0; i < NEO_VPD_IMAGESIZE; i++) {
a = neo_read_eeprom(brd->re_map_membase, i);
- brd->vpd[i*2] = a & 0xff;
- brd->vpd[(i*2)+1] = (a >> 8) & 0xff;
+ brd->vpd[i * 2] = a & 0xff;
+ brd->vpd[(i * 2) + 1] = (a >> 8) & 0xff;
}
if (((brd->vpd[0x08] != 0x82) /* long resource name tag */
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c
index 48e4b90578c1..b79eab084c02 100644
--- a/drivers/staging/dgnc/dgnc_tty.c
+++ b/drivers/staging/dgnc/dgnc_tty.c
@@ -448,7 +448,7 @@ void dgnc_tty_uninit(struct dgnc_board *brd)
* dgnc_wmove - Write data to transmit queue.
*
* ch - Pointer to channel structure.
- * buf - Poiter to characters to be moved.
+ * buf - Pointer to characters to be moved.
* n - Number of characters to move.
*
*=======================================================================*/
diff --git a/drivers/staging/dgnc/dgnc_utils.c b/drivers/staging/dgnc/dgnc_utils.c
index f76de82908d3..95272f4765fc 100644
--- a/drivers/staging/dgnc/dgnc_utils.c
+++ b/drivers/staging/dgnc/dgnc_utils.c
@@ -1,7 +1,6 @@
#include <linux/tty.h>
#include <linux/sched.h>
#include "dgnc_utils.h"
-#include "digi.h"
/*
* dgnc_ms_sleep()
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index 4e6c16af40fc..beb9411658ba 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -823,7 +823,7 @@ static int _nbu2ss_out_dma(
u32 length
)
{
- u8 *pBuffer;
+ dma_addr_t pBuffer;
u32 mpkt;
u32 lmpkt;
u32 dmacnt;
@@ -836,7 +836,7 @@ static int _nbu2ss_out_dma(
return 1; /* DMA is forwarded */
req->dma_flag = TRUE;
- pBuffer = (u8 *)req->req.dma;
+ pBuffer = req->req.dma;
pBuffer += req->req.actual;
/* DMA Address */
@@ -1034,7 +1034,7 @@ static int _nbu2ss_in_dma(
u32 length
)
{
- u8 *pBuffer;
+ dma_addr_t pBuffer;
u32 mpkt; /* MaxPacketSize */
u32 lmpkt; /* Last Packet Data Size */
u32 dmacnt; /* IN Data Size */
@@ -1080,7 +1080,7 @@ static int _nbu2ss_in_dma(
_nbu2ss_writel(&preg->EP_DCR[num].EP_DCR2, data);
/* Address setting */
- pBuffer = (u8 *)req->req.dma;
+ pBuffer = req->req.dma;
pBuffer += req->req.actual;
_nbu2ss_writel(&preg->EP_DCR[num].EP_TADR, (u32)pBuffer);
@@ -1285,11 +1285,7 @@ static void _nbu2ss_restert_transfer(struct nbu2ss_ep *ep)
bool bflag = FALSE;
struct nbu2ss_req *req;
- if (list_empty(&ep->queue))
- req = NULL;
- else
- req = list_entry(ep->queue.next, struct nbu2ss_req, queue);
-
+ req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
if (!req)
return;
@@ -1784,11 +1780,7 @@ static inline int _nbu2ss_ep0_in_data_stage(struct nbu2ss_udc *udc)
struct nbu2ss_req *req;
struct nbu2ss_ep *ep = &udc->ep[0];
- if (list_empty(&ep->queue))
- req = NULL;
- else
- req = list_entry(ep->queue.next, struct nbu2ss_req, queue);
-
+ req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
if (!req)
req = &udc->ep0_req;
@@ -1811,11 +1803,7 @@ static inline int _nbu2ss_ep0_out_data_stage(struct nbu2ss_udc *udc)
struct nbu2ss_req *req;
struct nbu2ss_ep *ep = &udc->ep[0];
- if (list_empty(&ep->queue))
- req = NULL;
- else
- req = list_entry(ep->queue.next, struct nbu2ss_req, queue);
-
+ req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
if (!req)
req = &udc->ep0_req;
@@ -1838,11 +1826,7 @@ static inline int _nbu2ss_ep0_status_stage(struct nbu2ss_udc *udc)
struct nbu2ss_req *req;
struct nbu2ss_ep *ep = &udc->ep[0];
- if (list_empty(&ep->queue))
- req = NULL;
- else
- req = list_entry(ep->queue.next, struct nbu2ss_req, queue);
-
+ req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
if (!req) {
req = &udc->ep0_req;
if (req->req.complete)
@@ -2145,11 +2129,7 @@ static inline void _nbu2ss_epn_int(struct nbu2ss_udc *udc, u32 epnum)
/* Interrupt Clear */
_nbu2ss_writel(&udc->p_regs->EP_REGS[num].EP_STATUS, ~(u32)status);
- if (list_empty(&ep->queue))
- req = NULL;
- else
- req = list_entry(ep->queue.next, struct nbu2ss_req, queue);
-
+ req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
if (!req) {
/* pr_warn("=== %s(%d) req == NULL\n", __func__, epnum); */
return;
@@ -2728,7 +2708,7 @@ static int nbu2ss_ep_queue(
spin_lock_irqsave(&udc->lock, flags);
#ifdef USE_DMA
- if ((u32)req->req.buf & 0x3)
+ if ((uintptr_t)req->req.buf & 0x3)
req->unaligned = TRUE;
else
req->unaligned = FALSE;
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c
index b3ea4bb54e2c..b676c486cb18 100644
--- a/drivers/staging/fwserial/fwserial.c
+++ b/drivers/staging/fwserial/fwserial.c
@@ -893,11 +893,10 @@ static void fwserial_destroy(struct kref *kref)
kfree(serial);
}
-void fwtty_port_put(struct fwtty_port *port)
+static void fwtty_port_put(struct fwtty_port *port)
{
kref_put(&port->serial->kref, fwserial_destroy);
}
-EXPORT_SYMBOL(fwtty_port_put);
static void fwtty_port_dtr_rts(struct tty_port *tty_port, int on)
{
diff --git a/drivers/staging/fwserial/fwserial.h b/drivers/staging/fwserial/fwserial.h
index 787aa4f3a41b..e13fe33a6897 100644
--- a/drivers/staging/fwserial/fwserial.h
+++ b/drivers/staging/fwserial/fwserial.h
@@ -342,16 +342,6 @@ static const char loop_dev_name[] = "fwloop";
extern struct tty_driver *fwtty_driver;
struct fwtty_port *fwtty_port_get(unsigned index);
-void fwtty_port_put(struct fwtty_port *port);
-
-static inline void fwtty_bind_console(struct fwtty_port *port,
- struct fwconsole_ops *fwcon_ops,
- void *data)
-{
- port->con_data = data;
- port->fwcon_ops = fwcon_ops;
-}
-
/*
* Returns the max send async payload size in bytes based on the unit device
* link speed. Self-limiting asynchronous bandwidth (via reducing the payload)
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
index 79de678807cc..17d148f6e02c 100644
--- a/drivers/staging/gdm724x/gdm_lte.c
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -555,7 +555,7 @@ int gdm_lte_event_init(void)
void gdm_lte_event_exit(void)
{
if (lte_event.sock && --lte_event.ref_cnt == 0) {
- netlink_exit(lte_event.sock);
+ sock_release(lte_event.sock->sk_socket);
lte_event.sock = NULL;
}
}
diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c
index e2c0f228f369..eb7e2523c354 100644
--- a/drivers/staging/gdm724x/gdm_tty.c
+++ b/drivers/staging/gdm724x/gdm_tty.c
@@ -64,7 +64,7 @@ static void gdm_port_destruct(struct tty_port *port)
kfree(gdm);
}
-static struct tty_port_operations gdm_port_ops = {
+static const struct tty_port_operations gdm_port_ops = {
.destruct = gdm_port_destruct,
};
diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c
index 92254fdaae1e..9d8347769e88 100644
--- a/drivers/staging/gdm724x/netlink_k.c
+++ b/drivers/staging/gdm724x/netlink_k.c
@@ -107,11 +107,6 @@ struct sock *netlink_init(int unit,
return sock;
}
-void netlink_exit(struct sock *sock)
-{
- sock_release(sock->sk_socket);
-}
-
int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
{
static u32 seq;
diff --git a/drivers/staging/gdm724x/netlink_k.h b/drivers/staging/gdm724x/netlink_k.h
index 589486d76714..7cf979b3f826 100644
--- a/drivers/staging/gdm724x/netlink_k.h
+++ b/drivers/staging/gdm724x/netlink_k.h
@@ -19,7 +19,6 @@
struct sock *netlink_init(int unit,
void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
-void netlink_exit(struct sock *sock);
int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
#endif /* _NETLINK_K_H_ */
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
index 81feffa5784a..cad347a05d18 100644
--- a/drivers/staging/gdm72xx/gdm_qos.c
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -101,7 +101,7 @@ void gdm_qos_init(void *nic_ptr)
}
qcb->qos_list_cnt = 0;
- qcb->qos_null_idx = QOS_MAX-1;
+ qcb->qos_null_idx = QOS_MAX - 1;
qcb->qos_limit_size = 255;
spin_lock_init(&qcb->qos_lock);
@@ -128,7 +128,7 @@ void gdm_qos_release_list(void *nic_ptr)
}
qcb->qos_list_cnt = 0;
- qcb->qos_null_idx = QOS_MAX-1;
+ qcb->qos_null_idx = QOS_MAX - 1;
for (i = 0; i < QOS_MAX; i++) {
list_for_each_entry_safe(entry, n, &qcb->qos_list[i], list) {
@@ -143,18 +143,18 @@ static int chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *stream, u8 *port)
{
int i;
- if (csr->classifier_rule_en&IPTYPEOFSERVICE) {
+ if (csr->classifier_rule_en & IPTYPEOFSERVICE) {
if (((stream[1] & csr->ip2s_mask) < csr->ip2s_lo) ||
((stream[1] & csr->ip2s_mask) > csr->ip2s_hi))
return 1;
}
- if (csr->classifier_rule_en&PROTOCOL) {
+ if (csr->classifier_rule_en & PROTOCOL) {
if (stream[9] != csr->protocol)
return 1;
}
- if (csr->classifier_rule_en&IPMASKEDSRCADDRESS) {
+ if (csr->classifier_rule_en & IPMASKEDSRCADDRESS) {
for (i = 0; i < 4; i++) {
if ((stream[12 + i] & csr->ipsrc_addrmask[i]) !=
(csr->ipsrc_addr[i] & csr->ipsrc_addrmask[i]))
@@ -162,7 +162,7 @@ static int chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *stream, u8 *port)
}
}
- if (csr->classifier_rule_en&IPMASKEDDSTADDRESS) {
+ if (csr->classifier_rule_en & IPMASKEDDSTADDRESS) {
for (i = 0; i < 4; i++) {
if ((stream[16 + i] & csr->ipdst_addrmask[i]) !=
(csr->ipdst_addr[i] & csr->ipdst_addrmask[i]))
@@ -170,14 +170,14 @@ static int chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *stream, u8 *port)
}
}
- if (csr->classifier_rule_en&PROTOCOLSRCPORTRANGE) {
- i = ((port[0]<<8)&0xff00)+port[1];
+ if (csr->classifier_rule_en & PROTOCOLSRCPORTRANGE) {
+ i = ((port[0] << 8) & 0xff00) + port[1];
if ((i < csr->srcport_lo) || (i > csr->srcport_hi))
return 1;
}
- if (csr->classifier_rule_en&PROTOCOLDSTPORTRANGE) {
- i = ((port[2]<<8)&0xff00)+port[3];
+ if (csr->classifier_rule_en & PROTOCOLDSTPORTRANGE) {
+ i = ((port[2] << 8) & 0xff00) + port[3];
if ((i < csr->dstport_lo) || (i > csr->dstport_hi))
return 1;
}
@@ -193,7 +193,7 @@ static int get_qos_index(struct nic *nic, u8 *iph, u8 *tcpudph)
if (!iph || !tcpudph)
return -1;
- ip_ver = (iph[0]>>4)&0xf;
+ ip_ver = (iph[0] >> 4) & 0xf;
if (ip_ver != 4)
return -1;
@@ -342,17 +342,17 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
if (sub_cmd_evt == QOS_REPORT) {
spin_lock_irqsave(&qcb->qos_lock, flags);
for (i = 0; i < qcb->qos_list_cnt; i++) {
- sfid = ((buf[(i*5)+6]<<24)&0xff000000);
- sfid += ((buf[(i*5)+7]<<16)&0xff0000);
- sfid += ((buf[(i*5)+8]<<8)&0xff00);
- sfid += (buf[(i*5)+9]);
+ sfid = ((buf[(i*5) + 6] << 24) & 0xff000000);
+ sfid += ((buf[(i*5) + 7] << 16) & 0xff0000);
+ sfid += ((buf[(i*5) + 8] << 8) & 0xff00);
+ sfid += (buf[(i*5) + 9]);
index = get_csr(qcb, sfid, 0);
if (index == -1) {
spin_unlock_irqrestore(&qcb->qos_lock, flags);
netdev_err(nic->netdev, "QoS ERROR: No SF\n");
return;
}
- qcb->csr[index].qos_buf_count = buf[(i*5)+10];
+ qcb->csr[index].qos_buf_count = buf[(i*5) + 10];
}
extract_qos_list(nic, &send_list);
@@ -363,9 +363,9 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
/* sub_cmd_evt == QOS_ADD || sub_cmd_evt == QOS_CHANG_DEL */
pos = 6;
- sfid = ((buf[pos++]<<24)&0xff000000);
- sfid += ((buf[pos++]<<16)&0xff0000);
- sfid += ((buf[pos++]<<8)&0xff00);
+ sfid = ((buf[pos++] << 24) & 0xff000000);
+ sfid += ((buf[pos++] << 16) & 0xff0000);
+ sfid += ((buf[pos++] << 8) & 0xff00);
sfid += (buf[pos++]);
index = get_csr(qcb, sfid, 1);
@@ -382,7 +382,7 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
spin_lock_irqsave(&qcb->qos_lock, flags);
qcb->csr[index].sfid = sfid;
- qcb->csr[index].classifier_rule_en = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].classifier_rule_en = ((buf[pos++] << 8) & 0xff00);
qcb->csr[index].classifier_rule_en += buf[pos++];
if (qcb->csr[index].classifier_rule_en == 0)
qcb->qos_null_idx = index;
@@ -406,16 +406,16 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
qcb->csr[index].ipdst_addr[1] = buf[pos++];
qcb->csr[index].ipdst_addr[2] = buf[pos++];
qcb->csr[index].ipdst_addr[3] = buf[pos++];
- qcb->csr[index].srcport_lo = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].srcport_lo = ((buf[pos++] << 8) & 0xff00);
qcb->csr[index].srcport_lo += buf[pos++];
- qcb->csr[index].srcport_hi = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].srcport_hi = ((buf[pos++] << 8) & 0xff00);
qcb->csr[index].srcport_hi += buf[pos++];
- qcb->csr[index].dstport_lo = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].dstport_lo = ((buf[pos++] << 8) & 0xff00);
qcb->csr[index].dstport_lo += buf[pos++];
- qcb->csr[index].dstport_hi = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].dstport_hi = ((buf[pos++] << 8) & 0xff00);
qcb->csr[index].dstport_hi += buf[pos++];
- qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+ qcb->qos_limit_size = 254 / qcb->qos_list_cnt;
spin_unlock_irqrestore(&qcb->qos_lock, flags);
} else if (sub_cmd_evt == QOS_CHANGE_DEL) {
netdev_dbg(nic->netdev, "QOS_CHANGE_DEL SFID = 0x%x, index=%d\n",
@@ -426,7 +426,7 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
spin_lock_irqsave(&qcb->qos_lock, flags);
qcb->csr[index].enabled = false;
qcb->qos_list_cnt--;
- qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+ qcb->qos_limit_size = 254 / qcb->qos_list_cnt;
list_for_each_entry_safe(entry, n, &qcb->qos_list[index],
list) {
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
index b0521da3c793..1f5a087723ba 100644
--- a/drivers/staging/gdm72xx/gdm_sdio.c
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -36,7 +36,7 @@
#define RX_BUF_SIZE (25*1024)
#define TX_HZ 2000
-#define TX_INTERVAL (1000000/TX_HZ)
+#define TX_INTERVAL (NSEC_PER_SEC/TX_HZ)
static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx)
{
@@ -303,7 +303,7 @@ static void send_sdu(struct sdio_func *func, struct tx_cxt *tx)
put_tx_struct(t->tx_cxt, t);
}
- do_gettimeofday(&tx->sdu_stamp);
+ tx->sdu_stamp = ktime_get();
spin_unlock_irqrestore(&tx->lock, flags);
}
@@ -330,7 +330,7 @@ static void do_tx(struct work_struct *work)
struct sdio_func *func = sdev->func;
struct tx_cxt *tx = &sdev->tx;
struct sdio_tx *t = NULL;
- struct timeval now, *before;
+ ktime_t now, before;
int is_sdu = 0;
long diff;
unsigned long flags;
@@ -346,11 +346,10 @@ static void do_tx(struct work_struct *work)
list_del(&t->list);
is_sdu = 0;
} else if (!tx->stop_sdu_tx && !list_empty(&tx->sdu_list)) {
- do_gettimeofday(&now);
- before = &tx->sdu_stamp;
+ now = ktime_get();
+ before = tx->sdu_stamp;
- diff = (now.tv_sec - before->tv_sec) * 1000000 +
- (now.tv_usec - before->tv_usec);
+ diff = ktime_to_ns(ktime_sub(now, before));
if (diff >= 0 && diff < TX_INTERVAL) {
schedule_work(&sdev->ws);
spin_unlock_irqrestore(&tx->lock, flags);
diff --git a/drivers/staging/gdm72xx/gdm_sdio.h b/drivers/staging/gdm72xx/gdm_sdio.h
index 77ad9d686f8e..aa7dad22a219 100644
--- a/drivers/staging/gdm72xx/gdm_sdio.h
+++ b/drivers/staging/gdm72xx/gdm_sdio.h
@@ -15,7 +15,7 @@
#define __GDM72XX_GDM_SDIO_H__
#include <linux/types.h>
-#include <linux/time.h>
+#include <linux/ktime.h>
#define MAX_NR_SDU_BUF 64
@@ -32,7 +32,7 @@ struct tx_cxt {
struct list_head free_list;
struct list_head sdu_list;
struct list_head hci_list;
- struct timeval sdu_stamp;
+ ktime_t sdu_stamp;
u8 *sdu_buf;
spinlock_t lock;
int can_send;
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
index d9ddced96e19..ba03f9386567 100644
--- a/drivers/staging/gdm72xx/gdm_wimax.c
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -84,11 +84,6 @@ static inline struct evt_entry *alloc_event_entry(void)
return kmalloc(sizeof(struct evt_entry), GFP_ATOMIC);
}
-static inline void free_event_entry(struct evt_entry *e)
-{
- kfree(e);
-}
-
static struct evt_entry *get_event_entry(void)
{
struct evt_entry *e;
@@ -180,11 +175,11 @@ static void gdm_wimax_event_exit(void)
list_for_each_entry_safe(e, temp, &wm_event.evtq, list) {
list_del(&e->list);
- free_event_entry(e);
+ kfree(e);
}
list_for_each_entry_safe(e, temp, &wm_event.freeq, list) {
list_del(&e->list);
- free_event_entry(e);
+ kfree(e);
}
spin_unlock_irqrestore(&wm_event.evt_lock, flags);
@@ -368,7 +363,7 @@ static void kdelete(void **buf)
}
}
-static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
+static int gdm_wimax_ioctl_get_data(struct udata_s *dst, struct data_s *src)
{
int size;
@@ -384,7 +379,7 @@ static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
return 0;
}
-static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src)
+static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct udata_s *src)
{
if (!src->size) {
dst->size = 0;
@@ -460,6 +455,7 @@ static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct wm_req_s *req = (struct wm_req_s *)ifr;
struct nic *nic = netdev_priv(dev);
int ret;
+ struct fsm_s fsm_buf;
if (cmd != SIOCWMIOCTL)
return -EOPNOTSUPP;
@@ -482,8 +478,11 @@ static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* NOTE: gdm_update_fsm should be called
* before gdm_wimax_ioctl_set_data is called.
*/
- gdm_update_fsm(dev,
- req->data.buf);
+ if (copy_from_user(&fsm_buf, req->data.buf,
+ sizeof(struct fsm_s)))
+ return -EFAULT;
+
+ gdm_update_fsm(dev, &fsm_buf);
}
ret = gdm_wimax_ioctl_set_data(
&nic->sdk_data[req->data_id], &req->data);
diff --git a/drivers/staging/gdm72xx/wm_ioctl.h b/drivers/staging/gdm72xx/wm_ioctl.h
index ed8f649c0042..631cb1d23c7e 100644
--- a/drivers/staging/gdm72xx/wm_ioctl.h
+++ b/drivers/staging/gdm72xx/wm_ioctl.h
@@ -78,13 +78,18 @@ struct data_s {
void *buf;
};
+struct udata_s {
+ int size;
+ void __user *buf;
+};
+
struct wm_req_s {
union {
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
unsigned short cmd;
unsigned short data_id;
- struct data_s data;
+ struct udata_s data;
/* NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq). */
};
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 9d7f0004d2d7..0e044cb0def8 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -17,33 +17,4 @@ source "drivers/staging/iio/meter/Kconfig"
source "drivers/staging/iio/resolver/Kconfig"
source "drivers/staging/iio/trigger/Kconfig"
-config IIO_DUMMY_EVGEN
- tristate
- select IRQ_WORK
-
-config IIO_SIMPLE_DUMMY
- tristate "An example driver with no hardware requirements"
- help
- Driver intended mainly as documentation for how to write
- a driver. May also be useful for testing userspace code
- without hardware.
-
-if IIO_SIMPLE_DUMMY
-
-config IIO_SIMPLE_DUMMY_EVENTS
- bool "Event generation support"
- select IIO_DUMMY_EVGEN
- help
- Add some dummy events to the simple dummy driver.
-
-config IIO_SIMPLE_DUMMY_BUFFER
- bool "Buffered capture support"
- select IIO_BUFFER
- select IIO_TRIGGER
- select IIO_KFIFO_BUF
- help
- Add buffered data capture to the simple dummy driver.
-
-endif # IIO_SIMPLE_DUMMY
-
endmenu
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index d87106135b27..3e616b4437f5 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -2,13 +2,6 @@
# Makefile for the industrial I/O core.
#
-obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
-iio_dummy-y := iio_simple_dummy.o
-iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o
-iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
-
-obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
-
obj-y += accel/
obj-y += adc/
obj-y += addac/
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index 20b878d35ea2..1920dc60cf3d 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -48,7 +48,7 @@ static int sca3000_read_data(struct sca3000_state *st,
}
};
*rx_p = kmalloc(len, GFP_KERNEL);
- if (*rx_p == NULL) {
+ if (!*rx_p) {
ret = -ENOMEM;
goto error_ret;
}
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 94ae4232ee77..58d4517e1836 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -23,7 +23,7 @@ config AD7606_IFACE_PARALLEL
ADC driver.
To compile this driver as a module, choose M here: the
- module will be called ad7606_iface_parallel.
+ module will be called ad7606_parallel.
config AD7606_IFACE_SPI
tristate "spi interface support"
@@ -34,7 +34,7 @@ config AD7606_IFACE_SPI
ADC driver.
To compile this driver as a module, choose M here: the
- module will be called ad7606_iface_spi.
+ module will be called ad7606_spi.
config AD7780
tristate "Analog Devices AD7780 and similar ADCs driver"
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index 1c4277dbd318..0c87ce3530f8 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -2,10 +2,9 @@
# Makefile for industrial I/O ADC drivers
#
-ad7606-y := ad7606_core.o
-ad7606-$(CONFIG_IIO_BUFFER) += ad7606_ring.o
-ad7606-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
-ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
+ad7606-y := ad7606_core.o ad7606_ring.o
+obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
+obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7780) += ad7780.o
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index bb40f3728742..92211039ffa9 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -609,7 +609,7 @@ static const struct iio_chan_spec ad7192_channels[] = {
static int ad7192_probe(struct spi_device *spi)
{
- const struct ad7192_platform_data *pdata = spi->dev.platform_data;
+ const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7192_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 35acb1a4669b..f45ebedb7a05 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -833,7 +833,7 @@ static const struct ad7280_platform_data ad7793_default_pdata = {
static int ad7280_probe(struct spi_device *spi)
{
- const struct ad7280_platform_data *pdata = spi->dev.platform_data;
+ const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7280_state *st;
int ret;
const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890};
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index 5796ed2409d0..2c9d8b7de9f5 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -559,6 +559,7 @@ error_disable_reg:
regulator_disable(st->reg);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(ad7606_probe);
int ad7606_remove(struct iio_dev *indio_dev, int irq)
{
@@ -575,6 +576,7 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq)
return 0;
}
+EXPORT_SYMBOL_GPL(ad7606_remove);
void ad7606_suspend(struct iio_dev *indio_dev)
{
@@ -586,6 +588,7 @@ void ad7606_suspend(struct iio_dev *indio_dev)
gpio_set_value(st->pdata->gpio_stby, 0);
}
}
+EXPORT_SYMBOL_GPL(ad7606_suspend);
void ad7606_resume(struct iio_dev *indio_dev)
{
@@ -600,6 +603,7 @@ void ad7606_resume(struct iio_dev *indio_dev)
ad7606_reset(st);
}
}
+EXPORT_SYMBOL_GPL(ad7606_resume);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index 3abc7789237f..1439cfdbb09c 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -15,15 +15,13 @@
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/sched.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/adc/ad_sigma_delta.h>
-#include "ad7780.h"
-
#define AD7780_RDY BIT(7)
#define AD7780_FILTER BIT(6)
#define AD7780_ERR BIT(5)
@@ -42,7 +40,7 @@ struct ad7780_chip_info {
struct ad7780_state {
const struct ad7780_chip_info *chip_info;
struct regulator *reg;
- int powerdown_gpio;
+ struct gpio_desc *powerdown_gpio;
unsigned int gain;
u16 int_vref_mv;
@@ -77,8 +75,7 @@ static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta,
break;
}
- if (gpio_is_valid(st->powerdown_gpio))
- gpio_set_value(st->powerdown_gpio, val);
+ gpiod_set_value(st->powerdown_gpio, val);
return 0;
}
@@ -163,7 +160,6 @@ static const struct iio_info ad7780_info = {
static int ad7780_probe(struct spi_device *spi)
{
- struct ad7780_platform_data *pdata = spi->dev.platform_data;
struct ad7780_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
@@ -189,12 +185,10 @@ static int ad7780_probe(struct spi_device *spi)
st->chip_info =
&ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- if (pdata && pdata->vref_mv)
- st->int_vref_mv = pdata->vref_mv;
- else if (voltage_uv)
+ if (voltage_uv)
st->int_vref_mv = voltage_uv / 1000;
else
- dev_warn(&spi->dev, "reference voltage unspecified\n");
+ dev_warn(&spi->dev, "Reference voltage unspecified\n");
spi_set_drvdata(spi, indio_dev);
@@ -205,18 +199,14 @@ static int ad7780_probe(struct spi_device *spi)
indio_dev->num_channels = 1;
indio_dev->info = &ad7780_info;
- if (pdata && gpio_is_valid(pdata->gpio_pdrst)) {
- ret = devm_gpio_request_one(&spi->dev,
- pdata->gpio_pdrst,
- GPIOF_OUT_INIT_LOW,
- "AD7780 /PDRST");
- if (ret) {
- dev_err(&spi->dev, "failed to request GPIO PDRST\n");
- goto error_disable_reg;
- }
- st->powerdown_gpio = pdata->gpio_pdrst;
- } else {
- st->powerdown_gpio = -1;
+ st->powerdown_gpio = devm_gpiod_get_optional(&spi->dev,
+ "powerdown",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->powerdown_gpio)) {
+ ret = PTR_ERR(st->powerdown_gpio);
+ dev_err(&spi->dev, "Failed to request powerdown GPIO: %d\n",
+ ret);
+ goto error_disable_reg;
}
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
diff --git a/drivers/staging/iio/adc/ad7780.h b/drivers/staging/iio/adc/ad7780.h
deleted file mode 100644
index 67e511c3d6f0..000000000000
--- a/drivers/staging/iio/adc/ad7780.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * AD7780/AD7781 SPI ADC driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-#ifndef IIO_ADC_AD7780_H_
-#define IIO_ADC_AD7780_H_
-
-/*
- * TODO: struct ad7780_platform_data needs to go into include/linux/iio
- */
-
-/* NOTE:
- * The AD7780 doesn't feature a dedicated SPI chip select, in addition it
- * features a dual use data out ready DOUT/RDY output.
- * In order to avoid contentions on the SPI bus, it's therefore necessary
- * to use spi bus locking combined with a dedicated GPIO to control the
- * power down reset signal of the AD7780.
- *
- * The DOUT/RDY output must also be wired to an interrupt capable GPIO.
- */
-
-struct ad7780_platform_data {
- u16 vref_mv;
- int gpio_pdrst;
-};
-
-#endif /* IIO_ADC_AD7780_H_ */
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index c8e156646528..22260512cf01 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -345,7 +345,7 @@ static int ad7816_probe(struct spi_device *spi_dev)
{
struct ad7816_chip_info *chip;
struct iio_dev *indio_dev;
- unsigned short *pins = spi_dev->dev.platform_data;
+ unsigned short *pins = dev_get_platdata(&spi_dev->dev);
int ret = 0;
int i;
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index d997d9c74ca8..bb1f15224ac8 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -319,12 +319,12 @@ struct mxs_lradc {
#define LRADC_CH_VALUE_OFFSET 0
#define LRADC_DELAY(n) (0xd0 + (0x10 * (n)))
-#define LRADC_DELAY_TRIGGER_LRADCS_MASK (0xff << 24)
+#define LRADC_DELAY_TRIGGER_LRADCS_MASK (0xffUL << 24)
#define LRADC_DELAY_TRIGGER_LRADCS_OFFSET 24
#define LRADC_DELAY_TRIGGER(x) \
(((x) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) & \
LRADC_DELAY_TRIGGER_LRADCS_MASK)
-#define LRADC_DELAY_KICK (1 << 20)
+#define LRADC_DELAY_KICK BIT(20)
#define LRADC_DELAY_TRIGGER_DELAYS_MASK (0xf << 16)
#define LRADC_DELAY_TRIGGER_DELAYS_OFFSET 16
#define LRADC_DELAY_TRIGGER_DELAYS(x) \
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 2b65faa6296a..18b27a1984b2 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -201,7 +201,7 @@ static const struct iio_info ad9832_info = {
static int ad9832_probe(struct spi_device *spi)
{
- struct ad9832_platform_data *pdata = spi->dev.platform_data;
+ struct ad9832_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad9832_state *st;
struct regulator *reg;
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 6464f2cbe94b..6366216e4f37 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -318,7 +318,7 @@ static const struct iio_info ad9833_info = {
static int ad9834_probe(struct spi_device *spi)
{
- struct ad9834_platform_data *pdata = spi->dev.platform_data;
+ struct ad9834_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad9834_state *st;
struct iio_dev *indio_dev;
struct regulator *reg;
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index 9dfd04855a1b..5b1c1650a0e4 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -1898,7 +1898,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
mutex_init(&chip->prox_mutex);
chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
- chip->pdata = clientp->dev.platform_data;
+ chip->pdata = dev_get_platdata(&clientp->dev);
chip->id = id->driver_data;
chip->chip_info =
&tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
index 4d74e8af5088..0d8a91ee5ffc 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -42,13 +42,6 @@
#include "curproc.h"
-static inline int __is_po2(unsigned long long val)
-{
- return !(val & (val - 1));
-}
-
-#define IS_PO2(val) __is_po2((unsigned long long)(val))
-
#define LOWEST_BIT_SET(x) ((x) & ~((x) - 1))
/*
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
index 787867847483..1530b0458a61 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
@@ -22,7 +22,8 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Intel Corporation.
+ *
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
index 70b8b29e831c..c3f2332fa043 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -41,6 +41,9 @@
#ifndef __LIBCFS_HASH_H__
#define __LIBCFS_HASH_H__
+
+#include <linux/hash.h>
+
/*
* Knuth recommends primes in approximately golden ratio to the maximum
* integer representable by a machine word for multiplicative hashing.
@@ -56,22 +59,13 @@
/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
#define CFS_GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001ULL
-/*
- * Ideally we would use HAVE_HASH_LONG for this, but on linux we configure
- * the linux kernel and user space at the same time, so we need to differentiate
- * between them explicitly. If this is not needed on other architectures, then
- * we'll need to move the functions to architecture specific headers.
- */
-
-#include <linux/hash.h>
-
/** disable debug */
-#define CFS_HASH_DEBUG_NONE 0
+#define CFS_HASH_DEBUG_NONE 0
/** record hash depth and output to console when it's too deep,
* computing overhead is low but consume more memory */
-#define CFS_HASH_DEBUG_1 1
+#define CFS_HASH_DEBUG_1 1
/** expensive, check key validation */
-#define CFS_HASH_DEBUG_2 2
+#define CFS_HASH_DEBUG_2 2
#define CFS_HASH_DEBUG_LEVEL CFS_HASH_DEBUG_NONE
@@ -108,16 +102,18 @@ struct cfs_hash_bucket {
* cfs_hash bucket descriptor, it's normally in stack of caller
*/
struct cfs_hash_bd {
- struct cfs_hash_bucket *bd_bucket; /**< address of bucket */
- unsigned int bd_offset; /**< offset in bucket */
+ /* address of bucket */
+ struct cfs_hash_bucket *bd_bucket;
+ /* offset in bucket */
+ unsigned int bd_offset;
};
-#define CFS_HASH_NAME_LEN 16 /**< default name length */
-#define CFS_HASH_BIGNAME_LEN 64 /**< bigname for param tree */
+#define CFS_HASH_NAME_LEN 16 /**< default name length */
+#define CFS_HASH_BIGNAME_LEN 64 /**< bigname for param tree */
-#define CFS_HASH_BKT_BITS 3 /**< default bits of bucket */
-#define CFS_HASH_BITS_MAX 30 /**< max bits of bucket */
-#define CFS_HASH_BITS_MIN CFS_HASH_BKT_BITS
+#define CFS_HASH_BKT_BITS 3 /**< default bits of bucket */
+#define CFS_HASH_BITS_MAX 30 /**< max bits of bucket */
+#define CFS_HASH_BITS_MIN CFS_HASH_BKT_BITS
/**
* common hash attributes.
@@ -133,41 +129,41 @@ enum cfs_hash_tag {
*/
CFS_HASH_NO_LOCK = 1 << 0,
/** no bucket lock, use one spinlock to protect the whole hash */
- CFS_HASH_NO_BKTLOCK = 1 << 1,
+ CFS_HASH_NO_BKTLOCK = 1 << 1,
/** rwlock to protect bucket */
- CFS_HASH_RW_BKTLOCK = 1 << 2,
+ CFS_HASH_RW_BKTLOCK = 1 << 2,
/** spinlock to protect bucket */
- CFS_HASH_SPIN_BKTLOCK = 1 << 3,
+ CFS_HASH_SPIN_BKTLOCK = 1 << 3,
/** always add new item to tail */
- CFS_HASH_ADD_TAIL = 1 << 4,
+ CFS_HASH_ADD_TAIL = 1 << 4,
/** hash-table doesn't have refcount on item */
- CFS_HASH_NO_ITEMREF = 1 << 5,
+ CFS_HASH_NO_ITEMREF = 1 << 5,
/** big name for param-tree */
CFS_HASH_BIGNAME = 1 << 6,
/** track global count */
CFS_HASH_COUNTER = 1 << 7,
/** rehash item by new key */
- CFS_HASH_REHASH_KEY = 1 << 8,
+ CFS_HASH_REHASH_KEY = 1 << 8,
/** Enable dynamic hash resizing */
- CFS_HASH_REHASH = 1 << 9,
+ CFS_HASH_REHASH = 1 << 9,
/** can shrink hash-size */
- CFS_HASH_SHRINK = 1 << 10,
+ CFS_HASH_SHRINK = 1 << 10,
/** assert hash is empty on exit */
- CFS_HASH_ASSERT_EMPTY = 1 << 11,
+ CFS_HASH_ASSERT_EMPTY = 1 << 11,
/** record hlist depth */
- CFS_HASH_DEPTH = 1 << 12,
+ CFS_HASH_DEPTH = 1 << 12,
/**
* rehash is always scheduled in a different thread, so current
* change on hash table is non-blocking
*/
- CFS_HASH_NBLK_CHANGE = 1 << 13,
+ CFS_HASH_NBLK_CHANGE = 1 << 13,
/** NB, we typed hs_flags as __u16, please change it
* if you need to extend >=16 flags */
};
/** most used attributes */
-#define CFS_HASH_DEFAULT (CFS_HASH_RW_BKTLOCK | \
- CFS_HASH_COUNTER | CFS_HASH_REHASH)
+#define CFS_HASH_DEFAULT (CFS_HASH_RW_BKTLOCK | \
+ CFS_HASH_COUNTER | CFS_HASH_REHASH)
/**
* cfs_hash is a hash-table implementation for general purpose, it can support:
@@ -211,7 +207,7 @@ enum cfs_hash_tag {
struct cfs_hash {
/** serialize with rehash, or serialize all operations if
* the hash-table has CFS_HASH_NO_BKTLOCK */
- union cfs_hash_lock hs_lock;
+ union cfs_hash_lock hs_lock;
/** hash operations */
struct cfs_hash_ops *hs_ops;
/** hash lock operations */
@@ -219,57 +215,57 @@ struct cfs_hash {
/** hash list operations */
struct cfs_hash_hlist_ops *hs_hops;
/** hash buckets-table */
- struct cfs_hash_bucket **hs_buckets;
+ struct cfs_hash_bucket **hs_buckets;
/** total number of items on this hash-table */
- atomic_t hs_count;
+ atomic_t hs_count;
/** hash flags, see cfs_hash_tag for detail */
- __u16 hs_flags;
+ __u16 hs_flags;
/** # of extra-bytes for bucket, for user saving extended attributes */
- __u16 hs_extra_bytes;
+ __u16 hs_extra_bytes;
/** wants to iterate */
- __u8 hs_iterating;
+ __u8 hs_iterating;
/** hash-table is dying */
- __u8 hs_exiting;
+ __u8 hs_exiting;
/** current hash bits */
- __u8 hs_cur_bits;
+ __u8 hs_cur_bits;
/** min hash bits */
- __u8 hs_min_bits;
+ __u8 hs_min_bits;
/** max hash bits */
- __u8 hs_max_bits;
+ __u8 hs_max_bits;
/** bits for rehash */
- __u8 hs_rehash_bits;
+ __u8 hs_rehash_bits;
/** bits for each bucket */
- __u8 hs_bkt_bits;
+ __u8 hs_bkt_bits;
/** resize min threshold */
- __u16 hs_min_theta;
+ __u16 hs_min_theta;
/** resize max threshold */
- __u16 hs_max_theta;
+ __u16 hs_max_theta;
/** resize count */
- __u32 hs_rehash_count;
+ __u32 hs_rehash_count;
/** # of iterators (caller of cfs_hash_for_each_*) */
- __u32 hs_iterators;
+ __u32 hs_iterators;
/** rehash workitem */
- cfs_workitem_t hs_rehash_wi;
+ cfs_workitem_t hs_rehash_wi;
/** refcount on this hash table */
- atomic_t hs_refcount;
+ atomic_t hs_refcount;
/** rehash buckets-table */
- struct cfs_hash_bucket **hs_rehash_buckets;
+ struct cfs_hash_bucket **hs_rehash_buckets;
#if CFS_HASH_DEBUG_LEVEL >= CFS_HASH_DEBUG_1
/** serialize debug members */
spinlock_t hs_dep_lock;
/** max depth */
- unsigned int hs_dep_max;
+ unsigned int hs_dep_max;
/** id of the deepest bucket */
- unsigned int hs_dep_bkt;
+ unsigned int hs_dep_bkt;
/** offset in the deepest bucket */
- unsigned int hs_dep_off;
+ unsigned int hs_dep_off;
/** bits when we found the max depth */
- unsigned int hs_dep_bits;
+ unsigned int hs_dep_bits;
/** workitem to output max depth */
- cfs_workitem_t hs_dep_wi;
+ cfs_workitem_t hs_dep_wi;
#endif
/** name of htable */
- char hs_name[0];
+ char hs_name[0];
};
struct cfs_hash_lock_ops {
@@ -324,11 +320,11 @@ struct cfs_hash_ops {
};
/** total number of buckets in @hs */
-#define CFS_HASH_NBKT(hs) \
+#define CFS_HASH_NBKT(hs) \
(1U << ((hs)->hs_cur_bits - (hs)->hs_bkt_bits))
/** total number of buckets in @hs while rehashing */
-#define CFS_HASH_RH_NBKT(hs) \
+#define CFS_HASH_RH_NBKT(hs) \
(1U << ((hs)->hs_rehash_bits - (hs)->hs_bkt_bits))
/** number of hlist for in bucket */
@@ -433,19 +429,22 @@ cfs_hash_with_nblk_change(struct cfs_hash *hs)
static inline int
cfs_hash_is_exiting(struct cfs_hash *hs)
-{ /* cfs_hash_destroy is called */
+{
+ /* cfs_hash_destroy is called */
return hs->hs_exiting;
}
static inline int
cfs_hash_is_rehashing(struct cfs_hash *hs)
-{ /* rehash is launched */
+{
+ /* rehash is launched */
return hs->hs_rehash_bits != 0;
}
static inline int
cfs_hash_is_iterating(struct cfs_hash *hs)
-{ /* someone is calling cfs_hash_for_each_* */
+{
+ /* someone is calling cfs_hash_for_each_* */
return hs->hs_iterating || hs->hs_iterators != 0;
}
@@ -641,13 +640,6 @@ cfs_hash_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
struct hlist_node *
cfs_hash_bd_peek_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
const void *key);
-struct hlist_node *
-cfs_hash_bd_findadd_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- const void *key, struct hlist_node *hnode,
- int insist_add);
-struct hlist_node *
-cfs_hash_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- const void *key, struct hlist_node *hnode);
/**
* operations on cfs_hash bucket (bd: bucket descriptor),
@@ -758,7 +750,7 @@ static inline void
cfs_hash_bucket_validate(struct cfs_hash *hs, struct cfs_hash_bd *bd,
struct hlist_node *hnode)
{
- struct cfs_hash_bd bds[2];
+ struct cfs_hash_bd bds[2];
cfs_hash_dual_bd_get(hs, cfs_hash_key(hs, hnode), bds);
LASSERT(bds[0].bd_bucket == bd->bd_bucket ||
@@ -777,9 +769,9 @@ cfs_hash_bucket_validate(struct cfs_hash *hs, struct cfs_hash_bd *bd,
#endif /* CFS_HASH_DEBUG_LEVEL */
-#define CFS_HASH_THETA_BITS 10
-#define CFS_HASH_MIN_THETA (1U << (CFS_HASH_THETA_BITS - 1))
-#define CFS_HASH_MAX_THETA (1U << (CFS_HASH_THETA_BITS + 1))
+#define CFS_HASH_THETA_BITS 10
+#define CFS_HASH_MIN_THETA (1U << (CFS_HASH_THETA_BITS - 1))
+#define CFS_HASH_MAX_THETA (1U << (CFS_HASH_THETA_BITS + 1))
/* Return integer component of theta */
static inline int __cfs_hash_theta_int(int theta)
@@ -848,20 +840,20 @@ cfs_hash_u64_hash(const __u64 key, unsigned mask)
}
/** iterate over all buckets in @bds (array of struct cfs_hash_bd) */
-#define cfs_hash_for_each_bd(bds, n, i) \
+#define cfs_hash_for_each_bd(bds, n, i) \
for (i = 0; i < n && (bds)[i].bd_bucket != NULL; i++)
/** iterate over all buckets of @hs */
-#define cfs_hash_for_each_bucket(hs, bd, pos) \
- for (pos = 0; \
- pos < CFS_HASH_NBKT(hs) && \
+#define cfs_hash_for_each_bucket(hs, bd, pos) \
+ for (pos = 0; \
+ pos < CFS_HASH_NBKT(hs) && \
((bd)->bd_bucket = (hs)->hs_buckets[pos]) != NULL; pos++)
/** iterate over all hlist of bucket @bd */
-#define cfs_hash_bd_for_each_hlist(hs, bd, hlist) \
- for ((bd)->bd_offset = 0; \
- (bd)->bd_offset < CFS_HASH_BKT_NHLIST(hs) && \
- (hlist = cfs_hash_bd_hhead(hs, bd)) != NULL; \
+#define cfs_hash_bd_for_each_hlist(hs, bd, hlist) \
+ for ((bd)->bd_offset = 0; \
+ (bd)->bd_offset < CFS_HASH_BKT_NHLIST(hs) && \
+ (hlist = cfs_hash_bd_hhead(hs, bd)) != NULL; \
(bd)->bd_offset++)
/* !__LIBCFS__HASH_H__ */
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h
index a989d2666230..41f3d810aea4 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h
@@ -91,7 +91,7 @@ typedef int (*libcfs_kkuc_cb_t)(__u32 data, void *cb_arg);
/* Kernel methods */
int libcfs_kkuc_msg_put(struct file *fp, void *payload);
int libcfs_kkuc_group_put(int group, void *payload);
-int libcfs_kkuc_group_add(struct file *fp, int uid, int group,
+int libcfs_kkuc_group_add(struct file *fp, int uid, unsigned int group,
__u32 data);
int libcfs_kkuc_group_rem(int uid, int group);
int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func,
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
index f0b0423a716b..d6273e143324 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
@@ -185,8 +185,6 @@ int libcfs_debug_cleanup(void);
int libcfs_debug_clear_buffer(void);
int libcfs_debug_mark_buffer(const char *text);
-void libcfs_debug_set_level(unsigned int debug_level);
-
/*
* allocate per-cpu-partition data, returned value is an array of pointers,
* variable can be indexed by CPU ID.
diff --git a/drivers/staging/lustre/include/linux/lnet/api.h b/drivers/staging/lustre/include/linux/lnet/api.h
index 9493d5e236c5..75285fde15e8 100644
--- a/drivers/staging/lustre/include/linux/lnet/api.h
+++ b/drivers/staging/lustre/include/linux/lnet/api.h
@@ -161,12 +161,6 @@ int LNetEQAlloc(unsigned int count_in,
int LNetEQFree(lnet_handle_eq_t eventq_in);
-int LNetEQGet(lnet_handle_eq_t eventq_in,
- lnet_event_t *event_out);
-
-int LNetEQWait(lnet_handle_eq_t eventq_in,
- lnet_event_t *event_out);
-
int LNetEQPoll(lnet_handle_eq_t *eventqs_in,
int neq_in,
int timeout_ms,
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
index b61d5045a566..b67a6607bb3b 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
@@ -23,7 +23,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012 - 2015, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h
index d792c4adb0ca..3bb9468e0b9d 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-types.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h
@@ -23,7 +23,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012 - 2015, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/include/linux/lnet/nidstr.h b/drivers/staging/lustre/include/linux/lnet/nidstr.h
index 46ad9147ad2a..4fc9ddce829d 100644
--- a/drivers/staging/lustre/include/linux/lnet/nidstr.h
+++ b/drivers/staging/lustre/include/linux/lnet/nidstr.h
@@ -23,7 +23,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011 - 2015, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
#ifndef _LNET_NIDSTRINGS_H
#define _LNET_NIDSTRINGS_H
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 7c730e3f7453..72af486b65df 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -2865,7 +2865,7 @@ static int __init kiblnd_module_init(void)
return 0;
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Kernel OpenIB gen2 LND v2.00");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index 263db37de7c8..025faa9f86b3 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index 260750354a41..c7b9ccb13f1c 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index ecfe73302350..05aa90ea597a 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -2621,8 +2621,8 @@ ksocknal_enumerate_interfaces(ksock_net_t *net)
net->ksnn_interfaces[j].ksni_ipaddr = ip;
net->ksnn_interfaces[j].ksni_netmask = mask;
- strncpy(&net->ksnn_interfaces[j].ksni_name[0],
- names[i], IFNAMSIZ);
+ strlcpy(net->ksnn_interfaces[j].ksni_name,
+ names[i], sizeof(net->ksnn_interfaces[j].ksni_name));
j++;
}
@@ -2805,8 +2805,9 @@ ksocknal_startup(lnet_ni_t *ni)
goto fail_1;
}
- strncpy(&net->ksnn_interfaces[i].ksni_name[0],
- ni->ni_interfaces[i], IFNAMSIZ);
+ strlcpy(net->ksnn_interfaces[i].ksni_name,
+ ni->ni_interfaces[i],
+ sizeof(net->ksnn_interfaces[i].ksni_name));
}
net->ksnn_ninterfaces = i;
}
@@ -2868,7 +2869,7 @@ ksocknal_module_init(void)
return 0;
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Kernel TCP Socket LND v3.0.0");
MODULE_LICENSE("GPL");
MODULE_VERSION("3.0.0");
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
index b349847f9cf9..f4fa72550657 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
@@ -679,6 +679,9 @@ int ksocknal_lib_recv_kiov(ksock_conn_t *conn);
int ksocknal_lib_get_conn_tunables(ksock_conn_t *conn, int *txmem,
int *rxmem, int *nagle);
+void ksocknal_read_callback(ksock_conn_t *conn);
+void ksocknal_write_callback(ksock_conn_t *conn);
+
int ksocknal_tunables_init(void);
void ksocknal_lib_csum_tx(ksock_tx_t *tx);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c
index 9de4f23910d8..cf8e43bd3c03 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c
@@ -580,8 +580,6 @@ ksocknal_lib_push_conn(ksock_conn_t *conn)
ksocknal_connsock_decref(conn);
}
-extern void ksocknal_read_callback(ksock_conn_t *conn);
-extern void ksocknal_write_callback(ksock_conn_t *conn);
/*
* socket call back in Linux
*/
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index 92ca1dd64076..fed57d90028d 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c
index 395412639935..362282fa00bf 100644
--- a/drivers/staging/lustre/lnet/lnet/api-ni.c
+++ b/drivers/staging/lustre/lnet/lnet/api-ni.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -354,16 +354,6 @@ lnet_counters_reset(void)
lnet_net_unlock(LNET_LOCK_EX);
}
-EXPORT_SYMBOL(lnet_counters_reset);
-
-static __u64
-lnet_create_interface_cookie(void)
-{
- /* NB the interface cookie in wire handles guards against delayed
- * replies and ACKs appearing valid after reboot.
- */
- return ktime_get_ns();
-}
static char *
lnet_res_type2str(int type)
@@ -553,8 +543,11 @@ lnet_prepare(lnet_pid_t requested_pid)
rc = lnet_create_remote_nets_table();
if (rc != 0)
goto failed;
-
- the_lnet.ln_interface_cookie = lnet_create_interface_cookie();
+ /*
+ * NB the interface cookie in wire handles guards against delayed
+ * replies and ACKs appearing valid after reboot.
+ */
+ the_lnet.ln_interface_cookie = ktime_get_ns();
the_lnet.ln_counters = cfs_percpt_alloc(lnet_cpt_table(),
sizeof(lnet_counters_t));
@@ -1159,7 +1152,6 @@ lnet_init(void)
lnet_register_lnd(&the_lolnd);
return 0;
}
-EXPORT_SYMBOL(lnet_init);
/**
* Finalize LNet library.
@@ -1183,7 +1175,6 @@ lnet_fini(void)
the_lnet.ln_init = 0;
}
-EXPORT_SYMBOL(lnet_fini);
/**
* Set LNet PID and start LNet interfaces, routing, and forwarding.
diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c
index 1b3bc8386524..284a3c271bc6 100644
--- a/drivers/staging/lustre/lnet/lnet/config.c
+++ b/drivers/staging/lustre/lnet/lnet/config.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -650,8 +650,8 @@ lnet_parse_route(char *str, int *im_a_router)
INIT_LIST_HEAD(&nets);
/* save a copy of the string for error messages */
- strncpy(cmd, str, sizeof(cmd) - 1);
- cmd[sizeof(cmd) - 1] = 0;
+ strncpy(cmd, str, sizeof(cmd));
+ cmd[sizeof(cmd) - 1] = '\0';
sep = str;
for (;;) {
@@ -972,11 +972,13 @@ lnet_splitnets(char *source, struct list_head *nets)
return 0;
offset += (int)(sep - tb->ltb_text);
- tb2 = lnet_new_text_buf(strlen(sep));
+ len = strlen(sep);
+ tb2 = lnet_new_text_buf(len);
if (tb2 == NULL)
return -ENOMEM;
- strcpy(tb2->ltb_text, sep);
+ strncpy(tb2->ltb_text, sep, len);
+ tb2->ltb_text[len] = '\0';
list_add_tail(&tb2->ltb_list, nets);
tb = tb2;
@@ -1021,8 +1023,8 @@ lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
tb = list_entry(raw_entries.next, struct lnet_text_buf_t,
ltb_list);
- strncpy(source, tb->ltb_text, sizeof(source)-1);
- source[sizeof(source)-1] = 0;
+ strncpy(source, tb->ltb_text, sizeof(source));
+ source[sizeof(source)-1] = '\0';
/* replace ltb_text with the network(s) add on match */
rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
@@ -1103,12 +1105,6 @@ lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
return count;
}
-static void
-lnet_ipaddr_free_enumeration(__u32 *ipaddrs, int nip)
-{
- LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
-}
-
static int
lnet_ipaddr_enumerate(__u32 **ipaddrsp)
{
@@ -1169,7 +1165,7 @@ lnet_ipaddr_enumerate(__u32 **ipaddrsp)
rc = nip;
}
}
- lnet_ipaddr_free_enumeration(ipaddrs, nif);
+ LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
}
return nip;
}
@@ -1195,7 +1191,7 @@ lnet_parse_ip2nets(char **networksp, char *ip2nets)
}
rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
- lnet_ipaddr_free_enumeration(ipaddrs, nip);
+ LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
if (rc < 0) {
LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c
index 60889ebd2f2b..64f94a690081 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-eq.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c
@@ -282,15 +282,6 @@ lnet_eq_dequeue_event(lnet_eq_t *eq, lnet_event_t *ev)
* at least one event between this event and the last event obtained from the
* EQ has been dropped due to limited space in the EQ.
*/
-int
-LNetEQGet(lnet_handle_eq_t eventq, lnet_event_t *event)
-{
- int which;
-
- return LNetEQPoll(&eventq, 1, 0,
- event, &which);
-}
-EXPORT_SYMBOL(LNetEQGet);
/**
* Block the calling process until there is an event in the EQ.
@@ -308,15 +299,6 @@ EXPORT_SYMBOL(LNetEQGet);
* at least one event between this event and the last event obtained from the
* EQ has been dropped due to limited space in the EQ.
*/
-int
-LNetEQWait(lnet_handle_eq_t eventq, lnet_event_t *event)
-{
- int which;
-
- return LNetEQPoll(&eventq, 1, LNET_TIME_FOREVER,
- event, &which);
-}
-EXPORT_SYMBOL(LNetEQWait);
static int
lnet_eq_wait_locked(int *timeout_ms)
diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c
index 5631f60a39bc..fb8f7be043ec 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-move.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-move.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -1645,7 +1645,6 @@ lnet_msgtyp2str(int type)
return "<UNKNOWN>";
}
}
-EXPORT_SYMBOL(lnet_msgtyp2str);
void
lnet_print_hdr(lnet_hdr_t *hdr)
diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
index b4f573ab62cc..bd7b071b2873 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
@@ -21,7 +21,7 @@
* GPL HEADER END
*/
/*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lnet/lnet/lib-socket.c b/drivers/staging/lustre/lnet/lnet/lib-socket.c
index 6f7ef4c737cd..589ecc84d1b8 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-socket.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-socket.c
@@ -23,7 +23,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2015 Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c
index 576201a8390c..c93c00752a4c 100644
--- a/drivers/staging/lustre/lnet/lnet/module.c
+++ b/drivers/staging/lustre/lnet/lnet/module.c
@@ -27,7 +27,7 @@
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -146,7 +146,7 @@ fini_lnet(void)
lnet_fini();
}
-MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("LNet v3.1");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index 4ea651c6db3a..f5faa414d250 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*
* This file is part of Portals
* http://sourceforge.net/projects/sandiaportals/
diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c
index 0605c651f797..1f04cc1fc31c 100644
--- a/drivers/staging/lustre/lnet/selftest/brw_test.c
+++ b/drivers/staging/lustre/lnet/selftest/brw_test.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -358,7 +358,7 @@ out:
}
static void
-brw_server_rpc_done(srpc_server_rpc_t *rpc)
+brw_server_rpc_done(struct srpc_server_rpc *rpc)
{
srpc_bulk_t *blk = rpc->srpc_bulk;
@@ -378,7 +378,7 @@ brw_server_rpc_done(srpc_server_rpc_t *rpc)
}
static int
-brw_bulk_ready(srpc_server_rpc_t *rpc, int status)
+brw_bulk_ready(struct srpc_server_rpc *rpc, int status)
{
__u64 magic = BRW_MAGIC;
srpc_brw_reply_t *reply = &rpc->srpc_replymsg.msg_body.brw_reply;
diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c
index 556c837cf62c..a534665403e5 100644
--- a/drivers/staging/lustre/lnet/selftest/conctl.c
+++ b/drivers/staging/lustre/lnet/selftest/conctl.c
@@ -925,5 +925,3 @@ out:
return rc;
}
-
-EXPORT_SYMBOL(lstcon_ioctl_entry);
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 64a0335934f3..1066c70434b1 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -612,8 +612,8 @@ lstcon_sesrpc_prep(lstcon_node_t *nd, int transop,
msrq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.mksn_reqst;
msrq->mksn_sid = console_session.ses_id;
msrq->mksn_force = console_session.ses_force;
- strncpy(msrq->mksn_name, console_session.ses_name,
- strlen(console_session.ses_name));
+ strlcpy(msrq->mksn_name, console_session.ses_name,
+ sizeof(msrq->mksn_name));
break;
case LST_TRANS_SESEND:
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index d315dd44ae3b..5619fc430e8d 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -277,12 +277,6 @@ lstcon_group_find(const char *name, lstcon_group_t **grpp)
return -ENOENT;
}
-static void
-lstcon_group_put(lstcon_group_t *grp)
-{
- lstcon_group_decref(grp);
-}
-
static int
lstcon_group_ndlink_find(lstcon_group_t *grp, lnet_process_id_t id,
lstcon_ndlink_t **ndlpp, int create)
@@ -324,8 +318,6 @@ lstcon_group_ndlink_move(lstcon_group_t *old,
list_add_tail(&ndl->ndl_hlink, &new->grp_ndl_hash[idx]);
list_add_tail(&ndl->ndl_link, &new->grp_ndl_list);
new->grp_nnode++;
-
- return;
}
static void
@@ -436,7 +428,7 @@ lstcon_group_nodes_add(lstcon_group_t *grp,
}
if (rc != 0) {
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
}
@@ -445,7 +437,7 @@ lstcon_group_nodes_add(lstcon_group_t *grp,
tmp, lstcon_sesrpc_condition, &trans);
if (rc != 0) {
CERROR("Can't create transaction: %d\n", rc);
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
}
@@ -460,7 +452,7 @@ lstcon_group_nodes_add(lstcon_group_t *grp,
lstcon_rpc_trans_destroy(trans);
lstcon_group_move(tmp, grp);
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
}
@@ -510,12 +502,12 @@ lstcon_group_nodes_remove(lstcon_group_t *grp,
lstcon_rpc_trans_destroy(trans);
/* release nodes anyway, because we can't rollback status */
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
error:
lstcon_group_move(tmp, grp);
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
}
@@ -529,7 +521,7 @@ lstcon_group_add(char *name)
rc = (lstcon_group_find(name, &grp) == 0) ? -EEXIST : 0;
if (rc != 0) {
/* find a group with same name */
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -563,14 +555,14 @@ lstcon_nodes_add(char *name, int count, lnet_process_id_t *ids_up,
if (grp->grp_ref > 2) {
/* referred by other threads or test */
CDEBUG(D_NET, "Group %s is busy\n", name);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return -EBUSY;
}
rc = lstcon_group_nodes_add(grp, count, ids_up, featp, result_up);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -591,7 +583,7 @@ lstcon_group_del(char *name)
if (grp->grp_ref > 2) {
/* referred by others threads or test */
CDEBUG(D_NET, "Group %s is busy\n", name);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return -EBUSY;
}
@@ -600,7 +592,7 @@ lstcon_group_del(char *name)
grp, lstcon_sesrpc_condition, &trans);
if (rc != 0) {
CERROR("Can't create transaction: %d\n", rc);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -608,10 +600,10 @@ lstcon_group_del(char *name)
lstcon_rpc_trans_destroy(trans);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
/* -ref for session, it's destroyed,
* status can't be rolled back, destroy group anyway */
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -631,7 +623,7 @@ lstcon_group_clean(char *name, int args)
if (grp->grp_ref > 2) {
/* referred by test */
CDEBUG(D_NET, "Group %s is busy\n", name);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return -EBUSY;
}
@@ -640,10 +632,10 @@ lstcon_group_clean(char *name, int args)
lstcon_group_drain(grp, args);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
/* release empty group */
if (list_empty(&grp->grp_ndl_list))
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return 0;
}
@@ -664,16 +656,16 @@ lstcon_nodes_remove(char *name, int count,
if (grp->grp_ref > 2) {
/* referred by test */
CDEBUG(D_NET, "Group %s is busy\n", name);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return -EBUSY;
}
rc = lstcon_group_nodes_remove(grp, count, ids_up, result_up);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
/* release empty group */
if (list_empty(&grp->grp_ndl_list))
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -694,7 +686,7 @@ lstcon_group_refresh(char *name, struct list_head *result_up)
if (grp->grp_ref > 2) {
/* referred by test */
CDEBUG(D_NET, "Group %s is busy\n", name);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return -EBUSY;
}
@@ -705,7 +697,7 @@ lstcon_group_refresh(char *name, struct list_head *result_up)
if (rc != 0) {
/* local error, return */
CDEBUG(D_NET, "Can't create transaction: %d\n", rc);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -715,7 +707,7 @@ lstcon_group_refresh(char *name, struct list_head *result_up)
lstcon_rpc_trans_destroy(trans);
/* -ref for me */
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -797,7 +789,7 @@ lstcon_group_info(char *name, lstcon_ndlist_ent_t *gents_p,
/* verbose query */
rc = lstcon_nodes_getent(&grp->grp_ndl_list,
index_p, count_p, dents_up);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -806,7 +798,7 @@ lstcon_group_info(char *name, lstcon_ndlist_ent_t *gents_p,
LIBCFS_ALLOC(gentp, sizeof(lstcon_ndlist_ent_t));
if (gentp == NULL) {
CERROR("Can't allocate ndlist_ent\n");
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return -ENOMEM;
}
@@ -819,7 +811,7 @@ lstcon_group_info(char *name, lstcon_ndlist_ent_t *gents_p,
LIBCFS_FREE(gentp, sizeof(lstcon_ndlist_ent_t));
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return 0;
}
@@ -1096,8 +1088,8 @@ lstcon_batch_destroy(lstcon_batch_t *bat)
list_del(&test->tes_link);
- lstcon_group_put(test->tes_src_grp);
- lstcon_group_put(test->tes_dst_grp);
+ lstcon_group_decref(test->tes_src_grp);
+ lstcon_group_decref(test->tes_dst_grp);
LIBCFS_FREE(test, offsetof(lstcon_test_t,
tes_param[test->tes_paramlen]));
@@ -1352,10 +1344,10 @@ out:
LIBCFS_FREE(test, offsetof(lstcon_test_t, tes_param[paramlen]));
if (dst_grp != NULL)
- lstcon_group_put(dst_grp);
+ lstcon_group_decref(dst_grp);
if (src_grp != NULL)
- lstcon_group_put(src_grp);
+ lstcon_group_decref(src_grp);
return rc;
}
@@ -1518,7 +1510,7 @@ lstcon_group_stat(char *grp_name, int timeout, struct list_head *result_up)
rc = lstcon_ndlist_stat(&grp->grp_ndl_list, timeout, result_up);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -1556,13 +1548,13 @@ lstcon_nodes_stat(int count, lnet_process_id_t *ids_up,
}
if (rc != 0) {
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
}
rc = lstcon_ndlist_stat(&tmp->grp_ndl_list, timeout, result_up);
- lstcon_group_put(tmp);
+ lstcon_group_decref(tmp);
return rc;
}
@@ -1629,7 +1621,7 @@ lstcon_group_debug(int timeout, char *name,
rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL,
timeout, result_up);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -1666,14 +1658,14 @@ lstcon_nodes_debug(int timeout,
}
if (rc != 0) {
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL,
timeout, result_up);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
return rc;
}
@@ -1739,7 +1731,8 @@ lstcon_session_new(char *name, int key, unsigned feats,
console_session.ses_feats_updated = 0;
console_session.ses_timeout = (timeout <= 0) ?
LST_CONSOLE_TIMEOUT : timeout;
- strcpy(console_session.ses_name, name);
+ strlcpy(console_session.ses_name, name,
+ sizeof(console_session.ses_name));
rc = lstcon_batch_add(LST_DEFAULT_BATCH);
if (rc != 0)
@@ -1847,7 +1840,7 @@ lstcon_session_end(void)
lstcon_group_t, grp_link);
LASSERT(grp->grp_ref == 1);
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
}
/* all nodes should be released */
@@ -1891,7 +1884,7 @@ lstcon_session_feats_check(unsigned feats)
}
static int
-lstcon_acceptor_handle(srpc_server_rpc_t *rpc)
+lstcon_acceptor_handle(struct srpc_server_rpc *rpc)
{
srpc_msg_t *rep = &rpc->srpc_replymsg;
srpc_msg_t *req = &rpc->srpc_reqstbuf->buf_msg;
@@ -1959,14 +1952,15 @@ lstcon_acceptor_handle(srpc_server_rpc_t *rpc)
if (grp->grp_userland == 0)
grp->grp_userland = 1;
- strcpy(jrep->join_session, console_session.ses_name);
+ strlcpy(jrep->join_session, console_session.ses_name,
+ sizeof(jrep->join_session));
jrep->join_timeout = console_session.ses_timeout;
jrep->join_status = 0;
out:
rep->msg_ses_feats = console_session.ses_features;
if (grp != NULL)
- lstcon_group_put(grp);
+ lstcon_group_decref(grp);
mutex_unlock(&console_session.ses_mutex);
diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c
index f18e50036809..1a2da7430190 100644
--- a/drivers/staging/lustre/lnet/selftest/framework.c
+++ b/drivers/staging/lustre/lnet/selftest/framework.c
@@ -111,7 +111,7 @@ static struct smoketest_framework {
spinlock_t fw_lock; /* serialise */
sfw_session_t *fw_session; /* _the_ session */
int fw_shuttingdown; /* shutdown in progress */
- srpc_server_rpc_t *fw_active_srpc; /* running RPC */
+ struct srpc_server_rpc *fw_active_srpc;/* running RPC */
} sfw_data;
/* forward ref's */
@@ -722,7 +722,7 @@ sfw_unpack_addtest_req(srpc_msg_t *msg)
}
static int
-sfw_add_test_instance(sfw_batch_t *tsb, srpc_server_rpc_t *rpc)
+sfw_add_test_instance(sfw_batch_t *tsb, struct srpc_server_rpc *rpc)
{
srpc_msg_t *msg = &rpc->srpc_reqstbuf->buf_msg;
srpc_test_reqst_t *req = &msg->msg_body.tes_reqst;
@@ -1091,7 +1091,7 @@ sfw_query_batch(sfw_batch_t *tsb, int testidx, srpc_batch_reply_t *reply)
}
void
-sfw_free_pages(srpc_server_rpc_t *rpc)
+sfw_free_pages(struct srpc_server_rpc *rpc)
{
srpc_free_bulk(rpc->srpc_bulk);
rpc->srpc_bulk = NULL;
@@ -1112,7 +1112,7 @@ sfw_alloc_pages(struct srpc_server_rpc *rpc, int cpt, int npages, int len,
}
static int
-sfw_add_test(srpc_server_rpc_t *rpc)
+sfw_add_test(struct srpc_server_rpc *rpc)
{
sfw_session_t *sn = sfw_data.fw_session;
srpc_test_reply_t *reply = &rpc->srpc_replymsg.msg_body.tes_reply;
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index 7005002c15da..2acf6ec717be 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -445,15 +445,6 @@ srpc_post_active_rdma(int portal, __u64 matchbits, void *buf, int len,
}
static int
-srpc_post_active_rqtbuf(lnet_process_id_t peer, int service, void *buf,
- int len, lnet_handle_md_t *mdh, srpc_event_t *ev)
-{
- return srpc_post_active_rdma(srpc_serv_portal(service), service,
- buf, len, LNET_MD_OP_PUT, peer,
- LNET_NID_ANY, mdh, ev);
-}
-
-static int
srpc_post_passive_rqtbuf(int service, int local, void *buf, int len,
lnet_handle_md_t *mdh, srpc_event_t *ev)
{
@@ -798,9 +789,11 @@ srpc_send_request(srpc_client_rpc_t *rpc)
ev->ev_data = rpc;
ev->ev_type = SRPC_REQUEST_SENT;
- rc = srpc_post_active_rqtbuf(rpc->crpc_dest, rpc->crpc_service,
- &rpc->crpc_reqstmsg, sizeof(srpc_msg_t),
- &rpc->crpc_reqstmdh, ev);
+ rc = srpc_post_active_rdma(srpc_serv_portal(rpc->crpc_service),
+ rpc->crpc_service, &rpc->crpc_reqstmsg,
+ sizeof(srpc_msg_t), LNET_MD_OP_PUT,
+ rpc->crpc_dest, LNET_NID_ANY,
+ &rpc->crpc_reqstmdh, ev);
if (rc != 0) {
LASSERT(rc == -ENOMEM);
ev->ev_fired = 1; /* no more event expected */
@@ -866,7 +859,7 @@ srpc_prepare_bulk(srpc_client_rpc_t *rpc)
}
static int
-srpc_do_bulk(srpc_server_rpc_t *rpc)
+srpc_do_bulk(struct srpc_server_rpc *rpc)
{
srpc_event_t *ev = &rpc->srpc_ev;
srpc_bulk_t *bk = rpc->srpc_bulk;
@@ -894,7 +887,7 @@ srpc_do_bulk(srpc_server_rpc_t *rpc)
/* only called from srpc_handle_rpc */
static void
-srpc_server_rpc_done(srpc_server_rpc_t *rpc, int status)
+srpc_server_rpc_done(struct srpc_server_rpc *rpc, int status)
{
struct srpc_service_cd *scd = rpc->srpc_scd;
struct srpc_service *sv = scd->scd_svc;
@@ -1404,7 +1397,7 @@ srpc_lnet_ev_handler(lnet_event_t *ev)
struct srpc_service_cd *scd;
srpc_event_t *rpcev = ev->md.user_ptr;
srpc_client_rpc_t *crpc;
- srpc_server_rpc_t *srpc;
+ struct srpc_server_rpc *srpc;
srpc_buffer_t *buffer;
srpc_service_t *sv;
srpc_msg_t *msg;
diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h
index 8a77d3fdfa54..870498339538 100644
--- a/drivers/staging/lustre/lnet/selftest/selftest.h
+++ b/drivers/staging/lustre/lnet/selftest/selftest.h
@@ -182,7 +182,7 @@ typedef struct swi_workitem {
} swi_workitem_t;
/* server-side state of a RPC */
-typedef struct srpc_server_rpc {
+struct srpc_server_rpc {
/* chain on srpc_service::*_rpcq */
struct list_head srpc_list;
struct srpc_service_cd *srpc_scd;
@@ -198,7 +198,7 @@ typedef struct srpc_server_rpc {
unsigned int srpc_aborted; /* being given up */
int srpc_status;
void (*srpc_done)(struct srpc_server_rpc *);
-} srpc_server_rpc_t;
+};
/* client-side state of a RPC */
typedef struct srpc_client_rpc {
@@ -318,8 +318,8 @@ typedef struct srpc_service {
* - sv_handler: process incoming RPC request
* - sv_bulk_ready: notify bulk data
*/
- int (*sv_handler) (srpc_server_rpc_t *);
- int (*sv_bulk_ready) (srpc_server_rpc_t *, int);
+ int (*sv_handler)(struct srpc_server_rpc *);
+ int (*sv_bulk_ready)(struct srpc_server_rpc *, int);
} srpc_service_t;
typedef struct {
@@ -423,9 +423,9 @@ void sfw_abort_rpc(srpc_client_rpc_t *rpc);
void sfw_post_rpc(srpc_client_rpc_t *rpc);
void sfw_client_rpc_done(srpc_client_rpc_t *rpc);
void sfw_unpack_message(srpc_msg_t *msg);
-void sfw_free_pages(srpc_server_rpc_t *rpc);
+void sfw_free_pages(struct srpc_server_rpc *rpc);
void sfw_add_bulk_page(srpc_bulk_t *bk, struct page *pg, int i);
-int sfw_alloc_pages(srpc_server_rpc_t *rpc, int cpt, int npages, int len,
+int sfw_alloc_pages(struct srpc_server_rpc *rpc, int cpt, int npages, int len,
int sink);
int sfw_make_session (srpc_mksn_reqst_t *request, srpc_mksn_reply_t *reply);
@@ -440,7 +440,7 @@ void srpc_free_bulk(srpc_bulk_t *bk);
srpc_bulk_t *srpc_alloc_bulk(int cpt, unsigned bulk_npg, unsigned bulk_len,
int sink);
int srpc_send_rpc(swi_workitem_t *wi);
-int srpc_send_reply(srpc_server_rpc_t *rpc);
+int srpc_send_reply(struct srpc_server_rpc *rpc);
int srpc_add_service(srpc_service_t *sv);
int srpc_remove_service(srpc_service_t *sv);
void srpc_shutdown_service(srpc_service_t *sv);
@@ -585,7 +585,7 @@ swi_state2str (int state)
do { \
int __I = 2; \
while (!(cond)) { \
- CDEBUG(IS_PO2(++__I) ? D_WARNING : D_NET, \
+ CDEBUG(is_power_of_2(++__I) ? D_WARNING : D_NET, \
fmt, ## __VA_ARGS__); \
spin_unlock(&(lock)); \
\
diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h
index 84daee1154dc..b79a813977cf 100644
--- a/drivers/staging/lustre/lustre/fid/fid_internal.h
+++ b/drivers/staging/lustre/lustre/fid/fid_internal.h
@@ -44,8 +44,6 @@
#include "../../include/linux/libcfs/libcfs.h"
/* Functions used internally in module. */
-int seq_client_alloc_super(struct lu_client_seq *seq,
- const struct lu_env *env);
extern struct lprocfs_vars seq_client_debugfs_list[];
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index 7c45e7479087..ff8f38dc10ce 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2013, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -142,27 +142,6 @@ out_req:
return rc;
}
-/* Request sequence-controller node to allocate new super-sequence. */
-int seq_client_alloc_super(struct lu_client_seq *seq,
- const struct lu_env *env)
-{
- int rc;
-
- mutex_lock(&seq->lcs_mutex);
-
- /* Check whether the connection to seq controller has been
- * setup (lcs_exp != NULL) */
- if (!seq->lcs_exp) {
- mutex_unlock(&seq->lcs_mutex);
- return -EINPROGRESS;
- }
-
- rc = seq_client_rpc(seq, &seq->lcs_space,
- SEQ_ALLOC_SUPER, "super");
- mutex_unlock(&seq->lcs_mutex);
- return rc;
-}
-
/* Request sequence-controller node to allocate new meta-sequence. */
static int seq_client_alloc_meta(const struct lu_env *env,
struct lu_client_seq *seq)
@@ -483,7 +462,7 @@ static void __exit fid_mod_exit(void)
ldebugfs_remove(&seq_debugfs_dir);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre FID Module");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1.0");
diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c
index ce90c1c54a63..39f2aa32e984 100644
--- a/drivers/staging/lustre/lustre/fid/lproc_fid.c
+++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index 446917484637..d9459e58e2ce 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -121,8 +121,8 @@ void fld_cache_fini(struct fld_cache *cache)
/**
* delete given node from list.
*/
-void fld_cache_entry_delete(struct fld_cache *cache,
- struct fld_cache_entry *node)
+static void fld_cache_entry_delete(struct fld_cache *cache,
+ struct fld_cache_entry *node)
{
list_del(&node->fce_list);
list_del(&node->fce_lru);
@@ -227,7 +227,6 @@ static int fld_cache_shrink(struct fld_cache *cache)
while (cache->fci_cache_count + cache->fci_threshold >
cache->fci_cache_size && curr != &cache->fci_lru) {
-
flde = list_entry(curr, struct fld_cache_entry, fce_lru);
curr = curr->prev;
fld_cache_entry_delete(cache, flde);
@@ -377,8 +376,8 @@ struct fld_cache_entry
* This function handles all cases of merging and breaking up of
* ranges.
*/
-int fld_cache_insert_nolock(struct fld_cache *cache,
- struct fld_cache_entry *f_new)
+static int fld_cache_insert_nolock(struct fld_cache *cache,
+ struct fld_cache_entry *f_new)
{
struct fld_cache_entry *f_curr;
struct fld_cache_entry *n;
@@ -444,36 +443,10 @@ int fld_cache_insert(struct fld_cache *cache,
return rc;
}
-void fld_cache_delete_nolock(struct fld_cache *cache,
- const struct lu_seq_range *range)
-{
- struct fld_cache_entry *flde;
- struct fld_cache_entry *tmp;
- struct list_head *head;
-
- head = &cache->fci_entries_head;
- list_for_each_entry_safe(flde, tmp, head, fce_list) {
- /* add list if next is end of list */
- if (range->lsr_start == flde->fce_range.lsr_start ||
- (range->lsr_end == flde->fce_range.lsr_end &&
- range->lsr_flags == flde->fce_range.lsr_flags)) {
- fld_cache_entry_delete(cache, flde);
- break;
- }
- }
-}
-
/**
* Delete FLD entry in FLD cache.
*
*/
-void fld_cache_delete(struct fld_cache *cache,
- const struct lu_seq_range *range)
-{
- write_lock(&cache->fci_lock);
- fld_cache_delete_nolock(cache, range);
- write_unlock(&cache->fci_lock);
-}
struct fld_cache_entry
*fld_cache_entry_lookup_nolock(struct fld_cache *cache,
diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h
index fbb232de6c74..12eb1647b4bf 100644
--- a/drivers/staging/lustre/lustre/fld/fld_internal.h
+++ b/drivers/staging/lustre/lustre/fld/fld_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -156,20 +156,11 @@ int fld_cache_insert(struct fld_cache *cache,
struct fld_cache_entry
*fld_cache_entry_create(const struct lu_seq_range *range);
-int fld_cache_insert_nolock(struct fld_cache *cache,
- struct fld_cache_entry *f_new);
-void fld_cache_delete(struct fld_cache *cache,
- const struct lu_seq_range *range);
-void fld_cache_delete_nolock(struct fld_cache *cache,
- const struct lu_seq_range *range);
int fld_cache_lookup(struct fld_cache *cache,
const u64 seq, struct lu_seq_range *range);
struct fld_cache_entry*
fld_cache_entry_lookup(struct fld_cache *cache, struct lu_seq_range *range);
-void fld_cache_entry_delete(struct fld_cache *cache,
- struct fld_cache_entry *node);
-void fld_dump_cache_entries(struct fld_cache *cache);
struct fld_cache_entry
*fld_cache_entry_lookup_nolock(struct fld_cache *cache,
diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c
index 3fd91bc77da5..d92c01b74865 100644
--- a/drivers/staging/lustre/lustre/fld/fld_request.c
+++ b/drivers/staging/lustre/lustre/fld/fld_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2013, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -501,7 +501,7 @@ static void __exit fld_mod_exit(void)
ldebugfs_remove(&fld_debugfs_dir);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre FLD");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c
index 603f56e6095b..41ceaa8198a7 100644
--- a/drivers/staging/lustre/lustre/fld/lproc_fld.c
+++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h
index 73564f8e3884..bd7acc2a1219 100644
--- a/drivers/staging/lustre/lustre/include/cl_object.h
+++ b/drivers/staging/lustre/lustre/include/cl_object.h
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -3127,7 +3127,6 @@ void cl_page_list_disown (const struct lu_env *env,
struct cl_io *io, struct cl_page_list *plist);
void cl_2queue_init (struct cl_2queue *queue);
-void cl_2queue_add (struct cl_2queue *queue, struct cl_page *page);
void cl_2queue_disown (const struct lu_env *env,
struct cl_io *io, struct cl_2queue *queue);
void cl_2queue_discard (const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h
index 9e654b218ca3..0ac8e0edcc48 100644
--- a/drivers/staging/lustre/lustre/include/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -624,9 +624,6 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
int lprocfs_single_release(struct inode *, struct file *);
int lprocfs_seq_release(struct inode *, struct file *);
-#define LPROCFS_CLIMP_EXIT(obd) \
- up_read(&(obd)->u.cli.cl_sem)
-
/* write the name##_seq_show function, call LPROC_SEQ_FOPS_RO for read-only
proc entries; otherwise, you will define name##_seq_write function also for
a read-write proc entry, and then call LPROC_SEQ_SEQ instead. Finally,
diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h
index fa78689748a9..1d79341a495d 100644
--- a/drivers/staging/lustre/lustre/include/lu_object.h
+++ b/drivers/staging/lustre/lustre/include/lu_object.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h b/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h
index 06ce8c9ae9ad..09088f40ba88 100644
--- a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h
+++ b/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h
@@ -26,6 +26,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2014, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index 0b721c65c2a3..b064b5821e3f 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
index 80f8ec529424..2b4dd656d5f5 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h
index 5e1ac129a681..7c6933ffc9c1 100644
--- a/drivers/staging/lustre/lustre/include/lustre_disk.h
+++ b/drivers/staging/lustre/lustre/include/lustre_disk.h
@@ -68,6 +68,7 @@
everything as string options */
#define LMD_MAGIC 0xbdacbd03
+#define LMD_PARAMS_MAXLEN 4096
/* gleaned from the mount command - no persistent info here */
struct lustre_mount_data {
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h
index 0e75a15fe0d4..9b319f1df025 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -872,8 +872,6 @@ struct ldlm_resource {
*/
struct mutex lr_lvb_mutex;
int lr_lvb_len;
- /** protected by lr_lock */
- void *lr_lvb_data;
/** When the resource was considered as contended. */
unsigned long lr_contention_time;
diff --git a/drivers/staging/lustre/lustre/include/lustre_eacl.h b/drivers/staging/lustre/lustre/include/lustre_eacl.h
index fee4d2c75506..0b66593a9526 100644
--- a/drivers/staging/lustre/lustre/include/lustre_eacl.h
+++ b/drivers/staging/lustre/lustre/include/lustre_eacl.h
@@ -76,8 +76,6 @@ extern int
lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size,
posix_acl_xattr_header **out);
extern void
-lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size);
-extern void
lustre_ext_acl_xattr_free(ext_acl_xattr_header *header);
extern ext_acl_xattr_header *
lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h
index 1daf4c572415..311e5aa9b0db 100644
--- a/drivers/staging/lustre/lustre/include/lustre_export.h
+++ b/drivers/staging/lustre/lustre/include/lustre_export.h
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index 47c3f3750240..9b1a9c695113 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h
index d8b3db9cdeba..551162624974 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fld.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fld.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2013, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_ha.h b/drivers/staging/lustre/lustre/include/lustre_ha.h
index 49dfbb14f381..5488a698dabd 100644
--- a/drivers/staging/lustre/lustre/include/lustre_ha.h
+++ b/drivers/staging/lustre/lustre/include/lustre_ha.h
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h
index 1de0c4d6f7f7..e4fc8b5e1336 100644
--- a/drivers/staging/lustre/lustre/include/lustre_log.h
+++ b/drivers/staging/lustre/lustre/include/lustre_log.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -94,9 +94,6 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_handle **lgh, struct llog_logid *logid,
char *name, enum llog_open_param open_param);
int llog_close(const struct lu_env *env, struct llog_handle *cathandle);
-int llog_backup(const struct lu_env *env, struct obd_device *obd,
- struct llog_ctxt *ctxt, struct llog_ctxt *bak_ctxt,
- char *name, char *backup);
/* llog_process flags */
#define LLOG_FLAG_NODEAMON 0x0001
diff --git a/drivers/staging/lustre/lustre/include/lustre_mds.h b/drivers/staging/lustre/lustre/include/lustre_mds.h
index a16eb8b61178..95d27ddecfb3 100644
--- a/drivers/staging/lustre/lustre/include/lustre_mds.h
+++ b/drivers/staging/lustre/lustre/include/lustre_mds.h
@@ -62,12 +62,6 @@ struct mds_group_info {
#define MDD_OBD_NAME "mdd_obd"
#define MDD_OBD_UUID "mdd_obd_uuid"
-static inline int md_should_create(__u64 flags)
-{
- return !(flags & MDS_OPEN_DELAY_CREATE ||
- !(flags & FMODE_WRITE));
-}
-
/* these are local flags, used only on the client, private */
#define M_CHECK_STALE 0200000000
diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h
index 0127f45ca0c3..d834ddd8183b 100644
--- a/drivers/staging/lustre/lustre/include/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/lustre_net.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_param.h b/drivers/staging/lustre/lustre/include/lustre_param.h
index 8f6c0b26cfab..383fe6febe4b 100644
--- a/drivers/staging/lustre/lustre/include/lustre_param.h
+++ b/drivers/staging/lustre/lustre/include/lustre_param.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/lustre_req_layout.h b/drivers/staging/lustre/lustre/include/lustre_req_layout.h
index df292f6d4a85..46a662f89322 100644
--- a/drivers/staging/lustre/lustre/include/lustre_req_layout.h
+++ b/drivers/staging/lustre/lustre/include/lustre_req_layout.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h
index 5e93afca3435..bcbe61301713 100644
--- a/drivers/staging/lustre/lustre/include/obd.h
+++ b/drivers/staging/lustre/lustre/include/obd.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -963,123 +963,123 @@ struct md_enqueue_info {
};
struct obd_ops {
- struct module *o_owner;
- int (*o_iocontrol)(unsigned int cmd, struct obd_export *exp, int len,
- void *karg, void *uarg);
- int (*o_get_info)(const struct lu_env *env, struct obd_export *,
- __u32 keylen, void *key, __u32 *vallen, void *val,
- struct lov_stripe_md *lsm);
- int (*o_set_info_async)(const struct lu_env *, struct obd_export *,
- __u32 keylen, void *key,
- __u32 vallen, void *val,
- struct ptlrpc_request_set *set);
- int (*o_attach)(struct obd_device *dev, u32 len, void *data);
- int (*o_detach)(struct obd_device *dev);
- int (*o_setup)(struct obd_device *dev, struct lustre_cfg *cfg);
- int (*o_precleanup)(struct obd_device *dev,
- enum obd_cleanup_stage cleanup_stage);
- int (*o_cleanup)(struct obd_device *dev);
- int (*o_process_config)(struct obd_device *dev, u32 len, void *data);
- int (*o_postrecov)(struct obd_device *dev);
- int (*o_add_conn)(struct obd_import *imp, struct obd_uuid *uuid,
- int priority);
- int (*o_del_conn)(struct obd_import *imp, struct obd_uuid *uuid);
+ struct module *owner;
+ int (*iocontrol)(unsigned int cmd, struct obd_export *exp, int len,
+ void *karg, void *uarg);
+ int (*get_info)(const struct lu_env *env, struct obd_export *,
+ __u32 keylen, void *key, __u32 *vallen, void *val,
+ struct lov_stripe_md *lsm);
+ int (*set_info_async)(const struct lu_env *, struct obd_export *,
+ __u32 keylen, void *key,
+ __u32 vallen, void *val,
+ struct ptlrpc_request_set *set);
+ int (*attach)(struct obd_device *dev, u32 len, void *data);
+ int (*detach)(struct obd_device *dev);
+ int (*setup)(struct obd_device *dev, struct lustre_cfg *cfg);
+ int (*precleanup)(struct obd_device *dev,
+ enum obd_cleanup_stage cleanup_stage);
+ int (*cleanup)(struct obd_device *dev);
+ int (*process_config)(struct obd_device *dev, u32 len, void *data);
+ int (*postrecov)(struct obd_device *dev);
+ int (*add_conn)(struct obd_import *imp, struct obd_uuid *uuid,
+ int priority);
+ int (*del_conn)(struct obd_import *imp, struct obd_uuid *uuid);
/* connect to the target device with given connection
* data. @ocd->ocd_connect_flags is modified to reflect flags actually
* granted by the target, which are guaranteed to be a subset of flags
* asked for. If @ocd == NULL, use default parameters. */
- int (*o_connect)(const struct lu_env *env,
- struct obd_export **exp, struct obd_device *src,
- struct obd_uuid *cluuid, struct obd_connect_data *ocd,
+ int (*connect)(const struct lu_env *env,
+ struct obd_export **exp, struct obd_device *src,
+ struct obd_uuid *cluuid, struct obd_connect_data *ocd,
+ void *localdata);
+ int (*reconnect)(const struct lu_env *env,
+ struct obd_export *exp, struct obd_device *src,
+ struct obd_uuid *cluuid,
+ struct obd_connect_data *ocd,
void *localdata);
- int (*o_reconnect)(const struct lu_env *env,
- struct obd_export *exp, struct obd_device *src,
- struct obd_uuid *cluuid,
- struct obd_connect_data *ocd,
- void *localdata);
- int (*o_disconnect)(struct obd_export *exp);
+ int (*disconnect)(struct obd_export *exp);
/* Initialize/finalize fids infrastructure. */
- int (*o_fid_init)(struct obd_device *obd,
- struct obd_export *exp, enum lu_cli_type type);
- int (*o_fid_fini)(struct obd_device *obd);
+ int (*fid_init)(struct obd_device *obd,
+ struct obd_export *exp, enum lu_cli_type type);
+ int (*fid_fini)(struct obd_device *obd);
/* Allocate new fid according to passed @hint. */
- int (*o_fid_alloc)(struct obd_export *exp, struct lu_fid *fid,
- struct md_op_data *op_data);
+ int (*fid_alloc)(struct obd_export *exp, struct lu_fid *fid,
+ struct md_op_data *op_data);
/*
* Object with @fid is getting deleted, we may want to do something
* about this.
*/
- int (*o_statfs)(const struct lu_env *, struct obd_export *exp,
- struct obd_statfs *osfs, __u64 max_age, __u32 flags);
- int (*o_statfs_async)(struct obd_export *exp, struct obd_info *oinfo,
- __u64 max_age, struct ptlrpc_request_set *set);
- int (*o_packmd)(struct obd_export *exp, struct lov_mds_md **disk_tgt,
- struct lov_stripe_md *mem_src);
- int (*o_unpackmd)(struct obd_export *exp,
- struct lov_stripe_md **mem_tgt,
- struct lov_mds_md *disk_src, int disk_len);
- int (*o_preallocate)(struct lustre_handle *, u32 *req, u64 *ids);
- int (*o_create)(const struct lu_env *env, struct obd_export *exp,
- struct obdo *oa, struct lov_stripe_md **ea,
- struct obd_trans_info *oti);
- int (*o_destroy)(const struct lu_env *env, struct obd_export *exp,
- struct obdo *oa, struct lov_stripe_md *ea,
- struct obd_trans_info *oti, struct obd_export *md_exp);
- int (*o_setattr)(const struct lu_env *, struct obd_export *exp,
- struct obd_info *oinfo, struct obd_trans_info *oti);
- int (*o_setattr_async)(struct obd_export *exp, struct obd_info *oinfo,
- struct obd_trans_info *oti,
- struct ptlrpc_request_set *rqset);
- int (*o_getattr)(const struct lu_env *env, struct obd_export *exp,
- struct obd_info *oinfo);
- int (*o_getattr_async)(struct obd_export *exp, struct obd_info *oinfo,
- struct ptlrpc_request_set *set);
- int (*o_adjust_kms)(struct obd_export *exp, struct lov_stripe_md *lsm,
- u64 size, int shrink);
- int (*o_preprw)(const struct lu_env *env, int cmd,
- struct obd_export *exp, struct obdo *oa, int objcount,
- struct obd_ioobj *obj, struct niobuf_remote *remote,
- int *nr_pages, struct niobuf_local *local,
- struct obd_trans_info *oti);
- int (*o_commitrw)(const struct lu_env *env, int cmd,
- struct obd_export *exp, struct obdo *oa,
- int objcount, struct obd_ioobj *obj,
- struct niobuf_remote *remote, int pages,
- struct niobuf_local *local,
- struct obd_trans_info *oti, int rc);
- int (*o_find_cbdata)(struct obd_export *, struct lov_stripe_md *,
- ldlm_iterator_t it, void *data);
- int (*o_init_export)(struct obd_export *exp);
- int (*o_destroy_export)(struct obd_export *exp);
+ int (*statfs)(const struct lu_env *, struct obd_export *exp,
+ struct obd_statfs *osfs, __u64 max_age, __u32 flags);
+ int (*statfs_async)(struct obd_export *exp, struct obd_info *oinfo,
+ __u64 max_age, struct ptlrpc_request_set *set);
+ int (*packmd)(struct obd_export *exp, struct lov_mds_md **disk_tgt,
+ struct lov_stripe_md *mem_src);
+ int (*unpackmd)(struct obd_export *exp,
+ struct lov_stripe_md **mem_tgt,
+ struct lov_mds_md *disk_src, int disk_len);
+ int (*preallocate)(struct lustre_handle *, u32 *req, u64 *ids);
+ int (*create)(const struct lu_env *env, struct obd_export *exp,
+ struct obdo *oa, struct lov_stripe_md **ea,
+ struct obd_trans_info *oti);
+ int (*destroy)(const struct lu_env *env, struct obd_export *exp,
+ struct obdo *oa, struct lov_stripe_md *ea,
+ struct obd_trans_info *oti, struct obd_export *md_exp);
+ int (*setattr)(const struct lu_env *, struct obd_export *exp,
+ struct obd_info *oinfo, struct obd_trans_info *oti);
+ int (*setattr_async)(struct obd_export *exp, struct obd_info *oinfo,
+ struct obd_trans_info *oti,
+ struct ptlrpc_request_set *rqset);
+ int (*getattr)(const struct lu_env *env, struct obd_export *exp,
+ struct obd_info *oinfo);
+ int (*getattr_async)(struct obd_export *exp, struct obd_info *oinfo,
+ struct ptlrpc_request_set *set);
+ int (*adjust_kms)(struct obd_export *exp, struct lov_stripe_md *lsm,
+ u64 size, int shrink);
+ int (*preprw)(const struct lu_env *env, int cmd,
+ struct obd_export *exp, struct obdo *oa, int objcount,
+ struct obd_ioobj *obj, struct niobuf_remote *remote,
+ int *nr_pages, struct niobuf_local *local,
+ struct obd_trans_info *oti);
+ int (*commitrw)(const struct lu_env *env, int cmd,
+ struct obd_export *exp, struct obdo *oa,
+ int objcount, struct obd_ioobj *obj,
+ struct niobuf_remote *remote, int pages,
+ struct niobuf_local *local,
+ struct obd_trans_info *oti, int rc);
+ int (*find_cbdata)(struct obd_export *, struct lov_stripe_md *,
+ ldlm_iterator_t it, void *data);
+ int (*init_export)(struct obd_export *exp);
+ int (*destroy_export)(struct obd_export *exp);
/* metadata-only methods */
- int (*o_import_event)(struct obd_device *, struct obd_import *,
- enum obd_import_event);
+ int (*import_event)(struct obd_device *, struct obd_import *,
+ enum obd_import_event);
- int (*o_notify)(struct obd_device *obd, struct obd_device *watched,
- enum obd_notify_event ev, void *data);
+ int (*notify)(struct obd_device *obd, struct obd_device *watched,
+ enum obd_notify_event ev, void *data);
- int (*o_health_check)(const struct lu_env *env, struct obd_device *);
- struct obd_uuid *(*o_get_uuid)(struct obd_export *exp);
+ int (*health_check)(const struct lu_env *env, struct obd_device *);
+ struct obd_uuid *(*get_uuid)(struct obd_export *exp);
/* quota methods */
- int (*o_quotacheck)(struct obd_device *, struct obd_export *,
- struct obd_quotactl *);
- int (*o_quotactl)(struct obd_device *, struct obd_export *,
+ int (*quotacheck)(struct obd_device *, struct obd_export *,
struct obd_quotactl *);
+ int (*quotactl)(struct obd_device *, struct obd_export *,
+ struct obd_quotactl *);
/* pools methods */
- int (*o_pool_new)(struct obd_device *obd, char *poolname);
- int (*o_pool_del)(struct obd_device *obd, char *poolname);
- int (*o_pool_add)(struct obd_device *obd, char *poolname,
- char *ostname);
- int (*o_pool_rem)(struct obd_device *obd, char *poolname,
- char *ostname);
- void (*o_getref)(struct obd_device *obd);
- void (*o_putref)(struct obd_device *obd);
+ int (*pool_new)(struct obd_device *obd, char *poolname);
+ int (*pool_del)(struct obd_device *obd, char *poolname);
+ int (*pool_add)(struct obd_device *obd, char *poolname,
+ char *ostname);
+ int (*pool_rem)(struct obd_device *obd, char *poolname,
+ char *ostname);
+ void (*getref)(struct obd_device *obd);
+ void (*putref)(struct obd_device *obd);
/*
* NOTE: If adding ops, add another LPROCFS_OBD_OP_INIT() line
* to lprocfs_alloc_obd_stats() in obdclass/lprocfs_status.c.
@@ -1124,89 +1124,89 @@ struct md_open_data {
struct lookup_intent;
struct md_ops {
- int (*m_getstatus)(struct obd_export *, struct lu_fid *);
- int (*m_null_inode)(struct obd_export *, const struct lu_fid *);
- int (*m_find_cbdata)(struct obd_export *, const struct lu_fid *,
- ldlm_iterator_t, void *);
- int (*m_close)(struct obd_export *, struct md_op_data *,
- struct md_open_data *, struct ptlrpc_request **);
- int (*m_create)(struct obd_export *, struct md_op_data *,
- const void *, int, int, __u32, __u32, cfs_cap_t,
- __u64, struct ptlrpc_request **);
- int (*m_done_writing)(struct obd_export *, struct md_op_data *,
- struct md_open_data *);
- int (*m_enqueue)(struct obd_export *, struct ldlm_enqueue_info *,
- struct lookup_intent *, struct md_op_data *,
- struct lustre_handle *, void *, int,
- struct ptlrpc_request **, __u64);
- int (*m_getattr)(struct obd_export *, struct md_op_data *,
- struct ptlrpc_request **);
- int (*m_getattr_name)(struct obd_export *, struct md_op_data *,
- struct ptlrpc_request **);
- int (*m_intent_lock)(struct obd_export *, struct md_op_data *,
- void *, int, struct lookup_intent *, int,
- struct ptlrpc_request **,
- ldlm_blocking_callback, __u64);
- int (*m_link)(struct obd_export *, struct md_op_data *,
+ int (*getstatus)(struct obd_export *, struct lu_fid *);
+ int (*null_inode)(struct obd_export *, const struct lu_fid *);
+ int (*find_cbdata)(struct obd_export *, const struct lu_fid *,
+ ldlm_iterator_t, void *);
+ int (*close)(struct obd_export *, struct md_op_data *,
+ struct md_open_data *, struct ptlrpc_request **);
+ int (*create)(struct obd_export *, struct md_op_data *,
+ const void *, int, int, __u32, __u32, cfs_cap_t,
+ __u64, struct ptlrpc_request **);
+ int (*done_writing)(struct obd_export *, struct md_op_data *,
+ struct md_open_data *);
+ int (*enqueue)(struct obd_export *, struct ldlm_enqueue_info *,
+ struct lookup_intent *, struct md_op_data *,
+ struct lustre_handle *, void *, int,
+ struct ptlrpc_request **, __u64);
+ int (*getattr)(struct obd_export *, struct md_op_data *,
+ struct ptlrpc_request **);
+ int (*getattr_name)(struct obd_export *, struct md_op_data *,
+ struct ptlrpc_request **);
+ int (*intent_lock)(struct obd_export *, struct md_op_data *,
+ void *, int, struct lookup_intent *, int,
+ struct ptlrpc_request **,
+ ldlm_blocking_callback, __u64);
+ int (*link)(struct obd_export *, struct md_op_data *,
+ struct ptlrpc_request **);
+ int (*rename)(struct obd_export *, struct md_op_data *,
+ const char *, int, const char *, int,
struct ptlrpc_request **);
- int (*m_rename)(struct obd_export *, struct md_op_data *,
- const char *, int, const char *, int,
- struct ptlrpc_request **);
- int (*m_is_subdir)(struct obd_export *, const struct lu_fid *,
- const struct lu_fid *,
+ int (*is_subdir)(struct obd_export *, const struct lu_fid *,
+ const struct lu_fid *,
struct ptlrpc_request **);
- int (*m_setattr)(struct obd_export *, struct md_op_data *, void *,
- int, void *, int, struct ptlrpc_request **,
+ int (*setattr)(struct obd_export *, struct md_op_data *, void *,
+ int, void *, int, struct ptlrpc_request **,
struct md_open_data **mod);
- int (*m_sync)(struct obd_export *, const struct lu_fid *,
+ int (*sync)(struct obd_export *, const struct lu_fid *,
+ struct ptlrpc_request **);
+ int (*readpage)(struct obd_export *, struct md_op_data *,
+ struct page **, struct ptlrpc_request **);
+
+ int (*unlink)(struct obd_export *, struct md_op_data *,
struct ptlrpc_request **);
- int (*m_readpage)(struct obd_export *, struct md_op_data *,
- struct page **, struct ptlrpc_request **);
- int (*m_unlink)(struct obd_export *, struct md_op_data *,
+ int (*setxattr)(struct obd_export *, const struct lu_fid *,
+ u64, const char *, const char *, int, int, int, __u32,
struct ptlrpc_request **);
- int (*m_setxattr)(struct obd_export *, const struct lu_fid *,
- u64, const char *, const char *, int, int, int, __u32,
- struct ptlrpc_request **);
-
- int (*m_getxattr)(struct obd_export *, const struct lu_fid *,
- u64, const char *, const char *, int, int, int,
- struct ptlrpc_request **);
+ int (*getxattr)(struct obd_export *, const struct lu_fid *,
+ u64, const char *, const char *, int, int, int,
+ struct ptlrpc_request **);
- int (*m_init_ea_size)(struct obd_export *, int, int, int, int);
+ int (*init_ea_size)(struct obd_export *, int, int, int, int);
- int (*m_get_lustre_md)(struct obd_export *, struct ptlrpc_request *,
- struct obd_export *, struct obd_export *,
- struct lustre_md *);
+ int (*get_lustre_md)(struct obd_export *, struct ptlrpc_request *,
+ struct obd_export *, struct obd_export *,
+ struct lustre_md *);
- int (*m_free_lustre_md)(struct obd_export *, struct lustre_md *);
+ int (*free_lustre_md)(struct obd_export *, struct lustre_md *);
- int (*m_set_open_replay_data)(struct obd_export *,
- struct obd_client_handle *,
- struct lookup_intent *);
- int (*m_clear_open_replay_data)(struct obd_export *,
- struct obd_client_handle *);
- int (*m_set_lock_data)(struct obd_export *, __u64 *, void *, __u64 *);
+ int (*set_open_replay_data)(struct obd_export *,
+ struct obd_client_handle *,
+ struct lookup_intent *);
+ int (*clear_open_replay_data)(struct obd_export *,
+ struct obd_client_handle *);
+ int (*set_lock_data)(struct obd_export *, __u64 *, void *, __u64 *);
- ldlm_mode_t (*m_lock_match)(struct obd_export *, __u64,
- const struct lu_fid *, ldlm_type_t,
- ldlm_policy_data_t *, ldlm_mode_t,
- struct lustre_handle *);
+ ldlm_mode_t (*lock_match)(struct obd_export *, __u64,
+ const struct lu_fid *, ldlm_type_t,
+ ldlm_policy_data_t *, ldlm_mode_t,
+ struct lustre_handle *);
- int (*m_cancel_unused)(struct obd_export *, const struct lu_fid *,
- ldlm_policy_data_t *, ldlm_mode_t,
- ldlm_cancel_flags_t flags, void *opaque);
+ int (*cancel_unused)(struct obd_export *, const struct lu_fid *,
+ ldlm_policy_data_t *, ldlm_mode_t,
+ ldlm_cancel_flags_t flags, void *opaque);
- int (*m_get_remote_perm)(struct obd_export *, const struct lu_fid *,
- __u32, struct ptlrpc_request **);
+ int (*get_remote_perm)(struct obd_export *, const struct lu_fid *,
+ __u32, struct ptlrpc_request **);
- int (*m_intent_getattr_async)(struct obd_export *,
- struct md_enqueue_info *,
- struct ldlm_enqueue_info *);
+ int (*intent_getattr_async)(struct obd_export *,
+ struct md_enqueue_info *,
+ struct ldlm_enqueue_info *);
- int (*m_revalidate_lock)(struct obd_export *, struct lookup_intent *,
- struct lu_fid *, __u64 *bits);
+ int (*revalidate_lock)(struct obd_export *, struct lookup_intent *,
+ struct lu_fid *, __u64 *bits);
/*
* NOTE: If adding ops, add another LPROCFS_MD_OP_INIT() line to
diff --git a/drivers/staging/lustre/lustre/include/obd_cksum.h b/drivers/staging/lustre/lustre/include/obd_cksum.h
index a0099d71773a..01db60405393 100644
--- a/drivers/staging/lustre/lustre/include/obd_cksum.h
+++ b/drivers/staging/lustre/lustre/include/obd_cksum.h
@@ -133,29 +133,6 @@ static inline cksum_type_t cksum_types_supported_client(void)
return ret;
}
-/* Server uses algos that perform at 50% or better of the Adler */
-static inline cksum_type_t cksum_types_supported_server(void)
-{
- int base_speed;
- cksum_type_t ret = OBD_CKSUM_ADLER;
-
- CDEBUG(D_INFO, "Crypto hash speed: crc %d, crc32c %d, adler %d\n",
- cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)),
- cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)),
- cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)));
-
- base_speed = cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_ADLER)) / 2;
-
- if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32C)) >=
- base_speed)
- ret |= OBD_CKSUM_CRC32C;
- if (cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)) >=
- base_speed)
- ret |= OBD_CKSUM_CRC32;
-
- return ret;
-}
-
/* Select the best checksum algorithm among those supplied in the cksum_types
* input.
*
diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h
index fd5f3731db92..97d80397503c 100644
--- a/drivers/staging/lustre/lustre/include/obd_class.h
+++ b/drivers/staging/lustre/lustre/include/obd_class.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -270,8 +270,8 @@ void obdo_to_ioobj(struct obdo *oa, struct obd_ioobj *ioobj);
void md_from_obdo(struct md_op_data *op_data, struct obdo *oa, u32 valid);
#define OBT(dev) (dev)->obd_type
-#define OBP(dev, op) (dev)->obd_type->typ_dt_ops->o_ ## op
-#define MDP(dev, op) (dev)->obd_type->typ_md_ops->m_ ## op
+#define OBP(dev, op) (dev)->obd_type->typ_dt_ops->op
+#define MDP(dev, op) (dev)->obd_type->typ_md_ops->op
#define CTXTP(ctxt, op) (ctxt)->loc_logops->lop_##op
/* Ensure obd_setup: used for cleanup which must be called
@@ -301,9 +301,9 @@ static inline int obd_check_dev_active(struct obd_device *obd)
}
#define OBD_COUNTER_OFFSET(op) \
- ((offsetof(struct obd_ops, o_ ## op) - \
- offsetof(struct obd_ops, o_iocontrol)) \
- / sizeof(((struct obd_ops *)(0))->o_iocontrol))
+ ((offsetof(struct obd_ops, op) - \
+ offsetof(struct obd_ops, iocontrol)) \
+ / sizeof(((struct obd_ops *)(0))->iocontrol))
#define OBD_COUNTER_INCREMENT(obdx, op) \
if ((obdx)->obd_stats != NULL) { \
@@ -324,9 +324,9 @@ static inline int obd_check_dev_active(struct obd_device *obd)
}
#define MD_COUNTER_OFFSET(op) \
- ((offsetof(struct md_ops, m_ ## op) - \
- offsetof(struct md_ops, m_getstatus)) \
- / sizeof(((struct md_ops *)(0))->m_getstatus))
+ ((offsetof(struct md_ops, op) - \
+ offsetof(struct md_ops, getstatus)) \
+ / sizeof(((struct md_ops *)(0))->getstatus))
#define MD_COUNTER_INCREMENT(obdx, op) \
if ((obd)->md_stats != NULL) { \
diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h
index a22a5308fb48..d031437c0528 100644
--- a/drivers/staging/lustre/lustre/include/obd_support.h
+++ b/drivers/staging/lustre/lustre/include/obd_support.h
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
index 0b8e4d2175ae..34dde7dede74 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -427,7 +427,7 @@ static void ccc_object_size_lock(struct cl_object *obj)
{
struct inode *inode = ccc_object_inode(obj);
- cl_isize_lock(inode);
+ ll_inode_size_lock(inode);
cl_object_attr_lock(obj);
}
@@ -436,7 +436,7 @@ static void ccc_object_size_unlock(struct cl_object *obj)
struct inode *inode = ccc_object_inode(obj);
cl_object_attr_unlock(obj);
- cl_isize_unlock(inode);
+ ll_inode_size_unlock(inode);
}
/*****************************************************************************
diff --git a/drivers/staging/lustre/lustre/ldlm/interval_tree.c b/drivers/staging/lustre/lustre/ldlm/interval_tree.c
index 39b571721881..a2ea8e5b93d8 100644
--- a/drivers/staging/lustre/lustre/ldlm/interval_tree.c
+++ b/drivers/staging/lustre/lustre/ldlm/interval_tree.c
@@ -96,18 +96,6 @@ static inline int extent_equal(struct interval_node_extent *e1,
return (e1->start == e2->start) && (e1->end == e2->end);
}
-static inline int node_compare(struct interval_node *n1,
- struct interval_node *n2)
-{
- return extent_compare(&n1->in_extent, &n2->in_extent);
-}
-
-static inline int node_equal(struct interval_node *n1,
- struct interval_node *n2)
-{
- return extent_equal(&n1->in_extent, &n2->in_extent);
-}
-
static inline __u64 max_u64(__u64 x, __u64 y)
{
return x > y ? x : y;
@@ -278,14 +266,14 @@ struct interval_node *interval_insert(struct interval_node *node,
p = root;
while (*p) {
parent = *p;
- if (node_equal(parent, node))
+ if (extent_equal(&parent->in_extent, &node->in_extent))
return parent;
/* max_high field must be updated after each iteration */
if (parent->in_max_high < interval_high(node))
parent->in_max_high = interval_high(node);
- if (node_compare(node, parent) < 0)
+ if (extent_compare(&node->in_extent, &parent->in_extent) < 0)
p = &parent->in_left;
else
p = &parent->in_right;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
index c787888eb8af..9c70f31ea56e 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
@@ -149,7 +149,7 @@ static inline int lock_mode_to_index(ldlm_mode_t mode)
int index;
LASSERT(mode != 0);
- LASSERT(IS_PO2(mode));
+ LASSERT(is_power_of_2(mode));
for (index = -1; mode; index++)
mode >>= 1;
LASSERT(index < LCK_MODE_NUM);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
index db3c9b7af7d5..849cc98df7dd 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
index ccce1e503120..3c8d4413d976 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
index 7f8c70056ffd..cf9ec0cfe247 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
index ca115119501a..79aeb2bf6c8e 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index 1a4eef64658f..3d7c137d223a 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -176,11 +176,6 @@ enum {
LDLM_POOL_LAST_STAT
};
-static inline struct ldlm_namespace *ldlm_pl2ns(struct ldlm_pool *pl)
-{
- return container_of(pl, struct ldlm_namespace, ns_pool);
-}
-
/**
* Calculates suggested grant_step in % of available locks for passed
* \a period. This is later used in grant_plan calculations.
@@ -213,22 +208,6 @@ static inline int ldlm_pool_t2gsp(unsigned int t)
}
/**
- * Returns current \a pl limit.
- */
-static __u32 ldlm_pool_get_limit(struct ldlm_pool *pl)
-{
- return atomic_read(&pl->pl_limit);
-}
-
-/**
- * Sets passed \a limit to \a pl.
- */
-static void ldlm_pool_set_limit(struct ldlm_pool *pl, __u32 limit)
-{
- atomic_set(&pl->pl_limit, limit);
-}
-
-/**
* Recalculates next stats on passed \a pl.
*
* \pre ->pl_lock is locked.
@@ -254,7 +233,8 @@ static void ldlm_pool_recalc_stats(struct ldlm_pool *pl)
}
/**
- * Sets SLV and Limit from ldlm_pl2ns(pl)->ns_obd tp passed \a pl.
+ * Sets SLV and Limit from container_of(pl, struct ldlm_namespace,
+ * ns_pool)->ns_obd tp passed \a pl.
*/
static void ldlm_cli_pool_pop_slv(struct ldlm_pool *pl)
{
@@ -264,11 +244,12 @@ static void ldlm_cli_pool_pop_slv(struct ldlm_pool *pl)
* Get new SLV and Limit from obd which is updated with coming
* RPCs.
*/
- obd = ldlm_pl2ns(pl)->ns_obd;
+ obd = container_of(pl, struct ldlm_namespace,
+ ns_pool)->ns_obd;
LASSERT(obd != NULL);
read_lock(&obd->obd_pool_lock);
pl->pl_server_lock_volume = obd->obd_pool_slv;
- ldlm_pool_set_limit(pl, obd->obd_pool_limit);
+ atomic_set(&pl->pl_limit, obd->obd_pool_limit);
read_unlock(&obd->obd_pool_lock);
}
@@ -304,7 +285,8 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
/*
* Do not cancel locks in case lru resize is disabled for this ns.
*/
- if (!ns_connect_lru_resize(ldlm_pl2ns(pl))) {
+ if (!ns_connect_lru_resize(container_of(pl, struct ldlm_namespace,
+ ns_pool))) {
ret = 0;
goto out;
}
@@ -315,7 +297,8 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
* It may be called when SLV has changed much, this is why we do not
* take into account pl->pl_recalc_time here.
*/
- ret = ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
+ ret = ldlm_cancel_lru(container_of(pl, struct ldlm_namespace, ns_pool),
+ 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
out:
spin_lock(&pl->pl_lock);
@@ -341,7 +324,7 @@ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
struct ldlm_namespace *ns;
int unused;
- ns = ldlm_pl2ns(pl);
+ ns = container_of(pl, struct ldlm_namespace, ns_pool);
/*
* Do not cancel locks in case lru resize is disabled for this ns.
@@ -453,7 +436,7 @@ static int lprocfs_pool_state_seq_show(struct seq_file *m, void *unused)
spin_lock(&pl->pl_lock);
slv = pl->pl_server_lock_volume;
clv = pl->pl_client_lock_volume;
- limit = ldlm_pool_get_limit(pl);
+ limit = atomic_read(&pl->pl_limit);
granted = atomic_read(&pl->pl_granted);
grant_rate = atomic_read(&pl->pl_grant_rate);
cancel_rate = atomic_read(&pl->pl_cancel_rate);
@@ -558,7 +541,8 @@ static struct kobj_type ldlm_pl_ktype = {
static int ldlm_pool_sysfs_init(struct ldlm_pool *pl)
{
- struct ldlm_namespace *ns = ldlm_pl2ns(pl);
+ struct ldlm_namespace *ns = container_of(pl, struct ldlm_namespace,
+ ns_pool);
int err;
init_completion(&pl->pl_kobj_unregister);
@@ -570,7 +554,8 @@ static int ldlm_pool_sysfs_init(struct ldlm_pool *pl)
static int ldlm_pool_debugfs_init(struct ldlm_pool *pl)
{
- struct ldlm_namespace *ns = ldlm_pl2ns(pl);
+ struct ldlm_namespace *ns = container_of(pl, struct ldlm_namespace,
+ ns_pool);
struct dentry *debugfs_ns_parent;
struct lprocfs_vars pool_vars[2];
char *var_name = NULL;
@@ -685,7 +670,7 @@ int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns,
snprintf(pl->pl_name, sizeof(pl->pl_name), "ldlm-pool-%s-%d",
ldlm_ns_name(ns), idx);
- ldlm_pool_set_limit(pl, 1);
+ atomic_set(&pl->pl_limit, 1);
pl->pl_server_lock_volume = 0;
pl->pl_ops = &ldlm_cli_pool_ops;
pl->pl_recalc_period = LDLM_POOL_CLI_DEF_RECALC_PERIOD;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
index fdf81b87aad7..b9eb37762434 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index c0a54bf406ca..0ae610015b7c 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -1154,8 +1154,6 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent,
CERROR("%s: lvbo_init failed for resource %#llx:%#llx: rc = %d\n",
ns->ns_obd->obd_name, name->name[0],
name->name[1], rc);
- kfree(res->lr_lvb_data);
- res->lr_lvb_data = NULL;
res->lr_lvb_len = rc;
mutex_unlock(&res->lr_lvb_mutex);
ldlm_resource_putref(res);
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index 1d1c67164418..0b38dad13546 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -94,17 +94,14 @@ static struct kernel_param_ops param_ops_debugmb = {
static unsigned int libcfs_debug_mb;
module_param(libcfs_debug_mb, debugmb, 0644);
MODULE_PARM_DESC(libcfs_debug_mb, "Total debug buffer size.");
-EXPORT_SYMBOL(libcfs_debug_mb);
unsigned int libcfs_printk = D_CANTMASK;
module_param(libcfs_printk, uint, 0644);
MODULE_PARM_DESC(libcfs_printk, "Lustre kernel debug console mask");
-EXPORT_SYMBOL(libcfs_printk);
unsigned int libcfs_console_ratelimit = 1;
module_param(libcfs_console_ratelimit, uint, 0644);
MODULE_PARM_DESC(libcfs_console_ratelimit, "Lustre kernel debug console ratelimit (0 to disable)");
-EXPORT_SYMBOL(libcfs_console_ratelimit);
static int param_set_delay_minmax(const char *val,
const struct kernel_param *kp,
@@ -135,9 +132,7 @@ static int param_get_delay(char *buffer, const struct kernel_param *kp)
}
unsigned int libcfs_console_max_delay;
-EXPORT_SYMBOL(libcfs_console_max_delay);
unsigned int libcfs_console_min_delay;
-EXPORT_SYMBOL(libcfs_console_min_delay);
static int param_set_console_max_delay(const char *val,
const struct kernel_param *kp)
@@ -207,10 +202,8 @@ static struct kernel_param_ops param_ops_uintpos = {
unsigned int libcfs_console_backoff = CDEBUG_DEFAULT_BACKOFF;
module_param(libcfs_console_backoff, uintpos, 0644);
MODULE_PARM_DESC(libcfs_console_backoff, "Lustre kernel debug console backoff factor");
-EXPORT_SYMBOL(libcfs_console_backoff);
unsigned int libcfs_debug_binary = 1;
-EXPORT_SYMBOL(libcfs_debug_binary);
unsigned int libcfs_stack = 3 * THREAD_SIZE / 4;
EXPORT_SYMBOL(libcfs_stack);
@@ -221,7 +214,6 @@ EXPORT_SYMBOL(libcfs_catastrophe);
unsigned int libcfs_panic_on_lbug = 1;
module_param(libcfs_panic_on_lbug, uint, 0644);
MODULE_PARM_DESC(libcfs_panic_on_lbug, "Lustre kernel panic on LBUG");
-EXPORT_SYMBOL(libcfs_panic_on_lbug);
static wait_queue_head_t debug_ctlwq;
@@ -512,9 +504,9 @@ int libcfs_debug_init(unsigned long bufsize)
}
if (libcfs_debug_file_path != NULL) {
- strncpy(libcfs_debug_file_path_arr,
- libcfs_debug_file_path, PATH_MAX-1);
- libcfs_debug_file_path_arr[PATH_MAX - 1] = '\0';
+ strlcpy(libcfs_debug_file_path_arr,
+ libcfs_debug_file_path,
+ sizeof(libcfs_debug_file_path_arr));
}
/* If libcfs_debug_mb is set to an invalid value or uninitialized
@@ -565,12 +557,3 @@ int libcfs_debug_mark_buffer(const char *text)
#undef DEBUG_SUBSYSTEM
#define DEBUG_SUBSYSTEM S_LNET
-
-void libcfs_debug_set_level(unsigned int debug_level)
-{
- pr_warn("Lustre: Setting portals debug level to %08x\n",
- debug_level);
- libcfs_debug = debug_level;
-}
-
-EXPORT_SYMBOL(libcfs_debug_set_level);
diff --git a/drivers/staging/lustre/lustre/libcfs/fail.c b/drivers/staging/lustre/lustre/libcfs/fail.c
index d39fecebd12d..27831432d69a 100644
--- a/drivers/staging/lustre/lustre/libcfs/fail.c
+++ b/drivers/staging/lustre/lustre/libcfs/fail.c
@@ -26,7 +26,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -126,7 +126,7 @@ int __cfs_fail_timeout_set(__u32 id, __u32 value, int ms, int set)
int ret;
ret = __cfs_fail_check_set(id, value, set);
- if (ret) {
+ if (ret && likely(ms > 0)) {
CERROR("cfs_fail_timeout id %x sleeping for %dms\n",
id, ms);
set_current_state(TASK_UNINTERRUPTIBLE);
diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c
index 030874428952..4d50510434be 100644
--- a/drivers/staging/lustre/lustre/libcfs/hash.c
+++ b/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -106,9 +106,10 @@
* Now we support both locked iteration & lockless iteration of hash
* table. Also, user can break the iteration by return 1 in callback.
*/
+#include <linux/seq_file.h>
+#include <linux/log2.h>
#include "../../include/linux/libcfs/libcfs.h"
-#include <linux/seq_file.h>
#if CFS_HASH_DEBUG_LEVEL >= CFS_HASH_DEBUG_1
static unsigned int warn_on_depth = 8;
@@ -161,49 +162,49 @@ cfs_hash_rw_unlock(union cfs_hash_lock *lock, int exclusive)
/** No lock hash */
static struct cfs_hash_lock_ops cfs_hash_nl_lops = {
.hs_lock = cfs_hash_nl_lock,
- .hs_unlock = cfs_hash_nl_unlock,
- .hs_bkt_lock = cfs_hash_nl_lock,
- .hs_bkt_unlock = cfs_hash_nl_unlock,
+ .hs_unlock = cfs_hash_nl_unlock,
+ .hs_bkt_lock = cfs_hash_nl_lock,
+ .hs_bkt_unlock = cfs_hash_nl_unlock,
};
/** no bucket lock, one spinlock to protect everything */
static struct cfs_hash_lock_ops cfs_hash_nbl_lops = {
.hs_lock = cfs_hash_spin_lock,
- .hs_unlock = cfs_hash_spin_unlock,
- .hs_bkt_lock = cfs_hash_nl_lock,
- .hs_bkt_unlock = cfs_hash_nl_unlock,
+ .hs_unlock = cfs_hash_spin_unlock,
+ .hs_bkt_lock = cfs_hash_nl_lock,
+ .hs_bkt_unlock = cfs_hash_nl_unlock,
};
/** spin bucket lock, rehash is enabled */
static struct cfs_hash_lock_ops cfs_hash_bkt_spin_lops = {
.hs_lock = cfs_hash_rw_lock,
- .hs_unlock = cfs_hash_rw_unlock,
- .hs_bkt_lock = cfs_hash_spin_lock,
- .hs_bkt_unlock = cfs_hash_spin_unlock,
+ .hs_unlock = cfs_hash_rw_unlock,
+ .hs_bkt_lock = cfs_hash_spin_lock,
+ .hs_bkt_unlock = cfs_hash_spin_unlock,
};
/** rw bucket lock, rehash is enabled */
static struct cfs_hash_lock_ops cfs_hash_bkt_rw_lops = {
.hs_lock = cfs_hash_rw_lock,
- .hs_unlock = cfs_hash_rw_unlock,
- .hs_bkt_lock = cfs_hash_rw_lock,
- .hs_bkt_unlock = cfs_hash_rw_unlock,
+ .hs_unlock = cfs_hash_rw_unlock,
+ .hs_bkt_lock = cfs_hash_rw_lock,
+ .hs_bkt_unlock = cfs_hash_rw_unlock,
};
/** spin bucket lock, rehash is disabled */
static struct cfs_hash_lock_ops cfs_hash_nr_bkt_spin_lops = {
.hs_lock = cfs_hash_nl_lock,
- .hs_unlock = cfs_hash_nl_unlock,
- .hs_bkt_lock = cfs_hash_spin_lock,
- .hs_bkt_unlock = cfs_hash_spin_unlock,
+ .hs_unlock = cfs_hash_nl_unlock,
+ .hs_bkt_lock = cfs_hash_spin_lock,
+ .hs_bkt_unlock = cfs_hash_spin_unlock,
};
/** rw bucket lock, rehash is disabled */
static struct cfs_hash_lock_ops cfs_hash_nr_bkt_rw_lops = {
.hs_lock = cfs_hash_nl_lock,
- .hs_unlock = cfs_hash_nl_unlock,
- .hs_bkt_lock = cfs_hash_rw_lock,
- .hs_bkt_unlock = cfs_hash_rw_unlock,
+ .hs_unlock = cfs_hash_nl_unlock,
+ .hs_bkt_lock = cfs_hash_rw_lock,
+ .hs_bkt_unlock = cfs_hash_rw_unlock,
};
static void
@@ -280,7 +281,7 @@ cfs_hash_hh_hnode_del(struct cfs_hash *hs, struct cfs_hash_bd *bd,
*/
struct cfs_hash_head_dep {
struct hlist_head hd_head; /**< entries list */
- unsigned int hd_depth; /**< list length */
+ unsigned int hd_depth; /**< list length */
};
static int
@@ -328,7 +329,7 @@ cfs_hash_hd_hnode_del(struct cfs_hash *hs, struct cfs_hash_bd *bd,
*/
struct cfs_hash_dhead {
struct hlist_head dh_head; /**< entries list */
- struct hlist_node *dh_tail; /**< the last entry */
+ struct hlist_node *dh_tail; /**< the last entry */
};
static int
@@ -384,8 +385,8 @@ cfs_hash_dh_hnode_del(struct cfs_hash *hs, struct cfs_hash_bd *bd,
*/
struct cfs_hash_dhead_dep {
struct hlist_head dd_head; /**< entries list */
- struct hlist_node *dd_tail; /**< the last entry */
- unsigned int dd_depth; /**< list length */
+ struct hlist_node *dd_tail; /**< the last entry */
+ unsigned int dd_depth; /**< list length */
};
static int
@@ -436,31 +437,31 @@ cfs_hash_dd_hnode_del(struct cfs_hash *hs, struct cfs_hash_bd *bd,
}
static struct cfs_hash_hlist_ops cfs_hash_hh_hops = {
- .hop_hhead = cfs_hash_hh_hhead,
- .hop_hhead_size = cfs_hash_hh_hhead_size,
- .hop_hnode_add = cfs_hash_hh_hnode_add,
- .hop_hnode_del = cfs_hash_hh_hnode_del,
+ .hop_hhead = cfs_hash_hh_hhead,
+ .hop_hhead_size = cfs_hash_hh_hhead_size,
+ .hop_hnode_add = cfs_hash_hh_hnode_add,
+ .hop_hnode_del = cfs_hash_hh_hnode_del,
};
static struct cfs_hash_hlist_ops cfs_hash_hd_hops = {
- .hop_hhead = cfs_hash_hd_hhead,
- .hop_hhead_size = cfs_hash_hd_hhead_size,
- .hop_hnode_add = cfs_hash_hd_hnode_add,
- .hop_hnode_del = cfs_hash_hd_hnode_del,
+ .hop_hhead = cfs_hash_hd_hhead,
+ .hop_hhead_size = cfs_hash_hd_hhead_size,
+ .hop_hnode_add = cfs_hash_hd_hnode_add,
+ .hop_hnode_del = cfs_hash_hd_hnode_del,
};
static struct cfs_hash_hlist_ops cfs_hash_dh_hops = {
- .hop_hhead = cfs_hash_dh_hhead,
- .hop_hhead_size = cfs_hash_dh_hhead_size,
- .hop_hnode_add = cfs_hash_dh_hnode_add,
- .hop_hnode_del = cfs_hash_dh_hnode_del,
+ .hop_hhead = cfs_hash_dh_hhead,
+ .hop_hhead_size = cfs_hash_dh_hhead_size,
+ .hop_hnode_add = cfs_hash_dh_hnode_add,
+ .hop_hnode_del = cfs_hash_dh_hnode_del,
};
static struct cfs_hash_hlist_ops cfs_hash_dd_hops = {
- .hop_hhead = cfs_hash_dd_hhead,
- .hop_hhead_size = cfs_hash_dd_hhead_size,
- .hop_hnode_add = cfs_hash_dd_hnode_add,
- .hop_hnode_del = cfs_hash_dd_hnode_del,
+ .hop_hhead = cfs_hash_dd_hhead,
+ .hop_hhead_size = cfs_hash_dd_hhead_size,
+ .hop_hnode_add = cfs_hash_dd_hnode_add,
+ .hop_hnode_del = cfs_hash_dd_hnode_del,
};
static void
@@ -529,7 +530,7 @@ void
cfs_hash_bd_add_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
struct hlist_node *hnode)
{
- int rc;
+ int rc;
rc = hs->hs_hops->hop_hnode_add(hs, bd, hnode);
cfs_hash_bd_dep_record(hs, bd, rc);
@@ -572,7 +573,7 @@ cfs_hash_bd_move_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd_old,
{
struct cfs_hash_bucket *obkt = bd_old->bd_bucket;
struct cfs_hash_bucket *nbkt = bd_new->bd_bucket;
- int rc;
+ int rc;
if (cfs_hash_bd_compare(bd_old, bd_new) == 0)
return;
@@ -593,34 +594,33 @@ cfs_hash_bd_move_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd_old,
if (unlikely(nbkt->hsb_version == 0))
nbkt->hsb_version++;
}
-EXPORT_SYMBOL(cfs_hash_bd_move_locked);
enum {
/** always set, for sanity (avoid ZERO intent) */
- CFS_HS_LOOKUP_MASK_FIND = BIT(0),
+ CFS_HS_LOOKUP_MASK_FIND = BIT(0),
/** return entry with a ref */
- CFS_HS_LOOKUP_MASK_REF = BIT(1),
+ CFS_HS_LOOKUP_MASK_REF = BIT(1),
/** add entry if not existing */
- CFS_HS_LOOKUP_MASK_ADD = BIT(2),
+ CFS_HS_LOOKUP_MASK_ADD = BIT(2),
/** delete entry, ignore other masks */
- CFS_HS_LOOKUP_MASK_DEL = BIT(3),
+ CFS_HS_LOOKUP_MASK_DEL = BIT(3),
};
enum cfs_hash_lookup_intent {
/** return item w/o refcount */
- CFS_HS_LOOKUP_IT_PEEK = CFS_HS_LOOKUP_MASK_FIND,
+ CFS_HS_LOOKUP_IT_PEEK = CFS_HS_LOOKUP_MASK_FIND,
/** return item with refcount */
- CFS_HS_LOOKUP_IT_FIND = (CFS_HS_LOOKUP_MASK_FIND |
- CFS_HS_LOOKUP_MASK_REF),
+ CFS_HS_LOOKUP_IT_FIND = (CFS_HS_LOOKUP_MASK_FIND |
+ CFS_HS_LOOKUP_MASK_REF),
/** return item w/o refcount if existed, otherwise add */
- CFS_HS_LOOKUP_IT_ADD = (CFS_HS_LOOKUP_MASK_FIND |
- CFS_HS_LOOKUP_MASK_ADD),
+ CFS_HS_LOOKUP_IT_ADD = (CFS_HS_LOOKUP_MASK_FIND |
+ CFS_HS_LOOKUP_MASK_ADD),
/** return item with refcount if existed, otherwise add */
- CFS_HS_LOOKUP_IT_FINDADD = (CFS_HS_LOOKUP_IT_FIND |
- CFS_HS_LOOKUP_MASK_ADD),
+ CFS_HS_LOOKUP_IT_FINDADD = (CFS_HS_LOOKUP_IT_FIND |
+ CFS_HS_LOOKUP_MASK_ADD),
/** delete if existed */
- CFS_HS_LOOKUP_IT_FINDDEL = (CFS_HS_LOOKUP_MASK_FIND |
- CFS_HS_LOOKUP_MASK_DEL)
+ CFS_HS_LOOKUP_IT_FINDDEL = (CFS_HS_LOOKUP_MASK_FIND |
+ CFS_HS_LOOKUP_MASK_DEL)
};
static struct hlist_node *
@@ -629,10 +629,10 @@ cfs_hash_bd_lookup_intent(struct cfs_hash *hs, struct cfs_hash_bd *bd,
enum cfs_hash_lookup_intent intent)
{
- struct hlist_head *hhead = cfs_hash_bd_hhead(hs, bd);
- struct hlist_node *ehnode;
- struct hlist_node *match;
- int intent_add = (intent & CFS_HS_LOOKUP_MASK_ADD) != 0;
+ struct hlist_head *hhead = cfs_hash_bd_hhead(hs, bd);
+ struct hlist_node *ehnode;
+ struct hlist_node *match;
+ int intent_add = (intent & CFS_HS_LOOKUP_MASK_ADD) != 0;
/* with this function, we can avoid a lot of useless refcount ops,
* which are expensive atomic operations most time. */
@@ -665,7 +665,8 @@ cfs_hash_bd_lookup_intent(struct cfs_hash *hs, struct cfs_hash_bd *bd,
}
struct hlist_node *
-cfs_hash_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd, const void *key)
+cfs_hash_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
+ const void *key)
{
return cfs_hash_bd_lookup_intent(hs, bd, key, NULL,
CFS_HS_LOOKUP_IT_FIND);
@@ -673,40 +674,20 @@ cfs_hash_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd, const voi
EXPORT_SYMBOL(cfs_hash_bd_lookup_locked);
struct hlist_node *
-cfs_hash_bd_peek_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd, const void *key)
+cfs_hash_bd_peek_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
+ const void *key)
{
return cfs_hash_bd_lookup_intent(hs, bd, key, NULL,
CFS_HS_LOOKUP_IT_PEEK);
}
EXPORT_SYMBOL(cfs_hash_bd_peek_locked);
-struct hlist_node *
-cfs_hash_bd_findadd_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- const void *key, struct hlist_node *hnode,
- int noref)
-{
- return cfs_hash_bd_lookup_intent(hs, bd, key, hnode,
- (!noref * CFS_HS_LOOKUP_MASK_REF) |
- CFS_HS_LOOKUP_IT_ADD);
-}
-EXPORT_SYMBOL(cfs_hash_bd_findadd_locked);
-
-struct hlist_node *
-cfs_hash_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- const void *key, struct hlist_node *hnode)
-{
- /* hnode can be NULL, we find the first item with @key */
- return cfs_hash_bd_lookup_intent(hs, bd, key, hnode,
- CFS_HS_LOOKUP_IT_FINDDEL);
-}
-EXPORT_SYMBOL(cfs_hash_bd_finddel_locked);
-
static void
cfs_hash_multi_bd_lock(struct cfs_hash *hs, struct cfs_hash_bd *bds,
unsigned n, int excl)
{
struct cfs_hash_bucket *prev = NULL;
- int i;
+ int i;
/**
* bds must be ascendantly ordered by bd->bd_bucket->hsb_index.
@@ -729,7 +710,7 @@ cfs_hash_multi_bd_unlock(struct cfs_hash *hs, struct cfs_hash_bd *bds,
unsigned n, int excl)
{
struct cfs_hash_bucket *prev = NULL;
- int i;
+ int i;
cfs_hash_for_each_bd(bds, n, i) {
if (prev != bds[i].bd_bucket) {
@@ -743,8 +724,8 @@ static struct hlist_node *
cfs_hash_multi_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
unsigned n, const void *key)
{
- struct hlist_node *ehnode;
- unsigned i;
+ struct hlist_node *ehnode;
+ unsigned i;
cfs_hash_for_each_bd(bds, n, i) {
ehnode = cfs_hash_bd_lookup_intent(hs, &bds[i], key, NULL,
@@ -756,13 +737,13 @@ cfs_hash_multi_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
}
static struct hlist_node *
-cfs_hash_multi_bd_findadd_locked(struct cfs_hash *hs,
- struct cfs_hash_bd *bds, unsigned n, const void *key,
+cfs_hash_multi_bd_findadd_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
+ unsigned n, const void *key,
struct hlist_node *hnode, int noref)
{
- struct hlist_node *ehnode;
- int intent;
- unsigned i;
+ struct hlist_node *ehnode;
+ int intent;
+ unsigned i;
LASSERT(hnode != NULL);
intent = (!noref * CFS_HS_LOOKUP_MASK_REF) | CFS_HS_LOOKUP_IT_PEEK;
@@ -777,7 +758,7 @@ cfs_hash_multi_bd_findadd_locked(struct cfs_hash *hs,
if (i == 1) { /* only one bucket */
cfs_hash_bd_add_locked(hs, &bds[0], hnode);
} else {
- struct cfs_hash_bd mybd;
+ struct cfs_hash_bd mybd;
cfs_hash_bd_get(hs, key, &mybd);
cfs_hash_bd_add_locked(hs, &mybd, hnode);
@@ -791,8 +772,8 @@ cfs_hash_multi_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
unsigned n, const void *key,
struct hlist_node *hnode)
{
- struct hlist_node *ehnode;
- unsigned i;
+ struct hlist_node *ehnode;
+ unsigned int i;
cfs_hash_for_each_bd(bds, n, i) {
ehnode = cfs_hash_bd_lookup_intent(hs, &bds[i], key, hnode,
@@ -806,7 +787,7 @@ cfs_hash_multi_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
static void
cfs_hash_bd_order(struct cfs_hash_bd *bd1, struct cfs_hash_bd *bd2)
{
- int rc;
+ int rc;
if (bd2->bd_bucket == NULL)
return;
@@ -831,7 +812,8 @@ cfs_hash_bd_order(struct cfs_hash_bd *bd1, struct cfs_hash_bd *bd2)
}
void
-cfs_hash_dual_bd_get(struct cfs_hash *hs, const void *key, struct cfs_hash_bd *bds)
+cfs_hash_dual_bd_get(struct cfs_hash *hs, const void *key,
+ struct cfs_hash_bd *bds)
{
/* NB: caller should hold hs_lock.rw if REHASH is set */
cfs_hash_bd_from_key(hs, hs->hs_buckets,
@@ -848,21 +830,18 @@ cfs_hash_dual_bd_get(struct cfs_hash *hs, const void *key, struct cfs_hash_bd *b
cfs_hash_bd_order(&bds[0], &bds[1]);
}
-EXPORT_SYMBOL(cfs_hash_dual_bd_get);
void
cfs_hash_dual_bd_lock(struct cfs_hash *hs, struct cfs_hash_bd *bds, int excl)
{
cfs_hash_multi_bd_lock(hs, bds, 2, excl);
}
-EXPORT_SYMBOL(cfs_hash_dual_bd_lock);
void
cfs_hash_dual_bd_unlock(struct cfs_hash *hs, struct cfs_hash_bd *bds, int excl)
{
cfs_hash_multi_bd_unlock(hs, bds, 2, excl);
}
-EXPORT_SYMBOL(cfs_hash_dual_bd_unlock);
struct hlist_node *
cfs_hash_dual_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
@@ -870,7 +849,6 @@ cfs_hash_dual_bd_lookup_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
{
return cfs_hash_multi_bd_lookup_locked(hs, bds, 2, key);
}
-EXPORT_SYMBOL(cfs_hash_dual_bd_lookup_locked);
struct hlist_node *
cfs_hash_dual_bd_findadd_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
@@ -880,7 +858,6 @@ cfs_hash_dual_bd_findadd_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
return cfs_hash_multi_bd_findadd_locked(hs, bds, 2, key,
hnode, noref);
}
-EXPORT_SYMBOL(cfs_hash_dual_bd_findadd_locked);
struct hlist_node *
cfs_hash_dual_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
@@ -888,13 +865,12 @@ cfs_hash_dual_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bds,
{
return cfs_hash_multi_bd_finddel_locked(hs, bds, 2, key, hnode);
}
-EXPORT_SYMBOL(cfs_hash_dual_bd_finddel_locked);
static void
cfs_hash_buckets_free(struct cfs_hash_bucket **buckets,
int bkt_size, int prev_size, int size)
{
- int i;
+ int i;
for (i = prev_size; i < size; i++) {
if (buckets[i] != NULL)
@@ -914,7 +890,7 @@ cfs_hash_buckets_realloc(struct cfs_hash *hs, struct cfs_hash_bucket **old_bkts,
unsigned int old_size, unsigned int new_size)
{
struct cfs_hash_bucket **new_bkts;
- int i;
+ int i;
LASSERT(old_size == 0 || old_bkts != NULL);
@@ -932,7 +908,7 @@ cfs_hash_buckets_realloc(struct cfs_hash *hs, struct cfs_hash_bucket **old_bkts,
for (i = old_size; i < new_size; i++) {
struct hlist_head *hhead;
- struct cfs_hash_bd bd;
+ struct cfs_hash_bd bd;
LIBCFS_ALLOC(new_bkts[i], cfs_hash_bkt_size(hs));
if (new_bkts[i] == NULL) {
@@ -969,7 +945,7 @@ cfs_hash_buckets_realloc(struct cfs_hash *hs, struct cfs_hash_bucket **old_bkts,
* @max_bits - Maximum allowed hash table resize, in bits
* @ops - Registered hash table operations
* @flags - CFS_HASH_REHASH enable synamic hash resizing
- * - CFS_HASH_SORT enable chained hash sort
+ * - CFS_HASH_SORT enable chained hash sort
*/
static int cfs_hash_rehash_worker(cfs_workitem_t *wi);
@@ -977,10 +953,10 @@ static int cfs_hash_rehash_worker(cfs_workitem_t *wi);
static int cfs_hash_dep_print(cfs_workitem_t *wi)
{
struct cfs_hash *hs = container_of(wi, struct cfs_hash, hs_dep_wi);
- int dep;
- int bkt;
- int off;
- int bits;
+ int dep;
+ int bkt;
+ int off;
+ int bits;
spin_lock(&hs->hs_dep_lock);
dep = hs->hs_dep_max;
@@ -1031,7 +1007,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
struct cfs_hash_ops *ops, unsigned flags)
{
struct cfs_hash *hs;
- int len;
+ int len;
CLASSERT(CFS_HASH_THETA_BITS < 15);
@@ -1062,8 +1038,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
if (hs == NULL)
return NULL;
- strncpy(hs->hs_name, name, len);
- hs->hs_name[len - 1] = '\0';
+ strlcpy(hs->hs_name, name, len);
hs->hs_flags = flags;
atomic_set(&hs->hs_refcount, 1);
@@ -1077,7 +1052,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
hs->hs_max_bits = (__u8)max_bits;
hs->hs_bkt_bits = (__u8)bkt_bits;
- hs->hs_ops = ops;
+ hs->hs_ops = ops;
hs->hs_extra_bytes = extra_bytes;
hs->hs_rehash_bits = 0;
cfs_wi_init(&hs->hs_rehash_wi, hs, cfs_hash_rehash_worker);
@@ -1102,10 +1077,10 @@ EXPORT_SYMBOL(cfs_hash_create);
static void
cfs_hash_destroy(struct cfs_hash *hs)
{
- struct hlist_node *hnode;
- struct hlist_node *pos;
- struct cfs_hash_bd bd;
- int i;
+ struct hlist_node *hnode;
+ struct hlist_node *pos;
+ struct cfs_hash_bd bd;
+ int i;
LASSERT(hs != NULL);
LASSERT(!cfs_hash_is_exiting(hs) &&
@@ -1223,8 +1198,8 @@ cfs_hash_rehash_inline(struct cfs_hash *hs)
void
cfs_hash_add(struct cfs_hash *hs, const void *key, struct hlist_node *hnode)
{
- struct cfs_hash_bd bd;
- int bits;
+ struct cfs_hash_bd bd;
+ int bits;
LASSERT(hlist_unhashed(hnode));
@@ -1248,8 +1223,8 @@ cfs_hash_find_or_add(struct cfs_hash *hs, const void *key,
struct hlist_node *hnode, int noref)
{
struct hlist_node *ehnode;
- struct cfs_hash_bd bds[2];
- int bits = 0;
+ struct cfs_hash_bd bds[2];
+ int bits = 0;
LASSERT(hlist_unhashed(hnode));
@@ -1261,7 +1236,7 @@ cfs_hash_find_or_add(struct cfs_hash *hs, const void *key,
hnode, noref);
cfs_hash_dual_bd_unlock(hs, bds, 1);
- if (ehnode == hnode) /* new item added */
+ if (ehnode == hnode) /* new item added */
bits = cfs_hash_rehash_bits(hs);
cfs_hash_unlock(hs, 0);
if (bits > 0)
@@ -1276,7 +1251,8 @@ cfs_hash_find_or_add(struct cfs_hash *hs, const void *key,
* Returns 0 on success or -EALREADY on key collisions.
*/
int
-cfs_hash_add_unique(struct cfs_hash *hs, const void *key, struct hlist_node *hnode)
+cfs_hash_add_unique(struct cfs_hash *hs, const void *key,
+ struct hlist_node *hnode)
{
return cfs_hash_find_or_add(hs, key, hnode, 1) != hnode ?
-EALREADY : 0;
@@ -1309,9 +1285,9 @@ EXPORT_SYMBOL(cfs_hash_findadd_unique);
void *
cfs_hash_del(struct cfs_hash *hs, const void *key, struct hlist_node *hnode)
{
- void *obj = NULL;
- int bits = 0;
- struct cfs_hash_bd bds[2];
+ void *obj = NULL;
+ int bits = 0;
+ struct cfs_hash_bd bds[2];
cfs_hash_lock(hs, 0);
cfs_hash_dual_bd_get_and_lock(hs, key, bds, 1);
@@ -1364,9 +1340,9 @@ EXPORT_SYMBOL(cfs_hash_del_key);
void *
cfs_hash_lookup(struct cfs_hash *hs, const void *key)
{
- void *obj = NULL;
- struct hlist_node *hnode;
- struct cfs_hash_bd bds[2];
+ void *obj = NULL;
+ struct hlist_node *hnode;
+ struct cfs_hash_bd bds[2];
cfs_hash_lock(hs, 0);
cfs_hash_dual_bd_get_and_lock(hs, key, bds, 0);
@@ -1383,7 +1359,8 @@ cfs_hash_lookup(struct cfs_hash *hs, const void *key)
EXPORT_SYMBOL(cfs_hash_lookup);
static void
-cfs_hash_for_each_enter(struct cfs_hash *hs) {
+cfs_hash_for_each_enter(struct cfs_hash *hs)
+{
LASSERT(!cfs_hash_is_exiting(hs));
if (!cfs_hash_with_rehash(hs))
@@ -1408,7 +1385,8 @@ cfs_hash_for_each_enter(struct cfs_hash *hs) {
}
static void
-cfs_hash_for_each_exit(struct cfs_hash *hs) {
+cfs_hash_for_each_exit(struct cfs_hash *hs)
+{
int remained;
int bits;
@@ -1439,14 +1417,15 @@ cfs_hash_for_each_exit(struct cfs_hash *hs) {
*/
static __u64
cfs_hash_for_each_tight(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
- void *data, int remove_safe) {
- struct hlist_node *hnode;
- struct hlist_node *pos;
- struct cfs_hash_bd bd;
- __u64 count = 0;
- int excl = !!remove_safe;
- int loop = 0;
- int i;
+ void *data, int remove_safe)
+{
+ struct hlist_node *hnode;
+ struct hlist_node *pos;
+ struct cfs_hash_bd bd;
+ __u64 count = 0;
+ int excl = !!remove_safe;
+ int loop = 0;
+ int i;
cfs_hash_for_each_enter(hs);
@@ -1514,8 +1493,8 @@ void
cfs_hash_cond_del(struct cfs_hash *hs, cfs_hash_cond_opt_cb_t func, void *data)
{
struct cfs_hash_cond_arg arg = {
- .func = func,
- .arg = data,
+ .func = func,
+ .arg = data,
};
cfs_hash_for_each_tight(hs, cfs_hash_cond_del_locked, &arg, 1);
@@ -1523,16 +1502,17 @@ cfs_hash_cond_del(struct cfs_hash *hs, cfs_hash_cond_opt_cb_t func, void *data)
EXPORT_SYMBOL(cfs_hash_cond_del);
void
-cfs_hash_for_each(struct cfs_hash *hs,
- cfs_hash_for_each_cb_t func, void *data)
+cfs_hash_for_each(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
+ void *data)
{
cfs_hash_for_each_tight(hs, func, data, 0);
}
EXPORT_SYMBOL(cfs_hash_for_each);
void
-cfs_hash_for_each_safe(struct cfs_hash *hs,
- cfs_hash_for_each_cb_t func, void *data) {
+cfs_hash_for_each_safe(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
+ void *data)
+{
cfs_hash_for_each_tight(hs, func, data, 1);
}
EXPORT_SYMBOL(cfs_hash_for_each_safe);
@@ -1581,15 +1561,16 @@ EXPORT_SYMBOL(cfs_hash_size_get);
*/
static int
cfs_hash_for_each_relax(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
- void *data) {
+ void *data)
+{
struct hlist_node *hnode;
struct hlist_node *tmp;
- struct cfs_hash_bd bd;
- __u32 version;
- int count = 0;
- int stop_on_change;
- int rc;
- int i;
+ struct cfs_hash_bd bd;
+ __u32 version;
+ int count = 0;
+ int stop_on_change;
+ int rc;
+ int i;
stop_on_change = cfs_hash_with_rehash_key(hs) ||
!cfs_hash_with_no_itemref(hs) ||
@@ -1645,8 +1626,9 @@ cfs_hash_for_each_relax(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
}
int
-cfs_hash_for_each_nolock(struct cfs_hash *hs,
- cfs_hash_for_each_cb_t func, void *data) {
+cfs_hash_for_each_nolock(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
+ void *data)
+{
if (cfs_hash_with_no_lock(hs) ||
cfs_hash_with_rehash_key(hs) ||
!cfs_hash_with_no_itemref(hs))
@@ -1677,9 +1659,10 @@ EXPORT_SYMBOL(cfs_hash_for_each_nolock);
* the required locking is in place to prevent concurrent insertions.
*/
int
-cfs_hash_for_each_empty(struct cfs_hash *hs,
- cfs_hash_for_each_cb_t func, void *data) {
- unsigned i = 0;
+cfs_hash_for_each_empty(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
+ void *data)
+{
+ unsigned i = 0;
if (cfs_hash_with_no_lock(hs))
return -EOPNOTSUPP;
@@ -1703,9 +1686,9 @@ void
cfs_hash_hlist_for_each(struct cfs_hash *hs, unsigned hindex,
cfs_hash_for_each_cb_t func, void *data)
{
- struct hlist_head *hhead;
- struct hlist_node *hnode;
- struct cfs_hash_bd bd;
+ struct hlist_head *hhead;
+ struct hlist_node *hnode;
+ struct cfs_hash_bd bd;
cfs_hash_for_each_enter(hs);
cfs_hash_lock(hs, 0);
@@ -1721,7 +1704,7 @@ cfs_hash_hlist_for_each(struct cfs_hash *hs, unsigned hindex,
break;
}
cfs_hash_bd_unlock(hs, &bd, 0);
- out:
+out:
cfs_hash_unlock(hs, 0);
cfs_hash_for_each_exit(hs);
}
@@ -1736,10 +1719,11 @@ EXPORT_SYMBOL(cfs_hash_hlist_for_each);
*/
void
cfs_hash_for_each_key(struct cfs_hash *hs, const void *key,
- cfs_hash_for_each_cb_t func, void *data) {
- struct hlist_node *hnode;
- struct cfs_hash_bd bds[2];
- unsigned i;
+ cfs_hash_for_each_cb_t func, void *data)
+{
+ struct hlist_node *hnode;
+ struct cfs_hash_bd bds[2];
+ unsigned int i;
cfs_hash_lock(hs, 0);
@@ -1777,7 +1761,7 @@ EXPORT_SYMBOL(cfs_hash_for_each_key);
void
cfs_hash_rehash_cancel_locked(struct cfs_hash *hs)
{
- int i;
+ int i;
/* need hold cfs_hash_lock(hs, 1) */
LASSERT(cfs_hash_with_rehash(hs) &&
@@ -1794,14 +1778,13 @@ cfs_hash_rehash_cancel_locked(struct cfs_hash *hs)
for (i = 2; cfs_hash_is_rehashing(hs); i++) {
cfs_hash_unlock(hs, 1);
/* raise console warning while waiting too long */
- CDEBUG(IS_PO2(i >> 3) ? D_WARNING : D_INFO,
+ CDEBUG(is_power_of_2(i >> 3) ? D_WARNING : D_INFO,
"hash %s is still rehashing, rescheded %d\n",
hs->hs_name, i - 1);
cond_resched();
cfs_hash_lock(hs, 1);
}
}
-EXPORT_SYMBOL(cfs_hash_rehash_cancel_locked);
void
cfs_hash_rehash_cancel(struct cfs_hash *hs)
@@ -1810,12 +1793,11 @@ cfs_hash_rehash_cancel(struct cfs_hash *hs)
cfs_hash_rehash_cancel_locked(hs);
cfs_hash_unlock(hs, 1);
}
-EXPORT_SYMBOL(cfs_hash_rehash_cancel);
int
cfs_hash_rehash(struct cfs_hash *hs, int do_rehash)
{
- int rc;
+ int rc;
LASSERT(cfs_hash_with_rehash(hs) && !cfs_hash_with_no_lock(hs));
@@ -1840,17 +1822,16 @@ cfs_hash_rehash(struct cfs_hash *hs, int do_rehash)
return cfs_hash_rehash_worker(&hs->hs_rehash_wi);
}
-EXPORT_SYMBOL(cfs_hash_rehash);
static int
cfs_hash_rehash_bd(struct cfs_hash *hs, struct cfs_hash_bd *old)
{
- struct cfs_hash_bd new;
- struct hlist_head *hhead;
- struct hlist_node *hnode;
- struct hlist_node *pos;
- void *key;
- int c = 0;
+ struct cfs_hash_bd new;
+ struct hlist_head *hhead;
+ struct hlist_node *hnode;
+ struct hlist_node *pos;
+ void *key;
+ int c = 0;
/* hold cfs_hash_lock(hs, 1), so don't need any bucket lock */
cfs_hash_bd_for_each_hlist(hs, old, hhead) {
@@ -1876,17 +1857,17 @@ cfs_hash_rehash_bd(struct cfs_hash *hs, struct cfs_hash_bd *old)
static int
cfs_hash_rehash_worker(cfs_workitem_t *wi)
{
- struct cfs_hash *hs = container_of(wi, struct cfs_hash, hs_rehash_wi);
+ struct cfs_hash *hs = container_of(wi, struct cfs_hash, hs_rehash_wi);
struct cfs_hash_bucket **bkts;
- struct cfs_hash_bd bd;
- unsigned int old_size;
- unsigned int new_size;
- int bsize;
- int count = 0;
- int rc = 0;
- int i;
+ struct cfs_hash_bd bd;
+ unsigned int old_size;
+ unsigned int new_size;
+ int bsize;
+ int count = 0;
+ int rc = 0;
+ int i;
- LASSERT (hs != NULL && cfs_hash_with_rehash(hs));
+ LASSERT(hs != NULL && cfs_hash_with_rehash(hs));
cfs_hash_lock(hs, 0);
LASSERT(cfs_hash_is_rehashing(hs));
@@ -1958,7 +1939,7 @@ cfs_hash_rehash_worker(cfs_workitem_t *wi)
hs->hs_rehash_buckets = NULL;
hs->hs_cur_bits = hs->hs_rehash_bits;
- out:
+out:
hs->hs_rehash_bits = 0;
if (rc == -ESRCH) /* never be scheduled again */
cfs_wi_exit(cfs_sched_rehash, wi);
@@ -1986,9 +1967,9 @@ cfs_hash_rehash_worker(cfs_workitem_t *wi)
void cfs_hash_rehash_key(struct cfs_hash *hs, const void *old_key,
void *new_key, struct hlist_node *hnode)
{
- struct cfs_hash_bd bds[3];
- struct cfs_hash_bd old_bds[2];
- struct cfs_hash_bd new_bd;
+ struct cfs_hash_bd bds[3];
+ struct cfs_hash_bd old_bds[2];
+ struct cfs_hash_bd new_bd;
LASSERT(!hlist_unhashed(hnode));
@@ -2014,7 +1995,7 @@ void cfs_hash_rehash_key(struct cfs_hash *hs, const void *old_key,
}
/* overwrite key inside locks, otherwise may screw up with
* other operations, i.e: rehash */
- cfs_hash_keycpy(hs, new_key, hnode);
+ cfs_hash_keycpy(hs, hnode, new_key);
cfs_hash_multi_bd_unlock(hs, bds, 3, 1);
cfs_hash_unlock(hs, 0);
@@ -2054,12 +2035,12 @@ cfs_hash_full_nbkt(struct cfs_hash *hs)
void cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
{
- int dist[8] = { 0, };
- int maxdep = -1;
- int maxdepb = -1;
- int total = 0;
- int theta;
- int i;
+ int dist[8] = { 0, };
+ int maxdep = -1;
+ int maxdepb = -1;
+ int total = 0;
+ int theta;
+ int i;
cfs_hash_lock(hs, 0);
theta = __cfs_hash_theta(hs);
@@ -2085,11 +2066,11 @@ void cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
* If you hash function results in a non-uniform hash the will
* be observable by outlier bucks in the distribution histogram.
*
- * Uniform hash distribution: 128/128/0/0/0/0/0/0
- * Non-Uniform hash distribution: 128/125/0/0/0/0/2/1
+ * Uniform hash distribution: 128/128/0/0/0/0/0/0
+ * Non-Uniform hash distribution: 128/125/0/0/0/0/2/1
*/
for (i = 0; i < cfs_hash_full_nbkt(hs); i++) {
- struct cfs_hash_bd bd;
+ struct cfs_hash_bd bd;
bd.bd_bucket = cfs_hash_full_bkts(hs)[i];
cfs_hash_bd_lock(hs, &bd, 0);
diff --git a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
index ad661a33a211..d8230aec9a2b 100644
--- a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
+++ b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
@@ -110,7 +110,8 @@ static DECLARE_RWSEM(kg_sem);
* @param uid identifier for this receiver
* @param group group number
*/
-int libcfs_kkuc_group_add(struct file *filp, int uid, int group, __u32 data)
+int libcfs_kkuc_group_add(struct file *filp, int uid, unsigned int group,
+ __u32 data)
{
struct kkuc_reg *reg;
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c b/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
index 94bc00785000..15782d9e6aa9 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
@@ -21,7 +21,7 @@
* GPL HEADER END
*/
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c b/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
index f4e08daba4d9..27cf86106363 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
@@ -134,7 +134,6 @@ cfs_percpt_current(void *vars)
return arr->va_ptrs[cpt];
}
-EXPORT_SYMBOL(cfs_percpt_current);
void *
cfs_percpt_index(void *vars, int idx)
@@ -146,7 +145,6 @@ cfs_percpt_index(void *vars, int idx)
LASSERT(idx >= 0 && idx < arr->va_count);
return arr->va_ptrs[idx];
}
-EXPORT_SYMBOL(cfs_percpt_index);
/*
* free variable array, see more detail in cfs_array_alloc
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
index d40be5396769..205a3ed435a8 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
index 209736454d06..e52afe35e7ea 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
@@ -22,7 +22,8 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Intel Corporation.
+ *
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -78,23 +79,6 @@ struct cfs_cpt_data {
static struct cfs_cpt_data cpt_data;
-static void cfs_cpu_core_siblings(int cpu, cpumask_t *mask)
-{
- /* return cpumask of cores in the same socket */
- cpumask_copy(mask, topology_core_cpumask(cpu));
-}
-
-/* return cpumask of HTs in the same core */
-static void cfs_cpu_ht_siblings(int cpu, cpumask_t *mask)
-{
- cpumask_copy(mask, topology_sibling_cpumask(cpu));
-}
-
-static void cfs_node_to_cpumask(int node, cpumask_t *mask)
-{
- cpumask_copy(mask, cpumask_of_node(node));
-}
-
void
cfs_cpt_table_free(struct cfs_cpt_table *cptab)
{
@@ -426,7 +410,7 @@ cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node)
mutex_lock(&cpt_data.cpt_mutex);
mask = cpt_data.cpt_cpumask;
- cfs_node_to_cpumask(node, mask);
+ cpumask_copy(mask, cpumask_of_node(node));
rc = cfs_cpt_set_cpumask(cptab, cpt, mask);
@@ -450,7 +434,7 @@ cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node)
mutex_lock(&cpt_data.cpt_mutex);
mask = cpt_data.cpt_cpumask;
- cfs_node_to_cpumask(node, mask);
+ cpumask_copy(mask, cpumask_of_node(node));
cfs_cpt_unset_cpumask(cptab, cpt, mask);
@@ -643,7 +627,7 @@ cfs_cpt_choose_ncpus(struct cfs_cpt_table *cptab, int cpt,
cpu = cpumask_first(node);
/* get cpumask for cores in the same socket */
- cfs_cpu_core_siblings(cpu, socket);
+ cpumask_copy(socket, topology_core_cpumask(cpu));
cpumask_and(socket, socket, node);
LASSERT(!cpumask_empty(socket));
@@ -652,7 +636,7 @@ cfs_cpt_choose_ncpus(struct cfs_cpt_table *cptab, int cpt,
int i;
/* get cpumask for hts in the same core */
- cfs_cpu_ht_siblings(cpu, core);
+ cpumask_copy(core, topology_sibling_cpumask(cpu));
cpumask_and(core, core, node);
LASSERT(!cpumask_empty(core));
@@ -769,7 +753,7 @@ cfs_cpt_table_create(int ncpt)
}
for_each_online_node(i) {
- cfs_node_to_cpumask(i, mask);
+ cpumask_copy(mask, cpumask_of_node(i));
while (!cpumask_empty(mask)) {
struct cfs_cpu_partition *part;
@@ -968,7 +952,8 @@ cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
mutex_lock(&cpt_data.cpt_mutex);
/* if all HTs in a core are offline, it may break affinity */
- cfs_cpu_ht_siblings(cpu, cpt_data.cpt_cpumask);
+ cpumask_copy(cpt_data.cpt_cpumask,
+ topology_sibling_cpumask(cpu));
warn = cpumask_any_and(cpt_data.cpt_cpumask,
cpu_online_mask) >= nr_cpu_ids;
mutex_unlock(&cpt_data.cpt_mutex);
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto-adler.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto-adler.c
index 5d8d8b79fa1f..db0572733712 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto-adler.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto-adler.c
@@ -37,11 +37,6 @@
#define CHKSUM_BLOCK_SIZE 1
#define CHKSUM_DIGEST_SIZE 4
-static u32 __adler32(u32 cksum, unsigned char const *p, size_t len)
-{
- return zlib_adler32(cksum, p, len);
-}
-
static int adler32_cra_init(struct crypto_tfm *tfm)
{
u32 *key = crypto_tfm_ctx(tfm);
@@ -79,14 +74,14 @@ static int adler32_update(struct shash_desc *desc, const u8 *data,
{
u32 *cksump = shash_desc_ctx(desc);
- *cksump = __adler32(*cksump, data, len);
+ *cksump = zlib_adler32(*cksump, data, len);
return 0;
}
static int __adler32_finup(u32 *cksump, const u8 *data, unsigned int len,
u8 *out)
{
- *(u32 *)out = __adler32(*cksump, data, len);
+ *(u32 *)out = zlib_adler32(*cksump, data, len);
return 0;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
index c74c80915dca..68515d9130c1 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
index 8689ea757c99..59c7bf3cbc1f 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
@@ -195,6 +195,5 @@ void libcfs_unregister_panic_notifier(void)
atomic_notifier_chain_unregister(&panic_notifier_list, &libcfs_panic_notifier);
}
-EXPORT_SYMBOL(libcfs_run_upcall);
EXPORT_SYMBOL(libcfs_run_lbug_upcall);
EXPORT_SYMBOL(lbug_with_loc);
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.h b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.h
deleted file mode 100644
index ba84e4ffddd1..000000000000
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- */
-
-#ifndef __LIBCFS_LINUX_TRACEFILE_H__
-#define __LIBCFS_LINUX_TRACEFILE_H__
-
-/**
- * three types of trace_data in linux
- */
-typedef enum {
- CFS_TCD_TYPE_PROC = 0,
- CFS_TCD_TYPE_SOFTIRQ,
- CFS_TCD_TYPE_IRQ,
- CFS_TCD_TYPE_MAX
-} cfs_trace_buf_type_t;
-
-#endif
diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c
index e7c2b26156b9..329d78ce272d 100644
--- a/drivers/staging/lustre/lustre/libcfs/module.c
+++ b/drivers/staging/lustre/lustre/libcfs/module.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -62,7 +62,7 @@
#include "../../include/linux/lnet/lnet.h"
#include "tracefile.h"
-MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Portals v3.1");
MODULE_LICENSE("GPL");
@@ -375,7 +375,7 @@ static int __proc_dobitmasks(void *data, int write,
} else {
rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
if (rc < 0) {
- cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
+ kfree(tmpstr);
return rc;
}
@@ -385,7 +385,7 @@ static int __proc_dobitmasks(void *data, int write,
*mask |= D_EMERG;
}
- cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
+ kfree(tmpstr);
return rc;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index f2d018d7823c..65c4f1ab0de8 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -199,7 +199,6 @@ static void cfs_tcd_shrink(struct cfs_trace_cpu_data *tcd)
pgcount + 1, tcd->tcd_cur_pages);
INIT_LIST_HEAD(&pc.pc_pages);
- spin_lock_init(&pc.pc_lock);
list_for_each_entry_safe(tage, tmp, &tcd->tcd_pages, linkage) {
if (pgcount-- == 0)
@@ -451,7 +450,7 @@ console:
cfs_print_to_console(&header, mask,
string_buf, needed, file, msgdata->msg_fn);
- cfs_trace_put_console_buffer(string_buf);
+ put_cpu();
}
if (cdls != NULL && cdls->cdls_count != 0) {
@@ -465,7 +464,7 @@ console:
cfs_print_to_console(&header, mask,
string_buf, needed, file, msgdata->msg_fn);
- cfs_trace_put_console_buffer(string_buf);
+ put_cpu();
cdls->cdls_count = 0;
}
@@ -522,7 +521,6 @@ static void collect_pages_on_all_cpus(struct page_collection *pc)
struct cfs_trace_cpu_data *tcd;
int i, cpu;
- spin_lock(&pc->pc_lock);
for_each_possible_cpu(cpu) {
cfs_tcd_for_each_type_lock(tcd, i, cpu) {
list_splice_init(&tcd->tcd_pages, &pc->pc_pages);
@@ -534,7 +532,6 @@ static void collect_pages_on_all_cpus(struct page_collection *pc)
}
}
}
- spin_unlock(&pc->pc_lock);
}
static void collect_pages(struct page_collection *pc)
@@ -555,7 +552,6 @@ static void put_pages_back_on_all_cpus(struct page_collection *pc)
struct cfs_trace_page *tmp;
int i, cpu;
- spin_lock(&pc->pc_lock);
for_each_possible_cpu(cpu) {
cfs_tcd_for_each_type_lock(tcd, i, cpu) {
cur_head = tcd->tcd_pages.next;
@@ -573,7 +569,6 @@ static void put_pages_back_on_all_cpus(struct page_collection *pc)
}
}
}
- spin_unlock(&pc->pc_lock);
}
static void put_pages_back(struct page_collection *pc)
@@ -592,7 +587,6 @@ static void put_pages_on_tcd_daemon_list(struct page_collection *pc,
struct cfs_trace_page *tage;
struct cfs_trace_page *tmp;
- spin_lock(&pc->pc_lock);
list_for_each_entry_safe(tage, tmp, &pc->pc_pages, linkage) {
__LASSERT_TAGE_INVARIANT(tage);
@@ -616,7 +610,6 @@ static void put_pages_on_tcd_daemon_list(struct page_collection *pc,
tcd->tcd_cur_daemon_pages--;
}
}
- spin_unlock(&pc->pc_lock);
}
static void put_pages_on_daemon_list(struct page_collection *pc)
@@ -636,8 +629,6 @@ void cfs_trace_debug_print(void)
struct cfs_trace_page *tage;
struct cfs_trace_page *tmp;
- spin_lock_init(&pc.pc_lock);
-
pc.pc_want_daemon_pages = 1;
collect_pages(&pc);
list_for_each_entry_safe(tage, tmp, &pc.pc_pages, linkage) {
@@ -692,7 +683,6 @@ int cfs_tracefile_dump_all_pages(char *filename)
goto out;
}
- spin_lock_init(&pc.pc_lock);
pc.pc_want_daemon_pages = 1;
collect_pages(&pc);
if (list_empty(&pc.pc_pages)) {
@@ -739,8 +729,6 @@ void cfs_trace_flush_pages(void)
struct cfs_trace_page *tage;
struct cfs_trace_page *tmp;
- spin_lock_init(&pc.pc_lock);
-
pc.pc_want_daemon_pages = 1;
collect_pages(&pc);
list_for_each_entry_safe(tage, tmp, &pc.pc_pages, linkage) {
@@ -817,11 +805,6 @@ int cfs_trace_allocate_string_buffer(char **str, int nob)
return 0;
}
-void cfs_trace_free_string_buffer(char *str, int nob)
-{
- kfree(str);
-}
-
int cfs_trace_dump_debug_buffer_usrstr(void __user *usr_str, int usr_str_nob)
{
char *str;
@@ -842,7 +825,7 @@ int cfs_trace_dump_debug_buffer_usrstr(void __user *usr_str, int usr_str_nob)
}
rc = cfs_tracefile_dump_all_pages(str);
out:
- cfs_trace_free_string_buffer(str, usr_str_nob + 1);
+ kfree(str);
return rc;
}
@@ -898,7 +881,7 @@ int cfs_trace_daemon_command_usrstr(void __user *usr_str, int usr_str_nob)
if (rc == 0)
rc = cfs_trace_daemon_command(str);
- cfs_trace_free_string_buffer(str, usr_str_nob + 1);
+ kfree(str);
return rc;
}
@@ -970,7 +953,6 @@ static int tracefiled(void *arg)
/* we're started late enough that we pick up init's fs context */
/* this is so broken in uml? what on earth is going on? */
- spin_lock_init(&pc.pc_lock);
complete(&tctl->tctl_start);
while (1) {
@@ -1170,7 +1152,6 @@ static void cfs_trace_cleanup(void)
struct page_collection pc;
INIT_LIST_HEAD(&pc.pc_pages);
- spin_lock_init(&pc.pc_lock);
trace_cleanup_on_all_cpus();
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.h b/drivers/staging/lustre/lustre/libcfs/tracefile.h
index cb7a3963589f..7bf1471a54fb 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.h
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.h
@@ -39,7 +39,12 @@
#include "../../include/linux/libcfs/libcfs.h"
-#include "linux/linux-tracefile.h"
+typedef enum {
+ CFS_TCD_TYPE_PROC = 0,
+ CFS_TCD_TYPE_SOFTIRQ,
+ CFS_TCD_TYPE_IRQ,
+ CFS_TCD_TYPE_MAX
+} cfs_trace_buf_type_t;
/* trace file lock routines */
@@ -70,7 +75,6 @@ int cfs_trace_copyin_string(char *knl_buffer, int knl_buffer_nob,
int cfs_trace_copyout_string(char __user *usr_buffer, int usr_buffer_nob,
const char *knl_str, char *append);
int cfs_trace_allocate_string_buffer(char **str, int nob);
-void cfs_trace_free_string_buffer(char *str, int nob);
int cfs_trace_dump_debug_buffer_usrstr(void __user *usr_str, int usr_str_nob);
int cfs_trace_daemon_command(char *str);
int cfs_trace_daemon_command_usrstr(void __user *usr_str, int usr_str_nob);
@@ -196,14 +200,6 @@ extern union cfs_trace_data_union (*cfs_trace_data[TCD_MAX_TYPES])[NR_CPUS];
struct page_collection {
struct list_head pc_pages;
/*
- * spin-lock protecting ->pc_pages. It is taken by smp_call_function()
- * call-back functions. XXX nikita: Which is horrible: all processors
- * receive NMI at the same time only to be serialized by this
- * lock. Probably ->pc_pages should be replaced with an array of
- * NR_CPUS elements accessed locklessly.
- */
- spinlock_t pc_lock;
- /*
* if this flag is set, collect_pages() will spill both
* ->tcd_daemon_pages and ->tcd_pages to the ->pc_pages. Otherwise,
* only ->tcd_pages are spilled.
@@ -260,13 +256,6 @@ void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking);
void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking);
-/**
- * trace_buf_type_t, trace_buf_idx_get() and trace_console_buffers[][]
- * are not public libcfs API; they should be defined in
- * platform-specific tracefile include files
- * (see, for example, linux-tracefile.h).
- */
-
extern char *cfs_trace_console_buffers[NR_CPUS][CFS_TCD_TYPE_MAX];
cfs_trace_buf_type_t cfs_trace_buf_idx_get(void);
@@ -279,12 +268,6 @@ cfs_trace_get_console_buffer(void)
return cfs_trace_console_buffers[i][j];
}
-static inline void
-cfs_trace_put_console_buffer(char *buffer)
-{
- put_cpu();
-}
-
static inline struct cfs_trace_cpu_data *
cfs_trace_get_tcd(void)
{
diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c
index e1143a566ac4..60bb88a00b41 100644
--- a/drivers/staging/lustre/lustre/libcfs/workitem.c
+++ b/drivers/staging/lustre/lustre/libcfs/workitem.c
@@ -86,32 +86,20 @@ static struct cfs_workitem_data {
int wi_stopping;
} cfs_wi_data;
-static inline void
-cfs_wi_sched_lock(struct cfs_wi_sched *sched)
-{
- spin_lock(&sched->ws_lock);
-}
-
-static inline void
-cfs_wi_sched_unlock(struct cfs_wi_sched *sched)
-{
- spin_unlock(&sched->ws_lock);
-}
-
static inline int
cfs_wi_sched_cansleep(struct cfs_wi_sched *sched)
{
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
if (sched->ws_stopping) {
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
return 0;
}
if (!list_empty(&sched->ws_runq)) {
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
return 0;
}
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
return 1;
}
@@ -125,7 +113,7 @@ cfs_wi_exit(struct cfs_wi_sched *sched, cfs_workitem_t *wi)
LASSERT(!in_interrupt()); /* because we use plain spinlock */
LASSERT(!sched->ws_stopping);
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
LASSERT(wi->wi_running);
if (wi->wi_scheduled) { /* cancel pending schedules */
@@ -139,7 +127,7 @@ cfs_wi_exit(struct cfs_wi_sched *sched, cfs_workitem_t *wi)
LASSERT(list_empty(&wi->wi_list));
wi->wi_scheduled = 1; /* LBUG future schedule attempts */
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
return;
}
@@ -161,7 +149,7 @@ cfs_wi_deschedule(struct cfs_wi_sched *sched, cfs_workitem_t *wi)
* means the workitem will not be scheduled and will not have
* any race with wi_action.
*/
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
rc = !(wi->wi_running);
@@ -177,7 +165,7 @@ cfs_wi_deschedule(struct cfs_wi_sched *sched, cfs_workitem_t *wi)
LASSERT (list_empty(&wi->wi_list));
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
return rc;
}
EXPORT_SYMBOL(cfs_wi_deschedule);
@@ -195,7 +183,7 @@ cfs_wi_schedule(struct cfs_wi_sched *sched, cfs_workitem_t *wi)
LASSERT(!in_interrupt()); /* because we use plain spinlock */
LASSERT(!sched->ws_stopping);
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
if (!wi->wi_scheduled) {
LASSERT (list_empty(&wi->wi_list));
@@ -211,7 +199,7 @@ cfs_wi_schedule(struct cfs_wi_sched *sched, cfs_workitem_t *wi)
}
LASSERT (!list_empty(&wi->wi_list));
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
return;
}
EXPORT_SYMBOL(cfs_wi_schedule);
@@ -225,7 +213,9 @@ cfs_wi_scheduler (void *arg)
/* CPT affinity scheduler? */
if (sched->ws_cptab != NULL)
- cfs_cpt_bind(sched->ws_cptab, sched->ws_cpt);
+ if (cfs_cpt_bind(sched->ws_cptab, sched->ws_cpt) != 0)
+ CWARN("Failed to bind %s on CPT %d\n",
+ sched->ws_name, sched->ws_cpt);
spin_lock(&cfs_wi_data.wi_glock);
@@ -235,7 +225,7 @@ cfs_wi_scheduler (void *arg)
spin_unlock(&cfs_wi_data.wi_glock);
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
while (!sched->ws_stopping) {
int nloops = 0;
@@ -256,12 +246,12 @@ cfs_wi_scheduler (void *arg)
wi->wi_running = 1;
wi->wi_scheduled = 0;
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
nloops++;
rc = (*wi->wi_action) (wi);
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
if (rc != 0) /* WI should be dead, even be freed! */
continue;
@@ -276,21 +266,21 @@ cfs_wi_scheduler (void *arg)
}
if (!list_empty(&sched->ws_runq)) {
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
/* don't sleep because some workitems still
* expect me to come back soon */
cond_resched();
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
continue;
}
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
rc = wait_event_interruptible_exclusive(sched->ws_waitq,
!cfs_wi_sched_cansleep(sched));
- cfs_wi_sched_lock(sched);
+ spin_lock(&sched->ws_lock);
}
- cfs_wi_sched_unlock(sched);
+ spin_unlock(&sched->ws_lock);
spin_lock(&cfs_wi_data.wi_glock);
sched->ws_nthreads--;
@@ -325,7 +315,7 @@ cfs_wi_sched_destroy(struct cfs_wi_sched *sched)
spin_lock(&cfs_wi_data.wi_glock);
while (sched->ws_nthreads > 0) {
- CDEBUG(IS_PO2(++i) ? D_WARNING : D_NET,
+ CDEBUG(is_power_of_2(++i) ? D_WARNING : D_NET,
"waiting for %d threads of WI sched[%s] to terminate\n",
sched->ws_nthreads, sched->ws_name);
@@ -360,8 +350,8 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab,
if (sched == NULL)
return -ENOMEM;
- strncpy(sched->ws_name, name, CFS_WS_NAME_LEN);
- sched->ws_name[CFS_WS_NAME_LEN - 1] = '\0';
+ strlcpy(sched->ws_name, name, CFS_WS_NAME_LEN);
+
sched->ws_cptab = cptab;
sched->ws_cpt = cpt;
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 80cba0448499..3d6745e63fe3 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 5c9502b5b358..7b355319079c 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -239,12 +239,6 @@ static int ll_dir_filler(void *_hash, struct page *page0)
return rc;
}
-static void ll_check_page(struct inode *dir, struct page *page)
-{
- /* XXX: check page format later */
- SetPageChecked(page);
-}
-
void ll_release_page(struct page *page, int remove)
{
kunmap(page);
@@ -432,7 +426,8 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash,
goto fail;
}
if (!PageChecked(page))
- ll_check_page(dir, page);
+ /* XXX: check page format later */
+ SetPageChecked(page);
if (PageError(page)) {
CERROR("page error: "DFID" at %llu: rc %d\n",
PFID(ll_inode2fid(dir)), hash, -5);
@@ -641,7 +636,7 @@ static int ll_send_mgc_param(struct obd_export *mgc, char *string)
if (!msp)
return -ENOMEM;
- strncpy(msp->mgs_param, string, MGS_PARAM_MAXLEN);
+ strlcpy(msp->mgs_param, string, sizeof(msp->mgs_param));
rc = obd_set_info_async(NULL, mgc, sizeof(KEY_SET_INFO), KEY_SET_INFO,
sizeof(struct mgs_send_param), msp, NULL);
if (rc)
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 31cd6b323a39..c92d58b770ec 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 6102b29dbf30..ee8a1d67d191 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -1285,16 +1285,6 @@ static inline struct ll_file_data *cl_iattr2fd(struct inode *inode,
return LUSTRE_FPRIVATE(attr->ia_file);
}
-static inline void cl_isize_lock(struct inode *inode)
-{
- ll_inode_size_lock(inode);
-}
-
-static inline void cl_isize_unlock(struct inode *inode)
-{
- ll_inode_size_unlock(inode);
-}
-
static inline void cl_isize_write_nolock(struct inode *inode, loff_t kms)
{
LASSERT(mutex_is_locked(&ll_i2info(inode)->lli_size_mutex));
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 4a8c759fef42..1db93af62bad 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c
index 7df978371c9a..bbae95c9feed 100644
--- a/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -27,7 +27,7 @@
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c
index fed50d538a41..420d39123877 100644
--- a/drivers/staging/lustre/lustre/llite/lloop.c
+++ b/drivers/staging/lustre/lustre/llite/lloop.c
@@ -877,6 +877,6 @@ module_exit(lloop_exit);
module_param(max_loop, int, 0444);
MODULE_PARM_DESC(max_loop, "maximum of lloop_device");
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre virtual block device");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index 190fc44114e1..f134ad9d23f0 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index 64db5e86672f..da5f443a0768 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -554,7 +554,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
retval = NULL;
else
retval = dentry;
- goto out;
out:
if (req)
ptlrpc_req_finished(req);
diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c
index f79193fa2fb7..95cdb0c58b04 100644
--- a/drivers/staging/lustre/lustre/llite/rw.c
+++ b/drivers/staging/lustre/lustre/llite/rw.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -880,14 +880,6 @@ static void ras_update_stride_detector(struct ll_readahead_state *ras,
return;
}
-static unsigned long
-stride_page_count(struct ll_readahead_state *ras, unsigned long len)
-{
- return stride_pg_count(ras->ras_stride_offset, ras->ras_stride_length,
- ras->ras_stride_pages, ras->ras_stride_offset,
- len);
-}
-
/* Stride Read-ahead window will be increased inc_len according to
* stride I/O pattern */
static void ras_stride_increase_window(struct ll_readahead_state *ras,
@@ -921,7 +913,9 @@ static void ras_stride_increase_window(struct ll_readahead_state *ras,
window_len += step * ras->ras_stride_length + left;
- if (stride_page_count(ras, window_len) <= ra->ra_max_pages_per_file)
+ if (stride_pg_count(ras->ras_stride_offset, ras->ras_stride_length,
+ ras->ras_stride_pages, ras->ras_stride_offset,
+ window_len) <= ra->ra_max_pages_per_file)
ras->ras_window_len = window_len;
RAS_CDEBUG(ras);
diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c
index 3da4c01e2159..39fa13b74cbd 100644
--- a/drivers/staging/lustre/lustre/llite/rw26.c
+++ b/drivers/staging/lustre/lustre/llite/rw26.c
@@ -298,7 +298,10 @@ ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io,
}
if (likely(do_io)) {
- cl_2queue_add(queue, clp);
+ /*
+ * Add a page to the incoming page list of 2-queue.
+ */
+ cl_page_list_add(&queue->c2_qin, clp);
/*
* Set page clip to tell transfer formation engine
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 18f5f2b7e902..88ffd8e3abdb 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -87,11 +87,6 @@ struct ll_sa_entry {
static unsigned int sai_generation;
static DEFINE_SPINLOCK(sai_generation_lock);
-static inline int ll_sa_entry_unhashed(struct ll_sa_entry *entry)
-{
- return list_empty(&entry->se_hash);
-}
-
/*
* The entry only can be released by the caller, it is necessary to hold lock.
*/
@@ -138,20 +133,6 @@ static inline int agl_should_run(struct ll_statahead_info *sai,
return (inode != NULL && S_ISREG(inode->i_mode) && sai->sai_agl_valid);
}
-static inline struct ll_sa_entry *
-sa_first_received_entry(struct ll_statahead_info *sai)
-{
- return list_entry(sai->sai_entries_received.next,
- struct ll_sa_entry, se_list);
-}
-
-static inline struct ll_inode_info *
-agl_first_entry(struct ll_statahead_info *sai)
-{
- return list_entry(sai->sai_entries_agl.next,
- struct ll_inode_info, lli_agl_list);
-}
-
static inline int sa_sent_full(struct ll_statahead_info *sai)
{
return atomic_read(&sai->sai_cache_count) >= sai->sai_max;
@@ -331,7 +312,7 @@ static void ll_sa_entry_put(struct ll_statahead_info *sai,
LASSERT(list_empty(&entry->se_link));
LASSERT(list_empty(&entry->se_list));
- LASSERT(ll_sa_entry_unhashed(entry));
+ LASSERT(list_empty(&entry->se_hash));
ll_sa_entry_cleanup(sai, entry);
iput(entry->se_inode);
@@ -346,7 +327,7 @@ do_sa_entry_fini(struct ll_statahead_info *sai, struct ll_sa_entry *entry)
{
struct ll_inode_info *lli = ll_i2info(sai->sai_inode);
- LASSERT(!ll_sa_entry_unhashed(entry));
+ LASSERT(!list_empty(&entry->se_hash));
LASSERT(!list_empty(&entry->se_link));
ll_sa_entry_unhash(sai, entry);
@@ -447,7 +428,7 @@ static void ll_agl_add(struct ll_statahead_info *sai,
igrab(inode);
spin_lock(&parent->lli_agl_lock);
- if (agl_list_empty(sai))
+ if (list_empty(&sai->sai_entries_agl))
added = 1;
list_add_tail(&child->lli_agl_list, &sai->sai_entries_agl);
spin_unlock(&parent->lli_agl_lock);
@@ -537,11 +518,11 @@ static void ll_sai_put(struct ll_statahead_info *sai)
do_sa_entry_fini(sai, entry);
LASSERT(list_empty(&sai->sai_entries));
- LASSERT(sa_received_empty(sai));
+ LASSERT(list_empty(&sai->sai_entries_received));
LASSERT(list_empty(&sai->sai_entries_stated));
LASSERT(atomic_read(&sai->sai_cache_count) == 0);
- LASSERT(agl_list_empty(sai));
+ LASSERT(list_empty(&sai->sai_entries_agl));
iput(inode);
kfree(sai);
@@ -621,11 +602,12 @@ static void ll_post_statahead(struct ll_statahead_info *sai)
int rc = 0;
spin_lock(&lli->lli_sa_lock);
- if (unlikely(sa_received_empty(sai))) {
+ if (unlikely(list_empty(&sai->sai_entries_received))) {
spin_unlock(&lli->lli_sa_lock);
return;
}
- entry = sa_first_received_entry(sai);
+ entry = list_entry(sai->sai_entries_received.next,
+ struct ll_sa_entry, se_list);
atomic_inc(&entry->se_refcount);
list_del_init(&entry->se_list);
spin_unlock(&lli->lli_sa_lock);
@@ -756,7 +738,7 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
* for readpage and other tries to enqueue lock on child
* with parent's lock held, for example: unlink. */
entry->se_handle = handle;
- wakeup = sa_received_empty(sai);
+ wakeup = list_empty(&sai->sai_entries_received);
list_add_tail(&entry->se_list,
&sai->sai_entries_received);
}
@@ -973,7 +955,7 @@ static int ll_agl_thread(void *arg)
while (1) {
l_wait_event(thread->t_ctl_waitq,
- !agl_list_empty(sai) ||
+ !list_empty(&sai->sai_entries_agl) ||
!thread_is_running(thread),
&lwi);
@@ -983,8 +965,9 @@ static int ll_agl_thread(void *arg)
spin_lock(&plli->lli_agl_lock);
/* The statahead thread maybe help to process AGL entries,
* so check whether list empty again. */
- if (!agl_list_empty(sai)) {
- clli = agl_first_entry(sai);
+ if (!list_empty(&sai->sai_entries_agl)) {
+ clli = list_entry(sai->sai_entries_agl.next,
+ struct ll_inode_info, lli_agl_list);
list_del_init(&clli->lli_agl_list);
spin_unlock(&plli->lli_agl_lock);
ll_agl_trigger(&clli->lli_vfs_inode, sai);
@@ -995,8 +978,9 @@ static int ll_agl_thread(void *arg)
spin_lock(&plli->lli_agl_lock);
sai->sai_agl_valid = 0;
- while (!agl_list_empty(sai)) {
- clli = agl_first_entry(sai);
+ while (!list_empty(&sai->sai_entries_agl)) {
+ clli = list_entry(sai->sai_entries_agl.next,
+ struct ll_inode_info, lli_agl_list);
list_del_init(&clli->lli_agl_list);
spin_unlock(&plli->lli_agl_lock);
clli->lli_agl_index = 0;
@@ -1136,13 +1120,13 @@ static int ll_statahead_thread(void *arg)
keep_it:
l_wait_event(thread->t_ctl_waitq,
!sa_sent_full(sai) ||
- !sa_received_empty(sai) ||
- !agl_list_empty(sai) ||
+ !list_empty(&sai->sai_entries_received) ||
+ !list_empty(&sai->sai_entries_agl) ||
!thread_is_running(thread),
&lwi);
interpret_it:
- while (!sa_received_empty(sai))
+ while (!list_empty(&sai->sai_entries_received))
ll_post_statahead(sai);
if (unlikely(!thread_is_running(thread))) {
@@ -1156,14 +1140,15 @@ interpret_it:
* to process the AGL entries. */
if (sa_sent_full(sai)) {
spin_lock(&plli->lli_agl_lock);
- while (!agl_list_empty(sai)) {
- clli = agl_first_entry(sai);
+ while (!list_empty(&sai->sai_entries_agl)) {
+ clli = list_entry(sai->sai_entries_agl.next,
+ struct ll_inode_info, lli_agl_list);
list_del_init(&clli->lli_agl_list);
spin_unlock(&plli->lli_agl_lock);
ll_agl_trigger(&clli->lli_vfs_inode,
sai);
- if (!sa_received_empty(sai))
+ if (!list_empty(&sai->sai_entries_received))
goto interpret_it;
if (unlikely(
@@ -1194,12 +1179,12 @@ do_it:
ll_release_page(page, 0);
while (1) {
l_wait_event(thread->t_ctl_waitq,
- !sa_received_empty(sai) ||
+ !list_empty(&sai->sai_entries_received) ||
sai->sai_sent == sai->sai_replied ||
!thread_is_running(thread),
&lwi);
- while (!sa_received_empty(sai))
+ while (!list_empty(&sai->sai_entries_received))
ll_post_statahead(sai);
if (unlikely(!thread_is_running(thread))) {
@@ -1208,14 +1193,15 @@ do_it:
}
if (sai->sai_sent == sai->sai_replied &&
- sa_received_empty(sai))
+ list_empty(&sai->sai_entries_received))
break;
}
spin_lock(&plli->lli_agl_lock);
- while (!agl_list_empty(sai) &&
+ while (!list_empty(&sai->sai_entries_agl) &&
thread_is_running(thread)) {
- clli = agl_first_entry(sai);
+ clli = list_entry(sai->sai_entries_agl.next,
+ struct ll_inode_info, lli_agl_list);
list_del_init(&clli->lli_agl_list);
spin_unlock(&plli->lli_agl_lock);
ll_agl_trigger(&clli->lli_vfs_inode, sai);
@@ -1260,12 +1246,12 @@ out:
}
ll_dir_chain_fini(&chain);
spin_lock(&plli->lli_sa_lock);
- if (!sa_received_empty(sai)) {
+ if (!list_empty(&sai->sai_entries_received)) {
thread_set_flags(thread, SVC_STOPPING);
spin_unlock(&plli->lli_sa_lock);
/* To release the resources held by received entries. */
- while (!sa_received_empty(sai))
+ while (!list_empty(&sai->sai_entries_received))
ll_post_statahead(sai);
spin_lock(&plli->lli_sa_lock);
diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c
index 013136860664..86c371ef71ea 100644
--- a/drivers/staging/lustre/lustre/llite/super25.c
+++ b/drivers/staging/lustre/lustre/llite/super25.c
@@ -106,7 +106,8 @@ static int __init init_lustre_lite(void)
rc = -ENOMEM;
ll_inode_cachep = kmem_cache_create("lustre_inode_cache",
sizeof(struct ll_inode_info),
- 0, SLAB_HWCACHE_ALIGN, NULL);
+ 0, SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT,
+ NULL);
if (ll_inode_cachep == NULL)
goto out_cache;
@@ -205,7 +206,7 @@ static void __exit exit_lustre_lite(void)
kmem_cache_destroy(ll_file_data_slab);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Lite Client File System");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c
index d16d6cfce81a..fdca4ec0555d 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_dev.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h
index b5a6661d47d5..2e39533a45f8 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_internal.h
+++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h
@@ -26,6 +26,8 @@
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2013, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index 37773c181729..f68e972886ca 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -849,7 +849,7 @@ static int vvp_io_read_page(const struct lu_env *env,
* Add page into the queue even when it is marked uptodate above.
* this will unlock it automatically as part of cl_page_list_disown().
*/
- cl_2queue_add(queue, page);
+ cl_page_list_add(&queue->c2_qin, page);
if (sbi->ll_ra_info.ra_max_pages_per_file &&
sbi->ll_ra_info.ra_max_pages)
ll_readahead(env, io, ras,
diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c
index f7b1144aadee..ff0948043c7a 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_lock.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c
@@ -26,6 +26,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2014, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c
index e13afb7e8dca..c82714ea898e 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_object.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_object.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/vvp_page.c b/drivers/staging/lustre/lustre/llite/vvp_page.c
index 92f60c350f35..99c0d7aee921 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_page.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_page.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 660b8ac37ae0..8eb43f192d1f 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -193,7 +193,10 @@ int ll_setxattr_common(struct inode *inode, const char *name,
ll_i2suppgid(inode), &req);
#ifdef CONFIG_FS_POSIX_ACL
if (new_value != NULL)
- lustre_posix_acl_xattr_free(new_value, size);
+ /*
+ * Release the posix ACL space.
+ */
+ kfree(new_value);
if (acl != NULL)
lustre_ext_acl_xattr_free(acl);
#endif
diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c
index e1e599ceb173..d1402762a0b2 100644
--- a/drivers/staging/lustre/lustre/llite/xattr_cache.c
+++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c
@@ -1,6 +1,8 @@
/*
* Copyright 2012 Xyratex Technology Limited
*
+ * Copyright (c) 2013, 2015, Intel Corporation.
+ *
* Author: Andrew Perepechko <Andrew_Perepechko@xyratex.com>
*
*/
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
index eebe45bdceb6..66de27f1d289 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
@@ -27,7 +27,7 @@
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -156,11 +156,11 @@ out:
* IT_OPEN is intended to open (and create, possible) an object. Parent (pid)
* may be split dir.
*/
-int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
- void *lmm, int lmmsize, struct lookup_intent *it,
- int flags, struct ptlrpc_request **reqp,
- ldlm_blocking_callback cb_blocking,
- __u64 extra_lock_flags)
+static int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
+ void *lmm, int lmmsize, struct lookup_intent *it,
+ int flags, struct ptlrpc_request **reqp,
+ ldlm_blocking_callback cb_blocking,
+ __u64 extra_lock_flags)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -239,11 +239,12 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
/*
* Handler for: getattr, lookup and revalidate cases.
*/
-int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
- void *lmm, int lmmsize, struct lookup_intent *it,
- int flags, struct ptlrpc_request **reqp,
- ldlm_blocking_callback cb_blocking,
- __u64 extra_lock_flags)
+static int lmv_intent_lookup(struct obd_export *exp,
+ struct md_op_data *op_data,
+ void *lmm, int lmmsize, struct lookup_intent *it,
+ int flags, struct ptlrpc_request **reqp,
+ ldlm_blocking_callback cb_blocking,
+ __u64 extra_lock_flags)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_internal.h b/drivers/staging/lustre/lustre/lmv/lmv_internal.h
index b808728daee7..eb8e673cbc3f 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_internal.h
+++ b/drivers/staging/lustre/lustre/lmv/lmv_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -56,20 +56,6 @@ int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
ldlm_blocking_callback cb_blocking,
__u64 extra_lock_flags);
-int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
- void *lmm, int lmmsize, struct lookup_intent *it,
- int flags, struct ptlrpc_request **reqp,
- ldlm_blocking_callback cb_blocking,
- __u64 extra_lock_flags);
-
-int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
- void *lmm, int lmmsize, struct lookup_intent *it,
- int flags, struct ptlrpc_request **reqp,
- ldlm_blocking_callback cb_blocking,
- __u64 extra_lock_flags);
-
-int lmv_blocking_ast(struct ldlm_lock *, struct ldlm_lock_desc *,
- void *, int);
int lmv_fld_lookup(struct lmv_obd *lmv, const struct lu_fid *fid, u32 *mds);
int __lmv_fid_alloc(struct lmv_obd *lmv, struct lu_fid *fid, u32 mds);
int lmv_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index 635a93cc94de..bbafe0a710d8 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -2744,55 +2744,55 @@ static int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
}
static struct obd_ops lmv_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_setup = lmv_setup,
- .o_cleanup = lmv_cleanup,
- .o_precleanup = lmv_precleanup,
- .o_process_config = lmv_process_config,
- .o_connect = lmv_connect,
- .o_disconnect = lmv_disconnect,
- .o_statfs = lmv_statfs,
- .o_get_info = lmv_get_info,
- .o_set_info_async = lmv_set_info_async,
- .o_packmd = lmv_packmd,
- .o_unpackmd = lmv_unpackmd,
- .o_notify = lmv_notify,
- .o_get_uuid = lmv_get_uuid,
- .o_iocontrol = lmv_iocontrol,
- .o_quotacheck = lmv_quotacheck,
- .o_quotactl = lmv_quotactl
+ .owner = THIS_MODULE,
+ .setup = lmv_setup,
+ .cleanup = lmv_cleanup,
+ .precleanup = lmv_precleanup,
+ .process_config = lmv_process_config,
+ .connect = lmv_connect,
+ .disconnect = lmv_disconnect,
+ .statfs = lmv_statfs,
+ .get_info = lmv_get_info,
+ .set_info_async = lmv_set_info_async,
+ .packmd = lmv_packmd,
+ .unpackmd = lmv_unpackmd,
+ .notify = lmv_notify,
+ .get_uuid = lmv_get_uuid,
+ .iocontrol = lmv_iocontrol,
+ .quotacheck = lmv_quotacheck,
+ .quotactl = lmv_quotactl
};
static struct md_ops lmv_md_ops = {
- .m_getstatus = lmv_getstatus,
- .m_null_inode = lmv_null_inode,
- .m_find_cbdata = lmv_find_cbdata,
- .m_close = lmv_close,
- .m_create = lmv_create,
- .m_done_writing = lmv_done_writing,
- .m_enqueue = lmv_enqueue,
- .m_getattr = lmv_getattr,
- .m_getxattr = lmv_getxattr,
- .m_getattr_name = lmv_getattr_name,
- .m_intent_lock = lmv_intent_lock,
- .m_link = lmv_link,
- .m_rename = lmv_rename,
- .m_setattr = lmv_setattr,
- .m_setxattr = lmv_setxattr,
- .m_sync = lmv_sync,
- .m_readpage = lmv_readpage,
- .m_unlink = lmv_unlink,
- .m_init_ea_size = lmv_init_ea_size,
- .m_cancel_unused = lmv_cancel_unused,
- .m_set_lock_data = lmv_set_lock_data,
- .m_lock_match = lmv_lock_match,
- .m_get_lustre_md = lmv_get_lustre_md,
- .m_free_lustre_md = lmv_free_lustre_md,
- .m_set_open_replay_data = lmv_set_open_replay_data,
- .m_clear_open_replay_data = lmv_clear_open_replay_data,
- .m_get_remote_perm = lmv_get_remote_perm,
- .m_intent_getattr_async = lmv_intent_getattr_async,
- .m_revalidate_lock = lmv_revalidate_lock
+ .getstatus = lmv_getstatus,
+ .null_inode = lmv_null_inode,
+ .find_cbdata = lmv_find_cbdata,
+ .close = lmv_close,
+ .create = lmv_create,
+ .done_writing = lmv_done_writing,
+ .enqueue = lmv_enqueue,
+ .getattr = lmv_getattr,
+ .getxattr = lmv_getxattr,
+ .getattr_name = lmv_getattr_name,
+ .intent_lock = lmv_intent_lock,
+ .link = lmv_link,
+ .rename = lmv_rename,
+ .setattr = lmv_setattr,
+ .setxattr = lmv_setxattr,
+ .sync = lmv_sync,
+ .readpage = lmv_readpage,
+ .unlink = lmv_unlink,
+ .init_ea_size = lmv_init_ea_size,
+ .cancel_unused = lmv_cancel_unused,
+ .set_lock_data = lmv_set_lock_data,
+ .lock_match = lmv_lock_match,
+ .get_lustre_md = lmv_get_lustre_md,
+ .free_lustre_md = lmv_free_lustre_md,
+ .set_open_replay_data = lmv_set_open_replay_data,
+ .clear_open_replay_data = lmv_clear_open_replay_data,
+ .get_remote_perm = lmv_get_remote_perm,
+ .intent_getattr_async = lmv_intent_getattr_async,
+ .revalidate_lock = lmv_revalidate_lock
};
static int __init lmv_init(void)
@@ -2812,7 +2812,7 @@ static void lmv_exit(void)
class_unregister_type(LUSTRE_LMV_NAME);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Logical Metadata Volume OBD driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
index 1c0fe65243e1..66a2492c1cc3 100644
--- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
+++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c
index 2e8b566458f6..3733fdc88c8c 100644
--- a/drivers/staging/lustre/lustre/lov/lov_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lov_dev.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c
index 34c1346f0dc7..b3c9c85aab9d 100644
--- a/drivers/staging/lustre/lustre/lov/lov_ea.c
+++ b/drivers/staging/lustre/lustre/lov/lov_ea.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h
index 515a5c147827..2d00bad58e35 100644
--- a/drivers/staging/lustre/lustre/lov/lov_internal.h
+++ b/drivers/staging/lustre/lustre/lov/lov_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -151,23 +151,10 @@ int lov_stripe_number(struct lov_stripe_md *lsm, u64 lov_off);
/* lov_qos.c */
#define LOV_USES_ASSIGNED_STRIPE 0
#define LOV_USES_DEFAULT_STRIPE 1
-int qos_add_tgt(struct obd_device *obd, __u32 index);
-int qos_del_tgt(struct obd_device *obd, struct lov_tgt_desc *tgt);
-void qos_shrink_lsm(struct lov_request_set *set);
-int qos_prep_create(struct obd_export *exp, struct lov_request_set *set);
-void qos_update(struct lov_obd *lov);
-void qos_statfs_done(struct lov_obd *lov);
-void qos_statfs_update(struct obd_device *obd, __u64 max_age, int wait);
-int qos_remedy_create(struct lov_request_set *set, struct lov_request *req);
/* lov_request.c */
-void lov_set_add_req(struct lov_request *req, struct lov_request_set *set);
-int lov_set_finished(struct lov_request_set *set, int idempotent);
-void lov_update_set(struct lov_request_set *set,
- struct lov_request *req, int rc);
int lov_update_common_set(struct lov_request_set *set,
struct lov_request *req, int rc);
-int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx);
int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set **reqset);
int lov_fini_getattr_set(struct lov_request_set *set);
@@ -184,8 +171,6 @@ int lov_update_setattr_set(struct lov_request_set *set,
int lov_fini_setattr_set(struct lov_request_set *set);
int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo,
struct lov_request_set **reqset);
-void lov_update_statfs(struct obd_statfs *osfs, struct obd_statfs *lov_sfs,
- int success);
int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs,
int success);
int lov_fini_statfs_set(struct lov_request_set *set);
diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c
index 5e6228b9ca01..93fe69eb2560 100644
--- a/drivers/staging/lustre/lustre/lov/lov_io.c
+++ b/drivers/staging/lustre/lustre/lov/lov_io.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c
index dd1cf3d2d039..97115bec7cca 100644
--- a/drivers/staging/lustre/lustre/lov/lov_merge.c
+++ b/drivers/staging/lustre/lustre/lov/lov_merge.c
@@ -27,7 +27,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c
index 7abe484c07c0..6c2bdfe9cdcf 100644
--- a/drivers/staging/lustre/lustre/lov/lov_obd.c
+++ b/drivers/staging/lustre/lustre/lov/lov_obd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -2277,35 +2277,35 @@ out:
}
static struct obd_ops lov_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_setup = lov_setup,
- .o_precleanup = lov_precleanup,
- .o_cleanup = lov_cleanup,
- /*.o_process_config = lov_process_config,*/
- .o_connect = lov_connect,
- .o_disconnect = lov_disconnect,
- .o_statfs = lov_statfs,
- .o_statfs_async = lov_statfs_async,
- .o_packmd = lov_packmd,
- .o_unpackmd = lov_unpackmd,
- .o_create = lov_create,
- .o_destroy = lov_destroy,
- .o_getattr_async = lov_getattr_async,
- .o_setattr_async = lov_setattr_async,
- .o_adjust_kms = lov_adjust_kms,
- .o_find_cbdata = lov_find_cbdata,
- .o_iocontrol = lov_iocontrol,
- .o_get_info = lov_get_info,
- .o_set_info_async = lov_set_info_async,
- .o_notify = lov_notify,
- .o_pool_new = lov_pool_new,
- .o_pool_rem = lov_pool_remove,
- .o_pool_add = lov_pool_add,
- .o_pool_del = lov_pool_del,
- .o_getref = lov_getref,
- .o_putref = lov_putref,
- .o_quotactl = lov_quotactl,
- .o_quotacheck = lov_quotacheck,
+ .owner = THIS_MODULE,
+ .setup = lov_setup,
+ .precleanup = lov_precleanup,
+ .cleanup = lov_cleanup,
+ /*.process_config = lov_process_config,*/
+ .connect = lov_connect,
+ .disconnect = lov_disconnect,
+ .statfs = lov_statfs,
+ .statfs_async = lov_statfs_async,
+ .packmd = lov_packmd,
+ .unpackmd = lov_unpackmd,
+ .create = lov_create,
+ .destroy = lov_destroy,
+ .getattr_async = lov_getattr_async,
+ .setattr_async = lov_setattr_async,
+ .adjust_kms = lov_adjust_kms,
+ .find_cbdata = lov_find_cbdata,
+ .iocontrol = lov_iocontrol,
+ .get_info = lov_get_info,
+ .set_info_async = lov_set_info_async,
+ .notify = lov_notify,
+ .pool_new = lov_pool_new,
+ .pool_rem = lov_pool_remove,
+ .pool_add = lov_pool_add,
+ .pool_del = lov_pool_del,
+ .getref = lov_getref,
+ .putref = lov_putref,
+ .quotactl = lov_quotactl,
+ .quotacheck = lov_quotacheck,
};
struct kmem_cache *lov_oinfo_slab;
@@ -2352,7 +2352,7 @@ static void /*__exit*/ lov_exit(void)
lu_kmem_fini(lov_caches);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Logical Object Volume OBD driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(LUSTRE_VERSION_STRING);
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c
index c7ff817bb6fb..3b79ebc8eccf 100644
--- a/drivers/staging/lustre/lustre/lov/lov_object.c
+++ b/drivers/staging/lustre/lustre/lov/lov_object.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c
index 9c8c77c05a8a..aa520aa76e09 100644
--- a/drivers/staging/lustre/lustre/lov/lov_offset.c
+++ b/drivers/staging/lustre/lustre/lov/lov_offset.c
@@ -27,7 +27,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index 2fb1e974cc70..6b2d1007192b 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -258,22 +258,9 @@ static int lov_verify_lmm(void *lmm, int lmm_bytes, __u16 *stripe_count)
int rc;
if (lsm_op_find(le32_to_cpu(*(__u32 *)lmm)) == NULL) {
- char *buffer;
- int sz;
-
CERROR("bad disk LOV MAGIC: 0x%08X; dumping LMM (size=%d):\n",
le32_to_cpu(*(__u32 *)lmm), lmm_bytes);
- sz = lmm_bytes * 2 + 1;
- buffer = libcfs_kvzalloc(sz, GFP_NOFS);
- if (buffer != NULL) {
- int i;
-
- for (i = 0; i < lmm_bytes; i++)
- sprintf(buffer+2*i, "%.2X", ((char *)lmm)[i]);
- buffer[sz - 1] = '\0';
- CERROR("%s\n", buffer);
- kvfree(buffer);
- }
+ CERROR("%*phN\n", lmm_bytes, lmm);
return -EINVAL;
}
rc = lsm_op_find(le32_to_cpu(*(__u32 *)lmm))->lsm_lmm_verify(lmm,
diff --git a/drivers/staging/lustre/lustre/lov/lov_page.c b/drivers/staging/lustre/lustre/lov/lov_page.c
index 463cadbd9d40..037ae91b74e7 100644
--- a/drivers/staging/lustre/lustre/lov/lov_page.c
+++ b/drivers/staging/lustre/lustre/lov/lov_page.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c
index b03827ef6514..b43ce6cd64c2 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pool.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pool.c
@@ -412,8 +412,7 @@ int lov_pool_new(struct obd_device *obd, char *poolname)
if (!new_pool)
return -ENOMEM;
- strncpy(new_pool->pool_name, poolname, LOV_MAXPOOLNAME);
- new_pool->pool_name[LOV_MAXPOOLNAME] = '\0';
+ strlcpy(new_pool->pool_name, poolname, sizeof(new_pool->pool_name));
new_pool->pool_lobd = obd;
/* ref count init to 1 because when created a pool is always used
* up to deletion
diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c
index 1a150c26798d..42deda71f577 100644
--- a/drivers/staging/lustre/lustre/lov/lov_request.c
+++ b/drivers/staging/lustre/lustre/lov/lov_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -74,7 +74,7 @@ void lov_finish_set(struct lov_request_set *set)
kfree(set);
}
-int lov_set_finished(struct lov_request_set *set, int idempotent)
+static int lov_set_finished(struct lov_request_set *set, int idempotent)
{
int completes = atomic_read(&set->set_completes);
@@ -89,8 +89,8 @@ int lov_set_finished(struct lov_request_set *set, int idempotent)
return 0;
}
-void lov_update_set(struct lov_request_set *set,
- struct lov_request *req, int rc)
+static void lov_update_set(struct lov_request_set *set,
+ struct lov_request *req, int rc)
{
req->rq_complete = 1;
req->rq_rc = rc;
@@ -118,7 +118,8 @@ int lov_update_common_set(struct lov_request_set *set,
return rc;
}
-void lov_set_add_req(struct lov_request *req, struct lov_request_set *set)
+static void lov_set_add_req(struct lov_request *req,
+ struct lov_request_set *set)
{
list_add_tail(&req->rq_link, &set->set_list);
set->set_count++;
@@ -144,7 +145,7 @@ static int lov_check_set(struct lov_obd *lov, int idx)
* If the OSC has not yet had a chance to connect to the OST the first time,
* wait once for it to connect instead of returning an error.
*/
-int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx)
+static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx)
{
wait_queue_head_t waitq;
struct l_wait_info lwi;
@@ -591,8 +592,9 @@ int lov_fini_statfs_set(struct lov_request_set *set)
return rc;
}
-void lov_update_statfs(struct obd_statfs *osfs, struct obd_statfs *lov_sfs,
- int success)
+static void lov_update_statfs(struct obd_statfs *osfs,
+ struct obd_statfs *lov_sfs,
+ int success)
{
int shift = 0, quit = 0;
__u64 tmp;
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
index 8bc04c8d3d60..f1795c3e2db5 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
@@ -26,6 +26,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2013, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_object.c b/drivers/staging/lustre/lustre/lov/lovsub_object.c
index d775e28d4097..5ba5ee1b8681 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_object.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_object.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c
index a0be15c6b55a..337241d84980 100644
--- a/drivers/staging/lustre/lustre/lov/lproc_lov.c
+++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
index 1c95f87a0e2a..38f267a60f59 100644
--- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
+++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -82,82 +82,6 @@ static ssize_t max_rpcs_in_flight_store(struct kobject *kobj,
}
LUSTRE_RW_ATTR(max_rpcs_in_flight);
-static int mdc_kuc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, NULL, inode->i_private);
-}
-
-/* temporary for testing */
-static ssize_t mdc_kuc_write(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *off)
-{
- struct obd_device *obd =
- ((struct seq_file *)file->private_data)->private;
- struct kuc_hdr *lh;
- struct hsm_action_list *hal;
- struct hsm_action_item *hai;
- int len;
- int fd, rc;
-
- rc = lprocfs_write_helper(buffer, count, &fd);
- if (rc)
- return rc;
-
- if (fd < 0)
- return -ERANGE;
- CWARN("message to fd %d\n", fd);
-
- len = sizeof(*lh) + sizeof(*hal) + MTI_NAME_MAXLEN +
- /* for mockup below */ 2 * cfs_size_round(sizeof(*hai));
-
- lh = kzalloc(len, GFP_NOFS);
- if (!lh)
- return -ENOMEM;
-
- lh->kuc_magic = KUC_MAGIC;
- lh->kuc_transport = KUC_TRANSPORT_HSM;
- lh->kuc_msgtype = HMT_ACTION_LIST;
- lh->kuc_msglen = len;
-
- hal = (struct hsm_action_list *)(lh + 1);
- hal->hal_version = HAL_VERSION;
- hal->hal_archive_id = 1;
- hal->hal_flags = 0;
- obd_uuid2fsname(hal->hal_fsname, obd->obd_name, MTI_NAME_MAXLEN);
-
- /* mock up an action list */
- hal->hal_count = 2;
- hai = hai_zero(hal);
- hai->hai_action = HSMA_ARCHIVE;
- hai->hai_fid.f_oid = 5;
- hai->hai_len = sizeof(*hai);
- hai = hai_next(hai);
- hai->hai_action = HSMA_RESTORE;
- hai->hai_fid.f_oid = 10;
- hai->hai_len = sizeof(*hai);
-
- /* This works for either broadcast or unicast to a single fd */
- if (fd == 0) {
- rc = libcfs_kkuc_group_put(KUC_GRP_HSM, lh);
- } else {
- struct file *fp = fget(fd);
-
- rc = libcfs_kkuc_msg_put(fp, lh);
- fput(fp);
- }
- kfree(lh);
- if (rc < 0)
- return rc;
- return count;
-}
-
-static struct file_operations mdc_kuc_fops = {
- .open = mdc_kuc_open,
- .write = mdc_kuc_write,
- .release = single_release,
-};
-
LPROC_SEQ_FOPS_WR_ONLY(mdc, ping);
LPROC_SEQ_FOPS_RO_TYPE(mdc, connect_flags);
@@ -196,7 +120,6 @@ static struct lprocfs_vars lprocfs_mdc_obd_vars[] = {
{ "timeouts", &mdc_timeouts_fops, NULL, 0 },
{ "import", &mdc_import_fops, NULL, 0 },
{ "state", &mdc_state_fops, NULL, 0 },
- { "hsm_nl", &mdc_kuc_fops, NULL, 0200 },
{ "pinger_recov", &mdc_pinger_recov_fops, NULL, 0 },
{ NULL }
};
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h
index 29b46f754726..3d2997a161b6 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h
+++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Intel Corporation.
+ * Copyright (c) 2011, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -44,7 +44,6 @@ void lprocfs_mdc_init_vars(struct lprocfs_static_vars *lvars);
void mdc_pack_body(struct ptlrpc_request *req, const struct lu_fid *fid,
__u64 valid, int ea_size, __u32 suppgid, int flags);
-int mdc_pack_req(struct ptlrpc_request *req, int version, int opc);
void mdc_is_subdir_pack(struct ptlrpc_request *req, const struct lu_fid *pfid,
const struct lu_fid *cfid, int flags);
void mdc_swap_layouts_pack(struct ptlrpc_request *req,
@@ -62,7 +61,6 @@ void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
__u32 mode, __u64 rdev, __u64 flags, const void *data,
int datalen);
void mdc_unlink_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
-void mdc_getxattr_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
void mdc_link_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
void mdc_rename_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
const char *old, int oldlen, const char *new, int newlen);
@@ -97,25 +95,12 @@ int mdc_resource_get_unused(struct obd_export *exp, const struct lu_fid *fid,
/* mdc/mdc_request.c */
int mdc_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
struct md_op_data *op_data);
-
-int mdc_open(struct obd_export *exp, u64 ino, int type, int flags,
- struct lov_mds_md *lmm, int lmm_size, struct lustre_handle *fh,
- struct ptlrpc_request **);
-
struct obd_client_handle;
-int mdc_get_lustre_md(struct obd_export *md_exp, struct ptlrpc_request *req,
- struct obd_export *dt_exp, struct obd_export *lmv_exp,
- struct lustre_md *md);
-
-int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md);
-
int mdc_set_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och,
struct lookup_intent *it);
-int mdc_clear_open_replay_data(struct obd_export *exp,
- struct obd_client_handle *och);
void mdc_commit_open(struct ptlrpc_request *req);
void mdc_replay_open(struct ptlrpc_request *req);
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
index 227fc9ee0dcf..7218532ffea3 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index d4bf34b61f3a..ef9a1e124ea4 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
index c87c7d8efa07..ac7695a10753 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 16a5a10d371e..57e0fc1e8549 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -447,9 +447,11 @@ static int mdc_unpack_acl(struct ptlrpc_request *req, struct lustre_md *md)
#define mdc_unpack_acl(req, md) 0
#endif
-int mdc_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
- struct obd_export *dt_exp, struct obd_export *md_exp,
- struct lustre_md *md)
+static int mdc_get_lustre_md(struct obd_export *exp,
+ struct ptlrpc_request *req,
+ struct obd_export *dt_exp,
+ struct obd_export *md_exp,
+ struct lustre_md *md)
{
struct req_capsule *pill = &req->rq_pill;
int rc;
@@ -573,7 +575,7 @@ out:
return rc;
}
-int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
+static int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
{
return 0;
}
@@ -737,8 +739,8 @@ static void mdc_free_open(struct md_open_data *mod)
ptlrpc_request_committed(mod->mod_close_req, committed);
}
-int mdc_clear_open_replay_data(struct obd_export *exp,
- struct obd_client_handle *och)
+static int mdc_clear_open_replay_data(struct obd_export *exp,
+ struct obd_client_handle *och)
{
struct md_open_data *mod = och->och_mod;
@@ -1179,7 +1181,6 @@ static int mdc_ioc_hsm_progress(struct obd_export *exp,
ptlrpc_request_set_replen(req);
rc = mdc_queue_wait(req);
- goto out;
out:
ptlrpc_req_finished(req);
return rc;
@@ -1214,7 +1215,6 @@ static int mdc_ioc_hsm_ct_register(struct obd_import *imp, __u32 archives)
ptlrpc_request_set_replen(req);
rc = mdc_queue_wait(req);
- goto out;
out:
ptlrpc_req_finished(req);
return rc;
@@ -1280,7 +1280,6 @@ static int mdc_ioc_hsm_ct_unregister(struct obd_import *imp)
ptlrpc_request_set_replen(req);
rc = mdc_queue_wait(req);
- goto out;
out:
ptlrpc_req_finished(req);
return rc;
@@ -1360,8 +1359,6 @@ static int mdc_ioc_hsm_state_set(struct obd_export *exp,
ptlrpc_request_set_replen(req);
rc = mdc_queue_wait(req);
- goto out;
-
out:
ptlrpc_req_finished(req);
return rc;
@@ -1425,8 +1422,6 @@ static int mdc_ioc_hsm_request(struct obd_export *exp,
ptlrpc_request_set_replen(req);
rc = mdc_queue_wait(req);
- goto out;
-
out:
ptlrpc_req_finished(req);
return rc;
@@ -2035,17 +2030,6 @@ static int mdc_hsm_ct_reregister(__u32 data, void *cb_arg)
return ((rc != 0) && (rc != -EEXIST)) ? rc : 0;
}
-/**
- * Re-establish all kuc contexts with MDT
- * after MDT shutdown/recovery.
- */
-static int mdc_kuc_reregister(struct obd_import *imp)
-{
- /* re-register HSM agents */
- return libcfs_kkuc_group_foreach(KUC_GRP_HSM, mdc_hsm_ct_reregister,
- (void *)imp);
-}
-
static int mdc_set_info_async(const struct lu_env *env,
struct obd_export *exp,
u32 keylen, void *key,
@@ -2208,7 +2192,10 @@ static int mdc_import_event(struct obd_device *obd, struct obd_import *imp,
rc = obd_notify_observer(obd, obd, OBD_NOTIFY_ACTIVE, NULL);
/* redo the kuc registration after reconnecting */
if (rc == 0)
- rc = mdc_kuc_reregister(imp);
+ /* re-register HSM agents */
+ rc = libcfs_kkuc_group_foreach(KUC_GRP_HSM,
+ mdc_hsm_ct_reregister,
+ (void *)imp);
break;
case IMP_EVENT_OCD:
rc = obd_notify_observer(obd, obd, OBD_NOTIFY_OCD, NULL);
@@ -2460,59 +2447,59 @@ static int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
}
static struct obd_ops mdc_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_setup = mdc_setup,
- .o_precleanup = mdc_precleanup,
- .o_cleanup = mdc_cleanup,
- .o_add_conn = client_import_add_conn,
- .o_del_conn = client_import_del_conn,
- .o_connect = client_connect_import,
- .o_disconnect = client_disconnect_export,
- .o_iocontrol = mdc_iocontrol,
- .o_set_info_async = mdc_set_info_async,
- .o_statfs = mdc_statfs,
- .o_fid_init = client_fid_init,
- .o_fid_fini = client_fid_fini,
- .o_fid_alloc = mdc_fid_alloc,
- .o_import_event = mdc_import_event,
- .o_get_info = mdc_get_info,
- .o_process_config = mdc_process_config,
- .o_get_uuid = mdc_get_uuid,
- .o_quotactl = mdc_quotactl,
- .o_quotacheck = mdc_quotacheck
+ .owner = THIS_MODULE,
+ .setup = mdc_setup,
+ .precleanup = mdc_precleanup,
+ .cleanup = mdc_cleanup,
+ .add_conn = client_import_add_conn,
+ .del_conn = client_import_del_conn,
+ .connect = client_connect_import,
+ .disconnect = client_disconnect_export,
+ .iocontrol = mdc_iocontrol,
+ .set_info_async = mdc_set_info_async,
+ .statfs = mdc_statfs,
+ .fid_init = client_fid_init,
+ .fid_fini = client_fid_fini,
+ .fid_alloc = mdc_fid_alloc,
+ .import_event = mdc_import_event,
+ .get_info = mdc_get_info,
+ .process_config = mdc_process_config,
+ .get_uuid = mdc_get_uuid,
+ .quotactl = mdc_quotactl,
+ .quotacheck = mdc_quotacheck
};
static struct md_ops mdc_md_ops = {
- .m_getstatus = mdc_getstatus,
- .m_null_inode = mdc_null_inode,
- .m_find_cbdata = mdc_find_cbdata,
- .m_close = mdc_close,
- .m_create = mdc_create,
- .m_done_writing = mdc_done_writing,
- .m_enqueue = mdc_enqueue,
- .m_getattr = mdc_getattr,
- .m_getattr_name = mdc_getattr_name,
- .m_intent_lock = mdc_intent_lock,
- .m_link = mdc_link,
- .m_is_subdir = mdc_is_subdir,
- .m_rename = mdc_rename,
- .m_setattr = mdc_setattr,
- .m_setxattr = mdc_setxattr,
- .m_getxattr = mdc_getxattr,
- .m_sync = mdc_sync,
- .m_readpage = mdc_readpage,
- .m_unlink = mdc_unlink,
- .m_cancel_unused = mdc_cancel_unused,
- .m_init_ea_size = mdc_init_ea_size,
- .m_set_lock_data = mdc_set_lock_data,
- .m_lock_match = mdc_lock_match,
- .m_get_lustre_md = mdc_get_lustre_md,
- .m_free_lustre_md = mdc_free_lustre_md,
- .m_set_open_replay_data = mdc_set_open_replay_data,
- .m_clear_open_replay_data = mdc_clear_open_replay_data,
- .m_get_remote_perm = mdc_get_remote_perm,
- .m_intent_getattr_async = mdc_intent_getattr_async,
- .m_revalidate_lock = mdc_revalidate_lock
+ .getstatus = mdc_getstatus,
+ .null_inode = mdc_null_inode,
+ .find_cbdata = mdc_find_cbdata,
+ .close = mdc_close,
+ .create = mdc_create,
+ .done_writing = mdc_done_writing,
+ .enqueue = mdc_enqueue,
+ .getattr = mdc_getattr,
+ .getattr_name = mdc_getattr_name,
+ .intent_lock = mdc_intent_lock,
+ .link = mdc_link,
+ .is_subdir = mdc_is_subdir,
+ .rename = mdc_rename,
+ .setattr = mdc_setattr,
+ .setxattr = mdc_setxattr,
+ .getxattr = mdc_getxattr,
+ .sync = mdc_sync,
+ .readpage = mdc_readpage,
+ .unlink = mdc_unlink,
+ .cancel_unused = mdc_cancel_unused,
+ .init_ea_size = mdc_init_ea_size,
+ .set_lock_data = mdc_set_lock_data,
+ .lock_match = mdc_lock_match,
+ .get_lustre_md = mdc_get_lustre_md,
+ .free_lustre_md = mdc_free_lustre_md,
+ .set_open_replay_data = mdc_set_open_replay_data,
+ .clear_open_replay_data = mdc_clear_open_replay_data,
+ .get_remote_perm = mdc_get_remote_perm,
+ .intent_getattr_async = mdc_intent_getattr_async,
+ .revalidate_lock = mdc_revalidate_lock
};
static int __init mdc_init(void)
@@ -2530,7 +2517,7 @@ static void /*__exit*/ mdc_exit(void)
class_unregister_type(LUSTRE_MDC_NAME);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Metadata Client");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index 5f53f3b7ceff..ab4800c20a95 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -463,7 +463,7 @@ int lprocfs_mgc_rd_ir_state(struct seq_file *m, void *data)
}
spin_unlock(&config_list_lock);
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
@@ -1293,7 +1293,7 @@ static int mgc_process_recover_log(struct obd_device *obd,
struct page **pages;
int nrpages;
bool eof = true;
- bool mne_swab = false;
+ bool mne_swab;
int i;
int ealen;
int rc;
@@ -1698,20 +1698,20 @@ out:
}
static struct obd_ops mgc_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_setup = mgc_setup,
- .o_precleanup = mgc_precleanup,
- .o_cleanup = mgc_cleanup,
- .o_add_conn = client_import_add_conn,
- .o_del_conn = client_import_del_conn,
- .o_connect = client_connect_import,
- .o_disconnect = client_disconnect_export,
- /* .o_enqueue = mgc_enqueue, */
- /* .o_iocontrol = mgc_iocontrol, */
- .o_set_info_async = mgc_set_info_async,
- .o_get_info = mgc_get_info,
- .o_import_event = mgc_import_event,
- .o_process_config = mgc_process_config,
+ .owner = THIS_MODULE,
+ .setup = mgc_setup,
+ .precleanup = mgc_precleanup,
+ .cleanup = mgc_cleanup,
+ .add_conn = client_import_add_conn,
+ .del_conn = client_import_del_conn,
+ .connect = client_connect_import,
+ .disconnect = client_disconnect_export,
+ /* .enqueue = mgc_enqueue, */
+ /* .iocontrol = mgc_iocontrol, */
+ .set_info_async = mgc_set_info_async,
+ .get_info = mgc_get_info,
+ .import_event = mgc_import_event,
+ .process_config = mgc_process_config,
};
static int __init mgc_init(void)
@@ -1725,7 +1725,7 @@ static void /*__exit*/ mgc_exit(void)
class_unregister_type(LUSTRE_MGC_NAME);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Management Client");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c
index 2e20cf635b27..49ba8851c8ac 100644
--- a/drivers/staging/lustre/lustre/obdclass/acl.c
+++ b/drivers/staging/lustre/lustre/obdclass/acl.c
@@ -236,15 +236,6 @@ _out:
EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
/*
- * Release the posix ACL space.
- */
-void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
-{
- kfree(header);
-}
-EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
-
-/*
* Release the extended ACL space.
*/
void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c
index e67cea758405..63246ba36798 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_io.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -236,16 +236,11 @@ int cl_io_rw_init(const struct lu_env *env, struct cl_io *io,
}
EXPORT_SYMBOL(cl_io_rw_init);
-static inline const struct lu_fid *
-cl_lock_descr_fid(const struct cl_lock_descr *descr)
-{
- return lu_object_fid(&descr->cld_obj->co_lu);
-}
-
static int cl_lock_descr_sort(const struct cl_lock_descr *d0,
const struct cl_lock_descr *d1)
{
- return lu_fid_cmp(cl_lock_descr_fid(d0), cl_lock_descr_fid(d1)) ?:
+ return lu_fid_cmp(lu_object_fid(&d0->cld_obj->co_lu),
+ lu_object_fid(&d1->cld_obj->co_lu)) ?:
__diff_normalize(d0->cld_start, d1->cld_start);
}
@@ -254,7 +249,8 @@ static int cl_lock_descr_cmp(const struct cl_lock_descr *d0,
{
int ret;
- ret = lu_fid_cmp(cl_lock_descr_fid(d0), cl_lock_descr_fid(d1));
+ ret = lu_fid_cmp(lu_object_fid(&d0->cld_obj->co_lu),
+ lu_object_fid(&d1->cld_obj->co_lu));
if (ret)
return ret;
if (d0->cld_end < d1->cld_start)
@@ -1216,15 +1212,6 @@ void cl_2queue_init(struct cl_2queue *queue)
EXPORT_SYMBOL(cl_2queue_init);
/**
- * Add a page to the incoming page list of 2-queue.
- */
-void cl_2queue_add(struct cl_2queue *queue, struct cl_page *page)
-{
- cl_page_list_add(&queue->c2_qin, page);
-}
-EXPORT_SYMBOL(cl_2queue_add);
-
-/**
* Disown pages in both lists of a 2-queue.
*/
void cl_2queue_disown(const struct lu_env *env,
@@ -1262,7 +1249,10 @@ EXPORT_SYMBOL(cl_2queue_fini);
void cl_2queue_init_page(struct cl_2queue *queue, struct cl_page *page)
{
cl_2queue_init(queue);
- cl_2queue_add(queue, page);
+ /*
+ * Add a page to the incoming page list of 2-queue.
+ */
+ cl_page_list_add(&queue->c2_qin, page);
}
EXPORT_SYMBOL(cl_2queue_init_page);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
index 5621bebf33a9..1836dc01499a 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
@@ -687,7 +687,7 @@ EXPORT_SYMBOL(cl_lock_mutex_get);
*
* \see cl_lock_mutex_get()
*/
-int cl_lock_mutex_try(const struct lu_env *env, struct cl_lock *lock)
+static int cl_lock_mutex_try(const struct lu_env *env, struct cl_lock *lock)
{
int result;
@@ -705,7 +705,6 @@ int cl_lock_mutex_try(const struct lu_env *env, struct cl_lock *lock)
result = -EBUSY;
return result;
}
-EXPORT_SYMBOL(cl_lock_mutex_try);
/**
{* Unlocks cl_lock object.
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index a1a6024220ff..57c8d5412bbd 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -704,7 +704,7 @@ static inline struct cl_env *cl_env_container(struct lu_env *env)
return container_of(env, struct cl_env, ce_lu);
}
-struct lu_env *cl_env_peek(int *refcheck)
+static struct lu_env *cl_env_peek(int *refcheck)
{
struct lu_env *env;
struct cl_env *cle;
@@ -724,7 +724,6 @@ struct lu_env *cl_env_peek(int *refcheck)
CDEBUG(D_OTHER, "%d@%p\n", cle ? cle->ce_ref : 0, cle);
return env;
}
-EXPORT_SYMBOL(cl_env_peek);
/**
* Returns lu_env: if there already is an environment associated with the
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c
index 2f569edd0811..61f28ebfc058 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_page.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c
index 3e9c24684690..0975e443057c 100644
--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c
@@ -27,7 +27,7 @@
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -576,7 +576,7 @@ static void cleanup_obdclass(void)
obd_zombie_impexp_stop();
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Class Driver Build Version: " BUILD_VERSION);
MODULE_LICENSE("GPL");
MODULE_VERSION(LUSTRE_VERSION_STRING);
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index 6477aeb88028..228c44c37c4a 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -27,7 +27,7 @@
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -132,7 +132,7 @@ static struct obd_type *class_get_type(const char *name)
if (type) {
spin_lock(&type->obd_type_lock);
type->typ_refcnt++;
- try_module_get(type->typ_dt_ops->o_owner);
+ try_module_get(type->typ_dt_ops->owner);
spin_unlock(&type->obd_type_lock);
}
return type;
@@ -143,7 +143,7 @@ void class_put_type(struct obd_type *type)
LASSERT(type);
spin_lock(&type->obd_type_lock);
type->typ_refcnt--;
- module_put(type->typ_dt_ops->o_owner);
+ module_put(type->typ_dt_ops->owner);
spin_unlock(&type->obd_type_lock);
}
EXPORT_SYMBOL(class_put_type);
@@ -155,7 +155,7 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
struct lu_device_type *ldt)
{
struct obd_type *type;
- int rc = 0;
+ int rc;
/* sanity check */
LASSERT(strnlen(name, CLASS_MAX_NAME) < CLASS_MAX_NAME);
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
index 518288df4d53..42fc26f4ae25 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
@@ -27,7 +27,7 @@
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c
index 7cb55ef79737..f956d7ed6785 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
index c442cae5fd37..0f05e9c4a5b2 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_internal.h b/drivers/staging/lustre/lustre/obdclass/llog_internal.h
index b9fe4b01c690..7fb48dda355e 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_internal.h
+++ b/drivers/staging/lustre/lustre/obdclass/llog_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
index 3900b9d4007e..9bc51998c05c 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
index 9354f75b5cab..3aa7393b20c3 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
@@ -27,7 +27,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index 333ac7d269b7..51fe15f5d687 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -502,7 +502,7 @@ int lprocfs_rd_server_uuid(struct seq_file *m, void *data)
obd2cli_tgt(obd), imp_state_name,
imp->imp_deactive ? "\tDEACTIVATED" : "");
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
@@ -526,7 +526,7 @@ int lprocfs_rd_conn_uuid(struct seq_file *m, void *data)
else
seq_puts(m, "<none>\n");
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
@@ -665,15 +665,18 @@ int lprocfs_rd_import(struct seq_file *m, void *data)
seq_printf(m, "%s%s", j ? ", " : "", nidstr);
j++;
}
- libcfs_nid2str_r(imp->imp_connection->c_peer.nid,
- nidstr, sizeof(nidstr));
+ if (imp->imp_connection != NULL)
+ libcfs_nid2str_r(imp->imp_connection->c_peer.nid,
+ nidstr, sizeof(nidstr));
+ else
+ strncpy(nidstr, "<none>", sizeof(nidstr));
seq_printf(m,
"]\n"
" current_connection: %s\n"
" connection_attempts: %u\n"
" generation: %u\n"
" in-progress_invalidations: %u\n",
- imp->imp_connection == NULL ? "<none>" : nidstr,
+ nidstr,
imp->imp_conn_cnt,
imp->imp_generation,
atomic_read(&imp->imp_inval_count));
@@ -765,7 +768,7 @@ int lprocfs_rd_import(struct seq_file *m, void *data)
}
out_climp:
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
EXPORT_SYMBOL(lprocfs_rd_import);
@@ -796,7 +799,7 @@ int lprocfs_rd_state(struct seq_file *m, void *data)
ptlrpc_import_state_name(ish->ish_state));
}
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
EXPORT_SYMBOL(lprocfs_rd_state);
@@ -857,7 +860,7 @@ int lprocfs_rd_timeouts(struct seq_file *m, void *data)
lprocfs_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
}
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
EXPORT_SYMBOL(lprocfs_rd_timeouts);
@@ -876,7 +879,7 @@ int lprocfs_rd_connect_flags(struct seq_file *m, void *data)
seq_printf(m, "flags=%#llx\n", flags);
obd_connect_seq_flags2str(m, flags, "\n");
seq_printf(m, "\n");
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
EXPORT_SYMBOL(lprocfs_rd_connect_flags);
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c
index 0193608a930a..ce248f4072c2 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -916,7 +916,7 @@ static void lu_obj_hop_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
LBUG(); /* we should never called it */
}
-struct cfs_hash_ops lu_site_hash_ops = {
+static struct cfs_hash_ops lu_site_hash_ops = {
.hs_hash = lu_obj_hop_hash,
.hs_key = lu_obj_hop_key,
.hs_keycmp = lu_obj_hop_keycmp,
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c
index c231e0da0e2a..49cdc647910c 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_config.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index 48003d5325e3..b5aa8168dbff 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -892,7 +892,7 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
}
lmd->lmd_magic = LMD_MAGIC;
- lmd->lmd_params = kzalloc(4096, GFP_NOFS);
+ lmd->lmd_params = kzalloc(LMD_PARAMS_MAXLEN, GFP_NOFS);
if (!lmd->lmd_params)
return -ENOMEM;
lmd->lmd_params[0] = '\0';
@@ -978,7 +978,7 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
goto invalid;
clear++;
} else if (strncmp(s1, "param=", 6) == 0) {
- int length;
+ size_t length, params_length;
char *tail = strchr(s1 + 6, ',');
if (tail == NULL)
@@ -986,8 +986,12 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
else
length = tail - s1;
length -= 6;
+ params_length = strlen(lmd->lmd_params);
+ if (params_length + length + 1 >= LMD_PARAMS_MAXLEN)
+ return -E2BIG;
strncat(lmd->lmd_params, s1 + 6, length);
- strcat(lmd->lmd_params, " ");
+ lmd->lmd_params[params_length + length] = '\0';
+ strlcat(lmd->lmd_params, " ", LMD_PARAMS_MAXLEN);
clear++;
} else if (strncmp(s1, "osd=", 4) == 0) {
rc = lmd_parse_string(&lmd->lmd_osd_type, s1 + 4);
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index a4a9a763ff02..7b53f7dd1797 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -1228,8 +1228,10 @@ static int cl_echo_object_brw(struct echo_object *eco, int rw, u64 offset,
cl_page_put(env, clp);
break;
}
-
- cl_2queue_add(queue, clp);
+ /*
+ * Add a page to the incoming page list of 2-queue.
+ */
+ cl_page_list_add(&queue->c2_qin, clp);
/* drop the reference count for cl_page_find, so that the page
* will be freed in cl_2queue_fini. */
@@ -2130,10 +2132,10 @@ static int echo_client_disconnect(struct obd_export *exp)
}
static struct obd_ops echo_client_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_iocontrol = echo_client_iocontrol,
- .o_connect = echo_client_connect,
- .o_disconnect = echo_client_disconnect
+ .owner = THIS_MODULE,
+ .iocontrol = echo_client_iocontrol,
+ .connect = echo_client_connect,
+ .disconnect = echo_client_disconnect
};
static int echo_client_init(void)
@@ -2172,7 +2174,7 @@ static void /*__exit*/ obdecho_exit(void)
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Testing Echo OBD driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(LUSTRE_VERSION_STRING);
diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c
index c4d44e70f1d7..1091536fc90d 100644
--- a/drivers/staging/lustre/lustre/osc/lproc_osc.c
+++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index b1d1a87f05e3..2229419b7184 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*
*/
/*
@@ -619,9 +619,9 @@ static inline int overlapped(struct osc_extent *ex1, struct osc_extent *ex2)
* Find or create an extent which includes @index, core function to manage
* extent tree.
*/
-struct osc_extent *osc_extent_find(const struct lu_env *env,
- struct osc_object *obj, pgoff_t index,
- int *grants)
+static struct osc_extent *osc_extent_find(const struct lu_env *env,
+ struct osc_object *obj, pgoff_t index,
+ int *grants)
{
struct client_obd *cli = osc_cli(obj);
@@ -1420,8 +1420,8 @@ static void __osc_unreserve_grant(struct client_obd *cli,
}
}
-void osc_unreserve_grant(struct client_obd *cli,
- unsigned int reserved, unsigned int unused)
+static void osc_unreserve_grant(struct client_obd *cli,
+ unsigned int reserved, unsigned int unused)
{
client_obd_list_lock(&cli->cl_loi_list_lock);
__osc_unreserve_grant(cli, reserved, unused);
diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
index d2d68452d382..415c27e4ab66 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
+++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c
index 69b523c0f570..7078cc57d8b9 100644
--- a/drivers/staging/lustre/lustre/osc/osc_dev.c
+++ b/drivers/staging/lustre/lustre/osc/osc_dev.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h
index 5ed30ecc84e3..a4c61463b1c7 100644
--- a/drivers/staging/lustre/lustre/osc/osc_internal.h
+++ b/drivers/staging/lustre/lustre/osc/osc_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -89,11 +89,6 @@ struct osc_cache_waiter {
int ocw_rc;
};
-int osc_create(const struct lu_env *env, struct obd_export *exp,
- struct obdo *oa, struct lov_stripe_md **ea,
- struct obd_trans_info *oti);
-int osc_real_create(struct obd_export *exp, struct obdo *oa,
- struct lov_stripe_md **ea, struct obd_trans_info *oti);
void osc_wake_cache_waiters(struct client_obd *cli);
int osc_shrink_grant_to_target(struct client_obd *cli, __u64 target_bytes);
void osc_update_next_shrink(struct client_obd *cli);
@@ -137,7 +132,6 @@ int osc_lru_shrink(struct client_obd *cli, int target);
extern spinlock_t osc_ast_guard;
-int osc_cleanup(struct obd_device *obd);
int osc_setup(struct obd_device *obd, struct lustre_cfg *lcfg);
int lproc_osc_attach_seqstat(struct obd_device *dev);
diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c
index d413496c0f63..abd0beb483fe 100644
--- a/drivers/staging/lustre/lustre/osc/osc_io.c
+++ b/drivers/staging/lustre/lustre/osc/osc_io.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c
index 194490dcaca9..71f2810d18b9 100644
--- a/drivers/staging/lustre/lustre/osc/osc_lock.c
+++ b/drivers/staging/lustre/lustre/osc/osc_lock.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c
index ba57f8df5c7f..fdd6219aacf6 100644
--- a/drivers/staging/lustre/lustre/osc/osc_object.c
+++ b/drivers/staging/lustre/lustre/osc/osc_object.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -158,8 +158,8 @@ static int osc_attr_get(const struct lu_env *env, struct cl_object *obj,
return 0;
}
-int osc_attr_set(const struct lu_env *env, struct cl_object *obj,
- const struct cl_attr *attr, unsigned valid)
+static int osc_attr_set(const struct lu_env *env, struct cl_object *obj,
+ const struct cl_attr *attr, unsigned valid)
{
struct lov_oinfo *oinfo = cl2osc(obj)->oo_oinfo;
struct ost_lvb *lvb = &oinfo->loi_lvb;
diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c
index 61eaf7172fdf..2439d804fe75 100644
--- a/drivers/staging/lustre/lustre/osc/osc_page.c
+++ b/drivers/staging/lustre/lustre/osc/osc_page.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c
index 199783103f71..e70e7961d763 100644
--- a/drivers/staging/lustre/lustre/osc/osc_quota.c
+++ b/drivers/staging/lustre/lustre/osc/osc_quota.c
@@ -23,7 +23,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*
* Code originally extracted from quota directory
*/
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index 367f83af12c0..7034f0a942c5 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -104,7 +104,7 @@ struct osc_enqueue_args {
static void osc_release_ppga(struct brw_page **ppga, u32 count);
static int brw_interpret(const struct lu_env *env,
struct ptlrpc_request *req, void *data, int rc);
-int osc_cleanup(struct obd_device *obd);
+static int osc_cleanup(struct obd_device *obd);
/* Pack OSC object metadata for disk storage (LE byte order). */
static int osc_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
@@ -431,8 +431,9 @@ static int osc_setattr_async(struct obd_export *exp, struct obd_info *oinfo,
oinfo->oi_cb_up, oinfo, rqset);
}
-int osc_real_create(struct obd_export *exp, struct obdo *oa,
- struct lov_stripe_md **ea, struct obd_trans_info *oti)
+static int osc_real_create(struct obd_export *exp, struct obdo *oa,
+ struct lov_stripe_md **ea,
+ struct obd_trans_info *oti)
{
struct ptlrpc_request *req;
struct ost_body *body;
@@ -689,9 +690,9 @@ static int osc_can_send_destroy(struct client_obd *cli)
return 0;
}
-int osc_create(const struct lu_env *env, struct obd_export *exp,
- struct obdo *oa, struct lov_stripe_md **ea,
- struct obd_trans_info *oti)
+static int osc_create(const struct lu_env *env, struct obd_export *exp,
+ struct obdo *oa, struct lov_stripe_md **ea,
+ struct obd_trans_info *oti)
{
int rc = 0;
@@ -2726,7 +2727,7 @@ static int osc_get_info(const struct lu_env *env, struct obd_export *exp,
}
*((u64 *)val) = *reply;
- out:
+out:
ptlrpc_req_finished(req);
return rc;
} else if (KEY_IS(KEY_FIEMAP)) {
@@ -3255,33 +3256,33 @@ static int osc_process_config(struct obd_device *obd, u32 len, void *buf)
}
struct obd_ops osc_obd_ops = {
- .o_owner = THIS_MODULE,
- .o_setup = osc_setup,
- .o_precleanup = osc_precleanup,
- .o_cleanup = osc_cleanup,
- .o_add_conn = client_import_add_conn,
- .o_del_conn = client_import_del_conn,
- .o_connect = client_connect_import,
- .o_reconnect = osc_reconnect,
- .o_disconnect = osc_disconnect,
- .o_statfs = osc_statfs,
- .o_statfs_async = osc_statfs_async,
- .o_packmd = osc_packmd,
- .o_unpackmd = osc_unpackmd,
- .o_create = osc_create,
- .o_destroy = osc_destroy,
- .o_getattr = osc_getattr,
- .o_getattr_async = osc_getattr_async,
- .o_setattr = osc_setattr,
- .o_setattr_async = osc_setattr_async,
- .o_find_cbdata = osc_find_cbdata,
- .o_iocontrol = osc_iocontrol,
- .o_get_info = osc_get_info,
- .o_set_info_async = osc_set_info_async,
- .o_import_event = osc_import_event,
- .o_process_config = osc_process_config,
- .o_quotactl = osc_quotactl,
- .o_quotacheck = osc_quotacheck,
+ .owner = THIS_MODULE,
+ .setup = osc_setup,
+ .precleanup = osc_precleanup,
+ .cleanup = osc_cleanup,
+ .add_conn = client_import_add_conn,
+ .del_conn = client_import_del_conn,
+ .connect = client_connect_import,
+ .reconnect = osc_reconnect,
+ .disconnect = osc_disconnect,
+ .statfs = osc_statfs,
+ .statfs_async = osc_statfs_async,
+ .packmd = osc_packmd,
+ .unpackmd = osc_unpackmd,
+ .create = osc_create,
+ .destroy = osc_destroy,
+ .getattr = osc_getattr,
+ .getattr_async = osc_getattr_async,
+ .setattr = osc_setattr,
+ .setattr_async = osc_setattr_async,
+ .find_cbdata = osc_find_cbdata,
+ .iocontrol = osc_iocontrol,
+ .get_info = osc_get_info,
+ .set_info_async = osc_set_info_async,
+ .import_event = osc_import_event,
+ .process_config = osc_process_config,
+ .quotactl = osc_quotactl,
+ .quotacheck = osc_quotacheck,
};
extern struct lu_kmem_descr osc_caches[];
@@ -3357,7 +3358,7 @@ static void /*__exit*/ osc_exit(void)
ptlrpc_free_rq_pool(osc_rq_pool);
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Object Storage Client (OSC)");
MODULE_LICENSE("GPL");
MODULE_VERSION(LUSTRE_VERSION_STRING);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index a9f1bf536da9..efdda09507bf 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c
index 9c2fd34e2eb9..990156986986 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/events.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/events.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015 Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c
index bfa410f7e773..f752c789bda0 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/import.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/import.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c
index d7c4f47808bd..c0e613c23854 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/layout.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
index 5122205cbb99..e87702073f1f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
index afab0dee7a5c..cc55b7973721 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -1197,7 +1197,7 @@ int lprocfs_wr_ping(struct file *file, const char __user *buffer,
return rc;
req = ptlrpc_prep_ping(obd->u.cli.cl_import);
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
if (req == NULL)
return -ENOMEM;
@@ -1291,7 +1291,7 @@ int lprocfs_rd_pinger_recov(struct seq_file *m, void *n)
return rc;
seq_printf(m, "%d\n", !imp->imp_no_pinger_recover);
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return 0;
}
@@ -1319,7 +1319,7 @@ int lprocfs_wr_pinger_recov(struct file *file, const char __user *buffer,
spin_lock(&imp->imp_lock);
imp->imp_no_pinger_recover = !val;
spin_unlock(&imp->imp_lock);
- LPROCFS_CLIMP_EXIT(obd);
+ up_read(&obd->u.cli.cl_sem);
return count;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
index 09ddeef6ba48..c5d7ff5cbd73 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pers.c b/drivers/staging/lustre/lustre/ptlrpc/pers.c
index 2a2a9fb6549c..ec3af109a1d7 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pers.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pers.c
@@ -26,6 +26,8 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2014, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
index 5c719f175657..fb2d5236a971 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
index ab6c4580f91c..8f67e0562b73 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -73,7 +73,6 @@ void ptlrpc_request_handle_notconn(struct ptlrpc_request *);
void lustre_assert_wire_constants(void);
int ptlrpc_import_in_recovery(struct obd_import *imp);
int ptlrpc_set_import_discon(struct obd_import *imp, __u32 conn_cnt);
-void ptlrpc_handle_failed_import(struct obd_import *imp);
int ptlrpc_replay_next(struct obd_import *imp, int *inflight);
void ptlrpc_initiate_recovery(struct obd_import *imp);
@@ -88,8 +87,6 @@ void ptlrpc_ldebugfs_register_service(struct dentry *debugfs_entry,
struct ptlrpc_service *svc);
void ptlrpc_lprocfs_unregister_service(struct ptlrpc_service *svc);
void ptlrpc_lprocfs_rpc_sent(struct ptlrpc_request *req, long amount);
-void ptlrpc_lprocfs_do_request_stat(struct ptlrpc_request *req,
- long q_usec, long work_usec);
/* NRS */
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
index 9deeb244166f..c4f1d0f5deb2 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
@@ -160,7 +160,7 @@ static void __exit ptlrpc_exit(void)
ptlrpc_connection_fini();
}
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Request Processor and Lock Management");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index ce036a1ac466..60fb0ced7137 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -27,7 +27,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -422,6 +422,7 @@ static int ptlrpcd(void *arg)
complete(&pc->pc_starting);
/*
+
* This mainloop strongly resembles ptlrpc_set_wait() except that our
* set never completes. ptlrpcd_check() calls ptlrpc_check_set() when
* there are requests in the set. New requests come in on the set's
diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c
index 7b1d72947330..db6626cab6f2 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/recover.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
index cd8a9987f7ac..6152c1b766c3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
index 7ff948fe1424..4b0b81c115ee 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
@@ -27,7 +27,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -83,8 +83,7 @@ int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
return 0;
}
- strncpy(buf, str, sizeof(buf));
- buf[sizeof(buf) - 1] = '\0';
+ strlcpy(buf, str, sizeof(buf));
bulk = strchr(buf, '-');
if (bulk)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
index f448b4567af0..905a41451ca3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index f45898f17793..8598300a61d1 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -27,7 +27,7 @@
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2010, 2012, Intel Corporation.
+ * Copyright (c) 2010, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
index 40f720ca3b14..61d9ca93c53a 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index 93bffbac8fc7..8fdf0ac4f287 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -179,14 +179,13 @@
#define BCM2048_DEFAULT_TIMEOUT 1500
#define BCM2048_AUTO_SEARCH_TIMEOUT 3000
-
#define BCM2048_FREQDEV_UNIT 10000
#define BCM2048_FREQV4L2_MULTI 625
#define dev_to_v4l2(f) ((f * BCM2048_FREQDEV_UNIT) / BCM2048_FREQV4L2_MULTI)
#define v4l2_to_dev(f) ((f * BCM2048_FREQV4L2_MULTI) / BCM2048_FREQDEV_UNIT)
-#define msb(x) ((u8)((u16) x >> 8))
-#define lsb(x) ((u8)((u16) x & 0x00FF))
+#define msb(x) ((u8)((u16)x >> 8))
+#define lsb(x) ((u8)((u16)x & 0x00FF))
#define compose_u16(msb, lsb) (((u16)msb << 8) | lsb)
#define BCM2048_DEFAULT_POWERING_DELAY 20
@@ -348,7 +347,7 @@ static struct region_info region_configs[] = {
* I2C Interface read / write
*/
static int bcm2048_send_command(struct bcm2048_device *bdev, unsigned int reg,
- unsigned int value)
+ unsigned int value)
{
struct i2c_client *client = bdev->client;
u8 data[2];
@@ -370,7 +369,7 @@ static int bcm2048_send_command(struct bcm2048_device *bdev, unsigned int reg,
}
static int bcm2048_recv_command(struct bcm2048_device *bdev, unsigned int reg,
- u8 *value)
+ u8 *value)
{
struct i2c_client *client = bdev->client;
@@ -385,7 +384,7 @@ static int bcm2048_recv_command(struct bcm2048_device *bdev, unsigned int reg,
}
static int bcm2048_recv_duples(struct bcm2048_device *bdev, unsigned int reg,
- u8 *value, u8 duples)
+ u8 *value, u8 duples)
{
struct i2c_client *client = bdev->client;
struct i2c_adapter *adap = client->adapter;
@@ -436,7 +435,7 @@ static int bcm2048_set_power_state(struct bcm2048_device *bdev, u8 power)
*/
if (power)
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
- bdev->cache_fm_rds_system);
+ bdev->cache_fm_rds_system);
msleep(BCM2048_DEFAULT_POWERING_DELAY);
if (!power)
@@ -475,17 +474,17 @@ static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on)
bdev->rds_state = BCM2048_RDS_ON;
flags = BCM2048_RDS_FLAG_FIFO_WLINE;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
- flags);
+ flags);
} else {
flags = 0;
bdev->rds_state = 0;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
- flags);
+ flags);
memset(&bdev->rds_info, 0, sizeof(bdev->rds_info));
}
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
- bdev->cache_fm_rds_system);
+ bdev->cache_fm_rds_system);
return err;
}
@@ -545,14 +544,14 @@ static int bcm2048_set_fm_automatic_stereo_mono(struct bcm2048_device *bdev,
bdev->cache_fm_ctrl |= BCM2048_STEREO_MONO_AUTO_SELECT;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
- bdev->cache_fm_ctrl);
+ bdev->cache_fm_ctrl);
mutex_unlock(&bdev->mutex);
return err;
}
static int bcm2048_set_fm_hi_lo_injection(struct bcm2048_device *bdev,
- u8 hi_lo)
+ u8 hi_lo)
{
int err;
@@ -564,7 +563,7 @@ static int bcm2048_set_fm_hi_lo_injection(struct bcm2048_device *bdev,
bdev->cache_fm_ctrl |= BCM2048_HI_LO_INJECTION;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
- bdev->cache_fm_ctrl);
+ bdev->cache_fm_ctrl);
mutex_unlock(&bdev->mutex);
return err;
@@ -592,7 +591,7 @@ static int bcm2048_set_fm_frequency(struct bcm2048_device *bdev, u32 frequency)
int err;
if (frequency < bdev->region_info.bottom_frequency ||
- frequency > bdev->region_info.top_frequency)
+ frequency > bdev->region_info.top_frequency)
return -EDOM;
frequency -= BCM2048_FREQUENCY_BASE;
@@ -601,7 +600,7 @@ static int bcm2048_set_fm_frequency(struct bcm2048_device *bdev, u32 frequency)
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ0, lsb(frequency));
err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ1,
- msb(frequency));
+ msb(frequency));
if (!err)
bdev->frequency = frequency;
@@ -632,12 +631,12 @@ static int bcm2048_get_fm_frequency(struct bcm2048_device *bdev)
}
static int bcm2048_set_fm_af_frequency(struct bcm2048_device *bdev,
- u32 frequency)
+ u32 frequency)
{
int err;
if (frequency < bdev->region_info.bottom_frequency ||
- frequency > bdev->region_info.top_frequency)
+ frequency > bdev->region_info.top_frequency)
return -EDOM;
frequency -= BCM2048_FREQUENCY_BASE;
@@ -645,9 +644,9 @@ static int bcm2048_set_fm_af_frequency(struct bcm2048_device *bdev,
mutex_lock(&bdev->mutex);
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ0,
- lsb(frequency));
+ lsb(frequency));
err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ1,
- msb(frequency));
+ msb(frequency));
if (!err)
bdev->frequency = frequency;
@@ -692,7 +691,7 @@ static int bcm2048_set_fm_deemphasis(struct bcm2048_device *bdev, int d)
bdev->cache_fm_audio_ctrl0 |= deemphasis;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
+ bdev->cache_fm_audio_ctrl0);
if (!err)
bdev->region_info.deemphasis = d;
@@ -740,7 +739,7 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region)
bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
- bdev->cache_fm_ctrl);
+ bdev->cache_fm_ctrl);
if (err) {
mutex_unlock(&bdev->mutex);
goto done;
@@ -748,7 +747,7 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region)
mutex_unlock(&bdev->mutex);
if (bdev->frequency < region_configs[region].bottom_frequency ||
- bdev->frequency > region_configs[region].top_frequency)
+ bdev->frequency > region_configs[region].top_frequency)
new_frequency = region_configs[region].bottom_frequency;
if (new_frequency > 0) {
@@ -759,7 +758,7 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region)
}
err = bcm2048_set_fm_deemphasis(bdev,
- region_configs[region].deemphasis);
+ region_configs[region].deemphasis);
done:
return err;
@@ -786,10 +785,10 @@ static int bcm2048_set_mute(struct bcm2048_device *bdev, u16 mute)
if (mute)
bdev->cache_fm_audio_ctrl0 |= (BCM2048_RF_MUTE |
- BCM2048_MANUAL_MUTE);
+ BCM2048_MANUAL_MUTE);
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
+ bdev->cache_fm_audio_ctrl0);
if (!err)
bdev->mute_state = mute;
@@ -807,7 +806,7 @@ static int bcm2048_get_mute(struct bcm2048_device *bdev)
if (bdev->power_state) {
err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- &value);
+ &value);
if (!err)
err = value & (BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE);
} else {
@@ -826,11 +825,11 @@ static int bcm2048_set_audio_route(struct bcm2048_device *bdev, u8 route)
route &= (BCM2048_AUDIO_ROUTE_DAC | BCM2048_AUDIO_ROUTE_I2S);
bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_AUDIO_ROUTE_DAC |
- BCM2048_AUDIO_ROUTE_I2S);
+ BCM2048_AUDIO_ROUTE_I2S);
bdev->cache_fm_audio_ctrl0 |= route;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
+ bdev->cache_fm_audio_ctrl0);
mutex_unlock(&bdev->mutex);
return err;
@@ -849,7 +848,7 @@ static int bcm2048_get_audio_route(struct bcm2048_device *bdev)
if (!err)
return value & (BCM2048_AUDIO_ROUTE_DAC |
- BCM2048_AUDIO_ROUTE_I2S);
+ BCM2048_AUDIO_ROUTE_I2S);
return err;
}
@@ -865,7 +864,7 @@ static int bcm2048_set_dac_output(struct bcm2048_device *bdev, u8 channels)
bdev->cache_fm_audio_ctrl0 |= channels;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
- bdev->cache_fm_audio_ctrl0);
+ bdev->cache_fm_audio_ctrl0);
mutex_unlock(&bdev->mutex);
return err;
@@ -884,13 +883,13 @@ static int bcm2048_get_dac_output(struct bcm2048_device *bdev)
if (!err)
return value & (BCM2048_DAC_OUTPUT_LEFT |
- BCM2048_DAC_OUTPUT_RIGHT);
+ BCM2048_DAC_OUTPUT_RIGHT);
return err;
}
static int bcm2048_set_fm_search_rssi_threshold(struct bcm2048_device *bdev,
- u8 threshold)
+ u8 threshold)
{
int err;
@@ -901,7 +900,7 @@ static int bcm2048_set_fm_search_rssi_threshold(struct bcm2048_device *bdev,
bdev->cache_fm_search_ctrl0 |= threshold;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0,
- bdev->cache_fm_search_ctrl0);
+ bdev->cache_fm_search_ctrl0);
mutex_unlock(&bdev->mutex);
return err;
@@ -937,7 +936,7 @@ static int bcm2048_set_fm_search_mode_direction(struct bcm2048_device *bdev,
bdev->cache_fm_search_ctrl0 |= BCM2048_SEARCH_DIRECTION;
err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0,
- bdev->cache_fm_search_ctrl0);
+ bdev->cache_fm_search_ctrl0);
mutex_unlock(&bdev->mutex);
return err;
@@ -961,7 +960,7 @@ static int bcm2048_get_fm_search_mode_direction(struct bcm2048_device *bdev)
}
static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev,
- u8 mode)
+ u8 mode)
{
int err, timeout, restart_rds = 0;
u8 value, flags;
@@ -1024,7 +1023,7 @@ static int bcm2048_get_fm_search_tune_mode(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE,
- &value);
+ &value);
mutex_unlock(&bdev->mutex);
@@ -1040,10 +1039,10 @@ static int bcm2048_set_rds_b_block_mask(struct bcm2048_device *bdev, u16 mask)
mutex_lock(&bdev->mutex);
- err = bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_BLKB_MASK0, lsb(mask));
- err |= bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_BLKB_MASK1, msb(mask));
+ err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0,
+ lsb(mask));
+ err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1,
+ msb(mask));
mutex_unlock(&bdev->mutex);
return err;
@@ -1056,10 +1055,8 @@ static int bcm2048_get_rds_b_block_mask(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
- err = bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_BLKB_MASK0, &lsb);
- err |= bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_BLKB_MASK1, &msb);
+ err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0, &lsb);
+ err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1, &msb);
mutex_unlock(&bdev->mutex);
@@ -1070,16 +1067,16 @@ static int bcm2048_get_rds_b_block_mask(struct bcm2048_device *bdev)
}
static int bcm2048_set_rds_b_block_match(struct bcm2048_device *bdev,
- u16 match)
+ u16 match)
{
int err;
mutex_lock(&bdev->mutex);
- err = bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_BLKB_MATCH0, lsb(match));
- err |= bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_BLKB_MATCH1, msb(match));
+ err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0,
+ lsb(match));
+ err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1,
+ msb(match));
mutex_unlock(&bdev->mutex);
return err;
@@ -1092,10 +1089,8 @@ static int bcm2048_get_rds_b_block_match(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
- err = bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_BLKB_MATCH0, &lsb);
- err |= bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_BLKB_MATCH1, &msb);
+ err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0, &lsb);
+ err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1, &msb);
mutex_unlock(&bdev->mutex);
@@ -1111,10 +1106,8 @@ static int bcm2048_set_rds_pi_mask(struct bcm2048_device *bdev, u16 mask)
mutex_lock(&bdev->mutex);
- err = bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_PI_MASK0, lsb(mask));
- err |= bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_PI_MASK1, msb(mask));
+ err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK0, lsb(mask));
+ err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK1, msb(mask));
mutex_unlock(&bdev->mutex);
return err;
@@ -1127,10 +1120,8 @@ static int bcm2048_get_rds_pi_mask(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
- err = bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_PI_MASK0, &lsb);
- err |= bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_PI_MASK1, &msb);
+ err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK0, &lsb);
+ err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK1, &msb);
mutex_unlock(&bdev->mutex);
@@ -1146,10 +1137,10 @@ static int bcm2048_set_rds_pi_match(struct bcm2048_device *bdev, u16 match)
mutex_lock(&bdev->mutex);
- err = bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_PI_MATCH0, lsb(match));
- err |= bcm2048_send_command(bdev,
- BCM2048_I2C_RDS_PI_MATCH1, msb(match));
+ err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH0,
+ lsb(match));
+ err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH1,
+ msb(match));
mutex_unlock(&bdev->mutex);
return err;
@@ -1162,10 +1153,8 @@ static int bcm2048_get_rds_pi_match(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
- err = bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_PI_MATCH0, &lsb);
- err |= bcm2048_recv_command(bdev,
- BCM2048_I2C_RDS_PI_MATCH1, &msb);
+ err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH0, &lsb);
+ err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH1, &msb);
mutex_unlock(&bdev->mutex);
@@ -1181,10 +1170,8 @@ static int bcm2048_set_fm_rds_mask(struct bcm2048_device *bdev, u16 mask)
mutex_lock(&bdev->mutex);
- err = bcm2048_send_command(bdev,
- BCM2048_I2C_FM_RDS_MASK0, lsb(mask));
- err |= bcm2048_send_command(bdev,
- BCM2048_I2C_FM_RDS_MASK1, msb(mask));
+ err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, lsb(mask));
+ err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, msb(mask));
mutex_unlock(&bdev->mutex);
return err;
@@ -1245,13 +1232,13 @@ static int bcm2048_set_fm_best_tune_mode(struct bcm2048_device *bdev, u8 mode)
/* Perform read as the manual indicates */
err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
- &value);
+ &value);
value &= ~BCM2048_BEST_TUNE_MODE;
if (mode)
value |= BCM2048_BEST_TUNE_MODE;
err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
- value);
+ value);
mutex_unlock(&bdev->mutex);
return err;
@@ -1265,7 +1252,7 @@ static int bcm2048_get_fm_best_tune_mode(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
- &value);
+ &value);
mutex_unlock(&bdev->mutex);
@@ -1352,7 +1339,7 @@ static int bcm2048_checkrev(struct bcm2048_device *bdev)
if (!err) {
dev_info(&bdev->client->dev, "BCM2048 Version 0x%x\n",
- version);
+ version);
return version;
}
@@ -1362,7 +1349,7 @@ static int bcm2048_checkrev(struct bcm2048_device *bdev)
static int bcm2048_get_rds_rt(struct bcm2048_device *bdev, char *data)
{
int err = 0, i, j = 0, ce = 0, cr = 0;
- char data_buffer[BCM2048_MAX_RDS_RT+1];
+ char data_buffer[BCM2048_MAX_RDS_RT + 1];
mutex_lock(&bdev->mutex);
@@ -1412,7 +1399,7 @@ unlock:
static int bcm2048_get_rds_ps(struct bcm2048_device *bdev, char *data)
{
int err = 0, i, j = 0;
- char data_buffer[BCM2048_MAX_RDS_PS+1];
+ char data_buffer[BCM2048_MAX_RDS_PS + 1];
mutex_lock(&bdev->mutex);
@@ -1448,12 +1435,10 @@ static void bcm2048_parse_rds_pi(struct bcm2048_device *bdev)
u16 pi;
for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
-
/* Block A match, only data without crc errors taken */
if (bdev->rds_info.radio_text[i] == BCM2048_RDS_BLOCK_A) {
-
- pi = (bdev->rds_info.radio_text[i+1] << 8) +
- bdev->rds_info.radio_text[i+2];
+ pi = (bdev->rds_info.radio_text[i + 1] << 8) +
+ bdev->rds_info.radio_text[i + 2];
if (!bdev->rds_info.rds_pi) {
bdev->rds_info.rds_pi = pi;
@@ -1478,20 +1463,21 @@ static int bcm2048_rds_block_crc(struct bcm2048_device *bdev, int i)
}
static void bcm2048_parse_rds_rt_block(struct bcm2048_device *bdev, int i,
- int index, int crc)
+ int index, int crc)
{
/* Good data will overwrite poor data */
if (crc) {
if (!bdev->rds_info.rds_rt[index])
bdev->rds_info.rds_rt[index] =
- bdev->rds_info.radio_text[i+1];
- if (!bdev->rds_info.rds_rt[index+1])
- bdev->rds_info.rds_rt[index+1] =
- bdev->rds_info.radio_text[i+2];
+ bdev->rds_info.radio_text[i + 1];
+ if (!bdev->rds_info.rds_rt[index + 1])
+ bdev->rds_info.rds_rt[index + 1] =
+ bdev->rds_info.radio_text[i + 2];
} else {
- bdev->rds_info.rds_rt[index] = bdev->rds_info.radio_text[i+1];
- bdev->rds_info.rds_rt[index+1] =
- bdev->rds_info.radio_text[i+2];
+ bdev->rds_info.rds_rt[index] =
+ bdev->rds_info.radio_text[i + 1];
+ bdev->rds_info.rds_rt[index + 1] =
+ bdev->rds_info.radio_text[i + 2];
}
}
@@ -1505,18 +1491,17 @@ static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i)
return -EIO;
if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_B) {
-
- rt_id = bdev->rds_info.radio_text[i+1] &
+ BCM2048_RDS_BLOCK_B) {
+ rt_id = bdev->rds_info.radio_text[i + 1] &
BCM2048_RDS_BLOCK_MASK;
- rt_group_b = bdev->rds_info.radio_text[i+1] &
+ rt_group_b = bdev->rds_info.radio_text[i + 1] &
BCM2048_RDS_GROUP_AB_MASK;
- rt_ab = bdev->rds_info.radio_text[i+2] &
+ rt_ab = bdev->rds_info.radio_text[i + 2] &
BCM2048_RDS_RT_AB_MASK;
if (rt_group_b != bdev->rds_info.rds_rt_group_b) {
memset(bdev->rds_info.rds_rt, 0,
- sizeof(bdev->rds_info.rds_rt));
+ sizeof(bdev->rds_info.rds_rt));
bdev->rds_info.rds_rt_group_b = rt_group_b;
}
@@ -1524,11 +1509,11 @@ static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i)
/* A to B or (vice versa), means: clear screen */
if (rt_ab != bdev->rds_info.rds_rt_ab) {
memset(bdev->rds_info.rds_rt, 0,
- sizeof(bdev->rds_info.rds_rt));
+ sizeof(bdev->rds_info.rds_rt));
bdev->rds_info.rds_rt_ab = rt_ab;
}
- index = bdev->rds_info.radio_text[i+2] &
+ index = bdev->rds_info.radio_text[i + 2] &
BCM2048_RDS_RT_INDEX;
if (bdev->rds_info.rds_rt_group_b)
@@ -1544,7 +1529,7 @@ static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i)
}
static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i,
- int index)
+ int index)
{
int crc;
@@ -1567,7 +1552,7 @@ static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i,
}
static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i,
- int index)
+ int index)
{
int crc;
@@ -1579,8 +1564,8 @@ static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i,
BUG_ON((index+4) >= BCM2048_MAX_RDS_RT);
if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_D)
- bcm2048_parse_rds_rt_block(bdev, i, index+2, crc);
+ BCM2048_RDS_BLOCK_D)
+ bcm2048_parse_rds_rt_block(bdev, i, index + 2, crc);
}
static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev)
@@ -1588,7 +1573,6 @@ static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev)
int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0;
for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
-
if (match_b) {
match_b = 0;
index = bcm2048_parse_rt_match_b(bdev, i);
@@ -1607,40 +1591,41 @@ static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev)
}
/* Skip erroneous blocks due to messed up A block altogether */
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK)
- == BCM2048_RDS_BLOCK_A) {
+ if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+ BCM2048_RDS_BLOCK_A) {
crc = bcm2048_rds_block_crc(bdev, i);
if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
continue;
- /* Syncronize to a good RDS PI */
- if (((bdev->rds_info.radio_text[i+1] << 8) +
- bdev->rds_info.radio_text[i+2]) ==
- bdev->rds_info.rds_pi)
- match_b = 1;
+ /* Synchronize to a good RDS PI */
+ if (((bdev->rds_info.radio_text[i + 1] << 8) +
+ bdev->rds_info.radio_text[i + 2]) ==
+ bdev->rds_info.rds_pi)
+ match_b = 1;
}
}
}
static void bcm2048_parse_rds_ps_block(struct bcm2048_device *bdev, int i,
- int index, int crc)
+ int index, int crc)
{
/* Good data will overwrite poor data */
if (crc) {
if (!bdev->rds_info.rds_ps[index])
bdev->rds_info.rds_ps[index] =
- bdev->rds_info.radio_text[i+1];
- if (!bdev->rds_info.rds_ps[index+1])
- bdev->rds_info.rds_ps[index+1] =
- bdev->rds_info.radio_text[i+2];
+ bdev->rds_info.radio_text[i + 1];
+ if (!bdev->rds_info.rds_ps[index + 1])
+ bdev->rds_info.rds_ps[index + 1] =
+ bdev->rds_info.radio_text[i + 2];
} else {
- bdev->rds_info.rds_ps[index] = bdev->rds_info.radio_text[i+1];
- bdev->rds_info.rds_ps[index+1] =
- bdev->rds_info.radio_text[i+2];
+ bdev->rds_info.rds_ps[index] =
+ bdev->rds_info.radio_text[i + 1];
+ bdev->rds_info.rds_ps[index + 1] =
+ bdev->rds_info.radio_text[i + 2];
}
}
static int bcm2048_parse_ps_match_c(struct bcm2048_device *bdev, int i,
- int index)
+ int index)
{
int crc;
@@ -1650,14 +1635,14 @@ static int bcm2048_parse_ps_match_c(struct bcm2048_device *bdev, int i,
return 0;
if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_C)
+ BCM2048_RDS_BLOCK_C)
return 1;
return 0;
}
static void bcm2048_parse_ps_match_d(struct bcm2048_device *bdev, int i,
- int index)
+ int index)
{
int crc;
@@ -1667,7 +1652,7 @@ static void bcm2048_parse_ps_match_d(struct bcm2048_device *bdev, int i,
return;
if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_D)
+ BCM2048_RDS_BLOCK_D)
bcm2048_parse_rds_ps_block(bdev, i, index, crc);
}
@@ -1682,10 +1667,10 @@ static int bcm2048_parse_ps_match_b(struct bcm2048_device *bdev, int i)
/* Block B Radio PS match */
if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
- BCM2048_RDS_BLOCK_B) {
- ps_id = bdev->rds_info.radio_text[i+1] &
+ BCM2048_RDS_BLOCK_B) {
+ ps_id = bdev->rds_info.radio_text[i + 1] &
BCM2048_RDS_BLOCK_MASK;
- ps_group = bdev->rds_info.radio_text[i+1] &
+ ps_group = bdev->rds_info.radio_text[i + 1] &
BCM2048_RDS_GROUP_AB_MASK;
/*
@@ -1709,7 +1694,7 @@ static int bcm2048_parse_ps_match_b(struct bcm2048_device *bdev, int i)
}
if (ps_id == BCM2048_RDS_PS) {
- index = bdev->rds_info.radio_text[i+2] &
+ index = bdev->rds_info.radio_text[i + 2] &
BCM2048_RDS_PS_INDEX;
index <<= 1;
return index;
@@ -1724,7 +1709,6 @@ static void bcm2048_parse_rds_ps(struct bcm2048_device *bdev)
int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0;
for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
-
if (match_b) {
match_b = 0;
index = bcm2048_parse_ps_match_b(bdev, i);
@@ -1743,16 +1727,16 @@ static void bcm2048_parse_rds_ps(struct bcm2048_device *bdev)
}
/* Skip erroneous blocks due to messed up A block altogether */
- if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK)
- == BCM2048_RDS_BLOCK_A) {
+ if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+ BCM2048_RDS_BLOCK_A) {
crc = bcm2048_rds_block_crc(bdev, i);
if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
continue;
- /* Syncronize to a good RDS PI */
- if (((bdev->rds_info.radio_text[i+1] << 8) +
- bdev->rds_info.radio_text[i+2]) ==
- bdev->rds_info.rds_pi)
- match_b = 1;
+ /* Synchronize to a good RDS PI */
+ if (((bdev->rds_info.radio_text[i + 1] << 8) +
+ bdev->rds_info.radio_text[i + 2]) ==
+ bdev->rds_info.rds_pi)
+ match_b = 1;
}
}
}
@@ -1764,7 +1748,7 @@ static void bcm2048_rds_fifo_receive(struct bcm2048_device *bdev)
mutex_lock(&bdev->mutex);
err = bcm2048_recv_duples(bdev, BCM2048_I2C_RDS_DATA,
- bdev->rds_info.radio_text, bdev->fifo_size);
+ bdev->rds_info.radio_text, bdev->fifo_size);
if (err != 2) {
dev_err(&bdev->client->dev, "RDS Read problem\n");
mutex_unlock(&bdev->mutex);
@@ -1801,8 +1785,8 @@ static int bcm2048_get_rds_data(struct bcm2048_device *bdev, char *data)
}
for (i = 0; i < bdev->rds_info.text_len; i++) {
- p += sprintf(data_buffer+p, "%x ",
- bdev->rds_info.radio_text[i]);
+ p += sprintf(data_buffer + p, "%x ",
+ bdev->rds_info.radio_text[i]);
}
memcpy(data, data_buffer, p);
@@ -1829,7 +1813,7 @@ static int bcm2048_init(struct bcm2048_device *bdev)
goto exit;
err = bcm2048_set_dac_output(bdev, BCM2048_DAC_OUTPUT_LEFT |
- BCM2048_DAC_OUTPUT_RIGHT);
+ BCM2048_DAC_OUTPUT_RIGHT);
exit:
return err;
@@ -1921,7 +1905,6 @@ static void bcm2048_work(struct work_struct *work)
if (flag_lsb & (BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED |
BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)) {
-
if (flag_lsb & BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)
bdev->scan_state = BCM2048_SCAN_FAIL;
else
@@ -1935,7 +1918,7 @@ static void bcm2048_work(struct work_struct *work)
if (bdev->rds_state) {
flags = BCM2048_RDS_FLAG_FIFO_WLINE;
bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
- flags);
+ flags);
}
bdev->rds_data_available = 1;
bdev->rd_index = 0; /* new data, new start */
@@ -2074,7 +2057,7 @@ property_str_read(rds_rt, (BCM2048_MAX_RDS_RT + 1))
property_str_read(rds_ps, (BCM2048_MAX_RDS_PS + 1))
property_read(fm_rds_flags, unsigned int, "%u")
-property_str_read(rds_data, BCM2048_MAX_RDS_RADIO_TEXT*5)
+property_str_read(rds_data, BCM2048_MAX_RDS_RADIO_TEXT * 5)
property_read(region_bottom_frequency, unsigned int, "%u")
property_read(region_top_frequency, unsigned int, "%u")
@@ -2084,70 +2067,70 @@ DEFINE_SYSFS_PROPERTY(region, unsigned, int, "%u", 0)
static struct device_attribute attrs[] = {
__ATTR(power_state, S_IRUGO | S_IWUSR, bcm2048_power_state_read,
- bcm2048_power_state_write),
+ bcm2048_power_state_write),
__ATTR(mute, S_IRUGO | S_IWUSR, bcm2048_mute_read,
- bcm2048_mute_write),
+ bcm2048_mute_write),
__ATTR(audio_route, S_IRUGO | S_IWUSR, bcm2048_audio_route_read,
- bcm2048_audio_route_write),
+ bcm2048_audio_route_write),
__ATTR(dac_output, S_IRUGO | S_IWUSR, bcm2048_dac_output_read,
- bcm2048_dac_output_write),
+ bcm2048_dac_output_write),
__ATTR(fm_hi_lo_injection, S_IRUGO | S_IWUSR,
- bcm2048_fm_hi_lo_injection_read,
- bcm2048_fm_hi_lo_injection_write),
+ bcm2048_fm_hi_lo_injection_read,
+ bcm2048_fm_hi_lo_injection_write),
__ATTR(fm_frequency, S_IRUGO | S_IWUSR, bcm2048_fm_frequency_read,
- bcm2048_fm_frequency_write),
+ bcm2048_fm_frequency_write),
__ATTR(fm_af_frequency, S_IRUGO | S_IWUSR,
- bcm2048_fm_af_frequency_read,
- bcm2048_fm_af_frequency_write),
+ bcm2048_fm_af_frequency_read,
+ bcm2048_fm_af_frequency_write),
__ATTR(fm_deemphasis, S_IRUGO | S_IWUSR, bcm2048_fm_deemphasis_read,
- bcm2048_fm_deemphasis_write),
+ bcm2048_fm_deemphasis_write),
__ATTR(fm_rds_mask, S_IRUGO | S_IWUSR, bcm2048_fm_rds_mask_read,
- bcm2048_fm_rds_mask_write),
+ bcm2048_fm_rds_mask_write),
__ATTR(fm_best_tune_mode, S_IRUGO | S_IWUSR,
- bcm2048_fm_best_tune_mode_read,
- bcm2048_fm_best_tune_mode_write),
+ bcm2048_fm_best_tune_mode_read,
+ bcm2048_fm_best_tune_mode_write),
__ATTR(fm_search_rssi_threshold, S_IRUGO | S_IWUSR,
- bcm2048_fm_search_rssi_threshold_read,
- bcm2048_fm_search_rssi_threshold_write),
+ bcm2048_fm_search_rssi_threshold_read,
+ bcm2048_fm_search_rssi_threshold_write),
__ATTR(fm_search_mode_direction, S_IRUGO | S_IWUSR,
- bcm2048_fm_search_mode_direction_read,
- bcm2048_fm_search_mode_direction_write),
+ bcm2048_fm_search_mode_direction_read,
+ bcm2048_fm_search_mode_direction_write),
__ATTR(fm_search_tune_mode, S_IRUGO | S_IWUSR,
- bcm2048_fm_search_tune_mode_read,
- bcm2048_fm_search_tune_mode_write),
+ bcm2048_fm_search_tune_mode_read,
+ bcm2048_fm_search_tune_mode_write),
__ATTR(rds, S_IRUGO | S_IWUSR, bcm2048_rds_read,
- bcm2048_rds_write),
+ bcm2048_rds_write),
__ATTR(rds_b_block_mask, S_IRUGO | S_IWUSR,
- bcm2048_rds_b_block_mask_read,
- bcm2048_rds_b_block_mask_write),
+ bcm2048_rds_b_block_mask_read,
+ bcm2048_rds_b_block_mask_write),
__ATTR(rds_b_block_match, S_IRUGO | S_IWUSR,
- bcm2048_rds_b_block_match_read,
- bcm2048_rds_b_block_match_write),
+ bcm2048_rds_b_block_match_read,
+ bcm2048_rds_b_block_match_write),
__ATTR(rds_pi_mask, S_IRUGO | S_IWUSR, bcm2048_rds_pi_mask_read,
- bcm2048_rds_pi_mask_write),
+ bcm2048_rds_pi_mask_write),
__ATTR(rds_pi_match, S_IRUGO | S_IWUSR, bcm2048_rds_pi_match_read,
- bcm2048_rds_pi_match_write),
+ bcm2048_rds_pi_match_write),
__ATTR(rds_wline, S_IRUGO | S_IWUSR, bcm2048_rds_wline_read,
- bcm2048_rds_wline_write),
+ bcm2048_rds_wline_write),
__ATTR(rds_pi, S_IRUGO, bcm2048_rds_pi_read, NULL),
__ATTR(rds_rt, S_IRUGO, bcm2048_rds_rt_read, NULL),
__ATTR(rds_ps, S_IRUGO, bcm2048_rds_ps_read, NULL),
__ATTR(fm_rds_flags, S_IRUGO, bcm2048_fm_rds_flags_read, NULL),
__ATTR(region_bottom_frequency, S_IRUGO,
- bcm2048_region_bottom_frequency_read, NULL),
+ bcm2048_region_bottom_frequency_read, NULL),
__ATTR(region_top_frequency, S_IRUGO,
- bcm2048_region_top_frequency_read, NULL),
+ bcm2048_region_top_frequency_read, NULL),
__ATTR(fm_carrier_error, S_IRUGO,
- bcm2048_fm_carrier_error_read, NULL),
+ bcm2048_fm_carrier_error_read, NULL),
__ATTR(fm_rssi, S_IRUGO,
- bcm2048_fm_rssi_read, NULL),
+ bcm2048_fm_rssi_read, NULL),
__ATTR(region, S_IRUGO | S_IWUSR, bcm2048_region_read,
- bcm2048_region_write),
+ bcm2048_region_write),
__ATTR(rds_data, S_IRUGO, bcm2048_rds_data_read, NULL),
};
static int bcm2048_sysfs_unregister_properties(struct bcm2048_device *bdev,
- int size)
+ int size)
{
int i;
@@ -2165,7 +2148,7 @@ static int bcm2048_sysfs_register_properties(struct bcm2048_device *bdev)
for (i = 0; i < ARRAY_SIZE(attrs); i++) {
if (device_create_file(&bdev->client->dev, &attrs[i]) != 0) {
dev_err(&bdev->client->dev,
- "could not register sysfs entry\n");
+ "could not register sysfs entry\n");
err = -EBUSY;
bcm2048_sysfs_unregister_properties(bdev, i);
break;
@@ -2175,7 +2158,6 @@ static int bcm2048_sysfs_register_properties(struct bcm2048_device *bdev)
return err;
}
-
static int bcm2048_fops_open(struct file *file)
{
struct bcm2048_device *bdev = video_drvdata(file);
@@ -2197,7 +2179,7 @@ static int bcm2048_fops_release(struct file *file)
}
static unsigned int bcm2048_fops_poll(struct file *file,
- struct poll_table_struct *pts)
+ struct poll_table_struct *pts)
{
struct bcm2048_device *bdev = video_drvdata(file);
int retval = 0;
@@ -2211,7 +2193,7 @@ static unsigned int bcm2048_fops_poll(struct file *file,
}
static ssize_t bcm2048_fops_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct bcm2048_device *bdev = video_drvdata(file);
int i;
@@ -2229,7 +2211,7 @@ static ssize_t bcm2048_fops_read(struct file *file, char __user *buf,
}
/* interruptible_sleep_on(&bdev->read_queue); */
if (wait_event_interruptible(bdev->read_queue,
- bdev->rds_data_available) < 0) {
+ bdev->rds_data_available) < 0) {
retval = -EINTR;
goto done;
}
@@ -2245,13 +2227,16 @@ static ssize_t bcm2048_fops_read(struct file *file, char __user *buf,
while (i < count) {
unsigned char tmpbuf[3];
- tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index+i+2];
- tmpbuf[i+1] = bdev->rds_info.radio_text[bdev->rd_index+i+1];
- tmpbuf[i+2] = (bdev->rds_info.radio_text[bdev->rd_index + i] & 0xf0) >> 4;
- if ((bdev->rds_info.radio_text[bdev->rd_index+i] &
- BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE)
- tmpbuf[i+2] |= 0x80;
- if (copy_to_user(buf+i, tmpbuf, 3)) {
+ tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index + i + 2];
+ tmpbuf[i + 1] =
+ bdev->rds_info.radio_text[bdev->rd_index + i + 1];
+ tmpbuf[i + 2] =
+ (bdev->rds_info.radio_text[bdev->rd_index + i] &
+ 0xf0) >> 4;
+ if ((bdev->rds_info.radio_text[bdev->rd_index + i] &
+ BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE)
+ tmpbuf[i + 2] |= 0x80;
+ if (copy_to_user(buf + i, tmpbuf, 3)) {
retval = -EFAULT;
break;
}
@@ -2319,7 +2304,7 @@ static struct v4l2_queryctrl bcm2048_v4l2_queryctrl[] = {
};
static int bcm2048_vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *capability)
+ struct v4l2_capability *capability)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
@@ -2337,7 +2322,7 @@ static int bcm2048_vidioc_querycap(struct file *file, void *priv,
}
static int bcm2048_vidioc_g_input(struct file *filp, void *priv,
- unsigned int *i)
+ unsigned int *i)
{
*i = 0;
@@ -2345,7 +2330,7 @@ static int bcm2048_vidioc_g_input(struct file *filp, void *priv,
}
static int bcm2048_vidioc_s_input(struct file *filp, void *priv,
- unsigned int i)
+ unsigned int i)
{
if (i)
return -EINVAL;
@@ -2354,7 +2339,7 @@ static int bcm2048_vidioc_s_input(struct file *filp, void *priv,
}
static int bcm2048_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+ struct v4l2_queryctrl *qc)
{
int i;
@@ -2369,7 +2354,7 @@ static int bcm2048_vidioc_queryctrl(struct file *file, void *priv,
}
static int bcm2048_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+ struct v4l2_control *ctrl)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
int err = 0;
@@ -2389,7 +2374,7 @@ static int bcm2048_vidioc_g_ctrl(struct file *file, void *priv,
}
static int bcm2048_vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+ struct v4l2_control *ctrl)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
int err = 0;
@@ -2417,7 +2402,7 @@ static int bcm2048_vidioc_s_ctrl(struct file *file, void *priv,
}
static int bcm2048_vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *audio)
+ struct v4l2_audio *audio)
{
if (audio->index > 1)
return -EINVAL;
@@ -2429,7 +2414,7 @@ static int bcm2048_vidioc_g_audio(struct file *file, void *priv,
}
static int bcm2048_vidioc_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *audio)
+ const struct v4l2_audio *audio)
{
if (audio->index != 0)
return -EINVAL;
@@ -2438,7 +2423,7 @@ static int bcm2048_vidioc_s_audio(struct file *file, void *priv,
}
static int bcm2048_vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *tuner)
+ struct v4l2_tuner *tuner)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
s8 f_error;
@@ -2493,7 +2478,7 @@ static int bcm2048_vidioc_g_tuner(struct file *file, void *priv,
}
static int bcm2048_vidioc_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *tuner)
+ const struct v4l2_tuner *tuner)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
@@ -2507,7 +2492,7 @@ static int bcm2048_vidioc_s_tuner(struct file *file, void *priv,
}
static int bcm2048_vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ struct v4l2_frequency *freq)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
int err = 0;
@@ -2528,7 +2513,7 @@ static int bcm2048_vidioc_g_frequency(struct file *file, void *priv,
}
static int bcm2048_vidioc_s_frequency(struct file *file, void *priv,
- const struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
int err;
@@ -2546,7 +2531,7 @@ static int bcm2048_vidioc_s_frequency(struct file *file, void *priv,
}
static int bcm2048_vidioc_s_hw_freq_seek(struct file *file, void *priv,
- const struct v4l2_hw_freq_seek *seek)
+ const struct v4l2_hw_freq_seek *seek)
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
int err;
@@ -2559,7 +2544,7 @@ static int bcm2048_vidioc_s_hw_freq_seek(struct file *file, void *priv,
err = bcm2048_set_fm_search_mode_direction(bdev, seek->seek_upward);
err |= bcm2048_set_fm_search_tune_mode(bdev,
- BCM2048_FM_AUTO_SEARCH_MODE);
+ BCM2048_FM_AUTO_SEARCH_MODE);
return err;
}
@@ -2594,7 +2579,7 @@ static 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)
+ const struct i2c_device_id *id)
{
struct bcm2048_device *bdev;
int err;
@@ -2613,8 +2598,8 @@ static int bcm2048_i2c_driver_probe(struct i2c_client *client,
if (client->irq) {
err = request_irq(client->irq,
- bcm2048_handler, IRQF_TRIGGER_FALLING,
- client->name, bdev);
+ bcm2048_handler, IRQF_TRIGGER_FALLING,
+ client->name, bdev);
if (err < 0) {
dev_err(&client->dev, "Could not request IRQ\n");
goto free_bdev;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index c492914768ea..ac78ed2f8bcc 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -1712,8 +1712,11 @@ ipipe_link_setup(struct media_entity *entity, const struct media_pad *local,
struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe);
u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
- switch (local->index | media_entity_type(remote->entity)) {
- case IPIPE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (!is_media_entity_v4l2_subdev(remote->entity))
+ return -EINVAL;
+
+ switch (local->index) {
+ case IPIPE_PAD_SINK:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
ipipe->input = IPIPE_INPUT_NONE;
break;
@@ -1726,7 +1729,7 @@ ipipe_link_setup(struct media_entity *entity, const struct media_pad *local,
ipipe->input = IPIPE_INPUT_CCDC;
break;
- case IPIPE_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case IPIPE_PAD_SOURCE:
/* out to RESIZER */
if (flags & MEDIA_LNK_FL_ENABLED)
ipipe->output = IPIPE_OUTPUT_RESIZER;
@@ -1840,7 +1843,7 @@ vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev)
v4l2_ctrl_handler_setup(&ipipe->ctrls);
sd->ctrl_handler = &ipipe->ctrls;
- return media_entity_init(me, IPIPE_PADS_NUM, pads, 0);
+ return media_entity_pads_init(me, IPIPE_PADS_NUM, pads);
}
/*
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
index 8b230541b1d1..633d6456fdce 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
@@ -885,9 +885,14 @@ ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
struct vpfe_device *vpfe = to_vpfe_device(ipipeif);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case IPIPEIF_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case IPIPEIF_PAD_SINK:
/* Single shot mode */
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
ipipeif->input = IPIPEIF_INPUT_NONE;
@@ -896,7 +901,7 @@ ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
ipipeif->input = IPIPEIF_INPUT_MEMORY;
break;
- case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ case IPIPEIF_PAD_SINK | 2 << 16:
/* read from isif */
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
ipipeif->input = IPIPEIF_INPUT_NONE;
@@ -908,7 +913,7 @@ ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
ipipeif->input = IPIPEIF_INPUT_ISIF;
break;
- case IPIPEIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case IPIPEIF_PAD_SOURCE | 2 << 16:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
ipipeif->output = IPIPEIF_OUTPUT_NONE;
break;
@@ -971,7 +976,7 @@ vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif,
ipipeif->video_in.vpfe_dev = vpfe_dev;
flags = 0;
- ret = media_entity_create_link(&ipipeif->video_in.video_dev.entity, 0,
+ ret = media_create_pad_link(&ipipeif->video_in.video_dev.entity, 0,
&ipipeif->subdev.entity, 0, flags);
if (ret < 0)
goto fail;
@@ -1026,7 +1031,7 @@ int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
ipipeif->output = IPIPEIF_OUTPUT_NONE;
me->ops = &ipipeif_media_ops;
- ret = media_entity_init(me, IPIPEIF_NUM_PADS, pads, 0);
+ ret = media_entity_pads_init(me, IPIPEIF_NUM_PADS, pads);
if (ret)
goto fail;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index 80907b464412..99057892d88d 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -1707,9 +1707,14 @@ isif_link_setup(struct media_entity *entity, const struct media_pad *local,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case ISIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case ISIF_PAD_SINK | 2 << 16:
/* read from decoder/sensor */
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
isif->input = ISIF_INPUT_NONE;
@@ -1720,7 +1725,7 @@ isif_link_setup(struct media_entity *entity, const struct media_pad *local,
isif->input = ISIF_INPUT_PARALLEL;
break;
- case ISIF_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ case ISIF_PAD_SOURCE:
/* write to memory */
if (flags & MEDIA_LNK_FL_ENABLED)
isif->output = ISIF_OUTPUT_MEMORY;
@@ -1728,7 +1733,7 @@ isif_link_setup(struct media_entity *entity, const struct media_pad *local,
isif->output = ISIF_OUTPUT_NONE;
break;
- case ISIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case ISIF_PAD_SOURCE | 2 << 16:
if (flags & MEDIA_LNK_FL_ENABLED)
isif->output = ISIF_OUTPUT_IPIPEIF;
else
@@ -1817,7 +1822,7 @@ int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
isif->video_out.vpfe_dev = vpfe_dev;
flags = 0;
/* connect isif to video node */
- ret = media_entity_create_link(&isif->subdev.entity, 1,
+ ret = media_create_pad_link(&isif->subdev.entity, 1,
&isif->video_out.video_dev.entity,
0, flags);
if (ret < 0)
@@ -2052,7 +2057,7 @@ int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
isif->input = ISIF_INPUT_NONE;
isif->output = ISIF_OUTPUT_NONE;
me->ops = &isif_media_ops;
- status = media_entity_init(me, ISIF_PADS_NUM, pads, 0);
+ status = media_entity_pads_init(me, ISIF_PADS_NUM, pads);
if (status)
goto isif_fail;
isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
index d892fee3f52f..a91395ce91e1 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
@@ -1648,10 +1648,15 @@ static int resizer_link_setup(struct media_entity *entity,
struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
u16 ipipe_source = vpfe_dev->vpfe_ipipe.output;
+ unsigned int index = local->index;
+
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
if (&resizer->crop_resizer.subdev == sd) {
- switch (local->index | media_entity_type(remote->entity)) {
- case RESIZER_CROP_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ switch (index) {
+ case RESIZER_CROP_PAD_SINK | 2 << 16:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->crop_resizer.input =
RESIZER_CROP_INPUT_NONE;
@@ -1671,7 +1676,7 @@ static int resizer_link_setup(struct media_entity *entity,
return -EINVAL;
break;
- case RESIZER_CROP_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case RESIZER_CROP_PAD_SOURCE | 2 << 16:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->crop_resizer.output =
RESIZER_CROP_OUTPUT_NONE;
@@ -1683,7 +1688,7 @@ static int resizer_link_setup(struct media_entity *entity,
resizer->crop_resizer.output = RESIZER_A;
break;
- case RESIZER_CROP_PAD_SOURCE2 | MEDIA_ENT_T_V4L2_SUBDEV:
+ case RESIZER_CROP_PAD_SOURCE2 | 2 << 16:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->crop_resizer.output2 =
RESIZER_CROP_OUTPUT_NONE;
@@ -1699,8 +1704,8 @@ static int resizer_link_setup(struct media_entity *entity,
return -EINVAL;
}
} else if (&resizer->resizer_a.subdev == sd) {
- switch (local->index | media_entity_type(remote->entity)) {
- case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ switch (index) {
+ case RESIZER_PAD_SINK | 2 << 16:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->resizer_a.input = RESIZER_INPUT_NONE;
break;
@@ -1710,7 +1715,7 @@ static int resizer_link_setup(struct media_entity *entity,
resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER;
break;
- case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ case RESIZER_PAD_SOURCE:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->resizer_a.output = RESIZER_OUTPUT_NONE;
break;
@@ -1724,8 +1729,8 @@ static int resizer_link_setup(struct media_entity *entity,
return -EINVAL;
}
} else if (&resizer->resizer_b.subdev == sd) {
- switch (local->index | media_entity_type(remote->entity)) {
- case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ switch (index) {
+ case RESIZER_PAD_SINK | 2 << 16:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->resizer_b.input = RESIZER_INPUT_NONE;
break;
@@ -1735,7 +1740,7 @@ static int resizer_link_setup(struct media_entity *entity,
resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER;
break;
- case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ case RESIZER_PAD_SOURCE:
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->resizer_b.output = RESIZER_OUTPUT_NONE;
break;
@@ -1826,27 +1831,27 @@ int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
resizer->resizer_b.video_out.vpfe_dev = vpfe_dev;
/* create link between Resizer Crop----> Resizer A*/
- ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 1,
+ ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 1,
&resizer->resizer_a.subdev.entity,
0, flags);
if (ret < 0)
goto out_create_link;
/* create link between Resizer Crop----> Resizer B*/
- ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 2,
+ ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 2,
&resizer->resizer_b.subdev.entity,
0, flags);
if (ret < 0)
goto out_create_link;
/* create link between Resizer A ----> video out */
- ret = media_entity_create_link(&resizer->resizer_a.subdev.entity, 1,
+ ret = media_create_pad_link(&resizer->resizer_a.subdev.entity, 1,
&resizer->resizer_a.video_out.video_dev.entity, 0, flags);
if (ret < 0)
goto out_create_link;
/* create link between Resizer B ----> video out */
- ret = media_entity_create_link(&resizer->resizer_b.subdev.entity, 1,
+ ret = media_create_pad_link(&resizer->resizer_b.subdev.entity, 1,
&resizer->resizer_b.video_out.video_dev.entity, 0, flags);
if (ret < 0)
goto out_create_link;
@@ -1910,7 +1915,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE;
vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz;
me->ops = &resizer_media_ops;
- ret = media_entity_init(me, RESIZER_CROP_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, RESIZER_CROP_PADS_NUM, pads);
if (ret)
return ret;
@@ -1932,7 +1937,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE;
vpfe_rsz->resizer_a.rsz_device = vpfe_rsz;
me->ops = &resizer_media_ops;
- ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
if (ret)
return ret;
@@ -1954,7 +1959,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE;
vpfe_rsz->resizer_b.rsz_device = vpfe_rsz;
me->ops = &resizer_media_ops;
- ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
if (ret)
return ret;
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index 69b678ca40c0..ec46f366dd17 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -445,32 +445,32 @@ static int vpfe_register_entities(struct vpfe_device *vpfe_dev)
/* if entity has no pads (ex: amplifier),
cant establish link */
if (vpfe_dev->sd[i]->entity.num_pads) {
- ret = media_entity_create_link(&vpfe_dev->sd[i]->entity,
+ ret = media_create_pad_link(&vpfe_dev->sd[i]->entity,
0, &vpfe_dev->vpfe_isif.subdev.entity,
0, flags);
if (ret < 0)
goto out_resizer_register;
}
- ret = media_entity_create_link(&vpfe_dev->vpfe_isif.subdev.entity, 1,
+ ret = media_create_pad_link(&vpfe_dev->vpfe_isif.subdev.entity, 1,
&vpfe_dev->vpfe_ipipeif.subdev.entity,
0, flags);
if (ret < 0)
goto out_resizer_register;
- ret = media_entity_create_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1,
+ ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1,
&vpfe_dev->vpfe_ipipe.subdev.entity,
0, flags);
if (ret < 0)
goto out_resizer_register;
- ret = media_entity_create_link(&vpfe_dev->vpfe_ipipe.subdev.entity,
+ ret = media_create_pad_link(&vpfe_dev->vpfe_ipipe.subdev.entity,
1, &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity,
0, flags);
if (ret < 0)
goto out_resizer_register;
- ret = media_entity_create_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1,
+ ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1,
&vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity,
0, flags);
if (ret < 0)
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index adb2bc8811ab..3ec7e65a3ffa 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -88,7 +88,7 @@ vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
{
struct media_pad *remote = media_entity_remote_pad(&video->pad);
- if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
if (pad)
*pad = remote->index;
@@ -127,13 +127,14 @@ __vpfe_video_get_format(struct vpfe_video_device *video,
}
/* make a note of pipeline details */
-static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
+static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
{
+ struct media_entity_graph graph;
struct media_entity *entity = &video->video_dev.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
struct vpfe_pipeline *pipe = &video->pipe;
struct vpfe_video_device *far_end = NULL;
- struct media_entity_graph graph;
+ int ret;
pipe->input_num = 0;
pipe->output_num = 0;
@@ -144,11 +145,16 @@ static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
pipe->outputs[pipe->output_num++] = video;
mutex_lock(&mdev->graph_mutex);
+ ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+ if (ret) {
+ mutex_unlock(&video->lock);
+ return -ENOMEM;
+ }
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
if (entity == &video->video_dev.entity)
continue;
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ if (!is_media_entity_v4l2_io(entity))
continue;
far_end = to_vpfe_video(media_entity_to_video_device(entity));
if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
@@ -156,7 +162,10 @@ static void vpfe_prepare_pipeline(struct vpfe_video_device *video)
else
pipe->outputs[pipe->output_num++] = far_end;
}
+ media_entity_graph_walk_cleanup(&graph);
mutex_unlock(&mdev->graph_mutex);
+
+ return 0;
}
/* update pipe state selected by user */
@@ -165,7 +174,9 @@ static int vpfe_update_pipe_state(struct vpfe_video_device *video)
struct vpfe_pipeline *pipe = &video->pipe;
int ret;
- vpfe_prepare_pipeline(video);
+ ret = vpfe_prepare_pipeline(video);
+ if (ret)
+ return ret;
/* Find out if there is any input video
if yes, it is single shot.
@@ -243,8 +254,7 @@ static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
/* Retrieve the source format */
pad = media_entity_remote_pad(pad);
- if (pad == NULL ||
- pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
subdev = media_entity_to_v4l2_subdev(pad->entity);
@@ -277,29 +287,35 @@ static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
*/
static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
{
- struct media_entity_graph graph;
struct media_entity *entity;
struct v4l2_subdev *subdev;
struct media_device *mdev;
- int ret = 0;
+ int ret;
if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
entity = vpfe_get_input_entity(pipe->outputs[0]);
else
entity = &pipe->inputs[0]->video_dev.entity;
- mdev = entity->parent;
+ mdev = entity->graph_obj.mdev;
mutex_lock(&mdev->graph_mutex);
- media_entity_graph_walk_start(&graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
+ ret = media_entity_graph_walk_init(&pipe->graph,
+ entity->graph_obj.mdev);
+ if (ret)
+ goto out;
+ media_entity_graph_walk_start(&pipe->graph, entity);
+ while ((entity = media_entity_graph_walk_next(&pipe->graph))) {
- if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+ if (!is_media_entity_v4l2_subdev(entity))
continue;
subdev = media_entity_to_v4l2_subdev(entity);
ret = v4l2_subdev_call(subdev, video, s_stream, 1);
if (ret < 0 && ret != -ENOIOCTLCMD)
break;
}
+out:
+ if (ret)
+ media_entity_graph_walk_cleanup(&pipe->graph);
mutex_unlock(&mdev->graph_mutex);
return ret;
}
@@ -317,7 +333,6 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
*/
static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
{
- struct media_entity_graph graph;
struct media_entity *entity;
struct v4l2_subdev *subdev;
struct media_device *mdev;
@@ -328,13 +343,13 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
else
entity = &pipe->inputs[0]->video_dev.entity;
- mdev = entity->parent;
+ mdev = entity->graph_obj.mdev;
mutex_lock(&mdev->graph_mutex);
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(&pipe->graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
+ while ((entity = media_entity_graph_walk_next(&pipe->graph))) {
- if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+ if (!is_media_entity_v4l2_subdev(entity))
continue;
subdev = media_entity_to_v4l2_subdev(entity);
ret = v4l2_subdev_call(subdev, video, s_stream, 0);
@@ -343,6 +358,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
}
mutex_unlock(&mdev->graph_mutex);
+ media_entity_graph_walk_cleanup(&pipe->graph);
return ret ? -ETIMEDOUT : 0;
}
@@ -1600,8 +1616,8 @@ int vpfe_video_init(struct vpfe_video_device *video, const char *name)
spin_lock_init(&video->irqlock);
spin_lock_init(&video->dma_queue_lock);
mutex_init(&video->lock);
- ret = media_entity_init(&video->video_dev.entity,
- 1, &video->pad, 0);
+ ret = media_entity_pads_init(&video->video_dev.entity,
+ 1, &video->pad);
if (ret < 0)
return ret;
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h
index 673cefe3ef61..653334d537d3 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.h
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.h
@@ -52,6 +52,7 @@ enum vpfe_video_state {
struct vpfe_pipeline {
/* media pipeline */
struct media_pipeline *pipe;
+ struct media_entity_graph graph;
/* state of the pipeline, continuous,
* single-shot or stopped
*/
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index e27a988540a6..30b473cfb020 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -389,15 +389,15 @@ static irqreturn_t iss_isr(int irq, void *_iss)
*
* Return the total number of users of all video device nodes in the pipeline.
*/
-static int iss_pipeline_pm_use_count(struct media_entity *entity)
+static int iss_pipeline_pm_use_count(struct media_entity *entity,
+ struct media_entity_graph *graph)
{
- struct media_entity_graph graph;
int use = 0;
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while ((entity = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+ while ((entity = media_entity_graph_walk_next(graph))) {
+ if (is_media_entity_v4l2_io(entity))
use += entity->use_count;
}
@@ -419,7 +419,7 @@ static int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
{
struct v4l2_subdev *subdev;
- subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+ subdev = is_media_entity_v4l2_subdev(entity)
? media_entity_to_v4l2_subdev(entity) : NULL;
if (entity->use_count == 0 && change > 0 && subdev) {
@@ -449,29 +449,29 @@ static int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
*
* Return 0 on success or a negative error code on failure.
*/
-static int iss_pipeline_pm_power(struct media_entity *entity, int change)
+static int iss_pipeline_pm_power(struct media_entity *entity, int change,
+ struct media_entity_graph *graph)
{
- struct media_entity_graph graph;
struct media_entity *first = entity;
int ret = 0;
if (!change)
return 0;
- media_entity_graph_walk_start(&graph, entity);
+ media_entity_graph_walk_start(graph, entity);
- while (!ret && (entity = media_entity_graph_walk_next(&graph)))
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ while (!ret && (entity = media_entity_graph_walk_next(graph)))
+ if (is_media_entity_v4l2_subdev(entity))
ret = iss_pipeline_pm_power_one(entity, change);
if (!ret)
return 0;
- media_entity_graph_walk_start(&graph, first);
+ media_entity_graph_walk_start(graph, first);
- while ((first = media_entity_graph_walk_next(&graph)) &&
+ while ((first = media_entity_graph_walk_next(graph)) &&
first != entity)
- if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+ if (is_media_entity_v4l2_subdev(first))
iss_pipeline_pm_power_one(first, -change);
return ret;
@@ -489,23 +489,24 @@ static int iss_pipeline_pm_power(struct media_entity *entity, int change)
* off is assumed to never fail. No failure can occur when the use parameter is
* set to 0.
*/
-int omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
+int omap4iss_pipeline_pm_use(struct media_entity *entity, int use,
+ struct media_entity_graph *graph)
{
int change = use ? 1 : -1;
int ret;
- mutex_lock(&entity->parent->graph_mutex);
+ mutex_lock(&entity->graph_obj.mdev->graph_mutex);
/* Apply use count to node. */
entity->use_count += change;
WARN_ON(entity->use_count < 0);
/* Apply power change to connected non-nodes. */
- ret = iss_pipeline_pm_power(entity, change);
+ ret = iss_pipeline_pm_power(entity, change, graph);
if (ret < 0)
entity->use_count -= change;
- mutex_unlock(&entity->parent->graph_mutex);
+ mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
return ret;
}
@@ -526,34 +527,48 @@ int omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
unsigned int notification)
{
+ struct media_entity_graph *graph =
+ &container_of(link->graph_obj.mdev, struct iss_device,
+ media_dev)->pm_count_graph;
struct media_entity *source = link->source->entity;
struct media_entity *sink = link->sink->entity;
- int source_use = iss_pipeline_pm_use_count(source);
- int sink_use = iss_pipeline_pm_use_count(sink);
+ int source_use;
+ int sink_use;
int ret;
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
+ ret = media_entity_graph_walk_init(graph,
+ link->graph_obj.mdev);
+ if (ret)
+ return ret;
+ }
+
+ source_use = iss_pipeline_pm_use_count(source, graph);
+ sink_use = iss_pipeline_pm_use_count(sink, graph);
+
if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
- !(link->flags & MEDIA_LNK_FL_ENABLED)) {
+ !(flags & MEDIA_LNK_FL_ENABLED)) {
/* Powering off entities is assumed to never fail. */
- iss_pipeline_pm_power(source, -sink_use);
- iss_pipeline_pm_power(sink, -source_use);
+ iss_pipeline_pm_power(source, -sink_use, graph);
+ iss_pipeline_pm_power(sink, -source_use, graph);
return 0;
}
- if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
(flags & MEDIA_LNK_FL_ENABLED)) {
- ret = iss_pipeline_pm_power(source, sink_use);
+ ret = iss_pipeline_pm_power(source, sink_use, graph);
if (ret < 0)
return ret;
- ret = iss_pipeline_pm_power(sink, source_use);
+ ret = iss_pipeline_pm_power(sink, source_use, graph);
if (ret < 0)
- iss_pipeline_pm_power(source, -sink_use);
-
- return ret;
+ iss_pipeline_pm_power(source, -sink_use, graph);
}
- return 0;
+ if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH)
+ media_entity_graph_walk_cleanup(graph);
+
+ return ret;
}
/* -----------------------------------------------------------------------------
@@ -590,8 +605,7 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe,
break;
pad = media_entity_remote_pad(pad);
- if (!pad ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -607,7 +621,7 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe,
* crashed. Mark it as such, the ISS will be reset when
* applications will release it.
*/
- iss->crashed |= 1U << subdev->entity.id;
+ media_entity_enum_set(&iss->crashed, &subdev->entity);
failure = -ETIMEDOUT;
}
}
@@ -642,7 +656,7 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe,
* pipeline won't start anyway (those entities would then likely fail to
* stop, making the problem worse).
*/
- if (pipe->entities & iss->crashed)
+ if (media_entity_enum_intersects(&pipe->ent_enum, &iss->crashed))
return -EIO;
spin_lock_irqsave(&pipe->lock, flags);
@@ -658,8 +672,7 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe,
break;
pad = media_entity_remote_pad(pad);
- if (!pad ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
entity = pad->entity;
@@ -763,7 +776,8 @@ static int iss_reset(struct iss_device *iss)
return -ETIMEDOUT;
}
- iss->crashed = 0;
+ media_entity_enum_zero(&iss->crashed);
+
return 0;
}
@@ -1092,7 +1106,7 @@ void omap4iss_put(struct iss_device *iss)
* be worth investigating whether resetting the ISP only can't
* fix the problem in some cases.
*/
- if (iss->crashed)
+ if (!media_entity_enum_empty(&iss->crashed))
iss_reset(iss);
iss_disable_clocks(iss);
}
@@ -1259,7 +1273,7 @@ static int iss_register_entities(struct iss_device *iss)
goto done;
}
- ret = media_entity_create_link(&sensor->entity, 0, input, pad,
+ ret = media_create_pad_link(&sensor->entity, 0, input, pad,
flags);
if (ret < 0)
goto done;
@@ -1274,6 +1288,68 @@ done:
return ret;
}
+/*
+ * iss_create_links() - Pads links creation for the subdevices
+ * @iss : Pointer to ISS device
+ *
+ * return negative error code or zero on success
+ */
+static int iss_create_links(struct iss_device *iss)
+{
+ int ret;
+
+ ret = omap4iss_csi2_create_links(iss);
+ if (ret < 0) {
+ dev_err(iss->dev, "CSI2 pads links creation failed\n");
+ return ret;
+ }
+
+ ret = omap4iss_ipipeif_create_links(iss);
+ if (ret < 0) {
+ dev_err(iss->dev, "ISP IPIPEIF pads links creation failed\n");
+ return ret;
+ }
+
+ ret = omap4iss_resizer_create_links(iss);
+ if (ret < 0) {
+ dev_err(iss->dev, "ISP RESIZER pads links creation failed\n");
+ return ret;
+ }
+
+ /* Connect the submodules. */
+ ret = media_create_pad_link(
+ &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
+ &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
+ &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
+ &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
+ &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = media_create_pad_link(
+ &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
+ &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+};
+
static void iss_cleanup_modules(struct iss_device *iss)
{
omap4iss_csi2_cleanup(iss);
@@ -1316,41 +1392,8 @@ static int iss_initialize_modules(struct iss_device *iss)
goto error_resizer;
}
- /* Connect the submodules. */
- ret = media_entity_create_link(
- &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
- &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
- &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
- &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
- &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
- ret = media_entity_create_link(
- &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
- &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap4iss_resizer_cleanup(iss);
error_resizer:
omap4iss_ipipe_cleanup(iss);
error_ipipe:
@@ -1464,10 +1507,21 @@ static int iss_probe(struct platform_device *pdev)
if (ret < 0)
goto error_modules;
+ ret = media_entity_enum_init(&iss->crashed, &iss->media_dev);
+ if (ret)
+ goto error_entities;
+
+ ret = iss_create_links(iss);
+ if (ret < 0)
+ goto error_entities;
+
omap4iss_put(iss);
return 0;
+error_entities:
+ iss_unregister_entities(iss);
+ media_entity_enum_cleanup(&iss->crashed);
error_modules:
iss_cleanup_modules(iss);
error_iss:
@@ -1485,6 +1539,7 @@ static int iss_remove(struct platform_device *pdev)
struct iss_device *iss = platform_get_drvdata(pdev);
iss_unregister_entities(iss);
+ media_entity_enum_cleanup(&iss->crashed);
iss_cleanup_modules(iss);
return 0;
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index 5929357fe687..05f08a3caa19 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -82,11 +82,12 @@ struct iss_reg {
/*
* struct iss_device - ISS device structure.
* @syscon: Regmap for the syscon register space
- * @crashed: Bitmask of crashed entities (indexed by entity ID)
+ * @crashed: Crashed entities
*/
struct iss_device {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
+ struct media_entity_graph pm_count_graph;
struct device *dev;
u32 revision;
@@ -101,7 +102,7 @@ struct iss_device {
u64 raw_dmamask;
struct mutex iss_mutex; /* For handling ref_count field */
- unsigned int crashed;
+ struct media_entity_enum crashed;
int has_context;
int ref_count;
@@ -151,7 +152,8 @@ void omap4iss_isp_subclk_enable(struct iss_device *iss,
void omap4iss_isp_subclk_disable(struct iss_device *iss,
enum iss_isp_subclk_resource res);
-int omap4iss_pipeline_pm_use(struct media_entity *entity, int use);
+int omap4iss_pipeline_pm_use(struct media_entity *entity, int use,
+ struct media_entity_graph *graph);
int omap4iss_register_entities(struct platform_device *pdev,
struct v4l2_device *v4l2_dev);
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index b941035139ae..aaca39d751a5 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -1170,14 +1170,19 @@ static int csi2_link_setup(struct media_entity *entity,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct iss_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
+ unsigned int index = local->index;
+
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
/*
* The ISS core doesn't support pipelines with multiple video outputs.
* Revisit this when it will be implemented, and return -EBUSY for now.
*/
- switch (local->index | media_entity_type(remote->entity)) {
- case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ switch (index) {
+ case CSI2_PAD_SOURCE:
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->output & ~CSI2_OUTPUT_MEMORY)
return -EBUSY;
@@ -1187,7 +1192,7 @@ static int csi2_link_setup(struct media_entity *entity,
}
break;
- case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ case CSI2_PAD_SOURCE | 2 << 16:
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->output & ~CSI2_OUTPUT_IPIPEIF)
return -EBUSY;
@@ -1271,7 +1276,7 @@ static int csi2_init_entities(struct iss_csi2_device *csi2, const char *subname)
pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
me->ops = &csi2_media_ops;
- ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -1290,16 +1295,8 @@ static int csi2_init_entities(struct iss_csi2_device *csi2, const char *subname)
if (ret < 0)
goto error_video;
- /* Connect the CSI2 subdev to the video node. */
- ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
- &csi2->video_out.video.entity, 0, 0);
- if (ret < 0)
- goto error_link;
-
return 0;
-error_link:
- omap4iss_video_cleanup(&csi2->video_out);
error_video:
media_entity_cleanup(&csi2->subdev.entity);
return ret;
@@ -1342,6 +1339,33 @@ int omap4iss_csi2_init(struct iss_device *iss)
}
/*
+ * omap4iss_csi2_create_links() - CSI2 pads links creation
+ * @iss: Pointer to ISS device
+ *
+ * return negative error code or zero on success
+ */
+int omap4iss_csi2_create_links(struct iss_device *iss)
+{
+ struct iss_csi2_device *csi2a = &iss->csi2a;
+ struct iss_csi2_device *csi2b = &iss->csi2b;
+ int ret;
+
+ /* Connect the CSI2a subdev to the video node. */
+ ret = media_create_pad_link(&csi2a->subdev.entity, CSI2_PAD_SOURCE,
+ &csi2a->video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Connect the CSI2b subdev to the video node. */
+ ret = media_create_pad_link(&csi2b->subdev.entity, CSI2_PAD_SOURCE,
+ &csi2b->video_out.video.entity, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
* omap4iss_csi2_cleanup - Routine for module driver cleanup
*/
void omap4iss_csi2_cleanup(struct iss_device *iss)
diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h
index f2f5343b4a80..24ab378d469f 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.h
+++ b/drivers/staging/media/omap4iss/iss_csi2.h
@@ -151,6 +151,7 @@ struct iss_csi2_device {
void omap4iss_csi2_isr(struct iss_csi2_device *csi2);
int omap4iss_csi2_reset(struct iss_csi2_device *csi2);
int omap4iss_csi2_init(struct iss_device *iss);
+int omap4iss_csi2_create_links(struct iss_device *iss);
void omap4iss_csi2_cleanup(struct iss_device *iss);
void omap4iss_csi2_unregister_entities(struct iss_csi2_device *csi2);
int omap4iss_csi2_register_entities(struct iss_csi2_device *csi2,
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c
index dd0abeffd893..d38782e8e84c 100644
--- a/drivers/staging/media/omap4iss/iss_ipipe.c
+++ b/drivers/staging/media/omap4iss/iss_ipipe.c
@@ -447,8 +447,11 @@ static int ipipe_link_setup(struct media_entity *entity,
struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
struct iss_device *iss = to_iss_device(ipipe);
- switch (local->index | media_entity_type(remote->entity)) {
- case IPIPE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (!is_media_entity_v4l2_subdev(remote->entity))
+ return -EINVAL;
+
+ switch (local->index) {
+ case IPIPE_PAD_SINK:
/* Read from IPIPEIF. */
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
ipipe->input = IPIPE_INPUT_NONE;
@@ -463,7 +466,7 @@ static int ipipe_link_setup(struct media_entity *entity,
break;
- case IPIPE_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+ case IPIPE_PAD_SOURCE_VP:
/* Send to RESIZER */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ipipe->output & ~IPIPE_OUTPUT_VP)
@@ -513,7 +516,7 @@ static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &ipipe_media_ops;
- ret = media_entity_init(me, IPIPE_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, IPIPE_PADS_NUM, pads);
if (ret < 0)
return ret;
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
index 5f9e449e7007..23de8330731d 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.c
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.c
@@ -662,9 +662,14 @@ static int ipipeif_link_setup(struct media_entity *entity,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
struct iss_device *iss = to_iss_device(ipipeif);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case IPIPEIF_PAD_SINK | 2 << 16:
/* Read from the sensor CSI2a or CSI2b. */
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
ipipeif->input = IPIPEIF_INPUT_NONE;
@@ -681,7 +686,7 @@ static int ipipeif_link_setup(struct media_entity *entity,
break;
- case IPIPEIF_PAD_SOURCE_ISIF_SF | MEDIA_ENT_T_DEVNODE:
+ case IPIPEIF_PAD_SOURCE_ISIF_SF:
/* Write to memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY)
@@ -692,7 +697,7 @@ static int ipipeif_link_setup(struct media_entity *entity,
}
break;
- case IPIPEIF_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+ case IPIPEIF_PAD_SOURCE_VP | 2 << 16:
/* Send to IPIPE/RESIZER */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (ipipeif->output & ~IPIPEIF_OUTPUT_VP)
@@ -743,7 +748,7 @@ static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif)
pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &ipipeif_media_ops;
- ret = media_entity_init(me, IPIPEIF_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, IPIPEIF_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -757,18 +762,7 @@ static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif)
ipipeif->video_out.bpl_zero_padding = 1;
ipipeif->video_out.bpl_max = 0x1ffe0;
- ret = omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF");
- if (ret < 0)
- return ret;
-
- /* Connect the IPIPEIF subdev to the video node. */
- ret = media_entity_create_link(&ipipeif->subdev.entity,
- IPIPEIF_PAD_SOURCE_ISIF_SF,
- &ipipeif->video_out.video.entity, 0, 0);
- if (ret < 0)
- return ret;
-
- return 0;
+ return omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF");
}
void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif)
@@ -821,6 +815,22 @@ int omap4iss_ipipeif_init(struct iss_device *iss)
}
/*
+ * omap4iss_ipipeif_create_links() - IPIPEIF pads links creation
+ * @iss: Pointer to ISS device
+ *
+ * return negative error code or zero on success
+ */
+int omap4iss_ipipeif_create_links(struct iss_device *iss)
+{
+ struct iss_ipipeif_device *ipipeif = &iss->ipipeif;
+
+ /* Connect the IPIPEIF subdev to the video node. */
+ return media_create_pad_link(&ipipeif->subdev.entity,
+ IPIPEIF_PAD_SOURCE_ISIF_SF,
+ &ipipeif->video_out.video.entity, 0, 0);
+}
+
+/*
* omap4iss_ipipeif_cleanup - IPIPEIF module cleanup.
* @iss: Device pointer specific to the OMAP4 ISS.
*/
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.h b/drivers/staging/media/omap4iss/iss_ipipeif.h
index c6bd96d9656c..bad32b1d6ad8 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.h
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.h
@@ -78,6 +78,7 @@ struct iss_ipipeif_device {
struct iss_device;
int omap4iss_ipipeif_init(struct iss_device *iss);
+int omap4iss_ipipeif_create_links(struct iss_device *iss);
void omap4iss_ipipeif_cleanup(struct iss_device *iss);
int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif,
struct v4l2_device *vdev);
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index 108961e05f53..f1d352c711d5 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -716,9 +716,14 @@ static int resizer_link_setup(struct media_entity *entity,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
struct iss_device *iss = to_iss_device(resizer);
+ unsigned int index = local->index;
- switch (local->index | media_entity_type(remote->entity)) {
- case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ /* FIXME: this is actually a hack! */
+ if (is_media_entity_v4l2_subdev(remote->entity))
+ index |= 2 << 16;
+
+ switch (index) {
+ case RESIZER_PAD_SINK | 2 << 16:
/* Read from IPIPE or IPIPEIF. */
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
resizer->input = RESIZER_INPUT_NONE;
@@ -735,7 +740,7 @@ static int resizer_link_setup(struct media_entity *entity,
break;
- case RESIZER_PAD_SOURCE_MEM | MEDIA_ENT_T_DEVNODE:
+ case RESIZER_PAD_SOURCE_MEM:
/* Write to memory */
if (flags & MEDIA_LNK_FL_ENABLED) {
if (resizer->output & ~RESIZER_OUTPUT_MEMORY)
@@ -785,7 +790,7 @@ static int resizer_init_entities(struct iss_resizer_device *resizer)
pads[RESIZER_PAD_SOURCE_MEM].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &resizer_media_ops;
- ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
+ ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
if (ret < 0)
return ret;
@@ -799,18 +804,7 @@ static int resizer_init_entities(struct iss_resizer_device *resizer)
resizer->video_out.bpl_zero_padding = 1;
resizer->video_out.bpl_max = 0x1ffe0;
- ret = omap4iss_video_init(&resizer->video_out, "ISP resizer a");
- if (ret < 0)
- return ret;
-
- /* Connect the RESIZER subdev to the video node. */
- ret = media_entity_create_link(&resizer->subdev.entity,
- RESIZER_PAD_SOURCE_MEM,
- &resizer->video_out.video.entity, 0, 0);
- if (ret < 0)
- return ret;
-
- return 0;
+ return omap4iss_video_init(&resizer->video_out, "ISP resizer a");
}
void omap4iss_resizer_unregister_entities(struct iss_resizer_device *resizer)
@@ -863,6 +857,22 @@ int omap4iss_resizer_init(struct iss_device *iss)
}
/*
+ * omap4iss_resizer_create_links() - RESIZER pads links creation
+ * @iss: Pointer to ISS device
+ *
+ * return negative error code or zero on success
+ */
+int omap4iss_resizer_create_links(struct iss_device *iss)
+{
+ struct iss_resizer_device *resizer = &iss->resizer;
+
+ /* Connect the RESIZER subdev to the video node. */
+ return media_create_pad_link(&resizer->subdev.entity,
+ RESIZER_PAD_SOURCE_MEM,
+ &resizer->video_out.video.entity, 0, 0);
+}
+
+/*
* omap4iss_resizer_cleanup - RESIZER module cleanup.
* @iss: Device pointer specific to the OMAP4 ISS.
*/
diff --git a/drivers/staging/media/omap4iss/iss_resizer.h b/drivers/staging/media/omap4iss/iss_resizer.h
index 1e145abafc65..8b7c5fe9ffed 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.h
+++ b/drivers/staging/media/omap4iss/iss_resizer.h
@@ -61,6 +61,7 @@ struct iss_resizer_device {
struct iss_device;
int omap4iss_resizer_init(struct iss_device *iss);
+int omap4iss_resizer_create_links(struct iss_device *iss);
void omap4iss_resizer_cleanup(struct iss_device *iss);
int omap4iss_resizer_register_entities(struct iss_resizer_device *resizer,
struct v4l2_device *vdev);
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index e9aeca08986f..058233a9de67 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -190,8 +190,7 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad)
remote = media_entity_remote_pad(&video->pad);
- if (!remote ||
- media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
if (pad)
@@ -206,17 +205,23 @@ iss_video_far_end(struct iss_video *video)
{
struct media_entity_graph graph;
struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
struct iss_video *far_end = NULL;
mutex_lock(&mdev->graph_mutex);
+
+ if (media_entity_graph_walk_init(&graph, mdev)) {
+ mutex_unlock(&mdev->graph_mutex);
+ return NULL;
+ }
+
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
if (entity == &video->video.entity)
continue;
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ if (!is_media_entity_v4l2_io(entity))
continue;
far_end = to_iss_video(media_entity_to_video_device(entity));
@@ -227,6 +232,9 @@ iss_video_far_end(struct iss_video *video)
}
mutex_unlock(&mdev->graph_mutex);
+
+ media_entity_graph_walk_cleanup(&graph);
+
return far_end;
}
@@ -750,7 +758,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
struct iss_video_fh *vfh = to_iss_video_fh(fh);
struct iss_video *video = video_drvdata(file);
struct media_entity_graph graph;
- struct media_entity *entity;
+ struct media_entity *entity = &video->video.entity;
enum iss_pipeline_state state;
struct iss_pipeline *pipe;
struct iss_video *far_end;
@@ -765,24 +773,30 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
/* Start streaming on the pipeline. No link touching an entity in the
* pipeline can be activated or deactivated once streaming is started.
*/
- pipe = video->video.entity.pipe
- ? to_iss_pipeline(&video->video.entity) : &video->pipe;
+ pipe = entity->pipe
+ ? to_iss_pipeline(entity) : &video->pipe;
pipe->external = NULL;
pipe->external_rate = 0;
pipe->external_bpp = 0;
- pipe->entities = 0;
+
+ ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
+ if (ret)
+ goto err_graph_walk_init;
+
+ ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+ if (ret)
+ goto err_graph_walk_init;
if (video->iss->pdata->set_constraints)
video->iss->pdata->set_constraints(video->iss, true);
- ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+ ret = media_entity_pipeline_start(entity, &pipe->pipe);
if (ret < 0)
goto err_media_entity_pipeline_start;
- entity = &video->video.entity;
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph)))
- pipe->entities |= 1 << entity->id;
+ media_entity_enum_set(&pipe->ent_enum, entity);
/* Verify that the currently configured format matches the output of
* the connected subdev.
@@ -852,7 +866,10 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
spin_unlock_irqrestore(&video->qlock, flags);
}
+ media_entity_graph_walk_cleanup(&graph);
+
mutex_unlock(&video->stream_lock);
+
return 0;
err_omap4iss_set_stream:
@@ -864,7 +881,13 @@ err_media_entity_pipeline_start:
video->iss->pdata->set_constraints(video->iss, false);
video->queue = NULL;
+ media_entity_graph_walk_cleanup(&graph);
+
+err_graph_walk_init:
+ media_entity_enum_cleanup(&pipe->ent_enum);
+
mutex_unlock(&video->stream_lock);
+
return ret;
}
@@ -902,6 +925,8 @@ iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
vb2_streamoff(&vfh->queue, type);
video->queue = NULL;
+ media_entity_enum_cleanup(&pipe->ent_enum);
+
if (video->iss->pdata->set_constraints)
video->iss->pdata->set_constraints(video->iss, false);
media_entity_pipeline_stop(&video->video.entity);
@@ -984,7 +1009,13 @@ static int iss_video_open(struct file *file)
goto done;
}
- ret = omap4iss_pipeline_pm_use(&video->video.entity, 1);
+ ret = media_entity_graph_walk_init(&handle->graph,
+ &video->iss->media_dev);
+ if (ret)
+ goto done;
+
+ ret = omap4iss_pipeline_pm_use(&video->video.entity, 1,
+ &handle->graph);
if (ret < 0) {
omap4iss_put(video->iss);
goto done;
@@ -1023,6 +1054,7 @@ static int iss_video_open(struct file *file)
done:
if (ret < 0) {
v4l2_fh_del(&handle->vfh);
+ media_entity_graph_walk_cleanup(&handle->graph);
kfree(handle);
}
@@ -1038,12 +1070,13 @@ static int iss_video_release(struct file *file)
/* Disable streaming and free the buffers queue resources. */
iss_video_streamoff(file, vfh, video->type);
- omap4iss_pipeline_pm_use(&video->video.entity, 0);
+ omap4iss_pipeline_pm_use(&video->video.entity, 0, &handle->graph);
/* Release the videobuf2 queue */
vb2_queue_release(&handle->queue);
/* Release the file handle. */
+ media_entity_graph_walk_cleanup(&handle->graph);
v4l2_fh_del(vfh);
kfree(handle);
file->private_data = NULL;
@@ -1102,7 +1135,7 @@ int omap4iss_video_init(struct iss_video *video, const char *name)
return -EINVAL;
}
- ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+ ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
if (ret < 0)
return ret;
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index 41532eda1277..34588b7176ca 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -77,7 +77,7 @@ enum iss_pipeline_state {
/*
* struct iss_pipeline - An OMAP4 ISS hardware pipeline
- * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
+ * @ent_enum: Entities in the pipeline
* @error: A hardware error occurred during capture
*/
struct iss_pipeline {
@@ -87,7 +87,7 @@ struct iss_pipeline {
enum iss_pipeline_stream_state stream_state;
struct iss_video *input;
struct iss_video *output;
- unsigned int entities;
+ struct media_entity_enum ent_enum;
atomic_t frame_number;
bool do_propagation; /* of frame number */
bool error;
@@ -183,6 +183,7 @@ struct iss_video_fh {
struct vb2_queue queue;
struct v4l2_format format;
struct v4l2_fract timeperframe;
+ struct media_entity_graph graph;
};
#define to_iss_video_fh(fh) container_of(fh, struct iss_video_fh, vfh)
diff --git a/drivers/staging/most/aim-network/networking.h b/drivers/staging/most/aim-network/networking.h
index 1b8b434fabb0..6f346d410525 100644
--- a/drivers/staging/most/aim-network/networking.h
+++ b/drivers/staging/most/aim-network/networking.h
@@ -15,9 +15,7 @@
#include "mostcore.h"
-
void most_deliver_netinfo(struct most_interface *iface,
unsigned char link_stat, unsigned char *mac_addr);
-
#endif
diff --git a/drivers/staging/most/hdm-dim2/dim2_errors.h b/drivers/staging/most/hdm-dim2/dim2_errors.h
index 314f7de2be73..5a713df1d1d4 100644
--- a/drivers/staging/most/hdm-dim2/dim2_errors.h
+++ b/drivers/staging/most/hdm-dim2/dim2_errors.h
@@ -19,7 +19,6 @@
extern "C" {
#endif
-
/**
* MOST DIM errors.
*/
@@ -59,7 +58,6 @@ enum dim_errors_t {
DIM_ERR_OVERFLOW,
};
-
#ifdef __cplusplus
}
#endif
diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.c b/drivers/staging/most/hdm-dim2/dim2_hal.c
index c915c44f025e..172257596f1f 100644
--- a/drivers/staging/most/hdm-dim2/dim2_hal.c
+++ b/drivers/staging/most/hdm-dim2/dim2_hal.c
@@ -74,7 +74,7 @@ static inline u32 bit_mask(u8 position)
static inline bool dim_on_error(u8 error_id, const char *error_message)
{
- DIMCB_OnError(error_id, error_message);
+ dimcb_on_error(error_id, error_message);
return false;
}
@@ -151,44 +151,44 @@ static void free_dbr(int offs, int size)
static u32 dim2_read_ctr(u32 ctr_addr, u16 mdat_idx)
{
- DIMCB_IoWrite(&g.dim2->MADR, ctr_addr);
+ dimcb_io_write(&g.dim2->MADR, ctr_addr);
/* wait till transfer is completed */
- while ((DIMCB_IoRead(&g.dim2->MCTL) & 1) != 1)
+ while ((dimcb_io_read(&g.dim2->MCTL) & 1) != 1)
continue;
- DIMCB_IoWrite(&g.dim2->MCTL, 0); /* clear transfer complete */
+ dimcb_io_write(&g.dim2->MCTL, 0); /* clear transfer complete */
- return DIMCB_IoRead((&g.dim2->MDAT0) + mdat_idx);
+ return dimcb_io_read((&g.dim2->MDAT0) + mdat_idx);
}
static void dim2_write_ctr_mask(u32 ctr_addr, const u32 *mask, const u32 *value)
{
enum { MADR_WNR_BIT = 31 };
- DIMCB_IoWrite(&g.dim2->MCTL, 0); /* clear transfer complete */
+ dimcb_io_write(&g.dim2->MCTL, 0); /* clear transfer complete */
if (mask[0] != 0)
- DIMCB_IoWrite(&g.dim2->MDAT0, value[0]);
+ dimcb_io_write(&g.dim2->MDAT0, value[0]);
if (mask[1] != 0)
- DIMCB_IoWrite(&g.dim2->MDAT1, value[1]);
+ dimcb_io_write(&g.dim2->MDAT1, value[1]);
if (mask[2] != 0)
- DIMCB_IoWrite(&g.dim2->MDAT2, value[2]);
+ dimcb_io_write(&g.dim2->MDAT2, value[2]);
if (mask[3] != 0)
- DIMCB_IoWrite(&g.dim2->MDAT3, value[3]);
+ dimcb_io_write(&g.dim2->MDAT3, value[3]);
- DIMCB_IoWrite(&g.dim2->MDWE0, mask[0]);
- DIMCB_IoWrite(&g.dim2->MDWE1, mask[1]);
- DIMCB_IoWrite(&g.dim2->MDWE2, mask[2]);
- DIMCB_IoWrite(&g.dim2->MDWE3, mask[3]);
+ dimcb_io_write(&g.dim2->MDWE0, mask[0]);
+ dimcb_io_write(&g.dim2->MDWE1, mask[1]);
+ dimcb_io_write(&g.dim2->MDWE2, mask[2]);
+ dimcb_io_write(&g.dim2->MDWE3, mask[3]);
- DIMCB_IoWrite(&g.dim2->MADR, bit_mask(MADR_WNR_BIT) | ctr_addr);
+ dimcb_io_write(&g.dim2->MADR, bit_mask(MADR_WNR_BIT) | ctr_addr);
/* wait till transfer is completed */
- while ((DIMCB_IoRead(&g.dim2->MCTL) & 1) != 1)
+ while ((dimcb_io_read(&g.dim2->MCTL) & 1) != 1)
continue;
- DIMCB_IoWrite(&g.dim2->MCTL, 0); /* clear transfer complete */
+ dimcb_io_write(&g.dim2->MCTL, 0); /* clear transfer complete */
}
static inline void dim2_write_ctr(u32 ctr_addr, const u32 *value)
@@ -341,15 +341,15 @@ static void dim2_configure_channel(
dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1, sync_mfe);
/* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */
- DIMCB_IoWrite(&g.dim2->ACMR0,
- DIMCB_IoRead(&g.dim2->ACMR0) | bit_mask(ch_addr));
+ dimcb_io_write(&g.dim2->ACMR0,
+ dimcb_io_read(&g.dim2->ACMR0) | bit_mask(ch_addr));
}
static void dim2_clear_channel(u8 ch_addr)
{
/* mask interrupt for used channel, disable mlb_sys_int[0] interrupt */
- DIMCB_IoWrite(&g.dim2->ACMR0,
- DIMCB_IoRead(&g.dim2->ACMR0) & ~bit_mask(ch_addr));
+ dimcb_io_write(&g.dim2->ACMR0,
+ dimcb_io_read(&g.dim2->ACMR0) & ~bit_mask(ch_addr));
dim2_clear_cat(AHB_CAT, ch_addr);
dim2_clear_adt(ch_addr);
@@ -455,20 +455,20 @@ static inline u16 norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
static void dim2_cleanup(void)
{
/* disable MediaLB */
- DIMCB_IoWrite(&g.dim2->MLBC0, false << MLBC0_MLBEN_BIT);
+ dimcb_io_write(&g.dim2->MLBC0, false << MLBC0_MLBEN_BIT);
dim2_clear_ctram();
/* disable mlb_int interrupt */
- DIMCB_IoWrite(&g.dim2->MIEN, 0);
+ dimcb_io_write(&g.dim2->MIEN, 0);
/* clear status for all dma channels */
- DIMCB_IoWrite(&g.dim2->ACSR0, 0xFFFFFFFF);
- DIMCB_IoWrite(&g.dim2->ACSR1, 0xFFFFFFFF);
+ dimcb_io_write(&g.dim2->ACSR0, 0xFFFFFFFF);
+ dimcb_io_write(&g.dim2->ACSR1, 0xFFFFFFFF);
/* mask interrupts for all channels */
- DIMCB_IoWrite(&g.dim2->ACMR0, 0);
- DIMCB_IoWrite(&g.dim2->ACMR1, 0);
+ dimcb_io_write(&g.dim2->ACMR0, 0);
+ dimcb_io_write(&g.dim2->ACMR1, 0);
}
static void dim2_initialize(bool enable_6pin, u8 mlb_clock)
@@ -476,23 +476,23 @@ static void dim2_initialize(bool enable_6pin, u8 mlb_clock)
dim2_cleanup();
/* configure and enable MediaLB */
- DIMCB_IoWrite(&g.dim2->MLBC0,
- enable_6pin << MLBC0_MLBPEN_BIT |
- mlb_clock << MLBC0_MLBCLK_SHIFT |
- MLBC0_FCNT_VAL(FRAMES_PER_SUBBUFF) << MLBC0_FCNT_SHIFT |
- true << MLBC0_MLBEN_BIT);
+ dimcb_io_write(&g.dim2->MLBC0,
+ enable_6pin << MLBC0_MLBPEN_BIT |
+ mlb_clock << MLBC0_MLBCLK_SHIFT |
+ MLBC0_FCNT_VAL(FRAMES_PER_SUBBUFF) << MLBC0_FCNT_SHIFT |
+ true << MLBC0_MLBEN_BIT);
/* activate all HBI channels */
- DIMCB_IoWrite(&g.dim2->HCMR0, 0xFFFFFFFF);
- DIMCB_IoWrite(&g.dim2->HCMR1, 0xFFFFFFFF);
+ dimcb_io_write(&g.dim2->HCMR0, 0xFFFFFFFF);
+ dimcb_io_write(&g.dim2->HCMR1, 0xFFFFFFFF);
/* enable HBI */
- DIMCB_IoWrite(&g.dim2->HCTL, bit_mask(HCTL_EN_BIT));
+ dimcb_io_write(&g.dim2->HCTL, bit_mask(HCTL_EN_BIT));
/* configure DMA */
- DIMCB_IoWrite(&g.dim2->ACTL,
- ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT |
- true << ACTL_SCE_BIT);
+ dimcb_io_write(&g.dim2->ACTL,
+ ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT |
+ true << ACTL_SCE_BIT);
}
static bool dim2_is_mlb_locked(void)
@@ -500,12 +500,12 @@ static bool dim2_is_mlb_locked(void)
u32 const mask0 = bit_mask(MLBC0_MLBLK_BIT);
u32 const mask1 = bit_mask(MLBC1_CLKMERR_BIT) |
bit_mask(MLBC1_LOCKERR_BIT);
- u32 const c1 = DIMCB_IoRead(&g.dim2->MLBC1);
+ u32 const c1 = dimcb_io_read(&g.dim2->MLBC1);
u32 const nda_mask = (u32)MLBC1_NDA_MASK << MLBC1_NDA_SHIFT;
- DIMCB_IoWrite(&g.dim2->MLBC1, c1 & nda_mask);
- return (DIMCB_IoRead(&g.dim2->MLBC1) & mask1) == 0 &&
- (DIMCB_IoRead(&g.dim2->MLBC0) & mask0) != 0;
+ dimcb_io_write(&g.dim2->MLBC1, c1 & nda_mask);
+ return (dimcb_io_read(&g.dim2->MLBC1) & mask1) == 0 &&
+ (dimcb_io_read(&g.dim2->MLBC0) & mask0) != 0;
}
/* -------------------------------------------------------------------------- */
@@ -531,7 +531,7 @@ static inline bool service_channel(u8 ch_addr, u8 idx)
}
/* clear channel status bit */
- DIMCB_IoWrite(&g.dim2->ACSR0, bit_mask(ch_addr));
+ dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
return true;
}
@@ -650,7 +650,7 @@ static bool channel_detach_buffers(struct dim_channel *ch, u16 buffers_number)
/* -------------------------------------------------------------------------- */
/* API */
-u8 DIM_Startup(void *dim_base_address, u32 mlb_clock)
+u8 dim_startup(void *dim_base_address, u32 mlb_clock)
{
g.dim_is_initialized = false;
@@ -673,13 +673,13 @@ u8 DIM_Startup(void *dim_base_address, u32 mlb_clock)
return DIM_NO_ERROR;
}
-void DIM_Shutdown(void)
+void dim_shutdown(void)
{
g.dim_is_initialized = false;
dim2_cleanup();
}
-bool DIM_GetLockState(void)
+bool dim_get_lock_state(void)
{
return dim2_is_mlb_locked();
}
@@ -706,7 +706,7 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx,
return DIM_NO_ERROR;
}
-u16 DIM_NormCtrlAsyncBufferSize(u16 buf_size)
+u16 dim_norm_ctrl_async_buffer_size(u16 buf_size)
{
return norm_ctrl_async_buffer_size(buf_size);
}
@@ -717,7 +717,7 @@ u16 DIM_NormCtrlAsyncBufferSize(u16 buf_size)
*
* Returns non-zero correct buffer size or zero by error.
*/
-u16 DIM_NormIsocBufferSize(u16 buf_size, u16 packet_length)
+u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length)
{
if (!check_packet_length(packet_length))
return 0;
@@ -731,7 +731,7 @@ u16 DIM_NormIsocBufferSize(u16 buf_size, u16 packet_length)
*
* Returns non-zero correct buffer size or zero by error.
*/
-u16 DIM_NormSyncBufferSize(u16 buf_size, u16 bytes_per_frame)
+u16 dim_norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
{
if (!check_bytes_per_frame(bytes_per_frame))
return 0;
@@ -739,22 +739,22 @@ u16 DIM_NormSyncBufferSize(u16 buf_size, u16 bytes_per_frame)
return norm_sync_buffer_size(buf_size, bytes_per_frame);
}
-u8 DIM_InitControl(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 max_buffer_size)
+u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 max_buffer_size)
{
return init_ctrl_async(ch, CAT_CT_VAL_CONTROL, is_tx, ch_address,
max_buffer_size);
}
-u8 DIM_InitAsync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 max_buffer_size)
+u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 max_buffer_size)
{
return init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address,
max_buffer_size);
}
-u8 DIM_InitIsoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 packet_length)
+u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 packet_length)
{
if (!g.dim_is_initialized || !ch)
return DIM_ERR_DRIVER_NOT_INITIALIZED;
@@ -778,8 +778,8 @@ u8 DIM_InitIsoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
return DIM_NO_ERROR;
}
-u8 DIM_InitSync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 bytes_per_frame)
+u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 bytes_per_frame)
{
if (!g.dim_is_initialized || !ch)
return DIM_ERR_DRIVER_NOT_INITIALIZED;
@@ -803,7 +803,7 @@ u8 DIM_InitSync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
return DIM_NO_ERROR;
}
-u8 DIM_DestroyChannel(struct dim_channel *ch)
+u8 dim_destroy_channel(struct dim_channel *ch)
{
if (!g.dim_is_initialized || !ch)
return DIM_ERR_DRIVER_NOT_INITIALIZED;
@@ -816,7 +816,7 @@ u8 DIM_DestroyChannel(struct dim_channel *ch)
return DIM_NO_ERROR;
}
-void DIM_ServiceIrq(struct dim_channel *const *channels)
+void dim_service_irq(struct dim_channel *const *channels)
{
bool state_changed;
@@ -850,11 +850,11 @@ void DIM_ServiceIrq(struct dim_channel *const *channels)
} while (state_changed);
/* clear pending Interrupts */
- DIMCB_IoWrite(&g.dim2->MS0, 0);
- DIMCB_IoWrite(&g.dim2->MS1, 0);
+ dimcb_io_write(&g.dim2->MS0, 0);
+ dimcb_io_write(&g.dim2->MS1, 0);
}
-u8 DIM_ServiceChannel(struct dim_channel *ch)
+u8 dim_service_channel(struct dim_channel *ch)
{
if (!g.dim_is_initialized || !ch)
return DIM_ERR_DRIVER_NOT_INITIALIZED;
@@ -862,8 +862,8 @@ u8 DIM_ServiceChannel(struct dim_channel *ch)
return channel_service(ch);
}
-struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch,
- struct dim_ch_state_t *state_ptr)
+struct dim_ch_state_t *dim_get_channel_state(struct dim_channel *ch,
+ struct dim_ch_state_t *state_ptr)
{
if (!ch || !state_ptr)
return NULL;
@@ -874,7 +874,8 @@ struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch,
return state_ptr;
}
-bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, u16 buffer_size)
+bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
+ u16 buffer_size)
{
if (!ch)
return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
@@ -883,7 +884,7 @@ bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, u16 buffer_size)
return channel_start(ch, buffer_addr, buffer_size);
}
-bool DIM_DetachBuffers(struct dim_channel *ch, u16 buffers_number)
+bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number)
{
if (!ch)
return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.h b/drivers/staging/most/hdm-dim2/dim2_hal.h
index ebb7d87a45fc..48cdd9c8cde1 100644
--- a/drivers/staging/most/hdm-dim2/dim2_hal.h
+++ b/drivers/staging/most/hdm-dim2/dim2_hal.h
@@ -17,7 +17,6 @@
#include <linux/types.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -66,51 +65,49 @@ struct dim_channel {
u16 done_sw_buffers_number; /*< Done software buffers number. */
};
+u8 dim_startup(void *dim_base_address, u32 mlb_clock);
-u8 DIM_Startup(void *dim_base_address, u32 mlb_clock);
-
-void DIM_Shutdown(void);
-
-bool DIM_GetLockState(void);
+void dim_shutdown(void);
-u16 DIM_NormCtrlAsyncBufferSize(u16 buf_size);
+bool dim_get_lock_state(void);
-u16 DIM_NormIsocBufferSize(u16 buf_size, u16 packet_length);
+u16 dim_norm_ctrl_async_buffer_size(u16 buf_size);
-u16 DIM_NormSyncBufferSize(u16 buf_size, u16 bytes_per_frame);
+u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length);
-u8 DIM_InitControl(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 max_buffer_size);
+u16 dim_norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame);
-u8 DIM_InitAsync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 max_buffer_size);
+u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 max_buffer_size);
-u8 DIM_InitIsoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 packet_length);
+u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 max_buffer_size);
-u8 DIM_InitSync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
- u16 bytes_per_frame);
+u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 packet_length);
-u8 DIM_DestroyChannel(struct dim_channel *ch);
+u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+ u16 bytes_per_frame);
-void DIM_ServiceIrq(struct dim_channel *const *channels);
+u8 dim_destroy_channel(struct dim_channel *ch);
-u8 DIM_ServiceChannel(struct dim_channel *ch);
+void dim_service_irq(struct dim_channel *const *channels);
-struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch,
- struct dim_ch_state_t *dim_ch_state_ptr);
+u8 dim_service_channel(struct dim_channel *ch);
-bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr,
- u16 buffer_size);
+struct dim_ch_state_t *dim_get_channel_state(struct dim_channel *ch,
+ struct dim_ch_state_t *state_ptr);
-bool DIM_DetachBuffers(struct dim_channel *ch, u16 buffers_number);
+bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
+ u16 buffer_size);
-u32 DIMCB_IoRead(u32 *ptr32);
+bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number);
-void DIMCB_IoWrite(u32 *ptr32, u32 value);
+u32 dimcb_io_read(u32 *ptr32);
-void DIMCB_OnError(u8 error_id, const char *error_message);
+void dimcb_io_write(u32 *ptr32, u32 value);
+void dimcb_on_error(u8 error_id, const char *error_message);
#ifdef __cplusplus
}
diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.c b/drivers/staging/most/hdm-dim2/dim2_hdm.c
index b6fe346f73b0..327d738c7194 100644
--- a/drivers/staging/most/hdm-dim2/dim2_hdm.c
+++ b/drivers/staging/most/hdm-dim2/dim2_hdm.c
@@ -73,8 +73,8 @@ struct hdm_channel {
char name[sizeof "caNNN"];
bool is_initialized;
struct dim_channel ch;
- struct list_head pending_list; /* before DIM_EnqueueBuffer() */
- struct list_head started_list; /* after DIM_EnqueueBuffer() */
+ struct list_head pending_list; /* before dim_enqueue_buffer() */
+ struct list_head started_list; /* after dim_enqueue_buffer() */
enum most_channel_direction direction;
enum most_channel_data_type data_type;
};
@@ -128,40 +128,40 @@ bool dim2_sysfs_get_state_cb(void)
unsigned long flags;
spin_lock_irqsave(&dim_lock, flags);
- state = DIM_GetLockState();
+ state = dim_get_lock_state();
spin_unlock_irqrestore(&dim_lock, flags);
return state;
}
/**
- * DIMCB_IoRead - callback from HAL to read an I/O register
+ * dimcb_io_read - callback from HAL to read an I/O register
* @ptr32: register address
*/
-u32 DIMCB_IoRead(u32 *ptr32)
+u32 dimcb_io_read(u32 *ptr32)
{
return __raw_readl(ptr32);
}
/**
- * DIMCB_IoWrite - callback from HAL to write value to an I/O register
+ * dimcb_io_write - callback from HAL to write value to an I/O register
* @ptr32: register address
* @value: value to write
*/
-void DIMCB_IoWrite(u32 *ptr32, u32 value)
+void dimcb_io_write(u32 *ptr32, u32 value)
{
__raw_writel(value, ptr32);
}
/**
- * DIMCB_OnError - callback from HAL to report miscommunication between
+ * dimcb_on_error - callback from HAL to report miscommunication between
* HDM and HAL
* @error_id: Error ID
* @error_message: Error message. Some text in a free format
*/
-void DIMCB_OnError(u8 error_id, const char *error_message)
+void dimcb_on_error(u8 error_id, const char *error_message)
{
- pr_err("DIMCB_OnError: error_id - %d, error_message - %s\n", error_id,
+ pr_err("dimcb_on_error: error_id - %d, error_message - %s\n", error_id,
error_message);
}
@@ -212,9 +212,9 @@ static int startup_dim(struct platform_device *pdev)
return ret;
}
- hal_ret = DIM_Startup(dev->io_base, dev->clk_speed);
+ hal_ret = dim_startup(dev->io_base, dev->clk_speed);
if (hal_ret != DIM_NO_ERROR) {
- pr_err("DIM_Startup failed: %d\n", hal_ret);
+ pr_err("dim_startup failed: %d\n", hal_ret);
if (pdata && pdata->destroy)
pdata->destroy(pdata);
return -ENODEV;
@@ -246,7 +246,7 @@ static int try_start_dim_transfer(struct hdm_channel *hdm_ch)
return -EAGAIN;
}
- if (!DIM_GetChannelState(&hdm_ch->ch, &st)->ready) {
+ if (!dim_get_channel_state(&hdm_ch->ch, &st)->ready) {
spin_unlock_irqrestore(&dim_lock, flags);
return -EAGAIN;
}
@@ -255,7 +255,7 @@ static int try_start_dim_transfer(struct hdm_channel *hdm_ch)
buf_size = mbo->buffer_length;
BUG_ON(mbo->bus_address == 0);
- if (!DIM_EnqueueBuffer(&hdm_ch->ch, mbo->bus_address, buf_size)) {
+ if (!dim_enqueue_buffer(&hdm_ch->ch, mbo->bus_address, buf_size)) {
list_del(head->next);
spin_unlock_irqrestore(&dim_lock, flags);
mbo->processed_length = 0;
@@ -340,13 +340,13 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx)
spin_lock_irqsave(&dim_lock, flags);
- done_buffers = DIM_GetChannelState(&hdm_ch->ch, &st)->done_buffers;
+ done_buffers = dim_get_channel_state(&hdm_ch->ch, &st)->done_buffers;
if (!done_buffers) {
spin_unlock_irqrestore(&dim_lock, flags);
return;
}
- if (!DIM_DetachBuffers(&hdm_ch->ch, done_buffers)) {
+ if (!dim_detach_buffers(&hdm_ch->ch, done_buffers)) {
spin_unlock_irqrestore(&dim_lock, flags);
return;
}
@@ -371,7 +371,6 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx)
if (hdm_ch->data_type == MOST_CH_ASYNC &&
hdm_ch->direction == MOST_CH_RX &&
PACKET_IS_NET_INFO(data)) {
-
retrieve_netinfo(dev, mbo);
spin_lock_irqsave(&dim_lock, flags);
@@ -380,7 +379,6 @@ static void service_done_flag(struct dim2_hdm *dev, int ch_idx)
} else {
if (hdm_ch->data_type == MOST_CH_CONTROL ||
hdm_ch->data_type == MOST_CH_ASYNC) {
-
u32 const data_size =
(u32)data[0] * 256 + data[1] + 2;
@@ -430,7 +428,7 @@ static void dim2_tasklet_fn(unsigned long data)
continue;
spin_lock_irqsave(&dim_lock, flags);
- DIM_ServiceChannel(&dev->hch[ch_idx].ch);
+ dim_service_channel(&dev->hch[ch_idx].ch);
spin_unlock_irqrestore(&dim_lock, flags);
service_done_flag(dev, ch_idx);
@@ -454,7 +452,7 @@ static irqreturn_t dim2_ahb_isr(int irq, void *_dev)
unsigned long flags;
spin_lock_irqsave(&dim_lock, flags);
- DIM_ServiceIrq(get_active_channels(dev, buffer));
+ dim_service_irq(get_active_channels(dev, buffer));
spin_unlock_irqrestore(&dim_lock, flags);
#if !defined(ENABLE_HDM_TEST)
@@ -536,7 +534,7 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
switch (ccfg->data_type) {
case MOST_CH_CONTROL:
- new_size = DIM_NormCtrlAsyncBufferSize(buf_size);
+ new_size = dim_norm_ctrl_async_buffer_size(buf_size);
if (new_size == 0) {
pr_err("%s: too small buffer size\n", hdm_ch->name);
return -EINVAL;
@@ -546,11 +544,11 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
pr_warn("%s: fixed buffer size (%d -> %d)\n",
hdm_ch->name, buf_size, new_size);
spin_lock_irqsave(&dim_lock, flags);
- hal_ret = DIM_InitControl(&hdm_ch->ch, is_tx, ch_addr,
- buf_size);
+ hal_ret = dim_init_control(&hdm_ch->ch, is_tx, ch_addr,
+ buf_size);
break;
case MOST_CH_ASYNC:
- new_size = DIM_NormCtrlAsyncBufferSize(buf_size);
+ new_size = dim_norm_ctrl_async_buffer_size(buf_size);
if (new_size == 0) {
pr_err("%s: too small buffer size\n", hdm_ch->name);
return -EINVAL;
@@ -560,10 +558,10 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
pr_warn("%s: fixed buffer size (%d -> %d)\n",
hdm_ch->name, buf_size, new_size);
spin_lock_irqsave(&dim_lock, flags);
- hal_ret = DIM_InitAsync(&hdm_ch->ch, is_tx, ch_addr, buf_size);
+ hal_ret = dim_init_async(&hdm_ch->ch, is_tx, ch_addr, buf_size);
break;
case MOST_CH_ISOC_AVP:
- new_size = DIM_NormIsocBufferSize(buf_size, sub_size);
+ new_size = dim_norm_isoc_buffer_size(buf_size, sub_size);
if (new_size == 0) {
pr_err("%s: invalid sub-buffer size or too small buffer size\n",
hdm_ch->name);
@@ -574,10 +572,10 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
pr_warn("%s: fixed buffer size (%d -> %d)\n",
hdm_ch->name, buf_size, new_size);
spin_lock_irqsave(&dim_lock, flags);
- hal_ret = DIM_InitIsoc(&hdm_ch->ch, is_tx, ch_addr, sub_size);
+ hal_ret = dim_init_isoc(&hdm_ch->ch, is_tx, ch_addr, sub_size);
break;
case MOST_CH_SYNC:
- new_size = DIM_NormSyncBufferSize(buf_size, sub_size);
+ new_size = dim_norm_sync_buffer_size(buf_size, sub_size);
if (new_size == 0) {
pr_err("%s: invalid sub-buffer size or too small buffer size\n",
hdm_ch->name);
@@ -588,7 +586,7 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
pr_warn("%s: fixed buffer size (%d -> %d)\n",
hdm_ch->name, buf_size, new_size);
spin_lock_irqsave(&dim_lock, flags);
- hal_ret = DIM_InitSync(&hdm_ch->ch, is_tx, ch_addr, sub_size);
+ hal_ret = dim_init_sync(&hdm_ch->ch, is_tx, ch_addr, sub_size);
break;
default:
pr_err("%s: configure failed, bad channel type: %d\n",
@@ -708,7 +706,7 @@ static int poison_channel(struct most_interface *most_iface, int ch_idx)
return -EPERM;
spin_lock_irqsave(&dim_lock, flags);
- hal_ret = DIM_DestroyChannel(&hdm_ch->ch);
+ hal_ret = dim_destroy_channel(&hdm_ch->ch);
hdm_ch->is_initialized = false;
if (ch_idx == dev->atx_idx)
dev->atx_idx = -1;
@@ -885,7 +883,7 @@ static int dim2_remove(struct platform_device *pdev)
unsigned long flags;
spin_lock_irqsave(&dim_lock, flags);
- DIM_Shutdown();
+ dim_shutdown();
spin_unlock_irqrestore(&dim_lock, flags);
if (pdata && pdata->destroy)
diff --git a/drivers/staging/most/hdm-dim2/dim2_reg.h b/drivers/staging/most/hdm-dim2/dim2_reg.h
index 476f66f4c566..bcf6a79f6744 100644
--- a/drivers/staging/most/hdm-dim2/dim2_reg.h
+++ b/drivers/staging/most/hdm-dim2/dim2_reg.h
@@ -21,7 +21,6 @@
extern "C" {
#endif
-
struct dim2_regs {
/* 0x00 */ u32 MLBC0;
/* 0x01 */ u32 rsvd0[1];
@@ -67,8 +66,7 @@ struct dim2_regs {
/* 0xF7 */ u32 ACMR1;
};
-
-#define DIM2_MASK(n) (~((~(u32)0)<<(n)))
+#define DIM2_MASK(n) (~((~(u32)0) << (n)))
enum {
MLBC0_MLBLK_BIT = 7,
@@ -168,7 +166,6 @@ enum {
CAT_CL_MASK = DIM2_MASK(6)
};
-
#ifdef __cplusplus
}
#endif
diff --git a/drivers/staging/most/hdm-dim2/dim2_sysfs.h b/drivers/staging/most/hdm-dim2/dim2_sysfs.h
index e719691035b0..b71dd027ebc7 100644
--- a/drivers/staging/most/hdm-dim2/dim2_sysfs.h
+++ b/drivers/staging/most/hdm-dim2/dim2_sysfs.h
@@ -16,10 +16,8 @@
#ifndef DIM2_SYSFS_H
#define DIM2_SYSFS_H
-
#include <linux/kobject.h>
-
struct medialb_bus {
struct kobject kobj_group;
};
@@ -35,5 +33,4 @@ void dim2_sysfs_destroy(struct medialb_bus *bus);
*/
bool dim2_sysfs_get_state_cb(void);
-
#endif /* DIM2_SYSFS_H */
diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c
index 19852ca7e59c..ed1ed25b6d1d 100644
--- a/drivers/staging/most/mostcore/core.c
+++ b/drivers/staging/most/mostcore/core.c
@@ -1587,8 +1587,7 @@ out:
return 0;
error:
- if (iface->mod)
- module_put(iface->mod);
+ module_put(iface->mod);
modref--;
mutex_unlock(&c->start_mutex);
return ret;
diff --git a/drivers/staging/most/mostcore/mostcore.h b/drivers/staging/most/mostcore/mostcore.h
index e148b324331a..bda3850d5435 100644
--- a/drivers/staging/most/mostcore/mostcore.h
+++ b/drivers/staging/most/mostcore/mostcore.h
@@ -60,7 +60,6 @@ enum most_channel_data_type {
MOST_CH_SYNC = 1 << 5,
};
-
enum mbo_status_flags {
/* MBO was processed successfully (data was send or received )*/
MBO_SUCCESS = 0,
@@ -317,5 +316,4 @@ int most_start_channel(struct most_interface *iface, int channel_idx,
int most_stop_channel(struct most_interface *iface, int channel_idx,
struct most_aim *);
-
#endif /* MOST_CORE_H_ */
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 47bb56f1f8c0..197d1124733d 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -31,8 +31,8 @@
static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
{
- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
- struct spinand_info *info = (struct spinand_info *)chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct spinand_info *info = nand_get_controller_data(chip);
struct spinand_state *state = (struct spinand_state *)info->priv;
return state;
@@ -633,7 +633,7 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
u8 *p = buf;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
- struct spinand_info *info = (struct spinand_info *)chip->priv;
+ struct spinand_info *info = nand_get_controller_data(chip);
enable_read_hw_ecc = 1;
@@ -679,7 +679,7 @@ static u8 spinand_read_byte(struct mtd_info *mtd)
static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
- struct spinand_info *info = (struct spinand_info *)chip->priv;
+ struct spinand_info *info = nand_get_controller_data(chip);
unsigned long timeo = jiffies;
int retval, state = chip->state;
@@ -744,8 +744,8 @@ static void spinand_reset(struct spi_device *spi_nand)
static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
int column, int page)
{
- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
- struct spinand_info *info = (struct spinand_info *)chip->priv;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct spinand_info *info = nand_get_controller_data(chip);
struct spinand_state *state = (struct spinand_state *)info->priv;
switch (command) {
@@ -850,7 +850,6 @@ static int spinand_probe(struct spi_device *spi_nand)
struct nand_chip *chip;
struct spinand_info *info;
struct spinand_state *state;
- struct mtd_part_parser_data ppdata;
info = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info),
GFP_KERNEL);
@@ -894,7 +893,8 @@ static int spinand_probe(struct spi_device *spi_nand)
pr_info("%s: disable ecc failed!\n", __func__);
#endif
- chip->priv = info;
+ nand_set_flash_node(chip, spi_nand->dev.of_node);
+ nand_set_controller_data(chip, info);
chip->read_buf = spinand_read_buf;
chip->write_buf = spinand_write_buf;
chip->read_byte = spinand_read_byte;
@@ -903,21 +903,17 @@ static int spinand_probe(struct spi_device *spi_nand)
chip->options |= NAND_CACHEPRG;
chip->select_chip = spinand_select_chip;
- mtd = devm_kzalloc(&spi_nand->dev, sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd)
- return -ENOMEM;
+ mtd = nand_to_mtd(chip);
dev_set_drvdata(&spi_nand->dev, mtd);
- mtd->priv = chip;
mtd->dev.parent = &spi_nand->dev;
mtd->oobsize = 64;
if (nand_scan(mtd, 1))
return -ENXIO;
- ppdata.of_node = spi_nand->dev.of_node;
- return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ return mtd_device_register(mtd, NULL, 0);
}
/*
diff --git a/drivers/staging/nvec/README b/drivers/staging/nvec/README
index 9a320b7fdbe6..0e2d5c4c875f 100644
--- a/drivers/staging/nvec/README
+++ b/drivers/staging/nvec/README
@@ -1,4 +1,4 @@
-NVEC: An NVidia compliant Embedded Controller Protocol Implemenation
+NVEC: An NVidia compliant Embedded Controller Protocol Implementation
This is an implementation of the NVEC protocol used to communicate with an
embedded controller (EC) via I2C bus. The EC is an I2C master while the host
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 802c9597d421..4ae44a5168f9 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -40,18 +40,18 @@
#include "nvec.h"
#define I2C_CNFG 0x00
-#define I2C_CNFG_PACKET_MODE_EN (1<<10)
-#define I2C_CNFG_NEW_MASTER_SFM (1<<11)
+#define I2C_CNFG_PACKET_MODE_EN (1 << 10)
+#define I2C_CNFG_NEW_MASTER_SFM (1 << 11)
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
#define I2C_SL_CNFG 0x20
-#define I2C_SL_NEWSL (1<<2)
-#define I2C_SL_NACK (1<<1)
-#define I2C_SL_RESP (1<<0)
-#define I2C_SL_IRQ (1<<3)
-#define END_TRANS (1<<4)
-#define RCVD (1<<2)
-#define RNW (1<<1)
+#define I2C_SL_NEWSL (1 << 2)
+#define I2C_SL_NACK (1 << 1)
+#define I2C_SL_RESP (1 << 0)
+#define I2C_SL_IRQ (1 << 3)
+#define END_TRANS (1 << 4)
+#define RCVD (1 << 2)
+#define RNW (1 << 1)
#define I2C_SL_RCVD 0x24
#define I2C_SL_STATUS 0x28
@@ -740,7 +740,7 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG);
writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
- writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
+ writel(nvec->i2c_addr >> 1, nvec->base + I2C_SL_ADDR1);
writel(0, nvec->base + I2C_SL_ADDR2);
enable_irq(nvec->irq);
diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h
index 13e4cee1f86d..07bd2b87f6a0 100644
--- a/drivers/staging/octeon/ethernet-defines.h
+++ b/drivers/staging/octeon/ethernet-defines.h
@@ -40,6 +40,6 @@
#define FAU_TOTAL_TX_TO_CLEAN (CVMX_FAU_REG_END - sizeof(u32))
#define FAU_NUM_PACKET_BUFFERS_TO_FREE (FAU_TOTAL_TX_TO_CLEAN - sizeof(u32))
-#define TOTAL_NUMBER_OF_PORTS (CVMX_PIP_NUM_INPUT_PORTS+1)
+#define TOTAL_NUMBER_OF_PORTS (CVMX_PIP_NUM_INPUT_PORTS + 1)
#endif /* __ETHERNET_DEFINES_H__ */
diff --git a/drivers/staging/rdma/amso1100/c2.c b/drivers/staging/rdma/amso1100/c2.c
index 35ac536b2d45..b46ebd1ae15a 100644
--- a/drivers/staging/rdma/amso1100/c2.c
+++ b/drivers/staging/rdma/amso1100/c2.c
@@ -87,11 +87,6 @@ static struct pci_device_id c2_pci_table[] = {
MODULE_DEVICE_TABLE(pci, c2_pci_table);
-static void c2_print_macaddr(struct net_device *netdev)
-{
- pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name, netdev->dev_addr, netdev->irq);
-}
-
static void c2_set_rxbufsize(struct c2_port *c2_port)
{
struct net_device *netdev = c2_port->netdev;
@@ -116,7 +111,8 @@ static int c2_tx_ring_alloc(struct c2_ring *tx_ring, void *vaddr,
struct c2_element *elem;
int i;
- tx_ring->start = kmalloc(sizeof(*elem) * tx_ring->count, GFP_KERNEL);
+ tx_ring->start = kmalloc_array(tx_ring->count, sizeof(*elem),
+ GFP_KERNEL);
if (!tx_ring->start)
return -ENOMEM;
@@ -165,7 +161,8 @@ static int c2_rx_ring_alloc(struct c2_ring *rx_ring, void *vaddr,
struct c2_element *elem;
int i;
- rx_ring->start = kmalloc(sizeof(*elem) * rx_ring->count, GFP_KERNEL);
+ rx_ring->start = kmalloc_array(rx_ring->count, sizeof(*elem),
+ GFP_KERNEL);
if (!rx_ring->start)
return -ENOMEM;
@@ -908,7 +905,8 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev,
/* Validate the MAC address */
if (!is_valid_ether_addr(netdev->dev_addr)) {
pr_debug("Invalid MAC Address\n");
- c2_print_macaddr(netdev);
+ pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name,
+ netdev->dev_addr, netdev->irq);
free_netdev(netdev);
return NULL;
}
@@ -1142,7 +1140,8 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
}
/* Print out the MAC address */
- c2_print_macaddr(netdev);
+ pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name, netdev->dev_addr,
+ netdev->irq);
ret = c2_rnic_init(c2dev);
if (ret) {
diff --git a/drivers/staging/rdma/amso1100/c2.h b/drivers/staging/rdma/amso1100/c2.h
index d619d735838b..21b565a91fd6 100644
--- a/drivers/staging/rdma/amso1100/c2.h
+++ b/drivers/staging/rdma/amso1100/c2.h
@@ -476,72 +476,72 @@ static inline int c2_errno(void *reply)
}
/* Device */
-extern int c2_register_device(struct c2_dev *c2dev);
-extern void c2_unregister_device(struct c2_dev *c2dev);
-extern int c2_rnic_init(struct c2_dev *c2dev);
-extern void c2_rnic_term(struct c2_dev *c2dev);
-extern void c2_rnic_interrupt(struct c2_dev *c2dev);
-extern int c2_del_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask);
-extern int c2_add_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask);
+int c2_register_device(struct c2_dev *c2dev);
+void c2_unregister_device(struct c2_dev *c2dev);
+int c2_rnic_init(struct c2_dev *c2dev);
+void c2_rnic_term(struct c2_dev *c2dev);
+void c2_rnic_interrupt(struct c2_dev *c2dev);
+int c2_del_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask);
+int c2_add_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask);
/* QPs */
-extern int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd,
+int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd,
struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp);
-extern void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp);
-extern struct ib_qp *c2_get_qp(struct ib_device *device, int qpn);
-extern int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
+void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp);
+struct ib_qp *c2_get_qp(struct ib_device *device, int qpn);
+int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
struct ib_qp_attr *attr, int attr_mask);
-extern int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
+int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
int ord, int ird);
-extern int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
struct ib_send_wr **bad_wr);
-extern int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
struct ib_recv_wr **bad_wr);
-extern void c2_init_qp_table(struct c2_dev *c2dev);
-extern void c2_cleanup_qp_table(struct c2_dev *c2dev);
-extern void c2_set_qp_state(struct c2_qp *, int);
-extern struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn);
+void c2_init_qp_table(struct c2_dev *c2dev);
+void c2_cleanup_qp_table(struct c2_dev *c2dev);
+void c2_set_qp_state(struct c2_qp *, int);
+struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn);
/* PDs */
-extern int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd);
-extern void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd);
-extern int c2_init_pd_table(struct c2_dev *c2dev);
-extern void c2_cleanup_pd_table(struct c2_dev *c2dev);
+int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd);
+void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd);
+int c2_init_pd_table(struct c2_dev *c2dev);
+void c2_cleanup_pd_table(struct c2_dev *c2dev);
/* CQs */
-extern int c2_init_cq(struct c2_dev *c2dev, int entries,
+int c2_init_cq(struct c2_dev *c2dev, int entries,
struct c2_ucontext *ctx, struct c2_cq *cq);
-extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
-extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
-extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
-extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
-extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
+void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
+void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
+void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
+int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
+int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
/* CM */
-extern int c2_llp_connect(struct iw_cm_id *cm_id,
+int c2_llp_connect(struct iw_cm_id *cm_id,
struct iw_cm_conn_param *iw_param);
-extern int c2_llp_accept(struct iw_cm_id *cm_id,
+int c2_llp_accept(struct iw_cm_id *cm_id,
struct iw_cm_conn_param *iw_param);
-extern int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata,
+int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata,
u8 pdata_len);
-extern int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog);
-extern int c2_llp_service_destroy(struct iw_cm_id *cm_id);
+int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog);
+int c2_llp_service_destroy(struct iw_cm_id *cm_id);
/* MM */
-extern int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
+int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
int page_size, int pbl_depth, u32 length,
u32 off, u64 *va, enum c2_acf acf,
struct c2_mr *mr);
-extern int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index);
+int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index);
/* AE */
-extern void c2_ae_event(struct c2_dev *c2dev, u32 mq_index);
+void c2_ae_event(struct c2_dev *c2dev, u32 mq_index);
/* MQSP Allocator */
-extern int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
+int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
struct sp_chunk **root);
-extern void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root);
-extern __be16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
+void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root);
+__be16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
dma_addr_t *dma_addr, gfp_t gfp_mask);
-extern void c2_free_mqsp(__be16* mqsp);
+void c2_free_mqsp(__be16* mqsp);
#endif
diff --git a/drivers/staging/rdma/amso1100/c2_mq.h b/drivers/staging/rdma/amso1100/c2_mq.h
index fc1b9a7cec4b..8e1b4d13409e 100644
--- a/drivers/staging/rdma/amso1100/c2_mq.h
+++ b/drivers/staging/rdma/amso1100/c2_mq.h
@@ -93,14 +93,14 @@ static __inline__ int c2_mq_full(struct c2_mq *q)
return q->priv == (be16_to_cpu(*q->shared) + q->q_size - 1) % q->q_size;
}
-extern void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count);
-extern void *c2_mq_alloc(struct c2_mq *q);
-extern void c2_mq_produce(struct c2_mq *q);
-extern void *c2_mq_consume(struct c2_mq *q);
-extern void c2_mq_free(struct c2_mq *q);
-extern void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count);
+void *c2_mq_alloc(struct c2_mq *q);
+void c2_mq_produce(struct c2_mq *q);
+void *c2_mq_consume(struct c2_mq *q);
+void c2_mq_free(struct c2_mq *q);
+void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
u8 __iomem *pool_start, u16 __iomem *peer, u32 type);
-extern void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
u8 *pool_start, u16 __iomem *peer, u32 type);
#endif /* _C2_MQ_H_ */
diff --git a/drivers/staging/rdma/amso1100/c2_provider.c b/drivers/staging/rdma/amso1100/c2_provider.c
index c707e45887c2..a092ac743c72 100644
--- a/drivers/staging/rdma/amso1100/c2_provider.c
+++ b/drivers/staging/rdma/amso1100/c2_provider.c
@@ -620,12 +620,9 @@ static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
{
- int err;
-
pr_debug("%s:%u\n", __func__, __LINE__);
- err = c2_llp_reject(cm_id, pdata, pdata_len);
- return err;
+ return c2_llp_reject(cm_id, pdata, pdata_len);
}
static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
@@ -642,12 +639,9 @@ static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
static int c2_service_destroy(struct iw_cm_id *cm_id)
{
- int err;
pr_debug("%s:%u\n", __func__, __LINE__);
- err = c2_llp_service_destroy(cm_id);
-
- return err;
+ return c2_llp_service_destroy(cm_id);
}
static int c2_pseudo_up(struct net_device *netdev)
diff --git a/drivers/staging/rdma/amso1100/c2_rnic.c b/drivers/staging/rdma/amso1100/c2_rnic.c
index d3c0f77767d9..5e65c6d07ca4 100644
--- a/drivers/staging/rdma/amso1100/c2_rnic.c
+++ b/drivers/staging/rdma/amso1100/c2_rnic.c
@@ -81,7 +81,6 @@
static int c2_adapter_init(struct c2_dev *c2dev)
{
struct c2wr_init_req wr;
- int err;
memset(&wr, 0, sizeof(wr));
c2_wr_set_id(&wr, CCWR_INIT);
@@ -94,9 +93,7 @@ static int c2_adapter_init(struct c2_dev *c2dev)
wr.q2_host_msg_pool = cpu_to_be64(c2dev->aeq.host_dma);
/* Post the init message */
- err = vq_send_wr(c2dev, (union c2wr *) & wr);
-
- return err;
+ return vq_send_wr(c2dev, (union c2wr *) & wr);
}
/*
diff --git a/drivers/staging/rdma/amso1100/c2_vq.h b/drivers/staging/rdma/amso1100/c2_vq.h
index 33805627a607..c1f6cef60213 100644
--- a/drivers/staging/rdma/amso1100/c2_vq.h
+++ b/drivers/staging/rdma/amso1100/c2_vq.h
@@ -47,17 +47,17 @@ struct c2_vq_req {
struct c2_qp *qp;
};
-extern int vq_init(struct c2_dev *c2dev);
-extern void vq_term(struct c2_dev *c2dev);
+int vq_init(struct c2_dev *c2dev);
+void vq_term(struct c2_dev *c2dev);
-extern struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev);
-extern void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req);
-extern void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req);
-extern void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req);
-extern int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr);
+struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev);
+void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req);
+void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req);
+void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req);
+int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr);
-extern void *vq_repbuf_alloc(struct c2_dev *c2dev);
-extern void vq_repbuf_free(struct c2_dev *c2dev, void *reply);
+void *vq_repbuf_alloc(struct c2_dev *c2dev);
+void vq_repbuf_free(struct c2_dev *c2dev, void *reply);
-extern int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req);
+int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req);
#endif /* _C2_VQ_H_ */
diff --git a/drivers/staging/rdma/ehca/ehca_av.c b/drivers/staging/rdma/ehca/ehca_av.c
index 465926319f3d..94e088c2d989 100644
--- a/drivers/staging/rdma/ehca/ehca_av.c
+++ b/drivers/staging/rdma/ehca/ehca_av.c
@@ -105,6 +105,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
if (ehca_static_rate < 0) {
u32 ipd;
+
if (ehca_calc_ipd(shca, ah_attr->port_num,
ah_attr->static_rate, &ipd)) {
ret = -EINVAL;
@@ -128,6 +129,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
int rc;
struct ib_port_attr port_attr;
union ib_gid gid;
+
memset(&port_attr, 0, sizeof(port_attr));
rc = ehca_query_port(pd->device, ah_attr->port_num,
&port_attr);
@@ -192,6 +194,7 @@ int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
int rc;
struct ib_port_attr port_attr;
union ib_gid gid;
+
memset(&port_attr, 0, sizeof(port_attr));
rc = ehca_query_port(ah->device, ah_attr->port_num,
&port_attr);
@@ -272,6 +275,5 @@ int ehca_init_av_cache(void)
void ehca_cleanup_av_cache(void)
{
- if (av_cache)
- kmem_cache_destroy(av_cache);
+ kmem_cache_destroy(av_cache);
}
diff --git a/drivers/staging/rdma/ehca/ehca_cq.c b/drivers/staging/rdma/ehca/ehca_cq.c
index ea1b5c1203b4..1aa7931fe860 100644
--- a/drivers/staging/rdma/ehca/ehca_cq.c
+++ b/drivers/staging/rdma/ehca/ehca_cq.c
@@ -393,6 +393,5 @@ int ehca_init_cq_cache(void)
void ehca_cleanup_cq_cache(void)
{
- if (cq_cache)
- kmem_cache_destroy(cq_cache);
+ kmem_cache_destroy(cq_cache);
}
diff --git a/drivers/staging/rdma/ehca/ehca_main.c b/drivers/staging/rdma/ehca/ehca_main.c
index 8246418cd4e0..860b974e9faa 100644
--- a/drivers/staging/rdma/ehca/ehca_main.c
+++ b/drivers/staging/rdma/ehca/ehca_main.c
@@ -245,8 +245,7 @@ static void ehca_destroy_slab_caches(void)
ehca_cleanup_cq_cache();
ehca_cleanup_pd_cache();
#ifdef CONFIG_PPC_64K_PAGES
- if (ctblk_cache)
- kmem_cache_destroy(ctblk_cache);
+ kmem_cache_destroy(ctblk_cache);
#endif
}
diff --git a/drivers/staging/rdma/ehca/ehca_mrmw.c b/drivers/staging/rdma/ehca/ehca_mrmw.c
index f914b30999f8..553e883a5718 100644
--- a/drivers/staging/rdma/ehca/ehca_mrmw.c
+++ b/drivers/staging/rdma/ehca/ehca_mrmw.c
@@ -2251,10 +2251,8 @@ int ehca_init_mrmw_cache(void)
void ehca_cleanup_mrmw_cache(void)
{
- if (mr_cache)
- kmem_cache_destroy(mr_cache);
- if (mw_cache)
- kmem_cache_destroy(mw_cache);
+ kmem_cache_destroy(mr_cache);
+ kmem_cache_destroy(mw_cache);
}
static inline int ehca_init_top_bmap(struct ehca_top_bmap *ehca_top_bmap,
diff --git a/drivers/staging/rdma/ehca/ehca_pd.c b/drivers/staging/rdma/ehca/ehca_pd.c
index 351577a6670a..2a8aae411941 100644
--- a/drivers/staging/rdma/ehca/ehca_pd.c
+++ b/drivers/staging/rdma/ehca/ehca_pd.c
@@ -119,6 +119,5 @@ int ehca_init_pd_cache(void)
void ehca_cleanup_pd_cache(void)
{
- if (pd_cache)
- kmem_cache_destroy(pd_cache);
+ kmem_cache_destroy(pd_cache);
}
diff --git a/drivers/staging/rdma/ehca/ehca_qp.c b/drivers/staging/rdma/ehca/ehca_qp.c
index 2e89356c46fa..896c01f810f6 100644
--- a/drivers/staging/rdma/ehca/ehca_qp.c
+++ b/drivers/staging/rdma/ehca/ehca_qp.c
@@ -2252,6 +2252,5 @@ int ehca_init_qp_cache(void)
void ehca_cleanup_qp_cache(void)
{
- if (qp_cache)
- kmem_cache_destroy(qp_cache);
+ kmem_cache_destroy(qp_cache);
}
diff --git a/drivers/staging/rdma/hfi1/Makefile b/drivers/staging/rdma/hfi1/Makefile
index 2e5daa6cdcc2..68c5a315e557 100644
--- a/drivers/staging/rdma/hfi1/Makefile
+++ b/drivers/staging/rdma/hfi1/Makefile
@@ -7,7 +7,7 @@
#
obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o
-hfi1-y := chip.o cq.o device.o diag.o dma.o driver.o eprom.o file_ops.o firmware.o \
+hfi1-y := chip.o cq.o device.o diag.o dma.o driver.o efivar.o eprom.o file_ops.o firmware.o \
init.o intr.o keys.o mad.o mmap.o mr.o pcie.o pio.o pio_copy.o \
qp.o qsfp.o rc.o ruc.o sdma.o srq.o sysfs.o trace.o twsi.o \
uc.o ud.o user_pages.o user_sdma.o verbs_mcast.o verbs.o
diff --git a/drivers/staging/rdma/hfi1/chip.c b/drivers/staging/rdma/hfi1/chip.c
index e48981994b10..bbe5ad85cec0 100644
--- a/drivers/staging/rdma/hfi1/chip.c
+++ b/drivers/staging/rdma/hfi1/chip.c
@@ -63,6 +63,7 @@
#include "pio.h"
#include "sdma.h"
#include "eprom.h"
+#include "efivar.h"
#define NUM_IB_PORTS 1
@@ -121,8 +122,8 @@ struct flag_table {
#define SEC_SC_HALTED 0x4 /* per-context only */
#define SEC_SPC_FREEZE 0x8 /* per-HFI only */
-#define VL15CTXT 1
#define MIN_KERNEL_KCTXTS 2
+#define FIRST_KERNEL_KCTXT 1
#define NUM_MAP_REGS 32
/* Bit offset into the GUID which carries HFI id information */
@@ -663,7 +664,7 @@ static struct flag_table egress_err_info_flags[] = {
*/
#define SES(name) SEND_ERR_STATUS_SEND_##name##_ERR_SMASK
static struct flag_table send_err_status_flags[] = {
-/* 0*/ FLAG_ENTRY0("SDmaRpyTagErr", SES(CSR_PARITY)),
+/* 0*/ FLAG_ENTRY0("SendCsrParityErr", SES(CSR_PARITY)),
/* 1*/ FLAG_ENTRY0("SendCsrReadBadAddrErr", SES(CSR_READ_BAD_ADDR)),
/* 2*/ FLAG_ENTRY0("SendCsrWriteBadAddrErr", SES(CSR_WRITE_BAD_ADDR))
};
@@ -1417,6 +1418,17 @@ static u64 access_sw_link_up_cnt(const struct cntr_entry *entry, void *context,
return read_write_sw(ppd->dd, &ppd->link_up, mode, data);
}
+static u64 access_sw_unknown_frame_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context;
+
+ if (vl != CNTR_INVALID_VL)
+ return 0;
+ return read_write_sw(ppd->dd, &ppd->unknown_frame_count, mode, data);
+}
+
static u64 access_sw_xmit_discards(const struct cntr_entry *entry,
void *context, int vl, int mode, u64 data)
{
@@ -1538,6 +1550,2336 @@ static u64 access_sw_send_schedule(const struct cntr_entry *entry,
return dd->verbs_dev.n_send_schedule;
}
+/* Software counters for the error status bits within MISC_ERR_STATUS */
+static u64 access_misc_pll_lock_fail_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[12];
+}
+
+static u64 access_misc_mbist_fail_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[11];
+}
+
+static u64 access_misc_invalid_eep_cmd_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[10];
+}
+
+static u64 access_misc_efuse_done_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[9];
+}
+
+static u64 access_misc_efuse_write_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[8];
+}
+
+static u64 access_misc_efuse_read_bad_addr_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[7];
+}
+
+static u64 access_misc_efuse_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[6];
+}
+
+static u64 access_misc_fw_auth_failed_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[5];
+}
+
+static u64 access_misc_key_mismatch_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[4];
+}
+
+static u64 access_misc_sbus_write_failed_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[3];
+}
+
+static u64 access_misc_csr_write_bad_addr_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[2];
+}
+
+static u64 access_misc_csr_read_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[1];
+}
+
+static u64 access_misc_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->misc_err_status_cnt[0];
+}
+
+/*
+ * Software counter for the aggregate of
+ * individual CceErrStatus counters
+ */
+static u64 access_sw_cce_err_status_aggregated_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_cce_err_status_aggregate;
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within CceErrStatus
+ */
+static u64 access_cce_msix_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[40];
+}
+
+static u64 access_cce_int_map_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[39];
+}
+
+static u64 access_cce_int_map_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[38];
+}
+
+static u64 access_cce_msix_table_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[37];
+}
+
+static u64 access_cce_msix_table_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[36];
+}
+
+static u64 access_cce_rxdma_conv_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[35];
+}
+
+static u64 access_cce_rcpl_async_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[34];
+}
+
+static u64 access_cce_seg_write_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[33];
+}
+
+static u64 access_cce_seg_read_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[32];
+}
+
+static u64 access_la_triggered_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[31];
+}
+
+static u64 access_cce_trgt_cpl_timeout_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[30];
+}
+
+static u64 access_pcic_receive_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[29];
+}
+
+static u64 access_pcic_transmit_back_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[28];
+}
+
+static u64 access_pcic_transmit_front_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[27];
+}
+
+static u64 access_pcic_cpl_dat_q_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[26];
+}
+
+static u64 access_pcic_cpl_hd_q_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[25];
+}
+
+static u64 access_pcic_post_dat_q_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[24];
+}
+
+static u64 access_pcic_post_hd_q_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[23];
+}
+
+static u64 access_pcic_retry_sot_mem_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[22];
+}
+
+static u64 access_pcic_retry_mem_unc_err(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[21];
+}
+
+static u64 access_pcic_n_post_dat_q_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[20];
+}
+
+static u64 access_pcic_n_post_h_q_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[19];
+}
+
+static u64 access_pcic_cpl_dat_q_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[18];
+}
+
+static u64 access_pcic_cpl_hd_q_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[17];
+}
+
+static u64 access_pcic_post_dat_q_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[16];
+}
+
+static u64 access_pcic_post_hd_q_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[15];
+}
+
+static u64 access_pcic_retry_sot_mem_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[14];
+}
+
+static u64 access_pcic_retry_mem_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[13];
+}
+
+static u64 access_cce_cli1_async_fifo_dbg_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[12];
+}
+
+static u64 access_cce_cli1_async_fifo_rxdma_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[11];
+}
+
+static u64 access_cce_cli1_async_fifo_sdma_hd_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[10];
+}
+
+static u64 access_cce_cl1_async_fifo_pio_crdt_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[9];
+}
+
+static u64 access_cce_cli2_async_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[8];
+}
+
+static u64 access_cce_csr_cfg_bus_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[7];
+}
+
+static u64 access_cce_cli0_async_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[6];
+}
+
+static u64 access_cce_rspd_data_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[5];
+}
+
+static u64 access_cce_trgt_access_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[4];
+}
+
+static u64 access_cce_trgt_async_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[3];
+}
+
+static u64 access_cce_csr_write_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[2];
+}
+
+static u64 access_cce_csr_read_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[1];
+}
+
+static u64 access_ccs_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->cce_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within RcvErrStatus
+ */
+static u64 access_rx_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[63];
+}
+
+static u64 access_rx_csr_write_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[62];
+}
+
+static u64 access_rx_csr_read_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[61];
+}
+
+static u64 access_rx_dma_csr_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[60];
+}
+
+static u64 access_rx_dma_dq_fsm_encoding_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[59];
+}
+
+static u64 access_rx_dma_eq_fsm_encoding_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[58];
+}
+
+static u64 access_rx_dma_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[57];
+}
+
+static u64 access_rx_rbuf_data_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[56];
+}
+
+static u64 access_rx_rbuf_data_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[55];
+}
+
+static u64 access_rx_dma_data_fifo_rd_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[54];
+}
+
+static u64 access_rx_dma_data_fifo_rd_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[53];
+}
+
+static u64 access_rx_dma_hdr_fifo_rd_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[52];
+}
+
+static u64 access_rx_dma_hdr_fifo_rd_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[51];
+}
+
+static u64 access_rx_rbuf_desc_part2_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[50];
+}
+
+static u64 access_rx_rbuf_desc_part2_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[49];
+}
+
+static u64 access_rx_rbuf_desc_part1_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[48];
+}
+
+static u64 access_rx_rbuf_desc_part1_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[47];
+}
+
+static u64 access_rx_hq_intr_fsm_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[46];
+}
+
+static u64 access_rx_hq_intr_csr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[45];
+}
+
+static u64 access_rx_lookup_csr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[44];
+}
+
+static u64 access_rx_lookup_rcv_array_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[43];
+}
+
+static u64 access_rx_lookup_rcv_array_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[42];
+}
+
+static u64 access_rx_lookup_des_part2_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[41];
+}
+
+static u64 access_rx_lookup_des_part1_unc_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[40];
+}
+
+static u64 access_rx_lookup_des_part1_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[39];
+}
+
+static u64 access_rx_rbuf_next_free_buf_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[38];
+}
+
+static u64 access_rx_rbuf_next_free_buf_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[37];
+}
+
+static u64 access_rbuf_fl_init_wr_addr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[36];
+}
+
+static u64 access_rx_rbuf_fl_initdone_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[35];
+}
+
+static u64 access_rx_rbuf_fl_write_addr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[34];
+}
+
+static u64 access_rx_rbuf_fl_rd_addr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[33];
+}
+
+static u64 access_rx_rbuf_empty_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[32];
+}
+
+static u64 access_rx_rbuf_full_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[31];
+}
+
+static u64 access_rbuf_bad_lookup_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[30];
+}
+
+static u64 access_rbuf_ctx_id_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[29];
+}
+
+static u64 access_rbuf_csr_qeopdw_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[28];
+}
+
+static u64 access_rx_rbuf_csr_q_num_of_pkt_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[27];
+}
+
+static u64 access_rx_rbuf_csr_q_t1_ptr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[26];
+}
+
+static u64 access_rx_rbuf_csr_q_hd_ptr_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[25];
+}
+
+static u64 access_rx_rbuf_csr_q_vld_bit_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[24];
+}
+
+static u64 access_rx_rbuf_csr_q_next_buf_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[23];
+}
+
+static u64 access_rx_rbuf_csr_q_ent_cnt_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[22];
+}
+
+static u64 access_rx_rbuf_csr_q_head_buf_num_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[21];
+}
+
+static u64 access_rx_rbuf_block_list_read_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[20];
+}
+
+static u64 access_rx_rbuf_block_list_read_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[19];
+}
+
+static u64 access_rx_rbuf_lookup_des_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[18];
+}
+
+static u64 access_rx_rbuf_lookup_des_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[17];
+}
+
+static u64 access_rx_rbuf_lookup_des_reg_unc_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[16];
+}
+
+static u64 access_rx_rbuf_lookup_des_reg_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[15];
+}
+
+static u64 access_rx_rbuf_free_list_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[14];
+}
+
+static u64 access_rx_rbuf_free_list_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[13];
+}
+
+static u64 access_rx_rcv_fsm_encoding_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[12];
+}
+
+static u64 access_rx_dma_flag_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[11];
+}
+
+static u64 access_rx_dma_flag_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[10];
+}
+
+static u64 access_rx_dc_sop_eop_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[9];
+}
+
+static u64 access_rx_rcv_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[8];
+}
+
+static u64 access_rx_rcv_qp_map_table_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[7];
+}
+
+static u64 access_rx_rcv_qp_map_table_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[6];
+}
+
+static u64 access_rx_rcv_data_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[5];
+}
+
+static u64 access_rx_rcv_data_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[4];
+}
+
+static u64 access_rx_rcv_hdr_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[3];
+}
+
+static u64 access_rx_rcv_hdr_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[2];
+}
+
+static u64 access_rx_dc_intf_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[1];
+}
+
+static u64 access_rx_dma_csr_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->rcv_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within SendPioErrStatus
+ */
+static u64 access_pio_pec_sop_head_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[35];
+}
+
+static u64 access_pio_pcc_sop_head_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[34];
+}
+
+static u64 access_pio_last_returned_cnt_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[33];
+}
+
+static u64 access_pio_current_free_cnt_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[32];
+}
+
+static u64 access_pio_reserved_31_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[31];
+}
+
+static u64 access_pio_reserved_30_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[30];
+}
+
+static u64 access_pio_ppmc_sop_len_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[29];
+}
+
+static u64 access_pio_ppmc_bqc_mem_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[28];
+}
+
+static u64 access_pio_vl_fifo_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[27];
+}
+
+static u64 access_pio_vlf_sop_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[26];
+}
+
+static u64 access_pio_vlf_v1_len_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[25];
+}
+
+static u64 access_pio_block_qw_count_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[24];
+}
+
+static u64 access_pio_write_qw_valid_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[23];
+}
+
+static u64 access_pio_state_machine_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[22];
+}
+
+static u64 access_pio_write_data_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[21];
+}
+
+static u64 access_pio_host_addr_mem_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[20];
+}
+
+static u64 access_pio_host_addr_mem_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[19];
+}
+
+static u64 access_pio_pkt_evict_sm_or_arb_sm_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[18];
+}
+
+static u64 access_pio_init_sm_in_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[17];
+}
+
+static u64 access_pio_ppmc_pbl_fifo_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[16];
+}
+
+static u64 access_pio_credit_ret_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[15];
+}
+
+static u64 access_pio_v1_len_mem_bank1_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[14];
+}
+
+static u64 access_pio_v1_len_mem_bank0_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[13];
+}
+
+static u64 access_pio_v1_len_mem_bank1_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[12];
+}
+
+static u64 access_pio_v1_len_mem_bank0_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[11];
+}
+
+static u64 access_pio_sm_pkt_reset_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[10];
+}
+
+static u64 access_pio_pkt_evict_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[9];
+}
+
+static u64 access_pio_sbrdctrl_crrel_fifo_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[8];
+}
+
+static u64 access_pio_sbrdctl_crrel_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[7];
+}
+
+static u64 access_pio_pec_fifo_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[6];
+}
+
+static u64 access_pio_pcc_fifo_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[5];
+}
+
+static u64 access_pio_sb_mem_fifo1_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[4];
+}
+
+static u64 access_pio_sb_mem_fifo0_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[3];
+}
+
+static u64 access_pio_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[2];
+}
+
+static u64 access_pio_write_addr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[1];
+}
+
+static u64 access_pio_write_bad_ctxt_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_pio_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within SendDmaErrStatus
+ */
+static u64 access_sdma_pcie_req_tracking_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_dma_err_status_cnt[3];
+}
+
+static u64 access_sdma_pcie_req_tracking_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_dma_err_status_cnt[2];
+}
+
+static u64 access_sdma_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_dma_err_status_cnt[1];
+}
+
+static u64 access_sdma_rpy_tag_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_dma_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within SendEgressErrStatus
+ */
+static u64 access_tx_read_pio_memory_csr_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[63];
+}
+
+static u64 access_tx_read_sdma_memory_csr_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[62];
+}
+
+static u64 access_tx_egress_fifo_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[61];
+}
+
+static u64 access_tx_read_pio_memory_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[60];
+}
+
+static u64 access_tx_read_sdma_memory_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[59];
+}
+
+static u64 access_tx_sb_hdr_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[58];
+}
+
+static u64 access_tx_credit_overrun_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[57];
+}
+
+static u64 access_tx_launch_fifo8_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[56];
+}
+
+static u64 access_tx_launch_fifo7_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[55];
+}
+
+static u64 access_tx_launch_fifo6_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[54];
+}
+
+static u64 access_tx_launch_fifo5_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[53];
+}
+
+static u64 access_tx_launch_fifo4_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[52];
+}
+
+static u64 access_tx_launch_fifo3_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[51];
+}
+
+static u64 access_tx_launch_fifo2_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[50];
+}
+
+static u64 access_tx_launch_fifo1_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[49];
+}
+
+static u64 access_tx_launch_fifo0_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[48];
+}
+
+static u64 access_tx_credit_return_vl_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[47];
+}
+
+static u64 access_tx_hcrc_insertion_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[46];
+}
+
+static u64 access_tx_egress_fifo_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[45];
+}
+
+static u64 access_tx_read_pio_memory_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[44];
+}
+
+static u64 access_tx_read_sdma_memory_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[43];
+}
+
+static u64 access_tx_sb_hdr_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[42];
+}
+
+static u64 access_tx_credit_return_partiy_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[41];
+}
+
+static u64 access_tx_launch_fifo8_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[40];
+}
+
+static u64 access_tx_launch_fifo7_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[39];
+}
+
+static u64 access_tx_launch_fifo6_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[38];
+}
+
+static u64 access_tx_launch_fifo5_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[37];
+}
+
+static u64 access_tx_launch_fifo4_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[36];
+}
+
+static u64 access_tx_launch_fifo3_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[35];
+}
+
+static u64 access_tx_launch_fifo2_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[34];
+}
+
+static u64 access_tx_launch_fifo1_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[33];
+}
+
+static u64 access_tx_launch_fifo0_unc_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[32];
+}
+
+static u64 access_tx_sdma15_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[31];
+}
+
+static u64 access_tx_sdma14_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[30];
+}
+
+static u64 access_tx_sdma13_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[29];
+}
+
+static u64 access_tx_sdma12_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[28];
+}
+
+static u64 access_tx_sdma11_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[27];
+}
+
+static u64 access_tx_sdma10_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[26];
+}
+
+static u64 access_tx_sdma9_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[25];
+}
+
+static u64 access_tx_sdma8_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[24];
+}
+
+static u64 access_tx_sdma7_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[23];
+}
+
+static u64 access_tx_sdma6_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[22];
+}
+
+static u64 access_tx_sdma5_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[21];
+}
+
+static u64 access_tx_sdma4_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[20];
+}
+
+static u64 access_tx_sdma3_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[19];
+}
+
+static u64 access_tx_sdma2_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[18];
+}
+
+static u64 access_tx_sdma1_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[17];
+}
+
+static u64 access_tx_sdma0_disallowed_packet_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[16];
+}
+
+static u64 access_tx_config_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[15];
+}
+
+static u64 access_tx_sbrd_ctl_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[14];
+}
+
+static u64 access_tx_launch_csr_parity_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[13];
+}
+
+static u64 access_tx_illegal_vl_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[12];
+}
+
+static u64 access_tx_sbrd_ctl_state_machine_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[11];
+}
+
+static u64 access_egress_reserved_10_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[10];
+}
+
+static u64 access_egress_reserved_9_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[9];
+}
+
+static u64 access_tx_sdma_launch_intf_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[8];
+}
+
+static u64 access_tx_pio_launch_intf_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[7];
+}
+
+static u64 access_egress_reserved_6_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[6];
+}
+
+static u64 access_tx_incorrect_link_state_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[5];
+}
+
+static u64 access_tx_linkdown_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[4];
+}
+
+static u64 access_tx_egress_fifi_underrun_or_parity_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[3];
+}
+
+static u64 access_egress_reserved_2_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[2];
+}
+
+static u64 access_tx_pkt_integrity_mem_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[1];
+}
+
+static u64 access_tx_pkt_integrity_mem_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_egress_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within SendErrStatus
+ */
+static u64 access_send_csr_write_bad_addr_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_err_status_cnt[2];
+}
+
+static u64 access_send_csr_read_bad_addr_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_err_status_cnt[1];
+}
+
+static u64 access_send_csr_parity_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->send_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within SendCtxtErrStatus
+ */
+static u64 access_pio_write_out_of_bounds_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_ctxt_err_status_cnt[4];
+}
+
+static u64 access_pio_write_overflow_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_ctxt_err_status_cnt[3];
+}
+
+static u64 access_pio_write_crosses_boundary_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_ctxt_err_status_cnt[2];
+}
+
+static u64 access_pio_disallowed_packet_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_ctxt_err_status_cnt[1];
+}
+
+static u64 access_pio_inconsistent_sop_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_ctxt_err_status_cnt[0];
+}
+
+/*
+ * Software counters corresponding to each of the
+ * error status bits within SendDmaEngErrStatus
+ */
+static u64 access_sdma_header_request_fifo_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[23];
+}
+
+static u64 access_sdma_header_storage_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[22];
+}
+
+static u64 access_sdma_packet_tracking_cor_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[21];
+}
+
+static u64 access_sdma_assembly_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[20];
+}
+
+static u64 access_sdma_desc_table_cor_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[19];
+}
+
+static u64 access_sdma_header_request_fifo_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[18];
+}
+
+static u64 access_sdma_header_storage_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[17];
+}
+
+static u64 access_sdma_packet_tracking_unc_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[16];
+}
+
+static u64 access_sdma_assembly_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[15];
+}
+
+static u64 access_sdma_desc_table_unc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[14];
+}
+
+static u64 access_sdma_timeout_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[13];
+}
+
+static u64 access_sdma_header_length_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[12];
+}
+
+static u64 access_sdma_header_address_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[11];
+}
+
+static u64 access_sdma_header_select_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[10];
+}
+
+static u64 access_sdma_reserved_9_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[9];
+}
+
+static u64 access_sdma_packet_desc_overflow_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[8];
+}
+
+static u64 access_sdma_length_mismatch_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl,
+ int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[7];
+}
+
+static u64 access_sdma_halt_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[6];
+}
+
+static u64 access_sdma_mem_read_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[5];
+}
+
+static u64 access_sdma_first_desc_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[4];
+}
+
+static u64 access_sdma_tail_out_of_bounds_err_cnt(
+ const struct cntr_entry *entry,
+ void *context, int vl, int mode, u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[3];
+}
+
+static u64 access_sdma_too_long_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[2];
+}
+
+static u64 access_sdma_gen_mismatch_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[1];
+}
+
+static u64 access_sdma_wrong_dw_err_cnt(const struct cntr_entry *entry,
+ void *context, int vl, int mode,
+ u64 data)
+{
+ struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+ return dd->sw_send_dma_eng_err_status_cnt[0];
+}
+
#define def_access_sw_cpu(cntr) \
static u64 access_sw_cpu_##cntr(const struct cntr_entry *entry, \
void *context, int vl, int mode, u64 data) \
@@ -1587,8 +3929,6 @@ static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = {
[C_RX_TID_FLGMS] = RXE32_DEV_CNTR_ELEM(RxTidFLGMs,
RCV_TID_FLOW_GEN_MISMATCH_CNT,
CNTR_NORMAL),
-[C_RX_CTX_RHQS] = RXE32_DEV_CNTR_ELEM(RxCtxRHQS, RCV_CONTEXT_RHQ_STALL,
- CNTR_NORMAL),
[C_RX_CTX_EGRS] = RXE32_DEV_CNTR_ELEM(RxCtxEgrS, RCV_CONTEXT_EGR_STALL,
CNTR_NORMAL),
[C_RCV_TID_FLSMS] = RXE32_DEV_CNTR_ELEM(RxTidFLSMs,
@@ -1730,6 +4070,794 @@ static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = {
access_sw_kmem_wait),
[C_SW_SEND_SCHED] = CNTR_ELEM("SendSched", 0, 0, CNTR_NORMAL,
access_sw_send_schedule),
+/* MISC_ERR_STATUS */
+[C_MISC_PLL_LOCK_FAIL_ERR] = CNTR_ELEM("MISC_PLL_LOCK_FAIL_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_pll_lock_fail_err_cnt),
+[C_MISC_MBIST_FAIL_ERR] = CNTR_ELEM("MISC_MBIST_FAIL_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_mbist_fail_err_cnt),
+[C_MISC_INVALID_EEP_CMD_ERR] = CNTR_ELEM("MISC_INVALID_EEP_CMD_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_invalid_eep_cmd_err_cnt),
+[C_MISC_EFUSE_DONE_PARITY_ERR] = CNTR_ELEM("MISC_EFUSE_DONE_PARITY_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_efuse_done_parity_err_cnt),
+[C_MISC_EFUSE_WRITE_ERR] = CNTR_ELEM("MISC_EFUSE_WRITE_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_efuse_write_err_cnt),
+[C_MISC_EFUSE_READ_BAD_ADDR_ERR] = CNTR_ELEM("MISC_EFUSE_READ_BAD_ADDR_ERR", 0,
+ 0, CNTR_NORMAL,
+ access_misc_efuse_read_bad_addr_err_cnt),
+[C_MISC_EFUSE_CSR_PARITY_ERR] = CNTR_ELEM("MISC_EFUSE_CSR_PARITY_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_efuse_csr_parity_err_cnt),
+[C_MISC_FW_AUTH_FAILED_ERR] = CNTR_ELEM("MISC_FW_AUTH_FAILED_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_fw_auth_failed_err_cnt),
+[C_MISC_KEY_MISMATCH_ERR] = CNTR_ELEM("MISC_KEY_MISMATCH_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_key_mismatch_err_cnt),
+[C_MISC_SBUS_WRITE_FAILED_ERR] = CNTR_ELEM("MISC_SBUS_WRITE_FAILED_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_sbus_write_failed_err_cnt),
+[C_MISC_CSR_WRITE_BAD_ADDR_ERR] = CNTR_ELEM("MISC_CSR_WRITE_BAD_ADDR_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_csr_write_bad_addr_err_cnt),
+[C_MISC_CSR_READ_BAD_ADDR_ERR] = CNTR_ELEM("MISC_CSR_READ_BAD_ADDR_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_csr_read_bad_addr_err_cnt),
+[C_MISC_CSR_PARITY_ERR] = CNTR_ELEM("MISC_CSR_PARITY_ERR", 0, 0,
+ CNTR_NORMAL,
+ access_misc_csr_parity_err_cnt),
+/* CceErrStatus */
+[C_CCE_ERR_STATUS_AGGREGATED_CNT] = CNTR_ELEM("CceErrStatusAggregatedCnt", 0, 0,
+ CNTR_NORMAL,
+ access_sw_cce_err_status_aggregated_cnt),
+[C_CCE_MSIX_CSR_PARITY_ERR] = CNTR_ELEM("CceMsixCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_msix_csr_parity_err_cnt),
+[C_CCE_INT_MAP_UNC_ERR] = CNTR_ELEM("CceIntMapUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_int_map_unc_err_cnt),
+[C_CCE_INT_MAP_COR_ERR] = CNTR_ELEM("CceIntMapCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_int_map_cor_err_cnt),
+[C_CCE_MSIX_TABLE_UNC_ERR] = CNTR_ELEM("CceMsixTableUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_msix_table_unc_err_cnt),
+[C_CCE_MSIX_TABLE_COR_ERR] = CNTR_ELEM("CceMsixTableCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_msix_table_cor_err_cnt),
+[C_CCE_RXDMA_CONV_FIFO_PARITY_ERR] = CNTR_ELEM("CceRxdmaConvFifoParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_cce_rxdma_conv_fifo_parity_err_cnt),
+[C_CCE_RCPL_ASYNC_FIFO_PARITY_ERR] = CNTR_ELEM("CceRcplAsyncFifoParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_cce_rcpl_async_fifo_parity_err_cnt),
+[C_CCE_SEG_WRITE_BAD_ADDR_ERR] = CNTR_ELEM("CceSegWriteBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_seg_write_bad_addr_err_cnt),
+[C_CCE_SEG_READ_BAD_ADDR_ERR] = CNTR_ELEM("CceSegReadBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_seg_read_bad_addr_err_cnt),
+[C_LA_TRIGGERED] = CNTR_ELEM("Cce LATriggered", 0, 0,
+ CNTR_NORMAL,
+ access_la_triggered_cnt),
+[C_CCE_TRGT_CPL_TIMEOUT_ERR] = CNTR_ELEM("CceTrgtCplTimeoutErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_trgt_cpl_timeout_err_cnt),
+[C_PCIC_RECEIVE_PARITY_ERR] = CNTR_ELEM("PcicReceiveParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_receive_parity_err_cnt),
+[C_PCIC_TRANSMIT_BACK_PARITY_ERR] = CNTR_ELEM("PcicTransmitBackParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_transmit_back_parity_err_cnt),
+[C_PCIC_TRANSMIT_FRONT_PARITY_ERR] = CNTR_ELEM("PcicTransmitFrontParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_pcic_transmit_front_parity_err_cnt),
+[C_PCIC_CPL_DAT_Q_UNC_ERR] = CNTR_ELEM("PcicCplDatQUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_cpl_dat_q_unc_err_cnt),
+[C_PCIC_CPL_HD_Q_UNC_ERR] = CNTR_ELEM("PcicCplHdQUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_cpl_hd_q_unc_err_cnt),
+[C_PCIC_POST_DAT_Q_UNC_ERR] = CNTR_ELEM("PcicPostDatQUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_post_dat_q_unc_err_cnt),
+[C_PCIC_POST_HD_Q_UNC_ERR] = CNTR_ELEM("PcicPostHdQUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_post_hd_q_unc_err_cnt),
+[C_PCIC_RETRY_SOT_MEM_UNC_ERR] = CNTR_ELEM("PcicRetrySotMemUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_retry_sot_mem_unc_err_cnt),
+[C_PCIC_RETRY_MEM_UNC_ERR] = CNTR_ELEM("PcicRetryMemUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_retry_mem_unc_err),
+[C_PCIC_N_POST_DAT_Q_PARITY_ERR] = CNTR_ELEM("PcicNPostDatQParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_n_post_dat_q_parity_err_cnt),
+[C_PCIC_N_POST_H_Q_PARITY_ERR] = CNTR_ELEM("PcicNPostHQParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_n_post_h_q_parity_err_cnt),
+[C_PCIC_CPL_DAT_Q_COR_ERR] = CNTR_ELEM("PcicCplDatQCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_cpl_dat_q_cor_err_cnt),
+[C_PCIC_CPL_HD_Q_COR_ERR] = CNTR_ELEM("PcicCplHdQCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_cpl_hd_q_cor_err_cnt),
+[C_PCIC_POST_DAT_Q_COR_ERR] = CNTR_ELEM("PcicPostDatQCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_post_dat_q_cor_err_cnt),
+[C_PCIC_POST_HD_Q_COR_ERR] = CNTR_ELEM("PcicPostHdQCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_post_hd_q_cor_err_cnt),
+[C_PCIC_RETRY_SOT_MEM_COR_ERR] = CNTR_ELEM("PcicRetrySotMemCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_retry_sot_mem_cor_err_cnt),
+[C_PCIC_RETRY_MEM_COR_ERR] = CNTR_ELEM("PcicRetryMemCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pcic_retry_mem_cor_err_cnt),
+[C_CCE_CLI1_ASYNC_FIFO_DBG_PARITY_ERR] = CNTR_ELEM(
+ "CceCli1AsyncFifoDbgParityError", 0, 0,
+ CNTR_NORMAL,
+ access_cce_cli1_async_fifo_dbg_parity_err_cnt),
+[C_CCE_CLI1_ASYNC_FIFO_RXDMA_PARITY_ERR] = CNTR_ELEM(
+ "CceCli1AsyncFifoRxdmaParityError", 0, 0,
+ CNTR_NORMAL,
+ access_cce_cli1_async_fifo_rxdma_parity_err_cnt
+ ),
+[C_CCE_CLI1_ASYNC_FIFO_SDMA_HD_PARITY_ERR] = CNTR_ELEM(
+ "CceCli1AsyncFifoSdmaHdParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_cli1_async_fifo_sdma_hd_parity_err_cnt),
+[C_CCE_CLI1_ASYNC_FIFO_PIO_CRDT_PARITY_ERR] = CNTR_ELEM(
+ "CceCli1AsyncFifoPioCrdtParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_cl1_async_fifo_pio_crdt_parity_err_cnt),
+[C_CCE_CLI2_ASYNC_FIFO_PARITY_ERR] = CNTR_ELEM("CceCli2AsyncFifoParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_cce_cli2_async_fifo_parity_err_cnt),
+[C_CCE_CSR_CFG_BUS_PARITY_ERR] = CNTR_ELEM("CceCsrCfgBusParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_csr_cfg_bus_parity_err_cnt),
+[C_CCE_CLI0_ASYNC_FIFO_PARTIY_ERR] = CNTR_ELEM("CceCli0AsyncFifoParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_cce_cli0_async_fifo_parity_err_cnt),
+[C_CCE_RSPD_DATA_PARITY_ERR] = CNTR_ELEM("CceRspdDataParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_rspd_data_parity_err_cnt),
+[C_CCE_TRGT_ACCESS_ERR] = CNTR_ELEM("CceTrgtAccessErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_trgt_access_err_cnt),
+[C_CCE_TRGT_ASYNC_FIFO_PARITY_ERR] = CNTR_ELEM("CceTrgtAsyncFifoParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_cce_trgt_async_fifo_parity_err_cnt),
+[C_CCE_CSR_WRITE_BAD_ADDR_ERR] = CNTR_ELEM("CceCsrWriteBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_csr_write_bad_addr_err_cnt),
+[C_CCE_CSR_READ_BAD_ADDR_ERR] = CNTR_ELEM("CceCsrReadBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_cce_csr_read_bad_addr_err_cnt),
+[C_CCE_CSR_PARITY_ERR] = CNTR_ELEM("CceCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_ccs_csr_parity_err_cnt),
+
+/* RcvErrStatus */
+[C_RX_CSR_PARITY_ERR] = CNTR_ELEM("RxCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_csr_parity_err_cnt),
+[C_RX_CSR_WRITE_BAD_ADDR_ERR] = CNTR_ELEM("RxCsrWriteBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_csr_write_bad_addr_err_cnt),
+[C_RX_CSR_READ_BAD_ADDR_ERR] = CNTR_ELEM("RxCsrReadBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_csr_read_bad_addr_err_cnt),
+[C_RX_DMA_CSR_UNC_ERR] = CNTR_ELEM("RxDmaCsrUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_csr_unc_err_cnt),
+[C_RX_DMA_DQ_FSM_ENCODING_ERR] = CNTR_ELEM("RxDmaDqFsmEncodingErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_dq_fsm_encoding_err_cnt),
+[C_RX_DMA_EQ_FSM_ENCODING_ERR] = CNTR_ELEM("RxDmaEqFsmEncodingErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_eq_fsm_encoding_err_cnt),
+[C_RX_DMA_CSR_PARITY_ERR] = CNTR_ELEM("RxDmaCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_csr_parity_err_cnt),
+[C_RX_RBUF_DATA_COR_ERR] = CNTR_ELEM("RxRbufDataCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_data_cor_err_cnt),
+[C_RX_RBUF_DATA_UNC_ERR] = CNTR_ELEM("RxRbufDataUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_data_unc_err_cnt),
+[C_RX_DMA_DATA_FIFO_RD_COR_ERR] = CNTR_ELEM("RxDmaDataFifoRdCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_data_fifo_rd_cor_err_cnt),
+[C_RX_DMA_DATA_FIFO_RD_UNC_ERR] = CNTR_ELEM("RxDmaDataFifoRdUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_data_fifo_rd_unc_err_cnt),
+[C_RX_DMA_HDR_FIFO_RD_COR_ERR] = CNTR_ELEM("RxDmaHdrFifoRdCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_hdr_fifo_rd_cor_err_cnt),
+[C_RX_DMA_HDR_FIFO_RD_UNC_ERR] = CNTR_ELEM("RxDmaHdrFifoRdUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_hdr_fifo_rd_unc_err_cnt),
+[C_RX_RBUF_DESC_PART2_COR_ERR] = CNTR_ELEM("RxRbufDescPart2CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_desc_part2_cor_err_cnt),
+[C_RX_RBUF_DESC_PART2_UNC_ERR] = CNTR_ELEM("RxRbufDescPart2UncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_desc_part2_unc_err_cnt),
+[C_RX_RBUF_DESC_PART1_COR_ERR] = CNTR_ELEM("RxRbufDescPart1CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_desc_part1_cor_err_cnt),
+[C_RX_RBUF_DESC_PART1_UNC_ERR] = CNTR_ELEM("RxRbufDescPart1UncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_desc_part1_unc_err_cnt),
+[C_RX_HQ_INTR_FSM_ERR] = CNTR_ELEM("RxHqIntrFsmErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_hq_intr_fsm_err_cnt),
+[C_RX_HQ_INTR_CSR_PARITY_ERR] = CNTR_ELEM("RxHqIntrCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_hq_intr_csr_parity_err_cnt),
+[C_RX_LOOKUP_CSR_PARITY_ERR] = CNTR_ELEM("RxLookupCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_lookup_csr_parity_err_cnt),
+[C_RX_LOOKUP_RCV_ARRAY_COR_ERR] = CNTR_ELEM("RxLookupRcvArrayCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_lookup_rcv_array_cor_err_cnt),
+[C_RX_LOOKUP_RCV_ARRAY_UNC_ERR] = CNTR_ELEM("RxLookupRcvArrayUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_lookup_rcv_array_unc_err_cnt),
+[C_RX_LOOKUP_DES_PART2_PARITY_ERR] = CNTR_ELEM("RxLookupDesPart2ParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_lookup_des_part2_parity_err_cnt),
+[C_RX_LOOKUP_DES_PART1_UNC_COR_ERR] = CNTR_ELEM("RxLookupDesPart1UncCorErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_lookup_des_part1_unc_cor_err_cnt),
+[C_RX_LOOKUP_DES_PART1_UNC_ERR] = CNTR_ELEM("RxLookupDesPart1UncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_lookup_des_part1_unc_err_cnt),
+[C_RX_RBUF_NEXT_FREE_BUF_COR_ERR] = CNTR_ELEM("RxRbufNextFreeBufCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_next_free_buf_cor_err_cnt),
+[C_RX_RBUF_NEXT_FREE_BUF_UNC_ERR] = CNTR_ELEM("RxRbufNextFreeBufUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_next_free_buf_unc_err_cnt),
+[C_RX_RBUF_FL_INIT_WR_ADDR_PARITY_ERR] = CNTR_ELEM(
+ "RxRbufFlInitWrAddrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rbuf_fl_init_wr_addr_parity_err_cnt),
+[C_RX_RBUF_FL_INITDONE_PARITY_ERR] = CNTR_ELEM("RxRbufFlInitdoneParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_fl_initdone_parity_err_cnt),
+[C_RX_RBUF_FL_WRITE_ADDR_PARITY_ERR] = CNTR_ELEM("RxRbufFlWrAddrParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_fl_write_addr_parity_err_cnt),
+[C_RX_RBUF_FL_RD_ADDR_PARITY_ERR] = CNTR_ELEM("RxRbufFlRdAddrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_fl_rd_addr_parity_err_cnt),
+[C_RX_RBUF_EMPTY_ERR] = CNTR_ELEM("RxRbufEmptyErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_empty_err_cnt),
+[C_RX_RBUF_FULL_ERR] = CNTR_ELEM("RxRbufFullErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_full_err_cnt),
+[C_RX_RBUF_BAD_LOOKUP_ERR] = CNTR_ELEM("RxRBufBadLookupErr", 0, 0,
+ CNTR_NORMAL,
+ access_rbuf_bad_lookup_err_cnt),
+[C_RX_RBUF_CTX_ID_PARITY_ERR] = CNTR_ELEM("RxRbufCtxIdParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rbuf_ctx_id_parity_err_cnt),
+[C_RX_RBUF_CSR_QEOPDW_PARITY_ERR] = CNTR_ELEM("RxRbufCsrQEOPDWParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rbuf_csr_qeopdw_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_NUM_OF_PKT_PARITY_ERR] = CNTR_ELEM(
+ "RxRbufCsrQNumOfPktParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_csr_q_num_of_pkt_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_T1_PTR_PARITY_ERR] = CNTR_ELEM(
+ "RxRbufCsrQTlPtrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_csr_q_t1_ptr_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_HD_PTR_PARITY_ERR] = CNTR_ELEM("RxRbufCsrQHdPtrParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_csr_q_hd_ptr_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_VLD_BIT_PARITY_ERR] = CNTR_ELEM("RxRbufCsrQVldBitParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_csr_q_vld_bit_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_NEXT_BUF_PARITY_ERR] = CNTR_ELEM("RxRbufCsrQNextBufParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_rx_rbuf_csr_q_next_buf_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_ENT_CNT_PARITY_ERR] = CNTR_ELEM("RxRbufCsrQEntCntParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_csr_q_ent_cnt_parity_err_cnt),
+[C_RX_RBUF_CSR_Q_HEAD_BUF_NUM_PARITY_ERR] = CNTR_ELEM(
+ "RxRbufCsrQHeadBufNumParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_csr_q_head_buf_num_parity_err_cnt),
+[C_RX_RBUF_BLOCK_LIST_READ_COR_ERR] = CNTR_ELEM("RxRbufBlockListReadCorErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_block_list_read_cor_err_cnt),
+[C_RX_RBUF_BLOCK_LIST_READ_UNC_ERR] = CNTR_ELEM("RxRbufBlockListReadUncErr", 0,
+ 0, CNTR_NORMAL,
+ access_rx_rbuf_block_list_read_unc_err_cnt),
+[C_RX_RBUF_LOOKUP_DES_COR_ERR] = CNTR_ELEM("RxRbufLookupDesCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_lookup_des_cor_err_cnt),
+[C_RX_RBUF_LOOKUP_DES_UNC_ERR] = CNTR_ELEM("RxRbufLookupDesUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_lookup_des_unc_err_cnt),
+[C_RX_RBUF_LOOKUP_DES_REG_UNC_COR_ERR] = CNTR_ELEM(
+ "RxRbufLookupDesRegUncCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_lookup_des_reg_unc_cor_err_cnt),
+[C_RX_RBUF_LOOKUP_DES_REG_UNC_ERR] = CNTR_ELEM("RxRbufLookupDesRegUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_lookup_des_reg_unc_err_cnt),
+[C_RX_RBUF_FREE_LIST_COR_ERR] = CNTR_ELEM("RxRbufFreeListCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_free_list_cor_err_cnt),
+[C_RX_RBUF_FREE_LIST_UNC_ERR] = CNTR_ELEM("RxRbufFreeListUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rbuf_free_list_unc_err_cnt),
+[C_RX_RCV_FSM_ENCODING_ERR] = CNTR_ELEM("RxRcvFsmEncodingErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_fsm_encoding_err_cnt),
+[C_RX_DMA_FLAG_COR_ERR] = CNTR_ELEM("RxDmaFlagCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_flag_cor_err_cnt),
+[C_RX_DMA_FLAG_UNC_ERR] = CNTR_ELEM("RxDmaFlagUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_flag_unc_err_cnt),
+[C_RX_DC_SOP_EOP_PARITY_ERR] = CNTR_ELEM("RxDcSopEopParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dc_sop_eop_parity_err_cnt),
+[C_RX_RCV_CSR_PARITY_ERR] = CNTR_ELEM("RxRcvCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_csr_parity_err_cnt),
+[C_RX_RCV_QP_MAP_TABLE_COR_ERR] = CNTR_ELEM("RxRcvQpMapTableCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_qp_map_table_cor_err_cnt),
+[C_RX_RCV_QP_MAP_TABLE_UNC_ERR] = CNTR_ELEM("RxRcvQpMapTableUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_qp_map_table_unc_err_cnt),
+[C_RX_RCV_DATA_COR_ERR] = CNTR_ELEM("RxRcvDataCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_data_cor_err_cnt),
+[C_RX_RCV_DATA_UNC_ERR] = CNTR_ELEM("RxRcvDataUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_data_unc_err_cnt),
+[C_RX_RCV_HDR_COR_ERR] = CNTR_ELEM("RxRcvHdrCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_hdr_cor_err_cnt),
+[C_RX_RCV_HDR_UNC_ERR] = CNTR_ELEM("RxRcvHdrUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_rcv_hdr_unc_err_cnt),
+[C_RX_DC_INTF_PARITY_ERR] = CNTR_ELEM("RxDcIntfParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dc_intf_parity_err_cnt),
+[C_RX_DMA_CSR_COR_ERR] = CNTR_ELEM("RxDmaCsrCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_rx_dma_csr_cor_err_cnt),
+/* SendPioErrStatus */
+[C_PIO_PEC_SOP_HEAD_PARITY_ERR] = CNTR_ELEM("PioPecSopHeadParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_pec_sop_head_parity_err_cnt),
+[C_PIO_PCC_SOP_HEAD_PARITY_ERR] = CNTR_ELEM("PioPccSopHeadParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_pcc_sop_head_parity_err_cnt),
+[C_PIO_LAST_RETURNED_CNT_PARITY_ERR] = CNTR_ELEM("PioLastReturnedCntParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_pio_last_returned_cnt_parity_err_cnt),
+[C_PIO_CURRENT_FREE_CNT_PARITY_ERR] = CNTR_ELEM("PioCurrentFreeCntParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_pio_current_free_cnt_parity_err_cnt),
+[C_PIO_RSVD_31_ERR] = CNTR_ELEM("Pio Reserved 31", 0, 0,
+ CNTR_NORMAL,
+ access_pio_reserved_31_err_cnt),
+[C_PIO_RSVD_30_ERR] = CNTR_ELEM("Pio Reserved 30", 0, 0,
+ CNTR_NORMAL,
+ access_pio_reserved_30_err_cnt),
+[C_PIO_PPMC_SOP_LEN_ERR] = CNTR_ELEM("PioPpmcSopLenErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_ppmc_sop_len_err_cnt),
+[C_PIO_PPMC_BQC_MEM_PARITY_ERR] = CNTR_ELEM("PioPpmcBqcMemParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_ppmc_bqc_mem_parity_err_cnt),
+[C_PIO_VL_FIFO_PARITY_ERR] = CNTR_ELEM("PioVlFifoParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_vl_fifo_parity_err_cnt),
+[C_PIO_VLF_SOP_PARITY_ERR] = CNTR_ELEM("PioVlfSopParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_vlf_sop_parity_err_cnt),
+[C_PIO_VLF_V1_LEN_PARITY_ERR] = CNTR_ELEM("PioVlfVlLenParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_vlf_v1_len_parity_err_cnt),
+[C_PIO_BLOCK_QW_COUNT_PARITY_ERR] = CNTR_ELEM("PioBlockQwCountParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_block_qw_count_parity_err_cnt),
+[C_PIO_WRITE_QW_VALID_PARITY_ERR] = CNTR_ELEM("PioWriteQwValidParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_write_qw_valid_parity_err_cnt),
+[C_PIO_STATE_MACHINE_ERR] = CNTR_ELEM("PioStateMachineErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_state_machine_err_cnt),
+[C_PIO_WRITE_DATA_PARITY_ERR] = CNTR_ELEM("PioWriteDataParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_write_data_parity_err_cnt),
+[C_PIO_HOST_ADDR_MEM_COR_ERR] = CNTR_ELEM("PioHostAddrMemCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_host_addr_mem_cor_err_cnt),
+[C_PIO_HOST_ADDR_MEM_UNC_ERR] = CNTR_ELEM("PioHostAddrMemUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_host_addr_mem_unc_err_cnt),
+[C_PIO_PKT_EVICT_SM_OR_ARM_SM_ERR] = CNTR_ELEM("PioPktEvictSmOrArbSmErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_pkt_evict_sm_or_arb_sm_err_cnt),
+[C_PIO_INIT_SM_IN_ERR] = CNTR_ELEM("PioInitSmInErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_init_sm_in_err_cnt),
+[C_PIO_PPMC_PBL_FIFO_ERR] = CNTR_ELEM("PioPpmcPblFifoErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_ppmc_pbl_fifo_err_cnt),
+[C_PIO_CREDIT_RET_FIFO_PARITY_ERR] = CNTR_ELEM("PioCreditRetFifoParityErr", 0,
+ 0, CNTR_NORMAL,
+ access_pio_credit_ret_fifo_parity_err_cnt),
+[C_PIO_V1_LEN_MEM_BANK1_COR_ERR] = CNTR_ELEM("PioVlLenMemBank1CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_v1_len_mem_bank1_cor_err_cnt),
+[C_PIO_V1_LEN_MEM_BANK0_COR_ERR] = CNTR_ELEM("PioVlLenMemBank0CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_v1_len_mem_bank0_cor_err_cnt),
+[C_PIO_V1_LEN_MEM_BANK1_UNC_ERR] = CNTR_ELEM("PioVlLenMemBank1UncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_v1_len_mem_bank1_unc_err_cnt),
+[C_PIO_V1_LEN_MEM_BANK0_UNC_ERR] = CNTR_ELEM("PioVlLenMemBank0UncErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_v1_len_mem_bank0_unc_err_cnt),
+[C_PIO_SM_PKT_RESET_PARITY_ERR] = CNTR_ELEM("PioSmPktResetParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_sm_pkt_reset_parity_err_cnt),
+[C_PIO_PKT_EVICT_FIFO_PARITY_ERR] = CNTR_ELEM("PioPktEvictFifoParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_pkt_evict_fifo_parity_err_cnt),
+[C_PIO_SBRDCTRL_CRREL_FIFO_PARITY_ERR] = CNTR_ELEM(
+ "PioSbrdctrlCrrelFifoParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_sbrdctrl_crrel_fifo_parity_err_cnt),
+[C_PIO_SBRDCTL_CRREL_PARITY_ERR] = CNTR_ELEM("PioSbrdctlCrrelParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_sbrdctl_crrel_parity_err_cnt),
+[C_PIO_PEC_FIFO_PARITY_ERR] = CNTR_ELEM("PioPecFifoParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_pec_fifo_parity_err_cnt),
+[C_PIO_PCC_FIFO_PARITY_ERR] = CNTR_ELEM("PioPccFifoParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_pcc_fifo_parity_err_cnt),
+[C_PIO_SB_MEM_FIFO1_ERR] = CNTR_ELEM("PioSbMemFifo1Err", 0, 0,
+ CNTR_NORMAL,
+ access_pio_sb_mem_fifo1_err_cnt),
+[C_PIO_SB_MEM_FIFO0_ERR] = CNTR_ELEM("PioSbMemFifo0Err", 0, 0,
+ CNTR_NORMAL,
+ access_pio_sb_mem_fifo0_err_cnt),
+[C_PIO_CSR_PARITY_ERR] = CNTR_ELEM("PioCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_csr_parity_err_cnt),
+[C_PIO_WRITE_ADDR_PARITY_ERR] = CNTR_ELEM("PioWriteAddrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_write_addr_parity_err_cnt),
+[C_PIO_WRITE_BAD_CTXT_ERR] = CNTR_ELEM("PioWriteBadCtxtErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_write_bad_ctxt_err_cnt),
+/* SendDmaErrStatus */
+[C_SDMA_PCIE_REQ_TRACKING_COR_ERR] = CNTR_ELEM("SDmaPcieReqTrackingCorErr", 0,
+ 0, CNTR_NORMAL,
+ access_sdma_pcie_req_tracking_cor_err_cnt),
+[C_SDMA_PCIE_REQ_TRACKING_UNC_ERR] = CNTR_ELEM("SDmaPcieReqTrackingUncErr", 0,
+ 0, CNTR_NORMAL,
+ access_sdma_pcie_req_tracking_unc_err_cnt),
+[C_SDMA_CSR_PARITY_ERR] = CNTR_ELEM("SDmaCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_csr_parity_err_cnt),
+[C_SDMA_RPY_TAG_ERR] = CNTR_ELEM("SDmaRpyTagErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_rpy_tag_err_cnt),
+/* SendEgressErrStatus */
+[C_TX_READ_PIO_MEMORY_CSR_UNC_ERR] = CNTR_ELEM("TxReadPioMemoryCsrUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_read_pio_memory_csr_unc_err_cnt),
+[C_TX_READ_SDMA_MEMORY_CSR_UNC_ERR] = CNTR_ELEM("TxReadSdmaMemoryCsrUncErr", 0,
+ 0, CNTR_NORMAL,
+ access_tx_read_sdma_memory_csr_err_cnt),
+[C_TX_EGRESS_FIFO_COR_ERR] = CNTR_ELEM("TxEgressFifoCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_egress_fifo_cor_err_cnt),
+[C_TX_READ_PIO_MEMORY_COR_ERR] = CNTR_ELEM("TxReadPioMemoryCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_read_pio_memory_cor_err_cnt),
+[C_TX_READ_SDMA_MEMORY_COR_ERR] = CNTR_ELEM("TxReadSdmaMemoryCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_read_sdma_memory_cor_err_cnt),
+[C_TX_SB_HDR_COR_ERR] = CNTR_ELEM("TxSbHdrCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_sb_hdr_cor_err_cnt),
+[C_TX_CREDIT_OVERRUN_ERR] = CNTR_ELEM("TxCreditOverrunErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_credit_overrun_err_cnt),
+[C_TX_LAUNCH_FIFO8_COR_ERR] = CNTR_ELEM("TxLaunchFifo8CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo8_cor_err_cnt),
+[C_TX_LAUNCH_FIFO7_COR_ERR] = CNTR_ELEM("TxLaunchFifo7CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo7_cor_err_cnt),
+[C_TX_LAUNCH_FIFO6_COR_ERR] = CNTR_ELEM("TxLaunchFifo6CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo6_cor_err_cnt),
+[C_TX_LAUNCH_FIFO5_COR_ERR] = CNTR_ELEM("TxLaunchFifo5CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo5_cor_err_cnt),
+[C_TX_LAUNCH_FIFO4_COR_ERR] = CNTR_ELEM("TxLaunchFifo4CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo4_cor_err_cnt),
+[C_TX_LAUNCH_FIFO3_COR_ERR] = CNTR_ELEM("TxLaunchFifo3CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo3_cor_err_cnt),
+[C_TX_LAUNCH_FIFO2_COR_ERR] = CNTR_ELEM("TxLaunchFifo2CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo2_cor_err_cnt),
+[C_TX_LAUNCH_FIFO1_COR_ERR] = CNTR_ELEM("TxLaunchFifo1CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo1_cor_err_cnt),
+[C_TX_LAUNCH_FIFO0_COR_ERR] = CNTR_ELEM("TxLaunchFifo0CorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_fifo0_cor_err_cnt),
+[C_TX_CREDIT_RETURN_VL_ERR] = CNTR_ELEM("TxCreditReturnVLErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_credit_return_vl_err_cnt),
+[C_TX_HCRC_INSERTION_ERR] = CNTR_ELEM("TxHcrcInsertionErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_hcrc_insertion_err_cnt),
+[C_TX_EGRESS_FIFI_UNC_ERR] = CNTR_ELEM("TxEgressFifoUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_egress_fifo_unc_err_cnt),
+[C_TX_READ_PIO_MEMORY_UNC_ERR] = CNTR_ELEM("TxReadPioMemoryUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_read_pio_memory_unc_err_cnt),
+[C_TX_READ_SDMA_MEMORY_UNC_ERR] = CNTR_ELEM("TxReadSdmaMemoryUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_read_sdma_memory_unc_err_cnt),
+[C_TX_SB_HDR_UNC_ERR] = CNTR_ELEM("TxSbHdrUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_sb_hdr_unc_err_cnt),
+[C_TX_CREDIT_RETURN_PARITY_ERR] = CNTR_ELEM("TxCreditReturnParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_credit_return_partiy_err_cnt),
+[C_TX_LAUNCH_FIFO8_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo8UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo8_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO7_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo7UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo7_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO6_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo6UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo6_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO5_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo5UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo5_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO4_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo4UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo4_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO3_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo3UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo3_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO2_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo2UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo2_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO1_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo1UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo1_unc_or_parity_err_cnt),
+[C_TX_LAUNCH_FIFO0_UNC_OR_PARITY_ERR] = CNTR_ELEM("TxLaunchFifo0UncOrParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_launch_fifo0_unc_or_parity_err_cnt),
+[C_TX_SDMA15_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma15DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma15_disallowed_packet_err_cnt),
+[C_TX_SDMA14_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma14DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma14_disallowed_packet_err_cnt),
+[C_TX_SDMA13_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma13DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma13_disallowed_packet_err_cnt),
+[C_TX_SDMA12_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma12DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma12_disallowed_packet_err_cnt),
+[C_TX_SDMA11_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma11DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma11_disallowed_packet_err_cnt),
+[C_TX_SDMA10_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma10DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma10_disallowed_packet_err_cnt),
+[C_TX_SDMA9_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma9DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma9_disallowed_packet_err_cnt),
+[C_TX_SDMA8_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma8DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma8_disallowed_packet_err_cnt),
+[C_TX_SDMA7_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma7DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma7_disallowed_packet_err_cnt),
+[C_TX_SDMA6_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma6DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma6_disallowed_packet_err_cnt),
+[C_TX_SDMA5_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma5DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma5_disallowed_packet_err_cnt),
+[C_TX_SDMA4_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma4DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma4_disallowed_packet_err_cnt),
+[C_TX_SDMA3_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma3DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma3_disallowed_packet_err_cnt),
+[C_TX_SDMA2_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma2DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma2_disallowed_packet_err_cnt),
+[C_TX_SDMA1_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma1DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma1_disallowed_packet_err_cnt),
+[C_TX_SDMA0_DISALLOWED_PACKET_ERR] = CNTR_ELEM("TxSdma0DisallowedPacketErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma0_disallowed_packet_err_cnt),
+[C_TX_CONFIG_PARITY_ERR] = CNTR_ELEM("TxConfigParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_config_parity_err_cnt),
+[C_TX_SBRD_CTL_CSR_PARITY_ERR] = CNTR_ELEM("TxSbrdCtlCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_sbrd_ctl_csr_parity_err_cnt),
+[C_TX_LAUNCH_CSR_PARITY_ERR] = CNTR_ELEM("TxLaunchCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_launch_csr_parity_err_cnt),
+[C_TX_ILLEGAL_CL_ERR] = CNTR_ELEM("TxIllegalVLErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_illegal_vl_err_cnt),
+[C_TX_SBRD_CTL_STATE_MACHINE_PARITY_ERR] = CNTR_ELEM(
+ "TxSbrdCtlStateMachineParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_sbrd_ctl_state_machine_parity_err_cnt),
+[C_TX_RESERVED_10] = CNTR_ELEM("Tx Egress Reserved 10", 0, 0,
+ CNTR_NORMAL,
+ access_egress_reserved_10_err_cnt),
+[C_TX_RESERVED_9] = CNTR_ELEM("Tx Egress Reserved 9", 0, 0,
+ CNTR_NORMAL,
+ access_egress_reserved_9_err_cnt),
+[C_TX_SDMA_LAUNCH_INTF_PARITY_ERR] = CNTR_ELEM("TxSdmaLaunchIntfParityErr",
+ 0, 0, CNTR_NORMAL,
+ access_tx_sdma_launch_intf_parity_err_cnt),
+[C_TX_PIO_LAUNCH_INTF_PARITY_ERR] = CNTR_ELEM("TxPioLaunchIntfParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_pio_launch_intf_parity_err_cnt),
+[C_TX_RESERVED_6] = CNTR_ELEM("Tx Egress Reserved 6", 0, 0,
+ CNTR_NORMAL,
+ access_egress_reserved_6_err_cnt),
+[C_TX_INCORRECT_LINK_STATE_ERR] = CNTR_ELEM("TxIncorrectLinkStateErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_incorrect_link_state_err_cnt),
+[C_TX_LINK_DOWN_ERR] = CNTR_ELEM("TxLinkdownErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_linkdown_err_cnt),
+[C_TX_EGRESS_FIFO_UNDERRUN_OR_PARITY_ERR] = CNTR_ELEM(
+ "EgressFifoUnderrunOrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_egress_fifi_underrun_or_parity_err_cnt),
+[C_TX_RESERVED_2] = CNTR_ELEM("Tx Egress Reserved 2", 0, 0,
+ CNTR_NORMAL,
+ access_egress_reserved_2_err_cnt),
+[C_TX_PKT_INTEGRITY_MEM_UNC_ERR] = CNTR_ELEM("TxPktIntegrityMemUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_pkt_integrity_mem_unc_err_cnt),
+[C_TX_PKT_INTEGRITY_MEM_COR_ERR] = CNTR_ELEM("TxPktIntegrityMemCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_tx_pkt_integrity_mem_cor_err_cnt),
+/* SendErrStatus */
+[C_SEND_CSR_WRITE_BAD_ADDR_ERR] = CNTR_ELEM("SendCsrWriteBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_send_csr_write_bad_addr_err_cnt),
+[C_SEND_CSR_READ_BAD_ADD_ERR] = CNTR_ELEM("SendCsrReadBadAddrErr", 0, 0,
+ CNTR_NORMAL,
+ access_send_csr_read_bad_addr_err_cnt),
+[C_SEND_CSR_PARITY_ERR] = CNTR_ELEM("SendCsrParityErr", 0, 0,
+ CNTR_NORMAL,
+ access_send_csr_parity_cnt),
+/* SendCtxtErrStatus */
+[C_PIO_WRITE_OUT_OF_BOUNDS_ERR] = CNTR_ELEM("PioWriteOutOfBoundsErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_write_out_of_bounds_err_cnt),
+[C_PIO_WRITE_OVERFLOW_ERR] = CNTR_ELEM("PioWriteOverflowErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_write_overflow_err_cnt),
+[C_PIO_WRITE_CROSSES_BOUNDARY_ERR] = CNTR_ELEM("PioWriteCrossesBoundaryErr",
+ 0, 0, CNTR_NORMAL,
+ access_pio_write_crosses_boundary_err_cnt),
+[C_PIO_DISALLOWED_PACKET_ERR] = CNTR_ELEM("PioDisallowedPacketErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_disallowed_packet_err_cnt),
+[C_PIO_INCONSISTENT_SOP_ERR] = CNTR_ELEM("PioInconsistentSopErr", 0, 0,
+ CNTR_NORMAL,
+ access_pio_inconsistent_sop_err_cnt),
+/* SendDmaEngErrStatus */
+[C_SDMA_HEADER_REQUEST_FIFO_COR_ERR] = CNTR_ELEM("SDmaHeaderRequestFifoCorErr",
+ 0, 0, CNTR_NORMAL,
+ access_sdma_header_request_fifo_cor_err_cnt),
+[C_SDMA_HEADER_STORAGE_COR_ERR] = CNTR_ELEM("SDmaHeaderStorageCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_header_storage_cor_err_cnt),
+[C_SDMA_PACKET_TRACKING_COR_ERR] = CNTR_ELEM("SDmaPacketTrackingCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_packet_tracking_cor_err_cnt),
+[C_SDMA_ASSEMBLY_COR_ERR] = CNTR_ELEM("SDmaAssemblyCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_assembly_cor_err_cnt),
+[C_SDMA_DESC_TABLE_COR_ERR] = CNTR_ELEM("SDmaDescTableCorErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_desc_table_cor_err_cnt),
+[C_SDMA_HEADER_REQUEST_FIFO_UNC_ERR] = CNTR_ELEM("SDmaHeaderRequestFifoUncErr",
+ 0, 0, CNTR_NORMAL,
+ access_sdma_header_request_fifo_unc_err_cnt),
+[C_SDMA_HEADER_STORAGE_UNC_ERR] = CNTR_ELEM("SDmaHeaderStorageUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_header_storage_unc_err_cnt),
+[C_SDMA_PACKET_TRACKING_UNC_ERR] = CNTR_ELEM("SDmaPacketTrackingUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_packet_tracking_unc_err_cnt),
+[C_SDMA_ASSEMBLY_UNC_ERR] = CNTR_ELEM("SDmaAssemblyUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_assembly_unc_err_cnt),
+[C_SDMA_DESC_TABLE_UNC_ERR] = CNTR_ELEM("SDmaDescTableUncErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_desc_table_unc_err_cnt),
+[C_SDMA_TIMEOUT_ERR] = CNTR_ELEM("SDmaTimeoutErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_timeout_err_cnt),
+[C_SDMA_HEADER_LENGTH_ERR] = CNTR_ELEM("SDmaHeaderLengthErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_header_length_err_cnt),
+[C_SDMA_HEADER_ADDRESS_ERR] = CNTR_ELEM("SDmaHeaderAddressErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_header_address_err_cnt),
+[C_SDMA_HEADER_SELECT_ERR] = CNTR_ELEM("SDmaHeaderSelectErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_header_select_err_cnt),
+[C_SMDA_RESERVED_9] = CNTR_ELEM("SDma Reserved 9", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_reserved_9_err_cnt),
+[C_SDMA_PACKET_DESC_OVERFLOW_ERR] = CNTR_ELEM("SDmaPacketDescOverflowErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_packet_desc_overflow_err_cnt),
+[C_SDMA_LENGTH_MISMATCH_ERR] = CNTR_ELEM("SDmaLengthMismatchErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_length_mismatch_err_cnt),
+[C_SDMA_HALT_ERR] = CNTR_ELEM("SDmaHaltErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_halt_err_cnt),
+[C_SDMA_MEM_READ_ERR] = CNTR_ELEM("SDmaMemReadErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_mem_read_err_cnt),
+[C_SDMA_FIRST_DESC_ERR] = CNTR_ELEM("SDmaFirstDescErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_first_desc_err_cnt),
+[C_SDMA_TAIL_OUT_OF_BOUNDS_ERR] = CNTR_ELEM("SDmaTailOutOfBoundsErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_tail_out_of_bounds_err_cnt),
+[C_SDMA_TOO_LONG_ERR] = CNTR_ELEM("SDmaTooLongErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_too_long_err_cnt),
+[C_SDMA_GEN_MISMATCH_ERR] = CNTR_ELEM("SDmaGenMismatchErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_gen_mismatch_err_cnt),
+[C_SDMA_WRONG_DW_ERR] = CNTR_ELEM("SDmaWrongDwErr", 0, 0,
+ CNTR_NORMAL,
+ access_sdma_wrong_dw_err_cnt),
};
static struct cntr_entry port_cntrs[PORT_CNTR_LAST] = {
@@ -1762,6 +4890,8 @@ static struct cntr_entry port_cntrs[PORT_CNTR_LAST] = {
access_sw_link_dn_cnt),
[C_SW_LINK_UP] = CNTR_ELEM("SwLinkUp", 0, 0, CNTR_SYNTH | CNTR_32BIT,
access_sw_link_up_cnt),
+[C_SW_UNKNOWN_FRAME] = CNTR_ELEM("UnknownFrame", 0, 0, CNTR_NORMAL,
+ access_sw_unknown_frame_cnt),
[C_SW_XMIT_DSCD] = CNTR_ELEM("XmitDscd", 0, 0, CNTR_SYNTH | CNTR_32BIT,
access_sw_xmit_discards),
[C_SW_XMIT_DSCD_VL] = CNTR_ELEM("XmitDscdVl", 0, 0,
@@ -1873,13 +5003,6 @@ static struct cntr_entry port_cntrs[PORT_CNTR_LAST] = {
/* ======================================================================== */
-/* return true if this is chip revision revision a0 */
-int is_a0(struct hfi1_devdata *dd)
-{
- return ((dd->revision >> CCE_REVISION_CHIP_REV_MINOR_SHIFT)
- & CCE_REVISION_CHIP_REV_MINOR_MASK) == 0;
-}
-
/* return true if this is chip revision revision a */
int is_ax(struct hfi1_devdata *dd)
{
@@ -1895,7 +5018,7 @@ int is_bx(struct hfi1_devdata *dd)
u8 chip_rev_minor =
dd->revision >> CCE_REVISION_CHIP_REV_MINOR_SHIFT
& CCE_REVISION_CHIP_REV_MINOR_MASK;
- return !!(chip_rev_minor & 0x10);
+ return (chip_rev_minor & 0xF0) == 0x10;
}
/*
@@ -2182,6 +5305,7 @@ static char *send_err_status_string(char *buf, int buf_len, u64 flags)
static void handle_cce_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
char buf[96];
+ int i = 0;
/*
* For most these errors, there is nothing that can be done except
@@ -2190,13 +5314,20 @@ static void handle_cce_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
dd_dev_info(dd, "CCE Error: %s\n",
cce_err_status_string(buf, sizeof(buf), reg));
- if ((reg & CCE_ERR_STATUS_CCE_CLI2_ASYNC_FIFO_PARITY_ERR_SMASK)
- && is_a0(dd)
- && (dd->icode != ICODE_FUNCTIONAL_SIMULATOR)) {
+ if ((reg & CCE_ERR_STATUS_CCE_CLI2_ASYNC_FIFO_PARITY_ERR_SMASK) &&
+ is_ax(dd) && (dd->icode != ICODE_FUNCTIONAL_SIMULATOR)) {
/* this error requires a manual drop into SPC freeze mode */
/* then a fix up */
start_freeze_handling(dd->pport, FREEZE_SELF);
}
+
+ for (i = 0; i < NUM_CCE_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i)) {
+ incr_cntr64(&dd->cce_err_status_cnt[i]);
+ /* maintain a counter over all cce_err_status errors */
+ incr_cntr64(&dd->sw_cce_err_status_aggregate);
+ }
+ }
}
/*
@@ -2241,6 +5372,7 @@ static void free_rcverr(struct hfi1_devdata *dd)
static void handle_rxe_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
char buf[96];
+ int i = 0;
dd_dev_info(dd, "Receive Error: %s\n",
rxe_err_status_string(buf, sizeof(buf), reg));
@@ -2252,41 +5384,63 @@ static void handle_rxe_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
* Freeze mode recovery is disabled for the errors
* in RXE_FREEZE_ABORT_MASK
*/
- if (is_a0(dd) && (reg & RXE_FREEZE_ABORT_MASK))
+ if (is_ax(dd) && (reg & RXE_FREEZE_ABORT_MASK))
flags = FREEZE_ABORT;
start_freeze_handling(dd->pport, flags);
}
+
+ for (i = 0; i < NUM_RCV_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i))
+ incr_cntr64(&dd->rcv_err_status_cnt[i]);
+ }
}
static void handle_misc_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
char buf[96];
+ int i = 0;
dd_dev_info(dd, "Misc Error: %s",
misc_err_status_string(buf, sizeof(buf), reg));
+ for (i = 0; i < NUM_MISC_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i))
+ incr_cntr64(&dd->misc_err_status_cnt[i]);
+ }
}
static void handle_pio_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
char buf[96];
+ int i = 0;
dd_dev_info(dd, "PIO Error: %s\n",
pio_err_status_string(buf, sizeof(buf), reg));
if (reg & ALL_PIO_FREEZE_ERR)
start_freeze_handling(dd->pport, 0);
+
+ for (i = 0; i < NUM_SEND_PIO_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i))
+ incr_cntr64(&dd->send_pio_err_status_cnt[i]);
+ }
}
static void handle_sdma_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
char buf[96];
+ int i = 0;
dd_dev_info(dd, "SDMA Error: %s\n",
sdma_err_status_string(buf, sizeof(buf), reg));
if (reg & ALL_SDMA_FREEZE_ERR)
start_freeze_handling(dd->pport, 0);
+
+ for (i = 0; i < NUM_SEND_DMA_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i))
+ incr_cntr64(&dd->send_dma_err_status_cnt[i]);
+ }
}
static void count_port_inactive(struct hfi1_devdata *dd)
@@ -2352,10 +5506,11 @@ static void handle_egress_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
u64 reg_copy = reg, handled = 0;
char buf[96];
+ int i = 0;
if (reg & ALL_TXE_EGRESS_FREEZE_ERR)
start_freeze_handling(dd->pport, 0);
- if (is_a0(dd) && (reg &
+ if (is_ax(dd) && (reg &
SEND_EGRESS_ERR_STATUS_TX_CREDIT_RETURN_VL_ERR_SMASK)
&& (dd->icode != ICODE_FUNCTIONAL_SIMULATOR))
start_freeze_handling(dd->pport, 0);
@@ -2383,15 +5538,25 @@ static void handle_egress_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
if (reg)
dd_dev_info(dd, "Egress Error: %s\n",
egress_err_status_string(buf, sizeof(buf), reg));
+
+ for (i = 0; i < NUM_SEND_EGRESS_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i))
+ incr_cntr64(&dd->send_egress_err_status_cnt[i]);
+ }
}
static void handle_txe_err(struct hfi1_devdata *dd, u32 unused, u64 reg)
{
char buf[96];
+ int i = 0;
dd_dev_info(dd, "Send Error: %s\n",
send_err_status_string(buf, sizeof(buf), reg));
+ for (i = 0; i < NUM_SEND_ERR_STATUS_COUNTERS; i++) {
+ if (reg & (1ull << i))
+ incr_cntr64(&dd->send_err_status_cnt[i]);
+ }
}
/*
@@ -2483,6 +5648,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd,
char flags[96];
u64 status;
u32 sw_index;
+ int i = 0;
sw_index = dd->hw_to_sw[hw_context];
if (sw_index >= dd->num_send_contexts) {
@@ -2516,12 +5682,23 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd,
*/
if (sc->type != SC_USER)
queue_work(dd->pport->hfi1_wq, &sc->halt_work);
+
+ /*
+ * Update the counters for the corresponding status bits.
+ * Note that these particular counters are aggregated over all
+ * 160 contexts.
+ */
+ for (i = 0; i < NUM_SEND_CTXT_ERR_STATUS_COUNTERS; i++) {
+ if (status & (1ull << i))
+ incr_cntr64(&dd->sw_ctxt_err_status_cnt[i]);
+ }
}
static void handle_sdma_eng_err(struct hfi1_devdata *dd,
unsigned int source, u64 status)
{
struct sdma_engine *sde;
+ int i = 0;
sde = &dd->per_sdma[source];
#ifdef CONFIG_SDMA_VERBOSITY
@@ -2531,6 +5708,16 @@ static void handle_sdma_eng_err(struct hfi1_devdata *dd,
sde->this_idx, source, (unsigned long long)status);
#endif
sdma_engine_error(sde, status);
+
+ /*
+ * Update the counters for the corresponding status bits.
+ * Note that these particular counters are aggregated over
+ * all 16 DMA engines.
+ */
+ for (i = 0; i < NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS; i++) {
+ if (status & (1ull << i))
+ incr_cntr64(&dd->sw_send_dma_eng_err_status_cnt[i]);
+ }
}
/*
@@ -3050,7 +6237,7 @@ static void adjust_lcb_for_fpga_serdes(struct hfi1_devdata *dd)
/* else this is _p */
version = emulator_rev(dd);
- if (!is_a0(dd))
+ if (!is_ax(dd))
version = 0x2d; /* all B0 use 0x2d or higher settings */
if (version <= 0x12) {
@@ -3313,7 +6500,6 @@ void handle_freeze(struct work_struct *work)
struct hfi1_devdata *dd = ppd->dd;
/* wait for freeze indicators on all affected blocks */
- dd_dev_info(dd, "Entering SPC freeze\n");
wait_for_freeze_status(dd, 1);
/* SPC is now frozen */
@@ -3336,7 +6522,7 @@ void handle_freeze(struct work_struct *work)
write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_UNFREEZE_SMASK);
wait_for_freeze_status(dd, 0);
- if (is_a0(dd)) {
+ if (is_ax(dd)) {
write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_FREEZE_SMASK);
wait_for_freeze_status(dd, 1);
write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_UNFREEZE_SMASK);
@@ -3371,7 +6557,6 @@ void handle_freeze(struct work_struct *work)
wake_up(&dd->event_queue);
/* no longer frozen */
- dd_dev_err(dd, "Exiting SPC freeze\n");
}
/*
@@ -3542,10 +6727,10 @@ static void add_full_mgmt_pkey(struct hfi1_pportdata *ppd)
{
struct hfi1_devdata *dd = ppd->dd;
- /* Sanity check - ppd->pkeys[2] should be 0 */
- if (ppd->pkeys[2] != 0)
- dd_dev_err(dd, "%s pkey[2] already set to 0x%x, resetting it to 0x%x\n",
- __func__, ppd->pkeys[2], FULL_MGMT_P_KEY);
+ /* Sanity check - ppd->pkeys[2] should be 0, or already initalized */
+ if (!((ppd->pkeys[2] == 0) || (ppd->pkeys[2] == FULL_MGMT_P_KEY)))
+ dd_dev_warn(dd, "%s pkey[2] already set to 0x%x, resetting it to 0x%x\n",
+ __func__, ppd->pkeys[2], FULL_MGMT_P_KEY);
ppd->pkeys[2] = FULL_MGMT_P_KEY;
(void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_PKEYS, 0);
}
@@ -3864,7 +7049,7 @@ void handle_verify_cap(struct work_struct *work)
* REPLAY_BUF_MBE_SMASK
* FLIT_INPUT_BUF_MBE_SMASK
*/
- if (is_a0(dd)) { /* fixed in B0 */
+ if (is_ax(dd)) { /* fixed in B0 */
reg = read_csr(dd, DC_LCB_CFG_LINK_KILL_EN);
reg |= DC_LCB_CFG_LINK_KILL_EN_REPLAY_BUF_MBE_SMASK
| DC_LCB_CFG_LINK_KILL_EN_FLIT_INPUT_BUF_MBE_SMASK;
@@ -3907,18 +7092,32 @@ void handle_verify_cap(struct work_struct *work)
*/
void apply_link_downgrade_policy(struct hfi1_pportdata *ppd, int refresh_widths)
{
- int skip = 1;
int do_bounce = 0;
- u16 lwde = ppd->link_width_downgrade_enabled;
+ int tries;
+ u16 lwde;
u16 tx, rx;
+ /* use the hls lock to avoid a race with actual link up */
+ tries = 0;
+retry:
mutex_lock(&ppd->hls_lock);
/* only apply if the link is up */
- if (ppd->host_link_state & HLS_UP)
- skip = 0;
- mutex_unlock(&ppd->hls_lock);
- if (skip)
- return;
+ if (!(ppd->host_link_state & HLS_UP)) {
+ /* still going up..wait and retry */
+ if (ppd->host_link_state & HLS_GOING_UP) {
+ if (++tries < 1000) {
+ mutex_unlock(&ppd->hls_lock);
+ usleep_range(100, 120); /* arbitrary */
+ goto retry;
+ }
+ dd_dev_err(ppd->dd,
+ "%s: giving up waiting for link state change\n",
+ __func__);
+ }
+ goto done;
+ }
+
+ lwde = ppd->link_width_downgrade_enabled;
if (refresh_widths) {
get_link_widths(ppd->dd, &tx, &rx);
@@ -3956,6 +7155,9 @@ void apply_link_downgrade_policy(struct hfi1_pportdata *ppd, int refresh_widths)
do_bounce = 1;
}
+done:
+ mutex_unlock(&ppd->hls_lock);
+
if (do_bounce) {
set_link_down_reason(ppd, OPA_LINKDOWN_REASON_WIDTH_POLICY, 0,
OPA_LINKDOWN_REASON_WIDTH_POLICY);
@@ -4046,6 +7248,11 @@ static void handle_8051_interrupt(struct hfi1_devdata *dd, u32 unused, u64 reg)
}
err &= ~(u64)FAILED_LNI;
}
+ /* unknown frames can happen durning LNI, just count */
+ if (err & UNKNOWN_FRAME) {
+ ppd->unknown_frame_count++;
+ err &= ~(u64)UNKNOWN_FRAME;
+ }
if (err) {
/* report remaining errors, but do not do anything */
dd_dev_err(dd, "8051 info error: %s\n",
@@ -4774,13 +7981,25 @@ int read_lcb_csr(struct hfi1_devdata *dd, u32 addr, u64 *data)
*/
static int write_lcb_via_8051(struct hfi1_devdata *dd, u32 addr, u64 data)
{
+ u32 regno;
+ int ret;
- if (acquire_lcb_access(dd, 0) == 0) {
- write_csr(dd, addr, data);
- release_lcb_access(dd, 0);
- return 0;
+ if (dd->icode == ICODE_FUNCTIONAL_SIMULATOR ||
+ (dd->dc8051_ver < dc8051_ver(0, 20))) {
+ if (acquire_lcb_access(dd, 0) == 0) {
+ write_csr(dd, addr, data);
+ release_lcb_access(dd, 0);
+ return 0;
+ }
+ return -EBUSY;
}
- return -EBUSY;
+
+ /* register is an index of LCB registers: (offset - base) / 8 */
+ regno = (addr - DC_LCB_CFG_RUN) >> 3;
+ ret = do_8051_command(dd, HCMD_WRITE_LCB_CSR, regno, &data);
+ if (ret != HCMD_SUCCESS)
+ return -EBUSY;
+ return 0;
}
/*
@@ -4862,6 +8081,26 @@ static int do_8051_command(
*/
/*
+ * When writing a LCB CSR, out_data contains the full value to
+ * to be written, while in_data contains the relative LCB
+ * address in 7:0. Do the work here, rather than the caller,
+ * of distrubting the write data to where it needs to go:
+ *
+ * Write data
+ * 39:00 -> in_data[47:8]
+ * 47:40 -> DC8051_CFG_EXT_DEV_0.RETURN_CODE
+ * 63:48 -> DC8051_CFG_EXT_DEV_0.RSP_DATA
+ */
+ if (type == HCMD_WRITE_LCB_CSR) {
+ in_data |= ((*out_data) & 0xffffffffffull) << 8;
+ reg = ((((*out_data) >> 40) & 0xff) <<
+ DC_DC8051_CFG_EXT_DEV_0_RETURN_CODE_SHIFT)
+ | ((((*out_data) >> 48) & 0xffff) <<
+ DC_DC8051_CFG_EXT_DEV_0_RSP_DATA_SHIFT);
+ write_csr(dd, DC_DC8051_CFG_EXT_DEV_0, reg);
+ }
+
+ /*
* Do two writes: the first to stabilize the type and req_data, the
* second to activate.
*/
@@ -5856,6 +9095,23 @@ void init_qsfp(struct hfi1_pportdata *ppd)
}
}
+/*
+ * Do a one-time initialize of the LCB block.
+ */
+static void init_lcb(struct hfi1_devdata *dd)
+{
+ /* the DC has been reset earlier in the driver load */
+
+ /* set LCB for cclk loopback on the port */
+ write_csr(dd, DC_LCB_CFG_TX_FIFOS_RESET, 0x01);
+ write_csr(dd, DC_LCB_CFG_LANE_WIDTH, 0x00);
+ write_csr(dd, DC_LCB_CFG_REINIT_AS_SLAVE, 0x00);
+ write_csr(dd, DC_LCB_CFG_CNT_FOR_SKIP_STALL, 0x110);
+ write_csr(dd, DC_LCB_CFG_CLK_CNTR, 0x08);
+ write_csr(dd, DC_LCB_CFG_LOOPBACK, 0x02);
+ write_csr(dd, DC_LCB_CFG_TX_FIFOS_RESET, 0x00);
+}
+
int bringup_serdes(struct hfi1_pportdata *ppd)
{
struct hfi1_devdata *dd = ppd->dd;
@@ -5877,6 +9133,9 @@ int bringup_serdes(struct hfi1_pportdata *ppd)
/* Set linkinit_reason on power up per OPA spec */
ppd->linkinit_reason = OPA_LINKINIT_REASON_LINKUP;
+ /* one-time init of the LCB */
+ init_lcb(dd);
+
if (loopback) {
ret = init_loopback(dd);
if (ret < 0)
@@ -6148,7 +9407,8 @@ u32 lrh_max_header_bytes(struct hfi1_devdata *dd)
static void set_send_length(struct hfi1_pportdata *ppd)
{
struct hfi1_devdata *dd = ppd->dd;
- u32 max_hb = lrh_max_header_bytes(dd), maxvlmtu = 0, dcmtu;
+ u32 max_hb = lrh_max_header_bytes(dd), dcmtu;
+ u32 maxvlmtu = dd->vld[15].mtu;
u64 len1 = 0, len2 = (((dd->vld[15].mtu + max_hb) >> 2)
& SEND_LEN_CHECK1_LEN_VL15_MASK) <<
SEND_LEN_CHECK1_LEN_VL15_SHIFT;
@@ -6319,9 +9579,10 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
* depending on how the link went down. The 8051 firmware
* will observe the needed wait time and only move to ready
* when that is completed. The largest of the quiet timeouts
- * is 2.5s, so wait that long and then a bit more.
+ * is 6s, so wait that long and then at least 0.5s more for
+ * other transitions, and another 0.5s for a buffer.
*/
- ret = wait_fm_ready(dd, 3000);
+ ret = wait_fm_ready(dd, 7000);
if (ret) {
dd_dev_err(dd,
"After going offline, timed out waiting for the 8051 to become ready to accept host requests\n");
@@ -7235,8 +10496,7 @@ static int set_buffer_control(struct hfi1_devdata *dd,
new_bc->vl[i].shared = 0;
}
new_total += be16_to_cpu(new_bc->overall_shared_limit);
- if (new_total > (u32)dd->link_credits)
- return -EINVAL;
+
/* fetch the current values */
get_buffer_control(dd, &cur_bc, &cur_total);
@@ -7282,8 +10542,8 @@ static int set_buffer_control(struct hfi1_devdata *dd,
*/
use_all_mask = 0;
if ((be16_to_cpu(new_bc->overall_shared_limit) <
- be16_to_cpu(cur_bc.overall_shared_limit))
- || (is_a0(dd) && any_shared_limit_changing)) {
+ be16_to_cpu(cur_bc.overall_shared_limit)) ||
+ (is_ax(dd) && any_shared_limit_changing)) {
set_global_shared(dd, 0);
cur_bc.overall_shared_limit = 0;
use_all_mask = 1;
@@ -7457,7 +10717,7 @@ int fm_set_table(struct hfi1_pportdata *ppd, int which, void *t)
*/
static int disable_data_vls(struct hfi1_devdata *dd)
{
- if (is_a0(dd))
+ if (is_ax(dd))
return 1;
pio_send_control(dd, PSC_DATA_VL_DISABLE);
@@ -7475,7 +10735,7 @@ static int disable_data_vls(struct hfi1_devdata *dd)
*/
int open_fill_data_vls(struct hfi1_devdata *dd)
{
- if (is_a0(dd))
+ if (is_ax(dd))
return 1;
pio_send_control(dd, PSC_DATA_VL_ENABLE);
@@ -7748,11 +11008,22 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt)
& RCV_TID_CTRL_TID_BASE_INDEX_MASK)
<< RCV_TID_CTRL_TID_BASE_INDEX_SHIFT);
write_kctxt_csr(dd, ctxt, RCV_TID_CTRL, reg);
- if (ctxt == VL15CTXT)
- write_csr(dd, RCV_VL15, VL15CTXT);
+ if (ctxt == HFI1_CTRL_CTXT)
+ write_csr(dd, RCV_VL15, HFI1_CTRL_CTXT);
}
if (op & HFI1_RCVCTRL_CTXT_DIS) {
write_csr(dd, RCV_VL15, 0);
+ /*
+ * When receive context is being disabled turn on tail
+ * update with a dummy tail address and then disable
+ * receive context.
+ */
+ if (dd->rcvhdrtail_dummy_physaddr) {
+ write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR,
+ dd->rcvhdrtail_dummy_physaddr);
+ rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK;
+ }
+
rcvctrl &= ~RCV_CTXT_CTRL_ENABLE_SMASK;
}
if (op & HFI1_RCVCTRL_INTRAVAIL_ENB)
@@ -7822,10 +11093,11 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt)
if (op & (HFI1_RCVCTRL_TAILUPD_DIS | HFI1_RCVCTRL_CTXT_DIS))
/*
* If the context has been disabled and the Tail Update has
- * been cleared, clear the RCV_HDR_TAIL_ADDR CSR so
- * it doesn't contain an address that is invalid.
+ * been cleared, set the RCV_HDR_TAIL_ADDR CSR to dummy address
+ * so it doesn't contain an address that is invalid.
*/
- write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR, 0);
+ write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR,
+ dd->rcvhdrtail_dummy_physaddr);
}
u32 hfi1_read_cntrs(struct hfi1_devdata *dd, loff_t pos, char **namep,
@@ -8785,7 +12057,7 @@ static void clean_up_interrupts(struct hfi1_devdata *dd)
/* turn off interrupts */
if (dd->num_msix_entries) {
/* MSI-X */
- hfi1_nomsix(dd);
+ pci_disable_msix(dd->pcidev);
} else {
/* INTx */
disable_intx(dd->pcidev);
@@ -8840,18 +12112,12 @@ static void remap_sdma_interrupts(struct hfi1_devdata *dd,
msix_intr);
}
-static void remap_receive_available_interrupt(struct hfi1_devdata *dd,
- int rx, int msix_intr)
-{
- remap_intr(dd, IS_RCVAVAIL_START + rx, msix_intr);
-}
-
static int request_intx_irq(struct hfi1_devdata *dd)
{
int ret;
- snprintf(dd->intx_name, sizeof(dd->intx_name), DRIVER_NAME"_%d",
- dd->unit);
+ snprintf(dd->intx_name, sizeof(dd->intx_name), DRIVER_NAME "_%d",
+ dd->unit);
ret = request_irq(dd->pcidev->irq, general_interrupt,
IRQF_SHARED, dd->intx_name, dd);
if (ret)
@@ -8870,7 +12136,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd)
int first_general, last_general;
int first_sdma, last_sdma;
int first_rx, last_rx;
- int first_cpu, restart_cpu, curr_cpu;
+ int first_cpu, curr_cpu;
int rcv_cpu, sdma_cpu;
int i, ret = 0, possible;
int ht;
@@ -8909,22 +12175,19 @@ static int request_msix_irqs(struct hfi1_devdata *dd)
topology_sibling_cpumask(cpumask_first(local_mask)));
for (i = possible/ht; i < possible; i++)
cpumask_clear_cpu(i, def);
- /* reset possible */
- possible = cpumask_weight(def);
/* def now has full cores on chosen node*/
first_cpu = cpumask_first(def);
if (nr_cpu_ids >= first_cpu)
first_cpu++;
- restart_cpu = first_cpu;
- curr_cpu = restart_cpu;
+ curr_cpu = first_cpu;
- for (i = first_cpu; i < dd->n_krcv_queues + first_cpu; i++) {
+ /* One context is reserved as control context */
+ for (i = first_cpu; i < dd->n_krcv_queues + first_cpu - 1; i++) {
cpumask_clear_cpu(curr_cpu, def);
cpumask_set_cpu(curr_cpu, rcv);
- if (curr_cpu >= possible)
- curr_cpu = restart_cpu;
- else
- curr_cpu++;
+ curr_cpu = cpumask_next(curr_cpu, def);
+ if (curr_cpu >= nr_cpu_ids)
+ break;
}
/* def mask has non-rcv, rcv has recv mask */
rcv_cpu = cpumask_first(rcv);
@@ -8953,7 +12216,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd)
handler = general_interrupt;
arg = dd;
snprintf(me->name, sizeof(me->name),
- DRIVER_NAME"_%d", dd->unit);
+ DRIVER_NAME "_%d", dd->unit);
err_info = "general";
} else if (first_sdma <= i && i < last_sdma) {
idx = i - first_sdma;
@@ -8961,7 +12224,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd)
handler = sdma_interrupt;
arg = sde;
snprintf(me->name, sizeof(me->name),
- DRIVER_NAME"_%d sdma%d", dd->unit, idx);
+ DRIVER_NAME "_%d sdma%d", dd->unit, idx);
err_info = "sdma";
remap_sdma_interrupts(dd, idx, i);
} else if (first_rx <= i && i < last_rx) {
@@ -8981,9 +12244,9 @@ static int request_msix_irqs(struct hfi1_devdata *dd)
thread = receive_context_thread;
arg = rcd;
snprintf(me->name, sizeof(me->name),
- DRIVER_NAME"_%d kctxt%d", dd->unit, idx);
+ DRIVER_NAME "_%d kctxt%d", dd->unit, idx);
err_info = "receive context";
- remap_receive_available_interrupt(dd, idx, i);
+ remap_intr(dd, IS_RCVAVAIL_START + idx, i);
} else {
/* not in our expected range - complain, then
ignore it */
@@ -9018,17 +12281,26 @@ static int request_msix_irqs(struct hfi1_devdata *dd)
if (handler == sdma_interrupt) {
dd_dev_info(dd, "sdma engine %d cpu %d\n",
sde->this_idx, sdma_cpu);
+ sde->cpu = sdma_cpu;
cpumask_set_cpu(sdma_cpu, dd->msix_entries[i].mask);
sdma_cpu = cpumask_next(sdma_cpu, def);
if (sdma_cpu >= nr_cpu_ids)
sdma_cpu = cpumask_first(def);
} else if (handler == receive_context_interrupt) {
- dd_dev_info(dd, "rcv ctxt %d cpu %d\n",
- rcd->ctxt, rcv_cpu);
- cpumask_set_cpu(rcv_cpu, dd->msix_entries[i].mask);
- rcv_cpu = cpumask_next(rcv_cpu, rcv);
- if (rcv_cpu >= nr_cpu_ids)
- rcv_cpu = cpumask_first(rcv);
+ dd_dev_info(dd, "rcv ctxt %d cpu %d\n", rcd->ctxt,
+ (rcd->ctxt == HFI1_CTRL_CTXT) ?
+ cpumask_first(def) : rcv_cpu);
+ if (rcd->ctxt == HFI1_CTRL_CTXT) {
+ /* map to first default */
+ cpumask_set_cpu(cpumask_first(def),
+ dd->msix_entries[i].mask);
+ } else {
+ cpumask_set_cpu(rcv_cpu,
+ dd->msix_entries[i].mask);
+ rcv_cpu = cpumask_next(rcv_cpu, rcv);
+ if (rcv_cpu >= nr_cpu_ids)
+ rcv_cpu = cpumask_first(rcv);
+ }
} else {
/* otherwise first def */
dd_dev_info(dd, "%s cpu %d\n",
@@ -9153,7 +12425,6 @@ fail:
static int set_up_context_variables(struct hfi1_devdata *dd)
{
int num_kernel_contexts;
- int num_user_contexts;
int total_contexts;
int ret;
unsigned ngroups;
@@ -9161,11 +12432,18 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
/*
* Kernel contexts: (to be fixed later):
* - min or 2 or 1 context/numa
- * - Context 0 - default/errors
- * - Context 1 - VL15
+ * - Context 0 - control context (VL15/multicast/error)
+ * - Context 1 - default context
*/
if (n_krcvqs)
- num_kernel_contexts = n_krcvqs + MIN_KERNEL_KCTXTS;
+ /*
+ * Don't count context 0 in n_krcvqs since
+ * is isn't used for normal verbs traffic.
+ *
+ * krcvqs will reflect number of kernel
+ * receive contexts above 0.
+ */
+ num_kernel_contexts = n_krcvqs + MIN_KERNEL_KCTXTS - 1;
else
num_kernel_contexts = num_online_nodes();
num_kernel_contexts =
@@ -9183,12 +12461,10 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
}
/*
* User contexts: (to be fixed later)
- * - set to num_rcv_contexts if non-zero
- * - default to 1 user context per CPU
+ * - default to 1 user context per CPU if num_user_contexts is
+ * negative
*/
- if (num_rcv_contexts)
- num_user_contexts = num_rcv_contexts;
- else
+ if (num_user_contexts < 0)
num_user_contexts = num_online_cpus();
total_contexts = num_kernel_contexts + num_user_contexts;
@@ -9455,7 +12731,7 @@ static void reset_asic_csrs(struct hfi1_devdata *dd)
/* We might want to retain this state across FLR if we ever use it */
write_csr(dd, ASIC_CFG_DRV_STR, 0);
- write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0);
+ /* ASIC_CFG_THERM_POLL_EN leave alone */
/* ASIC_STS_THERM read-only */
/* ASIC_CFG_RESET leave alone */
@@ -9906,7 +13182,7 @@ static void init_chip(struct hfi1_devdata *dd)
/* restore command and BARs */
restore_pci_variables(dd);
- if (is_a0(dd)) {
+ if (is_ax(dd)) {
dd_dev_info(dd, "Resetting CSRs with FLR\n");
hfi1_pcie_flr(dd);
restore_pci_variables(dd);
@@ -9925,23 +13201,20 @@ static void init_chip(struct hfi1_devdata *dd)
write_csr(dd, CCE_DC_CTRL, 0);
/* Set the LED off */
- if (is_a0(dd))
+ if (is_ax(dd))
setextled(dd, 0);
/*
* Clear the QSFP reset.
- * A0 leaves the out lines floating on power on, then on an FLR
- * enforces a 0 on all out pins. The driver does not touch
+ * An FLR enforces a 0 on all out pins. The driver does not touch
* ASIC_QSFPn_OUT otherwise. This leaves RESET_N low and
- * anything plugged constantly in reset, if it pays attention
+ * anything plugged constantly in reset, if it pays attention
* to RESET_N.
- * A prime example of this is SiPh. For now, set all pins high.
+ * Prime examples of this are optical cables. Set all pins high.
* I2CCLK and I2CDAT will change per direction, and INT_N and
* MODPRS_N are input only and their value is ignored.
*/
- if (is_a0(dd)) {
- write_csr(dd, ASIC_QSFP1_OUT, 0x1f);
- write_csr(dd, ASIC_QSFP2_OUT, 0x1f);
- }
+ write_csr(dd, ASIC_QSFP1_OUT, 0x1f);
+ write_csr(dd, ASIC_QSFP2_OUT, 0x1f);
}
static void init_early_variables(struct hfi1_devdata *dd)
@@ -9951,7 +13224,7 @@ static void init_early_variables(struct hfi1_devdata *dd)
/* assign link credit variables */
dd->vau = CM_VAU;
dd->link_credits = CM_GLOBAL_CREDITS;
- if (is_a0(dd))
+ if (is_ax(dd))
dd->link_credits--;
dd->vcu = cu_to_vcu(hfi1_cu);
/* enough room for 8 MAD packets plus header - 17K */
@@ -10017,12 +13290,6 @@ static void init_qpmap_table(struct hfi1_devdata *dd,
u64 ctxt = first_ctxt;
for (i = 0; i < 256;) {
- if (ctxt == VL15CTXT) {
- ctxt++;
- if (ctxt > last_ctxt)
- ctxt = first_ctxt;
- continue;
- }
reg |= ctxt << (8 * (i % 8));
i++;
ctxt++;
@@ -10065,7 +13332,7 @@ static void init_qos(struct hfi1_devdata *dd, u32 first_ctxt)
unsigned qpns_per_vl, ctxt, i, qpn, n = 1, m;
u64 *rsmmap;
u64 reg;
- u8 rxcontext = is_a0(dd) ? 0 : 0xff; /* 0 is default if a0 ver. */
+ u8 rxcontext = is_ax(dd) ? 0 : 0xff; /* 0 is default if a0 ver. */
/* validate */
if (dd->n_krcv_queues <= MIN_KERNEL_KCTXTS ||
@@ -10087,6 +13354,8 @@ static void init_qos(struct hfi1_devdata *dd, u32 first_ctxt)
if (num_vls * qpns_per_vl > dd->chip_rcv_contexts)
goto bail;
rsmmap = kmalloc_array(NUM_MAP_REGS, sizeof(u64), GFP_KERNEL);
+ if (!rsmmap)
+ goto bail;
memset(rsmmap, rxcontext, NUM_MAP_REGS * sizeof(u64));
/* init the local copy of the table */
for (i = 0, ctxt = first_ctxt; i < num_vls; i++) {
@@ -10135,19 +13404,13 @@ static void init_qos(struct hfi1_devdata *dd, u32 first_ctxt)
/* Enable RSM */
add_rcvctrl(dd, RCV_CTRL_RCV_RSM_ENABLE_SMASK);
kfree(rsmmap);
- /* map everything else (non-VL15) to context 0 */
- init_qpmap_table(
- dd,
- 0,
- 0);
+ /* map everything else to first context */
+ init_qpmap_table(dd, FIRST_KERNEL_KCTXT, MIN_KERNEL_KCTXTS - 1);
dd->qos_shift = n + 1;
return;
bail:
dd->qos_shift = 1;
- init_qpmap_table(
- dd,
- dd->n_krcv_queues > MIN_KERNEL_KCTXTS ? MIN_KERNEL_KCTXTS : 0,
- dd->n_krcv_queues - 1);
+ init_qpmap_table(dd, FIRST_KERNEL_KCTXT, dd->n_krcv_queues - 1);
}
static void init_rxe(struct hfi1_devdata *dd)
@@ -10276,7 +13539,7 @@ int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt, u16 jkey)
* Enable send-side J_KEY integrity check, unless this is A0 h/w
* (due to A0 erratum).
*/
- if (!is_a0(dd)) {
+ if (!is_ax(dd)) {
reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE);
reg |= SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg);
@@ -10309,7 +13572,7 @@ int hfi1_clear_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt)
* This check would not have been enabled for A0 h/w, see
* set_ctxt_jkey().
*/
- if (!is_a0(dd)) {
+ if (!is_ax(dd)) {
reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE);
reg &= ~SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg);
@@ -10418,6 +13681,32 @@ static void asic_should_init(struct hfi1_devdata *dd)
spin_unlock_irqrestore(&hfi1_devs_lock, flags);
}
+/*
+ * Set dd->boardname. Use a generic name if a name is not returned from
+ * EFI variable space.
+ *
+ * Return 0 on success, -ENOMEM if space could not be allocated.
+ */
+static int obtain_boardname(struct hfi1_devdata *dd)
+{
+ /* generic board description */
+ const char generic[] =
+ "Intel Omni-Path Host Fabric Interface Adapter 100 Series";
+ unsigned long size;
+ int ret;
+
+ ret = read_hfi1_efi_var(dd, "description", &size,
+ (void **)&dd->boardname);
+ if (ret) {
+ dd_dev_err(dd, "Board description not found\n");
+ /* use generic description */
+ dd->boardname = kstrdup(generic, GFP_KERNEL);
+ if (!dd->boardname)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
/**
* Allocate and initialize the device structure for the hfi.
* @dev: the pci_dev for hfi1_ib device
@@ -10554,9 +13843,9 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
/* insure num_vls isn't larger than number of sdma engines */
if (HFI1_CAP_IS_KSET(SDMA) && num_vls > dd->chip_sdma_engines) {
dd_dev_err(dd, "num_vls %u too large, using %u VLs\n",
- num_vls, HFI1_MAX_VLS_SUPPORTED);
- ppd->vls_supported = num_vls = HFI1_MAX_VLS_SUPPORTED;
- ppd->vls_operational = ppd->vls_supported;
+ num_vls, dd->chip_sdma_engines);
+ num_vls = dd->chip_sdma_engines;
+ ppd->vls_supported = dd->chip_sdma_engines;
}
/*
@@ -10615,18 +13904,13 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
parse_platform_config(dd);
- /* add board names as they are defined */
- dd->boardname = kmalloc(64, GFP_KERNEL);
- if (!dd->boardname)
+ ret = obtain_boardname(dd);
+ if (ret)
goto bail_cleanup;
- snprintf(dd->boardname, 64, "Board ID 0x%llx",
- dd->revision >> CCE_REVISION_BOARD_ID_LOWER_NIBBLE_SHIFT
- & CCE_REVISION_BOARD_ID_LOWER_NIBBLE_MASK);
snprintf(dd->boardversion, BOARD_VERS_MAX,
- "ChipABI %u.%u, %s, ChipRev %u.%u, SW Compat %llu\n",
+ "ChipABI %u.%u, ChipRev %u.%u, SW Compat %llu\n",
HFI1_CHIP_VERS_MAJ, HFI1_CHIP_VERS_MIN,
- dd->boardname,
(u32)dd->majrev,
(u32)dd->minrev,
(dd->revision >> CCE_REVISION_SW_SHIFT)
@@ -10803,7 +14087,9 @@ static int thermal_init(struct hfi1_devdata *dd)
acquire_hw_mutex(dd);
dd_dev_info(dd, "Initializing thermal sensor\n");
-
+ /* Disable polling of thermal readings */
+ write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x0);
+ msleep(100);
/* Thermal Sensor Initialization */
/* Step 1: Reset the Thermal SBus Receiver */
ret = sbus_request_slow(dd, SBUS_THERMAL, 0x0,
diff --git a/drivers/staging/rdma/hfi1/chip.h b/drivers/staging/rdma/hfi1/chip.h
index ebf9041a1c5e..5b375ddc345d 100644
--- a/drivers/staging/rdma/hfi1/chip.h
+++ b/drivers/staging/rdma/hfi1/chip.h
@@ -235,6 +235,7 @@
#define HCMD_MISC 0x05
#define HCMD_READ_LCB_IDLE_MSG 0x06
#define HCMD_READ_LCB_CSR 0x07
+#define HCMD_WRITE_LCB_CSR 0x08
#define HCMD_INTERFACE_TEST 0xff
/* DC_DC8051_CFG_HOST_CMD_1.RETURN_CODE - 8051 host command return */
@@ -663,7 +664,6 @@ void get_linkup_link_widths(struct hfi1_pportdata *ppd);
void read_ltp_rtt(struct hfi1_devdata *dd);
void clear_linkup_counters(struct hfi1_devdata *dd);
u32 hdrqempty(struct hfi1_ctxtdata *rcd);
-int is_a0(struct hfi1_devdata *dd);
int is_ax(struct hfi1_devdata *dd);
int is_bx(struct hfi1_devdata *dd);
u32 read_physical_state(struct hfi1_devdata *dd);
@@ -721,7 +721,6 @@ enum {
C_RX_TID_FULL,
C_RX_TID_INVALID,
C_RX_TID_FLGMS,
- C_RX_CTX_RHQS,
C_RX_CTX_EGRS,
C_RCV_TID_FLSMS,
C_CCE_PCI_CR_ST,
@@ -788,6 +787,275 @@ enum {
C_SW_PIO_WAIT,
C_SW_KMEM_WAIT,
C_SW_SEND_SCHED,
+/* MISC_ERR_STATUS */
+ C_MISC_PLL_LOCK_FAIL_ERR,
+ C_MISC_MBIST_FAIL_ERR,
+ C_MISC_INVALID_EEP_CMD_ERR,
+ C_MISC_EFUSE_DONE_PARITY_ERR,
+ C_MISC_EFUSE_WRITE_ERR,
+ C_MISC_EFUSE_READ_BAD_ADDR_ERR,
+ C_MISC_EFUSE_CSR_PARITY_ERR,
+ C_MISC_FW_AUTH_FAILED_ERR,
+ C_MISC_KEY_MISMATCH_ERR,
+ C_MISC_SBUS_WRITE_FAILED_ERR,
+ C_MISC_CSR_WRITE_BAD_ADDR_ERR,
+ C_MISC_CSR_READ_BAD_ADDR_ERR,
+ C_MISC_CSR_PARITY_ERR,
+/* CceErrStatus */
+ /*
+ * A special counter that is the aggregate count
+ * of all the cce_err_status errors. The remainder
+ * are actual bits in the CceErrStatus register.
+ */
+ C_CCE_ERR_STATUS_AGGREGATED_CNT,
+ C_CCE_MSIX_CSR_PARITY_ERR,
+ C_CCE_INT_MAP_UNC_ERR,
+ C_CCE_INT_MAP_COR_ERR,
+ C_CCE_MSIX_TABLE_UNC_ERR,
+ C_CCE_MSIX_TABLE_COR_ERR,
+ C_CCE_RXDMA_CONV_FIFO_PARITY_ERR,
+ C_CCE_RCPL_ASYNC_FIFO_PARITY_ERR,
+ C_CCE_SEG_WRITE_BAD_ADDR_ERR,
+ C_CCE_SEG_READ_BAD_ADDR_ERR,
+ C_LA_TRIGGERED,
+ C_CCE_TRGT_CPL_TIMEOUT_ERR,
+ C_PCIC_RECEIVE_PARITY_ERR,
+ C_PCIC_TRANSMIT_BACK_PARITY_ERR,
+ C_PCIC_TRANSMIT_FRONT_PARITY_ERR,
+ C_PCIC_CPL_DAT_Q_UNC_ERR,
+ C_PCIC_CPL_HD_Q_UNC_ERR,
+ C_PCIC_POST_DAT_Q_UNC_ERR,
+ C_PCIC_POST_HD_Q_UNC_ERR,
+ C_PCIC_RETRY_SOT_MEM_UNC_ERR,
+ C_PCIC_RETRY_MEM_UNC_ERR,
+ C_PCIC_N_POST_DAT_Q_PARITY_ERR,
+ C_PCIC_N_POST_H_Q_PARITY_ERR,
+ C_PCIC_CPL_DAT_Q_COR_ERR,
+ C_PCIC_CPL_HD_Q_COR_ERR,
+ C_PCIC_POST_DAT_Q_COR_ERR,
+ C_PCIC_POST_HD_Q_COR_ERR,
+ C_PCIC_RETRY_SOT_MEM_COR_ERR,
+ C_PCIC_RETRY_MEM_COR_ERR,
+ C_CCE_CLI1_ASYNC_FIFO_DBG_PARITY_ERR,
+ C_CCE_CLI1_ASYNC_FIFO_RXDMA_PARITY_ERR,
+ C_CCE_CLI1_ASYNC_FIFO_SDMA_HD_PARITY_ERR,
+ C_CCE_CLI1_ASYNC_FIFO_PIO_CRDT_PARITY_ERR,
+ C_CCE_CLI2_ASYNC_FIFO_PARITY_ERR,
+ C_CCE_CSR_CFG_BUS_PARITY_ERR,
+ C_CCE_CLI0_ASYNC_FIFO_PARTIY_ERR,
+ C_CCE_RSPD_DATA_PARITY_ERR,
+ C_CCE_TRGT_ACCESS_ERR,
+ C_CCE_TRGT_ASYNC_FIFO_PARITY_ERR,
+ C_CCE_CSR_WRITE_BAD_ADDR_ERR,
+ C_CCE_CSR_READ_BAD_ADDR_ERR,
+ C_CCE_CSR_PARITY_ERR,
+/* RcvErrStatus */
+ C_RX_CSR_PARITY_ERR,
+ C_RX_CSR_WRITE_BAD_ADDR_ERR,
+ C_RX_CSR_READ_BAD_ADDR_ERR,
+ C_RX_DMA_CSR_UNC_ERR,
+ C_RX_DMA_DQ_FSM_ENCODING_ERR,
+ C_RX_DMA_EQ_FSM_ENCODING_ERR,
+ C_RX_DMA_CSR_PARITY_ERR,
+ C_RX_RBUF_DATA_COR_ERR,
+ C_RX_RBUF_DATA_UNC_ERR,
+ C_RX_DMA_DATA_FIFO_RD_COR_ERR,
+ C_RX_DMA_DATA_FIFO_RD_UNC_ERR,
+ C_RX_DMA_HDR_FIFO_RD_COR_ERR,
+ C_RX_DMA_HDR_FIFO_RD_UNC_ERR,
+ C_RX_RBUF_DESC_PART2_COR_ERR,
+ C_RX_RBUF_DESC_PART2_UNC_ERR,
+ C_RX_RBUF_DESC_PART1_COR_ERR,
+ C_RX_RBUF_DESC_PART1_UNC_ERR,
+ C_RX_HQ_INTR_FSM_ERR,
+ C_RX_HQ_INTR_CSR_PARITY_ERR,
+ C_RX_LOOKUP_CSR_PARITY_ERR,
+ C_RX_LOOKUP_RCV_ARRAY_COR_ERR,
+ C_RX_LOOKUP_RCV_ARRAY_UNC_ERR,
+ C_RX_LOOKUP_DES_PART2_PARITY_ERR,
+ C_RX_LOOKUP_DES_PART1_UNC_COR_ERR,
+ C_RX_LOOKUP_DES_PART1_UNC_ERR,
+ C_RX_RBUF_NEXT_FREE_BUF_COR_ERR,
+ C_RX_RBUF_NEXT_FREE_BUF_UNC_ERR,
+ C_RX_RBUF_FL_INIT_WR_ADDR_PARITY_ERR,
+ C_RX_RBUF_FL_INITDONE_PARITY_ERR,
+ C_RX_RBUF_FL_WRITE_ADDR_PARITY_ERR,
+ C_RX_RBUF_FL_RD_ADDR_PARITY_ERR,
+ C_RX_RBUF_EMPTY_ERR,
+ C_RX_RBUF_FULL_ERR,
+ C_RX_RBUF_BAD_LOOKUP_ERR,
+ C_RX_RBUF_CTX_ID_PARITY_ERR,
+ C_RX_RBUF_CSR_QEOPDW_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_NUM_OF_PKT_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_T1_PTR_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_HD_PTR_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_VLD_BIT_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_NEXT_BUF_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_ENT_CNT_PARITY_ERR,
+ C_RX_RBUF_CSR_Q_HEAD_BUF_NUM_PARITY_ERR,
+ C_RX_RBUF_BLOCK_LIST_READ_COR_ERR,
+ C_RX_RBUF_BLOCK_LIST_READ_UNC_ERR,
+ C_RX_RBUF_LOOKUP_DES_COR_ERR,
+ C_RX_RBUF_LOOKUP_DES_UNC_ERR,
+ C_RX_RBUF_LOOKUP_DES_REG_UNC_COR_ERR,
+ C_RX_RBUF_LOOKUP_DES_REG_UNC_ERR,
+ C_RX_RBUF_FREE_LIST_COR_ERR,
+ C_RX_RBUF_FREE_LIST_UNC_ERR,
+ C_RX_RCV_FSM_ENCODING_ERR,
+ C_RX_DMA_FLAG_COR_ERR,
+ C_RX_DMA_FLAG_UNC_ERR,
+ C_RX_DC_SOP_EOP_PARITY_ERR,
+ C_RX_RCV_CSR_PARITY_ERR,
+ C_RX_RCV_QP_MAP_TABLE_COR_ERR,
+ C_RX_RCV_QP_MAP_TABLE_UNC_ERR,
+ C_RX_RCV_DATA_COR_ERR,
+ C_RX_RCV_DATA_UNC_ERR,
+ C_RX_RCV_HDR_COR_ERR,
+ C_RX_RCV_HDR_UNC_ERR,
+ C_RX_DC_INTF_PARITY_ERR,
+ C_RX_DMA_CSR_COR_ERR,
+/* SendPioErrStatus */
+ C_PIO_PEC_SOP_HEAD_PARITY_ERR,
+ C_PIO_PCC_SOP_HEAD_PARITY_ERR,
+ C_PIO_LAST_RETURNED_CNT_PARITY_ERR,
+ C_PIO_CURRENT_FREE_CNT_PARITY_ERR,
+ C_PIO_RSVD_31_ERR,
+ C_PIO_RSVD_30_ERR,
+ C_PIO_PPMC_SOP_LEN_ERR,
+ C_PIO_PPMC_BQC_MEM_PARITY_ERR,
+ C_PIO_VL_FIFO_PARITY_ERR,
+ C_PIO_VLF_SOP_PARITY_ERR,
+ C_PIO_VLF_V1_LEN_PARITY_ERR,
+ C_PIO_BLOCK_QW_COUNT_PARITY_ERR,
+ C_PIO_WRITE_QW_VALID_PARITY_ERR,
+ C_PIO_STATE_MACHINE_ERR,
+ C_PIO_WRITE_DATA_PARITY_ERR,
+ C_PIO_HOST_ADDR_MEM_COR_ERR,
+ C_PIO_HOST_ADDR_MEM_UNC_ERR,
+ C_PIO_PKT_EVICT_SM_OR_ARM_SM_ERR,
+ C_PIO_INIT_SM_IN_ERR,
+ C_PIO_PPMC_PBL_FIFO_ERR,
+ C_PIO_CREDIT_RET_FIFO_PARITY_ERR,
+ C_PIO_V1_LEN_MEM_BANK1_COR_ERR,
+ C_PIO_V1_LEN_MEM_BANK0_COR_ERR,
+ C_PIO_V1_LEN_MEM_BANK1_UNC_ERR,
+ C_PIO_V1_LEN_MEM_BANK0_UNC_ERR,
+ C_PIO_SM_PKT_RESET_PARITY_ERR,
+ C_PIO_PKT_EVICT_FIFO_PARITY_ERR,
+ C_PIO_SBRDCTRL_CRREL_FIFO_PARITY_ERR,
+ C_PIO_SBRDCTL_CRREL_PARITY_ERR,
+ C_PIO_PEC_FIFO_PARITY_ERR,
+ C_PIO_PCC_FIFO_PARITY_ERR,
+ C_PIO_SB_MEM_FIFO1_ERR,
+ C_PIO_SB_MEM_FIFO0_ERR,
+ C_PIO_CSR_PARITY_ERR,
+ C_PIO_WRITE_ADDR_PARITY_ERR,
+ C_PIO_WRITE_BAD_CTXT_ERR,
+/* SendDmaErrStatus */
+ C_SDMA_PCIE_REQ_TRACKING_COR_ERR,
+ C_SDMA_PCIE_REQ_TRACKING_UNC_ERR,
+ C_SDMA_CSR_PARITY_ERR,
+ C_SDMA_RPY_TAG_ERR,
+/* SendEgressErrStatus */
+ C_TX_READ_PIO_MEMORY_CSR_UNC_ERR,
+ C_TX_READ_SDMA_MEMORY_CSR_UNC_ERR,
+ C_TX_EGRESS_FIFO_COR_ERR,
+ C_TX_READ_PIO_MEMORY_COR_ERR,
+ C_TX_READ_SDMA_MEMORY_COR_ERR,
+ C_TX_SB_HDR_COR_ERR,
+ C_TX_CREDIT_OVERRUN_ERR,
+ C_TX_LAUNCH_FIFO8_COR_ERR,
+ C_TX_LAUNCH_FIFO7_COR_ERR,
+ C_TX_LAUNCH_FIFO6_COR_ERR,
+ C_TX_LAUNCH_FIFO5_COR_ERR,
+ C_TX_LAUNCH_FIFO4_COR_ERR,
+ C_TX_LAUNCH_FIFO3_COR_ERR,
+ C_TX_LAUNCH_FIFO2_COR_ERR,
+ C_TX_LAUNCH_FIFO1_COR_ERR,
+ C_TX_LAUNCH_FIFO0_COR_ERR,
+ C_TX_CREDIT_RETURN_VL_ERR,
+ C_TX_HCRC_INSERTION_ERR,
+ C_TX_EGRESS_FIFI_UNC_ERR,
+ C_TX_READ_PIO_MEMORY_UNC_ERR,
+ C_TX_READ_SDMA_MEMORY_UNC_ERR,
+ C_TX_SB_HDR_UNC_ERR,
+ C_TX_CREDIT_RETURN_PARITY_ERR,
+ C_TX_LAUNCH_FIFO8_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO7_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO6_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO5_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO4_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO3_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO2_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO1_UNC_OR_PARITY_ERR,
+ C_TX_LAUNCH_FIFO0_UNC_OR_PARITY_ERR,
+ C_TX_SDMA15_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA14_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA13_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA12_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA11_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA10_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA9_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA8_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA7_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA6_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA5_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA4_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA3_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA2_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA1_DISALLOWED_PACKET_ERR,
+ C_TX_SDMA0_DISALLOWED_PACKET_ERR,
+ C_TX_CONFIG_PARITY_ERR,
+ C_TX_SBRD_CTL_CSR_PARITY_ERR,
+ C_TX_LAUNCH_CSR_PARITY_ERR,
+ C_TX_ILLEGAL_CL_ERR,
+ C_TX_SBRD_CTL_STATE_MACHINE_PARITY_ERR,
+ C_TX_RESERVED_10,
+ C_TX_RESERVED_9,
+ C_TX_SDMA_LAUNCH_INTF_PARITY_ERR,
+ C_TX_PIO_LAUNCH_INTF_PARITY_ERR,
+ C_TX_RESERVED_6,
+ C_TX_INCORRECT_LINK_STATE_ERR,
+ C_TX_LINK_DOWN_ERR,
+ C_TX_EGRESS_FIFO_UNDERRUN_OR_PARITY_ERR,
+ C_TX_RESERVED_2,
+ C_TX_PKT_INTEGRITY_MEM_UNC_ERR,
+ C_TX_PKT_INTEGRITY_MEM_COR_ERR,
+/* SendErrStatus */
+ C_SEND_CSR_WRITE_BAD_ADDR_ERR,
+ C_SEND_CSR_READ_BAD_ADD_ERR,
+ C_SEND_CSR_PARITY_ERR,
+/* SendCtxtErrStatus */
+ C_PIO_WRITE_OUT_OF_BOUNDS_ERR,
+ C_PIO_WRITE_OVERFLOW_ERR,
+ C_PIO_WRITE_CROSSES_BOUNDARY_ERR,
+ C_PIO_DISALLOWED_PACKET_ERR,
+ C_PIO_INCONSISTENT_SOP_ERR,
+/*SendDmaEngErrStatus */
+ C_SDMA_HEADER_REQUEST_FIFO_COR_ERR,
+ C_SDMA_HEADER_STORAGE_COR_ERR,
+ C_SDMA_PACKET_TRACKING_COR_ERR,
+ C_SDMA_ASSEMBLY_COR_ERR,
+ C_SDMA_DESC_TABLE_COR_ERR,
+ C_SDMA_HEADER_REQUEST_FIFO_UNC_ERR,
+ C_SDMA_HEADER_STORAGE_UNC_ERR,
+ C_SDMA_PACKET_TRACKING_UNC_ERR,
+ C_SDMA_ASSEMBLY_UNC_ERR,
+ C_SDMA_DESC_TABLE_UNC_ERR,
+ C_SDMA_TIMEOUT_ERR,
+ C_SDMA_HEADER_LENGTH_ERR,
+ C_SDMA_HEADER_ADDRESS_ERR,
+ C_SDMA_HEADER_SELECT_ERR,
+ C_SMDA_RESERVED_9,
+ C_SDMA_PACKET_DESC_OVERFLOW_ERR,
+ C_SDMA_LENGTH_MISMATCH_ERR,
+ C_SDMA_HALT_ERR,
+ C_SDMA_MEM_READ_ERR,
+ C_SDMA_FIRST_DESC_ERR,
+ C_SDMA_TAIL_OUT_OF_BOUNDS_ERR,
+ C_SDMA_TOO_LONG_ERR,
+ C_SDMA_GEN_MISMATCH_ERR,
+ C_SDMA_WRONG_DW_ERR,
DEV_CNTR_LAST /* Must be kept last */
};
@@ -810,6 +1078,7 @@ enum {
C_RX_WORDS,
C_SW_LINK_DOWN,
C_SW_LINK_UP,
+ C_SW_UNKNOWN_FRAME,
C_SW_XMIT_DSCD,
C_SW_XMIT_DSCD_VL,
C_SW_XMIT_CSTR_ERR,
diff --git a/drivers/staging/rdma/hfi1/chip_registers.h b/drivers/staging/rdma/hfi1/chip_registers.h
index bf45de29d8bd..701e9e1012a6 100644
--- a/drivers/staging/rdma/hfi1/chip_registers.h
+++ b/drivers/staging/rdma/hfi1/chip_registers.h
@@ -318,6 +318,9 @@
#define DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT 0
#define DC_LCB_CFG_TX_FIFOS_RESET (DC_LCB_CSRS + 0x000000000008)
#define DC_LCB_CFG_TX_FIFOS_RESET_VAL_SHIFT 0
+#define DC_LCB_CFG_REINIT_AS_SLAVE (DC_LCB_CSRS + 0x000000000030)
+#define DC_LCB_CFG_CNT_FOR_SKIP_STALL (DC_LCB_CSRS + 0x000000000040)
+#define DC_LCB_CFG_CLK_CNTR (DC_LCB_CSRS + 0x000000000110)
#define DC_LCB_ERR_CLR (DC_LCB_CSRS + 0x000000000308)
#define DC_LCB_ERR_EN (DC_LCB_CSRS + 0x000000000310)
#define DC_LCB_ERR_FLG (DC_LCB_CSRS + 0x000000000300)
@@ -379,7 +382,6 @@
#define DC_LCB_STS_ROUND_TRIP_LTP_CNT (DC_LCB_CSRS + 0x0000000004B0)
#define RCV_BUF_OVFL_CNT 10
#define RCV_CONTEXT_EGR_STALL 22
-#define RCV_CONTEXT_RHQ_STALL 21
#define RCV_DATA_PKT_CNT 0
#define RCV_DWORD_CNT 1
#define RCV_TID_FLOW_GEN_MISMATCH_CNT 20
diff --git a/drivers/staging/rdma/hfi1/common.h b/drivers/staging/rdma/hfi1/common.h
index 5e203239c5b0..5dd92720faae 100644
--- a/drivers/staging/rdma/hfi1/common.h
+++ b/drivers/staging/rdma/hfi1/common.h
@@ -132,13 +132,14 @@
* HFI1_CAP_RESERVED_MASK bits.
*/
#define HFI1_CAP_WRITABLE_MASK (HFI1_CAP_SDMA_AHG | \
- HFI1_CAP_HDRSUPP | \
- HFI1_CAP_MULTI_PKT_EGR | \
- HFI1_CAP_NODROP_RHQ_FULL | \
- HFI1_CAP_NODROP_EGR_FULL | \
- HFI1_CAP_ALLOW_PERM_JKEY | \
- HFI1_CAP_STATIC_RATE_CTRL | \
- HFI1_CAP_PRINT_UNIMPL)
+ HFI1_CAP_HDRSUPP | \
+ HFI1_CAP_MULTI_PKT_EGR | \
+ HFI1_CAP_NODROP_RHQ_FULL | \
+ HFI1_CAP_NODROP_EGR_FULL | \
+ HFI1_CAP_ALLOW_PERM_JKEY | \
+ HFI1_CAP_STATIC_RATE_CTRL | \
+ HFI1_CAP_PRINT_UNIMPL | \
+ HFI1_CAP_TID_UNMAP)
/*
* A set of capability bits that are "global" and are not allowed to be
* set in the user bitmask.
diff --git a/drivers/staging/rdma/hfi1/diag.c b/drivers/staging/rdma/hfi1/diag.c
index 88414d720469..0c8831705664 100644
--- a/drivers/staging/rdma/hfi1/diag.c
+++ b/drivers/staging/rdma/hfi1/diag.c
@@ -78,8 +78,8 @@
hfi1_cdbg(SNOOP, fmt, ##__VA_ARGS__)
/* Snoop option mask */
-#define SNOOP_DROP_SEND (1 << 0)
-#define SNOOP_USE_METADATA (1 << 1)
+#define SNOOP_DROP_SEND BIT(0)
+#define SNOOP_USE_METADATA BIT(1)
static u8 snoop_flags;
@@ -135,7 +135,7 @@ static struct cdev diagpkt_cdev;
static struct device *diagpkt_device;
static ssize_t diagpkt_write(struct file *fp, const char __user *data,
- size_t count, loff_t *off);
+ size_t count, loff_t *off);
static const struct file_operations diagpkt_file_ops = {
.owner = THIS_MODULE,
@@ -177,37 +177,37 @@ struct hfi1_link_info {
#define HFI1_SNOOP_IOCGETLINKSTATE \
_IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ)
#define HFI1_SNOOP_IOCSETLINKSTATE \
- _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+1)
+ _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 1)
#define HFI1_SNOOP_IOCCLEARQUEUE \
- _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+2)
+ _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 2)
#define HFI1_SNOOP_IOCCLEARFILTER \
- _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+3)
+ _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 3)
#define HFI1_SNOOP_IOCSETFILTER \
- _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+4)
+ _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 4)
#define HFI1_SNOOP_IOCGETVERSION \
- _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+5)
+ _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 5)
#define HFI1_SNOOP_IOCSET_OPTS \
- _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+6)
+ _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 6)
/*
* These offsets +6/+7 could change, but these are already known and used
* IOCTL numbers so don't change them without a good reason.
*/
#define HFI1_SNOOP_IOCGETLINKSTATE_EXTRA \
- _IOWR(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+6, \
+ _IOWR(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 6, \
struct hfi1_link_info)
#define HFI1_SNOOP_IOCSETLINKSTATE_EXTRA \
- _IOWR(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+7, \
+ _IOWR(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ + 7, \
struct hfi1_link_info)
static int hfi1_snoop_open(struct inode *in, struct file *fp);
static ssize_t hfi1_snoop_read(struct file *fp, char __user *data,
- size_t pkt_len, loff_t *off);
+ size_t pkt_len, loff_t *off);
static ssize_t hfi1_snoop_write(struct file *fp, const char __user *data,
- size_t count, loff_t *off);
+ size_t count, loff_t *off);
static long hfi1_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
static unsigned int hfi1_snoop_poll(struct file *fp,
- struct poll_table_struct *wait);
+ struct poll_table_struct *wait);
static int hfi1_snoop_release(struct inode *in, struct file *fp);
struct hfi1_packet_filter_command {
@@ -323,14 +323,12 @@ static void hfi1_snoop_remove(struct hfi1_devdata *dd)
void hfi1_diag_remove(struct hfi1_devdata *dd)
{
-
hfi1_snoop_remove(dd);
if (atomic_dec_and_test(&diagpkt_count))
hfi1_cdev_cleanup(&diagpkt_cdev, &diagpkt_device);
hfi1_cdev_cleanup(&dd->diag_cdev, &dd->diag_device);
}
-
/*
* Allocated structure shared between the credit return mechanism and
* diagpkt_send().
@@ -379,6 +377,7 @@ static ssize_t diagpkt_send(struct diag_pkt *dp)
pio_release_cb credit_cb = NULL;
void *credit_arg = NULL;
struct diagpkt_wait *wait = NULL;
+ int trycount = 0;
dd = hfi1_lookup(dp->unit);
if (!dd || !(dd->flags & HFI1_PRESENT) || !dd->kregbase) {
@@ -393,7 +392,7 @@ static ssize_t diagpkt_send(struct diag_pkt *dp)
if (dp->version != _DIAG_PKT_VERS) {
dd_dev_err(dd, "Invalid version %u for diagpkt_write\n",
- dp->version);
+ dp->version);
ret = -EINVAL;
goto bail;
}
@@ -440,7 +439,7 @@ static ssize_t diagpkt_send(struct diag_pkt *dp)
}
if (copy_from_user(tmpbuf,
- (const void __user *) (unsigned long) dp->data,
+ (const void __user *)(unsigned long)dp->data,
dp->len)) {
ret = -EFAULT;
goto bail;
@@ -493,8 +492,15 @@ static ssize_t diagpkt_send(struct diag_pkt *dp)
credit_arg = wait;
}
+retry:
pbuf = sc_buffer_alloc(sc, total_len, credit_cb, credit_arg);
if (!pbuf) {
+ if (trycount == 0) {
+ /* force a credit return and try again */
+ sc_return_credits(sc);
+ trycount = 1;
+ goto retry;
+ }
/*
* No send buffer means no credit callback. Undo
* the wait set-up that was done above. We free wait
@@ -530,9 +536,9 @@ static ssize_t diagpkt_send(struct diag_pkt *dp)
* NOTE: PRC_FILL_ERR is at best informational and cannot
* be depended on.
*/
- if (!ret && (((wait->code & PRC_STATUS_ERR)
- || (wait->code & PRC_FILL_ERR)
- || (wait->code & PRC_SC_DISABLE))))
+ if (!ret && (((wait->code & PRC_STATUS_ERR) ||
+ (wait->code & PRC_FILL_ERR) ||
+ (wait->code & PRC_SC_DISABLE))))
ret = -EIO;
put_diagpkt_wait(wait); /* finished with the structure */
@@ -545,7 +551,7 @@ bail:
}
static ssize_t diagpkt_write(struct file *fp, const char __user *data,
- size_t count, loff_t *off)
+ size_t count, loff_t *off)
{
struct hfi1_devdata *dd;
struct send_context *sc;
@@ -565,7 +571,7 @@ static ssize_t diagpkt_write(struct file *fp, const char __user *data,
*/
if (dp.pbc) {
dd = hfi1_lookup(dp.unit);
- if (dd == NULL)
+ if (!dd)
return -ENODEV;
vl = (dp.pbc >> PBC_VL_SHIFT) & PBC_VL_MASK;
sc = dd->vld[vl].sc;
@@ -598,7 +604,7 @@ static int hfi1_snoop_add(struct hfi1_devdata *dd, const char *name)
if (ret) {
dd_dev_err(dd, "Couldn't create %s device: %d", name, ret);
hfi1_cdev_cleanup(&dd->hfi1_snoop.cdev,
- &dd->hfi1_snoop.class_dev);
+ &dd->hfi1_snoop.class_dev);
}
return ret;
@@ -611,7 +617,6 @@ static struct hfi1_devdata *hfi1_dd_from_sc_inode(struct inode *in)
dd = hfi1_lookup(unit);
return dd;
-
}
/* clear or restore send context integrity checks */
@@ -652,7 +657,7 @@ static int hfi1_snoop_open(struct inode *in, struct file *fp)
mutex_lock(&hfi1_mutex);
dd = hfi1_dd_from_sc_inode(in);
- if (dd == NULL) {
+ if (!dd) {
ret = -ENODEV;
goto bail;
}
@@ -739,7 +744,7 @@ static int hfi1_snoop_release(struct inode *in, struct file *fp)
int mode_flag;
dd = hfi1_dd_from_sc_inode(in);
- if (dd == NULL)
+ if (!dd)
return -ENODEV;
spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
@@ -794,7 +799,7 @@ static unsigned int hfi1_snoop_poll(struct file *fp,
struct hfi1_devdata *dd;
dd = hfi1_dd_from_sc_inode(fp->f_inode);
- if (dd == NULL)
+ if (!dd)
return -ENODEV;
spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
@@ -805,7 +810,6 @@ static unsigned int hfi1_snoop_poll(struct file *fp,
spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
return ret;
-
}
static ssize_t hfi1_snoop_write(struct file *fp, const char __user *data,
@@ -822,7 +826,7 @@ static ssize_t hfi1_snoop_write(struct file *fp, const char __user *data,
struct hfi1_pportdata *ppd;
dd = hfi1_dd_from_sc_inode(fp->f_inode);
- if (dd == NULL)
+ if (!dd)
return -ENODEV;
ppd = dd->pport;
@@ -847,7 +851,7 @@ static ssize_t hfi1_snoop_write(struct file *fp, const char __user *data,
if (copy_from_user(&byte_one, data, 1))
return -EINVAL;
- if (copy_from_user(&byte_two, data+1, 1))
+ if (copy_from_user(&byte_two, data + 1, 1))
return -EINVAL;
sc4 = (byte_one >> 4) & 0xf;
@@ -920,7 +924,7 @@ static ssize_t hfi1_snoop_read(struct file *fp, char __user *data,
struct hfi1_devdata *dd;
dd = hfi1_dd_from_sc_inode(fp->f_inode);
- if (dd == NULL)
+ if (!dd)
return -ENODEV;
spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
@@ -946,16 +950,18 @@ static ssize_t hfi1_snoop_read(struct file *fp, char __user *data,
spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
if (pkt_len >= packet->total_len) {
if (copy_to_user(data, packet->data,
- packet->total_len))
+ packet->total_len))
ret = -EFAULT;
else
ret = packet->total_len;
- } else
+ } else {
ret = -EINVAL;
+ }
kfree(packet);
- } else
+ } else {
spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
+ }
return ret;
}
@@ -966,9 +972,9 @@ static long hfi1_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
void *filter_value = NULL;
long ret = 0;
int value = 0;
- u8 physState = 0;
- u8 linkState = 0;
- u16 devState = 0;
+ u8 phys_state = 0;
+ u8 link_state = 0;
+ u16 dev_state = 0;
unsigned long flags = 0;
unsigned long *argp = NULL;
struct hfi1_packet_filter_command filter_cmd = {0};
@@ -976,237 +982,221 @@ static long hfi1_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
struct hfi1_pportdata *ppd = NULL;
unsigned int index;
struct hfi1_link_info link_info;
+ int read_cmd, write_cmd, read_ok, write_ok;
dd = hfi1_dd_from_sc_inode(fp->f_inode);
- if (dd == NULL)
+ if (!dd)
return -ENODEV;
- spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
-
mode_flag = dd->hfi1_snoop.mode_flag;
+ read_cmd = _IOC_DIR(cmd) & _IOC_READ;
+ write_cmd = _IOC_DIR(cmd) & _IOC_WRITE;
+ write_ok = access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
+ read_ok = access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
- if (((_IOC_DIR(cmd) & _IOC_READ)
- && !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)))
- || ((_IOC_DIR(cmd) & _IOC_WRITE)
- && !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)))) {
- ret = -EFAULT;
- } else if (!capable(CAP_SYS_ADMIN)) {
- ret = -EPERM;
- } else if ((mode_flag & HFI1_PORT_CAPTURE_MODE) &&
- (cmd != HFI1_SNOOP_IOCCLEARQUEUE) &&
- (cmd != HFI1_SNOOP_IOCCLEARFILTER) &&
- (cmd != HFI1_SNOOP_IOCSETFILTER)) {
+ if ((read_cmd && !write_ok) || (write_cmd && !read_ok))
+ return -EFAULT;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if ((mode_flag & HFI1_PORT_CAPTURE_MODE) &&
+ (cmd != HFI1_SNOOP_IOCCLEARQUEUE) &&
+ (cmd != HFI1_SNOOP_IOCCLEARFILTER) &&
+ (cmd != HFI1_SNOOP_IOCSETFILTER))
/* Capture devices are allowed only 3 operations
* 1.Clear capture queue
* 2.Clear capture filter
* 3.Set capture filter
* Other are invalid.
*/
- ret = -EINVAL;
- } else {
- switch (cmd) {
- case HFI1_SNOOP_IOCSETLINKSTATE:
- snoop_dbg("HFI1_SNOOP_IOCSETLINKSTATE is not valid");
- ret = -EINVAL;
- break;
+ return -EINVAL;
- case HFI1_SNOOP_IOCSETLINKSTATE_EXTRA:
- memset(&link_info, 0, sizeof(link_info));
+ switch (cmd) {
+ case HFI1_SNOOP_IOCSETLINKSTATE_EXTRA:
+ memset(&link_info, 0, sizeof(link_info));
- if (copy_from_user(&link_info,
- (struct hfi1_link_info __user *)arg,
- sizeof(link_info)))
- ret = -EFAULT;
+ if (copy_from_user(&link_info,
+ (struct hfi1_link_info __user *)arg,
+ sizeof(link_info)))
+ return -EFAULT;
- value = link_info.port_state;
- index = link_info.port_number;
- if (index > dd->num_pports - 1) {
- ret = -EINVAL;
- break;
- }
+ value = link_info.port_state;
+ index = link_info.port_number;
+ if (index > dd->num_pports - 1)
+ return -EINVAL;
- ppd = &dd->pport[index];
- if (!ppd) {
- ret = -EINVAL;
- break;
- }
+ ppd = &dd->pport[index];
+ if (!ppd)
+ return -EINVAL;
- /* What we want to transition to */
- physState = (value >> 4) & 0xF;
- linkState = value & 0xF;
- snoop_dbg("Setting link state 0x%x", value);
-
- switch (linkState) {
- case IB_PORT_NOP:
- if (physState == 0)
- break;
- /* fall through */
- case IB_PORT_DOWN:
- switch (physState) {
- case 0:
- devState = HLS_DN_DOWNDEF;
- break;
- case 2:
- devState = HLS_DN_POLL;
- break;
- case 3:
- devState = HLS_DN_DISABLE;
- break;
- default:
- ret = -EINVAL;
- goto done;
- }
- ret = set_link_state(ppd, devState);
- break;
- case IB_PORT_ARMED:
- ret = set_link_state(ppd, HLS_UP_ARMED);
- if (!ret)
- send_idle_sma(dd, SMA_IDLE_ARM);
- break;
- case IB_PORT_ACTIVE:
- ret = set_link_state(ppd, HLS_UP_ACTIVE);
- if (!ret)
- send_idle_sma(dd, SMA_IDLE_ACTIVE);
- break;
- default:
- ret = -EINVAL;
- break;
- }
+ /* What we want to transition to */
+ phys_state = (value >> 4) & 0xF;
+ link_state = value & 0xF;
+ snoop_dbg("Setting link state 0x%x", value);
- if (ret)
+ switch (link_state) {
+ case IB_PORT_NOP:
+ if (phys_state == 0)
break;
- /* fall through */
- case HFI1_SNOOP_IOCGETLINKSTATE:
- case HFI1_SNOOP_IOCGETLINKSTATE_EXTRA:
- if (cmd == HFI1_SNOOP_IOCGETLINKSTATE_EXTRA) {
- memset(&link_info, 0, sizeof(link_info));
- if (copy_from_user(&link_info,
- (struct hfi1_link_info __user *)arg,
- sizeof(link_info)))
- ret = -EFAULT;
- index = link_info.port_number;
- } else {
- ret = __get_user(index, (int __user *) arg);
- if (ret != 0)
- break;
- }
-
- if (index > dd->num_pports - 1) {
- ret = -EINVAL;
+ /* fall through */
+ case IB_PORT_DOWN:
+ switch (phys_state) {
+ case 0:
+ dev_state = HLS_DN_DOWNDEF;
break;
- }
-
- ppd = &dd->pport[index];
- if (!ppd) {
- ret = -EINVAL;
+ case 2:
+ dev_state = HLS_DN_POLL;
break;
+ case 3:
+ dev_state = HLS_DN_DISABLE;
+ break;
+ default:
+ return -EINVAL;
}
- value = hfi1_ibphys_portstate(ppd);
- value <<= 4;
- value |= driver_lstate(ppd);
-
- snoop_dbg("Link port | Link State: %d", value);
-
- if ((cmd == HFI1_SNOOP_IOCGETLINKSTATE_EXTRA) ||
- (cmd == HFI1_SNOOP_IOCSETLINKSTATE_EXTRA)) {
- link_info.port_state = value;
- link_info.node_guid = cpu_to_be64(ppd->guid);
- link_info.link_speed_active =
- ppd->link_speed_active;
- link_info.link_width_active =
- ppd->link_width_active;
- if (copy_to_user(
- (struct hfi1_link_info __user *)arg,
- &link_info, sizeof(link_info)))
- ret = -EFAULT;
- } else {
- ret = __put_user(value, (int __user *)arg);
- }
+ ret = set_link_state(ppd, dev_state);
break;
-
- case HFI1_SNOOP_IOCCLEARQUEUE:
- snoop_dbg("Clearing snoop queue");
- drain_snoop_list(&dd->hfi1_snoop.queue);
+ case IB_PORT_ARMED:
+ ret = set_link_state(ppd, HLS_UP_ARMED);
+ if (!ret)
+ send_idle_sma(dd, SMA_IDLE_ARM);
break;
-
- case HFI1_SNOOP_IOCCLEARFILTER:
- snoop_dbg("Clearing filter");
- if (dd->hfi1_snoop.filter_callback) {
- /* Drain packets first */
- drain_snoop_list(&dd->hfi1_snoop.queue);
- dd->hfi1_snoop.filter_callback = NULL;
- }
- kfree(dd->hfi1_snoop.filter_value);
- dd->hfi1_snoop.filter_value = NULL;
+ case IB_PORT_ACTIVE:
+ ret = set_link_state(ppd, HLS_UP_ACTIVE);
+ if (!ret)
+ send_idle_sma(dd, SMA_IDLE_ACTIVE);
break;
+ default:
+ return -EINVAL;
+ }
- case HFI1_SNOOP_IOCSETFILTER:
- snoop_dbg("Setting filter");
- /* just copy command structure */
- argp = (unsigned long *)arg;
- if (copy_from_user(&filter_cmd, (void __user *)argp,
- sizeof(filter_cmd))) {
- ret = -EFAULT;
- break;
- }
- if (filter_cmd.opcode >= HFI1_MAX_FILTERS) {
- pr_alert("Invalid opcode in request\n");
- ret = -EINVAL;
+ if (ret)
+ break;
+ /* fall through */
+ case HFI1_SNOOP_IOCGETLINKSTATE:
+ case HFI1_SNOOP_IOCGETLINKSTATE_EXTRA:
+ if (cmd == HFI1_SNOOP_IOCGETLINKSTATE_EXTRA) {
+ memset(&link_info, 0, sizeof(link_info));
+ if (copy_from_user(&link_info,
+ (struct hfi1_link_info __user *)arg,
+ sizeof(link_info)))
+ return -EFAULT;
+ index = link_info.port_number;
+ } else {
+ ret = __get_user(index, (int __user *)arg);
+ if (ret != 0)
break;
- }
+ }
- snoop_dbg("Opcode %d Len %d Ptr %p",
- filter_cmd.opcode, filter_cmd.length,
- filter_cmd.value_ptr);
+ if (index > dd->num_pports - 1)
+ return -EINVAL;
- filter_value = kcalloc(filter_cmd.length, sizeof(u8),
- GFP_KERNEL);
- if (!filter_value) {
- pr_alert("Not enough memory\n");
- ret = -ENOMEM;
- break;
- }
- /* copy remaining data from userspace */
- if (copy_from_user((u8 *)filter_value,
- (void __user *)filter_cmd.value_ptr,
- filter_cmd.length)) {
- kfree(filter_value);
- ret = -EFAULT;
- break;
- }
+ ppd = &dd->pport[index];
+ if (!ppd)
+ return -EINVAL;
+
+ value = hfi1_ibphys_portstate(ppd);
+ value <<= 4;
+ value |= driver_lstate(ppd);
+
+ snoop_dbg("Link port | Link State: %d", value);
+
+ if ((cmd == HFI1_SNOOP_IOCGETLINKSTATE_EXTRA) ||
+ (cmd == HFI1_SNOOP_IOCSETLINKSTATE_EXTRA)) {
+ link_info.port_state = value;
+ link_info.node_guid = cpu_to_be64(ppd->guid);
+ link_info.link_speed_active =
+ ppd->link_speed_active;
+ link_info.link_width_active =
+ ppd->link_width_active;
+ if (copy_to_user((struct hfi1_link_info __user *)arg,
+ &link_info, sizeof(link_info)))
+ return -EFAULT;
+ } else {
+ ret = __put_user(value, (int __user *)arg);
+ }
+ break;
+
+ case HFI1_SNOOP_IOCCLEARQUEUE:
+ snoop_dbg("Clearing snoop queue");
+ spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
+ drain_snoop_list(&dd->hfi1_snoop.queue);
+ spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
+ break;
+
+ case HFI1_SNOOP_IOCCLEARFILTER:
+ snoop_dbg("Clearing filter");
+ spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
+ if (dd->hfi1_snoop.filter_callback) {
/* Drain packets first */
drain_snoop_list(&dd->hfi1_snoop.queue);
- dd->hfi1_snoop.filter_callback =
- hfi1_filters[filter_cmd.opcode].filter;
- /* just in case we see back to back sets */
- kfree(dd->hfi1_snoop.filter_value);
- dd->hfi1_snoop.filter_value = filter_value;
+ dd->hfi1_snoop.filter_callback = NULL;
+ }
+ kfree(dd->hfi1_snoop.filter_value);
+ dd->hfi1_snoop.filter_value = NULL;
+ spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
+ break;
- break;
- case HFI1_SNOOP_IOCGETVERSION:
- value = SNOOP_CAPTURE_VERSION;
- snoop_dbg("Getting version: %d", value);
- ret = __put_user(value, (int __user *)arg);
- break;
- case HFI1_SNOOP_IOCSET_OPTS:
- snoop_flags = 0;
- ret = __get_user(value, (int __user *) arg);
- if (ret != 0)
- break;
+ case HFI1_SNOOP_IOCSETFILTER:
+ snoop_dbg("Setting filter");
+ /* just copy command structure */
+ argp = (unsigned long *)arg;
+ if (copy_from_user(&filter_cmd, (void __user *)argp,
+ sizeof(filter_cmd)))
+ return -EFAULT;
- snoop_dbg("Setting snoop option %d", value);
- if (value & SNOOP_DROP_SEND)
- snoop_flags |= SNOOP_DROP_SEND;
- if (value & SNOOP_USE_METADATA)
- snoop_flags |= SNOOP_USE_METADATA;
- break;
- default:
- ret = -ENOTTY;
- break;
+ if (filter_cmd.opcode >= HFI1_MAX_FILTERS) {
+ pr_alert("Invalid opcode in request\n");
+ return -EINVAL;
+ }
+
+ snoop_dbg("Opcode %d Len %d Ptr %p",
+ filter_cmd.opcode, filter_cmd.length,
+ filter_cmd.value_ptr);
+
+ filter_value = kcalloc(filter_cmd.length, sizeof(u8),
+ GFP_KERNEL);
+ if (!filter_value)
+ return -ENOMEM;
+
+ /* copy remaining data from userspace */
+ if (copy_from_user((u8 *)filter_value,
+ (void __user *)filter_cmd.value_ptr,
+ filter_cmd.length)) {
+ kfree(filter_value);
+ return -EFAULT;
}
+ /* Drain packets first */
+ spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags);
+ drain_snoop_list(&dd->hfi1_snoop.queue);
+ dd->hfi1_snoop.filter_callback =
+ hfi1_filters[filter_cmd.opcode].filter;
+ /* just in case we see back to back sets */
+ kfree(dd->hfi1_snoop.filter_value);
+ dd->hfi1_snoop.filter_value = filter_value;
+ spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
+ break;
+ case HFI1_SNOOP_IOCGETVERSION:
+ value = SNOOP_CAPTURE_VERSION;
+ snoop_dbg("Getting version: %d", value);
+ ret = __put_user(value, (int __user *)arg);
+ break;
+ case HFI1_SNOOP_IOCSET_OPTS:
+ snoop_flags = 0;
+ ret = __get_user(value, (int __user *)arg);
+ if (ret != 0)
+ break;
+
+ snoop_dbg("Setting snoop option %d", value);
+ if (value & SNOOP_DROP_SEND)
+ snoop_flags |= SNOOP_DROP_SEND;
+ if (value & SNOOP_USE_METADATA)
+ snoop_flags |= SNOOP_USE_METADATA;
+ break;
+ default:
+ return -ENOTTY;
}
-done:
- spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags);
+
return ret;
}
@@ -1321,7 +1311,6 @@ static int hfi1_filter_mad_mgmt_class(void *ibhdr, void *packet_data,
static int hfi1_filter_qp_number(void *ibhdr, void *packet_data, void *value)
{
-
struct hfi1_ib_header *hdr;
struct hfi1_other_headers *ohdr = NULL;
int ret;
@@ -1404,7 +1393,6 @@ static int hfi1_filter_ib_service_level(void *ibhdr, void *packet_data,
static int hfi1_filter_ib_pkey(void *ibhdr, void *packet_data, void *value)
{
-
u32 lnh = 0;
struct hfi1_ib_header *hdr;
struct hfi1_other_headers *ohdr = NULL;
@@ -1476,16 +1464,14 @@ static struct snoop_packet *allocate_snoop_packet(u32 hdr_len,
u32 data_len,
u32 md_len)
{
-
struct snoop_packet *packet;
- packet = kzalloc(sizeof(struct snoop_packet) + hdr_len + data_len
+ packet = kzalloc(sizeof(*packet) + hdr_len + data_len
+ md_len,
GFP_ATOMIC | __GFP_NOWARN);
if (likely(packet))
INIT_LIST_HEAD(&packet->list);
-
return packet;
}
@@ -1542,12 +1528,11 @@ int snoop_recv_handler(struct hfi1_packet *packet)
unlikely(snoop_flags & SNOOP_USE_METADATA))
md_len = sizeof(struct capture_md);
-
s_packet = allocate_snoop_packet(header_size,
tlen - header_size,
md_len);
- if (unlikely(s_packet == NULL)) {
+ if (unlikely(!s_packet)) {
dd_dev_warn_ratelimited(ppd->dd, "Unable to allocate snoop/capture packet\n");
break;
}
@@ -1618,14 +1603,12 @@ int snoop_recv_handler(struct hfi1_packet *packet)
/*
* Handle snooping and capturing packets when sdma is being used.
*/
-int snoop_send_dma_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc)
+int snoop_send_dma_handler(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc)
{
- pr_alert("Snooping/Capture of Send DMA Packets Is Not Supported!\n");
+ pr_alert("Snooping/Capture of Send DMA Packets Is Not Supported!\n");
snoop_dbg("Unsupported Operation");
- return hfi1_verbs_send_dma(qp, ibhdr, hdrwords, ss, len, plen, dwords,
- 0);
+ return hfi1_verbs_send_dma(qp, ps, 0);
}
/*
@@ -1633,12 +1616,16 @@ int snoop_send_dma_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr,
* bypass packets. The only way to send a bypass packet currently is to use the
* diagpkt interface. When that interface is enable snoop/capture is not.
*/
-int snoop_send_pio_handler(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc)
+int snoop_send_pio_handler(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc)
{
- struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
- struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
+ struct ahg_ib_header *ahdr = qp->s_hdr;
+ u32 hdrwords = qp->s_hdrwords;
+ struct hfi1_sge_state *ss = qp->s_cur_sge;
+ u32 len = qp->s_cur_size;
+ u32 dwords = (len + 3) >> 2;
+ u32 plen = hdrwords + dwords + 2; /* includes pbc */
+ struct hfi1_pportdata *ppd = ps->ppd;
struct snoop_packet *s_packet = NULL;
u32 *hdr = (u32 *)&ahdr->ibh;
u32 length = 0;
@@ -1666,7 +1653,7 @@ int snoop_send_pio_handler(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
/* not using ss->total_len as arg 2 b/c that does not count CRC */
s_packet = allocate_snoop_packet(hdr_len, tlen - hdr_len, md_len);
- if (unlikely(s_packet == NULL)) {
+ if (unlikely(!s_packet)) {
dd_dev_warn_ratelimited(ppd->dd, "Unable to allocate snoop/capture packet\n");
goto out;
}
@@ -1783,8 +1770,7 @@ int snoop_send_pio_handler(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
break;
}
out:
- return hfi1_verbs_send_pio(qp, ahdr, hdrwords, ss, len, plen, dwords,
- md.u.pbc);
+ return hfi1_verbs_send_pio(qp, ps, md.u.pbc);
}
/*
@@ -1836,7 +1822,7 @@ void snoop_inline_pio_send(struct hfi1_devdata *dd, struct pio_buf *pbuf,
s_packet = allocate_snoop_packet(packet_len, 0, md_len);
- if (unlikely(s_packet == NULL)) {
+ if (unlikely(!s_packet)) {
dd_dev_warn_ratelimited(dd, "Unable to allocate snoop/capture packet\n");
goto inline_pio_out;
}
@@ -1868,5 +1854,4 @@ void snoop_inline_pio_send(struct hfi1_devdata *dd, struct pio_buf *pbuf,
inline_pio_out:
pio_copy(dd, pbuf, pbc, from, count);
-
}
diff --git a/drivers/staging/rdma/hfi1/driver.c b/drivers/staging/rdma/hfi1/driver.c
index ce69141b56cb..8485de1fce08 100644
--- a/drivers/staging/rdma/hfi1/driver.c
+++ b/drivers/staging/rdma/hfi1/driver.c
@@ -158,7 +158,7 @@ const char *get_unit_name(int unit)
{
static char iname[16];
- snprintf(iname, sizeof(iname), DRIVER_NAME"_%u", unit);
+ snprintf(iname, sizeof(iname), DRIVER_NAME "_%u", unit);
return iname;
}
@@ -436,59 +436,58 @@ static inline void init_packet(struct hfi1_ctxtdata *rcd,
#ifndef CONFIG_PRESCAN_RXQ
static void prescan_rxq(struct hfi1_packet *packet) {}
-#else /* CONFIG_PRESCAN_RXQ */
+#else /* !CONFIG_PRESCAN_RXQ */
static int prescan_receive_queue;
static void process_ecn(struct hfi1_qp *qp, struct hfi1_ib_header *hdr,
struct hfi1_other_headers *ohdr,
- u64 rhf, struct ib_grh *grh)
+ u64 rhf, u32 bth1, struct ib_grh *grh)
{
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
- u32 bth1;
+ u32 rqpn = 0;
+ u16 rlid;
u8 sc5, svc_type;
- int is_fecn, is_becn;
switch (qp->ibqp.qp_type) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
case IB_QPT_UD:
+ rlid = be16_to_cpu(hdr->lrh[3]);
+ rqpn = be32_to_cpu(ohdr->u.ud.deth[1]) & HFI1_QPN_MASK;
svc_type = IB_CC_SVCTYPE_UD;
break;
- case IB_QPT_UC: /* LATER */
- case IB_QPT_RC: /* LATER */
+ case IB_QPT_UC:
+ rlid = qp->remote_ah_attr.dlid;
+ rqpn = qp->remote_qpn;
+ svc_type = IB_CC_SVCTYPE_UC;
+ break;
+ case IB_QPT_RC:
+ rlid = qp->remote_ah_attr.dlid;
+ rqpn = qp->remote_qpn;
+ svc_type = IB_CC_SVCTYPE_RC;
+ break;
default:
return;
}
- is_fecn = (be32_to_cpu(ohdr->bth[1]) >> HFI1_FECN_SHIFT) &
- HFI1_FECN_MASK;
- is_becn = (be32_to_cpu(ohdr->bth[1]) >> HFI1_BECN_SHIFT) &
- HFI1_BECN_MASK;
-
sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf;
if (rhf_dc_info(rhf))
sc5 |= 0x10;
- if (is_fecn) {
- u32 src_qpn = be32_to_cpu(ohdr->u.ud.deth[1]) & HFI1_QPN_MASK;
+ if (bth1 & HFI1_FECN_SMASK) {
u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]);
u16 dlid = be16_to_cpu(hdr->lrh[1]);
- u16 slid = be16_to_cpu(hdr->lrh[3]);
- return_cnp(ibp, qp, src_qpn, pkey, dlid, slid, sc5, grh);
+ return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc5, grh);
}
- if (is_becn) {
+ if (bth1 & HFI1_BECN_SMASK) {
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
- u32 lqpn = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK;
+ u32 lqpn = bth1 & HFI1_QPN_MASK;
u8 sl = ibp->sc_to_sl[sc5];
- process_becn(ppd, sl, 0, lqpn, 0, svc_type);
+ process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type);
}
-
- /* turn off BECN, or FECN */
- bth1 = be32_to_cpu(ohdr->bth[1]);
- bth1 &= ~(HFI1_FECN_MASK << HFI1_FECN_SHIFT);
- bth1 &= ~(HFI1_BECN_MASK << HFI1_BECN_SHIFT);
- ohdr->bth[1] = cpu_to_be32(bth1);
}
struct ps_mdata {
@@ -508,38 +507,51 @@ static inline void init_ps_mdata(struct ps_mdata *mdata,
mdata->rcd = rcd;
mdata->rsize = packet->rsize;
mdata->maxcnt = packet->maxcnt;
+ mdata->ps_head = packet->rhqoff;
- if (rcd->ps_state.initialized == 0) {
- mdata->ps_head = packet->rhqoff;
- rcd->ps_state.initialized++;
- } else
- mdata->ps_head = rcd->ps_state.ps_head;
-
- if (HFI1_CAP_IS_KSET(DMA_RTAIL)) {
- mdata->ps_tail = packet->hdrqtail;
- mdata->ps_seq = 0; /* not used with DMA_RTAIL */
+ if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) {
+ mdata->ps_tail = get_rcvhdrtail(rcd);
+ if (rcd->ctxt == HFI1_CTRL_CTXT)
+ mdata->ps_seq = rcd->seq_cnt;
+ else
+ mdata->ps_seq = 0; /* not used with DMA_RTAIL */
} else {
mdata->ps_tail = 0; /* used only with DMA_RTAIL*/
mdata->ps_seq = rcd->seq_cnt;
}
}
-static inline int ps_done(struct ps_mdata *mdata, u64 rhf)
+static inline int ps_done(struct ps_mdata *mdata, u64 rhf,
+ struct hfi1_ctxtdata *rcd)
{
- if (HFI1_CAP_IS_KSET(DMA_RTAIL))
+ if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL))
return mdata->ps_head == mdata->ps_tail;
return mdata->ps_seq != rhf_rcv_seq(rhf);
}
-static inline void update_ps_mdata(struct ps_mdata *mdata)
+static inline int ps_skip(struct ps_mdata *mdata, u64 rhf,
+ struct hfi1_ctxtdata *rcd)
{
- struct hfi1_ctxtdata *rcd = mdata->rcd;
+ /*
+ * Control context can potentially receive an invalid rhf.
+ * Drop such packets.
+ */
+ if ((rcd->ctxt == HFI1_CTRL_CTXT) && (mdata->ps_head != mdata->ps_tail))
+ return mdata->ps_seq != rhf_rcv_seq(rhf);
+
+ return 0;
+}
+static inline void update_ps_mdata(struct ps_mdata *mdata,
+ struct hfi1_ctxtdata *rcd)
+{
mdata->ps_head += mdata->rsize;
- if (mdata->ps_head > mdata->maxcnt)
+ if (mdata->ps_head >= mdata->maxcnt)
mdata->ps_head = 0;
- rcd->ps_state.ps_head = mdata->ps_head;
- if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) {
+
+ /* Control context must do seq counting */
+ if (!HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL) ||
+ (rcd->ctxt == HFI1_CTRL_CTXT)) {
if (++mdata->ps_seq > 13)
mdata->ps_seq = 1;
}
@@ -571,13 +583,16 @@ static void prescan_rxq(struct hfi1_packet *packet)
struct hfi1_other_headers *ohdr;
struct ib_grh *grh = NULL;
u64 rhf = rhf_to_cpu(rhf_addr);
- u32 etype = rhf_rcv_type(rhf), qpn;
+ u32 etype = rhf_rcv_type(rhf), qpn, bth1;
int is_ecn = 0;
u8 lnh;
- if (ps_done(&mdata, rhf))
+ if (ps_done(&mdata, rhf, rcd))
break;
+ if (ps_skip(&mdata, rhf, rcd))
+ goto next;
+
if (etype != RHF_RCV_TYPE_IB)
goto next;
@@ -593,15 +608,13 @@ static void prescan_rxq(struct hfi1_packet *packet)
} else
goto next; /* just in case */
- is_ecn |= be32_to_cpu(ohdr->bth[1]) &
- (HFI1_FECN_MASK << HFI1_FECN_SHIFT);
- is_ecn |= be32_to_cpu(ohdr->bth[1]) &
- (HFI1_BECN_MASK << HFI1_BECN_SHIFT);
+ bth1 = be32_to_cpu(ohdr->bth[1]);
+ is_ecn = !!(bth1 & (HFI1_FECN_SMASK | HFI1_BECN_SMASK));
if (!is_ecn)
goto next;
- qpn = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK;
+ qpn = bth1 & HFI1_QPN_MASK;
rcu_read_lock();
qp = hfi1_lookup_qpn(ibp, qpn);
@@ -610,14 +623,44 @@ static void prescan_rxq(struct hfi1_packet *packet)
goto next;
}
- process_ecn(qp, hdr, ohdr, rhf, grh);
+ process_ecn(qp, hdr, ohdr, rhf, bth1, grh);
rcu_read_unlock();
+
+ /* turn off BECN, FECN */
+ bth1 &= ~(HFI1_FECN_SMASK | HFI1_BECN_SMASK);
+ ohdr->bth[1] = cpu_to_be32(bth1);
next:
- update_ps_mdata(&mdata);
+ update_ps_mdata(&mdata, rcd);
}
}
#endif /* CONFIG_PRESCAN_RXQ */
+static inline int skip_rcv_packet(struct hfi1_packet *packet, int thread)
+{
+ int ret = RCV_PKT_OK;
+
+ /* Set up for the next packet */
+ packet->rhqoff += packet->rsize;
+ if (packet->rhqoff >= packet->maxcnt)
+ packet->rhqoff = 0;
+
+ packet->numpkt++;
+ if (unlikely((packet->numpkt & (MAX_PKT_RECV - 1)) == 0)) {
+ if (thread) {
+ cond_resched();
+ } else {
+ ret = RCV_PKT_LIMIT;
+ this_cpu_inc(*packet->rcd->dd->rcv_limit);
+ }
+ }
+
+ packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff +
+ packet->rcd->dd->rhf_offset;
+ packet->rhf = rhf_to_cpu(packet->rhf_addr);
+
+ return ret;
+}
+
static inline int process_rcv_packet(struct hfi1_packet *packet, int thread)
{
int ret = RCV_PKT_OK;
@@ -721,8 +764,8 @@ static inline void process_rcv_qp_work(struct hfi1_packet *packet)
*/
list_for_each_entry_safe(qp, nqp, &rcd->qp_wait_list, rspwait) {
list_del_init(&qp->rspwait);
- if (qp->r_flags & HFI1_R_RSP_NAK) {
- qp->r_flags &= ~HFI1_R_RSP_NAK;
+ if (qp->r_flags & HFI1_R_RSP_DEFERED_ACK) {
+ qp->r_flags &= ~HFI1_R_RSP_DEFERED_ACK;
hfi1_send_rc_ack(rcd, qp, 0);
}
if (qp->r_flags & HFI1_R_RSP_SEND) {
@@ -791,7 +834,6 @@ int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread)
while (last == RCV_PKT_OK) {
last = process_rcv_packet(&packet, thread);
- hdrqtail = get_rcvhdrtail(rcd);
if (packet.rhqoff == hdrqtail)
last = RCV_PKT_DONE;
process_rcv_update(last, &packet);
@@ -806,7 +848,7 @@ static inline void set_all_nodma_rtail(struct hfi1_devdata *dd)
{
int i;
- for (i = 0; i < dd->first_user_ctxt; i++)
+ for (i = HFI1_CTRL_CTXT + 1; i < dd->first_user_ctxt; i++)
dd->rcd[i]->do_interrupt =
&handle_receive_interrupt_nodma_rtail;
}
@@ -815,7 +857,7 @@ static inline void set_all_dma_rtail(struct hfi1_devdata *dd)
{
int i;
- for (i = 0; i < dd->first_user_ctxt; i++)
+ for (i = HFI1_CTRL_CTXT + 1; i < dd->first_user_ctxt; i++)
dd->rcd[i]->do_interrupt =
&handle_receive_interrupt_dma_rtail;
}
@@ -831,12 +873,16 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread)
{
struct hfi1_devdata *dd = rcd->dd;
u32 hdrqtail;
- int last = RCV_PKT_OK, needset = 1;
+ int needset, last = RCV_PKT_OK;
struct hfi1_packet packet;
+ int skip_pkt = 0;
+
+ /* Control context will always use the slow path interrupt handler */
+ needset = (rcd->ctxt == HFI1_CTRL_CTXT) ? 0 : 1;
init_packet(rcd, &packet);
- if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) {
+ if (!HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) {
u32 seq = rhf_rcv_seq(packet.rhf);
if (seq != rcd->seq_cnt) {
@@ -851,6 +897,17 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread)
goto bail;
}
smp_rmb(); /* prevent speculative reads of dma'ed hdrq */
+
+ /*
+ * Control context can potentially receive an invalid
+ * rhf. Drop such packets.
+ */
+ if (rcd->ctxt == HFI1_CTRL_CTXT) {
+ u32 seq = rhf_rcv_seq(packet.rhf);
+
+ if (seq != rcd->seq_cnt)
+ skip_pkt = 1;
+ }
}
prescan_rxq(&packet);
@@ -868,11 +925,14 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread)
dd->rhf_offset;
packet.rhf = rhf_to_cpu(packet.rhf_addr);
+ } else if (skip_pkt) {
+ last = skip_rcv_packet(&packet, thread);
+ skip_pkt = 0;
} else {
last = process_rcv_packet(&packet, thread);
}
- if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) {
+ if (!HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) {
u32 seq = rhf_rcv_seq(packet.rhf);
if (++rcd->seq_cnt > 13)
@@ -888,6 +948,19 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread)
} else {
if (packet.rhqoff == hdrqtail)
last = RCV_PKT_DONE;
+ /*
+ * Control context can potentially receive an invalid
+ * rhf. Drop such packets.
+ */
+ if (rcd->ctxt == HFI1_CTRL_CTXT) {
+ u32 seq = rhf_rcv_seq(packet.rhf);
+
+ if (++rcd->seq_cnt > 13)
+ rcd->seq_cnt = 1;
+ if (!last && (seq != rcd->seq_cnt))
+ skip_pkt = 1;
+ }
+
if (needset) {
dd_dev_info(dd,
"Switching to DMA_RTAIL\n");
@@ -1163,20 +1236,20 @@ void handle_eflags(struct hfi1_packet *packet)
struct hfi1_ctxtdata *rcd = packet->rcd;
u32 rte = rhf_rcv_type_err(packet->rhf);
- dd_dev_err(rcd->dd,
- "receive context %d: rhf 0x%016llx, errs [ %s%s%s%s%s%s%s%s] rte 0x%x\n",
- rcd->ctxt, packet->rhf,
- packet->rhf & RHF_K_HDR_LEN_ERR ? "k_hdr_len " : "",
- packet->rhf & RHF_DC_UNC_ERR ? "dc_unc " : "",
- packet->rhf & RHF_DC_ERR ? "dc " : "",
- packet->rhf & RHF_TID_ERR ? "tid " : "",
- packet->rhf & RHF_LEN_ERR ? "len " : "",
- packet->rhf & RHF_ECC_ERR ? "ecc " : "",
- packet->rhf & RHF_VCRC_ERR ? "vcrc " : "",
- packet->rhf & RHF_ICRC_ERR ? "icrc " : "",
- rte);
-
rcv_hdrerr(rcd, rcd->ppd, packet);
+ if (rhf_err_flags(packet->rhf))
+ dd_dev_err(rcd->dd,
+ "receive context %d: rhf 0x%016llx, errs [ %s%s%s%s%s%s%s%s] rte 0x%x\n",
+ rcd->ctxt, packet->rhf,
+ packet->rhf & RHF_K_HDR_LEN_ERR ? "k_hdr_len " : "",
+ packet->rhf & RHF_DC_UNC_ERR ? "dc_unc " : "",
+ packet->rhf & RHF_DC_ERR ? "dc " : "",
+ packet->rhf & RHF_TID_ERR ? "tid " : "",
+ packet->rhf & RHF_LEN_ERR ? "len " : "",
+ packet->rhf & RHF_ECC_ERR ? "ecc " : "",
+ packet->rhf & RHF_VCRC_ERR ? "vcrc " : "",
+ packet->rhf & RHF_ICRC_ERR ? "icrc " : "",
+ rte);
}
/*
diff --git a/drivers/staging/rdma/hfi1/efivar.c b/drivers/staging/rdma/hfi1/efivar.c
new file mode 100644
index 000000000000..7dc5bae220e0
--- /dev/null
+++ b/drivers/staging/rdma/hfi1/efivar.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#include "efivar.h"
+
+/* GUID for HFI1 variables in EFI */
+#define HFI1_EFIVAR_GUID EFI_GUID(0xc50a953e, 0xa8b2, 0x42a6, \
+ 0xbf, 0x89, 0xd3, 0x33, 0xa6, 0xe9, 0xe6, 0xd4)
+/* largest EFI data size we expect */
+#define EFI_DATA_SIZE 4096
+
+/*
+ * Read the named EFI variable. Return the size of the actual data in *size
+ * and a kmalloc'ed buffer in *return_data. The caller must free the
+ * data. It is guaranteed that *return_data will be NULL and *size = 0
+ * if this routine fails.
+ *
+ * Return 0 on success, -errno on failure.
+ */
+static int read_efi_var(const char *name, unsigned long *size,
+ void **return_data)
+{
+ efi_status_t status;
+ efi_char16_t *uni_name;
+ efi_guid_t guid;
+ unsigned long temp_size;
+ void *temp_buffer;
+ void *data;
+ int i;
+ int ret;
+
+ /* set failure return values */
+ *size = 0;
+ *return_data = NULL;
+
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ return -EOPNOTSUPP;
+
+ uni_name = kzalloc(sizeof(efi_char16_t) * (strlen(name) + 1),
+ GFP_KERNEL);
+ temp_buffer = kzalloc(EFI_DATA_SIZE, GFP_KERNEL);
+
+ if (!uni_name || !temp_buffer) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* input: the size of the buffer */
+ temp_size = EFI_DATA_SIZE;
+
+ /* convert ASCII to unicode - it is a 1:1 mapping */
+ for (i = 0; name[i]; i++)
+ uni_name[i] = name[i];
+
+ /* need a variable for our GUID */
+ guid = HFI1_EFIVAR_GUID;
+
+ /* call into EFI runtime services */
+ status = efi.get_variable(
+ uni_name,
+ &guid,
+ NULL,
+ &temp_size,
+ temp_buffer);
+
+ /*
+ * It would be nice to call efi_status_to_err() here, but that
+ * is in the EFIVAR_FS code and may not be compiled in.
+ * However, even that is insufficient since it does not cover
+ * EFI_BUFFER_TOO_SMALL which could be an important return.
+ * For now, just split out succces or not found.
+ */
+ ret = status == EFI_SUCCESS ? 0 :
+ status == EFI_NOT_FOUND ? -ENOENT :
+ -EINVAL;
+ if (ret)
+ goto fail;
+
+ /*
+ * We have successfully read the EFI variable into our
+ * temporary buffer. Now allocate a correctly sized
+ * buffer.
+ */
+ data = kmalloc(temp_size, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ memcpy(data, temp_buffer, temp_size);
+ *size = temp_size;
+ *return_data = data;
+
+fail:
+ kfree(uni_name);
+ kfree(temp_buffer);
+
+ return ret;
+}
+
+/*
+ * Read an HFI1 EFI variable of the form:
+ * <PCIe address>-<kind>
+ * Return an kalloc'ed array and size of the data.
+ *
+ * Returns 0 on success, -errno on failure.
+ */
+int read_hfi1_efi_var(struct hfi1_devdata *dd, const char *kind,
+ unsigned long *size, void **return_data)
+{
+ char name[64];
+
+ /* create a common prefix */
+ snprintf(name, sizeof(name), "%04x:%02x:%02x.%x-%s",
+ pci_domain_nr(dd->pcidev->bus),
+ dd->pcidev->bus->number,
+ PCI_SLOT(dd->pcidev->devfn),
+ PCI_FUNC(dd->pcidev->devfn),
+ kind);
+
+ return read_efi_var(name, size, return_data);
+}
diff --git a/drivers/staging/rdma/hfi1/efivar.h b/drivers/staging/rdma/hfi1/efivar.h
new file mode 100644
index 000000000000..070706225c51
--- /dev/null
+++ b/drivers/staging/rdma/hfi1/efivar.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+#ifndef _HFI1_EFIVAR_H
+#define _HFI1_EFIVAR_H
+
+#include <linux/efi.h>
+
+#include "hfi.h"
+
+int read_hfi1_efi_var(struct hfi1_devdata *dd, const char *kind,
+ unsigned long *size, void **return_data);
+
+#endif /* _HFI1_EFIVAR_H */
diff --git a/drivers/staging/rdma/hfi1/eprom.c b/drivers/staging/rdma/hfi1/eprom.c
index b61d3ae93ed1..fb620c97f592 100644
--- a/drivers/staging/rdma/hfi1/eprom.c
+++ b/drivers/staging/rdma/hfi1/eprom.c
@@ -53,17 +53,26 @@
#include "eprom.h"
/*
- * The EPROM is logically divided into two partitions:
+ * The EPROM is logically divided into three partitions:
* partition 0: the first 128K, visible from PCI ROM BAR
- * partition 1: the rest
+ * partition 1: 4K config file (sector size)
+ * partition 2: the rest
*/
#define P0_SIZE (128 * 1024)
+#define P1_SIZE (4 * 1024)
#define P1_START P0_SIZE
+#define P2_START (P0_SIZE + P1_SIZE)
+
+/* erase sizes supported by the controller */
+#define SIZE_4KB (4 * 1024)
+#define MASK_4KB (SIZE_4KB - 1)
-/* largest erase size supported by the controller */
#define SIZE_32KB (32 * 1024)
#define MASK_32KB (SIZE_32KB - 1)
+#define SIZE_64KB (64 * 1024)
+#define MASK_64KB (SIZE_64KB - 1)
+
/* controller page size, in bytes */
#define EP_PAGE_SIZE 256
#define EEP_PAGE_MASK (EP_PAGE_SIZE - 1)
@@ -75,10 +84,12 @@
#define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr)
#define CMD_READ_SR1 ((0x05 << CMD_SHIFT))
#define CMD_WRITE_ENABLE ((0x06 << CMD_SHIFT))
+#define CMD_SECTOR_ERASE_4KB(addr) ((0x20 << CMD_SHIFT) | addr)
#define CMD_SECTOR_ERASE_32KB(addr) ((0x52 << CMD_SHIFT) | addr)
#define CMD_CHIP_ERASE ((0x60 << CMD_SHIFT))
#define CMD_READ_MANUF_DEV_ID ((0x90 << CMD_SHIFT))
#define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT))
+#define CMD_SECTOR_ERASE_64KB(addr) ((0xd8 << CMD_SHIFT) | addr)
/* controller interface speeds */
#define EP_SPEED_FULL 0x2 /* full speed */
@@ -188,28 +199,43 @@ static int erase_chip(struct hfi1_devdata *dd)
}
/*
- * Erase a range using the 32KB erase command.
+ * Erase a range.
*/
-static int erase_32kb_range(struct hfi1_devdata *dd, u32 start, u32 end)
+static int erase_range(struct hfi1_devdata *dd, u32 start, u32 len)
{
+ u32 end = start + len;
int ret = 0;
if (end < start)
return -EINVAL;
- if ((start & MASK_32KB) || (end & MASK_32KB)) {
+ /* check the end points for the minimum erase */
+ if ((start & MASK_4KB) || (end & MASK_4KB)) {
dd_dev_err(dd,
- "%s: non-aligned range (0x%x,0x%x) for a 32KB erase\n",
+ "%s: non-aligned range (0x%x,0x%x) for a 4KB erase\n",
__func__, start, end);
return -EINVAL;
}
write_enable(dd);
- for (; start < end; start += SIZE_32KB) {
+ while (start < end) {
write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_WRITE_ENABLE);
- write_csr(dd, ASIC_EEP_ADDR_CMD,
- CMD_SECTOR_ERASE_32KB(start));
+ /* check in order of largest to smallest */
+ if (((start & MASK_64KB) == 0) && (start + SIZE_64KB <= end)) {
+ write_csr(dd, ASIC_EEP_ADDR_CMD,
+ CMD_SECTOR_ERASE_64KB(start));
+ start += SIZE_64KB;
+ } else if (((start & MASK_32KB) == 0) &&
+ (start + SIZE_32KB <= end)) {
+ write_csr(dd, ASIC_EEP_ADDR_CMD,
+ CMD_SECTOR_ERASE_32KB(start));
+ start += SIZE_32KB;
+ } else { /* 4KB will work */
+ write_csr(dd, ASIC_EEP_ADDR_CMD,
+ CMD_SECTOR_ERASE_4KB(start));
+ start += SIZE_4KB;
+ }
ret = wait_for_not_busy(dd);
if (ret)
goto done;
@@ -309,6 +335,18 @@ done:
return ret;
}
+/* convert an range composite to a length, in bytes */
+static inline u32 extract_rlen(u32 composite)
+{
+ return (composite & 0xffff) * EP_PAGE_SIZE;
+}
+
+/* convert an range composite to a start, in bytes */
+static inline u32 extract_rstart(u32 composite)
+{
+ return (composite >> 16) * EP_PAGE_SIZE;
+}
+
/*
* Perform the given operation on the EPROM. Called from user space. The
* user credentials have already been checked.
@@ -319,6 +357,8 @@ int handle_eprom_command(const struct hfi1_cmd *cmd)
{
struct hfi1_devdata *dd;
u32 dev_id;
+ u32 rlen; /* range length */
+ u32 rstart; /* range start */
int ret = 0;
/*
@@ -364,54 +404,29 @@ int handle_eprom_command(const struct hfi1_cmd *cmd)
sizeof(u32)))
ret = -EFAULT;
break;
+
case HFI1_CMD_EP_ERASE_CHIP:
ret = erase_chip(dd);
break;
- case HFI1_CMD_EP_ERASE_P0:
- if (cmd->len != P0_SIZE) {
- ret = -ERANGE;
- break;
- }
- ret = erase_32kb_range(dd, 0, cmd->len);
- break;
- case HFI1_CMD_EP_ERASE_P1:
- /* check for overflow */
- if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) {
- ret = -ERANGE;
- break;
- }
- ret = erase_32kb_range(dd, P1_START, P1_START + cmd->len);
- break;
- case HFI1_CMD_EP_READ_P0:
- if (cmd->len != P0_SIZE) {
- ret = -ERANGE;
- break;
- }
- ret = read_length(dd, 0, cmd->len, cmd->addr);
- break;
- case HFI1_CMD_EP_READ_P1:
- /* check for overflow */
- if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) {
- ret = -ERANGE;
- break;
- }
- ret = read_length(dd, P1_START, cmd->len, cmd->addr);
+
+ case HFI1_CMD_EP_ERASE_RANGE:
+ rlen = extract_rlen(cmd->len);
+ rstart = extract_rstart(cmd->len);
+ ret = erase_range(dd, rstart, rlen);
break;
- case HFI1_CMD_EP_WRITE_P0:
- if (cmd->len > P0_SIZE) {
- ret = -ERANGE;
- break;
- }
- ret = write_length(dd, 0, cmd->len, cmd->addr);
+
+ case HFI1_CMD_EP_READ_RANGE:
+ rlen = extract_rlen(cmd->len);
+ rstart = extract_rstart(cmd->len);
+ ret = read_length(dd, rstart, rlen, cmd->addr);
break;
- case HFI1_CMD_EP_WRITE_P1:
- /* check for overflow */
- if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) {
- ret = -ERANGE;
- break;
- }
- ret = write_length(dd, P1_START, cmd->len, cmd->addr);
+
+ case HFI1_CMD_EP_WRITE_RANGE:
+ rlen = extract_rlen(cmd->len);
+ rstart = extract_rstart(cmd->len);
+ ret = write_length(dd, rstart, rlen, cmd->addr);
break;
+
default:
dd_dev_err(dd, "%s: unexpected command %d\n",
__func__, cmd->type);
diff --git a/drivers/staging/rdma/hfi1/file_ops.c b/drivers/staging/rdma/hfi1/file_ops.c
index aae9826ec62b..d57d549052c8 100644
--- a/drivers/staging/rdma/hfi1/file_ops.c
+++ b/drivers/staging/rdma/hfi1/file_ops.c
@@ -47,20 +47,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/cdev.h>
-#include <linux/swap.h>
#include <linux/vmalloc.h>
-#include <linux/highmem.h>
#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <asm/pgtable.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/cred.h>
-#include <linux/uio.h>
#include "hfi.h"
#include "pio.h"
@@ -68,6 +58,7 @@
#include "common.h"
#include "trace.h"
#include "user_sdma.h"
+#include "user_exp_rcv.h"
#include "eprom.h"
#undef pr_fmt
@@ -170,18 +161,6 @@ enum mmap_types {
HFI1_MMAP_TOKEN_SET(SUBCTXT, subctxt) | \
HFI1_MMAP_TOKEN_SET(OFFSET, (offset_in_page(addr))))
-#define EXP_TID_SET(field, value) \
- (((value) & EXP_TID_TID##field##_MASK) << \
- EXP_TID_TID##field##_SHIFT)
-#define EXP_TID_CLEAR(tid, field) { \
- (tid) &= ~(EXP_TID_TID##field##_MASK << \
- EXP_TID_TID##field##_SHIFT); \
- }
-#define EXP_TID_RESET(tid, field, value) do { \
- EXP_TID_CLEAR(tid, field); \
- (tid) |= EXP_TID_SET(field, value); \
- } while (0)
-
#define dbg(fmt, ...) \
pr_info(fmt, ##__VA_ARGS__)
@@ -204,7 +183,8 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
size_t count, loff_t *offset)
{
const struct hfi1_cmd __user *ucmd;
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_cmd cmd;
struct hfi1_user_info uinfo;
struct hfi1_tid_info tinfo;
@@ -254,12 +234,9 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
break;
case HFI1_CMD_EP_INFO:
case HFI1_CMD_EP_ERASE_CHIP:
- case HFI1_CMD_EP_ERASE_P0:
- case HFI1_CMD_EP_ERASE_P1:
- case HFI1_CMD_EP_READ_P0:
- case HFI1_CMD_EP_READ_P1:
- case HFI1_CMD_EP_WRITE_P0:
- case HFI1_CMD_EP_WRITE_P1:
+ case HFI1_CMD_EP_ERASE_RANGE:
+ case HFI1_CMD_EP_READ_RANGE:
+ case HFI1_CMD_EP_WRITE_RANGE:
uctxt_required = 0; /* assigned user context not required */
must_be_root = 1; /* validate user */
copy = 0;
@@ -338,17 +315,17 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
ret = exp_tid_free(fp, &tinfo);
break;
case HFI1_CMD_RECV_CTRL:
- ret = manage_rcvq(uctxt, subctxt_fp(fp), (int)user_val);
+ ret = manage_rcvq(uctxt, fd->subctxt, (int)user_val);
break;
case HFI1_CMD_POLL_TYPE:
uctxt->poll_type = (typeof(uctxt->poll_type))user_val;
break;
case HFI1_CMD_ACK_EVENT:
- ret = user_event_ack(uctxt, subctxt_fp(fp), user_val);
+ ret = user_event_ack(uctxt, fd->subctxt, user_val);
break;
case HFI1_CMD_SET_PKEY:
if (HFI1_CAP_IS_USET(PKEY_CHECK))
- ret = set_ctxt_pkey(uctxt, subctxt_fp(fp), user_val);
+ ret = set_ctxt_pkey(uctxt, fd->subctxt, user_val);
else
ret = -EPERM;
break;
@@ -413,12 +390,9 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
}
case HFI1_CMD_EP_INFO:
case HFI1_CMD_EP_ERASE_CHIP:
- case HFI1_CMD_EP_ERASE_P0:
- case HFI1_CMD_EP_ERASE_P1:
- case HFI1_CMD_EP_READ_P0:
- case HFI1_CMD_EP_READ_P1:
- case HFI1_CMD_EP_WRITE_P0:
- case HFI1_CMD_EP_WRITE_P1:
+ case HFI1_CMD_EP_ERASE_RANGE:
+ case HFI1_CMD_EP_READ_RANGE:
+ case HFI1_CMD_EP_WRITE_RANGE:
ret = handle_eprom_command(&cmd);
break;
}
@@ -431,13 +405,13 @@ bail:
static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
{
- struct hfi1_user_sdma_pkt_q *pq;
- struct hfi1_user_sdma_comp_q *cq;
+ struct hfi1_filedata *fd = kiocb->ki_filp->private_data;
+ struct hfi1_user_sdma_pkt_q *pq = fd->pq;
+ struct hfi1_user_sdma_comp_q *cq = fd->cq;
int ret = 0, done = 0, reqs = 0;
unsigned long dim = from->nr_segs;
- if (!user_sdma_comp_fp(kiocb->ki_filp) ||
- !user_sdma_pkt_fp(kiocb->ki_filp)) {
+ if (!cq || !pq) {
ret = -EIO;
goto done;
}
@@ -448,10 +422,7 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
}
hfi1_cdbg(SDMA, "SDMA request from %u:%u (%lu)",
- ctxt_fp(kiocb->ki_filp)->ctxt, subctxt_fp(kiocb->ki_filp),
- dim);
- pq = user_sdma_pkt_fp(kiocb->ki_filp);
- cq = user_sdma_comp_fp(kiocb->ki_filp);
+ fd->uctxt->ctxt, fd->subctxt, dim);
if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) {
ret = -ENOSPC;
@@ -476,7 +447,8 @@ done:
static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
{
- struct hfi1_ctxtdata *uctxt;
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd;
unsigned long flags, pfn;
u64 token = vma->vm_pgoff << PAGE_SHIFT,
@@ -486,7 +458,6 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
int ret = 0;
u16 ctxt;
- uctxt = ctxt_fp(fp);
if (!is_valid_mmap(token) || !uctxt ||
!(vma->vm_flags & VM_SHARED)) {
ret = -EINVAL;
@@ -496,7 +467,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
ctxt = HFI1_MMAP_TOKEN_GET(CTXT, token);
subctxt = HFI1_MMAP_TOKEN_GET(SUBCTXT, token);
type = HFI1_MMAP_TOKEN_GET(TYPE, token);
- if (ctxt != uctxt->ctxt || subctxt != subctxt_fp(fp)) {
+ if (ctxt != uctxt->ctxt || subctxt != fd->subctxt) {
ret = -EINVAL;
goto done;
}
@@ -660,13 +631,12 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
vmf = 1;
break;
case SDMA_COMP: {
- struct hfi1_user_sdma_comp_q *cq;
+ struct hfi1_user_sdma_comp_q *cq = fd->cq;
- if (!user_sdma_comp_fp(fp)) {
+ if (!cq) {
ret = -EFAULT;
goto done;
}
- cq = user_sdma_comp_fp(fp);
memaddr = (u64)cq->comps;
memlen = ALIGN(sizeof(*cq->comps) * cq->nentries, PAGE_SIZE);
flags |= VM_IO | VM_DONTEXPAND;
@@ -680,16 +650,16 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
if ((vma->vm_end - vma->vm_start) != memlen) {
hfi1_cdbg(PROC, "%u:%u Memory size mismatch %lu:%lu",
- uctxt->ctxt, subctxt_fp(fp),
+ uctxt->ctxt, fd->subctxt,
(vma->vm_end - vma->vm_start), memlen);
ret = -EINVAL;
goto done;
}
vma->vm_flags = flags;
- dd_dev_info(dd,
- "%s: %u:%u type:%u io/vf:%d/%d, addr:0x%llx, len:%lu(%lu), flags:0x%lx\n",
- __func__, ctxt, subctxt, type, mapio, vmf, memaddr, memlen,
+ hfi1_cdbg(PROC,
+ "%u:%u type:%u io/vf:%d/%d, addr:0x%llx, len:%lu(%lu), flags:0x%lx\n",
+ ctxt, subctxt, type, mapio, vmf, memaddr, memlen,
vma->vm_end - vma->vm_start, vma->vm_flags);
pfn = (unsigned long)(memaddr >> PAGE_SHIFT);
if (vmf) {
@@ -730,7 +700,7 @@ static unsigned int hfi1_poll(struct file *fp, struct poll_table_struct *pt)
struct hfi1_ctxtdata *uctxt;
unsigned pollflag;
- uctxt = ctxt_fp(fp);
+ uctxt = ((struct hfi1_filedata *)fp->private_data)->uctxt;
if (!uctxt)
pollflag = POLLERR;
else if (uctxt->poll_type == HFI1_POLL_TYPE_URGENT)
@@ -761,8 +731,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
flush_wc();
/* drain user sdma queue */
- if (fdata->pq)
- hfi1_user_sdma_free_queues(fdata);
+ hfi1_user_sdma_free_queues(fdata);
/*
* Clear any left over, unhandled events so the next process that
@@ -874,6 +843,14 @@ done:
return ret;
}
+/* return true if the device available for general use */
+static int usable_device(struct hfi1_devdata *dd)
+{
+ struct hfi1_pportdata *ppd = dd->pport;
+
+ return driver_lstate(ppd) == IB_PORT_ACTIVE;
+}
+
static int get_user_context(struct file *fp, struct hfi1_user_info *uinfo,
int devno, unsigned alg)
{
@@ -903,7 +880,11 @@ static int get_user_context(struct file *fp, struct hfi1_user_info *uinfo,
for (dev = 0; dev < devmax; dev++) {
pdd = hfi1_lookup(dev);
- if (pdd && pdd->freectxts &&
+ if (!pdd)
+ continue;
+ if (!usable_device(pdd))
+ continue;
+ if (pdd->freectxts &&
pdd->freectxts > free) {
dd = pdd;
free = pdd->freectxts;
@@ -912,7 +893,11 @@ static int get_user_context(struct file *fp, struct hfi1_user_info *uinfo,
} else {
for (dev = 0; dev < devmax; dev++) {
pdd = hfi1_lookup(dev);
- if (pdd && pdd->freectxts) {
+ if (!pdd)
+ continue;
+ if (!usable_device(pdd))
+ continue;
+ if (pdd->freectxts) {
dd = pdd;
break;
}
@@ -930,13 +915,13 @@ static int find_shared_ctxt(struct file *fp,
{
int devmax, ndev, i;
int ret = 0;
+ struct hfi1_filedata *fd = fp->private_data;
devmax = hfi1_count_units(NULL, NULL);
for (ndev = 0; ndev < devmax; ndev++) {
struct hfi1_devdata *dd = hfi1_lookup(ndev);
- /* device portion of usable() */
if (!(dd && (dd->flags & HFI1_PRESENT) && dd->kregbase))
continue;
for (i = dd->first_user_ctxt; i < dd->num_rcv_contexts; i++) {
@@ -959,10 +944,10 @@ static int find_shared_ctxt(struct file *fp,
ret = -EINVAL;
goto done;
}
- ctxt_fp(fp) = uctxt;
- subctxt_fp(fp) = uctxt->cnt++;
- uctxt->subpid[subctxt_fp(fp)] = current->pid;
- uctxt->active_slaves |= 1 << subctxt_fp(fp);
+ fd->uctxt = uctxt;
+ fd->subctxt = uctxt->cnt++;
+ uctxt->subpid[fd->subctxt] = current->pid;
+ uctxt->active_slaves |= 1 << fd->subctxt;
ret = 1;
goto done;
}
@@ -975,6 +960,7 @@ done:
static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
struct hfi1_user_info *uinfo)
{
+ struct hfi1_filedata *fd = fp->private_data;
struct hfi1_ctxtdata *uctxt;
unsigned ctxt;
int ret;
@@ -1011,8 +997,8 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
if (!uctxt->sc)
return -ENOMEM;
- dbg("allocated send context %u(%u)\n", uctxt->sc->sw_index,
- uctxt->sc->hw_context);
+ hfi1_cdbg(PROC, "allocated send context %u(%u)\n", uctxt->sc->sw_index,
+ uctxt->sc->hw_context);
ret = sc_enable(uctxt->sc);
if (ret)
return ret;
@@ -1022,7 +1008,7 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
* This has to be done here so the rest of the sub-contexts find the
* proper master.
*/
- if (uinfo->subctxt_cnt && !subctxt_fp(fp)) {
+ if (uinfo->subctxt_cnt && !fd->subctxt) {
ret = init_subctxts(uctxt, uinfo);
/*
* On error, we don't need to disable and de-allocate the
@@ -1042,7 +1028,7 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
spin_lock_init(&uctxt->sdma_qlock);
hfi1_stats.sps_ctxts++;
dd->freectxts--;
- ctxt_fp(fp) = uctxt;
+ fd->uctxt = uctxt;
return 0;
}
@@ -1106,7 +1092,8 @@ static int user_init(struct file *fp)
{
int ret;
unsigned int rcvctrl_ops = 0;
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
/* make sure that the context has already been setup */
if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags)) {
@@ -1118,7 +1105,7 @@ static int user_init(struct file *fp)
* Subctxts don't need to initialize anything since master
* has done it.
*/
- if (subctxt_fp(fp)) {
+ if (fd->subctxt) {
ret = wait_event_interruptible(uctxt->wait,
!test_bit(HFI1_CTXT_MASTER_UNINIT,
&uctxt->event_flags));
@@ -1178,8 +1165,8 @@ done:
static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
{
struct hfi1_ctxt_info cinfo;
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
int ret = 0;
memset(&cinfo, 0, sizeof(cinfo));
@@ -1189,7 +1176,7 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
cinfo.num_active = hfi1_count_active_units();
cinfo.unit = uctxt->dd->unit;
cinfo.ctxt = uctxt->ctxt;
- cinfo.subctxt = subctxt_fp(fp);
+ cinfo.subctxt = fd->subctxt;
cinfo.rcvtids = roundup(uctxt->egrbufs.alloced,
uctxt->dd->rcv_entries.group_size) +
uctxt->expected_count;
@@ -1201,10 +1188,10 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
cinfo.egrtids = uctxt->egrbufs.alloced;
cinfo.rcvhdrq_cnt = uctxt->rcvhdrq_cnt;
cinfo.rcvhdrq_entsize = uctxt->rcvhdrqentsize << 2;
- cinfo.sdma_ring_size = user_sdma_comp_fp(fp)->nentries;
+ cinfo.sdma_ring_size = fd->cq->nentries;
cinfo.rcvegr_size = uctxt->egrbufs.rcvtid_size;
- trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, subctxt_fp(fp), cinfo);
+ trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, fd->subctxt, cinfo);
if (copy_to_user(ubase, &cinfo, sizeof(cinfo)))
ret = -EFAULT;
done:
@@ -1213,7 +1200,8 @@ done:
static int setup_ctxt(struct file *fp)
{
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
int ret = 0;
@@ -1222,7 +1210,7 @@ static int setup_ctxt(struct file *fp)
* programming of eager buffers. This is done if context sharing
* is not requested or by the master process.
*/
- if (!uctxt->subctxt_cnt || !subctxt_fp(fp)) {
+ if (!uctxt->subctxt_cnt || !fd->subctxt) {
ret = hfi1_init_ctxt(uctxt->sc);
if (ret)
goto done;
@@ -1234,7 +1222,7 @@ static int setup_ctxt(struct file *fp)
ret = hfi1_setup_eagerbufs(uctxt);
if (ret)
goto done;
- if (uctxt->subctxt_cnt && !subctxt_fp(fp)) {
+ if (uctxt->subctxt_cnt && !fd->subctxt) {
ret = setup_subctxt(uctxt);
if (ret)
goto done;
@@ -1277,7 +1265,7 @@ static int setup_ctxt(struct file *fp)
uctxt->tidusemap[uctxt->tidmapcnt - 1] =
~((1ULL << (uctxt->numtidgroups %
BITS_PER_LONG)) - 1);
- trace_hfi1_exp_tid_map(uctxt->ctxt, subctxt_fp(fp), 0,
+ trace_hfi1_exp_tid_map(uctxt->ctxt, fd->subctxt, 0,
uctxt->tidusemap, uctxt->tidmapcnt);
}
ret = hfi1_user_sdma_alloc_queues(uctxt, fp);
@@ -1292,7 +1280,8 @@ done:
static int get_base_info(struct file *fp, void __user *ubase, __u32 len)
{
struct hfi1_base_info binfo;
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
ssize_t sz;
unsigned offset;
@@ -1314,50 +1303,50 @@ static int get_base_info(struct file *fp, void __user *ubase, __u32 len)
offset = ((u64)uctxt->sc->hw_free -
(u64)dd->cr_base[uctxt->numa_id].va) % PAGE_SIZE;
binfo.sc_credits_addr = HFI1_MMAP_TOKEN(PIO_CRED, uctxt->ctxt,
- subctxt_fp(fp), offset);
+ fd->subctxt, offset);
binfo.pio_bufbase = HFI1_MMAP_TOKEN(PIO_BUFS, uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
uctxt->sc->base_addr);
binfo.pio_bufbase_sop = HFI1_MMAP_TOKEN(PIO_BUFS_SOP,
uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
uctxt->sc->base_addr);
binfo.rcvhdr_bufbase = HFI1_MMAP_TOKEN(RCV_HDRQ, uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
uctxt->rcvhdrq);
binfo.rcvegr_bufbase = HFI1_MMAP_TOKEN(RCV_EGRBUF, uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
uctxt->egrbufs.rcvtids[0].phys);
binfo.sdma_comp_bufbase = HFI1_MMAP_TOKEN(SDMA_COMP, uctxt->ctxt,
- subctxt_fp(fp), 0);
+ fd->subctxt, 0);
/*
* user regs are at
* (RXE_PER_CONTEXT_USER + (ctxt * RXE_PER_CONTEXT_SIZE))
*/
binfo.user_regbase = HFI1_MMAP_TOKEN(UREGS, uctxt->ctxt,
- subctxt_fp(fp), 0);
+ fd->subctxt, 0);
offset = offset_in_page((((uctxt->ctxt - dd->first_user_ctxt) *
- HFI1_MAX_SHARED_CTXTS) + subctxt_fp(fp)) *
+ HFI1_MAX_SHARED_CTXTS) + fd->subctxt) *
sizeof(*dd->events));
binfo.events_bufbase = HFI1_MMAP_TOKEN(EVENTS, uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
offset);
binfo.status_bufbase = HFI1_MMAP_TOKEN(STATUS, uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
dd->status);
if (HFI1_CAP_IS_USET(DMA_RTAIL))
binfo.rcvhdrtail_base = HFI1_MMAP_TOKEN(RTAIL, uctxt->ctxt,
- subctxt_fp(fp), 0);
+ fd->subctxt, 0);
if (uctxt->subctxt_cnt) {
binfo.subctxt_uregbase = HFI1_MMAP_TOKEN(SUBCTXT_UREGS,
uctxt->ctxt,
- subctxt_fp(fp), 0);
+ fd->subctxt, 0);
binfo.subctxt_rcvhdrbuf = HFI1_MMAP_TOKEN(SUBCTXT_RCV_HDRQ,
uctxt->ctxt,
- subctxt_fp(fp), 0);
+ fd->subctxt, 0);
binfo.subctxt_rcvegrbuf = HFI1_MMAP_TOKEN(SUBCTXT_EGRBUF,
uctxt->ctxt,
- subctxt_fp(fp), 0);
+ fd->subctxt, 0);
}
sz = (len < sizeof(binfo)) ? len : sizeof(binfo);
if (copy_to_user(ubase, &binfo, sz))
@@ -1368,7 +1357,8 @@ static int get_base_info(struct file *fp, void __user *ubase, __u32 len)
static unsigned int poll_urgent(struct file *fp,
struct poll_table_struct *pt)
{
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
unsigned pollflag;
@@ -1390,7 +1380,8 @@ static unsigned int poll_urgent(struct file *fp,
static unsigned int poll_next(struct file *fp,
struct poll_table_struct *pt)
{
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
unsigned pollflag;
@@ -1562,7 +1553,8 @@ static inline unsigned num_free_groups(unsigned long map, u16 *start)
static int exp_tid_setup(struct file *fp, struct hfi1_tid_info *tinfo)
{
int ret = 0;
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
unsigned tid, mapped = 0, npages, ngroups, exp_groups,
tidpairs = uctxt->expected_count / 2;
@@ -1671,8 +1663,8 @@ static int exp_tid_setup(struct file *fp, struct hfi1_tid_info *tinfo)
* Now that we know how many free RcvArray entries we have,
* we can pin that many user pages.
*/
- ret = hfi1_get_user_pages(vaddr + (mapped * PAGE_SIZE),
- pinned, pages);
+ ret = hfi1_acquire_user_pages(vaddr + (mapped * PAGE_SIZE),
+ pinned, true, pages);
if (ret) {
/*
* We can't continue because the pages array won't be
@@ -1718,7 +1710,7 @@ static int exp_tid_setup(struct file *fp, struct hfi1_tid_info *tinfo)
pages[pmapped], 0,
tidsize, PCI_DMA_FROMDEVICE);
trace_hfi1_exp_rcv_set(uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
tid, vaddr,
phys[pmapped],
pages[pmapped]);
@@ -1763,7 +1755,7 @@ static int exp_tid_setup(struct file *fp, struct hfi1_tid_info *tinfo)
(((useidx & 0xffffff) << 16) |
((bitidx + bits_used) & 0xffffff)));
}
- trace_hfi1_exp_tid_map(uctxt->ctxt, subctxt_fp(fp), 0, uctxt->tidusemap,
+ trace_hfi1_exp_tid_map(uctxt->ctxt, fd->subctxt, 0, uctxt->tidusemap,
uctxt->tidmapcnt);
done:
@@ -1792,7 +1784,8 @@ bail:
static int exp_tid_free(struct file *fp, struct hfi1_tid_info *tinfo)
{
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
unsigned long tidmap[uctxt->tidmapcnt];
struct page **pages;
@@ -1828,7 +1821,7 @@ static int exp_tid_free(struct file *fp, struct hfi1_tid_info *tinfo)
hfi1_put_tid(dd, tid, PT_INVALID,
0, 0);
trace_hfi1_exp_rcv_free(uctxt->ctxt,
- subctxt_fp(fp),
+ fd->subctxt,
tid, phys[i],
pages[i]);
pci_unmap_page(dd->pcidev, phys[i],
@@ -1840,12 +1833,12 @@ static int exp_tid_free(struct file *fp, struct hfi1_tid_info *tinfo)
}
}
flush_wc();
- hfi1_release_user_pages(pshadow, pcount);
+ hfi1_release_user_pages(pshadow, pcount, true);
clear_bit(bitidx, &uctxt->tidusemap[idx]);
map &= ~(1ULL<<bitidx);
}
}
- trace_hfi1_exp_tid_map(uctxt->ctxt, subctxt_fp(fp), 1, uctxt->tidusemap,
+ trace_hfi1_exp_tid_map(uctxt->ctxt, fd->subctxt, 1, uctxt->tidusemap,
uctxt->tidmapcnt);
done:
return ret;
@@ -1869,7 +1862,7 @@ static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt)
uctxt->physshadow[tid] = 0;
uctxt->tid_pg_list[tid] = NULL;
pci_unmap_page(dd->pcidev, phys, PAGE_SIZE, PCI_DMA_FROMDEVICE);
- hfi1_release_user_pages(&p, 1);
+ hfi1_release_user_pages(&p, 1, true);
}
}
diff --git a/drivers/staging/rdma/hfi1/firmware.c b/drivers/staging/rdma/hfi1/firmware.c
index b4bdcf341aac..28ae42faa018 100644
--- a/drivers/staging/rdma/hfi1/firmware.c
+++ b/drivers/staging/rdma/hfi1/firmware.c
@@ -68,6 +68,10 @@
#define DEFAULT_FW_SBUS_NAME "hfi1_sbus.fw"
#define DEFAULT_FW_PCIE_NAME "hfi1_pcie.fw"
#define DEFAULT_PLATFORM_CONFIG_NAME "hfi1_platform.dat"
+#define ALT_FW_8051_NAME_ASIC "hfi1_dc8051_d.fw"
+#define ALT_FW_FABRIC_NAME "hfi1_fabric_d.fw"
+#define ALT_FW_SBUS_NAME "hfi1_sbus_d.fw"
+#define ALT_FW_PCIE_NAME "hfi1_pcie_d.fw"
static uint fw_8051_load = 1;
static uint fw_fabric_serdes_load = 1;
@@ -158,7 +162,8 @@ struct firmware_details {
static DEFINE_MUTEX(fw_mutex);
enum fw_state {
FW_EMPTY,
- FW_ACQUIRED,
+ FW_TRY,
+ FW_FINAL,
FW_ERR
};
static enum fw_state fw_state = FW_EMPTY;
@@ -428,8 +433,8 @@ static int obtain_one_firmware(struct hfi1_devdata *dd, const char *name,
ret = request_firmware(&fdet->fw, name, &dd->pcidev->dev);
if (ret) {
- dd_dev_err(dd, "cannot load firmware \"%s\", err %d\n",
- name, ret);
+ dd_dev_err(dd, "cannot find firmware \"%s\", err %d\n",
+ name, ret);
return ret;
}
@@ -539,28 +544,53 @@ done:
static void dispose_one_firmware(struct firmware_details *fdet)
{
release_firmware(fdet->fw);
- fdet->fw = NULL;
+ /* erase all previous information */
+ memset(fdet, 0, sizeof(*fdet));
}
/*
- * Called by all HFIs when loading their firmware - i.e. device probe time.
- * The first one will do the actual firmware load. Use a mutex to resolve
- * any possible race condition.
+ * Obtain the 4 firmwares from the OS. All must be obtained at once or not
+ * at all. If called with the firmware state in FW_TRY, use alternate names.
+ * On exit, this routine will have set the firmware state to one of FW_TRY,
+ * FW_FINAL, or FW_ERR.
*
- * The call to this routine cannot be moved to driver load because the kernel
- * call request_firmware() requires a device which is only available after
- * the first device probe.
+ * Must be holding fw_mutex.
*/
-static int obtain_firmware(struct hfi1_devdata *dd)
+static void __obtain_firmware(struct hfi1_devdata *dd)
{
int err = 0;
- mutex_lock(&fw_mutex);
- if (fw_state == FW_ACQUIRED) {
- goto done; /* already acquired */
- } else if (fw_state == FW_ERR) {
- err = fw_err;
- goto done; /* already tried and failed */
+ if (fw_state == FW_FINAL) /* nothing more to obtain */
+ return;
+ if (fw_state == FW_ERR) /* already in error */
+ return;
+
+ /* fw_state is FW_EMPTY or FW_TRY */
+retry:
+ if (fw_state == FW_TRY) {
+ /*
+ * We tried the original and it failed. Move to the
+ * alternate.
+ */
+ dd_dev_info(dd, "using alternate firmware names\n");
+ /*
+ * Let others run. Some systems, when missing firmware, does
+ * something that holds for 30 seconds. If we do that twice
+ * in a row it triggers task blocked warning.
+ */
+ cond_resched();
+ if (fw_8051_load)
+ dispose_one_firmware(&fw_8051);
+ if (fw_fabric_serdes_load)
+ dispose_one_firmware(&fw_fabric);
+ if (fw_sbus_load)
+ dispose_one_firmware(&fw_sbus);
+ if (fw_pcie_serdes_load)
+ dispose_one_firmware(&fw_pcie);
+ fw_8051_name = ALT_FW_8051_NAME_ASIC;
+ fw_fabric_serdes_name = ALT_FW_FABRIC_NAME;
+ fw_sbus_name = ALT_FW_SBUS_NAME;
+ fw_pcie_serdes_name = ALT_FW_PCIE_NAME;
}
if (fw_8051_load) {
@@ -588,27 +618,82 @@ static int obtain_firmware(struct hfi1_devdata *dd)
goto done;
}
+done:
+ if (err) {
+ /* oops, had problems obtaining a firmware */
+ if (fw_state == FW_EMPTY) {
+ /* retry with alternate */
+ fw_state = FW_TRY;
+ goto retry;
+ }
+ fw_state = FW_ERR;
+ fw_err = -ENOENT;
+ } else {
+ /* success */
+ if (fw_state == FW_EMPTY)
+ fw_state = FW_TRY; /* may retry later */
+ else
+ fw_state = FW_FINAL; /* cannot try again */
+ }
+}
+
+/*
+ * Called by all HFIs when loading their firmware - i.e. device probe time.
+ * The first one will do the actual firmware load. Use a mutex to resolve
+ * any possible race condition.
+ *
+ * The call to this routine cannot be moved to driver load because the kernel
+ * call request_firmware() requires a device which is only available after
+ * the first device probe.
+ */
+static int obtain_firmware(struct hfi1_devdata *dd)
+{
+ unsigned long timeout;
+ int err = 0;
+
+ mutex_lock(&fw_mutex);
+
+ /* 40s delay due to long delay on missing firmware on some systems */
+ timeout = jiffies + msecs_to_jiffies(40000);
+ while (fw_state == FW_TRY) {
+ /*
+ * Another device is trying the firmware. Wait until it
+ * decides what works (or not).
+ */
+ if (time_after(jiffies, timeout)) {
+ /* waited too long */
+ dd_dev_err(dd, "Timeout waiting for firmware try");
+ fw_state = FW_ERR;
+ fw_err = -ETIMEDOUT;
+ break;
+ }
+ mutex_unlock(&fw_mutex);
+ msleep(20); /* arbitrary delay */
+ mutex_lock(&fw_mutex);
+ }
+ /* not in FW_TRY state */
+
+ if (fw_state == FW_FINAL)
+ goto done; /* already acquired */
+ else if (fw_state == FW_ERR)
+ goto done; /* already tried and failed */
+ /* fw_state is FW_EMPTY */
+
+ /* set fw_state to FW_TRY, FW_FINAL, or FW_ERR, and fw_err */
+ __obtain_firmware(dd);
+
if (platform_config_load) {
platform_config = NULL;
err = request_firmware(&platform_config, platform_config_name,
&dd->pcidev->dev);
- if (err) {
- err = 0;
+ if (err)
platform_config = NULL;
- }
}
- /* success */
- fw_state = FW_ACQUIRED;
-
done:
- if (err) {
- fw_err = err;
- fw_state = FW_ERR;
- }
mutex_unlock(&fw_mutex);
- return err;
+ return fw_err;
}
/*
@@ -638,6 +723,38 @@ void dispose_firmware(void)
}
/*
+ * Called with the result of a firmware download.
+ *
+ * Return 1 to retry loading the firmware, 0 to stop.
+ */
+static int retry_firmware(struct hfi1_devdata *dd, int load_result)
+{
+ int retry;
+
+ mutex_lock(&fw_mutex);
+
+ if (load_result == 0) {
+ /*
+ * The load succeeded, so expect all others to do the same.
+ * Do not retry again.
+ */
+ if (fw_state == FW_TRY)
+ fw_state = FW_FINAL;
+ retry = 0; /* do NOT retry */
+ } else if (fw_state == FW_TRY) {
+ /* load failed, obtain alternate firmware */
+ __obtain_firmware(dd);
+ retry = (fw_state == FW_FINAL);
+ } else {
+ /* else in FW_FINAL or FW_ERR, no retry in either case */
+ retry = 0;
+ }
+
+ mutex_unlock(&fw_mutex);
+ return retry;
+}
+
+/*
* Write a block of data to a given array CSR. All calls will be in
* multiples of 8 bytes.
*/
@@ -951,7 +1068,7 @@ void sbus_request(struct hfi1_devdata *dd,
static void turn_off_spicos(struct hfi1_devdata *dd, int flags)
{
/* only needed on A0 */
- if (!is_a0(dd))
+ if (!is_ax(dd))
return;
dd_dev_info(dd, "Turning off spicos:%s%s\n",
@@ -1248,7 +1365,9 @@ int load_firmware(struct hfi1_devdata *dd)
fabric_serdes_addrs[dd->hfi1_id],
NUM_FABRIC_SERDES);
turn_off_spicos(dd, SPICO_FABRIC);
- ret = load_fabric_serdes_firmware(dd, &fw_fabric);
+ do {
+ ret = load_fabric_serdes_firmware(dd, &fw_fabric);
+ } while (retry_firmware(dd, ret));
clear_sbus_fast_mode(dd);
release_hw_mutex(dd);
@@ -1257,7 +1376,9 @@ int load_firmware(struct hfi1_devdata *dd)
}
if (fw_8051_load) {
- ret = load_8051_firmware(dd, &fw_8051);
+ do {
+ ret = load_8051_firmware(dd, &fw_8051);
+ } while (retry_firmware(dd, ret));
if (ret)
return ret;
}
@@ -1568,9 +1689,11 @@ int load_pcie_firmware(struct hfi1_devdata *dd)
/* both firmware loads below use the SBus */
set_sbus_fast_mode(dd);
- if (fw_sbus_load && (dd->flags & HFI1_DO_INIT_ASIC)) {
+ if (fw_sbus_load) {
turn_off_spicos(dd, SPICO_SBUS);
- ret = load_sbus_firmware(dd, &fw_sbus);
+ do {
+ ret = load_sbus_firmware(dd, &fw_sbus);
+ } while (retry_firmware(dd, ret));
if (ret)
goto done;
}
@@ -1581,7 +1704,9 @@ int load_pcie_firmware(struct hfi1_devdata *dd)
pcie_serdes_broadcast[dd->hfi1_id],
pcie_serdes_addrs[dd->hfi1_id],
NUM_PCIE_SERDES);
- ret = load_pcie_serdes_firmware(dd, &fw_pcie);
+ do {
+ ret = load_pcie_serdes_firmware(dd, &fw_pcie);
+ } while (retry_firmware(dd, ret));
if (ret)
goto done;
}
diff --git a/drivers/staging/rdma/hfi1/hfi.h b/drivers/staging/rdma/hfi1/hfi.h
index 190f7a2f6773..2611bb2e764d 100644
--- a/drivers/staging/rdma/hfi1/hfi.h
+++ b/drivers/staging/rdma/hfi1/hfi.h
@@ -100,6 +100,26 @@ extern unsigned long hfi1_cap_mask;
HFI1_CAP_MISC_MASK)
/*
+ * Control context is always 0 and handles the error packets.
+ * It also handles the VL15 and multicast packets.
+ */
+#define HFI1_CTRL_CTXT 0
+
+/*
+ * Driver context will store software counters for each of the events
+ * associated with these status registers
+ */
+#define NUM_CCE_ERR_STATUS_COUNTERS 41
+#define NUM_RCV_ERR_STATUS_COUNTERS 64
+#define NUM_MISC_ERR_STATUS_COUNTERS 13
+#define NUM_SEND_PIO_ERR_STATUS_COUNTERS 36
+#define NUM_SEND_DMA_ERR_STATUS_COUNTERS 4
+#define NUM_SEND_EGRESS_ERR_STATUS_COUNTERS 64
+#define NUM_SEND_ERR_STATUS_COUNTERS 3
+#define NUM_SEND_CTXT_ERR_STATUS_COUNTERS 5
+#define NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS 24
+
+/*
* per driver stats, either not device nor port-specific, or
* summed over all of the devices and ports.
* They are described by name via ipathfs filesystem, so layout
@@ -139,15 +159,6 @@ extern const struct pci_error_handlers hfi1_pci_err_handler;
struct hfi1_opcode_stats_perctx;
#endif
-/*
- * struct ps_state keeps state associated with RX queue "prescanning"
- * (prescanning for FECNs, and BECNs), if prescanning is in use.
- */
-struct ps_state {
- u32 ps_head;
- int initialized;
-};
-
struct ctxt_eager_bufs {
ssize_t size; /* total size of eager buffers */
u32 count; /* size of buffers array */
@@ -243,7 +254,7 @@ struct hfi1_ctxtdata {
/* chip offset of PIO buffers for this ctxt */
u32 piobufs;
/* per-context configuration flags */
- u16 flags;
+ u32 flags;
/* per-context event flags for fileops/intr communication */
unsigned long event_flags;
/* WAIT_RCV that timed out, no interrupt */
@@ -302,10 +313,6 @@ struct hfi1_ctxtdata {
struct list_head sdma_queues;
spinlock_t sdma_qlock;
-#ifdef CONFIG_PRESCAN_RXQ
- struct ps_state ps_state;
-#endif /* CONFIG_PRESCAN_RXQ */
-
/*
* The interrupt handler for a particular receive context can vary
* throughout it's lifetime. This is not a lock protected data member so
@@ -706,6 +713,8 @@ struct hfi1_pportdata {
u64 link_downed;
/* number of times link retrained successfully */
u64 link_up;
+ /* number of times a link unknown frame was reported */
+ u64 unknown_frame_count;
/* port_ltp_crc_mode is returned in 'portinfo' MADs */
u16 port_ltp_crc_mode;
/* port_crc_mode_enabled is the crc we support */
@@ -1053,6 +1062,26 @@ struct hfi1_devdata {
atomic_t drop_packet;
u8 do_drop;
+ /*
+ * Software counters for the status bits defined by the
+ * associated error status registers
+ */
+ u64 cce_err_status_cnt[NUM_CCE_ERR_STATUS_COUNTERS];
+ u64 rcv_err_status_cnt[NUM_RCV_ERR_STATUS_COUNTERS];
+ u64 misc_err_status_cnt[NUM_MISC_ERR_STATUS_COUNTERS];
+ u64 send_pio_err_status_cnt[NUM_SEND_PIO_ERR_STATUS_COUNTERS];
+ u64 send_dma_err_status_cnt[NUM_SEND_DMA_ERR_STATUS_COUNTERS];
+ u64 send_egress_err_status_cnt[NUM_SEND_EGRESS_ERR_STATUS_COUNTERS];
+ u64 send_err_status_cnt[NUM_SEND_ERR_STATUS_COUNTERS];
+
+ /* Software counter that spans all contexts */
+ u64 sw_ctxt_err_status_cnt[NUM_SEND_CTXT_ERR_STATUS_COUNTERS];
+ /* Software counter that spans all DMA engines */
+ u64 sw_send_dma_eng_err_status_cnt[
+ NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS];
+ /* Software counter that aggregates all cce_err_status errors */
+ u64 sw_cce_err_status_aggregate;
+
/* receive interrupt functions */
rhf_rcv_function_ptr *rhf_rcv_function_map;
rhf_rcv_function_ptr normal_rhf_rcv_functions[8];
@@ -1061,12 +1090,10 @@ struct hfi1_devdata {
* Handlers for outgoing data so that snoop/capture does not
* have to have its hooks in the send path
*/
- int (*process_pio_send)(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr,
- u32 hdrwords, struct hfi1_sge_state *ss,
- u32 len, u32 plen, u32 dwords, u64 pbc);
- int (*process_dma_send)(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr,
- u32 hdrwords, struct hfi1_sge_state *ss,
- u32 len, u32 plen, u32 dwords, u64 pbc);
+ int (*process_pio_send)(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc);
+ int (*process_dma_send)(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc);
void (*pio_inline_send)(struct hfi1_devdata *dd, struct pio_buf *pbuf,
u64 pbc, const void *from, size_t count);
@@ -1084,6 +1111,10 @@ struct hfi1_devdata {
/* Save the enabled LCB error bits */
u64 lcb_err_en;
u8 dc_shutdown;
+
+ /* receive context tail dummy address */
+ __le64 *rcvhdrtail_dummy_kvaddr;
+ dma_addr_t rcvhdrtail_dummy_physaddr;
};
/* 8051 firmware version helper */
@@ -1414,27 +1445,13 @@ void reset_link_credits(struct hfi1_devdata *dd);
void assign_remote_cm_au_table(struct hfi1_devdata *dd, u8 vcu);
int snoop_recv_handler(struct hfi1_packet *packet);
-int snoop_send_dma_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc);
-int snoop_send_pio_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc);
+int snoop_send_dma_handler(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc);
+int snoop_send_pio_handler(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc);
void snoop_inline_pio_send(struct hfi1_devdata *dd, struct pio_buf *pbuf,
u64 pbc, const void *from, size_t count);
-/* for use in system calls, where we want to know device type, etc. */
-#define ctxt_fp(fp) \
- (((struct hfi1_filedata *)(fp)->private_data)->uctxt)
-#define subctxt_fp(fp) \
- (((struct hfi1_filedata *)(fp)->private_data)->subctxt)
-#define tidcursor_fp(fp) \
- (((struct hfi1_filedata *)(fp)->private_data)->tidcursor)
-#define user_sdma_pkt_fp(fp) \
- (((struct hfi1_filedata *)(fp)->private_data)->pq)
-#define user_sdma_comp_fp(fp) \
- (((struct hfi1_filedata *)(fp)->private_data)->cq)
-
static inline struct hfi1_devdata *dd_from_ppd(struct hfi1_pportdata *ppd)
{
return ppd->dd;
@@ -1570,8 +1587,8 @@ void hfi1_set_led_override(struct hfi1_pportdata *ppd, unsigned int val);
*/
#define DEFAULT_RCVHDR_ENTSIZE 32
-int hfi1_get_user_pages(unsigned long, size_t, struct page **);
-void hfi1_release_user_pages(struct page **, size_t);
+int hfi1_acquire_user_pages(unsigned long, size_t, bool, struct page **);
+void hfi1_release_user_pages(struct page **, size_t, bool);
static inline void clear_rcvhdrtail(const struct hfi1_ctxtdata *rcd)
{
@@ -1612,7 +1629,6 @@ void hfi1_pcie_flr(struct hfi1_devdata *);
int pcie_speeds(struct hfi1_devdata *);
void request_msix(struct hfi1_devdata *, u32 *, struct hfi1_msix_entry *);
void hfi1_enable_intx(struct pci_dev *);
-void hfi1_nomsix(struct hfi1_devdata *);
void restore_pci_variables(struct hfi1_devdata *dd);
int do_pcie_gen3_transition(struct hfi1_devdata *dd);
int parse_platform_config(struct hfi1_devdata *dd);
@@ -1649,7 +1665,7 @@ void update_sge(struct hfi1_sge_state *ss, u32 length);
extern unsigned int hfi1_max_mtu;
extern unsigned int hfi1_cu;
extern unsigned int user_credit_return_threshold;
-extern uint num_rcv_contexts;
+extern int num_user_contexts;
extern unsigned n_krcvqs;
extern u8 krcvqs[];
extern int krcvqsset;
@@ -1713,7 +1729,7 @@ static inline u64 hfi1_pkt_default_send_ctxt_mask(struct hfi1_devdata *dd,
else
base_sc_integrity |= HFI1_PKT_KERNEL_SC_INTEGRITY;
- if (is_a0(dd))
+ if (is_ax(dd))
/* turn off send-side job key checks - A0 erratum */
return base_sc_integrity &
~SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
@@ -1740,7 +1756,7 @@ static inline u64 hfi1_pkt_base_sdma_integrity(struct hfi1_devdata *dd)
| SEND_DMA_CHECK_ENABLE_CHECK_VL_SMASK
| SEND_DMA_CHECK_ENABLE_CHECK_ENABLE_SMASK;
- if (is_a0(dd))
+ if (is_ax(dd))
/* turn off send-side job key checks - A0 erratum */
return base_sdma_integrity &
~SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
diff --git a/drivers/staging/rdma/hfi1/init.c b/drivers/staging/rdma/hfi1/init.c
index 8666f3ad24e9..4dd8051aba7e 100644
--- a/drivers/staging/rdma/hfi1/init.c
+++ b/drivers/staging/rdma/hfi1/init.c
@@ -60,6 +60,7 @@
#include "hfi.h"
#include "device.h"
#include "common.h"
+#include "trace.h"
#include "mad.h"
#include "sdma.h"
#include "debugfs.h"
@@ -81,15 +82,15 @@
* Number of user receive contexts we are configured to use (to allow for more
* pio buffers per ctxt, etc.) Zero means use one user context per CPU.
*/
-uint num_rcv_contexts;
-module_param_named(num_rcv_contexts, num_rcv_contexts, uint, S_IRUGO);
+int num_user_contexts = -1;
+module_param_named(num_user_contexts, num_user_contexts, uint, S_IRUGO);
MODULE_PARM_DESC(
- num_rcv_contexts, "Set max number of user receive contexts to use");
+ num_user_contexts, "Set max number of user contexts to use");
u8 krcvqs[RXE_NUM_DATA_VL];
int krcvqsset;
module_param_array(krcvqs, byte, &krcvqsset, S_IRUGO);
-MODULE_PARM_DESC(krcvqs, "Array of the number of kernel receive queues by VL");
+MODULE_PARM_DESC(krcvqs, "Array of the number of non-control kernel receive queues by VL");
/* computed based on above array */
unsigned n_krcvqs;
@@ -112,7 +113,7 @@ MODULE_PARM_DESC(hdrq_entsize, "Size of header queue entries: 2 - 8B, 16 - 64B (
unsigned int user_credit_return_threshold = 33; /* default is 33% */
module_param(user_credit_return_threshold, uint, S_IRUGO);
-MODULE_PARM_DESC(user_credit_return_theshold, "Credit return threshold for user send contexts, return when unreturned credits passes this many blocks (in percent of allocated blocks, 0 is off)");
+MODULE_PARM_DESC(user_credit_return_threshold, "Credit return threshold for user send contexts, return when unreturned credits passes this many blocks (in percent of allocated blocks, 0 is off)");
static inline u64 encode_rcv_header_entry_size(u16);
@@ -129,6 +130,9 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
int ret;
int local_node_id = pcibus_to_node(dd->pcidev->bus);
+ /* Control context has to be always 0 */
+ BUILD_BUG_ON(HFI1_CTRL_CTXT != 0);
+
if (local_node_id < 0)
local_node_id = numa_node_id();
dd->assigned_node_id = local_node_id;
@@ -158,6 +162,10 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
HFI1_CAP_KGET(NODROP_RHQ_FULL) |
HFI1_CAP_KGET(NODROP_EGR_FULL) |
HFI1_CAP_KGET(DMA_RTAIL);
+
+ /* Control context must use DMA_RTAIL */
+ if (rcd->ctxt == HFI1_CTRL_CTXT)
+ rcd->flags |= HFI1_CAP_DMA_RTAIL;
rcd->seq_cnt = 1;
rcd->sc = sc_alloc(dd, SC_ACK, rcd->rcvhdrqentsize, dd->node);
@@ -208,7 +216,7 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt)
if (rcd) {
u32 rcvtids, max_entries;
- dd_dev_info(dd, "%s: setting up context %u\n", __func__, ctxt);
+ hfi1_cdbg(PROC, "setting up context %u\n", ctxt);
INIT_LIST_HEAD(&rcd->qp_wait_list);
rcd->ppd = ppd;
@@ -279,8 +287,9 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt)
rcd->ctxt);
rcd->egrbufs.count = MAX_EAGER_ENTRIES;
}
- dd_dev_info(dd, "ctxt%u: max Eager buffer RcvArray entries: %u\n",
- rcd->ctxt, rcd->egrbufs.count);
+ hfi1_cdbg(PROC,
+ "ctxt%u: max Eager buffer RcvArray entries: %u\n",
+ rcd->ctxt, rcd->egrbufs.count);
/*
* Allocate array that will hold the eager buffer accounting
@@ -308,8 +317,8 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt)
*/
if (rcd->egrbufs.size < hfi1_max_mtu) {
rcd->egrbufs.size = __roundup_pow_of_two(hfi1_max_mtu);
- dd_dev_info(dd,
- "ctxt%u: eager bufs size too small. Adjusting to %zu\n",
+ hfi1_cdbg(PROC,
+ "ctxt%u: eager bufs size too small. Adjusting to %zu\n",
rcd->ctxt, rcd->egrbufs.size);
}
rcd->egrbufs.rcvtid_size = HFI1_MAX_EAGER_BUFFER_SIZE;
@@ -601,20 +610,19 @@ static int create_workqueues(struct hfi1_devdata *dd)
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
ppd = dd->pport + pidx;
if (!ppd->hfi1_wq) {
- char wq_name[8]; /* 3 + 2 + 1 + 1 + 1 */
-
- snprintf(wq_name, sizeof(wq_name), "hfi%d_%d",
- dd->unit, pidx);
ppd->hfi1_wq =
- create_singlethread_workqueue(wq_name);
+ alloc_workqueue(
+ "hfi%d_%d",
+ WQ_SYSFS | WQ_HIGHPRI | WQ_CPU_INTENSIVE,
+ dd->num_sdma,
+ dd->unit, pidx);
if (!ppd->hfi1_wq)
goto wq_error;
}
}
return 0;
wq_error:
- pr_err("create_singlethread_workqueue failed for port %d\n",
- pidx + 1);
+ pr_err("alloc_workqueue failed for port %d\n", pidx + 1);
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
ppd = dd->pport + pidx;
if (ppd->hfi1_wq) {
@@ -670,7 +678,7 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
dd->process_dma_send = hfi1_verbs_send_dma;
dd->pio_inline_send = pio_copy;
- if (is_a0(dd)) {
+ if (is_ax(dd)) {
atomic_set(&dd->drop_packet, DROP_PACKET_ON);
dd->do_drop = 1;
} else {
@@ -691,6 +699,18 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
if (ret)
goto done;
+ /* allocate dummy tail memory for all receive contexts */
+ dd->rcvhdrtail_dummy_kvaddr = dma_zalloc_coherent(
+ &dd->pcidev->dev, sizeof(u64),
+ &dd->rcvhdrtail_dummy_physaddr,
+ GFP_KERNEL);
+
+ if (!dd->rcvhdrtail_dummy_kvaddr) {
+ dd_dev_err(dd, "cannot allocate dummy tail memory\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
/* dd->rcd can be NULL if early initialization failed */
for (i = 0; dd->rcd && i < dd->first_user_ctxt; ++i) {
/*
@@ -1266,6 +1286,14 @@ static void cleanup_device_data(struct hfi1_devdata *dd)
tmp = dd->rcd;
dd->rcd = NULL;
spin_unlock_irqrestore(&dd->uctxt_lock, flags);
+
+ if (dd->rcvhdrtail_dummy_kvaddr) {
+ dma_free_coherent(&dd->pcidev->dev, sizeof(u64),
+ (void *)dd->rcvhdrtail_dummy_kvaddr,
+ dd->rcvhdrtail_dummy_physaddr);
+ dd->rcvhdrtail_dummy_kvaddr = NULL;
+ }
+
for (ctxt = 0; tmp && ctxt < dd->num_rcv_contexts; ctxt++) {
struct hfi1_ctxtdata *rcd = tmp[ctxt];
@@ -1308,6 +1336,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret = 0, j, pidx, initfail;
struct hfi1_devdata *dd = NULL;
+ struct hfi1_pportdata *ppd;
/* First, lock the non-writable module parameters */
HFI1_CAP_LOCK();
@@ -1322,6 +1351,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) {
hfi1_early_err(&pdev->dev, "Invalid HdrQ Entry size %u\n",
hfi1_hdrq_entsize);
+ ret = -EINVAL;
goto bail;
}
@@ -1403,8 +1433,14 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (initfail || ret) {
stop_timers(dd);
flush_workqueue(ib_wq);
- for (pidx = 0; pidx < dd->num_pports; ++pidx)
+ for (pidx = 0; pidx < dd->num_pports; ++pidx) {
hfi1_quiet_serdes(dd->pport + pidx);
+ ppd = dd->pport + pidx;
+ if (ppd->hfi1_wq) {
+ destroy_workqueue(ppd->hfi1_wq);
+ ppd->hfi1_wq = NULL;
+ }
+ }
if (!j)
hfi1_device_remove(dd);
if (!ret)
@@ -1521,6 +1557,14 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
reg = (dd->rcvhdrsize & RCV_HDR_SIZE_HDR_SIZE_MASK)
<< RCV_HDR_SIZE_HDR_SIZE_SHIFT;
write_kctxt_csr(dd, rcd->ctxt, RCV_HDR_SIZE, reg);
+
+ /*
+ * Program dummy tail address for every receive context
+ * before enabling any receive context
+ */
+ write_kctxt_csr(dd, rcd->ctxt, RCV_HDR_TAIL_ADDR,
+ dd->rcvhdrtail_dummy_physaddr);
+
return 0;
bail_free:
@@ -1660,9 +1704,11 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
rcd->egrbufs.numbufs = idx;
rcd->egrbufs.size = alloced_bytes;
- dd_dev_info(dd, "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %zuKB\n",
- rcd->ctxt, rcd->egrbufs.alloced, rcd->egrbufs.rcvtid_size,
- rcd->egrbufs.size);
+ hfi1_cdbg(PROC,
+ "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %zuKB\n",
+ rcd->ctxt, rcd->egrbufs.alloced, rcd->egrbufs.rcvtid_size,
+ rcd->egrbufs.size);
+
/*
* Set the contexts rcv array head update threshold to the closest
@@ -1683,13 +1729,14 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
rcd->expected_count = MAX_TID_PAIR_ENTRIES * 2;
rcd->expected_base = rcd->eager_base + egrtop;
- dd_dev_info(dd, "ctxt%u: eager:%u, exp:%u, egrbase:%u, expbase:%u\n",
- rcd->ctxt, rcd->egrbufs.alloced, rcd->expected_count,
- rcd->eager_base, rcd->expected_base);
+ hfi1_cdbg(PROC, "ctxt%u: eager:%u, exp:%u, egrbase:%u, expbase:%u\n",
+ rcd->ctxt, rcd->egrbufs.alloced, rcd->expected_count,
+ rcd->eager_base, rcd->expected_base);
if (!hfi1_rcvbuf_validate(rcd->egrbufs.rcvtid_size, PT_EAGER, &order)) {
- dd_dev_err(dd, "ctxt%u: current Eager buffer size is invalid %u\n",
- rcd->ctxt, rcd->egrbufs.rcvtid_size);
+ hfi1_cdbg(PROC,
+ "ctxt%u: current Eager buffer size is invalid %u\n",
+ rcd->ctxt, rcd->egrbufs.rcvtid_size);
ret = -EINVAL;
goto bail;
}
diff --git a/drivers/staging/rdma/hfi1/iowait.h b/drivers/staging/rdma/hfi1/iowait.h
index fa361b405851..e8ba5606d08d 100644
--- a/drivers/staging/rdma/hfi1/iowait.h
+++ b/drivers/staging/rdma/hfi1/iowait.h
@@ -150,12 +150,14 @@ static inline void iowait_init(
* iowait_schedule() - initialize wait structure
* @wait: wait struct to schedule
* @wq: workqueue for schedule
+ * @cpu: cpu
*/
static inline void iowait_schedule(
struct iowait *wait,
- struct workqueue_struct *wq)
+ struct workqueue_struct *wq,
+ int cpu)
{
- queue_work(wq, &wait->iowork);
+ queue_work_on(cpu, wq, &wait->iowork);
}
/**
diff --git a/drivers/staging/rdma/hfi1/mad.c b/drivers/staging/rdma/hfi1/mad.c
index 32f703736185..4f5dbd14b5de 100644
--- a/drivers/staging/rdma/hfi1/mad.c
+++ b/drivers/staging/rdma/hfi1/mad.c
@@ -84,7 +84,7 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len)
{
struct ib_mad_send_buf *send_buf;
struct ib_mad_agent *agent;
- struct ib_smp *smp;
+ struct opa_smp *smp;
int ret;
unsigned long flags;
unsigned long timeout;
@@ -117,15 +117,15 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len)
return;
smp = send_buf->mad;
- smp->base_version = IB_MGMT_BASE_VERSION;
+ smp->base_version = OPA_MGMT_BASE_VERSION;
smp->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- smp->class_version = 1;
+ smp->class_version = OPA_SMI_CLASS_VERSION;
smp->method = IB_MGMT_METHOD_TRAP;
ibp->tid++;
smp->tid = cpu_to_be64(ibp->tid);
smp->attr_id = IB_SMP_ATTR_NOTICE;
/* o14-1: smp->mkey = 0; */
- memcpy(smp->data, data, len);
+ memcpy(smp->route.lid.data, data, len);
spin_lock_irqsave(&ibp->lock, flags);
if (!ibp->sm_ah) {
@@ -164,11 +164,16 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len)
* Send a bad [PQ]_Key trap (ch. 14.3.8).
*/
void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
- u32 qp1, u32 qp2, __be16 lid1, __be16 lid2)
+ u32 qp1, u32 qp2, u16 lid1, u16 lid2)
{
- struct ib_mad_notice_attr data;
+ struct opa_mad_notice_attr data;
+ u32 lid = ppd_from_ibp(ibp)->lid;
+ u32 _lid1 = lid1;
+ u32 _lid2 = lid2;
- if (trap_num == IB_NOTICE_TRAP_BAD_PKEY)
+ memset(&data, 0, sizeof(data));
+
+ if (trap_num == OPA_TRAP_BAD_P_KEY)
ibp->pkey_violations++;
else
ibp->qkey_violations++;
@@ -176,17 +181,15 @@ void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
/* Send violation trap */
data.generic_type = IB_NOTICE_TYPE_SECURITY;
- data.prod_type_msb = 0;
data.prod_type_lsb = IB_NOTICE_PROD_CA;
data.trap_num = trap_num;
- data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
- data.toggle_count = 0;
- memset(&data.details, 0, sizeof(data.details));
- data.details.ntc_257_258.lid1 = lid1;
- data.details.ntc_257_258.lid2 = lid2;
- data.details.ntc_257_258.key = cpu_to_be32(key);
- data.details.ntc_257_258.sl_qp1 = cpu_to_be32((sl << 28) | qp1);
- data.details.ntc_257_258.qp2 = cpu_to_be32(qp2);
+ data.issuer_lid = cpu_to_be32(lid);
+ data.ntc_257_258.lid1 = cpu_to_be32(_lid1);
+ data.ntc_257_258.lid2 = cpu_to_be32(_lid2);
+ data.ntc_257_258.key = cpu_to_be32(key);
+ data.ntc_257_258.sl = sl << 3;
+ data.ntc_257_258.qp1 = cpu_to_be32(qp1);
+ data.ntc_257_258.qp2 = cpu_to_be32(qp2);
send_trap(ibp, &data, sizeof(data));
}
@@ -197,32 +200,30 @@ void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
static void bad_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad,
__be64 mkey, __be32 dr_slid, u8 return_path[], u8 hop_cnt)
{
- struct ib_mad_notice_attr data;
+ struct opa_mad_notice_attr data;
+ u32 lid = ppd_from_ibp(ibp)->lid;
+ memset(&data, 0, sizeof(data));
/* Send violation trap */
data.generic_type = IB_NOTICE_TYPE_SECURITY;
- data.prod_type_msb = 0;
data.prod_type_lsb = IB_NOTICE_PROD_CA;
- data.trap_num = IB_NOTICE_TRAP_BAD_MKEY;
- data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
- data.toggle_count = 0;
- memset(&data.details, 0, sizeof(data.details));
- data.details.ntc_256.lid = data.issuer_lid;
- data.details.ntc_256.method = mad->method;
- data.details.ntc_256.attr_id = mad->attr_id;
- data.details.ntc_256.attr_mod = mad->attr_mod;
- data.details.ntc_256.mkey = mkey;
+ data.trap_num = OPA_TRAP_BAD_M_KEY;
+ data.issuer_lid = cpu_to_be32(lid);
+ data.ntc_256.lid = data.issuer_lid;
+ data.ntc_256.method = mad->method;
+ data.ntc_256.attr_id = mad->attr_id;
+ data.ntc_256.attr_mod = mad->attr_mod;
+ data.ntc_256.mkey = mkey;
if (mad->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
-
- data.details.ntc_256.dr_slid = (__force __be16)dr_slid;
- data.details.ntc_256.dr_trunc_hop = IB_NOTICE_TRAP_DR_NOTICE;
- if (hop_cnt > ARRAY_SIZE(data.details.ntc_256.dr_rtn_path)) {
- data.details.ntc_256.dr_trunc_hop |=
+ data.ntc_256.dr_slid = dr_slid;
+ data.ntc_256.dr_trunc_hop = IB_NOTICE_TRAP_DR_NOTICE;
+ if (hop_cnt > ARRAY_SIZE(data.ntc_256.dr_rtn_path)) {
+ data.ntc_256.dr_trunc_hop |=
IB_NOTICE_TRAP_DR_TRUNC;
- hop_cnt = ARRAY_SIZE(data.details.ntc_256.dr_rtn_path);
+ hop_cnt = ARRAY_SIZE(data.ntc_256.dr_rtn_path);
}
- data.details.ntc_256.dr_trunc_hop |= hop_cnt;
- memcpy(data.details.ntc_256.dr_rtn_path, return_path,
+ data.ntc_256.dr_trunc_hop |= hop_cnt;
+ memcpy(data.ntc_256.dr_rtn_path, return_path,
hop_cnt);
}
@@ -234,17 +235,17 @@ static void bad_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad,
*/
void hfi1_cap_mask_chg(struct hfi1_ibport *ibp)
{
- struct ib_mad_notice_attr data;
+ struct opa_mad_notice_attr data;
+ u32 lid = ppd_from_ibp(ibp)->lid;
+
+ memset(&data, 0, sizeof(data));
data.generic_type = IB_NOTICE_TYPE_INFO;
- data.prod_type_msb = 0;
data.prod_type_lsb = IB_NOTICE_PROD_CA;
- data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
- data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
- data.toggle_count = 0;
- memset(&data.details, 0, sizeof(data.details));
- data.details.ntc_144.lid = data.issuer_lid;
- data.details.ntc_144.new_cap_mask = cpu_to_be32(ibp->port_cap_flags);
+ data.trap_num = OPA_TRAP_CHANGE_CAPABILITY;
+ data.issuer_lid = cpu_to_be32(lid);
+ data.ntc_144.lid = data.issuer_lid;
+ data.ntc_144.new_cap_mask = cpu_to_be32(ibp->port_cap_flags);
send_trap(ibp, &data, sizeof(data));
}
@@ -254,17 +255,17 @@ void hfi1_cap_mask_chg(struct hfi1_ibport *ibp)
*/
void hfi1_sys_guid_chg(struct hfi1_ibport *ibp)
{
- struct ib_mad_notice_attr data;
+ struct opa_mad_notice_attr data;
+ u32 lid = ppd_from_ibp(ibp)->lid;
+
+ memset(&data, 0, sizeof(data));
data.generic_type = IB_NOTICE_TYPE_INFO;
- data.prod_type_msb = 0;
data.prod_type_lsb = IB_NOTICE_PROD_CA;
- data.trap_num = IB_NOTICE_TRAP_SYS_GUID_CHG;
- data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
- data.toggle_count = 0;
- memset(&data.details, 0, sizeof(data.details));
- data.details.ntc_145.lid = data.issuer_lid;
- data.details.ntc_145.new_sys_guid = ib_hfi1_sys_image_guid;
+ data.trap_num = OPA_TRAP_CHANGE_SYSGUID;
+ data.issuer_lid = cpu_to_be32(lid);
+ data.ntc_145.new_sys_guid = ib_hfi1_sys_image_guid;
+ data.ntc_145.lid = data.issuer_lid;
send_trap(ibp, &data, sizeof(data));
}
@@ -274,18 +275,18 @@ void hfi1_sys_guid_chg(struct hfi1_ibport *ibp)
*/
void hfi1_node_desc_chg(struct hfi1_ibport *ibp)
{
- struct ib_mad_notice_attr data;
+ struct opa_mad_notice_attr data;
+ u32 lid = ppd_from_ibp(ibp)->lid;
+
+ memset(&data, 0, sizeof(data));
data.generic_type = IB_NOTICE_TYPE_INFO;
- data.prod_type_msb = 0;
data.prod_type_lsb = IB_NOTICE_PROD_CA;
- data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
- data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
- data.toggle_count = 0;
- memset(&data.details, 0, sizeof(data.details));
- data.details.ntc_144.lid = data.issuer_lid;
- data.details.ntc_144.local_changes = 1;
- data.details.ntc_144.change_flags = IB_NOTICE_TRAP_NODE_DESC_CHG;
+ data.trap_num = OPA_TRAP_CHANGE_CAPABILITY;
+ data.issuer_lid = cpu_to_be32(lid);
+ data.ntc_144.lid = data.issuer_lid;
+ data.ntc_144.change_flags =
+ cpu_to_be16(OPA_NOTICE_TRAP_NODE_DESC_CHG);
send_trap(ibp, &data, sizeof(data));
}
@@ -2076,13 +2077,20 @@ struct opa_aggregate {
u8 data[0];
};
-/* Request contains first two fields, response contains those plus the rest */
+#define MSK_LLI 0x000000f0
+#define MSK_LLI_SFT 4
+#define MSK_LER 0x0000000f
+#define MSK_LER_SFT 0
+#define ADD_LLI 8
+#define ADD_LER 2
+
+/* Request contains first three fields, response contains those plus the rest */
struct opa_port_data_counters_msg {
__be64 port_select_mask[4];
__be32 vl_select_mask;
+ __be32 resolution;
/* Response fields follow */
- __be32 reserved1;
struct _port_dctrs {
u8 port_number;
u8 reserved2[3];
@@ -2271,34 +2279,8 @@ static void a0_portstatus(struct hfi1_pportdata *ppd,
{
if (!is_bx(ppd->dd)) {
unsigned long vl;
- int vfi = 0;
u64 max_vl_xmit_wait = 0, tmp;
u32 vl_all_mask = VL_MASK_ALL;
- u64 rcv_data, rcv_bubble;
-
- rcv_data = be64_to_cpu(rsp->port_rcv_data);
- rcv_bubble = be64_to_cpu(rsp->port_rcv_bubble);
- /* In the measured time period, calculate the total number
- * of flits that were received. Subtract out one false
- * rcv_bubble increment for every 32 received flits but
- * don't let the number go negative.
- */
- if (rcv_bubble >= (rcv_data>>5)) {
- rcv_bubble -= (rcv_data>>5);
- rsp->port_rcv_bubble = cpu_to_be64(rcv_bubble);
- }
- for_each_set_bit(vl, (unsigned long *)&(vl_select_mask),
- 8 * sizeof(vl_select_mask)) {
- rcv_data = be64_to_cpu(rsp->vls[vfi].port_vl_rcv_data);
- rcv_bubble =
- be64_to_cpu(rsp->vls[vfi].port_vl_rcv_bubble);
- if (rcv_bubble >= (rcv_data>>5)) {
- rcv_bubble -= (rcv_data>>5);
- rsp->vls[vfi].port_vl_rcv_bubble =
- cpu_to_be64(rcv_bubble);
- }
- vfi++;
- }
for_each_set_bit(vl, (unsigned long *)&(vl_all_mask),
8 * sizeof(vl_all_mask)) {
@@ -2363,8 +2345,6 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
CNTR_INVALID_VL));
rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS,
CNTR_INVALID_VL));
- rsp->port_rcv_bubble =
- cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL));
rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS,
CNTR_INVALID_VL));
rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS,
@@ -2434,9 +2414,6 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
tmp = read_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl));
rsp->vls[vfi].port_vl_rcv_data = cpu_to_be64(tmp);
- rsp->vls[vfi].port_vl_rcv_bubble =
- cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL_VL,
- idx_from_vl(vl)));
rsp->vls[vfi].port_vl_rcv_pkts =
cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL,
@@ -2474,7 +2451,8 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
return reply((struct ib_mad_hdr *)pmp);
}
-static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port)
+static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port,
+ u8 res_lli, u8 res_ler)
{
struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
struct hfi1_ibport *ibp = to_iport(ibdev, port);
@@ -2490,14 +2468,14 @@ static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port)
CNTR_INVALID_VL);
error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR,
CNTR_INVALID_VL);
- error_counter_summary += read_dev_cntr(dd, C_DC_TX_REPLAY,
- CNTR_INVALID_VL);
- error_counter_summary += read_dev_cntr(dd, C_DC_RX_REPLAY,
- CNTR_INVALID_VL);
- error_counter_summary += read_dev_cntr(dd, C_DC_SEQ_CRC_CNT,
- CNTR_INVALID_VL);
- error_counter_summary += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT,
- CNTR_INVALID_VL);
+ /* local link integrity must be right-shifted by the lli resolution */
+ tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL);
+ tmp += read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL);
+ error_counter_summary += (tmp >> res_lli);
+ /* link error recovery must b right-shifted by the ler resolution */
+ tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL);
+ tmp += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL);
+ error_counter_summary += (tmp >> res_ler);
error_counter_summary += read_dev_cntr(dd, C_DC_RCV_ERR,
CNTR_INVALID_VL);
error_counter_summary += read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL);
@@ -2519,32 +2497,8 @@ static void a0_datacounters(struct hfi1_devdata *dd, struct _port_dctrs *rsp,
if (!is_bx(dd)) {
unsigned long vl;
int vfi = 0;
- u64 rcv_data, rcv_bubble, sum_vl_xmit_wait = 0;
-
- rcv_data = be64_to_cpu(rsp->port_rcv_data);
- rcv_bubble = be64_to_cpu(rsp->port_rcv_bubble);
- /* In the measured time period, calculate the total number
- * of flits that were received. Subtract out one false
- * rcv_bubble increment for every 32 received flits but
- * don't let the number go negative.
- */
- if (rcv_bubble >= (rcv_data>>5)) {
- rcv_bubble -= (rcv_data>>5);
- rsp->port_rcv_bubble = cpu_to_be64(rcv_bubble);
- }
- for_each_set_bit(vl, (unsigned long *)&(vl_select_mask),
- 8 * sizeof(vl_select_mask)) {
- rcv_data = be64_to_cpu(rsp->vls[vfi].port_vl_rcv_data);
- rcv_bubble =
- be64_to_cpu(rsp->vls[vfi].port_vl_rcv_bubble);
- if (rcv_bubble >= (rcv_data>>5)) {
- rcv_bubble -= (rcv_data>>5);
- rsp->vls[vfi].port_vl_rcv_bubble =
- cpu_to_be64(rcv_bubble);
- }
- vfi++;
- }
- vfi = 0;
+ u64 sum_vl_xmit_wait = 0;
+
for_each_set_bit(vl, (unsigned long *)&(vl_select_mask),
8 * sizeof(vl_select_mask)) {
u64 tmp = sum_vl_xmit_wait +
@@ -2575,6 +2529,7 @@ static int pma_get_opa_datacounters(struct opa_pma_mad *pmp,
u32 num_ports;
u8 num_pslm;
u8 lq, num_vls;
+ u8 res_lli, res_ler;
u64 port_mask;
unsigned long port_num;
unsigned long vl;
@@ -2585,6 +2540,10 @@ static int pma_get_opa_datacounters(struct opa_pma_mad *pmp,
num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3]));
num_vls = hweight32(be32_to_cpu(req->vl_select_mask));
vl_select_mask = be32_to_cpu(req->vl_select_mask);
+ res_lli = (u8)(be32_to_cpu(req->resolution) & MSK_LLI) >> MSK_LLI_SFT;
+ res_lli = res_lli ? res_lli + ADD_LLI : 0;
+ res_ler = (u8)(be32_to_cpu(req->resolution) & MSK_LER) >> MSK_LER_SFT;
+ res_ler = res_ler ? res_ler + ADD_LER : 0;
if (num_ports != 1 || (vl_select_mask & ~VL_MASK_ALL)) {
pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
@@ -2635,8 +2594,6 @@ static int pma_get_opa_datacounters(struct opa_pma_mad *pmp,
CNTR_INVALID_VL));
rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS,
CNTR_INVALID_VL));
- rsp->port_rcv_bubble =
- cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL));
rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS,
CNTR_INVALID_VL));
rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS,
@@ -2655,7 +2612,8 @@ static int pma_get_opa_datacounters(struct opa_pma_mad *pmp,
cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL));
rsp->port_error_counter_summary =
- cpu_to_be64(get_error_counter_summary(ibdev, port));
+ cpu_to_be64(get_error_counter_summary(ibdev, port,
+ res_lli, res_ler));
vlinfo = &(rsp->vls[0]);
vfi = 0;
@@ -2675,9 +2633,6 @@ static int pma_get_opa_datacounters(struct opa_pma_mad *pmp,
rsp->vls[vfi].port_vl_rcv_data =
cpu_to_be64(read_dev_cntr(dd, C_DC_RX_FLIT_VL,
idx_from_vl(vl)));
- rsp->vls[vfi].port_vl_rcv_bubble =
- cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL_VL,
- idx_from_vl(vl)));
rsp->vls[vfi].port_vl_xmit_pkts =
cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL,
@@ -3458,7 +3413,7 @@ static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
u32 nport = OPA_AM_NPORT(am);
u64 reg;
- if (nport != 1 || OPA_AM_PORTNUM(am)) {
+ if (nport != 1) {
smp->status |= IB_SMP_INVALID_FIELD;
return reply((struct ib_mad_hdr *)smp);
}
@@ -3483,7 +3438,7 @@ static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data,
u32 nport = OPA_AM_NPORT(am);
int on = !!(be32_to_cpu(p->rsvd_led_mask) & OPA_LED_MASK);
- if (nport != 1 || OPA_AM_PORTNUM(am)) {
+ if (nport != 1) {
smp->status |= IB_SMP_INVALID_FIELD;
return reply((struct ib_mad_hdr *)smp);
}
diff --git a/drivers/staging/rdma/hfi1/mad.h b/drivers/staging/rdma/hfi1/mad.h
index 47457501c044..f0317750e2fc 100644
--- a/drivers/staging/rdma/hfi1/mad.h
+++ b/drivers/staging/rdma/hfi1/mad.h
@@ -60,7 +60,121 @@
#endif
#include "opa_compat.h"
+/*
+ * OPA Traps
+ */
+#define OPA_TRAP_GID_NOW_IN_SERVICE cpu_to_be16(64)
+#define OPA_TRAP_GID_OUT_OF_SERVICE cpu_to_be16(65)
+#define OPA_TRAP_ADD_MULTICAST_GROUP cpu_to_be16(66)
+#define OPA_TRAL_DEL_MULTICAST_GROUP cpu_to_be16(67)
+#define OPA_TRAP_UNPATH cpu_to_be16(68)
+#define OPA_TRAP_REPATH cpu_to_be16(69)
+#define OPA_TRAP_PORT_CHANGE_STATE cpu_to_be16(128)
+#define OPA_TRAP_LINK_INTEGRITY cpu_to_be16(129)
+#define OPA_TRAP_EXCESSIVE_BUFFER_OVERRUN cpu_to_be16(130)
+#define OPA_TRAP_FLOW_WATCHDOG cpu_to_be16(131)
+#define OPA_TRAP_CHANGE_CAPABILITY cpu_to_be16(144)
+#define OPA_TRAP_CHANGE_SYSGUID cpu_to_be16(145)
+#define OPA_TRAP_BAD_M_KEY cpu_to_be16(256)
+#define OPA_TRAP_BAD_P_KEY cpu_to_be16(257)
+#define OPA_TRAP_BAD_Q_KEY cpu_to_be16(258)
+#define OPA_TRAP_SWITCH_BAD_PKEY cpu_to_be16(259)
+#define OPA_SMA_TRAP_DATA_LINK_WIDTH cpu_to_be16(2048)
+/*
+ * Generic trap/notice other local changes flags (trap 144).
+ */
+#define OPA_NOTICE_TRAP_LWDE_CHG 0x08 /* Link Width Downgrade Enable
+ * changed
+ */
+#define OPA_NOTICE_TRAP_LSE_CHG 0x04 /* Link Speed Enable changed */
+#define OPA_NOTICE_TRAP_LWE_CHG 0x02 /* Link Width Enable changed */
+#define OPA_NOTICE_TRAP_NODE_DESC_CHG 0x01
+
+struct opa_mad_notice_attr {
+ u8 generic_type;
+ u8 prod_type_msb;
+ __be16 prod_type_lsb;
+ __be16 trap_num;
+ __be16 toggle_count;
+ __be32 issuer_lid;
+ __be32 reserved1;
+ union ib_gid issuer_gid;
+
+ union {
+ struct {
+ u8 details[64];
+ } raw_data;
+
+ struct {
+ union ib_gid gid;
+ } __packed ntc_64_65_66_67;
+
+ struct {
+ __be32 lid;
+ } __packed ntc_128;
+
+ struct {
+ __be32 lid; /* where violation happened */
+ u8 port_num; /* where violation happened */
+ } __packed ntc_129_130_131;
+
+ struct {
+ __be32 lid; /* LID where change occurred */
+ __be32 new_cap_mask; /* new capability mask */
+ __be16 reserved2;
+ __be16 cap_mask;
+ __be16 change_flags; /* low 4 bits only */
+ } __packed ntc_144;
+
+ struct {
+ __be64 new_sys_guid;
+ __be32 lid; /* lid where sys guid changed */
+ } __packed ntc_145;
+
+ struct {
+ __be32 lid;
+ __be32 dr_slid;
+ u8 method;
+ u8 dr_trunc_hop;
+ __be16 attr_id;
+ __be32 attr_mod;
+ __be64 mkey;
+ u8 dr_rtn_path[30];
+ } __packed ntc_256;
+
+ struct {
+ __be32 lid1;
+ __be32 lid2;
+ __be32 key;
+ u8 sl; /* SL: high 5 bits */
+ u8 reserved3[3];
+ union ib_gid gid1;
+ union ib_gid gid2;
+ __be32 qp1; /* high 8 bits reserved */
+ __be32 qp2; /* high 8 bits reserved */
+ } __packed ntc_257_258;
+
+ struct {
+ __be16 flags; /* low 8 bits reserved */
+ __be16 pkey;
+ __be32 lid1;
+ __be32 lid2;
+ u8 sl; /* SL: high 5 bits */
+ u8 reserved4[3];
+ union ib_gid gid1;
+ union ib_gid gid2;
+ __be32 qp1; /* high 8 bits reserved */
+ __be32 qp2; /* high 8 bits reserved */
+ } __packed ntc_259;
+
+ struct {
+ __be32 lid;
+ } __packed ntc_2048;
+
+ };
+ u8 class_data[0];
+};
#define IB_VLARB_LOWPRI_0_31 1
#define IB_VLARB_LOWPRI_32_63 2
diff --git a/drivers/staging/rdma/hfi1/pcie.c b/drivers/staging/rdma/hfi1/pcie.c
index a956044459a2..8317b07d722a 100644
--- a/drivers/staging/rdma/hfi1/pcie.c
+++ b/drivers/staging/rdma/hfi1/pcie.c
@@ -426,14 +426,6 @@ void request_msix(struct hfi1_devdata *dd, u32 *nent,
tune_pcie_caps(dd);
}
-/*
- * Disable MSI-X.
- */
-void hfi1_nomsix(struct hfi1_devdata *dd)
-{
- pci_disable_msix(dd->pcidev);
-}
-
void hfi1_enable_intx(struct pci_dev *pdev)
{
/* first, turn on INTx */
@@ -475,8 +467,18 @@ static void tune_pcie_caps(struct hfi1_devdata *dd)
{
struct pci_dev *parent;
u16 rc_mpss, rc_mps, ep_mpss, ep_mps;
- u16 rc_mrrs, ep_mrrs, max_mrrs;
+ u16 rc_mrrs, ep_mrrs, max_mrrs, ectl;
+ /*
+ * Turn on extended tags in DevCtl in case the BIOS has turned it off
+ * to improve WFR SDMA bandwidth
+ */
+ pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL, &ectl);
+ if (!(ectl & PCI_EXP_DEVCTL_EXT_TAG)) {
+ dd_dev_info(dd, "Enabling PCIe extended tags\n");
+ ectl |= PCI_EXP_DEVCTL_EXT_TAG;
+ pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL, ectl);
+ }
/* Find out supported and configured values for parent (root) */
parent = dd->pcidev->bus->self;
if (!pci_is_root_bus(parent->bus)) {
@@ -915,7 +917,7 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
/*
* A0 needs an additional SBR
*/
- if (is_a0(dd))
+ if (is_ax(dd))
nsbr++;
/*
@@ -947,17 +949,7 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
}
retry:
-
- if (therm) {
- /*
- * toggle SPICO_ENABLE to get back to the state
- * just after the firmware load
- */
- sbus_request(dd, SBUS_MASTER_BROADCAST, 0x01,
- WRITE_SBUS_RECEIVER, 0x00000040);
- sbus_request(dd, SBUS_MASTER_BROADCAST, 0x01,
- WRITE_SBUS_RECEIVER, 0x00000140);
- }
+ /* the SBus download will reset the spico for thermal */
/* step 3: download SBus Master firmware */
/* step 4: download PCIe Gen3 SerDes firmware */
@@ -1201,7 +1193,7 @@ retry:
write_csr(dd, CCE_DC_CTRL, 0);
/* Set the LED off */
- if (is_a0(dd))
+ if (is_ax(dd))
setextled(dd, 0);
/* check for any per-lane errors */
diff --git a/drivers/staging/rdma/hfi1/pio.c b/drivers/staging/rdma/hfi1/pio.c
index e5c32db4bc67..b51a4416312b 100644
--- a/drivers/staging/rdma/hfi1/pio.c
+++ b/drivers/staging/rdma/hfi1/pio.c
@@ -660,6 +660,24 @@ void set_pio_integrity(struct send_context *sc)
write_kctxt_csr(dd, hw_context, SC(CHECK_ENABLE), reg);
}
+static u32 get_buffers_allocated(struct send_context *sc)
+{
+ int cpu;
+ u32 ret = 0;
+
+ for_each_possible_cpu(cpu)
+ ret += *per_cpu_ptr(sc->buffers_allocated, cpu);
+ return ret;
+}
+
+static void reset_buffers_allocated(struct send_context *sc)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ (*per_cpu_ptr(sc->buffers_allocated, cpu)) = 0;
+}
+
/*
* Allocate a NUMA relative send context structure of the given type along
* with a HW context.
@@ -668,7 +686,7 @@ struct send_context *sc_alloc(struct hfi1_devdata *dd, int type,
uint hdrqentsize, int numa)
{
struct send_context_info *sci;
- struct send_context *sc;
+ struct send_context *sc = NULL;
dma_addr_t pa;
unsigned long flags;
u64 reg;
@@ -686,10 +704,20 @@ struct send_context *sc_alloc(struct hfi1_devdata *dd, int type,
if (!sc)
return NULL;
+ sc->buffers_allocated = alloc_percpu(u32);
+ if (!sc->buffers_allocated) {
+ kfree(sc);
+ dd_dev_err(dd,
+ "Cannot allocate buffers_allocated per cpu counters\n"
+ );
+ return NULL;
+ }
+
spin_lock_irqsave(&dd->sc_lock, flags);
ret = sc_hw_alloc(dd, type, &sw_index, &hw_context);
if (ret) {
spin_unlock_irqrestore(&dd->sc_lock, flags);
+ free_percpu(sc->buffers_allocated);
kfree(sc);
return NULL;
}
@@ -705,7 +733,6 @@ struct send_context *sc_alloc(struct hfi1_devdata *dd, int type,
spin_lock_init(&sc->credit_ctrl_lock);
INIT_LIST_HEAD(&sc->piowait);
INIT_WORK(&sc->halt_work, sc_halted);
- atomic_set(&sc->buffers_allocated, 0);
init_waitqueue_head(&sc->halt_wait);
/* grouping is always single context for now */
@@ -815,15 +842,16 @@ struct send_context *sc_alloc(struct hfi1_devdata *dd, int type,
}
}
- dd_dev_info(dd,
- "Send context %u(%u) %s group %u credits %u credit_ctrl 0x%llx threshold %u\n",
- sw_index,
- hw_context,
- sc_type_name(type),
- sc->group,
- sc->credits,
- sc->credit_ctrl,
- thresh);
+ hfi1_cdbg(PIO,
+ "Send context %u(%u) %s group %u credits %u credit_ctrl 0x%llx threshold %u\n",
+ sw_index,
+ hw_context,
+ sc_type_name(type),
+ sc->group,
+ sc->credits,
+ sc->credit_ctrl,
+ thresh);
+
return sc;
}
@@ -865,6 +893,7 @@ void sc_free(struct send_context *sc)
spin_unlock_irqrestore(&dd->sc_lock, flags);
kfree(sc->sr);
+ free_percpu(sc->buffers_allocated);
kfree(sc);
}
@@ -1028,7 +1057,7 @@ int sc_restart(struct send_context *sc)
/* kernel context */
loop = 0;
while (1) {
- count = atomic_read(&sc->buffers_allocated);
+ count = get_buffers_allocated(sc);
if (count == 0)
break;
if (loop > 100) {
@@ -1196,7 +1225,8 @@ int sc_enable(struct send_context *sc)
sc->sr_head = 0;
sc->sr_tail = 0;
sc->flags = 0;
- atomic_set(&sc->buffers_allocated, 0);
+ /* the alloc lock insures no fast path allocation */
+ reset_buffers_allocated(sc);
/*
* Clear all per-context errors. Some of these will be set when
@@ -1372,7 +1402,8 @@ retry:
/* there is enough room */
- atomic_inc(&sc->buffers_allocated);
+ preempt_disable();
+ this_cpu_inc(*sc->buffers_allocated);
/* read this once */
head = sc->sr_head;
@@ -1564,6 +1595,7 @@ void sc_release_update(struct send_context *sc)
u64 hw_free;
u32 head, tail;
unsigned long old_free;
+ unsigned long free;
unsigned long extra;
unsigned long flags;
int code;
@@ -1578,7 +1610,7 @@ void sc_release_update(struct send_context *sc)
extra = (((hw_free & CR_COUNTER_SMASK) >> CR_COUNTER_SHIFT)
- (old_free & CR_COUNTER_MASK))
& CR_COUNTER_MASK;
- sc->free = old_free + extra;
+ free = old_free + extra;
trace_hfi1_piofree(sc, extra);
/* call sent buffer callbacks */
@@ -1588,7 +1620,7 @@ void sc_release_update(struct send_context *sc)
while (head != tail) {
pbuf = &sc->sr[tail].pbuf;
- if (sent_before(sc->free, pbuf->sent_at)) {
+ if (sent_before(free, pbuf->sent_at)) {
/* not sent yet */
break;
}
@@ -1602,8 +1634,10 @@ void sc_release_update(struct send_context *sc)
if (tail >= sc->sr_size)
tail = 0;
}
- /* update tail, in case we moved it */
sc->sr_tail = tail;
+ /* make sure tail is updated before free */
+ smp_wmb();
+ sc->free = free;
spin_unlock_irqrestore(&sc->release_lock, flags);
sc_piobufavail(sc);
}
diff --git a/drivers/staging/rdma/hfi1/pio.h b/drivers/staging/rdma/hfi1/pio.h
index 0bb885ca3cfb..53d3e0a79375 100644
--- a/drivers/staging/rdma/hfi1/pio.h
+++ b/drivers/staging/rdma/hfi1/pio.h
@@ -130,7 +130,7 @@ struct send_context {
spinlock_t credit_ctrl_lock ____cacheline_aligned_in_smp;
u64 credit_ctrl; /* cache for credit control */
u32 credit_intr_count; /* count of credit intr users */
- atomic_t buffers_allocated; /* count of buffers allocated */
+ u32 __percpu *buffers_allocated;/* count of buffers allocated */
wait_queue_head_t halt_wait; /* wait until kernel sees interrupt */
};
diff --git a/drivers/staging/rdma/hfi1/pio_copy.c b/drivers/staging/rdma/hfi1/pio_copy.c
index 8972bbc02038..ebb0bafc68cb 100644
--- a/drivers/staging/rdma/hfi1/pio_copy.c
+++ b/drivers/staging/rdma/hfi1/pio_copy.c
@@ -160,7 +160,8 @@ void pio_copy(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc,
}
/* finished with this buffer */
- atomic_dec(&pbuf->sc->buffers_allocated);
+ this_cpu_dec(*pbuf->sc->buffers_allocated);
+ preempt_enable();
}
/* USE_SHIFTS is faster in user-space tests on a Xeon X5570 @ 2.93GHz */
@@ -854,5 +855,6 @@ void seg_pio_copy_end(struct pio_buf *pbuf)
}
/* finished with this buffer */
- atomic_dec(&pbuf->sc->buffers_allocated);
+ this_cpu_dec(*pbuf->sc->buffers_allocated);
+ preempt_enable();
}
diff --git a/drivers/staging/rdma/hfi1/qp.c b/drivers/staging/rdma/hfi1/qp.c
index f8c36166962f..ce036810d576 100644
--- a/drivers/staging/rdma/hfi1/qp.c
+++ b/drivers/staging/rdma/hfi1/qp.c
@@ -378,6 +378,7 @@ static void reset_qp(struct hfi1_qp *qp, enum ib_qp_type type)
}
qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
qp->r_nak_state = 0;
+ qp->r_adefered = 0;
qp->r_aflags = 0;
qp->r_flags = 0;
qp->s_head = 0;
@@ -617,7 +618,7 @@ int hfi1_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int mig = 0;
int ret;
u32 pmtu = 0; /* for gcc warning only */
- struct hfi1_devdata *dd;
+ struct hfi1_devdata *dd = dd_from_dev(dev);
spin_lock_irq(&qp->r_lock);
spin_lock(&qp->s_lock);
@@ -631,23 +632,35 @@ int hfi1_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
goto inval;
if (attr_mask & IB_QP_AV) {
+ u8 sc;
+
if (attr->ah_attr.dlid >= HFI1_MULTICAST_LID_BASE)
goto inval;
if (hfi1_check_ah(qp->ibqp.device, &attr->ah_attr))
goto inval;
+ sc = ah_to_sc(ibqp->device, &attr->ah_attr);
+ if (!qp_to_sdma_engine(qp, sc) &&
+ dd->flags & HFI1_HAS_SEND_DMA)
+ goto inval;
}
if (attr_mask & IB_QP_ALT_PATH) {
+ u8 sc;
+
if (attr->alt_ah_attr.dlid >= HFI1_MULTICAST_LID_BASE)
goto inval;
if (hfi1_check_ah(qp->ibqp.device, &attr->alt_ah_attr))
goto inval;
- if (attr->alt_pkey_index >= hfi1_get_npkeys(dd_from_dev(dev)))
+ if (attr->alt_pkey_index >= hfi1_get_npkeys(dd))
+ goto inval;
+ sc = ah_to_sc(ibqp->device, &attr->alt_ah_attr);
+ if (!qp_to_sdma_engine(qp, sc) &&
+ dd->flags & HFI1_HAS_SEND_DMA)
goto inval;
}
if (attr_mask & IB_QP_PKEY_INDEX)
- if (attr->pkey_index >= hfi1_get_npkeys(dd_from_dev(dev)))
+ if (attr->pkey_index >= hfi1_get_npkeys(dd))
goto inval;
if (attr_mask & IB_QP_MIN_RNR_TIMER)
@@ -792,6 +805,8 @@ int hfi1_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->remote_ah_attr = attr->ah_attr;
qp->s_srate = attr->ah_attr.static_rate;
qp->srate_mbps = ib_rate_to_mbps(qp->s_srate);
+ qp->s_sc = ah_to_sc(ibqp->device, &qp->remote_ah_attr);
+ qp->s_sde = qp_to_sdma_engine(qp, qp->s_sc);
}
if (attr_mask & IB_QP_ALT_PATH) {
@@ -806,6 +821,8 @@ int hfi1_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->port_num = qp->alt_ah_attr.port_num;
qp->s_pkey_index = qp->s_alt_pkey_index;
qp->s_flags |= HFI1_S_AHG_CLEAR;
+ qp->s_sc = ah_to_sc(ibqp->device, &qp->remote_ah_attr);
+ qp->s_sde = qp_to_sdma_engine(qp, qp->s_sc);
}
}
@@ -1528,9 +1545,6 @@ struct sdma_engine *qp_to_sdma_engine(struct hfi1_qp *qp, u8 sc5)
if (!(dd->flags & HFI1_HAS_SEND_DMA))
return NULL;
switch (qp->ibqp.qp_type) {
- case IB_QPT_UC:
- case IB_QPT_RC:
- break;
case IB_QPT_SMI:
return NULL;
default:
@@ -1685,3 +1699,25 @@ void qp_comm_est(struct hfi1_qp *qp)
qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
}
}
+
+/*
+ * Switch to alternate path.
+ * The QP s_lock should be held and interrupts disabled.
+ */
+void hfi1_migrate_qp(struct hfi1_qp *qp)
+{
+ struct ib_event ev;
+
+ qp->s_mig_state = IB_MIG_MIGRATED;
+ qp->remote_ah_attr = qp->alt_ah_attr;
+ qp->port_num = qp->alt_ah_attr.port_num;
+ qp->s_pkey_index = qp->s_alt_pkey_index;
+ qp->s_flags |= HFI1_S_AHG_CLEAR;
+ qp->s_sc = ah_to_sc(qp->ibqp.device, &qp->remote_ah_attr);
+ qp->s_sde = qp_to_sdma_engine(qp, qp->s_sc);
+
+ ev.device = qp->ibqp.device;
+ ev.element.qp = &qp->ibqp;
+ ev.event = IB_EVENT_PATH_MIG;
+ qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+}
diff --git a/drivers/staging/rdma/hfi1/qp.h b/drivers/staging/rdma/hfi1/qp.h
index b9c1575990aa..62a94c5d7dca 100644
--- a/drivers/staging/rdma/hfi1/qp.h
+++ b/drivers/staging/rdma/hfi1/qp.h
@@ -128,7 +128,6 @@ static inline void clear_ahg(struct hfi1_qp *qp)
if (qp->s_sde && qp->s_ahgidx >= 0)
sdma_ahg_free(qp->s_sde, qp->s_ahgidx);
qp->s_ahgidx = -1;
- qp->s_sde = NULL;
}
/**
@@ -212,7 +211,7 @@ int hfi1_qp_init(struct hfi1_ibdev *dev);
void hfi1_qp_exit(struct hfi1_ibdev *dev);
/**
- * hfi1_qp_waitup - wake up on the indicated event
+ * hfi1_qp_wakeup - wake up on the indicated event
* @qp: the QP
* @flag: flag the qp on which the qp is stalled
*/
@@ -223,19 +222,19 @@ struct sdma_engine *qp_to_sdma_engine(struct hfi1_qp *qp, u8 sc5);
struct qp_iter;
/**
- * qp_iter_init - wake up on the indicated event
+ * qp_iter_init - initialize the iterator for the qp hash list
* @dev: the hfi1_ibdev
*/
struct qp_iter *qp_iter_init(struct hfi1_ibdev *dev);
/**
- * qp_iter_next - wakeup on the indicated event
+ * qp_iter_next - Find the next qp in the hash list
* @iter: the iterator for the qp hash list
*/
int qp_iter_next(struct qp_iter *iter);
/**
- * qp_iter_next - wake up on the indicated event
+ * qp_iter_print - print the qp information to seq_file
* @s: the seq_file to emit the qp information on
* @iter: the iterator for the qp hash list
*/
@@ -247,4 +246,41 @@ void qp_iter_print(struct seq_file *s, struct qp_iter *iter);
*/
void qp_comm_est(struct hfi1_qp *qp);
+/**
+ * _hfi1_schedule_send - schedule progress
+ * @qp: the QP
+ *
+ * This schedules qp progress w/o regard to the s_flags.
+ *
+ * It is only used in the post send, which doesn't hold
+ * the s_lock.
+ */
+static inline void _hfi1_schedule_send(struct hfi1_qp *qp)
+{
+ struct hfi1_ibport *ibp =
+ to_iport(qp->ibqp.device, qp->port_num);
+ struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
+ struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
+
+ iowait_schedule(&qp->s_iowait, ppd->hfi1_wq,
+ qp->s_sde ?
+ qp->s_sde->cpu :
+ cpumask_first(cpumask_of_node(dd->assigned_node_id)));
+}
+
+/**
+ * hfi1_schedule_send - schedule progress
+ * @qp: the QP
+ *
+ * This schedules qp progress and caller should hold
+ * the s_lock.
+ */
+static inline void hfi1_schedule_send(struct hfi1_qp *qp)
+{
+ if (hfi1_send_ok(qp))
+ _hfi1_schedule_send(qp);
+}
+
+void hfi1_migrate_qp(struct hfi1_qp *qp);
+
#endif /* _QP_H */
diff --git a/drivers/staging/rdma/hfi1/qsfp.c b/drivers/staging/rdma/hfi1/qsfp.c
index ffdb1d787a80..6326a915d7fd 100644
--- a/drivers/staging/rdma/hfi1/qsfp.c
+++ b/drivers/staging/rdma/hfi1/qsfp.c
@@ -475,7 +475,7 @@ int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len)
u8 *cache = &ppd->qsfp_info.cache[0];
u8 bin_buff[QSFP_DUMP_CHUNK];
char lenstr[6];
- int sofar, ret;
+ int sofar;
int bidx = 0;
u8 *atten = &cache[QSFP_ATTEN_OFFS];
u8 *vendor_oui = &cache[QSFP_VOUI_OFFS];
@@ -536,6 +536,5 @@ int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len)
bidx += QSFP_DUMP_CHUNK;
}
}
- ret = sofar;
- return ret;
+ return sofar;
}
diff --git a/drivers/staging/rdma/hfi1/rc.c b/drivers/staging/rdma/hfi1/rc.c
index 5fc93bb312f1..6f4a155f7931 100644
--- a/drivers/staging/rdma/hfi1/rc.c
+++ b/drivers/staging/rdma/hfi1/rc.c
@@ -1608,6 +1608,27 @@ bail:
return;
}
+static inline void rc_defered_ack(struct hfi1_ctxtdata *rcd,
+ struct hfi1_qp *qp)
+{
+ if (list_empty(&qp->rspwait)) {
+ qp->r_flags |= HFI1_R_RSP_DEFERED_ACK;
+ atomic_inc(&qp->refcount);
+ list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
+ }
+}
+
+static inline void rc_cancel_ack(struct hfi1_qp *qp)
+{
+ qp->r_adefered = 0;
+ if (list_empty(&qp->rspwait))
+ return;
+ list_del_init(&qp->rspwait);
+ qp->r_flags &= ~HFI1_R_RSP_DEFERED_ACK;
+ if (atomic_dec_and_test(&qp->refcount))
+ wake_up(&qp->wait);
+}
+
/**
* rc_rcv_error - process an incoming duplicate or error RC packet
* @ohdr: the other headers for this packet
@@ -1650,11 +1671,7 @@ static noinline int rc_rcv_error(struct hfi1_other_headers *ohdr, void *data,
* in the receive queue have been processed.
* Otherwise, we end up propagating congestion.
*/
- if (list_empty(&qp->rspwait)) {
- qp->r_flags |= HFI1_R_RSP_NAK;
- atomic_inc(&qp->refcount);
- list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
- }
+ rc_defered_ack(rcd, qp);
}
goto done;
}
@@ -1978,7 +1995,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
}
psn = be32_to_cpu(ohdr->bth[2]);
- opcode = bth0 >> 24;
+ opcode = (bth0 >> 24) & 0xff;
/*
* Process responses (ACKs) before anything else. Note that the
@@ -2329,19 +2346,29 @@ send_last:
qp->r_ack_psn = psn;
qp->r_nak_state = 0;
/* Send an ACK if requested or required. */
- if (psn & (1 << 31))
- goto send_ack;
+ if (psn & IB_BTH_REQ_ACK) {
+ if (packet->numpkt == 0) {
+ rc_cancel_ack(qp);
+ goto send_ack;
+ }
+ if (qp->r_adefered >= HFI1_PSN_CREDIT) {
+ rc_cancel_ack(qp);
+ goto send_ack;
+ }
+ if (unlikely(is_fecn)) {
+ rc_cancel_ack(qp);
+ goto send_ack;
+ }
+ qp->r_adefered++;
+ rc_defered_ack(rcd, qp);
+ }
return;
rnr_nak:
qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
qp->r_ack_psn = qp->r_psn;
/* Queue RNR NAK for later */
- if (list_empty(&qp->rspwait)) {
- qp->r_flags |= HFI1_R_RSP_NAK;
- atomic_inc(&qp->refcount);
- list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
- }
+ rc_defered_ack(rcd, qp);
return;
nack_op_err:
@@ -2349,11 +2376,7 @@ nack_op_err:
qp->r_nak_state = IB_NAK_REMOTE_OPERATIONAL_ERROR;
qp->r_ack_psn = qp->r_psn;
/* Queue NAK for later */
- if (list_empty(&qp->rspwait)) {
- qp->r_flags |= HFI1_R_RSP_NAK;
- atomic_inc(&qp->refcount);
- list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
- }
+ rc_defered_ack(rcd, qp);
return;
nack_inv_unlck:
@@ -2363,11 +2386,7 @@ nack_inv:
qp->r_nak_state = IB_NAK_INVALID_REQUEST;
qp->r_ack_psn = qp->r_psn;
/* Queue NAK for later */
- if (list_empty(&qp->rspwait)) {
- qp->r_flags |= HFI1_R_RSP_NAK;
- atomic_inc(&qp->refcount);
- list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
- }
+ rc_defered_ack(rcd, qp);
return;
nack_acc_unlck:
@@ -2391,19 +2410,19 @@ void hfi1_rc_hdrerr(
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
int diff;
u32 opcode;
- u32 psn;
+ u32 psn, bth0;
/* Check for GRH */
ohdr = &hdr->u.oth;
if (has_grh)
ohdr = &hdr->u.l.oth;
- opcode = be32_to_cpu(ohdr->bth[0]);
- if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode))
+ bth0 = be32_to_cpu(ohdr->bth[0]);
+ if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, bth0))
return;
psn = be32_to_cpu(ohdr->bth[2]);
- opcode >>= 24;
+ opcode = (bth0 >> 24) & 0xff;
/* Only deal with RDMA Writes for now */
if (opcode < IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) {
@@ -2421,13 +2440,7 @@ void hfi1_rc_hdrerr(
* Otherwise, we end up
* propagating congestion.
*/
- if (list_empty(&qp->rspwait)) {
- qp->r_flags |= HFI1_R_RSP_NAK;
- atomic_inc(&qp->refcount);
- list_add_tail(
- &qp->rspwait,
- &rcd->qp_wait_list);
- }
+ rc_defered_ack(rcd, qp);
} /* Out of sequence NAK */
} /* QP Request NAKs */
}
diff --git a/drivers/staging/rdma/hfi1/ruc.c b/drivers/staging/rdma/hfi1/ruc.c
index 49bc9fd7a51a..4a91975b68d7 100644
--- a/drivers/staging/rdma/hfi1/ruc.c
+++ b/drivers/staging/rdma/hfi1/ruc.c
@@ -241,26 +241,6 @@ bail:
return ret;
}
-/*
- * Switch to alternate path.
- * The QP s_lock should be held and interrupts disabled.
- */
-void hfi1_migrate_qp(struct hfi1_qp *qp)
-{
- struct ib_event ev;
-
- qp->s_mig_state = IB_MIG_MIGRATED;
- qp->remote_ah_attr = qp->alt_ah_attr;
- qp->port_num = qp->alt_ah_attr.port_num;
- qp->s_pkey_index = qp->s_alt_pkey_index;
- qp->s_flags |= HFI1_S_AHG_CLEAR;
-
- ev.device = qp->ibqp.device;
- ev.element.qp = &qp->ibqp;
- ev.event = IB_EVENT_PATH_MIG;
- qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
-}
-
static __be64 get_sguid(struct hfi1_ibport *ibp, unsigned index)
{
if (!index) {
@@ -308,11 +288,12 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_ib_header *hdr,
}
if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), (u16)bth0,
sc5, be16_to_cpu(hdr->lrh[3])))) {
- hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY,
+ hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_P_KEY,
(u16)bth0,
(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
0, qp->ibqp.qp_num,
- hdr->lrh[3], hdr->lrh[1]);
+ be16_to_cpu(hdr->lrh[3]),
+ be16_to_cpu(hdr->lrh[1]));
goto err;
}
/* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
@@ -340,11 +321,12 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_ib_header *hdr,
}
if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), (u16)bth0,
sc5, be16_to_cpu(hdr->lrh[3])))) {
- hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY,
+ hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_P_KEY,
(u16)bth0,
(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
0, qp->ibqp.qp_num,
- hdr->lrh[3], hdr->lrh[1]);
+ be16_to_cpu(hdr->lrh[3]),
+ be16_to_cpu(hdr->lrh[1]));
goto err;
}
/* Validate the SLID. See Ch. 9.6.1.5 */
@@ -714,11 +696,8 @@ static inline void build_ahg(struct hfi1_qp *qp, u32 npsn)
clear_ahg(qp);
if (!(qp->s_flags & HFI1_S_AHG_VALID)) {
/* first middle that needs copy */
- if (qp->s_ahgidx < 0) {
- if (!qp->s_sde)
- qp->s_sde = qp_to_sdma_engine(qp, qp->s_sc);
+ if (qp->s_ahgidx < 0)
qp->s_ahgidx = sdma_ahg_alloc(qp->s_sde);
- }
if (qp->s_ahgidx >= 0) {
qp->s_ahgpsn = npsn;
qp->s_hdr->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
@@ -761,7 +740,6 @@ void hfi1_make_ruc_header(struct hfi1_qp *qp, struct hfi1_other_headers *ohdr,
u16 lrh0;
u32 nwords;
u32 extra_bytes;
- u8 sc5;
u32 bth1;
/* Construct the header. */
@@ -775,9 +753,7 @@ void hfi1_make_ruc_header(struct hfi1_qp *qp, struct hfi1_other_headers *ohdr,
lrh0 = HFI1_LRH_GRH;
middle = 0;
}
- sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl];
- lrh0 |= (sc5 & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4;
- qp->s_sc = sc5;
+ lrh0 |= (qp->s_sc & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4;
/*
* reset s_hdr/AHG fields
*
@@ -835,16 +811,20 @@ void hfi1_do_send(struct work_struct *work)
{
struct iowait *wait = container_of(work, struct iowait, iowork);
struct hfi1_qp *qp = container_of(wait, struct hfi1_qp, s_iowait);
- struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
- struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
+ struct hfi1_pkt_state ps;
int (*make_req)(struct hfi1_qp *qp);
unsigned long flags;
unsigned long timeout;
+ ps.dev = to_idev(qp->ibqp.device);
+ ps.ibp = to_iport(qp->ibqp.device, qp->port_num);
+ ps.ppd = ppd_from_ibp(ps.ibp);
+
if ((qp->ibqp.qp_type == IB_QPT_RC ||
qp->ibqp.qp_type == IB_QPT_UC) &&
!loopback &&
- (qp->remote_ah_attr.dlid & ~((1 << ppd->lmc) - 1)) == ppd->lid) {
+ (qp->remote_ah_attr.dlid & ~((1 << ps.ppd->lmc) - 1)) ==
+ ps.ppd->lid) {
ruc_loopback(qp);
return;
}
@@ -876,8 +856,7 @@ void hfi1_do_send(struct work_struct *work)
* If the packet cannot be sent now, return and
* the send tasklet will be woken up later.
*/
- if (hfi1_verbs_send(qp, qp->s_hdr, qp->s_hdrwords,
- qp->s_cur_sge, qp->s_cur_size))
+ if (hfi1_verbs_send(qp, &ps))
break;
/* Record that s_hdr is empty. */
qp->s_hdrwords = 0;
@@ -886,7 +865,7 @@ void hfi1_do_send(struct work_struct *work)
/* allow other tasks to run */
if (unlikely(time_after(jiffies, timeout))) {
cond_resched();
- ppd->dd->verbs_dev.n_send_schedule++;
+ ps.ppd->dd->verbs_dev.n_send_schedule++;
timeout = jiffies + SEND_RESCHED_TIMEOUT;
}
} while (make_req(qp));
diff --git a/drivers/staging/rdma/hfi1/sdma.c b/drivers/staging/rdma/hfi1/sdma.c
index 2a1da2189900..9a15f1f32b45 100644
--- a/drivers/staging/rdma/hfi1/sdma.c
+++ b/drivers/staging/rdma/hfi1/sdma.c
@@ -236,7 +236,6 @@ static void sdma_hw_clean_up_task(unsigned long);
static void sdma_put(struct sdma_state *);
static void sdma_set_state(struct sdma_engine *, enum sdma_states);
static void sdma_start_hw_clean_up(struct sdma_engine *);
-static void sdma_start_sw_clean_up(struct sdma_engine *);
static void sdma_sw_clean_up_task(unsigned long);
static void sdma_sendctrl(struct sdma_engine *, unsigned);
static void init_sdma_regs(struct sdma_engine *, u32, uint);
@@ -470,12 +469,6 @@ static void sdma_err_halt_wait(struct work_struct *work)
sdma_process_event(sde, sdma_event_e15_hw_halt_done);
}
-static void sdma_start_err_halt_wait(struct sdma_engine *sde)
-{
- schedule_work(&sde->err_halt_worker);
-}
-
-
static void sdma_err_progress_check_schedule(struct sdma_engine *sde)
{
if (!is_bx(sde->dd) && HFI1_CAP_IS_KSET(SDMA_AHG)) {
@@ -682,11 +675,6 @@ static void sdma_start_hw_clean_up(struct sdma_engine *sde)
tasklet_hi_schedule(&sde->sdma_hw_clean_up_task);
}
-static void sdma_start_sw_clean_up(struct sdma_engine *sde)
-{
- tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
-}
-
static void sdma_set_state(struct sdma_engine *sde,
enum sdma_states next_state)
{
@@ -777,19 +765,27 @@ struct sdma_engine *sdma_select_engine_vl(
struct sdma_map_elem *e;
struct sdma_engine *rval;
- if (WARN_ON(vl > 8))
- return NULL;
+ /* NOTE This should only happen if SC->VL changed after the initial
+ * checks on the QP/AH
+ * Default will return engine 0 below
+ */
+ if (vl >= num_vls) {
+ rval = NULL;
+ goto done;
+ }
rcu_read_lock();
m = rcu_dereference(dd->sdma_map);
if (unlikely(!m)) {
rcu_read_unlock();
- return NULL;
+ return &dd->per_sdma[0];
}
e = m->map[vl & m->mask];
rval = e->sde[selector & e->mask];
rcu_read_unlock();
+done:
+ rval = !rval ? &dd->per_sdma[0] : rval;
trace_hfi1_sdma_engine_select(dd, selector, vl, rval->this_idx);
return rval;
}
@@ -1874,7 +1870,7 @@ static void dump_sdma_state(struct sdma_engine *sde)
}
#define SDE_FMT \
- "SDE %u STE %s C 0x%llx S 0x%016llx E 0x%llx T(HW) 0x%llx T(SW) 0x%x H(HW) 0x%llx H(SW) 0x%x H(D) 0x%llx DM 0x%llx GL 0x%llx R 0x%llx LIS 0x%llx AHGI 0x%llx TXT %u TXH %u DT %u DH %u FLNE %d DQF %u SLC 0x%llx\n"
+ "SDE %u CPU %d STE %s C 0x%llx S 0x%016llx E 0x%llx T(HW) 0x%llx T(SW) 0x%x H(HW) 0x%llx H(SW) 0x%x H(D) 0x%llx DM 0x%llx GL 0x%llx R 0x%llx LIS 0x%llx AHGI 0x%llx TXT %u TXH %u DT %u DH %u FLNE %d DQF %u SLC 0x%llx\n"
/**
* sdma_seqfile_dump_sde() - debugfs dump of sde
* @s: seq file
@@ -1894,6 +1890,7 @@ void sdma_seqfile_dump_sde(struct seq_file *s, struct sdma_engine *sde)
head = sde->descq_head & sde->sdma_mask;
tail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask;
seq_printf(s, SDE_FMT, sde->this_idx,
+ sde->cpu,
sdma_state_name(sde->state.current_state),
(unsigned long long)read_sde_csr(sde, SD(CTRL)),
(unsigned long long)read_sde_csr(sde, SD(STATUS)),
@@ -2308,7 +2305,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
case sdma_event_e50_hw_cleaned:
break;
case sdma_event_e60_hw_halted:
- sdma_start_err_halt_wait(sde);
+ schedule_work(&sde->err_halt_worker);
break;
case sdma_event_e70_go_idle:
ss->go_s99_running = 0;
@@ -2389,7 +2386,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
break;
case sdma_event_e60_hw_halted:
sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
- sdma_start_err_halt_wait(sde);
+ schedule_work(&sde->err_halt_worker);
break;
case sdma_event_e70_go_idle:
break;
@@ -2452,7 +2449,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
switch (event) {
case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e10_go_hw_start:
break;
@@ -2494,13 +2491,13 @@ static void __sdma_process_event(struct sdma_engine *sde,
switch (event) {
case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e10_go_hw_start:
break;
case sdma_event_e15_hw_halt_done:
sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e25_hw_clean_up_done:
break;
@@ -2512,7 +2509,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
case sdma_event_e50_hw_cleaned:
break;
case sdma_event_e60_hw_halted:
- sdma_start_err_halt_wait(sde);
+ schedule_work(&sde->err_halt_worker);
break;
case sdma_event_e70_go_idle:
ss->go_s99_running = 0;
@@ -2535,13 +2532,13 @@ static void __sdma_process_event(struct sdma_engine *sde,
switch (event) {
case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e10_go_hw_start:
break;
case sdma_event_e15_hw_halt_done:
sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e25_hw_clean_up_done:
break;
@@ -2553,7 +2550,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
case sdma_event_e50_hw_cleaned:
break;
case sdma_event_e60_hw_halted:
- sdma_start_err_halt_wait(sde);
+ schedule_work(&sde->err_halt_worker);
break;
case sdma_event_e70_go_idle:
ss->go_s99_running = 0;
@@ -2575,7 +2572,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
switch (event) {
case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e10_go_hw_start:
break;
@@ -2599,7 +2596,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
break;
case sdma_event_e81_hw_frozen:
sdma_set_state(sde, sdma_state_s82_freeze_sw_clean);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e82_hw_unfreeze:
break;
@@ -2614,7 +2611,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
switch (event) {
case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e10_go_hw_start:
break;
@@ -2658,7 +2655,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
switch (event) {
case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
- sdma_start_sw_clean_up(sde);
+ tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
break;
case sdma_event_e10_go_hw_start:
break;
@@ -2681,7 +2678,7 @@ static void __sdma_process_event(struct sdma_engine *sde,
* progress check
*/
sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
- sdma_start_err_halt_wait(sde);
+ schedule_work(&sde->err_halt_worker);
break;
case sdma_event_e70_go_idle:
sdma_set_state(sde, sdma_state_s60_idle_halt_wait);
@@ -2734,22 +2731,21 @@ static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
tx->coalesce_buf = kmalloc(tx->tlen + sizeof(u32),
GFP_ATOMIC);
if (!tx->coalesce_buf)
- return -ENOMEM;
-
+ goto enomem;
tx->coalesce_idx = 0;
}
return 0;
}
if (unlikely(tx->num_desc == MAX_DESC))
- return -ENOMEM;
+ goto enomem;
tx->descp = kmalloc_array(
MAX_DESC,
sizeof(struct sdma_desc),
GFP_ATOMIC);
if (!tx->descp)
- return -ENOMEM;
+ goto enomem;
/* reserve last descriptor for coalescing */
tx->desc_limit = MAX_DESC - 1;
@@ -2757,6 +2753,9 @@ static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
for (i = 0; i < tx->num_desc; i++)
tx->descp[i] = tx->descs[i];
return 0;
+enomem:
+ sdma_txclean(dd, tx);
+ return -ENOMEM;
}
/*
diff --git a/drivers/staging/rdma/hfi1/sdma.h b/drivers/staging/rdma/hfi1/sdma.h
index cc22d2ee2054..da89e6458162 100644
--- a/drivers/staging/rdma/hfi1/sdma.h
+++ b/drivers/staging/rdma/hfi1/sdma.h
@@ -410,8 +410,6 @@ struct sdma_engine {
u64 idle_mask;
u64 progress_mask;
/* private: */
- struct workqueue_struct *wq;
- /* private: */
volatile __le64 *head_dma; /* DMA'ed by chip */
/* private: */
dma_addr_t head_phys;
@@ -426,6 +424,8 @@ struct sdma_engine {
u32 sdma_mask;
/* private */
struct sdma_state state;
+ /* private */
+ int cpu;
/* private: */
u8 sdma_shift;
/* private: */
@@ -774,10 +774,13 @@ static inline int _sdma_txadd_daddr(
tx->tlen -= len;
/* special cases for last */
if (!tx->tlen) {
- if (tx->packet_len & (sizeof(u32) - 1))
+ if (tx->packet_len & (sizeof(u32) - 1)) {
rval = _pad_sdma_tx_descs(dd, tx);
- else
+ if (rval)
+ return rval;
+ } else {
_sdma_close_tx(dd, tx);
+ }
}
tx->num_desc++;
return rval;
@@ -990,7 +993,9 @@ static inline void sdma_iowait_schedule(
struct sdma_engine *sde,
struct iowait *wait)
{
- iowait_schedule(wait, sde->wq);
+ struct hfi1_pportdata *ppd = sde->dd->pport;
+
+ iowait_schedule(wait, ppd->hfi1_wq, sde->cpu);
}
/* for use by interrupt handling */
diff --git a/drivers/staging/rdma/hfi1/trace.c b/drivers/staging/rdma/hfi1/trace.c
index f55b75194847..10122e84cb2f 100644
--- a/drivers/staging/rdma/hfi1/trace.c
+++ b/drivers/staging/rdma/hfi1/trace.c
@@ -67,7 +67,7 @@ u8 ibhdr_exhdr_len(struct hfi1_ib_header *hdr)
#define IMM_PRN "imm %d"
#define RETH_PRN "reth vaddr 0x%.16llx rkey 0x%.8x dlen 0x%.8x"
-#define AETH_PRN "aeth syn 0x%.2x msn 0x%.8x"
+#define AETH_PRN "aeth syn 0x%.2x %s msn 0x%.8x"
#define DETH_PRN "deth qkey 0x%.8x sqpn 0x%.6x"
#define ATOMICACKETH_PRN "origdata %lld"
#define ATOMICETH_PRN "vaddr 0x%llx rkey 0x%.8x sdata %lld cdata %lld"
@@ -79,6 +79,19 @@ static u64 ib_u64_get(__be32 *p)
return ((u64)be32_to_cpu(p[0]) << 32) | be32_to_cpu(p[1]);
}
+static const char *parse_syndrome(u8 syndrome)
+{
+ switch (syndrome >> 5) {
+ case 0:
+ return "ACK";
+ case 1:
+ return "RNRNAK";
+ case 3:
+ return "NAK";
+ }
+ return "";
+}
+
const char *parse_everbs_hdrs(
struct trace_seq *p,
u8 opcode,
@@ -124,16 +137,18 @@ const char *parse_everbs_hdrs(
case OP(RC, RDMA_READ_RESPONSE_LAST):
case OP(RC, RDMA_READ_RESPONSE_ONLY):
case OP(RC, ACKNOWLEDGE):
- trace_seq_printf(p, AETH_PRN,
- be32_to_cpu(eh->aeth) >> 24,
- be32_to_cpu(eh->aeth) & HFI1_MSN_MASK);
+ trace_seq_printf(p, AETH_PRN, be32_to_cpu(eh->aeth) >> 24,
+ parse_syndrome(be32_to_cpu(eh->aeth) >> 24),
+ be32_to_cpu(eh->aeth) & HFI1_MSN_MASK);
break;
/* aeth + atomicacketh */
case OP(RC, ATOMIC_ACKNOWLEDGE):
trace_seq_printf(p, AETH_PRN " " ATOMICACKETH_PRN,
- (be32_to_cpu(eh->at.aeth) >> 24) & 0xff,
- be32_to_cpu(eh->at.aeth) & HFI1_MSN_MASK,
- (unsigned long long)ib_u64_get(eh->at.atomic_ack_eth));
+ be32_to_cpu(eh->at.aeth) >> 24,
+ parse_syndrome(be32_to_cpu(eh->at.aeth) >> 24),
+ be32_to_cpu(eh->at.aeth) & HFI1_MSN_MASK,
+ (unsigned long long)
+ ib_u64_get(eh->at.atomic_ack_eth));
break;
/* atomiceth */
case OP(RC, COMPARE_SWAP):
diff --git a/drivers/staging/rdma/hfi1/trace.h b/drivers/staging/rdma/hfi1/trace.h
index 57430295c404..86c12ebfd4f0 100644
--- a/drivers/staging/rdma/hfi1/trace.h
+++ b/drivers/staging/rdma/hfi1/trace.h
@@ -417,7 +417,8 @@ __print_symbolic(opcode, \
ib_opcode_name(UC_RDMA_WRITE_ONLY), \
ib_opcode_name(UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
ib_opcode_name(UD_SEND_ONLY), \
- ib_opcode_name(UD_SEND_ONLY_WITH_IMMEDIATE))
+ ib_opcode_name(UD_SEND_ONLY_WITH_IMMEDIATE), \
+ ib_opcode_name(CNP))
#define LRH_PRN "vl %d lver %d sl %d lnh %d,%s dlid %.4x len %d slid %.4x"
diff --git a/drivers/staging/rdma/hfi1/uc.c b/drivers/staging/rdma/hfi1/uc.c
index 6095039c4485..4f2a7889a852 100644
--- a/drivers/staging/rdma/hfi1/uc.c
+++ b/drivers/staging/rdma/hfi1/uc.c
@@ -268,7 +268,7 @@ void hfi1_uc_rcv(struct hfi1_packet *packet)
u32 tlen = packet->tlen;
struct hfi1_qp *qp = packet->qp;
struct hfi1_other_headers *ohdr = packet->ohdr;
- u32 opcode;
+ u32 bth0, opcode;
u32 hdrsize = packet->hlen;
u32 psn;
u32 pad;
@@ -278,10 +278,9 @@ void hfi1_uc_rcv(struct hfi1_packet *packet)
int has_grh = rcv_flags & HFI1_HAS_GRH;
int ret;
u32 bth1;
- struct ib_grh *grh = NULL;
- opcode = be32_to_cpu(ohdr->bth[0]);
- if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode))
+ bth0 = be32_to_cpu(ohdr->bth[0]);
+ if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, bth0))
return;
bth1 = be32_to_cpu(ohdr->bth[1]);
@@ -303,6 +302,7 @@ void hfi1_uc_rcv(struct hfi1_packet *packet)
}
if (bth1 & HFI1_FECN_SMASK) {
+ struct ib_grh *grh = NULL;
u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]);
u16 slid = be16_to_cpu(hdr->lrh[3]);
u16 dlid = be16_to_cpu(hdr->lrh[1]);
@@ -310,13 +310,16 @@ void hfi1_uc_rcv(struct hfi1_packet *packet)
u8 sc5;
sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl];
+ if (has_grh)
+ grh = &hdr->u.l.grh;
- return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5, grh);
+ return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5,
+ grh);
}
}
psn = be32_to_cpu(ohdr->bth[2]);
- opcode >>= 24;
+ opcode = (bth0 >> 24) & 0xff;
/* Compare the PSN verses the expected PSN. */
if (unlikely(cmp_psn(psn, qp->r_psn) != 0)) {
diff --git a/drivers/staging/rdma/hfi1/ud.c b/drivers/staging/rdma/hfi1/ud.c
index 5a9c784bec04..bd1b402c1e14 100644
--- a/drivers/staging/rdma/hfi1/ud.c
+++ b/drivers/staging/rdma/hfi1/ud.c
@@ -111,11 +111,10 @@ static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe)
((1 << ppd->lmc) - 1));
if (unlikely(ingress_pkey_check(ppd, pkey, sc5,
qp->s_pkey_index, slid))) {
- hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY, pkey,
+ hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_P_KEY, pkey,
ah_attr->sl,
sqp->ibqp.qp_num, qp->ibqp.qp_num,
- cpu_to_be16(slid),
- cpu_to_be16(ah_attr->dlid));
+ slid, ah_attr->dlid);
goto drop;
}
}
@@ -135,11 +134,11 @@ static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe)
lid = ppd->lid | (ah_attr->src_path_bits &
((1 << ppd->lmc) - 1));
- hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_QKEY, qkey,
+ hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_Q_KEY, qkey,
ah_attr->sl,
sqp->ibqp.qp_num, qp->ibqp.qp_num,
- cpu_to_be16(lid),
- cpu_to_be16(ah_attr->dlid));
+ lid,
+ ah_attr->dlid);
goto drop;
}
}
@@ -383,6 +382,7 @@ int hfi1_make_ud_req(struct hfi1_qp *qp)
lrh0 |= (sc5 & 0xf) << 12;
qp->s_sc = sc5;
}
+ qp->s_sde = qp_to_sdma_engine(qp, qp->s_sc);
qp->s_hdr->ibh.lrh[0] = cpu_to_be16(lrh0);
qp->s_hdr->ibh.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
qp->s_hdr->ibh.lrh[2] =
@@ -736,12 +736,13 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
* for invalid pkeys is optional according to
* IB spec (release 1.3, section 10.9.4)
*/
- hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY,
+ hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_P_KEY,
pkey,
(be16_to_cpu(hdr->lrh[0]) >> 4) &
0xF,
src_qp, qp->ibqp.qp_num,
- hdr->lrh[3], hdr->lrh[1]);
+ be16_to_cpu(hdr->lrh[3]),
+ be16_to_cpu(hdr->lrh[1]));
return;
}
} else {
@@ -752,10 +753,11 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
}
if (unlikely(qkey != qp->qkey)) {
- hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_QKEY, qkey,
+ hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_Q_KEY, qkey,
(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
src_qp, qp->ibqp.qp_num,
- hdr->lrh[3], hdr->lrh[1]);
+ be16_to_cpu(hdr->lrh[3]),
+ be16_to_cpu(hdr->lrh[1]));
return;
}
/* Drop invalid MAD packets (see 13.5.3.1). */
diff --git a/drivers/staging/rdma/hfi1/user_exp_rcv.h b/drivers/staging/rdma/hfi1/user_exp_rcv.h
new file mode 100644
index 000000000000..4f4876e1d353
--- /dev/null
+++ b/drivers/staging/rdma/hfi1/user_exp_rcv.h
@@ -0,0 +1,74 @@
+#ifndef _HFI1_USER_EXP_RCV_H
+#define _HFI1_USER_EXP_RCV_H
+/*
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#define EXP_TID_TIDLEN_MASK 0x7FFULL
+#define EXP_TID_TIDLEN_SHIFT 0
+#define EXP_TID_TIDCTRL_MASK 0x3ULL
+#define EXP_TID_TIDCTRL_SHIFT 20
+#define EXP_TID_TIDIDX_MASK 0x3FFULL
+#define EXP_TID_TIDIDX_SHIFT 22
+#define EXP_TID_GET(tid, field) \
+ (((tid) >> EXP_TID_TID##field##_SHIFT) & EXP_TID_TID##field##_MASK)
+
+#define EXP_TID_SET(field, value) \
+ (((value) & EXP_TID_TID##field##_MASK) << \
+ EXP_TID_TID##field##_SHIFT)
+#define EXP_TID_CLEAR(tid, field) ({ \
+ (tid) &= ~(EXP_TID_TID##field##_MASK << \
+ EXP_TID_TID##field##_SHIFT); \
+ })
+#define EXP_TID_RESET(tid, field, value) do { \
+ EXP_TID_CLEAR(tid, field); \
+ (tid) |= EXP_TID_SET(field, (value)); \
+ } while (0)
+
+#endif /* _HFI1_USER_EXP_RCV_H */
diff --git a/drivers/staging/rdma/hfi1/user_pages.c b/drivers/staging/rdma/hfi1/user_pages.c
index 9071afbd7bf4..692de658f0dc 100644
--- a/drivers/staging/rdma/hfi1/user_pages.c
+++ b/drivers/staging/rdma/hfi1/user_pages.c
@@ -49,59 +49,11 @@
*/
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/device.h>
#include "hfi.h"
-static void __hfi1_release_user_pages(struct page **p, size_t num_pages,
- int dirty)
-{
- size_t i;
-
- for (i = 0; i < num_pages; i++) {
- if (dirty)
- set_page_dirty_lock(p[i]);
- put_page(p[i]);
- }
-}
-
-/*
- * Call with current->mm->mmap_sem held.
- */
-static int __hfi1_get_user_pages(unsigned long start_page, size_t num_pages,
- struct page **p)
-{
- unsigned long lock_limit;
- size_t got;
- int ret;
-
- lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
- if (num_pages > lock_limit && !capable(CAP_IPC_LOCK)) {
- ret = -ENOMEM;
- goto bail;
- }
-
- for (got = 0; got < num_pages; got += ret) {
- ret = get_user_pages(current, current->mm,
- start_page + got * PAGE_SIZE,
- num_pages - got, 1, 1,
- p + got, NULL);
- if (ret < 0)
- goto bail_release;
- }
-
- current->mm->pinned_vm += num_pages;
-
- ret = 0;
- goto bail;
-
-bail_release:
- __hfi1_release_user_pages(p, got, 0);
-bail:
- return ret;
-}
-
/**
* hfi1_map_page - a safety wrapper around pci_map_page()
*
@@ -116,41 +68,44 @@ dma_addr_t hfi1_map_page(struct pci_dev *hwdev, struct page *page,
return phys;
}
-/**
- * hfi1_get_user_pages - lock user pages into memory
- * @start_page: the start page
- * @num_pages: the number of pages
- * @p: the output page structures
- *
- * This function takes a given start page (page aligned user virtual
- * address) and pins it and the following specified number of pages. For
- * now, num_pages is always 1, but that will probably change at some point
- * (because caller is doing expected sends on a single virtually contiguous
- * buffer, so we can do all pages at once).
- */
-int hfi1_get_user_pages(unsigned long start_page, size_t num_pages,
- struct page **p)
+int hfi1_acquire_user_pages(unsigned long vaddr, size_t npages, bool writable,
+ struct page **pages)
{
+ unsigned long pinned, lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ bool can_lock = capable(CAP_IPC_LOCK);
int ret;
- down_write(&current->mm->mmap_sem);
+ down_read(&current->mm->mmap_sem);
+ pinned = current->mm->pinned_vm;
+ up_read(&current->mm->mmap_sem);
- ret = __hfi1_get_user_pages(start_page, num_pages, p);
+ if (pinned + npages > lock_limit && !can_lock)
+ return -ENOMEM;
+ ret = get_user_pages_fast(vaddr, npages, writable, pages);
+ if (ret < 0)
+ return ret;
+
+ down_write(&current->mm->mmap_sem);
+ current->mm->pinned_vm += ret;
up_write(&current->mm->mmap_sem);
return ret;
}
-void hfi1_release_user_pages(struct page **p, size_t num_pages)
+void hfi1_release_user_pages(struct page **p, size_t npages, bool dirty)
{
- if (current->mm) /* during close after signal, mm can be NULL */
- down_write(&current->mm->mmap_sem);
+ size_t i;
- __hfi1_release_user_pages(p, num_pages, 1);
+ for (i = 0; i < npages; i++) {
+ if (dirty)
+ set_page_dirty_lock(p[i]);
+ put_page(p[i]);
+ }
- if (current->mm) {
- current->mm->pinned_vm -= num_pages;
+ if (current->mm) { /* during close after signal, mm can be NULL */
+ down_write(&current->mm->mmap_sem);
+ current->mm->pinned_vm -= npages;
up_write(&current->mm->mmap_sem);
}
}
diff --git a/drivers/staging/rdma/hfi1/user_sdma.c b/drivers/staging/rdma/hfi1/user_sdma.c
index 36c838dcf023..d3de771a0770 100644
--- a/drivers/staging/rdma/hfi1/user_sdma.c
+++ b/drivers/staging/rdma/hfi1/user_sdma.c
@@ -146,8 +146,8 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12
#define KDETH_OM_MAX_SIZE (1 << ((KDETH_OM_LARGE / KDETH_OM_SMALL) + 1))
/* Last packet in the request */
-#define TXREQ_FLAGS_REQ_LAST_PKT (1 << 0)
-#define TXREQ_FLAGS_IOVEC_LAST_PKT (1 << 0)
+#define TXREQ_FLAGS_REQ_LAST_PKT BIT(0)
+#define TXREQ_FLAGS_IOVEC_LAST_PKT BIT(0)
#define SDMA_REQ_IN_USE 0
#define SDMA_REQ_FOR_THREAD 1
@@ -156,9 +156,9 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12
#define SDMA_REQ_HAS_ERROR 4
#define SDMA_REQ_DONE_ERROR 5
-#define SDMA_PKT_Q_INACTIVE (1 << 0)
-#define SDMA_PKT_Q_ACTIVE (1 << 1)
-#define SDMA_PKT_Q_DEFERRED (1 << 2)
+#define SDMA_PKT_Q_INACTIVE BIT(0)
+#define SDMA_PKT_Q_ACTIVE BIT(1)
+#define SDMA_PKT_Q_DEFERRED BIT(2)
/*
* Maximum retry attempts to submit a TX request
@@ -214,12 +214,6 @@ struct user_sdma_request {
*/
u8 omfactor;
/*
- * pointer to the user's task_struct. We are going to
- * get a reference to it so we can process io vectors
- * at a later time.
- */
- struct task_struct *user_proc;
- /*
* pointer to the user's mm_struct. We are going to
* get a reference to it so it doesn't get freed
* since we might not be in process context when we
@@ -245,9 +239,13 @@ struct user_sdma_request {
u16 tididx;
u32 sent;
u64 seqnum;
- spinlock_t list_lock;
struct list_head txps;
+ spinlock_t txcmp_lock; /* protect txcmp list */
+ struct list_head txcmp;
unsigned long flags;
+ /* status of the last txreq completed */
+ int status;
+ struct work_struct worker;
};
/*
@@ -260,6 +258,7 @@ struct user_sdma_txreq {
/* Packet header for the txreq */
struct hfi1_pkt_header hdr;
struct sdma_txreq txreq;
+ struct list_head list;
struct user_sdma_request *req;
struct {
struct user_sdma_iovec *vec;
@@ -282,10 +281,12 @@ struct user_sdma_txreq {
static int user_sdma_send_pkts(struct user_sdma_request *, unsigned);
static int num_user_pages(const struct iovec *);
static void user_sdma_txreq_cb(struct sdma_txreq *, int, int);
+static void user_sdma_delayed_completion(struct work_struct *);
static void user_sdma_free_request(struct user_sdma_request *);
static int pin_vector_pages(struct user_sdma_request *,
struct user_sdma_iovec *);
-static void unpin_vector_pages(struct user_sdma_iovec *);
+static void unpin_vector_pages(struct user_sdma_request *,
+ struct user_sdma_iovec *);
static int check_header_template(struct user_sdma_request *,
struct hfi1_pkt_header *, u32, u32);
static int set_txreq_header(struct user_sdma_request *,
@@ -352,6 +353,7 @@ static void sdma_kmem_cache_ctor(void *obj)
int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
{
+ struct hfi1_filedata *fd;
int ret = 0;
unsigned memsize;
char buf[64];
@@ -365,6 +367,8 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
goto done;
}
+ fd = fp->private_data;
+
if (!hfi1_sdma_comp_ring_size) {
ret = -EINVAL;
goto done;
@@ -384,16 +388,17 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
INIT_LIST_HEAD(&pq->list);
pq->dd = dd;
pq->ctxt = uctxt->ctxt;
- pq->subctxt = subctxt_fp(fp);
+ pq->subctxt = fd->subctxt;
pq->n_max_reqs = hfi1_sdma_comp_ring_size;
pq->state = SDMA_PKT_Q_INACTIVE;
atomic_set(&pq->n_reqs, 0);
+ init_waitqueue_head(&pq->wait);
iowait_init(&pq->busy, 0, NULL, defer_packet_queue,
activate_packet_queue);
pq->reqidx = 0;
snprintf(buf, 64, "txreq-kmem-cache-%u-%u-%u", dd->unit, uctxt->ctxt,
- subctxt_fp(fp));
+ fd->subctxt);
pq->txreq_cache = kmem_cache_create(buf,
sizeof(struct user_sdma_txreq),
L1_CACHE_BYTES,
@@ -404,7 +409,7 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
uctxt->ctxt);
goto pq_txreq_nomem;
}
- user_sdma_pkt_fp(fp) = pq;
+ fd->pq = pq;
cq = kzalloc(sizeof(*cq), GFP_KERNEL);
if (!cq)
goto cq_nomem;
@@ -416,7 +421,7 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
goto cq_comps_nomem;
cq->nentries = hfi1_sdma_comp_ring_size;
- user_sdma_comp_fp(fp) = cq;
+ fd->cq = cq;
spin_lock_irqsave(&uctxt->sdma_qlock, flags);
list_add(&pq->list, &uctxt->sdma_queues);
@@ -431,7 +436,7 @@ pq_txreq_nomem:
kfree(pq->reqs);
pq_reqs_nomem:
kfree(pq);
- user_sdma_pkt_fp(fp) = NULL;
+ fd->pq = NULL;
pq_nomem:
ret = -ENOMEM;
done:
@@ -448,26 +453,16 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
uctxt->ctxt, fd->subctxt);
pq = fd->pq;
if (pq) {
- u16 i, j;
-
spin_lock_irqsave(&uctxt->sdma_qlock, flags);
if (!list_empty(&pq->list))
list_del_init(&pq->list);
spin_unlock_irqrestore(&uctxt->sdma_qlock, flags);
iowait_sdma_drain(&pq->busy);
- if (pq->reqs) {
- for (i = 0, j = 0; i < atomic_read(&pq->n_reqs) &&
- j < pq->n_max_reqs; j++) {
- struct user_sdma_request *req = &pq->reqs[j];
-
- if (test_bit(SDMA_REQ_IN_USE, &req->flags)) {
- set_comp_state(req, ERROR, -ECOMM);
- user_sdma_free_request(req);
- i++;
- }
- }
- kfree(pq->reqs);
- }
+ /* Wait until all requests have been freed. */
+ wait_event_interruptible(
+ pq->wait,
+ (ACCESS_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE));
+ kfree(pq->reqs);
kmem_cache_destroy(pq->txreq_cache);
kfree(pq);
fd->pq = NULL;
@@ -485,9 +480,10 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
unsigned long dim, unsigned long *count)
{
int ret = 0, i = 0, sent;
- struct hfi1_ctxtdata *uctxt = ctxt_fp(fp);
- struct hfi1_user_sdma_pkt_q *pq = user_sdma_pkt_fp(fp);
- struct hfi1_user_sdma_comp_q *cq = user_sdma_comp_fp(fp);
+ struct hfi1_filedata *fd = fp->private_data;
+ struct hfi1_ctxtdata *uctxt = fd->uctxt;
+ struct hfi1_user_sdma_pkt_q *pq = fd->pq;
+ struct hfi1_user_sdma_comp_q *cq = fd->cq;
struct hfi1_devdata *dd = pq->dd;
unsigned long idx = 0;
u8 pcount = initial_pkt_count;
@@ -499,40 +495,36 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
hfi1_cdbg(
SDMA,
"[%u:%u:%u] First vector not big enough for header %lu/%lu",
- dd->unit, uctxt->ctxt, subctxt_fp(fp),
+ dd->unit, uctxt->ctxt, fd->subctxt,
iovec[idx].iov_len, sizeof(info) + sizeof(req->hdr));
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
ret = copy_from_user(&info, iovec[idx].iov_base, sizeof(info));
if (ret) {
hfi1_cdbg(SDMA, "[%u:%u:%u] Failed to copy info QW (%d)",
- dd->unit, uctxt->ctxt, subctxt_fp(fp), ret);
- ret = -EFAULT;
- goto done;
+ dd->unit, uctxt->ctxt, fd->subctxt, ret);
+ return -EFAULT;
}
- trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, subctxt_fp(fp),
+ trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, fd->subctxt,
(u16 *)&info);
if (cq->comps[info.comp_idx].status == QUEUED) {
hfi1_cdbg(SDMA, "[%u:%u:%u] Entry %u is in QUEUED state",
- dd->unit, uctxt->ctxt, subctxt_fp(fp),
+ dd->unit, uctxt->ctxt, fd->subctxt,
info.comp_idx);
- ret = -EBADSLT;
- goto done;
+ return -EBADSLT;
}
if (!info.fragsize) {
hfi1_cdbg(SDMA,
"[%u:%u:%u:%u] Request does not specify fragsize",
- dd->unit, uctxt->ctxt, subctxt_fp(fp), info.comp_idx);
- ret = -EINVAL;
- goto done;
+ dd->unit, uctxt->ctxt, fd->subctxt, info.comp_idx);
+ return -EINVAL;
}
/*
* We've done all the safety checks that we can up to this point,
* "allocate" the request entry.
*/
hfi1_cdbg(SDMA, "[%u:%u:%u] Using req/comp entry %u\n", dd->unit,
- uctxt->ctxt, subctxt_fp(fp), info.comp_idx);
+ uctxt->ctxt, fd->subctxt, info.comp_idx);
req = pq->reqs + info.comp_idx;
memset(req, 0, sizeof(*req));
/* Mark the request as IN_USE before we start filling it in. */
@@ -540,8 +532,12 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
req->data_iovs = req_iovcnt(info.ctrl) - 1;
req->pq = pq;
req->cq = cq;
+ req->status = -1;
INIT_LIST_HEAD(&req->txps);
- spin_lock_init(&req->list_lock);
+ INIT_LIST_HEAD(&req->txcmp);
+ INIT_WORK(&req->worker, user_sdma_delayed_completion);
+
+ spin_lock_init(&req->txcmp_lock);
memcpy(&req->info, &info, sizeof(info));
if (req_opcode(info.ctrl) == EXPECTED)
@@ -550,8 +546,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
if (!info.npkts || req->data_iovs > MAX_VECTORS_PER_REQ) {
SDMA_DBG(req, "Too many vectors (%u/%u)", req->data_iovs,
MAX_VECTORS_PER_REQ);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
/* Copy the header from the user buffer */
ret = copy_from_user(&req->hdr, iovec[idx].iov_base + sizeof(info),
@@ -659,7 +654,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
/* Have to select the engine */
req->sde = sdma_select_engine_vl(dd,
- (u32)(uctxt->ctxt + subctxt_fp(fp)),
+ (u32)(uctxt->ctxt + fd->subctxt),
vl);
if (!req->sde || !sdma_running(req->sde)) {
ret = -ECOMM;
@@ -681,18 +676,16 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
sent = user_sdma_send_pkts(req, pcount);
if (unlikely(sent < 0)) {
if (sent != -EBUSY) {
- ret = sent;
- goto send_err;
+ req->status = sent;
+ set_comp_state(req, ERROR, req->status);
+ return sent;
} else
sent = 0;
}
atomic_inc(&pq->n_reqs);
+ xchg(&pq->state, SDMA_PKT_Q_ACTIVE);
if (sent < req->info.npkts) {
- /* Take the references to the user's task and mm_struct */
- get_task_struct(current);
- req->user_proc = current;
-
/*
* This is a somewhat blocking send implementation.
* The driver will block the caller until all packets of the
@@ -702,8 +695,10 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
while (!test_bit(SDMA_REQ_SEND_DONE, &req->flags)) {
ret = user_sdma_send_pkts(req, pcount);
if (ret < 0) {
- if (ret != -EBUSY)
- goto send_err;
+ if (ret != -EBUSY) {
+ req->status = ret;
+ return ret;
+ }
wait_event_interruptible_timeout(
pq->busy.wait_dma,
(pq->state == SDMA_PKT_Q_ACTIVE),
@@ -713,14 +708,10 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
}
}
- ret = 0;
*count += idx;
- goto done;
-send_err:
- set_comp_state(req, ERROR, ret);
+ return 0;
free_req:
user_sdma_free_request(req);
-done:
return ret;
}
@@ -778,20 +769,24 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
struct hfi1_user_sdma_pkt_q *pq = NULL;
struct user_sdma_iovec *iovec = NULL;
- if (!req->pq) {
- ret = -EINVAL;
- goto done;
- }
+ if (!req->pq)
+ return -EINVAL;
pq = req->pq;
+ /* If tx completion has reported an error, we are done. */
+ if (test_bit(SDMA_REQ_HAS_ERROR, &req->flags)) {
+ set_bit(SDMA_REQ_DONE_ERROR, &req->flags);
+ return -EFAULT;
+ }
+
/*
* Check if we might have sent the entire request already
*/
if (unlikely(req->seqnum == req->info.npkts)) {
if (!list_empty(&req->txps))
goto dosend;
- goto done;
+ return ret;
}
if (!maxpkts || maxpkts > req->info.npkts - req->seqnum)
@@ -808,19 +803,18 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
*/
if (test_bit(SDMA_REQ_HAS_ERROR, &req->flags)) {
set_bit(SDMA_REQ_DONE_ERROR, &req->flags);
- ret = -EFAULT;
- goto done;
+ return -EFAULT;
}
tx = kmem_cache_alloc(pq->txreq_cache, GFP_KERNEL);
- if (!tx) {
- ret = -ENOMEM;
- goto done;
- }
+ if (!tx)
+ return -ENOMEM;
+
tx->flags = 0;
tx->req = req;
tx->busycount = 0;
tx->idx = -1;
+ INIT_LIST_HEAD(&tx->list);
memset(tx->iovecs, 0, sizeof(tx->iovecs));
if (req->seqnum == req->info.npkts - 1)
@@ -945,9 +939,8 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
if (ret) {
int i;
- dd_dev_err(pq->dd,
- "SDMA txreq add page failed %d\n",
- ret);
+ SDMA_DBG(req, "SDMA txreq add page failed %d\n",
+ ret);
/* Mark all assigned vectors as complete so they
* are unpinned in the callback. */
for (i = tx->idx; i >= 0; i--) {
@@ -1017,12 +1010,12 @@ dosend:
if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags))
sdma_ahg_free(req->sde, req->ahg_idx);
}
- goto done;
+ return ret;
+
free_txreq:
sdma_txclean(pq->dd, &tx->txreq);
free_tx:
kmem_cache_free(pq->txreq_cache, tx);
-done:
return ret;
}
@@ -1041,52 +1034,58 @@ static inline int num_user_pages(const struct iovec *iov)
static int pin_vector_pages(struct user_sdma_request *req,
struct user_sdma_iovec *iovec) {
- int ret = 0;
- unsigned pinned;
+ int pinned, npages;
- iovec->npages = num_user_pages(&iovec->iov);
- iovec->pages = kcalloc(iovec->npages, sizeof(*iovec->pages),
- GFP_KERNEL);
+ npages = num_user_pages(&iovec->iov);
+ iovec->pages = kcalloc(npages, sizeof(*iovec->pages), GFP_KERNEL);
if (!iovec->pages) {
SDMA_DBG(req, "Failed page array alloc");
- ret = -ENOMEM;
- goto done;
+ return -ENOMEM;
}
- /* If called by the kernel thread, use the user's mm */
- if (current->flags & PF_KTHREAD)
- use_mm(req->user_proc->mm);
- pinned = get_user_pages_fast(
- (unsigned long)iovec->iov.iov_base,
- iovec->npages, 0, iovec->pages);
- /* If called by the kernel thread, unuse the user's mm */
- if (current->flags & PF_KTHREAD)
- unuse_mm(req->user_proc->mm);
- if (pinned != iovec->npages) {
- SDMA_DBG(req, "Failed to pin pages (%u/%u)", pinned,
- iovec->npages);
- ret = -EFAULT;
- goto pfree;
+
+ /*
+ * Get a reference to the process's mm so we can use it when
+ * unpinning the io vectors.
+ */
+ req->pq->user_mm = get_task_mm(current);
+
+ pinned = hfi1_acquire_user_pages((unsigned long)iovec->iov.iov_base,
+ npages, 0, iovec->pages);
+
+ if (pinned < 0)
+ return pinned;
+
+ iovec->npages = pinned;
+ if (pinned != npages) {
+ SDMA_DBG(req, "Failed to pin pages (%d/%u)", pinned, npages);
+ unpin_vector_pages(req, iovec);
+ return -EFAULT;
}
- goto done;
-pfree:
- unpin_vector_pages(iovec);
-done:
- return ret;
+ return 0;
}
-static void unpin_vector_pages(struct user_sdma_iovec *iovec)
+static void unpin_vector_pages(struct user_sdma_request *req,
+ struct user_sdma_iovec *iovec)
{
- unsigned i;
+ /*
+ * Unpinning is done through the workqueue so use the
+ * process's mm if we have a reference to it.
+ */
+ if ((current->flags & PF_KTHREAD) && req->pq->user_mm)
+ use_mm(req->pq->user_mm);
- if (ACCESS_ONCE(iovec->offset) != iovec->iov.iov_len) {
- hfi1_cdbg(SDMA,
- "the complete vector has not been sent yet %llu %zu",
- iovec->offset, iovec->iov.iov_len);
- return;
+ hfi1_release_user_pages(iovec->pages, iovec->npages, 0);
+
+ /*
+ * Unuse the user's mm (see above) and release the
+ * reference to it.
+ */
+ if (req->pq->user_mm) {
+ if (current->flags & PF_KTHREAD)
+ unuse_mm(req->pq->user_mm);
+ mmput(req->pq->user_mm);
}
- for (i = 0; i < iovec->npages; i++)
- if (iovec->pages[i])
- put_page(iovec->pages[i]);
+
kfree(iovec->pages);
iovec->pages = NULL;
iovec->npages = 0;
@@ -1354,54 +1353,116 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,
return diff;
}
+/*
+ * SDMA tx request completion callback. Called when the SDMA progress
+ * state machine gets notification that the SDMA descriptors for this
+ * tx request have been processed by the DMA engine. Called in
+ * interrupt context.
+ */
static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status,
int drain)
{
struct user_sdma_txreq *tx =
container_of(txreq, struct user_sdma_txreq, txreq);
- struct user_sdma_request *req = tx->req;
- struct hfi1_user_sdma_pkt_q *pq = req ? req->pq : NULL;
- u64 tx_seqnum;
+ struct user_sdma_request *req;
+ bool defer;
+ int i;
- if (unlikely(!req || !pq))
+ if (!tx->req)
return;
- /* If we have any io vectors associated with this txreq,
- * check whether they need to be 'freed'. */
- if (tx->idx != -1) {
- int i;
+ req = tx->req;
+ /*
+ * If this is the callback for the last packet of the request,
+ * queue up the request for clean up.
+ */
+ defer = (tx->seqnum == req->info.npkts - 1);
- for (i = tx->idx; i >= 0; i--) {
- if (tx->iovecs[i].flags & TXREQ_FLAGS_IOVEC_LAST_PKT)
- unpin_vector_pages(tx->iovecs[i].vec);
+ /*
+ * If we have any io vectors associated with this txreq,
+ * check whether they need to be 'freed'. We can't free them
+ * here because the unpin function needs to be able to sleep.
+ */
+ for (i = tx->idx; i >= 0; i--) {
+ if (tx->iovecs[i].flags & TXREQ_FLAGS_IOVEC_LAST_PKT) {
+ defer = true;
+ break;
}
}
- tx_seqnum = tx->seqnum;
- kmem_cache_free(pq->txreq_cache, tx);
-
+ req->status = status;
if (status != SDMA_TXREQ_S_OK) {
- dd_dev_err(pq->dd, "SDMA completion with error %d", status);
- set_comp_state(req, ERROR, status);
+ SDMA_DBG(req, "SDMA completion with error %d",
+ status);
set_bit(SDMA_REQ_HAS_ERROR, &req->flags);
- /* Do not free the request until the sender loop has ack'ed
- * the error and we've seen all txreqs. */
- if (tx_seqnum == ACCESS_ONCE(req->seqnum) &&
- test_bit(SDMA_REQ_DONE_ERROR, &req->flags)) {
- atomic_dec(&pq->n_reqs);
- user_sdma_free_request(req);
- }
+ defer = true;
+ }
+
+ /*
+ * Defer the clean up of the iovectors and the request until later
+ * so it can be done outside of interrupt context.
+ */
+ if (defer) {
+ spin_lock(&req->txcmp_lock);
+ list_add_tail(&tx->list, &req->txcmp);
+ spin_unlock(&req->txcmp_lock);
+ schedule_work(&req->worker);
} else {
- if (tx_seqnum == req->info.npkts - 1) {
- /* We've sent and completed all packets in this
- * request. Signal completion to the user */
- atomic_dec(&pq->n_reqs);
- set_comp_state(req, COMPLETE, 0);
- user_sdma_free_request(req);
+ kmem_cache_free(req->pq->txreq_cache, tx);
+ }
+}
+
+static void user_sdma_delayed_completion(struct work_struct *work)
+{
+ struct user_sdma_request *req =
+ container_of(work, struct user_sdma_request, worker);
+ struct hfi1_user_sdma_pkt_q *pq = req->pq;
+ struct user_sdma_txreq *tx = NULL;
+ unsigned long flags;
+ u64 seqnum;
+ int i;
+
+ while (1) {
+ spin_lock_irqsave(&req->txcmp_lock, flags);
+ if (!list_empty(&req->txcmp)) {
+ tx = list_first_entry(&req->txcmp,
+ struct user_sdma_txreq, list);
+ list_del(&tx->list);
+ }
+ spin_unlock_irqrestore(&req->txcmp_lock, flags);
+ if (!tx)
+ break;
+
+ for (i = tx->idx; i >= 0; i--)
+ if (tx->iovecs[i].flags & TXREQ_FLAGS_IOVEC_LAST_PKT)
+ unpin_vector_pages(req, tx->iovecs[i].vec);
+
+ seqnum = tx->seqnum;
+ kmem_cache_free(pq->txreq_cache, tx);
+ tx = NULL;
+
+ if (req->status != SDMA_TXREQ_S_OK) {
+ if (seqnum == ACCESS_ONCE(req->seqnum) &&
+ test_bit(SDMA_REQ_DONE_ERROR, &req->flags)) {
+ atomic_dec(&pq->n_reqs);
+ set_comp_state(req, ERROR, req->status);
+ user_sdma_free_request(req);
+ break;
+ }
+ } else {
+ if (seqnum == req->info.npkts - 1) {
+ atomic_dec(&pq->n_reqs);
+ set_comp_state(req, COMPLETE, 0);
+ user_sdma_free_request(req);
+ break;
+ }
}
}
- if (!atomic_read(&pq->n_reqs))
+
+ if (!atomic_read(&pq->n_reqs)) {
xchg(&pq->state, SDMA_PKT_Q_INACTIVE);
+ wake_up(&pq->wait);
+ }
}
static void user_sdma_free_request(struct user_sdma_request *req)
@@ -1422,10 +1483,8 @@ static void user_sdma_free_request(struct user_sdma_request *req)
for (i = 0; i < req->data_iovs; i++)
if (req->iovs[i].npages && req->iovs[i].pages)
- unpin_vector_pages(&req->iovs[i]);
+ unpin_vector_pages(req, &req->iovs[i]);
}
- if (req->user_proc)
- put_task_struct(req->user_proc);
kfree(req->tids);
clear_bit(SDMA_REQ_IN_USE, &req->flags);
}
diff --git a/drivers/staging/rdma/hfi1/user_sdma.h b/drivers/staging/rdma/hfi1/user_sdma.h
index fa4422553e23..0afa28508a8a 100644
--- a/drivers/staging/rdma/hfi1/user_sdma.h
+++ b/drivers/staging/rdma/hfi1/user_sdma.h
@@ -52,15 +52,7 @@
#include "common.h"
#include "iowait.h"
-
-#define EXP_TID_TIDLEN_MASK 0x7FFULL
-#define EXP_TID_TIDLEN_SHIFT 0
-#define EXP_TID_TIDCTRL_MASK 0x3ULL
-#define EXP_TID_TIDCTRL_SHIFT 20
-#define EXP_TID_TIDIDX_MASK 0x7FFULL
-#define EXP_TID_TIDIDX_SHIFT 22
-#define EXP_TID_GET(tid, field) \
- (((tid) >> EXP_TID_TID##field##_SHIFT) & EXP_TID_TID##field##_MASK)
+#include "user_exp_rcv.h"
extern uint extended_psn;
@@ -76,6 +68,8 @@ struct hfi1_user_sdma_pkt_q {
struct user_sdma_request *reqs;
struct iowait busy;
unsigned state;
+ wait_queue_head_t wait;
+ struct mm_struct *user_mm;
};
struct hfi1_user_sdma_comp_q {
diff --git a/drivers/staging/rdma/hfi1/verbs.c b/drivers/staging/rdma/hfi1/verbs.c
index 9beb0aa876f0..ef0feaa684a4 100644
--- a/drivers/staging/rdma/hfi1/verbs.c
+++ b/drivers/staging/rdma/hfi1/verbs.c
@@ -162,6 +162,8 @@ static inline struct hfi1_ucontext *to_iucontext(struct ib_ucontext
return container_of(ibucontext, struct hfi1_ucontext, ibucontext);
}
+static inline void _hfi1_schedule_send(struct hfi1_qp *qp);
+
/*
* Translate ib_wr_opcode into ib_wc_opcode.
*/
@@ -509,9 +511,9 @@ static int post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
nreq++;
}
bail:
- if (nreq && !call_send)
- hfi1_schedule_send(qp);
spin_unlock_irqrestore(&qp->s_lock, flags);
+ if (nreq && !call_send)
+ _hfi1_schedule_send(qp);
if (nreq && call_send)
hfi1_do_send(&qp->s_iowait.iowork);
return err;
@@ -999,17 +1001,19 @@ bail_txadd:
return ret;
}
-int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc)
+int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc)
{
- struct hfi1_ibdev *dev = to_idev(qp->ibqp.device);
- struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
- struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
+ struct ahg_ib_header *ahdr = qp->s_hdr;
+ u32 hdrwords = qp->s_hdrwords;
+ struct hfi1_sge_state *ss = qp->s_cur_sge;
+ u32 len = qp->s_cur_size;
+ u32 plen = hdrwords + ((len + 3) >> 2) + 2; /* includes pbc */
+ struct hfi1_ibdev *dev = ps->dev;
+ struct hfi1_pportdata *ppd = ps->ppd;
struct verbs_txreq *tx;
struct sdma_txreq *stx;
u64 pbc_flags = 0;
- struct sdma_engine *sde;
u8 sc5 = qp->s_sc;
int ret;
@@ -1030,12 +1034,7 @@ int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
if (IS_ERR(tx))
goto bail_tx;
- if (!qp->s_hdr->sde) {
- tx->sde = sde = qp_to_sdma_engine(qp, sc5);
- if (!sde)
- goto bail_no_sde;
- } else
- tx->sde = sde = qp->s_hdr->sde;
+ tx->sde = qp->s_sde;
if (likely(pbc == 0)) {
u32 vl = sc_to_vlt(dd_from_ibdev(qp->ibqp.device), sc5);
@@ -1050,17 +1049,15 @@ int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
if (qp->s_rdma_mr)
qp->s_rdma_mr = NULL;
tx->hdr_dwords = hdrwords + 2;
- ret = build_verbs_tx_desc(sde, ss, len, tx, ahdr, pbc);
+ ret = build_verbs_tx_desc(tx->sde, ss, len, tx, ahdr, pbc);
if (unlikely(ret))
goto bail_build;
trace_output_ibhdr(dd_from_ibdev(qp->ibqp.device), &ahdr->ibh);
- ret = sdma_send_txreq(sde, &qp->s_iowait, &tx->txreq);
+ ret = sdma_send_txreq(tx->sde, &qp->s_iowait, &tx->txreq);
if (unlikely(ret == -ECOMM))
goto bail_ecomm;
return ret;
-bail_no_sde:
- hfi1_put_txreq(tx);
bail_ecomm:
/* The current one got "sent" */
return 0;
@@ -1126,12 +1123,16 @@ struct send_context *qp_to_send_context(struct hfi1_qp *qp, u8 sc5)
return dd->vld[vl].sc;
}
-int hfi1_verbs_send_pio(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc)
+int hfi1_verbs_send_pio(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc)
{
- struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
- struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
+ struct ahg_ib_header *ahdr = qp->s_hdr;
+ u32 hdrwords = qp->s_hdrwords;
+ struct hfi1_sge_state *ss = qp->s_cur_sge;
+ u32 len = qp->s_cur_size;
+ u32 dwords = (len + 3) >> 2;
+ u32 plen = hdrwords + dwords + 2; /* includes pbc */
+ struct hfi1_pportdata *ppd = ps->ppd;
u32 *hdr = (u32 *)&ahdr->ibh;
u64 pbc_flags = 0;
u32 sc5;
@@ -1303,23 +1304,18 @@ bad:
/**
* hfi1_verbs_send - send a packet
* @qp: the QP to send on
- * @ahdr: the packet header
- * @hdrwords: the number of 32-bit words in the header
- * @ss: the SGE to send
- * @len: the length of the packet in bytes
+ * @ps: the state of the packet to send
*
* Return zero if packet is sent or queued OK.
* Return non-zero and clear qp->s_flags HFI1_S_BUSY otherwise.
*/
-int hfi1_verbs_send(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len)
+int hfi1_verbs_send(struct hfi1_qp *qp, struct hfi1_pkt_state *ps)
{
struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
- u32 plen;
+ struct ahg_ib_header *ahdr = qp->s_hdr;
int ret;
int pio = 0;
unsigned long flags = 0;
- u32 dwords = (len + 3) >> 2;
/*
* VL15 packets (IB_QPT_SMI) will always use PIO, so we
@@ -1350,23 +1346,16 @@ int hfi1_verbs_send(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
return -EINVAL;
}
- /*
- * Calculate the send buffer trigger address.
- * The +2 counts for the pbc control qword
- */
- plen = hdrwords + dwords + 2;
-
if (pio) {
- ret = dd->process_pio_send(
- qp, ahdr, hdrwords, ss, len, plen, dwords, 0);
+ ret = dd->process_pio_send(qp, ps, 0);
} else {
#ifdef CONFIG_SDMA_VERBOSITY
dd_dev_err(dd, "CONFIG SDMA %s:%d %s()\n",
slashstrip(__FILE__), __LINE__, __func__);
- dd_dev_err(dd, "SDMA hdrwords = %u, len = %u\n", hdrwords, len);
+ dd_dev_err(dd, "SDMA hdrwords = %u, len = %u\n", qp->s_hdrwords,
+ qp->s_cur_size);
#endif
- ret = dd->process_dma_send(
- qp, ahdr, hdrwords, ss, len, plen, dwords, 0);
+ ret = dd->process_dma_send(qp, ps, 0);
}
return ret;
@@ -2135,28 +2124,43 @@ void hfi1_unregister_ib_device(struct hfi1_devdata *dd)
vfree(dev->lk_table.table);
}
-/*
- * This must be called with s_lock held.
- */
-void hfi1_schedule_send(struct hfi1_qp *qp)
-{
- if (hfi1_send_ok(qp)) {
- struct hfi1_ibport *ibp =
- to_iport(qp->ibqp.device, qp->port_num);
- struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
-
- iowait_schedule(&qp->s_iowait, ppd->hfi1_wq);
- }
-}
-
void hfi1_cnp_rcv(struct hfi1_packet *packet)
{
struct hfi1_ibport *ibp = &packet->rcd->ppd->ibport_data;
-
- if (packet->qp->ibqp.qp_type == IB_QPT_UC)
- hfi1_uc_rcv(packet);
- else if (packet->qp->ibqp.qp_type == IB_QPT_UD)
- hfi1_ud_rcv(packet);
- else
+ struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
+ struct hfi1_ib_header *hdr = packet->hdr;
+ struct hfi1_qp *qp = packet->qp;
+ u32 lqpn, rqpn = 0;
+ u16 rlid = 0;
+ u8 sl, sc5, sc4_bit, svc_type;
+ bool sc4_set = has_sc4_bit(packet);
+
+ switch (packet->qp->ibqp.qp_type) {
+ case IB_QPT_UC:
+ rlid = qp->remote_ah_attr.dlid;
+ rqpn = qp->remote_qpn;
+ svc_type = IB_CC_SVCTYPE_UC;
+ break;
+ case IB_QPT_RC:
+ rlid = qp->remote_ah_attr.dlid;
+ rqpn = qp->remote_qpn;
+ svc_type = IB_CC_SVCTYPE_RC;
+ break;
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ case IB_QPT_UD:
+ svc_type = IB_CC_SVCTYPE_UD;
+ break;
+ default:
ibp->n_pkt_drops++;
+ return;
+ }
+
+ sc4_bit = sc4_set << 4;
+ sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf;
+ sc5 |= sc4_bit;
+ sl = ibp->sc_to_sl[sc5];
+ lqpn = qp->ibqp.qp_num;
+
+ process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type);
}
diff --git a/drivers/staging/rdma/hfi1/verbs.h b/drivers/staging/rdma/hfi1/verbs.h
index 041ad07ee699..72106e5362b9 100644
--- a/drivers/staging/rdma/hfi1/verbs.h
+++ b/drivers/staging/rdma/hfi1/verbs.h
@@ -120,9 +120,9 @@ struct hfi1_packet;
#define HFI1_VENDOR_IPG cpu_to_be16(0xFFA0)
-#define IB_BTH_REQ_ACK (1 << 31)
-#define IB_BTH_SOLICITED (1 << 23)
-#define IB_BTH_MIG_REQ (1 << 22)
+#define IB_BTH_REQ_ACK BIT(31)
+#define IB_BTH_SOLICITED BIT(23)
+#define IB_BTH_MIG_REQ BIT(22)
#define IB_GRH_VERSION 6
#define IB_GRH_VERSION_MASK 0xF
@@ -441,7 +441,8 @@ struct hfi1_qp {
struct hfi1_swqe *s_wq; /* send work queue */
struct hfi1_mmap_info *ip;
struct ahg_ib_header *s_hdr; /* next packet header to send */
- u8 s_sc; /* SC[0..4] for next packet */
+ /* sc for UC/RC QPs - based on ah for UD */
+ u8 s_sc;
unsigned long timeout_jiffies; /* computed from timeout */
enum ib_mtu path_mtu;
@@ -489,6 +490,7 @@ struct hfi1_qp {
u32 r_psn; /* expected rcv packet sequence number */
u32 r_msn; /* message sequence number */
+ u8 r_adefered; /* number of acks defered */
u8 r_state; /* opcode of last packet received */
u8 r_flags;
u8 r_head_ack_queue; /* index into s_ack_queue[] */
@@ -544,6 +546,16 @@ struct hfi1_qp {
};
/*
+ * This structure is used to hold commonly lookedup and computed values during
+ * the send engine progress.
+ */
+struct hfi1_pkt_state {
+ struct hfi1_ibdev *dev;
+ struct hfi1_ibport *ibp;
+ struct hfi1_pportdata *ppd;
+};
+
+/*
* Atomic bit definitions for r_aflags.
*/
#define HFI1_R_WRID_VALID 0
@@ -552,11 +564,13 @@ struct hfi1_qp {
/*
* Bit definitions for r_flags.
*/
-#define HFI1_R_REUSE_SGE 0x01
-#define HFI1_R_RDMAR_SEQ 0x02
-#define HFI1_R_RSP_NAK 0x04
-#define HFI1_R_RSP_SEND 0x08
-#define HFI1_R_COMM_EST 0x10
+#define HFI1_R_REUSE_SGE 0x01
+#define HFI1_R_RDMAR_SEQ 0x02
+/* defer ack until end of interrupt session */
+#define HFI1_R_RSP_DEFERED_ACK 0x04
+/* relay ack to send engine */
+#define HFI1_R_RSP_SEND 0x08
+#define HFI1_R_COMM_EST 0x10
/*
* Bit definitions for s_flags.
@@ -846,9 +860,8 @@ static inline int hfi1_send_ok(struct hfi1_qp *qp)
/*
* This must be called with s_lock held.
*/
-void hfi1_schedule_send(struct hfi1_qp *qp);
void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
- u32 qp1, u32 qp2, __be16 lid1, __be16 lid2);
+ u32 qp1, u32 qp2, u16 lid1, u16 lid2);
void hfi1_cap_mask_chg(struct hfi1_ibport *ibp);
void hfi1_sys_guid_chg(struct hfi1_ibport *ibp);
void hfi1_node_desc_chg(struct hfi1_ibport *ibp);
@@ -927,8 +940,7 @@ int hfi1_mcast_tree_empty(struct hfi1_ibport *ibp);
struct verbs_txreq;
void hfi1_put_txreq(struct verbs_txreq *tx);
-int hfi1_verbs_send(struct hfi1_qp *qp, struct ahg_ib_header *ahdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len);
+int hfi1_verbs_send(struct hfi1_qp *qp, struct hfi1_pkt_state *ps);
void hfi1_copy_sge(struct hfi1_sge_state *ss, void *data, u32 length,
int release);
@@ -1069,8 +1081,6 @@ int hfi1_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
int hfi1_get_rwqe(struct hfi1_qp *qp, int wr_id_only);
-void hfi1_migrate_qp(struct hfi1_qp *qp);
-
int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_ib_header *hdr,
int has_grh, struct hfi1_qp *qp, u32 bth0);
@@ -1101,13 +1111,11 @@ void hfi1_ib_rcv(struct hfi1_packet *packet);
unsigned hfi1_get_npkeys(struct hfi1_devdata *);
-int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct ahg_ib_header *hdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc);
+int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc);
-int hfi1_verbs_send_pio(struct hfi1_qp *qp, struct ahg_ib_header *hdr,
- u32 hdrwords, struct hfi1_sge_state *ss, u32 len,
- u32 plen, u32 dwords, u64 pbc);
+int hfi1_verbs_send_pio(struct hfi1_qp *qp, struct hfi1_pkt_state *ps,
+ u64 pbc);
struct send_context *qp_to_send_context(struct hfi1_qp *qp, u8 sc5);
diff --git a/drivers/staging/rdma/ipath/ipath_file_ops.c b/drivers/staging/rdma/ipath/ipath_file_ops.c
index 13c3cd11ab92..6187b848b3ca 100644
--- a/drivers/staging/rdma/ipath/ipath_file_ops.c
+++ b/drivers/staging/rdma/ipath/ipath_file_ops.c
@@ -917,15 +917,15 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
chunk = pd->port_rcvegrbuf_chunks;
egrperchunk = pd->port_rcvegrbufs_perchunk;
size = pd->port_rcvegrbuf_size;
- pd->port_rcvegrbuf = kmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]),
- GFP_KERNEL);
+ pd->port_rcvegrbuf = kmalloc_array(chunk, sizeof(pd->port_rcvegrbuf[0]),
+ GFP_KERNEL);
if (!pd->port_rcvegrbuf) {
ret = -ENOMEM;
goto bail;
}
pd->port_rcvegrbuf_phys =
- kmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]),
- GFP_KERNEL);
+ kmalloc_array(chunk, sizeof(pd->port_rcvegrbuf_phys[0]),
+ GFP_KERNEL);
if (!pd->port_rcvegrbuf_phys) {
ret = -ENOMEM;
goto bail_rcvegrbuf;
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
index 3cdb40fea5ee..e5d29fe9d446 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -1240,11 +1240,6 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
return 0;
}
-static void update_bcn_fixed_ie(struct adapter *padapter)
-{
- DBG_88E("%s\n", __func__);
-}
-
static void update_bcn_erpinfo_ie(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -1279,31 +1274,6 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter)
}
}
-static void update_bcn_htcap_ie(struct adapter *padapter)
-{
- DBG_88E("%s\n", __func__);
-}
-
-static void update_bcn_htinfo_ie(struct adapter *padapter)
-{
- DBG_88E("%s\n", __func__);
-}
-
-static void update_bcn_rsn_ie(struct adapter *padapter)
-{
- DBG_88E("%s\n", __func__);
-}
-
-static void update_bcn_wpa_ie(struct adapter *padapter)
-{
- DBG_88E("%s\n", __func__);
-}
-
-static void update_bcn_wmm_ie(struct adapter *padapter)
-{
- DBG_88E("%s\n", __func__);
-}
-
static void update_bcn_wps_ie(struct adapter *padapter)
{
u8 *pwps_ie = NULL, *pwps_ie_src;
@@ -1354,22 +1324,12 @@ static void update_bcn_wps_ie(struct adapter *padapter)
kfree(pbackup_remainder_ie);
}
-static void update_bcn_p2p_ie(struct adapter *padapter)
-{
-}
-
static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
{
DBG_88E("%s\n", __func__);
- if (!memcmp(RTW_WPA_OUI, oui, 4))
- update_bcn_wpa_ie(padapter);
- else if (!memcmp(WMM_OUI, oui, 4))
- update_bcn_wmm_ie(padapter);
- else if (!memcmp(WPS_OUI, oui, 4))
+ if (!memcmp(WPS_OUI, oui, 4))
update_bcn_wps_ie(padapter);
- else if (!memcmp(P2P_OUI, oui, 4))
- update_bcn_p2p_ie(padapter);
else
DBG_88E("unknown OUI type!\n");
}
@@ -1391,24 +1351,12 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
spin_lock_bh(&pmlmepriv->bcn_update_lock);
switch (ie_id) {
- case 0xFF:
- update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
- break;
case _TIM_IE_:
update_BCNTIM(padapter);
break;
case _ERPINFO_IE_:
update_bcn_erpinfo_ie(padapter);
break;
- case _HT_CAPABILITY_IE_:
- update_bcn_htcap_ie(padapter);
- break;
- case _RSN_IE_2_:
- update_bcn_rsn_ie(padapter);
- break;
- case _HT_ADD_INFO_IE_:
- update_bcn_htinfo_ie(padapter);
- break;
case _VENDOR_SPECIFIC_IE_:
update_bcn_vendor_spec_ie(padapter, oui);
break;
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
index 9b7026e7d55b..433b926ceae7 100644
--- a/drivers/staging/rtl8188eu/core/rtw_cmd.c
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -201,23 +201,20 @@ _next:
if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) {
pcmd->res = H2C_DROPPED;
- goto post_process;
- }
-
- if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
- cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
-
- if (cmd_hdl) {
- ret = cmd_hdl(pcmd->padapter, pcmd->parmbuf);
- pcmd->res = ret;
- }
} else {
- pcmd->res = H2C_PARAMETERS_ERROR;
- }
+ if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
+ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
- cmd_hdl = NULL;
+ if (cmd_hdl) {
+ ret = cmd_hdl(pcmd->padapter, pcmd->parmbuf);
+ pcmd->res = ret;
+ }
+ } else {
+ pcmd->res = H2C_PARAMETERS_ERROR;
+ }
-post_process:
+ cmd_hdl = NULL;
+ }
/* call callback function for post-processed */
if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
@@ -242,15 +239,11 @@ post_process:
pcmdpriv->cmdthd_running = false;
/* free all cmd_obj resources */
- do {
- pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
- if (pcmd == NULL)
- break;
-
+ while ((pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue))) {
/* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */
rtw_free_cmd_obj(pcmd);
- } while (1);
+ }
up(&pcmdpriv->terminate_cmdthread_sema);
@@ -570,31 +563,19 @@ u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra n
struct setopmode_parm *psetop;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- u8 res = _SUCCESS;
-
ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
- if (ph2c == NULL) {
- res = false;
- goto exit;
- }
psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL);
-
- if (psetop == NULL) {
+ if (!ph2c || !psetop) {
kfree(ph2c);
- res = false;
- goto exit;
+ kfree(psetop);
+ return false;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
psetop->mode = (u8)networktype;
- res = rtw_enqueue_cmd(pcmdpriv, ph2c);
-
-exit:
-
-
- return res;
+ return rtw_enqueue_cmd(pcmdpriv, ph2c);
}
u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
@@ -607,28 +588,16 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct sta_info *sta = (struct sta_info *)psta;
- u8 res = _SUCCESS;
-
ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
- if (ph2c == NULL) {
- res = _FAIL;
- goto exit;
- }
-
psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
- if (psetstakey_para == NULL) {
- kfree(ph2c);
- res = _FAIL;
- goto exit;
- }
-
psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL);
- if (psetstakey_rsp == NULL) {
+
+ if (!ph2c || !psetstakey_para || !psetstakey_rsp) {
kfree(ph2c);
kfree(psetstakey_para);
- res = _FAIL;
- goto exit;
+ kfree(psetstakey_rsp);
+ return _FAIL;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
@@ -650,12 +619,7 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
/* jeff: set this because at least sw key is ready */
padapter->securitypriv.busetkipkey = true;
- res = rtw_enqueue_cmd(pcmdpriv, ph2c);
-
-exit:
-
-
- return res;
+ return rtw_enqueue_cmd(pcmdpriv, ph2c);
}
u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
@@ -1086,31 +1050,19 @@ u8 rtw_ps_cmd(struct adapter *padapter)
struct drvextra_cmd_parm *pdrvextra_cmd_parm;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- u8 res = _SUCCESS;
-
ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
- if (ppscmd == NULL) {
- res = _FAIL;
- goto exit;
- }
-
pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
- if (pdrvextra_cmd_parm == NULL) {
+ if (!ppscmd || !pdrvextra_cmd_parm) {
kfree(ppscmd);
- res = _FAIL;
- goto exit;
+ kfree(pdrvextra_cmd_parm);
+ return _FAIL;
}
pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
pdrvextra_cmd_parm->pbuf = NULL;
init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
- res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
-
-exit:
-
-
- return res;
+ return rtw_enqueue_cmd(pcmdpriv, ppscmd);
}
#ifdef CONFIG_88EU_AP_MODE
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
index eb894233a785..2320fb11af24 100644
--- a/drivers/staging/rtl8188eu/core/rtw_efuse.c
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -224,7 +224,7 @@ static void efuse_read_phymap_from_txpktbuf(
)
{
u16 dbg_addr = 0;
- u32 start = 0, passing_time = 0;
+ unsigned long start = 0;
u8 reg_0x143 = 0;
u32 lo32 = 0, hi32 = 0;
u16 len = 0, count = 0;
@@ -248,7 +248,7 @@ static void efuse_read_phymap_from_txpktbuf(
usb_write8(adapter, REG_TXPKTBUF_DBG, 0);
start = jiffies;
while (!(reg_0x143 = usb_read8(adapter, REG_TXPKTBUF_DBG)) &&
- (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
+ jiffies_to_msecs(jiffies - start) < 1000) {
DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, usb_read8(adapter, 0x106));
usleep_range(1000, 2000);
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
index 22f5b45f5f7f..cf60717a6c19 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -27,13 +27,6 @@
extern void indicate_wx_scan_complete_event(struct adapter *padapter);
-#define IS_MAC_ADDRESS_BROADCAST(addr) \
-(\
- ((addr[0] == 0xff) && (addr[1] == 0xff) && \
- (addr[2] == 0xff) && (addr[3] == 0xff) && \
- (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \
-)
-
u8 rtw_do_join(struct adapter *padapter)
{
struct list_head *plist, *phead;
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index c1b82f71b682..abab854e6889 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -163,7 +163,8 @@ exit:
static void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 isfreeall)
{
- u32 curr_time, delta_time;
+ unsigned long curr_time;
+ u32 delta_time;
u32 lifetime = SCANQUEUE_LIFETIME;
struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
@@ -272,7 +273,7 @@ int rtw_if_up(struct adapter *padapter)
void rtw_generate_random_ibss(u8 *pibss)
{
- u32 curtime = jiffies;
+ unsigned long curtime = jiffies;
pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */
pibss[1] = 0x11;
@@ -365,20 +366,13 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue)
phead = get_list_head(scanned_queue);
- plist = phead->next;
-
- while (1) {
- if (phead == plist)
- break;
-
+ for (plist = phead->next; plist != phead; plist = plist->next) {
pwlan = container_of(plist, struct wlan_network, list);
if (!pwlan->fixed) {
if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned))
oldest = pwlan;
}
-
- plist = plist->next;
}
return oldest;
}
@@ -878,14 +872,14 @@ inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted)
void rtw_scan_abort(struct adapter *adapter)
{
- u32 start;
+ unsigned long start;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
start = jiffies;
pmlmeext->scan_abort = true;
while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) &&
- rtw_get_passing_time_ms(start) <= 200) {
+ jiffies_to_msecs(jiffies - start) <= 200) {
if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
break;
DBG_88E(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
@@ -1474,6 +1468,7 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
, struct wlan_network **candidate, struct wlan_network *competitor)
{
int updated = false;
+ unsigned long since_scan;
struct adapter *adapter = container_of(pmlmepriv, struct adapter, mlmepriv);
@@ -1494,7 +1489,8 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
goto exit;
if (pmlmepriv->to_roaming) {
- if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= RTW_SCAN_RESULT_EXPIRE ||
+ since_scan = jiffies - competitor->last_scanned;
+ if (jiffies_to_msecs(since_scan) >= RTW_SCAN_RESULT_EXPIRE ||
is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) == false)
goto exit;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index d900546b672f..3eca6874b6df 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -609,7 +609,7 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da)
return;
}
-static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack)
+static int issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, bool wait_ack)
{
int ret = _FAIL;
struct xmit_frame *pmgntframe;
@@ -702,22 +702,16 @@ exit:
return ret;
}
-static inline void issue_probereq(struct adapter *padapter,
- struct ndis_802_11_ssid *pssid, u8 *da)
-{
- _issue_probereq(padapter, pssid, da, false);
-}
-
static int issue_probereq_ex(struct adapter *padapter,
struct ndis_802_11_ssid *pssid, u8 *da,
int try_cnt, int wait_ms)
{
int ret;
int i = 0;
- u32 start = jiffies;
+ unsigned long start = jiffies;
do {
- ret = _issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false);
+ ret = issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false);
i++;
@@ -738,11 +732,13 @@ static int issue_probereq_ex(struct adapter *padapter,
if (da)
DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
else
DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
}
exit:
return ret;
@@ -1299,7 +1295,7 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow
{
int ret;
int i = 0;
- u32 start = jiffies;
+ unsigned long start = jiffies;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
@@ -1329,11 +1325,13 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow
if (da)
DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
else
DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
}
exit:
return ret;
@@ -1424,7 +1422,7 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int
{
int ret;
int i = 0;
- u32 start = jiffies;
+ unsigned long start = jiffies;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
@@ -1454,11 +1452,13 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int
if (da)
DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
else
DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
}
exit:
return ret;
@@ -1536,7 +1536,7 @@ static int issue_deauth_ex(struct adapter *padapter, u8 *da,
{
int ret;
int i = 0;
- u32 start = jiffies;
+ unsigned long start = jiffies;
do {
ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? true : false);
@@ -1559,11 +1559,13 @@ static int issue_deauth_ex(struct adapter *padapter, u8 *da,
if (da)
DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
else
DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt,
+ jiffies_to_msecs(jiffies - start));
}
exit:
return ret;
@@ -1965,7 +1967,7 @@ unsigned int send_beacon(struct adapter *padapter)
int issue = 0;
int poll = 0;
- u32 start = jiffies;
+ unsigned long start = jiffies;
rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
do {
@@ -1981,13 +1983,16 @@ unsigned int send_beacon(struct adapter *padapter)
if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
return _FAIL;
if (!bxmitok) {
- DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start));
+ DBG_88E("%s fail! %u ms\n", __func__,
+ jiffies_to_msecs(jiffies - start));
return _FAIL;
} else {
- u32 passing_time = rtw_get_passing_time_ms(start);
+ u32 passing_time = jiffies_to_msecs(jiffies - start);
if (passing_time > 100 || issue > 3)
- DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start));
+ DBG_88E("%s success, issue:%d, poll:%d, %u ms\n",
+ __func__, issue, poll,
+ jiffies_to_msecs(jiffies - start));
return _SUCCESS;
}
}
@@ -2029,24 +2034,28 @@ static void site_survey(struct adapter *padapter)
for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
/* todo: to issue two probe req??? */
- issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+ issue_probereq(padapter,
+ &(pmlmeext->sitesurvey_res.ssid[i]),
+ NULL, false);
/* msleep(SURVEY_TO>>1); */
- issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+ issue_probereq(padapter,
+ &(pmlmeext->sitesurvey_res.ssid[i]),
+ NULL, false);
}
}
if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
/* todo: to issue two probe req??? */
- issue_probereq(padapter, NULL, NULL);
+ issue_probereq(padapter, NULL, NULL, false);
/* msleep(SURVEY_TO>>1); */
- issue_probereq(padapter, NULL, NULL);
+ issue_probereq(padapter, NULL, NULL, false);
}
if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
/* todo: to issue two probe req??? */
- issue_probereq(padapter, NULL, NULL);
+ issue_probereq(padapter, NULL, NULL, false);
/* msleep(SURVEY_TO>>1); */
- issue_probereq(padapter, NULL, NULL);
+ issue_probereq(padapter, NULL, NULL, false);
}
}
@@ -4820,9 +4829,18 @@ void linked_status_chk(struct adapter *padapter)
} else {
if (rx_chk != _SUCCESS) {
if (pmlmeext->retry == 0) {
- issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
- issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
- issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+ issue_probereq(padapter,
+ &pmlmeinfo->network.Ssid,
+ pmlmeinfo->network.MacAddress,
+ false);
+ issue_probereq(padapter,
+ &pmlmeinfo->network.Ssid,
+ pmlmeinfo->network.MacAddress,
+ false);
+ issue_probereq(padapter,
+ &pmlmeinfo->network.Ssid,
+ pmlmeinfo->network.MacAddress,
+ false);
}
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
index 9765946466ab..5e1ef9fdcf47 100644
--- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
@@ -348,7 +348,7 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
static u8 PS_RDY_CHECK(struct adapter *padapter)
{
- u32 curr_time, delta_time;
+ unsigned long curr_time, delta_time;
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -418,7 +418,7 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
*/
s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
{
- u32 start_time;
+ unsigned long start_time;
u8 bAwake = false;
s32 err = 0;
@@ -435,7 +435,7 @@ s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
break;
}
- if (rtw_get_passing_time_ms(start_time) > delay_ms) {
+ if (jiffies_to_msecs(jiffies - start_time) > delay_ms) {
err = -1;
DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
break;
@@ -561,24 +561,24 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
unsigned long expires;
+ unsigned long start;
int ret = _SUCCESS;
expires = jiffies + msecs_to_jiffies(ips_deffer_ms);
if (time_before(pwrpriv->ips_deny_time, expires))
pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
-{
- u32 start = jiffies;
+ start = jiffies;
if (pwrpriv->ps_processing) {
DBG_88E("%s wait ps_processing...\n", __func__);
- while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000)
+ while (pwrpriv->ps_processing &&
+ jiffies_to_msecs(jiffies - start) <= 3000)
usleep_range(1000, 3000);
if (pwrpriv->ps_processing)
DBG_88E("%s wait ps_processing timeout\n", __func__);
else
DBG_88E("%s wait ps_processing done\n", __func__);
}
-}
/* System suspend is not allowed to wakeup */
if ((!pwrpriv->bInternalAutoSuspend) && (pwrpriv->bInSuspend)) {
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index cabb810369bd..e778132b73dc 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -641,7 +641,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
if (pattrib->psta)
stainfo = pattrib->psta;
else
- stainfo = rtw_get_stainfo(&padapter->stapriv , &pattrib->ra[0]);
+ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);
@@ -1702,12 +1702,12 @@ u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe)
return addr;
}
-static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib)
+static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib)
{
u8 qsel;
qsel = pattrib->priority;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority=%d , qsel = %d\n", pattrib->priority , qsel));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority=%d , qsel = %d\n", pattrib->priority, qsel));
pattrib->qsel = qsel;
}
@@ -2186,11 +2186,6 @@ void rtw_sctx_done_err(struct submit_ctx **sctx, int status)
}
}
-void rtw_sctx_done(struct submit_ctx **sctx)
-{
- rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS);
-}
-
int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms)
{
struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
diff --git a/drivers/staging/rtl8188eu/hal/fw.c b/drivers/staging/rtl8188eu/hal/fw.c
index 23aa6d37acac..4d72537644b3 100644
--- a/drivers/staging/rtl8188eu/hal/fw.c
+++ b/drivers/staging/rtl8188eu/hal/fw.c
@@ -58,43 +58,31 @@ static void _rtl88e_fw_block_write(struct adapter *adapt,
const u8 *buffer, u32 size)
{
u32 blk_sz = sizeof(u32);
- u8 *buf_ptr = (u8 *)buffer;
- u32 *pu4BytePtr = (u32 *)buffer;
- u32 i, offset, blk_cnt, remain;
+ const u8 *byte_buffer;
+ const u32 *dword_buffer = (u32 *)buffer;
+ u32 i, write_address, blk_cnt, remain;
blk_cnt = size / blk_sz;
remain = size % blk_sz;
- for (i = 0; i < blk_cnt; i++) {
- offset = i * blk_sz;
- usb_write32(adapt, (FW_8192C_START_ADDRESS + offset),
- *(pu4BytePtr + i));
- }
+ write_address = FW_8192C_START_ADDRESS;
- if (remain) {
- offset = blk_cnt * blk_sz;
- buf_ptr += offset;
- for (i = 0; i < remain; i++) {
- usb_write8(adapt, (FW_8192C_START_ADDRESS +
- offset + i), *(buf_ptr + i));
- }
- }
+ for (i = 0; i < blk_cnt; i++, write_address += blk_sz)
+ usb_write32(adapt, write_address, dword_buffer[i]);
+
+ byte_buffer = buffer + blk_cnt * blk_sz;
+ for (i = 0; i < remain; i++, write_address++)
+ usb_write8(adapt, write_address, byte_buffer[i]);
}
static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
{
- u32 fwlen = *pfwlen;
- u8 remain = (u8)(fwlen % 4);
-
- remain = (remain == 0) ? 0 : (4 - remain);
+ u32 i;
- while (remain > 0) {
- pfwbuf[fwlen] = 0;
- fwlen++;
- remain--;
- }
+ for (i = *pfwlen; i < roundup(*pfwlen, 4); i++)
+ pfwbuf[i] = 0;
- *pfwlen = fwlen;
+ *pfwlen = i;
}
static void _rtl88e_fw_page_write(struct adapter *adapt,
diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c
index 38e9fdc312d3..3871cda2eec2 100644
--- a/drivers/staging/rtl8188eu/hal/hal_com.c
+++ b/drivers/staging/rtl8188eu/hal/hal_com.c
@@ -32,19 +32,19 @@ void dump_chip_info(struct HAL_VERSION chip_vers)
char buf[128];
cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_");
- cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ?
+ cnt += sprintf((buf+cnt), "%s_", chip_vers.ChipType == NORMAL_CHIP ?
"Normal_Chip" : "Test_Chip");
- cnt += sprintf((buf+cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ?
+ cnt += sprintf((buf+cnt), "%s_", chip_vers.VendorType == CHIP_VENDOR_TSMC ?
"TSMC" : "UMC");
- if (IS_A_CUT(chip_vers))
+ if (chip_vers.CUTVersion == A_CUT_VERSION)
cnt += sprintf((buf+cnt), "A_CUT_");
- else if (IS_B_CUT(chip_vers))
+ else if (chip_vers.CUTVersion == B_CUT_VERSION)
cnt += sprintf((buf+cnt), "B_CUT_");
- else if (IS_C_CUT(chip_vers))
+ else if (chip_vers.CUTVersion == C_CUT_VERSION)
cnt += sprintf((buf+cnt), "C_CUT_");
- else if (IS_D_CUT(chip_vers))
+ else if (chip_vers.CUTVersion == D_CUT_VERSION)
cnt += sprintf((buf+cnt), "D_CUT_");
- else if (IS_E_CUT(chip_vers))
+ else if (chip_vers.CUTVersion == E_CUT_VERSION)
cnt += sprintf((buf+cnt), "E_CUT_");
else
cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_",
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
index fca590949409..199a77acd7a9 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
@@ -67,7 +67,7 @@ static void Init_ODM_ComInfo_88E(struct adapter *Adapter)
ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_FAB_VER, fab_ver);
ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_CUT_VER, cut_ver);
- ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(hal_data->VersionID));
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_MP_TEST_CHIP, hal_data->VersionID.ChipType == NORMAL_CHIP ? true : false);
ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PATCH_ID, hal_data->CustomerID);
ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec);
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index e3e5d6f5d4f9..2592bc298f84 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -53,7 +53,7 @@ s32 iol_execute(struct adapter *padapter, u8 control)
{
s32 status = _FAIL;
u8 reg_0x88 = 0;
- u32 start = 0, passing_time = 0;
+ unsigned long start = 0;
control = control&0x0f;
reg_0x88 = usb_read8(padapter, REG_HMEBOX_E0);
@@ -61,8 +61,8 @@ s32 iol_execute(struct adapter *padapter, u8 control)
start = jiffies;
while ((reg_0x88 = usb_read8(padapter, REG_HMEBOX_E0)) & control &&
- (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
- ;
+ jiffies_to_msecs(jiffies - start) < 1000) {
+ udelay(5);
}
reg_0x88 = usb_read8(padapter, REG_HMEBOX_E0);
@@ -242,6 +242,7 @@ static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data)
status = _FAIL;
break;
}
+ udelay(5);
} while (count++);
return status;
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
index 7c5086ecff17..e04303ce80af 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
@@ -463,30 +463,26 @@ s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitp
}
/* 3 1. pick up first frame */
- do {
- rtw_free_xmitframe(pxmitpriv, pxmitframe);
-
- pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
- if (pxmitframe == NULL) {
- /* no more xmit frame, release xmit buffer */
- rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
- return false;
- }
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
- pxmitframe->pxmitbuf = pxmitbuf;
- pxmitframe->buf_addr = pxmitbuf->pbuf;
- pxmitbuf->priv_data = pxmitframe;
+ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+ if (pxmitframe == NULL) {
+ /* no more xmit frame, release xmit buffer */
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+ return false;
+ }
- pxmitframe->agg_num = 1; /* alloc xmitframe should assign to 1. */
- pxmitframe->pkt_offset = 1; /* first frame of aggregation, reserve offset */
+ pxmitframe->pxmitbuf = pxmitbuf;
+ pxmitframe->buf_addr = pxmitbuf->pbuf;
+ pxmitbuf->priv_data = pxmitframe;
- rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+ pxmitframe->agg_num = 1; /* alloc xmitframe should assign to 1. */
+ pxmitframe->pkt_offset = 1; /* first frame of aggregation, reserve offset */
- /* always return ndis_packet after rtw_xmitframe_coalesce */
- rtw_os_xmit_complete(adapt, pxmitframe);
+ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
- break;
- } while (1);
+ /* always return ndis_packet after rtw_xmitframe_coalesce */
+ rtw_os_xmit_complete(adapt, pxmitframe);
/* 3 2. aggregate same priority and same DA(AP or STA) frames */
pfirstframe = pxmitframe;
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index 7e72259f0e40..5789e1e23f0a 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -684,7 +684,7 @@ static u32 rtl8188eu_hal_init(struct adapter *Adapter)
struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
struct registry_priv *pregistrypriv = &Adapter->registrypriv;
- u32 init_start_time = jiffies;
+ unsigned long init_start_time = jiffies;
#define HAL_INIT_PROFILE_TAG(stage) do {} while (0)
@@ -903,7 +903,8 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK);
exit:
HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
- DBG_88E("%s in %dms\n", __func__, rtw_get_passing_time_ms(init_start_time));
+ DBG_88E("%s in %dms\n", __func__,
+ jiffies_to_msecs(jiffies - init_start_time));
return status;
@@ -1149,14 +1150,15 @@ static void _ReadRFType(struct adapter *Adapter)
static void _ReadAdapterInfo8188EU(struct adapter *Adapter)
{
- u32 start = jiffies;
+ unsigned long start = jiffies;
MSG_88E("====> %s\n", __func__);
_ReadRFType(Adapter);/* rf_chip -> _InitRFType() */
_ReadPROMContent(Adapter);
- MSG_88E("<==== %s in %d ms\n", __func__, rtw_get_passing_time_ms(start));
+ MSG_88E("<==== %s in %d ms\n", __func__,
+ jiffies_to_msecs(jiffies - start));
}
#define GPIO_DEBUG_PORT_NUM 0
diff --git a/drivers/staging/rtl8188eu/include/HalVerDef.h b/drivers/staging/rtl8188eu/include/HalVerDef.h
index 56b4ff08e509..6f2b2a436b04 100644
--- a/drivers/staging/rtl8188eu/include/HalVerDef.h
+++ b/drivers/staging/rtl8188eu/include/HalVerDef.h
@@ -47,37 +47,4 @@ struct HAL_VERSION {
enum HAL_VENDOR VendorType;
};
-/* Get element */
-#define GET_CVID_CHIP_TYPE(version) (((version).ChipType))
-#define GET_CVID_MANUFACTUER(version) (((version).VendorType))
-#define GET_CVID_CUT_VERSION(version) (((version).CUTVersion))
-
-/* Common Macro. -- */
-/* HAL_VERSION VersionID */
-
-/* HAL_CHIP_TYPE_E */
-#define IS_TEST_CHIP(version) \
- ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false)
-#define IS_NORMAL_CHIP(version) \
- ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false)
-
-/* HAL_CUT_VERSION_E */
-#define IS_A_CUT(version) \
- ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false)
-#define IS_B_CUT(version) \
- ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false)
-#define IS_C_CUT(version) \
- ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false)
-#define IS_D_CUT(version) \
- ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? true : false)
-#define IS_E_CUT(version) \
- ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? true : false)
-
-
-/* HAL_VENDOR_E */
-#define IS_CHIP_VENDOR_TSMC(version) \
- ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false)
-#define IS_CHIP_VENDOR_UMC(version) \
- ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false)
-
#endif
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
index e24fe8cc3d0b..22de53d6539a 100644
--- a/drivers/staging/rtl8188eu/include/osdep_service.h
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -87,8 +87,6 @@ u32 _rtw_down_sema(struct semaphore *sema);
void _rtw_init_queue(struct __queue *pqueue);
-s32 rtw_get_passing_time_ms(u32 start);
-
struct rtw_netdev_priv_indicator {
void *priv;
u32 sizeof_priv;
diff --git a/drivers/staging/rtl8188eu/include/rtw_xmit.h b/drivers/staging/rtl8188eu/include/rtw_xmit.h
index 62f5db169523..b7c20883d355 100644
--- a/drivers/staging/rtl8188eu/include/rtw_xmit.h
+++ b/drivers/staging/rtl8188eu/include/rtw_xmit.h
@@ -197,7 +197,6 @@ enum {
void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms);
int rtw_sctx_wait(struct submit_ctx *sctx);
void rtw_sctx_done_err(struct submit_ctx **sctx, int status);
-void rtw_sctx_done(struct submit_ctx **sctx);
struct xmit_buf {
struct list_head list;
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
index d063d02db7f0..9201b94d017c 100644
--- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -1100,7 +1100,7 @@ netdev_open_error:
int rtw_ips_pwr_up(struct adapter *padapter)
{
int result;
- u32 start_time = jiffies;
+ unsigned long start_time = jiffies;
DBG_88E("===> rtw_ips_pwr_up..............\n");
rtw_reset_drv_sw(padapter);
@@ -1109,13 +1109,14 @@ int rtw_ips_pwr_up(struct adapter *padapter)
rtw_led_control(padapter, LED_CTL_NO_LINK);
- DBG_88E("<=== rtw_ips_pwr_up.............. in %dms\n", rtw_get_passing_time_ms(start_time));
+ DBG_88E("<=== rtw_ips_pwr_up.............. in %dms\n",
+ jiffies_to_msecs(jiffies - start_time));
return result;
}
void rtw_ips_pwr_down(struct adapter *padapter)
{
- u32 start_time = jiffies;
+ unsigned long start_time = jiffies;
DBG_88E("===> rtw_ips_pwr_down...................\n");
@@ -1124,7 +1125,8 @@ void rtw_ips_pwr_down(struct adapter *padapter)
rtw_led_control(padapter, LED_CTL_POWER_OFF);
rtw_ips_dev_unload(padapter);
- DBG_88E("<=== rtw_ips_pwr_down..................... in %dms\n", rtw_get_passing_time_ms(start_time));
+ DBG_88E("<=== rtw_ips_pwr_down..................... in %dms\n",
+ jiffies_to_msecs(jiffies - start_time));
}
void rtw_ips_dev_unload(struct adapter *padapter)
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
index 466cd76fc1c4..d87b54711c0d 100644
--- a/drivers/staging/rtl8188eu/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -77,12 +77,6 @@ void _rtw_init_queue(struct __queue *pqueue)
spin_lock_init(&(pqueue->lock));
}
-/* the input parameter start must be in jiffies */
-inline s32 rtw_get_passing_time_ms(u32 start)
-{
- return jiffies_to_msecs(jiffies-start);
-}
-
struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv,
void *old_priv)
{
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index 82a7c27c517f..01d50f7c1667 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -227,7 +227,7 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
struct net_device *pnetdev = padapter->pnetdev;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- u32 start_time = jiffies;
+ unsigned long start_time = jiffies;
pr_debug("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
@@ -282,7 +282,7 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
exit:
pr_debug("<=== %s .............. in %dms\n", __func__,
- rtw_get_passing_time_ms(start_time));
+ jiffies_to_msecs(jiffies - start_time));
return 0;
}
@@ -292,7 +292,7 @@ static int rtw_resume_process(struct adapter *padapter)
struct net_device *pnetdev;
struct pwrctrl_priv *pwrpriv = NULL;
int ret = -1;
- u32 start_time = jiffies;
+ unsigned long start_time = jiffies;
pr_debug("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
@@ -323,7 +323,7 @@ exit:
if (pwrpriv)
pwrpriv->bInSuspend = false;
pr_debug("<=== %s return %d.............. in %dms\n", __func__,
- ret, rtw_get_passing_time_ms(start_time));
+ ret, jiffies_to_msecs(jiffies - start_time));
return ret;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index 0b407feb5407..5e3bbe5c3ca4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -90,13 +90,12 @@ void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask,
u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask)
{
- u32 Ret = 0, OriginalValue, BitShift;
+ u32 OriginalValue, BitShift;
OriginalValue = rtl92e_readl(dev, dwRegAddr);
BitShift = _rtl92e_calculate_bit_shift(dwBitMask);
- Ret = (OriginalValue & dwBitMask) >> BitShift;
- return Ret;
+ return (OriginalValue & dwBitMask) >> BitShift;
}
static u32 _rtl92e_phy_rf_read(struct net_device *dev,
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index e06864f64beb..f4a4eae72aa4 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -5114,21 +5114,6 @@ static void __exit rtl8192_usb_module_exit(void)
RT_TRACE(COMP_DOWN, "Exiting");
}
-
-void rtl8192_try_wake_queue(struct net_device *dev, int pri)
-{
- unsigned long flags;
- short enough_desc;
- struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
-
- spin_lock_irqsave(&priv->tx_lock, flags);
- enough_desc = check_nic_enough_desc(dev, pri);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
-
- if (enough_desc)
- ieee80211_wake_queue(priv->ieee80211);
-}
-
void EnableHWSecurityConfig8192(struct net_device *dev)
{
u8 SECR_value = 0x0;
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index 70656441c145..f264d88364a1 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -38,21 +38,6 @@ static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
#define rtl819XAGCTAB_Array Rtl8192UsbAGCTAB_Array
/******************************************************************************
- * function: This function reads BB parameters from header file we generate,
- * and does register read/write
- * input: u32 bitmask //taget bit pos in the addr to be modified
- * output: none
- * return: u32 return the shift bit position of the mask
- ******************************************************************************/
-static u32 rtl8192_CalculateBitShift(u32 bitmask)
-{
- u32 i;
-
- i = ffs(bitmask) - 1;
- return i;
-}
-
-/******************************************************************************
* function: This function checks different RF type to execute legal judgement.
* If RF Path is illegal, we will return false.
* input: net_device *dev
@@ -94,7 +79,7 @@ void rtl8192_setBBreg(struct net_device *dev, u32 reg_addr, u32 bitmask,
if (bitmask != bMaskDWord) {
read_nic_dword(dev, reg_addr, &reg);
- bitshift = rtl8192_CalculateBitShift(bitmask);
+ bitshift = ffs(bitmask) - 1;
reg &= ~bitmask;
reg |= data << bitshift;
write_nic_dword(dev, reg_addr, reg);
@@ -117,7 +102,7 @@ u32 rtl8192_QueryBBReg(struct net_device *dev, u32 reg_addr, u32 bitmask)
u32 reg, bitshift;
read_nic_dword(dev, reg_addr, &reg);
- bitshift = rtl8192_CalculateBitShift(bitmask);
+ bitshift = ffs(bitmask) - 1;
return (reg & bitmask) >> bitshift;
}
@@ -306,7 +291,7 @@ void rtl8192_phy_SetRFReg(struct net_device *dev, RF90_RADIO_PATH_E eRFPath,
if (bitmask != bMask12Bits) {
/* RF data is 12 bits only */
reg = phy_FwRFSerialRead(dev, eRFPath, reg_addr);
- bitshift = rtl8192_CalculateBitShift(bitmask);
+ bitshift = ffs(bitmask) - 1;
reg &= ~bitmask;
reg |= data << bitshift;
@@ -321,7 +306,7 @@ void rtl8192_phy_SetRFReg(struct net_device *dev, RF90_RADIO_PATH_E eRFPath,
if (bitmask != bMask12Bits) {
/* RF data is 12 bits only */
reg = rtl8192_phy_RFSerialRead(dev, eRFPath, reg_addr);
- bitshift = rtl8192_CalculateBitShift(bitmask);
+ bitshift = ffs(bitmask) - 1;
reg &= ~bitmask;
reg |= data << bitshift;
@@ -356,7 +341,7 @@ u32 rtl8192_phy_QueryRFReg(struct net_device *dev, RF90_RADIO_PATH_E eRFPath,
} else {
reg = rtl8192_phy_RFSerialRead(dev, eRFPath, reg_addr);
}
- bitshift = rtl8192_CalculateBitShift(bitmask);
+ bitshift = ffs(bitmask) - 1;
reg = (reg & bitmask) >> bitshift;
return reg;
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index a4a002b55128..04f727fc95ea 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -123,7 +123,7 @@ static void _free_network(struct mlme_priv *pmlmepriv,
spin_unlock_irqrestore(&free_queue->lock, irqL);
}
-static void _free_network_nolock(struct mlme_priv *pmlmepriv,
+static void free_network_nolock(struct mlme_priv *pmlmepriv,
struct wlan_network *pnetwork)
{
struct __queue *free_queue = &pmlmepriv->free_bss_pool;
@@ -234,12 +234,6 @@ static struct wlan_network *alloc_network(struct mlme_priv *pmlmepriv)
return _r8712_alloc_network(pmlmepriv);
}
-static void free_network_nolock(struct mlme_priv *pmlmepriv,
- struct wlan_network *pnetwork)
-{
- _free_network_nolock(pmlmepriv, pnetwork);
-}
-
void r8712_free_network_queue(struct _adapter *dev)
{
_free_network_queue(dev);
diff --git a/drivers/staging/rtl8723au/core/rtw_efuse.c b/drivers/staging/rtl8723au/core/rtw_efuse.c
index 906b5782d165..f174b4d1a018 100644
--- a/drivers/staging/rtl8723au/core/rtw_efuse.c
+++ b/drivers/staging/rtl8723au/core/rtw_efuse.c
@@ -273,48 +273,6 @@ u8 EFUSE_Read1Byte23a(struct rtw_adapter *Adapter, u16 Address)
return 0xFF;
}
-/* Copy from WMAC fot EFUSE write 1 byte. */
-void EFUSE_Write1Byte(struct rtw_adapter *Adapter, u16 Address, u8 Value)
-{
- u8 Bytetemp = {0x00};
- u8 temp = {0x00};
- u32 k = 0;
- u16 contentLen = 0;
-
- EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI,
- TYPE_EFUSE_REAL_CONTENT_LEN,
- (void *)&contentLen);
-
- if (Address < contentLen) { /* E-fuse 512Byte */
- rtl8723au_write8(Adapter, EFUSE_CTRL, Value);
-
- /* Write E-fuse Register address bit0~7 */
- temp = Address & 0xFF;
- rtl8723au_write8(Adapter, EFUSE_CTRL+1, temp);
- Bytetemp = rtl8723au_read8(Adapter, EFUSE_CTRL+2);
-
- /* Write E-fuse Register address bit8~9 */
- temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
- rtl8723au_write8(Adapter, EFUSE_CTRL+2, temp);
-
- /* Write 0x30[31]= 1 */
- Bytetemp = rtl8723au_read8(Adapter, EFUSE_CTRL+3);
- temp = Bytetemp | 0x80;
- rtl8723au_write8(Adapter, EFUSE_CTRL+3, temp);
-
- /* Wait Write-ready (0x30[31]= 0) */
- Bytetemp = rtl8723au_read8(Adapter, EFUSE_CTRL+3);
- while (Bytetemp & 0x80) {
- Bytetemp = rtl8723au_read8(Adapter, EFUSE_CTRL+3);
- k++;
- if (k == 100) {
- k = 0;
- break;
- }
- }
- }
-}
-
/* Read one byte from real Efuse. */
int efuse_OneByteRead23a(struct rtw_adapter *pAdapter, u16 addr, u8 *data)
{
@@ -501,7 +459,8 @@ int rtw_BT_efuse_map_read23a(struct rtw_adapter *padapter,
}
/* Read All Efuse content */
-void Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse)
+static void Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType,
+ u8 *Efuse)
{
u16 mapLen = 0;
diff --git a/drivers/staging/sm750fb/modedb.h b/drivers/staging/sm750fb/modedb.h
deleted file mode 100644
index 83cb2e2ae51a..000000000000
--- a/drivers/staging/sm750fb/modedb.h
+++ /dev/null
@@ -1,233 +0,0 @@
-
-static const struct fb_videomode modedb2[] = {
- {
- /* 640x400 @ 70 Hz, 31.5 kHz hsync */
- NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 640x480 @ 60 Hz, 31.5 kHz hsync */
- NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 800x600 @ 56 Hz, 35.15 kHz hsync */
- NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
- NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8,
- 0, FB_VMODE_INTERLACED
- }, {
- /* 640x400 @ 85 Hz, 37.86 kHz hsync */
- NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
- FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
- /* 640x480 @ 72 Hz, 36.5 kHz hsync */
- NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 640x480 @ 75 Hz, 37.50 kHz hsync */
- NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 800x600 @ 60 Hz, 37.8 kHz hsync */
- NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 640x480 @ 85 Hz, 43.27 kHz hsync */
- NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
- NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10,
- 0, FB_VMODE_INTERLACED
- }, {
- /* 800x600 @ 72 Hz, 48.0 kHz hsync */
- NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1024x768 @ 60 Hz, 48.4 kHz hsync */
- NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 640x480 @ 100 Hz, 53.01 kHz hsync */
- NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1152x864 @ 60 Hz, 53.5 kHz hsync */
- NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 800x600 @ 85 Hz, 55.84 kHz hsync */
- NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1024x768 @ 70 Hz, 56.5 kHz hsync */
- NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1280x960-60 VESA */
- NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA
- }, {
- /* 1280x1024-60 VESA */
- NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA
- }, {
- /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
- NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12,
- 0, FB_VMODE_INTERLACED
- }, {
- /* 800x600 @ 100 Hz, 64.02 kHz hsync */
- NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1024x768 @ 76 Hz, 62.5 kHz hsync */
- NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1152x864 @ 70 Hz, 62.4 kHz hsync */
- NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
- NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1400x1050 @ 60Hz, 63.9 kHz hsync */
- NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
- NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
- NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1024x768 @ 85 Hz, 70.24 kHz hsync */
- NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1152x864 @ 78 Hz, 70.8 kHz hsync */
- NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
- NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1600x1200 @ 60Hz, 75.00 kHz hsync */
- NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1152x864 @ 84 Hz, 76.0 kHz hsync */
- NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
- NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1024x768 @ 100Hz, 80.21 kHz hsync */
- NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
- NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
- NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1152x864 @ 100 Hz, 89.62 kHz hsync */
- NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
- NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
- NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
- NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
- NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 1800x1440 @ 64Hz, 96.15 kHz hsync */
- NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 1800x1440 @ 70Hz, 104.52 kHz hsync */
- NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
- /* 512x384 @ 78 Hz, 31.50 kHz hsync */
- NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 512x384 @ 85 Hz, 34.38 kHz hsync */
- NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
- NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
- NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 320x240 @ 72 Hz, 36.5 kHz hsync */
- NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
- NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 400x300 @ 60 Hz, 37.8 kHz hsync */
- NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 400x300 @ 72 Hz, 48.0 kHz hsync */
- NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
- NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 480x300 @ 60 Hz, 37.8 kHz hsync */
- NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 480x300 @ 63 Hz, 39.6 kHz hsync */
- NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2,
- 0, FB_VMODE_DOUBLE
- }, {
- /* 480x300 @ 72 Hz, 48.0 kHz hsync */
- NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3,
- 0, FB_VMODE_DOUBLE
- },
-};
-static const int nmodedb2 = sizeof(modedb2);
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 860e1c288ad5..c78421b5b0e7 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -21,8 +21,6 @@
#include "sm750_accel.h"
#include "sm750_cursor.h"
-#include "modedb.h"
-
/*
* #ifdef __BIG_ENDIAN
* ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf,
diff --git a/drivers/staging/unisys/include/channel.h b/drivers/staging/unisys/include/channel.h
index c6c24423a7f0..5af59a5fce61 100644
--- a/drivers/staging/unisys/include/channel.h
+++ b/drivers/staging/unisys/include/channel.h
@@ -60,15 +60,19 @@ enum channel_clientstate {
CHANNELCLI_DISABLED = 1, /* client can see channel but is NOT
* allowed to use it unless given TBD
* explicit request (should actually be
- * < DETACHED) */
+ * < DETACHED)
+ */
CHANNELCLI_ATTACHING = 2, /* legacy EFI client request
- * for EFI server to attach */
+ * for EFI server to attach
+ */
CHANNELCLI_ATTACHED = 3, /* idle, but client may want
- * to use channel any time */
+ * to use channel any time
+ */
CHANNELCLI_BUSY = 4, /* client either wants to use or is
- * using channel */
- CHANNELCLI_OWNED = 5 /* "no worries" state - client can
- * access channel anytime */
+ * using channel
+ */
+ CHANNELCLI_OWNED = 5 /* "no worries" state - client can */
+ /* access channel anytime */
};
static inline const u8 *
@@ -116,11 +120,13 @@ ULTRA_CHANNELCLI_STRING(u32 v)
/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */
/* throttling invalid boot channel statetransition error due to client
- * disabled */
+ * disabled
+ */
#define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED 0x01
/* throttling invalid boot channel statetransition error due to client
- * not attached */
+ * not attached
+ */
#define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02
/* throttling invalid boot channel statetransition error due to busy channel */
@@ -128,24 +134,28 @@ ULTRA_CHANNELCLI_STRING(u32 v)
/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */
/* throttling invalid guest OS channel statetransition error due to
- * client disabled */
+ * client disabled
+ */
#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED 0x01
/* throttling invalid guest OS channel statetransition error due to
- * client not attached */
+ * client not attached
+ */
#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED 0x02
/* throttling invalid guest OS channel statetransition error due to
- * busy channel */
+ * busy channel
+ */
#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY 0x04
/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so
-* that windows guest can look at the FeatureFlags in the io channel,
-* and configure the windows driver to use interrupts or not based on
-* this setting. This flag is set in uislib after the
-* ULTRA_VHBA_init_channel is called. All feature bits for all
-* channels should be defined here. The io channel feature bits are
-* defined right here */
+ * that windows guest can look at the FeatureFlags in the io channel,
+ * and configure the windows driver to use interrupts or not based on
+ * this setting. This flag is set in uislib after the
+ * ULTRA_VHBA_init_channel is called. All feature bits for all
+ * channels should be defined here. The io channel feature bits are
+ * defined right here
+ */
#define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1)
#define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3)
#define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4)
@@ -156,7 +166,7 @@ ULTRA_CHANNELCLI_STRING(u32 v)
struct channel_header {
u64 signature; /* Signature */
u32 legacy_state; /* DEPRECATED - being replaced by */
- /* / SrvState, CliStateBoot, and CliStateOS below */
+ /* SrvState, CliStateBoot, and CliStateOS below */
u32 header_size; /* sizeof(struct channel_header) */
u64 size; /* Total size of this channel in bytes */
u64 features; /* Flags to modify behavior */
@@ -169,25 +179,32 @@ struct channel_header {
uuid_le zone_uuid; /* Guid of Channel's zone */
u32 cli_str_offset; /* offset from channel header to
* nul-terminated ClientString (0 if
- * ClientString not present) */
+ * ClientString not present)
+ */
u32 cli_state_boot; /* CHANNEL_CLIENTSTATE of pre-boot
- * EFI client of this channel */
+ * EFI client of this channel
+ */
u32 cmd_state_cli; /* CHANNEL_COMMANDSTATE (overloaded in
* Windows drivers, see ServerStateUp,
- * ServerStateDown, etc) */
+ * ServerStateDown, etc)
+ */
u32 cli_state_os; /* CHANNEL_CLIENTSTATE of Guest OS
- * client of this channel */
+ * client of this channel
+ */
u32 ch_characteristic; /* CHANNEL_CHARACTERISTIC_<xxx> */
u32 cmd_state_srv; /* CHANNEL_COMMANDSTATE (overloaded in
* Windows drivers, see ServerStateUp,
- * ServerStateDown, etc) */
+ * ServerStateDown, etc)
+ */
u32 srv_state; /* CHANNEL_SERVERSTATE */
u8 cli_error_boot; /* bits to indicate err states for
* boot clients, so err messages can
- * be throttled */
+ * be throttled
+ */
u8 cli_error_os; /* bits to indicate err states for OS
* clients, so err messages can be
- * throttled */
+ * throttled
+ */
u8 filler[1]; /* Pad out to 128 byte cacheline */
/* Please add all new single-byte values below here */
u8 recover_channel;
@@ -205,29 +222,33 @@ struct signal_queue_header {
u64 features; /* Flags to modify behavior */
u64 num_sent; /* Total # of signals placed in this queue */
u64 num_overflows; /* Total # of inserts failed due to
- * full queue */
+ * full queue
+ */
u32 signal_size; /* Total size of a signal for this queue */
u32 max_slots; /* Max # of slots in queue, 1 slot is
- * always empty */
+ * always empty
+ */
u32 max_signals; /* Max # of signals in queue
- * (MaxSignalSlots-1) */
+ * (MaxSignalSlots-1)
+ */
u32 head; /* Queue head signal # */
/* 2nd cache line */
u64 num_received; /* Total # of signals removed from this queue */
- u32 tail; /* Queue tail signal # (on separate
- * cache line) */
+ u32 tail; /* Queue tail signal */
u32 reserved1; /* Reserved field */
u64 reserved2; /* Reserved field */
u64 client_queue;
u64 num_irq_received; /* Total # of Interrupts received. This
- * is incremented by the ISR in the
- * guest windows driver */
+ * is incremented by the ISR in the
+ * guest windows driver
+ */
u64 num_empty; /* Number of times that visor_signal_remove
- * is called and returned Empty
- * Status. */
+ * is called and returned Empty Status.
+ */
u32 errorflags; /* Error bits set during SignalReinit
* to denote trouble with client's
- * fields */
+ * fields
+ */
u8 filler[12]; /* Pad out to 64 byte cacheline */
} __packed;
@@ -272,8 +293,7 @@ spar_check_channel_client(void __iomem *ch,
return 0;
}
}
- if (expected_min_bytes > 0) { /* caller wants us to verify
- * channel size */
+ if (expected_min_bytes > 0) { /* verify channel size */
unsigned long long bytes =
readq(&((struct channel_header __iomem *)
(ch))->size);
@@ -284,8 +304,7 @@ spar_check_channel_client(void __iomem *ch,
return 0;
}
}
- if (expected_version > 0) { /* caller wants us to verify
- * channel version */
+ if (expected_version > 0) { /* verify channel version */
unsigned long ver = readl(&((struct channel_header __iomem *)
(ch))->version_id);
if (ver != expected_version) {
@@ -295,8 +314,7 @@ spar_check_channel_client(void __iomem *ch,
return 0;
}
}
- if (expected_signature > 0) { /* caller wants us to verify
- * channel signature */
+ if (expected_signature > 0) { /* verify channel signature */
unsigned long long sig =
readq(&((struct channel_header __iomem *)
(ch))->signature);
@@ -319,8 +337,7 @@ static inline int spar_check_channel_server(uuid_le typeuuid, char *name,
u64 expected_min_bytes,
u64 actual_bytes)
{
- if (expected_min_bytes > 0) /* caller wants us to verify
- * channel size */
+ if (expected_min_bytes > 0) /* verify channel size */
if (actual_bytes < expected_min_bytes) {
pr_err("Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8llx actual=0x%-8.8llx\n",
name, &typeuuid, expected_min_bytes,
@@ -354,7 +371,8 @@ pathname_last_n_nodes(u8 *s, unsigned int n)
if (p == s)
break; /* should never happen, unless someone
* is changing the string while we are
- * looking at it!! */
+ * looking at it!!
+ */
if ((*p == '/') || (*p == '\\'))
n--;
}
@@ -395,7 +413,8 @@ spar_channel_client_acquire_os(void __iomem *ch, u8 *id)
if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED) {
if (readb(&hdr->cli_error_os) != 0) {
/* we are in an error msg throttling state;
- * come out of it */
+ * come out of it
+ */
pr_info("%s Channel OS client acquire now successful\n",
id);
writeb(0, &hdr->cli_error_os);
@@ -404,8 +423,9 @@ spar_channel_client_acquire_os(void __iomem *ch, u8 *id)
}
/* We have to do it the "hard way". We transition to BUSY,
- * and can use the channel iff our competitor has not also
- * transitioned to BUSY. */
+ * and can use the channel iff our competitor has not also
+ * transitioned to BUSY.
+ */
if (readl(&hdr->cli_state_os) != CHANNELCLI_ATTACHED) {
if ((readb(&hdr->cli_error_os)
& ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) {
diff --git a/drivers/staging/unisys/include/iochannel.h b/drivers/staging/unisys/include/iochannel.h
index 14e656ff73ec..162ca187a66b 100644
--- a/drivers/staging/unisys/include/iochannel.h
+++ b/drivers/staging/unisys/include/iochannel.h
@@ -6,7 +6,8 @@
/*
* Everything needed for IOPart-GuestPart communication is define in
* this file. Note: Everything is OS-independent because this file is
- * used by Windows, Linux and possible EFI drivers. */
+ * used by Windows, Linux and possible EFI drivers.
+ */
/*
* Communication flow between the IOPart and GuestPart uses the channel headers
@@ -66,21 +67,15 @@
* IO Partition is defined below.
*/
-/*
- * Defines and enums.
- */
-
+/* Defines and enums. */
#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))
-/* these define the two queues per data channel between iopart and
- * ioguestparts
- */
-#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to
- * iopart */
-
-#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from
- * iopart - same queue as previous queue */
+/* define the two queues per data channel between iopart and ioguestparts */
+/* used by ioguestpart to 'insert' signals to iopart */
+#define IOCHAN_TO_IOPART 0
+/* used by ioguestpart to 'remove' signals from iopart, same previous queue */
+#define IOCHAN_FROM_IOPART 1
/* size of cdb - i.e., scsi cmnd */
#define MAX_CMND_SIZE 16
@@ -92,26 +87,29 @@
/* various types of network packets that can be sent in cmdrsp */
enum net_types {
NET_RCV_POST = 0, /* submit buffer to hold receiving
- * incoming packet */
+ * incoming packet
+ */
/* virtnic -> uisnic */
NET_RCV, /* incoming packet received */
/* uisnic -> virtpci */
- NET_XMIT, /* for outgoing net packets */
+ NET_XMIT, /* for outgoing net packets */
/* virtnic -> uisnic */
NET_XMIT_DONE, /* outgoing packet xmitted */
/* uisnic -> virtpci */
NET_RCV_ENBDIS, /* enable/disable packet reception */
/* virtnic -> uisnic */
- NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet
- * reception */
+ NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet */
+ /* reception */
/* uisnic -> virtnic */
NET_RCV_PROMISC, /* enable/disable promiscuous mode */
/* virtnic -> uisnic */
NET_CONNECT_STATUS, /* indicate the loss or restoration of a network
- * connection */
+ * connection
+ */
/* uisnic -> virtnic */
NET_MACADDR, /* indicates the client has requested to update
- * its MAC addr */
+ * its MAC addr
+ */
NET_MACADDR_ACK, /* MAC address */
};
@@ -170,51 +168,43 @@ struct vhba_wwnn {
} __packed;
/* WARNING: Values stired in this structure must contain maximum counts (not
- * maximum values). */
-struct vhba_config_max { /* 20 bytes */
- u32 max_channel; /* maximum channel for devices attached to this
- * bus */
- u32 max_id; /* maximum SCSI ID for devices attached to this
- * bus */
- u32 max_lun; /* maximum SCSI LUN for devices attached to this
- * bus */
- u32 cmd_per_lun; /* maximum number of outstanding commands per
- * lun that are allowed at one time */
- u32 max_io_size; /* maximum io size for devices attached to this
- * bus */
+ * maximum values).
+ */
+struct vhba_config_max {/* 20 bytes */
+ u32 max_channel;/* maximum channel for devices attached to this bus */
+ u32 max_id; /* maximum SCSI ID for devices attached to bus */
+ u32 max_lun; /* maximum SCSI LUN for devices attached to bus */
+ u32 cmd_per_lun;/* maximum number of outstanding commands per LUN */
+ u32 max_io_size;/* maximum io size for devices attached to this bus */
/* max io size is often determined by the resource of the hba. e.g */
/* max scatter gather list length * page size / sector size */
} __packed;
struct uiscmdrsp_scsi {
- u64 handle; /* the handle to the cmd that was received -
- * send it back as is in the rsp packet. */
+ u64 handle; /* the handle to the cmd that was received */
+ /* send it back as is in the rsp packet. */
u8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */
u32 bufflen; /* length of data to be transferred out or in */
- u16 guest_phys_entries; /* Number of entries in scatter-gather (sg)
- * list */
+ u16 guest_phys_entries; /* Number of entries in scatter-gather list */
struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address
* information for each
- * fragment */
+ * fragment
+ */
enum dma_data_direction data_dir; /* direction of the data, if any */
- struct uisscsi_dest vdest; /* identifies the virtual hba, id,
- * channel, lun to which cmd was sent */
+ struct uisscsi_dest vdest; /* identifies the virtual hba, id, */
+ /* channel, lun to which cmd was sent */
- /* the following fields are needed to queue the rsp back to cmd
- * originator */
- int linuxstat; /* the original Linux status - for use by linux
- * vdisk code */
+ /* Needed to queue the rsp back to cmd originator */
+ int linuxstat; /* original Linux status used by linux vdisk */
u8 scsistat; /* the scsi status */
- u8 addlstat; /* non-scsi status - covers cases like timeout
- * needed by windows guests */
+ u8 addlstat; /* non-scsi status */
#define ADDL_SEL_TIMEOUT 4
/* the following fields are need to determine the result of command */
u8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */
/* it holds the sense_data struct; */
/* see that struct for details. */
- void *vdisk; /* contains pointer to the vdisk so that we can clean up
- * when the IO completes. */
+ void *vdisk; /* pointer to the vdisk to clean up when IO completes. */
int no_disk_result;
/* used to return no disk inquiry result
* when no_disk_result is set to 1,
@@ -258,15 +248,15 @@ struct uiscmdrsp_scsi {
*/
#define NO_DISK_INQUIRY_RESULT_LEN 36
-#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry
- * result */
+#define MIN_INQUIRY_RESULT_LEN 5 /* 5 bytes minimum for inquiry result */
/* SCSI device version for no disk inquiry result */
#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */
/* Windows and Linux want different things for a non-existent lun. So, we'll let
* caller pass in the peripheral qualifier and type.
- * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */
+ * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5.
+ */
#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \
do { \
@@ -305,9 +295,7 @@ struct uiscmdrsp_scsi {
} \
} while (0)
-/*
- * Struct & Defines to support sense information.
- */
+/* Struct & Defines to support sense information. */
/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is
* initialized in exactly the manner that is recommended in Windows (hence the
@@ -342,13 +330,11 @@ struct sense_data {
struct net_pkt_xmt {
int len; /* full length of data in the packet */
int num_frags; /* number of fragments in frags containing data */
- struct phys_info frags[MAX_PHYS_INFO]; /* physical page information for
- * each fragment */
+ struct phys_info frags[MAX_PHYS_INFO]; /* physical page information */
char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */
struct {
- /* these are needed for csum at uisnic end */
- u8 valid; /* 1 = rest of this struct is valid - else
- * ignore */
+ /* these are needed for csum at uisnic end */
+ u8 valid; /* 1 = struct is valid - else ignore */
u8 hrawoffv; /* 1 = hwrafoff is valid */
u8 nhrawoffv; /* 1 = nhwrafoff is valid */
u16 protocol; /* specifies packet protocol */
@@ -380,16 +366,18 @@ struct net_pkt_xmtdone {
*/
#define RCVPOST_BUF_SIZE 4032
#define MAX_NET_RCV_CHAIN \
- ((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE)
+ ((ETH_MAX_MTU + ETH_HEADER_SIZE + RCVPOST_BUF_SIZE - 1) \
+ / RCVPOST_BUF_SIZE)
struct net_pkt_rcvpost {
/* rcv buf size must be large enough to include ethernet data len +
* ethernet header len - we are choosing 2K because it is guaranteed
- * to be describable */
- struct phys_info frag; /* physical page information for the
- * single fragment 2K rcv buf */
- u64 unique_num; /* This is used to make sure that
- * receive posts are returned to */
+ * to be describable
+ */
+ struct phys_info frag; /* physical page information for the */
+ /* single fragment 2K rcv buf */
+ u64 unique_num;
+ /* unique_num ensure that receive posts are returned to */
/* the Adapter which we sent them originally. */
} __packed;
@@ -399,8 +387,7 @@ struct net_pkt_rcv {
u32 rcv_done_len; /* length of received data */
u8 numrcvbufs; /* number of receive buffers that contain the */
/* incoming data; guest end MUST chain these together. */
- void *rcvbuf[MAX_NET_RCV_CHAIN]; /* the list of receive buffers
- * that must be chained; */
+ void *rcvbuf[MAX_NET_RCV_CHAIN]; /* list of chained rcvbufs */
/* each entry is a receive buffer provided by NET_RCV_POST. */
/* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
u64 unique_num;
@@ -469,18 +456,17 @@ struct uiscmdrsp_scsitaskmgmt {
#define TASK_MGMT_FAILED 0
} __packed;
-/* The following is used by uissd to send disk add/remove notifications to
- * Guest */
+/* Used by uissd to send disk add/remove notifications to Guest */
/* Note that the vHba pointer is not used by the Client/Guest side. */
struct uiscmdrsp_disknotify {
u8 add; /* 0-remove, 1-add */
- void *v_hba; /* Pointer to vhba_info for channel info to
- * route msg */
+ void *v_hba; /* channel info to route msg */
u32 channel, id, lun; /* SCSI Path of Disk to added or removed */
} __packed;
/* The following is used by virthba/vSCSI to send the Acquire/Release commands
- * to the IOVM. */
+ * to the IOVM.
+ */
struct uiscmdrsp_vdiskmgmt {
enum vdisk_mgmt_types vdisktype;
@@ -533,8 +519,8 @@ struct uiscmdrsp {
struct uiscmdrsp_disknotify disknotify;
struct uiscmdrsp_vdiskmgmt vdiskmgmt;
};
- void *private_data; /* used to send the response when the cmd is
- * done (scsi & scsittaskmgmt). */
+ void *private_data; /* send the response when the cmd is */
+ /* done (scsi & scsittaskmgmt). */
struct uiscmdrsp *next; /* General Purpose Queue Link */
struct uiscmdrsp *activeQ_next; /* Used to track active commands */
struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
@@ -564,15 +550,11 @@ struct spar_io_channel_protocol {
} __packed;
#define MAX_CLIENTSTRING_LEN 1024
- u8 client_string[MAX_CLIENTSTRING_LEN];/* NULL terminated - so holds
- * max - 1 bytes */
+ /* client_string is NULL termimated so holds max -1 bytes */
+ u8 client_string[MAX_CLIENTSTRING_LEN];
} __packed;
-
-/*
- * INLINE functions for initializing and accessing I/O data channels
- */
-
+/* INLINE functions for initializing and accessing I/O data channels */
#define SIZEOF_PROTOCOL (COVER(sizeof(struct spar_io_channel_protocol), 64))
#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
@@ -584,8 +566,7 @@ struct spar_io_channel_protocol {
* pfn-off-size entires.
*/
-/* we deal with 4K page sizes when we it comes to passing page information
- * between */
+/* use 4K page sizes when we it comes to passing page information between */
/* Guest and IOPartition. */
#define PI_PAGE_SIZE 0x1000
#define PI_PAGE_MASK 0x0FFF
@@ -594,18 +575,8 @@ struct spar_io_channel_protocol {
* room)
*/
static inline u16
-add_physinfo_entries(u32 inp_pfn, /* input - specifies the pfn to be used
- * to add entries */
- u16 inp_off, /* input - specifies the off to be used
- * to add entries */
- u32 inp_len, /* input - specifies the len to be used
- * to add entries */
- u16 index, /* input - index in array at which new
- * entries are added */
- u16 max_pi_arr_entries, /* input - specifies the maximum
- * entries pi_arr can hold */
- struct phys_info pi_arr[]) /* input & output - array to
- * which entries are added */
+add_physinfo_entries(u32 inp_pfn, u16 inp_off, u32 inp_len, u16 index,
+ u16 max_pi_arr_entries, struct phys_info pi_arr[])
{
u32 len;
u16 i, firstlen;
diff --git a/drivers/staging/unisys/include/vbushelper.h b/drivers/staging/unisys/include/vbushelper.h
index f272975b2920..f1b6aacb79d7 100644
--- a/drivers/staging/unisys/include/vbushelper.h
+++ b/drivers/staging/unisys/include/vbushelper.h
@@ -19,7 +19,8 @@
#define __VBUSHELPER_H__
/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the
- * command line */
+ * command line
+ */
#define TARGET_HOSTNAME "linuxguest"
diff --git a/drivers/staging/unisys/include/visorbus.h b/drivers/staging/unisys/include/visorbus.h
index 9235536fa75f..2a64a9ce0208 100644
--- a/drivers/staging/unisys/include/visorbus.h
+++ b/drivers/staging/unisys/include/visorbus.h
@@ -140,8 +140,8 @@ struct visor_device {
struct {
int major, minor;
void *attr; /* private use by devmajorminor_attr.c you can
- * change this constant to whatever you
- * want; */
+ * change this constant to whatever you want
+ */
} devnodes[5];
/* the code will detect and behave appropriately) */
struct semaphore visordriver_callback_lock;
diff --git a/drivers/staging/unisys/visorbus/Kconfig b/drivers/staging/unisys/visorbus/Kconfig
index 9b299ac86015..511388075ffa 100644
--- a/drivers/staging/unisys/visorbus/Kconfig
+++ b/drivers/staging/unisys/visorbus/Kconfig
@@ -6,4 +6,9 @@ config UNISYS_VISORBUS
tristate "Unisys visorbus driver"
depends on UNISYSSPAR
---help---
- If you say Y here, you will enable the Unisys visorbus driver.
+ The visorbus driver is a virtualized bus for the Unisys s-Par firmware.
+ Virtualized devices allow Linux guests on a system to share disks and
+ network cards that do not have SR-IOV support, and to be accessed using
+ the partition desktop application. The visorbus driver is required to
+ discover devices on an s-Par guest, and must be present for any other
+ s-Par guest driver to function correctly.
diff --git a/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
index 3c97ebac4f32..23ad0ea6c9fc 100644
--- a/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
+++ b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
@@ -39,7 +39,8 @@
#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */
/* Payload and Parameter Related------------------------------------[400-499] */
#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
- * DEVICE_CONFIGURE */
+ * DEVICE_CONFIGURE
+ */
#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
@@ -48,36 +49,43 @@
* BUS_CONFIGURE,
* DEVICE_CREATE,
* DEVICE_CONFIG
- * DEVICE_DESTROY */
+ * DEVICE_DESTROY
+ */
#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
/* DEVICE_CREATE,
* DEVICE_CONFIGURE,
- * DEVICE_DESTROY */
+ * DEVICE_DESTROY
+ */
#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE,
- * DEVICE_CONFIGURE */
+ * DEVICE_CONFIGURE
+ */
/* Partition Driver Callback Interface----------------------[600-699] */
#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
* BUS_DESTROY,
* DEVICE_CREATE,
- * DEVICE_DESTROY */
+ * DEVICE_DESTROY
+ */
/* Unable to invoke VIRTPCI callback */
#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605
/* BUS_CREATE,
* BUS_DESTROY,
* DEVICE_CREATE,
- * DEVICE_DESTROY */
+ * DEVICE_DESTROY
+ */
/* VIRTPCI Callback returned error */
#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606
/* SWITCH_ATTACHEXTPORT,
* SWITCH_DETACHEXTPORT
- * DEVICE_CONFIGURE */
+ * DEVICE_CONFIGURE
+ */
/* generic device callback returned error */
/* Bus Related------------------------------------------------------[700-799] */
#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */
/* Channel Related--------------------------------------------------[800-899] */
#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
- * DEVICE_DESTROY */
+ * DEVICE_DESTROY
+ */
#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
/* Chipset Shutdown Related---------------------------------------[1000-1099] */
#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000
diff --git a/drivers/staging/unisys/visorbus/periodic_work.c b/drivers/staging/unisys/visorbus/periodic_work.c
index 115b7aa9560a..00b152764f84 100644
--- a/drivers/staging/unisys/visorbus/periodic_work.c
+++ b/drivers/staging/unisys/visorbus/periodic_work.c
@@ -43,11 +43,12 @@ static void periodic_work_func(struct work_struct *work)
(*pw->workfunc)(pw->workfuncarg);
}
-struct periodic_work *visor_periodic_work_create(ulong jiffy_interval,
- struct workqueue_struct *workqueue,
- void (*workfunc)(void *),
- void *workfuncarg,
- const char *devnam)
+struct periodic_work
+*visor_periodic_work_create(ulong jiffy_interval,
+ struct workqueue_struct *workqueue,
+ void (*workfunc)(void *),
+ void *workfuncarg,
+ const char *devnam)
{
struct periodic_work *pw;
diff --git a/drivers/staging/unisys/visorbus/vbuschannel.h b/drivers/staging/unisys/visorbus/vbuschannel.h
index 80e64477e547..90fa12e62f26 100644
--- a/drivers/staging/unisys/visorbus/vbuschannel.h
+++ b/drivers/staging/unisys/visorbus/vbuschannel.h
@@ -36,10 +36,11 @@ static const uuid_le spar_vbus_channel_protocol_uuid =
#define SPAR_VBUS_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
/* Must increment this whenever you insert or delete fields within this channel
-* struct. Also increment whenever you change the meaning of fields within this
-* channel struct so as to break pre-existing software. Note that you can
-* usually add fields to the END of the channel struct withOUT needing to
-* increment this. */
+ * struct. Also increment whenever you change the meaning of fields within this
+ * channel struct so as to break pre-existing software. Note that you can
+ * usually add fields to the END of the channel struct withOUT needing to
+ * increment this.
+ */
#define SPAR_VBUS_CHANNEL_PROTOCOL_VERSIONID 1
#define SPAR_VBUS_CHANNEL_OK_CLIENT(ch) \
diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c
index a272b48bab28..eac97d22278a 100644
--- a/drivers/staging/unisys/visorbus/visorbus_main.c
+++ b/drivers/staging/unisys/visorbus/visorbus_main.c
@@ -1078,7 +1078,8 @@ away:
}
/* Write the contents of <info> to the struct
- * spar_vbus_channel_protocol.chp_info. */
+ * spar_vbus_channel_protocol.chp_info.
+ */
static int
write_vbus_chp_info(struct visorchannel *chan,
@@ -1096,7 +1097,8 @@ write_vbus_chp_info(struct visorchannel *chan,
}
/* Write the contents of <info> to the struct
- * spar_vbus_channel_protocol.bus_info. */
+ * spar_vbus_channel_protocol.bus_info.
+ */
static int
write_vbus_bus_info(struct visorchannel *chan,
@@ -1370,7 +1372,8 @@ pause_state_change_complete(struct visor_device *dev, int status)
/* Notify the chipset driver that the pause is complete, which
* will presumably want to send some sort of response to the
- * initiator. */
+ * initiator.
+ */
(*chipset_responders.device_pause) (dev, status);
}
@@ -1390,7 +1393,8 @@ resume_state_change_complete(struct visor_device *dev, int status)
/* Notify the chipset driver that the resume is complete,
* which will presumably want to send some sort of response to
- * the initiator. */
+ * the initiator.
+ */
(*chipset_responders.device_resume) (dev, status);
}
@@ -1437,7 +1441,8 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause)
* existing problem prevents us from ever getting a bus
* resume... This hack would fail to work should we
* ever have a bus that contains NO devices, since we
- * would never even get here in that case. */
+ * would never even get here in that case.
+ */
fix_vbus_dev_info(dev);
if (!drv->resume)
goto away;
diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c
index a4e117f101cf..891b8db7c5ec 100644
--- a/drivers/staging/unisys/visorbus/visorchannel.c
+++ b/drivers/staging/unisys/visorbus/visorchannel.c
@@ -41,8 +41,8 @@ struct visorchannel {
struct channel_header chan_hdr;
uuid_le guid;
ulong size;
- bool needs_lock; /* channel creator knows if more than one
- * thread will be inserting or removing */
+ bool needs_lock; /* channel creator knows if more than one */
+ /* thread will be inserting or removing */
spinlock_t insert_lock; /* protect head writes in chan_hdr */
spinlock_t remove_lock; /* protect tail writes in chan_hdr */
diff --git a/drivers/staging/unisys/visorbus/vmcallinterface.h b/drivers/staging/unisys/visorbus/vmcallinterface.h
index c8d8483bd4df..c043fa41ceda 100644
--- a/drivers/staging/unisys/visorbus/vmcallinterface.h
+++ b/drivers/staging/unisys/visorbus/vmcallinterface.h
@@ -43,20 +43,15 @@ enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */
* - the 0x01 identifies it as the 1st instance of a VMCALL_VIRTPART
* type of VMCALL
*/
-
- VMCALL_IO_CONTROLVM_ADDR = 0x0501, /* used by all Guests, not just
- * IO */
- VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET = 0x0708, /* Allow caller to
- * query virtual time
- * offset */
- VMCALL_POST_CODE_LOGEVENT = 0x070B, /* LOGEVENT Post Code (RDX) with
- * specified subsystem mask (RCX
- * - monitor_subsystems.h) and
- * severity (RDX) */
- VMCALL_UPDATE_PHYSICAL_TIME = 0x0a02 /* Allow
- * ULTRA_SERVICE_CAPABILITY_TIME
- * capable guest to make
- * VMCALL */
+ /* used by all Guests, not just IO */
+ VMCALL_IO_CONTROLVM_ADDR = 0x0501,
+ /* Allow caller to query virtual time offset */
+ VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET = 0x0708,
+ /* LOGEVENT Post Code (RDX) with specified subsystem mask */
+ /* (RCX - monitor_subsystems.h) and severity (RDX) */
+ VMCALL_POST_CODE_LOGEVENT = 0x070B,
+ /* Allow ULTRA_SERVICE_CAPABILITY_TIME capable guest to make VMCALL */
+ VMCALL_UPDATE_PHYSICAL_TIME = 0x0a02
};
#define VMCALL_SUCCESS 0
@@ -74,7 +69,8 @@ enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */
unisys_extended_vmcall(method, param1, param2, param3)
/* The following uses VMCALL_POST_CODE_LOGEVENT interface but is currently
- * not used much */
+ * not used much
+ */
#define ISSUE_IO_VMCALL_POSTCODE_SEVERITY(postcode, severity) \
ISSUE_IO_EXTENDED_VMCALL(VMCALL_POST_CODE_LOGEVENT, severity, \
MDS_APPOS, postcode)
@@ -84,11 +80,11 @@ enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */
/* Parameters to VMCALL_IO_CONTROLVM_ADDR interface */
struct vmcall_io_controlvm_addr_params {
- /* The Guest-relative physical address of the ControlVm channel.
- * This VMCall fills this in with the appropriate address. */
+ /* The Guest-relative physical address of the ControlVm channel. */
+ /* This VMCall fills this in with the appropriate address. */
u64 address; /* contents provided by this VMCALL (OUT) */
- /* the size of the ControlVm channel in bytes This VMCall fills this
- * in with the appropriate address. */
+ /* the size of the ControlVm channel in bytes This VMCall fills this */
+ /* in with the appropriate address. */
u32 channel_bytes; /* contents provided by this VMCALL (OUT) */
u8 unused[4]; /* Unused Bytes in the 64-Bit Aligned Struct */
} __packed;
diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c
index c119f20dfd44..d5178b44ba8c 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -453,7 +453,6 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd,
struct uiscmdrsp *cmdrsp;
struct scsi_device *scsidev = scsicmd->device;
int insert_location;
- unsigned char op;
unsigned char *cdb = scsicmd->cmnd;
struct Scsi_Host *scsihost = scsidev->host;
unsigned int i;
@@ -461,7 +460,6 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd,
(struct visorhba_devdata *)scsihost->hostdata;
struct scatterlist *sg = NULL;
struct scatterlist *sglist = NULL;
- int err = 0;
if (devdata->serverdown || devdata->serverchangingstate)
return SCSI_MLQUEUE_DEVICE_BUSY;
@@ -496,10 +494,8 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd,
if (cmdrsp->scsi.bufflen > devdata->max_buff_len)
devdata->max_buff_len = cmdrsp->scsi.bufflen;
- if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) {
- err = SCSI_MLQUEUE_DEVICE_BUSY;
+ if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO)
goto err_del_scsipending_ent;
- }
/* convert buffer to phys information */
/* buffer is scatterlist - copy it out */
@@ -511,19 +507,17 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd,
}
cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd);
- op = cdb[0];
if (!visorchannel_signalinsert(devdata->dev->visorchannel,
IOCHAN_TO_IOPART,
- cmdrsp)) {
+ cmdrsp))
/* queue must be full and we aren't going to wait */
- err = SCSI_MLQUEUE_DEVICE_BUSY;
goto err_del_scsipending_ent;
- }
+
return 0;
err_del_scsipending_ent:
del_scsipending_ent(devdata, insert_location);
- return err;
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
/**
@@ -759,11 +753,9 @@ do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
struct visorhba_devdata *devdata;
struct visordisk_info *vdisk;
struct scsi_device *scsidev;
- struct sense_data *sd;
scsidev = scsicmd->device;
memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
- sd = (struct sense_data *)scsicmd->sense_buffer;
/* Do not log errors for disk-not-present inquiries */
if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
diff --git a/drivers/staging/unisys/visorinput/Kconfig b/drivers/staging/unisys/visorinput/Kconfig
index d83deb4137e8..3476d419d32c 100644
--- a/drivers/staging/unisys/visorinput/Kconfig
+++ b/drivers/staging/unisys/visorinput/Kconfig
@@ -6,5 +6,10 @@ config UNISYS_VISORINPUT
tristate "Unisys visorinput driver"
depends on UNISYSSPAR && UNISYS_VISORBUS && FB
---help---
- If you say Y here, you will enable the Unisys visorinput driver.
+ The Unisys s-Par visorinput driver provides a virtualized system
+ console (keyboard and mouse) that is accessible through the
+ s-Par firmware's user interface. s-Par provides video using the EFI
+ GOP protocol, so If this driver is not present, the Linux guest should
+ still boot with visible output in the partition desktop, but keyboard
+ and mouse interaction will not be available.
diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c
index 5c16f6634368..38d4d5b884df 100644
--- a/drivers/staging/unisys/visorinput/visorinput.c
+++ b/drivers/staging/unisys/visorinput/visorinput.c
@@ -523,7 +523,7 @@ visorinput_channel_interrupt(struct visor_device *dev)
struct ultra_inputreport r;
int scancode, keycode;
struct input_dev *visorinput_dev;
- int xmotion, ymotion, zmotion, button;
+ int xmotion, ymotion, button;
int i;
struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device);
@@ -604,12 +604,10 @@ visorinput_channel_interrupt(struct visor_device *dev)
}
break;
case inputaction_wheel_rotate_away:
- zmotion = r.activity.arg1;
input_report_rel(visorinput_dev, REL_WHEEL, 1);
input_sync(visorinput_dev);
break;
case inputaction_wheel_rotate_toward:
- zmotion = r.activity.arg1;
input_report_rel(visorinput_dev, REL_WHEEL, -1);
input_sync(visorinput_dev);
break;
diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c
index 296b11cea247..05194707278a 100644
--- a/drivers/staging/unisys/visornic/visornic_main.c
+++ b/drivers/staging/unisys/visornic/visornic_main.c
@@ -1742,7 +1742,6 @@ poll_for_irq(unsigned long v)
atomic_set(&devdata->interrupt_rcvd, 0);
mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2));
-
}
/**
diff --git a/drivers/staging/vme/devices/vme_pio2_cntr.c b/drivers/staging/vme/devices/vme_pio2_cntr.c
index 6335471faa36..486c30c4956f 100644
--- a/drivers/staging/vme/devices/vme_pio2_cntr.c
+++ b/drivers/staging/vme/devices/vme_pio2_cntr.c
@@ -61,7 +61,7 @@ int pio2_cntr_reset(struct pio2_card *card)
/* Ensure all counter interrupts are cleared */
do {
retval = vme_master_read(card->window, &reg, 1,
- PIO2_REGS_INT_STAT_CNTR);
+ PIO2_REGS_INT_STAT_CNTR);
if (retval < 0)
return retval;
} while (reg != 0);
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c
index 35c6ce5047de..4f3cdbcedb3e 100644
--- a/drivers/staging/vme/devices/vme_pio2_core.c
+++ b/drivers/staging/vme/devices/vme_pio2_core.c
@@ -90,7 +90,7 @@ static void pio2_int(int level, int vector, void *ptr)
case 4:
/* Channels 0 to 7 */
retval = vme_master_read(card->window, &reg, 1,
- PIO2_REGS_INT_STAT[vec - 1]);
+ PIO2_REGS_INT_STAT[vec - 1]);
if (retval < 0) {
dev_err(&card->vdev->dev,
"Unable to read IRQ status register\n");
@@ -100,8 +100,8 @@ static void pio2_int(int level, int vector, void *ptr)
channel = ((vec - 1) * 8) + i;
if (reg & PIO2_CHANNEL_BIT[channel])
dev_info(&card->vdev->dev,
- "Interrupt on I/O channel %d\n",
- channel);
+ "Interrupt on I/O channel %d\n",
+ channel);
}
break;
case 5:
@@ -215,7 +215,7 @@ static int pio2_probe(struct vme_dev *vdev)
u8 reg;
int vec;
- card = kzalloc(sizeof(struct pio2_card), GFP_KERNEL);
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card) {
retval = -ENOMEM;
goto err_struct;
@@ -230,7 +230,7 @@ static int pio2_probe(struct vme_dev *vdev)
card->vdev = vdev;
for (i = 0; i < PIO2_VARIANT_LENGTH; i++) {
- if (isdigit(card->variant[i]) == 0) {
+ if (!isdigit(card->variant[i])) {
dev_err(&card->vdev->dev, "Variant invalid\n");
retval = -EINVAL;
goto err_variant;
@@ -289,7 +289,7 @@ static int pio2_probe(struct vme_dev *vdev)
}
retval = vme_master_set(card->window, 1, card->base, 0x10000, VME_A24,
- (VME_SCT | VME_USER | VME_DATA), VME_D16);
+ VME_SCT | VME_USER | VME_DATA, VME_D16);
if (retval) {
dev_err(&card->vdev->dev,
"Unable to configure VME master resource\n");
@@ -335,7 +335,7 @@ static int pio2_probe(struct vme_dev *vdev)
/* Set VME vector */
retval = vme_master_write(card->window, &card->irq_vector, 1,
- PIO2_REGS_VME_VECTOR);
+ PIO2_REGS_VME_VECTOR);
if (retval < 0)
return retval;
@@ -343,7 +343,7 @@ static int pio2_probe(struct vme_dev *vdev)
vec = card->irq_vector | PIO2_VME_VECTOR_SPUR;
retval = vme_irq_request(vdev, card->irq_level, vec,
- &pio2_int, (void *)card);
+ &pio2_int, card);
if (retval < 0) {
dev_err(&card->vdev->dev,
"Unable to attach VME interrupt vector0x%x, level 0x%x\n",
@@ -356,7 +356,7 @@ static int pio2_probe(struct vme_dev *vdev)
vec = card->irq_vector | PIO2_VECTOR_BANK[i];
retval = vme_irq_request(vdev, card->irq_level, vec,
- &pio2_int, (void *)card);
+ &pio2_int, card);
if (retval < 0) {
dev_err(&card->vdev->dev,
"Unable to attach VME interrupt vector0x%x, level 0x%x\n",
@@ -370,7 +370,7 @@ static int pio2_probe(struct vme_dev *vdev)
vec = card->irq_vector | PIO2_VECTOR_CNTR[i];
retval = vme_irq_request(vdev, card->irq_level, vec,
- &pio2_int, (void *)card);
+ &pio2_int, card);
if (retval < 0) {
dev_err(&card->vdev->dev,
"Unable to attach VME interrupt vector0x%x, level 0x%x\n",
@@ -397,7 +397,7 @@ static int pio2_probe(struct vme_dev *vdev)
dev_set_drvdata(&card->vdev->dev, card);
dev_info(&card->vdev->dev,
- "PIO2 (variant %s) configured at 0x%lx\n", card->variant,
+ "PIO2 (variant %s) configured at 0x%lx\n", card->variant,
card->base);
return 0;
diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c
index 77901b345a71..df992c3cb5ce 100644
--- a/drivers/staging/vme/devices/vme_pio2_gpio.c
+++ b/drivers/staging/vme/devices/vme_pio2_gpio.c
@@ -37,14 +37,13 @@ static int pio2_gpio_get(struct gpio_chip *chip, unsigned int offset)
struct pio2_card *card = gpio_to_pio2_card(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) |
- (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
-
+ (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
dev_err(&card->vdev->dev, "Channel not available as input\n");
return 0;
}
retval = vme_master_read(card->window, &reg, 1,
- PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]);
+ PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]);
if (retval < 0) {
dev_err(&card->vdev->dev, "Unable to read from GPIO\n");
return 0;
@@ -67,16 +66,15 @@ static int pio2_gpio_get(struct gpio_chip *chip, unsigned int offset)
return 0;
}
-static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static void pio2_gpio_set(struct gpio_chip *chip,
+ unsigned int offset, int value)
{
u8 reg;
int retval;
struct pio2_card *card = gpio_to_pio2_card(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
- (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
-
+ (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
dev_err(&card->vdev->dev, "Channel not available as output\n");
return;
}
@@ -89,7 +87,7 @@ static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset,
~PIO2_CHANNEL_BIT[offset];
retval = vme_master_write(card->window, &reg, 1,
- PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]);
+ PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]);
if (retval < 0) {
dev_err(&card->vdev->dev, "Unable to write to GPIO\n");
return;
@@ -105,7 +103,7 @@ static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
struct pio2_card *card = gpio_to_pio2_card(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) |
- (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
+ (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
dev_err(&card->vdev->dev,
"Channel directionality not configurable at runtime\n");
@@ -124,7 +122,7 @@ static int pio2_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
struct pio2_card *card = gpio_to_pio2_card(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
- (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
+ (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
dev_err(&card->vdev->dev,
"Channel directionality not configurable at runtime\n");
@@ -150,7 +148,7 @@ int pio2_gpio_reset(struct pio2_card *card)
/* Zero output registers */
for (i = 0; i < 4; i++) {
retval = vme_master_write(card->window, &data, 1,
- PIO2_REGS_DATA[i]);
+ PIO2_REGS_DATA[i]);
if (retval < 0)
return retval;
card->bank[i].value = 0;
@@ -159,12 +157,12 @@ int pio2_gpio_reset(struct pio2_card *card)
/* Set input interrupt masks */
for (i = 0; i < 4; i++) {
retval = vme_master_write(card->window, &data, 1,
- PIO2_REGS_INT_MASK[i * 2]);
+ PIO2_REGS_INT_MASK[i * 2]);
if (retval < 0)
return retval;
retval = vme_master_write(card->window, &data, 1,
- PIO2_REGS_INT_MASK[(i * 2) + 1]);
+ PIO2_REGS_INT_MASK[(i * 2) + 1]);
if (retval < 0)
return retval;
@@ -176,7 +174,7 @@ int pio2_gpio_reset(struct pio2_card *card)
for (i = 0; i < 4; i++) {
do {
retval = vme_master_read(card->window, &data, 1,
- PIO2_REGS_INT_STAT[i]);
+ PIO2_REGS_INT_STAT[i]);
if (retval < 0)
return retval;
} while (data != 0);
@@ -192,7 +190,7 @@ int pio2_gpio_init(struct pio2_card *card)
label = kasprintf(GFP_KERNEL,
"%s@%s", driver_name, dev_name(&card->vdev->dev));
- if (label == NULL)
+ if (!label)
return -ENOMEM;
card->gc.label = label;
@@ -207,7 +205,7 @@ int pio2_gpio_init(struct pio2_card *card)
card->gc.set = pio2_gpio_set;
/* This function adds a memory mapped GPIO chip */
- retval = gpiochip_add(&(card->gc));
+ retval = gpiochip_add(&card->gc);
if (retval) {
dev_err(&card->vdev->dev, "Unable to register GPIO\n");
kfree(card->gc.label);
@@ -220,7 +218,7 @@ void pio2_gpio_exit(struct pio2_card *card)
{
const char *label = card->gc.label;
- gpiochip_remove(&(card->gc));
+ gpiochip_remove(&card->gc);
kfree(label);
}
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 8e61a3b3e7e4..b95883bc68fe 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -308,8 +308,8 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case VME_IRQ_GEN:
copied = copy_from_user(&irq_req, argp,
- sizeof(struct vme_irq_id));
- if (copied != 0) {
+ sizeof(irq_req));
+ if (copied) {
pr_warn("Partial copy from userspace\n");
return -EFAULT;
}
@@ -322,7 +322,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
case MASTER_MINOR:
switch (cmd) {
case VME_GET_MASTER:
- memset(&master, 0, sizeof(struct vme_master));
+ memset(&master, 0, sizeof(master));
/* XXX We do not want to push aspace, cycle and width
* to userspace as they are
@@ -334,8 +334,8 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
&master.cycle, &master.dwidth);
copied = copy_to_user(argp, &master,
- sizeof(struct vme_master));
- if (copied != 0) {
+ sizeof(master));
+ if (copied) {
pr_warn("Partial copy to userspace\n");
return -EFAULT;
}
@@ -350,7 +350,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
}
copied = copy_from_user(&master, argp, sizeof(master));
- if (copied != 0) {
+ if (copied) {
pr_warn("Partial copy from userspace\n");
return -EFAULT;
}
@@ -368,7 +368,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
case SLAVE_MINOR:
switch (cmd) {
case VME_GET_SLAVE:
- memset(&slave, 0, sizeof(struct vme_slave));
+ memset(&slave, 0, sizeof(slave));
/* XXX We do not want to push aspace, cycle and width
* to userspace as they are
@@ -379,8 +379,8 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
&slave.aspace, &slave.cycle);
copied = copy_to_user(argp, &slave,
- sizeof(struct vme_slave));
- if (copied != 0) {
+ sizeof(slave));
+ if (copied) {
pr_warn("Partial copy to userspace\n");
return -EFAULT;
}
@@ -390,7 +390,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
case VME_SET_SLAVE:
copied = copy_from_user(&slave, argp, sizeof(slave));
- if (copied != 0) {
+ if (copied) {
pr_warn("Partial copy from userspace\n");
return -EFAULT;
}
@@ -757,7 +757,7 @@ static int __init vme_user_init(void)
* we just change the code in vme_user_match().
*/
retval = vme_register_driver(&vme_user_driver, VME_MAX_SLOTS);
- if (retval != 0)
+ if (retval)
goto err_reg;
return retval;
diff --git a/drivers/staging/vme/devices/vme_user.h b/drivers/staging/vme/devices/vme_user.h
index b8cc7bc78a73..a6cb75686fa4 100644
--- a/drivers/staging/vme/devices/vme_user.h
+++ b/drivers/staging/vme/devices/vme_user.h
@@ -20,7 +20,6 @@ struct vme_master {
#endif
} __packed;
-
/*
* IOCTL Commands and structures
*/
@@ -28,7 +27,6 @@ struct vme_master {
/* Magic number for use in ioctls */
#define VME_IOC_MAGIC 0xAE
-
/* VMEbus Slave Window Configuration Structure */
struct vme_slave {
__u32 enable; /* State of Window */
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index e5be261f2e69..9417c935fc30 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: baseband.c
*
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index 771ea4054174..807a5809b5d9 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: baseband.h
*
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 927243ebcb56..a382fc6aa9d3 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: card.c
* Purpose: Provide functions to setup NIC operation mode
diff --git a/drivers/staging/vt6656/card.h b/drivers/staging/vt6656/card.h
index 03fc1678896b..c2cde7e92c8f 100644
--- a/drivers/staging/vt6656/card.h
+++ b/drivers/staging/vt6656/card.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: card.h
*
diff --git a/drivers/staging/vt6656/channel.c b/drivers/staging/vt6656/channel.c
index 8412d0532fb2..a0fe288c1322 100644
--- a/drivers/staging/vt6656/channel.c
+++ b/drivers/staging/vt6656/channel.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: channel.c
*
diff --git a/drivers/staging/vt6656/channel.h b/drivers/staging/vt6656/channel.h
index 21c080803714..fcea6995fe26 100644
--- a/drivers/staging/vt6656/channel.h
+++ b/drivers/staging/vt6656/channel.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: channel.h
*
diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h
index f79af8513ff2..59e3071021bd 100644
--- a/drivers/staging/vt6656/desc.h
+++ b/drivers/staging/vt6656/desc.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: desc.h
*
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index dec36f296f3d..76b5f4127f95 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: device.h
*
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index e6367ed3b0bb..6019aac8bdd5 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: dpc.c
*
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
index 95e0e83a487e..5a92bd86cee2 100644
--- a/drivers/staging/vt6656/dpc.h
+++ b/drivers/staging/vt6656/dpc.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: dpc.h
*
diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c
index d440f284bf18..1b48f9c86f63 100644
--- a/drivers/staging/vt6656/firmware.c
+++ b/drivers/staging/vt6656/firmware.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: baseband.c
*
diff --git a/drivers/staging/vt6656/firmware.h b/drivers/staging/vt6656/firmware.h
index d594dbe1c147..e2b54acb8fdb 100644
--- a/drivers/staging/vt6656/firmware.h
+++ b/drivers/staging/vt6656/firmware.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: firmware.h
*
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
index 14b8ebc6508d..8d05acbc0e23 100644
--- a/drivers/staging/vt6656/int.c
+++ b/drivers/staging/vt6656/int.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: int.c
*
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h
index 154605c63947..97e55bacbb7c 100644
--- a/drivers/staging/vt6656/int.h
+++ b/drivers/staging/vt6656/int.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: int.h
*
diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c
index 181745d8e250..0246a8fc47fe 100644
--- a/drivers/staging/vt6656/key.c
+++ b/drivers/staging/vt6656/key.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: key.c
*
@@ -163,7 +159,6 @@ int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
}
-
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
vnt_set_keymode(hw, mac_addr, key, VNT_KEY_PAIRWISE,
key_dec_mode, true);
diff --git a/drivers/staging/vt6656/key.h b/drivers/staging/vt6656/key.h
index 3cb1291055ed..7861faf5138f 100644
--- a/drivers/staging/vt6656/key.h
+++ b/drivers/staging/vt6656/key.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: key.h
*
diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c
index 5dfac05b9cf1..eeed16e9124e 100644
--- a/drivers/staging/vt6656/mac.c
+++ b/drivers/staging/vt6656/mac.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: mac.c
*
diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h
index d53fcef87b4a..4c6e610f1bc1 100644
--- a/drivers/staging/vt6656/mac.h
+++ b/drivers/staging/vt6656/mac.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: mac.h
*
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 01e642db311e..ee8d1e1a24c2 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: main_usb.c
*
diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c
index 13afce27951c..c025dab0f62c 100644
--- a/drivers/staging/vt6656/power.c
+++ b/drivers/staging/vt6656/power.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: power.c
*
diff --git a/drivers/staging/vt6656/power.h b/drivers/staging/vt6656/power.h
index 7696b714850c..9d1ebb695f9d 100644
--- a/drivers/staging/vt6656/power.h
+++ b/drivers/staging/vt6656/power.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: power.h
*
diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c
index c4286ccac320..816206c92f57 100644
--- a/drivers/staging/vt6656/rf.c
+++ b/drivers/staging/vt6656/rf.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: rf.c
*
diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h
index 3acdc65b1e56..c3d4f06d65f4 100644
--- a/drivers/staging/vt6656/rf.h
+++ b/drivers/staging/vt6656/rf.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: rf.h
*
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index efb54f53b4f9..a0c69b697901 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: rxtx.c
*
diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h
index 90b34ab2f6ce..4a79c404275b 100644
--- a/drivers/staging/vt6656/rxtx.h
+++ b/drivers/staging/vt6656/rxtx.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: rxtx.h
*
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index c975c3b87093..351a99f3d684 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: usbpipe.c
*
diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h
index e74aa0809928..8bafd9aee1fa 100644
--- a/drivers/staging/vt6656/usbpipe.h
+++ b/drivers/staging/vt6656/usbpipe.h
@@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*
* File: usbpipe.h
*
diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c
index 3cbf4791bac1..4846a898d39b 100644
--- a/drivers/staging/vt6656/wcmd.c
+++ b/drivers/staging/vt6656/wcmd.c
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: wcmd.c
*
diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h
index 2b0ee285eb0b..764c09ccd42d 100644
--- a/drivers/staging/vt6656/wcmd.h
+++ b/drivers/staging/vt6656/wcmd.h
@@ -12,9 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* File: wcmd.h
*
diff --git a/drivers/staging/wilc1000/Kconfig b/drivers/staging/wilc1000/Kconfig
index ee51b4278088..dce9cee9134a 100644
--- a/drivers/staging/wilc1000/Kconfig
+++ b/drivers/staging/wilc1000/Kconfig
@@ -1,41 +1,12 @@
-config WILC1000_DRIVER
- bool "WILC1000 support (WiFi only)"
- depends on CFG80211 && WEXT_CORE && INET
- ---help---
- This module only support IEEE 802.11n WiFi.
-
-if WILC1000_DRIVER
-
config WILC1000
tristate
-
-choice
- prompt "Memory Allocation"
- default WILC1000_PREALLOCATE_AT_LOADING_DRIVER
-
-config WILC1000_PREALLOCATE_AT_LOADING_DRIVER
- bool "Preallocate memory at loading driver"
+ select WIRELESS_EXT
---help---
- This choice supports static allocation of the memory
- for the receive buffer. The driver will allocate the RX buffer
- during initial time. The driver will also free the buffer
- by calling network device stop.
-
-config WILC1000_DYNAMICALLY_ALLOCATE_MEMROY
- bool "Dynamically allocate memory in real time"
- ---help---
- This choice supports dynamic allocation of the memory
- for the receive buffer. The driver will allocate the RX buffer
- when it is required.
-endchoice
-
-choice
- prompt "Bus Type"
- default WILC1000_SDIO
+ This module only support IEEE 802.11n WiFi.
config WILC1000_SDIO
- bool "SDIO support"
- depends on MMC
+ tristate "Atmel WILC1000 SDIO (WiFi only)"
+ depends on CFG80211 && INET && MMC
select WILC1000
---help---
This module adds support for the SDIO interface of adapters using
@@ -48,9 +19,9 @@ config WILC1000_SDIO
this if your platform is using the SDIO bus.
config WILC1000_SPI
- depends on SPI
+ tristate "Atmel WILC1000 SPI (WiFi only)"
+ depends on CFG80211 && INET && SPI
select WILC1000
- bool "SPI support"
---help---
This module adds support for the SPI interface of adapters using
WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral
@@ -59,10 +30,9 @@ config WILC1000_SPI
full-duplex slave synchronous serial interface that is available
immediately following reset when pin 9 (SDIO_SPI_CFG) is tied to
VDDIO. Select this if your platform is using the SPI bus.
-endchoice
config WILC1000_HW_OOB_INTR
- bool "Use out of band interrupt"
+ bool "WILC1000 out of band interrupt"
depends on WILC1000_SDIO
default n
---help---
@@ -71,5 +41,3 @@ config WILC1000_HW_OOB_INTR
mechanism for SDIO host controllers that don't support SDIO interrupt.
Select this option If the SDIO host controller in your platform
doesn't support SDIO time devision interrupt.
-
-endif
diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile
index 64c2f1b83dfb..20a5cb9d4f4c 100644
--- a/drivers/staging/wilc1000/Makefile
+++ b/drivers/staging/wilc1000/Makefile
@@ -1,28 +1,20 @@
obj-$(CONFIG_WILC1000) += wilc1000.o
-ccflags-$(CONFIG_WILC1000_SDIO) += -DWILC_SDIO -DCOMPLEMENT_BOOT
-ccflags-$(CONFIG_WILC1000_HW_OOB_INTR) += -DWILC_SDIO_IRQ_GPIO
-ccflags-$(CONFIG_WILC1000_SPI) += -DWILC_SPI
-
ccflags-y += -DSTA_FIRMWARE=\"atmel/wilc1000_fw.bin\" \
-DAP_FIRMWARE=\"atmel/wilc1000_ap_fw.bin\" \
-DP2P_CONCURRENCY_FIRMWARE=\"atmel/wilc1000_p2p_fw.bin\"
-ccflags-y += -I$(src)/ -D__CHECK_ENDIAN__ -DWILC_ASIC_A0 \
- -Wno-unused-function -DWILC_DEBUGFS
+ccflags-y += -I$(src)/ -DWILC_ASIC_A0 -DWILC_DEBUGFS
#ccflags-y += -DTCP_ACK_FILTER
-ccflags-$(CONFIG_WILC1000_PREALLOCATE_AT_LOADING_DRIVER) += -DMEMORY_STATIC \
- -DWILC_PREALLOC_AT_INSMOD
-
-ccflags-$(CONFIG_WILC1000_DYNAMICALLY_ALLOCATE_MEMROY) += -DWILC_NORMAL_ALLOC
-
-
wilc1000-objs := wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \
wilc_msgqueue.o \
coreconfigurator.o host_interface.o \
- wilc_sdio.o wilc_spi.o wilc_wlan_cfg.o wilc_debugfs.o \
+ wilc_wlan_cfg.o wilc_debugfs.o \
wilc_wlan.o
-wilc1000-$(CONFIG_WILC1000_SDIO) += linux_wlan_sdio.o
-wilc1000-$(CONFIG_WILC1000_SPI) += linux_wlan_spi.o
+obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
+wilc1000-sdio-objs += wilc_sdio.o
+
+obj-$(CONFIG_WILC1000_SPI) += wilc1000-spi.o
+wilc1000-spi-objs += wilc_spi.o
diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c
index 9568bdb6319b..2d4d3f190c01 100644
--- a/drivers/staging/wilc1000/coreconfigurator.c
+++ b/drivers/staging/wilc1000/coreconfigurator.c
@@ -287,7 +287,7 @@ static inline u16 get_asoc_id(u8 *data)
return asoc_id;
}
-u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset)
+static u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset)
{
u16 u16index;
@@ -315,7 +315,7 @@ u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset)
/* This function gets the current channel information from
* the 802.11n beacon/probe response frame */
-u8 get_current_channel_802_11n(u8 *pu8msa, u16 u16RxLen)
+static u8 get_current_channel_802_11n(u8 *pu8msa, u16 u16RxLen)
{
u16 index;
@@ -344,7 +344,7 @@ u8 get_current_channel_802_11n(u8 *pu8msa, u16 u16RxLen)
* @date 1 Mar 2012
* @version 1.0
*/
-s32 parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo)
+s32 wilc_parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo)
{
tstrNetworkInfo *pstrNetworkInfo = NULL;
u8 u8MsgType = 0;
@@ -436,7 +436,7 @@ s32 parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo)
/* Get DTIM Period */
pu8TimElm = get_tim_elm(pu8msa, u16RxLen + FCS_LEN, u8index);
- if (pu8TimElm != NULL)
+ if (pu8TimElm)
pstrNetworkInfo->u8DtimPeriod = pu8TimElm[3];
pu8IEs = &pu8msa[MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN];
u16IEsLen = u16RxLen - (MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN);
@@ -466,12 +466,12 @@ s32 parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo)
* @date 1 Mar 2012
* @version 1.0
*/
-s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo)
+s32 wilc_dealloc_network_info(tstrNetworkInfo *pstrNetworkInfo)
{
s32 s32Error = 0;
- if (pstrNetworkInfo != NULL) {
- if (pstrNetworkInfo->pu8IEs != NULL) {
+ if (pstrNetworkInfo) {
+ if (pstrNetworkInfo->pu8IEs) {
kfree(pstrNetworkInfo->pu8IEs);
pstrNetworkInfo->pu8IEs = NULL;
} else {
@@ -499,7 +499,7 @@ s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo)
* @date 2 Apr 2012
* @version 1.0
*/
-s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen,
+s32 wilc_parse_assoc_resp_info(u8 *pu8Buffer, u32 u32BufferLen,
tstrConnectRespInfo **ppstrConnectRespInfo)
{
s32 s32Error = 0;
@@ -551,12 +551,12 @@ s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen,
* @date 2 Apr 2012
* @version 1.0
*/
-s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo)
+s32 wilc_dealloc_assoc_resp_info(tstrConnectRespInfo *pstrConnectRespInfo)
{
s32 s32Error = 0;
- if (pstrConnectRespInfo != NULL) {
- if (pstrConnectRespInfo->pu8RespIEs != NULL) {
+ if (pstrConnectRespInfo) {
+ if (pstrConnectRespInfo->pu8RespIEs) {
kfree(pstrConnectRespInfo->pu8RespIEs);
pstrConnectRespInfo->pu8RespIEs = NULL;
} else {
@@ -588,7 +588,8 @@ s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo)
* @date 1 Mar 2012
* @version 1.0
*/
-s32 send_config_pkt(u8 mode, struct wid *wids, u32 count, u32 drv)
+s32 wilc_send_config_pkt(struct wilc *wilc, u8 mode, struct wid *wids,
+ u32 count, u32 drv)
{
s32 counter = 0, ret = 0;
@@ -596,11 +597,11 @@ s32 send_config_pkt(u8 mode, struct wid *wids, u32 count, u32 drv)
for (counter = 0; counter < count; counter++) {
PRINT_INFO(CORECONFIG_DBG, "Sending CFG packet [%d][%d]\n", !counter,
(counter == count - 1));
- if (!wilc_wlan_cfg_get(!counter,
+ if (!wilc_wlan_cfg_get(wilc, !counter,
wids[counter].id,
(counter == count - 1),
drv)) {
- ret = -1;
+ ret = -ETIMEDOUT;
printk("[Sendconfigpkt]Get Timed out\n");
break;
}
@@ -611,18 +612,17 @@ s32 send_config_pkt(u8 mode, struct wid *wids, u32 count, u32 drv)
wids[counter].id,
wids[counter].val,
wids[counter].size);
-
}
} else if (mode == SET_CFG) {
for (counter = 0; counter < count; counter++) {
PRINT_D(CORECONFIG_DBG, "Sending config SET PACKET WID:%x\n", wids[counter].id);
- if (!wilc_wlan_cfg_set(!counter,
+ if (!wilc_wlan_cfg_set(wilc, !counter,
wids[counter].id,
wids[counter].val,
wids[counter].size,
(counter == count - 1),
drv)) {
- ret = -1;
+ ret = -ETIMEDOUT;
printk("[Sendconfigpkt]Set Timed out\n");
break;
}
diff --git a/drivers/staging/wilc1000/coreconfigurator.h b/drivers/staging/wilc1000/coreconfigurator.h
index 6294d929a800..fc43d04ca1da 100644
--- a/drivers/staging/wilc1000/coreconfigurator.h
+++ b/drivers/staging/wilc1000/coreconfigurator.h
@@ -72,7 +72,7 @@ typedef enum {
struct wid {
u16 id;
- enum WID_TYPE type;
+ enum wid_type type;
s32 size;
s8 *val;
};
@@ -127,16 +127,18 @@ typedef struct {
size_t ie_len;
} tstrDisconnectNotifInfo;
-s32 send_config_pkt(u8 mode, struct wid *wids, u32 count, u32 drv);
-s32 parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo);
-s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo);
+s32 wilc_send_config_pkt(struct wilc *wilc, u8 mode, struct wid *wids,
+ u32 count, u32 drv);
+s32 wilc_parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo);
+s32 wilc_dealloc_network_info(tstrNetworkInfo *pstrNetworkInfo);
-s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen,
+s32 wilc_parse_assoc_resp_info(u8 *pu8Buffer, u32 u32BufferLen,
tstrConnectRespInfo **ppstrConnectRespInfo);
-s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo);
-
-void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length);
-void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length);
-void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length);
-
+s32 wilc_dealloc_assoc_resp_info(tstrConnectRespInfo *pstrConnectRespInfo);
+void wilc_scan_complete_received(struct wilc *wilc, u8 *pu8Buffer,
+ u32 u32Length);
+void wilc_network_info_received(struct wilc *wilc, u8 *pu8Buffer,
+ u32 u32Length);
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *pu8Buffer,
+ u32 u32Length);
#endif
diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c
index dbbe72c7e255..8c7752034032 100644
--- a/drivers/staging/wilc1000/host_interface.c
+++ b/drivers/staging/wilc1000/host_interface.c
@@ -4,17 +4,12 @@
#include <linux/delay.h>
#include "host_interface.h"
#include "coreconfigurator.h"
+#include "wilc_wlan.h"
#include "wilc_wlan_if.h"
#include "wilc_msgqueue.h"
#include <linux/etherdevice.h>
#include "wilc_wfi_netdevice.h"
-extern u8 connecting;
-
-extern struct timer_list hDuringIpTimer;
-
-extern u8 g_wilc_initialized;
-
#define HOST_IF_MSG_SCAN 0
#define HOST_IF_MSG_CONNECT 1
#define HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO 2
@@ -48,7 +43,6 @@ extern u8 g_wilc_initialized;
#define HOST_IF_MSG_FLUSH_CONNECT 30
#define HOST_IF_MSG_GET_STATISTICS 31
#define HOST_IF_MSG_SET_MULTICAST_FILTER 32
-#define HOST_IF_MSG_ADD_BA_SESSION 33
#define HOST_IF_MSG_DEL_BA_SESSION 34
#define HOST_IF_MSG_Q_IDLE 35
#define HOST_IF_MSG_DEL_ALL_STA 36
@@ -199,7 +193,7 @@ union message_body {
struct host_if_msg {
u16 id;
union message_body body;
- struct host_if_drv *drv;
+ struct wilc_vif *vif;
};
struct join_bss_param {
@@ -231,10 +225,9 @@ struct join_bss_param {
u8 start_time[4];
};
-static struct host_if_drv *wfidrv_list[NUM_CONCURRENT_IFC + 1];
struct host_if_drv *terminated_handle;
-bool g_obtainingIP;
-u8 P2P_LISTEN_STATE;
+bool wilc_optaining_ip;
+static u8 P2P_LISTEN_STATE;
static struct task_struct *hif_thread_handler;
static WILC_MsgQueueHandle hif_msg_q;
static struct semaphore hif_sema_thread;
@@ -243,7 +236,7 @@ static struct semaphore hif_sema_wait_response;
static struct semaphore hif_sema_deinit;
static struct timer_list periodic_rssi;
-u8 gau8MulticastMacAddrList[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
+u8 wilc_multicast_mac_addr_list[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
static u8 rcv_assoc_resp[MAX_ASSOC_RESP_FRAME_SIZE];
@@ -259,86 +252,57 @@ static u8 del_beacon;
static u32 clients_count;
static u8 *join_req;
-u8 *info_element;
+static u8 *info_element;
static u8 mode_11i;
-u8 auth_type;
-u32 join_req_size;
+static u8 auth_type;
+static u32 join_req_size;
static u32 info_element_size;
-static struct host_if_drv *join_req_drv;
+static struct wilc_vif *join_req_vif;
#define REAL_JOIN_REQ 0
#define FLUSHED_JOIN_REQ 1
#define FLUSHED_BYTE_POS 79
static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo);
-extern void chip_sleep_manually(u32 u32SleepTime);
-extern int linux_wlan_get_num_conn_ifcs(void);
-
-static int add_handler_in_list(struct host_if_drv *handler)
+/* The u8IfIdx starts from 0 to NUM_CONCURRENT_IFC -1, but 0 index used as
+ * special purpose in wilc device, so we add 1 to the index to starts from 1.
+ * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.
+ */
+int wilc_get_vif_idx(struct wilc_vif *vif)
{
- int i;
-
- for (i = 1; i < ARRAY_SIZE(wfidrv_list); i++) {
- if (!wfidrv_list[i]) {
- wfidrv_list[i] = handler;
- return 0;
- }
- }
-
- return -ENOBUFS;
+ return vif->u8IfIdx + 1;
}
-static int remove_handler_in_list(struct host_if_drv *handler)
+/* We need to minus 1 from idx which is from wilc device to get real index
+ * of wilc->vif[], because we add 1 when pass to wilc device in the function
+ * wilc_get_vif_idx.
+ * As a result, the index should be between 0 and NUM_CONCURRENT_IFC -1.
+ */
+static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)
{
- int i;
+ int index = idx - 1;
- for (i = 1; i < ARRAY_SIZE(wfidrv_list); i++) {
- if (wfidrv_list[i] == handler) {
- wfidrv_list[i] = NULL;
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-static int get_id_from_handler(struct host_if_drv *handler)
-{
- int i;
-
- if (!handler)
- return 0;
-
- for (i = 1; i < ARRAY_SIZE(wfidrv_list); i++) {
- if (wfidrv_list[i] == handler)
- return i;
- }
-
- return 0;
-}
-
-static struct host_if_drv *get_handler_from_id(int id)
-{
- if (id <= 0 || id >= ARRAY_SIZE(wfidrv_list))
+ if (index < 0 || index >= NUM_CONCURRENT_IFC)
return NULL;
- return wfidrv_list[id];
+
+ return wilc->vif[index];
}
-static s32 Handle_SetChannel(struct host_if_drv *hif_drv,
- struct channel_attr *pstrHostIFSetChan)
+static s32 handle_set_channel(struct wilc_vif *vif,
+ struct channel_attr *hif_set_ch)
{
s32 result = 0;
struct wid wid;
wid.id = (u16)WID_CURRENT_CHANNEL;
wid.type = WID_CHAR;
- wid.val = (char *)&pstrHostIFSetChan->set_ch;
+ wid.val = (char *)&hif_set_ch->set_ch;
wid.size = sizeof(char);
PRINT_D(HOSTINF_DBG, "Setting channel\n");
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to set channel\n");
@@ -348,21 +312,21 @@ static s32 Handle_SetChannel(struct host_if_drv *hif_drv,
return result;
}
-static s32 Handle_SetWfiDrvHandler(struct host_if_drv *hif_drv,
- struct drv_handler *pstrHostIfSetDrvHandler)
+static s32 handle_set_wfi_drv_handler(struct wilc_vif *vif,
+ struct drv_handler *hif_drv_handler)
{
s32 result = 0;
struct wid wid;
wid.id = (u16)WID_SET_DRV_HANDLER;
wid.type = WID_INT;
- wid.val = (s8 *)&pstrHostIfSetDrvHandler->handler;
+ wid.val = (s8 *)&hif_drv_handler->handler;
wid.size = sizeof(u32);
- result = send_config_pkt(SET_CFG, &wid, 1,
- pstrHostIfSetDrvHandler->handler);
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ hif_drv_handler->handler);
- if (!hif_drv)
+ if (!hif_drv_handler->handler)
up(&hif_sema_driver);
if (result) {
@@ -373,21 +337,21 @@ static s32 Handle_SetWfiDrvHandler(struct host_if_drv *hif_drv,
return result;
}
-static s32 Handle_SetOperationMode(struct host_if_drv *hif_drv,
- struct op_mode *pstrHostIfSetOperationMode)
+static s32 handle_set_operation_mode(struct wilc_vif *vif,
+ struct op_mode *hif_op_mode)
{
s32 result = 0;
struct wid wid;
wid.id = (u16)WID_SET_OPERATION_MODE;
wid.type = WID_INT;
- wid.val = (s8 *)&pstrHostIfSetOperationMode->mode;
+ wid.val = (s8 *)&hif_op_mode->mode;
wid.size = sizeof(u32);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
- if ((pstrHostIfSetOperationMode->mode) == IDLE_MODE)
+ if ((hif_op_mode->mode) == IDLE_MODE)
up(&hif_sema_driver);
if (result) {
@@ -398,28 +362,34 @@ static s32 Handle_SetOperationMode(struct host_if_drv *hif_drv,
return result;
}
-s32 Handle_set_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx)
+static s32 host_int_get_ipaddress(struct wilc_vif *vif,
+ struct host_if_drv *hif_drv,
+ u8 *u16ipadd, u8 idx);
+
+static s32 handle_set_ip_address(struct wilc_vif *vif, u8 *ip_addr, u8 idx)
{
s32 result = 0;
struct wid wid;
- char firmwareIPAddress[4] = {0};
+ char firmware_ip_addr[4] = {0};
+ struct host_if_drv *hif_drv = vif->hif_drv;
- if (pu8IPAddr[0] < 192)
- pu8IPAddr[0] = 0;
+ if (ip_addr[0] < 192)
+ ip_addr[0] = 0;
- PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %pI4\n", idx, pu8IPAddr);
+ PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %pI4\n",
+ idx, ip_addr);
- memcpy(set_ip[idx], pu8IPAddr, IP_ALEN);
+ memcpy(set_ip[idx], ip_addr, IP_ALEN);
wid.id = (u16)WID_IP_ADDRESS;
wid.type = WID_STR;
- wid.val = (u8 *)pu8IPAddr;
+ wid.val = (u8 *)ip_addr;
wid.size = IP_ALEN;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
- host_int_get_ipaddress(hif_drv, firmwareIPAddress, idx);
+ host_int_get_ipaddress(vif, hif_drv, firmware_ip_addr, idx);
if (result) {
PRINT_ER("Failed to set IP address\n");
@@ -431,7 +401,7 @@ s32 Handle_set_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx)
return result;
}
-s32 Handle_get_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx)
+static s32 handle_get_ip_address(struct wilc_vif *vif, u8 idx)
{
s32 result = 0;
struct wid wid;
@@ -441,8 +411,8 @@ s32 Handle_get_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx)
wid.val = kmalloc(IP_ALEN, GFP_KERNEL);
wid.size = IP_ALEN;
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
PRINT_INFO(HOSTINF_DBG, "%pI4\n", wid.val);
@@ -451,7 +421,7 @@ s32 Handle_get_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx)
kfree(wid.val);
if (memcmp(get_ip[idx], set_ip[idx], IP_ALEN) != 0)
- host_int_setup_ipaddress(hif_drv, set_ip[idx], idx);
+ wilc_setup_ipaddress(vif, set_ip[idx], idx);
if (result != 0) {
PRINT_ER("Failed to get IP address\n");
@@ -465,8 +435,8 @@ s32 Handle_get_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx)
return result;
}
-static s32 Handle_SetMacAddress(struct host_if_drv *hif_drv,
- struct set_mac_addr *pstrHostIfSetMacAddress)
+static s32 handle_set_mac_address(struct wilc_vif *vif,
+ struct set_mac_addr *set_mac_addr)
{
s32 result = 0;
struct wid wid;
@@ -476,7 +446,7 @@ static s32 Handle_SetMacAddress(struct host_if_drv *hif_drv,
PRINT_ER("No buffer to send mac address\n");
return -EFAULT;
}
- memcpy(mac_buf, pstrHostIfSetMacAddress->mac_addr, ETH_ALEN);
+ memcpy(mac_buf, set_mac_addr->mac_addr, ETH_ALEN);
wid.id = (u16)WID_MAC_ADDR;
wid.type = WID_STR;
@@ -484,8 +454,8 @@ static s32 Handle_SetMacAddress(struct host_if_drv *hif_drv,
wid.size = ETH_ALEN;
PRINT_D(GENERIC_DBG, "mac addr = :%pM\n", wid.val);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to set mac address\n");
result = -EFAULT;
@@ -495,19 +465,19 @@ static s32 Handle_SetMacAddress(struct host_if_drv *hif_drv,
return result;
}
-static s32 Handle_GetMacAddress(struct host_if_drv *hif_drv,
- struct get_mac_addr *pstrHostIfGetMacAddress)
+static s32 handle_get_mac_address(struct wilc_vif *vif,
+ struct get_mac_addr *get_mac_addr)
{
s32 result = 0;
struct wid wid;
wid.id = (u16)WID_MAC_ADDR;
wid.type = WID_STR;
- wid.val = pstrHostIfGetMacAddress->mac_addr;
+ wid.val = get_mac_addr->mac_addr;
wid.size = ETH_ALEN;
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to get mac address\n");
@@ -518,258 +488,270 @@ static s32 Handle_GetMacAddress(struct host_if_drv *hif_drv,
return result;
}
-static s32 Handle_CfgParam(struct host_if_drv *hif_drv,
- struct cfg_param_attr *strHostIFCfgParamAttr)
+static s32 handle_cfg_param(struct wilc_vif *vif,
+ struct cfg_param_attr *cfg_param_attr)
{
s32 result = 0;
- struct wid strWIDList[32];
- u8 u8WidCnt = 0;
+ struct wid wid_list[32];
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ u8 wid_cnt = 0;
- down(&hif_drv->gtOsCfgValuesSem);
+ down(&hif_drv->sem_cfg_values);
PRINT_D(HOSTINF_DBG, "Setting CFG params\n");
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & BSS_TYPE) {
- if (strHostIFCfgParamAttr->cfg_attr_info.bss_type < 6) {
- strWIDList[u8WidCnt].id = WID_BSS_TYPE;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.bss_type;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.bss_type = (u8)strHostIFCfgParamAttr->cfg_attr_info.bss_type;
+ if (cfg_param_attr->cfg_attr_info.flag & BSS_TYPE) {
+ if (cfg_param_attr->cfg_attr_info.bss_type < 6) {
+ wid_list[wid_cnt].id = WID_BSS_TYPE;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.bss_type;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.bss_type = (u8)cfg_param_attr->cfg_attr_info.bss_type;
} else {
PRINT_ER("check value 6 over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & AUTH_TYPE) {
- if ((strHostIFCfgParamAttr->cfg_attr_info.auth_type) == 1 || (strHostIFCfgParamAttr->cfg_attr_info.auth_type) == 2 || (strHostIFCfgParamAttr->cfg_attr_info.auth_type) == 5) {
- strWIDList[u8WidCnt].id = WID_AUTH_TYPE;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.auth_type;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.auth_type = (u8)strHostIFCfgParamAttr->cfg_attr_info.auth_type;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & AUTH_TYPE) {
+ if (cfg_param_attr->cfg_attr_info.auth_type == 1 ||
+ cfg_param_attr->cfg_attr_info.auth_type == 2 ||
+ cfg_param_attr->cfg_attr_info.auth_type == 5) {
+ wid_list[wid_cnt].id = WID_AUTH_TYPE;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.auth_type;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.auth_type = (u8)cfg_param_attr->cfg_attr_info.auth_type;
} else {
PRINT_ER("Impossible value \n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & AUTHEN_TIMEOUT) {
- if (strHostIFCfgParamAttr->cfg_attr_info.auth_timeout > 0 && strHostIFCfgParamAttr->cfg_attr_info.auth_timeout < 65536) {
- strWIDList[u8WidCnt].id = WID_AUTH_TIMEOUT;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.auth_timeout;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.auth_timeout = strHostIFCfgParamAttr->cfg_attr_info.auth_timeout;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & AUTHEN_TIMEOUT) {
+ if (cfg_param_attr->cfg_attr_info.auth_timeout > 0 &&
+ cfg_param_attr->cfg_attr_info.auth_timeout < 65536) {
+ wid_list[wid_cnt].id = WID_AUTH_TIMEOUT;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.auth_timeout;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.auth_timeout = cfg_param_attr->cfg_attr_info.auth_timeout;
} else {
PRINT_ER("Range(1 ~ 65535) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & POWER_MANAGEMENT) {
- if (strHostIFCfgParamAttr->cfg_attr_info.power_mgmt_mode < 5) {
- strWIDList[u8WidCnt].id = WID_POWER_MANAGEMENT;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.power_mgmt_mode;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.power_mgmt_mode = (u8)strHostIFCfgParamAttr->cfg_attr_info.power_mgmt_mode;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & POWER_MANAGEMENT) {
+ if (cfg_param_attr->cfg_attr_info.power_mgmt_mode < 5) {
+ wid_list[wid_cnt].id = WID_POWER_MANAGEMENT;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.power_mgmt_mode;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.power_mgmt_mode = (u8)cfg_param_attr->cfg_attr_info.power_mgmt_mode;
} else {
PRINT_ER("Invalide power mode\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & RETRY_SHORT) {
- if ((strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit > 0) && (strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit < 256)) {
- strWIDList[u8WidCnt].id = WID_SHORT_RETRY_LIMIT;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.short_retry_limit = strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & RETRY_SHORT) {
+ if (cfg_param_attr->cfg_attr_info.short_retry_limit > 0 &&
+ cfg_param_attr->cfg_attr_info.short_retry_limit < 256) {
+ wid_list[wid_cnt].id = WID_SHORT_RETRY_LIMIT;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.short_retry_limit;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.short_retry_limit = cfg_param_attr->cfg_attr_info.short_retry_limit;
} else {
PRINT_ER("Range(1~256) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & RETRY_LONG) {
- if ((strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit > 0) && (strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit < 256)) {
- strWIDList[u8WidCnt].id = WID_LONG_RETRY_LIMIT;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit;
-
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.long_retry_limit = strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & RETRY_LONG) {
+ if (cfg_param_attr->cfg_attr_info.long_retry_limit > 0 &&
+ cfg_param_attr->cfg_attr_info.long_retry_limit < 256) {
+ wid_list[wid_cnt].id = WID_LONG_RETRY_LIMIT;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.long_retry_limit;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.long_retry_limit = cfg_param_attr->cfg_attr_info.long_retry_limit;
} else {
PRINT_ER("Range(1~256) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & FRAG_THRESHOLD) {
- if (strHostIFCfgParamAttr->cfg_attr_info.frag_threshold > 255 && strHostIFCfgParamAttr->cfg_attr_info.frag_threshold < 7937) {
- strWIDList[u8WidCnt].id = WID_FRAG_THRESHOLD;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.frag_threshold;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.frag_threshold = strHostIFCfgParamAttr->cfg_attr_info.frag_threshold;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & FRAG_THRESHOLD) {
+ if (cfg_param_attr->cfg_attr_info.frag_threshold > 255 &&
+ cfg_param_attr->cfg_attr_info.frag_threshold < 7937) {
+ wid_list[wid_cnt].id = WID_FRAG_THRESHOLD;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.frag_threshold;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.frag_threshold = cfg_param_attr->cfg_attr_info.frag_threshold;
} else {
PRINT_ER("Threshold Range fail\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & RTS_THRESHOLD) {
- if (strHostIFCfgParamAttr->cfg_attr_info.rts_threshold > 255 && strHostIFCfgParamAttr->cfg_attr_info.rts_threshold < 65536) {
- strWIDList[u8WidCnt].id = WID_RTS_THRESHOLD;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.rts_threshold;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.rts_threshold = strHostIFCfgParamAttr->cfg_attr_info.rts_threshold;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & RTS_THRESHOLD) {
+ if (cfg_param_attr->cfg_attr_info.rts_threshold > 255 &&
+ cfg_param_attr->cfg_attr_info.rts_threshold < 65536) {
+ wid_list[wid_cnt].id = WID_RTS_THRESHOLD;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.rts_threshold;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.rts_threshold = cfg_param_attr->cfg_attr_info.rts_threshold;
} else {
PRINT_ER("Threshold Range fail\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & PREAMBLE) {
- if (strHostIFCfgParamAttr->cfg_attr_info.preamble_type < 3) {
- strWIDList[u8WidCnt].id = WID_PREAMBLE;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.preamble_type;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.preamble_type = strHostIFCfgParamAttr->cfg_attr_info.preamble_type;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & PREAMBLE) {
+ if (cfg_param_attr->cfg_attr_info.preamble_type < 3) {
+ wid_list[wid_cnt].id = WID_PREAMBLE;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.preamble_type;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.preamble_type = cfg_param_attr->cfg_attr_info.preamble_type;
} else {
PRINT_ER("Preamle Range(0~2) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & SHORT_SLOT_ALLOWED) {
- if (strHostIFCfgParamAttr->cfg_attr_info.short_slot_allowed < 2) {
- strWIDList[u8WidCnt].id = WID_SHORT_SLOT_ALLOWED;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.short_slot_allowed;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.short_slot_allowed = (u8)strHostIFCfgParamAttr->cfg_attr_info.short_slot_allowed;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & SHORT_SLOT_ALLOWED) {
+ if (cfg_param_attr->cfg_attr_info.short_slot_allowed < 2) {
+ wid_list[wid_cnt].id = WID_SHORT_SLOT_ALLOWED;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.short_slot_allowed;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.short_slot_allowed = (u8)cfg_param_attr->cfg_attr_info.short_slot_allowed;
} else {
PRINT_ER("Short slot(2) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & TXOP_PROT_DISABLE) {
- if (strHostIFCfgParamAttr->cfg_attr_info.txop_prot_disabled < 2) {
- strWIDList[u8WidCnt].id = WID_11N_TXOP_PROT_DISABLE;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.txop_prot_disabled;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.txop_prot_disabled = (u8)strHostIFCfgParamAttr->cfg_attr_info.txop_prot_disabled;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & TXOP_PROT_DISABLE) {
+ if (cfg_param_attr->cfg_attr_info.txop_prot_disabled < 2) {
+ wid_list[wid_cnt].id = WID_11N_TXOP_PROT_DISABLE;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.txop_prot_disabled;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.txop_prot_disabled = (u8)cfg_param_attr->cfg_attr_info.txop_prot_disabled;
} else {
PRINT_ER("TXOP prot disable\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & BEACON_INTERVAL) {
- if (strHostIFCfgParamAttr->cfg_attr_info.beacon_interval > 0 && strHostIFCfgParamAttr->cfg_attr_info.beacon_interval < 65536) {
- strWIDList[u8WidCnt].id = WID_BEACON_INTERVAL;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.beacon_interval;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.beacon_interval = strHostIFCfgParamAttr->cfg_attr_info.beacon_interval;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & BEACON_INTERVAL) {
+ if (cfg_param_attr->cfg_attr_info.beacon_interval > 0 &&
+ cfg_param_attr->cfg_attr_info.beacon_interval < 65536) {
+ wid_list[wid_cnt].id = WID_BEACON_INTERVAL;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.beacon_interval;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.beacon_interval = cfg_param_attr->cfg_attr_info.beacon_interval;
} else {
PRINT_ER("Beacon interval(1~65535) fail\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & DTIM_PERIOD) {
- if (strHostIFCfgParamAttr->cfg_attr_info.dtim_period > 0 && strHostIFCfgParamAttr->cfg_attr_info.dtim_period < 256) {
- strWIDList[u8WidCnt].id = WID_DTIM_PERIOD;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.dtim_period;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.dtim_period = strHostIFCfgParamAttr->cfg_attr_info.dtim_period;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & DTIM_PERIOD) {
+ if (cfg_param_attr->cfg_attr_info.dtim_period > 0 &&
+ cfg_param_attr->cfg_attr_info.dtim_period < 256) {
+ wid_list[wid_cnt].id = WID_DTIM_PERIOD;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.dtim_period;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.dtim_period = cfg_param_attr->cfg_attr_info.dtim_period;
} else {
PRINT_ER("DTIM range(1~255) fail\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & SITE_SURVEY) {
- if (strHostIFCfgParamAttr->cfg_attr_info.site_survey_enabled < 3) {
- strWIDList[u8WidCnt].id = WID_SITE_SURVEY;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.site_survey_enabled;
- strWIDList[u8WidCnt].type = WID_CHAR;
- strWIDList[u8WidCnt].size = sizeof(char);
- hif_drv->strCfgValues.site_survey_enabled = (u8)strHostIFCfgParamAttr->cfg_attr_info.site_survey_enabled;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & SITE_SURVEY) {
+ if (cfg_param_attr->cfg_attr_info.site_survey_enabled < 3) {
+ wid_list[wid_cnt].id = WID_SITE_SURVEY;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.site_survey_enabled;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ hif_drv->cfg_values.site_survey_enabled = (u8)cfg_param_attr->cfg_attr_info.site_survey_enabled;
} else {
PRINT_ER("Site survey disable\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & SITE_SURVEY_SCAN_TIME) {
- if (strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time > 0 && strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time < 65536) {
- strWIDList[u8WidCnt].id = WID_SITE_SURVEY_SCAN_TIME;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.site_survey_scan_time = strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & SITE_SURVEY_SCAN_TIME) {
+ if (cfg_param_attr->cfg_attr_info.site_survey_scan_time > 0 &&
+ cfg_param_attr->cfg_attr_info.site_survey_scan_time < 65536) {
+ wid_list[wid_cnt].id = WID_SITE_SURVEY_SCAN_TIME;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.site_survey_scan_time;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.site_survey_scan_time = cfg_param_attr->cfg_attr_info.site_survey_scan_time;
} else {
PRINT_ER("Site survey scan time(1~65535) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & ACTIVE_SCANTIME) {
- if (strHostIFCfgParamAttr->cfg_attr_info.active_scan_time > 0 && strHostIFCfgParamAttr->cfg_attr_info.active_scan_time < 65536) {
- strWIDList[u8WidCnt].id = WID_ACTIVE_SCAN_TIME;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.active_scan_time;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.active_scan_time = strHostIFCfgParamAttr->cfg_attr_info.active_scan_time;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & ACTIVE_SCANTIME) {
+ if (cfg_param_attr->cfg_attr_info.active_scan_time > 0 &&
+ cfg_param_attr->cfg_attr_info.active_scan_time < 65536) {
+ wid_list[wid_cnt].id = WID_ACTIVE_SCAN_TIME;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.active_scan_time;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.active_scan_time = cfg_param_attr->cfg_attr_info.active_scan_time;
} else {
PRINT_ER("Active scan time(1~65535) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
- }
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & PASSIVE_SCANTIME) {
- if (strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time > 0 && strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time < 65536) {
- strWIDList[u8WidCnt].id = WID_PASSIVE_SCAN_TIME;
- strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.passive_scan_time = strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time;
+ wid_cnt++;
+ }
+ if (cfg_param_attr->cfg_attr_info.flag & PASSIVE_SCANTIME) {
+ if (cfg_param_attr->cfg_attr_info.passive_scan_time > 0 &&
+ cfg_param_attr->cfg_attr_info.passive_scan_time < 65536) {
+ wid_list[wid_cnt].id = WID_PASSIVE_SCAN_TIME;
+ wid_list[wid_cnt].val = (s8 *)&cfg_param_attr->cfg_attr_info.passive_scan_time;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.passive_scan_time = cfg_param_attr->cfg_attr_info.passive_scan_time;
} else {
PRINT_ER("Passive scan time(1~65535) over\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
+ wid_cnt++;
}
- if (strHostIFCfgParamAttr->cfg_attr_info.flag & CURRENT_TX_RATE) {
- enum CURRENT_TXRATE curr_tx_rate = strHostIFCfgParamAttr->cfg_attr_info.curr_tx_rate;
+ if (cfg_param_attr->cfg_attr_info.flag & CURRENT_TX_RATE) {
+ enum CURRENT_TXRATE curr_tx_rate = cfg_param_attr->cfg_attr_info.curr_tx_rate;
if (curr_tx_rate == AUTORATE || curr_tx_rate == MBPS_1
|| curr_tx_rate == MBPS_2 || curr_tx_rate == MBPS_5_5
@@ -777,38 +759,40 @@ static s32 Handle_CfgParam(struct host_if_drv *hif_drv,
|| curr_tx_rate == MBPS_9 || curr_tx_rate == MBPS_12
|| curr_tx_rate == MBPS_18 || curr_tx_rate == MBPS_24
|| curr_tx_rate == MBPS_36 || curr_tx_rate == MBPS_48 || curr_tx_rate == MBPS_54) {
- strWIDList[u8WidCnt].id = WID_CURRENT_TX_RATE;
- strWIDList[u8WidCnt].val = (s8 *)&curr_tx_rate;
- strWIDList[u8WidCnt].type = WID_SHORT;
- strWIDList[u8WidCnt].size = sizeof(u16);
- hif_drv->strCfgValues.curr_tx_rate = (u8)curr_tx_rate;
+ wid_list[wid_cnt].id = WID_CURRENT_TX_RATE;
+ wid_list[wid_cnt].val = (s8 *)&curr_tx_rate;
+ wid_list[wid_cnt].type = WID_SHORT;
+ wid_list[wid_cnt].size = sizeof(u16);
+ hif_drv->cfg_values.curr_tx_rate = (u8)curr_tx_rate;
} else {
PRINT_ER("out of TX rate\n");
result = -EINVAL;
goto ERRORHANDLER;
}
- u8WidCnt++;
+ wid_cnt++;
}
- result = send_config_pkt(SET_CFG, strWIDList, u8WidCnt,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, wid_list,
+ wid_cnt, wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Error in setting CFG params\n");
ERRORHANDLER:
- up(&hif_drv->gtOsCfgValuesSem);
+ up(&hif_drv->sem_cfg_values);
return result;
}
-static s32 Handle_wait_msg_q_empty(void)
+static void Handle_wait_msg_q_empty(void)
{
- g_wilc_initialized = 0;
+ wilc_initialized = 0;
up(&hif_sema_wait_response);
- return 0;
}
-static s32 Handle_Scan(struct host_if_drv *hif_drv,
+static s32 Handle_ScanDone(struct wilc_vif *vif,
+ enum scan_event enuEvent);
+
+static s32 Handle_Scan(struct wilc_vif *vif,
struct scan_attr *pstrHostIFscanAttr)
{
s32 result = 0;
@@ -818,21 +802,24 @@ static s32 Handle_Scan(struct host_if_drv *hif_drv,
u8 *pu8Buffer;
u8 valuesize = 0;
u8 *pu8HdnNtwrksWidVal = NULL;
+ struct host_if_drv *hif_drv = vif->hif_drv;
PRINT_D(HOSTINF_DBG, "Setting SCAN params\n");
- PRINT_D(HOSTINF_DBG, "Scanning: In [%d] state\n", hif_drv->enuHostIFstate);
+ PRINT_D(HOSTINF_DBG, "Scanning: In [%d] state\n", hif_drv->hif_state);
- hif_drv->usr_scan_req.pfUserScanResult = pstrHostIFscanAttr->result;
- hif_drv->usr_scan_req.u32UserScanPvoid = pstrHostIFscanAttr->arg;
+ hif_drv->usr_scan_req.scan_result = pstrHostIFscanAttr->result;
+ hif_drv->usr_scan_req.arg = pstrHostIFscanAttr->arg;
- if ((hif_drv->enuHostIFstate >= HOST_IF_SCANNING) && (hif_drv->enuHostIFstate < HOST_IF_CONNECTED)) {
- PRINT_D(GENERIC_DBG, "Don't scan we are already in [%d] state\n", hif_drv->enuHostIFstate);
+ if ((hif_drv->hif_state >= HOST_IF_SCANNING) &&
+ (hif_drv->hif_state < HOST_IF_CONNECTED)) {
+ PRINT_D(GENERIC_DBG, "Don't scan already in [%d] state\n",
+ hif_drv->hif_state);
PRINT_ER("Already scan\n");
result = -EBUSY;
goto ERRORHANDLER;
}
- if (g_obtainingIP || connecting) {
+ if (wilc_optaining_ip || wilc_connecting) {
PRINT_D(GENERIC_DBG, "[handle_scan]: Don't do obss scan until IP adresss is obtained\n");
PRINT_ER("Don't do obss scan\n");
result = -EBUSY;
@@ -841,7 +828,7 @@ static s32 Handle_Scan(struct host_if_drv *hif_drv,
PRINT_D(HOSTINF_DBG, "Setting SCAN params\n");
- hif_drv->usr_scan_req.u32RcvdChCount = 0;
+ hif_drv->usr_scan_req.rcvd_ch_cnt = 0;
strWIDList[u32WidsCount].id = (u16)WID_SSID_PROBE_REQ;
strWIDList[u32WidsCount].type = WID_STR;
@@ -904,13 +891,14 @@ static s32 Handle_Scan(struct host_if_drv *hif_drv,
strWIDList[u32WidsCount].val = (s8 *)&pstrHostIFscanAttr->src;
u32WidsCount++;
- if (hif_drv->enuHostIFstate == HOST_IF_CONNECTED)
+ if (hif_drv->hif_state == HOST_IF_CONNECTED)
scan_while_connected = true;
- else if (hif_drv->enuHostIFstate == HOST_IF_IDLE)
+ else if (hif_drv->hif_state == HOST_IF_IDLE)
scan_while_connected = false;
- result = send_config_pkt(SET_CFG, strWIDList, u32WidsCount,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, strWIDList,
+ u32WidsCount,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send scan paramters config packet\n");
@@ -919,8 +907,8 @@ static s32 Handle_Scan(struct host_if_drv *hif_drv,
ERRORHANDLER:
if (result) {
- del_timer(&hif_drv->hScanTimer);
- Handle_ScanDone(hif_drv, SCAN_EVENT_ABORTED);
+ del_timer(&hif_drv->scan_timer);
+ Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
}
kfree(pstrHostIFscanAttr->ch_freq_list);
@@ -936,12 +924,13 @@ ERRORHANDLER:
return result;
}
-static s32 Handle_ScanDone(struct host_if_drv *hif_drv,
+static s32 Handle_ScanDone(struct wilc_vif *vif,
enum scan_event enuEvent)
{
s32 result = 0;
u8 u8abort_running_scan;
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
PRINT_D(HOSTINF_DBG, "in Handle_ScanDone()\n");
@@ -953,8 +942,8 @@ static s32 Handle_ScanDone(struct host_if_drv *hif_drv,
wid.val = (s8 *)&u8abort_running_scan;
wid.size = sizeof(char);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to set abort running scan\n");
@@ -967,17 +956,17 @@ static s32 Handle_ScanDone(struct host_if_drv *hif_drv,
return result;
}
- if (hif_drv->usr_scan_req.pfUserScanResult) {
- hif_drv->usr_scan_req.pfUserScanResult(enuEvent, NULL,
- hif_drv->usr_scan_req.u32UserScanPvoid, NULL);
- hif_drv->usr_scan_req.pfUserScanResult = NULL;
+ if (hif_drv->usr_scan_req.scan_result) {
+ hif_drv->usr_scan_req.scan_result(enuEvent, NULL,
+ hif_drv->usr_scan_req.arg, NULL);
+ hif_drv->usr_scan_req.scan_result = NULL;
}
return result;
}
-u8 u8ConnectedSSID[6] = {0};
-static s32 Handle_Connect(struct host_if_drv *hif_drv,
+u8 wilc_connected_ssid[6] = {0};
+static s32 Handle_Connect(struct wilc_vif *vif,
struct connect_attr *pstrHostIFconnectAttr)
{
s32 result = 0;
@@ -985,10 +974,11 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
u32 u32WidsCount = 0, dummyval = 0;
u8 *pu8CurrByte = NULL;
struct join_bss_param *ptstrJoinBssParam;
+ struct host_if_drv *hif_drv = vif->hif_drv;
PRINT_D(GENERIC_DBG, "Handling connect request\n");
- if (memcmp(pstrHostIFconnectAttr->bssid, u8ConnectedSSID, ETH_ALEN) == 0) {
+ if (memcmp(pstrHostIFconnectAttr->bssid, wilc_connected_ssid, ETH_ALEN) == 0) {
result = 0;
PRINT_ER("Trying to connect to an already connected AP, Discard connect request\n");
return result;
@@ -1008,7 +998,7 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
memcpy(hif_drv->usr_conn_req.pu8bssid, pstrHostIFconnectAttr->bssid, 6);
}
- hif_drv->usr_conn_req.ssidLen = pstrHostIFconnectAttr->ssid_len;
+ hif_drv->usr_conn_req.ssid_len = pstrHostIFconnectAttr->ssid_len;
if (pstrHostIFconnectAttr->ssid) {
hif_drv->usr_conn_req.pu8ssid = kmalloc(pstrHostIFconnectAttr->ssid_len + 1, GFP_KERNEL);
memcpy(hif_drv->usr_conn_req.pu8ssid,
@@ -1017,18 +1007,18 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
hif_drv->usr_conn_req.pu8ssid[pstrHostIFconnectAttr->ssid_len] = '\0';
}
- hif_drv->usr_conn_req.ConnReqIEsLen = pstrHostIFconnectAttr->ies_len;
+ hif_drv->usr_conn_req.ies_len = pstrHostIFconnectAttr->ies_len;
if (pstrHostIFconnectAttr->ies) {
- hif_drv->usr_conn_req.pu8ConnReqIEs = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL);
- memcpy(hif_drv->usr_conn_req.pu8ConnReqIEs,
+ hif_drv->usr_conn_req.ies = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL);
+ memcpy(hif_drv->usr_conn_req.ies,
pstrHostIFconnectAttr->ies,
pstrHostIFconnectAttr->ies_len);
}
hif_drv->usr_conn_req.u8security = pstrHostIFconnectAttr->security;
- hif_drv->usr_conn_req.tenuAuth_type = pstrHostIFconnectAttr->auth_type;
- hif_drv->usr_conn_req.pfUserConnectResult = pstrHostIFconnectAttr->result;
- hif_drv->usr_conn_req.u32UserConnectPvoid = pstrHostIFconnectAttr->arg;
+ hif_drv->usr_conn_req.auth_type = pstrHostIFconnectAttr->auth_type;
+ hif_drv->usr_conn_req.conn_result = pstrHostIFconnectAttr->result;
+ hif_drv->usr_conn_req.arg = pstrHostIFconnectAttr->arg;
strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT;
strWIDList[u32WidsCount].type = WID_INT;
@@ -1051,14 +1041,14 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
{
strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_ASSOCIATE;
strWIDList[u32WidsCount].type = WID_BIN_DATA;
- strWIDList[u32WidsCount].val = hif_drv->usr_conn_req.pu8ConnReqIEs;
- strWIDList[u32WidsCount].size = hif_drv->usr_conn_req.ConnReqIEsLen;
+ strWIDList[u32WidsCount].val = hif_drv->usr_conn_req.ies;
+ strWIDList[u32WidsCount].size = hif_drv->usr_conn_req.ies_len;
u32WidsCount++;
if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
- info_element_size = hif_drv->usr_conn_req.ConnReqIEsLen;
+ info_element_size = hif_drv->usr_conn_req.ies_len;
info_element = kmalloc(info_element_size, GFP_KERNEL);
- memcpy(info_element, hif_drv->usr_conn_req.pu8ConnReqIEs,
+ memcpy(info_element, hif_drv->usr_conn_req.ies,
info_element_size);
}
}
@@ -1076,13 +1066,14 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
strWIDList[u32WidsCount].id = (u16)WID_AUTH_TYPE;
strWIDList[u32WidsCount].type = WID_CHAR;
strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)(&hif_drv->usr_conn_req.tenuAuth_type);
+ strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.auth_type;
u32WidsCount++;
if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7))
- auth_type = (u8)hif_drv->usr_conn_req.tenuAuth_type;
+ auth_type = (u8)hif_drv->usr_conn_req.auth_type;
- PRINT_INFO(HOSTINF_DBG, "Authentication Type = %x\n", hif_drv->usr_conn_req.tenuAuth_type);
+ PRINT_INFO(HOSTINF_DBG, "Authentication Type = %x\n",
+ hif_drv->usr_conn_req.auth_type);
PRINT_D(HOSTINF_DBG, "Connecting to network of SSID %s on channel %d\n",
hif_drv->usr_conn_req.pu8ssid, pstrHostIFconnectAttr->ch);
@@ -1141,7 +1132,7 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
*(pu8CurrByte++) = ptstrJoinBssParam->uapsd_cap;
*(pu8CurrByte++) = ptstrJoinBssParam->ht_capable;
- hif_drv->usr_conn_req.IsHTCapable = ptstrJoinBssParam->ht_capable;
+ hif_drv->usr_conn_req.ht_capable = ptstrJoinBssParam->ht_capable;
*(pu8CurrByte++) = ptstrJoinBssParam->rsn_found;
PRINT_D(HOSTINF_DBG, "* rsn found %d*\n", *(pu8CurrByte - 1));
@@ -1194,36 +1185,38 @@ static s32 Handle_Connect(struct host_if_drv *hif_drv,
if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
memcpy(join_req, pu8CurrByte, join_req_size);
- join_req_drv = hif_drv;
+ join_req_vif = vif;
}
PRINT_D(GENERIC_DBG, "send HOST_IF_WAITING_CONN_RESP\n");
if (pstrHostIFconnectAttr->bssid) {
- memcpy(u8ConnectedSSID, pstrHostIFconnectAttr->bssid, ETH_ALEN);
-
- PRINT_D(GENERIC_DBG, "save Bssid = %pM\n", pstrHostIFconnectAttr->bssid);
- PRINT_D(GENERIC_DBG, "save bssid = %pM\n", u8ConnectedSSID);
+ memcpy(wilc_connected_ssid,
+ pstrHostIFconnectAttr->bssid, ETH_ALEN);
+ PRINT_D(GENERIC_DBG, "save Bssid = %pM\n",
+ pstrHostIFconnectAttr->bssid);
+ PRINT_D(GENERIC_DBG, "save bssid = %pM\n", wilc_connected_ssid);
}
- result = send_config_pkt(SET_CFG, strWIDList, u32WidsCount,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, strWIDList,
+ u32WidsCount,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("failed to send config packet\n");
result = -EFAULT;
goto ERRORHANDLER;
} else {
PRINT_D(GENERIC_DBG, "set HOST_IF_WAITING_CONN_RESP\n");
- hif_drv->enuHostIFstate = HOST_IF_WAITING_CONN_RESP;
+ hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
}
ERRORHANDLER:
if (result) {
tstrConnectInfo strConnectInfo;
- del_timer(&hif_drv->hConnectTimer);
+ del_timer(&hif_drv->connect_timer);
- PRINT_D(HOSTINF_DBG, "could not start connecting to the required network\n");
+ PRINT_D(HOSTINF_DBG, "could not start wilc_connecting to the required network\n");
memset(&strConnectInfo, 0, sizeof(tstrConnectInfo));
@@ -1244,7 +1237,7 @@ ERRORHANDLER:
MAC_DISCONNECTED,
NULL,
pstrHostIFconnectAttr->arg);
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
+ hif_drv->hif_state = HOST_IF_IDLE;
kfree(strConnectInfo.pu8ReqIEs);
strConnectInfo.pu8ReqIEs = NULL;
@@ -1267,7 +1260,7 @@ ERRORHANDLER:
return result;
}
-static s32 Handle_FlushConnect(struct host_if_drv *hif_drv)
+static s32 Handle_FlushConnect(struct wilc_vif *vif)
{
s32 result = 0;
struct wid strWIDList[5];
@@ -1303,8 +1296,9 @@ static s32 Handle_FlushConnect(struct host_if_drv *hif_drv)
u32WidsCount++;
- result = send_config_pkt(SET_CFG, strWIDList, u32WidsCount,
- get_id_from_handler(join_req_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, strWIDList,
+ u32WidsCount,
+ wilc_get_vif_idx(join_req_vif));
if (result) {
PRINT_ER("failed to send config packet\n");
result = -EINVAL;
@@ -1313,43 +1307,44 @@ static s32 Handle_FlushConnect(struct host_if_drv *hif_drv)
return result;
}
-static s32 Handle_ConnectTimeout(struct host_if_drv *hif_drv)
+static s32 Handle_ConnectTimeout(struct wilc_vif *vif)
{
s32 result = 0;
tstrConnectInfo strConnectInfo;
struct wid wid;
u16 u16DummyReasonCode = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("Driver handler is NULL\n");
return result;
}
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
+ hif_drv->hif_state = HOST_IF_IDLE;
scan_while_connected = false;
memset(&strConnectInfo, 0, sizeof(tstrConnectInfo));
- if (hif_drv->usr_conn_req.pfUserConnectResult) {
+ if (hif_drv->usr_conn_req.conn_result) {
if (hif_drv->usr_conn_req.pu8bssid) {
memcpy(strConnectInfo.au8bssid,
hif_drv->usr_conn_req.pu8bssid, 6);
}
- if (hif_drv->usr_conn_req.pu8ConnReqIEs) {
- strConnectInfo.ReqIEsLen = hif_drv->usr_conn_req.ConnReqIEsLen;
- strConnectInfo.pu8ReqIEs = kmalloc(hif_drv->usr_conn_req.ConnReqIEsLen, GFP_KERNEL);
+ if (hif_drv->usr_conn_req.ies) {
+ strConnectInfo.ReqIEsLen = hif_drv->usr_conn_req.ies_len;
+ strConnectInfo.pu8ReqIEs = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL);
memcpy(strConnectInfo.pu8ReqIEs,
- hif_drv->usr_conn_req.pu8ConnReqIEs,
- hif_drv->usr_conn_req.ConnReqIEsLen);
+ hif_drv->usr_conn_req.ies,
+ hif_drv->usr_conn_req.ies_len);
}
- hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_CONN_RESP,
- &strConnectInfo,
- MAC_DISCONNECTED,
- NULL,
- hif_drv->usr_conn_req.u32UserConnectPvoid);
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ &strConnectInfo,
+ MAC_DISCONNECTED,
+ NULL,
+ hif_drv->usr_conn_req.arg);
kfree(strConnectInfo.pu8ReqIEs);
strConnectInfo.pu8ReqIEs = NULL;
@@ -1364,25 +1359,28 @@ static s32 Handle_ConnectTimeout(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, "Sending disconnect request\n");
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send dissconect config packet\n");
- hif_drv->usr_conn_req.ssidLen = 0;
+ hif_drv->usr_conn_req.ssid_len = 0;
kfree(hif_drv->usr_conn_req.pu8ssid);
+ hif_drv->usr_conn_req.pu8ssid = NULL;
kfree(hif_drv->usr_conn_req.pu8bssid);
- hif_drv->usr_conn_req.ConnReqIEsLen = 0;
- kfree(hif_drv->usr_conn_req.pu8ConnReqIEs);
+ hif_drv->usr_conn_req.pu8bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
- eth_zero_addr(u8ConnectedSSID);
+ eth_zero_addr(wilc_connected_ssid);
- if (join_req && join_req_drv == hif_drv) {
+ if (join_req && join_req_vif == vif) {
kfree(join_req);
join_req = NULL;
}
- if (info_element && join_req_drv == hif_drv) {
+ if (info_element && join_req_vif == vif) {
kfree(info_element);
info_element = NULL;
}
@@ -1390,7 +1388,7 @@ static s32 Handle_ConnectTimeout(struct host_if_drv *hif_drv)
return result;
}
-static s32 Handle_RcvdNtwrkInfo(struct host_if_drv *hif_drv,
+static s32 Handle_RcvdNtwrkInfo(struct wilc_vif *vif,
struct rcvd_net_info *pstrRcvdNetworkInfo)
{
u32 i;
@@ -1398,30 +1396,31 @@ static s32 Handle_RcvdNtwrkInfo(struct host_if_drv *hif_drv,
s32 result = 0;
tstrNetworkInfo *pstrNetworkInfo = NULL;
void *pJoinParams = NULL;
+ struct host_if_drv *hif_drv = vif->hif_drv;
bNewNtwrkFound = true;
PRINT_INFO(HOSTINF_DBG, "Handling received network info\n");
- if (hif_drv->usr_scan_req.pfUserScanResult) {
+ if (hif_drv->usr_scan_req.scan_result) {
PRINT_D(HOSTINF_DBG, "State: Scanning, parsing network information received\n");
- parse_network_info(pstrRcvdNetworkInfo->buffer, &pstrNetworkInfo);
+ wilc_parse_network_info(pstrRcvdNetworkInfo->buffer, &pstrNetworkInfo);
if ((!pstrNetworkInfo) ||
- (!hif_drv->usr_scan_req.pfUserScanResult)) {
+ (!hif_drv->usr_scan_req.scan_result)) {
PRINT_ER("driver is null\n");
result = -EINVAL;
goto done;
}
- for (i = 0; i < hif_drv->usr_scan_req.u32RcvdChCount; i++) {
- if ((hif_drv->usr_scan_req.astrFoundNetworkInfo[i].au8bssid) &&
+ for (i = 0; i < hif_drv->usr_scan_req.rcvd_ch_cnt; i++) {
+ if ((hif_drv->usr_scan_req.net_info[i].au8bssid) &&
(pstrNetworkInfo->au8bssid)) {
- if (memcmp(hif_drv->usr_scan_req.astrFoundNetworkInfo[i].au8bssid,
+ if (memcmp(hif_drv->usr_scan_req.net_info[i].au8bssid,
pstrNetworkInfo->au8bssid, 6) == 0) {
- if (pstrNetworkInfo->s8rssi <= hif_drv->usr_scan_req.astrFoundNetworkInfo[i].s8rssi) {
+ if (pstrNetworkInfo->s8rssi <= hif_drv->usr_scan_req.net_info[i].s8rssi) {
PRINT_D(HOSTINF_DBG, "Network previously discovered\n");
goto done;
} else {
- hif_drv->usr_scan_req.astrFoundNetworkInfo[i].s8rssi = pstrNetworkInfo->s8rssi;
+ hif_drv->usr_scan_req.net_info[i].s8rssi = pstrNetworkInfo->s8rssi;
bNewNtwrkFound = false;
break;
}
@@ -1432,30 +1431,30 @@ static s32 Handle_RcvdNtwrkInfo(struct host_if_drv *hif_drv,
if (bNewNtwrkFound) {
PRINT_D(HOSTINF_DBG, "New network found\n");
- if (hif_drv->usr_scan_req.u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) {
- hif_drv->usr_scan_req.astrFoundNetworkInfo[hif_drv->usr_scan_req.u32RcvdChCount].s8rssi = pstrNetworkInfo->s8rssi;
+ if (hif_drv->usr_scan_req.rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) {
+ hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].s8rssi = pstrNetworkInfo->s8rssi;
- if (hif_drv->usr_scan_req.astrFoundNetworkInfo[hif_drv->usr_scan_req.u32RcvdChCount].au8bssid &&
+ if (hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].au8bssid &&
pstrNetworkInfo->au8bssid) {
- memcpy(hif_drv->usr_scan_req.astrFoundNetworkInfo[hif_drv->usr_scan_req.u32RcvdChCount].au8bssid,
+ memcpy(hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].au8bssid,
pstrNetworkInfo->au8bssid, 6);
- hif_drv->usr_scan_req.u32RcvdChCount++;
+ hif_drv->usr_scan_req.rcvd_ch_cnt++;
pstrNetworkInfo->bNewNetwork = true;
pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo);
- hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
- hif_drv->usr_scan_req.u32UserScanPvoid,
- pJoinParams);
+ hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
+ hif_drv->usr_scan_req.arg,
+ pJoinParams);
}
} else {
PRINT_WRN(HOSTINF_DBG, "Discovered networks exceeded max. limit\n");
}
} else {
pstrNetworkInfo->bNewNetwork = false;
- hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
- hif_drv->usr_scan_req.u32UserScanPvoid, NULL);
+ hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
+ hif_drv->usr_scan_req.arg, NULL);
}
}
@@ -1464,14 +1463,19 @@ done:
pstrRcvdNetworkInfo->buffer = NULL;
if (pstrNetworkInfo) {
- DeallocateNetworkInfo(pstrNetworkInfo);
+ wilc_dealloc_network_info(pstrNetworkInfo);
pstrNetworkInfo = NULL;
}
return result;
}
-static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
+static s32 host_int_get_assoc_res_info(struct wilc_vif *vif,
+ u8 *pu8AssocRespInfo,
+ u32 u32MaxAssocRespInfoLen,
+ u32 *pu32RcvdAssocRespInfoLen);
+
+static s32 Handle_RcvdGnrlAsyncInfo(struct wilc_vif *vif,
struct rcvd_async_info *pstrRcvdGnrlAsyncInfo)
{
s32 result = 0;
@@ -1486,19 +1490,20 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
tstrConnectInfo strConnectInfo;
tstrDisconnectNotifInfo strDisconnectNotifInfo;
s32 s32Err = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("Driver handler is NULL\n");
return -ENODEV;
}
- PRINT_D(GENERIC_DBG, "Current State = %d,Received state = %d\n", hif_drv->enuHostIFstate,
- pstrRcvdGnrlAsyncInfo->buffer[7]);
+ PRINT_D(GENERIC_DBG, "Current State = %d,Received state = %d\n",
+ hif_drv->hif_state, pstrRcvdGnrlAsyncInfo->buffer[7]);
- if ((hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) ||
- (hif_drv->enuHostIFstate == HOST_IF_CONNECTED) ||
- hif_drv->usr_scan_req.pfUserScanResult) {
+ if ((hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) ||
+ (hif_drv->hif_state == HOST_IF_CONNECTED) ||
+ hif_drv->usr_scan_req.scan_result) {
if (!pstrRcvdGnrlAsyncInfo->buffer ||
- !hif_drv->usr_conn_req.pfUserConnectResult) {
+ !hif_drv->usr_conn_req.conn_result) {
PRINT_ER("driver is null\n");
return -EINVAL;
}
@@ -1518,8 +1523,8 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
u8MacStatusReasonCode = pstrRcvdGnrlAsyncInfo->buffer[8];
u8MacStatusAdditionalInfo = pstrRcvdGnrlAsyncInfo->buffer[9];
PRINT_INFO(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Info = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo);
- if (hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) {
- u32 u32RcvdAssocRespInfoLen;
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+ u32 u32RcvdAssocRespInfoLen = 0;
tstrConnectRespInfo *pstrConnectRespInfo = NULL;
PRINT_D(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Code = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo);
@@ -1529,7 +1534,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
if (u8MacStatus == MAC_CONNECTED) {
memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE);
- host_int_get_assoc_res_info(hif_drv,
+ host_int_get_assoc_res_info(vif,
rcv_assoc_resp,
MAX_ASSOC_RESP_FRAME_SIZE,
&u32RcvdAssocRespInfoLen);
@@ -1538,10 +1543,10 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
if (u32RcvdAssocRespInfoLen != 0) {
PRINT_D(HOSTINF_DBG, "Parsing association response\n");
- s32Err = ParseAssocRespInfo(rcv_assoc_resp, u32RcvdAssocRespInfoLen,
+ s32Err = wilc_parse_assoc_resp_info(rcv_assoc_resp, u32RcvdAssocRespInfoLen,
&pstrConnectRespInfo);
if (s32Err) {
- PRINT_ER("ParseAssocRespInfo() returned error %d\n", s32Err);
+ PRINT_ER("wilc_parse_assoc_resp_info() returned error %d\n", s32Err);
} else {
strConnectInfo.u16ConnectStatus = pstrConnectRespInfo->u16ConnectStatus;
@@ -1556,7 +1561,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
}
if (pstrConnectRespInfo) {
- DeallocateAssocRespInfo(pstrConnectRespInfo);
+ wilc_dealloc_assoc_resp_info(pstrConnectRespInfo);
pstrConnectRespInfo = NULL;
}
}
@@ -1566,11 +1571,10 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
if ((u8MacStatus == MAC_CONNECTED) &&
(strConnectInfo.u16ConnectStatus != SUCCESSFUL_STATUSCODE)) {
PRINT_ER("Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n");
- eth_zero_addr(u8ConnectedSSID);
-
+ eth_zero_addr(wilc_connected_ssid);
} else if (u8MacStatus == MAC_DISCONNECTED) {
PRINT_ER("Received MAC status is MAC_DISCONNECTED\n");
- eth_zero_addr(u8ConnectedSSID);
+ eth_zero_addr(wilc_connected_ssid);
}
if (hif_drv->usr_conn_req.pu8bssid) {
@@ -1579,40 +1583,40 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
if ((u8MacStatus == MAC_CONNECTED) &&
(strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE)) {
- memcpy(hif_drv->au8AssociatedBSSID,
+ memcpy(hif_drv->assoc_bssid,
hif_drv->usr_conn_req.pu8bssid, ETH_ALEN);
}
}
- if (hif_drv->usr_conn_req.pu8ConnReqIEs) {
- strConnectInfo.ReqIEsLen = hif_drv->usr_conn_req.ConnReqIEsLen;
- strConnectInfo.pu8ReqIEs = kmalloc(hif_drv->usr_conn_req.ConnReqIEsLen, GFP_KERNEL);
+ if (hif_drv->usr_conn_req.ies) {
+ strConnectInfo.ReqIEsLen = hif_drv->usr_conn_req.ies_len;
+ strConnectInfo.pu8ReqIEs = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL);
memcpy(strConnectInfo.pu8ReqIEs,
- hif_drv->usr_conn_req.pu8ConnReqIEs,
- hif_drv->usr_conn_req.ConnReqIEsLen);
+ hif_drv->usr_conn_req.ies,
+ hif_drv->usr_conn_req.ies_len);
}
- del_timer(&hif_drv->hConnectTimer);
- hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_CONN_RESP,
- &strConnectInfo,
- u8MacStatus,
- NULL,
- hif_drv->usr_conn_req.u32UserConnectPvoid);
+ del_timer(&hif_drv->connect_timer);
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ &strConnectInfo,
+ u8MacStatus,
+ NULL,
+ hif_drv->usr_conn_req.arg);
if ((u8MacStatus == MAC_CONNECTED) &&
(strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE)) {
- host_int_set_power_mgmt(hif_drv, 0, 0);
+ wilc_set_power_mgmt(vif, 0, 0);
PRINT_D(HOSTINF_DBG, "MAC status : CONNECTED and Connect Status : Successful\n");
- hif_drv->enuHostIFstate = HOST_IF_CONNECTED;
+ hif_drv->hif_state = HOST_IF_CONNECTED;
PRINT_D(GENERIC_DBG, "Obtaining an IP, Disable Scan\n");
- g_obtainingIP = true;
- mod_timer(&hDuringIpTimer,
+ wilc_optaining_ip = true;
+ mod_timer(&wilc_during_ip_timer,
jiffies + msecs_to_jiffies(10000));
} else {
PRINT_D(HOSTINF_DBG, "MAC status : %d and Connect Status : %d\n", u8MacStatus, strConnectInfo.u16ConnectStatus);
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
+ hif_drv->hif_state = HOST_IF_IDLE;
scan_while_connected = false;
}
@@ -1621,69 +1625,75 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
kfree(strConnectInfo.pu8ReqIEs);
strConnectInfo.pu8ReqIEs = NULL;
- hif_drv->usr_conn_req.ssidLen = 0;
+ hif_drv->usr_conn_req.ssid_len = 0;
kfree(hif_drv->usr_conn_req.pu8ssid);
+ hif_drv->usr_conn_req.pu8ssid = NULL;
kfree(hif_drv->usr_conn_req.pu8bssid);
- hif_drv->usr_conn_req.ConnReqIEsLen = 0;
- kfree(hif_drv->usr_conn_req.pu8ConnReqIEs);
+ hif_drv->usr_conn_req.pu8bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
} else if ((u8MacStatus == MAC_DISCONNECTED) &&
- (hif_drv->enuHostIFstate == HOST_IF_CONNECTED)) {
+ (hif_drv->hif_state == HOST_IF_CONNECTED)) {
PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW\n");
memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo));
- if (hif_drv->usr_scan_req.pfUserScanResult) {
+ if (hif_drv->usr_scan_req.scan_result) {
PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running OBSS Scan >>\n\n");
- del_timer(&hif_drv->hScanTimer);
- Handle_ScanDone((void *)hif_drv, SCAN_EVENT_ABORTED);
+ del_timer(&hif_drv->scan_timer);
+ Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
}
strDisconnectNotifInfo.u16reason = 0;
strDisconnectNotifInfo.ie = NULL;
strDisconnectNotifInfo.ie_len = 0;
- if (hif_drv->usr_conn_req.pfUserConnectResult) {
- g_obtainingIP = false;
- host_int_set_power_mgmt(hif_drv, 0, 0);
+ if (hif_drv->usr_conn_req.conn_result) {
+ wilc_optaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
- hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF,
- NULL,
- 0,
- &strDisconnectNotifInfo,
- hif_drv->usr_conn_req.u32UserConnectPvoid);
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
+ NULL,
+ 0,
+ &strDisconnectNotifInfo,
+ hif_drv->usr_conn_req.arg);
} else {
PRINT_ER("Connect result callback function is NULL\n");
}
- eth_zero_addr(hif_drv->au8AssociatedBSSID);
+ eth_zero_addr(hif_drv->assoc_bssid);
- hif_drv->usr_conn_req.ssidLen = 0;
+ hif_drv->usr_conn_req.ssid_len = 0;
kfree(hif_drv->usr_conn_req.pu8ssid);
+ hif_drv->usr_conn_req.pu8ssid = NULL;
kfree(hif_drv->usr_conn_req.pu8bssid);
- hif_drv->usr_conn_req.ConnReqIEsLen = 0;
- kfree(hif_drv->usr_conn_req.pu8ConnReqIEs);
+ hif_drv->usr_conn_req.pu8bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
- if (join_req && join_req_drv == hif_drv) {
+ if (join_req && join_req_vif == vif) {
kfree(join_req);
join_req = NULL;
}
- if (info_element && join_req_drv == hif_drv) {
+ if (info_element && join_req_vif == vif) {
kfree(info_element);
info_element = NULL;
}
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
+ hif_drv->hif_state = HOST_IF_IDLE;
scan_while_connected = false;
} else if ((u8MacStatus == MAC_DISCONNECTED) &&
- (hif_drv->usr_scan_req.pfUserScanResult)) {
+ (hif_drv->usr_scan_req.scan_result)) {
PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW while scanning\n");
PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running Scan >>\n\n");
- del_timer(&hif_drv->hScanTimer);
- if (hif_drv->usr_scan_req.pfUserScanResult)
- Handle_ScanDone(hif_drv, SCAN_EVENT_ABORTED);
+ del_timer(&hif_drv->scan_timer);
+ if (hif_drv->usr_scan_req.scan_result)
+ Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
}
}
@@ -1693,7 +1703,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv,
return result;
}
-static int Handle_Key(struct host_if_drv *hif_drv,
+static int Handle_Key(struct wilc_vif *vif,
struct key_attr *pstrHostIFkeyAttr)
{
s32 result = 0;
@@ -1703,6 +1713,7 @@ static int Handle_Key(struct host_if_drv *hif_drv,
u8 *pu8keybuf;
s8 s8idxarray[1];
s8 ret = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
switch (pstrHostIFkeyAttr->type) {
case WEP:
@@ -1742,12 +1753,11 @@ static int Handle_Key(struct host_if_drv *hif_drv,
strWIDList[3].size = pstrHostIFkeyAttr->attr.wep.key_len;
strWIDList[3].val = (s8 *)pu8keybuf;
- result = send_config_pkt(SET_CFG, strWIDList, 4,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ strWIDList, 4,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
- }
-
- if (pstrHostIFkeyAttr->action & ADDKEY) {
+ } else if (pstrHostIFkeyAttr->action & ADDKEY) {
PRINT_D(HOSTINF_DBG, "Handling WEP key\n");
pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2, GFP_KERNEL);
if (!pu8keybuf) {
@@ -1765,8 +1775,9 @@ static int Handle_Key(struct host_if_drv *hif_drv,
wid.val = (s8 *)pu8keybuf;
wid.size = pstrHostIFkeyAttr->attr.wep.key_len + 2;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
} else if (pstrHostIFkeyAttr->action & REMOVEKEY) {
PRINT_D(HOSTINF_DBG, "Removing key\n");
@@ -1777,8 +1788,9 @@ static int Handle_Key(struct host_if_drv *hif_drv,
wid.val = s8idxarray;
wid.size = 1;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
} else {
wid.id = (u16)WID_KEY_ID;
wid.type = WID_CHAR;
@@ -1787,13 +1799,14 @@ static int Handle_Key(struct host_if_drv *hif_drv,
PRINT_D(HOSTINF_DBG, "Setting default key index\n");
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
}
- up(&hif_drv->hSemTestKeyBlock);
+ up(&hif_drv->sem_test_key_block);
break;
- case WPARxGtk:
+ case WPA_RX_GTK:
if (pstrHostIFkeyAttr->action & ADDKEY_AP) {
pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
if (!pu8keybuf) {
@@ -1820,14 +1833,13 @@ static int Handle_Key(struct host_if_drv *hif_drv,
strWIDList[1].val = (s8 *)pu8keybuf;
strWIDList[1].size = RX_MIC_KEY_MSG_LEN;
- result = send_config_pkt(SET_CFG, strWIDList, 2,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ strWIDList, 2,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
- up(&hif_drv->hSemTestKeyBlock);
- }
-
- if (pstrHostIFkeyAttr->action & ADDKEY) {
+ up(&hif_drv->sem_test_key_block);
+ } else if (pstrHostIFkeyAttr->action & ADDKEY) {
PRINT_D(HOSTINF_DBG, "Handling group key(Rx) function\n");
pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
@@ -1837,10 +1849,10 @@ static int Handle_Key(struct host_if_drv *hif_drv,
goto _WPARxGtk_end_case_;
}
- if (hif_drv->enuHostIFstate == HOST_IF_CONNECTED)
- memcpy(pu8keybuf, hif_drv->au8AssociatedBSSID, ETH_ALEN);
+ if (hif_drv->hif_state == HOST_IF_CONNECTED)
+ memcpy(pu8keybuf, hif_drv->assoc_bssid, ETH_ALEN);
else
- PRINT_ER("Couldn't handle WPARxGtk while enuHostIFstate is not HOST_IF_CONNECTED\n");
+ PRINT_ER("Couldn't handle WPARxGtk while state is not HOST_IF_CONNECTED\n");
memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8);
memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1);
@@ -1853,11 +1865,12 @@ static int Handle_Key(struct host_if_drv *hif_drv,
wid.val = (s8 *)pu8keybuf;
wid.size = RX_MIC_KEY_MSG_LEN;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
- up(&hif_drv->hSemTestKeyBlock);
+ up(&hif_drv->sem_test_key_block);
}
_WPARxGtk_end_case_:
kfree(pstrHostIFkeyAttr->attr.wpa.key);
@@ -1867,7 +1880,7 @@ _WPARxGtk_end_case_:
break;
- case WPAPtk:
+ case WPA_PTK:
if (pstrHostIFkeyAttr->action & ADDKEY_AP) {
pu8keybuf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL);
if (!pu8keybuf) {
@@ -1892,12 +1905,12 @@ _WPARxGtk_end_case_:
strWIDList[1].val = (s8 *)pu8keybuf;
strWIDList[1].size = PTK_KEY_MSG_LEN + 1;
- result = send_config_pkt(SET_CFG, strWIDList, 2,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ strWIDList, 2,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
- up(&hif_drv->hSemTestKeyBlock);
- }
- if (pstrHostIFkeyAttr->action & ADDKEY) {
+ up(&hif_drv->sem_test_key_block);
+ } else if (pstrHostIFkeyAttr->action & ADDKEY) {
pu8keybuf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL);
if (!pu8keybuf) {
PRINT_ER("No buffer to send PTK Key\n");
@@ -1915,10 +1928,11 @@ _WPARxGtk_end_case_:
wid.val = (s8 *)pu8keybuf;
wid.size = PTK_KEY_MSG_LEN;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
- up(&hif_drv->hSemTestKeyBlock);
+ up(&hif_drv->sem_test_key_block);
}
_WPAPtk_end_case_:
@@ -1950,8 +1964,8 @@ _WPAPtk_end_case_:
wid.val = (s8 *)pu8keybuf;
wid.size = (pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
kfree(pu8keybuf);
break;
@@ -1963,9 +1977,10 @@ _WPAPtk_end_case_:
return result;
}
-static void Handle_Disconnect(struct host_if_drv *hif_drv)
+static void Handle_Disconnect(struct wilc_vif *vif)
{
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
s32 result = 0;
u16 u16DummyReasonCode = 0;
@@ -1977,13 +1992,13 @@ static void Handle_Disconnect(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, "Sending disconnect request\n");
- g_obtainingIP = false;
- host_int_set_power_mgmt(hif_drv, 0, 0);
+ wilc_optaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
- eth_zero_addr(u8ConnectedSSID);
+ eth_zero_addr(wilc_connected_ssid);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to send dissconect config packet\n");
@@ -1996,66 +2011,75 @@ static void Handle_Disconnect(struct host_if_drv *hif_drv)
strDisconnectNotifInfo.ie = NULL;
strDisconnectNotifInfo.ie_len = 0;
- if (hif_drv->usr_scan_req.pfUserScanResult) {
- del_timer(&hif_drv->hScanTimer);
- hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_ABORTED, NULL,
- hif_drv->usr_scan_req.u32UserScanPvoid, NULL);
-
- hif_drv->usr_scan_req.pfUserScanResult = NULL;
+ if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED,
+ NULL,
+ hif_drv->usr_scan_req.arg,
+ NULL);
+ hif_drv->usr_scan_req.scan_result = NULL;
}
- if (hif_drv->usr_conn_req.pfUserConnectResult) {
- if (hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) {
+ if (hif_drv->usr_conn_req.conn_result) {
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
PRINT_D(HOSTINF_DBG, "Upper layer requested termination of connection\n");
- del_timer(&hif_drv->hConnectTimer);
+ del_timer(&hif_drv->connect_timer);
}
- hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL,
- 0, &strDisconnectNotifInfo, hif_drv->usr_conn_req.u32UserConnectPvoid);
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
+ NULL,
+ 0,
+ &strDisconnectNotifInfo,
+ hif_drv->usr_conn_req.arg);
} else {
- PRINT_ER("usr_conn_req.pfUserConnectResult = NULL\n");
+ PRINT_ER("usr_conn_req.conn_result = NULL\n");
}
scan_while_connected = false;
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
+ hif_drv->hif_state = HOST_IF_IDLE;
- eth_zero_addr(hif_drv->au8AssociatedBSSID);
+ eth_zero_addr(hif_drv->assoc_bssid);
- hif_drv->usr_conn_req.ssidLen = 0;
+ hif_drv->usr_conn_req.ssid_len = 0;
kfree(hif_drv->usr_conn_req.pu8ssid);
+ hif_drv->usr_conn_req.pu8ssid = NULL;
kfree(hif_drv->usr_conn_req.pu8bssid);
- hif_drv->usr_conn_req.ConnReqIEsLen = 0;
- kfree(hif_drv->usr_conn_req.pu8ConnReqIEs);
+ hif_drv->usr_conn_req.pu8bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
- if (join_req && join_req_drv == hif_drv) {
+ if (join_req && join_req_vif == vif) {
kfree(join_req);
join_req = NULL;
}
- if (info_element && join_req_drv == hif_drv) {
+ if (info_element && join_req_vif == vif) {
kfree(info_element);
info_element = NULL;
}
}
- up(&hif_drv->hSemTestDisconnectBlock);
+ up(&hif_drv->sem_test_disconn_block);
}
-void resolve_disconnect_aberration(struct host_if_drv *hif_drv)
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
{
- if (!hif_drv)
+ if (!vif->hif_drv)
return;
- if ((hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) || (hif_drv->enuHostIFstate == HOST_IF_CONNECTING)) {
+ if ((vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) ||
+ (vif->hif_drv->hif_state == HOST_IF_CONNECTING)) {
PRINT_D(HOSTINF_DBG, "\n\n<< correcting Supplicant state machine >>\n\n");
- host_int_disconnect(hif_drv, 1);
+ wilc_disconnect(vif, 1);
}
}
-static s32 Handle_GetChnl(struct host_if_drv *hif_drv)
+static s32 Handle_GetChnl(struct wilc_vif *vif)
{
s32 result = 0;
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
wid.id = (u16)WID_CURRENT_CHANNEL;
wid.type = WID_CHAR;
@@ -2064,20 +2088,20 @@ static s32 Handle_GetChnl(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, "Getting channel value\n");
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to get channel number\n");
result = -EFAULT;
}
- up(&hif_drv->hSemGetCHNL);
+ up(&hif_drv->sem_get_chnl);
return result;
}
-static void Handle_GetRssi(struct host_if_drv *hif_drv)
+static void Handle_GetRssi(struct wilc_vif *vif)
{
s32 result = 0;
struct wid wid;
@@ -2089,20 +2113,21 @@ static void Handle_GetRssi(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, "Getting RSSI value\n");
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to get RSSI value\n");
result = -EFAULT;
}
- up(&hif_drv->hSemGetRSSI);
+ up(&vif->hif_drv->sem_get_rssi);
}
-static void Handle_GetLinkspeed(struct host_if_drv *hif_drv)
+static void Handle_GetLinkspeed(struct wilc_vif *vif)
{
s32 result = 0;
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
link_speed = 0;
@@ -2113,17 +2138,18 @@ static void Handle_GetLinkspeed(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, "Getting LINKSPEED value\n");
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to get LINKSPEED value\n");
result = -EFAULT;
}
- up(&hif_drv->hSemGetLINKSPEED);
+ up(&hif_drv->sem_get_link_speed);
}
-s32 Handle_GetStatistics(struct host_if_drv *hif_drv, struct rf_info *pstrStatistics)
+static s32 Handle_GetStatistics(struct wilc_vif *vif,
+ struct rf_info *pstrStatistics)
{
struct wid strWIDList[5];
u32 u32WidsCount = 0, result = 0;
@@ -2131,35 +2157,36 @@ s32 Handle_GetStatistics(struct host_if_drv *hif_drv, struct rf_info *pstrStatis
strWIDList[u32WidsCount].id = WID_LINKSPEED;
strWIDList[u32WidsCount].type = WID_CHAR;
strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u8LinkSpeed;
+ strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->link_speed;
u32WidsCount++;
strWIDList[u32WidsCount].id = WID_RSSI;
strWIDList[u32WidsCount].type = WID_CHAR;
strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->s8RSSI;
+ strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rssi;
u32WidsCount++;
strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT;
strWIDList[u32WidsCount].type = WID_INT;
strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u32TxCount;
+ strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_cnt;
u32WidsCount++;
strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT;
strWIDList[u32WidsCount].type = WID_INT;
strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u32RxCount;
+ strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rx_cnt;
u32WidsCount++;
strWIDList[u32WidsCount].id = WID_FAILED_COUNT;
strWIDList[u32WidsCount].type = WID_INT;
strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u32TxFailureCount;
+ strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_fail_cnt;
u32WidsCount++;
- result = send_config_pkt(GET_CFG, strWIDList, u32WidsCount,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, strWIDList,
+ u32WidsCount,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send scan paramters config packet\n");
@@ -2168,12 +2195,13 @@ s32 Handle_GetStatistics(struct host_if_drv *hif_drv, struct rf_info *pstrStatis
return 0;
}
-static s32 Handle_Get_InActiveTime(struct host_if_drv *hif_drv,
+static s32 Handle_Get_InActiveTime(struct wilc_vif *vif,
struct sta_inactive_t *strHostIfStaInactiveT)
{
s32 result = 0;
u8 *stamac;
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
wid.id = (u16)WID_SET_STA_MAC_INACTIVE_TIME;
wid.type = WID_STR;
@@ -2185,8 +2213,8 @@ static s32 Handle_Get_InActiveTime(struct host_if_drv *hif_drv,
PRINT_D(CFG80211_DBG, "SETING STA inactive time\n");
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to SET incative time\n");
@@ -2198,8 +2226,8 @@ static s32 Handle_Get_InActiveTime(struct host_if_drv *hif_drv,
wid.val = (s8 *)&inactive_time;
wid.size = sizeof(u32);
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to get incative time\n");
@@ -2208,12 +2236,12 @@ static s32 Handle_Get_InActiveTime(struct host_if_drv *hif_drv,
PRINT_D(CFG80211_DBG, "Getting inactive time : %d\n", inactive_time);
- up(&hif_drv->hSemInactiveTime);
+ up(&hif_drv->sem_inactive_time);
return result;
}
-static void Handle_AddBeacon(struct host_if_drv *hif_drv,
+static void Handle_AddBeacon(struct wilc_vif *vif,
struct beacon_attr *pstrSetBeaconParam)
{
s32 result = 0;
@@ -2253,12 +2281,12 @@ static void Handle_AddBeacon(struct host_if_drv *hif_drv,
*pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 16) & 0xFF);
*pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 24) & 0xFF);
- if (pstrSetBeaconParam->tail > 0)
+ if (pstrSetBeaconParam->tail)
memcpy(pu8CurrByte, pstrSetBeaconParam->tail, pstrSetBeaconParam->tail_len);
pu8CurrByte += pstrSetBeaconParam->tail_len;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send add beacon config packet\n");
@@ -2268,7 +2296,7 @@ ERRORHANDLER:
kfree(pstrSetBeaconParam->tail);
}
-static void Handle_DelBeacon(struct host_if_drv *hif_drv)
+static void Handle_DelBeacon(struct wilc_vif *vif)
{
s32 result = 0;
struct wid wid;
@@ -2286,8 +2314,8 @@ static void Handle_DelBeacon(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, "Deleting BEACON\n");
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send delete beacon config packet\n");
}
@@ -2300,45 +2328,47 @@ static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer,
pu8CurrByte = pu8Buffer;
PRINT_D(HOSTINF_DBG, "Packing STA params\n");
- memcpy(pu8CurrByte, pstrStationParam->au8BSSID, ETH_ALEN);
+ memcpy(pu8CurrByte, pstrStationParam->bssid, ETH_ALEN);
pu8CurrByte += ETH_ALEN;
- *pu8CurrByte++ = pstrStationParam->u16AssocID & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u16AssocID >> 8) & 0xFF;
+ *pu8CurrByte++ = pstrStationParam->aid & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->aid >> 8) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->u8NumRates;
- if (pstrStationParam->u8NumRates > 0)
- memcpy(pu8CurrByte, pstrStationParam->pu8Rates, pstrStationParam->u8NumRates);
- pu8CurrByte += pstrStationParam->u8NumRates;
+ *pu8CurrByte++ = pstrStationParam->rates_len;
+ if (pstrStationParam->rates_len > 0)
+ memcpy(pu8CurrByte, pstrStationParam->rates,
+ pstrStationParam->rates_len);
+ pu8CurrByte += pstrStationParam->rates_len;
- *pu8CurrByte++ = pstrStationParam->bIsHTSupported;
- *pu8CurrByte++ = pstrStationParam->u16HTCapInfo & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u16HTCapInfo >> 8) & 0xFF;
+ *pu8CurrByte++ = pstrStationParam->ht_supported;
+ *pu8CurrByte++ = pstrStationParam->ht_capa_info & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->ht_capa_info >> 8) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->u8AmpduParams;
- memcpy(pu8CurrByte, pstrStationParam->au8SuppMCsSet, WILC_SUPP_MCS_SET_SIZE);
+ *pu8CurrByte++ = pstrStationParam->ht_ampdu_params;
+ memcpy(pu8CurrByte, pstrStationParam->ht_supp_mcs_set,
+ WILC_SUPP_MCS_SET_SIZE);
pu8CurrByte += WILC_SUPP_MCS_SET_SIZE;
- *pu8CurrByte++ = pstrStationParam->u16HTExtParams & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u16HTExtParams >> 8) & 0xFF;
+ *pu8CurrByte++ = pstrStationParam->ht_ext_params & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->ht_ext_params >> 8) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->u32TxBeamformingCap & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 8) & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 16) & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 24) & 0xFF;
+ *pu8CurrByte++ = pstrStationParam->ht_tx_bf_cap & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->ht_tx_bf_cap >> 8) & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->ht_tx_bf_cap >> 16) & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->ht_tx_bf_cap >> 24) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->u8ASELCap;
+ *pu8CurrByte++ = pstrStationParam->ht_ante_sel;
- *pu8CurrByte++ = pstrStationParam->u16FlagsMask & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u16FlagsMask >> 8) & 0xFF;
+ *pu8CurrByte++ = pstrStationParam->flags_mask & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->flags_mask >> 8) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->u16FlagsSet & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->u16FlagsSet >> 8) & 0xFF;
+ *pu8CurrByte++ = pstrStationParam->flags_set & 0xFF;
+ *pu8CurrByte++ = (pstrStationParam->flags_set >> 8) & 0xFF;
return pu8CurrByte - pu8Buffer;
}
-static void Handle_AddStation(struct host_if_drv *hif_drv,
+static void Handle_AddStation(struct wilc_vif *vif,
struct add_sta_param *pstrStationParam)
{
s32 result = 0;
@@ -2348,7 +2378,7 @@ static void Handle_AddStation(struct host_if_drv *hif_drv,
PRINT_D(HOSTINF_DBG, "Handling add station\n");
wid.id = (u16)WID_ADD_STA;
wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates;
+ wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->rates_len;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
@@ -2357,17 +2387,17 @@ static void Handle_AddStation(struct host_if_drv *hif_drv,
pu8CurrByte = wid.val;
pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result != 0)
PRINT_ER("Failed to send add station config packet\n");
ERRORHANDLER:
- kfree(pstrStationParam->pu8Rates);
+ kfree(pstrStationParam->rates);
kfree(wid.val);
}
-static void Handle_DelAllSta(struct host_if_drv *hif_drv,
+static void Handle_DelAllSta(struct wilc_vif *vif,
struct del_all_sta *pstrDelAllStaParam)
{
s32 result = 0;
@@ -2399,8 +2429,8 @@ static void Handle_DelAllSta(struct host_if_drv *hif_drv,
pu8CurrByte += ETH_ALEN;
}
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send add station config packet\n");
@@ -2410,7 +2440,7 @@ ERRORHANDLER:
up(&hif_sema_wait_response);
}
-static void Handle_DelStation(struct host_if_drv *hif_drv,
+static void Handle_DelStation(struct wilc_vif *vif,
struct del_sta *pstrDelStaParam)
{
s32 result = 0;
@@ -2431,8 +2461,8 @@ static void Handle_DelStation(struct host_if_drv *hif_drv,
memcpy(pu8CurrByte, pstrDelStaParam->mac_addr, ETH_ALEN);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send add station config packet\n");
@@ -2440,7 +2470,7 @@ ERRORHANDLER:
kfree(wid.val);
}
-static void Handle_EditStation(struct host_if_drv *hif_drv,
+static void Handle_EditStation(struct wilc_vif *vif,
struct add_sta_param *pstrStationParam)
{
s32 result = 0;
@@ -2449,7 +2479,7 @@ static void Handle_EditStation(struct host_if_drv *hif_drv,
wid.id = (u16)WID_EDIT_STA;
wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates;
+ wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->rates_len;
PRINT_D(HOSTINF_DBG, "Handling edit station\n");
wid.val = kmalloc(wid.size, GFP_KERNEL);
@@ -2459,52 +2489,54 @@ static void Handle_EditStation(struct host_if_drv *hif_drv,
pu8CurrByte = wid.val;
pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam);
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send edit station config packet\n");
ERRORHANDLER:
- kfree(pstrStationParam->pu8Rates);
+ kfree(pstrStationParam->rates);
kfree(wid.val);
}
-static int Handle_RemainOnChan(struct host_if_drv *hif_drv,
+static int Handle_RemainOnChan(struct wilc_vif *vif,
struct remain_ch *pstrHostIfRemainOnChan)
{
s32 result = 0;
u8 u8remain_on_chan_flag;
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv->remain_on_ch_pending) {
- hif_drv->remain_on_ch.pVoid = pstrHostIfRemainOnChan->pVoid;
- hif_drv->remain_on_ch.pRemainOnChanExpired = pstrHostIfRemainOnChan->pRemainOnChanExpired;
- hif_drv->remain_on_ch.pRemainOnChanReady = pstrHostIfRemainOnChan->pRemainOnChanReady;
- hif_drv->remain_on_ch.u16Channel = pstrHostIfRemainOnChan->u16Channel;
- hif_drv->remain_on_ch.u32ListenSessionID = pstrHostIfRemainOnChan->u32ListenSessionID;
+ hif_drv->remain_on_ch.arg = pstrHostIfRemainOnChan->arg;
+ hif_drv->remain_on_ch.expired = pstrHostIfRemainOnChan->expired;
+ hif_drv->remain_on_ch.ready = pstrHostIfRemainOnChan->ready;
+ hif_drv->remain_on_ch.ch = pstrHostIfRemainOnChan->ch;
+ hif_drv->remain_on_ch.id = pstrHostIfRemainOnChan->id;
} else {
- pstrHostIfRemainOnChan->u16Channel = hif_drv->remain_on_ch.u16Channel;
+ pstrHostIfRemainOnChan->ch = hif_drv->remain_on_ch.ch;
}
- if (hif_drv->usr_scan_req.pfUserScanResult) {
+ if (hif_drv->usr_scan_req.scan_result) {
PRINT_INFO(GENERIC_DBG, "Required to remain on chan while scanning return\n");
hif_drv->remain_on_ch_pending = 1;
result = -EBUSY;
goto ERRORHANDLER;
}
- if (hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) {
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
PRINT_INFO(GENERIC_DBG, "Required to remain on chan while connecting return\n");
result = -EBUSY;
goto ERRORHANDLER;
}
- if (g_obtainingIP || connecting) {
+ if (wilc_optaining_ip || wilc_connecting) {
PRINT_D(GENERIC_DBG, "[handle_scan]: Don't do obss scan until IP adresss is obtained\n");
result = -EBUSY;
goto ERRORHANDLER;
}
- PRINT_D(HOSTINF_DBG, "Setting channel :%d\n", pstrHostIfRemainOnChan->u16Channel);
+ PRINT_D(HOSTINF_DBG, "Setting channel :%d\n",
+ pstrHostIfRemainOnChan->ch);
u8remain_on_chan_flag = true;
wid.id = (u16)WID_REMAIN_ON_CHAN;
@@ -2517,23 +2549,23 @@ static int Handle_RemainOnChan(struct host_if_drv *hif_drv,
}
wid.val[0] = u8remain_on_chan_flag;
- wid.val[1] = (s8)pstrHostIfRemainOnChan->u16Channel;
+ wid.val[1] = (s8)pstrHostIfRemainOnChan->ch;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result != 0)
PRINT_ER("Failed to set remain on channel\n");
ERRORHANDLER:
{
P2P_LISTEN_STATE = 1;
- hif_drv->hRemainOnChannel.data = (unsigned long)hif_drv;
- mod_timer(&hif_drv->hRemainOnChannel,
+ hif_drv->remain_on_ch_timer.data = (unsigned long)vif;
+ mod_timer(&hif_drv->remain_on_ch_timer,
jiffies +
msecs_to_jiffies(pstrHostIfRemainOnChan->u32duration));
- if (hif_drv->remain_on_ch.pRemainOnChanReady)
- hif_drv->remain_on_ch.pRemainOnChanReady(hif_drv->remain_on_ch.pVoid);
+ if (hif_drv->remain_on_ch.ready)
+ hif_drv->remain_on_ch.ready(hif_drv->remain_on_ch.arg);
if (hif_drv->remain_on_ch_pending)
hif_drv->remain_on_ch_pending = 0;
@@ -2542,14 +2574,16 @@ ERRORHANDLER:
return result;
}
-static int Handle_RegisterFrame(struct host_if_drv *hif_drv,
+static int Handle_RegisterFrame(struct wilc_vif *vif,
struct reg_frame *pstrHostIfRegisterFrame)
{
s32 result = 0;
struct wid wid;
u8 *pu8CurrByte;
- PRINT_D(HOSTINF_DBG, "Handling frame register Flag : %d FrameType: %d\n", pstrHostIfRegisterFrame->bReg, pstrHostIfRegisterFrame->u16FrameType);
+ PRINT_D(HOSTINF_DBG, "Handling frame register : %d FrameType: %d\n",
+ pstrHostIfRegisterFrame->reg,
+ pstrHostIfRegisterFrame->frame_type);
wid.id = (u16)WID_REGISTER_FRAME;
wid.type = WID_STR;
@@ -2559,15 +2593,14 @@ static int Handle_RegisterFrame(struct host_if_drv *hif_drv,
pu8CurrByte = wid.val;
- *pu8CurrByte++ = pstrHostIfRegisterFrame->bReg;
- *pu8CurrByte++ = pstrHostIfRegisterFrame->u8Regid;
- memcpy(pu8CurrByte, &pstrHostIfRegisterFrame->u16FrameType,
- sizeof(u16));
+ *pu8CurrByte++ = pstrHostIfRegisterFrame->reg;
+ *pu8CurrByte++ = pstrHostIfRegisterFrame->reg_id;
+ memcpy(pu8CurrByte, &pstrHostIfRegisterFrame->frame_type, sizeof(u16));
wid.size = sizeof(u16) + 2;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
PRINT_ER("Failed to frame register config packet\n");
result = -EINVAL;
@@ -2576,12 +2609,13 @@ static int Handle_RegisterFrame(struct host_if_drv *hif_drv,
return result;
}
-static u32 Handle_ListenStateExpired(struct host_if_drv *hif_drv,
+static u32 Handle_ListenStateExpired(struct wilc_vif *vif,
struct remain_ch *pstrHostIfRemainOnChan)
{
u8 u8remain_on_chan_flag;
struct wid wid;
s32 result = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
PRINT_D(HOSTINF_DBG, "CANCEL REMAIN ON CHAN\n");
@@ -2592,22 +2626,24 @@ static u32 Handle_ListenStateExpired(struct host_if_drv *hif_drv,
wid.size = 2;
wid.val = kmalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
+ if (!wid.val) {
PRINT_ER("Failed to allocate memory\n");
+ return -ENOMEM;
+ }
wid.val[0] = u8remain_on_chan_flag;
wid.val[1] = FALSE_FRMWR_CHANNEL;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result != 0) {
PRINT_ER("Failed to set remain on channel\n");
goto _done_;
}
- if (hif_drv->remain_on_ch.pRemainOnChanExpired) {
- hif_drv->remain_on_ch.pRemainOnChanExpired(hif_drv->remain_on_ch.pVoid,
- pstrHostIfRemainOnChan->u32ListenSessionID);
+ if (hif_drv->remain_on_ch.expired) {
+ hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
+ pstrHostIfRemainOnChan->id);
}
P2P_LISTEN_STATE = 0;
} else {
@@ -2623,21 +2659,21 @@ static void ListenTimerCB(unsigned long arg)
{
s32 result = 0;
struct host_if_msg msg;
- struct host_if_drv *hif_drv = (struct host_if_drv *)arg;
+ struct wilc_vif *vif = (struct wilc_vif *)arg;
- del_timer(&hif_drv->hRemainOnChannel);
+ del_timer(&vif->hif_drv->remain_on_ch_timer);
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_LISTEN_TIMER_FIRED;
- msg.drv = hif_drv;
- msg.body.remain_on_ch.u32ListenSessionID = hif_drv->remain_on_ch.u32ListenSessionID;
+ msg.vif = vif;
+ msg.body.remain_on_ch.id = vif->hif_drv->remain_on_ch.id;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("wilc_mq_send fail\n");
}
-static void Handle_PowerManagement(struct host_if_drv *hif_drv,
+static void Handle_PowerManagement(struct wilc_vif *vif,
struct power_mgmt_param *strPowerMgmtParam)
{
s32 result = 0;
@@ -2656,13 +2692,13 @@ static void Handle_PowerManagement(struct host_if_drv *hif_drv,
PRINT_D(HOSTINF_DBG, "Handling Power Management\n");
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send power management config packet\n");
}
-static void Handle_SetMulticastFilter(struct host_if_drv *hif_drv,
+static void Handle_SetMulticastFilter(struct wilc_vif *vif,
struct set_multicast *strHostIfSetMulti)
{
s32 result = 0;
@@ -2680,9 +2716,9 @@ static void Handle_SetMulticastFilter(struct host_if_drv *hif_drv,
pu8CurrByte = wid.val;
*pu8CurrByte++ = (strHostIfSetMulti->enabled & 0xFF);
- *pu8CurrByte++ = ((strHostIfSetMulti->enabled >> 8) & 0xFF);
- *pu8CurrByte++ = ((strHostIfSetMulti->enabled >> 16) & 0xFF);
- *pu8CurrByte++ = ((strHostIfSetMulti->enabled >> 24) & 0xFF);
+ *pu8CurrByte++ = 0;
+ *pu8CurrByte++ = 0;
+ *pu8CurrByte++ = 0;
*pu8CurrByte++ = (strHostIfSetMulti->cnt & 0xFF);
*pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 8) & 0xFF);
@@ -2690,10 +2726,11 @@ static void Handle_SetMulticastFilter(struct host_if_drv *hif_drv,
*pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 24) & 0xFF);
if ((strHostIfSetMulti->cnt) > 0)
- memcpy(pu8CurrByte, gau8MulticastMacAddrList, ((strHostIfSetMulti->cnt) * ETH_ALEN));
+ memcpy(pu8CurrByte, wilc_multicast_mac_addr_list,
+ ((strHostIfSetMulti->cnt) * ETH_ALEN));
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_ER("Failed to send setup multicast config packet\n");
@@ -2701,71 +2738,7 @@ ERRORHANDLER:
kfree(wid.val);
}
-static s32 Handle_AddBASession(struct host_if_drv *hif_drv,
- struct ba_session_info *strHostIfBASessionInfo)
-{
- s32 result = 0;
- struct wid wid;
- int AddbaTimeout = 100;
- char *ptr = NULL;
-
- PRINT_D(HOSTINF_DBG, "Opening Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\nBufferSize == %d\nSessionTimeOut = %d\n",
- strHostIfBASessionInfo->au8Bssid[0],
- strHostIfBASessionInfo->au8Bssid[1],
- strHostIfBASessionInfo->au8Bssid[2],
- strHostIfBASessionInfo->u16BufferSize,
- strHostIfBASessionInfo->u16SessionTimeout,
- strHostIfBASessionInfo->u8Ted);
-
- wid.id = (u16)WID_11E_P_ACTION_REQ;
- wid.type = WID_STR;
- wid.val = kmalloc(BLOCK_ACK_REQ_SIZE, GFP_KERNEL);
- wid.size = BLOCK_ACK_REQ_SIZE;
- ptr = wid.val;
- *ptr++ = 0x14;
- *ptr++ = 0x3;
- *ptr++ = 0x0;
- memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN);
- ptr += ETH_ALEN;
- *ptr++ = strHostIfBASessionInfo->u8Ted;
- *ptr++ = 1;
- *ptr++ = (strHostIfBASessionInfo->u16BufferSize & 0xFF);
- *ptr++ = ((strHostIfBASessionInfo->u16BufferSize >> 16) & 0xFF);
- *ptr++ = (strHostIfBASessionInfo->u16SessionTimeout & 0xFF);
- *ptr++ = ((strHostIfBASessionInfo->u16SessionTimeout >> 16) & 0xFF);
- *ptr++ = (AddbaTimeout & 0xFF);
- *ptr++ = ((AddbaTimeout >> 16) & 0xFF);
- *ptr++ = 8;
- *ptr++ = 0;
-
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
- if (result)
- PRINT_D(HOSTINF_DBG, "Couldn't open BA Session\n");
-
- wid.id = (u16)WID_11E_P_ACTION_REQ;
- wid.type = WID_STR;
- wid.size = 15;
- ptr = wid.val;
- *ptr++ = 15;
- *ptr++ = 7;
- *ptr++ = 0x2;
- memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN);
- ptr += ETH_ALEN;
- *ptr++ = strHostIfBASessionInfo->u8Ted;
- *ptr++ = 8;
- *ptr++ = (strHostIfBASessionInfo->u16BufferSize & 0xFF);
- *ptr++ = ((strHostIfBASessionInfo->u16SessionTimeout >> 16) & 0xFF);
- *ptr++ = 3;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
-
- kfree(wid.val);
-
- return result;
-}
-
-static s32 Handle_DelAllRxBASessions(struct host_if_drv *hif_drv,
+static s32 Handle_DelAllRxBASessions(struct wilc_vif *vif,
struct ba_session_info *strHostIfBASessionInfo)
{
s32 result = 0;
@@ -2773,10 +2746,10 @@ static s32 Handle_DelAllRxBASessions(struct host_if_drv *hif_drv,
char *ptr = NULL;
PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\n",
- strHostIfBASessionInfo->au8Bssid[0],
- strHostIfBASessionInfo->au8Bssid[1],
- strHostIfBASessionInfo->au8Bssid[2],
- strHostIfBASessionInfo->u8Ted);
+ strHostIfBASessionInfo->bssid[0],
+ strHostIfBASessionInfo->bssid[1],
+ strHostIfBASessionInfo->bssid[2],
+ strHostIfBASessionInfo->tid);
wid.id = (u16)WID_DEL_ALL_RX_BA;
wid.type = WID_STR;
@@ -2786,14 +2759,14 @@ static s32 Handle_DelAllRxBASessions(struct host_if_drv *hif_drv,
*ptr++ = 0x14;
*ptr++ = 0x3;
*ptr++ = 0x2;
- memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN);
+ memcpy(ptr, strHostIfBASessionInfo->bssid, ETH_ALEN);
ptr += ETH_ALEN;
- *ptr++ = strHostIfBASessionInfo->u8Ted;
+ *ptr++ = strHostIfBASessionInfo->tid;
*ptr++ = 0;
*ptr++ = 32;
- result = send_config_pkt(SET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result)
PRINT_D(HOSTINF_DBG, "Couldn't delete BA Session\n");
@@ -2808,19 +2781,20 @@ static int hostIFthread(void *pvArg)
{
u32 u32Ret;
struct host_if_msg msg;
- struct host_if_drv *hif_drv;
+ struct wilc *wilc = (struct wilc*)pvArg;
+ struct wilc_vif *vif;
memset(&msg, 0, sizeof(struct host_if_msg));
while (1) {
wilc_mq_recv(&hif_msg_q, &msg, sizeof(struct host_if_msg), &u32Ret);
- hif_drv = (struct host_if_drv *)msg.drv;
+ vif = msg.vif;
if (msg.id == HOST_IF_MSG_EXIT) {
PRINT_D(GENERIC_DBG, "THREAD: Exiting HostIfThread\n");
break;
}
- if ((!g_wilc_initialized)) {
+ if ((!wilc_initialized)) {
PRINT_D(GENERIC_DBG, "--WAIT--");
usleep_range(200 * 1000, 200 * 1000);
wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
@@ -2828,7 +2802,7 @@ static int hostIFthread(void *pvArg)
}
if (msg.id == HOST_IF_MSG_CONNECT &&
- hif_drv->usr_scan_req.pfUserScanResult) {
+ vif->hif_drv->usr_scan_req.scan_result) {
PRINT_D(HOSTINF_DBG, "Requeue connect request till scan done received\n");
wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
usleep_range(2 * 1000, 2 * 1000);
@@ -2841,167 +2815,169 @@ static int hostIFthread(void *pvArg)
break;
case HOST_IF_MSG_SCAN:
- Handle_Scan(msg.drv, &msg.body.scan_info);
+ Handle_Scan(msg.vif, &msg.body.scan_info);
break;
case HOST_IF_MSG_CONNECT:
- Handle_Connect(msg.drv, &msg.body.con_info);
+ Handle_Connect(msg.vif, &msg.body.con_info);
break;
case HOST_IF_MSG_FLUSH_CONNECT:
- Handle_FlushConnect(msg.drv);
+ Handle_FlushConnect(msg.vif);
break;
case HOST_IF_MSG_RCVD_NTWRK_INFO:
- Handle_RcvdNtwrkInfo(msg.drv, &msg.body.net_info);
+ Handle_RcvdNtwrkInfo(msg.vif, &msg.body.net_info);
break;
case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO:
- Handle_RcvdGnrlAsyncInfo(msg.drv, &msg.body.async_info);
+ Handle_RcvdGnrlAsyncInfo(vif,
+ &msg.body.async_info);
break;
case HOST_IF_MSG_KEY:
- Handle_Key(msg.drv, &msg.body.key_info);
+ Handle_Key(msg.vif, &msg.body.key_info);
break;
case HOST_IF_MSG_CFG_PARAMS:
-
- Handle_CfgParam(msg.drv, &msg.body.cfg_info);
+ handle_cfg_param(msg.vif, &msg.body.cfg_info);
break;
case HOST_IF_MSG_SET_CHANNEL:
- Handle_SetChannel(msg.drv, &msg.body.channel_info);
+ handle_set_channel(msg.vif, &msg.body.channel_info);
break;
case HOST_IF_MSG_DISCONNECT:
- Handle_Disconnect(msg.drv);
+ Handle_Disconnect(msg.vif);
break;
case HOST_IF_MSG_RCVD_SCAN_COMPLETE:
- del_timer(&hif_drv->hScanTimer);
+ del_timer(&vif->hif_drv->scan_timer);
PRINT_D(HOSTINF_DBG, "scan completed successfully\n");
- if (!linux_wlan_get_num_conn_ifcs())
- chip_sleep_manually(INFINITE_SLEEP_TIME);
+ if (!wilc_wlan_get_num_conn_ifcs(wilc))
+ wilc_chip_sleep_manually(wilc);
- Handle_ScanDone(msg.drv, SCAN_EVENT_DONE);
+ Handle_ScanDone(msg.vif, SCAN_EVENT_DONE);
- if (hif_drv->remain_on_ch_pending)
- Handle_RemainOnChan(msg.drv, &msg.body.remain_on_ch);
+ if (vif->hif_drv->remain_on_ch_pending)
+ Handle_RemainOnChan(msg.vif,
+ &msg.body.remain_on_ch);
break;
case HOST_IF_MSG_GET_RSSI:
- Handle_GetRssi(msg.drv);
+ Handle_GetRssi(msg.vif);
break;
case HOST_IF_MSG_GET_LINKSPEED:
- Handle_GetLinkspeed(msg.drv);
+ Handle_GetLinkspeed(msg.vif);
break;
case HOST_IF_MSG_GET_STATISTICS:
- Handle_GetStatistics(msg.drv, (struct rf_info *)msg.body.data);
+ Handle_GetStatistics(msg.vif,
+ (struct rf_info *)msg.body.data);
break;
case HOST_IF_MSG_GET_CHNL:
- Handle_GetChnl(msg.drv);
+ Handle_GetChnl(msg.vif);
break;
case HOST_IF_MSG_ADD_BEACON:
- Handle_AddBeacon(msg.drv, &msg.body.beacon_info);
+ Handle_AddBeacon(msg.vif, &msg.body.beacon_info);
break;
case HOST_IF_MSG_DEL_BEACON:
- Handle_DelBeacon(msg.drv);
+ Handle_DelBeacon(msg.vif);
break;
case HOST_IF_MSG_ADD_STATION:
- Handle_AddStation(msg.drv, &msg.body.add_sta_info);
+ Handle_AddStation(msg.vif, &msg.body.add_sta_info);
break;
case HOST_IF_MSG_DEL_STATION:
- Handle_DelStation(msg.drv, &msg.body.del_sta_info);
+ Handle_DelStation(msg.vif, &msg.body.del_sta_info);
break;
case HOST_IF_MSG_EDIT_STATION:
- Handle_EditStation(msg.drv, &msg.body.edit_sta_info);
+ Handle_EditStation(msg.vif, &msg.body.edit_sta_info);
break;
case HOST_IF_MSG_GET_INACTIVETIME:
- Handle_Get_InActiveTime(msg.drv, &msg.body.mac_info);
+ Handle_Get_InActiveTime(msg.vif, &msg.body.mac_info);
break;
case HOST_IF_MSG_SCAN_TIMER_FIRED:
PRINT_D(HOSTINF_DBG, "Scan Timeout\n");
- Handle_ScanDone(msg.drv, SCAN_EVENT_ABORTED);
+ Handle_ScanDone(msg.vif, SCAN_EVENT_ABORTED);
break;
case HOST_IF_MSG_CONNECT_TIMER_FIRED:
PRINT_D(HOSTINF_DBG, "Connect Timeout\n");
- Handle_ConnectTimeout(msg.drv);
+ Handle_ConnectTimeout(msg.vif);
break;
case HOST_IF_MSG_POWER_MGMT:
- Handle_PowerManagement(msg.drv, &msg.body.pwr_mgmt_info);
+ Handle_PowerManagement(msg.vif,
+ &msg.body.pwr_mgmt_info);
break;
case HOST_IF_MSG_SET_WFIDRV_HANDLER:
- Handle_SetWfiDrvHandler(msg.drv,
- &msg.body.drv);
+ handle_set_wfi_drv_handler(msg.vif, &msg.body.drv);
break;
case HOST_IF_MSG_SET_OPERATION_MODE:
- Handle_SetOperationMode(msg.drv, &msg.body.mode);
+ handle_set_operation_mode(msg.vif, &msg.body.mode);
break;
case HOST_IF_MSG_SET_IPADDRESS:
PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_IPADDRESS\n");
- Handle_set_IPAddress(msg.drv, msg.body.ip_info.ip_addr, msg.body.ip_info.idx);
+ handle_set_ip_address(vif,
+ msg.body.ip_info.ip_addr,
+ msg.body.ip_info.idx);
break;
case HOST_IF_MSG_GET_IPADDRESS:
PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_IPADDRESS\n");
- Handle_get_IPAddress(msg.drv, msg.body.ip_info.ip_addr, msg.body.ip_info.idx);
+ handle_get_ip_address(vif, msg.body.ip_info.idx);
break;
case HOST_IF_MSG_SET_MAC_ADDRESS:
- Handle_SetMacAddress(msg.drv, &msg.body.set_mac_info);
+ handle_set_mac_address(msg.vif,
+ &msg.body.set_mac_info);
break;
case HOST_IF_MSG_GET_MAC_ADDRESS:
- Handle_GetMacAddress(msg.drv, &msg.body.get_mac_info);
+ handle_get_mac_address(msg.vif,
+ &msg.body.get_mac_info);
break;
case HOST_IF_MSG_REMAIN_ON_CHAN:
PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_REMAIN_ON_CHAN\n");
- Handle_RemainOnChan(msg.drv, &msg.body.remain_on_ch);
+ Handle_RemainOnChan(msg.vif, &msg.body.remain_on_ch);
break;
case HOST_IF_MSG_REGISTER_FRAME:
PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_REGISTER_FRAME\n");
- Handle_RegisterFrame(msg.drv, &msg.body.reg_frame);
+ Handle_RegisterFrame(msg.vif, &msg.body.reg_frame);
break;
case HOST_IF_MSG_LISTEN_TIMER_FIRED:
- Handle_ListenStateExpired(msg.drv, &msg.body.remain_on_ch);
+ Handle_ListenStateExpired(msg.vif, &msg.body.remain_on_ch);
break;
case HOST_IF_MSG_SET_MULTICAST_FILTER:
PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_MULTICAST_FILTER\n");
- Handle_SetMulticastFilter(msg.drv, &msg.body.multicast_info);
- break;
-
- case HOST_IF_MSG_ADD_BA_SESSION:
- Handle_AddBASession(msg.drv, &msg.body.session_info);
+ Handle_SetMulticastFilter(msg.vif, &msg.body.multicast_info);
break;
case HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS:
- Handle_DelAllRxBASessions(msg.drv, &msg.body.session_info);
+ Handle_DelAllRxBASessions(msg.vif, &msg.body.session_info);
break;
case HOST_IF_MSG_DEL_ALL_STA:
- Handle_DelAllSta(msg.drv, &msg.body.del_all_sta_info);
+ Handle_DelAllSta(msg.vif, &msg.body.del_all_sta_info);
break;
default:
@@ -3017,11 +2993,11 @@ static int hostIFthread(void *pvArg)
static void TimerCB_Scan(unsigned long arg)
{
- void *pvArg = (void *)arg;
+ struct wilc_vif *vif = (struct wilc_vif *)arg;
struct host_if_msg msg;
memset(&msg, 0, sizeof(struct host_if_msg));
- msg.drv = pvArg;
+ msg.vif = vif;
msg.id = HOST_IF_MSG_SCAN_TIMER_FIRED;
wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
@@ -3029,17 +3005,17 @@ static void TimerCB_Scan(unsigned long arg)
static void TimerCB_Connect(unsigned long arg)
{
- void *pvArg = (void *)arg;
+ struct wilc_vif *vif = (struct wilc_vif *)arg;
struct host_if_msg msg;
memset(&msg, 0, sizeof(struct host_if_msg));
- msg.drv = pvArg;
+ msg.vif = vif;
msg.id = HOST_IF_MSG_CONNECT_TIMER_FIRED;
wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
}
-s32 host_int_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress)
+s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress)
{
struct wid wid;
@@ -3051,10 +3027,11 @@ s32 host_int_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress)
return 0;
}
-int host_int_remove_wep_key(struct host_if_drv *hif_drv, u8 index)
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
{
int result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
result = -EFAULT;
@@ -3067,21 +3044,22 @@ int host_int_remove_wep_key(struct host_if_drv *hif_drv, u8 index)
msg.id = HOST_IF_MSG_KEY;
msg.body.key_info.type = WEP;
msg.body.key_info.action = REMOVEKEY;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.key_info.attr.wep.index = index;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Error in sending message queue : Request to remove WEP key\n");
- down(&hif_drv->hSemTestKeyBlock);
+ down(&hif_drv->sem_test_key_block);
return result;
}
-int host_int_set_wep_default_key(struct host_if_drv *hif_drv, u8 index)
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
{
int result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
result = -EFAULT;
@@ -3094,24 +3072,23 @@ int host_int_set_wep_default_key(struct host_if_drv *hif_drv, u8 index)
msg.id = HOST_IF_MSG_KEY;
msg.body.key_info.type = WEP;
msg.body.key_info.action = DEFAULTKEY;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.key_info.attr.wep.index = index;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Error in sending message queue : Default key index\n");
- down(&hif_drv->hSemTestKeyBlock);
+ down(&hif_drv->sem_test_key_block);
return result;
}
-int host_int_add_wep_key_bss_sta(struct host_if_drv *hif_drv,
- const u8 *key,
- u8 len,
- u8 index)
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index)
{
int result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -3123,7 +3100,7 @@ int host_int_add_wep_key_bss_sta(struct host_if_drv *hif_drv,
msg.id = HOST_IF_MSG_KEY;
msg.body.key_info.type = WEP;
msg.body.key_info.action = ADDKEY;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.key_info.attr.wep.key = kmemdup(key, len, GFP_KERNEL);
if (!msg.body.key_info.attr.wep.key)
return -ENOMEM;
@@ -3134,20 +3111,17 @@ int host_int_add_wep_key_bss_sta(struct host_if_drv *hif_drv,
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Error in sending message queue :WEP Key\n");
- down(&hif_drv->hSemTestKeyBlock);
+ down(&hif_drv->sem_test_key_block);
return result;
}
-int host_int_add_wep_key_bss_ap(struct host_if_drv *hif_drv,
- const u8 *key,
- u8 len,
- u8 index,
- u8 mode,
- enum AUTHTYPE auth_type)
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index, u8 mode, enum AUTHTYPE auth_type)
{
int result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
int i;
if (!hif_drv) {
@@ -3164,7 +3138,7 @@ int host_int_add_wep_key_bss_ap(struct host_if_drv *hif_drv,
msg.id = HOST_IF_MSG_KEY;
msg.body.key_info.type = WEP;
msg.body.key_info.action = ADDKEY_AP;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.key_info.attr.wep.key = kmemdup(key, len, GFP_KERNEL);
if (!msg.body.key_info.attr.wep.key)
return -ENOMEM;
@@ -3178,85 +3152,86 @@ int host_int_add_wep_key_bss_ap(struct host_if_drv *hif_drv,
if (result)
PRINT_ER("Error in sending message queue :WEP Key\n");
- down(&hif_drv->hSemTestKeyBlock);
+ down(&hif_drv->sem_test_key_block);
return result;
}
-s32 host_int_add_ptk(struct host_if_drv *hif_drv, const u8 *pu8Ptk,
- u8 u8PtkKeylen, const u8 *mac_addr,
- const u8 *pu8RxMic, const u8 *pu8TxMic,
- u8 mode, u8 u8Ciphermode, u8 u8Idx)
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+ const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+ u8 mode, u8 cipher_mode, u8 index)
{
- s32 result = 0;
+ int result = 0;
struct host_if_msg msg;
- u8 u8KeyLen = u8PtkKeylen;
- u32 i;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ u8 key_len = ptk_key_len;
+ int i;
if (!hif_drv) {
PRINT_ER("driver is null\n");
return -EFAULT;
}
- if (pu8RxMic)
- u8KeyLen += RX_MIC_KEY_LEN;
+ if (rx_mic)
+ key_len += RX_MIC_KEY_LEN;
- if (pu8TxMic)
- u8KeyLen += TX_MIC_KEY_LEN;
+ if (tx_mic)
+ key_len += TX_MIC_KEY_LEN;
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_KEY;
- msg.body.key_info.type = WPAPtk;
+ msg.body.key_info.type = WPA_PTK;
if (mode == AP_MODE) {
msg.body.key_info.action = ADDKEY_AP;
- msg.body.key_info.attr.wpa.index = u8Idx;
+ msg.body.key_info.attr.wpa.index = index;
}
if (mode == STATION_MODE)
msg.body.key_info.action = ADDKEY;
- msg.body.key_info.attr.wpa.key = kmalloc(u8PtkKeylen, GFP_KERNEL);
- memcpy(msg.body.key_info.attr.wpa.key, pu8Ptk, u8PtkKeylen);
+ msg.body.key_info.attr.wpa.key = kmemdup(ptk, ptk_key_len, GFP_KERNEL);
+ if (!msg.body.key_info.attr.wpa.key)
+ return -ENOMEM;
- if (pu8RxMic) {
- memcpy(msg.body.key_info.attr.wpa.key + 16, pu8RxMic, RX_MIC_KEY_LEN);
+ if (rx_mic) {
+ memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic, RX_MIC_KEY_LEN);
if (INFO) {
for (i = 0; i < RX_MIC_KEY_LEN; i++)
- PRINT_INFO(CFG80211_DBG, "PairwiseRx[%d] = %x\n", i, pu8RxMic[i]);
+ PRINT_INFO(CFG80211_DBG, "PairwiseRx[%d] = %x\n", i, rx_mic[i]);
}
}
- if (pu8TxMic) {
- memcpy(msg.body.key_info.attr.wpa.key + 24, pu8TxMic, TX_MIC_KEY_LEN);
+ if (tx_mic) {
+ memcpy(msg.body.key_info.attr.wpa.key + 24, tx_mic, TX_MIC_KEY_LEN);
if (INFO) {
for (i = 0; i < TX_MIC_KEY_LEN; i++)
- PRINT_INFO(CFG80211_DBG, "PairwiseTx[%d] = %x\n", i, pu8TxMic[i]);
+ PRINT_INFO(CFG80211_DBG, "PairwiseTx[%d] = %x\n", i, tx_mic[i]);
}
}
- msg.body.key_info.attr.wpa.key_len = u8KeyLen;
+ msg.body.key_info.attr.wpa.key_len = key_len;
msg.body.key_info.attr.wpa.mac_addr = mac_addr;
- msg.body.key_info.attr.wpa.mode = u8Ciphermode;
- msg.drv = hif_drv;
+ msg.body.key_info.attr.wpa.mode = cipher_mode;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Error in sending message queue: PTK Key\n");
- down(&hif_drv->hSemTestKeyBlock);
+ down(&hif_drv->sem_test_key_block);
return result;
}
-s32 host_int_add_rx_gtk(struct host_if_drv *hif_drv, const u8 *pu8RxGtk,
- u8 u8GtkKeylen, u8 u8KeyIdx,
- u32 u32KeyRSClen, const u8 *KeyRSC,
- const u8 *pu8RxMic, const u8 *pu8TxMic,
- u8 mode, u8 u8Ciphermode)
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+ u8 index, u32 key_rsc_len, const u8 *key_rsc,
+ const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+ u8 cipher_mode)
{
- s32 result = 0;
+ int result = 0;
struct host_if_msg msg;
- u8 u8KeyLen = u8GtkKeylen;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ u8 key_len = gtk_key_len;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -3264,56 +3239,64 @@ s32 host_int_add_rx_gtk(struct host_if_drv *hif_drv, const u8 *pu8RxGtk,
}
memset(&msg, 0, sizeof(struct host_if_msg));
- if (pu8RxMic)
- u8KeyLen += RX_MIC_KEY_LEN;
+ if (rx_mic)
+ key_len += RX_MIC_KEY_LEN;
- if (pu8TxMic)
- u8KeyLen += TX_MIC_KEY_LEN;
+ if (tx_mic)
+ key_len += TX_MIC_KEY_LEN;
- if (KeyRSC) {
- msg.body.key_info.attr.wpa.seq = kmalloc(u32KeyRSClen, GFP_KERNEL);
- memcpy(msg.body.key_info.attr.wpa.seq, KeyRSC, u32KeyRSClen);
+ if (key_rsc) {
+ msg.body.key_info.attr.wpa.seq = kmemdup(key_rsc,
+ key_rsc_len,
+ GFP_KERNEL);
+ if (!msg.body.key_info.attr.wpa.seq)
+ return -ENOMEM;
}
msg.id = HOST_IF_MSG_KEY;
- msg.body.key_info.type = WPARxGtk;
- msg.drv = hif_drv;
+ msg.body.key_info.type = WPA_RX_GTK;
+ msg.vif = vif;
if (mode == AP_MODE) {
msg.body.key_info.action = ADDKEY_AP;
- msg.body.key_info.attr.wpa.mode = u8Ciphermode;
+ msg.body.key_info.attr.wpa.mode = cipher_mode;
}
if (mode == STATION_MODE)
msg.body.key_info.action = ADDKEY;
- msg.body.key_info.attr.wpa.key = kmalloc(u8KeyLen, GFP_KERNEL);
- memcpy(msg.body.key_info.attr.wpa.key, pu8RxGtk, u8GtkKeylen);
+ msg.body.key_info.attr.wpa.key = kmemdup(rx_gtk,
+ key_len,
+ GFP_KERNEL);
+ if (!msg.body.key_info.attr.wpa.key)
+ return -ENOMEM;
- if (pu8RxMic)
- memcpy(msg.body.key_info.attr.wpa.key + 16, pu8RxMic,
+ if (rx_mic)
+ memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic,
RX_MIC_KEY_LEN);
- if (pu8TxMic)
- memcpy(msg.body.key_info.attr.wpa.key + 24, pu8TxMic,
+ if (tx_mic)
+ memcpy(msg.body.key_info.attr.wpa.key + 24, tx_mic,
TX_MIC_KEY_LEN);
- msg.body.key_info.attr.wpa.index = u8KeyIdx;
- msg.body.key_info.attr.wpa.key_len = u8KeyLen;
- msg.body.key_info.attr.wpa.seq_len = u32KeyRSClen;
+ msg.body.key_info.attr.wpa.index = index;
+ msg.body.key_info.attr.wpa.key_len = key_len;
+ msg.body.key_info.attr.wpa.seq_len = key_rsc_len;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Error in sending message queue: RX GTK\n");
- down(&hif_drv->hSemTestKeyBlock);
+ down(&hif_drv->sem_test_key_block);
return result;
}
-s32 host_int_set_pmkid_info(struct host_if_drv *hif_drv, struct host_if_pmkid_attr *pu8PmkidInfoArray)
+s32 wilc_set_pmkid_info(struct wilc_vif *vif,
+ struct host_if_pmkid_attr *pu8PmkidInfoArray)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
u32 i;
if (!hif_drv) {
@@ -3326,7 +3309,7 @@ s32 host_int_set_pmkid_info(struct host_if_drv *hif_drv, struct host_if_pmkid_at
msg.id = HOST_IF_MSG_KEY;
msg.body.key_info.type = PMKSA;
msg.body.key_info.action = ADDKEY;
- msg.drv = hif_drv;
+ msg.vif = vif;
for (i = 0; i < pu8PmkidInfoArray->numpmkid; i++) {
memcpy(msg.body.key_info.attr.pmkid.pmkidlist[i].bssid,
@@ -3342,37 +3325,7 @@ s32 host_int_set_pmkid_info(struct host_if_drv *hif_drv, struct host_if_pmkid_at
return result;
}
-s32 host_int_get_pmkid_info(struct host_if_drv *hif_drv,
- u8 *pu8PmkidInfoArray,
- u32 u32PmkidInfoLen)
-{
- struct wid wid;
-
- wid.id = (u16)WID_PMKID_INFO;
- wid.type = WID_STR;
- wid.size = u32PmkidInfoLen;
- wid.val = pu8PmkidInfoArray;
-
- return 0;
-}
-
-s32 host_int_set_RSNAConfigPSKPassPhrase(struct host_if_drv *hif_drv,
- u8 *pu8PassPhrase,
- u8 u8Psklength)
-{
- struct wid wid;
-
- if ((u8Psklength > 7) && (u8Psklength < 65)) {
- wid.id = (u16)WID_11I_PSK;
- wid.type = WID_STR;
- wid.val = pu8PassPhrase;
- wid.size = u8Psklength;
- }
-
- return 0;
-}
-
-s32 host_int_get_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress)
+s32 wilc_get_mac_address(struct wilc_vif *vif, u8 *pu8MacAddress)
{
s32 result = 0;
struct host_if_msg msg;
@@ -3381,7 +3334,7 @@ s32 host_int_get_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress)
msg.id = HOST_IF_MSG_GET_MAC_ADDRESS;
msg.body.get_mac_info.mac_addr = pu8MacAddress;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3393,7 +3346,7 @@ s32 host_int_get_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress)
return result;
}
-s32 host_int_set_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress)
+s32 wilc_set_mac_address(struct wilc_vif *vif, u8 *pu8MacAddress)
{
s32 result = 0;
struct host_if_msg msg;
@@ -3403,7 +3356,7 @@ s32 host_int_set_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress)
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_SET_MAC_ADDRESS;
memcpy(msg.body.set_mac_info.mac_addr, pu8MacAddress, ETH_ALEN);
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -3412,52 +3365,15 @@ s32 host_int_set_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress)
return result;
}
-s32 host_int_get_RSNAConfigPSKPassPhrase(struct host_if_drv *hif_drv,
- u8 *pu8PassPhrase, u8 u8Psklength)
-{
- struct wid wid;
-
- wid.id = (u16)WID_11I_PSK;
- wid.type = WID_STR;
- wid.size = u8Psklength;
- wid.val = pu8PassPhrase;
-
- return 0;
-}
-
-s32 host_int_set_start_scan_req(struct host_if_drv *hif_drv, u8 scanSource)
-{
- struct wid wid;
-
- wid.id = (u16)WID_START_SCAN_REQ;
- wid.type = WID_CHAR;
- wid.val = (s8 *)&scanSource;
- wid.size = sizeof(char);
-
- return 0;
-}
-
-s32 host_int_get_start_scan_req(struct host_if_drv *hif_drv, u8 *pu8ScanSource)
-{
- struct wid wid;
-
- wid.id = (u16)WID_START_SCAN_REQ;
- wid.type = WID_CHAR;
- wid.val = (s8 *)pu8ScanSource;
- wid.size = sizeof(char);
-
- return 0;
-}
-
-s32 host_int_set_join_req(struct host_if_drv *hif_drv, u8 *pu8bssid,
- const u8 *pu8ssid, size_t ssidLen,
- const u8 *pu8IEs, size_t IEsLen,
- wilc_connect_result pfConnectResult, void *pvUserArg,
- u8 u8security, enum AUTHTYPE tenuAuth_type,
- u8 u8channel, void *pJoinParams)
+s32 wilc_set_join_req(struct wilc_vif *vif, u8 *pu8bssid, const u8 *pu8ssid,
+ size_t ssidLen, const u8 *pu8IEs, size_t IEsLen,
+ wilc_connect_result pfConnectResult, void *pvUserArg,
+ u8 u8security, enum AUTHTYPE tenuAuth_type,
+ u8 u8channel, void *pJoinParams)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv || !pfConnectResult) {
PRINT_ER("Driver is null\n");
@@ -3479,7 +3395,7 @@ s32 host_int_set_join_req(struct host_if_drv *hif_drv, u8 *pu8bssid,
msg.body.con_info.result = pfConnectResult;
msg.body.con_info.arg = pvUserArg;
msg.body.con_info.params = pJoinParams;
- msg.drv = hif_drv ;
+ msg.vif = vif;
if (pu8bssid) {
msg.body.con_info.bssid = kmalloc(6, GFP_KERNEL);
@@ -3497,10 +3413,11 @@ s32 host_int_set_join_req(struct host_if_drv *hif_drv, u8 *pu8bssid,
msg.body.con_info.ies = kmalloc(IEsLen, GFP_KERNEL);
memcpy(msg.body.con_info.ies, pu8IEs, IEsLen);
}
- if (hif_drv->enuHostIFstate < HOST_IF_CONNECTING)
- hif_drv->enuHostIFstate = HOST_IF_CONNECTING;
+ if (hif_drv->hif_state < HOST_IF_CONNECTING)
+ hif_drv->hif_state = HOST_IF_CONNECTING;
else
- PRINT_D(GENERIC_DBG, "Don't set state to 'connecting' as state is %d\n", hif_drv->enuHostIFstate);
+ PRINT_D(GENERIC_DBG, "Don't set state to 'connecting' : %d\n",
+ hif_drv->hif_state);
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3508,17 +3425,18 @@ s32 host_int_set_join_req(struct host_if_drv *hif_drv, u8 *pu8bssid,
return -EFAULT;
}
- hif_drv->hConnectTimer.data = (unsigned long)hif_drv;
- mod_timer(&hif_drv->hConnectTimer,
+ hif_drv->connect_timer.data = (unsigned long)vif;
+ mod_timer(&hif_drv->connect_timer,
jiffies + msecs_to_jiffies(HOST_IF_CONNECT_TIMEOUT));
return result;
}
-s32 host_int_flush_join_req(struct host_if_drv *hif_drv)
+s32 wilc_flush_join_req(struct wilc_vif *vif)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!join_req)
return -EFAULT;
@@ -3529,7 +3447,7 @@ s32 host_int_flush_join_req(struct host_if_drv *hif_drv)
}
msg.id = HOST_IF_MSG_FLUSH_CONNECT;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3540,10 +3458,11 @@ s32 host_int_flush_join_req(struct host_if_drv *hif_drv)
return result;
}
-s32 host_int_disconnect(struct host_if_drv *hif_drv, u16 u16ReasonCode)
+s32 wilc_disconnect(struct wilc_vif *vif, u16 u16ReasonCode)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("Driver is null\n");
@@ -3553,50 +3472,25 @@ s32 host_int_disconnect(struct host_if_drv *hif_drv, u16 u16ReasonCode)
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_DISCONNECT;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Failed to send message queue: disconnect\n");
- down(&hif_drv->hSemTestDisconnectBlock);
+ down(&hif_drv->sem_test_disconn_block);
return result;
}
-s32 host_int_disconnect_station(struct host_if_drv *hif_drv, u8 assoc_id)
-{
- struct wid wid;
-
- wid.id = (u16)WID_DISCONNECT;
- wid.type = WID_CHAR;
- wid.val = (s8 *)&assoc_id;
- wid.size = sizeof(char);
-
- return 0;
-}
-
-s32 host_int_get_assoc_req_info(struct host_if_drv *hif_drv,
- u8 *pu8AssocReqInfo,
- u32 u32AssocReqInfoLen)
-{
- struct wid wid;
-
- wid.id = (u16)WID_ASSOC_REQ_INFO;
- wid.type = WID_STR;
- wid.val = pu8AssocReqInfo;
- wid.size = u32AssocReqInfoLen;
-
- return 0;
-}
-
-s32 host_int_get_assoc_res_info(struct host_if_drv *hif_drv,
- u8 *pu8AssocRespInfo,
- u32 u32MaxAssocRespInfoLen,
- u32 *pu32RcvdAssocRespInfoLen)
+static s32 host_int_get_assoc_res_info(struct wilc_vif *vif,
+ u8 *pu8AssocRespInfo,
+ u32 u32MaxAssocRespInfoLen,
+ u32 *pu32RcvdAssocRespInfoLen)
{
s32 result = 0;
struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("Driver is null\n");
@@ -3608,8 +3502,8 @@ s32 host_int_get_assoc_res_info(struct host_if_drv *hif_drv,
wid.val = pu8AssocRespInfo;
wid.size = u32MaxAssocRespInfoLen;
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
+ result = wilc_send_config_pkt(vif->wilc, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
if (result) {
*pu32RcvdAssocRespInfoLen = 0;
PRINT_ER("Failed to send association response config packet\n");
@@ -3621,24 +3515,11 @@ s32 host_int_get_assoc_res_info(struct host_if_drv *hif_drv,
return result;
}
-s32 host_int_get_rx_power_level(struct host_if_drv *hif_drv,
- u8 *pu8RxPowerLevel,
- u32 u32RxPowerLevelLen)
-{
- struct wid wid;
-
- wid.id = (u16)WID_RX_POWER_LEVEL;
- wid.type = WID_STR;
- wid.val = pu8RxPowerLevel;
- wid.size = u32RxPowerLevelLen;
-
- return 0;
-}
-
-int host_int_set_mac_chnl_num(struct host_if_drv *hif_drv, u8 channel)
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
{
int result;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -3648,7 +3529,7 @@ int host_int_set_mac_chnl_num(struct host_if_drv *hif_drv, u8 channel)
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_SET_CHANNEL;
msg.body.channel_info.set_ch = channel;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3659,7 +3540,7 @@ int host_int_set_mac_chnl_num(struct host_if_drv *hif_drv, u8 channel)
return 0;
}
-int host_int_wait_msg_queue_idle(void)
+int wilc_wait_msg_queue_idle(void)
{
int result = 0;
struct host_if_msg msg;
@@ -3677,15 +3558,15 @@ int host_int_wait_msg_queue_idle(void)
return result;
}
-int host_int_set_wfi_drv_handler(struct host_if_drv *hif_drv)
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index)
{
int result = 0;
struct host_if_msg msg;
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_SET_WFIDRV_HANDLER;
- msg.body.drv.handler = get_id_from_handler(hif_drv);
- msg.drv = hif_drv;
+ msg.body.drv.handler = index;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3696,7 +3577,7 @@ int host_int_set_wfi_drv_handler(struct host_if_drv *hif_drv)
return result;
}
-int host_int_set_operation_mode(struct host_if_drv *hif_drv, u32 mode)
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
{
int result = 0;
struct host_if_msg msg;
@@ -3704,7 +3585,7 @@ int host_int_set_operation_mode(struct host_if_drv *hif_drv, u32 mode)
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_SET_OPERATION_MODE;
msg.body.mode.mode = mode;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3715,36 +3596,12 @@ int host_int_set_operation_mode(struct host_if_drv *hif_drv, u32 mode)
return result;
}
-s32 host_int_get_host_chnl_num(struct host_if_drv *hif_drv, u8 *pu8ChNo)
-{
- s32 result = 0;
- struct host_if_msg msg;
-
- if (!hif_drv) {
- PRINT_ER("driver is null\n");
- return -EFAULT;
- }
-
- memset(&msg, 0, sizeof(struct host_if_msg));
-
- msg.id = HOST_IF_MSG_GET_CHNL;
- msg.drv = hif_drv;
-
- result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
- if (result)
- PRINT_ER("wilc mq send fail\n");
- down(&hif_drv->hSemGetCHNL);
-
- *pu8ChNo = ch_no;
-
- return result;
-}
-
-s32 host_int_get_inactive_time(struct host_if_drv *hif_drv,
- const u8 *mac, u32 *pu32InactiveTime)
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+ u32 *pu32InactiveTime)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -3755,55 +3612,28 @@ s32 host_int_get_inactive_time(struct host_if_drv *hif_drv,
memcpy(msg.body.mac_info.mac, mac, ETH_ALEN);
msg.id = HOST_IF_MSG_GET_INACTIVETIME;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
PRINT_ER("Failed to send get host channel param's message queue ");
- down(&hif_drv->hSemInactiveTime);
+ down(&hif_drv->sem_inactive_time);
*pu32InactiveTime = inactive_time;
return result;
}
-s32 host_int_test_get_int_wid(struct host_if_drv *hif_drv, u32 *pu32TestMemAddr)
-{
- s32 result = 0;
- struct wid wid;
-
- if (!hif_drv) {
- PRINT_ER("driver is null\n");
- return -EFAULT;
- }
-
- wid.id = (u16)WID_MEMORY_ADDRESS;
- wid.type = WID_INT;
- wid.val = (s8 *)pu32TestMemAddr;
- wid.size = sizeof(u32);
-
- result = send_config_pkt(GET_CFG, &wid, 1,
- get_id_from_handler(hif_drv));
-
- if (result) {
- PRINT_ER("Failed to get wid value\n");
- return -EINVAL;
- } else {
- PRINT_D(HOSTINF_DBG, "Successfully got wid value\n");
- }
-
- return result;
-}
-
-s32 host_int_get_rssi(struct host_if_drv *hif_drv, s8 *ps8Rssi)
+s32 wilc_get_rssi(struct wilc_vif *vif, s8 *ps8Rssi)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_GET_RSSI;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3811,7 +3641,7 @@ s32 host_int_get_rssi(struct host_if_drv *hif_drv, s8 *ps8Rssi)
return -EFAULT;
}
- down(&hif_drv->hSemGetRSSI);
+ down(&hif_drv->sem_get_rssi);
if (!ps8Rssi) {
PRINT_ER("RSS pointer value is null");
@@ -3823,34 +3653,7 @@ s32 host_int_get_rssi(struct host_if_drv *hif_drv, s8 *ps8Rssi)
return result;
}
-s32 host_int_get_link_speed(struct host_if_drv *hif_drv, s8 *ps8lnkspd)
-{
- struct host_if_msg msg;
- s32 result = 0;
-
- memset(&msg, 0, sizeof(struct host_if_msg));
- msg.id = HOST_IF_MSG_GET_LINKSPEED;
- msg.drv = hif_drv;
-
- result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
- if (result) {
- PRINT_ER("Failed to send GET_LINKSPEED to message queue ");
- return -EFAULT;
- }
-
- down(&hif_drv->hSemGetLINKSPEED);
-
- if (!ps8lnkspd) {
- PRINT_ER("LINKSPEED pointer value is null");
- return -EFAULT;
- }
-
- *ps8lnkspd = link_speed;
-
- return result;
-}
-
-s32 host_int_get_statistics(struct host_if_drv *hif_drv, struct rf_info *pstrStatistics)
+s32 wilc_get_statistics(struct wilc_vif *vif, struct rf_info *pstrStatistics)
{
s32 result = 0;
struct host_if_msg msg;
@@ -3858,7 +3661,7 @@ s32 host_int_get_statistics(struct host_if_drv *hif_drv, struct rf_info *pstrSta
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_GET_STATISTICS;
msg.body.data = (char *)pstrStatistics;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -3870,14 +3673,14 @@ s32 host_int_get_statistics(struct host_if_drv *hif_drv, struct rf_info *pstrSta
return result;
}
-s32 host_int_scan(struct host_if_drv *hif_drv, u8 u8ScanSource,
- u8 u8ScanType, u8 *pu8ChnlFreqList,
- u8 u8ChnlListLen, const u8 *pu8IEs,
- size_t IEsLen, wilc_scan_result ScanResult,
- void *pvUserArg, struct hidden_network *pstrHiddenNetwork)
+s32 wilc_scan(struct wilc_vif *vif, u8 u8ScanSource, u8 u8ScanType,
+ u8 *pu8ChnlFreqList, u8 u8ChnlListLen, const u8 *pu8IEs,
+ size_t IEsLen, wilc_scan_result ScanResult, void *pvUserArg,
+ struct hidden_network *pstrHiddenNetwork)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv || !ScanResult) {
PRINT_ER("hif_drv or ScanResult = NULL\n");
@@ -3895,7 +3698,7 @@ s32 host_int_scan(struct host_if_drv *hif_drv, u8 u8ScanSource,
} else
PRINT_D(HOSTINF_DBG, "pstrHiddenNetwork IS EQUAL TO NULL\n");
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.scan_info.src = u8ScanSource;
msg.body.scan_info.type = u8ScanType;
msg.body.scan_info.result = ScanResult;
@@ -3916,18 +3719,19 @@ s32 host_int_scan(struct host_if_drv *hif_drv, u8 u8ScanSource,
}
PRINT_D(HOSTINF_DBG, ">> Starting the SCAN timer\n");
- hif_drv->hScanTimer.data = (unsigned long)hif_drv;
- mod_timer(&hif_drv->hScanTimer,
+ hif_drv->scan_timer.data = (unsigned long)vif;
+ mod_timer(&hif_drv->scan_timer,
jiffies + msecs_to_jiffies(HOST_IF_SCAN_TIMEOUT));
return result;
}
-s32 hif_set_cfg(struct host_if_drv *hif_drv,
- struct cfg_param_val *pstrCfgParamVal)
+s32 wilc_hif_set_cfg(struct wilc_vif *vif,
+ struct cfg_param_val *pstrCfgParamVal)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("hif_drv NULL\n");
@@ -3937,123 +3741,30 @@ s32 hif_set_cfg(struct host_if_drv *hif_drv,
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_CFG_PARAMS;
msg.body.cfg_info.cfg_attr_info = *pstrCfgParamVal;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
return result;
}
-s32 hif_get_cfg(struct host_if_drv *hif_drv, u16 u16WID, u16 *pu16WID_Value)
-{
- s32 result = 0;
-
- down(&hif_drv->gtOsCfgValuesSem);
-
- if (!hif_drv) {
- PRINT_ER("hif_drv NULL\n");
- return -EFAULT;
- }
- PRINT_D(HOSTINF_DBG, "Getting configuration parameters\n");
- switch (u16WID) {
- case WID_BSS_TYPE:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.bss_type;
- break;
-
- case WID_AUTH_TYPE:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.auth_type;
- break;
-
- case WID_AUTH_TIMEOUT:
- *pu16WID_Value = hif_drv->strCfgValues.auth_timeout;
- break;
-
- case WID_POWER_MANAGEMENT:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.power_mgmt_mode;
- break;
-
- case WID_SHORT_RETRY_LIMIT:
- *pu16WID_Value = hif_drv->strCfgValues.short_retry_limit;
- break;
-
- case WID_LONG_RETRY_LIMIT:
- *pu16WID_Value = hif_drv->strCfgValues.long_retry_limit;
- break;
-
- case WID_FRAG_THRESHOLD:
- *pu16WID_Value = hif_drv->strCfgValues.frag_threshold;
- break;
-
- case WID_RTS_THRESHOLD:
- *pu16WID_Value = hif_drv->strCfgValues.rts_threshold;
- break;
-
- case WID_PREAMBLE:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.preamble_type;
- break;
-
- case WID_SHORT_SLOT_ALLOWED:
- *pu16WID_Value = (u16) hif_drv->strCfgValues.short_slot_allowed;
- break;
-
- case WID_11N_TXOP_PROT_DISABLE:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.txop_prot_disabled;
- break;
-
- case WID_BEACON_INTERVAL:
- *pu16WID_Value = hif_drv->strCfgValues.beacon_interval;
- break;
-
- case WID_DTIM_PERIOD:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.dtim_period;
- break;
-
- case WID_SITE_SURVEY:
- *pu16WID_Value = (u16)hif_drv->strCfgValues.site_survey_enabled;
- break;
-
- case WID_SITE_SURVEY_SCAN_TIME:
- *pu16WID_Value = hif_drv->strCfgValues.site_survey_scan_time;
- break;
-
- case WID_ACTIVE_SCAN_TIME:
- *pu16WID_Value = hif_drv->strCfgValues.active_scan_time;
- break;
-
- case WID_PASSIVE_SCAN_TIME:
- *pu16WID_Value = hif_drv->strCfgValues.passive_scan_time;
- break;
-
- case WID_CURRENT_TX_RATE:
- *pu16WID_Value = hif_drv->strCfgValues.curr_tx_rate;
- break;
-
- default:
- break;
- }
-
- up(&hif_drv->gtOsCfgValuesSem);
-
- return result;
-}
-
static void GetPeriodicRSSI(unsigned long arg)
{
- struct host_if_drv *hif_drv = (struct host_if_drv *)arg;
+ struct wilc_vif *vif = (struct wilc_vif *)arg;
- if (!hif_drv) {
+ if (!vif->hif_drv) {
PRINT_ER("Driver handler is NULL\n");
return;
}
- if (hif_drv->enuHostIFstate == HOST_IF_CONNECTED) {
+ if (vif->hif_drv->hif_state == HOST_IF_CONNECTED) {
s32 result = 0;
struct host_if_msg msg;
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_GET_RSSI;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result) {
@@ -4061,20 +3772,20 @@ static void GetPeriodicRSSI(unsigned long arg)
return;
}
}
- periodic_rssi.data = (unsigned long)hif_drv;
+ periodic_rssi.data = (unsigned long)vif;
mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
}
-s32 host_int_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
+s32 wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
{
s32 result = 0;
struct host_if_drv *hif_drv;
- int err;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
+ int i;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
PRINT_D(HOSTINF_DBG, "Initializing host interface for client %d\n", clients_count + 1);
@@ -4088,13 +3799,13 @@ s32 host_int_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
goto _fail_;
}
*hif_drv_handler = hif_drv;
- err = add_handler_in_list(hif_drv);
- if (err) {
- result = -EFAULT;
- goto _fail_timer_2;
- }
+ for (i = 0; i < wilc->vif_num; i++)
+ if (dev == wilc->vif[i]->ndev) {
+ wilc->vif[i]->hif_drv = hif_drv;
+ break;
+ }
- g_obtainingIP = false;
+ wilc_optaining_ip = false;
PRINT_D(HOSTINF_DBG, "Global handle pointer value=%p\n", hif_drv);
if (clients_count == 0) {
@@ -4103,12 +3814,12 @@ s32 host_int_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
sema_init(&hif_sema_deinit, 1);
}
- sema_init(&hif_drv->hSemTestKeyBlock, 0);
- sema_init(&hif_drv->hSemTestDisconnectBlock, 0);
- sema_init(&hif_drv->hSemGetRSSI, 0);
- sema_init(&hif_drv->hSemGetLINKSPEED, 0);
- sema_init(&hif_drv->hSemGetCHNL, 0);
- sema_init(&hif_drv->hSemInactiveTime, 0);
+ sema_init(&hif_drv->sem_test_key_block, 0);
+ sema_init(&hif_drv->sem_test_disconn_block, 0);
+ sema_init(&hif_drv->sem_get_rssi, 0);
+ sema_init(&hif_drv->sem_get_link_speed, 0);
+ sema_init(&hif_drv->sem_get_chnl, 0);
+ sema_init(&hif_drv->sem_inactive_time, 0);
PRINT_D(HOSTINF_DBG, "INIT: CLIENT COUNT %d\n", clients_count);
@@ -4129,56 +3840,50 @@ s32 host_int_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
goto _fail_mq_;
}
setup_timer(&periodic_rssi, GetPeriodicRSSI,
- (unsigned long)hif_drv);
+ (unsigned long)vif);
mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
}
- setup_timer(&hif_drv->hScanTimer, TimerCB_Scan, 0);
-
- setup_timer(&hif_drv->hConnectTimer, TimerCB_Connect, 0);
+ setup_timer(&hif_drv->scan_timer, TimerCB_Scan, 0);
+ setup_timer(&hif_drv->connect_timer, TimerCB_Connect, 0);
+ setup_timer(&hif_drv->remain_on_ch_timer, ListenTimerCB, 0);
- setup_timer(&hif_drv->hRemainOnChannel, ListenTimerCB, 0);
+ sema_init(&hif_drv->sem_cfg_values, 1);
+ down(&hif_drv->sem_cfg_values);
- sema_init(&hif_drv->gtOsCfgValuesSem, 1);
- down(&hif_drv->gtOsCfgValuesSem);
+ hif_drv->hif_state = HOST_IF_IDLE;
+ hif_drv->cfg_values.site_survey_enabled = SITE_SURVEY_OFF;
+ hif_drv->cfg_values.scan_source = DEFAULT_SCAN;
+ hif_drv->cfg_values.active_scan_time = ACTIVE_SCAN_TIME;
+ hif_drv->cfg_values.passive_scan_time = PASSIVE_SCAN_TIME;
+ hif_drv->cfg_values.curr_tx_rate = AUTORATE;
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
- hif_drv->strCfgValues.site_survey_enabled = SITE_SURVEY_OFF;
- hif_drv->strCfgValues.scan_source = DEFAULT_SCAN;
- hif_drv->strCfgValues.active_scan_time = ACTIVE_SCAN_TIME;
- hif_drv->strCfgValues.passive_scan_time = PASSIVE_SCAN_TIME;
- hif_drv->strCfgValues.curr_tx_rate = AUTORATE;
-
- hif_drv->u64P2p_MgmtTimeout = 0;
+ hif_drv->p2p_timeout = 0;
PRINT_INFO(HOSTINF_DBG, "Initialization values, Site survey value: %d\n Scan source: %d\n Active scan time: %d\n Passive scan time: %d\nCurrent tx Rate = %d\n",
+ hif_drv->cfg_values.site_survey_enabled,
+ hif_drv->cfg_values.scan_source,
+ hif_drv->cfg_values.active_scan_time,
+ hif_drv->cfg_values.passive_scan_time,
+ hif_drv->cfg_values.curr_tx_rate);
- hif_drv->strCfgValues.site_survey_enabled, hif_drv->strCfgValues.scan_source,
- hif_drv->strCfgValues.active_scan_time, hif_drv->strCfgValues.passive_scan_time,
- hif_drv->strCfgValues.curr_tx_rate);
-
- up(&hif_drv->gtOsCfgValuesSem);
+ up(&hif_drv->sem_cfg_values);
clients_count++;
return result;
-_fail_timer_2:
- up(&hif_drv->gtOsCfgValuesSem);
- del_timer_sync(&hif_drv->hConnectTimer);
- del_timer_sync(&hif_drv->hScanTimer);
- kthread_stop(hif_thread_handler);
_fail_mq_:
wilc_mq_destroy(&hif_msg_q);
_fail_:
return result;
}
-s32 host_int_deinit(struct host_if_drv *hif_drv)
+s32 wilc_deinit(struct wilc_vif *vif)
{
s32 result = 0;
struct host_if_msg msg;
- int ret;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("hif_drv = NULL\n");
@@ -4190,28 +3895,27 @@ s32 host_int_deinit(struct host_if_drv *hif_drv)
terminated_handle = hif_drv;
PRINT_D(HOSTINF_DBG, "De-initializing host interface for client %d\n", clients_count);
- if (del_timer_sync(&hif_drv->hScanTimer))
+ if (del_timer_sync(&hif_drv->scan_timer))
PRINT_D(HOSTINF_DBG, ">> Scan timer is active\n");
- if (del_timer_sync(&hif_drv->hConnectTimer))
+ if (del_timer_sync(&hif_drv->connect_timer))
PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n");
if (del_timer_sync(&periodic_rssi))
PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n");
- del_timer_sync(&hif_drv->hRemainOnChannel);
+ del_timer_sync(&hif_drv->remain_on_ch_timer);
- host_int_set_wfi_drv_handler(NULL);
+ wilc_set_wfi_drv_handler(vif, 0);
down(&hif_sema_driver);
- if (hif_drv->usr_scan_req.pfUserScanResult) {
- hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_ABORTED, NULL,
- hif_drv->usr_scan_req.u32UserScanPvoid, NULL);
-
- hif_drv->usr_scan_req.pfUserScanResult = NULL;
+ if (hif_drv->usr_scan_req.scan_result) {
+ hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
+ hif_drv->usr_scan_req.arg, NULL);
+ hif_drv->usr_scan_req.scan_result = NULL;
}
- hif_drv->enuHostIFstate = HOST_IF_IDLE;
+ hif_drv->hif_state = HOST_IF_IDLE;
scan_while_connected = false;
@@ -4222,7 +3926,7 @@ s32 host_int_deinit(struct host_if_drv *hif_drv)
PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n");
msg.id = HOST_IF_MSG_EXIT;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result != 0)
@@ -4233,12 +3937,6 @@ s32 host_int_deinit(struct host_if_drv *hif_drv)
wilc_mq_destroy(&hif_msg_q);
}
- down(&hif_drv->gtOsCfgValuesSem);
-
- ret = remove_handler_in_list(hif_drv);
- if (ret)
- result = -ENOENT;
-
kfree(hif_drv);
clients_count--;
@@ -4247,15 +3945,20 @@ s32 host_int_deinit(struct host_if_drv *hif_drv)
return result;
}
-void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length)
+void wilc_network_info_received(struct wilc *wilc, u8 *pu8Buffer,
+ u32 u32Length)
{
s32 result = 0;
struct host_if_msg msg;
int id;
struct host_if_drv *hif_drv = NULL;
+ struct wilc_vif *vif;
id = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24));
- hif_drv = get_handler_from_id(id);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
if (!hif_drv || hif_drv == terminated_handle) {
PRINT_ER("NetworkInfo received but driver not init[%p]\n", hif_drv);
@@ -4265,7 +3968,7 @@ void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length)
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_RCVD_NTWRK_INFO;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.net_info.len = u32Length;
msg.body.net_info.buffer = kmalloc(u32Length, GFP_KERNEL);
@@ -4276,17 +3979,25 @@ void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length)
PRINT_ER("Error in sending network info message queue message parameters: Error(%d)\n", result);
}
-void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length)
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *pu8Buffer,
+ u32 u32Length)
{
s32 result = 0;
struct host_if_msg msg;
int id;
struct host_if_drv *hif_drv = NULL;
+ struct wilc_vif *vif;
down(&hif_sema_deinit);
id = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24));
- hif_drv = get_handler_from_id(id);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif) {
+ up(&hif_sema_deinit);
+ return;
+ }
+
+ hif_drv = vif->hif_drv;
PRINT_D(HOSTINF_DBG, "General asynchronous info packet received\n");
if (!hif_drv || hif_drv == terminated_handle) {
@@ -4295,7 +4006,7 @@ void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length)
return;
}
- if (!hif_drv->usr_conn_req.pfUserConnectResult) {
+ if (!hif_drv->usr_conn_req.conn_result) {
PRINT_ER("Received mac status is not needed when there is no current Connect Reques\n");
up(&hif_sema_deinit);
return;
@@ -4304,7 +4015,7 @@ void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length)
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.async_info.len = u32Length;
msg.body.async_info.buffer = kmalloc(u32Length, GFP_KERNEL);
@@ -4317,26 +4028,31 @@ void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length)
up(&hif_sema_deinit);
}
-void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length)
+void wilc_scan_complete_received(struct wilc *wilc, u8 *pu8Buffer,
+ u32 u32Length)
{
s32 result = 0;
struct host_if_msg msg;
int id;
struct host_if_drv *hif_drv = NULL;
+ struct wilc_vif *vif;
id = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24));
- hif_drv = get_handler_from_id(id);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
PRINT_D(GENERIC_DBG, "Scan notification received %p\n", hif_drv);
if (!hif_drv || hif_drv == terminated_handle)
return;
- if (hif_drv->usr_scan_req.pfUserScanResult) {
+ if (hif_drv->usr_scan_req.scan_result) {
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_RCVD_SCAN_COMPLETE;
- msg.drv = hif_drv;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -4346,14 +4062,15 @@ void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length)
return;
}
-s32 host_int_remain_on_channel(struct host_if_drv *hif_drv, u32 u32SessionID,
- u32 u32duration, u16 chan,
- wilc_remain_on_chan_expired RemainOnChanExpired,
- wilc_remain_on_chan_ready RemainOnChanReady,
- void *pvUserArg)
+s32 wilc_remain_on_channel(struct wilc_vif *vif, u32 u32SessionID,
+ u32 u32duration, u16 chan,
+ wilc_remain_on_chan_expired RemainOnChanExpired,
+ wilc_remain_on_chan_ready RemainOnChanReady,
+ void *pvUserArg)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4363,13 +4080,13 @@ s32 host_int_remain_on_channel(struct host_if_drv *hif_drv, u32 u32SessionID,
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_REMAIN_ON_CHAN;
- msg.body.remain_on_ch.u16Channel = chan;
- msg.body.remain_on_ch.pRemainOnChanExpired = RemainOnChanExpired;
- msg.body.remain_on_ch.pRemainOnChanReady = RemainOnChanReady;
- msg.body.remain_on_ch.pVoid = pvUserArg;
+ msg.body.remain_on_ch.ch = chan;
+ msg.body.remain_on_ch.expired = RemainOnChanExpired;
+ msg.body.remain_on_ch.ready = RemainOnChanReady;
+ msg.body.remain_on_ch.arg = pvUserArg;
msg.body.remain_on_ch.u32duration = u32duration;
- msg.body.remain_on_ch.u32ListenSessionID = u32SessionID;
- msg.drv = hif_drv;
+ msg.body.remain_on_ch.id = u32SessionID;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -4378,22 +4095,23 @@ s32 host_int_remain_on_channel(struct host_if_drv *hif_drv, u32 u32SessionID,
return result;
}
-s32 host_int_ListenStateExpired(struct host_if_drv *hif_drv, u32 u32SessionID)
+s32 wilc_listen_state_expired(struct wilc_vif *vif, u32 u32SessionID)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
return -EFAULT;
}
- del_timer(&hif_drv->hRemainOnChannel);
+ del_timer(&hif_drv->remain_on_ch_timer);
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_LISTEN_TIMER_FIRED;
- msg.drv = hif_drv;
- msg.body.remain_on_ch.u32ListenSessionID = u32SessionID;
+ msg.vif = vif;
+ msg.body.remain_on_ch.id = u32SessionID;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -4402,10 +4120,11 @@ s32 host_int_ListenStateExpired(struct host_if_drv *hif_drv, u32 u32SessionID)
return result;
}
-s32 host_int_frame_register(struct host_if_drv *hif_drv, u16 u16FrameType, bool bReg)
+s32 wilc_frame_register(struct wilc_vif *vif, u16 u16FrameType, bool bReg)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4418,21 +4137,21 @@ s32 host_int_frame_register(struct host_if_drv *hif_drv, u16 u16FrameType, bool
switch (u16FrameType) {
case ACTION:
PRINT_D(HOSTINF_DBG, "ACTION\n");
- msg.body.reg_frame.u8Regid = ACTION_FRM_IDX;
+ msg.body.reg_frame.reg_id = ACTION_FRM_IDX;
break;
case PROBE_REQ:
PRINT_D(HOSTINF_DBG, "PROBE REQ\n");
- msg.body.reg_frame.u8Regid = PROBE_REQ_IDX;
+ msg.body.reg_frame.reg_id = PROBE_REQ_IDX;
break;
default:
PRINT_D(HOSTINF_DBG, "Not valid frame type\n");
break;
}
- msg.body.reg_frame.u16FrameType = u16FrameType;
- msg.body.reg_frame.bReg = bReg;
- msg.drv = hif_drv;
+ msg.body.reg_frame.frame_type = u16FrameType;
+ msg.body.reg_frame.reg = bReg;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -4441,13 +4160,13 @@ s32 host_int_frame_register(struct host_if_drv *hif_drv, u16 u16FrameType, bool
return result;
}
-s32 host_int_add_beacon(struct host_if_drv *hif_drv, u32 u32Interval,
- u32 u32DTIMPeriod, u32 u32HeadLen, u8 *pu8Head,
- u32 u32TailLen, u8 *pu8Tail)
+s32 wilc_add_beacon(struct wilc_vif *vif, u32 u32Interval, u32 u32DTIMPeriod,
+ u32 u32HeadLen, u8 *pu8Head, u32 u32TailLen, u8 *pu8Tail)
{
s32 result = 0;
struct host_if_msg msg;
struct beacon_attr *pstrSetBeaconParam = &msg.body.beacon_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4459,7 +4178,7 @@ s32 host_int_add_beacon(struct host_if_drv *hif_drv, u32 u32Interval,
PRINT_D(HOSTINF_DBG, "Setting adding beacon message queue params\n");
msg.id = HOST_IF_MSG_ADD_BEACON;
- msg.drv = hif_drv;
+ msg.vif = vif;
pstrSetBeaconParam->interval = u32Interval;
pstrSetBeaconParam->dtim_period = u32DTIMPeriod;
pstrSetBeaconParam->head_len = u32HeadLen;
@@ -4495,10 +4214,11 @@ ERRORHANDLER:
return result;
}
-s32 host_int_del_beacon(struct host_if_drv *hif_drv)
+int wilc_del_beacon(struct wilc_vif *vif)
{
- s32 result = 0;
+ int result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4506,7 +4226,7 @@ s32 host_int_del_beacon(struct host_if_drv *hif_drv)
}
msg.id = HOST_IF_MSG_DEL_BEACON;
- msg.drv = hif_drv;
+ msg.vif = vif;
PRINT_D(HOSTINF_DBG, "Setting deleting beacon message queue params\n");
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
@@ -4516,12 +4236,12 @@ s32 host_int_del_beacon(struct host_if_drv *hif_drv)
return result;
}
-s32 host_int_add_station(struct host_if_drv *hif_drv,
- struct add_sta_param *pstrStaParams)
+int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param)
{
- s32 result = 0;
+ int result = 0;
struct host_if_msg msg;
- struct add_sta_param *pstrAddStationMsg = &msg.body.add_sta_info;
+ struct add_sta_param *add_sta_info = &msg.body.add_sta_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4533,17 +4253,15 @@ s32 host_int_add_station(struct host_if_drv *hif_drv,
PRINT_D(HOSTINF_DBG, "Setting adding station message queue params\n");
msg.id = HOST_IF_MSG_ADD_STATION;
- msg.drv = hif_drv;
-
- memcpy(pstrAddStationMsg, pstrStaParams, sizeof(struct add_sta_param));
- if (pstrAddStationMsg->u8NumRates > 0) {
- u8 *rates = kmalloc(pstrAddStationMsg->u8NumRates, GFP_KERNEL);
-
- if (!rates)
+ msg.vif = vif;
+
+ memcpy(add_sta_info, sta_param, sizeof(struct add_sta_param));
+ if (add_sta_info->rates_len > 0) {
+ add_sta_info->rates = kmemdup(sta_param->rates,
+ add_sta_info->rates_len,
+ GFP_KERNEL);
+ if (!add_sta_info->rates)
return -ENOMEM;
-
- memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates);
- pstrAddStationMsg->pu8Rates = rates;
}
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
@@ -4552,11 +4270,12 @@ s32 host_int_add_station(struct host_if_drv *hif_drv,
return result;
}
-s32 host_int_del_station(struct host_if_drv *hif_drv, const u8 *pu8MacAddr)
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
{
- s32 result = 0;
+ int result = 0;
struct host_if_msg msg;
- struct del_sta *pstrDelStationMsg = &msg.body.del_sta_info;
+ struct del_sta *del_sta_info = &msg.body.del_sta_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4568,12 +4287,12 @@ s32 host_int_del_station(struct host_if_drv *hif_drv, const u8 *pu8MacAddr)
PRINT_D(HOSTINF_DBG, "Setting deleting station message queue params\n");
msg.id = HOST_IF_MSG_DEL_STATION;
- msg.drv = hif_drv;
+ msg.vif = vif;
- if (!pu8MacAddr)
- eth_broadcast_addr(pstrDelStationMsg->mac_addr);
+ if (!mac_addr)
+ eth_broadcast_addr(del_sta_info->mac_addr);
else
- memcpy(pstrDelStationMsg->mac_addr, pu8MacAddr, ETH_ALEN);
+ memcpy(del_sta_info->mac_addr, mac_addr, ETH_ALEN);
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -4581,12 +4300,12 @@ s32 host_int_del_station(struct host_if_drv *hif_drv, const u8 *pu8MacAddr)
return result;
}
-s32 host_int_del_allstation(struct host_if_drv *hif_drv,
- u8 pu8MacAddr[][ETH_ALEN])
+s32 wilc_del_allstation(struct wilc_vif *vif, u8 pu8MacAddr[][ETH_ALEN])
{
s32 result = 0;
struct host_if_msg msg;
struct del_all_sta *pstrDelAllStationMsg = &msg.body.del_all_sta_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
u8 au8Zero_Buff[ETH_ALEN] = {0};
u32 i;
u8 u8AssocNumb = 0;
@@ -4601,7 +4320,7 @@ s32 host_int_del_allstation(struct host_if_drv *hif_drv,
PRINT_D(HOSTINF_DBG, "Setting deauthenticating station message queue params\n");
msg.id = HOST_IF_MSG_DEL_ALL_STA;
- msg.drv = hif_drv;
+ msg.vif = vif;
for (i = 0; i < MAX_NUM_STA; i++) {
if (memcmp(pu8MacAddr[i], au8Zero_Buff, ETH_ALEN)) {
@@ -4632,12 +4351,13 @@ s32 host_int_del_allstation(struct host_if_drv *hif_drv,
return result;
}
-s32 host_int_edit_station(struct host_if_drv *hif_drv,
- struct add_sta_param *pstrStaParams)
+s32 wilc_edit_station(struct wilc_vif *vif,
+ struct add_sta_param *pstrStaParams)
{
s32 result = 0;
struct host_if_msg msg;
struct add_sta_param *pstrAddStationMsg = &msg.body.add_sta_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4649,17 +4369,18 @@ s32 host_int_edit_station(struct host_if_drv *hif_drv,
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_EDIT_STATION;
- msg.drv = hif_drv;
+ msg.vif = vif;
memcpy(pstrAddStationMsg, pstrStaParams, sizeof(struct add_sta_param));
- if (pstrAddStationMsg->u8NumRates > 0) {
- u8 *rates = kmalloc(pstrAddStationMsg->u8NumRates, GFP_KERNEL);
+ if (pstrAddStationMsg->rates_len > 0) {
+ u8 *rates = kmalloc(pstrAddStationMsg->rates_len, GFP_KERNEL);
if (!rates)
return -ENOMEM;
- memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates);
- pstrAddStationMsg->pu8Rates = rates;
+ memcpy(rates, pstrStaParams->rates,
+ pstrAddStationMsg->rates_len);
+ pstrAddStationMsg->rates = rates;
}
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
@@ -4669,13 +4390,12 @@ s32 host_int_edit_station(struct host_if_drv *hif_drv,
return result;
}
-s32 host_int_set_power_mgmt(struct host_if_drv *hif_drv,
- bool bIsEnabled,
- u32 u32Timeout)
+s32 wilc_set_power_mgmt(struct wilc_vif *vif, bool bIsEnabled, u32 u32Timeout)
{
s32 result = 0;
struct host_if_msg msg;
struct power_mgmt_param *pstrPowerMgmtParam = &msg.body.pwr_mgmt_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
PRINT_INFO(HOSTINF_DBG, "\n\n>> Setting PS to %d <<\n\n", bIsEnabled);
@@ -4689,7 +4409,7 @@ s32 host_int_set_power_mgmt(struct host_if_drv *hif_drv,
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_POWER_MGMT;
- msg.drv = hif_drv;
+ msg.vif = vif;
pstrPowerMgmtParam->enabled = bIsEnabled;
pstrPowerMgmtParam->timeout = u32Timeout;
@@ -4700,13 +4420,13 @@ s32 host_int_set_power_mgmt(struct host_if_drv *hif_drv,
return result;
}
-s32 host_int_setup_multicast_filter(struct host_if_drv *hif_drv,
- bool bIsEnabled,
- u32 u32count)
+s32 wilc_setup_multicast_filter(struct wilc_vif *vif, bool bIsEnabled,
+ u32 u32count)
{
s32 result = 0;
struct host_if_msg msg;
struct set_multicast *pstrMulticastFilterParam = &msg.body.multicast_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4718,7 +4438,7 @@ s32 host_int_setup_multicast_filter(struct host_if_drv *hif_drv,
memset(&msg, 0, sizeof(struct host_if_msg));
msg.id = HOST_IF_MSG_SET_MULTICAST_FILTER;
- msg.drv = hif_drv;
+ msg.vif = vif;
pstrMulticastFilterParam->enabled = bIsEnabled;
pstrMulticastFilterParam->cnt = u32count;
@@ -4886,7 +4606,7 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo)
return (void *)pNewJoinBssParam;
}
-void host_int_freeJoinParams(void *pJoinParams)
+void wilc_free_join_params(void *pJoinParams)
{
if ((struct bss_param *)pJoinParams)
kfree((struct bss_param *)pJoinParams);
@@ -4894,41 +4614,12 @@ void host_int_freeJoinParams(void *pJoinParams)
PRINT_ER("Unable to FREE null pointer\n");
}
-s32 host_int_delBASession(struct host_if_drv *hif_drv, char *pBSSID, char TID)
-{
- s32 result = 0;
- struct host_if_msg msg;
- struct ba_session_info *pBASessionInfo = &msg.body.session_info;
-
- if (!hif_drv) {
- PRINT_ER("driver is null\n");
- return -EFAULT;
- }
-
- memset(&msg, 0, sizeof(struct host_if_msg));
-
- msg.id = HOST_IF_MSG_DEL_BA_SESSION;
-
- memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN);
- pBASessionInfo->u8Ted = TID;
- msg.drv = hif_drv;
-
- result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
- if (result)
- PRINT_ER("wilc_mq_send fail\n");
-
- down(&hif_sema_wait_response);
-
- return result;
-}
-
-s32 host_int_del_All_Rx_BASession(struct host_if_drv *hif_drv,
- char *pBSSID,
- char TID)
+s32 wilc_del_all_rx_ba_session(struct wilc_vif *vif, char *pBSSID, char TID)
{
s32 result = 0;
struct host_if_msg msg;
struct ba_session_info *pBASessionInfo = &msg.body.session_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
PRINT_ER("driver is null\n");
@@ -4939,9 +4630,9 @@ s32 host_int_del_All_Rx_BASession(struct host_if_drv *hif_drv,
msg.id = HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS;
- memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN);
- pBASessionInfo->u8Ted = TID;
- msg.drv = hif_drv;
+ memcpy(pBASessionInfo->bssid, pBSSID, ETH_ALEN);
+ pBASessionInfo->tid = TID;
+ msg.vif = vif;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
if (result)
@@ -4952,10 +4643,11 @@ s32 host_int_del_All_Rx_BASession(struct host_if_drv *hif_drv,
return result;
}
-s32 host_int_setup_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx)
+s32 wilc_setup_ipaddress(struct wilc_vif *vif, u8 *u16ipadd, u8 idx)
{
s32 result = 0;
struct host_if_msg msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
return 0;
@@ -4969,7 +4661,7 @@ s32 host_int_setup_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx)
msg.id = HOST_IF_MSG_SET_IPADDRESS;
msg.body.ip_info.ip_addr = u16ipadd;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.ip_info.idx = idx;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
@@ -4979,7 +4671,9 @@ s32 host_int_setup_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx)
return result;
}
-s32 host_int_get_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx)
+static s32 host_int_get_ipaddress(struct wilc_vif *vif,
+ struct host_if_drv *hif_drv,
+ u8 *u16ipadd, u8 idx)
{
s32 result = 0;
struct host_if_msg msg;
@@ -4994,7 +4688,7 @@ s32 host_int_get_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx)
msg.id = HOST_IF_MSG_GET_IPADDRESS;
msg.body.ip_info.ip_addr = u16ipadd;
- msg.drv = hif_drv;
+ msg.vif = vif;
msg.body.ip_info.idx = idx;
result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg));
diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h
index b854db5ac932..8faac27002e9 100644
--- a/drivers/staging/wilc1000/host_interface.h
+++ b/drivers/staging/wilc1000/host_interface.h
@@ -1,12 +1,3 @@
-/*!
- * @file host_interface.h
- * @brief File containg host interface APIs
- * @author zsalah
- * @sa host_interface.c
- * @date 8 March 2012
- * @version 1.0
- */
-
#ifndef HOST_INT_H
#define HOST_INT_H
@@ -19,8 +10,12 @@
#define STATION_MODE 0x02
#define GO_MODE 0x03
#define CLIENT_MODE 0x04
+#define ACTION 0xD0
+#define PROBE_REQ 0x40
+#define PROBE_RESP 0x50
-
+#define ACTION_FRM_IDX 0
+#define PROBE_REQ_IDX 1
#define MAX_NUM_STA 9
#define ACTIVE_SCAN_TIME 10
#define PASSIVE_SCAN_TIME 1200
@@ -58,11 +53,11 @@
#define NUM_CONCURRENT_IFC 2
struct rf_info {
- u8 u8LinkSpeed;
- s8 s8RSSI;
- u32 u32TxCount;
- u32 u32RxCount;
- u32 u32TxFailureCount;
+ u8 link_speed;
+ s8 rssi;
+ u32 tx_cnt;
+ u32 rx_cnt;
+ u32 tx_fail_cnt;
};
enum host_if_state {
@@ -168,36 +163,23 @@ enum conn_event {
enum KEY_TYPE {
WEP,
- WPARxGtk,
- WPAPtk,
+ WPA_RX_GTK,
+ WPA_PTK,
PMKSA,
};
-
-/*Scan callBack function definition*/
typedef void (*wilc_scan_result)(enum scan_event, tstrNetworkInfo *,
void *, void *);
-/*Connect callBack function definition*/
typedef void (*wilc_connect_result)(enum conn_event,
tstrConnectInfo *,
u8,
tstrDisconnectNotifInfo *,
void *);
-typedef void (*wilc_remain_on_chan_expired)(void *, u32); /*Remain on channel expiration callback function*/
-typedef void (*wilc_remain_on_chan_ready)(void *); /*Remain on channel callback function*/
+typedef void (*wilc_remain_on_chan_expired)(void *, u32);
+typedef void (*wilc_remain_on_chan_ready)(void *);
-/*!
- * @struct rcvd_net_info
- * @brief Structure to hold Received Asynchronous Network info
- * @details
- * @todo
- * @sa
- * @author Mostafa Abu Bakr
- * @date 25 March 2012
- * @version 1.0
- */
struct rcvd_net_info {
u8 *buffer;
u32 len;
@@ -214,29 +196,23 @@ struct hidden_network {
};
struct user_scan_req {
- /* Scan user call back function */
- wilc_scan_result pfUserScanResult;
-
- /* User specific parameter to be delivered through the Scan User Callback function */
- void *u32UserScanPvoid;
-
- u32 u32RcvdChCount;
- struct found_net_info astrFoundNetworkInfo[MAX_NUM_SCANNED_NETWORKS];
+ wilc_scan_result scan_result;
+ void *arg;
+ u32 rcvd_ch_cnt;
+ struct found_net_info net_info[MAX_NUM_SCANNED_NETWORKS];
};
struct user_conn_req {
u8 *pu8bssid;
u8 *pu8ssid;
u8 u8security;
- enum AUTHTYPE tenuAuth_type;
- size_t ssidLen;
- u8 *pu8ConnReqIEs;
- size_t ConnReqIEsLen;
- /* Connect user call back function */
- wilc_connect_result pfUserConnectResult;
- bool IsHTCapable;
- /* User specific parameter to be delivered through the Connect User Callback function */
- void *u32UserConnectPvoid;
+ enum AUTHTYPE auth_type;
+ size_t ssid_len;
+ u8 *ies;
+ size_t ies_len;
+ wilc_connect_result conn_result;
+ bool ht_capable;
+ void *arg;
};
struct drv_handler {
@@ -256,875 +232,155 @@ struct get_mac_addr {
};
struct ba_session_info {
- u8 au8Bssid[ETH_ALEN];
- u8 u8Ted;
- u16 u16BufferSize;
- u16 u16SessionTimeout;
+ u8 bssid[ETH_ALEN];
+ u8 tid;
+ u16 buf_size;
+ u16 time_out;
};
struct remain_ch {
- u16 u16Channel;
+ u16 ch;
u32 u32duration;
- wilc_remain_on_chan_expired pRemainOnChanExpired;
- wilc_remain_on_chan_ready pRemainOnChanReady;
- void *pVoid;
- u32 u32ListenSessionID;
+ wilc_remain_on_chan_expired expired;
+ wilc_remain_on_chan_ready ready;
+ void *arg;
+ u32 id;
};
struct reg_frame {
- bool bReg;
- u16 u16FrameType;
- u8 u8Regid;
+ bool reg;
+ u16 frame_type;
+ u8 reg_id;
};
-
-#define ACTION 0xD0
-#define PROBE_REQ 0x40
-#define PROBE_RESP 0x50
-#define ACTION_FRM_IDX 0
-#define PROBE_REQ_IDX 1
-
-
enum p2p_listen_state {
P2P_IDLE,
P2P_LISTEN,
P2P_GRP_FORMATION
};
+struct wilc;
struct host_if_drv {
struct user_scan_req usr_scan_req;
struct user_conn_req usr_conn_req;
struct remain_ch remain_on_ch;
u8 remain_on_ch_pending;
- u64 u64P2p_MgmtTimeout;
- u8 u8P2PConnect;
+ u64 p2p_timeout;
+ u8 p2p_connect;
+
+ enum host_if_state hif_state;
- enum host_if_state enuHostIFstate;
+ u8 assoc_bssid[ETH_ALEN];
+ struct cfg_param_val cfg_values;
- u8 au8AssociatedBSSID[ETH_ALEN];
- struct cfg_param_val strCfgValues;
-/* semaphores */
- struct semaphore gtOsCfgValuesSem;
- struct semaphore hSemTestKeyBlock;
+ struct semaphore sem_cfg_values;
+ struct semaphore sem_test_key_block;
+ struct semaphore sem_test_disconn_block;
+ struct semaphore sem_get_rssi;
+ struct semaphore sem_get_link_speed;
+ struct semaphore sem_get_chnl;
+ struct semaphore sem_inactive_time;
- struct semaphore hSemTestDisconnectBlock;
- struct semaphore hSemGetRSSI;
- struct semaphore hSemGetLINKSPEED;
- struct semaphore hSemGetCHNL;
- struct semaphore hSemInactiveTime;
-/* timer handlers */
- struct timer_list hScanTimer;
- struct timer_list hConnectTimer;
- struct timer_list hRemainOnChannel;
+ struct timer_list scan_timer;
+ struct timer_list connect_timer;
+ struct timer_list remain_on_ch_timer;
bool IFC_UP;
};
struct add_sta_param {
- u8 au8BSSID[ETH_ALEN];
- u16 u16AssocID;
- u8 u8NumRates;
- const u8 *pu8Rates;
- bool bIsHTSupported;
- u16 u16HTCapInfo;
- u8 u8AmpduParams;
- u8 au8SuppMCsSet[16];
- u16 u16HTExtParams;
- u32 u32TxBeamformingCap;
- u8 u8ASELCap;
- u16 u16FlagsMask; /*<! Determines which of u16FlagsSet were changed>*/
- u16 u16FlagsSet; /*<! Decoded according to tenuWILC_StaFlag */
+ u8 bssid[ETH_ALEN];
+ u16 aid;
+ u8 rates_len;
+ const u8 *rates;
+ bool ht_supported;
+ u16 ht_capa_info;
+ u8 ht_ampdu_params;
+ u8 ht_supp_mcs_set[16];
+ u16 ht_ext_params;
+ u32 ht_tx_bf_cap;
+ u8 ht_ante_sel;
+ u16 flags_mask;
+ u16 flags_set;
};
-/*****************************************************************************/
-/* */
-/* Host Interface API */
-/* */
-/*****************************************************************************/
-
-/**
- * @brief removes wpa/wpa2 keys
- * @details only in BSS STA mode if External Supplicant support is enabled.
- * removes all WPA/WPA2 station key entries from MAC hardware.
- * @param[in,out] handle to the wifi driver
- * @param[in] 6 bytes of Station Adress in the station entry table
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_remove_key(struct host_if_drv *hWFIDrv, const u8 *pu8StaAddress);
-/**
- * @brief removes WEP key
- * @details valid only in BSS STA mode if External Supplicant support is enabled.
- * remove a WEP key entry from MAC HW.
- * The BSS Station automatically finds the index of the entry using its
- * BSS ID and removes that entry from the MAC hardware.
- * @param[in,out] handle to the wifi driver
- * @param[in] 6 bytes of Station Adress in the station entry table
- * @return Error code indicating success/failure
- * @note NO need for the STA add since it is not used for processing
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-int host_int_remove_wep_key(struct host_if_drv *wfi_drv, u8 index);
-/**
- * @brief sets WEP deafault key
- * @details Sets the index of the WEP encryption key in use,
- * in the key table
- * @param[in,out] handle to the wifi driver
- * @param[in] key index ( 0, 1, 2, 3)
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-int host_int_set_wep_default_key(struct host_if_drv *hif_drv, u8 index);
-
-/**
- * @brief sets WEP deafault key
- * @details valid only in BSS STA mode if External Supplicant support is enabled.
- * sets WEP key entry into MAC hardware when it receives the
- * corresponding request from NDIS.
- * @param[in,out] handle to the wifi driver
- * @param[in] message containing WEP Key in the following format
- *|---------------------------------------|
- *|Key ID Value | Key Length | Key |
- *|-------------|------------|------------|
- | 1byte | 1byte | Key Length |
- ||---------------------------------------|
- |
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-int host_int_add_wep_key_bss_sta(struct host_if_drv *hif_drv,
- const u8 *key, u8 len, u8 index);
-/**
- * @brief host_int_add_wep_key_bss_ap
- * @details valid only in AP mode if External Supplicant support is enabled.
- * sets WEP key entry into MAC hardware when it receives the
- * corresponding request from NDIS.
- * @param[in,out] handle to the wifi driver
- *
- *
- * @return Error code indicating success/failure
- * @note
- * @author mdaftedar
- * @date 28 Feb 2013
- * @version 1.0
- */
-int host_int_add_wep_key_bss_ap(struct host_if_drv *hif_drv,
- const u8 *key, u8 len, u8 index, u8 mode,
- enum AUTHTYPE auth_type);
-
-/**
- * @brief adds ptk Key
- * @details
- * @param[in,out] handle to the wifi driver
- * @param[in] message containing PTK Key in the following format
- *|-------------------------------------------------------------------------|
- *|Sta Adress | Key Length | Temporal Key | Rx Michael Key |Tx Michael Key |
- *|-----------|------------|---------------|----------------|---------------|
- | 6 bytes | 1byte | 16 bytes | 8 bytes | 8 bytes |
- ||-------------------------------------------------------------------------|
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_add_ptk(struct host_if_drv *hWFIDrv, const u8 *pu8Ptk, u8 u8PtkKeylen,
- const u8 *mac_addr, const u8 *pu8RxMic, const u8 *pu8TxMic, u8 mode, u8 u8Ciphermode, u8 u8Idx);
-
-/**
- * @brief host_int_get_inactive_time
- * @details
- * @param[in,out] handle to the wifi driver
- * @param[in] message containing inactive time
- *
- * @return Error code indicating success/failure
- * @note
- * @author mdaftedar
- * @date 15 April 2013
- * @version 1.0
- */
-s32 host_int_get_inactive_time(struct host_if_drv *hWFIDrv, const u8 *mac, u32 *pu32InactiveTime);
-
-/**
- * @brief adds Rx GTk Key
- * @details
- * @param[in,out] handle to the wifi driver
- * @param[in] message containing Rx GTK Key in the following format
- *|----------------------------------------------------------------------------|
- *|Sta Address | Key RSC | KeyID | Key Length | Temporal Key | Rx Michael Key |
- *|------------|---------|-------|------------|---------------|----------------|
- | 6 bytes | 8 byte |1 byte | 1 byte | 16 bytes | 8 bytes |
- ||----------------------------------------------------------------------------|
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_add_rx_gtk(struct host_if_drv *hWFIDrv, const u8 *pu8RxGtk, u8 u8GtkKeylen,
- u8 u8KeyIdx, u32 u32KeyRSClen, const u8 *KeyRSC,
- const u8 *pu8RxMic, const u8 *pu8TxMic, u8 mode, u8 u8Ciphermode);
-
-
-/**
- * @brief adds Tx GTk Key
- * @details
- * @param[in,out] handle to the wifi driver
- * @param[in] message containing Tx GTK Key in the following format
- *|----------------------------------------------------|
- | KeyID | Key Length | Temporal Key | Tx Michael Key |
- ||-------|------------|--------------|----------------|
- ||1 byte | 1 byte | 16 bytes | 8 bytes |
- ||----------------------------------------------------|
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_add_tx_gtk(struct host_if_drv *hWFIDrv, u8 u8KeyLen, u8 *pu8TxGtk, u8 u8KeyIdx);
-
-/**
- * @brief caches the pmkid
- * @details valid only in BSS STA mode if External Supplicant
- * support is enabled. This Function sets the PMKID in firmware
- * when host drivr receives the corresponding request from NDIS.
- * The firmware then includes theset PMKID in the appropriate
- * management frames
- * @param[in,out] handle to the wifi driver
- * @param[in] message containing PMKID Info in the following format
- *|-----------------------------------------------------------------|
- *|NumEntries | BSSID[1] | PMKID[1] | ... | BSSID[K] | PMKID[K] |
- *|-----------|------------|----------|-------|----------|----------|
- | 1 | 6 | 16 | ... | 6 | 16 |
- ||-----------------------------------------------------------------|
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-
-s32 host_int_set_pmkid_info(struct host_if_drv *hWFIDrv, struct host_if_pmkid_attr *pu8PmkidInfoArray);
-/**
- * @brief gets the cached the pmkid info
- * @details valid only in BSS STA mode if External Supplicant
- * support is enabled. This Function sets the PMKID in firmware
- * when host drivr receives the corresponding request from NDIS.
- * The firmware then includes theset PMKID in the appropriate
- * management frames
- * @param[in,out] handle to the wifi driver,
- *
- * message containing PMKID Info in the following format
- *|-----------------------------------------------------------------|
- *|NumEntries | BSSID[1] | PMKID[1] | ... | BSSID[K] | PMKID[K] |
- *|-----------|------------|----------|-------|----------|----------|
- | 1 | 6 | 16 | ... | 6 | 16 |
- ||-----------------------------------------------------------------|
- * @param[in]
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-
-s32 host_int_get_pmkid_info(struct host_if_drv *hWFIDrv, u8 *pu8PmkidInfoArray,
- u32 u32PmkidInfoLen);
-
-/**
- * @brief sets the pass phrase
- * @details AP/STA mode. This function gives the pass phrase used to
- * generate the Pre-Shared Key when WPA/WPA2 is enabled
- * The length of the field can vary from 8 to 64 bytes,
- * the lower layer should get the
- * @param[in,out] handle to the wifi driver,
- * @param[in] String containing PSK
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_set_RSNAConfigPSKPassPhrase(struct host_if_drv *hWFIDrv, u8 *pu8PassPhrase,
- u8 u8Psklength);
-/**
- * @brief gets the pass phrase
- * @details AP/STA mode. This function gets the pass phrase used to
- * generate the Pre-Shared Key when WPA/WPA2 is enabled
- * The length of the field can vary from 8 to 64 bytes,
- * the lower layer should get the
- * @param[in,out] handle to the wifi driver,
- * String containing PSK
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_get_RSNAConfigPSKPassPhrase(struct host_if_drv *hWFIDrv,
- u8 *pu8PassPhrase, u8 u8Psklength);
-
-/**
- * @brief gets mac address
- * @details
- * @param[in,out] handle to the wifi driver,
- *
- * @return Error code indicating success/failure
- * @note
- * @author mdaftedar
- * @date 19 April 2012
- * @version 1.0
- */
-s32 host_int_get_MacAddress(struct host_if_drv *hWFIDrv, u8 *pu8MacAddress);
-
-/**
- * @brief sets mac address
- * @details
- * @param[in,out] handle to the wifi driver,
- *
- * @return Error code indicating success/failure
- * @note
- * @author mabubakr
- * @date 16 July 2012
- * @version 1.0
- */
-s32 host_int_set_MacAddress(struct host_if_drv *hWFIDrv, u8 *pu8MacAddress);
-
-/**
- * @brief wait until msg q is empty
- * @details
- * @param[in,out]
- *
- * @return Error code indicating success/failure
- * @note
- * @author asobhy
- * @date 19 march 2014
- * @version 1.0
- */
-int host_int_wait_msg_queue_idle(void);
-
-/**
- * @brief sets a start scan request
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] Scan Source one of the following values
- * DEFAULT_SCAN 0
- * USER_SCAN BIT0
- * OBSS_PERIODIC_SCAN BIT1
- * OBSS_ONETIME_SCAN BIT2
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-
-s32 host_int_set_start_scan_req(struct host_if_drv *hWFIDrv, u8 scanSource);
-/**
- * @brief gets scan source of the last scan
- * @details
- * @param[in,out] handle to the wifi driver,
- * Scan Source one of the following values
- * DEFAULT_SCAN 0
- * USER_SCAN BIT0
- * OBSS_PERIODIC_SCAN BIT1
- * OBSS_ONETIME_SCAN BIT2
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_get_start_scan_req(struct host_if_drv *hWFIDrv, u8 *pu8ScanSource);
-
-/**
- * @brief sets a join request
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] Index of the bss descriptor
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-
-s32 host_int_set_join_req(struct host_if_drv *hWFIDrv, u8 *pu8bssid,
- const u8 *pu8ssid, size_t ssidLen,
- const u8 *pu8IEs, size_t IEsLen,
- wilc_connect_result pfConnectResult, void *pvUserArg,
- u8 u8security, enum AUTHTYPE tenuAuth_type,
- u8 u8channel,
- void *pJoinParams);
-
-/**
- * @brief Flush a join request parameters to FW, but actual connection
- * @details The function is called in situation where WILC is connected to AP and
- * required to switch to hybrid FW for P2P connection
- * @param[in] handle to the wifi driver,
- * @return Error code indicating success/failure
- * @note
- * @author Amr Abdel-Moghny
- * @date 19 DEC 2013
- * @version 8.0
- */
-
-s32 host_int_flush_join_req(struct host_if_drv *hWFIDrv);
-
-
-/**
- * @brief disconnects from the currently associated network
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] Reason Code of the Disconnection
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_disconnect(struct host_if_drv *hWFIDrv, u16 u16ReasonCode);
-
-/**
- * @brief disconnects a sta
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] Association Id of the station to be disconnected
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_disconnect_station(struct host_if_drv *hWFIDrv, u8 assoc_id);
-/**
- * @brief gets a Association request info
- * @details
- * @param[in,out] handle to the wifi driver,
- * Message containg assoc. req info in the following format
- * ------------------------------------------------------------------------
- | Management Frame Format |
- ||-------------------------------------------------------------------|
- ||Frame Control|Duration|DA|SA|BSSID|Sequence Control|Frame Body|FCS |
- ||-------------|--------|--|--|-----|----------------|----------|----|
- | 2 |2 |6 |6 |6 | 2 |0 - 2312 | 4 |
- ||-------------------------------------------------------------------|
- | |
- | Association Request Frame - Frame Body |
- ||-------------------------------------------------------------------|
- | Capability Information | Listen Interval | SSID | Supported Rates |
- ||------------------------|-----------------|------|-----------------|
- | 2 | 2 | 2-34 | 3-10 |
- | ---------------------------------------------------------------------
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-
-s32 host_int_get_assoc_req_info(struct host_if_drv *hWFIDrv, u8 *pu8AssocReqInfo,
- u32 u32AssocReqInfoLen);
-/**
- * @brief gets a Association Response info
- * @details
- * @param[in,out] handle to the wifi driver,
- * Message containg assoc. resp info
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-
-s32 host_int_get_assoc_res_info(struct host_if_drv *hWFIDrv, u8 *pu8AssocRespInfo,
- u32 u32MaxAssocRespInfoLen, u32 *pu32RcvdAssocRespInfoLen);
-/**
- * @brief gets a Association Response info
- * @details Valid only in STA mode. This function gives the RSSI
- * values observed in all the channels at the time of scanning.
- * The length of the field is 1 greater that the total number of
- * channels supported. Byte 0 contains the number of channels while
- * each of Byte N contains the observed RSSI value for the channel index N.
- * @param[in,out] handle to the wifi driver,
- * array of scanned channels' RSSI
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_get_rx_power_level(struct host_if_drv *hWFIDrv, u8 *pu8RxPowerLevel,
- u32 u32RxPowerLevelLen);
-
-/**
- * @brief sets a channel
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] Index of the channel to be set
- *|-------------------------------------------------------------------|
- | CHANNEL1 CHANNEL2 .... CHANNEL14 |
- | Input: 1 2 14 |
- ||-------------------------------------------------------------------|
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-int host_int_set_mac_chnl_num(struct host_if_drv *wfi_drv, u8 channel);
-
-/**
- * @brief gets the current channel index
- * @details
- * @param[in,out] handle to the wifi driver,
- * current channel index
- *|-----------------------------------------------------------------------|
- | CHANNEL1 CHANNEL2 .... CHANNEL14 |
- | Input: 1 2 14 |
- ||-----------------------------------------------------------------------|
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_get_host_chnl_num(struct host_if_drv *hWFIDrv, u8 *pu8ChNo);
-/**
- * @brief gets the sta rssi
- * @details gets the currently maintained RSSI value for the station.
- * The received signal strength value in dB.
- * The range of valid values is -128 to 0.
- * @param[in,out] handle to the wifi driver,
- * rssi value in dB
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_get_rssi(struct host_if_drv *hWFIDrv, s8 *ps8Rssi);
-s32 host_int_get_link_speed(struct host_if_drv *hWFIDrv, s8 *ps8lnkspd);
-/**
- * @brief scans a set of channels
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] Scan source
- * Scan Type PASSIVE_SCAN = 0,
- * ACTIVE_SCAN = 1
- * Channels Array
- * Channels Array length
- * Scan Callback function
- * User Argument to be delivered back through the Scan Cllback function
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_scan(struct host_if_drv *hWFIDrv, u8 u8ScanSource,
- u8 u8ScanType, u8 *pu8ChnlFreqList,
- u8 u8ChnlListLen, const u8 *pu8IEs,
- size_t IEsLen, wilc_scan_result ScanResult,
- void *pvUserArg,
- struct hidden_network *pstrHiddenNetwork);
-/**
- * @brief sets configuration wids values
- * @details
- * @param[in,out] handle to the wifi driver,
- * @param[in] WID, WID value
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 hif_set_cfg(struct host_if_drv *hWFIDrv, struct cfg_param_val *pstrCfgParamVal);
-
-/**
- * @brief gets configuration wids values
- * @details
- * @param[in,out] handle to the wifi driver,
- * WID value
- * @param[in] WID,
- * @return Error code indicating success/failure
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 hif_get_cfg(struct host_if_drv *hWFIDrv, u16 u16WID, u16 *pu16WID_Value);
-/*****************************************************************************/
-/* Notification Functions */
-/*****************************************************************************/
-/**
- * @brief host interface initialization function
- * @details
- * @param[in,out] handle to the wifi driver,
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_init(struct net_device *dev, struct host_if_drv **phWFIDrv);
-
-/**
- * @brief host interface initialization function
- * @details
- * @param[in,out] handle to the wifi driver,
- * @note
- * @author zsalah
- * @date 8 March 2012
- * @version 1.0
- */
-s32 host_int_deinit(struct host_if_drv *hWFIDrv);
-
-
-/*!
- * @fn s32 host_int_add_beacon(WILC_WFIDrvHandle hWFIDrv,u8 u8Index)
- * @brief Sends a beacon to the firmware to be transmitted over the air
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] u32Interval Beacon Interval. Period between two successive beacons on air
- * @param[in] u32DTIMPeriod DTIM Period. Indicates how many Beacon frames
- * (including the current frame) appear before the next DTIM
- * @param[in] u32Headlen Length of the head buffer in bytes
- * @param[in] pu8Head Pointer to the beacon's head buffer. Beacon's head
- * is the part from the beacon's start till the TIM element, NOT including the TIM
- * @param[in] u32Taillen Length of the tail buffer in bytes
- * @param[in] pu8Tail Pointer to the beacon's tail buffer. Beacon's tail
- * starts just after the TIM inormation element
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 10 Julys 2012
- * @version 1.0 Description
- *
- */
-s32 host_int_add_beacon(struct host_if_drv *hWFIDrv, u32 u32Interval,
- u32 u32DTIMPeriod,
- u32 u32HeadLen, u8 *pu8Head,
- u32 u32TailLen, u8 *pu8tail);
-
-
-/*!
- * @fn s32 host_int_del_beacon(WILC_WFIDrvHandle hWFIDrv)
- * @brief Removes the beacon and stops trawilctting it over the air
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 10 Julys 2012
- * @version 1.0 Description
- */
-s32 host_int_del_beacon(struct host_if_drv *hWFIDrv);
-
-/*!
- * @fn s32 host_int_add_station(WILC_WFIDrvHandle hWFIDrv,
- * struct add_sta_param *pstrStaParams)
- * @brief Notifies the firmware with a new associated stations
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] pstrStaParams Station's parameters
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 12 July 2012
- * @version 1.0 Description
- */
-s32 host_int_add_station(struct host_if_drv *hWFIDrv,
- struct add_sta_param *pstrStaParams);
-
-/*!
- * @fn s32 host_int_del_allstation(WILC_WFIDrvHandle hWFIDrv, const u8* pu8MacAddr)
- * @brief Deauthenticates clients when group is terminating
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] pu8MacAddr Station's mac address
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Mai Daftedar
- * @date 09 April 2014
- * @version 1.0 Description
- */
-s32 host_int_del_allstation(struct host_if_drv *hWFIDrv, u8 pu8MacAddr[][ETH_ALEN]);
-
-/*!
- * @fn s32 host_int_del_station(WILC_WFIDrvHandle hWFIDrv, u8* pu8MacAddr)
- * @brief Notifies the firmware with a new deleted station
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] pu8MacAddr Station's mac address
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 15 July 2012
- * @version 1.0 Description
- */
-s32 host_int_del_station(struct host_if_drv *hWFIDrv, const u8 *pu8MacAddr);
-
-/*!
- * @fn s32 host_int_edit_station(WILC_WFIDrvHandle hWFIDrv,
- * struct add_sta_param *pstrStaParams)
- * @brief Notifies the firmware with new parameters of an already associated station
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] pstrStaParams Station's parameters
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 15 July 2012
- * @version 1.0 Description
- */
-s32 host_int_edit_station(struct host_if_drv *hWFIDrv,
- struct add_sta_param *pstrStaParams);
-
-/*!
- * @fn s32 host_int_set_power_mgmt(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32Timeout)
- * @brief Set the power management mode to enabled or disabled
- * @details
- * @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] bIsEnabled TRUE if enabled, FALSE otherwise
- * @param[in] u32Timeout A timeout value of -1 allows the driver to adjust
- * the dynamic ps timeout value
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 24 November 2012
- * @version 1.0 Description
- */
-s32 host_int_set_power_mgmt(struct host_if_drv *hWFIDrv, bool bIsEnabled, u32 u32Timeout);
-/* @param[in,out] hWFIDrv handle to the wifi driver
- * @param[in] bIsEnabled TRUE if enabled, FALSE otherwise
- * @param[in] u8count count of mac address entries in the filter table
- *
- * @return 0 for Success, error otherwise
- * @todo
- * @sa
- * @author Adham Abozaeid
- * @date 24 November 2012
- * @version 1.0 Description
- */
-s32 host_int_setup_multicast_filter(struct host_if_drv *hWFIDrv, bool bIsEnabled, u32 u32count);
-/**
- * @brief host_int_setup_ipaddress
- * @details set IP address on firmware
- * @param[in]
- * @return Error code.
- * @author Abdelrahman Sobhy
- * @date
- * @version 1.0
- */
-s32 host_int_setup_ipaddress(struct host_if_drv *hWFIDrv, u8 *pu8IPAddr, u8 idx);
-
-
-/**
- * @brief host_int_delBASession
- * @details Delete single Rx BA session
- * @param[in]
- * @return Error code.
- * @author Abdelrahman Sobhy
- * @date
- * @version 1.0
- */
-s32 host_int_delBASession(struct host_if_drv *hWFIDrv, char *pBSSID, char TID);
-
-/**
- * @brief host_int_delBASession
- * @details Delete all Rx BA session
- * @param[in]
- * @return Error code.
- * @author Abdelrahman Sobhy
- * @date
- * @version 1.0
- */
-s32 host_int_del_All_Rx_BASession(struct host_if_drv *hWFIDrv, char *pBSSID, char TID);
-
-
-/**
- * @brief host_int_get_ipaddress
- * @details get IP address on firmware
- * @param[in]
- * @return Error code.
- * @author Abdelrahman Sobhy
- * @date
- * @version 1.0
- */
-s32 host_int_get_ipaddress(struct host_if_drv *hWFIDrv, u8 *pu8IPAddr, u8 idx);
-
-/**
- * @brief host_int_remain_on_channel
- * @details
- * @param[in]
- * @return Error code.
- * @author
- * @date
- * @version 1.0
- */
-s32 host_int_remain_on_channel(struct host_if_drv *hWFIDrv, u32 u32SessionID, u32 u32duration, u16 chan, wilc_remain_on_chan_expired RemainOnChanExpired, wilc_remain_on_chan_ready RemainOnChanReady, void *pvUserArg);
-
-/**
- * @brief host_int_ListenStateExpired
- * @details
- * @param[in] Handle to wifi driver
- * Duration to remain on channel
- * Channel to remain on
- * Pointer to fn to be called on receive frames in listen state
- * Pointer to remain-on-channel expired fn
- * Priv
- * @return Error code.
- * @author
- * @date
- * @version 1.0
- */
-s32 host_int_ListenStateExpired(struct host_if_drv *hWFIDrv, u32 u32SessionID);
-
-/**
- * @brief host_int_frame_register
- * @details
- * @param[in]
- * @return Error code.
- * @author
- * @date
- * @version 1.0
- */
-s32 host_int_frame_register(struct host_if_drv *hWFIDrv, u16 u16FrameType, bool bReg);
-/**
- * @brief host_int_set_wfi_drv_handler
- * @details
- * @param[in]
- * @return Error code.
- * @author
- * @date
- * @version 1.0
- */
-int host_int_set_wfi_drv_handler(struct host_if_drv *address);
-int host_int_set_operation_mode(struct host_if_drv *wfi_drv, u32 mode);
-
-static s32 Handle_ScanDone(struct host_if_drv *drvHandler, enum scan_event enuEvent);
-
-void host_int_freeJoinParams(void *pJoinParams);
-
-s32 host_int_get_statistics(struct host_if_drv *hWFIDrv, struct rf_info *pstrStatistics);
+struct wilc_vif;
+s32 wilc_remove_key(struct host_if_drv *hWFIDrv, const u8 *pu8StaAddress);
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index);
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index, u8 mode, enum AUTHTYPE auth_type);
+s32 wilc_add_ptk(struct wilc_vif *vif, const u8 *pu8Ptk, u8 u8PtkKeylen,
+ const u8 *mac_addr, const u8 *pu8RxMic, const u8 *pu8TxMic,
+ u8 mode, u8 u8Ciphermode, u8 u8Idx);
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+ u32 *pu32InactiveTime);
+s32 wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *pu8RxGtk, u8 u8GtkKeylen,
+ u8 u8KeyIdx, u32 u32KeyRSClen, const u8 *KeyRSC,
+ const u8 *pu8RxMic, const u8 *pu8TxMic, u8 mode,
+ u8 u8Ciphermode);
+s32 wilc_add_tx_gtk(struct host_if_drv *hWFIDrv, u8 u8KeyLen,
+ u8 *pu8TxGtk, u8 u8KeyIdx);
+s32 wilc_set_pmkid_info(struct wilc_vif *vif,
+ struct host_if_pmkid_attr *pu8PmkidInfoArray);
+s32 wilc_get_mac_address(struct wilc_vif *vif, u8 *pu8MacAddress);
+s32 wilc_set_mac_address(struct wilc_vif *vif, u8 *pu8MacAddress);
+int wilc_wait_msg_queue_idle(void);
+s32 wilc_set_start_scan_req(struct host_if_drv *hWFIDrv, u8 scanSource);
+s32 wilc_set_join_req(struct wilc_vif *vif, u8 *pu8bssid, const u8 *pu8ssid,
+ size_t ssidLen, const u8 *pu8IEs, size_t IEsLen,
+ wilc_connect_result pfConnectResult, void *pvUserArg,
+ u8 u8security, enum AUTHTYPE tenuAuth_type,
+ u8 u8channel, void *pJoinParams);
+s32 wilc_flush_join_req(struct wilc_vif *vif);
+s32 wilc_disconnect(struct wilc_vif *vif, u16 u16ReasonCode);
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
+s32 wilc_get_rssi(struct wilc_vif *vif, s8 *ps8Rssi);
+s32 wilc_scan(struct wilc_vif *vif, u8 u8ScanSource, u8 u8ScanType,
+ u8 *pu8ChnlFreqList, u8 u8ChnlListLen, const u8 *pu8IEs,
+ size_t IEsLen, wilc_scan_result ScanResult, void *pvUserArg,
+ struct hidden_network *pstrHiddenNetwork);
+s32 wilc_hif_set_cfg(struct wilc_vif *vif,
+ struct cfg_param_val *pstrCfgParamVal);
+s32 wilc_init(struct net_device *dev, struct host_if_drv **phWFIDrv);
+s32 wilc_deinit(struct wilc_vif *vif);
+s32 wilc_add_beacon(struct wilc_vif *vif, u32 u32Interval, u32 u32DTIMPeriod,
+ u32 u32HeadLen, u8 *pu8Head, u32 u32TailLen, u8 *pu8Tail);
+int wilc_del_beacon(struct wilc_vif *vif);
+int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param);
+s32 wilc_del_allstation(struct wilc_vif *vif, u8 pu8MacAddr[][ETH_ALEN]);
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
+s32 wilc_edit_station(struct wilc_vif *vif,
+ struct add_sta_param *pstrStaParams);
+s32 wilc_set_power_mgmt(struct wilc_vif *vif, bool bIsEnabled, u32 u32Timeout);
+s32 wilc_setup_multicast_filter(struct wilc_vif *vif, bool bIsEnabled,
+ u32 u32count);
+s32 wilc_setup_ipaddress(struct wilc_vif *vif, u8 *u16ipadd, u8 idx);
+s32 wilc_del_all_rx_ba_session(struct wilc_vif *vif, char *pBSSID, char TID);
+s32 wilc_remain_on_channel(struct wilc_vif *vif, u32 u32SessionID,
+ u32 u32duration, u16 chan,
+ wilc_remain_on_chan_expired RemainOnChanExpired,
+ wilc_remain_on_chan_ready RemainOnChanReady,
+ void *pvUserArg);
+s32 wilc_listen_state_expired(struct wilc_vif *vif, u32 u32SessionID);
+s32 wilc_frame_register(struct wilc_vif *vif, u16 u16FrameType, bool bReg);
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index);
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
+
+void wilc_free_join_params(void *pJoinParams);
+
+s32 wilc_get_statistics(struct wilc_vif *vif, struct rf_info *pstrStatistics);
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
+int wilc_get_vif_idx(struct wilc_vif *vif);
+
+extern bool wilc_optaining_ip;
+extern u8 wilc_connected_ssid[6];
+extern u8 wilc_multicast_mac_addr_list[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
+
+extern int wilc_connecting;
+extern u8 wilc_initialized;
+extern struct timer_list wilc_during_ip_timer;
#endif
diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c
index 450af1b77f99..e550027645b7 100644
--- a/drivers/staging/wilc1000/linux_mon.c
+++ b/drivers/staging/wilc1000/linux_mon.c
@@ -26,12 +26,9 @@ struct wilc_wfi_radiotap_cb_hdr {
static struct net_device *wilc_wfi_mon; /* global monitor netdev */
-extern int mac_xmit(struct sk_buff *skb, struct net_device *dev);
-
-
-u8 srcAdd[6];
-u8 bssid[6];
-u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static u8 srcAdd[6];
+static u8 bssid[6];
+static u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/**
* @brief WILC_WFI_monitor_rx
* @details
@@ -195,7 +192,7 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
mgmt_tx->size = len;
memcpy(mgmt_tx->buff, buf, len);
- wilc_wlan_txq_add_mgmt_pkt(mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
+ wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
mgmt_tx_complete);
netif_wake_queue(dev);
@@ -298,7 +295,7 @@ static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb,
mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
dev_kfree_skb(skb);
} else
- ret = mac_xmit(skb, mon_priv->real_ndev);
+ ret = wilc_mac_xmit(skb, mon_priv->real_ndev);
return ret;
}
diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c
index 2a5b36fd8b48..54fe9d74b780 100644
--- a/drivers/staging/wilc1000/linux_wlan.c
+++ b/drivers/staging/wilc1000/linux_wlan.c
@@ -23,61 +23,8 @@
#include <linux/kernel.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
#include <linux/semaphore.h>
-#ifdef WILC_SDIO
-#include "linux_wlan_sdio.h"
-#else
-#include "linux_wlan_spi.h"
-#endif
-
-#if defined(CUSTOMER_PLATFORM)
-/*
- TODO : Write power control functions as customer platform.
- */
-#else
-
- #define _linux_wlan_device_power_on() {}
- #define _linux_wlan_device_power_off() {}
-
- #define _linux_wlan_device_detection() {}
- #define _linux_wlan_device_removal() {}
-#endif
-
-extern bool g_obtainingIP;
-extern void resolve_disconnect_aberration(void *drvHandler);
-extern u8 gau8MulticastMacAddrList[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
-extern struct timer_list hDuringIpTimer;
-
-static int linux_wlan_device_power(int on_off)
-{
- PRINT_D(INIT_DBG, "linux_wlan_device_power.. (%d)\n", on_off);
-
- if (on_off) {
- _linux_wlan_device_power_on();
- } else {
- _linux_wlan_device_power_off();
- }
-
- return 0;
-}
-
-static int linux_wlan_device_detection(int on_off)
-{
- PRINT_D(INIT_DBG, "linux_wlan_device_detection.. (%d)\n", on_off);
-
-#ifdef WILC_SDIO
- if (on_off) {
- _linux_wlan_device_detection();
- } else {
- _linux_wlan_device_removal();
- }
-#endif
-
- return 0;
-}
-
static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr);
static struct notifier_block g_dev_notifier = {
@@ -86,40 +33,24 @@ static struct notifier_block g_dev_notifier = {
#define IRQ_WAIT 1
#define IRQ_NO_WAIT 0
-/*
- * to sync between mac_close and module exit.
- * don't initialize or de-initialize from init/deinitlocks
- * to be initialized from module wilc_netdev_init and
- * deinitialized from mdoule_exit
- */
static struct semaphore close_exit_sync;
static int wlan_deinit_locks(struct net_device *dev);
static void wlan_deinitialize_threads(struct net_device *dev);
-extern void WILC_WFI_monitor_rx(u8 *buff, u32 size);
-extern void WILC_WFI_p2p_rx(struct net_device *dev, u8 *buff, u32 size);
static void linux_wlan_tx_complete(void *priv, int status);
static int mac_init_fn(struct net_device *ndev);
-int mac_xmit(struct sk_buff *skb, struct net_device *dev);
-int mac_open(struct net_device *ndev);
-int mac_close(struct net_device *ndev);
static struct net_device_stats *mac_stats(struct net_device *dev);
static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd);
static void wilc_set_multicast_list(struct net_device *dev);
-/*
- * for now - in frmw_to_linux there should be private data to be passed to it
- * and this data should be pointer to net device
- */
-struct wilc *g_linux_wlan;
-bool bEnablePS = true;
+bool wilc_enable_ps = true;
static const struct net_device_ops wilc_netdev_ops = {
.ndo_init = mac_init_fn,
- .ndo_open = mac_open,
- .ndo_stop = mac_close,
- .ndo_start_xmit = mac_xmit,
+ .ndo_open = wilc_mac_open,
+ .ndo_stop = wilc_mac_close,
+ .ndo_start_xmit = wilc_mac_xmit,
.ndo_do_ioctl = mac_ioctl,
.ndo_get_stats = mac_stats,
.ndo_set_rx_mode = wilc_set_multicast_list,
@@ -130,130 +61,129 @@ static int dev_state_ev_handler(struct notifier_block *this, unsigned long event
{
struct in_ifaddr *dev_iface = (struct in_ifaddr *)ptr;
struct wilc_priv *priv;
- struct host_if_drv *pstrWFIDrv;
+ struct host_if_drv *hif_drv;
struct net_device *dev;
- u8 *pIP_Add_buff;
- perInterface_wlan_t *nic;
+ u8 *ip_addr_buf;
+ struct wilc_vif *vif;
u8 null_ip[4] = {0};
char wlan_dev_name[5] = "wlan0";
- if (dev_iface == NULL || dev_iface->ifa_dev == NULL || dev_iface->ifa_dev->dev == NULL) {
+ if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev) {
PRINT_D(GENERIC_DBG, "dev_iface = NULL\n");
return NOTIFY_DONE;
}
- if ((memcmp(dev_iface->ifa_label, "wlan0", 5)) && (memcmp(dev_iface->ifa_label, "p2p0", 4))) {
+ if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
+ memcmp(dev_iface->ifa_label, "p2p0", 4)) {
PRINT_D(GENERIC_DBG, "Interface is neither WLAN0 nor P2P0\n");
return NOTIFY_DONE;
}
dev = (struct net_device *)dev_iface->ifa_dev->dev;
- if (dev->ieee80211_ptr == NULL || dev->ieee80211_ptr->wiphy == NULL) {
+ if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) {
PRINT_D(GENERIC_DBG, "No Wireless registerd\n");
return NOTIFY_DONE;
}
priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
- if (priv == NULL) {
+ if (!priv) {
PRINT_D(GENERIC_DBG, "No Wireless Priv\n");
return NOTIFY_DONE;
}
- pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
- nic = netdev_priv(dev);
- if (nic == NULL || pstrWFIDrv == NULL) {
+ hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
+ vif = netdev_priv(dev);
+ if (!vif || !hif_drv) {
PRINT_D(GENERIC_DBG, "No Wireless Priv\n");
return NOTIFY_DONE;
}
- PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler +++\n"); /* tony */
+ PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler +++\n");
switch (event) {
case NETDEV_UP:
- PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_UP %p\n", dev); /* tony */
+ PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_UP %p\n", dev);
PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Obtained ===============\n\n");
- /*If we are in station mode or client mode*/
- if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) {
- pstrWFIDrv->IFC_UP = 1;
- g_obtainingIP = false;
- del_timer(&hDuringIpTimer);
+ if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
+ hif_drv->IFC_UP = 1;
+ wilc_optaining_ip = false;
+ del_timer(&wilc_during_ip_timer);
PRINT_D(GENERIC_DBG, "IP obtained , enable scan\n");
}
- if (bEnablePS)
- host_int_set_power_mgmt(pstrWFIDrv, 1, 0);
+ if (wilc_enable_ps)
+ wilc_set_power_mgmt(vif, 1, 0);
PRINT_D(GENERIC_DBG, "[%s] Up IP\n", dev_iface->ifa_label);
- pIP_Add_buff = (char *) (&(dev_iface->ifa_address));
- PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]);
- host_int_setup_ipaddress(pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx);
+ ip_addr_buf = (char *)&dev_iface->ifa_address;
+ PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n",
+ ip_addr_buf[0], ip_addr_buf[1],
+ ip_addr_buf[2], ip_addr_buf[3]);
+ wilc_setup_ipaddress(vif, ip_addr_buf, vif->u8IfIdx);
break;
case NETDEV_DOWN:
- PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_DOWN %p\n", dev); /* tony */
+ PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_DOWN %p\n", dev);
PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Released ===============\n\n");
- if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) {
- pstrWFIDrv->IFC_UP = 0;
- g_obtainingIP = false;
+ if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
+ hif_drv->IFC_UP = 0;
+ wilc_optaining_ip = false;
}
if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0)
- host_int_set_power_mgmt(pstrWFIDrv, 0, 0);
+ wilc_set_power_mgmt(vif, 0, 0);
- resolve_disconnect_aberration(pstrWFIDrv);
+ wilc_resolve_disconnect_aberration(vif);
PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label);
- pIP_Add_buff = null_ip;
- PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]);
+ ip_addr_buf = null_ip;
+ PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n",
+ ip_addr_buf[0], ip_addr_buf[1],
+ ip_addr_buf[2], ip_addr_buf[3]);
- host_int_setup_ipaddress(pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx);
+ wilc_setup_ipaddress(vif, ip_addr_buf, vif->u8IfIdx);
break;
default:
- PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler event=default\n"); /* tony */
+ PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler event=default\n");
PRINT_INFO(GENERIC_DBG, "[%s] unknown dev event: %lu\n", dev_iface->ifa_label, event);
break;
}
return NOTIFY_DONE;
-
}
-#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO)
static irqreturn_t isr_uh_routine(int irq, void *user_data)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
struct net_device *dev = (struct net_device *)user_data;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
PRINT_D(INT_DBG, "Interrupt received UH\n");
- /*While mac is closing cacncel the handling of any interrupts received*/
if (wilc->close) {
PRINT_ER("Driver is CLOSING: Can't handle UH interrupt\n");
return IRQ_HANDLED;
}
return IRQ_WAKE_THREAD;
}
-#endif
-irqreturn_t isr_bh_routine(int irq, void *userdata)
+static irqreturn_t isr_bh_routine(int irq, void *userdata)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(userdata);
- wilc = nic->wilc;
+ vif = netdev_priv(userdata);
+ wilc = vif->wilc;
- /*While mac is closing cacncel the handling of any interrupts received*/
if (wilc->close) {
PRINT_ER("Driver is CLOSING: Can't handle BH interrupt\n");
return IRQ_HANDLED;
@@ -265,154 +195,131 @@ irqreturn_t isr_bh_routine(int irq, void *userdata)
return IRQ_HANDLED;
}
-#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO)
static int init_irq(struct net_device *dev)
{
int ret = 0;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wl;
- nic = netdev_priv(dev);
- wl = nic->wilc;
-
- /*initialize GPIO and register IRQ num*/
- /*GPIO request*/
- if ((gpio_request(GPIO_NUM, "WILC_INTR") == 0) &&
- (gpio_direction_input(GPIO_NUM) == 0)) {
-#if defined(CUSTOMER_PLATFORM)
-/*
- TODO : save the registerd irq number to the private wilc context in kernel.
- *
- * ex) nic->dev_irq_num = gpio_to_irq(GPIO_NUM);
- */
-#else
- wl->dev_irq_num = gpio_to_irq(GPIO_NUM);
-#endif
+ vif = netdev_priv(dev);
+ wl = vif->wilc;
+
+ if ((gpio_request(wl->gpio, "WILC_INTR") == 0) &&
+ (gpio_direction_input(wl->gpio) == 0)) {
+ wl->dev_irq_num = gpio_to_irq(wl->gpio);
} else {
ret = -1;
PRINT_ER("could not obtain gpio for WILC_INTR\n");
}
- if ((ret != -1) && (request_threaded_irq(wl->dev_irq_num, isr_uh_routine, isr_bh_routine,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT, /*Without IRQF_ONESHOT the uh will remain kicked in and dont gave a chance to bh*/
- "WILC_IRQ", dev)) < 0) {
-
- PRINT_ER("Failed to request IRQ for GPIO: %d\n", GPIO_NUM);
+ if (ret != -1 && request_threaded_irq(wl->dev_irq_num,
+ isr_uh_routine,
+ isr_bh_routine,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "WILC_IRQ", dev) < 0) {
+ PRINT_ER("Failed to request IRQ for GPIO: %d\n", wl->gpio);
+ gpio_free(wl->gpio);
ret = -1;
} else {
-
PRINT_D(INIT_DBG, "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n",
- wl->dev_irq_num, GPIO_NUM);
+ wl->dev_irq_num, wl->gpio);
}
return ret;
}
-#endif
static void deinit_irq(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
-#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO)
/* Deintialize IRQ */
- if (&wilc->dev_irq_num != 0) {
+ if (wilc->dev_irq_num) {
free_irq(wilc->dev_irq_num, wilc);
-
- gpio_free(GPIO_NUM);
+ gpio_free(wilc->gpio);
}
-#endif
}
-/*
- * OS functions
- */
-void linux_wlan_dbg(u8 *buff)
+void wilc_dbg(u8 *buff)
{
PRINT_D(INIT_DBG, "%d\n", *buff);
}
-int linux_wlan_lock_timeout(void *vp, u32 timeout)
+int wilc_lock_timeout(struct wilc *nic, void *vp, u32 timeout)
{
+ /* FIXME: replace with mutex_lock or wait_for_completion */
int error = -1;
PRINT_D(LOCK_DBG, "Locking %p\n", vp);
- if (vp != NULL)
- error = down_timeout((struct semaphore *)vp, msecs_to_jiffies(timeout));
+ if (vp)
+ error = down_timeout((struct semaphore *)vp,
+ msecs_to_jiffies(timeout));
else
PRINT_ER("Failed, mutex is NULL\n");
return error;
}
-void linux_wlan_mac_indicate(struct wilc *wilc, int flag)
+void wilc_mac_indicate(struct wilc *wilc, int flag)
{
- /*I have to do it that way becuase there is no mean to encapsulate device pointer
- * as a parameter
- */
int status;
if (flag == WILC_MAC_INDICATE_STATUS) {
- wilc_wlan_cfg_get_val(WID_STATUS, (unsigned char *)&status, 4);
+ wilc_wlan_cfg_get_val(WID_STATUS,
+ (unsigned char *)&status, 4);
if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
wilc->mac_status = status;
up(&wilc->sync_event);
} else {
wilc->mac_status = status;
}
-
- if (wilc->mac_status == WILC_MAC_STATUS_CONNECT) { /* Connect */
- }
-
} else if (flag == WILC_MAC_INDICATE_SCAN) {
PRINT_D(GENERIC_DBG, "Scanning ...\n");
-
}
-
}
-struct net_device *GetIfHandler(struct wilc *wilc, u8 *pMacHeader)
+static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
{
- u8 *Bssid, *Bssid1;
+ u8 *bssid, *bssid1;
int i = 0;
- Bssid = pMacHeader + 10;
- Bssid1 = pMacHeader + 4;
+ bssid = mac_header + 10;
+ bssid1 = mac_header + 4;
for (i = 0; i < wilc->vif_num; i++)
- if (!memcmp(Bssid1, wilc->vif[i].bssid, ETH_ALEN) ||
- !memcmp(Bssid, wilc->vif[i].bssid, ETH_ALEN))
- return wilc->vif[i].ndev;
+ if (!memcmp(bssid1, wilc->vif[i]->bssid, ETH_ALEN) ||
+ !memcmp(bssid, wilc->vif[i]->bssid, ETH_ALEN))
+ return wilc->vif[i]->ndev;
PRINT_INFO(INIT_DBG, "Invalide handle\n");
for (i = 0; i < 25; i++)
- PRINT_D(INIT_DBG, "%02x ", pMacHeader[i]);
- Bssid = pMacHeader + 18;
- Bssid1 = pMacHeader + 12;
+ PRINT_D(INIT_DBG, "%02x ", mac_header[i]);
+ bssid = mac_header + 18;
+ bssid1 = mac_header + 12;
for (i = 0; i < wilc->vif_num; i++)
- if (!memcmp(Bssid1, wilc->vif[i].bssid, ETH_ALEN) ||
- !memcmp(Bssid, wilc->vif[i].bssid, ETH_ALEN))
- return wilc->vif[i].ndev;
+ if (!memcmp(bssid1, wilc->vif[i]->bssid, ETH_ALEN) ||
+ !memcmp(bssid, wilc->vif[i]->bssid, ETH_ALEN))
+ return wilc->vif[i]->ndev;
PRINT_INFO(INIT_DBG, "\n");
return NULL;
}
-int linux_wlan_set_bssid(struct net_device *wilc_netdev, u8 *pBSSID)
+int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid)
{
int i = 0;
int ret = -1;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(wilc_netdev);
- wilc = nic->wilc;
+ vif = netdev_priv(wilc_netdev);
+ wilc = vif->wilc;
for (i = 0; i < wilc->vif_num; i++)
- if (wilc->vif[i].ndev == wilc_netdev) {
- memcpy(wilc->vif[i].bssid, pBSSID, 6);
+ if (wilc->vif[i]->ndev == wilc_netdev) {
+ memcpy(wilc->vif[i]->bssid, bssid, 6);
ret = 0;
break;
}
@@ -420,15 +327,14 @@ int linux_wlan_set_bssid(struct net_device *wilc_netdev, u8 *pBSSID)
return ret;
}
-/*Function to get number of connected interfaces*/
-int linux_wlan_get_num_conn_ifcs(void)
+int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
{
u8 i = 0;
u8 null_bssid[6] = {0};
u8 ret_val = 0;
- for (i = 0; i < g_linux_wlan->vif_num; i++)
- if (memcmp(g_linux_wlan->vif[i].bssid, null_bssid, 6))
+ for (i = 0; i < wilc->vif_num; i++)
+ if (memcmp(wilc->vif[i]->bssid, null_bssid, 6))
ret_val++;
return ret_val;
@@ -439,7 +345,7 @@ int linux_wlan_get_num_conn_ifcs(void)
static int linux_wlan_txq_task(void *vp)
{
int ret, txq_count;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wl;
struct net_device *dev = vp;
#if defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS
@@ -451,20 +357,16 @@ static int linux_wlan_txq_task(void *vp)
int backoff_weight = TX_BACKOFF_WEIGHT_MIN;
#endif
- nic = netdev_priv(dev);
- wl = nic->wilc;
+ vif = netdev_priv(dev);
+ wl = vif->wilc;
- /* inform wilc1000_wlan_init that TXQ task is started. */
up(&wl->txq_thread_started);
while (1) {
-
PRINT_D(TX_DBG, "txq_task Taking a nap :)\n");
down(&wl->txq_event);
- /* wait_for_completion(&pd->txq_event); */
PRINT_D(TX_DBG, "txq_task Who waked me up :$\n");
if (wl->close) {
- /*Unlock the mutex in the mac_close function to indicate the exiting of the TX thread */
up(&wl->txq_thread_started);
while (!kthread_should_stop())
@@ -479,23 +381,19 @@ static int linux_wlan_txq_task(void *vp)
#else
do {
ret = wilc_wlan_handle_txq(dev, &txq_count);
- if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD /* && netif_queue_stopped(pd->wilc_netdev)*/) {
+ if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
PRINT_D(TX_DBG, "Waking up queue\n");
- /* netif_wake_queue(pd->wilc_netdev); */
- if (netif_queue_stopped(wl->vif[0].ndev))
- netif_wake_queue(wl->vif[0].ndev);
- if (netif_queue_stopped(wl->vif[1].ndev))
- netif_wake_queue(wl->vif[1].ndev);
+
+ if (netif_queue_stopped(wl->vif[0]->ndev))
+ netif_wake_queue(wl->vif[0]->ndev);
+ if (netif_queue_stopped(wl->vif[1]->ndev))
+ netif_wake_queue(wl->vif[1]->ndev);
}
- if (ret == WILC_TX_ERR_NO_BUF) { /* failed to allocate buffers in chip. */
+ if (ret == WILC_TX_ERR_NO_BUF) {
do {
- /* Back off from sending packets for some time. */
- /* schedule_timeout will allow RX task to run and free buffers.*/
- /* set_current_state(TASK_UNINTERRUPTIBLE); */
- /* timeout = schedule_timeout(timeout); */
msleep(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight);
- } while (/*timeout*/ 0);
+ } while (0);
backoff_weight += TX_BACKOFF_WEIGHT_INCR_STEP;
if (backoff_weight > TX_BACKOFF_WEIGHT_MAX)
backoff_weight = TX_BACKOFF_WEIGHT_MAX;
@@ -506,376 +404,326 @@ static int linux_wlan_txq_task(void *vp)
backoff_weight = TX_BACKOFF_WEIGHT_MIN;
}
}
- /*TODO: drop packets after a certain time/number of retry count. */
- } while (ret == WILC_TX_ERR_NO_BUF && !wl->close); /* retry sending packets if no more buffers in chip. */
+ } while (ret == WILC_TX_ERR_NO_BUF && !wl->close);
#endif
}
return 0;
}
-void linux_wlan_rx_complete(void)
+void wilc_rx_complete(struct wilc *nic)
{
PRINT_D(RX_DBG, "RX completed\n");
}
-int linux_wlan_get_firmware(perInterface_wlan_t *p_nic)
+int wilc_wlan_get_firmware(struct net_device *dev)
{
-
- perInterface_wlan_t *nic = p_nic;
+ struct wilc_vif *vif;
+ struct wilc *wilc;
int ret = 0;
const struct firmware *wilc_firmware;
char *firmware;
- if (nic->iftype == AP_MODE)
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
+
+ if (vif->iftype == AP_MODE) {
firmware = AP_FIRMWARE;
- else if (nic->iftype == STATION_MODE)
+ } else if (vif->iftype == STATION_MODE) {
firmware = STA_FIRMWARE;
-
- else {
+ } else {
PRINT_D(INIT_DBG, "Get P2P_CONCURRENCY_FIRMWARE\n");
firmware = P2P_CONCURRENCY_FIRMWARE;
}
- if (nic == NULL) {
- PRINT_ER("NIC is NULL\n");
+ if (!vif) {
+ PRINT_ER("vif is NULL\n");
goto _fail_;
}
- if (&nic->wilc_netdev->dev == NULL) {
- PRINT_ER("&nic->wilc_netdev->dev is NULL\n");
+ if (!(&vif->ndev->dev)) {
+ PRINT_ER("&vif->ndev->dev is NULL\n");
goto _fail_;
}
- /* the firmare should be located in /lib/firmware in
- * root file system with the name specified above */
-
-#ifdef WILC_SDIO
- if (request_firmware(&wilc_firmware, firmware, &g_linux_wlan->wilc_sdio_func->dev) != 0) {
+ if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
PRINT_ER("%s - firmare not available\n", firmware);
ret = -1;
goto _fail_;
}
-#else
- if (request_firmware(&wilc_firmware, firmware, &g_linux_wlan->wilc_spidev->dev) != 0) {
- PRINT_ER("%s - firmare not available\n", firmware);
- ret = -1;
- goto _fail_;
- }
-#endif
- g_linux_wlan->firmware = wilc_firmware;
+ wilc->firmware = wilc_firmware;
_fail_:
return ret;
-
}
-static int linux_wlan_start_firmware(perInterface_wlan_t *nic)
+static int linux_wlan_start_firmware(struct net_device *dev)
{
-
+ struct wilc_vif *vif;
+ struct wilc *wilc;
int ret = 0;
- /* start firmware */
+
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
+
PRINT_D(INIT_DBG, "Starting Firmware ...\n");
- ret = wilc_wlan_start();
+ ret = wilc_wlan_start(wilc);
if (ret < 0) {
PRINT_ER("Failed to start Firmware\n");
- goto _fail_;
+ return ret;
}
- /* wait for mac ready */
PRINT_D(INIT_DBG, "Waiting for Firmware to get ready ...\n");
- ret = linux_wlan_lock_timeout(&g_linux_wlan->sync_event, 5000);
+ ret = wilc_lock_timeout(wilc, &wilc->sync_event, 5000);
if (ret) {
PRINT_D(INIT_DBG, "Firmware start timed out");
- goto _fail_;
+ return ret;
}
- /*
- * TODO: Driver shouoldn't wait forever for firmware to get started -
- * in case of timeout this should be handled properly
- */
PRINT_D(INIT_DBG, "Firmware successfully started\n");
-_fail_:
- return ret;
+ return 0;
}
-static int linux_wlan_firmware_download(struct wilc *p_nic)
-{
+static int wilc1000_firmware_download(struct net_device *dev)
+{
+ struct wilc_vif *vif;
+ struct wilc *wilc;
int ret = 0;
- if (!g_linux_wlan->firmware) {
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
+
+ if (!wilc->firmware) {
PRINT_ER("Firmware buffer is NULL\n");
- ret = -ENOBUFS;
- goto _FAIL_;
+ return -ENOBUFS;
}
- /**
- * do the firmware download
- **/
PRINT_D(INIT_DBG, "Downloading Firmware ...\n");
- ret = wilc_wlan_firmware_download(g_linux_wlan->firmware->data,
- g_linux_wlan->firmware->size);
+ ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data,
+ wilc->firmware->size);
if (ret < 0)
- goto _FAIL_;
+ return ret;
- /* Freeing FW buffer */
PRINT_D(INIT_DBG, "Freeing FW buffer ...\n");
PRINT_D(INIT_DBG, "Releasing firmware\n");
- release_firmware(g_linux_wlan->firmware);
+ release_firmware(wilc->firmware);
+ wilc->firmware = NULL;
PRINT_D(INIT_DBG, "Download Succeeded\n");
-_FAIL_:
- return ret;
+ return 0;
}
-/* startup configuration - could be changed later using iconfig*/
-static int linux_wlan_init_test_config(struct net_device *dev, struct wilc *p_nic)
+static int linux_wlan_init_test_config(struct net_device *dev,
+ struct wilc *wilc)
{
-
unsigned char c_val[64];
unsigned char mac_add[] = {0x00, 0x80, 0xC2, 0x5E, 0xa2, 0xff};
struct wilc_priv *priv;
- struct host_if_drv *pstrWFIDrv;
+ struct host_if_drv *hif_drv;
PRINT_D(TX_DBG, "Start configuring Firmware\n");
get_random_bytes(&mac_add[5], 1);
get_random_bytes(&mac_add[4], 1);
priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
- pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
- PRINT_D(INIT_DBG, "Host = %p\n", pstrWFIDrv);
+ hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
+ PRINT_D(INIT_DBG, "Host = %p\n", hif_drv);
- PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n", mac_add[0], mac_add[1], mac_add[2], mac_add[3], mac_add[4], mac_add[5]);
- wilc_get_chipid(0);
+ PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n",
+ mac_add[0], mac_add[1], mac_add[2],
+ mac_add[3], mac_add[4], mac_add[5]);
+ wilc_get_chipid(wilc, 0);
*(int *)c_val = 1;
- if (!wilc_wlan_cfg_set(1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0))
goto _fail_;
- /*to tell fw that we are going to use PC test - WILC specific*/
c_val[0] = 0;
- if (!wilc_wlan_cfg_set(0, WID_PC_TEST_MODE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = INFRASTRUCTURE;
- if (!wilc_wlan_cfg_set(0, WID_BSS_TYPE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_BSS_TYPE, c_val, 1, 0, 0))
goto _fail_;
- /* c_val[0] = RATE_AUTO; */
c_val[0] = RATE_AUTO;
- if (!wilc_wlan_cfg_set(0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = G_MIXED_11B_2_MODE;
- if (!wilc_wlan_cfg_set(0, WID_11G_OPERATING_MODE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11G_OPERATING_MODE, c_val, 1, 0,
+ 0))
goto _fail_;
c_val[0] = 1;
- if (!wilc_wlan_cfg_set(0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = G_SHORT_PREAMBLE;
- if (!wilc_wlan_cfg_set(0, WID_PREAMBLE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_PREAMBLE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = AUTO_PROT;
- if (!wilc_wlan_cfg_set(0, WID_11N_PROT_MECH, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = ACTIVE_SCAN;
- if (!wilc_wlan_cfg_set(0, WID_SCAN_TYPE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_SCAN_TYPE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = SITE_SURVEY_OFF;
- if (!wilc_wlan_cfg_set(0, WID_SITE_SURVEY, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_SITE_SURVEY, c_val, 1, 0, 0))
goto _fail_;
- *((int *)c_val) = 0xffff; /* Never use RTS-CTS */
- if (!wilc_wlan_cfg_set(0, WID_RTS_THRESHOLD, c_val, 2, 0, 0))
+ *((int *)c_val) = 0xffff;
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0))
goto _fail_;
*((int *)c_val) = 2346;
- if (!wilc_wlan_cfg_set(0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0))
goto _fail_;
- /* SSID */
- /* -------------------------------------------------------------- */
- /* Configuration : String with length less than 32 bytes */
- /* Values to set : Any string with length less than 32 bytes */
- /* ( In BSS Station Set SSID to "" (null string) */
- /* to enable Broadcast SSID suppport ) */
- /* -------------------------------------------------------------- */
c_val[0] = 0;
- if (!wilc_wlan_cfg_set(0, WID_BCAST_SSID, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_BCAST_SSID, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = 1;
- if (!wilc_wlan_cfg_set(0, WID_QOS_ENABLE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_QOS_ENABLE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = NO_POWERSAVE;
- if (!wilc_wlan_cfg_set(0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0))
goto _fail_;
- c_val[0] = NO_ENCRYPT; /* NO_ENCRYPT, 0x79 */
- if (!wilc_wlan_cfg_set(0, WID_11I_MODE, c_val, 1, 0, 0))
+ c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11I_MODE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = OPEN_SYSTEM;
- if (!wilc_wlan_cfg_set(0, WID_AUTH_TYPE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_AUTH_TYPE, c_val, 1, 0, 0))
goto _fail_;
- /* WEP/802 11I Configuration */
- /* ------------------------------------------------------------------ */
- /* Configuration : WEP Key */
- /* Values (0x) : 5 byte for WEP40 and 13 bytes for WEP104 */
- /* In case more than 5 bytes are passed on for WEP 40 */
- /* only first 5 bytes will be used as the key */
- /* ------------------------------------------------------------------ */
-
strcpy(c_val, "123456790abcdef1234567890");
- if (!wilc_wlan_cfg_set(0, WID_WEP_KEY_VALUE, c_val, (strlen(c_val) + 1), 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_WEP_KEY_VALUE, c_val,
+ (strlen(c_val) + 1), 0, 0))
goto _fail_;
- /* WEP/802 11I Configuration */
- /* ------------------------------------------------------------------ */
- /* Configuration : AES/TKIP WPA/RSNA Pre-Shared Key */
- /* Values to set : Any string with length greater than equal to 8 bytes */
- /* and less than 64 bytes */
- /* ------------------------------------------------------------------ */
strcpy(c_val, "12345678");
- if (!wilc_wlan_cfg_set(0, WID_11I_PSK, c_val, (strlen(c_val)), 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0,
+ 0))
goto _fail_;
- /* IEEE802.1X Key Configuration */
- /* ------------------------------------------------------------------ */
- /* Configuration : Radius Server Access Secret Key */
- /* Values to set : Any string with length greater than equal to 8 bytes */
- /* and less than 65 bytes */
- /* ------------------------------------------------------------------ */
strcpy(c_val, "password");
- if (!wilc_wlan_cfg_set(0, WID_1X_KEY, c_val, (strlen(c_val) + 1), 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1),
+ 0, 0))
goto _fail_;
- /* IEEE802.1X Server Address Configuration */
- /* ------------------------------------------------------------------ */
- /* Configuration : Radius Server IP Address */
- /* Values to set : Any valid IP Address */
- /* ------------------------------------------------------------------ */
c_val[0] = 192;
c_val[1] = 168;
c_val[2] = 1;
c_val[3] = 112;
- if (!wilc_wlan_cfg_set(0, WID_1X_SERV_ADDR, c_val, 4, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0))
goto _fail_;
c_val[0] = 3;
- if (!wilc_wlan_cfg_set(0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = 3;
- if (!wilc_wlan_cfg_set(0, WID_DTIM_PERIOD, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = NORMAL_ACK;
- if (!wilc_wlan_cfg_set(0, WID_ACK_POLICY, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_ACK_POLICY, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = 0;
- if (!wilc_wlan_cfg_set(0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1,
+ 0, 0))
goto _fail_;
c_val[0] = 48;
- if (!wilc_wlan_cfg_set(0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0,
+ 0))
goto _fail_;
c_val[0] = 28;
- if (!wilc_wlan_cfg_set(0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0,
+ 0))
goto _fail_;
- /* Beacon Interval */
- /* -------------------------------------------------------------------- */
- /* Configuration : Sets the beacon interval value */
- /* Values to set : Any 16-bit value */
- /* -------------------------------------------------------------------- */
-
*((int *)c_val) = 100;
- if (!wilc_wlan_cfg_set(0, WID_BEACON_INTERVAL, c_val, 2, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0))
goto _fail_;
c_val[0] = REKEY_DISABLE;
- if (!wilc_wlan_cfg_set(0, WID_REKEY_POLICY, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_POLICY, c_val, 1, 0, 0))
goto _fail_;
- /* Rekey Time (s) (Used only when the Rekey policy is 2 or 4) */
- /* -------------------------------------------------------------------- */
- /* Configuration : Sets the Rekey Time (s) */
- /* Values to set : 32-bit value */
- /* -------------------------------------------------------------------- */
*((int *)c_val) = 84600;
- if (!wilc_wlan_cfg_set(0, WID_REKEY_PERIOD, c_val, 4, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0))
goto _fail_;
- /* Rekey Packet Count (in 1000s; used when Rekey Policy is 3) */
- /* -------------------------------------------------------------------- */
- /* Configuration : Sets Rekey Group Packet count */
- /* Values to set : 32-bit Value */
- /* -------------------------------------------------------------------- */
*((int *)c_val) = 500;
- if (!wilc_wlan_cfg_set(0, WID_REKEY_PACKET_COUNT, c_val, 4, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0,
+ 0))
goto _fail_;
c_val[0] = 1;
- if (!wilc_wlan_cfg_set(0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0,
+ 0))
goto _fail_;
c_val[0] = G_SELF_CTS_PROT;
- if (!wilc_wlan_cfg_set(0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0))
goto _fail_;
- c_val[0] = 1; /* Enable N */
- if (!wilc_wlan_cfg_set(0, WID_11N_ENABLE, c_val, 1, 0, 0))
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_ENABLE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = HT_MIXED_MODE;
- if (!wilc_wlan_cfg_set(0, WID_11N_OPERATING_MODE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_OPERATING_MODE, c_val, 1, 0,
+ 0))
goto _fail_;
- c_val[0] = 1; /* TXOP Prot disable in N mode: No RTS-CTS on TX A-MPDUs to save air-time. */
- if (!wilc_wlan_cfg_set(0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0, 0))
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0,
+ 0))
goto _fail_;
memcpy(c_val, mac_add, 6);
- if (!wilc_wlan_cfg_set(0, WID_MAC_ADDR, c_val, 6, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_MAC_ADDR, c_val, 6, 0, 0))
goto _fail_;
- /**
- * AP only
- **/
c_val[0] = DETECT_PROTECT_REPORT;
- if (!wilc_wlan_cfg_set(0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1,
+ 0, 0))
goto _fail_;
c_val[0] = RTS_CTS_NONHT_PROT;
- if (!wilc_wlan_cfg_set(0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = 0;
- if (!wilc_wlan_cfg_set(0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0,
+ 0))
goto _fail_;
c_val[0] = MIMO_MODE;
- if (!wilc_wlan_cfg_set(0, WID_11N_SMPS_MODE, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0))
goto _fail_;
c_val[0] = 7;
- if (!wilc_wlan_cfg_set(0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0, 0))
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0,
+ 0))
goto _fail_;
- c_val[0] = 1; /* Enable N with immediate block ack. */
- if (!wilc_wlan_cfg_set(0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1, 1, 1))
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(wilc, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1,
+ 1, 1))
goto _fail_;
return 0;
@@ -884,14 +732,13 @@ _fail_:
return -1;
}
-/**************************/
void wilc1000_wlan_deinit(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wl;
- nic = netdev_priv(dev);
- wl = nic->wilc;
+ vif = netdev_priv(dev);
+ wl = vif->wilc;
if (!wl) {
netdev_err(dev, "wl is NULL\n");
@@ -901,20 +748,14 @@ void wilc1000_wlan_deinit(struct net_device *dev)
if (wl->initialized) {
netdev_info(dev, "Deinitializing wilc1000...\n");
-#if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31)
- /* johnny : remove */
- PRINT_D(INIT_DBG, "skip wilc_bus_set_default_speed\n");
-#else
- wilc_bus_set_default_speed();
-#endif
-
PRINT_D(INIT_DBG, "Disabling IRQ\n");
-#ifdef WILC_SDIO
- mutex_lock(&wl->hif_cs);
- disable_sdio_interrupt();
- mutex_unlock(&wl->hif_cs);
-#endif
- if (&wl->txq_event != NULL)
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt) {
+ mutex_lock(&wl->hif_cs);
+ wl->hif_func->disable_interrupt(wl);
+ mutex_unlock(&wl->hif_cs);
+ }
+ if (&wl->txq_event)
up(&wl->txq_event);
PRINT_D(INIT_DBG, "Deinitializing Threads\n");
@@ -923,25 +764,25 @@ void wilc1000_wlan_deinit(struct net_device *dev)
PRINT_D(INIT_DBG, "Deinitializing IRQ\n");
deinit_irq(dev);
- wilc_wlan_stop();
+ wilc_wlan_stop(wl);
PRINT_D(INIT_DBG, "Deinitializing WILC Wlan\n");
wilc_wlan_cleanup(dev);
-#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO)
- #if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31)
- PRINT_D(INIT_DBG, "Disabling IRQ 2\n");
-
- mutex_lock(&wl->hif_cs);
- disable_sdio_interrupt();
- mutex_unlock(&wl->hif_cs);
- #endif
+#if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31)
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt) {
+
+ PRINT_D(INIT_DBG, "Disabling IRQ 2\n");
+
+ mutex_lock(&wl->hif_cs);
+ wl->hif_func->disable_interrupt(wl);
+ mutex_unlock(&wl->hif_cs);
+ }
#endif
- /*De-Initialize locks*/
PRINT_D(INIT_DBG, "Deinitializing Locks\n");
wlan_deinit_locks(dev);
- /* announce that wilc1000 is not initialized */
wl->initialized = false;
PRINT_D(INIT_DBG, "wilc1000 deinitialization Done\n");
@@ -951,13 +792,13 @@ void wilc1000_wlan_deinit(struct net_device *dev)
}
}
-int wlan_init_locks(struct net_device *dev)
+static int wlan_init_locks(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wl;
- nic = netdev_priv(dev);
- wl = nic->wilc;
+ vif = netdev_priv(dev);
+ wl = vif->wilc;
PRINT_D(INIT_DBG, "Initializing Locks ...\n");
@@ -979,105 +820,68 @@ int wlan_init_locks(struct net_device *dev)
static int wlan_deinit_locks(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
PRINT_D(INIT_DBG, "De-Initializing Locks\n");
- if (&wilc->hif_cs != NULL)
+ if (&wilc->hif_cs)
mutex_destroy(&wilc->hif_cs);
- if (&wilc->rxq_cs != NULL)
+ if (&wilc->rxq_cs)
mutex_destroy(&wilc->rxq_cs);
return 0;
}
-void linux_to_wlan(wilc_wlan_inp_t *nwi, struct wilc *nic)
-{
-
- PRINT_D(INIT_DBG, "Linux to Wlan services ...\n");
-
- nwi->os_context.os_private = (void *)nic;
-#ifdef WILC_SDIO
- nwi->io_func.io_type = HIF_SDIO;
- nwi->io_func.io_init = linux_sdio_init;
- nwi->io_func.io_deinit = linux_sdio_deinit;
- nwi->io_func.u.sdio.sdio_cmd52 = linux_sdio_cmd52;
- nwi->io_func.u.sdio.sdio_cmd53 = linux_sdio_cmd53;
- nwi->io_func.u.sdio.sdio_set_max_speed = linux_sdio_set_max_speed;
- nwi->io_func.u.sdio.sdio_set_default_speed = linux_sdio_set_default_speed;
-#else
- nwi->io_func.io_type = HIF_SPI;
- nwi->io_func.io_init = linux_spi_init;
- nwi->io_func.io_deinit = linux_spi_deinit;
- nwi->io_func.u.spi.spi_tx = linux_spi_write;
- nwi->io_func.u.spi.spi_rx = linux_spi_read;
- nwi->io_func.u.spi.spi_trx = linux_spi_write_read;
- nwi->io_func.u.spi.spi_max_speed = linux_spi_set_max_speed;
-#endif
-}
-
-int wlan_initialize_threads(struct net_device *dev)
+static int wlan_initialize_threads(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- int ret = 0;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
PRINT_D(INIT_DBG, "Initializing Threads ...\n");
-
- /* create tx task */
PRINT_D(INIT_DBG, "Creating kthread for transmission\n");
wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev,
"K_TXQ_TASK");
if (!wilc->txq_thread) {
PRINT_ER("couldn't create TXQ thread\n");
- ret = -ENOBUFS;
- goto _fail_2;
+ wilc->close = 0;
+ return -ENOBUFS;
}
- /* wait for TXQ task to start. */
down(&wilc->txq_thread_started);
return 0;
-
-_fail_2:
- /*De-Initialize 2nd thread*/
- wilc->close = 0;
- return ret;
}
static void wlan_deinitialize_threads(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wl;
-
- nic = netdev_priv(dev);
- wl = nic->wilc;
+ vif = netdev_priv(dev);
+ wl = vif->wilc;
wl->close = 1;
PRINT_D(INIT_DBG, "Deinitializing Threads\n");
- if (&wl->txq_event != NULL)
+ if (&wl->txq_event)
up(&wl->txq_event);
- if (wl->txq_thread != NULL) {
+ if (wl->txq_thread) {
kthread_stop(wl->txq_thread);
wl->txq_thread = NULL;
}
}
-int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic)
+int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif)
{
- wilc_wlan_inp_t nwi;
- perInterface_wlan_t *nic = p_nic;
int ret = 0;
- struct wilc *wl = nic->wilc;
+ struct wilc *wl = vif->wilc;
if (!wl->initialized) {
wl->mac_status = WILC_MAC_STATUS_INIT;
@@ -1085,22 +889,18 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic)
wlan_init_locks(dev);
- linux_to_wlan(&nwi, wl);
-
- ret = wilc_wlan_init(&nwi);
+ ret = wilc_wlan_init(dev);
if (ret < 0) {
PRINT_ER("Initializing WILC_Wlan FAILED\n");
ret = -EIO;
goto _fail_locks_;
}
-#if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO)
- if (init_irq(dev)) {
+ if (wl->gpio >= 0 && init_irq(dev)) {
PRINT_ER("couldn't initialize IRQ\n");
ret = -EIO;
goto _fail_locks_;
}
-#endif
ret = wlan_initialize_threads(dev);
if (ret < 0) {
@@ -1109,39 +909,35 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic)
goto _fail_wilc_wlan_;
}
-#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO)
- if (enable_sdio_interrupt()) {
+ if (!wl->dev_irq_num &&
+ wl->hif_func->enable_interrupt &&
+ wl->hif_func->enable_interrupt(wl)) {
PRINT_ER("couldn't initialize IRQ\n");
ret = -EIO;
goto _fail_irq_init_;
}
-#endif
- if (linux_wlan_get_firmware(nic)) {
+ if (wilc_wlan_get_firmware(dev)) {
PRINT_ER("Can't get firmware\n");
ret = -EIO;
goto _fail_irq_enable_;
}
- /*Download firmware*/
- ret = linux_wlan_firmware_download(wl);
+ ret = wilc1000_firmware_download(dev);
if (ret < 0) {
PRINT_ER("Failed to download firmware\n");
ret = -EIO;
goto _fail_irq_enable_;
}
- /* Start firmware*/
- ret = linux_wlan_start_firmware(nic);
+ ret = linux_wlan_start_firmware(dev);
if (ret < 0) {
PRINT_ER("Failed to start firmware\n");
ret = -EIO;
goto _fail_irq_enable_;
}
- wilc_bus_set_max_speed();
-
- if (wilc_wlan_cfg_get(1, WID_FIRMWARE_VERSION, 1, 0)) {
+ if (wilc_wlan_cfg_get(wl, 1, WID_FIRMWARE_VERSION, 1, 0)) {
int size;
char Firmware_ver[20];
@@ -1151,7 +947,6 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic)
Firmware_ver[size] = '\0';
PRINT_D(INIT_DBG, "***** Firmware Ver = %s *******\n", Firmware_ver);
}
- /* Initialize firmware with default configuration */
ret = linux_wlan_init_test_config(dev, wl);
if (ret < 0) {
@@ -1161,20 +956,19 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic)
}
wl->initialized = true;
- return 0; /*success*/
+ return 0;
_fail_fw_start_:
- wilc_wlan_stop();
+ wilc_wlan_stop(wl);
_fail_irq_enable_:
-#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO)
- disable_sdio_interrupt();
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt)
+ wl->hif_func->disable_interrupt(wl);
_fail_irq_init_:
-#endif
-#if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO)
- deinit_irq(dev);
+ if (wl->dev_irq_num)
+ deinit_irq(dev);
-#endif
wlan_deinitialize_threads(dev);
_fail_wilc_wlan_:
wilc_wlan_cleanup(dev);
@@ -1187,44 +981,36 @@ _fail_locks_:
return ret;
}
-/*
- * - this function will be called automatically by OS when module inserted.
- */
-
-int mac_init_fn(struct net_device *ndev)
+static int mac_init_fn(struct net_device *ndev)
{
-
- /*Why we do this !!!*/
- netif_start_queue(ndev); /* ma */
- netif_stop_queue(ndev); /* ma */
+ netif_start_queue(ndev);
+ netif_stop_queue(ndev);
return 0;
}
-/* This fn is called, when this device is setup using ifconfig */
-int mac_open(struct net_device *ndev)
+int wilc_mac_open(struct net_device *ndev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
+ struct wilc *wilc;
- /*No need for setting mac address here anymore,*/
- /*Just set it in init_test_config()*/
unsigned char mac_add[ETH_ALEN] = {0};
int ret = 0;
int i = 0;
struct wilc_priv *priv;
struct wilc *wl;
- nic = netdev_priv(ndev);
- wl = nic->wilc;
+ vif = netdev_priv(ndev);
+ wl = vif->wilc;
-#ifdef WILC_SPI
- if (!wl|| !wl->wilc_spidev) {
+ if (!wl|| !wl->dev) {
netdev_err(ndev, "wilc1000: SPI device not ready\n");
return -ENODEV;
}
-#endif
- nic = netdev_priv(ndev);
- priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy);
+
+ vif = netdev_priv(ndev);
+ wilc = vif->wilc;
+ priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
PRINT_D(INIT_DBG, "MAC OPEN[%p]\n", ndev);
ret = wilc_init_host_int(ndev);
@@ -1234,153 +1020,143 @@ int mac_open(struct net_device *ndev)
return ret;
}
- /*initialize platform*/
PRINT_D(INIT_DBG, "*** re-init ***\n");
- ret = wilc1000_wlan_init(ndev, nic);
+ ret = wilc1000_wlan_init(ndev, vif);
if (ret < 0) {
PRINT_ER("Failed to initialize wilc1000\n");
wilc_deinit_host_int(ndev);
return ret;
}
- Set_machw_change_vir_if(ndev, false);
+ wilc_set_machw_change_vir_if(ndev, false);
- host_int_get_MacAddress(priv->hWILCWFIDrv, mac_add);
+ wilc_get_mac_address(vif, mac_add);
PRINT_D(INIT_DBG, "Mac address: %pM\n", mac_add);
- /* loop through the NUM of supported devices and set the MAC address */
for (i = 0; i < wl->vif_num; i++) {
- if (ndev == wl->vif[i].ndev) {
- memcpy(wl->vif[i].src_addr, mac_add, ETH_ALEN);
- wl->vif[i].hif_drv = priv->hWILCWFIDrv;
+ if (ndev == wl->vif[i]->ndev) {
+ memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
break;
}
}
- /* TODO: get MAC address whenever the source is EPROM - hardcoded and copy it to ndev*/
- memcpy(ndev->dev_addr, wl->vif[i].src_addr, ETH_ALEN);
+ memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
if (!is_valid_ether_addr(ndev->dev_addr)) {
PRINT_ER("Error: Wrong MAC address\n");
- ret = -EINVAL;
- goto _err_;
+ wilc_deinit_host_int(ndev);
+ wilc1000_wlan_deinit(ndev);
+ return -EINVAL;
}
- wilc_mgmt_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev->ieee80211_ptr,
- nic->g_struct_frame_reg[0].frame_type, nic->g_struct_frame_reg[0].reg);
- wilc_mgmt_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev->ieee80211_ptr,
- nic->g_struct_frame_reg[1].frame_type, nic->g_struct_frame_reg[1].reg);
+ wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
+ vif->ndev->ieee80211_ptr,
+ vif->g_struct_frame_reg[0].frame_type,
+ vif->g_struct_frame_reg[0].reg);
+ wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
+ vif->ndev->ieee80211_ptr,
+ vif->g_struct_frame_reg[1].frame_type,
+ vif->g_struct_frame_reg[1].reg);
netif_wake_queue(ndev);
wl->open_ifcs++;
- nic->mac_opened = 1;
+ vif->mac_opened = 1;
return 0;
-
-_err_:
- wilc_deinit_host_int(ndev);
- wilc1000_wlan_deinit(ndev);
- return ret;
}
-struct net_device_stats *mac_stats(struct net_device *dev)
+static struct net_device_stats *mac_stats(struct net_device *dev)
{
- perInterface_wlan_t *nic = netdev_priv(dev);
+ struct wilc_vif *vif= netdev_priv(dev);
- return &nic->netstats;
+ return &vif->netstats;
}
-/* Setup the multicast filter */
static void wilc_set_multicast_list(struct net_device *dev)
{
-
struct netdev_hw_addr *ha;
struct wilc_priv *priv;
- struct host_if_drv *pstrWFIDrv;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
int i = 0;
priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
- pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
+ vif = netdev_priv(dev);
+ hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
if (!dev)
return;
- PRINT_D(INIT_DBG, "Setting Multicast List with count = %d.\n", dev->mc.count);
+ PRINT_D(INIT_DBG, "Setting Multicast List with count = %d.\n",
+ dev->mc.count);
if (dev->flags & IFF_PROMISC) {
- /* Normally, we should configure the chip to retrive all packets
- * but we don't wanna support this right now */
- /* TODO: add promiscuous mode support */
PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets\n");
return;
}
- /* If there's more addresses than we handle, get all multicast
- * packets and sort them out in software. */
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) {
+ if ((dev->flags & IFF_ALLMULTI) ||
+ (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) {
PRINT_D(INIT_DBG, "Disable multicast filter, retrive all multicast packets\n");
- /* get all multicast packets */
- host_int_setup_multicast_filter(pstrWFIDrv, false, 0);
+ wilc_setup_multicast_filter(vif, false, 0);
return;
}
- /* No multicast? Just get our own stuff */
if ((dev->mc.count) == 0) {
PRINT_D(INIT_DBG, "Enable multicast filter, retrive directed packets only.\n");
- host_int_setup_multicast_filter(pstrWFIDrv, true, 0);
+ wilc_setup_multicast_filter(vif, true, 0);
return;
}
- /* Store all of the multicast addresses in the hardware filter */
- netdev_for_each_mc_addr(ha, dev)
- {
- memcpy(gau8MulticastMacAddrList[i], ha->addr, ETH_ALEN);
+ netdev_for_each_mc_addr(ha, dev) {
+ memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN);
PRINT_D(INIT_DBG, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i,
- gau8MulticastMacAddrList[i][0], gau8MulticastMacAddrList[i][1], gau8MulticastMacAddrList[i][2], gau8MulticastMacAddrList[i][3], gau8MulticastMacAddrList[i][4], gau8MulticastMacAddrList[i][5]);
+ wilc_multicast_mac_addr_list[i][0],
+ wilc_multicast_mac_addr_list[i][1],
+ wilc_multicast_mac_addr_list[i][2],
+ wilc_multicast_mac_addr_list[i][3],
+ wilc_multicast_mac_addr_list[i][4],
+ wilc_multicast_mac_addr_list[i][5]);
i++;
}
- host_int_setup_multicast_filter(pstrWFIDrv, true, (dev->mc.count));
+ wilc_setup_multicast_filter(vif, true, (dev->mc.count));
return;
-
}
static void linux_wlan_tx_complete(void *priv, int status)
{
-
struct tx_complete_data *pv_data = (struct tx_complete_data *)priv;
if (status == 1)
PRINT_D(TX_DBG, "Packet sent successfully - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb);
else
PRINT_D(TX_DBG, "Couldn't send packet - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb);
- /* Free the SK Buffer, its work is done */
dev_kfree_skb(pv_data->skb);
kfree(pv_data);
}
-int mac_xmit(struct sk_buff *skb, struct net_device *ndev)
+int wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct tx_complete_data *tx_data = NULL;
- int QueueCount;
- char *pu8UdpBuffer;
+ int queue_count;
+ char *udp_buf;
struct iphdr *ih;
struct ethhdr *eth_h;
struct wilc *wilc;
- nic = netdev_priv(ndev);
- wilc = nic->wilc;
+ vif = netdev_priv(ndev);
+ wilc = vif->wilc;
PRINT_D(TX_DBG, "Sending packet just received from TCP/IP\n");
- /* Stop the network interface queue */
if (skb->dev != ndev) {
PRINT_ER("Packet not destined to this device\n");
return 0;
}
- tx_data = kmalloc(sizeof(struct tx_complete_data), GFP_ATOMIC);
- if (tx_data == NULL) {
+ tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
+ if (!tx_data) {
PRINT_ER("Failed to allocate memory for tx_data structure\n");
dev_kfree_skb(skb);
netif_wake_queue(ndev);
@@ -1395,59 +1171,55 @@ int mac_xmit(struct sk_buff *skb, struct net_device *ndev)
if (eth_h->h_proto == 0x8e88)
PRINT_D(INIT_DBG, "EAPOL transmitted\n");
- /*get source and dest ip addresses*/
ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
- pu8UdpBuffer = (char *)ih + sizeof(struct iphdr);
- if ((pu8UdpBuffer[1] == 68 && pu8UdpBuffer[3] == 67) || (pu8UdpBuffer[1] == 67 && pu8UdpBuffer[3] == 68))
- PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n", pu8UdpBuffer[248], pu8UdpBuffer[249], pu8UdpBuffer[250]);
+ udp_buf = (char *)ih + sizeof(struct iphdr);
+ if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
+ (udp_buf[1] == 67 && udp_buf[3] == 68))
+ PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n",
+ udp_buf[248], udp_buf[249], udp_buf[250]);
PRINT_D(TX_DBG, "Sending packet - Size = %d - Address = %p - SKB = %p\n", tx_data->size, tx_data->buff, tx_data->skb);
-
- /* Send packet to MAC HW - for now the tx_complete function will be just status
- * indicator. still not sure if I need to suspend host transmission till the tx_complete
- * function called or not?
- * allocated buffer will be freed in tx_complete function.
- */
PRINT_D(TX_DBG, "Adding tx packet to TX Queue\n");
- nic->netstats.tx_packets++;
- nic->netstats.tx_bytes += tx_data->size;
- tx_data->pBssid = wilc->vif[nic->u8IfIdx].bssid;
- QueueCount = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
- tx_data->buff, tx_data->size,
- linux_wlan_tx_complete);
-
- if (QueueCount > FLOW_CONTROL_UPPER_THRESHOLD) {
- netif_stop_queue(wilc->vif[0].ndev);
- netif_stop_queue(wilc->vif[1].ndev);
+ vif->netstats.tx_packets++;
+ vif->netstats.tx_bytes += tx_data->size;
+ tx_data->pBssid = wilc->vif[vif->u8IfIdx]->bssid;
+ queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
+ tx_data->buff, tx_data->size,
+ linux_wlan_tx_complete);
+
+ if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
+ netif_stop_queue(wilc->vif[0]->ndev);
+ netif_stop_queue(wilc->vif[1]->ndev);
}
return 0;
}
-int mac_close(struct net_device *ndev)
+int wilc_mac_close(struct net_device *ndev)
{
struct wilc_priv *priv;
- perInterface_wlan_t *nic;
- struct host_if_drv *pstrWFIDrv;
+ struct wilc_vif *vif;
+ struct host_if_drv *hif_drv;
struct wilc *wl;
- nic = netdev_priv(ndev);
+ vif = netdev_priv(ndev);
- if ((nic == NULL) || (nic->wilc_netdev == NULL) || (nic->wilc_netdev->ieee80211_ptr == NULL) || (nic->wilc_netdev->ieee80211_ptr->wiphy == NULL)) {
- PRINT_ER("nic = NULL\n");
+ if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
+ !vif->ndev->ieee80211_ptr->wiphy) {
+ PRINT_ER("vif = NULL\n");
return 0;
}
- priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy);
- wl = nic->wilc;
+ priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
+ wl = vif->wilc;
- if (priv == NULL) {
+ if (!priv) {
PRINT_ER("priv = NULL\n");
return 0;
}
- pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
+ hif_drv = (struct host_if_drv *)priv->hWILCWFIDrv;
PRINT_D(GENERIC_DBG, "Mac close\n");
@@ -1456,8 +1228,8 @@ int mac_close(struct net_device *ndev)
return 0;
}
- if (pstrWFIDrv == NULL) {
- PRINT_ER("pstrWFIDrv = NULL\n");
+ if (!hif_drv) {
+ PRINT_ER("hif_drv = NULL\n");
return 0;
}
@@ -1468,11 +1240,10 @@ int mac_close(struct net_device *ndev)
return 0;
}
- if (nic->wilc_netdev != NULL) {
- /* Stop the network interface queue */
- netif_stop_queue(nic->wilc_netdev);
+ if (vif->ndev) {
+ netif_stop_queue(vif->ndev);
- wilc_deinit_host_int(nic->wilc_netdev);
+ wilc_deinit_host_int(vif->ndev);
}
if (wl->open_ifcs == 0) {
@@ -1483,59 +1254,54 @@ int mac_close(struct net_device *ndev)
}
up(&close_exit_sync);
- nic->mac_opened = 0;
+ vif->mac_opened = 0;
return 0;
}
-int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
+static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
{
-
u8 *buff = NULL;
s8 rssi;
u32 size = 0, length = 0;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc_priv *priv;
- s32 s32Error = 0;
+ s32 ret = 0;
struct wilc *wilc;
- /* struct iwreq *wrq = (struct iwreq *) req; // tony moved to case SIOCSIWPRIV */
- nic = netdev_priv(ndev);
- wilc = nic->wilc;
+ vif = netdev_priv(ndev);
+ wilc = vif->wilc;
if (!wilc->initialized)
return 0;
switch (cmd) {
-
- /* ]] 2013-06-24 */
case SIOCSIWPRIV:
{
- struct iwreq *wrq = (struct iwreq *) req; /* added by tony */
+ struct iwreq *wrq = (struct iwreq *) req;
size = wrq->u.data.length;
if (size && wrq->u.data.pointer) {
-
- buff = memdup_user(wrq->u.data.pointer, wrq->u.data.length);
+ buff = memdup_user(wrq->u.data.pointer,
+ wrq->u.data.length);
if (IS_ERR(buff))
return PTR_ERR(buff);
if (strncasecmp(buff, "RSSI", length) == 0) {
- priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy);
- s32Error = host_int_get_rssi(priv->hWILCWFIDrv, &(rssi));
- if (s32Error)
+ priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
+ ret = wilc_get_rssi(vif, &rssi);
+ if (ret)
PRINT_ER("Failed to send get rssi param's message queue ");
PRINT_INFO(GENERIC_DBG, "RSSI :%d\n", rssi);
- /*Rounding up the rssi negative value*/
rssi += 5;
snprintf(buff, size, "rssi %d", rssi);
if (copy_to_user(wrq->u.data.pointer, buff, size)) {
PRINT_ER("%s: failed to copy data to user buffer\n", __func__);
- s32Error = -EFAULT;
+ ret = -EFAULT;
goto done;
}
}
@@ -1546,7 +1312,7 @@ int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
default:
{
PRINT_INFO(GENERIC_DBG, "Command - %d - has been received\n", cmd);
- s32Error = -EOPNOTSUPP;
+ ret = -EOPNOTSUPP;
goto done;
}
}
@@ -1555,64 +1321,47 @@ done:
kfree(buff);
- return s32Error;
+ return ret;
}
-void frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
+void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
{
-
unsigned int frame_len = 0;
int stats;
unsigned char *buff_to_send = NULL;
struct sk_buff *skb;
struct net_device *wilc_netdev;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
- wilc_netdev = GetIfHandler(wilc, buff);
- if (wilc_netdev == NULL)
+ wilc_netdev = get_if_handler(wilc, buff);
+ if (!wilc_netdev)
return;
buff += pkt_offset;
- nic = netdev_priv(wilc_netdev);
+ vif = netdev_priv(wilc_netdev);
if (size > 0) {
-
frame_len = size;
buff_to_send = buff;
- /* Need to send the packet up to the host, allocate a skb buffer */
skb = dev_alloc_skb(frame_len);
- if (skb == NULL) {
+ if (!skb) {
PRINT_ER("Low memory - packet droped\n");
return;
}
- if (wilc == NULL || wilc_netdev == NULL)
+ if (!wilc || !wilc_netdev)
PRINT_ER("wilc_netdev in wilc is NULL");
skb->dev = wilc_netdev;
- if (skb->dev == NULL)
+ if (!skb->dev)
PRINT_ER("skb->dev is NULL\n");
- /*
- * for(i=0;i<40;i++)
- * {
- * if(i<frame_len)
- * WILC_PRINTF("buff_to_send[%d]=%2x\n",i,buff_to_send[i]);
- *
- * }*/
-
- /* skb_put(skb, frame_len); */
memcpy(skb_put(skb, frame_len), buff_to_send, frame_len);
- /* WILC_PRINTF("After MEM_CPY\n"); */
-
- /* nic = netdev_priv(wilc_netdev); */
-
skb->protocol = eth_type_trans(skb, wilc_netdev);
- /* Send the packet to the stack by giving it to the bridge */
- nic->netstats.rx_packets++;
- nic->netstats.rx_bytes += frame_len;
+ vif->netstats.rx_packets++;
+ vif->netstats.rx_bytes += frame_len;
skb->ip_summed = CHECKSUM_UNNECESSARY;
stats = netif_rx(skb);
PRINT_D(RX_DBG, "netif_rx ret value is: %d\n", stats);
@@ -1622,211 +1371,132 @@ void frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
{
int i = 0;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
- /*Pass the frame on the monitor interface, if any.*/
- /*Otherwise, pass it on p2p0 netdev, if registered on it*/
for (i = 0; i < wilc->vif_num; i++) {
- nic = netdev_priv(wilc->vif[i].ndev);
- if (nic->monitor_flag) {
+ vif = netdev_priv(wilc->vif[i]->ndev);
+ if (vif->monitor_flag) {
WILC_WFI_monitor_rx(buff, size);
return;
}
}
- nic = netdev_priv(wilc->vif[1].ndev); /* p2p0 */
- if ((buff[0] == nic->g_struct_frame_reg[0].frame_type && nic->g_struct_frame_reg[0].reg) ||
- (buff[0] == nic->g_struct_frame_reg[1].frame_type && nic->g_struct_frame_reg[1].reg))
- WILC_WFI_p2p_rx(wilc->vif[1].ndev, buff, size);
+ vif = netdev_priv(wilc->vif[1]->ndev);
+ if ((buff[0] == vif->g_struct_frame_reg[0].frame_type && vif->g_struct_frame_reg[0].reg) ||
+ (buff[0] == vif->g_struct_frame_reg[1].frame_type && vif->g_struct_frame_reg[1].reg))
+ WILC_WFI_p2p_rx(wilc->vif[1]->ndev, buff, size);
}
-void wl_wlan_cleanup(void)
+void wilc_netdev_cleanup(struct wilc *wilc)
{
int i = 0;
- perInterface_wlan_t *nic[NUM_CONCURRENT_IFC];
+ struct wilc_vif *vif[NUM_CONCURRENT_IFC];
- if (g_linux_wlan &&
- (g_linux_wlan->vif[0].ndev || g_linux_wlan->vif[1].ndev)) {
+ if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
unregister_inetaddr_notifier(&g_dev_notifier);
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
- nic[i] = netdev_priv(g_linux_wlan->vif[i].ndev);
+ vif[i] = netdev_priv(wilc->vif[i]->ndev);
}
- if (g_linux_wlan && g_linux_wlan->firmware)
- release_firmware(g_linux_wlan->firmware);
+ if (wilc && wilc->firmware)
+ release_firmware(wilc->firmware);
- if (g_linux_wlan &&
- (g_linux_wlan->vif[0].ndev || g_linux_wlan->vif[1].ndev)) {
- linux_wlan_lock_timeout(&close_exit_sync, 12 * 1000);
+ if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
+ wilc_lock_timeout(wilc, &close_exit_sync, 12 * 1000);
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
- if (g_linux_wlan->vif[i].ndev)
- if (nic[i]->mac_opened)
- mac_close(g_linux_wlan->vif[i].ndev);
+ if (wilc->vif[i]->ndev)
+ if (vif[i]->mac_opened)
+ wilc_mac_close(wilc->vif[i]->ndev);
for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
- unregister_netdev(g_linux_wlan->vif[i].ndev);
- wilc_free_wiphy(g_linux_wlan->vif[i].ndev);
- free_netdev(g_linux_wlan->vif[i].ndev);
+ unregister_netdev(wilc->vif[i]->ndev);
+ wilc_free_wiphy(wilc->vif[i]->ndev);
+ free_netdev(wilc->vif[i]->ndev);
}
}
- kfree(g_linux_wlan);
-
-#if defined(WILC_DEBUGFS)
- wilc_debugfs_remove();
-#endif
- linux_wlan_device_detection(0);
- linux_wlan_device_power(0);
+ kfree(wilc);
}
+EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
-int wilc_netdev_init(struct wilc **wilc)
+int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
+ int gpio, const struct wilc_hif_func *ops)
{
int i;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct net_device *ndev;
+ struct wilc *wl;
sema_init(&close_exit_sync, 0);
- /*create the common structure*/
- g_linux_wlan = kzalloc(sizeof(*g_linux_wlan), GFP_KERNEL);
- if (!g_linux_wlan)
+ wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+ if (!wl)
return -ENOMEM;
- *wilc = g_linux_wlan;
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->gpio = gpio;
+ wl->hif_func = ops;
register_inetaddr_notifier(&g_dev_notifier);
for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
- /*allocate first ethernet device with perinterface_wlan_t as its private data*/
- ndev = alloc_etherdev(sizeof(perInterface_wlan_t));
+ ndev = alloc_etherdev(sizeof(struct wilc_vif));
if (!ndev) {
PRINT_ER("Failed to allocate ethernet dev\n");
return -1;
}
- nic = netdev_priv(ndev);
- memset(nic, 0, sizeof(perInterface_wlan_t));
+ vif = netdev_priv(ndev);
+ memset(vif, 0, sizeof(struct wilc_vif));
- /*Name the Devices*/
- if (i == 0) {
- #if defined(NM73131) /* tony, 2012-09-20 */
- strcpy(ndev->name, "wilc_eth%d");
- #elif defined(PLAT_CLM9722) /* rachel */
- strcpy(ndev->name, "eth%d");
- #else /* PANDA_BOARD, PLAT_ALLWINNER_A10, PLAT_ALLWINNER_A20, PLAT_ALLWINNER_A31, PLAT_AML8726_M3 or PLAT_WMS8304 */
+ if (i == 0)
strcpy(ndev->name, "wlan%d");
- #endif
- } else
+ else
strcpy(ndev->name, "p2p%d");
- nic->u8IfIdx = g_linux_wlan->vif_num;
- nic->wilc_netdev = ndev;
- nic->wilc = *wilc;
- g_linux_wlan->vif[g_linux_wlan->vif_num].ndev = ndev;
- g_linux_wlan->vif_num++;
+ vif->u8IfIdx = wl->vif_num;
+ vif->wilc = *wilc;
+ wl->vif[i] = vif;
+ wl->vif[wl->vif_num]->ndev = ndev;
+ wl->vif_num++;
ndev->netdev_ops = &wilc_netdev_ops;
{
struct wireless_dev *wdev;
- /*Register WiFi*/
- wdev = wilc_create_wiphy(ndev);
+ wdev = wilc_create_wiphy(ndev, dev);
- #ifdef WILC_SDIO
- /* set netdev, tony */
- SET_NETDEV_DEV(ndev, &local_sdio_func->dev);
- #endif
+ if (dev)
+ SET_NETDEV_DEV(ndev, dev);
- if (wdev == NULL) {
+ if (!wdev) {
PRINT_ER("Can't register WILC Wiphy\n");
return -1;
}
- /*linking the wireless_dev structure with the netdevice*/
- nic->wilc_netdev->ieee80211_ptr = wdev;
- nic->wilc_netdev->ml_priv = nic;
- wdev->netdev = nic->wilc_netdev;
- nic->netstats.rx_packets = 0;
- nic->netstats.tx_packets = 0;
- nic->netstats.rx_bytes = 0;
- nic->netstats.tx_bytes = 0;
-
+ vif->ndev->ieee80211_ptr = wdev;
+ vif->ndev->ml_priv = vif;
+ wdev->netdev = vif->ndev;
+ vif->netstats.rx_packets = 0;
+ vif->netstats.tx_packets = 0;
+ vif->netstats.rx_bytes = 0;
+ vif->netstats.tx_bytes = 0;
}
if (register_netdev(ndev)) {
- PRINT_ER("Device couldn't be registered - %s\n", ndev->name);
- return -1; /* ERROR */
+ PRINT_ER("Device couldn't be registered - %s\n",
+ ndev->name);
+ return -1;
}
- nic->iftype = STATION_MODE;
- nic->mac_opened = 0;
-
- }
-
- #ifndef WILC_SDIO
- if (!linux_spi_init(&g_linux_wlan->wilc_spidev)) {
- PRINT_ER("Can't initialize SPI\n");
- return -1; /* ERROR */
+ vif->iftype = STATION_MODE;
+ vif->mac_opened = 0;
}
- g_linux_wlan->wilc_spidev = wilc_spi_dev;
- #else
- g_linux_wlan->wilc_sdio_func = local_sdio_func;
- #endif
return 0;
}
-
-/*The 1st function called after module inserted*/
-static int __init init_wilc_driver(void)
-{
-#ifdef WILC_SPI
- struct wilc *wilc;
-#endif
-
-#if defined(WILC_DEBUGFS)
- if (wilc_debugfs_init() < 0) {
- PRINT_D(GENERIC_DBG, "fail to create debugfs for wilc driver\n");
- return -1;
- }
-#endif
-
- printk("IN INIT FUNCTION\n");
- printk("*** WILC1000 driver VERSION=[10.2] FW_VER=[10.2] ***\n");
-
- linux_wlan_device_power(1);
- msleep(100);
- linux_wlan_device_detection(1);
-
-#ifdef WILC_SDIO
- {
- int ret;
-
- ret = sdio_register_driver(&wilc_bus);
- if (ret < 0)
- PRINT_D(INIT_DBG, "init_wilc_driver: Failed register sdio driver\n");
-
- return ret;
- }
-#else
- PRINT_D(INIT_DBG, "Initializing netdev\n");
- if (wilc_netdev_init(&wilc))
- PRINT_ER("Couldn't initialize netdev\n");
- return 0;
-#endif
-}
-late_initcall(init_wilc_driver);
-
-static void __exit exit_wilc_driver(void)
-{
-#ifndef WILC_SDIO
- PRINT_D(INIT_DBG, "SPI unregister...\n");
- spi_unregister_driver(&wilc_bus);
-#else
- PRINT_D(INIT_DBG, "SDIO unregister...\n");
- sdio_unregister_driver(&wilc_bus);
-#endif
-}
-module_exit(exit_wilc_driver);
+EXPORT_SYMBOL_GPL(wilc_netdev_init);
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wilc1000/linux_wlan_common.h b/drivers/staging/wilc1000/linux_wlan_common.h
index 2b76e41ebd4d..5d40f05124c1 100644
--- a/drivers/staging/wilc1000/linux_wlan_common.h
+++ b/drivers/staging/wilc1000/linux_wlan_common.h
@@ -38,11 +38,8 @@ enum debug_region {
#define FIRM_DBG (1 << Firmware_debug)
#if defined (WILC_DEBUGFS)
-int wilc_debugfs_init(void);
-void wilc_debugfs_remove(void);
-
-extern atomic_t REGION;
-extern atomic_t DEBUG_LEVEL;
+extern atomic_t WILC_REGION;
+extern atomic_t WILC_DEBUG_LEVEL;
#define DEBUG BIT(0)
#define INFO BIT(1)
@@ -51,8 +48,8 @@ extern atomic_t DEBUG_LEVEL;
#define PRINT_D(region, ...) \
do { \
- if ((atomic_read(&DEBUG_LEVEL) & DEBUG) && \
- ((atomic_read(&REGION)) & (region))) { \
+ if ((atomic_read(&WILC_DEBUG_LEVEL) & DEBUG) && \
+ ((atomic_read(&WILC_REGION)) & (region))) { \
printk("DBG [%s: %d]", __func__, __LINE__); \
printk(__VA_ARGS__); \
} \
@@ -60,8 +57,8 @@ extern atomic_t DEBUG_LEVEL;
#define PRINT_INFO(region, ...) \
do { \
- if ((atomic_read(&DEBUG_LEVEL) & INFO) && \
- ((atomic_read(&REGION)) & (region))) { \
+ if ((atomic_read(&WILC_DEBUG_LEVEL) & INFO) && \
+ ((atomic_read(&WILC_REGION)) & (region))) { \
printk("INFO [%s]", __func__); \
printk(__VA_ARGS__); \
} \
@@ -69,8 +66,8 @@ extern atomic_t DEBUG_LEVEL;
#define PRINT_WRN(region, ...) \
do { \
- if ((atomic_read(&DEBUG_LEVEL) & WRN) && \
- ((atomic_read(&REGION)) & (region))) { \
+ if ((atomic_read(&WILC_DEBUG_LEVEL) & WRN) && \
+ ((atomic_read(&WILC_REGION)) & (region))) { \
printk("WRN [%s: %d]", __func__, __LINE__); \
printk(__VA_ARGS__); \
} \
@@ -78,7 +75,7 @@ extern atomic_t DEBUG_LEVEL;
#define PRINT_ER(...) \
do { \
- if ((atomic_read(&DEBUG_LEVEL) & ERR)) { \
+ if ((atomic_read(&WILC_DEBUG_LEVEL) & ERR)) { \
printk("ERR [%s: %d]", __func__, __LINE__); \
printk(__VA_ARGS__); \
} \
@@ -121,14 +118,13 @@ extern atomic_t DEBUG_LEVEL;
printk("ERR [%s: %d]", __func__, __LINE__); \
printk(__VA_ARGS__); \
} while (0)
+
#endif
#define FN_IN /* PRINT_D(">>> \n") */
#define FN_OUT /* PRINT_D("<<<\n") */
-#ifdef MEMORY_STATIC
#define LINUX_RX_SIZE (96 * 1024)
-#endif
#define LINUX_TX_SIZE (64 * 1024)
diff --git a/drivers/staging/wilc1000/linux_wlan_sdio.c b/drivers/staging/wilc1000/linux_wlan_sdio.c
deleted file mode 100644
index 4aff953a88f1..000000000000
--- a/drivers/staging/wilc1000/linux_wlan_sdio.c
+++ /dev/null
@@ -1,251 +0,0 @@
-#include "wilc_wfi_netdevice.h"
-
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/host.h>
-
-
-
-#define SDIO_MODALIAS "wilc1000_sdio"
-
-#if defined(CUSTOMER_PLATFORM)
-/* TODO : User have to stable bus clock as user's environment. */
- #ifdef MAX_BUS_SPEED
- #define MAX_SPEED MAX_BUS_SPEED
- #else
- #define MAX_SPEED 50000000
- #endif
-#else
- #define MAX_SPEED (6 * 1000000) /* Max 50M */
-#endif
-
-struct wilc_sdio {
- struct sdio_func *func;
- struct wilc *wilc;
-};
-
-struct sdio_func *local_sdio_func;
-
-static unsigned int sdio_default_speed;
-
-#define SDIO_VENDOR_ID_WILC 0x0296
-#define SDIO_DEVICE_ID_WILC 0x5347
-
-static const struct sdio_device_id wilc_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
- { },
-};
-
-
-static void wilc_sdio_interrupt(struct sdio_func *func)
-{
- struct wilc_sdio *wl_sdio;
-
- wl_sdio = sdio_get_drvdata(func);
-
-#ifndef WILC_SDIO_IRQ_GPIO
- sdio_release_host(func);
- wilc_handle_isr(wl_sdio->wilc);
- sdio_claim_host(func);
-#endif
-}
-
-
-int linux_sdio_cmd52(sdio_cmd52_t *cmd)
-{
- struct sdio_func *func = g_linux_wlan->wilc_sdio_func;
- int ret;
- u8 data;
-
- sdio_claim_host(func);
-
- func->num = cmd->function;
- if (cmd->read_write) { /* write */
- if (cmd->raw) {
- sdio_writeb(func, cmd->data, cmd->address, &ret);
- data = sdio_readb(func, cmd->address, &ret);
- cmd->data = data;
- } else {
- sdio_writeb(func, cmd->data, cmd->address, &ret);
- }
- } else { /* read */
- data = sdio_readb(func, cmd->address, &ret);
- cmd->data = data;
- }
-
- sdio_release_host(func);
-
- if (ret < 0) {
- PRINT_ER("wilc_sdio_cmd52..failed, err(%d)\n", ret);
- return 0;
- }
- return 1;
-}
-
-
-int linux_sdio_cmd53(sdio_cmd53_t *cmd)
-{
- struct sdio_func *func = g_linux_wlan->wilc_sdio_func;
- int size, ret;
-
- sdio_claim_host(func);
-
- func->num = cmd->function;
- func->cur_blksize = cmd->block_size;
- if (cmd->block_mode)
- size = cmd->count * cmd->block_size;
- else
- size = cmd->count;
-
- if (cmd->read_write) { /* write */
- ret = sdio_memcpy_toio(func, cmd->address, (void *)cmd->buffer, size);
- } else { /* read */
- ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, cmd->address, size);
- }
-
- sdio_release_host(func);
-
-
- if (ret < 0) {
- PRINT_ER("wilc_sdio_cmd53..failed, err(%d)\n", ret);
- return 0;
- }
-
- return 1;
-}
-
-static int linux_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
-{
- struct wilc_sdio *wl_sdio;
- struct wilc *wilc;
-
- PRINT_D(INIT_DBG, "probe function\n");
- wl_sdio = kzalloc(sizeof(struct wilc_sdio), GFP_KERNEL);
- if (!wl_sdio)
- return -ENOMEM;
-
- PRINT_D(INIT_DBG, "Initializing netdev\n");
- local_sdio_func = func;
- if (wilc_netdev_init(&wilc)) {
- PRINT_ER("Couldn't initialize netdev\n");
- kfree(wl_sdio);
- return -1;
- }
- wl_sdio->func = func;
- wl_sdio->wilc = wilc;
- sdio_set_drvdata(func, wl_sdio);
-
- printk("Driver Initializing success\n");
- return 0;
-}
-
-static void linux_sdio_remove(struct sdio_func *func)
-{
- struct wilc_sdio *wl_sdio;
-
- wl_sdio = sdio_get_drvdata(func);
- wl_wlan_cleanup();
- kfree(wl_sdio);
-}
-
-struct sdio_driver wilc_bus = {
- .name = SDIO_MODALIAS,
- .id_table = wilc_sdio_ids,
- .probe = linux_sdio_probe,
- .remove = linux_sdio_remove,
-};
-
-int enable_sdio_interrupt(void)
-{
- int ret = 0;
-#ifndef WILC_SDIO_IRQ_GPIO
-
- sdio_claim_host(local_sdio_func);
- ret = sdio_claim_irq(local_sdio_func, wilc_sdio_interrupt);
- sdio_release_host(local_sdio_func);
-
- if (ret < 0) {
- PRINT_ER("can't claim sdio_irq, err(%d)\n", ret);
- ret = -EIO;
- }
-#endif
- return ret;
-}
-
-void disable_sdio_interrupt(void)
-{
-
-#ifndef WILC_SDIO_IRQ_GPIO
- int ret;
-
- PRINT_D(INIT_DBG, "disable_sdio_interrupt IN\n");
-
- sdio_claim_host(local_sdio_func);
- ret = sdio_release_irq(local_sdio_func);
- if (ret < 0) {
- PRINT_ER("can't release sdio_irq, err(%d)\n", ret);
- }
- sdio_release_host(local_sdio_func);
-
- PRINT_D(INIT_DBG, "disable_sdio_interrupt OUT\n");
-#endif
-}
-
-static int linux_sdio_set_speed(int speed)
-{
- struct mmc_ios ios;
-
- sdio_claim_host(local_sdio_func);
-
- memcpy((void *)&ios, (void *)&local_sdio_func->card->host->ios, sizeof(struct mmc_ios));
- local_sdio_func->card->host->ios.clock = speed;
- ios.clock = speed;
- local_sdio_func->card->host->ops->set_ios(local_sdio_func->card->host, &ios);
- sdio_release_host(local_sdio_func);
- PRINT_INFO(INIT_DBG, "@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed);
-
- return 1;
-}
-
-static int linux_sdio_get_speed(void)
-{
- return local_sdio_func->card->host->ios.clock;
-}
-
-int linux_sdio_init(void *pv)
-{
-
- /**
- * TODO :
- **/
-
-
- sdio_default_speed = linux_sdio_get_speed();
- return 1;
-}
-
-void linux_sdio_deinit(void *pv)
-{
-
- /**
- * TODO :
- **/
-
-
- sdio_unregister_driver(&wilc_bus);
-}
-
-int linux_sdio_set_max_speed(void)
-{
- return linux_sdio_set_speed(MAX_SPEED);
-}
-
-int linux_sdio_set_default_speed(void)
-{
- return linux_sdio_set_speed(sdio_default_speed);
-}
-
-
-
diff --git a/drivers/staging/wilc1000/linux_wlan_sdio.h b/drivers/staging/wilc1000/linux_wlan_sdio.h
deleted file mode 100644
index 4b515f5108e7..000000000000
--- a/drivers/staging/wilc1000/linux_wlan_sdio.h
+++ /dev/null
@@ -1,14 +0,0 @@
-extern struct sdio_func *local_sdio_func;
-extern struct sdio_driver wilc_bus;
-
-#include <linux/mmc/sdio_func.h>
-
-int linux_sdio_init(void *);
-void linux_sdio_deinit(void *);
-int linux_sdio_cmd52(sdio_cmd52_t *cmd);
-int linux_sdio_cmd53(sdio_cmd53_t *cmd);
-int enable_sdio_interrupt(void);
-void disable_sdio_interrupt(void);
-int linux_sdio_set_max_speed(void);
-int linux_sdio_set_default_speed(void);
-
diff --git a/drivers/staging/wilc1000/linux_wlan_spi.c b/drivers/staging/wilc1000/linux_wlan_spi.c
deleted file mode 100644
index 039d06192d6b..000000000000
--- a/drivers/staging/wilc1000/linux_wlan_spi.c
+++ /dev/null
@@ -1,409 +0,0 @@
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <linux/uaccess.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-
-#include "linux_wlan_common.h"
-#include "linux_wlan_spi.h"
-
-#define USE_SPI_DMA 0 /* johnny add */
-
-#ifdef WILC_ASIC_A0
- #if defined(PLAT_PANDA_ES_OMAP4460)
- #define MIN_SPEED 12000000
- #define MAX_SPEED 24000000
- #elif defined(PLAT_WMS8304)
- #define MIN_SPEED 12000000
- #define MAX_SPEED 24000000 /* 4000000 */
- #elif defined(CUSTOMER_PLATFORM)
-/*
- TODO : define Clock speed under 48M.
- *
- * ex)
- * #define MIN_SPEED 24000000
- * #define MAX_SPEED 48000000
- */
- #else
- #define MIN_SPEED 24000000
- #define MAX_SPEED 48000000
- #endif
-#else /* WILC_ASIC_A0 */
-/* Limit clk to 6MHz on FPGA. */
- #define MIN_SPEED 6000000
- #define MAX_SPEED 6000000
-#endif /* WILC_ASIC_A0 */
-
-static u32 SPEED = MIN_SPEED;
-
-struct spi_device *wilc_spi_dev;
-void linux_spi_deinit(void *vp);
-
-static int __init wilc_bus_probe(struct spi_device *spi)
-{
-
- PRINT_D(BUS_DBG, "spiModalias: %s\n", spi->modalias);
- PRINT_D(BUS_DBG, "spiMax-Speed: %d\n", spi->max_speed_hz);
- wilc_spi_dev = spi;
-
- printk("Driver Initializing success\n");
- return 0;
-}
-
-static int __exit wilc_bus_remove(struct spi_device *spi)
-{
-
- return 0;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id wilc1000_of_match[] = {
- { .compatible = "atmel,wilc_spi", },
- {}
-};
-MODULE_DEVICE_TABLE(of, wilc1000_of_match);
-#endif
-
-struct spi_driver wilc_bus __refdata = {
- .driver = {
- .name = MODALIAS,
-#ifdef CONFIG_OF
- .of_match_table = wilc1000_of_match,
-#endif
- },
- .probe = wilc_bus_probe,
- .remove = __exit_p(wilc_bus_remove),
-};
-
-
-void linux_spi_deinit(void *vp)
-{
-
- spi_unregister_driver(&wilc_bus);
-
- SPEED = MIN_SPEED;
- PRINT_ER("@@@@@@@@@@@@ restore SPI speed to %d @@@@@@@@@\n", SPEED);
-
-}
-
-
-
-int linux_spi_init(void *vp)
-{
- int ret = 1;
- static int called;
-
-
- if (called == 0) {
- called++;
- ret = spi_register_driver(&wilc_bus);
- }
-
- /* change return value to match WILC interface */
- (ret < 0) ? (ret = 0) : (ret = 1);
-
- return ret;
-}
-
-#if defined(PLAT_WMS8304)
-#define TXRX_PHASE_SIZE (4096)
-#endif
-
-#if defined(TXRX_PHASE_SIZE)
-
-int linux_spi_write(u8 *b, u32 len)
-{
- int ret;
-
- if (len > 0 && b != NULL) {
- int i = 0;
- int blk = len / TXRX_PHASE_SIZE;
- int remainder = len % TXRX_PHASE_SIZE;
-
- char *r_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL);
- if (!r_buffer)
- return -ENOMEM;
-
- if (blk) {
- while (i < blk) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .tx_buf = b + (i * TXRX_PHASE_SIZE),
- .len = TXRX_PHASE_SIZE,
- .speed_hz = SPEED,
- .bits_per_word = 8,
- .delay_usecs = 0,
- };
-
- tr.rx_buf = r_buffer;
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA;
-
- spi_message_add_tail(&tr, &msg);
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
- i++;
-
- }
- }
- if (remainder) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .tx_buf = b + (blk * TXRX_PHASE_SIZE),
- .len = remainder,
- .speed_hz = SPEED,
- .bits_per_word = 8,
- .delay_usecs = 0,
- };
- tr.rx_buf = r_buffer;
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA; /* rachel */
-
- spi_message_add_tail(&tr, &msg);
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
- }
- kfree(r_buffer);
- } else {
- PRINT_ER("can't write data with the following length: %d\n", len);
- PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len);
- ret = -1;
- }
-
- /* change return value to match WILC interface */
- (ret < 0) ? (ret = 0) : (ret = 1);
-
- return ret;
-
-}
-
-#else
-int linux_spi_write(u8 *b, u32 len)
-{
-
- int ret;
- struct spi_message msg;
-
- if (len > 0 && b != NULL) {
- struct spi_transfer tr = {
- .tx_buf = b,
- .len = len,
- .speed_hz = SPEED,
- .delay_usecs = 0,
- };
- char *r_buffer = kzalloc(len, GFP_KERNEL);
- if (!r_buffer)
- return -ENOMEM;
-
- tr.rx_buf = r_buffer;
- PRINT_D(BUS_DBG, "Request writing %d bytes\n", len);
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
-/* [[johnny add */
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA;
-/* ]] */
- spi_message_add_tail(&tr, &msg);
-
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
-
- kfree(r_buffer);
- } else {
- PRINT_ER("can't write data with the following length: %d\n", len);
- PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len);
- ret = -1;
- }
-
- /* change return value to match WILC interface */
- (ret < 0) ? (ret = 0) : (ret = 1);
-
-
- return ret;
-}
-
-#endif
-
-#if defined(TXRX_PHASE_SIZE)
-
-int linux_spi_read(u8 *rb, u32 rlen)
-{
- int ret;
-
- if (rlen > 0) {
- int i = 0;
-
- int blk = rlen / TXRX_PHASE_SIZE;
- int remainder = rlen % TXRX_PHASE_SIZE;
-
- char *t_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL);
- if (!t_buffer)
- return -ENOMEM;
-
- if (blk) {
- while (i < blk) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .rx_buf = rb + (i * TXRX_PHASE_SIZE),
- .len = TXRX_PHASE_SIZE,
- .speed_hz = SPEED,
- .bits_per_word = 8,
- .delay_usecs = 0,
- };
- tr.tx_buf = t_buffer;
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA;
-
- spi_message_add_tail(&tr, &msg);
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
- i++;
- }
- }
- if (remainder) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .rx_buf = rb + (blk * TXRX_PHASE_SIZE),
- .len = remainder,
- .speed_hz = SPEED,
- .bits_per_word = 8,
- .delay_usecs = 0,
- };
- tr.tx_buf = t_buffer;
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA; /* rachel */
-
- spi_message_add_tail(&tr, &msg);
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
- }
-
- kfree(t_buffer);
- } else {
- PRINT_ER("can't read data with the following length: %u\n", rlen);
- ret = -1;
- }
- /* change return value to match WILC interface */
- (ret < 0) ? (ret = 0) : (ret = 1);
-
- return ret;
-}
-
-#else
-int linux_spi_read(u8 *rb, u32 rlen)
-{
-
- int ret;
-
- if (rlen > 0) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .rx_buf = rb,
- .len = rlen,
- .speed_hz = SPEED,
- .delay_usecs = 0,
-
- };
- char *t_buffer = kzalloc(rlen, GFP_KERNEL);
- if (!t_buffer)
- return -ENOMEM;
-
- tr.tx_buf = t_buffer;
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
-/* [[ johnny add */
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA;
-/* ]] */
- spi_message_add_tail(&tr, &msg);
-
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
- kfree(t_buffer);
- } else {
- PRINT_ER("can't read data with the following length: %u\n", rlen);
- ret = -1;
- }
- /* change return value to match WILC interface */
- (ret < 0) ? (ret = 0) : (ret = 1);
-
- return ret;
-}
-
-#endif
-
-int linux_spi_write_read(u8 *wb, u8 *rb, u32 rlen)
-{
-
- int ret;
-
- if (rlen > 0) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .rx_buf = rb,
- .tx_buf = wb,
- .len = rlen,
- .speed_hz = SPEED,
- .bits_per_word = 8,
- .delay_usecs = 0,
-
- };
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = wilc_spi_dev;
- msg.is_dma_mapped = USE_SPI_DMA;
-
- spi_message_add_tail(&tr, &msg);
- ret = spi_sync(wilc_spi_dev, &msg);
- if (ret < 0) {
- PRINT_ER("SPI transaction failed\n");
- }
- } else {
- PRINT_ER("can't read data with the following length: %u\n", rlen);
- ret = -1;
- }
- /* change return value to match WILC interface */
- (ret < 0) ? (ret = 0) : (ret = 1);
-
- return ret;
-}
-
-int linux_spi_set_max_speed(void)
-{
- SPEED = MAX_SPEED;
-
- PRINT_INFO(BUS_DBG, "@@@@@@@@@@@@ change SPI speed to %d @@@@@@@@@\n", SPEED);
- return 1;
-}
diff --git a/drivers/staging/wilc1000/linux_wlan_spi.h b/drivers/staging/wilc1000/linux_wlan_spi.h
deleted file mode 100644
index 7356785296f9..000000000000
--- a/drivers/staging/wilc1000/linux_wlan_spi.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef LINUX_WLAN_SPI_H
-#define LINUX_WLAN_SPI_H
-
-#include <linux/spi/spi.h>
-extern struct spi_device *wilc_spi_dev;
-extern struct spi_driver wilc_bus;
-
-int linux_spi_init(void *vp);
-void linux_spi_deinit(void *vp);
-int linux_spi_write(u8 *b, u32 len);
-int linux_spi_read(u8 *rb, u32 rlen);
-int linux_spi_write_read(u8 *wb, u8 *rb, u32 rlen);
-int linux_spi_set_max_speed(void);
-#endif
diff --git a/drivers/staging/wilc1000/wilc_debugfs.c b/drivers/staging/wilc1000/wilc_debugfs.c
index ae111862e7a9..27c653a0cdf9 100644
--- a/drivers/staging/wilc1000/wilc_debugfs.c
+++ b/drivers/staging/wilc1000/wilc_debugfs.c
@@ -26,8 +26,10 @@ static struct dentry *wilc_dir;
#define DBG_REGION_ALL (GENERIC_DBG | HOSTAPD_DBG | HOSTINF_DBG | CORECONFIG_DBG | CFG80211_DBG | INT_DBG | TX_DBG | RX_DBG | LOCK_DBG | INIT_DBG | BUS_DBG | MEM_DBG)
#define DBG_LEVEL_ALL (DEBUG | INFO | WRN | ERR)
-atomic_t REGION = ATOMIC_INIT(INIT_DBG | GENERIC_DBG | CFG80211_DBG | FIRM_DBG | HOSTAPD_DBG);
-atomic_t DEBUG_LEVEL = ATOMIC_INIT(ERR);
+atomic_t WILC_REGION = ATOMIC_INIT(INIT_DBG | GENERIC_DBG | CFG80211_DBG | FIRM_DBG | HOSTAPD_DBG);
+EXPORT_SYMBOL_GPL(WILC_REGION);
+atomic_t WILC_DEBUG_LEVEL = ATOMIC_INIT(ERR);
+EXPORT_SYMBOL_GPL(WILC_DEBUG_LEVEL);
/*
* --------------------------------------------------------------------------------
@@ -43,7 +45,7 @@ static ssize_t wilc_debug_level_read(struct file *file, char __user *userbuf, si
if (*ppos > 0)
return 0;
- res = scnprintf(buf, sizeof(buf), "Debug Level: %x\n", atomic_read(&DEBUG_LEVEL));
+ res = scnprintf(buf, sizeof(buf), "Debug Level: %x\n", atomic_read(&WILC_DEBUG_LEVEL));
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
@@ -59,11 +61,11 @@ static ssize_t wilc_debug_level_write(struct file *filp, const char __user *buf,
return ret;
if (flag > DBG_LEVEL_ALL) {
- printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&DEBUG_LEVEL));
+ printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&WILC_DEBUG_LEVEL));
return -EINVAL;
}
- atomic_set(&DEBUG_LEVEL, (int)flag);
+ atomic_set(&WILC_DEBUG_LEVEL, (int)flag);
if (flag == 0)
printk("Debug-level disabled\n");
@@ -82,7 +84,7 @@ static ssize_t wilc_debug_region_read(struct file *file, char __user *userbuf, s
if (*ppos > 0)
return 0;
- res = scnprintf(buf, sizeof(buf), "Debug region: %x\n", atomic_read(&REGION));
+ res = scnprintf(buf, sizeof(buf), "Debug region: %x\n", atomic_read(&WILC_REGION));
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
@@ -102,12 +104,12 @@ static ssize_t wilc_debug_region_write(struct file *filp, const char *buf, size_
flag = buffer[0] - '0';
if (flag > DBG_REGION_ALL) {
- printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&REGION));
+ printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&WILC_REGION));
return -EFAULT;
}
- atomic_set(&REGION, (int)flag);
- printk("new debug-region is %x\n", atomic_read(&REGION));
+ atomic_set(&WILC_REGION, (int)flag);
+ printk("new debug-region is %x\n", atomic_read(&WILC_REGION));
return count;
}
@@ -136,7 +138,7 @@ static struct wilc_debugfs_info_t debugfs_info[] = {
{ "wilc_debug_region", 0666, (INIT_DBG | GENERIC_DBG | CFG80211_DBG), FOPS(NULL, wilc_debug_region_read, wilc_debug_region_write, NULL), },
};
-int wilc_debugfs_init(void)
+static int __init wilc_debugfs_init(void)
{
int i;
@@ -171,11 +173,13 @@ int wilc_debugfs_init(void)
}
return 0;
}
+module_init(wilc_debugfs_init);
-void wilc_debugfs_remove(void)
+static void __exit wilc_debugfs_remove(void)
{
debugfs_remove_recursive(wilc_dir);
}
+module_exit(wilc_debugfs_remove);
#endif
diff --git a/drivers/staging/wilc1000/wilc_msgqueue.c b/drivers/staging/wilc1000/wilc_msgqueue.c
index 0eff121b8291..098390cdf319 100644
--- a/drivers/staging/wilc1000/wilc_msgqueue.c
+++ b/drivers/staging/wilc1000/wilc_msgqueue.c
@@ -115,7 +115,6 @@ int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
u32 *pu32ReceivedLength)
{
Message *pstrMessage;
- int result = 0;
unsigned long flags;
if ((!pHandle) || (u32RecvBufferSize == 0)
@@ -135,12 +134,6 @@ int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
down(&pHandle->hSem);
- /* other non-timeout scenarios */
- if (result) {
- PRINT_ER("Non-timeout\n");
- return result;
- }
-
if (pHandle->bExiting) {
PRINT_ER("pHandle fail\n");
return -EFAULT;
@@ -174,5 +167,5 @@ int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
- return result;
+ return 0;
}
diff --git a/drivers/staging/wilc1000/wilc_msgqueue.h b/drivers/staging/wilc1000/wilc_msgqueue.h
index d231c334ed93..d7e0328bacee 100644
--- a/drivers/staging/wilc1000/wilc_msgqueue.h
+++ b/drivers/staging/wilc1000/wilc_msgqueue.h
@@ -35,7 +35,7 @@ typedef struct __MessageQueue_struct {
* any other message queue having the same name in the system
* @param[in,out] pHandle handle to the message queue object
* @param[in] pstrAttrs Optional attributes, NULL for default
- * @return Error code indicating sucess/failure
+ * @return Error code indicating success/failure
* @author syounan
* @date 30 Aug 2010
* @version 1.0
@@ -44,7 +44,7 @@ int wilc_mq_create(WILC_MsgQueueHandle *pHandle);
/*!
* @brief Sends a message
- * @details Sends a message, this API will block unil the message is
+ * @details Sends a message, this API will block until the message is
* actually sent or until it is timedout (as long as the feature
* CONFIG_WILC_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout
* is not set to WILC_OS_INFINITY), zero timeout is a valid value
@@ -52,7 +52,7 @@ int wilc_mq_create(WILC_MsgQueueHandle *pHandle);
* @param[in] pvSendBuffer pointer to the data to send
* @param[in] u32SendBufferSize the size of the data to send
* @param[in] pstrAttrs Optional attributes, NULL for default
- * @return Error code indicating sucess/failure
+ * @return Error code indicating success/failure
* @author syounan
* @date 30 Aug 2010
* @version 1.0
@@ -62,7 +62,7 @@ int wilc_mq_send(WILC_MsgQueueHandle *pHandle,
/*!
* @brief Receives a message
- * @details Receives a message, this API will block unil a message is
+ * @details Receives a message, this API will block until a message is
* received or until it is timedout (as long as the feature
* CONFIG_WILC_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout
* is not set to WILC_OS_INFINITY), zero timeout is a valid value
@@ -71,7 +71,7 @@ int wilc_mq_send(WILC_MsgQueueHandle *pHandle,
* @param[in] u32RecvBufferSize the size of the receive buffer
* @param[out] pu32ReceivedLength the length of received data
* @param[in] pstrAttrs Optional attributes, NULL for default
- * @return Error code indicating sucess/failure
+ * @return Error code indicating success/failure
* @author syounan
* @date 30 Aug 2010
* @version 1.0
@@ -84,7 +84,7 @@ int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
* @brief Destroys an existing Message queue
* @param[in] pHandle handle to the message queue object
* @param[in] pstrAttrs Optional attributes, NULL for default
- * @return Error code indicating sucess/failure
+ * @return Error code indicating success/failure
* @author syounan
* @date 30 Aug 2010
* @version 1.0
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index 300c571e4e2d..e961b5004902 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -10,17 +10,29 @@
#include <linux/string.h>
#include "wilc_wlan_if.h"
#include "wilc_wlan.h"
+#include "wilc_wfi_netdevice.h"
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/host.h>
+#include <linux/of_gpio.h>
+
+#define SDIO_MODALIAS "wilc1000_sdio"
+
+#define SDIO_VENDOR_ID_WILC 0x0296
+#define SDIO_DEVICE_ID_WILC 0x5347
+
+static const struct sdio_device_id wilc_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
+ { },
+};
#define WILC_SDIO_BLOCK_SIZE 512
typedef struct {
- void *os_context;
+ bool irq_gpio;
u32 block_size;
- int (*sdio_cmd52)(sdio_cmd52_t *);
- int (*sdio_cmd53)(sdio_cmd53_t *);
- int (*sdio_set_max_speed)(void);
- int (*sdio_set_default_speed)(void);
- wilc_debug_func dPrint;
int nint;
#define MAX_NUN_INT_THRPT_ENH2 (5) /* Max num interrupts allowed in registers 0xf7, 0xf8 */
int has_thrpt_enh3;
@@ -28,10 +40,155 @@ typedef struct {
static wilc_sdio_t g_sdio;
-#ifdef WILC_SDIO_IRQ_GPIO
-static int sdio_write_reg(u32 addr, u32 data);
-static int sdio_read_reg(u32 addr, u32 *data);
-#endif
+static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data);
+static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data);
+
+static void wilc_sdio_interrupt(struct sdio_func *func)
+{
+ sdio_release_host(func);
+ wilc_handle_isr(sdio_get_drvdata(func));
+ sdio_claim_host(func);
+}
+
+static int wilc_sdio_cmd52(struct wilc *wilc, sdio_cmd52_t *cmd)
+{
+ struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
+ int ret;
+ u8 data;
+
+ sdio_claim_host(func);
+
+ func->num = cmd->function;
+ if (cmd->read_write) { /* write */
+ if (cmd->raw) {
+ sdio_writeb(func, cmd->data, cmd->address, &ret);
+ data = sdio_readb(func, cmd->address, &ret);
+ cmd->data = data;
+ } else {
+ sdio_writeb(func, cmd->data, cmd->address, &ret);
+ }
+ } else { /* read */
+ data = sdio_readb(func, cmd->address, &ret);
+ cmd->data = data;
+ }
+
+ sdio_release_host(func);
+
+ if (ret)
+ dev_err(&func->dev, "wilc_sdio_cmd52..failed, err(%d)\n", ret);
+ return ret;
+}
+
+
+static int wilc_sdio_cmd53(struct wilc *wilc, sdio_cmd53_t *cmd)
+{
+ struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
+ int size, ret;
+
+ sdio_claim_host(func);
+
+ func->num = cmd->function;
+ func->cur_blksize = cmd->block_size;
+ if (cmd->block_mode)
+ size = cmd->count * cmd->block_size;
+ else
+ size = cmd->count;
+
+ if (cmd->read_write) { /* write */
+ ret = sdio_memcpy_toio(func, cmd->address,
+ (void *)cmd->buffer, size);
+ } else { /* read */
+ ret = sdio_memcpy_fromio(func, (void *)cmd->buffer,
+ cmd->address, size);
+ }
+
+ sdio_release_host(func);
+
+ if (ret)
+ dev_err(&func->dev, "wilc_sdio_cmd53..failed, err(%d)\n", ret);
+
+ return ret;
+}
+
+static int linux_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct wilc *wilc;
+ int gpio, ret;
+
+ gpio = -1;
+ if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
+ gpio = of_get_gpio(func->dev.of_node, 0);
+ if (gpio < 0)
+ gpio = GPIO_NUM;
+ }
+
+ dev_dbg(&func->dev, "Initializing netdev\n");
+ ret = wilc_netdev_init(&wilc, &func->dev, HIF_SDIO, gpio,
+ &wilc_hif_sdio);
+ if (ret) {
+ dev_err(&func->dev, "Couldn't initialize netdev\n");
+ return ret;
+ }
+ sdio_set_drvdata(func, wilc);
+ wilc->dev = &func->dev;
+
+ dev_info(&func->dev, "Driver Initializing success\n");
+ return 0;
+}
+
+static void linux_sdio_remove(struct sdio_func *func)
+{
+ wilc_netdev_cleanup(sdio_get_drvdata(func));
+}
+
+static struct sdio_driver wilc1000_sdio_driver = {
+ .name = SDIO_MODALIAS,
+ .id_table = wilc_sdio_ids,
+ .probe = linux_sdio_probe,
+ .remove = linux_sdio_remove,
+};
+module_driver(wilc1000_sdio_driver,
+ sdio_register_driver,
+ sdio_unregister_driver);
+MODULE_LICENSE("GPL");
+
+static int wilc_sdio_enable_interrupt(struct wilc *dev)
+{
+ struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
+ int ret = 0;
+
+ sdio_claim_host(func);
+ ret = sdio_claim_irq(func, wilc_sdio_interrupt);
+ sdio_release_host(func);
+
+ if (ret < 0) {
+ dev_err(&func->dev, "can't claim sdio_irq, err(%d)\n", ret);
+ ret = -EIO;
+ }
+ return ret;
+}
+
+static void wilc_sdio_disable_interrupt(struct wilc *dev)
+{
+ struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
+ int ret;
+
+ dev_dbg(&func->dev, "wilc_sdio_disable_interrupt IN\n");
+
+ sdio_claim_host(func);
+ ret = sdio_release_irq(func);
+ if (ret < 0)
+ dev_err(&func->dev, "can't release sdio_irq, err(%d)\n", ret);
+ sdio_release_host(func);
+
+ dev_info(&func->dev, "wilc_sdio_disable_interrupt OUT\n");
+}
+
+static int wilc_sdio_init(void)
+{
+ return 1;
+}
/********************************************
*
@@ -39,9 +196,11 @@ static int sdio_read_reg(u32 addr, u32 *data);
*
********************************************/
-static int sdio_set_func0_csa_address(u32 adr)
+static int sdio_set_func0_csa_address(struct wilc *wilc, u32 adr)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
sdio_cmd52_t cmd;
+ int ret;
/**
* Review: BIG ENDIAN
@@ -51,22 +210,25 @@ static int sdio_set_func0_csa_address(u32 adr)
cmd.raw = 0;
cmd.address = 0x10c;
cmd.data = (u8)adr;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10c data...\n");
goto _fail_;
}
cmd.address = 0x10d;
cmd.data = (u8)(adr >> 8);
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10d data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10d data...\n");
goto _fail_;
}
cmd.address = 0x10e;
cmd.data = (u8)(adr >> 16);
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10e data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10e data...\n");
goto _fail_;
}
@@ -75,24 +237,28 @@ _fail_:
return 0;
}
-static int sdio_set_func0_block_size(u32 block_size)
+static int sdio_set_func0_block_size(struct wilc *wilc, u32 block_size)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
sdio_cmd52_t cmd;
+ int ret;
cmd.read_write = 1;
cmd.function = 0;
cmd.raw = 0;
cmd.address = 0x10;
cmd.data = (u8)block_size;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10 data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10 data...\n");
goto _fail_;
}
cmd.address = 0x11;
cmd.data = (u8)(block_size >> 8);
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x11 data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x11 data...\n");
goto _fail_;
}
@@ -107,23 +273,27 @@ _fail_:
*
********************************************/
-static int sdio_set_func1_block_size(u32 block_size)
+static int sdio_set_func1_block_size(struct wilc *wilc, u32 block_size)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
sdio_cmd52_t cmd;
+ int ret;
cmd.read_write = 1;
cmd.function = 0;
cmd.raw = 0;
cmd.address = 0x110;
cmd.data = (u8)block_size;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x110 data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x110 data...\n");
goto _fail_;
}
cmd.address = 0x111;
cmd.data = (u8)(block_size >> 8);
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x111 data...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x111 data...\n");
goto _fail_;
}
@@ -132,100 +302,17 @@ _fail_:
return 0;
}
-static int sdio_clear_int(void)
-{
-#ifndef WILC_SDIO_IRQ_GPIO
- /* u32 sts; */
- sdio_cmd52_t cmd;
-
- cmd.read_write = 0;
- cmd.function = 1;
- cmd.raw = 0;
- cmd.address = 0x4;
- cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
-
- return cmd.data;
-#else
- u32 reg;
-
- if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, &reg)) {
- g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0);
- return 0;
- }
- reg &= ~0x1;
- sdio_write_reg(WILC_HOST_RX_CTRL_0, reg);
- return 1;
-#endif
-
-}
-
-u32 sdio_xfer_cnt(void)
-{
- u32 cnt = 0;
- sdio_cmd52_t cmd;
-
- cmd.read_write = 0;
- cmd.function = 1;
- cmd.raw = 0;
- cmd.address = 0x1C;
- cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
- cnt = cmd.data;
-
- cmd.read_write = 0;
- cmd.function = 1;
- cmd.raw = 0;
- cmd.address = 0x1D;
- cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
- cnt |= (cmd.data << 8);
-
- cmd.read_write = 0;
- cmd.function = 1;
- cmd.raw = 0;
- cmd.address = 0x1E;
- cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
- cnt |= (cmd.data << 16);
-
- return cnt;
-}
-
/********************************************
*
* Sdio interfaces
*
********************************************/
-int sdio_check_bs(void)
+static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
{
- sdio_cmd52_t cmd;
-
- /**
- * poll until BS is 0
- **/
- cmd.read_write = 0;
- cmd.function = 0;
- cmd.raw = 0;
- cmd.address = 0xc;
- cmd.data = 0;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get BS register...\n");
- goto _fail_;
- }
-
- return 1;
-
-_fail_:
-
- return 0;
-}
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ int ret;
-static int sdio_write_reg(u32 addr, u32 data)
-{
-#ifdef BIG_ENDIAN
- data = BYTE_SWAP(data);
-#endif
+ data = cpu_to_le32(data);
if ((addr >= 0xf0) && (addr <= 0xff)) {
sdio_cmd52_t cmd;
@@ -235,8 +322,10 @@ static int sdio_write_reg(u32 addr, u32 data)
cmd.raw = 0;
cmd.address = addr;
cmd.data = data;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd 52, read reg (%08x) ...\n", addr);
goto _fail_;
}
} else {
@@ -245,7 +334,7 @@ static int sdio_write_reg(u32 addr, u32 data)
/**
* set the AHB address
**/
- if (!sdio_set_func0_csa_address(addr))
+ if (!sdio_set_func0_csa_address(wilc, addr))
goto _fail_;
cmd.read_write = 1;
@@ -256,9 +345,10 @@ static int sdio_write_reg(u32 addr, u32 data)
cmd.count = 4;
cmd.buffer = (u8 *)&data;
cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
-
- if (!g_sdio.sdio_cmd53(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, write reg (%08x)...\n", addr);
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53, write reg (%08x)...\n", addr);
goto _fail_;
}
}
@@ -270,11 +360,12 @@ _fail_:
return 0;
}
-static int sdio_write(u32 addr, u8 *buf, u32 size)
+static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
u32 block_size = g_sdio.block_size;
sdio_cmd53_t cmd;
- int nblk, nleft;
+ int nblk, nleft, ret;
cmd.read_write = 1;
if (addr > 0) {
@@ -317,11 +408,13 @@ static int sdio_write(u32 addr, u8 *buf, u32 size)
cmd.buffer = buf;
cmd.block_size = block_size;
if (addr > 0) {
- if (!sdio_set_func0_csa_address(addr))
+ if (!sdio_set_func0_csa_address(wilc, addr))
goto _fail_;
}
- if (!g_sdio.sdio_cmd53(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr);
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], block send...\n", addr);
goto _fail_;
}
if (addr > 0)
@@ -338,11 +431,13 @@ static int sdio_write(u32 addr, u8 *buf, u32 size)
cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
if (addr > 0) {
- if (!sdio_set_func0_csa_address(addr))
+ if (!sdio_set_func0_csa_address(wilc, addr))
goto _fail_;
}
- if (!g_sdio.sdio_cmd53(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr);
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], bytes send...\n", addr);
goto _fail_;
}
}
@@ -354,8 +449,11 @@ _fail_:
return 0;
}
-static int sdio_read_reg(u32 addr, u32 *data)
+static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ int ret;
+
if ((addr >= 0xf0) && (addr <= 0xff)) {
sdio_cmd52_t cmd;
@@ -363,15 +461,17 @@ static int sdio_read_reg(u32 addr, u32 *data)
cmd.function = 0;
cmd.raw = 0;
cmd.address = addr;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd 52, read reg (%08x) ...\n", addr);
goto _fail_;
}
*data = cmd.data;
} else {
sdio_cmd53_t cmd;
- if (!sdio_set_func0_csa_address(addr))
+ if (!sdio_set_func0_csa_address(wilc, addr))
goto _fail_;
cmd.read_write = 0;
@@ -383,16 +483,15 @@ static int sdio_read_reg(u32 addr, u32 *data)
cmd.buffer = (u8 *)data;
cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
-
- if (!g_sdio.sdio_cmd53(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, read reg (%08x)...\n", addr);
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53, read reg (%08x)...\n", addr);
goto _fail_;
}
}
-#ifdef BIG_ENDIAN
- *data = BYTE_SWAP(*data);
-#endif
+ *data = cpu_to_le32(*data);
return 1;
@@ -401,11 +500,12 @@ _fail_:
return 0;
}
-static int sdio_read(u32 addr, u8 *buf, u32 size)
+static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
u32 block_size = g_sdio.block_size;
sdio_cmd53_t cmd;
- int nblk, nleft;
+ int nblk, nleft, ret;
cmd.read_write = 0;
if (addr > 0) {
@@ -448,11 +548,13 @@ static int sdio_read(u32 addr, u8 *buf, u32 size)
cmd.buffer = buf;
cmd.block_size = block_size;
if (addr > 0) {
- if (!sdio_set_func0_csa_address(addr))
+ if (!sdio_set_func0_csa_address(wilc, addr))
goto _fail_;
}
- if (!g_sdio.sdio_cmd53(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr);
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], block read...\n", addr);
goto _fail_;
}
if (addr > 0)
@@ -469,11 +571,13 @@ static int sdio_read(u32 addr, u8 *buf, u32 size)
cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
if (addr > 0) {
- if (!sdio_set_func0_csa_address(addr))
+ if (!sdio_set_func0_csa_address(wilc, addr))
goto _fail_;
}
- if (!g_sdio.sdio_cmd53(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes read...\n", addr);
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], bytes read...\n", addr);
goto _fail_;
}
}
@@ -491,94 +595,29 @@ _fail_:
*
********************************************/
-static int sdio_deinit(void *pv)
+static int sdio_deinit(struct wilc *wilc)
{
return 1;
}
-static int sdio_sync(void)
-{
- u32 reg;
-
- /**
- * Disable power sequencer
- **/
- if (!sdio_read_reg(WILC_MISC, &reg)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n");
- return 0;
- }
-
- reg &= ~BIT(8);
- if (!sdio_write_reg(WILC_MISC, reg)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n");
- return 0;
- }
-
-#ifdef WILC_SDIO_IRQ_GPIO
- {
- u32 reg;
- int ret;
-
- /**
- * interrupt pin mux select
- **/
- ret = sdio_read_reg(WILC_PIN_MUX_0, &reg);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
- return 0;
- }
- reg |= BIT(8);
- ret = sdio_write_reg(WILC_PIN_MUX_0, reg);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
- return 0;
- }
-
- /**
- * interrupt enable
- **/
- ret = sdio_read_reg(WILC_INTR_ENABLE, &reg);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
- return 0;
- }
- reg |= BIT(16);
- ret = sdio_write_reg(WILC_INTR_ENABLE, reg);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
- return 0;
- }
- }
-#endif
-
- return 1;
-}
-
-static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
+static int sdio_init(struct wilc *wilc)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
sdio_cmd52_t cmd;
- int loop;
+ int loop, ret;
u32 chipid;
memset(&g_sdio, 0, sizeof(wilc_sdio_t));
- g_sdio.dPrint = func;
- g_sdio.os_context = inp->os_context.os_private;
+ g_sdio.irq_gpio = (wilc->dev_irq_num);
- if (inp->io_func.io_init) {
- if (!inp->io_func.io_init(g_sdio.os_context)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed io init bus...\n");
- return 0;
- }
+ if (!wilc_sdio_init()) {
+ dev_err(&func->dev, "Failed io init bus...\n");
+ return 0;
} else {
return 0;
}
- g_sdio.sdio_cmd52 = inp->io_func.u.sdio.sdio_cmd52;
- g_sdio.sdio_cmd53 = inp->io_func.u.sdio.sdio_cmd53;
- g_sdio.sdio_set_max_speed = inp->io_func.u.sdio.sdio_set_max_speed;
- g_sdio.sdio_set_default_speed = inp->io_func.u.sdio.sdio_set_default_speed;
-
/**
* function 0 csa enable
**/
@@ -587,16 +626,17 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
cmd.raw = 1;
cmd.address = 0x100;
cmd.data = 0x80;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, enable csa...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Fail cmd 52, enable csa...\n");
goto _fail_;
}
/**
* function 0 block size
**/
- if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set func 0 block size...\n");
+ if (!sdio_set_func0_block_size(wilc, WILC_SDIO_BLOCK_SIZE)) {
+ dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n");
goto _fail_;
}
g_sdio.block_size = WILC_SDIO_BLOCK_SIZE;
@@ -609,8 +649,10 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
cmd.raw = 1;
cmd.address = 0x2;
cmd.data = 0x2;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio] Fail cmd 52, set IOE register...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Fail cmd 52, set IOE register...\n");
goto _fail_;
}
@@ -624,8 +666,10 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
loop = 3;
do {
cmd.data = 0;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get IOR register...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Fail cmd 52, get IOR register...\n");
goto _fail_;
}
if (cmd.data == 0x2)
@@ -633,15 +677,15 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
} while (loop--);
if (loop <= 0) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail func 1 is not ready...\n");
+ dev_err(&func->dev, "Fail func 1 is not ready...\n");
goto _fail_;
}
/**
* func 1 is ready, set func 1 block size
**/
- if (!sdio_set_func1_block_size(WILC_SDIO_BLOCK_SIZE)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail set func 1 block size...\n");
+ if (!sdio_set_func1_block_size(wilc, WILC_SDIO_BLOCK_SIZE)) {
+ dev_err(&func->dev, "Fail set func 1 block size...\n");
goto _fail_;
}
@@ -653,24 +697,25 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
cmd.raw = 1;
cmd.address = 0x4;
cmd.data = 0x3;
- if (!g_sdio.sdio_cmd52(&cmd)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set IEN register...\n");
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Fail cmd 52, set IEN register...\n");
goto _fail_;
}
/**
* make sure can read back chip id correctly
**/
- if (!sdio_read_reg(0x1000, &chipid)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd read chip id...\n");
+ if (!sdio_read_reg(wilc, 0x1000, &chipid)) {
+ dev_err(&func->dev, "Fail cmd read chip id...\n");
goto _fail_;
}
- g_sdio.dPrint(N_ERR, "[wilc sdio]: chipid (%08x)\n", chipid);
+ dev_err(&func->dev, "chipid (%08x)\n", chipid);
if ((chipid & 0xfff) > 0x2a0)
g_sdio.has_thrpt_enh3 = 1;
else
g_sdio.has_thrpt_enh3 = 0;
- g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3);
+ dev_info(&func->dev, "has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3);
return 1;
@@ -679,19 +724,8 @@ _fail_:
return 0;
}
-static void sdio_set_max_speed(void)
+static int sdio_read_size(struct wilc *wilc, u32 *size)
{
- g_sdio.sdio_set_max_speed();
-}
-
-static void sdio_set_default_speed(void)
-{
- g_sdio.sdio_set_default_speed();
-}
-
-static int sdio_read_size(u32 *size)
-{
-
u32 tmp;
sdio_cmd52_t cmd;
@@ -703,7 +737,7 @@ static int sdio_read_size(u32 *size)
cmd.raw = 0;
cmd.address = 0xf2;
cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
+ wilc_sdio_cmd52(wilc, &cmd);
tmp = cmd.data;
/* cmd.read_write = 0; */
@@ -711,54 +745,53 @@ static int sdio_read_size(u32 *size)
/* cmd.raw = 0; */
cmd.address = 0xf3;
cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
+ wilc_sdio_cmd52(wilc, &cmd);
tmp |= (cmd.data << 8);
*size = tmp;
return 1;
}
-static int sdio_read_int(u32 *int_status)
+static int sdio_read_int(struct wilc *wilc, u32 *int_status)
{
-
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
u32 tmp;
sdio_cmd52_t cmd;
- sdio_read_size(&tmp);
+ sdio_read_size(wilc, &tmp);
/**
* Read IRQ flags
**/
-#ifndef WILC_SDIO_IRQ_GPIO
- cmd.function = 1;
- cmd.address = 0x04;
- cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
-
- if (cmd.data & BIT(0))
- tmp |= INT_0;
- if (cmd.data & BIT(2))
- tmp |= INT_1;
- if (cmd.data & BIT(3))
- tmp |= INT_2;
- if (cmd.data & BIT(4))
- tmp |= INT_3;
- if (cmd.data & BIT(5))
- tmp |= INT_4;
- if (cmd.data & BIT(6))
- tmp |= INT_5;
- {
+ if (!g_sdio.irq_gpio) {
int i;
+ cmd.function = 1;
+ cmd.address = 0x04;
+ cmd.data = 0;
+ wilc_sdio_cmd52(wilc, &cmd);
+
+ if (cmd.data & BIT(0))
+ tmp |= INT_0;
+ if (cmd.data & BIT(2))
+ tmp |= INT_1;
+ if (cmd.data & BIT(3))
+ tmp |= INT_2;
+ if (cmd.data & BIT(4))
+ tmp |= INT_3;
+ if (cmd.data & BIT(5))
+ tmp |= INT_4;
+ if (cmd.data & BIT(6))
+ tmp |= INT_5;
for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt (1) : tmp=%x, data=%x\n", tmp, cmd.data);
+ dev_err(&func->dev,
+ "Unexpected interrupt (1) : tmp=%x, data=%x\n",
+ tmp, cmd.data);
break;
}
}
- }
-#else
- {
+ } else {
u32 irq_flags;
cmd.read_write = 0;
@@ -766,35 +799,32 @@ static int sdio_read_int(u32 *int_status)
cmd.raw = 0;
cmd.address = 0xf7;
cmd.data = 0;
- g_sdio.sdio_cmd52(&cmd);
+ wilc_sdio_cmd52(wilc, &cmd);
irq_flags = cmd.data & 0x1f;
tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET);
}
-#endif
-
*int_status = tmp;
return 1;
}
-static int sdio_clear_int_ext(u32 val)
+static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
int ret;
if (g_sdio.has_thrpt_enh3) {
u32 reg;
-#ifdef WILC_SDIO_IRQ_GPIO
- {
+ if (g_sdio.irq_gpio) {
u32 flags;
flags = val & (BIT(MAX_NUN_INT_THRPT_ENH2) - 1);
reg = flags;
+ } else {
+ reg = 0;
}
-#else
- reg = 0;
-#endif
/* select VMM table 0 */
if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
reg |= BIT(5);
@@ -813,16 +843,17 @@ static int sdio_clear_int_ext(u32 val)
cmd.address = 0xf8;
cmd.data = reg;
- ret = g_sdio.sdio_cmd52(&cmd);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf8 data (%d) ...\n",
+ __LINE__);
goto _fail_;
}
}
} else {
-#ifdef WILC_SDIO_IRQ_GPIO
- {
+ if (g_sdio.irq_gpio) {
/* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
/* Cannot clear multiple interrupts. Must clear each interrupt individually */
u32 flags;
@@ -842,9 +873,11 @@ static int sdio_clear_int_ext(u32 val)
cmd.address = 0xf8;
cmd.data = BIT(i);
- ret = g_sdio.sdio_cmd52(&cmd);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf8 data (%d) ...\n",
+ __LINE__);
goto _fail_;
}
@@ -857,12 +890,13 @@ static int sdio_clear_int_ext(u32 val)
goto _fail_;
for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
if (flags & 1)
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt cleared %d...\n", i);
+ dev_err(&func->dev,
+ "Unexpected interrupt cleared %d...\n",
+ i);
flags >>= 1;
}
}
}
-#endif /* WILC_SDIO_IRQ_GPIO */
{
u32 vmm_ctl;
@@ -886,9 +920,11 @@ static int sdio_clear_int_ext(u32 val)
cmd.raw = 0;
cmd.address = 0xf6;
cmd.data = vmm_ctl;
- ret = g_sdio.sdio_cmd52(&cmd);
- if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf6 data (%d) ...\n", __LINE__);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf6 data (%d) ...\n",
+ __LINE__);
goto _fail_;
}
}
@@ -900,16 +936,18 @@ _fail_:
return 0;
}
-static int sdio_sync_ext(int nint /* how mant interrupts to enable. */)
+static int sdio_sync_ext(struct wilc *wilc, int nint)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
u32 reg;
if (nint > MAX_NUM_INT) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Too many interupts (%d)...\n", nint);
+ dev_err(&func->dev, "Too many interupts (%d)...\n", nint);
return 0;
}
if (nint > MAX_NUN_INT_THRPT_ENH2) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Error: Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n");
+ dev_err(&func->dev,
+ "Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n");
return 0;
}
@@ -918,71 +956,77 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */)
/**
* Disable power sequencer
**/
- if (!sdio_read_reg(WILC_MISC, &reg)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n");
+ if (!sdio_read_reg(wilc, WILC_MISC, &reg)) {
+ dev_err(&func->dev, "Failed read misc reg...\n");
return 0;
}
reg &= ~BIT(8);
- if (!sdio_write_reg(WILC_MISC, reg)) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n");
+ if (!sdio_write_reg(wilc, WILC_MISC, reg)) {
+ dev_err(&func->dev, "Failed write misc reg...\n");
return 0;
}
-#ifdef WILC_SDIO_IRQ_GPIO
- {
+ if (g_sdio.irq_gpio) {
u32 reg;
int ret, i;
/**
* interrupt pin mux select
**/
- ret = sdio_read_reg(WILC_PIN_MUX_0, &reg);
+ ret = sdio_read_reg(wilc, WILC_PIN_MUX_0, &reg);
if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
+ dev_err(&func->dev, "Failed read reg (%08x)...\n",
+ WILC_PIN_MUX_0);
return 0;
}
reg |= BIT(8);
- ret = sdio_write_reg(WILC_PIN_MUX_0, reg);
+ ret = sdio_write_reg(wilc, WILC_PIN_MUX_0, reg);
if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
+ dev_err(&func->dev, "Failed write reg (%08x)...\n",
+ WILC_PIN_MUX_0);
return 0;
}
/**
* interrupt enable
**/
- ret = sdio_read_reg(WILC_INTR_ENABLE, &reg);
+ ret = sdio_read_reg(wilc, WILC_INTR_ENABLE, &reg);
if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
+ dev_err(&func->dev, "Failed read reg (%08x)...\n",
+ WILC_INTR_ENABLE);
return 0;
}
for (i = 0; (i < 5) && (nint > 0); i++, nint--)
reg |= BIT((27 + i));
- ret = sdio_write_reg(WILC_INTR_ENABLE, reg);
+ ret = sdio_write_reg(wilc, WILC_INTR_ENABLE, reg);
if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
+ dev_err(&func->dev, "Failed write reg (%08x)...\n",
+ WILC_INTR_ENABLE);
return 0;
}
if (nint) {
- ret = sdio_read_reg(WILC_INTR2_ENABLE, &reg);
+ ret = sdio_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE);
+ dev_err(&func->dev,
+ "Failed read reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
return 0;
}
for (i = 0; (i < 3) && (nint > 0); i++, nint--)
reg |= BIT(i);
- ret = sdio_read_reg(WILC_INTR2_ENABLE, &reg);
+ ret = sdio_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
if (!ret) {
- g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE);
+ dev_err(&func->dev,
+ "Failed write reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
return 0;
}
}
}
-#endif /* WILC_SDIO_IRQ_GPIO */
return 1;
}
@@ -992,23 +1036,20 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */)
*
********************************************/
-wilc_hif_func_t hif_sdio = {
- sdio_init,
- sdio_deinit,
- sdio_read_reg,
- sdio_write_reg,
- sdio_read,
- sdio_write,
- sdio_sync,
- sdio_clear_int,
- sdio_read_int,
- sdio_clear_int_ext,
- sdio_read_size,
- sdio_write,
- sdio_read,
- sdio_sync_ext,
-
- sdio_set_max_speed,
- sdio_set_default_speed,
+const struct wilc_hif_func wilc_hif_sdio = {
+ .hif_init = sdio_init,
+ .hif_deinit = sdio_deinit,
+ .hif_read_reg = sdio_read_reg,
+ .hif_write_reg = sdio_write_reg,
+ .hif_block_rx = sdio_read,
+ .hif_block_tx = sdio_write,
+ .hif_read_int = sdio_read_int,
+ .hif_clear_int_ext = sdio_clear_int_ext,
+ .hif_read_size = sdio_read_size,
+ .hif_block_tx_ext = sdio_write,
+ .hif_block_rx_ext = sdio_read,
+ .hif_sync_ext = sdio_sync_ext,
+ .enable_interrupt = wilc_sdio_enable_interrupt,
+ .disable_interrupt = wilc_sdio_disable_interrupt,
};
diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c
index 599508beabf8..86de50c9f7f5 100644
--- a/drivers/staging/wilc1000/wilc_spi.c
+++ b/drivers/staging/wilc1000/wilc_spi.c
@@ -6,18 +6,25 @@
/* */
/* */
/* //////////////////////////////////////////////////////////////////////////// */
-
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/of_gpio.h>
+
+#include "linux_wlan_common.h"
#include <linux/string.h>
#include "wilc_wlan_if.h"
#include "wilc_wlan.h"
+#include "wilc_wfi_netdevice.h"
typedef struct {
- void *os_context;
- int (*spi_tx)(u8 *, u32);
- int (*spi_rx)(u8 *, u32);
- int (*spi_trx)(u8 *, u8 *, u32);
- int (*spi_max_speed)(void);
- wilc_debug_func dPrint;
int crc_off;
int nint;
int has_thrpt_enh;
@@ -25,8 +32,8 @@ typedef struct {
static wilc_spi_t g_spi;
-static int spi_read(u32, u8 *, u32);
-static int spi_write(u32, u8 *, u32);
+static int wilc_spi_read(struct wilc *wilc, u32, u8 *, u32);
+static int wilc_spi_write(struct wilc *wilc, u32, u8 *, u32);
/********************************************
*
@@ -111,165 +118,175 @@ static u8 crc7(u8 crc, const u8 *buffer, u32 len)
#define DATA_PKT_SZ_8K (8 * 1024)
#define DATA_PKT_SZ DATA_PKT_SZ_8K
-static int spi_cmd(u8 cmd, u32 adr, u32 data, u32 sz, u8 clockless)
+#define USE_SPI_DMA 0
+
+static const struct wilc1000_ops wilc1000_spi_ops;
+
+static int wilc_bus_probe(struct spi_device *spi)
{
- u8 bc[9];
- int len = 5;
- int result = N_OK;
+ int ret, gpio;
+ struct wilc *wilc;
- bc[0] = cmd;
- switch (cmd) {
- case CMD_SINGLE_READ: /* single word (4 bytes) read */
- bc[1] = (u8)(adr >> 16);
- bc[2] = (u8)(adr >> 8);
- bc[3] = (u8)adr;
- len = 5;
- break;
+ gpio = of_get_gpio(spi->dev.of_node, 0);
+ if (gpio < 0)
+ gpio = GPIO_NUM;
- case CMD_INTERNAL_READ: /* internal register read */
- bc[1] = (u8)(adr >> 8);
- if (clockless)
- bc[1] |= BIT(7);
- bc[2] = (u8)adr;
- bc[3] = 0x00;
- len = 5;
- break;
+ ret = wilc_netdev_init(&wilc, NULL, HIF_SPI, GPIO_NUM, &wilc_hif_spi);
+ if (ret)
+ return ret;
- case CMD_TERMINATE: /* termination */
- bc[1] = 0x00;
- bc[2] = 0x00;
- bc[3] = 0x00;
- len = 5;
- break;
+ spi_set_drvdata(spi, wilc);
+ wilc->dev = &spi->dev;
- case CMD_REPEAT: /* repeat */
- bc[1] = 0x00;
- bc[2] = 0x00;
- bc[3] = 0x00;
- len = 5;
- break;
+ return 0;
+}
- case CMD_RESET: /* reset */
- bc[1] = 0xff;
- bc[2] = 0xff;
- bc[3] = 0xff;
- len = 5;
- break;
+static int wilc_bus_remove(struct spi_device *spi)
+{
+ wilc_netdev_cleanup(spi_get_drvdata(spi));
+ return 0;
+}
- case CMD_DMA_WRITE: /* dma write */
- case CMD_DMA_READ: /* dma read */
- bc[1] = (u8)(adr >> 16);
- bc[2] = (u8)(adr >> 8);
- bc[3] = (u8)adr;
- bc[4] = (u8)(sz >> 8);
- bc[5] = (u8)(sz);
- len = 7;
- break;
+static const struct of_device_id wilc1000_of_match[] = {
+ { .compatible = "atmel,wilc_spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, wilc1000_of_match);
+
+struct spi_driver wilc1000_spi_driver = {
+ .driver = {
+ .name = MODALIAS,
+ .of_match_table = wilc1000_of_match,
+ },
+ .probe = wilc_bus_probe,
+ .remove = wilc_bus_remove,
+};
+module_spi_driver(wilc1000_spi_driver);
+MODULE_LICENSE("GPL");
- case CMD_DMA_EXT_WRITE: /* dma extended write */
- case CMD_DMA_EXT_READ: /* dma extended read */
- bc[1] = (u8)(adr >> 16);
- bc[2] = (u8)(adr >> 8);
- bc[3] = (u8)adr;
- bc[4] = (u8)(sz >> 16);
- bc[5] = (u8)(sz >> 8);
- bc[6] = (u8)(sz);
- len = 8;
- break;
+static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+ struct spi_message msg;
- case CMD_INTERNAL_WRITE: /* internal register write */
- bc[1] = (u8)(adr >> 8);
- if (clockless)
- bc[1] |= BIT(7);
- bc[2] = (u8)(adr);
- bc[3] = (u8)(data >> 24);
- bc[4] = (u8)(data >> 16);
- bc[5] = (u8)(data >> 8);
- bc[6] = (u8)(data);
- len = 8;
- break;
+ if (len > 0 && b) {
+ struct spi_transfer tr = {
+ .tx_buf = b,
+ .len = len,
+ .delay_usecs = 0,
+ };
+ char *r_buffer = kzalloc(len, GFP_KERNEL);
- case CMD_SINGLE_WRITE: /* single word write */
- bc[1] = (u8)(adr >> 16);
- bc[2] = (u8)(adr >> 8);
- bc[3] = (u8)(adr);
- bc[4] = (u8)(data >> 24);
- bc[5] = (u8)(data >> 16);
- bc[6] = (u8)(data >> 8);
- bc[7] = (u8)(data);
- len = 9;
- break;
+ if (!r_buffer)
+ return -ENOMEM;
- default:
- result = N_FAIL;
- break;
- }
+ tr.rx_buf = r_buffer;
+ dev_dbg(&spi->dev, "Request writing %d bytes\n", len);
- if (result) {
- if (!g_spi.crc_off)
- bc[len - 1] = (crc7(0x7f, (const u8 *)&bc[0], len - 1)) << 1;
- else
- len -= 1;
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+ spi_message_add_tail(&tr, &msg);
- if (!g_spi.spi_tx(bc, len)) {
- PRINT_ER("[wilc spi]: Failed cmd write, bus error...\n");
- result = N_FAIL;
- }
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+
+ kfree(r_buffer);
+ } else {
+ dev_err(&spi->dev,
+ "can't write data with the following length: %d\n",
+ len);
+ dev_err(&spi->dev,
+ "FAILED due to NULL buffer or ZERO length check the following length: %d\n",
+ len);
+ ret = -EINVAL;
}
- return result;
+ return ret;
}
-static int spi_cmd_rsp(u8 cmd)
+static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen)
{
- u8 rsp;
- int result = N_OK;
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
- /**
- * Command/Control response
- **/
- if ((cmd == CMD_RESET) ||
- (cmd == CMD_TERMINATE) ||
- (cmd == CMD_REPEAT)) {
- if (!g_spi.spi_rx(&rsp, 1)) {
- result = N_FAIL;
- goto _fail_;
- }
- }
+ if (rlen > 0) {
+ struct spi_message msg;
+ struct spi_transfer tr = {
+ .rx_buf = rb,
+ .len = rlen,
+ .delay_usecs = 0,
- if (!g_spi.spi_rx(&rsp, 1)) {
- PRINT_ER("[wilc spi]: Failed cmd response read, bus error...\n");
- result = N_FAIL;
- goto _fail_;
- }
+ };
+ char *t_buffer = kzalloc(rlen, GFP_KERNEL);
- if (rsp != cmd) {
- PRINT_ER("[wilc spi]: Failed cmd response, cmd (%02x), resp (%02x)\n", cmd, rsp);
- result = N_FAIL;
- goto _fail_;
- }
+ if (!t_buffer)
+ return -ENOMEM;
- /**
- * State response
- **/
- if (!g_spi.spi_rx(&rsp, 1)) {
- PRINT_ER("[wilc spi]: Failed cmd state read, bus error...\n");
- result = N_FAIL;
- goto _fail_;
- }
+ tr.tx_buf = t_buffer;
- if (rsp != 0x00) {
- PRINT_ER("[wilc spi]: Failed cmd state response state (%02x)\n", rsp);
- result = N_FAIL;
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+ spi_message_add_tail(&tr, &msg);
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+ kfree(t_buffer);
+ } else {
+ dev_err(&spi->dev,
+ "can't read data with the following length: %u\n",
+ rlen);
+ ret = -EINVAL;
}
-_fail_:
+ return ret;
+}
- return result;
+static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+
+ if (rlen > 0) {
+ struct spi_message msg;
+ struct spi_transfer tr = {
+ .rx_buf = rb,
+ .tx_buf = wb,
+ .len = rlen,
+ .bits_per_word = 8,
+ .delay_usecs = 0,
+
+ };
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+
+ spi_message_add_tail(&tr, &msg);
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+ } else {
+ dev_err(&spi->dev,
+ "can't read data with the following length: %u\n",
+ rlen);
+ ret = -EINVAL;
+ }
+
+ return ret;
}
-static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
+static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
+ u8 clockless)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
u8 wb[32], rb[32];
u8 wix, rix;
u32 len2;
@@ -398,7 +415,7 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
#undef NUM_DUMMY_BYTES
if (len2 > ARRAY_SIZE(wb)) {
- PRINT_ER("[wilc spi]: spi buffer size too small (%d) (%zu)\n",
+ dev_err(&spi->dev, "spi buffer size too small (%d) (%zu)\n",
len2, ARRAY_SIZE(wb));
result = N_FAIL;
return result;
@@ -409,8 +426,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
}
rix = len;
- if (!g_spi.spi_trx(wb, rb, len2)) {
- PRINT_ER("[wilc spi]: Failed cmd write, bus error...\n");
+ if (wilc_spi_tx_rx(wilc, wb, rb, len2)) {
+ dev_err(&spi->dev, "Failed cmd write, bus error...\n");
result = N_FAIL;
return result;
}
@@ -430,7 +447,7 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
/* } while(&rptr[1] <= &rb[len2]); */
if (rsp != cmd) {
- PRINT_ER("[wilc spi]: Failed cmd response, cmd (%02x)"
+ dev_err(&spi->dev, "Failed cmd response, cmd (%02x)"
", resp (%02x)\n", cmd, rsp);
result = N_FAIL;
return result;
@@ -441,8 +458,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
**/
rsp = rb[rix++];
if (rsp != 0x00) {
- PRINT_ER("[wilc spi]: Failed cmd state response "
- "state (%02x)\n", rsp);
+ dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+ rsp);
result = N_FAIL;
return result;
}
@@ -469,8 +486,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
} while (retry--);
if (retry <= 0) {
- PRINT_ER("[wilc spi]: Error, data read "
- "response (%02x)\n", rsp);
+ dev_err(&spi->dev,
+ "Error, data read response (%02x)\n", rsp);
result = N_RESET;
return result;
}
@@ -485,7 +502,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
b[2] = rb[rix++];
b[3] = rb[rix++];
} else {
- PRINT_ER("[wilc spi]: buffer overrun when reading data.\n");
+ dev_err(&spi->dev,
+ "buffer overrun when reading data.\n");
result = N_FAIL;
return result;
}
@@ -498,7 +516,7 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
crc[0] = rb[rix++];
crc[1] = rb[rix++];
} else {
- PRINT_ER("[wilc spi]: buffer overrun when reading crc.\n");
+ dev_err(&spi->dev,"buffer overrun when reading crc.\n");
result = N_FAIL;
return result;
}
@@ -524,8 +542,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
/**
* Read bytes
**/
- if (!g_spi.spi_rx(&b[ix], nbytes)) {
- PRINT_ER("[wilc spi]: Failed data block read, bus error...\n");
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev, "Failed data block read, bus error...\n");
result = N_FAIL;
goto _error_;
}
@@ -534,8 +552,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
* Read Crc
**/
if (!g_spi.crc_off) {
- if (!g_spi.spi_rx(crc, 2)) {
- PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n");
+ if (wilc_spi_rx(wilc, crc, 2)) {
+ dev_err(&spi->dev, "Failed data block crc read, bus error...\n");
result = N_FAIL;
goto _error_;
}
@@ -565,8 +583,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
**/
retry = 10;
do {
- if (!g_spi.spi_rx(&rsp, 1)) {
- PRINT_ER("[wilc spi]: Failed data response read, bus error...\n");
+ if (wilc_spi_rx(wilc, &rsp, 1)) {
+ dev_err(&spi->dev, "Failed data response read, bus error...\n");
result = N_FAIL;
break;
}
@@ -581,8 +599,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
/**
* Read bytes
**/
- if (!g_spi.spi_rx(&b[ix], nbytes)) {
- PRINT_ER("[wilc spi]: Failed data block read, bus error...\n");
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev, "Failed data block read, bus error...\n");
result = N_FAIL;
break;
}
@@ -591,8 +609,8 @@ static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless)
* Read Crc
**/
if (!g_spi.crc_off) {
- if (!g_spi.spi_rx(crc, 2)) {
- PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n");
+ if (wilc_spi_rx(wilc, crc, 2)) {
+ dev_err(&spi->dev, "Failed data block crc read, bus error...\n");
result = N_FAIL;
break;
}
@@ -607,76 +625,9 @@ _error_:
return result;
}
-static int spi_data_read(u8 *b, u32 sz)
-{
- int retry, ix, nbytes;
- int result = N_OK;
- u8 crc[2];
- u8 rsp;
-
- /**
- * Data
- **/
- ix = 0;
- do {
- if (sz <= DATA_PKT_SZ)
- nbytes = sz;
- else
- nbytes = DATA_PKT_SZ;
-
- /**
- * Data Respnose header
- **/
- retry = 10;
- do {
- if (!g_spi.spi_rx(&rsp, 1)) {
- PRINT_ER("[wilc spi]: Failed data response read, bus error...\n");
- result = N_FAIL;
- break;
- }
- if (((rsp >> 4) & 0xf) == 0xf)
- break;
- } while (retry--);
-
- if (result == N_FAIL)
- break;
-
- if (retry <= 0) {
- PRINT_ER("[wilc spi]: Failed data response read...(%02x)\n", rsp);
- result = N_FAIL;
- break;
- }
-
- /**
- * Read bytes
- **/
- if (!g_spi.spi_rx(&b[ix], nbytes)) {
- PRINT_ER("[wilc spi]: Failed data block read, bus error...\n");
- result = N_FAIL;
- break;
- }
-
- /**
- * Read Crc
- **/
- if (!g_spi.crc_off) {
- if (!g_spi.spi_rx(crc, 2)) {
- PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n");
- result = N_FAIL;
- break;
- }
- }
-
- ix += nbytes;
- sz -= nbytes;
-
- } while (sz);
-
- return result;
-}
-
-static int spi_data_write(u8 *b, u32 sz)
+static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int ix, nbytes;
int result = 1;
u8 cmd, order, crc[2] = {0};
@@ -709,8 +660,9 @@ static int spi_data_write(u8 *b, u32 sz)
order = 0x2;
}
cmd |= order;
- if (!g_spi.spi_tx(&cmd, 1)) {
- PRINT_ER("[wilc spi]: Failed data block cmd write, bus error...\n");
+ if (wilc_spi_tx(wilc, &cmd, 1)) {
+ dev_err(&spi->dev,
+ "Failed data block cmd write, bus error...\n");
result = N_FAIL;
break;
}
@@ -718,8 +670,9 @@ static int spi_data_write(u8 *b, u32 sz)
/**
* Write data
**/
- if (!g_spi.spi_tx(&b[ix], nbytes)) {
- PRINT_ER("[wilc spi]: Failed data block write, bus error...\n");
+ if (wilc_spi_tx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed data block write, bus error...\n");
result = N_FAIL;
break;
}
@@ -728,8 +681,8 @@ static int spi_data_write(u8 *b, u32 sz)
* Write Crc
**/
if (!g_spi.crc_off) {
- if (!g_spi.spi_tx(crc, 2)) {
- PRINT_ER("[wilc spi]: Failed data block crc write, bus error...\n");
+ if (wilc_spi_tx(wilc, crc, 2)) {
+ dev_err(&spi->dev,"Failed data block crc write, bus error...\n");
result = N_FAIL;
break;
}
@@ -752,34 +705,34 @@ static int spi_data_write(u8 *b, u32 sz)
*
********************************************/
-static int spi_internal_write(u32 adr, u32 dat)
+static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int result;
-#ifdef BIG_ENDIAN
- dat = BYTE_SWAP(dat);
-#endif
- result = spi_cmd_complete(CMD_INTERNAL_WRITE, adr, (u8 *)&dat, 4, 0);
+ dat = cpu_to_le32(dat);
+ result = spi_cmd_complete(wilc, CMD_INTERNAL_WRITE, adr, (u8 *)&dat, 4,
+ 0);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed internal write cmd...\n");
+ dev_err(&spi->dev, "Failed internal write cmd...\n");
}
return result;
}
-static int spi_internal_read(u32 adr, u32 *data)
+static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int result;
- result = spi_cmd_complete(CMD_INTERNAL_READ, adr, (u8 *)data, 4, 0);
+ result = spi_cmd_complete(wilc, CMD_INTERNAL_READ, adr, (u8 *)data, 4,
+ 0);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed internal read cmd...\n");
+ dev_err(&spi->dev, "Failed internal read cmd...\n");
return 0;
}
-#ifdef BIG_ENDIAN
- *data = BYTE_SWAP(*data);
-#endif
+ *data = cpu_to_le32(*data);
return 1;
}
@@ -790,31 +743,31 @@ static int spi_internal_read(u32 adr, u32 *data)
*
********************************************/
-static int spi_write_reg(u32 addr, u32 data)
+static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int result = N_OK;
u8 cmd = CMD_SINGLE_WRITE;
u8 clockless = 0;
-#ifdef BIG_ENDIAN
- data = BYTE_SWAP(data);
-#endif
+ data = cpu_to_le32(data);
if (addr < 0x30) {
/* Clockless register*/
cmd = CMD_INTERNAL_WRITE;
clockless = 1;
}
- result = spi_cmd_complete(cmd, addr, (u8 *)&data, 4, clockless);
+ result = spi_cmd_complete(wilc, cmd, addr, (u8 *)&data, 4, clockless);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed cmd, write reg (%08x)...\n", addr);
+ dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr);
}
return result;
}
-static int spi_write(u32 addr, u8 *buf, u32 size)
+static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int result;
u8 cmd = CMD_DMA_EXT_WRITE;
@@ -824,60 +777,61 @@ static int spi_write(u32 addr, u8 *buf, u32 size)
if (size <= 4)
return 0;
- result = spi_cmd_complete(cmd, addr, NULL, size, 0);
+ result = spi_cmd_complete(wilc, cmd, addr, NULL, size, 0);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed cmd, write block (%08x)...\n", addr);
+ dev_err(&spi->dev,
+ "Failed cmd, write block (%08x)...\n", addr);
return 0;
}
/**
* Data
**/
- result = spi_data_write(buf, size);
+ result = spi_data_write(wilc, buf, size);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed block data write...\n");
+ dev_err(&spi->dev, "Failed block data write...\n");
}
return 1;
}
-static int spi_read_reg(u32 addr, u32 *data)
+static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int result = N_OK;
u8 cmd = CMD_SINGLE_READ;
u8 clockless = 0;
if (addr < 0x30) {
- /* PRINT_ER("***** read addr %d\n\n", addr); */
+ /* dev_err(&spi->dev, "***** read addr %d\n\n", addr); */
/* Clockless register*/
cmd = CMD_INTERNAL_READ;
clockless = 1;
}
- result = spi_cmd_complete(cmd, addr, (u8 *)data, 4, clockless);
+ result = spi_cmd_complete(wilc, cmd, addr, (u8 *)data, 4, clockless);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed cmd, read reg (%08x)...\n", addr);
+ dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr);
return 0;
}
-#ifdef BIG_ENDIAN
- *data = BYTE_SWAP(*data);
-#endif
+ *data = cpu_to_le32(*data);
return 1;
}
-static int spi_read(u32 addr, u8 *buf, u32 size)
+static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
u8 cmd = CMD_DMA_EXT_READ;
int result;
if (size <= 4)
return 0;
- result = spi_cmd_complete(cmd, addr, buf, size, 0);
+ result = spi_cmd_complete(wilc, cmd, addr, buf, size, 0);
if (result != N_OK) {
- PRINT_ER("[wilc spi]: Failed cmd, read block (%08x)...\n", addr);
+ dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr);
return 0;
}
@@ -890,20 +844,7 @@ static int spi_read(u32 addr, u8 *buf, u32 size)
*
********************************************/
-static int spi_clear_int(void)
-{
- u32 reg;
-
- if (!spi_read_reg(WILC_HOST_RX_CTRL_0, &reg)) {
- PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0);
- return 0;
- }
- reg &= ~0x1;
- spi_write_reg(WILC_HOST_RX_CTRL_0, reg);
- return 1;
-}
-
-static int spi_deinit(void *pv)
+static int _wilc_spi_deinit(struct wilc *wilc)
{
/**
* TODO:
@@ -911,46 +852,9 @@ static int spi_deinit(void *pv)
return 1;
}
-static int spi_sync(void)
-{
- u32 reg;
- int ret;
-
- /**
- * interrupt pin mux select
- **/
- ret = spi_read_reg(WILC_PIN_MUX_0, &reg);
- if (!ret) {
- PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
- return 0;
- }
- reg |= BIT(8);
- ret = spi_write_reg(WILC_PIN_MUX_0, reg);
- if (!ret) {
- PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
- return 0;
- }
-
- /**
- * interrupt enable
- **/
- ret = spi_read_reg(WILC_INTR_ENABLE, &reg);
- if (!ret) {
- PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
- return 0;
- }
- reg |= BIT(16);
- ret = spi_write_reg(WILC_INTR_ENABLE, reg);
- if (!ret) {
- PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
- return 0;
- }
-
- return 1;
-}
-
-static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
+static int wilc_spi_init(struct wilc *wilc)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
u32 reg;
u32 chipid;
@@ -958,8 +862,8 @@ static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
if (isinit) {
- if (!spi_read_reg(0x1000, &chipid)) {
- PRINT_ER("[wilc spi]: Fail cmd read chip id...\n");
+ if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) {
+ dev_err(&spi->dev, "Fail cmd read chip id...\n");
return 0;
}
return 1;
@@ -967,21 +871,6 @@ static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
memset(&g_spi, 0, sizeof(wilc_spi_t));
- g_spi.dPrint = func;
- g_spi.os_context = inp->os_context.os_private;
- if (inp->io_func.io_init) {
- if (!inp->io_func.io_init(g_spi.os_context)) {
- PRINT_ER("[wilc spi]: Failed io init bus...\n");
- return 0;
- }
- } else {
- return 0;
- }
- g_spi.spi_tx = inp->io_func.u.spi.spi_tx;
- g_spi.spi_rx = inp->io_func.u.spi.spi_rx;
- g_spi.spi_trx = inp->io_func.u.spi.spi_trx;
- g_spi.spi_max_speed = inp->io_func.u.spi.spi_max_speed;
-
/**
* configure protocol
**/
@@ -989,14 +878,15 @@ static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
/* TODO: We can remove the CRC trials if there is a definite way to reset */
/* the SPI to it's initial value. */
- if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, &reg)) {
+ if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
/* Read failed. Try with CRC off. This might happen when module
* is removed but chip isn't reset*/
g_spi.crc_off = 1;
- PRINT_ER("[wilc spi]: Failed internal read protocol with CRC on, retyring with CRC off...\n");
- if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, &reg)) {
+ dev_err(&spi->dev, "Failed internal read protocol with CRC on, retyring with CRC off...\n");
+ if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
/* Reaad failed with both CRC on and off, something went bad */
- PRINT_ER("[wilc spi]: Failed internal read protocol...\n");
+ dev_err(&spi->dev,
+ "Failed internal read protocol...\n");
return 0;
}
}
@@ -1004,8 +894,8 @@ static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
reg &= ~0xc; /* disable crc checking */
reg &= ~0x70;
reg |= (0x5 << 4);
- if (!spi_internal_write(WILC_SPI_PROTOCOL_OFFSET, reg)) {
- PRINT_ER("[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__);
+ if (!spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg)) {
+ dev_err(&spi->dev, "[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__);
return 0;
}
g_spi.crc_off = 1;
@@ -1015,11 +905,11 @@ static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
/**
* make sure can read back chip id correctly
**/
- if (!spi_read_reg(0x1000, &chipid)) {
- PRINT_ER("[wilc spi]: Fail cmd read chip id...\n");
+ if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) {
+ dev_err(&spi->dev, "Fail cmd read chip id...\n");
return 0;
}
- /* PRINT_ER("[wilc spi]: chipid (%08x)\n", chipid); */
+ /* dev_err(&spi->dev, "chipid (%08x)\n", chipid); */
g_spi.has_thrpt_enh = 1;
@@ -1028,29 +918,24 @@ static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
return 1;
}
-static void spi_max_bus_speed(void)
-{
- g_spi.spi_max_speed();
-}
-
-static void spi_default_bus_speed(void)
-{
-}
-
-static int spi_read_size(u32 *size)
+static int wilc_spi_read_size(struct wilc *wilc, u32 *size)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int ret;
if (g_spi.has_thrpt_enh) {
- ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, size);
+ ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
+ size);
*size = *size & IRQ_DMA_WD_CNT_MASK;
} else {
u32 tmp;
u32 byte_cnt;
- ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt);
+ ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE,
+ &byte_cnt);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed read WILC_VMM_TO_HOST_SIZE ...\n");
+ dev_err(&spi->dev,
+ "Failed read WILC_VMM_TO_HOST_SIZE ...\n");
goto _fail_;
}
tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
@@ -1065,19 +950,23 @@ _fail_:
-static int spi_read_int(u32 *int_status)
+static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int ret;
if (g_spi.has_thrpt_enh) {
- ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, int_status);
+ ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
+ int_status);
} else {
u32 tmp;
u32 byte_cnt;
- ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt);
+ ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE,
+ &byte_cnt);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed read WILC_VMM_TO_HOST_SIZE ...\n");
+ dev_err(&spi->dev,
+ "Failed read WILC_VMM_TO_HOST_SIZE ...\n");
goto _fail_;
}
tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
@@ -1091,11 +980,12 @@ static int spi_read_int(u32 *int_status)
happended = 0;
- spi_read_reg(0x1a90, &irq_flags);
+ wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
if (g_spi.nint > 5) {
- spi_read_reg(0x1a94, &irq_flags);
+ wilc_spi_read_reg(wilc, 0x1a94,
+ &irq_flags);
tmp |= (((irq_flags >> 0) & 0x7) << (IRG_FLAGS_OFFSET + 5));
}
@@ -1105,7 +995,7 @@ static int spi_read_int(u32 *int_status)
unkmown_mask = ~((1ul << g_spi.nint) - 1);
if ((tmp >> IRG_FLAGS_OFFSET) & unkmown_mask) {
- PRINT_ER("[wilc spi]: Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unkmown_mask);
+ dev_err(&spi->dev, "Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unkmown_mask);
happended = 1;
}
}
@@ -1121,12 +1011,14 @@ _fail_:
return ret;
}
-static int spi_clear_int_ext(u32 val)
+static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
int ret;
if (g_spi.has_thrpt_enh) {
- ret = spi_internal_write(0xe844 - WILC_SPI_REG_BASE, val);
+ ret = spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
+ val);
} else {
u32 flags;
@@ -1138,18 +1030,22 @@ static int spi_clear_int_ext(u32 val)
for (i = 0; i < g_spi.nint; i++) {
/* No matter what you write 1 or 0, it will clear interrupt. */
if (flags & 1)
- ret = spi_write_reg(0x10c8 + i * 4, 1);
+ ret = wilc_spi_write_reg(wilc, 0x10c8 + i * 4, 1);
if (!ret)
break;
flags >>= 1;
}
if (!ret) {
- PRINT_ER("[wilc spi]: Failed spi_write_reg, set reg %x ...\n", 0x10c8 + i * 4);
+ dev_err(&spi->dev,
+ "Failed wilc_spi_write_reg, set reg %x ...\n",
+ 0x10c8 + i * 4);
goto _fail_;
}
for (i = g_spi.nint; i < MAX_NUM_INT; i++) {
if (flags & 1)
- PRINT_ER("[wilc spi]: Unexpected interrupt cleared %d...\n", i);
+ dev_err(&spi->dev,
+ "Unexpected interrupt cleared %d...\n",
+ i);
flags >>= 1;
}
}
@@ -1165,9 +1061,11 @@ static int spi_clear_int_ext(u32 val)
if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
tbl_ctl |= BIT(1);
- ret = spi_write_reg(WILC_VMM_TBL_CTL, tbl_ctl);
+ ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL,
+ tbl_ctl);
if (!ret) {
- PRINT_ER("[wilc spi]: fail write reg vmm_tbl_ctl...\n");
+ dev_err(&spi->dev,
+ "fail write reg vmm_tbl_ctl...\n");
goto _fail_;
}
@@ -1175,9 +1073,10 @@ static int spi_clear_int_ext(u32 val)
/**
* enable vmm transfer.
**/
- ret = spi_write_reg(WILC_VMM_CORE_CTL, 1);
+ ret = wilc_spi_write_reg(wilc,
+ WILC_VMM_CORE_CTL, 1);
if (!ret) {
- PRINT_ER("[wilc spi]: fail write reg vmm_core_ctl...\n");
+ dev_err(&spi->dev,"fail write reg vmm_core_ctl...\n");
goto _fail_;
}
}
@@ -1187,13 +1086,14 @@ _fail_:
return ret;
}
-static int spi_sync_ext(int nint /* how mant interrupts to enable. */)
+static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
{
+ struct spi_device *spi = to_spi_device(wilc->dev);
u32 reg;
int ret, i;
if (nint > MAX_NUM_INT) {
- PRINT_ER("[wilc spi]: Too many interupts (%d)...\n", nint);
+ dev_err(&spi->dev, "Too many interupts (%d)...\n", nint);
return 0;
}
@@ -1202,39 +1102,44 @@ static int spi_sync_ext(int nint /* how mant interrupts to enable. */)
/**
* interrupt pin mux select
**/
- ret = spi_read_reg(WILC_PIN_MUX_0, &reg);
+ ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, &reg);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
+ dev_err(&spi->dev, "Failed read reg (%08x)...\n",
+ WILC_PIN_MUX_0);
return 0;
}
reg |= BIT(8);
- ret = spi_write_reg(WILC_PIN_MUX_0, reg);
+ ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
+ dev_err(&spi->dev, "Failed write reg (%08x)...\n",
+ WILC_PIN_MUX_0);
return 0;
}
/**
* interrupt enable
**/
- ret = spi_read_reg(WILC_INTR_ENABLE, &reg);
+ ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, &reg);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
+ dev_err(&spi->dev, "Failed read reg (%08x)...\n",
+ WILC_INTR_ENABLE);
return 0;
}
for (i = 0; (i < 5) && (nint > 0); i++, nint--) {
reg |= (BIT((27 + i)));
}
- ret = spi_write_reg(WILC_INTR_ENABLE, reg);
+ ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
+ dev_err(&spi->dev, "Failed write reg (%08x)...\n",
+ WILC_INTR_ENABLE);
return 0;
}
if (nint) {
- ret = spi_read_reg(WILC_INTR2_ENABLE, &reg);
+ ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE);
+ dev_err(&spi->dev, "Failed read reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
return 0;
}
@@ -1242,9 +1147,10 @@ static int spi_sync_ext(int nint /* how mant interrupts to enable. */)
reg |= BIT(i);
}
- ret = spi_read_reg(WILC_INTR2_ENABLE, &reg);
+ ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
if (!ret) {
- PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE);
+ dev_err(&spi->dev, "Failed write reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
return 0;
}
}
@@ -1256,21 +1162,17 @@ static int spi_sync_ext(int nint /* how mant interrupts to enable. */)
* Global spi HIF function table
*
********************************************/
-wilc_hif_func_t hif_spi = {
- spi_init,
- spi_deinit,
- spi_read_reg,
- spi_write_reg,
- spi_read,
- spi_write,
- spi_sync,
- spi_clear_int,
- spi_read_int,
- spi_clear_int_ext,
- spi_read_size,
- spi_write,
- spi_read,
- spi_sync_ext,
- spi_max_bus_speed,
- spi_default_bus_speed,
+const struct wilc_hif_func wilc_hif_spi = {
+ .hif_init = wilc_spi_init,
+ .hif_deinit = _wilc_spi_deinit,
+ .hif_read_reg = wilc_spi_read_reg,
+ .hif_write_reg = wilc_spi_write_reg,
+ .hif_block_rx = wilc_spi_read,
+ .hif_block_tx = wilc_spi_write,
+ .hif_read_int = wilc_spi_read_int,
+ .hif_clear_int_ext = wilc_spi_clear_int_ext,
+ .hif_read_size = wilc_spi_read_size,
+ .hif_block_tx_ext = wilc_spi_write,
+ .hif_block_rx_ext = wilc_spi_read,
+ .hif_sync_ext = wilc_spi_sync_ext,
};
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index 3e9501727812..53fb2d4bb0bd 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -1,40 +1,101 @@
-/*!
- * @file wilc_wfi_cfgopertaions.c
- * @brief CFG80211 Function Implementation functionality
- * @author aabouzaeid
- * mabubakr
- * mdaftedar
- * zsalah
- * @sa wilc_wfi_cfgopertaions.h top level OS wrapper file
- * @date 31 Aug 2010
- * @version 1.0
- */
-
#include "wilc_wfi_cfgoperations.h"
-#ifdef WILC_SDIO
-#include "linux_wlan_sdio.h"
-#endif
+#include "host_interface.h"
#include <linux/errno.h>
+#define NO_ENCRYPT 0
+#define ENCRYPT_ENABLED BIT(0)
+#define WEP BIT(1)
+#define WEP_EXTENDED BIT(2)
+#define WPA BIT(3)
+#define WPA2 BIT(4)
+#define AES BIT(5)
+#define TKIP BIT(6)
+
+#define FRAME_TYPE_ID 0
+#define ACTION_CAT_ID 24
+#define ACTION_SUBTYPE_ID 25
+#define P2P_PUB_ACTION_SUBTYPE 30
+
+#define ACTION_FRAME 0xd0
+#define GO_INTENT_ATTR_ID 0x04
+#define CHANLIST_ATTR_ID 0x0b
+#define OPERCHAN_ATTR_ID 0x11
+#define PUB_ACTION_ATTR_ID 0x04
+#define P2PELEM_ATTR_ID 0xdd
+
+#define GO_NEG_REQ 0x00
+#define GO_NEG_RSP 0x01
+#define GO_NEG_CONF 0x02
+#define P2P_INV_REQ 0x03
+#define P2P_INV_RSP 0x04
+#define PUBLIC_ACT_VENDORSPEC 0x09
+#define GAS_INTIAL_REQ 0x0a
+#define GAS_INTIAL_RSP 0x0b
+
+#define INVALID_CHANNEL 0
+
+#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ)
+#define SCAN_RESULT_EXPIRE (40 * HZ)
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+};
+
+static const struct ieee80211_txrx_stypes
+ wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4)
+ }
+};
+
+#define WILC_WFI_DWELL_PASSIVE 100
+#define WILC_WFI_DWELL_ACTIVE 40
+
+#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54
+#define DEFAULT_LINK_SPEED 72
+
+
#define IS_MANAGMEMENT 0x100
#define IS_MANAGMEMENT_CALLBACK 0x080
#define IS_MGMT_STATUS_SUCCES 0x040
#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
-extern int linux_wlan_get_firmware(perInterface_wlan_t *p_nic);
+extern int wilc_mac_open(struct net_device *ndev);
+extern int wilc_mac_close(struct net_device *ndev);
-extern int mac_open(struct net_device *ndev);
-extern int mac_close(struct net_device *ndev);
-
-tstrNetworkInfo astrLastScannedNtwrksShadow[MAX_NUM_SCANNED_NETWORKS_SHADOW];
-u32 u32LastScannedNtwrksCountShadow;
-struct timer_list hDuringIpTimer;
-struct timer_list hAgingTimer;
+static tstrNetworkInfo last_scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW];
+static u32 last_scanned_cnt;
+struct timer_list wilc_during_ip_timer;
+static struct timer_list hAgingTimer;
static u8 op_ifcs;
-extern u8 u8ConnectedSSID[6];
-u8 g_wilc_initialized = 1;
-extern bool g_obtainingIP;
+u8 wilc_initialized = 1;
#define CHAN2G(_channel, _freq, _flags) { \
.band = IEEE80211_BAND_2GHZ, \
@@ -45,8 +106,7 @@ extern bool g_obtainingIP;
.max_power = 30, \
}
-/*Frequency range for channels*/
-static struct ieee80211_channel WILC_WFI_2ghz_channels[] = {
+static struct ieee80211_channel ieee80211_2ghz_channels[] = {
CHAN2G(1, 2412, 0),
CHAN2G(2, 2417, 0),
CHAN2G(3, 2422, 0),
@@ -69,9 +129,7 @@ static struct ieee80211_channel WILC_WFI_2ghz_channels[] = {
.flags = (_flags), \
}
-
-/* Table 6 in section 3.2.1.1 */
-static struct ieee80211_rate WILC_WFI_rates[] = {
+static struct ieee80211_rate ieee80211_bitrates[] = {
RATETAB_ENT(10, 0, 0),
RATETAB_ENT(20, 1, 0),
RATETAB_ENT(55, 2, 0),
@@ -91,22 +149,19 @@ struct p2p_mgmt_data {
u8 *buff;
};
-/*Global variable used to state the current connected STA channel*/
-u8 u8WLANChannel = INVALID_CHANNEL;
-
-u8 curr_channel;
-
-u8 u8P2P_oui[] = {0x50, 0x6f, 0x9A, 0x09};
-u8 u8P2Plocalrandom = 0x01;
-u8 u8P2Precvrandom = 0x00;
-u8 u8P2P_vendorspec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
-bool bWilc_ie;
+static u8 wlan_channel = INVALID_CHANNEL;
+static u8 curr_channel;
+static u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
+static u8 p2p_local_random = 0x01;
+static u8 p2p_recv_random = 0x00;
+static u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
+static bool wilc_ie;
static struct ieee80211_supported_band WILC_WFI_band_2ghz = {
- .channels = WILC_WFI_2ghz_channels,
- .n_channels = ARRAY_SIZE(WILC_WFI_2ghz_channels),
- .bitrates = WILC_WFI_rates,
- .n_bitrates = ARRAY_SIZE(WILC_WFI_rates),
+ .channels = ieee80211_2ghz_channels,
+ .n_channels = ARRAY_SIZE(ieee80211_2ghz_channels),
+ .bitrates = ieee80211_bitrates,
+ .n_bitrates = ARRAY_SIZE(ieee80211_bitrates),
};
@@ -115,19 +170,19 @@ struct add_key_params {
bool pairwise;
u8 *mac_addr;
};
-struct add_key_params g_add_gtk_key_params;
-struct wilc_wfi_key g_key_gtk_params;
-struct add_key_params g_add_ptk_key_params;
-struct wilc_wfi_key g_key_ptk_params;
-struct wilc_wfi_wep_key g_key_wep_params;
-bool g_ptk_keys_saved;
-bool g_gtk_keys_saved;
-bool g_wep_keys_saved;
+static struct add_key_params g_add_gtk_key_params;
+static struct wilc_wfi_key g_key_gtk_params;
+static struct add_key_params g_add_ptk_key_params;
+static struct wilc_wfi_key g_key_ptk_params;
+static struct wilc_wfi_wep_key g_key_wep_params;
+static bool g_ptk_keys_saved;
+static bool g_gtk_keys_saved;
+static bool g_wep_keys_saved;
#define AGING_TIME (9 * 1000)
-#define duringIP_TIME 15000
+#define during_ip_time 15000
-void clear_shadow_scan(void *pUserVoid)
+static void clear_shadow_scan(void)
{
int i;
@@ -135,34 +190,33 @@ void clear_shadow_scan(void *pUserVoid)
del_timer_sync(&hAgingTimer);
PRINT_INFO(CORECONFIG_DBG, "destroy aging timer\n");
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- if (astrLastScannedNtwrksShadow[u32LastScannedNtwrksCountShadow].pu8IEs != NULL) {
- kfree(astrLastScannedNtwrksShadow[i].pu8IEs);
- astrLastScannedNtwrksShadow[u32LastScannedNtwrksCountShadow].pu8IEs = NULL;
+ for (i = 0; i < last_scanned_cnt; i++) {
+ if (last_scanned_shadow[last_scanned_cnt].pu8IEs) {
+ kfree(last_scanned_shadow[i].pu8IEs);
+ last_scanned_shadow[last_scanned_cnt].pu8IEs = NULL;
}
- host_int_freeJoinParams(astrLastScannedNtwrksShadow[i].pJoinParams);
- astrLastScannedNtwrksShadow[i].pJoinParams = NULL;
+ wilc_free_join_params(last_scanned_shadow[i].pJoinParams);
+ last_scanned_shadow[i].pJoinParams = NULL;
}
- u32LastScannedNtwrksCountShadow = 0;
+ last_scanned_cnt = 0;
}
-
}
-u32 get_rssi_avg(tstrNetworkInfo *pstrNetworkInfo)
+static u32 get_rssi_avg(tstrNetworkInfo *network_info)
{
u8 i;
int rssi_v = 0;
- u8 num_rssi = (pstrNetworkInfo->strRssi.u8Full) ? NUM_RSSI : (pstrNetworkInfo->strRssi.u8Index);
+ u8 num_rssi = (network_info->strRssi.u8Full) ? NUM_RSSI : (network_info->strRssi.u8Index);
for (i = 0; i < num_rssi; i++)
- rssi_v += pstrNetworkInfo->strRssi.as8RSSI[i];
+ rssi_v += network_info->strRssi.as8RSSI[i];
rssi_v /= num_rssi;
return rssi_v;
}
-void refresh_scan(void *pUserVoid, u8 all, bool bDirectScan)
+static void refresh_scan(void *user_void, u8 all, bool direct_scan)
{
struct wilc_priv *priv;
struct wiphy *wiphy;
@@ -170,55 +224,49 @@ void refresh_scan(void *pUserVoid, u8 all, bool bDirectScan)
int i;
int rssi = 0;
- priv = (struct wilc_priv *)pUserVoid;
+ priv = (struct wilc_priv *)user_void;
wiphy = priv->dev->ieee80211_ptr->wiphy;
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- tstrNetworkInfo *pstrNetworkInfo;
+ for (i = 0; i < last_scanned_cnt; i++) {
+ tstrNetworkInfo *network_info;
- pstrNetworkInfo = &(astrLastScannedNtwrksShadow[i]);
+ network_info = &last_scanned_shadow[i];
-
- if ((!pstrNetworkInfo->u8Found) || all) {
- s32 s32Freq;
+ if (!network_info->u8Found || all) {
+ s32 freq;
struct ieee80211_channel *channel;
- if (pstrNetworkInfo != NULL) {
-
- s32Freq = ieee80211_channel_to_frequency((s32)pstrNetworkInfo->u8channel, IEEE80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, s32Freq);
+ if (network_info) {
+ freq = ieee80211_channel_to_frequency((s32)network_info->u8channel, IEEE80211_BAND_2GHZ);
+ channel = ieee80211_get_channel(wiphy, freq);
- rssi = get_rssi_avg(pstrNetworkInfo);
- if (memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7) || bDirectScan) {
- bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo,
- pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs,
- (size_t)pstrNetworkInfo->u16IEsLen, (((s32)rssi) * 100), GFP_KERNEL);
+ rssi = get_rssi_avg(network_info);
+ if (memcmp("DIRECT-", network_info->au8ssid, 7) ||
+ direct_scan) {
+ bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, network_info->au8bssid, network_info->u64Tsf, network_info->u16CapInfo,
+ network_info->u16BeaconPeriod, (const u8 *)network_info->pu8IEs,
+ (size_t)network_info->u16IEsLen, (((s32)rssi) * 100), GFP_KERNEL);
cfg80211_put_bss(wiphy, bss);
}
}
-
}
}
-
}
-void reset_shadow_found(void *pUserVoid)
+static void reset_shadow_found(void)
{
int i;
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- astrLastScannedNtwrksShadow[i].u8Found = 0;
-
- }
+ for (i = 0; i < last_scanned_cnt; i++)
+ last_scanned_shadow[i].u8Found = 0;
}
-void update_scan_time(void *pUserVoid)
+static void update_scan_time(void)
{
int i;
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies;
- }
+ for (i = 0; i < last_scanned_cnt; i++)
+ last_scanned_shadow[i].u32TimeRcvdInScan = jiffies;
}
static void remove_network_from_shadow(unsigned long arg)
@@ -227,24 +275,25 @@ static void remove_network_from_shadow(unsigned long arg)
int i, j;
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- if (time_after(now, astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan + (unsigned long)(SCAN_RESULT_EXPIRE))) {
- PRINT_D(CFG80211_DBG, "Network expired in ScanShadow: %s\n", astrLastScannedNtwrksShadow[i].au8ssid);
+ for (i = 0; i < last_scanned_cnt; i++) {
+ if (time_after(now, last_scanned_shadow[i].u32TimeRcvdInScan + (unsigned long)(SCAN_RESULT_EXPIRE))) {
+ PRINT_D(CFG80211_DBG, "Network expired in ScanShadow: %s\n", last_scanned_shadow[i].au8ssid);
- kfree(astrLastScannedNtwrksShadow[i].pu8IEs);
- astrLastScannedNtwrksShadow[i].pu8IEs = NULL;
+ kfree(last_scanned_shadow[i].pu8IEs);
+ last_scanned_shadow[i].pu8IEs = NULL;
- host_int_freeJoinParams(astrLastScannedNtwrksShadow[i].pJoinParams);
+ wilc_free_join_params(last_scanned_shadow[i].pJoinParams);
- for (j = i; (j < u32LastScannedNtwrksCountShadow - 1); j++) {
- astrLastScannedNtwrksShadow[j] = astrLastScannedNtwrksShadow[j + 1];
- }
- u32LastScannedNtwrksCountShadow--;
+ for (j = i; (j < last_scanned_cnt - 1); j++)
+ last_scanned_shadow[j] = last_scanned_shadow[j + 1];
+
+ last_scanned_cnt--;
}
}
- PRINT_D(CFG80211_DBG, "Number of cached networks: %d\n", u32LastScannedNtwrksCountShadow);
- if (u32LastScannedNtwrksCountShadow != 0) {
+ PRINT_D(CFG80211_DBG, "Number of cached networks: %d\n",
+ last_scanned_cnt);
+ if (last_scanned_cnt != 0) {
hAgingTimer.data = arg;
mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME));
} else {
@@ -255,24 +304,24 @@ static void remove_network_from_shadow(unsigned long arg)
static void clear_duringIP(unsigned long arg)
{
PRINT_D(GENERIC_DBG, "GO:IP Obtained , enable scan\n");
- g_obtainingIP = false;
+ wilc_optaining_ip = false;
}
-int is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid)
+static int is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo,
+ void *user_void)
{
int state = -1;
int i;
- if (u32LastScannedNtwrksCountShadow == 0) {
+ if (last_scanned_cnt == 0) {
PRINT_D(CFG80211_DBG, "Starting Aging timer\n");
- hAgingTimer.data = (unsigned long)pUserVoid;
+ hAgingTimer.data = (unsigned long)user_void;
mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME));
state = -1;
} else {
- /* Linear search for now */
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid,
- pstrNetworkInfo->au8bssid, 6) == 0) {
+ for (i = 0; i < last_scanned_cnt; i++) {
+ if (memcmp(last_scanned_shadow[i].au8bssid,
+ pstrNetworkInfo->au8bssid, 6) == 0) {
state = i;
break;
}
@@ -281,78 +330,60 @@ int is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid)
return state;
}
-void add_network_to_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams)
+static void add_network_to_shadow(tstrNetworkInfo *pstrNetworkInfo,
+ void *user_void, void *pJoinParams)
{
- int ap_found = is_network_in_shadow(pstrNetworkInfo, pUserVoid);
+ int ap_found = is_network_in_shadow(pstrNetworkInfo, user_void);
u32 ap_index = 0;
u8 rssi_index = 0;
- if (u32LastScannedNtwrksCountShadow >= MAX_NUM_SCANNED_NETWORKS_SHADOW) {
+ if (last_scanned_cnt >= MAX_NUM_SCANNED_NETWORKS_SHADOW) {
PRINT_D(CFG80211_DBG, "Shadow network reached its maximum limit\n");
return;
}
if (ap_found == -1) {
- ap_index = u32LastScannedNtwrksCountShadow;
- u32LastScannedNtwrksCountShadow++;
-
+ ap_index = last_scanned_cnt;
+ last_scanned_cnt++;
} else {
ap_index = ap_found;
}
- rssi_index = astrLastScannedNtwrksShadow[ap_index].strRssi.u8Index;
- astrLastScannedNtwrksShadow[ap_index].strRssi.as8RSSI[rssi_index++] = pstrNetworkInfo->s8rssi;
+ rssi_index = last_scanned_shadow[ap_index].strRssi.u8Index;
+ last_scanned_shadow[ap_index].strRssi.as8RSSI[rssi_index++] = pstrNetworkInfo->s8rssi;
if (rssi_index == NUM_RSSI) {
rssi_index = 0;
- astrLastScannedNtwrksShadow[ap_index].strRssi.u8Full = 1;
- }
- astrLastScannedNtwrksShadow[ap_index].strRssi.u8Index = rssi_index;
-
- astrLastScannedNtwrksShadow[ap_index].s8rssi = pstrNetworkInfo->s8rssi;
- astrLastScannedNtwrksShadow[ap_index].u16CapInfo = pstrNetworkInfo->u16CapInfo;
-
- astrLastScannedNtwrksShadow[ap_index].u8SsidLen = pstrNetworkInfo->u8SsidLen;
- memcpy(astrLastScannedNtwrksShadow[ap_index].au8ssid,
- pstrNetworkInfo->au8ssid, pstrNetworkInfo->u8SsidLen);
-
- memcpy(astrLastScannedNtwrksShadow[ap_index].au8bssid,
- pstrNetworkInfo->au8bssid, ETH_ALEN);
-
- astrLastScannedNtwrksShadow[ap_index].u16BeaconPeriod = pstrNetworkInfo->u16BeaconPeriod;
- astrLastScannedNtwrksShadow[ap_index].u8DtimPeriod = pstrNetworkInfo->u8DtimPeriod;
- astrLastScannedNtwrksShadow[ap_index].u8channel = pstrNetworkInfo->u8channel;
-
- astrLastScannedNtwrksShadow[ap_index].u16IEsLen = pstrNetworkInfo->u16IEsLen;
- astrLastScannedNtwrksShadow[ap_index].u64Tsf = pstrNetworkInfo->u64Tsf;
+ last_scanned_shadow[ap_index].strRssi.u8Full = 1;
+ }
+ last_scanned_shadow[ap_index].strRssi.u8Index = rssi_index;
+ last_scanned_shadow[ap_index].s8rssi = pstrNetworkInfo->s8rssi;
+ last_scanned_shadow[ap_index].u16CapInfo = pstrNetworkInfo->u16CapInfo;
+ last_scanned_shadow[ap_index].u8SsidLen = pstrNetworkInfo->u8SsidLen;
+ memcpy(last_scanned_shadow[ap_index].au8ssid,
+ pstrNetworkInfo->au8ssid, pstrNetworkInfo->u8SsidLen);
+ memcpy(last_scanned_shadow[ap_index].au8bssid,
+ pstrNetworkInfo->au8bssid, ETH_ALEN);
+ last_scanned_shadow[ap_index].u16BeaconPeriod = pstrNetworkInfo->u16BeaconPeriod;
+ last_scanned_shadow[ap_index].u8DtimPeriod = pstrNetworkInfo->u8DtimPeriod;
+ last_scanned_shadow[ap_index].u8channel = pstrNetworkInfo->u8channel;
+ last_scanned_shadow[ap_index].u16IEsLen = pstrNetworkInfo->u16IEsLen;
+ last_scanned_shadow[ap_index].u64Tsf = pstrNetworkInfo->u64Tsf;
if (ap_found != -1)
- kfree(astrLastScannedNtwrksShadow[ap_index].pu8IEs);
- astrLastScannedNtwrksShadow[ap_index].pu8IEs =
- kmalloc(pstrNetworkInfo->u16IEsLen, GFP_KERNEL); /* will be deallocated by the WILC_WFI_CfgScan() function */
- memcpy(astrLastScannedNtwrksShadow[ap_index].pu8IEs,
- pstrNetworkInfo->pu8IEs, pstrNetworkInfo->u16IEsLen);
-
- astrLastScannedNtwrksShadow[ap_index].u32TimeRcvdInScan = jiffies;
- astrLastScannedNtwrksShadow[ap_index].u32TimeRcvdInScanCached = jiffies;
- astrLastScannedNtwrksShadow[ap_index].u8Found = 1;
+ kfree(last_scanned_shadow[ap_index].pu8IEs);
+ last_scanned_shadow[ap_index].pu8IEs =
+ kmalloc(pstrNetworkInfo->u16IEsLen, GFP_KERNEL);
+ memcpy(last_scanned_shadow[ap_index].pu8IEs,
+ pstrNetworkInfo->pu8IEs, pstrNetworkInfo->u16IEsLen);
+ last_scanned_shadow[ap_index].u32TimeRcvdInScan = jiffies;
+ last_scanned_shadow[ap_index].u32TimeRcvdInScanCached = jiffies;
+ last_scanned_shadow[ap_index].u8Found = 1;
if (ap_found != -1)
- host_int_freeJoinParams(astrLastScannedNtwrksShadow[ap_index].pJoinParams);
- astrLastScannedNtwrksShadow[ap_index].pJoinParams = pJoinParams;
-
+ wilc_free_join_params(last_scanned_shadow[ap_index].pJoinParams);
+ last_scanned_shadow[ap_index].pJoinParams = pJoinParams;
}
-
-/**
- * @brief CfgScanResult
- * @details Callback function which returns the scan results found
- *
- * @param[in] tenuScanEvent enuScanEvent: enum, indicating the scan event triggered, whether that is
- * SCAN_EVENT_NETWORK_FOUND or SCAN_EVENT_DONE
- * tstrNetworkInfo* pstrNetworkInfo: structure holding the scan results information
- * void* pUserVoid: Private structure associated with the wireless interface
- * @return NONE
- * @author mabubakr
- * @date
- * @version 1.0
- */
-static void CfgScanResult(enum scan_event enuScanEvent, tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams)
+static void CfgScanResult(enum scan_event scan_event,
+ tstrNetworkInfo *network_info,
+ void *user_void,
+ void *join_params)
{
struct wilc_priv *priv;
struct wiphy *wiphy;
@@ -360,56 +391,45 @@ static void CfgScanResult(enum scan_event enuScanEvent, tstrNetworkInfo *pstrNet
struct ieee80211_channel *channel;
struct cfg80211_bss *bss = NULL;
- priv = (struct wilc_priv *)pUserVoid;
+ priv = (struct wilc_priv *)user_void;
if (priv->bCfgScanning) {
- if (enuScanEvent == SCAN_EVENT_NETWORK_FOUND) {
+ if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
wiphy = priv->dev->ieee80211_ptr->wiphy;
if (!wiphy)
return;
- if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC
- &&
- ((((s32)pstrNetworkInfo->s8rssi) * 100) < 0
- ||
- (((s32)pstrNetworkInfo->s8rssi) * 100) > 100)
- ) {
+ if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
+ (((s32)network_info->s8rssi * 100) < 0 ||
+ ((s32)network_info->s8rssi * 100) > 100)) {
PRINT_ER("wiphy signal type fial\n");
return;
}
- if (pstrNetworkInfo != NULL) {
- s32Freq = ieee80211_channel_to_frequency((s32)pstrNetworkInfo->u8channel, IEEE80211_BAND_2GHZ);
+ if (network_info) {
+ s32Freq = ieee80211_channel_to_frequency((s32)network_info->u8channel, IEEE80211_BAND_2GHZ);
channel = ieee80211_get_channel(wiphy, s32Freq);
if (!channel)
return;
PRINT_INFO(CFG80211_DBG, "Network Info:: CHANNEL Frequency: %d, RSSI: %d, CapabilityInfo: %d,"
- "BeaconPeriod: %d\n", channel->center_freq, (((s32)pstrNetworkInfo->s8rssi) * 100),
- pstrNetworkInfo->u16CapInfo, pstrNetworkInfo->u16BeaconPeriod);
-
- if (pstrNetworkInfo->bNewNetwork) {
- if (priv->u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) { /* TODO: mostafa: to be replaced by */
- /* max_scan_ssids */
- PRINT_D(CFG80211_DBG, "Network %s found\n", pstrNetworkInfo->au8ssid);
-
+ "BeaconPeriod: %d\n", channel->center_freq, (((s32)network_info->s8rssi) * 100),
+ network_info->u16CapInfo, network_info->u16BeaconPeriod);
+ if (network_info->bNewNetwork) {
+ if (priv->u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) {
+ PRINT_D(CFG80211_DBG, "Network %s found\n", network_info->au8ssid);
priv->u32RcvdChCount++;
-
-
- if (pJoinParams == NULL) {
+ if (!join_params)
PRINT_INFO(CORECONFIG_DBG, ">> Something really bad happened\n");
- }
- add_network_to_shadow(pstrNetworkInfo, priv, pJoinParams);
-
- /*P2P peers are sent to WPA supplicant and added to shadow table*/
+ add_network_to_shadow(network_info, priv, join_params);
- if (!(memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7))) {
- bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo,
- pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs,
- (size_t)pstrNetworkInfo->u16IEsLen, (((s32)pstrNetworkInfo->s8rssi) * 100), GFP_KERNEL);
+ if (!(memcmp("DIRECT-", network_info->au8ssid, 7))) {
+ bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, network_info->au8bssid, network_info->u64Tsf, network_info->u16CapInfo,
+ network_info->u16BeaconPeriod, (const u8 *)network_info->pu8IEs,
+ (size_t)network_info->u16IEsLen, (((s32)network_info->s8rssi) * 100), GFP_KERNEL);
cfg80211_put_bss(wiphy, bss);
}
@@ -419,19 +439,19 @@ static void CfgScanResult(enum scan_event enuScanEvent, tstrNetworkInfo *pstrNet
}
} else {
u32 i;
- /* So this network is discovered before, we'll just update its RSSI */
+
for (i = 0; i < priv->u32RcvdChCount; i++) {
- if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) {
- PRINT_D(CFG80211_DBG, "Update RSSI of %s\n", astrLastScannedNtwrksShadow[i].au8ssid);
+ if (memcmp(last_scanned_shadow[i].au8bssid, network_info->au8bssid, 6) == 0) {
+ PRINT_D(CFG80211_DBG, "Update RSSI of %s\n", last_scanned_shadow[i].au8ssid);
- astrLastScannedNtwrksShadow[i].s8rssi = pstrNetworkInfo->s8rssi;
- astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies;
+ last_scanned_shadow[i].s8rssi = network_info->s8rssi;
+ last_scanned_shadow[i].u32TimeRcvdInScan = jiffies;
break;
}
}
}
}
- } else if (enuScanEvent == SCAN_EVENT_DONE) {
+ } else if (scan_event == SCAN_EVENT_DONE) {
PRINT_D(CFG80211_DBG, "Scan Done[%p]\n", priv->dev);
PRINT_D(CFG80211_DBG, "Refreshing Scan ...\n");
refresh_scan(priv, 1, false);
@@ -443,23 +463,19 @@ static void CfgScanResult(enum scan_event enuScanEvent, tstrNetworkInfo *pstrNet
down(&(priv->hSemScanReq));
- if (priv->pstrScanReq != NULL) {
+ if (priv->pstrScanReq) {
cfg80211_scan_done(priv->pstrScanReq, false);
priv->u32RcvdChCount = 0;
priv->bCfgScanning = false;
priv->pstrScanReq = NULL;
}
up(&(priv->hSemScanReq));
-
- }
- /*Aborting any scan operation during mac close*/
- else if (enuScanEvent == SCAN_EVENT_ABORTED) {
+ } else if (scan_event == SCAN_EVENT_ABORTED) {
down(&(priv->hSemScanReq));
PRINT_D(CFG80211_DBG, "Scan Aborted\n");
- if (priv->pstrScanReq != NULL) {
-
- update_scan_time(priv);
+ if (priv->pstrScanReq) {
+ update_scan_time();
refresh_scan(priv, 1, false);
cfg80211_scan_done(priv->pstrScanReq, false);
@@ -471,60 +487,7 @@ static void CfgScanResult(enum scan_event enuScanEvent, tstrNetworkInfo *pstrNet
}
}
-
-/**
- * @brief WILC_WFI_Set_PMKSA
- * @details Check if pmksa is cached and set it.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
-int WILC_WFI_Set_PMKSA(u8 *bssid, struct wilc_priv *priv)
-{
- u32 i;
- s32 s32Error = 0;
-
-
- for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
-
- if (!memcmp(bssid, priv->pmkid_list.pmkidlist[i].bssid,
- ETH_ALEN)) {
- PRINT_D(CFG80211_DBG, "PMKID successful comparison");
-
- /*If bssid is found, set the values*/
- s32Error = host_int_set_pmkid_info(priv->hWILCWFIDrv, &priv->pmkid_list);
-
- if (s32Error != 0)
- PRINT_ER("Error in pmkid\n");
-
- break;
- }
- }
-
- return s32Error;
-
-
-}
-int linux_wlan_set_bssid(struct net_device *wilc_netdev, u8 *pBSSID);
-
-
-/**
- * @brief CfgConnectResult
- * @details
- * @param[in] tenuConnDisconnEvent enuConnDisconnEvent: Type of connection response either
- * connection response or disconnection notification.
- * tstrConnectInfo* pstrConnectInfo: COnnection information.
- * u8 u8MacStatus: Mac Status from firmware
- * tstrDisconnectNotifInfo* pstrDisconnectNotifInfo: Disconnection Notification
- * void* pUserVoid: Private data associated with wireless interface
- * @return NONE
- * @author mabubakr
- * @date 01 MAR 2012
- * @version 1.0
- */
-int connecting;
+int wilc_connecting;
static void CfgConnectResult(enum conn_event enuConnDisconnEvent,
tstrConnectInfo *pstrConnectInfo,
@@ -537,18 +500,17 @@ static void CfgConnectResult(enum conn_event enuConnDisconnEvent,
struct host_if_drv *pstrWFIDrv;
u8 NullBssid[ETH_ALEN] = {0};
struct wilc *wl;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
- connecting = 0;
+ wilc_connecting = 0;
priv = (struct wilc_priv *)pUserVoid;
dev = priv->dev;
- nic = netdev_priv(dev);
- wl = nic->wilc;
+ vif = netdev_priv(dev);
+ wl = vif->wilc;
pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
if (enuConnDisconnEvent == CONN_DISCONN_EVENT_CONN_RESP) {
- /*Initialization*/
u16 u16ConnectStatus;
u16ConnectStatus = pstrConnectInfo->u16ConnectStatus;
@@ -557,15 +519,12 @@ static void CfgConnectResult(enum conn_event enuConnDisconnEvent,
if ((u8MacStatus == MAC_DISCONNECTED) &&
(pstrConnectInfo->u16ConnectStatus == SUCCESSFUL_STATUSCODE)) {
- /* The case here is that our station was waiting for association response frame and has just received it containing status code
- * = SUCCESSFUL_STATUSCODE, while mac status is MAC_DISCONNECTED (which means something wrong happened) */
u16ConnectStatus = WLAN_STATUS_UNSPECIFIED_FAILURE;
- linux_wlan_set_bssid(priv->dev, NullBssid);
- eth_zero_addr(u8ConnectedSSID);
+ wilc_wlan_set_bssid(priv->dev, NullBssid);
+ eth_zero_addr(wilc_connected_ssid);
- /*Invalidate u8WLANChannel value on wlan0 disconnect*/
- if (!pstrWFIDrv->u8P2PConnect)
- u8WLANChannel = INVALID_CHANNEL;
+ if (!pstrWFIDrv->p2p_connect)
+ wlan_channel = INVALID_CHANNEL;
PRINT_ER("Unspecified failure: Connection status %d : MAC status = %d\n", u16ConnectStatus, u8MacStatus);
}
@@ -579,13 +538,13 @@ static void CfgConnectResult(enum conn_event enuConnDisconnEvent,
memcpy(priv->au8AssociatedBss, pstrConnectInfo->au8bssid, ETH_ALEN);
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid,
- pstrConnectInfo->au8bssid, ETH_ALEN) == 0) {
+ for (i = 0; i < last_scanned_cnt; i++) {
+ if (memcmp(last_scanned_shadow[i].au8bssid,
+ pstrConnectInfo->au8bssid, ETH_ALEN) == 0) {
unsigned long now = jiffies;
if (time_after(now,
- astrLastScannedNtwrksShadow[i].u32TimeRcvdInScanCached + (unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ)))) {
+ last_scanned_shadow[i].u32TimeRcvdInScanCached + (unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ)))) {
bNeedScanRefresh = true;
}
@@ -593,12 +552,8 @@ static void CfgConnectResult(enum conn_event enuConnDisconnEvent,
}
}
- if (bNeedScanRefresh) {
- /*Also, refrsh DIRECT- results if */
+ if (bNeedScanRefresh)
refresh_scan(priv, 1, true);
-
- }
-
}
@@ -609,68 +564,47 @@ static void CfgConnectResult(enum conn_event enuConnDisconnEvent,
cfg80211_connect_result(dev, pstrConnectInfo->au8bssid,
pstrConnectInfo->pu8ReqIEs, pstrConnectInfo->ReqIEsLen,
pstrConnectInfo->pu8RespIEs, pstrConnectInfo->u16RespIEsLen,
- u16ConnectStatus, GFP_KERNEL); /* TODO: mostafa: u16ConnectStatus to */
- /* be replaced by pstrConnectInfo->u16ConnectStatus */
+ u16ConnectStatus, GFP_KERNEL);
} else if (enuConnDisconnEvent == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
- g_obtainingIP = false;
+ wilc_optaining_ip = false;
PRINT_ER("Received MAC_DISCONNECTED from firmware with reason %d on dev [%p]\n",
pstrDisconnectNotifInfo->u16reason, priv->dev);
- u8P2Plocalrandom = 0x01;
- u8P2Precvrandom = 0x00;
- bWilc_ie = false;
+ p2p_local_random = 0x01;
+ p2p_recv_random = 0x00;
+ wilc_ie = false;
eth_zero_addr(priv->au8AssociatedBss);
- linux_wlan_set_bssid(priv->dev, NullBssid);
- eth_zero_addr(u8ConnectedSSID);
-
- /*Invalidate u8WLANChannel value on wlan0 disconnect*/
- if (!pstrWFIDrv->u8P2PConnect)
- u8WLANChannel = INVALID_CHANNEL;
- /*Incase "P2P CLIENT Connected" send deauthentication reason by 3 to force the WPA_SUPPLICANT to directly change
- * virtual interface to station*/
- if ((pstrWFIDrv->IFC_UP) && (dev == wl->vif[1].ndev)) {
+ wilc_wlan_set_bssid(priv->dev, NullBssid);
+ eth_zero_addr(wilc_connected_ssid);
+
+ if (!pstrWFIDrv->p2p_connect)
+ wlan_channel = INVALID_CHANNEL;
+ if ((pstrWFIDrv->IFC_UP) && (dev == wl->vif[1]->ndev)) {
pstrDisconnectNotifInfo->u16reason = 3;
- }
- /*Incase "P2P CLIENT during connection(not connected)" send deauthentication reason by 1 to force the WPA_SUPPLICANT
- * to scan again and retry the connection*/
- else if ((!pstrWFIDrv->IFC_UP) && (dev == wl->vif[1].ndev)) {
+ } else if ((!pstrWFIDrv->IFC_UP) && (dev == wl->vif[1]->ndev)) {
pstrDisconnectNotifInfo->u16reason = 1;
}
cfg80211_disconnected(dev, pstrDisconnectNotifInfo->u16reason, pstrDisconnectNotifInfo->ie,
pstrDisconnectNotifInfo->ie_len, false,
GFP_KERNEL);
-
}
-
}
-
-/**
- * @brief set_channel
- * @details Set channel for a given wireless interface. Some devices
- * may support multi-channel operation (by channel hopping) so cfg80211
- * doesn't verify much. Note, however, that the passed netdev may be
- * %NULL as well if the user requested changing the channel for the
- * device itself, or for a monitor interface.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int set_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
u32 channelnum = 0;
struct wilc_priv *priv;
int result = 0;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
PRINT_D(CFG80211_DBG, "Setting channel %d with frequency %d\n", channelnum, chandef->chan->center_freq);
curr_channel = channelnum;
- result = host_int_set_mac_chnl_num(priv->hWILCWFIDrv, channelnum);
+ result = wilc_set_mac_chnl_num(vif, channelnum);
if (result != 0)
PRINT_ER("Error in setting channel %d\n", channelnum);
@@ -678,19 +612,6 @@ static int set_channel(struct wiphy *wiphy,
return result;
}
-/**
- * @brief scan
- * @details Request to do a scan. If returning zero, the scan request is given
- * the driver, and will be valid until passed to cfg80211_scan_done().
- * For scan results, call cfg80211_inform_bss(); you can call this outside
- * the scan/scan_done bracket too.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mabubakr
- * @date 01 MAR 2012
- * @version 1.0
- */
-
static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
struct wilc_priv *priv;
@@ -698,21 +619,20 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
s32 s32Error = 0;
u8 au8ScanChanList[MAX_NUM_SCANNED_NETWORKS];
struct hidden_network strHiddenNetwork;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
priv->pstrScanReq = request;
priv->u32RcvdChCount = 0;
- host_int_set_wfi_drv_handler(priv->hWILCWFIDrv);
-
-
- reset_shadow_found(priv);
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif));
+ reset_shadow_found();
priv->bCfgScanning = true;
- if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) { /* TODO: mostafa: to be replaced by */
- /* max_scan_ssids */
+ if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) {
for (i = 0; i < request->n_channels; i++) {
au8ScanChanList[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq);
PRINT_INFO(CFG80211_DBG, "ScanChannel List[%d] = %d,", i, au8ScanChanList[i]);
@@ -724,15 +644,13 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
PRINT_D(CFG80211_DBG, "Number of SSIDs %d\n", request->n_ssids);
if (request->n_ssids >= 1) {
-
-
strHiddenNetwork.pstrHiddenNetworkInfo = kmalloc(request->n_ssids * sizeof(struct hidden_network), GFP_KERNEL);
strHiddenNetwork.u8ssidnum = request->n_ssids;
for (i = 0; i < request->n_ssids; i++) {
-
- if (request->ssids[i].ssid != NULL && request->ssids[i].ssid_len != 0) {
+ if (request->ssids[i].ssid &&
+ request->ssids[i].ssid_len != 0) {
strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL);
memcpy(strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid, request->ssids[i].ssid, request->ssids[i].ssid_len);
strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen = request->ssids[i].ssid_len;
@@ -742,18 +660,21 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
}
}
PRINT_D(CFG80211_DBG, "Trigger Scan Request\n");
- s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN,
- au8ScanChanList, request->n_channels,
- (const u8 *)request->ie, request->ie_len,
- CfgScanResult, (void *)priv, &strHiddenNetwork);
+ s32Error = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN,
+ au8ScanChanList,
+ request->n_channels,
+ (const u8 *)request->ie,
+ request->ie_len, CfgScanResult,
+ (void *)priv, &strHiddenNetwork);
} else {
PRINT_D(CFG80211_DBG, "Trigger Scan Request\n");
- s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN,
- au8ScanChanList, request->n_channels,
- (const u8 *)request->ie, request->ie_len,
- CfgScanResult, (void *)priv, NULL);
+ s32Error = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN,
+ au8ScanChanList,
+ request->n_channels,
+ (const u8 *)request->ie,
+ request->ie_len, CfgScanResult,
+ (void *)priv, NULL);
}
-
} else {
PRINT_ER("Requested num of scanned channels is greater than the max, supported"
" channels\n");
@@ -767,18 +688,6 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
return s32Error;
}
-/**
- * @brief connect
- * @details Connect to the ESS with the specified parameters. When connected,
- * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS.
- * If the connection fails for some reason, call cfg80211_connect_result()
- * with the status from the AP.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mabubakr
- * @date 01 MAR 2012
- * @version 1.0
- */
static int connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
@@ -793,39 +702,37 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
struct wilc_priv *priv;
struct host_if_drv *pstrWFIDrv;
tstrNetworkInfo *pstrNetworkInfo = NULL;
+ struct wilc_vif *vif;
-
- connecting = 1;
+ wilc_connecting = 1;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
pstrWFIDrv = (struct host_if_drv *)(priv->hWILCWFIDrv);
- host_int_set_wfi_drv_handler(priv->hWILCWFIDrv);
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif));
PRINT_D(CFG80211_DBG, "Connecting to SSID [%s] on netdev [%p] host if [%p]\n", sme->ssid, dev, priv->hWILCWFIDrv);
if (!(strncmp(sme->ssid, "DIRECT-", 7))) {
PRINT_D(CFG80211_DBG, "Connected to Direct network,OBSS disabled\n");
- pstrWFIDrv->u8P2PConnect = 1;
- } else
- pstrWFIDrv->u8P2PConnect = 0;
+ pstrWFIDrv->p2p_connect = 1;
+ } else {
+ pstrWFIDrv->p2p_connect = 0;
+ }
PRINT_INFO(CFG80211_DBG, "Required SSID = %s\n , AuthType = %d\n", sme->ssid, sme->auth_type);
- for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) {
- if ((sme->ssid_len == astrLastScannedNtwrksShadow[i].u8SsidLen) &&
- memcmp(astrLastScannedNtwrksShadow[i].au8ssid,
- sme->ssid,
- sme->ssid_len) == 0) {
+ for (i = 0; i < last_scanned_cnt; i++) {
+ if ((sme->ssid_len == last_scanned_shadow[i].u8SsidLen) &&
+ memcmp(last_scanned_shadow[i].au8ssid,
+ sme->ssid,
+ sme->ssid_len) == 0) {
PRINT_INFO(CFG80211_DBG, "Network with required SSID is found %s\n", sme->ssid);
- if (sme->bssid == NULL) {
- /* BSSID is not passed from the user, so decision of matching
- * is done by SSID only */
+ if (!sme->bssid) {
PRINT_INFO(CFG80211_DBG, "BSSID is not passed from the user\n");
break;
} else {
- /* BSSID is also passed from the user, so decision of matching
- * should consider also this passed BSSID */
- if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid,
- sme->bssid,
- ETH_ALEN) == 0) {
+ if (memcmp(last_scanned_shadow[i].au8bssid,
+ sme->bssid,
+ ETH_ALEN) == 0) {
PRINT_INFO(CFG80211_DBG, "BSSID is passed from the user and matched\n");
break;
}
@@ -833,10 +740,10 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
}
}
- if (i < u32LastScannedNtwrksCountShadow) {
+ if (i < last_scanned_cnt) {
PRINT_D(CFG80211_DBG, "Required bss is in scan results\n");
- pstrNetworkInfo = &(astrLastScannedNtwrksShadow[i]);
+ pstrNetworkInfo = &last_scanned_shadow[i];
PRINT_INFO(CFG80211_DBG, "network BSSID to be associated: %x%x%x%x%x%x\n",
pstrNetworkInfo->au8bssid[0], pstrNetworkInfo->au8bssid[1],
@@ -844,7 +751,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
pstrNetworkInfo->au8bssid[4], pstrNetworkInfo->au8bssid[5]);
} else {
s32Error = -ENOENT;
- if (u32LastScannedNtwrksCountShadow == 0)
+ if (last_scanned_cnt == 0)
PRINT_D(CFG80211_DBG, "No Scan results yet\n");
else
PRINT_D(CFG80211_DBG, "Required bss not in scan results: Error(%d)\n", s32Error);
@@ -867,8 +774,6 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
}
if (sme->crypto.cipher_group != NO_ENCRYPT) {
- /* To determine the u8security value, first we check the group cipher suite then {in case of WPA or WPA2}
- * we will add to it the pairwise cipher suite(s) */
pcwpa_version = "Default";
PRINT_D(CORECONFIG_DBG, ">> sme->crypto.wpa_versions: %x\n", sme->crypto.wpa_versions);
if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) {
@@ -891,8 +796,9 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
g_key_wep_params.key_idx = sme->key_idx;
g_wep_keys_saved = true;
- host_int_set_wep_default_key(priv->hWILCWFIDrv, sme->key_idx);
- host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, sme->key, sme->key_len, sme->key_idx);
+ wilc_set_wep_default_keyid(vif, sme->key_idx);
+ wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
+ sme->key_idx);
} else if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104) {
u8security = ENCRYPT_ENABLED | WEP | WEP_EXTENDED;
pcgroup_encrypt_val = "WEP104";
@@ -908,15 +814,15 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
g_key_wep_params.key_idx = sme->key_idx;
g_wep_keys_saved = true;
- host_int_set_wep_default_key(priv->hWILCWFIDrv, sme->key_idx);
- host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, sme->key, sme->key_len, sme->key_idx);
+ wilc_set_wep_default_keyid(vif, sme->key_idx);
+ wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
+ sme->key_idx);
} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_TKIP) {
u8security = ENCRYPT_ENABLED | WPA2 | TKIP;
pcgroup_encrypt_val = "WPA2_TKIP";
pccipher_group = "TKIP";
- } else { /* TODO: mostafa: here we assume that any other encryption type is AES */
- /* tenuSecurity_t = WPA2_AES; */
+ } else {
u8security = ENCRYPT_ENABLED | WPA2 | AES;
pcgroup_encrypt_val = "WPA2_AES";
pccipher_group = "AES";
@@ -927,12 +833,10 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
u8security = ENCRYPT_ENABLED | WPA | TKIP;
pcgroup_encrypt_val = "WPA_TKIP";
pccipher_group = "TKIP";
- } else { /* TODO: mostafa: here we assume that any other encryption type is AES */
- /* tenuSecurity_t = WPA_AES; */
+ } else {
u8security = ENCRYPT_ENABLED | WPA | AES;
pcgroup_encrypt_val = "WPA_AES";
pccipher_group = "AES";
-
}
pcwpa_version = "WPA_VERSION_1";
@@ -942,17 +846,14 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
goto done;
}
-
}
- /* After we set the u8security value from checking the group cipher suite, {in case of WPA or WPA2} we will
- * add to it the pairwise cipher suite(s) */
if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
|| (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) {
if (sme->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP) {
u8security = u8security | TKIP;
- } else { /* TODO: mostafa: here we assume that any other encryption type is AES */
+ } else {
u8security = u8security | AES;
}
}
@@ -976,8 +877,6 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
PRINT_D(CFG80211_DBG, "Automatic Authentation type = %d\n", sme->auth_type);
}
-
- /* ai: key_mgmt: enterprise case */
if (sme->crypto.n_akm_suites) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
@@ -997,19 +896,19 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
curr_channel = pstrNetworkInfo->u8channel;
- if (!pstrWFIDrv->u8P2PConnect) {
- u8WLANChannel = pstrNetworkInfo->u8channel;
- }
+ if (!pstrWFIDrv->p2p_connect)
+ wlan_channel = pstrNetworkInfo->u8channel;
- linux_wlan_set_bssid(dev, pstrNetworkInfo->au8bssid);
+ wilc_wlan_set_bssid(dev, pstrNetworkInfo->au8bssid);
- s32Error = host_int_set_join_req(priv->hWILCWFIDrv, pstrNetworkInfo->au8bssid, sme->ssid,
- sme->ssid_len, sme->ie, sme->ie_len,
- CfgConnectResult, (void *)priv, u8security,
- tenuAuth_type, pstrNetworkInfo->u8channel,
- pstrNetworkInfo->pJoinParams);
+ s32Error = wilc_set_join_req(vif, pstrNetworkInfo->au8bssid, sme->ssid,
+ sme->ssid_len, sme->ie, sme->ie_len,
+ CfgConnectResult, (void *)priv,
+ u8security, tenuAuth_type,
+ pstrNetworkInfo->u8channel,
+ pstrNetworkInfo->pJoinParams);
if (s32Error != 0) {
- PRINT_ER("host_int_set_join_req(): Error(%d)\n", s32Error);
+ PRINT_ER("wilc_set_join_req(): Error(%d)\n", s32Error);
s32Error = -ENOENT;
goto done;
}
@@ -1019,40 +918,31 @@ done:
return s32Error;
}
-
-/**
- * @brief disconnect
- * @details Disconnect from the BSS/ESS.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code)
{
s32 s32Error = 0;
struct wilc_priv *priv;
struct host_if_drv *pstrWFIDrv;
+ struct wilc_vif *vif;
u8 NullBssid[ETH_ALEN] = {0};
- connecting = 0;
+ wilc_connecting = 0;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
- /*Invalidate u8WLANChannel value on wlan0 disconnect*/
pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
- if (!pstrWFIDrv->u8P2PConnect)
- u8WLANChannel = INVALID_CHANNEL;
- linux_wlan_set_bssid(priv->dev, NullBssid);
+ if (!pstrWFIDrv->p2p_connect)
+ wlan_channel = INVALID_CHANNEL;
+ wilc_wlan_set_bssid(priv->dev, NullBssid);
PRINT_D(CFG80211_DBG, "Disconnecting with reason code(%d)\n", reason_code);
- u8P2Plocalrandom = 0x01;
- u8P2Precvrandom = 0x00;
- bWilc_ie = false;
- pstrWFIDrv->u64P2p_MgmtTimeout = 0;
+ p2p_local_random = 0x01;
+ p2p_recv_random = 0x00;
+ wilc_ie = false;
+ pstrWFIDrv->p2p_timeout = 0;
- s32Error = host_int_disconnect(priv->hWILCWFIDrv, reason_code);
+ s32Error = wilc_disconnect(vif, reason_code);
if (s32Error != 0) {
PRINT_ER("Error in disconnecting: Error(%d)\n", s32Error);
s32Error = -EINVAL;
@@ -1061,16 +951,6 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_co
return s32Error;
}
-/**
- * @brief add_key
- * @details Add a key with the given parameters. @mac_addr will be %NULL
- * when adding a group key.
- * @param[in] key : key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise,
const u8 *mac_addr, struct key_params *params)
@@ -1086,11 +966,11 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
u8 u8pmode = NO_ENCRYPT;
enum AUTHTYPE tenuAuth_type = ANY;
struct wilc *wl;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(netdev);
- wl = nic->wilc;
+ vif = netdev_priv(netdev);
+ wl = vif->wilc;
PRINT_D(CFG80211_DBG, "Adding key with cipher suite = %x\n", params->cipher);
@@ -1105,7 +985,6 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
if (priv->wdev->iftype == NL80211_IFTYPE_AP) {
-
priv->WILC_WFI_wep_default = key_index;
priv->WILC_WFI_wep_key_len[key_index] = params->key_len;
memcpy(priv->WILC_WFI_wep_key[key_index], params->key, params->key_len);
@@ -1123,7 +1002,9 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
else
u8mode = ENCRYPT_ENABLED | WEP | WEP_EXTENDED;
- host_int_add_wep_key_bss_ap(priv->hWILCWFIDrv, params->key, params->key_len, key_index, u8mode, tenuAuth_type);
+ wilc_add_wep_key_bss_ap(vif, params->key,
+ params->key_len, key_index,
+ u8mode, tenuAuth_type);
break;
}
if (memcmp(params->key, priv->WILC_WFI_wep_key[key_index], params->key_len)) {
@@ -1137,7 +1018,8 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
for (i = 0; i < params->key_len; i++)
PRINT_INFO(CFG80211_DBG, "WEP key value[%d] = %d\n", i, params->key[i]);
}
- host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, params->key, params->key_len, key_index);
+ wilc_add_wep_key_bss_sta(vif, params->key,
+ params->key_len, key_index);
}
break;
@@ -1145,14 +1027,12 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
if (priv->wdev->iftype == NL80211_IFTYPE_AP || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO) {
-
- if (priv->wilc_gtk[key_index] == NULL) {
+ if (!priv->wilc_gtk[key_index]) {
priv->wilc_gtk[key_index] = kmalloc(sizeof(struct wilc_wfi_key), GFP_KERNEL);
priv->wilc_gtk[key_index]->key = NULL;
priv->wilc_gtk[key_index]->seq = NULL;
-
}
- if (priv->wilc_ptk[key_index] == NULL) {
+ if (!priv->wilc_ptk[key_index]) {
priv->wilc_ptk[key_index] = kmalloc(sizeof(struct wilc_wfi_key), GFP_KERNEL);
priv->wilc_ptk[key_index]->key = NULL;
priv->wilc_ptk[key_index]->seq = NULL;
@@ -1169,18 +1049,14 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
priv->wilc_groupkey = u8gmode;
if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) {
-
pu8TxMic = params->key + 24;
pu8RxMic = params->key + 16;
KeyLen = params->key_len - 16;
}
- /* if there has been previous allocation for the same index through its key, free that memory and allocate again*/
kfree(priv->wilc_gtk[key_index]->key);
priv->wilc_gtk[key_index]->key = kmalloc(params->key_len, GFP_KERNEL);
memcpy(priv->wilc_gtk[key_index]->key, params->key, params->key_len);
-
- /* if there has been previous allocation for the same index through its seq, free that memory and allocate again*/
kfree(priv->wilc_gtk[key_index]->seq);
if ((params->seq_len) > 0) {
@@ -1200,8 +1076,10 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
}
- host_int_add_rx_gtk(priv->hWILCWFIDrv, params->key, KeyLen,
- key_index, params->seq_len, params->seq, pu8RxMic, pu8TxMic, AP_MODE, u8gmode);
+ wilc_add_rx_gtk(vif, params->key, KeyLen,
+ key_index, params->seq_len,
+ params->seq, pu8RxMic,
+ pu8TxMic, AP_MODE, u8gmode);
} else {
PRINT_INFO(CFG80211_DBG, "STA Address: %x%x%x%x%x\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4]);
@@ -1213,7 +1091,6 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) {
-
pu8TxMic = params->key + 24;
pu8RxMic = params->key + 16;
KeyLen = params->key_len - 16;
@@ -1245,8 +1122,9 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
priv->wilc_ptk[key_index]->key_len = params->key_len;
priv->wilc_ptk[key_index]->seq_len = params->seq_len;
- host_int_add_ptk(priv->hWILCWFIDrv, params->key, KeyLen, mac_addr,
- pu8RxMic, pu8TxMic, AP_MODE, u8pmode, key_index);
+ wilc_add_ptk(vif, params->key, KeyLen,
+ mac_addr, pu8RxMic, pu8TxMic,
+ AP_MODE, u8pmode, key_index);
}
break;
}
@@ -1255,14 +1133,12 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
u8mode = 0;
if (!pairwise) {
if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) {
- /* swap the tx mic by rx mic */
pu8RxMic = params->key + 24;
pu8TxMic = params->key + 16;
KeyLen = params->key_len - 16;
}
- /*save keys only on interface 0 (wifi interface)*/
- if (!g_gtk_keys_saved && netdev == wl->vif[0].ndev) {
+ if (!g_gtk_keys_saved && netdev == wl->vif[0]->ndev) {
g_add_gtk_key_params.key_idx = key_index;
g_add_gtk_key_params.pairwise = pairwise;
if (!mac_addr) {
@@ -1287,18 +1163,19 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
g_gtk_keys_saved = true;
}
- host_int_add_rx_gtk(priv->hWILCWFIDrv, params->key, KeyLen,
- key_index, params->seq_len, params->seq, pu8RxMic, pu8TxMic, STATION_MODE, u8mode);
+ wilc_add_rx_gtk(vif, params->key, KeyLen,
+ key_index, params->seq_len,
+ params->seq, pu8RxMic,
+ pu8TxMic, STATION_MODE,
+ u8mode);
} else {
if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) {
- /* swap the tx mic by rx mic */
pu8RxMic = params->key + 24;
pu8TxMic = params->key + 16;
KeyLen = params->key_len - 16;
}
- /*save keys only on interface 0 (wifi interface)*/
- if (!g_ptk_keys_saved && netdev == wl->vif[0].ndev) {
+ if (!g_ptk_keys_saved && netdev == wl->vif[0]->ndev) {
g_add_ptk_key_params.key_idx = key_index;
g_add_ptk_key_params.pairwise = pairwise;
if (!mac_addr) {
@@ -1323,8 +1200,9 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
g_ptk_keys_saved = true;
}
- host_int_add_ptk(priv->hWILCWFIDrv, params->key, KeyLen, mac_addr,
- pu8RxMic, pu8TxMic, STATION_MODE, u8mode, key_index);
+ wilc_add_ptk(vif, params->key, KeyLen,
+ mac_addr, pu8RxMic, pu8TxMic,
+ STATION_MODE, u8mode, key_index);
PRINT_D(CFG80211_DBG, "Adding pairwise key\n");
if (INFO) {
for (i = 0; i < params->key_len; i++)
@@ -1337,22 +1215,11 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
default:
PRINT_ER("Not supported cipher: Error(%d)\n", s32Error);
s32Error = -ENOTSUPP;
-
}
return s32Error;
}
-/**
- * @brief del_key
- * @details Remove a key given the @mac_addr (%NULL for a group key)
- * and @key_index, return -ENOENT if the key doesn't exist.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index,
bool pairwise,
@@ -1360,26 +1227,21 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
{
struct wilc_priv *priv;
struct wilc *wl;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(netdev);
- wl = nic->wilc;
+ vif = netdev_priv(netdev);
+ wl = vif->wilc;
- /*delete saved keys, if any*/
- if (netdev == wl->vif[0].ndev) {
+ if (netdev == wl->vif[0]->ndev) {
g_ptk_keys_saved = false;
g_gtk_keys_saved = false;
g_wep_keys_saved = false;
- /*Delete saved WEP keys params, if any*/
kfree(g_key_wep_params.key);
g_key_wep_params.key = NULL;
- /*freeing memory allocated by "wilc_gtk" and "wilc_ptk" in "WILC_WIFI_ADD_KEY"*/
-
if ((priv->wilc_gtk[key_index]) != NULL) {
-
kfree(priv->wilc_gtk[key_index]->key);
priv->wilc_gtk[key_index]->key = NULL;
kfree(priv->wilc_gtk[key_index]->seq);
@@ -1387,11 +1249,9 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
kfree(priv->wilc_gtk[key_index]);
priv->wilc_gtk[key_index] = NULL;
-
}
if ((priv->wilc_ptk[key_index]) != NULL) {
-
kfree(priv->wilc_ptk[key_index]->key);
priv->wilc_ptk[key_index]->key = NULL;
kfree(priv->wilc_ptk[key_index]->seq);
@@ -1400,7 +1260,6 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
priv->wilc_ptk[key_index] = NULL;
}
- /*Delete saved PTK and GTK keys params, if any*/
kfree(g_key_ptk_params.key);
g_key_ptk_params.key = NULL;
kfree(g_key_ptk_params.seq);
@@ -1411,8 +1270,7 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
kfree(g_key_gtk_params.seq);
g_key_gtk_params.seq = NULL;
- /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/
- Set_machw_change_vir_if(netdev, false);
+ wilc_set_machw_change_vir_if(netdev, false);
}
if (key_index >= 0 && key_index <= 3) {
@@ -1420,28 +1278,15 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
priv->WILC_WFI_wep_key_len[key_index] = 0;
PRINT_D(CFG80211_DBG, "Removing WEP key with index = %d\n", key_index);
- host_int_remove_wep_key(priv->hWILCWFIDrv, key_index);
+ wilc_remove_wep_key(vif, key_index);
} else {
PRINT_D(CFG80211_DBG, "Removing all installed keys\n");
- host_int_remove_key(priv->hWILCWFIDrv, mac_addr);
+ wilc_remove_key(priv->hWILCWFIDrv, mac_addr);
}
return 0;
}
-/**
- * @brief get_key
- * @details Get information about the key with the given parameters.
- * @mac_addr will be %NULL when requesting information for a group
- * key. All pointers given to the @callback function need not be valid
- * after it returns. This function should return an error if it is
- * not possible to retrieve the key, -ENOENT if it doesn't exist.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise,
const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *))
@@ -1477,69 +1322,48 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
callback(cookie, &key_params);
- return 0; /* priv->wilc_gtk->key_len ?0 : -ENOENT; */
+ return 0;
}
-/**
- * @brief set_default_key
- * @details Set the default management frame key on an interface
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool unicast, bool multicast)
{
struct wilc_priv *priv;
-
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
PRINT_D(CFG80211_DBG, "Setting default key with idx = %d\n", key_index);
if (key_index != priv->WILC_WFI_wep_default) {
-
- host_int_set_wep_default_key(priv->hWILCWFIDrv, key_index);
+ wilc_set_wep_default_keyid(vif, key_index);
}
return 0;
}
-/**
- * @brief get_station
- * @details Get station information for the station identified by @mac
- * @param[in] NONE
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
-
static int get_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac, struct station_info *sinfo)
{
struct wilc_priv *priv;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
u32 i = 0;
u32 associatedsta = 0;
u32 inactive_time = 0;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(dev);
+ vif = netdev_priv(dev);
- if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) {
+ if (vif->iftype == AP_MODE || vif->iftype == GO_MODE) {
PRINT_D(HOSTAPD_DBG, "Getting station parameters\n");
PRINT_INFO(HOSTAPD_DBG, ": %x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4]);
for (i = 0; i < NUM_STA_ASSOCIATED; i++) {
-
if (!(memcmp(mac, priv->assoc_stainfo.au8Sta_AssociatedBss[i], ETH_ALEN))) {
associatedsta = i;
break;
}
-
}
if (associatedsta == -1) {
@@ -1549,16 +1373,15 @@ static int get_station(struct wiphy *wiphy, struct net_device *dev,
sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME);
- host_int_get_inactive_time(priv->hWILCWFIDrv, mac, &(inactive_time));
+ wilc_get_inactive_time(vif, mac, &inactive_time);
sinfo->inactive_time = 1000 * inactive_time;
PRINT_D(CFG80211_DBG, "Inactive time %d\n", sinfo->inactive_time);
-
}
- if (nic->iftype == STATION_MODE) {
+ if (vif->iftype == STATION_MODE) {
struct rf_info strStatistics;
- host_int_get_statistics(priv->hWILCWFIDrv, &strStatistics);
+ wilc_get_statistics(vif, &strStatistics);
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) |
BIT(NL80211_STA_INFO_RX_PACKETS) |
@@ -1566,16 +1389,17 @@ static int get_station(struct wiphy *wiphy, struct net_device *dev,
BIT(NL80211_STA_INFO_TX_FAILED) |
BIT(NL80211_STA_INFO_TX_BITRATE);
- sinfo->signal = strStatistics.s8RSSI;
- sinfo->rx_packets = strStatistics.u32RxCount;
- sinfo->tx_packets = strStatistics.u32TxCount + strStatistics.u32TxFailureCount;
- sinfo->tx_failed = strStatistics.u32TxFailureCount;
- sinfo->txrate.legacy = strStatistics.u8LinkSpeed * 10;
+ sinfo->signal = strStatistics.rssi;
+ sinfo->rx_packets = strStatistics.rx_cnt;
+ sinfo->tx_packets = strStatistics.tx_cnt + strStatistics.tx_fail_cnt;
+ sinfo->tx_failed = strStatistics.tx_fail_cnt;
+ sinfo->txrate.legacy = strStatistics.link_speed * 10;
- if ((strStatistics.u8LinkSpeed > TCP_ACK_FILTER_LINK_SPEED_THRESH) && (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED))
- Enable_TCP_ACK_Filter(true);
- else if (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED)
- Enable_TCP_ACK_Filter(false);
+ if ((strStatistics.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH) &&
+ (strStatistics.link_speed != DEFAULT_LINK_SPEED))
+ wilc_enable_tcp_ack_filter(true);
+ else if (strStatistics.link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(false);
PRINT_D(CORECONFIG_DBG, "*** stats[%d][%d][%d][%d][%d]\n", sinfo->signal, sinfo->rx_packets, sinfo->tx_packets,
sinfo->tx_failed, sinfo->txrate.legacy);
@@ -1583,28 +1407,6 @@ static int get_station(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
-
-/**
- * @brief change_bss
- * @details Modify parameters for a given BSS.
- * @param[in]
- * -use_cts_prot: Whether to use CTS protection
- * (0 = no, 1 = yes, -1 = do not change)
- * -use_short_preamble: Whether the use of short preambles is allowed
- * (0 = no, 1 = yes, -1 = do not change)
- * -use_short_slot_time: Whether the use of short slot time is allowed
- * (0 = no, 1 = yes, -1 = do not change)
- * -basic_rates: basic rates in IEEE 802.11 format
- * (or NULL for no change)
- * -basic_rates_len: number of basic rates
- * -ap_isolate: do not forward packets between connected stations
- * -ht_opmode: HT Operation mode
- * (u16 = opmode, -1 = do not change)
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int change_bss(struct wiphy *wiphy, struct net_device *dev,
struct bss_parameters *params)
{
@@ -1612,23 +1414,15 @@ static int change_bss(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
-/**
- * @brief set_wiphy_params
- * @details Notify that wiphy parameters have changed;
- * @param[in] Changed bitfield (see &enum wiphy_params_flags) describes which values
- * have changed.
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
s32 s32Error = 0;
struct cfg_param_val pstrCfgParamVal;
struct wilc_priv *priv;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
pstrCfgParamVal.flag = 0;
PRINT_D(CFG80211_DBG, "Setting Wiphy params\n");
@@ -1640,17 +1434,14 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
pstrCfgParamVal.short_retry_limit = priv->dev->ieee80211_ptr->wiphy->retry_short;
}
if (changed & WIPHY_PARAM_RETRY_LONG) {
-
PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RETRY_LONG %d\n", priv->dev->ieee80211_ptr->wiphy->retry_long);
pstrCfgParamVal.flag |= RETRY_LONG;
pstrCfgParamVal.long_retry_limit = priv->dev->ieee80211_ptr->wiphy->retry_long;
-
}
if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n", priv->dev->ieee80211_ptr->wiphy->frag_threshold);
pstrCfgParamVal.flag |= FRAG_THRESHOLD;
pstrCfgParamVal.frag_threshold = priv->dev->ieee80211_ptr->wiphy->frag_threshold;
-
}
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
@@ -1658,11 +1449,10 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
pstrCfgParamVal.flag |= RTS_THRESHOLD;
pstrCfgParamVal.rts_threshold = priv->dev->ieee80211_ptr->wiphy->rts_threshold;
-
}
PRINT_D(CFG80211_DBG, "Setting CFG params in the host interface\n");
- s32Error = hif_set_cfg(priv->hWILCWFIDrv, &pstrCfgParamVal);
+ s32Error = wilc_hif_set_cfg(vif, &pstrCfgParamVal);
if (s32Error)
PRINT_ER("Error in setting WIPHY PARAMS\n");
@@ -1670,33 +1460,22 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
return s32Error;
}
-/**
- * @brief set_pmksa
- * @details Cache a PMKID for a BSSID. This is mostly useful for fullmac
- * devices running firmwares capable of generating the (re) association
- * RSN IE. It allows for faster roaming between WPA2 BSSIDs.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
u32 i;
s32 s32Error = 0;
u8 flag = 0;
-
+ struct wilc_vif *vif;
struct wilc_priv *priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
PRINT_D(CFG80211_DBG, "Setting PMKSA\n");
for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
ETH_ALEN)) {
- /*If bssid already exists and pmkid value needs to reset*/
flag = PMKID_FOUND;
PRINT_D(CFG80211_DBG, "PMKID already exists\n");
break;
@@ -1717,24 +1496,14 @@ static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
if (!s32Error) {
PRINT_D(CFG80211_DBG, "Setting pmkid in the host interface\n");
- s32Error = host_int_set_pmkid_info(priv->hWILCWFIDrv, &priv->pmkid_list);
+ s32Error = wilc_set_pmkid_info(vif, &priv->pmkid_list);
}
return s32Error;
}
-/**
- * @brief del_pmksa
- * @details Delete a cached PMKID.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
-
u32 i;
s32 s32Error = 0;
@@ -1745,7 +1514,6 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
ETH_ALEN)) {
- /*If bssid is found, reset the values*/
PRINT_D(CFG80211_DBG, "Reseting PMKID values\n");
memset(&priv->pmkid_list.pmkidlist[i], 0, sizeof(struct host_if_pmkid));
break;
@@ -1769,43 +1537,18 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
return s32Error;
}
-/**
- * @brief flush_pmksa
- * @details Flush all cached PMKIDs.
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
{
struct wilc_priv *priv = wiphy_priv(wiphy);
PRINT_D(CFG80211_DBG, "Flushing PMKID key values\n");
- /*Get cashed Pmkids and set all with zeros*/
memset(&priv->pmkid_list, 0, sizeof(struct host_if_pmkid_attr));
return 0;
}
-
-/**
- * @brief WILC_WFI_CfgParseRxAction
- * @details Function parses the received frames and modifies the following attributes:
- * -GO Intent
- * -Channel list
- * -Operating Channel
- *
- * @param[in] u8* Buffer, u32 length
- * @return NONE.
- * @author mdaftedar
- * @date 12 DEC 2012
- * @version
- */
-
-void WILC_WFI_CfgParseRxAction(u8 *buf, u32 len)
+static void WILC_WFI_CfgParseRxAction(u8 *buf, u32 len)
{
u32 index = 0;
u32 i = 0, j = 0;
@@ -1822,42 +1565,30 @@ void WILC_WFI_CfgParseRxAction(u8 *buf, u32 len)
channel_list_attr_index = index;
else if (buf[index] == OPERCHAN_ATTR_ID)
op_channel_attr_index = index;
- index += buf[index + 1] + 3; /* ID,Length byte */
+ index += buf[index + 1] + 3;
}
- if (u8WLANChannel != INVALID_CHANNEL) {
-
- /*Modify channel list attribute*/
+ if (wlan_channel != INVALID_CHANNEL) {
if (channel_list_attr_index) {
PRINT_D(GENERIC_DBG, "Modify channel list attribute\n");
for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) {
if (buf[i] == 0x51) {
for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) {
- buf[j] = u8WLANChannel;
+ buf[j] = wlan_channel;
}
break;
}
}
}
- /*Modify operating channel attribute*/
+
if (op_channel_attr_index) {
PRINT_D(GENERIC_DBG, "Modify operating channel attribute\n");
buf[op_channel_attr_index + 6] = 0x51;
- buf[op_channel_attr_index + 7] = u8WLANChannel;
+ buf[op_channel_attr_index + 7] = wlan_channel;
}
}
}
-/**
- * @brief WILC_WFI_CfgParseTxAction
- * @details Function parses the transmitted action frames and modifies the
- * GO Intent attribute
- * @param[in] u8* Buffer, u32 length, bool bOperChan, u8 iftype
- * @return NONE.
- * @author mdaftedar
- * @date 12 DEC 2012
- * @version
- */
-void WILC_WFI_CfgParseTxAction(u8 *buf, u32 len, bool bOperChan, u8 iftype)
+static void WILC_WFI_CfgParseTxAction(u8 *buf, u32 len, bool bOperChan, u8 iftype)
{
u32 index = 0;
u32 i = 0, j = 0;
@@ -1876,44 +1607,31 @@ void WILC_WFI_CfgParseTxAction(u8 *buf, u32 len, bool bOperChan, u8 iftype)
channel_list_attr_index = index;
else if (buf[index] == OPERCHAN_ATTR_ID)
op_channel_attr_index = index;
- index += buf[index + 1] + 3; /* ID,Length byte */
+ index += buf[index + 1] + 3;
}
- if (u8WLANChannel != INVALID_CHANNEL && bOperChan) {
-
- /*Modify channel list attribute*/
+ if (wlan_channel != INVALID_CHANNEL && bOperChan) {
if (channel_list_attr_index) {
PRINT_D(GENERIC_DBG, "Modify channel list attribute\n");
for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) {
if (buf[i] == 0x51) {
for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) {
- buf[j] = u8WLANChannel;
+ buf[j] = wlan_channel;
}
break;
}
}
}
- /*Modify operating channel attribute*/
+
if (op_channel_attr_index) {
PRINT_D(GENERIC_DBG, "Modify operating channel attribute\n");
buf[op_channel_attr_index + 6] = 0x51;
- buf[op_channel_attr_index + 7] = u8WLANChannel;
+ buf[op_channel_attr_index + 7] = wlan_channel;
}
}
}
-/* @brief WILC_WFI_p2p_rx
- * @details
- * @param[in]
- *
- * @return None
- * @author Mai Daftedar
- * @date 2 JUN 2013
- * @version 1.0
- */
-
void WILC_WFI_p2p_rx (struct net_device *dev, u8 *buff, u32 size)
{
-
struct wilc_priv *priv;
u32 header, pkt_offset;
struct host_if_drv *pstrWFIDrv;
@@ -1923,11 +1641,8 @@ void WILC_WFI_p2p_rx (struct net_device *dev, u8 *buff, u32 size)
priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
- /* Get WILC header */
memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
- /* The packet offset field conain info about what type of managment frame */
- /* we are dealing with and ack status */
pkt_offset = GET_PKT_OFFSET(header);
if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
@@ -1948,21 +1663,18 @@ void WILC_WFI_p2p_rx (struct net_device *dev, u8 *buff, u32 size)
return;
}
} else {
-
PRINT_D(GENERIC_DBG, "Rx Frame Type:%x\n", buff[FRAME_TYPE_ID]);
- /*Upper layer is informed that the frame is received on this freq*/
s32Freq = ieee80211_channel_to_frequency(curr_channel, IEEE80211_BAND_2GHZ);
if (ieee80211_is_action(buff[FRAME_TYPE_ID])) {
PRINT_D(GENERIC_DBG, "Rx Action Frame Type: %x %x\n", buff[ACTION_SUBTYPE_ID], buff[P2P_PUB_ACTION_SUBTYPE]);
- if (priv->bCfgScanning && time_after_eq(jiffies, (unsigned long)pstrWFIDrv->u64P2p_MgmtTimeout)) {
+ if (priv->bCfgScanning && time_after_eq(jiffies, (unsigned long)pstrWFIDrv->p2p_timeout)) {
PRINT_D(GENERIC_DBG, "Receiving action frames from wrong channels\n");
return;
}
if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
-
switch (buff[ACTION_SUBTYPE_ID]) {
case GAS_INTIAL_REQ:
PRINT_D(GENERIC_DBG, "GAS INITIAL REQ %x\n", buff[ACTION_SUBTYPE_ID]);
@@ -1973,39 +1685,37 @@ void WILC_WFI_p2p_rx (struct net_device *dev, u8 *buff, u32 size)
break;
case PUBLIC_ACT_VENDORSPEC:
- /*Now we have a public action vendor specific action frame, check if its a p2p public action frame
- * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/
- if (!memcmp(u8P2P_oui, &buff[ACTION_SUBTYPE_ID + 1], 4)) {
+ if (!memcmp(p2p_oui, &buff[ACTION_SUBTYPE_ID + 1], 4)) {
if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) {
- if (!bWilc_ie) {
+ if (!wilc_ie) {
for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) {
- if (!memcmp(u8P2P_vendorspec, &buff[i], 6)) {
- u8P2Precvrandom = buff[i + 6];
- bWilc_ie = true;
- PRINT_D(GENERIC_DBG, "WILC Vendor specific IE:%02x\n", u8P2Precvrandom);
+ if (!memcmp(p2p_vendor_spec, &buff[i], 6)) {
+ p2p_recv_random = buff[i + 6];
+ wilc_ie = true;
+ PRINT_D(GENERIC_DBG, "WILC Vendor specific IE:%02x\n", p2p_recv_random);
break;
}
}
}
}
- if (u8P2Plocalrandom > u8P2Precvrandom) {
+ if (p2p_local_random > p2p_recv_random) {
if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP
|| buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) {
for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) {
- if (buff[i] == P2PELEM_ATTR_ID && !(memcmp(u8P2P_oui, &buff[i + 2], 4))) {
+ if (buff[i] == P2PELEM_ATTR_ID && !(memcmp(p2p_oui, &buff[i + 2], 4))) {
WILC_WFI_CfgParseRxAction(&buff[i + 6], size - (i + 6));
break;
}
}
}
- } else
- PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom);
+ } else {
+ PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", p2p_local_random, p2p_recv_random);
+ }
}
- if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP) && (bWilc_ie)) {
+ if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP) && (wilc_ie)) {
PRINT_D(GENERIC_DBG, "Sending P2P to host without extra elemnt\n");
- /* extra attribute for sig_dbm: signal strength in mBm, or 0 if unknown */
cfg80211_rx_mgmt(priv->wdev, s32Freq, 0, buff, size - 7, 0);
return;
}
@@ -2022,16 +1732,6 @@ void WILC_WFI_p2p_rx (struct net_device *dev, u8 *buff, u32 size)
}
}
-/**
- * @brief WILC_WFI_mgmt_tx_complete
- * @details Returns result of writing mgmt frame to VMM (Tx buffers are freed here)
- * @param[in] priv
- * transmitting status
- * @return None
- * @author Amr Abdelmoghny
- * @date 20 MAY 2013
- * @version 1.0
- */
static void WILC_WFI_mgmt_tx_complete(void *priv, int status)
{
struct p2p_mgmt_data *pv_data = (struct p2p_mgmt_data *)priv;
@@ -2041,16 +1741,6 @@ static void WILC_WFI_mgmt_tx_complete(void *priv, int status)
kfree(pv_data);
}
-/**
- * @brief WILC_WFI_RemainOnChannelReady
- * @details Callback function, called from handle_remain_on_channel on being ready on channel
- * @param
- * @return none
- * @author Amr abdelmoghny
- * @date 9 JUNE 2013
- * @version
- */
-
static void WILC_WFI_RemainOnChannelReady(void *pUserVoid)
{
struct wilc_priv *priv;
@@ -2068,16 +1758,6 @@ static void WILC_WFI_RemainOnChannelReady(void *pUserVoid)
GFP_KERNEL);
}
-/**
- * @brief WILC_WFI_RemainOnChannelExpired
- * @details Callback function, called on expiration of remain-on-channel duration
- * @param
- * @return none
- * @author Amr abdelmoghny
- * @date 15 MAY 2013
- * @version
- */
-
static void WILC_WFI_RemainOnChannelExpired(void *pUserVoid, u32 u32SessionID)
{
struct wilc_priv *priv;
@@ -2089,7 +1769,6 @@ static void WILC_WFI_RemainOnChannelExpired(void *pUserVoid, u32 u32SessionID)
priv->bInP2PlistenState = false;
- /*Inform wpas of remain-on-channel expiration*/
cfg80211_remain_on_channel_expired(priv->wdev,
priv->strRemainOnChanParams.u64ListenCookie,
priv->strRemainOnChanParams.pstrListenChan,
@@ -2100,20 +1779,6 @@ static void WILC_WFI_RemainOnChannelExpired(void *pUserVoid, u32 u32SessionID)
}
}
-
-/**
- * @brief remain_on_channel
- * @details Request the driver to remain awake on the specified
- * channel for the specified duration to complete an off-channel
- * operation (e.g., public action frame exchange). When the driver is
- * ready on the requested channel, it must indicate this with an event
- * notification by calling cfg80211_ready_on_channel().
- * @param[in]
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
@@ -2121,8 +1786,10 @@ static int remain_on_channel(struct wiphy *wiphy,
{
s32 s32Error = 0;
struct wilc_priv *priv;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
PRINT_D(GENERIC_DBG, "Remaining on channel %d\n", chan->hw_value);
@@ -2134,61 +1801,37 @@ static int remain_on_channel(struct wiphy *wiphy,
curr_channel = chan->hw_value;
- /*Setting params needed by WILC_WFI_RemainOnChannelExpired()*/
priv->strRemainOnChanParams.pstrListenChan = chan;
priv->strRemainOnChanParams.u64ListenCookie = *cookie;
priv->strRemainOnChanParams.u32ListenDuration = duration;
priv->strRemainOnChanParams.u32ListenSessionID++;
- s32Error = host_int_remain_on_channel(priv->hWILCWFIDrv
- , priv->strRemainOnChanParams.u32ListenSessionID
- , duration
- , chan->hw_value
- , WILC_WFI_RemainOnChannelExpired
- , WILC_WFI_RemainOnChannelReady
- , (void *)priv);
+ s32Error = wilc_remain_on_channel(vif,
+ priv->strRemainOnChanParams.u32ListenSessionID,
+ duration, chan->hw_value,
+ WILC_WFI_RemainOnChannelExpired,
+ WILC_WFI_RemainOnChannelReady, (void *)priv);
return s32Error;
}
-/**
- * @brief cancel_remain_on_channel
- * @details Cancel an on-going remain-on-channel operation.
- * This allows the operation to be terminated prior to timeout based on
- * the duration value.
- * @param[in] struct wiphy *wiphy,
- * @param[in] struct net_device *dev
- * @param[in] u64 cookie,
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int cancel_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie)
{
s32 s32Error = 0;
struct wilc_priv *priv;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
PRINT_D(CFG80211_DBG, "Cancel remain on channel\n");
- s32Error = host_int_ListenStateExpired(priv->hWILCWFIDrv, priv->strRemainOnChanParams.u32ListenSessionID);
+ s32Error = wilc_listen_state_expired(vif, priv->strRemainOnChanParams.u32ListenSessionID);
return s32Error;
}
-/**
- * @brief WILC_WFI_mgmt_tx_frame
- * @details
- *
- * @param[in]
- * @return NONE.
- * @author mdaftedar
- * @date 01 JUL 2012
- * @version
- */
-extern bool bEnablePS;
+
static int mgmt_tx(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
@@ -2203,10 +1846,10 @@ static int mgmt_tx(struct wiphy *wiphy,
struct wilc_priv *priv;
struct host_if_drv *pstrWFIDrv;
u32 i;
- perInterface_wlan_t *nic;
- u32 buf_len = len + sizeof(u8P2P_vendorspec) + sizeof(u8P2Plocalrandom);
+ struct wilc_vif *vif;
+ u32 buf_len = len + sizeof(p2p_vendor_spec) + sizeof(p2p_local_random);
- nic = netdev_priv(wdev->netdev);
+ vif = netdev_priv(wdev->netdev);
priv = wiphy_priv(wiphy);
pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv;
@@ -2215,15 +1858,13 @@ static int mgmt_tx(struct wiphy *wiphy,
mgmt = (const struct ieee80211_mgmt *) buf;
if (ieee80211_is_mgmt(mgmt->frame_control)) {
-
- /*mgmt frame allocation*/
mgmt_tx = kmalloc(sizeof(struct p2p_mgmt_data), GFP_KERNEL);
- if (mgmt_tx == NULL) {
+ if (!mgmt_tx) {
PRINT_ER("Failed to allocate memory for mgmt_tx structure\n");
return -EFAULT;
}
mgmt_tx->buff = kmalloc(buf_len, GFP_KERNEL);
- if (mgmt_tx->buff == NULL) {
+ if (!mgmt_tx->buff) {
PRINT_ER("Failed to allocate memory for mgmt_tx buff\n");
kfree(mgmt_tx);
return -EFAULT;
@@ -2235,23 +1876,18 @@ static int mgmt_tx(struct wiphy *wiphy,
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
PRINT_D(GENERIC_DBG, "TX: Probe Response\n");
PRINT_D(GENERIC_DBG, "Setting channel: %d\n", chan->hw_value);
- host_int_set_mac_chnl_num(priv->hWILCWFIDrv, chan->hw_value);
- /*Save the current channel after we tune to it*/
+ wilc_set_mac_chnl_num(vif, chan->hw_value);
curr_channel = chan->hw_value;
} else if (ieee80211_is_action(mgmt->frame_control)) {
PRINT_D(GENERIC_DBG, "ACTION FRAME:%x\n", (u16)mgmt->frame_control);
if (buf[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
- /*Only set the channel, if not a negotiation confirmation frame
- * (If Negotiation confirmation frame, force it
- * to be transmitted on the same negotiation channel)*/
-
if (buf[ACTION_SUBTYPE_ID] != PUBLIC_ACT_VENDORSPEC ||
buf[P2P_PUB_ACTION_SUBTYPE] != GO_NEG_CONF) {
PRINT_D(GENERIC_DBG, "Setting channel: %d\n", chan->hw_value);
- host_int_set_mac_chnl_num(priv->hWILCWFIDrv, chan->hw_value);
- /*Save the current channel after we tune to it*/
+ wilc_set_mac_chnl_num(vif,
+ chan->hw_value);
curr_channel = chan->hw_value;
}
switch (buf[ACTION_SUBTYPE_ID]) {
@@ -2269,48 +1905,37 @@ static int mgmt_tx(struct wiphy *wiphy,
case PUBLIC_ACT_VENDORSPEC:
{
- /*Now we have a public action vendor specific action frame, check if its a p2p public action frame
- * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/
- if (!memcmp(u8P2P_oui, &buf[ACTION_SUBTYPE_ID + 1], 4)) {
- /*For the connection of two WILC's connection generate a rand number to determine who will be a GO*/
+ if (!memcmp(p2p_oui, &buf[ACTION_SUBTYPE_ID + 1], 4)) {
if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) {
- if (u8P2Plocalrandom == 1 && u8P2Precvrandom < u8P2Plocalrandom) {
- get_random_bytes(&u8P2Plocalrandom, 1);
- /*Increment the number to prevent if its 0*/
- u8P2Plocalrandom++;
+ if (p2p_local_random == 1 && p2p_recv_random < p2p_local_random) {
+ get_random_bytes(&p2p_local_random, 1);
+ p2p_local_random++;
}
}
if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP
|| buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) {
- if (u8P2Plocalrandom > u8P2Precvrandom) {
- PRINT_D(GENERIC_DBG, "LOCAL WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom);
+ if (p2p_local_random > p2p_recv_random) {
+ PRINT_D(GENERIC_DBG, "LOCAL WILL BE GO LocaRand=%02x RecvRand %02x\n", p2p_local_random, p2p_recv_random);
- /*Search for the p2p information information element , after the Public action subtype theres a byte for teh dialog token, skip that*/
for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) {
- if (buf[i] == P2PELEM_ATTR_ID && !(memcmp(u8P2P_oui, &buf[i + 2], 4))) {
+ if (buf[i] == P2PELEM_ATTR_ID && !(memcmp(p2p_oui, &buf[i + 2], 4))) {
if (buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)
- WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), true, nic->iftype);
-
- /*If using supplicant go intent, no need at all*/
- /*to parse transmitted negotiation frames*/
+ WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), true, vif->iftype);
else
- WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), false, nic->iftype);
+ WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), false, vif->iftype);
break;
}
}
if (buf[P2P_PUB_ACTION_SUBTYPE] != P2P_INV_REQ && buf[P2P_PUB_ACTION_SUBTYPE] != P2P_INV_RSP) {
- /*
- * Adding WILC information element to allow two WILC devices to
- * identify each other and connect
- */
- memcpy(&mgmt_tx->buff[len], u8P2P_vendorspec, sizeof(u8P2P_vendorspec));
- mgmt_tx->buff[len + sizeof(u8P2P_vendorspec)] = u8P2Plocalrandom;
+ memcpy(&mgmt_tx->buff[len], p2p_vendor_spec, sizeof(p2p_vendor_spec));
+ mgmt_tx->buff[len + sizeof(p2p_vendor_spec)] = p2p_local_random;
mgmt_tx->size = buf_len;
}
- } else
- PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom);
+ } else {
+ PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", p2p_local_random, p2p_recv_random);
+ }
}
} else {
@@ -2326,18 +1951,17 @@ static int mgmt_tx(struct wiphy *wiphy,
break;
}
}
-
}
PRINT_D(GENERIC_DBG, "TX: ACTION FRAME Type:%x : Chan:%d\n", buf[ACTION_SUBTYPE_ID], chan->hw_value);
- pstrWFIDrv->u64P2p_MgmtTimeout = (jiffies + msecs_to_jiffies(wait));
-
- PRINT_D(GENERIC_DBG, "Current Jiffies: %lu Timeout:%llu\n", jiffies, pstrWFIDrv->u64P2p_MgmtTimeout);
+ pstrWFIDrv->p2p_timeout = (jiffies + msecs_to_jiffies(wait));
+ PRINT_D(GENERIC_DBG, "Current Jiffies: %lu Timeout:%llu\n",
+ jiffies, pstrWFIDrv->p2p_timeout);
}
- wilc_wlan_txq_add_mgmt_pkt(mgmt_tx, mgmt_tx->buff,
- mgmt_tx->size,
+ wilc_wlan_txq_add_mgmt_pkt(wdev->netdev, mgmt_tx,
+ mgmt_tx->buff, mgmt_tx->size,
WILC_WFI_mgmt_tx_complete);
} else {
PRINT_D(GENERIC_DBG, "This function transmits only management frames\n");
@@ -2357,7 +1981,7 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
PRINT_D(GENERIC_DBG, "Tx Cancel wait :%lu\n", jiffies);
- pstrWFIDrv->u64P2p_MgmtTimeout = jiffies;
+ pstrWFIDrv->p2p_timeout = jiffies;
if (!priv->bInP2PlistenState) {
cfg80211_remain_on_channel_expired(priv->wdev,
@@ -2369,28 +1993,16 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
return 0;
}
-/**
- * @brief wilc_mgmt_frame_register
- * @details Notify driver that a management frame type was
- * registered. Note that this callback may not sleep, and cannot run
- * concurrently with itself.
- * @param[in]
- * @return NONE.
- * @author mdaftedar
- * @date 01 JUL 2012
- * @version
- */
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
u16 frame_type, bool reg)
{
-
struct wilc_priv *priv;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wl;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(priv->wdev->netdev);
- wl = nic->wilc;
+ vif = netdev_priv(priv->wdev->netdev);
+ wl = vif->wilc;
if (!frame_type)
return;
@@ -2399,15 +2011,15 @@ void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
switch (frame_type) {
case PROBE_REQ:
{
- nic->g_struct_frame_reg[0].frame_type = frame_type;
- nic->g_struct_frame_reg[0].reg = reg;
+ vif->g_struct_frame_reg[0].frame_type = frame_type;
+ vif->g_struct_frame_reg[0].reg = reg;
}
break;
case ACTION:
{
- nic->g_struct_frame_reg[1].frame_type = frame_type;
- nic->g_struct_frame_reg[1].reg = reg;
+ vif->g_struct_frame_reg[1].frame_type = frame_type;
+ vif->g_struct_frame_reg[1].reg = reg;
}
break;
@@ -2415,54 +2027,27 @@ void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
{
break;
}
-
}
- /*If mac is closed, then return*/
+
if (!wl->initialized) {
PRINT_D(GENERIC_DBG, "Return since mac is closed\n");
return;
}
- host_int_frame_register(priv->hWILCWFIDrv, frame_type, reg);
-
-
+ wilc_frame_register(vif, frame_type, reg);
}
-/**
- * @brief set_cqm_rssi_config
- * @details Configure connection quality monitor RSSI threshold.
- * @param[in] struct wiphy *wiphy:
- * @param[in] struct net_device *dev:
- * @param[in] s32 rssi_thold:
- * @param[in] u32 rssi_hyst:
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
s32 rssi_thold, u32 rssi_hyst)
{
PRINT_D(CFG80211_DBG, "Setting CQM RSSi Function\n");
return 0;
-
}
-/**
- * @brief dump_station
- * @details Configure connection quality monitor RSSI threshold.
- * @param[in] struct wiphy *wiphy:
- * @param[in] struct net_device *dev
- * @param[in] int idx
- * @param[in] u8 *mac
- * @param[in] struct station_info *sinfo
- * @return int : Return 0 on Success
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
+
static int dump_station(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *mac, struct station_info *sinfo)
{
struct wilc_priv *priv;
+ struct wilc_vif *vif;
PRINT_D(CFG80211_DBG, "Dumping station information\n");
@@ -2470,143 +2055,109 @@ static int dump_station(struct wiphy *wiphy, struct net_device *dev,
return -ENOENT;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
- host_int_get_rssi(priv->hWILCWFIDrv, &(sinfo->signal));
+ wilc_get_rssi(vif, &sinfo->signal);
return 0;
-
}
-
-/**
- * @brief set_power_mgmt
- * @details
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 JUL 2012
- * @version 1.0
- */
static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout)
{
struct wilc_priv *priv;
+ struct wilc_vif *vif;
PRINT_D(CFG80211_DBG, " Power save Enabled= %d , TimeOut = %d\n", enabled, timeout);
- if (wiphy == NULL)
+ if (!wiphy)
return -ENOENT;
priv = wiphy_priv(wiphy);
- if (priv->hWILCWFIDrv == NULL) {
+ vif = netdev_priv(priv->dev);
+ if (!priv->hWILCWFIDrv) {
PRINT_ER("Driver is NULL\n");
return -EIO;
}
- if (bEnablePS)
- host_int_set_power_mgmt(priv->hWILCWFIDrv, enabled, timeout);
+ if (wilc_enable_ps)
+ wilc_set_power_mgmt(vif, enabled, timeout);
return 0;
-
}
-/**
- * @brief change_virtual_intf
- * @details Change type/configuration of virtual interface,
- * keep the struct wireless_dev's iftype updated.
- * @param[in] NONE
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
-int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic);
-
static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
enum nl80211_iftype type, u32 *flags, struct vif_params *params)
{
struct wilc_priv *priv;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
u8 interface_type;
u16 TID = 0;
u8 i;
struct wilc *wl;
- nic = netdev_priv(dev);
+ vif = netdev_priv(dev);
priv = wiphy_priv(wiphy);
- wl = nic->wilc;
+ wl = vif->wilc;
PRINT_D(HOSTAPD_DBG, "In Change virtual interface function\n");
PRINT_D(HOSTAPD_DBG, "Wireless interface name =%s\n", dev->name);
- u8P2Plocalrandom = 0x01;
- u8P2Precvrandom = 0x00;
-
- bWilc_ie = false;
-
- g_obtainingIP = false;
- del_timer(&hDuringIpTimer);
+ p2p_local_random = 0x01;
+ p2p_recv_random = 0x00;
+ wilc_ie = false;
+ wilc_optaining_ip = false;
+ del_timer(&wilc_during_ip_timer);
PRINT_D(GENERIC_DBG, "Changing virtual interface, enable scan\n");
- /*Set WILC_CHANGING_VIR_IF register to disallow adding futrue keys to CE H/W*/
+
if (g_ptk_keys_saved && g_gtk_keys_saved) {
- Set_machw_change_vir_if(dev, true);
+ wilc_set_machw_change_vir_if(dev, true);
}
switch (type) {
case NL80211_IFTYPE_STATION:
- connecting = 0;
+ wilc_connecting = 0;
PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_STATION\n");
- /* send delba over wlan interface */
-
-
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
- nic->monitor_flag = 0;
- nic->iftype = STATION_MODE;
+ vif->monitor_flag = 0;
+ vif->iftype = STATION_MODE;
- /*Remove the enteries of the previously connected clients*/
memset(priv->assoc_stainfo.au8Sta_AssociatedBss, 0, MAX_NUM_STA * ETH_ALEN);
- interface_type = nic->iftype;
- nic->iftype = STATION_MODE;
+ interface_type = vif->iftype;
+ vif->iftype = STATION_MODE;
if (wl->initialized) {
- host_int_del_All_Rx_BASession(priv->hWILCWFIDrv,
- wl->vif[0].bssid, TID);
- /* ensure that the message Q is empty */
- host_int_wait_msg_queue_idle();
+ wilc_del_all_rx_ba_session(vif, wl->vif[0]->bssid,
+ TID);
+ wilc_wait_msg_queue_idle();
- /*Eliminate host interface blocking state*/
up(&wl->cfg_event);
wilc1000_wlan_deinit(dev);
- wilc1000_wlan_init(dev, nic);
- g_wilc_initialized = 1;
- nic->iftype = interface_type;
+ wilc1000_wlan_init(dev, vif);
+ wilc_initialized = 1;
+ vif->iftype = interface_type;
- /*Setting interface 1 drv handler and mac address in newly downloaded FW*/
- host_int_set_wfi_drv_handler(wl->vif[0].hif_drv);
- host_int_set_MacAddress(wl->vif[0].hif_drv,
- wl->vif[0].src_addr);
- host_int_set_operation_mode(priv->hWILCWFIDrv, STATION_MODE);
+ wilc_set_wfi_drv_handler(vif,
+ wilc_get_vif_idx(wl->vif[0]));
+ wilc_set_mac_address(wl->vif[0], wl->vif[0]->src_addr);
+ wilc_set_operation_mode(vif, STATION_MODE);
- /*Add saved WEP keys, if any*/
if (g_wep_keys_saved) {
- host_int_set_wep_default_key(wl->vif[0].hif_drv,
- g_key_wep_params.key_idx);
- host_int_add_wep_key_bss_sta(wl->vif[0].hif_drv,
- g_key_wep_params.key,
- g_key_wep_params.key_len,
- g_key_wep_params.key_idx);
+ wilc_set_wep_default_keyid(wl->vif[0],
+ g_key_wep_params.key_idx);
+ wilc_add_wep_key_bss_sta(wl->vif[0],
+ g_key_wep_params.key,
+ g_key_wep_params.key_len,
+ g_key_wep_params.key_idx);
}
- /*No matter the driver handler passed here, it will be overwriiten*/
- /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/
- host_int_flush_join_req(priv->hWILCWFIDrv);
+ wilc_flush_join_req(vif);
- /*Add saved PTK and GTK keys, if any*/
if (g_ptk_keys_saved && g_gtk_keys_saved) {
PRINT_D(CFG80211_DBG, "ptk %x %x %x\n", g_key_ptk_params.key[0],
g_key_ptk_params.key[1],
@@ -2614,15 +2165,15 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
PRINT_D(CFG80211_DBG, "gtk %x %x %x\n", g_key_gtk_params.key[0],
g_key_gtk_params.key[1],
g_key_gtk_params.key[2]);
- add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy,
- wl->vif[0].ndev,
+ add_key(wl->vif[0]->ndev->ieee80211_ptr->wiphy,
+ wl->vif[0]->ndev,
g_add_ptk_key_params.key_idx,
g_add_ptk_key_params.pairwise,
g_add_ptk_key_params.mac_addr,
(struct key_params *)(&g_key_ptk_params));
- add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy,
- wl->vif[0].ndev,
+ add_key(wl->vif[0]->ndev->ieee80211_ptr->wiphy,
+ wl->vif[0]->ndev,
g_add_gtk_key_params.key_idx,
g_add_gtk_key_params.pairwise,
g_add_gtk_key_params.mac_addr,
@@ -2631,64 +2182,58 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
if (wl->initialized) {
for (i = 0; i < num_reg_frame; i++) {
- PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
- host_int_frame_register(priv->hWILCWFIDrv,
- nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
+ PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
+ wilc_frame_register(vif,
+ vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
}
}
- bEnablePS = true;
- host_int_set_power_mgmt(priv->hWILCWFIDrv, 1, 0);
+ wilc_enable_ps = true;
+ wilc_set_power_mgmt(vif, 1, 0);
}
break;
case NL80211_IFTYPE_P2P_CLIENT:
- bEnablePS = false;
- host_int_set_power_mgmt(priv->hWILCWFIDrv, 0, 0);
- connecting = 0;
+ wilc_enable_ps = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+ wilc_connecting = 0;
PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_P2P_CLIENT\n");
- host_int_del_All_Rx_BASession(priv->hWILCWFIDrv,
- wl->vif[0].bssid, TID);
+ wilc_del_all_rx_ba_session(vif, wl->vif[0]->bssid, TID);
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
- nic->monitor_flag = 0;
+ vif->monitor_flag = 0;
PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n");
- nic->iftype = CLIENT_MODE;
+ vif->iftype = CLIENT_MODE;
if (wl->initialized) {
- /* ensure that the message Q is empty */
- host_int_wait_msg_queue_idle();
+ wilc_wait_msg_queue_idle();
wilc1000_wlan_deinit(dev);
- wilc1000_wlan_init(dev, nic);
- g_wilc_initialized = 1;
+ wilc1000_wlan_init(dev, vif);
+ wilc_initialized = 1;
- host_int_set_wfi_drv_handler(wl->vif[0].hif_drv);
- host_int_set_MacAddress(wl->vif[0].hif_drv,
- wl->vif[0].src_addr);
- host_int_set_operation_mode(priv->hWILCWFIDrv, STATION_MODE);
+ wilc_set_wfi_drv_handler(vif,
+ wilc_get_vif_idx(wl->vif[0]));
+ wilc_set_mac_address(wl->vif[0], wl->vif[0]->src_addr);
+ wilc_set_operation_mode(vif, STATION_MODE);
- /*Add saved WEP keys, if any*/
if (g_wep_keys_saved) {
- host_int_set_wep_default_key(wl->vif[0].hif_drv,
- g_key_wep_params.key_idx);
- host_int_add_wep_key_bss_sta(wl->vif[0].hif_drv,
- g_key_wep_params.key,
- g_key_wep_params.key_len,
- g_key_wep_params.key_idx);
+ wilc_set_wep_default_keyid(wl->vif[0],
+ g_key_wep_params.key_idx);
+ wilc_add_wep_key_bss_sta(wl->vif[0],
+ g_key_wep_params.key,
+ g_key_wep_params.key_len,
+ g_key_wep_params.key_idx);
}
- /*No matter the driver handler passed here, it will be overwriiten*/
- /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/
- host_int_flush_join_req(priv->hWILCWFIDrv);
+ wilc_flush_join_req(vif);
- /*Add saved PTK and GTK keys, if any*/
if (g_ptk_keys_saved && g_gtk_keys_saved) {
PRINT_D(CFG80211_DBG, "ptk %x %x %x\n", g_key_ptk_params.key[0],
g_key_ptk_params.key[1],
@@ -2696,59 +2241,58 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
PRINT_D(CFG80211_DBG, "gtk %x %x %x\n", g_key_gtk_params.key[0],
g_key_gtk_params.key[1],
g_key_gtk_params.key[2]);
- add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy,
- wl->vif[0].ndev,
+ add_key(wl->vif[0]->ndev->ieee80211_ptr->wiphy,
+ wl->vif[0]->ndev,
g_add_ptk_key_params.key_idx,
g_add_ptk_key_params.pairwise,
g_add_ptk_key_params.mac_addr,
(struct key_params *)(&g_key_ptk_params));
- add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy,
- wl->vif[0].ndev,
+ add_key(wl->vif[0]->ndev->ieee80211_ptr->wiphy,
+ wl->vif[0]->ndev,
g_add_gtk_key_params.key_idx,
g_add_gtk_key_params.pairwise,
g_add_gtk_key_params.mac_addr,
(struct key_params *)(&g_key_gtk_params));
}
- /*Refresh scan, to refresh the scan results to the wpa_supplicant. Set MachHw to false to enable further key installments*/
refresh_scan(priv, 1, true);
- Set_machw_change_vir_if(dev, false);
+ wilc_set_machw_change_vir_if(dev, false);
if (wl->initialized) {
for (i = 0; i < num_reg_frame; i++) {
- PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
- host_int_frame_register(priv->hWILCWFIDrv,
- nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
+ PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
+ wilc_frame_register(vif,
+ vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
}
}
}
break;
case NL80211_IFTYPE_AP:
- bEnablePS = false;
+ wilc_enable_ps = false;
PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_AP %d\n", type);
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
- nic->iftype = AP_MODE;
+ vif->iftype = AP_MODE;
PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv);
PRINT_D(HOSTAPD_DBG, "Downloading AP firmware\n");
- linux_wlan_get_firmware(nic);
- /*If wilc is running, then close-open to actually get new firmware running (serves P2P)*/
+ wilc_wlan_get_firmware(dev);
+
if (wl->initialized) {
- nic->iftype = AP_MODE;
- mac_close(dev);
- mac_open(dev);
+ vif->iftype = AP_MODE;
+ wilc_mac_close(dev);
+ wilc_mac_open(dev);
for (i = 0; i < num_reg_frame; i++) {
- PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
- host_int_frame_register(priv->hWILCWFIDrv,
- nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
+ PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
+ wilc_frame_register(vif,
+ vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
}
}
break;
@@ -2756,16 +2300,12 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
case NL80211_IFTYPE_P2P_GO:
PRINT_D(GENERIC_DBG, "start duringIP timer\n");
- g_obtainingIP = true;
- mod_timer(&hDuringIpTimer, jiffies + msecs_to_jiffies(duringIP_TIME));
- host_int_set_power_mgmt(priv->hWILCWFIDrv, 0, 0);
- /*Delete block ack has to be the latest config packet*/
- /*sent before downloading new FW. This is because it blocks on*/
- /*hWaitResponse semaphore, which allows previous config*/
- /*packets to actually take action on old FW*/
- host_int_del_All_Rx_BASession(priv->hWILCWFIDrv,
- wl->vif[0].bssid, TID);
- bEnablePS = false;
+ wilc_optaining_ip = true;
+ mod_timer(&wilc_during_ip_timer,
+ jiffies + msecs_to_jiffies(during_ip_time));
+ wilc_set_power_mgmt(vif, 0, 0);
+ wilc_del_all_rx_ba_session(vif, wl->vif[0]->bssid, TID);
+ wilc_enable_ps = false;
PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_GO\n");
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
@@ -2775,36 +2315,28 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n");
- nic->iftype = GO_MODE;
+ vif->iftype = GO_MODE;
- /* ensure that the message Q is empty */
- host_int_wait_msg_queue_idle();
+ wilc_wait_msg_queue_idle();
wilc1000_wlan_deinit(dev);
- wilc1000_wlan_init(dev, nic);
- g_wilc_initialized = 1;
-
+ wilc1000_wlan_init(dev, vif);
+ wilc_initialized = 1;
- /*Setting interface 1 drv handler and mac address in newly downloaded FW*/
- host_int_set_wfi_drv_handler(wl->vif[0].hif_drv);
- host_int_set_MacAddress(wl->vif[0].hif_drv,
- wl->vif[0].src_addr);
- host_int_set_operation_mode(priv->hWILCWFIDrv, AP_MODE);
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(wl->vif[0]));
+ wilc_set_mac_address(wl->vif[0], wl->vif[0]->src_addr);
+ wilc_set_operation_mode(vif, AP_MODE);
- /*Add saved WEP keys, if any*/
if (g_wep_keys_saved) {
- host_int_set_wep_default_key(wl->vif[0].hif_drv,
- g_key_wep_params.key_idx);
- host_int_add_wep_key_bss_sta(wl->vif[0].hif_drv,
- g_key_wep_params.key,
- g_key_wep_params.key_len,
- g_key_wep_params.key_idx);
+ wilc_set_wep_default_keyid(wl->vif[0],
+ g_key_wep_params.key_idx);
+ wilc_add_wep_key_bss_sta(wl->vif[0],
+ g_key_wep_params.key,
+ g_key_wep_params.key_len,
+ g_key_wep_params.key_idx);
}
- /*No matter the driver handler passed here, it will be overwriiten*/
- /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/
- host_int_flush_join_req(priv->hWILCWFIDrv);
+ wilc_flush_join_req(vif);
- /*Add saved PTK and GTK keys, if any*/
if (g_ptk_keys_saved && g_gtk_keys_saved) {
PRINT_D(CFG80211_DBG, "ptk %x %x %x cipher %x\n", g_key_ptk_params.key[0],
g_key_ptk_params.key[1],
@@ -2814,15 +2346,15 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
g_key_gtk_params.key[1],
g_key_gtk_params.key[2],
g_key_gtk_params.cipher);
- add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy,
- wl->vif[0].ndev,
+ add_key(wl->vif[0]->ndev->ieee80211_ptr->wiphy,
+ wl->vif[0]->ndev,
g_add_ptk_key_params.key_idx,
g_add_ptk_key_params.pairwise,
g_add_ptk_key_params.mac_addr,
(struct key_params *)(&g_key_ptk_params));
- add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy,
- wl->vif[0].ndev,
+ add_key(wl->vif[0]->ndev->ieee80211_ptr->wiphy,
+ wl->vif[0]->ndev,
g_add_gtk_key_params.key_idx,
g_add_gtk_key_params.pairwise,
g_add_gtk_key_params.mac_addr,
@@ -2831,11 +2363,11 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
if (wl->initialized) {
for (i = 0; i < num_reg_frame; i++) {
- PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
- host_int_frame_register(priv->hWILCWFIDrv,
- nic->g_struct_frame_reg[i].frame_type,
- nic->g_struct_frame_reg[i].reg);
+ PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
+ wilc_frame_register(vif,
+ vif->g_struct_frame_reg[i].frame_type,
+ vif->g_struct_frame_reg[i].reg);
}
}
break;
@@ -2848,32 +2380,6 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
-/* (austin.2013-07-23)
- *
- * To support revised cfg80211_ops
- *
- * add_beacon --> start_ap
- * set_beacon --> change_beacon
- * del_beacon --> stop_ap
- *
- * beacon_parameters --> cfg80211_ap_settings
- * cfg80211_beacon_data
- *
- * applicable for linux kernel 3.4+
- */
-
-/**
- * @brief start_ap
- * @details Add a beacon with given parameters, @head, @interval
- * and @dtim_period will be valid, @tail is optional.
- * @param[in] wiphy
- * @param[in] dev The net device structure
- * @param[in] settings cfg80211_ap_settings parameters for the beacon to be added
- * @return int : Return 0 on Success.
- * @author austin
- * @date 23 JUL 2013
- * @version 1.0
- */
static int start_ap(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ap_settings *settings)
{
@@ -2881,11 +2387,11 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
struct wilc_priv *priv;
s32 s32Error = 0;
struct wilc *wl;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(dev);
- wl = nic->wilc;
+ vif = netdev_priv(dev);
+ wl = vif ->wilc;
PRINT_D(HOSTAPD_DBG, "Starting ap\n");
PRINT_D(HOSTAPD_DBG, "Interval = %d\n DTIM period = %d\n Head length = %zu Tail length = %zu\n",
@@ -2896,73 +2402,53 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
if (s32Error != 0)
PRINT_ER("Error in setting channel\n");
- linux_wlan_set_bssid(dev, wl->vif[0].src_addr);
+ wilc_wlan_set_bssid(dev, wl->vif[0]->src_addr);
- s32Error = host_int_add_beacon(priv->hWILCWFIDrv,
- settings->beacon_interval,
- settings->dtim_period,
- beacon->head_len, (u8 *)beacon->head,
- beacon->tail_len, (u8 *)beacon->tail);
+ s32Error = wilc_add_beacon(vif, settings->beacon_interval,
+ settings->dtim_period, beacon->head_len,
+ (u8 *)beacon->head, beacon->tail_len,
+ (u8 *)beacon->tail);
return s32Error;
}
-/**
- * @brief change_beacon
- * @details Add a beacon with given parameters, @head, @interval
- * and @dtim_period will be valid, @tail is optional.
- * @param[in] wiphy
- * @param[in] dev The net device structure
- * @param[in] beacon cfg80211_beacon_data for the beacon to be changed
- * @return int : Return 0 on Success.
- * @author austin
- * @date 23 JUL 2013
- * @version 1.0
- */
static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_beacon_data *beacon)
{
struct wilc_priv *priv;
+ struct wilc_vif *vif;
s32 s32Error = 0;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
PRINT_D(HOSTAPD_DBG, "Setting beacon\n");
- s32Error = host_int_add_beacon(priv->hWILCWFIDrv,
- 0,
- 0,
- beacon->head_len, (u8 *)beacon->head,
- beacon->tail_len, (u8 *)beacon->tail);
+ s32Error = wilc_add_beacon(vif, 0, 0, beacon->head_len,
+ (u8 *)beacon->head, beacon->tail_len,
+ (u8 *)beacon->tail);
return s32Error;
}
-/**
- * @brief stop_ap
- * @details Remove beacon configuration and stop sending the beacon.
- * @param[in]
- * @return int : Return 0 on Success.
- * @author austin
- * @date 23 JUL 2013
- * @version 1.0
- */
static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
s32 s32Error = 0;
struct wilc_priv *priv;
+ struct wilc_vif *vif;
u8 NullBssid[ETH_ALEN] = {0};
if (!wiphy)
return -EFAULT;
priv = wiphy_priv(wiphy);
+ vif = netdev_priv(priv->dev);
PRINT_D(HOSTAPD_DBG, "Deleting beacon\n");
- linux_wlan_set_bssid(dev, NullBssid);
+ wilc_wlan_set_bssid(dev, NullBssid);
- s32Error = host_int_del_beacon(priv->hWILCWFIDrv);
+ s32Error = wilc_del_beacon(vif);
if (s32Error)
PRINT_ER("Host delete beacon fail\n");
@@ -2970,68 +2456,70 @@ static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
return s32Error;
}
-/**
- * @brief add_station
- * @details Add a new station.
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int add_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac, struct station_parameters *params)
{
s32 s32Error = 0;
struct wilc_priv *priv;
struct add_sta_param strStaParams = { {0} };
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
if (!wiphy)
return -EFAULT;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(dev);
+ vif = netdev_priv(dev);
- if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) {
- memcpy(strStaParams.au8BSSID, mac, ETH_ALEN);
+ if (vif->iftype == AP_MODE || vif->iftype == GO_MODE) {
+ memcpy(strStaParams.bssid, mac, ETH_ALEN);
memcpy(priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid], mac, ETH_ALEN);
- strStaParams.u16AssocID = params->aid;
- strStaParams.u8NumRates = params->supported_rates_len;
- strStaParams.pu8Rates = params->supported_rates;
+ strStaParams.aid = params->aid;
+ strStaParams.rates_len = params->supported_rates_len;
+ strStaParams.rates = params->supported_rates;
PRINT_D(CFG80211_DBG, "Adding station parameters %d\n", params->aid);
PRINT_D(CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][0], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][1], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][2], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][3], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][4],
priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][5]);
- PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.u16AssocID);
- PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n", strStaParams.u8NumRates);
+ PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.aid);
+ PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n",
+ strStaParams.rates_len);
- if (params->ht_capa == NULL) {
- strStaParams.bIsHTSupported = false;
+ if (!params->ht_capa) {
+ strStaParams.ht_supported = false;
} else {
- strStaParams.bIsHTSupported = true;
- strStaParams.u16HTCapInfo = params->ht_capa->cap_info;
- strStaParams.u8AmpduParams = params->ht_capa->ampdu_params_info;
- memcpy(strStaParams.au8SuppMCsSet, &params->ht_capa->mcs, WILC_SUPP_MCS_SET_SIZE);
- strStaParams.u16HTExtParams = params->ht_capa->extended_ht_cap_info;
- strStaParams.u32TxBeamformingCap = params->ht_capa->tx_BF_cap_info;
- strStaParams.u8ASELCap = params->ht_capa->antenna_selection_info;
+ strStaParams.ht_supported = true;
+ strStaParams.ht_capa_info = params->ht_capa->cap_info;
+ strStaParams.ht_ampdu_params = params->ht_capa->ampdu_params_info;
+ memcpy(strStaParams.ht_supp_mcs_set,
+ &params->ht_capa->mcs,
+ WILC_SUPP_MCS_SET_SIZE);
+ strStaParams.ht_ext_params = params->ht_capa->extended_ht_cap_info;
+ strStaParams.ht_tx_bf_cap = params->ht_capa->tx_BF_cap_info;
+ strStaParams.ht_ante_sel = params->ht_capa->antenna_selection_info;
}
- strStaParams.u16FlagsMask = params->sta_flags_mask;
- strStaParams.u16FlagsSet = params->sta_flags_set;
-
- PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n", strStaParams.bIsHTSupported);
- PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n", strStaParams.u16HTCapInfo);
- PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n", strStaParams.u8AmpduParams);
- PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n", strStaParams.u16HTExtParams);
- PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n", strStaParams.u32TxBeamformingCap);
- PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n", strStaParams.u8ASELCap);
- PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n", strStaParams.u16FlagsMask);
- PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n", strStaParams.u16FlagsSet);
-
- s32Error = host_int_add_station(priv->hWILCWFIDrv, &strStaParams);
+ strStaParams.flags_mask = params->sta_flags_mask;
+ strStaParams.flags_set = params->sta_flags_set;
+
+ PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n",
+ strStaParams.ht_supported);
+ PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n",
+ strStaParams.ht_capa_info);
+ PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n",
+ strStaParams.ht_ampdu_params);
+ PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n",
+ strStaParams.ht_ext_params);
+ PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n",
+ strStaParams.ht_tx_bf_cap);
+ PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n",
+ strStaParams.ht_ante_sel);
+ PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n",
+ strStaParams.flags_mask);
+ PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n",
+ strStaParams.flags_set);
+
+ s32Error = wilc_add_station(vif, &strStaParams);
if (s32Error)
PRINT_ER("Host add station fail\n");
}
@@ -3039,41 +2527,33 @@ static int add_station(struct wiphy *wiphy, struct net_device *dev,
return s32Error;
}
-/**
- * @brief del_station
- * @details Remove a station; @mac may be NULL to remove all stations.
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int del_station(struct wiphy *wiphy, struct net_device *dev,
struct station_del_parameters *params)
{
const u8 *mac = params->mac;
s32 s32Error = 0;
struct wilc_priv *priv;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
if (!wiphy)
return -EFAULT;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(dev);
+ vif = netdev_priv(dev);
- if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) {
+ if (vif->iftype == AP_MODE || vif->iftype == GO_MODE) {
PRINT_D(HOSTAPD_DBG, "Deleting station\n");
- if (mac == NULL) {
+ if (!mac) {
PRINT_D(HOSTAPD_DBG, "All associated stations\n");
- s32Error = host_int_del_allstation(priv->hWILCWFIDrv, priv->assoc_stainfo.au8Sta_AssociatedBss);
+ s32Error = wilc_del_allstation(vif,
+ priv->assoc_stainfo.au8Sta_AssociatedBss);
} else {
PRINT_D(HOSTAPD_DBG, "With mac address: %x%x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
- s32Error = host_int_del_station(priv->hWILCWFIDrv, mac);
+ s32Error = wilc_del_station(vif, mac);
if (s32Error)
PRINT_ER("Host delete station fail\n");
@@ -3081,22 +2561,13 @@ static int del_station(struct wiphy *wiphy, struct net_device *dev,
return s32Error;
}
-/**
- * @brief change_station
- * @details Modify a given station.
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
static int change_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac, struct station_parameters *params)
{
s32 s32Error = 0;
struct wilc_priv *priv;
struct add_sta_param strStaParams = { {0} };
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
PRINT_D(HOSTAPD_DBG, "Change station paramters\n");
@@ -3105,61 +2576,63 @@ static int change_station(struct wiphy *wiphy, struct net_device *dev,
return -EFAULT;
priv = wiphy_priv(wiphy);
- nic = netdev_priv(dev);
-
- if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) {
- memcpy(strStaParams.au8BSSID, mac, ETH_ALEN);
- strStaParams.u16AssocID = params->aid;
- strStaParams.u8NumRates = params->supported_rates_len;
- strStaParams.pu8Rates = params->supported_rates;
-
- PRINT_D(HOSTAPD_DBG, "BSSID = %x%x%x%x%x%x\n", strStaParams.au8BSSID[0], strStaParams.au8BSSID[1], strStaParams.au8BSSID[2], strStaParams.au8BSSID[3], strStaParams.au8BSSID[4],
- strStaParams.au8BSSID[5]);
- PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.u16AssocID);
- PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n", strStaParams.u8NumRates);
-
- if (params->ht_capa == NULL) {
- strStaParams.bIsHTSupported = false;
+ vif = netdev_priv(dev);
+
+ if (vif->iftype == AP_MODE || vif->iftype == GO_MODE) {
+ memcpy(strStaParams.bssid, mac, ETH_ALEN);
+ strStaParams.aid = params->aid;
+ strStaParams.rates_len = params->supported_rates_len;
+ strStaParams.rates = params->supported_rates;
+
+ PRINT_D(HOSTAPD_DBG, "BSSID = %x%x%x%x%x%x\n",
+ strStaParams.bssid[0], strStaParams.bssid[1],
+ strStaParams.bssid[2], strStaParams.bssid[3],
+ strStaParams.bssid[4], strStaParams.bssid[5]);
+ PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.aid);
+ PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n",
+ strStaParams.rates_len);
+
+ if (!params->ht_capa) {
+ strStaParams.ht_supported = false;
} else {
- strStaParams.bIsHTSupported = true;
- strStaParams.u16HTCapInfo = params->ht_capa->cap_info;
- strStaParams.u8AmpduParams = params->ht_capa->ampdu_params_info;
- memcpy(strStaParams.au8SuppMCsSet, &params->ht_capa->mcs, WILC_SUPP_MCS_SET_SIZE);
- strStaParams.u16HTExtParams = params->ht_capa->extended_ht_cap_info;
- strStaParams.u32TxBeamformingCap = params->ht_capa->tx_BF_cap_info;
- strStaParams.u8ASELCap = params->ht_capa->antenna_selection_info;
-
+ strStaParams.ht_supported = true;
+ strStaParams.ht_capa_info = params->ht_capa->cap_info;
+ strStaParams.ht_ampdu_params = params->ht_capa->ampdu_params_info;
+ memcpy(strStaParams.ht_supp_mcs_set,
+ &params->ht_capa->mcs,
+ WILC_SUPP_MCS_SET_SIZE);
+ strStaParams.ht_ext_params = params->ht_capa->extended_ht_cap_info;
+ strStaParams.ht_tx_bf_cap = params->ht_capa->tx_BF_cap_info;
+ strStaParams.ht_ante_sel = params->ht_capa->antenna_selection_info;
}
- strStaParams.u16FlagsMask = params->sta_flags_mask;
- strStaParams.u16FlagsSet = params->sta_flags_set;
-
- PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n", strStaParams.bIsHTSupported);
- PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n", strStaParams.u16HTCapInfo);
- PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n", strStaParams.u8AmpduParams);
- PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n", strStaParams.u16HTExtParams);
- PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n", strStaParams.u32TxBeamformingCap);
- PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n", strStaParams.u8ASELCap);
- PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n", strStaParams.u16FlagsMask);
- PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n", strStaParams.u16FlagsSet);
-
- s32Error = host_int_edit_station(priv->hWILCWFIDrv, &strStaParams);
+ strStaParams.flags_mask = params->sta_flags_mask;
+ strStaParams.flags_set = params->sta_flags_set;
+
+ PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n",
+ strStaParams.ht_supported);
+ PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n",
+ strStaParams.ht_capa_info);
+ PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n",
+ strStaParams.ht_ampdu_params);
+ PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n",
+ strStaParams.ht_ext_params);
+ PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n",
+ strStaParams.ht_tx_bf_cap);
+ PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n",
+ strStaParams.ht_ante_sel);
+ PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n",
+ strStaParams.flags_mask);
+ PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n",
+ strStaParams.flags_set);
+
+ s32Error = wilc_edit_station(vif, &strStaParams);
if (s32Error)
PRINT_ER("Host edit station fail\n");
}
return s32Error;
}
-
-/**
- * @brief add_virtual_intf
- * @details
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 JUL 2012
- * @version 1.0
- */
static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
const char *name,
unsigned char name_assign_type,
@@ -3167,7 +2640,7 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
u32 *flags,
struct vif_params *params)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc_priv *priv;
struct net_device *new_ifc = NULL;
@@ -3177,32 +2650,23 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", priv->wdev->netdev);
- nic = netdev_priv(priv->wdev->netdev);
+ vif = netdev_priv(priv->wdev->netdev);
if (type == NL80211_IFTYPE_MONITOR) {
PRINT_D(HOSTAPD_DBG, "Monitor interface mode: Initializing mon interface virtual device driver\n");
- PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", nic->wilc_netdev);
- new_ifc = WILC_WFI_init_mon_interface(name, nic->wilc_netdev);
- if (new_ifc != NULL) {
+ PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", vif->ndev);
+ new_ifc = WILC_WFI_init_mon_interface(name, vif->ndev);
+ if (new_ifc) {
PRINT_D(HOSTAPD_DBG, "Setting monitor flag in private structure\n");
- nic = netdev_priv(priv->wdev->netdev);
- nic->monitor_flag = 1;
+ vif = netdev_priv(priv->wdev->netdev);
+ vif->monitor_flag = 1;
} else
PRINT_ER("Error in initializing monitor interface\n ");
}
return priv->wdev;
}
-/**
- * @brief del_virtual_intf
- * @details
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 JUL 2012
- * @version 1.0
- */
static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{
PRINT_D(HOSTAPD_DBG, "Deleting virtual interface\n");
@@ -3210,7 +2674,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
}
static struct cfg80211_ops wilc_cfg80211_ops = {
-
.set_monitor_channel = set_channel,
.scan = scan,
.connect = connect,
@@ -3247,27 +2710,12 @@ static struct cfg80211_ops wilc_cfg80211_ops = {
};
-
-
-
-
-/**
- * @brief WILC_WFI_update_stats
- * @details Modify parameters for a given BSS.
- * @param[in]
- * @return int : Return 0 on Success.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed)
{
-
struct wilc_priv *priv;
priv = wiphy_priv(wiphy);
switch (changed) {
-
case WILC_WFI_RX_PKT:
{
priv->netstats.rx_packets++;
@@ -3291,46 +2739,31 @@ int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed)
return 0;
}
-/**
- * @brief WILC_WFI_CfgAlloc
- * @details Allocation of the wireless device structure and assigning it
- * to the cfg80211 operations structure.
- * @param[in] NONE
- * @return wireless_dev : Returns pointer to wireless_dev structure.
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
-struct wireless_dev *WILC_WFI_CfgAlloc(void)
+static struct wireless_dev *WILC_WFI_CfgAlloc(void)
{
-
struct wireless_dev *wdev;
PRINT_D(CFG80211_DBG, "Allocating wireless device\n");
- /*Allocating the wireless device structure*/
+
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev) {
PRINT_ER("Cannot allocate wireless device\n");
goto _fail_;
}
- /*Creating a new wiphy, linking wireless structure with the wiphy structure*/
wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv));
if (!wdev->wiphy) {
PRINT_ER("Cannot allocate wiphy\n");
goto _fail_mem_;
-
}
- /* enable 802.11n HT */
WILC_WFI_band_2ghz.ht_cap.ht_supported = 1;
WILC_WFI_band_2ghz.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
WILC_WFI_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
WILC_WFI_band_2ghz.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
WILC_WFI_band_2ghz.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
- /*wiphy bands*/
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &WILC_WFI_band_2ghz;
return wdev;
@@ -3339,18 +2772,9 @@ _fail_mem_:
kfree(wdev);
_fail_:
return NULL;
-
}
-/**
- * @brief wilc_create_wiphy
- * @details Registering of the wiphy structure and interface modes
- * @param[in] NONE
- * @return NONE
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
-struct wireless_dev *wilc_create_wiphy(struct net_device *net)
+
+struct wireless_dev *wilc_create_wiphy(struct net_device *net, struct device *dev)
{
struct wilc_priv *priv;
struct wireless_dev *wdev;
@@ -3359,38 +2783,25 @@ struct wireless_dev *wilc_create_wiphy(struct net_device *net)
PRINT_D(CFG80211_DBG, "Registering wifi device\n");
wdev = WILC_WFI_CfgAlloc();
- if (wdev == NULL) {
+ if (!wdev) {
PRINT_ER("CfgAlloc Failed\n");
return NULL;
}
-
- /*Return hardware description structure (wiphy)'s priv*/
priv = wdev_priv(wdev);
sema_init(&(priv->SemHandleUpdateStats), 1);
-
- /*Link the wiphy with wireless structure*/
priv->wdev = wdev;
-
- /*Maximum number of probed ssid to be added by user for the scan request*/
wdev->wiphy->max_scan_ssids = MAX_NUM_PROBED_SSID;
- /*Maximum number of pmkids to be cashed*/
wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
PRINT_INFO(CFG80211_DBG, "Max number of PMKIDs = %d\n", wdev->wiphy->max_num_pmkids);
wdev->wiphy->max_scan_ie_len = 1000;
-
- /*signal strength in mBm (100*dBm) */
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
- /*Set the availaible cipher suites*/
wdev->wiphy->cipher_suites = cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
- /*Setting default managment types: for register action frame: */
wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
wdev->wiphy->max_remain_on_channel_duration = 500;
- /*Setting the wiphy interfcae mode and type before registering the wiphy*/
wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT);
wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
@@ -3402,36 +2813,21 @@ struct wireless_dev *wilc_create_wiphy(struct net_device *net)
wdev->wiphy->max_scan_ssids, wdev->wiphy->max_scan_ie_len, wdev->wiphy->signal_type,
wdev->wiphy->interface_modes, wdev->iftype);
- #ifdef WILC_SDIO
- set_wiphy_dev(wdev->wiphy, &local_sdio_func->dev);
- #endif
+ set_wiphy_dev(wdev->wiphy, dev);
- /*Register wiphy structure*/
s32Error = wiphy_register(wdev->wiphy);
if (s32Error) {
PRINT_ER("Cannot register wiphy device\n");
- /*should define what action to be taken in such failure*/
} else {
PRINT_D(CFG80211_DBG, "Successful Registering\n");
}
priv->dev = net;
return wdev;
-
-
}
-/**
- * @brief WILC_WFI_WiphyFree
- * @details Freeing allocation of the wireless device structure
- * @param[in] NONE
- * @return NONE
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
+
int wilc_init_host_int(struct net_device *net)
{
-
int s32Error = 0;
struct wilc_priv *priv;
@@ -3440,7 +2836,7 @@ int wilc_init_host_int(struct net_device *net)
priv = wdev_priv(net->ieee80211_ptr);
if (op_ifcs == 0) {
setup_timer(&hAgingTimer, remove_network_from_shadow, 0);
- setup_timer(&hDuringIpTimer, clear_duringIP, 0);
+ setup_timer(&wilc_during_ip_timer, clear_duringIP, 0);
}
op_ifcs++;
if (s32Error < 0) {
@@ -3453,29 +2849,21 @@ int wilc_init_host_int(struct net_device *net)
priv->bInP2PlistenState = false;
sema_init(&(priv->hSemScanReq), 1);
- s32Error = host_int_init(net, &priv->hWILCWFIDrv);
+ s32Error = wilc_init(net, &priv->hWILCWFIDrv);
if (s32Error)
PRINT_ER("Error while initializing hostinterface\n");
return s32Error;
}
-/**
- * @brief WILC_WFI_WiphyFree
- * @details Freeing allocation of the wireless device structure
- * @param[in] NONE
- * @return NONE
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
int wilc_deinit_host_int(struct net_device *net)
{
int s32Error = 0;
-
+ struct wilc_vif *vif;
struct wilc_priv *priv;
priv = wdev_priv(net->ieee80211_ptr);
+ vif = netdev_priv(priv->dev);
priv->gbAutoRateAdjusted = false;
@@ -3483,13 +2871,12 @@ int wilc_deinit_host_int(struct net_device *net)
op_ifcs--;
- s32Error = host_int_deinit(priv->hWILCWFIDrv);
+ s32Error = wilc_deinit(vif);
- /* Clear the Shadow scan */
- clear_shadow_scan(priv);
+ clear_shadow_scan();
if (op_ifcs == 0) {
PRINT_D(CORECONFIG_DBG, "destroy during ip\n");
- del_timer_sync(&hDuringIpTimer);
+ del_timer_sync(&wilc_during_ip_timer);
}
if (s32Error)
@@ -3498,16 +2885,6 @@ int wilc_deinit_host_int(struct net_device *net)
return s32Error;
}
-
-/**
- * @brief WILC_WFI_WiphyFree
- * @details Freeing allocation of the wireless device structure
- * @param[in] NONE
- * @return NONE
- * @author mdaftedar
- * @date 01 MAR 2012
- * @version 1.0
- */
void wilc_free_wiphy(struct net_device *net)
{
PRINT_D(CFG80211_DBG, "Unregistering wiphy\n");
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
index 39cd8e1b5675..ab53d9d59081 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
@@ -10,88 +10,7 @@
#define NM_WFI_CFGOPERATIONS
#include "wilc_wfi_netdevice.h"
-/* The following macros describe the bitfield map used by the firmware to determine its 11i mode */
-#define NO_ENCRYPT 0
-#define ENCRYPT_ENABLED BIT(0)
-#define WEP BIT(1)
-#define WEP_EXTENDED BIT(2)
-#define WPA BIT(3)
-#define WPA2 BIT(4)
-#define AES BIT(5)
-#define TKIP BIT(6)
-
-/*Public action frame index IDs*/
-#define FRAME_TYPE_ID 0
-#define ACTION_CAT_ID 24
-#define ACTION_SUBTYPE_ID 25
-#define P2P_PUB_ACTION_SUBTYPE 30
-
-/*Public action frame Attribute IDs*/
-#define ACTION_FRAME 0xd0
-#define GO_INTENT_ATTR_ID 0x04
-#define CHANLIST_ATTR_ID 0x0b
-#define OPERCHAN_ATTR_ID 0x11
-#define PUB_ACTION_ATTR_ID 0x04
-#define P2PELEM_ATTR_ID 0xdd
-
-/*Public action subtype values*/
-#define GO_NEG_REQ 0x00
-#define GO_NEG_RSP 0x01
-#define GO_NEG_CONF 0x02
-#define P2P_INV_REQ 0x03
-#define P2P_INV_RSP 0x04
-#define PUBLIC_ACT_VENDORSPEC 0x09
-#define GAS_INTIAL_REQ 0x0a
-#define GAS_INTIAL_RSP 0x0b
-
-#define INVALID_CHANNEL 0
-
-#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ)
-#define SCAN_RESULT_EXPIRE (40 * HZ)
-
-static const u32 cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
- WLAN_CIPHER_SUITE_AES_CMAC,
-};
-
-static const struct ieee80211_txrx_stypes
- wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
- [NL80211_IFTYPE_STATION] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- },
- [NL80211_IFTYPE_AP] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4) |
- BIT(IEEE80211_STYPE_DEAUTH >> 4) |
- BIT(IEEE80211_STYPE_ACTION >> 4)
- },
- [NL80211_IFTYPE_P2P_CLIENT] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
- BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4) |
- BIT(IEEE80211_STYPE_DEAUTH >> 4)
- }
-};
-
-/* Time to stay on the channel */
-#define WILC_WFI_DWELL_PASSIVE 100
-#define WILC_WFI_DWELL_ACTIVE 40
-
-struct wireless_dev *WILC_WFI_CfgAlloc(void);
-struct wireless_dev *wilc_create_wiphy(struct net_device *net);
+struct wireless_dev *wilc_create_wiphy(struct net_device *net, struct device *dev);
void wilc_free_wiphy(struct net_device *net);
int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed);
int wilc_deinit_host_int(struct net_device *net);
@@ -102,8 +21,4 @@ struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_devi
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
u16 frame_type, bool reg);
-#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54
-#define DEFAULT_LINK_SPEED 72
-void Enable_TCP_ACK_Filter(bool value);
-
#endif
diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
index 0bfe7626ad2d..98ac8ed04a06 100644
--- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h
+++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
@@ -149,6 +149,13 @@ typedef struct {
} struct_frame_reg;
struct wilc_vif {
+ u8 u8IfIdx;
+ u8 iftype;
+ int monitor_flag;
+ int mac_opened;
+ struct_frame_reg g_struct_frame_reg[num_reg_frame];
+ struct net_device_stats netstats;
+ struct wilc *wilc;
u8 src_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
struct host_if_drv *hif_drv;
@@ -156,14 +163,15 @@ struct wilc_vif {
};
struct wilc {
+ const struct wilc_hif_func *hif_func;
+ int io_type;
int mac_status;
+ int gpio;
bool initialized;
- #if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO)
- unsigned short dev_irq_num;
- #endif
+ int dev_irq_num;
int close;
u8 vif_num;
- struct wilc_vif vif[NUM_CONCURRENT_IFC];
+ struct wilc_vif *vif[NUM_CONCURRENT_IFC];
u8 open_ifcs;
struct semaphore txq_add_to_head_cs;
@@ -180,42 +188,54 @@ struct wilc {
struct task_struct *txq_thread;
+ int quit;
+ int cfg_frame_in_use;
+ struct wilc_cfg_frame cfg_frame;
+ u32 cfg_frame_offset;
+ int cfg_seq_no;
+
+ u8 *rx_buffer;
+ u32 rx_buffer_offset;
+ u8 *tx_buffer;
+
+ unsigned long txq_spinlock_flags;
+
+ struct txq_entry_t *txq_head;
+ struct txq_entry_t *txq_tail;
+ int txq_entries;
+ int txq_exit;
+
+ struct rxq_entry_t *rxq_head;
+ struct rxq_entry_t *rxq_tail;
+ int rxq_entries;
+ int rxq_exit;
+
unsigned char eth_src_address[NUM_CONCURRENT_IFC][6];
const struct firmware *firmware;
-#ifdef WILC_SDIO
- struct sdio_func *wilc_sdio_func;
-#else
- struct spi_device *wilc_spidev;
-#endif
+ struct device *dev;
};
-typedef struct {
- u8 u8IfIdx;
- u8 iftype;
- int monitor_flag;
- int mac_opened;
- struct_frame_reg g_struct_frame_reg[num_reg_frame];
- struct net_device *wilc_netdev;
- struct net_device_stats netstats;
- struct wilc *wilc;
-} perInterface_wlan_t;
-
struct WILC_WFI_mon_priv {
struct net_device *real_ndev;
};
-extern struct wilc *g_linux_wlan;
-extern struct net_device *WILC_WFI_devs[];
-void frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
-void linux_wlan_mac_indicate(struct wilc *wilc, int flag);
-void linux_wlan_rx_complete(void);
-void linux_wlan_dbg(u8 *buff);
-int linux_wlan_lock_timeout(void *vp, u32 timeout);
-void wl_wlan_cleanup(void);
-int wilc_netdev_init(struct wilc **wilc);
+int wilc1000_wlan_init(struct net_device *dev, struct wilc_vif *vif);
+
+void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
+void wilc_mac_indicate(struct wilc *wilc, int flag);
+void wilc_rx_complete(struct wilc *wilc);
+void wilc_dbg(u8 *buff);
+
+int wilc_lock_timeout(struct wilc *wilc, void *, u32 timeout);
+void wilc_netdev_cleanup(struct wilc *wilc);
+int wilc_netdev_init(struct wilc **wilc, struct device *, int io_type, int gpio,
+ const struct wilc_hif_func *ops);
void wilc1000_wlan_deinit(struct net_device *dev);
void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
-u16 Set_machw_change_vir_if(struct net_device *dev, bool bValue);
+u16 wilc_set_machw_change_vir_if(struct net_device *dev, bool value);
+int wilc_wlan_get_firmware(struct net_device *dev);
+int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid);
+
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c
index c02665747705..83af51bb83e8 100644
--- a/drivers/staging/wilc1000/wilc_wlan.c
+++ b/drivers/staging/wilc1000/wilc_wlan.c
@@ -1,95 +1,15 @@
-/* ////////////////////////////////////////////////////////////////////////// */
-/* */
-/* Copyright (c) Atmel Corporation. All rights reserved. */
-/* */
-/* Module Name: wilc_wlan.c */
-/* */
-/* */
-/* //////////////////////////////////////////////////////////////////////////// */
-
#include "wilc_wlan_if.h"
+#include "wilc_wlan.h"
#include "wilc_wfi_netdevice.h"
#include "wilc_wlan_cfg.h"
-/********************************************
- *
- * Global
- *
- ********************************************/
-extern wilc_hif_func_t hif_sdio;
-extern wilc_hif_func_t hif_spi;
-u32 wilc_get_chipid(u8 update);
-
-
-
-typedef struct {
- int quit;
-
- /**
- * input interface functions
- **/
- wilc_wlan_io_func_t io_func;
-
- /**
- * host interface functions
- **/
- wilc_hif_func_t hif_func;
-
- /**
- * configuration interface functions
- **/
- int cfg_frame_in_use;
- wilc_cfg_frame_t cfg_frame;
- u32 cfg_frame_offset;
- int cfg_seq_no;
-
- /**
- * RX buffer
- **/
- #ifdef MEMORY_STATIC
- u8 *rx_buffer;
- u32 rx_buffer_offset;
- #endif
- /**
- * TX buffer
- **/
- u8 *tx_buffer;
- u32 tx_buffer_offset;
-
- /**
- * TX queue
- **/
-
- unsigned long txq_spinlock_flags;
-
- struct txq_entry_t *txq_head;
- struct txq_entry_t *txq_tail;
- int txq_entries;
- int txq_exit;
-
- /**
- * RX queue
- **/
- struct rxq_entry_t *rxq_head;
- struct rxq_entry_t *rxq_tail;
- int rxq_entries;
- int rxq_exit;
-
-
-} wilc_wlan_dev_t;
-
-static wilc_wlan_dev_t g_wlan;
-
-static inline void chip_allow_sleep(void);
-static inline void chip_wakeup(void);
-/********************************************
- *
- * Debug
- *
- ********************************************/
-
+#ifdef WILC_OPTIMIZE_SLEEP_INT
+static inline void chip_allow_sleep(struct wilc *wilc);
+#endif
+static inline void chip_wakeup(struct wilc *wilc);
static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ;
+/* FIXME: replace with dev_debug() */
static void wilc_debug(u32 flag, char *fmt, ...)
{
char buf[256];
@@ -100,244 +20,214 @@ static void wilc_debug(u32 flag, char *fmt, ...)
vsprintf(buf, fmt, args);
va_end(args);
- linux_wlan_dbg(buf);
+ wilc_dbg(buf);
}
}
-static CHIP_PS_STATE_T genuChipPSstate = CHIP_WAKEDUP;
+static CHIP_PS_STATE_T chip_ps_state = CHIP_WAKEDUP;
-/*acquire_bus() and release_bus() are made static inline functions*/
-/*as a temporary workaround to fix a problem of receiving*/
-/*unknown interrupt from FW*/
-static inline void acquire_bus(BUS_ACQUIRE_T acquire)
+static inline void acquire_bus(struct wilc *wilc, BUS_ACQUIRE_T acquire)
{
-
- mutex_lock(&g_linux_wlan->hif_cs);
+ mutex_lock(&wilc->hif_cs);
#ifndef WILC_OPTIMIZE_SLEEP_INT
- if (genuChipPSstate != CHIP_WAKEDUP)
+ if (chip_ps_state != CHIP_WAKEDUP)
#endif
{
if (acquire == ACQUIRE_AND_WAKEUP)
- chip_wakeup();
+ chip_wakeup(wilc);
}
-
}
-static inline void release_bus(BUS_RELEASE_T release)
+
+static inline void release_bus(struct wilc *wilc, BUS_RELEASE_T release)
{
#ifdef WILC_OPTIMIZE_SLEEP_INT
if (release == RELEASE_ALLOW_SLEEP)
- chip_allow_sleep();
+ chip_allow_sleep(wilc);
#endif
- mutex_unlock(&g_linux_wlan->hif_cs);
+ mutex_unlock(&wilc->hif_cs);
}
-/********************************************
- *
- * Queue
- *
- ********************************************/
+#ifdef TCP_ACK_FILTER
static void wilc_wlan_txq_remove(struct txq_entry_t *tqe)
{
- wilc_wlan_dev_t *p = &g_wlan;
- if (tqe == p->txq_head) {
-
- p->txq_head = tqe->next;
- if (p->txq_head)
- p->txq_head->prev = NULL;
-
-
- } else if (tqe == p->txq_tail) {
- p->txq_tail = (tqe->prev);
- if (p->txq_tail)
- p->txq_tail->next = NULL;
+ if (tqe == wilc->txq_head) {
+ wilc->txq_head = tqe->next;
+ if (wilc->txq_head)
+ wilc->txq_head->prev = NULL;
+ } else if (tqe == wilc->txq_tail) {
+ wilc->txq_tail = (tqe->prev);
+ if (wilc->txq_tail)
+ wilc->txq_tail->next = NULL;
} else {
tqe->prev->next = tqe->next;
tqe->next->prev = tqe->prev;
}
- p->txq_entries -= 1;
-
+ wilc->txq_entries -= 1;
}
+#endif
-static struct txq_entry_t *wilc_wlan_txq_remove_from_head(void)
+static struct txq_entry_t *
+wilc_wlan_txq_remove_from_head(struct net_device *dev)
{
struct txq_entry_t *tqe;
- wilc_wlan_dev_t *p = &g_wlan;
unsigned long flags;
+ struct wilc_vif *vif;
+ struct wilc *wilc;
- spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
- if (p->txq_head) {
- tqe = p->txq_head;
- p->txq_head = tqe->next;
- if (p->txq_head)
- p->txq_head->prev = NULL;
-
- p->txq_entries -= 1;
-
-
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+ if (wilc->txq_head) {
+ tqe = wilc->txq_head;
+ wilc->txq_head = tqe->next;
+ if (wilc->txq_head)
+ wilc->txq_head->prev = NULL;
+ wilc->txq_entries -= 1;
} else {
tqe = NULL;
}
- spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
return tqe;
}
-static void wilc_wlan_txq_add_to_tail(struct txq_entry_t *tqe)
+static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
+ struct txq_entry_t *tqe)
{
- wilc_wlan_dev_t *p = &g_wlan;
unsigned long flags;
- spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
+ struct wilc_vif *vif;
+ struct wilc *wilc;
+
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
- if (p->txq_head == NULL) {
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ if (!wilc->txq_head) {
tqe->next = NULL;
tqe->prev = NULL;
- p->txq_head = tqe;
- p->txq_tail = tqe;
+ wilc->txq_head = tqe;
+ wilc->txq_tail = tqe;
} else {
tqe->next = NULL;
- tqe->prev = p->txq_tail;
- p->txq_tail->next = tqe;
- p->txq_tail = tqe;
+ tqe->prev = wilc->txq_tail;
+ wilc->txq_tail->next = tqe;
+ wilc->txq_tail = tqe;
}
- p->txq_entries += 1;
- PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
+ wilc->txq_entries += 1;
+ PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", wilc->txq_entries);
- spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
- /**
- * wake up TX queue
- **/
PRINT_D(TX_DBG, "Wake the txq_handling\n");
- up(&g_linux_wlan->txq_event);
+ up(&wilc->txq_event);
}
-static int wilc_wlan_txq_add_to_head(struct txq_entry_t *tqe)
+static int wilc_wlan_txq_add_to_head(struct wilc *wilc, struct txq_entry_t *tqe)
{
- wilc_wlan_dev_t *p = &g_wlan;
unsigned long flags;
- if (linux_wlan_lock_timeout(&g_linux_wlan->txq_add_to_head_cs,
+ if (wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs,
CFG_PKTS_TIMEOUT))
return -1;
- spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
- if (p->txq_head == NULL) {
+ if (!wilc->txq_head) {
tqe->next = NULL;
tqe->prev = NULL;
- p->txq_head = tqe;
- p->txq_tail = tqe;
+ wilc->txq_head = tqe;
+ wilc->txq_tail = tqe;
} else {
- tqe->next = p->txq_head;
+ tqe->next = wilc->txq_head;
tqe->prev = NULL;
- p->txq_head->prev = tqe;
- p->txq_head = tqe;
+ wilc->txq_head->prev = tqe;
+ wilc->txq_head = tqe;
}
- p->txq_entries += 1;
- PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries);
+ wilc->txq_entries += 1;
+ PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", wilc->txq_entries);
- spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
- up(&g_linux_wlan->txq_add_to_head_cs);
-
-
- /**
- * wake up TX queue
- **/
- up(&g_linux_wlan->txq_event);
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+ up(&wilc->txq_add_to_head_cs);
+ up(&wilc->txq_event);
PRINT_D(TX_DBG, "Wake up the txq_handler\n");
return 0;
-
}
-u32 Statisitcs_totalAcks = 0, Statisitcs_DroppedAcks = 0;
-
#ifdef TCP_ACK_FILTER
-struct Ack_session_info;
-struct Ack_session_info {
- u32 Ack_seq_num;
- u32 Bigger_Ack_num;
+struct ack_session_info;
+struct ack_session_info {
+ u32 seq_num;
+ u32 bigger_ack_num;
u16 src_port;
u16 dst_port;
u16 status;
};
-typedef struct {
+struct pending_acks_info {
u32 ack_num;
- u32 Session_index;
+ u32 session_index;
struct txq_entry_t *txqe;
-} Pending_Acks_info_t /*Ack_info_t*/;
-
-
-
+};
-struct Ack_session_info *Free_head;
-struct Ack_session_info *Alloc_head;
#define NOT_TCP_ACK (-1)
#define MAX_TCP_SESSION 25
#define MAX_PENDING_ACKS 256
-struct Ack_session_info Acks_keep_track_info[2 * MAX_TCP_SESSION];
-Pending_Acks_info_t Pending_Acks_info[MAX_PENDING_ACKS];
-
-u32 PendingAcks_arrBase;
-u32 Opened_TCP_session;
-u32 Pending_Acks;
-
+static struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
+static struct pending_acks_info pending_acks_info[MAX_PENDING_ACKS];
+static u32 pending_base;
+static u32 tcp_session;
+static u32 pending_acks;
-static inline int Init_TCP_tracking(void)
+static inline int init_tcp_tracking(void)
{
-
return 0;
-
}
-static inline int add_TCP_track_session(u32 src_prt, u32 dst_prt, u32 seq)
+
+static inline int add_tcp_session(u32 src_prt, u32 dst_prt, u32 seq)
{
- Acks_keep_track_info[Opened_TCP_session].Ack_seq_num = seq;
- Acks_keep_track_info[Opened_TCP_session].Bigger_Ack_num = 0;
- Acks_keep_track_info[Opened_TCP_session].src_port = src_prt;
- Acks_keep_track_info[Opened_TCP_session].dst_port = dst_prt;
- Opened_TCP_session++;
+ ack_session_info[tcp_session].seq_num = seq;
+ ack_session_info[tcp_session].bigger_ack_num = 0;
+ ack_session_info[tcp_session].src_port = src_prt;
+ ack_session_info[tcp_session].dst_port = dst_prt;
+ tcp_session++;
- PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", Opened_TCP_session, seq);
+ PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", tcp_session, seq);
return 0;
}
-static inline int Update_TCP_track_session(u32 index, u32 Ack)
+static inline int update_tcp_session(u32 index, u32 ack)
{
-
- if (Ack > Acks_keep_track_info[index].Bigger_Ack_num)
- Acks_keep_track_info[index].Bigger_Ack_num = Ack;
+ if (ack > ack_session_info[index].bigger_ack_num)
+ ack_session_info[index].bigger_ack_num = ack;
return 0;
-
}
-static inline int add_TCP_Pending_Ack(u32 Ack, u32 Session_index, struct txq_entry_t *txqe)
-{
- Statisitcs_totalAcks++;
- if (Pending_Acks < MAX_PENDING_ACKS) {
- Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].ack_num = Ack;
- Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].txqe = txqe;
- Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].Session_index = Session_index;
- txqe->tcp_PendingAck_index = PendingAcks_arrBase + Pending_Acks;
- Pending_Acks++;
-
- } else {
+static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
+ struct txq_entry_t *txqe)
+{
+ if (pending_acks < MAX_PENDING_ACKS) {
+ pending_acks_info[pending_base + pending_acks].ack_num = ack;
+ pending_acks_info[pending_base + pending_acks].txqe = txqe;
+ pending_acks_info[pending_base + pending_acks].session_index = session_index;
+ txqe->tcp_pending_ack_idx = pending_base + pending_acks;
+ pending_acks++;
}
return 0;
}
-static inline int remove_TCP_related(void)
+static inline int remove_TCP_related(struct wilc *wilc)
{
- wilc_wlan_dev_t *p = &g_wlan;
unsigned long flags;
- spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
- spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
return 0;
}
@@ -348,54 +238,55 @@ static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
u8 *buffer = tqe->buffer;
unsigned short h_proto;
int i;
- wilc_wlan_dev_t *p = &g_wlan;
unsigned long flags;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
- spin_lock_irqsave(&wilc->txq_spinlock, flags);
eth_hdr_ptr = &buffer[0];
h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
- if (h_proto == 0x0800) { /* IP */
+ if (h_proto == 0x0800) {
u8 *ip_hdr_ptr;
u8 protocol;
ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
protocol = ip_hdr_ptr[9];
-
if (protocol == 0x06) {
u8 *tcp_hdr_ptr;
- u32 IHL, Total_Length, Data_offset;
+ u32 IHL, total_length, data_offset;
tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
IHL = (ip_hdr_ptr[0] & 0xf) << 2;
- Total_Length = (((u32)ip_hdr_ptr[2]) << 8) + ((u32)ip_hdr_ptr[3]);
- Data_offset = (((u32)tcp_hdr_ptr[12] & 0xf0) >> 2);
- if (Total_Length == (IHL + Data_offset)) { /*we want to recognize the clear Acks(packet only carry Ack infos not with data) so data size must be equal zero*/
- u32 seq_no, Ack_no;
-
- seq_no = (((u32)tcp_hdr_ptr[4]) << 24) + (((u32)tcp_hdr_ptr[5]) << 16) + (((u32)tcp_hdr_ptr[6]) << 8) + ((u32)tcp_hdr_ptr[7]);
-
- Ack_no = (((u32)tcp_hdr_ptr[8]) << 24) + (((u32)tcp_hdr_ptr[9]) << 16) + (((u32)tcp_hdr_ptr[10]) << 8) + ((u32)tcp_hdr_ptr[11]);
-
-
- for (i = 0; i < Opened_TCP_session; i++) {
- if (Acks_keep_track_info[i].Ack_seq_num == seq_no) {
- Update_TCP_track_session(i, Ack_no);
+ total_length = ((u32)ip_hdr_ptr[2] << 8) +
+ (u32)ip_hdr_ptr[3];
+ data_offset = ((u32)tcp_hdr_ptr[12] & 0xf0) >> 2;
+ if (total_length == (IHL + data_offset)) {
+ u32 seq_no, ack_no;
+
+ seq_no = ((u32)tcp_hdr_ptr[4] << 24) +
+ ((u32)tcp_hdr_ptr[5] << 16) +
+ ((u32)tcp_hdr_ptr[6] << 8) +
+ (u32)tcp_hdr_ptr[7];
+
+ ack_no = ((u32)tcp_hdr_ptr[8] << 24) +
+ ((u32)tcp_hdr_ptr[9] << 16) +
+ ((u32)tcp_hdr_ptr[10] << 8) +
+ (u32)tcp_hdr_ptr[11];
+
+ for (i = 0; i < tcp_session; i++) {
+ if (ack_session_info[i].seq_num == seq_no) {
+ update_tcp_session(i, ack_no);
break;
}
}
- if (i == Opened_TCP_session)
- add_TCP_track_session(0, 0, seq_no);
-
- add_TCP_Pending_Ack(Ack_no, i, tqe);
-
+ if (i == tcp_session)
+ add_tcp_session(0, 0, seq_no);
+ add_tcp_pending_ack(ack_no, i, tqe);
}
} else {
@@ -408,83 +299,81 @@ static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
return ret;
}
-
static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
{
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
u32 i = 0;
- u32 Dropped = 0;
- wilc_wlan_dev_t *p = &g_wlan;
+ u32 dropped = 0;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
- spin_lock_irqsave(&wilc->txq_spinlock, p->txq_spinlock_flags);
- for (i = PendingAcks_arrBase; i < (PendingAcks_arrBase + Pending_Acks); i++) {
- if (Pending_Acks_info[i].ack_num < Acks_keep_track_info[Pending_Acks_info[i].Session_index].Bigger_Ack_num) {
+ spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
+ for (i = pending_base; i < (pending_base + pending_acks); i++) {
+ if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) {
struct txq_entry_t *tqe;
- PRINT_D(TCP_ENH, "DROP ACK: %u\n", Pending_Acks_info[i].ack_num);
- tqe = Pending_Acks_info[i].txqe;
+ PRINT_D(TCP_ENH, "DROP ACK: %u\n",
+ pending_acks_info[i].ack_num);
+ tqe = pending_acks_info[i].txqe;
if (tqe) {
wilc_wlan_txq_remove(tqe);
- Statisitcs_DroppedAcks++;
- tqe->status = 1; /* mark the packet send */
+ tqe->status = 1;
if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv, tqe->status);
+ tqe->tx_complete_func(tqe->priv,
+ tqe->status);
kfree(tqe);
- Dropped++;
+ dropped++;
}
}
}
- Pending_Acks = 0;
- Opened_TCP_session = 0;
+ pending_acks = 0;
+ tcp_session = 0;
- if (PendingAcks_arrBase == 0)
- PendingAcks_arrBase = MAX_TCP_SESSION;
+ if (pending_base == 0)
+ pending_base = MAX_TCP_SESSION;
else
- PendingAcks_arrBase = 0;
-
+ pending_base = 0;
- spin_unlock_irqrestore(&wilc->txq_spinlock, p->txq_spinlock_flags);
+ spin_unlock_irqrestore(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
- while (Dropped > 0) {
- /*consume the semaphore count of the removed packet*/
- linux_wlan_lock_timeout(&wilc->txq_event, 1);
- Dropped--;
+ while (dropped > 0) {
+ wilc_lock_timeout(wilc, &wilc->txq_event, 1);
+ dropped--;
}
return 1;
}
#endif
-bool EnableTCPAckFilter = false;
+static bool enabled = false;
-void Enable_TCP_ACK_Filter(bool value)
+void wilc_enable_tcp_ack_filter(bool value)
{
- EnableTCPAckFilter = value;
+ enabled = value;
}
-bool is_TCP_ACK_Filter_Enabled(void)
+#ifdef TCP_ACK_FILTER
+static bool is_tcp_ack_filter_enabled(void)
{
- return EnableTCPAckFilter;
+ return enabled;
}
+#endif
-static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
+static int wilc_wlan_txq_add_cfg_pkt(struct wilc *wilc, u8 *buffer, u32 buffer_size)
{
- wilc_wlan_dev_t *p = &g_wlan;
struct txq_entry_t *tqe;
PRINT_D(TX_DBG, "Adding config packet ...\n");
- if (p->quit) {
+ if (wilc->quit) {
PRINT_D(TX_DBG, "Return due to clear function\n");
- up(&g_linux_wlan->cfg_event);
+ up(&wilc->cfg_event);
return 0;
}
- tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
- if (tqe == NULL) {
+ tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
+ if (!tqe) {
PRINT_ER("Failed to allocate memory\n");
return 0;
}
@@ -495,14 +384,11 @@ static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
tqe->tx_complete_func = NULL;
tqe->priv = NULL;
#ifdef TCP_ACK_FILTER
- tqe->tcp_PendingAck_index = NOT_TCP_ACK;
+ tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
#endif
- /**
- * Configuration packet always at the front
- **/
PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n");
- if (wilc_wlan_txq_add_to_head(tqe))
+ if (wilc_wlan_txq_add_to_head(wilc, tqe))
return 0;
return 1;
}
@@ -510,15 +396,18 @@ static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size)
int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
u32 buffer_size, wilc_tx_complete_func_t func)
{
- wilc_wlan_dev_t *p = &g_wlan;
struct txq_entry_t *tqe;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc;
+
+ wilc = vif->wilc;
- if (p->quit)
+ if (wilc->quit)
return 0;
- tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC);
+ tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
- if (tqe == NULL)
+ if (!tqe)
return 0;
tqe->type = WILC_NET_PKT;
tqe->buffer = buffer;
@@ -528,27 +417,29 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n");
#ifdef TCP_ACK_FILTER
- tqe->tcp_PendingAck_index = NOT_TCP_ACK;
- if (is_TCP_ACK_Filter_Enabled())
+ tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
+ if (is_tcp_ack_filter_enabled())
tcp_process(dev, tqe);
#endif
- wilc_wlan_txq_add_to_tail(tqe);
- /*return number of itemes in the queue*/
- return p->txq_entries;
+ wilc_wlan_txq_add_to_tail(dev, tqe);
+ return wilc->txq_entries;
}
-int wilc_wlan_txq_add_mgmt_pkt(void *priv, u8 *buffer, u32 buffer_size, wilc_tx_complete_func_t func)
+int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, wilc_tx_complete_func_t func)
{
-
- wilc_wlan_dev_t *p = &g_wlan;
struct txq_entry_t *tqe;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc;
+
+ wilc = vif->wilc;
- if (p->quit)
+ if (wilc->quit)
return 0;
- tqe = kmalloc(sizeof(struct txq_entry_t), GFP_KERNEL);
+ tqe = kmalloc(sizeof(*tqe), GFP_KERNEL);
- if (tqe == NULL)
+ if (!tqe)
return 0;
tqe->type = WILC_MGMT_PKT;
tqe->buffer = buffer;
@@ -556,25 +447,23 @@ int wilc_wlan_txq_add_mgmt_pkt(void *priv, u8 *buffer, u32 buffer_size, wilc_tx_
tqe->tx_complete_func = func;
tqe->priv = priv;
#ifdef TCP_ACK_FILTER
- tqe->tcp_PendingAck_index = NOT_TCP_ACK;
+ tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
#endif
PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n");
- wilc_wlan_txq_add_to_tail(tqe);
+ wilc_wlan_txq_add_to_tail(dev, tqe);
return 1;
}
-static struct txq_entry_t *wilc_wlan_txq_get_first(void)
+static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
{
- wilc_wlan_dev_t *p = &g_wlan;
struct txq_entry_t *tqe;
unsigned long flags;
- spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags);
-
- tqe = p->txq_head;
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
- spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags);
+ tqe = wilc->txq_head;
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
return tqe;
}
@@ -583,52 +472,50 @@ static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
struct txq_entry_t *tqe)
{
unsigned long flags;
+
spin_lock_irqsave(&wilc->txq_spinlock, flags);
tqe = tqe->next;
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
-
return tqe;
}
static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
{
- wilc_wlan_dev_t *p = &g_wlan;
- if (p->quit)
+ if (wilc->quit)
return 0;
mutex_lock(&wilc->rxq_cs);
- if (p->rxq_head == NULL) {
+ if (!wilc->rxq_head) {
PRINT_D(RX_DBG, "Add to Queue head\n");
rqe->next = NULL;
- p->rxq_head = rqe;
- p->rxq_tail = rqe;
+ wilc->rxq_head = rqe;
+ wilc->rxq_tail = rqe;
} else {
PRINT_D(RX_DBG, "Add to Queue tail\n");
- p->rxq_tail->next = rqe;
+ wilc->rxq_tail->next = rqe;
rqe->next = NULL;
- p->rxq_tail = rqe;
+ wilc->rxq_tail = rqe;
}
- p->rxq_entries += 1;
- PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries);
+ wilc->rxq_entries += 1;
+ PRINT_D(RX_DBG, "Number of queue entries: %d\n", wilc->rxq_entries);
mutex_unlock(&wilc->rxq_cs);
- return p->rxq_entries;
+ return wilc->rxq_entries;
}
static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
{
- wilc_wlan_dev_t *p = &g_wlan;
PRINT_D(RX_DBG, "Getting rxQ element\n");
- if (p->rxq_head) {
+ if (wilc->rxq_head) {
struct rxq_entry_t *rqe;
mutex_lock(&wilc->rxq_cs);
- rqe = p->rxq_head;
- p->rxq_head = p->rxq_head->next;
- p->rxq_entries -= 1;
+ rqe = wilc->rxq_head;
+ wilc->rxq_head = wilc->rxq_head->next;
+ wilc->rxq_entries -= 1;
PRINT_D(RX_DBG, "RXQ entries decreased\n");
mutex_unlock(&wilc->rxq_cs);
return rqe;
@@ -637,197 +524,151 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
return NULL;
}
-
-/********************************************
- *
- * Power Save handle functions
- *
- ********************************************/
-
-
-
#ifdef WILC_OPTIMIZE_SLEEP_INT
-static inline void chip_allow_sleep(void)
+static inline void chip_allow_sleep(struct wilc *wilc)
{
u32 reg = 0;
- /* Clear bit 1 */
- g_wlan.hif_func.hif_read_reg(0xf0, &reg);
+ wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
- g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
+ wilc->hif_func->hif_write_reg(wilc, 0xf0, reg & ~BIT(0));
}
-static inline void chip_wakeup(void)
+static inline void chip_wakeup(struct wilc *wilc)
{
u32 reg, clk_status_reg, trials = 0;
u32 sleep_time;
- if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
+ if ((wilc->io_type & 0x1) == HIF_SPI) {
do {
- g_wlan.hif_func.hif_read_reg(1, &reg);
- /* Set bit 1 */
- g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
-
- /* Clear bit 1*/
- g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
+ wilc->hif_func->hif_read_reg(wilc, 1, &reg);
+ wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
+ wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
do {
- /* Wait for the chip to stabilize*/
usleep_range(2 * 1000, 2 * 1000);
- /* Make sure chip is awake. This is an extra step that can be removed */
- /* later to avoid the bus access overhead */
- if ((wilc_get_chipid(true) == 0))
+ if ((wilc_get_chipid(wilc, true) == 0))
wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
- } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
+ } while ((wilc_get_chipid(wilc, true) == 0) && ((++trials % 3) == 0));
- } while (wilc_get_chipid(true) == 0);
- } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
- g_wlan.hif_func.hif_read_reg(0xf0, &reg);
+ } while (wilc_get_chipid(wilc, true) == 0);
+ } else if ((wilc->io_type & 0x1) == HIF_SDIO) {
+ wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
do {
- /* Set bit 1 */
- g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg | BIT(0));
+ wilc->hif_func->hif_read_reg(wilc, 0xf1,
+ &clk_status_reg);
- /* Check the clock status */
- g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
-
- /* in case of clocks off, wait 2ms, and check it again. */
- /* if still off, wait for another 2ms, for a total wait of 6ms. */
- /* If still off, redo the wake up sequence */
while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) {
- /* Wait for the chip to stabilize*/
usleep_range(2 * 1000, 2 * 1000);
- /* Make sure chip is awake. This is an extra step that can be removed */
- /* later to avoid the bus access overhead */
- g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg);
+ wilc->hif_func->hif_read_reg(wilc, 0xf1,
+ &clk_status_reg);
if ((clk_status_reg & 0x1) == 0)
wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n");
-
}
- /* in case of failure, Reset the wakeup bit to introduce a new edge on the next loop */
if ((clk_status_reg & 0x1) == 0) {
- /* Reset bit 0 */
- g_wlan.hif_func.hif_write_reg(0xf0, reg &
- (~BIT(0)));
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg & (~BIT(0)));
}
} while ((clk_status_reg & 0x1) == 0);
}
-
- if (genuChipPSstate == CHIP_SLEEPING_MANUAL) {
- g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
+ if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
+ wilc->hif_func->hif_read_reg(wilc, 0x1C0C, &reg);
reg &= ~BIT(0);
- g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
+ wilc->hif_func->hif_write_reg(wilc, 0x1C0C, reg);
- if (wilc_get_chipid(false) >= 0x1002b0) {
- /* Enable PALDO back right after wakeup */
+ if (wilc_get_chipid(wilc, false) >= 0x1002b0) {
u32 val32;
- g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
+ wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
val32 |= BIT(6);
- g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
+ wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
- g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
+ wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
val32 |= BIT(6);
- g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
+ wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
}
}
- genuChipPSstate = CHIP_WAKEDUP;
+ chip_ps_state = CHIP_WAKEDUP;
}
#else
-static inline void chip_wakeup(void)
+static inline void chip_wakeup(struct wilc *wilc)
{
u32 reg, trials = 0;
do {
- if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) {
- g_wlan.hif_func.hif_read_reg(1, &reg);
- /* Make sure bit 1 is 0 before we start. */
- g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
- /* Set bit 1 */
- g_wlan.hif_func.hif_write_reg(1, reg | BIT(1));
- /* Clear bit 1*/
- g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1));
- } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) {
- /* Make sure bit 0 is 0 before we start. */
- g_wlan.hif_func.hif_read_reg(0xf0, &reg);
- g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
- /* Set bit 1 */
- g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0));
- /* Clear bit 1 */
- g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0));
+ if ((wilc->io_type & 0x1) == HIF_SPI) {
+ wilc->hif_func->hif_read_reg(wilc, 1, &reg);
+ wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
+ wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
+ wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
+ } else if ((wilc->io_type & 0x1) == HIF_SDIO) {
+ wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg & ~BIT(0));
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg | BIT(0));
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg & ~BIT(0));
}
do {
- /* Wait for the chip to stabilize*/
mdelay(3);
- /* Make sure chip is awake. This is an extra step that can be removed */
- /* later to avoid the bus access overhead */
- if ((wilc_get_chipid(true) == 0))
+ if ((wilc_get_chipid(wilc, true) == 0))
wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n");
- } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0));
+ } while ((wilc_get_chipid(wilc, true) == 0) && ((++trials % 3) == 0));
- } while (wilc_get_chipid(true) == 0);
+ } while (wilc_get_chipid(wilc, true) == 0);
- if (genuChipPSstate == CHIP_SLEEPING_MANUAL) {
- g_wlan.hif_func.hif_read_reg(0x1C0C, &reg);
+ if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
+ wilc->hif_func->hif_read_reg(wilc, 0x1C0C, &reg);
reg &= ~BIT(0);
- g_wlan.hif_func.hif_write_reg(0x1C0C, reg);
+ wilc->hif_func->hif_write_reg(wilc, 0x1C0C, reg);
- if (wilc_get_chipid(false) >= 0x1002b0) {
- /* Enable PALDO back right after wakeup */
+ if (wilc_get_chipid(wilc, false) >= 0x1002b0) {
u32 val32;
- g_wlan.hif_func.hif_read_reg(0x1e1c, &val32);
+ wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
val32 |= BIT(6);
- g_wlan.hif_func.hif_write_reg(0x1e1c, val32);
+ wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
- g_wlan.hif_func.hif_read_reg(0x1e9c, &val32);
+ wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
val32 |= BIT(6);
- g_wlan.hif_func.hif_write_reg(0x1e9c, val32);
+ wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
}
}
- genuChipPSstate = CHIP_WAKEDUP;
+ chip_ps_state = CHIP_WAKEDUP;
}
#endif
-void chip_sleep_manually(u32 u32SleepTime)
+void wilc_chip_sleep_manually(struct wilc *wilc)
{
- if (genuChipPSstate != CHIP_WAKEDUP) {
- /* chip is already sleeping. Do nothing */
+ if (chip_ps_state != CHIP_WAKEDUP)
return;
- }
- acquire_bus(ACQUIRE_ONLY);
+ acquire_bus(wilc, ACQUIRE_ONLY);
#ifdef WILC_OPTIMIZE_SLEEP_INT
- chip_allow_sleep();
+ chip_allow_sleep(wilc);
#endif
+ wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1);
- /* Trigger the manual sleep interrupt */
- g_wlan.hif_func.hif_write_reg(0x10a8, 1);
-
- genuChipPSstate = CHIP_SLEEPING_MANUAL;
- release_bus(RELEASE_ONLY);
-
+ chip_ps_state = CHIP_SLEEPING_MANUAL;
+ release_bus(wilc, RELEASE_ONLY);
}
-
-/********************************************
- *
- * Tx, Rx queue handle functions
- *
- ********************************************/
-int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
+int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
{
- wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan;
int i, entries = 0;
u32 sum;
u32 reg;
- u8 *txb = p->tx_buffer;
+ u8 *txb;
u32 offset = 0;
int vmm_sz = 0;
struct txq_entry_t *tqe;
@@ -835,32 +676,29 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
int counter;
int timeout;
u32 vmm_table[WILC_VMM_TBL_SIZE];
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
- p->txq_exit = 0;
+ txb = wilc->tx_buffer;
+ wilc->txq_exit = 0;
do {
- if (p->quit)
+ if (wilc->quit)
break;
- linux_wlan_lock_timeout(&wilc->txq_add_to_head_cs,
+ wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs,
CFG_PKTS_TIMEOUT);
#ifdef TCP_ACK_FILTER
wilc_wlan_txq_filter_dup_tcp_ack(dev);
#endif
- /**
- * build the vmm list
- **/
PRINT_D(TX_DBG, "Getting the head of the TxQ\n");
- tqe = wilc_wlan_txq_get_first();
+ tqe = wilc_wlan_txq_get_first(wilc);
i = 0;
sum = 0;
do {
- if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE - 1)) /* reserve last entry to 0 */) {
-
+ if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
if (tqe->type == WILC_CFG_PKT)
vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
@@ -872,23 +710,22 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
vmm_sz += tqe->buffer_size;
PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz);
- if (vmm_sz & 0x3) { /* has to be word aligned */
+ if (vmm_sz & 0x3)
vmm_sz = (vmm_sz + 4) & ~0x3;
- }
+
if ((sum + vmm_sz) > LINUX_TX_SIZE)
break;
PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz);
- vmm_table[i] = vmm_sz / 4; /* table take the word size */
- PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]);
+ vmm_table[i] = vmm_sz / 4;
+ PRINT_D(TX_DBG, "VMMTable entry size = %d\n",
+ vmm_table[i]);
if (tqe->type == WILC_CFG_PKT) {
vmm_table[i] |= BIT(10);
PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]);
}
-#ifdef BIG_ENDIAN
- vmm_table[i] = BYTE_SWAP(vmm_table[i]);
-#endif
+ vmm_table[i] = cpu_to_le32(vmm_table[i]);
i++;
sum += vmm_sz;
@@ -899,27 +736,24 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
}
} while (1);
- if (i == 0) { /* nothing in the queue */
+ if (i == 0) {
PRINT_D(TX_DBG, "Nothing in TX-Q\n");
break;
} else {
PRINT_D(TX_DBG, "Mark the last entry in VMM table - number of previous entries = %d\n", i);
- vmm_table[i] = 0x0; /* mark the last element to 0 */
+ vmm_table[i] = 0x0;
}
- acquire_bus(ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
counter = 0;
do {
-
- ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL,
+ &reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n");
break;
}
if ((reg & 0x1) == 0) {
- /**
- * write to vmm table
- **/
PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4));
break;
} else {
@@ -927,69 +761,52 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
if (counter > 200) {
counter = 0;
PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n");
- ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
break;
}
- /**
- * wait for vmm table is ready
- **/
PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
usleep_range(3000, 3000);
- acquire_bus(ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
}
- } while (!p->quit);
+ } while (!wilc->quit);
if (!ret)
goto _end_;
timeout = 200;
do {
-
- /**
- * write to vmm table
- **/
- ret = p->hif_func.hif_block_tx(WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
+ ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
if (!ret) {
wilc_debug(N_ERR, "ERR block TX of VMM table.\n");
break;
}
-
- /**
- * interrupt firmware
- **/
- ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x2);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL,
+ 0x2);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n");
break;
}
- /**
- * wait for confirm...
- **/
-
do {
- ret = p->hif_func.hif_read_reg(WILC_HOST_VMM_CTL, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n");
break;
}
if ((reg >> 2) & 0x1) {
- /**
- * Get the entries
- **/
entries = ((reg >> 3) & 0x3f);
break;
} else {
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
usleep_range(3000, 3000);
- acquire_bus(ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg);
}
} while (--timeout);
if (timeout <= 0) {
- ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
break;
}
@@ -999,14 +816,13 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
if (entries == 0) {
PRINT_WRN(GENERIC_DBG, "[wilc txq]: no more buffer in the chip (reg: %08x), retry later [[ %d, %x ]]\n", reg, i, vmm_table[i - 1]);
- /* undo the transaction. */
- ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n");
break;
}
reg &= ~BIT(0);
- ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n");
break;
@@ -1025,58 +841,50 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
goto _end_;
}
- /* since copying data into txb takes some time, then
- * allow the bus lock to be released let the RX task go. */
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
- /**
- * Copy data to the TX buffer
- **/
offset = 0;
i = 0;
do {
- tqe = wilc_wlan_txq_remove_from_head();
- if (tqe != NULL && (vmm_table[i] != 0)) {
+ tqe = wilc_wlan_txq_remove_from_head(dev);
+ if (tqe && (vmm_table[i] != 0)) {
u32 header, buffer_offset;
-#ifdef BIG_ENDIAN
- vmm_table[i] = BYTE_SWAP(vmm_table[i]);
-#endif
- vmm_sz = (vmm_table[i] & 0x3ff); /* in word unit */
+ vmm_table[i] = cpu_to_le32(vmm_table[i]);
+ vmm_sz = (vmm_table[i] & 0x3ff);
vmm_sz *= 4;
- header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz;
+ header = (tqe->type << 31) |
+ (tqe->buffer_size << 15) |
+ vmm_sz;
if (tqe->type == WILC_MGMT_PKT)
header |= BIT(30);
else
header &= ~BIT(30);
-#ifdef BIG_ENDIAN
- header = BYTE_SWAP(header);
-#endif
+ header = cpu_to_le32(header);
memcpy(&txb[offset], &header, 4);
if (tqe->type == WILC_CFG_PKT) {
buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
- }
- else if (tqe->type == WILC_NET_PKT) {
- char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid;
+ } else if (tqe->type == WILC_NET_PKT) {
+ char *bssid = ((struct tx_complete_data *)(tqe->priv))->pBssid;
buffer_offset = ETH_ETHERNET_HDR_OFFSET;
- /* copy the bssid at the sart of the buffer */
- memcpy(&txb[offset + 4], pBSSID, 6);
- }
- else {
+ memcpy(&txb[offset + 4], bssid, 6);
+ } else {
buffer_offset = HOST_HDR_OFFSET;
}
- memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size);
+ memcpy(&txb[offset + buffer_offset],
+ tqe->buffer, tqe->buffer_size);
offset += vmm_sz;
i++;
- tqe->status = 1; /* mark the packet send */
+ tqe->status = 1;
if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv, tqe->status);
+ tqe->tx_complete_func(tqe->priv,
+ tqe->status);
#ifdef TCP_ACK_FILTER
- if (tqe->tcp_PendingAck_index != NOT_TCP_ACK)
- Pending_Acks_info[tqe->tcp_PendingAck_index].txqe = NULL;
+ if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK)
+ pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL;
#endif
kfree(tqe);
} else {
@@ -1084,21 +892,15 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
}
} while (--entries);
- /**
- * lock the bus
- **/
- acquire_bus(ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
- ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM);
+ ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n");
goto _end_;
}
- /**
- * transfer
- **/
- ret = p->hif_func.hif_block_tx_ext(0, txb, offset);
+ ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset);
if (!ret) {
wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n");
goto _end_;
@@ -1106,49 +908,43 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount)
_end_:
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
if (ret != 1)
break;
} while (0);
up(&wilc->txq_add_to_head_cs);
- p->txq_exit = 1;
+ wilc->txq_exit = 1;
PRINT_D(TX_DBG, "THREAD: Exiting txq\n");
- /* return tx[]q count */
- *pu32TxqCount = p->txq_entries;
+ *txq_count = wilc->txq_entries;
return ret;
}
static void wilc_wlan_handle_rxq(struct wilc *wilc)
{
- wilc_wlan_dev_t *p = &g_wlan;
int offset = 0, size, has_packet = 0;
u8 *buffer;
struct rxq_entry_t *rqe;
- p->rxq_exit = 0;
-
-
-
+ wilc->rxq_exit = 0;
do {
- if (p->quit) {
+ if (wilc->quit) {
PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n");
up(&wilc->cfg_event);
break;
}
rqe = wilc_wlan_rxq_remove(wilc);
- if (rqe == NULL) {
+ if (!rqe) {
PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n");
break;
}
buffer = rqe->buffer;
size = rqe->buffer_size;
- PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer);
+ PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n",
+ size, buffer);
offset = 0;
-
-
do {
u32 header;
u32 pkt_len, pkt_offset, tp_len;
@@ -1156,12 +952,9 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc)
PRINT_D(RX_DBG, "In the 2nd do-while\n");
memcpy(&header, &buffer[offset], 4);
-#ifdef BIG_ENDIAN
- header = BYTE_SWAP(header);
-#endif
- PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset);
-
-
+ header = cpu_to_le32(header);
+ PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n",
+ header, offset);
is_cfg_packet = (header >> 31) & 0x1;
pkt_offset = (header >> 22) & 0x1ff;
@@ -1177,45 +970,34 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc)
#define IS_MANAGMEMENT_CALLBACK 0x080
#define IS_MGMT_STATUS_SUCCES 0x040
-
if (pkt_offset & IS_MANAGMEMENT) {
- /* reset mgmt indicator bit, to use pkt_offeset in furthur calculations */
- pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES);
+ pkt_offset &= ~(IS_MANAGMEMENT |
+ IS_MANAGMEMENT_CALLBACK |
+ IS_MGMT_STATUS_SUCCES);
WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
- }
- else
- {
-
+ } else {
if (!is_cfg_packet) {
if (pkt_len > 0) {
- frmw_to_linux(wilc,
+ wilc_frmw_to_linux(wilc,
&buffer[offset],
pkt_len,
pkt_offset);
has_packet = 1;
}
} else {
- wilc_cfg_rsp_t rsp;
-
-
+ struct wilc_cfg_rsp rsp;
- wilc_wlan_cfg_indicate_rx(&buffer[pkt_offset + offset], pkt_len, &rsp);
+ wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp);
if (rsp.type == WILC_CFG_RSP) {
- /**
- * wake up the waiting task...
- **/
- PRINT_D(RX_DBG, "p->cfg_seq_no = %d - rsp.seq_no = %d\n", p->cfg_seq_no, rsp.seq_no);
- if (p->cfg_seq_no == rsp.seq_no)
+ PRINT_D(RX_DBG, "wilc->cfg_seq_no = %d - rsp.seq_no = %d\n", wilc->cfg_seq_no, rsp.seq_no);
+ if (wilc->cfg_seq_no == rsp.seq_no)
up(&wilc->cfg_event);
} else if (rsp.type == WILC_CFG_RSP_STATUS) {
- /**
- * Call back to indicate status...
- **/
- linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
+ wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
} else if (rsp.type == WILC_CFG_RSP_SCAN) {
- linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
+ wilc_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
}
}
}
@@ -1223,224 +1005,163 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc)
if (offset >= size)
break;
} while (1);
-
-
-#ifndef MEMORY_STATIC
- kfree(buffer);
-#endif
kfree(rqe);
if (has_packet)
- linux_wlan_rx_complete();
+ wilc_rx_complete(wilc);
} while (1);
- p->rxq_exit = 1;
+ wilc->rxq_exit = 1;
PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n");
}
-/********************************************
- *
- * Fast DMA Isr
- *
- ********************************************/
-static void wilc_unknown_isr_ext(void)
+static void wilc_unknown_isr_ext(struct wilc *wilc)
{
- g_wlan.hif_func.hif_clear_int_ext(0);
+ wilc->hif_func->hif_clear_int_ext(wilc, 0);
}
-static void wilc_pllupdate_isr_ext(u32 int_stats)
-{
+static void wilc_pllupdate_isr_ext(struct wilc *wilc, u32 int_stats)
+{
int trials = 10;
- g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR);
+ wilc->hif_func->hif_clear_int_ext(wilc, PLL_INT_CLR);
- /* Waiting for PLL */
- mdelay(WILC_PLL_TO);
+ if (wilc->io_type == HIF_SDIO)
+ mdelay(WILC_PLL_TO_SDIO);
+ else
+ mdelay(WILC_PLL_TO_SPI);
- /* poll till read a valid data */
- while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) {
+ while (!(ISWILC1000(wilc_get_chipid(wilc, true)) && --trials)) {
PRINT_D(TX_DBG, "PLL update retrying\n");
mdelay(1);
}
}
-static void wilc_sleeptimer_isr_ext(u32 int_stats1)
+static void wilc_sleeptimer_isr_ext(struct wilc *wilc, u32 int_stats1)
{
- g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR);
+ wilc->hif_func->hif_clear_int_ext(wilc, SLEEP_INT_CLR);
#ifndef WILC_OPTIMIZE_SLEEP_INT
- genuChipPSstate = CHIP_SLEEPING_AUTO;
+ chip_ps_state = CHIP_SLEEPING_AUTO;
#endif
}
static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
{
- wilc_wlan_dev_t *p = &g_wlan;
-#ifdef MEMORY_STATIC
- u32 offset = p->rx_buffer_offset;
-#endif
+ u32 offset = wilc->rx_buffer_offset;
u8 *buffer = NULL;
u32 size;
u32 retries = 0;
int ret = 0;
struct rxq_entry_t *rqe;
-
- /**
- * Get the rx size
- **/
-
size = ((int_status & 0x7fff) << 2);
while (!size && retries < 10) {
u32 time = 0;
- /*looping more secure*/
- /*zero size make a crashe because the dma will not happen and that will block the firmware*/
+
wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++);
- p->hif_func.hif_read_size(&size);
+ wilc->hif_func->hif_read_size(wilc, &size);
size = ((size & 0x7fff) << 2);
retries++;
-
}
if (size > 0) {
-#ifdef MEMORY_STATIC
if (LINUX_RX_SIZE - offset < size)
offset = 0;
- if (p->rx_buffer)
- buffer = &p->rx_buffer[offset];
- else {
+ if (wilc->rx_buffer) {
+ buffer = &wilc->rx_buffer[offset];
+ } else {
wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size);
goto _end_;
}
-#else
- buffer = kmalloc(size, GFP_KERNEL);
- if (buffer == NULL) {
- wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size);
- usleep_range(100 * 1000, 100 * 1000);
- goto _end_;
- }
-#endif
-
- /**
- * clear the chip's interrupt after getting size some register getting corrupted after clear the interrupt
- **/
- p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM);
-
-
- /**
- * start transfer
- **/
- ret = p->hif_func.hif_block_rx_ext(0, buffer, size);
+ wilc->hif_func->hif_clear_int_ext(wilc,
+ DATA_INT_CLR | ENABLE_RX_VMM);
+ ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size);
if (!ret) {
wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n");
goto _end_;
}
_end_:
-
-
if (ret) {
-#ifdef MEMORY_STATIC
offset += size;
- p->rx_buffer_offset = offset;
-#endif
- /**
- * add to rx queue
- **/
- rqe = kmalloc(sizeof(struct rxq_entry_t), GFP_KERNEL);
- if (rqe != NULL) {
+ wilc->rx_buffer_offset = offset;
+ rqe = kmalloc(sizeof(*rqe), GFP_KERNEL);
+ if (rqe) {
rqe->buffer = buffer;
rqe->buffer_size = size;
PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer);
wilc_wlan_rxq_add(wilc, rqe);
}
- } else {
-#ifndef MEMORY_STATIC
- kfree(buffer);
-#endif
}
}
wilc_wlan_handle_rxq(wilc);
}
-void wilc_handle_isr(void *wilc)
+void wilc_handle_isr(struct wilc *wilc)
{
u32 int_status;
- acquire_bus(ACQUIRE_AND_WAKEUP);
- g_wlan.hif_func.hif_read_int(&int_status);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+ wilc->hif_func->hif_read_int(wilc, &int_status);
if (int_status & PLL_INT_EXT)
- wilc_pllupdate_isr_ext(int_status);
+ wilc_pllupdate_isr_ext(wilc, int_status);
if (int_status & DATA_INT_EXT) {
wilc_wlan_handle_isr_ext(wilc, int_status);
#ifndef WILC_OPTIMIZE_SLEEP_INT
- /* Chip is up and talking*/
- genuChipPSstate = CHIP_WAKEDUP;
+ chip_ps_state = CHIP_WAKEDUP;
#endif
}
if (int_status & SLEEP_INT_EXT)
- wilc_sleeptimer_isr_ext(int_status);
+ wilc_sleeptimer_isr_ext(wilc, int_status);
if (!(int_status & (ALL_INT_EXT))) {
-#ifdef WILC_SDIO
- PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status);
-#endif
- wilc_unknown_isr_ext();
+ wilc_unknown_isr_ext(wilc);
}
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
}
+EXPORT_SYMBOL_GPL(wilc_handle_isr);
-/********************************************
- *
- * Firmware download
- *
- ********************************************/
-int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size)
+int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size)
{
- wilc_wlan_dev_t *p = &g_wlan;
u32 offset;
u32 addr, size, size2, blksz;
u8 *dma_buffer;
int ret = 0;
blksz = BIT(12);
- /* Allocate a DMA coherent buffer. */
dma_buffer = kmalloc(blksz, GFP_KERNEL);
- if (dma_buffer == NULL) {
- /*EIO 5*/
- ret = -5;
+ if (!dma_buffer) {
+ ret = -EIO;
PRINT_ER("Can't allocate buffer for firmware download IO error\n ");
goto _fail_1;
}
PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size);
- /**
- * load the firmware
- **/
+
offset = 0;
do {
memcpy(&addr, &buffer[offset], 4);
memcpy(&size, &buffer[offset + 4], 4);
-#ifdef BIG_ENDIAN
- addr = BYTE_SWAP(addr);
- size = BYTE_SWAP(size);
-#endif
- acquire_bus(ACQUIRE_ONLY);
+ addr = cpu_to_le32(addr);
+ size = cpu_to_le32(size);
+ acquire_bus(wilc, ACQUIRE_ONLY);
offset += 8;
while (((int)size) && (offset < buffer_size)) {
if (size <= blksz)
size2 = size;
else
size2 = blksz;
- /* Copy firmware into a DMA coherent buffer */
+
memcpy(dma_buffer, &buffer[offset], size2);
- ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2);
+ ret = wilc->hif_func->hif_block_tx(wilc, addr, dma_buffer,
+ size2);
if (!ret)
break;
@@ -1448,11 +1169,10 @@ int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size)
offset += size2;
size -= size2;
}
- release_bus(RELEASE_ONLY);
+ release_bus(wilc, RELEASE_ONLY);
if (!ret) {
- /*EIO 5*/
- ret = -5;
+ ret = -EIO;
PRINT_ER("Can't download firmware IO error\n ");
goto _fail_;
}
@@ -1468,40 +1188,29 @@ _fail_1:
return (ret < 0) ? ret : 0;
}
-/********************************************
- *
- * Common
- *
- ********************************************/
-int wilc_wlan_start(void)
+int wilc_wlan_start(struct wilc *wilc)
{
- wilc_wlan_dev_t *p = &g_wlan;
u32 reg = 0;
int ret;
u32 chipid;
- /**
- * Set the host interface
- **/
- if (p->io_func.io_type == HIF_SDIO) {
+ if (wilc->io_type == HIF_SDIO) {
reg = 0;
- reg |= BIT(3); /* bug 4456 and 4557 */
- } else if (p->io_func.io_type == HIF_SPI) {
+ reg |= BIT(3);
+ } else if (wilc->io_type == HIF_SPI) {
reg = 1;
}
- acquire_bus(ACQUIRE_ONLY);
- ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg);
+ acquire_bus(wilc, ACQUIRE_ONLY);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n");
- release_bus(RELEASE_ONLY);
- /* EIO 5*/
- ret = -5;
+ release_bus(wilc, RELEASE_ONLY);
+ ret = -EIO;
return ret;
}
reg = 0;
-#ifdef WILC_SDIO_IRQ_GPIO
- reg |= WILC_HAVE_SDIO_IRQ_GPIO;
-#endif
+ if (wilc->io_type == HIF_SDIO && wilc->dev_irq_num)
+ reg |= WILC_HAVE_SDIO_IRQ_GPIO;
#ifdef WILC_DISABLE_PMU
#else
@@ -1519,123 +1228,103 @@ int wilc_wlan_start(void)
#endif
reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
-
-
-/*Set oscillator frequency*/
#ifdef XTAL_24
reg |= WILC_HAVE_XTAL_24;
#endif
-
-/*Enable/Disable GPIO configuration for FW logs*/
#ifdef DISABLE_WILC_UART
reg |= WILC_HAVE_DISABLE_WILC_UART;
#endif
- ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n");
- release_bus(RELEASE_ONLY);
- /* EIO 5*/
- ret = -5;
+ release_bus(wilc, RELEASE_ONLY);
+ ret = -EIO;
return ret;
}
- /**
- * Bus related
- **/
- p->hif_func.hif_sync_ext(NUM_INT_EXT);
+ wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);
- ret = p->hif_func.hif_read_reg(0x1000, &chipid);
+ ret = wilc->hif_func->hif_read_reg(wilc, 0x1000, &chipid);
if (!ret) {
wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n");
- release_bus(RELEASE_ONLY);
- /* EIO 5*/
- ret = -5;
+ release_bus(wilc, RELEASE_ONLY);
+ ret = -EIO;
return ret;
}
- /**
- * Go...
- **/
-
-
- p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
+ wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
if ((reg & BIT(10)) == BIT(10)) {
reg &= ~BIT(10);
- p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
- p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
+ wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
}
reg |= BIT(10);
- ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
- p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
- release_bus(RELEASE_ONLY);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
+ release_bus(wilc, RELEASE_ONLY);
return (ret < 0) ? ret : 0;
}
-void wilc_wlan_global_reset(void)
+void wilc_wlan_global_reset(struct wilc *wilc)
{
-
- wilc_wlan_dev_t *p = &g_wlan;
-
- acquire_bus(ACQUIRE_AND_WAKEUP);
- p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0);
- release_bus(RELEASE_ONLY);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+ wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, 0x0);
+ release_bus(wilc, RELEASE_ONLY);
}
-int wilc_wlan_stop(void)
+int wilc_wlan_stop(struct wilc *wilc)
{
- wilc_wlan_dev_t *p = &g_wlan;
u32 reg = 0;
int ret;
u8 timeout = 10;
- /**
- * TODO: stop the firmware, need a re-download
- **/
- acquire_bus(ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
- ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
if (!ret) {
PRINT_ER("Error while reading reg\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
return ret;
}
reg &= ~BIT(10);
-
-
- ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
if (!ret) {
PRINT_ER("Error while writing reg\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
return ret;
}
-
-
do {
- ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
if (!ret) {
PRINT_ER("Error while reading reg\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
return ret;
}
- PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
- /*Workaround to ensure that the chip is actually reset*/
+ PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n",
+ reg, timeout);
+
if ((reg & BIT(10))) {
- PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout);
+ PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n",
+ timeout);
reg &= ~BIT(10);
- ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0,
+ reg);
timeout--;
} else {
- PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout);
- ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, &reg);
+ PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n",
+ timeout);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0,
+ &reg);
if (!ret) {
PRINT_ER("Error while reading reg\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
return ret;
}
- PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout);
+ PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n",
+ reg, timeout);
break;
}
@@ -1643,33 +1332,32 @@ int wilc_wlan_stop(void)
reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
BIT(29) | BIT(30) | BIT(31));
- p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
+ wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
reg = (u32)~BIT(10);
- ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
return ret;
}
void wilc_wlan_cleanup(struct net_device *dev)
{
- wilc_wlan_dev_t *p = &g_wlan;
struct txq_entry_t *tqe;
struct rxq_entry_t *rqe;
u32 reg = 0;
int ret;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
- p->quit = 1;
+ wilc->quit = 1;
do {
- tqe = wilc_wlan_txq_remove_from_head();
- if (tqe == NULL)
+ tqe = wilc_wlan_txq_remove_from_head(dev);
+ if (!tqe)
break;
if (tqe->tx_complete_func)
tqe->tx_complete_func(tqe->priv, 0);
@@ -1678,157 +1366,133 @@ void wilc_wlan_cleanup(struct net_device *dev)
do {
rqe = wilc_wlan_rxq_remove(wilc);
- if (rqe == NULL)
+ if (!rqe)
break;
-#ifndef MEMORY_STATIC
- kfree(rqe->buffer);
-#endif
kfree(rqe);
} while (1);
- /**
- * clean up buffer
- **/
-
- #ifdef MEMORY_STATIC
- kfree(p->rx_buffer);
- p->rx_buffer = NULL;
- #endif
- kfree(p->tx_buffer);
+ kfree(wilc->rx_buffer);
+ wilc->rx_buffer = NULL;
+ kfree(wilc->tx_buffer);
+ wilc->tx_buffer = NULL;
- acquire_bus(ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
-
- ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
if (!ret) {
PRINT_ER("Error while reading reg\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
}
PRINT_ER("Writing ABORT reg\n");
- ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT));
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
+ (reg | ABORT_INT));
if (!ret) {
PRINT_ER("Error while writing reg\n");
- release_bus(RELEASE_ALLOW_SLEEP);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
}
- release_bus(RELEASE_ALLOW_SLEEP);
- /**
- * io clean up
- **/
- p->hif_func.hif_deinit(NULL);
-
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ wilc->hif_func->hif_deinit(NULL);
}
-static int wilc_wlan_cfg_commit(int type, u32 drvHandler)
+static int wilc_wlan_cfg_commit(struct wilc *wilc, int type, u32 drv_handler)
{
- wilc_wlan_dev_t *p = &g_wlan;
- wilc_cfg_frame_t *cfg = &p->cfg_frame;
- int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
- int seq_no = p->cfg_seq_no % 256;
- int driver_handler = (u32)drvHandler;
-
+ struct wilc_cfg_frame *cfg = &wilc->cfg_frame;
+ int total_len = wilc->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
+ int seq_no = wilc->cfg_seq_no % 256;
+ int driver_handler = (u32)drv_handler;
- /**
- * Set up header
- **/
- if (type == WILC_CFG_SET) { /* Set */
+ if (type == WILC_CFG_SET)
cfg->wid_header[0] = 'W';
- } else { /* Query */
+ else
cfg->wid_header[0] = 'Q';
- }
- cfg->wid_header[1] = seq_no; /* sequence number */
+ cfg->wid_header[1] = seq_no;
cfg->wid_header[2] = (u8)total_len;
cfg->wid_header[3] = (u8)(total_len >> 8);
cfg->wid_header[4] = (u8)driver_handler;
cfg->wid_header[5] = (u8)(driver_handler >> 8);
cfg->wid_header[6] = (u8)(driver_handler >> 16);
cfg->wid_header[7] = (u8)(driver_handler >> 24);
- p->cfg_seq_no = seq_no;
-
- /**
- * Add to TX queue
- **/
+ wilc->cfg_seq_no = seq_no;
- if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len))
+ if (!wilc_wlan_txq_add_cfg_pkt(wilc, &cfg->wid_header[0], total_len))
return -1;
return 0;
}
-int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size,
- int commit, u32 drvHandler)
+int wilc_wlan_cfg_set(struct wilc *wilc, int start, u32 wid, u8 *buffer,
+ u32 buffer_size, int commit, u32 drv_handler)
{
- wilc_wlan_dev_t *p = &g_wlan;
u32 offset;
int ret_size;
-
- if (p->cfg_frame_in_use)
+ if (wilc->cfg_frame_in_use)
return 0;
if (start)
- p->cfg_frame_offset = 0;
+ wilc->cfg_frame_offset = 0;
- offset = p->cfg_frame_offset;
- ret_size = wilc_wlan_cfg_set_wid(p->cfg_frame.frame, offset, (u16)wid,
- buffer, buffer_size);
+ offset = wilc->cfg_frame_offset;
+ ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,
+ (u16)wid, buffer, buffer_size);
offset += ret_size;
- p->cfg_frame_offset = offset;
+ wilc->cfg_frame_offset = offset;
if (commit) {
- PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no);
+ PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n",
+ wilc->cfg_seq_no);
PRINT_D(RX_DBG, "Processing cfg_set()\n");
- p->cfg_frame_in_use = 1;
+ wilc->cfg_frame_in_use = 1;
- if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler))
+ if (wilc_wlan_cfg_commit(wilc, WILC_CFG_SET, drv_handler))
ret_size = 0;
- if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
+ if (wilc_lock_timeout(wilc, &wilc->cfg_event,
CFG_PKTS_TIMEOUT)) {
PRINT_D(TX_DBG, "Set Timed Out\n");
ret_size = 0;
}
- p->cfg_frame_in_use = 0;
- p->cfg_frame_offset = 0;
- p->cfg_seq_no += 1;
-
+ wilc->cfg_frame_in_use = 0;
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
}
return ret_size;
}
-int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler)
+
+int wilc_wlan_cfg_get(struct wilc *wilc, int start, u32 wid, int commit,
+ u32 drv_handler)
{
- wilc_wlan_dev_t *p = &g_wlan;
u32 offset;
int ret_size;
-
- if (p->cfg_frame_in_use)
+ if (wilc->cfg_frame_in_use)
return 0;
if (start)
- p->cfg_frame_offset = 0;
+ wilc->cfg_frame_offset = 0;
- offset = p->cfg_frame_offset;
- ret_size = wilc_wlan_cfg_get_wid(p->cfg_frame.frame, offset, (u16)wid);
+ offset = wilc->cfg_frame_offset;
+ ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset,
+ (u16)wid);
offset += ret_size;
- p->cfg_frame_offset = offset;
+ wilc->cfg_frame_offset = offset;
if (commit) {
- p->cfg_frame_in_use = 1;
+ wilc->cfg_frame_in_use = 1;
- if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler))
+ if (wilc_wlan_cfg_commit(wilc, WILC_CFG_QUERY, drv_handler))
ret_size = 0;
-
- if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event,
+ if (wilc_lock_timeout(wilc, &wilc->cfg_event,
CFG_PKTS_TIMEOUT)) {
PRINT_D(TX_DBG, "Get Timed Out\n");
ret_size = 0;
}
PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n");
- p->cfg_frame_in_use = 0;
- p->cfg_frame_offset = 0;
- p->cfg_seq_no += 1;
+ wilc->cfg_frame_in_use = 0;
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
}
return ret_size;
@@ -1843,92 +1507,69 @@ int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size)
return ret;
}
-void wilc_bus_set_max_speed(void)
-{
-
- /* Increase bus speed to max possible. */
- g_wlan.hif_func.hif_set_max_bus_speed();
-}
-
-void wilc_bus_set_default_speed(void)
-{
-
- /* Restore bus speed to default. */
- g_wlan.hif_func.hif_set_default_bus_speed();
-}
-u32 init_chip(void)
+static u32 init_chip(struct net_device *dev)
{
u32 chipid;
u32 reg, ret = 0;
+ struct wilc_vif *vif;
+ struct wilc *wilc;
- acquire_bus(ACQUIRE_ONLY);
-
- chipid = wilc_get_chipid(true);
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
+ acquire_bus(wilc, ACQUIRE_ONLY);
+ chipid = wilc_get_chipid(wilc, true);
if ((chipid & 0xfff) != 0xa0) {
- /**
- * Avoid booting from boot ROM. Make sure that Drive IRQN [SDIO platform]
- * or SD_DAT3 [SPI platform] to ?1?
- **/
- /* Set cortus reset register to register control. */
- ret = g_wlan.hif_func.hif_read_reg(0x1118, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, &reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n");
return ret;
}
reg |= BIT(0);
- ret = g_wlan.hif_func.hif_write_reg(0x1118, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
if (!ret) {
wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n");
return ret;
}
- /**
- * Write branch intruction to IRAM (0x71 trap) at location 0xFFFF0000
- * (Cortus map) or C0000 (AHB map).
- **/
- ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71);
+ ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
if (!ret) {
wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n");
return ret;
}
}
- release_bus(RELEASE_ONLY);
+ release_bus(wilc, RELEASE_ONLY);
return ret;
-
}
-u32 wilc_get_chipid(u8 update)
+u32 wilc_get_chipid(struct wilc *wilc, u8 update)
{
static u32 chipid;
- /* SDIO can't read into global variables */
- /* Use this variable as a temp, then copy to the global */
u32 tempchipid = 0;
u32 rfrevid;
if (chipid == 0 || update != 0) {
- g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid);
- g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid);
+ wilc->hif_func->hif_read_reg(wilc, 0x1000, &tempchipid);
+ wilc->hif_func->hif_read_reg(wilc, 0x13f4, &rfrevid);
if (!ISWILC1000(tempchipid)) {
chipid = 0;
goto _fail_;
}
if (tempchipid == 0x1002a0) {
- if (rfrevid == 0x1) { /* 1002A0 */
- } else { /* if (rfrevid == 0x2) */ /* 1002A1 */
+ if (rfrevid == 0x1) {
+ } else {
tempchipid = 0x1002a1;
}
} else if (tempchipid == 0x1002b0) {
- if (rfrevid == 3) { /* 1002B0 */
- } else if (rfrevid == 4) { /* 1002B1 */
+ if (rfrevid == 3) {
+ } else if (rfrevid == 4) {
tempchipid = 0x1002b1;
- } else { /* if(rfrevid == 5) */ /* 1002B2 */
+ } else {
tempchipid = 0x1002b2;
}
- } else {
}
chipid = tempchipid;
@@ -1937,129 +1578,88 @@ _fail_:
return chipid;
}
-int wilc_wlan_init(wilc_wlan_inp_t *inp)
+int wilc_wlan_init(struct net_device *dev)
{
-
int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc;
+
+ wilc = vif->wilc;
PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n");
- memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t));
-
- /**
- * store the input
- **/
- memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t));
- /***
- * host interface init
- **/
- if ((inp->io_func.io_type & 0x1) == HIF_SDIO) {
- if (!hif_sdio.hif_init(inp, wilc_debug)) {
- /* EIO 5 */
- ret = -5;
- goto _fail_;
- }
- memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t));
- } else {
- if ((inp->io_func.io_type & 0x1) == HIF_SPI) {
- /**
- * TODO:
- **/
- if (!hif_spi.hif_init(inp, wilc_debug)) {
- /* EIO 5 */
- ret = -5;
- goto _fail_;
- }
- memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t));
- } else {
- /* EIO 5 */
- ret = -5;
- goto _fail_;
- }
+ if (!wilc->hif_func->hif_init(wilc)) {
+ ret = -EIO;
+ goto _fail_;
}
- /***
- * mac interface init
- **/
if (!wilc_wlan_cfg_init(wilc_debug)) {
- /* ENOBUFS 105 */
- ret = -105;
+ ret = -ENOBUFS;
goto _fail_;
}
- /**
- * alloc tx, rx buffer
- **/
- if (g_wlan.tx_buffer == NULL)
- g_wlan.tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
- PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer);
+ if (!wilc->tx_buffer)
+ wilc->tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
+ PRINT_D(TX_DBG, "wilc->tx_buffer = %p\n", wilc->tx_buffer);
- if (g_wlan.tx_buffer == NULL) {
- /* ENOBUFS 105 */
- ret = -105;
+ if (!wilc->tx_buffer) {
+ ret = -ENOBUFS;
PRINT_ER("Can't allocate Tx Buffer");
goto _fail_;
}
-/* rx_buffer is not used unless we activate USE_MEM STATIC which is not applicable, allocating such memory is useless*/
-#if defined (MEMORY_STATIC)
- if (g_wlan.rx_buffer == NULL)
- g_wlan.rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
- PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer);
- if (g_wlan.rx_buffer == NULL) {
- /* ENOBUFS 105 */
- ret = -105;
+ if (!wilc->rx_buffer)
+ wilc->rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
+ PRINT_D(TX_DBG, "wilc->rx_buffer =%p\n", wilc->rx_buffer);
+ if (!wilc->rx_buffer) {
+ ret = -ENOBUFS;
PRINT_ER("Can't allocate Rx Buffer");
goto _fail_;
}
-#endif
- if (!init_chip()) {
- /* EIO 5 */
- ret = -5;
+ if (!init_chip(dev)) {
+ ret = -EIO;
goto _fail_;
}
#ifdef TCP_ACK_FILTER
- Init_TCP_tracking();
+ init_tcp_tracking();
#endif
return 1;
_fail_:
- #ifdef MEMORY_STATIC
- kfree(g_wlan.rx_buffer);
- g_wlan.rx_buffer = NULL;
- #endif
- kfree(g_wlan.tx_buffer);
- g_wlan.tx_buffer = NULL;
+ kfree(wilc->rx_buffer);
+ wilc->rx_buffer = NULL;
+ kfree(wilc->tx_buffer);
+ wilc->tx_buffer = NULL;
return ret;
-
}
-u16 Set_machw_change_vir_if(struct net_device *dev, bool bValue)
+u16 wilc_set_machw_change_vir_if(struct net_device *dev, bool value)
{
u16 ret;
u32 reg;
- perInterface_wlan_t *nic;
+ struct wilc_vif *vif;
struct wilc *wilc;
- nic = netdev_priv(dev);
- wilc = nic->wilc;
+ vif = netdev_priv(dev);
+ wilc = vif->wilc;
- /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/
mutex_lock(&wilc->hif_cs);
- ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, &reg);
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHANGING_VIR_IF,
+ &reg);
if (!ret)
PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n");
- if (bValue)
+ if (value)
reg |= BIT(31);
else
reg &= ~BIT(31);
- ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_CHANGING_VIR_IF,
+ reg);
if (!ret)
PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n");
diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h
index 57e1d5174050..2edd7445f4a3 100644
--- a/drivers/staging/wilc1000/wilc_wlan.h
+++ b/drivers/staging/wilc1000/wilc_wlan.h
@@ -1,155 +1,131 @@
#ifndef WILC_WLAN_H
#define WILC_WLAN_H
+#include <linux/types.h>
-
-#define ISWILC1000(id) (((id & 0xfffff000) == 0x100000) ? 1 : 0)
-
+#define ISWILC1000(id) ((id & 0xfffff000) == 0x100000 ? 1 : 0)
/********************************************
*
* Mac eth header length
*
********************************************/
-#define DRIVER_HANDLER_SIZE 4
-#define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */
-#define SUB_MSDU_HEADER_LENGTH 14
-#define SNAP_HDR_LEN 8
-#define ETHERNET_HDR_LEN 14
-#define WORD_ALIGNMENT_PAD 0
-
-#define ETH_ETHERNET_HDR_OFFSET (MAX_MAC_HDR_LEN + SUB_MSDU_HEADER_LENGTH + \
- SNAP_HDR_LEN - ETHERNET_HDR_LEN + WORD_ALIGNMENT_PAD)
-
-#define HOST_HDR_OFFSET 4
-#define ETHERNET_HDR_LEN 14
-#define IP_HDR_LEN 20
-#define IP_HDR_OFFSET ETHERNET_HDR_LEN
-#define UDP_HDR_OFFSET (IP_HDR_LEN + IP_HDR_OFFSET)
-#define UDP_HDR_LEN 8
-#define UDP_DATA_OFFSET (UDP_HDR_OFFSET + UDP_HDR_LEN)
-#define ETH_CONFIG_PKT_HDR_LEN UDP_DATA_OFFSET
-
-#define ETH_CONFIG_PKT_HDR_OFFSET (ETH_ETHERNET_HDR_OFFSET + \
- ETH_CONFIG_PKT_HDR_LEN)
-
-/********************************************
- *
- * Endian Conversion
- *
- ********************************************/
-
-#define BYTE_SWAP(val) ((((val) & 0x000000FF) << 24) + \
- (((val) & 0x0000FF00) << 8) + \
- (((val) & 0x00FF0000) >> 8) + \
- (((val) & 0xFF000000) >> 24))
+#define DRIVER_HANDLER_SIZE 4
+#define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */
+#define SUB_MSDU_HEADER_LENGTH 14
+#define SNAP_HDR_LEN 8
+#define ETHERNET_HDR_LEN 14
+#define WORD_ALIGNMENT_PAD 0
+
+#define ETH_ETHERNET_HDR_OFFSET (MAX_MAC_HDR_LEN + \
+ SUB_MSDU_HEADER_LENGTH + \
+ SNAP_HDR_LEN - \
+ ETHERNET_HDR_LEN + \
+ WORD_ALIGNMENT_PAD)
+
+#define HOST_HDR_OFFSET 4
+#define ETHERNET_HDR_LEN 14
+#define IP_HDR_LEN 20
+#define IP_HDR_OFFSET ETHERNET_HDR_LEN
+#define UDP_HDR_OFFSET (IP_HDR_LEN + IP_HDR_OFFSET)
+#define UDP_HDR_LEN 8
+#define UDP_DATA_OFFSET (UDP_HDR_OFFSET + UDP_HDR_LEN)
+#define ETH_CONFIG_PKT_HDR_LEN UDP_DATA_OFFSET
+
+#define ETH_CONFIG_PKT_HDR_OFFSET (ETH_ETHERNET_HDR_OFFSET + \
+ ETH_CONFIG_PKT_HDR_LEN)
/********************************************
*
* Register Defines
*
********************************************/
-#define WILC_PERIPH_REG_BASE 0x1000
-#define WILC_CHANGING_VIR_IF (0x108c)
-#define WILC_CHIPID (WILC_PERIPH_REG_BASE)
-#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400)
-#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408)
-#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c)
-#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70)
-#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74)
-#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78)
-#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80)
-#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84)
-#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88)
-#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428)
-#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00)
-#define WILC_INTR_ENABLE (WILC_INTR_REG_BASE)
-#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4)
-
-#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10)
-#define WILC_INTR_TYPE (WILC_INTR_REG_BASE + 0x20)
-#define WILC_INTR_CLEAR (WILC_INTR_REG_BASE + 0x30)
-#define WILC_INTR_STATUS (WILC_INTR_REG_BASE + 0x40)
-
-#define WILC_VMM_TBL_SIZE 64
-#define WILC_VMM_TX_TBL_BASE (0x150400)
-#define WILC_VMM_RX_TBL_BASE (0x150500)
-
-#define WILC_VMM_BASE 0x150000
-#define WILC_VMM_CORE_CTL (WILC_VMM_BASE)
-#define WILC_VMM_TBL_CTL (WILC_VMM_BASE + 0x4)
-#define WILC_VMM_TBL_ENTRY (WILC_VMM_BASE + 0x8)
-#define WILC_VMM_TBL0_SIZE (WILC_VMM_BASE + 0xc)
-#define WILC_VMM_TO_HOST_SIZE (WILC_VMM_BASE + 0x10)
-#define WILC_VMM_CORE_CFG (WILC_VMM_BASE + 0x14)
-#define WILC_VMM_TBL_ACTIVE (WILC_VMM_BASE + 040)
-#define WILC_VMM_TBL_STATUS (WILC_VMM_BASE + 0x44)
-
-#define WILC_SPI_REG_BASE 0xe800
-#define WILC_SPI_CTL (WILC_SPI_REG_BASE)
-#define WILC_SPI_MASTER_DMA_ADDR (WILC_SPI_REG_BASE + 0x4)
-#define WILC_SPI_MASTER_DMA_COUNT (WILC_SPI_REG_BASE + 0x8)
-#define WILC_SPI_SLAVE_DMA_ADDR (WILC_SPI_REG_BASE + 0xc)
-#define WILC_SPI_SLAVE_DMA_COUNT (WILC_SPI_REG_BASE + 0x10)
-#define WILC_SPI_TX_MODE (WILC_SPI_REG_BASE + 0x20)
-#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24)
-#define WILC_SPI_INTR_CTL (WILC_SPI_REG_BASE + 0x2c)
-
-#define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - WILC_SPI_REG_BASE)
-
-#define WILC_AHB_DATA_MEM_BASE 0x30000
-#define WILC_AHB_SHARE_MEM_BASE 0xd0000
-
-#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE
-#define WILC_VMM_TBL_RX_SHADOW_SIZE (256)
-
-#define WILC_GP_REG_0 0x149c
-#define WILC_GP_REG_1 0x14a0
-
-#define rHAVE_SDIO_IRQ_GPIO_BIT (0)
-#define rHAVE_USE_PMU_BIT (1)
-#define rHAVE_SLEEP_CLK_SRC_RTC_BIT (2)
-#define rHAVE_SLEEP_CLK_SRC_XO_BIT (3)
-#define rHAVE_EXT_PA_INV_TX_RX_BIT (4)
-#define rHAVE_LEGACY_RF_SETTINGS_BIT (5)
-#define rHAVE_XTAL_24_BIT (6)
-#define rHAVE_DISABLE_WILC_UART_BIT (7)
-
-
-#define WILC_HAVE_SDIO_IRQ_GPIO (1 << rHAVE_SDIO_IRQ_GPIO_BIT)
-#define WILC_HAVE_USE_PMU (1 << rHAVE_USE_PMU_BIT)
-#define WILC_HAVE_SLEEP_CLK_SRC_RTC (1 << rHAVE_SLEEP_CLK_SRC_RTC_BIT)
-#define WILC_HAVE_SLEEP_CLK_SRC_XO (1 << rHAVE_SLEEP_CLK_SRC_XO_BIT)
-#define WILC_HAVE_EXT_PA_INV_TX_RX (1 << rHAVE_EXT_PA_INV_TX_RX_BIT)
-#define WILC_HAVE_LEGACY_RF_SETTINGS (1 << rHAVE_LEGACY_RF_SETTINGS_BIT)
-#define WILC_HAVE_XTAL_24 (1 << rHAVE_XTAL_24_BIT)
-#define WILC_HAVE_DISABLE_WILC_UART (1 << rHAVE_DISABLE_WILC_UART_BIT)
-
+#define WILC_PERIPH_REG_BASE 0x1000
+#define WILC_CHANGING_VIR_IF 0x108c
+#define WILC_CHIPID WILC_PERIPH_REG_BASE
+#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400)
+#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408)
+#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c)
+#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70)
+#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74)
+#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78)
+#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80)
+#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84)
+#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88)
+#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428)
+#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00)
+#define WILC_INTR_ENABLE WILC_INTR_REG_BASE
+#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4)
+
+#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10)
+#define WILC_INTR_TYPE (WILC_INTR_REG_BASE + 0x20)
+#define WILC_INTR_CLEAR (WILC_INTR_REG_BASE + 0x30)
+#define WILC_INTR_STATUS (WILC_INTR_REG_BASE + 0x40)
+
+#define WILC_VMM_TBL_SIZE 64
+#define WILC_VMM_TX_TBL_BASE 0x150400
+#define WILC_VMM_RX_TBL_BASE 0x150500
+
+#define WILC_VMM_BASE 0x150000
+#define WILC_VMM_CORE_CTL WILC_VMM_BASE
+#define WILC_VMM_TBL_CTL (WILC_VMM_BASE + 0x4)
+#define WILC_VMM_TBL_ENTRY (WILC_VMM_BASE + 0x8)
+#define WILC_VMM_TBL0_SIZE (WILC_VMM_BASE + 0xc)
+#define WILC_VMM_TO_HOST_SIZE (WILC_VMM_BASE + 0x10)
+#define WILC_VMM_CORE_CFG (WILC_VMM_BASE + 0x14)
+#define WILC_VMM_TBL_ACTIVE (WILC_VMM_BASE + 040)
+#define WILC_VMM_TBL_STATUS (WILC_VMM_BASE + 0x44)
+
+#define WILC_SPI_REG_BASE 0xe800
+#define WILC_SPI_CTL WILC_SPI_REG_BASE
+#define WILC_SPI_MASTER_DMA_ADDR (WILC_SPI_REG_BASE + 0x4)
+#define WILC_SPI_MASTER_DMA_COUNT (WILC_SPI_REG_BASE + 0x8)
+#define WILC_SPI_SLAVE_DMA_ADDR (WILC_SPI_REG_BASE + 0xc)
+#define WILC_SPI_SLAVE_DMA_COUNT (WILC_SPI_REG_BASE + 0x10)
+#define WILC_SPI_TX_MODE (WILC_SPI_REG_BASE + 0x20)
+#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24)
+#define WILC_SPI_INTR_CTL (WILC_SPI_REG_BASE + 0x2c)
+
+#define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - \
+ WILC_SPI_REG_BASE)
+
+#define WILC_AHB_DATA_MEM_BASE 0x30000
+#define WILC_AHB_SHARE_MEM_BASE 0xd0000
+
+#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE
+#define WILC_VMM_TBL_RX_SHADOW_SIZE 256
+
+#define WILC_GP_REG_0 0x149c
+#define WILC_GP_REG_1 0x14a0
+
+#define WILC_HAVE_SDIO_IRQ_GPIO BIT(0)
+#define WILC_HAVE_USE_PMU BIT(1)
+#define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2)
+#define WILC_HAVE_SLEEP_CLK_SRC_XO BIT(3)
+#define WILC_HAVE_EXT_PA_INV_TX_RX BIT(4)
+#define WILC_HAVE_LEGACY_RF_SETTINGS BIT(5)
+#define WILC_HAVE_XTAL_24 BIT(6)
+#define WILC_HAVE_DISABLE_WILC_UART BIT(7)
/********************************************
*
* Wlan Defines
*
********************************************/
-#define WILC_CFG_PKT 1
-#define WILC_NET_PKT 0
-#define WILC_MGMT_PKT 2
+#define WILC_CFG_PKT 1
+#define WILC_NET_PKT 0
+#define WILC_MGMT_PKT 2
-#define WILC_CFG_SET 1
-#define WILC_CFG_QUERY 0
-
-#define WILC_CFG_RSP 1
-#define WILC_CFG_RSP_STATUS 2
-#define WILC_CFG_RSP_SCAN 3
-
-#ifdef WILC_SDIO
-#define WILC_PLL_TO 4
-#else
-#define WILC_PLL_TO 2
-#endif
+#define WILC_CFG_SET 1
+#define WILC_CFG_QUERY 0
+#define WILC_CFG_RSP 1
+#define WILC_CFG_RSP_STATUS 2
+#define WILC_CFG_RSP_SCAN 3
-#define ABORT_INT BIT(31)
+#define WILC_PLL_TO_SDIO 4
+#define WILC_PLL_TO_SPI 2
+#define ABORT_INT BIT(31)
/*******************************************/
/* E0 and later Interrupt flags. */
@@ -165,15 +141,15 @@
/* 20: INT4 flag */
/* 21: INT5 flag */
/*******************************************/
-#define IRG_FLAGS_OFFSET 16
-#define IRQ_DMA_WD_CNT_MASK ((1ul << IRG_FLAGS_OFFSET) - 1)
-#define INT_0 (1 << (IRG_FLAGS_OFFSET))
-#define INT_1 (1 << (IRG_FLAGS_OFFSET + 1))
-#define INT_2 (1 << (IRG_FLAGS_OFFSET + 2))
-#define INT_3 (1 << (IRG_FLAGS_OFFSET + 3))
-#define INT_4 (1 << (IRG_FLAGS_OFFSET + 4))
-#define INT_5 (1 << (IRG_FLAGS_OFFSET + 5))
-#define MAX_NUM_INT (6)
+#define IRG_FLAGS_OFFSET 16
+#define IRQ_DMA_WD_CNT_MASK ((1ul << IRG_FLAGS_OFFSET) - 1)
+#define INT_0 BIT(IRG_FLAGS_OFFSET)
+#define INT_1 BIT(IRG_FLAGS_OFFSET + 1)
+#define INT_2 BIT(IRG_FLAGS_OFFSET + 2)
+#define INT_3 BIT(IRG_FLAGS_OFFSET + 3)
+#define INT_4 BIT(IRG_FLAGS_OFFSET + 4)
+#define INT_5 BIT(IRG_FLAGS_OFFSET + 5)
+#define MAX_NUM_INT 6
/*******************************************/
/* E0 and later Interrupt flags. */
@@ -188,30 +164,28 @@
/* 7: Select VMM table 2 */
/* 8: Enable VMM */
/*******************************************/
-#define CLR_INT0 BIT(0)
-#define CLR_INT1 BIT(1)
-#define CLR_INT2 BIT(2)
-#define CLR_INT3 BIT(3)
-#define CLR_INT4 BIT(4)
-#define CLR_INT5 BIT(5)
-#define SEL_VMM_TBL0 BIT(6)
-#define SEL_VMM_TBL1 BIT(7)
-#define EN_VMM BIT(8)
-
-#define DATA_INT_EXT INT_0
-#define PLL_INT_EXT INT_1
-#define SLEEP_INT_EXT INT_2
-#define ALL_INT_EXT (DATA_INT_EXT | PLL_INT_EXT | SLEEP_INT_EXT)
-#define NUM_INT_EXT (3)
-
-#define DATA_INT_CLR CLR_INT0
-#define PLL_INT_CLR CLR_INT1
-#define SLEEP_INT_CLR CLR_INT2
-
-#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM)
-#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM)
-
-
+#define CLR_INT0 BIT(0)
+#define CLR_INT1 BIT(1)
+#define CLR_INT2 BIT(2)
+#define CLR_INT3 BIT(3)
+#define CLR_INT4 BIT(4)
+#define CLR_INT5 BIT(5)
+#define SEL_VMM_TBL0 BIT(6)
+#define SEL_VMM_TBL1 BIT(7)
+#define EN_VMM BIT(8)
+
+#define DATA_INT_EXT INT_0
+#define PLL_INT_EXT INT_1
+#define SLEEP_INT_EXT INT_2
+#define ALL_INT_EXT (DATA_INT_EXT | PLL_INT_EXT | SLEEP_INT_EXT)
+#define NUM_INT_EXT 3
+
+#define DATA_INT_CLR CLR_INT0
+#define PLL_INT_CLR CLR_INT1
+#define SLEEP_INT_CLR CLR_INT2
+
+#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM)
+#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM)
/*time for expiring the semaphores of cfg packets*/
#define CFG_PKTS_TIMEOUT 2000
/********************************************
@@ -231,7 +205,7 @@ struct txq_entry_t {
struct txq_entry_t *next;
struct txq_entry_t *prev;
int type;
- int tcp_PendingAck_index;
+ int tcp_pending_ack_idx;
u8 *buffer;
int buffer_size;
void *priv;
@@ -250,25 +224,26 @@ struct rxq_entry_t {
* Host IF Structure
*
********************************************/
+struct wilc;
+struct wilc_hif_func {
+ int (*hif_init)(struct wilc *);
+ int (*hif_deinit)(struct wilc *);
+ int (*hif_read_reg)(struct wilc *, u32, u32 *);
+ int (*hif_write_reg)(struct wilc *, u32, u32);
+ int (*hif_block_rx)(struct wilc *, u32, u8 *, u32);
+ int (*hif_block_tx)(struct wilc *, u32, u8 *, u32);
+ int (*hif_read_int)(struct wilc *, u32 *);
+ int (*hif_clear_int_ext)(struct wilc *, u32);
+ int (*hif_read_size)(struct wilc *, u32 *);
+ int (*hif_block_tx_ext)(struct wilc *, u32, u8 *, u32);
+ int (*hif_block_rx_ext)(struct wilc *, u32, u8 *, u32);
+ int (*hif_sync_ext)(struct wilc *, int);
+ int (*enable_interrupt)(struct wilc *nic);
+ void (*disable_interrupt)(struct wilc *nic);
+};
-typedef struct {
- int (*hif_init)(wilc_wlan_inp_t *, wilc_debug_func);
- int (*hif_deinit)(void *);
- int (*hif_read_reg)(u32, u32 *);
- int (*hif_write_reg)(u32, u32);
- int (*hif_block_rx)(u32, u8 *, u32);
- int (*hif_block_tx)(u32, u8 *, u32);
- int (*hif_sync)(void);
- int (*hif_clear_int)(void);
- int (*hif_read_int)(u32 *);
- int (*hif_clear_int_ext)(u32);
- int (*hif_read_size)(u32 *);
- int (*hif_block_tx_ext)(u32, u8 *, u32);
- int (*hif_block_rx_ext)(u32, u8 *, u32);
- int (*hif_sync_ext)(int);
- void (*hif_set_max_bus_speed)(void);
- void (*hif_set_default_bus_speed)(void);
-} wilc_hif_func_t;
+extern const struct wilc_hif_func wilc_hif_spi;
+extern const struct wilc_hif_func wilc_hif_sdio;
/********************************************
*
@@ -276,37 +251,50 @@ typedef struct {
*
********************************************/
-#define MAX_CFG_FRAME_SIZE 1468
+#define MAX_CFG_FRAME_SIZE 1468
-typedef struct {
+struct wilc_cfg_frame {
u8 ether_header[14];
u8 ip_header[20];
u8 udp_header[8];
u8 wid_header[8];
u8 frame[MAX_CFG_FRAME_SIZE];
-} wilc_cfg_frame_t;
-
-typedef struct {
- int (*wlan_tx)(u8 *, u32, wilc_tx_complete_func_t);
-} wilc_wlan_cfg_func_t;
+};
-typedef struct {
+struct wilc_cfg_rsp {
int type;
u32 seq_no;
-} wilc_cfg_rsp_t;
+};
-int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size);
-int wilc_wlan_start(void);
-int wilc_wlan_stop(void);
+struct wilc;
+
+int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size);
+int wilc_wlan_start(struct wilc *);
+int wilc_wlan_stop(struct wilc *);
int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
u32 buffer_size, wilc_tx_complete_func_t func);
-int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount);
-void wilc_handle_isr(void *wilc);
+int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count);
+void wilc_handle_isr(struct wilc *wilc);
void wilc_wlan_cleanup(struct net_device *dev);
-int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size,
- int commit, u32 drvHandler);
-int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler);
+int wilc_wlan_cfg_set(struct wilc *wilc, int start, u32 wid, u8 *buffer,
+ u32 buffer_size, int commit, u32 drv_handler);
+int wilc_wlan_cfg_get(struct wilc *wilc, int start, u32 wid, int commit,
+ u32 drv_handler);
int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size);
-int wilc_wlan_txq_add_mgmt_pkt(void *priv, u8 *buffer, u32 buffer_size,
- wilc_tx_complete_func_t func);
+int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, wilc_tx_complete_func_t func);
+void wilc_chip_sleep_manually(struct wilc *wilc);
+
+void wilc_enable_tcp_ack_filter(bool value);
+int wilc_wlan_get_num_conn_ifcs(struct wilc *);
+int wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
+
+int wilc_mac_open(struct net_device *ndev);
+int wilc_mac_close(struct net_device *ndev);
+
+int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *pBSSID);
+void WILC_WFI_p2p_rx(struct net_device *dev, u8 *buff, u32 size);
+
+extern bool wilc_enable_ps;
+
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c
index a34a81cdeb5e..b72c77bb35f1 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.c
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c
@@ -275,9 +275,7 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
while (size > 0) {
i = 0;
wid = info[0] | (info[1] << 8);
-#ifdef BIG_ENDIAN
- wid = BYTE_SWAP(wid);
-#endif
+ wid = cpu_to_le32(wid);
PRINT_INFO(GENERIC_DBG, "Processing response for %d seq %d\n", wid, seq++);
switch ((wid >> 12) & 0x7) {
case WID_CHAR:
@@ -300,11 +298,7 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
break;
if (g_cfg_hword[i].id == wid) {
-#ifdef BIG_ENDIAN
- g_cfg_hword[i].val = (info[3] << 8) | (info[4]);
-#else
- g_cfg_hword[i].val = info[3] | (info[4] << 8);
-#endif
+ g_cfg_hword[i].val = cpu_to_le16(info[3] | (info[4] << 8));
break;
}
i++;
@@ -318,11 +312,7 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
break;
if (g_cfg_word[i].id == wid) {
-#ifdef BIG_ENDIAN
- g_cfg_word[i].val = (info[3] << 24) | (info[4] << 16) | (info[5] << 8) | (info[6]);
-#else
- g_cfg_word[i].val = info[3] | (info[4] << 8) | (info[5] << 16) | (info[6] << 24);
-#endif
+ g_cfg_word[i].val = cpu_to_le32(info[3] | (info[4] << 8) | (info[5] << 16) | (info[6] << 24));
break;
}
i++;
@@ -505,7 +495,8 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
return ret;
}
-int wilc_wlan_cfg_indicate_rx(u8 *frame, int size, wilc_cfg_rsp_t *rsp)
+int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
+ struct wilc_cfg_rsp *rsp)
{
int ret = 1;
u8 msg_type;
@@ -532,17 +523,17 @@ int wilc_wlan_cfg_indicate_rx(u8 *frame, int size, wilc_cfg_rsp_t *rsp)
rsp->seq_no = msg_id;
/*call host interface info parse as well*/
PRINT_INFO(RX_DBG, "Info message received\n");
- GnrlAsyncInfoReceived(frame - 4, size + 4);
+ wilc_gnrl_async_info_received(wilc, frame - 4, size + 4);
break;
case 'N':
- NetworkInfoReceived(frame - 4, size + 4);
+ wilc_network_info_received(wilc, frame - 4, size + 4);
rsp->type = 0;
break;
case 'S':
PRINT_INFO(RX_DBG, "Scan Notification Received\n");
- host_int_ScanCompleteReceived(frame - 4, size + 4);
+ wilc_scan_complete_received(wilc, frame - 4, size + 4);
break;
default:
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.h b/drivers/staging/wilc1000/wilc_wlan_cfg.h
index 30e60ec4d29f..5f74eb83562f 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.h
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.h
@@ -30,10 +30,12 @@ typedef struct {
u8 *str;
} wilc_cfg_str_t;
+struct wilc;
int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size);
int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id);
int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size);
-int wilc_wlan_cfg_indicate_rx(u8 *frame, int size, wilc_cfg_rsp_t *rsp);
+int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
+ struct wilc_cfg_rsp *rsp);
int wilc_wlan_cfg_init(wilc_debug_func func);
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h
index be972afe6e62..618903caff54 100644
--- a/drivers/staging/wilc1000/wilc_wlan_if.h
+++ b/drivers/staging/wilc1000/wilc_wlan_if.h
@@ -12,6 +12,7 @@
#include <linux/semaphore.h>
#include "linux_wlan_common.h"
+#include <linux/netdevice.h>
/********************************************
*
@@ -71,26 +72,6 @@ typedef struct {
u32 block_size;
} sdio_cmd53_t;
-typedef struct {
- int io_type;
- int (*io_init)(void *);
- void (*io_deinit)(void *);
- union {
- struct {
- int (*sdio_cmd52)(sdio_cmd52_t *);
- int (*sdio_cmd53)(sdio_cmd53_t *);
- int (*sdio_set_max_speed)(void);
- int (*sdio_set_default_speed)(void);
- } sdio;
- struct {
- int (*spi_max_speed)(void);
- int (*spi_tx)(u8 *, u32);
- int (*spi_rx)(u8 *, u32);
- int (*spi_trx)(u8 *, u8 *, u32);
- } spi;
- } u;
-} wilc_wlan_io_func_t;
-
#define WILC_MAC_INDICATE_STATUS 0x1
#define WILC_MAC_STATUS_INIT -1
#define WILC_MAC_STATUS_READY 0
@@ -98,15 +79,6 @@ typedef struct {
#define WILC_MAC_INDICATE_SCAN 0x2
-typedef struct {
- void *os_private;
-} wilc_wlan_os_context_t;
-
-typedef struct {
- wilc_wlan_os_context_t os_context;
- wilc_wlan_io_func_t io_func;
-} wilc_wlan_inp_t;
-
struct tx_complete_data {
int size;
void *buff;
@@ -315,7 +287,7 @@ typedef enum {
SW_TRIGGER_ABORT,
} TX_ABORT_OPTION_T;
-enum WID_TYPE {
+enum wid_type {
WID_CHAR = 0,
WID_SHORT = 1,
WID_INT = 2,
@@ -937,10 +909,10 @@ typedef enum {
WID_MAX = 0xFFFF
} WID_T;
-int wilc_wlan_init(wilc_wlan_inp_t *inp);
-
+struct wilc;
+int wilc_wlan_init(struct net_device *dev);
void wilc_bus_set_max_speed(void);
void wilc_bus_set_default_speed(void);
-u32 wilc_get_chipid(u8 update);
+u32 wilc_get_chipid(struct wilc *wilc, u8 update);
#endif
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 444ebed7313a..7551ac25d89d 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -177,9 +177,6 @@ static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb);
static void hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin);
-static void
-hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout);
-
static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin,
int urb_status);
@@ -3504,7 +3501,7 @@ static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb)
rxmeta->signal = usbin->rxfrm.desc.signal - hw->dbmadjust;
rxmeta->noise = usbin->rxfrm.desc.silence - hw->dbmadjust;
- prism2sta_ev_rx(wlandev, skb);
+ p80211netdev_rx(wlandev, skb);
break;
@@ -3628,7 +3625,7 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev,
}
/* pass it back up */
- prism2sta_ev_rx(wlandev, skb);
+ p80211netdev_rx(wlandev, skb);
}
/*----------------------------------------------------------------
@@ -3674,7 +3671,6 @@ static void hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin)
static void hfa384x_usbout_callback(struct urb *urb)
{
wlandevice_t *wlandev = urb->context;
- hfa384x_usbout_t *usbout = urb->transfer_buffer;
#ifdef DEBUG_USB
dbprint_urb(urb);
@@ -3683,7 +3679,7 @@ static void hfa384x_usbout_callback(struct urb *urb)
if (wlandev && wlandev->netdev) {
switch (urb->status) {
case 0:
- hfa384x_usbout_tx(wlandev, usbout);
+ prism2sta_ev_alloc(wlandev);
break;
case -EPIPE:
@@ -4038,30 +4034,6 @@ static int hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx)
}
/*----------------------------------------------------------------
-* hfa384x_usbout_tx
-*
-* At this point we have finished a send of a frame. Mark the URB
-* as available and call ev_alloc to notify higher layers we're
-* ready for more.
-*
-* Arguments:
-* wlandev wlan device
-* usbout ptr to the usb transfer buffer
-*
-* Returns:
-* nothing
-*
-* Side effects:
-*
-* Call context:
-* interrupt
-----------------------------------------------------------------*/
-static void hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout)
-{
- prism2sta_ev_alloc(wlandev);
-}
-
-/*----------------------------------------------------------------
* hfa384x_isgood_pdrcore
*
* Quick check of PDR codes.
diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h
index c547e1cb4c0d..810ee68aa18e 100644
--- a/drivers/staging/wlan-ng/p80211netdev.h
+++ b/drivers/staging/wlan-ng/p80211netdev.h
@@ -141,7 +141,6 @@ typedef struct p80211_frmrx_t {
struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev);
/* wireless extensions' ioctls */
extern struct iw_handler_def p80211wext_handler_def;
-int p80211wext_event_associated(struct wlandevice *wlandev, int assoc);
/* WEP stuff */
#define NUM_WEPKEYS 4
diff --git a/drivers/staging/wlan-ng/prism2mgmt.h b/drivers/staging/wlan-ng/prism2mgmt.h
index 16f123959104..7a9f424607b7 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.h
+++ b/drivers/staging/wlan-ng/prism2mgmt.h
@@ -68,7 +68,6 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate);
void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status);
void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status);
-void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb);
void prism2sta_ev_alloc(wlandevice_t *wlandev);
int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp);
diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c
index b4a15ef3a405..cdda07d1c268 100644
--- a/drivers/staging/wlan-ng/prism2mib.c
+++ b/drivers/staging/wlan-ng/prism2mib.c
@@ -660,7 +660,6 @@ static int prism2mib_fragmentationthreshold(struct mibrec *mib,
struct p80211msg_dot11req_mibset *msg,
void *data)
{
- int result;
u32 *uint32 = (u32 *) data;
if (!isget)
@@ -672,9 +671,7 @@ static int prism2mib_fragmentationthreshold(struct mibrec *mib,
return 0;
}
- result = prism2mib_uint32(mib, isget, wlandev, hw, msg, data);
-
- return result;
+ return prism2mib_uint32(mib, isget, wlandev, hw, msg, data);
}
/*----------------------------------------------------------------
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index c57f48a1d8df..131223afd918 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -1837,27 +1837,6 @@ void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status)
}
/*
- * prism2sta_ev_rx
- *
- * Handles the Rx event.
- *
- * Arguments:
- * wlandev wlan device structure
- *
- * Returns:
- * nothing
- *
- * Side effects:
- *
- * Call context:
- * interrupt
- */
-void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb)
-{
- p80211netdev_rx(wlandev, skb);
-}
-
-/*
* prism2sta_ev_alloc
*
* Handles the Alloc event.
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 72204fbf2bb1..576a7a43470c 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1333,7 +1333,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
/*
* Check if a delayed TASK_ABORTED status needs to
* be sent now if the ISCSI_FLAG_CMD_FINAL has been
- * received with the unsolicitied data out.
+ * received with the unsolicited data out.
*/
if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
iscsit_stop_dataout_timer(cmd);
@@ -3435,7 +3435,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
if ((tpg->tpg_attrib.generate_node_acls == 0) &&
(tpg->tpg_attrib.demo_mode_discovery == 0) &&
- (!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg,
+ (!target_tpg_has_node_acl(&tpg->tpg_se_tpg,
cmd->conn->sess->sess_ops->InitiatorName))) {
continue;
}
@@ -4459,9 +4459,6 @@ int iscsit_close_connection(
return 0;
}
- spin_unlock_bh(&sess->conn_lock);
-
- return 0;
}
int iscsit_close_session(struct iscsi_session *sess)
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 255204cc43e6..2f821de63049 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -725,11 +725,8 @@ static ssize_t lio_target_nacl_cmdsn_depth_store(struct config_item *item,
if (iscsit_get_tpg(tpg) < 0)
return -EINVAL;
- /*
- * iscsit_tpg_set_initiator_node_queue_depth() assumes force=1
- */
- ret = iscsit_tpg_set_initiator_node_queue_depth(tpg,
- config_item_name(acl_ci), cmdsn_depth, 1);
+
+ ret = core_tpg_set_initiator_node_queue_depth(se_nacl, cmdsn_depth);
pr_debug("LIO_Target_ConfigFS: %s/%s Set CmdSN Window: %u for"
"InitiatorName: %s\n", config_item_name(wwn_ci),
@@ -1593,28 +1590,30 @@ static int lio_tpg_check_prot_fabric_only(
}
/*
- * Called with spin_lock_bh(struct se_portal_group->session_lock) held..
- *
- * Also, this function calls iscsit_inc_session_usage_count() on the
+ * This function calls iscsit_inc_session_usage_count() on the
* struct iscsi_session in question.
*/
static int lio_tpg_shutdown_session(struct se_session *se_sess)
{
struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+ struct se_portal_group *se_tpg = &sess->tpg->tpg_se_tpg;
+ spin_lock_bh(&se_tpg->session_lock);
spin_lock(&sess->conn_lock);
if (atomic_read(&sess->session_fall_back_to_erl0) ||
atomic_read(&sess->session_logout) ||
(sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
spin_unlock(&sess->conn_lock);
+ spin_unlock_bh(&se_tpg->session_lock);
return 0;
}
atomic_set(&sess->session_reinstatement, 1);
spin_unlock(&sess->conn_lock);
iscsit_stop_time2retain_timer(sess);
- iscsit_stop_session(sess, 1, 1);
+ spin_unlock_bh(&se_tpg->session_lock);
+ iscsit_stop_session(sess, 1, 1);
return 1;
}
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 2e561deb30a2..9214c9dafa2b 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -160,8 +160,7 @@ static int iscsit_handle_r2t_snack(
" protocol error.\n", cmd->init_task_tag, begrun,
(begrun + runlength), cmd->acked_data_sn);
- return iscsit_reject_cmd(cmd,
- ISCSI_REASON_PROTOCOL_ERROR, buf);
+ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if (runlength) {
@@ -628,8 +627,8 @@ int iscsit_dataout_datapduinorder_no_fbit(
if (cmd->pdu_list[i].seq_no == pdu->seq_no) {
if (!first_pdu)
first_pdu = &cmd->pdu_list[i];
- xfer_len += cmd->pdu_list[i].length;
- pdu_count++;
+ xfer_len += cmd->pdu_list[i].length;
+ pdu_count++;
} else if (pdu_count)
break;
}
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 2cbea2af7cd0..3a1f9a7e6bb6 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -1668,7 +1668,7 @@ void iscsi_set_session_parameters(
param->value);
} else if (!strcmp(param->name, INITIALR2T)) {
ops->InitialR2T = !strcmp(param->value, YES);
- pr_debug("InitialR2T: %s\n",
+ pr_debug("InitialR2T: %s\n",
param->value);
} else if (!strcmp(param->name, IMMEDIATEDATA)) {
ops->ImmediateData = !strcmp(param->value, YES);
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index 11320df939f7..3d637055c36f 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -82,7 +82,7 @@ int iscsit_tmr_task_warm_reset(
pr_err("TMR Opcode TARGET_WARM_RESET authorization"
" failed for Initiator Node: %s\n",
sess->se_sess->se_node_acl->initiatorname);
- return -1;
+ return -1;
}
/*
* Do the real work in transport_generic_do_tmr().
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index 23c95cd14167..0814e5894a96 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -590,16 +590,6 @@ int iscsit_tpg_del_network_portal(
return iscsit_tpg_release_np(tpg_np, tpg, np);
}
-int iscsit_tpg_set_initiator_node_queue_depth(
- struct iscsi_portal_group *tpg,
- unsigned char *initiatorname,
- u32 queue_depth,
- int force)
-{
- return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg,
- initiatorname, queue_depth, force);
-}
-
int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication)
{
unsigned char buf1[256], buf2[256], *none = NULL;
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h
index 9db32bd24cd4..2da211920c18 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.h
+++ b/drivers/target/iscsi/iscsi_target_tpg.h
@@ -26,8 +26,6 @@ extern struct iscsi_tpg_np *iscsit_tpg_add_network_portal(struct iscsi_portal_gr
int);
extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *,
struct iscsi_tpg_np *);
-extern int iscsit_tpg_set_initiator_node_queue_depth(struct iscsi_portal_group *,
- unsigned char *, u32, int);
extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32);
extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32);
extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 4fb0eca86857..d41a5c300e31 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -1036,12 +1036,26 @@ static ssize_t tcm_loop_tpg_transport_status_store(struct config_item *item,
return -EINVAL;
}
+static ssize_t tcm_loop_tpg_address_show(struct config_item *item,
+ char *page)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
+ struct tcm_loop_tpg, tl_se_tpg);
+ struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
+
+ return snprintf(page, PAGE_SIZE, "%d:0:%d\n",
+ tl_hba->sh->host_no, tl_tpg->tl_tpgt);
+}
+
CONFIGFS_ATTR(tcm_loop_tpg_, nexus);
CONFIGFS_ATTR(tcm_loop_tpg_, transport_status);
+CONFIGFS_ATTR_RO(tcm_loop_tpg_, address);
static struct configfs_attribute *tcm_loop_tpg_attrs[] = {
&tcm_loop_tpg_attr_nexus,
&tcm_loop_tpg_attr_transport_status,
+ &tcm_loop_tpg_attr_address,
NULL,
};
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 35f7d31b29d2..3072f1aca8ec 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -39,8 +39,6 @@
#include "sbp_target.h"
-static const struct target_core_fabric_ops sbp_ops;
-
/* FireWire address region for management and command block address handlers */
static const struct fw_address_region sbp_register_region = {
.start = CSR_REGISTER_BASE + 0x10000,
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index b9b9ffde4c7a..3327c49674d3 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -278,7 +278,7 @@ EXPORT_SYMBOL(target_depend_item);
void target_undepend_item(struct config_item *item)
{
- return configfs_undepend_item(&target_core_fabrics, item);
+ return configfs_undepend_item(item);
}
EXPORT_SYMBOL(target_undepend_item);
@@ -499,6 +499,7 @@ DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_lba_count);
DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_block_desc_count);
DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity);
DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity_alignment);
+DEF_CONFIGFS_ATTRIB_SHOW(unmap_zeroes_data);
DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len);
#define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \
@@ -548,7 +549,8 @@ static ssize_t _name##_store(struct config_item *item, const char *page,\
size_t count) \
{ \
printk_once(KERN_WARNING \
- "ignoring deprecated ##_name## attribute\n"); \
+ "ignoring deprecated %s attribute\n", \
+ __stringify(_name)); \
return count; \
}
@@ -866,6 +868,39 @@ static ssize_t emulate_rest_reord_store(struct config_item *item,
return count;
}
+static ssize_t unmap_zeroes_data_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_dev_attrib *da = to_attrib(item);
+ bool flag;
+ int ret;
+
+ ret = strtobool(page, &flag);
+ if (ret < 0)
+ return ret;
+
+ if (da->da_dev->export_count) {
+ pr_err("dev[%p]: Unable to change SE Device"
+ " unmap_zeroes_data while export_count is %d\n",
+ da->da_dev, da->da_dev->export_count);
+ return -EINVAL;
+ }
+ /*
+ * We expect this value to be non-zero when generic Block Layer
+ * Discard supported is detected iblock_configure_device().
+ */
+ if (flag && !da->max_unmap_block_desc_count) {
+ pr_err("dev[%p]: Thin Provisioning LBPRZ will not be set"
+ " because max_unmap_block_desc_count is zero\n",
+ da->da_dev);
+ return -ENOSYS;
+ }
+ da->unmap_zeroes_data = flag;
+ pr_debug("dev[%p]: SE Device Thin Provisioning LBPRZ bit: %d\n",
+ da->da_dev, flag);
+ return 0;
+}
+
/*
* Note, this can only be called on unexported SE Device Object.
*/
@@ -998,6 +1033,7 @@ CONFIGFS_ATTR(, max_unmap_lba_count);
CONFIGFS_ATTR(, max_unmap_block_desc_count);
CONFIGFS_ATTR(, unmap_granularity);
CONFIGFS_ATTR(, unmap_granularity_alignment);
+CONFIGFS_ATTR(, unmap_zeroes_data);
CONFIGFS_ATTR(, max_write_same_len);
/*
@@ -1034,6 +1070,7 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
&attr_max_unmap_block_desc_count,
&attr_unmap_granularity,
&attr_unmap_granularity_alignment,
+ &attr_unmap_zeroes_data,
&attr_max_write_same_len,
NULL,
};
@@ -1980,14 +2017,14 @@ static ssize_t target_dev_lba_map_store(struct config_item *item,
struct se_device *dev = to_device(item);
struct t10_alua_lba_map *lba_map = NULL;
struct list_head lba_list;
- char *map_entries, *ptr;
+ char *map_entries, *orig, *ptr;
char state;
int pg_num = -1, pg;
int ret = 0, num = 0, pg_id, alua_state;
unsigned long start_lba = -1, end_lba = -1;
unsigned long segment_size = -1, segment_mult = -1;
- map_entries = kstrdup(page, GFP_KERNEL);
+ orig = map_entries = kstrdup(page, GFP_KERNEL);
if (!map_entries)
return -ENOMEM;
@@ -2085,7 +2122,7 @@ out:
} else
core_alua_set_lba_map(dev, &lba_list,
segment_size, segment_mult);
- kfree(map_entries);
+ kfree(orig);
return count;
}
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 88ea4e4f124b..cacd97a8cbd0 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -813,6 +813,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT;
dev->dev_attrib.unmap_granularity_alignment =
DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
+ dev->dev_attrib.unmap_zeroes_data =
+ DA_UNMAP_ZEROES_DATA_DEFAULT;
dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
xcopy_lun = &dev->xcopy_lun;
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index f29c69120054..e77d15000caa 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -138,6 +138,8 @@ static int iblock_configure_device(struct se_device *dev)
q->limits.discard_granularity >> 9;
dev->dev_attrib.unmap_granularity_alignment =
q->limits.discard_alignment;
+ dev->dev_attrib.unmap_zeroes_data =
+ q->limits.discard_zeroes_data;
pr_debug("IBLOCK: BLOCK Discard support available,"
" disabled by default\n");
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index e7933115087a..b1795735eafc 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -1457,8 +1457,7 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl)
static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
{
struct se_lun_acl *lun_acl;
- struct se_node_acl *nacl;
- struct se_portal_group *tpg;
+
/*
* For nacl->dynamic_node_acl=1
*/
@@ -1467,17 +1466,13 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
if (!lun_acl)
return 0;
- nacl = lun_acl->se_lun_nacl;
- tpg = nacl->se_tpg;
-
return target_depend_item(&lun_acl->se_lun_group.cg_item);
}
static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
{
struct se_lun_acl *lun_acl;
- struct se_node_acl *nacl;
- struct se_portal_group *tpg;
+
/*
* For nacl->dynamic_node_acl=1
*/
@@ -1487,8 +1482,6 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
kref_put(&se_deve->pr_kref, target_pr_kref_release);
return;
}
- nacl = lun_acl->se_lun_nacl;
- tpg = nacl->se_tpg;
target_undepend_item(&lun_acl->se_lun_group.cg_item);
kref_put(&se_deve->pr_kref, target_pr_kref_release);
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 98698d875742..a9057aa07176 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -141,9 +141,17 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
* Set Thin Provisioning Enable bit following sbc3r22 in section
* READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
*/
- if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws)
+ if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws) {
buf[14] |= 0x80;
+ /*
+ * LBPRZ signifies that zeroes will be read back from an LBA after
+ * an UNMAP or WRITE SAME w/ unmap bit (sbc3r36 5.16.2)
+ */
+ if (dev->dev_attrib.unmap_zeroes_data)
+ buf[14] |= 0x40;
+ }
+
rbuf = transport_kmap_data_sg(cmd);
if (rbuf) {
memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 9413e1a949e5..0aa47babd16c 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -635,6 +635,18 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
if (dev->dev_attrib.emulate_tpws != 0)
buf[5] |= 0x40 | 0x20;
+ /*
+ * The unmap_zeroes_data set means that the underlying device supports
+ * REQ_DISCARD and has the discard_zeroes_data bit set. This satisfies
+ * the SBC requirements for LBPRZ, meaning that a subsequent read
+ * will return zeroes after an UNMAP or WRITE SAME (16) to an LBA
+ * See sbc4r36 6.6.4.
+ */
+ if (((dev->dev_attrib.emulate_tpu != 0) ||
+ (dev->dev_attrib.emulate_tpws != 0)) &&
+ (dev->dev_attrib.unmap_zeroes_data != 0))
+ buf[5] |= 0x04;
+
return 0;
}
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 28fb3016370f..fcdcb117c60d 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -201,7 +201,7 @@ static void core_tmr_drain_tmr_list(
/*
* If this function was called with a valid pr_res_key
* parameter (eg: for PROUT PREEMPT_AND_ABORT service action
- * skip non regisration key matching TMRs.
+ * skip non registration key matching TMRs.
*/
if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
continue;
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 5fb9dd7f08bb..3608b1b5ecf7 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -75,9 +75,21 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(
unsigned char *initiatorname)
{
struct se_node_acl *acl;
-
+ /*
+ * Obtain se_node_acl->acl_kref using fabric driver provided
+ * initiatorname[] during node acl endpoint lookup driven by
+ * new se_session login.
+ *
+ * The reference is held until se_session shutdown -> release
+ * occurs via fabric driver invoked transport_deregister_session()
+ * or transport_free_session() code.
+ */
mutex_lock(&tpg->acl_node_mutex);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if (acl) {
+ if (!kref_get_unless_zero(&acl->acl_kref))
+ acl = NULL;
+ }
mutex_unlock(&tpg->acl_node_mutex);
return acl;
@@ -157,28 +169,25 @@ void core_tpg_add_node_to_devs(
mutex_unlock(&tpg->tpg_lun_mutex);
}
-/* core_set_queue_depth_for_node():
- *
- *
- */
-static int core_set_queue_depth_for_node(
- struct se_portal_group *tpg,
- struct se_node_acl *acl)
+static void
+target_set_nacl_queue_depth(struct se_portal_group *tpg,
+ struct se_node_acl *acl, u32 queue_depth)
{
+ acl->queue_depth = queue_depth;
+
if (!acl->queue_depth) {
- pr_err("Queue depth for %s Initiator Node: %s is 0,"
+ pr_warn("Queue depth for %s Initiator Node: %s is 0,"
"defaulting to 1.\n", tpg->se_tpg_tfo->get_fabric_name(),
acl->initiatorname);
acl->queue_depth = 1;
}
-
- return 0;
}
static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg,
const unsigned char *initiatorname)
{
struct se_node_acl *acl;
+ u32 queue_depth;
acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size),
GFP_KERNEL);
@@ -193,24 +202,20 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg,
spin_lock_init(&acl->nacl_sess_lock);
mutex_init(&acl->lun_entry_mutex);
atomic_set(&acl->acl_pr_ref_count, 0);
+
if (tpg->se_tpg_tfo->tpg_get_default_depth)
- acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);
+ queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);
else
- acl->queue_depth = 1;
+ queue_depth = 1;
+ target_set_nacl_queue_depth(tpg, acl, queue_depth);
+
snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
acl->se_tpg = tpg;
acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
tpg->se_tpg_tfo->set_default_node_attributes(acl);
- if (core_set_queue_depth_for_node(tpg, acl) < 0)
- goto out_free_acl;
-
return acl;
-
-out_free_acl:
- kfree(acl);
- return NULL;
}
static void target_add_node_acl(struct se_node_acl *acl)
@@ -219,7 +224,6 @@ static void target_add_node_acl(struct se_node_acl *acl)
mutex_lock(&tpg->acl_node_mutex);
list_add_tail(&acl->acl_list, &tpg->acl_node_list);
- tpg->num_node_acls++;
mutex_unlock(&tpg->acl_node_mutex);
pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s"
@@ -232,6 +236,25 @@ static void target_add_node_acl(struct se_node_acl *acl)
acl->initiatorname);
}
+bool target_tpg_has_node_acl(struct se_portal_group *tpg,
+ const char *initiatorname)
+{
+ struct se_node_acl *acl;
+ bool found = false;
+
+ mutex_lock(&tpg->acl_node_mutex);
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (!strcmp(acl->initiatorname, initiatorname)) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&tpg->acl_node_mutex);
+
+ return found;
+}
+EXPORT_SYMBOL(target_tpg_has_node_acl);
+
struct se_node_acl *core_tpg_check_initiator_node_acl(
struct se_portal_group *tpg,
unsigned char *initiatorname)
@@ -248,6 +271,15 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
acl = target_alloc_node_acl(tpg, initiatorname);
if (!acl)
return NULL;
+ /*
+ * When allocating a dynamically generated node_acl, go ahead
+ * and take the extra kref now before returning to the fabric
+ * driver caller.
+ *
+ * Note this reference will be released at session shutdown
+ * time within transport_free_session() code.
+ */
+ kref_get(&acl->acl_kref);
acl->dynamic_node_acl = 1;
/*
@@ -318,7 +350,6 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)
acl->dynamic_node_acl = 0;
}
list_del(&acl->acl_list);
- tpg->num_node_acls--;
mutex_unlock(&tpg->acl_node_mutex);
spin_lock_irqsave(&acl->nacl_sess_lock, flags);
@@ -329,7 +360,8 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)
if (sess->sess_tearing_down != 0)
continue;
- target_get_session(sess);
+ if (!target_get_session(sess))
+ continue;
list_move(&sess->sess_acl_list, &sess_list);
}
spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
@@ -366,108 +398,52 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)
*
*/
int core_tpg_set_initiator_node_queue_depth(
- struct se_portal_group *tpg,
- unsigned char *initiatorname,
- u32 queue_depth,
- int force)
+ struct se_node_acl *acl,
+ u32 queue_depth)
{
- struct se_session *sess, *init_sess = NULL;
- struct se_node_acl *acl;
+ LIST_HEAD(sess_list);
+ struct se_portal_group *tpg = acl->se_tpg;
+ struct se_session *sess, *sess_tmp;
unsigned long flags;
- int dynamic_acl = 0;
-
- mutex_lock(&tpg->acl_node_mutex);
- acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
- if (!acl) {
- pr_err("Access Control List entry for %s Initiator"
- " Node %s does not exists for TPG %hu, ignoring"
- " request.\n", tpg->se_tpg_tfo->get_fabric_name(),
- initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
- mutex_unlock(&tpg->acl_node_mutex);
- return -ENODEV;
- }
- if (acl->dynamic_node_acl) {
- acl->dynamic_node_acl = 0;
- dynamic_acl = 1;
- }
- mutex_unlock(&tpg->acl_node_mutex);
-
- spin_lock_irqsave(&tpg->session_lock, flags);
- list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
- if (sess->se_node_acl != acl)
- continue;
-
- if (!force) {
- pr_err("Unable to change queue depth for %s"
- " Initiator Node: %s while session is"
- " operational. To forcefully change the queue"
- " depth and force session reinstatement"
- " use the \"force=1\" parameter.\n",
- tpg->se_tpg_tfo->get_fabric_name(), initiatorname);
- spin_unlock_irqrestore(&tpg->session_lock, flags);
-
- mutex_lock(&tpg->acl_node_mutex);
- if (dynamic_acl)
- acl->dynamic_node_acl = 1;
- mutex_unlock(&tpg->acl_node_mutex);
- return -EEXIST;
- }
- /*
- * Determine if the session needs to be closed by our context.
- */
- if (!tpg->se_tpg_tfo->shutdown_session(sess))
- continue;
-
- init_sess = sess;
- break;
- }
+ int rc;
/*
* User has requested to change the queue depth for a Initiator Node.
* Change the value in the Node's struct se_node_acl, and call
- * core_set_queue_depth_for_node() to add the requested queue depth.
- *
- * Finally call tpg->se_tpg_tfo->close_session() to force session
- * reinstatement to occur if there is an active session for the
- * $FABRIC_MOD Initiator Node in question.
+ * target_set_nacl_queue_depth() to set the new queue depth.
*/
- acl->queue_depth = queue_depth;
+ target_set_nacl_queue_depth(tpg, acl, queue_depth);
+
+ spin_lock_irqsave(&acl->nacl_sess_lock, flags);
+ list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list,
+ sess_acl_list) {
+ if (sess->sess_tearing_down != 0)
+ continue;
+ if (!target_get_session(sess))
+ continue;
+ spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
- if (core_set_queue_depth_for_node(tpg, acl) < 0) {
- spin_unlock_irqrestore(&tpg->session_lock, flags);
/*
- * Force session reinstatement if
- * core_set_queue_depth_for_node() failed, because we assume
- * the $FABRIC_MOD has already the set session reinstatement
- * bit from tpg->se_tpg_tfo->shutdown_session() called above.
+ * Finally call tpg->se_tpg_tfo->close_session() to force session
+ * reinstatement to occur if there is an active session for the
+ * $FABRIC_MOD Initiator Node in question.
*/
- if (init_sess)
- tpg->se_tpg_tfo->close_session(init_sess);
-
- mutex_lock(&tpg->acl_node_mutex);
- if (dynamic_acl)
- acl->dynamic_node_acl = 1;
- mutex_unlock(&tpg->acl_node_mutex);
- return -EINVAL;
+ rc = tpg->se_tpg_tfo->shutdown_session(sess);
+ target_put_session(sess);
+ if (!rc) {
+ spin_lock_irqsave(&acl->nacl_sess_lock, flags);
+ continue;
+ }
+ target_put_session(sess);
+ spin_lock_irqsave(&acl->nacl_sess_lock, flags);
}
- spin_unlock_irqrestore(&tpg->session_lock, flags);
- /*
- * If the $FABRIC_MOD session for the Initiator Node ACL exists,
- * forcefully shutdown the $FABRIC_MOD session/nexus.
- */
- if (init_sess)
- tpg->se_tpg_tfo->close_session(init_sess);
+ spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
pr_debug("Successfully changed queue depth to: %d for Initiator"
- " Node: %s on %s Target Portal Group: %u\n", queue_depth,
- initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
+ " Node: %s on %s Target Portal Group: %u\n", acl->queue_depth,
+ acl->initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg));
- mutex_lock(&tpg->acl_node_mutex);
- if (dynamic_acl)
- acl->dynamic_node_acl = 1;
- mutex_unlock(&tpg->acl_node_mutex);
-
return 0;
}
EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth);
@@ -595,7 +571,6 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
*/
list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) {
list_del(&nacl->acl_list);
- se_tpg->num_node_acls--;
core_tpg_wait_for_nacl_pr_ref(nacl);
core_free_device_list_for_node(nacl, se_tpg);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4fdcee2006d1..9f3608e10f25 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -341,7 +341,6 @@ void __transport_register_session(
&buf[0], PR_REG_ISID_LEN);
se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
}
- kref_get(&se_nacl->acl_kref);
spin_lock_irq(&se_nacl->nacl_sess_lock);
/*
@@ -384,9 +383,9 @@ static void target_release_session(struct kref *kref)
se_tpg->se_tpg_tfo->close_session(se_sess);
}
-void target_get_session(struct se_session *se_sess)
+int target_get_session(struct se_session *se_sess)
{
- kref_get(&se_sess->sess_kref);
+ return kref_get_unless_zero(&se_sess->sess_kref);
}
EXPORT_SYMBOL(target_get_session);
@@ -432,6 +431,7 @@ void target_put_nacl(struct se_node_acl *nacl)
{
kref_put(&nacl->acl_kref, target_complete_nacl);
}
+EXPORT_SYMBOL(target_put_nacl);
void transport_deregister_session_configfs(struct se_session *se_sess)
{
@@ -464,6 +464,15 @@ EXPORT_SYMBOL(transport_deregister_session_configfs);
void transport_free_session(struct se_session *se_sess)
{
+ struct se_node_acl *se_nacl = se_sess->se_node_acl;
+ /*
+ * Drop the se_node_acl->nacl_kref obtained from within
+ * core_tpg_get_initiator_node_acl().
+ */
+ if (se_nacl) {
+ se_sess->se_node_acl = NULL;
+ target_put_nacl(se_nacl);
+ }
if (se_sess->sess_cmd_map) {
percpu_ida_destroy(&se_sess->sess_tag_pool);
kvfree(se_sess->sess_cmd_map);
@@ -478,7 +487,7 @@ void transport_deregister_session(struct se_session *se_sess)
const struct target_core_fabric_ops *se_tfo;
struct se_node_acl *se_nacl;
unsigned long flags;
- bool comp_nacl = true, drop_nacl = false;
+ bool drop_nacl = false;
if (!se_tpg) {
transport_free_session(se_sess);
@@ -502,7 +511,6 @@ void transport_deregister_session(struct se_session *se_sess)
if (se_nacl && se_nacl->dynamic_node_acl) {
if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
list_del(&se_nacl->acl_list);
- se_tpg->num_node_acls--;
drop_nacl = true;
}
}
@@ -511,18 +519,16 @@ void transport_deregister_session(struct se_session *se_sess)
if (drop_nacl) {
core_tpg_wait_for_nacl_pr_ref(se_nacl);
core_free_device_list_for_node(se_nacl, se_tpg);
+ se_sess->se_node_acl = NULL;
kfree(se_nacl);
- comp_nacl = false;
}
pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
se_tpg->se_tpg_tfo->get_fabric_name());
/*
* If last kref is dropping now for an explicit NodeACL, awake sleeping
* ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
- * removal context.
+ * removal context from within transport_free_session() code.
*/
- if (se_nacl && comp_nacl)
- target_put_nacl(se_nacl);
transport_free_session(se_sess);
}
@@ -715,7 +721,10 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- queue_work(target_completion_wq, &cmd->work);
+ if (cmd->cpuid == -1)
+ queue_work(target_completion_wq, &cmd->work);
+ else
+ queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
}
EXPORT_SYMBOL(target_complete_cmd);
@@ -1309,7 +1318,7 @@ EXPORT_SYMBOL(target_setup_cmd_from_cdb);
/*
* Used by fabric module frontends to queue tasks directly.
- * Many only be used from process context only
+ * May only be used from process context.
*/
int transport_handle_cdb_direct(
struct se_cmd *cmd)
@@ -1582,7 +1591,7 @@ static void target_complete_tmr_failure(struct work_struct *work)
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
unsigned char *sense, u64 unpacked_lun,
void *fabric_tmr_ptr, unsigned char tm_type,
- gfp_t gfp, unsigned int tag, int flags)
+ gfp_t gfp, u64 tag, int flags)
{
struct se_portal_group *se_tpg;
int ret;
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 5e6d6cb348fc..dd600e5ead71 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -152,6 +152,7 @@ static struct genl_family tcmu_genl_family = {
.maxattr = TCMU_ATTR_MAX,
.mcgrps = tcmu_mcgrps,
.n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),
+ .netnsok = true,
};
static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
@@ -194,7 +195,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
static inline void tcmu_flush_dcache_range(void *vaddr, size_t size)
{
- unsigned long offset = (unsigned long) vaddr & ~PAGE_MASK;
+ unsigned long offset = offset_in_page(vaddr);
size = round_up(size+offset, PAGE_SIZE);
vaddr -= offset;
@@ -840,7 +841,7 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int mino
genlmsg_end(skb, msg_header);
- ret = genlmsg_multicast(&tcmu_genl_family, skb, 0,
+ ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0,
TCMU_MCGRP_CONFIG, GFP_KERNEL);
/* We don't care if no one is listening */
@@ -917,8 +918,10 @@ static int tcmu_configure_device(struct se_device *dev)
if (ret)
goto err_register;
+ /* User can set hw_block_size before enable the device */
+ if (dev->dev_attrib.hw_block_size == 0)
+ dev->dev_attrib.hw_block_size = 512;
/* Other attributes can be configured in userspace */
- dev->dev_attrib.hw_block_size = 512;
dev->dev_attrib.hw_max_sectors = 128;
dev->dev_attrib.hw_queue_depth = 128;
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index 39909dadef3e..c30003bd4ff0 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -166,7 +166,6 @@ void ft_aborted_task(struct se_cmd *);
*/
void ft_recv_req(struct ft_sess *, struct fc_frame *);
struct ft_tpg *ft_lport_find_tpg(struct fc_lport *);
-struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *);
void ft_recv_write_data(struct ft_cmd *, struct fc_frame *);
void ft_dump_cmd(struct ft_cmd *, const char *caller);
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 85aeaa0ad303..4d375e95841b 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -171,9 +171,31 @@ static ssize_t ft_nacl_node_name_store(struct config_item *item,
CONFIGFS_ATTR(ft_nacl_, node_name);
CONFIGFS_ATTR(ft_nacl_, port_name);
+static ssize_t ft_nacl_tag_show(struct config_item *item,
+ char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%s", acl_to_nacl(item)->acl_tag);
+}
+
+static ssize_t ft_nacl_tag_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
+ int ret;
+
+ ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page);
+
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+CONFIGFS_ATTR(ft_nacl_, tag);
+
static struct configfs_attribute *ft_nacl_base_attrs[] = {
&ft_nacl_attr_port_name,
&ft_nacl_attr_node_name,
+ &ft_nacl_attr_tag,
NULL,
};
@@ -198,31 +220,6 @@ static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name)
return 0;
}
-struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
-{
- struct ft_node_acl *found = NULL;
- struct ft_node_acl *acl;
- struct se_portal_group *se_tpg = &tpg->se_tpg;
- struct se_node_acl *se_acl;
-
- mutex_lock(&se_tpg->acl_node_mutex);
- list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) {
- acl = container_of(se_acl, struct ft_node_acl, se_node_acl);
- pr_debug("acl %p port_name %llx\n",
- acl, (unsigned long long)acl->node_auth.port_name);
- if (acl->node_auth.port_name == rdata->ids.port_name ||
- acl->node_auth.node_name == rdata->ids.node_name) {
- pr_debug("acl %p port_name %llx matched\n", acl,
- (unsigned long long)rdata->ids.port_name);
- found = acl;
- /* XXX need to hold onto ACL */
- break;
- }
- }
- mutex_unlock(&se_tpg->acl_node_mutex);
- return found;
-}
-
/*
* local_port port_group (tpg) ops.
*/
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index 847c1aa6fbf4..6f7c65abfe2a 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -154,9 +154,9 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
BUG_ON(!page);
from = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
page_addr = from;
- from += mem_off & ~PAGE_MASK;
+ from += offset_in_page(mem_off);
tlen = min(tlen, (size_t)(PAGE_SIZE -
- (mem_off & ~PAGE_MASK)));
+ offset_in_page(mem_off)));
memcpy(to, from, tlen);
kunmap_atomic(page_addr);
to += tlen;
@@ -314,9 +314,9 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
to = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
page_addr = to;
- to += mem_off & ~PAGE_MASK;
+ to += offset_in_page(mem_off);
tlen = min(tlen, (size_t)(PAGE_SIZE -
- (mem_off & ~PAGE_MASK)));
+ offset_in_page(mem_off)));
memcpy(to, from, tlen);
kunmap_atomic(page_addr);
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index 7b934eac995d..e19f4c58c6fa 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -191,10 +191,15 @@ out:
* Caller holds ft_lport_lock.
*/
static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
- struct ft_node_acl *acl)
+ struct fc_rport_priv *rdata)
{
+ struct se_portal_group *se_tpg = &tport->tpg->se_tpg;
+ struct se_node_acl *se_acl;
struct ft_sess *sess;
struct hlist_head *head;
+ unsigned char initiatorname[TRANSPORT_IQN_LEN];
+
+ ft_format_wwn(&initiatorname[0], TRANSPORT_IQN_LEN, rdata->ids.port_name);
head = &tport->hash[ft_sess_hash(port_id)];
hlist_for_each_entry_rcu(sess, head, hash)
@@ -212,7 +217,14 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
kfree(sess);
return NULL;
}
- sess->se_sess->se_node_acl = &acl->se_node_acl;
+
+ se_acl = core_tpg_get_initiator_node_acl(se_tpg, &initiatorname[0]);
+ if (!se_acl) {
+ transport_free_session(sess->se_sess);
+ kfree(sess);
+ return NULL;
+ }
+ sess->se_sess->se_node_acl = se_acl;
sess->tport = tport;
sess->port_id = port_id;
kref_init(&sess->kref); /* ref for table entry */
@@ -221,7 +233,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
pr_debug("port_id %x sess %p\n", port_id, sess);
- transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl,
+ transport_register_session(&tport->tpg->se_tpg, se_acl,
sess->se_sess, sess);
return sess;
}
@@ -260,6 +272,14 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
return NULL;
}
+static void ft_close_sess(struct ft_sess *sess)
+{
+ transport_deregister_session_configfs(sess->se_sess);
+ target_sess_cmd_list_set_waiting(sess->se_sess);
+ target_wait_for_sess_cmds(sess->se_sess);
+ ft_sess_put(sess);
+}
+
/*
* Delete all sessions from tport.
* Caller holds ft_lport_lock.
@@ -273,8 +293,7 @@ static void ft_sess_delete_all(struct ft_tport *tport)
head < &tport->hash[FT_SESS_HASH_SIZE]; head++) {
hlist_for_each_entry_rcu(sess, head, hash) {
ft_sess_unhash(sess);
- transport_deregister_session_configfs(sess->se_sess);
- ft_sess_put(sess); /* release from table */
+ ft_close_sess(sess); /* release from table */
}
}
}
@@ -313,8 +332,7 @@ void ft_sess_close(struct se_session *se_sess)
pr_debug("port_id %x\n", port_id);
ft_sess_unhash(sess);
mutex_unlock(&ft_lport_lock);
- transport_deregister_session_configfs(se_sess);
- ft_sess_put(sess);
+ ft_close_sess(sess);
/* XXX Send LOGO or PRLO */
synchronize_rcu(); /* let transport deregister happen */
}
@@ -343,17 +361,12 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
{
struct ft_tport *tport;
struct ft_sess *sess;
- struct ft_node_acl *acl;
u32 fcp_parm;
tport = ft_tport_get(rdata->local_port);
if (!tport)
goto not_target; /* not a target for this local port */
- acl = ft_acl_get(tport->tpg, rdata);
- if (!acl)
- goto not_target; /* no target for this remote */
-
if (!rspp)
goto fill;
@@ -375,7 +388,7 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
spp->spp_flags |= FC_SPP_EST_IMG_PAIR;
if (!(fcp_parm & FCP_SPPF_INIT_FCN))
return FC_SPP_RESP_CONF;
- sess = ft_sess_create(tport, rdata->ids.port_id, acl);
+ sess = ft_sess_create(tport, rdata->ids.port_id, rdata);
if (!sess)
return FC_SPP_RESP_RES;
if (!sess->params)
@@ -460,8 +473,7 @@ static void ft_prlo(struct fc_rport_priv *rdata)
return;
}
mutex_unlock(&ft_lport_lock);
- transport_deregister_session_configfs(sess->se_sess);
- ft_sess_put(sess); /* release from table */
+ ft_close_sess(sess); /* release from table */
rdata->prli_count--;
/* XXX TBD - clearing actions. unit attn, see 4.10 */
}
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index e53d9a512c6d..2caaf5a2516d 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#undef SERIAL_PARANOIA_CHECK
-#define SERIAL_DO_RESTART
/* Set of debugging defines */
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index d4a1331675ed..abbed201dc74 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -292,14 +292,14 @@ static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
#endif /* CONFIG_CYZ_INTR */
-static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
+static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
{
struct cyclades_card *card = port->card;
cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
}
-static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
+static u8 cyy_readb(struct cyclades_port *port, u32 reg)
{
struct cyclades_card *card = port->card;
@@ -321,7 +321,7 @@ static inline bool cyz_fpga_loaded(struct cyclades_card *card)
return __cyz_fpga_loaded(card->ctl_addr.p9060);
}
-static inline bool cyz_is_loaded(struct cyclades_card *card)
+static bool cyz_is_loaded(struct cyclades_card *card)
{
struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
@@ -329,7 +329,7 @@ static inline bool cyz_is_loaded(struct cyclades_card *card)
readl(&fw_id->signature) == ZFIRM_ID;
}
-static inline int serial_paranoia_check(struct cyclades_port *info,
+static int serial_paranoia_check(struct cyclades_port *info,
const char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 2054427992e0..99875949bfb7 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -220,7 +220,7 @@ static struct isi_port isi_ports[PORT_COUNT];
* it wants to talk.
*/
-static inline int WaitTillCardIsFree(unsigned long base)
+static int WaitTillCardIsFree(unsigned long base)
{
unsigned int count = 0;
unsigned int a = in_atomic(); /* do we run under spinlock? */
@@ -280,7 +280,7 @@ static void raise_dtr(struct isi_port *port)
}
/* card->lock HAS to be held */
-static inline void drop_dtr(struct isi_port *port)
+static void drop_dtr(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 14c54e041065..92982d7c0489 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -155,7 +155,6 @@ struct mon_str {
#define LOWWAIT 2
#define EMPTYWAIT 3
-#define SERIAL_DO_RESTART
#define WAKEUP_CHARS 256
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index e49c2bce551d..d9a5fc28fef4 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -162,12 +162,23 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
return put_user(x, ptr);
}
-static inline int tty_copy_to_user(struct tty_struct *tty,
- void __user *to,
- const void *from,
- unsigned long n)
+static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
+ size_t tail, size_t n)
{
struct n_tty_data *ldata = tty->disc_data;
+ size_t size = N_TTY_BUF_SIZE - tail;
+ const void *from = read_buf_addr(ldata, tail);
+ int uncopied;
+
+ if (n > size) {
+ tty_audit_add_data(tty, from, size, ldata->icanon);
+ uncopied = copy_to_user(to, from, size);
+ if (uncopied)
+ return uncopied;
+ to += size;
+ n -= size;
+ from = ldata->read_buf;
+ }
tty_audit_add_data(tty, from, n, ldata->icanon);
return copy_to_user(to, from, n);
@@ -1201,9 +1212,7 @@ static void n_tty_receive_overrun(struct tty_struct *tty)
ldata->num_overrun++;
if (time_after(jiffies, ldata->overrun_time + HZ) ||
time_after(ldata->overrun_time, jiffies)) {
- printk(KERN_WARNING "%s: %d input overrun(s)\n",
- tty_name(tty),
- ldata->num_overrun);
+ tty_warn(tty, "%d input overrun(s)\n", ldata->num_overrun);
ldata->overrun_time = jiffies;
ldata->num_overrun = 0;
}
@@ -1486,8 +1495,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
n_tty_receive_overrun(tty);
break;
default:
- printk(KERN_ERR "%s: unknown flag %d\n",
- tty_name(tty), flag);
+ tty_err(tty, "unknown flag %d\n", flag);
break;
}
}
@@ -2006,11 +2014,11 @@ static int copy_from_read_buf(struct tty_struct *tty,
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
if (n) {
- retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
+ const unsigned char *from = read_buf_addr(ldata, tail);
+ retval = copy_to_user(*b, from, n);
n -= retval;
- is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
- tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
- ldata->icanon);
+ is_eof = n == 1 && *from == EOF_CHAR(tty);
+ tty_audit_add_data(tty, from, n, ldata->icanon);
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
@@ -2072,12 +2080,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
if (eol == N_TTY_BUF_SIZE && more) {
/* scan wrapped without finding set bit */
eol = find_next_bit(ldata->read_flags, more, 0);
- if (eol != more)
- found = 1;
- } else if (eol != size)
- found = 1;
+ found = eol != more;
+ } else
+ found = eol != size;
- size = N_TTY_BUF_SIZE - tail;
n = eol - tail;
if (n > N_TTY_BUF_SIZE)
n += N_TTY_BUF_SIZE;
@@ -2088,17 +2094,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
n = c;
}
- n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
- __func__, eol, found, n, c, size, more);
-
- if (n > size) {
- ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size);
- if (ret)
- return -EFAULT;
- ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size);
- } else
- ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n);
+ n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
+ __func__, eol, found, n, c, tail, more);
+ ret = tty_copy_to_user(tty, *b, tail, n);
if (ret)
return -EFAULT;
*b += n;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a45660f62db5..b3110040164a 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -788,7 +788,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
- tty_debug_hangup(tty, "(tty count=%d)\n", tty->count);
+ tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
tty_unlock(tty);
return 0;
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 0140ba4aacde..0982c1a44187 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -157,7 +157,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
#endif
-static int m68328_console_initted = 0;
+static int m68328_console_initted;
static int m68328_console_baud = CONSOLE_BAUD_RATE;
static int m68328_console_cbaud = DEFAULT_CBAUD;
@@ -274,8 +274,8 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
#endif
ch = GET_FIELD(rx, URX_RXDATA);
- if(info->is_cons) {
- if(URX_BREAK & rx) { /* whee, break received */
+ if (info->is_cons) {
+ if (URX_BREAK & rx) { /* whee, break received */
return;
#ifdef CONFIG_MAGIC_SYSRQ
} else if (ch == 0x10) { /* ^P */
@@ -302,7 +302,7 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
tty_insert_flip_char(&info->tport, ch, flag);
#ifndef CONFIG_XCOPILOT_BUGS
- } while((rx = uart->urx.w) & URX_DATA_READY);
+ } while ((rx = uart->urx.w) & URX_DATA_READY);
#endif
tty_schedule_flip(&info->tport);
@@ -330,7 +330,7 @@ static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt--;
- if(info->xmit_cnt <= 0) {
+ if (info->xmit_cnt <= 0) {
/* All done for now... TX ints off */
uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
goto clear_and_return;
@@ -452,45 +452,45 @@ struct {
}
#ifndef CONFIG_M68VZ328
hw_baud_table[18] = {
- {0,0}, /* 0 */
- {0,0}, /* 50 */
- {0,0}, /* 75 */
- {0,0}, /* 110 */
- {0,0}, /* 134 */
- {0,0}, /* 150 */
- {0,0}, /* 200 */
- {7,0x26}, /* 300 */
- {6,0x26}, /* 600 */
- {5,0x26}, /* 1200 */
- {0,0}, /* 1800 */
- {4,0x26}, /* 2400 */
- {3,0x26}, /* 4800 */
- {2,0x26}, /* 9600 */
- {1,0x26}, /* 19200 */
- {0,0x26}, /* 38400 */
- {1,0x38}, /* 57600 */
- {0,0x38}, /* 115200 */
+ {0, 0}, /* 0 */
+ {0, 0}, /* 50 */
+ {0, 0}, /* 75 */
+ {0, 0}, /* 110 */
+ {0, 0}, /* 134 */
+ {0, 0}, /* 150 */
+ {0, 0}, /* 200 */
+ {7, 0x26}, /* 300 */
+ {6, 0x26}, /* 600 */
+ {5, 0x26}, /* 1200 */
+ {0, 0}, /* 1800 */
+ {4, 0x26}, /* 2400 */
+ {3, 0x26}, /* 4800 */
+ {2, 0x26}, /* 9600 */
+ {1, 0x26}, /* 19200 */
+ {0, 0x26}, /* 38400 */
+ {1, 0x38}, /* 57600 */
+ {0, 0x38}, /* 115200 */
};
#else
hw_baud_table[18] = {
- {0,0}, /* 0 */
- {0,0}, /* 50 */
- {0,0}, /* 75 */
- {0,0}, /* 110 */
- {0,0}, /* 134 */
- {0,0}, /* 150 */
- {0,0}, /* 200 */
- {0,0}, /* 300 */
- {7,0x26}, /* 600 */
- {6,0x26}, /* 1200 */
- {0,0}, /* 1800 */
- {5,0x26}, /* 2400 */
- {4,0x26}, /* 4800 */
- {3,0x26}, /* 9600 */
- {2,0x26}, /* 19200 */
- {1,0x26}, /* 38400 */
- {0,0x26}, /* 57600 */
- {1,0x38}, /* 115200 */
+ {0, 0}, /* 0 */
+ {0, 0}, /* 50 */
+ {0, 0}, /* 75 */
+ {0, 0}, /* 110 */
+ {0, 0}, /* 134 */
+ {0, 0}, /* 150 */
+ {0, 0}, /* 200 */
+ {0, 0}, /* 300 */
+ {7, 0x26}, /* 600 */
+ {6, 0x26}, /* 1200 */
+ {0, 0}, /* 1800 */
+ {5, 0x26}, /* 2400 */
+ {4, 0x26}, /* 4800 */
+ {3, 0x26}, /* 9600 */
+ {2, 0x26}, /* 19200 */
+ {1, 0x26}, /* 38400 */
+ {0, 0x26}, /* 57600 */
+ {1, 0x38}, /* 115200 */
};
#endif
/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
@@ -538,7 +538,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
#ifdef CONFIG_SERIAL_68328_RTS_CTS
if (cflag & CRTSCTS) {
- uart->utx.w &= ~ UTX_NOCTS;
+ uart->utx.w &= ~UTX_NOCTS;
} else {
uart->utx.w |= UTX_NOCTS;
}
@@ -591,8 +591,8 @@ void console_print_68328(const char *p)
{
char c;
- while((c=*(p++)) != 0) {
- if(c == '\n')
+ while ((c = *(p++)) != 0) {
+ if (c == '\n')
rs_put_char('\r');
rs_put_char(c);
}
@@ -624,7 +624,7 @@ static void rs_flush_chars(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
return;
#ifndef USE_INTS
- for(;;) {
+ for (;;) {
#endif
/* Enable transmitter */
@@ -659,9 +659,9 @@ static void rs_flush_chars(struct tty_struct *tty)
local_irq_restore(flags);
}
-extern void console_printn(const char * b, int count);
+extern void console_printn(const char *b, int count);
-static int rs_write(struct tty_struct * tty,
+static int rs_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
int c, total = 0;
@@ -700,7 +700,7 @@ static int rs_write(struct tty_struct * tty,
/* Enable transmitter */
local_irq_disable();
#ifndef USE_INTS
- while(info->xmit_cnt) {
+ while (info->xmit_cnt) {
#endif
uart->ustcnt |= USTCNT_TXEN;
@@ -767,7 +767,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
-static void rs_throttle(struct tty_struct * tty)
+static void rs_throttle(struct tty_struct *tty)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
@@ -780,7 +780,7 @@ static void rs_throttle(struct tty_struct * tty)
/* Turn off RTS line (do this atomic) */
}
-static void rs_unthrottle(struct tty_struct * tty)
+static void rs_unthrottle(struct tty_struct *tty)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
@@ -803,8 +803,8 @@ static void rs_unthrottle(struct tty_struct * tty)
* ------------------------------------------------------------
*/
-static int get_serial_info(struct m68k_serial * info,
- struct serial_struct * retinfo)
+static int get_serial_info(struct m68k_serial *info,
+ struct serial_struct *retinfo)
{
struct serial_struct tmp;
@@ -827,7 +827,7 @@ static int get_serial_info(struct m68k_serial * info,
}
static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
- struct serial_struct * new_info)
+ struct serial_struct *new_info)
{
struct tty_port *port = &info->tport;
struct serial_struct new_serial;
@@ -883,7 +883,7 @@ check_and_exit:
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
+static int get_lsr_info(struct m68k_serial *info, unsigned int *value)
{
#ifdef CONFIG_SERIAL_68328_RTS_CTS
m68328_uart *uart = &uart_addr[info->line];
@@ -904,7 +904,7 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
/*
* This routine sends a break character out the serial port.
*/
-static void send_break(struct m68k_serial * info, unsigned int duration)
+static void send_break(struct m68k_serial *info, unsigned int duration)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
@@ -922,7 +922,7 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
static int rs_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
- struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+ struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
int retval;
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
@@ -992,9 +992,9 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
-static void rs_close(struct tty_struct *tty, struct file * filp)
+static void rs_close(struct tty_struct *tty, struct file *filp)
{
- struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+ struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
struct tty_port *port = &info->tport;
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
@@ -1079,7 +1079,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
*/
void rs_hangup(struct tty_struct *tty)
{
- struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+ struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_hangup"))
return;
@@ -1098,7 +1098,7 @@ void rs_hangup(struct tty_struct *tty)
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
-int rs_open(struct tty_struct *tty, struct file * filp)
+int rs_open(struct tty_struct *tty, struct file *filp)
{
struct m68k_serial *info;
int retval;
@@ -1180,7 +1180,7 @@ rs68328_init(void)
local_irq_save(flags);
- for(i=0;i<NR_PORTS;i++) {
+ for (i = 0; i < NR_PORTS; i++) {
info = &m68k_soft[i];
tty_port_init(&info->tport);
@@ -1198,7 +1198,7 @@ rs68328_init(void)
printk(" is a builtin MC68328 UART\n");
#ifdef CONFIG_M68VZ328
- if (i > 0 )
+ if (i > 0)
PJSEL &= 0xCF; /* PSW enable second port output */
#endif
@@ -1263,7 +1263,7 @@ int m68328_console_setup(struct console *cp, char *arg)
return(-1);
if (arg)
- n = simple_strtoul(arg,NULL,0);
+ n = simple_strtoul(arg, NULL, 0);
for (i = 0; i < ARRAY_SIZE(baud_table); i++)
if (baud_table[i] == n)
@@ -1279,7 +1279,7 @@ int m68328_console_setup(struct console *cp, char *arg)
}
m68328_set_baud(); /* make sure baud rate changes */
- return(0);
+ return 0;
}
@@ -1298,7 +1298,7 @@ void m68328_console_write (struct console *co, const char *str,
while (count--) {
if (*str == '\n')
rs_put_char('\r');
- rs_put_char( *str++ );
+ rs_put_char(*str++);
}
}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 39126460c1f5..c9720a97a977 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -620,7 +620,7 @@ static int univ8250_console_setup(struct console *co, char *options)
* @options: ptr to option string from console command line
*
* Only attempts to match console command lines of the form:
- * console=uart[8250],io|mmio|mmio32,<addr>[,<options>]
+ * console=uart[8250],io|mmio|mmio16|mmio32,<addr>[,<options>]
* console=uart[8250],0x<addr>[,<options>]
* This form is used to register an initial earlycon boot console and
* replace it with the serial8250_console at 8250 driver init.
@@ -650,8 +650,9 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
if (port->iotype != iotype)
continue;
- if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) &&
- (port->mapbase != addr))
+ if ((iotype == UPIO_MEM || iotype == UPIO_MEM16 ||
+ iotype == UPIO_MEM32 || iotype == UPIO_MEM32BE)
+ && (port->mapbase != addr))
continue;
if (iotype == UPIO_PORT && port->iobase != addr)
continue;
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index ceb85792a5cf..af62131af21e 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -42,6 +42,8 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
switch (port->iotype) {
case UPIO_MEM:
return readb(port->membase + offset);
+ case UPIO_MEM16:
+ return readw(port->membase + (offset << 1));
case UPIO_MEM32:
return readl(port->membase + (offset << 2));
case UPIO_MEM32BE:
@@ -59,6 +61,9 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int
case UPIO_MEM:
writeb(value, port->membase + offset);
break;
+ case UPIO_MEM16:
+ writew(value, port->membase + (offset << 1));
+ break;
case UPIO_MEM32:
writel(value, port->membase + (offset << 2));
break;
@@ -73,43 +78,27 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-static void __init wait_for_xmitr(struct uart_port *port)
+static void __init serial_putc(struct uart_port *port, int c)
{
unsigned int status;
+ serial8250_early_out(port, UART_TX, c);
+
for (;;) {
status = serial8250_early_in(port, UART_LSR);
if ((status & BOTH_EMPTY) == BOTH_EMPTY)
- return;
+ break;
cpu_relax();
}
}
-static void __init serial_putc(struct uart_port *port, int c)
-{
- wait_for_xmitr(port);
- serial8250_early_out(port, UART_TX, c);
-}
-
static void __init early_serial8250_write(struct console *console,
const char *s, unsigned int count)
{
struct earlycon_device *device = console->data;
struct uart_port *port = &device->port;
- unsigned int ier;
-
- /* Save the IER and disable interrupts preserving the UUE bit */
- ier = serial8250_early_in(port, UART_IER);
- if (ier)
- serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
uart_console_write(port, s, count, serial_putc);
-
- /* Wait for transmitter to become empty and restore the IER */
- wait_for_xmitr(port);
-
- if (ier)
- serial8250_early_out(port, UART_IER, ier);
}
static void __init init_port(struct earlycon_device *device)
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 49394b4c5cfd..d6e1ec9b4fde 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -48,6 +48,7 @@ static const struct of_device_id of_match[];
#define UART_MCR_MDCE BIT(7)
#define UART_MCR_FCM BIT(6)
+#ifdef CONFIG_SERIAL_EARLYCON
static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -140,6 +141,7 @@ OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
ingenic_early_console_setup);
+#endif /* CONFIG_SERIAL_EARLYCON */
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
{
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 78883ca64ddd..0e590b233f03 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -16,7 +16,7 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -245,23 +245,6 @@ static int mtk8250_probe(struct platform_device *pdev)
return 0;
}
-static int mtk8250_remove(struct platform_device *pdev)
-{
- struct mtk8250_data *data = platform_get_drvdata(pdev);
-
- pm_runtime_get_sync(&pdev->dev);
-
- serial8250_unregister_port(data->line);
-
- pm_runtime_disable(&pdev->dev);
- pm_runtime_put_noidle(&pdev->dev);
-
- if (!pm_runtime_status_suspended(&pdev->dev))
- mtk8250_runtime_suspend(&pdev->dev);
-
- return 0;
-}
-
#ifdef CONFIG_PM_SLEEP
static int mtk8250_suspend(struct device *dev)
{
@@ -292,18 +275,18 @@ static const struct of_device_id mtk8250_of_match[] = {
{ .compatible = "mediatek,mt6577-uart" },
{ /* Sentinel */ }
};
-MODULE_DEVICE_TABLE(of, mtk8250_of_match);
static struct platform_driver mtk8250_platform_driver = {
.driver = {
- .name = "mt6577-uart",
- .pm = &mtk8250_pm_ops,
- .of_match_table = mtk8250_of_match,
+ .name = "mt6577-uart",
+ .pm = &mtk8250_pm_ops,
+ .of_match_table = mtk8250_of_match,
+ .suppress_bind_attrs = true,
+
},
.probe = mtk8250_probe,
- .remove = mtk8250_remove,
};
-module_platform_driver(mtk8250_platform_driver);
+builtin_platform_driver(mtk8250_platform_driver);
#ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init early_mtk8250_setup(struct earlycon_device *device,
@@ -319,7 +302,3 @@ static int __init early_mtk8250_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
#endif
-
-MODULE_AUTHOR("Matthias Brugger");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/8250/8250_of.c
index de5029649795..33021c1f7d55 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -18,14 +18,9 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-#include <linux/nwpserial.h>
#include <linux/clk.h>
-#ifdef CONFIG_SERIAL_8250_MODULE
-#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE
-#endif
-
-#include "8250/8250.h"
+#include "8250.h"
struct of_serial_info {
struct clk *clk;
@@ -122,6 +117,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
case 1:
port->iotype = UPIO_MEM;
break;
+ case 2:
+ port->iotype = UPIO_MEM16;
+ break;
case 4:
port->iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32;
@@ -195,7 +193,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
goto out;
switch (port_type) {
-#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
{
struct uart_8250_port port8250;
@@ -212,12 +209,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
ret = serial8250_register_8250_port(&port8250);
break;
}
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- case PORT_NWPSERIAL:
- ret = nwpserial_register_port(&port);
- break;
-#endif
default:
/* need to add code for these */
case PORT_UNKNOWN:
@@ -245,16 +236,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
{
struct of_serial_info *info = platform_get_drvdata(ofdev);
switch (info->type) {
-#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
serial8250_unregister_port(info->line);
break;
-#endif
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- case PORT_NWPSERIAL:
- nwpserial_unregister_port(info->line);
- break;
-#endif
default:
/* need to add code for these */
break;
@@ -267,7 +251,6 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
}
#ifdef CONFIG_PM_SLEEP
-#ifdef CONFIG_SERIAL_8250
static void of_serial_suspend_8250(struct of_serial_info *info)
{
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
@@ -288,15 +271,6 @@ static void of_serial_resume_8250(struct of_serial_info *info)
serial8250_resume_port(info->line);
}
-#else
-static inline void of_serial_suspend_8250(struct of_serial_info *info)
-{
-}
-
-static inline void of_serial_resume_8250(struct of_serial_info *info)
-{
-}
-#endif
static int of_serial_suspend(struct device *dev)
{
@@ -353,10 +327,6 @@ static const struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_XSCALE, },
{ .compatible = "mrvl,pxa-uart",
.data = (void *)PORT_XSCALE, },
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- { .compatible = "ibm,qpace-nwp-serial",
- .data = (void *)PORT_NWPSERIAL, },
-#endif
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 52d82d2ac726..8d262bce97e4 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -368,6 +368,18 @@ static void mem_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset);
}
+static void mem16_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = offset << p->regshift;
+ writew(value, p->membase + offset);
+}
+
+static unsigned int mem16_serial_in(struct uart_port *p, int offset)
+{
+ offset = offset << p->regshift;
+ return readw(p->membase + offset);
+}
+
static void mem32_serial_out(struct uart_port *p, int offset, int value)
{
offset = offset << p->regshift;
@@ -425,6 +437,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem_serial_out;
break;
+ case UPIO_MEM16:
+ p->serial_in = mem16_serial_in;
+ p->serial_out = mem16_serial_out;
+ break;
+
case UPIO_MEM32:
p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out;
@@ -459,6 +476,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
{
switch (p->iotype) {
case UPIO_MEM:
+ case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
@@ -2462,6 +2480,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM32BE:
+ case UPIO_MEM16:
case UPIO_MEM:
if (!port->mapbase)
break;
@@ -2499,6 +2518,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM32BE:
+ case UPIO_MEM16:
case UPIO_MEM:
if (!port->mapbase)
break;
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 245edbb68d4b..bab6b3ae2540 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -13,6 +13,7 @@
*/
#include <linux/clk.h>
+#include <linux/console.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -34,6 +35,29 @@ struct uniphier8250_priv {
spinlock_t atomic_write_lock;
};
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init uniphier_early_console_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ /* This hardware always expects MMIO32 register interface. */
+ device->port.iotype = UPIO_MEM32;
+ device->port.regshift = 2;
+
+ /*
+ * Do not touch the divisor register in early_serial8250_setup();
+ * we assume it has been initialized by a boot loader.
+ */
+ device->baud = 0;
+
+ return early_serial8250_setup(device, options);
+}
+OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart",
+ uniphier_early_console_setup);
+#endif
+
/*
* The register map is slightly different from that of 8250.
* IO callbacks must be overridden for correct access to FCR, LCR, and MCR.
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 6412f1455beb..b03cb5175113 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -361,9 +361,8 @@ config SERIAL_8250_UNIPHIER
config SERIAL_8250_INGENIC
bool "Support for Ingenic SoC serial ports"
- depends on SERIAL_8250_CONSOLE && OF_FLATTREE
+ depends on OF_FLATTREE
select LIBFDT
- select SERIAL_EARLYCON
help
If you have a system using an Ingenic SoC and wish to make use of
its UARTs, say Y to this option. If unsure, say N.
@@ -372,9 +371,18 @@ config SERIAL_8250_MID
tristate "Support for serial ports on Intel MID platforms"
depends on SERIAL_8250 && PCI
select HSU_DMA if SERIAL_8250_DMA
- select HSU_DMA_PCI if X86_INTEL_MID
+ select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
select RATIONAL
help
Selecting this option will enable handling of the extra features
present on the UART found on Intel Medfield SOC and various other
Intel platforms.
+
+config SERIAL_OF_PLATFORM
+ tristate "Devicetree based probing for 8250 ports"
+ depends on SERIAL_8250 && OF
+ help
+ This option is used for all 8250 compatible serial ports that
+ are probed through devicetree, including Open Firmware based
+ PowerPC systems and embedded systems on architectures using the
+ flattened device tree format.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index e177f8681ada..b9b9bca5b6c3 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -28,5 +28,6 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index f38beb28e7ae..39721ec4f415 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -115,6 +115,7 @@ config SERIAL_SB1250_DUART_CONSOLE
config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
+ depends on HAS_DMA
depends on ARCH_AT91 || AVR32 || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
@@ -571,9 +572,11 @@ config BFIN_UART3_CTSRTS
config SERIAL_IMX
tristate "IMX serial port support"
+ depends on HAS_DMA
depends on ARCH_MXC || COMPILE_TEST
select SERIAL_CORE
select RATIONAL
+ select SERIAL_MCTRL_GPIO if GPIOLIB
help
If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option.
@@ -1044,7 +1047,7 @@ config SERIAL_SGI_IOC3
say Y or M. Otherwise, say N.
config SERIAL_MSM
- bool "MSM on-chip serial port support"
+ tristate "MSM on-chip serial port support"
depends on ARCH_QCOM
select SERIAL_CORE
@@ -1094,16 +1097,6 @@ config SERIAL_NETX_CONSOLE
If you have enabled the serial port on the Hilscher NetX SoC
you can make it the console by answering Y to this option.
-config SERIAL_OF_PLATFORM
- tristate "Serial port on Open Firmware platform bus"
- depends on OF
- depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
- help
- If you have a PowerPC based system that has serial ports
- on a platform specific bus, you should enable this option.
- Currently, only 8250 compatible ports are supported, but
- others can easily be added.
-
config SERIAL_OMAP
tristate "OMAP serial port support"
depends on ARCH_OMAP2PLUS
@@ -1131,23 +1124,6 @@ config SERIAL_OMAP_CONSOLE
your boot loader about how to pass options to the kernel at
boot time.)
-config SERIAL_OF_PLATFORM_NWPSERIAL
- tristate "NWP serial port driver"
- depends on PPC_DCR
- select SERIAL_OF_PLATFORM
- select SERIAL_CORE_CONSOLE
- select SERIAL_CORE
- help
- This driver supports the cell network processor nwp serial
- device.
-
-config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
- bool "Console on NWP serial port"
- depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
- select SERIAL_CORE_CONSOLE
- help
- Support for Console on the NWP serial ports.
-
config SERIAL_LANTIQ
bool "Lantiq serial driver"
depends on LANTIQ
@@ -1409,8 +1385,9 @@ config SERIAL_PCH_UART_CONSOLE
warnings and which allows logins in single user mode).
config SERIAL_MXS_AUART
- depends on ARCH_MXS || COMPILE_TEST
tristate "MXS AUART support"
+ depends on HAS_DMA
+ depends on ARCH_MXS || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
help
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 5ab41119b3dc..b391c9b31960 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -63,8 +63,6 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
-obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 899a77187bde..c0da0ccbbcf5 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -60,6 +60,8 @@
#include <linux/io.h>
#include <linux/acpi.h>
+#include "amba-pl011.h"
+
#define UART_NR 14
#define SERIAL_AMBA_MAJOR 204
@@ -71,11 +73,27 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
+static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
+ [REG_DR] = UART01x_DR,
+ [REG_FR] = UART01x_FR,
+ [REG_LCRH_RX] = UART011_LCRH,
+ [REG_LCRH_TX] = UART011_LCRH,
+ [REG_IBRD] = UART011_IBRD,
+ [REG_FBRD] = UART011_FBRD,
+ [REG_CR] = UART011_CR,
+ [REG_IFLS] = UART011_IFLS,
+ [REG_IMSC] = UART011_IMSC,
+ [REG_RIS] = UART011_RIS,
+ [REG_MIS] = UART011_MIS,
+ [REG_ICR] = UART011_ICR,
+ [REG_DMACR] = UART011_DMACR,
+};
+
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
+ const u16 *reg_offset;
unsigned int ifls;
- unsigned int lcrh_tx;
- unsigned int lcrh_rx;
+ bool access_32b;
bool oversampling;
bool dma_threshold;
bool cts_event_workaround;
@@ -91,9 +109,8 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
}
static struct vendor_data vendor_arm = {
+ .reg_offset = pl011_std_offsets,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
- .lcrh_tx = UART011_LCRH,
- .lcrh_rx = UART011_LCRH,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
@@ -103,6 +120,7 @@ static struct vendor_data vendor_arm = {
};
static struct vendor_data vendor_sbsa = {
+ .reg_offset = pl011_std_offsets,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
@@ -110,15 +128,41 @@ static struct vendor_data vendor_sbsa = {
.fixed_options = true,
};
+static u16 pl011_st_offsets[REG_ARRAY_SIZE] = {
+ [REG_DR] = UART01x_DR,
+ [REG_ST_DMAWM] = ST_UART011_DMAWM,
+ [REG_ST_TIMEOUT] = ST_UART011_TIMEOUT,
+ [REG_FR] = UART01x_FR,
+ [REG_LCRH_RX] = ST_UART011_LCRH_RX,
+ [REG_LCRH_TX] = ST_UART011_LCRH_TX,
+ [REG_IBRD] = UART011_IBRD,
+ [REG_FBRD] = UART011_FBRD,
+ [REG_CR] = UART011_CR,
+ [REG_IFLS] = UART011_IFLS,
+ [REG_IMSC] = UART011_IMSC,
+ [REG_RIS] = UART011_RIS,
+ [REG_MIS] = UART011_MIS,
+ [REG_ICR] = UART011_ICR,
+ [REG_DMACR] = UART011_DMACR,
+ [REG_ST_XFCR] = ST_UART011_XFCR,
+ [REG_ST_XON1] = ST_UART011_XON1,
+ [REG_ST_XON2] = ST_UART011_XON2,
+ [REG_ST_XOFF1] = ST_UART011_XOFF1,
+ [REG_ST_XOFF2] = ST_UART011_XOFF2,
+ [REG_ST_ITCR] = ST_UART011_ITCR,
+ [REG_ST_ITIP] = ST_UART011_ITIP,
+ [REG_ST_ABCR] = ST_UART011_ABCR,
+ [REG_ST_ABIMSC] = ST_UART011_ABIMSC,
+};
+
static unsigned int get_fifosize_st(struct amba_device *dev)
{
return 64;
}
static struct vendor_data vendor_st = {
+ .reg_offset = pl011_st_offsets,
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
- .lcrh_tx = ST_UART011_LCRH_TX,
- .lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
.dma_threshold = true,
.cts_event_workaround = true,
@@ -127,6 +171,29 @@ static struct vendor_data vendor_st = {
.get_fifosize = get_fifosize_st,
};
+static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
+ [REG_DR] = ZX_UART011_DR,
+ [REG_FR] = ZX_UART011_FR,
+ [REG_LCRH_RX] = ZX_UART011_LCRH,
+ [REG_LCRH_TX] = ZX_UART011_LCRH,
+ [REG_IBRD] = ZX_UART011_IBRD,
+ [REG_FBRD] = ZX_UART011_FBRD,
+ [REG_CR] = ZX_UART011_CR,
+ [REG_IFLS] = ZX_UART011_IFLS,
+ [REG_IMSC] = ZX_UART011_IMSC,
+ [REG_RIS] = ZX_UART011_RIS,
+ [REG_MIS] = ZX_UART011_MIS,
+ [REG_ICR] = ZX_UART011_ICR,
+ [REG_DMACR] = ZX_UART011_DMACR,
+};
+
+static struct vendor_data vendor_zte = {
+ .reg_offset = pl011_zte_offsets,
+ .access_32b = true,
+ .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+ .get_fifosize = get_fifosize_arm,
+};
+
/* Deals with DMA transactions */
struct pl011_sgbuf {
@@ -162,14 +229,13 @@ struct pl011_dmatx_data {
*/
struct uart_amba_port {
struct uart_port port;
+ const u16 *reg_offset;
struct clk *clk;
const struct vendor_data *vendor;
unsigned int dmacr; /* dma control reg */
unsigned int im; /* interrupt mask */
unsigned int old_status;
unsigned int fifosize; /* vendor-specific */
- unsigned int lcrh_tx; /* vendor-specific */
- unsigned int lcrh_rx; /* vendor-specific */
unsigned int old_cr; /* state during shutdown */
bool autorts;
unsigned int fixed_baud; /* vendor-set fixed baud rate */
@@ -184,6 +250,32 @@ struct uart_amba_port {
#endif
};
+static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ return uap->reg_offset[reg];
+}
+
+static unsigned int pl011_read(const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
+
+ return (uap->port.iotype == UPIO_MEM32) ?
+ readl_relaxed(addr) : readw_relaxed(addr);
+}
+
+static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
+
+ if (uap->port.iotype == UPIO_MEM32)
+ writel_relaxed(val, addr);
+ else
+ writew_relaxed(val, addr);
+}
+
/*
* Reads up to 256 characters from the FIFO or until it's empty and
* inserts them into the TTY layer. Returns the number of characters
@@ -196,13 +288,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
int fifotaken = 0;
while (max_count--) {
- status = readw(uap->port.membase + UART01x_FR);
+ status = pl011_read(uap, REG_FR);
if (status & UART01x_FR_RXFE)
break;
/* Take chars from the FIFO and update status */
- ch = readw(uap->port.membase + UART01x_DR) |
- UART_DUMMY_DR_RX;
+ ch = pl011_read(uap, REG_DR) | UART_DUMMY_DR_RX;
flag = TTY_NORMAL;
uap->port.icount.rx++;
fifotaken++;
@@ -284,7 +375,8 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
struct device *dev = uap->port.dev;
struct dma_slave_config tx_conf = {
- .dst_addr = uap->port.mapbase + UART01x_DR,
+ .dst_addr = uap->port.mapbase +
+ pl011_reg_to_offset(uap, REG_DR),
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.direction = DMA_MEM_TO_DEV,
.dst_maxburst = uap->fifosize >> 1,
@@ -339,7 +431,8 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
if (chan) {
struct dma_slave_config rx_conf = {
- .src_addr = uap->port.mapbase + UART01x_DR,
+ .src_addr = uap->port.mapbase +
+ pl011_reg_to_offset(uap, REG_DR),
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.direction = DMA_DEV_TO_MEM,
.src_maxburst = uap->fifosize >> 2,
@@ -438,7 +531,7 @@ static void pl011_dma_tx_callback(void *data)
dmacr = uap->dmacr;
uap->dmacr = dmacr & ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
/*
* If TX DMA was disabled, it means that we've stopped the DMA for
@@ -552,7 +645,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
dma_dev->device_issue_pending(chan);
uap->dmacr |= UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->dmatx.queued = true;
/*
@@ -588,9 +681,9 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
*/
if (uap->dmatx.queued) {
uap->dmacr |= UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return true;
}
@@ -600,7 +693,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
*/
if (pl011_dma_tx_refill(uap) > 0) {
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return true;
}
return false;
@@ -614,7 +707,7 @@ static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
{
if (uap->dmatx.queued) {
uap->dmacr &= ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
}
@@ -640,14 +733,12 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
if (!uap->dmatx.queued) {
if (pl011_dma_tx_refill(uap) > 0) {
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase +
- UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
} else
ret = false;
} else if (!(uap->dmacr & UART011_TXDMAE)) {
uap->dmacr |= UART011_TXDMAE;
- writew(uap->dmacr,
- uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
return ret;
}
@@ -658,9 +749,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
*/
dmacr = uap->dmacr;
uap->dmacr &= ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
- if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+ if (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) {
/*
* No space in the FIFO, so enable the transmit interrupt
* so we know when there is space. Note that once we've
@@ -669,13 +760,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
return false;
}
- writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+ pl011_write(uap->port.x_char, uap, REG_DR);
uap->port.icount.tx++;
uap->port.x_char = 0;
/* Success - restore the DMA state */
uap->dmacr = dmacr;
- writew(dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(dmacr, uap, REG_DMACR);
return true;
}
@@ -703,7 +794,7 @@ __acquires(&uap->port.lock)
DMA_TO_DEVICE);
uap->dmatx.queued = false;
uap->dmacr &= ~UART011_TXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
}
@@ -743,11 +834,11 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
dma_async_issue_pending(rxchan);
uap->dmacr |= UART011_RXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->dmarx.running = true;
uap->im &= ~UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return 0;
}
@@ -805,8 +896,8 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
*/
if (dma_count == pending && readfifo) {
/* Clear any error flags */
- writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
- uap->port.membase + UART011_ICR);
+ pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
+ UART011_FEIS, uap, REG_ICR);
/*
* If we read all the DMA'd characters, and we had an
@@ -854,7 +945,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
/* Disable RX DMA - incoming data will wait in the FIFO */
uap->dmacr &= ~UART011_RXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
uap->dmarx.running = false;
pending = sgbuf->sg.length - state.residue;
@@ -874,7 +965,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
"fall back to interrupt mode\n");
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
}
}
@@ -922,7 +1013,7 @@ static void pl011_dma_rx_callback(void *data)
dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
"fall back to interrupt mode\n");
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
}
}
@@ -935,7 +1026,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
{
/* FIXME. Just disable the DMA enable */
uap->dmacr &= ~UART011_RXDMAE;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
}
/*
@@ -979,7 +1070,7 @@ static void pl011_dma_rx_poll(unsigned long args)
spin_lock_irqsave(&uap->port.lock, flags);
pl011_dma_rx_stop(uap);
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
spin_unlock_irqrestore(&uap->port.lock, flags);
uap->dmarx.running = false;
@@ -1041,7 +1132,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
skip_rx:
/* Turn on DMA error (RX/TX will be enabled on demand) */
uap->dmacr |= UART011_DMAONERR;
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
/*
* ST Micro variants has some specific dma burst threshold
@@ -1049,8 +1140,8 @@ skip_rx:
* be issued above/below 16 bytes.
*/
if (uap->vendor->dma_threshold)
- writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
- uap->port.membase + ST_UART011_DMAWM);
+ pl011_write(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
+ uap, REG_ST_DMAWM);
if (uap->using_rx_dma) {
if (pl011_dma_rx_trigger_dma(uap))
@@ -1075,12 +1166,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
return;
/* Disable RX and TX DMA */
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+ while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
barrier();
spin_lock_irq(&uap->port.lock);
uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
- writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ pl011_write(uap->dmacr, uap, REG_DMACR);
spin_unlock_irq(&uap->port.lock);
if (uap->using_tx_dma) {
@@ -1181,7 +1272,7 @@ static void pl011_stop_tx(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
uap->im &= ~UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_tx_stop(uap);
}
@@ -1191,7 +1282,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
static void pl011_start_tx_pio(struct uart_amba_port *uap)
{
uap->im |= UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
pl011_tx_chars(uap, false);
}
@@ -1211,7 +1302,7 @@ static void pl011_stop_rx(struct uart_port *port)
uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
UART011_PEIM|UART011_BEIM|UART011_OEIM);
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_rx_stop(uap);
}
@@ -1222,7 +1313,7 @@ static void pl011_enable_ms(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
}
static void pl011_rx_chars(struct uart_amba_port *uap)
@@ -1242,7 +1333,7 @@ __acquires(&uap->port.lock)
dev_dbg(uap->port.dev, "could not trigger RX DMA job "
"fall back to interrupt mode again\n");
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
} else {
#ifdef CONFIG_DMA_ENGINE
/* Start Rx DMA poll */
@@ -1263,10 +1354,10 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
bool from_irq)
{
if (unlikely(!from_irq) &&
- readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
return false; /* unable to transmit character */
- writew(c, uap->port.membase + UART01x_DR);
+ pl011_write(c, uap, REG_DR);
uap->port.icount.tx++;
return true;
@@ -1313,7 +1404,7 @@ static void pl011_modem_status(struct uart_amba_port *uap)
{
unsigned int status, delta;
- status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+ status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
delta = status ^ uap->old_status;
uap->old_status = status;
@@ -1341,15 +1432,15 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
return;
/* workaround to make sure that all bits are unlocked.. */
- writew(0x00, uap->port.membase + UART011_ICR);
+ pl011_write(0x00, uap, REG_ICR);
/*
* WA: introduce 26ns(1 uart clk) delay before W1C;
* single apb access will incur 2 pclk(133.12Mhz) delay,
* so add 2 dummy reads
*/
- dummy_read = readw(uap->port.membase + UART011_ICR);
- dummy_read = readw(uap->port.membase + UART011_ICR);
+ dummy_read = pl011_read(uap, REG_ICR);
+ dummy_read = pl011_read(uap, REG_ICR);
}
static irqreturn_t pl011_int(int irq, void *dev_id)
@@ -1361,15 +1452,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
int handled = 0;
spin_lock_irqsave(&uap->port.lock, flags);
- imsc = readw(uap->port.membase + UART011_IMSC);
- status = readw(uap->port.membase + UART011_RIS) & imsc;
+ imsc = pl011_read(uap, REG_IMSC);
+ status = pl011_read(uap, REG_RIS) & imsc;
if (status) {
do {
check_apply_cts_event_workaround(uap);
- writew(status & ~(UART011_TXIS|UART011_RTIS|
- UART011_RXIS),
- uap->port.membase + UART011_ICR);
+ pl011_write(status & ~(UART011_TXIS|UART011_RTIS|
+ UART011_RXIS),
+ uap, REG_ICR);
if (status & (UART011_RTIS|UART011_RXIS)) {
if (pl011_dma_rx_running(uap))
@@ -1386,7 +1477,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (pass_counter-- == 0)
break;
- status = readw(uap->port.membase + UART011_RIS) & imsc;
+ status = pl011_read(uap, REG_RIS) & imsc;
} while (status != 0);
handled = 1;
}
@@ -1400,7 +1491,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- unsigned int status = readw(uap->port.membase + UART01x_FR);
+ unsigned int status = pl011_read(uap, REG_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
@@ -1409,7 +1500,7 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
unsigned int result = 0;
- unsigned int status = readw(uap->port.membase + UART01x_FR);
+ unsigned int status = pl011_read(uap, REG_FR);
#define TIOCMBIT(uartbit, tiocmbit) \
if (status & uartbit) \
@@ -1429,7 +1520,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
container_of(port, struct uart_amba_port, port);
unsigned int cr;
- cr = readw(uap->port.membase + UART011_CR);
+ cr = pl011_read(uap, REG_CR);
#define TIOCMBIT(tiocmbit, uartbit) \
if (mctrl & tiocmbit) \
@@ -1449,7 +1540,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
}
#undef TIOCMBIT
- writew(cr, uap->port.membase + UART011_CR);
+ pl011_write(cr, uap, REG_CR);
}
static void pl011_break_ctl(struct uart_port *port, int break_state)
@@ -1460,12 +1551,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
unsigned int lcr_h;
spin_lock_irqsave(&uap->port.lock, flags);
- lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+ lcr_h = pl011_read(uap, REG_LCRH_TX);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
- writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+ pl011_write(lcr_h, uap, REG_LCRH_TX);
spin_unlock_irqrestore(&uap->port.lock, flags);
}
@@ -1475,9 +1566,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- unsigned char __iomem *regs = uap->port.membase;
- writew(readw(regs + UART011_MIS), regs + UART011_ICR);
+ pl011_write(pl011_read(uap, REG_MIS), uap, REG_ICR);
/*
* There is no way to clear TXIM as this is "ready to transmit IRQ", so
* we simply mask it. start_tx() will unmask it.
@@ -1491,7 +1581,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
* (including tx queue), so we're also fine with start_tx()'s caller
* side.
*/
- writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC);
+ pl011_write(pl011_read(uap, REG_IMSC) & ~UART011_TXIM, uap,
+ REG_IMSC);
}
static int pl011_get_poll_char(struct uart_port *port)
@@ -1506,11 +1597,11 @@ static int pl011_get_poll_char(struct uart_port *port)
*/
pl011_quiesce_irqs(port);
- status = readw(uap->port.membase + UART01x_FR);
+ status = pl011_read(uap, REG_FR);
if (status & UART01x_FR_RXFE)
return NO_POLL_CHAR;
- return readw(uap->port.membase + UART01x_DR);
+ return pl011_read(uap, REG_DR);
}
static void pl011_put_poll_char(struct uart_port *port,
@@ -1519,10 +1610,10 @@ static void pl011_put_poll_char(struct uart_port *port,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+ while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
barrier();
- writew(ch, uap->port.membase + UART01x_DR);
+ pl011_write(ch, uap, REG_DR);
}
#endif /* CONFIG_CONSOLE_POLL */
@@ -1546,15 +1637,16 @@ static int pl011_hwinit(struct uart_port *port)
uap->port.uartclk = clk_get_rate(uap->clk);
/* Clear pending error and receive interrupts */
- writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
- UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+ pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
+ UART011_FEIS | UART011_RTIS | UART011_RXIS,
+ uap, REG_ICR);
/*
* Save interrupts enable mask, and enable RX interrupts in case if
* the interrupt is used for NMI entry.
*/
- uap->im = readw(uap->port.membase + UART011_IMSC);
- writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+ uap->im = pl011_read(uap, REG_IMSC);
+ pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC);
if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
@@ -1566,24 +1658,30 @@ static int pl011_hwinit(struct uart_port *port)
return 0;
}
+static bool pl011_split_lcrh(const struct uart_amba_port *uap)
+{
+ return pl011_reg_to_offset(uap, REG_LCRH_RX) !=
+ pl011_reg_to_offset(uap, REG_LCRH_TX);
+}
+
static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
{
- writew(lcr_h, uap->port.membase + uap->lcrh_rx);
- if (uap->lcrh_rx != uap->lcrh_tx) {
+ pl011_write(lcr_h, uap, REG_LCRH_RX);
+ if (pl011_split_lcrh(uap)) {
int i;
/*
* Wait 10 PCLKs before writing LCRH_TX register,
* to get this delay write read only register 10 times
*/
for (i = 0; i < 10; ++i)
- writew(0xff, uap->port.membase + UART011_MIS);
- writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+ pl011_write(0xff, uap, REG_MIS);
+ pl011_write(lcr_h, uap, REG_LCRH_TX);
}
}
static int pl011_allocate_irq(struct uart_amba_port *uap)
{
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
}
@@ -1598,12 +1696,11 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
spin_lock_irq(&uap->port.lock);
/* Clear out any spuriously appearing RX interrupts */
- writew(UART011_RTIS | UART011_RXIS,
- uap->port.membase + UART011_ICR);
+ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
spin_unlock_irq(&uap->port.lock);
}
@@ -1622,21 +1719,21 @@ static int pl011_startup(struct uart_port *port)
if (retval)
goto clk_dis;
- writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
+ pl011_write(uap->vendor->ifls, uap, REG_IFLS);
spin_lock_irq(&uap->port.lock);
/* restore RTS and DTR */
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
- writew(cr, uap->port.membase + UART011_CR);
+ pl011_write(cr, uap, REG_CR);
spin_unlock_irq(&uap->port.lock);
/*
* initialise the old status of the modem signals
*/
- uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+ uap->old_status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
/* Startup DMA */
pl011_dma_startup(uap);
@@ -1677,9 +1774,9 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
{
unsigned long val;
- val = readw(uap->port.membase + lcrh);
+ val = pl011_read(uap, lcrh);
val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
- writew(val, uap->port.membase + lcrh);
+ pl011_write(val, uap, lcrh);
}
/*
@@ -1693,19 +1790,19 @@ static void pl011_disable_uart(struct uart_amba_port *uap)
uap->autorts = false;
spin_lock_irq(&uap->port.lock);
- cr = readw(uap->port.membase + UART011_CR);
+ cr = pl011_read(uap, REG_CR);
uap->old_cr = cr;
cr &= UART011_CR_RTS | UART011_CR_DTR;
cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- writew(cr, uap->port.membase + UART011_CR);
+ pl011_write(cr, uap, REG_CR);
spin_unlock_irq(&uap->port.lock);
/*
* disable break condition and fifos
*/
- pl011_shutdown_channel(uap, uap->lcrh_rx);
- if (uap->lcrh_rx != uap->lcrh_tx)
- pl011_shutdown_channel(uap, uap->lcrh_tx);
+ pl011_shutdown_channel(uap, REG_LCRH_RX);
+ if (pl011_split_lcrh(uap))
+ pl011_shutdown_channel(uap, REG_LCRH_TX);
}
static void pl011_disable_interrupts(struct uart_amba_port *uap)
@@ -1714,8 +1811,8 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap)
/* mask all interrupts and clear all pending ones */
uap->im = 0;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ pl011_write(uap->im, uap, REG_IMSC);
+ pl011_write(0xffff, uap, REG_ICR);
spin_unlock_irq(&uap->port.lock);
}
@@ -1867,8 +1964,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
pl011_enable_ms(port);
/* first, disable everything */
- old_cr = readw(port->membase + UART011_CR);
- writew(0, port->membase + UART011_CR);
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write(0, uap, REG_CR);
if (termios->c_cflag & CRTSCTS) {
if (old_cr & UART011_CR_RTS)
@@ -1901,17 +1998,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
quot -= 2;
}
/* Set baud rate */
- writew(quot & 0x3f, port->membase + UART011_FBRD);
- writew(quot >> 6, port->membase + UART011_IBRD);
+ pl011_write(quot & 0x3f, uap, REG_FBRD);
+ pl011_write(quot >> 6, uap, REG_IBRD);
/*
* ----------v----------v----------v----------v-----
- * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
- * UART011_FBRD & UART011_IBRD.
+ * NOTE: REG_LCRH_TX and REG_LCRH_RX MUST BE WRITTEN AFTER
+ * REG_FBRD & REG_IBRD.
* ----------^----------^----------^----------^-----
*/
pl011_write_lcr_h(uap, lcr_h);
- writew(old_cr, port->membase + UART011_CR);
+ pl011_write(old_cr, uap, REG_CR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -2052,9 +2149,9 @@ static void pl011_console_putchar(struct uart_port *port, int ch)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+ while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
barrier();
- writew(ch, uap->port.membase + UART01x_DR);
+ pl011_write(ch, uap, REG_DR);
}
static void
@@ -2079,10 +2176,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* First save the CR then disable the interrupts
*/
if (!uap->vendor->always_enabled) {
- old_cr = readw(uap->port.membase + UART011_CR);
+ old_cr = pl011_read(uap, REG_CR);
new_cr = old_cr & ~UART011_CR_CTSEN;
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- writew(new_cr, uap->port.membase + UART011_CR);
+ pl011_write(new_cr, uap, REG_CR);
}
uart_console_write(&uap->port, s, count, pl011_console_putchar);
@@ -2092,10 +2189,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* and restore the TCR
*/
do {
- status = readw(uap->port.membase + UART01x_FR);
+ status = pl011_read(uap, REG_FR);
} while (status & UART01x_FR_BUSY);
if (!uap->vendor->always_enabled)
- writew(old_cr, uap->port.membase + UART011_CR);
+ pl011_write(old_cr, uap, REG_CR);
if (locked)
spin_unlock(&uap->port.lock);
@@ -2108,10 +2205,10 @@ static void __init
pl011_console_get_options(struct uart_amba_port *uap, int *baud,
int *parity, int *bits)
{
- if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
+ if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, ibrd, fbrd;
- lcr_h = readw(uap->port.membase + uap->lcrh_tx);
+ lcr_h = pl011_read(uap, REG_LCRH_TX);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
@@ -2126,13 +2223,13 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
else
*bits = 8;
- ibrd = readw(uap->port.membase + UART011_IBRD);
- fbrd = readw(uap->port.membase + UART011_FBRD);
+ ibrd = pl011_read(uap, REG_IBRD);
+ fbrd = pl011_read(uap, REG_FBRD);
*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
if (uap->vendor->oversampling) {
- if (readw(uap->port.membase + UART011_CR)
+ if (pl011_read(uap, REG_CR)
& ST_UART011_CR_OVSFACT)
*baud *= 2;
}
@@ -2206,7 +2303,10 @@ static void pl011_putc(struct uart_port *port, int c)
{
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
;
- writeb(c, port->membase + UART01x_DR);
+ if (port->iotype == UPIO_MEM32)
+ writel(c, port->membase + UART01x_DR);
+ else
+ writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
;
}
@@ -2319,7 +2419,6 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
uap->port.dev = dev;
uap->port.mapbase = mmiobase->start;
uap->port.membase = base;
- uap->port.iotype = UPIO_MEM;
uap->port.fifosize = uap->fifosize;
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = index;
@@ -2334,8 +2433,8 @@ static int pl011_register_port(struct uart_amba_port *uap)
int ret;
/* Ensure interrupts from this UART are masked and cleared */
- writew(0, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ pl011_write(0, uap, REG_IMSC);
+ pl011_write(0xffff, uap, REG_ICR);
if (!amba_reg.state) {
ret = uart_register_driver(&amba_reg);
@@ -2372,10 +2471,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (IS_ERR(uap->clk))
return PTR_ERR(uap->clk);
+ uap->reg_offset = vendor->reg_offset;
uap->vendor = vendor;
- uap->lcrh_rx = vendor->lcrh_rx;
- uap->lcrh_tx = vendor->lcrh_tx;
uap->fifosize = vendor->get_fifosize(dev);
+ uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
uap->port.irq = dev->irq[0];
uap->port.ops = &amba_pl011_pops;
@@ -2453,8 +2552,10 @@ static int sbsa_uart_probe(struct platform_device *pdev)
if (!uap)
return -ENOMEM;
+ uap->reg_offset = vendor_sbsa.reg_offset;
uap->vendor = &vendor_sbsa;
uap->fifosize = 32;
+ uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM;
uap->port.irq = platform_get_irq(pdev, 0);
uap->port.ops = &sbsa_uart_pops;
uap->fixed_baud = baudrate;
diff --git a/drivers/tty/serial/amba-pl011.h b/drivers/tty/serial/amba-pl011.h
new file mode 100644
index 000000000000..411c60e1f9a4
--- /dev/null
+++ b/drivers/tty/serial/amba-pl011.h
@@ -0,0 +1,34 @@
+#ifndef AMBA_PL011_H
+#define AMBA_PL011_H
+
+enum {
+ REG_DR,
+ REG_ST_DMAWM,
+ REG_ST_TIMEOUT,
+ REG_FR,
+ REG_LCRH_RX,
+ REG_LCRH_TX,
+ REG_IBRD,
+ REG_FBRD,
+ REG_CR,
+ REG_IFLS,
+ REG_IMSC,
+ REG_RIS,
+ REG_MIS,
+ REG_ICR,
+ REG_DMACR,
+ REG_ST_XFCR,
+ REG_ST_XON1,
+ REG_ST_XON2,
+ REG_ST_XOFF1,
+ REG_ST_XOFF2,
+ REG_ST_ITCR,
+ REG_ST_ITIP,
+ REG_ST_ABCR,
+ REG_ST_ABIMSC,
+
+ /* The size of the array - must be last */
+ REG_ARRAY_SIZE,
+};
+
+#endif
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 94294558943c..1c0884d8ef32 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -155,7 +154,6 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct mctrl_gpios *gpios;
- int gpio_irq[UART_GPIO_MAX];
unsigned int tx_done_mask;
u32 fifo_size;
u32 rts_high;
@@ -190,8 +188,6 @@ static const struct of_device_id atmel_serial_dt_ids[] = {
{ .compatible = "atmel,at91sam9260-usart" },
{ /* sentinel */ }
};
-
-MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
#endif
static inline struct atmel_uart_port *
@@ -550,27 +546,21 @@ static void atmel_enable_ms(struct uart_port *port)
atmel_port->ms_irq_enabled = true;
- if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
ier |= ATMEL_US_CTSIC;
- if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR))
ier |= ATMEL_US_DSRIC;
- if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI))
ier |= ATMEL_US_RIIC;
- if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
- enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD))
ier |= ATMEL_US_DCDIC;
atmel_uart_writel(port, ATMEL_US_IER, ier);
+
+ mctrl_gpio_enable_ms(atmel_port->gpios);
}
/*
@@ -589,24 +579,18 @@ static void atmel_disable_ms(struct uart_port *port)
atmel_port->ms_irq_enabled = false;
- if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
- else
+ mctrl_gpio_disable_ms(atmel_port->gpios);
+
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
idr |= ATMEL_US_CTSIC;
- if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR))
idr |= ATMEL_US_DSRIC;
- if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI))
idr |= ATMEL_US_RIIC;
- if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
- disable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
- else
+ if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD))
idr |= ATMEL_US_DCDIC;
atmel_uart_writel(port, ATMEL_US_IDR, idr);
@@ -1264,7 +1248,6 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
struct uart_port *port = dev_id;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, pending, mask, pass_counter = 0;
- bool gpio_handled = false;
spin_lock(&atmel_port->lock_suspended);
@@ -1272,24 +1255,6 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
status = atmel_get_lines_status(port);
mask = atmel_uart_readl(port, ATMEL_US_IMR);
pending = status & mask;
- if (!gpio_handled) {
- /*
- * Dealing with GPIO interrupt
- */
- if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
- pending |= ATMEL_US_CTSIC;
-
- if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
- pending |= ATMEL_US_DSRIC;
-
- if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
- pending |= ATMEL_US_RIIC;
-
- if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
- pending |= ATMEL_US_DCDIC;
-
- gpio_handled = true;
- }
if (!pending)
break;
@@ -1778,45 +1743,6 @@ static void atmel_get_ip_name(struct uart_port *port)
}
}
-static void atmel_free_gpio_irq(struct uart_port *port)
-{
- struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- enum mctrl_gpio_idx i;
-
- for (i = 0; i < UART_GPIO_MAX; i++)
- if (atmel_port->gpio_irq[i] >= 0)
- free_irq(atmel_port->gpio_irq[i], port);
-}
-
-static int atmel_request_gpio_irq(struct uart_port *port)
-{
- struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- int *irq = atmel_port->gpio_irq;
- enum mctrl_gpio_idx i;
- int err = 0;
-
- for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
- if (irq[i] < 0)
- continue;
-
- irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
- err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
- "atmel_serial", port);
- if (err)
- dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
- irq[i]);
- }
-
- /*
- * If something went wrong, rollback.
- */
- while (err && (--i >= 0))
- if (irq[i] >= 0)
- free_irq(irq[i], port);
-
- return err;
-}
-
/*
* Perform initialization and enable port for reception
*/
@@ -1846,13 +1772,6 @@ static int atmel_startup(struct uart_port *port)
return retval;
}
- /*
- * Get the GPIO lines IRQ
- */
- retval = atmel_request_gpio_irq(port);
- if (retval)
- goto free_irq;
-
tasklet_enable(&atmel_port->tasklet);
/*
@@ -1948,11 +1867,6 @@ static int atmel_startup(struct uart_port *port)
}
return 0;
-
-free_irq:
- free_irq(port->irq, port);
-
- return retval;
}
/*
@@ -2018,7 +1932,6 @@ static void atmel_shutdown(struct uart_port *port)
* Free the interrupts
*/
free_irq(port->irq, port);
- atmel_free_gpio_irq(port);
atmel_port->ms_irq_enabled = false;
@@ -2686,26 +2599,6 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
-static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
-{
- enum mctrl_gpio_idx i;
- struct gpio_desc *gpiod;
-
- p->gpios = mctrl_gpio_init_noauto(dev, 0);
- if (IS_ERR(p->gpios))
- return PTR_ERR(p->gpios);
-
- for (i = 0; i < UART_GPIO_MAX; i++) {
- gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
- if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
- p->gpio_irq[i] = gpiod_to_irq(gpiod);
- else
- p->gpio_irq[i] = -EINVAL;
- }
-
- return 0;
-}
-
static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
struct platform_device *pdev)
{
@@ -2788,16 +2681,16 @@ static int atmel_serial_probe(struct platform_device *pdev)
spin_lock_init(&port->lock_suspended);
- ret = atmel_init_gpios(port, &pdev->dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to initialize GPIOs.");
- goto err_clear_bit;
- }
-
ret = atmel_init_port(port, pdev);
if (ret)
goto err_clear_bit;
+ port->gpios = mctrl_gpio_init(&port->uart, 0);
+ if (IS_ERR(port->gpios)) {
+ ret = PTR_ERR(port->gpios);
+ goto err_clear_bit;
+ }
+
if (!atmel_use_pdc_rx(&port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
@@ -2866,37 +2759,14 @@ err:
return ret;
}
-static int atmel_serial_remove(struct platform_device *pdev)
-{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- int ret = 0;
-
- tasklet_kill(&atmel_port->tasklet);
-
- device_init_wakeup(&pdev->dev, 0);
-
- ret = uart_remove_one_port(&atmel_uart, port);
-
- kfree(atmel_port->rx_ring.buf);
-
- /* "port" is allocated statically, so we shouldn't free it */
-
- clear_bit(port->line, atmel_ports_in_use);
-
- clk_put(atmel_port->clk);
-
- return ret;
-}
-
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
- .remove = atmel_serial_remove,
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.driver = {
- .name = "atmel_usart",
- .of_match_table = of_match_ptr(atmel_serial_dt_ids),
+ .name = "atmel_usart",
+ .of_match_table = of_match_ptr(atmel_serial_dt_ids),
+ .suppress_bind_attrs = true,
},
};
@@ -2914,17 +2784,4 @@ static int __init atmel_serial_init(void)
return ret;
}
-
-static void __exit atmel_serial_exit(void)
-{
- platform_driver_unregister(&atmel_serial_driver);
- uart_unregister_driver(&atmel_uart);
-}
-
-module_init(atmel_serial_init);
-module_exit(atmel_serial_exit);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:atmel_usart");
+device_initcall(atmel_serial_init);
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index a1c0a89d9c7f..c28e5c24da16 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -653,7 +653,7 @@ static struct uart_ops bcm_uart_ops = {
#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
+static void wait_for_xmitr(struct uart_port *port)
{
unsigned int tmout;
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index ae3cf94b146b..293ecbb00684 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -213,7 +213,7 @@ static void bfin_serial_stop_rx(struct uart_port *port)
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
unsigned int status, ch, flg;
- static struct timeval anomaly_start = { .tv_sec = 0 };
+ static u64 anomaly_start;
status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
@@ -246,27 +246,24 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
* character time +/- some percent. So 1.5 sounds good. All other
* Blackfin families operate properly. Woo.
*/
- if (anomaly_start.tv_sec) {
- struct timeval curr;
- suseconds_t usecs;
+ if (anomaly_start > 0) {
+ u64 curr, nsecs, threshold_ns;
if ((~ch & (~ch + 1)) & 0xff)
goto known_good_char;
- do_gettimeofday(&curr);
- if (curr.tv_sec - anomaly_start.tv_sec > 1)
+ curr = ktime_get_ns();
+ nsecs = curr - anomaly_start;
+ if (nsecs >> 32)
goto known_good_char;
- usecs = 0;
- if (curr.tv_sec != anomaly_start.tv_sec)
- usecs += USEC_PER_SEC;
- usecs += curr.tv_usec - anomaly_start.tv_usec;
-
- if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
+ threshold_ns = UART_GET_ANOMALY_THRESHOLD(uart)
+ * NSEC_PER_USEC;
+ if (nsecs > threshold_ns)
goto known_good_char;
if (ch)
- anomaly_start.tv_sec = 0;
+ anomaly_start = 0;
else
anomaly_start = curr;
@@ -274,14 +271,14 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
known_good_char:
status &= ~BI;
- anomaly_start.tv_sec = 0;
+ anomaly_start = 0;
}
}
if (status & BI) {
if (ANOMALY_05000363)
if (bfin_revid() < 5)
- do_gettimeofday(&anomaly_start);
+ anomaly_start = ktime_get_ns();
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index b5b2f2be6be7..3f2423690d01 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -71,10 +71,16 @@ static int __init parse_options(struct earlycon_device *device, char *options)
return -EINVAL;
switch (port->iotype) {
+ case UPIO_MEM:
+ port->mapbase = addr;
+ break;
+ case UPIO_MEM16:
+ port->regshift = 1;
+ port->mapbase = addr;
+ break;
case UPIO_MEM32:
case UPIO_MEM32BE:
- port->regshift = 2; /* fall-through */
- case UPIO_MEM:
+ port->regshift = 2;
port->mapbase = addr;
break;
case UPIO_PORT:
@@ -91,10 +97,11 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length);
}
- if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 ||
- port->iotype == UPIO_MEM32BE)
+ if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
+ port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
(port->iotype == UPIO_MEM) ? "" :
+ (port->iotype == UPIO_MEM16) ? "16" :
(port->iotype == UPIO_MEM32) ? "32" : "32be",
(unsigned long long)port->mapbase,
device->options);
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index ffc7cb2585a6..c60a8d5e4020 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#define SERIAL_DO_RESTART
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 016e4be05cec..9362f54c816c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -44,6 +44,8 @@
#include <linux/platform_data/serial-imx.h>
#include <linux/platform_data/dma-imx.h>
+#include "serial_mctrl_gpio.h"
+
/* Register definitions */
#define URXD0 0x0 /* Receiver Register */
#define URTX0 0x40 /* Transmitter Register */
@@ -148,8 +150,11 @@
#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
#define USR2_IDLE (1<<12) /* Idle condition */
+#define USR2_RIDELT (1<<10) /* Ring Interrupt Delta */
+#define USR2_RIIN (1<<9) /* Ring Indicator Input */
#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
#define USR2_WAKE (1<<7) /* Wake */
+#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
#define USR2_TXDC (1<<3) /* Transmitter complete */
#define USR2_BRCD (1<<2) /* Break condition */
@@ -206,6 +211,8 @@ struct imx_port {
struct clk *clk_per;
const struct imx_uart_data *devdata;
+ struct mctrl_gpios *gpios;
+
/* DMA fields */
unsigned int dma_is_inited:1;
unsigned int dma_is_enabled:1;
@@ -308,49 +315,24 @@ static void imx_port_ucrs_restore(struct uart_port *port,
}
#endif
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void imx_mctrl_check(struct imx_port *sport)
+static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
{
- unsigned int status, changed;
-
- status = sport->port.ops->get_mctrl(&sport->port);
- changed = status ^ sport->old_status;
-
- if (changed == 0)
- return;
-
- sport->old_status = status;
+ *ucr2 &= ~UCR2_CTSC;
+ *ucr2 |= UCR2_CTS;
- if (changed & TIOCM_RI)
- sport->port.icount.rng++;
- if (changed & TIOCM_DSR)
- sport->port.icount.dsr++;
- if (changed & TIOCM_CAR)
- uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
- if (changed & TIOCM_CTS)
- uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
- wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+ mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS);
}
-/*
- * This is our per-port timeout handler, for checking the
- * modem status signals.
- */
-static void imx_timeout(unsigned long data)
+static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
{
- struct imx_port *sport = (struct imx_port *)data;
- unsigned long flags;
+ *ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
- if (sport->port.state) {
- spin_lock_irqsave(&sport->port.lock, flags);
- imx_mctrl_check(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS);
+}
- mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
- }
+static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2)
+{
+ *ucr2 |= UCR2_CTSC;
}
/*
@@ -376,9 +358,9 @@ static void imx_stop_tx(struct uart_port *port)
readl(port->membase + USR2) & USR2_TXDC) {
temp = readl(port->membase + UCR2);
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
- temp &= ~UCR2_CTS;
+ imx_port_rts_inactive(sport, &temp);
else
- temp |= UCR2_CTS;
+ imx_port_rts_active(sport, &temp);
writel(temp, port->membase + UCR2);
temp = readl(port->membase + UCR4);
@@ -420,6 +402,8 @@ static void imx_enable_ms(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
mod_timer(&sport->timer, jiffies);
+
+ mctrl_gpio_enable_ms(sport->gpios);
}
static void imx_dma_tx(struct imx_port *sport);
@@ -579,14 +563,14 @@ static void imx_start_tx(struct uart_port *port)
unsigned long temp;
if (port->rs485.flags & SER_RS485_ENABLED) {
- /* enable transmitter and shifter empty irq */
temp = readl(port->membase + UCR2);
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
- temp &= ~UCR2_CTS;
+ imx_port_rts_inactive(sport, &temp);
else
- temp |= UCR2_CTS;
+ imx_port_rts_active(sport, &temp);
writel(temp, port->membase + UCR2);
+ /* enable transmitter and shifter empty irq */
temp = readl(port->membase + UCR4);
temp |= UCR4_TCEN;
writel(temp, port->membase + UCR4);
@@ -801,23 +785,35 @@ static unsigned int imx_tx_empty(struct uart_port *port)
/*
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
*/
-static unsigned int imx_get_mctrl(struct uart_port *port)
+static unsigned int imx_get_hwmctrl(struct imx_port *sport)
{
- struct imx_port *sport = (struct imx_port *)port;
- unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+ unsigned int tmp = TIOCM_DSR;
+ unsigned usr1 = readl(sport->port.membase + USR1);
- if (readl(sport->port.membase + USR1) & USR1_RTSS)
+ if (usr1 & USR1_RTSS)
tmp |= TIOCM_CTS;
- if (readl(sport->port.membase + UCR2) & UCR2_CTS)
- tmp |= TIOCM_RTS;
+ /* in DCE mode DCDIN is always 0 */
+ if (!(usr1 & USR2_DCDIN))
+ tmp |= TIOCM_CAR;
- if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP)
- tmp |= TIOCM_LOOP;
+ /* in DCE mode RIIN is always 0 */
+ if (readl(sport->port.membase + USR2) & USR2_RIIN)
+ tmp |= TIOCM_RI;
return tmp;
}
+static unsigned int imx_get_mctrl(struct uart_port *port)
+{
+ struct imx_port *sport = (struct imx_port *)port;
+ unsigned int ret = imx_get_hwmctrl(sport);
+
+ mctrl_gpio_get(sport->gpios, &ret);
+
+ return ret;
+}
+
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -831,10 +827,17 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
writel(temp, sport->port.membase + UCR2);
}
+ temp = readl(sport->port.membase + UCR3) & ~UCR3_DSR;
+ if (!(mctrl & TIOCM_DTR))
+ temp |= UCR3_DSR;
+ writel(temp, sport->port.membase + UCR3);
+
temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP;
if (mctrl & TIOCM_LOOP)
temp |= UTS_LOOP;
writel(temp, sport->port.membase + uts_reg(sport));
+
+ mctrl_gpio_set(sport->gpios, mctrl);
}
/*
@@ -857,6 +860,51 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&sport->port.lock, flags);
}
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void imx_mctrl_check(struct imx_port *sport)
+{
+ unsigned int status, changed;
+
+ status = imx_get_hwmctrl(sport);
+ changed = status ^ sport->old_status;
+
+ if (changed == 0)
+ return;
+
+ sport->old_status = status;
+
+ if (changed & TIOCM_RI)
+ sport->port.icount.rng++;
+ if (changed & TIOCM_DSR)
+ sport->port.icount.dsr++;
+ if (changed & TIOCM_CAR)
+ uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+ if (changed & TIOCM_CTS)
+ uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+ wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void imx_timeout(unsigned long data)
+{
+ struct imx_port *sport = (struct imx_port *)data;
+ unsigned long flags;
+
+ if (sport->port.state) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ imx_mctrl_check(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+ }
+}
+
#define RX_BUF_SIZE (PAGE_SIZE)
static void imx_rx_dma_done(struct imx_port *sport)
{
@@ -1207,6 +1255,8 @@ static void imx_shutdown(struct uart_port *port)
imx_uart_dma_exit(sport);
}
+ mctrl_gpio_disable_ms(sport->gpios);
+
spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
@@ -1284,9 +1334,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
- unsigned int ucr2, old_ucr1, old_ucr2, baud, quot;
+ unsigned long ucr2, old_ucr1, old_ucr2;
+ unsigned int baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- unsigned int div, ufcr;
+ unsigned long div, ufcr;
unsigned long num, denom;
uint64_t tdiv64;
@@ -1315,19 +1366,25 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
* it under manual control and keep transmitter
* disabled.
*/
- if (!(port->rs485.flags &
- SER_RS485_RTS_AFTER_SEND))
- ucr2 |= UCR2_CTS;
+ if (port->rs485.flags &
+ SER_RS485_RTS_AFTER_SEND)
+ imx_port_rts_inactive(sport, &ucr2);
+ else
+ imx_port_rts_active(sport, &ucr2);
} else {
- ucr2 |= UCR2_CTSC;
+ imx_port_rts_auto(sport, &ucr2);
}
} else {
termios->c_cflag &= ~CRTSCTS;
}
- } else if (port->rs485.flags & SER_RS485_ENABLED)
+ } else if (port->rs485.flags & SER_RS485_ENABLED) {
/* disable transmitter */
- if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
- ucr2 |= UCR2_CTS;
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ imx_port_rts_inactive(sport, &ucr2);
+ else
+ imx_port_rts_active(sport, &ucr2);
+ }
+
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
@@ -1568,11 +1625,10 @@ static int imx_rs485_config(struct uart_port *port,
/* disable transmitter */
temp = readl(sport->port.membase + UCR2);
- temp &= ~UCR2_CTSC;
if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
- temp &= ~UCR2_CTS;
+ imx_port_rts_inactive(sport, &temp);
else
- temp |= UCR2_CTS;
+ imx_port_rts_active(sport, &temp);
writel(temp, sport->port.membase + UCR2);
}
@@ -1857,11 +1913,10 @@ static int serial_imx_probe_dt(struct imx_port *sport,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *of_id =
- of_match_device(imx_uart_dt_ids, &pdev->dev);
int ret;
- if (!np)
+ sport->devdata = of_device_get_match_data(&pdev->dev);
+ if (!sport->devdata)
/* no device tree device */
return 1;
@@ -1878,8 +1933,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
if (of_get_property(np, "fsl,dte-mode", NULL))
sport->dte_mode = 1;
- sport->devdata = of_id->data;
-
return 0;
}
#else
@@ -1948,6 +2001,10 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
+ sport->gpios = mctrl_gpio_init(&sport->port, 0);
+ if (IS_ERR(sport->gpios))
+ return PTR_ERR(sport->gpios);
+
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index efbd87a76656..a119f11bf2f4 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -70,7 +70,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out;
}
- rc = pci_request_regions(pdev, "jsm");
+ rc = pci_request_regions(pdev, JSM_DRIVER_NAME);
if (rc) {
dev_err(&pdev->dev, "pci_request_region FAILED\n");
goto out_disable_device;
@@ -328,7 +328,7 @@ static struct pci_device_id jsm_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
static struct pci_driver jsm_driver = {
- .name = "jsm",
+ .name = JSM_DRIVER_NAME,
.id_table = jsm_pci_tbl,
.probe = jsm_probe_one,
.remove = jsm_remove_one,
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 932b2accd06f..c6fdd6369534 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -714,7 +714,7 @@ static void neo_clear_break(struct jsm_channel *ch)
/*
* Parse the ISR register.
*/
-static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
+static void neo_parse_isr(struct jsm_board *brd, u32 port)
{
struct jsm_channel *ch;
u8 isr;
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index 8f7f83a14c93..0eeb64f2499c 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -990,7 +990,7 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
/*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct uart_sio_port *up)
+static void wait_for_xmitr(struct uart_sio_port *up)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index d45133056f51..3f98165b479c 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1174,7 +1174,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
#ifdef CONFIG_GPIOLIB
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
- s->gpio.dev = dev;
+ s->gpio.parent = dev;
s->gpio.label = dev_name(dev);
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 3141aa20843d..a44290e9b5a8 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -158,7 +158,7 @@ static inline void men_z135_reg_set(struct men_z135_port *uart,
* @addr: Register address
* @val: value to clear
*/
-static inline void men_z135_reg_clr(struct men_z135_port *uart,
+static void men_z135_reg_clr(struct men_z135_port *uart,
u32 addr, u32 val)
{
struct uart_port *port = &uart->port;
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 0fc83c962d10..b12a37bd37b6 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -57,6 +57,7 @@
#define AML_UART_RX_EMPTY BIT(20)
#define AML_UART_TX_FULL BIT(21)
#define AML_UART_TX_EMPTY BIT(22)
+#define AML_UART_XMIT_BUSY BIT(25)
#define AML_UART_ERR (AML_UART_PARITY_ERR | \
AML_UART_FRAME_ERR | \
AML_UART_TX_FIFO_WERR)
@@ -100,7 +101,8 @@ static unsigned int meson_uart_tx_empty(struct uart_port *port)
u32 val;
val = readl(port->membase + AML_UART_STATUS);
- return (val & AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
+ val &= (AML_UART_TX_EMPTY | AML_UART_XMIT_BUSY);
+ return (val == AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
}
static void meson_uart_stop_tx(struct uart_port *port)
@@ -108,7 +110,7 @@ static void meson_uart_stop_tx(struct uart_port *port)
u32 val;
val = readl(port->membase + AML_UART_CONTROL);
- val &= ~AML_UART_TX_EN;
+ val &= ~AML_UART_TX_INT_EN;
writel(val, port->membase + AML_UART_CONTROL);
}
@@ -131,7 +133,7 @@ static void meson_uart_shutdown(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
val = readl(port->membase + AML_UART_CONTROL);
- val &= ~(AML_UART_RX_EN | AML_UART_TX_EN);
+ val &= ~AML_UART_RX_EN;
val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
writel(val, port->membase + AML_UART_CONTROL);
@@ -142,6 +144,7 @@ static void meson_uart_start_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned int ch;
+ u32 val;
if (uart_tx_stopped(port)) {
meson_uart_stop_tx(port);
@@ -165,6 +168,12 @@ static void meson_uart_start_tx(struct uart_port *port)
port->icount.tx++;
}
+ if (!uart_circ_empty(xmit)) {
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= AML_UART_TX_INT_EN;
+ writel(val, port->membase + AML_UART_CONTROL);
+ }
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -228,8 +237,10 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
meson_receive_chars(port);
- if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL))
- meson_uart_start_tx(port);
+ if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
+ if (readl(port->membase + AML_UART_CONTROL) & AML_UART_TX_INT_EN)
+ meson_uart_start_tx(port);
+ }
spin_unlock(&port->lock);
@@ -241,10 +252,9 @@ static const char *meson_uart_type(struct uart_port *port)
return (port->type == PORT_MESON) ? "meson_uart" : NULL;
}
-static int meson_uart_startup(struct uart_port *port)
+static void meson_uart_reset(struct uart_port *port)
{
u32 val;
- int ret = 0;
val = readl(port->membase + AML_UART_CONTROL);
val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
@@ -252,6 +262,18 @@ static int meson_uart_startup(struct uart_port *port)
val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
writel(val, port->membase + AML_UART_CONTROL);
+}
+
+static int meson_uart_startup(struct uart_port *port)
+{
+ u32 val;
+ int ret = 0;
+
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= AML_UART_CLR_ERR;
+ writel(val, port->membase + AML_UART_CONTROL);
+ val &= ~AML_UART_CLR_ERR;
+ writel(val, port->membase + AML_UART_CONTROL);
val |= (AML_UART_RX_EN | AML_UART_TX_EN);
writel(val, port->membase + AML_UART_CONTROL);
@@ -272,7 +294,7 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
{
u32 val;
- while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_EMPTY))
+ while (!meson_uart_tx_empty(port))
cpu_relax();
val = readl(port->membase + AML_UART_REG5);
@@ -367,9 +389,26 @@ static int meson_uart_verify_port(struct uart_port *port,
return ret;
}
+static int meson_uart_res_size(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(port->dev, "cannot obtain I/O memory region");
+ return -ENODEV;
+ }
+
+ return resource_size(res);
+}
+
static void meson_uart_release_port(struct uart_port *port)
{
+ int size = meson_uart_res_size(port);
+
if (port->flags & UPF_IOREMAP) {
+ devm_release_mem_region(port->dev, port->mapbase, size);
devm_iounmap(port->dev, port->membase);
port->membase = NULL;
}
@@ -377,16 +416,10 @@ static void meson_uart_release_port(struct uart_port *port)
static int meson_uart_request_port(struct uart_port *port)
{
- struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *res;
- int size;
+ int size = meson_uart_res_size(port);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "cannot obtain I/O memory region");
- return -ENODEV;
- }
- size = resource_size(res);
+ if (size < 0)
+ return size;
if (!devm_request_mem_region(port->dev, port->mapbase, size,
dev_name(port->dev))) {
@@ -448,6 +481,7 @@ static void meson_serial_console_write(struct console *co, const char *s,
struct uart_port *port;
unsigned long flags;
int locked;
+ u32 val, tmp;
port = meson_ports[co->index];
if (!port)
@@ -463,7 +497,13 @@ static void meson_serial_console_write(struct console *co, const char *s,
locked = 1;
}
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= AML_UART_TX_EN;
+ tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
+ writel(tmp, port->membase + AML_UART_CONTROL);
+
uart_console_write(port, s, count, meson_console_putchar);
+ writel(val, port->membase + AML_UART_CONTROL);
if (locked)
spin_unlock(&port->lock);
@@ -570,6 +610,12 @@ static int meson_uart_probe(struct platform_device *pdev)
meson_ports[pdev->id] = port;
platform_set_drvdata(pdev, port);
+ /* reset port before registering (and possibly registering console) */
+ if (meson_uart_request_port(port) >= 0) {
+ meson_uart_reset(port);
+ meson_uart_release_port(port);
+ }
+
ret = uart_add_one_port(&meson_uart_driver, port);
if (ret)
meson_ports[pdev->id] = NULL;
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
deleted file mode 100644
index 5da7622e88c3..000000000000
--- a/drivers/tty/serial/nwpserial.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Serial Port driver for a NWP uart device
- *
- * Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.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.
- *
- */
-#include <linux/init.h>
-#include <linux/export.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/irqreturn.h>
-#include <linux/mutex.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/nwpserial.h>
-#include <linux/delay.h>
-#include <asm/prom.h>
-#include <asm/dcr.h>
-
-#define NWPSERIAL_NR 2
-
-#define NWPSERIAL_STATUS_RXVALID 0x1
-#define NWPSERIAL_STATUS_TXFULL 0x2
-
-struct nwpserial_port {
- struct uart_port port;
- dcr_host_t dcr_host;
- unsigned int ier;
- unsigned int mcr;
-};
-
-static DEFINE_MUTEX(nwpserial_mutex);
-static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
-
-static void wait_for_bits(struct nwpserial_port *up, int bits)
-{
- unsigned int status, tmout = 10000;
-
- /* Wait up to 10ms for the character(s) to be sent. */
- do {
- status = dcr_read(up->dcr_host, UART_LSR);
-
- if (--tmout == 0)
- break;
- udelay(1);
- } while ((status & bits) != bits);
-}
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static void nwpserial_console_putchar(struct uart_port *port, int c)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
- /* check if tx buffer is full */
- wait_for_bits(up, UART_LSR_THRE);
- dcr_write(up->dcr_host, UART_TX, c);
- up->port.icount.tx++;
-}
-
-static void
-nwpserial_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct nwpserial_port *up = &nwpserial_ports[co->index];
- unsigned long flags;
- int locked = 1;
-
- if (oops_in_progress)
- locked = spin_trylock_irqsave(&up->port.lock, flags);
- else
- spin_lock_irqsave(&up->port.lock, flags);
-
- /* save and disable interrupt */
- up->ier = dcr_read(up->dcr_host, UART_IER);
- dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
-
- uart_console_write(&up->port, s, count, nwpserial_console_putchar);
-
- /* wait for transmitter to become empty */
- while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
- cpu_relax();
-
- /* restore interrupt state */
- dcr_write(up->dcr_host, UART_IER, up->ier);
-
- if (locked)
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static struct uart_driver nwpserial_reg;
-static struct console nwpserial_console = {
- .name = "ttySQ",
- .write = nwpserial_console_write,
- .device = uart_console_device,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &nwpserial_reg,
-};
-#define NWPSERIAL_CONSOLE (&nwpserial_console)
-#else
-#define NWPSERIAL_CONSOLE NULL
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
-
-/**************************************************************************/
-
-static int nwpserial_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-static void nwpserial_release_port(struct uart_port *port)
-{
- /* N/A */
-}
-
-static void nwpserial_config_port(struct uart_port *port, int flags)
-{
- port->type = PORT_NWPSERIAL;
-}
-
-static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
-{
- struct nwpserial_port *up = dev_id;
- struct tty_port *port = &up->port.state->port;
- irqreturn_t ret;
- unsigned int iir;
- unsigned char ch;
-
- spin_lock(&up->port.lock);
-
- /* check if the uart was the interrupt source. */
- iir = dcr_read(up->dcr_host, UART_IIR);
- if (!iir) {
- ret = IRQ_NONE;
- goto out;
- }
-
- do {
- up->port.icount.rx++;
- ch = dcr_read(up->dcr_host, UART_RX);
- if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
- tty_insert_flip_char(port, ch, TTY_NORMAL);
- } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
-
- spin_unlock(&up->port.lock);
- tty_flip_buffer_push(port);
- spin_lock(&up->port.lock);
-
- ret = IRQ_HANDLED;
-
- /* clear interrupt */
- dcr_write(up->dcr_host, UART_IIR, 1);
-out:
- spin_unlock(&up->port.lock);
- return ret;
-}
-
-static int nwpserial_startup(struct uart_port *port)
-{
- struct nwpserial_port *up;
- int err;
-
- up = container_of(port, struct nwpserial_port, port);
-
- /* disable flow control by default */
- up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
- dcr_write(up->dcr_host, UART_MCR, up->mcr);
-
- /* register interrupt handler */
- err = request_irq(up->port.irq, nwpserial_interrupt,
- IRQF_SHARED, "nwpserial", up);
- if (err)
- return err;
-
- /* enable interrupts */
- up->ier = UART_IER_RDI;
- dcr_write(up->dcr_host, UART_IER, up->ier);
-
- /* enable receiving */
- up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
-
- return 0;
-}
-
-static void nwpserial_shutdown(struct uart_port *port)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
-
- /* disable receiving */
- up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
- /* disable interrupts from this port */
- up->ier = 0;
- dcr_write(up->dcr_host, UART_IER, up->ier);
-
- /* free irq */
- free_irq(up->port.irq, up);
-}
-
-static int nwpserial_verify_port(struct uart_port *port,
- struct serial_struct *ser)
-{
- return -EINVAL;
-}
-
-static const char *nwpserial_type(struct uart_port *port)
-{
- return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
-}
-
-static void nwpserial_set_termios(struct uart_port *port,
- struct ktermios *termios, struct ktermios *old)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
-
- up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
- | NWPSERIAL_STATUS_TXFULL;
-
- up->port.ignore_status_mask = 0;
- /* ignore all characters if CREAD is not set */
- if ((termios->c_cflag & CREAD) == 0)
- up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
-
- /* Copy back the old hardware settings */
- if (old)
- tty_termios_copy_hw(termios, old);
-}
-
-static void nwpserial_break_ctl(struct uart_port *port, int ctl)
-{
- /* N/A */
-}
-
-static void nwpserial_stop_rx(struct uart_port *port)
-{
- struct nwpserial_port *up;
- up = container_of(port, struct nwpserial_port, port);
- /* don't forward any more data (like !CREAD) */
- up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
-}
-
-static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
-{
- /* check if tx buffer is full */
- wait_for_bits(up, UART_LSR_THRE);
- dcr_write(up->dcr_host, UART_TX, c);
- up->port.icount.tx++;
-}
-
-static void nwpserial_start_tx(struct uart_port *port)
-{
- struct nwpserial_port *up;
- struct circ_buf *xmit;
- up = container_of(port, struct nwpserial_port, port);
- xmit = &up->port.state->xmit;
-
- if (port->x_char) {
- nwpserial_putchar(up, up->port.x_char);
- port->x_char = 0;
- }
-
- while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
- nwpserial_putchar(up, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
- }
-}
-
-static unsigned int nwpserial_get_mctrl(struct uart_port *port)
-{
- return 0;
-}
-
-static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- /* N/A */
-}
-
-static void nwpserial_stop_tx(struct uart_port *port)
-{
- /* N/A */
-}
-
-static unsigned int nwpserial_tx_empty(struct uart_port *port)
-{
- struct nwpserial_port *up;
- unsigned long flags;
- int ret;
- up = container_of(port, struct nwpserial_port, port);
-
- spin_lock_irqsave(&up->port.lock, flags);
- ret = dcr_read(up->dcr_host, UART_LSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
-}
-
-static struct uart_ops nwpserial_pops = {
- .tx_empty = nwpserial_tx_empty,
- .set_mctrl = nwpserial_set_mctrl,
- .get_mctrl = nwpserial_get_mctrl,
- .stop_tx = nwpserial_stop_tx,
- .start_tx = nwpserial_start_tx,
- .stop_rx = nwpserial_stop_rx,
- .break_ctl = nwpserial_break_ctl,
- .startup = nwpserial_startup,
- .shutdown = nwpserial_shutdown,
- .set_termios = nwpserial_set_termios,
- .type = nwpserial_type,
- .release_port = nwpserial_release_port,
- .request_port = nwpserial_request_port,
- .config_port = nwpserial_config_port,
- .verify_port = nwpserial_verify_port,
-};
-
-static struct uart_driver nwpserial_reg = {
- .owner = THIS_MODULE,
- .driver_name = "nwpserial",
- .dev_name = "ttySQ",
- .major = TTY_MAJOR,
- .minor = 68,
- .nr = NWPSERIAL_NR,
- .cons = NWPSERIAL_CONSOLE,
-};
-
-int nwpserial_register_port(struct uart_port *port)
-{
- struct nwpserial_port *up = NULL;
- int ret = -1;
- int i;
- static int first = 1;
- int dcr_len;
- int dcr_base;
- struct device_node *dn;
-
- mutex_lock(&nwpserial_mutex);
-
- dn = port->dev->of_node;
- if (dn == NULL)
- goto out;
-
- /* get dcr base. */
- dcr_base = dcr_resource_start(dn, 0);
-
- /* find matching entry */
- for (i = 0; i < NWPSERIAL_NR; i++)
- if (nwpserial_ports[i].port.iobase == dcr_base) {
- up = &nwpserial_ports[i];
- break;
- }
-
- /* we didn't find a mtching entry, search for a free port */
- if (up == NULL)
- for (i = 0; i < NWPSERIAL_NR; i++)
- if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
- nwpserial_ports[i].port.iobase == 0) {
- up = &nwpserial_ports[i];
- break;
- }
-
- if (up == NULL) {
- ret = -EBUSY;
- goto out;
- }
-
- if (first)
- uart_register_driver(&nwpserial_reg);
- first = 0;
-
- up->port.membase = port->membase;
- up->port.irq = port->irq;
- up->port.uartclk = port->uartclk;
- up->port.fifosize = port->fifosize;
- up->port.regshift = port->regshift;
- up->port.iotype = port->iotype;
- up->port.flags = port->flags;
- up->port.mapbase = port->mapbase;
- up->port.private_data = port->private_data;
-
- if (port->dev)
- up->port.dev = port->dev;
-
- if (up->port.iobase != dcr_base) {
- up->port.ops = &nwpserial_pops;
- up->port.fifosize = 16;
-
- spin_lock_init(&up->port.lock);
-
- up->port.iobase = dcr_base;
- dcr_len = dcr_resource_len(dn, 0);
-
- up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
- if (!DCR_MAP_OK(up->dcr_host)) {
- printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
- goto out;
- }
- }
-
- ret = uart_add_one_port(&nwpserial_reg, &up->port);
- if (ret == 0)
- ret = up->port.line;
-
-out:
- mutex_unlock(&nwpserial_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL(nwpserial_register_port);
-
-void nwpserial_unregister_port(int line)
-{
- struct nwpserial_port *up = &nwpserial_ports[line];
- mutex_lock(&nwpserial_mutex);
- uart_remove_one_port(&nwpserial_reg, &up->port);
-
- up->port.type = PORT_UNKNOWN;
-
- mutex_unlock(&nwpserial_mutex);
-}
-EXPORT_SYMBOL(nwpserial_unregister_port);
-
-#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
-static int __init nwpserial_console_init(void)
-{
- struct nwpserial_port *up = NULL;
- struct device_node *dn;
- const char *name;
- int dcr_base;
- int dcr_len;
- int i;
-
- /* search for a free port */
- for (i = 0; i < NWPSERIAL_NR; i++)
- if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
- up = &nwpserial_ports[i];
- break;
- }
-
- if (up == NULL)
- return -1;
-
- name = of_get_property(of_chosen, "linux,stdout-path", NULL);
- if (name == NULL)
- return -1;
-
- dn = of_find_node_by_path(name);
- if (!dn)
- return -1;
-
- spin_lock_init(&up->port.lock);
- up->port.ops = &nwpserial_pops;
- up->port.type = PORT_NWPSERIAL;
- up->port.fifosize = 16;
-
- dcr_base = dcr_resource_start(dn, 0);
- dcr_len = dcr_resource_len(dn, 0);
- up->port.iobase = dcr_base;
-
- up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
- if (!DCR_MAP_OK(up->dcr_host)) {
- printk("Cannot map DCR resources for SERIAL");
- return -1;
- }
- register_console(&nwpserial_console);
- return 0;
-}
-console_initcall(nwpserial_console_init);
-#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 9d4c84f7485f..b645f9228ed7 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1165,7 +1165,7 @@ serial_omap_type(struct uart_port *port)
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-static inline void wait_for_xmitr(struct uart_omap_port *up)
+static void wait_for_xmitr(struct uart_omap_port *up)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 9becba654892..41eab75ba2af 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -603,7 +603,7 @@ static struct uart_driver serial_pxa_reg;
/*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct uart_pxa_port *up)
+static void wait_for_xmitr(struct uart_pxa_port *up)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index edb5305b9d4d..13f8d5f70272 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -389,6 +389,13 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
const u8 line = sc16is7xx_line(port);
u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line;
+ /*
+ * Don't send zero-length data, at least on SPI it confuses the chip
+ * delivering wrong TXLVL data.
+ */
+ if (unlikely(!to_send))
+ return;
+
regcache_cache_bypass(s->regmap, true);
regmap_raw_write(s->regmap, addr, s->buf, to_send);
regcache_cache_bypass(s->regmap, false);
@@ -630,6 +637,12 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
if (likely(to_send)) {
/* Limit to size of TX FIFO */
txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
+ if (txlen > SC16IS7XX_FIFO_SIZE) {
+ dev_err_ratelimited(port->dev,
+ "chip reports %d free bytes in TX fifo, but it only has %d",
+ txlen, SC16IS7XX_FIFO_SIZE);
+ txlen = 0;
+ }
to_send = (to_send > txlen) ? txlen : to_send;
/* Add data to send */
@@ -1180,7 +1193,7 @@ static int sc16is7xx_probe(struct device *dev,
if (devtype->nr_gpio) {
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
- s->gpio.dev = dev;
+ s->gpio.parent = dev;
s->gpio.label = dev_name(dev);
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index def5199ca004..b1f54ab1818c 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -110,7 +110,7 @@ static void uart_start(struct tty_struct *tty)
spin_unlock_irqrestore(&port->lock, flags);
}
-static inline void
+static void
uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
{
unsigned long flags;
@@ -1818,8 +1818,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* @options: ptr for <options> field; NULL if not present (out)
*
* Decodes earlycon kernel command line parameters of the form
- * earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
- * console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
+ * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
+ * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
*
* The optional form
* earlycon=<name>,0x<addr>,<options>
@@ -1834,6 +1834,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
+ } else if (strncmp(p, "mmio16,", 7) == 0) {
+ *iotype = UPIO_MEM16;
+ p += 7;
} else if (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32;
p += 7;
@@ -2186,6 +2189,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
"I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
+ case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
@@ -2831,6 +2835,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6);
case UPIO_MEM:
+ case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 3eb57eb532f1..226ad23b136c 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -193,6 +193,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
return gpios;
}
+EXPORT_SYMBOL_GPL(mctrl_gpio_init);
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
@@ -247,3 +248,4 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
disable_irq(gpios->irq[i]);
}
}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 51c7507b0444..4646a9f531ad 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2,6 +2,7 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
* Copyright (C) 2002 - 2011 Paul Mundt
+ * Copyright (C) 2015 Glider bvba
* Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
*
* based off of the old drivers/char/sh-sci.c by:
@@ -38,7 +39,6 @@
#include <linux/major.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -76,6 +76,14 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0))
+enum SCI_CLKS {
+ SCI_FCK, /* Functional Clock */
+ SCI_SCK, /* Optional External Clock */
+ SCI_BRG_INT, /* Optional BRG Internal Clock Source */
+ SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_NUM_CLKS
+};
+
struct sci_port {
struct uart_port port;
@@ -92,10 +100,9 @@ struct sci_port {
struct timer_list break_timer;
int break_flag;
- /* Interface clock */
- struct clk *iclk;
- /* Function clock */
- struct clk *fclk;
+ /* Clocks */
+ struct clk *clks[SCI_NUM_CLKS];
+ unsigned long clk_rates[SCI_NUM_CLKS];
int irqs[SCIx_NR_IRQS];
char *irqstr[SCIx_NR_IRQS];
@@ -116,8 +123,6 @@ struct sci_port {
struct timer_list rx_timer;
unsigned int rx_timeout;
#endif
-
- struct notifier_block freq_transition;
};
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@@ -163,6 +168,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -185,6 +192,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -206,6 +215,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = { 0x30, 16 },
[SCPDR] = { 0x34, 16 },
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -227,6 +238,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = { 0x30, 16 },
[SCPDR] = { 0x34, 16 },
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -249,6 +262,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -270,6 +285,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -291,6 +308,32 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
+ },
+
+ /*
+ * Common SCIF definitions for ports with a Baud Rate Generator for
+ * External Clock (BRG).
+ */
+ [SCIx_SH4_SCIF_BRG_REGTYPE] = {
+ [SCSMR] = { 0x00, 16 },
+ [SCBRR] = { 0x04, 8 },
+ [SCSCR] = { 0x08, 16 },
+ [SCxTDR] = { 0x0c, 8 },
+ [SCxSR] = { 0x10, 16 },
+ [SCxRDR] = { 0x14, 8 },
+ [SCFCR] = { 0x18, 16 },
+ [SCFDR] = { 0x1c, 16 },
+ [SCTFDR] = sci_reg_invalid,
+ [SCRFDR] = sci_reg_invalid,
+ [SCSPTR] = { 0x20, 16 },
+ [SCLSR] = { 0x24, 16 },
+ [HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
+ [SCDL] = { 0x30, 16 },
+ [SCCKS] = { 0x34, 16 },
},
/*
@@ -312,6 +355,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = { 0x40, 16 },
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = { 0x30, 16 },
+ [SCCKS] = { 0x34, 16 },
},
/*
@@ -334,6 +379,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -356,6 +403,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
/*
@@ -378,6 +427,8 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[HSSRR] = sci_reg_invalid,
[SCPCR] = sci_reg_invalid,
[SCPDR] = sci_reg_invalid,
+ [SCDL] = sci_reg_invalid,
+ [SCCKS] = sci_reg_invalid,
},
};
@@ -452,18 +503,24 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)
static void sci_port_enable(struct sci_port *sci_port)
{
+ unsigned int i;
+
if (!sci_port->port.dev)
return;
pm_runtime_get_sync(sci_port->port.dev);
- clk_prepare_enable(sci_port->iclk);
- sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
- clk_prepare_enable(sci_port->fclk);
+ for (i = 0; i < SCI_NUM_CLKS; i++) {
+ clk_prepare_enable(sci_port->clks[i]);
+ sci_port->clk_rates[i] = clk_get_rate(sci_port->clks[i]);
+ }
+ sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
}
static void sci_port_disable(struct sci_port *sci_port)
{
+ unsigned int i;
+
if (!sci_port->port.dev)
return;
@@ -475,8 +532,8 @@ static void sci_port_disable(struct sci_port *sci_port)
del_timer_sync(&sci_port->break_timer);
sci_port->break_flag = 0;
- clk_disable_unprepare(sci_port->fclk);
- clk_disable_unprepare(sci_port->iclk);
+ for (i = SCI_NUM_CLKS; i-- > 0; )
+ clk_disable_unprepare(sci_port->clks[i]);
pm_runtime_put_sync(sci_port->port.dev);
}
@@ -1606,29 +1663,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
return ret;
}
-/*
- * Here we define a transition notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
- unsigned long phase, void *p)
-{
- struct sci_port *sci_port;
- unsigned long flags;
-
- sci_port = container_of(self, struct sci_port, freq_transition);
-
- if (phase == CPUFREQ_POSTCHANGE) {
- struct uart_port *port = &sci_port->port;
-
- spin_lock_irqsave(&port->lock, flags);
- port->uartclk = clk_get_rate(sci_port->iclk);
- spin_unlock_irqrestore(&port->lock, flags);
- }
-
- return NOTIFY_OK;
-}
-
static const struct sci_irq_desc {
const char *desc;
irq_handler_t handler;
@@ -1864,90 +1898,149 @@ static void sci_shutdown(struct uart_port *port)
sci_free_irq(s);
}
-static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned long freq)
+static int sci_sck_calc(struct sci_port *s, unsigned int bps,
+ unsigned int *srr)
{
- if (s->sampling_rate)
- return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;
+ unsigned long freq = s->clk_rates[SCI_SCK];
+ unsigned int min_sr, max_sr, sr;
+ int err, min_err = INT_MAX;
+
+ if (s->sampling_rate) {
+ /* SCI(F) has a fixed sampling rate */
+ min_sr = max_sr = s->sampling_rate / 2;
+ } else {
+ /* HSCIF has a variable 1/(8..32) sampling rate */
+ min_sr = 8;
+ max_sr = 32;
+ }
+
+ for (sr = max_sr; sr >= min_sr; sr--) {
+ err = DIV_ROUND_CLOSEST(freq, sr) - bps;
+ if (abs(err) >= abs(min_err))
+ continue;
- /* Warn, but use a safe default */
- WARN_ON(1);
+ min_err = err;
+ *srr = sr - 1;
- return ((freq + 16 * bps) / (32 * bps) - 1);
+ if (!err)
+ break;
+ }
+
+ dev_dbg(s->port.dev, "SCK: %u%+d bps using SR %u\n", bps, min_err,
+ *srr + 1);
+ return min_err;
}
-/* calculate frame length from SMR */
-static int sci_baud_calc_frame_len(unsigned int smr_val)
+static int sci_brg_calc(struct sci_port *s, unsigned int bps,
+ unsigned long freq, unsigned int *dlr,
+ unsigned int *srr)
{
- int len = 10;
+ unsigned int min_sr, max_sr, sr, dl;
+ int err, min_err = INT_MAX;
- if (smr_val & SCSMR_CHR)
- len--;
- if (smr_val & SCSMR_PE)
- len++;
- if (smr_val & SCSMR_STOP)
- len++;
+ if (s->sampling_rate) {
+ /* SCIF has a fixed sampling rate */
+ min_sr = max_sr = s->sampling_rate / 2;
+ } else {
+ /* HSCIF has a variable 1/(8..32) sampling rate */
+ min_sr = 8;
+ max_sr = 32;
+ }
- return len;
-}
+ for (sr = max_sr; sr >= min_sr; sr--) {
+ dl = DIV_ROUND_CLOSEST(freq, sr * bps);
+ dl = clamp(dl, 1U, 65535U);
+
+ err = DIV_ROUND_CLOSEST(freq, sr * dl) - bps;
+ if (abs(err) >= abs(min_err))
+ continue;
+ min_err = err;
+ *dlr = dl;
+ *srr = sr - 1;
-/* calculate sample rate, BRR, and clock select for HSCIF */
-static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
- int *brr, unsigned int *srr,
- unsigned int *cks, int frame_len)
+ if (!err)
+ break;
+ }
+
+ dev_dbg(s->port.dev, "BRG: %u%+d bps using DL %u SR %u\n", bps,
+ min_err, *dlr, *srr + 1);
+ return min_err;
+}
+
+/* calculate sample rate, BRR, and clock select */
+static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
+ unsigned int *brr, unsigned int *srr,
+ unsigned int *cks)
{
- int sr, c, br, err, recv_margin;
- int min_err = 1000; /* 100% */
- int recv_max_margin = 0;
+ unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
+ unsigned long freq = s->clk_rates[SCI_FCK];
+ int err, min_err = INT_MAX;
- /* Find the combination of sample rate and clock select with the
- smallest deviation from the desired baud rate. */
- for (sr = 8; sr <= 32; sr++) {
+ if (s->sampling_rate) {
+ min_sr = max_sr = s->sampling_rate;
+ shift = 0;
+ } else {
+ /* HSCIF has a variable sample rate */
+ min_sr = 8;
+ max_sr = 32;
+ shift = 1;
+ }
+
+ /*
+ * Find the combination of sample rate and clock select with the
+ * smallest deviation from the desired baud rate.
+ * Prefer high sample rates to maximise the receive margin.
+ *
+ * M: Receive margin (%)
+ * N: Ratio of bit rate to clock (N = sampling rate)
+ * D: Clock duty (D = 0 to 1.0)
+ * L: Frame length (L = 9 to 12)
+ * F: Absolute value of clock frequency deviation
+ *
+ * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
+ * (|D - 0.5| / N * (1 + F))|
+ * NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
+ */
+ for (sr = max_sr; sr >= min_sr; sr--) {
for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */
- br = DIV_ROUND_CLOSEST(freq, (sr *
- (1 << (2 * c + 1)) * bps)) - 1;
- br = clamp(br, 0, 255);
- err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr *
- (1 << (2 * c + 1)) / 1000)) -
- 1000;
- /* Calc recv margin
- * M: Receive margin (%)
- * N: Ratio of bit rate to clock (N = sampling rate)
- * D: Clock duty (D = 0 to 1.0)
- * L: Frame length (L = 9 to 12)
- * F: Absolute value of clock frequency deviation
+ prediv = sr * (1 << (2 * c + shift));
+
+ /*
+ * We need to calculate:
*
- * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
- * (|D - 0.5| / N * (1 + F))|
- * NOTE: Usually, treat D for 0.5, F is 0 by this
- * calculation.
+ * br = freq / (prediv * bps) clamped to [1..256]
+ * err = freq / (br * prediv) - bps
+ *
+ * Watch out for overflow when calculating the desired
+ * sampling clock rate!
*/
- recv_margin = abs((500 -
- DIV_ROUND_CLOSEST(1000, sr << 1)) / 10);
- if (abs(min_err) > abs(err)) {
- min_err = err;
- recv_max_margin = recv_margin;
- } else if ((min_err == err) &&
- (recv_margin > recv_max_margin))
- recv_max_margin = recv_margin;
- else
+ if (bps > UINT_MAX / prediv)
+ break;
+
+ scrate = prediv * bps;
+ br = DIV_ROUND_CLOSEST(freq, scrate);
+ br = clamp(br, 1U, 256U);
+
+ err = DIV_ROUND_CLOSEST(freq, br * prediv) - bps;
+ if (abs(err) >= abs(min_err))
continue;
- *brr = br;
+ min_err = err;
+ *brr = br - 1;
*srr = sr - 1;
*cks = c;
+
+ if (!err)
+ goto found;
}
}
- if (min_err == 1000) {
- WARN_ON(1);
- /* use defaults */
- *brr = 255;
- *srr = 15;
- *cks = 0;
- }
+found:
+ dev_dbg(s->port.dev, "BRR: %u%+d bps using N %u SR %u cks %u\n", bps,
+ min_err, *brr, *srr + 1, *cks);
+ return min_err;
}
static void sci_reset(struct uart_port *port)
@@ -1969,11 +2062,14 @@ static void sci_reset(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ unsigned int baud, smr_val = 0, scr_val = 0, i;
+ unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
+ unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
struct sci_port *s = to_sci_port(port);
const struct plat_sci_reg *reg;
- unsigned int baud, smr_val = 0, max_baud, cks = 0;
- int t = -1;
- unsigned int srr = 15;
+ int min_err = INT_MAX, err;
+ unsigned long max_freq = 0;
+ int best_clk = -1;
if ((termios->c_cflag & CSIZE) == CS7)
smr_val |= SCSMR_CHR;
@@ -1992,41 +2088,123 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
* that the previous boot loader has enabled required clocks and
* setup the baud rate generator hardware for us already.
*/
- max_baud = port->uartclk ? port->uartclk / 16 : 115200;
-
- baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
- if (likely(baud && port->uartclk)) {
- if (s->cfg->type == PORT_HSCIF) {
- int frame_len = sci_baud_calc_frame_len(smr_val);
- sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,
- &cks, frame_len);
- } else {
- t = sci_scbrr_calc(s, baud, port->uartclk);
- for (cks = 0; t >= 256 && cks <= 3; cks++)
- t >>= 2;
+ if (!port->uartclk) {
+ baud = uart_get_baud_rate(port, termios, old, 0, 115200);
+ goto done;
+ }
+
+ for (i = 0; i < SCI_NUM_CLKS; i++)
+ max_freq = max(max_freq, s->clk_rates[i]);
+
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ max_freq / max(s->sampling_rate, 8U));
+ if (!baud)
+ goto done;
+
+ /*
+ * There can be multiple sources for the sampling clock. Find the one
+ * that gives us the smallest deviation from the desired baud rate.
+ */
+
+ /* Optional Undivided External Clock */
+ if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA &&
+ port->type != PORT_SCIFB) {
+ err = sci_sck_calc(s, baud, &srr1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_SCK;
+ scr_val = SCSCR_CKE1;
+ sccks = SCCKS_CKS;
+ min_err = err;
+ srr = srr1;
+ if (!err)
+ goto done;
}
}
+ /* Optional BRG Frequency Divided External Clock */
+ if (s->clk_rates[SCI_SCIF_CLK] && sci_getreg(port, SCDL)->size) {
+ err = sci_brg_calc(s, baud, s->clk_rates[SCI_SCIF_CLK], &dl1,
+ &srr1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_SCIF_CLK;
+ scr_val = SCSCR_CKE1;
+ sccks = 0;
+ min_err = err;
+ dl = dl1;
+ srr = srr1;
+ if (!err)
+ goto done;
+ }
+ }
+
+ /* Optional BRG Frequency Divided Internal Clock */
+ if (s->clk_rates[SCI_BRG_INT] && sci_getreg(port, SCDL)->size) {
+ err = sci_brg_calc(s, baud, s->clk_rates[SCI_BRG_INT], &dl1,
+ &srr1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_BRG_INT;
+ scr_val = SCSCR_CKE1;
+ sccks = SCCKS_XIN;
+ min_err = err;
+ dl = dl1;
+ srr = srr1;
+ if (!min_err)
+ goto done;
+ }
+ }
+
+ /* Divided Functional Clock using standard Bit Rate Register */
+ err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_FCK;
+ scr_val = 0;
+ min_err = err;
+ brr = brr1;
+ srr = srr1;
+ cks = cks1;
+ }
+
+done:
+ if (best_clk >= 0)
+ dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
+ s->clks[best_clk], baud, min_err);
+
sci_port_enable(s);
- sci_reset(port);
+ /*
+ * Program the optional External Baud Rate Generator (BRG) first.
+ * It controls the mux to select (H)SCK or frequency divided clock.
+ */
+ if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
+ serial_port_out(port, SCDL, dl);
+ serial_port_out(port, SCCKS, sccks);
+ }
- smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+ sci_reset(port);
uart_update_timeout(port, termios->c_cflag, baud);
- dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n",
- __func__, smr_val, cks, t, s->cfg->scscr);
-
- if (t >= 0) {
- serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks);
- serial_port_out(port, SCBRR, t);
- reg = sci_getreg(port, HSSRR);
- if (reg->size)
+ if (best_clk >= 0) {
+ smr_val |= cks;
+ dev_dbg(port->dev,
+ "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
+ scr_val, smr_val, brr, sccks, dl, srr);
+ serial_port_out(port, SCSCR, scr_val);
+ serial_port_out(port, SCSMR, smr_val);
+ serial_port_out(port, SCBRR, brr);
+ if (sci_getreg(port, HSSRR)->size)
serial_port_out(port, HSSRR, srr | HSCIF_SRE);
- udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
- } else
+
+ /* Wait one bit interval */
+ udelay((1000000 + (baud - 1)) / baud);
+ } else {
+ /* Don't touch the bit rate configuration */
+ scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
+ smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+ dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
+ serial_port_out(port, SCSCR, scr_val);
serial_port_out(port, SCSMR, smr_val);
+ }
sci_init_pins(port, termios->c_cflag);
@@ -2051,7 +2229,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, SCFCR, ctrl);
}
- serial_port_out(port, SCSCR, s->cfg->scscr);
+ scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
+ dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
+ serial_port_out(port, SCSCR, scr_val);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
@@ -2241,6 +2421,63 @@ static struct uart_ops sci_uart_ops = {
#endif
};
+static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
+{
+ const char *clk_names[] = {
+ [SCI_FCK] = "fck",
+ [SCI_SCK] = "sck",
+ [SCI_BRG_INT] = "brg_int",
+ [SCI_SCIF_CLK] = "scif_clk",
+ };
+ struct clk *clk;
+ unsigned int i;
+
+ if (sci_port->cfg->type == PORT_HSCIF)
+ clk_names[SCI_SCK] = "hsck";
+
+ for (i = 0; i < SCI_NUM_CLKS; i++) {
+ clk = devm_clk_get(dev, clk_names[i]);
+ if (PTR_ERR(clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (IS_ERR(clk) && i == SCI_FCK) {
+ /*
+ * "fck" used to be called "sci_ick", and we need to
+ * maintain DT backward compatibility.
+ */
+ clk = devm_clk_get(dev, "sci_ick");
+ if (PTR_ERR(clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (!IS_ERR(clk))
+ goto found;
+
+ /*
+ * Not all SH platforms declare a clock lookup entry
+ * for SCI devices, in which case we need to get the
+ * global "peripheral_clk" clock.
+ */
+ clk = devm_clk_get(dev, "peripheral_clk");
+ if (!IS_ERR(clk))
+ goto found;
+
+ dev_err(dev, "failed to get %s (%ld)\n", clk_names[i],
+ PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+found:
+ if (IS_ERR(clk))
+ dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i],
+ PTR_ERR(clk));
+ else
+ dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i],
+ clk, clk);
+ sci_port->clks[i] = IS_ERR(clk) ? NULL : clk;
+ }
+ return 0;
+}
+
static int sci_init_single(struct platform_device *dev,
struct sci_port *sci_port, unsigned int index,
struct plat_sci_port *p, bool early)
@@ -2333,22 +2570,9 @@ static int sci_init_single(struct platform_device *dev,
sci_port->sampling_rate = p->sampling_rate;
if (!early) {
- sci_port->iclk = clk_get(&dev->dev, "sci_ick");
- if (IS_ERR(sci_port->iclk)) {
- sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
- if (IS_ERR(sci_port->iclk)) {
- dev_err(&dev->dev, "can't get iclk\n");
- return PTR_ERR(sci_port->iclk);
- }
- }
-
- /*
- * The function clock is optional, ignore it if we can't
- * find it.
- */
- sci_port->fclk = clk_get(&dev->dev, "sci_fck");
- if (IS_ERR(sci_port->fclk))
- sci_port->fclk = NULL;
+ ret = sci_init_clocks(sci_port, &dev->dev);
+ if (ret < 0)
+ return ret;
port->dev = &dev->dev;
@@ -2405,9 +2629,6 @@ static int sci_init_single(struct platform_device *dev,
static void sci_cleanup_single(struct sci_port *port)
{
- clk_put(port->iclk);
- clk_put(port->fclk);
-
pm_runtime_disable(port->port.dev);
}
@@ -2426,7 +2647,7 @@ static void serial_console_write(struct console *co, const char *s,
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl;
+ unsigned short bits, ctrl, ctrl_temp;
unsigned long flags;
int locked = 1;
@@ -2438,9 +2659,11 @@ static void serial_console_write(struct console *co, const char *s,
else
spin_lock(&port->lock);
- /* first save the SCSCR then disable the interrupts */
+ /* first save SCSCR then disable interrupts, keep clock source */
ctrl = serial_port_in(port, SCSCR);
- serial_port_out(port, SCSCR, sci_port->cfg->scscr);
+ ctrl_temp = (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
+ serial_port_out(port, SCSCR, ctrl_temp);
uart_console_write(port, s, count, serial_console_putchar);
@@ -2559,9 +2782,6 @@ static int sci_remove(struct platform_device *dev)
{
struct sci_port *port = platform_get_drvdata(dev);
- cpufreq_unregister_notifier(&port->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-
uart_remove_one_port(&sci_uart_driver, &port->port);
sci_cleanup_single(port);
@@ -2569,42 +2789,44 @@ static int sci_remove(struct platform_device *dev)
return 0;
}
-struct sci_port_info {
- unsigned int type;
- unsigned int regtype;
-};
+
+#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
+#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
+#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
static const struct of_device_id of_sci_match[] = {
+ /* SoC-specific types */
+ {
+ .compatible = "renesas,scif-r7s72100",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+ },
+ /* Family-specific types */
+ {
+ .compatible = "renesas,rcar-gen1-scif",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ }, {
+ .compatible = "renesas,rcar-gen2-scif",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ }, {
+ .compatible = "renesas,rcar-gen3-scif",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ },
+ /* Generic types */
{
.compatible = "renesas,scif",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCIF,
- .regtype = SCIx_SH4_SCIF_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
}, {
.compatible = "renesas,scifa",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCIFA,
- .regtype = SCIx_SCIFA_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
}, {
.compatible = "renesas,scifb",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCIFB,
- .regtype = SCIx_SCIFB_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
}, {
.compatible = "renesas,hscif",
- .data = &(const struct sci_port_info) {
- .type = PORT_HSCIF,
- .regtype = SCIx_HSCIF_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
}, {
.compatible = "renesas,sci",
- .data = &(const struct sci_port_info) {
- .type = PORT_SCI,
- .regtype = SCIx_SCI_REGTYPE,
- },
+ .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
}, {
/* Terminator */
},
@@ -2616,24 +2838,21 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
- const struct sci_port_info *info;
struct plat_sci_port *p;
int id;
if (!IS_ENABLED(CONFIG_OF) || !np)
return NULL;
- match = of_match_node(of_sci_match, pdev->dev.of_node);
+ match = of_match_node(of_sci_match, np);
if (!match)
return NULL;
- info = match->data;
-
p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
if (!p)
return NULL;
- /* Get the line number for the aliases node. */
+ /* Get the line number from the aliases node. */
id = of_alias_get_id(np, "serial");
if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
@@ -2643,8 +2862,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
*dev_id = id;
p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
- p->type = info->type;
- p->regtype = info->regtype;
+ p->type = SCI_OF_TYPE(match->data);
+ p->regtype = SCI_OF_REGTYPE(match->data);
p->scscr = SCSCR_RE | SCSCR_TE;
return p;
@@ -2714,16 +2933,6 @@ static int sci_probe(struct platform_device *dev)
if (ret)
return ret;
- sp->freq_transition.notifier_call = sci_notifier;
-
- ret = cpufreq_register_notifier(&sp->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
- if (unlikely(ret < 0)) {
- uart_remove_one_port(&sci_uart_driver, &sp->port);
- sci_cleanup_single(sp);
- return ret;
- }
-
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_gdb_detach();
#endif
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index bf69bbdcc1f9..fb1760250421 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -27,6 +27,8 @@ enum {
HSSRR, /* Sampling Rate Register */
SCPCR, /* Serial Port Control Register */
SCPDR, /* Serial Port Data Register */
+ SCDL, /* BRG Frequency Division Register */
+ SCCKS, /* BRG Clock Select Register */
SCIx_NR_REGS,
};
@@ -109,6 +111,14 @@ enum {
#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */
#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */
+/*
+ * BRG Clock Select Register (Some SCIF and HSCIF)
+ * The Baud Rate Generator for external clock can provide a clock source for
+ * the sampling clock. It outputs either its frequency divided clock, or the
+ * (undivided) (H)SCK external clock.
+ */
+#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
+#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 9dbae01d41ce..ef26c4a60be4 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -517,7 +517,7 @@ static struct uart_ops serial_sprd_ops = {
};
#ifdef CONFIG_SERIAL_SPRD_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
+static void wait_for_xmitr(struct uart_port *port)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index e124d2e88996..9ad98eaa35bf 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1262,7 +1262,7 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up)
/*
* Wait for transmitter & holding register to empty
*/
-static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
+static void wait_for_xmitr(struct uart_sunsu_port *up)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 73190f5d2832..1a7dc3c590b1 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -31,7 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/fs_uart_pd.h>
-#include <asm/ucc_slow.h>
+#include <soc/fsl/qe/ucc_slow.h>
#include <linux/firmware.h>
#include <asm/reg.h>
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 4079ec56f5f9..b384060e3b1f 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -485,7 +485,7 @@ static struct uart_driver vt8500_uart_driver;
#ifdef CONFIG_SERIAL_VT8500_CONSOLE
-static inline void wait_for_xmitr(struct uart_port *port)
+static void wait_for_xmitr(struct uart_port *port)
{
unsigned int status, tmout = 10000;
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 6fc39fbfc275..5505ea842179 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -89,7 +89,7 @@
* module identification
*/
static char *driver_name = "SyncLink GT";
-static char *tty_driver_name = "synclink_gt";
+static char *slgt_driver_name = "synclink_gt";
static char *tty_dev_prefix = "ttySLG";
MODULE_LICENSE("GPL");
#define MGSL_MAGIC 0x5401
@@ -3799,7 +3799,7 @@ static int __init slgt_init(void)
/* Initialize the tty_driver structure */
- serial_driver->driver_name = tty_driver_name;
+ serial_driver->driver_name = slgt_driver_name;
serial_driver->name = tty_dev_prefix;
serial_driver->major = ttymajor;
serial_driver->minor_start = 64;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index bcc8e1e8bb72..892c92354745 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -256,19 +256,24 @@ const char *tty_name(const struct tty_struct *tty)
EXPORT_SYMBOL(tty_name);
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
+const char *tty_driver_name(const struct tty_struct *tty)
+{
+ if (!tty || !tty->driver)
+ return "";
+ return tty->driver->name;
+}
+
+static int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
const char *routine)
{
#ifdef TTY_PARANOIA_CHECK
if (!tty) {
- printk(KERN_WARNING
- "null TTY for (%d:%d) in %s\n",
+ pr_warn("(%d:%d): %s: NULL tty\n",
imajor(inode), iminor(inode), routine);
return 1;
}
if (tty->magic != TTY_MAGIC) {
- printk(KERN_WARNING
- "bad magic number for tty struct (%d:%d) in %s\n",
+ pr_warn("(%d:%d): %s: bad magic number\n",
imajor(inode), iminor(inode), routine);
return 1;
}
@@ -293,9 +298,8 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
tty->link && tty->link->count)
count++;
if (tty->count != count) {
- printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
- "!= #fd's(%d) in %s\n",
- tty->name, tty->count, count, routine);
+ tty_warn(tty, "%s: tty->count(%d) != #fd's(%d)\n",
+ routine, tty->count, count);
return count;
}
#endif
@@ -420,10 +424,8 @@ int __tty_check_change(struct tty_struct *tty, int sig)
}
rcu_read_unlock();
- if (!tty_pgrp) {
- pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n",
- tty_name(tty), sig);
- }
+ if (!tty_pgrp)
+ tty_warn(tty, "sig=%d, tty->pgrp == NULL!\n", sig);
return ret;
}
@@ -781,7 +783,7 @@ static void do_tty_hangup(struct work_struct *work)
void tty_hangup(struct tty_struct *tty)
{
- tty_debug_hangup(tty, "\n");
+ tty_debug_hangup(tty, "hangup\n");
schedule_work(&tty->hangup_work);
}
@@ -798,7 +800,7 @@ EXPORT_SYMBOL(tty_hangup);
void tty_vhangup(struct tty_struct *tty)
{
- tty_debug_hangup(tty, "\n");
+ tty_debug_hangup(tty, "vhangup\n");
__tty_hangup(tty, 0);
}
@@ -835,7 +837,7 @@ void tty_vhangup_self(void)
static void tty_vhangup_session(struct tty_struct *tty)
{
- tty_debug_hangup(tty, "\n");
+ tty_debug_hangup(tty, "session hangup\n");
__tty_hangup(tty, 1);
}
@@ -1239,8 +1241,7 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
return -EIO;
/* Short term debug to catch buggy drivers */
if (tty->ops->write_room == NULL)
- printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
- tty->driver->name);
+ tty_err(tty, "missing write_room method\n");
ld = tty_ldisc_ref_wait(tty);
if (!ld->ops->write)
ret = -EIO;
@@ -1561,8 +1562,8 @@ err_module_put:
/* call the tty release_tty routine to clean out this slot */
err_release_tty:
tty_unlock(tty);
- printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
- "clearing slot %d\n", idx);
+ tty_info_ratelimited(tty, "ldisc open failed (%d), clearing slot %d\n",
+ retval, idx);
release_tty(tty, idx);
return ERR_PTR(retval);
}
@@ -1580,10 +1581,8 @@ void tty_free_termios(struct tty_struct *tty)
tp = tty->driver->termios[idx];
if (tp == NULL) {
tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
- if (tp == NULL) {
- pr_warn("tty: no memory to save termios state.\n");
+ if (tp == NULL)
return;
- }
tty->driver->termios[idx] = tp;
}
*tp = tty->termios;
@@ -1788,7 +1787,7 @@ int tty_release(struct inode *inode, struct file *filp)
return 0;
}
- tty_debug_hangup(tty, "(tty count=%d)...\n", tty->count);
+ tty_debug_hangup(tty, "releasing (count=%d)\n", tty->count);
if (tty->ops->close)
tty->ops->close(tty, filp);
@@ -1837,8 +1836,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (once) {
once = 0;
- printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
- __func__, tty_name(tty));
+ tty_warn(tty, "read/write wait queue active!\n");
}
schedule_timeout_killable(timeout);
if (timeout < 120 * HZ)
@@ -1849,14 +1847,12 @@ int tty_release(struct inode *inode, struct file *filp)
if (o_tty) {
if (--o_tty->count < 0) {
- printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
- __func__, o_tty->count, tty_name(o_tty));
+ tty_warn(tty, "bad slave count (%d)\n", o_tty->count);
o_tty->count = 0;
}
}
if (--tty->count < 0) {
- printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
- __func__, tty->count, tty_name(tty));
+ tty_warn(tty, "bad tty->count (%d)\n", tty->count);
tty->count = 0;
}
@@ -1907,7 +1903,7 @@ int tty_release(struct inode *inode, struct file *filp)
/* Wait for pending work before tty destruction commmences */
tty_flush_works(tty);
- tty_debug_hangup(tty, "freeing structure...\n");
+ tty_debug_hangup(tty, "freeing structure\n");
/*
* The release_tty function takes care of the details of clearing
* the slots and preserving the termios structure. The tty_unlock_pair
@@ -2097,7 +2093,7 @@ retry_open:
tty->driver->subtype == PTY_TYPE_MASTER)
noctty = 1;
- tty_debug_hangup(tty, "(tty count=%d)\n", tty->count);
+ tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
if (tty->ops->open)
retval = tty->ops->open(tty, filp);
@@ -2106,7 +2102,7 @@ retry_open:
filp->f_flags = saved_flags;
if (retval) {
- tty_debug_hangup(tty, "error %d, releasing...\n", retval);
+ tty_debug_hangup(tty, "open error %d, releasing\n", retval);
tty_unlock(tty); /* need to call tty_release without BTM */
tty_release(inode, filp);
@@ -2870,7 +2866,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
no_tty();
return 0;
case TIOCSCTTY:
- return tiocsctty(tty, file, arg);
+ return tiocsctty(real_tty, file, arg);
case TIOCGPGRP:
return tiocgpgrp(tty, real_tty, p);
case TIOCSPGRP:
@@ -3028,28 +3024,24 @@ void __do_SAK(struct tty_struct *tty)
read_lock(&tasklist_lock);
/* Kill the entire session */
do_each_pid_task(session, PIDTYPE_SID, p) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): task_session(p)==tty->session\n",
- task_pid_nr(p), p->comm);
+ tty_notice(tty, "SAK: killed process %d (%s): by session\n",
+ task_pid_nr(p), p->comm);
send_sig(SIGKILL, p, 1);
} while_each_pid_task(session, PIDTYPE_SID, p);
- /* Now kill any processes that happen to have the
- * tty open.
- */
+
+ /* Now kill any processes that happen to have the tty open */
do_each_thread(g, p) {
if (p->signal->tty == tty) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): task_session(p)==tty->session\n",
- task_pid_nr(p), p->comm);
+ tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n",
+ task_pid_nr(p), p->comm);
send_sig(SIGKILL, p, 1);
continue;
}
task_lock(p);
i = iterate_fd(p->files, 0, this_tty, tty);
if (i != 0) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): fd#%d opened to the tty\n",
- task_pid_nr(p), p->comm, i - 1);
+ tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n",
+ task_pid_nr(p), p->comm, i - 1);
force_sig(SIGKILL, p);
}
task_unlock(p);
@@ -3219,7 +3211,7 @@ EXPORT_SYMBOL(tty_register_device);
static void tty_device_create_release(struct device *dev)
{
- pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
+ dev_dbg(dev, "releasing...\n");
kfree(dev);
}
@@ -3255,8 +3247,8 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
bool cdev = false;
if (index >= driver->num) {
- printk(KERN_ERR "Attempt to register invalid tty line number "
- " (%d).\n", index);
+ pr_err("%s: Attempt to register invalid tty line number (%d)\n",
+ driver->name, index);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 1445dd39aa62..0ea351388724 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -216,7 +216,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
void tty_wait_until_sent(struct tty_struct *tty, long timeout)
{
- tty_debug_wait_until_sent(tty, "\n");
+ tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
@@ -239,19 +239,14 @@ EXPORT_SYMBOL(tty_wait_until_sent);
* Termios Helper Methods
*/
-static void unset_locked_termios(struct ktermios *termios,
- struct ktermios *old,
- struct ktermios *locked)
+static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
{
+ struct ktermios *termios = &tty->termios;
+ struct ktermios *locked = &tty->termios_locked;
int i;
#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
- if (!locked) {
- printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
- return;
- }
-
NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
@@ -463,10 +458,8 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
#else
- if (ifound == -1 || ofound == -1) {
- printk_once(KERN_WARNING "tty: Unable to return correct "
- "speed data as your architecture needs updating.\n");
- }
+ if (ifound == -1 || ofound == -1)
+ pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
#endif
}
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
@@ -556,7 +549,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
down_write(&tty->termios_rwsem);
old_termios = tty->termios;
tty->termios = *new_termios;
- unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
+ unset_locked_termios(tty, &old_termios);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 629e3c865072..a054d03c22e7 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -185,7 +185,7 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
*
* Complement of tty_ldisc_get().
*/
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
+static void tty_ldisc_put(struct tty_ldisc *ld)
{
if (WARN_ON_ONCE(!ld))
return;
@@ -417,6 +417,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do
* any harm.
*
+ * The line discipline-related tty_struct fields are reset to
+ * prevent the ldisc driver from re-using stale information for
+ * the new ldisc instance.
+ *
* Locking: takes termios_rwsem
*/
@@ -425,6 +429,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
down_write(&tty->termios_rwsem);
tty->termios.c_line = num;
up_write(&tty->termios_rwsem);
+
+ tty->disc_data = NULL;
+ tty->receive_room = 0;
}
/**
@@ -529,34 +536,21 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_lock(tty);
retval = tty_ldisc_lock(tty, 5 * HZ);
- if (retval) {
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return retval;
- }
+ if (retval)
+ goto err;
- /*
- * Check the no-op case
- */
+ /* Check the no-op case */
+ if (tty->ldisc->ops->num == ldisc)
+ goto out;
- if (tty->ldisc->ops->num == ldisc) {
- tty_ldisc_unlock(tty);
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return 0;
+ if (test_bit(TTY_HUPPED, &tty->flags)) {
+ /* We were raced by hangup */
+ retval = -EIO;
+ goto out;
}
old_ldisc = tty->ldisc;
- if (test_bit(TTY_HUPPED, &tty->flags)) {
- /* We were raced by the hangup method. It will have stomped
- the ldisc data and closed the ldisc down */
- tty_ldisc_unlock(tty);
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return -EIO;
- }
-
/* Shutdown the old discipline. */
tty_ldisc_close(tty, old_ldisc);
@@ -582,18 +576,15 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
the old ldisc (if it was restored as part of error cleanup
above). In either case, releasing a single reference from
the old ldisc is correct. */
-
- tty_ldisc_put(old_ldisc);
-
- /*
- * Allow ldisc referencing to occur again
- */
+ new_ldisc = old_ldisc;
+out:
tty_ldisc_unlock(tty);
/* Restart the work queue in case no characters kick it off. Safe if
already running */
tty_buffer_restart_work(tty->port);
-
+err:
+ tty_ldisc_put(new_ldisc); /* drop the extra reference */
tty_unlock(tty);
return retval;
}
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
index ad7eba5ca380..1bf8ed13f827 100644
--- a/drivers/tty/tty_ldsem.c
+++ b/drivers/tty/tty_ldsem.c
@@ -319,7 +319,7 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
-static inline int __ldsem_down_read_nested(struct ld_semaphore *sem,
+static int __ldsem_down_read_nested(struct ld_semaphore *sem,
int subclass, long timeout)
{
long count;
@@ -338,7 +338,7 @@ static inline int __ldsem_down_read_nested(struct ld_semaphore *sem,
return 1;
}
-static inline int __ldsem_down_write_nested(struct ld_semaphore *sem,
+static int __ldsem_down_write_nested(struct ld_semaphore *sem,
int subclass, long timeout)
{
long count;
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 0efcf713b756..77703a391207 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -12,11 +12,8 @@
void __lockfunc tty_lock(struct tty_struct *tty)
{
- if (tty->magic != TTY_MAGIC) {
- pr_err("L Bad %p\n", tty);
- WARN_ON(1);
+ if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
return;
- }
tty_kref_get(tty);
mutex_lock(&tty->legacy_mutex);
}
@@ -24,11 +21,8 @@ EXPORT_SYMBOL(tty_lock);
void __lockfunc tty_unlock(struct tty_struct *tty)
{
- if (tty->magic != TTY_MAGIC) {
- pr_err("U Bad %p\n", tty);
- WARN_ON(1);
+ if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty))
return;
- }
mutex_unlock(&tty->legacy_mutex);
tty_kref_put(tty);
}
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 482f33f20043..846ed481c24f 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -462,14 +462,13 @@ int tty_port_close_start(struct tty_port *port,
spin_lock_irqsave(&port->lock, flags);
if (tty->count == 1 && port->count != 1) {
- printk(KERN_WARNING
- "tty_port_close_start: tty->count = 1 port count = %d.\n",
- port->count);
+ tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
+ port->count);
port->count = 1;
}
if (--port->count < 0) {
- printk(KERN_WARNING "tty_port_close_start: count = %d\n",
- port->count);
+ tty_warn(tty, "%s: bad port count (%d)\n", __func__,
+ port->count);
port->count = 0;
}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 4462d167900c..e7cbc44eef57 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -634,7 +634,7 @@ static void set_origin(struct vc_data *vc)
vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
}
-static inline void save_screen(struct vc_data *vc)
+static void save_screen(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index 5619b8ca3bf3..3644a3500b70 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -37,9 +37,4 @@ config USB_CHIPIDEA_HOST
Say Y here to enable host controller functionality of the
ChipIdea driver.
-config USB_CHIPIDEA_DEBUG
- bool "ChipIdea driver debug"
- help
- Say Y here to enable debugging output of the ChipIdea driver.
-
endif
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 4decb12f2578..518e445476c3 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -1,11 +1,8 @@
-ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
-
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
-ci_hdrc-y := core.o otg.o
+ci_hdrc-y := core.o otg.o debug.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
-ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
# Glue/Bridge layers go here
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 41d7cf6d63ba..cd414559040f 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -433,4 +433,7 @@ int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
void ci_platform_configure(struct ci_hdrc *ci);
+int dbg_create_files(struct ci_hdrc *ci);
+
+void dbg_remove_files(struct ci_hdrc *ci);
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 5a048b7b92e8..f14f4ab47ebb 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -345,6 +345,11 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
return 0;
}
+static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
+{
+ ci_hdrc_imx_remove(pdev);
+}
+
#ifdef CONFIG_PM
static int imx_controller_suspend(struct device *dev)
{
@@ -462,6 +467,7 @@ static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
static struct platform_driver ci_hdrc_imx_driver = {
.probe = ci_hdrc_imx_probe,
.remove = ci_hdrc_imx_remove,
+ .shutdown = ci_hdrc_imx_shutdown,
.driver = {
.name = "imx_usb",
.of_match_table = ci_hdrc_imx_dt_ids,
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index d79ecc08a1be..3889809fd0c4 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -25,7 +25,8 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
case CI_HDRC_CONTROLLER_RESET_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
- writel(0, USB_AHBMODE);
+ /* use AHB transactor, allow posted data writes */
+ writel(0x8, USB_AHBMODE);
usb_phy_init(ci->usb_phy);
break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 965d0e240dcb..7404064b9bbc 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -23,7 +23,6 @@
* - BUS: bus glue code, bus abstraction layer
*
* Compile Options
- * - CONFIG_USB_CHIPIDEA_DEBUG: enable debug facilities
* - STALL_IN: non-empty bulk-in pipes cannot be halted
* if defined mass storage compliance succeeds but with warnings
* => case 4: Hi > Dn
@@ -71,7 +70,6 @@
#include "udc.h"
#include "bits.h"
#include "host.h"
-#include "debug.h"
#include "otg.h"
#include "otg_fsm.h"
@@ -688,52 +686,39 @@ static int ci_get_platdata(struct device *dev,
if (usb_get_maximum_speed(dev) == USB_SPEED_FULL)
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
- if (of_find_property(dev->of_node, "phy-clkgate-delay-us", NULL))
- of_property_read_u32(dev->of_node, "phy-clkgate-delay-us",
+ of_property_read_u32(dev->of_node, "phy-clkgate-delay-us",
&platdata->phy_clkgate_delay_us);
platdata->itc_setting = 1;
- if (of_find_property(dev->of_node, "itc-setting", NULL)) {
- ret = of_property_read_u32(dev->of_node, "itc-setting",
- &platdata->itc_setting);
- if (ret) {
- dev_err(dev,
- "failed to get itc-setting\n");
- return ret;
- }
- }
- if (of_find_property(dev->of_node, "ahb-burst-config", NULL)) {
- ret = of_property_read_u32(dev->of_node, "ahb-burst-config",
- &platdata->ahb_burst_config);
- if (ret) {
- dev_err(dev,
- "failed to get ahb-burst-config\n");
- return ret;
- }
+ of_property_read_u32(dev->of_node, "itc-setting",
+ &platdata->itc_setting);
+
+ ret = of_property_read_u32(dev->of_node, "ahb-burst-config",
+ &platdata->ahb_burst_config);
+ if (!ret) {
platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST;
+ } else if (ret != -EINVAL) {
+ dev_err(dev, "failed to get ahb-burst-config\n");
+ return ret;
}
- if (of_find_property(dev->of_node, "tx-burst-size-dword", NULL)) {
- ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword",
- &platdata->tx_burst_size);
- if (ret) {
- dev_err(dev,
- "failed to get tx-burst-size-dword\n");
- return ret;
- }
+ ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword",
+ &platdata->tx_burst_size);
+ if (!ret) {
platdata->flags |= CI_HDRC_OVERRIDE_TX_BURST;
+ } else if (ret != -EINVAL) {
+ dev_err(dev, "failed to get tx-burst-size-dword\n");
+ return ret;
}
- if (of_find_property(dev->of_node, "rx-burst-size-dword", NULL)) {
- ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword",
- &platdata->rx_burst_size);
- if (ret) {
- dev_err(dev,
- "failed to get rx-burst-size-dword\n");
- return ret;
- }
+ ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword",
+ &platdata->rx_burst_size);
+ if (!ret) {
platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
+ } else if (ret != -EINVAL) {
+ dev_err(dev, "failed to get rx-burst-size-dword\n");
+ return ret;
}
ext_id = ERR_PTR(-ENODEV);
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 58c8485a0715..a4f7db2e18dd 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -15,7 +15,6 @@
#include "ci.h"
#include "udc.h"
#include "bits.h"
-#include "debug.h"
#include "otg.h"
/**
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
deleted file mode 100644
index e16478c4a943..000000000000
--- a/drivers/usb/chipidea/debug.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * debug.h - ChipIdea USB driver debug interfaces
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * 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 __DRIVERS_USB_CHIPIDEA_DEBUG_H
-#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
-
-#ifdef CONFIG_USB_CHIPIDEA_DEBUG
-int dbg_create_files(struct ci_hdrc *ci);
-void dbg_remove_files(struct ci_hdrc *ci);
-#else
-static inline int dbg_create_files(struct ci_hdrc *ci)
-{
- return 0;
-}
-
-static inline void dbg_remove_files(struct ci_hdrc *ci)
-{
-}
-#endif
-
-#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 3d24304405b3..053bac9d983c 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -190,6 +190,8 @@ static void host_stop(struct ci_hdrc *ci)
(ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON))
regulator_disable(ci->platdata->reg_vbus);
}
+ ci->hcd = NULL;
+ ci->otg.host = NULL;
}
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 00ab59d45da1..ba90dc66703d 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -485,20 +485,30 @@ static void ci_otg_loc_conn(struct otg_fsm *fsm, int on)
/*
* Generate SOF by host.
- * This is controlled through suspend/resume the port.
* In host mode, controller will automatically send SOF.
* Suspend will block the data on the port.
+ *
+ * This is controlled through usbcore by usb autosuspend,
+ * so the usb device class driver need support autosuspend,
+ * otherwise the bus suspend will not happen.
*/
static void ci_otg_loc_sof(struct otg_fsm *fsm, int on)
{
- struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
+ struct usb_device *udev;
- if (on)
- hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_FPR,
- PORTSC_FPR);
- else
- hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_SUSP,
- PORTSC_SUSP);
+ if (!fsm->otg->host)
+ return;
+
+ udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+ if (!udev)
+ return;
+
+ if (on) {
+ usb_disable_autosuspend(udev);
+ } else {
+ pm_runtime_set_autosuspend_delay(&udev->dev, 0);
+ usb_enable_autosuspend(udev);
+ }
}
/*
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index 2689375ae5da..262d6ef8df7c 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -62,7 +62,7 @@
/* SSEND time before SRP */
#define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */
-#ifdef CONFIG_USB_OTG_FSM
+#if IS_ENABLED(CONFIG_USB_OTG_FSM)
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);
int ci_otg_fsm_work(struct ci_hdrc *ci);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 391a1225b0ba..3eafa2c9a2ba 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -26,7 +26,6 @@
#include "ci.h"
#include "udc.h"
#include "bits.h"
-#include "debug.h"
#include "otg.h"
#include "otg_fsm.h"
@@ -349,14 +348,13 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
if (node == NULL)
return -ENOMEM;
- node->ptr = dma_pool_alloc(hwep->td_pool, GFP_ATOMIC,
+ node->ptr = dma_pool_zalloc(hwep->td_pool, GFP_ATOMIC,
&node->dma);
if (node->ptr == NULL) {
kfree(node);
return -ENOMEM;
}
- memset(node->ptr, 0, sizeof(struct ci_hw_td));
node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
@@ -404,9 +402,9 @@ static inline u8 _usb_addr(struct ci_hw_ep *ep)
}
/**
- * _hardware_queue: configures a request at hardware level
- * @gadget: gadget
+ * _hardware_enqueue: configures a request at hardware level
* @hwep: endpoint
+ * @hwreq: request
*
* This function returns an error code
*/
@@ -435,19 +433,28 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
if (hwreq->req.dma % PAGE_SIZE)
pages--;
- if (rest == 0)
- add_td_to_list(hwep, hwreq, 0);
+ if (rest == 0) {
+ ret = add_td_to_list(hwep, hwreq, 0);
+ if (ret < 0)
+ goto done;
+ }
while (rest > 0) {
unsigned count = min(hwreq->req.length - hwreq->req.actual,
(unsigned)(pages * CI_HDRC_PAGE_SIZE));
- add_td_to_list(hwep, hwreq, count);
+ ret = add_td_to_list(hwep, hwreq, count);
+ if (ret < 0)
+ goto done;
+
rest -= count;
}
if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
- && (hwreq->req.length % hwep->ep.maxpacket == 0))
- add_td_to_list(hwep, hwreq, 0);
+ && (hwreq->req.length % hwep->ep.maxpacket == 0)) {
+ ret = add_td_to_list(hwep, hwreq, 0);
+ if (ret < 0)
+ goto done;
+ }
firstnode = list_first_entry(&hwreq->tds, struct td_node, td);
@@ -788,8 +795,12 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
/**
* _ep_queue: queues (submits) an I/O request to an endpoint
+ * @ep: endpoint
+ * @req: request
+ * @gfp_flags: GFP flags (not used)
*
* Caller must hold lock
+ * This function returns an error code
*/
static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index 673d53038ed2..e6ec125e4485 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -17,6 +17,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
+#include <linux/of_platform.h>
const char *usb_otg_state_string(enum usb_otg_state state)
{
@@ -106,25 +107,72 @@ static const char *const usb_dr_modes[] = {
[USB_DR_MODE_OTG] = "otg",
};
+static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
+ if (!strcmp(usb_dr_modes[i], str))
+ return i;
+
+ return USB_DR_MODE_UNKNOWN;
+}
+
enum usb_dr_mode usb_get_dr_mode(struct device *dev)
{
const char *dr_mode;
- int err, i;
+ int err;
err = device_property_read_string(dev, "dr_mode", &dr_mode);
if (err < 0)
return USB_DR_MODE_UNKNOWN;
- for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
- if (!strcmp(dr_mode, usb_dr_modes[i]))
- return i;
-
- return USB_DR_MODE_UNKNOWN;
+ return usb_get_dr_mode_from_string(dr_mode);
}
EXPORT_SYMBOL_GPL(usb_get_dr_mode);
#ifdef CONFIG_OF
/**
+ * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
+ * which is associated with the given phy device_node
+ * @np: Pointer to the given phy device_node
+ *
+ * In dts a usb controller associates with phy devices. The function gets
+ * the string from property 'dr_mode' of the controller associated with the
+ * given phy device node, and returns the correspondig enum usb_dr_mode.
+ */
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
+{
+ struct device_node *controller = NULL;
+ struct device_node *phy;
+ const char *dr_mode;
+ int index;
+ int err;
+
+ do {
+ controller = of_find_node_with_property(controller, "phys");
+ index = 0;
+ do {
+ phy = of_parse_phandle(controller, "phys", index);
+ of_node_put(phy);
+ if (phy == phy_np)
+ goto finish;
+ index++;
+ } while (phy);
+ } while (controller);
+
+finish:
+ err = of_property_read_string(controller, "dr_mode", &dr_mode);
+ of_node_put(controller);
+
+ if (err < 0)
+ return USB_DR_MODE_UNKNOWN;
+
+ return usb_get_dr_mode_from_string(dr_mode);
+}
+EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy);
+
+/**
* of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
* for given targeted hosts (non-PC hosts)
* @np: Pointer to the given device_node
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index dbc3e143453a..59e7a3369084 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -100,6 +100,11 @@ static bool usbfs_snoop;
module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
+static unsigned usbfs_snoop_max = 65536;
+module_param(usbfs_snoop_max, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usbfs_snoop_max,
+ "maximum number of bytes to print while snooping");
+
#define snoop(dev, format, arg...) \
do { \
if (usbfs_snoop) \
@@ -368,6 +373,7 @@ static void snoop_urb(struct usb_device *udev,
ep, t, d, length, timeout_or_status);
}
+ data_len = min(data_len, usbfs_snoop_max);
if (data && data_len > 0) {
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
data, data_len, 1);
@@ -378,7 +384,8 @@ static void snoop_urb_data(struct urb *urb, unsigned len)
{
int i, size;
- if (!usbfs_snoop)
+ len = min(len, usbfs_snoop_max);
+ if (!usbfs_snoop || len == 0)
return;
if (urb->num_sgs == 0) {
@@ -1685,8 +1692,12 @@ static struct async *reap_as(struct usb_dev_state *ps)
static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
+
if (as) {
- int retval = processcompl(as, (void __user * __user *)arg);
+ int retval;
+
+ snoop(&ps->dev->dev, "reap %p\n", as->userurb);
+ retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
return retval;
}
@@ -1702,6 +1713,7 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
as = async_getcompleted(ps);
if (as) {
+ snoop(&ps->dev->dev, "reap %p\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -1828,8 +1840,12 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
+
if (as) {
- int retval = processcompl_compat(as, (void __user * __user *)arg);
+ int retval;
+
+ snoop(&ps->dev->dev, "reap %p\n", as->userurb);
+ retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
return retval;
}
@@ -1845,6 +1861,7 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
as = async_getcompleted(ps);
if (as) {
+ snoop(&ps->dev->dev, "reap %p\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -2249,7 +2266,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
#endif
case USBDEVFS_DISCARDURB:
- snoop(&dev->dev, "%s: DISCARDURB\n", __func__);
+ snoop(&dev->dev, "%s: DISCARDURB %p\n", __func__, p);
ret = proc_unlinkurb(ps, p);
break;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 1c102d60cd9f..df0e3b92533a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -3000,7 +3000,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
-struct usb_mon_operations *mon_ops;
+const struct usb_mon_operations *mon_ops;
/*
* The registration is unlocked.
@@ -3010,7 +3010,7 @@ struct usb_mon_operations *mon_ops;
* symbols from usbcore, usbcore gets referenced and cannot be unloaded first.
*/
-int usb_mon_register (struct usb_mon_operations *ops)
+int usb_mon_register(const struct usb_mon_operations *ops)
{
if (mon_ops)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ddbf32d599cb..51b436918f78 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3324,7 +3324,7 @@ static int finish_port_resume(struct usb_device *udev)
/*
* There are some SS USB devices which take longer time for link training.
* XHCI specs 4.19.4 says that when Link training is successful, port
- * sets CSC bit to 1. So if SW reads port status before successful link
+ * sets CCS bit to 1. So if SW reads port status before successful link
* training, then it will not find device to be present.
* USB Analyzer log with such buggy devices show that in some cases
* device switch on the RX termination after long delay of host enabling
@@ -3335,14 +3335,17 @@ static int finish_port_resume(struct usb_device *udev)
* routine implements a 2000 ms timeout for link training. If in a case
* link trains before timeout, loop will exit earlier.
*
+ * There are also some 2.0 hard drive based devices and 3.0 thumb
+ * drives that, when plugged into a 2.0 only port, take a long
+ * time to set CCS after VBUS enable.
+ *
* FIXME: If a device was connected before suspend, but was removed
* while system was asleep, then the loop in the following routine will
* only exit at timeout.
*
- * This routine should only be called when persist is enabled for a SS
- * device.
+ * This routine should only be called when persist is enabled.
*/
-static int wait_for_ss_port_enable(struct usb_device *udev,
+static int wait_for_connected(struct usb_device *udev,
struct usb_hub *hub, int *port1,
u16 *portchange, u16 *portstatus)
{
@@ -3355,6 +3358,7 @@ static int wait_for_ss_port_enable(struct usb_device *udev,
delay_ms += 20;
status = hub_port_status(hub, *port1, portstatus, portchange);
}
+ dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms);
return status;
}
@@ -3454,8 +3458,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
}
}
- if (udev->persist_enabled && hub_is_superspeed(hub->hdev))
- status = wait_for_ss_port_enable(udev, hub, &port1, &portchange,
+ if (udev->persist_enabled)
+ status = wait_for_connected(udev, hub, &port1, &portchange,
&portstatus);
status = check_port_resume_type(udev,
@@ -3895,17 +3899,30 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
return;
}
- if (usb_set_lpm_timeout(udev, state, timeout))
+ if (usb_set_lpm_timeout(udev, state, timeout)) {
/* If we can't set the parent hub U1/U2 timeout,
* device-initiated LPM won't be allowed either, so let the xHCI
* host know that this link state won't be enabled.
*/
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+ } else {
+ /* Only a configured device will accept the Set Feature
+ * U1/U2_ENABLE
+ */
+ if (udev->actconfig)
+ usb_set_device_initiated_lpm(udev, state, true);
- /* Only a configured device will accept the Set Feature U1/U2_ENABLE */
- else if (udev->actconfig)
- usb_set_device_initiated_lpm(udev, state, true);
-
+ /* As soon as usb_set_lpm_timeout(timeout) returns 0, the
+ * hub-initiated LPM is enabled. Thus, LPM is enabled no
+ * matter the result of usb_set_device_initiated_lpm().
+ * The only difference is whether device is able to initiate
+ * LPM.
+ */
+ if (state == USB3_LPM_U1)
+ udev->usb3_lpm_u1_enabled = 1;
+ else if (state == USB3_LPM_U2)
+ udev->usb3_lpm_u2_enabled = 1;
+ }
}
/*
@@ -3945,6 +3962,18 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
"bus schedule bandwidth may be impacted.\n",
usb3_lpm_names[state]);
+
+ /* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM
+ * is disabled. Hub will disallows link to enter U1/U2 as well,
+ * even device is initiating LPM. Hence LPM is disabled if hub LPM
+ * timeout set to 0, no matter device-initiated LPM is disabled or
+ * not.
+ */
+ if (state == USB3_LPM_U1)
+ udev->usb3_lpm_u1_enabled = 0;
+ else if (state == USB3_LPM_U2)
+ udev->usb3_lpm_u2_enabled = 0;
+
return 0;
}
@@ -3979,8 +4008,6 @@ int usb_disable_lpm(struct usb_device *udev)
if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
goto enable_lpm;
- udev->usb3_lpm_enabled = 0;
-
return 0;
enable_lpm:
@@ -4017,6 +4044,8 @@ EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
void usb_enable_lpm(struct usb_device *udev)
{
struct usb_hcd *hcd;
+ struct usb_hub *hub;
+ struct usb_port *port_dev;
if (!udev || !udev->parent ||
udev->speed != USB_SPEED_SUPER ||
@@ -4036,10 +4065,17 @@ void usb_enable_lpm(struct usb_device *udev)
if (udev->lpm_disable_count > 0)
return;
- usb_enable_link_state(hcd, udev, USB3_LPM_U1);
- usb_enable_link_state(hcd, udev, USB3_LPM_U2);
+ hub = usb_hub_to_struct_hub(udev->parent);
+ if (!hub)
+ return;
+
+ port_dev = hub->ports[udev->portnum - 1];
+
+ if (port_dev->usb3_lpm_u1_permit)
+ usb_enable_link_state(hcd, udev, USB3_LPM_U1);
- udev->usb3_lpm_enabled = 1;
+ if (port_dev->usb3_lpm_u2_permit)
+ usb_enable_link_state(hcd, udev, USB3_LPM_U2);
}
EXPORT_SYMBOL_GPL(usb_enable_lpm);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 688817fb3246..45d070dd1d03 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -92,6 +92,8 @@ struct usb_hub {
* @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
* @portnum: port index num based one
* @is_superspeed cache super-speed status
+ * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
+ * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
*/
struct usb_port {
struct usb_device *child;
@@ -104,6 +106,8 @@ struct usb_port {
struct mutex status_lock;
u8 portnum;
unsigned int is_superspeed:1;
+ unsigned int usb3_lpm_u1_permit:1;
+ unsigned int usb3_lpm_u2_permit:1;
};
#define to_usb_port(_dev) \
@@ -155,4 +159,3 @@ static inline int hub_port_debounce_be_stable(struct usb_hub *hub,
{
return hub_port_debounce(hub, port1, false);
}
-
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 514b563e3e5f..14718a9ffcfb 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -50,6 +50,72 @@ static ssize_t connect_type_show(struct device *dev,
}
static DEVICE_ATTR_RO(connect_type);
+static ssize_t usb3_lpm_permit_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ const char *p;
+
+ if (port_dev->usb3_lpm_u1_permit) {
+ if (port_dev->usb3_lpm_u2_permit)
+ p = "u1_u2";
+ else
+ p = "u1";
+ } else {
+ if (port_dev->usb3_lpm_u2_permit)
+ p = "u2";
+ else
+ p = "0";
+ }
+
+ return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t usb3_lpm_permit_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ struct usb_device *udev = port_dev->child;
+ struct usb_hcd *hcd;
+
+ if (!strncmp(buf, "u1_u2", 5)) {
+ port_dev->usb3_lpm_u1_permit = 1;
+ port_dev->usb3_lpm_u2_permit = 1;
+
+ } else if (!strncmp(buf, "u1", 2)) {
+ port_dev->usb3_lpm_u1_permit = 1;
+ port_dev->usb3_lpm_u2_permit = 0;
+
+ } else if (!strncmp(buf, "u2", 2)) {
+ port_dev->usb3_lpm_u1_permit = 0;
+ port_dev->usb3_lpm_u2_permit = 1;
+
+ } else if (!strncmp(buf, "0", 1)) {
+ port_dev->usb3_lpm_u1_permit = 0;
+ port_dev->usb3_lpm_u2_permit = 0;
+ } else
+ return -EINVAL;
+
+ /* If device is connected to the port, disable or enable lpm
+ * to make new u1 u2 setting take effect immediately.
+ */
+ if (udev) {
+ hcd = bus_to_hcd(udev->bus);
+ if (!hcd)
+ return -EINVAL;
+ usb_lock_device(udev);
+ mutex_lock(hcd->bandwidth_mutex);
+ if (!usb_disable_lpm(udev))
+ usb_enable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_unlock_device(udev);
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb3_lpm_permit);
+
static struct attribute *port_dev_attrs[] = {
&dev_attr_connect_type.attr,
NULL,
@@ -64,6 +130,21 @@ static const struct attribute_group *port_dev_group[] = {
NULL,
};
+static struct attribute *port_dev_usb3_attrs[] = {
+ &dev_attr_usb3_lpm_permit.attr,
+ NULL,
+};
+
+static struct attribute_group port_dev_usb3_attr_grp = {
+ .attrs = port_dev_usb3_attrs,
+};
+
+static const struct attribute_group *port_dev_usb3_group[] = {
+ &port_dev_attr_grp,
+ &port_dev_usb3_attr_grp,
+ NULL,
+};
+
static void usb_port_device_release(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
@@ -407,6 +488,7 @@ static void find_and_link_peer(struct usb_hub *hub, int port1)
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
{
struct usb_port *port_dev;
+ struct usb_device *hdev = hub->hdev;
int retval;
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
@@ -423,7 +505,12 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
port_dev->portnum = port1;
set_bit(port1, hub->power_bits);
port_dev->dev.parent = hub->intfdev;
- port_dev->dev.groups = port_dev_group;
+ if (hub_is_superspeed(hdev)) {
+ port_dev->usb3_lpm_u1_permit = 1;
+ port_dev->usb3_lpm_u2_permit = 1;
+ port_dev->dev.groups = port_dev_usb3_group;
+ } else
+ port_dev->dev.groups = port_dev_group;
port_dev->dev.type = &usb_port_device_type;
port_dev->dev.driver = &usb_port_driver;
if (hub_is_superspeed(hub->hdev))
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d9ec2de6c4cf..65b6e6b84043 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -531,7 +531,7 @@ static ssize_t usb2_lpm_besl_store(struct device *dev,
}
static DEVICE_ATTR_RW(usb2_lpm_besl);
-static ssize_t usb3_hardware_lpm_show(struct device *dev,
+static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
@@ -539,7 +539,7 @@ static ssize_t usb3_hardware_lpm_show(struct device *dev,
usb_lock_device(udev);
- if (udev->usb3_lpm_enabled)
+ if (udev->usb3_lpm_u1_enabled)
p = "enabled";
else
p = "disabled";
@@ -548,7 +548,26 @@ static ssize_t usb3_hardware_lpm_show(struct device *dev,
return sprintf(buf, "%s\n", p);
}
-static DEVICE_ATTR_RO(usb3_hardware_lpm);
+static DEVICE_ATTR_RO(usb3_hardware_lpm_u1);
+
+static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ const char *p;
+
+ usb_lock_device(udev);
+
+ if (udev->usb3_lpm_u2_enabled)
+ p = "enabled";
+ else
+ p = "disabled";
+
+ usb_unlock_device(udev);
+
+ return sprintf(buf, "%s\n", p);
+}
+static DEVICE_ATTR_RO(usb3_hardware_lpm_u2);
static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_hardware_lpm.attr,
@@ -562,7 +581,8 @@ static struct attribute_group usb2_hardware_lpm_attr_group = {
};
static struct attribute *usb3_hardware_lpm_attr[] = {
- &dev_attr_usb3_hardware_lpm.attr,
+ &dev_attr_usb3_hardware_lpm_u1.attr,
+ &dev_attr_usb3_hardware_lpm_u2.attr,
NULL,
};
static struct attribute_group usb3_hardware_lpm_attr_group = {
@@ -592,7 +612,8 @@ static int add_power_attributes(struct device *dev)
if (udev->usb2_hw_lpm_capable == 1)
rc = sysfs_merge_group(&dev->kobj,
&usb2_hardware_lpm_attr_group);
- if (udev->lpm_capable == 1)
+ if (udev->speed == USB_SPEED_SUPER &&
+ udev->lpm_capable == 1)
rc = sysfs_merge_group(&dev->kobj,
&usb3_hardware_lpm_attr_group);
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index cafc11902794..ebb29caa3fe4 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -49,12 +49,7 @@ const char *usbcore_name = "usbcore";
static bool nousb; /* Disable USB when built into kernel image */
-/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
-#ifdef MODULE
module_param(nousb, bool, 0444);
-#else
-core_param(nousb, nousb, bool, 0444);
-#endif
/*
* for external read access to <nousb>
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index ef73e498e98f..39a0fa8a4c0a 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -481,64 +481,168 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
-static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
+int dwc2_core_reset(struct dwc2_hsotg *hsotg)
{
u32 greset;
int count = 0;
- u32 gusbcfg;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
- /* Wait for AHB master IDLE state */
+ /* Core Soft Reset */
+ greset = dwc2_readl(hsotg->regs + GRSTCTL);
+ greset |= GRSTCTL_CSFTRST;
+ dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
- usleep_range(20000, 40000);
+ udelay(1);
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 50) {
dev_warn(hsotg->dev,
- "%s() HANG! AHB Idle GRSTCTL=%0x\n",
+ "%s() HANG! Soft Reset GRSTCTL=%0x\n",
__func__, greset);
return -EBUSY;
}
- } while (!(greset & GRSTCTL_AHBIDLE));
+ } while (greset & GRSTCTL_CSFTRST);
- /* Core Soft Reset */
+ /* Wait for AHB master IDLE state */
count = 0;
- greset |= GRSTCTL_CSFTRST;
- dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
- usleep_range(20000, 40000);
+ udelay(1);
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 50) {
dev_warn(hsotg->dev,
- "%s() HANG! Soft Reset GRSTCTL=%0x\n",
+ "%s() HANG! AHB Idle GRSTCTL=%0x\n",
__func__, greset);
return -EBUSY;
}
- } while (greset & GRSTCTL_CSFTRST);
+ } while (!(greset & GRSTCTL_AHBIDLE));
- if (hsotg->dr_mode == USB_DR_MODE_HOST) {
- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
- gusbcfg |= GUSBCFG_FORCEHOSTMODE;
- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
- } else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
- gusbcfg |= GUSBCFG_FORCEDEVMODE;
- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
- } else if (hsotg->dr_mode == USB_DR_MODE_OTG) {
- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
- gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
- }
+ return 0;
+}
+
+/*
+ * Force the mode of the controller.
+ *
+ * Forcing the mode is needed for two cases:
+ *
+ * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
+ * controller to stay in a particular mode regardless of ID pin
+ * changes. We do this usually after a core reset.
+ *
+ * 2) During probe we want to read reset values of the hw
+ * configuration registers that are only available in either host or
+ * device mode. We may need to force the mode if the current mode does
+ * not allow us to access the register in the mode that we want.
+ *
+ * In either case it only makes sense to force the mode if the
+ * controller hardware is OTG capable.
+ *
+ * Checks are done in this function to determine whether doing a force
+ * would be valid or not.
+ *
+ * If a force is done, it requires a 25ms delay to take effect.
+ *
+ * Returns true if the mode was forced.
+ */
+static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
+{
+ u32 gusbcfg;
+ u32 set;
+ u32 clear;
+
+ dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device");
+
+ /*
+ * Force mode has no effect if the hardware is not OTG.
+ */
+ if (!dwc2_hw_is_otg(hsotg))
+ return false;
+
+ /*
+ * If dr_mode is either peripheral or host only, there is no
+ * need to ever force the mode to the opposite mode.
+ */
+ if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
+ return false;
+
+ if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
+ return false;
+
+ gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+
+ set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
+ clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
+
+ /*
+ * If the force mode bit is already set, don't set it.
+ */
+ if ((gusbcfg & set) && !(gusbcfg & clear))
+ return false;
+
+ gusbcfg &= ~clear;
+ gusbcfg |= set;
+ dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
+
+ msleep(25);
+ return true;
+}
+
+/*
+ * Clears the force mode bits.
+ */
+static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
+{
+ u32 gusbcfg;
+
+ gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+ gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
+ dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
/*
* NOTE: This long sleep is _very_ important, otherwise the core will
* not stay in host mode after a connector ID change!
*/
- usleep_range(150000, 200000);
+ msleep(25);
+}
+
+/*
+ * Sets or clears force mode based on the dr_mode parameter.
+ */
+void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
+{
+ switch (hsotg->dr_mode) {
+ case USB_DR_MODE_HOST:
+ dwc2_force_mode(hsotg, true);
+ break;
+ case USB_DR_MODE_PERIPHERAL:
+ dwc2_force_mode(hsotg, false);
+ break;
+ case USB_DR_MODE_OTG:
+ dwc2_clear_force_mode(hsotg);
+ break;
+ default:
+ dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
+ __func__, hsotg->dr_mode);
+ break;
+ }
+}
+
+/*
+ * Do core a soft reset of the core. Be careful with this because it
+ * resets all the internal state machines of the core.
+ *
+ * Additionally this will apply force mode as per the hsotg->dr_mode
+ * parameter.
+ */
+int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
+{
+ int retval;
+ retval = dwc2_core_reset(hsotg);
+ if (retval)
+ return retval;
+
+ dwc2_force_dr_mode(hsotg);
return 0;
}
@@ -553,16 +657,20 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
*/
if (select_phy) {
dev_dbg(hsotg->dev, "FS PHY selected\n");
+
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- usbcfg |= GUSBCFG_PHYSEL;
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+ if (!(usbcfg & GUSBCFG_PHYSEL)) {
+ usbcfg |= GUSBCFG_PHYSEL;
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
- /* Reset after a PHY select */
- retval = dwc2_core_reset(hsotg);
- if (retval) {
- dev_err(hsotg->dev, "%s() Reset failed, aborting",
- __func__);
- return retval;
+ /* Reset after a PHY select */
+ retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+
+ if (retval) {
+ dev_err(hsotg->dev,
+ "%s: Reset failed, aborting", __func__);
+ return retval;
+ }
}
}
@@ -597,13 +705,13 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
- u32 usbcfg;
+ u32 usbcfg, usbcfg_old;
int retval = 0;
if (!select_phy)
return 0;
- usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg = usbcfg_old = dwc2_readl(hsotg->regs + GUSBCFG);
/*
* HS PHY parameters. These parameters are preserved during soft reset
@@ -631,14 +739,16 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
break;
}
- dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+ if (usbcfg != usbcfg_old) {
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
- /* Reset after setting the PHY parameters */
- retval = dwc2_core_reset(hsotg);
- if (retval) {
- dev_err(hsotg->dev, "%s() Reset failed, aborting",
- __func__);
- return retval;
+ /* Reset after setting the PHY parameters */
+ retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ if (retval) {
+ dev_err(hsotg->dev,
+ "%s: Reset failed, aborting", __func__);
+ return retval;
+ }
}
return retval;
@@ -765,11 +875,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
* dwc2_core_init() - Initializes the DWC_otg controller registers and
* prepares the core for device mode or host mode operation
*
- * @hsotg: Programming view of the DWC_otg controller
- * @select_phy: If true then also set the Phy type
- * @irq: If >= 0, the irq to register
+ * @hsotg: Programming view of the DWC_otg controller
+ * @initial_setup: If true then this is the first init for this instance.
*/
-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
{
u32 usbcfg, otgctl;
int retval;
@@ -791,18 +900,26 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
- /* Reset the Controller */
- retval = dwc2_core_reset(hsotg);
- if (retval) {
- dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
- __func__);
- return retval;
+ /*
+ * Reset the Controller
+ *
+ * We only need to reset the controller if this is a re-init.
+ * For the first init we know for sure that earlier code reset us (it
+ * needed to in order to properly detect various parameters).
+ */
+ if (!initial_setup) {
+ retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ if (retval) {
+ dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
+ __func__);
+ return retval;
+ }
}
/*
* This needs to happen in FS mode before any other programming occurs
*/
- retval = dwc2_phy_init(hsotg, select_phy);
+ retval = dwc2_phy_init(hsotg, initial_setup);
if (retval)
return retval;
@@ -1707,6 +1824,7 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
u32 hcchar;
u32 hctsiz = 0;
u16 num_packets;
+ u32 ec_mc;
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -1743,6 +1861,13 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
TSIZ_XFERSIZE_MASK;
+
+ /* For split set ec_mc for immediate retries */
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ ec_mc = 3;
+ else
+ ec_mc = 1;
} else {
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, "no split\n");
@@ -1805,6 +1930,9 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
TSIZ_XFERSIZE_MASK;
+
+ /* The ec_mc gets the multi_count for non-split */
+ ec_mc = chan->multi_count;
}
chan->start_pkt_count = num_packets;
@@ -1855,8 +1983,7 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
hcchar &= ~HCCHAR_MULTICNT_MASK;
- hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
- HCCHAR_MULTICNT_MASK;
+ hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;
dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
if (hcchar & HCCHAR_CHDIS)
@@ -1905,7 +2032,6 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan)
{
u32 hcchar;
- u32 hc_dma;
u32 hctsiz = 0;
if (chan->do_ping)
@@ -1934,14 +2060,14 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
- hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK;
+ dma_sync_single_for_device(hsotg->dev, chan->desc_list_addr,
+ chan->desc_list_sz, DMA_TO_DEVICE);
+
+ dwc2_writel(chan->desc_list_addr, hsotg->regs + HCDMA(chan->hc_num));
- /* Always start from first descriptor */
- hc_dma &= ~HCDMA_CTD_MASK;
- dwc2_writel(hc_dma, hsotg->regs + HCDMA(chan->hc_num));
if (dbg_hc(chan))
- dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n",
- hc_dma, chan->hc_num);
+ dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n",
+ &chan->desc_list_addr, chan->hc_num);
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
hcchar &= ~HCCHAR_MULTICNT_MASK;
@@ -2485,6 +2611,29 @@ void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)
hsotg->core_params->dma_desc_enable = val;
}
+void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+
+ if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
+ !hsotg->hw_params.dma_desc_enable))
+ valid = 0;
+ if (val < 0)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for dma_desc_fs_enable parameter. Check HW configuration.\n",
+ val);
+ val = (hsotg->core_params->dma_enable > 0 &&
+ hsotg->hw_params.dma_desc_enable);
+ }
+
+ hsotg->core_params->dma_desc_fs_enable = val;
+ dev_dbg(hsotg->dev, "Setting dma_desc_fs_enable to %d\n", val);
+}
+
void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
int val)
{
@@ -3016,6 +3165,7 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
dwc2_set_param_otg_cap(hsotg, params->otg_cap);
dwc2_set_param_dma_enable(hsotg, params->dma_enable);
dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable);
+ dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable);
dwc2_set_param_host_support_fs_ls_low_power(hsotg,
params->host_support_fs_ls_low_power);
dwc2_set_param_enable_dynamic_fifo(hsotg,
@@ -3052,17 +3202,93 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
dwc2_set_param_hibernation(hsotg, params->hibernation);
}
+/*
+ * Forces either host or device mode if the controller is not
+ * currently in that mode.
+ *
+ * Returns true if the mode was forced.
+ */
+static bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host)
+{
+ if (host && dwc2_is_host_mode(hsotg))
+ return false;
+ else if (!host && dwc2_is_device_mode(hsotg))
+ return false;
+
+ return dwc2_force_mode(hsotg, host);
+}
+
+/*
+ * Gets host hardware parameters. Forces host mode if not currently in
+ * host mode. Should be called immediately after a core soft reset in
+ * order to get the reset values.
+ */
+static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_hw_params *hw = &hsotg->hw_params;
+ u32 gnptxfsiz;
+ u32 hptxfsiz;
+ bool forced;
+
+ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
+ return;
+
+ forced = dwc2_force_mode_if_needed(hsotg, true);
+
+ gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
+ hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
+ dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+ dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
+
+ if (forced)
+ dwc2_clear_force_mode(hsotg);
+
+ hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+ FIFOSIZE_DEPTH_SHIFT;
+ hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+ FIFOSIZE_DEPTH_SHIFT;
+}
+
+/*
+ * Gets device hardware parameters. Forces device mode if not
+ * currently in device mode. Should be called immediately after a core
+ * soft reset in order to get the reset values.
+ */
+static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_hw_params *hw = &hsotg->hw_params;
+ bool forced;
+ u32 gnptxfsiz;
+
+ if (hsotg->dr_mode == USB_DR_MODE_HOST)
+ return;
+
+ forced = dwc2_force_mode_if_needed(hsotg, false);
+
+ gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
+ dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+
+ if (forced)
+ dwc2_clear_force_mode(hsotg);
+
+ hw->dev_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+ FIFOSIZE_DEPTH_SHIFT;
+}
+
/**
* During device initialization, read various hardware configuration
* registers and interpret the contents.
+ *
+ * This should be called during driver probe. It will perform a core
+ * soft reset in order to get the reset values of the parameters.
*/
int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
unsigned width;
u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
- u32 hptxfsiz, grxfsiz, gnptxfsiz;
- u32 gusbcfg;
+ u32 grxfsiz;
+ int retval;
/*
* Attempt to ensure this device is really a DWC_otg Controller.
@@ -3082,6 +3308,10 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
+ retval = dwc2_core_reset(hsotg);
+ if (retval)
+ return retval;
+
hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1);
hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3);
@@ -3094,20 +3324,16 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
- /* Force host mode to get HPTXFSIZ / GNPTXFSIZ exact power on value */
- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- gusbcfg |= GUSBCFG_FORCEHOSTMODE;
- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
- usleep_range(100000, 150000);
+ /*
+ * Host specific hardware parameters. Reading these parameters
+ * requires the controller to be in host mode. The mode will
+ * be forced, if necessary, to read these values.
+ */
+ dwc2_get_host_hwparams(hsotg);
+ dwc2_get_dev_hwparams(hsotg);
- gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
- hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
- dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
- dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
- gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
- gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
- dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
- usleep_range(100000, 150000);
+ /* hwcfg1 */
+ hw->dev_ep_dirs = hwcfg1;
/* hwcfg2 */
hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
@@ -3163,10 +3389,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
/* fifo sizes */
hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
GRXFSIZ_DEPTH_SHIFT;
- hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
- FIFOSIZE_DEPTH_SHIFT;
- hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
- FIFOSIZE_DEPTH_SHIFT;
dev_dbg(hsotg->dev, "Detected values from hardware:\n");
dev_dbg(hsotg->dev, " op_mode=%d\n",
@@ -3275,6 +3497,43 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
}
+/* Returns the controller's GHWCFG2.OTG_MODE. */
+unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg)
+{
+ u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
+
+ return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+ GHWCFG2_OP_MODE_SHIFT;
+}
+
+/* Returns true if the controller is capable of DRD. */
+bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg)
+{
+ unsigned op_mode = dwc2_op_mode(hsotg);
+
+ return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) ||
+ (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) ||
+ (op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE);
+}
+
+/* Returns true if the controller is host-only. */
+bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg)
+{
+ unsigned op_mode = dwc2_op_mode(hsotg);
+
+ return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
+ (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
+}
+
+/* Returns true if the controller is device-only. */
+bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
+{
+ unsigned op_mode = dwc2_op_mode(hsotg);
+
+ return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
+ (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
+}
+
MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
MODULE_AUTHOR("Synopsys, Inc.");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index a66d3cb62b65..7fb6434f4639 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -246,6 +246,13 @@ enum dwc2_ep0_state {
* value for this if none is specified.
* 0 - Address DMA
* 1 - Descriptor DMA (default, if available)
+ * @dma_desc_fs_enable: When DMA mode is enabled, specifies whether to use
+ * address DMA mode or descriptor DMA mode for accessing
+ * the data FIFOs in Full Speed mode only. The driver
+ * will automatically detect the value for this if none is
+ * specified.
+ * 0 - Address DMA
+ * 1 - Descriptor DMA in FS (default, if available)
* @speed: Specifies the maximum speed of operation in host and
* device mode. The actual speed depends on the speed of
* the attached device and the value of phy_type.
@@ -375,6 +382,7 @@ struct dwc2_core_params {
int otg_ver;
int dma_enable;
int dma_desc_enable;
+ int dma_desc_fs_enable;
int speed;
int enable_dynamic_fifo;
int en_multiple_tx_fifo;
@@ -451,15 +459,18 @@ struct dwc2_core_params {
* 1 - 16 bits
* 2 - 8 or 16 bits
* @snpsid: Value from SNPSID register
+ * @dev_ep_dirs: Direction of device endpoints (GHWCFG1)
*/
struct dwc2_hw_params {
unsigned op_mode:3;
unsigned arch:2;
unsigned dma_desc_enable:1;
+ unsigned dma_desc_fs_enable:1;
unsigned enable_dynamic_fifo:1;
unsigned en_multiple_tx_fifo:1;
unsigned host_rx_fifo_size:16;
unsigned host_nperio_tx_fifo_size:16;
+ unsigned dev_nperio_tx_fifo_size:16;
unsigned host_perio_tx_fifo_size:16;
unsigned nperio_tx_q_depth:3;
unsigned host_perio_tx_q_depth:3;
@@ -476,6 +487,7 @@ struct dwc2_hw_params {
unsigned power_optimized:1;
unsigned utmi_phy_data_width:2;
u32 snpsid;
+ u32 dev_ep_dirs;
};
/* Size of control and EP0 buffers */
@@ -676,6 +688,9 @@ struct dwc2_hregs_backup {
* @otg_port: OTG port number
* @frame_list: Frame list
* @frame_list_dma: Frame list DMA address
+ * @frame_list_sz: Frame list size
+ * @desc_gen_cache: Kmem cache for generic descriptors
+ * @desc_hsisoc_cache: Kmem cache for hs isochronous descriptors
*
* These are for peripheral mode:
*
@@ -770,6 +785,7 @@ struct dwc2_hsotg {
u16 frame_number;
u16 periodic_qh_count;
bool bus_suspended;
+ bool new_connection;
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
#define FRAME_NUM_ARRAY_SIZE 1000
@@ -794,6 +810,9 @@ struct dwc2_hsotg {
u8 otg_port;
u32 *frame_list;
dma_addr_t frame_list_dma;
+ u32 frame_list_sz;
+ struct kmem_cache *desc_gen_cache;
+ struct kmem_cache *desc_hsisoc_cache;
#ifdef DEBUG
u32 frrem_samples;
@@ -864,10 +883,14 @@ enum dwc2_halt_status {
* The following functions support initialization of the core driver component
* and the DWC_otg controller
*/
+extern int dwc2_core_reset(struct dwc2_hsotg *hsotg);
+extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg);
extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
+void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
+
/*
* Host core Functions.
* The following functions support managing the DWC_otg controller in host
@@ -901,7 +924,7 @@ extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq);
+extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
@@ -942,6 +965,16 @@ extern void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
/*
+ * When DMA mode is enabled specifies whether to use
+ * address DMA or DMA Descritor mode with full speed devices
+ * for accessing the data FIFOs in host mode.
+ * 0 - address DMA
+ * 1 - FS DMA Descriptor(default, if available)
+ */
+extern void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg,
+ int val);
+
+/*
* Specifies the maximum speed of operation in host and device mode.
* The actual speed depends on the speed of the attached device and
* the value of phy_type. The actual speed depends on the speed of the
@@ -1110,6 +1143,31 @@ extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
/*
+ * The following functions check the controller's OTG operation mode
+ * capability (GHWCFG2.OTG_MODE).
+ *
+ * These functions can be used before the internal hsotg->hw_params
+ * are read in and cached so they always read directly from the
+ * GHWCFG2 register.
+ */
+unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg);
+bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg);
+bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg);
+bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg);
+
+/*
+ * Returns the mode of operation, host or device
+ */
+static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
+{
+ return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
+}
+static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
+{
+ return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
+}
+
+/*
* Dump core registers and SPRAM
*/
extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg);
@@ -1154,12 +1212,14 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
#else
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
{ return 0; }
-static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {}
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 27daa42788b1..d85c5c9f96c1 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -86,9 +86,6 @@ static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
hprt0 &= ~HPRT0_ENA;
dwc2_writel(hprt0, hsotg->regs + HPRT0);
}
-
- /* Clear interrupt */
- dwc2_writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS);
}
/**
@@ -98,11 +95,11 @@ static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
{
- dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
- dwc2_is_host_mode(hsotg) ? "Host" : "Device");
-
/* Clear interrupt */
dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
+
+ dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
+ dwc2_is_host_mode(hsotg) ? "Host" : "Device");
}
/**
@@ -239,7 +236,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
hsotg->op_state);
spin_unlock(&hsotg->lock);
- dwc2_hcd_disconnect(hsotg);
+ dwc2_hcd_disconnect(hsotg, false);
spin_lock(&hsotg->lock);
hsotg->op_state = OTG_STATE_A_PERIPHERAL;
} else {
@@ -276,9 +273,13 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
{
- u32 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+ u32 gintmsk;
+
+ /* Clear interrupt */
+ dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
/* Need to disable SOF interrupt immediately */
+ gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
@@ -295,9 +296,6 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
queue_work(hsotg->wq_otg, &hsotg->wf_otg);
spin_lock(&hsotg->lock);
}
-
- /* Clear interrupt */
- dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
}
/**
@@ -315,12 +313,12 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
{
int ret;
- dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
- hsotg->lx_state);
-
/* Clear interrupt */
dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
+ dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
+ hsotg->lx_state);
+
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->lx_state == DWC2_L2) {
ret = dwc2_exit_hibernation(hsotg, true);
@@ -347,6 +345,10 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
int ret;
+
+ /* Clear interrupt */
+ dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
+
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
@@ -368,10 +370,9 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
} else {
- if (hsotg->core_params->hibernation) {
- dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
+ if (hsotg->core_params->hibernation)
return;
- }
+
if (hsotg->lx_state != DWC2_L1) {
u32 pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
@@ -385,9 +386,6 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
hsotg->lx_state = DWC2_L0;
}
}
-
- /* Clear interrupt */
- dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
}
/*
@@ -396,14 +394,14 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
{
+ dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
+
dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device",
dwc2_op_state_str(hsotg));
if (hsotg->op_state == OTG_STATE_A_HOST)
- dwc2_hcd_disconnect(hsotg);
-
- dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
+ dwc2_hcd_disconnect(hsotg, false);
}
/*
@@ -419,6 +417,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
u32 dsts;
int ret;
+ /* Clear interrupt */
+ dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
+
dev_dbg(hsotg->dev, "USB SUSPEND\n");
if (dwc2_is_device_mode(hsotg)) {
@@ -437,7 +438,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
if (!dwc2_is_device_connected(hsotg)) {
dev_dbg(hsotg->dev,
"ignore suspend request before enumeration\n");
- goto clear_int;
+ return;
}
ret = dwc2_enter_hibernation(hsotg);
@@ -476,10 +477,6 @@ skip_power_saving:
hsotg->op_state = OTG_STATE_A_HOST;
}
}
-
-clear_int:
- /* Clear interrupt */
- dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
}
#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 0abf73c91beb..422ab7da4eb5 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -2095,7 +2095,7 @@ static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
*/
/* catch both EnumSpd_FS and EnumSpd_FS48 */
- switch (dsts & DSTS_ENUMSPD_MASK) {
+ switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) {
case DSTS_ENUMSPD_FS:
case DSTS_ENUMSPD_FS48:
hsotg->gadget.speed = USB_SPEED_FULL;
@@ -2244,54 +2244,6 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
GINTSTS_RXFLVL)
/**
- * dwc2_hsotg_corereset - issue softreset to the core
- * @hsotg: The device state
- *
- * Issue a soft reset to the core, and await the core finishing it.
- */
-static int dwc2_hsotg_corereset(struct dwc2_hsotg *hsotg)
-{
- int timeout;
- u32 grstctl;
-
- dev_dbg(hsotg->dev, "resetting core\n");
-
- /* issue soft reset */
- dwc2_writel(GRSTCTL_CSFTRST, hsotg->regs + GRSTCTL);
-
- timeout = 10000;
- do {
- grstctl = dwc2_readl(hsotg->regs + GRSTCTL);
- } while ((grstctl & GRSTCTL_CSFTRST) && timeout-- > 0);
-
- if (grstctl & GRSTCTL_CSFTRST) {
- dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
- return -EINVAL;
- }
-
- timeout = 10000;
-
- while (1) {
- u32 grstctl = dwc2_readl(hsotg->regs + GRSTCTL);
-
- if (timeout-- < 0) {
- dev_info(hsotg->dev,
- "%s: reset failed, GRSTCTL=%08x\n",
- __func__, grstctl);
- return -ETIMEDOUT;
- }
-
- if (!(grstctl & GRSTCTL_AHBIDLE))
- continue;
-
- break; /* reset done */
- }
-
- dev_dbg(hsotg->dev, "reset successful\n");
- return 0;
-}
-
-/**
* dwc2_hsotg_core_init - issue softreset to the core
* @hsotg: The device state
*
@@ -2307,7 +2259,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
if (!is_usb_reset)
- if (dwc2_hsotg_corereset(hsotg))
+ if (dwc2_core_reset(hsotg))
return;
/*
@@ -2585,7 +2537,7 @@ irq_retry:
if (gintsts & GINTSTS_GOUTNAKEFF) {
dev_info(hsotg->dev, "GOUTNakEff triggered\n");
- dwc2_writel(DCTL_CGOUTNAK, hsotg->regs + DCTL);
+ __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK);
dwc2_hsotg_dump(hsotg);
}
@@ -2593,7 +2545,7 @@ irq_retry:
if (gintsts & GINTSTS_GINNAKEFF) {
dev_info(hsotg->dev, "GINNakEff triggered\n");
- dwc2_writel(DCTL_CGNPINNAK, hsotg->regs + DCTL);
+ __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK);
dwc2_hsotg_dump(hsotg);
}
@@ -2911,15 +2863,15 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
"%s: timeout DIEPINT.NAKEFF\n", __func__);
} else {
/* Clear any pending nak effect interrupt */
- dwc2_writel(GINTSTS_GINNAKEFF, hsotg->regs + GINTSTS);
+ dwc2_writel(GINTSTS_GOUTNAKEFF, hsotg->regs + GINTSTS);
- __orr32(hsotg->regs + DCTL, DCTL_SGNPINNAK);
+ __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
/* Wait for global nak to take effect */
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
- GINTSTS_GINNAKEFF, 100))
+ GINTSTS_GOUTNAKEFF, 100))
dev_warn(hsotg->dev,
- "%s: timeout GINTSTS.GINNAKEFF\n", __func__);
+ "%s: timeout GINTSTS.GOUTNAKEFF\n", __func__);
}
/* Disable ep */
@@ -2944,7 +2896,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
/* TODO: Flush shared tx fifo */
} else {
/* Remove global NAKs */
- __bic32(hsotg->regs + DCTL, DCTL_SGNPINNAK);
+ __bic32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
}
}
@@ -3403,8 +3355,8 @@ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
/* check hardware configuration */
- cfg = dwc2_readl(hsotg->regs + GHWCFG2);
- hsotg->num_of_eps = (cfg >> GHWCFG2_NUM_DEV_EP_SHIFT) & 0xF;
+ hsotg->num_of_eps = hsotg->hw_params.num_dev_ep;
+
/* Add ep0 */
hsotg->num_of_eps++;
@@ -3415,7 +3367,7 @@ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
/* Same dwc2_hsotg_ep is used in both directions for ep0 */
hsotg->eps_out[0] = hsotg->eps_in[0];
- cfg = dwc2_readl(hsotg->regs + GHWCFG1);
+ cfg = hsotg->hw_params.dev_ep_dirs;
for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) {
ep_type = cfg & 3;
/* Direction in or both */
@@ -3434,11 +3386,8 @@ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
}
}
- cfg = dwc2_readl(hsotg->regs + GHWCFG3);
- hsotg->fifo_mem = (cfg >> GHWCFG3_DFIFO_DEPTH_SHIFT);
-
- cfg = dwc2_readl(hsotg->regs + GHWCFG4);
- hsotg->dedicated_fifos = (cfg >> GHWCFG4_DED_FIFO_SHIFT) & 1;
+ hsotg->fifo_mem = hsotg->hw_params.total_fifo_size;
+ hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo;
dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
hsotg->num_of_eps,
@@ -3563,6 +3512,17 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo));
/* Device tree specific probe */
dwc2_hsotg_of_probe(hsotg);
+
+ /* Check against largest possible value. */
+ if (hsotg->g_np_g_tx_fifo_sz >
+ hsotg->hw_params.dev_nperio_tx_fifo_size) {
+ dev_warn(dev, "Specified GNPTXFDEP=%d > %d\n",
+ hsotg->g_np_g_tx_fifo_sz,
+ hsotg->hw_params.dev_nperio_tx_fifo_size);
+ hsotg->g_np_g_tx_fifo_sz =
+ hsotg->hw_params.dev_nperio_tx_fifo_size;
+ }
+
/* Dump fifo information */
dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
hsotg->g_np_g_tx_fifo_sz);
@@ -3579,31 +3539,12 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
- /*
- * Force Device mode before initialization.
- * This allows correctly configuring fifo for device mode.
- */
- __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEHOSTMODE);
- __orr32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
-
- /*
- * According to Synopsys databook, this sleep is needed for the force
- * device mode to take effect.
- */
- msleep(25);
-
- dwc2_hsotg_corereset(hsotg);
ret = dwc2_hsotg_hw_cfg(hsotg);
if (ret) {
dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret);
return ret;
}
- dwc2_hsotg_init(hsotg);
-
- /* Switch back to default configuration */
- __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
-
hsotg->ctrl_buff = devm_kzalloc(hsotg->dev,
DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
if (!hsotg->ctrl_buff) {
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 571c21727ff9..8847c72e55f6 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -268,15 +268,33 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
}
/**
+ * dwc2_hcd_connect() - Handles connect of the HCD
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_connect(struct dwc2_hsotg *hsotg)
+{
+ if (hsotg->lx_state != DWC2_L0)
+ usb_hcd_resume_root_hub(hsotg->priv);
+
+ hsotg->flags.b.port_connect_status_change = 1;
+ hsotg->flags.b.port_connect_status = 1;
+}
+
+/**
* dwc2_hcd_disconnect() - Handles disconnect of the HCD
*
* @hsotg: Pointer to struct dwc2_hsotg
+ * @force: If true, we won't try to reconnect even if we see device connected.
*
* Must be called with interrupt disabled and spinlock held
*/
-void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
+void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force)
{
u32 intr;
+ u32 hprt0;
/* Set status flags for the hub driver */
hsotg->flags.b.port_connect_status_change = 1;
@@ -315,6 +333,24 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
dwc2_hcd_cleanup_channels(hsotg);
dwc2_host_disconnect(hsotg);
+
+ /*
+ * Add an extra check here to see if we're actually connected but
+ * we don't have a detection interrupt pending. This can happen if:
+ * 1. hardware sees connect
+ * 2. hardware sees disconnect
+ * 3. hardware sees connect
+ * 4. dwc2_port_intr() - clears connect interrupt
+ * 5. dwc2_handle_common_intr() - calls here
+ *
+ * Without the extra check here we will end calling disconnect
+ * and won't get any future interrupts to handle the connect.
+ */
+ if (!force) {
+ hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+ if (!(hprt0 & HPRT0_CONNDET) && (hprt0 & HPRT0_CONNSTS))
+ dwc2_hcd_connect(hsotg);
+ }
}
/**
@@ -881,8 +917,10 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
*/
chan->multi_count = dwc2_hb_mult(qh->maxp);
- if (hsotg->core_params->dma_desc_enable > 0)
+ if (hsotg->core_params->dma_desc_enable > 0) {
chan->desc_list_addr = qh->desc_list_dma;
+ chan->desc_list_sz = qh->desc_list_sz;
+ }
dwc2_hc_init(hsotg, chan);
chan->qh = qh;
@@ -1382,7 +1420,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
dev_err(hsotg->dev,
"Connection id status change timed out\n");
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
- dwc2_core_init(hsotg, false, -1);
+ dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false);
@@ -1405,7 +1443,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
hsotg->op_state = OTG_STATE_A_HOST;
/* Initialize the Core for Host mode */
- dwc2_core_init(hsotg, false, -1);
+ dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
dwc2_hcd_start(hsotg);
}
@@ -1734,6 +1772,28 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
port_status |= USB_PORT_STAT_TEST;
/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+ if (hsotg->core_params->dma_desc_fs_enable) {
+ /*
+ * Enable descriptor DMA only if a full speed
+ * device is connected.
+ */
+ if (hsotg->new_connection &&
+ ((port_status &
+ (USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_HIGH_SPEED |
+ USB_PORT_STAT_LOW_SPEED)) ==
+ USB_PORT_STAT_CONNECTION)) {
+ u32 hcfg;
+
+ dev_info(hsotg->dev, "Enabling descriptor DMA mode\n");
+ hsotg->core_params->dma_desc_enable = 1;
+ hcfg = dwc2_readl(hsotg->regs + HCFG);
+ hcfg |= HCFG_DESCDMA;
+ dwc2_writel(hcfg, hsotg->regs + HCFG);
+ hsotg->new_connection = false;
+ }
+ }
+
dev_vdbg(hsotg->dev, "port_status=%08x\n", port_status);
*(__le32 *)buf = cpu_to_le32(port_status);
break;
@@ -2298,13 +2358,19 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
{
struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
reset_work.work);
+ unsigned long flags;
u32 hprt0;
dev_dbg(hsotg->dev, "USB RESET function called\n");
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~HPRT0_RST;
dwc2_writel(hprt0, hsotg->regs + HPRT0);
hsotg->flags.b.port_reset_change = 1;
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
}
/*
@@ -2366,7 +2432,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
spin_lock_irqsave(&hsotg->lock, flags);
/* Ensure hcd is disconnected */
- dwc2_hcd_disconnect(hsotg);
+ dwc2_hcd_disconnect(hsotg, true);
dwc2_hcd_stop(hsotg);
hsotg->lx_state = DWC2_L3;
hcd->state = HC_STATE_HALT;
@@ -3054,7 +3120,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
dwc2_disable_global_interrupts(hsotg);
/* Initialize the DWC_otg core, and select the Phy type */
- retval = dwc2_core_init(hsotg, true, irq);
+ retval = dwc2_core_init(hsotg, true);
if (retval)
goto error2;
@@ -3122,6 +3188,47 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
if (!hsotg->status_buf)
goto error3;
+ /*
+ * Create kmem caches to handle descriptor buffers in descriptor
+ * DMA mode.
+ * Alignment must be set to 512 bytes.
+ */
+ if (hsotg->core_params->dma_desc_enable ||
+ hsotg->core_params->dma_desc_fs_enable) {
+ hsotg->desc_gen_cache = kmem_cache_create("dwc2-gen-desc",
+ sizeof(struct dwc2_hcd_dma_desc) *
+ MAX_DMA_DESC_NUM_GENERIC, 512, SLAB_CACHE_DMA,
+ NULL);
+ if (!hsotg->desc_gen_cache) {
+ dev_err(hsotg->dev,
+ "unable to create dwc2 generic desc cache\n");
+
+ /*
+ * Disable descriptor dma mode since it will not be
+ * usable.
+ */
+ hsotg->core_params->dma_desc_enable = 0;
+ hsotg->core_params->dma_desc_fs_enable = 0;
+ }
+
+ hsotg->desc_hsisoc_cache = kmem_cache_create("dwc2-hsisoc-desc",
+ sizeof(struct dwc2_hcd_dma_desc) *
+ MAX_DMA_DESC_NUM_HS_ISOC, 512, 0, NULL);
+ if (!hsotg->desc_hsisoc_cache) {
+ dev_err(hsotg->dev,
+ "unable to create dwc2 hs isoc desc cache\n");
+
+ kmem_cache_destroy(hsotg->desc_gen_cache);
+
+ /*
+ * Disable descriptor dma mode since it will not be
+ * usable.
+ */
+ hsotg->core_params->dma_desc_enable = 0;
+ hsotg->core_params->dma_desc_fs_enable = 0;
+ }
+ }
+
hsotg->otg_port = 1;
hsotg->frame_list = NULL;
hsotg->frame_list_dma = 0;
@@ -3145,7 +3252,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
*/
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval < 0)
- goto error3;
+ goto error4;
device_wakeup_enable(hcd->self.controller);
@@ -3155,6 +3262,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
return 0;
+error4:
+ kmem_cache_destroy(hsotg->desc_gen_cache);
+ kmem_cache_destroy(hsotg->desc_hsisoc_cache);
error3:
dwc2_hcd_release(hsotg);
error2:
@@ -3195,6 +3305,10 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
usb_remove_hcd(hcd);
hsotg->priv = NULL;
+
+ kmem_cache_destroy(hsotg->desc_gen_cache);
+ kmem_cache_destroy(hsotg->desc_hsisoc_cache);
+
dwc2_hcd_release(hsotg);
usb_put_hcd(hcd);
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index f105bada2fd1..8f0a29cefdf7 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -107,6 +107,7 @@ struct dwc2_qh;
* @qh: QH for the transfer being processed by this channel
* @hc_list_entry: For linking to list of host channels
* @desc_list_addr: Current QH's descriptor list DMA address
+ * @desc_list_sz: Current QH's descriptor list size
*
* This structure represents the state of a single host channel when acting in
* host mode. It contains the data items needed to transfer packets to an
@@ -159,6 +160,7 @@ struct dwc2_host_chan {
struct dwc2_qh *qh;
struct list_head hc_list_entry;
dma_addr_t desc_list_addr;
+ u32 desc_list_sz;
};
struct dwc2_hcd_pipe_info {
@@ -251,6 +253,7 @@ enum dwc2_transaction_type {
* schedule
* @desc_list: List of transfer descriptors
* @desc_list_dma: Physical address of desc_list
+ * @desc_list_sz: Size of descriptors list
* @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
* descriptor and indicates original XferSize value for the
* descriptor
@@ -284,6 +287,7 @@ struct dwc2_qh {
struct list_head qh_list_entry;
struct dwc2_hcd_dma_desc *desc_list;
dma_addr_t desc_list_dma;
+ u32 desc_list_sz;
u32 *n_bytes;
unsigned tt_buffer_dirty:1;
};
@@ -340,6 +344,8 @@ struct dwc2_qtd {
u8 isoc_split_pos;
u16 isoc_frame_index;
u16 isoc_split_offset;
+ u16 isoc_td_last;
+ u16 isoc_td_first;
u32 ssplit_out_xfer_count;
u8 error_count;
u8 n_desc;
@@ -378,18 +384,6 @@ static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
}
/*
- * Returns the mode of operation, host or device
- */
-static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
-{
- return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
-}
-static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
-{
- return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
-}
-
-/*
* Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
* are read as 1, they won't clear when written back.
*/
@@ -535,6 +529,19 @@ static inline bool dbg_perio(void) { return false; }
#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
/*
+ * Returns true if frame1 index is greater than frame2 index. The comparison
+ * is done modulo FRLISTEN_64_SIZE. This accounts for the rollover of the
+ * frame number when the max index frame number is reached.
+ */
+static inline bool dwc2_frame_idx_num_gt(u16 fr_idx1, u16 fr_idx2)
+{
+ u16 diff = fr_idx1 - fr_idx2;
+ u16 sign = diff & (FRLISTEN_64_SIZE >> 1);
+
+ return diff && !sign;
+}
+
+/*
* Returns true if frame1 is less than or equal to frame2. The comparison is
* done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
* frame number when the max frame number is reached.
diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c
index 78993aba9335..36606fc33c0d 100644
--- a/drivers/usb/dwc2/hcd_ddma.c
+++ b/drivers/usb/dwc2/hcd_ddma.c
@@ -87,22 +87,31 @@ static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
gfp_t flags)
{
- qh->desc_list = dma_alloc_coherent(hsotg->dev,
- sizeof(struct dwc2_hcd_dma_desc) *
- dwc2_max_desc_num(qh), &qh->desc_list_dma,
- flags);
+ struct kmem_cache *desc_cache;
+ if (qh->ep_type == USB_ENDPOINT_XFER_ISOC
+ && qh->dev_speed == USB_SPEED_HIGH)
+ desc_cache = hsotg->desc_hsisoc_cache;
+ else
+ desc_cache = hsotg->desc_gen_cache;
+
+ qh->desc_list_sz = sizeof(struct dwc2_hcd_dma_desc) *
+ dwc2_max_desc_num(qh);
+
+ qh->desc_list = kmem_cache_zalloc(desc_cache, flags | GFP_DMA);
if (!qh->desc_list)
return -ENOMEM;
- memset(qh->desc_list, 0,
- sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh));
+ qh->desc_list_dma = dma_map_single(hsotg->dev, qh->desc_list,
+ qh->desc_list_sz,
+ DMA_TO_DEVICE);
qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags);
if (!qh->n_bytes) {
- dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
- * dwc2_max_desc_num(qh), qh->desc_list,
- qh->desc_list_dma);
+ dma_unmap_single(hsotg->dev, qh->desc_list_dma,
+ qh->desc_list_sz,
+ DMA_FROM_DEVICE);
+ kfree(qh->desc_list);
qh->desc_list = NULL;
return -ENOMEM;
}
@@ -112,10 +121,18 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
+ struct kmem_cache *desc_cache;
+
+ if (qh->ep_type == USB_ENDPOINT_XFER_ISOC
+ && qh->dev_speed == USB_SPEED_HIGH)
+ desc_cache = hsotg->desc_hsisoc_cache;
+ else
+ desc_cache = hsotg->desc_gen_cache;
+
if (qh->desc_list) {
- dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
- * dwc2_max_desc_num(qh), qh->desc_list,
- qh->desc_list_dma);
+ dma_unmap_single(hsotg->dev, qh->desc_list_dma,
+ qh->desc_list_sz, DMA_FROM_DEVICE);
+ kmem_cache_free(desc_cache, qh->desc_list);
qh->desc_list = NULL;
}
@@ -128,21 +145,20 @@ static int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags)
if (hsotg->frame_list)
return 0;
- hsotg->frame_list = dma_alloc_coherent(hsotg->dev,
- 4 * FRLISTEN_64_SIZE,
- &hsotg->frame_list_dma,
- mem_flags);
+ hsotg->frame_list_sz = 4 * FRLISTEN_64_SIZE;
+ hsotg->frame_list = kzalloc(hsotg->frame_list_sz, GFP_ATOMIC | GFP_DMA);
if (!hsotg->frame_list)
return -ENOMEM;
- memset(hsotg->frame_list, 0, 4 * FRLISTEN_64_SIZE);
+ hsotg->frame_list_dma = dma_map_single(hsotg->dev, hsotg->frame_list,
+ hsotg->frame_list_sz,
+ DMA_TO_DEVICE);
+
return 0;
}
static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg)
{
- u32 *frame_list;
- dma_addr_t frame_list_dma;
unsigned long flags;
spin_lock_irqsave(&hsotg->lock, flags);
@@ -152,14 +168,14 @@ static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg)
return;
}
- frame_list = hsotg->frame_list;
- frame_list_dma = hsotg->frame_list_dma;
+ dma_unmap_single(hsotg->dev, hsotg->frame_list_dma,
+ hsotg->frame_list_sz, DMA_FROM_DEVICE);
+
+ kfree(hsotg->frame_list);
hsotg->frame_list = NULL;
spin_unlock_irqrestore(&hsotg->lock, flags);
- dma_free_coherent(hsotg->dev, 4 * FRLISTEN_64_SIZE, frame_list,
- frame_list_dma);
}
static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
@@ -249,6 +265,15 @@ static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
j = (j + inc) & (FRLISTEN_64_SIZE - 1);
} while (j != i);
+ /*
+ * Sync frame list since controller will access it if periodic
+ * channel is currently enabled.
+ */
+ dma_sync_single_for_device(hsotg->dev,
+ hsotg->frame_list_dma,
+ hsotg->frame_list_sz,
+ DMA_TO_DEVICE);
+
if (!enable)
return;
@@ -278,6 +303,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
hsotg->non_periodic_channels--;
} else {
dwc2_update_frame_list(hsotg, qh, 0);
+ hsotg->available_host_channels++;
}
/*
@@ -360,6 +386,8 @@ err0:
*/
void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
+ unsigned long flags;
+
dwc2_desc_list_free(hsotg, qh);
/*
@@ -369,8 +397,10 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
* when it comes here from endpoint disable routine
* channel remains assigned.
*/
+ spin_lock_irqsave(&hsotg->lock, flags);
if (qh->channel)
dwc2_release_channel_ddma(hsotg, qh);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
qh->ep_type == USB_ENDPOINT_XFER_INT) &&
@@ -524,14 +554,23 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT &
HOST_DMA_ISOC_NBYTES_MASK;
+ /* Set active bit */
+ dma_desc->status |= HOST_DMA_A;
+
+ qh->ntd++;
+ qtd->isoc_frame_index_last++;
+
#ifdef ISOC_URB_GIVEBACK_ASAP
/* Set IOC for each descriptor corresponding to last frame of URB */
if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
dma_desc->status |= HOST_DMA_IOC;
#endif
- qh->ntd++;
- qtd->isoc_frame_index_last++;
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma +
+ (idx * sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
}
static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
@@ -539,11 +578,32 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
{
struct dwc2_qtd *qtd;
u32 max_xfer_size;
- u16 idx, inc, n_desc, ntd_max = 0;
+ u16 idx, inc, n_desc = 0, ntd_max = 0;
+ u16 cur_idx;
+ u16 next_idx;
idx = qh->td_last;
inc = qh->interval;
- n_desc = 0;
+ hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
+ cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
+ next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
+
+ /*
+ * Ensure current frame number didn't overstep last scheduled
+ * descriptor. If it happens, the only way to recover is to move
+ * qh->td_last to current frame number + 1.
+ * So that next isoc descriptor will be scheduled on frame number + 1
+ * and not on a past frame.
+ */
+ if (dwc2_frame_idx_num_gt(cur_idx, next_idx) || (cur_idx == next_idx)) {
+ if (inc < 32) {
+ dev_vdbg(hsotg->dev,
+ "current frame number overstep last descriptor\n");
+ qh->td_last = dwc2_desclist_idx_inc(cur_idx, inc,
+ qh->dev_speed);
+ idx = qh->td_last;
+ }
+ }
if (qh->interval) {
ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
@@ -556,15 +616,20 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS;
list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
+ if (qtd->in_process &&
+ qtd->isoc_frame_index_last ==
+ qtd->urb->packet_count)
+ continue;
+
+ qtd->isoc_td_first = idx;
while (qh->ntd < ntd_max && qtd->isoc_frame_index_last <
qtd->urb->packet_count) {
- if (n_desc > 1)
- qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh,
max_xfer_size, idx);
idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed);
n_desc++;
}
+ qtd->isoc_td_last = idx;
qtd->in_process = 1;
}
@@ -575,6 +640,11 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
if (qh->ntd == ntd_max) {
idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
qh->desc_list[idx].status |= HOST_DMA_IOC;
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma + (idx *
+ sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
}
#else
/*
@@ -604,13 +674,12 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
qh->desc_list[idx].status |= HOST_DMA_IOC;
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma +
+ (idx * sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
#endif
-
- if (n_desc) {
- qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
- if (n_desc > 1)
- qh->desc_list[0].status |= HOST_DMA_A;
- }
}
static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
@@ -647,6 +716,12 @@ static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
dma_desc->buf = (u32)chan->xfer_dma;
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma +
+ (n_desc * sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
+
/*
* Last (or only) descriptor of IN transfer with actual size less
* than MaxPacket
@@ -697,6 +772,12 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
"set A bit in desc %d (%p)\n",
n_desc - 1,
&qh->desc_list[n_desc - 1]);
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma +
+ ((n_desc - 1) *
+ sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
}
dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
dev_vdbg(hsotg->dev,
@@ -722,10 +803,19 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A;
dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n",
n_desc - 1, &qh->desc_list[n_desc - 1]);
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma + (n_desc - 1) *
+ sizeof(struct dwc2_hcd_dma_desc),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
if (n_desc > 1) {
qh->desc_list[0].status |= HOST_DMA_A;
dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n",
&qh->desc_list[0]);
+ dma_sync_single_for_device(hsotg->dev,
+ qh->desc_list_dma,
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_TO_DEVICE);
}
chan->ntd = n_desc;
}
@@ -800,7 +890,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd,
struct dwc2_qh *qh, u16 idx)
{
- struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
+ struct dwc2_hcd_dma_desc *dma_desc;
struct dwc2_hcd_iso_packet_desc *frame_desc;
u16 remain = 0;
int rc = 0;
@@ -808,6 +898,13 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
if (!qtd->urb)
return -EINVAL;
+ dma_sync_single_for_cpu(hsotg->dev, qh->desc_list_dma + (idx *
+ sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_FROM_DEVICE);
+
+ dma_desc = &qh->desc_list[idx];
+
frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
if (chan->ep_is_in)
@@ -911,17 +1008,51 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
if (!qtd->in_process)
break;
+
+ /*
+ * Ensure idx corresponds to descriptor where first urb of this
+ * qtd was added. In fact, during isoc desc init, dwc2 may skip
+ * an index if current frame number is already over this index.
+ */
+ if (idx != qtd->isoc_td_first) {
+ dev_vdbg(hsotg->dev,
+ "try to complete %d instead of %d\n",
+ idx, qtd->isoc_td_first);
+ idx = qtd->isoc_td_first;
+ }
+
do {
+ struct dwc2_qtd *qtd_next;
+ u16 cur_idx;
+
rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
idx);
if (rc < 0)
return;
idx = dwc2_desclist_idx_inc(idx, qh->interval,
chan->speed);
- if (rc == DWC2_CMPL_STOP)
- goto stop_scan;
+ if (!rc)
+ continue;
+
if (rc == DWC2_CMPL_DONE)
break;
+
+ /* rc == DWC2_CMPL_STOP */
+
+ if (qh->interval >= 32)
+ goto stop_scan;
+
+ qh->td_first = idx;
+ cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
+ qtd_next = list_first_entry(&qh->qtd_list,
+ struct dwc2_qtd,
+ qtd_list_entry);
+ if (dwc2_frame_idx_num_gt(cur_idx,
+ qtd_next->isoc_td_last))
+ break;
+
+ goto stop_scan;
+
} while (idx != qh->td_first);
}
@@ -1029,6 +1160,12 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
if (!urb)
return -EINVAL;
+ dma_sync_single_for_cpu(hsotg->dev,
+ qh->desc_list_dma + (desc_num *
+ sizeof(struct dwc2_hcd_dma_desc)),
+ sizeof(struct dwc2_hcd_dma_desc),
+ DMA_FROM_DEVICE);
+
dma_desc = &qh->desc_list[desc_num];
n_bytes = qh->n_bytes[desc_num];
dev_vdbg(hsotg->dev,
@@ -1037,7 +1174,10 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
halt_status, n_bytes,
xfer_done);
- if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
+ if (*xfer_done && urb->status != -EINPROGRESS)
+ failed = 1;
+
+ if (failed) {
dwc2_host_complete(hsotg, qtd, urb->status);
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
@@ -1165,6 +1305,21 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
/* Release the channel if halted or session completed */
if (halt_status != DWC2_HC_XFER_COMPLETE ||
list_empty(&qh->qtd_list)) {
+ struct dwc2_qtd *qtd, *qtd_tmp;
+
+ /*
+ * Kill all remainings QTDs since channel has been
+ * halted.
+ */
+ list_for_each_entry_safe(qtd, qtd_tmp,
+ &qh->qtd_list,
+ qtd_list_entry) {
+ dwc2_host_complete(hsotg, qtd,
+ -ECONNRESET);
+ dwc2_hcd_qtd_unlink_and_free(hsotg,
+ qtd, qh);
+ }
+
/* Halt the channel if session completed */
if (halt_status == DWC2_HC_XFER_COMPLETE)
dwc2_hc_halt(hsotg, chan, halt_status);
@@ -1174,7 +1329,12 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
/* Keep in assigned schedule to continue transfer */
list_move(&qh->qh_list_entry,
&hsotg->periodic_sched_assigned);
- continue_isoc_xfer = 1;
+ /*
+ * If channel has been halted during giveback of urb
+ * then prevent any new scheduling.
+ */
+ if (!chan->halt_status)
+ continue_isoc_xfer = 1;
}
/*
* Todo: Consider the case when period exceeds FrameList size.
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index bda0b21b850f..f8253803a050 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -122,6 +122,9 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
struct dwc2_qh *qh;
enum dwc2_transaction_type tr_type;
+ /* Clear interrupt */
+ dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
+
#ifdef DEBUG_SOF
dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
#endif
@@ -146,9 +149,6 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
tr_type = dwc2_hcd_select_transactions(hsotg);
if (tr_type != DWC2_TRANSACTION_NONE)
dwc2_hcd_queue_transactions(hsotg, tr_type);
-
- /* Clear interrupt */
- dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
}
/*
@@ -312,6 +312,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
if (do_reset) {
*hprt0_modify |= HPRT0_RST;
+ dwc2_writel(*hprt0_modify, hsotg->regs + HPRT0);
queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
msecs_to_jiffies(60));
} else {
@@ -347,15 +348,12 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
* Set flag and clear if detected
*/
if (hprt0 & HPRT0_CONNDET) {
+ dwc2_writel(hprt0_modify | HPRT0_CONNDET, hsotg->regs + HPRT0);
+
dev_vdbg(hsotg->dev,
"--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
hprt0);
- if (hsotg->lx_state != DWC2_L0)
- usb_hcd_resume_root_hub(hsotg->priv);
-
- hsotg->flags.b.port_connect_status_change = 1;
- hsotg->flags.b.port_connect_status = 1;
- hprt0_modify |= HPRT0_CONNDET;
+ dwc2_hcd_connect(hsotg);
/*
* The Hub driver asserts a reset when it sees port connect
@@ -368,27 +366,36 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
* Clear if detected - Set internal flag if disabled
*/
if (hprt0 & HPRT0_ENACHG) {
+ dwc2_writel(hprt0_modify | HPRT0_ENACHG, hsotg->regs + HPRT0);
dev_vdbg(hsotg->dev,
" --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
hprt0, !!(hprt0 & HPRT0_ENA));
- hprt0_modify |= HPRT0_ENACHG;
- if (hprt0 & HPRT0_ENA)
+ if (hprt0 & HPRT0_ENA) {
+ hsotg->new_connection = true;
dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify);
- else
+ } else {
hsotg->flags.b.port_enable_change = 1;
+ if (hsotg->core_params->dma_desc_fs_enable) {
+ u32 hcfg;
+
+ hsotg->core_params->dma_desc_enable = 0;
+ hsotg->new_connection = false;
+ hcfg = dwc2_readl(hsotg->regs + HCFG);
+ hcfg &= ~HCFG_DESCDMA;
+ dwc2_writel(hcfg, hsotg->regs + HCFG);
+ }
+ }
}
/* Overcurrent Change Interrupt */
if (hprt0 & HPRT0_OVRCURRCHG) {
+ dwc2_writel(hprt0_modify | HPRT0_OVRCURRCHG,
+ hsotg->regs + HPRT0);
dev_vdbg(hsotg->dev,
" --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
hprt0);
hsotg->flags.b.port_over_current_change = 1;
- hprt0_modify |= HPRT0_OVRCURRCHG;
}
-
- /* Clear Port Interrupts */
- dwc2_writel(hprt0_modify, hsotg->regs + HPRT0);
}
/*
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 7d8d06cfe3c1..27d402f680a3 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -232,7 +232,7 @@ struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
*/
void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
- if (hsotg->core_params->dma_desc_enable > 0) {
+ if (qh->desc_list) {
dwc2_hcd_qh_free_ddma(hsotg, qh);
} else {
/* kfree(NULL) is safe */
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 553f24606c43..281b57b36ab4 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -769,10 +769,6 @@
#define TSIZ_XFERSIZE_SHIFT 0
#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch))
-#define HCDMA_DMA_ADDR_MASK (0x1fffff << 11)
-#define HCDMA_DMA_ADDR_SHIFT 11
-#define HCDMA_CTD_MASK (0xff << 3)
-#define HCDMA_CTD_SHIFT 3
#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch))
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 39c1cbf0e75d..510f787434b3 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -54,11 +54,44 @@
static const char dwc2_driver_name[] = "dwc2";
+static const struct dwc2_core_params params_hi6220 = {
+ .otg_cap = 2, /* No HNP/SRP capable */
+ .otg_ver = 0, /* 1.3 */
+ .dma_enable = 1,
+ .dma_desc_enable = 0,
+ .dma_desc_fs_enable = 0,
+ .speed = 0, /* High Speed */
+ .enable_dynamic_fifo = 1,
+ .en_multiple_tx_fifo = 1,
+ .host_rx_fifo_size = 512,
+ .host_nperio_tx_fifo_size = 512,
+ .host_perio_tx_fifo_size = 512,
+ .max_transfer_size = 65535,
+ .max_packet_count = 511,
+ .host_channels = 16,
+ .phy_type = 1, /* UTMI */
+ .phy_utmi_width = 8,
+ .phy_ulpi_ddr = 0, /* Single */
+ .phy_ulpi_ext_vbus = 0,
+ .i2c_enable = 0,
+ .ulpi_fs_ls = 0,
+ .host_support_fs_ls_low_power = 0,
+ .host_ls_low_power_phy_clk = 0, /* 48 MHz */
+ .ts_dline = 0,
+ .reload_ctl = 0,
+ .ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
+ GAHBCFG_HBSTLEN_SHIFT,
+ .uframe_sched = 0,
+ .external_id_pin_ctl = -1,
+ .hibernation = -1,
+};
+
static const struct dwc2_core_params params_bcm2835 = {
.otg_cap = 0, /* HNP/SRP capable */
.otg_ver = 0, /* 1.3 */
.dma_enable = 1,
.dma_desc_enable = 0,
+ .dma_desc_fs_enable = 0,
.speed = 0, /* High Speed */
.enable_dynamic_fifo = 1,
.en_multiple_tx_fifo = 1,
@@ -89,6 +122,7 @@ static const struct dwc2_core_params params_rk3066 = {
.otg_ver = -1,
.dma_enable = -1,
.dma_desc_enable = 0,
+ .dma_desc_fs_enable = 0,
.speed = -1,
.enable_dynamic_fifo = 1,
.en_multiple_tx_fifo = -1,
@@ -115,6 +149,71 @@ static const struct dwc2_core_params params_rk3066 = {
.hibernation = -1,
};
+/*
+ * Check the dr_mode against the module configuration and hardware
+ * capabilities.
+ *
+ * The hardware, module, and dr_mode, can each be set to host, device,
+ * or otg. Check that all these values are compatible and adjust the
+ * value of dr_mode if possible.
+ *
+ * actual
+ * HW MOD dr_mode dr_mode
+ * ------------------------------
+ * HST HST any : HST
+ * HST DEV any : ---
+ * HST OTG any : HST
+ *
+ * DEV HST any : ---
+ * DEV DEV any : DEV
+ * DEV OTG any : DEV
+ *
+ * OTG HST any : HST
+ * OTG DEV any : DEV
+ * OTG OTG any : dr_mode
+ */
+static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg)
+{
+ enum usb_dr_mode mode;
+
+ hsotg->dr_mode = usb_get_dr_mode(hsotg->dev);
+ if (hsotg->dr_mode == USB_DR_MODE_UNKNOWN)
+ hsotg->dr_mode = USB_DR_MODE_OTG;
+
+ mode = hsotg->dr_mode;
+
+ if (dwc2_hw_is_device(hsotg)) {
+ if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) {
+ dev_err(hsotg->dev,
+ "Controller does not support host mode.\n");
+ return -EINVAL;
+ }
+ mode = USB_DR_MODE_PERIPHERAL;
+ } else if (dwc2_hw_is_host(hsotg)) {
+ if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) {
+ dev_err(hsotg->dev,
+ "Controller does not support device mode.\n");
+ return -EINVAL;
+ }
+ mode = USB_DR_MODE_HOST;
+ } else {
+ if (IS_ENABLED(CONFIG_USB_DWC2_HOST))
+ mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL))
+ mode = USB_DR_MODE_PERIPHERAL;
+ }
+
+ if (mode != hsotg->dr_mode) {
+ dev_warn(hsotg->dev,
+ "Configuration mismatch. dr_mode forced to %s\n",
+ mode == USB_DR_MODE_HOST ? "host" : "device");
+
+ hsotg->dr_mode = mode;
+ }
+
+ return 0;
+}
+
static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
{
struct platform_device *pdev = to_platform_device(hsotg->dev);
@@ -306,8 +405,28 @@ static int dwc2_driver_remove(struct platform_device *dev)
return 0;
}
+/**
+ * dwc2_driver_shutdown() - Called on device shutdown
+ *
+ * @dev: Platform device
+ *
+ * In specific conditions (involving usb hubs) dwc2 devices can create a
+ * lot of interrupts, even to the point of overwhelming devices running
+ * at low frequencies. Some devices need to do special clock handling
+ * at shutdown-time which may bring the system clock below the threshold
+ * of being able to handle the dwc2 interrupts. Disabling dwc2-irqs
+ * prevents reboots/poweroffs from getting stuck in such cases.
+ */
+static void dwc2_driver_shutdown(struct platform_device *dev)
+{
+ struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+
+ disable_irq(hsotg->irq);
+}
+
static const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
+ { .compatible = "hisilicon,hi6220-usb", .data = &params_hi6220 },
{ .compatible = "rockchip,rk3066-usb", .data = &params_rk3066 },
{ .compatible = "snps,dwc2", .data = NULL },
{ .compatible = "samsung,s3c6400-hsotg", .data = NULL},
@@ -335,7 +454,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
struct dwc2_hsotg *hsotg;
struct resource *res;
int retval;
- int irq;
match = of_match_device(dwc2_of_match_table, &dev->dev);
if (match && match->data) {
@@ -348,8 +466,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
/*
* Disable descriptor dma mode by default as the HW can support
* it, but does not support it for SPLIT transactions.
+ * Disable it for FS devices as well.
*/
defparams.dma_desc_enable = 0;
+ defparams.dma_desc_fs_enable = 0;
}
hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
@@ -375,19 +495,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
(unsigned long)res->start, hsotg->regs);
- hsotg->dr_mode = usb_get_dr_mode(&dev->dev);
- if (IS_ENABLED(CONFIG_USB_DWC2_HOST) &&
- hsotg->dr_mode != USB_DR_MODE_HOST) {
- hsotg->dr_mode = USB_DR_MODE_HOST;
- dev_warn(hsotg->dev,
- "Configuration mismatch. Forcing host mode\n");
- } else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) &&
- hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
- hsotg->dr_mode = USB_DR_MODE_PERIPHERAL;
- dev_warn(hsotg->dev,
- "Configuration mismatch. Forcing peripheral mode\n");
- }
-
retval = dwc2_lowlevel_hw_init(hsotg);
if (retval)
return retval;
@@ -401,15 +508,15 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_set_all_params(hsotg->core_params, -1);
- irq = platform_get_irq(dev, 0);
- if (irq < 0) {
+ hsotg->irq = platform_get_irq(dev, 0);
+ if (hsotg->irq < 0) {
dev_err(&dev->dev, "missing IRQ resource\n");
- return irq;
+ return hsotg->irq;
}
dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
- irq);
- retval = devm_request_irq(hsotg->dev, irq,
+ hsotg->irq);
+ retval = devm_request_irq(hsotg->dev, hsotg->irq,
dwc2_handle_common_intr, IRQF_SHARED,
dev_name(hsotg->dev), hsotg);
if (retval)
@@ -419,7 +526,11 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
return retval;
- /* Detect config values from hardware */
+ retval = dwc2_get_dr_mode(hsotg);
+ if (retval)
+ return retval;
+
+ /* Reset the controller and detect hardware config values */
retval = dwc2_get_hwparams(hsotg);
if (retval)
goto error;
@@ -427,15 +538,17 @@ static int dwc2_driver_probe(struct platform_device *dev)
/* Validate parameter values */
dwc2_set_parameters(hsotg, params);
+ dwc2_force_dr_mode(hsotg);
+
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
- retval = dwc2_gadget_init(hsotg, irq);
+ retval = dwc2_gadget_init(hsotg, hsotg->irq);
if (retval)
goto error;
hsotg->gadget_enabled = 1;
}
if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
- retval = dwc2_hcd_init(hsotg, irq);
+ retval = dwc2_hcd_init(hsotg, hsotg->irq);
if (retval) {
if (hsotg->gadget_enabled)
dwc2_hsotg_remove(hsotg);
@@ -502,6 +615,7 @@ static struct platform_driver dwc2_platform_driver = {
},
.probe = dwc2_driver_probe,
.remove = dwc2_driver_remove,
+ .shutdown = dwc2_driver_shutdown,
};
module_platform_driver(dwc2_platform_driver);
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 5a42c4590402..a64ce1c94d6d 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -87,6 +87,15 @@ config USB_DWC3_KEYSTONE
Support of USB2/3 functionality in TI Keystone2 platforms.
Say 'Y' or 'M' here if you have one such device
+config USB_DWC3_OF_SIMPLE
+ tristate "Generic OF Simple Glue Layer"
+ depends on OF && COMMON_CLK
+ default USB_DWC3
+ help
+ Support USB2/3 functionality in simple SoC integrations.
+ Currently supports Xilinx and Qualcomm DWC USB3 IP.
+ Say 'Y' or 'M' if you have one such device.
+
config USB_DWC3_ST
tristate "STMicroelectronics Platforms"
depends on ARCH_STI && OF
@@ -96,12 +105,4 @@ config USB_DWC3_ST
inside (i.e. STiH407).
Say 'Y' or 'M' if you have one such device.
-config USB_DWC3_QCOM
- tristate "Qualcomm Platforms"
- depends on ARCH_QCOM || COMPILE_TEST
- default USB_DWC3
- help
- Recent Qualcomm SoCs ship with one DesignWare Core USB3 IP inside,
- say 'Y' or 'M' if you have one such device.
-
endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index acc951d46c27..22420e17d68b 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -37,5 +37,5 @@ obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o
obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o
obj-$(CONFIG_USB_DWC3_KEYSTONE) += dwc3-keystone.o
-obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o
+obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o
obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 22b4797383cd..de5e01f41bc2 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -272,7 +272,8 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
for (n = 0; n < dwc->num_event_buffers; n++) {
evt = dwc->ev_buffs[n];
- dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+ dwc3_trace(trace_dwc3_core,
+ "Event buf %p dma %08llx length %d\n",
evt->buf, (unsigned long long) evt->dma,
evt->length);
@@ -608,12 +609,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
reg |= DWC3_GCTL_GBLHIBERNATIONEN;
break;
default:
- dev_dbg(dwc->dev, "No power optimization available\n");
+ dwc3_trace(trace_dwc3_core, "No power optimization available\n");
}
/* check if current dwc3 is on simulation board */
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
- dev_dbg(dwc->dev, "it is on FPGA board\n");
+ dwc3_trace(trace_dwc3_core,
+ "running on FPGA platform\n");
dwc->is_fpga = true;
}
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 36f1cb74588c..29130682e547 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -37,6 +37,7 @@
#define DWC3_MSG_MAX 500
/* Global constants */
+#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */
#define DWC3_EP0_BOUNCE_SIZE 512
#define DWC3_ENDPOINTS_NUM 32
#define DWC3_XHCI_RESOURCES_NUM 2
@@ -647,6 +648,7 @@ struct dwc3_scratchpad_array {
* @ctrl_req: usb control request which is used for ep0
* @ep0_trb: trb which is used for the ctrl_req
* @ep0_bounce: bounce buffer for ep0
+ * @zlp_buf: used when request->zero is set
* @setup_buf: used while precessing STD USB requests
* @ctrl_req_addr: dma address of ctrl_req
* @ep0_trb: dma address of ep0_trb
@@ -734,6 +736,7 @@ struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
struct dwc3_trb *ep0_trb;
void *ep0_bounce;
+ void *zlp_buf;
void *scratchbuf;
u8 *setup_buf;
dma_addr_t ctrl_req_addr;
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
new file mode 100644
index 000000000000..9c9f74155066
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -0,0 +1,180 @@
+/**
+ * dwc3-of-simple.c - OF glue layer for simple integrations
+ *
+ * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@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 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This is a combination of the old dwc3-qcom.c by Ivan T. Ivanov
+ * <iivanov@mm-sol.com> and the original patch adding support for Xilinx' SoC
+ * by Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+struct dwc3_of_simple {
+ struct device *dev;
+ struct clk **clks;
+ int num_clocks;
+};
+
+static int dwc3_of_simple_probe(struct platform_device *pdev)
+{
+ struct dwc3_of_simple *simple;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ int ret;
+ int i;
+
+ simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
+ if (!simple)
+ return -ENOMEM;
+
+ ret = of_clk_get_parent_count(np);
+ if (ret < 0)
+ return ret;
+
+ simple->num_clocks = ret;
+
+ simple->clks = devm_kcalloc(dev, simple->num_clocks,
+ sizeof(struct clk *), GFP_KERNEL);
+ if (!simple->clks)
+ return -ENOMEM;
+
+ simple->dev = dev;
+
+ for (i = 0; i < simple->num_clocks; i++) {
+ struct clk *clk;
+
+ clk = of_clk_get(np, i);
+ if (IS_ERR(clk)) {
+ while (--i >= 0)
+ clk_put(simple->clks[i]);
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret < 0) {
+ while (--i >= 0) {
+ clk_disable_unprepare(simple->clks[i]);
+ clk_put(simple->clks[i]);
+ }
+ clk_put(clk);
+
+ return ret;
+ }
+
+ simple->clks[i] = clk;
+ }
+
+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret) {
+ for (i = 0; i < simple->num_clocks; i++) {
+ clk_disable_unprepare(simple->clks[i]);
+ clk_put(simple->clks[i]);
+ }
+
+ return ret;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ return 0;
+}
+
+static int dwc3_of_simple_remove(struct platform_device *pdev)
+{
+ struct dwc3_of_simple *simple = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ int i;
+
+ for (i = 0; i < simple->num_clocks; i++) {
+ clk_unprepare(simple->clks[i]);
+ clk_put(simple->clks[i]);
+ }
+
+ of_platform_depopulate(dev);
+
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int dwc3_of_simple_runtime_suspend(struct device *dev)
+{
+ struct dwc3_of_simple *simple = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < simple->num_clocks; i++)
+ clk_disable(simple->clks[i]);
+
+ return 0;
+}
+
+static int dwc3_of_simple_runtime_resume(struct device *dev)
+{
+ struct dwc3_of_simple *simple = dev_get_drvdata(dev);
+ int ret;
+ int i;
+
+ for (i = 0; i < simple->num_clocks; i++) {
+ ret = clk_enable(simple->clks[i]);
+ if (ret < 0) {
+ while (--i >= 0)
+ clk_disable(simple->clks[i]);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
+ dwc3_of_simple_runtime_resume, NULL)
+};
+
+static const struct of_device_id of_dwc3_simple_match[] = {
+ { .compatible = "qcom,dwc3" },
+ { .compatible = "xlnx,zynqmp-dwc3" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
+
+static struct platform_driver dwc3_of_simple_driver = {
+ .probe = dwc3_of_simple_probe,
+ .remove = dwc3_of_simple_remove,
+ .driver = {
+ .name = "dwc3-of-simple",
+ .of_match_table = of_dwc3_simple_match,
+ },
+};
+
+module_platform_driver(dwc3_of_simple_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
deleted file mode 100644
index 088026048f49..000000000000
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-
-struct dwc3_qcom {
- struct device *dev;
-
- struct clk *core_clk;
- struct clk *iface_clk;
- struct clk *sleep_clk;
-};
-
-static int dwc3_qcom_probe(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- struct dwc3_qcom *qdwc;
- int ret;
-
- qdwc = devm_kzalloc(&pdev->dev, sizeof(*qdwc), GFP_KERNEL);
- if (!qdwc)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, qdwc);
-
- qdwc->dev = &pdev->dev;
-
- qdwc->core_clk = devm_clk_get(qdwc->dev, "core");
- if (IS_ERR(qdwc->core_clk)) {
- dev_err(qdwc->dev, "failed to get core clock\n");
- return PTR_ERR(qdwc->core_clk);
- }
-
- qdwc->iface_clk = devm_clk_get(qdwc->dev, "iface");
- if (IS_ERR(qdwc->iface_clk)) {
- dev_info(qdwc->dev, "failed to get optional iface clock\n");
- qdwc->iface_clk = NULL;
- }
-
- qdwc->sleep_clk = devm_clk_get(qdwc->dev, "sleep");
- if (IS_ERR(qdwc->sleep_clk)) {
- dev_info(qdwc->dev, "failed to get optional sleep clock\n");
- qdwc->sleep_clk = NULL;
- }
-
- ret = clk_prepare_enable(qdwc->core_clk);
- if (ret) {
- dev_err(qdwc->dev, "failed to enable core clock\n");
- goto err_core;
- }
-
- ret = clk_prepare_enable(qdwc->iface_clk);
- if (ret) {
- dev_err(qdwc->dev, "failed to enable optional iface clock\n");
- goto err_iface;
- }
-
- ret = clk_prepare_enable(qdwc->sleep_clk);
- if (ret) {
- dev_err(qdwc->dev, "failed to enable optional sleep clock\n");
- goto err_sleep;
- }
-
- ret = of_platform_populate(node, NULL, NULL, qdwc->dev);
- if (ret) {
- dev_err(qdwc->dev, "failed to register core - %d\n", ret);
- goto err_clks;
- }
-
- return 0;
-
-err_clks:
- clk_disable_unprepare(qdwc->sleep_clk);
-err_sleep:
- clk_disable_unprepare(qdwc->iface_clk);
-err_iface:
- clk_disable_unprepare(qdwc->core_clk);
-err_core:
- return ret;
-}
-
-static int dwc3_qcom_remove(struct platform_device *pdev)
-{
- struct dwc3_qcom *qdwc = platform_get_drvdata(pdev);
-
- of_platform_depopulate(&pdev->dev);
-
- clk_disable_unprepare(qdwc->sleep_clk);
- clk_disable_unprepare(qdwc->iface_clk);
- clk_disable_unprepare(qdwc->core_clk);
-
- return 0;
-}
-
-static const struct of_device_id of_dwc3_match[] = {
- { .compatible = "qcom,dwc3" },
- { /* Sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, of_dwc3_match);
-
-static struct platform_driver dwc3_qcom_driver = {
- .probe = dwc3_qcom_probe,
- .remove = dwc3_qcom_remove,
- .driver = {
- .name = "qcom-dwc3",
- .of_match_table = of_dwc3_match,
- },
-};
-
-module_platform_driver(dwc3_qcom_driver);
-
-MODULE_ALIAS("platform:qcom-dwc3");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("DesignWare USB3 QCOM Glue Layer");
-MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 5320e939e090..3a9354abcb68 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -817,6 +817,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING) {
+ dwc->setup_packet_pending = true;
+
dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
if (r)
@@ -916,8 +918,10 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
}
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
- if (status == DWC3_TRBSTS_SETUP_PENDING)
+ if (status == DWC3_TRBSTS_SETUP_PENDING) {
+ dwc->setup_packet_pending = true;
dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
+ }
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
@@ -971,7 +975,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->number);
if (ret) {
- dev_dbg(dwc->dev, "failed to map request\n");
+ dwc3_trace(trace_dwc3_ep0, "failed to map request\n");
return;
}
@@ -999,7 +1003,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->number);
if (ret) {
- dev_dbg(dwc->dev, "failed to map request\n");
+ dwc3_trace(trace_dwc3_ep0, "failed to map request\n");
return;
}
@@ -1063,8 +1067,6 @@ static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
- dwc->setup_packet_pending = true;
-
switch (event->status) {
case DEPEVT_STATUS_CONTROL_DATA:
dwc3_trace(trace_dwc3_ep0, "Control Data");
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a58376fd65fe..af023a81a0b0 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -265,9 +265,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
usb_gadget_unmap_request(&dwc->gadget, &req->request,
req->direction);
- dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
- req, dep->name, req->request.actual,
- req->request.length, status);
trace_dwc3_gadget_giveback(req);
spin_unlock(&dwc->lock);
@@ -664,11 +661,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
dep = to_dwc3_ep(ep);
dwc = dep->dwc;
- if (dep->flags & DWC3_EP_ENABLED) {
- dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
- dep->name);
+ if (dev_WARN_ONCE(dwc->dev, dep->flags & DWC3_EP_ENABLED,
+ "%s is already enabled\n",
+ dep->name))
return 0;
- }
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
@@ -692,11 +688,10 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
dep = to_dwc3_ep(ep);
dwc = dep->dwc;
- if (!(dep->flags & DWC3_EP_ENABLED)) {
- dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
- dep->name);
+ if (dev_WARN_ONCE(dwc->dev, !(dep->flags & DWC3_EP_ENABLED),
+ "%s is already disabled\n",
+ dep->name))
return 0;
- }
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_disable(dep);
@@ -985,8 +980,6 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
cmd |= DWC3_DEPCMD_PARAM(cmd_param);
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
if (ret < 0) {
- dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
-
/*
* FIXME we need to iterate over the list of requests
* here and stop, unmap, free and del each of the linked
@@ -1044,6 +1037,20 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
struct dwc3 *dwc = dep->dwc;
int ret;
+ if (!dep->endpoint.desc) {
+ dwc3_trace(trace_dwc3_gadget,
+ "trying to queue request %p to disabled %s\n",
+ &req->request, dep->endpoint.name);
+ return -ESHUTDOWN;
+ }
+
+ if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
+ &req->request, req->dep->name)) {
+ dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'\n",
+ &req->request, req->dep->name);
+ return -EINVAL;
+ }
+
req->request.actual = 0;
req->request.status = -EINPROGRESS;
req->direction = dep->direction;
@@ -1141,7 +1148,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
out:
if (ret && ret != -EBUSY)
- dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "%s: failed to kick transfers\n",
dep->name);
if (ret == -EBUSY)
ret = 0;
@@ -1149,6 +1157,32 @@ out:
return ret;
}
+static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ dwc3_gadget_ep_free_request(ep, request);
+}
+
+static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_request *req;
+ struct usb_request *request;
+ struct usb_ep *ep = &dep->endpoint;
+
+ dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n");
+ request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
+ if (!request)
+ return -ENOMEM;
+
+ request->length = 0;
+ request->buf = dwc->zlp_buf;
+ request->complete = __dwc3_gadget_ep_zlp_complete;
+
+ req = to_dwc3_request(request);
+
+ return __dwc3_gadget_ep_queue(dep, req);
+}
+
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags)
{
@@ -1161,22 +1195,18 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
int ret;
spin_lock_irqsave(&dwc->lock, flags);
- if (!dep->endpoint.desc) {
- dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
- request, ep->name);
- ret = -ESHUTDOWN;
- goto out;
- }
-
- if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
- request, req->dep->name)) {
- ret = -EINVAL;
- goto out;
- }
-
ret = __dwc3_gadget_ep_queue(dep, req);
-out:
+ /*
+ * Okay, here's the thing, if gadget driver has requested for a ZLP by
+ * setting request->zero, instead of doing magic, we will just queue an
+ * extra usb_request ourselves so that it gets handled the same way as
+ * any other request.
+ */
+ if (ret == 0 && request->zero && request->length &&
+ (request->length % ep->maxpacket == 0))
+ ret = __dwc3_gadget_ep_queue_zlp(dwc, dep);
+
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -1246,7 +1276,8 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
(!list_empty(&dep->req_queued) ||
!list_empty(&dep->request_list)))) {
- dev_dbg(dwc->dev, "%s: pending request, cannot halt\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "%s: pending request, cannot halt\n",
dep->name);
return -EAGAIN;
}
@@ -1373,7 +1404,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
speed = reg & DWC3_DSTS_CONNECTSPD;
if (speed == DWC3_DSTS_SUPERSPEED) {
- dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+ dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
ret = -EINVAL;
goto out;
}
@@ -1385,8 +1416,9 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */
break;
default:
- dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
- link_state);
+ dwc3_trace(trace_dwc3_gadget,
+ "can't wakeup from '%s'\n",
+ dwc3_gadget_link_string(link_state));
ret = -EINVAL;
goto out;
}
@@ -1825,7 +1857,8 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
if (count) {
trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
- dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "%s: incomplete IN transfer\n",
dep->name);
/*
* If missed isoc occurred and there is
@@ -1887,10 +1920,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
do {
req = next_request(&dep->req_queued);
- if (!req) {
- WARN_ON_ONCE(1);
+ if (WARN_ON_ONCE(!req))
return 1;
- }
+
i = 0;
do {
slot = req->start_slot + i;
@@ -2004,7 +2036,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dep->resource_index = 0;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "%s is an Isochronous endpoint\n",
dep->name);
return;
}
@@ -2031,7 +2064,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
if (!ret || ret == -EBUSY)
return;
- dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "%s: failed to kick transfers\n",
dep->name);
}
@@ -2053,11 +2087,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
case DEPEVT_STREAMEVT_NOTFOUND:
/* FALLTHROUGH */
default:
- dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+ dwc3_trace(trace_dwc3_gadget,
+ "unable to find suitable stream\n");
}
break;
case DWC3_DEPEVT_RXTXFIFOEVT:
- dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+ dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun\n", dep->name);
break;
case DWC3_DEPEVT_EPCMDCMPLT:
dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
@@ -2230,8 +2265,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
*
* Our suggested workaround is to follow the Disconnect
* Event steps here, instead, based on a setup_packet_pending
- * flag. Such flag gets set whenever we have a XferNotReady
- * event on EP0 and gets cleared on XferComplete for the
+ * flag. Such flag gets set whenever we have a SETUP_PENDING
+ * status for EP0 TRBs and gets cleared on XferComplete for the
* same endpoint.
*
* Refers to:
@@ -2744,6 +2779,12 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err3;
}
+ dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL);
+ if (!dwc->zlp_buf) {
+ ret = -ENOMEM;
+ goto err4;
+ }
+
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
@@ -2785,16 +2826,19 @@ int dwc3_gadget_init(struct dwc3 *dwc)
ret = dwc3_gadget_init_endpoints(dwc);
if (ret)
- goto err4;
+ goto err5;
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
- goto err4;
+ goto err5;
}
return 0;
+err5:
+ kfree(dwc->zlp_buf);
+
err4:
dwc3_gadget_free_endpoints(dwc);
dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
@@ -2827,6 +2871,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc->ep0_bounce, dwc->ep0_bounce_addr);
kfree(dwc->setup_buf);
+ kfree(dwc->zlp_buf);
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
dwc->ep0_trb, dwc->ep0_trb_addr);
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 9c10669ab91f..3ac7252f4427 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -117,6 +117,9 @@ DECLARE_EVENT_CLASS(dwc3_log_request,
__field(unsigned, actual)
__field(unsigned, length)
__field(int, status)
+ __field(int, zero)
+ __field(int, short_not_ok)
+ __field(int, no_interrupt)
),
TP_fast_assign(
snprintf(__get_str(name), DWC3_MSG_MAX, "%s", req->dep->name);
@@ -124,9 +127,15 @@ DECLARE_EVENT_CLASS(dwc3_log_request,
__entry->actual = req->request.actual;
__entry->length = req->request.length;
__entry->status = req->request.status;
+ __entry->zero = req->request.zero;
+ __entry->short_not_ok = req->request.short_not_ok;
+ __entry->no_interrupt = req->request.no_interrupt;
),
- TP_printk("%s: req %p length %u/%u ==> %d",
+ TP_printk("%s: req %p length %u/%u %s%s%s ==> %d",
__get_str(name), __entry->req, __entry->actual, __entry->length,
+ __entry->zero ? "Z" : "z",
+ __entry->short_not_ok ? "S" : "s",
+ __entry->no_interrupt ? "i" : "I",
__entry->status
)
);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 33834aa09ed4..af5d922a8f5d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -127,6 +127,12 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
a module parameter as well.
If unsure, say 2.
+config U_SERIAL_CONSOLE
+ bool "Serial gadget console support"
+ depends on USB_G_SERIAL
+ help
+ It supports the serial gadget can be used as a console.
+
source "drivers/usb/gadget/udc/Kconfig"
#
@@ -199,6 +205,9 @@ config USB_F_HID
config USB_F_PRINTER
tristate
+config USB_F_TCM
+ tristate
+
choice
tristate "USB Gadget Drivers"
default USB_ETH
@@ -451,6 +460,20 @@ config USB_CONFIGFS_F_PRINTER
For more information, see Documentation/usb/gadget_printer.txt
which includes sample code for accessing the device file.
+config USB_CONFIGFS_F_TCM
+ bool "USB Gadget Target Fabric"
+ depends on TARGET_CORE
+ depends on USB_CONFIGFS
+ select USB_LIBCOMPOSITE
+ select USB_F_TCM
+ help
+ This fabric is a USB gadget component. Two USB protocols are
+ supported that is BBB or BOT (Bulk Only Transport) and UAS
+ (USB Attached SCSI). BOT is advertised on alternative
+ interface 0 (primary) and UAS is on alternative interface 1.
+ Both protocols can work on USB2.0 and USB3.0.
+ UAS utilizes the USB 3.0 feature called streams support.
+
source "drivers/usb/gadget/legacy/Kconfig"
endchoice
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 163d305e1200..590c44989e5e 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -56,7 +56,6 @@ struct gadget_info {
struct list_head string_list;
struct list_head available_func;
- const char *udc_name;
struct usb_composite_driver composite;
struct usb_composite_dev cdev;
bool use_os_desc;
@@ -233,21 +232,23 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item,
static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page)
{
- return sprintf(page, "%s\n", to_gadget_info(item)->udc_name ?: "");
+ char *udc_name = to_gadget_info(item)->composite.gadget_driver.udc_name;
+
+ return sprintf(page, "%s\n", udc_name ?: "");
}
static int unregister_gadget(struct gadget_info *gi)
{
int ret;
- if (!gi->udc_name)
+ if (!gi->composite.gadget_driver.udc_name)
return -ENODEV;
ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver);
if (ret)
return ret;
- kfree(gi->udc_name);
- gi->udc_name = NULL;
+ kfree(gi->composite.gadget_driver.udc_name);
+ gi->composite.gadget_driver.udc_name = NULL;
return 0;
}
@@ -271,14 +272,16 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
if (ret)
goto err;
} else {
- if (gi->udc_name) {
+ if (gi->composite.gadget_driver.udc_name) {
ret = -EBUSY;
goto err;
}
- ret = usb_udc_attach_driver(name, &gi->composite.gadget_driver);
- if (ret)
+ gi->composite.gadget_driver.udc_name = name;
+ ret = usb_gadget_probe_driver(&gi->composite.gadget_driver);
+ if (ret) {
+ gi->composite.gadget_driver.udc_name = NULL;
goto err;
- gi->udc_name = name;
+ }
}
mutex_unlock(&gi->lock);
return len;
@@ -427,9 +430,9 @@ static int config_usb_cfg_unlink(
* remove the function.
*/
mutex_lock(&gi->lock);
- if (gi->udc_name)
+ if (gi->composite.gadget_driver.udc_name)
unregister_gadget(gi);
- WARN_ON(gi->udc_name);
+ WARN_ON(gi->composite.gadget_driver.udc_name);
list_for_each_entry(f, &cfg->func_list, list) {
if (f->fi == fi) {
@@ -873,10 +876,10 @@ static int os_desc_unlink(struct config_item *os_desc_ci,
struct usb_composite_dev *cdev = &gi->cdev;
mutex_lock(&gi->lock);
- if (gi->udc_name)
+ if (gi->composite.gadget_driver.udc_name)
unregister_gadget(gi);
cdev->os_desc_config = NULL;
- WARN_ON(gi->udc_name);
+ WARN_ON(gi->composite.gadget_driver.udc_name);
mutex_unlock(&gi->lock);
return 0;
}
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index bd7def576955..cb8c225e8549 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -44,3 +44,5 @@ usb_f_hid-y := f_hid.o
obj-$(CONFIG_USB_F_HID) += usb_f_hid.o
usb_f_printer-y := f_printer.o
obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o
+usb_f_tcm-y := f_tcm.o
+obj-$(CONFIG_USB_F_TCM) += usb_f_tcm.o
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 898a570319f1..fb1fe96d3215 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/kfifo.h>
#include <sound/core.h>
#include <sound/initval.h>
@@ -75,6 +76,7 @@ struct f_midi {
struct usb_ep *in_ep, *out_ep;
struct snd_card *card;
struct snd_rawmidi *rmidi;
+ u8 ms_id;
struct snd_rawmidi_substream *in_substream[MAX_PORTS];
struct snd_rawmidi_substream *out_substream[MAX_PORTS];
@@ -87,6 +89,9 @@ struct f_midi {
int index;
char *id;
unsigned int buflen, qlen;
+ /* This fifo is used as a buffer ring for pre-allocated IN usb_requests */
+ DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);
+ unsigned int in_last_port;
};
static inline struct f_midi *func_to_midi(struct usb_function *f)
@@ -94,7 +99,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f)
return container_of(f, struct f_midi, func);
}
-static void f_midi_transmit(struct f_midi *midi, struct usb_request *req);
+static void f_midi_transmit(struct f_midi *midi);
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
@@ -201,12 +206,6 @@ static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep,
return alloc_ep_req(ep, length, length);
}
-static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
-{
- kfree(req->buf);
- usb_ep_free_request(ep, req);
-}
-
static const uint8_t f_midi_cin_length[] = {
0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
};
@@ -258,7 +257,8 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req)
} else if (ep == midi->in_ep) {
/* Our transmit completed. See if there's more to go.
* f_midi_transmit eats req, don't queue it again. */
- f_midi_transmit(midi, req);
+ req->length = 0;
+ f_midi_transmit(midi);
return;
}
break;
@@ -269,10 +269,12 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req)
case -ESHUTDOWN: /* disconnect from host */
VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length);
- if (ep == midi->out_ep)
+ if (ep == midi->out_ep) {
f_midi_handle_out_data(ep, req);
-
- free_ep_req(ep, req);
+ /* We don't need to free IN requests because it's handled
+ * by the midi->in_req_fifo. */
+ free_ep_req(ep, req);
+ }
return;
case -EOVERFLOW: /* buffer overrun on read means that
@@ -324,12 +326,11 @@ static int f_midi_start_ep(struct f_midi *midi,
static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_midi *midi = func_to_midi(f);
- struct usb_composite_dev *cdev = f->config->cdev;
unsigned i;
int err;
- /* For Control Device interface we do nothing */
- if (intf == 0)
+ /* we only set alt for MIDIStreaming interface */
+ if (intf != midi->ms_id)
return 0;
err = f_midi_start_ep(midi, f, midi->in_ep);
@@ -340,23 +341,19 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (err)
return err;
- usb_ep_disable(midi->out_ep);
+ /* pre-allocate write usb requests to use on f_midi_transmit. */
+ while (kfifo_avail(&midi->in_req_fifo)) {
+ struct usb_request *req =
+ midi_alloc_ep_req(midi->in_ep, midi->buflen);
- err = config_ep_by_speed(midi->gadget, f, midi->out_ep);
- if (err) {
- ERROR(cdev, "can't configure %s: %d\n",
- midi->out_ep->name, err);
- return err;
- }
+ if (req == NULL)
+ return -ENOMEM;
- err = usb_ep_enable(midi->out_ep);
- if (err) {
- ERROR(cdev, "can't start %s: %d\n",
- midi->out_ep->name, err);
- return err;
- }
+ req->length = 0;
+ req->complete = f_midi_complete;
- midi->out_ep->driver_data = midi;
+ kfifo_put(&midi->in_req_fifo, req);
+ }
/* allocate a bunch of read buffers and queue them all at once. */
for (i = 0; i < midi->qlen && err == 0; i++) {
@@ -368,9 +365,10 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
req->complete = f_midi_complete;
err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC);
if (err) {
- ERROR(midi, "%s queue req: %d\n",
+ ERROR(midi, "%s: couldn't enqueue request: %d\n",
midi->out_ep->name, err);
free_ep_req(midi->out_ep, req);
+ return err;
}
}
@@ -381,6 +379,7 @@ static void f_midi_disable(struct usb_function *f)
{
struct f_midi *midi = func_to_midi(f);
struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = NULL;
DBG(cdev, "disable\n");
@@ -390,6 +389,10 @@ static void f_midi_disable(struct usb_function *f)
*/
usb_ep_disable(midi->in_ep);
usb_ep_disable(midi->out_ep);
+
+ /* release IN requests */
+ while (kfifo_get(&midi->in_req_fifo, &req))
+ free_ep_req(midi->in_ep, req);
}
static int f_midi_snd_free(struct snd_device *device)
@@ -511,57 +514,113 @@ static void f_midi_transmit_byte(struct usb_request *req,
}
}
-static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
+static void f_midi_drop_out_substreams(struct f_midi *midi)
{
- struct usb_ep *ep = midi->in_ep;
- int i;
-
- if (!ep)
- return;
-
- if (!req)
- req = midi_alloc_ep_req(ep, midi->buflen);
-
- if (!req) {
- ERROR(midi, "%s: alloc_ep_request failed\n", __func__);
- return;
- }
- req->length = 0;
- req->complete = f_midi_complete;
+ unsigned int i;
for (i = 0; i < MAX_PORTS; i++) {
struct gmidi_in_port *port = midi->in_port[i];
struct snd_rawmidi_substream *substream = midi->in_substream[i];
- if (!port || !port->active || !substream)
+ if (!port)
+ break;
+
+ if (!port->active || !substream)
continue;
- while (req->length + 3 < midi->buflen) {
- uint8_t b;
- if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
- port->active = 0;
+ snd_rawmidi_drop_output(substream);
+ }
+}
+
+static void f_midi_transmit(struct f_midi *midi)
+{
+ struct usb_ep *ep = midi->in_ep;
+ bool active;
+
+ /* We only care about USB requests if IN endpoint is enabled */
+ if (!ep || !ep->enabled)
+ goto drop_out;
+
+ do {
+ struct usb_request *req = NULL;
+ unsigned int len, i;
+
+ active = false;
+
+ /* We peek the request in order to reuse it if it fails
+ * to enqueue on its endpoint */
+ len = kfifo_peek(&midi->in_req_fifo, &req);
+ if (len != 1) {
+ ERROR(midi, "%s: Couldn't get usb request\n", __func__);
+ goto drop_out;
+ }
+
+ /* If buffer overrun, then we ignore this transmission.
+ * IMPORTANT: This will cause the user-space rawmidi device to block until a) usb
+ * requests have been completed or b) snd_rawmidi_write() times out. */
+ if (req->length > 0)
+ return;
+
+ for (i = midi->in_last_port; i < MAX_PORTS; i++) {
+ struct gmidi_in_port *port = midi->in_port[i];
+ struct snd_rawmidi_substream *substream = midi->in_substream[i];
+
+ if (!port) {
+ /* Reset counter when we reach the last available port */
+ midi->in_last_port = 0;
+ break;
+ }
+
+ if (!port->active || !substream)
+ continue;
+
+ while (req->length + 3 < midi->buflen) {
+ uint8_t b;
+
+ if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
+ port->active = 0;
+ break;
+ }
+ f_midi_transmit_byte(req, port, b);
+ }
+
+ active = !!port->active;
+ /* Check if last port is still active, which means that
+ * there is still data on that substream but this current
+ * request run out of space. */
+ if (active) {
+ midi->in_last_port = i;
+ /* There is no need to re-iterate though midi ports. */
break;
}
- f_midi_transmit_byte(req, port, b);
}
- }
- if (req->length > 0 && ep->enabled) {
- int err;
+ if (req->length > 0) {
+ int err;
- err = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (err < 0)
- ERROR(midi, "%s queue req: %d\n",
- midi->in_ep->name, err);
- } else {
- free_ep_req(ep, req);
- }
+ err = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (err < 0) {
+ ERROR(midi, "%s failed to queue req: %d\n",
+ midi->in_ep->name, err);
+ req->length = 0; /* Re-use request next time. */
+ } else {
+ /* Upon success, put request at the back of the queue. */
+ kfifo_skip(&midi->in_req_fifo);
+ kfifo_put(&midi->in_req_fifo, req);
+ }
+ }
+ } while (active);
+
+ return;
+
+drop_out:
+ f_midi_drop_out_substreams(midi);
}
static void f_midi_in_tasklet(unsigned long data)
{
struct f_midi *midi = (struct f_midi *) data;
- f_midi_transmit(midi, NULL);
+ f_midi_transmit(midi);
}
static int f_midi_in_open(struct snd_rawmidi_substream *substream)
@@ -687,6 +746,7 @@ static int f_midi_register_card(struct f_midi *midi)
goto fail;
}
midi->rmidi = rmidi;
+ midi->in_last_port = 0;
strcpy(rmidi->name, card->shortname);
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
@@ -755,6 +815,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
goto fail;
ms_interface_desc.bInterfaceNumber = status;
ac_header_desc.baInterfaceNr[0] = status;
+ midi->ms_id = status;
status = -ENODEV;
@@ -1075,6 +1136,7 @@ static void f_midi_free(struct usb_function *f)
mutex_lock(&opts->lock);
for (i = opts->in_ports - 1; i >= 0; --i)
kfree(midi->in_port[i]);
+ kfifo_free(&midi->in_req_fifo);
kfree(midi);
--opts->refcnt;
mutex_unlock(&opts->lock);
@@ -1148,6 +1210,12 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
midi->index = opts->index;
midi->buflen = opts->buflen;
midi->qlen = opts->qlen;
+ midi->in_last_port = 0;
+
+ status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL);
+ if (status)
+ goto setup_fail;
+
++opts->refcnt;
mutex_unlock(&opts->lock);
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 9f3ced62d916..242ba5caffe5 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -34,13 +34,6 @@
* plus two that support control-OUT tests. If the optional "autoresume"
* mode is enabled, it provides good functional coverage for the "USBCV"
* test harness from USB-IF.
- *
- * Note that because this doesn't queue more than one request at a time,
- * some other function must be used to test queueing logic. The network
- * link (g_ether) is the best overall option for that, since its TX and RX
- * queues are relatively independent, will receive a range of packet sizes,
- * and can often be made to run out completely. Those issues are important
- * when stress testing peripheral controller drivers.
*/
struct f_sourcesink {
struct usb_function function;
@@ -57,6 +50,8 @@ struct f_sourcesink {
unsigned isoc_mult;
unsigned isoc_maxburst;
unsigned buflen;
+ unsigned bulk_qlen;
+ unsigned iso_qlen;
};
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@@ -303,12 +298,6 @@ static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
return alloc_ep_req(ep, len, ss->buflen);
}
-void free_ep_req(struct usb_ep *ep, struct usb_request *req)
-{
- kfree(req->buf);
- usb_ep_free_request(ep, req);
-}
-
static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
{
int value;
@@ -595,31 +584,33 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
{
struct usb_ep *ep;
struct usb_request *req;
- int i, size, status;
-
- for (i = 0; i < 8; i++) {
- if (is_iso) {
- switch (speed) {
- case USB_SPEED_SUPER:
- size = ss->isoc_maxpacket *
- (ss->isoc_mult + 1) *
- (ss->isoc_maxburst + 1);
- break;
- case USB_SPEED_HIGH:
- size = ss->isoc_maxpacket * (ss->isoc_mult + 1);
- break;
- default:
- size = ss->isoc_maxpacket > 1023 ?
- 1023 : ss->isoc_maxpacket;
- break;
- }
- ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
- req = ss_alloc_ep_req(ep, size);
- } else {
- ep = is_in ? ss->in_ep : ss->out_ep;
- req = ss_alloc_ep_req(ep, 0);
+ int i, size, qlen, status = 0;
+
+ if (is_iso) {
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ size = ss->isoc_maxpacket *
+ (ss->isoc_mult + 1) *
+ (ss->isoc_maxburst + 1);
+ break;
+ case USB_SPEED_HIGH:
+ size = ss->isoc_maxpacket * (ss->isoc_mult + 1);
+ break;
+ default:
+ size = ss->isoc_maxpacket > 1023 ?
+ 1023 : ss->isoc_maxpacket;
+ break;
}
+ ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
+ qlen = ss->iso_qlen;
+ } else {
+ ep = is_in ? ss->in_ep : ss->out_ep;
+ qlen = ss->bulk_qlen;
+ size = 0;
+ }
+ for (i = 0; i < qlen; i++) {
+ req = ss_alloc_ep_req(ep, size);
if (!req)
return -ENOMEM;
@@ -638,10 +629,8 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
ep->name, status);
free_ep_req(ep, req);
+ return status;
}
-
- if (!is_iso)
- break;
}
return status;
@@ -869,6 +858,8 @@ static struct usb_function *source_sink_alloc_func(
ss->isoc_mult = ss_opts->isoc_mult;
ss->isoc_maxburst = ss_opts->isoc_maxburst;
ss->buflen = ss_opts->bulk_buflen;
+ ss->bulk_qlen = ss_opts->bulk_qlen;
+ ss->iso_qlen = ss_opts->iso_qlen;
ss->function.name = "source/sink";
ss->function.bind = sourcesink_bind;
@@ -1153,6 +1144,82 @@ end:
CONFIGFS_ATTR(f_ss_opts_, bulk_buflen);
+static ssize_t f_ss_opts_bulk_qlen_show(struct config_item *item, char *page)
+{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
+ int result;
+
+ mutex_lock(&opts->lock);
+ result = sprintf(page, "%u\n", opts->bulk_qlen);
+ mutex_unlock(&opts->lock);
+
+ return result;
+}
+
+static ssize_t f_ss_opts_bulk_qlen_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
+ int ret;
+ u32 num;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ ret = kstrtou32(page, 0, &num);
+ if (ret)
+ goto end;
+
+ opts->bulk_qlen = num;
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+CONFIGFS_ATTR(f_ss_opts_, bulk_qlen);
+
+static ssize_t f_ss_opts_iso_qlen_show(struct config_item *item, char *page)
+{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
+ int result;
+
+ mutex_lock(&opts->lock);
+ result = sprintf(page, "%u\n", opts->iso_qlen);
+ mutex_unlock(&opts->lock);
+
+ return result;
+}
+
+static ssize_t f_ss_opts_iso_qlen_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
+ int ret;
+ u32 num;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ ret = kstrtou32(page, 0, &num);
+ if (ret)
+ goto end;
+
+ opts->iso_qlen = num;
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+CONFIGFS_ATTR(f_ss_opts_, iso_qlen);
+
static struct configfs_attribute *ss_attrs[] = {
&f_ss_opts_attr_pattern,
&f_ss_opts_attr_isoc_interval,
@@ -1160,6 +1227,8 @@ static struct configfs_attribute *ss_attrs[] = {
&f_ss_opts_attr_isoc_mult,
&f_ss_opts_attr_isoc_maxburst,
&f_ss_opts_attr_bulk_buflen,
+ &f_ss_opts_attr_bulk_qlen,
+ &f_ss_opts_attr_iso_qlen,
NULL,
};
@@ -1189,6 +1258,8 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
+ ss_opts->bulk_qlen = GZERO_SS_BULK_QLEN;
+ ss_opts->iso_qlen = GZERO_SS_ISO_QLEN;
config_group_init_type_name(&ss_opts->func_inst.group, "",
&ss_func_type);
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
new file mode 100644
index 000000000000..bad007b5a190
--- /dev/null
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -0,0 +1,2381 @@
+/* Target based USB-Gadget
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <asm/unaligned.h>
+
+#include "tcm.h"
+#include "u_tcm.h"
+#include "configfs.h"
+
+#define TPG_INSTANCES 1
+
+struct tpg_instance {
+ struct usb_function_instance *func_inst;
+ struct usbg_tpg *tpg;
+};
+
+static struct tpg_instance tpg_instances[TPG_INSTANCES];
+
+static DEFINE_MUTEX(tpg_instances_lock);
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+ return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+ kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+ int ret;
+
+ if (fu->flags & USBG_BOT_CMD_PEND)
+ return 0;
+
+ ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+ if (!ret)
+ fu->flags |= USBG_BOT_CMD_PEND;
+ return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ usbg_cleanup_cmd(cmd);
+ if (req->status < 0) {
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+ return;
+ }
+
+ /* CSW completed, wait for next CBW */
+ bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+ unsigned int csw_stat;
+
+ csw_stat = cmd->csw_code;
+ csw->Tag = cmd->bot_tag;
+ csw->Status = csw_stat;
+ fu->bot_status.req->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct f_uas *fu = cmd->fu;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ if (cmd->data_len) {
+ if (cmd->data_len > ep->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ return;
+ }
+ bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ struct usb_request *req;
+ struct usb_ep *ep;
+
+ csw->Residue = cpu_to_le32(cmd->data_len);
+
+ if (cmd->data_len) {
+ if (cmd->is_read) {
+ ep = fu->ep_in;
+ req = fu->bot_req_in;
+ } else {
+ ep = fu->ep_out;
+ req = fu->bot_req_out;
+ }
+
+ if (cmd->data_len > fu->ep_in->maxpacket) {
+ req->length = ep->maxpacket;
+ cmd->data_len -= ep->maxpacket;
+ } else {
+ req->length = cmd->data_len;
+ cmd->data_len = 0;
+ }
+ req->complete = bot_err_compl;
+ req->context = cmd;
+ req->buf = fu->cmd.buf;
+ usb_ep_queue(ep, req, GFP_KERNEL);
+ } else {
+ bot_enqueue_sense_code(fu, cmd);
+ }
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+ struct f_uas *fu = cmd->fu;
+ struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+ int ret;
+
+ if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+ if (!moved_data && cmd->data_len) {
+ /*
+ * the host wants to move data, we don't. Fill / empty
+ * the pipe and then send the csw with reside set.
+ */
+ cmd->csw_code = US_BULK_STAT_OK;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ csw->Tag = cmd->bot_tag;
+ csw->Residue = cpu_to_le32(0);
+ csw->Status = US_BULK_STAT_OK;
+ fu->bot_status.req->context = cmd;
+
+ ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+ } else {
+ cmd->csw_code = US_BULK_STAT_FAIL;
+ bot_send_bad_status(cmd);
+ }
+ return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+ bool moved_data = false;
+
+ if (!cmd->is_read)
+ moved_data = true;
+ return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+
+ if (req->status < 0)
+ pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+ bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ bot_send_bad_status(cmd);
+ return 0;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ fu->bot_req_in->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_in->buf = NULL;
+ fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_in->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_in->complete = bot_read_compl;
+ fu->bot_req_in->length = se_cmd->data_length;
+ fu->bot_req_in->context = cmd;
+ ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ if (!cmd->data_len) {
+ cmd->csw_code = US_BULK_STAT_PHASE;
+ return -EINVAL;
+ }
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ fu->bot_req_out->buf = cmd->data_buf;
+ } else {
+ fu->bot_req_out->buf = NULL;
+ fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+ fu->bot_req_out->sg = se_cmd->t_data_sg;
+ }
+
+ fu->bot_req_out->complete = usbg_data_write_cmpl;
+ fu->bot_req_out->length = se_cmd->data_length;
+ fu->bot_req_out->context = cmd;
+
+ ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ wait_for_completion(&cmd->write_complete);
+ target_execute_cmd(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ fu->flags &= ~USBG_BOT_CMD_PEND;
+
+ if (req->status < 0)
+ return;
+
+ ret = bot_submit_command(fu, req->buf, req->actual);
+ if (ret)
+ pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+
+ fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_req_in)
+ goto err;
+
+ fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->bot_req_out)
+ goto err_out;
+
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err_cmd;
+
+ fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!fu->bot_status.req)
+ goto err_sts;
+
+ fu->bot_status.req->buf = &fu->bot_status.csw;
+ fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+ fu->bot_status.req->complete = bot_status_complete;
+ fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+ fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = bot_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_out->maxpacket;
+ fu->cmd.req->context = fu;
+
+ ret = bot_enqueue_cmd_cbw(fu);
+ if (ret)
+ goto err_queue;
+ return 0;
+err_queue:
+ kfree(fu->cmd.buf);
+ fu->cmd.buf = NULL;
+err_buf:
+ usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ fu->cmd.req = NULL;
+err_cmd:
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ fu->bot_req_out = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ fu->bot_req_in = NULL;
+err:
+ pr_err("BOT: endpoint setup failed\n");
+ return -ENOMEM;
+}
+
+static void bot_cleanup_old_alt(struct f_uas *fu)
+{
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+
+ if (!fu->bot_req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+ usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+ usb_ep_free_request(fu->ep_out, fu->cmd.req);
+ usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+ kfree(fu->cmd.buf);
+
+ fu->bot_req_in = NULL;
+ fu->bot_req_out = NULL;
+ fu->cmd.req = NULL;
+ fu->bot_status.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_BOT;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ ret = bot_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+ pr_info("Using the BOT protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+ int luns;
+ u8 *ret_lun;
+
+ switch (ctrl->bRequest) {
+ case US_BULK_GET_MAX_LUN:
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ return -ENOTSUPP;
+
+ if (w_length < 1)
+ return -EINVAL;
+ if (w_value != 0)
+ return -EINVAL;
+ luns = atomic_read(&fu->tpg->tpg_port_count);
+ if (!luns) {
+ pr_err("No LUNs configured?\n");
+ return -EINVAL;
+ }
+ /*
+ * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+ * accessed. The upper limit is 0xf
+ */
+ luns--;
+ if (luns > 0xf) {
+ pr_info_once("Limiting the number of luns to 16\n");
+ luns = 0xf;
+ }
+ ret_lun = cdev->req->buf;
+ *ret_lun = luns;
+ cdev->req->length = 1;
+ return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+
+ case US_BULK_RESET_REQUEST:
+ /* XXX maybe we should remove previous requests for IN + OUT */
+ bot_enqueue_cmd_cbw(fu);
+ return 0;
+ }
+ return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+ /* We have either all three allocated or none */
+ if (!stream->req_in)
+ return;
+
+ usb_ep_free_request(fu->ep_in, stream->req_in);
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+
+ stream->req_in = NULL;
+ stream->req_out = NULL;
+ stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+ kfree(fu->cmd.buf);
+ fu->cmd.req = NULL;
+ fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+ int i;
+
+ if (!(fu->flags & USBG_ENABLED))
+ return;
+
+ usb_ep_disable(fu->ep_in);
+ usb_ep_disable(fu->ep_out);
+ usb_ep_disable(fu->ep_status);
+ usb_ep_disable(fu->ep_cmd);
+
+ for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+ uasp_cleanup_one_stream(fu, &fu->stream[i]);
+ uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+ struct uas_stream *stream = cmd->stream;
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ sg_copy_to_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+
+ stream->req_in->buf = cmd->data_buf;
+ } else {
+ stream->req_in->buf = NULL;
+ stream->req_in->num_sgs = se_cmd->t_data_nents;
+ stream->req_in->sg = se_cmd->t_data_sg;
+ }
+
+ stream->req_in->complete = uasp_status_data_cmpl;
+ stream->req_in->length = se_cmd->data_length;
+ stream->req_in->context = cmd;
+
+ cmd->state = UASP_SEND_STATUS;
+ return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct sense_iu *iu = &cmd->sense_iu;
+ struct uas_stream *stream = cmd->stream;
+
+ cmd->state = UASP_QUEUE_COMMAND;
+ iu->iu_id = IU_ID_STATUS;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ /*
+ * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+ */
+ iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+ iu->status = se_cmd->scsi_status;
+ stream->req_status->context = cmd;
+ stream->req_status->length = se_cmd->scsi_sense_length + 16;
+ stream->req_status->buf = iu;
+ stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct uas_stream *stream = cmd->stream;
+ struct f_uas *fu = cmd->fu;
+ int ret;
+
+ if (req->status < 0)
+ goto cleanup;
+
+ switch (cmd->state) {
+ case UASP_SEND_DATA:
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_RECEIVE_DATA:
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_SEND_STATUS:
+ uasp_prepare_status(cmd);
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ break;
+
+ case UASP_QUEUE_COMMAND:
+ usbg_cleanup_cmd(cmd);
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ break;
+
+ default:
+ BUG();
+ }
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+ cmd->fu = fu;
+ uasp_prepare_status(cmd);
+ return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = uasp_prepare_r_request(cmd);
+ if (ret)
+ goto out;
+ ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+ if (ret) {
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ kfree(cmd->data_buf);
+ cmd->data_buf = NULL;
+ }
+
+ } else {
+
+ iu->iu_id = IU_ID_READ_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_SEND_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+ }
+out:
+ return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+ struct f_uas *fu = cmd->fu;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct uas_stream *stream = cmd->stream;
+ struct sense_iu *iu = &cmd->sense_iu;
+ int ret;
+
+ init_completion(&cmd->write_complete);
+ cmd->fu = fu;
+
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ if (fu->flags & USBG_USE_STREAMS) {
+
+ ret = usbg_prepare_w_request(cmd, stream->req_out);
+ if (ret)
+ goto cleanup;
+ ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+
+ } else {
+
+ iu->iu_id = IU_ID_WRITE_READY;
+ iu->tag = cpu_to_be16(cmd->tag);
+
+ stream->req_status->complete = uasp_status_data_cmpl;
+ stream->req_status->context = cmd;
+
+ cmd->state = UASP_RECEIVE_DATA;
+ stream->req_status->buf = iu;
+ stream->req_status->length = sizeof(struct iu);
+
+ ret = usb_ep_queue(fu->ep_status, stream->req_status,
+ GFP_ATOMIC);
+ if (ret)
+ pr_err("%s(%d)\n", __func__, __LINE__);
+ }
+
+ wait_for_completion(&cmd->write_complete);
+ target_execute_cmd(se_cmd);
+cleanup:
+ return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_uas *fu = req->context;
+ int ret;
+
+ if (req->status < 0)
+ return;
+
+ ret = usbg_submit_command(fu, req->buf, req->actual);
+ /*
+ * Once we tune for performance enqueue the command req here again so
+ * we can receive a second command while we processing this one. Pay
+ * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+ * don't break HS.
+ */
+ if (!ret)
+ return;
+ usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+ stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+ if (!stream->req_in)
+ goto out;
+
+ stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+ if (!stream->req_out)
+ goto err_out;
+
+ stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+ if (!stream->req_status)
+ goto err_sts;
+
+ return 0;
+err_sts:
+ usb_ep_free_request(fu->ep_status, stream->req_status);
+ stream->req_status = NULL;
+err_out:
+ usb_ep_free_request(fu->ep_out, stream->req_out);
+ stream->req_out = NULL;
+out:
+ return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+ fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+ if (!fu->cmd.req)
+ goto err;
+
+ fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+ if (!fu->cmd.buf)
+ goto err_buf;
+
+ fu->cmd.req->complete = uasp_cmd_complete;
+ fu->cmd.req->buf = fu->cmd.buf;
+ fu->cmd.req->length = fu->ep_cmd->maxpacket;
+ fu->cmd.req->context = fu;
+ return 0;
+
+err_buf:
+ usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+ return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+ int i;
+
+ for (i = 0; i < max_streams; i++) {
+ struct uas_stream *s = &fu->stream[i];
+
+ s->req_in->stream_id = i + 1;
+ s->req_out->stream_id = i + 1;
+ s->req_status->stream_id = i + 1;
+ }
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+ int ret;
+ int i;
+ int max_streams;
+
+ if (fu->flags & USBG_USE_STREAMS)
+ max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+ else
+ max_streams = 1;
+
+ for (i = 0; i < max_streams; i++) {
+ ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+ if (ret)
+ goto err_cleanup;
+ }
+
+ ret = uasp_alloc_cmd(fu);
+ if (ret)
+ goto err_free_stream;
+ uasp_setup_stream_res(fu, max_streams);
+
+ ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+ if (ret)
+ goto err_free_stream;
+
+ return 0;
+
+err_free_stream:
+ uasp_free_cmdreq(fu);
+
+err_cleanup:
+ if (i) {
+ do {
+ uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+ i--;
+ } while (i);
+ }
+ pr_err("UASP: endpoint setup failed\n");
+ return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+ struct usb_function *f = &fu->function;
+ struct usb_gadget *gadget = f->config->cdev->gadget;
+ int ret;
+
+ fu->flags = USBG_IS_UAS;
+
+ if (gadget->speed == USB_SPEED_SUPER)
+ fu->flags |= USBG_USE_STREAMS;
+
+ config_ep_by_speed(gadget, f, fu->ep_in);
+ ret = usb_ep_enable(fu->ep_in);
+ if (ret)
+ goto err_b_in;
+
+ config_ep_by_speed(gadget, f, fu->ep_out);
+ ret = usb_ep_enable(fu->ep_out);
+ if (ret)
+ goto err_b_out;
+
+ config_ep_by_speed(gadget, f, fu->ep_cmd);
+ ret = usb_ep_enable(fu->ep_cmd);
+ if (ret)
+ goto err_cmd;
+ config_ep_by_speed(gadget, f, fu->ep_status);
+ ret = usb_ep_enable(fu->ep_status);
+ if (ret)
+ goto err_status;
+
+ ret = uasp_prepare_reqs(fu);
+ if (ret)
+ goto err_wq;
+ fu->flags |= USBG_ENABLED;
+
+ pr_info("Using the UAS protocol\n");
+ return;
+err_wq:
+ usb_ep_disable(fu->ep_status);
+err_status:
+ usb_ep_disable(fu->ep_cmd);
+err_cmd:
+ usb_ep_disable(fu->ep_out);
+err_b_out:
+ usb_ep_disable(fu->ep_in);
+err_b_in:
+ fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+ int ret;
+
+ switch (cdb[0]) {
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case INQUIRY:
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ case SERVICE_ACTION_IN_16:
+ case MAINTENANCE_IN:
+ case PERSISTENT_RESERVE_IN:
+ case SECURITY_PROTOCOL_IN:
+ case ACCESS_CONTROL_IN:
+ case REPORT_LUNS:
+ case READ_BLOCK_LIMITS:
+ case READ_POSITION:
+ case READ_CAPACITY:
+ case READ_TOC:
+ case READ_FORMAT_CAPACITIES:
+ case REQUEST_SENSE:
+ ret = DMA_FROM_DEVICE;
+ break;
+
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ case WRITE_VERIFY:
+ case WRITE_VERIFY_12:
+ case PERSISTENT_RESERVE_OUT:
+ case MAINTENANCE_OUT:
+ case SECURITY_PROTOCOL_OUT:
+ case ACCESS_CONTROL_OUT:
+ ret = DMA_TO_DEVICE;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case TEST_UNIT_READY:
+ case SYNCHRONIZE_CACHE:
+ case START_STOP:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ ret = DMA_NONE;
+ break;
+ default:
+#define CMD_DIR_MSG "target: Unknown data direction for SCSI Opcode 0x%02x\n"
+ pr_warn(CMD_DIR_MSG, cdb[0]);
+#undef CMD_DIR_MSG
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usbg_cmd *cmd = req->context;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+
+ if (req->status < 0) {
+ pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+ goto cleanup;
+ }
+
+ if (req->num_sgs == 0) {
+ sg_copy_from_buffer(se_cmd->t_data_sg,
+ se_cmd->t_data_nents,
+ cmd->data_buf,
+ se_cmd->data_length);
+ }
+
+ complete(&cmd->write_complete);
+ return;
+
+cleanup:
+ usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct f_uas *fu = cmd->fu;
+ struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+ if (!gadget->sg_supported) {
+ cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+ if (!cmd->data_buf)
+ return -ENOMEM;
+
+ req->buf = cmd->data_buf;
+ } else {
+ req->buf = NULL;
+ req->num_sgs = se_cmd->t_data_nents;
+ req->sg = se_cmd->t_data_sg;
+ }
+
+ req->complete = usbg_data_write_cmpl;
+ req->length = se_cmd->data_length;
+ req->context = cmd;
+ return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_status_response(cmd);
+ else
+ return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_write_request(cmd);
+ else
+ return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ struct f_uas *fu = cmd->fu;
+
+ if (fu->flags & USBG_IS_BOT)
+ return bot_send_read_response(cmd);
+ else
+ return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+ goto out;
+ }
+
+ if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0)
+ goto out;
+
+ return;
+
+out:
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct command_iu *cmd_iu = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+
+ if (cmd_iu->iu_id != IU_ID_COMMAND) {
+ pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+ cmd_len = (cmd_iu->len & ~0x3) + 16;
+ if (cmd_len > USBG_MAX_CMD)
+ goto err;
+
+ memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+ cmd->tag = be16_to_cpup(&cmd_iu->tag);
+ cmd->se_cmd.tag = cmd->tag;
+ if (fu->flags & USBG_USE_STREAMS) {
+ if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+ goto err;
+ if (!cmd->tag)
+ cmd->stream = &fu->stream[0];
+ else
+ cmd->stream = &fu->stream[cmd->tag - 1];
+ } else {
+ cmd->stream = &fu->stream[0];
+ }
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ switch (cmd_iu->prio_attr & 0x7) {
+ case UAS_HEAD_TAG:
+ cmd->prio_attr = TCM_HEAD_TAG;
+ break;
+ case UAS_ORDERED_TAG:
+ cmd->prio_attr = TCM_ORDERED_TAG;
+ break;
+ case UAS_ACA:
+ cmd->prio_attr = TCM_ACA_TAG;
+ break;
+ default:
+ pr_debug_once("Unsupported prio_attr: %02x.\n",
+ cmd_iu->prio_attr);
+ case UAS_SIMPLE_TAG:
+ cmd->prio_attr = TCM_SIMPLE_TAG;
+ break;
+ }
+
+ cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+ INIT_WORK(&cmd->work, usbg_cmd_work);
+ queue_work(tpg->workqueue, &cmd->work);
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+ struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+ struct se_cmd *se_cmd;
+ struct tcm_usbg_nexus *tv_nexus;
+ struct usbg_tpg *tpg;
+ int dir;
+
+ se_cmd = &cmd->se_cmd;
+ tpg = cmd->fu->tpg;
+ tv_nexus = tpg->tpg_nexus;
+ dir = get_cmd_dir(cmd->cmd_buf);
+ if (dir < 0) {
+ transport_init_se_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense);
+ goto out;
+ }
+
+ if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ cmd->data_len, cmd->prio_attr, dir, 0) < 0)
+ goto out;
+
+ return;
+
+out:
+ transport_send_check_condition_and_sense(se_cmd,
+ TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+ usbg_cleanup_cmd(cmd);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+ void *cmdbuf, unsigned int len)
+{
+ struct bulk_cb_wrap *cbw = cmdbuf;
+ struct usbg_cmd *cmd;
+ struct usbg_tpg *tpg;
+ struct tcm_usbg_nexus *tv_nexus;
+ u32 cmd_len;
+
+ if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+ pr_err("Wrong signature on CBW\n");
+ return -EINVAL;
+ }
+ if (len != 31) {
+ pr_err("Wrong length for CBW\n");
+ return -EINVAL;
+ }
+
+ cmd_len = cbw->Length;
+ if (cmd_len < 1 || cmd_len > 16)
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->fu = fu;
+
+ /* XXX until I figure out why I can't free in on complete */
+ kref_init(&cmd->ref);
+ kref_get(&cmd->ref);
+
+ tpg = fu->tpg;
+
+ memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+ cmd->bot_tag = cbw->Tag;
+
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ pr_err("Missing nexus, ignoring command\n");
+ goto err;
+ }
+
+ cmd->prio_attr = TCM_SIMPLE_TAG;
+ cmd->unpacked_lun = cbw->Lun;
+ cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+ cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+ cmd->se_cmd.tag = le32_to_cpu(cmd->bot_tag);
+
+ INIT_WORK(&cmd->work, bot_cmd_work);
+ queue_work(tpg->workqueue, &cmd->work);
+
+ return 0;
+err:
+ kfree(cmd);
+ return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+ return "usb_gadget";
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ struct usbg_tport *tport = tpg->tport;
+
+ return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ return tpg->tport_tpgt;
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+ struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+ ref);
+
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+ kfree(cmd->data_buf);
+ kfree(cmd);
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+}
+
+static void usbg_aborted_task(struct se_cmd *se_cmd)
+{
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+ const char *n;
+ unsigned int len;
+
+ n = strstr(name, "naa.");
+ if (!n)
+ return NULL;
+ n += 4;
+ len = strlen(n);
+ if (len == 0 || len > USBG_NAMELEN - 1)
+ return NULL;
+ return n;
+}
+
+static int usbg_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
+{
+ if (!usbg_check_wwn(name))
+ return -EINVAL;
+ return 0;
+}
+
+static struct se_portal_group *usbg_make_tpg(
+ struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+ tport_wwn);
+ struct usbg_tpg *tpg;
+ unsigned long tpgt;
+ int ret;
+ struct f_tcm_opts *opts;
+ unsigned i;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+ ret = -ENODEV;
+ mutex_lock(&tpg_instances_lock);
+ for (i = 0; i < TPG_INSTANCES; ++i)
+ if (tpg_instances[i].func_inst && !tpg_instances[i].tpg)
+ break;
+ if (i == TPG_INSTANCES)
+ goto unlock_inst;
+
+ opts = container_of(tpg_instances[i].func_inst, struct f_tcm_opts,
+ func_inst);
+ mutex_lock(&opts->dep_lock);
+ if (!opts->ready)
+ goto unlock_dep;
+
+ if (opts->has_dep) {
+ if (!try_module_get(opts->dependent))
+ goto unlock_dep;
+ } else {
+ ret = configfs_depend_item_unlocked(
+ group->cg_subsys,
+ &opts->func_inst.group.cg_item);
+ if (ret)
+ goto unlock_dep;
+ }
+
+ tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!tpg)
+ goto unref_dep;
+ mutex_init(&tpg->tpg_mutex);
+ atomic_set(&tpg->tpg_port_count, 0);
+ tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+ if (!tpg->workqueue)
+ goto free_tpg;
+
+ tpg->tport = tport;
+ tpg->tport_tpgt = tpgt;
+
+ /*
+ * SPC doesn't assign a protocol identifier for USB-SCSI, so we
+ * pretend to be SAS..
+ */
+ ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS);
+ if (ret < 0)
+ goto free_workqueue;
+
+ tpg_instances[i].tpg = tpg;
+ tpg->fi = tpg_instances[i].func_inst;
+ mutex_unlock(&opts->dep_lock);
+ mutex_unlock(&tpg_instances_lock);
+ return &tpg->se_tpg;
+
+free_workqueue:
+ destroy_workqueue(tpg->workqueue);
+free_tpg:
+ kfree(tpg);
+unref_dep:
+ if (opts->has_dep)
+ module_put(opts->dependent);
+ else
+ configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
+unlock_dep:
+ mutex_unlock(&opts->dep_lock);
+unlock_inst:
+ mutex_unlock(&tpg_instances_lock);
+
+ return ERR_PTR(ret);
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *);
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg,
+ struct usbg_tpg, se_tpg);
+ unsigned i;
+ struct f_tcm_opts *opts;
+
+ tcm_usbg_drop_nexus(tpg);
+ core_tpg_deregister(se_tpg);
+ destroy_workqueue(tpg->workqueue);
+
+ mutex_lock(&tpg_instances_lock);
+ for (i = 0; i < TPG_INSTANCES; ++i)
+ if (tpg_instances[i].tpg == tpg)
+ break;
+ if (i < TPG_INSTANCES)
+ tpg_instances[i].tpg = NULL;
+ opts = container_of(tpg_instances[i].func_inst,
+ struct f_tcm_opts, func_inst);
+ mutex_lock(&opts->dep_lock);
+ if (opts->has_dep)
+ module_put(opts->dependent);
+ else
+ configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
+ mutex_unlock(&opts->dep_lock);
+ mutex_unlock(&tpg_instances_lock);
+
+ kfree(tpg);
+}
+
+static struct se_wwn *usbg_make_tport(
+ struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct usbg_tport *tport;
+ const char *wnn_name;
+ u64 wwpn = 0;
+
+ wnn_name = usbg_check_wwn(name);
+ if (!wnn_name)
+ return ERR_PTR(-EINVAL);
+
+ tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+ if (!(tport))
+ return ERR_PTR(-ENOMEM);
+
+ tport->tport_wwpn = wwpn;
+ snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);
+ return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+ struct usbg_tport *tport = container_of(wwn,
+ struct usbg_tport, tport_wwn);
+ kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_version_show(struct config_item *item, char *page)
+{
+ return sprintf(page, "usb-gadget fabric module\n");
+}
+
+CONFIGFS_ATTR_RO(usbg_wwn_, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+ &usbg_wwn_attr_version,
+ NULL,
+};
+
+static ssize_t tcm_usbg_tpg_enable_show(struct config_item *item, char *page)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *);
+static void usbg_detach(struct usbg_tpg *);
+
+static ssize_t tcm_usbg_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ bool op;
+ ssize_t ret;
+
+ ret = strtobool(page, &op);
+ if (ret)
+ return ret;
+
+ if ((op && tpg->gadget_connect) || (!op && !tpg->gadget_connect))
+ return -EINVAL;
+
+ if (op)
+ ret = usbg_attach(tpg);
+ else
+ usbg_detach(tpg);
+ if (ret)
+ return ret;
+
+ tpg->gadget_connect = op;
+
+ return count;
+}
+
+static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ struct tcm_usbg_nexus *tv_nexus;
+ ssize_t ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = snprintf(page, PAGE_SIZE, "%s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+ struct se_portal_group *se_tpg;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret;
+
+ mutex_lock(&tpg->tpg_mutex);
+ if (tpg->tpg_nexus) {
+ ret = -EEXIST;
+ pr_debug("tpg->tpg_nexus already exists\n");
+ goto err_unlock;
+ }
+ se_tpg = &tpg->se_tpg;
+
+ ret = -ENOMEM;
+ tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+ if (!tv_nexus)
+ goto err_unlock;
+ tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);
+ if (IS_ERR(tv_nexus->tvn_se_sess))
+ goto err_free;
+
+ /*
+ * Since we are running in 'demo mode' this call with generate a
+ * struct se_node_acl for the tcm_vhost struct se_portal_group with
+ * the SCSI Initiator port name of the passed configfs group 'name'.
+ */
+ tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+ se_tpg, name);
+ if (!tv_nexus->tvn_se_sess->se_node_acl) {
+#define MAKE_NEXUS_MSG "core_tpg_check_initiator_node_acl() failed for %s\n"
+ pr_debug(MAKE_NEXUS_MSG, name);
+#undef MAKE_NEXUS_MSG
+ goto err_session;
+ }
+ /*
+ * Now register the TCM vHost virtual I_T Nexus as active.
+ */
+ transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+ tv_nexus->tvn_se_sess, tv_nexus);
+ tpg->tpg_nexus = tv_nexus;
+ mutex_unlock(&tpg->tpg_mutex);
+ return 0;
+
+err_session:
+ transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+ kfree(tv_nexus);
+err_unlock:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+ struct se_session *se_sess;
+ struct tcm_usbg_nexus *tv_nexus;
+ int ret = -ENODEV;
+
+ mutex_lock(&tpg->tpg_mutex);
+ tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus)
+ goto out;
+
+ se_sess = tv_nexus->tvn_se_sess;
+ if (!se_sess)
+ goto out;
+
+ if (atomic_read(&tpg->tpg_port_count)) {
+ ret = -EPERM;
+#define MSG "Unable to remove Host I_T Nexus with active TPG port count: %d\n"
+ pr_err(MSG, atomic_read(&tpg->tpg_port_count));
+#undef MSG
+ goto out;
+ }
+
+ pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+ /*
+ * Release the SCSI I_T Nexus to the emulated vHost Target Port
+ */
+ transport_deregister_session(tv_nexus->tvn_se_sess);
+ tpg->tpg_nexus = NULL;
+
+ kfree(tv_nexus);
+ ret = 0;
+out:
+ mutex_unlock(&tpg->tpg_mutex);
+ return ret;
+}
+
+static ssize_t tcm_usbg_tpg_nexus_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+ unsigned char i_port[USBG_NAMELEN], *ptr;
+ int ret;
+
+ if (!strncmp(page, "NULL", 4)) {
+ ret = tcm_usbg_drop_nexus(tpg);
+ return (!ret) ? count : ret;
+ }
+ if (strlen(page) >= USBG_NAMELEN) {
+
+#define NEXUS_STORE_MSG "Emulated NAA Sas Address: %s, exceeds max: %d\n"
+ pr_err(NEXUS_STORE_MSG, page, USBG_NAMELEN);
+#undef NEXUS_STORE_MSG
+ return -EINVAL;
+ }
+ snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+ ptr = strstr(i_port, "naa.");
+ if (!ptr) {
+ pr_err("Missing 'naa.' prefix\n");
+ return -EINVAL;
+ }
+
+ if (i_port[strlen(i_port) - 1] == '\n')
+ i_port[strlen(i_port) - 1] = '\0';
+
+ ret = tcm_usbg_make_nexus(tpg, &i_port[0]);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+CONFIGFS_ATTR(tcm_usbg_tpg_, enable);
+CONFIGFS_ATTR(tcm_usbg_tpg_, nexus);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+ &tcm_usbg_tpg_attr_enable,
+ &tcm_usbg_tpg_attr_nexus,
+ NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_inc(&tpg->tpg_port_count);
+ smp_mb__after_atomic();
+ return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+ atomic_dec(&tpg->tpg_port_count);
+ smp_mb__after_atomic();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+ se_cmd);
+
+ kref_put(&cmd->ref, usbg_cmd_release);
+ return 1;
+}
+
+static const struct target_core_fabric_ops usbg_ops = {
+ .module = THIS_MODULE,
+ .name = "usb_gadget",
+ .get_fabric_name = usbg_get_fabric_name,
+ .tpg_get_wwn = usbg_get_fabric_wwn,
+ .tpg_get_tag = usbg_get_tag,
+ .tpg_check_demo_mode = usbg_check_true,
+ .tpg_check_demo_mode_cache = usbg_check_false,
+ .tpg_check_demo_mode_write_protect = usbg_check_false,
+ .tpg_check_prod_mode_write_protect = usbg_check_false,
+ .tpg_get_inst_index = usbg_tpg_get_inst_index,
+ .release_cmd = usbg_release_cmd,
+ .shutdown_session = usbg_shutdown_session,
+ .close_session = usbg_close_session,
+ .sess_get_index = usbg_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = usbg_send_write_request,
+ .write_pending_status = usbg_write_pending_status,
+ .set_default_node_attributes = usbg_set_default_node_attrs,
+ .get_cmd_state = usbg_get_cmd_state,
+ .queue_data_in = usbg_send_read_response,
+ .queue_status = usbg_send_status_response,
+ .queue_tm_rsp = usbg_queue_tm_rsp,
+ .aborted_task = usbg_aborted_task,
+ .check_stop_free = usbg_check_stop_free,
+
+ .fabric_make_wwn = usbg_make_tport,
+ .fabric_drop_wwn = usbg_drop_tport,
+ .fabric_make_tpg = usbg_make_tpg,
+ .fabric_drop_tpg = usbg_drop_tpg,
+ .fabric_post_link = usbg_port_link,
+ .fabric_pre_unlink = usbg_port_unlink,
+ .fabric_init_nodeacl = usbg_init_nodeacl,
+
+ .tfc_wwn_attrs = usbg_wwn_attrs,
+ .tfc_tpg_base_attrs = usbg_base_attrs,
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+ .bLength = sizeof(bot_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bAlternateSetting = USB_G_ALT_INT_BBB,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_BULK,
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+ .bLength = sizeof(uasp_intf_desc),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 4,
+ .bAlternateSetting = USB_G_ALT_INT_UAS,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = USB_SC_SCSI,
+ .bInterfaceProtocol = USB_PR_UAS,
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+ .bLength = sizeof(uasp_bi_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+ .bLength = sizeof(uasp_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+ .wBytesPerInterval = 0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+ .bLength = sizeof(bot_bi_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+ .bLength = sizeof(uasp_bo_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+ .bLength = sizeof(uasp_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+ .bLength = sizeof(bot_bo_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+ .bLength = sizeof(uasp_status_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+ .bLength = sizeof(uasp_status_in_ep_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+ .bLength = sizeof(uasp_cmd_pipe_desc),
+ .bDescriptorType = USB_DT_PIPE_USAGE,
+ .bPipeID = CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+ .bLength = sizeof(uasp_cmd_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+ (struct usb_descriptor_header *) &bot_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+ (struct usb_descriptor_header *) &uasp_intf_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+ (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+ (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_status_desc,
+ (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+ (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+ (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+ (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+ NULL,
+};
+
+static struct usb_string tcm_us_strings[] = {
+ [USB_G_STR_INT_UAS].s = "USB Attached SCSI",
+ [USB_G_STR_INT_BBB].s = "Bulk Only Transport",
+ { },
+};
+
+static struct usb_gadget_strings tcm_stringtab = {
+ .language = 0x0409,
+ .strings = tcm_us_strings,
+};
+
+static struct usb_gadget_strings *tcm_strings[] = {
+ &tcm_stringtab,
+ NULL,
+};
+
+static int tcm_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+ struct usb_string *us;
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct usb_ep *ep;
+ struct f_tcm_opts *opts;
+ int iface;
+ int ret;
+
+ opts = container_of(f->fi, struct f_tcm_opts, func_inst);
+
+ mutex_lock(&opts->dep_lock);
+ if (!opts->can_attach) {
+ mutex_unlock(&opts->dep_lock);
+ return -ENODEV;
+ }
+ mutex_unlock(&opts->dep_lock);
+ us = usb_gstrings_attach(c->cdev, tcm_strings,
+ ARRAY_SIZE(tcm_us_strings));
+ if (IS_ERR(us))
+ return PTR_ERR(us);
+ bot_intf_desc.iInterface = us[USB_G_STR_INT_BBB].id;
+ uasp_intf_desc.iInterface = us[USB_G_STR_INT_UAS].id;
+
+ iface = usb_interface_id(c, f);
+ if (iface < 0)
+ return iface;
+
+ bot_intf_desc.bInterfaceNumber = iface;
+ uasp_intf_desc.bInterfaceNumber = iface;
+ fu->iface = iface;
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+ &uasp_bi_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+
+ fu->ep_in = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+ &uasp_bo_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ fu->ep_out = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+ &uasp_status_in_ep_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ fu->ep_status = ep;
+
+ ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+ &uasp_cmd_comp_desc);
+ if (!ep)
+ goto ep_fail;
+ fu->ep_cmd = ep;
+
+ /* Assume endpoint addresses are the same for both speeds */
+ uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+ uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+ uasp_fs_status_desc.bEndpointAddress =
+ uasp_ss_status_desc.bEndpointAddress;
+ uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+ ret = usb_assign_descriptors(f, uasp_fs_function_desc,
+ uasp_hs_function_desc, uasp_ss_function_desc);
+ if (ret)
+ goto ep_fail;
+
+ return 0;
+ep_fail:
+ pr_err("Can't claim all required eps\n");
+
+ return -ENOTSUPP;
+}
+
+struct guas_setup_wq {
+ struct work_struct work;
+ struct f_uas *fu;
+ unsigned int alt;
+};
+
+static void tcm_delayed_set_alt(struct work_struct *wq)
+{
+ struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+ work);
+ struct f_uas *fu = work->fu;
+ int alt = work->alt;
+
+ kfree(work);
+
+ if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+
+ if (alt == USB_G_ALT_INT_BBB)
+ bot_set_alt(fu);
+ else if (alt == USB_G_ALT_INT_UAS)
+ uasp_set_alt(fu);
+ usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int tcm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+ struct guas_setup_wq *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return -ENOMEM;
+ INIT_WORK(&work->work, tcm_delayed_set_alt);
+ work->fu = fu;
+ work->alt = alt;
+ schedule_work(&work->work);
+ return USB_GADGET_DELAYED_STATUS;
+ }
+ return -EOPNOTSUPP;
+}
+
+static void tcm_disable(struct usb_function *f)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (fu->flags & USBG_IS_UAS)
+ uasp_cleanup_old_alt(fu);
+ else if (fu->flags & USBG_IS_BOT)
+ bot_cleanup_old_alt(fu);
+ fu->flags = 0;
+}
+
+static int tcm_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_uas *fu = to_f_uas(f);
+
+ if (!(fu->flags & USBG_IS_BOT))
+ return -EOPNOTSUPP;
+
+ return usbg_bot_setup(f, ctrl);
+}
+
+static inline struct f_tcm_opts *to_f_tcm_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_tcm_opts,
+ func_inst.group);
+}
+
+static void tcm_attr_release(struct config_item *item)
+{
+ struct f_tcm_opts *opts = to_f_tcm_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations tcm_item_ops = {
+ .release = tcm_attr_release,
+};
+
+static struct config_item_type tcm_func_type = {
+ .ct_item_ops = &tcm_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static void tcm_free_inst(struct usb_function_instance *f)
+{
+ struct f_tcm_opts *opts;
+ unsigned i;
+
+ opts = container_of(f, struct f_tcm_opts, func_inst);
+
+ mutex_lock(&tpg_instances_lock);
+ for (i = 0; i < TPG_INSTANCES; ++i)
+ if (tpg_instances[i].func_inst == f)
+ break;
+ if (i < TPG_INSTANCES)
+ tpg_instances[i].func_inst = NULL;
+ mutex_unlock(&tpg_instances_lock);
+
+ kfree(opts);
+}
+
+static int tcm_register_callback(struct usb_function_instance *f)
+{
+ struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+ mutex_lock(&opts->dep_lock);
+ opts->can_attach = true;
+ mutex_unlock(&opts->dep_lock);
+
+ return 0;
+}
+
+static void tcm_unregister_callback(struct usb_function_instance *f)
+{
+ struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+ mutex_lock(&opts->dep_lock);
+ unregister_gadget_item(opts->
+ func_inst.group.cg_item.ci_parent->ci_parent);
+ opts->can_attach = false;
+ mutex_unlock(&opts->dep_lock);
+}
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+ struct usb_function_instance *f = tpg->fi;
+ struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+ if (opts->tcm_register_callback)
+ return opts->tcm_register_callback(f);
+
+ return 0;
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+ struct usb_function_instance *f = tpg->fi;
+ struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+ if (opts->tcm_unregister_callback)
+ opts->tcm_unregister_callback(f);
+}
+
+static int tcm_set_name(struct usb_function_instance *f, const char *name)
+{
+ struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
+
+ pr_debug("tcm: Activating %s\n", name);
+
+ mutex_lock(&opts->dep_lock);
+ opts->ready = true;
+ mutex_unlock(&opts->dep_lock);
+
+ return 0;
+}
+
+static struct usb_function_instance *tcm_alloc_inst(void)
+{
+ struct f_tcm_opts *opts;
+ int i;
+
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&tpg_instances_lock);
+ for (i = 0; i < TPG_INSTANCES; ++i)
+ if (!tpg_instances[i].func_inst)
+ break;
+
+ if (i == TPG_INSTANCES) {
+ mutex_unlock(&tpg_instances_lock);
+ kfree(opts);
+ return ERR_PTR(-EBUSY);
+ }
+ tpg_instances[i].func_inst = &opts->func_inst;
+ mutex_unlock(&tpg_instances_lock);
+
+ mutex_init(&opts->dep_lock);
+ opts->func_inst.set_inst_name = tcm_set_name;
+ opts->func_inst.free_func_inst = tcm_free_inst;
+ opts->tcm_register_callback = tcm_register_callback;
+ opts->tcm_unregister_callback = tcm_unregister_callback;
+
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &tcm_func_type);
+
+ return &opts->func_inst;
+}
+
+static void tcm_free(struct usb_function *f)
+{
+ struct f_uas *tcm = to_f_uas(f);
+
+ kfree(tcm);
+}
+
+static void tcm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ usb_free_all_descriptors(f);
+}
+
+static struct usb_function *tcm_alloc(struct usb_function_instance *fi)
+{
+ struct f_uas *fu;
+ unsigned i;
+
+ mutex_lock(&tpg_instances_lock);
+ for (i = 0; i < TPG_INSTANCES; ++i)
+ if (tpg_instances[i].func_inst == fi)
+ break;
+ if (i == TPG_INSTANCES) {
+ mutex_unlock(&tpg_instances_lock);
+ return ERR_PTR(-ENODEV);
+ }
+
+ fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+ if (!fu) {
+ mutex_unlock(&tpg_instances_lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ fu->function.name = "Target Function";
+ fu->function.bind = tcm_bind;
+ fu->function.unbind = tcm_unbind;
+ fu->function.set_alt = tcm_set_alt;
+ fu->function.setup = tcm_setup;
+ fu->function.disable = tcm_disable;
+ fu->function.free_func = tcm_free;
+ fu->tpg = tpg_instances[i].tpg;
+ mutex_unlock(&tpg_instances_lock);
+
+ return &fu->function;
+}
+
+DECLARE_USB_FUNCTION(tcm, tcm_alloc_inst, tcm_alloc);
+
+static int tcm_init(void)
+{
+ int ret;
+
+ ret = usb_function_register(&tcmusb_func);
+ if (ret)
+ return ret;
+
+ ret = target_register_template(&usbg_ops);
+ if (ret)
+ usb_function_unregister(&tcmusb_func);
+
+ return ret;
+}
+module_init(tcm_init);
+
+static void tcm_exit(void)
+{
+ target_unregister_template(&usbg_ops);
+ usb_function_unregister(&tcmusb_func);
+}
+module_exit(tcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sebastian Andrzej Siewior");
diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h
index 15f180904f8a..492924d0d599 100644
--- a/drivers/usb/gadget/function/g_zero.h
+++ b/drivers/usb/gadget/function/g_zero.h
@@ -10,6 +10,8 @@
#define GZERO_QLEN 32
#define GZERO_ISOC_INTERVAL 4
#define GZERO_ISOC_MAXPACKET 1024
+#define GZERO_SS_BULK_QLEN 1
+#define GZERO_SS_ISO_QLEN 8
struct usb_zero_options {
unsigned pattern;
@@ -19,6 +21,8 @@ struct usb_zero_options {
unsigned isoc_maxburst;
unsigned bulk_buflen;
unsigned qlen;
+ unsigned ss_bulk_qlen;
+ unsigned ss_iso_qlen;
};
struct f_ss_opts {
@@ -29,6 +33,8 @@ struct f_ss_opts {
unsigned isoc_mult;
unsigned isoc_maxburst;
unsigned bulk_buflen;
+ unsigned bulk_qlen;
+ unsigned iso_qlen;
/*
* Read/write access to configfs attributes is handled by configfs.
@@ -59,7 +65,6 @@ void lb_modexit(void);
int lb_modinit(void);
/* common utilities */
-void free_ep_req(struct usb_ep *ep, struct usb_request *req);
void disable_endpoints(struct usb_composite_dev *cdev,
struct usb_ep *in, struct usb_ep *out,
struct usb_ep *iso_in, struct usb_ep *iso_out);
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.h b/drivers/usb/gadget/function/tcm.h
index 0b749e1aa2f1..b75c6f3e1980 100644
--- a/drivers/usb/gadget/legacy/tcm_usb_gadget.h
+++ b/drivers/usb/gadget/function/tcm.h
@@ -16,8 +16,7 @@
#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
enum {
- USB_G_STR_CONFIG = USB_GADGET_FIRST_AVAIL_IDX,
- USB_G_STR_INT_UAS,
+ USB_G_STR_INT_UAS = 0,
USB_G_STR_INT_BBB,
};
@@ -40,6 +39,8 @@ struct usbg_tpg {
u32 gadget_connect;
struct tcm_usbg_nexus *tpg_nexus;
atomic_t tpg_port_count;
+
+ struct usb_function_instance *fi;
};
struct usbg_tport {
@@ -128,6 +129,4 @@ struct f_uas {
struct usb_request *bot_req_out;
};
-extern struct usbg_tpg *the_only_tpg_I_currently_have;
-
-#endif
+#endif /* __TARGET_USB_GADGET_H__ */
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 6554322af2c1..637809e3bd0d 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -143,21 +143,11 @@ static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
static int ueth_change_mtu(struct net_device *net, int new_mtu)
{
- struct eth_dev *dev = netdev_priv(net);
- unsigned long flags;
- int status = 0;
+ if (new_mtu <= ETH_HLEN || new_mtu > GETHER_MAX_ETH_FRAME_LEN)
+ return -ERANGE;
+ net->mtu = new_mtu;
- /* don't change MTU on "live" link (peer won't know) */
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb)
- status = -EBUSY;
- else if (new_mtu <= ETH_HLEN || new_mtu > GETHER_MAX_ETH_FRAME_LEN)
- status = -ERANGE;
- else
- net->mtu = new_mtu;
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return status;
+ return 0;
}
static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index f7771d86ad6c..6af145f2a99d 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -27,6 +27,8 @@
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/kthread.h>
#include "u_serial.h"
@@ -79,6 +81,7 @@
*/
#define QUEUE_SIZE 16
#define WRITE_BUF_SIZE 8192 /* TX only */
+#define GS_CONSOLE_BUF_SIZE 8192
/* circular buffer */
struct gs_buf {
@@ -88,6 +91,17 @@ struct gs_buf {
char *buf_put;
};
+/* console info */
+struct gscons_info {
+ struct gs_port *port;
+ struct task_struct *console_thread;
+ struct gs_buf con_buf;
+ /* protect the buf and busy flag */
+ spinlock_t con_lock;
+ int req_busy;
+ struct usb_request *console_req;
+};
+
/*
* The port structure holds info for each port, one for each minor number
* (and thus for each /dev/ node).
@@ -1023,6 +1037,246 @@ static const struct tty_operations gs_tty_ops = {
static struct tty_driver *gs_tty_driver;
+#ifdef CONFIG_U_SERIAL_CONSOLE
+
+static struct gscons_info gscons_info;
+static struct console gserial_cons;
+
+static struct usb_request *gs_request_new(struct usb_ep *ep)
+{
+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (!req)
+ return NULL;
+
+ req->buf = kmalloc(ep->maxpacket, GFP_ATOMIC);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+
+ return req;
+}
+
+static void gs_request_free(struct usb_request *req, struct usb_ep *ep)
+{
+ if (!req)
+ return;
+
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
+{
+ struct gscons_info *info = &gscons_info;
+
+ switch (req->status) {
+ default:
+ pr_warn("%s: unexpected %s status %d\n",
+ __func__, ep->name, req->status);
+ case 0:
+ /* normal completion */
+ spin_lock(&info->con_lock);
+ info->req_busy = 0;
+ spin_unlock(&info->con_lock);
+
+ wake_up_process(info->console_thread);
+ break;
+ case -ESHUTDOWN:
+ /* disconnect */
+ pr_vdebug("%s: %s shutdown\n", __func__, ep->name);
+ break;
+ }
+}
+
+static int gs_console_connect(int port_num)
+{
+ struct gscons_info *info = &gscons_info;
+ struct gs_port *port;
+ struct usb_ep *ep;
+
+ if (port_num != gserial_cons.index) {
+ pr_err("%s: port num [%d] is not support console\n",
+ __func__, port_num);
+ return -ENXIO;
+ }
+
+ port = ports[port_num].port;
+ ep = port->port_usb->in;
+ if (!info->console_req) {
+ info->console_req = gs_request_new(ep);
+ if (!info->console_req)
+ return -ENOMEM;
+ info->console_req->complete = gs_complete_out;
+ }
+
+ info->port = port;
+ spin_lock(&info->con_lock);
+ info->req_busy = 0;
+ spin_unlock(&info->con_lock);
+ pr_vdebug("port[%d] console connect!\n", port_num);
+ return 0;
+}
+
+static void gs_console_disconnect(struct usb_ep *ep)
+{
+ struct gscons_info *info = &gscons_info;
+ struct usb_request *req = info->console_req;
+
+ gs_request_free(req, ep);
+ info->console_req = NULL;
+}
+
+static int gs_console_thread(void *data)
+{
+ struct gscons_info *info = &gscons_info;
+ struct gs_port *port;
+ struct usb_request *req;
+ struct usb_ep *ep;
+ int xfer, ret, count, size;
+
+ do {
+ port = info->port;
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!port || !port->port_usb
+ || !port->port_usb->in || !info->console_req)
+ goto sched;
+
+ req = info->console_req;
+ ep = port->port_usb->in;
+
+ spin_lock_irq(&info->con_lock);
+ count = gs_buf_data_avail(&info->con_buf);
+ size = ep->maxpacket;
+
+ if (count > 0 && !info->req_busy) {
+ set_current_state(TASK_RUNNING);
+ if (count < size)
+ size = count;
+
+ xfer = gs_buf_get(&info->con_buf, req->buf, size);
+ req->length = xfer;
+
+ spin_unlock(&info->con_lock);
+ ret = usb_ep_queue(ep, req, GFP_ATOMIC);
+ spin_lock(&info->con_lock);
+ if (ret < 0)
+ info->req_busy = 0;
+ else
+ info->req_busy = 1;
+
+ spin_unlock_irq(&info->con_lock);
+ } else {
+ spin_unlock_irq(&info->con_lock);
+sched:
+ if (kthread_should_stop()) {
+ set_current_state(TASK_RUNNING);
+ break;
+ }
+ schedule();
+ }
+ } while (1);
+
+ return 0;
+}
+
+static int gs_console_setup(struct console *co, char *options)
+{
+ struct gscons_info *info = &gscons_info;
+ int status;
+
+ info->port = NULL;
+ info->console_req = NULL;
+ info->req_busy = 0;
+ spin_lock_init(&info->con_lock);
+
+ status = gs_buf_alloc(&info->con_buf, GS_CONSOLE_BUF_SIZE);
+ if (status) {
+ pr_err("%s: allocate console buffer failed\n", __func__);
+ return status;
+ }
+
+ info->console_thread = kthread_create(gs_console_thread,
+ co, "gs_console");
+ if (IS_ERR(info->console_thread)) {
+ pr_err("%s: cannot create console thread\n", __func__);
+ gs_buf_free(&info->con_buf);
+ return PTR_ERR(info->console_thread);
+ }
+ wake_up_process(info->console_thread);
+
+ return 0;
+}
+
+static void gs_console_write(struct console *co,
+ const char *buf, unsigned count)
+{
+ struct gscons_info *info = &gscons_info;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->con_lock, flags);
+ gs_buf_put(&info->con_buf, buf, count);
+ spin_unlock_irqrestore(&info->con_lock, flags);
+
+ wake_up_process(info->console_thread);
+}
+
+static struct tty_driver *gs_console_device(struct console *co, int *index)
+{
+ struct tty_driver **p = (struct tty_driver **)co->data;
+
+ if (!*p)
+ return NULL;
+
+ *index = co->index;
+ return *p;
+}
+
+static struct console gserial_cons = {
+ .name = "ttyGS",
+ .write = gs_console_write,
+ .device = gs_console_device,
+ .setup = gs_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &gs_tty_driver,
+};
+
+static void gserial_console_init(void)
+{
+ register_console(&gserial_cons);
+}
+
+static void gserial_console_exit(void)
+{
+ struct gscons_info *info = &gscons_info;
+
+ unregister_console(&gserial_cons);
+ kthread_stop(info->console_thread);
+ gs_buf_free(&info->con_buf);
+}
+
+#else
+
+static int gs_console_connect(int port_num)
+{
+ return 0;
+}
+
+static void gs_console_disconnect(struct usb_ep *ep)
+{
+}
+
+static void gserial_console_init(void)
+{
+}
+
+static void gserial_console_exit(void)
+{
+}
+
+#endif
+
static int
gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
{
@@ -1096,6 +1350,7 @@ void gserial_free_line(unsigned char port_num)
gserial_free_port(port);
tty_unregister_device(gs_tty_driver, port_num);
+ gserial_console_exit();
}
EXPORT_SYMBOL_GPL(gserial_free_line);
@@ -1138,6 +1393,7 @@ int gserial_alloc_line(unsigned char *line_num)
goto err;
}
*line_num = port_num;
+ gserial_console_init();
err:
return ret;
}
@@ -1219,6 +1475,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
gser->disconnect(gser);
}
+ status = gs_console_connect(port_num);
spin_unlock_irqrestore(&port->port_lock, flags);
return status;
@@ -1277,6 +1534,7 @@ void gserial_disconnect(struct gserial *gser)
port->read_allocated = port->read_started =
port->write_allocated = port->write_started = 0;
+ gs_console_disconnect(gser->in);
spin_unlock_irqrestore(&port->port_lock, flags);
}
EXPORT_SYMBOL_GPL(gserial_disconnect);
diff --git a/drivers/usb/gadget/function/u_tcm.h b/drivers/usb/gadget/function/u_tcm.h
new file mode 100644
index 000000000000..0bd751e0483f
--- /dev/null
+++ b/drivers/usb/gadget/function/u_tcm.h
@@ -0,0 +1,50 @@
+/*
+ * u_tcm.h
+ *
+ * Utility definitions for the tcm function
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
+ *
+ * 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 U_TCM_H
+#define U_TCM_H
+
+#include <linux/usb/composite.h>
+
+/**
+ * @dependent: optional dependent module. Meant for legacy gadget.
+ * If non-null its refcount will be increased when a tpg is created and
+ * decreased when tpg is dropped.
+ * @dep_lock: lock for dependent module operations.
+ * @ready: true if the dependent module information is set.
+ * @can_attach: true a function can be bound to gadget
+ * @has_dep: true if there is a dependent module
+ *
+ */
+struct f_tcm_opts {
+ struct usb_function_instance func_inst;
+ struct module *dependent;
+ struct mutex dep_lock;
+ bool ready;
+ bool can_attach;
+ bool has_dep;
+
+ /*
+ * Callbacks to be removed when legacy tcm gadget disappears.
+ *
+ * If you use the new function registration interface
+ * programmatically, you MUST set these callbacks to
+ * something sensible (e.g. probe/remove the composite).
+ */
+ int (*tcm_register_callback)(struct usb_function_instance *);
+ void (*tcm_unregister_callback)(struct usb_function_instance *);
+};
+
+#endif /* U_TCM_H */
diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
index 4d682ad7bf23..a23d1b90454c 100644
--- a/drivers/usb/gadget/legacy/Kconfig
+++ b/drivers/usb/gadget/legacy/Kconfig
@@ -250,6 +250,7 @@ config USB_GADGET_TARGET
tristate "USB Gadget Target Fabric Module"
depends on TARGET_CORE
select USB_LIBCOMPOSITE
+ select USB_F_TCM
help
This fabric is an USB gadget. Two USB protocols are supported that is
BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c
index 4b158e2d1e57..c16089efc322 100644
--- a/drivers/usb/gadget/legacy/acm_ms.c
+++ b/drivers/usb/gadget/legacy/acm_ms.c
@@ -40,7 +40,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_MISC /* 0xEF */,
.bDeviceSubClass = 2,
diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c
index 685cf3b4b78f..5d7b3c6a422b 100644
--- a/drivers/usb/gadget/legacy/audio.c
+++ b/drivers/usb/gadget/legacy/audio.c
@@ -123,7 +123,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x200),
+ /* .bcdUSB = DYNAMIC */
#ifdef CONFIG_GADGET_UAC1
.bDeviceClass = USB_CLASS_PER_INTERFACE,
diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c
index ecd8c8d62f2e..51c08682de84 100644
--- a/drivers/usb/gadget/legacy/cdc2.c
+++ b/drivers/usb/gadget/legacy/cdc2.c
@@ -43,7 +43,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_COMM,
.bDeviceSubClass = 0,
diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c
index 31e9160223e9..25a2c2e48592 100644
--- a/drivers/usb/gadget/legacy/ether.c
+++ b/drivers/usb/gadget/legacy/ether.c
@@ -151,7 +151,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16 (0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_COMM,
.bDeviceSubClass = 0,
diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c
index 320a81b2baa6..f85639ef8a8f 100644
--- a/drivers/usb/gadget/legacy/g_ffs.c
+++ b/drivers/usb/gadget/legacy/g_ffs.c
@@ -69,7 +69,7 @@ static struct usb_device_descriptor gfs_dev_desc = {
.bLength = sizeof gfs_dev_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.idVendor = cpu_to_le16(GFS_VENDOR_ID),
diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c
index 8a18348ae86e..fc2ac150f5ff 100644
--- a/drivers/usb/gadget/legacy/gmidi.c
+++ b/drivers/usb/gadget/legacy/gmidi.c
@@ -21,19 +21,12 @@
/* #define VERBOSE_DEBUG */
#include <linux/kernel.h>
-#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
#include <sound/initval.h>
-#include <sound/rawmidi.h>
-#include <linux/usb/ch9.h>
#include <linux/usb/composite.h>
#include <linux/usb/gadget.h>
-#include <linux/usb/audio.h>
-#include <linux/usb/midi.h>
#include "u_midi.h"
@@ -42,7 +35,6 @@
MODULE_AUTHOR("Ben Williamson");
MODULE_LICENSE("GPL v2");
-static const char shortname[] = "g_midi";
static const char longname[] = "MIDI Gadget";
USB_GADGET_COMPOSITE_OPTIONS();
@@ -61,7 +53,7 @@ MODULE_PARM_DESC(buflen, "MIDI buffer length");
static unsigned int qlen = 32;
module_param(qlen, uint, S_IRUGO);
-MODULE_PARM_DESC(qlen, "USB read request queue length");
+MODULE_PARM_DESC(qlen, "USB read and write request queue length");
static unsigned int in_ports = 1;
module_param(in_ports, uint, S_IRUGO);
@@ -86,7 +78,7 @@ MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
static struct usb_device_descriptor device_desc = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
index 7e5d2c48476e..a71a884f79fc 100644
--- a/drivers/usb/gadget/legacy/hid.c
+++ b/drivers/usb/gadget/legacy/hid.c
@@ -47,7 +47,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
/* .bDeviceClass = USB_CLASS_COMM, */
/* .bDeviceSubClass = 0, */
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index f454c7af489c..365afd7e14f8 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1137,10 +1137,9 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
dev->gadget->ep0, dev->req,
GFP_KERNEL);
}
+ spin_lock_irq(&dev->lock);
if (retval < 0) {
- spin_lock_irq (&dev->lock);
clean_req (dev->gadget->ep0, dev->req);
- spin_unlock_irq (&dev->lock);
} else
retval = len;
diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c
index bda3c519110f..e61af53c7d2b 100644
--- a/drivers/usb/gadget/legacy/mass_storage.c
+++ b/drivers/usb/gadget/legacy/mass_storage.c
@@ -55,7 +55,7 @@ static struct usb_device_descriptor msg_device_desc = {
.bLength = sizeof msg_device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_PER_INTERFACE,
/* Vendor and product id can be overridden by module parameters. */
diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c
index 4fe794ddcd49..229d704a620b 100644
--- a/drivers/usb/gadget/legacy/multi.c
+++ b/drivers/usb/gadget/legacy/multi.c
@@ -67,7 +67,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_MISC /* 0xEF */,
.bDeviceSubClass = 2,
diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c
index 2bae4381332d..0aba68253e3d 100644
--- a/drivers/usb/gadget/legacy/ncm.c
+++ b/drivers/usb/gadget/legacy/ncm.c
@@ -49,7 +49,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16 (0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_COMM,
.bDeviceSubClass = 0,
diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c
index 8b3f6fb1825d..09975046c694 100644
--- a/drivers/usb/gadget/legacy/nokia.c
+++ b/drivers/usb/gadget/legacy/nokia.c
@@ -89,7 +89,7 @@ static struct usb_gadget_strings *dev_strings[] = {
static struct usb_device_descriptor device_desc = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_COMM,
.idVendor = cpu_to_le16(NOKIA_VENDOR_ID),
.idProduct = cpu_to_le16(NOKIA_PRODUCT_ID),
diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c
index a22d30a4def1..6f969a86175c 100644
--- a/drivers/usb/gadget/legacy/printer.c
+++ b/drivers/usb/gadget/legacy/printer.c
@@ -71,7 +71,7 @@ static struct usb_function *f_printer;
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c
index c5d42e0347a9..9d89adce756d 100644
--- a/drivers/usb/gadget/legacy/serial.c
+++ b/drivers/usb/gadget/legacy/serial.c
@@ -65,7 +65,7 @@ static struct usb_gadget_strings *dev_strings[] = {
static struct usb_device_descriptor device_desc = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
/* .bDeviceClass = f(use_acm) */
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
index 22e56158d585..0b0bb98319cd 100644
--- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
@@ -21,1973 +21,30 @@
#include <target/target_core_fabric.h>
#include <asm/unaligned.h>
-#include "tcm_usb_gadget.h"
+#include "u_tcm.h"
USB_GADGET_COMPOSITE_OPTIONS();
-static inline struct f_uas *to_f_uas(struct usb_function *f)
-{
- return container_of(f, struct f_uas, function);
-}
-
-static void usbg_cmd_release(struct kref *);
-
-static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
-{
- kref_put(&cmd->ref, usbg_cmd_release);
-}
-
-/* Start bot.c code */
-
-static int bot_enqueue_cmd_cbw(struct f_uas *fu)
-{
- int ret;
-
- if (fu->flags & USBG_BOT_CMD_PEND)
- return 0;
-
- ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
- if (!ret)
- fu->flags |= USBG_BOT_CMD_PEND;
- return ret;
-}
-
-static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct f_uas *fu = cmd->fu;
-
- usbg_cleanup_cmd(cmd);
- if (req->status < 0) {
- pr_err("ERR %s(%d)\n", __func__, __LINE__);
- return;
- }
-
- /* CSW completed, wait for next CBW */
- bot_enqueue_cmd_cbw(fu);
-}
-
-static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
-{
- struct bulk_cs_wrap *csw = &fu->bot_status.csw;
- int ret;
- u8 *sense;
- unsigned int csw_stat;
-
- csw_stat = cmd->csw_code;
-
- /*
- * We can't send SENSE as a response. So we take ASC & ASCQ from our
- * sense buffer and queue it and hope the host sends a REQUEST_SENSE
- * command where it learns why we failed.
- */
- sense = cmd->sense_iu.sense;
-
- csw->Tag = cmd->bot_tag;
- csw->Status = csw_stat;
- fu->bot_status.req->context = cmd;
- ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
-}
-
-static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct f_uas *fu = cmd->fu;
-
- if (req->status < 0)
- pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
- if (cmd->data_len) {
- if (cmd->data_len > ep->maxpacket) {
- req->length = ep->maxpacket;
- cmd->data_len -= ep->maxpacket;
- } else {
- req->length = cmd->data_len;
- cmd->data_len = 0;
- }
-
- usb_ep_queue(ep, req, GFP_ATOMIC);
- return ;
- }
- bot_enqueue_sense_code(fu, cmd);
-}
-
-static void bot_send_bad_status(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct bulk_cs_wrap *csw = &fu->bot_status.csw;
- struct usb_request *req;
- struct usb_ep *ep;
-
- csw->Residue = cpu_to_le32(cmd->data_len);
-
- if (cmd->data_len) {
- if (cmd->is_read) {
- ep = fu->ep_in;
- req = fu->bot_req_in;
- } else {
- ep = fu->ep_out;
- req = fu->bot_req_out;
- }
-
- if (cmd->data_len > fu->ep_in->maxpacket) {
- req->length = ep->maxpacket;
- cmd->data_len -= ep->maxpacket;
- } else {
- req->length = cmd->data_len;
- cmd->data_len = 0;
- }
- req->complete = bot_err_compl;
- req->context = cmd;
- req->buf = fu->cmd.buf;
- usb_ep_queue(ep, req, GFP_KERNEL);
- } else {
- bot_enqueue_sense_code(fu, cmd);
- }
-}
-
-static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
-{
- struct f_uas *fu = cmd->fu;
- struct bulk_cs_wrap *csw = &fu->bot_status.csw;
- int ret;
-
- if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
- if (!moved_data && cmd->data_len) {
- /*
- * the host wants to move data, we don't. Fill / empty
- * the pipe and then send the csw with reside set.
- */
- cmd->csw_code = US_BULK_STAT_OK;
- bot_send_bad_status(cmd);
- return 0;
- }
-
- csw->Tag = cmd->bot_tag;
- csw->Residue = cpu_to_le32(0);
- csw->Status = US_BULK_STAT_OK;
- fu->bot_status.req->context = cmd;
-
- ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
- if (ret)
- pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
- } else {
- cmd->csw_code = US_BULK_STAT_FAIL;
- bot_send_bad_status(cmd);
- }
- return 0;
-}
-
-/*
- * Called after command (no data transfer) or after the write (to device)
- * operation is completed
- */
-static int bot_send_status_response(struct usbg_cmd *cmd)
-{
- bool moved_data = false;
-
- if (!cmd->is_read)
- moved_data = true;
- return bot_send_status(cmd, moved_data);
-}
-
-/* Read request completed, now we have to send the CSW */
-static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
-
- if (req->status < 0)
- pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
- bot_send_status(cmd, true);
-}
-
-static int bot_send_read_response(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
- int ret;
-
- if (!cmd->data_len) {
- cmd->csw_code = US_BULK_STAT_PHASE;
- bot_send_bad_status(cmd);
- return 0;
- }
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- sg_copy_to_buffer(se_cmd->t_data_sg,
- se_cmd->t_data_nents,
- cmd->data_buf,
- se_cmd->data_length);
-
- fu->bot_req_in->buf = cmd->data_buf;
- } else {
- fu->bot_req_in->buf = NULL;
- fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
- fu->bot_req_in->sg = se_cmd->t_data_sg;
- }
-
- fu->bot_req_in->complete = bot_read_compl;
- fu->bot_req_in->length = se_cmd->data_length;
- fu->bot_req_in->context = cmd;
- ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
- return 0;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
-static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
-
-static int bot_send_write_request(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
- int ret;
-
- init_completion(&cmd->write_complete);
- cmd->fu = fu;
-
- if (!cmd->data_len) {
- cmd->csw_code = US_BULK_STAT_PHASE;
- return -EINVAL;
- }
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- fu->bot_req_out->buf = cmd->data_buf;
- } else {
- fu->bot_req_out->buf = NULL;
- fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
- fu->bot_req_out->sg = se_cmd->t_data_sg;
- }
-
- fu->bot_req_out->complete = usbg_data_write_cmpl;
- fu->bot_req_out->length = se_cmd->data_length;
- fu->bot_req_out->context = cmd;
-
- ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
-
- wait_for_completion(&cmd->write_complete);
- target_execute_cmd(se_cmd);
-cleanup:
- return ret;
-}
-
-static int bot_submit_command(struct f_uas *, void *, unsigned int);
-
-static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_uas *fu = req->context;
- int ret;
-
- fu->flags &= ~USBG_BOT_CMD_PEND;
-
- if (req->status < 0)
- return;
-
- ret = bot_submit_command(fu, req->buf, req->actual);
- if (ret)
- pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
-}
-
-static int bot_prepare_reqs(struct f_uas *fu)
-{
- int ret;
-
- fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
- if (!fu->bot_req_in)
- goto err;
-
- fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
- if (!fu->bot_req_out)
- goto err_out;
-
- fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
- if (!fu->cmd.req)
- goto err_cmd;
-
- fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
- if (!fu->bot_status.req)
- goto err_sts;
-
- fu->bot_status.req->buf = &fu->bot_status.csw;
- fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
- fu->bot_status.req->complete = bot_status_complete;
- fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
-
- fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
- if (!fu->cmd.buf)
- goto err_buf;
-
- fu->cmd.req->complete = bot_cmd_complete;
- fu->cmd.req->buf = fu->cmd.buf;
- fu->cmd.req->length = fu->ep_out->maxpacket;
- fu->cmd.req->context = fu;
-
- ret = bot_enqueue_cmd_cbw(fu);
- if (ret)
- goto err_queue;
- return 0;
-err_queue:
- kfree(fu->cmd.buf);
- fu->cmd.buf = NULL;
-err_buf:
- usb_ep_free_request(fu->ep_in, fu->bot_status.req);
-err_sts:
- usb_ep_free_request(fu->ep_out, fu->cmd.req);
- fu->cmd.req = NULL;
-err_cmd:
- usb_ep_free_request(fu->ep_out, fu->bot_req_out);
- fu->bot_req_out = NULL;
-err_out:
- usb_ep_free_request(fu->ep_in, fu->bot_req_in);
- fu->bot_req_in = NULL;
-err:
- pr_err("BOT: endpoint setup failed\n");
- return -ENOMEM;
-}
-
-static void bot_cleanup_old_alt(struct f_uas *fu)
-{
- if (!(fu->flags & USBG_ENABLED))
- return;
-
- usb_ep_disable(fu->ep_in);
- usb_ep_disable(fu->ep_out);
-
- if (!fu->bot_req_in)
- return;
-
- usb_ep_free_request(fu->ep_in, fu->bot_req_in);
- usb_ep_free_request(fu->ep_out, fu->bot_req_out);
- usb_ep_free_request(fu->ep_out, fu->cmd.req);
- usb_ep_free_request(fu->ep_out, fu->bot_status.req);
-
- kfree(fu->cmd.buf);
-
- fu->bot_req_in = NULL;
- fu->bot_req_out = NULL;
- fu->cmd.req = NULL;
- fu->bot_status.req = NULL;
- fu->cmd.buf = NULL;
-}
-
-static void bot_set_alt(struct f_uas *fu)
-{
- struct usb_function *f = &fu->function;
- struct usb_gadget *gadget = f->config->cdev->gadget;
- int ret;
-
- fu->flags = USBG_IS_BOT;
-
- config_ep_by_speed(gadget, f, fu->ep_in);
- ret = usb_ep_enable(fu->ep_in);
- if (ret)
- goto err_b_in;
-
- config_ep_by_speed(gadget, f, fu->ep_out);
- ret = usb_ep_enable(fu->ep_out);
- if (ret)
- goto err_b_out;
-
- ret = bot_prepare_reqs(fu);
- if (ret)
- goto err_wq;
- fu->flags |= USBG_ENABLED;
- pr_info("Using the BOT protocol\n");
- return;
-err_wq:
- usb_ep_disable(fu->ep_out);
-err_b_out:
- usb_ep_disable(fu->ep_in);
-err_b_in:
- fu->flags = USBG_IS_BOT;
-}
-
-static int usbg_bot_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
-{
- struct f_uas *fu = to_f_uas(f);
- struct usb_composite_dev *cdev = f->config->cdev;
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
- int luns;
- u8 *ret_lun;
-
- switch (ctrl->bRequest) {
- case US_BULK_GET_MAX_LUN:
- if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE))
- return -ENOTSUPP;
-
- if (w_length < 1)
- return -EINVAL;
- if (w_value != 0)
- return -EINVAL;
- luns = atomic_read(&fu->tpg->tpg_port_count);
- if (!luns) {
- pr_err("No LUNs configured?\n");
- return -EINVAL;
- }
- /*
- * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
- * accessed. The upper limit is 0xf
- */
- luns--;
- if (luns > 0xf) {
- pr_info_once("Limiting the number of luns to 16\n");
- luns = 0xf;
- }
- ret_lun = cdev->req->buf;
- *ret_lun = luns;
- cdev->req->length = 1;
- return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
- break;
-
- case US_BULK_RESET_REQUEST:
- /* XXX maybe we should remove previous requests for IN + OUT */
- bot_enqueue_cmd_cbw(fu);
- return 0;
- break;
- }
- return -ENOTSUPP;
-}
-
-/* Start uas.c code */
-
-static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
-{
- /* We have either all three allocated or none */
- if (!stream->req_in)
- return;
-
- usb_ep_free_request(fu->ep_in, stream->req_in);
- usb_ep_free_request(fu->ep_out, stream->req_out);
- usb_ep_free_request(fu->ep_status, stream->req_status);
-
- stream->req_in = NULL;
- stream->req_out = NULL;
- stream->req_status = NULL;
-}
-
-static void uasp_free_cmdreq(struct f_uas *fu)
-{
- usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
- kfree(fu->cmd.buf);
- fu->cmd.req = NULL;
- fu->cmd.buf = NULL;
-}
-
-static void uasp_cleanup_old_alt(struct f_uas *fu)
-{
- int i;
-
- if (!(fu->flags & USBG_ENABLED))
- return;
-
- usb_ep_disable(fu->ep_in);
- usb_ep_disable(fu->ep_out);
- usb_ep_disable(fu->ep_status);
- usb_ep_disable(fu->ep_cmd);
-
- for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
- uasp_cleanup_one_stream(fu, &fu->stream[i]);
- uasp_free_cmdreq(fu);
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
-
-static int uasp_prepare_r_request(struct usbg_cmd *cmd)
-{
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct f_uas *fu = cmd->fu;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
- struct uas_stream *stream = cmd->stream;
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- sg_copy_to_buffer(se_cmd->t_data_sg,
- se_cmd->t_data_nents,
- cmd->data_buf,
- se_cmd->data_length);
-
- stream->req_in->buf = cmd->data_buf;
- } else {
- stream->req_in->buf = NULL;
- stream->req_in->num_sgs = se_cmd->t_data_nents;
- stream->req_in->sg = se_cmd->t_data_sg;
- }
-
- stream->req_in->complete = uasp_status_data_cmpl;
- stream->req_in->length = se_cmd->data_length;
- stream->req_in->context = cmd;
-
- cmd->state = UASP_SEND_STATUS;
- return 0;
-}
-
-static void uasp_prepare_status(struct usbg_cmd *cmd)
-{
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct sense_iu *iu = &cmd->sense_iu;
- struct uas_stream *stream = cmd->stream;
-
- cmd->state = UASP_QUEUE_COMMAND;
- iu->iu_id = IU_ID_STATUS;
- iu->tag = cpu_to_be16(cmd->tag);
-
- /*
- * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
- */
- iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
- iu->status = se_cmd->scsi_status;
- stream->req_status->context = cmd;
- stream->req_status->length = se_cmd->scsi_sense_length + 16;
- stream->req_status->buf = iu;
- stream->req_status->complete = uasp_status_data_cmpl;
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct uas_stream *stream = cmd->stream;
- struct f_uas *fu = cmd->fu;
- int ret;
-
- if (req->status < 0)
- goto cleanup;
-
- switch (cmd->state) {
- case UASP_SEND_DATA:
- ret = uasp_prepare_r_request(cmd);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- break;
-
- case UASP_RECEIVE_DATA:
- ret = usbg_prepare_w_request(cmd, stream->req_out);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- break;
-
- case UASP_SEND_STATUS:
- uasp_prepare_status(cmd);
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- break;
-
- case UASP_QUEUE_COMMAND:
- usbg_cleanup_cmd(cmd);
- usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
- break;
-
- default:
- BUG();
- }
- return;
-
-cleanup:
- usbg_cleanup_cmd(cmd);
-}
-
-static int uasp_send_status_response(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct uas_stream *stream = cmd->stream;
- struct sense_iu *iu = &cmd->sense_iu;
-
- iu->tag = cpu_to_be16(cmd->tag);
- stream->req_status->complete = uasp_status_data_cmpl;
- stream->req_status->context = cmd;
- cmd->fu = fu;
- uasp_prepare_status(cmd);
- return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
-}
-
-static int uasp_send_read_response(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct uas_stream *stream = cmd->stream;
- struct sense_iu *iu = &cmd->sense_iu;
- int ret;
-
- cmd->fu = fu;
-
- iu->tag = cpu_to_be16(cmd->tag);
- if (fu->flags & USBG_USE_STREAMS) {
-
- ret = uasp_prepare_r_request(cmd);
- if (ret)
- goto out;
- ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
- if (ret) {
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- kfree(cmd->data_buf);
- cmd->data_buf = NULL;
- }
-
- } else {
-
- iu->iu_id = IU_ID_READ_READY;
- iu->tag = cpu_to_be16(cmd->tag);
-
- stream->req_status->complete = uasp_status_data_cmpl;
- stream->req_status->context = cmd;
-
- cmd->state = UASP_SEND_DATA;
- stream->req_status->buf = iu;
- stream->req_status->length = sizeof(struct iu);
-
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
- }
-out:
- return ret;
-}
-
-static int uasp_send_write_request(struct usbg_cmd *cmd)
-{
- struct f_uas *fu = cmd->fu;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct uas_stream *stream = cmd->stream;
- struct sense_iu *iu = &cmd->sense_iu;
- int ret;
-
- init_completion(&cmd->write_complete);
- cmd->fu = fu;
-
- iu->tag = cpu_to_be16(cmd->tag);
-
- if (fu->flags & USBG_USE_STREAMS) {
-
- ret = usbg_prepare_w_request(cmd, stream->req_out);
- if (ret)
- goto cleanup;
- ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
-
- } else {
-
- iu->iu_id = IU_ID_WRITE_READY;
- iu->tag = cpu_to_be16(cmd->tag);
-
- stream->req_status->complete = uasp_status_data_cmpl;
- stream->req_status->context = cmd;
-
- cmd->state = UASP_RECEIVE_DATA;
- stream->req_status->buf = iu;
- stream->req_status->length = sizeof(struct iu);
-
- ret = usb_ep_queue(fu->ep_status, stream->req_status,
- GFP_ATOMIC);
- if (ret)
- pr_err("%s(%d)\n", __func__, __LINE__);
- }
-
- wait_for_completion(&cmd->write_complete);
- target_execute_cmd(se_cmd);
-cleanup:
- return ret;
-}
-
-static int usbg_submit_command(struct f_uas *, void *, unsigned int);
-
-static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_uas *fu = req->context;
- int ret;
-
- if (req->status < 0)
- return;
-
- ret = usbg_submit_command(fu, req->buf, req->actual);
- /*
- * Once we tune for performance enqueue the command req here again so
- * we can receive a second command while we processing this one. Pay
- * attention to properly sync STAUS endpoint with DATA IN + OUT so you
- * don't break HS.
- */
- if (!ret)
- return;
- usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-}
-
-static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
-{
- stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
- if (!stream->req_in)
- goto out;
-
- stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
- if (!stream->req_out)
- goto err_out;
-
- stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
- if (!stream->req_status)
- goto err_sts;
-
- return 0;
-err_sts:
- usb_ep_free_request(fu->ep_status, stream->req_status);
- stream->req_status = NULL;
-err_out:
- usb_ep_free_request(fu->ep_out, stream->req_out);
- stream->req_out = NULL;
-out:
- return -ENOMEM;
-}
-
-static int uasp_alloc_cmd(struct f_uas *fu)
-{
- fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
- if (!fu->cmd.req)
- goto err;
-
- fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
- if (!fu->cmd.buf)
- goto err_buf;
-
- fu->cmd.req->complete = uasp_cmd_complete;
- fu->cmd.req->buf = fu->cmd.buf;
- fu->cmd.req->length = fu->ep_cmd->maxpacket;
- fu->cmd.req->context = fu;
- return 0;
-
-err_buf:
- usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
-err:
- return -ENOMEM;
-}
-
-static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
-{
- int i;
-
- for (i = 0; i < max_streams; i++) {
- struct uas_stream *s = &fu->stream[i];
-
- s->req_in->stream_id = i + 1;
- s->req_out->stream_id = i + 1;
- s->req_status->stream_id = i + 1;
- }
-}
-
-static int uasp_prepare_reqs(struct f_uas *fu)
-{
- int ret;
- int i;
- int max_streams;
-
- if (fu->flags & USBG_USE_STREAMS)
- max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
- else
- max_streams = 1;
-
- for (i = 0; i < max_streams; i++) {
- ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
- if (ret)
- goto err_cleanup;
- }
-
- ret = uasp_alloc_cmd(fu);
- if (ret)
- goto err_free_stream;
- uasp_setup_stream_res(fu, max_streams);
-
- ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
- if (ret)
- goto err_free_stream;
-
- return 0;
-
-err_free_stream:
- uasp_free_cmdreq(fu);
-
-err_cleanup:
- if (i) {
- do {
- uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
- i--;
- } while (i);
- }
- pr_err("UASP: endpoint setup failed\n");
- return ret;
-}
-
-static void uasp_set_alt(struct f_uas *fu)
-{
- struct usb_function *f = &fu->function;
- struct usb_gadget *gadget = f->config->cdev->gadget;
- int ret;
-
- fu->flags = USBG_IS_UAS;
-
- if (gadget->speed == USB_SPEED_SUPER)
- fu->flags |= USBG_USE_STREAMS;
-
- config_ep_by_speed(gadget, f, fu->ep_in);
- ret = usb_ep_enable(fu->ep_in);
- if (ret)
- goto err_b_in;
-
- config_ep_by_speed(gadget, f, fu->ep_out);
- ret = usb_ep_enable(fu->ep_out);
- if (ret)
- goto err_b_out;
-
- config_ep_by_speed(gadget, f, fu->ep_cmd);
- ret = usb_ep_enable(fu->ep_cmd);
- if (ret)
- goto err_cmd;
- config_ep_by_speed(gadget, f, fu->ep_status);
- ret = usb_ep_enable(fu->ep_status);
- if (ret)
- goto err_status;
-
- ret = uasp_prepare_reqs(fu);
- if (ret)
- goto err_wq;
- fu->flags |= USBG_ENABLED;
-
- pr_info("Using the UAS protocol\n");
- return;
-err_wq:
- usb_ep_disable(fu->ep_status);
-err_status:
- usb_ep_disable(fu->ep_cmd);
-err_cmd:
- usb_ep_disable(fu->ep_out);
-err_b_out:
- usb_ep_disable(fu->ep_in);
-err_b_in:
- fu->flags = 0;
-}
-
-static int get_cmd_dir(const unsigned char *cdb)
-{
- int ret;
-
- switch (cdb[0]) {
- case READ_6:
- case READ_10:
- case READ_12:
- case READ_16:
- case INQUIRY:
- case MODE_SENSE:
- case MODE_SENSE_10:
- case SERVICE_ACTION_IN_16:
- case MAINTENANCE_IN:
- case PERSISTENT_RESERVE_IN:
- case SECURITY_PROTOCOL_IN:
- case ACCESS_CONTROL_IN:
- case REPORT_LUNS:
- case READ_BLOCK_LIMITS:
- case READ_POSITION:
- case READ_CAPACITY:
- case READ_TOC:
- case READ_FORMAT_CAPACITIES:
- case REQUEST_SENSE:
- ret = DMA_FROM_DEVICE;
- break;
-
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- case MODE_SELECT:
- case MODE_SELECT_10:
- case WRITE_VERIFY:
- case WRITE_VERIFY_12:
- case PERSISTENT_RESERVE_OUT:
- case MAINTENANCE_OUT:
- case SECURITY_PROTOCOL_OUT:
- case ACCESS_CONTROL_OUT:
- ret = DMA_TO_DEVICE;
- break;
- case ALLOW_MEDIUM_REMOVAL:
- case TEST_UNIT_READY:
- case SYNCHRONIZE_CACHE:
- case START_STOP:
- case ERASE:
- case REZERO_UNIT:
- case SEEK_10:
- case SPACE:
- case VERIFY:
- case WRITE_FILEMARKS:
- ret = DMA_NONE;
- break;
- default:
- pr_warn("target: Unknown data direction for SCSI Opcode "
- "0x%02x\n", cdb[0]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
- struct usbg_cmd *cmd = req->context;
- struct se_cmd *se_cmd = &cmd->se_cmd;
-
- if (req->status < 0) {
- pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
- goto cleanup;
- }
-
- if (req->num_sgs == 0) {
- sg_copy_from_buffer(se_cmd->t_data_sg,
- se_cmd->t_data_nents,
- cmd->data_buf,
- se_cmd->data_length);
- }
-
- complete(&cmd->write_complete);
- return;
-
-cleanup:
- usbg_cleanup_cmd(cmd);
-}
-
-static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
-{
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct f_uas *fu = cmd->fu;
- struct usb_gadget *gadget = fuas_to_gadget(fu);
-
- if (!gadget->sg_supported) {
- cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
- if (!cmd->data_buf)
- return -ENOMEM;
-
- req->buf = cmd->data_buf;
- } else {
- req->buf = NULL;
- req->num_sgs = se_cmd->t_data_nents;
- req->sg = se_cmd->t_data_sg;
- }
-
- req->complete = usbg_data_write_cmpl;
- req->length = se_cmd->data_length;
- req->context = cmd;
- return 0;
-}
-
-static int usbg_send_status_response(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return bot_send_status_response(cmd);
- else
- return uasp_send_status_response(cmd);
-}
-
-static int usbg_send_write_request(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return bot_send_write_request(cmd);
- else
- return uasp_send_write_request(cmd);
-}
-
-static int usbg_send_read_response(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- struct f_uas *fu = cmd->fu;
-
- if (fu->flags & USBG_IS_BOT)
- return bot_send_read_response(cmd);
- else
- return uasp_send_read_response(cmd);
-}
-
-static void usbg_cmd_work(struct work_struct *work)
-{
- struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- struct usbg_tpg *tpg;
- int dir;
-
- se_cmd = &cmd->se_cmd;
- tpg = cmd->fu->tpg;
- tv_nexus = tpg->tpg_nexus;
- dir = get_cmd_dir(cmd->cmd_buf);
- if (dir < 0) {
- transport_init_se_cmd(se_cmd,
- tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
- tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
- cmd->prio_attr, cmd->sense_iu.sense);
- goto out;
- }
-
- if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
- cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
- 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0)
- goto out;
-
- return;
-
-out:
- transport_send_check_condition_and_sense(se_cmd,
- TCM_UNSUPPORTED_SCSI_OPCODE, 1);
- usbg_cleanup_cmd(cmd);
-}
-
-static int usbg_submit_command(struct f_uas *fu,
- void *cmdbuf, unsigned int len)
-{
- struct command_iu *cmd_iu = cmdbuf;
- struct usbg_cmd *cmd;
- struct usbg_tpg *tpg;
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- u32 cmd_len;
- int ret;
-
- if (cmd_iu->iu_id != IU_ID_COMMAND) {
- pr_err("Unsupported type %d\n", cmd_iu->iu_id);
- return -EINVAL;
- }
-
- cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
- if (!cmd)
- return -ENOMEM;
-
- cmd->fu = fu;
-
- /* XXX until I figure out why I can't free in on complete */
- kref_init(&cmd->ref);
- kref_get(&cmd->ref);
-
- tpg = fu->tpg;
- cmd_len = (cmd_iu->len & ~0x3) + 16;
- if (cmd_len > USBG_MAX_CMD)
- goto err;
-
- memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
-
- cmd->tag = be16_to_cpup(&cmd_iu->tag);
- cmd->se_cmd.tag = cmd->tag;
- if (fu->flags & USBG_USE_STREAMS) {
- if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
- goto err;
- if (!cmd->tag)
- cmd->stream = &fu->stream[0];
- else
- cmd->stream = &fu->stream[cmd->tag - 1];
- } else {
- cmd->stream = &fu->stream[0];
- }
-
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus) {
- pr_err("Missing nexus, ignoring command\n");
- goto err;
- }
-
- switch (cmd_iu->prio_attr & 0x7) {
- case UAS_HEAD_TAG:
- cmd->prio_attr = TCM_HEAD_TAG;
- break;
- case UAS_ORDERED_TAG:
- cmd->prio_attr = TCM_ORDERED_TAG;
- break;
- case UAS_ACA:
- cmd->prio_attr = TCM_ACA_TAG;
- break;
- default:
- pr_debug_once("Unsupported prio_attr: %02x.\n",
- cmd_iu->prio_attr);
- case UAS_SIMPLE_TAG:
- cmd->prio_attr = TCM_SIMPLE_TAG;
- break;
- }
-
- se_cmd = &cmd->se_cmd;
- cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
-
- INIT_WORK(&cmd->work, usbg_cmd_work);
- ret = queue_work(tpg->workqueue, &cmd->work);
- if (ret < 0)
- goto err;
-
- return 0;
-err:
- kfree(cmd);
- return -EINVAL;
-}
-
-static void bot_cmd_work(struct work_struct *work)
-{
- struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- struct usbg_tpg *tpg;
- int dir;
-
- se_cmd = &cmd->se_cmd;
- tpg = cmd->fu->tpg;
- tv_nexus = tpg->tpg_nexus;
- dir = get_cmd_dir(cmd->cmd_buf);
- if (dir < 0) {
- transport_init_se_cmd(se_cmd,
- tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
- tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
- cmd->prio_attr, cmd->sense_iu.sense);
- goto out;
- }
-
- if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
- cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
- cmd->data_len, cmd->prio_attr, dir, 0) < 0)
- goto out;
-
- return;
-
-out:
- transport_send_check_condition_and_sense(se_cmd,
- TCM_UNSUPPORTED_SCSI_OPCODE, 1);
- usbg_cleanup_cmd(cmd);
-}
-
-static int bot_submit_command(struct f_uas *fu,
- void *cmdbuf, unsigned int len)
-{
- struct bulk_cb_wrap *cbw = cmdbuf;
- struct usbg_cmd *cmd;
- struct usbg_tpg *tpg;
- struct se_cmd *se_cmd;
- struct tcm_usbg_nexus *tv_nexus;
- u32 cmd_len;
- int ret;
-
- if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
- pr_err("Wrong signature on CBW\n");
- return -EINVAL;
- }
- if (len != 31) {
- pr_err("Wrong length for CBW\n");
- return -EINVAL;
- }
-
- cmd_len = cbw->Length;
- if (cmd_len < 1 || cmd_len > 16)
- return -EINVAL;
-
- cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
- if (!cmd)
- return -ENOMEM;
-
- cmd->fu = fu;
-
- /* XXX until I figure out why I can't free in on complete */
- kref_init(&cmd->ref);
- kref_get(&cmd->ref);
-
- tpg = fu->tpg;
-
- memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
-
- cmd->bot_tag = cbw->Tag;
-
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus) {
- pr_err("Missing nexus, ignoring command\n");
- goto err;
- }
-
- cmd->prio_attr = TCM_SIMPLE_TAG;
- se_cmd = &cmd->se_cmd;
- cmd->unpacked_lun = cbw->Lun;
- cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
- cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
- cmd->se_cmd.tag = le32_to_cpu(cmd->bot_tag);
-
- INIT_WORK(&cmd->work, bot_cmd_work);
- ret = queue_work(tpg->workqueue, &cmd->work);
- if (ret < 0)
- goto err;
-
- return 0;
-err:
- kfree(cmd);
- return -EINVAL;
-}
-
-/* Start fabric.c code */
-
-static int usbg_check_true(struct se_portal_group *se_tpg)
-{
- return 1;
-}
-
-static int usbg_check_false(struct se_portal_group *se_tpg)
-{
- return 0;
-}
-
-static char *usbg_get_fabric_name(void)
-{
- return "usb_gadget";
-}
-
-static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- struct usbg_tport *tport = tpg->tport;
-
- return &tport->tport_name[0];
-}
-
-static u16 usbg_get_tag(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
- return tpg->tport_tpgt;
-}
-
-static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
-{
- return 1;
-}
-
-static void usbg_cmd_release(struct kref *ref)
-{
- struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
- ref);
-
- transport_generic_free_cmd(&cmd->se_cmd, 0);
-}
-
-static void usbg_release_cmd(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
- kfree(cmd->data_buf);
- kfree(cmd);
- return;
-}
-
-static int usbg_shutdown_session(struct se_session *se_sess)
-{
- return 0;
-}
-
-static void usbg_close_session(struct se_session *se_sess)
-{
- return;
-}
-
-static u32 usbg_sess_get_index(struct se_session *se_sess)
-{
- return 0;
-}
-
-/*
- * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
- */
-static int usbg_write_pending_status(struct se_cmd *se_cmd)
-{
- return 0;
-}
-
-static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
-{
- return;
-}
-
-static int usbg_get_cmd_state(struct se_cmd *se_cmd)
-{
- return 0;
-}
-
-static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
-{
-}
-
-static void usbg_aborted_task(struct se_cmd *se_cmd)
-{
- return;
-}
-
-static const char *usbg_check_wwn(const char *name)
-{
- const char *n;
- unsigned int len;
-
- n = strstr(name, "naa.");
- if (!n)
- return NULL;
- n += 4;
- len = strlen(n);
- if (len == 0 || len > USBG_NAMELEN - 1)
- return NULL;
- return n;
-}
-
-static int usbg_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
-{
- if (!usbg_check_wwn(name))
- return -EINVAL;
- return 0;
-}
-
-struct usbg_tpg *the_only_tpg_I_currently_have;
-
-static struct se_portal_group *usbg_make_tpg(
- struct se_wwn *wwn,
- struct config_group *group,
- const char *name)
-{
- struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
- tport_wwn);
- struct usbg_tpg *tpg;
- unsigned long tpgt;
- int ret;
-
- if (strstr(name, "tpgt_") != name)
- return ERR_PTR(-EINVAL);
- if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
- return ERR_PTR(-EINVAL);
- if (the_only_tpg_I_currently_have) {
- pr_err("Until the gadget framework can't handle multiple\n");
- pr_err("gadgets, you can't do this here.\n");
- return ERR_PTR(-EBUSY);
- }
-
- tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
- if (!tpg)
- return ERR_PTR(-ENOMEM);
- mutex_init(&tpg->tpg_mutex);
- atomic_set(&tpg->tpg_port_count, 0);
- tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
- if (!tpg->workqueue) {
- kfree(tpg);
- return NULL;
- }
-
- tpg->tport = tport;
- tpg->tport_tpgt = tpgt;
-
- /*
- * SPC doesn't assign a protocol identifier for USB-SCSI, so we
- * pretend to be SAS..
- */
- ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS);
- if (ret < 0) {
- destroy_workqueue(tpg->workqueue);
- kfree(tpg);
- return NULL;
- }
- the_only_tpg_I_currently_have = tpg;
- return &tpg->se_tpg;
-}
-
-static void usbg_drop_tpg(struct se_portal_group *se_tpg)
-{
- struct usbg_tpg *tpg = container_of(se_tpg,
- struct usbg_tpg, se_tpg);
-
- core_tpg_deregister(se_tpg);
- destroy_workqueue(tpg->workqueue);
- kfree(tpg);
- the_only_tpg_I_currently_have = NULL;
-}
-
-static struct se_wwn *usbg_make_tport(
- struct target_fabric_configfs *tf,
- struct config_group *group,
- const char *name)
-{
- struct usbg_tport *tport;
- const char *wnn_name;
- u64 wwpn = 0;
-
- wnn_name = usbg_check_wwn(name);
- if (!wnn_name)
- return ERR_PTR(-EINVAL);
-
- tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
- if (!(tport))
- return ERR_PTR(-ENOMEM);
- tport->tport_wwpn = wwpn;
- snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);
- return &tport->tport_wwn;
-}
-
-static void usbg_drop_tport(struct se_wwn *wwn)
-{
- struct usbg_tport *tport = container_of(wwn,
- struct usbg_tport, tport_wwn);
- kfree(tport);
-}
-
-/*
- * If somebody feels like dropping the version property, go ahead.
- */
-static ssize_t usbg_wwn_version_show(struct config_item *item, char *page)
-{
- return sprintf(page, "usb-gadget fabric module\n");
-}
-
-CONFIGFS_ATTR_RO(usbg_wwn_, version);
-
-static struct configfs_attribute *usbg_wwn_attrs[] = {
- &usbg_wwn_attr_version,
- NULL,
-};
-
-static ssize_t tcm_usbg_tpg_enable_show(struct config_item *item, char *page)
-{
- struct se_portal_group *se_tpg = to_tpg(item);
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
- return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
-}
-
-static int usbg_attach(struct usbg_tpg *);
-static void usbg_detach(struct usbg_tpg *);
-
-static ssize_t tcm_usbg_tpg_enable_store(struct config_item *item,
- const char *page, size_t count)
-{
- struct se_portal_group *se_tpg = to_tpg(item);
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
- unsigned long op;
- ssize_t ret;
-
- ret = kstrtoul(page, 0, &op);
- if (ret < 0)
- return -EINVAL;
- if (op > 1)
- return -EINVAL;
-
- if (op && tpg->gadget_connect)
- goto out;
- if (!op && !tpg->gadget_connect)
- goto out;
-
- if (op) {
- ret = usbg_attach(tpg);
- if (ret)
- goto out;
- } else {
- usbg_detach(tpg);
- }
- tpg->gadget_connect = op;
-out:
- return count;
-}
-
-static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page)
-{
- struct se_portal_group *se_tpg = to_tpg(item);
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
- struct tcm_usbg_nexus *tv_nexus;
- ssize_t ret;
-
- mutex_lock(&tpg->tpg_mutex);
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus) {
- ret = -ENODEV;
- goto out;
- }
- ret = snprintf(page, PAGE_SIZE, "%s\n",
- tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-out:
- mutex_unlock(&tpg->tpg_mutex);
- return ret;
-}
-
-static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
-{
- struct se_portal_group *se_tpg;
- struct tcm_usbg_nexus *tv_nexus;
- int ret;
-
- mutex_lock(&tpg->tpg_mutex);
- if (tpg->tpg_nexus) {
- ret = -EEXIST;
- pr_debug("tpg->tpg_nexus already exists\n");
- goto err_unlock;
- }
- se_tpg = &tpg->se_tpg;
-
- ret = -ENOMEM;
- tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
- if (!tv_nexus)
- goto err_unlock;
- tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);
- if (IS_ERR(tv_nexus->tvn_se_sess))
- goto err_free;
-
- /*
- * Since we are running in 'demo mode' this call with generate a
- * struct se_node_acl for the tcm_vhost struct se_portal_group with
- * the SCSI Initiator port name of the passed configfs group 'name'.
- */
- tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
- se_tpg, name);
- if (!tv_nexus->tvn_se_sess->se_node_acl) {
- pr_debug("core_tpg_check_initiator_node_acl() failed"
- " for %s\n", name);
- goto err_session;
- }
- /*
- * Now register the TCM vHost virtual I_T Nexus as active.
- */
- transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
- tv_nexus->tvn_se_sess, tv_nexus);
- tpg->tpg_nexus = tv_nexus;
- mutex_unlock(&tpg->tpg_mutex);
- return 0;
-
-err_session:
- transport_free_session(tv_nexus->tvn_se_sess);
-err_free:
- kfree(tv_nexus);
-err_unlock:
- mutex_unlock(&tpg->tpg_mutex);
- return ret;
-}
-
-static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
-{
- struct se_session *se_sess;
- struct tcm_usbg_nexus *tv_nexus;
- int ret = -ENODEV;
-
- mutex_lock(&tpg->tpg_mutex);
- tv_nexus = tpg->tpg_nexus;
- if (!tv_nexus)
- goto out;
-
- se_sess = tv_nexus->tvn_se_sess;
- if (!se_sess)
- goto out;
-
- if (atomic_read(&tpg->tpg_port_count)) {
- ret = -EPERM;
- pr_err("Unable to remove Host I_T Nexus with"
- " active TPG port count: %d\n",
- atomic_read(&tpg->tpg_port_count));
- goto out;
- }
-
- pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
- tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
- /*
- * Release the SCSI I_T Nexus to the emulated vHost Target Port
- */
- transport_deregister_session(tv_nexus->tvn_se_sess);
- tpg->tpg_nexus = NULL;
-
- kfree(tv_nexus);
- ret = 0;
-out:
- mutex_unlock(&tpg->tpg_mutex);
- return ret;
-}
-
-static ssize_t tcm_usbg_tpg_nexus_store(struct config_item *item,
- const char *page, size_t count)
-{
- struct se_portal_group *se_tpg = to_tpg(item);
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
- unsigned char i_port[USBG_NAMELEN], *ptr;
- int ret;
-
- if (!strncmp(page, "NULL", 4)) {
- ret = tcm_usbg_drop_nexus(tpg);
- return (!ret) ? count : ret;
- }
- if (strlen(page) >= USBG_NAMELEN) {
- pr_err("Emulated NAA Sas Address: %s, exceeds"
- " max: %d\n", page, USBG_NAMELEN);
- return -EINVAL;
- }
- snprintf(i_port, USBG_NAMELEN, "%s", page);
-
- ptr = strstr(i_port, "naa.");
- if (!ptr) {
- pr_err("Missing 'naa.' prefix\n");
- return -EINVAL;
- }
-
- if (i_port[strlen(i_port) - 1] == '\n')
- i_port[strlen(i_port) - 1] = '\0';
-
- ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
- if (ret < 0)
- return ret;
- return count;
-}
-
-CONFIGFS_ATTR(tcm_usbg_tpg_, enable);
-CONFIGFS_ATTR(tcm_usbg_tpg_, nexus);
-
-static struct configfs_attribute *usbg_base_attrs[] = {
- &tcm_usbg_tpg_attr_enable,
- &tcm_usbg_tpg_attr_nexus,
- NULL,
-};
-
-static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
- atomic_inc(&tpg->tpg_port_count);
- smp_mb__after_atomic();
- return 0;
-}
-
-static void usbg_port_unlink(struct se_portal_group *se_tpg,
- struct se_lun *se_lun)
-{
- struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
- atomic_dec(&tpg->tpg_port_count);
- smp_mb__after_atomic();
-}
-
-static int usbg_check_stop_free(struct se_cmd *se_cmd)
-{
- struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
- se_cmd);
-
- kref_put(&cmd->ref, usbg_cmd_release);
- return 1;
-}
-
-static const struct target_core_fabric_ops usbg_ops = {
- .module = THIS_MODULE,
- .name = "usb_gadget",
- .get_fabric_name = usbg_get_fabric_name,
- .tpg_get_wwn = usbg_get_fabric_wwn,
- .tpg_get_tag = usbg_get_tag,
- .tpg_check_demo_mode = usbg_check_true,
- .tpg_check_demo_mode_cache = usbg_check_false,
- .tpg_check_demo_mode_write_protect = usbg_check_false,
- .tpg_check_prod_mode_write_protect = usbg_check_false,
- .tpg_get_inst_index = usbg_tpg_get_inst_index,
- .release_cmd = usbg_release_cmd,
- .shutdown_session = usbg_shutdown_session,
- .close_session = usbg_close_session,
- .sess_get_index = usbg_sess_get_index,
- .sess_get_initiator_sid = NULL,
- .write_pending = usbg_send_write_request,
- .write_pending_status = usbg_write_pending_status,
- .set_default_node_attributes = usbg_set_default_node_attrs,
- .get_cmd_state = usbg_get_cmd_state,
- .queue_data_in = usbg_send_read_response,
- .queue_status = usbg_send_status_response,
- .queue_tm_rsp = usbg_queue_tm_rsp,
- .aborted_task = usbg_aborted_task,
- .check_stop_free = usbg_check_stop_free,
-
- .fabric_make_wwn = usbg_make_tport,
- .fabric_drop_wwn = usbg_drop_tport,
- .fabric_make_tpg = usbg_make_tpg,
- .fabric_drop_tpg = usbg_drop_tpg,
- .fabric_post_link = usbg_port_link,
- .fabric_pre_unlink = usbg_port_unlink,
- .fabric_init_nodeacl = usbg_init_nodeacl,
-
- .tfc_wwn_attrs = usbg_wwn_attrs,
- .tfc_tpg_base_attrs = usbg_base_attrs,
-};
-
-/* Start gadget.c code */
-
-static struct usb_interface_descriptor bot_intf_desc = {
- .bLength = sizeof(bot_intf_desc),
- .bDescriptorType = USB_DT_INTERFACE,
- .bNumEndpoints = 2,
- .bAlternateSetting = USB_G_ALT_INT_BBB,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = USB_SC_SCSI,
- .bInterfaceProtocol = USB_PR_BULK,
-};
-
-static struct usb_interface_descriptor uasp_intf_desc = {
- .bLength = sizeof(uasp_intf_desc),
- .bDescriptorType = USB_DT_INTERFACE,
- .bNumEndpoints = 4,
- .bAlternateSetting = USB_G_ALT_INT_UAS,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = USB_SC_SCSI,
- .bInterfaceProtocol = USB_PR_UAS,
-};
-
-static struct usb_endpoint_descriptor uasp_bi_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
- .bLength = sizeof(uasp_bi_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = DATA_IN_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
- .bLength = sizeof(uasp_bi_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 0,
- .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
- .wBytesPerInterval = 0,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
- .bLength = sizeof(bot_bi_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 0,
-};
-
-static struct usb_endpoint_descriptor uasp_bo_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
- .bLength = sizeof(uasp_bo_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = DATA_OUT_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(0x400),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
- .bLength = sizeof(uasp_bo_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
- .bLength = sizeof(bot_bo_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_endpoint_descriptor uasp_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
- .bLength = sizeof(uasp_status_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = STATUS_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_status_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
- .bLength = sizeof(uasp_status_in_ep_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_endpoint_descriptor uasp_cmd_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
- .bLength = sizeof(uasp_cmd_pipe_desc),
- .bDescriptorType = USB_DT_PIPE_USAGE,
- .bPipeID = CMD_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
- .bLength = sizeof(uasp_cmd_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_descriptor_header *uasp_fs_function_desc[] = {
- (struct usb_descriptor_header *) &bot_intf_desc,
- (struct usb_descriptor_header *) &uasp_fs_bi_desc,
- (struct usb_descriptor_header *) &uasp_fs_bo_desc,
-
- (struct usb_descriptor_header *) &uasp_intf_desc,
- (struct usb_descriptor_header *) &uasp_fs_bi_desc,
- (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
- (struct usb_descriptor_header *) &uasp_fs_bo_desc,
- (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
- (struct usb_descriptor_header *) &uasp_fs_status_desc,
- (struct usb_descriptor_header *) &uasp_status_pipe_desc,
- (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
- (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
- NULL,
-};
-
-static struct usb_descriptor_header *uasp_hs_function_desc[] = {
- (struct usb_descriptor_header *) &bot_intf_desc,
- (struct usb_descriptor_header *) &uasp_bi_desc,
- (struct usb_descriptor_header *) &uasp_bo_desc,
-
- (struct usb_descriptor_header *) &uasp_intf_desc,
- (struct usb_descriptor_header *) &uasp_bi_desc,
- (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
- (struct usb_descriptor_header *) &uasp_bo_desc,
- (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
- (struct usb_descriptor_header *) &uasp_status_desc,
- (struct usb_descriptor_header *) &uasp_status_pipe_desc,
- (struct usb_descriptor_header *) &uasp_cmd_desc,
- (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
- NULL,
-};
-
-static struct usb_descriptor_header *uasp_ss_function_desc[] = {
- (struct usb_descriptor_header *) &bot_intf_desc,
- (struct usb_descriptor_header *) &uasp_ss_bi_desc,
- (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_ss_bo_desc,
- (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
-
- (struct usb_descriptor_header *) &uasp_intf_desc,
- (struct usb_descriptor_header *) &uasp_ss_bi_desc,
- (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
- (struct usb_descriptor_header *) &uasp_ss_bo_desc,
- (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
- (struct usb_descriptor_header *) &uasp_ss_status_desc,
- (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
- (struct usb_descriptor_header *) &uasp_status_pipe_desc,
- (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
- (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
- (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
- NULL,
-};
-
#define UAS_VENDOR_ID 0x0525 /* NetChip */
#define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
static struct usb_device_descriptor usbg_device_desc = {
.bLength = sizeof(usbg_device_desc),
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.idVendor = cpu_to_le16(UAS_VENDOR_ID),
.idProduct = cpu_to_le16(UAS_PRODUCT_ID),
.bNumConfigurations = 1,
};
+#define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX
+
static struct usb_string usbg_us_strings[] = {
[USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor",
[USB_GADGET_PRODUCT_IDX].s = "Target Product",
[USB_GADGET_SERIAL_IDX].s = "000000000001",
[USB_G_STR_CONFIG].s = "default config",
- [USB_G_STR_INT_UAS].s = "USB Attached SCSI",
- [USB_G_STR_INT_BBB].s = "Bulk Only Transport",
{ },
};
@@ -2001,184 +58,42 @@ static struct usb_gadget_strings *usbg_strings[] = {
NULL,
};
-static int guas_unbind(struct usb_composite_dev *cdev)
-{
- return 0;
-}
-
-static struct usb_configuration usbg_config_driver = {
- .label = "Linux Target",
- .bConfigurationValue = 1,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};
+static struct usb_function_instance *fi_tcm;
+static struct usb_function *f_tcm;
-static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+static int guas_unbind(struct usb_composite_dev *cdev)
{
- struct f_uas *fu = to_f_uas(f);
- struct usb_gadget *gadget = c->cdev->gadget;
- struct usb_ep *ep;
- int iface;
- int ret;
-
- iface = usb_interface_id(c, f);
- if (iface < 0)
- return iface;
-
- bot_intf_desc.bInterfaceNumber = iface;
- uasp_intf_desc.bInterfaceNumber = iface;
- fu->iface = iface;
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
- &uasp_bi_ep_comp_desc);
- if (!ep)
- goto ep_fail;
- fu->ep_in = ep;
-
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
- &uasp_bo_ep_comp_desc);
- if (!ep)
- goto ep_fail;
- fu->ep_out = ep;
-
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
- &uasp_status_in_ep_comp_desc);
- if (!ep)
- goto ep_fail;
- fu->ep_status = ep;
-
- ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
- &uasp_cmd_comp_desc);
- if (!ep)
- goto ep_fail;
- fu->ep_cmd = ep;
-
- /* Assume endpoint addresses are the same for both speeds */
- uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
- uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
- uasp_status_desc.bEndpointAddress =
- uasp_ss_status_desc.bEndpointAddress;
- uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
- uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
- uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
- uasp_fs_status_desc.bEndpointAddress =
- uasp_ss_status_desc.bEndpointAddress;
- uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
- ret = usb_assign_descriptors(f, uasp_fs_function_desc,
- uasp_hs_function_desc, uasp_ss_function_desc);
- if (ret)
- goto ep_fail;
+ if (!IS_ERR_OR_NULL(f_tcm))
+ usb_put_function(f_tcm);
return 0;
-ep_fail:
- pr_err("Can't claim all required eps\n");
- return -ENOTSUPP;
}
-static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+static int tcm_do_config(struct usb_configuration *c)
{
- struct f_uas *fu = to_f_uas(f);
+ int status;
- usb_free_all_descriptors(f);
- kfree(fu);
-}
-
-struct guas_setup_wq {
- struct work_struct work;
- struct f_uas *fu;
- unsigned int alt;
-};
-
-static void usbg_delayed_set_alt(struct work_struct *wq)
-{
- struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
- work);
- struct f_uas *fu = work->fu;
- int alt = work->alt;
-
- kfree(work);
-
- if (fu->flags & USBG_IS_BOT)
- bot_cleanup_old_alt(fu);
- if (fu->flags & USBG_IS_UAS)
- uasp_cleanup_old_alt(fu);
-
- if (alt == USB_G_ALT_INT_BBB)
- bot_set_alt(fu);
- else if (alt == USB_G_ALT_INT_UAS)
- uasp_set_alt(fu);
- usb_composite_setup_continue(fu->function.config->cdev);
-}
-
-static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
- struct f_uas *fu = to_f_uas(f);
-
- if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
- struct guas_setup_wq *work;
+ f_tcm = usb_get_function(fi_tcm);
+ if (IS_ERR(f_tcm))
+ return PTR_ERR(f_tcm);
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- if (!work)
- return -ENOMEM;
- INIT_WORK(&work->work, usbg_delayed_set_alt);
- work->fu = fu;
- work->alt = alt;
- schedule_work(&work->work);
- return USB_GADGET_DELAYED_STATUS;
+ status = usb_add_function(c, f_tcm);
+ if (status < 0) {
+ usb_put_function(f_tcm);
+ return status;
}
- return -EOPNOTSUPP;
-}
-
-static void usbg_disable(struct usb_function *f)
-{
- struct f_uas *fu = to_f_uas(f);
-
- if (fu->flags & USBG_IS_UAS)
- uasp_cleanup_old_alt(fu);
- else if (fu->flags & USBG_IS_BOT)
- bot_cleanup_old_alt(fu);
- fu->flags = 0;
-}
-
-static int usbg_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
-{
- struct f_uas *fu = to_f_uas(f);
-
- if (!(fu->flags & USBG_IS_BOT))
- return -EOPNOTSUPP;
- return usbg_bot_setup(f, ctrl);
+ return 0;
}
-static int usbg_cfg_bind(struct usb_configuration *c)
-{
- struct f_uas *fu;
- int ret;
-
- fu = kzalloc(sizeof(*fu), GFP_KERNEL);
- if (!fu)
- return -ENOMEM;
- fu->function.name = "Target Function";
- fu->function.bind = usbg_bind;
- fu->function.unbind = usbg_unbind;
- fu->function.set_alt = usbg_set_alt;
- fu->function.setup = usbg_setup;
- fu->function.disable = usbg_disable;
- fu->tpg = the_only_tpg_I_currently_have;
-
- bot_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_BBB].id;
- uasp_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_UAS].id;
-
- ret = usb_add_function(c, &fu->function);
- if (ret)
- goto err;
+static struct usb_configuration usbg_config_driver = {
+ .label = "Linux Target",
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
- return 0;
-err:
- kfree(fu);
- return ret;
-}
+static int usbg_attach(struct usb_function_instance *f);
+static void usbg_detach(struct usb_function_instance *f);
static int usb_target_bind(struct usb_composite_dev *cdev)
{
@@ -2196,8 +111,7 @@ static int usb_target_bind(struct usb_composite_dev *cdev)
usbg_config_driver.iConfiguration =
usbg_us_strings[USB_G_STR_CONFIG].id;
- ret = usb_add_config(cdev, &usbg_config_driver,
- usbg_cfg_bind);
+ ret = usb_add_config(cdev, &usbg_config_driver, tcm_do_config);
if (ret)
return ret;
usb_composite_overwrite_options(cdev, &coverwrite);
@@ -2213,25 +127,44 @@ static struct usb_composite_driver usbg_driver = {
.unbind = guas_unbind,
};
-static int usbg_attach(struct usbg_tpg *tpg)
+static int usbg_attach(struct usb_function_instance *f)
{
return usb_composite_probe(&usbg_driver);
}
-static void usbg_detach(struct usbg_tpg *tpg)
+static void usbg_detach(struct usb_function_instance *f)
{
usb_composite_unregister(&usbg_driver);
}
static int __init usb_target_gadget_init(void)
{
- return target_register_template(&usbg_ops);
+ struct f_tcm_opts *tcm_opts;
+
+ fi_tcm = usb_get_function_instance("tcm");
+ if (IS_ERR(fi_tcm))
+ return PTR_ERR(fi_tcm);
+
+ tcm_opts = container_of(fi_tcm, struct f_tcm_opts, func_inst);
+ mutex_lock(&tcm_opts->dep_lock);
+ tcm_opts->tcm_register_callback = usbg_attach;
+ tcm_opts->tcm_unregister_callback = usbg_detach;
+ tcm_opts->dependent = THIS_MODULE;
+ tcm_opts->can_attach = true;
+ tcm_opts->has_dep = true;
+ mutex_unlock(&tcm_opts->dep_lock);
+
+ fi_tcm->set_inst_name(fi_tcm, "tcm-legacy");
+
+ return 0;
}
module_init(usb_target_gadget_init);
static void __exit usb_target_gadget_exit(void)
{
- target_unregister_template(&usbg_ops);
+ if (!IS_ERR_OR_NULL(fi_tcm))
+ usb_put_function_instance(fi_tcm);
+
}
module_exit(usb_target_gadget_exit);
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index 72c976bf3530..f9661cd627c8 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -77,7 +77,7 @@ static struct usb_function *f_uvc;
static struct usb_device_descriptor webcam_device_descriptor = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_MISC,
.bDeviceSubClass = 0x02,
.bDeviceProtocol = 0x01,
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index 37a410056fed..d02e2ce73ea5 100644
--- a/drivers/usb/gadget/legacy/zero.c
+++ b/drivers/usb/gadget/legacy/zero.c
@@ -68,6 +68,8 @@ static struct usb_zero_options gzero_options = {
.isoc_maxpacket = GZERO_ISOC_MAXPACKET,
.bulk_buflen = GZERO_BULK_BUFLEN,
.qlen = GZERO_QLEN,
+ .ss_bulk_qlen = GZERO_SS_BULK_QLEN,
+ .ss_iso_qlen = GZERO_SS_ISO_QLEN,
};
/*-------------------------------------------------------------------------*/
@@ -113,7 +115,7 @@ static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ /* .bcdUSB = DYNAMIC */
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
@@ -255,6 +257,14 @@ static struct usb_function_instance *func_inst_lb;
module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(qlen, "depth of loopback queue");
+module_param_named(ss_bulk_qlen, gzero_options.ss_bulk_qlen, uint,
+ S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(bulk_qlen, "depth of sourcesink queue for bulk transfer");
+
+module_param_named(ss_iso_qlen, gzero_options.ss_iso_qlen, uint,
+ S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(iso_qlen, "depth of sourcesink queue for iso transfer");
+
static int zero_bind(struct usb_composite_dev *cdev)
{
struct f_ss_opts *ss_opts;
@@ -285,6 +295,8 @@ static int zero_bind(struct usb_composite_dev *cdev)
ss_opts->isoc_mult = gzero_options.isoc_mult;
ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
ss_opts->bulk_buflen = gzero_options.bulk_buflen;
+ ss_opts->bulk_qlen = gzero_options.ss_bulk_qlen;
+ ss_opts->iso_qlen = gzero_options.ss_iso_qlen;
func_ss = usb_get_function(func_inst_ss);
if (IS_ERR(func_ss)) {
diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c
index c6276f0268ae..4bc7eea8bfc8 100644
--- a/drivers/usb/gadget/u_f.c
+++ b/drivers/usb/gadget/u_f.c
@@ -11,7 +11,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/usb/gadget.h>
#include "u_f.h"
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len)
diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h
index 1d5f0eb68552..4247cc098a89 100644
--- a/drivers/usb/gadget/u_f.h
+++ b/drivers/usb/gadget/u_f.h
@@ -16,6 +16,8 @@
#ifndef __U_F_H__
#define __U_F_H__
+#include <linux/usb/gadget.h>
+
/* Variable Length Array Macros **********************************************/
#define vla_group(groupname) size_t groupname##__next = 0
#define vla_group_size(groupname) groupname##__next
@@ -45,8 +47,12 @@
struct usb_ep;
struct usb_request;
+/* Requests allocated via alloc_ep_req() must be freed by free_ep_req(). */
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len);
+static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
#endif /* __U_F_H__ */
-
-
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index cdbff54e07ac..753c29bd11ad 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -174,6 +174,17 @@ config USB_RENESAS_USBHS_UDC
dynamically linked module called "renesas_usbhs" and force all
gadget drivers to also be dynamically linked.
+config USB_RENESAS_USB3
+ tristate 'Renesas USB3.0 Peripheral controller'
+ depends on ARCH_SHMOBILE || COMPILE_TEST
+ help
+ Renesas USB3.0 Peripheral controller is a USB peripheral controller
+ that supports super, high, and full speed USB 3.0 data transfers.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "renesas_usb3" and force all
+ gadget drivers to also be dynamically linked.
+
config USB_PXA27X
tristate "PXA 27x"
help
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index fba2049bf985..dfee53446319 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -19,6 +19,7 @@ fsl_usb2_udc-y := fsl_udc_core.o
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
+obj-$(CONFIG_USB_RENESAS_USB3) += renesas_usb3.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index 8cbb00325824..f5fccb3e4152 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -1083,7 +1083,7 @@ static int bcm63xx_ep_disable(struct usb_ep *ep)
struct bcm63xx_ep *bep = our_ep(ep);
struct bcm63xx_udc *udc = bep->udc;
struct iudma_ch *iudma = bep->iudma;
- struct list_head *pos, *n;
+ struct bcm63xx_req *breq, *n;
unsigned long flags;
if (!ep || !ep->desc)
@@ -1099,10 +1099,7 @@ static int bcm63xx_ep_disable(struct usb_ep *ep)
iudma_reset_channel(udc, iudma);
if (!list_empty(&bep->queue)) {
- list_for_each_safe(pos, n, &bep->queue) {
- struct bcm63xx_req *breq =
- list_entry(pos, struct bcm63xx_req, queue);
-
+ list_for_each_entry_safe(breq, n, &bep->queue, queue) {
usb_gadget_unmap_request(&udc->gadget, &breq->req,
iudma->is_tx);
list_del(&breq->queue);
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index 5fb6f8b4f0b4..53c0692f1b09 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -38,7 +38,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include <asm/cpm.h>
#include <asm/dma.h>
#include <asm/reg.h>
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index b9429bc42511..39b7136d31d9 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -253,13 +253,12 @@ static struct gr_dma_desc *gr_alloc_dma_desc(struct gr_ep *ep, gfp_t gfp_flags)
dma_addr_t paddr;
struct gr_dma_desc *dma_desc;
- dma_desc = dma_pool_alloc(ep->dev->desc_pool, gfp_flags, &paddr);
+ dma_desc = dma_pool_zalloc(ep->dev->desc_pool, gfp_flags, &paddr);
if (!dma_desc) {
dev_err(ep->dev->dev, "Could not allocate from DMA pool\n");
return NULL;
}
- memset(dma_desc, 0, sizeof(*dma_desc));
dma_desc->paddr = paddr;
return dma_desc;
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 00b5006baf15..79fe6b77ee44 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -28,42 +28,29 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/proc_fs.h>
-#include <linux/clk.h>
+#include <linux/slab.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/i2c.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
#include <linux/usb/isp1301.h>
-#include <asm/byteorder.h>
-#include <mach/hardware.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-
-#include <mach/platform.h>
-#include <mach/irqs.h>
-#include <mach/board.h>
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#endif
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
/*
* USB device configuration structure
*/
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
new file mode 100644
index 000000000000..93a3bec81df7
--- /dev/null
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -0,0 +1,1975 @@
+/*
+ * Renesas USB3.0 Peripheral driver (USB gadget)
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* register definitions */
+#define USB3_AXI_INT_STA 0x008
+#define USB3_AXI_INT_ENA 0x00c
+#define USB3_DMA_INT_STA 0x010
+#define USB3_DMA_INT_ENA 0x014
+#define USB3_USB_COM_CON 0x200
+#define USB3_USB20_CON 0x204
+#define USB3_USB30_CON 0x208
+#define USB3_USB_STA 0x210
+#define USB3_DRD_CON 0x218
+#define USB3_USB_INT_STA_1 0x220
+#define USB3_USB_INT_STA_2 0x224
+#define USB3_USB_INT_ENA_1 0x228
+#define USB3_USB_INT_ENA_2 0x22c
+#define USB3_STUP_DAT_0 0x230
+#define USB3_STUP_DAT_1 0x234
+#define USB3_P0_MOD 0x280
+#define USB3_P0_CON 0x288
+#define USB3_P0_STA 0x28c
+#define USB3_P0_INT_STA 0x290
+#define USB3_P0_INT_ENA 0x294
+#define USB3_P0_LNG 0x2a0
+#define USB3_P0_READ 0x2a4
+#define USB3_P0_WRITE 0x2a8
+#define USB3_PIPE_COM 0x2b0
+#define USB3_PN_MOD 0x2c0
+#define USB3_PN_RAMMAP 0x2c4
+#define USB3_PN_CON 0x2c8
+#define USB3_PN_STA 0x2cc
+#define USB3_PN_INT_STA 0x2d0
+#define USB3_PN_INT_ENA 0x2d4
+#define USB3_PN_LNG 0x2e0
+#define USB3_PN_READ 0x2e4
+#define USB3_PN_WRITE 0x2e8
+#define USB3_SSIFCMD 0x340
+
+/* AXI_INT_ENA and AXI_INT_STA */
+#define AXI_INT_DMAINT BIT(31)
+#define AXI_INT_EPCINT BIT(30)
+
+/* LCLKSEL */
+#define LCLKSEL_LSEL BIT(18)
+
+/* USB_COM_CON */
+#define USB_COM_CON_CONF BIT(24)
+#define USB_COM_CON_SPD_MODE BIT(17)
+#define USB_COM_CON_EP0_EN BIT(16)
+#define USB_COM_CON_DEV_ADDR_SHIFT 8
+#define USB_COM_CON_DEV_ADDR_MASK GENMASK(14, USB_COM_CON_DEV_ADDR_SHIFT)
+#define USB_COM_CON_DEV_ADDR(n) (((n) << USB_COM_CON_DEV_ADDR_SHIFT) & \
+ USB_COM_CON_DEV_ADDR_MASK)
+#define USB_COM_CON_RX_DETECTION BIT(1)
+#define USB_COM_CON_PIPE_CLR BIT(0)
+
+/* USB20_CON */
+#define USB20_CON_B2_PUE BIT(31)
+#define USB20_CON_B2_SUSPEND BIT(24)
+#define USB20_CON_B2_CONNECT BIT(17)
+#define USB20_CON_B2_TSTMOD_SHIFT 8
+#define USB20_CON_B2_TSTMOD_MASK GENMASK(10, USB20_CON_B2_TSTMOD_SHIFT)
+#define USB20_CON_B2_TSTMOD(n) (((n) << USB20_CON_B2_TSTMOD_SHIFT) & \
+ USB20_CON_B2_TSTMOD_MASK)
+#define USB20_CON_B2_TSTMOD_EN BIT(0)
+
+/* USB30_CON */
+#define USB30_CON_POW_SEL_SHIFT 24
+#define USB30_CON_POW_SEL_MASK GENMASK(26, USB30_CON_POW_SEL_SHIFT)
+#define USB30_CON_POW_SEL_IN_U3 BIT(26)
+#define USB30_CON_POW_SEL_IN_DISCON 0
+#define USB30_CON_POW_SEL_P2_TO_P0 BIT(25)
+#define USB30_CON_POW_SEL_P0_TO_P3 BIT(24)
+#define USB30_CON_POW_SEL_P0_TO_P2 0
+#define USB30_CON_B3_PLLWAKE BIT(23)
+#define USB30_CON_B3_CONNECT BIT(17)
+#define USB30_CON_B3_HOTRST_CMP BIT(1)
+
+/* USB_STA */
+#define USB_STA_SPEED_MASK (BIT(2) | BIT(1))
+#define USB_STA_SPEED_HS BIT(2)
+#define USB_STA_SPEED_FS BIT(1)
+#define USB_STA_SPEED_SS 0
+#define USB_STA_VBUS_STA BIT(0)
+
+/* DRD_CON */
+#define DRD_CON_PERI_CON BIT(24)
+
+/* USB_INT_ENA_1 and USB_INT_STA_1 */
+#define USB_INT_1_B3_PLLWKUP BIT(31)
+#define USB_INT_1_B3_LUPSUCS BIT(30)
+#define USB_INT_1_B3_DISABLE BIT(27)
+#define USB_INT_1_B3_WRMRST BIT(21)
+#define USB_INT_1_B3_HOTRST BIT(20)
+#define USB_INT_1_B2_USBRST BIT(12)
+#define USB_INT_1_B2_L1SPND BIT(11)
+#define USB_INT_1_B2_SPND BIT(9)
+#define USB_INT_1_B2_RSUM BIT(8)
+#define USB_INT_1_SPEED BIT(1)
+#define USB_INT_1_VBUS_CNG BIT(0)
+
+/* USB_INT_ENA_2 and USB_INT_STA_2 */
+#define USB_INT_2_PIPE(n) BIT(n)
+
+/* P0_MOD */
+#define P0_MOD_DIR BIT(6)
+
+/* P0_CON and PN_CON */
+#define PX_CON_BYTE_EN_MASK (BIT(10) | BIT(9))
+#define PX_CON_BYTE_EN_SHIFT 9
+#define PX_CON_BYTE_EN_BYTES(n) (((n) << PX_CON_BYTE_EN_SHIFT) & \
+ PX_CON_BYTE_EN_MASK)
+#define PX_CON_SEND BIT(8)
+
+/* P0_CON */
+#define P0_CON_ST_RES_MASK (BIT(27) | BIT(26))
+#define P0_CON_ST_RES_FORCE_STALL BIT(27)
+#define P0_CON_ST_RES_NORMAL BIT(26)
+#define P0_CON_ST_RES_FORCE_NRDY 0
+#define P0_CON_OT_RES_MASK (BIT(25) | BIT(24))
+#define P0_CON_OT_RES_FORCE_STALL BIT(25)
+#define P0_CON_OT_RES_NORMAL BIT(24)
+#define P0_CON_OT_RES_FORCE_NRDY 0
+#define P0_CON_IN_RES_MASK (BIT(17) | BIT(16))
+#define P0_CON_IN_RES_FORCE_STALL BIT(17)
+#define P0_CON_IN_RES_NORMAL BIT(16)
+#define P0_CON_IN_RES_FORCE_NRDY 0
+#define P0_CON_RES_WEN BIT(7)
+#define P0_CON_BCLR BIT(1)
+
+/* P0_STA and PN_STA */
+#define PX_STA_BUFSTS BIT(0)
+
+/* P0_INT_ENA and P0_INT_STA */
+#define P0_INT_STSED BIT(18)
+#define P0_INT_STSST BIT(17)
+#define P0_INT_SETUP BIT(16)
+#define P0_INT_RCVNL BIT(8)
+#define P0_INT_ERDY BIT(7)
+#define P0_INT_FLOW BIT(6)
+#define P0_INT_STALL BIT(2)
+#define P0_INT_NRDY BIT(1)
+#define P0_INT_BFRDY BIT(0)
+#define P0_INT_ALL_BITS (P0_INT_STSED | P0_INT_SETUP | P0_INT_BFRDY)
+
+/* PN_MOD */
+#define PN_MOD_DIR BIT(6)
+#define PN_MOD_TYPE_SHIFT 4
+#define PN_MOD_TYPE_MASK GENMASK(5, PN_MOD_TYPE_SHIFT)
+#define PN_MOD_TYPE(n) (((n) << PN_MOD_TYPE_SHIFT) & \
+ PN_MOD_TYPE_MASK)
+#define PN_MOD_EPNUM_MASK GENMASK(3, 0)
+#define PN_MOD_EPNUM(n) ((n) & PN_MOD_EPNUM_MASK)
+
+/* PN_RAMMAP */
+#define PN_RAMMAP_RAMAREA_SHIFT 29
+#define PN_RAMMAP_RAMAREA_MASK GENMASK(31, PN_RAMMAP_RAMAREA_SHIFT)
+#define PN_RAMMAP_RAMAREA_16KB BIT(31)
+#define PN_RAMMAP_RAMAREA_8KB (BIT(30) | BIT(29))
+#define PN_RAMMAP_RAMAREA_4KB BIT(30)
+#define PN_RAMMAP_RAMAREA_2KB BIT(29)
+#define PN_RAMMAP_RAMAREA_1KB 0
+#define PN_RAMMAP_MPKT_SHIFT 16
+#define PN_RAMMAP_MPKT_MASK GENMASK(26, PN_RAMMAP_MPKT_SHIFT)
+#define PN_RAMMAP_MPKT(n) (((n) << PN_RAMMAP_MPKT_SHIFT) & \
+ PN_RAMMAP_MPKT_MASK)
+#define PN_RAMMAP_RAMIF_SHIFT 14
+#define PN_RAMMAP_RAMIF_MASK GENMASK(15, PN_RAMMAP_RAMIF_SHIFT)
+#define PN_RAMMAP_RAMIF(n) (((n) << PN_RAMMAP_RAMIF_SHIFT) & \
+ PN_RAMMAP_RAMIF_MASK)
+#define PN_RAMMAP_BASEAD_MASK GENMASK(13, 0)
+#define PN_RAMMAP_BASEAD(offs) (((offs) >> 3) & PN_RAMMAP_BASEAD_MASK)
+#define PN_RAMMAP_DATA(area, ramif, basead) ((PN_RAMMAP_##area) | \
+ (PN_RAMMAP_RAMIF(ramif)) | \
+ (PN_RAMMAP_BASEAD(basead)))
+
+/* PN_CON */
+#define PN_CON_EN BIT(31)
+#define PN_CON_DATAIF_EN BIT(30)
+#define PN_CON_RES_MASK (BIT(17) | BIT(16))
+#define PN_CON_RES_FORCE_STALL BIT(17)
+#define PN_CON_RES_NORMAL BIT(16)
+#define PN_CON_RES_FORCE_NRDY 0
+#define PN_CON_LAST BIT(11)
+#define PN_CON_RES_WEN BIT(7)
+#define PN_CON_CLR BIT(0)
+
+/* PN_INT_STA and PN_INT_ENA */
+#define PN_INT_LSTTR BIT(4)
+#define PN_INT_BFRDY BIT(0)
+
+/* USB3_SSIFCMD */
+#define SSIFCMD_URES_U2 BIT(9)
+#define SSIFCMD_URES_U1 BIT(8)
+#define SSIFCMD_UDIR_U2 BIT(7)
+#define SSIFCMD_UDIR_U1 BIT(6)
+#define SSIFCMD_UREQ_U2 BIT(5)
+#define SSIFCMD_UREQ_U1 BIT(4)
+
+#define USB3_EP0_SS_MAX_PACKET_SIZE 512
+#define USB3_EP0_HSFS_MAX_PACKET_SIZE 64
+#define USB3_EP0_BUF_SIZE 8
+#define USB3_MAX_NUM_PIPES 30
+#define USB3_WAIT_US 3
+
+struct renesas_usb3;
+struct renesas_usb3_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+#define USB3_EP_NAME_SIZE 8
+struct renesas_usb3_ep {
+ struct usb_ep ep;
+ struct renesas_usb3 *usb3;
+ int num;
+ char ep_name[USB3_EP_NAME_SIZE];
+ struct list_head queue;
+ u32 rammap_val;
+ bool dir_in;
+ bool halt;
+ bool wedge;
+ bool started;
+};
+
+struct renesas_usb3_priv {
+ int ramsize_per_ramif; /* unit = bytes */
+ int num_ramif;
+ int ramsize_per_pipe; /* unit = bytes */
+ bool workaround_for_vbus; /* if true, don't check vbus signal */
+};
+
+struct renesas_usb3 {
+ void __iomem *reg;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+
+ struct renesas_usb3_ep *usb3_ep;
+ int num_usb3_eps;
+
+ spinlock_t lock;
+ int disabled_count;
+
+ struct usb_request *ep0_req;
+ u16 test_mode;
+ u8 ep0_buf[USB3_EP0_BUF_SIZE];
+ bool softconnect;
+ bool workaround_for_vbus;
+};
+
+#define gadget_to_renesas_usb3(_gadget) \
+ container_of(_gadget, struct renesas_usb3, gadget)
+#define renesas_usb3_to_gadget(renesas_usb3) (&renesas_usb3->gadget)
+#define usb3_to_dev(_usb3) (_usb3->gadget.dev.parent)
+
+#define usb_ep_to_usb3_ep(_ep) container_of(_ep, struct renesas_usb3_ep, ep)
+#define usb3_ep_to_usb3(_usb3_ep) (_usb3_ep->usb3)
+#define usb_req_to_usb3_req(_req) container_of(_req, \
+ struct renesas_usb3_request, req)
+
+#define usb3_get_ep(usb3, n) ((usb3)->usb3_ep + (n))
+#define usb3_for_each_ep(usb3_ep, usb3, i) \
+ for ((i) = 0, usb3_ep = usb3_get_ep(usb3, (i)); \
+ (i) < (usb3)->num_usb3_eps; \
+ (i)++, usb3_ep = usb3_get_ep(usb3, (i)))
+
+static const char udc_name[] = "renesas_usb3";
+
+static void usb3_write(struct renesas_usb3 *usb3, u32 data, u32 offs)
+{
+ iowrite32(data, usb3->reg + offs);
+}
+
+static u32 usb3_read(struct renesas_usb3 *usb3, u32 offs)
+{
+ return ioread32(usb3->reg + offs);
+}
+
+static void usb3_set_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
+{
+ u32 val = usb3_read(usb3, offs);
+
+ val |= bits;
+ usb3_write(usb3, val, offs);
+}
+
+static void usb3_clear_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
+{
+ u32 val = usb3_read(usb3, offs);
+
+ val &= ~bits;
+ usb3_write(usb3, val, offs);
+}
+
+static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
+ u32 expected)
+{
+ int i;
+
+ for (i = 0; i < USB3_WAIT_US; i++) {
+ if ((usb3_read(usb3, reg) & mask) == expected)
+ return 0;
+ udelay(1);
+ }
+
+ dev_dbg(usb3_to_dev(usb3), "%s: timed out (%8x, %08x, %08x)\n",
+ __func__, reg, mask, expected);
+
+ return -EBUSY;
+}
+
+static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits)
+{
+ usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1);
+}
+
+static void usb3_disable_irq_1(struct renesas_usb3 *usb3, u32 bits)
+{
+ usb3_clear_bit(usb3, bits, USB3_USB_INT_ENA_1);
+}
+
+static void usb3_enable_pipe_irq(struct renesas_usb3 *usb3, int num)
+{
+ usb3_set_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2);
+}
+
+static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
+{
+ usb3_clear_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2);
+}
+
+static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
+{
+ /* Set AXI_INT */
+ usb3_write(usb3, ~0, USB3_DMA_INT_STA);
+ usb3_write(usb3, 0, USB3_DMA_INT_ENA);
+ usb3_set_bit(usb3, AXI_INT_DMAINT | AXI_INT_EPCINT, USB3_AXI_INT_ENA);
+}
+
+static void usb3_init_epc_registers(struct renesas_usb3 *usb3)
+{
+ /* FIXME: How to change host / peripheral mode as well? */
+ usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+
+ usb3_write(usb3, ~0, USB3_USB_INT_STA_1);
+ usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
+}
+
+static bool usb3_wakeup_usb2_phy(struct renesas_usb3 *usb3)
+{
+ if (!(usb3_read(usb3, USB3_USB20_CON) & USB20_CON_B2_SUSPEND))
+ return true; /* already waked it up */
+
+ usb3_clear_bit(usb3, USB20_CON_B2_SUSPEND, USB3_USB20_CON);
+ usb3_enable_irq_1(usb3, USB_INT_1_B2_RSUM);
+
+ return false;
+}
+
+static void usb3_usb2_pullup(struct renesas_usb3 *usb3, int pullup)
+{
+ u32 bits = USB20_CON_B2_PUE | USB20_CON_B2_CONNECT;
+
+ if (usb3->softconnect && pullup)
+ usb3_set_bit(usb3, bits, USB3_USB20_CON);
+ else
+ usb3_clear_bit(usb3, bits, USB3_USB20_CON);
+}
+
+static void usb3_set_test_mode(struct renesas_usb3 *usb3)
+{
+ u32 val = usb3_read(usb3, USB3_USB20_CON);
+
+ val &= ~USB20_CON_B2_TSTMOD_MASK;
+ val |= USB20_CON_B2_TSTMOD(usb3->test_mode);
+ usb3_write(usb3, val | USB20_CON_B2_TSTMOD_EN, USB3_USB20_CON);
+ if (!usb3->test_mode)
+ usb3_clear_bit(usb3, USB20_CON_B2_TSTMOD_EN, USB3_USB20_CON);
+}
+
+static void usb3_start_usb2_connection(struct renesas_usb3 *usb3)
+{
+ usb3->disabled_count++;
+ usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON);
+ usb3_set_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON);
+ usb3_usb2_pullup(usb3, 1);
+}
+
+static int usb3_is_usb3_phy_in_u3(struct renesas_usb3 *usb3)
+{
+ return usb3_read(usb3, USB3_USB30_CON) & USB30_CON_POW_SEL_IN_U3;
+}
+
+static bool usb3_wakeup_usb3_phy(struct renesas_usb3 *usb3)
+{
+ if (!usb3_is_usb3_phy_in_u3(usb3))
+ return true; /* already waked it up */
+
+ usb3_set_bit(usb3, USB30_CON_B3_PLLWAKE, USB3_USB30_CON);
+ usb3_enable_irq_1(usb3, USB_INT_1_B3_PLLWKUP);
+
+ return false;
+}
+
+static u16 usb3_feature_get_un_enabled(struct renesas_usb3 *usb3)
+{
+ u32 mask_u2 = SSIFCMD_UDIR_U2 | SSIFCMD_UREQ_U2;
+ u32 mask_u1 = SSIFCMD_UDIR_U1 | SSIFCMD_UREQ_U1;
+ u32 val = usb3_read(usb3, USB3_SSIFCMD);
+ u16 ret = 0;
+
+ /* Enables {U2,U1} if the bits of UDIR and UREQ are set to 0 */
+ if (!(val & mask_u2))
+ ret |= 1 << USB_DEV_STAT_U2_ENABLED;
+ if (!(val & mask_u1))
+ ret |= 1 << USB_DEV_STAT_U1_ENABLED;
+
+ return ret;
+}
+
+static void usb3_feature_u2_enable(struct renesas_usb3 *usb3, bool enable)
+{
+ u32 bits = SSIFCMD_UDIR_U2 | SSIFCMD_UREQ_U2;
+
+ /* Enables U2 if the bits of UDIR and UREQ are set to 0 */
+ if (enable)
+ usb3_clear_bit(usb3, bits, USB3_SSIFCMD);
+ else
+ usb3_set_bit(usb3, bits, USB3_SSIFCMD);
+}
+
+static void usb3_feature_u1_enable(struct renesas_usb3 *usb3, bool enable)
+{
+ u32 bits = SSIFCMD_UDIR_U1 | SSIFCMD_UREQ_U1;
+
+ /* Enables U1 if the bits of UDIR and UREQ are set to 0 */
+ if (enable)
+ usb3_clear_bit(usb3, bits, USB3_SSIFCMD);
+ else
+ usb3_set_bit(usb3, bits, USB3_SSIFCMD);
+}
+
+static void usb3_start_operation_for_usb3(struct renesas_usb3 *usb3)
+{
+ usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON);
+ usb3_clear_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON);
+ usb3_set_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON);
+}
+
+static void usb3_start_usb3_connection(struct renesas_usb3 *usb3)
+{
+ usb3_start_operation_for_usb3(usb3);
+ usb3_set_bit(usb3, USB_COM_CON_RX_DETECTION, USB3_USB_COM_CON);
+
+ usb3_enable_irq_1(usb3, USB_INT_1_B3_LUPSUCS | USB_INT_1_B3_DISABLE |
+ USB_INT_1_SPEED);
+}
+
+static void usb3_stop_usb3_connection(struct renesas_usb3 *usb3)
+{
+ usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON);
+}
+
+static void usb3_transition_to_default_state(struct renesas_usb3 *usb3,
+ bool is_usb3)
+{
+ usb3_set_bit(usb3, USB_INT_2_PIPE(0), USB3_USB_INT_ENA_2);
+ usb3_write(usb3, P0_INT_ALL_BITS, USB3_P0_INT_STA);
+ usb3_set_bit(usb3, P0_INT_ALL_BITS, USB3_P0_INT_ENA);
+
+ if (is_usb3)
+ usb3_enable_irq_1(usb3, USB_INT_1_B3_WRMRST |
+ USB_INT_1_B3_HOTRST);
+ else
+ usb3_enable_irq_1(usb3, USB_INT_1_B2_SPND |
+ USB_INT_1_B2_L1SPND | USB_INT_1_B2_USBRST);
+}
+
+static void usb3_connect(struct renesas_usb3 *usb3)
+{
+ if (usb3_wakeup_usb3_phy(usb3))
+ usb3_start_usb3_connection(usb3);
+}
+
+static void usb3_reset_epc(struct renesas_usb3 *usb3)
+{
+ usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON);
+ usb3_clear_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON);
+ usb3_set_bit(usb3, USB_COM_CON_PIPE_CLR, USB3_USB_COM_CON);
+ usb3->test_mode = 0;
+ usb3_set_test_mode(usb3);
+}
+
+static void usb3_disconnect(struct renesas_usb3 *usb3)
+{
+ usb3->disabled_count = 0;
+ usb3_usb2_pullup(usb3, 0);
+ usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON);
+ usb3_reset_epc(usb3);
+
+ if (usb3->driver)
+ usb3->driver->disconnect(&usb3->gadget);
+}
+
+static void usb3_check_vbus(struct renesas_usb3 *usb3)
+{
+ if (usb3->workaround_for_vbus) {
+ usb3_connect(usb3);
+ } else {
+ if (usb3_read(usb3, USB3_USB_STA) & USB_STA_VBUS_STA)
+ usb3_connect(usb3);
+ else
+ usb3_disconnect(usb3);
+ }
+}
+
+static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
+{
+ usb3_init_axi_bridge(usb3);
+ usb3_init_epc_registers(usb3);
+
+ usb3_check_vbus(usb3);
+}
+
+static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
+{
+ usb3_disconnect(usb3);
+ usb3_write(usb3, 0, USB3_P0_INT_ENA);
+ usb3_write(usb3, 0, USB3_PN_INT_ENA);
+ usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
+ usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
+ usb3_write(usb3, 0, USB3_AXI_INT_ENA);
+}
+
+static void usb3_irq_epc_int_1_pll_wakeup(struct renesas_usb3 *usb3)
+{
+ usb3_disable_irq_1(usb3, USB_INT_1_B3_PLLWKUP);
+ usb3_clear_bit(usb3, USB30_CON_B3_PLLWAKE, USB3_USB30_CON);
+ usb3_start_usb3_connection(usb3);
+}
+
+static void usb3_irq_epc_int_1_linkup_success(struct renesas_usb3 *usb3)
+{
+ usb3_transition_to_default_state(usb3, true);
+}
+
+static void usb3_irq_epc_int_1_resume(struct renesas_usb3 *usb3)
+{
+ usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM);
+ usb3_start_usb2_connection(usb3);
+ usb3_transition_to_default_state(usb3, false);
+}
+
+static void usb3_irq_epc_int_1_disable(struct renesas_usb3 *usb3)
+{
+ usb3_stop_usb3_connection(usb3);
+ if (usb3_wakeup_usb2_phy(usb3))
+ usb3_irq_epc_int_1_resume(usb3);
+}
+
+static void usb3_irq_epc_int_1_bus_reset(struct renesas_usb3 *usb3)
+{
+ usb3_reset_epc(usb3);
+ if (usb3->disabled_count < 3)
+ usb3_start_usb3_connection(usb3);
+ else
+ usb3_start_usb2_connection(usb3);
+}
+
+static void usb3_irq_epc_int_1_vbus_change(struct renesas_usb3 *usb3)
+{
+ usb3_check_vbus(usb3);
+}
+
+static void usb3_irq_epc_int_1_hot_reset(struct renesas_usb3 *usb3)
+{
+ usb3_reset_epc(usb3);
+ usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON);
+
+ /* This bit shall be set within 12ms from the start of HotReset */
+ usb3_set_bit(usb3, USB30_CON_B3_HOTRST_CMP, USB3_USB30_CON);
+}
+
+static void usb3_irq_epc_int_1_warm_reset(struct renesas_usb3 *usb3)
+{
+ usb3_reset_epc(usb3);
+ usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON);
+
+ usb3_start_operation_for_usb3(usb3);
+ usb3_enable_irq_1(usb3, USB_INT_1_SPEED);
+}
+
+static void usb3_irq_epc_int_1_speed(struct renesas_usb3 *usb3)
+{
+ u32 speed = usb3_read(usb3, USB3_USB_STA) & USB_STA_SPEED_MASK;
+
+ switch (speed) {
+ case USB_STA_SPEED_SS:
+ usb3->gadget.speed = USB_SPEED_SUPER;
+ break;
+ case USB_STA_SPEED_HS:
+ usb3->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case USB_STA_SPEED_FS:
+ usb3->gadget.speed = USB_SPEED_FULL;
+ break;
+ default:
+ usb3->gadget.speed = USB_SPEED_UNKNOWN;
+ break;
+ }
+}
+
+static void usb3_irq_epc_int_1(struct renesas_usb3 *usb3, u32 int_sta_1)
+{
+ if (int_sta_1 & USB_INT_1_B3_PLLWKUP)
+ usb3_irq_epc_int_1_pll_wakeup(usb3);
+
+ if (int_sta_1 & USB_INT_1_B3_LUPSUCS)
+ usb3_irq_epc_int_1_linkup_success(usb3);
+
+ if (int_sta_1 & USB_INT_1_B3_HOTRST)
+ usb3_irq_epc_int_1_hot_reset(usb3);
+
+ if (int_sta_1 & USB_INT_1_B3_WRMRST)
+ usb3_irq_epc_int_1_warm_reset(usb3);
+
+ if (int_sta_1 & USB_INT_1_B3_DISABLE)
+ usb3_irq_epc_int_1_disable(usb3);
+
+ if (int_sta_1 & USB_INT_1_B2_USBRST)
+ usb3_irq_epc_int_1_bus_reset(usb3);
+
+ if (int_sta_1 & USB_INT_1_B2_RSUM)
+ usb3_irq_epc_int_1_resume(usb3);
+
+ if (int_sta_1 & USB_INT_1_SPEED)
+ usb3_irq_epc_int_1_speed(usb3);
+
+ if (int_sta_1 & USB_INT_1_VBUS_CNG)
+ usb3_irq_epc_int_1_vbus_change(usb3);
+}
+
+static struct renesas_usb3_request *__usb3_get_request(struct renesas_usb3_ep
+ *usb3_ep)
+{
+ return list_first_entry_or_null(&usb3_ep->queue,
+ struct renesas_usb3_request, queue);
+}
+
+static struct renesas_usb3_request *usb3_get_request(struct renesas_usb3_ep
+ *usb3_ep)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ struct renesas_usb3_request *usb3_req;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ usb3_req = __usb3_get_request(usb3_ep);
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
+ return usb3_req;
+}
+
+static void usb3_request_done(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req, int status)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n",
+ usb3_ep->num, usb3_req->req.length, usb3_req->req.actual,
+ status);
+ usb3_req->req.status = status;
+ spin_lock_irqsave(&usb3->lock, flags);
+ usb3_ep->started = false;
+ list_del_init(&usb3_req->queue);
+ spin_unlock_irqrestore(&usb3->lock, flags);
+ usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req);
+}
+
+static void usb3_irq_epc_pipe0_status_end(struct renesas_usb3 *usb3)
+{
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0);
+ struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep);
+
+ if (usb3_req)
+ usb3_request_done(usb3_ep, usb3_req, 0);
+ if (usb3->test_mode)
+ usb3_set_test_mode(usb3);
+}
+
+static void usb3_get_setup_data(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl)
+{
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0);
+ u32 *data = (u32 *)ctrl;
+
+ *data++ = usb3_read(usb3, USB3_STUP_DAT_0);
+ *data = usb3_read(usb3, USB3_STUP_DAT_1);
+
+ /* update this driver's flag */
+ usb3_ep->dir_in = !!(ctrl->bRequestType & USB_DIR_IN);
+}
+
+static void usb3_set_p0_con_update_res(struct renesas_usb3 *usb3, u32 res)
+{
+ u32 val = usb3_read(usb3, USB3_P0_CON);
+
+ val &= ~(P0_CON_ST_RES_MASK | P0_CON_OT_RES_MASK | P0_CON_IN_RES_MASK);
+ val |= res | P0_CON_RES_WEN;
+ usb3_write(usb3, val, USB3_P0_CON);
+}
+
+static void usb3_set_p0_con_for_ctrl_read_data(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_NRDY |
+ P0_CON_OT_RES_FORCE_STALL |
+ P0_CON_IN_RES_NORMAL);
+}
+
+static void usb3_set_p0_con_for_ctrl_read_status(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_NORMAL |
+ P0_CON_OT_RES_FORCE_STALL |
+ P0_CON_IN_RES_NORMAL);
+}
+
+static void usb3_set_p0_con_for_ctrl_write_data(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_NRDY |
+ P0_CON_OT_RES_NORMAL |
+ P0_CON_IN_RES_FORCE_STALL);
+}
+
+static void usb3_set_p0_con_for_ctrl_write_status(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_NORMAL |
+ P0_CON_OT_RES_NORMAL |
+ P0_CON_IN_RES_FORCE_STALL);
+}
+
+static void usb3_set_p0_con_for_no_data(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_NORMAL |
+ P0_CON_OT_RES_FORCE_STALL |
+ P0_CON_IN_RES_FORCE_STALL);
+}
+
+static void usb3_set_p0_con_stall(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_STALL |
+ P0_CON_OT_RES_FORCE_STALL |
+ P0_CON_IN_RES_FORCE_STALL);
+}
+
+static void usb3_set_p0_con_stop(struct renesas_usb3 *usb3)
+{
+ usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_NRDY |
+ P0_CON_OT_RES_FORCE_NRDY |
+ P0_CON_IN_RES_FORCE_NRDY);
+}
+
+static int usb3_pn_change(struct renesas_usb3 *usb3, int num)
+{
+ if (num == 0 || num > usb3->num_usb3_eps)
+ return -ENXIO;
+
+ usb3_write(usb3, num, USB3_PIPE_COM);
+
+ return 0;
+}
+
+static void usb3_set_pn_con_update_res(struct renesas_usb3 *usb3, u32 res)
+{
+ u32 val = usb3_read(usb3, USB3_PN_CON);
+
+ val &= ~PN_CON_RES_MASK;
+ val |= res & PN_CON_RES_MASK;
+ val |= PN_CON_RES_WEN;
+ usb3_write(usb3, val, USB3_PN_CON);
+}
+
+static void usb3_pn_start(struct renesas_usb3 *usb3)
+{
+ usb3_set_pn_con_update_res(usb3, PN_CON_RES_NORMAL);
+}
+
+static void usb3_pn_stop(struct renesas_usb3 *usb3)
+{
+ usb3_set_pn_con_update_res(usb3, PN_CON_RES_FORCE_NRDY);
+}
+
+static void usb3_pn_stall(struct renesas_usb3 *usb3)
+{
+ usb3_set_pn_con_update_res(usb3, PN_CON_RES_FORCE_STALL);
+}
+
+static int usb3_pn_con_clear(struct renesas_usb3 *usb3)
+{
+ usb3_set_bit(usb3, PN_CON_CLR, USB3_PN_CON);
+
+ return usb3_wait(usb3, USB3_PN_CON, PN_CON_CLR, 0);
+}
+
+static bool usb3_is_transfer_complete(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req)
+{
+ struct usb_request *req = &usb3_req->req;
+
+ if ((!req->zero && req->actual == req->length) ||
+ (req->actual % usb3_ep->ep.maxpacket) || (req->length == 0))
+ return true;
+ else
+ return false;
+}
+
+static int usb3_wait_pipe_status(struct renesas_usb3_ep *usb3_ep, u32 mask)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ u32 sta_reg = usb3_ep->num ? USB3_PN_STA : USB3_P0_STA;
+
+ return usb3_wait(usb3, sta_reg, mask, mask);
+}
+
+static void usb3_set_px_con_send(struct renesas_usb3_ep *usb3_ep, int bytes,
+ bool last)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ u32 con_reg = usb3_ep->num ? USB3_PN_CON : USB3_P0_CON;
+ u32 val = usb3_read(usb3, con_reg);
+
+ val |= PX_CON_SEND | PX_CON_BYTE_EN_BYTES(bytes);
+ val |= (usb3_ep->num && last) ? PN_CON_LAST : 0;
+ usb3_write(usb3, val, con_reg);
+}
+
+static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req,
+ u32 fifo_reg)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ int i;
+ int len = min_t(unsigned, usb3_req->req.length - usb3_req->req.actual,
+ usb3_ep->ep.maxpacket);
+ u8 *buf = usb3_req->req.buf + usb3_req->req.actual;
+ u32 tmp = 0;
+ bool is_last;
+
+ if (usb3_wait_pipe_status(usb3_ep, PX_STA_BUFSTS) < 0)
+ return -EBUSY;
+
+ /* Update gadget driver parameter */
+ usb3_req->req.actual += len;
+
+ /* Write data to the register */
+ if (len >= 4) {
+ iowrite32_rep(usb3->reg + fifo_reg, buf, len / 4);
+ buf += (len / 4) * 4;
+ len %= 4; /* update len to use usb3_set_pX_con_send() */
+ }
+
+ if (len) {
+ for (i = 0; i < len; i++)
+ tmp |= buf[i] << (8 * i);
+ usb3_write(usb3, tmp, fifo_reg);
+ }
+
+ is_last = usb3_is_transfer_complete(usb3_ep, usb3_req);
+ /* Send the data */
+ usb3_set_px_con_send(usb3_ep, len, is_last);
+
+ return is_last ? 0 : -EAGAIN;
+}
+
+static u32 usb3_get_received_length(struct renesas_usb3_ep *usb3_ep)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ u32 lng_reg = usb3_ep->num ? USB3_PN_LNG : USB3_P0_LNG;
+
+ return usb3_read(usb3, lng_reg);
+}
+
+static int usb3_read_pipe(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req, u32 fifo_reg)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ int i;
+ int len = min_t(unsigned, usb3_req->req.length - usb3_req->req.actual,
+ usb3_get_received_length(usb3_ep));
+ u8 *buf = usb3_req->req.buf + usb3_req->req.actual;
+ u32 tmp = 0;
+
+ if (!len)
+ return 0;
+
+ /* Update gadget driver parameter */
+ usb3_req->req.actual += len;
+
+ /* Read data from the register */
+ if (len >= 4) {
+ ioread32_rep(usb3->reg + fifo_reg, buf, len / 4);
+ buf += (len / 4) * 4;
+ len %= 4;
+ }
+
+ if (len) {
+ tmp = usb3_read(usb3, fifo_reg);
+ for (i = 0; i < len; i++)
+ buf[i] = (tmp >> (8 * i)) & 0xff;
+ }
+
+ return usb3_is_transfer_complete(usb3_ep, usb3_req) ? 0 : -EAGAIN;
+}
+
+static void usb3_set_status_stage(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+
+ if (usb3_ep->dir_in) {
+ usb3_set_p0_con_for_ctrl_read_status(usb3);
+ } else {
+ if (!usb3_req->req.length)
+ usb3_set_p0_con_for_no_data(usb3);
+ else
+ usb3_set_p0_con_for_ctrl_write_status(usb3);
+ }
+}
+
+static void usb3_p0_xfer(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req)
+{
+ int ret = -EAGAIN;
+
+ if (usb3_ep->dir_in)
+ ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_P0_WRITE);
+ else
+ ret = usb3_read_pipe(usb3_ep, usb3_req, USB3_P0_READ);
+
+ if (!ret)
+ usb3_set_status_stage(usb3_ep, usb3_req);
+}
+
+static void usb3_start_pipe0(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+
+ if (usb3_ep->started)
+ return;
+
+ usb3_ep->started = true;
+
+ if (usb3_ep->dir_in) {
+ usb3_set_bit(usb3, P0_MOD_DIR, USB3_P0_MOD);
+ usb3_set_p0_con_for_ctrl_read_data(usb3);
+ } else {
+ usb3_clear_bit(usb3, P0_MOD_DIR, USB3_P0_MOD);
+ usb3_set_p0_con_for_ctrl_write_data(usb3);
+ }
+
+ usb3_p0_xfer(usb3_ep, usb3_req);
+}
+
+static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ struct renesas_usb3_request *usb3_req_first = usb3_get_request(usb3_ep);
+ unsigned long flags;
+ int ret = -EAGAIN;
+ u32 enable_bits = 0;
+
+ if (usb3_ep->halt || usb3_ep->started)
+ return;
+ if (usb3_req != usb3_req_first)
+ return;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ if (usb3_pn_change(usb3, usb3_ep->num) < 0)
+ goto out;
+
+ usb3_ep->started = true;
+ usb3_pn_start(usb3);
+
+ if (usb3_ep->dir_in) {
+ ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_PN_WRITE);
+ enable_bits |= PN_INT_LSTTR;
+ }
+
+ if (ret < 0)
+ enable_bits |= PN_INT_BFRDY;
+
+ if (enable_bits) {
+ usb3_set_bit(usb3, enable_bits, USB3_PN_INT_ENA);
+ usb3_enable_pipe_irq(usb3, usb3_ep->num);
+ }
+out:
+ spin_unlock_irqrestore(&usb3->lock, flags);
+}
+
+static int renesas_usb3_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep);
+ struct renesas_usb3_request *usb3_req = usb_req_to_usb3_req(_req);
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ dev_dbg(usb3_to_dev(usb3), "ep_queue: ep%2d, %u\n", usb3_ep->num,
+ _req->length);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+ spin_lock_irqsave(&usb3->lock, flags);
+ list_add_tail(&usb3_req->queue, &usb3_ep->queue);
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
+ if (!usb3_ep->num)
+ usb3_start_pipe0(usb3_ep, usb3_req);
+ else
+ usb3_start_pipen(usb3_ep, usb3_req);
+
+ return 0;
+}
+
+static void usb3_set_device_address(struct renesas_usb3 *usb3, u16 addr)
+{
+ /* DEV_ADDR bit field is cleared by WarmReset, HotReset and BusReset */
+ usb3_set_bit(usb3, USB_COM_CON_DEV_ADDR(addr), USB3_USB_COM_CON);
+}
+
+static bool usb3_std_req_set_address(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl)
+{
+ if (ctrl->wValue >= 128)
+ return true; /* stall */
+
+ usb3_set_device_address(usb3, ctrl->wValue);
+ usb3_set_p0_con_for_no_data(usb3);
+
+ return false;
+}
+
+static void usb3_pipe0_internal_xfer(struct renesas_usb3 *usb3,
+ void *tx_data, size_t len,
+ void (*complete)(struct usb_ep *ep,
+ struct usb_request *req))
+{
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0);
+
+ if (tx_data)
+ memcpy(usb3->ep0_buf, tx_data,
+ min_t(size_t, len, USB3_EP0_BUF_SIZE));
+
+ usb3->ep0_req->buf = &usb3->ep0_buf;
+ usb3->ep0_req->length = len;
+ usb3->ep0_req->complete = complete;
+ renesas_usb3_ep_queue(&usb3_ep->ep, usb3->ep0_req, GFP_ATOMIC);
+}
+
+static void usb3_pipe0_get_status_completion(struct usb_ep *ep,
+ struct usb_request *req)
+{
+}
+
+static bool usb3_std_req_get_status(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl)
+{
+ bool stall = false;
+ struct renesas_usb3_ep *usb3_ep;
+ int num;
+ u16 status = 0;
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ if (usb3->gadget.is_selfpowered)
+ status |= 1 << USB_DEVICE_SELF_POWERED;
+ if (usb3->gadget.speed == USB_SPEED_SUPER)
+ status |= usb3_feature_get_un_enabled(usb3);
+ break;
+ case USB_RECIP_INTERFACE:
+ break;
+ case USB_RECIP_ENDPOINT:
+ num = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+ usb3_ep = usb3_get_ep(usb3, num);
+ if (usb3_ep->halt)
+ status |= 1 << USB_ENDPOINT_HALT;
+ break;
+ default:
+ stall = true;
+ break;
+ }
+
+ if (!stall) {
+ status = cpu_to_le16(status);
+ dev_dbg(usb3_to_dev(usb3), "get_status: req = %p\n",
+ usb_req_to_usb3_req(usb3->ep0_req));
+ usb3_pipe0_internal_xfer(usb3, &status, sizeof(status),
+ usb3_pipe0_get_status_completion);
+ }
+
+ return stall;
+}
+
+static bool usb3_std_req_feature_device(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl, bool set)
+{
+ bool stall = true;
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ switch (w_value) {
+ case USB_DEVICE_TEST_MODE:
+ if (!set)
+ break;
+ usb3->test_mode = le16_to_cpu(ctrl->wIndex) >> 8;
+ stall = false;
+ break;
+ case USB_DEVICE_U1_ENABLE:
+ case USB_DEVICE_U2_ENABLE:
+ if (usb3->gadget.speed != USB_SPEED_SUPER)
+ break;
+ if (w_value == USB_DEVICE_U1_ENABLE)
+ usb3_feature_u1_enable(usb3, set);
+ if (w_value == USB_DEVICE_U2_ENABLE)
+ usb3_feature_u2_enable(usb3, set);
+ stall = false;
+ break;
+ default:
+ break;
+ }
+
+ return stall;
+}
+
+static int usb3_set_halt_p0(struct renesas_usb3_ep *usb3_ep, bool halt)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+
+ if (unlikely(usb3_ep->num))
+ return -EINVAL;
+
+ usb3_ep->halt = halt;
+ if (halt)
+ usb3_set_p0_con_stall(usb3);
+ else
+ usb3_set_p0_con_stop(usb3);
+
+ return 0;
+}
+
+static int usb3_set_halt_pn(struct renesas_usb3_ep *usb3_ep, bool halt,
+ bool is_clear_feature)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ if (!usb3_pn_change(usb3, usb3_ep->num)) {
+ usb3_ep->halt = halt;
+ if (halt) {
+ usb3_pn_stall(usb3);
+ } else if (!is_clear_feature || !usb3_ep->wedge) {
+ usb3_pn_con_clear(usb3);
+ usb3_set_bit(usb3, PN_CON_EN, USB3_PN_CON);
+ usb3_pn_stop(usb3);
+ }
+ }
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
+ return 0;
+}
+
+static int usb3_set_halt(struct renesas_usb3_ep *usb3_ep, bool halt,
+ bool is_clear_feature)
+{
+ int ret = 0;
+
+ if (halt && usb3_ep->started)
+ return -EAGAIN;
+
+ if (usb3_ep->num)
+ ret = usb3_set_halt_pn(usb3_ep, halt, is_clear_feature);
+ else
+ ret = usb3_set_halt_p0(usb3_ep, halt);
+
+ return ret;
+}
+
+static bool usb3_std_req_feature_endpoint(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl,
+ bool set)
+{
+ int num = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+ struct renesas_usb3_ep *usb3_ep;
+ struct renesas_usb3_request *usb3_req;
+
+ if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT)
+ return true; /* stall */
+
+ usb3_ep = usb3_get_ep(usb3, num);
+ usb3_set_halt(usb3_ep, set, true);
+
+ /* Restarts a queue if clear feature */
+ if (!set) {
+ usb3_ep->started = false;
+ usb3_req = usb3_get_request(usb3_ep);
+ if (usb3_req)
+ usb3_start_pipen(usb3_ep, usb3_req);
+ }
+
+ return false;
+}
+
+static bool usb3_std_req_feature(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl, bool set)
+{
+ bool stall = false;
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ stall = usb3_std_req_feature_device(usb3, ctrl, set);
+ break;
+ case USB_RECIP_INTERFACE:
+ break;
+ case USB_RECIP_ENDPOINT:
+ stall = usb3_std_req_feature_endpoint(usb3, ctrl, set);
+ break;
+ default:
+ stall = true;
+ break;
+ }
+
+ if (!stall)
+ usb3_set_p0_con_for_no_data(usb3);
+
+ return stall;
+}
+
+static void usb3_pipe0_set_sel_completion(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ /* TODO */
+}
+
+static bool usb3_std_req_set_sel(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl)
+{
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ if (w_length != 6)
+ return true; /* stall */
+
+ dev_dbg(usb3_to_dev(usb3), "set_sel: req = %p\n",
+ usb_req_to_usb3_req(usb3->ep0_req));
+ usb3_pipe0_internal_xfer(usb3, NULL, 6, usb3_pipe0_set_sel_completion);
+
+ return false;
+}
+
+static bool usb3_std_req_set_configuration(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl)
+{
+ if (ctrl->wValue > 0)
+ usb3_set_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON);
+ else
+ usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON);
+
+ return false;
+}
+
+/**
+ * usb3_handle_standard_request - handle some standard requests
+ * @usb3: the renesas_usb3 pointer
+ * @ctrl: a pointer of setup data
+ *
+ * Returns true if this function handled a standard request
+ */
+static bool usb3_handle_standard_request(struct renesas_usb3 *usb3,
+ struct usb_ctrlrequest *ctrl)
+{
+ bool ret = false;
+ bool stall = false;
+
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (ctrl->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ stall = usb3_std_req_set_address(usb3, ctrl);
+ ret = true;
+ break;
+ case USB_REQ_GET_STATUS:
+ stall = usb3_std_req_get_status(usb3, ctrl);
+ ret = true;
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ stall = usb3_std_req_feature(usb3, ctrl, false);
+ ret = true;
+ break;
+ case USB_REQ_SET_FEATURE:
+ stall = usb3_std_req_feature(usb3, ctrl, true);
+ ret = true;
+ break;
+ case USB_REQ_SET_SEL:
+ stall = usb3_std_req_set_sel(usb3, ctrl);
+ ret = true;
+ break;
+ case USB_REQ_SET_ISOCH_DELAY:
+ /* This hardware doesn't support Isochronous xfer */
+ stall = true;
+ ret = true;
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ usb3_std_req_set_configuration(usb3, ctrl);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (stall)
+ usb3_set_p0_con_stall(usb3);
+
+ return ret;
+}
+
+static int usb3_p0_con_clear_buffer(struct renesas_usb3 *usb3)
+{
+ usb3_set_bit(usb3, P0_CON_BCLR, USB3_P0_CON);
+
+ return usb3_wait(usb3, USB3_P0_CON, P0_CON_BCLR, 0);
+}
+
+static void usb3_irq_epc_pipe0_setup(struct renesas_usb3 *usb3)
+{
+ struct usb_ctrlrequest ctrl;
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0);
+
+ /* Call giveback function if previous transfer is not completed */
+ if (usb3_ep->started)
+ usb3_request_done(usb3_ep, usb3_get_request(usb3_ep),
+ -ECONNRESET);
+
+ usb3_p0_con_clear_buffer(usb3);
+ usb3_get_setup_data(usb3, &ctrl);
+ if (!usb3_handle_standard_request(usb3, &ctrl))
+ if (usb3->driver->setup(&usb3->gadget, &ctrl) < 0)
+ usb3_set_p0_con_stall(usb3);
+}
+
+static void usb3_irq_epc_pipe0_bfrdy(struct renesas_usb3 *usb3)
+{
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0);
+ struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep);
+
+ if (!usb3_req)
+ return;
+
+ usb3_p0_xfer(usb3_ep, usb3_req);
+}
+
+static void usb3_irq_epc_pipe0(struct renesas_usb3 *usb3)
+{
+ u32 p0_int_sta = usb3_read(usb3, USB3_P0_INT_STA);
+
+ p0_int_sta &= usb3_read(usb3, USB3_P0_INT_ENA);
+ usb3_write(usb3, p0_int_sta, USB3_P0_INT_STA);
+ if (p0_int_sta & P0_INT_STSED)
+ usb3_irq_epc_pipe0_status_end(usb3);
+ if (p0_int_sta & P0_INT_SETUP)
+ usb3_irq_epc_pipe0_setup(usb3);
+ if (p0_int_sta & P0_INT_BFRDY)
+ usb3_irq_epc_pipe0_bfrdy(usb3);
+}
+
+static void usb3_request_done_pipen(struct renesas_usb3 *usb3,
+ struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req,
+ int status)
+{
+ usb3_pn_stop(usb3);
+ usb3_disable_pipe_irq(usb3, usb3_ep->num);
+ usb3_request_done(usb3_ep, usb3_req, status);
+
+ /* get next usb3_req */
+ usb3_req = usb3_get_request(usb3_ep);
+ if (usb3_req)
+ usb3_start_pipen(usb3_ep, usb3_req);
+}
+
+static void usb3_irq_epc_pipen_lsttr(struct renesas_usb3 *usb3, int num)
+{
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, num);
+ struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep);
+
+ if (!usb3_req)
+ return;
+
+ if (usb3_ep->dir_in) {
+ dev_dbg(usb3_to_dev(usb3), "%s: len = %u, actual = %u\n",
+ __func__, usb3_req->req.length, usb3_req->req.actual);
+ usb3_request_done_pipen(usb3, usb3_ep, usb3_req, 0);
+ }
+}
+
+static void usb3_irq_epc_pipen_bfrdy(struct renesas_usb3 *usb3, int num)
+{
+ struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, num);
+ struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep);
+
+ if (!usb3_req)
+ return;
+
+ if (usb3_ep->dir_in) {
+ /* Do not stop the IN pipe here to detect LSTTR interrupt */
+ if (!usb3_write_pipe(usb3_ep, usb3_req, USB3_PN_WRITE))
+ usb3_clear_bit(usb3, PN_INT_BFRDY, USB3_PN_INT_ENA);
+ } else {
+ if (!usb3_read_pipe(usb3_ep, usb3_req, USB3_PN_READ))
+ usb3_request_done_pipen(usb3, usb3_ep, usb3_req, 0);
+ }
+}
+
+static void usb3_irq_epc_pipen(struct renesas_usb3 *usb3, int num)
+{
+ u32 pn_int_sta;
+
+ if (usb3_pn_change(usb3, num) < 0)
+ return;
+
+ pn_int_sta = usb3_read(usb3, USB3_PN_INT_STA);
+ pn_int_sta &= usb3_read(usb3, USB3_PN_INT_ENA);
+ usb3_write(usb3, pn_int_sta, USB3_PN_INT_STA);
+ if (pn_int_sta & PN_INT_LSTTR)
+ usb3_irq_epc_pipen_lsttr(usb3, num);
+ if (pn_int_sta & PN_INT_BFRDY)
+ usb3_irq_epc_pipen_bfrdy(usb3, num);
+}
+
+static void usb3_irq_epc_int_2(struct renesas_usb3 *usb3, u32 int_sta_2)
+{
+ int i;
+
+ for (i = 0; i < usb3->num_usb3_eps; i++) {
+ if (int_sta_2 & USB_INT_2_PIPE(i)) {
+ if (!i)
+ usb3_irq_epc_pipe0(usb3);
+ else
+ usb3_irq_epc_pipen(usb3, i);
+ }
+ }
+}
+
+static void usb3_irq_epc(struct renesas_usb3 *usb3)
+{
+ u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1);
+ u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2);
+
+ int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1);
+ if (int_sta_1) {
+ usb3_write(usb3, int_sta_1, USB3_USB_INT_STA_1);
+ usb3_irq_epc_int_1(usb3, int_sta_1);
+ }
+
+ int_sta_2 &= usb3_read(usb3, USB3_USB_INT_ENA_2);
+ if (int_sta_2)
+ usb3_irq_epc_int_2(usb3, int_sta_2);
+}
+
+static irqreturn_t renesas_usb3_irq(int irq, void *_usb3)
+{
+ struct renesas_usb3 *usb3 = _usb3;
+ irqreturn_t ret = IRQ_NONE;
+ u32 axi_int_sta = usb3_read(usb3, USB3_AXI_INT_STA);
+
+ if (axi_int_sta & AXI_INT_EPCINT) {
+ usb3_irq_epc(usb3);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static void usb3_write_pn_mod(struct renesas_usb3_ep *usb3_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ u32 val = 0;
+
+ val |= usb3_ep->dir_in ? PN_MOD_DIR : 0;
+ val |= PN_MOD_TYPE(usb_endpoint_type(desc));
+ val |= PN_MOD_EPNUM(usb_endpoint_num(desc));
+ usb3_write(usb3, val, USB3_PN_MOD);
+}
+
+static u32 usb3_calc_ramarea(int ram_size)
+{
+ WARN_ON(ram_size > SZ_16K);
+
+ if (ram_size <= SZ_1K)
+ return PN_RAMMAP_RAMAREA_1KB;
+ else if (ram_size <= SZ_2K)
+ return PN_RAMMAP_RAMAREA_2KB;
+ else if (ram_size <= SZ_4K)
+ return PN_RAMMAP_RAMAREA_4KB;
+ else if (ram_size <= SZ_8K)
+ return PN_RAMMAP_RAMAREA_8KB;
+ else
+ return PN_RAMMAP_RAMAREA_16KB;
+}
+
+static u32 usb3_calc_rammap_val(struct renesas_usb3_ep *usb3_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ return usb3_ep->rammap_val | PN_RAMMAP_MPKT(usb_endpoint_maxp(desc));
+}
+
+static int usb3_enable_pipe_n(struct renesas_usb3_ep *usb3_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ usb3_ep->dir_in = usb_endpoint_dir_in(desc);
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ if (!usb3_pn_change(usb3, usb3_ep->num)) {
+ usb3_write_pn_mod(usb3_ep, desc);
+ usb3_write(usb3, usb3_calc_rammap_val(usb3_ep, desc),
+ USB3_PN_RAMMAP);
+ usb3_pn_con_clear(usb3);
+ usb3_set_bit(usb3, PN_CON_EN, USB3_PN_CON);
+ }
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
+ return 0;
+}
+
+static int usb3_disable_pipe_n(struct renesas_usb3_ep *usb3_ep)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ usb3_ep->halt = false;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ if (!usb3_pn_change(usb3, usb3_ep->num)) {
+ usb3_write(usb3, 0, USB3_PN_RAMMAP);
+ usb3_clear_bit(usb3, PN_CON_EN, USB3_PN_CON);
+ }
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
+ return 0;
+}
+
+/*------- usb_ep_ops -----------------------------------------------------*/
+static int renesas_usb3_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep);
+
+ return usb3_enable_pipe_n(usb3_ep, desc);
+}
+
+static int renesas_usb3_ep_disable(struct usb_ep *_ep)
+{
+ struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep);
+ struct renesas_usb3_request *usb3_req;
+
+ do {
+ usb3_req = usb3_get_request(usb3_ep);
+ if (!usb3_req)
+ break;
+ usb3_request_done(usb3_ep, usb3_req, -ESHUTDOWN);
+ } while (1);
+
+ return usb3_disable_pipe_n(usb3_ep);
+}
+
+static struct usb_request *__renesas_usb3_ep_alloc_request(gfp_t gfp_flags)
+{
+ struct renesas_usb3_request *usb3_req;
+
+ usb3_req = kzalloc(sizeof(struct renesas_usb3_request), gfp_flags);
+ if (!usb3_req)
+ return NULL;
+
+ INIT_LIST_HEAD(&usb3_req->queue);
+
+ return &usb3_req->req;
+}
+
+static void __renesas_usb3_ep_free_request(struct usb_request *_req)
+{
+ struct renesas_usb3_request *usb3_req = usb_req_to_usb3_req(_req);
+
+ kfree(usb3_req);
+}
+
+static struct usb_request *renesas_usb3_ep_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ return __renesas_usb3_ep_alloc_request(gfp_flags);
+}
+
+static void renesas_usb3_ep_free_request(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ __renesas_usb3_ep_free_request(_req);
+}
+
+static int renesas_usb3_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep);
+ struct renesas_usb3_request *usb3_req = usb_req_to_usb3_req(_req);
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+
+ dev_dbg(usb3_to_dev(usb3), "ep_dequeue: ep%2d, %u\n", usb3_ep->num,
+ _req->length);
+
+ usb3_request_done_pipen(usb3, usb3_ep, usb3_req, -ECONNRESET);
+
+ return 0;
+}
+
+static int renesas_usb3_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ return usb3_set_halt(usb_ep_to_usb3_ep(_ep), !!value, false);
+}
+
+static int renesas_usb3_ep_set_wedge(struct usb_ep *_ep)
+{
+ struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep);
+
+ usb3_ep->wedge = true;
+ return usb3_set_halt(usb3_ep, true, false);
+}
+
+static void renesas_usb3_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep);
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+ unsigned long flags;
+
+ if (usb3_ep->num) {
+ spin_lock_irqsave(&usb3->lock, flags);
+ if (!usb3_pn_change(usb3, usb3_ep->num)) {
+ usb3_pn_con_clear(usb3);
+ usb3_set_bit(usb3, PN_CON_EN, USB3_PN_CON);
+ }
+ spin_unlock_irqrestore(&usb3->lock, flags);
+ } else {
+ usb3_p0_con_clear_buffer(usb3);
+ }
+}
+
+static struct usb_ep_ops renesas_usb3_ep_ops = {
+ .enable = renesas_usb3_ep_enable,
+ .disable = renesas_usb3_ep_disable,
+
+ .alloc_request = renesas_usb3_ep_alloc_request,
+ .free_request = renesas_usb3_ep_free_request,
+
+ .queue = renesas_usb3_ep_queue,
+ .dequeue = renesas_usb3_ep_dequeue,
+
+ .set_halt = renesas_usb3_ep_set_halt,
+ .set_wedge = renesas_usb3_ep_set_wedge,
+ .fifo_flush = renesas_usb3_ep_fifo_flush,
+};
+
+/*------- usb_gadget_ops -------------------------------------------------*/
+static int renesas_usb3_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct renesas_usb3 *usb3;
+
+ if (!driver || driver->max_speed < USB_SPEED_FULL ||
+ !driver->setup)
+ return -EINVAL;
+
+ usb3 = gadget_to_renesas_usb3(gadget);
+
+ /* hook up the driver */
+ usb3->driver = driver;
+
+ renesas_usb3_init_controller(usb3);
+
+ return 0;
+}
+
+static int renesas_usb3_stop(struct usb_gadget *gadget)
+{
+ struct renesas_usb3 *usb3 = gadget_to_renesas_usb3(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ usb3->softconnect = false;
+ usb3->gadget.speed = USB_SPEED_UNKNOWN;
+ usb3->driver = NULL;
+ renesas_usb3_stop_controller(usb3);
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
+ return 0;
+}
+
+static int renesas_usb3_get_frame(struct usb_gadget *_gadget)
+{
+ return -EOPNOTSUPP;
+}
+
+static int renesas_usb3_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct renesas_usb3 *usb3 = gadget_to_renesas_usb3(gadget);
+
+ usb3->softconnect = !!is_on;
+
+ return 0;
+}
+
+static int renesas_usb3_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+ gadget->is_selfpowered = !!is_self;
+
+ return 0;
+}
+
+static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
+ .get_frame = renesas_usb3_get_frame,
+ .udc_start = renesas_usb3_start,
+ .udc_stop = renesas_usb3_stop,
+ .pullup = renesas_usb3_pullup,
+ .set_selfpowered = renesas_usb3_set_selfpowered,
+};
+
+/*------- platform_driver ------------------------------------------------*/
+static int renesas_usb3_remove(struct platform_device *pdev)
+{
+ struct renesas_usb3 *usb3 = platform_get_drvdata(pdev);
+
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ usb_del_gadget_udc(&usb3->gadget);
+
+ __renesas_usb3_ep_free_request(usb3->ep0_req);
+
+ return 0;
+}
+
+static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev,
+ const struct renesas_usb3_priv *priv)
+{
+ struct renesas_usb3_ep *usb3_ep;
+ int i;
+
+ /* calculate num_usb3_eps from renesas_usb3_priv */
+ usb3->num_usb3_eps = priv->ramsize_per_ramif * priv->num_ramif * 2 /
+ priv->ramsize_per_pipe + 1;
+
+ if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES)
+ usb3->num_usb3_eps = USB3_MAX_NUM_PIPES;
+
+ usb3->usb3_ep = devm_kzalloc(dev, sizeof(*usb3_ep) * usb3->num_usb3_eps,
+ GFP_KERNEL);
+ if (!usb3->usb3_ep)
+ return -ENOMEM;
+
+ dev_dbg(dev, "%s: num_usb3_eps = %d\n", __func__, usb3->num_usb3_eps);
+ /*
+ * This driver prepares pipes as the followings:
+ * - odd pipes = IN pipe
+ * - even pipes = OUT pipe (except pipe 0)
+ */
+ usb3_for_each_ep(usb3_ep, usb3, i) {
+ snprintf(usb3_ep->ep_name, sizeof(usb3_ep->ep_name), "ep%d", i);
+ usb3_ep->usb3 = usb3;
+ usb3_ep->num = i;
+ usb3_ep->ep.name = usb3_ep->ep_name;
+ usb3_ep->ep.ops = &renesas_usb3_ep_ops;
+ INIT_LIST_HEAD(&usb3_ep->queue);
+ INIT_LIST_HEAD(&usb3_ep->ep.ep_list);
+ if (!i) {
+ /* for control pipe */
+ usb3->gadget.ep0 = &usb3_ep->ep;
+ usb_ep_set_maxpacket_limit(&usb3_ep->ep,
+ USB3_EP0_HSFS_MAX_PACKET_SIZE);
+ usb3_ep->ep.caps.type_control = true;
+ usb3_ep->ep.caps.dir_in = true;
+ usb3_ep->ep.caps.dir_out = true;
+ continue;
+ }
+
+ /* for bulk or interrupt pipe */
+ usb_ep_set_maxpacket_limit(&usb3_ep->ep, ~0);
+ list_add_tail(&usb3_ep->ep.ep_list, &usb3->gadget.ep_list);
+ usb3_ep->ep.caps.type_bulk = true;
+ usb3_ep->ep.caps.type_int = true;
+ if (i & 1)
+ usb3_ep->ep.caps.dir_in = true;
+ else
+ usb3_ep->ep.caps.dir_out = true;
+ }
+
+ return 0;
+}
+
+static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev,
+ const struct renesas_usb3_priv *priv)
+{
+ struct renesas_usb3_ep *usb3_ep;
+ int i;
+ u32 ramif[2], basead[2]; /* index 0 = for IN pipes */
+ u32 *cur_ramif, *cur_basead;
+ u32 val;
+
+ memset(ramif, 0, sizeof(ramif));
+ memset(basead, 0, sizeof(basead));
+
+ /*
+ * This driver prepares pipes as the followings:
+ * - all pipes = the same size as "ramsize_per_pipe"
+ * Please refer to the "Method of Specifying RAM Mapping"
+ */
+ usb3_for_each_ep(usb3_ep, usb3, i) {
+ if (!i)
+ continue; /* out of scope if ep num = 0 */
+ if (usb3_ep->ep.caps.dir_in) {
+ cur_ramif = &ramif[0];
+ cur_basead = &basead[0];
+ } else {
+ cur_ramif = &ramif[1];
+ cur_basead = &basead[1];
+ }
+
+ if (*cur_basead > priv->ramsize_per_ramif)
+ continue; /* out of memory for IN or OUT pipe */
+
+ /* calculate rammap_val */
+ val = PN_RAMMAP_RAMIF(*cur_ramif);
+ val |= usb3_calc_ramarea(priv->ramsize_per_pipe);
+ val |= PN_RAMMAP_BASEAD(*cur_basead);
+ usb3_ep->rammap_val = val;
+
+ dev_dbg(dev, "ep%2d: val = %08x, ramif = %d, base = %x\n",
+ i, val, *cur_ramif, *cur_basead);
+
+ /* update current ramif */
+ if (*cur_ramif + 1 == priv->num_ramif) {
+ *cur_ramif = 0;
+ *cur_basead += priv->ramsize_per_pipe;
+ } else {
+ (*cur_ramif)++;
+ }
+ }
+}
+
+static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795 = {
+ .ramsize_per_ramif = SZ_16K,
+ .num_ramif = 2,
+ .ramsize_per_pipe = SZ_4K,
+ .workaround_for_vbus = true,
+};
+
+static const struct of_device_id usb3_of_match[] = {
+ {
+ .compatible = "renesas,r8a7795-usb3-peri",
+ .data = &renesas_usb3_priv_r8a7795,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, usb3_of_match);
+
+static int renesas_usb3_probe(struct platform_device *pdev)
+{
+ struct renesas_usb3 *usb3;
+ struct resource *res;
+ const struct of_device_id *match;
+ int irq, ret;
+ const struct renesas_usb3_priv *priv;
+
+ match = of_match_node(usb3_of_match, pdev->dev.of_node);
+ if (!match)
+ return -ENODEV;
+ priv = match->data;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+
+ usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
+ if (!usb3)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ usb3->reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(usb3->reg))
+ return PTR_ERR(usb3->reg);
+
+ platform_set_drvdata(pdev, usb3);
+ spin_lock_init(&usb3->lock);
+
+ usb3->gadget.ops = &renesas_usb3_gadget_ops;
+ usb3->gadget.name = udc_name;
+ usb3->gadget.max_speed = USB_SPEED_SUPER;
+ INIT_LIST_HEAD(&usb3->gadget.ep_list);
+ ret = renesas_usb3_init_ep(usb3, &pdev->dev, priv);
+ if (ret < 0)
+ return ret;
+ renesas_usb3_init_ram(usb3, &pdev->dev, priv);
+
+ ret = devm_request_irq(&pdev->dev, irq, renesas_usb3_irq, 0,
+ dev_name(&pdev->dev), usb3);
+ if (ret < 0)
+ return ret;
+
+ /* for ep0 handling */
+ usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL);
+ if (!usb3->ep0_req)
+ return -ENOMEM;
+
+ ret = usb_add_gadget_udc(&pdev->dev, &usb3->gadget);
+ if (ret < 0)
+ goto err_add_udc;
+
+ usb3->workaround_for_vbus = priv->workaround_for_vbus;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ dev_info(&pdev->dev, "probed\n");
+
+ return 0;
+
+err_add_udc:
+ __renesas_usb3_ep_free_request(usb3->ep0_req);
+
+ return ret;
+}
+
+static struct platform_driver renesas_usb3_driver = {
+ .probe = renesas_usb3_probe,
+ .remove = renesas_usb3_remove,
+ .driver = {
+ .name = (char *)udc_name,
+ .of_match_table = of_match_ptr(usb3_of_match),
+ },
+};
+module_platform_driver(renesas_usb3_driver);
+
+MODULE_DESCRIPTION("Renesas USB3.0 Peripheral driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");
+MODULE_ALIAS("platform:renesas_usb3");
diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c
index e9def42ce50d..82a9e2a3bedc 100644
--- a/drivers/usb/gadget/udc/s3c-hsudc.c
+++ b/drivers/usb/gadget/udc/s3c-hsudc.c
@@ -569,7 +569,7 @@ static int s3c_hsudc_handle_reqfeat(struct s3c_hsudc *hsudc,
hsep = &hsudc->ep[ep_num];
switch (le16_to_cpu(ctrl->wValue)) {
case USB_ENDPOINT_HALT:
- if (set || (!set && !hsep->wedge))
+ if (set || !hsep->wedge)
s3c_hsudc_set_halt(&hsep->ep, set);
return 0;
}
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index f660afba715d..fd73a3ea07c2 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -51,8 +51,12 @@ struct usb_udc {
static struct class *udc_class;
static LIST_HEAD(udc_list);
+static LIST_HEAD(gadget_driver_pending_list);
static DEFINE_MUTEX(udc_lock);
+static int udc_bind_to_driver(struct usb_udc *udc,
+ struct usb_gadget_driver *driver);
+
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_HAS_DMA
@@ -356,6 +360,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
struct usb_udc *udc;
+ struct usb_gadget_driver *driver;
int ret = -ENOMEM;
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
@@ -403,6 +408,18 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
+ /* pick up one of pending gadget drivers */
+ list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
+ if (!driver->udc_name || strcmp(driver->udc_name,
+ dev_name(&udc->dev)) == 0) {
+ ret = udc_bind_to_driver(udc, driver);
+ if (ret)
+ goto err4;
+ list_del(&driver->pending);
+ break;
+ }
+ }
+
mutex_unlock(&udc_lock);
return 0;
@@ -473,10 +490,14 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_del(&udc->list);
- mutex_unlock(&udc_lock);
- if (udc->driver)
+ if (udc->driver) {
+ struct usb_gadget_driver *driver = udc->driver;
+
usb_gadget_remove_driver(udc);
+ list_add(&driver->pending, &gadget_driver_pending_list);
+ }
+ mutex_unlock(&udc_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
flush_work(&gadget->work);
@@ -520,50 +541,36 @@ err1:
return ret;
}
-int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver)
-{
- struct usb_udc *udc = NULL;
- int ret = -ENODEV;
-
- mutex_lock(&udc_lock);
- list_for_each_entry(udc, &udc_list, list) {
- ret = strcmp(name, dev_name(&udc->dev));
- if (!ret)
- break;
- }
- if (ret) {
- ret = -ENODEV;
- goto out;
- }
- if (udc->driver) {
- ret = -EBUSY;
- goto out;
- }
- ret = udc_bind_to_driver(udc, driver);
-out:
- mutex_unlock(&udc_lock);
- return ret;
-}
-EXPORT_SYMBOL_GPL(usb_udc_attach_driver);
-
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
struct usb_udc *udc = NULL;
- int ret;
+ int ret = -ENODEV;
if (!driver || !driver->bind || !driver->setup)
return -EINVAL;
mutex_lock(&udc_lock);
- list_for_each_entry(udc, &udc_list, list) {
- /* For now we take the first one */
- if (!udc->driver)
+ if (driver->udc_name) {
+ list_for_each_entry(udc, &udc_list, list) {
+ ret = strcmp(driver->udc_name, dev_name(&udc->dev));
+ if (!ret)
+ break;
+ }
+ if (!ret && !udc->driver)
goto found;
+ } else {
+ list_for_each_entry(udc, &udc_list, list) {
+ /* For now we take the first one */
+ if (!udc->driver)
+ goto found;
+ }
}
- pr_debug("couldn't find an available UDC\n");
+ list_add_tail(&driver->pending, &gadget_driver_pending_list);
+ pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
+ driver->function);
mutex_unlock(&udc_lock);
- return -ENODEV;
+ return 0;
found:
ret = udc_bind_to_driver(udc, driver);
mutex_unlock(&udc_lock);
@@ -589,6 +596,10 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
break;
}
+ if (ret) {
+ list_del(&driver->pending);
+ ret = 0;
+ }
mutex_unlock(&udc_lock);
return ret;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 3bb08870148f..daa563ff1fa0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -41,6 +41,15 @@ config USB_XHCI_PLATFORM
If unsure, say N.
+config USB_XHCI_MTK
+ tristate "xHCI support for Mediatek MT65xx"
+ select MFD_SYSCON
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ ---help---
+ Say 'Y' to enable the support for the xHCI host controller
+ found in Mediatek MT65xx SoCs.
+ If unsure, say N.
+
config USB_XHCI_MVEBU
tristate "xHCI support for Marvell Armada 375/38x"
select USB_XHCI_PLATFORM
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index e7558abc994d..65a06b4382bf 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -13,6 +13,9 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-y += xhci-trace.o
+ifneq ($(CONFIG_USB_XHCI_MTK), )
+ xhci-hcd-y += xhci-mtk-sch.o
+endif
xhci-plat-hcd-y := xhci-plat.o
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
@@ -64,6 +67,7 @@ obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
+obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 5398e3d42822..291aaa2baed8 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -21,6 +21,7 @@
*/
#include <linux/bcma/bcma.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -36,6 +37,7 @@ MODULE_LICENSE("GPL");
struct bcma_hcd_device {
struct platform_device *ehci_dev;
struct platform_device *ohci_dev;
+ struct gpio_desc *gpio_desc;
};
/* Wait for bitmask in a register to get set or cleared.
@@ -228,19 +230,12 @@ static void bcma_hcd_init_chip_arm(struct bcma_device *dev)
static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
{
- int gpio;
+ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
- gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0);
- if (!gpio_is_valid(gpio))
+ if (IS_ERR_OR_NULL(usb_dev->gpio_desc))
return;
- if (val) {
- gpio_request(gpio, "bcma-hcd-gpio");
- gpio_set_value(gpio, 1);
- } else {
- gpio_set_value(gpio, 0);
- gpio_free(gpio);
- }
+ gpiod_set_value(usb_dev->gpio_desc, val);
}
static const struct usb_ehci_pdata ehci_pdata = {
@@ -314,7 +309,11 @@ static int bcma_hcd_probe(struct bcma_device *dev)
if (!usb_dev)
return -ENOMEM;
- bcma_hci_platform_power_gpio(dev, true);
+ if (dev->dev.of_node)
+ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
+ &dev->dev.of_node->fwnode);
+ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
+ gpiod_direction_output(usb_dev->gpio_desc, 1);
switch (dev->id.id) {
case BCMA_CORE_NS_USB20:
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index b26b96e25a13..b7d623f1523c 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -436,7 +436,8 @@ static void qh_lines (
scratch = hc32_to_cpup(ehci, &hw->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
temp = scnprintf (next, size,
- "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
+ "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)"
+ " [cur %08x next %08x buf[0] %08x]",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
@@ -444,7 +445,10 @@ static void qh_lines (
hc32_to_cpup(ehci, &hw->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
? "data1" : "data0",
- (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
+ (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f,
+ hc32_to_cpup(ehci, &hw->hw_current),
+ hc32_to_cpup(ehci, &hw->hw_qtd_next),
+ hc32_to_cpup(ehci, &hw->hw_buf[0]));
size -= temp;
next += temp;
@@ -464,7 +468,8 @@ static void qh_lines (
mark = '/';
}
temp = snprintf (next, size,
- "\n\t%p%c%s len=%d %08x urb %p",
+ "\n\t%p%c%s len=%d %08x urb %p"
+ " [td %08x buf[0] %08x]",
td, mark, ({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break;
@@ -474,7 +479,9 @@ static void qh_lines (
} tmp;}),
(scratch >> 16) & 0x7fff,
scratch,
- td->urb);
+ td->urb,
+ (u32) td->qtd_dma,
+ hc32_to_cpup(ehci, &td->hw_buf[0]));
if (size < temp)
temp = size;
size -= temp;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 48c92bf78bd0..14178bbf0694 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -98,7 +98,7 @@ module_param (park, uint, S_IRUGO);
MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
/* for flakey hardware, ignore overcurrent indicators */
-static bool ignore_oc = 0;
+static bool ignore_oc;
module_param (ignore_oc, bool, S_IRUGO);
MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index b6205fac3567..4de43011df23 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -128,21 +128,13 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
ehci->dummy = NULL;
/* DMA consistent memory and pools */
- if (ehci->qtd_pool)
- dma_pool_destroy (ehci->qtd_pool);
+ dma_pool_destroy(ehci->qtd_pool);
ehci->qtd_pool = NULL;
-
- if (ehci->qh_pool) {
- dma_pool_destroy (ehci->qh_pool);
- ehci->qh_pool = NULL;
- }
-
- if (ehci->itd_pool)
- dma_pool_destroy (ehci->itd_pool);
+ dma_pool_destroy(ehci->qh_pool);
+ ehci->qh_pool = NULL;
+ dma_pool_destroy(ehci->itd_pool);
ehci->itd_pool = NULL;
-
- if (ehci->sitd_pool)
- dma_pool_destroy (ehci->sitd_pool);
+ dma_pool_destroy(ehci->sitd_pool);
ehci->sitd_pool = NULL;
if (ehci->periodic)
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index c4f84c81de01..c23e2858c815 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -57,8 +57,8 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
/* bursts of unspecified length. */
writel(0, USB_AHBBURST);
- /* Use the AHB transactor */
- writel(0, USB_AHBMODE);
+ /* Use the AHB transactor, allow posted data writes */
+ writel(0x8, USB_AHBMODE);
/* Disable streaming mode and select host mode */
writel(0x13, USB_USBMODE);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 54f5332f814d..aad0777240d3 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -132,10 +132,14 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
* qtd is updated in qh_completions(). Update the QH
* overlay here.
*/
- if (qh->hw->hw_token & ACTIVE_BIT(ehci))
+ if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
qh->hw->hw_qtd_next = qtd->hw_next;
- else
+ if (qh->should_be_inactive)
+ ehci_warn(ehci, "qh %p should be inactive!\n", qh);
+ } else {
qh_update(ehci, qh, qtd);
+ }
+ qh->should_be_inactive = 0;
}
/*-------------------------------------------------------------------------*/
@@ -438,6 +442,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
(hw->hw_token & ACTIVE_BIT(ehci))) {
token = hc32_to_cpu(ehci, hw->hw_token);
hw->hw_token &= ~ACTIVE_BIT(ehci);
+ qh->should_be_inactive = 1;
/* An unlink may leave an incomplete
* async transaction in the TT buffer.
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 46f62e41bcde..ec61aedb0067 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -439,6 +439,7 @@ struct ehci_qh {
unsigned dequeue_during_giveback:1;
unsigned exception:1; /* got a fault, or an unlink
was requested */
+ unsigned should_be_inactive:1;
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index c6cebb96fd21..0960f41f945a 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -31,7 +31,7 @@
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include <asm/fsl_gtm.h>
#include "fhci.h"
diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c
index 3bacdd7befe9..60d55eb3de0d 100644
--- a/drivers/usb/host/fhci-hub.c
+++ b/drivers/usb/host/fhci-hub.c
@@ -24,7 +24,7 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/gpio.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include "fhci.h"
/* virtual root hub specific descriptor */
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 95ca5986e672..a9609a336efe 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -25,7 +25,7 @@
#include <linux/io.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/qe.h>
#include <asm/fsl_gtm.h>
#include "fhci.h"
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index 1498061f0aea..f82ad5df1b0d 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -85,7 +85,7 @@ static struct usb_td __iomem *next_bd(struct usb_td __iomem *base,
void fhci_push_dummy_bd(struct endpoint *ep)
{
- if (ep->already_pushed_dummy_bd == false) {
+ if (!ep->already_pushed_dummy_bd) {
u16 td_status = in_be16(&ep->empty_td->status);
out_be32(&ep->empty_td->buf_ptr, DUMMY_BD_BUFFER);
diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h
index 154e6a007727..3fc82c1c3c73 100644
--- a/drivers/usb/host/fhci.h
+++ b/drivers/usb/host/fhci.h
@@ -27,8 +27,8 @@
#include <linux/io.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
-#include <asm/qe.h>
-#include <asm/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
#define USB_CLOCK 48000000
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 760cb57e954e..04dcedfdebf8 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -99,13 +99,13 @@ static void io_watchdog_func(unsigned long _ohci);
/* Some boards misreport power switching/overcurrent */
-static bool distrust_firmware = 1;
+static bool distrust_firmware = true;
module_param (distrust_firmware, bool, 0);
MODULE_PARM_DESC (distrust_firmware,
"true to distrust firmware power/overcurrent setup");
/* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */
-static bool no_handshake = 0;
+static bool no_handshake;
module_param (no_handshake, bool, 0);
MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index ba1bec7db026..e8c006e7a960 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -365,19 +365,19 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
if (!pdata)
return -ENOMEM;
- if (of_get_property(np, "marvell,enable-port1", NULL))
+ if (of_property_read_bool(np, "marvell,enable-port1"))
pdata->flags |= ENABLE_PORT1;
- if (of_get_property(np, "marvell,enable-port2", NULL))
+ if (of_property_read_bool(np, "marvell,enable-port2"))
pdata->flags |= ENABLE_PORT2;
- if (of_get_property(np, "marvell,enable-port3", NULL))
+ if (of_property_read_bool(np, "marvell,enable-port3"))
pdata->flags |= ENABLE_PORT3;
- if (of_get_property(np, "marvell,port-sense-low", NULL))
+ if (of_property_read_bool(np, "marvell,port-sense-low"))
pdata->flags |= POWER_SENSE_LOW;
- if (of_get_property(np, "marvell,power-control-low", NULL))
+ if (of_property_read_bool(np, "marvell,power-control-low"))
pdata->flags |= POWER_CONTROL_LOW;
- if (of_get_property(np, "marvell,no-oc-protection", NULL))
+ if (of_property_read_bool(np, "marvell,no-oc-protection"))
pdata->flags |= NO_OC_PROTECTION;
- if (of_get_property(np, "marvell,oc-mode-perport", NULL))
+ if (of_property_read_bool(np, "marvell,oc-mode-perport"))
pdata->flags |= OC_MODE_PERPORT;
if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp))
pdata->power_on_delay = tmp;
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 1f139d82cee0..bc74aca8a54c 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -394,8 +394,7 @@ static void ehci_quiesce(struct oxu_hcd *oxu)
u32 temp;
#ifdef DEBUG
- if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
- BUG();
+ BUG_ON(!HC_IS_RUNNING(oxu_to_hcd(oxu)->state));
#endif
/* wait for any schedule enables/disables to take effect */
@@ -1709,9 +1708,8 @@ static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
#ifdef DEBUG
assert_spin_locked(&oxu->lock);
- if (oxu->reclaim || (qh->qh_state != QH_STATE_LINKED
- && qh->qh_state != QH_STATE_UNLINK_WAIT))
- BUG();
+ BUG_ON(oxu->reclaim || (qh->qh_state != QH_STATE_LINKED
+ && qh->qh_state != QH_STATE_UNLINK_WAIT));
#endif
/* stop async schedule right now? */
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index f9400564cb72..26cb8c861e6e 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -984,24 +984,17 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
* Find the Legacy Support Capability register -
* this is optional for xHCI host controllers.
*/
- ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
- do {
- if ((ext_cap_offset + sizeof(val)) > len) {
- /* We're reading garbage from the controller */
- dev_warn(&pdev->dev,
- "xHCI controller failing to respond");
- return;
- }
+ ext_cap_offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_LEGACY);
- if (!ext_cap_offset)
- /* We've reached the end of the extended capabilities */
- goto hc_init;
+ if (!ext_cap_offset)
+ goto hc_init;
- val = readl(base + ext_cap_offset);
- if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
- break;
- ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset);
- } while (1);
+ if ((ext_cap_offset + sizeof(val)) > len) {
+ /* We're reading garbage from the controller */
+ dev_warn(&pdev->dev, "xHCI controller failing to respond");
+ return;
+ }
+ val = readl(base + ext_cap_offset);
/* If the BIOS owns the HC, signal that the OS wants it, and wait */
if (val & XHCI_HC_BIOS_OWNED) {
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 692ccc69345e..05c85c7baf84 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -73,7 +73,7 @@ MODULE_LICENSE("GPL");
#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
INT_MODULE_PARM(testing, 0);
/* Some boards misreport power switching/overcurrent*/
-static bool distrust_firmware = 1;
+static bool distrust_firmware = true;
module_param(distrust_firmware, bool, 0);
MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
"t setup");
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index da6f56d996ce..c17ea1589b83 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -248,11 +248,10 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
dma_addr_t dma_handle;
struct uhci_qh *qh;
- qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
+ qh = dma_pool_zalloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
if (!qh)
return NULL;
- memset(qh, 0, sizeof(*qh));
qh->dma_handle = dma_handle;
qh->element = UHCI_PTR_TERM(uhci);
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index 9f1c0538b211..1a8e960d073b 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -30,10 +30,9 @@ struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
struct whc_qset *qset;
dma_addr_t dma;
- qset = dma_pool_alloc(whc->qset_pool, mem_flags, &dma);
+ qset = dma_pool_zalloc(whc->qset_pool, mem_flags, &dma);
if (qset == NULL)
return NULL;
- memset(qset, 0, sizeof(struct whc_qset));
qset->qset_dma = dma;
qset->whc = whc;
@@ -400,7 +399,7 @@ static void urb_dequeue_work(struct work_struct *work)
struct whc *whc = qset->whc;
unsigned long flags;
- if (wurb->is_async == true)
+ if (wurb->is_async)
asl_update(whc, WUSBCMD_ASYNC_UPDATED
| WUSBCMD_ASYNC_SYNCED_DB
| WUSBCMD_ASYNC_QSET_RM);
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 9fe3225e6c61..04ce6b156b35 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -91,66 +91,39 @@
#include <linux/io.h>
/**
- * Return the next extended capability pointer register.
- *
- * @base PCI register base address.
- *
- * @ext_offset Offset of the 32-bit register that contains the extended
- * capabilites pointer. If searching for the first extended capability, pass
- * in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability,
- * pass in the offset of the current extended capability register.
- *
- * Returns 0 if there is no next extended capability register or returns the register offset
- * from the PCI registers base address.
- */
-static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
-{
- u32 next;
-
- next = readl(base + ext_offset);
-
- if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
- /* Find the first extended capability */
- next = XHCI_HCC_EXT_CAPS(next);
- ext_offset = 0;
- } else {
- /* Find the next extended capability */
- next = XHCI_EXT_CAPS_NEXT(next);
- }
-
- if (!next)
- return 0;
- /*
- * Address calculation from offset of extended capabilities
- * (or HCCPARAMS) register - see section 5.3.6 and section 7.
- */
- return ext_offset + (next << 2);
-}
-
-/**
* Find the offset of the extended capabilities with capability ID id.
*
- * @base PCI MMIO registers base address.
- * @ext_offset Offset from base of the first extended capability to look at,
- * or the address of HCCPARAMS.
- * @id Extended capability ID to search for.
+ * @base PCI MMIO registers base address.
+ * @start address at which to start looking, (0 or HCC_PARAMS to start at
+ * beginning of list)
+ * @id Extended capability ID to search for.
*
- * This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities
- * to make sure that the list doesn't contain a loop.
+ * Returns the offset of the next matching extended capability structure.
+ * Some capabilities can occur several times, e.g., the XHCI_EXT_CAPS_PROTOCOL,
+ * and this provides a way to find them all.
*/
-static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id)
+
+static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id)
{
u32 val;
- int limit = XHCI_MAX_EXT_CAPS;
-
- while (ext_offset && limit > 0) {
- val = readl(base + ext_offset);
- if (XHCI_EXT_CAPS_ID(val) == id)
- break;
- ext_offset = xhci_find_next_cap_offset(base, ext_offset);
- limit--;
- }
- if (limit > 0)
- return ext_offset;
+ u32 next;
+ u32 offset;
+
+ offset = start;
+ if (!start || start == XHCI_HCC_PARAMS_OFFSET) {
+ val = readl(base + XHCI_HCC_PARAMS_OFFSET);
+ offset = XHCI_HCC_EXT_CAPS(val) << 2;
+ if (!offset)
+ return 0;
+ };
+ do {
+ val = readl(base + offset);
+ if (XHCI_EXT_CAPS_ID(val) == id && offset != start)
+ return offset;
+
+ next = XHCI_EXT_CAPS_NEXT(val);
+ offset += next << 2;
+ } while (next);
+
return 0;
}
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index f980c239eded..b30b4ce294d3 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -855,7 +855,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
xhci_hub_report_usb2_link_state(&status, raw_port_status);
}
if (bus_state->port_c_suspend & (1 << wIndex))
- status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ status |= USB_PORT_STAT_C_SUSPEND << 16;
return status;
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index c48cbe731356..5cd080e0a685 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -47,13 +47,12 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
if (!seg)
return NULL;
- seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
+ seg->trbs = dma_pool_zalloc(xhci->segment_pool, flags, &dma);
if (!seg->trbs) {
kfree(seg);
return NULL;
}
- memset(seg->trbs, 0, TRB_SEGMENT_SIZE);
/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
if (cycle_state == 0) {
for (i = 0; i < TRBS_PER_SEGMENT; i++)
@@ -517,12 +516,11 @@ static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci
if (type == XHCI_CTX_TYPE_INPUT)
ctx->size += CTX_SIZE(xhci->hcc_params);
- ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma);
+ ctx->bytes = dma_pool_zalloc(xhci->device_pool, flags, &ctx->dma);
if (!ctx->bytes) {
kfree(ctx);
return NULL;
}
- memset(ctx->bytes, 0, ctx->size);
return ctx;
}
@@ -1245,7 +1243,7 @@ static unsigned int xhci_microframes_to_exponent(struct usb_device *udev,
interval = fls(desc_interval) - 1;
interval = clamp_val(interval, min_exponent, max_exponent);
if ((1 << interval) != desc_interval)
- dev_warn(&udev->dev,
+ dev_dbg(&udev->dev,
"ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
ep->desc.bEndpointAddress,
1 << interval,
@@ -2064,17 +2062,19 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
}
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
- __le32 __iomem *addr, u8 major_revision, int max_caps)
+ __le32 __iomem *addr, int max_caps)
{
u32 temp, port_offset, port_count;
int i;
+ u8 major_revision;
struct xhci_hub *rhub;
temp = readl(addr);
+ major_revision = XHCI_EXT_PORT_MAJOR(temp);
- if (XHCI_EXT_PORT_MAJOR(temp) == 0x03) {
+ if (major_revision == 0x03) {
rhub = &xhci->usb3_rhub;
- } else if (XHCI_EXT_PORT_MAJOR(temp) <= 0x02) {
+ } else if (major_revision <= 0x02) {
rhub = &xhci->usb2_rhub;
} else {
xhci_warn(xhci, "Ignoring unknown port speed, "
@@ -2190,19 +2190,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
*/
static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
{
- __le32 __iomem *addr, *tmp_addr;
- u32 offset, tmp_offset;
+ void __iomem *base;
+ u32 offset;
unsigned int num_ports;
int i, j, port_index;
int cap_count = 0;
-
- addr = &xhci->cap_regs->hcc_params;
- offset = XHCI_HCC_EXT_CAPS(readl(addr));
- if (offset == 0) {
- xhci_err(xhci, "No Extended Capability registers, "
- "unable to set up roothub.\n");
- return -ENODEV;
- }
+ u32 cap_start;
num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
@@ -2220,48 +2213,34 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
for (j = 0; j < XHCI_MAX_INTERVAL; j++)
INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
}
+ base = &xhci->cap_regs->hc_capbase;
- /*
- * For whatever reason, the first capability offset is from the
- * capability register base, not from the HCCPARAMS register.
- * See section 5.3.6 for offset calculation.
- */
- addr = &xhci->cap_regs->hc_capbase + offset;
-
- tmp_addr = addr;
- tmp_offset = offset;
+ cap_start = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_PROTOCOL);
+ if (!cap_start) {
+ xhci_err(xhci, "No Extended Capability registers, unable to set up roothub\n");
+ return -ENODEV;
+ }
+ offset = cap_start;
/* count extended protocol capability entries for later caching */
- do {
- u32 cap_id;
- cap_id = readl(tmp_addr);
- if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
- cap_count++;
- tmp_offset = XHCI_EXT_CAPS_NEXT(cap_id);
- tmp_addr += tmp_offset;
- } while (tmp_offset);
+ while (offset) {
+ cap_count++;
+ offset = xhci_find_next_ext_cap(base, offset,
+ XHCI_EXT_CAPS_PROTOCOL);
+ }
xhci->ext_caps = kzalloc(sizeof(*xhci->ext_caps) * cap_count, flags);
if (!xhci->ext_caps)
return -ENOMEM;
- while (1) {
- u32 cap_id;
-
- cap_id = readl(addr);
- if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
- xhci_add_in_port(xhci, num_ports, addr,
- (u8) XHCI_EXT_PORT_MAJOR(cap_id),
- cap_count);
- offset = XHCI_EXT_CAPS_NEXT(cap_id);
- if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports)
- == num_ports)
+ offset = cap_start;
+
+ while (offset) {
+ xhci_add_in_port(xhci, num_ports, base + offset, cap_count);
+ if (xhci->num_usb2_ports + xhci->num_usb3_ports == num_ports)
break;
- /*
- * Once you're into the Extended Capabilities, the offset is
- * always relative to the register holding the offset.
- */
- addr += offset;
+ offset = xhci_find_next_ext_cap(base, offset,
+ XHCI_EXT_CAPS_PROTOCOL);
}
if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
new file mode 100644
index 000000000000..c30de7c39f44
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author:
+ * Zhigang.Wei <zhigang.wei@mediatek.com>
+ * Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "xhci.h"
+#include "xhci-mtk.h"
+
+#define SS_BW_BOUNDARY 51000
+/* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */
+#define HS_BW_BOUNDARY 6144
+/* usb2 spec section11.18.1: at most 188 FS bytes per microframe */
+#define FS_PAYLOAD_MAX 188
+
+/* mtk scheduler bitmasks */
+#define EP_BPKTS(p) ((p) & 0x3f)
+#define EP_BCSCOUNT(p) (((p) & 0x7) << 8)
+#define EP_BBM(p) ((p) << 11)
+#define EP_BOFFSET(p) ((p) & 0x3fff)
+#define EP_BREPEAT(p) (((p) & 0x7fff) << 16)
+
+static int is_fs_or_ls(enum usb_device_speed speed)
+{
+ return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW;
+}
+
+/*
+* get the index of bandwidth domains array which @ep belongs to.
+*
+* the bandwidth domain array is saved to @sch_array of struct xhci_hcd_mtk,
+* each HS root port is treated as a single bandwidth domain,
+* but each SS root port is treated as two bandwidth domains, one for IN eps,
+* one for OUT eps.
+* @real_port value is defined as follow according to xHCI spec:
+* 1 for SSport0, ..., N+1 for SSportN, N+2 for HSport0, N+3 for HSport1, etc
+* so the bandwidth domain array is organized as follow for simplification:
+* SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY
+*/
+static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct xhci_virt_device *virt_dev;
+ int bw_index;
+
+ virt_dev = xhci->devs[udev->slot_id];
+
+ if (udev->speed == USB_SPEED_SUPER) {
+ if (usb_endpoint_dir_out(&ep->desc))
+ bw_index = (virt_dev->real_port - 1) * 2;
+ else
+ bw_index = (virt_dev->real_port - 1) * 2 + 1;
+ } else {
+ /* add one more for each SS port */
+ bw_index = virt_dev->real_port + xhci->num_usb3_ports - 1;
+ }
+
+ return bw_index;
+}
+
+static void setup_sch_info(struct usb_device *udev,
+ struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep)
+{
+ u32 ep_type;
+ u32 ep_interval;
+ u32 max_packet_size;
+ u32 max_burst;
+ u32 mult;
+ u32 esit_pkts;
+
+ ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
+ ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info));
+ max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
+ max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2));
+ mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info));
+
+ sch_ep->esit = 1 << ep_interval;
+ sch_ep->offset = 0;
+ sch_ep->burst_mode = 0;
+
+ if (udev->speed == USB_SPEED_HIGH) {
+ sch_ep->cs_count = 0;
+
+ /*
+ * usb_20 spec section5.9
+ * a single microframe is enough for HS synchromous endpoints
+ * in a interval
+ */
+ sch_ep->num_budget_microframes = 1;
+ sch_ep->repeat = 0;
+
+ /*
+ * xHCI spec section6.2.3.4
+ * @max_burst is the number of additional transactions
+ * opportunities per microframe
+ */
+ sch_ep->pkts = max_burst + 1;
+ sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
+ } else if (udev->speed == USB_SPEED_SUPER) {
+ /* usb3_r1 spec section4.4.7 & 4.4.8 */
+ sch_ep->cs_count = 0;
+ esit_pkts = (mult + 1) * (max_burst + 1);
+ if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
+ sch_ep->pkts = esit_pkts;
+ sch_ep->num_budget_microframes = 1;
+ sch_ep->repeat = 0;
+ }
+
+ if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) {
+ if (esit_pkts <= sch_ep->esit)
+ sch_ep->pkts = 1;
+ else
+ sch_ep->pkts = roundup_pow_of_two(esit_pkts)
+ / sch_ep->esit;
+
+ sch_ep->num_budget_microframes =
+ DIV_ROUND_UP(esit_pkts, sch_ep->pkts);
+
+ if (sch_ep->num_budget_microframes > 1)
+ sch_ep->repeat = 1;
+ else
+ sch_ep->repeat = 0;
+ }
+ sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
+ } else if (is_fs_or_ls(udev->speed)) {
+
+ /*
+ * usb_20 spec section11.18.4
+ * assume worst cases
+ */
+ sch_ep->repeat = 0;
+ sch_ep->pkts = 1; /* at most one packet for each microframe */
+ if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
+ sch_ep->cs_count = 3; /* at most need 3 CS*/
+ /* one for SS and one for budgeted transaction */
+ sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
+ sch_ep->bw_cost_per_microframe = max_packet_size;
+ }
+ if (ep_type == ISOC_OUT_EP) {
+
+ /*
+ * the best case FS budget assumes that 188 FS bytes
+ * occur in each microframe
+ */
+ sch_ep->num_budget_microframes = DIV_ROUND_UP(
+ max_packet_size, FS_PAYLOAD_MAX);
+ sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
+ sch_ep->cs_count = sch_ep->num_budget_microframes;
+ }
+ if (ep_type == ISOC_IN_EP) {
+ /* at most need additional two CS. */
+ sch_ep->cs_count = DIV_ROUND_UP(
+ max_packet_size, FS_PAYLOAD_MAX) + 2;
+ sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
+ sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
+ }
+ }
+}
+
+/* Get maximum bandwidth when we schedule at offset slot. */
+static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw,
+ struct mu3h_sch_ep_info *sch_ep, u32 offset)
+{
+ u32 num_esit;
+ u32 max_bw = 0;
+ int i;
+ int j;
+
+ num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
+ for (i = 0; i < num_esit; i++) {
+ u32 base = offset + i * sch_ep->esit;
+
+ for (j = 0; j < sch_ep->num_budget_microframes; j++) {
+ if (sch_bw->bus_bw[base + j] > max_bw)
+ max_bw = sch_bw->bus_bw[base + j];
+ }
+ }
+ return max_bw;
+}
+
+static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
+ struct mu3h_sch_ep_info *sch_ep, int bw_cost)
+{
+ u32 num_esit;
+ u32 base;
+ int i;
+ int j;
+
+ num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
+ for (i = 0; i < num_esit; i++) {
+ base = sch_ep->offset + i * sch_ep->esit;
+ for (j = 0; j < sch_ep->num_budget_microframes; j++)
+ sch_bw->bus_bw[base + j] += bw_cost;
+ }
+}
+
+static int check_sch_bw(struct usb_device *udev,
+ struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
+{
+ u32 offset;
+ u32 esit;
+ u32 num_budget_microframes;
+ u32 min_bw;
+ u32 min_index;
+ u32 worst_bw;
+ u32 bw_boundary;
+
+ if (sch_ep->esit > XHCI_MTK_MAX_ESIT)
+ sch_ep->esit = XHCI_MTK_MAX_ESIT;
+
+ esit = sch_ep->esit;
+ num_budget_microframes = sch_ep->num_budget_microframes;
+
+ /*
+ * Search through all possible schedule microframes.
+ * and find a microframe where its worst bandwidth is minimum.
+ */
+ min_bw = ~0;
+ min_index = 0;
+ for (offset = 0; offset < esit; offset++) {
+ if ((offset + num_budget_microframes) > sch_ep->esit)
+ break;
+
+ /*
+ * usb_20 spec section11.18:
+ * must never schedule Start-Split in Y6
+ */
+ if (is_fs_or_ls(udev->speed) && (offset % 8 == 6))
+ continue;
+
+ worst_bw = get_max_bw(sch_bw, sch_ep, offset);
+ if (min_bw > worst_bw) {
+ min_bw = worst_bw;
+ min_index = offset;
+ }
+ if (min_bw == 0)
+ break;
+ }
+ sch_ep->offset = min_index;
+
+ bw_boundary = (udev->speed == USB_SPEED_SUPER)
+ ? SS_BW_BOUNDARY : HS_BW_BOUNDARY;
+
+ /* check bandwidth */
+ if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary)
+ return -ERANGE;
+
+ /* update bus bandwidth info */
+ update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe);
+
+ return 0;
+}
+
+static bool need_bw_sch(struct usb_host_endpoint *ep,
+ enum usb_device_speed speed, int has_tt)
+{
+ /* only for periodic endpoints */
+ if (usb_endpoint_xfer_control(&ep->desc)
+ || usb_endpoint_xfer_bulk(&ep->desc))
+ return false;
+
+ /*
+ * for LS & FS periodic endpoints which its device don't attach
+ * to TT are also ignored, root-hub will schedule them directly
+ */
+ if (is_fs_or_ls(speed) && !has_tt)
+ return false;
+
+ return true;
+}
+
+int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
+{
+ struct mu3h_sch_bw_info *sch_array;
+ int num_usb_bus;
+ int i;
+
+ /* ss IN and OUT are separated */
+ num_usb_bus = mtk->num_u3_ports * 2 + mtk->num_u2_ports;
+
+ sch_array = kcalloc(num_usb_bus, sizeof(*sch_array), GFP_KERNEL);
+ if (sch_array == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < num_usb_bus; i++)
+ INIT_LIST_HEAD(&sch_array[i].bw_ep_list);
+
+ mtk->sch_array = sch_array;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
+
+void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk)
+{
+ kfree(mtk->sch_array);
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_sch_exit);
+
+int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+ struct xhci_hcd *xhci;
+ struct xhci_ep_ctx *ep_ctx;
+ struct xhci_slot_ctx *slot_ctx;
+ struct xhci_virt_device *virt_dev;
+ struct mu3h_sch_bw_info *sch_bw;
+ struct mu3h_sch_ep_info *sch_ep;
+ struct mu3h_sch_bw_info *sch_array;
+ unsigned int ep_index;
+ int bw_index;
+ int ret = 0;
+
+ xhci = hcd_to_xhci(hcd);
+ virt_dev = xhci->devs[udev->slot_id];
+ ep_index = xhci_get_endpoint_index(&ep->desc);
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
+ sch_array = mtk->sch_array;
+
+ xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
+ __func__, usb_endpoint_type(&ep->desc), udev->speed,
+ GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)),
+ usb_endpoint_dir_in(&ep->desc), ep);
+
+ if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
+ return 0;
+
+ bw_index = get_bw_index(xhci, udev, ep);
+ sch_bw = &sch_array[bw_index];
+
+ sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO);
+ if (!sch_ep)
+ return -ENOMEM;
+
+ setup_sch_info(udev, ep_ctx, sch_ep);
+
+ ret = check_sch_bw(udev, sch_bw, sch_ep);
+ if (ret) {
+ xhci_err(xhci, "Not enough bandwidth!\n");
+ kfree(sch_ep);
+ return -ENOSPC;
+ }
+
+ list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
+ sch_ep->ep = ep;
+
+ ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
+ | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
+ ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
+ | EP_BREPEAT(sch_ep->repeat));
+
+ xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
+ sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
+ sch_ep->offset, sch_ep->repeat);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
+
+void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+ struct xhci_hcd *xhci;
+ struct xhci_slot_ctx *slot_ctx;
+ struct xhci_virt_device *virt_dev;
+ struct mu3h_sch_bw_info *sch_array;
+ struct mu3h_sch_bw_info *sch_bw;
+ struct mu3h_sch_ep_info *sch_ep;
+ int bw_index;
+
+ xhci = hcd_to_xhci(hcd);
+ virt_dev = xhci->devs[udev->slot_id];
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ sch_array = mtk->sch_array;
+
+ xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n",
+ __func__, usb_endpoint_type(&ep->desc), udev->speed,
+ GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)),
+ usb_endpoint_dir_in(&ep->desc), ep);
+
+ if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
+ return;
+
+ bw_index = get_bw_index(xhci, udev, ep);
+ sch_bw = &sch_array[bw_index];
+
+ list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
+ if (sch_ep->ep == ep) {
+ update_bus_bw(sch_bw, sch_ep,
+ -sch_ep->bw_cost_per_microframe);
+ list_del(&sch_ep->endpoint);
+ kfree(sch_ep);
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
new file mode 100644
index 000000000000..c9ab6a44c34a
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk.c
@@ -0,0 +1,763 @@
+/*
+ * MediaTek xHCI Host Controller Driver
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author:
+ * Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include "xhci.h"
+#include "xhci-mtk.h"
+
+/* ip_pw_ctrl0 register */
+#define CTRL0_IP_SW_RST BIT(0)
+
+/* ip_pw_ctrl1 register */
+#define CTRL1_IP_HOST_PDN BIT(0)
+
+/* ip_pw_ctrl2 register */
+#define CTRL2_IP_DEV_PDN BIT(0)
+
+/* ip_pw_sts1 register */
+#define STS1_IP_SLEEP_STS BIT(30)
+#define STS1_XHCI_RST BIT(11)
+#define STS1_SYS125_RST BIT(10)
+#define STS1_REF_RST BIT(8)
+#define STS1_SYSPLL_STABLE BIT(0)
+
+/* ip_xhci_cap register */
+#define CAP_U3_PORT_NUM(p) ((p) & 0xff)
+#define CAP_U2_PORT_NUM(p) (((p) >> 8) & 0xff)
+
+/* u3_ctrl_p register */
+#define CTRL_U3_PORT_HOST_SEL BIT(2)
+#define CTRL_U3_PORT_PDN BIT(1)
+#define CTRL_U3_PORT_DIS BIT(0)
+
+/* u2_ctrl_p register */
+#define CTRL_U2_PORT_HOST_SEL BIT(2)
+#define CTRL_U2_PORT_PDN BIT(1)
+#define CTRL_U2_PORT_DIS BIT(0)
+
+/* u2_phy_pll register */
+#define CTRL_U2_FORCE_PLL_STB BIT(28)
+
+#define PERI_WK_CTRL0 0x400
+#define UWK_CTR0_0P_LS_PE BIT(8) /* posedge */
+#define UWK_CTR0_0P_LS_NE BIT(7) /* negedge for 0p linestate*/
+#define UWK_CTL1_1P_LS_C(x) (((x) & 0xf) << 1)
+#define UWK_CTL1_1P_LS_E BIT(0)
+
+#define PERI_WK_CTRL1 0x404
+#define UWK_CTL1_IS_C(x) (((x) & 0xf) << 26)
+#define UWK_CTL1_IS_E BIT(25)
+#define UWK_CTL1_0P_LS_C(x) (((x) & 0xf) << 21)
+#define UWK_CTL1_0P_LS_E BIT(20)
+#define UWK_CTL1_IDDIG_C(x) (((x) & 0xf) << 11) /* cycle debounce */
+#define UWK_CTL1_IDDIG_E BIT(10) /* enable debounce */
+#define UWK_CTL1_IDDIG_P BIT(9) /* polarity */
+#define UWK_CTL1_0P_LS_P BIT(7)
+#define UWK_CTL1_IS_P BIT(6) /* polarity for ip sleep */
+
+enum ssusb_wakeup_src {
+ SSUSB_WK_IP_SLEEP = 1,
+ SSUSB_WK_LINE_STATE = 2,
+};
+
+static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
+{
+ struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
+ u32 value, check_val;
+ int ret;
+ int i;
+
+ /* power on host ip */
+ value = readl(&ippc->ip_pw_ctr1);
+ value &= ~CTRL1_IP_HOST_PDN;
+ writel(value, &ippc->ip_pw_ctr1);
+
+ /* power on and enable all u3 ports */
+ for (i = 0; i < mtk->num_u3_ports; i++) {
+ value = readl(&ippc->u3_ctrl_p[i]);
+ value &= ~(CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS);
+ value |= CTRL_U3_PORT_HOST_SEL;
+ writel(value, &ippc->u3_ctrl_p[i]);
+ }
+
+ /* power on and enable all u2 ports */
+ for (i = 0; i < mtk->num_u2_ports; i++) {
+ value = readl(&ippc->u2_ctrl_p[i]);
+ value &= ~(CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS);
+ value |= CTRL_U2_PORT_HOST_SEL;
+ writel(value, &ippc->u2_ctrl_p[i]);
+ }
+
+ /*
+ * wait for clocks to be stable, and clock domains reset to
+ * be inactive after power on and enable ports
+ */
+ check_val = STS1_SYSPLL_STABLE | STS1_REF_RST |
+ STS1_SYS125_RST | STS1_XHCI_RST;
+
+ ret = readl_poll_timeout(&ippc->ip_pw_sts1, value,
+ (check_val == (value & check_val)), 100, 20000);
+ if (ret) {
+ dev_err(mtk->dev, "clocks are not stable (0x%x)\n", value);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xhci_mtk_host_disable(struct xhci_hcd_mtk *mtk)
+{
+ struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
+ u32 value;
+ int ret;
+ int i;
+
+ /* power down all u3 ports */
+ for (i = 0; i < mtk->num_u3_ports; i++) {
+ value = readl(&ippc->u3_ctrl_p[i]);
+ value |= CTRL_U3_PORT_PDN;
+ writel(value, &ippc->u3_ctrl_p[i]);
+ }
+
+ /* power down all u2 ports */
+ for (i = 0; i < mtk->num_u2_ports; i++) {
+ value = readl(&ippc->u2_ctrl_p[i]);
+ value |= CTRL_U2_PORT_PDN;
+ writel(value, &ippc->u2_ctrl_p[i]);
+ }
+
+ /* power down host ip */
+ value = readl(&ippc->ip_pw_ctr1);
+ value |= CTRL1_IP_HOST_PDN;
+ writel(value, &ippc->ip_pw_ctr1);
+
+ /* wait for host ip to sleep */
+ ret = readl_poll_timeout(&ippc->ip_pw_sts1, value,
+ (value & STS1_IP_SLEEP_STS), 100, 100000);
+ if (ret) {
+ dev_err(mtk->dev, "ip sleep failed!!!\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int xhci_mtk_ssusb_config(struct xhci_hcd_mtk *mtk)
+{
+ struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
+ u32 value;
+
+ /* reset whole ip */
+ value = readl(&ippc->ip_pw_ctr0);
+ value |= CTRL0_IP_SW_RST;
+ writel(value, &ippc->ip_pw_ctr0);
+ udelay(1);
+ value = readl(&ippc->ip_pw_ctr0);
+ value &= ~CTRL0_IP_SW_RST;
+ writel(value, &ippc->ip_pw_ctr0);
+
+ /*
+ * device ip is default power-on in fact
+ * power down device ip, otherwise ip-sleep will fail
+ */
+ value = readl(&ippc->ip_pw_ctr2);
+ value |= CTRL2_IP_DEV_PDN;
+ writel(value, &ippc->ip_pw_ctr2);
+
+ value = readl(&ippc->ip_xhci_cap);
+ mtk->num_u3_ports = CAP_U3_PORT_NUM(value);
+ mtk->num_u2_ports = CAP_U2_PORT_NUM(value);
+ dev_dbg(mtk->dev, "%s u2p:%d, u3p:%d\n", __func__,
+ mtk->num_u2_ports, mtk->num_u3_ports);
+
+ return xhci_mtk_host_enable(mtk);
+}
+
+static int xhci_mtk_clks_enable(struct xhci_hcd_mtk *mtk)
+{
+ int ret;
+
+ ret = clk_prepare_enable(mtk->sys_clk);
+ if (ret) {
+ dev_err(mtk->dev, "failed to enable sys_clk\n");
+ goto sys_clk_err;
+ }
+
+ if (mtk->wakeup_src) {
+ ret = clk_prepare_enable(mtk->wk_deb_p0);
+ if (ret) {
+ dev_err(mtk->dev, "failed to enable wk_deb_p0\n");
+ goto usb_p0_err;
+ }
+
+ ret = clk_prepare_enable(mtk->wk_deb_p1);
+ if (ret) {
+ dev_err(mtk->dev, "failed to enable wk_deb_p1\n");
+ goto usb_p1_err;
+ }
+ }
+ return 0;
+
+usb_p1_err:
+ clk_disable_unprepare(mtk->wk_deb_p0);
+usb_p0_err:
+ clk_disable_unprepare(mtk->sys_clk);
+sys_clk_err:
+ return -EINVAL;
+}
+
+static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk)
+{
+ if (mtk->wakeup_src) {
+ clk_disable_unprepare(mtk->wk_deb_p1);
+ clk_disable_unprepare(mtk->wk_deb_p0);
+ }
+ clk_disable_unprepare(mtk->sys_clk);
+}
+
+/* only clocks can be turn off for ip-sleep wakeup mode */
+static void usb_wakeup_ip_sleep_en(struct xhci_hcd_mtk *mtk)
+{
+ u32 tmp;
+ struct regmap *pericfg = mtk->pericfg;
+
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ tmp &= ~UWK_CTL1_IS_P;
+ tmp &= ~(UWK_CTL1_IS_C(0xf));
+ tmp |= UWK_CTL1_IS_C(0x8);
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp);
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
+
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ dev_dbg(mtk->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
+ __func__, tmp);
+}
+
+static void usb_wakeup_ip_sleep_dis(struct xhci_hcd_mtk *mtk)
+{
+ u32 tmp;
+
+ regmap_read(mtk->pericfg, PERI_WK_CTRL1, &tmp);
+ tmp &= ~UWK_CTL1_IS_E;
+ regmap_write(mtk->pericfg, PERI_WK_CTRL1, tmp);
+}
+
+/*
+* for line-state wakeup mode, phy's power should not power-down
+* and only support cable plug in/out
+*/
+static void usb_wakeup_line_state_en(struct xhci_hcd_mtk *mtk)
+{
+ u32 tmp;
+ struct regmap *pericfg = mtk->pericfg;
+
+ /* line-state of u2-port0 */
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ tmp &= ~UWK_CTL1_0P_LS_P;
+ tmp &= ~(UWK_CTL1_0P_LS_C(0xf));
+ tmp |= UWK_CTL1_0P_LS_C(0x8);
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp);
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_0P_LS_E);
+
+ /* line-state of u2-port1 */
+ regmap_read(pericfg, PERI_WK_CTRL0, &tmp);
+ tmp &= ~(UWK_CTL1_1P_LS_C(0xf));
+ tmp |= UWK_CTL1_1P_LS_C(0x8);
+ regmap_write(pericfg, PERI_WK_CTRL0, tmp);
+ regmap_write(pericfg, PERI_WK_CTRL0, tmp | UWK_CTL1_1P_LS_E);
+}
+
+static void usb_wakeup_line_state_dis(struct xhci_hcd_mtk *mtk)
+{
+ u32 tmp;
+ struct regmap *pericfg = mtk->pericfg;
+
+ /* line-state of u2-port0 */
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ tmp &= ~UWK_CTL1_0P_LS_E;
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp);
+
+ /* line-state of u2-port1 */
+ regmap_read(pericfg, PERI_WK_CTRL0, &tmp);
+ tmp &= ~UWK_CTL1_1P_LS_E;
+ regmap_write(pericfg, PERI_WK_CTRL0, tmp);
+}
+
+static void usb_wakeup_enable(struct xhci_hcd_mtk *mtk)
+{
+ if (mtk->wakeup_src == SSUSB_WK_IP_SLEEP)
+ usb_wakeup_ip_sleep_en(mtk);
+ else if (mtk->wakeup_src == SSUSB_WK_LINE_STATE)
+ usb_wakeup_line_state_en(mtk);
+}
+
+static void usb_wakeup_disable(struct xhci_hcd_mtk *mtk)
+{
+ if (mtk->wakeup_src == SSUSB_WK_IP_SLEEP)
+ usb_wakeup_ip_sleep_dis(mtk);
+ else if (mtk->wakeup_src == SSUSB_WK_LINE_STATE)
+ usb_wakeup_line_state_dis(mtk);
+}
+
+static int usb_wakeup_of_property_parse(struct xhci_hcd_mtk *mtk,
+ struct device_node *dn)
+{
+ struct device *dev = mtk->dev;
+
+ /*
+ * wakeup function is optional, so it is not an error if this property
+ * does not exist, and in such case, no need to get relative
+ * properties anymore.
+ */
+ of_property_read_u32(dn, "mediatek,wakeup-src", &mtk->wakeup_src);
+ if (!mtk->wakeup_src)
+ return 0;
+
+ mtk->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0");
+ if (IS_ERR(mtk->wk_deb_p0)) {
+ dev_err(dev, "fail to get wakeup_deb_p0\n");
+ return PTR_ERR(mtk->wk_deb_p0);
+ }
+
+ mtk->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1");
+ if (IS_ERR(mtk->wk_deb_p1)) {
+ dev_err(dev, "fail to get wakeup_deb_p1\n");
+ return PTR_ERR(mtk->wk_deb_p1);
+ }
+
+ mtk->pericfg = syscon_regmap_lookup_by_phandle(dn,
+ "mediatek,syscon-wakeup");
+ if (IS_ERR(mtk->pericfg)) {
+ dev_err(dev, "fail to get pericfg regs\n");
+ return PTR_ERR(mtk->pericfg);
+ }
+
+ return 0;
+}
+
+static int xhci_mtk_setup(struct usb_hcd *hcd);
+static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
+ .extra_priv_size = sizeof(struct xhci_hcd),
+ .reset = xhci_mtk_setup,
+};
+
+static struct hc_driver __read_mostly xhci_mtk_hc_driver;
+
+static int xhci_mtk_phy_init(struct xhci_hcd_mtk *mtk)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < mtk->num_phys; i++) {
+ ret = phy_init(mtk->phys[i]);
+ if (ret)
+ goto exit_phy;
+ }
+ return 0;
+
+exit_phy:
+ for (; i > 0; i--)
+ phy_exit(mtk->phys[i - 1]);
+
+ return ret;
+}
+
+static int xhci_mtk_phy_exit(struct xhci_hcd_mtk *mtk)
+{
+ int i;
+
+ for (i = 0; i < mtk->num_phys; i++)
+ phy_exit(mtk->phys[i]);
+
+ return 0;
+}
+
+static int xhci_mtk_phy_power_on(struct xhci_hcd_mtk *mtk)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < mtk->num_phys; i++) {
+ ret = phy_power_on(mtk->phys[i]);
+ if (ret)
+ goto power_off_phy;
+ }
+ return 0;
+
+power_off_phy:
+ for (; i > 0; i--)
+ phy_power_off(mtk->phys[i - 1]);
+
+ return ret;
+}
+
+static void xhci_mtk_phy_power_off(struct xhci_hcd_mtk *mtk)
+{
+ unsigned int i;
+
+ for (i = 0; i < mtk->num_phys; i++)
+ phy_power_off(mtk->phys[i]);
+}
+
+static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk)
+{
+ int ret;
+
+ ret = regulator_enable(mtk->vbus);
+ if (ret) {
+ dev_err(mtk->dev, "failed to enable vbus\n");
+ return ret;
+ }
+
+ ret = regulator_enable(mtk->vusb33);
+ if (ret) {
+ dev_err(mtk->dev, "failed to enable vusb33\n");
+ regulator_disable(mtk->vbus);
+ return ret;
+ }
+ return 0;
+}
+
+static void xhci_mtk_ldos_disable(struct xhci_hcd_mtk *mtk)
+{
+ regulator_disable(mtk->vbus);
+ regulator_disable(mtk->vusb33);
+}
+
+static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= XHCI_PLAT;
+ xhci->quirks |= XHCI_MTK_HOST;
+ /*
+ * MTK host controller gives a spurious successful event after a
+ * short transfer. Ignore it.
+ */
+ xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+ if (mtk->lpm_support)
+ xhci->quirks |= XHCI_LPM_SUPPORT;
+}
+
+/* called during probe() after chip reset completes */
+static int xhci_mtk_setup(struct usb_hcd *hcd)
+{
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+ int ret;
+
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ ret = xhci_mtk_ssusb_config(mtk);
+ if (ret)
+ return ret;
+ ret = xhci_mtk_sch_init(mtk);
+ if (ret)
+ return ret;
+ }
+
+ return xhci_gen_setup(hcd, xhci_mtk_quirks);
+}
+
+static int xhci_mtk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct xhci_hcd_mtk *mtk;
+ const struct hc_driver *driver;
+ struct xhci_hcd *xhci;
+ struct resource *res;
+ struct usb_hcd *hcd;
+ struct phy *phy;
+ int phy_num;
+ int ret = -ENODEV;
+ int irq;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ driver = &xhci_mtk_hc_driver;
+ mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL);
+ if (!mtk)
+ return -ENOMEM;
+
+ mtk->dev = dev;
+ mtk->vbus = devm_regulator_get(dev, "vbus");
+ if (IS_ERR(mtk->vbus)) {
+ dev_err(dev, "fail to get vbus\n");
+ return PTR_ERR(mtk->vbus);
+ }
+
+ mtk->vusb33 = devm_regulator_get(dev, "vusb33");
+ if (IS_ERR(mtk->vusb33)) {
+ dev_err(dev, "fail to get vusb33\n");
+ return PTR_ERR(mtk->vusb33);
+ }
+
+ mtk->sys_clk = devm_clk_get(dev, "sys_ck");
+ if (IS_ERR(mtk->sys_clk)) {
+ dev_err(dev, "fail to get sys_ck\n");
+ return PTR_ERR(mtk->sys_clk);
+ }
+
+ mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable");
+
+ ret = usb_wakeup_of_property_parse(mtk, node);
+ if (ret)
+ return ret;
+
+ mtk->num_phys = of_count_phandle_with_args(node,
+ "phys", "#phy-cells");
+ if (mtk->num_phys > 0) {
+ mtk->phys = devm_kcalloc(dev, mtk->num_phys,
+ sizeof(*mtk->phys), GFP_KERNEL);
+ if (!mtk->phys)
+ return -ENOMEM;
+ } else {
+ mtk->num_phys = 0;
+ }
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ device_enable_async_suspend(dev);
+
+ ret = xhci_mtk_ldos_enable(mtk);
+ if (ret)
+ goto disable_pm;
+
+ ret = xhci_mtk_clks_enable(mtk);
+ if (ret)
+ goto disable_ldos;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ goto disable_clk;
+
+ /* Initialize dma_mask and coherent_dma_mask to 32-bits */
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ if (ret)
+ goto disable_clk;
+
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+ else
+ dma_set_mask(dev, DMA_BIT_MASK(32));
+
+ hcd = usb_create_hcd(driver, dev, dev_name(dev));
+ if (!hcd) {
+ ret = -ENOMEM;
+ goto disable_clk;
+ }
+
+ /*
+ * USB 2.0 roothub is stored in the platform_device.
+ * Swap it with mtk HCD.
+ */
+ mtk->hcd = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, mtk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hcd->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hcd->regs)) {
+ ret = PTR_ERR(hcd->regs);
+ goto put_usb2_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ mtk->ippc_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mtk->ippc_regs)) {
+ ret = PTR_ERR(mtk->ippc_regs);
+ goto put_usb2_hcd;
+ }
+
+ for (phy_num = 0; phy_num < mtk->num_phys; phy_num++) {
+ phy = devm_of_phy_get_by_index(dev, node, phy_num);
+ if (IS_ERR(phy)) {
+ ret = PTR_ERR(phy);
+ goto put_usb2_hcd;
+ }
+ mtk->phys[phy_num] = phy;
+ }
+
+ ret = xhci_mtk_phy_init(mtk);
+ if (ret)
+ goto put_usb2_hcd;
+
+ ret = xhci_mtk_phy_power_on(mtk);
+ if (ret)
+ goto exit_phys;
+
+ device_init_wakeup(dev, true);
+
+ xhci = hcd_to_xhci(hcd);
+ xhci->main_hcd = hcd;
+ xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
+ dev_name(dev), hcd);
+ if (!xhci->shared_hcd) {
+ ret = -ENOMEM;
+ goto power_off_phys;
+ }
+
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ xhci->shared_hcd->can_do_streams = 1;
+
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto put_usb3_hcd;
+
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto dealloc_usb2_hcd;
+
+ return 0;
+
+dealloc_usb2_hcd:
+ usb_remove_hcd(hcd);
+
+put_usb3_hcd:
+ xhci_mtk_sch_exit(mtk);
+ usb_put_hcd(xhci->shared_hcd);
+
+power_off_phys:
+ xhci_mtk_phy_power_off(mtk);
+ device_init_wakeup(dev, false);
+
+exit_phys:
+ xhci_mtk_phy_exit(mtk);
+
+put_usb2_hcd:
+ usb_put_hcd(hcd);
+
+disable_clk:
+ xhci_mtk_clks_disable(mtk);
+
+disable_ldos:
+ xhci_mtk_ldos_disable(mtk);
+
+disable_pm:
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ return ret;
+}
+
+static int xhci_mtk_remove(struct platform_device *dev)
+{
+ struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev);
+ struct usb_hcd *hcd = mtk->hcd;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ usb_remove_hcd(xhci->shared_hcd);
+ xhci_mtk_phy_power_off(mtk);
+ xhci_mtk_phy_exit(mtk);
+ device_init_wakeup(&dev->dev, false);
+
+ usb_remove_hcd(hcd);
+ usb_put_hcd(xhci->shared_hcd);
+ usb_put_hcd(hcd);
+ xhci_mtk_sch_exit(mtk);
+ xhci_mtk_clks_disable(mtk);
+ xhci_mtk_ldos_disable(mtk);
+ pm_runtime_put_sync(&dev->dev);
+ pm_runtime_disable(&dev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int xhci_mtk_suspend(struct device *dev)
+{
+ struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+
+ xhci_mtk_host_disable(mtk);
+ xhci_mtk_phy_power_off(mtk);
+ xhci_mtk_clks_disable(mtk);
+ usb_wakeup_enable(mtk);
+ return 0;
+}
+
+static int xhci_mtk_resume(struct device *dev)
+{
+ struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+
+ usb_wakeup_disable(mtk);
+ xhci_mtk_clks_enable(mtk);
+ xhci_mtk_phy_power_on(mtk);
+ xhci_mtk_host_enable(mtk);
+ return 0;
+}
+
+static const struct dev_pm_ops xhci_mtk_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(xhci_mtk_suspend, xhci_mtk_resume)
+};
+#define DEV_PM_OPS (&xhci_mtk_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id mtk_xhci_of_match[] = {
+ { .compatible = "mediatek,mt8173-xhci"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, mtk_xhci_of_match);
+#endif
+
+static struct platform_driver mtk_xhci_driver = {
+ .probe = xhci_mtk_probe,
+ .remove = xhci_mtk_remove,
+ .driver = {
+ .name = "xhci-mtk",
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(mtk_xhci_of_match),
+ },
+};
+MODULE_ALIAS("platform:xhci-mtk");
+
+static int __init xhci_mtk_init(void)
+{
+ xhci_init_driver(&xhci_mtk_hc_driver, &xhci_mtk_overrides);
+ return platform_driver_register(&mtk_xhci_driver);
+}
+module_init(xhci_mtk_init);
+
+static void __exit xhci_mtk_exit(void)
+{
+ platform_driver_unregister(&mtk_xhci_driver);
+}
+module_exit(xhci_mtk_exit);
+
+MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek xHCI Host Controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
new file mode 100644
index 000000000000..7da677c79ea8
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author:
+ * Zhigang.Wei <zhigang.wei@mediatek.com>
+ * Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _XHCI_MTK_H_
+#define _XHCI_MTK_H_
+
+#include "xhci.h"
+
+/**
+ * To simplify scheduler algorithm, set a upper limit for ESIT,
+ * if a synchromous ep's ESIT is larger than @XHCI_MTK_MAX_ESIT,
+ * round down to the limit value, that means allocating more
+ * bandwidth to it.
+ */
+#define XHCI_MTK_MAX_ESIT 64
+
+/**
+ * struct mu3h_sch_bw_info: schedule information for bandwidth domain
+ *
+ * @bus_bw: array to keep track of bandwidth already used at each uframes
+ * @bw_ep_list: eps in the bandwidth domain
+ *
+ * treat a HS root port as a bandwidth domain, but treat a SS root port as
+ * two bandwidth domains, one for IN eps and another for OUT eps.
+ */
+struct mu3h_sch_bw_info {
+ u32 bus_bw[XHCI_MTK_MAX_ESIT];
+ struct list_head bw_ep_list;
+};
+
+/**
+ * struct mu3h_sch_ep_info: schedule information for endpoint
+ *
+ * @esit: unit is 125us, equal to 2 << Interval field in ep-context
+ * @num_budget_microframes: number of continuous uframes
+ * (@repeat==1) scheduled within the interval
+ * @bw_cost_per_microframe: bandwidth cost per microframe
+ * @endpoint: linked into bandwidth domain which it belongs to
+ * @ep: address of usb_host_endpoint struct
+ * @offset: which uframe of the interval that transfer should be
+ * scheduled first time within the interval
+ * @repeat: the time gap between two uframes that transfers are
+ * scheduled within a interval. in the simple algorithm, only
+ * assign 0 or 1 to it; 0 means using only one uframe in a
+ * interval, and 1 means using @num_budget_microframes
+ * continuous uframes
+ * @pkts: number of packets to be transferred in the scheduled uframes
+ * @cs_count: number of CS that host will trigger
+ * @burst_mode: burst mode for scheduling. 0: normal burst mode,
+ * distribute the bMaxBurst+1 packets for a single burst
+ * according to @pkts and @repeat, repeate the burst multiple
+ * times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets
+ * according to @pkts and @repeat. normal mode is used by
+ * default
+ */
+struct mu3h_sch_ep_info {
+ u32 esit;
+ u32 num_budget_microframes;
+ u32 bw_cost_per_microframe;
+ struct list_head endpoint;
+ void *ep;
+ /*
+ * mtk xHCI scheduling information put into reserved DWs
+ * in ep context
+ */
+ u32 offset;
+ u32 repeat;
+ u32 pkts;
+ u32 cs_count;
+ u32 burst_mode;
+};
+
+#define MU3C_U3_PORT_MAX 4
+#define MU3C_U2_PORT_MAX 5
+
+/**
+ * struct mu3c_ippc_regs: MTK ssusb ip port control registers
+ * @ip_pw_ctr0~3: ip power and clock control registers
+ * @ip_pw_sts1~2: ip power and clock status registers
+ * @ip_xhci_cap: ip xHCI capability register
+ * @u3_ctrl_p[x]: ip usb3 port x control register, only low 4bytes are used
+ * @u2_ctrl_p[x]: ip usb2 port x control register, only low 4bytes are used
+ * @u2_phy_pll: usb2 phy pll control register
+ */
+struct mu3c_ippc_regs {
+ __le32 ip_pw_ctr0;
+ __le32 ip_pw_ctr1;
+ __le32 ip_pw_ctr2;
+ __le32 ip_pw_ctr3;
+ __le32 ip_pw_sts1;
+ __le32 ip_pw_sts2;
+ __le32 reserved0[3];
+ __le32 ip_xhci_cap;
+ __le32 reserved1[2];
+ __le64 u3_ctrl_p[MU3C_U3_PORT_MAX];
+ __le64 u2_ctrl_p[MU3C_U2_PORT_MAX];
+ __le32 reserved2;
+ __le32 u2_phy_pll;
+ __le32 reserved3[33]; /* 0x80 ~ 0xff */
+};
+
+struct xhci_hcd_mtk {
+ struct device *dev;
+ struct usb_hcd *hcd;
+ struct mu3h_sch_bw_info *sch_array;
+ struct mu3c_ippc_regs __iomem *ippc_regs;
+ int num_u2_ports;
+ int num_u3_ports;
+ struct regulator *vusb33;
+ struct regulator *vbus;
+ struct clk *sys_clk; /* sys and mac clock */
+ struct clk *wk_deb_p0; /* port0's wakeup debounce clock */
+ struct clk *wk_deb_p1;
+ struct regmap *pericfg;
+ struct phy **phys;
+ int num_phys;
+ int wakeup_src;
+ bool lpm_support;
+};
+
+static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
+{
+ return dev_get_drvdata(hcd->self.controller);
+}
+
+#if IS_ENABLED(CONFIG_USB_XHCI_MTK)
+int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk);
+void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk);
+int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+
+#else
+static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd,
+ struct usb_device *udev, struct usb_host_endpoint *ep)
+{
+ return 0;
+}
+
+static inline void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd,
+ struct usb_device *udev, struct usb_host_endpoint *ep)
+{
+}
+
+#endif
+
+#endif /* _XHCI_MTK_H_ */
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index c62109091d12..58c43ed7ff3b 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -53,7 +53,6 @@ static struct hc_driver __read_mostly xhci_pci_hc_driver;
static int xhci_pci_setup(struct usb_hcd *hcd);
static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
- .extra_priv_size = sizeof(struct xhci_hcd),
.reset = xhci_pci_setup,
};
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 05647e6753cd..770b6b088797 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -22,6 +22,7 @@
#include <linux/acpi.h>
#include "xhci.h"
+#include "xhci-plat.h"
#include "xhci-mvebu.h"
#include "xhci-rcar.h"
@@ -31,7 +32,7 @@ static int xhci_plat_setup(struct usb_hcd *hcd);
static int xhci_plat_start(struct usb_hcd *hcd);
static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
- .extra_priv_size = sizeof(struct xhci_hcd),
+ .extra_priv_size = sizeof(struct xhci_plat_priv),
.reset = xhci_plat_setup,
.start = xhci_plat_start,
};
@@ -49,11 +50,10 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
/* called during probe() after chip reset completes */
static int xhci_plat_setup(struct usb_hcd *hcd)
{
- struct device_node *of_node = hcd->self.controller->of_node;
int ret;
- if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") ||
- of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) {
+ if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
+ xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) {
ret = xhci_rcar_init_quirk(hcd);
if (ret)
return ret;
@@ -64,19 +64,62 @@ static int xhci_plat_setup(struct usb_hcd *hcd)
static int xhci_plat_start(struct usb_hcd *hcd)
{
- struct device_node *of_node = hcd->self.controller->of_node;
-
- if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") ||
- of_device_is_compatible(of_node, "renesas,xhci-r8a7791"))
+ if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
+ xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
xhci_rcar_start(hcd);
return xhci_run(hcd);
}
+#ifdef CONFIG_OF
+static const struct xhci_plat_priv xhci_plat_marvell_armada = {
+ .type = XHCI_PLAT_TYPE_MARVELL_ARMADA,
+};
+
+static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
+ .type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
+ .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
+};
+
+static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
+ .type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
+ .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2,
+};
+
+static const struct of_device_id usb_xhci_of_match[] = {
+ {
+ .compatible = "generic-xhci",
+ }, {
+ .compatible = "xhci-platform",
+ }, {
+ .compatible = "marvell,armada-375-xhci",
+ .data = &xhci_plat_marvell_armada,
+ }, {
+ .compatible = "marvell,armada-380-xhci",
+ .data = &xhci_plat_marvell_armada,
+ }, {
+ .compatible = "renesas,xhci-r8a7790",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,xhci-r8a7791",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,xhci-r8a7793",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,xhci-r8a7795",
+ .data = &xhci_plat_renesas_rcar_gen3,
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
+#endif
+
static int xhci_plat_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
+ const struct of_device_id *match;
const struct hc_driver *driver;
struct xhci_hcd *xhci;
struct resource *res;
@@ -134,10 +177,17 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_hcd;
}
- if (of_device_is_compatible(pdev->dev.of_node,
- "marvell,armada-375-xhci") ||
- of_device_is_compatible(pdev->dev.of_node,
- "marvell,armada-380-xhci")) {
+ xhci = hcd_to_xhci(hcd);
+ match = of_match_node(usb_xhci_of_match, node);
+ if (match) {
+ const struct xhci_plat_priv *priv_match = match->data;
+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+ /* Just copy data for now */
+ *priv = *priv_match;
+ }
+
+ if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_MARVELL_ARMADA)) {
ret = xhci_mvebu_mbus_init_quirk(pdev);
if (ret)
goto disable_clk;
@@ -145,7 +195,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
device_wakeup_enable(hcd->self.controller);
- xhci = hcd_to_xhci(hcd);
xhci->clk = clk;
xhci->main_hcd = hcd;
xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
@@ -256,19 +305,6 @@ static const struct dev_pm_ops xhci_plat_pm_ops = {
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM */
-#ifdef CONFIG_OF
-static const struct of_device_id usb_xhci_of_match[] = {
- { .compatible = "generic-xhci" },
- { .compatible = "xhci-platform" },
- { .compatible = "marvell,armada-375-xhci"},
- { .compatible = "marvell,armada-380-xhci"},
- { .compatible = "renesas,xhci-r8a7790"},
- { .compatible = "renesas,xhci-r8a7791"},
- { },
-};
-MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
-#endif
-
static const struct acpi_device_id usb_xhci_acpi_match[] = {
/* XHCI-compliant USB Controller */
{ "PNP0D10", },
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
new file mode 100644
index 000000000000..5a2e2e3936c4
--- /dev/null
+++ b/drivers/usb/host/xhci-plat.h
@@ -0,0 +1,39 @@
+/*
+ * xhci-plat.h - xHCI host controller driver platform Bus Glue.
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _XHCI_PLAT_H
+#define _XHCI_PLAT_H
+
+#include "xhci.h" /* for hcd_to_xhci() */
+
+enum xhci_plat_type {
+ XHCI_PLAT_TYPE_MARVELL_ARMADA,
+ XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
+ XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
+};
+
+struct xhci_plat_priv {
+ enum xhci_plat_type type;
+ const char *firmware_name;
+};
+
+#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
+
+static inline bool xhci_plat_type_is(struct usb_hcd *hcd,
+ enum xhci_plat_type type)
+{
+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+ if (priv && priv->type == type)
+ return true;
+ else
+ return false;
+}
+#endif /* _XHCI_PLAT_H */
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index ff0d1b44ea58..623100e9385e 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -14,10 +14,17 @@
#include <linux/usb/phy.h>
#include "xhci.h"
+#include "xhci-plat.h"
#include "xhci-rcar.h"
-#define FIRMWARE_NAME "r8a779x_usb3_v1.dlmem"
-MODULE_FIRMWARE(FIRMWARE_NAME);
+/*
+* - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes
+* performance degradation. So, this driver continues to use the V1 if R-Car
+* Gen2.
+* - The V1 firmware is impossible to use on R-Car Gen3.
+*/
+MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1);
+MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2);
/*** Register Offset ***/
#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */
@@ -56,6 +63,19 @@ MODULE_FIRMWARE(FIRMWARE_NAME);
#define RCAR_USB3_RX_POL_VAL BIT(21)
#define RCAR_USB3_TX_POL_VAL BIT(4)
+static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
+{
+ /* LCLK Select */
+ writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK);
+ /* USB3.0 Configuration */
+ writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1);
+ writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2);
+ writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3);
+ /* USB3.0 Polarity */
+ writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL);
+ writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
+}
+
void xhci_rcar_start(struct usb_hcd *hcd)
{
u32 temp;
@@ -65,27 +85,23 @@ void xhci_rcar_start(struct usb_hcd *hcd)
temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
temp |= RCAR_USB3_INT_ENA_VAL;
writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
- /* LCLK Select */
- writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK);
- /* USB3.0 Configuration */
- writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1);
- writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2);
- writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3);
- /* USB3.0 Polarity */
- writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL);
- writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
+ if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2))
+ xhci_rcar_start_gen2(hcd);
}
}
-static int xhci_rcar_download_firmware(struct device *dev, void __iomem *regs)
+static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
{
+ struct device *dev = hcd->self.controller;
+ void __iomem *regs = hcd->regs;
+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
const struct firmware *fw;
int retval, index, j, time;
int timeout = 10000;
u32 data, val, temp;
/* request R-Car USB3.0 firmware */
- retval = request_firmware(&fw, FIRMWARE_NAME, dev);
+ retval = request_firmware(&fw, priv->firmware_name, dev);
if (retval)
return retval;
@@ -144,5 +160,5 @@ int xhci_rcar_init_quirk(struct usb_hcd *hcd)
if (!hcd->regs)
return 0;
- return xhci_rcar_download_firmware(hcd->self.controller, hcd->regs);
+ return xhci_rcar_download_firmware(hcd);
}
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h
index 58501256715d..2941a25cfe98 100644
--- a/drivers/usb/host/xhci-rcar.h
+++ b/drivers/usb/host/xhci-rcar.h
@@ -11,6 +11,9 @@
#ifndef _XHCI_RCAR_H
#define _XHCI_RCAR_H
+#define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem"
+#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem"
+
#if IS_ENABLED(CONFIG_USB_XHCI_RCAR)
void xhci_rcar_start(struct usb_hcd *hcd);
int xhci_rcar_init_quirk(struct usb_hcd *hcd);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index eeaa6c6bd540..f1c21c40b4a6 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -68,6 +68,7 @@
#include <linux/slab.h>
#include "xhci.h"
#include "xhci-trace.h"
+#include "xhci-mtk.h"
/*
* Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
@@ -3075,17 +3076,22 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
{
u32 maxp, total_packet_count;
- if (xhci->hci_version < 0x100)
+ /* MTK xHCI is mostly 0.97 but contains some features from 1.0 */
+ if (xhci->hci_version < 0x100 && !(xhci->quirks & XHCI_MTK_HOST))
return ((td_total_len - transferred) >> 10);
- maxp = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
- total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
-
/* One TRB with a zero-length data packet. */
if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) ||
trb_buff_len == td_total_len)
return 0;
+ /* for MTK xHCI, TD size doesn't include this TRB */
+ if (xhci->quirks & XHCI_MTK_HOST)
+ trb_buff_len = 0;
+
+ maxp = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
+ total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
+
/* Queueing functions don't count the current TRB into transferred */
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
}
@@ -3473,7 +3479,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= 0x1;
/* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
- if (xhci->hci_version >= 0x100) {
+ if ((xhci->hci_version >= 0x100) || (xhci->quirks & XHCI_MTK_HOST)) {
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_TX_TYPE(TRB_DATA_IN);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 3f912705dcef..26a44c0e969e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -31,6 +31,7 @@
#include "xhci.h"
#include "xhci-trace.h"
+#include "xhci-mtk.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -634,7 +635,11 @@ int xhci_run(struct usb_hcd *hcd)
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
- temp |= (u32) 160;
+ /*
+ * the increment interval is 8 times as much as that defined
+ * in xHCI spec on MTK's controller
+ */
+ temp |= (u32) ((xhci->quirks & XHCI_MTK_HOST) ? 20 : 160);
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
@@ -1698,6 +1703,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
+ if (xhci->quirks & XHCI_MTK_HOST)
+ xhci_mtk_drop_ep_quirk(hcd, udev, ep);
+
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
@@ -1793,6 +1801,15 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
return -ENOMEM;
}
+ if (xhci->quirks & XHCI_MTK_HOST) {
+ ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
+ if (ret < 0) {
+ xhci_free_or_cache_endpoint_ring(xhci,
+ virt_dev, ep_index);
+ return ret;
+ }
+ }
+
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
@@ -4960,7 +4977,7 @@ EXPORT_SYMBOL_GPL(xhci_gen_setup);
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
- .hcd_priv_size = sizeof(struct xhci_hcd *),
+ .hcd_priv_size = sizeof(struct xhci_hcd),
/*
* generic hardware linkage
@@ -5059,6 +5076,10 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+
+ if (usb_disabled())
+ return -ENODEV;
+
return 0;
}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 0b9451250e33..9be7348872ba 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1630,6 +1630,7 @@ struct xhci_hcd {
/* For controllers with a broken beyond repair streams implementation */
#define XHCI_BROKEN_STREAMS (1 << 19)
#define XHCI_PME_STUCK_QUIRK (1 << 20)
+#define XHCI_MTK_HOST (1 << 21)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1656,6 +1657,9 @@ struct xhci_hcd {
u32 port_status_u0;
/* Compliance Mode Timer Triggered every 2 seconds */
#define COMP_MODE_RCVRY_MSECS 2000
+
+ /* platform-specific data -- must come last */
+ unsigned long priv[0] __aligned(sizeof(s64));
};
/* Platform specific overrides to generic XHCI hc_driver ops */
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 637f3f7cfce8..92fdb6e9faff 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -22,18 +22,42 @@ static void complicated_callback(struct urb *urb);
/*-------------------------------------------------------------------------*/
/* FIXME make these public somewhere; usbdevfs.h? */
-struct usbtest_param {
+
+/* Parameter for usbtest driver. */
+struct usbtest_param_32 {
/* inputs */
- unsigned test_num; /* 0..(TEST_CASES-1) */
- unsigned iterations;
- unsigned length;
- unsigned vary;
- unsigned sglen;
+ __u32 test_num; /* 0..(TEST_CASES-1) */
+ __u32 iterations;
+ __u32 length;
+ __u32 vary;
+ __u32 sglen;
/* outputs */
- struct timeval duration;
+ __s32 duration_sec;
+ __s32 duration_usec;
};
-#define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param)
+
+/*
+ * Compat parameter to the usbtest driver.
+ * This supports older user space binaries compiled with 64 bit compiler.
+ */
+struct usbtest_param_64 {
+ /* inputs */
+ __u32 test_num; /* 0..(TEST_CASES-1) */
+ __u32 iterations;
+ __u32 length;
+ __u32 vary;
+ __u32 sglen;
+
+ /* outputs */
+ __s64 duration_sec;
+ __s64 duration_usec;
+};
+
+/* IOCTL interface to the driver. */
+#define USBTEST_REQUEST_32 _IOWR('U', 100, struct usbtest_param_32)
+/* COMPAT IOCTL interface to the driver. */
+#define USBTEST_REQUEST_64 _IOWR('U', 100, struct usbtest_param_64)
/*-------------------------------------------------------------------------*/
@@ -1030,7 +1054,7 @@ struct ctrl_ctx {
unsigned pending;
int status;
struct urb **urb;
- struct usbtest_param *param;
+ struct usbtest_param_32 *param;
int last;
};
@@ -1155,7 +1179,7 @@ error:
}
static int
-test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)
+test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param)
{
struct usb_device *udev = testdev_to_usbdev(dev);
struct urb **urb;
@@ -1849,7 +1873,7 @@ static void complicated_callback(struct urb *urb)
goto done;
default:
dev_err(&ctx->dev->intf->dev,
- "iso resubmit err %d\n",
+ "resubmit err %d\n",
status);
/* FALLTHROUGH */
case -ENODEV: /* disconnected */
@@ -1863,7 +1887,7 @@ static void complicated_callback(struct urb *urb)
if (ctx->pending == 0) {
if (ctx->errors)
dev_err(&ctx->dev->intf->dev,
- "iso test, %lu errors out of %lu\n",
+ "during the test, %lu errors out of %lu\n",
ctx->errors, ctx->packet_count);
complete(&ctx->done);
}
@@ -1930,7 +1954,7 @@ static struct urb *iso_alloc_urb(
}
static int
-test_queue(struct usbtest_dev *dev, struct usbtest_param *param,
+test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param,
int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)
{
struct transfer_context context;
@@ -2049,81 +2073,20 @@ static int test_unaligned_bulk(
return retval;
}
-/*-------------------------------------------------------------------------*/
-
-/* We only have this one interface to user space, through usbfs.
- * User mode code can scan usbfs to find N different devices (maybe on
- * different busses) to use when testing, and allocate one thread per
- * test. So discovery is simplified, and we have no device naming issues.
- *
- * Don't use these only as stress/load tests. Use them along with with
- * other USB bus activity: plugging, unplugging, mousing, mp3 playback,
- * video capture, and so on. Run different tests at different times, in
- * different sequences. Nothing here should interact with other devices,
- * except indirectly by consuming USB bandwidth and CPU resources for test
- * threads and request completion. But the only way to know that for sure
- * is to test when HC queues are in use by many devices.
- *
- * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(),
- * it locks out usbcore in certain code paths. Notably, if you disconnect
- * the device-under-test, hub_wq will wait block forever waiting for the
- * ioctl to complete ... so that usb_disconnect() can abort the pending
- * urbs and then call usbtest_disconnect(). To abort a test, you're best
- * off just killing the userspace task and waiting for it to exit.
- */
-
+/* Run tests. */
static int
-usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
+usbtest_do_ioctl(struct usb_interface *intf, struct usbtest_param_32 *param)
{
struct usbtest_dev *dev = usb_get_intfdata(intf);
struct usb_device *udev = testdev_to_usbdev(dev);
- struct usbtest_param *param = buf;
- int retval = -EOPNOTSUPP;
struct urb *urb;
struct scatterlist *sg;
struct usb_sg_request req;
- struct timeval start;
unsigned i;
-
- /* FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is. */
-
- pattern = mod_pattern;
-
- if (code != USBTEST_REQUEST)
- return -EOPNOTSUPP;
+ int retval = -EOPNOTSUPP;
if (param->iterations <= 0)
return -EINVAL;
-
- if (param->sglen > MAX_SGLEN)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
-
- /* FIXME: What if a system sleep starts while a test is running? */
-
- /* some devices, like ez-usb default devices, need a non-default
- * altsetting to have any active endpoints. some tests change
- * altsettings; force a default so most tests don't need to check.
- */
- if (dev->info->alt >= 0) {
- int res;
-
- if (intf->altsetting->desc.bInterfaceNumber) {
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
- res = set_altsetting(dev, dev->info->alt);
- if (res) {
- dev_err(&intf->dev,
- "set altsetting to %d failed, %d\n",
- dev->info->alt, res);
- mutex_unlock(&dev->lock);
- return res;
- }
- }
-
/*
* Just a bunch of test cases that every HCD is expected to handle.
*
@@ -2133,7 +2096,6 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
* FIXME add more tests! cancel requests, verify the data, control
* queueing, concurrent read+write threads, and so on.
*/
- do_gettimeofday(&start);
switch (param->test_num) {
case 0:
@@ -2548,13 +2510,116 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
dev->in_pipe, NULL, 0);
break;
}
- do_gettimeofday(&param->duration);
- param->duration.tv_sec -= start.tv_sec;
- param->duration.tv_usec -= start.tv_usec;
- if (param->duration.tv_usec < 0) {
- param->duration.tv_usec += 1000 * 1000;
- param->duration.tv_sec -= 1;
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* We only have this one interface to user space, through usbfs.
+ * User mode code can scan usbfs to find N different devices (maybe on
+ * different busses) to use when testing, and allocate one thread per
+ * test. So discovery is simplified, and we have no device naming issues.
+ *
+ * Don't use these only as stress/load tests. Use them along with with
+ * other USB bus activity: plugging, unplugging, mousing, mp3 playback,
+ * video capture, and so on. Run different tests at different times, in
+ * different sequences. Nothing here should interact with other devices,
+ * except indirectly by consuming USB bandwidth and CPU resources for test
+ * threads and request completion. But the only way to know that for sure
+ * is to test when HC queues are in use by many devices.
+ *
+ * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(),
+ * it locks out usbcore in certain code paths. Notably, if you disconnect
+ * the device-under-test, hub_wq will wait block forever waiting for the
+ * ioctl to complete ... so that usb_disconnect() can abort the pending
+ * urbs and then call usbtest_disconnect(). To abort a test, you're best
+ * off just killing the userspace task and waiting for it to exit.
+ */
+
+static int
+usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
+{
+
+ struct usbtest_dev *dev = usb_get_intfdata(intf);
+ struct usbtest_param_64 *param_64 = buf;
+ struct usbtest_param_32 temp;
+ struct usbtest_param_32 *param_32 = buf;
+ struct timespec64 start;
+ struct timespec64 end;
+ struct timespec64 duration;
+ int retval = -EOPNOTSUPP;
+
+ /* FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is. */
+
+ pattern = mod_pattern;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+
+ /* FIXME: What if a system sleep starts while a test is running? */
+
+ /* some devices, like ez-usb default devices, need a non-default
+ * altsetting to have any active endpoints. some tests change
+ * altsettings; force a default so most tests don't need to check.
+ */
+ if (dev->info->alt >= 0) {
+ if (intf->altsetting->desc.bInterfaceNumber) {
+ retval = -ENODEV;
+ goto free_mutex;
+ }
+ retval = set_altsetting(dev, dev->info->alt);
+ if (retval) {
+ dev_err(&intf->dev,
+ "set altsetting to %d failed, %d\n",
+ dev->info->alt, retval);
+ goto free_mutex;
+ }
+ }
+
+ switch (code) {
+ case USBTEST_REQUEST_64:
+ temp.test_num = param_64->test_num;
+ temp.iterations = param_64->iterations;
+ temp.length = param_64->length;
+ temp.sglen = param_64->sglen;
+ temp.vary = param_64->vary;
+ param_32 = &temp;
+ break;
+
+ case USBTEST_REQUEST_32:
+ break;
+
+ default:
+ retval = -EOPNOTSUPP;
+ goto free_mutex;
+ }
+
+ ktime_get_ts64(&start);
+
+ retval = usbtest_do_ioctl(intf, param_32);
+ if (retval)
+ goto free_mutex;
+
+ ktime_get_ts64(&end);
+
+ duration = timespec64_sub(end, start);
+
+ temp.duration_sec = duration.tv_sec;
+ temp.duration_usec = duration.tv_nsec/NSEC_PER_USEC;
+
+ switch (code) {
+ case USBTEST_REQUEST_32:
+ param_32->duration_sec = temp.duration_sec;
+ param_32->duration_usec = temp.duration_usec;
+ break;
+
+ case USBTEST_REQUEST_64:
+ param_64->duration_sec = temp.duration_sec;
+ param_64->duration_usec = temp.duration_usec;
+ break;
}
+
+free_mutex:
mutex_unlock(&dev->lock);
return retval;
}
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 3598f1a62673..1a874a1f3890 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/time64.h>
#include <asm/uaccess.h>
@@ -92,8 +93,8 @@ struct mon_bin_hdr {
unsigned short busnum; /* Bus number */
char flag_setup;
char flag_data;
- s64 ts_sec; /* gettimeofday */
- s32 ts_usec; /* gettimeofday */
+ s64 ts_sec; /* getnstimeofday64 */
+ s32 ts_usec; /* getnstimeofday64 */
int status;
unsigned int len_urb; /* Length of data (submitted or actual) */
unsigned int len_cap; /* Delivered length */
@@ -483,7 +484,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
char ev_type, int status)
{
const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
- struct timeval ts;
+ struct timespec64 ts;
unsigned long flags;
unsigned int urb_length;
unsigned int offset;
@@ -494,7 +495,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
struct mon_bin_hdr *ep;
char data_tag = 0;
- do_gettimeofday(&ts);
+ getnstimeofday64(&ts);
spin_lock_irqsave(&rp->b_lock, flags);
@@ -568,7 +569,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
- ep->ts_usec = ts.tv_usec;
+ ep->ts_usec = ts.tv_nsec / NSEC_PER_USEC;
ep->status = status;
ep->len_urb = urb_length;
ep->len_cap = length + lendesc;
@@ -629,12 +630,12 @@ static void mon_bin_complete(void *data, struct urb *urb, int status)
static void mon_bin_error(void *data, struct urb *urb, int error)
{
struct mon_reader_bin *rp = data;
- struct timeval ts;
+ struct timespec64 ts;
unsigned long flags;
unsigned int offset;
struct mon_bin_hdr *ep;
- do_gettimeofday(&ts);
+ getnstimeofday64(&ts);
spin_lock_irqsave(&rp->b_lock, flags);
@@ -656,7 +657,7 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
- ep->ts_usec = ts.tv_usec;
+ ep->ts_usec = ts.tv_nsec / NSEC_PER_USEC;
ep->status = error;
ep->flag_setup = '-';
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index f7c292f4891e..fec3f1128fdc 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -241,7 +241,7 @@ static struct notifier_block mon_nb = {
/*
* Ops
*/
-static struct usb_mon_operations mon_ops_0 = {
+static const struct usb_mon_operations mon_ops_0 = {
.urb_submit = mon_submit,
.urb_submit_error = mon_submit_error,
.urb_complete = mon_complete,
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index ad408251d955..e59334b09c41 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -9,6 +9,7 @@
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/ktime.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
@@ -176,12 +177,12 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
static inline unsigned int mon_get_timestamp(void)
{
- struct timeval tval;
+ struct timespec64 now;
unsigned int stamp;
- do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */
- stamp = stamp * 1000000 + tval.tv_usec;
+ ktime_get_ts64(&now);
+ stamp = now.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */
+ stamp = stamp * USEC_PER_SEC + now.tv_nsec / NSEC_PER_USEC;
return stamp;
}
@@ -386,7 +387,8 @@ static ssize_t mon_text_read_t(struct file *file, char __user *buf,
struct mon_event_text *ep;
struct mon_text_ptr ptr;
- if (IS_ERR(ep = mon_text_read_wait(rp, file)))
+ ep = mon_text_read_wait(rp, file);
+ if (IS_ERR(ep))
return PTR_ERR(ep);
mutex_lock(&rp->printf_lock);
ptr.cnt = 0;
@@ -413,7 +415,8 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
struct mon_event_text *ep;
struct mon_text_ptr ptr;
- if (IS_ERR(ep = mon_text_read_wait(rp, file)))
+ ep = mon_text_read_wait(rp, file);
+ if (IS_ERR(ep))
return PTR_ERR(ep);
mutex_lock(&rp->printf_lock);
ptr.cnt = 0;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ee9ff7028b92..c3791a01ab31 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1360,8 +1360,7 @@ static int ep_config_from_table(struct musb *musb)
break;
}
- printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
- musb_driver_name, fifo_mode);
+ pr_debug("%s: setup fifo_mode %d\n", musb_driver_name, fifo_mode);
done:
@@ -1390,7 +1389,7 @@ done:
musb->nr_endpoints = max(epn, musb->nr_endpoints);
}
- printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n",
+ pr_debug("%s: %d/%d max ep, %d/%d memory\n",
musb_driver_name,
n + 1, musb->config->num_eps * 2 - 1,
offset, (1 << (musb->config->ram_bits + 2)));
@@ -1491,8 +1490,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
if (reg & MUSB_CONFIGDATA_SOFTCONE)
strcat(aInfo, ", SoftConn");
- printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
- musb_driver_name, reg, aInfo);
+ pr_debug("%s: ConfigData=0x%02x (%s)\n", musb_driver_name, reg, aInfo);
aDate[0] = 0;
if (MUSB_CONTROLLER_MHDRC == musb_type) {
@@ -1502,9 +1500,8 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
musb->is_multipoint = 0;
type = "";
#ifndef CONFIG_USB_OTG_BLACKLIST_HUB
- printk(KERN_ERR
- "%s: kernel must blacklist external hubs\n",
- musb_driver_name);
+ pr_err("%s: kernel must blacklist external hubs\n",
+ musb_driver_name);
#endif
}
@@ -1513,8 +1510,8 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers),
MUSB_HWVERS_MINOR(musb->hwvers),
(musb->hwvers & MUSB_HWVERS_RC) ? "RC" : "");
- printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
- musb_driver_name, type, aRevision, aDate);
+ pr_debug("%s: %sHDRC RTL version %s %s\n",
+ musb_driver_name, type, aRevision, aDate);
/* configure ep0 */
musb_configure_ep0(musb);
@@ -1705,6 +1702,23 @@ EXPORT_SYMBOL_GPL(musb_dma_completion);
#define use_dma 0
#endif
+static void (*musb_phy_callback)(enum musb_vbus_id_status status);
+
+/*
+ * musb_mailbox - optional phy notifier function
+ * @status phy state change
+ *
+ * Optionally gets called from the USB PHY. Note that the USB PHY must be
+ * disabled at the point the phy_callback is registered or unregistered.
+ */
+void musb_mailbox(enum musb_vbus_id_status status)
+{
+ if (musb_phy_callback)
+ musb_phy_callback(status);
+
+};
+EXPORT_SYMBOL_GPL(musb_mailbox);
+
/*-------------------------------------------------------------------------*/
static ssize_t
@@ -2117,8 +2131,15 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb->xceiv->io_ops = &musb_ulpi_access;
}
+ if (musb->ops->phy_callback)
+ musb_phy_callback = musb->ops->phy_callback;
+
pm_runtime_get_sync(musb->controller);
+ status = usb_phy_init(musb->xceiv);
+ if (status < 0)
+ goto err_usb_phy_init;
+
if (use_dma && dev->dma_mask) {
musb->dma_controller =
musb_dma_controller_create(musb, musb->mregs);
@@ -2239,7 +2260,11 @@ fail3:
cancel_delayed_work_sync(&musb->deassert_reset_work);
if (musb->dma_controller)
musb_dma_controller_destroy(musb->dma_controller);
+
fail2_5:
+ usb_phy_shutdown(musb->xceiv);
+
+err_usb_phy_init:
pm_runtime_put_sync(musb->controller);
fail2:
@@ -2295,10 +2320,13 @@ static int musb_remove(struct platform_device *pdev)
*/
musb_exit_debugfs(musb);
musb_shutdown(pdev);
+ musb_phy_callback = NULL;
if (musb->dma_controller)
musb_dma_controller_destroy(musb->dma_controller);
+ usb_phy_shutdown(musb->xceiv);
+
cancel_work_sync(&musb->irq_work);
cancel_delayed_work_sync(&musb->finish_resume_work);
cancel_delayed_work_sync(&musb->deassert_reset_work);
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 2337d7a7d62d..fd215fb45fd4 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -168,6 +168,7 @@ struct musb_io;
* @adjust_channel_params: pre check for standard dma channel_program func
* @pre_root_reset_end: called before the root usb port reset flag gets cleared
* @post_root_reset_end: called after the root usb port reset flag gets cleared
+ * @phy_callback: optional callback function for the phy to call
*/
struct musb_platform_ops {
@@ -214,6 +215,7 @@ struct musb_platform_ops {
dma_addr_t *dma_addr, u32 *len);
void (*pre_root_reset_end)(struct musb *musb);
void (*post_root_reset_end)(struct musb *musb);
+ void (*phy_callback)(enum musb_vbus_id_status status);
};
/*
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 67ad630c86c9..87bd578799a8 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -353,9 +353,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
* 1 >0 Yes(FS bulk)
*/
if (!musb_ep->hb_mult ||
- (musb_ep->hb_mult &&
- can_bulk_split(musb,
- musb_ep->type)))
+ can_bulk_split(musb,
+ musb_ep->type))
csr |= MUSB_TXCSR_AUTOSET;
}
csr &= ~MUSB_TXCSR_P_UNDERRUN;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 1bd9232ff76f..c84e0322c108 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -36,7 +36,7 @@
#include <linux/pm_runtime.h>
#include <linux/err.h>
#include <linux/delay.h>
-#include <linux/usb/musb-omap.h>
+#include <linux/usb/musb.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h>
@@ -46,7 +46,7 @@
struct omap2430_glue {
struct device *dev;
struct platform_device *musb;
- enum omap_musb_vbus_id_status status;
+ enum musb_vbus_id_status status;
struct work_struct omap_musb_mailbox_work;
struct device *control_otghs;
};
@@ -234,7 +234,7 @@ static inline void omap2430_low_level_init(struct musb *musb)
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
}
-void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
+static void omap2430_musb_mailbox(enum musb_vbus_id_status status)
{
struct omap2430_glue *glue = _glue;
@@ -251,7 +251,6 @@ void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
schedule_work(&glue->omap_musb_mailbox_work);
}
-EXPORT_SYMBOL_GPL(omap_musb_mailbox);
static void omap_musb_set_mailbox(struct omap2430_glue *glue)
{
@@ -262,7 +261,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
struct usb_otg *otg = musb->xceiv->otg;
switch (glue->status) {
- case OMAP_MUSB_ID_GROUND:
+ case MUSB_ID_GROUND:
dev_dbg(dev, "ID GND\n");
otg->default_a = true;
@@ -276,7 +275,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
}
break;
- case OMAP_MUSB_VBUS_VALID:
+ case MUSB_VBUS_VALID:
dev_dbg(dev, "VBUS Connect\n");
otg->default_a = false;
@@ -287,8 +286,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
break;
- case OMAP_MUSB_ID_FLOAT:
- case OMAP_MUSB_VBUS_OFF:
+ case MUSB_ID_FLOAT:
+ case MUSB_VBUS_OFF:
dev_dbg(dev, "VBUS Disconnect\n");
musb->xceiv->last_event = USB_EVENT_NONE;
@@ -430,7 +429,7 @@ static int omap2430_musb_init(struct musb *musb)
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
- if (glue->status != OMAP_MUSB_UNKNOWN)
+ if (glue->status != MUSB_UNKNOWN)
omap_musb_set_mailbox(glue);
phy_init(musb->phy);
@@ -455,7 +454,7 @@ static void omap2430_musb_enable(struct musb *musb)
switch (glue->status) {
- case OMAP_MUSB_ID_GROUND:
+ case MUSB_ID_GROUND:
omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST);
if (data->interface_type != MUSB_INTERFACE_UTMI)
break;
@@ -474,7 +473,7 @@ static void omap2430_musb_enable(struct musb *musb)
}
break;
- case OMAP_MUSB_VBUS_VALID:
+ case MUSB_VBUS_VALID:
omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
break;
@@ -488,7 +487,7 @@ static void omap2430_musb_disable(struct musb *musb)
struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
- if (glue->status != OMAP_MUSB_UNKNOWN)
+ if (glue->status != MUSB_UNKNOWN)
omap_control_usb_set_mode(glue->control_otghs,
USB_MODE_DISCONNECT);
}
@@ -520,6 +519,8 @@ static const struct musb_platform_ops omap2430_ops = {
.enable = omap2430_musb_enable,
.disable = omap2430_musb_disable,
+
+ .phy_callback = omap2430_musb_mailbox,
};
static u64 omap2430_dmamask = DMA_BIT_MASK(32);
@@ -551,7 +552,7 @@ static int omap2430_probe(struct platform_device *pdev)
glue->dev = &pdev->dev;
glue->musb = musb;
- glue->status = OMAP_MUSB_UNKNOWN;
+ glue->status = MUSB_UNKNOWN;
glue->control_otghs = ERR_PTR(-ENODEV);
if (np) {
@@ -663,8 +664,11 @@ static int omap2430_remove(struct platform_device *pdev)
{
struct omap2430_glue *glue = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(glue->dev);
cancel_work_sync(&glue->omap_musb_mailbox_work);
platform_device_unregister(glue->musb);
+ pm_runtime_put_sync(glue->dev);
+ pm_runtime_disable(glue->dev);
return 0;
}
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 22e8ecb6bfbd..c6904742e2aa 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -66,6 +66,7 @@ config AM335X_PHY_USB
select USB_PHY
select AM335X_CONTROL_USB
select NOP_USB_XCEIV
+ select USB_COMMON
help
This driver provides PHY support for that phy which part for the
AM335x SoC.
@@ -186,19 +187,6 @@ config USB_MXS_PHY
MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
-config USB_RCAR_PHY
- tristate "Renesas R-Car USB PHY support"
- depends on USB || USB_GADGET
- depends on ARCH_R8A7778 || ARCH_R8A7779 || COMPILE_TEST
- select USB_PHY
- help
- Say Y here to add support for the Renesas R-Car USB common PHY driver.
- This chip is typically used as USB PHY for USB host, gadget.
- This driver supports R8A7778 and R8A7779.
-
- To compile this driver as a module, choose M here: the
- module will be called phy-rcar-usb.
-
config USB_ULPI
bool "Generic ULPI Transceiver Driver"
depends on ARM || ARM64
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 19c0dccbb116..b433e5d89be4 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -23,7 +23,6 @@ obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o
obj-$(CONFIG_USB_QCOM_8X16_PHY) += phy-qcom-8x16-usb.o
obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o
obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
-obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
index 7b3035ff9434..42a1afe36a90 100644
--- a/drivers/usb/phy/phy-am335x-control.c
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -4,7 +4,8 @@
#include <linux/of.h>
#include <linux/io.h>
#include <linux/delay.h>
-#include "am35x-phy-control.h"
+#include <linux/usb/otg.h>
+#include "phy-am335x-control.h"
struct am335x_control_usb {
struct device *dev;
@@ -58,7 +59,8 @@ static void am335x_phy_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
spin_unlock(&usb_ctrl->lock);
}
-static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
+static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id,
+ enum usb_dr_mode dr_mode, bool on)
{
struct am335x_control_usb *usb_ctrl;
u32 val;
@@ -80,8 +82,14 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
val = readl(usb_ctrl->phy_reg + reg);
if (on) {
- val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
- val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+ if (dr_mode == USB_DR_MODE_HOST) {
+ val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN |
+ USBPHY_OTGVDET_EN);
+ val |= USBPHY_OTGSESSEND_EN;
+ } else {
+ val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+ val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+ }
} else {
val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
}
diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/phy-am335x-control.h
index b96594d1962c..e86b3165d69d 100644
--- a/drivers/usb/phy/am35x-phy-control.h
+++ b/drivers/usb/phy/phy-am335x-control.h
@@ -2,13 +2,15 @@
#define _AM335x_PHY_CONTROL_H_
struct phy_control {
- void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+ void (*phy_power)(struct phy_control *phy_ctrl, u32 id,
+ enum usb_dr_mode dr_mode, bool on);
void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
};
-static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on)
+static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id,
+ enum usb_dr_mode dr_mode, bool on)
{
- phy_ctrl->phy_power(phy_ctrl, id, on);
+ phy_ctrl->phy_power(phy_ctrl, id, dr_mode, on);
}
static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index 90b67a4ca221..39b424f7f629 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -8,21 +8,23 @@
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/usb/of.h>
-#include "am35x-phy-control.h"
+#include "phy-am335x-control.h"
#include "phy-generic.h"
struct am335x_phy {
struct usb_phy_generic usb_phy_gen;
struct phy_control *phy_ctrl;
int id;
+ enum usb_dr_mode dr_mode;
};
static int am335x_init(struct usb_phy *phy)
{
struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
- phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true);
return 0;
}
@@ -30,7 +32,7 @@ static void am335x_shutdown(struct usb_phy *phy)
{
struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
- phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
}
static int am335x_phy_probe(struct platform_device *pdev)
@@ -46,12 +48,15 @@ static int am335x_phy_probe(struct platform_device *pdev)
am_phy->phy_ctrl = am335x_get_phy_control(dev);
if (!am_phy->phy_ctrl)
return -EPROBE_DEFER;
+
am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
if (am_phy->id < 0) {
dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
return am_phy->id;
}
+ am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node);
+
ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
if (ret)
return ret;
@@ -75,7 +80,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
*/
device_set_wakeup_enable(dev, false);
- phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
return 0;
}
@@ -105,7 +110,7 @@ static int am335x_phy_suspend(struct device *dev)
if (device_may_wakeup(dev))
phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true);
- phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
return 0;
}
@@ -115,7 +120,7 @@ static int am335x_phy_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct am335x_phy *am_phy = platform_get_drvdata(pdev);
- phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true);
if (device_may_wakeup(dev))
phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false);
diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c
deleted file mode 100644
index 1e09b8377885..000000000000
--- a/drivers/usb/phy/phy-rcar-usb.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Renesas R-Car USB phy driver
- *
- * Copyright (C) 2012-2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * 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/delay.h>
-#include <linux/io.h>
-#include <linux/usb/otg.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/platform_data/usb-rcar-phy.h>
-
-/* REGS block */
-#define USBPCTRL0 0x00
-#define USBPCTRL1 0x04
-#define USBST 0x08
-#define USBEH0 0x0C
-#define USBOH0 0x1C
-#define USBCTL0 0x58
-
-/* High-speed signal quality characteristic control registers (R8A7778 only) */
-#define HSQCTL1 0x24
-#define HSQCTL2 0x28
-
-/* USBPCTRL0 */
-#define OVC2 (1 << 10) /* (R8A7779 only) */
- /* Switches the OVC input pin for port 2: */
- /* 1: USB_OVC2, 0: OVC2 */
-#define OVC1_VBUS1 (1 << 9) /* Switches the OVC input pin for port 1: */
- /* 1: USB_OVC1, 0: OVC1/VBUS1 */
- /* Function mode: set to 0 */
-#define OVC0 (1 << 8) /* Switches the OVC input pin for port 0: */
- /* 1: USB_OVC0 pin, 0: OVC0 */
-#define OVC2_ACT (1 << 6) /* (R8A7779 only) */
- /* Host mode: OVC2 polarity: */
- /* 1: active-high, 0: active-low */
-#define PENC (1 << 4) /* Function mode: output level of PENC1 pin: */
- /* 1: high, 0: low */
-#define OVC0_ACT (1 << 3) /* Host mode: OVC0 polarity: */
- /* 1: active-high, 0: active-low */
-#define OVC1_ACT (1 << 1) /* Host mode: OVC1 polarity: */
- /* 1: active-high, 0: active-low */
- /* Function mode: be sure to set to 1 */
-#define PORT1 (1 << 0) /* Selects port 1 mode: */
- /* 1: function, 0: host */
-/* USBPCTRL1 */
-#define PHY_RST (1 << 2)
-#define PLL_ENB (1 << 1)
-#define PHY_ENB (1 << 0)
-
-/* USBST */
-#define ST_ACT (1 << 31)
-#define ST_PLL (1 << 30)
-
-struct rcar_usb_phy_priv {
- struct usb_phy phy;
- spinlock_t lock;
-
- void __iomem *reg0;
- void __iomem *reg1;
- int counter;
-};
-
-#define usb_phy_to_priv(p) container_of(p, struct rcar_usb_phy_priv, phy)
-
-
-/*
- * USB initial/install operation.
- *
- * This function setup USB phy.
- * The used value and setting order came from
- * [USB :: Initial setting] on datasheet.
- */
-static int rcar_usb_phy_init(struct usb_phy *phy)
-{
- struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
- struct device *dev = phy->dev;
- struct rcar_phy_platform_data *pdata = dev_get_platdata(dev);
- void __iomem *reg0 = priv->reg0;
- void __iomem *reg1 = priv->reg1;
- static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
- int i;
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->counter++ == 0) {
-
- /*
- * USB phy start-up
- */
-
- /* (1) USB-PHY standby release */
- iowrite32(PHY_ENB, (reg0 + USBPCTRL1));
-
- /* (2) start USB-PHY internal PLL */
- iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1));
-
- /* (3) set USB-PHY in accord with the conditions of usage */
- if (reg1) {
- u32 hsqctl1 = pdata->ferrite_bead ? 0x41 : 0;
- u32 hsqctl2 = pdata->ferrite_bead ? 0x0d : 7;
-
- iowrite32(hsqctl1, reg1 + HSQCTL1);
- iowrite32(hsqctl2, reg1 + HSQCTL2);
- }
-
- /* (4) USB module status check */
- for (i = 0; i < 1024; i++) {
- udelay(10);
- val = ioread32(reg0 + USBST);
- if (val == (ST_ACT | ST_PLL))
- break;
- }
-
- if (val != (ST_ACT | ST_PLL)) {
- dev_err(dev, "USB phy not ready\n");
- goto phy_init_end;
- }
-
- /* (5) USB-PHY reset clear */
- iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1));
-
- /* Board specific port settings */
- val = 0;
- if (pdata->port1_func)
- val |= PORT1;
- if (pdata->penc1)
- val |= PENC;
- for (i = 0; i < 3; i++) {
- /* OVCn bits follow each other in the right order */
- if (pdata->ovc_pin[i].select_3_3v)
- val |= OVC0 << i;
- /* OVCn_ACT bits are spaced by irregular intervals */
- if (pdata->ovc_pin[i].active_high)
- val |= ovcn_act[i];
- }
- iowrite32(val, (reg0 + USBPCTRL0));
-
- /*
- * Bus alignment settings
- */
-
- /* (1) EHCI bus alignment (little endian) */
- iowrite32(0x00000000, (reg0 + USBEH0));
-
- /* (1) OHCI bus alignment (little endian) */
- iowrite32(0x00000000, (reg0 + USBOH0));
- }
-
-phy_init_end:
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static void rcar_usb_phy_shutdown(struct usb_phy *phy)
-{
- struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
- void __iomem *reg0 = priv->reg0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->counter-- == 1) /* last user */
- iowrite32(0x00000000, (reg0 + USBPCTRL1));
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int rcar_usb_phy_probe(struct platform_device *pdev)
-{
- struct rcar_usb_phy_priv *priv;
- struct resource *res0, *res1;
- struct device *dev = &pdev->dev;
- void __iomem *reg0, *reg1 = NULL;
- int ret;
-
- if (!dev_get_platdata(&pdev->dev)) {
- dev_err(dev, "No platform data\n");
- return -EINVAL;
- }
-
- res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- reg0 = devm_ioremap_resource(dev, res0);
- if (IS_ERR(reg0))
- return PTR_ERR(reg0);
-
- res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- reg1 = devm_ioremap_resource(dev, res1);
- if (IS_ERR(reg1))
- return PTR_ERR(reg1);
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->reg0 = reg0;
- priv->reg1 = reg1;
- priv->counter = 0;
- priv->phy.dev = dev;
- priv->phy.label = dev_name(dev);
- priv->phy.init = rcar_usb_phy_init;
- priv->phy.shutdown = rcar_usb_phy_shutdown;
- spin_lock_init(&priv->lock);
-
- ret = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
- if (ret < 0) {
- dev_err(dev, "usb phy addition error\n");
- return ret;
- }
-
- platform_set_drvdata(pdev, priv);
-
- return ret;
-}
-
-static int rcar_usb_phy_remove(struct platform_device *pdev)
-{
- struct rcar_usb_phy_priv *priv = platform_get_drvdata(pdev);
-
- usb_remove_phy(&priv->phy);
-
- return 0;
-}
-
-static struct platform_driver rcar_usb_phy_driver = {
- .driver = {
- .name = "rcar_usb_phy",
- },
- .probe = rcar_usb_phy_probe,
- .remove = rcar_usb_phy_remove,
-};
-
-module_platform_driver(rcar_usb_phy_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Renesas R-Car USB phy");
-MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 12741856a75c..014dbbd72132 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -25,7 +25,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/usb/musb-omap.h>
+#include <linux/usb/musb.h>
#include <linux/usb/phy_companion.h>
#include <linux/phy/omap_usb.h>
#include <linux/i2c/twl.h>
@@ -102,7 +102,7 @@ struct twl6030_usb {
int irq1;
int irq2;
- enum omap_musb_vbus_id_status linkstat;
+ enum musb_vbus_id_status linkstat;
u8 asleep;
bool vbus_enable;
const char *regulator;
@@ -189,13 +189,13 @@ static ssize_t twl6030_usb_vbus_show(struct device *dev,
spin_lock_irqsave(&twl->lock, flags);
switch (twl->linkstat) {
- case OMAP_MUSB_VBUS_VALID:
+ case MUSB_VBUS_VALID:
ret = snprintf(buf, PAGE_SIZE, "vbus\n");
break;
- case OMAP_MUSB_ID_GROUND:
+ case MUSB_ID_GROUND:
ret = snprintf(buf, PAGE_SIZE, "id\n");
break;
- case OMAP_MUSB_VBUS_OFF:
+ case MUSB_VBUS_OFF:
ret = snprintf(buf, PAGE_SIZE, "none\n");
break;
default:
@@ -210,7 +210,7 @@ static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
struct twl6030_usb *twl = _twl;
- enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
+ enum musb_vbus_id_status status = MUSB_UNKNOWN;
u8 vbus_state, hw_state;
int ret;
@@ -225,14 +225,14 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
dev_err(twl->dev, "Failed to enable usb3v3\n");
twl->asleep = 1;
- status = OMAP_MUSB_VBUS_VALID;
+ status = MUSB_VBUS_VALID;
twl->linkstat = status;
- omap_musb_mailbox(status);
+ musb_mailbox(status);
} else {
- if (twl->linkstat != OMAP_MUSB_UNKNOWN) {
- status = OMAP_MUSB_VBUS_OFF;
+ if (twl->linkstat != MUSB_UNKNOWN) {
+ status = MUSB_VBUS_OFF;
twl->linkstat = status;
- omap_musb_mailbox(status);
+ musb_mailbox(status);
if (twl->asleep) {
regulator_disable(twl->usb3v3);
twl->asleep = 0;
@@ -248,7 +248,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{
struct twl6030_usb *twl = _twl;
- enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
+ enum musb_vbus_id_status status = MUSB_UNKNOWN;
u8 hw_state;
int ret;
@@ -262,9 +262,9 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
twl->asleep = 1;
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
- status = OMAP_MUSB_ID_GROUND;
+ status = MUSB_ID_GROUND;
twl->linkstat = status;
- omap_musb_mailbox(status);
+ musb_mailbox(status);
} else {
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
@@ -334,7 +334,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
twl->dev = &pdev->dev;
twl->irq1 = platform_get_irq(pdev, 0);
twl->irq2 = platform_get_irq(pdev, 1);
- twl->linkstat = OMAP_MUSB_UNKNOWN;
+ twl->linkstat = MUSB_UNKNOWN;
twl->comparator.set_vbus = twl6030_set_vbus;
twl->comparator.start_srp = twl6030_start_srp;
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index d82fa36c3465..5af9ca5d54ab 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -302,37 +302,37 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv)
*/
/* commonly used on old SH-Mobile SoCs */
-static u32 usbhsc_default_pipe_type[] = {
- USB_ENDPOINT_XFER_CONTROL,
- USB_ENDPOINT_XFER_ISOC,
- USB_ENDPOINT_XFER_ISOC,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_INT,
- USB_ENDPOINT_XFER_INT,
- USB_ENDPOINT_XFER_INT,
- USB_ENDPOINT_XFER_INT,
+static struct renesas_usbhs_driver_pipe_config usbhsc_default_pipe[] = {
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x18, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x28, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x38, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x48, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x04, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x05, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x06, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x07, false),
};
/* commonly used on newer SH-Mobile and R-Car SoCs */
-static u32 usbhsc_new_pipe_type[] = {
- USB_ENDPOINT_XFER_CONTROL,
- USB_ENDPOINT_XFER_ISOC,
- USB_ENDPOINT_XFER_ISOC,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_INT,
- USB_ENDPOINT_XFER_INT,
- USB_ENDPOINT_XFER_INT,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
- USB_ENDPOINT_XFER_BULK,
+static struct renesas_usbhs_driver_pipe_config usbhsc_new_pipe[] = {
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x28, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x48, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x58, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x68, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x04, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x05, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x06, false),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x78, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x88, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x98, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xa8, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xb8, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xc8, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xd8, true),
};
/*
@@ -481,6 +481,15 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,usbhs-r8a7795",
.data = (void *)USBHS_TYPE_RCAR_GEN2,
},
+ {
+ .compatible = "renesas,rcar-gen2-usbhs",
+ .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ },
+ {
+ /* Gen3 is compatible with Gen2 */
+ .compatible = "renesas,rcar-gen3-usbhs",
+ .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, usbhs_of_match);
@@ -564,10 +573,9 @@ static int usbhs_probe(struct platform_device *pdev)
switch (priv->dparam.type) {
case USBHS_TYPE_RCAR_GEN2:
priv->pfunc = usbhs_rcar2_ops;
- if (!priv->dparam.pipe_type) {
- priv->dparam.pipe_type = usbhsc_new_pipe_type;
- priv->dparam.pipe_size =
- ARRAY_SIZE(usbhsc_new_pipe_type);
+ if (!priv->dparam.pipe_configs) {
+ priv->dparam.pipe_configs = usbhsc_new_pipe;
+ priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
break;
default:
@@ -586,9 +594,9 @@ static int usbhs_probe(struct platform_device *pdev)
dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
/* set default param if platform doesn't have */
- if (!priv->dparam.pipe_type) {
- priv->dparam.pipe_type = usbhsc_default_pipe_type;
- priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
+ if (!priv->dparam.pipe_configs) {
+ priv->dparam.pipe_configs = usbhsc_default_pipe;
+ priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe);
}
if (!priv->dparam.pio_dma_border)
priv->dparam.pio_dma_border = 64; /* 64byte */
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 8f7a78e70975..657f9672ceba 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -1042,6 +1042,8 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
struct usbhsg_gpriv *gpriv;
struct usbhsg_uep *uep;
struct device *dev = usbhs_priv_to_dev(priv);
+ struct renesas_usbhs_driver_pipe_config *pipe_configs =
+ usbhs_get_dparam(priv, pipe_configs);
int pipe_size = usbhs_get_dparam(priv, pipe_size);
int i;
int ret;
@@ -1111,13 +1113,16 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
gpriv->gadget.ep0 = &uep->ep;
usb_ep_set_maxpacket_limit(&uep->ep, 64);
uep->ep.caps.type_control = true;
- }
- /* init normal pipe */
- else {
- usb_ep_set_maxpacket_limit(&uep->ep, 512);
- uep->ep.caps.type_iso = true;
- uep->ep.caps.type_bulk = true;
- uep->ep.caps.type_int = true;
+ } else {
+ /* init normal pipe */
+ if (pipe_configs[i].type == USB_ENDPOINT_XFER_ISOC)
+ uep->ep.caps.type_iso = true;
+ if (pipe_configs[i].type == USB_ENDPOINT_XFER_BULK)
+ uep->ep.caps.type_bulk = true;
+ if (pipe_configs[i].type == USB_ENDPOINT_XFER_INT)
+ uep->ep.caps.type_int = true;
+ usb_ep_set_maxpacket_limit(&uep->ep,
+ pipe_configs[i].bufsize);
list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list);
}
uep->ep.caps.dir_in = true;
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index bd050359926c..1a8e4c45c4c5 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -1414,7 +1414,8 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
{
struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
struct usbhs_pipe *pipe;
- u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);
+ struct renesas_usbhs_driver_pipe_config *pipe_configs =
+ usbhs_get_dparam(priv, pipe_configs);
int pipe_size = usbhs_get_dparam(priv, pipe_size);
int old_type, dir_in, i;
@@ -1442,15 +1443,15 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
* USB_ENDPOINT_XFER_BULK -> dir in
* ...
*/
- dir_in = (pipe_type[i] == old_type);
- old_type = pipe_type[i];
+ dir_in = (pipe_configs[i].type == old_type);
+ old_type = pipe_configs[i].type;
- if (USB_ENDPOINT_XFER_CONTROL == pipe_type[i]) {
+ if (USB_ENDPOINT_XFER_CONTROL == pipe_configs[i].type) {
pipe = usbhs_dcp_malloc(priv);
usbhsh_hpriv_to_dcp(hpriv) = pipe;
} else {
pipe = usbhs_pipe_malloc(priv,
- pipe_type[i],
+ pipe_configs[i].type,
dir_in);
}
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 4f9c3356127a..0e95d2925dc5 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -44,6 +44,15 @@ char *usbhs_pipe_name(struct usbhs_pipe *pipe)
return usbhsp_pipe_name[usbhs_pipe_type(pipe)];
}
+static struct renesas_usbhs_driver_pipe_config
+*usbhsp_get_pipe_config(struct usbhs_priv *priv, int pipe_num)
+{
+ struct renesas_usbhs_driver_pipe_config *pipe_configs =
+ usbhs_get_dparam(priv, pipe_configs);
+
+ return &pipe_configs[pipe_num];
+}
+
/*
* DCPCTR/PIPEnCTR functions
*/
@@ -384,18 +393,6 @@ void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
/*
* pipe setup
*/
-static int usbhsp_possible_double_buffer(struct usbhs_pipe *pipe)
-{
- /*
- * only ISO / BULK pipe can use double buffer
- */
- if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) ||
- usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
- return 1;
-
- return 0;
-}
-
static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
int is_host,
int dir_in)
@@ -412,7 +409,6 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
[USB_ENDPOINT_XFER_INT] = TYPE_INT,
[USB_ENDPOINT_XFER_ISOC] = TYPE_ISO,
};
- int is_double = usbhsp_possible_double_buffer(pipe);
if (usbhs_pipe_is_dcp(pipe))
return -EINVAL;
@@ -434,10 +430,7 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
bfre = 0; /* FIXME */
- /* DBLB */
- if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
- usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
- dblb = (is_double) ? DBLB : 0;
+ /* DBLB: see usbhs_pipe_config_update() */
/* CNTMD */
if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
@@ -473,13 +466,13 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
- struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct device *dev = usbhs_priv_to_dev(priv);
int pipe_num = usbhs_pipe_number(pipe);
- int is_double = usbhsp_possible_double_buffer(pipe);
u16 buff_size;
u16 bufnmb;
u16 bufnmb_cnt;
+ struct renesas_usbhs_driver_pipe_config *pipe_config =
+ usbhsp_get_pipe_config(priv, pipe_num);
/*
* PIPEBUF
@@ -489,56 +482,13 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
* - "Features" - "Pipe configuration"
* - "Operation" - "FIFO Buffer Memory"
* - "Operation" - "Pipe Control"
- *
- * ex) if pipe6 - pipe9 are USB_ENDPOINT_XFER_INT (SH7724)
- *
- * BUFNMB: PIPE
- * 0: pipe0 (DCP 256byte)
- * 1: -
- * 2: -
- * 3: -
- * 4: pipe6 (INT 64byte)
- * 5: pipe7 (INT 64byte)
- * 6: pipe8 (INT 64byte)
- * 7: pipe9 (INT 64byte)
- * 8 - xx: free (for BULK, ISOC)
*/
-
- /*
- * FIXME
- *
- * it doesn't have good buffer allocator
- *
- * DCP : 256 byte
- * BULK: 512 byte
- * INT : 64 byte
- * ISOC: 512 byte
- */
- if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_CONTROL))
- buff_size = 256;
- else if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT))
- buff_size = 64;
- else
- buff_size = 512;
+ buff_size = pipe_config->bufsize;
+ bufnmb = pipe_config->bufnum;
/* change buff_size to register value */
bufnmb_cnt = (buff_size / 64) - 1;
- /* BUFNMB has been reserved for INT pipe
- * see above */
- if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT)) {
- bufnmb = pipe_num - 2;
- } else {
- bufnmb = info->bufnmb_last;
- info->bufnmb_last += bufnmb_cnt + 1;
-
- /*
- * double buffer
- */
- if (is_double)
- info->bufnmb_last += bufnmb_cnt + 1;
- }
-
dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n",
pipe_num, buff_size, bufnmb);
@@ -549,8 +499,13 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
u16 epnum, u16 maxp)
{
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ int pipe_num = usbhs_pipe_number(pipe);
+ struct renesas_usbhs_driver_pipe_config *pipe_config =
+ usbhsp_get_pipe_config(priv, pipe_num);
+ u16 dblb = pipe_config->double_buf ? DBLB : 0;
+
if (devsel > 0xA) {
- struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct device *dev = usbhs_priv_to_dev(priv);
dev_err(dev, "devsel error %d\n", devsel);
@@ -568,7 +523,7 @@ void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
maxp);
if (!usbhs_pipe_is_dcp(pipe))
- usbhsp_pipe_cfg_set(pipe, 0x000F, epnum);
+ usbhsp_pipe_cfg_set(pipe, 0x000F | DBLB, epnum | dblb);
}
/*
@@ -708,23 +663,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
struct usbhs_pipe *pipe;
int i;
- /*
- * FIXME
- *
- * driver needs good allocator.
- *
- * find first free buffer area (BULK, ISOC)
- * (DCP, INT area is fixed)
- *
- * buffer number 0 - 3 have been reserved for DCP
- * see
- * usbhsp_to_bufnmb
- */
- info->bufnmb_last = 4;
usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
- if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT))
- info->bufnmb_last++;
-
usbhsp_flags_init(pipe);
pipe->fifo = NULL;
pipe->mod_private = NULL;
@@ -851,12 +790,13 @@ int usbhs_pipe_probe(struct usbhs_priv *priv)
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct usbhs_pipe *pipe;
struct device *dev = usbhs_priv_to_dev(priv);
- u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);
+ struct renesas_usbhs_driver_pipe_config *pipe_configs =
+ usbhs_get_dparam(priv, pipe_configs);
int pipe_size = usbhs_get_dparam(priv, pipe_size);
int i;
/* This driver expects 1st pipe is DCP */
- if (pipe_type[0] != USB_ENDPOINT_XFER_CONTROL) {
+ if (pipe_configs[0].type != USB_ENDPOINT_XFER_CONTROL) {
dev_err(dev, "1st PIPE is not DCP\n");
return -EINVAL;
}
@@ -876,10 +816,10 @@ int usbhs_pipe_probe(struct usbhs_priv *priv)
pipe->priv = priv;
usbhs_pipe_type(pipe) =
- pipe_type[i] & USB_ENDPOINT_XFERTYPE_MASK;
+ pipe_configs[i].type & USB_ENDPOINT_XFERTYPE_MASK;
dev_dbg(dev, "pipe %x\t: %s\n",
- i, usbhsp_pipe_name[pipe_type[i]]);
+ i, usbhsp_pipe_name[pipe_configs[i].type]);
}
return 0;
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index b0bc7b603016..3212ab51e844 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -46,7 +46,6 @@ struct usbhs_pipe {
struct usbhs_pipe_info {
struct usbhs_pipe *pipe;
int size; /* array size of "pipe" */
- int bufnmb_last; /* FIXME : driver needs good allocator */
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map);
};
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b5115d..f612dda9c977 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -475,6 +475,22 @@ config USB_SERIAL_MOS7840
To compile this driver as a module, choose M here: the
module will be called mos7840. If unsure, choose N.
+config USB_SERIAL_MXUPORT11
+ tristate "USB Moxa UPORT 11x0 Serial Driver"
+ ---help---
+ Say Y here if you want to use a MOXA UPort 11x0 Serial hub.
+
+ This driver supports:
+
+ - UPort 1110 : 1 port RS-232 USB to Serial Hub.
+ - UPort 1130 : 1 port RS-422/485 USB to Serial Hub.
+ - UPort 1130I : 1 port RS-422/485 USB to Serial Hub with Isolation.
+ - UPort 1150 : 1 port RS-232/422/485 USB to Serial Hub.
+ - UPort 1150I : 1 port RS-232/422/485 USB to Serial Hub with Isolation.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mxu11x0.
+
config USB_SERIAL_MXUPORT
tristate "USB Moxa UPORT Serial Driver"
---help---
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 349d9df0895f..f3fa5e53702d 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_MXUPORT) += mxuport.o
+obj-$(CONFIG_USB_SERIAL_MXUPORT11) += mxu11x0.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 7d4f51a32e66..9b90ad747d87 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -38,13 +38,14 @@ static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
struct ktermios *);
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
struct ktermios*);
+static bool cp210x_tx_empty(struct usb_serial_port *port);
static int cp210x_tiocmget(struct tty_struct *);
static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int, unsigned int);
static void cp210x_break_ctl(struct tty_struct *, int);
-static int cp210x_startup(struct usb_serial *);
-static void cp210x_release(struct usb_serial *);
+static int cp210x_port_probe(struct usb_serial_port *);
+static int cp210x_port_remove(struct usb_serial_port *);
static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
static const struct usb_device_id id_table[] = {
@@ -160,6 +161,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+ { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
{ USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */
@@ -196,8 +198,9 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-struct cp210x_serial_private {
+struct cp210x_port_private {
__u8 bInterfaceNumber;
+ bool has_swapped_line_ctl;
};
static struct usb_serial_driver cp210x_device = {
@@ -213,10 +216,11 @@ static struct usb_serial_driver cp210x_device = {
.close = cp210x_close,
.break_ctl = cp210x_break_ctl,
.set_termios = cp210x_set_termios,
+ .tx_empty = cp210x_tx_empty,
.tiocmget = cp210x_tiocmget,
.tiocmset = cp210x_tiocmset,
- .attach = cp210x_startup,
- .release = cp210x_release,
+ .port_probe = cp210x_port_probe,
+ .port_remove = cp210x_port_remove,
.dtr_rts = cp210x_dtr_rts
};
@@ -299,6 +303,25 @@ static struct usb_serial_driver * const serial_drivers[] = {
#define CONTROL_WRITE_DTR 0x0100
#define CONTROL_WRITE_RTS 0x0200
+/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
+struct cp210x_comm_status {
+ __le32 ulErrors;
+ __le32 ulHoldReasons;
+ __le32 ulAmountInInQueue;
+ __le32 ulAmountInOutQueue;
+ u8 bEofReceived;
+ u8 bWaitForImmediate;
+ u8 bReserved;
+} __packed;
+
+/*
+ * CP210X_PURGE - 16 bits passed in wValue of USB request.
+ * SiLabs app note AN571 gives a strange description of the 4 bits:
+ * bit 0 or bit 2 clears the transmit queue and 1 or 3 receive.
+ * writing 1 to all, however, purges cp2108 well enough to avoid the hang.
+ */
+#define PURGE_ALL 0x000f
+
/*
* cp210x_get_config
* Reads from the CP210x configuration registers
@@ -310,7 +333,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
__le32 *buf;
int result, i, length;
@@ -324,7 +347,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
- spriv->bInterfaceNumber, buf, size,
+ port_priv->bInterfaceNumber, buf, size,
USB_CTRL_GET_TIMEOUT);
/* Convert data into an array of integers */
@@ -355,7 +378,7 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
__le32 *buf;
int result, i, length;
@@ -374,13 +397,13 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
- spriv->bInterfaceNumber, buf, size,
+ port_priv->bInterfaceNumber, buf, size,
USB_CTRL_SET_TIMEOUT);
} else {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
request, REQTYPE_HOST_TO_INTERFACE, data[0],
- spriv->bInterfaceNumber, NULL, 0,
+ port_priv->bInterfaceNumber, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
@@ -410,6 +433,60 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,
}
/*
+ * Detect CP2108 GET_LINE_CTL bug and activate workaround.
+ * Write a known good value 0x800, read it back.
+ * If it comes back swapped the bug is detected.
+ * Preserve the original register value.
+ */
+static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port)
+{
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
+ unsigned int line_ctl_save;
+ unsigned int line_ctl_test;
+ int err;
+
+ err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_save, 2);
+ if (err)
+ return err;
+
+ line_ctl_test = 0x800;
+ err = cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_test, 2);
+ if (err)
+ return err;
+
+ err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_test, 2);
+ if (err)
+ return err;
+
+ if (line_ctl_test == 8) {
+ port_priv->has_swapped_line_ctl = true;
+ line_ctl_save = swab16((u16)line_ctl_save);
+ }
+
+ return cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_save, 2);
+}
+
+/*
+ * Must always be called instead of cp210x_get_config(CP210X_GET_LINE_CTL)
+ * to workaround cp2108 bug and get correct value.
+ */
+static int cp210x_get_line_ctl(struct usb_serial_port *port, unsigned int *ctl)
+{
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
+ int err;
+
+ err = cp210x_get_config(port, CP210X_GET_LINE_CTL, ctl, 2);
+ if (err)
+ return err;
+
+ /* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */
+ if (port_priv->has_swapped_line_ctl)
+ *ctl = swab16((u16)(*ctl));
+
+ return 0;
+}
+
+/*
* cp210x_quantise_baudrate
* Quantises the baud rate as per AN205 Table 1
*/
@@ -474,11 +551,63 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
+ unsigned int purge_ctl;
+
usb_serial_generic_close(port);
+
+ /* Clear both queues; cp2108 needs this to avoid an occasional hang */
+ purge_ctl = PURGE_ALL;
+ cp210x_set_config(port, CP210X_PURGE, &purge_ctl, 2);
+
cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
/*
+ * Read how many bytes are waiting in the TX queue.
+ */
+static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
+ u32 *count)
+{
+ struct usb_serial *serial = port->serial;
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
+ struct cp210x_comm_status *sts;
+ int result;
+
+ sts = kmalloc(sizeof(*sts), GFP_KERNEL);
+ if (!sts)
+ return -ENOMEM;
+
+ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ CP210X_GET_COMM_STATUS, REQTYPE_INTERFACE_TO_HOST,
+ 0, port_priv->bInterfaceNumber, sts, sizeof(*sts),
+ USB_CTRL_GET_TIMEOUT);
+ if (result == sizeof(*sts)) {
+ *count = le32_to_cpu(sts->ulAmountInOutQueue);
+ result = 0;
+ } else {
+ dev_err(&port->dev, "failed to get comm status: %d\n", result);
+ if (result >= 0)
+ result = -EPROTO;
+ }
+
+ kfree(sts);
+
+ return result;
+}
+
+static bool cp210x_tx_empty(struct usb_serial_port *port)
+{
+ int err;
+ u32 count;
+
+ err = cp210x_get_tx_queue_byte_count(port, &count);
+ if (err)
+ return true;
+
+ return !count;
+}
+
+/*
* cp210x_get_termios
* Reads the baud rate, data bits, parity, stop bits and flow control mode
* from the device, corrects any unsupported values, and configures the
@@ -519,7 +648,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
cflag = *cflagp;
- cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
+ cp210x_get_line_ctl(port, &bits);
cflag &= ~CSIZE;
switch (bits & BITS_DATA_MASK) {
case BITS_DATA_5:
@@ -687,7 +816,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
/* If the number of data bits is to be updated */
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
- cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
+ cp210x_get_line_ctl(port, &bits);
bits &= ~BITS_DATA_MASK;
switch (cflag & CSIZE) {
case CS5:
@@ -721,7 +850,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
if ((cflag & (PARENB|PARODD|CMSPAR)) !=
(old_cflag & (PARENB|PARODD|CMSPAR))) {
- cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
+ cp210x_get_line_ctl(port, &bits);
bits &= ~BITS_PARITY_MASK;
if (cflag & PARENB) {
if (cflag & CMSPAR) {
@@ -747,7 +876,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
}
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
- cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
+ cp210x_get_line_ctl(port, &bits);
bits &= ~BITS_STOP_MASK;
if (cflag & CSTOPB) {
bits |= BITS_STOP_2;
@@ -862,29 +991,39 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
}
-static int cp210x_startup(struct usb_serial *serial)
+static int cp210x_port_probe(struct usb_serial_port *port)
{
+ struct usb_serial *serial = port->serial;
struct usb_host_interface *cur_altsetting;
- struct cp210x_serial_private *spriv;
+ struct cp210x_port_private *port_priv;
+ int ret;
- spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
- if (!spriv)
+ port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+ if (!port_priv)
return -ENOMEM;
cur_altsetting = serial->interface->cur_altsetting;
- spriv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
+ port_priv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
+
+ usb_set_serial_port_data(port, port_priv);
- usb_set_serial_data(serial, spriv);
+ ret = cp210x_detect_swapped_line_ctl(port);
+ if (ret) {
+ kfree(port_priv);
+ return ret;
+ }
return 0;
}
-static void cp210x_release(struct usb_serial *serial)
+static int cp210x_port_remove(struct usb_serial_port *port)
{
- struct cp210x_serial_private *spriv;
+ struct cp210x_port_private *port_priv;
+
+ port_priv = usb_get_serial_port_data(port);
+ kfree(port_priv);
- spriv = usb_get_serial_data(serial);
- kfree(spriv);
+ return 0;
}
module_usb_serial_driver(serial_drivers, id_table);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index c0866971db2b..f49327d20ee8 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1046,9 +1046,8 @@ static void edge_close(struct usb_serial_port *port)
edge_port->closePending = true;
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPChase) {
/* flush and chase */
edge_port->chaseResponsePending = true;
@@ -1061,9 +1060,8 @@ static void edge_close(struct usb_serial_port *port)
edge_port->chaseResponsePending = false;
}
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPClose) {
/* close the port */
dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLOSE_PORT\n", __func__);
send_iosp_ext_cmd(edge_port, IOSP_CMD_CLOSE_PORT, 0);
@@ -1612,9 +1610,8 @@ static void edge_break(struct tty_struct *tty, int break_state)
struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
int status;
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPChase) {
/* flush and chase */
edge_port->chaseResponsePending = true;
@@ -1628,9 +1625,8 @@ static void edge_break(struct tty_struct *tty, int break_state)
}
}
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPSetClrBreak) {
if (break_state == -1) {
dev_dbg(&port->dev, "%s - Sending IOSP_CMD_SET_BREAK\n", __func__);
status = send_iosp_ext_cmd(edge_port,
@@ -2465,9 +2461,8 @@ static void change_port_settings(struct tty_struct *tty,
unsigned char stop_char = STOP_CHAR(tty);
unsigned char start_char = START_CHAR(tty);
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPSetXChar) {
send_iosp_ext_cmd(edge_port,
IOSP_CMD_SET_XON_CHAR, start_char);
send_iosp_ext_cmd(edge_port,
@@ -2494,13 +2489,11 @@ static void change_port_settings(struct tty_struct *tty,
}
/* Set flow control to the configured value */
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)
send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+ if (!edge_serial->is_epic ||
+ edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)
send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 8ac9b55f05af..2c69bfcdacc6 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -635,7 +635,7 @@ static void mos7840_interrupt_callback(struct urb *urb)
* Byte 4 IIR Port 4 (port.number is 3)
* Byte 5 FIFO status for both */
- if (length && length > 5) {
+ if (length > 5) {
dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n");
return;
}
diff --git a/drivers/usb/serial/mxu11x0.c b/drivers/usb/serial/mxu11x0.c
new file mode 100644
index 000000000000..e3c3f57c2d82
--- /dev/null
+++ b/drivers/usb/serial/mxu11x0.c
@@ -0,0 +1,986 @@
+/*
+ * USB Moxa UPORT 11x0 Serial Driver
+ *
+ * Copyright (C) 2007 MOXA Technologies Co., Ltd.
+ * Copyright (C) 2015 Mathieu Othacehe <m.othacehe@gmail.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.
+ *
+ *
+ * Supports the following Moxa USB to serial converters:
+ * UPort 1110, 1 port RS-232 USB to Serial Hub.
+ * UPort 1130, 1 port RS-422/485 USB to Serial Hub.
+ * UPort 1130I, 1 port RS-422/485 USB to Serial Hub with isolation
+ * protection.
+ * UPort 1150, 1 port RS-232/422/485 USB to Serial Hub.
+ * UPort 1150I, 1 port RS-232/422/485 USB to Serial Hub with isolation
+ * protection.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+/* Vendor and product ids */
+#define MXU1_VENDOR_ID 0x110a
+#define MXU1_1110_PRODUCT_ID 0x1110
+#define MXU1_1130_PRODUCT_ID 0x1130
+#define MXU1_1150_PRODUCT_ID 0x1150
+#define MXU1_1151_PRODUCT_ID 0x1151
+#define MXU1_1131_PRODUCT_ID 0x1131
+
+/* Commands */
+#define MXU1_GET_VERSION 0x01
+#define MXU1_GET_PORT_STATUS 0x02
+#define MXU1_GET_PORT_DEV_INFO 0x03
+#define MXU1_GET_CONFIG 0x04
+#define MXU1_SET_CONFIG 0x05
+#define MXU1_OPEN_PORT 0x06
+#define MXU1_CLOSE_PORT 0x07
+#define MXU1_START_PORT 0x08
+#define MXU1_STOP_PORT 0x09
+#define MXU1_TEST_PORT 0x0A
+#define MXU1_PURGE_PORT 0x0B
+#define MXU1_RESET_EXT_DEVICE 0x0C
+#define MXU1_GET_OUTQUEUE 0x0D
+#define MXU1_WRITE_DATA 0x80
+#define MXU1_READ_DATA 0x81
+#define MXU1_REQ_TYPE_CLASS 0x82
+
+/* Module identifiers */
+#define MXU1_I2C_PORT 0x01
+#define MXU1_IEEE1284_PORT 0x02
+#define MXU1_UART1_PORT 0x03
+#define MXU1_UART2_PORT 0x04
+#define MXU1_RAM_PORT 0x05
+
+/* Modem status */
+#define MXU1_MSR_DELTA_CTS 0x01
+#define MXU1_MSR_DELTA_DSR 0x02
+#define MXU1_MSR_DELTA_RI 0x04
+#define MXU1_MSR_DELTA_CD 0x08
+#define MXU1_MSR_CTS 0x10
+#define MXU1_MSR_DSR 0x20
+#define MXU1_MSR_RI 0x40
+#define MXU1_MSR_CD 0x80
+#define MXU1_MSR_DELTA_MASK 0x0F
+#define MXU1_MSR_MASK 0xF0
+
+/* Line status */
+#define MXU1_LSR_OVERRUN_ERROR 0x01
+#define MXU1_LSR_PARITY_ERROR 0x02
+#define MXU1_LSR_FRAMING_ERROR 0x04
+#define MXU1_LSR_BREAK 0x08
+#define MXU1_LSR_ERROR 0x0F
+#define MXU1_LSR_RX_FULL 0x10
+#define MXU1_LSR_TX_EMPTY 0x20
+
+/* Modem control */
+#define MXU1_MCR_LOOP 0x04
+#define MXU1_MCR_DTR 0x10
+#define MXU1_MCR_RTS 0x20
+
+/* Mask settings */
+#define MXU1_UART_ENABLE_RTS_IN 0x0001
+#define MXU1_UART_DISABLE_RTS 0x0002
+#define MXU1_UART_ENABLE_PARITY_CHECKING 0x0008
+#define MXU1_UART_ENABLE_DSR_OUT 0x0010
+#define MXU1_UART_ENABLE_CTS_OUT 0x0020
+#define MXU1_UART_ENABLE_X_OUT 0x0040
+#define MXU1_UART_ENABLE_XA_OUT 0x0080
+#define MXU1_UART_ENABLE_X_IN 0x0100
+#define MXU1_UART_ENABLE_DTR_IN 0x0800
+#define MXU1_UART_DISABLE_DTR 0x1000
+#define MXU1_UART_ENABLE_MS_INTS 0x2000
+#define MXU1_UART_ENABLE_AUTO_START_DMA 0x4000
+#define MXU1_UART_SEND_BREAK_SIGNAL 0x8000
+
+/* Parity */
+#define MXU1_UART_NO_PARITY 0x00
+#define MXU1_UART_ODD_PARITY 0x01
+#define MXU1_UART_EVEN_PARITY 0x02
+#define MXU1_UART_MARK_PARITY 0x03
+#define MXU1_UART_SPACE_PARITY 0x04
+
+/* Stop bits */
+#define MXU1_UART_1_STOP_BITS 0x00
+#define MXU1_UART_1_5_STOP_BITS 0x01
+#define MXU1_UART_2_STOP_BITS 0x02
+
+/* Bits per character */
+#define MXU1_UART_5_DATA_BITS 0x00
+#define MXU1_UART_6_DATA_BITS 0x01
+#define MXU1_UART_7_DATA_BITS 0x02
+#define MXU1_UART_8_DATA_BITS 0x03
+
+/* Operation modes */
+#define MXU1_UART_232 0x00
+#define MXU1_UART_485_RECEIVER_DISABLED 0x01
+#define MXU1_UART_485_RECEIVER_ENABLED 0x02
+
+/* Pipe transfer mode and timeout */
+#define MXU1_PIPE_MODE_CONTINUOUS 0x01
+#define MXU1_PIPE_MODE_MASK 0x03
+#define MXU1_PIPE_TIMEOUT_MASK 0x7C
+#define MXU1_PIPE_TIMEOUT_ENABLE 0x80
+
+/* Config struct */
+struct mxu1_uart_config {
+ __be16 wBaudRate;
+ __be16 wFlags;
+ u8 bDataBits;
+ u8 bParity;
+ u8 bStopBits;
+ char cXon;
+ char cXoff;
+ u8 bUartMode;
+} __packed;
+
+/* Purge modes */
+#define MXU1_PURGE_OUTPUT 0x00
+#define MXU1_PURGE_INPUT 0x80
+
+/* Read/Write data */
+#define MXU1_RW_DATA_ADDR_SFR 0x10
+#define MXU1_RW_DATA_ADDR_IDATA 0x20
+#define MXU1_RW_DATA_ADDR_XDATA 0x30
+#define MXU1_RW_DATA_ADDR_CODE 0x40
+#define MXU1_RW_DATA_ADDR_GPIO 0x50
+#define MXU1_RW_DATA_ADDR_I2C 0x60
+#define MXU1_RW_DATA_ADDR_FLASH 0x70
+#define MXU1_RW_DATA_ADDR_DSP 0x80
+
+#define MXU1_RW_DATA_UNSPECIFIED 0x00
+#define MXU1_RW_DATA_BYTE 0x01
+#define MXU1_RW_DATA_WORD 0x02
+#define MXU1_RW_DATA_DOUBLE_WORD 0x04
+
+struct mxu1_write_data_bytes {
+ u8 bAddrType;
+ u8 bDataType;
+ u8 bDataCounter;
+ __be16 wBaseAddrHi;
+ __be16 wBaseAddrLo;
+ u8 bData[0];
+} __packed;
+
+/* Interrupt codes */
+#define MXU1_CODE_HARDWARE_ERROR 0xFF
+#define MXU1_CODE_DATA_ERROR 0x03
+#define MXU1_CODE_MODEM_STATUS 0x04
+
+static inline int mxu1_get_func_from_code(unsigned char code)
+{
+ return code & 0x0f;
+}
+
+/* Download firmware max packet size */
+#define MXU1_DOWNLOAD_MAX_PACKET_SIZE 64
+
+/* Firmware image header */
+struct mxu1_firmware_header {
+ __le16 wLength;
+ u8 bCheckSum;
+} __packed;
+
+#define MXU1_UART_BASE_ADDR 0xFFA0
+#define MXU1_UART_OFFSET_MCR 0x0004
+
+#define MXU1_BAUD_BASE 923077
+
+#define MXU1_TRANSFER_TIMEOUT 2
+#define MXU1_DOWNLOAD_TIMEOUT 1000
+#define MXU1_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */
+
+struct mxu1_port {
+ u8 msr;
+ u8 mcr;
+ u8 uart_mode;
+ spinlock_t spinlock; /* Protects msr */
+ struct mutex mutex; /* Protects mcr */
+ bool send_break;
+};
+
+struct mxu1_device {
+ u16 mxd_model;
+};
+
+static const struct usb_device_id mxu1_idtable[] = {
+ { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
+ { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
+ { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
+ { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
+ { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, mxu1_idtable);
+
+/* Write the given buffer out to the control pipe. */
+static int mxu1_send_ctrl_data_urb(struct usb_serial *serial,
+ u8 request,
+ u16 value, u16 index,
+ void *data, size_t size)
+{
+ int status;
+
+ status = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ request,
+ (USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE), value, index,
+ data, size,
+ USB_CTRL_SET_TIMEOUT);
+ if (status < 0) {
+ dev_err(&serial->interface->dev,
+ "%s - usb_control_msg failed: %d\n",
+ __func__, status);
+ return status;
+ }
+
+ if (status != size) {
+ dev_err(&serial->interface->dev,
+ "%s - short write (%d / %zd)\n",
+ __func__, status, size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* Send a vendor request without any data */
+static int mxu1_send_ctrl_urb(struct usb_serial *serial,
+ u8 request, u16 value, u16 index)
+{
+ return mxu1_send_ctrl_data_urb(serial, request, value, index,
+ NULL, 0);
+}
+
+static int mxu1_download_firmware(struct usb_serial *serial,
+ const struct firmware *fw_p)
+{
+ int status = 0;
+ int buffer_size;
+ int pos;
+ int len;
+ int done;
+ u8 cs = 0;
+ u8 *buffer;
+ struct usb_device *dev = serial->dev;
+ struct mxu1_firmware_header *header;
+ unsigned int pipe;
+
+ pipe = usb_sndbulkpipe(dev, serial->port[0]->bulk_out_endpointAddress);
+
+ buffer_size = fw_p->size + sizeof(*header);
+ buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ memcpy(buffer, fw_p->data, fw_p->size);
+ memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size);
+
+ for (pos = sizeof(*header); pos < buffer_size; pos++)
+ cs = (u8)(cs + buffer[pos]);
+
+ header = (struct mxu1_firmware_header *)buffer;
+ header->wLength = cpu_to_le16(buffer_size - sizeof(*header));
+ header->bCheckSum = cs;
+
+ dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__);
+
+ for (pos = 0; pos < buffer_size; pos += done) {
+ len = min(buffer_size - pos, MXU1_DOWNLOAD_MAX_PACKET_SIZE);
+
+ status = usb_bulk_msg(dev, pipe, buffer + pos, len, &done,
+ MXU1_DOWNLOAD_TIMEOUT);
+ if (status)
+ break;
+ }
+
+ kfree(buffer);
+
+ if (status) {
+ dev_err(&dev->dev, "failed to download firmware: %d\n", status);
+ return status;
+ }
+
+ msleep_interruptible(100);
+ usb_reset_device(dev);
+
+ dev_dbg(&dev->dev, "%s - download successful\n", __func__);
+
+ return 0;
+}
+
+static int mxu1_port_probe(struct usb_serial_port *port)
+{
+ struct mxu1_port *mxport;
+ struct mxu1_device *mxdev;
+
+ if (!port->interrupt_in_urb) {
+ dev_err(&port->dev, "no interrupt urb\n");
+ return -ENODEV;
+ }
+
+ mxport = kzalloc(sizeof(struct mxu1_port), GFP_KERNEL);
+ if (!mxport)
+ return -ENOMEM;
+
+ spin_lock_init(&mxport->spinlock);
+ mutex_init(&mxport->mutex);
+
+ mxdev = usb_get_serial_data(port->serial);
+
+ switch (mxdev->mxd_model) {
+ case MXU1_1110_PRODUCT_ID:
+ case MXU1_1150_PRODUCT_ID:
+ case MXU1_1151_PRODUCT_ID:
+ mxport->uart_mode = MXU1_UART_232;
+ break;
+ case MXU1_1130_PRODUCT_ID:
+ case MXU1_1131_PRODUCT_ID:
+ mxport->uart_mode = MXU1_UART_485_RECEIVER_DISABLED;
+ break;
+ }
+
+ usb_set_serial_port_data(port, mxport);
+
+ port->port.closing_wait =
+ msecs_to_jiffies(MXU1_DEFAULT_CLOSING_WAIT * 10);
+ port->port.drain_delay = 1;
+
+ return 0;
+}
+
+static int mxu1_startup(struct usb_serial *serial)
+{
+ struct mxu1_device *mxdev;
+ struct usb_device *dev = serial->dev;
+ struct usb_host_interface *cur_altsetting;
+ char fw_name[32];
+ const struct firmware *fw_p = NULL;
+ int err;
+
+ dev_dbg(&serial->interface->dev, "%s - product 0x%04X, num configurations %d, configuration value %d\n",
+ __func__, le16_to_cpu(dev->descriptor.idProduct),
+ dev->descriptor.bNumConfigurations,
+ dev->actconfig->desc.bConfigurationValue);
+
+ /* create device structure */
+ mxdev = kzalloc(sizeof(struct mxu1_device), GFP_KERNEL);
+ if (!mxdev)
+ return -ENOMEM;
+
+ usb_set_serial_data(serial, mxdev);
+
+ mxdev->mxd_model = le16_to_cpu(dev->descriptor.idProduct);
+
+ cur_altsetting = serial->interface->cur_altsetting;
+
+ /* if we have only 1 configuration, download firmware */
+ if (cur_altsetting->desc.bNumEndpoints == 1) {
+
+ snprintf(fw_name,
+ sizeof(fw_name),
+ "moxa/moxa-%04x.fw",
+ mxdev->mxd_model);
+
+ err = request_firmware(&fw_p, fw_name, &serial->interface->dev);
+ if (err) {
+ dev_err(&serial->interface->dev, "failed to request firmware: %d\n",
+ err);
+ goto err_free_mxdev;
+ }
+
+ err = mxu1_download_firmware(serial, fw_p);
+ if (err)
+ goto err_release_firmware;
+
+ /* device is being reset */
+ err = -ENODEV;
+ goto err_release_firmware;
+ }
+
+ return 0;
+
+err_release_firmware:
+ release_firmware(fw_p);
+err_free_mxdev:
+ kfree(mxdev);
+
+ return err;
+}
+
+static int mxu1_write_byte(struct usb_serial_port *port, u32 addr,
+ u8 mask, u8 byte)
+{
+ int status;
+ size_t size;
+ struct mxu1_write_data_bytes *data;
+
+ dev_dbg(&port->dev, "%s - addr 0x%08X, mask 0x%02X, byte 0x%02X\n",
+ __func__, addr, mask, byte);
+
+ size = sizeof(struct mxu1_write_data_bytes) + 2;
+ data = kzalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->bAddrType = MXU1_RW_DATA_ADDR_XDATA;
+ data->bDataType = MXU1_RW_DATA_BYTE;
+ data->bDataCounter = 1;
+ data->wBaseAddrHi = cpu_to_be16(addr >> 16);
+ data->wBaseAddrLo = cpu_to_be16(addr);
+ data->bData[0] = mask;
+ data->bData[1] = byte;
+
+ status = mxu1_send_ctrl_data_urb(port->serial, MXU1_WRITE_DATA, 0,
+ MXU1_RAM_PORT, data, size);
+ if (status < 0)
+ dev_err(&port->dev, "%s - failed: %d\n", __func__, status);
+
+ kfree(data);
+
+ return status;
+}
+
+static int mxu1_set_mcr(struct usb_serial_port *port, unsigned int mcr)
+{
+ int status;
+
+ status = mxu1_write_byte(port,
+ MXU1_UART_BASE_ADDR + MXU1_UART_OFFSET_MCR,
+ MXU1_MCR_RTS | MXU1_MCR_DTR | MXU1_MCR_LOOP,
+ mcr);
+ return status;
+}
+
+static void mxu1_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct mxu1_port *mxport = usb_get_serial_port_data(port);
+ struct mxu1_uart_config *config;
+ tcflag_t cflag, iflag;
+ speed_t baud;
+ int status;
+ unsigned int mcr;
+
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
+
+ if (old_termios &&
+ !tty_termios_hw_change(&tty->termios, old_termios) &&
+ tty->termios.c_iflag == old_termios->c_iflag) {
+ dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
+ return;
+ }
+
+ dev_dbg(&port->dev,
+ "%s - cflag 0x%08x, iflag 0x%08x\n", __func__, cflag, iflag);
+
+ if (old_termios) {
+ dev_dbg(&port->dev, "%s - old cflag 0x%08x, old iflag 0x%08x\n",
+ __func__,
+ old_termios->c_cflag,
+ old_termios->c_iflag);
+ }
+
+ config = kzalloc(sizeof(*config), GFP_KERNEL);
+ if (!config)
+ return;
+
+ /* these flags must be set */
+ config->wFlags |= MXU1_UART_ENABLE_MS_INTS;
+ config->wFlags |= MXU1_UART_ENABLE_AUTO_START_DMA;
+ if (mxport->send_break)
+ config->wFlags |= MXU1_UART_SEND_BREAK_SIGNAL;
+ config->bUartMode = mxport->uart_mode;
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
+ config->bDataBits = MXU1_UART_5_DATA_BITS;
+ break;
+ case CS6:
+ config->bDataBits = MXU1_UART_6_DATA_BITS;
+ break;
+ case CS7:
+ config->bDataBits = MXU1_UART_7_DATA_BITS;
+ break;
+ default:
+ case CS8:
+ config->bDataBits = MXU1_UART_8_DATA_BITS;
+ break;
+ }
+
+ if (C_PARENB(tty)) {
+ config->wFlags |= MXU1_UART_ENABLE_PARITY_CHECKING;
+ if (C_CMSPAR(tty)) {
+ if (C_PARODD(tty))
+ config->bParity = MXU1_UART_MARK_PARITY;
+ else
+ config->bParity = MXU1_UART_SPACE_PARITY;
+ } else {
+ if (C_PARODD(tty))
+ config->bParity = MXU1_UART_ODD_PARITY;
+ else
+ config->bParity = MXU1_UART_EVEN_PARITY;
+ }
+ } else {
+ config->bParity = MXU1_UART_NO_PARITY;
+ }
+
+ if (C_CSTOPB(tty))
+ config->bStopBits = MXU1_UART_2_STOP_BITS;
+ else
+ config->bStopBits = MXU1_UART_1_STOP_BITS;
+
+ if (C_CRTSCTS(tty)) {
+ /* RTS flow control must be off to drop RTS for baud rate B0 */
+ if (C_BAUD(tty) != B0)
+ config->wFlags |= MXU1_UART_ENABLE_RTS_IN;
+ config->wFlags |= MXU1_UART_ENABLE_CTS_OUT;
+ }
+
+ if (I_IXOFF(tty) || I_IXON(tty)) {
+ config->cXon = START_CHAR(tty);
+ config->cXoff = STOP_CHAR(tty);
+
+ if (I_IXOFF(tty))
+ config->wFlags |= MXU1_UART_ENABLE_X_IN;
+
+ if (I_IXON(tty))
+ config->wFlags |= MXU1_UART_ENABLE_X_OUT;
+ }
+
+ baud = tty_get_baud_rate(tty);
+ if (!baud)
+ baud = 9600;
+ config->wBaudRate = MXU1_BAUD_BASE / baud;
+
+ dev_dbg(&port->dev, "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",
+ __func__, baud, config->wBaudRate, config->wFlags,
+ config->bDataBits, config->bParity, config->bStopBits,
+ config->cXon, config->cXoff, config->bUartMode);
+
+ cpu_to_be16s(&config->wBaudRate);
+ cpu_to_be16s(&config->wFlags);
+
+ status = mxu1_send_ctrl_data_urb(port->serial, MXU1_SET_CONFIG, 0,
+ MXU1_UART1_PORT, config,
+ sizeof(*config));
+ if (status)
+ dev_err(&port->dev, "cannot set config: %d\n", status);
+
+ mutex_lock(&mxport->mutex);
+ mcr = mxport->mcr;
+
+ if (C_BAUD(tty) == B0)
+ mcr &= ~(MXU1_MCR_DTR | MXU1_MCR_RTS);
+ else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+ mcr |= MXU1_MCR_DTR | MXU1_MCR_RTS;
+
+ status = mxu1_set_mcr(port, mcr);
+ if (status)
+ dev_err(&port->dev, "cannot set modem control: %d\n", status);
+ else
+ mxport->mcr = mcr;
+
+ mutex_unlock(&mxport->mutex);
+
+ kfree(config);
+}
+
+static int mxu1_get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *ret_arg)
+{
+ struct serial_struct ret_serial;
+ unsigned cwait;
+
+ if (!ret_arg)
+ return -EFAULT;
+
+ cwait = port->port.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = jiffies_to_msecs(cwait) / 10;
+
+ memset(&ret_serial, 0, sizeof(ret_serial));
+
+ ret_serial.type = PORT_16550A;
+ ret_serial.line = port->minor;
+ ret_serial.port = 0;
+ ret_serial.xmit_fifo_size = port->bulk_out_size;
+ ret_serial.baud_base = MXU1_BAUD_BASE;
+ ret_serial.close_delay = 5*HZ;
+ ret_serial.closing_wait = cwait;
+
+ if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int mxu1_set_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *new_arg)
+{
+ struct serial_struct new_serial;
+ unsigned cwait;
+
+ if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
+ return -EFAULT;
+
+ cwait = new_serial.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
+
+ port->port.closing_wait = cwait;
+
+ return 0;
+}
+
+static int mxu1_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return mxu1_get_serial_info(port,
+ (struct serial_struct __user *)arg);
+ case TIOCSSERIAL:
+ return mxu1_set_serial_info(port,
+ (struct serial_struct __user *)arg);
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int mxu1_tiocmget(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct mxu1_port *mxport = usb_get_serial_port_data(port);
+ unsigned int result;
+ unsigned int msr;
+ unsigned int mcr;
+ unsigned long flags;
+
+ mutex_lock(&mxport->mutex);
+ spin_lock_irqsave(&mxport->spinlock, flags);
+
+ msr = mxport->msr;
+ mcr = mxport->mcr;
+
+ spin_unlock_irqrestore(&mxport->spinlock, flags);
+ mutex_unlock(&mxport->mutex);
+
+ result = ((mcr & MXU1_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((mcr & MXU1_MCR_RTS) ? TIOCM_RTS : 0) |
+ ((mcr & MXU1_MCR_LOOP) ? TIOCM_LOOP : 0) |
+ ((msr & MXU1_MSR_CTS) ? TIOCM_CTS : 0) |
+ ((msr & MXU1_MSR_CD) ? TIOCM_CAR : 0) |
+ ((msr & MXU1_MSR_RI) ? TIOCM_RI : 0) |
+ ((msr & MXU1_MSR_DSR) ? TIOCM_DSR : 0);
+
+ dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result);
+
+ return result;
+}
+
+static int mxu1_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct mxu1_port *mxport = usb_get_serial_port_data(port);
+ int err;
+ unsigned int mcr;
+
+ mutex_lock(&mxport->mutex);
+ mcr = mxport->mcr;
+
+ if (set & TIOCM_RTS)
+ mcr |= MXU1_MCR_RTS;
+ if (set & TIOCM_DTR)
+ mcr |= MXU1_MCR_DTR;
+ if (set & TIOCM_LOOP)
+ mcr |= MXU1_MCR_LOOP;
+
+ if (clear & TIOCM_RTS)
+ mcr &= ~MXU1_MCR_RTS;
+ if (clear & TIOCM_DTR)
+ mcr &= ~MXU1_MCR_DTR;
+ if (clear & TIOCM_LOOP)
+ mcr &= ~MXU1_MCR_LOOP;
+
+ err = mxu1_set_mcr(port, mcr);
+ if (!err)
+ mxport->mcr = mcr;
+
+ mutex_unlock(&mxport->mutex);
+
+ return err;
+}
+
+static void mxu1_break(struct tty_struct *tty, int break_state)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct mxu1_port *mxport = usb_get_serial_port_data(port);
+
+ if (break_state == -1)
+ mxport->send_break = true;
+ else
+ mxport->send_break = false;
+
+ mxu1_set_termios(tty, port, NULL);
+}
+
+static int mxu1_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct mxu1_port *mxport = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int status;
+ u16 open_settings;
+
+ open_settings = (MXU1_PIPE_MODE_CONTINUOUS |
+ MXU1_PIPE_TIMEOUT_ENABLE |
+ (MXU1_TRANSFER_TIMEOUT << 2));
+
+ mxport->msr = 0;
+
+ status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (status) {
+ dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+ status);
+ return status;
+ }
+
+ if (tty)
+ mxu1_set_termios(tty, port, NULL);
+
+ status = mxu1_send_ctrl_urb(serial, MXU1_OPEN_PORT,
+ open_settings, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "cannot send open command: %d\n", status);
+ goto unlink_int_urb;
+ }
+
+ status = mxu1_send_ctrl_urb(serial, MXU1_START_PORT,
+ 0, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "cannot send start command: %d\n", status);
+ goto unlink_int_urb;
+ }
+
+ status = mxu1_send_ctrl_urb(serial, MXU1_PURGE_PORT,
+ MXU1_PURGE_INPUT, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "cannot clear input buffers: %d\n",
+ status);
+
+ goto unlink_int_urb;
+ }
+
+ status = mxu1_send_ctrl_urb(serial, MXU1_PURGE_PORT,
+ MXU1_PURGE_OUTPUT, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "cannot clear output buffers: %d\n",
+ status);
+
+ goto unlink_int_urb;
+ }
+
+ /*
+ * reset the data toggle on the bulk endpoints to work around bug in
+ * host controllers where things get out of sync some times
+ */
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ if (tty)
+ mxu1_set_termios(tty, port, NULL);
+
+ status = mxu1_send_ctrl_urb(serial, MXU1_OPEN_PORT,
+ open_settings, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "cannot send open command: %d\n", status);
+ goto unlink_int_urb;
+ }
+
+ status = mxu1_send_ctrl_urb(serial, MXU1_START_PORT,
+ 0, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "cannot send start command: %d\n", status);
+ goto unlink_int_urb;
+ }
+
+ status = usb_serial_generic_open(tty, port);
+ if (status)
+ goto unlink_int_urb;
+
+ return 0;
+
+unlink_int_urb:
+ usb_kill_urb(port->interrupt_in_urb);
+
+ return status;
+}
+
+static void mxu1_close(struct usb_serial_port *port)
+{
+ int status;
+
+ usb_serial_generic_close(port);
+ usb_kill_urb(port->interrupt_in_urb);
+
+ status = mxu1_send_ctrl_urb(port->serial, MXU1_CLOSE_PORT,
+ 0, MXU1_UART1_PORT);
+ if (status) {
+ dev_err(&port->dev, "failed to send close port command: %d\n",
+ status);
+ }
+}
+
+static void mxu1_handle_new_msr(struct usb_serial_port *port, u8 msr)
+{
+ struct mxu1_port *mxport = usb_get_serial_port_data(port);
+ struct async_icount *icount;
+ unsigned long flags;
+
+ dev_dbg(&port->dev, "%s - msr 0x%02X\n", __func__, msr);
+
+ spin_lock_irqsave(&mxport->spinlock, flags);
+ mxport->msr = msr & MXU1_MSR_MASK;
+ spin_unlock_irqrestore(&mxport->spinlock, flags);
+
+ if (msr & MXU1_MSR_DELTA_MASK) {
+ icount = &port->icount;
+ if (msr & MXU1_MSR_DELTA_CTS)
+ icount->cts++;
+ if (msr & MXU1_MSR_DELTA_DSR)
+ icount->dsr++;
+ if (msr & MXU1_MSR_DELTA_CD)
+ icount->dcd++;
+ if (msr & MXU1_MSR_DELTA_RI)
+ icount->rng++;
+
+ wake_up_interruptible(&port->port.delta_msr_wait);
+ }
+}
+
+static void mxu1_interrupt_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ int length = urb->actual_length;
+ int function;
+ int status;
+ u8 msr;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ dev_dbg(&port->dev, "%s - urb shutting down: %d\n",
+ __func__, urb->status);
+ return;
+ default:
+ dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
+ __func__, urb->status);
+ goto exit;
+ }
+
+ if (length != 2) {
+ dev_dbg(&port->dev, "%s - bad packet size: %d\n",
+ __func__, length);
+ goto exit;
+ }
+
+ if (data[0] == MXU1_CODE_HARDWARE_ERROR) {
+ dev_err(&port->dev, "hardware error: %d\n", data[1]);
+ goto exit;
+ }
+
+ function = mxu1_get_func_from_code(data[0]);
+
+ dev_dbg(&port->dev, "%s - function %d, data 0x%02X\n",
+ __func__, function, data[1]);
+
+ switch (function) {
+ case MXU1_CODE_DATA_ERROR:
+ dev_dbg(&port->dev, "%s - DATA ERROR, data 0x%02X\n",
+ __func__, data[1]);
+ break;
+
+ case MXU1_CODE_MODEM_STATUS:
+ msr = data[1];
+ mxu1_handle_new_msr(port, msr);
+ break;
+
+ default:
+ dev_err(&port->dev, "unknown interrupt code: 0x%02X\n",
+ data[1]);
+ break;
+ }
+
+exit:
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&port->dev, "resubmit interrupt urb failed: %d\n",
+ status);
+ }
+}
+
+static struct usb_serial_driver mxu11x0_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mxu11x0",
+ },
+ .description = "MOXA UPort 11x0",
+ .id_table = mxu1_idtable,
+ .num_ports = 1,
+ .port_probe = mxu1_port_probe,
+ .attach = mxu1_startup,
+ .open = mxu1_open,
+ .close = mxu1_close,
+ .ioctl = mxu1_ioctl,
+ .set_termios = mxu1_set_termios,
+ .tiocmget = mxu1_tiocmget,
+ .tiocmset = mxu1_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
+ .break_ctl = mxu1_break,
+ .read_int_callback = mxu1_interrupt_callback,
+};
+
+static struct usb_serial_driver *const serial_drivers[] = {
+ &mxu11x0_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, mxu1_idtable);
+
+MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
+MODULE_DESCRIPTION("MOXA UPort 11x0 USB to Serial Hub Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("moxa/moxa-1110.fw");
+MODULE_FIRMWARE("moxa/moxa-1130.fw");
+MODULE_FIRMWARE("moxa/moxa-1131.fw");
+MODULE_FIRMWARE("moxa/moxa-1150.fw");
+MODULE_FIRMWARE("moxa/moxa-1151.fw");
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 5c66d3f7a6d0..9ff9404f99d7 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -49,18 +49,18 @@ struct uas_dev_info {
};
enum {
- SUBMIT_STATUS_URB = (1 << 1),
- ALLOC_DATA_IN_URB = (1 << 2),
- SUBMIT_DATA_IN_URB = (1 << 3),
- ALLOC_DATA_OUT_URB = (1 << 4),
- SUBMIT_DATA_OUT_URB = (1 << 5),
- ALLOC_CMD_URB = (1 << 6),
- SUBMIT_CMD_URB = (1 << 7),
- COMMAND_INFLIGHT = (1 << 8),
- DATA_IN_URB_INFLIGHT = (1 << 9),
- DATA_OUT_URB_INFLIGHT = (1 << 10),
- COMMAND_ABORTED = (1 << 11),
- IS_IN_WORK_LIST = (1 << 12),
+ SUBMIT_STATUS_URB = BIT(1),
+ ALLOC_DATA_IN_URB = BIT(2),
+ SUBMIT_DATA_IN_URB = BIT(3),
+ ALLOC_DATA_OUT_URB = BIT(4),
+ SUBMIT_DATA_OUT_URB = BIT(5),
+ ALLOC_CMD_URB = BIT(6),
+ SUBMIT_CMD_URB = BIT(7),
+ COMMAND_INFLIGHT = BIT(8),
+ DATA_IN_URB_INFLIGHT = BIT(9),
+ DATA_OUT_URB_INFLIGHT = BIT(10),
+ COMMAND_ABORTED = BIT(11),
+ IS_IN_WORK_LIST = BIT(12),
};
/* Overrides scsi_pointer */
@@ -74,7 +74,7 @@ struct uas_cmd_info {
/* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
- struct uas_dev_info *devinfo, gfp_t gfp);
+ struct uas_dev_info *devinfo);
static void uas_do_work(struct work_struct *work);
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
static void uas_free_streams(struct uas_dev_info *devinfo);
@@ -105,7 +105,7 @@ static void uas_do_work(struct work_struct *work)
if (!(cmdinfo->state & IS_IN_WORK_LIST))
continue;
- err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
if (!err)
cmdinfo->state &= ~IS_IN_WORK_LIST;
else
@@ -240,7 +240,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
int err;
cmdinfo->state |= direction | SUBMIT_STATUS_URB;
- err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
if (err) {
uas_add_work(cmdinfo);
}
@@ -512,7 +512,7 @@ static struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd, gfp_t gfp)
}
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
- struct uas_dev_info *devinfo, gfp_t gfp)
+ struct uas_dev_info *devinfo)
{
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct urb *urb;
@@ -520,14 +520,14 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
lockdep_assert_held(&devinfo->lock);
if (cmdinfo->state & SUBMIT_STATUS_URB) {
- urb = uas_submit_sense_urb(cmnd, gfp);
+ urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC);
if (!urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~SUBMIT_STATUS_URB;
}
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
- cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
+ cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC,
cmnd, DMA_FROM_DEVICE);
if (!cmdinfo->data_in_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
@@ -536,7 +536,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
- err = usb_submit_urb(cmdinfo->data_in_urb, gfp);
+ err = usb_submit_urb(cmdinfo->data_in_urb, GFP_ATOMIC);
if (err) {
usb_unanchor_urb(cmdinfo->data_in_urb);
uas_log_cmd_state(cmnd, "data in submit err", err);
@@ -547,7 +547,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
}
if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
- cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
+ cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC,
cmnd, DMA_TO_DEVICE);
if (!cmdinfo->data_out_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
@@ -556,7 +556,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
- err = usb_submit_urb(cmdinfo->data_out_urb, gfp);
+ err = usb_submit_urb(cmdinfo->data_out_urb, GFP_ATOMIC);
if (err) {
usb_unanchor_urb(cmdinfo->data_out_urb);
uas_log_cmd_state(cmnd, "data out submit err", err);
@@ -567,7 +567,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
}
if (cmdinfo->state & ALLOC_CMD_URB) {
- cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
+ cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, GFP_ATOMIC, cmnd);
if (!cmdinfo->cmd_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_CMD_URB;
@@ -575,7 +575,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & SUBMIT_CMD_URB) {
usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
- err = usb_submit_urb(cmdinfo->cmd_urb, gfp);
+ err = usb_submit_urb(cmdinfo->cmd_urb, GFP_ATOMIC);
if (err) {
usb_unanchor_urb(cmdinfo->cmd_urb);
uas_log_cmd_state(cmnd, "cmd submit err", err);
@@ -653,7 +653,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
if (!devinfo->use_streams)
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
- err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
+ err = uas_submit_urbs(cmnd, devinfo);
if (err) {
/* If we did nothing, give up now */
if (cmdinfo->state & SUBMIT_STATUS_URB) {
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c
index bdcb13cc1d54..01c20a260a8b 100644
--- a/drivers/uwb/uwbd.c
+++ b/drivers/uwb/uwbd.c
@@ -279,7 +279,6 @@ static int uwbd(void *param)
HZ);
if (should_stop)
break;
- try_to_freeze();
spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
if (!list_empty(&rc->uwbd.event_list)) {
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index 850d86ca685b..da6e2ce77495 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -31,6 +31,21 @@ menuconfig VFIO
If you don't know what to do here, say N.
+menuconfig VFIO_NOIOMMU
+ bool "VFIO No-IOMMU support"
+ depends on VFIO
+ help
+ VFIO is built on the ability to isolate devices using the IOMMU.
+ Only with an IOMMU can userspace access to DMA capable devices be
+ considered secure. VFIO No-IOMMU mode enables IOMMU groups for
+ devices without IOMMU backing for the purpose of re-using the VFIO
+ infrastructure in a non-secure mode. Use of this mode will result
+ in an unsupportable kernel and will therefore taint the kernel.
+ Device assignment to virtual machines is also not possible with
+ this mode since there is no IOMMU to provide DMA translation.
+
+ If you don't know what to do here, say N.
+
source "drivers/vfio/pci/Kconfig"
source "drivers/vfio/platform/Kconfig"
source "virt/lib/Kconfig"
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 56bf6dbb93db..2760a7ba3f30 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -940,13 +940,13 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
return -EINVAL;
- group = iommu_group_get(&pdev->dev);
+ group = vfio_iommu_group_get(&pdev->dev);
if (!group)
return -EINVAL;
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
if (!vdev) {
- iommu_group_put(group);
+ vfio_iommu_group_put(group, &pdev->dev);
return -ENOMEM;
}
@@ -957,7 +957,7 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
if (ret) {
- iommu_group_put(group);
+ vfio_iommu_group_put(group, &pdev->dev);
kfree(vdev);
return ret;
}
@@ -993,7 +993,7 @@ static void vfio_pci_remove(struct pci_dev *pdev)
if (!vdev)
return;
- iommu_group_put(pdev->dev.iommu_group);
+ vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev);
kfree(vdev);
if (vfio_pci_is_vga(pdev)) {
diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
index da5356f48d0b..d4030d0c38e9 100644
--- a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
+++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
@@ -110,7 +110,7 @@ int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
usleep_range(10, 15);
count = 2000;
- while (count-- && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1))
+ while (--count && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1))
usleep_range(500, 600);
if (!count)
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 6070b793cbcb..82f25cc1c460 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -62,6 +62,7 @@ struct vfio_container {
struct rw_semaphore group_lock;
struct vfio_iommu_driver *iommu_driver;
void *iommu_data;
+ bool noiommu;
};
struct vfio_unbound_dev {
@@ -84,6 +85,7 @@ struct vfio_group {
struct list_head unbound_list;
struct mutex unbound_lock;
atomic_t opened;
+ bool noiommu;
};
struct vfio_device {
@@ -95,6 +97,128 @@ struct vfio_device {
void *device_data;
};
+#ifdef CONFIG_VFIO_NOIOMMU
+static bool noiommu __read_mostly;
+module_param_named(enable_unsafe_noiommu_mode,
+ noiommu, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. This mode provides no device isolation, no DMA translation, no host kernel protection, cannot be used for device assignment to virtual machines, requires RAWIO permissions, and will taint the kernel. If you do not know what this is for, step away. (default: false)");
+#endif
+
+/*
+ * vfio_iommu_group_{get,put} are only intended for VFIO bus driver probe
+ * and remove functions, any use cases other than acquiring the first
+ * reference for the purpose of calling vfio_add_group_dev() or removing
+ * that symmetric reference after vfio_del_group_dev() should use the raw
+ * iommu_group_{get,put} functions. In particular, vfio_iommu_group_put()
+ * removes the device from the dummy group and cannot be nested.
+ */
+struct iommu_group *vfio_iommu_group_get(struct device *dev)
+{
+ struct iommu_group *group;
+ int __maybe_unused ret;
+
+ group = iommu_group_get(dev);
+
+#ifdef CONFIG_VFIO_NOIOMMU
+ /*
+ * With noiommu enabled, an IOMMU group will be created for a device
+ * that doesn't already have one and doesn't have an iommu_ops on their
+ * bus. We use iommu_present() again in the main code to detect these
+ * fake groups.
+ */
+ if (group || !noiommu || iommu_present(dev->bus))
+ return group;
+
+ group = iommu_group_alloc();
+ if (IS_ERR(group))
+ return NULL;
+
+ iommu_group_set_name(group, "vfio-noiommu");
+ ret = iommu_group_add_device(group, dev);
+ iommu_group_put(group);
+ if (ret)
+ return NULL;
+
+ /*
+ * Where to taint? At this point we've added an IOMMU group for a
+ * device that is not backed by iommu_ops, therefore any iommu_
+ * callback using iommu_ops can legitimately Oops. So, while we may
+ * be about to give a DMA capable device to a user without IOMMU
+ * protection, which is clearly taint-worthy, let's go ahead and do
+ * it here.
+ */
+ add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+ dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
+#endif
+
+ return group;
+}
+EXPORT_SYMBOL_GPL(vfio_iommu_group_get);
+
+void vfio_iommu_group_put(struct iommu_group *group, struct device *dev)
+{
+#ifdef CONFIG_VFIO_NOIOMMU
+ if (!iommu_present(dev->bus))
+ iommu_group_remove_device(dev);
+#endif
+
+ iommu_group_put(group);
+}
+EXPORT_SYMBOL_GPL(vfio_iommu_group_put);
+
+#ifdef CONFIG_VFIO_NOIOMMU
+static void *vfio_noiommu_open(unsigned long arg)
+{
+ if (arg != VFIO_NOIOMMU_IOMMU)
+ return ERR_PTR(-EINVAL);
+ if (!capable(CAP_SYS_RAWIO))
+ return ERR_PTR(-EPERM);
+
+ return NULL;
+}
+
+static void vfio_noiommu_release(void *iommu_data)
+{
+}
+
+static long vfio_noiommu_ioctl(void *iommu_data,
+ unsigned int cmd, unsigned long arg)
+{
+ if (cmd == VFIO_CHECK_EXTENSION)
+ return noiommu && (arg == VFIO_NOIOMMU_IOMMU) ? 1 : 0;
+
+ return -ENOTTY;
+}
+
+static int vfio_iommu_present(struct device *dev, void *unused)
+{
+ return iommu_present(dev->bus) ? 1 : 0;
+}
+
+static int vfio_noiommu_attach_group(void *iommu_data,
+ struct iommu_group *iommu_group)
+{
+ return iommu_group_for_each_dev(iommu_group, NULL,
+ vfio_iommu_present) ? -EINVAL : 0;
+}
+
+static void vfio_noiommu_detach_group(void *iommu_data,
+ struct iommu_group *iommu_group)
+{
+}
+
+static const struct vfio_iommu_driver_ops vfio_noiommu_ops = {
+ .name = "vfio-noiommu",
+ .owner = THIS_MODULE,
+ .open = vfio_noiommu_open,
+ .release = vfio_noiommu_release,
+ .ioctl = vfio_noiommu_ioctl,
+ .attach_group = vfio_noiommu_attach_group,
+ .detach_group = vfio_noiommu_detach_group,
+};
+#endif
+
+
/**
* IOMMU driver registration
*/
@@ -199,7 +323,8 @@ static void vfio_group_unlock_and_free(struct vfio_group *group)
/**
* Group objects - create, release, get, put, search
*/
-static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
+static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
+ bool iommu_present)
{
struct vfio_group *group, *tmp;
struct device *dev;
@@ -217,6 +342,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
atomic_set(&group->container_users, 0);
atomic_set(&group->opened, 0);
group->iommu_group = iommu_group;
+ group->noiommu = !iommu_present;
group->nb.notifier_call = vfio_iommu_group_notifier;
@@ -252,7 +378,8 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
dev = device_create(vfio.class, NULL,
MKDEV(MAJOR(vfio.group_devt), minor),
- group, "%d", iommu_group_id(iommu_group));
+ group, "%s%d", group->noiommu ? "noiommu-" : "",
+ iommu_group_id(iommu_group));
if (IS_ERR(dev)) {
vfio_free_group_minor(minor);
vfio_group_unlock_and_free(group);
@@ -640,7 +767,7 @@ int vfio_add_group_dev(struct device *dev,
group = vfio_group_get_from_iommu(iommu_group);
if (!group) {
- group = vfio_create_group(iommu_group);
+ group = vfio_create_group(iommu_group, iommu_present(dev->bus));
if (IS_ERR(group)) {
iommu_group_put(iommu_group);
return PTR_ERR(group);
@@ -854,6 +981,14 @@ static long vfio_ioctl_check_extension(struct vfio_container *container,
mutex_lock(&vfio.iommu_drivers_lock);
list_for_each_entry(driver, &vfio.iommu_drivers_list,
vfio_next) {
+
+#ifdef CONFIG_VFIO_NOIOMMU
+ if (!list_empty(&container->group_list) &&
+ (container->noiommu !=
+ (driver->ops == &vfio_noiommu_ops)))
+ continue;
+#endif
+
if (!try_module_get(driver->ops->owner))
continue;
@@ -925,6 +1060,15 @@ static long vfio_ioctl_set_iommu(struct vfio_container *container,
list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) {
void *data;
+#ifdef CONFIG_VFIO_NOIOMMU
+ /*
+ * Only noiommu containers can use vfio-noiommu and noiommu
+ * containers can only use vfio-noiommu.
+ */
+ if (container->noiommu != (driver->ops == &vfio_noiommu_ops))
+ continue;
+#endif
+
if (!try_module_get(driver->ops->owner))
continue;
@@ -1187,6 +1331,9 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd)
if (atomic_read(&group->container_users))
return -EINVAL;
+ if (group->noiommu && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
f = fdget(container_fd);
if (!f.file)
return -EBADF;
@@ -1202,6 +1349,13 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd)
down_write(&container->group_lock);
+ /* Real groups and fake groups cannot mix */
+ if (!list_empty(&container->group_list) &&
+ container->noiommu != group->noiommu) {
+ ret = -EPERM;
+ goto unlock_out;
+ }
+
driver = container->iommu_driver;
if (driver) {
ret = driver->ops->attach_group(container->iommu_data,
@@ -1211,6 +1365,7 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd)
}
group->container = container;
+ container->noiommu = group->noiommu;
list_add(&group->container_next, &container->group_list);
/* Get a reference on the container and mark a user within the group */
@@ -1241,6 +1396,9 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
!group->container->iommu_driver || !vfio_group_viable(group))
return -EINVAL;
+ if (group->noiommu && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
device = vfio_device_get_from_name(group, buf);
if (!device)
return -ENODEV;
@@ -1283,6 +1441,10 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
fd_install(ret, filep);
+ if (group->noiommu)
+ dev_warn(device->dev, "vfio-noiommu device opened by user "
+ "(%s:%d)\n", current->comm, task_pid_nr(current));
+
return ret;
}
@@ -1371,6 +1533,11 @@ static int vfio_group_fops_open(struct inode *inode, struct file *filep)
if (!group)
return -ENODEV;
+ if (group->noiommu && !capable(CAP_SYS_RAWIO)) {
+ vfio_group_put(group);
+ return -EPERM;
+ }
+
/* Do we need multiple instances of the group open? Seems not. */
opened = atomic_cmpxchg(&group->opened, 0, 1);
if (opened) {
@@ -1533,6 +1700,11 @@ struct vfio_group *vfio_group_get_external_user(struct file *filep)
if (!atomic_inc_not_zero(&group->container_users))
return ERR_PTR(-EINVAL);
+ if (group->noiommu) {
+ atomic_dec(&group->container_users);
+ return ERR_PTR(-EPERM);
+ }
+
if (!group->container->iommu_driver ||
!vfio_group_viable(group)) {
atomic_dec(&group->container_users);
@@ -1625,6 +1797,9 @@ static int __init vfio_init(void)
request_module_nowait("vfio_iommu_type1");
request_module_nowait("vfio_iommu_spapr_tce");
+#ifdef CONFIG_VFIO_NOIOMMU
+ vfio_register_iommu_driver(&vfio_noiommu_ops);
+#endif
return 0;
err_cdev_add:
@@ -1641,6 +1816,9 @@ static void __exit vfio_cleanup(void)
{
WARN_ON(!list_empty(&vfio.group_list));
+#ifdef CONFIG_VFIO_NOIOMMU
+ vfio_unregister_iommu_driver(&vfio_noiommu_ops);
+#endif
idr_destroy(&vfio.group_idr);
cdev_del(&vfio.group_cdev);
unregister_chrdev_region(vfio.group_devt, MINORMASK);
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 59d47cb638d5..6f1ea3dddbad 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -995,7 +995,7 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
if (info.argsz < minsz)
return -EINVAL;
- info.flags = 0;
+ info.flags = VFIO_IOMMU_INFO_PGSIZES;
info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 98ffe71e8af2..510e559c060e 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -566,11 +566,13 @@ static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev,
mutex_lock(&data->lock);
error = adp8860_read(data->client, ADP8860_PH1LEVL, &reg_val);
- ret_val = reg_val;
- error |= adp8860_read(data->client, ADP8860_PH1LEVH, &reg_val);
+ if (!error) {
+ ret_val = reg_val;
+ error = adp8860_read(data->client, ADP8860_PH1LEVH, &reg_val);
+ }
mutex_unlock(&data->lock);
- if (error < 0)
+ if (error)
return error;
/* Return 13-bit conversion value for the first light sensor */
@@ -621,10 +623,12 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
/* Set user supplied ambient light zone */
mutex_lock(&data->lock);
- adp8860_read(data->client, ADP8860_CFGR, &reg_val);
- reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
- reg_val |= (val - 1) << CFGR_BLV_SHIFT;
- adp8860_write(data->client, ADP8860_CFGR, reg_val);
+ ret = adp8860_read(data->client, ADP8860_CFGR, &reg_val);
+ if (!ret) {
+ reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
+ reg_val |= (val - 1) << CFGR_BLV_SHIFT;
+ adp8860_write(data->client, ADP8860_CFGR, reg_val);
+ }
mutex_unlock(&data->lock);
}
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 9d738352d7d4..21acac90fd77 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -807,10 +807,12 @@ static ssize_t adp8870_bl_ambient_light_zone_store(struct device *dev,
/* Set user supplied ambient light zone */
mutex_lock(&data->lock);
- adp8870_read(data->client, ADP8870_CFGR, &reg_val);
- reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
- reg_val |= (val - 1) << CFGR_BLV_SHIFT;
- adp8870_write(data->client, ADP8870_CFGR, reg_val);
+ ret = adp8870_read(data->client, ADP8870_CFGR, &reg_val);
+ if (!ret) {
+ reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
+ reg_val |= (val - 1) << CFGR_BLV_SHIFT;
+ adp8870_write(data->client, ADP8870_CFGR, reg_val);
+ }
mutex_unlock(&data->lock);
}
diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c
index 5fbbc2ebdf93..18134416b154 100644
--- a/drivers/video/backlight/gpio_backlight.c
+++ b/drivers/video/backlight/gpio_backlight.c
@@ -89,6 +89,7 @@ static int gpio_backlight_probe(struct platform_device *pdev)
struct backlight_device *bl;
struct gpio_backlight *gbl;
struct device_node *np = pdev->dev.of_node;
+ unsigned long flags = GPIOF_DIR_OUT;
int ret;
if (!pdata && !np) {
@@ -114,9 +115,12 @@ static int gpio_backlight_probe(struct platform_device *pdev)
gbl->def_value = pdata->def_value;
}
- ret = devm_gpio_request_one(gbl->dev, gbl->gpio, GPIOF_DIR_OUT |
- (gbl->active ? GPIOF_INIT_LOW
- : GPIOF_INIT_HIGH),
+ if (gbl->active)
+ flags |= gbl->def_value ? GPIOF_INIT_HIGH : GPIOF_INIT_LOW;
+ else
+ flags |= gbl->def_value ? GPIOF_INIT_LOW : GPIOF_INIT_HIGH;
+
+ ret = devm_gpio_request_one(gbl->dev, gbl->gpio, flags,
pdata ? pdata->name : "backlight");
if (ret < 0) {
dev_err(&pdev->dev, "unable to request GPIO\n");
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index ae3c6b6fd5db..64f9e1b8655f 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -198,7 +198,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct platform_pwm_backlight_data defdata;
struct backlight_properties props;
struct backlight_device *bl;
+ struct device_node *node = pdev->dev.of_node;
struct pwm_bl_data *pb;
+ int initial_blank = FB_BLANK_UNBLANK;
int ret;
if (!data) {
@@ -242,7 +244,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enabled = false;
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
- GPIOD_OUT_HIGH);
+ GPIOD_ASIS);
if (IS_ERR(pb->enable_gpio)) {
ret = PTR_ERR(pb->enable_gpio);
goto err_alloc;
@@ -264,15 +266,32 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enable_gpio = gpio_to_desc(data->enable_gpio);
}
+ if (pb->enable_gpio) {
+ /*
+ * If the driver is probed from the device tree and there is a
+ * phandle link pointing to the backlight node, it is safe to
+ * assume that another driver will enable the backlight at the
+ * appropriate time. Therefore, if it is disabled, keep it so.
+ */
+ if (node && node->phandle &&
+ gpiod_get_direction(pb->enable_gpio) == GPIOF_DIR_OUT &&
+ gpiod_get_value(pb->enable_gpio) == 0)
+ initial_blank = FB_BLANK_POWERDOWN;
+ else
+ gpiod_direction_output(pb->enable_gpio, 1);
+ }
+
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
if (IS_ERR(pb->power_supply)) {
ret = PTR_ERR(pb->power_supply);
goto err_alloc;
}
+ if (node && node->phandle && !regulator_is_enabled(pb->power_supply))
+ initial_blank = FB_BLANK_POWERDOWN;
+
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
- if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER
- && !pdev->dev.of_node) {
+ if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER && !node) {
dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
pb->legacy = true;
pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
@@ -309,6 +328,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
+ if (pb->legacy)
+ pwm_free(pb->pwm);
goto err_alloc;
}
@@ -320,6 +341,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
}
bl->props.brightness = data->dft_brightness;
+ bl->props.power = initial_blank;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c
index 61d72bffd402..fd524ad860a5 100644
--- a/drivers/video/backlight/tps65217_bl.c
+++ b/drivers/video/backlight/tps65217_bl.c
@@ -320,10 +320,19 @@ static int tps65217_bl_probe(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id tps65217_bl_of_match[] = {
+ { .compatible = "ti,tps65217-bl", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, tps65217_bl_of_match);
+#endif
+
static struct platform_driver tps65217_bl_driver = {
.probe = tps65217_bl_probe,
.driver = {
.name = "tps65217-bl",
+ .of_match_table = of_match_ptr(tps65217_bl_of_match),
},
};
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index e6d16d65e4e6..8ea45a5cd806 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -5,6 +5,7 @@
menuconfig FB
tristate "Support for frame buffer devices"
select FB_CMDLINE
+ select FB_NOTIFY
---help---
The frame buffer device provides an abstraction for the graphics
hardware. It represents the frame buffer of some video hardware and
@@ -56,6 +57,9 @@ config FIRMWARE_EDID
config FB_CMDLINE
bool
+config FB_NOTIFY
+ bool
+
config FB_DDC
tristate
depends on FB
@@ -1506,6 +1510,7 @@ config FB_SIS
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_BOOT_VESA_SUPPORT if FB_SIS = y
+ select FB_SIS_300 if !FB_SIS_315
help
This is the frame buffer device driver for the SiS 300, 315, 330
and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets.
@@ -1880,6 +1885,8 @@ config FB_PXA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEOMODE_HELPERS if OF
+ select FB_MODE_HELPERS if OF
---help---
Frame buffer driver for the built-in LCD controller in the Intel
PXA2x0 processor.
@@ -1990,16 +1997,6 @@ config FB_SH_MOBILE_LCDC
---help---
Frame buffer driver for the on-chip SH-Mobile LCD controller.
-config FB_SH_MOBILE_HDMI
- tristate "SuperH Mobile HDMI controller support"
- depends on FB_SH_MOBILE_LCDC
- select FB_MODE_HELPERS
- select SOUND
- select SND
- select SND_SOC
- ---help---
- Driver for the on-chip SH-Mobile HDMI controller.
-
config FB_TMIO
tristate "Toshiba Mobile IO FrameBuffer support"
depends on FB && (MFD_TMIO || COMPILE_TEST)
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 50ed1b4fc2bf..65fb15075c8f 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -118,7 +118,6 @@ obj-$(CONFIG_FB_UDL) += udlfb.o
obj-$(CONFIG_FB_SMSCUFX) += smscufx.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
-obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
diff --git a/drivers/video/fbdev/auo_k190x.c b/drivers/video/fbdev/auo_k190x.c
index 8d2499d1cafb..9580374667ba 100644
--- a/drivers/video/fbdev/auo_k190x.c
+++ b/drivers/video/fbdev/auo_k190x.c
@@ -773,9 +773,7 @@ static void auok190x_recover(struct auok190xfb_par *par)
/*
* Power-management
*/
-
-#ifdef CONFIG_PM
-static int auok190x_runtime_suspend(struct device *dev)
+static int __maybe_unused auok190x_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct fb_info *info = platform_get_drvdata(pdev);
@@ -822,7 +820,7 @@ finish:
return 0;
}
-static int auok190x_runtime_resume(struct device *dev)
+static int __maybe_unused auok190x_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct fb_info *info = platform_get_drvdata(pdev);
@@ -856,7 +854,7 @@ static int auok190x_runtime_resume(struct device *dev)
return 0;
}
-static int auok190x_suspend(struct device *dev)
+static int __maybe_unused auok190x_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct fb_info *info = platform_get_drvdata(pdev);
@@ -896,7 +894,7 @@ static int auok190x_suspend(struct device *dev)
return 0;
}
-static int auok190x_resume(struct device *dev)
+static int __maybe_unused auok190x_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct fb_info *info = platform_get_drvdata(pdev);
@@ -933,7 +931,6 @@ static int auok190x_resume(struct device *dev)
return 0;
}
-#endif
const struct dev_pm_ops auok190x_pm = {
SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
index 23d86a8b7d7b..9e3ddf225393 100644
--- a/drivers/video/fbdev/core/Makefile
+++ b/drivers/video/fbdev/core/Makefile
@@ -1,5 +1,5 @@
-obj-y += fb_notify.o
obj-$(CONFIG_FB_CMDLINE) += fb_cmdline.o
+obj-$(CONFIG_FB_NOTIFY) += fb_notify.o
obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 0705d8883ede..4e73b6f6b1c0 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1608,6 +1608,11 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
return 0;
}
+static bool lockless_register_fb;
+module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
+MODULE_PARM_DESC(lockless_register_fb,
+ "Lockless framebuffer registration for debugging [default=off]");
+
static int do_register_framebuffer(struct fb_info *fb_info)
{
int i, ret;
@@ -1675,15 +1680,18 @@ static int do_register_framebuffer(struct fb_info *fb_info)
registered_fb[i] = fb_info;
event.info = fb_info;
- console_lock();
+ if (!lockless_register_fb)
+ console_lock();
if (!lock_fb_info(fb_info)) {
- console_unlock();
+ if (!lockless_register_fb)
+ console_unlock();
return -ENODEV;
}
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
unlock_fb_info(fb_info);
- console_unlock();
+ if (!lockless_register_fb)
+ console_unlock();
return 0;
}
diff --git a/drivers/video/fbdev/geode/display_gx1.c b/drivers/video/fbdev/geode/display_gx1.c
index 926d53eeb549..b383eb9882bf 100644
--- a/drivers/video/fbdev/geode/display_gx1.c
+++ b/drivers/video/fbdev/geode/display_gx1.c
@@ -208,7 +208,7 @@ static void gx1_set_hw_palette_reg(struct fb_info *info, unsigned regno,
writel(val, par->dc_regs + DC_PAL_DATA);
}
-struct geode_dc_ops gx1_dc_ops = {
+const struct geode_dc_ops gx1_dc_ops = {
.set_mode = gx1_set_mode,
.set_palette_reg = gx1_set_hw_palette_reg,
};
diff --git a/drivers/video/fbdev/geode/display_gx1.h b/drivers/video/fbdev/geode/display_gx1.h
index 671c05558c79..e1cc41b343ca 100644
--- a/drivers/video/fbdev/geode/display_gx1.h
+++ b/drivers/video/fbdev/geode/display_gx1.h
@@ -18,7 +18,7 @@
unsigned gx1_gx_base(void);
int gx1_frame_buffer_size(void);
-extern struct geode_dc_ops gx1_dc_ops;
+extern const struct geode_dc_ops gx1_dc_ops;
/* GX1 configuration I/O registers */
diff --git a/drivers/video/fbdev/geode/geodefb.h b/drivers/video/fbdev/geode/geodefb.h
index ae04820e0c57..e2e07934868f 100644
--- a/drivers/video/fbdev/geode/geodefb.h
+++ b/drivers/video/fbdev/geode/geodefb.h
@@ -31,8 +31,8 @@ struct geodefb_par {
int panel_y;
void __iomem *dc_regs;
void __iomem *vid_regs;
- struct geode_dc_ops *dc_ops;
- struct geode_vid_ops *vid_ops;
+ const struct geode_dc_ops *dc_ops;
+ const struct geode_vid_ops *vid_ops;
};
#endif /* !__GEODEFB_H__ */
diff --git a/drivers/video/fbdev/geode/video_cs5530.c b/drivers/video/fbdev/geode/video_cs5530.c
index 649c3943d431..880613200ecf 100644
--- a/drivers/video/fbdev/geode/video_cs5530.c
+++ b/drivers/video/fbdev/geode/video_cs5530.c
@@ -186,7 +186,7 @@ static int cs5530_blank_display(struct fb_info *info, int blank_mode)
return 0;
}
-struct geode_vid_ops cs5530_vid_ops = {
+const struct geode_vid_ops cs5530_vid_ops = {
.set_dclk = cs5530_set_dclk_frequency,
.configure_display = cs5530_configure_display,
.blank_display = cs5530_blank_display,
diff --git a/drivers/video/fbdev/geode/video_cs5530.h b/drivers/video/fbdev/geode/video_cs5530.h
index 56cecca7f1ce..c843348bfa20 100644
--- a/drivers/video/fbdev/geode/video_cs5530.h
+++ b/drivers/video/fbdev/geode/video_cs5530.h
@@ -15,7 +15,7 @@
#ifndef __VIDEO_CS5530_H__
#define __VIDEO_CS5530_H__
-extern struct geode_vid_ops cs5530_vid_ops;
+extern const struct geode_vid_ops cs5530_vid_ops;
/* CS5530 Video device registers */
diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c
index 452e1163ad02..cf5ccd0f2252 100644
--- a/drivers/video/fbdev/i740fb.c
+++ b/drivers/video/fbdev/i740fb.c
@@ -346,11 +346,10 @@ static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX);
u32 err_best = 512 * I740_FFIX;
u32 f_err, f_vco;
- int m_best = 0, n_best = 0, p_best = 0, d_best = 0;
+ int m_best = 0, n_best = 0, p_best = 0;
int m, n;
p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX)));
- d_best = 0;
f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX;
freq = freq / I740_RFREQ_FIX;
@@ -363,7 +362,7 @@ static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
m = 3;
{
- u32 f_out = (((m * I740_REF_FREQ * (4 << 2 * d_best))
+ u32 f_out = (((m * I740_REF_FREQ * 4)
/ n) + ((1 << p_best) / 2)) / (1 << p_best);
f_err = (freq - f_out);
@@ -386,8 +385,7 @@ static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
par->video_clk2_n = (n_best - 2) & 0xFF;
par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS)
| (((m_best - 2) >> 8) & VCO_M_MSBS));
- par->video_clk2_div_sel =
- ((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1);
+ par->video_clk2_div_sel = ((p_best << 4) | REF_DIV_1);
}
static int i740fb_decode_var(const struct fb_var_screeninfo *var,
diff --git a/drivers/video/fbdev/omap2/Kconfig b/drivers/video/fbdev/omap2/Kconfig
index c22955d2de9a..0921c4de8407 100644
--- a/drivers/video/fbdev/omap2/Kconfig
+++ b/drivers/video/fbdev/omap2/Kconfig
@@ -1,10 +1,5 @@
-config OMAP2_VRFB
- bool
-
if ARCH_OMAP2PLUS
-source "drivers/video/fbdev/omap2/dss/Kconfig"
source "drivers/video/fbdev/omap2/omapfb/Kconfig"
-source "drivers/video/fbdev/omap2/displays-new/Kconfig"
endif
diff --git a/drivers/video/fbdev/omap2/Makefile b/drivers/video/fbdev/omap2/Makefile
index f8745ec369cc..71ab5ac91106 100644
--- a/drivers/video/fbdev/omap2/Makefile
+++ b/drivers/video/fbdev/omap2/Makefile
@@ -1,5 +1 @@
-obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
-
-obj-y += dss/
-obj-y += displays-new/
-obj-$(CONFIG_FB_OMAP2) += omapfb/
+obj-y += omapfb/
diff --git a/drivers/video/fbdev/omap2/omapfb/Kconfig b/drivers/video/fbdev/omap2/omapfb/Kconfig
index 4cb12ce68855..e6226aeed17e 100644
--- a/drivers/video/fbdev/omap2/omapfb/Kconfig
+++ b/drivers/video/fbdev/omap2/omapfb/Kconfig
@@ -1,7 +1,12 @@
+config OMAP2_VRFB
+ bool
+
menuconfig FB_OMAP2
tristate "OMAP2+ frame buffer support"
- depends on FB && OMAP2_DSS && !DRM_OMAP
+ depends on FB
+ depends on DRM_OMAP = n
+ select FB_OMAP2_DSS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -9,6 +14,8 @@ menuconfig FB_OMAP2
help
Frame buffer driver for OMAP2+ based boards.
+if FB_OMAP2
+
config FB_OMAP2_DEBUG_SUPPORT
bool "Debug support for OMAP2+ FB"
default y
@@ -25,3 +32,8 @@ config FB_OMAP2_NUM_FBS
help
Select the number of framebuffers created. OMAP2/3 has 3 overlays
so normally this would be 3.
+
+source "drivers/video/fbdev/omap2/omapfb/dss/Kconfig"
+source "drivers/video/fbdev/omap2/omapfb/displays/Kconfig"
+
+endif
diff --git a/drivers/video/fbdev/omap2/omapfb/Makefile b/drivers/video/fbdev/omap2/omapfb/Makefile
index 51c2e00d9bf8..ad68ecf141af 100644
--- a/drivers/video/fbdev/omap2/omapfb/Makefile
+++ b/drivers/video/fbdev/omap2/omapfb/Makefile
@@ -1,2 +1,5 @@
+obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
+obj-y += dss/
+obj-y += displays/
obj-$(CONFIG_FB_OMAP2) += omapfb.o
omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/Kconfig b/drivers/video/fbdev/omap2/omapfb/displays/Kconfig
new file mode 100644
index 000000000000..08f12039dd02
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/Kconfig
@@ -0,0 +1,86 @@
+menu "OMAPFB Panel and Encoder Drivers"
+ depends on FB_OMAP2_DSS
+
+config FB_OMAP2_ENCODER_OPA362
+ tristate "OPA362 external analog amplifier"
+ help
+ Driver for OPA362 external analog TV amplifier controlled
+ through a GPIO.
+
+config FB_OMAP2_ENCODER_TFP410
+ tristate "TFP410 DPI to DVI Encoder"
+ help
+ Driver for TFP410 DPI to DVI encoder.
+
+config FB_OMAP2_ENCODER_TPD12S015
+ tristate "TPD12S015 HDMI ESD protection and level shifter"
+ help
+ Driver for TPD12S015, which offers HDMI ESD protection and level
+ shifting.
+
+config FB_OMAP2_CONNECTOR_DVI
+ tristate "DVI Connector"
+ depends on I2C
+ help
+ Driver for a generic DVI connector.
+
+config FB_OMAP2_CONNECTOR_HDMI
+ tristate "HDMI Connector"
+ help
+ Driver for a generic HDMI connector.
+
+config FB_OMAP2_CONNECTOR_ANALOG_TV
+ tristate "Analog TV Connector"
+ help
+ Driver for a generic analog TV connector.
+
+config FB_OMAP2_PANEL_DPI
+ tristate "Generic DPI panel"
+ help
+ Driver for generic DPI panels.
+
+config FB_OMAP2_PANEL_DSI_CM
+ tristate "Generic DSI Command Mode Panel"
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Driver for generic DSI command mode panels.
+
+config FB_OMAP2_PANEL_SONY_ACX565AKM
+ tristate "ACX565AKM Panel"
+ depends on SPI && BACKLIGHT_CLASS_DEVICE
+ help
+ This is the LCD panel used on Nokia N900
+
+config FB_OMAP2_PANEL_LGPHILIPS_LB035Q02
+ tristate "LG.Philips LB035Q02 LCD Panel"
+ depends on SPI
+ help
+ LCD Panel used on the Gumstix Overo Palo35
+
+config FB_OMAP2_PANEL_SHARP_LS037V7DW01
+ tristate "Sharp LS037V7DW01 LCD Panel"
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ LCD Panel used in TI's SDP3430 and EVM boards
+
+config FB_OMAP2_PANEL_TPO_TD028TTEC1
+ tristate "TPO TD028TTEC1 LCD Panel"
+ depends on SPI
+ help
+ LCD panel used in Openmoko.
+
+config FB_OMAP2_PANEL_TPO_TD043MTEA1
+ tristate "TPO TD043MTEA1 LCD Panel"
+ depends on SPI
+ help
+ LCD Panel used in OMAP3 Pandora
+
+config FB_OMAP2_PANEL_NEC_NL8048HL11
+ tristate "NEC NL8048HL11 Panel"
+ depends on SPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ This NEC NL8048HL11 panel is TFT LCD used in the
+ Zoom2/3/3630 sdp boards.
+
+endmenu
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/Makefile b/drivers/video/fbdev/omap2/omapfb/displays/Makefile
new file mode 100644
index 000000000000..4f7459272256
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_FB_OMAP2_ENCODER_OPA362) += encoder-opa362.o
+obj-$(CONFIG_FB_OMAP2_ENCODER_TFP410) += encoder-tfp410.o
+obj-$(CONFIG_FB_OMAP2_ENCODER_TPD12S015) += encoder-tpd12s015.o
+obj-$(CONFIG_FB_OMAP2_CONNECTOR_DVI) += connector-dvi.o
+obj-$(CONFIG_FB_OMAP2_CONNECTOR_HDMI) += connector-hdmi.o
+obj-$(CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
+obj-$(CONFIG_FB_OMAP2_PANEL_DPI) += panel-dpi.o
+obj-$(CONFIG_FB_OMAP2_PANEL_DSI_CM) += panel-dsi-cm.o
+obj-$(CONFIG_FB_OMAP2_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
+obj-$(CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
+obj-$(CONFIG_FB_OMAP2_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
+obj-$(CONFIG_FB_OMAP2_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
+obj-$(CONFIG_FB_OMAP2_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
+obj-$(CONFIG_FB_OMAP2_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c
new file mode 100644
index 000000000000..8511c648a15c
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c
@@ -0,0 +1,320 @@
+/*
+ * Analog TV Connector driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct device *dev;
+
+ struct omap_video_timings timings;
+
+ enum omap_dss_venc_type connector_type;
+ bool invert_polarity;
+};
+
+static const struct omap_video_timings tvc_pal_timings = {
+ .x_res = 720,
+ .y_res = 574,
+ .pixelclock = 13500000,
+ .hsw = 64,
+ .hfp = 12,
+ .hbp = 68,
+ .vsw = 5,
+ .vfp = 5,
+ .vbp = 41,
+
+ .interlace = true,
+};
+
+static const struct of_device_id tvc_of_match[];
+
+struct tvc_of_data {
+ enum omap_dss_venc_type connector_type;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int tvc_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(ddata->dev, "connect\n");
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.atv->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void tvc_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(ddata->dev, "disconnect\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.atv->disconnect(in, dssdev);
+}
+
+static int tvc_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(ddata->dev, "enable\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.atv->set_timings(in, &ddata->timings);
+
+ if (!ddata->dev->of_node) {
+ in->ops.atv->set_type(in, ddata->connector_type);
+
+ in->ops.atv->invert_vid_out_polarity(in,
+ ddata->invert_polarity);
+ }
+
+ r = in->ops.atv->enable(in);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return r;
+}
+
+static void tvc_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(ddata->dev, "disable\n");
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ in->ops.atv->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void tvc_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.atv->set_timings(in, timings);
+}
+
+static void tvc_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->timings;
+}
+
+static int tvc_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.atv->check_timings(in, timings);
+}
+
+static u32 tvc_get_wss(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.atv->get_wss(in);
+}
+
+static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.atv->set_wss(in, wss);
+}
+
+static struct omap_dss_driver tvc_driver = {
+ .connect = tvc_connect,
+ .disconnect = tvc_disconnect,
+
+ .enable = tvc_enable,
+ .disable = tvc_disable,
+
+ .set_timings = tvc_set_timings,
+ .get_timings = tvc_get_timings,
+ .check_timings = tvc_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+
+ .get_wss = tvc_get_wss,
+ .set_wss = tvc_set_wss,
+};
+
+static int tvc_probe_pdata(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct connector_atv_platform_data *pdata;
+ struct omap_dss_device *in, *dssdev;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "Failed to find video source\n");
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ ddata->connector_type = pdata->connector_type;
+ ddata->invert_polarity = pdata->invert_polarity;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int tvc_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int tvc_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+ ddata->dev = &pdev->dev;
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = tvc_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = tvc_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ ddata->timings = tvc_pal_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->driver = &tvc_driver;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = tvc_pal_timings;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit tvc_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(&ddata->dssdev);
+
+ tvc_disable(dssdev);
+ tvc_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id tvc_of_match[] = {
+ { .compatible = "omapdss,svideo-connector", },
+ { .compatible = "omapdss,composite-video-connector", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, tvc_of_match);
+
+static struct platform_driver tvc_connector_driver = {
+ .probe = tvc_probe,
+ .remove = __exit_p(tvc_remove),
+ .driver = {
+ .name = "connector-analog-tv",
+ .of_match_table = tvc_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(tvc_connector_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("Analog TV Connector driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
new file mode 100644
index 000000000000..d811e6dcaef7
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
@@ -0,0 +1,398 @@
+/*
+ * Generic DVI Connector driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/i2c.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <drm/drm_edid.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+static const struct omap_video_timings dvic_default_timings = {
+ .x_res = 640,
+ .y_res = 480,
+
+ .pixelclock = 23500000,
+
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+
+ .vfp = 3,
+ .vsw = 4,
+ .vbp = 7,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+};
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct omap_video_timings timings;
+
+ struct i2c_adapter *i2c_adapter;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int dvic_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dvi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void dvic_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dvi->disconnect(in, dssdev);
+}
+
+static int dvic_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.dvi->set_timings(in, &ddata->timings);
+
+ r = in->ops.dvi->enable(in);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void dvic_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ in->ops.dvi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void dvic_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dvi->set_timings(in, timings);
+}
+
+static void dvic_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->timings;
+}
+
+static int dvic_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dvi->check_timings(in, timings);
+}
+
+static int dvic_ddc_read(struct i2c_adapter *adapter,
+ unsigned char *buf, u16 count, u8 offset)
+{
+ int r, retries;
+
+ for (retries = 3; retries > 0; retries--) {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = DDC_ADDR,
+ .flags = 0,
+ .len = 1,
+ .buf = &offset,
+ }, {
+ .addr = DDC_ADDR,
+ .flags = I2C_M_RD,
+ .len = count,
+ .buf = buf,
+ }
+ };
+
+ r = i2c_transfer(adapter, msgs, 2);
+ if (r == 2)
+ return 0;
+
+ if (r != -EAGAIN)
+ break;
+ }
+
+ return r < 0 ? r : -EIO;
+}
+
+static int dvic_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ int r, l, bytes_read;
+
+ if (!ddata->i2c_adapter)
+ return -ENODEV;
+
+ l = min(EDID_LENGTH, len);
+ r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
+ if (r)
+ return r;
+
+ bytes_read = l;
+
+ /* if there are extensions, read second block */
+ if (len > EDID_LENGTH && edid[0x7e] > 0) {
+ l = min(EDID_LENGTH, len - EDID_LENGTH);
+
+ r = dvic_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
+ l, EDID_LENGTH);
+ if (r)
+ return r;
+
+ bytes_read += l;
+ }
+
+ return bytes_read;
+}
+
+static bool dvic_detect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ unsigned char out;
+ int r;
+
+ if (!ddata->i2c_adapter)
+ return true;
+
+ r = dvic_ddc_read(ddata->i2c_adapter, &out, 1, 0);
+
+ return r == 0;
+}
+
+static struct omap_dss_driver dvic_driver = {
+ .connect = dvic_connect,
+ .disconnect = dvic_disconnect,
+
+ .enable = dvic_enable,
+ .disable = dvic_disable,
+
+ .set_timings = dvic_set_timings,
+ .get_timings = dvic_get_timings,
+ .check_timings = dvic_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+
+ .read_edid = dvic_read_edid,
+ .detect = dvic_detect,
+};
+
+static int dvic_probe_pdata(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct connector_dvi_platform_data *pdata;
+ struct omap_dss_device *in, *dssdev;
+ int i2c_bus_num;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ i2c_bus_num = pdata->i2c_bus_num;
+
+ if (i2c_bus_num != -1) {
+ struct i2c_adapter *adapter;
+
+ adapter = i2c_get_adapter(i2c_bus_num);
+ if (!adapter) {
+ dev_err(&pdev->dev,
+ "Failed to get I2C adapter, bus %d\n",
+ i2c_bus_num);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->i2c_adapter = adapter;
+ }
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ i2c_put_adapter(ddata->i2c_adapter);
+
+ dev_err(&pdev->dev, "Failed to find video source\n");
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int dvic_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ struct device_node *adapter_node;
+ struct i2c_adapter *adapter;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0);
+ if (adapter_node) {
+ adapter = of_get_i2c_adapter_by_node(adapter_node);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n");
+ omap_dss_put_device(ddata->in);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->i2c_adapter = adapter;
+ }
+
+ return 0;
+}
+
+static int dvic_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = dvic_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = dvic_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ ddata->timings = dvic_default_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->driver = &dvic_driver;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_DVI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = dvic_default_timings;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+ omap_dss_put_device(ddata->in);
+
+ i2c_put_adapter(ddata->i2c_adapter);
+
+ return r;
+}
+
+static int __exit dvic_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(&ddata->dssdev);
+
+ dvic_disable(dssdev);
+ dvic_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ i2c_put_adapter(ddata->i2c_adapter);
+
+ return 0;
+}
+
+static const struct of_device_id dvic_of_match[] = {
+ { .compatible = "omapdss,dvi-connector", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, dvic_of_match);
+
+static struct platform_driver dvi_connector_driver = {
+ .probe = dvic_probe,
+ .remove = __exit_p(dvic_remove),
+ .driver = {
+ .name = "connector-dvi",
+ .of_match_table = dvic_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(dvi_connector_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("Generic DVI Connector driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c
new file mode 100644
index 000000000000..6ee4129bc0c0
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c
@@ -0,0 +1,348 @@
+/*
+ * HDMI Connector driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+#include <drm/drm_edid.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+static const struct omap_video_timings hdmic_default_timings = {
+ .x_res = 640,
+ .y_res = 480,
+ .pixelclock = 25175000,
+ .hsw = 96,
+ .hfp = 16,
+ .hbp = 48,
+ .vsw = 2,
+ .vfp = 11,
+ .vbp = 31,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+
+ .interlace = false,
+};
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct device *dev;
+
+ struct omap_video_timings timings;
+
+ int hpd_gpio;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int hdmic_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(ddata->dev, "connect\n");
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.hdmi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void hdmic_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(ddata->dev, "disconnect\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.hdmi->disconnect(in, dssdev);
+}
+
+static int hdmic_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(ddata->dev, "enable\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.hdmi->set_timings(in, &ddata->timings);
+
+ r = in->ops.hdmi->enable(in);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return r;
+}
+
+static void hdmic_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(ddata->dev, "disable\n");
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ in->ops.hdmi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void hdmic_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.hdmi->set_timings(in, timings);
+}
+
+static void hdmic_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->timings;
+}
+
+static int hdmic_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.hdmi->check_timings(in, timings);
+}
+
+static int hdmic_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.hdmi->read_edid(in, edid, len);
+}
+
+static bool hdmic_detect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (gpio_is_valid(ddata->hpd_gpio))
+ return gpio_get_value_cansleep(ddata->hpd_gpio);
+ else
+ return in->ops.hdmi->detect(in);
+}
+
+static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
+}
+
+static int hdmic_set_infoframe(struct omap_dss_device *dssdev,
+ const struct hdmi_avi_infoframe *avi)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.hdmi->set_infoframe(in, avi);
+}
+
+static struct omap_dss_driver hdmic_driver = {
+ .connect = hdmic_connect,
+ .disconnect = hdmic_disconnect,
+
+ .enable = hdmic_enable,
+ .disable = hdmic_disable,
+
+ .set_timings = hdmic_set_timings,
+ .get_timings = hdmic_get_timings,
+ .check_timings = hdmic_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+
+ .read_edid = hdmic_read_edid,
+ .detect = hdmic_detect,
+ .set_hdmi_mode = hdmic_set_hdmi_mode,
+ .set_hdmi_infoframe = hdmic_set_infoframe,
+};
+
+static int hdmic_probe_pdata(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct connector_hdmi_platform_data *pdata;
+ struct omap_dss_device *in, *dssdev;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ ddata->hpd_gpio = -ENODEV;
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "Failed to find video source\n");
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int hdmic_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ int gpio;
+
+ /* HPD GPIO */
+ gpio = of_get_named_gpio(node, "hpd-gpios", 0);
+ if (gpio_is_valid(gpio))
+ ddata->hpd_gpio = gpio;
+ else
+ ddata->hpd_gpio = -ENODEV;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int hdmic_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+ ddata->dev = &pdev->dev;
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = hdmic_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = hdmic_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->hpd_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
+ GPIOF_DIR_IN, "hdmi_hpd");
+ if (r)
+ goto err_reg;
+ }
+
+ ddata->timings = hdmic_default_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->driver = &hdmic_driver;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = hdmic_default_timings;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit hdmic_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(&ddata->dssdev);
+
+ hdmic_disable(dssdev);
+ hdmic_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id hdmic_of_match[] = {
+ { .compatible = "omapdss,hdmi-connector", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, hdmic_of_match);
+
+static struct platform_driver hdmi_connector_driver = {
+ .probe = hdmic_probe,
+ .remove = __exit_p(hdmic_remove),
+ .driver = {
+ .name = "connector-hdmi",
+ .of_match_table = hdmic_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(hdmi_connector_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("HDMI Connector driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c
new file mode 100644
index 000000000000..8c246c213e06
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c
@@ -0,0 +1,278 @@
+/*
+ * OPA362 analog video amplifier with output/power control
+ *
+ * Copyright (C) 2014 Golden Delicious Computers
+ * Author: H. Nikolaus Schaller <hns@goldelico.com>
+ *
+ * based on encoder-tfp410
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct gpio_desc *enable_gpio;
+
+ struct omap_video_timings timings;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int opa362_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(dssdev->dev, "connect\n");
+
+ if (omapdss_device_is_connected(dssdev))
+ return -EBUSY;
+
+ r = in->ops.atv->connect(in, dssdev);
+ if (r)
+ return r;
+
+ dst->src = dssdev;
+ dssdev->dst = dst;
+
+ return 0;
+}
+
+static void opa362_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "disconnect\n");
+
+ WARN_ON(!omapdss_device_is_connected(dssdev));
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ WARN_ON(dst != dssdev->dst);
+ if (dst != dssdev->dst)
+ return;
+
+ dst->src = NULL;
+ dssdev->dst = NULL;
+
+ in->ops.atv->disconnect(in, &ddata->dssdev);
+}
+
+static int opa362_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(dssdev->dev, "enable\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.atv->set_timings(in, &ddata->timings);
+
+ r = in->ops.atv->enable(in);
+ if (r)
+ return r;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void opa362_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "disable\n");
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
+
+ in->ops.atv->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void opa362_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "set_timings\n");
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.atv->set_timings(in, timings);
+}
+
+static void opa362_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ dev_dbg(dssdev->dev, "get_timings\n");
+
+ *timings = ddata->timings;
+}
+
+static int opa362_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "check_timings\n");
+
+ return in->ops.atv->check_timings(in, timings);
+}
+
+static void opa362_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ /* we can only drive a COMPOSITE output */
+ WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
+
+}
+
+static const struct omapdss_atv_ops opa362_atv_ops = {
+ .connect = opa362_connect,
+ .disconnect = opa362_disconnect,
+
+ .enable = opa362_enable,
+ .disable = opa362_disable,
+
+ .check_timings = opa362_check_timings,
+ .set_timings = opa362_set_timings,
+ .get_timings = opa362_get_timings,
+
+ .set_type = opa362_set_type,
+};
+
+static int opa362_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev, *in;
+ struct gpio_desc *gpio;
+ int r;
+
+ dev_dbg(&pdev->dev, "probe\n");
+
+ if (node == NULL) {
+ dev_err(&pdev->dev, "Unable to find device tree\n");
+ return -EINVAL;
+ }
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(gpio))
+ return PTR_ERR(gpio);
+
+ ddata->enable_gpio = gpio;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->ops.atv = &opa362_atv_ops;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->owner = THIS_MODULE;
+
+ r = omapdss_register_output(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register output\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit opa362_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_output(&ddata->dssdev);
+
+ WARN_ON(omapdss_device_is_enabled(dssdev));
+ if (omapdss_device_is_enabled(dssdev))
+ opa362_disable(dssdev);
+
+ WARN_ON(omapdss_device_is_connected(dssdev));
+ if (omapdss_device_is_connected(dssdev))
+ opa362_disconnect(dssdev, dssdev->dst);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id opa362_of_match[] = {
+ { .compatible = "omapdss,ti,opa362", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, opa362_of_match);
+
+static struct platform_driver opa362_driver = {
+ .probe = opa362_probe,
+ .remove = __exit_p(opa362_remove),
+ .driver = {
+ .name = "amplifier-opa362",
+ .of_match_table = opa362_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(opa362_driver);
+
+MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
+MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c
new file mode 100644
index 000000000000..d9048b3df495
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c
@@ -0,0 +1,320 @@
+/*
+ * TFP410 DPI-to-DVI encoder driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ int pd_gpio;
+ int data_lines;
+
+ struct omap_video_timings timings;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int tfp410_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return -EBUSY;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ dst->src = dssdev;
+ dssdev->dst = dst;
+
+ return 0;
+}
+
+static void tfp410_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ WARN_ON(!omapdss_device_is_connected(dssdev));
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ WARN_ON(dst != dssdev->dst);
+ if (dst != dssdev->dst)
+ return;
+
+ dst->src = NULL;
+ dssdev->dst = NULL;
+
+ in->ops.dpi->disconnect(in, &ddata->dssdev);
+}
+
+static int tfp410_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.dpi->set_timings(in, &ddata->timings);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_set_value_cansleep(ddata->pd_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void tfp410_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_set_value_cansleep(ddata->pd_gpio, 0);
+
+ in->ops.dpi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void tfp410_fix_timings(struct omap_video_timings *timings)
+{
+ timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+}
+
+static void tfp410_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ tfp410_fix_timings(timings);
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void tfp410_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->timings;
+}
+
+static int tfp410_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ tfp410_fix_timings(timings);
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static const struct omapdss_dvi_ops tfp410_dvi_ops = {
+ .connect = tfp410_connect,
+ .disconnect = tfp410_disconnect,
+
+ .enable = tfp410_enable,
+ .disable = tfp410_disable,
+
+ .check_timings = tfp410_check_timings,
+ .set_timings = tfp410_set_timings,
+ .get_timings = tfp410_get_timings,
+};
+
+static int tfp410_probe_pdata(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct encoder_tfp410_platform_data *pdata;
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ ddata->pd_gpio = pdata->power_down_gpio;
+
+ ddata->data_lines = pdata->data_lines;
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "Failed to find video source\n");
+ return -ENODEV;
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int tfp410_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ int gpio;
+
+ gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
+
+ if (gpio_is_valid(gpio) || gpio == -ENOENT) {
+ ddata->pd_gpio = gpio;
+ } else {
+ dev_err(&pdev->dev, "failed to parse PD gpio\n");
+ return gpio;
+ }
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int tfp410_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = tfp410_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = tfp410_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->pd_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
+ GPIOF_OUT_INIT_LOW, "tfp410 PD");
+ if (r) {
+ dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
+ ddata->pd_gpio);
+ goto err_gpio;
+ }
+ }
+
+ dssdev = &ddata->dssdev;
+ dssdev->ops.dvi = &tfp410_dvi_ops;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->phy.dpi.data_lines = ddata->data_lines;
+ dssdev->port_num = 1;
+
+ r = omapdss_register_output(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register output\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit tfp410_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_output(&ddata->dssdev);
+
+ WARN_ON(omapdss_device_is_enabled(dssdev));
+ if (omapdss_device_is_enabled(dssdev))
+ tfp410_disable(dssdev);
+
+ WARN_ON(omapdss_device_is_connected(dssdev));
+ if (omapdss_device_is_connected(dssdev))
+ tfp410_disconnect(dssdev, dssdev->dst);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id tfp410_of_match[] = {
+ { .compatible = "omapdss,ti,tfp410", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, tfp410_of_match);
+
+static struct platform_driver tfp410_driver = {
+ .probe = tfp410_probe,
+ .remove = __exit_p(tfp410_remove),
+ .driver = {
+ .name = "tfp410",
+ .of_match_table = tfp410_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(tfp410_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
new file mode 100644
index 000000000000..677e2545fcbe
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
@@ -0,0 +1,328 @@
+/*
+ * TPD12S015 HDMI ESD protection & level shifter chip driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/completion.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct gpio_desc *ct_cp_hpd_gpio;
+ struct gpio_desc *ls_oe_gpio;
+ struct gpio_desc *hpd_gpio;
+
+ struct omap_video_timings timings;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int tpd_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ r = in->ops.hdmi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ dst->src = dssdev;
+ dssdev->dst = dst;
+
+ if (ddata->ct_cp_hpd_gpio) {
+ gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
+ /* DC-DC converter needs at max 300us to get to 90% of 5V */
+ udelay(300);
+ }
+
+ return 0;
+}
+
+static void tpd_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
+
+ dst->src = NULL;
+ dssdev->dst = NULL;
+
+ in->ops.hdmi->disconnect(in, &ddata->dssdev);
+}
+
+static int tpd_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
+ in->ops.hdmi->set_timings(in, &ddata->timings);
+
+ r = in->ops.hdmi->enable(in);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return r;
+}
+
+static void tpd_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
+ in->ops.hdmi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void tpd_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.hdmi->set_timings(in, timings);
+}
+
+static void tpd_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->timings;
+}
+
+static int tpd_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ r = in->ops.hdmi->check_timings(in, timings);
+
+ return r;
+}
+
+static int tpd_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!gpiod_get_value_cansleep(ddata->hpd_gpio))
+ return -ENODEV;
+
+ gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
+
+ r = in->ops.hdmi->read_edid(in, edid, len);
+
+ gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
+
+ return r;
+}
+
+static bool tpd_detect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ return gpiod_get_value_cansleep(ddata->hpd_gpio);
+}
+
+static int tpd_set_infoframe(struct omap_dss_device *dssdev,
+ const struct hdmi_avi_infoframe *avi)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.hdmi->set_infoframe(in, avi);
+}
+
+static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev,
+ bool hdmi_mode)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
+}
+
+static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
+ .connect = tpd_connect,
+ .disconnect = tpd_disconnect,
+
+ .enable = tpd_enable,
+ .disable = tpd_disable,
+
+ .check_timings = tpd_check_timings,
+ .set_timings = tpd_set_timings,
+ .get_timings = tpd_get_timings,
+
+ .read_edid = tpd_read_edid,
+ .detect = tpd_detect,
+ .set_infoframe = tpd_set_infoframe,
+ .set_hdmi_mode = tpd_set_hdmi_mode,
+};
+
+static int tpd_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int tpd_probe(struct platform_device *pdev)
+{
+ struct omap_dss_device *in, *dssdev;
+ struct panel_drv_data *ddata;
+ int r;
+ struct gpio_desc *gpio;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (pdev->dev.of_node) {
+ r = tpd_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+
+ gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
+ GPIOD_OUT_LOW);
+ if (IS_ERR(gpio))
+ goto err_gpio;
+
+ ddata->ct_cp_hpd_gpio = gpio;
+
+ gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
+ GPIOD_OUT_LOW);
+ if (IS_ERR(gpio))
+ goto err_gpio;
+
+ ddata->ls_oe_gpio = gpio;
+
+ gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
+ GPIOD_IN);
+ if (IS_ERR(gpio))
+ goto err_gpio;
+
+ ddata->hpd_gpio = gpio;
+
+ dssdev = &ddata->dssdev;
+ dssdev->ops.hdmi = &tpd_hdmi_ops;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
+ dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->port_num = 1;
+
+ in = ddata->in;
+
+ r = omapdss_register_output(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register output\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit tpd_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_output(&ddata->dssdev);
+
+ WARN_ON(omapdss_device_is_enabled(dssdev));
+ if (omapdss_device_is_enabled(dssdev))
+ tpd_disable(dssdev);
+
+ WARN_ON(omapdss_device_is_connected(dssdev));
+ if (omapdss_device_is_connected(dssdev))
+ tpd_disconnect(dssdev, dssdev->dst);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id tpd_of_match[] = {
+ { .compatible = "omapdss,ti,tpd12s015", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, tpd_of_match);
+
+static struct platform_driver tpd_driver = {
+ .probe = tpd_probe,
+ .remove = __exit_p(tpd_remove),
+ .driver = {
+ .name = "tpd12s015",
+ .of_match_table = tpd_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(tpd_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("TPD12S015 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c
new file mode 100644
index 000000000000..e780fd4f8b46
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c
@@ -0,0 +1,328 @@
+/*
+ * Generic MIPI DPI Panel Driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+#include <video/of_display_timing.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ int data_lines;
+
+ struct omap_video_timings videomode;
+
+ /* used for non-DT boot, to be removed */
+ int backlight_gpio;
+
+ struct gpio_desc *enable_gpio;
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int panel_dpi_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int panel_dpi_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
+
+ if (gpio_is_valid(ddata->backlight_gpio))
+ gpio_set_value_cansleep(ddata->backlight_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void panel_dpi_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (gpio_is_valid(ddata->backlight_gpio))
+ gpio_set_value_cansleep(ddata->backlight_gpio, 0);
+
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
+
+ in->ops.dpi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver panel_dpi_ops = {
+ .connect = panel_dpi_connect,
+ .disconnect = panel_dpi_disconnect,
+
+ .enable = panel_dpi_enable,
+ .disable = panel_dpi_disable,
+
+ .set_timings = panel_dpi_set_timings,
+ .get_timings = panel_dpi_get_timings,
+ .check_timings = panel_dpi_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+};
+
+static int panel_dpi_probe_pdata(struct platform_device *pdev)
+{
+ const struct panel_dpi_platform_data *pdata;
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev, *in;
+ struct videomode vm;
+ int r;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ videomode_from_timing(pdata->display_timing, &vm);
+ videomode_to_omap_video_timings(&vm, &ddata->videomode);
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
+ GPIOF_OUT_INIT_LOW, "panel enable");
+ if (r)
+ goto err_gpio;
+
+ ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
+
+ ddata->backlight_gpio = pdata->backlight_gpio;
+
+ return 0;
+
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int panel_dpi_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ int r;
+ struct display_timing timing;
+ struct videomode vm;
+ struct gpio_desc *gpio;
+
+ gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(gpio))
+ return PTR_ERR(gpio);
+
+ ddata->enable_gpio = gpio;
+
+ ddata->backlight_gpio = -ENOENT;
+
+ r = of_get_display_timing(node, "panel-timing", &timing);
+ if (r) {
+ dev_err(&pdev->dev, "failed to get video timing\n");
+ return r;
+ }
+
+ videomode_from_timing(&timing, &vm);
+ videomode_to_omap_video_timings(&vm, &ddata->videomode);
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int panel_dpi_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = panel_dpi_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = panel_dpi_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->backlight_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
+ GPIOF_OUT_INIT_LOW, "panel backlight");
+ if (r)
+ goto err_gpio;
+ }
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &pdev->dev;
+ dssdev->driver = &panel_dpi_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+ dssdev->phy.dpi.data_lines = ddata->data_lines;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit panel_dpi_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(dssdev);
+
+ panel_dpi_disable(dssdev);
+ panel_dpi_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id panel_dpi_of_match[] = {
+ { .compatible = "omapdss,panel-dpi", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
+
+static struct platform_driver panel_dpi_driver = {
+ .probe = panel_dpi_probe,
+ .remove = __exit_p(panel_dpi_remove),
+ .driver = {
+ .name = "panel-dpi",
+ .of_match_table = panel_dpi_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(panel_dpi_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
new file mode 100644
index 000000000000..3414c2609320
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
@@ -0,0 +1,1388 @@
+/*
+ * Generic DSI Command Mode panel driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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.
+ */
+
+/* #define DEBUG */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+#include <video/mipi_display.h>
+
+/* DSI Virtual channel. Hardcoded for now. */
+#define TCH 0
+
+#define DCS_READ_NUM_ERRORS 0x05
+#define DCS_BRIGHTNESS 0x51
+#define DCS_CTRL_DISPLAY 0x53
+#define DCS_GET_ID1 0xda
+#define DCS_GET_ID2 0xdb
+#define DCS_GET_ID3 0xdc
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct omap_video_timings timings;
+
+ struct platform_device *pdev;
+
+ struct mutex lock;
+
+ struct backlight_device *bldev;
+
+ unsigned long hw_guard_end; /* next value of jiffies when we can
+ * issue the next sleep in/out command
+ */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+
+ /* panel HW configuration from DT or platform data */
+ int reset_gpio;
+ int ext_te_gpio;
+
+ bool use_dsi_backlight;
+
+ struct omap_dsi_pin_config pin_config;
+
+ /* runtime variables */
+ bool enabled;
+
+ bool te_enabled;
+
+ atomic_t do_update;
+ int channel;
+
+ struct delayed_work te_timeout_work;
+
+ bool intro_printed;
+
+ struct workqueue_struct *workqueue;
+
+ bool ulps_enabled;
+ unsigned ulps_timeout;
+ struct delayed_work ulps_work;
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static irqreturn_t dsicm_te_isr(int irq, void *data);
+static void dsicm_te_timeout_work_callback(struct work_struct *work);
+static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);
+
+static int dsicm_panel_reset(struct panel_drv_data *ddata);
+
+static void dsicm_ulps_work(struct work_struct *work);
+
+static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
+{
+ ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct panel_drv_data *ddata)
+{
+ unsigned long wait = ddata->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
+{
+ struct omap_dss_device *in = ddata->in;
+ int r;
+ u8 buf[1];
+
+ r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);
+
+ if (r < 0)
+ return r;
+
+ *data = buf[0];
+
+ return 0;
+}
+
+static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
+{
+ struct omap_dss_device *in = ddata->in;
+ return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);
+}
+
+static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
+{
+ struct omap_dss_device *in = ddata->in;
+ u8 buf[2] = { dcs_cmd, param };
+
+ return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);
+}
+
+static int dsicm_sleep_in(struct panel_drv_data *ddata)
+
+{
+ struct omap_dss_device *in = ddata->in;
+ u8 cmd;
+ int r;
+
+ hw_guard_wait(ddata);
+
+ cmd = MIPI_DCS_ENTER_SLEEP_MODE;
+ r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);
+ if (r)
+ return r;
+
+ hw_guard_start(ddata, 120);
+
+ usleep_range(5000, 10000);
+
+ return 0;
+}
+
+static int dsicm_sleep_out(struct panel_drv_data *ddata)
+{
+ int r;
+
+ hw_guard_wait(ddata);
+
+ r = dsicm_dcs_write_0(ddata, MIPI_DCS_EXIT_SLEEP_MODE);
+ if (r)
+ return r;
+
+ hw_guard_start(ddata, 120);
+
+ usleep_range(5000, 10000);
+
+ return 0;
+}
+
+static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
+{
+ int r;
+
+ r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);
+ if (r)
+ return r;
+ r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);
+ if (r)
+ return r;
+ r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int dsicm_set_update_window(struct panel_drv_data *ddata,
+ u16 x, u16 y, u16 w, u16 h)
+{
+ struct omap_dss_device *in = ddata->in;
+ int r;
+ u16 x1 = x;
+ u16 x2 = x + w - 1;
+ u16 y1 = y;
+ u16 y2 = y + h - 1;
+
+ u8 buf[5];
+ buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
+ buf[1] = (x1 >> 8) & 0xff;
+ buf[2] = (x1 >> 0) & 0xff;
+ buf[3] = (x2 >> 8) & 0xff;
+ buf[4] = (x2 >> 0) & 0xff;
+
+ r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
+ if (r)
+ return r;
+
+ buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
+ buf[1] = (y1 >> 8) & 0xff;
+ buf[2] = (y1 >> 0) & 0xff;
+ buf[3] = (y2 >> 8) & 0xff;
+ buf[4] = (y2 >> 0) & 0xff;
+
+ r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
+ if (r)
+ return r;
+
+ in->ops.dsi->bta_sync(in, ddata->channel);
+
+ return r;
+}
+
+static void dsicm_queue_ulps_work(struct panel_drv_data *ddata)
+{
+ if (ddata->ulps_timeout > 0)
+ queue_delayed_work(ddata->workqueue, &ddata->ulps_work,
+ msecs_to_jiffies(ddata->ulps_timeout));
+}
+
+static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)
+{
+ cancel_delayed_work(&ddata->ulps_work);
+}
+
+static int dsicm_enter_ulps(struct panel_drv_data *ddata)
+{
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (ddata->ulps_enabled)
+ return 0;
+
+ dsicm_cancel_ulps_work(ddata);
+
+ r = _dsicm_enable_te(ddata, false);
+ if (r)
+ goto err;
+
+ if (gpio_is_valid(ddata->ext_te_gpio))
+ disable_irq(gpio_to_irq(ddata->ext_te_gpio));
+
+ in->ops.dsi->disable(in, false, true);
+
+ ddata->ulps_enabled = true;
+
+ return 0;
+
+err:
+ dev_err(&ddata->pdev->dev, "enter ULPS failed");
+ dsicm_panel_reset(ddata);
+
+ ddata->ulps_enabled = false;
+
+ dsicm_queue_ulps_work(ddata);
+
+ return r;
+}
+
+static int dsicm_exit_ulps(struct panel_drv_data *ddata)
+{
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!ddata->ulps_enabled)
+ return 0;
+
+ r = in->ops.dsi->enable(in);
+ if (r) {
+ dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
+ goto err1;
+ }
+
+ in->ops.dsi->enable_hs(in, ddata->channel, true);
+
+ r = _dsicm_enable_te(ddata, true);
+ if (r) {
+ dev_err(&ddata->pdev->dev, "failed to re-enable TE");
+ goto err2;
+ }
+
+ if (gpio_is_valid(ddata->ext_te_gpio))
+ enable_irq(gpio_to_irq(ddata->ext_te_gpio));
+
+ dsicm_queue_ulps_work(ddata);
+
+ ddata->ulps_enabled = false;
+
+ return 0;
+
+err2:
+ dev_err(&ddata->pdev->dev, "failed to exit ULPS");
+
+ r = dsicm_panel_reset(ddata);
+ if (!r) {
+ if (gpio_is_valid(ddata->ext_te_gpio))
+ enable_irq(gpio_to_irq(ddata->ext_te_gpio));
+ ddata->ulps_enabled = false;
+ }
+err1:
+ dsicm_queue_ulps_work(ddata);
+
+ return r;
+}
+
+static int dsicm_wake_up(struct panel_drv_data *ddata)
+{
+ if (ddata->ulps_enabled)
+ return dsicm_exit_ulps(ddata);
+
+ dsicm_cancel_ulps_work(ddata);
+ dsicm_queue_ulps_work(ddata);
+ return 0;
+}
+
+static int dsicm_bl_update_status(struct backlight_device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+ int level;
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK)
+ level = dev->props.brightness;
+ else
+ level = 0;
+
+ dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level);
+
+ mutex_lock(&ddata->lock);
+
+ if (ddata->enabled) {
+ in->ops.dsi->bus_lock(in);
+
+ r = dsicm_wake_up(ddata);
+ if (!r)
+ r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);
+
+ in->ops.dsi->bus_unlock(in);
+ } else {
+ r = 0;
+ }
+
+ mutex_unlock(&ddata->lock);
+
+ return r;
+}
+
+static int dsicm_bl_get_intensity(struct backlight_device *dev)
+{
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK)
+ return dev->props.brightness;
+
+ return 0;
+}
+
+static const struct backlight_ops dsicm_bl_ops = {
+ .get_brightness = dsicm_bl_get_intensity,
+ .update_status = dsicm_bl_update_status,
+};
+
+static void dsicm_get_resolution(struct omap_dss_device *dssdev,
+ u16 *xres, u16 *yres)
+{
+ *xres = dssdev->panel.timings.x_res;
+ *yres = dssdev->panel.timings.y_res;
+}
+
+static ssize_t dsicm_num_errors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *in = ddata->in;
+ u8 errors = 0;
+ int r;
+
+ mutex_lock(&ddata->lock);
+
+ if (ddata->enabled) {
+ in->ops.dsi->bus_lock(in);
+
+ r = dsicm_wake_up(ddata);
+ if (!r)
+ r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,
+ &errors);
+
+ in->ops.dsi->bus_unlock(in);
+ } else {
+ r = -ENODEV;
+ }
+
+ mutex_unlock(&ddata->lock);
+
+ if (r)
+ return r;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", errors);
+}
+
+static ssize_t dsicm_hw_revision_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *in = ddata->in;
+ u8 id1, id2, id3;
+ int r;
+
+ mutex_lock(&ddata->lock);
+
+ if (ddata->enabled) {
+ in->ops.dsi->bus_lock(in);
+
+ r = dsicm_wake_up(ddata);
+ if (!r)
+ r = dsicm_get_id(ddata, &id1, &id2, &id3);
+
+ in->ops.dsi->bus_unlock(in);
+ } else {
+ r = -ENODEV;
+ }
+
+ mutex_unlock(&ddata->lock);
+
+ if (r)
+ return r;
+
+ return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
+}
+
+static ssize_t dsicm_store_ulps(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *in = ddata->in;
+ unsigned long t;
+ int r;
+
+ r = kstrtoul(buf, 0, &t);
+ if (r)
+ return r;
+
+ mutex_lock(&ddata->lock);
+
+ if (ddata->enabled) {
+ in->ops.dsi->bus_lock(in);
+
+ if (t)
+ r = dsicm_enter_ulps(ddata);
+ else
+ r = dsicm_wake_up(ddata);
+
+ in->ops.dsi->bus_unlock(in);
+ }
+
+ mutex_unlock(&ddata->lock);
+
+ if (r)
+ return r;
+
+ return count;
+}
+
+static ssize_t dsicm_show_ulps(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ unsigned t;
+
+ mutex_lock(&ddata->lock);
+ t = ddata->ulps_enabled;
+ mutex_unlock(&ddata->lock);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t dsicm_store_ulps_timeout(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *in = ddata->in;
+ unsigned long t;
+ int r;
+
+ r = kstrtoul(buf, 0, &t);
+ if (r)
+ return r;
+
+ mutex_lock(&ddata->lock);
+ ddata->ulps_timeout = t;
+
+ if (ddata->enabled) {
+ /* dsicm_wake_up will restart the timer */
+ in->ops.dsi->bus_lock(in);
+ r = dsicm_wake_up(ddata);
+ in->ops.dsi->bus_unlock(in);
+ }
+
+ mutex_unlock(&ddata->lock);
+
+ if (r)
+ return r;
+
+ return count;
+}
+
+static ssize_t dsicm_show_ulps_timeout(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ unsigned t;
+
+ mutex_lock(&ddata->lock);
+ t = ddata->ulps_timeout;
+ mutex_unlock(&ddata->lock);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL);
+static DEVICE_ATTR(hw_revision, S_IRUGO, dsicm_hw_revision_show, NULL);
+static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
+ dsicm_show_ulps, dsicm_store_ulps);
+static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
+ dsicm_show_ulps_timeout, dsicm_store_ulps_timeout);
+
+static struct attribute *dsicm_attrs[] = {
+ &dev_attr_num_dsi_errors.attr,
+ &dev_attr_hw_revision.attr,
+ &dev_attr_ulps.attr,
+ &dev_attr_ulps_timeout.attr,
+ NULL,
+};
+
+static struct attribute_group dsicm_attr_group = {
+ .attrs = dsicm_attrs,
+};
+
+static void dsicm_hw_reset(struct panel_drv_data *ddata)
+{
+ if (!gpio_is_valid(ddata->reset_gpio))
+ return;
+
+ gpio_set_value(ddata->reset_gpio, 1);
+ udelay(10);
+ /* reset the panel */
+ gpio_set_value(ddata->reset_gpio, 0);
+ /* assert reset */
+ udelay(10);
+ gpio_set_value(ddata->reset_gpio, 1);
+ /* wait after releasing reset */
+ usleep_range(5000, 10000);
+}
+
+static int dsicm_power_on(struct panel_drv_data *ddata)
+{
+ struct omap_dss_device *in = ddata->in;
+ u8 id1, id2, id3;
+ int r;
+ struct omap_dss_dsi_config dsi_config = {
+ .mode = OMAP_DSS_DSI_CMD_MODE,
+ .pixel_format = OMAP_DSS_DSI_FMT_RGB888,
+ .timings = &ddata->timings,
+ .hs_clk_min = 150000000,
+ .hs_clk_max = 300000000,
+ .lp_clk_min = 7000000,
+ .lp_clk_max = 10000000,
+ };
+
+ if (ddata->pin_config.num_pins > 0) {
+ r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
+ if (r) {
+ dev_err(&ddata->pdev->dev,
+ "failed to configure DSI pins\n");
+ goto err0;
+ }
+ }
+
+ r = in->ops.dsi->set_config(in, &dsi_config);
+ if (r) {
+ dev_err(&ddata->pdev->dev, "failed to configure DSI\n");
+ goto err0;
+ }
+
+ r = in->ops.dsi->enable(in);
+ if (r) {
+ dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
+ goto err0;
+ }
+
+ dsicm_hw_reset(ddata);
+
+ in->ops.dsi->enable_hs(in, ddata->channel, false);
+
+ r = dsicm_sleep_out(ddata);
+ if (r)
+ goto err;
+
+ r = dsicm_get_id(ddata, &id1, &id2, &id3);
+ if (r)
+ goto err;
+
+ r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, 0xff);
+ if (r)
+ goto err;
+
+ r = dsicm_dcs_write_1(ddata, DCS_CTRL_DISPLAY,
+ (1<<2) | (1<<5)); /* BL | BCTRL */
+ if (r)
+ goto err;
+
+ r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_PIXEL_FORMAT,
+ MIPI_DCS_PIXEL_FMT_24BIT);
+ if (r)
+ goto err;
+
+ r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_ON);
+ if (r)
+ goto err;
+
+ r = _dsicm_enable_te(ddata, ddata->te_enabled);
+ if (r)
+ goto err;
+
+ r = in->ops.dsi->enable_video_output(in, ddata->channel);
+ if (r)
+ goto err;
+
+ ddata->enabled = 1;
+
+ if (!ddata->intro_printed) {
+ dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n",
+ id1, id2, id3);
+ ddata->intro_printed = true;
+ }
+
+ in->ops.dsi->enable_hs(in, ddata->channel, true);
+
+ return 0;
+err:
+ dev_err(&ddata->pdev->dev, "error while enabling panel, issuing HW reset\n");
+
+ dsicm_hw_reset(ddata);
+
+ in->ops.dsi->disable(in, true, false);
+err0:
+ return r;
+}
+
+static void dsicm_power_off(struct panel_drv_data *ddata)
+{
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ in->ops.dsi->disable_video_output(in, ddata->channel);
+
+ r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);
+ if (!r)
+ r = dsicm_sleep_in(ddata);
+
+ if (r) {
+ dev_err(&ddata->pdev->dev,
+ "error disabling panel, issuing HW reset\n");
+ dsicm_hw_reset(ddata);
+ }
+
+ in->ops.dsi->disable(in, true, false);
+
+ ddata->enabled = 0;
+}
+
+static int dsicm_panel_reset(struct panel_drv_data *ddata)
+{
+ dev_err(&ddata->pdev->dev, "performing LCD reset\n");
+
+ dsicm_power_off(ddata);
+ dsicm_hw_reset(ddata);
+ return dsicm_power_on(ddata);
+}
+
+static int dsicm_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ struct device *dev = &ddata->pdev->dev;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dsi->connect(in, dssdev);
+ if (r) {
+ dev_err(dev, "Failed to connect to video source\n");
+ return r;
+ }
+
+ r = in->ops.dsi->request_vc(ddata->in, &ddata->channel);
+ if (r) {
+ dev_err(dev, "failed to get virtual channel\n");
+ goto err_req_vc;
+ }
+
+ r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH);
+ if (r) {
+ dev_err(dev, "failed to set VC_ID\n");
+ goto err_vc_id;
+ }
+
+ return 0;
+
+err_vc_id:
+ in->ops.dsi->release_vc(ddata->in, ddata->channel);
+err_req_vc:
+ in->ops.dsi->disconnect(in, dssdev);
+ return r;
+}
+
+static void dsicm_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dsi->release_vc(in, ddata->channel);
+ in->ops.dsi->disconnect(in, dssdev);
+}
+
+static int dsicm_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(&ddata->pdev->dev, "enable\n");
+
+ mutex_lock(&ddata->lock);
+
+ if (!omapdss_device_is_connected(dssdev)) {
+ r = -ENODEV;
+ goto err;
+ }
+
+ if (omapdss_device_is_enabled(dssdev)) {
+ r = 0;
+ goto err;
+ }
+
+ in->ops.dsi->bus_lock(in);
+
+ r = dsicm_power_on(ddata);
+
+ in->ops.dsi->bus_unlock(in);
+
+ if (r)
+ goto err;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ mutex_unlock(&ddata->lock);
+
+ return 0;
+err:
+ dev_dbg(&ddata->pdev->dev, "enable failed\n");
+ mutex_unlock(&ddata->lock);
+ return r;
+}
+
+static void dsicm_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(&ddata->pdev->dev, "disable\n");
+
+ mutex_lock(&ddata->lock);
+
+ dsicm_cancel_ulps_work(ddata);
+
+ in->ops.dsi->bus_lock(in);
+
+ if (omapdss_device_is_enabled(dssdev)) {
+ r = dsicm_wake_up(ddata);
+ if (!r)
+ dsicm_power_off(ddata);
+ }
+
+ in->ops.dsi->bus_unlock(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+ mutex_unlock(&ddata->lock);
+}
+
+static void dsicm_framedone_cb(int err, void *data)
+{
+ struct panel_drv_data *ddata = data;
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);
+ in->ops.dsi->bus_unlock(ddata->in);
+}
+
+static irqreturn_t dsicm_te_isr(int irq, void *data)
+{
+ struct panel_drv_data *ddata = data;
+ struct omap_dss_device *in = ddata->in;
+ int old;
+ int r;
+
+ old = atomic_cmpxchg(&ddata->do_update, 1, 0);
+
+ if (old) {
+ cancel_delayed_work(&ddata->te_timeout_work);
+
+ r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
+ ddata);
+ if (r)
+ goto err;
+ }
+
+ return IRQ_HANDLED;
+err:
+ dev_err(&ddata->pdev->dev, "start update failed\n");
+ in->ops.dsi->bus_unlock(in);
+ return IRQ_HANDLED;
+}
+
+static void dsicm_te_timeout_work_callback(struct work_struct *work)
+{
+ struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
+ te_timeout_work.work);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");
+
+ atomic_set(&ddata->do_update, 0);
+ in->ops.dsi->bus_unlock(in);
+}
+
+static int dsicm_update(struct omap_dss_device *dssdev,
+ u16 x, u16 y, u16 w, u16 h)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
+
+ mutex_lock(&ddata->lock);
+ in->ops.dsi->bus_lock(in);
+
+ r = dsicm_wake_up(ddata);
+ if (r)
+ goto err;
+
+ if (!ddata->enabled) {
+ r = 0;
+ goto err;
+ }
+
+ /* XXX no need to send this every frame, but dsi break if not done */
+ r = dsicm_set_update_window(ddata, 0, 0,
+ dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+ if (r)
+ goto err;
+
+ if (ddata->te_enabled && gpio_is_valid(ddata->ext_te_gpio)) {
+ schedule_delayed_work(&ddata->te_timeout_work,
+ msecs_to_jiffies(250));
+ atomic_set(&ddata->do_update, 1);
+ } else {
+ r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
+ ddata);
+ if (r)
+ goto err;
+ }
+
+ /* note: no bus_unlock here. unlock is in framedone_cb */
+ mutex_unlock(&ddata->lock);
+ return 0;
+err:
+ in->ops.dsi->bus_unlock(in);
+ mutex_unlock(&ddata->lock);
+ return r;
+}
+
+static int dsicm_sync(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(&ddata->pdev->dev, "sync\n");
+
+ mutex_lock(&ddata->lock);
+ in->ops.dsi->bus_lock(in);
+ in->ops.dsi->bus_unlock(in);
+ mutex_unlock(&ddata->lock);
+
+ dev_dbg(&ddata->pdev->dev, "sync done\n");
+
+ return 0;
+}
+
+static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
+{
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (enable)
+ r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_TEAR_ON, 0);
+ else
+ r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);
+
+ if (!gpio_is_valid(ddata->ext_te_gpio))
+ in->ops.dsi->enable_te(in, enable);
+
+ /* possible panel bug */
+ msleep(100);
+
+ return r;
+}
+
+static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ mutex_lock(&ddata->lock);
+
+ if (ddata->te_enabled == enable)
+ goto end;
+
+ in->ops.dsi->bus_lock(in);
+
+ if (ddata->enabled) {
+ r = dsicm_wake_up(ddata);
+ if (r)
+ goto err;
+
+ r = _dsicm_enable_te(ddata, enable);
+ if (r)
+ goto err;
+ }
+
+ ddata->te_enabled = enable;
+
+ in->ops.dsi->bus_unlock(in);
+end:
+ mutex_unlock(&ddata->lock);
+
+ return 0;
+err:
+ in->ops.dsi->bus_unlock(in);
+ mutex_unlock(&ddata->lock);
+
+ return r;
+}
+
+static int dsicm_get_te(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ int r;
+
+ mutex_lock(&ddata->lock);
+ r = ddata->te_enabled;
+ mutex_unlock(&ddata->lock);
+
+ return r;
+}
+
+static int dsicm_memory_read(struct omap_dss_device *dssdev,
+ void *buf, size_t size,
+ u16 x, u16 y, u16 w, u16 h)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+ int first = 1;
+ int plen;
+ unsigned buf_used = 0;
+
+ if (size < w * h * 3)
+ return -ENOMEM;
+
+ mutex_lock(&ddata->lock);
+
+ if (!ddata->enabled) {
+ r = -ENODEV;
+ goto err1;
+ }
+
+ size = min(w * h * 3,
+ dssdev->panel.timings.x_res *
+ dssdev->panel.timings.y_res * 3);
+
+ in->ops.dsi->bus_lock(in);
+
+ r = dsicm_wake_up(ddata);
+ if (r)
+ goto err2;
+
+ /* plen 1 or 2 goes into short packet. until checksum error is fixed,
+ * use short packets. plen 32 works, but bigger packets seem to cause
+ * an error. */
+ if (size % 2)
+ plen = 1;
+ else
+ plen = 2;
+
+ dsicm_set_update_window(ddata, x, y, w, h);
+
+ r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);
+ if (r)
+ goto err2;
+
+ while (buf_used < size) {
+ u8 dcs_cmd = first ? 0x2e : 0x3e;
+ first = 0;
+
+ r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,
+ buf + buf_used, size - buf_used);
+
+ if (r < 0) {
+ dev_err(dssdev->dev, "read error\n");
+ goto err3;
+ }
+
+ buf_used += r;
+
+ if (r < plen) {
+ dev_err(&ddata->pdev->dev, "short read\n");
+ break;
+ }
+
+ if (signal_pending(current)) {
+ dev_err(&ddata->pdev->dev, "signal pending, "
+ "aborting memory read\n");
+ r = -ERESTARTSYS;
+ goto err3;
+ }
+ }
+
+ r = buf_used;
+
+err3:
+ in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);
+err2:
+ in->ops.dsi->bus_unlock(in);
+err1:
+ mutex_unlock(&ddata->lock);
+ return r;
+}
+
+static void dsicm_ulps_work(struct work_struct *work)
+{
+ struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
+ ulps_work.work);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ mutex_lock(&ddata->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !ddata->enabled) {
+ mutex_unlock(&ddata->lock);
+ return;
+ }
+
+ in->ops.dsi->bus_lock(in);
+
+ dsicm_enter_ulps(ddata);
+
+ in->ops.dsi->bus_unlock(in);
+ mutex_unlock(&ddata->lock);
+}
+
+static struct omap_dss_driver dsicm_ops = {
+ .connect = dsicm_connect,
+ .disconnect = dsicm_disconnect,
+
+ .enable = dsicm_enable,
+ .disable = dsicm_disable,
+
+ .update = dsicm_update,
+ .sync = dsicm_sync,
+
+ .get_resolution = dsicm_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+ .enable_te = dsicm_enable_te,
+ .get_te = dsicm_get_te,
+
+ .memory_read = dsicm_memory_read,
+};
+
+static int dsicm_probe_pdata(struct platform_device *pdev)
+{
+ const struct panel_dsicm_platform_data *pdata;
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return -EPROBE_DEFER;
+ }
+ ddata->in = in;
+
+ ddata->reset_gpio = pdata->reset_gpio;
+
+ if (pdata->use_ext_te)
+ ddata->ext_te_gpio = pdata->ext_te_gpio;
+ else
+ ddata->ext_te_gpio = -1;
+
+ ddata->ulps_timeout = pdata->ulps_timeout;
+
+ ddata->use_dsi_backlight = pdata->use_dsi_backlight;
+
+ ddata->pin_config = pdata->pin_config;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int dsicm_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *in;
+ int gpio;
+
+ gpio = of_get_named_gpio(node, "reset-gpios", 0);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(&pdev->dev, "failed to parse reset gpio\n");
+ return gpio;
+ }
+ ddata->reset_gpio = gpio;
+
+ gpio = of_get_named_gpio(node, "te-gpios", 0);
+ if (gpio_is_valid(gpio) || gpio == -ENOENT) {
+ ddata->ext_te_gpio = gpio;
+ } else {
+ dev_err(&pdev->dev, "failed to parse TE gpio\n");
+ return gpio;
+ }
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ /* TODO: ulps, backlight */
+
+ return 0;
+}
+
+static int dsicm_probe(struct platform_device *pdev)
+{
+ struct backlight_properties props;
+ struct panel_drv_data *ddata;
+ struct backlight_device *bldev = NULL;
+ struct device *dev = &pdev->dev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ dev_dbg(dev, "probe\n");
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+ ddata->pdev = pdev;
+
+ if (dev_get_platdata(dev)) {
+ r = dsicm_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = dsicm_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ ddata->timings.x_res = 864;
+ ddata->timings.y_res = 480;
+ ddata->timings.pixelclock = 864 * 480 * 60;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = dev;
+ dssdev->driver = &dsicm_ops;
+ dssdev->panel.timings = ddata->timings;
+ dssdev->type = OMAP_DISPLAY_TYPE_DSI;
+ dssdev->owner = THIS_MODULE;
+
+ dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
+ dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
+ OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ mutex_init(&ddata->lock);
+
+ atomic_set(&ddata->do_update, 0);
+
+ if (gpio_is_valid(ddata->reset_gpio)) {
+ r = devm_gpio_request_one(dev, ddata->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "taal rst");
+ if (r) {
+ dev_err(dev, "failed to request reset gpio\n");
+ return r;
+ }
+ }
+
+ if (gpio_is_valid(ddata->ext_te_gpio)) {
+ r = devm_gpio_request_one(dev, ddata->ext_te_gpio,
+ GPIOF_IN, "taal irq");
+ if (r) {
+ dev_err(dev, "GPIO request failed\n");
+ return r;
+ }
+
+ r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio),
+ dsicm_te_isr,
+ IRQF_TRIGGER_RISING,
+ "taal vsync", ddata);
+
+ if (r) {
+ dev_err(dev, "IRQ request failed\n");
+ return r;
+ }
+
+ INIT_DEFERRABLE_WORK(&ddata->te_timeout_work,
+ dsicm_te_timeout_work_callback);
+
+ dev_dbg(dev, "Using GPIO TE\n");
+ }
+
+ ddata->workqueue = create_singlethread_workqueue("dsicm_wq");
+ if (ddata->workqueue == NULL) {
+ dev_err(dev, "can't create workqueue\n");
+ return -ENOMEM;
+ }
+ INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);
+
+ dsicm_hw_reset(ddata);
+
+ if (ddata->use_dsi_backlight) {
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 255;
+
+ props.type = BACKLIGHT_RAW;
+ bldev = backlight_device_register(dev_name(dev),
+ dev, ddata, &dsicm_bl_ops, &props);
+ if (IS_ERR(bldev)) {
+ r = PTR_ERR(bldev);
+ goto err_bl;
+ }
+
+ ddata->bldev = bldev;
+
+ bldev->props.fb_blank = FB_BLANK_UNBLANK;
+ bldev->props.power = FB_BLANK_UNBLANK;
+ bldev->props.brightness = 255;
+
+ dsicm_bl_update_status(bldev);
+ }
+
+ r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
+ if (r) {
+ dev_err(dev, "failed to create sysfs files\n");
+ goto err_sysfs_create;
+ }
+
+ return 0;
+
+err_sysfs_create:
+ if (bldev != NULL)
+ backlight_device_unregister(bldev);
+err_bl:
+ destroy_workqueue(ddata->workqueue);
+err_reg:
+ return r;
+}
+
+static int __exit dsicm_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct backlight_device *bldev;
+
+ dev_dbg(&pdev->dev, "remove\n");
+
+ omapdss_unregister_display(dssdev);
+
+ dsicm_disable(dssdev);
+ dsicm_disconnect(dssdev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);
+
+ bldev = ddata->bldev;
+ if (bldev != NULL) {
+ bldev->props.power = FB_BLANK_POWERDOWN;
+ dsicm_bl_update_status(bldev);
+ backlight_device_unregister(bldev);
+ }
+
+ omap_dss_put_device(ddata->in);
+
+ dsicm_cancel_ulps_work(ddata);
+ destroy_workqueue(ddata->workqueue);
+
+ /* reset, to be sure that the panel is in a valid state */
+ dsicm_hw_reset(ddata);
+
+ return 0;
+}
+
+static const struct of_device_id dsicm_of_match[] = {
+ { .compatible = "omapdss,panel-dsi-cm", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, dsicm_of_match);
+
+static struct platform_driver dsicm_driver = {
+ .probe = dsicm_probe,
+ .remove = __exit_p(dsicm_remove),
+ .driver = {
+ .name = "panel-dsi-cm",
+ .of_match_table = dsicm_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(dsicm_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c
new file mode 100644
index 000000000000..18eb60e9c9ec
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c
@@ -0,0 +1,404 @@
+/*
+ * LG.Philips LB035Q02 LCD Panel driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ * Based on a driver by: Steve Sakoman <steve@sakoman.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/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+static struct omap_video_timings lb035q02_timings = {
+ .x_res = 320,
+ .y_res = 240,
+
+ .pixelclock = 6500000,
+
+ .hsw = 2,
+ .hfp = 20,
+ .hbp = 68,
+
+ .vsw = 2,
+ .vfp = 4,
+ .vbp = 18,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+};
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct spi_device *spi;
+
+ int data_lines;
+
+ struct omap_video_timings videomode;
+
+ /* used for non-DT boot, to be removed */
+ int backlight_gpio;
+
+ struct gpio_desc *enable_gpio;
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val)
+{
+ struct spi_message msg;
+ struct spi_transfer index_xfer = {
+ .len = 3,
+ .cs_change = 1,
+ };
+ struct spi_transfer value_xfer = {
+ .len = 3,
+ };
+ u8 buffer[16];
+
+ spi_message_init(&msg);
+
+ /* register index */
+ buffer[0] = 0x70;
+ buffer[1] = 0x00;
+ buffer[2] = reg & 0x7f;
+ index_xfer.tx_buf = buffer;
+ spi_message_add_tail(&index_xfer, &msg);
+
+ /* register value */
+ buffer[4] = 0x72;
+ buffer[5] = val >> 8;
+ buffer[6] = val;
+ value_xfer.tx_buf = buffer + 4;
+ spi_message_add_tail(&value_xfer, &msg);
+
+ return spi_sync(spi, &msg);
+}
+
+static void init_lb035q02_panel(struct spi_device *spi)
+{
+ /* Init sequence from page 28 of the lb035q02 spec */
+ lb035q02_write_reg(spi, 0x01, 0x6300);
+ lb035q02_write_reg(spi, 0x02, 0x0200);
+ lb035q02_write_reg(spi, 0x03, 0x0177);
+ lb035q02_write_reg(spi, 0x04, 0x04c7);
+ lb035q02_write_reg(spi, 0x05, 0xffc0);
+ lb035q02_write_reg(spi, 0x06, 0xe806);
+ lb035q02_write_reg(spi, 0x0a, 0x4008);
+ lb035q02_write_reg(spi, 0x0b, 0x0000);
+ lb035q02_write_reg(spi, 0x0d, 0x0030);
+ lb035q02_write_reg(spi, 0x0e, 0x2800);
+ lb035q02_write_reg(spi, 0x0f, 0x0000);
+ lb035q02_write_reg(spi, 0x16, 0x9f80);
+ lb035q02_write_reg(spi, 0x17, 0x0a0f);
+ lb035q02_write_reg(spi, 0x1e, 0x00c1);
+ lb035q02_write_reg(spi, 0x30, 0x0300);
+ lb035q02_write_reg(spi, 0x31, 0x0007);
+ lb035q02_write_reg(spi, 0x32, 0x0000);
+ lb035q02_write_reg(spi, 0x33, 0x0000);
+ lb035q02_write_reg(spi, 0x34, 0x0707);
+ lb035q02_write_reg(spi, 0x35, 0x0004);
+ lb035q02_write_reg(spi, 0x36, 0x0302);
+ lb035q02_write_reg(spi, 0x37, 0x0202);
+ lb035q02_write_reg(spi, 0x3a, 0x0a0d);
+ lb035q02_write_reg(spi, 0x3b, 0x0806);
+}
+
+static int lb035q02_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ init_lb035q02_panel(ddata->spi);
+
+ return 0;
+}
+
+static void lb035q02_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int lb035q02_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
+
+ if (gpio_is_valid(ddata->backlight_gpio))
+ gpio_set_value_cansleep(ddata->backlight_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void lb035q02_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
+
+ if (gpio_is_valid(ddata->backlight_gpio))
+ gpio_set_value_cansleep(ddata->backlight_gpio, 0);
+
+ in->ops.dpi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void lb035q02_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void lb035q02_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int lb035q02_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver lb035q02_ops = {
+ .connect = lb035q02_connect,
+ .disconnect = lb035q02_disconnect,
+
+ .enable = lb035q02_enable,
+ .disable = lb035q02_disable,
+
+ .set_timings = lb035q02_set_timings,
+ .get_timings = lb035q02_get_timings,
+ .check_timings = lb035q02_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+};
+
+static int lb035q02_probe_pdata(struct spi_device *spi)
+{
+ const struct panel_lb035q02_platform_data *pdata;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev, *in;
+ int r;
+
+ pdata = dev_get_platdata(&spi->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&spi->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio,
+ GPIOF_OUT_INIT_LOW, "panel enable");
+ if (r)
+ goto err_gpio;
+
+ ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
+
+ ddata->backlight_gpio = pdata->backlight_gpio;
+
+ return 0;
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int lb035q02_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+ struct gpio_desc *gpio;
+
+ gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(gpio)) {
+ dev_err(&spi->dev, "failed to parse enable gpio\n");
+ return PTR_ERR(gpio);
+ }
+
+ ddata->enable_gpio = gpio;
+
+ ddata->backlight_gpio = -ENOENT;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int lb035q02_panel_spi_probe(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, ddata);
+
+ ddata->spi = spi;
+
+ if (dev_get_platdata(&spi->dev)) {
+ r = lb035q02_probe_pdata(spi);
+ if (r)
+ return r;
+ } else if (spi->dev.of_node) {
+ r = lb035q02_probe_of(spi);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->backlight_gpio)) {
+ r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio,
+ GPIOF_OUT_INIT_LOW, "panel backlight");
+ if (r)
+ goto err_gpio;
+ }
+
+ ddata->videomode = lb035q02_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &spi->dev;
+ dssdev->driver = &lb035q02_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+ dssdev->phy.dpi.data_lines = ddata->data_lines;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&spi->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int lb035q02_panel_spi_remove(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(dssdev);
+
+ lb035q02_disable(dssdev);
+ lb035q02_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id lb035q02_of_match[] = {
+ { .compatible = "omapdss,lgphilips,lb035q02", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, lb035q02_of_match);
+
+static struct spi_driver lb035q02_spi_driver = {
+ .probe = lb035q02_panel_spi_probe,
+ .remove = lb035q02_panel_spi_remove,
+ .driver = {
+ .name = "panel_lgphilips_lb035q02",
+ .of_match_table = lb035q02_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_spi_driver(lb035q02_spi_driver);
+
+MODULE_ALIAS("spi:lgphilips,lb035q02");
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c
new file mode 100644
index 000000000000..8a928c9a2fc9
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c
@@ -0,0 +1,437 @@
+/*
+ * NEC NL8048HL11 Panel driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct omap_video_timings videomode;
+
+ int data_lines;
+
+ int res_gpio;
+ int qvga_gpio;
+
+ struct spi_device *spi;
+};
+
+#define LCD_XRES 800
+#define LCD_YRES 480
+/*
+ * NEC PIX Clock Ratings
+ * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
+ */
+#define LCD_PIXEL_CLOCK 23800000
+
+static const struct {
+ unsigned char addr;
+ unsigned char dat;
+} nec_8048_init_seq[] = {
+ { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
+ { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
+ { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
+ { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
+ { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
+ { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
+ { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
+ { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
+ { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
+ { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
+ { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
+ { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
+ { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
+ { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
+ { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
+ { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
+ { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
+ { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
+};
+
+static const struct omap_video_timings nec_8048_panel_timings = {
+ .x_res = LCD_XRES,
+ .y_res = LCD_YRES,
+ .pixelclock = LCD_PIXEL_CLOCK,
+ .hfp = 6,
+ .hsw = 1,
+ .hbp = 4,
+ .vfp = 3,
+ .vsw = 1,
+ .vbp = 4,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
+ unsigned char reg_data)
+{
+ int ret = 0;
+ unsigned int cmd = 0, data = 0;
+
+ cmd = 0x0000 | reg_addr; /* register address write */
+ data = 0x0100 | reg_data; /* register data write */
+ data = (cmd << 16) | data;
+
+ ret = spi_write(spi, (unsigned char *)&data, 4);
+ if (ret)
+ pr_err("error in spi_write %x\n", data);
+
+ return ret;
+}
+
+static int init_nec_8048_wvga_lcd(struct spi_device *spi)
+{
+ unsigned int i;
+ /* Initialization Sequence */
+ /* nec_8048_spi_send(spi, REG, VAL) */
+ for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
+ nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
+ nec_8048_init_seq[i].dat);
+ udelay(20);
+ nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
+ nec_8048_init_seq[i].dat);
+ return 0;
+}
+
+static int nec_8048_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void nec_8048_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int nec_8048_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ if (gpio_is_valid(ddata->res_gpio))
+ gpio_set_value_cansleep(ddata->res_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void nec_8048_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (gpio_is_valid(ddata->res_gpio))
+ gpio_set_value_cansleep(ddata->res_gpio, 0);
+
+ in->ops.dpi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void nec_8048_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void nec_8048_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int nec_8048_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver nec_8048_ops = {
+ .connect = nec_8048_connect,
+ .disconnect = nec_8048_disconnect,
+
+ .enable = nec_8048_enable,
+ .disable = nec_8048_disable,
+
+ .set_timings = nec_8048_set_timings,
+ .get_timings = nec_8048_get_timings,
+ .check_timings = nec_8048_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+};
+
+
+static int nec_8048_probe_pdata(struct spi_device *spi)
+{
+ const struct panel_nec_nl8048hl11_platform_data *pdata;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&spi->dev);
+
+ ddata->qvga_gpio = pdata->qvga_gpio;
+ ddata->res_gpio = pdata->res_gpio;
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&spi->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int nec_8048_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+ int gpio;
+
+ gpio = of_get_named_gpio(node, "reset-gpios", 0);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(&spi->dev, "failed to parse enable gpio\n");
+ return gpio;
+ }
+ ddata->res_gpio = gpio;
+
+ /* XXX the panel spec doesn't mention any QVGA pin?? */
+ ddata->qvga_gpio = -ENOENT;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int nec_8048_probe(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 32;
+
+ r = spi_setup(spi);
+ if (r < 0) {
+ dev_err(&spi->dev, "spi_setup failed: %d\n", r);
+ return r;
+ }
+
+ init_nec_8048_wvga_lcd(spi);
+
+ ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, ddata);
+
+ ddata->spi = spi;
+
+ if (dev_get_platdata(&spi->dev)) {
+ r = nec_8048_probe_pdata(spi);
+ if (r)
+ return r;
+ } else if (spi->dev.of_node) {
+ r = nec_8048_probe_of(spi);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->qvga_gpio)) {
+ r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
+ GPIOF_OUT_INIT_HIGH, "lcd QVGA");
+ if (r)
+ goto err_gpio;
+ }
+
+ if (gpio_is_valid(ddata->res_gpio)) {
+ r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd RES");
+ if (r)
+ goto err_gpio;
+ }
+
+ ddata->videomode = nec_8048_panel_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &spi->dev;
+ dssdev->driver = &nec_8048_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&spi->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int nec_8048_remove(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(&ddata->spi->dev, "%s\n", __func__);
+
+ omapdss_unregister_display(dssdev);
+
+ nec_8048_disable(dssdev);
+ nec_8048_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int nec_8048_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ nec_8048_spi_send(spi, 2, 0x01);
+ mdelay(40);
+
+ return 0;
+}
+
+static int nec_8048_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ /* reinitialize the panel */
+ spi_setup(spi);
+ nec_8048_spi_send(spi, 2, 0x00);
+ init_nec_8048_wvga_lcd(spi);
+
+ return 0;
+}
+static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend,
+ nec_8048_resume);
+#define NEC_8048_PM_OPS (&nec_8048_pm_ops)
+#else
+#define NEC_8048_PM_OPS NULL
+#endif
+
+static const struct of_device_id nec_8048_of_match[] = {
+ { .compatible = "omapdss,nec,nl8048hl11", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, nec_8048_of_match);
+
+static struct spi_driver nec_8048_driver = {
+ .driver = {
+ .name = "panel-nec-nl8048hl11",
+ .pm = NEC_8048_PM_OPS,
+ .of_match_table = nec_8048_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = nec_8048_probe,
+ .remove = nec_8048_remove,
+};
+
+module_spi_driver(nec_8048_driver);
+
+MODULE_ALIAS("spi:nec,nl8048hl11");
+MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
+MODULE_DESCRIPTION("NEC-NL8048HL11 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c
new file mode 100644
index 000000000000..abfd1f6e3327
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c
@@ -0,0 +1,415 @@
+/*
+ * LCD panel driver for Sharp LS037V7DW01
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/delay.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+ struct regulator *vcc;
+
+ int data_lines;
+
+ struct omap_video_timings videomode;
+
+ struct gpio_desc *resb_gpio; /* low = reset active min 20 us */
+ struct gpio_desc *ini_gpio; /* high = power on */
+ struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */
+ struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */
+ struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */
+};
+
+static const struct omap_video_timings sharp_ls_timings = {
+ .x_res = 480,
+ .y_res = 640,
+
+ .pixelclock = 19200000,
+
+ .hsw = 2,
+ .hfp = 1,
+ .hbp = 28,
+
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 1,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int sharp_ls_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void sharp_ls_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int sharp_ls_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ if (ddata->vcc) {
+ r = regulator_enable(ddata->vcc);
+ if (r != 0)
+ return r;
+ }
+
+ r = in->ops.dpi->enable(in);
+ if (r) {
+ regulator_disable(ddata->vcc);
+ return r;
+ }
+
+ /* wait couple of vsyncs until enabling the LCD */
+ msleep(50);
+
+ if (ddata->resb_gpio)
+ gpiod_set_value_cansleep(ddata->resb_gpio, 1);
+
+ if (ddata->ini_gpio)
+ gpiod_set_value_cansleep(ddata->ini_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void sharp_ls_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (ddata->ini_gpio)
+ gpiod_set_value_cansleep(ddata->ini_gpio, 0);
+
+ if (ddata->resb_gpio)
+ gpiod_set_value_cansleep(ddata->resb_gpio, 0);
+
+ /* wait at least 5 vsyncs after disabling the LCD */
+
+ msleep(100);
+
+ in->ops.dpi->disable(in);
+
+ if (ddata->vcc)
+ regulator_disable(ddata->vcc);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver sharp_ls_ops = {
+ .connect = sharp_ls_connect,
+ .disconnect = sharp_ls_disconnect,
+
+ .enable = sharp_ls_enable,
+ .disable = sharp_ls_disable,
+
+ .set_timings = sharp_ls_set_timings,
+ .get_timings = sharp_ls_get_timings,
+ .check_timings = sharp_ls_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+};
+
+static int sharp_ls_get_gpio(struct device *dev, int gpio, unsigned long flags,
+ char *desc, struct gpio_desc **gpiod)
+{
+ struct gpio_desc *gd;
+ int r;
+
+ *gpiod = NULL;
+
+ r = devm_gpio_request_one(dev, gpio, flags, desc);
+ if (r)
+ return r == -ENOENT ? 0 : r;
+
+ gd = gpio_to_desc(gpio);
+ if (IS_ERR(gd))
+ return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd);
+
+ *gpiod = gd;
+ return 0;
+}
+
+static int sharp_ls_probe_pdata(struct platform_device *pdev)
+{
+ const struct panel_sharp_ls037v7dw01_platform_data *pdata;
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev, *in;
+ int r;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->mo_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd MO", &ddata->mo_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->lr_gpio, GPIOF_OUT_INIT_HIGH,
+ "lcd LR", &ddata->lr_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->ud_gpio, GPIOF_OUT_INIT_HIGH,
+ "lcd UD", &ddata->ud_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->resb_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd RESB", &ddata->resb_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->ini_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd INI", &ddata->ini_gpio);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
+ const char *desc, struct gpio_desc **gpiod)
+{
+ struct gpio_desc *gd;
+
+ *gpiod = NULL;
+
+ gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW);
+ if (IS_ERR(gd))
+ return PTR_ERR(gd);
+
+ *gpiod = gd;
+ return 0;
+}
+
+static int sharp_ls_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ int r;
+
+ ddata->vcc = devm_regulator_get(&pdev->dev, "envdd");
+ if (IS_ERR(ddata->vcc)) {
+ dev_err(&pdev->dev, "failed to get regulator\n");
+ return PTR_ERR(ddata->vcc);
+ }
+
+ /* lcd INI */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio);
+ if (r)
+ return r;
+
+ /* lcd RESB */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio);
+ if (r)
+ return r;
+
+ /* lcd MO */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio);
+ if (r)
+ return r;
+
+ /* lcd LR */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio);
+ if (r)
+ return r;
+
+ /* lcd UD */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio);
+ if (r)
+ return r;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int sharp_ls_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = sharp_ls_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else if (pdev->dev.of_node) {
+ r = sharp_ls_probe_of(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ ddata->videomode = sharp_ls_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &pdev->dev;
+ dssdev->driver = &sharp_ls_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+ dssdev->phy.dpi.data_lines = ddata->data_lines;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit sharp_ls_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(dssdev);
+
+ sharp_ls_disable(dssdev);
+ sharp_ls_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id sharp_ls_of_match[] = {
+ { .compatible = "omapdss,sharp,ls037v7dw01", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sharp_ls_of_match);
+
+static struct platform_driver sharp_ls_driver = {
+ .probe = sharp_ls_probe,
+ .remove = __exit_p(sharp_ls_remove),
+ .driver = {
+ .name = "panel-sharp-ls037v7dw01",
+ .of_match_table = sharp_ls_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(sharp_ls_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
new file mode 100644
index 000000000000..31efcca801bd
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
@@ -0,0 +1,917 @@
+/*
+ * Sony ACX565AKM LCD Panel driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Original Driver Author: Imre Deak <imre.deak@nokia.com>
+ * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+#define MIPID_CMD_READ_DISP_ID 0x04
+#define MIPID_CMD_READ_RED 0x06
+#define MIPID_CMD_READ_GREEN 0x07
+#define MIPID_CMD_READ_BLUE 0x08
+#define MIPID_CMD_READ_DISP_STATUS 0x09
+#define MIPID_CMD_RDDSDR 0x0F
+#define MIPID_CMD_SLEEP_IN 0x10
+#define MIPID_CMD_SLEEP_OUT 0x11
+#define MIPID_CMD_DISP_OFF 0x28
+#define MIPID_CMD_DISP_ON 0x29
+#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
+#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
+#define MIPID_CMD_WRITE_CTRL_DISP 0x53
+
+#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
+#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
+#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
+#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
+
+#define MIPID_CMD_READ_CTRL_DISP 0x54
+#define MIPID_CMD_WRITE_CABC 0x55
+#define MIPID_CMD_READ_CABC 0x56
+
+#define MIPID_VER_LPH8923 3
+#define MIPID_VER_LS041Y3 4
+#define MIPID_VER_L4F00311 8
+#define MIPID_VER_ACX565AKM 9
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ int reset_gpio;
+ int datapairs;
+
+ struct omap_video_timings videomode;
+
+ char *name;
+ int enabled;
+ int model;
+ int revision;
+ u8 display_id[3];
+ unsigned has_bc:1;
+ unsigned has_cabc:1;
+ unsigned cabc_mode;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+
+ struct spi_device *spi;
+ struct mutex mutex;
+
+ struct backlight_device *bl_dev;
+};
+
+static const struct omap_video_timings acx565akm_panel_timings = {
+ .x_res = 800,
+ .y_res = 480,
+ .pixelclock = 24000000,
+ .hfp = 28,
+ .hsw = 4,
+ .hbp = 24,
+ .vfp = 3,
+ .vsw = 3,
+ .vbp = 4,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd,
+ const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct spi_message m;
+ struct spi_transfer *x, xfer[5];
+ int r;
+
+ BUG_ON(ddata->spi == NULL);
+
+ spi_message_init(&m);
+
+ memset(xfer, 0, sizeof(xfer));
+ x = &xfer[0];
+
+ cmd &= 0xff;
+ x->tx_buf = &cmd;
+ x->bits_per_word = 9;
+ x->len = 2;
+
+ if (rlen > 1 && wlen == 0) {
+ /*
+ * Between the command and the response data there is a
+ * dummy clock cycle. Add an extra bit after the command
+ * word to account for this.
+ */
+ x->bits_per_word = 10;
+ cmd <<= 1;
+ }
+ spi_message_add_tail(x, &m);
+
+ if (wlen) {
+ x++;
+ x->tx_buf = wbuf;
+ x->len = wlen;
+ x->bits_per_word = 9;
+ spi_message_add_tail(x, &m);
+ }
+
+ if (rlen) {
+ x++;
+ x->rx_buf = rbuf;
+ x->len = rlen;
+ spi_message_add_tail(x, &m);
+ }
+
+ r = spi_sync(ddata->spi, &m);
+ if (r < 0)
+ dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r);
+}
+
+static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd)
+{
+ acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void acx565akm_write(struct panel_drv_data *ddata,
+ int reg, const u8 *buf, int len)
+{
+ acx565akm_transfer(ddata, reg, buf, len, NULL, 0);
+}
+
+static inline void acx565akm_read(struct panel_drv_data *ddata,
+ int reg, u8 *buf, int len)
+{
+ acx565akm_transfer(ddata, reg, NULL, 0, buf, len);
+}
+
+static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
+{
+ ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct panel_drv_data *ddata)
+{
+ unsigned long wait = ddata->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+static void set_sleep_mode(struct panel_drv_data *ddata, int on)
+{
+ int cmd;
+
+ if (on)
+ cmd = MIPID_CMD_SLEEP_IN;
+ else
+ cmd = MIPID_CMD_SLEEP_OUT;
+ /*
+ * We have to keep 120msec between sleep in/out commands.
+ * (8.2.15, 8.2.16).
+ */
+ hw_guard_wait(ddata);
+ acx565akm_cmd(ddata, cmd);
+ hw_guard_start(ddata, 120);
+}
+
+static void set_display_state(struct panel_drv_data *ddata, int enabled)
+{
+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+ acx565akm_cmd(ddata, cmd);
+}
+
+static int panel_enabled(struct panel_drv_data *ddata)
+{
+ u32 disp_status;
+ int enabled;
+
+ acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS,
+ (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ dev_dbg(&ddata->spi->dev,
+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ return enabled;
+}
+
+static int panel_detect(struct panel_drv_data *ddata)
+{
+ acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3);
+ dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+ ddata->display_id[0],
+ ddata->display_id[1],
+ ddata->display_id[2]);
+
+ switch (ddata->display_id[0]) {
+ case 0x10:
+ ddata->model = MIPID_VER_ACX565AKM;
+ ddata->name = "acx565akm";
+ ddata->has_bc = 1;
+ ddata->has_cabc = 1;
+ break;
+ case 0x29:
+ ddata->model = MIPID_VER_L4F00311;
+ ddata->name = "l4f00311";
+ break;
+ case 0x45:
+ ddata->model = MIPID_VER_LPH8923;
+ ddata->name = "lph8923";
+ break;
+ case 0x83:
+ ddata->model = MIPID_VER_LS041Y3;
+ ddata->name = "ls041y3";
+ break;
+ default:
+ ddata->name = "unknown";
+ dev_err(&ddata->spi->dev, "invalid display ID\n");
+ return -ENODEV;
+ }
+
+ ddata->revision = ddata->display_id[1];
+
+ dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n",
+ ddata->name, ddata->revision);
+
+ return 0;
+}
+
+/*----------------------Backlight Control-------------------------*/
+
+static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable)
+{
+ u16 ctrl;
+
+ acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
+ if (enable) {
+ ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON;
+ } else {
+ ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON);
+ }
+
+ ctrl |= 1 << 8;
+ acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
+}
+
+static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode)
+{
+ u16 cabc_ctrl;
+
+ ddata->cabc_mode = mode;
+ if (!ddata->enabled)
+ return;
+ cabc_ctrl = 0;
+ acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
+ cabc_ctrl &= ~3;
+ cabc_ctrl |= (1 << 8) | (mode & 3);
+ acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
+}
+
+static unsigned get_cabc_mode(struct panel_drv_data *ddata)
+{
+ return ddata->cabc_mode;
+}
+
+static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata)
+{
+ u8 cabc_ctrl;
+
+ acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
+ return cabc_ctrl & 3;
+}
+
+static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level)
+{
+ int bv;
+
+ bv = level | (1 << 8);
+ acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
+
+ if (level)
+ enable_backlight_ctrl(ddata, 1);
+ else
+ enable_backlight_ctrl(ddata, 0);
+}
+
+static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata)
+{
+ u8 bv;
+
+ acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
+
+ return bv;
+}
+
+
+static int acx565akm_bl_update_status(struct backlight_device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
+ int level;
+
+ dev_dbg(&ddata->spi->dev, "%s\n", __func__);
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK)
+ level = dev->props.brightness;
+ else
+ level = 0;
+
+ if (ddata->has_bc)
+ acx565akm_set_brightness(ddata, level);
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+static int acx565akm_bl_get_intensity(struct backlight_device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
+
+ dev_dbg(&dev->dev, "%s\n", __func__);
+
+ if (!ddata->has_bc)
+ return -ENODEV;
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK) {
+ if (ddata->has_bc)
+ return acx565akm_get_actual_brightness(ddata);
+ else
+ return dev->props.brightness;
+ }
+
+ return 0;
+}
+
+static int acx565akm_bl_update_status_locked(struct backlight_device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
+ int r;
+
+ mutex_lock(&ddata->mutex);
+ r = acx565akm_bl_update_status(dev);
+ mutex_unlock(&ddata->mutex);
+
+ return r;
+}
+
+static int acx565akm_bl_get_intensity_locked(struct backlight_device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
+ int r;
+
+ mutex_lock(&ddata->mutex);
+ r = acx565akm_bl_get_intensity(dev);
+ mutex_unlock(&ddata->mutex);
+
+ return r;
+}
+
+static const struct backlight_ops acx565akm_bl_ops = {
+ .get_brightness = acx565akm_bl_get_intensity_locked,
+ .update_status = acx565akm_bl_update_status_locked,
+};
+
+/*--------------------Auto Brightness control via Sysfs---------------------*/
+
+static const char * const cabc_modes[] = {
+ "off", /* always used when CABC is not supported */
+ "ui",
+ "still-image",
+ "moving-image",
+};
+
+static ssize_t show_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ const char *mode_str;
+ int mode;
+ int len;
+
+ if (!ddata->has_cabc)
+ mode = 0;
+ else
+ mode = get_cabc_mode(ddata);
+ mode_str = "unknown";
+ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
+ mode_str = cabc_modes[mode];
+ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
+
+ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
+}
+
+static ssize_t store_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
+ const char *mode_str = cabc_modes[i];
+ int cmp_len = strlen(mode_str);
+
+ if (count > 0 && buf[count - 1] == '\n')
+ count--;
+ if (count != cmp_len)
+ continue;
+
+ if (strncmp(buf, mode_str, cmp_len) == 0)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cabc_modes))
+ return -EINVAL;
+
+ if (!ddata->has_cabc && i != 0)
+ return -EINVAL;
+
+ mutex_lock(&ddata->mutex);
+ set_cabc_mode(ddata, i);
+ mutex_unlock(&ddata->mutex);
+
+ return count;
+}
+
+static ssize_t show_cabc_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ int len;
+ int i;
+
+ if (!ddata->has_cabc)
+ return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
+
+ for (i = 0, len = 0;
+ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
+ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
+ i ? " " : "", cabc_modes[i],
+ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
+
+ return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
+}
+
+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
+ show_cabc_mode, store_cabc_mode);
+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
+ show_cabc_available_modes, NULL);
+
+static struct attribute *bldev_attrs[] = {
+ &dev_attr_cabc_mode.attr,
+ &dev_attr_cabc_available_modes.attr,
+ NULL,
+};
+
+static struct attribute_group bldev_attr_group = {
+ .attrs = bldev_attrs,
+};
+
+static int acx565akm_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.sdi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void acx565akm_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.sdi->disconnect(in, dssdev);
+}
+
+static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(&ddata->spi->dev, "%s\n", __func__);
+
+ in->ops.sdi->set_timings(in, &ddata->videomode);
+
+ if (ddata->datapairs > 0)
+ in->ops.sdi->set_datapairs(in, ddata->datapairs);
+
+ r = in->ops.sdi->enable(in);
+ if (r) {
+ pr_err("%s sdi enable failed\n", __func__);
+ return r;
+ }
+
+ /*FIXME tweak me */
+ msleep(50);
+
+ if (gpio_is_valid(ddata->reset_gpio))
+ gpio_set_value(ddata->reset_gpio, 1);
+
+ if (ddata->enabled) {
+ dev_dbg(&ddata->spi->dev, "panel already enabled\n");
+ return 0;
+ }
+
+ /*
+ * We have to meet all the following delay requirements:
+ * 1. tRW: reset pulse width 10usec (7.12.1)
+ * 2. tRT: reset cancel time 5msec (7.12.1)
+ * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
+ * case (7.6.2)
+ * 4. 120msec before the sleep out command (7.12.1)
+ */
+ msleep(120);
+
+ set_sleep_mode(ddata, 0);
+ ddata->enabled = 1;
+
+ /* 5msec between sleep out and the next command. (8.2.16) */
+ usleep_range(5000, 10000);
+ set_display_state(ddata, 1);
+ set_cabc_mode(ddata, ddata->cabc_mode);
+
+ return acx565akm_bl_update_status(ddata->bl_dev);
+}
+
+static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "%s\n", __func__);
+
+ if (!ddata->enabled)
+ return;
+
+ set_display_state(ddata, 0);
+ set_sleep_mode(ddata, 1);
+ ddata->enabled = 0;
+ /*
+ * We have to provide PCLK,HS,VS signals for 2 frames (worst case
+ * ~50msec) after sending the sleep in command and asserting the
+ * reset signal. We probably could assert the reset w/o the delay
+ * but we still delay to avoid possible artifacts. (7.6.1)
+ */
+ msleep(50);
+
+ if (gpio_is_valid(ddata->reset_gpio))
+ gpio_set_value(ddata->reset_gpio, 0);
+
+ /* FIXME need to tweak this delay */
+ msleep(100);
+
+ in->ops.sdi->disable(in);
+}
+
+static int acx565akm_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ int r;
+
+ dev_dbg(dssdev->dev, "%s\n", __func__);
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ mutex_lock(&ddata->mutex);
+ r = acx565akm_panel_power_on(dssdev);
+ mutex_unlock(&ddata->mutex);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void acx565akm_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ dev_dbg(dssdev->dev, "%s\n", __func__);
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ mutex_lock(&ddata->mutex);
+ acx565akm_panel_power_off(dssdev);
+ mutex_unlock(&ddata->mutex);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void acx565akm_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.sdi->set_timings(in, timings);
+}
+
+static void acx565akm_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int acx565akm_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.sdi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver acx565akm_ops = {
+ .connect = acx565akm_connect,
+ .disconnect = acx565akm_disconnect,
+
+ .enable = acx565akm_enable,
+ .disable = acx565akm_disable,
+
+ .set_timings = acx565akm_set_timings,
+ .get_timings = acx565akm_get_timings,
+ .check_timings = acx565akm_check_timings,
+
+ .get_resolution = omapdss_default_get_resolution,
+};
+
+static int acx565akm_probe_pdata(struct spi_device *spi)
+{
+ const struct panel_acx565akm_platform_data *pdata;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&spi->dev);
+
+ ddata->reset_gpio = pdata->reset_gpio;
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&spi->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+ ddata->in = in;
+
+ ddata->datapairs = pdata->datapairs;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int acx565akm_probe_of(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct device_node *np = spi->dev.of_node;
+
+ ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+
+ ddata->in = omapdss_of_find_source_for_first_ep(np);
+ if (IS_ERR(ddata->in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(ddata->in);
+ }
+
+ return 0;
+}
+
+static int acx565akm_probe(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ struct backlight_device *bldev;
+ int max_brightness, brightness;
+ struct backlight_properties props;
+ int r;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->mode = SPI_MODE_3;
+
+ ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, ddata);
+
+ ddata->spi = spi;
+
+ mutex_init(&ddata->mutex);
+
+ if (dev_get_platdata(&spi->dev)) {
+ r = acx565akm_probe_pdata(spi);
+ if (r)
+ return r;
+ } else if (spi->dev.of_node) {
+ r = acx565akm_probe_of(spi);
+ if (r)
+ return r;
+ } else {
+ dev_err(&spi->dev, "platform data missing!\n");
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->reset_gpio)) {
+ r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd reset");
+ if (r)
+ goto err_gpio;
+ }
+
+ if (gpio_is_valid(ddata->reset_gpio))
+ gpio_set_value(ddata->reset_gpio, 1);
+
+ /*
+ * After reset we have to wait 5 msec before the first
+ * command can be sent.
+ */
+ usleep_range(5000, 10000);
+
+ ddata->enabled = panel_enabled(ddata);
+
+ r = panel_detect(ddata);
+
+ if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio))
+ gpio_set_value(ddata->reset_gpio, 0);
+
+ if (r) {
+ dev_err(&spi->dev, "%s panel detect error\n", __func__);
+ goto err_detect;
+ }
+
+ memset(&props, 0, sizeof(props));
+ props.fb_blank = FB_BLANK_UNBLANK;
+ props.power = FB_BLANK_UNBLANK;
+ props.type = BACKLIGHT_RAW;
+
+ bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
+ ddata, &acx565akm_bl_ops, &props);
+ if (IS_ERR(bldev)) {
+ r = PTR_ERR(bldev);
+ goto err_reg_bl;
+ }
+ ddata->bl_dev = bldev;
+ if (ddata->has_cabc) {
+ r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
+ if (r) {
+ dev_err(&bldev->dev,
+ "%s failed to create sysfs files\n", __func__);
+ goto err_sysfs;
+ }
+ ddata->cabc_mode = get_hw_cabc_mode(ddata);
+ }
+
+ max_brightness = 255;
+
+ if (ddata->has_bc)
+ brightness = acx565akm_get_actual_brightness(ddata);
+ else
+ brightness = 0;
+
+ bldev->props.max_brightness = max_brightness;
+ bldev->props.brightness = brightness;
+
+ acx565akm_bl_update_status(bldev);
+
+
+ ddata->videomode = acx565akm_panel_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &spi->dev;
+ dssdev->driver = &acx565akm_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_SDI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&spi->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+ sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group);
+err_sysfs:
+ backlight_device_unregister(bldev);
+err_reg_bl:
+err_detect:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int acx565akm_remove(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(&ddata->spi->dev, "%s\n", __func__);
+
+ sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
+ backlight_device_unregister(ddata->bl_dev);
+
+ omapdss_unregister_display(dssdev);
+
+ acx565akm_disable(dssdev);
+ acx565akm_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id acx565akm_of_match[] = {
+ { .compatible = "omapdss,sony,acx565akm", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, acx565akm_of_match);
+
+static struct spi_driver acx565akm_driver = {
+ .driver = {
+ .name = "acx565akm",
+ .of_match_table = acx565akm_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = acx565akm_probe,
+ .remove = acx565akm_remove,
+};
+
+module_spi_driver(acx565akm_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("acx565akm LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c
new file mode 100644
index 000000000000..4d657f3ab679
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c
@@ -0,0 +1,511 @@
+/*
+ * Toppoly TD028TTEC1 panel support
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Neo 1973 code (jbt6k74.c):
+ * Copyright (C) 2006-2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * Ported and adapted from Neo 1973 U-Boot by:
+ * H. Nikolaus Schaller <hns@goldelico.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ int data_lines;
+
+ struct omap_video_timings videomode;
+
+ struct spi_device *spi_dev;
+};
+
+static struct omap_video_timings td028ttec1_panel_timings = {
+ .x_res = 480,
+ .y_res = 640,
+ .pixelclock = 22153000,
+ .hfp = 24,
+ .hsw = 8,
+ .hbp = 8,
+ .vfp = 4,
+ .vsw = 2,
+ .vbp = 2,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+};
+
+#define JBT_COMMAND 0x000
+#define JBT_DATA 0x100
+
+static int jbt_ret_write_0(struct panel_drv_data *ddata, u8 reg)
+{
+ int rc;
+ u16 tx_buf = JBT_COMMAND | reg;
+
+ rc = spi_write(ddata->spi_dev, (u8 *)&tx_buf,
+ 1*sizeof(u16));
+ if (rc != 0)
+ dev_err(&ddata->spi_dev->dev,
+ "jbt_ret_write_0 spi_write ret %d\n", rc);
+
+ return rc;
+}
+
+static int jbt_reg_write_1(struct panel_drv_data *ddata, u8 reg, u8 data)
+{
+ int rc;
+ u16 tx_buf[2];
+
+ tx_buf[0] = JBT_COMMAND | reg;
+ tx_buf[1] = JBT_DATA | data;
+ rc = spi_write(ddata->spi_dev, (u8 *)tx_buf,
+ 2*sizeof(u16));
+ if (rc != 0)
+ dev_err(&ddata->spi_dev->dev,
+ "jbt_reg_write_1 spi_write ret %d\n", rc);
+
+ return rc;
+}
+
+static int jbt_reg_write_2(struct panel_drv_data *ddata, u8 reg, u16 data)
+{
+ int rc;
+ u16 tx_buf[3];
+
+ tx_buf[0] = JBT_COMMAND | reg;
+ tx_buf[1] = JBT_DATA | (data >> 8);
+ tx_buf[2] = JBT_DATA | (data & 0xff);
+
+ rc = spi_write(ddata->spi_dev, (u8 *)tx_buf,
+ 3*sizeof(u16));
+
+ if (rc != 0)
+ dev_err(&ddata->spi_dev->dev,
+ "jbt_reg_write_2 spi_write ret %d\n", rc);
+
+ return rc;
+}
+
+enum jbt_register {
+ JBT_REG_SLEEP_IN = 0x10,
+ JBT_REG_SLEEP_OUT = 0x11,
+
+ JBT_REG_DISPLAY_OFF = 0x28,
+ JBT_REG_DISPLAY_ON = 0x29,
+
+ JBT_REG_RGB_FORMAT = 0x3a,
+ JBT_REG_QUAD_RATE = 0x3b,
+
+ JBT_REG_POWER_ON_OFF = 0xb0,
+ JBT_REG_BOOSTER_OP = 0xb1,
+ JBT_REG_BOOSTER_MODE = 0xb2,
+ JBT_REG_BOOSTER_FREQ = 0xb3,
+ JBT_REG_OPAMP_SYSCLK = 0xb4,
+ JBT_REG_VSC_VOLTAGE = 0xb5,
+ JBT_REG_VCOM_VOLTAGE = 0xb6,
+ JBT_REG_EXT_DISPL = 0xb7,
+ JBT_REG_OUTPUT_CONTROL = 0xb8,
+ JBT_REG_DCCLK_DCEV = 0xb9,
+ JBT_REG_DISPLAY_MODE1 = 0xba,
+ JBT_REG_DISPLAY_MODE2 = 0xbb,
+ JBT_REG_DISPLAY_MODE = 0xbc,
+ JBT_REG_ASW_SLEW = 0xbd,
+ JBT_REG_DUMMY_DISPLAY = 0xbe,
+ JBT_REG_DRIVE_SYSTEM = 0xbf,
+
+ JBT_REG_SLEEP_OUT_FR_A = 0xc0,
+ JBT_REG_SLEEP_OUT_FR_B = 0xc1,
+ JBT_REG_SLEEP_OUT_FR_C = 0xc2,
+ JBT_REG_SLEEP_IN_LCCNT_D = 0xc3,
+ JBT_REG_SLEEP_IN_LCCNT_E = 0xc4,
+ JBT_REG_SLEEP_IN_LCCNT_F = 0xc5,
+ JBT_REG_SLEEP_IN_LCCNT_G = 0xc6,
+
+ JBT_REG_GAMMA1_FINE_1 = 0xc7,
+ JBT_REG_GAMMA1_FINE_2 = 0xc8,
+ JBT_REG_GAMMA1_INCLINATION = 0xc9,
+ JBT_REG_GAMMA1_BLUE_OFFSET = 0xca,
+
+ JBT_REG_BLANK_CONTROL = 0xcf,
+ JBT_REG_BLANK_TH_TV = 0xd0,
+ JBT_REG_CKV_ON_OFF = 0xd1,
+ JBT_REG_CKV_1_2 = 0xd2,
+ JBT_REG_OEV_TIMING = 0xd3,
+ JBT_REG_ASW_TIMING_1 = 0xd4,
+ JBT_REG_ASW_TIMING_2 = 0xd5,
+
+ JBT_REG_HCLOCK_VGA = 0xec,
+ JBT_REG_HCLOCK_QVGA = 0xed,
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
+ dssdev->state);
+
+ /* three times command zero */
+ r |= jbt_ret_write_0(ddata, 0x00);
+ usleep_range(1000, 2000);
+ r |= jbt_ret_write_0(ddata, 0x00);
+ usleep_range(1000, 2000);
+ r |= jbt_ret_write_0(ddata, 0x00);
+ usleep_range(1000, 2000);
+
+ if (r) {
+ dev_warn(dssdev->dev, "transfer error\n");
+ goto transfer_err;
+ }
+
+ /* deep standby out */
+ r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x17);
+
+ /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */
+ r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE, 0x80);
+
+ /* Quad mode off */
+ r |= jbt_reg_write_1(ddata, JBT_REG_QUAD_RATE, 0x00);
+
+ /* AVDD on, XVDD on */
+ r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x16);
+
+ /* Output control */
+ r |= jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9);
+
+ /* Sleep mode off */
+ r |= jbt_ret_write_0(ddata, JBT_REG_SLEEP_OUT);
+
+ /* at this point we have like 50% grey */
+
+ /* initialize register set */
+ r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE1, 0x01);
+ r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE2, 0x00);
+ r |= jbt_reg_write_1(ddata, JBT_REG_RGB_FORMAT, 0x60);
+ r |= jbt_reg_write_1(ddata, JBT_REG_DRIVE_SYSTEM, 0x10);
+ r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_OP, 0x56);
+ r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_MODE, 0x33);
+ r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
+ r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
+ r |= jbt_reg_write_1(ddata, JBT_REG_OPAMP_SYSCLK, 0x02);
+ r |= jbt_reg_write_1(ddata, JBT_REG_VSC_VOLTAGE, 0x2b);
+ r |= jbt_reg_write_1(ddata, JBT_REG_VCOM_VOLTAGE, 0x40);
+ r |= jbt_reg_write_1(ddata, JBT_REG_EXT_DISPL, 0x03);
+ r |= jbt_reg_write_1(ddata, JBT_REG_DCCLK_DCEV, 0x04);
+ /*
+ * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
+ * to avoid red / blue flicker
+ */
+ r |= jbt_reg_write_1(ddata, JBT_REG_ASW_SLEW, 0x04);
+ r |= jbt_reg_write_1(ddata, JBT_REG_DUMMY_DISPLAY, 0x00);
+
+ r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11);
+ r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11);
+ r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11);
+ r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040);
+ r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0);
+ r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020);
+ r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0);
+
+ r |= jbt_reg_write_2(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533);
+ r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_FINE_2, 0x00);
+ r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00);
+ r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
+
+ r |= jbt_reg_write_2(ddata, JBT_REG_HCLOCK_VGA, 0x1f0);
+ r |= jbt_reg_write_1(ddata, JBT_REG_BLANK_CONTROL, 0x02);
+ r |= jbt_reg_write_2(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
+
+ r |= jbt_reg_write_1(ddata, JBT_REG_CKV_ON_OFF, 0x01);
+ r |= jbt_reg_write_2(ddata, JBT_REG_CKV_1_2, 0x0000);
+
+ r |= jbt_reg_write_2(ddata, JBT_REG_OEV_TIMING, 0x0d0e);
+ r |= jbt_reg_write_2(ddata, JBT_REG_ASW_TIMING_1, 0x11a4);
+ r |= jbt_reg_write_1(ddata, JBT_REG_ASW_TIMING_2, 0x0e);
+
+ r |= jbt_ret_write_0(ddata, JBT_REG_DISPLAY_ON);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+transfer_err:
+
+ return r ? -EIO : 0;
+}
+
+static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
+
+ jbt_ret_write_0(ddata, JBT_REG_DISPLAY_OFF);
+ jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
+ jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN);
+ jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
+
+ in->ops.dpi->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver td028ttec1_ops = {
+ .connect = td028ttec1_panel_connect,
+ .disconnect = td028ttec1_panel_disconnect,
+
+ .enable = td028ttec1_panel_enable,
+ .disable = td028ttec1_panel_disable,
+
+ .set_timings = td028ttec1_panel_set_timings,
+ .get_timings = td028ttec1_panel_get_timings,
+ .check_timings = td028ttec1_panel_check_timings,
+};
+
+static int td028ttec1_panel_probe_pdata(struct spi_device *spi)
+{
+ const struct panel_tpo_td028ttec1_platform_data *pdata;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&spi->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&spi->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int td028ttec1_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int td028ttec1_panel_probe(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->bits_per_word = 9;
+ spi->mode = SPI_MODE_3;
+
+ r = spi_setup(spi);
+ if (r < 0) {
+ dev_err(&spi->dev, "spi_setup failed: %d\n", r);
+ return r;
+ }
+
+ ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, ddata);
+
+ ddata->spi_dev = spi;
+
+ if (dev_get_platdata(&spi->dev)) {
+ r = td028ttec1_panel_probe_pdata(spi);
+ if (r)
+ return r;
+ } else if (spi->dev.of_node) {
+ r = td028ttec1_probe_of(spi);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ ddata->videomode = td028ttec1_panel_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &spi->dev;
+ dssdev->driver = &td028ttec1_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+ dssdev->phy.dpi.data_lines = ddata->data_lines;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&spi->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int td028ttec1_panel_remove(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__);
+
+ omapdss_unregister_display(dssdev);
+
+ td028ttec1_panel_disable(dssdev);
+ td028ttec1_panel_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id td028ttec1_of_match[] = {
+ { .compatible = "omapdss,toppoly,td028ttec1", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, td028ttec1_of_match);
+
+static struct spi_driver td028ttec1_spi_driver = {
+ .probe = td028ttec1_panel_probe,
+ .remove = td028ttec1_panel_remove,
+
+ .driver = {
+ .name = "panel-tpo-td028ttec1",
+ .of_match_table = td028ttec1_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_spi_driver(td028ttec1_spi_driver);
+
+MODULE_ALIAS("spi:toppoly,td028ttec1");
+MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
+MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c
new file mode 100644
index 000000000000..68e3b68a2920
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c
@@ -0,0 +1,686 @@
+/*
+ * TPO TD043MTEA1 Panel driver
+ *
+ * Author: Gražvydas Ignotas <notasas@gmail.com>
+ * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+#define TPO_R02_MODE(x) ((x) & 7)
+#define TPO_R02_MODE_800x480 7
+#define TPO_R02_NCLK_RISING BIT(3)
+#define TPO_R02_HSYNC_HIGH BIT(4)
+#define TPO_R02_VSYNC_HIGH BIT(5)
+
+#define TPO_R03_NSTANDBY BIT(0)
+#define TPO_R03_EN_CP_CLK BIT(1)
+#define TPO_R03_EN_VGL_PUMP BIT(2)
+#define TPO_R03_EN_PWM BIT(3)
+#define TPO_R03_DRIVING_CAP_100 BIT(4)
+#define TPO_R03_EN_PRE_CHARGE BIT(6)
+#define TPO_R03_SOFTWARE_CTL BIT(7)
+
+#define TPO_R04_NFLIP_H BIT(0)
+#define TPO_R04_NFLIP_V BIT(1)
+#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
+#define TPO_R04_VGL_FREQ_1H BIT(4)
+
+#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
+ TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
+ TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
+ TPO_R03_SOFTWARE_CTL)
+
+#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
+ TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
+
+static const u16 tpo_td043_def_gamma[12] = {
+ 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023
+};
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct omap_video_timings videomode;
+
+ int data_lines;
+
+ struct spi_device *spi;
+ struct regulator *vcc_reg;
+ int nreset_gpio;
+ u16 gamma[12];
+ u32 mode;
+ u32 hmirror:1;
+ u32 vmirror:1;
+ u32 powered_on:1;
+ u32 spi_suspended:1;
+ u32 power_on_resume:1;
+};
+
+static const struct omap_video_timings tpo_td043_timings = {
+ .x_res = 800,
+ .y_res = 480,
+
+ .pixelclock = 36000000,
+
+ .hsw = 1,
+ .hfp = 68,
+ .hbp = 214,
+
+ .vsw = 1,
+ .vfp = 39,
+ .vbp = 34,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
+{
+ struct spi_message m;
+ struct spi_transfer xfer;
+ u16 w;
+ int r;
+
+ spi_message_init(&m);
+
+ memset(&xfer, 0, sizeof(xfer));
+
+ w = ((u16)addr << 10) | (1 << 8) | data;
+ xfer.tx_buf = &w;
+ xfer.bits_per_word = 16;
+ xfer.len = 2;
+ spi_message_add_tail(&xfer, &m);
+
+ r = spi_sync(spi, &m);
+ if (r < 0)
+ dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
+ return r;
+}
+
+static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
+{
+ u8 i, val;
+
+ /* gamma bits [9:8] */
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x11, val);
+
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x12, val);
+
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x13, val);
+
+ /* gamma bits [7:0] */
+ for (val = i = 0; i < 12; i++)
+ tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
+}
+
+static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
+{
+ u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V |
+ TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
+ if (h)
+ reg4 &= ~TPO_R04_NFLIP_H;
+ if (v)
+ reg4 &= ~TPO_R04_NFLIP_V;
+
+ return tpo_td043_write(spi, 4, reg4);
+}
+
+static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
+
+ ddata->hmirror = enable;
+ return tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
+ ddata->vmirror);
+}
+
+static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
+
+ return ddata->hmirror;
+}
+
+static ssize_t tpo_td043_vmirror_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror);
+}
+
+static ssize_t tpo_td043_vmirror_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ int val;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ val = !!val;
+
+ ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val);
+ if (ret < 0)
+ return ret;
+
+ ddata->vmirror = val;
+
+ return count;
+}
+
+static ssize_t tpo_td043_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode);
+}
+
+static ssize_t tpo_td043_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ ret = kstrtol(buf, 0, &val);
+ if (ret != 0 || val & ~7)
+ return -EINVAL;
+
+ ddata->mode = val;
+
+ val |= TPO_R02_NCLK_RISING;
+ tpo_td043_write(ddata->spi, 2, val);
+
+ return count;
+}
+
+static ssize_t tpo_td043_gamma_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ ssize_t len = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) {
+ ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
+ ddata->gamma[i]);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t tpo_td043_gamma_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ unsigned int g[12];
+ int ret;
+ int i;
+
+ ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
+ &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
+ &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+
+ if (ret != 12)
+ return -EINVAL;
+
+ for (i = 0; i < 12; i++)
+ ddata->gamma[i] = g[i];
+
+ tpo_td043_write_gamma(ddata->spi, ddata->gamma);
+
+ return count;
+}
+
+static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
+ tpo_td043_vmirror_show, tpo_td043_vmirror_store);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ tpo_td043_mode_show, tpo_td043_mode_store);
+static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
+ tpo_td043_gamma_show, tpo_td043_gamma_store);
+
+static struct attribute *tpo_td043_attrs[] = {
+ &dev_attr_vmirror.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_gamma.attr,
+ NULL,
+};
+
+static struct attribute_group tpo_td043_attr_group = {
+ .attrs = tpo_td043_attrs,
+};
+
+static int tpo_td043_power_on(struct panel_drv_data *ddata)
+{
+ int r;
+
+ if (ddata->powered_on)
+ return 0;
+
+ r = regulator_enable(ddata->vcc_reg);
+ if (r != 0)
+ return r;
+
+ /* wait for panel to stabilize */
+ msleep(160);
+
+ if (gpio_is_valid(ddata->nreset_gpio))
+ gpio_set_value(ddata->nreset_gpio, 1);
+
+ tpo_td043_write(ddata->spi, 2,
+ TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING);
+ tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL);
+ tpo_td043_write(ddata->spi, 0x20, 0xf0);
+ tpo_td043_write(ddata->spi, 0x21, 0xf0);
+ tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
+ ddata->vmirror);
+ tpo_td043_write_gamma(ddata->spi, ddata->gamma);
+
+ ddata->powered_on = 1;
+ return 0;
+}
+
+static void tpo_td043_power_off(struct panel_drv_data *ddata)
+{
+ if (!ddata->powered_on)
+ return;
+
+ tpo_td043_write(ddata->spi, 3,
+ TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
+
+ if (gpio_is_valid(ddata->nreset_gpio))
+ gpio_set_value(ddata->nreset_gpio, 0);
+
+ /* wait for at least 2 vsyncs before cutting off power */
+ msleep(50);
+
+ tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_STANDBY);
+
+ regulator_disable(ddata->vcc_reg);
+
+ ddata->powered_on = 0;
+}
+
+static int tpo_td043_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void tpo_td043_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int tpo_td043_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ /*
+ * If we are resuming from system suspend, SPI clocks might not be
+ * enabled yet, so we'll program the LCD from SPI PM resume callback.
+ */
+ if (!ddata->spi_suspended) {
+ r = tpo_td043_power_on(ddata);
+ if (r) {
+ in->ops.dpi->disable(in);
+ return r;
+ }
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void tpo_td043_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ in->ops.dpi->disable(in);
+
+ if (!ddata->spi_suspended)
+ tpo_td043_power_off(ddata);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver tpo_td043_ops = {
+ .connect = tpo_td043_connect,
+ .disconnect = tpo_td043_disconnect,
+
+ .enable = tpo_td043_enable,
+ .disable = tpo_td043_disable,
+
+ .set_timings = tpo_td043_set_timings,
+ .get_timings = tpo_td043_get_timings,
+ .check_timings = tpo_td043_check_timings,
+
+ .set_mirror = tpo_td043_set_hmirror,
+ .get_mirror = tpo_td043_get_hmirror,
+
+ .get_resolution = omapdss_default_get_resolution,
+};
+
+
+static int tpo_td043_probe_pdata(struct spi_device *spi)
+{
+ const struct panel_tpo_td043mtea1_platform_data *pdata;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&spi->dev);
+
+ ddata->nreset_gpio = pdata->nreset_gpio;
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&spi->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int tpo_td043_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+ int gpio;
+
+ gpio = of_get_named_gpio(node, "reset-gpios", 0);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(&spi->dev, "failed to parse enable gpio\n");
+ return gpio;
+ }
+ ddata->nreset_gpio = gpio;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
+static int tpo_td043_probe(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->bits_per_word = 16;
+ spi->mode = SPI_MODE_0;
+
+ r = spi_setup(spi);
+ if (r < 0) {
+ dev_err(&spi->dev, "spi_setup failed: %d\n", r);
+ return r;
+ }
+
+ ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, ddata);
+
+ ddata->spi = spi;
+
+ if (dev_get_platdata(&spi->dev)) {
+ r = tpo_td043_probe_pdata(spi);
+ if (r)
+ return r;
+ } else if (spi->dev.of_node) {
+ r = tpo_td043_probe_of(spi);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ ddata->mode = TPO_R02_MODE_800x480;
+ memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma));
+
+ ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
+ if (IS_ERR(ddata->vcc_reg)) {
+ dev_err(&spi->dev, "failed to get LCD VCC regulator\n");
+ r = PTR_ERR(ddata->vcc_reg);
+ goto err_regulator;
+ }
+
+ if (gpio_is_valid(ddata->nreset_gpio)) {
+ r = devm_gpio_request_one(&spi->dev,
+ ddata->nreset_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd reset");
+ if (r < 0) {
+ dev_err(&spi->dev, "couldn't request reset GPIO\n");
+ goto err_gpio_req;
+ }
+ }
+
+ r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group);
+ if (r) {
+ dev_err(&spi->dev, "failed to create sysfs files\n");
+ goto err_sysfs;
+ }
+
+ ddata->videomode = tpo_td043_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &spi->dev;
+ dssdev->driver = &tpo_td043_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&spi->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+ sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
+err_sysfs:
+err_gpio_req:
+err_regulator:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int tpo_td043_remove(struct spi_device *spi)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(&ddata->spi->dev, "%s\n", __func__);
+
+ omapdss_unregister_display(dssdev);
+
+ tpo_td043_disable(dssdev);
+ tpo_td043_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tpo_td043_spi_suspend(struct device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", ddata);
+
+ ddata->power_on_resume = ddata->powered_on;
+ tpo_td043_power_off(ddata);
+ ddata->spi_suspended = 1;
+
+ return 0;
+}
+
+static int tpo_td043_spi_resume(struct device *dev)
+{
+ struct panel_drv_data *ddata = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(dev, "tpo_td043_spi_resume\n");
+
+ if (ddata->power_on_resume) {
+ ret = tpo_td043_power_on(ddata);
+ if (ret)
+ return ret;
+ }
+ ddata->spi_suspended = 0;
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
+ tpo_td043_spi_suspend, tpo_td043_spi_resume);
+
+static const struct of_device_id tpo_td043_of_match[] = {
+ { .compatible = "omapdss,tpo,td043mtea1", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, tpo_td043_of_match);
+
+static struct spi_driver tpo_td043_spi_driver = {
+ .driver = {
+ .name = "panel-tpo-td043mtea1",
+ .pm = &tpo_td043_spi_pm,
+ .of_match_table = tpo_td043_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = tpo_td043_probe,
+ .remove = tpo_td043_remove,
+};
+
+module_spi_driver(tpo_td043_spi_driver);
+
+MODULE_ALIAS("spi:tpo,td043mtea1");
+MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
new file mode 100644
index 000000000000..27d220212870
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
@@ -0,0 +1,129 @@
+config FB_OMAP2_DSS_INIT
+ bool
+
+config FB_OMAP2_DSS
+ tristate
+ select VIDEOMODE_HELPERS
+ select FB_OMAP2_DSS_INIT
+ select HDMI
+
+config FB_OMAP2_DSS_DEBUG
+ bool "Debug support"
+ default n
+ help
+ This enables printing of debug messages. Alternatively, debug messages
+ can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
+ appropriate flags in <debugfs>/dynamic_debug/control.
+
+config FB_OMAP2_DSS_DEBUGFS
+ bool "Debugfs filesystem support"
+ depends on DEBUG_FS
+ default n
+ help
+ This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
+ querying about clock configuration and register configuration of dss,
+ dispc, dsi, hdmi and rfbi.
+
+config FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ bool "Collect DSS IRQ statistics"
+ depends on FB_OMAP2_DSS_DEBUGFS
+ default n
+ help
+ Collect DSS IRQ statistics, printable via debugfs.
+
+ The statistics can be found from
+ <debugfs>/omapdss/dispc_irq for DISPC interrupts, and
+ <debugfs>/omapdss/dsi_irq for DSI interrupts.
+
+config FB_OMAP2_DSS_DPI
+ bool "DPI support"
+ default y
+ help
+ DPI Interface. This is the Parallel Display Interface.
+
+config FB_OMAP2_DSS_RFBI
+ bool "RFBI support"
+ depends on BROKEN
+ default n
+ help
+ MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
+ Instrument's terminology).
+
+ DBI is a bus between the host processor and a peripheral,
+ such as a display or a framebuffer chip.
+
+ See http://www.mipi.org/ for DBI specifications.
+
+config FB_OMAP2_DSS_VENC
+ bool "VENC support"
+ default y
+ help
+ OMAP Video Encoder support for S-Video and composite TV-out.
+
+config FB_OMAP2_DSS_HDMI_COMMON
+ bool
+
+config FB_OMAP4_DSS_HDMI
+ bool "HDMI support for OMAP4"
+ default y
+ select FB_OMAP2_DSS_HDMI_COMMON
+ help
+ HDMI support for OMAP4 based SoCs.
+
+config FB_OMAP5_DSS_HDMI
+ bool "HDMI support for OMAP5"
+ default n
+ select FB_OMAP2_DSS_HDMI_COMMON
+ help
+ HDMI Interface for OMAP5 and similar cores. This adds the High
+ Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
+ specification.
+
+config FB_OMAP2_DSS_SDI
+ bool "SDI support"
+ default n
+ help
+ SDI (Serial Display Interface) support.
+
+ SDI is a high speed one-way display serial bus between the host
+ processor and a display.
+
+config FB_OMAP2_DSS_DSI
+ bool "DSI support"
+ default n
+ help
+ MIPI DSI (Display Serial Interface) support.
+
+ DSI is a high speed half-duplex serial interface between the host
+ processor and a peripheral, such as a display or a framebuffer chip.
+
+ See http://www.mipi.org/ for DSI specifications.
+
+config FB_OMAP2_DSS_MIN_FCK_PER_PCK
+ int "Minimum FCK/PCK ratio (for scaling)"
+ range 0 32
+ default 0
+ help
+ This can be used to adjust the minimum FCK/PCK ratio.
+
+ With this you can make sure that DISPC FCK is at least
+ n x PCK. Video plane scaling requires higher FCK than
+ normally.
+
+ If this is set to 0, there's no extra constraint on the
+ DISPC FCK. However, the FCK will at minimum be
+ 2xPCK (if active matrix) or 3xPCK (if passive matrix).
+
+ Max FCK is 173MHz, so this doesn't work if your PCK
+ is very high.
+
+config FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
+ bool "Sleep 20ms after VENC reset"
+ default y
+ help
+ There is a 20ms sleep after VENC reset which seemed to fix the
+ reset. The reason for the bug is unclear, and it's also unclear
+ on what platforms this happens.
+
+ This option enables the sleep, and is enabled by default. You can
+ disable the sleep if it doesn't cause problems on your platform.
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Makefile b/drivers/video/fbdev/omap2/omapfb/dss/Makefile
new file mode 100644
index 000000000000..02308e24f3ef
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/Makefile
@@ -0,0 +1,18 @@
+obj-$(CONFIG_FB_OMAP2_DSS_INIT) += omapdss-boot-init.o
+obj-$(CONFIG_FB_OMAP2_DSS) += omapdss.o
+# Core DSS files
+omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
+ output.o dss-of.o pll.o video-pll.o
+# DSS compat layer files
+omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
+ dispc-compat.o display-sysfs.o
+omapdss-$(CONFIG_FB_OMAP2_DSS_DPI) += dpi.o
+omapdss-$(CONFIG_FB_OMAP2_DSS_RFBI) += rfbi.o
+omapdss-$(CONFIG_FB_OMAP2_DSS_VENC) += venc.o
+omapdss-$(CONFIG_FB_OMAP2_DSS_SDI) += sdi.o
+omapdss-$(CONFIG_FB_OMAP2_DSS_DSI) += dsi.o
+omapdss-$(CONFIG_FB_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \
+ hdmi_phy.o
+omapdss-$(CONFIG_FB_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o
+omapdss-$(CONFIG_FB_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o
+ccflags-$(CONFIG_FB_OMAP2_DSS_DEBUG) += -DDEBUG
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/apply.c b/drivers/video/fbdev/omap2/omapfb/dss/apply.c
new file mode 100644
index 000000000000..663ccc3bf4e5
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/apply.c
@@ -0,0 +1,1702 @@
+/*
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "APPLY"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+#include "dispc-compat.h"
+
+/*
+ * We have 4 levels of cache for the dispc settings. First two are in SW and
+ * the latter two in HW.
+ *
+ * set_info()
+ * v
+ * +--------------------+
+ * | user_info |
+ * +--------------------+
+ * v
+ * apply()
+ * v
+ * +--------------------+
+ * | info |
+ * +--------------------+
+ * v
+ * write_regs()
+ * v
+ * +--------------------+
+ * | shadow registers |
+ * +--------------------+
+ * v
+ * VFP or lcd/digit_enable
+ * v
+ * +--------------------+
+ * | registers |
+ * +--------------------+
+ */
+
+struct ovl_priv_data {
+
+ bool user_info_dirty;
+ struct omap_overlay_info user_info;
+
+ bool info_dirty;
+ struct omap_overlay_info info;
+
+ bool shadow_info_dirty;
+
+ bool extra_info_dirty;
+ bool shadow_extra_info_dirty;
+
+ bool enabled;
+ u32 fifo_low, fifo_high;
+
+ /*
+ * True if overlay is to be enabled. Used to check and calculate configs
+ * for the overlay before it is enabled in the HW.
+ */
+ bool enabling;
+};
+
+struct mgr_priv_data {
+
+ bool user_info_dirty;
+ struct omap_overlay_manager_info user_info;
+
+ bool info_dirty;
+ struct omap_overlay_manager_info info;
+
+ bool shadow_info_dirty;
+
+ /* If true, GO bit is up and shadow registers cannot be written.
+ * Never true for manual update displays */
+ bool busy;
+
+ /* If true, dispc output is enabled */
+ bool updating;
+
+ /* If true, a display is enabled using this manager */
+ bool enabled;
+
+ bool extra_info_dirty;
+ bool shadow_extra_info_dirty;
+
+ struct omap_video_timings timings;
+ struct dss_lcd_mgr_config lcd_config;
+
+ void (*framedone_handler)(void *);
+ void *framedone_handler_data;
+};
+
+static struct {
+ struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
+ struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
+
+ bool irq_enabled;
+} dss_data;
+
+/* protects dss_data */
+static spinlock_t data_lock;
+/* lock for blocking functions */
+static DEFINE_MUTEX(apply_lock);
+static DECLARE_COMPLETION(extra_updated_completion);
+
+static void dss_register_vsync_isr(void);
+
+static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
+{
+ return &dss_data.ovl_priv_data_array[ovl->id];
+}
+
+static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
+{
+ return &dss_data.mgr_priv_data_array[mgr->id];
+}
+
+static void apply_init_priv(void)
+{
+ const int num_ovls = dss_feat_get_num_ovls();
+ struct mgr_priv_data *mp;
+ int i;
+
+ spin_lock_init(&data_lock);
+
+ for (i = 0; i < num_ovls; ++i) {
+ struct ovl_priv_data *op;
+
+ op = &dss_data.ovl_priv_data_array[i];
+
+ op->info.color_mode = OMAP_DSS_COLOR_RGB16;
+ op->info.rotation_type = OMAP_DSS_ROT_DMA;
+
+ op->info.global_alpha = 255;
+
+ switch (i) {
+ case 0:
+ op->info.zorder = 0;
+ break;
+ case 1:
+ op->info.zorder =
+ dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
+ break;
+ case 2:
+ op->info.zorder =
+ dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
+ break;
+ case 3:
+ op->info.zorder =
+ dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
+ break;
+ }
+
+ op->user_info = op->info;
+ }
+
+ /*
+ * Initialize some of the lcd_config fields for TV manager, this lets
+ * us prevent checking if the manager is LCD or TV at some places
+ */
+ mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
+
+ mp->lcd_config.video_port_width = 24;
+ mp->lcd_config.clock_info.lck_div = 1;
+ mp->lcd_config.clock_info.pck_div = 1;
+}
+
+/*
+ * A LCD manager's stallmode decides whether it is in manual or auto update. TV
+ * manager is always auto update, stallmode field for TV manager is false by
+ * default
+ */
+static bool ovl_manual_update(struct omap_overlay *ovl)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
+
+ return mp->lcd_config.stallmode;
+}
+
+static bool mgr_manual_update(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ return mp->lcd_config.stallmode;
+}
+
+static int dss_check_settings_low(struct omap_overlay_manager *mgr,
+ bool applying)
+{
+ struct omap_overlay_info *oi;
+ struct omap_overlay_manager_info *mi;
+ struct omap_overlay *ovl;
+ struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
+ struct ovl_priv_data *op;
+ struct mgr_priv_data *mp;
+
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled)
+ return 0;
+
+ if (applying && mp->user_info_dirty)
+ mi = &mp->user_info;
+ else
+ mi = &mp->info;
+
+ /* collect the infos to be tested into the array */
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ op = get_ovl_priv(ovl);
+
+ if (!op->enabled && !op->enabling)
+ oi = NULL;
+ else if (applying && op->user_info_dirty)
+ oi = &op->user_info;
+ else
+ oi = &op->info;
+
+ ois[ovl->id] = oi;
+ }
+
+ return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
+}
+
+/*
+ * check manager and overlay settings using overlay_info from data->info
+ */
+static int dss_check_settings(struct omap_overlay_manager *mgr)
+{
+ return dss_check_settings_low(mgr, false);
+}
+
+/*
+ * check manager and overlay settings using overlay_info from ovl->info if
+ * dirty and from data->info otherwise
+ */
+static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
+{
+ return dss_check_settings_low(mgr, true);
+}
+
+static bool need_isr(void)
+{
+ const int num_mgrs = dss_feat_get_num_mgrs();
+ int i;
+
+ for (i = 0; i < num_mgrs; ++i) {
+ struct omap_overlay_manager *mgr;
+ struct mgr_priv_data *mp;
+ struct omap_overlay *ovl;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled)
+ continue;
+
+ if (mgr_manual_update(mgr)) {
+ /* to catch FRAMEDONE */
+ if (mp->updating)
+ return true;
+ } else {
+ /* to catch GO bit going down */
+ if (mp->busy)
+ return true;
+
+ /* to write new values to registers */
+ if (mp->info_dirty)
+ return true;
+
+ /* to set GO bit */
+ if (mp->shadow_info_dirty)
+ return true;
+
+ /*
+ * NOTE: we don't check extra_info flags for disabled
+ * managers, once the manager is enabled, the extra_info
+ * related manager changes will be taken in by HW.
+ */
+
+ /* to write new values to registers */
+ if (mp->extra_info_dirty)
+ return true;
+
+ /* to set GO bit */
+ if (mp->shadow_extra_info_dirty)
+ return true;
+
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ struct ovl_priv_data *op;
+
+ op = get_ovl_priv(ovl);
+
+ /*
+ * NOTE: we check extra_info flags even for
+ * disabled overlays, as extra_infos need to be
+ * always written.
+ */
+
+ /* to write new values to registers */
+ if (op->extra_info_dirty)
+ return true;
+
+ /* to set GO bit */
+ if (op->shadow_extra_info_dirty)
+ return true;
+
+ if (!op->enabled)
+ continue;
+
+ /* to write new values to registers */
+ if (op->info_dirty)
+ return true;
+
+ /* to set GO bit */
+ if (op->shadow_info_dirty)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool need_go(struct omap_overlay_manager *mgr)
+{
+ struct omap_overlay *ovl;
+ struct mgr_priv_data *mp;
+ struct ovl_priv_data *op;
+
+ mp = get_mgr_priv(mgr);
+
+ if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
+ return true;
+
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ op = get_ovl_priv(ovl);
+ if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
+ return true;
+ }
+
+ return false;
+}
+
+/* returns true if an extra_info field is currently being updated */
+static bool extra_info_update_ongoing(void)
+{
+ const int num_mgrs = dss_feat_get_num_mgrs();
+ int i;
+
+ for (i = 0; i < num_mgrs; ++i) {
+ struct omap_overlay_manager *mgr;
+ struct omap_overlay *ovl;
+ struct mgr_priv_data *mp;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled)
+ continue;
+
+ if (!mp->updating)
+ continue;
+
+ if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
+ return true;
+
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+
+ if (op->extra_info_dirty || op->shadow_extra_info_dirty)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* wait until no extra_info updates are pending */
+static void wait_pending_extra_info_updates(void)
+{
+ bool updating;
+ unsigned long flags;
+ unsigned long t;
+ int r;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ updating = extra_info_update_ongoing();
+
+ if (!updating) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ return;
+ }
+
+ init_completion(&extra_updated_completion);
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ t = msecs_to_jiffies(500);
+ r = wait_for_completion_timeout(&extra_updated_completion, t);
+ if (r == 0)
+ DSSWARN("timeout in wait_pending_extra_info_updates\n");
+}
+
+static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
+{
+ struct omap_dss_device *dssdev;
+
+ dssdev = mgr->output;
+ if (dssdev == NULL)
+ return NULL;
+
+ while (dssdev->dst)
+ dssdev = dssdev->dst;
+
+ if (dssdev->driver)
+ return dssdev;
+ else
+ return NULL;
+}
+
+static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
+{
+ return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;
+}
+
+static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
+{
+ unsigned long timeout = msecs_to_jiffies(500);
+ u32 irq;
+ int r;
+
+ if (mgr->output == NULL)
+ return -ENODEV;
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ switch (mgr->output->id) {
+ case OMAP_DSS_OUTPUT_VENC:
+ irq = DISPC_IRQ_EVSYNC_ODD;
+ break;
+ case OMAP_DSS_OUTPUT_HDMI:
+ irq = DISPC_IRQ_EVSYNC_EVEN;
+ break;
+ default:
+ irq = dispc_mgr_get_vsync_irq(mgr->id);
+ break;
+ }
+
+ r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+
+ dispc_runtime_put();
+
+ return r;
+}
+
+static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
+{
+ unsigned long timeout = msecs_to_jiffies(500);
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ u32 irq;
+ unsigned long flags;
+ int r;
+ int i;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mgr_manual_update(mgr)) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ return 0;
+ }
+
+ if (!mp->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ irq = dispc_mgr_get_vsync_irq(mgr->id);
+
+ i = 0;
+ while (1) {
+ bool shadow_dirty, dirty;
+
+ spin_lock_irqsave(&data_lock, flags);
+ dirty = mp->info_dirty;
+ shadow_dirty = mp->shadow_info_dirty;
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ if (!dirty && !shadow_dirty) {
+ r = 0;
+ break;
+ }
+
+ /* 4 iterations is the worst case:
+ * 1 - initial iteration, dirty = true (between VFP and VSYNC)
+ * 2 - first VSYNC, dirty = true
+ * 3 - dirty = false, shadow_dirty = true
+ * 4 - shadow_dirty = false */
+ if (i++ == 3) {
+ DSSERR("mgr(%d)->wait_for_go() not finishing\n",
+ mgr->id);
+ r = 0;
+ break;
+ }
+
+ r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+ if (r == -ERESTARTSYS)
+ break;
+
+ if (r) {
+ DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
+ break;
+ }
+ }
+
+ dispc_runtime_put();
+
+ return r;
+}
+
+static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
+{
+ unsigned long timeout = msecs_to_jiffies(500);
+ struct ovl_priv_data *op;
+ struct mgr_priv_data *mp;
+ u32 irq;
+ unsigned long flags;
+ int r;
+ int i;
+
+ if (!ovl->manager)
+ return 0;
+
+ mp = get_mgr_priv(ovl->manager);
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (ovl_manual_update(ovl)) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ return 0;
+ }
+
+ if (!mp->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
+
+ op = get_ovl_priv(ovl);
+ i = 0;
+ while (1) {
+ bool shadow_dirty, dirty;
+
+ spin_lock_irqsave(&data_lock, flags);
+ dirty = op->info_dirty;
+ shadow_dirty = op->shadow_info_dirty;
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ if (!dirty && !shadow_dirty) {
+ r = 0;
+ break;
+ }
+
+ /* 4 iterations is the worst case:
+ * 1 - initial iteration, dirty = true (between VFP and VSYNC)
+ * 2 - first VSYNC, dirty = true
+ * 3 - dirty = false, shadow_dirty = true
+ * 4 - shadow_dirty = false */
+ if (i++ == 3) {
+ DSSERR("ovl(%d)->wait_for_go() not finishing\n",
+ ovl->id);
+ r = 0;
+ break;
+ }
+
+ r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+ if (r == -ERESTARTSYS)
+ break;
+
+ if (r) {
+ DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
+ break;
+ }
+ }
+
+ dispc_runtime_put();
+
+ return r;
+}
+
+static void dss_ovl_write_regs(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ struct omap_overlay_info *oi;
+ bool replication;
+ struct mgr_priv_data *mp;
+ int r;
+
+ DSSDBG("writing ovl %d regs\n", ovl->id);
+
+ if (!op->enabled || !op->info_dirty)
+ return;
+
+ oi = &op->info;
+
+ mp = get_mgr_priv(ovl->manager);
+
+ replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
+
+ r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
+ if (r) {
+ /*
+ * We can't do much here, as this function can be called from
+ * vsync interrupt.
+ */
+ DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
+
+ /* This will leave fifo configurations in a nonoptimal state */
+ op->enabled = false;
+ dispc_ovl_enable(ovl->id, false);
+ return;
+ }
+
+ op->info_dirty = false;
+ if (mp->updating)
+ op->shadow_info_dirty = true;
+}
+
+static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ struct mgr_priv_data *mp;
+
+ DSSDBG("writing ovl %d regs extra\n", ovl->id);
+
+ if (!op->extra_info_dirty)
+ return;
+
+ /* note: write also when op->enabled == false, so that the ovl gets
+ * disabled */
+
+ dispc_ovl_enable(ovl->id, op->enabled);
+ dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
+
+ mp = get_mgr_priv(ovl->manager);
+
+ op->extra_info_dirty = false;
+ if (mp->updating)
+ op->shadow_extra_info_dirty = true;
+}
+
+static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ struct omap_overlay *ovl;
+
+ DSSDBG("writing mgr %d regs\n", mgr->id);
+
+ if (!mp->enabled)
+ return;
+
+ WARN_ON(mp->busy);
+
+ /* Commit overlay settings */
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ dss_ovl_write_regs(ovl);
+ dss_ovl_write_regs_extra(ovl);
+ }
+
+ if (mp->info_dirty) {
+ dispc_mgr_setup(mgr->id, &mp->info);
+
+ mp->info_dirty = false;
+ if (mp->updating)
+ mp->shadow_info_dirty = true;
+ }
+}
+
+static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ DSSDBG("writing mgr %d regs extra\n", mgr->id);
+
+ if (!mp->extra_info_dirty)
+ return;
+
+ dispc_mgr_set_timings(mgr->id, &mp->timings);
+
+ /* lcd_config parameters */
+ if (dss_mgr_is_lcd(mgr->id))
+ dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
+
+ mp->extra_info_dirty = false;
+ if (mp->updating)
+ mp->shadow_extra_info_dirty = true;
+}
+
+static void dss_write_regs(void)
+{
+ const int num_mgrs = omap_dss_get_num_overlay_managers();
+ int i;
+
+ for (i = 0; i < num_mgrs; ++i) {
+ struct omap_overlay_manager *mgr;
+ struct mgr_priv_data *mp;
+ int r;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
+ continue;
+
+ r = dss_check_settings(mgr);
+ if (r) {
+ DSSERR("cannot write registers for manager %s: "
+ "illegal configuration\n", mgr->name);
+ continue;
+ }
+
+ dss_mgr_write_regs(mgr);
+ dss_mgr_write_regs_extra(mgr);
+ }
+}
+
+static void dss_set_go_bits(void)
+{
+ const int num_mgrs = omap_dss_get_num_overlay_managers();
+ int i;
+
+ for (i = 0; i < num_mgrs; ++i) {
+ struct omap_overlay_manager *mgr;
+ struct mgr_priv_data *mp;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
+ continue;
+
+ if (!need_go(mgr))
+ continue;
+
+ mp->busy = true;
+
+ if (!dss_data.irq_enabled && need_isr())
+ dss_register_vsync_isr();
+
+ dispc_mgr_go(mgr->id);
+ }
+
+}
+
+static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
+{
+ struct omap_overlay *ovl;
+ struct mgr_priv_data *mp;
+ struct ovl_priv_data *op;
+
+ mp = get_mgr_priv(mgr);
+ mp->shadow_info_dirty = false;
+ mp->shadow_extra_info_dirty = false;
+
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ op = get_ovl_priv(ovl);
+ op->shadow_info_dirty = false;
+ op->shadow_extra_info_dirty = false;
+ }
+}
+
+static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *dst)
+{
+ return mgr->set_output(mgr, dst);
+}
+
+static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *dst)
+{
+ mgr->unset_output(mgr);
+}
+
+static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ WARN_ON(mp->updating);
+
+ r = dss_check_settings(mgr);
+ if (r) {
+ DSSERR("cannot start manual update: illegal configuration\n");
+ spin_unlock_irqrestore(&data_lock, flags);
+ return;
+ }
+
+ dss_mgr_write_regs(mgr);
+ dss_mgr_write_regs_extra(mgr);
+
+ mp->updating = true;
+
+ if (!dss_data.irq_enabled && need_isr())
+ dss_register_vsync_isr();
+
+ dispc_mgr_enable_sync(mgr->id);
+
+ spin_unlock_irqrestore(&data_lock, flags);
+}
+
+static void dss_apply_irq_handler(void *data, u32 mask);
+
+static void dss_register_vsync_isr(void)
+{
+ const int num_mgrs = dss_feat_get_num_mgrs();
+ u32 mask;
+ int r, i;
+
+ mask = 0;
+ for (i = 0; i < num_mgrs; ++i)
+ mask |= dispc_mgr_get_vsync_irq(i);
+
+ for (i = 0; i < num_mgrs; ++i)
+ mask |= dispc_mgr_get_framedone_irq(i);
+
+ r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
+ WARN_ON(r);
+
+ dss_data.irq_enabled = true;
+}
+
+static void dss_unregister_vsync_isr(void)
+{
+ const int num_mgrs = dss_feat_get_num_mgrs();
+ u32 mask;
+ int r, i;
+
+ mask = 0;
+ for (i = 0; i < num_mgrs; ++i)
+ mask |= dispc_mgr_get_vsync_irq(i);
+
+ for (i = 0; i < num_mgrs; ++i)
+ mask |= dispc_mgr_get_framedone_irq(i);
+
+ r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
+ WARN_ON(r);
+
+ dss_data.irq_enabled = false;
+}
+
+static void dss_apply_irq_handler(void *data, u32 mask)
+{
+ const int num_mgrs = dss_feat_get_num_mgrs();
+ int i;
+ bool extra_updating;
+
+ spin_lock(&data_lock);
+
+ /* clear busy, updating flags, shadow_dirty flags */
+ for (i = 0; i < num_mgrs; i++) {
+ struct omap_overlay_manager *mgr;
+ struct mgr_priv_data *mp;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled)
+ continue;
+
+ mp->updating = dispc_mgr_is_enabled(i);
+
+ if (!mgr_manual_update(mgr)) {
+ bool was_busy = mp->busy;
+ mp->busy = dispc_mgr_go_busy(i);
+
+ if (was_busy && !mp->busy)
+ mgr_clear_shadow_dirty(mgr);
+ }
+ }
+
+ dss_write_regs();
+ dss_set_go_bits();
+
+ extra_updating = extra_info_update_ongoing();
+ if (!extra_updating)
+ complete_all(&extra_updated_completion);
+
+ /* call framedone handlers for manual update displays */
+ for (i = 0; i < num_mgrs; i++) {
+ struct omap_overlay_manager *mgr;
+ struct mgr_priv_data *mp;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ mp = get_mgr_priv(mgr);
+
+ if (!mgr_manual_update(mgr) || !mp->framedone_handler)
+ continue;
+
+ if (mask & dispc_mgr_get_framedone_irq(i))
+ mp->framedone_handler(mp->framedone_handler_data);
+ }
+
+ if (!need_isr())
+ dss_unregister_vsync_isr();
+
+ spin_unlock(&data_lock);
+}
+
+static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op;
+
+ op = get_ovl_priv(ovl);
+
+ if (!op->user_info_dirty)
+ return;
+
+ op->user_info_dirty = false;
+ op->info_dirty = true;
+ op->info = op->user_info;
+}
+
+static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp;
+
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->user_info_dirty)
+ return;
+
+ mp->user_info_dirty = false;
+ mp->info_dirty = true;
+ mp->info = mp->user_info;
+}
+
+static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
+{
+ unsigned long flags;
+ struct omap_overlay *ovl;
+ int r;
+
+ DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ r = dss_check_settings_apply(mgr);
+ if (r) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ DSSERR("failed to apply settings: illegal configuration.\n");
+ return r;
+ }
+
+ /* Configure overlays */
+ list_for_each_entry(ovl, &mgr->overlays, list)
+ omap_dss_mgr_apply_ovl(ovl);
+
+ /* Configure manager */
+ omap_dss_mgr_apply_mgr(mgr);
+
+ dss_write_regs();
+ dss_set_go_bits();
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ return 0;
+}
+
+static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
+{
+ struct ovl_priv_data *op;
+
+ op = get_ovl_priv(ovl);
+
+ if (op->enabled == enable)
+ return;
+
+ op->enabled = enable;
+ op->extra_info_dirty = true;
+}
+
+static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
+ u32 fifo_low, u32 fifo_high)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+
+ if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
+ return;
+
+ op->fifo_low = fifo_low;
+ op->fifo_high = fifo_high;
+ op->extra_info_dirty = true;
+}
+
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ u32 fifo_low, fifo_high;
+ bool use_fifo_merge = false;
+
+ if (!op->enabled && !op->enabling)
+ return;
+
+ dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
+ use_fifo_merge, ovl_manual_update(ovl));
+
+ dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
+}
+
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
+{
+ struct omap_overlay *ovl;
+ struct mgr_priv_data *mp;
+
+ mp = get_mgr_priv(mgr);
+
+ if (!mp->enabled)
+ return;
+
+ list_for_each_entry(ovl, &mgr->overlays, list)
+ dss_ovl_setup_fifo(ovl);
+}
+
+static void dss_setup_fifos(void)
+{
+ const int num_mgrs = omap_dss_get_num_overlay_managers();
+ struct omap_overlay_manager *mgr;
+ int i;
+
+ for (i = 0; i < num_mgrs; ++i) {
+ mgr = omap_dss_get_overlay_manager(i);
+ dss_mgr_setup_fifos(mgr);
+ }
+}
+
+static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
+ int r;
+
+ mutex_lock(&apply_lock);
+
+ if (mp->enabled)
+ goto out;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ mp->enabled = true;
+
+ r = dss_check_settings(mgr);
+ if (r) {
+ DSSERR("failed to enable manager %d: check_settings failed\n",
+ mgr->id);
+ goto err;
+ }
+
+ dss_setup_fifos();
+
+ dss_write_regs();
+ dss_set_go_bits();
+
+ if (!mgr_manual_update(mgr))
+ mp->updating = true;
+
+ if (!dss_data.irq_enabled && need_isr())
+ dss_register_vsync_isr();
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ if (!mgr_manual_update(mgr))
+ dispc_mgr_enable_sync(mgr->id);
+
+out:
+ mutex_unlock(&apply_lock);
+
+ return 0;
+
+err:
+ mp->enabled = false;
+ spin_unlock_irqrestore(&data_lock, flags);
+ mutex_unlock(&apply_lock);
+ return r;
+}
+
+static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
+
+ mutex_lock(&apply_lock);
+
+ if (!mp->enabled)
+ goto out;
+
+ wait_pending_extra_info_updates();
+
+ if (!mgr_manual_update(mgr))
+ dispc_mgr_disable_sync(mgr->id);
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ mp->updating = false;
+ mp->enabled = false;
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+out:
+ mutex_unlock(&apply_lock);
+}
+
+static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
+ struct omap_overlay_manager_info *info)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
+ int r;
+
+ r = dss_mgr_simple_check(mgr, info);
+ if (r)
+ return r;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ mp->user_info = *info;
+ mp->user_info_dirty = true;
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ return 0;
+}
+
+static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
+ struct omap_overlay_manager_info *info)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ *info = mp->user_info;
+
+ spin_unlock_irqrestore(&data_lock, flags);
+}
+
+static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *output)
+{
+ int r;
+
+ mutex_lock(&apply_lock);
+
+ if (mgr->output) {
+ DSSERR("manager %s is already connected to an output\n",
+ mgr->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ if ((mgr->supported_outputs & output->id) == 0) {
+ DSSERR("output does not support manager %s\n",
+ mgr->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ output->manager = mgr;
+ mgr->output = output;
+
+ mutex_unlock(&apply_lock);
+
+ return 0;
+err:
+ mutex_unlock(&apply_lock);
+ return r;
+}
+
+static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
+{
+ int r;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
+
+ mutex_lock(&apply_lock);
+
+ if (!mgr->output) {
+ DSSERR("failed to unset output, output not set\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mp->enabled) {
+ DSSERR("output can't be unset when manager is enabled\n");
+ r = -EINVAL;
+ goto err1;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ mgr->output->manager = NULL;
+ mgr->output = NULL;
+
+ mutex_unlock(&apply_lock);
+
+ return 0;
+err1:
+ spin_unlock_irqrestore(&data_lock, flags);
+err:
+ mutex_unlock(&apply_lock);
+
+ return r;
+}
+
+static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
+ const struct omap_video_timings *timings)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ mp->timings = *timings;
+ mp->extra_info_dirty = true;
+}
+
+static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
+ const struct omap_video_timings *timings)
+{
+ unsigned long flags;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mp->updating) {
+ DSSERR("cannot set timings for %s: manager needs to be disabled\n",
+ mgr->name);
+ goto out;
+ }
+
+ dss_apply_mgr_timings(mgr, timings);
+out:
+ spin_unlock_irqrestore(&data_lock, flags);
+}
+
+static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
+ const struct dss_lcd_mgr_config *config)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ mp->lcd_config = *config;
+ mp->extra_info_dirty = true;
+}
+
+static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
+ const struct dss_lcd_mgr_config *config)
+{
+ unsigned long flags;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mp->enabled) {
+ DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
+ mgr->name);
+ goto out;
+ }
+
+ dss_apply_mgr_lcd_config(mgr, config);
+out:
+ spin_unlock_irqrestore(&data_lock, flags);
+}
+
+static int dss_ovl_set_info(struct omap_overlay *ovl,
+ struct omap_overlay_info *info)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+ int r;
+
+ r = dss_ovl_simple_check(ovl, info);
+ if (r)
+ return r;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ op->user_info = *info;
+ op->user_info_dirty = true;
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ return 0;
+}
+
+static void dss_ovl_get_info(struct omap_overlay *ovl,
+ struct omap_overlay_info *info)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ *info = op->user_info;
+
+ spin_unlock_irqrestore(&data_lock, flags);
+}
+
+static int dss_ovl_set_manager(struct omap_overlay *ovl,
+ struct omap_overlay_manager *mgr)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+ int r;
+
+ if (!mgr)
+ return -EINVAL;
+
+ mutex_lock(&apply_lock);
+
+ if (ovl->manager) {
+ DSSERR("overlay '%s' already has a manager '%s'\n",
+ ovl->name, ovl->manager->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ r = dispc_runtime_get();
+ if (r)
+ goto err;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (op->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ DSSERR("overlay has to be disabled to change the manager\n");
+ r = -EINVAL;
+ goto err1;
+ }
+
+ dispc_ovl_set_channel_out(ovl->id, mgr->id);
+
+ ovl->manager = mgr;
+ list_add_tail(&ovl->list, &mgr->overlays);
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ dispc_runtime_put();
+
+ mutex_unlock(&apply_lock);
+
+ return 0;
+
+err1:
+ dispc_runtime_put();
+err:
+ mutex_unlock(&apply_lock);
+ return r;
+}
+
+static int dss_ovl_unset_manager(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+ int r;
+
+ mutex_lock(&apply_lock);
+
+ if (!ovl->manager) {
+ DSSERR("failed to detach overlay: manager not set\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (op->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ DSSERR("overlay has to be disabled to unset the manager\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ /* wait for pending extra_info updates to ensure the ovl is disabled */
+ wait_pending_extra_info_updates();
+
+ /*
+ * For a manual update display, there is no guarantee that the overlay
+ * is really disabled in HW, we may need an extra update from this
+ * manager before the configurations can go in. Return an error if the
+ * overlay needed an update from the manager.
+ *
+ * TODO: Instead of returning an error, try to do a dummy manager update
+ * here to disable the overlay in hardware. Use the *GATED fields in
+ * the DISPC_CONFIG registers to do a dummy update.
+ */
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (ovl_manual_update(ovl) && op->extra_info_dirty) {
+ spin_unlock_irqrestore(&data_lock, flags);
+ DSSERR("need an update to change the manager\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ ovl->manager = NULL;
+ list_del(&ovl->list);
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ mutex_unlock(&apply_lock);
+
+ return 0;
+err:
+ mutex_unlock(&apply_lock);
+ return r;
+}
+
+static bool dss_ovl_is_enabled(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+ bool e;
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ e = op->enabled;
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ return e;
+}
+
+static int dss_ovl_enable(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+ int r;
+
+ mutex_lock(&apply_lock);
+
+ if (op->enabled) {
+ r = 0;
+ goto err1;
+ }
+
+ if (ovl->manager == NULL || ovl->manager->output == NULL) {
+ r = -EINVAL;
+ goto err1;
+ }
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ op->enabling = true;
+
+ r = dss_check_settings(ovl->manager);
+ if (r) {
+ DSSERR("failed to enable overlay %d: check_settings failed\n",
+ ovl->id);
+ goto err2;
+ }
+
+ dss_setup_fifos();
+
+ op->enabling = false;
+ dss_apply_ovl_enable(ovl, true);
+
+ dss_write_regs();
+ dss_set_go_bits();
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ mutex_unlock(&apply_lock);
+
+ return 0;
+err2:
+ op->enabling = false;
+ spin_unlock_irqrestore(&data_lock, flags);
+err1:
+ mutex_unlock(&apply_lock);
+ return r;
+}
+
+static int dss_ovl_disable(struct omap_overlay *ovl)
+{
+ struct ovl_priv_data *op = get_ovl_priv(ovl);
+ unsigned long flags;
+ int r;
+
+ mutex_lock(&apply_lock);
+
+ if (!op->enabled) {
+ r = 0;
+ goto err;
+ }
+
+ if (ovl->manager == NULL || ovl->manager->output == NULL) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ spin_lock_irqsave(&data_lock, flags);
+
+ dss_apply_ovl_enable(ovl, false);
+ dss_write_regs();
+ dss_set_go_bits();
+
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ mutex_unlock(&apply_lock);
+
+ return 0;
+
+err:
+ mutex_unlock(&apply_lock);
+ return r;
+}
+
+static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
+ void (*handler)(void *), void *data)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ if (mp->framedone_handler)
+ return -EBUSY;
+
+ mp->framedone_handler = handler;
+ mp->framedone_handler_data = data;
+
+ return 0;
+}
+
+static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
+ void (*handler)(void *), void *data)
+{
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+ WARN_ON(mp->framedone_handler != handler ||
+ mp->framedone_handler_data != data);
+
+ mp->framedone_handler = NULL;
+ mp->framedone_handler_data = NULL;
+}
+
+static const struct dss_mgr_ops apply_mgr_ops = {
+ .connect = dss_mgr_connect_compat,
+ .disconnect = dss_mgr_disconnect_compat,
+ .start_update = dss_mgr_start_update_compat,
+ .enable = dss_mgr_enable_compat,
+ .disable = dss_mgr_disable_compat,
+ .set_timings = dss_mgr_set_timings_compat,
+ .set_lcd_config = dss_mgr_set_lcd_config_compat,
+ .register_framedone_handler = dss_mgr_register_framedone_handler_compat,
+ .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
+};
+
+static int compat_refcnt;
+static DEFINE_MUTEX(compat_init_lock);
+
+int omapdss_compat_init(void)
+{
+ struct platform_device *pdev = dss_get_core_pdev();
+ int i, r;
+
+ mutex_lock(&compat_init_lock);
+
+ if (compat_refcnt++ > 0)
+ goto out;
+
+ apply_init_priv();
+
+ dss_init_overlay_managers_sysfs(pdev);
+ dss_init_overlays(pdev);
+
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
+ struct omap_overlay_manager *mgr;
+
+ mgr = omap_dss_get_overlay_manager(i);
+
+ mgr->set_output = &dss_mgr_set_output;
+ mgr->unset_output = &dss_mgr_unset_output;
+ mgr->apply = &omap_dss_mgr_apply;
+ mgr->set_manager_info = &dss_mgr_set_info;
+ mgr->get_manager_info = &dss_mgr_get_info;
+ mgr->wait_for_go = &dss_mgr_wait_for_go;
+ mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
+ mgr->get_device = &dss_mgr_get_device;
+ }
+
+ for (i = 0; i < omap_dss_get_num_overlays(); i++) {
+ struct omap_overlay *ovl = omap_dss_get_overlay(i);
+
+ ovl->is_enabled = &dss_ovl_is_enabled;
+ ovl->enable = &dss_ovl_enable;
+ ovl->disable = &dss_ovl_disable;
+ ovl->set_manager = &dss_ovl_set_manager;
+ ovl->unset_manager = &dss_ovl_unset_manager;
+ ovl->set_overlay_info = &dss_ovl_set_info;
+ ovl->get_overlay_info = &dss_ovl_get_info;
+ ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
+ ovl->get_device = &dss_ovl_get_device;
+ }
+
+ r = dss_install_mgr_ops(&apply_mgr_ops);
+ if (r)
+ goto err_mgr_ops;
+
+ r = display_init_sysfs(pdev);
+ if (r)
+ goto err_disp_sysfs;
+
+ dispc_runtime_get();
+
+ r = dss_dispc_initialize_irq();
+ if (r)
+ goto err_init_irq;
+
+ dispc_runtime_put();
+
+out:
+ mutex_unlock(&compat_init_lock);
+
+ return 0;
+
+err_init_irq:
+ dispc_runtime_put();
+ display_uninit_sysfs(pdev);
+
+err_disp_sysfs:
+ dss_uninstall_mgr_ops();
+
+err_mgr_ops:
+ dss_uninit_overlay_managers_sysfs(pdev);
+ dss_uninit_overlays(pdev);
+
+ compat_refcnt--;
+
+ mutex_unlock(&compat_init_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_compat_init);
+
+void omapdss_compat_uninit(void)
+{
+ struct platform_device *pdev = dss_get_core_pdev();
+
+ mutex_lock(&compat_init_lock);
+
+ if (--compat_refcnt > 0)
+ goto out;
+
+ dss_dispc_uninitialize_irq();
+
+ display_uninit_sysfs(pdev);
+
+ dss_uninstall_mgr_ops();
+
+ dss_uninit_overlay_managers_sysfs(pdev);
+ dss_uninit_overlays(pdev);
+out:
+ mutex_unlock(&compat_init_lock);
+}
+EXPORT_SYMBOL(omapdss_compat_uninit);
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/core.c b/drivers/video/fbdev/omap2/omapfb/dss/core.c
new file mode 100644
index 000000000000..5a87179b7312
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/core.c
@@ -0,0 +1,343 @@
+/*
+ * linux/drivers/video/omap2/dss/core.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "CORE"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+#include <linux/slab.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static struct {
+ struct platform_device *pdev;
+
+ const char *default_display_name;
+} core;
+
+static char *def_disp_name;
+module_param_named(def_disp, def_disp_name, charp, 0);
+MODULE_PARM_DESC(def_disp, "default display name");
+
+const char *omapdss_get_default_display_name(void)
+{
+ return core.default_display_name;
+}
+EXPORT_SYMBOL(omapdss_get_default_display_name);
+
+enum omapdss_version omapdss_get_version(void)
+{
+ struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
+ return pdata->version;
+}
+EXPORT_SYMBOL(omapdss_get_version);
+
+struct platform_device *dss_get_core_pdev(void)
+{
+ return core.pdev;
+}
+
+int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
+{
+ struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
+
+ if (!board_data->dsi_enable_pads)
+ return -ENOENT;
+
+ return board_data->dsi_enable_pads(dsi_id, lane_mask);
+}
+
+void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
+{
+ struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
+
+ if (!board_data->dsi_disable_pads)
+ return;
+
+ return board_data->dsi_disable_pads(dsi_id, lane_mask);
+}
+
+int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
+{
+ struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
+
+ if (pdata->set_min_bus_tput)
+ return pdata->set_min_bus_tput(dev, tput);
+ else
+ return 0;
+}
+
+#if defined(CONFIG_FB_OMAP2_DSS_DEBUGFS)
+static int dss_debug_show(struct seq_file *s, void *unused)
+{
+ void (*func)(struct seq_file *) = s->private;
+ func(s);
+ return 0;
+}
+
+static int dss_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dss_debug_show, inode->i_private);
+}
+
+static const struct file_operations dss_debug_fops = {
+ .open = dss_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *dss_debugfs_dir;
+
+static int dss_initialize_debugfs(void)
+{
+ dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
+ if (IS_ERR(dss_debugfs_dir)) {
+ int err = PTR_ERR(dss_debugfs_dir);
+ dss_debugfs_dir = NULL;
+ return err;
+ }
+
+ debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
+ &dss_debug_dump_clocks, &dss_debug_fops);
+
+ return 0;
+}
+
+static void dss_uninitialize_debugfs(void)
+{
+ if (dss_debugfs_dir)
+ debugfs_remove_recursive(dss_debugfs_dir);
+}
+
+int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
+{
+ struct dentry *d;
+
+ d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
+ write, &dss_debug_fops);
+
+ return PTR_ERR_OR_ZERO(d);
+}
+#else /* CONFIG_FB_OMAP2_DSS_DEBUGFS */
+static inline int dss_initialize_debugfs(void)
+{
+ return 0;
+}
+static inline void dss_uninitialize_debugfs(void)
+{
+}
+int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
+{
+ return 0;
+}
+#endif /* CONFIG_FB_OMAP2_DSS_DEBUGFS */
+
+/* PLATFORM DEVICE */
+static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
+{
+ DSSDBG("pm notif %lu\n", v);
+
+ switch (v) {
+ case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ case PM_RESTORE_PREPARE:
+ DSSDBG("suspending displays\n");
+ return dss_suspend_all_devices();
+
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ case PM_POST_RESTORE:
+ DSSDBG("resuming displays\n");
+ return dss_resume_all_devices();
+
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block omap_dss_pm_notif_block = {
+ .notifier_call = omap_dss_pm_notif,
+};
+
+static int __init omap_dss_probe(struct platform_device *pdev)
+{
+ struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+ int r;
+
+ core.pdev = pdev;
+
+ dss_features_init(omapdss_get_version());
+
+ r = dss_initialize_debugfs();
+ if (r)
+ goto err_debugfs;
+
+ if (def_disp_name)
+ core.default_display_name = def_disp_name;
+ else if (pdata->default_display_name)
+ core.default_display_name = pdata->default_display_name;
+ else if (pdata->default_device)
+ core.default_display_name = pdata->default_device->name;
+
+ register_pm_notifier(&omap_dss_pm_notif_block);
+
+ return 0;
+
+err_debugfs:
+
+ return r;
+}
+
+static int omap_dss_remove(struct platform_device *pdev)
+{
+ unregister_pm_notifier(&omap_dss_pm_notif_block);
+
+ dss_uninitialize_debugfs();
+
+ return 0;
+}
+
+static void omap_dss_shutdown(struct platform_device *pdev)
+{
+ DSSDBG("shutdown\n");
+ dss_disable_all_devices();
+}
+
+static struct platform_driver omap_dss_driver = {
+ .remove = omap_dss_remove,
+ .shutdown = omap_dss_shutdown,
+ .driver = {
+ .name = "omapdss",
+ },
+};
+
+/* INIT */
+static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
+ dss_init_platform_driver,
+ dispc_init_platform_driver,
+#ifdef CONFIG_FB_OMAP2_DSS_DSI
+ dsi_init_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_DPI
+ dpi_init_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_SDI
+ sdi_init_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_RFBI
+ rfbi_init_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_VENC
+ venc_init_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP4_DSS_HDMI
+ hdmi4_init_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP5_DSS_HDMI
+ hdmi5_init_platform_driver,
+#endif
+};
+
+static void (*dss_output_drv_unreg_funcs[])(void) = {
+#ifdef CONFIG_FB_OMAP5_DSS_HDMI
+ hdmi5_uninit_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP4_DSS_HDMI
+ hdmi4_uninit_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_VENC
+ venc_uninit_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_RFBI
+ rfbi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_SDI
+ sdi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_DPI
+ dpi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_FB_OMAP2_DSS_DSI
+ dsi_uninit_platform_driver,
+#endif
+ dispc_uninit_platform_driver,
+ dss_uninit_platform_driver,
+};
+
+static int __init omap_dss_init(void)
+{
+ int r;
+ int i;
+
+ r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
+ if (r)
+ return r;
+
+ for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
+ r = dss_output_drv_reg_funcs[i]();
+ if (r)
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+ for (i = ARRAY_SIZE(dss_output_drv_reg_funcs) - i;
+ i < ARRAY_SIZE(dss_output_drv_reg_funcs);
+ ++i)
+ dss_output_drv_unreg_funcs[i]();
+
+ platform_driver_unregister(&omap_dss_driver);
+
+ return r;
+}
+
+static void __exit omap_dss_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i)
+ dss_output_drv_unreg_funcs[i]();
+
+ platform_driver_unregister(&omap_dss_driver);
+}
+
+module_init(omap_dss_init);
+module_exit(omap_dss_exit);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
+MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
new file mode 100644
index 000000000000..6607db37a5e4
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "APPLY"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+#include "dispc-compat.h"
+
+#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
+ DISPC_IRQ_OCP_ERR | \
+ DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
+ DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
+ DISPC_IRQ_SYNC_LOST | \
+ DISPC_IRQ_SYNC_LOST_DIGIT)
+
+#define DISPC_MAX_NR_ISRS 8
+
+struct omap_dispc_isr_data {
+ omap_dispc_isr_t isr;
+ void *arg;
+ u32 mask;
+};
+
+struct dispc_irq_stats {
+ unsigned long last_reset;
+ unsigned irq_count;
+ unsigned irqs[32];
+};
+
+static struct {
+ spinlock_t irq_lock;
+ u32 irq_error_mask;
+ struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
+ u32 error_irqs;
+ struct work_struct error_work;
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ spinlock_t irq_stats_lock;
+ struct dispc_irq_stats irq_stats;
+#endif
+} dispc_compat;
+
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dispc_dump_irqs(struct seq_file *s)
+{
+ unsigned long flags;
+ struct dispc_irq_stats stats;
+
+ spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
+
+ stats = dispc_compat.irq_stats;
+ memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
+ dispc_compat.irq_stats.last_reset = jiffies;
+
+ spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
+
+ seq_printf(s, "period %u ms\n",
+ jiffies_to_msecs(jiffies - stats.last_reset));
+
+ seq_printf(s, "irqs %d\n", stats.irq_count);
+#define PIS(x) \
+ seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
+
+ PIS(FRAMEDONE);
+ PIS(VSYNC);
+ PIS(EVSYNC_EVEN);
+ PIS(EVSYNC_ODD);
+ PIS(ACBIAS_COUNT_STAT);
+ PIS(PROG_LINE_NUM);
+ PIS(GFX_FIFO_UNDERFLOW);
+ PIS(GFX_END_WIN);
+ PIS(PAL_GAMMA_MASK);
+ PIS(OCP_ERR);
+ PIS(VID1_FIFO_UNDERFLOW);
+ PIS(VID1_END_WIN);
+ PIS(VID2_FIFO_UNDERFLOW);
+ PIS(VID2_END_WIN);
+ if (dss_feat_get_num_ovls() > 3) {
+ PIS(VID3_FIFO_UNDERFLOW);
+ PIS(VID3_END_WIN);
+ }
+ PIS(SYNC_LOST);
+ PIS(SYNC_LOST_DIGIT);
+ PIS(WAKEUP);
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ PIS(FRAMEDONE2);
+ PIS(VSYNC2);
+ PIS(ACBIAS_COUNT_STAT2);
+ PIS(SYNC_LOST2);
+ }
+ if (dss_has_feature(FEAT_MGR_LCD3)) {
+ PIS(FRAMEDONE3);
+ PIS(VSYNC3);
+ PIS(ACBIAS_COUNT_STAT3);
+ PIS(SYNC_LOST3);
+ }
+#undef PIS
+}
+#endif
+
+/* dispc.irq_lock has to be locked by the caller */
+static void _omap_dispc_set_irqs(void)
+{
+ u32 mask;
+ int i;
+ struct omap_dispc_isr_data *isr_data;
+
+ mask = dispc_compat.irq_error_mask;
+
+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
+ isr_data = &dispc_compat.registered_isr[i];
+
+ if (isr_data->isr == NULL)
+ continue;
+
+ mask |= isr_data->mask;
+ }
+
+ dispc_write_irqenable(mask);
+}
+
+int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
+{
+ int i;
+ int ret;
+ unsigned long flags;
+ struct omap_dispc_isr_data *isr_data;
+
+ if (isr == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dispc_compat.irq_lock, flags);
+
+ /* check for duplicate entry */
+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
+ isr_data = &dispc_compat.registered_isr[i];
+ if (isr_data->isr == isr && isr_data->arg == arg &&
+ isr_data->mask == mask) {
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ isr_data = NULL;
+ ret = -EBUSY;
+
+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
+ isr_data = &dispc_compat.registered_isr[i];
+
+ if (isr_data->isr != NULL)
+ continue;
+
+ isr_data->isr = isr;
+ isr_data->arg = arg;
+ isr_data->mask = mask;
+ ret = 0;
+
+ break;
+ }
+
+ if (ret)
+ goto err;
+
+ _omap_dispc_set_irqs();
+
+ spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
+
+ return 0;
+err:
+ spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(omap_dispc_register_isr);
+
+int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
+{
+ int i;
+ unsigned long flags;
+ int ret = -EINVAL;
+ struct omap_dispc_isr_data *isr_data;
+
+ spin_lock_irqsave(&dispc_compat.irq_lock, flags);
+
+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
+ isr_data = &dispc_compat.registered_isr[i];
+ if (isr_data->isr != isr || isr_data->arg != arg ||
+ isr_data->mask != mask)
+ continue;
+
+ /* found the correct isr */
+
+ isr_data->isr = NULL;
+ isr_data->arg = NULL;
+ isr_data->mask = 0;
+
+ ret = 0;
+ break;
+ }
+
+ if (ret == 0)
+ _omap_dispc_set_irqs();
+
+ spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(omap_dispc_unregister_isr);
+
+static void print_irq_status(u32 status)
+{
+ if ((status & dispc_compat.irq_error_mask) == 0)
+ return;
+
+#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
+
+ pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
+ status,
+ PIS(OCP_ERR),
+ PIS(GFX_FIFO_UNDERFLOW),
+ PIS(VID1_FIFO_UNDERFLOW),
+ PIS(VID2_FIFO_UNDERFLOW),
+ dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
+ PIS(SYNC_LOST),
+ PIS(SYNC_LOST_DIGIT),
+ dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
+ dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
+#undef PIS
+}
+
+/* Called from dss.c. Note that we don't touch clocks here,
+ * but we presume they are on because we got an IRQ. However,
+ * an irq handler may turn the clocks off, so we may not have
+ * clock later in the function. */
+static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
+{
+ int i;
+ u32 irqstatus, irqenable;
+ u32 handledirqs = 0;
+ u32 unhandled_errors;
+ struct omap_dispc_isr_data *isr_data;
+ struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
+
+ spin_lock(&dispc_compat.irq_lock);
+
+ irqstatus = dispc_read_irqstatus();
+ irqenable = dispc_read_irqenable();
+
+ /* IRQ is not for us */
+ if (!(irqstatus & irqenable)) {
+ spin_unlock(&dispc_compat.irq_lock);
+ return IRQ_NONE;
+ }
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_lock(&dispc_compat.irq_stats_lock);
+ dispc_compat.irq_stats.irq_count++;
+ dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
+ spin_unlock(&dispc_compat.irq_stats_lock);
+#endif
+
+ print_irq_status(irqstatus);
+
+ /* Ack the interrupt. Do it here before clocks are possibly turned
+ * off */
+ dispc_clear_irqstatus(irqstatus);
+ /* flush posted write */
+ dispc_read_irqstatus();
+
+ /* make a copy and unlock, so that isrs can unregister
+ * themselves */
+ memcpy(registered_isr, dispc_compat.registered_isr,
+ sizeof(registered_isr));
+
+ spin_unlock(&dispc_compat.irq_lock);
+
+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
+ isr_data = &registered_isr[i];
+
+ if (!isr_data->isr)
+ continue;
+
+ if (isr_data->mask & irqstatus) {
+ isr_data->isr(isr_data->arg, irqstatus);
+ handledirqs |= isr_data->mask;
+ }
+ }
+
+ spin_lock(&dispc_compat.irq_lock);
+
+ unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
+
+ if (unhandled_errors) {
+ dispc_compat.error_irqs |= unhandled_errors;
+
+ dispc_compat.irq_error_mask &= ~unhandled_errors;
+ _omap_dispc_set_irqs();
+
+ schedule_work(&dispc_compat.error_work);
+ }
+
+ spin_unlock(&dispc_compat.irq_lock);
+
+ return IRQ_HANDLED;
+}
+
+static void dispc_error_worker(struct work_struct *work)
+{
+ int i;
+ u32 errors;
+ unsigned long flags;
+ static const unsigned fifo_underflow_bits[] = {
+ DISPC_IRQ_GFX_FIFO_UNDERFLOW,
+ DISPC_IRQ_VID1_FIFO_UNDERFLOW,
+ DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+ DISPC_IRQ_VID3_FIFO_UNDERFLOW,
+ };
+
+ spin_lock_irqsave(&dispc_compat.irq_lock, flags);
+ errors = dispc_compat.error_irqs;
+ dispc_compat.error_irqs = 0;
+ spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
+
+ dispc_runtime_get();
+
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl;
+ unsigned bit;
+
+ ovl = omap_dss_get_overlay(i);
+ bit = fifo_underflow_bits[i];
+
+ if (bit & errors) {
+ DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
+ ovl->name);
+ ovl->disable(ovl);
+ msleep(50);
+ }
+ }
+
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ struct omap_overlay_manager *mgr;
+ unsigned bit;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ bit = dispc_mgr_get_sync_lost_irq(i);
+
+ if (bit & errors) {
+ int j;
+
+ DSSERR("SYNC_LOST on channel %s, restarting the output "
+ "with video overlays disabled\n",
+ mgr->name);
+
+ dss_mgr_disable(mgr);
+
+ for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
+ struct omap_overlay *ovl;
+ ovl = omap_dss_get_overlay(j);
+
+ if (ovl->id != OMAP_DSS_GFX &&
+ ovl->manager == mgr)
+ ovl->disable(ovl);
+ }
+
+ dss_mgr_enable(mgr);
+ }
+ }
+
+ if (errors & DISPC_IRQ_OCP_ERR) {
+ DSSERR("OCP_ERR\n");
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ struct omap_overlay_manager *mgr;
+
+ mgr = omap_dss_get_overlay_manager(i);
+ dss_mgr_disable(mgr);
+ }
+ }
+
+ spin_lock_irqsave(&dispc_compat.irq_lock, flags);
+ dispc_compat.irq_error_mask |= errors;
+ _omap_dispc_set_irqs();
+ spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
+
+ dispc_runtime_put();
+}
+
+int dss_dispc_initialize_irq(void)
+{
+ int r;
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_lock_init(&dispc_compat.irq_stats_lock);
+ dispc_compat.irq_stats.last_reset = jiffies;
+ dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
+#endif
+
+ spin_lock_init(&dispc_compat.irq_lock);
+
+ memset(dispc_compat.registered_isr, 0,
+ sizeof(dispc_compat.registered_isr));
+
+ dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
+ if (dss_has_feature(FEAT_MGR_LCD3))
+ dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
+ if (dss_feat_get_num_ovls() > 3)
+ dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
+
+ /*
+ * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
+ * so clear it
+ */
+ dispc_clear_irqstatus(dispc_read_irqstatus());
+
+ INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
+
+ _omap_dispc_set_irqs();
+
+ r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
+ if (r) {
+ DSSERR("dispc_request_irq failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+void dss_dispc_uninitialize_irq(void)
+{
+ dispc_free_irq(&dispc_compat);
+}
+
+static void dispc_mgr_disable_isr(void *data, u32 mask)
+{
+ struct completion *compl = data;
+ complete(compl);
+}
+
+static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
+{
+ dispc_mgr_enable(channel, true);
+}
+
+static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
+{
+ DECLARE_COMPLETION_ONSTACK(framedone_compl);
+ int r;
+ u32 irq;
+
+ if (!dispc_mgr_is_enabled(channel))
+ return;
+
+ /*
+ * When we disable LCD output, we need to wait for FRAMEDONE to know
+ * that DISPC has finished with the LCD output.
+ */
+
+ irq = dispc_mgr_get_framedone_irq(channel);
+
+ r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
+ irq);
+ if (r)
+ DSSERR("failed to register FRAMEDONE isr\n");
+
+ dispc_mgr_enable(channel, false);
+
+ /* if we couldn't register for framedone, just sleep and exit */
+ if (r) {
+ msleep(100);
+ return;
+ }
+
+ if (!wait_for_completion_timeout(&framedone_compl,
+ msecs_to_jiffies(100)))
+ DSSERR("timeout waiting for FRAME DONE\n");
+
+ r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
+ irq);
+ if (r)
+ DSSERR("failed to unregister FRAMEDONE isr\n");
+}
+
+static void dispc_digit_out_enable_isr(void *data, u32 mask)
+{
+ struct completion *compl = data;
+
+ /* ignore any sync lost interrupts */
+ if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
+ complete(compl);
+}
+
+static void dispc_mgr_enable_digit_out(void)
+{
+ DECLARE_COMPLETION_ONSTACK(vsync_compl);
+ int r;
+ u32 irq_mask;
+
+ if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
+ return;
+
+ /*
+ * Digit output produces some sync lost interrupts during the first
+ * frame when enabling. Those need to be ignored, so we register for the
+ * sync lost irq to prevent the error handler from triggering.
+ */
+
+ irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
+ dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
+
+ r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
+ irq_mask);
+ if (r) {
+ DSSERR("failed to register %x isr\n", irq_mask);
+ return;
+ }
+
+ dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
+
+ /* wait for the first evsync */
+ if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
+ DSSERR("timeout waiting for digit out to start\n");
+
+ r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
+ irq_mask);
+ if (r)
+ DSSERR("failed to unregister %x isr\n", irq_mask);
+}
+
+static void dispc_mgr_disable_digit_out(void)
+{
+ DECLARE_COMPLETION_ONSTACK(framedone_compl);
+ int r, i;
+ u32 irq_mask;
+ int num_irqs;
+
+ if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
+ return;
+
+ /*
+ * When we disable the digit output, we need to wait for FRAMEDONE to
+ * know that DISPC has finished with the output.
+ */
+
+ irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
+ num_irqs = 1;
+
+ if (!irq_mask) {
+ /*
+ * omap 2/3 don't have framedone irq for TV, so we need to use
+ * vsyncs for this.
+ */
+
+ irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
+ /*
+ * We need to wait for both even and odd vsyncs. Note that this
+ * is not totally reliable, as we could get a vsync interrupt
+ * before we disable the output, which leads to timeout in the
+ * wait_for_completion.
+ */
+ num_irqs = 2;
+ }
+
+ r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
+ irq_mask);
+ if (r)
+ DSSERR("failed to register %x isr\n", irq_mask);
+
+ dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
+
+ /* if we couldn't register the irq, just sleep and exit */
+ if (r) {
+ msleep(100);
+ return;
+ }
+
+ for (i = 0; i < num_irqs; ++i) {
+ if (!wait_for_completion_timeout(&framedone_compl,
+ msecs_to_jiffies(100)))
+ DSSERR("timeout waiting for digit out to stop\n");
+ }
+
+ r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
+ irq_mask);
+ if (r)
+ DSSERR("failed to unregister %x isr\n", irq_mask);
+}
+
+void dispc_mgr_enable_sync(enum omap_channel channel)
+{
+ if (dss_mgr_is_lcd(channel))
+ dispc_mgr_enable_lcd_out(channel);
+ else if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ dispc_mgr_enable_digit_out();
+ else
+ WARN_ON(1);
+}
+
+void dispc_mgr_disable_sync(enum omap_channel channel)
+{
+ if (dss_mgr_is_lcd(channel))
+ dispc_mgr_disable_lcd_out(channel);
+ else if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ dispc_mgr_disable_digit_out();
+ else
+ WARN_ON(1);
+}
+
+static inline void dispc_irq_wait_handler(void *data, u32 mask)
+{
+ complete((struct completion *)data);
+}
+
+int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
+ unsigned long timeout)
+{
+
+ int r;
+ DECLARE_COMPLETION_ONSTACK(completion);
+
+ r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
+ irqmask);
+
+ if (r)
+ return r;
+
+ timeout = wait_for_completion_interruptible_timeout(&completion,
+ timeout);
+
+ omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ if (timeout == -ERESTARTSYS)
+ return -ERESTARTSYS;
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h
new file mode 100644
index 000000000000..14a69b3d4fb0
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DSS_DISPC_COMPAT_H
+#define __OMAP2_DSS_DISPC_COMPAT_H
+
+void dispc_mgr_enable_sync(enum omap_channel channel);
+void dispc_mgr_disable_sync(enum omap_channel channel);
+
+int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
+ unsigned long timeout);
+
+int dss_dispc_initialize_irq(void);
+void dss_dispc_uninitialize_irq(void);
+
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c
new file mode 100644
index 000000000000..5491e304f4fe
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c
@@ -0,0 +1,4234 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "DISPC"
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/export.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/hardirq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+#include "dispc.h"
+
+/* DISPC */
+#define DISPC_SZ_REGS SZ_4K
+
+enum omap_burst_size {
+ BURST_SIZE_X2 = 0,
+ BURST_SIZE_X4 = 1,
+ BURST_SIZE_X8 = 2,
+};
+
+#define REG_GET(idx, start, end) \
+ FLD_GET(dispc_read_reg(idx), start, end)
+
+#define REG_FLD_MOD(idx, val, start, end) \
+ dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
+
+struct dispc_features {
+ u8 sw_start;
+ u8 fp_start;
+ u8 bp_start;
+ u16 sw_max;
+ u16 vp_max;
+ u16 hp_max;
+ u8 mgr_width_start;
+ u8 mgr_height_start;
+ u16 mgr_width_max;
+ u16 mgr_height_max;
+ unsigned long max_lcd_pclk;
+ unsigned long max_tv_pclk;
+ int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
+ unsigned long (*calc_core_clk) (unsigned long pclk,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ bool mem_to_mem);
+ u8 num_fifos;
+
+ /* swap GFX & WB fifos */
+ bool gfx_fifo_workaround:1;
+
+ /* no DISPC_IRQ_FRAMEDONETV on this SoC */
+ bool no_framedone_tv:1;
+
+ /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
+ bool mstandby_workaround:1;
+
+ bool set_max_preload:1;
+
+ /* PIXEL_INC is not added to the last pixel of a line */
+ bool last_pixel_inc_missing:1;
+
+ /* POL_FREQ has ALIGN bit */
+ bool supports_sync_align:1;
+
+ bool has_writeback:1;
+};
+
+#define DISPC_MAX_NR_FIFOS 5
+
+static struct {
+ struct platform_device *pdev;
+ void __iomem *base;
+
+ int irq;
+ irq_handler_t user_handler;
+ void *user_data;
+
+ unsigned long core_clk_rate;
+ unsigned long tv_pclk_rate;
+
+ u32 fifo_size[DISPC_MAX_NR_FIFOS];
+ /* maps which plane is using a fifo. fifo-id -> plane-id */
+ int fifo_assignment[DISPC_MAX_NR_FIFOS];
+
+ bool ctx_valid;
+ u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
+
+ const struct dispc_features *feat;
+
+ bool is_enabled;
+
+ struct regmap *syscon_pol;
+ u32 syscon_pol_offset;
+
+ /* DISPC_CONTROL & DISPC_CONFIG lock*/
+ spinlock_t control_lock;
+} dispc;
+
+enum omap_color_component {
+ /* used for all color formats for OMAP3 and earlier
+ * and for RGB and Y color component on OMAP4
+ */
+ DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
+ /* used for UV component for
+ * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
+ * color formats on OMAP4
+ */
+ DISPC_COLOR_COMPONENT_UV = 1 << 1,
+};
+
+enum mgr_reg_fields {
+ DISPC_MGR_FLD_ENABLE,
+ DISPC_MGR_FLD_STNTFT,
+ DISPC_MGR_FLD_GO,
+ DISPC_MGR_FLD_TFTDATALINES,
+ DISPC_MGR_FLD_STALLMODE,
+ DISPC_MGR_FLD_TCKENABLE,
+ DISPC_MGR_FLD_TCKSELECTION,
+ DISPC_MGR_FLD_CPR,
+ DISPC_MGR_FLD_FIFOHANDCHECK,
+ /* used to maintain a count of the above fields */
+ DISPC_MGR_FLD_NUM,
+};
+
+struct dispc_reg_field {
+ u16 reg;
+ u8 high;
+ u8 low;
+};
+
+static const struct {
+ const char *name;
+ u32 vsync_irq;
+ u32 framedone_irq;
+ u32 sync_lost_irq;
+ struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
+} mgr_desc[] = {
+ [OMAP_DSS_CHANNEL_LCD] = {
+ .name = "LCD",
+ .vsync_irq = DISPC_IRQ_VSYNC,
+ .framedone_irq = DISPC_IRQ_FRAMEDONE,
+ .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
+ .reg_desc = {
+ [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
+ [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
+ [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
+ [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
+ [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
+ [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
+ [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
+ [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
+ [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
+ },
+ },
+ [OMAP_DSS_CHANNEL_DIGIT] = {
+ .name = "DIGIT",
+ .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
+ .framedone_irq = DISPC_IRQ_FRAMEDONETV,
+ .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
+ .reg_desc = {
+ [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
+ [DISPC_MGR_FLD_STNTFT] = { },
+ [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
+ [DISPC_MGR_FLD_TFTDATALINES] = { },
+ [DISPC_MGR_FLD_STALLMODE] = { },
+ [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
+ [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
+ [DISPC_MGR_FLD_CPR] = { },
+ [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
+ },
+ },
+ [OMAP_DSS_CHANNEL_LCD2] = {
+ .name = "LCD2",
+ .vsync_irq = DISPC_IRQ_VSYNC2,
+ .framedone_irq = DISPC_IRQ_FRAMEDONE2,
+ .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
+ .reg_desc = {
+ [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
+ [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
+ [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
+ [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
+ [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
+ [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
+ [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
+ [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
+ [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
+ },
+ },
+ [OMAP_DSS_CHANNEL_LCD3] = {
+ .name = "LCD3",
+ .vsync_irq = DISPC_IRQ_VSYNC3,
+ .framedone_irq = DISPC_IRQ_FRAMEDONE3,
+ .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
+ .reg_desc = {
+ [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
+ [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
+ [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
+ [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
+ [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
+ [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
+ [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
+ [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
+ [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
+ },
+ },
+};
+
+struct color_conv_coef {
+ int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
+ int full_range;
+};
+
+static unsigned long dispc_fclk_rate(void);
+static unsigned long dispc_core_clk_rate(void);
+static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
+static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
+
+static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
+static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
+
+static inline void dispc_write_reg(const u16 idx, u32 val)
+{
+ __raw_writel(val, dispc.base + idx);
+}
+
+static inline u32 dispc_read_reg(const u16 idx)
+{
+ return __raw_readl(dispc.base + idx);
+}
+
+static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
+{
+ const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
+ return REG_GET(rfld.reg, rfld.high, rfld.low);
+}
+
+static void mgr_fld_write(enum omap_channel channel,
+ enum mgr_reg_fields regfld, int val) {
+ const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
+ const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG;
+ unsigned long flags;
+
+ if (need_lock)
+ spin_lock_irqsave(&dispc.control_lock, flags);
+
+ REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
+
+ if (need_lock)
+ spin_unlock_irqrestore(&dispc.control_lock, flags);
+}
+
+#define SR(reg) \
+ dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
+#define RR(reg) \
+ dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
+
+static void dispc_save_context(void)
+{
+ int i, j;
+
+ DSSDBG("dispc_save_context\n");
+
+ SR(IRQENABLE);
+ SR(CONTROL);
+ SR(CONFIG);
+ SR(LINE_NUMBER);
+ if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+ dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
+ SR(GLOBAL_ALPHA);
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ SR(CONTROL2);
+ SR(CONFIG2);
+ }
+ if (dss_has_feature(FEAT_MGR_LCD3)) {
+ SR(CONTROL3);
+ SR(CONFIG3);
+ }
+
+ for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
+ SR(DEFAULT_COLOR(i));
+ SR(TRANS_COLOR(i));
+ SR(SIZE_MGR(i));
+ if (i == OMAP_DSS_CHANNEL_DIGIT)
+ continue;
+ SR(TIMING_H(i));
+ SR(TIMING_V(i));
+ SR(POL_FREQ(i));
+ SR(DIVISORo(i));
+
+ SR(DATA_CYCLE1(i));
+ SR(DATA_CYCLE2(i));
+ SR(DATA_CYCLE3(i));
+
+ if (dss_has_feature(FEAT_CPR)) {
+ SR(CPR_COEF_R(i));
+ SR(CPR_COEF_G(i));
+ SR(CPR_COEF_B(i));
+ }
+ }
+
+ for (i = 0; i < dss_feat_get_num_ovls(); i++) {
+ SR(OVL_BA0(i));
+ SR(OVL_BA1(i));
+ SR(OVL_POSITION(i));
+ SR(OVL_SIZE(i));
+ SR(OVL_ATTRIBUTES(i));
+ SR(OVL_FIFO_THRESHOLD(i));
+ SR(OVL_ROW_INC(i));
+ SR(OVL_PIXEL_INC(i));
+ if (dss_has_feature(FEAT_PRELOAD))
+ SR(OVL_PRELOAD(i));
+ if (i == OMAP_DSS_GFX) {
+ SR(OVL_WINDOW_SKIP(i));
+ SR(OVL_TABLE_BA(i));
+ continue;
+ }
+ SR(OVL_FIR(i));
+ SR(OVL_PICTURE_SIZE(i));
+ SR(OVL_ACCU0(i));
+ SR(OVL_ACCU1(i));
+
+ for (j = 0; j < 8; j++)
+ SR(OVL_FIR_COEF_H(i, j));
+
+ for (j = 0; j < 8; j++)
+ SR(OVL_FIR_COEF_HV(i, j));
+
+ for (j = 0; j < 5; j++)
+ SR(OVL_CONV_COEF(i, j));
+
+ if (dss_has_feature(FEAT_FIR_COEF_V)) {
+ for (j = 0; j < 8; j++)
+ SR(OVL_FIR_COEF_V(i, j));
+ }
+
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ SR(OVL_BA0_UV(i));
+ SR(OVL_BA1_UV(i));
+ SR(OVL_FIR2(i));
+ SR(OVL_ACCU2_0(i));
+ SR(OVL_ACCU2_1(i));
+
+ for (j = 0; j < 8; j++)
+ SR(OVL_FIR_COEF_H2(i, j));
+
+ for (j = 0; j < 8; j++)
+ SR(OVL_FIR_COEF_HV2(i, j));
+
+ for (j = 0; j < 8; j++)
+ SR(OVL_FIR_COEF_V2(i, j));
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ SR(OVL_ATTRIBUTES2(i));
+ }
+
+ if (dss_has_feature(FEAT_CORE_CLK_DIV))
+ SR(DIVISOR);
+
+ dispc.ctx_valid = true;
+
+ DSSDBG("context saved\n");
+}
+
+static void dispc_restore_context(void)
+{
+ int i, j;
+
+ DSSDBG("dispc_restore_context\n");
+
+ if (!dispc.ctx_valid)
+ return;
+
+ /*RR(IRQENABLE);*/
+ /*RR(CONTROL);*/
+ RR(CONFIG);
+ RR(LINE_NUMBER);
+ if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+ dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
+ RR(GLOBAL_ALPHA);
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ RR(CONFIG2);
+ if (dss_has_feature(FEAT_MGR_LCD3))
+ RR(CONFIG3);
+
+ for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
+ RR(DEFAULT_COLOR(i));
+ RR(TRANS_COLOR(i));
+ RR(SIZE_MGR(i));
+ if (i == OMAP_DSS_CHANNEL_DIGIT)
+ continue;
+ RR(TIMING_H(i));
+ RR(TIMING_V(i));
+ RR(POL_FREQ(i));
+ RR(DIVISORo(i));
+
+ RR(DATA_CYCLE1(i));
+ RR(DATA_CYCLE2(i));
+ RR(DATA_CYCLE3(i));
+
+ if (dss_has_feature(FEAT_CPR)) {
+ RR(CPR_COEF_R(i));
+ RR(CPR_COEF_G(i));
+ RR(CPR_COEF_B(i));
+ }
+ }
+
+ for (i = 0; i < dss_feat_get_num_ovls(); i++) {
+ RR(OVL_BA0(i));
+ RR(OVL_BA1(i));
+ RR(OVL_POSITION(i));
+ RR(OVL_SIZE(i));
+ RR(OVL_ATTRIBUTES(i));
+ RR(OVL_FIFO_THRESHOLD(i));
+ RR(OVL_ROW_INC(i));
+ RR(OVL_PIXEL_INC(i));
+ if (dss_has_feature(FEAT_PRELOAD))
+ RR(OVL_PRELOAD(i));
+ if (i == OMAP_DSS_GFX) {
+ RR(OVL_WINDOW_SKIP(i));
+ RR(OVL_TABLE_BA(i));
+ continue;
+ }
+ RR(OVL_FIR(i));
+ RR(OVL_PICTURE_SIZE(i));
+ RR(OVL_ACCU0(i));
+ RR(OVL_ACCU1(i));
+
+ for (j = 0; j < 8; j++)
+ RR(OVL_FIR_COEF_H(i, j));
+
+ for (j = 0; j < 8; j++)
+ RR(OVL_FIR_COEF_HV(i, j));
+
+ for (j = 0; j < 5; j++)
+ RR(OVL_CONV_COEF(i, j));
+
+ if (dss_has_feature(FEAT_FIR_COEF_V)) {
+ for (j = 0; j < 8; j++)
+ RR(OVL_FIR_COEF_V(i, j));
+ }
+
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ RR(OVL_BA0_UV(i));
+ RR(OVL_BA1_UV(i));
+ RR(OVL_FIR2(i));
+ RR(OVL_ACCU2_0(i));
+ RR(OVL_ACCU2_1(i));
+
+ for (j = 0; j < 8; j++)
+ RR(OVL_FIR_COEF_H2(i, j));
+
+ for (j = 0; j < 8; j++)
+ RR(OVL_FIR_COEF_HV2(i, j));
+
+ for (j = 0; j < 8; j++)
+ RR(OVL_FIR_COEF_V2(i, j));
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ RR(OVL_ATTRIBUTES2(i));
+ }
+
+ if (dss_has_feature(FEAT_CORE_CLK_DIV))
+ RR(DIVISOR);
+
+ /* enable last, because LCD & DIGIT enable are here */
+ RR(CONTROL);
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ RR(CONTROL2);
+ if (dss_has_feature(FEAT_MGR_LCD3))
+ RR(CONTROL3);
+ /* clear spurious SYNC_LOST_DIGIT interrupts */
+ dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT);
+
+ /*
+ * enable last so IRQs won't trigger before
+ * the context is fully restored
+ */
+ RR(IRQENABLE);
+
+ DSSDBG("context restored\n");
+}
+
+#undef SR
+#undef RR
+
+int dispc_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("dispc_runtime_get\n");
+
+ r = pm_runtime_get_sync(&dispc.pdev->dev);
+ WARN_ON(r < 0);
+ return r < 0 ? r : 0;
+}
+EXPORT_SYMBOL(dispc_runtime_get);
+
+void dispc_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("dispc_runtime_put\n");
+
+ r = pm_runtime_put_sync(&dispc.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+EXPORT_SYMBOL(dispc_runtime_put);
+
+u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
+{
+ return mgr_desc[channel].vsync_irq;
+}
+EXPORT_SYMBOL(dispc_mgr_get_vsync_irq);
+
+u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
+{
+ if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
+ return 0;
+
+ return mgr_desc[channel].framedone_irq;
+}
+EXPORT_SYMBOL(dispc_mgr_get_framedone_irq);
+
+u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
+{
+ return mgr_desc[channel].sync_lost_irq;
+}
+EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq);
+
+u32 dispc_wb_get_framedone_irq(void)
+{
+ return DISPC_IRQ_FRAMEDONEWB;
+}
+
+bool dispc_mgr_go_busy(enum omap_channel channel)
+{
+ return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
+}
+EXPORT_SYMBOL(dispc_mgr_go_busy);
+
+void dispc_mgr_go(enum omap_channel channel)
+{
+ WARN_ON(!dispc_mgr_is_enabled(channel));
+ WARN_ON(dispc_mgr_go_busy(channel));
+
+ DSSDBG("GO %s\n", mgr_desc[channel].name);
+
+ mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
+}
+EXPORT_SYMBOL(dispc_mgr_go);
+
+bool dispc_wb_go_busy(void)
+{
+ return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
+}
+
+void dispc_wb_go(void)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+ bool enable, go;
+
+ enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
+
+ if (!enable)
+ return;
+
+ go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
+ if (go) {
+ DSSERR("GO bit not down for WB\n");
+ return;
+ }
+
+ REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
+}
+
+static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
+{
+ dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
+}
+
+static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
+{
+ dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
+}
+
+static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
+{
+ dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
+}
+
+static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
+{
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
+}
+
+static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
+ u32 value)
+{
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
+}
+
+static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
+{
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
+}
+
+static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
+ int fir_vinc, int five_taps,
+ enum omap_color_component color_comp)
+{
+ const struct dispc_coef *h_coef, *v_coef;
+ int i;
+
+ h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
+ v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
+
+ for (i = 0; i < 8; i++) {
+ u32 h, hv;
+
+ h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
+ | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
+ | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
+ | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
+ hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
+ | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
+ | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
+ | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
+
+ if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
+ dispc_ovl_write_firh_reg(plane, i, h);
+ dispc_ovl_write_firhv_reg(plane, i, hv);
+ } else {
+ dispc_ovl_write_firh2_reg(plane, i, h);
+ dispc_ovl_write_firhv2_reg(plane, i, hv);
+ }
+
+ }
+
+ if (five_taps) {
+ for (i = 0; i < 8; i++) {
+ u32 v;
+ v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
+ | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
+ if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
+ dispc_ovl_write_firv_reg(plane, i, v);
+ else
+ dispc_ovl_write_firv2_reg(plane, i, v);
+ }
+ }
+}
+
+
+static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
+ const struct color_conv_coef *ct)
+{
+#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
+
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
+
+#undef CVAL
+}
+
+static void dispc_setup_color_conv_coef(void)
+{
+ int i;
+ int num_ovl = dss_feat_get_num_ovls();
+ const struct color_conv_coef ctbl_bt601_5_ovl = {
+ /* YUV -> RGB */
+ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
+ };
+ const struct color_conv_coef ctbl_bt601_5_wb = {
+ /* RGB -> YUV */
+ 66, 129, 25, 112, -94, -18, -38, -74, 112, 0,
+ };
+
+ for (i = 1; i < num_ovl; i++)
+ dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
+
+ if (dispc.feat->has_writeback)
+ dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb);
+}
+
+static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
+{
+ dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
+}
+
+static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
+{
+ dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
+}
+
+static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
+{
+ dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
+}
+
+static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
+{
+ dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
+}
+
+static void dispc_ovl_set_pos(enum omap_plane plane,
+ enum omap_overlay_caps caps, int x, int y)
+{
+ u32 val;
+
+ if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
+ return;
+
+ val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
+
+ dispc_write_reg(DISPC_OVL_POSITION(plane), val);
+}
+
+static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
+ int height)
+{
+ u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
+
+ if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
+ dispc_write_reg(DISPC_OVL_SIZE(plane), val);
+ else
+ dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
+}
+
+static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
+ int height)
+{
+ u32 val;
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
+
+ if (plane == OMAP_DSS_WB)
+ dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
+ else
+ dispc_write_reg(DISPC_OVL_SIZE(plane), val);
+}
+
+static void dispc_ovl_set_zorder(enum omap_plane plane,
+ enum omap_overlay_caps caps, u8 zorder)
+{
+ if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+ return;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
+}
+
+static void dispc_ovl_enable_zorder_planes(void)
+{
+ int i;
+
+ if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
+ return;
+
+ for (i = 0; i < dss_feat_get_num_ovls(); i++)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
+}
+
+static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
+ enum omap_overlay_caps caps, bool enable)
+{
+ if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+ return;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
+}
+
+static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
+ enum omap_overlay_caps caps, u8 global_alpha)
+{
+ static const unsigned shifts[] = { 0, 8, 16, 24, };
+ int shift;
+
+ if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+ return;
+
+ shift = shifts[plane];
+ REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
+}
+
+static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
+{
+ dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
+}
+
+static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
+{
+ dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
+}
+
+static void dispc_ovl_set_color_mode(enum omap_plane plane,
+ enum omap_color_mode color_mode)
+{
+ u32 m = 0;
+ if (plane != OMAP_DSS_GFX) {
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ m = 0x0; break;
+ case OMAP_DSS_COLOR_RGBX16:
+ m = 0x1; break;
+ case OMAP_DSS_COLOR_RGBA16:
+ m = 0x2; break;
+ case OMAP_DSS_COLOR_RGB12U:
+ m = 0x4; break;
+ case OMAP_DSS_COLOR_ARGB16:
+ m = 0x5; break;
+ case OMAP_DSS_COLOR_RGB16:
+ m = 0x6; break;
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ m = 0x7; break;
+ case OMAP_DSS_COLOR_RGB24U:
+ m = 0x8; break;
+ case OMAP_DSS_COLOR_RGB24P:
+ m = 0x9; break;
+ case OMAP_DSS_COLOR_YUV2:
+ m = 0xa; break;
+ case OMAP_DSS_COLOR_UYVY:
+ m = 0xb; break;
+ case OMAP_DSS_COLOR_ARGB32:
+ m = 0xc; break;
+ case OMAP_DSS_COLOR_RGBA32:
+ m = 0xd; break;
+ case OMAP_DSS_COLOR_RGBX32:
+ m = 0xe; break;
+ case OMAP_DSS_COLOR_XRGB16_1555:
+ m = 0xf; break;
+ default:
+ BUG(); return;
+ }
+ } else {
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_CLUT1:
+ m = 0x0; break;
+ case OMAP_DSS_COLOR_CLUT2:
+ m = 0x1; break;
+ case OMAP_DSS_COLOR_CLUT4:
+ m = 0x2; break;
+ case OMAP_DSS_COLOR_CLUT8:
+ m = 0x3; break;
+ case OMAP_DSS_COLOR_RGB12U:
+ m = 0x4; break;
+ case OMAP_DSS_COLOR_ARGB16:
+ m = 0x5; break;
+ case OMAP_DSS_COLOR_RGB16:
+ m = 0x6; break;
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ m = 0x7; break;
+ case OMAP_DSS_COLOR_RGB24U:
+ m = 0x8; break;
+ case OMAP_DSS_COLOR_RGB24P:
+ m = 0x9; break;
+ case OMAP_DSS_COLOR_RGBX16:
+ m = 0xa; break;
+ case OMAP_DSS_COLOR_RGBA16:
+ m = 0xb; break;
+ case OMAP_DSS_COLOR_ARGB32:
+ m = 0xc; break;
+ case OMAP_DSS_COLOR_RGBA32:
+ m = 0xd; break;
+ case OMAP_DSS_COLOR_RGBX32:
+ m = 0xe; break;
+ case OMAP_DSS_COLOR_XRGB16_1555:
+ m = 0xf; break;
+ default:
+ BUG(); return;
+ }
+ }
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
+}
+
+static void dispc_ovl_configure_burst_type(enum omap_plane plane,
+ enum omap_dss_rotation_type rotation_type)
+{
+ if (dss_has_feature(FEAT_BURST_2D) == 0)
+ return;
+
+ if (rotation_type == OMAP_DSS_ROT_TILER)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
+ else
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
+}
+
+void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
+{
+ int shift;
+ u32 val;
+ int chan = 0, chan2 = 0;
+
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ shift = 8;
+ break;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
+ shift = 16;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ chan = 0;
+ chan2 = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ chan = 1;
+ chan2 = 0;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ chan = 0;
+ chan2 = 1;
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ if (dss_has_feature(FEAT_MGR_LCD3)) {
+ chan = 0;
+ chan2 = 2;
+ } else {
+ BUG();
+ return;
+ }
+ break;
+ case OMAP_DSS_CHANNEL_WB:
+ chan = 0;
+ chan2 = 3;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ val = FLD_MOD(val, chan, shift, shift);
+ val = FLD_MOD(val, chan2, 31, 30);
+ } else {
+ val = FLD_MOD(val, channel, shift, shift);
+ }
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
+}
+EXPORT_SYMBOL(dispc_ovl_set_channel_out);
+
+static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
+{
+ int shift;
+ u32 val;
+
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ shift = 8;
+ break;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
+ shift = 16;
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+
+ if (FLD_GET(val, shift, shift) == 1)
+ return OMAP_DSS_CHANNEL_DIGIT;
+
+ if (!dss_has_feature(FEAT_MGR_LCD2))
+ return OMAP_DSS_CHANNEL_LCD;
+
+ switch (FLD_GET(val, 31, 30)) {
+ case 0:
+ default:
+ return OMAP_DSS_CHANNEL_LCD;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD2;
+ case 2:
+ return OMAP_DSS_CHANNEL_LCD3;
+ case 3:
+ return OMAP_DSS_CHANNEL_WB;
+ }
+}
+
+void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
+}
+
+static void dispc_ovl_set_burst_size(enum omap_plane plane,
+ enum omap_burst_size burst_size)
+{
+ static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
+ int shift;
+
+ shift = shifts[plane];
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
+}
+
+static void dispc_configure_burst_sizes(void)
+{
+ int i;
+ const int burst_size = BURST_SIZE_X8;
+
+ /* Configure burst size always to maximum size */
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i)
+ dispc_ovl_set_burst_size(i, burst_size);
+ if (dispc.feat->has_writeback)
+ dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size);
+}
+
+static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
+{
+ unsigned unit = dss_feat_get_burst_size_unit();
+ /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
+ return unit * 8;
+}
+
+void dispc_enable_gamma_table(bool enable)
+{
+ /*
+ * This is partially implemented to support only disabling of
+ * the gamma table.
+ */
+ if (enable) {
+ DSSWARN("Gamma table enabling for TV not yet supported");
+ return;
+ }
+
+ REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
+}
+
+static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
+{
+ if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ return;
+
+ mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
+}
+
+static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
+ const struct omap_dss_cpr_coefs *coefs)
+{
+ u32 coef_r, coef_g, coef_b;
+
+ if (!dss_mgr_is_lcd(channel))
+ return;
+
+ coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
+ FLD_VAL(coefs->rb, 9, 0);
+ coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
+ FLD_VAL(coefs->gb, 9, 0);
+ coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
+ FLD_VAL(coefs->bb, 9, 0);
+
+ dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
+ dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
+ dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
+}
+
+static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
+{
+ u32 val;
+
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ val = FLD_MOD(val, enable, 9, 9);
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
+}
+
+static void dispc_ovl_enable_replication(enum omap_plane plane,
+ enum omap_overlay_caps caps, bool enable)
+{
+ static const unsigned shifts[] = { 5, 10, 10, 10 };
+ int shift;
+
+ if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
+ return;
+
+ shift = shifts[plane];
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
+}
+
+static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
+ u16 height)
+{
+ u32 val;
+
+ val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) |
+ FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0);
+
+ dispc_write_reg(DISPC_SIZE_MGR(channel), val);
+}
+
+static void dispc_init_fifos(void)
+{
+ u32 size;
+ int fifo;
+ u8 start, end;
+ u32 unit;
+ int i;
+
+ unit = dss_feat_get_buffer_size_unit();
+
+ dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
+
+ for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
+ size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
+ size *= unit;
+ dispc.fifo_size[fifo] = size;
+
+ /*
+ * By default fifos are mapped directly to overlays, fifo 0 to
+ * ovl 0, fifo 1 to ovl 1, etc.
+ */
+ dispc.fifo_assignment[fifo] = fifo;
+ }
+
+ /*
+ * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
+ * causes problems with certain use cases, like using the tiler in 2D
+ * mode. The below hack swaps the fifos of GFX and WB planes, thus
+ * giving GFX plane a larger fifo. WB but should work fine with a
+ * smaller fifo.
+ */
+ if (dispc.feat->gfx_fifo_workaround) {
+ u32 v;
+
+ v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
+
+ v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
+ v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
+ v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
+ v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
+
+ dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
+
+ dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
+ dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
+ }
+
+ /*
+ * Setup default fifo thresholds.
+ */
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
+ u32 low, high;
+ const bool use_fifomerge = false;
+ const bool manual_update = false;
+
+ dispc_ovl_compute_fifo_thresholds(i, &low, &high,
+ use_fifomerge, manual_update);
+
+ dispc_ovl_set_fifo_threshold(i, low, high);
+ }
+
+ if (dispc.feat->has_writeback) {
+ u32 low, high;
+ const bool use_fifomerge = false;
+ const bool manual_update = false;
+
+ dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high,
+ use_fifomerge, manual_update);
+
+ dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high);
+ }
+}
+
+static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
+{
+ int fifo;
+ u32 size = 0;
+
+ for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
+ if (dispc.fifo_assignment[fifo] == plane)
+ size += dispc.fifo_size[fifo];
+ }
+
+ return size;
+}
+
+void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
+{
+ u8 hi_start, hi_end, lo_start, lo_end;
+ u32 unit;
+
+ unit = dss_feat_get_buffer_size_unit();
+
+ WARN_ON(low % unit != 0);
+ WARN_ON(high % unit != 0);
+
+ low /= unit;
+ high /= unit;
+
+ dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
+ dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
+
+ DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
+ plane,
+ REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
+ lo_start, lo_end) * unit,
+ REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
+ hi_start, hi_end) * unit,
+ low * unit, high * unit);
+
+ dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
+ FLD_VAL(high, hi_start, hi_end) |
+ FLD_VAL(low, lo_start, lo_end));
+
+ /*
+ * configure the preload to the pipeline's high threhold, if HT it's too
+ * large for the preload field, set the threshold to the maximum value
+ * that can be held by the preload register
+ */
+ if (dss_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload &&
+ plane != OMAP_DSS_WB)
+ dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
+}
+
+void dispc_enable_fifomerge(bool enable)
+{
+ if (!dss_has_feature(FEAT_FIFO_MERGE)) {
+ WARN_ON(enable);
+ return;
+ }
+
+ DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
+ REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
+}
+
+void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
+ u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
+ bool manual_update)
+{
+ /*
+ * All sizes are in bytes. Both the buffer and burst are made of
+ * buffer_units, and the fifo thresholds must be buffer_unit aligned.
+ */
+
+ unsigned buf_unit = dss_feat_get_buffer_size_unit();
+ unsigned ovl_fifo_size, total_fifo_size, burst_size;
+ int i;
+
+ burst_size = dispc_ovl_get_burst_size(plane);
+ ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
+
+ if (use_fifomerge) {
+ total_fifo_size = 0;
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i)
+ total_fifo_size += dispc_ovl_get_fifo_size(i);
+ } else {
+ total_fifo_size = ovl_fifo_size;
+ }
+
+ /*
+ * We use the same low threshold for both fifomerge and non-fifomerge
+ * cases, but for fifomerge we calculate the high threshold using the
+ * combined fifo size
+ */
+
+ if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
+ *fifo_low = ovl_fifo_size - burst_size * 2;
+ *fifo_high = total_fifo_size - burst_size;
+ } else if (plane == OMAP_DSS_WB) {
+ /*
+ * Most optimal configuration for writeback is to push out data
+ * to the interconnect the moment writeback pushes enough pixels
+ * in the FIFO to form a burst
+ */
+ *fifo_low = 0;
+ *fifo_high = burst_size;
+ } else {
+ *fifo_low = ovl_fifo_size - burst_size;
+ *fifo_high = total_fifo_size - buf_unit;
+ }
+}
+
+static void dispc_ovl_set_mflag(enum omap_plane plane, bool enable)
+{
+ int bit;
+
+ if (plane == OMAP_DSS_GFX)
+ bit = 14;
+ else
+ bit = 23;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
+}
+
+static void dispc_ovl_set_mflag_threshold(enum omap_plane plane,
+ int low, int high)
+{
+ dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane),
+ FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
+}
+
+static void dispc_init_mflag(void)
+{
+ int i;
+
+ /*
+ * HACK: NV12 color format and MFLAG seem to have problems working
+ * together: using two displays, and having an NV12 overlay on one of
+ * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
+ * Changing MFLAG thresholds and PRELOAD to certain values seem to
+ * remove the errors, but there doesn't seem to be a clear logic on
+ * which values work and which not.
+ *
+ * As a work-around, set force MFLAG to always on.
+ */
+ dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE,
+ (1 << 0) | /* MFLAG_CTRL = force always on */
+ (0 << 2)); /* MFLAG_START = disable */
+
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
+ u32 size = dispc_ovl_get_fifo_size(i);
+ u32 unit = dss_feat_get_buffer_size_unit();
+ u32 low, high;
+
+ dispc_ovl_set_mflag(i, true);
+
+ /*
+ * Simulation team suggests below thesholds:
+ * HT = fifosize * 5 / 8;
+ * LT = fifosize * 4 / 8;
+ */
+
+ low = size * 4 / 8 / unit;
+ high = size * 5 / 8 / unit;
+
+ dispc_ovl_set_mflag_threshold(i, low, high);
+ }
+
+ if (dispc.feat->has_writeback) {
+ u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB);
+ u32 unit = dss_feat_get_buffer_size_unit();
+ u32 low, high;
+
+ dispc_ovl_set_mflag(OMAP_DSS_WB, true);
+
+ /*
+ * Simulation team suggests below thesholds:
+ * HT = fifosize * 5 / 8;
+ * LT = fifosize * 4 / 8;
+ */
+
+ low = size * 4 / 8 / unit;
+ high = size * 5 / 8 / unit;
+
+ dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high);
+ }
+}
+
+static void dispc_ovl_set_fir(enum omap_plane plane,
+ int hinc, int vinc,
+ enum omap_color_component color_comp)
+{
+ u32 val;
+
+ if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
+ u8 hinc_start, hinc_end, vinc_start, vinc_end;
+
+ dss_feat_get_reg_field(FEAT_REG_FIRHINC,
+ &hinc_start, &hinc_end);
+ dss_feat_get_reg_field(FEAT_REG_FIRVINC,
+ &vinc_start, &vinc_end);
+ val = FLD_VAL(vinc, vinc_start, vinc_end) |
+ FLD_VAL(hinc, hinc_start, hinc_end);
+
+ dispc_write_reg(DISPC_OVL_FIR(plane), val);
+ } else {
+ val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
+ dispc_write_reg(DISPC_OVL_FIR2(plane), val);
+ }
+}
+
+static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
+{
+ u32 val;
+ u8 hor_start, hor_end, vert_start, vert_end;
+
+ dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+ dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+ val = FLD_VAL(vaccu, vert_start, vert_end) |
+ FLD_VAL(haccu, hor_start, hor_end);
+
+ dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
+}
+
+static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
+{
+ u32 val;
+ u8 hor_start, hor_end, vert_start, vert_end;
+
+ dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+ dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+ val = FLD_VAL(vaccu, vert_start, vert_end) |
+ FLD_VAL(haccu, hor_start, hor_end);
+
+ dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
+}
+
+static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
+ int vaccu)
+{
+ u32 val;
+
+ val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+ dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
+}
+
+static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
+ int vaccu)
+{
+ u32 val;
+
+ val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+ dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
+}
+
+static void dispc_ovl_set_scale_param(enum omap_plane plane,
+ u16 orig_width, u16 orig_height,
+ u16 out_width, u16 out_height,
+ bool five_taps, u8 rotation,
+ enum omap_color_component color_comp)
+{
+ int fir_hinc, fir_vinc;
+
+ fir_hinc = 1024 * orig_width / out_width;
+ fir_vinc = 1024 * orig_height / out_height;
+
+ dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
+ color_comp);
+ dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
+}
+
+static void dispc_ovl_set_accu_uv(enum omap_plane plane,
+ u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
+ bool ilace, enum omap_color_mode color_mode, u8 rotation)
+{
+ int h_accu2_0, h_accu2_1;
+ int v_accu2_0, v_accu2_1;
+ int chroma_hinc, chroma_vinc;
+ int idx;
+
+ struct accu {
+ s8 h0_m, h0_n;
+ s8 h1_m, h1_n;
+ s8 v0_m, v0_n;
+ s8 v1_m, v1_n;
+ };
+
+ const struct accu *accu_table;
+ const struct accu *accu_val;
+
+ static const struct accu accu_nv12[4] = {
+ { 0, 1, 0, 1 , -1, 2, 0, 1 },
+ { 1, 2, -3, 4 , 0, 1, 0, 1 },
+ { -1, 1, 0, 1 , -1, 2, 0, 1 },
+ { -1, 2, -1, 2 , -1, 1, 0, 1 },
+ };
+
+ static const struct accu accu_nv12_ilace[4] = {
+ { 0, 1, 0, 1 , -3, 4, -1, 4 },
+ { -1, 4, -3, 4 , 0, 1, 0, 1 },
+ { -1, 1, 0, 1 , -1, 4, -3, 4 },
+ { -3, 4, -3, 4 , -1, 1, 0, 1 },
+ };
+
+ static const struct accu accu_yuv[4] = {
+ { 0, 1, 0, 1, 0, 1, 0, 1 },
+ { 0, 1, 0, 1, 0, 1, 0, 1 },
+ { -1, 1, 0, 1, 0, 1, 0, 1 },
+ { 0, 1, 0, 1, -1, 1, 0, 1 },
+ };
+
+ switch (rotation) {
+ case OMAP_DSS_ROT_0:
+ idx = 0;
+ break;
+ case OMAP_DSS_ROT_90:
+ idx = 1;
+ break;
+ case OMAP_DSS_ROT_180:
+ idx = 2;
+ break;
+ case OMAP_DSS_ROT_270:
+ idx = 3;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ if (ilace)
+ accu_table = accu_nv12_ilace;
+ else
+ accu_table = accu_nv12;
+ break;
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ accu_table = accu_yuv;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ accu_val = &accu_table[idx];
+
+ chroma_hinc = 1024 * orig_width / out_width;
+ chroma_vinc = 1024 * orig_height / out_height;
+
+ h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
+ h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
+ v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
+ v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
+
+ dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
+ dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
+}
+
+static void dispc_ovl_set_scaling_common(enum omap_plane plane,
+ u16 orig_width, u16 orig_height,
+ u16 out_width, u16 out_height,
+ bool ilace, bool five_taps,
+ bool fieldmode, enum omap_color_mode color_mode,
+ u8 rotation)
+{
+ int accu0 = 0;
+ int accu1 = 0;
+ u32 l;
+
+ dispc_ovl_set_scale_param(plane, orig_width, orig_height,
+ out_width, out_height, five_taps,
+ rotation, DISPC_COLOR_COMPONENT_RGB_Y);
+ l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+
+ /* RESIZEENABLE and VERTICALTAPS */
+ l &= ~((0x3 << 5) | (0x1 << 21));
+ l |= (orig_width != out_width) ? (1 << 5) : 0;
+ l |= (orig_height != out_height) ? (1 << 6) : 0;
+ l |= five_taps ? (1 << 21) : 0;
+
+ /* VRESIZECONF and HRESIZECONF */
+ if (dss_has_feature(FEAT_RESIZECONF)) {
+ l &= ~(0x3 << 7);
+ l |= (orig_width <= out_width) ? 0 : (1 << 7);
+ l |= (orig_height <= out_height) ? 0 : (1 << 8);
+ }
+
+ /* LINEBUFFERSPLIT */
+ if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
+ l &= ~(0x1 << 22);
+ l |= five_taps ? (1 << 22) : 0;
+ }
+
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
+
+ /*
+ * field 0 = even field = bottom field
+ * field 1 = odd field = top field
+ */
+ if (ilace && !fieldmode) {
+ accu1 = 0;
+ accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
+ if (accu0 >= 1024/2) {
+ accu1 = 1024/2;
+ accu0 -= accu1;
+ }
+ }
+
+ dispc_ovl_set_vid_accu0(plane, 0, accu0);
+ dispc_ovl_set_vid_accu1(plane, 0, accu1);
+}
+
+static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
+ u16 orig_width, u16 orig_height,
+ u16 out_width, u16 out_height,
+ bool ilace, bool five_taps,
+ bool fieldmode, enum omap_color_mode color_mode,
+ u8 rotation)
+{
+ int scale_x = out_width != orig_width;
+ int scale_y = out_height != orig_height;
+ bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
+
+ if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
+ return;
+ if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
+ color_mode != OMAP_DSS_COLOR_UYVY &&
+ color_mode != OMAP_DSS_COLOR_NV12)) {
+ /* reset chroma resampling for RGB formats */
+ if (plane != OMAP_DSS_WB)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
+ return;
+ }
+
+ dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
+ out_height, ilace, color_mode, rotation);
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_NV12:
+ if (chroma_upscale) {
+ /* UV is subsampled by 2 horizontally and vertically */
+ orig_height >>= 1;
+ orig_width >>= 1;
+ } else {
+ /* UV is downsampled by 2 horizontally and vertically */
+ orig_height <<= 1;
+ orig_width <<= 1;
+ }
+
+ break;
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ /* For YUV422 with 90/270 rotation, we don't upsample chroma */
+ if (rotation == OMAP_DSS_ROT_0 ||
+ rotation == OMAP_DSS_ROT_180) {
+ if (chroma_upscale)
+ /* UV is subsampled by 2 horizontally */
+ orig_width >>= 1;
+ else
+ /* UV is downsampled by 2 horizontally */
+ orig_width <<= 1;
+ }
+
+ /* must use FIR for YUV422 if rotated */
+ if (rotation != OMAP_DSS_ROT_0)
+ scale_x = scale_y = true;
+
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ if (out_width != orig_width)
+ scale_x = true;
+ if (out_height != orig_height)
+ scale_y = true;
+
+ dispc_ovl_set_scale_param(plane, orig_width, orig_height,
+ out_width, out_height, five_taps,
+ rotation, DISPC_COLOR_COMPONENT_UV);
+
+ if (plane != OMAP_DSS_WB)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
+ (scale_x || scale_y) ? 1 : 0, 8, 8);
+
+ /* set H scaling */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
+ /* set V scaling */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
+}
+
+static void dispc_ovl_set_scaling(enum omap_plane plane,
+ u16 orig_width, u16 orig_height,
+ u16 out_width, u16 out_height,
+ bool ilace, bool five_taps,
+ bool fieldmode, enum omap_color_mode color_mode,
+ u8 rotation)
+{
+ BUG_ON(plane == OMAP_DSS_GFX);
+
+ dispc_ovl_set_scaling_common(plane,
+ orig_width, orig_height,
+ out_width, out_height,
+ ilace, five_taps,
+ fieldmode, color_mode,
+ rotation);
+
+ dispc_ovl_set_scaling_uv(plane,
+ orig_width, orig_height,
+ out_width, out_height,
+ ilace, five_taps,
+ fieldmode, color_mode,
+ rotation);
+}
+
+static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
+ enum omap_dss_rotation_type rotation_type,
+ bool mirroring, enum omap_color_mode color_mode)
+{
+ bool row_repeat = false;
+ int vidrot = 0;
+
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY) {
+
+ if (mirroring) {
+ switch (rotation) {
+ case OMAP_DSS_ROT_0:
+ vidrot = 2;
+ break;
+ case OMAP_DSS_ROT_90:
+ vidrot = 1;
+ break;
+ case OMAP_DSS_ROT_180:
+ vidrot = 0;
+ break;
+ case OMAP_DSS_ROT_270:
+ vidrot = 3;
+ break;
+ }
+ } else {
+ switch (rotation) {
+ case OMAP_DSS_ROT_0:
+ vidrot = 0;
+ break;
+ case OMAP_DSS_ROT_90:
+ vidrot = 1;
+ break;
+ case OMAP_DSS_ROT_180:
+ vidrot = 2;
+ break;
+ case OMAP_DSS_ROT_270:
+ vidrot = 3;
+ break;
+ }
+ }
+
+ if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
+ row_repeat = true;
+ else
+ row_repeat = false;
+ }
+
+ /*
+ * OMAP4/5 Errata i631:
+ * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
+ * rows beyond the framebuffer, which may cause OCP error.
+ */
+ if (color_mode == OMAP_DSS_COLOR_NV12 &&
+ rotation_type != OMAP_DSS_ROT_TILER)
+ vidrot = 1;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
+ if (dss_has_feature(FEAT_ROWREPEATENABLE))
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
+ row_repeat ? 1 : 0, 18, 18);
+
+ if (color_mode == OMAP_DSS_COLOR_NV12) {
+ bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
+ (rotation == OMAP_DSS_ROT_0 ||
+ rotation == OMAP_DSS_ROT_180);
+ /* DOUBLESTRIDE */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
+ }
+
+}
+
+static int color_mode_to_bpp(enum omap_color_mode color_mode)
+{
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_CLUT1:
+ return 1;
+ case OMAP_DSS_COLOR_CLUT2:
+ return 2;
+ case OMAP_DSS_COLOR_CLUT4:
+ return 4;
+ case OMAP_DSS_COLOR_CLUT8:
+ case OMAP_DSS_COLOR_NV12:
+ return 8;
+ case OMAP_DSS_COLOR_RGB12U:
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_ARGB16:
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ case OMAP_DSS_COLOR_RGBA16:
+ case OMAP_DSS_COLOR_RGBX16:
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ case OMAP_DSS_COLOR_XRGB16_1555:
+ return 16;
+ case OMAP_DSS_COLOR_RGB24P:
+ return 24;
+ case OMAP_DSS_COLOR_RGB24U:
+ case OMAP_DSS_COLOR_ARGB32:
+ case OMAP_DSS_COLOR_RGBA32:
+ case OMAP_DSS_COLOR_RGBX32:
+ return 32;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static s32 pixinc(int pixels, u8 ps)
+{
+ if (pixels == 1)
+ return 1;
+ else if (pixels > 1)
+ return 1 + (pixels - 1) * ps;
+ else if (pixels < 0)
+ return 1 - (-pixels + 1) * ps;
+ else
+ BUG();
+ return 0;
+}
+
+static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
+ u16 screen_width,
+ u16 width, u16 height,
+ enum omap_color_mode color_mode, bool fieldmode,
+ unsigned int field_offset,
+ unsigned *offset0, unsigned *offset1,
+ s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
+{
+ u8 ps;
+
+ /* FIXME CLUT formats */
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_CLUT1:
+ case OMAP_DSS_COLOR_CLUT2:
+ case OMAP_DSS_COLOR_CLUT4:
+ case OMAP_DSS_COLOR_CLUT8:
+ BUG();
+ return;
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ ps = 4;
+ break;
+ default:
+ ps = color_mode_to_bpp(color_mode) / 8;
+ break;
+ }
+
+ DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
+ width, height);
+
+ /*
+ * field 0 = even field = bottom field
+ * field 1 = odd field = top field
+ */
+ switch (rotation + mirror * 4) {
+ case OMAP_DSS_ROT_0:
+ case OMAP_DSS_ROT_180:
+ /*
+ * If the pixel format is YUV or UYVY divide the width
+ * of the image by 2 for 0 and 180 degree rotation.
+ */
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ width = width >> 1;
+ case OMAP_DSS_ROT_90:
+ case OMAP_DSS_ROT_270:
+ *offset1 = 0;
+ if (field_offset)
+ *offset0 = field_offset * screen_width * ps;
+ else
+ *offset0 = 0;
+
+ *row_inc = pixinc(1 +
+ (y_predecim * screen_width - x_predecim * width) +
+ (fieldmode ? screen_width : 0), ps);
+ *pix_inc = pixinc(x_predecim, ps);
+ break;
+
+ case OMAP_DSS_ROT_0 + 4:
+ case OMAP_DSS_ROT_180 + 4:
+ /* If the pixel format is YUV or UYVY divide the width
+ * of the image by 2 for 0 degree and 180 degree
+ */
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ width = width >> 1;
+ case OMAP_DSS_ROT_90 + 4:
+ case OMAP_DSS_ROT_270 + 4:
+ *offset1 = 0;
+ if (field_offset)
+ *offset0 = field_offset * screen_width * ps;
+ else
+ *offset0 = 0;
+ *row_inc = pixinc(1 -
+ (y_predecim * screen_width + x_predecim * width) -
+ (fieldmode ? screen_width : 0), ps);
+ *pix_inc = pixinc(x_predecim, ps);
+ break;
+
+ default:
+ BUG();
+ return;
+ }
+}
+
+static void calc_dma_rotation_offset(u8 rotation, bool mirror,
+ u16 screen_width,
+ u16 width, u16 height,
+ enum omap_color_mode color_mode, bool fieldmode,
+ unsigned int field_offset,
+ unsigned *offset0, unsigned *offset1,
+ s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
+{
+ u8 ps;
+ u16 fbw, fbh;
+
+ /* FIXME CLUT formats */
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_CLUT1:
+ case OMAP_DSS_COLOR_CLUT2:
+ case OMAP_DSS_COLOR_CLUT4:
+ case OMAP_DSS_COLOR_CLUT8:
+ BUG();
+ return;
+ default:
+ ps = color_mode_to_bpp(color_mode) / 8;
+ break;
+ }
+
+ DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
+ width, height);
+
+ /* width & height are overlay sizes, convert to fb sizes */
+
+ if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
+ fbw = width;
+ fbh = height;
+ } else {
+ fbw = height;
+ fbh = width;
+ }
+
+ /*
+ * field 0 = even field = bottom field
+ * field 1 = odd field = top field
+ */
+ switch (rotation + mirror * 4) {
+ case OMAP_DSS_ROT_0:
+ *offset1 = 0;
+ if (field_offset)
+ *offset0 = *offset1 + field_offset * screen_width * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(1 +
+ (y_predecim * screen_width - fbw * x_predecim) +
+ (fieldmode ? screen_width : 0), ps);
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(x_predecim, ps);
+ break;
+ case OMAP_DSS_ROT_90:
+ *offset1 = screen_width * (fbh - 1) * ps;
+ if (field_offset)
+ *offset0 = *offset1 + field_offset * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
+ y_predecim + (fieldmode ? 1 : 0), ps);
+ *pix_inc = pixinc(-x_predecim * screen_width, ps);
+ break;
+ case OMAP_DSS_ROT_180:
+ *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
+ if (field_offset)
+ *offset0 = *offset1 - field_offset * screen_width * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(-1 -
+ (y_predecim * screen_width - fbw * x_predecim) -
+ (fieldmode ? screen_width : 0), ps);
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(-x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(-x_predecim, ps);
+ break;
+ case OMAP_DSS_ROT_270:
+ *offset1 = (fbw - 1) * ps;
+ if (field_offset)
+ *offset0 = *offset1 - field_offset * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
+ y_predecim - (fieldmode ? 1 : 0), ps);
+ *pix_inc = pixinc(x_predecim * screen_width, ps);
+ break;
+
+ /* mirroring */
+ case OMAP_DSS_ROT_0 + 4:
+ *offset1 = (fbw - 1) * ps;
+ if (field_offset)
+ *offset0 = *offset1 + field_offset * screen_width * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
+ (fieldmode ? screen_width : 0),
+ ps);
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(-x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(-x_predecim, ps);
+ break;
+
+ case OMAP_DSS_ROT_90 + 4:
+ *offset1 = 0;
+ if (field_offset)
+ *offset0 = *offset1 + field_offset * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
+ y_predecim + (fieldmode ? 1 : 0),
+ ps);
+ *pix_inc = pixinc(x_predecim * screen_width, ps);
+ break;
+
+ case OMAP_DSS_ROT_180 + 4:
+ *offset1 = screen_width * (fbh - 1) * ps;
+ if (field_offset)
+ *offset0 = *offset1 - field_offset * screen_width * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
+ (fieldmode ? screen_width : 0),
+ ps);
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(x_predecim, ps);
+ break;
+
+ case OMAP_DSS_ROT_270 + 4:
+ *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
+ if (field_offset)
+ *offset0 = *offset1 - field_offset * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
+ y_predecim - (fieldmode ? 1 : 0),
+ ps);
+ *pix_inc = pixinc(-x_predecim * screen_width, ps);
+ break;
+
+ default:
+ BUG();
+ return;
+ }
+}
+
+static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
+ enum omap_color_mode color_mode, bool fieldmode,
+ unsigned int field_offset, unsigned *offset0, unsigned *offset1,
+ s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
+{
+ u8 ps;
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_CLUT1:
+ case OMAP_DSS_COLOR_CLUT2:
+ case OMAP_DSS_COLOR_CLUT4:
+ case OMAP_DSS_COLOR_CLUT8:
+ BUG();
+ return;
+ default:
+ ps = color_mode_to_bpp(color_mode) / 8;
+ break;
+ }
+
+ DSSDBG("scrw %d, width %d\n", screen_width, width);
+
+ /*
+ * field 0 = even field = bottom field
+ * field 1 = odd field = top field
+ */
+ *offset1 = 0;
+ if (field_offset)
+ *offset0 = *offset1 + field_offset * screen_width * ps;
+ else
+ *offset0 = *offset1;
+ *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
+ (fieldmode ? screen_width : 0), ps);
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(x_predecim, ps);
+}
+
+/*
+ * This function is used to avoid synclosts in OMAP3, because of some
+ * undocumented horizontal position and timing related limitations.
+ */
+static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
+ const struct omap_video_timings *t, u16 pos_x,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ bool five_taps)
+{
+ const int ds = DIV_ROUND_UP(height, out_height);
+ unsigned long nonactive;
+ static const u8 limits[3] = { 8, 10, 20 };
+ u64 val, blank;
+ int i;
+
+ nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
+
+ i = 0;
+ if (out_height < height)
+ i++;
+ if (out_width < width)
+ i++;
+ blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk);
+ DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
+ if (blank <= limits[i])
+ return -EINVAL;
+
+ /* FIXME add checks for 3-tap filter once the limitations are known */
+ if (!five_taps)
+ return 0;
+
+ /*
+ * Pixel data should be prepared before visible display point starts.
+ * So, atleast DS-2 lines must have already been fetched by DISPC
+ * during nonactive - pos_x period.
+ */
+ val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
+ DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
+ val, max(0, ds - 2) * width);
+ if (val < max(0, ds - 2) * width)
+ return -EINVAL;
+
+ /*
+ * All lines need to be refilled during the nonactive period of which
+ * only one line can be loaded during the active period. So, atleast
+ * DS - 1 lines should be loaded during nonactive period.
+ */
+ val = div_u64((u64)nonactive * lclk, pclk);
+ DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
+ val, max(0, ds - 1) * width);
+ if (val < max(0, ds - 1) * width)
+ return -EINVAL;
+
+ return 0;
+}
+
+static unsigned long calc_core_clk_five_taps(unsigned long pclk,
+ const struct omap_video_timings *mgr_timings, u16 width,
+ u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode)
+{
+ u32 core_clk = 0;
+ u64 tmp;
+
+ if (height <= out_height && width <= out_width)
+ return (unsigned long) pclk;
+
+ if (height > out_height) {
+ unsigned int ppl = mgr_timings->x_res;
+
+ tmp = (u64)pclk * height * out_width;
+ do_div(tmp, 2 * out_height * ppl);
+ core_clk = tmp;
+
+ if (height > 2 * out_height) {
+ if (ppl == out_width)
+ return 0;
+
+ tmp = (u64)pclk * (height - 2 * out_height) * out_width;
+ do_div(tmp, 2 * out_height * (ppl - out_width));
+ core_clk = max_t(u32, core_clk, tmp);
+ }
+ }
+
+ if (width > out_width) {
+ tmp = (u64)pclk * width;
+ do_div(tmp, out_width);
+ core_clk = max_t(u32, core_clk, tmp);
+
+ if (color_mode == OMAP_DSS_COLOR_RGB24U)
+ core_clk <<= 1;
+ }
+
+ return core_clk;
+}
+
+static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ if (height > out_height && width > out_width)
+ return pclk * 4;
+ else
+ return pclk * 2;
+}
+
+static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ unsigned int hf, vf;
+
+ /*
+ * FIXME how to determine the 'A' factor
+ * for the no downscaling case ?
+ */
+
+ if (width > 3 * out_width)
+ hf = 4;
+ else if (width > 2 * out_width)
+ hf = 3;
+ else if (width > out_width)
+ hf = 2;
+ else
+ hf = 1;
+ if (height > out_height)
+ vf = 2;
+ else
+ vf = 1;
+
+ return pclk * vf * hf;
+}
+
+static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ /*
+ * If the overlay/writeback is in mem to mem mode, there are no
+ * downscaling limitations with respect to pixel clock, return 1 as
+ * required core clock to represent that we have sufficient enough
+ * core clock to do maximum downscaling
+ */
+ if (mem_to_mem)
+ return 1;
+
+ if (width > out_width)
+ return DIV_ROUND_UP(pclk, out_width) * width;
+ else
+ return pclk;
+}
+
+static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ *five_taps = false;
+
+ do {
+ in_height = height / *decim_y;
+ in_width = width / *decim_x;
+ *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
+ in_height, out_width, out_height, mem_to_mem);
+ error = (in_width > maxsinglelinewidth || !*core_clk ||
+ *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x == *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (error) {
+ DSSERR("failed to find scaling settings\n");
+ return -EINVAL;
+ }
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale max input width exceeded");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ int error;
+ u16 in_width, in_height;
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ do {
+ in_height = height / *decim_y;
+ in_width = width / *decim_x;
+ *five_taps = in_height > out_height;
+
+ if (in_width > maxsinglelinewidth)
+ if (in_height > out_height &&
+ in_height < out_height * 2)
+ *five_taps = false;
+again:
+ if (*five_taps)
+ *core_clk = calc_core_clk_five_taps(pclk, mgr_timings,
+ in_width, in_height, out_width,
+ out_height, color_mode);
+ else
+ *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
+ in_height, out_width, out_height,
+ mem_to_mem);
+
+ error = check_horiz_timing_omap3(pclk, lclk, mgr_timings,
+ pos_x, in_width, in_height, out_width,
+ out_height, *five_taps);
+ if (error && *five_taps) {
+ *five_taps = false;
+ goto again;
+ }
+
+ error = (error || in_width > maxsinglelinewidth * 2 ||
+ (in_width > maxsinglelinewidth && *five_taps) ||
+ !*core_clk || *core_clk > dispc_core_clk_rate());
+
+ if (!error) {
+ /* verify that we're inside the limits of scaler */
+ if (in_width / 4 > out_width)
+ error = 1;
+
+ if (*five_taps) {
+ if (in_height / 4 > out_height)
+ error = 1;
+ } else {
+ if (in_height / 2 > out_height)
+ error = 1;
+ }
+ }
+
+ if (error)
+ ++*decim_y;
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (error) {
+ DSSERR("failed to find scaling settings\n");
+ return -EINVAL;
+ }
+
+ if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width,
+ in_height, out_width, out_height, *five_taps)) {
+ DSSERR("horizontal timing too tight\n");
+ return -EINVAL;
+ }
+
+ if (in_width > (maxsinglelinewidth * 2)) {
+ DSSERR("Cannot setup scaling");
+ DSSERR("width exceeds maximum width possible");
+ return -EINVAL;
+ }
+
+ if (in_width > maxsinglelinewidth && *five_taps) {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ u16 in_width, in_width_max;
+ int decim_x_min = *decim_x;
+ u16 in_height = height / *decim_y;
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+
+ if (mem_to_mem) {
+ in_width_max = out_width * maxdownscale;
+ } else {
+ in_width_max = dispc_core_clk_rate() /
+ DIV_ROUND_UP(pclk, out_width);
+ }
+
+ *decim_x = DIV_ROUND_UP(width, in_width_max);
+
+ *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
+ if (*decim_x > *x_predecim)
+ return -EINVAL;
+
+ do {
+ in_width = width / *decim_x;
+ } while (*decim_x <= *x_predecim &&
+ in_width > maxsinglelinewidth && ++*decim_x);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale width exceeds max line width");
+ return -EINVAL;
+ }
+
+ *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
+ out_width, out_height, mem_to_mem);
+ return 0;
+}
+
+#define DIV_FRAC(dividend, divisor) \
+ ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
+
+static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
+ enum omap_overlay_caps caps,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, u16 pos_x,
+ enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
+{
+ const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+ const int max_decim_limit = 16;
+ unsigned long core_clk = 0;
+ int decim_x, decim_y, ret;
+
+ if (width == out_width && height == out_height)
+ return 0;
+
+ if (!mem_to_mem && (pclk == 0 || mgr_timings->pixelclock == 0)) {
+ DSSERR("cannot calculate scaling settings: pclk is zero\n");
+ return -EINVAL;
+ }
+
+ if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
+ return -EINVAL;
+
+ if (mem_to_mem) {
+ *x_predecim = *y_predecim = 1;
+ } else {
+ *x_predecim = max_decim_limit;
+ *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
+ dss_has_feature(FEAT_BURST_2D)) ?
+ 2 : max_decim_limit;
+ }
+
+ if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
+ color_mode == OMAP_DSS_COLOR_CLUT2 ||
+ color_mode == OMAP_DSS_COLOR_CLUT4 ||
+ color_mode == OMAP_DSS_COLOR_CLUT8) {
+ *x_predecim = 1;
+ *y_predecim = 1;
+ *five_taps = false;
+ return 0;
+ }
+
+ decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
+ decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
+
+ if (decim_x > *x_predecim || out_width > width * 8)
+ return -EINVAL;
+
+ if (decim_y > *y_predecim || out_height > height * 8)
+ return -EINVAL;
+
+ ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height,
+ out_width, out_height, color_mode, five_taps,
+ x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
+ mem_to_mem);
+ if (ret)
+ return ret;
+
+ DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n",
+ width, height,
+ out_width, out_height,
+ out_width / width, DIV_FRAC(out_width, width),
+ out_height / height, DIV_FRAC(out_height, height),
+
+ decim_x, decim_y,
+ width / decim_x, height / decim_y,
+ out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
+ out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
+
+ *five_taps ? 5 : 3,
+ core_clk, dispc_core_clk_rate());
+
+ if (!core_clk || core_clk > dispc_core_clk_rate()) {
+ DSSERR("failed to set up scaling, "
+ "required core clk rate = %lu Hz, "
+ "current core clk rate = %lu Hz\n",
+ core_clk, dispc_core_clk_rate());
+ return -EINVAL;
+ }
+
+ *x_predecim = decim_x;
+ *y_predecim = decim_y;
+ return 0;
+}
+
+int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
+ const struct omap_overlay_info *oi,
+ const struct omap_video_timings *timings,
+ int *x_predecim, int *y_predecim)
+{
+ enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
+ bool five_taps = true;
+ bool fieldmode = false;
+ u16 in_height = oi->height;
+ u16 in_width = oi->width;
+ bool ilace = timings->interlace;
+ u16 out_width, out_height;
+ int pos_x = oi->pos_x;
+ unsigned long pclk = dispc_mgr_pclk_rate(channel);
+ unsigned long lclk = dispc_mgr_lclk_rate(channel);
+
+ out_width = oi->out_width == 0 ? oi->width : oi->out_width;
+ out_height = oi->out_height == 0 ? oi->height : oi->out_height;
+
+ if (ilace && oi->height == out_height)
+ fieldmode = true;
+
+ if (ilace) {
+ if (fieldmode)
+ in_height /= 2;
+ out_height /= 2;
+
+ DSSDBG("adjusting for ilace: height %d, out_height %d\n",
+ in_height, out_height);
+ }
+
+ if (!dss_feat_color_mode_supported(plane, oi->color_mode))
+ return -EINVAL;
+
+ return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width,
+ in_height, out_width, out_height, oi->color_mode,
+ &five_taps, x_predecim, y_predecim, pos_x,
+ oi->rotation_type, false);
+}
+EXPORT_SYMBOL(dispc_ovl_check);
+
+static int dispc_ovl_setup_common(enum omap_plane plane,
+ enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
+ u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
+ u16 out_width, u16 out_height, enum omap_color_mode color_mode,
+ u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
+ u8 global_alpha, enum omap_dss_rotation_type rotation_type,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem)
+{
+ bool five_taps = true;
+ bool fieldmode = false;
+ int r, cconv = 0;
+ unsigned offset0, offset1;
+ s32 row_inc;
+ s32 pix_inc;
+ u16 frame_width, frame_height;
+ unsigned int field_offset = 0;
+ u16 in_height = height;
+ u16 in_width = width;
+ int x_predecim = 1, y_predecim = 1;
+ bool ilace = mgr_timings->interlace;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ unsigned long lclk = dispc_plane_lclk_rate(plane);
+
+ if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
+ return -EINVAL;
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ case OMAP_DSS_COLOR_NV12:
+ if (in_width & 1) {
+ DSSERR("input width %d is not even for YUV format\n",
+ in_width);
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ out_width = out_width == 0 ? width : out_width;
+ out_height = out_height == 0 ? height : out_height;
+
+ if (ilace && height == out_height)
+ fieldmode = true;
+
+ if (ilace) {
+ if (fieldmode)
+ in_height /= 2;
+ pos_y /= 2;
+ out_height /= 2;
+
+ DSSDBG("adjusting for ilace: height %d, pos_y %d, "
+ "out_height %d\n", in_height, pos_y,
+ out_height);
+ }
+
+ if (!dss_feat_color_mode_supported(plane, color_mode))
+ return -EINVAL;
+
+ r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width,
+ in_height, out_width, out_height, color_mode,
+ &five_taps, &x_predecim, &y_predecim, pos_x,
+ rotation_type, mem_to_mem);
+ if (r)
+ return r;
+
+ in_width = in_width / x_predecim;
+ in_height = in_height / y_predecim;
+
+ if (x_predecim > 1 || y_predecim > 1)
+ DSSDBG("predecimation %d x %x, new input size %d x %d\n",
+ x_predecim, y_predecim, in_width, in_height);
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ case OMAP_DSS_COLOR_NV12:
+ if (in_width & 1) {
+ DSSDBG("predecimated input width is not even for YUV format\n");
+ DSSDBG("adjusting input width %d -> %d\n",
+ in_width, in_width & ~1);
+
+ in_width &= ~1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY ||
+ color_mode == OMAP_DSS_COLOR_NV12)
+ cconv = 1;
+
+ if (ilace && !fieldmode) {
+ /*
+ * when downscaling the bottom field may have to start several
+ * source lines below the top field. Unfortunately ACCUI
+ * registers will only hold the fractional part of the offset
+ * so the integer part must be added to the base address of the
+ * bottom field.
+ */
+ if (!in_height || in_height == out_height)
+ field_offset = 0;
+ else
+ field_offset = in_height / out_height / 2;
+ }
+
+ /* Fields are independent but interleaved in memory. */
+ if (fieldmode)
+ field_offset = 1;
+
+ offset0 = 0;
+ offset1 = 0;
+ row_inc = 0;
+ pix_inc = 0;
+
+ if (plane == OMAP_DSS_WB) {
+ frame_width = out_width;
+ frame_height = out_height;
+ } else {
+ frame_width = in_width;
+ frame_height = height;
+ }
+
+ if (rotation_type == OMAP_DSS_ROT_TILER)
+ calc_tiler_rotation_offset(screen_width, frame_width,
+ color_mode, fieldmode, field_offset,
+ &offset0, &offset1, &row_inc, &pix_inc,
+ x_predecim, y_predecim);
+ else if (rotation_type == OMAP_DSS_ROT_DMA)
+ calc_dma_rotation_offset(rotation, mirror, screen_width,
+ frame_width, frame_height,
+ color_mode, fieldmode, field_offset,
+ &offset0, &offset1, &row_inc, &pix_inc,
+ x_predecim, y_predecim);
+ else
+ calc_vrfb_rotation_offset(rotation, mirror,
+ screen_width, frame_width, frame_height,
+ color_mode, fieldmode, field_offset,
+ &offset0, &offset1, &row_inc, &pix_inc,
+ x_predecim, y_predecim);
+
+ DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
+ offset0, offset1, row_inc, pix_inc);
+
+ dispc_ovl_set_color_mode(plane, color_mode);
+
+ dispc_ovl_configure_burst_type(plane, rotation_type);
+
+ dispc_ovl_set_ba0(plane, paddr + offset0);
+ dispc_ovl_set_ba1(plane, paddr + offset1);
+
+ if (OMAP_DSS_COLOR_NV12 == color_mode) {
+ dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
+ dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
+ }
+
+ if (dispc.feat->last_pixel_inc_missing)
+ row_inc += pix_inc - 1;
+
+ dispc_ovl_set_row_inc(plane, row_inc);
+ dispc_ovl_set_pix_inc(plane, pix_inc);
+
+ DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
+ in_height, out_width, out_height);
+
+ dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
+
+ dispc_ovl_set_input_size(plane, in_width, in_height);
+
+ if (caps & OMAP_DSS_OVL_CAP_SCALE) {
+ dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
+ out_height, ilace, five_taps, fieldmode,
+ color_mode, rotation);
+ dispc_ovl_set_output_size(plane, out_width, out_height);
+ dispc_ovl_set_vid_color_conv(plane, cconv);
+ }
+
+ dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
+ color_mode);
+
+ dispc_ovl_set_zorder(plane, caps, zorder);
+ dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
+ dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
+
+ dispc_ovl_enable_replication(plane, caps, replication);
+
+ return 0;
+}
+
+int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem)
+{
+ int r;
+ enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
+ enum omap_channel channel;
+
+ channel = dispc_ovl_get_channel_out(plane);
+
+ DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
+ " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
+ plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
+ oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
+ oi->color_mode, oi->rotation, oi->mirror, channel, replication);
+
+ r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr,
+ oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
+ oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
+ oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
+ oi->rotation_type, replication, mgr_timings, mem_to_mem);
+
+ return r;
+}
+EXPORT_SYMBOL(dispc_ovl_setup);
+
+int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
+ bool mem_to_mem, const struct omap_video_timings *mgr_timings)
+{
+ int r;
+ u32 l;
+ enum omap_plane plane = OMAP_DSS_WB;
+ const int pos_x = 0, pos_y = 0;
+ const u8 zorder = 0, global_alpha = 0;
+ const bool replication = false;
+ bool truncation;
+ int in_width = mgr_timings->x_res;
+ int in_height = mgr_timings->y_res;
+ enum omap_overlay_caps caps =
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
+
+ DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
+ "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
+ in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
+ wi->mirror);
+
+ r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
+ wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
+ wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
+ wi->pre_mult_alpha, global_alpha, wi->rotation_type,
+ replication, mgr_timings, mem_to_mem);
+
+ switch (wi->color_mode) {
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_RGB24P:
+ case OMAP_DSS_COLOR_ARGB16:
+ case OMAP_DSS_COLOR_RGBA16:
+ case OMAP_DSS_COLOR_RGB12U:
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ case OMAP_DSS_COLOR_XRGB16_1555:
+ case OMAP_DSS_COLOR_RGBX16:
+ truncation = true;
+ break;
+ default:
+ truncation = false;
+ break;
+ }
+
+ /* setup extra DISPC_WB_ATTRIBUTES */
+ l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
+ l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
+ if (mem_to_mem)
+ l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */
+ else
+ l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
+
+ if (mem_to_mem) {
+ /* WBDELAYCOUNT */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
+ } else {
+ int wbdelay;
+
+ wbdelay = min(mgr_timings->vfp + mgr_timings->vsw +
+ mgr_timings->vbp, 255);
+
+ /* WBDELAYCOUNT */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
+ }
+
+ return r;
+}
+
+int dispc_ovl_enable(enum omap_plane plane, bool enable)
+{
+ DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(dispc_ovl_enable);
+
+bool dispc_ovl_enabled(enum omap_plane plane)
+{
+ return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
+}
+EXPORT_SYMBOL(dispc_ovl_enabled);
+
+void dispc_mgr_enable(enum omap_channel channel, bool enable)
+{
+ mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
+ /* flush posted write */
+ mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
+}
+EXPORT_SYMBOL(dispc_mgr_enable);
+
+bool dispc_mgr_is_enabled(enum omap_channel channel)
+{
+ return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
+}
+EXPORT_SYMBOL(dispc_mgr_is_enabled);
+
+void dispc_wb_enable(bool enable)
+{
+ dispc_ovl_enable(OMAP_DSS_WB, enable);
+}
+
+bool dispc_wb_is_enabled(void)
+{
+ return dispc_ovl_enabled(OMAP_DSS_WB);
+}
+
+static void dispc_lcd_enable_signal_polarity(bool act_high)
+{
+ if (!dss_has_feature(FEAT_LCDENABLEPOL))
+ return;
+
+ REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
+}
+
+void dispc_lcd_enable_signal(bool enable)
+{
+ if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
+ return;
+
+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
+}
+
+void dispc_pck_free_enable(bool enable)
+{
+ if (!dss_has_feature(FEAT_PCKFREEENABLE))
+ return;
+
+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
+}
+
+static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
+{
+ mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
+}
+
+
+static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
+{
+ mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
+}
+
+static void dispc_set_loadmode(enum omap_dss_load_mode mode)
+{
+ REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
+}
+
+
+static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
+{
+ dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
+}
+
+static void dispc_mgr_set_trans_key(enum omap_channel ch,
+ enum omap_dss_trans_key_type type,
+ u32 trans_key)
+{
+ mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
+
+ dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
+}
+
+static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
+{
+ mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
+}
+
+static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
+ bool enable)
+{
+ if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
+ return;
+
+ if (ch == OMAP_DSS_CHANNEL_LCD)
+ REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
+ else if (ch == OMAP_DSS_CHANNEL_DIGIT)
+ REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
+}
+
+void dispc_mgr_setup(enum omap_channel channel,
+ const struct omap_overlay_manager_info *info)
+{
+ dispc_mgr_set_default_color(channel, info->default_color);
+ dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
+ dispc_mgr_enable_trans_key(channel, info->trans_enabled);
+ dispc_mgr_enable_alpha_fixed_zorder(channel,
+ info->partial_alpha_enabled);
+ if (dss_has_feature(FEAT_CPR)) {
+ dispc_mgr_enable_cpr(channel, info->cpr_enable);
+ dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
+ }
+}
+EXPORT_SYMBOL(dispc_mgr_setup);
+
+static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
+{
+ int code;
+
+ switch (data_lines) {
+ case 12:
+ code = 0;
+ break;
+ case 16:
+ code = 1;
+ break;
+ case 18:
+ code = 2;
+ break;
+ case 24:
+ code = 3;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
+}
+
+static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
+{
+ u32 l;
+ int gpout0, gpout1;
+
+ switch (mode) {
+ case DSS_IO_PAD_MODE_RESET:
+ gpout0 = 0;
+ gpout1 = 0;
+ break;
+ case DSS_IO_PAD_MODE_RFBI:
+ gpout0 = 1;
+ gpout1 = 0;
+ break;
+ case DSS_IO_PAD_MODE_BYPASS:
+ gpout0 = 1;
+ gpout1 = 1;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ l = dispc_read_reg(DISPC_CONTROL);
+ l = FLD_MOD(l, gpout0, 15, 15);
+ l = FLD_MOD(l, gpout1, 16, 16);
+ dispc_write_reg(DISPC_CONTROL, l);
+}
+
+static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
+{
+ mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
+}
+
+void dispc_mgr_set_lcd_config(enum omap_channel channel,
+ const struct dss_lcd_mgr_config *config)
+{
+ dispc_mgr_set_io_pad_mode(config->io_pad_mode);
+
+ dispc_mgr_enable_stallmode(channel, config->stallmode);
+ dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck);
+
+ dispc_mgr_set_clock_div(channel, &config->clock_info);
+
+ dispc_mgr_set_tft_data_lines(channel, config->video_port_width);
+
+ dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity);
+
+ dispc_mgr_set_lcd_type_tft(channel);
+}
+EXPORT_SYMBOL(dispc_mgr_set_lcd_config);
+
+static bool _dispc_mgr_size_ok(u16 width, u16 height)
+{
+ return width <= dispc.feat->mgr_width_max &&
+ height <= dispc.feat->mgr_height_max;
+}
+
+static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp)
+{
+ if (hsw < 1 || hsw > dispc.feat->sw_max ||
+ hfp < 1 || hfp > dispc.feat->hp_max ||
+ hbp < 1 || hbp > dispc.feat->hp_max ||
+ vsw < 1 || vsw > dispc.feat->sw_max ||
+ vfp < 0 || vfp > dispc.feat->vp_max ||
+ vbp < 0 || vbp > dispc.feat->vp_max)
+ return false;
+ return true;
+}
+
+static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
+ unsigned long pclk)
+{
+ if (dss_mgr_is_lcd(channel))
+ return pclk <= dispc.feat->max_lcd_pclk ? true : false;
+ else
+ return pclk <= dispc.feat->max_tv_pclk ? true : false;
+}
+
+bool dispc_mgr_timings_ok(enum omap_channel channel,
+ const struct omap_video_timings *timings)
+{
+ if (!_dispc_mgr_size_ok(timings->x_res, timings->y_res))
+ return false;
+
+ if (!_dispc_mgr_pclk_ok(channel, timings->pixelclock))
+ return false;
+
+ if (dss_mgr_is_lcd(channel)) {
+ /* TODO: OMAP4+ supports interlace for LCD outputs */
+ if (timings->interlace)
+ return false;
+
+ if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
+ timings->hbp, timings->vsw, timings->vfp,
+ timings->vbp))
+ return false;
+ }
+
+ return true;
+}
+
+static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
+ int hfp, int hbp, int vsw, int vfp, int vbp,
+ enum omap_dss_signal_level vsync_level,
+ enum omap_dss_signal_level hsync_level,
+ enum omap_dss_signal_edge data_pclk_edge,
+ enum omap_dss_signal_level de_level,
+ enum omap_dss_signal_edge sync_pclk_edge)
+
+{
+ u32 timing_h, timing_v, l;
+ bool onoff, rf, ipc, vs, hs, de;
+
+ timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
+ FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
+ timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(vfp, dispc.feat->fp_start, 8) |
+ FLD_VAL(vbp, dispc.feat->bp_start, 20);
+
+ dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
+ dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
+
+ switch (vsync_level) {
+ case OMAPDSS_SIG_ACTIVE_LOW:
+ vs = true;
+ break;
+ case OMAPDSS_SIG_ACTIVE_HIGH:
+ vs = false;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (hsync_level) {
+ case OMAPDSS_SIG_ACTIVE_LOW:
+ hs = true;
+ break;
+ case OMAPDSS_SIG_ACTIVE_HIGH:
+ hs = false;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (de_level) {
+ case OMAPDSS_SIG_ACTIVE_LOW:
+ de = true;
+ break;
+ case OMAPDSS_SIG_ACTIVE_HIGH:
+ de = false;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (data_pclk_edge) {
+ case OMAPDSS_DRIVE_SIG_RISING_EDGE:
+ ipc = false;
+ break;
+ case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
+ ipc = true;
+ break;
+ default:
+ BUG();
+ }
+
+ /* always use the 'rf' setting */
+ onoff = true;
+
+ switch (sync_pclk_edge) {
+ case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
+ rf = false;
+ break;
+ case OMAPDSS_DRIVE_SIG_RISING_EDGE:
+ rf = true;
+ break;
+ default:
+ BUG();
+ }
+
+ l = FLD_VAL(onoff, 17, 17) |
+ FLD_VAL(rf, 16, 16) |
+ FLD_VAL(de, 15, 15) |
+ FLD_VAL(ipc, 14, 14) |
+ FLD_VAL(hs, 13, 13) |
+ FLD_VAL(vs, 12, 12);
+
+ /* always set ALIGN bit when available */
+ if (dispc.feat->supports_sync_align)
+ l |= (1 << 18);
+
+ dispc_write_reg(DISPC_POL_FREQ(channel), l);
+
+ if (dispc.syscon_pol) {
+ const int shifts[] = {
+ [OMAP_DSS_CHANNEL_LCD] = 0,
+ [OMAP_DSS_CHANNEL_LCD2] = 1,
+ [OMAP_DSS_CHANNEL_LCD3] = 2,
+ };
+
+ u32 mask, val;
+
+ mask = (1 << 0) | (1 << 3) | (1 << 6);
+ val = (rf << 0) | (ipc << 3) | (onoff << 6);
+
+ mask <<= 16 + shifts[channel];
+ val <<= 16 + shifts[channel];
+
+ regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
+ mask, val);
+ }
+}
+
+/* change name to mode? */
+void dispc_mgr_set_timings(enum omap_channel channel,
+ const struct omap_video_timings *timings)
+{
+ unsigned xtot, ytot;
+ unsigned long ht, vt;
+ struct omap_video_timings t = *timings;
+
+ DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res);
+
+ if (!dispc_mgr_timings_ok(channel, &t)) {
+ BUG();
+ return;
+ }
+
+ if (dss_mgr_is_lcd(channel)) {
+ _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw,
+ t.vfp, t.vbp, t.vsync_level, t.hsync_level,
+ t.data_pclk_edge, t.de_level, t.sync_pclk_edge);
+
+ xtot = t.x_res + t.hfp + t.hsw + t.hbp;
+ ytot = t.y_res + t.vfp + t.vsw + t.vbp;
+
+ ht = timings->pixelclock / xtot;
+ vt = timings->pixelclock / xtot / ytot;
+
+ DSSDBG("pck %u\n", timings->pixelclock);
+ DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
+ t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp);
+ DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
+ t.vsync_level, t.hsync_level, t.data_pclk_edge,
+ t.de_level, t.sync_pclk_edge);
+
+ DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
+ } else {
+ if (t.interlace)
+ t.y_res /= 2;
+ }
+
+ dispc_mgr_set_size(channel, t.x_res, t.y_res);
+}
+EXPORT_SYMBOL(dispc_mgr_set_timings);
+
+static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
+ u16 pck_div)
+{
+ BUG_ON(lck_div < 1);
+ BUG_ON(pck_div < 1);
+
+ dispc_write_reg(DISPC_DIVISORo(channel),
+ FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
+
+ if (!dss_has_feature(FEAT_CORE_CLK_DIV) &&
+ channel == OMAP_DSS_CHANNEL_LCD)
+ dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
+}
+
+static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
+ int *pck_div)
+{
+ u32 l;
+ l = dispc_read_reg(DISPC_DIVISORo(channel));
+ *lck_div = FLD_GET(l, 23, 16);
+ *pck_div = FLD_GET(l, 7, 0);
+}
+
+static unsigned long dispc_fclk_rate(void)
+{
+ struct dss_pll *pll;
+ unsigned long r = 0;
+
+ switch (dss_get_dispc_clk_source()) {
+ case OMAP_DSS_CLK_SRC_FCK:
+ r = dss_get_dispc_clk_rate();
+ break;
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ pll = dss_pll_find("dsi0");
+ if (!pll)
+ pll = dss_pll_find("video0");
+
+ r = pll->cinfo.clkout[0];
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+ pll = dss_pll_find("dsi1");
+ if (!pll)
+ pll = dss_pll_find("video1");
+
+ r = pll->cinfo.clkout[0];
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ return r;
+}
+
+static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
+{
+ struct dss_pll *pll;
+ int lcd;
+ unsigned long r;
+ u32 l;
+
+ if (dss_mgr_is_lcd(channel)) {
+ l = dispc_read_reg(DISPC_DIVISORo(channel));
+
+ lcd = FLD_GET(l, 23, 16);
+
+ switch (dss_get_lcd_clk_source(channel)) {
+ case OMAP_DSS_CLK_SRC_FCK:
+ r = dss_get_dispc_clk_rate();
+ break;
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ pll = dss_pll_find("dsi0");
+ if (!pll)
+ pll = dss_pll_find("video0");
+
+ r = pll->cinfo.clkout[0];
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+ pll = dss_pll_find("dsi1");
+ if (!pll)
+ pll = dss_pll_find("video1");
+
+ r = pll->cinfo.clkout[0];
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ return r / lcd;
+ } else {
+ return dispc_fclk_rate();
+ }
+}
+
+static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
+{
+ unsigned long r;
+
+ if (dss_mgr_is_lcd(channel)) {
+ int pcd;
+ u32 l;
+
+ l = dispc_read_reg(DISPC_DIVISORo(channel));
+
+ pcd = FLD_GET(l, 7, 0);
+
+ r = dispc_mgr_lclk_rate(channel);
+
+ return r / pcd;
+ } else {
+ return dispc.tv_pclk_rate;
+ }
+}
+
+void dispc_set_tv_pclk(unsigned long pclk)
+{
+ dispc.tv_pclk_rate = pclk;
+}
+
+static unsigned long dispc_core_clk_rate(void)
+{
+ return dispc.core_clk_rate;
+}
+
+static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
+{
+ enum omap_channel channel;
+
+ if (plane == OMAP_DSS_WB)
+ return 0;
+
+ channel = dispc_ovl_get_channel_out(plane);
+
+ return dispc_mgr_pclk_rate(channel);
+}
+
+static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
+{
+ enum omap_channel channel;
+
+ if (plane == OMAP_DSS_WB)
+ return 0;
+
+ channel = dispc_ovl_get_channel_out(plane);
+
+ return dispc_mgr_lclk_rate(channel);
+}
+
+static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
+{
+ int lcd, pcd;
+ enum omap_dss_clk_source lcd_clk_src;
+
+ seq_printf(s, "- %s -\n", mgr_desc[channel].name);
+
+ lcd_clk_src = dss_get_lcd_clk_source(channel);
+
+ seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name,
+ dss_get_generic_clk_source_name(lcd_clk_src),
+ dss_feat_get_clk_source_name(lcd_clk_src));
+
+ dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
+
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ dispc_mgr_lclk_rate(channel), lcd);
+ seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+ dispc_mgr_pclk_rate(channel), pcd);
+}
+
+void dispc_dump_clocks(struct seq_file *s)
+{
+ int lcd;
+ u32 l;
+ enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
+
+ if (dispc_runtime_get())
+ return;
+
+ seq_printf(s, "- DISPC -\n");
+
+ seq_printf(s, "dispc fclk source = %s (%s)\n",
+ dss_get_generic_clk_source_name(dispc_clk_src),
+ dss_feat_get_clk_source_name(dispc_clk_src));
+
+ seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
+
+ if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+ seq_printf(s, "- DISPC-CORE-CLK -\n");
+ l = dispc_read_reg(DISPC_DIVISOR);
+ lcd = FLD_GET(l, 23, 16);
+
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ (dispc_fclk_rate()/lcd), lcd);
+ }
+
+ dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
+
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
+ if (dss_has_feature(FEAT_MGR_LCD3))
+ dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
+
+ dispc_runtime_put();
+}
+
+static void dispc_dump_regs(struct seq_file *s)
+{
+ int i, j;
+ const char *mgr_names[] = {
+ [OMAP_DSS_CHANNEL_LCD] = "LCD",
+ [OMAP_DSS_CHANNEL_DIGIT] = "TV",
+ [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
+ [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
+ };
+ const char *ovl_names[] = {
+ [OMAP_DSS_GFX] = "GFX",
+ [OMAP_DSS_VIDEO1] = "VID1",
+ [OMAP_DSS_VIDEO2] = "VID2",
+ [OMAP_DSS_VIDEO3] = "VID3",
+ [OMAP_DSS_WB] = "WB",
+ };
+ const char **p_names;
+
+#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
+
+ if (dispc_runtime_get())
+ return;
+
+ /* DISPC common registers */
+ DUMPREG(DISPC_REVISION);
+ DUMPREG(DISPC_SYSCONFIG);
+ DUMPREG(DISPC_SYSSTATUS);
+ DUMPREG(DISPC_IRQSTATUS);
+ DUMPREG(DISPC_IRQENABLE);
+ DUMPREG(DISPC_CONTROL);
+ DUMPREG(DISPC_CONFIG);
+ DUMPREG(DISPC_CAPABLE);
+ DUMPREG(DISPC_LINE_STATUS);
+ DUMPREG(DISPC_LINE_NUMBER);
+ if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+ dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
+ DUMPREG(DISPC_GLOBAL_ALPHA);
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ DUMPREG(DISPC_CONTROL2);
+ DUMPREG(DISPC_CONFIG2);
+ }
+ if (dss_has_feature(FEAT_MGR_LCD3)) {
+ DUMPREG(DISPC_CONTROL3);
+ DUMPREG(DISPC_CONFIG3);
+ }
+ if (dss_has_feature(FEAT_MFLAG))
+ DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE);
+
+#undef DUMPREG
+
+#define DISPC_REG(i, name) name(i)
+#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
+ (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
+ dispc_read_reg(DISPC_REG(i, r)))
+
+ p_names = mgr_names;
+
+ /* DISPC channel specific registers */
+ for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
+ DUMPREG(i, DISPC_DEFAULT_COLOR);
+ DUMPREG(i, DISPC_TRANS_COLOR);
+ DUMPREG(i, DISPC_SIZE_MGR);
+
+ if (i == OMAP_DSS_CHANNEL_DIGIT)
+ continue;
+
+ DUMPREG(i, DISPC_TIMING_H);
+ DUMPREG(i, DISPC_TIMING_V);
+ DUMPREG(i, DISPC_POL_FREQ);
+ DUMPREG(i, DISPC_DIVISORo);
+
+ DUMPREG(i, DISPC_DATA_CYCLE1);
+ DUMPREG(i, DISPC_DATA_CYCLE2);
+ DUMPREG(i, DISPC_DATA_CYCLE3);
+
+ if (dss_has_feature(FEAT_CPR)) {
+ DUMPREG(i, DISPC_CPR_COEF_R);
+ DUMPREG(i, DISPC_CPR_COEF_G);
+ DUMPREG(i, DISPC_CPR_COEF_B);
+ }
+ }
+
+ p_names = ovl_names;
+
+ for (i = 0; i < dss_feat_get_num_ovls(); i++) {
+ DUMPREG(i, DISPC_OVL_BA0);
+ DUMPREG(i, DISPC_OVL_BA1);
+ DUMPREG(i, DISPC_OVL_POSITION);
+ DUMPREG(i, DISPC_OVL_SIZE);
+ DUMPREG(i, DISPC_OVL_ATTRIBUTES);
+ DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
+ DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
+ DUMPREG(i, DISPC_OVL_ROW_INC);
+ DUMPREG(i, DISPC_OVL_PIXEL_INC);
+
+ if (dss_has_feature(FEAT_PRELOAD))
+ DUMPREG(i, DISPC_OVL_PRELOAD);
+ if (dss_has_feature(FEAT_MFLAG))
+ DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
+
+ if (i == OMAP_DSS_GFX) {
+ DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
+ DUMPREG(i, DISPC_OVL_TABLE_BA);
+ continue;
+ }
+
+ DUMPREG(i, DISPC_OVL_FIR);
+ DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
+ DUMPREG(i, DISPC_OVL_ACCU0);
+ DUMPREG(i, DISPC_OVL_ACCU1);
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ DUMPREG(i, DISPC_OVL_BA0_UV);
+ DUMPREG(i, DISPC_OVL_BA1_UV);
+ DUMPREG(i, DISPC_OVL_FIR2);
+ DUMPREG(i, DISPC_OVL_ACCU2_0);
+ DUMPREG(i, DISPC_OVL_ACCU2_1);
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
+ }
+
+ if (dispc.feat->has_writeback) {
+ i = OMAP_DSS_WB;
+ DUMPREG(i, DISPC_OVL_BA0);
+ DUMPREG(i, DISPC_OVL_BA1);
+ DUMPREG(i, DISPC_OVL_SIZE);
+ DUMPREG(i, DISPC_OVL_ATTRIBUTES);
+ DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
+ DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
+ DUMPREG(i, DISPC_OVL_ROW_INC);
+ DUMPREG(i, DISPC_OVL_PIXEL_INC);
+
+ if (dss_has_feature(FEAT_MFLAG))
+ DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
+
+ DUMPREG(i, DISPC_OVL_FIR);
+ DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
+ DUMPREG(i, DISPC_OVL_ACCU0);
+ DUMPREG(i, DISPC_OVL_ACCU1);
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ DUMPREG(i, DISPC_OVL_BA0_UV);
+ DUMPREG(i, DISPC_OVL_BA1_UV);
+ DUMPREG(i, DISPC_OVL_FIR2);
+ DUMPREG(i, DISPC_OVL_ACCU2_0);
+ DUMPREG(i, DISPC_OVL_ACCU2_1);
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
+ }
+
+#undef DISPC_REG
+#undef DUMPREG
+
+#define DISPC_REG(plane, name, i) name(plane, i)
+#define DUMPREG(plane, name, i) \
+ seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
+ (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
+ dispc_read_reg(DISPC_REG(plane, name, i)))
+
+ /* Video pipeline coefficient registers */
+
+ /* start from OMAP_DSS_VIDEO1 */
+ for (i = 1; i < dss_feat_get_num_ovls(); i++) {
+ for (j = 0; j < 8; j++)
+ DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
+
+ for (j = 0; j < 8; j++)
+ DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
+
+ for (j = 0; j < 5; j++)
+ DUMPREG(i, DISPC_OVL_CONV_COEF, j);
+
+ if (dss_has_feature(FEAT_FIR_COEF_V)) {
+ for (j = 0; j < 8; j++)
+ DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
+ }
+
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ for (j = 0; j < 8; j++)
+ DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
+
+ for (j = 0; j < 8; j++)
+ DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
+
+ for (j = 0; j < 8; j++)
+ DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
+ }
+ }
+
+ dispc_runtime_put();
+
+#undef DISPC_REG
+#undef DUMPREG
+}
+
+/* calculate clock rates using dividers in cinfo */
+int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
+ struct dispc_clock_info *cinfo)
+{
+ if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
+ return -EINVAL;
+ if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
+ return -EINVAL;
+
+ cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
+ cinfo->pck = cinfo->lck / cinfo->pck_div;
+
+ return 0;
+}
+
+bool dispc_div_calc(unsigned long dispc,
+ unsigned long pck_min, unsigned long pck_max,
+ dispc_div_calc_func func, void *data)
+{
+ int lckd, lckd_start, lckd_stop;
+ int pckd, pckd_start, pckd_stop;
+ unsigned long pck, lck;
+ unsigned long lck_max;
+ unsigned long pckd_hw_min, pckd_hw_max;
+ unsigned min_fck_per_pck;
+ unsigned long fck;
+
+#ifdef CONFIG_FB_OMAP2_DSS_MIN_FCK_PER_PCK
+ min_fck_per_pck = CONFIG_FB_OMAP2_DSS_MIN_FCK_PER_PCK;
+#else
+ min_fck_per_pck = 0;
+#endif
+
+ pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
+ pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
+
+ lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ pck_min = pck_min ? pck_min : 1;
+ pck_max = pck_max ? pck_max : ULONG_MAX;
+
+ lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
+ lckd_stop = min(dispc / pck_min, 255ul);
+
+ for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
+ lck = dispc / lckd;
+
+ pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
+ pckd_stop = min(lck / pck_min, pckd_hw_max);
+
+ for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
+ pck = lck / pckd;
+
+ /*
+ * For OMAP2/3 the DISPC fclk is the same as LCD's logic
+ * clock, which means we're configuring DISPC fclk here
+ * also. Thus we need to use the calculated lck. For
+ * OMAP4+ the DISPC fclk is a separate clock.
+ */
+ if (dss_has_feature(FEAT_CORE_CLK_DIV))
+ fck = dispc_core_clk_rate();
+ else
+ fck = lck;
+
+ if (fck < pck * min_fck_per_pck)
+ continue;
+
+ if (func(lckd, pckd, lck, pck, data))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void dispc_mgr_set_clock_div(enum omap_channel channel,
+ const struct dispc_clock_info *cinfo)
+{
+ DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
+ DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
+
+ dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
+}
+
+int dispc_mgr_get_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo)
+{
+ unsigned long fck;
+
+ fck = dispc_fclk_rate();
+
+ cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
+ cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
+
+ cinfo->lck = fck / cinfo->lck_div;
+ cinfo->pck = cinfo->lck / cinfo->pck_div;
+
+ return 0;
+}
+
+u32 dispc_read_irqstatus(void)
+{
+ return dispc_read_reg(DISPC_IRQSTATUS);
+}
+EXPORT_SYMBOL(dispc_read_irqstatus);
+
+void dispc_clear_irqstatus(u32 mask)
+{
+ dispc_write_reg(DISPC_IRQSTATUS, mask);
+}
+EXPORT_SYMBOL(dispc_clear_irqstatus);
+
+u32 dispc_read_irqenable(void)
+{
+ return dispc_read_reg(DISPC_IRQENABLE);
+}
+EXPORT_SYMBOL(dispc_read_irqenable);
+
+void dispc_write_irqenable(u32 mask)
+{
+ u32 old_mask = dispc_read_reg(DISPC_IRQENABLE);
+
+ /* clear the irqstatus for newly enabled irqs */
+ dispc_clear_irqstatus((mask ^ old_mask) & mask);
+
+ dispc_write_reg(DISPC_IRQENABLE, mask);
+}
+EXPORT_SYMBOL(dispc_write_irqenable);
+
+void dispc_enable_sidle(void)
+{
+ REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
+}
+
+void dispc_disable_sidle(void)
+{
+ REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
+}
+
+static void _omap_dispc_initial_config(void)
+{
+ u32 l;
+
+ /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
+ if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+ l = dispc_read_reg(DISPC_DIVISOR);
+ /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
+ l = FLD_MOD(l, 1, 0, 0);
+ l = FLD_MOD(l, 1, 23, 16);
+ dispc_write_reg(DISPC_DIVISOR, l);
+
+ dispc.core_clk_rate = dispc_fclk_rate();
+ }
+
+ /* FUNCGATED */
+ if (dss_has_feature(FEAT_FUNCGATED))
+ REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
+
+ dispc_setup_color_conv_coef();
+
+ dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
+
+ dispc_init_fifos();
+
+ dispc_configure_burst_sizes();
+
+ dispc_ovl_enable_zorder_planes();
+
+ if (dispc.feat->mstandby_workaround)
+ REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
+
+ if (dss_has_feature(FEAT_MFLAG))
+ dispc_init_mflag();
+}
+
+static const struct dispc_features omap24xx_dispc_feats = {
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .sw_max = 64,
+ .vp_max = 255,
+ .hp_max = 256,
+ .mgr_width_start = 10,
+ .mgr_height_start = 26,
+ .mgr_width_max = 2048,
+ .mgr_height_max = 2048,
+ .max_lcd_pclk = 66500000,
+ .calc_scaling = dispc_ovl_calc_scaling_24xx,
+ .calc_core_clk = calc_core_clk_24xx,
+ .num_fifos = 3,
+ .no_framedone_tv = true,
+ .set_max_preload = false,
+ .last_pixel_inc_missing = true,
+};
+
+static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .sw_max = 64,
+ .vp_max = 255,
+ .hp_max = 256,
+ .mgr_width_start = 10,
+ .mgr_height_start = 26,
+ .mgr_width_max = 2048,
+ .mgr_height_max = 2048,
+ .max_lcd_pclk = 173000000,
+ .max_tv_pclk = 59000000,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .num_fifos = 3,
+ .no_framedone_tv = true,
+ .set_max_preload = false,
+ .last_pixel_inc_missing = true,
+};
+
+static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .mgr_width_start = 10,
+ .mgr_height_start = 26,
+ .mgr_width_max = 2048,
+ .mgr_height_max = 2048,
+ .max_lcd_pclk = 173000000,
+ .max_tv_pclk = 59000000,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .num_fifos = 3,
+ .no_framedone_tv = true,
+ .set_max_preload = false,
+ .last_pixel_inc_missing = true,
+};
+
+static const struct dispc_features omap44xx_dispc_feats = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .mgr_width_start = 10,
+ .mgr_height_start = 26,
+ .mgr_width_max = 2048,
+ .mgr_height_max = 2048,
+ .max_lcd_pclk = 170000000,
+ .max_tv_pclk = 185625000,
+ .calc_scaling = dispc_ovl_calc_scaling_44xx,
+ .calc_core_clk = calc_core_clk_44xx,
+ .num_fifos = 5,
+ .gfx_fifo_workaround = true,
+ .set_max_preload = true,
+ .supports_sync_align = true,
+ .has_writeback = true,
+};
+
+static const struct dispc_features omap54xx_dispc_feats = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .mgr_width_start = 11,
+ .mgr_height_start = 27,
+ .mgr_width_max = 4096,
+ .mgr_height_max = 4096,
+ .max_lcd_pclk = 170000000,
+ .max_tv_pclk = 186000000,
+ .calc_scaling = dispc_ovl_calc_scaling_44xx,
+ .calc_core_clk = calc_core_clk_44xx,
+ .num_fifos = 5,
+ .gfx_fifo_workaround = true,
+ .mstandby_workaround = true,
+ .set_max_preload = true,
+ .supports_sync_align = true,
+ .has_writeback = true,
+};
+
+static int dispc_init_features(struct platform_device *pdev)
+{
+ const struct dispc_features *src;
+ struct dispc_features *dst;
+
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(&pdev->dev, "Failed to allocate DISPC Features\n");
+ return -ENOMEM;
+ }
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ src = &omap24xx_dispc_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ src = &omap34xx_rev1_0_dispc_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ case OMAPDSS_VER_AM43xx:
+ src = &omap34xx_rev3_0_dispc_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ src = &omap44xx_dispc_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
+ src = &omap54xx_dispc_feats;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ dispc.feat = dst;
+
+ return 0;
+}
+
+static irqreturn_t dispc_irq_handler(int irq, void *arg)
+{
+ if (!dispc.is_enabled)
+ return IRQ_NONE;
+
+ return dispc.user_handler(irq, dispc.user_data);
+}
+
+int dispc_request_irq(irq_handler_t handler, void *dev_id)
+{
+ int r;
+
+ if (dispc.user_handler != NULL)
+ return -EBUSY;
+
+ dispc.user_handler = handler;
+ dispc.user_data = dev_id;
+
+ /* ensure the dispc_irq_handler sees the values above */
+ smp_wmb();
+
+ r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler,
+ IRQF_SHARED, "OMAP DISPC", &dispc);
+ if (r) {
+ dispc.user_handler = NULL;
+ dispc.user_data = NULL;
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(dispc_request_irq);
+
+void dispc_free_irq(void *dev_id)
+{
+ devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc);
+
+ dispc.user_handler = NULL;
+ dispc.user_data = NULL;
+}
+EXPORT_SYMBOL(dispc_free_irq);
+
+/* DISPC HW IP initialisation */
+static int dispc_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ u32 rev;
+ int r = 0;
+ struct resource *dispc_mem;
+ struct device_node *np = pdev->dev.of_node;
+
+ dispc.pdev = pdev;
+
+ spin_lock_init(&dispc.control_lock);
+
+ r = dispc_init_features(dispc.pdev);
+ if (r)
+ return r;
+
+ dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
+ if (!dispc_mem) {
+ DSSERR("can't get IORESOURCE_MEM DISPC\n");
+ return -EINVAL;
+ }
+
+ dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
+ resource_size(dispc_mem));
+ if (!dispc.base) {
+ DSSERR("can't ioremap DISPC\n");
+ return -ENOMEM;
+ }
+
+ dispc.irq = platform_get_irq(dispc.pdev, 0);
+ if (dispc.irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ return -ENODEV;
+ }
+
+ if (np && of_property_read_bool(np, "syscon-pol")) {
+ dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
+ if (IS_ERR(dispc.syscon_pol)) {
+ dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
+ return PTR_ERR(dispc.syscon_pol);
+ }
+
+ if (of_property_read_u32_index(np, "syscon-pol", 1,
+ &dispc.syscon_pol_offset)) {
+ dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
+ return -EINVAL;
+ }
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ r = dispc_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ _omap_dispc_initial_config();
+
+ rev = dispc_read_reg(DISPC_REVISION);
+ dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ dispc_runtime_put();
+
+ dss_init_overlay_managers();
+
+ dss_debugfs_create_file("dispc", dispc_dump_regs);
+
+ return 0;
+
+err_runtime_get:
+ pm_runtime_disable(&pdev->dev);
+ return r;
+}
+
+static void dispc_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ pm_runtime_disable(dev);
+
+ dss_uninit_overlay_managers();
+}
+
+static const struct component_ops dispc_component_ops = {
+ .bind = dispc_bind,
+ .unbind = dispc_unbind,
+};
+
+static int dispc_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &dispc_component_ops);
+}
+
+static int dispc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dispc_component_ops);
+ return 0;
+}
+
+static int dispc_runtime_suspend(struct device *dev)
+{
+ dispc.is_enabled = false;
+ /* ensure the dispc_irq_handler sees the is_enabled value */
+ smp_wmb();
+ /* wait for current handler to finish before turning the DISPC off */
+ synchronize_irq(dispc.irq);
+
+ dispc_save_context();
+
+ return 0;
+}
+
+static int dispc_runtime_resume(struct device *dev)
+{
+ /*
+ * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
+ * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
+ * _omap_dispc_initial_config(). We can thus use it to detect if
+ * we have lost register context.
+ */
+ if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
+ _omap_dispc_initial_config();
+
+ dispc_restore_context();
+ }
+
+ dispc.is_enabled = true;
+ /* ensure the dispc_irq_handler sees the is_enabled value */
+ smp_wmb();
+
+ return 0;
+}
+
+static const struct dev_pm_ops dispc_pm_ops = {
+ .runtime_suspend = dispc_runtime_suspend,
+ .runtime_resume = dispc_runtime_resume,
+};
+
+static const struct of_device_id dispc_of_match[] = {
+ { .compatible = "ti,omap2-dispc", },
+ { .compatible = "ti,omap3-dispc", },
+ { .compatible = "ti,omap4-dispc", },
+ { .compatible = "ti,omap5-dispc", },
+ { .compatible = "ti,dra7-dispc", },
+ {},
+};
+
+static struct platform_driver omap_dispchw_driver = {
+ .probe = dispc_probe,
+ .remove = dispc_remove,
+ .driver = {
+ .name = "omapdss_dispc",
+ .pm = &dispc_pm_ops,
+ .of_match_table = dispc_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init dispc_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dispchw_driver);
+}
+
+void dispc_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_dispchw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.h b/drivers/video/fbdev/omap2/omapfb/dss/dispc.h
new file mode 100644
index 000000000000..483744223dd1
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.h
@@ -0,0 +1,918 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc.h
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Archit Taneja <archit@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DISPC_REG_H
+#define __OMAP2_DISPC_REG_H
+
+/* DISPC common registers */
+#define DISPC_REVISION 0x0000
+#define DISPC_SYSCONFIG 0x0010
+#define DISPC_SYSSTATUS 0x0014
+#define DISPC_IRQSTATUS 0x0018
+#define DISPC_IRQENABLE 0x001C
+#define DISPC_CONTROL 0x0040
+#define DISPC_CONFIG 0x0044
+#define DISPC_CAPABLE 0x0048
+#define DISPC_LINE_STATUS 0x005C
+#define DISPC_LINE_NUMBER 0x0060
+#define DISPC_GLOBAL_ALPHA 0x0074
+#define DISPC_CONTROL2 0x0238
+#define DISPC_CONFIG2 0x0620
+#define DISPC_DIVISOR 0x0804
+#define DISPC_GLOBAL_BUFFER 0x0800
+#define DISPC_CONTROL3 0x0848
+#define DISPC_CONFIG3 0x084C
+#define DISPC_MSTANDBY_CTRL 0x0858
+#define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C
+
+/* DISPC overlay registers */
+#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
+ DISPC_BA0_OFFSET(n))
+#define DISPC_OVL_BA1(n) (DISPC_OVL_BASE(n) + \
+ DISPC_BA1_OFFSET(n))
+#define DISPC_OVL_BA0_UV(n) (DISPC_OVL_BASE(n) + \
+ DISPC_BA0_UV_OFFSET(n))
+#define DISPC_OVL_BA1_UV(n) (DISPC_OVL_BASE(n) + \
+ DISPC_BA1_UV_OFFSET(n))
+#define DISPC_OVL_POSITION(n) (DISPC_OVL_BASE(n) + \
+ DISPC_POS_OFFSET(n))
+#define DISPC_OVL_SIZE(n) (DISPC_OVL_BASE(n) + \
+ DISPC_SIZE_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ATTR_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES2(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ATTR2_OFFSET(n))
+#define DISPC_OVL_FIFO_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
+ DISPC_FIFO_THRESH_OFFSET(n))
+#define DISPC_OVL_FIFO_SIZE_STATUS(n) (DISPC_OVL_BASE(n) + \
+ DISPC_FIFO_SIZE_STATUS_OFFSET(n))
+#define DISPC_OVL_ROW_INC(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ROW_INC_OFFSET(n))
+#define DISPC_OVL_PIXEL_INC(n) (DISPC_OVL_BASE(n) + \
+ DISPC_PIX_INC_OFFSET(n))
+#define DISPC_OVL_WINDOW_SKIP(n) (DISPC_OVL_BASE(n) + \
+ DISPC_WINDOW_SKIP_OFFSET(n))
+#define DISPC_OVL_TABLE_BA(n) (DISPC_OVL_BASE(n) + \
+ DISPC_TABLE_BA_OFFSET(n))
+#define DISPC_OVL_FIR(n) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_OFFSET(n))
+#define DISPC_OVL_FIR2(n) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR2_OFFSET(n))
+#define DISPC_OVL_PICTURE_SIZE(n) (DISPC_OVL_BASE(n) + \
+ DISPC_PIC_SIZE_OFFSET(n))
+#define DISPC_OVL_ACCU0(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ACCU0_OFFSET(n))
+#define DISPC_OVL_ACCU1(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ACCU1_OFFSET(n))
+#define DISPC_OVL_ACCU2_0(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ACCU2_0_OFFSET(n))
+#define DISPC_OVL_ACCU2_1(n) (DISPC_OVL_BASE(n) + \
+ DISPC_ACCU2_1_OFFSET(n))
+#define DISPC_OVL_FIR_COEF_H(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_COEF_H_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_COEF_HV_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_H2(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_COEF_H2_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV2(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_COEF_HV2_OFFSET(n, i))
+#define DISPC_OVL_CONV_COEF(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_CONV_COEF_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_COEF_V_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V2(n, i) (DISPC_OVL_BASE(n) + \
+ DISPC_FIR_COEF_V2_OFFSET(n, i))
+#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
+ DISPC_PRELOAD_OFFSET(n))
+#define DISPC_OVL_MFLAG_THRESHOLD(n) DISPC_MFLAG_THRESHOLD_OFFSET(n)
+
+/* DISPC up/downsampling FIR filter coefficient structure */
+struct dispc_coef {
+ s8 hc4_vc22;
+ s8 hc3_vc2;
+ u8 hc2_vc1;
+ s8 hc1_vc0;
+ s8 hc0_vc00;
+};
+
+const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
+
+/* DISPC manager/channel specific registers */
+static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x004C;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ return 0x0050;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03AC;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0814;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0054;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ return 0x0058;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03B0;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0818;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_TIMING_H(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0064;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x0400;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0840;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_TIMING_V(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0068;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x0404;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0844;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x006C;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x0408;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x083C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_DIVISORo(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0070;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x040C;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0838;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
+static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x007C;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ return 0x0078;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03CC;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0834;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x01D4;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03C0;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0828;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x01D8;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03C4;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x082C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x01DC;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03C8;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0830;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0220;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03BC;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0824;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0224;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03B8;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x0820;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return 0x0228;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ BUG();
+ return 0;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return 0x03B4;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return 0x081C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* DISPC overlay register base addresses */
+static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0080;
+ case OMAP_DSS_VIDEO1:
+ return 0x00BC;
+ case OMAP_DSS_VIDEO2:
+ return 0x014C;
+ case OMAP_DSS_VIDEO3:
+ return 0x0300;
+ case OMAP_DSS_WB:
+ return 0x0500;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* DISPC overlay register offsets */
+static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0000;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0008;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0004;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x000C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0544;
+ case OMAP_DSS_VIDEO2:
+ return 0x04BC;
+ case OMAP_DSS_VIDEO3:
+ return 0x0310;
+ case OMAP_DSS_WB:
+ return 0x0118;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0548;
+ case OMAP_DSS_VIDEO2:
+ return 0x04C0;
+ case OMAP_DSS_VIDEO3:
+ return 0x0314;
+ case OMAP_DSS_WB:
+ return 0x011C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0008;
+ case OMAP_DSS_VIDEO3:
+ return 0x009C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x000C;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x00A8;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0020;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0010;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0070;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0568;
+ case OMAP_DSS_VIDEO2:
+ return 0x04DC;
+ case OMAP_DSS_VIDEO3:
+ return 0x032C;
+ case OMAP_DSS_WB:
+ return 0x0310;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0024;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0014;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x008C;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0028;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0018;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0088;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x002C;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x001C;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x00A4;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0030;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0020;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0098;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0034;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
+ BUG();
+ return 0;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0038;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
+ BUG();
+ return 0;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0024;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0090;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0580;
+ case OMAP_DSS_VIDEO2:
+ return 0x055C;
+ case OMAP_DSS_VIDEO3:
+ return 0x0424;
+ case OMAP_DSS_WB:
+ return 0x290;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0028;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0094;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+
+static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x002C;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0000;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0584;
+ case OMAP_DSS_VIDEO2:
+ return 0x0560;
+ case OMAP_DSS_VIDEO3:
+ return 0x0428;
+ case OMAP_DSS_WB:
+ return 0x0294;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0030;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0004;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0588;
+ case OMAP_DSS_VIDEO2:
+ return 0x0564;
+ case OMAP_DSS_VIDEO3:
+ return 0x042C;
+ case OMAP_DSS_WB:
+ return 0x0298;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0034 + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0010 + i * 0x8;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x058C + i * 0x8;
+ case OMAP_DSS_VIDEO2:
+ return 0x0568 + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ return 0x0430 + i * 0x8;
+ case OMAP_DSS_WB:
+ return 0x02A0 + i * 0x8;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ return 0x0038 + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0014 + i * 0x8;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0590 + i * 8;
+ case OMAP_DSS_VIDEO2:
+ return 0x056C + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ return 0x0434 + i * 0x8;
+ case OMAP_DSS_WB:
+ return 0x02A4 + i * 0x8;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4,} */
+static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0074 + i * 0x4;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x0124 + i * 0x4;
+ case OMAP_DSS_VIDEO2:
+ return 0x00B4 + i * 0x4;
+ case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
+ return 0x0050 + i * 0x4;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ BUG();
+ return 0;
+ case OMAP_DSS_VIDEO1:
+ return 0x05CC + i * 0x4;
+ case OMAP_DSS_VIDEO2:
+ return 0x05A8 + i * 0x4;
+ case OMAP_DSS_VIDEO3:
+ return 0x0470 + i * 0x4;
+ case OMAP_DSS_WB:
+ return 0x02E0 + i * 0x4;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x01AC;
+ case OMAP_DSS_VIDEO1:
+ return 0x0174;
+ case OMAP_DSS_VIDEO2:
+ return 0x00E8;
+ case OMAP_DSS_VIDEO3:
+ return 0x00A0;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u16 DISPC_MFLAG_THRESHOLD_OFFSET(enum omap_plane plane)
+{
+ switch (plane) {
+ case OMAP_DSS_GFX:
+ return 0x0860;
+ case OMAP_DSS_VIDEO1:
+ return 0x0864;
+ case OMAP_DSS_VIDEO2:
+ return 0x0868;
+ case OMAP_DSS_VIDEO3:
+ return 0x086c;
+ case OMAP_DSS_WB:
+ return 0x0870;
+ default:
+ BUG();
+ return 0;
+ }
+}
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c
new file mode 100644
index 000000000000..038c15b04215
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c
@@ -0,0 +1,325 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc_coefs.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Chandrabhanu Mahapatra <cmahapatra@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <video/omapdss.h>
+
+#include "dispc.h"
+
+static const struct dispc_coef coef3_M8[8] = {
+ { 0, 0, 128, 0, 0 },
+ { 0, -4, 123, 9, 0 },
+ { 0, -4, 108, 24, 0 },
+ { 0, -2, 87, 43, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 43, 87, -2, 0 },
+ { 0, 24, 108, -4, 0 },
+ { 0, 9, 123, -4, 0 },
+};
+
+static const struct dispc_coef coef3_M9[8] = {
+ { 0, 6, 116, 6, 0 },
+ { 0, 0, 112, 16, 0 },
+ { 0, -2, 100, 30, 0 },
+ { 0, -2, 83, 47, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 47, 83, -2, 0 },
+ { 0, 30, 100, -2, 0 },
+ { 0, 16, 112, 0, 0 },
+};
+
+static const struct dispc_coef coef3_M10[8] = {
+ { 0, 10, 108, 10, 0 },
+ { 0, 3, 104, 21, 0 },
+ { 0, 0, 94, 34, 0 },
+ { 0, -1, 80, 49, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 49, 80, -1, 0 },
+ { 0, 34, 94, 0, 0 },
+ { 0, 21, 104, 3, 0 },
+};
+
+static const struct dispc_coef coef3_M11[8] = {
+ { 0, 14, 100, 14, 0 },
+ { 0, 6, 98, 24, 0 },
+ { 0, 2, 90, 36, 0 },
+ { 0, 0, 78, 50, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 50, 78, 0, 0 },
+ { 0, 36, 90, 2, 0 },
+ { 0, 24, 98, 6, 0 },
+};
+
+static const struct dispc_coef coef3_M12[8] = {
+ { 0, 16, 96, 16, 0 },
+ { 0, 9, 93, 26, 0 },
+ { 0, 4, 86, 38, 0 },
+ { 0, 1, 76, 51, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 51, 76, 1, 0 },
+ { 0, 38, 86, 4, 0 },
+ { 0, 26, 93, 9, 0 },
+};
+
+static const struct dispc_coef coef3_M13[8] = {
+ { 0, 18, 92, 18, 0 },
+ { 0, 10, 90, 28, 0 },
+ { 0, 5, 83, 40, 0 },
+ { 0, 1, 75, 52, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 52, 75, 1, 0 },
+ { 0, 40, 83, 5, 0 },
+ { 0, 28, 90, 10, 0 },
+};
+
+static const struct dispc_coef coef3_M14[8] = {
+ { 0, 20, 88, 20, 0 },
+ { 0, 12, 86, 30, 0 },
+ { 0, 6, 81, 41, 0 },
+ { 0, 2, 74, 52, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 52, 74, 2, 0 },
+ { 0, 41, 81, 6, 0 },
+ { 0, 30, 86, 12, 0 },
+};
+
+static const struct dispc_coef coef3_M16[8] = {
+ { 0, 22, 84, 22, 0 },
+ { 0, 14, 82, 32, 0 },
+ { 0, 8, 78, 42, 0 },
+ { 0, 3, 72, 53, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 53, 72, 3, 0 },
+ { 0, 42, 78, 8, 0 },
+ { 0, 32, 82, 14, 0 },
+};
+
+static const struct dispc_coef coef3_M19[8] = {
+ { 0, 24, 80, 24, 0 },
+ { 0, 16, 79, 33, 0 },
+ { 0, 9, 76, 43, 0 },
+ { 0, 4, 70, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 70, 4, 0 },
+ { 0, 43, 76, 9, 0 },
+ { 0, 33, 79, 16, 0 },
+};
+
+static const struct dispc_coef coef3_M22[8] = {
+ { 0, 25, 78, 25, 0 },
+ { 0, 17, 77, 34, 0 },
+ { 0, 10, 74, 44, 0 },
+ { 0, 5, 69, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 69, 5, 0 },
+ { 0, 44, 74, 10, 0 },
+ { 0, 34, 77, 17, 0 },
+};
+
+static const struct dispc_coef coef3_M26[8] = {
+ { 0, 26, 76, 26, 0 },
+ { 0, 19, 74, 35, 0 },
+ { 0, 11, 72, 45, 0 },
+ { 0, 5, 69, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 69, 5, 0 },
+ { 0, 45, 72, 11, 0 },
+ { 0, 35, 74, 19, 0 },
+};
+
+static const struct dispc_coef coef3_M32[8] = {
+ { 0, 27, 74, 27, 0 },
+ { 0, 19, 73, 36, 0 },
+ { 0, 12, 71, 45, 0 },
+ { 0, 6, 68, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 68, 6, 0 },
+ { 0, 45, 71, 12, 0 },
+ { 0, 36, 73, 19, 0 },
+};
+
+static const struct dispc_coef coef5_M8[8] = {
+ { 0, 0, 128, 0, 0 },
+ { -2, 14, 125, -10, 1 },
+ { -6, 33, 114, -15, 2 },
+ { -10, 55, 98, -16, 1 },
+ { 0, -14, 78, 78, -14 },
+ { 1, -16, 98, 55, -10 },
+ { 2, -15, 114, 33, -6 },
+ { 1, -10, 125, 14, -2 },
+};
+
+static const struct dispc_coef coef5_M9[8] = {
+ { -3, 10, 114, 10, -3 },
+ { -6, 24, 111, 0, -1 },
+ { -8, 40, 103, -7, 0 },
+ { -11, 58, 91, -11, 1 },
+ { 0, -12, 76, 76, -12 },
+ { 1, -11, 91, 58, -11 },
+ { 0, -7, 103, 40, -8 },
+ { -1, 0, 111, 24, -6 },
+};
+
+static const struct dispc_coef coef5_M10[8] = {
+ { -4, 18, 100, 18, -4 },
+ { -6, 30, 99, 8, -3 },
+ { -8, 44, 93, 0, -1 },
+ { -9, 58, 84, -5, 0 },
+ { 0, -8, 72, 72, -8 },
+ { 0, -5, 84, 58, -9 },
+ { -1, 0, 93, 44, -8 },
+ { -3, 8, 99, 30, -6 },
+};
+
+static const struct dispc_coef coef5_M11[8] = {
+ { -5, 23, 92, 23, -5 },
+ { -6, 34, 90, 13, -3 },
+ { -6, 45, 85, 6, -2 },
+ { -6, 57, 78, 0, -1 },
+ { 0, -4, 68, 68, -4 },
+ { -1, 0, 78, 57, -6 },
+ { -2, 6, 85, 45, -6 },
+ { -3, 13, 90, 34, -6 },
+};
+
+static const struct dispc_coef coef5_M12[8] = {
+ { -4, 26, 84, 26, -4 },
+ { -5, 36, 82, 18, -3 },
+ { -4, 46, 78, 10, -2 },
+ { -3, 55, 72, 5, -1 },
+ { 0, 0, 64, 64, 0 },
+ { -1, 5, 72, 55, -3 },
+ { -2, 10, 78, 46, -4 },
+ { -3, 18, 82, 36, -5 },
+};
+
+static const struct dispc_coef coef5_M13[8] = {
+ { -3, 28, 78, 28, -3 },
+ { -3, 37, 76, 21, -3 },
+ { -2, 45, 73, 14, -2 },
+ { 0, 53, 68, 8, -1 },
+ { 0, 3, 61, 61, 3 },
+ { -1, 8, 68, 53, 0 },
+ { -2, 14, 73, 45, -2 },
+ { -3, 21, 76, 37, -3 },
+};
+
+static const struct dispc_coef coef5_M14[8] = {
+ { -2, 30, 72, 30, -2 },
+ { -1, 37, 71, 23, -2 },
+ { 0, 45, 69, 16, -2 },
+ { 3, 52, 64, 10, -1 },
+ { 0, 6, 58, 58, 6 },
+ { -1, 10, 64, 52, 3 },
+ { -2, 16, 69, 45, 0 },
+ { -2, 23, 71, 37, -1 },
+};
+
+static const struct dispc_coef coef5_M16[8] = {
+ { 0, 31, 66, 31, 0 },
+ { 1, 38, 65, 25, -1 },
+ { 3, 44, 62, 20, -1 },
+ { 6, 49, 59, 14, 0 },
+ { 0, 10, 54, 54, 10 },
+ { 0, 14, 59, 49, 6 },
+ { -1, 20, 62, 44, 3 },
+ { -1, 25, 65, 38, 1 },
+};
+
+static const struct dispc_coef coef5_M19[8] = {
+ { 3, 32, 58, 32, 3 },
+ { 4, 38, 58, 27, 1 },
+ { 7, 42, 55, 23, 1 },
+ { 10, 46, 54, 18, 0 },
+ { 0, 14, 50, 50, 14 },
+ { 0, 18, 54, 46, 10 },
+ { 1, 23, 55, 42, 7 },
+ { 1, 27, 58, 38, 4 },
+};
+
+static const struct dispc_coef coef5_M22[8] = {
+ { 4, 33, 54, 33, 4 },
+ { 6, 37, 54, 28, 3 },
+ { 9, 41, 53, 24, 1 },
+ { 12, 45, 51, 20, 0 },
+ { 0, 16, 48, 48, 16 },
+ { 0, 20, 51, 45, 12 },
+ { 1, 24, 53, 41, 9 },
+ { 3, 28, 54, 37, 6 },
+};
+
+static const struct dispc_coef coef5_M26[8] = {
+ { 6, 33, 50, 33, 6 },
+ { 8, 36, 51, 29, 4 },
+ { 11, 40, 50, 25, 2 },
+ { 14, 43, 48, 22, 1 },
+ { 0, 18, 46, 46, 18 },
+ { 1, 22, 48, 43, 14 },
+ { 2, 25, 50, 40, 11 },
+ { 4, 29, 51, 36, 8 },
+};
+
+static const struct dispc_coef coef5_M32[8] = {
+ { 7, 33, 48, 33, 7 },
+ { 10, 36, 48, 29, 5 },
+ { 13, 39, 47, 26, 3 },
+ { 16, 42, 46, 23, 1 },
+ { 0, 19, 45, 45, 19 },
+ { 1, 23, 46, 42, 16 },
+ { 3, 26, 47, 39, 13 },
+ { 5, 29, 48, 36, 10 },
+};
+
+const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
+{
+ int i;
+ static const struct {
+ int Mmin;
+ int Mmax;
+ const struct dispc_coef *coef_3;
+ const struct dispc_coef *coef_5;
+ } coefs[] = {
+ { 27, 32, coef3_M32, coef5_M32 },
+ { 23, 26, coef3_M26, coef5_M26 },
+ { 20, 22, coef3_M22, coef5_M22 },
+ { 17, 19, coef3_M19, coef5_M19 },
+ { 15, 16, coef3_M16, coef5_M16 },
+ { 14, 14, coef3_M14, coef5_M14 },
+ { 13, 13, coef3_M13, coef5_M13 },
+ { 12, 12, coef3_M12, coef5_M12 },
+ { 11, 11, coef3_M11, coef5_M11 },
+ { 10, 10, coef3_M10, coef5_M10 },
+ { 9, 9, coef3_M9, coef5_M9 },
+ { 4, 8, coef3_M8, coef5_M8 },
+ /*
+ * When upscaling more than two times, blockiness and outlines
+ * around the image are observed when M8 tables are used. M11,
+ * M16 and M19 tables are used to prevent this.
+ */
+ { 3, 3, coef3_M11, coef5_M11 },
+ { 2, 2, coef3_M16, coef5_M16 },
+ { 0, 1, coef3_M19, coef5_M19 },
+ };
+
+ inc /= 128;
+ for (i = 0; i < ARRAY_SIZE(coefs); ++i)
+ if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
+ return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
+ return NULL;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
new file mode 100644
index 000000000000..75b5286029ee
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "DISPLAY"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include <video/omapdss.h>
+#include "dss.h"
+
+static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ dssdev->name ?
+ dssdev->name : "");
+}
+
+static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ omapdss_device_is_enabled(dssdev));
+}
+
+static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
+ const char *buf, size_t size)
+{
+ int r;
+ bool enable;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ if (enable == omapdss_device_is_enabled(dssdev))
+ return size;
+
+ if (omapdss_device_is_connected(dssdev) == false)
+ return -ENODEV;
+
+ if (enable) {
+ r = dssdev->driver->enable(dssdev);
+ if (r)
+ return r;
+ } else {
+ dssdev->driver->disable(dssdev);
+ }
+
+ return size;
+}
+
+static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ dssdev->driver->get_te ?
+ dssdev->driver->get_te(dssdev) : 0);
+}
+
+static ssize_t display_tear_store(struct omap_dss_device *dssdev,
+ const char *buf, size_t size)
+{
+ int r;
+ bool te;
+
+ if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
+ return -ENOENT;
+
+ r = strtobool(buf, &te);
+ if (r)
+ return r;
+
+ r = dssdev->driver->enable_te(dssdev, te);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
+{
+ struct omap_video_timings t;
+
+ if (!dssdev->driver->get_timings)
+ return -ENOENT;
+
+ dssdev->driver->get_timings(dssdev, &t);
+
+ return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
+ t.pixelclock,
+ t.x_res, t.hfp, t.hbp, t.hsw,
+ t.y_res, t.vfp, t.vbp, t.vsw);
+}
+
+static ssize_t display_timings_store(struct omap_dss_device *dssdev,
+ const char *buf, size_t size)
+{
+ struct omap_video_timings t = dssdev->panel.timings;
+ int r, found;
+
+ if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
+ return -ENOENT;
+
+ found = 0;
+#ifdef CONFIG_FB_OMAP2_DSS_VENC
+ if (strncmp("pal", buf, 3) == 0) {
+ t = omap_dss_pal_timings;
+ found = 1;
+ } else if (strncmp("ntsc", buf, 4) == 0) {
+ t = omap_dss_ntsc_timings;
+ found = 1;
+ }
+#endif
+ if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
+ &t.pixelclock,
+ &t.x_res, &t.hfp, &t.hbp, &t.hsw,
+ &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
+ return -EINVAL;
+
+ r = dssdev->driver->check_timings(dssdev, &t);
+ if (r)
+ return r;
+
+ dssdev->driver->disable(dssdev);
+ dssdev->driver->set_timings(dssdev, &t);
+ r = dssdev->driver->enable(dssdev);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
+{
+ int rotate;
+ if (!dssdev->driver->get_rotate)
+ return -ENOENT;
+ rotate = dssdev->driver->get_rotate(dssdev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
+}
+
+static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
+ const char *buf, size_t size)
+{
+ int rot, r;
+
+ if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
+ return -ENOENT;
+
+ r = kstrtoint(buf, 0, &rot);
+ if (r)
+ return r;
+
+ r = dssdev->driver->set_rotate(dssdev, rot);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
+{
+ int mirror;
+ if (!dssdev->driver->get_mirror)
+ return -ENOENT;
+ mirror = dssdev->driver->get_mirror(dssdev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
+}
+
+static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
+ const char *buf, size_t size)
+{
+ int r;
+ bool mirror;
+
+ if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
+ return -ENOENT;
+
+ r = strtobool(buf, &mirror);
+ if (r)
+ return r;
+
+ r = dssdev->driver->set_mirror(dssdev, mirror);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
+{
+ unsigned int wss;
+
+ if (!dssdev->driver->get_wss)
+ return -ENOENT;
+
+ wss = dssdev->driver->get_wss(dssdev);
+
+ return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
+}
+
+static ssize_t display_wss_store(struct omap_dss_device *dssdev,
+ const char *buf, size_t size)
+{
+ u32 wss;
+ int r;
+
+ if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
+ return -ENOENT;
+
+ r = kstrtou32(buf, 0, &wss);
+ if (r)
+ return r;
+
+ if (wss > 0xfffff)
+ return -EINVAL;
+
+ r = dssdev->driver->set_wss(dssdev, wss);
+ if (r)
+ return r;
+
+ return size;
+}
+
+struct display_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_dss_device *, char *);
+ ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
+};
+
+#define DISPLAY_ATTR(_name, _mode, _show, _store) \
+ struct display_attribute display_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
+ display_enabled_show, display_enabled_store);
+static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
+ display_tear_show, display_tear_store);
+static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
+ display_timings_show, display_timings_store);
+static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
+ display_rotate_show, display_rotate_store);
+static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
+ display_mirror_show, display_mirror_store);
+static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
+ display_wss_show, display_wss_store);
+
+static struct attribute *display_sysfs_attrs[] = {
+ &display_attr_name.attr,
+ &display_attr_display_name.attr,
+ &display_attr_enabled.attr,
+ &display_attr_tear_elim.attr,
+ &display_attr_timings.attr,
+ &display_attr_rotate.attr,
+ &display_attr_mirror.attr,
+ &display_attr_wss.attr,
+ NULL
+};
+
+static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_dss_device *dssdev;
+ struct display_attribute *display_attr;
+
+ dssdev = container_of(kobj, struct omap_dss_device, kobj);
+ display_attr = container_of(attr, struct display_attribute, attr);
+
+ if (!display_attr->show)
+ return -ENOENT;
+
+ return display_attr->show(dssdev, buf);
+}
+
+static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_dss_device *dssdev;
+ struct display_attribute *display_attr;
+
+ dssdev = container_of(kobj, struct omap_dss_device, kobj);
+ display_attr = container_of(attr, struct display_attribute, attr);
+
+ if (!display_attr->store)
+ return -ENOENT;
+
+ return display_attr->store(dssdev, buf, size);
+}
+
+static const struct sysfs_ops display_sysfs_ops = {
+ .show = display_attr_show,
+ .store = display_attr_store,
+};
+
+static struct kobj_type display_ktype = {
+ .sysfs_ops = &display_sysfs_ops,
+ .default_attrs = display_sysfs_attrs,
+};
+
+int display_init_sysfs(struct platform_device *pdev)
+{
+ struct omap_dss_device *dssdev = NULL;
+ int r;
+
+ for_each_dss_dev(dssdev) {
+ r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
+ &pdev->dev.kobj, "%s", dssdev->alias);
+ if (r) {
+ DSSERR("failed to create sysfs files\n");
+ omap_dss_put_device(dssdev);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ display_uninit_sysfs(pdev);
+
+ return r;
+}
+
+void display_uninit_sysfs(struct platform_device *pdev)
+{
+ struct omap_dss_device *dssdev = NULL;
+
+ for_each_dss_dev(dssdev) {
+ if (kobject_name(&dssdev->kobj) == NULL)
+ continue;
+
+ kobject_del(&dssdev->kobj);
+ kobject_put(&dssdev->kobj);
+
+ memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
+ }
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display.c b/drivers/video/fbdev/omap2/omapfb/dss/display.c
new file mode 100644
index 000000000000..ef5b9027985d
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/display.c
@@ -0,0 +1,338 @@
+/*
+ * linux/drivers/video/omap2/dss/display.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "DISPLAY"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include <video/omapdss.h>
+#include "dss.h"
+#include "dss_features.h"
+
+void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
+ u16 *xres, u16 *yres)
+{
+ *xres = dssdev->panel.timings.x_res;
+ *yres = dssdev->panel.timings.y_res;
+}
+EXPORT_SYMBOL(omapdss_default_get_resolution);
+
+int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
+{
+ switch (dssdev->type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ if (dssdev->phy.dpi.data_lines == 24)
+ return 24;
+ else
+ return 16;
+
+ case OMAP_DISPLAY_TYPE_DBI:
+ if (dssdev->ctrl.pixel_size == 24)
+ return 24;
+ else
+ return 16;
+ case OMAP_DISPLAY_TYPE_DSI:
+ if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
+ return 24;
+ else
+ return 16;
+ case OMAP_DISPLAY_TYPE_VENC:
+ case OMAP_DISPLAY_TYPE_SDI:
+ case OMAP_DISPLAY_TYPE_HDMI:
+ case OMAP_DISPLAY_TYPE_DVI:
+ return 24;
+ default:
+ BUG();
+ return 0;
+ }
+}
+EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
+
+void omapdss_default_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = dssdev->panel.timings;
+}
+EXPORT_SYMBOL(omapdss_default_get_timings);
+
+int dss_suspend_all_devices(void)
+{
+ struct omap_dss_device *dssdev = NULL;
+
+ for_each_dss_dev(dssdev) {
+ if (!dssdev->driver)
+ continue;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ dssdev->driver->disable(dssdev);
+ dssdev->activate_after_resume = true;
+ } else {
+ dssdev->activate_after_resume = false;
+ }
+ }
+
+ return 0;
+}
+
+int dss_resume_all_devices(void)
+{
+ struct omap_dss_device *dssdev = NULL;
+
+ for_each_dss_dev(dssdev) {
+ if (!dssdev->driver)
+ continue;
+
+ if (dssdev->activate_after_resume) {
+ dssdev->driver->enable(dssdev);
+ dssdev->activate_after_resume = false;
+ }
+ }
+
+ return 0;
+}
+
+void dss_disable_all_devices(void)
+{
+ struct omap_dss_device *dssdev = NULL;
+
+ for_each_dss_dev(dssdev) {
+ if (!dssdev->driver)
+ continue;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ dssdev->driver->disable(dssdev);
+ }
+}
+
+static LIST_HEAD(panel_list);
+static DEFINE_MUTEX(panel_list_mutex);
+static int disp_num_counter;
+
+int omapdss_register_display(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_driver *drv = dssdev->driver;
+ int id;
+
+ /*
+ * Note: this presumes all the displays are either using DT or non-DT,
+ * which normally should be the case. This also presumes that all
+ * displays either have an DT alias, or none has.
+ */
+
+ if (dssdev->dev->of_node) {
+ id = of_alias_get_id(dssdev->dev->of_node, "display");
+
+ if (id < 0)
+ id = disp_num_counter++;
+ } else {
+ id = disp_num_counter++;
+ }
+
+ snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
+
+ /* Use 'label' property for name, if it exists */
+ if (dssdev->dev->of_node)
+ of_property_read_string(dssdev->dev->of_node, "label",
+ &dssdev->name);
+
+ if (dssdev->name == NULL)
+ dssdev->name = dssdev->alias;
+
+ if (drv && drv->get_resolution == NULL)
+ drv->get_resolution = omapdss_default_get_resolution;
+ if (drv && drv->get_recommended_bpp == NULL)
+ drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
+ if (drv && drv->get_timings == NULL)
+ drv->get_timings = omapdss_default_get_timings;
+
+ mutex_lock(&panel_list_mutex);
+ list_add_tail(&dssdev->panel_list, &panel_list);
+ mutex_unlock(&panel_list_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(omapdss_register_display);
+
+void omapdss_unregister_display(struct omap_dss_device *dssdev)
+{
+ mutex_lock(&panel_list_mutex);
+ list_del(&dssdev->panel_list);
+ mutex_unlock(&panel_list_mutex);
+}
+EXPORT_SYMBOL(omapdss_unregister_display);
+
+struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
+{
+ if (!try_module_get(dssdev->owner))
+ return NULL;
+
+ if (get_device(dssdev->dev) == NULL) {
+ module_put(dssdev->owner);
+ return NULL;
+ }
+
+ return dssdev;
+}
+EXPORT_SYMBOL(omap_dss_get_device);
+
+void omap_dss_put_device(struct omap_dss_device *dssdev)
+{
+ put_device(dssdev->dev);
+ module_put(dssdev->owner);
+}
+EXPORT_SYMBOL(omap_dss_put_device);
+
+/*
+ * ref count of the found device is incremented.
+ * ref count of from-device is decremented.
+ */
+struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
+{
+ struct list_head *l;
+ struct omap_dss_device *dssdev;
+
+ mutex_lock(&panel_list_mutex);
+
+ if (list_empty(&panel_list)) {
+ dssdev = NULL;
+ goto out;
+ }
+
+ if (from == NULL) {
+ dssdev = list_first_entry(&panel_list, struct omap_dss_device,
+ panel_list);
+ omap_dss_get_device(dssdev);
+ goto out;
+ }
+
+ omap_dss_put_device(from);
+
+ list_for_each(l, &panel_list) {
+ dssdev = list_entry(l, struct omap_dss_device, panel_list);
+ if (dssdev == from) {
+ if (list_is_last(l, &panel_list)) {
+ dssdev = NULL;
+ goto out;
+ }
+
+ dssdev = list_entry(l->next, struct omap_dss_device,
+ panel_list);
+ omap_dss_get_device(dssdev);
+ goto out;
+ }
+ }
+
+ WARN(1, "'from' dssdev not found\n");
+
+ dssdev = NULL;
+out:
+ mutex_unlock(&panel_list_mutex);
+ return dssdev;
+}
+EXPORT_SYMBOL(omap_dss_get_next_device);
+
+struct omap_dss_device *omap_dss_find_device(void *data,
+ int (*match)(struct omap_dss_device *dssdev, void *data))
+{
+ struct omap_dss_device *dssdev = NULL;
+
+ while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
+ if (match(dssdev, data))
+ return dssdev;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(omap_dss_find_device);
+
+void videomode_to_omap_video_timings(const struct videomode *vm,
+ struct omap_video_timings *ovt)
+{
+ memset(ovt, 0, sizeof(*ovt));
+
+ ovt->pixelclock = vm->pixelclock;
+ ovt->x_res = vm->hactive;
+ ovt->hbp = vm->hback_porch;
+ ovt->hfp = vm->hfront_porch;
+ ovt->hsw = vm->hsync_len;
+ ovt->y_res = vm->vactive;
+ ovt->vbp = vm->vback_porch;
+ ovt->vfp = vm->vfront_porch;
+ ovt->vsw = vm->vsync_len;
+
+ ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
+ OMAPDSS_SIG_ACTIVE_HIGH :
+ OMAPDSS_SIG_ACTIVE_LOW;
+ ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
+ OMAPDSS_SIG_ACTIVE_HIGH :
+ OMAPDSS_SIG_ACTIVE_LOW;
+ ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
+ OMAPDSS_SIG_ACTIVE_HIGH :
+ OMAPDSS_SIG_ACTIVE_LOW;
+ ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
+ OMAPDSS_DRIVE_SIG_RISING_EDGE :
+ OMAPDSS_DRIVE_SIG_FALLING_EDGE;
+
+ ovt->sync_pclk_edge = ovt->data_pclk_edge;
+}
+EXPORT_SYMBOL(videomode_to_omap_video_timings);
+
+void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
+ struct videomode *vm)
+{
+ memset(vm, 0, sizeof(*vm));
+
+ vm->pixelclock = ovt->pixelclock;
+
+ vm->hactive = ovt->x_res;
+ vm->hback_porch = ovt->hbp;
+ vm->hfront_porch = ovt->hfp;
+ vm->hsync_len = ovt->hsw;
+ vm->vactive = ovt->y_res;
+ vm->vback_porch = ovt->vbp;
+ vm->vfront_porch = ovt->vfp;
+ vm->vsync_len = ovt->vsw;
+
+ if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
+ vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+ else
+ vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+
+ if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
+ vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+ else
+ vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+
+ if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
+ vm->flags |= DISPLAY_FLAGS_DE_HIGH;
+ else
+ vm->flags |= DISPLAY_FLAGS_DE_LOW;
+
+ if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
+ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+ else
+ vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+}
+EXPORT_SYMBOL(omap_video_timings_to_videomode);
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c
new file mode 100644
index 000000000000..7953e6a52346
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c
@@ -0,0 +1,899 @@
+/*
+ * linux/drivers/video/omap2/dss/dpi.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "DPI"
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+#define HSDIV_DISPC 0
+
+struct dpi_data {
+ struct platform_device *pdev;
+
+ struct regulator *vdds_dsi_reg;
+ struct dss_pll *pll;
+
+ struct mutex lock;
+
+ struct omap_video_timings timings;
+ struct dss_lcd_mgr_config mgr_config;
+ int data_lines;
+
+ struct omap_dss_device output;
+
+ bool port_initialized;
+};
+
+static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
+{
+ return container_of(dssdev, struct dpi_data, output);
+}
+
+/* only used in non-DT mode */
+static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
+{
+ return dev_get_drvdata(&pdev->dev);
+}
+
+static struct dss_pll *dpi_get_pll(enum omap_channel channel)
+{
+ /*
+ * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
+ * would also be used for DISPC fclk. Meaning, when the DPI output is
+ * disabled, DISPC clock will be disabled, and TV out will stop.
+ */
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ case OMAPDSS_VER_AM43xx:
+ return NULL;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return dss_pll_find("dsi0");
+ case OMAP_DSS_CHANNEL_LCD2:
+ return dss_pll_find("dsi1");
+ default:
+ return NULL;
+ }
+
+ case OMAPDSS_VER_OMAP5:
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return dss_pll_find("dsi0");
+ case OMAP_DSS_CHANNEL_LCD3:
+ return dss_pll_find("dsi1");
+ default:
+ return NULL;
+ }
+
+ case OMAPDSS_VER_DRA7xx:
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ case OMAP_DSS_CHANNEL_LCD2:
+ return dss_pll_find("video0");
+ case OMAP_DSS_CHANNEL_LCD3:
+ return dss_pll_find("video1");
+ default:
+ return NULL;
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
+{
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
+ case OMAP_DSS_CHANNEL_LCD2:
+ return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
+ default:
+ /* this shouldn't happen */
+ WARN_ON(1);
+ return OMAP_DSS_CLK_SRC_FCK;
+ }
+}
+
+struct dpi_clk_calc_ctx {
+ struct dss_pll *pll;
+
+ /* inputs */
+
+ unsigned long pck_min, pck_max;
+
+ /* outputs */
+
+ struct dss_pll_clock_info dsi_cinfo;
+ unsigned long fck;
+ struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ /*
+ * Odd dividers give us uneven duty cycle, causing problem when level
+ * shifted. So skip all odd dividers when the pixel clock is on the
+ * higher side.
+ */
+ if (ctx->pck_min >= 100000000) {
+ if (lckd > 1 && lckd % 2 != 0)
+ return false;
+
+ if (pckd > 1 && pckd % 2 != 0)
+ return false;
+ }
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ return true;
+}
+
+
+static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ /*
+ * Odd dividers give us uneven duty cycle, causing problem when level
+ * shifted. So skip all odd dividers when the pixel clock is on the
+ * higher side.
+ */
+ if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
+ return false;
+
+ ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+ ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
+
+ return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+
+static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
+ unsigned long clkdco,
+ void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.n = n;
+ ctx->dsi_cinfo.m = m;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkdco = clkdco;
+
+ return dss_pll_hsdiv_calc(ctx->pll, clkdco,
+ ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
+ dpi_calc_hsdiv_cb, ctx);
+}
+
+static bool dpi_calc_dss_cb(unsigned long fck, void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ ctx->fck = fck;
+
+ return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
+ struct dpi_clk_calc_ctx *ctx)
+{
+ unsigned long clkin;
+ unsigned long pll_min, pll_max;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->pll = dpi->pll;
+ ctx->pck_min = pck - 1000;
+ ctx->pck_max = pck + 1000;
+
+ pll_min = 0;
+ pll_max = 0;
+
+ clkin = clk_get_rate(ctx->pll->clkin);
+
+ return dss_pll_calc(ctx->pll, clkin,
+ pll_min, pll_max,
+ dpi_calc_pll_cb, ctx);
+}
+
+static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+ int i;
+
+ /*
+ * DSS fck gives us very few possibilities, so finding a good pixel
+ * clock may not be possible. We try multiple times to find the clock,
+ * each time widening the pixel clock range we look for, up to
+ * +/- ~15MHz.
+ */
+
+ for (i = 0; i < 25; ++i) {
+ bool ok;
+
+ memset(ctx, 0, sizeof(*ctx));
+ if (pck > 1000 * i * i * i)
+ ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
+ else
+ ctx->pck_min = 0;
+ ctx->pck_max = pck + 1000 * i * i * i;
+
+ ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
+ if (ok)
+ return ok;
+ }
+
+ return false;
+}
+
+
+
+static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
+ unsigned long pck_req, unsigned long *fck, int *lck_div,
+ int *pck_div)
+{
+ struct dpi_clk_calc_ctx ctx;
+ int r;
+ bool ok;
+
+ ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
+ if (!ok)
+ return -EINVAL;
+
+ r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
+ if (r)
+ return r;
+
+ dss_select_lcd_clk_source(channel,
+ dpi_get_alt_clk_src(channel));
+
+ dpi->mgr_config.clock_info = ctx.dispc_cinfo;
+
+ *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
+ *lck_div = ctx.dispc_cinfo.lck_div;
+ *pck_div = ctx.dispc_cinfo.pck_div;
+
+ return 0;
+}
+
+static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
+ unsigned long *fck, int *lck_div, int *pck_div)
+{
+ struct dpi_clk_calc_ctx ctx;
+ int r;
+ bool ok;
+
+ ok = dpi_dss_clk_calc(pck_req, &ctx);
+ if (!ok)
+ return -EINVAL;
+
+ r = dss_set_fck_rate(ctx.fck);
+ if (r)
+ return r;
+
+ dpi->mgr_config.clock_info = ctx.dispc_cinfo;
+
+ *fck = ctx.fck;
+ *lck_div = ctx.dispc_cinfo.lck_div;
+ *pck_div = ctx.dispc_cinfo.pck_div;
+
+ return 0;
+}
+
+static int dpi_set_mode(struct dpi_data *dpi)
+{
+ struct omap_dss_device *out = &dpi->output;
+ struct omap_overlay_manager *mgr = out->manager;
+ struct omap_video_timings *t = &dpi->timings;
+ int lck_div = 0, pck_div = 0;
+ unsigned long fck = 0;
+ unsigned long pck;
+ int r = 0;
+
+ if (dpi->pll)
+ r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
+ &lck_div, &pck_div);
+ else
+ r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
+ &lck_div, &pck_div);
+ if (r)
+ return r;
+
+ pck = fck / lck_div / pck_div;
+
+ if (pck != t->pixelclock) {
+ DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
+ t->pixelclock, pck);
+
+ t->pixelclock = pck;
+ }
+
+ dss_mgr_set_timings(mgr, t);
+
+ return 0;
+}
+
+static void dpi_config_lcd_manager(struct dpi_data *dpi)
+{
+ struct omap_dss_device *out = &dpi->output;
+ struct omap_overlay_manager *mgr = out->manager;
+
+ dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
+
+ dpi->mgr_config.stallmode = false;
+ dpi->mgr_config.fifohandcheck = false;
+
+ dpi->mgr_config.video_port_width = dpi->data_lines;
+
+ dpi->mgr_config.lcden_sig_polarity = 0;
+
+ dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
+}
+
+static int dpi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_dss_device *out = &dpi->output;
+ int r;
+
+ mutex_lock(&dpi->lock);
+
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
+ DSSERR("no VDSS_DSI regulator\n");
+ r = -ENODEV;
+ goto err_no_reg;
+ }
+
+ if (out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err_no_out_mgr;
+ }
+
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
+ r = regulator_enable(dpi->vdds_dsi_reg);
+ if (r)
+ goto err_reg_enable;
+ }
+
+ r = dispc_runtime_get();
+ if (r)
+ goto err_get_dispc;
+
+ r = dss_dpi_select_source(out->port_num, out->manager->id);
+ if (r)
+ goto err_src_sel;
+
+ if (dpi->pll) {
+ r = dss_pll_enable(dpi->pll);
+ if (r)
+ goto err_dsi_pll_init;
+ }
+
+ r = dpi_set_mode(dpi);
+ if (r)
+ goto err_set_mode;
+
+ dpi_config_lcd_manager(dpi);
+
+ mdelay(2);
+
+ r = dss_mgr_enable(out->manager);
+ if (r)
+ goto err_mgr_enable;
+
+ mutex_unlock(&dpi->lock);
+
+ return 0;
+
+err_mgr_enable:
+err_set_mode:
+ if (dpi->pll)
+ dss_pll_disable(dpi->pll);
+err_dsi_pll_init:
+err_src_sel:
+ dispc_runtime_put();
+err_get_dispc:
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
+ regulator_disable(dpi->vdds_dsi_reg);
+err_reg_enable:
+err_no_out_mgr:
+err_no_reg:
+ mutex_unlock(&dpi->lock);
+ return r;
+}
+
+static void dpi_display_disable(struct omap_dss_device *dssdev)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_overlay_manager *mgr = dpi->output.manager;
+
+ mutex_lock(&dpi->lock);
+
+ dss_mgr_disable(mgr);
+
+ if (dpi->pll) {
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
+ dss_pll_disable(dpi->pll);
+ }
+
+ dispc_runtime_put();
+
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
+ regulator_disable(dpi->vdds_dsi_reg);
+
+ mutex_unlock(&dpi->lock);
+}
+
+static void dpi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
+ DSSDBG("dpi_set_timings\n");
+
+ mutex_lock(&dpi->lock);
+
+ dpi->timings = *timings;
+
+ mutex_unlock(&dpi->lock);
+}
+
+static void dpi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
+ mutex_lock(&dpi->lock);
+
+ *timings = dpi->timings;
+
+ mutex_unlock(&dpi->lock);
+}
+
+static int dpi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_overlay_manager *mgr = dpi->output.manager;
+ int lck_div, pck_div;
+ unsigned long fck;
+ unsigned long pck;
+ struct dpi_clk_calc_ctx ctx;
+ bool ok;
+
+ if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
+ return -EINVAL;
+
+ if (timings->pixelclock == 0)
+ return -EINVAL;
+
+ if (dpi->pll) {
+ ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
+ if (!ok)
+ return -EINVAL;
+
+ fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
+ } else {
+ ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
+ if (!ok)
+ return -EINVAL;
+
+ fck = ctx.fck;
+ }
+
+ lck_div = ctx.dispc_cinfo.lck_div;
+ pck_div = ctx.dispc_cinfo.pck_div;
+
+ pck = fck / lck_div / pck_div;
+
+ timings->pixelclock = pck;
+
+ return 0;
+}
+
+static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
+ mutex_lock(&dpi->lock);
+
+ dpi->data_lines = data_lines;
+
+ mutex_unlock(&dpi->lock);
+}
+
+static int dpi_verify_dsi_pll(struct dss_pll *pll)
+{
+ int r;
+
+ /* do initial setup with the PLL to see if it is operational */
+
+ r = dss_pll_enable(pll);
+ if (r)
+ return r;
+
+ dss_pll_disable(pll);
+
+ return 0;
+}
+
+static int dpi_init_regulator(struct dpi_data *dpi)
+{
+ struct regulator *vdds_dsi;
+
+ if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
+ return 0;
+
+ if (dpi->vdds_dsi_reg)
+ return 0;
+
+ vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
+ if (IS_ERR(vdds_dsi)) {
+ if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
+ DSSERR("can't get VDDS_DSI regulator\n");
+ return PTR_ERR(vdds_dsi);
+ }
+
+ dpi->vdds_dsi_reg = vdds_dsi;
+
+ return 0;
+}
+
+static void dpi_init_pll(struct dpi_data *dpi)
+{
+ struct dss_pll *pll;
+
+ if (dpi->pll)
+ return;
+
+ pll = dpi_get_pll(dpi->output.dispc_channel);
+ if (!pll)
+ return;
+
+ /* On DRA7 we need to set a mux to use the PLL */
+ if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
+ dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
+
+ if (dpi_verify_dsi_pll(pll)) {
+ DSSWARN("DSI PLL not operational\n");
+ return;
+ }
+
+ dpi->pll = pll;
+}
+
+/*
+ * Return a hardcoded channel for the DPI output. This should work for
+ * current use cases, but this can be later expanded to either resolve
+ * the channel in some more dynamic manner, or get the channel as a user
+ * parameter.
+ */
+static enum omap_channel dpi_get_channel(int port_num)
+{
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ case OMAPDSS_VER_AM43xx:
+ return OMAP_DSS_CHANNEL_LCD;
+
+ case OMAPDSS_VER_DRA7xx:
+ switch (port_num) {
+ case 2:
+ return OMAP_DSS_CHANNEL_LCD3;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD2;
+ case 0:
+ default:
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ return OMAP_DSS_CHANNEL_LCD2;
+
+ case OMAPDSS_VER_OMAP5:
+ return OMAP_DSS_CHANNEL_LCD3;
+
+ default:
+ DSSWARN("unsupported DSS version\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+}
+
+static int dpi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = dpi_init_regulator(dpi);
+ if (r)
+ return r;
+
+ dpi_init_pll(dpi);
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void dpi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static const struct omapdss_dpi_ops dpi_ops = {
+ .connect = dpi_connect,
+ .disconnect = dpi_disconnect,
+
+ .enable = dpi_display_enable,
+ .disable = dpi_display_disable,
+
+ .check_timings = dpi_check_timings,
+ .set_timings = dpi_set_timings,
+ .get_timings = dpi_get_timings,
+
+ .set_data_lines = dpi_set_data_lines,
+};
+
+static void dpi_init_output(struct platform_device *pdev)
+{
+ struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
+ struct omap_dss_device *out = &dpi->output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_DPI;
+ out->output_type = OMAP_DISPLAY_TYPE_DPI;
+ out->name = "dpi.0";
+ out->dispc_channel = dpi_get_channel(0);
+ out->ops.dpi = &dpi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void dpi_uninit_output(struct platform_device *pdev)
+{
+ struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
+ struct omap_dss_device *out = &dpi->output;
+
+ omapdss_unregister_output(out);
+}
+
+static void dpi_init_output_port(struct platform_device *pdev,
+ struct device_node *port)
+{
+ struct dpi_data *dpi = port->data;
+ struct omap_dss_device *out = &dpi->output;
+ int r;
+ u32 port_num;
+
+ r = of_property_read_u32(port, "reg", &port_num);
+ if (r)
+ port_num = 0;
+
+ switch (port_num) {
+ case 2:
+ out->name = "dpi.2";
+ break;
+ case 1:
+ out->name = "dpi.1";
+ break;
+ case 0:
+ default:
+ out->name = "dpi.0";
+ break;
+ }
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_DPI;
+ out->output_type = OMAP_DISPLAY_TYPE_DPI;
+ out->dispc_channel = dpi_get_channel(port_num);
+ out->port_num = port_num;
+ out->ops.dpi = &dpi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void dpi_uninit_output_port(struct device_node *port)
+{
+ struct dpi_data *dpi = port->data;
+ struct omap_dss_device *out = &dpi->output;
+
+ omapdss_unregister_output(out);
+}
+
+static int dpi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dpi_data *dpi;
+
+ dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+ if (!dpi)
+ return -ENOMEM;
+
+ dpi->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, dpi);
+
+ mutex_init(&dpi->lock);
+
+ dpi_init_output(pdev);
+
+ return 0;
+}
+
+static void dpi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ dpi_uninit_output(pdev);
+}
+
+static const struct component_ops dpi_component_ops = {
+ .bind = dpi_bind,
+ .unbind = dpi_unbind,
+};
+
+static int dpi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &dpi_component_ops);
+}
+
+static int dpi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dpi_component_ops);
+ return 0;
+}
+
+static struct platform_driver omap_dpi_driver = {
+ .probe = dpi_probe,
+ .remove = dpi_remove,
+ .driver = {
+ .name = "omapdss_dpi",
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init dpi_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dpi_driver);
+}
+
+void dpi_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_dpi_driver);
+}
+
+int dpi_init_port(struct platform_device *pdev, struct device_node *port)
+{
+ struct dpi_data *dpi;
+ struct device_node *ep;
+ u32 datalines;
+ int r;
+
+ dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+ if (!dpi)
+ return -ENOMEM;
+
+ ep = omapdss_of_get_next_endpoint(port, NULL);
+ if (!ep)
+ return 0;
+
+ r = of_property_read_u32(ep, "data-lines", &datalines);
+ if (r) {
+ DSSERR("failed to parse datalines\n");
+ goto err_datalines;
+ }
+
+ dpi->data_lines = datalines;
+
+ of_node_put(ep);
+
+ dpi->pdev = pdev;
+ port->data = dpi;
+
+ mutex_init(&dpi->lock);
+
+ dpi_init_output_port(pdev, port);
+
+ dpi->port_initialized = true;
+
+ return 0;
+
+err_datalines:
+ of_node_put(ep);
+
+ return r;
+}
+
+void dpi_uninit_port(struct device_node *port)
+{
+ struct dpi_data *dpi = port->data;
+
+ if (!dpi->port_initialized)
+ return;
+
+ dpi_uninit_output_port(port);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c
new file mode 100644
index 000000000000..0eec073b3919
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c
@@ -0,0 +1,5607 @@
+/*
+ * linux/drivers/video/omap2/dss/dsi.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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/>.
+ */
+
+#define DSS_SUBSYS_NAME "DSI"
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/semaphore.h>
+#include <linux/seq_file.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+#include <video/mipi_display.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+#define DSI_CATCH_MISSING_TE
+
+struct dsi_reg { u16 module; u16 idx; };
+
+#define DSI_REG(mod, idx) ((const struct dsi_reg) { mod, idx })
+
+/* DSI Protocol Engine */
+
+#define DSI_PROTO 0
+#define DSI_PROTO_SZ 0x200
+
+#define DSI_REVISION DSI_REG(DSI_PROTO, 0x0000)
+#define DSI_SYSCONFIG DSI_REG(DSI_PROTO, 0x0010)
+#define DSI_SYSSTATUS DSI_REG(DSI_PROTO, 0x0014)
+#define DSI_IRQSTATUS DSI_REG(DSI_PROTO, 0x0018)
+#define DSI_IRQENABLE DSI_REG(DSI_PROTO, 0x001C)
+#define DSI_CTRL DSI_REG(DSI_PROTO, 0x0040)
+#define DSI_GNQ DSI_REG(DSI_PROTO, 0x0044)
+#define DSI_COMPLEXIO_CFG1 DSI_REG(DSI_PROTO, 0x0048)
+#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(DSI_PROTO, 0x004C)
+#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(DSI_PROTO, 0x0050)
+#define DSI_CLK_CTRL DSI_REG(DSI_PROTO, 0x0054)
+#define DSI_TIMING1 DSI_REG(DSI_PROTO, 0x0058)
+#define DSI_TIMING2 DSI_REG(DSI_PROTO, 0x005C)
+#define DSI_VM_TIMING1 DSI_REG(DSI_PROTO, 0x0060)
+#define DSI_VM_TIMING2 DSI_REG(DSI_PROTO, 0x0064)
+#define DSI_VM_TIMING3 DSI_REG(DSI_PROTO, 0x0068)
+#define DSI_CLK_TIMING DSI_REG(DSI_PROTO, 0x006C)
+#define DSI_TX_FIFO_VC_SIZE DSI_REG(DSI_PROTO, 0x0070)
+#define DSI_RX_FIFO_VC_SIZE DSI_REG(DSI_PROTO, 0x0074)
+#define DSI_COMPLEXIO_CFG2 DSI_REG(DSI_PROTO, 0x0078)
+#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(DSI_PROTO, 0x007C)
+#define DSI_VM_TIMING4 DSI_REG(DSI_PROTO, 0x0080)
+#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(DSI_PROTO, 0x0084)
+#define DSI_VM_TIMING5 DSI_REG(DSI_PROTO, 0x0088)
+#define DSI_VM_TIMING6 DSI_REG(DSI_PROTO, 0x008C)
+#define DSI_VM_TIMING7 DSI_REG(DSI_PROTO, 0x0090)
+#define DSI_STOPCLK_TIMING DSI_REG(DSI_PROTO, 0x0094)
+#define DSI_VC_CTRL(n) DSI_REG(DSI_PROTO, 0x0100 + (n * 0x20))
+#define DSI_VC_TE(n) DSI_REG(DSI_PROTO, 0x0104 + (n * 0x20))
+#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0108 + (n * 0x20))
+#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(DSI_PROTO, 0x010C + (n * 0x20))
+#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0110 + (n * 0x20))
+#define DSI_VC_IRQSTATUS(n) DSI_REG(DSI_PROTO, 0x0118 + (n * 0x20))
+#define DSI_VC_IRQENABLE(n) DSI_REG(DSI_PROTO, 0x011C + (n * 0x20))
+
+/* DSIPHY_SCP */
+
+#define DSI_PHY 1
+#define DSI_PHY_OFFSET 0x200
+#define DSI_PHY_SZ 0x40
+
+#define DSI_DSIPHY_CFG0 DSI_REG(DSI_PHY, 0x0000)
+#define DSI_DSIPHY_CFG1 DSI_REG(DSI_PHY, 0x0004)
+#define DSI_DSIPHY_CFG2 DSI_REG(DSI_PHY, 0x0008)
+#define DSI_DSIPHY_CFG5 DSI_REG(DSI_PHY, 0x0014)
+#define DSI_DSIPHY_CFG10 DSI_REG(DSI_PHY, 0x0028)
+
+/* DSI_PLL_CTRL_SCP */
+
+#define DSI_PLL 2
+#define DSI_PLL_OFFSET 0x300
+#define DSI_PLL_SZ 0x20
+
+#define DSI_PLL_CONTROL DSI_REG(DSI_PLL, 0x0000)
+#define DSI_PLL_STATUS DSI_REG(DSI_PLL, 0x0004)
+#define DSI_PLL_GO DSI_REG(DSI_PLL, 0x0008)
+#define DSI_PLL_CONFIGURATION1 DSI_REG(DSI_PLL, 0x000C)
+#define DSI_PLL_CONFIGURATION2 DSI_REG(DSI_PLL, 0x0010)
+
+#define REG_GET(dsidev, idx, start, end) \
+ FLD_GET(dsi_read_reg(dsidev, idx), start, end)
+
+#define REG_FLD_MOD(dsidev, idx, val, start, end) \
+ dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
+
+/* Global interrupts */
+#define DSI_IRQ_VC0 (1 << 0)
+#define DSI_IRQ_VC1 (1 << 1)
+#define DSI_IRQ_VC2 (1 << 2)
+#define DSI_IRQ_VC3 (1 << 3)
+#define DSI_IRQ_WAKEUP (1 << 4)
+#define DSI_IRQ_RESYNC (1 << 5)
+#define DSI_IRQ_PLL_LOCK (1 << 7)
+#define DSI_IRQ_PLL_UNLOCK (1 << 8)
+#define DSI_IRQ_PLL_RECALL (1 << 9)
+#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
+#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
+#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
+#define DSI_IRQ_TE_TRIGGER (1 << 16)
+#define DSI_IRQ_ACK_TRIGGER (1 << 17)
+#define DSI_IRQ_SYNC_LOST (1 << 18)
+#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
+#define DSI_IRQ_TA_TIMEOUT (1 << 20)
+#define DSI_IRQ_ERROR_MASK \
+ (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
+ DSI_IRQ_TA_TIMEOUT)
+#define DSI_IRQ_CHANNEL_MASK 0xf
+
+/* Virtual channel interrupts */
+#define DSI_VC_IRQ_CS (1 << 0)
+#define DSI_VC_IRQ_ECC_CORR (1 << 1)
+#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
+#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
+#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
+#define DSI_VC_IRQ_BTA (1 << 5)
+#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
+#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
+#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
+#define DSI_VC_IRQ_ERROR_MASK \
+ (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
+ DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
+ DSI_VC_IRQ_FIFO_TX_UDF)
+
+/* ComplexIO interrupts */
+#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
+#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
+#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
+#define DSI_CIO_IRQ_ERRSYNCESC4 (1 << 3)
+#define DSI_CIO_IRQ_ERRSYNCESC5 (1 << 4)
+#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
+#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
+#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
+#define DSI_CIO_IRQ_ERRESC4 (1 << 8)
+#define DSI_CIO_IRQ_ERRESC5 (1 << 9)
+#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
+#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
+#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
+#define DSI_CIO_IRQ_ERRCONTROL4 (1 << 13)
+#define DSI_CIO_IRQ_ERRCONTROL5 (1 << 14)
+#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
+#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
+#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
+#define DSI_CIO_IRQ_STATEULPS4 (1 << 18)
+#define DSI_CIO_IRQ_STATEULPS5 (1 << 19)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
+#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
+#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
+#define DSI_CIO_IRQ_ERROR_MASK \
+ (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
+ DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
+ DSI_CIO_IRQ_ERRSYNCESC5 | \
+ DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
+ DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
+ DSI_CIO_IRQ_ERRESC5 | \
+ DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
+ DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
+ DSI_CIO_IRQ_ERRCONTROL5 | \
+ DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
+ DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
+ DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
+ DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
+ DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
+
+typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
+
+static int dsi_display_init_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr);
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr);
+
+static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
+
+/* DSI PLL HSDIV indices */
+#define HSDIV_DISPC 0
+#define HSDIV_DSI 1
+
+#define DSI_MAX_NR_ISRS 2
+#define DSI_MAX_NR_LANES 5
+
+enum dsi_lane_function {
+ DSI_LANE_UNUSED = 0,
+ DSI_LANE_CLK,
+ DSI_LANE_DATA1,
+ DSI_LANE_DATA2,
+ DSI_LANE_DATA3,
+ DSI_LANE_DATA4,
+};
+
+struct dsi_lane_config {
+ enum dsi_lane_function function;
+ u8 polarity;
+};
+
+struct dsi_isr_data {
+ omap_dsi_isr_t isr;
+ void *arg;
+ u32 mask;
+};
+
+enum fifo_size {
+ DSI_FIFO_SIZE_0 = 0,
+ DSI_FIFO_SIZE_32 = 1,
+ DSI_FIFO_SIZE_64 = 2,
+ DSI_FIFO_SIZE_96 = 3,
+ DSI_FIFO_SIZE_128 = 4,
+};
+
+enum dsi_vc_source {
+ DSI_VC_SOURCE_L4 = 0,
+ DSI_VC_SOURCE_VP,
+};
+
+struct dsi_irq_stats {
+ unsigned long last_reset;
+ unsigned irq_count;
+ unsigned dsi_irqs[32];
+ unsigned vc_irqs[4][32];
+ unsigned cio_irqs[32];
+};
+
+struct dsi_isr_tables {
+ struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
+ struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
+ struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
+};
+
+struct dsi_clk_calc_ctx {
+ struct platform_device *dsidev;
+ struct dss_pll *pll;
+
+ /* inputs */
+
+ const struct omap_dss_dsi_config *config;
+
+ unsigned long req_pck_min, req_pck_nom, req_pck_max;
+
+ /* outputs */
+
+ struct dss_pll_clock_info dsi_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+
+ struct omap_video_timings dispc_vm;
+ struct omap_dss_dsi_videomode_timings dsi_vm;
+};
+
+struct dsi_lp_clock_info {
+ unsigned long lp_clk;
+ u16 lp_clk_div;
+};
+
+struct dsi_data {
+ struct platform_device *pdev;
+ void __iomem *proto_base;
+ void __iomem *phy_base;
+ void __iomem *pll_base;
+
+ int module_id;
+
+ int irq;
+
+ bool is_enabled;
+
+ struct clk *dss_clk;
+
+ struct dispc_clock_info user_dispc_cinfo;
+ struct dss_pll_clock_info user_dsi_cinfo;
+
+ struct dsi_lp_clock_info user_lp_cinfo;
+ struct dsi_lp_clock_info current_lp_cinfo;
+
+ struct dss_pll pll;
+
+ bool vdds_dsi_enabled;
+ struct regulator *vdds_dsi_reg;
+
+ struct {
+ enum dsi_vc_source source;
+ struct omap_dss_device *dssdev;
+ enum fifo_size tx_fifo_size;
+ enum fifo_size rx_fifo_size;
+ int vc_id;
+ } vc[4];
+
+ struct mutex lock;
+ struct semaphore bus_lock;
+
+ spinlock_t irq_lock;
+ struct dsi_isr_tables isr_tables;
+ /* space for a copy used by the interrupt handler */
+ struct dsi_isr_tables isr_tables_copy;
+
+ int update_channel;
+#ifdef DSI_PERF_MEASURE
+ unsigned update_bytes;
+#endif
+
+ bool te_enabled;
+ bool ulps_enabled;
+
+ void (*framedone_callback)(int, void *);
+ void *framedone_data;
+
+ struct delayed_work framedone_timeout_work;
+
+#ifdef DSI_CATCH_MISSING_TE
+ struct timer_list te_timer;
+#endif
+
+ unsigned long cache_req_pck;
+ unsigned long cache_clk_freq;
+ struct dss_pll_clock_info cache_cinfo;
+
+ u32 errors;
+ spinlock_t errors_lock;
+#ifdef DSI_PERF_MEASURE
+ ktime_t perf_setup_time;
+ ktime_t perf_start_time;
+#endif
+ int debug_read;
+ int debug_write;
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ spinlock_t irq_stats_lock;
+ struct dsi_irq_stats irq_stats;
+#endif
+
+ unsigned num_lanes_supported;
+ unsigned line_buffer_size;
+
+ struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
+ unsigned num_lanes_used;
+
+ unsigned scp_clk_refcount;
+
+ struct dss_lcd_mgr_config mgr_config;
+ struct omap_video_timings timings;
+ enum omap_dss_dsi_pixel_format pix_fmt;
+ enum omap_dss_dsi_mode mode;
+ struct omap_dss_dsi_videomode_timings vm_timings;
+
+ struct omap_dss_device output;
+};
+
+struct dsi_packet_sent_handler_data {
+ struct platform_device *dsidev;
+ struct completion *completion;
+};
+
+struct dsi_module_id_data {
+ u32 address;
+ int id;
+};
+
+static const struct of_device_id dsi_of_match[];
+
+#ifdef DSI_PERF_MEASURE
+static bool dsi_perf;
+module_param(dsi_perf, bool, 0644);
+#endif
+
+static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
+{
+ return dev_get_drvdata(&dsidev->dev);
+}
+
+static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
+{
+ return to_platform_device(dssdev->dev);
+}
+
+static struct platform_device *dsi_get_dsidev_from_id(int module)
+{
+ struct omap_dss_device *out;
+ enum omap_dss_output_id id;
+
+ switch (module) {
+ case 0:
+ id = OMAP_DSS_OUTPUT_DSI1;
+ break;
+ case 1:
+ id = OMAP_DSS_OUTPUT_DSI2;
+ break;
+ default:
+ return NULL;
+ }
+
+ out = omap_dss_get_output(id);
+
+ return out ? to_platform_device(out->dev) : NULL;
+}
+
+static inline void dsi_write_reg(struct platform_device *dsidev,
+ const struct dsi_reg idx, u32 val)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ void __iomem *base;
+
+ switch(idx.module) {
+ case DSI_PROTO: base = dsi->proto_base; break;
+ case DSI_PHY: base = dsi->phy_base; break;
+ case DSI_PLL: base = dsi->pll_base; break;
+ default: return;
+ }
+
+ __raw_writel(val, base + idx.idx);
+}
+
+static inline u32 dsi_read_reg(struct platform_device *dsidev,
+ const struct dsi_reg idx)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ void __iomem *base;
+
+ switch(idx.module) {
+ case DSI_PROTO: base = dsi->proto_base; break;
+ case DSI_PHY: base = dsi->phy_base; break;
+ case DSI_PLL: base = dsi->pll_base; break;
+ default: return 0;
+ }
+
+ return __raw_readl(base + idx.idx);
+}
+
+static void dsi_bus_lock(struct omap_dss_device *dssdev)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ down(&dsi->bus_lock);
+}
+
+static void dsi_bus_unlock(struct omap_dss_device *dssdev)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ up(&dsi->bus_lock);
+}
+
+static bool dsi_bus_is_locked(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ return dsi->bus_lock.count == 0;
+}
+
+static void dsi_completion_handler(void *data, u32 mask)
+{
+ complete((struct completion *)data);
+}
+
+static inline int wait_for_bit_change(struct platform_device *dsidev,
+ const struct dsi_reg idx, int bitnum, int value)
+{
+ unsigned long timeout;
+ ktime_t wait;
+ int t;
+
+ /* first busyloop to see if the bit changes right away */
+ t = 100;
+ while (t-- > 0) {
+ if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
+ return value;
+ }
+
+ /* then loop for 500ms, sleeping for 1ms in between */
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (time_before(jiffies, timeout)) {
+ if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
+ return value;
+
+ wait = ns_to_ktime(1000 * 1000);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+ }
+
+ return !value;
+}
+
+u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
+{
+ switch (fmt) {
+ case OMAP_DSS_DSI_FMT_RGB888:
+ case OMAP_DSS_DSI_FMT_RGB666:
+ return 24;
+ case OMAP_DSS_DSI_FMT_RGB666_PACKED:
+ return 18;
+ case OMAP_DSS_DSI_FMT_RGB565:
+ return 16;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+#ifdef DSI_PERF_MEASURE
+static void dsi_perf_mark_setup(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ dsi->perf_setup_time = ktime_get();
+}
+
+static void dsi_perf_mark_start(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ dsi->perf_start_time = ktime_get();
+}
+
+static void dsi_perf_show(struct platform_device *dsidev, const char *name)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ ktime_t t, setup_time, trans_time;
+ u32 total_bytes;
+ u32 setup_us, trans_us, total_us;
+
+ if (!dsi_perf)
+ return;
+
+ t = ktime_get();
+
+ setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
+ setup_us = (u32)ktime_to_us(setup_time);
+ if (setup_us == 0)
+ setup_us = 1;
+
+ trans_time = ktime_sub(t, dsi->perf_start_time);
+ trans_us = (u32)ktime_to_us(trans_time);
+ if (trans_us == 0)
+ trans_us = 1;
+
+ total_us = setup_us + trans_us;
+
+ total_bytes = dsi->update_bytes;
+
+ printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
+ "%u bytes, %u kbytes/sec\n",
+ name,
+ setup_us,
+ trans_us,
+ total_us,
+ 1000*1000 / total_us,
+ total_bytes,
+ total_bytes * 1000 / total_us);
+}
+#else
+static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
+{
+}
+
+static inline void dsi_perf_mark_start(struct platform_device *dsidev)
+{
+}
+
+static inline void dsi_perf_show(struct platform_device *dsidev,
+ const char *name)
+{
+}
+#endif
+
+static int verbose_irq;
+
+static void print_irq_status(u32 status)
+{
+ if (status == 0)
+ return;
+
+ if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0)
+ return;
+
+#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : ""
+
+ pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ status,
+ verbose_irq ? PIS(VC0) : "",
+ verbose_irq ? PIS(VC1) : "",
+ verbose_irq ? PIS(VC2) : "",
+ verbose_irq ? PIS(VC3) : "",
+ PIS(WAKEUP),
+ PIS(RESYNC),
+ PIS(PLL_LOCK),
+ PIS(PLL_UNLOCK),
+ PIS(PLL_RECALL),
+ PIS(COMPLEXIO_ERR),
+ PIS(HS_TX_TIMEOUT),
+ PIS(LP_RX_TIMEOUT),
+ PIS(TE_TRIGGER),
+ PIS(ACK_TRIGGER),
+ PIS(SYNC_LOST),
+ PIS(LDO_POWER_GOOD),
+ PIS(TA_TIMEOUT));
+#undef PIS
+}
+
+static void print_irq_status_vc(int channel, u32 status)
+{
+ if (status == 0)
+ return;
+
+ if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
+ return;
+
+#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : ""
+
+ pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n",
+ channel,
+ status,
+ PIS(CS),
+ PIS(ECC_CORR),
+ PIS(ECC_NO_CORR),
+ verbose_irq ? PIS(PACKET_SENT) : "",
+ PIS(BTA),
+ PIS(FIFO_TX_OVF),
+ PIS(FIFO_RX_OVF),
+ PIS(FIFO_TX_UDF),
+ PIS(PP_BUSY_CHANGE));
+#undef PIS
+}
+
+static void print_irq_status_cio(u32 status)
+{
+ if (status == 0)
+ return;
+
+#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : ""
+
+ pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ status,
+ PIS(ERRSYNCESC1),
+ PIS(ERRSYNCESC2),
+ PIS(ERRSYNCESC3),
+ PIS(ERRESC1),
+ PIS(ERRESC2),
+ PIS(ERRESC3),
+ PIS(ERRCONTROL1),
+ PIS(ERRCONTROL2),
+ PIS(ERRCONTROL3),
+ PIS(STATEULPS1),
+ PIS(STATEULPS2),
+ PIS(STATEULPS3),
+ PIS(ERRCONTENTIONLP0_1),
+ PIS(ERRCONTENTIONLP1_1),
+ PIS(ERRCONTENTIONLP0_2),
+ PIS(ERRCONTENTIONLP1_2),
+ PIS(ERRCONTENTIONLP0_3),
+ PIS(ERRCONTENTIONLP1_3),
+ PIS(ULPSACTIVENOT_ALL0),
+ PIS(ULPSACTIVENOT_ALL1));
+#undef PIS
+}
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
+ u32 *vcstatus, u32 ciostatus)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int i;
+
+ spin_lock(&dsi->irq_stats_lock);
+
+ dsi->irq_stats.irq_count++;
+ dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
+
+ for (i = 0; i < 4; ++i)
+ dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
+
+ dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
+
+ spin_unlock(&dsi->irq_stats_lock);
+}
+#else
+#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
+#endif
+
+static int debug_irq;
+
+static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
+ u32 *vcstatus, u32 ciostatus)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int i;
+
+ if (irqstatus & DSI_IRQ_ERROR_MASK) {
+ DSSERR("DSI error, irqstatus %x\n", irqstatus);
+ print_irq_status(irqstatus);
+ spin_lock(&dsi->errors_lock);
+ dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
+ spin_unlock(&dsi->errors_lock);
+ } else if (debug_irq) {
+ print_irq_status(irqstatus);
+ }
+
+ for (i = 0; i < 4; ++i) {
+ if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
+ DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
+ i, vcstatus[i]);
+ print_irq_status_vc(i, vcstatus[i]);
+ } else if (debug_irq) {
+ print_irq_status_vc(i, vcstatus[i]);
+ }
+ }
+
+ if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
+ DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
+ print_irq_status_cio(ciostatus);
+ } else if (debug_irq) {
+ print_irq_status_cio(ciostatus);
+ }
+}
+
+static void dsi_call_isrs(struct dsi_isr_data *isr_array,
+ unsigned isr_array_size, u32 irqstatus)
+{
+ struct dsi_isr_data *isr_data;
+ int i;
+
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+ if (isr_data->isr && isr_data->mask & irqstatus)
+ isr_data->isr(isr_data->arg, irqstatus);
+ }
+}
+
+static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
+ u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+ int i;
+
+ dsi_call_isrs(isr_tables->isr_table,
+ ARRAY_SIZE(isr_tables->isr_table),
+ irqstatus);
+
+ for (i = 0; i < 4; ++i) {
+ if (vcstatus[i] == 0)
+ continue;
+ dsi_call_isrs(isr_tables->isr_table_vc[i],
+ ARRAY_SIZE(isr_tables->isr_table_vc[i]),
+ vcstatus[i]);
+ }
+
+ if (ciostatus != 0)
+ dsi_call_isrs(isr_tables->isr_table_cio,
+ ARRAY_SIZE(isr_tables->isr_table_cio),
+ ciostatus);
+}
+
+static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
+{
+ struct platform_device *dsidev;
+ struct dsi_data *dsi;
+ u32 irqstatus, vcstatus[4], ciostatus;
+ int i;
+
+ dsidev = (struct platform_device *) arg;
+ dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (!dsi->is_enabled)
+ return IRQ_NONE;
+
+ spin_lock(&dsi->irq_lock);
+
+ irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
+
+ /* IRQ is not for us */
+ if (!irqstatus) {
+ spin_unlock(&dsi->irq_lock);
+ return IRQ_NONE;
+ }
+
+ dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+ /* flush posted write */
+ dsi_read_reg(dsidev, DSI_IRQSTATUS);
+
+ for (i = 0; i < 4; ++i) {
+ if ((irqstatus & (1 << i)) == 0) {
+ vcstatus[i] = 0;
+ continue;
+ }
+
+ vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
+
+ dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
+ /* flush posted write */
+ dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
+ }
+
+ if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
+ ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
+
+ dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
+ /* flush posted write */
+ dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
+ } else {
+ ciostatus = 0;
+ }
+
+#ifdef DSI_CATCH_MISSING_TE
+ if (irqstatus & DSI_IRQ_TE_TRIGGER)
+ del_timer(&dsi->te_timer);
+#endif
+
+ /* make a copy and unlock, so that isrs can unregister
+ * themselves */
+ memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
+ sizeof(dsi->isr_tables));
+
+ spin_unlock(&dsi->irq_lock);
+
+ dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
+
+ dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
+
+ dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
+
+ return IRQ_HANDLED;
+}
+
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
+ struct dsi_isr_data *isr_array,
+ unsigned isr_array_size, u32 default_mask,
+ const struct dsi_reg enable_reg,
+ const struct dsi_reg status_reg)
+{
+ struct dsi_isr_data *isr_data;
+ u32 mask;
+ u32 old_mask;
+ int i;
+
+ mask = default_mask;
+
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+
+ if (isr_data->isr == NULL)
+ continue;
+
+ mask |= isr_data->mask;
+ }
+
+ old_mask = dsi_read_reg(dsidev, enable_reg);
+ /* clear the irqstatus for newly enabled irqs */
+ dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
+ dsi_write_reg(dsidev, enable_reg, mask);
+
+ /* flush posted writes */
+ dsi_read_reg(dsidev, enable_reg);
+ dsi_read_reg(dsidev, status_reg);
+}
+
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 mask = DSI_IRQ_ERROR_MASK;
+#ifdef DSI_CATCH_MISSING_TE
+ mask |= DSI_IRQ_TE_TRIGGER;
+#endif
+ _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
+ ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
+ DSI_IRQENABLE, DSI_IRQSTATUS);
+}
+
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
+ ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
+ DSI_VC_IRQ_ERROR_MASK,
+ DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
+}
+
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
+ ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
+ DSI_CIO_IRQ_ERROR_MASK,
+ DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
+}
+
+static void _dsi_initialize_irq(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int vc;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
+
+ _omap_dsi_set_irqs(dsidev);
+ for (vc = 0; vc < 4; ++vc)
+ _omap_dsi_set_irqs_vc(dsidev, vc);
+ _omap_dsi_set_irqs_cio(dsidev);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+}
+
+static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+ struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+ struct dsi_isr_data *isr_data;
+ int free_idx;
+ int i;
+
+ BUG_ON(isr == NULL);
+
+ /* check for duplicate entry and find a free slot */
+ free_idx = -1;
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+
+ if (isr_data->isr == isr && isr_data->arg == arg &&
+ isr_data->mask == mask) {
+ return -EINVAL;
+ }
+
+ if (isr_data->isr == NULL && free_idx == -1)
+ free_idx = i;
+ }
+
+ if (free_idx == -1)
+ return -EBUSY;
+
+ isr_data = &isr_array[free_idx];
+ isr_data->isr = isr;
+ isr_data->arg = arg;
+ isr_data->mask = mask;
+
+ return 0;
+}
+
+static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+ struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+ struct dsi_isr_data *isr_data;
+ int i;
+
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+ if (isr_data->isr != isr || isr_data->arg != arg ||
+ isr_data->mask != mask)
+ continue;
+
+ isr_data->isr = NULL;
+ isr_data->arg = NULL;
+ isr_data->mask = 0;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
+ void *arg, u32 mask)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
+ ARRAY_SIZE(dsi->isr_tables.isr_table));
+
+ if (r == 0)
+ _omap_dsi_set_irqs(dsidev);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_unregister_isr(struct platform_device *dsidev,
+ omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
+ ARRAY_SIZE(dsi->isr_tables.isr_table));
+
+ if (r == 0)
+ _omap_dsi_set_irqs(dsidev);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
+ omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ r = _dsi_register_isr(isr, arg, mask,
+ dsi->isr_tables.isr_table_vc[channel],
+ ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_vc(dsidev, channel);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
+ omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ r = _dsi_unregister_isr(isr, arg, mask,
+ dsi->isr_tables.isr_table_vc[channel],
+ ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_vc(dsidev, channel);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_register_isr_cio(struct platform_device *dsidev,
+ omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
+ ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_cio(dsidev);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_unregister_isr_cio(struct platform_device *dsidev,
+ omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi->irq_lock, flags);
+
+ r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
+ ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_cio(dsidev);
+
+ spin_unlock_irqrestore(&dsi->irq_lock, flags);
+
+ return r;
+}
+
+static u32 dsi_get_errors(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ u32 e;
+ spin_lock_irqsave(&dsi->errors_lock, flags);
+ e = dsi->errors;
+ dsi->errors = 0;
+ spin_unlock_irqrestore(&dsi->errors_lock, flags);
+ return e;
+}
+
+static int dsi_runtime_get(struct platform_device *dsidev)
+{
+ int r;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ DSSDBG("dsi_runtime_get\n");
+
+ r = pm_runtime_get_sync(&dsi->pdev->dev);
+ WARN_ON(r < 0);
+ return r < 0 ? r : 0;
+}
+
+static void dsi_runtime_put(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int r;
+
+ DSSDBG("dsi_runtime_put\n");
+
+ r = pm_runtime_put_sync(&dsi->pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static int dsi_regulator_init(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct regulator *vdds_dsi;
+ int r;
+
+ if (dsi->vdds_dsi_reg != NULL)
+ return 0;
+
+ vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd");
+
+ if (IS_ERR(vdds_dsi)) {
+ if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
+ DSSERR("can't get DSI VDD regulator\n");
+ return PTR_ERR(vdds_dsi);
+ }
+
+ if (regulator_can_change_voltage(vdds_dsi)) {
+ r = regulator_set_voltage(vdds_dsi, 1800000, 1800000);
+ if (r) {
+ devm_regulator_put(vdds_dsi);
+ DSSERR("can't set the DSI regulator voltage\n");
+ return r;
+ }
+ }
+
+ dsi->vdds_dsi_reg = vdds_dsi;
+
+ return 0;
+}
+
+static void _dsi_print_reset_status(struct platform_device *dsidev)
+{
+ u32 l;
+ int b0, b1, b2;
+
+ /* A dummy read using the SCP interface to any DSIPHY register is
+ * required after DSIPHY reset to complete the reset of the DSI complex
+ * I/O. */
+ l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+
+ if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
+ b0 = 28;
+ b1 = 27;
+ b2 = 26;
+ } else {
+ b0 = 24;
+ b1 = 25;
+ b2 = 26;
+ }
+
+#define DSI_FLD_GET(fld, start, end)\
+ FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end)
+
+ pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n",
+ DSI_FLD_GET(PLL_STATUS, 0, 0),
+ DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29),
+ DSI_FLD_GET(DSIPHY_CFG5, b0, b0),
+ DSI_FLD_GET(DSIPHY_CFG5, b1, b1),
+ DSI_FLD_GET(DSIPHY_CFG5, b2, b2),
+ DSI_FLD_GET(DSIPHY_CFG5, 29, 29),
+ DSI_FLD_GET(DSIPHY_CFG5, 30, 30),
+ DSI_FLD_GET(DSIPHY_CFG5, 31, 31));
+
+#undef DSI_FLD_GET
+}
+
+static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
+{
+ DSSDBG("dsi_if_enable(%d)\n", enable);
+
+ enable = enable ? 1 : 0;
+ REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
+
+ if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
+ DSSERR("Failed to set dsi_if_enable to %d\n", enable);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ return dsi->pll.cinfo.clkout[HSDIV_DISPC];
+}
+
+static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ return dsi->pll.cinfo.clkout[HSDIV_DSI];
+}
+
+static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ return dsi->pll.cinfo.clkdco / 16;
+}
+
+static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
+{
+ unsigned long r;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) {
+ /* DSI FCLK source is DSS_CLK_FCK */
+ r = clk_get_rate(dsi->dss_clk);
+ } else {
+ /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
+ r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
+ }
+
+ return r;
+}
+
+static int dsi_lp_clock_calc(unsigned long dsi_fclk,
+ unsigned long lp_clk_min, unsigned long lp_clk_max,
+ struct dsi_lp_clock_info *lp_cinfo)
+{
+ unsigned lp_clk_div;
+ unsigned long lp_clk;
+
+ lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
+ lp_clk = dsi_fclk / 2 / lp_clk_div;
+
+ if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
+ return -EINVAL;
+
+ lp_cinfo->lp_clk_div = lp_clk_div;
+ lp_cinfo->lp_clk = lp_clk;
+
+ return 0;
+}
+
+static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long dsi_fclk;
+ unsigned lp_clk_div;
+ unsigned long lp_clk;
+ unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
+
+
+ lp_clk_div = dsi->user_lp_cinfo.lp_clk_div;
+
+ if (lp_clk_div == 0 || lp_clk_div > lpdiv_max)
+ return -EINVAL;
+
+ dsi_fclk = dsi_fclk_rate(dsidev);
+
+ lp_clk = dsi_fclk / 2 / lp_clk_div;
+
+ DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
+ dsi->current_lp_cinfo.lp_clk = lp_clk;
+ dsi->current_lp_cinfo.lp_clk_div = lp_clk_div;
+
+ /* LP_CLK_DIVISOR */
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
+
+ /* LP_RX_SYNCHRO_ENABLE */
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
+
+ return 0;
+}
+
+static void dsi_enable_scp_clk(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (dsi->scp_clk_refcount++ == 0)
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dsi_disable_scp_clk(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ WARN_ON(dsi->scp_clk_refcount == 0);
+ if (--dsi->scp_clk_refcount == 0)
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
+}
+
+enum dsi_pll_power_state {
+ DSI_PLL_POWER_OFF = 0x0,
+ DSI_PLL_POWER_ON_HSCLK = 0x1,
+ DSI_PLL_POWER_ON_ALL = 0x2,
+ DSI_PLL_POWER_ON_DIV = 0x3,
+};
+
+static int dsi_pll_power(struct platform_device *dsidev,
+ enum dsi_pll_power_state state)
+{
+ int t = 0;
+
+ /* DSI-PLL power command 0x3 is not working */
+ if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
+ state == DSI_PLL_POWER_ON_DIV)
+ state = DSI_PLL_POWER_ON_ALL;
+
+ /* PLL_PWR_CMD */
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
+
+ /* PLL_PWR_STATUS */
+ while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
+ if (++t > 1000) {
+ DSSERR("Failed to set DSI PLL power mode to %d\n",
+ state);
+ return -ENODEV;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+
+static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo)
+{
+ unsigned long max_dsi_fck;
+
+ max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
+
+ cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck);
+ cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI];
+}
+
+static int dsi_pll_enable(struct dss_pll *pll)
+{
+ struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
+ struct platform_device *dsidev = dsi->pdev;
+ int r = 0;
+
+ DSSDBG("PLL init\n");
+
+ r = dsi_regulator_init(dsidev);
+ if (r)
+ return r;
+
+ r = dsi_runtime_get(dsidev);
+ if (r)
+ return r;
+
+ /*
+ * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
+ */
+ dsi_enable_scp_clk(dsidev);
+
+ if (!dsi->vdds_dsi_enabled) {
+ r = regulator_enable(dsi->vdds_dsi_reg);
+ if (r)
+ goto err0;
+ dsi->vdds_dsi_enabled = true;
+ }
+
+ /* XXX PLL does not come out of reset without this... */
+ dispc_pck_free_enable(1);
+
+ if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
+ DSSERR("PLL not coming out of reset.\n");
+ r = -ENODEV;
+ dispc_pck_free_enable(0);
+ goto err1;
+ }
+
+ /* XXX ... but if left on, we get problems when planes do not
+ * fill the whole display. No idea about this */
+ dispc_pck_free_enable(0);
+
+ r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL);
+
+ if (r)
+ goto err1;
+
+ DSSDBG("PLL init done\n");
+
+ return 0;
+err1:
+ if (dsi->vdds_dsi_enabled) {
+ regulator_disable(dsi->vdds_dsi_reg);
+ dsi->vdds_dsi_enabled = false;
+ }
+err0:
+ dsi_disable_scp_clk(dsidev);
+ dsi_runtime_put(dsidev);
+ return r;
+}
+
+static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
+ if (disconnect_lanes) {
+ WARN_ON(!dsi->vdds_dsi_enabled);
+ regulator_disable(dsi->vdds_dsi_reg);
+ dsi->vdds_dsi_enabled = false;
+ }
+
+ dsi_disable_scp_clk(dsidev);
+ dsi_runtime_put(dsidev);
+
+ DSSDBG("PLL uninit done\n");
+}
+
+static void dsi_pll_disable(struct dss_pll *pll)
+{
+ struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
+ struct platform_device *dsidev = dsi->pdev;
+
+ dsi_pll_uninit(dsidev, true);
+}
+
+static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
+ struct seq_file *s)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
+ enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
+ int dsi_module = dsi->module_id;
+ struct dss_pll *pll = &dsi->pll;
+
+ dispc_clk_src = dss_get_dispc_clk_source();
+ dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
+
+ if (dsi_runtime_get(dsidev))
+ return;
+
+ seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
+
+ seq_printf(s, "dsi pll clkin\t%lu\n", clk_get_rate(pll->clkin));
+
+ seq_printf(s, "Fint\t\t%-16lun %u\n", cinfo->fint, cinfo->n);
+
+ seq_printf(s, "CLKIN4DDR\t%-16lum %u\n",
+ cinfo->clkdco, cinfo->m);
+
+ seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n",
+ dss_feat_get_clk_source_name(dsi_module == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
+ cinfo->clkout[HSDIV_DISPC],
+ cinfo->mX[HSDIV_DISPC],
+ dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
+ "off" : "on");
+
+ seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n",
+ dss_feat_get_clk_source_name(dsi_module == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
+ cinfo->clkout[HSDIV_DSI],
+ cinfo->mX[HSDIV_DSI],
+ dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
+ "off" : "on");
+
+ seq_printf(s, "- DSI%d -\n", dsi_module + 1);
+
+ seq_printf(s, "dsi fclk source = %s (%s)\n",
+ dss_get_generic_clk_source_name(dsi_clk_src),
+ dss_feat_get_clk_source_name(dsi_clk_src));
+
+ seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
+
+ seq_printf(s, "DDR_CLK\t\t%lu\n",
+ cinfo->clkdco / 4);
+
+ seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
+
+ seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);
+
+ dsi_runtime_put(dsidev);
+}
+
+void dsi_dump_clocks(struct seq_file *s)
+{
+ struct platform_device *dsidev;
+ int i;
+
+ for (i = 0; i < MAX_NUM_DSI; i++) {
+ dsidev = dsi_get_dsidev_from_id(i);
+ if (dsidev)
+ dsi_dump_dsidev_clocks(dsidev, s);
+ }
+}
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
+ struct seq_file *s)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long flags;
+ struct dsi_irq_stats stats;
+
+ spin_lock_irqsave(&dsi->irq_stats_lock, flags);
+
+ stats = dsi->irq_stats;
+ memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
+ dsi->irq_stats.last_reset = jiffies;
+
+ spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
+
+ seq_printf(s, "period %u ms\n",
+ jiffies_to_msecs(jiffies - stats.last_reset));
+
+ seq_printf(s, "irqs %d\n", stats.irq_count);
+#define PIS(x) \
+ seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
+
+ seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
+ PIS(VC0);
+ PIS(VC1);
+ PIS(VC2);
+ PIS(VC3);
+ PIS(WAKEUP);
+ PIS(RESYNC);
+ PIS(PLL_LOCK);
+ PIS(PLL_UNLOCK);
+ PIS(PLL_RECALL);
+ PIS(COMPLEXIO_ERR);
+ PIS(HS_TX_TIMEOUT);
+ PIS(LP_RX_TIMEOUT);
+ PIS(TE_TRIGGER);
+ PIS(ACK_TRIGGER);
+ PIS(SYNC_LOST);
+ PIS(LDO_POWER_GOOD);
+ PIS(TA_TIMEOUT);
+#undef PIS
+
+#define PIS(x) \
+ seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
+ stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
+ stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
+ stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
+ stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
+
+ seq_printf(s, "-- VC interrupts --\n");
+ PIS(CS);
+ PIS(ECC_CORR);
+ PIS(PACKET_SENT);
+ PIS(FIFO_TX_OVF);
+ PIS(FIFO_RX_OVF);
+ PIS(BTA);
+ PIS(ECC_NO_CORR);
+ PIS(FIFO_TX_UDF);
+ PIS(PP_BUSY_CHANGE);
+#undef PIS
+
+#define PIS(x) \
+ seq_printf(s, "%-20s %10d\n", #x, \
+ stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
+
+ seq_printf(s, "-- CIO interrupts --\n");
+ PIS(ERRSYNCESC1);
+ PIS(ERRSYNCESC2);
+ PIS(ERRSYNCESC3);
+ PIS(ERRESC1);
+ PIS(ERRESC2);
+ PIS(ERRESC3);
+ PIS(ERRCONTROL1);
+ PIS(ERRCONTROL2);
+ PIS(ERRCONTROL3);
+ PIS(STATEULPS1);
+ PIS(STATEULPS2);
+ PIS(STATEULPS3);
+ PIS(ERRCONTENTIONLP0_1);
+ PIS(ERRCONTENTIONLP1_1);
+ PIS(ERRCONTENTIONLP0_2);
+ PIS(ERRCONTENTIONLP1_2);
+ PIS(ERRCONTENTIONLP0_3);
+ PIS(ERRCONTENTIONLP1_3);
+ PIS(ULPSACTIVENOT_ALL0);
+ PIS(ULPSACTIVENOT_ALL1);
+#undef PIS
+}
+
+static void dsi1_dump_irqs(struct seq_file *s)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
+
+ dsi_dump_dsidev_irqs(dsidev, s);
+}
+
+static void dsi2_dump_irqs(struct seq_file *s)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
+
+ dsi_dump_dsidev_irqs(dsidev, s);
+}
+#endif
+
+static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
+ struct seq_file *s)
+{
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
+
+ if (dsi_runtime_get(dsidev))
+ return;
+ dsi_enable_scp_clk(dsidev);
+
+ DUMPREG(DSI_REVISION);
+ DUMPREG(DSI_SYSCONFIG);
+ DUMPREG(DSI_SYSSTATUS);
+ DUMPREG(DSI_IRQSTATUS);
+ DUMPREG(DSI_IRQENABLE);
+ DUMPREG(DSI_CTRL);
+ DUMPREG(DSI_COMPLEXIO_CFG1);
+ DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
+ DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
+ DUMPREG(DSI_CLK_CTRL);
+ DUMPREG(DSI_TIMING1);
+ DUMPREG(DSI_TIMING2);
+ DUMPREG(DSI_VM_TIMING1);
+ DUMPREG(DSI_VM_TIMING2);
+ DUMPREG(DSI_VM_TIMING3);
+ DUMPREG(DSI_CLK_TIMING);
+ DUMPREG(DSI_TX_FIFO_VC_SIZE);
+ DUMPREG(DSI_RX_FIFO_VC_SIZE);
+ DUMPREG(DSI_COMPLEXIO_CFG2);
+ DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
+ DUMPREG(DSI_VM_TIMING4);
+ DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
+ DUMPREG(DSI_VM_TIMING5);
+ DUMPREG(DSI_VM_TIMING6);
+ DUMPREG(DSI_VM_TIMING7);
+ DUMPREG(DSI_STOPCLK_TIMING);
+
+ DUMPREG(DSI_VC_CTRL(0));
+ DUMPREG(DSI_VC_TE(0));
+ DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
+ DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
+ DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
+ DUMPREG(DSI_VC_IRQSTATUS(0));
+ DUMPREG(DSI_VC_IRQENABLE(0));
+
+ DUMPREG(DSI_VC_CTRL(1));
+ DUMPREG(DSI_VC_TE(1));
+ DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
+ DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
+ DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
+ DUMPREG(DSI_VC_IRQSTATUS(1));
+ DUMPREG(DSI_VC_IRQENABLE(1));
+
+ DUMPREG(DSI_VC_CTRL(2));
+ DUMPREG(DSI_VC_TE(2));
+ DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
+ DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
+ DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
+ DUMPREG(DSI_VC_IRQSTATUS(2));
+ DUMPREG(DSI_VC_IRQENABLE(2));
+
+ DUMPREG(DSI_VC_CTRL(3));
+ DUMPREG(DSI_VC_TE(3));
+ DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
+ DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
+ DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
+ DUMPREG(DSI_VC_IRQSTATUS(3));
+ DUMPREG(DSI_VC_IRQENABLE(3));
+
+ DUMPREG(DSI_DSIPHY_CFG0);
+ DUMPREG(DSI_DSIPHY_CFG1);
+ DUMPREG(DSI_DSIPHY_CFG2);
+ DUMPREG(DSI_DSIPHY_CFG5);
+
+ DUMPREG(DSI_PLL_CONTROL);
+ DUMPREG(DSI_PLL_STATUS);
+ DUMPREG(DSI_PLL_GO);
+ DUMPREG(DSI_PLL_CONFIGURATION1);
+ DUMPREG(DSI_PLL_CONFIGURATION2);
+
+ dsi_disable_scp_clk(dsidev);
+ dsi_runtime_put(dsidev);
+#undef DUMPREG
+}
+
+static void dsi1_dump_regs(struct seq_file *s)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
+
+ dsi_dump_dsidev_regs(dsidev, s);
+}
+
+static void dsi2_dump_regs(struct seq_file *s)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
+
+ dsi_dump_dsidev_regs(dsidev, s);
+}
+
+enum dsi_cio_power_state {
+ DSI_COMPLEXIO_POWER_OFF = 0x0,
+ DSI_COMPLEXIO_POWER_ON = 0x1,
+ DSI_COMPLEXIO_POWER_ULPS = 0x2,
+};
+
+static int dsi_cio_power(struct platform_device *dsidev,
+ enum dsi_cio_power_state state)
+{
+ int t = 0;
+
+ /* PWR_CMD */
+ REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
+
+ /* PWR_STATUS */
+ while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
+ 26, 25) != state) {
+ if (++t > 1000) {
+ DSSERR("failed to set complexio power state to "
+ "%d\n", state);
+ return -ENODEV;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
+{
+ int val;
+
+ /* line buffer on OMAP3 is 1024 x 24bits */
+ /* XXX: for some reason using full buffer size causes
+ * considerable TX slowdown with update sizes that fill the
+ * whole buffer */
+ if (!dss_has_feature(FEAT_DSI_GNQ))
+ return 1023 * 3;
+
+ val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
+
+ switch (val) {
+ case 1:
+ return 512 * 3; /* 512x24 bits */
+ case 2:
+ return 682 * 3; /* 682x24 bits */
+ case 3:
+ return 853 * 3; /* 853x24 bits */
+ case 4:
+ return 1024 * 3; /* 1024x24 bits */
+ case 5:
+ return 1194 * 3; /* 1194x24 bits */
+ case 6:
+ return 1365 * 3; /* 1365x24 bits */
+ case 7:
+ return 1920 * 3; /* 1920x24 bits */
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static int dsi_set_lane_config(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ static const u8 offsets[] = { 0, 4, 8, 12, 16 };
+ static const enum dsi_lane_function functions[] = {
+ DSI_LANE_CLK,
+ DSI_LANE_DATA1,
+ DSI_LANE_DATA2,
+ DSI_LANE_DATA3,
+ DSI_LANE_DATA4,
+ };
+ u32 r;
+ int i;
+
+ r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
+
+ for (i = 0; i < dsi->num_lanes_used; ++i) {
+ unsigned offset = offsets[i];
+ unsigned polarity, lane_number;
+ unsigned t;
+
+ for (t = 0; t < dsi->num_lanes_supported; ++t)
+ if (dsi->lanes[t].function == functions[i])
+ break;
+
+ if (t == dsi->num_lanes_supported)
+ return -EINVAL;
+
+ lane_number = t;
+ polarity = dsi->lanes[t].polarity;
+
+ r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
+ r = FLD_MOD(r, polarity, offset + 3, offset + 3);
+ }
+
+ /* clear the unused lanes */
+ for (; i < dsi->num_lanes_supported; ++i) {
+ unsigned offset = offsets[i];
+
+ r = FLD_MOD(r, 0, offset + 2, offset);
+ r = FLD_MOD(r, 0, offset + 3, offset + 3);
+ }
+
+ dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
+
+ return 0;
+}
+
+static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ /* convert time in ns to ddr ticks, rounding up */
+ unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
+ return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
+}
+
+static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
+ return ddr * 1000 * 1000 / (ddr_clk / 1000);
+}
+
+static void dsi_cio_timings(struct platform_device *dsidev)
+{
+ u32 r;
+ u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
+ u32 tlpx_half, tclk_trail, tclk_zero;
+ u32 tclk_prepare;
+
+ /* calculate timings */
+
+ /* 1 * DDR_CLK = 2 * UI */
+
+ /* min 40ns + 4*UI max 85ns + 6*UI */
+ ths_prepare = ns2ddr(dsidev, 70) + 2;
+
+ /* min 145ns + 10*UI */
+ ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
+
+ /* min max(8*UI, 60ns+4*UI) */
+ ths_trail = ns2ddr(dsidev, 60) + 5;
+
+ /* min 100ns */
+ ths_exit = ns2ddr(dsidev, 145);
+
+ /* tlpx min 50n */
+ tlpx_half = ns2ddr(dsidev, 25);
+
+ /* min 60ns */
+ tclk_trail = ns2ddr(dsidev, 60) + 2;
+
+ /* min 38ns, max 95ns */
+ tclk_prepare = ns2ddr(dsidev, 65);
+
+ /* min tclk-prepare + tclk-zero = 300ns */
+ tclk_zero = ns2ddr(dsidev, 260);
+
+ DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
+ ths_prepare, ddr2ns(dsidev, ths_prepare),
+ ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
+ DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
+ ths_trail, ddr2ns(dsidev, ths_trail),
+ ths_exit, ddr2ns(dsidev, ths_exit));
+
+ DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
+ "tclk_zero %u (%uns)\n",
+ tlpx_half, ddr2ns(dsidev, tlpx_half),
+ tclk_trail, ddr2ns(dsidev, tclk_trail),
+ tclk_zero, ddr2ns(dsidev, tclk_zero));
+ DSSDBG("tclk_prepare %u (%uns)\n",
+ tclk_prepare, ddr2ns(dsidev, tclk_prepare));
+
+ /* program timings */
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
+ r = FLD_MOD(r, ths_prepare, 31, 24);
+ r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
+ r = FLD_MOD(r, ths_trail, 15, 8);
+ r = FLD_MOD(r, ths_exit, 7, 0);
+ dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
+ r = FLD_MOD(r, tlpx_half, 20, 16);
+ r = FLD_MOD(r, tclk_trail, 15, 8);
+ r = FLD_MOD(r, tclk_zero, 7, 0);
+
+ if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
+ r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
+ r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
+ r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
+ }
+
+ dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
+ r = FLD_MOD(r, tclk_prepare, 7, 0);
+ dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
+}
+
+/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
+static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
+ unsigned mask_p, unsigned mask_n)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int i;
+ u32 l;
+ u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;
+
+ l = 0;
+
+ for (i = 0; i < dsi->num_lanes_supported; ++i) {
+ unsigned p = dsi->lanes[i].polarity;
+
+ if (mask_p & (1 << i))
+ l |= 1 << (i * 2 + (p ? 0 : 1));
+
+ if (mask_n & (1 << i))
+ l |= 1 << (i * 2 + (p ? 1 : 0));
+ }
+
+ /*
+ * Bits in REGLPTXSCPDAT4TO0DXDY:
+ * 17: DY0 18: DX0
+ * 19: DY1 20: DX1
+ * 21: DY2 22: DX2
+ * 23: DY3 24: DX3
+ * 25: DY4 26: DX4
+ */
+
+ /* Set the lane override configuration */
+
+ /* REGLPTXSCPDAT4TO0DXDY */
+ REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
+
+ /* Enable lane override */
+
+ /* ENLPTXSCPDAT */
+ REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
+}
+
+static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
+{
+ /* Disable lane override */
+ REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
+ /* Reset the lane override configuration */
+ /* REGLPTXSCPDAT4TO0DXDY */
+ REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
+}
+
+static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int t, i;
+ bool in_use[DSI_MAX_NR_LANES];
+ static const u8 offsets_old[] = { 28, 27, 26 };
+ static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
+ const u8 *offsets;
+
+ if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
+ offsets = offsets_old;
+ else
+ offsets = offsets_new;
+
+ for (i = 0; i < dsi->num_lanes_supported; ++i)
+ in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;
+
+ t = 100000;
+ while (true) {
+ u32 l;
+ int ok;
+
+ l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+
+ ok = 0;
+ for (i = 0; i < dsi->num_lanes_supported; ++i) {
+ if (!in_use[i] || (l & (1 << offsets[i])))
+ ok++;
+ }
+
+ if (ok == dsi->num_lanes_supported)
+ break;
+
+ if (--t == 0) {
+ for (i = 0; i < dsi->num_lanes_supported; ++i) {
+ if (!in_use[i] || (l & (1 << offsets[i])))
+ continue;
+
+ DSSERR("CIO TXCLKESC%d domain not coming " \
+ "out of reset\n", i);
+ }
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+/* return bitmask of enabled lanes, lane0 being the lsb */
+static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned mask = 0;
+ int i;
+
+ for (i = 0; i < dsi->num_lanes_supported; ++i) {
+ if (dsi->lanes[i].function != DSI_LANE_UNUSED)
+ mask |= 1 << i;
+ }
+
+ return mask;
+}
+
+static int dsi_cio_init(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int r;
+ u32 l;
+
+ DSSDBG("DSI CIO init starts");
+
+ r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
+ if (r)
+ return r;
+
+ dsi_enable_scp_clk(dsidev);
+
+ /* A dummy read using the SCP interface to any DSIPHY register is
+ * required after DSIPHY reset to complete the reset of the DSI complex
+ * I/O. */
+ dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+
+ if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
+ DSSERR("CIO SCP Clock domain not coming out of reset.\n");
+ r = -EIO;
+ goto err_scp_clk_dom;
+ }
+
+ r = dsi_set_lane_config(dsidev);
+ if (r)
+ goto err_scp_clk_dom;
+
+ /* set TX STOP MODE timer to maximum for this operation */
+ l = dsi_read_reg(dsidev, DSI_TIMING1);
+ l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
+ l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
+ l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
+ l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
+ dsi_write_reg(dsidev, DSI_TIMING1, l);
+
+ if (dsi->ulps_enabled) {
+ unsigned mask_p;
+ int i;
+
+ DSSDBG("manual ulps exit\n");
+
+ /* ULPS is exited by Mark-1 state for 1ms, followed by
+ * stop state. DSS HW cannot do this via the normal
+ * ULPS exit sequence, as after reset the DSS HW thinks
+ * that we are not in ULPS mode, and refuses to send the
+ * sequence. So we need to send the ULPS exit sequence
+ * manually by setting positive lines high and negative lines
+ * low for 1ms.
+ */
+
+ mask_p = 0;
+
+ for (i = 0; i < dsi->num_lanes_supported; ++i) {
+ if (dsi->lanes[i].function == DSI_LANE_UNUSED)
+ continue;
+ mask_p |= 1 << i;
+ }
+
+ dsi_cio_enable_lane_override(dsidev, mask_p, 0);
+ }
+
+ r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
+ if (r)
+ goto err_cio_pwr;
+
+ if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
+ DSSERR("CIO PWR clock domain not coming out of reset.\n");
+ r = -ENODEV;
+ goto err_cio_pwr_dom;
+ }
+
+ dsi_if_enable(dsidev, true);
+ dsi_if_enable(dsidev, false);
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
+
+ r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
+ if (r)
+ goto err_tx_clk_esc_rst;
+
+ if (dsi->ulps_enabled) {
+ /* Keep Mark-1 state for 1ms (as per DSI spec) */
+ ktime_t wait = ns_to_ktime(1000 * 1000);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+
+ /* Disable the override. The lanes should be set to Mark-11
+ * state by the HW */
+ dsi_cio_disable_lane_override(dsidev);
+ }
+
+ /* FORCE_TX_STOP_MODE_IO */
+ REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
+
+ dsi_cio_timings(dsidev);
+
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ /* DDR_CLK_ALWAYS_ON */
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
+ dsi->vm_timings.ddr_clk_always_on, 13, 13);
+ }
+
+ dsi->ulps_enabled = false;
+
+ DSSDBG("CIO init done\n");
+
+ return 0;
+
+err_tx_clk_esc_rst:
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
+err_cio_pwr_dom:
+ dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
+err_cio_pwr:
+ if (dsi->ulps_enabled)
+ dsi_cio_disable_lane_override(dsidev);
+err_scp_clk_dom:
+ dsi_disable_scp_clk(dsidev);
+ dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
+ return r;
+}
+
+static void dsi_cio_uninit(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ /* DDR_CLK_ALWAYS_ON */
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
+
+ dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
+ dsi_disable_scp_clk(dsidev);
+ dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
+}
+
+static void dsi_config_tx_fifo(struct platform_device *dsidev,
+ enum fifo_size size1, enum fifo_size size2,
+ enum fifo_size size3, enum fifo_size size4)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 r = 0;
+ int add = 0;
+ int i;
+
+ dsi->vc[0].tx_fifo_size = size1;
+ dsi->vc[1].tx_fifo_size = size2;
+ dsi->vc[2].tx_fifo_size = size3;
+ dsi->vc[3].tx_fifo_size = size4;
+
+ for (i = 0; i < 4; i++) {
+ u8 v;
+ int size = dsi->vc[i].tx_fifo_size;
+
+ if (add + size > 4) {
+ DSSERR("Illegal FIFO configuration\n");
+ BUG();
+ return;
+ }
+
+ v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
+ r |= v << (8 * i);
+ /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
+ add += size;
+ }
+
+ dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
+}
+
+static void dsi_config_rx_fifo(struct platform_device *dsidev,
+ enum fifo_size size1, enum fifo_size size2,
+ enum fifo_size size3, enum fifo_size size4)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 r = 0;
+ int add = 0;
+ int i;
+
+ dsi->vc[0].rx_fifo_size = size1;
+ dsi->vc[1].rx_fifo_size = size2;
+ dsi->vc[2].rx_fifo_size = size3;
+ dsi->vc[3].rx_fifo_size = size4;
+
+ for (i = 0; i < 4; i++) {
+ u8 v;
+ int size = dsi->vc[i].rx_fifo_size;
+
+ if (add + size > 4) {
+ DSSERR("Illegal FIFO configuration\n");
+ BUG();
+ return;
+ }
+
+ v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
+ r |= v << (8 * i);
+ /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
+ add += size;
+ }
+
+ dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
+}
+
+static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
+{
+ u32 r;
+
+ r = dsi_read_reg(dsidev, DSI_TIMING1);
+ r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
+ dsi_write_reg(dsidev, DSI_TIMING1, r);
+
+ if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
+ DSSERR("TX_STOP bit not going down\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
+{
+ return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
+}
+
+static void dsi_packet_sent_handler_vp(void *data, u32 mask)
+{
+ struct dsi_packet_sent_handler_data *vp_data =
+ (struct dsi_packet_sent_handler_data *) data;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
+ const int channel = dsi->update_channel;
+ u8 bit = dsi->te_enabled ? 30 : 31;
+
+ if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
+ complete(vp_data->completion);
+}
+
+static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ DECLARE_COMPLETION_ONSTACK(completion);
+ struct dsi_packet_sent_handler_data vp_data = {
+ .dsidev = dsidev,
+ .completion = &completion
+ };
+ int r = 0;
+ u8 bit;
+
+ bit = dsi->te_enabled ? 30 : 31;
+
+ r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+ &vp_data, DSI_VC_IRQ_PACKET_SENT);
+ if (r)
+ goto err0;
+
+ /* Wait for completion only if TE_EN/TE_START is still set */
+ if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
+ if (wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(10)) == 0) {
+ DSSERR("Failed to complete previous frame transfer\n");
+ r = -EIO;
+ goto err1;
+ }
+ }
+
+ dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+ &vp_data, DSI_VC_IRQ_PACKET_SENT);
+
+ return 0;
+err1:
+ dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+ &vp_data, DSI_VC_IRQ_PACKET_SENT);
+err0:
+ return r;
+}
+
+static void dsi_packet_sent_handler_l4(void *data, u32 mask)
+{
+ struct dsi_packet_sent_handler_data *l4_data =
+ (struct dsi_packet_sent_handler_data *) data;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
+ const int channel = dsi->update_channel;
+
+ if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
+ complete(l4_data->completion);
+}
+
+static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
+{
+ DECLARE_COMPLETION_ONSTACK(completion);
+ struct dsi_packet_sent_handler_data l4_data = {
+ .dsidev = dsidev,
+ .completion = &completion
+ };
+ int r = 0;
+
+ r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+ &l4_data, DSI_VC_IRQ_PACKET_SENT);
+ if (r)
+ goto err0;
+
+ /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
+ if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
+ if (wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(10)) == 0) {
+ DSSERR("Failed to complete previous l4 transfer\n");
+ r = -EIO;
+ goto err1;
+ }
+ }
+
+ dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+ &l4_data, DSI_VC_IRQ_PACKET_SENT);
+
+ return 0;
+err1:
+ dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+ &l4_data, DSI_VC_IRQ_PACKET_SENT);
+err0:
+ return r;
+}
+
+static int dsi_sync_vc(struct platform_device *dsidev, int channel)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ WARN_ON(in_interrupt());
+
+ if (!dsi_vc_is_enabled(dsidev, channel))
+ return 0;
+
+ switch (dsi->vc[channel].source) {
+ case DSI_VC_SOURCE_VP:
+ return dsi_sync_vc_vp(dsidev, channel);
+ case DSI_VC_SOURCE_L4:
+ return dsi_sync_vc_l4(dsidev, channel);
+ default:
+ BUG();
+ return -EINVAL;
+ }
+}
+
+static int dsi_vc_enable(struct platform_device *dsidev, int channel,
+ bool enable)
+{
+ DSSDBG("dsi_vc_enable channel %d, enable %d\n",
+ channel, enable);
+
+ enable = enable ? 1 : 0;
+
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
+
+ if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
+ 0, enable) != enable) {
+ DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 r;
+
+ DSSDBG("Initial config of virtual channel %d", channel);
+
+ r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
+
+ if (FLD_GET(r, 15, 15)) /* VC_BUSY */
+ DSSERR("VC(%d) busy when trying to configure it!\n",
+ channel);
+
+ r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
+ r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
+ r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
+ r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
+ r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
+ r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
+ r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
+ if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
+ r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
+
+ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
+ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
+
+ dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
+
+ dsi->vc[channel].source = DSI_VC_SOURCE_L4;
+}
+
+static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
+ enum dsi_vc_source source)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (dsi->vc[channel].source == source)
+ return 0;
+
+ DSSDBG("Source config of virtual channel %d", channel);
+
+ dsi_sync_vc(dsidev, channel);
+
+ dsi_vc_enable(dsidev, channel, 0);
+
+ /* VC_BUSY */
+ if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
+ DSSERR("vc(%d) busy when trying to config for VP\n", channel);
+ return -EIO;
+ }
+
+ /* SOURCE, 0 = L4, 1 = video port */
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);
+
+ /* DCS_CMD_ENABLE */
+ if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
+ bool enable = source == DSI_VC_SOURCE_VP;
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
+ }
+
+ dsi_vc_enable(dsidev, channel, 1);
+
+ dsi->vc[channel].source = source;
+
+ return 0;
+}
+
+static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
+ bool enable)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ dsi_vc_enable(dsidev, channel, 0);
+ dsi_if_enable(dsidev, 0);
+
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
+
+ dsi_vc_enable(dsidev, channel, 1);
+ dsi_if_enable(dsidev, 1);
+
+ dsi_force_tx_stop_mode_io(dsidev);
+
+ /* start the DDR clock by sending a NULL packet */
+ if (dsi->vm_timings.ddr_clk_always_on && enable)
+ dsi_vc_send_null(dssdev, channel);
+}
+
+static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
+{
+ while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
+ u32 val;
+ val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
+ DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
+ (val >> 0) & 0xff,
+ (val >> 8) & 0xff,
+ (val >> 16) & 0xff,
+ (val >> 24) & 0xff);
+ }
+}
+
+static void dsi_show_rx_ack_with_err(u16 err)
+{
+ DSSERR("\tACK with ERROR (%#x):\n", err);
+ if (err & (1 << 0))
+ DSSERR("\t\tSoT Error\n");
+ if (err & (1 << 1))
+ DSSERR("\t\tSoT Sync Error\n");
+ if (err & (1 << 2))
+ DSSERR("\t\tEoT Sync Error\n");
+ if (err & (1 << 3))
+ DSSERR("\t\tEscape Mode Entry Command Error\n");
+ if (err & (1 << 4))
+ DSSERR("\t\tLP Transmit Sync Error\n");
+ if (err & (1 << 5))
+ DSSERR("\t\tHS Receive Timeout Error\n");
+ if (err & (1 << 6))
+ DSSERR("\t\tFalse Control Error\n");
+ if (err & (1 << 7))
+ DSSERR("\t\t(reserved7)\n");
+ if (err & (1 << 8))
+ DSSERR("\t\tECC Error, single-bit (corrected)\n");
+ if (err & (1 << 9))
+ DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
+ if (err & (1 << 10))
+ DSSERR("\t\tChecksum Error\n");
+ if (err & (1 << 11))
+ DSSERR("\t\tData type not recognized\n");
+ if (err & (1 << 12))
+ DSSERR("\t\tInvalid VC ID\n");
+ if (err & (1 << 13))
+ DSSERR("\t\tInvalid Transmission Length\n");
+ if (err & (1 << 14))
+ DSSERR("\t\t(reserved14)\n");
+ if (err & (1 << 15))
+ DSSERR("\t\tDSI Protocol Violation\n");
+}
+
+static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
+ int channel)
+{
+ /* RX_FIFO_NOT_EMPTY */
+ while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
+ u32 val;
+ u8 dt;
+ val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
+ DSSERR("\trawval %#08x\n", val);
+ dt = FLD_GET(val, 5, 0);
+ if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
+ u16 err = FLD_GET(val, 23, 8);
+ dsi_show_rx_ack_with_err(err);
+ } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) {
+ DSSERR("\tDCS short response, 1 byte: %#x\n",
+ FLD_GET(val, 23, 8));
+ } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
+ DSSERR("\tDCS short response, 2 byte: %#x\n",
+ FLD_GET(val, 23, 8));
+ } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
+ DSSERR("\tDCS long response, len %d\n",
+ FLD_GET(val, 23, 8));
+ dsi_vc_flush_long_data(dsidev, channel);
+ } else {
+ DSSERR("\tunknown datatype 0x%02x\n", dt);
+ }
+ }
+ return 0;
+}
+
+static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (dsi->debug_write || dsi->debug_read)
+ DSSDBG("dsi_vc_send_bta %d\n", channel);
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ /* RX_FIFO_NOT_EMPTY */
+ if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
+ DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
+ dsi_vc_flush_receive_data(dsidev, channel);
+ }
+
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
+
+ /* flush posted write */
+ dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
+
+ return 0;
+}
+
+static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ DECLARE_COMPLETION_ONSTACK(completion);
+ int r = 0;
+ u32 err;
+
+ r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
+ &completion, DSI_VC_IRQ_BTA);
+ if (r)
+ goto err0;
+
+ r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
+ DSI_IRQ_ERROR_MASK);
+ if (r)
+ goto err1;
+
+ r = dsi_vc_send_bta(dsidev, channel);
+ if (r)
+ goto err2;
+
+ if (wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(500)) == 0) {
+ DSSERR("Failed to receive BTA\n");
+ r = -EIO;
+ goto err2;
+ }
+
+ err = dsi_get_errors(dsidev);
+ if (err) {
+ DSSERR("Error while sending BTA: %x\n", err);
+ r = -EIO;
+ goto err2;
+ }
+err2:
+ dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
+ DSI_IRQ_ERROR_MASK);
+err1:
+ dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
+ &completion, DSI_VC_IRQ_BTA);
+err0:
+ return r;
+}
+
+static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
+ int channel, u8 data_type, u16 len, u8 ecc)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 val;
+ u8 data_id;
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ data_id = data_type | dsi->vc[channel].vc_id << 6;
+
+ val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
+ FLD_VAL(ecc, 31, 24);
+
+ dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
+}
+
+static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
+ int channel, u8 b1, u8 b2, u8 b3, u8 b4)
+{
+ u32 val;
+
+ val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
+
+/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
+ b1, b2, b3, b4, val); */
+
+ dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
+}
+
+static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
+ u8 data_type, u8 *data, u16 len, u8 ecc)
+{
+ /*u32 val; */
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int i;
+ u8 *p;
+ int r = 0;
+ u8 b1, b2, b3, b4;
+
+ if (dsi->debug_write)
+ DSSDBG("dsi_vc_send_long, %d bytes\n", len);
+
+ /* len + header */
+ if (dsi->vc[channel].tx_fifo_size * 32 * 4 < len + 4) {
+ DSSERR("unable to send long packet: packet too long.\n");
+ return -EINVAL;
+ }
+
+ dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
+
+ dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
+
+ p = data;
+ for (i = 0; i < len >> 2; i++) {
+ if (dsi->debug_write)
+ DSSDBG("\tsending full packet %d\n", i);
+
+ b1 = *p++;
+ b2 = *p++;
+ b3 = *p++;
+ b4 = *p++;
+
+ dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
+ }
+
+ i = len % 4;
+ if (i) {
+ b1 = 0; b2 = 0; b3 = 0;
+
+ if (dsi->debug_write)
+ DSSDBG("\tsending remainder bytes %d\n", i);
+
+ switch (i) {
+ case 3:
+ b1 = *p++;
+ b2 = *p++;
+ b3 = *p++;
+ break;
+ case 2:
+ b1 = *p++;
+ b2 = *p++;
+ break;
+ case 1:
+ b1 = *p++;
+ break;
+ }
+
+ dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
+ }
+
+ return r;
+}
+
+static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
+ u8 data_type, u16 data, u8 ecc)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 r;
+ u8 data_id;
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ if (dsi->debug_write)
+ DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
+ channel,
+ data_type, data & 0xff, (data >> 8) & 0xff);
+
+ dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
+
+ if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
+ DSSERR("ERROR FIFO FULL, aborting transfer\n");
+ return -EINVAL;
+ }
+
+ data_id = data_type | dsi->vc[channel].vc_id << 6;
+
+ r = (data_id << 0) | (data << 8) | (ecc << 24);
+
+ dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
+
+ return 0;
+}
+
+static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL,
+ 0, 0);
+}
+
+static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
+ int channel, u8 *data, int len, enum dss_dsi_content_type type)
+{
+ int r;
+
+ if (len == 0) {
+ BUG_ON(type == DSS_DSI_CONTENT_DCS);
+ r = dsi_vc_send_short(dsidev, channel,
+ MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0);
+ } else if (len == 1) {
+ r = dsi_vc_send_short(dsidev, channel,
+ type == DSS_DSI_CONTENT_GENERIC ?
+ MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
+ MIPI_DSI_DCS_SHORT_WRITE, data[0], 0);
+ } else if (len == 2) {
+ r = dsi_vc_send_short(dsidev, channel,
+ type == DSS_DSI_CONTENT_GENERIC ?
+ MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ data[0] | (data[1] << 8), 0);
+ } else {
+ r = dsi_vc_send_long(dsidev, channel,
+ type == DSS_DSI_CONTENT_GENERIC ?
+ MIPI_DSI_GENERIC_LONG_WRITE :
+ MIPI_DSI_DCS_LONG_WRITE, data, len, 0);
+ }
+
+ return r;
+}
+
+static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+ u8 *data, int len)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_write_nosync_common(dsidev, channel, data, len,
+ DSS_DSI_CONTENT_DCS);
+}
+
+static int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
+ u8 *data, int len)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_write_nosync_common(dsidev, channel, data, len,
+ DSS_DSI_CONTENT_GENERIC);
+}
+
+static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
+ u8 *data, int len, enum dss_dsi_content_type type)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ int r;
+
+ r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
+ if (r)
+ goto err;
+
+ r = dsi_vc_send_bta_sync(dssdev, channel);
+ if (r)
+ goto err;
+
+ /* RX_FIFO_NOT_EMPTY */
+ if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
+ DSSERR("rx fifo not empty after write, dumping data:\n");
+ dsi_vc_flush_receive_data(dsidev, channel);
+ r = -EIO;
+ goto err;
+ }
+
+ return 0;
+err:
+ DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n",
+ channel, data[0], len);
+ return r;
+}
+
+static int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+ int len)
+{
+ return dsi_vc_write_common(dssdev, channel, data, len,
+ DSS_DSI_CONTENT_DCS);
+}
+
+static int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+ int len)
+{
+ return dsi_vc_write_common(dssdev, channel, data, len,
+ DSS_DSI_CONTENT_GENERIC);
+}
+
+static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
+ int channel, u8 dcs_cmd)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int r;
+
+ if (dsi->debug_read)
+ DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n",
+ channel, dcs_cmd);
+
+ r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0);
+ if (r) {
+ DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)"
+ " failed\n", channel, dcs_cmd);
+ return r;
+ }
+
+ return 0;
+}
+
+static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
+ int channel, u8 *reqdata, int reqlen)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u16 data;
+ u8 data_type;
+ int r;
+
+ if (dsi->debug_read)
+ DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n",
+ channel, reqlen);
+
+ if (reqlen == 0) {
+ data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
+ data = 0;
+ } else if (reqlen == 1) {
+ data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
+ data = reqdata[0];
+ } else if (reqlen == 2) {
+ data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
+ data = reqdata[0] | (reqdata[1] << 8);
+ } else {
+ BUG();
+ return -EINVAL;
+ }
+
+ r = dsi_vc_send_short(dsidev, channel, data_type, data, 0);
+ if (r) {
+ DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)"
+ " failed\n", channel, reqlen);
+ return r;
+ }
+
+ return 0;
+}
+
+static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel,
+ u8 *buf, int buflen, enum dss_dsi_content_type type)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 val;
+ u8 dt;
+ int r;
+
+ /* RX_FIFO_NOT_EMPTY */
+ if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
+ DSSERR("RX fifo empty when trying to read.\n");
+ r = -EIO;
+ goto err;
+ }
+
+ val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
+ if (dsi->debug_read)
+ DSSDBG("\theader: %08x\n", val);
+ dt = FLD_GET(val, 5, 0);
+ if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
+ u16 err = FLD_GET(val, 23, 8);
+ dsi_show_rx_ack_with_err(err);
+ r = -EIO;
+ goto err;
+
+ } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE :
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) {
+ u8 data = FLD_GET(val, 15, 8);
+ if (dsi->debug_read)
+ DSSDBG("\t%s short response, 1 byte: %02x\n",
+ type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
+ "DCS", data);
+
+ if (buflen < 1) {
+ r = -EIO;
+ goto err;
+ }
+
+ buf[0] = data;
+
+ return 1;
+ } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE :
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) {
+ u16 data = FLD_GET(val, 23, 8);
+ if (dsi->debug_read)
+ DSSDBG("\t%s short response, 2 byte: %04x\n",
+ type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
+ "DCS", data);
+
+ if (buflen < 2) {
+ r = -EIO;
+ goto err;
+ }
+
+ buf[0] = data & 0xff;
+ buf[1] = (data >> 8) & 0xff;
+
+ return 2;
+ } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
+ MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE :
+ MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) {
+ int w;
+ int len = FLD_GET(val, 23, 8);
+ if (dsi->debug_read)
+ DSSDBG("\t%s long response, len %d\n",
+ type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
+ "DCS", len);
+
+ if (len > buflen) {
+ r = -EIO;
+ goto err;
+ }
+
+ /* two byte checksum ends the packet, not included in len */
+ for (w = 0; w < len + 2;) {
+ int b;
+ val = dsi_read_reg(dsidev,
+ DSI_VC_SHORT_PACKET_HEADER(channel));
+ if (dsi->debug_read)
+ DSSDBG("\t\t%02x %02x %02x %02x\n",
+ (val >> 0) & 0xff,
+ (val >> 8) & 0xff,
+ (val >> 16) & 0xff,
+ (val >> 24) & 0xff);
+
+ for (b = 0; b < 4; ++b) {
+ if (w < len)
+ buf[w] = (val >> (b * 8)) & 0xff;
+ /* we discard the 2 byte checksum */
+ ++w;
+ }
+ }
+
+ return len;
+ } else {
+ DSSERR("\tunknown datatype 0x%02x\n", dt);
+ r = -EIO;
+ goto err;
+ }
+
+err:
+ DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel,
+ type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS");
+
+ return r;
+}
+
+static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+ u8 *buf, int buflen)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ int r;
+
+ r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
+ if (r)
+ goto err;
+
+ r = dsi_vc_send_bta_sync(dssdev, channel);
+ if (r)
+ goto err;
+
+ r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
+ DSS_DSI_CONTENT_DCS);
+ if (r < 0)
+ goto err;
+
+ if (r != buflen) {
+ r = -EIO;
+ goto err;
+ }
+
+ return 0;
+err:
+ DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd);
+ return r;
+}
+
+static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
+ u8 *reqdata, int reqlen, u8 *buf, int buflen)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ int r;
+
+ r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
+ if (r)
+ return r;
+
+ r = dsi_vc_send_bta_sync(dssdev, channel);
+ if (r)
+ return r;
+
+ r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
+ DSS_DSI_CONTENT_GENERIC);
+ if (r < 0)
+ return r;
+
+ if (r != buflen) {
+ r = -EIO;
+ return r;
+ }
+
+ return 0;
+}
+
+static int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
+ u16 len)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_send_short(dsidev, channel,
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
+}
+
+static int dsi_enter_ulps(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ DECLARE_COMPLETION_ONSTACK(completion);
+ int r, i;
+ unsigned mask;
+
+ DSSDBG("Entering ULPS");
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ WARN_ON(dsi->ulps_enabled);
+
+ if (dsi->ulps_enabled)
+ return 0;
+
+ /* DDR_CLK_ALWAYS_ON */
+ if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
+ dsi_if_enable(dsidev, 0);
+ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
+ dsi_if_enable(dsidev, 1);
+ }
+
+ dsi_sync_vc(dsidev, 0);
+ dsi_sync_vc(dsidev, 1);
+ dsi_sync_vc(dsidev, 2);
+ dsi_sync_vc(dsidev, 3);
+
+ dsi_force_tx_stop_mode_io(dsidev);
+
+ dsi_vc_enable(dsidev, 0, false);
+ dsi_vc_enable(dsidev, 1, false);
+ dsi_vc_enable(dsidev, 2, false);
+ dsi_vc_enable(dsidev, 3, false);
+
+ if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
+ DSSERR("HS busy when enabling ULPS\n");
+ return -EIO;
+ }
+
+ if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
+ DSSERR("LP busy when enabling ULPS\n");
+ return -EIO;
+ }
+
+ r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
+ DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+ if (r)
+ return r;
+
+ mask = 0;
+
+ for (i = 0; i < dsi->num_lanes_supported; ++i) {
+ if (dsi->lanes[i].function == DSI_LANE_UNUSED)
+ continue;
+ mask |= 1 << i;
+ }
+ /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
+ /* LANEx_ULPS_SIG2 */
+ REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5);
+
+ /* flush posted write and wait for SCP interface to finish the write */
+ dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
+
+ if (wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(1000)) == 0) {
+ DSSERR("ULPS enable timeout\n");
+ r = -EIO;
+ goto err;
+ }
+
+ dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
+ DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+
+ /* Reset LANEx_ULPS_SIG2 */
+ REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5);
+
+ /* flush posted write and wait for SCP interface to finish the write */
+ dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
+
+ dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
+
+ dsi_if_enable(dsidev, false);
+
+ dsi->ulps_enabled = true;
+
+ return 0;
+
+err:
+ dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
+ DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+ return r;
+}
+
+static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
+ unsigned ticks, bool x4, bool x16)
+{
+ unsigned long fck;
+ unsigned long total_ticks;
+ u32 r;
+
+ BUG_ON(ticks > 0x1fff);
+
+ /* ticks in DSI_FCK */
+ fck = dsi_fclk_rate(dsidev);
+
+ r = dsi_read_reg(dsidev, DSI_TIMING2);
+ r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
+ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
+ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
+ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
+ dsi_write_reg(dsidev, DSI_TIMING2, r);
+
+ total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
+
+ DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
+ total_ticks,
+ ticks, x4 ? " x4" : "", x16 ? " x16" : "",
+ (total_ticks * 1000) / (fck / 1000 / 1000));
+}
+
+static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
+ bool x8, bool x16)
+{
+ unsigned long fck;
+ unsigned long total_ticks;
+ u32 r;
+
+ BUG_ON(ticks > 0x1fff);
+
+ /* ticks in DSI_FCK */
+ fck = dsi_fclk_rate(dsidev);
+
+ r = dsi_read_reg(dsidev, DSI_TIMING1);
+ r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
+ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */
+ r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */
+ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
+ dsi_write_reg(dsidev, DSI_TIMING1, r);
+
+ total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
+
+ DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
+ total_ticks,
+ ticks, x8 ? " x8" : "", x16 ? " x16" : "",
+ (total_ticks * 1000) / (fck / 1000 / 1000));
+}
+
+static void dsi_set_stop_state_counter(struct platform_device *dsidev,
+ unsigned ticks, bool x4, bool x16)
+{
+ unsigned long fck;
+ unsigned long total_ticks;
+ u32 r;
+
+ BUG_ON(ticks > 0x1fff);
+
+ /* ticks in DSI_FCK */
+ fck = dsi_fclk_rate(dsidev);
+
+ r = dsi_read_reg(dsidev, DSI_TIMING1);
+ r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
+ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */
+ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */
+ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
+ dsi_write_reg(dsidev, DSI_TIMING1, r);
+
+ total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
+
+ DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
+ total_ticks,
+ ticks, x4 ? " x4" : "", x16 ? " x16" : "",
+ (total_ticks * 1000) / (fck / 1000 / 1000));
+}
+
+static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
+ unsigned ticks, bool x4, bool x16)
+{
+ unsigned long fck;
+ unsigned long total_ticks;
+ u32 r;
+
+ BUG_ON(ticks > 0x1fff);
+
+ /* ticks in TxByteClkHS */
+ fck = dsi_get_txbyteclkhs(dsidev);
+
+ r = dsi_read_reg(dsidev, DSI_TIMING2);
+ r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
+ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */
+ r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */
+ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
+ dsi_write_reg(dsidev, DSI_TIMING2, r);
+
+ total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
+
+ DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
+ total_ticks,
+ ticks, x4 ? " x4" : "", x16 ? " x16" : "",
+ (total_ticks * 1000) / (fck / 1000 / 1000));
+}
+
+static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int num_line_buffers;
+
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
+ struct omap_video_timings *timings = &dsi->timings;
+ /*
+ * Don't use line buffers if width is greater than the video
+ * port's line buffer size
+ */
+ if (dsi->line_buffer_size <= timings->x_res * bpp / 8)
+ num_line_buffers = 0;
+ else
+ num_line_buffers = 2;
+ } else {
+ /* Use maximum number of line buffers in command mode */
+ num_line_buffers = 2;
+ }
+
+ /* LINE_BUFFER */
+ REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
+}
+
+static void dsi_config_vp_sync_events(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ bool sync_end;
+ u32 r;
+
+ if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE)
+ sync_end = true;
+ else
+ sync_end = false;
+
+ r = dsi_read_reg(dsidev, DSI_CTRL);
+ r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */
+ r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */
+ r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */
+ r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */
+ r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */
+ r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */
+ r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */
+ dsi_write_reg(dsidev, DSI_CTRL, r);
+}
+
+static void dsi_config_blanking_modes(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int blanking_mode = dsi->vm_timings.blanking_mode;
+ int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
+ int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
+ int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
+ u32 r;
+
+ /*
+ * 0 = TX FIFO packets sent or LPS in corresponding blanking periods
+ * 1 = Long blanking packets are sent in corresponding blanking periods
+ */
+ r = dsi_read_reg(dsidev, DSI_CTRL);
+ r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */
+ r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */
+ r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */
+ r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */
+ dsi_write_reg(dsidev, DSI_CTRL, r);
+}
+
+/*
+ * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3
+ * results in maximum transition time for data and clock lanes to enter and
+ * exit HS mode. Hence, this is the scenario where the least amount of command
+ * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS
+ * clock cycles that can be used to interleave command mode data in HS so that
+ * all scenarios are satisfied.
+ */
+static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs,
+ int exit_hs, int exiths_clk, int ddr_pre, int ddr_post)
+{
+ int transition;
+
+ /*
+ * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition
+ * time of data lanes only, if it isn't set, we need to consider HS
+ * transition time of both data and clock lanes. HS transition time
+ * of Scenario 3 is considered.
+ */
+ if (ddr_alwon) {
+ transition = enter_hs + exit_hs + max(enter_hs, 2) + 1;
+ } else {
+ int trans1, trans2;
+ trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1;
+ trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre +
+ enter_hs + 1;
+ transition = max(trans1, trans2);
+ }
+
+ return blank > transition ? blank - transition : 0;
+}
+
+/*
+ * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1
+ * results in maximum transition time for data lanes to enter and exit LP mode.
+ * Hence, this is the scenario where the least amount of command mode data can
+ * be interleaved. We program the minimum amount of bytes that can be
+ * interleaved in LP so that all scenarios are satisfied.
+ */
+static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
+ int lp_clk_div, int tdsi_fclk)
+{
+ int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */
+ int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */
+ int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */
+ int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */
+ int lp_inter; /* cmd mode data that can be interleaved, in bytes */
+
+ /* maximum LP transition time according to Scenario 1 */
+ trans_lp = exit_hs + max(enter_hs, 2) + 1;
+
+ /* CLKIN4DDR = 16 * TXBYTECLKHS */
+ tlp_avail = thsbyte_clk * (blank - trans_lp);
+
+ ttxclkesc = tdsi_fclk * lp_clk_div;
+
+ lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc -
+ 26) / 16;
+
+ return max(lp_inter, 0);
+}
+
+static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int blanking_mode;
+ int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
+ int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div;
+ int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
+ int tclk_trail, ths_exit, exiths_clk;
+ bool ddr_alwon;
+ struct omap_video_timings *timings = &dsi->timings;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
+ int ndl = dsi->num_lanes_used - 1;
+ int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1;
+ int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
+ int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
+ int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
+ int bl_interleave_hs = 0, bl_interleave_lp = 0;
+ u32 r;
+
+ r = dsi_read_reg(dsidev, DSI_CTRL);
+ blanking_mode = FLD_GET(r, 20, 20);
+ hfp_blanking_mode = FLD_GET(r, 21, 21);
+ hbp_blanking_mode = FLD_GET(r, 22, 22);
+ hsa_blanking_mode = FLD_GET(r, 23, 23);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
+ hbp = FLD_GET(r, 11, 0);
+ hfp = FLD_GET(r, 23, 12);
+ hsa = FLD_GET(r, 31, 24);
+
+ r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
+ ddr_clk_post = FLD_GET(r, 7, 0);
+ ddr_clk_pre = FLD_GET(r, 15, 8);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING7);
+ exit_hs_mode_lat = FLD_GET(r, 15, 0);
+ enter_hs_mode_lat = FLD_GET(r, 31, 16);
+
+ r = dsi_read_reg(dsidev, DSI_CLK_CTRL);
+ lp_clk_div = FLD_GET(r, 12, 0);
+ ddr_alwon = FLD_GET(r, 13, 13);
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
+ ths_exit = FLD_GET(r, 7, 0);
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
+ tclk_trail = FLD_GET(r, 15, 8);
+
+ exiths_clk = ths_exit + tclk_trail;
+
+ width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
+ bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl);
+
+ if (!hsa_blanking_mode) {
+ hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ exiths_clk, ddr_clk_pre, ddr_clk_post);
+ hsa_interleave_lp = dsi_compute_interleave_lp(hsa,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ lp_clk_div, dsi_fclk_hsdiv);
+ }
+
+ if (!hfp_blanking_mode) {
+ hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ exiths_clk, ddr_clk_pre, ddr_clk_post);
+ hfp_interleave_lp = dsi_compute_interleave_lp(hfp,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ lp_clk_div, dsi_fclk_hsdiv);
+ }
+
+ if (!hbp_blanking_mode) {
+ hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ exiths_clk, ddr_clk_pre, ddr_clk_post);
+
+ hbp_interleave_lp = dsi_compute_interleave_lp(hbp,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ lp_clk_div, dsi_fclk_hsdiv);
+ }
+
+ if (!blanking_mode) {
+ bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ exiths_clk, ddr_clk_pre, ddr_clk_post);
+
+ bl_interleave_lp = dsi_compute_interleave_lp(bllp,
+ enter_hs_mode_lat, exit_hs_mode_lat,
+ lp_clk_div, dsi_fclk_hsdiv);
+ }
+
+ DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n",
+ hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs,
+ bl_interleave_hs);
+
+ DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n",
+ hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp,
+ bl_interleave_lp);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING4);
+ r = FLD_MOD(r, hsa_interleave_hs, 23, 16);
+ r = FLD_MOD(r, hfp_interleave_hs, 15, 8);
+ r = FLD_MOD(r, hbp_interleave_hs, 7, 0);
+ dsi_write_reg(dsidev, DSI_VM_TIMING4, r);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING5);
+ r = FLD_MOD(r, hsa_interleave_lp, 23, 16);
+ r = FLD_MOD(r, hfp_interleave_lp, 15, 8);
+ r = FLD_MOD(r, hbp_interleave_lp, 7, 0);
+ dsi_write_reg(dsidev, DSI_VM_TIMING5, r);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING6);
+ r = FLD_MOD(r, bl_interleave_hs, 31, 15);
+ r = FLD_MOD(r, bl_interleave_lp, 16, 0);
+ dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
+}
+
+static int dsi_proto_config(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u32 r;
+ int buswidth = 0;
+
+ dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32);
+
+ dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32);
+
+ /* XXX what values for the timeouts? */
+ dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
+ dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
+ dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
+ dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
+
+ switch (dsi_get_pixel_size(dsi->pix_fmt)) {
+ case 16:
+ buswidth = 0;
+ break;
+ case 18:
+ buswidth = 1;
+ break;
+ case 24:
+ buswidth = 2;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ r = dsi_read_reg(dsidev, DSI_CTRL);
+ r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
+ r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
+ r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
+ r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
+ r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
+ r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
+ r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
+ r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
+ if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
+ r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
+ /* DCS_CMD_CODE, 1=start, 0=continue */
+ r = FLD_MOD(r, 0, 25, 25);
+ }
+
+ dsi_write_reg(dsidev, DSI_CTRL, r);
+
+ dsi_config_vp_num_line_buffers(dsidev);
+
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ dsi_config_vp_sync_events(dsidev);
+ dsi_config_blanking_modes(dsidev);
+ dsi_config_cmd_mode_interleaving(dsidev);
+ }
+
+ dsi_vc_initial_config(dsidev, 0);
+ dsi_vc_initial_config(dsidev, 1);
+ dsi_vc_initial_config(dsidev, 2);
+ dsi_vc_initial_config(dsidev, 3);
+
+ return 0;
+}
+
+static void dsi_proto_timings(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
+ unsigned tclk_pre, tclk_post;
+ unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
+ unsigned ths_trail, ths_exit;
+ unsigned ddr_clk_pre, ddr_clk_post;
+ unsigned enter_hs_mode_lat, exit_hs_mode_lat;
+ unsigned ths_eot;
+ int ndl = dsi->num_lanes_used - 1;
+ u32 r;
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
+ ths_prepare = FLD_GET(r, 31, 24);
+ ths_prepare_ths_zero = FLD_GET(r, 23, 16);
+ ths_zero = ths_prepare_ths_zero - ths_prepare;
+ ths_trail = FLD_GET(r, 15, 8);
+ ths_exit = FLD_GET(r, 7, 0);
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
+ tlpx = FLD_GET(r, 20, 16) * 2;
+ tclk_trail = FLD_GET(r, 15, 8);
+ tclk_zero = FLD_GET(r, 7, 0);
+
+ r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
+ tclk_prepare = FLD_GET(r, 7, 0);
+
+ /* min 8*UI */
+ tclk_pre = 20;
+ /* min 60ns + 52*UI */
+ tclk_post = ns2ddr(dsidev, 60) + 26;
+
+ ths_eot = DIV_ROUND_UP(4, ndl);
+
+ ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
+ 4);
+ ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
+
+ BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
+ BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
+
+ r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
+ r = FLD_MOD(r, ddr_clk_pre, 15, 8);
+ r = FLD_MOD(r, ddr_clk_post, 7, 0);
+ dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
+
+ DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
+ ddr_clk_pre,
+ ddr_clk_post);
+
+ enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
+ DIV_ROUND_UP(ths_prepare, 4) +
+ DIV_ROUND_UP(ths_zero + 3, 4);
+
+ exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
+
+ r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
+ FLD_VAL(exit_hs_mode_lat, 15, 0);
+ dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
+
+ DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
+ enter_hs_mode_lat, exit_hs_mode_lat);
+
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ /* TODO: Implement a video mode check_timings function */
+ int hsa = dsi->vm_timings.hsa;
+ int hfp = dsi->vm_timings.hfp;
+ int hbp = dsi->vm_timings.hbp;
+ int vsa = dsi->vm_timings.vsa;
+ int vfp = dsi->vm_timings.vfp;
+ int vbp = dsi->vm_timings.vbp;
+ int window_sync = dsi->vm_timings.window_sync;
+ bool hsync_end;
+ struct omap_video_timings *timings = &dsi->timings;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
+ int tl, t_he, width_bytes;
+
+ hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE;
+ t_he = hsync_end ?
+ ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
+
+ width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
+
+ /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */
+ tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp +
+ DIV_ROUND_UP(width_bytes + 6, ndl) + hbp;
+
+ DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp,
+ hfp, hsync_end ? hsa : 0, tl);
+ DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp,
+ vsa, timings->y_res);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
+ r = FLD_MOD(r, hbp, 11, 0); /* HBP */
+ r = FLD_MOD(r, hfp, 23, 12); /* HFP */
+ r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */
+ dsi_write_reg(dsidev, DSI_VM_TIMING1, r);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING2);
+ r = FLD_MOD(r, vbp, 7, 0); /* VBP */
+ r = FLD_MOD(r, vfp, 15, 8); /* VFP */
+ r = FLD_MOD(r, vsa, 23, 16); /* VSA */
+ r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */
+ dsi_write_reg(dsidev, DSI_VM_TIMING2, r);
+
+ r = dsi_read_reg(dsidev, DSI_VM_TIMING3);
+ r = FLD_MOD(r, timings->y_res, 14, 0); /* VACT */
+ r = FLD_MOD(r, tl, 31, 16); /* TL */
+ dsi_write_reg(dsidev, DSI_VM_TIMING3, r);
+ }
+}
+
+static int dsi_configure_pins(struct omap_dss_device *dssdev,
+ const struct omap_dsi_pin_config *pin_cfg)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int num_pins;
+ const int *pins;
+ struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
+ int num_lanes;
+ int i;
+
+ static const enum dsi_lane_function functions[] = {
+ DSI_LANE_CLK,
+ DSI_LANE_DATA1,
+ DSI_LANE_DATA2,
+ DSI_LANE_DATA3,
+ DSI_LANE_DATA4,
+ };
+
+ num_pins = pin_cfg->num_pins;
+ pins = pin_cfg->pins;
+
+ if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
+ || num_pins % 2 != 0)
+ return -EINVAL;
+
+ for (i = 0; i < DSI_MAX_NR_LANES; ++i)
+ lanes[i].function = DSI_LANE_UNUSED;
+
+ num_lanes = 0;
+
+ for (i = 0; i < num_pins; i += 2) {
+ u8 lane, pol;
+ int dx, dy;
+
+ dx = pins[i];
+ dy = pins[i + 1];
+
+ if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
+ return -EINVAL;
+
+ if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
+ return -EINVAL;
+
+ if (dx & 1) {
+ if (dy != dx - 1)
+ return -EINVAL;
+ pol = 1;
+ } else {
+ if (dy != dx + 1)
+ return -EINVAL;
+ pol = 0;
+ }
+
+ lane = dx / 2;
+
+ lanes[lane].function = functions[i / 2];
+ lanes[lane].polarity = pol;
+ num_lanes++;
+ }
+
+ memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
+ dsi->num_lanes_used = num_lanes;
+
+ return 0;
+}
+
+static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dsi->output.manager;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
+ struct omap_dss_device *out = &dsi->output;
+ u8 data_type;
+ u16 word_count;
+ int r;
+
+ if (out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ return -ENODEV;
+ }
+
+ r = dsi_display_init_dispc(dsidev, mgr);
+ if (r)
+ goto err_init_dispc;
+
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ switch (dsi->pix_fmt) {
+ case OMAP_DSS_DSI_FMT_RGB888:
+ data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
+ break;
+ case OMAP_DSS_DSI_FMT_RGB666:
+ data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
+ break;
+ case OMAP_DSS_DSI_FMT_RGB666_PACKED:
+ data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
+ break;
+ case OMAP_DSS_DSI_FMT_RGB565:
+ data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
+ break;
+ default:
+ r = -EINVAL;
+ goto err_pix_fmt;
+ }
+
+ dsi_if_enable(dsidev, false);
+ dsi_vc_enable(dsidev, channel, false);
+
+ /* MODE, 1 = video mode */
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
+
+ word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
+
+ dsi_vc_write_long_header(dsidev, channel, data_type,
+ word_count, 0);
+
+ dsi_vc_enable(dsidev, channel, true);
+ dsi_if_enable(dsidev, true);
+ }
+
+ r = dss_mgr_enable(mgr);
+ if (r)
+ goto err_mgr_enable;
+
+ return 0;
+
+err_mgr_enable:
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ dsi_if_enable(dsidev, false);
+ dsi_vc_enable(dsidev, channel, false);
+ }
+err_pix_fmt:
+ dsi_display_uninit_dispc(dsidev, mgr);
+err_init_dispc:
+ return r;
+}
+
+static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dsi->output.manager;
+
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ dsi_if_enable(dsidev, false);
+ dsi_vc_enable(dsidev, channel, false);
+
+ /* MODE, 0 = command mode */
+ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
+
+ dsi_vc_enable(dsidev, channel, true);
+ dsi_if_enable(dsidev, true);
+ }
+
+ dss_mgr_disable(mgr);
+
+ dsi_display_uninit_dispc(dsidev, mgr);
+}
+
+static void dsi_update_screen_dispc(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dsi->output.manager;
+ unsigned bytespp;
+ unsigned bytespl;
+ unsigned bytespf;
+ unsigned total_len;
+ unsigned packet_payload;
+ unsigned packet_len;
+ u32 l;
+ int r;
+ const unsigned channel = dsi->update_channel;
+ const unsigned line_buf_size = dsi->line_buffer_size;
+ u16 w = dsi->timings.x_res;
+ u16 h = dsi->timings.y_res;
+
+ DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
+
+ dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
+
+ bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
+ bytespl = w * bytespp;
+ bytespf = bytespl * h;
+
+ /* NOTE: packet_payload has to be equal to N * bytespl, where N is
+ * number of lines in a packet. See errata about VP_CLK_RATIO */
+
+ if (bytespf < line_buf_size)
+ packet_payload = bytespf;
+ else
+ packet_payload = (line_buf_size) / bytespl * bytespl;
+
+ packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
+ total_len = (bytespf / packet_payload) * packet_len;
+
+ if (bytespf % packet_payload)
+ total_len += (bytespf % packet_payload) + 1;
+
+ l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
+ dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
+
+ dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE,
+ packet_len, 0);
+
+ if (dsi->te_enabled)
+ l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
+ else
+ l = FLD_MOD(l, 1, 31, 31); /* TE_START */
+ dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
+
+ /* We put SIDLEMODE to no-idle for the duration of the transfer,
+ * because DSS interrupts are not capable of waking up the CPU and the
+ * framedone interrupt could be delayed for quite a long time. I think
+ * the same goes for any DSS interrupts, but for some reason I have not
+ * seen the problem anywhere else than here.
+ */
+ dispc_disable_sidle();
+
+ dsi_perf_mark_start(dsidev);
+
+ r = schedule_delayed_work(&dsi->framedone_timeout_work,
+ msecs_to_jiffies(250));
+ BUG_ON(r == 0);
+
+ dss_mgr_set_timings(mgr, &dsi->timings);
+
+ dss_mgr_start_update(mgr);
+
+ if (dsi->te_enabled) {
+ /* disable LP_RX_TO, so that we can receive TE. Time to wait
+ * for TE is longer than the timer allows */
+ REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
+
+ dsi_vc_send_bta(dsidev, channel);
+
+#ifdef DSI_CATCH_MISSING_TE
+ mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
+#endif
+ }
+}
+
+#ifdef DSI_CATCH_MISSING_TE
+static void dsi_te_timeout(unsigned long arg)
+{
+ DSSERR("TE not received for 250ms!\n");
+}
+#endif
+
+static void dsi_handle_framedone(struct platform_device *dsidev, int error)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ /* SIDLEMODE back to smart-idle */
+ dispc_enable_sidle();
+
+ if (dsi->te_enabled) {
+ /* enable LP_RX_TO again after the TE */
+ REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+ }
+
+ dsi->framedone_callback(error, dsi->framedone_data);
+
+ if (!error)
+ dsi_perf_show(dsidev, "DISPC");
+}
+
+static void dsi_framedone_timeout_work_callback(struct work_struct *work)
+{
+ struct dsi_data *dsi = container_of(work, struct dsi_data,
+ framedone_timeout_work.work);
+ /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
+ * 250ms which would conflict with this timeout work. What should be
+ * done is first cancel the transfer on the HW, and then cancel the
+ * possibly scheduled framedone work. However, cancelling the transfer
+ * on the HW is buggy, and would probably require resetting the whole
+ * DSI */
+
+ DSSERR("Framedone not received for 250ms!\n");
+
+ dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
+}
+
+static void dsi_framedone_irq_callback(void *data)
+{
+ struct platform_device *dsidev = (struct platform_device *) data;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
+ * turns itself off. However, DSI still has the pixels in its buffers,
+ * and is sending the data.
+ */
+
+ cancel_delayed_work(&dsi->framedone_timeout_work);
+
+ dsi_handle_framedone(dsidev, 0);
+}
+
+static int dsi_update(struct omap_dss_device *dssdev, int channel,
+ void (*callback)(int, void *), void *data)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ u16 dw, dh;
+
+ dsi_perf_mark_setup(dsidev);
+
+ dsi->update_channel = channel;
+
+ dsi->framedone_callback = callback;
+ dsi->framedone_data = data;
+
+ dw = dsi->timings.x_res;
+ dh = dsi->timings.y_res;
+
+#ifdef DSI_PERF_MEASURE
+ dsi->update_bytes = dw * dh *
+ dsi_get_pixel_size(dsi->pix_fmt) / 8;
+#endif
+ dsi_update_screen_dispc(dsidev);
+
+ return 0;
+}
+
+/* Display funcs */
+
+static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dispc_clock_info dispc_cinfo;
+ int r;
+ unsigned long fck;
+
+ fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+
+ dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div;
+ dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div;
+
+ r = dispc_calc_clock_rates(fck, &dispc_cinfo);
+ if (r) {
+ DSSERR("Failed to calc dispc clocks\n");
+ return r;
+ }
+
+ dsi->mgr_config.clock_info = dispc_cinfo;
+
+ return 0;
+}
+
+static int dsi_display_init_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int r;
+
+ dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
+
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
+ r = dss_mgr_register_framedone_handler(mgr,
+ dsi_framedone_irq_callback, dsidev);
+ if (r) {
+ DSSERR("can't register FRAMEDONE handler\n");
+ goto err;
+ }
+
+ dsi->mgr_config.stallmode = true;
+ dsi->mgr_config.fifohandcheck = true;
+ } else {
+ dsi->mgr_config.stallmode = false;
+ dsi->mgr_config.fifohandcheck = false;
+ }
+
+ /*
+ * override interlace, logic level and edge related parameters in
+ * omap_video_timings with default values
+ */
+ dsi->timings.interlace = false;
+ dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
+
+ dss_mgr_set_timings(mgr, &dsi->timings);
+
+ r = dsi_configure_dispc_clocks(dsidev);
+ if (r)
+ goto err1;
+
+ dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
+ dsi->mgr_config.video_port_width =
+ dsi_get_pixel_size(dsi->pix_fmt);
+ dsi->mgr_config.lcden_sig_polarity = 0;
+
+ dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
+
+ return 0;
+err1:
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
+ dss_mgr_unregister_framedone_handler(mgr,
+ dsi_framedone_irq_callback, dsidev);
+err:
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
+ return r;
+}
+
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
+ dss_mgr_unregister_framedone_handler(mgr,
+ dsi_framedone_irq_callback, dsidev);
+
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
+}
+
+static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dss_pll_clock_info cinfo;
+ int r;
+
+ cinfo = dsi->user_dsi_cinfo;
+
+ r = dss_pll_set_config(&dsi->pll, &cinfo);
+ if (r) {
+ DSSERR("Failed to set dsi clocks\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static int dsi_display_init_dsi(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int r;
+
+ r = dss_pll_enable(&dsi->pll);
+ if (r)
+ goto err0;
+
+ r = dsi_configure_dsi_clocks(dsidev);
+ if (r)
+ goto err1;
+
+ dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI);
+
+ DSSDBG("PLL OK\n");
+
+ r = dsi_cio_init(dsidev);
+ if (r)
+ goto err2;
+
+ _dsi_print_reset_status(dsidev);
+
+ dsi_proto_timings(dsidev);
+ dsi_set_lp_clk_divisor(dsidev);
+
+ if (1)
+ _dsi_print_reset_status(dsidev);
+
+ r = dsi_proto_config(dsidev);
+ if (r)
+ goto err3;
+
+ /* enable interface */
+ dsi_vc_enable(dsidev, 0, 1);
+ dsi_vc_enable(dsidev, 1, 1);
+ dsi_vc_enable(dsidev, 2, 1);
+ dsi_vc_enable(dsidev, 3, 1);
+ dsi_if_enable(dsidev, 1);
+ dsi_force_tx_stop_mode_io(dsidev);
+
+ return 0;
+err3:
+ dsi_cio_uninit(dsidev);
+err2:
+ dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
+err1:
+ dss_pll_disable(&dsi->pll);
+err0:
+ return r;
+}
+
+static void dsi_display_uninit_dsi(struct platform_device *dsidev,
+ bool disconnect_lanes, bool enter_ulps)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (enter_ulps && !dsi->ulps_enabled)
+ dsi_enter_ulps(dsidev);
+
+ /* disable interface */
+ dsi_if_enable(dsidev, 0);
+ dsi_vc_enable(dsidev, 0, 0);
+ dsi_vc_enable(dsidev, 1, 0);
+ dsi_vc_enable(dsidev, 2, 0);
+ dsi_vc_enable(dsidev, 3, 0);
+
+ dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
+ dsi_cio_uninit(dsidev);
+ dsi_pll_uninit(dsidev, disconnect_lanes);
+}
+
+static int dsi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int r = 0;
+
+ DSSDBG("dsi_display_enable\n");
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ mutex_lock(&dsi->lock);
+
+ r = dsi_runtime_get(dsidev);
+ if (r)
+ goto err_get_dsi;
+
+ _dsi_initialize_irq(dsidev);
+
+ r = dsi_display_init_dsi(dsidev);
+ if (r)
+ goto err_init_dsi;
+
+ mutex_unlock(&dsi->lock);
+
+ return 0;
+
+err_init_dsi:
+ dsi_runtime_put(dsidev);
+err_get_dsi:
+ mutex_unlock(&dsi->lock);
+ DSSDBG("dsi_display_enable FAILED\n");
+ return r;
+}
+
+static void dsi_display_disable(struct omap_dss_device *dssdev,
+ bool disconnect_lanes, bool enter_ulps)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ DSSDBG("dsi_display_disable\n");
+
+ WARN_ON(!dsi_bus_is_locked(dsidev));
+
+ mutex_lock(&dsi->lock);
+
+ dsi_sync_vc(dsidev, 0);
+ dsi_sync_vc(dsidev, 1);
+ dsi_sync_vc(dsidev, 2);
+ dsi_sync_vc(dsidev, 3);
+
+ dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
+
+ dsi_runtime_put(dsidev);
+
+ mutex_unlock(&dsi->lock);
+}
+
+static int dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ dsi->te_enabled = enable;
+ return 0;
+}
+
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+static void print_dsi_vm(const char *str,
+ const struct omap_dss_dsi_videomode_timings *t)
+{
+ unsigned long byteclk = t->hsclk / 4;
+ int bl, wc, pps, tot;
+
+ wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
+ pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
+ bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
+ tot = bl + pps;
+
+#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
+
+ pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
+ "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
+ str,
+ byteclk,
+ t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
+ bl, pps, tot,
+ TO_DSI_T(t->hss),
+ TO_DSI_T(t->hsa),
+ TO_DSI_T(t->hse),
+ TO_DSI_T(t->hbp),
+ TO_DSI_T(pps),
+ TO_DSI_T(t->hfp),
+
+ TO_DSI_T(bl),
+ TO_DSI_T(pps),
+
+ TO_DSI_T(tot));
+#undef TO_DSI_T
+}
+
+static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
+{
+ unsigned long pck = t->pixelclock;
+ int hact, bl, tot;
+
+ hact = t->x_res;
+ bl = t->hsw + t->hbp + t->hfp;
+ tot = hact + bl;
+
+#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
+
+ pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
+ "%u/%u/%u/%u = %u + %u = %u\n",
+ str,
+ pck,
+ t->hsw, t->hbp, hact, t->hfp,
+ bl, hact, tot,
+ TO_DISPC_T(t->hsw),
+ TO_DISPC_T(t->hbp),
+ TO_DISPC_T(hact),
+ TO_DISPC_T(t->hfp),
+ TO_DISPC_T(bl),
+ TO_DISPC_T(hact),
+ TO_DISPC_T(tot));
+#undef TO_DISPC_T
+}
+
+/* note: this is not quite accurate */
+static void print_dsi_dispc_vm(const char *str,
+ const struct omap_dss_dsi_videomode_timings *t)
+{
+ struct omap_video_timings vm = { 0 };
+ unsigned long byteclk = t->hsclk / 4;
+ unsigned long pck;
+ u64 dsi_tput;
+ int dsi_hact, dsi_htot;
+
+ dsi_tput = (u64)byteclk * t->ndl * 8;
+ pck = (u32)div64_u64(dsi_tput, t->bitspp);
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
+ dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
+
+ vm.pixelclock = pck;
+ vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
+ vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
+ vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
+ vm.x_res = t->hact;
+
+ print_dispc_vm(str, &vm);
+}
+#endif /* PRINT_VERBOSE_VM_TIMINGS */
+
+static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+ struct omap_video_timings *t = &ctx->dispc_vm;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ *t = *ctx->config->timings;
+ t->pixelclock = pck;
+ t->x_res = ctx->config->timings->x_res;
+ t->y_res = ctx->config->timings->y_res;
+ t->hsw = t->hfp = t->hbp = t->vsw = 1;
+ t->vfp = t->vbp = 0;
+
+ return true;
+}
+
+static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+ ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
+
+ return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
+ dsi_cm_calc_dispc_cb, ctx);
+}
+
+static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint,
+ unsigned long clkdco, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.n = n;
+ ctx->dsi_cinfo.m = m;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkdco = clkdco;
+
+ return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
+ dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
+ dsi_cm_calc_hsdiv_cb, ctx);
+}
+
+static bool dsi_cm_calc(struct dsi_data *dsi,
+ const struct omap_dss_dsi_config *cfg,
+ struct dsi_clk_calc_ctx *ctx)
+{
+ unsigned long clkin;
+ int bitspp, ndl;
+ unsigned long pll_min, pll_max;
+ unsigned long pck, txbyteclk;
+
+ clkin = clk_get_rate(dsi->pll.clkin);
+ bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ ndl = dsi->num_lanes_used - 1;
+
+ /*
+ * Here we should calculate minimum txbyteclk to be able to send the
+ * frame in time, and also to handle TE. That's not very simple, though,
+ * especially as we go to LP between each pixel packet due to HW
+ * "feature". So let's just estimate very roughly and multiply by 1.5.
+ */
+ pck = cfg->timings->pixelclock;
+ pck = pck * 3 / 2;
+ txbyteclk = pck * bitspp / 8 / ndl;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dsi->pdev;
+ ctx->pll = &dsi->pll;
+ ctx->config = cfg;
+ ctx->req_pck_min = pck;
+ ctx->req_pck_nom = pck;
+ ctx->req_pck_max = pck * 3 / 2;
+
+ pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
+ pll_max = cfg->hs_clk_max * 4;
+
+ return dss_pll_calc(ctx->pll, clkin,
+ pll_min, pll_max,
+ dsi_cm_calc_pll_cb, ctx);
+}
+
+static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
+ const struct omap_dss_dsi_config *cfg = ctx->config;
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ int ndl = dsi->num_lanes_used - 1;
+ unsigned long hsclk = ctx->dsi_cinfo.clkdco / 4;
+ unsigned long byteclk = hsclk / 4;
+
+ unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
+ int xres;
+ int panel_htot, panel_hbl; /* pixels */
+ int dispc_htot, dispc_hbl; /* pixels */
+ int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
+ int hfp, hsa, hbp;
+ const struct omap_video_timings *req_vm;
+ struct omap_video_timings *dispc_vm;
+ struct omap_dss_dsi_videomode_timings *dsi_vm;
+ u64 dsi_tput, dispc_tput;
+
+ dsi_tput = (u64)byteclk * ndl * 8;
+
+ req_vm = cfg->timings;
+ req_pck_min = ctx->req_pck_min;
+ req_pck_max = ctx->req_pck_max;
+ req_pck_nom = ctx->req_pck_nom;
+
+ dispc_pck = ctx->dispc_cinfo.pck;
+ dispc_tput = (u64)dispc_pck * bitspp;
+
+ xres = req_vm->x_res;
+
+ panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
+ panel_htot = xres + panel_hbl;
+
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
+
+ /*
+ * When there are no line buffers, DISPC and DSI must have the
+ * same tput. Otherwise DISPC tput needs to be higher than DSI's.
+ */
+ if (dsi->line_buffer_size < xres * bitspp / 8) {
+ if (dispc_tput != dsi_tput)
+ return false;
+ } else {
+ if (dispc_tput < dsi_tput)
+ return false;
+ }
+
+ /* DSI tput must be over the min requirement */
+ if (dsi_tput < (u64)bitspp * req_pck_min)
+ return false;
+
+ /* When non-burst mode, DSI tput must be below max requirement. */
+ if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
+ if (dsi_tput > (u64)bitspp * req_pck_max)
+ return false;
+ }
+
+ hss = DIV_ROUND_UP(4, ndl);
+
+ if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
+ if (ndl == 3 && req_vm->hsw == 0)
+ hse = 1;
+ else
+ hse = DIV_ROUND_UP(4, ndl);
+ } else {
+ hse = 0;
+ }
+
+ /* DSI htot to match the panel's nominal pck */
+ dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
+
+ /* fail if there would be no time for blanking */
+ if (dsi_htot < hss + hse + dsi_hact)
+ return false;
+
+ /* total DSI blanking needed to achieve panel's TL */
+ dsi_hbl = dsi_htot - dsi_hact;
+
+ /* DISPC htot to match the DSI TL */
+ dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
+
+ /* verify that the DSI and DISPC TLs are the same */
+ if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
+ return false;
+
+ dispc_hbl = dispc_htot - xres;
+
+ /* setup DSI videomode */
+
+ dsi_vm = &ctx->dsi_vm;
+ memset(dsi_vm, 0, sizeof(*dsi_vm));
+
+ dsi_vm->hsclk = hsclk;
+
+ dsi_vm->ndl = ndl;
+ dsi_vm->bitspp = bitspp;
+
+ if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) {
+ hsa = 0;
+ } else if (ndl == 3 && req_vm->hsw == 0) {
+ hsa = 0;
+ } else {
+ hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom);
+ hsa = max(hsa - hse, 1);
+ }
+
+ hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
+ hbp = max(hbp, 1);
+
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
+ if (hfp < 1) {
+ int t;
+ /* we need to take cycles from hbp */
+
+ t = 1 - hfp;
+ hbp = max(hbp - t, 1);
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
+
+ if (hfp < 1 && hsa > 0) {
+ /* we need to take cycles from hsa */
+ t = 1 - hfp;
+ hsa = max(hsa - t, 1);
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
+ }
+ }
+
+ if (hfp < 1)
+ return false;
+
+ dsi_vm->hss = hss;
+ dsi_vm->hsa = hsa;
+ dsi_vm->hse = hse;
+ dsi_vm->hbp = hbp;
+ dsi_vm->hact = xres;
+ dsi_vm->hfp = hfp;
+
+ dsi_vm->vsa = req_vm->vsw;
+ dsi_vm->vbp = req_vm->vbp;
+ dsi_vm->vact = req_vm->y_res;
+ dsi_vm->vfp = req_vm->vfp;
+
+ dsi_vm->trans_mode = cfg->trans_mode;
+
+ dsi_vm->blanking_mode = 0;
+ dsi_vm->hsa_blanking_mode = 1;
+ dsi_vm->hfp_blanking_mode = 1;
+ dsi_vm->hbp_blanking_mode = 1;
+
+ dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
+ dsi_vm->window_sync = 4;
+
+ /* setup DISPC videomode */
+
+ dispc_vm = &ctx->dispc_vm;
+ *dispc_vm = *req_vm;
+ dispc_vm->pixelclock = dispc_pck;
+
+ if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
+ hsa = div64_u64((u64)req_vm->hsw * dispc_pck,
+ req_pck_nom);
+ hsa = max(hsa, 1);
+ } else {
+ hsa = 1;
+ }
+
+ hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
+ hbp = max(hbp, 1);
+
+ hfp = dispc_hbl - hsa - hbp;
+ if (hfp < 1) {
+ int t;
+ /* we need to take cycles from hbp */
+
+ t = 1 - hfp;
+ hbp = max(hbp - t, 1);
+ hfp = dispc_hbl - hsa - hbp;
+
+ if (hfp < 1) {
+ /* we need to take cycles from hsa */
+ t = 1 - hfp;
+ hsa = max(hsa - t, 1);
+ hfp = dispc_hbl - hsa - hbp;
+ }
+ }
+
+ if (hfp < 1)
+ return false;
+
+ dispc_vm->hfp = hfp;
+ dispc_vm->hsw = hsa;
+ dispc_vm->hbp = hbp;
+
+ return true;
+}
+
+
+static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ if (dsi_vm_calc_blanking(ctx) == false)
+ return false;
+
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+ print_dispc_vm("dispc", &ctx->dispc_vm);
+ print_dsi_vm("dsi ", &ctx->dsi_vm);
+ print_dispc_vm("req ", ctx->config->timings);
+ print_dsi_dispc_vm("act ", &ctx->dsi_vm);
+#endif
+
+ return true;
+}
+
+static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+ unsigned long pck_max;
+
+ ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+ ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
+
+ /*
+ * In burst mode we can let the dispc pck be arbitrarily high, but it
+ * limits our scaling abilities. So for now, don't aim too high.
+ */
+
+ if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE)
+ pck_max = ctx->req_pck_max + 10000000;
+ else
+ pck_max = ctx->req_pck_max;
+
+ return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
+ dsi_vm_calc_dispc_cb, ctx);
+}
+
+static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint,
+ unsigned long clkdco, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.n = n;
+ ctx->dsi_cinfo.m = m;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkdco = clkdco;
+
+ return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
+ dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
+ dsi_vm_calc_hsdiv_cb, ctx);
+}
+
+static bool dsi_vm_calc(struct dsi_data *dsi,
+ const struct omap_dss_dsi_config *cfg,
+ struct dsi_clk_calc_ctx *ctx)
+{
+ const struct omap_video_timings *t = cfg->timings;
+ unsigned long clkin;
+ unsigned long pll_min;
+ unsigned long pll_max;
+ int ndl = dsi->num_lanes_used - 1;
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ unsigned long byteclk_min;
+
+ clkin = clk_get_rate(dsi->pll.clkin);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dsi->pdev;
+ ctx->pll = &dsi->pll;
+ ctx->config = cfg;
+
+ /* these limits should come from the panel driver */
+ ctx->req_pck_min = t->pixelclock - 1000;
+ ctx->req_pck_nom = t->pixelclock;
+ ctx->req_pck_max = t->pixelclock + 1000;
+
+ byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
+ pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
+
+ if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) {
+ pll_max = cfg->hs_clk_max * 4;
+ } else {
+ unsigned long byteclk_max;
+ byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
+ ndl * 8);
+
+ pll_max = byteclk_max * 4 * 4;
+ }
+
+ return dss_pll_calc(ctx->pll, clkin,
+ pll_min, pll_max,
+ dsi_vm_calc_pll_cb, ctx);
+}
+
+static int dsi_set_config(struct omap_dss_device *dssdev,
+ const struct omap_dss_dsi_config *config)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clk_calc_ctx ctx;
+ bool ok;
+ int r;
+
+ mutex_lock(&dsi->lock);
+
+ dsi->pix_fmt = config->pixel_format;
+ dsi->mode = config->mode;
+
+ if (config->mode == OMAP_DSS_DSI_VIDEO_MODE)
+ ok = dsi_vm_calc(dsi, config, &ctx);
+ else
+ ok = dsi_cm_calc(dsi, config, &ctx);
+
+ if (!ok) {
+ DSSERR("failed to find suitable DSI clock settings\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
+
+ r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI],
+ config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo);
+ if (r) {
+ DSSERR("failed to find suitable DSI LP clock settings\n");
+ goto err;
+ }
+
+ dsi->user_dsi_cinfo = ctx.dsi_cinfo;
+ dsi->user_dispc_cinfo = ctx.dispc_cinfo;
+
+ dsi->timings = ctx.dispc_vm;
+ dsi->vm_timings = ctx.dsi_vm;
+
+ mutex_unlock(&dsi->lock);
+
+ return 0;
+err:
+ mutex_unlock(&dsi->lock);
+
+ return r;
+}
+
+/*
+ * Return a hardcoded channel for the DSI output. This should work for
+ * current use cases, but this can be later expanded to either resolve
+ * the channel in some more dynamic manner, or get the channel as a user
+ * parameter.
+ */
+static enum omap_channel dsi_get_channel(int module_id)
+{
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ case OMAPDSS_VER_AM43xx:
+ DSSWARN("DSI not supported\n");
+ return OMAP_DSS_CHANNEL_LCD;
+
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ return OMAP_DSS_CHANNEL_LCD;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ switch (module_id) {
+ case 0:
+ return OMAP_DSS_CHANNEL_LCD;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD2;
+ default:
+ DSSWARN("unsupported module id\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+
+ case OMAPDSS_VER_OMAP5:
+ switch (module_id) {
+ case 0:
+ return OMAP_DSS_CHANNEL_LCD;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD3;
+ default:
+ DSSWARN("unsupported module id\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+
+ default:
+ DSSWARN("unsupported DSS version\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+}
+
+static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
+ if (!dsi->vc[i].dssdev) {
+ dsi->vc[i].dssdev = dssdev;
+ *channel = i;
+ return 0;
+ }
+ }
+
+ DSSERR("cannot get VC for display %s", dssdev->name);
+ return -ENOSPC;
+}
+
+static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if (vc_id < 0 || vc_id > 3) {
+ DSSERR("VC ID out of range\n");
+ return -EINVAL;
+ }
+
+ if (channel < 0 || channel > 3) {
+ DSSERR("Virtual Channel out of range\n");
+ return -EINVAL;
+ }
+
+ if (dsi->vc[channel].dssdev != dssdev) {
+ DSSERR("Virtual Channel not allocated to display %s\n",
+ dssdev->name);
+ return -EINVAL;
+ }
+
+ dsi->vc[channel].vc_id = vc_id;
+
+ return 0;
+}
+
+static void dsi_release_vc(struct omap_dss_device *dssdev, int channel)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ if ((channel >= 0 && channel <= 3) &&
+ dsi->vc[channel].dssdev == dssdev) {
+ dsi->vc[channel].dssdev = NULL;
+ dsi->vc[channel].vc_id = 0;
+ }
+}
+
+
+static int dsi_get_clocks(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct clk *clk;
+
+ clk = devm_clk_get(&dsidev->dev, "fck");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get fck\n");
+ return PTR_ERR(clk);
+ }
+
+ dsi->dss_clk = clk;
+
+ return 0;
+}
+
+static int dsi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = dsi_regulator_init(dsidev);
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dssdev->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void dsi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static const struct omapdss_dsi_ops dsi_ops = {
+ .connect = dsi_connect,
+ .disconnect = dsi_disconnect,
+
+ .bus_lock = dsi_bus_lock,
+ .bus_unlock = dsi_bus_unlock,
+
+ .enable = dsi_display_enable,
+ .disable = dsi_display_disable,
+
+ .enable_hs = dsi_vc_enable_hs,
+
+ .configure_pins = dsi_configure_pins,
+ .set_config = dsi_set_config,
+
+ .enable_video_output = dsi_enable_video_output,
+ .disable_video_output = dsi_disable_video_output,
+
+ .update = dsi_update,
+
+ .enable_te = dsi_enable_te,
+
+ .request_vc = dsi_request_vc,
+ .set_vc_id = dsi_set_vc_id,
+ .release_vc = dsi_release_vc,
+
+ .dcs_write = dsi_vc_dcs_write,
+ .dcs_write_nosync = dsi_vc_dcs_write_nosync,
+ .dcs_read = dsi_vc_dcs_read,
+
+ .gen_write = dsi_vc_generic_write,
+ .gen_write_nosync = dsi_vc_generic_write_nosync,
+ .gen_read = dsi_vc_generic_read,
+
+ .bta_sync = dsi_vc_send_bta_sync,
+
+ .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
+};
+
+static void dsi_init_output(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_dss_device *out = &dsi->output;
+
+ out->dev = &dsidev->dev;
+ out->id = dsi->module_id == 0 ?
+ OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+ out->output_type = OMAP_DISPLAY_TYPE_DSI;
+ out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
+ out->dispc_channel = dsi_get_channel(dsi->module_id);
+ out->ops.dsi = &dsi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void dsi_uninit_output(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_dss_device *out = &dsi->output;
+
+ omapdss_unregister_output(out);
+}
+
+static int dsi_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+ struct property *prop;
+ u32 lane_arr[10];
+ int len, num_pins;
+ int r, i;
+ struct device_node *ep;
+ struct omap_dsi_pin_config pin_cfg;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return 0;
+
+ prop = of_find_property(ep, "lanes", &len);
+ if (prop == NULL) {
+ dev_err(&pdev->dev, "failed to find lane data\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ num_pins = len / sizeof(u32);
+
+ if (num_pins < 4 || num_pins % 2 != 0 ||
+ num_pins > dsi->num_lanes_supported * 2) {
+ dev_err(&pdev->dev, "bad number of lanes\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
+ if (r) {
+ dev_err(&pdev->dev, "failed to read lane data\n");
+ goto err;
+ }
+
+ pin_cfg.num_pins = num_pins;
+ for (i = 0; i < num_pins; ++i)
+ pin_cfg.pins[i] = (int)lane_arr[i];
+
+ r = dsi_configure_pins(&dsi->output, &pin_cfg);
+ if (r) {
+ dev_err(&pdev->dev, "failed to configure pins");
+ goto err;
+ }
+
+ of_node_put(ep);
+
+ return 0;
+
+err:
+ of_node_put(ep);
+ return r;
+}
+
+static const struct dss_pll_ops dsi_pll_ops = {
+ .enable = dsi_pll_enable,
+ .disable = dsi_pll_disable,
+ .set_config = dss_pll_write_config_type_a,
+};
+
+static const struct dss_pll_hw dss_omap3_dsi_pll_hw = {
+ .n_max = (1 << 7) - 1,
+ .m_max = (1 << 11) - 1,
+ .mX_max = (1 << 4) - 1,
+ .fint_min = 750000,
+ .fint_max = 2100000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 7,
+ .n_lsb = 1,
+ .m_msb = 18,
+ .m_lsb = 8,
+
+ .mX_msb[0] = 22,
+ .mX_lsb[0] = 19,
+ .mX_msb[1] = 26,
+ .mX_lsb[1] = 23,
+
+ .has_stopmode = true,
+ .has_freqsel = true,
+ .has_selfreqdco = false,
+ .has_refsel = false,
+};
+
+static const struct dss_pll_hw dss_omap4_dsi_pll_hw = {
+ .n_max = (1 << 8) - 1,
+ .m_max = (1 << 12) - 1,
+ .mX_max = (1 << 5) - 1,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 25,
+ .mX_lsb[0] = 21,
+ .mX_msb[1] = 30,
+ .mX_lsb[1] = 26,
+
+ .has_stopmode = true,
+ .has_freqsel = false,
+ .has_selfreqdco = false,
+ .has_refsel = false,
+};
+
+static const struct dss_pll_hw dss_omap5_dsi_pll_hw = {
+ .n_max = (1 << 8) - 1,
+ .m_max = (1 << 12) - 1,
+ .mX_max = (1 << 5) - 1,
+ .fint_min = 150000,
+ .fint_max = 52000000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 25,
+ .mX_lsb[0] = 21,
+ .mX_msb[1] = 30,
+ .mX_lsb[1] = 26,
+
+ .has_stopmode = true,
+ .has_freqsel = false,
+ .has_selfreqdco = true,
+ .has_refsel = true,
+};
+
+static int dsi_init_pll_data(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dss_pll *pll = &dsi->pll;
+ struct clk *clk;
+ int r;
+
+ clk = devm_clk_get(&dsidev->dev, "sys_clk");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get sys_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
+ pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
+ pll->clkin = clk;
+ pll->base = dsi->pll_base;
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ pll->hw = &dss_omap3_dsi_pll_hw;
+ break;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ pll->hw = &dss_omap4_dsi_pll_hw;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ pll->hw = &dss_omap5_dsi_pll_hw;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ pll->ops = &dsi_pll_ops;
+
+ r = dss_pll_register(pll);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+/* DSI1 HW IP initialisation */
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *dsidev = to_platform_device(dev);
+ u32 rev;
+ int r, i;
+ struct dsi_data *dsi;
+ struct resource *dsi_mem;
+ struct resource *res;
+ struct resource temp_res;
+
+ dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ dsi->pdev = dsidev;
+ dev_set_drvdata(&dsidev->dev, dsi);
+
+ spin_lock_init(&dsi->irq_lock);
+ spin_lock_init(&dsi->errors_lock);
+ dsi->errors = 0;
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_lock_init(&dsi->irq_stats_lock);
+ dsi->irq_stats.last_reset = jiffies;
+#endif
+
+ mutex_init(&dsi->lock);
+ sema_init(&dsi->bus_lock, 1);
+
+ INIT_DEFERRABLE_WORK(&dsi->framedone_timeout_work,
+ dsi_framedone_timeout_work_callback);
+
+#ifdef DSI_CATCH_MISSING_TE
+ init_timer(&dsi->te_timer);
+ dsi->te_timer.function = dsi_te_timeout;
+ dsi->te_timer.data = 0;
+#endif
+
+ res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "proto");
+ if (!res) {
+ res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
+ if (!res) {
+ DSSERR("can't get IORESOURCE_MEM DSI\n");
+ return -EINVAL;
+ }
+
+ temp_res.start = res->start;
+ temp_res.end = temp_res.start + DSI_PROTO_SZ - 1;
+ res = &temp_res;
+ }
+
+ dsi_mem = res;
+
+ dsi->proto_base = devm_ioremap(&dsidev->dev, res->start,
+ resource_size(res));
+ if (!dsi->proto_base) {
+ DSSERR("can't ioremap DSI protocol engine\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "phy");
+ if (!res) {
+ res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
+ if (!res) {
+ DSSERR("can't get IORESOURCE_MEM DSI\n");
+ return -EINVAL;
+ }
+
+ temp_res.start = res->start + DSI_PHY_OFFSET;
+ temp_res.end = temp_res.start + DSI_PHY_SZ - 1;
+ res = &temp_res;
+ }
+
+ dsi->phy_base = devm_ioremap(&dsidev->dev, res->start,
+ resource_size(res));
+ if (!dsi->proto_base) {
+ DSSERR("can't ioremap DSI PHY\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "pll");
+ if (!res) {
+ res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
+ if (!res) {
+ DSSERR("can't get IORESOURCE_MEM DSI\n");
+ return -EINVAL;
+ }
+
+ temp_res.start = res->start + DSI_PLL_OFFSET;
+ temp_res.end = temp_res.start + DSI_PLL_SZ - 1;
+ res = &temp_res;
+ }
+
+ dsi->pll_base = devm_ioremap(&dsidev->dev, res->start,
+ resource_size(res));
+ if (!dsi->proto_base) {
+ DSSERR("can't ioremap DSI PLL\n");
+ return -ENOMEM;
+ }
+
+ dsi->irq = platform_get_irq(dsi->pdev, 0);
+ if (dsi->irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ return -ENODEV;
+ }
+
+ r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler,
+ IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev);
+ if (r < 0) {
+ DSSERR("request_irq failed\n");
+ return r;
+ }
+
+ if (dsidev->dev.of_node) {
+ const struct of_device_id *match;
+ const struct dsi_module_id_data *d;
+
+ match = of_match_node(dsi_of_match, dsidev->dev.of_node);
+ if (!match) {
+ DSSERR("unsupported DSI module\n");
+ return -ENODEV;
+ }
+
+ d = match->data;
+
+ while (d->address != 0 && d->address != dsi_mem->start)
+ d++;
+
+ if (d->address == 0) {
+ DSSERR("unsupported DSI module\n");
+ return -ENODEV;
+ }
+
+ dsi->module_id = d->id;
+ } else {
+ dsi->module_id = dsidev->id;
+ }
+
+ /* DSI VCs initialization */
+ for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
+ dsi->vc[i].source = DSI_VC_SOURCE_L4;
+ dsi->vc[i].dssdev = NULL;
+ dsi->vc[i].vc_id = 0;
+ }
+
+ r = dsi_get_clocks(dsidev);
+ if (r)
+ return r;
+
+ dsi_init_pll_data(dsidev);
+
+ pm_runtime_enable(&dsidev->dev);
+
+ r = dsi_runtime_get(dsidev);
+ if (r)
+ goto err_runtime_get;
+
+ rev = dsi_read_reg(dsidev, DSI_REVISION);
+ dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
+ * of data to 3 by default */
+ if (dss_has_feature(FEAT_DSI_GNQ))
+ /* NB_DATA_LANES */
+ dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
+ else
+ dsi->num_lanes_supported = 3;
+
+ dsi->line_buffer_size = dsi_get_line_buf_size(dsidev);
+
+ dsi_init_output(dsidev);
+
+ if (dsidev->dev.of_node) {
+ r = dsi_probe_of(dsidev);
+ if (r) {
+ DSSERR("Invalid DSI DT data\n");
+ goto err_probe_of;
+ }
+
+ r = of_platform_populate(dsidev->dev.of_node, NULL, NULL,
+ &dsidev->dev);
+ if (r)
+ DSSERR("Failed to populate DSI child devices: %d\n", r);
+ }
+
+ dsi_runtime_put(dsidev);
+
+ if (dsi->module_id == 0)
+ dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs);
+ else if (dsi->module_id == 1)
+ dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs);
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+ if (dsi->module_id == 0)
+ dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs);
+ else if (dsi->module_id == 1)
+ dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs);
+#endif
+
+ return 0;
+
+err_probe_of:
+ dsi_uninit_output(dsidev);
+ dsi_runtime_put(dsidev);
+
+err_runtime_get:
+ pm_runtime_disable(&dsidev->dev);
+ return r;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *dsidev = to_platform_device(dev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ of_platform_depopulate(&dsidev->dev);
+
+ WARN_ON(dsi->scp_clk_refcount > 0);
+
+ dss_pll_unregister(&dsi->pll);
+
+ dsi_uninit_output(dsidev);
+
+ pm_runtime_disable(&dsidev->dev);
+
+ if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
+ regulator_disable(dsi->vdds_dsi_reg);
+ dsi->vdds_dsi_enabled = false;
+ }
+}
+
+static const struct component_ops dsi_component_ops = {
+ .bind = dsi_bind,
+ .unbind = dsi_unbind,
+};
+
+static int dsi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &dsi_component_ops);
+}
+
+static int dsi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dsi_component_ops);
+ return 0;
+}
+
+static int dsi_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+
+ dsi->is_enabled = false;
+ /* ensure the irq handler sees the is_enabled value */
+ smp_wmb();
+ /* wait for current handler to finish before turning the DSI off */
+ synchronize_irq(dsi->irq);
+
+ dispc_runtime_put();
+
+ return 0;
+}
+
+static int dsi_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+ int r;
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ dsi->is_enabled = true;
+ /* ensure the irq handler sees the is_enabled value */
+ smp_wmb();
+
+ return 0;
+}
+
+static const struct dev_pm_ops dsi_pm_ops = {
+ .runtime_suspend = dsi_runtime_suspend,
+ .runtime_resume = dsi_runtime_resume,
+};
+
+static const struct dsi_module_id_data dsi_of_data_omap3[] = {
+ { .address = 0x4804fc00, .id = 0, },
+ { },
+};
+
+static const struct dsi_module_id_data dsi_of_data_omap4[] = {
+ { .address = 0x58004000, .id = 0, },
+ { .address = 0x58005000, .id = 1, },
+ { },
+};
+
+static const struct dsi_module_id_data dsi_of_data_omap5[] = {
+ { .address = 0x58004000, .id = 0, },
+ { .address = 0x58009000, .id = 1, },
+ { },
+};
+
+static const struct of_device_id dsi_of_match[] = {
+ { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
+ { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
+ { .compatible = "ti,omap5-dsi", .data = dsi_of_data_omap5, },
+ {},
+};
+
+static struct platform_driver omap_dsihw_driver = {
+ .probe = dsi_probe,
+ .remove = dsi_remove,
+ .driver = {
+ .name = "omapdss_dsi",
+ .pm = &dsi_pm_ops,
+ .of_match_table = dsi_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init dsi_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dsihw_driver);
+}
+
+void dsi_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_dsihw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c b/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c
new file mode 100644
index 000000000000..bf407b6ba15c
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/seq_file.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+struct device_node *
+omapdss_of_get_next_port(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *port = NULL;
+
+ if (!parent)
+ return NULL;
+
+ if (!prev) {
+ struct device_node *ports;
+ /*
+ * It's the first call, we have to find a port subnode
+ * within this node or within an optional 'ports' node.
+ */
+ ports = of_get_child_by_name(parent, "ports");
+ if (ports)
+ parent = ports;
+
+ port = of_get_child_by_name(parent, "port");
+
+ /* release the 'ports' node */
+ of_node_put(ports);
+ } else {
+ struct device_node *ports;
+
+ ports = of_get_parent(prev);
+ if (!ports)
+ return NULL;
+
+ do {
+ port = of_get_next_child(ports, prev);
+ if (!port) {
+ of_node_put(ports);
+ return NULL;
+ }
+ prev = port;
+ } while (of_node_cmp(port->name, "port") != 0);
+
+ of_node_put(ports);
+ }
+
+ return port;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
+
+struct device_node *
+omapdss_of_get_next_endpoint(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *ep = NULL;
+
+ if (!parent)
+ return NULL;
+
+ do {
+ ep = of_get_next_child(parent, prev);
+ if (!ep)
+ return NULL;
+ prev = ep;
+ } while (of_node_cmp(ep->name, "endpoint") != 0);
+
+ return ep;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
+
+struct device_node *dss_of_port_get_parent_device(struct device_node *port)
+{
+ struct device_node *np;
+ int i;
+
+ if (!port)
+ return NULL;
+
+ np = of_get_parent(port);
+
+ for (i = 0; i < 2 && np; ++i) {
+ struct property *prop;
+
+ prop = of_find_property(np, "compatible", NULL);
+
+ if (prop)
+ return np;
+
+ np = of_get_next_parent(np);
+ }
+
+ return NULL;
+}
+
+u32 dss_of_port_get_port_number(struct device_node *port)
+{
+ int r;
+ u32 reg;
+
+ r = of_property_read_u32(port, "reg", &reg);
+ if (r)
+ reg = 0;
+
+ return reg;
+}
+
+static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
+{
+ struct device_node *np;
+
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np)
+ return NULL;
+
+ np = of_get_next_parent(np);
+
+ return np;
+}
+
+struct device_node *
+omapdss_of_get_first_endpoint(const struct device_node *parent)
+{
+ struct device_node *port, *ep;
+
+ port = omapdss_of_get_next_port(parent, NULL);
+
+ if (!port)
+ return NULL;
+
+ ep = omapdss_of_get_next_endpoint(port, NULL);
+
+ of_node_put(port);
+
+ return ep;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
+
+struct omap_dss_device *
+omapdss_of_find_source_for_first_ep(struct device_node *node)
+{
+ struct device_node *ep;
+ struct device_node *src_port;
+ struct omap_dss_device *src;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return ERR_PTR(-EINVAL);
+
+ src_port = omapdss_of_get_remote_port(ep);
+ if (!src_port) {
+ of_node_put(ep);
+ return ERR_PTR(-EINVAL);
+ }
+
+ of_node_put(ep);
+
+ src = omap_dss_find_output_by_port_node(src_port);
+
+ of_node_put(src_port);
+
+ return src ? src : ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.c b/drivers/video/fbdev/omap2/omapfb/dss/dss.c
new file mode 100644
index 000000000000..0078c4d1fc31
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.c
@@ -0,0 +1,1329 @@
+/*
+ * linux/drivers/video/omap2/dss/dss.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "DSS"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/gfp.h>
+#include <linux/sizes.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+#define DSS_SZ_REGS SZ_512
+
+struct dss_reg {
+ u16 idx;
+};
+
+#define DSS_REG(idx) ((const struct dss_reg) { idx })
+
+#define DSS_REVISION DSS_REG(0x0000)
+#define DSS_SYSCONFIG DSS_REG(0x0010)
+#define DSS_SYSSTATUS DSS_REG(0x0014)
+#define DSS_CONTROL DSS_REG(0x0040)
+#define DSS_SDI_CONTROL DSS_REG(0x0044)
+#define DSS_PLL_CONTROL DSS_REG(0x0048)
+#define DSS_SDI_STATUS DSS_REG(0x005C)
+
+#define REG_GET(idx, start, end) \
+ FLD_GET(dss_read_reg(idx), start, end)
+
+#define REG_FLD_MOD(idx, val, start, end) \
+ dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
+
+struct dss_features {
+ u8 fck_div_max;
+ u8 dss_fck_multiplier;
+ const char *parent_clk_name;
+ const enum omap_display_type *ports;
+ int num_ports;
+ int (*dpi_select_source)(int port, enum omap_channel channel);
+};
+
+static struct {
+ struct platform_device *pdev;
+ void __iomem *base;
+ struct regmap *syscon_pll_ctrl;
+ u32 syscon_pll_ctrl_offset;
+
+ struct clk *parent_clk;
+ struct clk *dss_clk;
+ unsigned long dss_clk_rate;
+
+ unsigned long cache_req_pck;
+ unsigned long cache_prate;
+ struct dispc_clock_info cache_dispc_cinfo;
+
+ enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
+ enum omap_dss_clk_source dispc_clk_source;
+ enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
+
+ bool ctx_valid;
+ u32 ctx[DSS_SZ_REGS / sizeof(u32)];
+
+ const struct dss_features *feat;
+
+ struct dss_pll *video1_pll;
+ struct dss_pll *video2_pll;
+} dss;
+
+static const char * const dss_generic_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
+};
+
+static bool dss_initialized;
+
+bool omapdss_is_initialized(void)
+{
+ return dss_initialized;
+}
+EXPORT_SYMBOL(omapdss_is_initialized);
+
+static inline void dss_write_reg(const struct dss_reg idx, u32 val)
+{
+ __raw_writel(val, dss.base + idx.idx);
+}
+
+static inline u32 dss_read_reg(const struct dss_reg idx)
+{
+ return __raw_readl(dss.base + idx.idx);
+}
+
+#define SR(reg) \
+ dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
+#define RR(reg) \
+ dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
+
+static void dss_save_context(void)
+{
+ DSSDBG("dss_save_context\n");
+
+ SR(CONTROL);
+
+ if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+ OMAP_DISPLAY_TYPE_SDI) {
+ SR(SDI_CONTROL);
+ SR(PLL_CONTROL);
+ }
+
+ dss.ctx_valid = true;
+
+ DSSDBG("context saved\n");
+}
+
+static void dss_restore_context(void)
+{
+ DSSDBG("dss_restore_context\n");
+
+ if (!dss.ctx_valid)
+ return;
+
+ RR(CONTROL);
+
+ if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+ OMAP_DISPLAY_TYPE_SDI) {
+ RR(SDI_CONTROL);
+ RR(PLL_CONTROL);
+ }
+
+ DSSDBG("context restored\n");
+}
+
+#undef SR
+#undef RR
+
+void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
+{
+ unsigned shift;
+ unsigned val;
+
+ if (!dss.syscon_pll_ctrl)
+ return;
+
+ val = !enable;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ shift = 0;
+ break;
+ case DSS_PLL_VIDEO2:
+ shift = 1;
+ break;
+ case DSS_PLL_HDMI:
+ shift = 2;
+ break;
+ default:
+ DSSERR("illegal DSS PLL ID %d\n", pll_id);
+ return;
+ }
+
+ regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
+ 1 << shift, val << shift);
+}
+
+void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
+ enum omap_channel channel)
+{
+ unsigned shift, val;
+
+ if (!dss.syscon_pll_ctrl)
+ return;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ shift = 3;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ val = 0; break;
+ case DSS_PLL_HDMI:
+ val = 1; break;
+ default:
+ DSSERR("error in PLL mux config for LCD\n");
+ return;
+ }
+
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ shift = 5;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ val = 0; break;
+ case DSS_PLL_VIDEO2:
+ val = 1; break;
+ case DSS_PLL_HDMI:
+ val = 2; break;
+ default:
+ DSSERR("error in PLL mux config for LCD2\n");
+ return;
+ }
+
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ shift = 7;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ val = 1; break;
+ case DSS_PLL_VIDEO2:
+ val = 0; break;
+ case DSS_PLL_HDMI:
+ val = 2; break;
+ default:
+ DSSERR("error in PLL mux config for LCD3\n");
+ return;
+ }
+
+ break;
+ default:
+ DSSERR("error in PLL mux config\n");
+ return;
+ }
+
+ regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
+ 0x3 << shift, val << shift);
+}
+
+void dss_sdi_init(int datapairs)
+{
+ u32 l;
+
+ BUG_ON(datapairs > 3 || datapairs < 1);
+
+ l = dss_read_reg(DSS_SDI_CONTROL);
+ l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
+ l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
+ l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
+ dss_write_reg(DSS_SDI_CONTROL, l);
+
+ l = dss_read_reg(DSS_PLL_CONTROL);
+ l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
+ l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
+ l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
+ dss_write_reg(DSS_PLL_CONTROL, l);
+}
+
+int dss_sdi_enable(void)
+{
+ unsigned long timeout;
+
+ dispc_pck_free_enable(1);
+
+ /* Reset SDI PLL */
+ REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
+ udelay(1); /* wait 2x PCLK */
+
+ /* Lock SDI PLL */
+ REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
+
+ /* Waiting for PLL lock request to complete */
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
+ if (time_after_eq(jiffies, timeout)) {
+ DSSERR("PLL lock request timed out\n");
+ goto err1;
+ }
+ }
+
+ /* Clearing PLL_GO bit */
+ REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
+
+ /* Waiting for PLL to lock */
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
+ if (time_after_eq(jiffies, timeout)) {
+ DSSERR("PLL lock timed out\n");
+ goto err1;
+ }
+ }
+
+ dispc_lcd_enable_signal(1);
+
+ /* Waiting for SDI reset to complete */
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
+ if (time_after_eq(jiffies, timeout)) {
+ DSSERR("SDI reset timed out\n");
+ goto err2;
+ }
+ }
+
+ return 0;
+
+ err2:
+ dispc_lcd_enable_signal(0);
+ err1:
+ /* Reset SDI PLL */
+ REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
+
+ dispc_pck_free_enable(0);
+
+ return -ETIMEDOUT;
+}
+
+void dss_sdi_disable(void)
+{
+ dispc_lcd_enable_signal(0);
+
+ dispc_pck_free_enable(0);
+
+ /* Reset SDI PLL */
+ REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
+}
+
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
+{
+ return dss_generic_clk_source_names[clk_src];
+}
+
+void dss_dump_clocks(struct seq_file *s)
+{
+ const char *fclk_name, *fclk_real_name;
+ unsigned long fclk_rate;
+
+ if (dss_runtime_get())
+ return;
+
+ seq_printf(s, "- DSS -\n");
+
+ fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
+ fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
+ fclk_rate = clk_get_rate(dss.dss_clk);
+
+ seq_printf(s, "%s (%s) = %lu\n",
+ fclk_name, fclk_real_name,
+ fclk_rate);
+
+ dss_runtime_put();
+}
+
+static void dss_dump_regs(struct seq_file *s)
+{
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
+
+ if (dss_runtime_get())
+ return;
+
+ DUMPREG(DSS_REVISION);
+ DUMPREG(DSS_SYSCONFIG);
+ DUMPREG(DSS_SYSSTATUS);
+ DUMPREG(DSS_CONTROL);
+
+ if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+ OMAP_DISPLAY_TYPE_SDI) {
+ DUMPREG(DSS_SDI_CONTROL);
+ DUMPREG(DSS_PLL_CONTROL);
+ DUMPREG(DSS_SDI_STATUS);
+ }
+
+ dss_runtime_put();
+#undef DUMPREG
+}
+
+static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
+{
+ int b;
+ u8 start, end;
+
+ switch (clk_src) {
+ case OMAP_DSS_CLK_SRC_FCK:
+ b = 0;
+ break;
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ b = 1;
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+ b = 2;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
+
+ REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */
+
+ dss.dispc_clk_source = clk_src;
+}
+
+void dss_select_dsi_clk_source(int dsi_module,
+ enum omap_dss_clk_source clk_src)
+{
+ int b, pos;
+
+ switch (clk_src) {
+ case OMAP_DSS_CLK_SRC_FCK:
+ b = 0;
+ break;
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+ BUG_ON(dsi_module != 0);
+ b = 1;
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
+ BUG_ON(dsi_module != 1);
+ b = 1;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ pos = dsi_module == 0 ? 1 : 10;
+ REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */
+
+ dss.dsi_clk_source[dsi_module] = clk_src;
+}
+
+void dss_select_lcd_clk_source(enum omap_channel channel,
+ enum omap_dss_clk_source clk_src)
+{
+ int b, ix, pos;
+
+ if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
+ dss_select_dispc_clk_source(clk_src);
+ return;
+ }
+
+ switch (clk_src) {
+ case OMAP_DSS_CLK_SRC_FCK:
+ b = 0;
+ break;
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
+ b = 1;
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+ BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
+ channel != OMAP_DSS_CHANNEL_LCD3);
+ b = 1;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
+ (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
+ REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
+
+ ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
+ (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
+ dss.lcd_clk_source[ix] = clk_src;
+}
+
+enum omap_dss_clk_source dss_get_dispc_clk_source(void)
+{
+ return dss.dispc_clk_source;
+}
+
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
+{
+ return dss.dsi_clk_source[dsi_module];
+}
+
+enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+{
+ if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+ int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
+ (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
+ return dss.lcd_clk_source[ix];
+ } else {
+ /* LCD_CLK source is the same as DISPC_FCLK source for
+ * OMAP2 and OMAP3 */
+ return dss.dispc_clk_source;
+ }
+}
+
+bool dss_div_calc(unsigned long pck, unsigned long fck_min,
+ dss_div_calc_func func, void *data)
+{
+ int fckd, fckd_start, fckd_stop;
+ unsigned long fck;
+ unsigned long fck_hw_max;
+ unsigned long fckd_hw_max;
+ unsigned long prate;
+ unsigned m;
+
+ fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ if (dss.parent_clk == NULL) {
+ unsigned pckd;
+
+ pckd = fck_hw_max / pck;
+
+ fck = pck * pckd;
+
+ fck = clk_round_rate(dss.dss_clk, fck);
+
+ return func(fck, data);
+ }
+
+ fckd_hw_max = dss.feat->fck_div_max;
+
+ m = dss.feat->dss_fck_multiplier;
+ prate = clk_get_rate(dss.parent_clk);
+
+ fck_min = fck_min ? fck_min : 1;
+
+ fckd_start = min(prate * m / fck_min, fckd_hw_max);
+ fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
+
+ for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
+ fck = DIV_ROUND_UP(prate, fckd) * m;
+
+ if (func(fck, data))
+ return true;
+ }
+
+ return false;
+}
+
+int dss_set_fck_rate(unsigned long rate)
+{
+ int r;
+
+ DSSDBG("set fck to %lu\n", rate);
+
+ r = clk_set_rate(dss.dss_clk, rate);
+ if (r)
+ return r;
+
+ dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
+
+ WARN_ONCE(dss.dss_clk_rate != rate,
+ "clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
+ rate);
+
+ return 0;
+}
+
+unsigned long dss_get_dispc_clk_rate(void)
+{
+ return dss.dss_clk_rate;
+}
+
+static int dss_setup_default_clock(void)
+{
+ unsigned long max_dss_fck, prate;
+ unsigned long fck;
+ unsigned fck_div;
+ int r;
+
+ max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ if (dss.parent_clk == NULL) {
+ fck = clk_round_rate(dss.dss_clk, max_dss_fck);
+ } else {
+ prate = clk_get_rate(dss.parent_clk);
+
+ fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
+ max_dss_fck);
+ fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier;
+ }
+
+ r = dss_set_fck_rate(fck);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+void dss_set_venc_output(enum omap_dss_venc_type type)
+{
+ int l = 0;
+
+ if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
+ l = 0;
+ else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
+ l = 1;
+ else
+ BUG();
+
+ /* venc out selection. 0 = comp, 1 = svideo */
+ REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
+}
+
+void dss_set_dac_pwrdn_bgz(bool enable)
+{
+ REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
+}
+
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
+{
+ enum omap_display_type dp;
+ dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
+
+ /* Complain about invalid selections */
+ WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
+ WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
+
+ /* Select only if we have options */
+ if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
+ REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
+}
+
+enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
+{
+ enum omap_display_type displays;
+
+ displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
+ if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
+ return DSS_VENC_TV_CLK;
+
+ if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
+ return DSS_HDMI_M_PCLK;
+
+ return REG_GET(DSS_CONTROL, 15, 15);
+}
+
+static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
+{
+ if (channel != OMAP_DSS_CHANNEL_LCD)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ val = 1;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 2;
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ val = 3;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
+
+ return 0;
+}
+
+static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
+{
+ switch (port) {
+ case 0:
+ return dss_dpi_select_source_omap5(port, channel);
+ case 1:
+ if (channel != OMAP_DSS_CHANNEL_LCD2)
+ return -EINVAL;
+ break;
+ case 2:
+ if (channel != OMAP_DSS_CHANNEL_LCD3)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int dss_dpi_select_source(int port, enum omap_channel channel)
+{
+ return dss.feat->dpi_select_source(port, channel);
+}
+
+static int dss_get_clocks(void)
+{
+ struct clk *clk;
+
+ clk = devm_clk_get(&dss.pdev->dev, "fck");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get clock fck\n");
+ return PTR_ERR(clk);
+ }
+
+ dss.dss_clk = clk;
+
+ if (dss.feat->parent_clk_name) {
+ clk = clk_get(NULL, dss.feat->parent_clk_name);
+ if (IS_ERR(clk)) {
+ DSSERR("Failed to get %s\n", dss.feat->parent_clk_name);
+ return PTR_ERR(clk);
+ }
+ } else {
+ clk = NULL;
+ }
+
+ dss.parent_clk = clk;
+
+ return 0;
+}
+
+static void dss_put_clocks(void)
+{
+ if (dss.parent_clk)
+ clk_put(dss.parent_clk);
+}
+
+int dss_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("dss_runtime_get\n");
+
+ r = pm_runtime_get_sync(&dss.pdev->dev);
+ WARN_ON(r < 0);
+ return r < 0 ? r : 0;
+}
+
+void dss_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("dss_runtime_put\n");
+
+ r = pm_runtime_put_sync(&dss.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
+}
+
+/* DEBUGFS */
+#if defined(CONFIG_FB_OMAP2_DSS_DEBUGFS)
+void dss_debug_dump_clocks(struct seq_file *s)
+{
+ dss_dump_clocks(s);
+ dispc_dump_clocks(s);
+#ifdef CONFIG_FB_OMAP2_DSS_DSI
+ dsi_dump_clocks(s);
+#endif
+}
+#endif
+
+
+static const enum omap_display_type omap2plus_ports[] = {
+ OMAP_DISPLAY_TYPE_DPI,
+};
+
+static const enum omap_display_type omap34xx_ports[] = {
+ OMAP_DISPLAY_TYPE_DPI,
+ OMAP_DISPLAY_TYPE_SDI,
+};
+
+static const enum omap_display_type dra7xx_ports[] = {
+ OMAP_DISPLAY_TYPE_DPI,
+ OMAP_DISPLAY_TYPE_DPI,
+ OMAP_DISPLAY_TYPE_DPI,
+};
+
+static const struct dss_features omap24xx_dss_feats = {
+ /*
+ * fck div max is really 16, but the divider range has gaps. The range
+ * from 1 to 6 has no gaps, so let's use that as a max.
+ */
+ .fck_div_max = 6,
+ .dss_fck_multiplier = 2,
+ .parent_clk_name = "core_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
+};
+
+static const struct dss_features omap34xx_dss_feats = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .parent_clk_name = "dpll4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap34xx_ports,
+ .num_ports = ARRAY_SIZE(omap34xx_ports),
+};
+
+static const struct dss_features omap3630_dss_feats = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .parent_clk_name = "dpll4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
+};
+
+static const struct dss_features omap44xx_dss_feats = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .parent_clk_name = "dpll_per_x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap4,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
+};
+
+static const struct dss_features omap54xx_dss_feats = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .parent_clk_name = "dpll_per_x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap5,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
+};
+
+static const struct dss_features am43xx_dss_feats = {
+ .fck_div_max = 0,
+ .dss_fck_multiplier = 0,
+ .parent_clk_name = NULL,
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
+};
+
+static const struct dss_features dra7xx_dss_feats = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .parent_clk_name = "dpll_per_x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_dra7xx,
+ .ports = dra7xx_ports,
+ .num_ports = ARRAY_SIZE(dra7xx_ports),
+};
+
+static int dss_init_features(struct platform_device *pdev)
+{
+ const struct dss_features *src;
+ struct dss_features *dst;
+
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
+ return -ENOMEM;
+ }
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ src = &omap24xx_dss_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_AM35xx:
+ src = &omap34xx_dss_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP3630:
+ src = &omap3630_dss_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ src = &omap44xx_dss_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ src = &omap54xx_dss_feats;
+ break;
+
+ case OMAPDSS_VER_AM43xx:
+ src = &am43xx_dss_feats;
+ break;
+
+ case OMAPDSS_VER_DRA7xx:
+ src = &dra7xx_dss_feats;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ dss.feat = dst;
+
+ return 0;
+}
+
+static int dss_init_ports(struct platform_device *pdev)
+{
+ struct device_node *parent = pdev->dev.of_node;
+ struct device_node *port;
+ int r;
+
+ if (parent == NULL)
+ return 0;
+
+ port = omapdss_of_get_next_port(parent, NULL);
+ if (!port)
+ return 0;
+
+ if (dss.feat->num_ports == 0)
+ return 0;
+
+ do {
+ enum omap_display_type port_type;
+ u32 reg;
+
+ r = of_property_read_u32(port, "reg", &reg);
+ if (r)
+ reg = 0;
+
+ if (reg >= dss.feat->num_ports)
+ continue;
+
+ port_type = dss.feat->ports[reg];
+
+ switch (port_type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ dpi_init_port(pdev, port);
+ break;
+ case OMAP_DISPLAY_TYPE_SDI:
+ sdi_init_port(pdev, port);
+ break;
+ default:
+ break;
+ }
+ } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
+
+ return 0;
+}
+
+static void dss_uninit_ports(struct platform_device *pdev)
+{
+ struct device_node *parent = pdev->dev.of_node;
+ struct device_node *port;
+
+ if (parent == NULL)
+ return;
+
+ port = omapdss_of_get_next_port(parent, NULL);
+ if (!port)
+ return;
+
+ if (dss.feat->num_ports == 0)
+ return;
+
+ do {
+ enum omap_display_type port_type;
+ u32 reg;
+ int r;
+
+ r = of_property_read_u32(port, "reg", &reg);
+ if (r)
+ reg = 0;
+
+ if (reg >= dss.feat->num_ports)
+ continue;
+
+ port_type = dss.feat->ports[reg];
+
+ switch (port_type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ dpi_uninit_port(port);
+ break;
+ case OMAP_DISPLAY_TYPE_SDI:
+ sdi_uninit_port(port);
+ break;
+ default:
+ break;
+ }
+ } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
+}
+
+static int dss_video_pll_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct regulator *pll_regulator;
+ int r;
+
+ if (!np)
+ return 0;
+
+ if (of_property_read_bool(np, "syscon-pll-ctrl")) {
+ dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
+ "syscon-pll-ctrl");
+ if (IS_ERR(dss.syscon_pll_ctrl)) {
+ dev_err(&pdev->dev,
+ "failed to get syscon-pll-ctrl regmap\n");
+ return PTR_ERR(dss.syscon_pll_ctrl);
+ }
+
+ if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
+ &dss.syscon_pll_ctrl_offset)) {
+ dev_err(&pdev->dev,
+ "failed to get syscon-pll-ctrl offset\n");
+ return -EINVAL;
+ }
+ }
+
+ pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
+ if (IS_ERR(pll_regulator)) {
+ r = PTR_ERR(pll_regulator);
+
+ switch (r) {
+ case -ENOENT:
+ pll_regulator = NULL;
+ break;
+
+ case -EPROBE_DEFER:
+ return -EPROBE_DEFER;
+
+ default:
+ DSSERR("can't get DPLL VDDA regulator\n");
+ return r;
+ }
+ }
+
+ if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
+ dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
+ if (IS_ERR(dss.video1_pll))
+ return PTR_ERR(dss.video1_pll);
+ }
+
+ if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
+ dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
+ if (IS_ERR(dss.video2_pll)) {
+ dss_video_pll_uninit(dss.video1_pll);
+ return PTR_ERR(dss.video2_pll);
+ }
+ }
+
+ return 0;
+}
+
+/* DSS HW IP initialisation */
+static int dss_bind(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *dss_mem;
+ u32 rev;
+ int r;
+
+ dss.pdev = pdev;
+
+ r = dss_init_features(dss.pdev);
+ if (r)
+ return r;
+
+ dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+ if (!dss_mem) {
+ DSSERR("can't get IORESOURCE_MEM DSS\n");
+ return -EINVAL;
+ }
+
+ dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
+ resource_size(dss_mem));
+ if (!dss.base) {
+ DSSERR("can't ioremap DSS\n");
+ return -ENOMEM;
+ }
+
+ r = dss_get_clocks();
+ if (r)
+ return r;
+
+ r = dss_setup_default_clock();
+ if (r)
+ goto err_setup_clocks;
+
+ r = dss_video_pll_probe(pdev);
+ if (r)
+ goto err_pll_init;
+
+ r = dss_init_ports(pdev);
+ if (r)
+ goto err_init_ports;
+
+ pm_runtime_enable(&pdev->dev);
+
+ r = dss_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
+
+ /* Select DPLL */
+ REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
+
+ dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+
+#ifdef CONFIG_FB_OMAP2_DSS_VENC
+ REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
+ REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
+ REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
+#endif
+ dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+ dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+ dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+ dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+ dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+
+ rev = dss_read_reg(DSS_REVISION);
+ printk(KERN_INFO "OMAP DSS rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ dss_runtime_put();
+
+ r = component_bind_all(&pdev->dev, NULL);
+ if (r)
+ goto err_component;
+
+ dss_debugfs_create_file("dss", dss_dump_regs);
+
+ pm_set_vt_switch(0);
+
+ dss_initialized = true;
+
+ return 0;
+
+err_component:
+err_runtime_get:
+ pm_runtime_disable(&pdev->dev);
+ dss_uninit_ports(pdev);
+err_init_ports:
+ if (dss.video1_pll)
+ dss_video_pll_uninit(dss.video1_pll);
+
+ if (dss.video2_pll)
+ dss_video_pll_uninit(dss.video2_pll);
+err_pll_init:
+err_setup_clocks:
+ dss_put_clocks();
+ return r;
+}
+
+static void dss_unbind(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ dss_initialized = false;
+
+ component_unbind_all(&pdev->dev, NULL);
+
+ if (dss.video1_pll)
+ dss_video_pll_uninit(dss.video1_pll);
+
+ if (dss.video2_pll)
+ dss_video_pll_uninit(dss.video2_pll);
+
+ dss_uninit_ports(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ dss_put_clocks();
+}
+
+static const struct component_master_ops dss_component_ops = {
+ .bind = dss_bind,
+ .unbind = dss_unbind,
+};
+
+static int dss_component_compare(struct device *dev, void *data)
+{
+ struct device *child = data;
+ return dev == child;
+}
+
+static int dss_add_child_component(struct device *dev, void *data)
+{
+ struct component_match **match = data;
+
+ /*
+ * HACK
+ * We don't have a working driver for rfbi, so skip it here always.
+ * Otherwise dss will never get probed successfully, as it will wait
+ * for rfbi to get probed.
+ */
+ if (strstr(dev_name(dev), "rfbi"))
+ return 0;
+
+ component_match_add(dev->parent, match, dss_component_compare, dev);
+
+ return 0;
+}
+
+static int dss_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ int r;
+
+ /* add all the child devices as components */
+ device_for_each_child(&pdev->dev, &match, dss_add_child_component);
+
+ r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int dss_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &dss_component_ops);
+ return 0;
+}
+
+static int dss_runtime_suspend(struct device *dev)
+{
+ dss_save_context();
+ dss_set_min_bus_tput(dev, 0);
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int dss_runtime_resume(struct device *dev)
+{
+ int r;
+
+ pinctrl_pm_select_default_state(dev);
+
+ /*
+ * Set an arbitrarily high tput request to ensure OPP100.
+ * What we should really do is to make a request to stay in OPP100,
+ * without any tput requirements, but that is not currently possible
+ * via the PM layer.
+ */
+
+ r = dss_set_min_bus_tput(dev, 1000000000);
+ if (r)
+ return r;
+
+ dss_restore_context();
+ return 0;
+}
+
+static const struct dev_pm_ops dss_pm_ops = {
+ .runtime_suspend = dss_runtime_suspend,
+ .runtime_resume = dss_runtime_resume,
+};
+
+static const struct of_device_id dss_of_match[] = {
+ { .compatible = "ti,omap2-dss", },
+ { .compatible = "ti,omap3-dss", },
+ { .compatible = "ti,omap4-dss", },
+ { .compatible = "ti,omap5-dss", },
+ { .compatible = "ti,dra7-dss", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, dss_of_match);
+
+static struct platform_driver omap_dsshw_driver = {
+ .probe = dss_probe,
+ .remove = dss_remove,
+ .driver = {
+ .name = "omapdss_dss",
+ .pm = &dss_pm_ops,
+ .of_match_table = dss_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init dss_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dsshw_driver);
+}
+
+void dss_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_dsshw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.h b/drivers/video/fbdev/omap2/omapfb/dss/dss.h
new file mode 100644
index 000000000000..b9066afee301
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.h
@@ -0,0 +1,468 @@
+/*
+ * linux/drivers/video/omap2/dss/dss.h
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#ifndef __OMAP2_DSS_H
+#define __OMAP2_DSS_H
+
+#include <linux/interrupt.h>
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+
+#ifdef DSS_SUBSYS_NAME
+#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt
+#else
+#define pr_fmt(fmt) fmt
+#endif
+
+#define DSSDBG(format, ...) \
+ pr_debug(format, ## __VA_ARGS__)
+
+#ifdef DSS_SUBSYS_NAME
+#define DSSERR(format, ...) \
+ printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
+ ## __VA_ARGS__)
+#else
+#define DSSERR(format, ...) \
+ printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
+#endif
+
+#ifdef DSS_SUBSYS_NAME
+#define DSSINFO(format, ...) \
+ printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
+ ## __VA_ARGS__)
+#else
+#define DSSINFO(format, ...) \
+ printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
+#endif
+
+#ifdef DSS_SUBSYS_NAME
+#define DSSWARN(format, ...) \
+ printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
+ ## __VA_ARGS__)
+#else
+#define DSSWARN(format, ...) \
+ printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
+#endif
+
+/* OMAP TRM gives bitfields as start:end, where start is the higher bit
+ number. For example 7:0 */
+#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
+#define FLD_MOD(orig, val, start, end) \
+ (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
+
+enum dss_io_pad_mode {
+ DSS_IO_PAD_MODE_RESET,
+ DSS_IO_PAD_MODE_RFBI,
+ DSS_IO_PAD_MODE_BYPASS,
+};
+
+enum dss_hdmi_venc_clk_source_select {
+ DSS_VENC_TV_CLK = 0,
+ DSS_HDMI_M_PCLK = 1,
+};
+
+enum dss_dsi_content_type {
+ DSS_DSI_CONTENT_DCS,
+ DSS_DSI_CONTENT_GENERIC,
+};
+
+enum dss_writeback_channel {
+ DSS_WB_LCD1_MGR = 0,
+ DSS_WB_LCD2_MGR = 1,
+ DSS_WB_TV_MGR = 2,
+ DSS_WB_OVL0 = 3,
+ DSS_WB_OVL1 = 4,
+ DSS_WB_OVL2 = 5,
+ DSS_WB_OVL3 = 6,
+ DSS_WB_LCD3_MGR = 7,
+};
+
+enum dss_pll_id {
+ DSS_PLL_DSI1,
+ DSS_PLL_DSI2,
+ DSS_PLL_HDMI,
+ DSS_PLL_VIDEO1,
+ DSS_PLL_VIDEO2,
+};
+
+struct dss_pll;
+
+#define DSS_PLL_MAX_HSDIVS 4
+
+/*
+ * Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7.
+ * Type-B PLLs: clkout[0] refers to m2.
+ */
+struct dss_pll_clock_info {
+ /* rates that we get with dividers below */
+ unsigned long fint;
+ unsigned long clkdco;
+ unsigned long clkout[DSS_PLL_MAX_HSDIVS];
+
+ /* dividers */
+ u16 n;
+ u16 m;
+ u32 mf;
+ u16 mX[DSS_PLL_MAX_HSDIVS];
+ u16 sd;
+};
+
+struct dss_pll_ops {
+ int (*enable)(struct dss_pll *pll);
+ void (*disable)(struct dss_pll *pll);
+ int (*set_config)(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+};
+
+struct dss_pll_hw {
+ unsigned n_max;
+ unsigned m_min;
+ unsigned m_max;
+ unsigned mX_max;
+
+ unsigned long fint_min, fint_max;
+ unsigned long clkdco_min, clkdco_low, clkdco_max;
+
+ u8 n_msb, n_lsb;
+ u8 m_msb, m_lsb;
+ u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS];
+
+ bool has_stopmode;
+ bool has_freqsel;
+ bool has_selfreqdco;
+ bool has_refsel;
+};
+
+struct dss_pll {
+ const char *name;
+ enum dss_pll_id id;
+
+ struct clk *clkin;
+ struct regulator *regulator;
+
+ void __iomem *base;
+
+ const struct dss_pll_hw *hw;
+
+ const struct dss_pll_ops *ops;
+
+ struct dss_pll_clock_info cinfo;
+};
+
+struct dispc_clock_info {
+ /* rates that we get with dividers below */
+ unsigned long lck;
+ unsigned long pck;
+
+ /* dividers */
+ u16 lck_div;
+ u16 pck_div;
+};
+
+struct dss_lcd_mgr_config {
+ enum dss_io_pad_mode io_pad_mode;
+
+ bool stallmode;
+ bool fifohandcheck;
+
+ struct dispc_clock_info clock_info;
+
+ int video_port_width;
+
+ int lcden_sig_polarity;
+};
+
+struct seq_file;
+struct platform_device;
+
+/* core */
+struct platform_device *dss_get_core_pdev(void);
+int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask);
+void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
+int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
+int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
+
+/* display */
+int dss_suspend_all_devices(void);
+int dss_resume_all_devices(void);
+void dss_disable_all_devices(void);
+
+int display_init_sysfs(struct platform_device *pdev);
+void display_uninit_sysfs(struct platform_device *pdev);
+
+/* manager */
+int dss_init_overlay_managers(void);
+void dss_uninit_overlay_managers(void);
+int dss_init_overlay_managers_sysfs(struct platform_device *pdev);
+void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev);
+int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
+ const struct omap_overlay_manager_info *info);
+int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
+ const struct omap_video_timings *timings);
+int dss_mgr_check(struct omap_overlay_manager *mgr,
+ struct omap_overlay_manager_info *info,
+ const struct omap_video_timings *mgr_timings,
+ const struct dss_lcd_mgr_config *config,
+ struct omap_overlay_info **overlay_infos);
+
+static inline bool dss_mgr_is_lcd(enum omap_channel id)
+{
+ if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 ||
+ id == OMAP_DSS_CHANNEL_LCD3)
+ return true;
+ else
+ return false;
+}
+
+int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
+ struct platform_device *pdev);
+void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
+
+/* overlay */
+void dss_init_overlays(struct platform_device *pdev);
+void dss_uninit_overlays(struct platform_device *pdev);
+void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
+int dss_ovl_simple_check(struct omap_overlay *ovl,
+ const struct omap_overlay_info *info);
+int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
+ const struct omap_video_timings *mgr_timings);
+bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
+ enum omap_color_mode mode);
+int dss_overlay_kobj_init(struct omap_overlay *ovl,
+ struct platform_device *pdev);
+void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
+
+/* DSS */
+int dss_init_platform_driver(void) __init;
+void dss_uninit_platform_driver(void);
+
+int dss_runtime_get(void);
+void dss_runtime_put(void);
+
+unsigned long dss_get_dispc_clk_rate(void);
+int dss_dpi_select_source(int port, enum omap_channel channel);
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
+enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
+void dss_dump_clocks(struct seq_file *s);
+
+/* DSS VIDEO PLL */
+struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
+ struct regulator *regulator);
+void dss_video_pll_uninit(struct dss_pll *pll);
+
+/* dss-of */
+struct device_node *dss_of_port_get_parent_device(struct device_node *port);
+u32 dss_of_port_get_port_number(struct device_node *port);
+
+#if defined(CONFIG_FB_OMAP2_DSS_DEBUGFS)
+void dss_debug_dump_clocks(struct seq_file *s);
+#endif
+
+void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable);
+void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
+ enum omap_channel channel);
+
+void dss_sdi_init(int datapairs);
+int dss_sdi_enable(void);
+void dss_sdi_disable(void);
+
+void dss_select_dsi_clk_source(int dsi_module,
+ enum omap_dss_clk_source clk_src);
+void dss_select_lcd_clk_source(enum omap_channel channel,
+ enum omap_dss_clk_source clk_src);
+enum omap_dss_clk_source dss_get_dispc_clk_source(void);
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
+enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
+
+void dss_set_venc_output(enum omap_dss_venc_type type);
+void dss_set_dac_pwrdn_bgz(bool enable);
+
+int dss_set_fck_rate(unsigned long rate);
+
+typedef bool (*dss_div_calc_func)(unsigned long fck, void *data);
+bool dss_div_calc(unsigned long pck, unsigned long fck_min,
+ dss_div_calc_func func, void *data);
+
+/* SDI */
+int sdi_init_platform_driver(void) __init;
+void sdi_uninit_platform_driver(void);
+
+#ifdef CONFIG_FB_OMAP2_DSS_SDI
+int sdi_init_port(struct platform_device *pdev, struct device_node *port);
+void sdi_uninit_port(struct device_node *port);
+#else
+static inline int sdi_init_port(struct platform_device *pdev,
+ struct device_node *port)
+{
+ return 0;
+}
+static inline void sdi_uninit_port(struct device_node *port)
+{
+}
+#endif
+
+/* DSI */
+
+#ifdef CONFIG_FB_OMAP2_DSS_DSI
+
+struct dentry;
+struct file_operations;
+
+int dsi_init_platform_driver(void) __init;
+void dsi_uninit_platform_driver(void);
+
+void dsi_dump_clocks(struct seq_file *s);
+
+void dsi_irq_handler(void);
+u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
+
+#else
+static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
+{
+ WARN(1, "%s: DSI not compiled in, returning pixel_size as 0\n",
+ __func__);
+ return 0;
+}
+#endif
+
+/* DPI */
+int dpi_init_platform_driver(void) __init;
+void dpi_uninit_platform_driver(void);
+
+#ifdef CONFIG_FB_OMAP2_DSS_DPI
+int dpi_init_port(struct platform_device *pdev, struct device_node *port);
+void dpi_uninit_port(struct device_node *port);
+#else
+static inline int dpi_init_port(struct platform_device *pdev,
+ struct device_node *port)
+{
+ return 0;
+}
+static inline void dpi_uninit_port(struct device_node *port)
+{
+}
+#endif
+
+/* DISPC */
+int dispc_init_platform_driver(void) __init;
+void dispc_uninit_platform_driver(void);
+void dispc_dump_clocks(struct seq_file *s);
+
+void dispc_enable_sidle(void);
+void dispc_disable_sidle(void);
+
+void dispc_lcd_enable_signal(bool enable);
+void dispc_pck_free_enable(bool enable);
+void dispc_enable_fifomerge(bool enable);
+void dispc_enable_gamma_table(bool enable);
+
+typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data);
+bool dispc_div_calc(unsigned long dispc,
+ unsigned long pck_min, unsigned long pck_max,
+ dispc_div_calc_func func, void *data);
+
+bool dispc_mgr_timings_ok(enum omap_channel channel,
+ const struct omap_video_timings *timings);
+int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
+ struct dispc_clock_info *cinfo);
+
+
+void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
+void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
+ u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
+ bool manual_update);
+
+void dispc_mgr_set_clock_div(enum omap_channel channel,
+ const struct dispc_clock_info *cinfo);
+int dispc_mgr_get_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo);
+void dispc_set_tv_pclk(unsigned long pclk);
+
+u32 dispc_wb_get_framedone_irq(void);
+bool dispc_wb_go_busy(void);
+void dispc_wb_go(void);
+void dispc_wb_enable(bool enable);
+bool dispc_wb_is_enabled(void);
+void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
+int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
+ bool mem_to_mem, const struct omap_video_timings *timings);
+
+/* VENC */
+int venc_init_platform_driver(void) __init;
+void venc_uninit_platform_driver(void);
+
+/* HDMI */
+int hdmi4_init_platform_driver(void) __init;
+void hdmi4_uninit_platform_driver(void);
+
+int hdmi5_init_platform_driver(void) __init;
+void hdmi5_uninit_platform_driver(void);
+
+/* RFBI */
+int rfbi_init_platform_driver(void) __init;
+void rfbi_uninit_platform_driver(void);
+
+
+#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
+static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
+{
+ int b;
+ for (b = 0; b < 32; ++b) {
+ if (irqstatus & (1 << b))
+ irq_arr[b]++;
+ }
+}
+#endif
+
+/* PLL */
+typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint,
+ unsigned long clkdco, void *data);
+typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc,
+ void *data);
+
+int dss_pll_register(struct dss_pll *pll);
+void dss_pll_unregister(struct dss_pll *pll);
+struct dss_pll *dss_pll_find(const char *name);
+int dss_pll_enable(struct dss_pll *pll);
+void dss_pll_disable(struct dss_pll *pll);
+int dss_pll_set_config(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+
+bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
+ unsigned long out_min, unsigned long out_max,
+ dss_hsdiv_calc_func func, void *data);
+bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dss_pll_calc_func func, void *data);
+int dss_pll_write_config_type_a(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+int dss_pll_write_config_type_b(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+int dss_pll_wait_reset_done(struct dss_pll *pll);
+
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c
new file mode 100644
index 000000000000..c886a2927f73
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c
@@ -0,0 +1,951 @@
+/*
+ * linux/drivers/video/omap2/dss/dss_features.c
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Archit Taneja <archit@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+/* Defines a generic omap register field */
+struct dss_reg_field {
+ u8 start, end;
+};
+
+struct dss_param_range {
+ int min, max;
+};
+
+struct omap_dss_features {
+ const struct dss_reg_field *reg_fields;
+ const int num_reg_fields;
+
+ const enum dss_feat_id *features;
+ const int num_features;
+
+ const int num_mgrs;
+ const int num_ovls;
+ const enum omap_display_type *supported_displays;
+ const enum omap_dss_output_id *supported_outputs;
+ const enum omap_color_mode *supported_color_modes;
+ const enum omap_overlay_caps *overlay_caps;
+ const char * const *clksrc_names;
+ const struct dss_param_range *dss_params;
+
+ const enum omap_dss_rotation_type supported_rotation_types;
+
+ const u32 buffer_size_unit;
+ const u32 burst_size_unit;
+};
+
+/* This struct is assigned to one of the below during initialization */
+static const struct omap_dss_features *omap_current_dss_features;
+
+static const struct dss_reg_field omap2_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 11, 0 },
+ [FEAT_REG_FIRVINC] = { 27, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 },
+ [FEAT_REG_FIFOSIZE] = { 8, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
+ [FEAT_REG_VERTICALACCU] = { 25, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
+};
+
+static const struct dss_reg_field omap3_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
+ [FEAT_REG_FIFOSIZE] = { 10, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
+ [FEAT_REG_VERTICALACCU] = { 25, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
+};
+
+static const struct dss_reg_field am43xx_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
+ [FEAT_REG_FIFOSIZE] = { 10, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
+ [FEAT_REG_VERTICALACCU] = { 25, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
+};
+
+static const struct dss_reg_field omap4_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
+ [FEAT_REG_FIFOSIZE] = { 15, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
+ [FEAT_REG_VERTICALACCU] = { 26, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
+};
+
+static const struct dss_reg_field omap5_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
+ [FEAT_REG_FIFOSIZE] = { 15, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
+ [FEAT_REG_VERTICALACCU] = { 26, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
+};
+
+static const enum omap_display_type omap2_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type omap3430_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type omap3630_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type am43xx_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
+};
+
+static const enum omap_display_type omap4_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+};
+
+static const enum omap_display_type omap5_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+};
+
+static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id am43xx_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
+};
+
+static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI2,
+};
+
+static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_HDMI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_LCD3 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI2,
+};
+
+static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+ OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
+ OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+ OMAP_DSS_COLOR_UYVY,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+ OMAP_DSS_COLOR_UYVY,
+};
+
+static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+ OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+ OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
+};
+
+static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+ OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
+ OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_VIDEO3 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_WB */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBX32,
+};
+
+static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+};
+
+static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
+};
+
+static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+};
+
+static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
+ OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
+
+ /* OMAP_DSS_VIDEO3 */
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
+};
+
+static const char * const omap2_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK1",
+};
+
+static const char * const omap3_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK",
+};
+
+static const char * const omap4_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
+};
+
+static const char * const omap5_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
+};
+
+static const struct dss_param_range omap2_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
+ [FEAT_PARAM_DSS_PCD] = { 2, 255 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 2 },
+ /*
+ * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
+ * scaler cannot scale a image with width more than 768.
+ */
+ [FEAT_PARAM_LINEWIDTH] = { 1, 768 },
+};
+
+static const struct dss_param_range omap3_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
+ [FEAT_PARAM_DSS_PCD] = { 1, 255 },
+ [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
+ [FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
+};
+
+static const struct dss_param_range am43xx_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
+ [FEAT_PARAM_DSS_PCD] = { 1, 255 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
+};
+
+static const struct dss_param_range omap4_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
+ [FEAT_PARAM_DSS_PCD] = { 1, 255 },
+ [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
+};
+
+static const struct dss_param_range omap5_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
+ [FEAT_PARAM_DSS_PCD] = { 1, 255 },
+ [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
+};
+
+static const enum dss_feat_id omap2_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+};
+
+static const enum dss_feat_id omap3430_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_DSI_REVERSE_TXCLKESC,
+ FEAT_VENC_REQUIRES_TV_DAC_CLK,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_OMAP3_DSI_FIFO_BUG,
+ FEAT_DPI_USES_VDDS_DSI,
+};
+
+static const enum dss_feat_id am35xx_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_DSI_REVERSE_TXCLKESC,
+ FEAT_VENC_REQUIRES_TV_DAC_CLK,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_OMAP3_DSI_FIFO_BUG,
+};
+
+static const enum dss_feat_id am43xx_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+};
+
+static const enum dss_feat_id omap3630_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_DSI_PLL_PWR_BUG,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_OMAP3_DSI_FIFO_BUG,
+ FEAT_DPI_USES_VDDS_DSI,
+};
+
+static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_GNQ,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+};
+
+static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_GNQ,
+ FEAT_HDMI_CTS_SWMODE,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+};
+
+static const enum dss_feat_id omap4_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_GNQ,
+ FEAT_HDMI_CTS_SWMODE,
+ FEAT_HDMI_AUDIO_USE_MCLK,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+};
+
+static const enum dss_feat_id omap5_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ FEAT_MGR_LCD3,
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_GNQ,
+ FEAT_HDMI_CTS_SWMODE,
+ FEAT_HDMI_AUDIO_USE_MCLK,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+ FEAT_DSI_PHY_DCC,
+ FEAT_MFLAG,
+};
+
+/* OMAP2 DSS Features */
+static const struct omap_dss_features omap2_dss_features = {
+ .reg_fields = omap2_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
+
+ .features = omap2_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap2_dss_feat_list),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap2_dss_supported_displays,
+ .supported_outputs = omap2_dss_supported_outputs,
+ .supported_color_modes = omap2_dss_supported_color_modes,
+ .overlay_caps = omap2_dss_overlay_caps,
+ .clksrc_names = omap2_dss_clk_source_names,
+ .dss_params = omap2_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+/* OMAP3 DSS Features */
+static const struct omap_dss_features omap3430_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .features = omap3430_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap3430_dss_feat_list),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3430_dss_supported_displays,
+ .supported_outputs = omap3430_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3430_dss_overlay_caps,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+/*
+ * AM35xx DSS Features. This is basically OMAP3 DSS Features without the
+ * vdds_dsi regulator.
+ */
+static const struct omap_dss_features am35xx_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .features = am35xx_dss_feat_list,
+ .num_features = ARRAY_SIZE(am35xx_dss_feat_list),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3430_dss_supported_displays,
+ .supported_outputs = omap3430_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3430_dss_overlay_caps,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+static const struct omap_dss_features am43xx_dss_features = {
+ .reg_fields = am43xx_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(am43xx_dss_reg_fields),
+
+ .features = am43xx_dss_feat_list,
+ .num_features = ARRAY_SIZE(am43xx_dss_feat_list),
+
+ .num_mgrs = 1,
+ .num_ovls = 3,
+ .supported_displays = am43xx_dss_supported_displays,
+ .supported_outputs = am43xx_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3430_dss_overlay_caps,
+ .clksrc_names = omap2_dss_clk_source_names,
+ .dss_params = am43xx_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+static const struct omap_dss_features omap3630_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .features = omap3630_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap3630_dss_feat_list),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3630_dss_supported_displays,
+ .supported_outputs = omap3630_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3630_dss_overlay_caps,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+/* OMAP4 DSS Features */
+/* For OMAP4430 ES 1.0 revision */
+static const struct omap_dss_features omap4430_es1_0_dss_features = {
+ .reg_fields = omap4_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
+
+ .features = omap4430_es1_0_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list),
+
+ .num_mgrs = 3,
+ .num_ovls = 4,
+ .supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap4_dss_clk_source_names,
+ .dss_params = omap4_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
+/* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */
+static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
+ .reg_fields = omap4_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
+
+ .features = omap4430_es2_0_1_2_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list),
+
+ .num_mgrs = 3,
+ .num_ovls = 4,
+ .supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap4_dss_clk_source_names,
+ .dss_params = omap4_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
+/* For all the other OMAP4 versions */
+static const struct omap_dss_features omap4_dss_features = {
+ .reg_fields = omap4_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
+
+ .features = omap4_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap4_dss_feat_list),
+
+ .num_mgrs = 3,
+ .num_ovls = 4,
+ .supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap4_dss_clk_source_names,
+ .dss_params = omap4_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
+/* OMAP5 DSS Features */
+static const struct omap_dss_features omap5_dss_features = {
+ .reg_fields = omap5_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
+
+ .features = omap5_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap5_dss_feat_list),
+
+ .num_mgrs = 4,
+ .num_ovls = 4,
+ .supported_displays = omap5_dss_supported_displays,
+ .supported_outputs = omap5_dss_supported_outputs,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap5_dss_clk_source_names,
+ .dss_params = omap5_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
+/* Functions returning values related to a DSS feature */
+int dss_feat_get_num_mgrs(void)
+{
+ return omap_current_dss_features->num_mgrs;
+}
+EXPORT_SYMBOL(dss_feat_get_num_mgrs);
+
+int dss_feat_get_num_ovls(void)
+{
+ return omap_current_dss_features->num_ovls;
+}
+EXPORT_SYMBOL(dss_feat_get_num_ovls);
+
+unsigned long dss_feat_get_param_min(enum dss_range_param param)
+{
+ return omap_current_dss_features->dss_params[param].min;
+}
+
+unsigned long dss_feat_get_param_max(enum dss_range_param param)
+{
+ return omap_current_dss_features->dss_params[param].max;
+}
+
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
+{
+ return omap_current_dss_features->supported_displays[channel];
+}
+
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
+{
+ return omap_current_dss_features->supported_outputs[channel];
+}
+
+enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
+{
+ return omap_current_dss_features->supported_color_modes[plane];
+}
+EXPORT_SYMBOL(dss_feat_get_supported_color_modes);
+
+enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane)
+{
+ return omap_current_dss_features->overlay_caps[plane];
+}
+
+bool dss_feat_color_mode_supported(enum omap_plane plane,
+ enum omap_color_mode color_mode)
+{
+ return omap_current_dss_features->supported_color_modes[plane] &
+ color_mode;
+}
+
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
+{
+ return omap_current_dss_features->clksrc_names[id];
+}
+
+u32 dss_feat_get_buffer_size_unit(void)
+{
+ return omap_current_dss_features->buffer_size_unit;
+}
+
+u32 dss_feat_get_burst_size_unit(void)
+{
+ return omap_current_dss_features->burst_size_unit;
+}
+
+/* DSS has_feature check */
+bool dss_has_feature(enum dss_feat_id id)
+{
+ int i;
+ const enum dss_feat_id *features = omap_current_dss_features->features;
+ const int num_features = omap_current_dss_features->num_features;
+
+ for (i = 0; i < num_features; i++) {
+ if (features[i] == id)
+ return true;
+ }
+
+ return false;
+}
+
+void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
+{
+ if (id >= omap_current_dss_features->num_reg_fields)
+ BUG();
+
+ *start = omap_current_dss_features->reg_fields[id].start;
+ *end = omap_current_dss_features->reg_fields[id].end;
+}
+
+bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type)
+{
+ return omap_current_dss_features->supported_rotation_types & rot_type;
+}
+
+void dss_features_init(enum omapdss_version version)
+{
+ switch (version) {
+ case OMAPDSS_VER_OMAP24xx:
+ omap_current_dss_features = &omap2_dss_features;
+ break;
+
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ omap_current_dss_features = &omap3430_dss_features;
+ break;
+
+ case OMAPDSS_VER_OMAP3630:
+ omap_current_dss_features = &omap3630_dss_features;
+ break;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ omap_current_dss_features = &omap4430_es1_0_dss_features;
+ break;
+
+ case OMAPDSS_VER_OMAP4430_ES2:
+ omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
+ break;
+
+ case OMAPDSS_VER_OMAP4:
+ omap_current_dss_features = &omap4_dss_features;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
+ omap_current_dss_features = &omap5_dss_features;
+ break;
+
+ case OMAPDSS_VER_AM35xx:
+ omap_current_dss_features = &am35xx_dss_features;
+ break;
+
+ case OMAPDSS_VER_AM43xx:
+ omap_current_dss_features = &am43xx_dss_features;
+ break;
+
+ default:
+ DSSWARN("Unsupported OMAP version");
+ break;
+ }
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h
new file mode 100644
index 000000000000..3d67d39f192f
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h
@@ -0,0 +1,108 @@
+/*
+ * linux/drivers/video/omap2/dss/dss_features.h
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Archit Taneja <archit@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DSS_FEATURES_H
+#define __OMAP2_DSS_FEATURES_H
+
+#define MAX_DSS_MANAGERS 4
+#define MAX_DSS_OVERLAYS 4
+#define MAX_DSS_LCD_MANAGERS 3
+#define MAX_NUM_DSI 2
+
+/* DSS has feature id */
+enum dss_feat_id {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_MGR_LCD2,
+ FEAT_MGR_LCD3,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ /* Independent core clk divider */
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ /* DSI-PLL power command 0x3 is not working */
+ FEAT_DSI_PLL_PWR_BUG,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_REVERSE_TXCLKESC,
+ FEAT_DSI_GNQ,
+ FEAT_DPI_USES_VDDS_DSI,
+ FEAT_HDMI_CTS_SWMODE,
+ FEAT_HDMI_AUDIO_USE_MCLK,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_VENC_REQUIRES_TV_DAC_CLK,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ /* An unknown HW bug causing the normal FIFO thresholds not to work */
+ FEAT_OMAP3_DSI_FIFO_BUG,
+ FEAT_BURST_2D,
+ FEAT_DSI_PHY_DCC,
+ FEAT_MFLAG,
+};
+
+/* DSS register field id */
+enum dss_feat_reg_field {
+ FEAT_REG_FIRHINC,
+ FEAT_REG_FIRVINC,
+ FEAT_REG_FIFOHIGHTHRESHOLD,
+ FEAT_REG_FIFOLOWTHRESHOLD,
+ FEAT_REG_FIFOSIZE,
+ FEAT_REG_HORIZONTALACCU,
+ FEAT_REG_VERTICALACCU,
+ FEAT_REG_DISPC_CLK_SWITCH,
+};
+
+enum dss_range_param {
+ FEAT_PARAM_DSS_FCK,
+ FEAT_PARAM_DSS_PCD,
+ FEAT_PARAM_DSIPLL_LPDIV,
+ FEAT_PARAM_DSI_FCK,
+ FEAT_PARAM_DOWNSCALE,
+ FEAT_PARAM_LINEWIDTH,
+};
+
+/* DSS Feature Functions */
+unsigned long dss_feat_get_param_min(enum dss_range_param param);
+unsigned long dss_feat_get_param_max(enum dss_range_param param);
+enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
+bool dss_feat_color_mode_supported(enum omap_plane plane,
+ enum omap_color_mode color_mode);
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
+
+u32 dss_feat_get_buffer_size_unit(void); /* in bytes */
+u32 dss_feat_get_burst_size_unit(void); /* in bytes */
+
+bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
+
+bool dss_has_feature(enum dss_feat_id id);
+void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
+void dss_features_init(enum omapdss_version version);
+
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
+
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h
new file mode 100644
index 000000000000..53616b02b613
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h
@@ -0,0 +1,370 @@
+/*
+ * HDMI driver definition for TI OMAP4 Processor.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HDMI_H
+#define _HDMI_H
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/hdmi.h>
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+/* HDMI Wrapper */
+
+#define HDMI_WP_REVISION 0x0
+#define HDMI_WP_SYSCONFIG 0x10
+#define HDMI_WP_IRQSTATUS_RAW 0x24
+#define HDMI_WP_IRQSTATUS 0x28
+#define HDMI_WP_IRQENABLE_SET 0x2C
+#define HDMI_WP_IRQENABLE_CLR 0x30
+#define HDMI_WP_IRQWAKEEN 0x34
+#define HDMI_WP_PWR_CTRL 0x40
+#define HDMI_WP_DEBOUNCE 0x44
+#define HDMI_WP_VIDEO_CFG 0x50
+#define HDMI_WP_VIDEO_SIZE 0x60
+#define HDMI_WP_VIDEO_TIMING_H 0x68
+#define HDMI_WP_VIDEO_TIMING_V 0x6C
+#define HDMI_WP_CLK 0x70
+#define HDMI_WP_AUDIO_CFG 0x80
+#define HDMI_WP_AUDIO_CFG2 0x84
+#define HDMI_WP_AUDIO_CTRL 0x88
+#define HDMI_WP_AUDIO_DATA 0x8C
+
+/* HDMI WP IRQ flags */
+#define HDMI_IRQ_CORE (1 << 0)
+#define HDMI_IRQ_OCP_TIMEOUT (1 << 4)
+#define HDMI_IRQ_AUDIO_FIFO_UNDERFLOW (1 << 8)
+#define HDMI_IRQ_AUDIO_FIFO_OVERFLOW (1 << 9)
+#define HDMI_IRQ_AUDIO_FIFO_SAMPLE_REQ (1 << 10)
+#define HDMI_IRQ_VIDEO_VSYNC (1 << 16)
+#define HDMI_IRQ_VIDEO_FRAME_DONE (1 << 17)
+#define HDMI_IRQ_PHY_LINE5V_ASSERT (1 << 24)
+#define HDMI_IRQ_LINK_CONNECT (1 << 25)
+#define HDMI_IRQ_LINK_DISCONNECT (1 << 26)
+#define HDMI_IRQ_PLL_LOCK (1 << 29)
+#define HDMI_IRQ_PLL_UNLOCK (1 << 30)
+#define HDMI_IRQ_PLL_RECAL (1 << 31)
+
+/* HDMI PLL */
+
+#define PLLCTRL_PLL_CONTROL 0x0
+#define PLLCTRL_PLL_STATUS 0x4
+#define PLLCTRL_PLL_GO 0x8
+#define PLLCTRL_CFG1 0xC
+#define PLLCTRL_CFG2 0x10
+#define PLLCTRL_CFG3 0x14
+#define PLLCTRL_SSC_CFG1 0x18
+#define PLLCTRL_SSC_CFG2 0x1C
+#define PLLCTRL_CFG4 0x20
+
+/* HDMI PHY */
+
+#define HDMI_TXPHY_TX_CTRL 0x0
+#define HDMI_TXPHY_DIGITAL_CTRL 0x4
+#define HDMI_TXPHY_POWER_CTRL 0x8
+#define HDMI_TXPHY_PAD_CFG_CTRL 0xC
+#define HDMI_TXPHY_BIST_CONTROL 0x1C
+
+enum hdmi_pll_pwr {
+ HDMI_PLLPWRCMD_ALLOFF = 0,
+ HDMI_PLLPWRCMD_PLLONLY = 1,
+ HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
+ HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
+};
+
+enum hdmi_phy_pwr {
+ HDMI_PHYPWRCMD_OFF = 0,
+ HDMI_PHYPWRCMD_LDOON = 1,
+ HDMI_PHYPWRCMD_TXON = 2
+};
+
+enum hdmi_core_hdmi_dvi {
+ HDMI_DVI = 0,
+ HDMI_HDMI = 1
+};
+
+enum hdmi_packing_mode {
+ HDMI_PACK_10b_RGB_YUV444 = 0,
+ HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
+ HDMI_PACK_20b_YUV422 = 2,
+ HDMI_PACK_ALREADYPACKED = 7
+};
+
+enum hdmi_stereo_channels {
+ HDMI_AUDIO_STEREO_NOCHANNELS = 0,
+ HDMI_AUDIO_STEREO_ONECHANNEL = 1,
+ HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
+ HDMI_AUDIO_STEREO_THREECHANNELS = 3,
+ HDMI_AUDIO_STEREO_FOURCHANNELS = 4
+};
+
+enum hdmi_audio_type {
+ HDMI_AUDIO_TYPE_LPCM = 0,
+ HDMI_AUDIO_TYPE_IEC = 1
+};
+
+enum hdmi_audio_justify {
+ HDMI_AUDIO_JUSTIFY_LEFT = 0,
+ HDMI_AUDIO_JUSTIFY_RIGHT = 1
+};
+
+enum hdmi_audio_sample_order {
+ HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
+ HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
+};
+
+enum hdmi_audio_samples_perword {
+ HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
+ HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
+};
+
+enum hdmi_audio_sample_size_omap {
+ HDMI_AUDIO_SAMPLE_16BITS = 0,
+ HDMI_AUDIO_SAMPLE_24BITS = 1
+};
+
+enum hdmi_audio_transf_mode {
+ HDMI_AUDIO_TRANSF_DMA = 0,
+ HDMI_AUDIO_TRANSF_IRQ = 1
+};
+
+enum hdmi_audio_blk_strt_end_sig {
+ HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
+ HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
+};
+
+enum hdmi_core_audio_layout {
+ HDMI_AUDIO_LAYOUT_2CH = 0,
+ HDMI_AUDIO_LAYOUT_8CH = 1,
+ HDMI_AUDIO_LAYOUT_6CH = 2
+};
+
+enum hdmi_core_cts_mode {
+ HDMI_AUDIO_CTS_MODE_HW = 0,
+ HDMI_AUDIO_CTS_MODE_SW = 1
+};
+
+enum hdmi_audio_mclk_mode {
+ HDMI_AUDIO_MCLK_128FS = 0,
+ HDMI_AUDIO_MCLK_256FS = 1,
+ HDMI_AUDIO_MCLK_384FS = 2,
+ HDMI_AUDIO_MCLK_512FS = 3,
+ HDMI_AUDIO_MCLK_768FS = 4,
+ HDMI_AUDIO_MCLK_1024FS = 5,
+ HDMI_AUDIO_MCLK_1152FS = 6,
+ HDMI_AUDIO_MCLK_192FS = 7
+};
+
+struct hdmi_video_format {
+ enum hdmi_packing_mode packing_mode;
+ u32 y_res; /* Line per panel */
+ u32 x_res; /* pixel per line */
+};
+
+struct hdmi_config {
+ struct omap_video_timings timings;
+ struct hdmi_avi_infoframe infoframe;
+ enum hdmi_core_hdmi_dvi hdmi_dvi_mode;
+};
+
+struct hdmi_audio_format {
+ enum hdmi_stereo_channels stereo_channels;
+ u8 active_chnnls_msk;
+ enum hdmi_audio_type type;
+ enum hdmi_audio_justify justification;
+ enum hdmi_audio_sample_order sample_order;
+ enum hdmi_audio_samples_perword samples_per_word;
+ enum hdmi_audio_sample_size_omap sample_size;
+ enum hdmi_audio_blk_strt_end_sig en_sig_blk_strt_end;
+};
+
+struct hdmi_audio_dma {
+ u8 transfer_size;
+ u8 block_size;
+ enum hdmi_audio_transf_mode mode;
+ u16 fifo_threshold;
+};
+
+struct hdmi_core_audio_i2s_config {
+ u8 in_length_bits;
+ u8 justification;
+ u8 sck_edge_mode;
+ u8 vbit;
+ u8 direction;
+ u8 shift;
+ u8 active_sds;
+};
+
+struct hdmi_core_audio_config {
+ struct hdmi_core_audio_i2s_config i2s_cfg;
+ struct snd_aes_iec958 *iec60958_cfg;
+ bool fs_override;
+ u32 n;
+ u32 cts;
+ u32 aud_par_busclk;
+ enum hdmi_core_audio_layout layout;
+ enum hdmi_core_cts_mode cts_mode;
+ bool use_mclk;
+ enum hdmi_audio_mclk_mode mclk_mode;
+ bool en_acr_pkt;
+ bool en_dsd_audio;
+ bool en_parallel_aud_input;
+ bool en_spdif;
+};
+
+struct hdmi_wp_data {
+ void __iomem *base;
+ phys_addr_t phys_base;
+};
+
+struct hdmi_pll_data {
+ struct dss_pll pll;
+
+ void __iomem *base;
+
+ struct hdmi_wp_data *wp;
+};
+
+struct hdmi_phy_data {
+ void __iomem *base;
+
+ u8 lane_function[4];
+ u8 lane_polarity[4];
+};
+
+struct hdmi_core_data {
+ void __iomem *base;
+};
+
+static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx,
+ u32 val)
+{
+ __raw_writel(val, base_addr + idx);
+}
+
+static inline u32 hdmi_read_reg(void __iomem *base_addr, const u32 idx)
+{
+ return __raw_readl(base_addr + idx);
+}
+
+#define REG_FLD_MOD(base, idx, val, start, end) \
+ hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\
+ val, start, end))
+#define REG_GET(base, idx, start, end) \
+ FLD_GET(hdmi_read_reg(base, idx), start, end)
+
+static inline int hdmi_wait_for_bit_change(void __iomem *base_addr,
+ const u32 idx, int b2, int b1, u32 val)
+{
+ u32 t = 0, v;
+ while (val != (v = REG_GET(base_addr, idx, b2, b1))) {
+ if (t++ > 10000)
+ return v;
+ udelay(1);
+ }
+ return v;
+}
+
+/* HDMI wrapper funcs */
+int hdmi_wp_video_start(struct hdmi_wp_data *wp);
+void hdmi_wp_video_stop(struct hdmi_wp_data *wp);
+void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s);
+u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp);
+void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus);
+void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask);
+void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask);
+int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val);
+int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val);
+void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
+ struct hdmi_video_format *video_fmt);
+void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
+ struct omap_video_timings *timings);
+void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
+ struct omap_video_timings *timings);
+void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
+ struct omap_video_timings *timings, struct hdmi_config *param);
+int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
+phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
+
+/* HDMI PLL funcs */
+void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
+void hdmi_pll_compute(struct hdmi_pll_data *pll,
+ unsigned long target_tmds, struct dss_pll_clock_info *pi);
+int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
+ struct hdmi_wp_data *wp);
+void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
+
+/* HDMI PHY funcs */
+int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
+ unsigned long lfbitclk);
+void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
+int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
+int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
+
+/* HDMI common funcs */
+int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
+ struct hdmi_phy_data *phy);
+
+/* Audio funcs */
+int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
+int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
+int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
+void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
+ struct hdmi_audio_format *aud_fmt);
+void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
+ struct hdmi_audio_dma *aud_dma);
+static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg)
+{
+ return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false;
+}
+
+/* HDMI DRV data */
+struct omap_hdmi {
+ struct mutex lock;
+ struct platform_device *pdev;
+
+ struct hdmi_wp_data wp;
+ struct hdmi_pll_data pll;
+ struct hdmi_phy_data phy;
+ struct hdmi_core_data core;
+
+ struct hdmi_config cfg;
+
+ struct regulator *vdda_reg;
+
+ bool core_enabled;
+
+ struct omap_dss_device output;
+
+ struct platform_device *audio_pdev;
+ void (*audio_abort_cb)(struct device *dev);
+ int wp_idlemode;
+
+ bool audio_configured;
+ struct omap_dss_audio audio_config;
+
+ /* This lock should be taken when booleans bellow are touched. */
+ spinlock_t audio_playing_lock;
+ bool audio_playing;
+ bool display_enabled;
+};
+
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
new file mode 100644
index 000000000000..7103c659a534
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
@@ -0,0 +1,839 @@
+/*
+ * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Yong Zhi
+ * Mythri pk <mythripk@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/component.h>
+#include <video/omapdss.h>
+#include <sound/omap-hdmi-audio.h>
+
+#include "hdmi4_core.h"
+#include "dss.h"
+#include "dss_features.h"
+#include "hdmi.h"
+
+static struct omap_hdmi hdmi;
+
+static int hdmi_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("hdmi_runtime_get\n");
+
+ r = pm_runtime_get_sync(&hdmi.pdev->dev);
+ WARN_ON(r < 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static void hdmi_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("hdmi_runtime_put\n");
+
+ r = pm_runtime_put_sync(&hdmi.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *data)
+{
+ struct hdmi_wp_data *wp = data;
+ u32 irqstatus;
+
+ irqstatus = hdmi_wp_get_irqstatus(wp);
+ hdmi_wp_set_irqstatus(wp, irqstatus);
+
+ if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
+ irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ /*
+ * If we get both connect and disconnect interrupts at the same
+ * time, turn off the PHY, clear interrupts, and restart, which
+ * raises connect interrupt if a cable is connected, or nothing
+ * if cable is not connected.
+ */
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
+
+ hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
+ HDMI_IRQ_LINK_DISCONNECT);
+
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
+ } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hdmi_init_regulator(void)
+{
+ int r;
+ struct regulator *reg;
+
+ if (hdmi.vdda_reg != NULL)
+ return 0;
+
+ reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
+
+ if (IS_ERR(reg)) {
+ if (PTR_ERR(reg) != -EPROBE_DEFER)
+ DSSERR("can't get VDDA regulator\n");
+ return PTR_ERR(reg);
+ }
+
+ if (regulator_can_change_voltage(reg)) {
+ r = regulator_set_voltage(reg, 1800000, 1800000);
+ if (r) {
+ devm_regulator_put(reg);
+ DSSWARN("can't set the regulator voltage\n");
+ return r;
+ }
+ }
+
+ hdmi.vdda_reg = reg;
+
+ return 0;
+}
+
+static int hdmi_power_on_core(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = regulator_enable(hdmi.vdda_reg);
+ if (r)
+ return r;
+
+ r = hdmi_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ /* Make selection of HDMI in DSS */
+ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+
+ hdmi.core_enabled = true;
+
+ return 0;
+
+err_runtime_get:
+ regulator_disable(hdmi.vdda_reg);
+
+ return r;
+}
+
+static void hdmi_power_off_core(struct omap_dss_device *dssdev)
+{
+ hdmi.core_enabled = false;
+
+ hdmi_runtime_put();
+ regulator_disable(hdmi.vdda_reg);
+}
+
+static int hdmi_power_on_full(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct omap_video_timings *p;
+ struct omap_overlay_manager *mgr = hdmi.output.manager;
+ struct hdmi_wp_data *wp = &hdmi.wp;
+ struct dss_pll_clock_info hdmi_cinfo = { 0 };
+
+ r = hdmi_power_on_core(dssdev);
+ if (r)
+ return r;
+
+ /* disable and clear irqs */
+ hdmi_wp_clear_irqenable(wp, 0xffffffff);
+ hdmi_wp_set_irqstatus(wp, 0xffffffff);
+
+ p = &hdmi.cfg.timings;
+
+ DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
+
+ hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
+
+ r = dss_pll_enable(&hdmi.pll.pll);
+ if (r) {
+ DSSERR("Failed to enable PLL\n");
+ goto err_pll_enable;
+ }
+
+ r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
+ if (r) {
+ DSSERR("Failed to configure PLL\n");
+ goto err_pll_cfg;
+ }
+
+ r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
+ hdmi_cinfo.clkout[0]);
+ if (r) {
+ DSSDBG("Failed to configure PHY\n");
+ goto err_phy_cfg;
+ }
+
+ r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ if (r)
+ goto err_phy_pwr;
+
+ hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
+
+ /* bypass TV gamma table */
+ dispc_enable_gamma_table(0);
+
+ /* tv size */
+ dss_mgr_set_timings(mgr, p);
+
+ r = hdmi_wp_video_start(&hdmi.wp);
+ if (r)
+ goto err_vid_enable;
+
+ r = dss_mgr_enable(mgr);
+ if (r)
+ goto err_mgr_enable;
+
+ hdmi_wp_set_irqenable(wp,
+ HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+
+ return 0;
+
+err_mgr_enable:
+ hdmi_wp_video_stop(&hdmi.wp);
+err_vid_enable:
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+err_phy_pwr:
+err_phy_cfg:
+err_pll_cfg:
+ dss_pll_disable(&hdmi.pll.pll);
+err_pll_enable:
+ hdmi_power_off_core(dssdev);
+ return -EIO;
+}
+
+static void hdmi_power_off_full(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = hdmi.output.manager;
+
+ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
+
+ dss_mgr_disable(mgr);
+
+ hdmi_wp_video_stop(&hdmi.wp);
+
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+
+ dss_pll_disable(&hdmi.pll.pll);
+
+ hdmi_power_off_core(dssdev);
+}
+
+static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ mutex_lock(&hdmi.lock);
+
+ hdmi.cfg.timings = *timings;
+
+ dispc_set_tv_pclk(timings->pixelclock);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = hdmi.cfg.timings;
+}
+
+static void hdmi_dump_regs(struct seq_file *s)
+{
+ mutex_lock(&hdmi.lock);
+
+ if (hdmi_runtime_get()) {
+ mutex_unlock(&hdmi.lock);
+ return;
+ }
+
+ hdmi_wp_dump(&hdmi.wp, s);
+ hdmi_pll_dump(&hdmi.pll, s);
+ hdmi_phy_dump(&hdmi.phy, s);
+ hdmi4_core_dump(&hdmi.core, s);
+
+ hdmi_runtime_put();
+ mutex_unlock(&hdmi.lock);
+}
+
+static int read_edid(u8 *buf, int len)
+{
+ int r;
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_runtime_get();
+ BUG_ON(r);
+
+ r = hdmi4_read_edid(&hdmi.core, buf, len);
+
+ hdmi_runtime_put();
+ mutex_unlock(&hdmi.lock);
+
+ return r;
+}
+
+static void hdmi_start_audio_stream(struct omap_hdmi *hd)
+{
+ hdmi_wp_audio_enable(&hd->wp, true);
+ hdmi4_audio_start(&hd->core, &hd->wp);
+}
+
+static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
+{
+ hdmi4_audio_stop(&hd->core, &hd->wp);
+ hdmi_wp_audio_enable(&hd->wp, false);
+}
+
+static int hdmi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+ unsigned long flags;
+ int r = 0;
+
+ DSSDBG("ENTER hdmi_display_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ if (out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err0;
+ }
+
+ r = hdmi_power_on_full(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
+
+ if (hdmi.audio_configured) {
+ r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
+ hdmi.cfg.timings.pixelclock);
+ if (r) {
+ DSSERR("Error restoring audio configuration: %d", r);
+ hdmi.audio_abort_cb(&hdmi.pdev->dev);
+ hdmi.audio_configured = false;
+ }
+ }
+
+ spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
+ if (hdmi.audio_configured && hdmi.audio_playing)
+ hdmi_start_audio_stream(&hdmi);
+ hdmi.display_enabled = true;
+ spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_display_disable(struct omap_dss_device *dssdev)
+{
+ unsigned long flags;
+
+ DSSDBG("Enter hdmi_display_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
+ hdmi_stop_audio_stream(&hdmi);
+ hdmi.display_enabled = false;
+ spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
+
+ hdmi_power_off_full(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_core_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ DSSDBG("ENTER omapdss_hdmi_core_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_power_on_core(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_core_disable(struct omap_dss_device *dssdev)
+{
+ DSSDBG("Enter omapdss_hdmi_core_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ hdmi_power_off_core(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = hdmi_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void hdmi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static int hdmi_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ bool need_enable;
+ int r;
+
+ need_enable = hdmi.core_enabled == false;
+
+ if (need_enable) {
+ r = hdmi_core_enable(dssdev);
+ if (r)
+ return r;
+ }
+
+ r = read_edid(edid, len);
+
+ if (need_enable)
+ hdmi_core_disable(dssdev);
+
+ return r;
+}
+
+static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
+ const struct hdmi_avi_infoframe *avi)
+{
+ hdmi.cfg.infoframe = *avi;
+ return 0;
+}
+
+static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
+ bool hdmi_mode)
+{
+ hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
+ return 0;
+}
+
+static const struct omapdss_hdmi_ops hdmi_ops = {
+ .connect = hdmi_connect,
+ .disconnect = hdmi_disconnect,
+
+ .enable = hdmi_display_enable,
+ .disable = hdmi_display_disable,
+
+ .check_timings = hdmi_display_check_timing,
+ .set_timings = hdmi_display_set_timing,
+ .get_timings = hdmi_display_get_timings,
+
+ .read_edid = hdmi_read_edid,
+ .set_infoframe = hdmi_set_infoframe,
+ .set_hdmi_mode = hdmi_set_hdmi_mode,
+};
+
+static void hdmi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_HDMI;
+ out->output_type = OMAP_DISPLAY_TYPE_HDMI;
+ out->name = "hdmi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+ out->ops.hdmi = &hdmi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void hdmi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ omapdss_unregister_output(out);
+}
+
+static int hdmi_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *ep;
+ int r;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return 0;
+
+ r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
+ if (r)
+ goto err;
+
+ of_node_put(ep);
+ return 0;
+
+err:
+ of_node_put(ep);
+ return r;
+}
+
+/* Audio callbacks */
+static int hdmi_audio_startup(struct device *dev,
+ void (*abort_cb)(struct device *dev))
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ hd->audio_abort_cb = abort_cb;
+
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static int hdmi_audio_shutdown(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ mutex_lock(&hd->lock);
+ hd->audio_abort_cb = NULL;
+ hd->audio_configured = false;
+ hd->audio_playing = false;
+ mutex_unlock(&hd->lock);
+
+ return 0;
+}
+
+static int hdmi_audio_start(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+
+ spin_lock_irqsave(&hd->audio_playing_lock, flags);
+
+ if (hd->display_enabled)
+ hdmi_start_audio_stream(hd);
+ hd->audio_playing = true;
+
+ spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
+ return 0;
+}
+
+static void hdmi_audio_stop(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+
+ spin_lock_irqsave(&hd->audio_playing_lock, flags);
+
+ if (hd->display_enabled)
+ hdmi_stop_audio_stream(hd);
+ hd->audio_playing = false;
+
+ spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
+}
+
+static int hdmi_audio_config(struct device *dev,
+ struct omap_dss_audio *dss_audio)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
+ hd->cfg.timings.pixelclock);
+ if (!ret) {
+ hd->audio_configured = true;
+ hd->audio_config = *dss_audio;
+ }
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
+ .audio_startup = hdmi_audio_startup,
+ .audio_shutdown = hdmi_audio_shutdown,
+ .audio_start = hdmi_audio_start,
+ .audio_stop = hdmi_audio_stop,
+ .audio_config = hdmi_audio_config,
+};
+
+static int hdmi_audio_register(struct device *dev)
+{
+ struct omap_hdmi_audio_pdata pdata = {
+ .dev = dev,
+ .dss_version = omapdss_get_version(),
+ .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
+ .ops = &hdmi_audio_ops,
+ };
+
+ hdmi.audio_pdev = platform_device_register_data(
+ dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
+ &pdata, sizeof(pdata));
+
+ if (IS_ERR(hdmi.audio_pdev))
+ return PTR_ERR(hdmi.audio_pdev);
+
+ return 0;
+}
+
+/* HDMI HW IP initialisation */
+static int hdmi4_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int r;
+ int irq;
+
+ hdmi.pdev = pdev;
+ dev_set_drvdata(&pdev->dev, &hdmi);
+
+ mutex_init(&hdmi.lock);
+ spin_lock_init(&hdmi.audio_playing_lock);
+
+ if (pdev->dev.of_node) {
+ r = hdmi_probe_of(pdev);
+ if (r)
+ return r;
+ }
+
+ r = hdmi_wp_init(pdev, &hdmi.wp);
+ if (r)
+ return r;
+
+ r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
+ if (r)
+ return r;
+
+ r = hdmi_phy_init(pdev, &hdmi.phy);
+ if (r)
+ goto err;
+
+ r = hdmi4_core_init(pdev, &hdmi.core);
+ if (r)
+ goto err;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ r = -ENODEV;
+ goto err;
+ }
+
+ r = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, hdmi_irq_handler,
+ IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
+ if (r) {
+ DSSERR("HDMI IRQ request failed\n");
+ goto err;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ hdmi_init_output(pdev);
+
+ r = hdmi_audio_register(&pdev->dev);
+ if (r) {
+ DSSERR("Registering HDMI audio failed\n");
+ hdmi_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
+
+ dss_debugfs_create_file("hdmi", hdmi_dump_regs);
+
+ return 0;
+err:
+ hdmi_pll_uninit(&hdmi.pll);
+ return r;
+}
+
+static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (hdmi.audio_pdev)
+ platform_device_unregister(hdmi.audio_pdev);
+
+ hdmi_uninit_output(pdev);
+
+ hdmi_pll_uninit(&hdmi.pll);
+
+ pm_runtime_disable(&pdev->dev);
+}
+
+static const struct component_ops hdmi4_component_ops = {
+ .bind = hdmi4_bind,
+ .unbind = hdmi4_unbind,
+};
+
+static int hdmi4_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &hdmi4_component_ops);
+}
+
+static int hdmi4_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &hdmi4_component_ops);
+ return 0;
+}
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+ dispc_runtime_put();
+
+ return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+ int r;
+
+ r = dispc_runtime_get();
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+ .runtime_suspend = hdmi_runtime_suspend,
+ .runtime_resume = hdmi_runtime_resume,
+};
+
+static const struct of_device_id hdmi_of_match[] = {
+ { .compatible = "ti,omap4-hdmi", },
+ {},
+};
+
+static struct platform_driver omapdss_hdmihw_driver = {
+ .probe = hdmi4_probe,
+ .remove = hdmi4_remove,
+ .driver = {
+ .name = "omapdss_hdmi",
+ .pm = &hdmi_pm_ops,
+ .of_match_table = hdmi_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init hdmi4_init_platform_driver(void)
+{
+ return platform_driver_register(&omapdss_hdmihw_driver);
+}
+
+void hdmi4_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omapdss_hdmihw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c
new file mode 100644
index 000000000000..fa72e735dad2
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c
@@ -0,0 +1,904 @@
+/*
+ * ti_hdmi_4xxx_ip.c
+ *
+ * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Yong Zhi
+ * Mythri pk <mythripk@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "HDMICORE"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <sound/asound.h>
+#include <sound/asoundef.h>
+
+#include "hdmi4_core.h"
+#include "dss_features.h"
+
+#define HDMI_CORE_AV 0x500
+
+static inline void __iomem *hdmi_av_base(struct hdmi_core_data *core)
+{
+ return core->base + HDMI_CORE_AV;
+}
+
+static int hdmi_core_ddc_init(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ /* Turn on CLK for DDC */
+ REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0);
+
+ /* IN_PROG */
+ if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) {
+ /* Abort transaction */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0);
+ /* IN_PROG */
+ if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+ 4, 4, 0) != 0) {
+ DSSERR("Timeout aborting DDC transaction\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* Clk SCL Devices */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0);
+
+ /* HDMI_CORE_DDC_STATUS_IN_PROG */
+ if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+ 4, 4, 0) != 0) {
+ DSSERR("Timeout starting SCL clock\n");
+ return -ETIMEDOUT;
+ }
+
+ /* Clear FIFO */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0);
+
+ /* HDMI_CORE_DDC_STATUS_IN_PROG */
+ if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+ 4, 4, 0) != 0) {
+ DSSERR("Timeout clearing DDC fifo\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
+ u8 *pedid, int ext)
+{
+ void __iomem *base = core->base;
+ u32 i;
+ char checksum;
+ u32 offset = 0;
+
+ /* HDMI_CORE_DDC_STATUS_IN_PROG */
+ if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
+ 4, 4, 0) != 0) {
+ DSSERR("Timeout waiting DDC to be ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (ext % 2 != 0)
+ offset = 0x80;
+
+ /* Load Segment Address Register */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0);
+
+ /* Load Slave Address Register */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
+
+ /* Load Offset Address Register */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+
+ /* Load Byte Count */
+ REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
+
+ /* Set DDC_CMD */
+ if (ext)
+ REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);
+ else
+ REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0);
+
+ /* HDMI_CORE_DDC_STATUS_BUS_LOW */
+ if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
+ DSSERR("I2C Bus Low?\n");
+ return -EIO;
+ }
+ /* HDMI_CORE_DDC_STATUS_NO_ACK */
+ if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
+ DSSERR("I2C No Ack\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < 0x80; ++i) {
+ int t;
+
+ /* IN_PROG */
+ if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 0) {
+ DSSERR("operation stopped when reading edid\n");
+ return -EIO;
+ }
+
+ t = 0;
+ /* FIFO_EMPTY */
+ while (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 1) {
+ if (t++ > 10000) {
+ DSSERR("timeout reading edid\n");
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
+ }
+
+ checksum = 0;
+ for (i = 0; i < 0x80; ++i)
+ checksum += pedid[i];
+
+ if (checksum != 0) {
+ DSSERR("E-EDID checksum failed!!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
+{
+ int r, l;
+
+ if (len < 128)
+ return -EINVAL;
+
+ r = hdmi_core_ddc_init(core);
+ if (r)
+ return r;
+
+ r = hdmi_core_ddc_edid(core, edid, 0);
+ if (r)
+ return r;
+
+ l = 128;
+
+ if (len >= 128 * 2 && edid[0x7e] > 0) {
+ r = hdmi_core_ddc_edid(core, edid + 0x80, 1);
+ if (r)
+ return r;
+ l += 128;
+ }
+
+ return l;
+}
+
+static void hdmi_core_init(struct hdmi_core_video_config *video_cfg)
+{
+ DSSDBG("Enter hdmi_core_init\n");
+
+ /* video core */
+ video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
+ video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
+ video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
+ video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
+ video_cfg->hdmi_dvi = HDMI_DVI;
+ video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
+}
+
+static void hdmi_core_powerdown_disable(struct hdmi_core_data *core)
+{
+ DSSDBG("Enter hdmi_core_powerdown_disable\n");
+ REG_FLD_MOD(core->base, HDMI_CORE_SYS_SYS_CTRL1, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_release(struct hdmi_core_data *core)
+{
+ DSSDBG("Enter hdmi_core_swreset_release\n");
+ REG_FLD_MOD(core->base, HDMI_CORE_SYS_SRST, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_assert(struct hdmi_core_data *core)
+{
+ DSSDBG("Enter hdmi_core_swreset_assert\n");
+ REG_FLD_MOD(core->base, HDMI_CORE_SYS_SRST, 0x1, 0, 0);
+}
+
+/* HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_core_data *core,
+ struct hdmi_core_video_config *cfg)
+{
+ u32 r = 0;
+ void __iomem *core_sys_base = core->base;
+ void __iomem *core_av_base = hdmi_av_base(core);
+
+ /* sys_ctrl1 default configuration not tunable */
+ r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1);
+ r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
+ r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
+ r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS, 2, 2);
+ r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE, 1, 1);
+ hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1, r);
+
+ REG_FLD_MOD(core_sys_base,
+ HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
+
+ /* Vid_Mode */
+ r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE);
+
+ /* dither truncation configuration */
+ if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
+ r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
+ r = FLD_MOD(r, 1, 5, 5);
+ } else {
+ r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
+ r = FLD_MOD(r, 0, 5, 5);
+ }
+ hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r);
+
+ /* HDMI_Ctrl */
+ r = hdmi_read_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL);
+ r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
+ r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
+ r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
+ hdmi_write_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL, r);
+
+ /* TMDS_CTRL */
+ REG_FLD_MOD(core_sys_base,
+ HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5);
+}
+
+static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core,
+ struct hdmi_avi_infoframe *frame)
+{
+ void __iomem *av_base = hdmi_av_base(core);
+ u8 data[HDMI_INFOFRAME_SIZE(AVI)];
+ int i;
+
+ hdmi_avi_infoframe_pack(frame, data, sizeof(data));
+
+ print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data,
+ HDMI_INFOFRAME_SIZE(AVI), false);
+
+ for (i = 0; i < sizeof(data); ++i) {
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_BASE + i * 4,
+ data[i]);
+ }
+}
+
+static void hdmi_core_av_packet_config(struct hdmi_core_data *core,
+ struct hdmi_core_packet_enable_repeat repeat_cfg)
+{
+ /* enable/repeat the infoframe */
+ hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL1,
+ (repeat_cfg.audio_pkt << 5) |
+ (repeat_cfg.audio_pkt_repeat << 4) |
+ (repeat_cfg.avi_infoframe << 1) |
+ (repeat_cfg.avi_infoframe_repeat));
+
+ /* enable/repeat the packet */
+ hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL2,
+ (repeat_cfg.gen_cntrl_pkt << 3) |
+ (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
+ (repeat_cfg.generic_pkt << 1) |
+ (repeat_cfg.generic_pkt_repeat));
+}
+
+void hdmi4_configure(struct hdmi_core_data *core,
+ struct hdmi_wp_data *wp, struct hdmi_config *cfg)
+{
+ /* HDMI */
+ struct omap_video_timings video_timing;
+ struct hdmi_video_format video_format;
+ /* HDMI core */
+ struct hdmi_core_video_config v_core_cfg;
+ struct hdmi_core_packet_enable_repeat repeat_cfg = { 0 };
+
+ hdmi_core_init(&v_core_cfg);
+
+ hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg);
+
+ hdmi_wp_video_config_timing(wp, &video_timing);
+
+ /* video config */
+ video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+ hdmi_wp_video_config_format(wp, &video_format);
+
+ hdmi_wp_video_config_interface(wp, &video_timing);
+
+ /*
+ * configure core video part
+ * set software reset in the core
+ */
+ hdmi_core_swreset_assert(core);
+
+ /* power down off */
+ hdmi_core_powerdown_disable(core);
+
+ v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
+ v_core_cfg.hdmi_dvi = cfg->hdmi_dvi_mode;
+
+ hdmi_core_video_config(core, &v_core_cfg);
+
+ /* release software reset in the core */
+ hdmi_core_swreset_release(core);
+
+ if (cfg->hdmi_dvi_mode == HDMI_HDMI) {
+ hdmi_core_write_avi_infoframe(core, &cfg->infoframe);
+
+ /* enable/repeat the infoframe */
+ repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
+ repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
+ /* wakeup */
+ repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
+ repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
+ }
+
+ hdmi_core_av_packet_config(core, repeat_cfg);
+}
+
+void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
+{
+ int i;
+
+#define CORE_REG(i, name) name(i)
+#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
+ hdmi_read_reg(core->base, r))
+#define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\
+ hdmi_read_reg(hdmi_av_base(core), r))
+#define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
+ (i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \
+ hdmi_read_reg(hdmi_av_base(core), CORE_REG(i, r)))
+
+ DUMPCORE(HDMI_CORE_SYS_VND_IDL);
+ DUMPCORE(HDMI_CORE_SYS_DEV_IDL);
+ DUMPCORE(HDMI_CORE_SYS_DEV_IDH);
+ DUMPCORE(HDMI_CORE_SYS_DEV_REV);
+ DUMPCORE(HDMI_CORE_SYS_SRST);
+ DUMPCORE(HDMI_CORE_SYS_SYS_CTRL1);
+ DUMPCORE(HDMI_CORE_SYS_SYS_STAT);
+ DUMPCORE(HDMI_CORE_SYS_SYS_CTRL3);
+ DUMPCORE(HDMI_CORE_SYS_DE_DLY);
+ DUMPCORE(HDMI_CORE_SYS_DE_CTRL);
+ DUMPCORE(HDMI_CORE_SYS_DE_TOP);
+ DUMPCORE(HDMI_CORE_SYS_DE_CNTL);
+ DUMPCORE(HDMI_CORE_SYS_DE_CNTH);
+ DUMPCORE(HDMI_CORE_SYS_DE_LINL);
+ DUMPCORE(HDMI_CORE_SYS_DE_LINH_1);
+ DUMPCORE(HDMI_CORE_SYS_HRES_L);
+ DUMPCORE(HDMI_CORE_SYS_HRES_H);
+ DUMPCORE(HDMI_CORE_SYS_VRES_L);
+ DUMPCORE(HDMI_CORE_SYS_VRES_H);
+ DUMPCORE(HDMI_CORE_SYS_IADJUST);
+ DUMPCORE(HDMI_CORE_SYS_POLDETECT);
+ DUMPCORE(HDMI_CORE_SYS_HWIDTH1);
+ DUMPCORE(HDMI_CORE_SYS_HWIDTH2);
+ DUMPCORE(HDMI_CORE_SYS_VWIDTH);
+ DUMPCORE(HDMI_CORE_SYS_VID_CTRL);
+ DUMPCORE(HDMI_CORE_SYS_VID_ACEN);
+ DUMPCORE(HDMI_CORE_SYS_VID_MODE);
+ DUMPCORE(HDMI_CORE_SYS_VID_BLANK1);
+ DUMPCORE(HDMI_CORE_SYS_VID_BLANK3);
+ DUMPCORE(HDMI_CORE_SYS_VID_BLANK1);
+ DUMPCORE(HDMI_CORE_SYS_DC_HEADER);
+ DUMPCORE(HDMI_CORE_SYS_VID_DITHER);
+ DUMPCORE(HDMI_CORE_SYS_RGB2XVYCC_CT);
+ DUMPCORE(HDMI_CORE_SYS_R2Y_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_R2Y_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_G2Y_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_G2Y_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_B2Y_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_B2Y_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_R2CB_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_R2CB_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_G2CB_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_G2CB_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_B2CB_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_B2CB_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_R2CR_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_R2CR_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_G2CR_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_G2CR_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_B2CR_COEFF_LOW);
+ DUMPCORE(HDMI_CORE_SYS_B2CR_COEFF_UP);
+ DUMPCORE(HDMI_CORE_SYS_RGB_OFFSET_LOW);
+ DUMPCORE(HDMI_CORE_SYS_RGB_OFFSET_UP);
+ DUMPCORE(HDMI_CORE_SYS_Y_OFFSET_LOW);
+ DUMPCORE(HDMI_CORE_SYS_Y_OFFSET_UP);
+ DUMPCORE(HDMI_CORE_SYS_CBCR_OFFSET_LOW);
+ DUMPCORE(HDMI_CORE_SYS_CBCR_OFFSET_UP);
+ DUMPCORE(HDMI_CORE_SYS_INTR_STATE);
+ DUMPCORE(HDMI_CORE_SYS_INTR1);
+ DUMPCORE(HDMI_CORE_SYS_INTR2);
+ DUMPCORE(HDMI_CORE_SYS_INTR3);
+ DUMPCORE(HDMI_CORE_SYS_INTR4);
+ DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK1);
+ DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK2);
+ DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK3);
+ DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK4);
+ DUMPCORE(HDMI_CORE_SYS_INTR_CTRL);
+ DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL);
+
+ DUMPCORE(HDMI_CORE_DDC_ADDR);
+ DUMPCORE(HDMI_CORE_DDC_SEGM);
+ DUMPCORE(HDMI_CORE_DDC_OFFSET);
+ DUMPCORE(HDMI_CORE_DDC_COUNT1);
+ DUMPCORE(HDMI_CORE_DDC_COUNT2);
+ DUMPCORE(HDMI_CORE_DDC_STATUS);
+ DUMPCORE(HDMI_CORE_DDC_CMD);
+ DUMPCORE(HDMI_CORE_DDC_DATA);
+
+ DUMPCOREAV(HDMI_CORE_AV_ACR_CTRL);
+ DUMPCOREAV(HDMI_CORE_AV_FREQ_SVAL);
+ DUMPCOREAV(HDMI_CORE_AV_N_SVAL1);
+ DUMPCOREAV(HDMI_CORE_AV_N_SVAL2);
+ DUMPCOREAV(HDMI_CORE_AV_N_SVAL3);
+ DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL1);
+ DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL2);
+ DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL3);
+ DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL1);
+ DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL2);
+ DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL3);
+ DUMPCOREAV(HDMI_CORE_AV_AUD_MODE);
+ DUMPCOREAV(HDMI_CORE_AV_SPDIF_CTRL);
+ DUMPCOREAV(HDMI_CORE_AV_HW_SPDIF_FS);
+ DUMPCOREAV(HDMI_CORE_AV_SWAP_I2S);
+ DUMPCOREAV(HDMI_CORE_AV_SPDIF_ERTH);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_IN_MAP);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_IN_CTRL);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_CHST0);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_CHST1);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_CHST2);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_CHST4);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_CHST5);
+ DUMPCOREAV(HDMI_CORE_AV_ASRC);
+ DUMPCOREAV(HDMI_CORE_AV_I2S_IN_LEN);
+ DUMPCOREAV(HDMI_CORE_AV_HDMI_CTRL);
+ DUMPCOREAV(HDMI_CORE_AV_AUDO_TXSTAT);
+ DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_1);
+ DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_2);
+ DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_3);
+ DUMPCOREAV(HDMI_CORE_AV_TEST_TXCTRL);
+ DUMPCOREAV(HDMI_CORE_AV_DPD);
+ DUMPCOREAV(HDMI_CORE_AV_PB_CTRL1);
+ DUMPCOREAV(HDMI_CORE_AV_PB_CTRL2);
+ DUMPCOREAV(HDMI_CORE_AV_AVI_TYPE);
+ DUMPCOREAV(HDMI_CORE_AV_AVI_VERS);
+ DUMPCOREAV(HDMI_CORE_AV_AVI_LEN);
+ DUMPCOREAV(HDMI_CORE_AV_AVI_CHSUM);
+
+ for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++)
+ DUMPCOREAV2(i, HDMI_CORE_AV_AVI_DBYTE);
+
+ DUMPCOREAV(HDMI_CORE_AV_SPD_TYPE);
+ DUMPCOREAV(HDMI_CORE_AV_SPD_VERS);
+ DUMPCOREAV(HDMI_CORE_AV_SPD_LEN);
+ DUMPCOREAV(HDMI_CORE_AV_SPD_CHSUM);
+
+ for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++)
+ DUMPCOREAV2(i, HDMI_CORE_AV_SPD_DBYTE);
+
+ DUMPCOREAV(HDMI_CORE_AV_AUDIO_TYPE);
+ DUMPCOREAV(HDMI_CORE_AV_AUDIO_VERS);
+ DUMPCOREAV(HDMI_CORE_AV_AUDIO_LEN);
+ DUMPCOREAV(HDMI_CORE_AV_AUDIO_CHSUM);
+
+ for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++)
+ DUMPCOREAV2(i, HDMI_CORE_AV_AUD_DBYTE);
+
+ DUMPCOREAV(HDMI_CORE_AV_MPEG_TYPE);
+ DUMPCOREAV(HDMI_CORE_AV_MPEG_VERS);
+ DUMPCOREAV(HDMI_CORE_AV_MPEG_LEN);
+ DUMPCOREAV(HDMI_CORE_AV_MPEG_CHSUM);
+
+ for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++)
+ DUMPCOREAV2(i, HDMI_CORE_AV_MPEG_DBYTE);
+
+ for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++)
+ DUMPCOREAV2(i, HDMI_CORE_AV_GEN_DBYTE);
+
+ DUMPCOREAV(HDMI_CORE_AV_CP_BYTE1);
+
+ for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++)
+ DUMPCOREAV2(i, HDMI_CORE_AV_GEN2_DBYTE);
+
+ DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
+}
+
+static void hdmi_core_audio_config(struct hdmi_core_data *core,
+ struct hdmi_core_audio_config *cfg)
+{
+ u32 r;
+ void __iomem *av_base = hdmi_av_base(core);
+
+ /*
+ * Parameters for generation of Audio Clock Recovery packets
+ */
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+
+ if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+ REG_FLD_MOD(av_base,
+ HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+ REG_FLD_MOD(av_base,
+ HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+ } else {
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
+ cfg->aud_par_busclk, 7, 0);
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+ (cfg->aud_par_busclk >> 8), 7, 0);
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+ (cfg->aud_par_busclk >> 16), 7, 0);
+ }
+
+ /* Set ACR clock divisor */
+ REG_FLD_MOD(av_base,
+ HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+ r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL);
+ /*
+ * Use TMDS clock for ACR packets. For devices that use
+ * the MCLK, this is the first part of the MCLK initialization.
+ */
+ r = FLD_MOD(r, 0, 2, 2);
+
+ r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+ r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r);
+
+ /* For devices using MCLK, this completes its initialization. */
+ if (cfg->use_mclk)
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_ACR_CTRL, 1, 2, 2);
+
+ /* Override of SPDIF sample frequency with value in I2S_CHST4 */
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
+ cfg->fs_override, 1, 1);
+
+ /*
+ * Set IEC-60958-3 channel status word. It is passed to the IP
+ * just as it is received. The user of the driver is responsible
+ * for its contents.
+ */
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0,
+ cfg->iec60958_cfg->status[0]);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1,
+ cfg->iec60958_cfg->status[1]);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2,
+ cfg->iec60958_cfg->status[2]);
+ /* yes, this is correct: status[3] goes to CHST4 register */
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4,
+ cfg->iec60958_cfg->status[3]);
+ /* yes, this is correct: status[4] goes to CHST5 register */
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5,
+ cfg->iec60958_cfg->status[4]);
+
+ /* set I2S parameters */
+ r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL);
+ r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+ r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+ r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
+ r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+ r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN,
+ cfg->i2s_cfg.in_length_bits, 3, 0);
+
+ /* Audio channels and mode parameters */
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+ r = hdmi_read_reg(av_base, HDMI_CORE_AV_AUD_MODE);
+ r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
+ r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
+ r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
+ r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
+
+ /* Audio channel mappings */
+ /* TODO: Make channel mapping dynamic. For now, map channels
+ * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as
+ * HDMI speaker order is different. See CEA-861 Section 6.6.2.
+ */
+ hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78);
+ REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5);
+}
+
+static void hdmi_core_audio_infoframe_cfg(struct hdmi_core_data *core,
+ struct snd_cea_861_aud_if *info_aud)
+{
+ u8 sum = 0, checksum = 0;
+ void __iomem *av_base = hdmi_av_base(core);
+
+ /*
+ * Set audio info frame type, version and length as
+ * described in HDMI 1.4a Section 8.2.2 specification.
+ * Checksum calculation is defined in Section 5.3.5.
+ */
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_VERS, 0x01);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+ sum += 0x84 + 0x001 + 0x00a;
+
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0),
+ info_aud->db1_ct_cc);
+ sum += info_aud->db1_ct_cc;
+
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1),
+ info_aud->db2_sf_ss);
+ sum += info_aud->db2_sf_ss;
+
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3);
+ sum += info_aud->db3;
+
+ /*
+ * The OMAP HDMI IP requires to use the 8-channel channel code when
+ * transmitting more than two channels.
+ */
+ if (info_aud->db4_ca != 0x00)
+ info_aud->db4_ca = 0x13;
+
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca);
+ sum += info_aud->db4_ca;
+
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4),
+ info_aud->db5_dminh_lsv);
+ sum += info_aud->db5_dminh_lsv;
+
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+ hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+ checksum = 0x100 - sum;
+ hdmi_write_reg(av_base,
+ HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+ /*
+ * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+ * is available.
+ */
+}
+
+int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct omap_dss_audio *audio, u32 pclk)
+{
+ struct hdmi_audio_format audio_format;
+ struct hdmi_audio_dma audio_dma;
+ struct hdmi_core_audio_config acore;
+ int err, n, cts, channel_count;
+ unsigned int fs_nr;
+ bool word_length_16b = false;
+
+ if (!audio || !audio->iec || !audio->cea || !core)
+ return -EINVAL;
+
+ acore.iec60958_cfg = audio->iec;
+ /*
+ * In the IEC-60958 status word, check if the audio sample word length
+ * is 16-bit as several optimizations can be performed in such case.
+ */
+ if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24))
+ if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)
+ word_length_16b = true;
+
+ /* I2S configuration. See Phillips' specification */
+ if (word_length_16b)
+ acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+ else
+ acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+ /*
+ * The I2S input word length is twice the lenght given in the IEC-60958
+ * status word. If the word size is greater than
+ * 20 bits, increment by one.
+ */
+ acore.i2s_cfg.in_length_bits = audio->iec->status[4]
+ & IEC958_AES4_CON_WORDLEN;
+ if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)
+ acore.i2s_cfg.in_length_bits++;
+ acore.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
+ acore.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
+ acore.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
+ acore.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
+
+ /* convert sample frequency to a number */
+ switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
+ case IEC958_AES3_CON_FS_32000:
+ fs_nr = 32000;
+ break;
+ case IEC958_AES3_CON_FS_44100:
+ fs_nr = 44100;
+ break;
+ case IEC958_AES3_CON_FS_48000:
+ fs_nr = 48000;
+ break;
+ case IEC958_AES3_CON_FS_88200:
+ fs_nr = 88200;
+ break;
+ case IEC958_AES3_CON_FS_96000:
+ fs_nr = 96000;
+ break;
+ case IEC958_AES3_CON_FS_176400:
+ fs_nr = 176400;
+ break;
+ case IEC958_AES3_CON_FS_192000:
+ fs_nr = 192000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hdmi_compute_acr(pclk, fs_nr, &n, &cts);
+
+ /* Audio clock regeneration settings */
+ acore.n = n;
+ acore.cts = cts;
+ if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
+ acore.aud_par_busclk = 0;
+ acore.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
+ acore.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
+ } else {
+ acore.aud_par_busclk = (((128 * 31) - 1) << 8);
+ acore.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
+ acore.use_mclk = true;
+ }
+
+ if (acore.use_mclk)
+ acore.mclk_mode = HDMI_AUDIO_MCLK_128FS;
+
+ /* Audio channels settings */
+ channel_count = (audio->cea->db1_ct_cc &
+ CEA861_AUDIO_INFOFRAME_DB1CC) + 1;
+
+ switch (channel_count) {
+ case 2:
+ audio_format.active_chnnls_msk = 0x03;
+ break;
+ case 3:
+ audio_format.active_chnnls_msk = 0x07;
+ break;
+ case 4:
+ audio_format.active_chnnls_msk = 0x0f;
+ break;
+ case 5:
+ audio_format.active_chnnls_msk = 0x1f;
+ break;
+ case 6:
+ audio_format.active_chnnls_msk = 0x3f;
+ break;
+ case 7:
+ audio_format.active_chnnls_msk = 0x7f;
+ break;
+ case 8:
+ audio_format.active_chnnls_msk = 0xff;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * the HDMI IP needs to enable four stereo channels when transmitting
+ * more than 2 audio channels. Similarly, the channel count in the
+ * Audio InfoFrame has to match the sample_present bits (some channels
+ * are padded with zeroes)
+ */
+ if (channel_count == 2) {
+ audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
+ acore.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
+ acore.layout = HDMI_AUDIO_LAYOUT_2CH;
+ } else {
+ audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS;
+ acore.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN |
+ HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN |
+ HDMI_AUDIO_I2S_SD3_EN;
+ acore.layout = HDMI_AUDIO_LAYOUT_8CH;
+ audio->cea->db1_ct_cc = 7;
+ }
+
+ acore.en_spdif = false;
+ /* use sample frequency from channel status word */
+ acore.fs_override = true;
+ /* enable ACR packets */
+ acore.en_acr_pkt = true;
+ /* disable direct streaming digital audio */
+ acore.en_dsd_audio = false;
+ /* use parallel audio interface */
+ acore.en_parallel_aud_input = true;
+
+ /* DMA settings */
+ if (word_length_16b)
+ audio_dma.transfer_size = 0x10;
+ else
+ audio_dma.transfer_size = 0x20;
+ audio_dma.block_size = 0xC0;
+ audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+ audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+ /* audio FIFO format settings */
+ if (word_length_16b) {
+ audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+ audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+ audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+ } else {
+ audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
+ audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
+ audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+ }
+ audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+ audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+ /* disable start/stop signals of IEC 60958 blocks */
+ audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
+
+ /* configure DMA and audio FIFO format*/
+ hdmi_wp_audio_config_dma(wp, &audio_dma);
+ hdmi_wp_audio_config_format(wp, &audio_format);
+
+ /* configure the core*/
+ hdmi_core_audio_config(core, &acore);
+
+ /* configure CEA 861 audio infoframe*/
+ hdmi_core_audio_infoframe_cfg(core, audio->cea);
+
+ return 0;
+}
+
+int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
+{
+ REG_FLD_MOD(hdmi_av_base(core),
+ HDMI_CORE_AV_AUD_MODE, true, 0, 0);
+
+ hdmi_wp_audio_core_req_enable(wp, true);
+
+ return 0;
+}
+
+void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
+{
+ REG_FLD_MOD(hdmi_av_base(core),
+ HDMI_CORE_AV_AUD_MODE, false, 0, 0);
+
+ hdmi_wp_audio_core_req_enable(wp, false);
+}
+
+int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
+{
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+ if (!res) {
+ DSSERR("can't get CORE mem resource\n");
+ return -EINVAL;
+ }
+
+ core->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(core->base)) {
+ DSSERR("can't ioremap CORE\n");
+ return PTR_ERR(core->base);
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h
new file mode 100644
index 000000000000..a069f96ec6f6
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h
@@ -0,0 +1,273 @@
+/*
+ * HDMI header definition for OMAP4 HDMI core IP
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HDMI4_CORE_H_
+#define _HDMI4_CORE_H_
+
+#include "hdmi.h"
+
+/* OMAP4 HDMI IP Core System */
+
+#define HDMI_CORE_SYS_VND_IDL 0x0
+#define HDMI_CORE_SYS_DEV_IDL 0x8
+#define HDMI_CORE_SYS_DEV_IDH 0xC
+#define HDMI_CORE_SYS_DEV_REV 0x10
+#define HDMI_CORE_SYS_SRST 0x14
+#define HDMI_CORE_SYS_SYS_CTRL1 0x20
+#define HDMI_CORE_SYS_SYS_STAT 0x24
+#define HDMI_CORE_SYS_SYS_CTRL3 0x28
+#define HDMI_CORE_SYS_DCTL 0x34
+#define HDMI_CORE_SYS_DE_DLY 0xC8
+#define HDMI_CORE_SYS_DE_CTRL 0xCC
+#define HDMI_CORE_SYS_DE_TOP 0xD0
+#define HDMI_CORE_SYS_DE_CNTL 0xD8
+#define HDMI_CORE_SYS_DE_CNTH 0xDC
+#define HDMI_CORE_SYS_DE_LINL 0xE0
+#define HDMI_CORE_SYS_DE_LINH_1 0xE4
+#define HDMI_CORE_SYS_HRES_L 0xE8
+#define HDMI_CORE_SYS_HRES_H 0xEC
+#define HDMI_CORE_SYS_VRES_L 0xF0
+#define HDMI_CORE_SYS_VRES_H 0xF4
+#define HDMI_CORE_SYS_IADJUST 0xF8
+#define HDMI_CORE_SYS_POLDETECT 0xFC
+#define HDMI_CORE_SYS_HWIDTH1 0x110
+#define HDMI_CORE_SYS_HWIDTH2 0x114
+#define HDMI_CORE_SYS_VWIDTH 0x11C
+#define HDMI_CORE_SYS_VID_CTRL 0x120
+#define HDMI_CORE_SYS_VID_ACEN 0x124
+#define HDMI_CORE_SYS_VID_MODE 0x128
+#define HDMI_CORE_SYS_VID_BLANK1 0x12C
+#define HDMI_CORE_SYS_VID_BLANK2 0x130
+#define HDMI_CORE_SYS_VID_BLANK3 0x134
+#define HDMI_CORE_SYS_DC_HEADER 0x138
+#define HDMI_CORE_SYS_VID_DITHER 0x13C
+#define HDMI_CORE_SYS_RGB2XVYCC_CT 0x140
+#define HDMI_CORE_SYS_R2Y_COEFF_LOW 0x144
+#define HDMI_CORE_SYS_R2Y_COEFF_UP 0x148
+#define HDMI_CORE_SYS_G2Y_COEFF_LOW 0x14C
+#define HDMI_CORE_SYS_G2Y_COEFF_UP 0x150
+#define HDMI_CORE_SYS_B2Y_COEFF_LOW 0x154
+#define HDMI_CORE_SYS_B2Y_COEFF_UP 0x158
+#define HDMI_CORE_SYS_R2CB_COEFF_LOW 0x15C
+#define HDMI_CORE_SYS_R2CB_COEFF_UP 0x160
+#define HDMI_CORE_SYS_G2CB_COEFF_LOW 0x164
+#define HDMI_CORE_SYS_G2CB_COEFF_UP 0x168
+#define HDMI_CORE_SYS_B2CB_COEFF_LOW 0x16C
+#define HDMI_CORE_SYS_B2CB_COEFF_UP 0x170
+#define HDMI_CORE_SYS_R2CR_COEFF_LOW 0x174
+#define HDMI_CORE_SYS_R2CR_COEFF_UP 0x178
+#define HDMI_CORE_SYS_G2CR_COEFF_LOW 0x17C
+#define HDMI_CORE_SYS_G2CR_COEFF_UP 0x180
+#define HDMI_CORE_SYS_B2CR_COEFF_LOW 0x184
+#define HDMI_CORE_SYS_B2CR_COEFF_UP 0x188
+#define HDMI_CORE_SYS_RGB_OFFSET_LOW 0x18C
+#define HDMI_CORE_SYS_RGB_OFFSET_UP 0x190
+#define HDMI_CORE_SYS_Y_OFFSET_LOW 0x194
+#define HDMI_CORE_SYS_Y_OFFSET_UP 0x198
+#define HDMI_CORE_SYS_CBCR_OFFSET_LOW 0x19C
+#define HDMI_CORE_SYS_CBCR_OFFSET_UP 0x1A0
+#define HDMI_CORE_SYS_INTR_STATE 0x1C0
+#define HDMI_CORE_SYS_INTR1 0x1C4
+#define HDMI_CORE_SYS_INTR2 0x1C8
+#define HDMI_CORE_SYS_INTR3 0x1CC
+#define HDMI_CORE_SYS_INTR4 0x1D0
+#define HDMI_CORE_SYS_INTR_UNMASK1 0x1D4
+#define HDMI_CORE_SYS_INTR_UNMASK2 0x1D8
+#define HDMI_CORE_SYS_INTR_UNMASK3 0x1DC
+#define HDMI_CORE_SYS_INTR_UNMASK4 0x1E0
+#define HDMI_CORE_SYS_INTR_CTRL 0x1E4
+#define HDMI_CORE_SYS_TMDS_CTRL 0x208
+
+/* value definitions for HDMI_CORE_SYS_SYS_CTRL1 fields */
+#define HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC 0x1
+#define HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC 0x1
+#define HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS 0x1
+#define HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE 0x1
+
+/* HDMI DDC E-DID */
+#define HDMI_CORE_DDC_ADDR 0x3B4
+#define HDMI_CORE_DDC_SEGM 0x3B8
+#define HDMI_CORE_DDC_OFFSET 0x3BC
+#define HDMI_CORE_DDC_COUNT1 0x3C0
+#define HDMI_CORE_DDC_COUNT2 0x3C4
+#define HDMI_CORE_DDC_STATUS 0x3C8
+#define HDMI_CORE_DDC_CMD 0x3CC
+#define HDMI_CORE_DDC_DATA 0x3D0
+
+/* HDMI IP Core Audio Video */
+
+#define HDMI_CORE_AV_ACR_CTRL 0x4
+#define HDMI_CORE_AV_FREQ_SVAL 0x8
+#define HDMI_CORE_AV_N_SVAL1 0xC
+#define HDMI_CORE_AV_N_SVAL2 0x10
+#define HDMI_CORE_AV_N_SVAL3 0x14
+#define HDMI_CORE_AV_CTS_SVAL1 0x18
+#define HDMI_CORE_AV_CTS_SVAL2 0x1C
+#define HDMI_CORE_AV_CTS_SVAL3 0x20
+#define HDMI_CORE_AV_CTS_HVAL1 0x24
+#define HDMI_CORE_AV_CTS_HVAL2 0x28
+#define HDMI_CORE_AV_CTS_HVAL3 0x2C
+#define HDMI_CORE_AV_AUD_MODE 0x50
+#define HDMI_CORE_AV_SPDIF_CTRL 0x54
+#define HDMI_CORE_AV_HW_SPDIF_FS 0x60
+#define HDMI_CORE_AV_SWAP_I2S 0x64
+#define HDMI_CORE_AV_SPDIF_ERTH 0x6C
+#define HDMI_CORE_AV_I2S_IN_MAP 0x70
+#define HDMI_CORE_AV_I2S_IN_CTRL 0x74
+#define HDMI_CORE_AV_I2S_CHST0 0x78
+#define HDMI_CORE_AV_I2S_CHST1 0x7C
+#define HDMI_CORE_AV_I2S_CHST2 0x80
+#define HDMI_CORE_AV_I2S_CHST4 0x84
+#define HDMI_CORE_AV_I2S_CHST5 0x88
+#define HDMI_CORE_AV_ASRC 0x8C
+#define HDMI_CORE_AV_I2S_IN_LEN 0x90
+#define HDMI_CORE_AV_HDMI_CTRL 0xBC
+#define HDMI_CORE_AV_AUDO_TXSTAT 0xC0
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 0xCC
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 0xD0
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 0xD4
+#define HDMI_CORE_AV_TEST_TXCTRL 0xF0
+#define HDMI_CORE_AV_DPD 0xF4
+#define HDMI_CORE_AV_PB_CTRL1 0xF8
+#define HDMI_CORE_AV_PB_CTRL2 0xFC
+#define HDMI_CORE_AV_AVI_BASE 0x100
+#define HDMI_CORE_AV_AVI_TYPE 0x100
+#define HDMI_CORE_AV_AVI_VERS 0x104
+#define HDMI_CORE_AV_AVI_LEN 0x108
+#define HDMI_CORE_AV_AVI_CHSUM 0x10C
+#define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110)
+#define HDMI_CORE_AV_SPD_TYPE 0x180
+#define HDMI_CORE_AV_SPD_VERS 0x184
+#define HDMI_CORE_AV_SPD_LEN 0x188
+#define HDMI_CORE_AV_SPD_CHSUM 0x18C
+#define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190)
+#define HDMI_CORE_AV_AUDIO_TYPE 0x200
+#define HDMI_CORE_AV_AUDIO_VERS 0x204
+#define HDMI_CORE_AV_AUDIO_LEN 0x208
+#define HDMI_CORE_AV_AUDIO_CHSUM 0x20C
+#define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210)
+#define HDMI_CORE_AV_MPEG_TYPE 0x280
+#define HDMI_CORE_AV_MPEG_VERS 0x284
+#define HDMI_CORE_AV_MPEG_LEN 0x288
+#define HDMI_CORE_AV_MPEG_CHSUM 0x28C
+#define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290)
+#define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300)
+#define HDMI_CORE_AV_CP_BYTE1 0x37C
+#define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380)
+#define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC
+
+#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4
+#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4
+#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4
+#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4
+
+#define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15
+#define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10
+#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27
+#define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31
+#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31
+
+enum hdmi_core_inputbus_width {
+ HDMI_INPUT_8BIT = 0,
+ HDMI_INPUT_10BIT = 1,
+ HDMI_INPUT_12BIT = 2
+};
+
+enum hdmi_core_dither_trunc {
+ HDMI_OUTPUTTRUNCATION_8BIT = 0,
+ HDMI_OUTPUTTRUNCATION_10BIT = 1,
+ HDMI_OUTPUTTRUNCATION_12BIT = 2,
+ HDMI_OUTPUTDITHER_8BIT = 3,
+ HDMI_OUTPUTDITHER_10BIT = 4,
+ HDMI_OUTPUTDITHER_12BIT = 5
+};
+
+enum hdmi_core_deepcolor_ed {
+ HDMI_DEEPCOLORPACKECTDISABLE = 0,
+ HDMI_DEEPCOLORPACKECTENABLE = 1
+};
+
+enum hdmi_core_packet_mode {
+ HDMI_PACKETMODERESERVEDVALUE = 0,
+ HDMI_PACKETMODE24BITPERPIXEL = 4,
+ HDMI_PACKETMODE30BITPERPIXEL = 5,
+ HDMI_PACKETMODE36BITPERPIXEL = 6,
+ HDMI_PACKETMODE48BITPERPIXEL = 7
+};
+
+enum hdmi_core_tclkselclkmult {
+ HDMI_FPLL05IDCK = 0,
+ HDMI_FPLL10IDCK = 1,
+ HDMI_FPLL20IDCK = 2,
+ HDMI_FPLL40IDCK = 3
+};
+
+enum hdmi_core_packet_ctrl {
+ HDMI_PACKETENABLE = 1,
+ HDMI_PACKETDISABLE = 0,
+ HDMI_PACKETREPEATON = 1,
+ HDMI_PACKETREPEATOFF = 0
+};
+
+enum hdmi_audio_i2s_config {
+ HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
+ HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
+ HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
+ HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
+ HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
+ HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
+ HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
+ HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
+ HDMI_AUDIO_I2S_SD0_EN = 1,
+ HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
+ HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
+ HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
+};
+
+struct hdmi_core_video_config {
+ enum hdmi_core_inputbus_width ip_bus_width;
+ enum hdmi_core_dither_trunc op_dither_truc;
+ enum hdmi_core_deepcolor_ed deep_color_pkt;
+ enum hdmi_core_packet_mode pkt_mode;
+ enum hdmi_core_hdmi_dvi hdmi_dvi;
+ enum hdmi_core_tclkselclkmult tclk_sel_clkmult;
+};
+
+struct hdmi_core_packet_enable_repeat {
+ u32 audio_pkt;
+ u32 audio_pkt_repeat;
+ u32 avi_infoframe;
+ u32 avi_infoframe_repeat;
+ u32 gen_cntrl_pkt;
+ u32 gen_cntrl_pkt_repeat;
+ u32 generic_pkt;
+ u32 generic_pkt_repeat;
+};
+
+int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
+void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct hdmi_config *cfg);
+void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
+int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
+
+int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
+void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
+int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct omap_dss_audio *audio, u32 pclk);
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
new file mode 100644
index 000000000000..a955a2c4c061
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
@@ -0,0 +1,876 @@
+/*
+ * HDMI driver for OMAP5
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ *
+ * Authors:
+ * Yong Zhi
+ * Mythri pk
+ * Archit Taneja <archit@ti.com>
+ * Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/component.h>
+#include <video/omapdss.h>
+#include <sound/omap-hdmi-audio.h>
+
+#include "hdmi5_core.h"
+#include "dss.h"
+#include "dss_features.h"
+
+static struct omap_hdmi hdmi;
+
+static int hdmi_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("hdmi_runtime_get\n");
+
+ r = pm_runtime_get_sync(&hdmi.pdev->dev);
+ WARN_ON(r < 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static void hdmi_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("hdmi_runtime_put\n");
+
+ r = pm_runtime_put_sync(&hdmi.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *data)
+{
+ struct hdmi_wp_data *wp = data;
+ u32 irqstatus;
+
+ irqstatus = hdmi_wp_get_irqstatus(wp);
+ hdmi_wp_set_irqstatus(wp, irqstatus);
+
+ if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
+ irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ u32 v;
+ /*
+ * If we get both connect and disconnect interrupts at the same
+ * time, turn off the PHY, clear interrupts, and restart, which
+ * raises connect interrupt if a cable is connected, or nothing
+ * if cable is not connected.
+ */
+
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
+
+ /*
+ * We always get bogus CONNECT & DISCONNECT interrupts when
+ * setting the PHY to LDOON. To ignore those, we force the RXDET
+ * line to 0 until the PHY power state has been changed.
+ */
+ v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
+ v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
+ v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
+ hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
+
+ hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
+ HDMI_IRQ_LINK_DISCONNECT);
+
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+
+ REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
+
+ } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
+ } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hdmi_init_regulator(void)
+{
+ int r;
+ struct regulator *reg;
+
+ if (hdmi.vdda_reg != NULL)
+ return 0;
+
+ reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
+ if (IS_ERR(reg)) {
+ DSSERR("can't get VDDA regulator\n");
+ return PTR_ERR(reg);
+ }
+
+ if (regulator_can_change_voltage(reg)) {
+ r = regulator_set_voltage(reg, 1800000, 1800000);
+ if (r) {
+ devm_regulator_put(reg);
+ DSSWARN("can't set the regulator voltage\n");
+ return r;
+ }
+ }
+
+ hdmi.vdda_reg = reg;
+
+ return 0;
+}
+
+static int hdmi_power_on_core(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = regulator_enable(hdmi.vdda_reg);
+ if (r)
+ return r;
+
+ r = hdmi_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ /* Make selection of HDMI in DSS */
+ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+
+ hdmi.core_enabled = true;
+
+ return 0;
+
+err_runtime_get:
+ regulator_disable(hdmi.vdda_reg);
+
+ return r;
+}
+
+static void hdmi_power_off_core(struct omap_dss_device *dssdev)
+{
+ hdmi.core_enabled = false;
+
+ hdmi_runtime_put();
+ regulator_disable(hdmi.vdda_reg);
+}
+
+static int hdmi_power_on_full(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct omap_video_timings *p;
+ struct omap_overlay_manager *mgr = hdmi.output.manager;
+ struct dss_pll_clock_info hdmi_cinfo = { 0 };
+
+ r = hdmi_power_on_core(dssdev);
+ if (r)
+ return r;
+
+ p = &hdmi.cfg.timings;
+
+ DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
+
+ hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
+
+ /* disable and clear irqs */
+ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
+ hdmi_wp_set_irqstatus(&hdmi.wp,
+ hdmi_wp_get_irqstatus(&hdmi.wp));
+
+ r = dss_pll_enable(&hdmi.pll.pll);
+ if (r) {
+ DSSERR("Failed to enable PLL\n");
+ goto err_pll_enable;
+ }
+
+ r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
+ if (r) {
+ DSSERR("Failed to configure PLL\n");
+ goto err_pll_cfg;
+ }
+
+ r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
+ hdmi_cinfo.clkout[0]);
+ if (r) {
+ DSSDBG("Failed to start PHY\n");
+ goto err_phy_cfg;
+ }
+
+ r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
+ if (r)
+ goto err_phy_pwr;
+
+ hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
+
+ /* bypass TV gamma table */
+ dispc_enable_gamma_table(0);
+
+ /* tv size */
+ dss_mgr_set_timings(mgr, p);
+
+ r = hdmi_wp_video_start(&hdmi.wp);
+ if (r)
+ goto err_vid_enable;
+
+ r = dss_mgr_enable(mgr);
+ if (r)
+ goto err_mgr_enable;
+
+ hdmi_wp_set_irqenable(&hdmi.wp,
+ HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+
+ return 0;
+
+err_mgr_enable:
+ hdmi_wp_video_stop(&hdmi.wp);
+err_vid_enable:
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+err_phy_pwr:
+err_phy_cfg:
+err_pll_cfg:
+ dss_pll_disable(&hdmi.pll.pll);
+err_pll_enable:
+ hdmi_power_off_core(dssdev);
+ return -EIO;
+}
+
+static void hdmi_power_off_full(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = hdmi.output.manager;
+
+ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
+
+ dss_mgr_disable(mgr);
+
+ hdmi_wp_video_stop(&hdmi.wp);
+
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+
+ dss_pll_disable(&hdmi.pll.pll);
+
+ hdmi_power_off_core(dssdev);
+}
+
+static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ /* TODO: proper interlace support */
+ if (timings->interlace)
+ return -EINVAL;
+
+ if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ mutex_lock(&hdmi.lock);
+
+ hdmi.cfg.timings = *timings;
+
+ dispc_set_tv_pclk(timings->pixelclock);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = hdmi.cfg.timings;
+}
+
+static void hdmi_dump_regs(struct seq_file *s)
+{
+ mutex_lock(&hdmi.lock);
+
+ if (hdmi_runtime_get()) {
+ mutex_unlock(&hdmi.lock);
+ return;
+ }
+
+ hdmi_wp_dump(&hdmi.wp, s);
+ hdmi_pll_dump(&hdmi.pll, s);
+ hdmi_phy_dump(&hdmi.phy, s);
+ hdmi5_core_dump(&hdmi.core, s);
+
+ hdmi_runtime_put();
+ mutex_unlock(&hdmi.lock);
+}
+
+static int read_edid(u8 *buf, int len)
+{
+ int r;
+ int idlemode;
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_runtime_get();
+ BUG_ON(r);
+
+ idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
+ /* No-idle mode */
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+
+ r = hdmi5_read_edid(&hdmi.core, buf, len);
+
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
+
+ hdmi_runtime_put();
+ mutex_unlock(&hdmi.lock);
+
+ return r;
+}
+
+static void hdmi_start_audio_stream(struct omap_hdmi *hd)
+{
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+ hdmi_wp_audio_enable(&hd->wp, true);
+ hdmi_wp_audio_core_req_enable(&hd->wp, true);
+}
+
+static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
+{
+ hdmi_wp_audio_core_req_enable(&hd->wp, false);
+ hdmi_wp_audio_enable(&hd->wp, false);
+ REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
+}
+
+static int hdmi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+ unsigned long flags;
+ int r = 0;
+
+ DSSDBG("ENTER hdmi_display_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ if (out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err0;
+ }
+
+ r = hdmi_power_on_full(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
+
+ if (hdmi.audio_configured) {
+ r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
+ hdmi.cfg.timings.pixelclock);
+ if (r) {
+ DSSERR("Error restoring audio configuration: %d", r);
+ hdmi.audio_abort_cb(&hdmi.pdev->dev);
+ hdmi.audio_configured = false;
+ }
+ }
+
+ spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
+ if (hdmi.audio_configured && hdmi.audio_playing)
+ hdmi_start_audio_stream(&hdmi);
+ hdmi.display_enabled = true;
+ spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_display_disable(struct omap_dss_device *dssdev)
+{
+ unsigned long flags;
+
+ DSSDBG("Enter hdmi_display_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
+ hdmi_stop_audio_stream(&hdmi);
+ hdmi.display_enabled = false;
+ spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
+
+ hdmi_power_off_full(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_core_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ DSSDBG("ENTER omapdss_hdmi_core_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_power_on_core(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_core_disable(struct omap_dss_device *dssdev)
+{
+ DSSDBG("Enter omapdss_hdmi_core_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ hdmi_power_off_core(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = hdmi_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void hdmi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static int hdmi_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ bool need_enable;
+ int r;
+
+ need_enable = hdmi.core_enabled == false;
+
+ if (need_enable) {
+ r = hdmi_core_enable(dssdev);
+ if (r)
+ return r;
+ }
+
+ r = read_edid(edid, len);
+
+ if (need_enable)
+ hdmi_core_disable(dssdev);
+
+ return r;
+}
+
+static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
+ const struct hdmi_avi_infoframe *avi)
+{
+ hdmi.cfg.infoframe = *avi;
+ return 0;
+}
+
+static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
+ bool hdmi_mode)
+{
+ hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
+ return 0;
+}
+
+static const struct omapdss_hdmi_ops hdmi_ops = {
+ .connect = hdmi_connect,
+ .disconnect = hdmi_disconnect,
+
+ .enable = hdmi_display_enable,
+ .disable = hdmi_display_disable,
+
+ .check_timings = hdmi_display_check_timing,
+ .set_timings = hdmi_display_set_timing,
+ .get_timings = hdmi_display_get_timings,
+
+ .read_edid = hdmi_read_edid,
+ .set_infoframe = hdmi_set_infoframe,
+ .set_hdmi_mode = hdmi_set_hdmi_mode,
+};
+
+static void hdmi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_HDMI;
+ out->output_type = OMAP_DISPLAY_TYPE_HDMI;
+ out->name = "hdmi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+ out->ops.hdmi = &hdmi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void hdmi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ omapdss_unregister_output(out);
+}
+
+static int hdmi_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *ep;
+ int r;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return 0;
+
+ r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
+ if (r)
+ goto err;
+
+ of_node_put(ep);
+ return 0;
+
+err:
+ of_node_put(ep);
+ return r;
+}
+
+/* Audio callbacks */
+static int hdmi_audio_startup(struct device *dev,
+ void (*abort_cb)(struct device *dev))
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ hd->audio_abort_cb = abort_cb;
+
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static int hdmi_audio_shutdown(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ mutex_lock(&hd->lock);
+ hd->audio_abort_cb = NULL;
+ hd->audio_configured = false;
+ hd->audio_playing = false;
+ mutex_unlock(&hd->lock);
+
+ return 0;
+}
+
+static int hdmi_audio_start(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+
+ spin_lock_irqsave(&hd->audio_playing_lock, flags);
+
+ if (hd->display_enabled)
+ hdmi_start_audio_stream(hd);
+ hd->audio_playing = true;
+
+ spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
+ return 0;
+}
+
+static void hdmi_audio_stop(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+
+ spin_lock_irqsave(&hd->audio_playing_lock, flags);
+
+ if (hd->display_enabled)
+ hdmi_stop_audio_stream(hd);
+ hd->audio_playing = false;
+
+ spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
+}
+
+static int hdmi_audio_config(struct device *dev,
+ struct omap_dss_audio *dss_audio)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
+ hd->cfg.timings.pixelclock);
+
+ if (!ret) {
+ hd->audio_configured = true;
+ hd->audio_config = *dss_audio;
+ }
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
+ .audio_startup = hdmi_audio_startup,
+ .audio_shutdown = hdmi_audio_shutdown,
+ .audio_start = hdmi_audio_start,
+ .audio_stop = hdmi_audio_stop,
+ .audio_config = hdmi_audio_config,
+};
+
+static int hdmi_audio_register(struct device *dev)
+{
+ struct omap_hdmi_audio_pdata pdata = {
+ .dev = dev,
+ .dss_version = omapdss_get_version(),
+ .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
+ .ops = &hdmi_audio_ops,
+ };
+
+ hdmi.audio_pdev = platform_device_register_data(
+ dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
+ &pdata, sizeof(pdata));
+
+ if (IS_ERR(hdmi.audio_pdev))
+ return PTR_ERR(hdmi.audio_pdev);
+
+ hdmi_runtime_get();
+ hdmi.wp_idlemode =
+ REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
+ hdmi_runtime_put();
+
+ return 0;
+}
+
+/* HDMI HW IP initialisation */
+static int hdmi5_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int r;
+ int irq;
+
+ hdmi.pdev = pdev;
+ dev_set_drvdata(&pdev->dev, &hdmi);
+
+ mutex_init(&hdmi.lock);
+ spin_lock_init(&hdmi.audio_playing_lock);
+
+ if (pdev->dev.of_node) {
+ r = hdmi_probe_of(pdev);
+ if (r)
+ return r;
+ }
+
+ r = hdmi_wp_init(pdev, &hdmi.wp);
+ if (r)
+ return r;
+
+ r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
+ if (r)
+ return r;
+
+ r = hdmi_phy_init(pdev, &hdmi.phy);
+ if (r)
+ goto err;
+
+ r = hdmi5_core_init(pdev, &hdmi.core);
+ if (r)
+ goto err;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ r = -ENODEV;
+ goto err;
+ }
+
+ r = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, hdmi_irq_handler,
+ IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
+ if (r) {
+ DSSERR("HDMI IRQ request failed\n");
+ goto err;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ hdmi_init_output(pdev);
+
+ r = hdmi_audio_register(&pdev->dev);
+ if (r) {
+ DSSERR("Registering HDMI audio failed %d\n", r);
+ hdmi_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
+
+ dss_debugfs_create_file("hdmi", hdmi_dump_regs);
+
+ return 0;
+err:
+ hdmi_pll_uninit(&hdmi.pll);
+ return r;
+}
+
+static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (hdmi.audio_pdev)
+ platform_device_unregister(hdmi.audio_pdev);
+
+ hdmi_uninit_output(pdev);
+
+ hdmi_pll_uninit(&hdmi.pll);
+
+ pm_runtime_disable(&pdev->dev);
+}
+
+static const struct component_ops hdmi5_component_ops = {
+ .bind = hdmi5_bind,
+ .unbind = hdmi5_unbind,
+};
+
+static int hdmi5_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &hdmi5_component_ops);
+}
+
+static int hdmi5_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &hdmi5_component_ops);
+ return 0;
+}
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+ dispc_runtime_put();
+
+ return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+ int r;
+
+ r = dispc_runtime_get();
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+ .runtime_suspend = hdmi_runtime_suspend,
+ .runtime_resume = hdmi_runtime_resume,
+};
+
+static const struct of_device_id hdmi_of_match[] = {
+ { .compatible = "ti,omap5-hdmi", },
+ { .compatible = "ti,dra7-hdmi", },
+ {},
+};
+
+static struct platform_driver omapdss_hdmihw_driver = {
+ .probe = hdmi5_probe,
+ .remove = hdmi5_remove,
+ .driver = {
+ .name = "omapdss_hdmi5",
+ .pm = &hdmi_pm_ops,
+ .of_match_table = hdmi_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init hdmi5_init_platform_driver(void)
+{
+ return platform_driver_register(&omapdss_hdmihw_driver);
+}
+
+void hdmi5_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omapdss_hdmihw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c
new file mode 100644
index 000000000000..8ea531d2652c
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c
@@ -0,0 +1,916 @@
+/*
+ * OMAP5 HDMI CORE IP driver library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ *
+ * Authors:
+ * Yong Zhi
+ * Mythri pk
+ * Archit Taneja <archit@ti.com>
+ * Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <drm/drm_edid.h>
+#include <sound/asound.h>
+#include <sound/asoundef.h>
+
+#include "hdmi5_core.h"
+
+/* only 24 bit color depth used for now */
+static const struct csc_table csc_table_deepcolor[] = {
+ /* HDMI_DEEP_COLOR_24BIT */
+ [0] = { 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32, },
+ /* HDMI_DEEP_COLOR_30BIT */
+ [1] = { 7015, 0, 0, 128, 0, 7015, 0, 128, 0, 0, 7015, 128, },
+ /* HDMI_DEEP_COLOR_36BIT */
+ [2] = { 7010, 0, 0, 512, 0, 7010, 0, 512, 0, 0, 7010, 512, },
+ /* FULL RANGE */
+ [3] = { 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0, },
+};
+
+static void hdmi_core_ddc_init(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+ const unsigned long long iclk = 266000000; /* DSS L3 ICLK */
+ const unsigned ss_scl_high = 4000; /* ns */
+ const unsigned ss_scl_low = 4700; /* ns */
+ const unsigned fs_scl_high = 600; /* ns */
+ const unsigned fs_scl_low = 1300; /* ns */
+ const unsigned sda_hold = 1000; /* ns */
+ const unsigned sfr_div = 10;
+ unsigned long long sfr;
+ unsigned v;
+
+ sfr = iclk / sfr_div; /* SFR_DIV */
+ sfr /= 1000; /* SFR clock in kHz */
+
+ /* Reset */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SOFTRSTZ, 0, 0, 0);
+ if (hdmi_wait_for_bit_change(base, HDMI_CORE_I2CM_SOFTRSTZ,
+ 0, 0, 1) != 1)
+ DSSERR("HDMI I2CM reset failed\n");
+
+ /* Standard (0) or Fast (1) Mode */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_DIV, 0, 3, 3);
+
+ /* Standard Mode SCL High counter */
+ v = DIV_ROUND_UP_ULL(ss_scl_high * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* Standard Mode SCL Low counter */
+ v = DIV_ROUND_UP_ULL(ss_scl_low * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* Fast Mode SCL High Counter */
+ v = DIV_ROUND_UP_ULL(fs_scl_high * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* Fast Mode SCL Low Counter */
+ v = DIV_ROUND_UP_ULL(fs_scl_low * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* SDA Hold Time */
+ v = DIV_ROUND_UP_ULL(sda_hold * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SDA_HOLD_ADDR, v & 0xff, 7, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SLAVE, 0x50, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGADDR, 0x30, 6, 0);
+
+ /* NACK_POL to high */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 7, 7);
+
+ /* NACK_MASK to unmasked */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 6, 6);
+
+ /* ARBITRATION_POL to high */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 3, 3);
+
+ /* ARBITRATION_MASK to unmasked */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 2, 2);
+
+ /* DONE_POL to high */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 3, 3);
+
+ /* DONE_MASK to unmasked */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2);
+}
+
+static void hdmi_core_ddc_uninit(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ /* Mask I2C interrupts */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
+}
+
+static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)
+{
+ void __iomem *base = core->base;
+ u8 cur_addr;
+ char checksum = 0;
+ const int retries = 1000;
+ u8 seg_ptr = ext / 2;
+ u8 edidbase = ((ext % 2) * 0x80);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0);
+
+ /*
+ * TODO: We use polling here, although we probably should use proper
+ * interrupts.
+ */
+ for (cur_addr = 0; cur_addr < 128; ++cur_addr) {
+ int i;
+
+ /* clear ERROR and DONE */
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_ADDRESS,
+ edidbase + cur_addr, 7, 0);
+
+ if (seg_ptr)
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 1, 1);
+ else
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 0, 0);
+
+ for (i = 0; i < retries; ++i) {
+ u32 stat;
+
+ stat = REG_GET(base, HDMI_CORE_IH_I2CM_STAT0, 1, 0);
+
+ /* I2CM_ERROR */
+ if (stat & 1) {
+ DSSERR("HDMI I2C Master Error\n");
+ return -EIO;
+ }
+
+ /* I2CM_DONE */
+ if (stat & (1 << 1))
+ break;
+
+ usleep_range(250, 1000);
+ }
+
+ if (i == retries) {
+ DSSERR("HDMI I2C timeout reading EDID\n");
+ return -EIO;
+ }
+
+ pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0);
+ checksum += pedid[cur_addr];
+ }
+
+ return 0;
+
+}
+
+int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
+{
+ int r, n, i;
+ int max_ext_blocks = (len / 128) - 1;
+
+ if (len < 128)
+ return -EINVAL;
+
+ hdmi_core_ddc_init(core);
+
+ r = hdmi_core_ddc_edid(core, edid, 0);
+ if (r)
+ goto out;
+
+ n = edid[0x7e];
+
+ if (n > max_ext_blocks)
+ n = max_ext_blocks;
+
+ for (i = 1; i <= n; i++) {
+ r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i);
+ if (r)
+ goto out;
+ }
+
+out:
+ hdmi_core_ddc_uninit(core);
+
+ return r ? r : len;
+}
+
+void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)
+{
+
+#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
+ hdmi_read_reg(core->base, r))
+
+ DUMPCORE(HDMI_CORE_FC_INVIDCONF);
+ DUMPCORE(HDMI_CORE_FC_INHACTIV0);
+ DUMPCORE(HDMI_CORE_FC_INHACTIV1);
+ DUMPCORE(HDMI_CORE_FC_INHBLANK0);
+ DUMPCORE(HDMI_CORE_FC_INHBLANK1);
+ DUMPCORE(HDMI_CORE_FC_INVACTIV0);
+ DUMPCORE(HDMI_CORE_FC_INVACTIV1);
+ DUMPCORE(HDMI_CORE_FC_INVBLANK);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY0);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY1);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH0);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH1);
+ DUMPCORE(HDMI_CORE_FC_VSYNCINDELAY);
+ DUMPCORE(HDMI_CORE_FC_VSYNCINWIDTH);
+ DUMPCORE(HDMI_CORE_FC_CTRLDUR);
+ DUMPCORE(HDMI_CORE_FC_EXCTRLDUR);
+ DUMPCORE(HDMI_CORE_FC_EXCTRLSPAC);
+ DUMPCORE(HDMI_CORE_FC_CH0PREAM);
+ DUMPCORE(HDMI_CORE_FC_CH1PREAM);
+ DUMPCORE(HDMI_CORE_FC_CH2PREAM);
+ DUMPCORE(HDMI_CORE_FC_AVICONF0);
+ DUMPCORE(HDMI_CORE_FC_AVICONF1);
+ DUMPCORE(HDMI_CORE_FC_AVICONF2);
+ DUMPCORE(HDMI_CORE_FC_AVIVID);
+ DUMPCORE(HDMI_CORE_FC_PRCONF);
+
+ DUMPCORE(HDMI_CORE_MC_CLKDIS);
+ DUMPCORE(HDMI_CORE_MC_SWRSTZREQ);
+ DUMPCORE(HDMI_CORE_MC_FLOWCTRL);
+ DUMPCORE(HDMI_CORE_MC_PHYRSTZ);
+ DUMPCORE(HDMI_CORE_MC_LOCKONCLOCK);
+
+ DUMPCORE(HDMI_CORE_I2CM_SLAVE);
+ DUMPCORE(HDMI_CORE_I2CM_ADDRESS);
+ DUMPCORE(HDMI_CORE_I2CM_DATAO);
+ DUMPCORE(HDMI_CORE_I2CM_DATAI);
+ DUMPCORE(HDMI_CORE_I2CM_OPERATION);
+ DUMPCORE(HDMI_CORE_I2CM_INT);
+ DUMPCORE(HDMI_CORE_I2CM_CTLINT);
+ DUMPCORE(HDMI_CORE_I2CM_DIV);
+ DUMPCORE(HDMI_CORE_I2CM_SEGADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SOFTRSTZ);
+ DUMPCORE(HDMI_CORE_I2CM_SEGPTR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SDA_HOLD_ADDR);
+}
+
+static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
+ struct hdmi_config *cfg)
+{
+ DSSDBG("hdmi_core_init\n");
+
+ /* video core */
+ video_cfg->data_enable_pol = 1; /* It is always 1*/
+ video_cfg->v_fc_config.timings.hsync_level = cfg->timings.hsync_level;
+ video_cfg->v_fc_config.timings.x_res = cfg->timings.x_res;
+ video_cfg->v_fc_config.timings.hsw = cfg->timings.hsw - 1;
+ video_cfg->v_fc_config.timings.hbp = cfg->timings.hbp;
+ video_cfg->v_fc_config.timings.hfp = cfg->timings.hfp;
+ video_cfg->hblank = cfg->timings.hfp +
+ cfg->timings.hbp + cfg->timings.hsw - 1;
+ video_cfg->v_fc_config.timings.vsync_level = cfg->timings.vsync_level;
+ video_cfg->v_fc_config.timings.y_res = cfg->timings.y_res;
+ video_cfg->v_fc_config.timings.vsw = cfg->timings.vsw;
+ video_cfg->v_fc_config.timings.vfp = cfg->timings.vfp;
+ video_cfg->v_fc_config.timings.vbp = cfg->timings.vbp;
+ video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */
+ video_cfg->vblank = cfg->timings.vsw +
+ cfg->timings.vfp + cfg->timings.vbp;
+ video_cfg->v_fc_config.hdmi_dvi_mode = cfg->hdmi_dvi_mode;
+ video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace;
+}
+
+/* DSS_HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_core_data *core,
+ struct hdmi_core_vid_config *cfg)
+{
+ void __iomem *base = core->base;
+ unsigned char r = 0;
+ bool vsync_pol, hsync_pol;
+
+ vsync_pol =
+ cfg->v_fc_config.timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
+ hsync_pol =
+ cfg->v_fc_config.timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
+
+ /* Set hsync, vsync and data-enable polarity */
+ r = hdmi_read_reg(base, HDMI_CORE_FC_INVIDCONF);
+ r = FLD_MOD(r, vsync_pol, 6, 6);
+ r = FLD_MOD(r, hsync_pol, 5, 5);
+ r = FLD_MOD(r, cfg->data_enable_pol, 4, 4);
+ r = FLD_MOD(r, cfg->vblank_osc, 1, 1);
+ r = FLD_MOD(r, cfg->v_fc_config.timings.interlace, 0, 0);
+ hdmi_write_reg(base, HDMI_CORE_FC_INVIDCONF, r);
+
+ /* set x resolution */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV1,
+ cfg->v_fc_config.timings.x_res >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV0,
+ cfg->v_fc_config.timings.x_res & 0xFF, 7, 0);
+
+ /* set y resolution */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV1,
+ cfg->v_fc_config.timings.y_res >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV0,
+ cfg->v_fc_config.timings.y_res & 0xFF, 7, 0);
+
+ /* set horizontal blanking pixels */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK1, cfg->hblank >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK0, cfg->hblank & 0xFF, 7, 0);
+
+ /* set vertial blanking pixels */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVBLANK, cfg->vblank, 7, 0);
+
+ /* set horizontal sync offset */
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY1,
+ cfg->v_fc_config.timings.hfp >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY0,
+ cfg->v_fc_config.timings.hfp & 0xFF, 7, 0);
+
+ /* set vertical sync offset */
+ REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINDELAY,
+ cfg->v_fc_config.timings.vfp, 7, 0);
+
+ /* set horizontal sync pulse width */
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH1,
+ (cfg->v_fc_config.timings.hsw >> 8), 1, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH0,
+ cfg->v_fc_config.timings.hsw & 0xFF, 7, 0);
+
+ /* set vertical sync pulse width */
+ REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINWIDTH,
+ cfg->v_fc_config.timings.vsw, 5, 0);
+
+ /* select DVI mode */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF,
+ cfg->v_fc_config.hdmi_dvi_mode, 3, 3);
+}
+
+static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+ int clr_depth = 0; /* 24 bit color depth */
+
+ /* COLOR_DEPTH */
+ REG_FLD_MOD(base, HDMI_CORE_VP_PR_CD, clr_depth, 7, 4);
+ /* BYPASS_EN */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 1, 6, 6);
+ /* PP_EN */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 1 : 0, 5, 5);
+ /* YCC422_EN */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, 0, 3, 3);
+ /* PP_STUFFING */
+ REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, clr_depth ? 1 : 0, 1, 1);
+ /* YCC422_STUFFING */
+ REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, 1, 2, 2);
+ /* OUTPUT_SELECTOR */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 2, 1, 0);
+}
+
+static void hdmi_core_config_csc(struct hdmi_core_data *core)
+{
+ int clr_depth = 0; /* 24 bit color depth */
+
+ /* CSC_COLORDEPTH */
+ REG_FLD_MOD(core->base, HDMI_CORE_CSC_SCALE, clr_depth, 7, 4);
+}
+
+static void hdmi_core_config_video_sampler(struct hdmi_core_data *core)
+{
+ int video_mapping = 1; /* for 24 bit color depth */
+
+ /* VIDEO_MAPPING */
+ REG_FLD_MOD(core->base, HDMI_CORE_TX_INVID0, video_mapping, 4, 0);
+}
+
+static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core,
+ struct hdmi_avi_infoframe *frame)
+{
+ void __iomem *base = core->base;
+ u8 data[HDMI_INFOFRAME_SIZE(AVI)];
+ u8 *ptr;
+ unsigned y, a, b, s;
+ unsigned c, m, r;
+ unsigned itc, ec, q, sc;
+ unsigned vic;
+ unsigned yq, cn, pr;
+
+ hdmi_avi_infoframe_pack(frame, data, sizeof(data));
+
+ print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data,
+ HDMI_INFOFRAME_SIZE(AVI), false);
+
+ ptr = data + HDMI_INFOFRAME_HEADER_SIZE;
+
+ y = (ptr[0] >> 5) & 0x3;
+ a = (ptr[0] >> 4) & 0x1;
+ b = (ptr[0] >> 2) & 0x3;
+ s = (ptr[0] >> 0) & 0x3;
+
+ c = (ptr[1] >> 6) & 0x3;
+ m = (ptr[1] >> 4) & 0x3;
+ r = (ptr[1] >> 0) & 0x3;
+
+ itc = (ptr[2] >> 7) & 0x1;
+ ec = (ptr[2] >> 4) & 0x7;
+ q = (ptr[2] >> 2) & 0x3;
+ sc = (ptr[2] >> 0) & 0x3;
+
+ vic = ptr[3];
+
+ yq = (ptr[4] >> 6) & 0x3;
+ cn = (ptr[4] >> 4) & 0x3;
+ pr = (ptr[4] >> 0) & 0xf;
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AVICONF0,
+ (a << 6) | (s << 4) | (b << 2) | (y << 0));
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AVICONF1,
+ (c << 6) | (m << 4) | (r << 0));
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AVICONF2,
+ (itc << 7) | (ec << 4) | (q << 2) | (sc << 0));
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AVIVID, vic);
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AVICONF3,
+ (yq << 2) | (cn << 0));
+
+ REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, pr, 3, 0);
+}
+
+static void hdmi_core_csc_config(struct hdmi_core_data *core,
+ struct csc_table csc_coeff)
+{
+ void __iomem *base = core->base;
+
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_MSB, csc_coeff.a1 >> 8 , 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_LSB, csc_coeff.a1, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_MSB, csc_coeff.a2 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_LSB, csc_coeff.a2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_MSB, csc_coeff.a3 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_LSB, csc_coeff.a3, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_MSB, csc_coeff.a4 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_LSB, csc_coeff.a4, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_MSB, csc_coeff.b1 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_LSB, csc_coeff.b1, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_MSB, csc_coeff.b2 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_LSB, csc_coeff.b2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_MSB, csc_coeff.b3 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_LSB, csc_coeff.b3, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_MSB, csc_coeff.b4 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_LSB, csc_coeff.b4, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_MSB, csc_coeff.c1 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_LSB, csc_coeff.c1, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_MSB, csc_coeff.c2 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_LSB, csc_coeff.c2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_MSB, csc_coeff.c3 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_LSB, csc_coeff.c3, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_MSB, csc_coeff.c4 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_LSB, csc_coeff.c4, 7, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_MC_FLOWCTRL, 0x1, 0, 0);
+}
+
+static void hdmi_core_configure_range(struct hdmi_core_data *core)
+{
+ struct csc_table csc_coeff = { 0 };
+
+ /* support limited range with 24 bit color depth for now */
+ csc_coeff = csc_table_deepcolor[0];
+
+ hdmi_core_csc_config(core, csc_coeff);
+}
+
+static void hdmi_core_enable_video_path(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ DSSDBG("hdmi_core_enable_video_path\n");
+
+ REG_FLD_MOD(base, HDMI_CORE_FC_CTRLDUR, 0x0C, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLDUR, 0x20, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLSPAC, 0x01, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_CH0PREAM, 0x0B, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_CH1PREAM, 0x16, 5, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_CH2PREAM, 0x21, 5, 0);
+ REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 0, 0);
+ REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 1, 1);
+}
+
+static void hdmi_core_mask_interrupts(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ /* Master IRQ mask */
+ REG_FLD_MOD(base, HDMI_CORE_IH_MUTE, 0x3, 1, 0);
+
+ /* Mask all the interrupts in HDMI core */
+
+ REG_FLD_MOD(base, HDMI_CORE_VP_MASK, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_MASK0, 0xe7, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_MASK1, 0xfb, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_MASK2, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 0x3, 3, 2);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_CEC_MASK, 0x7f, 6, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
+
+ REG_FLD_MOD(base, HDMI_CORE_PHY_MASK0, 0xf3, 7, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
+
+ /* Clear all the current interrupt bits */
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xe7, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xfb, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0x7, 2, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0x7f, 6, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
+}
+
+static void hdmi_core_enable_interrupts(struct hdmi_core_data *core)
+{
+ /* Unmute interrupts */
+ REG_FLD_MOD(core->base, HDMI_CORE_IH_MUTE, 0x0, 1, 0);
+}
+
+int hdmi5_core_handle_irqs(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CMPHY_STAT0, 0xff, 7, 0);
+
+ return 0;
+}
+
+void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct hdmi_config *cfg)
+{
+ struct omap_video_timings video_timing;
+ struct hdmi_video_format video_format;
+ struct hdmi_core_vid_config v_core_cfg;
+
+ hdmi_core_mask_interrupts(core);
+
+ hdmi_core_init(&v_core_cfg, cfg);
+
+ hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg);
+
+ hdmi_wp_video_config_timing(wp, &video_timing);
+
+ /* video config */
+ video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+ hdmi_wp_video_config_format(wp, &video_format);
+
+ hdmi_wp_video_config_interface(wp, &video_timing);
+
+ /* support limited range with 24 bit color depth for now */
+ hdmi_core_configure_range(core);
+ cfg->infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
+
+ /*
+ * configure core video part, set software reset in the core
+ */
+ v_core_cfg.packet_mode = HDMI_PACKETMODE24BITPERPIXEL;
+
+ hdmi_core_video_config(core, &v_core_cfg);
+
+ hdmi_core_config_video_packetizer(core);
+ hdmi_core_config_csc(core);
+ hdmi_core_config_video_sampler(core);
+
+ if (cfg->hdmi_dvi_mode == HDMI_HDMI)
+ hdmi_core_write_avi_infoframe(core, &cfg->infoframe);
+
+ hdmi_core_enable_video_path(core);
+
+ hdmi_core_enable_interrupts(core);
+}
+
+static void hdmi5_core_audio_config(struct hdmi_core_data *core,
+ struct hdmi_core_audio_config *cfg)
+{
+ void __iomem *base = core->base;
+ u8 val;
+
+ /* Mute audio before configuring */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0xf, 7, 4);
+
+ /* Set the N parameter */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_N1, cfg->n, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_N2, cfg->n >> 8, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_N3, cfg->n >> 16, 3, 0);
+
+ /*
+ * CTS manual mode. Automatic mode is not supported when using audio
+ * parallel interface.
+ */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, 1, 4, 4);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS1, cfg->cts, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS2, cfg->cts >> 8, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, cfg->cts >> 16, 3, 0);
+
+ /* Layout of Audio Sample Packets: 2-channel or multichannels */
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH)
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 0, 0);
+ else
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 1, 0, 0);
+
+ /* Configure IEC-609580 Validity bits */
+ /* Channel 0 is valid */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 0, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 4, 4);
+
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH)
+ val = 1;
+ else
+ val = 0;
+
+ /* Channels 1, 2 setting */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 1, 1);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 5, 5);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 2, 2);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 6, 6);
+ /* Channel 3 setting */
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH)
+ val = 1;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 3, 3);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 7, 7);
+
+ /* Configure IEC-60958 User bits */
+ /* TODO: should be set by user. */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSU, 0, 7, 0);
+
+ /* Configure IEC-60958 Channel Status word */
+ /* CGMSA */
+ val = cfg->iec60958_cfg->status[5] & IEC958_AES5_CON_CGMSA;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 5, 4);
+
+ /* Copyright */
+ val = (cfg->iec60958_cfg->status[0] &
+ IEC958_AES0_CON_NOT_COPYRIGHT) >> 2;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 0, 0);
+
+ /* Category */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(1),
+ cfg->iec60958_cfg->status[1]);
+
+ /* PCM audio mode */
+ val = (cfg->iec60958_cfg->status[0] & IEC958_AES0_CON_MODE) >> 6;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 6, 4);
+
+ /* Source number */
+ val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0);
+
+ /* Channel number right 0 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
+ /* Channel number right 1*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 4, 7, 4);
+ /* Channel number right 2 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 6, 3, 0);
+ /* Channel number right 3*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 8, 7, 4);
+ /* Channel number left 0 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 1, 3, 0);
+ /* Channel number left 1*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 3, 7, 4);
+ /* Channel number left 2 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 5, 3, 0);
+ /* Channel number left 3*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 7, 7, 4);
+
+ /* Clock accuracy and sample rate */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(7),
+ cfg->iec60958_cfg->status[3]);
+
+ /* Original sample rate and word length */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(8),
+ cfg->iec60958_cfg->status[4]);
+
+ /* Enable FIFO empty and full interrupts */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 3, 3, 2);
+
+ /* Configure GPA */
+ /* select HBR/SPDIF interfaces */
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH) {
+ /* select HBR/SPDIF interfaces */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
+ /* enable two channels in GPA */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 3, 7, 0);
+ } else if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH) {
+ /* select HBR/SPDIF interfaces */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
+ /* enable six channels in GPA */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0x3F, 7, 0);
+ } else {
+ /* select HBR/SPDIF interfaces */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
+ /* enable eight channels in GPA */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0xFF, 7, 0);
+ }
+
+ /* disable HBR */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 0, 0, 0);
+ /* enable PCUV */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 1, 1, 1);
+ /* enable GPA FIFO full and empty mask */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 3, 1, 0);
+ /* set polarity of GPA FIFO empty interrupts */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_POL, 1, 0, 0);
+
+ /* unmute audio */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 7, 4);
+}
+
+static void hdmi5_core_audio_infoframe_cfg(struct hdmi_core_data *core,
+ struct snd_cea_861_aud_if *info_aud)
+{
+ void __iomem *base = core->base;
+
+ /* channel count and coding type fields in AUDICONF0 are swapped */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF0,
+ (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC) << 4 |
+ (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CT) >> 4);
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF1, info_aud->db2_sf_ss);
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF2, info_aud->db4_ca);
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3,
+ (info_aud->db5_dminh_lsv & CEA861_AUDIO_INFOFRAME_DB5_DM_INH) >> 3 |
+ (info_aud->db5_dminh_lsv & CEA861_AUDIO_INFOFRAME_DB5_LSV));
+}
+
+int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct omap_dss_audio *audio, u32 pclk)
+{
+ struct hdmi_audio_format audio_format;
+ struct hdmi_audio_dma audio_dma;
+ struct hdmi_core_audio_config core_cfg;
+ int err, n, cts, channel_count;
+ unsigned int fs_nr;
+ bool word_length_16b = false;
+
+ if (!audio || !audio->iec || !audio->cea || !core)
+ return -EINVAL;
+
+ core_cfg.iec60958_cfg = audio->iec;
+
+ if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) &&
+ (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16))
+ word_length_16b = true;
+
+ /* only 16-bit word length supported atm */
+ if (!word_length_16b)
+ return -EINVAL;
+
+ switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
+ case IEC958_AES3_CON_FS_32000:
+ fs_nr = 32000;
+ break;
+ case IEC958_AES3_CON_FS_44100:
+ fs_nr = 44100;
+ break;
+ case IEC958_AES3_CON_FS_48000:
+ fs_nr = 48000;
+ break;
+ case IEC958_AES3_CON_FS_88200:
+ fs_nr = 88200;
+ break;
+ case IEC958_AES3_CON_FS_96000:
+ fs_nr = 96000;
+ break;
+ case IEC958_AES3_CON_FS_176400:
+ fs_nr = 176400;
+ break;
+ case IEC958_AES3_CON_FS_192000:
+ fs_nr = 192000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hdmi_compute_acr(pclk, fs_nr, &n, &cts);
+ core_cfg.n = n;
+ core_cfg.cts = cts;
+
+ /* Audio channels settings */
+ channel_count = (audio->cea->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC)
+ + 1;
+
+ if (channel_count == 2)
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
+ else if (channel_count == 6)
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_6CH;
+ else
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_8CH;
+
+ /* DMA settings */
+ if (word_length_16b)
+ audio_dma.transfer_size = 0x10;
+ else
+ audio_dma.transfer_size = 0x20;
+ audio_dma.block_size = 0xC0;
+ audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+ audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+ /* audio FIFO format settings for 16-bit samples*/
+ audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+ audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+ audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+ audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+
+ /* only LPCM atm */
+ audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+
+ /* only allowed option */
+ audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+
+ /* disable start/stop signals of IEC 60958 blocks */
+ audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
+
+ /* configure DMA and audio FIFO format*/
+ hdmi_wp_audio_config_dma(wp, &audio_dma);
+ hdmi_wp_audio_config_format(wp, &audio_format);
+
+ /* configure the core */
+ hdmi5_core_audio_config(core, &core_cfg);
+
+ /* configure CEA 861 audio infoframe */
+ hdmi5_core_audio_infoframe_cfg(core, audio->cea);
+
+ return 0;
+}
+
+int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
+{
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+ if (!res) {
+ DSSERR("can't get CORE IORESOURCE_MEM HDMI\n");
+ return -EINVAL;
+ }
+
+ core->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(core->base)) {
+ DSSERR("can't ioremap HDMI core\n");
+ return PTR_ERR(core->base);
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h
new file mode 100644
index 000000000000..f2f1022c5516
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h
@@ -0,0 +1,304 @@
+/*
+ * HDMI driver definition for TI OMAP5 processors.
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HDMI5_CORE_H_
+#define _HDMI5_CORE_H_
+
+#include "hdmi.h"
+
+/* HDMI IP Core System */
+
+/* HDMI Identification */
+#define HDMI_CORE_DESIGN_ID 0x00000
+#define HDMI_CORE_REVISION_ID 0x00004
+#define HDMI_CORE_PRODUCT_ID0 0x00008
+#define HDMI_CORE_PRODUCT_ID1 0x0000C
+#define HDMI_CORE_CONFIG0_ID 0x00010
+#define HDMI_CORE_CONFIG1_ID 0x00014
+#define HDMI_CORE_CONFIG2_ID 0x00018
+#define HDMI_CORE_CONFIG3_ID 0x0001C
+
+/* HDMI Interrupt */
+#define HDMI_CORE_IH_FC_STAT0 0x00400
+#define HDMI_CORE_IH_FC_STAT1 0x00404
+#define HDMI_CORE_IH_FC_STAT2 0x00408
+#define HDMI_CORE_IH_AS_STAT0 0x0040C
+#define HDMI_CORE_IH_PHY_STAT0 0x00410
+#define HDMI_CORE_IH_I2CM_STAT0 0x00414
+#define HDMI_CORE_IH_CEC_STAT0 0x00418
+#define HDMI_CORE_IH_VP_STAT0 0x0041C
+#define HDMI_CORE_IH_I2CMPHY_STAT0 0x00420
+#define HDMI_CORE_IH_MUTE 0x007FC
+
+/* HDMI Video Sampler */
+#define HDMI_CORE_TX_INVID0 0x00800
+#define HDMI_CORE_TX_INSTUFFING 0x00804
+#define HDMI_CORE_TX_RGYDATA0 0x00808
+#define HDMI_CORE_TX_RGYDATA1 0x0080C
+#define HDMI_CORE_TX_RCRDATA0 0x00810
+#define HDMI_CORE_TX_RCRDATA1 0x00814
+#define HDMI_CORE_TX_BCBDATA0 0x00818
+#define HDMI_CORE_TX_BCBDATA1 0x0081C
+
+/* HDMI Video Packetizer */
+#define HDMI_CORE_VP_STATUS 0x02000
+#define HDMI_CORE_VP_PR_CD 0x02004
+#define HDMI_CORE_VP_STUFF 0x02008
+#define HDMI_CORE_VP_REMAP 0x0200C
+#define HDMI_CORE_VP_CONF 0x02010
+#define HDMI_CORE_VP_STAT 0x02014
+#define HDMI_CORE_VP_INT 0x02018
+#define HDMI_CORE_VP_MASK 0x0201C
+#define HDMI_CORE_VP_POL 0x02020
+
+/* Frame Composer */
+#define HDMI_CORE_FC_INVIDCONF 0x04000
+#define HDMI_CORE_FC_INHACTIV0 0x04004
+#define HDMI_CORE_FC_INHACTIV1 0x04008
+#define HDMI_CORE_FC_INHBLANK0 0x0400C
+#define HDMI_CORE_FC_INHBLANK1 0x04010
+#define HDMI_CORE_FC_INVACTIV0 0x04014
+#define HDMI_CORE_FC_INVACTIV1 0x04018
+#define HDMI_CORE_FC_INVBLANK 0x0401C
+#define HDMI_CORE_FC_HSYNCINDELAY0 0x04020
+#define HDMI_CORE_FC_HSYNCINDELAY1 0x04024
+#define HDMI_CORE_FC_HSYNCINWIDTH0 0x04028
+#define HDMI_CORE_FC_HSYNCINWIDTH1 0x0402C
+#define HDMI_CORE_FC_VSYNCINDELAY 0x04030
+#define HDMI_CORE_FC_VSYNCINWIDTH 0x04034
+#define HDMI_CORE_FC_INFREQ0 0x04038
+#define HDMI_CORE_FC_INFREQ1 0x0403C
+#define HDMI_CORE_FC_INFREQ2 0x04040
+#define HDMI_CORE_FC_CTRLDUR 0x04044
+#define HDMI_CORE_FC_EXCTRLDUR 0x04048
+#define HDMI_CORE_FC_EXCTRLSPAC 0x0404C
+#define HDMI_CORE_FC_CH0PREAM 0x04050
+#define HDMI_CORE_FC_CH1PREAM 0x04054
+#define HDMI_CORE_FC_CH2PREAM 0x04058
+#define HDMI_CORE_FC_AVICONF3 0x0405C
+#define HDMI_CORE_FC_GCP 0x04060
+#define HDMI_CORE_FC_AVICONF0 0x04064
+#define HDMI_CORE_FC_AVICONF1 0x04068
+#define HDMI_CORE_FC_AVICONF2 0x0406C
+#define HDMI_CORE_FC_AVIVID 0x04070
+#define HDMI_CORE_FC_AVIETB0 0x04074
+#define HDMI_CORE_FC_AVIETB1 0x04078
+#define HDMI_CORE_FC_AVISBB0 0x0407C
+#define HDMI_CORE_FC_AVISBB1 0x04080
+#define HDMI_CORE_FC_AVIELB0 0x04084
+#define HDMI_CORE_FC_AVIELB1 0x04088
+#define HDMI_CORE_FC_AVISRB0 0x0408C
+#define HDMI_CORE_FC_AVISRB1 0x04090
+#define HDMI_CORE_FC_AUDICONF0 0x04094
+#define HDMI_CORE_FC_AUDICONF1 0x04098
+#define HDMI_CORE_FC_AUDICONF2 0x0409C
+#define HDMI_CORE_FC_AUDICONF3 0x040A0
+#define HDMI_CORE_FC_VSDIEEEID0 0x040A4
+#define HDMI_CORE_FC_VSDSIZE 0x040A8
+#define HDMI_CORE_FC_VSDIEEEID1 0x040C0
+#define HDMI_CORE_FC_VSDIEEEID2 0x040C4
+#define HDMI_CORE_FC_VSDPAYLOAD(n) (n * 4 + 0x040C8)
+#define HDMI_CORE_FC_SPDVENDORNAME(n) (n * 4 + 0x04128)
+#define HDMI_CORE_FC_SPDPRODUCTNAME(n) (n * 4 + 0x04148)
+#define HDMI_CORE_FC_SPDDEVICEINF 0x04188
+#define HDMI_CORE_FC_AUDSCONF 0x0418C
+#define HDMI_CORE_FC_AUDSSTAT 0x04190
+#define HDMI_CORE_FC_AUDSV 0x04194
+#define HDMI_CORE_FC_AUDSU 0x04198
+#define HDMI_CORE_FC_AUDSCHNLS(n) (n * 4 + 0x0419C)
+#define HDMI_CORE_FC_CTRLQHIGH 0x041CC
+#define HDMI_CORE_FC_CTRLQLOW 0x041D0
+#define HDMI_CORE_FC_ACP0 0x041D4
+#define HDMI_CORE_FC_ACP(n) ((16-n) * 4 + 0x04208)
+#define HDMI_CORE_FC_ISCR1_0 0x04248
+#define HDMI_CORE_FC_ISCR1(n) ((16-n) * 4 + 0x0424C)
+#define HDMI_CORE_FC_ISCR2(n) ((15-n) * 4 + 0x0428C)
+#define HDMI_CORE_FC_DATAUTO0 0x042CC
+#define HDMI_CORE_FC_DATAUTO1 0x042D0
+#define HDMI_CORE_FC_DATAUTO2 0x042D4
+#define HDMI_CORE_FC_DATMAN 0x042D8
+#define HDMI_CORE_FC_DATAUTO3 0x042DC
+#define HDMI_CORE_FC_RDRB(n) (n * 4 + 0x042E0)
+#define HDMI_CORE_FC_STAT0 0x04340
+#define HDMI_CORE_FC_INT0 0x04344
+#define HDMI_CORE_FC_MASK0 0x04348
+#define HDMI_CORE_FC_POL0 0x0434C
+#define HDMI_CORE_FC_STAT1 0x04350
+#define HDMI_CORE_FC_INT1 0x04354
+#define HDMI_CORE_FC_MASK1 0x04358
+#define HDMI_CORE_FC_POL1 0x0435C
+#define HDMI_CORE_FC_STAT2 0x04360
+#define HDMI_CORE_FC_INT2 0x04364
+#define HDMI_CORE_FC_MASK2 0x04368
+#define HDMI_CORE_FC_POL2 0x0436C
+#define HDMI_CORE_FC_PRCONF 0x04380
+#define HDMI_CORE_FC_GMD_STAT 0x04400
+#define HDMI_CORE_FC_GMD_EN 0x04404
+#define HDMI_CORE_FC_GMD_UP 0x04408
+#define HDMI_CORE_FC_GMD_CONF 0x0440C
+#define HDMI_CORE_FC_GMD_HB 0x04410
+#define HDMI_CORE_FC_GMD_PB(n) (n * 4 + 0x04414)
+#define HDMI_CORE_FC_DBGFORCE 0x04800
+#define HDMI_CORE_FC_DBGAUD0CH0 0x04804
+#define HDMI_CORE_FC_DBGAUD1CH0 0x04808
+#define HDMI_CORE_FC_DBGAUD2CH0 0x0480C
+#define HDMI_CORE_FC_DBGAUD0CH1 0x04810
+#define HDMI_CORE_FC_DBGAUD1CH1 0x04814
+#define HDMI_CORE_FC_DBGAUD2CH1 0x04818
+#define HDMI_CORE_FC_DBGAUD0CH2 0x0481C
+#define HDMI_CORE_FC_DBGAUD1CH2 0x04820
+#define HDMI_CORE_FC_DBGAUD2CH2 0x04824
+#define HDMI_CORE_FC_DBGAUD0CH3 0x04828
+#define HDMI_CORE_FC_DBGAUD1CH3 0x0482C
+#define HDMI_CORE_FC_DBGAUD2CH3 0x04830
+#define HDMI_CORE_FC_DBGAUD0CH4 0x04834
+#define HDMI_CORE_FC_DBGAUD1CH4 0x04838
+#define HDMI_CORE_FC_DBGAUD2CH4 0x0483C
+#define HDMI_CORE_FC_DBGAUD0CH5 0x04840
+#define HDMI_CORE_FC_DBGAUD1CH5 0x04844
+#define HDMI_CORE_FC_DBGAUD2CH5 0x04848
+#define HDMI_CORE_FC_DBGAUD0CH6 0x0484C
+#define HDMI_CORE_FC_DBGAUD1CH6 0x04850
+#define HDMI_CORE_FC_DBGAUD2CH6 0x04854
+#define HDMI_CORE_FC_DBGAUD0CH7 0x04858
+#define HDMI_CORE_FC_DBGAUD1CH7 0x0485C
+#define HDMI_CORE_FC_DBGAUD2CH7 0x04860
+#define HDMI_CORE_FC_DBGTMDS0 0x04864
+#define HDMI_CORE_FC_DBGTMDS1 0x04868
+#define HDMI_CORE_FC_DBGTMDS2 0x0486C
+#define HDMI_CORE_PHY_MASK0 0x0C018
+#define HDMI_CORE_PHY_I2CM_INT_ADDR 0x0C09C
+#define HDMI_CORE_PHY_I2CM_CTLINT_ADDR 0x0C0A0
+
+/* HDMI Audio */
+#define HDMI_CORE_AUD_CONF0 0x0C400
+#define HDMI_CORE_AUD_CONF1 0x0C404
+#define HDMI_CORE_AUD_INT 0x0C408
+#define HDMI_CORE_AUD_N1 0x0C800
+#define HDMI_CORE_AUD_N2 0x0C804
+#define HDMI_CORE_AUD_N3 0x0C808
+#define HDMI_CORE_AUD_CTS1 0x0C80C
+#define HDMI_CORE_AUD_CTS2 0x0C810
+#define HDMI_CORE_AUD_CTS3 0x0C814
+#define HDMI_CORE_AUD_INCLKFS 0x0C818
+#define HDMI_CORE_AUD_CC08 0x0CC08
+#define HDMI_CORE_AUD_GP_CONF0 0x0D400
+#define HDMI_CORE_AUD_GP_CONF1 0x0D404
+#define HDMI_CORE_AUD_GP_CONF2 0x0D408
+#define HDMI_CORE_AUD_D010 0x0D010
+#define HDMI_CORE_AUD_GP_STAT 0x0D40C
+#define HDMI_CORE_AUD_GP_INT 0x0D410
+#define HDMI_CORE_AUD_GP_POL 0x0D414
+#define HDMI_CORE_AUD_GP_MASK 0x0D418
+
+/* HDMI Main Controller */
+#define HDMI_CORE_MC_CLKDIS 0x10004
+#define HDMI_CORE_MC_SWRSTZREQ 0x10008
+#define HDMI_CORE_MC_FLOWCTRL 0x10010
+#define HDMI_CORE_MC_PHYRSTZ 0x10014
+#define HDMI_CORE_MC_LOCKONCLOCK 0x10018
+
+/* HDMI COLOR SPACE CONVERTER */
+#define HDMI_CORE_CSC_CFG 0x10400
+#define HDMI_CORE_CSC_SCALE 0x10404
+#define HDMI_CORE_CSC_COEF_A1_MSB 0x10408
+#define HDMI_CORE_CSC_COEF_A1_LSB 0x1040C
+#define HDMI_CORE_CSC_COEF_A2_MSB 0x10410
+#define HDMI_CORE_CSC_COEF_A2_LSB 0x10414
+#define HDMI_CORE_CSC_COEF_A3_MSB 0x10418
+#define HDMI_CORE_CSC_COEF_A3_LSB 0x1041C
+#define HDMI_CORE_CSC_COEF_A4_MSB 0x10420
+#define HDMI_CORE_CSC_COEF_A4_LSB 0x10424
+#define HDMI_CORE_CSC_COEF_B1_MSB 0x10428
+#define HDMI_CORE_CSC_COEF_B1_LSB 0x1042C
+#define HDMI_CORE_CSC_COEF_B2_MSB 0x10430
+#define HDMI_CORE_CSC_COEF_B2_LSB 0x10434
+#define HDMI_CORE_CSC_COEF_B3_MSB 0x10438
+#define HDMI_CORE_CSC_COEF_B3_LSB 0x1043C
+#define HDMI_CORE_CSC_COEF_B4_MSB 0x10440
+#define HDMI_CORE_CSC_COEF_B4_LSB 0x10444
+#define HDMI_CORE_CSC_COEF_C1_MSB 0x10448
+#define HDMI_CORE_CSC_COEF_C1_LSB 0x1044C
+#define HDMI_CORE_CSC_COEF_C2_MSB 0x10450
+#define HDMI_CORE_CSC_COEF_C2_LSB 0x10454
+#define HDMI_CORE_CSC_COEF_C3_MSB 0x10458
+#define HDMI_CORE_CSC_COEF_C3_LSB 0x1045C
+#define HDMI_CORE_CSC_COEF_C4_MSB 0x10460
+#define HDMI_CORE_CSC_COEF_C4_LSB 0x10464
+
+/* HDMI HDCP */
+#define HDMI_CORE_HDCP_MASK 0x14020
+
+/* HDMI CEC */
+#define HDMI_CORE_CEC_MASK 0x17408
+
+/* HDMI I2C Master */
+#define HDMI_CORE_I2CM_SLAVE 0x157C8
+#define HDMI_CORE_I2CM_ADDRESS 0x157CC
+#define HDMI_CORE_I2CM_DATAO 0x157D0
+#define HDMI_CORE_I2CM_DATAI 0X157D4
+#define HDMI_CORE_I2CM_OPERATION 0x157D8
+#define HDMI_CORE_I2CM_INT 0x157DC
+#define HDMI_CORE_I2CM_CTLINT 0x157E0
+#define HDMI_CORE_I2CM_DIV 0x157E4
+#define HDMI_CORE_I2CM_SEGADDR 0x157E8
+#define HDMI_CORE_I2CM_SOFTRSTZ 0x157EC
+#define HDMI_CORE_I2CM_SEGPTR 0x157F0
+#define HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR 0x157F4
+#define HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR 0x157F8
+#define HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR 0x157FC
+#define HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR 0x15800
+#define HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR 0x15804
+#define HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR 0x15808
+#define HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR 0x1580C
+#define HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR 0x15810
+#define HDMI_CORE_I2CM_SDA_HOLD_ADDR 0x15814
+
+enum hdmi_core_packet_mode {
+ HDMI_PACKETMODERESERVEDVALUE = 0,
+ HDMI_PACKETMODE24BITPERPIXEL = 4,
+ HDMI_PACKETMODE30BITPERPIXEL = 5,
+ HDMI_PACKETMODE36BITPERPIXEL = 6,
+ HDMI_PACKETMODE48BITPERPIXEL = 7,
+};
+
+struct hdmi_core_vid_config {
+ struct hdmi_config v_fc_config;
+ enum hdmi_core_packet_mode packet_mode;
+ int data_enable_pol;
+ int vblank_osc;
+ int hblank;
+ int vblank;
+};
+
+struct csc_table {
+ u16 a1, a2, a3, a4;
+ u16 b1, b2, b3, b4;
+ u16 c1, c2, c3, c4;
+};
+
+int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
+void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s);
+int hdmi5_core_handle_irqs(struct hdmi_core_data *core);
+void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct hdmi_config *cfg);
+int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
+
+int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct omap_dss_audio *audio, u32 pclk);
+#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_common.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_common.c
new file mode 100644
index 000000000000..1b8fcc6c4ba1
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_common.c
@@ -0,0 +1,148 @@
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <video/omapdss.h>
+
+#include "hdmi.h"
+
+int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
+ struct hdmi_phy_data *phy)
+{
+ struct property *prop;
+ int r, len;
+
+ prop = of_find_property(ep, "lanes", &len);
+ if (prop) {
+ u32 lanes[8];
+
+ if (len / sizeof(u32) != ARRAY_SIZE(lanes)) {
+ dev_err(&pdev->dev, "bad number of lanes\n");
+ return -EINVAL;
+ }
+
+ r = of_property_read_u32_array(ep, "lanes", lanes,
+ ARRAY_SIZE(lanes));
+ if (r) {
+ dev_err(&pdev->dev, "failed to read lane data\n");
+ return r;
+ }
+
+ r = hdmi_phy_parse_lanes(phy, lanes);
+ if (r) {
+ dev_err(&pdev->dev, "failed to parse lane data\n");
+ return r;
+ }
+ } else {
+ static const u32 default_lanes[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+ r = hdmi_phy_parse_lanes(phy, default_lanes);
+ if (WARN_ON(r)) {
+ dev_err(&pdev->dev, "failed to parse lane data\n");
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
+{
+ u32 deep_color;
+ bool deep_color_correct = false;
+
+ if (n == NULL || cts == NULL)
+ return -EINVAL;
+
+ /* TODO: When implemented, query deep color mode here. */
+ deep_color = 100;
+
+ /*
+ * When using deep color, the default N value (as in the HDMI
+ * specification) yields to an non-integer CTS. Hence, we
+ * modify it while keeping the restrictions described in
+ * section 7.2.1 of the HDMI 1.4a specification.
+ */
+ switch (sample_freq) {
+ case 32000:
+ case 48000:
+ case 96000:
+ case 192000:
+ if (deep_color == 125)
+ if (pclk == 27027000 || pclk == 74250000)
+ deep_color_correct = true;
+ if (deep_color == 150)
+ if (pclk == 27027000)
+ deep_color_correct = true;
+ break;
+ case 44100:
+ case 88200:
+ case 176400:
+ if (deep_color == 125)
+ if (pclk == 27027000)
+ deep_color_correct = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (deep_color_correct) {
+ switch (sample_freq) {
+ case 32000:
+ *n = 8192;
+ break;
+ case 44100:
+ *n = 12544;
+ break;
+ case 48000:
+ *n = 8192;
+ break;
+ case 88200:
+ *n = 25088;
+ break;
+ case 96000:
+ *n = 16384;
+ break;
+ case 176400:
+ *n = 50176;
+ break;
+ case 192000:
+ *n = 32768;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (sample_freq) {
+ case 32000:
+ *n = 4096;
+ break;
+ case 44100:
+ *n = 6272;
+ break;
+ case 48000:
+ *n = 6144;
+ break;
+ case 88200:
+ *n = 12544;
+ break;
+ case 96000:
+ *n = 12288;
+ break;
+ case 176400:
+ *n = 25088;
+ break;
+ case 192000:
+ *n = 24576;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+ *cts = (pclk/1000) * (*n / 128) * deep_color / (sample_freq / 10);
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c
new file mode 100644
index 000000000000..1f5d19c119ce
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c
@@ -0,0 +1,247 @@
+/*
+ * HDMI PHY
+ *
+ * Copyright (C) 2013 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+struct hdmi_phy_features {
+ bool bist_ctrl;
+ bool ldo_voltage;
+ unsigned long max_phy;
+};
+
+static const struct hdmi_phy_features *phy_feat;
+
+void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
+{
+#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
+ hdmi_read_reg(phy->base, r))
+
+ DUMPPHY(HDMI_TXPHY_TX_CTRL);
+ DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
+ DUMPPHY(HDMI_TXPHY_POWER_CTRL);
+ DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
+ if (phy_feat->bist_ctrl)
+ DUMPPHY(HDMI_TXPHY_BIST_CONTROL);
+}
+
+int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes)
+{
+ int i;
+
+ for (i = 0; i < 8; i += 2) {
+ u8 lane, pol;
+ int dx, dy;
+
+ dx = lanes[i];
+ dy = lanes[i + 1];
+
+ if (dx < 0 || dx >= 8)
+ return -EINVAL;
+
+ if (dy < 0 || dy >= 8)
+ return -EINVAL;
+
+ if (dx & 1) {
+ if (dy != dx - 1)
+ return -EINVAL;
+ pol = 1;
+ } else {
+ if (dy != dx + 1)
+ return -EINVAL;
+ pol = 0;
+ }
+
+ lane = dx / 2;
+
+ phy->lane_function[lane] = i / 2;
+ phy->lane_polarity[lane] = pol;
+ }
+
+ return 0;
+}
+
+static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
+{
+ static const u16 pad_cfg_list[] = {
+ 0x0123,
+ 0x0132,
+ 0x0312,
+ 0x0321,
+ 0x0231,
+ 0x0213,
+ 0x1023,
+ 0x1032,
+ 0x3012,
+ 0x3021,
+ 0x2031,
+ 0x2013,
+ 0x1203,
+ 0x1302,
+ 0x3102,
+ 0x3201,
+ 0x2301,
+ 0x2103,
+ 0x1230,
+ 0x1320,
+ 0x3120,
+ 0x3210,
+ 0x2310,
+ 0x2130,
+ };
+
+ u16 lane_cfg = 0;
+ int i;
+ unsigned lane_cfg_val;
+ u16 pol_val = 0;
+
+ for (i = 0; i < 4; ++i)
+ lane_cfg |= phy->lane_function[i] << ((3 - i) * 4);
+
+ pol_val |= phy->lane_polarity[0] << 0;
+ pol_val |= phy->lane_polarity[1] << 3;
+ pol_val |= phy->lane_polarity[2] << 2;
+ pol_val |= phy->lane_polarity[3] << 1;
+
+ for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i)
+ if (pad_cfg_list[i] == lane_cfg)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list)))
+ i = 0;
+
+ lane_cfg_val = i;
+
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22);
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
+}
+
+int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
+ unsigned long lfbitclk)
+{
+ u8 freqout;
+
+ /*
+ * Read address 0 in order to get the SCP reset done completed
+ * Dummy access performed to make sure reset is done
+ */
+ hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
+
+ /*
+ * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
+ * HDMI_PHYPWRCMD_LDOON command.
+ */
+ if (phy_feat->bist_ctrl)
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
+
+ /*
+ * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
+ * to be used for TMDS.
+ */
+ if (hfbitclk != lfbitclk)
+ freqout = 0;
+ else if (hfbitclk / 10 < phy_feat->max_phy)
+ freqout = 1;
+ else
+ freqout = 2;
+
+ /*
+ * Write to phy address 0 to configure the clock
+ * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
+ */
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
+
+ /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
+ hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
+
+ /* Setup max LDO voltage */
+ if (phy_feat->ldo_voltage)
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+
+ hdmi_phy_configure_lanes(phy);
+
+ return 0;
+}
+
+static const struct hdmi_phy_features omap44xx_phy_feats = {
+ .bist_ctrl = false,
+ .ldo_voltage = true,
+ .max_phy = 185675000,
+};
+
+static const struct hdmi_phy_features omap54xx_phy_feats = {
+ .bist_ctrl = true,
+ .ldo_voltage = false,
+ .max_phy = 186000000,
+};
+
+static int hdmi_phy_init_features(struct platform_device *pdev)
+{
+ struct hdmi_phy_features *dst;
+ const struct hdmi_phy_features *src;
+
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
+ return -ENOMEM;
+ }
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ src = &omap44xx_phy_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
+ src = &omap54xx_phy_feats;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ phy_feat = dst;
+
+ return 0;
+}
+
+int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
+{
+ int r;
+ struct resource *res;
+
+ r = hdmi_phy_init_features(pdev);
+ if (r)
+ return r;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+ if (!res) {
+ DSSERR("can't get PHY mem resource\n");
+ return -EINVAL;
+ }
+
+ phy->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(phy->base)) {
+ DSSERR("can't ioremap TX PHY\n");
+ return PTR_ERR(phy->base);
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c
new file mode 100644
index 000000000000..06e23a7c432c
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c
@@ -0,0 +1,255 @@
+/*
+ * HDMI PLL
+ *
+ * Copyright (C) 2013 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#define DSS_SUBSYS_NAME "HDMIPLL"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
+{
+#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
+ hdmi_read_reg(pll->base, r))
+
+ DUMPPLL(PLLCTRL_PLL_CONTROL);
+ DUMPPLL(PLLCTRL_PLL_STATUS);
+ DUMPPLL(PLLCTRL_PLL_GO);
+ DUMPPLL(PLLCTRL_CFG1);
+ DUMPPLL(PLLCTRL_CFG2);
+ DUMPPLL(PLLCTRL_CFG3);
+ DUMPPLL(PLLCTRL_SSC_CFG1);
+ DUMPPLL(PLLCTRL_SSC_CFG2);
+ DUMPPLL(PLLCTRL_CFG4);
+}
+
+void hdmi_pll_compute(struct hdmi_pll_data *pll,
+ unsigned long target_tmds, struct dss_pll_clock_info *pi)
+{
+ unsigned long fint, clkdco, clkout;
+ unsigned long target_bitclk, target_clkdco;
+ unsigned long min_dco;
+ unsigned n, m, mf, m2, sd;
+ unsigned long clkin;
+ const struct dss_pll_hw *hw = pll->pll.hw;
+
+ clkin = clk_get_rate(pll->pll.clkin);
+
+ DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
+
+ target_bitclk = target_tmds * 10;
+
+ /* Fint */
+ n = DIV_ROUND_UP(clkin, hw->fint_max);
+ fint = clkin / n;
+
+ /* adjust m2 so that the clkdco will be high enough */
+ min_dco = roundup(hw->clkdco_min, fint);
+ m2 = DIV_ROUND_UP(min_dco, target_bitclk);
+ if (m2 == 0)
+ m2 = 1;
+
+ target_clkdco = target_bitclk * m2;
+ m = target_clkdco / fint;
+
+ clkdco = fint * m;
+
+ /* adjust clkdco with fractional mf */
+ if (WARN_ON(target_clkdco - clkdco > fint))
+ mf = 0;
+ else
+ mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
+
+ if (mf > 0)
+ clkdco += (u32)div_u64((u64)mf * fint, 262144);
+
+ clkout = clkdco / m2;
+
+ /* sigma-delta */
+ sd = DIV_ROUND_UP(fint * m, 250000000);
+
+ DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
+ n, m, mf, m2, sd);
+ DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
+
+ pi->n = n;
+ pi->m = m;
+ pi->mf = mf;
+ pi->mX[0] = m2;
+ pi->sd = sd;
+
+ pi->fint = fint;
+ pi->clkdco = clkdco;
+ pi->clkout[0] = clkout;
+}
+
+static int hdmi_pll_enable(struct dss_pll *dsspll)
+{
+ struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
+ struct hdmi_wp_data *wp = pll->wp;
+ u16 r = 0;
+
+ dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
+
+ r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void hdmi_pll_disable(struct dss_pll *dsspll)
+{
+ struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
+ struct hdmi_wp_data *wp = pll->wp;
+
+ hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
+
+ dss_ctrl_pll_enable(DSS_PLL_HDMI, false);
+}
+
+static const struct dss_pll_ops dsi_pll_ops = {
+ .enable = hdmi_pll_enable,
+ .disable = hdmi_pll_disable,
+ .set_config = dss_pll_write_config_type_b,
+};
+
+static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
+ .n_max = 255,
+ .m_min = 20,
+ .m_max = 4095,
+ .mX_max = 127,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+
+ .clkdco_min = 500000000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 2000000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 24,
+ .mX_lsb[0] = 18,
+
+ .has_selfreqdco = true,
+};
+
+static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
+ .n_max = 255,
+ .m_min = 20,
+ .m_max = 2045,
+ .mX_max = 127,
+ .fint_min = 620000,
+ .fint_max = 2500000,
+
+ .clkdco_min = 750000000,
+ .clkdco_low = 1500000000,
+ .clkdco_max = 2500000000UL,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 24,
+ .mX_lsb[0] = 18,
+
+ .has_selfreqdco = true,
+ .has_refsel = true,
+};
+
+static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
+{
+ struct dss_pll *pll = &hpll->pll;
+ struct clk *clk;
+ int r;
+
+ clk = devm_clk_get(&pdev->dev, "sys_clk");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get sys_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ pll->name = "hdmi";
+ pll->id = DSS_PLL_HDMI;
+ pll->base = hpll->base;
+ pll->clkin = clk;
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ pll->hw = &dss_omap4_hdmi_pll_hw;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
+ pll->hw = &dss_omap5_hdmi_pll_hw;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ pll->ops = &dsi_pll_ops;
+
+ r = dss_pll_register(pll);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
+ struct hdmi_wp_data *wp)
+{
+ int r;
+ struct resource *res;
+
+ pll->wp = wp;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
+ if (!res) {
+ DSSERR("can't get PLL mem resource\n");
+ return -EINVAL;
+ }
+
+ pll->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pll->base)) {
+ DSSERR("can't ioremap PLLCTRL\n");
+ return PTR_ERR(pll->base);
+ }
+
+ r = dsi_init_pll_data(pdev, pll);
+ if (r) {
+ DSSERR("failed to init HDMI PLL\n");
+ return r;
+ }
+
+ return 0;
+}
+
+void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
+{
+ struct dss_pll *pll = &hpll->pll;
+
+ dss_pll_unregister(pll);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c
new file mode 100644
index 000000000000..7c544bc56fb5
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c
@@ -0,0 +1,282 @@
+/*
+ * HDMI wrapper
+ *
+ * Copyright (C) 2013 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#define DSS_SUBSYS_NAME "HDMIWP"
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
+{
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
+
+ DUMPREG(HDMI_WP_REVISION);
+ DUMPREG(HDMI_WP_SYSCONFIG);
+ DUMPREG(HDMI_WP_IRQSTATUS_RAW);
+ DUMPREG(HDMI_WP_IRQSTATUS);
+ DUMPREG(HDMI_WP_IRQENABLE_SET);
+ DUMPREG(HDMI_WP_IRQENABLE_CLR);
+ DUMPREG(HDMI_WP_IRQWAKEEN);
+ DUMPREG(HDMI_WP_PWR_CTRL);
+ DUMPREG(HDMI_WP_DEBOUNCE);
+ DUMPREG(HDMI_WP_VIDEO_CFG);
+ DUMPREG(HDMI_WP_VIDEO_SIZE);
+ DUMPREG(HDMI_WP_VIDEO_TIMING_H);
+ DUMPREG(HDMI_WP_VIDEO_TIMING_V);
+ DUMPREG(HDMI_WP_CLK);
+ DUMPREG(HDMI_WP_AUDIO_CFG);
+ DUMPREG(HDMI_WP_AUDIO_CFG2);
+ DUMPREG(HDMI_WP_AUDIO_CTRL);
+ DUMPREG(HDMI_WP_AUDIO_DATA);
+}
+
+u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
+{
+ return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
+}
+
+void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
+{
+ hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
+ /* flush posted write */
+ hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
+}
+
+void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
+{
+ hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
+}
+
+void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
+{
+ hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
+}
+
+/* PHY_PWR_CMD */
+int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
+{
+ /* Return if already the state */
+ if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
+ return 0;
+
+ /* Command for power control of HDMI PHY */
+ REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
+
+ /* Status of the power control of HDMI PHY */
+ if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
+ != val) {
+ DSSERR("Failed to set PHY power mode to %d\n", val);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/* PLL_PWR_CMD */
+int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
+{
+ /* Command for power control of HDMI PLL */
+ REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
+
+ /* wait till PHY_PWR_STATUS is set */
+ if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
+ != val) {
+ DSSERR("Failed to set PLL_PWR_STATUS\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int hdmi_wp_video_start(struct hdmi_wp_data *wp)
+{
+ REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
+
+ return 0;
+}
+
+void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
+{
+ int i;
+
+ hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);
+
+ REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
+
+ for (i = 0; i < 50; ++i) {
+ u32 v;
+
+ msleep(20);
+
+ v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);
+ if (v & HDMI_IRQ_VIDEO_FRAME_DONE)
+ return;
+ }
+
+ DSSERR("no HDMI FRAMEDONE when disabling output\n");
+}
+
+void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
+ struct hdmi_video_format *video_fmt)
+{
+ u32 l = 0;
+
+ REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
+ 10, 8);
+
+ l |= FLD_VAL(video_fmt->y_res, 31, 16);
+ l |= FLD_VAL(video_fmt->x_res, 15, 0);
+ hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
+}
+
+void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
+ struct omap_video_timings *timings)
+{
+ u32 r;
+ bool vsync_pol, hsync_pol;
+ DSSDBG("Enter hdmi_wp_video_config_interface\n");
+
+ vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
+ hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
+
+ r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
+ r = FLD_MOD(r, vsync_pol, 7, 7);
+ r = FLD_MOD(r, hsync_pol, 6, 6);
+ r = FLD_MOD(r, timings->interlace, 3, 3);
+ r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
+ hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
+}
+
+void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
+ struct omap_video_timings *timings)
+{
+ u32 timing_h = 0;
+ u32 timing_v = 0;
+
+ DSSDBG("Enter hdmi_wp_video_config_timing\n");
+
+ timing_h |= FLD_VAL(timings->hbp, 31, 20);
+ timing_h |= FLD_VAL(timings->hfp, 19, 8);
+ timing_h |= FLD_VAL(timings->hsw, 7, 0);
+ hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
+
+ timing_v |= FLD_VAL(timings->vbp, 31, 20);
+ timing_v |= FLD_VAL(timings->vfp, 19, 8);
+ timing_v |= FLD_VAL(timings->vsw, 7, 0);
+ hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
+}
+
+void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
+ struct omap_video_timings *timings, struct hdmi_config *param)
+{
+ DSSDBG("Enter hdmi_wp_video_init_format\n");
+
+ video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
+ video_fmt->y_res = param->timings.y_res;
+ video_fmt->x_res = param->timings.x_res;
+ if (param->timings.interlace)
+ video_fmt->y_res /= 2;
+
+ timings->hbp = param->timings.hbp;
+ timings->hfp = param->timings.hfp;
+ timings->hsw = param->timings.hsw;
+ timings->vbp = param->timings.vbp;
+ timings->vfp = param->timings.vfp;
+ timings->vsw = param->timings.vsw;
+ timings->vsync_level = param->timings.vsync_level;
+ timings->hsync_level = param->timings.hsync_level;
+ timings->interlace = param->timings.interlace;
+}
+
+void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
+ struct hdmi_audio_format *aud_fmt)
+{
+ u32 r;
+
+ DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+ r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
+ if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
+ omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
+ omapdss_get_version() == OMAPDSS_VER_OMAP4) {
+ r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+ r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+ }
+ r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
+ r = FLD_MOD(r, aud_fmt->type, 4, 4);
+ r = FLD_MOD(r, aud_fmt->justification, 3, 3);
+ r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+ r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
+ r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+ hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
+}
+
+void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
+ struct hdmi_audio_dma *aud_dma)
+{
+ u32 r;
+
+ DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+ r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
+ r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+ r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+ hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
+
+ r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
+ r = FLD_MOD(r, aud_dma->mode, 9, 9);
+ r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
+ hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
+}
+
+int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
+{
+ REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
+
+ return 0;
+}
+
+int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
+{
+ REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
+
+ return 0;
+}
+
+int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
+{
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
+ if (!res) {
+ DSSERR("can't get WP mem resource\n");
+ return -EINVAL;
+ }
+ wp->phys_base = res->start;
+
+ wp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wp->base)) {
+ DSSERR("can't ioremap HDMI WP\n");
+ return PTR_ERR(wp->base);
+ }
+
+ return 0;
+}
+
+phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
+{
+ return wp->phys_base + HDMI_WP_AUDIO_DATA;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
new file mode 100644
index 000000000000..a7414fb12830
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "MANAGER"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
+}
+
+static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
+{
+ struct omap_dss_device *dssdev = mgr->get_device(mgr);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
+ dssdev->name : "<none>");
+}
+
+static int manager_display_match(struct omap_dss_device *dssdev, void *data)
+{
+ const char *str = data;
+
+ return sysfs_streq(dssdev->name, str);
+}
+
+static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ int r = 0;
+ size_t len = size;
+ struct omap_dss_device *dssdev = NULL;
+ struct omap_dss_device *old_dssdev;
+
+ if (buf[size-1] == '\n')
+ --len;
+
+ if (len > 0)
+ dssdev = omap_dss_find_device((void *)buf,
+ manager_display_match);
+
+ if (len > 0 && dssdev == NULL)
+ return -EINVAL;
+
+ if (dssdev) {
+ DSSDBG("display %s found\n", dssdev->name);
+
+ if (omapdss_device_is_connected(dssdev)) {
+ DSSERR("new display is already connected\n");
+ r = -EINVAL;
+ goto put_device;
+ }
+
+ if (omapdss_device_is_enabled(dssdev)) {
+ DSSERR("new display is not disabled\n");
+ r = -EINVAL;
+ goto put_device;
+ }
+ }
+
+ old_dssdev = mgr->get_device(mgr);
+ if (old_dssdev) {
+ if (omapdss_device_is_enabled(old_dssdev)) {
+ DSSERR("old display is not disabled\n");
+ r = -EINVAL;
+ goto put_device;
+ }
+
+ old_dssdev->driver->disconnect(old_dssdev);
+ }
+
+ if (dssdev) {
+ r = dssdev->driver->connect(dssdev);
+ if (r) {
+ DSSERR("failed to connect new device\n");
+ goto put_device;
+ }
+
+ old_dssdev = mgr->get_device(mgr);
+ if (old_dssdev != dssdev) {
+ DSSERR("failed to connect device to this manager\n");
+ dssdev->driver->disconnect(dssdev);
+ goto put_device;
+ }
+
+ r = mgr->apply(mgr);
+ if (r) {
+ DSSERR("failed to apply dispc config\n");
+ goto put_device;
+ }
+ }
+
+put_device:
+ if (dssdev)
+ omap_dss_put_device(dssdev);
+
+ return r ? r : size;
+}
+
+static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
+}
+
+static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ u32 color;
+ int r;
+
+ r = kstrtouint(buf, 0, &color);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.default_color = color;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static const char *trans_key_type_str[] = {
+ "gfx-destination",
+ "video-source",
+};
+
+static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ enum omap_dss_trans_key_type key_type;
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ key_type = info.trans_key_type;
+ BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
+}
+
+static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ enum omap_dss_trans_key_type key_type;
+ struct omap_overlay_manager_info info;
+ int r;
+
+ for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+ key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
+ if (sysfs_streq(buf, trans_key_type_str[key_type]))
+ break;
+ }
+
+ if (key_type == ARRAY_SIZE(trans_key_type_str))
+ return -EINVAL;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_key_type = key_type;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
+}
+
+static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ u32 key_value;
+ int r;
+
+ r = kstrtouint(buf, 0, &key_value);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_key = key_value;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
+}
+
+static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ bool enable;
+ int r;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_enabled = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_alpha_blending_enabled_show(
+ struct omap_overlay_manager *mgr, char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
+ return -ENODEV;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.partial_alpha_enabled);
+}
+
+static ssize_t manager_alpha_blending_enabled_store(
+ struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ bool enable;
+ int r;
+
+ if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
+ return -ENODEV;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.partial_alpha_enabled = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
+}
+
+static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ int r;
+ bool enable;
+
+ if (!dss_has_feature(FEAT_CPR))
+ return -ENODEV;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ if (info.cpr_enable == enable)
+ return size;
+
+ info.cpr_enable = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE,
+ "%d %d %d %d %d %d %d %d %d\n",
+ info.cpr_coefs.rr,
+ info.cpr_coefs.rg,
+ info.cpr_coefs.rb,
+ info.cpr_coefs.gr,
+ info.cpr_coefs.gg,
+ info.cpr_coefs.gb,
+ info.cpr_coefs.br,
+ info.cpr_coefs.bg,
+ info.cpr_coefs.bb);
+}
+
+static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ struct omap_dss_cpr_coefs coefs;
+ int r, i;
+ s16 *arr;
+
+ if (!dss_has_feature(FEAT_CPR))
+ return -ENODEV;
+
+ if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
+ &coefs.rr, &coefs.rg, &coefs.rb,
+ &coefs.gr, &coefs.gg, &coefs.gb,
+ &coefs.br, &coefs.bg, &coefs.bb) != 9)
+ return -EINVAL;
+
+ arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
+ coefs.gr, coefs.gg, coefs.gb,
+ coefs.br, coefs.bg, coefs.bb };
+
+ for (i = 0; i < 9; ++i) {
+ if (arr[i] < -512 || arr[i] > 511)
+ return -EINVAL;
+ }
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.cpr_coefs = coefs;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+struct manager_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_overlay_manager *, char *);
+ ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
+};
+
+#define MANAGER_ATTR(_name, _mode, _show, _store) \
+ struct manager_attribute manager_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
+static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
+ manager_display_show, manager_display_store);
+static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
+ manager_default_color_show, manager_default_color_store);
+static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
+ manager_trans_key_type_show, manager_trans_key_type_store);
+static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
+ manager_trans_key_value_show, manager_trans_key_value_store);
+static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
+ manager_trans_key_enabled_show,
+ manager_trans_key_enabled_store);
+static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
+ manager_alpha_blending_enabled_show,
+ manager_alpha_blending_enabled_store);
+static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
+ manager_cpr_enable_show,
+ manager_cpr_enable_store);
+static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
+ manager_cpr_coef_show,
+ manager_cpr_coef_store);
+
+
+static struct attribute *manager_sysfs_attrs[] = {
+ &manager_attr_name.attr,
+ &manager_attr_display.attr,
+ &manager_attr_default_color.attr,
+ &manager_attr_trans_key_type.attr,
+ &manager_attr_trans_key_value.attr,
+ &manager_attr_trans_key_enabled.attr,
+ &manager_attr_alpha_blending_enabled.attr,
+ &manager_attr_cpr_enable.attr,
+ &manager_attr_cpr_coef.attr,
+ NULL
+};
+
+static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_overlay_manager *manager;
+ struct manager_attribute *manager_attr;
+
+ manager = container_of(kobj, struct omap_overlay_manager, kobj);
+ manager_attr = container_of(attr, struct manager_attribute, attr);
+
+ if (!manager_attr->show)
+ return -ENOENT;
+
+ return manager_attr->show(manager, buf);
+}
+
+static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager *manager;
+ struct manager_attribute *manager_attr;
+
+ manager = container_of(kobj, struct omap_overlay_manager, kobj);
+ manager_attr = container_of(attr, struct manager_attribute, attr);
+
+ if (!manager_attr->store)
+ return -ENOENT;
+
+ return manager_attr->store(manager, buf, size);
+}
+
+static const struct sysfs_ops manager_sysfs_ops = {
+ .show = manager_attr_show,
+ .store = manager_attr_store,
+};
+
+static struct kobj_type manager_ktype = {
+ .sysfs_ops = &manager_sysfs_ops,
+ .default_attrs = manager_sysfs_attrs,
+};
+
+int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
+ struct platform_device *pdev)
+{
+ return kobject_init_and_add(&mgr->kobj, &manager_ktype,
+ &pdev->dev.kobj, "manager%d", mgr->id);
+}
+
+void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
+{
+ kobject_del(&mgr->kobj);
+ kobject_put(&mgr->kobj);
+
+ memset(&mgr->kobj, 0, sizeof(mgr->kobj));
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager.c b/drivers/video/fbdev/omap2/omapfb/dss/manager.c
new file mode 100644
index 000000000000..08a67f4f6a20
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/manager.c
@@ -0,0 +1,263 @@
+/*
+ * linux/drivers/video/omap2/dss/manager.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "MANAGER"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static int num_managers;
+static struct omap_overlay_manager *managers;
+
+int dss_init_overlay_managers(void)
+{
+ int i;
+
+ num_managers = dss_feat_get_num_mgrs();
+
+ managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
+ GFP_KERNEL);
+
+ BUG_ON(managers == NULL);
+
+ for (i = 0; i < num_managers; ++i) {
+ struct omap_overlay_manager *mgr = &managers[i];
+
+ switch (i) {
+ case 0:
+ mgr->name = "lcd";
+ mgr->id = OMAP_DSS_CHANNEL_LCD;
+ break;
+ case 1:
+ mgr->name = "tv";
+ mgr->id = OMAP_DSS_CHANNEL_DIGIT;
+ break;
+ case 2:
+ mgr->name = "lcd2";
+ mgr->id = OMAP_DSS_CHANNEL_LCD2;
+ break;
+ case 3:
+ mgr->name = "lcd3";
+ mgr->id = OMAP_DSS_CHANNEL_LCD3;
+ break;
+ }
+
+ mgr->caps = 0;
+ mgr->supported_displays =
+ dss_feat_get_supported_displays(mgr->id);
+ mgr->supported_outputs =
+ dss_feat_get_supported_outputs(mgr->id);
+
+ INIT_LIST_HEAD(&mgr->overlays);
+ }
+
+ return 0;
+}
+
+int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
+{
+ int i, r;
+
+ for (i = 0; i < num_managers; ++i) {
+ struct omap_overlay_manager *mgr = &managers[i];
+
+ r = dss_manager_kobj_init(mgr, pdev);
+ if (r)
+ DSSERR("failed to create sysfs file\n");
+ }
+
+ return 0;
+}
+
+void dss_uninit_overlay_managers(void)
+{
+ kfree(managers);
+ managers = NULL;
+ num_managers = 0;
+}
+
+void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < num_managers; ++i) {
+ struct omap_overlay_manager *mgr = &managers[i];
+
+ dss_manager_kobj_uninit(mgr);
+ }
+}
+
+int omap_dss_get_num_overlay_managers(void)
+{
+ return num_managers;
+}
+EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
+
+struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
+{
+ if (num >= num_managers)
+ return NULL;
+
+ return &managers[num];
+}
+EXPORT_SYMBOL(omap_dss_get_overlay_manager);
+
+int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
+ const struct omap_overlay_manager_info *info)
+{
+ if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
+ /*
+ * OMAP3 supports only graphics source transparency color key
+ * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
+ * Alpha Mode.
+ */
+ if (info->partial_alpha_enabled && info->trans_enabled
+ && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
+ DSSERR("check_manager: illegal transparency key\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
+ struct omap_overlay_info **overlay_infos)
+{
+ struct omap_overlay *ovl1, *ovl2;
+ struct omap_overlay_info *info1, *info2;
+
+ list_for_each_entry(ovl1, &mgr->overlays, list) {
+ info1 = overlay_infos[ovl1->id];
+
+ if (info1 == NULL)
+ continue;
+
+ list_for_each_entry(ovl2, &mgr->overlays, list) {
+ if (ovl1 == ovl2)
+ continue;
+
+ info2 = overlay_infos[ovl2->id];
+
+ if (info2 == NULL)
+ continue;
+
+ if (info1->zorder == info2->zorder) {
+ DSSERR("overlays %d and %d have the same "
+ "zorder %d\n",
+ ovl1->id, ovl2->id, info1->zorder);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
+ const struct omap_video_timings *timings)
+{
+ if (!dispc_mgr_timings_ok(mgr->id, timings)) {
+ DSSERR("check_manager: invalid timings\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
+ const struct dss_lcd_mgr_config *config)
+{
+ struct dispc_clock_info cinfo = config->clock_info;
+ int dl = config->video_port_width;
+ bool stallmode = config->stallmode;
+ bool fifohandcheck = config->fifohandcheck;
+
+ if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
+ return -EINVAL;
+
+ if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
+ return -EINVAL;
+
+ if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
+ return -EINVAL;
+
+ /* fifohandcheck should be used only with stallmode */
+ if (!stallmode && fifohandcheck)
+ return -EINVAL;
+
+ /*
+ * io pad mode can be only checked by using dssdev connected to the
+ * manager. Ignore checking these for now, add checks when manager
+ * is capable of holding information related to the connected interface
+ */
+
+ return 0;
+}
+
+int dss_mgr_check(struct omap_overlay_manager *mgr,
+ struct omap_overlay_manager_info *info,
+ const struct omap_video_timings *mgr_timings,
+ const struct dss_lcd_mgr_config *lcd_config,
+ struct omap_overlay_info **overlay_infos)
+{
+ struct omap_overlay *ovl;
+ int r;
+
+ if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
+ r = dss_mgr_check_zorder(mgr, overlay_infos);
+ if (r)
+ return r;
+ }
+
+ r = dss_mgr_check_timings(mgr, mgr_timings);
+ if (r)
+ return r;
+
+ r = dss_mgr_check_lcd_config(mgr, lcd_config);
+ if (r)
+ return r;
+
+ list_for_each_entry(ovl, &mgr->overlays, list) {
+ struct omap_overlay_info *oi;
+ int r;
+
+ oi = overlay_infos[ovl->id];
+
+ if (oi == NULL)
+ continue;
+
+ r = dss_ovl_check(ovl, oi, mgr_timings);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c
new file mode 100644
index 000000000000..136d30484d02
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2014 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * As omapdss panel drivers are omapdss specific, but we want to define the
+ * DT-data in generic manner, we convert the compatible strings of the panel and
+ * encoder nodes from "panel-foo" to "omapdss,panel-foo". This way we can have
+ * both correct DT data and omapdss specific drivers.
+ *
+ * When we get generic panel drivers to the kernel, this file will be removed.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+static struct list_head dss_conv_list __initdata;
+
+static const char prefix[] __initconst = "omapdss,";
+
+struct dss_conv_node {
+ struct list_head list;
+ struct device_node *node;
+ bool root;
+};
+
+static int __init omapdss_count_strings(const struct property *prop)
+{
+ const char *p = prop->value;
+ int l = 0, total = 0;
+ int i;
+
+ for (i = 0; total < prop->length; total += l, p += l, i++)
+ l = strlen(p) + 1;
+
+ return i;
+}
+
+static void __init omapdss_update_prop(struct device_node *node, char *compat,
+ int len)
+{
+ struct property *prop;
+
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return;
+
+ prop->name = "compatible";
+ prop->value = compat;
+ prop->length = len;
+
+ of_update_property(node, prop);
+}
+
+static void __init omapdss_prefix_strcpy(char *dst, int dst_len,
+ const char *src, int src_len)
+{
+ size_t total = 0;
+
+ while (total < src_len) {
+ size_t l = strlen(src) + 1;
+
+ strcpy(dst, prefix);
+ dst += strlen(prefix);
+
+ strcpy(dst, src);
+ dst += l;
+
+ src += l;
+ total += l;
+ }
+}
+
+/* prepend compatible property strings with "omapdss," */
+static void __init omapdss_omapify_node(struct device_node *node)
+{
+ struct property *prop;
+ char *new_compat;
+ int num_strs;
+ int new_len;
+
+ prop = of_find_property(node, "compatible", NULL);
+
+ if (!prop || !prop->value)
+ return;
+
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return;
+
+ /* is it already prefixed? */
+ if (strncmp(prefix, prop->value, strlen(prefix)) == 0)
+ return;
+
+ num_strs = omapdss_count_strings(prop);
+
+ new_len = prop->length + strlen(prefix) * num_strs;
+ new_compat = kmalloc(new_len, GFP_KERNEL);
+
+ omapdss_prefix_strcpy(new_compat, new_len, prop->value, prop->length);
+
+ omapdss_update_prop(node, new_compat, new_len);
+}
+
+static void __init omapdss_add_to_list(struct device_node *node, bool root)
+{
+ struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node),
+ GFP_KERNEL);
+ if (n) {
+ n->node = node;
+ n->root = root;
+ list_add(&n->list, &dss_conv_list);
+ }
+}
+
+static bool __init omapdss_list_contains(const struct device_node *node)
+{
+ struct dss_conv_node *n;
+
+ list_for_each_entry(n, &dss_conv_list, list) {
+ if (n->node == node)
+ return true;
+ }
+
+ return false;
+}
+
+static void __init omapdss_walk_device(struct device_node *node, bool root)
+{
+ struct device_node *n;
+
+ omapdss_add_to_list(node, root);
+
+ /*
+ * of_graph_get_remote_port_parent() prints an error if there is no
+ * port/ports node. To avoid that, check first that there's the node.
+ */
+ n = of_get_child_by_name(node, "ports");
+ if (!n)
+ n = of_get_child_by_name(node, "port");
+ if (!n)
+ return;
+
+ of_node_put(n);
+
+ n = NULL;
+ while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
+ struct device_node *pn;
+
+ pn = of_graph_get_remote_port_parent(n);
+
+ if (!pn)
+ continue;
+
+ if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
+ of_node_put(pn);
+ continue;
+ }
+
+ omapdss_walk_device(pn, false);
+ }
+}
+
+static const struct of_device_id omapdss_of_match[] __initconst = {
+ { .compatible = "ti,omap2-dss", },
+ { .compatible = "ti,omap3-dss", },
+ { .compatible = "ti,omap4-dss", },
+ { .compatible = "ti,omap5-dss", },
+ { .compatible = "ti,dra7-dss", },
+ {},
+};
+
+static int __init omapdss_boot_init(void)
+{
+ struct device_node *dss, *child;
+
+ INIT_LIST_HEAD(&dss_conv_list);
+
+ dss = of_find_matching_node(NULL, omapdss_of_match);
+
+ if (dss == NULL || !of_device_is_available(dss))
+ return 0;
+
+ omapdss_walk_device(dss, true);
+
+ for_each_available_child_of_node(dss, child) {
+ if (!of_find_property(child, "compatible", NULL))
+ continue;
+
+ omapdss_walk_device(child, true);
+ }
+
+ while (!list_empty(&dss_conv_list)) {
+ struct dss_conv_node *n;
+
+ n = list_first_entry(&dss_conv_list, struct dss_conv_node,
+ list);
+
+ if (!n->root)
+ omapdss_omapify_node(n->node);
+
+ list_del(&n->list);
+ of_node_put(n->node);
+ kfree(n);
+ }
+
+ return 0;
+}
+
+subsys_initcall(omapdss_boot_init);
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/output.c b/drivers/video/fbdev/omap2/omapfb/dss/output.c
new file mode 100644
index 000000000000..16072159bd24
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/output.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Ltd
+ * Author: Archit Taneja <archit@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+static LIST_HEAD(output_list);
+static DEFINE_MUTEX(output_lock);
+
+int omapdss_output_set_device(struct omap_dss_device *out,
+ struct omap_dss_device *dssdev)
+{
+ int r;
+
+ mutex_lock(&output_lock);
+
+ if (out->dst) {
+ DSSERR("output already has device %s connected to it\n",
+ out->dst->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (out->output_type != dssdev->type) {
+ DSSERR("output type and display type don't match\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ out->dst = dssdev;
+ dssdev->src = out;
+
+ mutex_unlock(&output_lock);
+
+ return 0;
+err:
+ mutex_unlock(&output_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_output_set_device);
+
+int omapdss_output_unset_device(struct omap_dss_device *out)
+{
+ int r;
+
+ mutex_lock(&output_lock);
+
+ if (!out->dst) {
+ DSSERR("output doesn't have a device connected to it\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) {
+ DSSERR("device %s is not disabled, cannot unset device\n",
+ out->dst->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ out->dst->src = NULL;
+ out->dst = NULL;
+
+ mutex_unlock(&output_lock);
+
+ return 0;
+err:
+ mutex_unlock(&output_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_output_unset_device);
+
+int omapdss_register_output(struct omap_dss_device *out)
+{
+ list_add_tail(&out->list, &output_list);
+ return 0;
+}
+EXPORT_SYMBOL(omapdss_register_output);
+
+void omapdss_unregister_output(struct omap_dss_device *out)
+{
+ list_del(&out->list);
+}
+EXPORT_SYMBOL(omapdss_unregister_output);
+
+struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
+{
+ struct omap_dss_device *out;
+
+ list_for_each_entry(out, &output_list, list) {
+ if (out->id == id)
+ return out;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(omap_dss_get_output);
+
+struct omap_dss_device *omap_dss_find_output(const char *name)
+{
+ struct omap_dss_device *out;
+
+ list_for_each_entry(out, &output_list, list) {
+ if (strcmp(out->name, name) == 0)
+ return omap_dss_get_device(out);
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(omap_dss_find_output);
+
+struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
+{
+ struct device_node *src_node;
+ struct omap_dss_device *out;
+ u32 reg;
+
+ src_node = dss_of_port_get_parent_device(port);
+ if (!src_node)
+ return NULL;
+
+ reg = dss_of_port_get_port_number(port);
+
+ list_for_each_entry(out, &output_list, list) {
+ if (out->dev->of_node == src_node && out->port_num == reg) {
+ of_node_put(src_node);
+ return omap_dss_get_device(out);
+ }
+ }
+
+ of_node_put(src_node);
+
+ return NULL;
+}
+EXPORT_SYMBOL(omap_dss_find_output_by_port_node);
+
+struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
+{
+ while (dssdev->src)
+ dssdev = dssdev->src;
+
+ if (dssdev->id != 0)
+ return omap_dss_get_device(dssdev);
+
+ return NULL;
+}
+EXPORT_SYMBOL(omapdss_find_output_from_display);
+
+struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out;
+ struct omap_overlay_manager *mgr;
+
+ out = omapdss_find_output_from_display(dssdev);
+
+ if (out == NULL)
+ return NULL;
+
+ mgr = out->manager;
+
+ omap_dss_put_device(out);
+
+ return mgr;
+}
+EXPORT_SYMBOL(omapdss_find_mgr_from_display);
+
+static const struct dss_mgr_ops *dss_mgr_ops;
+
+int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops)
+{
+ if (dss_mgr_ops)
+ return -EBUSY;
+
+ dss_mgr_ops = mgr_ops;
+
+ return 0;
+}
+EXPORT_SYMBOL(dss_install_mgr_ops);
+
+void dss_uninstall_mgr_ops(void)
+{
+ dss_mgr_ops = NULL;
+}
+EXPORT_SYMBOL(dss_uninstall_mgr_ops);
+
+int dss_mgr_connect(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *dst)
+{
+ return dss_mgr_ops->connect(mgr, dst);
+}
+EXPORT_SYMBOL(dss_mgr_connect);
+
+void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *dst)
+{
+ dss_mgr_ops->disconnect(mgr, dst);
+}
+EXPORT_SYMBOL(dss_mgr_disconnect);
+
+void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
+ const struct omap_video_timings *timings)
+{
+ dss_mgr_ops->set_timings(mgr, timings);
+}
+EXPORT_SYMBOL(dss_mgr_set_timings);
+
+void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
+ const struct dss_lcd_mgr_config *config)
+{
+ dss_mgr_ops->set_lcd_config(mgr, config);
+}
+EXPORT_SYMBOL(dss_mgr_set_lcd_config);
+
+int dss_mgr_enable(struct omap_overlay_manager *mgr)
+{
+ return dss_mgr_ops->enable(mgr);
+}
+EXPORT_SYMBOL(dss_mgr_enable);
+
+void dss_mgr_disable(struct omap_overlay_manager *mgr)
+{
+ dss_mgr_ops->disable(mgr);
+}
+EXPORT_SYMBOL(dss_mgr_disable);
+
+void dss_mgr_start_update(struct omap_overlay_manager *mgr)
+{
+ dss_mgr_ops->start_update(mgr);
+}
+EXPORT_SYMBOL(dss_mgr_start_update);
+
+int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
+ void (*handler)(void *), void *data)
+{
+ return dss_mgr_ops->register_framedone_handler(mgr, handler, data);
+}
+EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
+
+void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
+ void (*handler)(void *), void *data)
+{
+ dss_mgr_ops->unregister_framedone_handler(mgr, handler, data);
+}
+EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
new file mode 100644
index 000000000000..4cc5ddebfb34
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "OVERLAY"
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
+}
+
+static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ovl->manager ? ovl->manager->name : "<none>");
+}
+
+static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
+ size_t size)
+{
+ int i, r;
+ struct omap_overlay_manager *mgr = NULL;
+ struct omap_overlay_manager *old_mgr;
+ int len = size;
+
+ if (buf[size-1] == '\n')
+ --len;
+
+ if (len > 0) {
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ mgr = omap_dss_get_overlay_manager(i);
+
+ if (sysfs_streq(buf, mgr->name))
+ break;
+
+ mgr = NULL;
+ }
+ }
+
+ if (len > 0 && mgr == NULL)
+ return -EINVAL;
+
+ if (mgr)
+ DSSDBG("manager %s found\n", mgr->name);
+
+ if (mgr == ovl->manager)
+ return size;
+
+ old_mgr = ovl->manager;
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ /* detach old manager */
+ if (old_mgr) {
+ r = ovl->unset_manager(ovl);
+ if (r) {
+ DSSERR("detach failed\n");
+ goto err;
+ }
+
+ r = old_mgr->apply(old_mgr);
+ if (r)
+ goto err;
+ }
+
+ if (mgr) {
+ r = ovl->set_manager(ovl, mgr);
+ if (r) {
+ DSSERR("Failed to attach overlay\n");
+ goto err;
+ }
+
+ r = mgr->apply(mgr);
+ if (r)
+ goto err;
+ }
+
+ dispc_runtime_put();
+
+ return size;
+
+err:
+ dispc_runtime_put();
+ return r;
+}
+
+static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.width, info.height);
+}
+
+static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
+}
+
+static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.pos_x, info.pos_y);
+}
+
+static ssize_t overlay_position_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ char *last;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.pos_x = simple_strtoul(buf, &last, 10);
+ ++last;
+ if (last - buf >= size)
+ return -EINVAL;
+
+ info.pos_y = simple_strtoul(last, &last, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.out_width, info.out_height);
+}
+
+static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ char *last;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.out_width = simple_strtoul(buf, &last, 10);
+ ++last;
+ if (last - buf >= size)
+ return -EINVAL;
+
+ info.out_height = simple_strtoul(last, &last, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
+}
+
+static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
+ size_t size)
+{
+ int r;
+ bool enable;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ if (enable)
+ r = ovl->enable(ovl);
+ else
+ r = ovl->disable(ovl);
+
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.global_alpha);
+}
+
+static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 alpha;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &alpha);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.global_alpha = alpha;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
+ char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.pre_mult_alpha);
+}
+
+static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 alpha;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &alpha);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.pre_mult_alpha = alpha;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 zorder;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &zorder);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.zorder = zorder;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+struct overlay_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_overlay *, char *);
+ ssize_t (*store)(struct omap_overlay *, const char *, size_t);
+};
+
+#define OVERLAY_ATTR(_name, _mode, _show, _store) \
+ struct overlay_attribute overlay_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
+static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
+ overlay_manager_show, overlay_manager_store);
+static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
+static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
+static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
+ overlay_position_show, overlay_position_store);
+static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
+ overlay_output_size_show, overlay_output_size_store);
+static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
+ overlay_enabled_show, overlay_enabled_store);
+static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
+ overlay_global_alpha_show, overlay_global_alpha_store);
+static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
+ overlay_pre_mult_alpha_show,
+ overlay_pre_mult_alpha_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+ overlay_zorder_show, overlay_zorder_store);
+
+static struct attribute *overlay_sysfs_attrs[] = {
+ &overlay_attr_name.attr,
+ &overlay_attr_manager.attr,
+ &overlay_attr_input_size.attr,
+ &overlay_attr_screen_width.attr,
+ &overlay_attr_position.attr,
+ &overlay_attr_output_size.attr,
+ &overlay_attr_enabled.attr,
+ &overlay_attr_global_alpha.attr,
+ &overlay_attr_pre_mult_alpha.attr,
+ &overlay_attr_zorder.attr,
+ NULL
+};
+
+static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_overlay *overlay;
+ struct overlay_attribute *overlay_attr;
+
+ overlay = container_of(kobj, struct omap_overlay, kobj);
+ overlay_attr = container_of(attr, struct overlay_attribute, attr);
+
+ if (!overlay_attr->show)
+ return -ENOENT;
+
+ return overlay_attr->show(overlay, buf);
+}
+
+static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay *overlay;
+ struct overlay_attribute *overlay_attr;
+
+ overlay = container_of(kobj, struct omap_overlay, kobj);
+ overlay_attr = container_of(attr, struct overlay_attribute, attr);
+
+ if (!overlay_attr->store)
+ return -ENOENT;
+
+ return overlay_attr->store(overlay, buf, size);
+}
+
+static const struct sysfs_ops overlay_sysfs_ops = {
+ .show = overlay_attr_show,
+ .store = overlay_attr_store,
+};
+
+static struct kobj_type overlay_ktype = {
+ .sysfs_ops = &overlay_sysfs_ops,
+ .default_attrs = overlay_sysfs_attrs,
+};
+
+int dss_overlay_kobj_init(struct omap_overlay *ovl,
+ struct platform_device *pdev)
+{
+ return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
+ &pdev->dev.kobj, "overlay%d", ovl->id);
+}
+
+void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
+{
+ kobject_del(&ovl->kobj);
+ kobject_put(&ovl->kobj);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c
new file mode 100644
index 000000000000..2f7cee985cdd
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c
@@ -0,0 +1,202 @@
+/*
+ * linux/drivers/video/omap2/dss/overlay.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "OVERLAY"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static int num_overlays;
+static struct omap_overlay *overlays;
+
+int omap_dss_get_num_overlays(void)
+{
+ return num_overlays;
+}
+EXPORT_SYMBOL(omap_dss_get_num_overlays);
+
+struct omap_overlay *omap_dss_get_overlay(int num)
+{
+ if (num >= num_overlays)
+ return NULL;
+
+ return &overlays[num];
+}
+EXPORT_SYMBOL(omap_dss_get_overlay);
+
+void dss_init_overlays(struct platform_device *pdev)
+{
+ int i, r;
+
+ num_overlays = dss_feat_get_num_ovls();
+
+ overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
+ GFP_KERNEL);
+
+ BUG_ON(overlays == NULL);
+
+ for (i = 0; i < num_overlays; ++i) {
+ struct omap_overlay *ovl = &overlays[i];
+
+ switch (i) {
+ case 0:
+ ovl->name = "gfx";
+ ovl->id = OMAP_DSS_GFX;
+ break;
+ case 1:
+ ovl->name = "vid1";
+ ovl->id = OMAP_DSS_VIDEO1;
+ break;
+ case 2:
+ ovl->name = "vid2";
+ ovl->id = OMAP_DSS_VIDEO2;
+ break;
+ case 3:
+ ovl->name = "vid3";
+ ovl->id = OMAP_DSS_VIDEO3;
+ break;
+ }
+
+ ovl->caps = dss_feat_get_overlay_caps(ovl->id);
+ ovl->supported_modes =
+ dss_feat_get_supported_color_modes(ovl->id);
+
+ r = dss_overlay_kobj_init(ovl, pdev);
+ if (r)
+ DSSERR("failed to create sysfs file\n");
+ }
+}
+
+void dss_uninit_overlays(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < num_overlays; ++i) {
+ struct omap_overlay *ovl = &overlays[i];
+ dss_overlay_kobj_uninit(ovl);
+ }
+
+ kfree(overlays);
+ overlays = NULL;
+ num_overlays = 0;
+}
+
+int dss_ovl_simple_check(struct omap_overlay *ovl,
+ const struct omap_overlay_info *info)
+{
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
+ if (info->out_width != 0 && info->width != info->out_width) {
+ DSSERR("check_overlay: overlay %d doesn't support "
+ "scaling\n", ovl->id);
+ return -EINVAL;
+ }
+
+ if (info->out_height != 0 && info->height != info->out_height) {
+ DSSERR("check_overlay: overlay %d doesn't support "
+ "scaling\n", ovl->id);
+ return -EINVAL;
+ }
+ }
+
+ if ((ovl->supported_modes & info->color_mode) == 0) {
+ DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
+ ovl->id, info->color_mode);
+ return -EINVAL;
+ }
+
+ if (info->zorder >= omap_dss_get_num_overlays()) {
+ DSSERR("check_overlay: zorder %d too high\n", info->zorder);
+ return -EINVAL;
+ }
+
+ if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
+ DSSERR("check_overlay: rotation type %d not supported\n",
+ info->rotation_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
+ const struct omap_video_timings *mgr_timings)
+{
+ u16 outw, outh;
+ u16 dw, dh;
+
+ dw = mgr_timings->x_res;
+ dh = mgr_timings->y_res;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
+ outw = info->width;
+ outh = info->height;
+ } else {
+ if (info->out_width == 0)
+ outw = info->width;
+ else
+ outw = info->out_width;
+
+ if (info->out_height == 0)
+ outh = info->height;
+ else
+ outh = info->out_height;
+ }
+
+ if (dw < info->pos_x + outw) {
+ DSSERR("overlay %d horizontally not inside the display area "
+ "(%d + %d >= %d)\n",
+ ovl->id, info->pos_x, outw, dw);
+ return -EINVAL;
+ }
+
+ if (dh < info->pos_y + outh) {
+ DSSERR("overlay %d vertically not inside the display area "
+ "(%d + %d >= %d)\n",
+ ovl->id, info->pos_y, outh, dh);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Checks if replication logic should be used. Only use when overlay is in
+ * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp
+ */
+bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
+ enum omap_color_mode mode)
+{
+ if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
+ return false;
+
+ return config.video_port_width > 16;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/pll.c b/drivers/video/fbdev/omap2/omapfb/dss/pll.c
new file mode 100644
index 000000000000..f974ddcd3b6e
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/pll.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2014 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 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "PLL"
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+#define PLL_CONTROL 0x0000
+#define PLL_STATUS 0x0004
+#define PLL_GO 0x0008
+#define PLL_CONFIGURATION1 0x000C
+#define PLL_CONFIGURATION2 0x0010
+#define PLL_CONFIGURATION3 0x0014
+#define PLL_SSC_CONFIGURATION1 0x0018
+#define PLL_SSC_CONFIGURATION2 0x001C
+#define PLL_CONFIGURATION4 0x0020
+
+static struct dss_pll *dss_plls[4];
+
+int dss_pll_register(struct dss_pll *pll)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+ if (!dss_plls[i]) {
+ dss_plls[i] = pll;
+ return 0;
+ }
+ }
+
+ return -EBUSY;
+}
+
+void dss_pll_unregister(struct dss_pll *pll)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+ if (dss_plls[i] == pll) {
+ dss_plls[i] = NULL;
+ return;
+ }
+ }
+}
+
+struct dss_pll *dss_pll_find(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+ if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)
+ return dss_plls[i];
+ }
+
+ return NULL;
+}
+
+int dss_pll_enable(struct dss_pll *pll)
+{
+ int r;
+
+ r = clk_prepare_enable(pll->clkin);
+ if (r)
+ return r;
+
+ if (pll->regulator) {
+ r = regulator_enable(pll->regulator);
+ if (r)
+ goto err_reg;
+ }
+
+ r = pll->ops->enable(pll);
+ if (r)
+ goto err_enable;
+
+ return 0;
+
+err_enable:
+ if (pll->regulator)
+ regulator_disable(pll->regulator);
+err_reg:
+ clk_disable_unprepare(pll->clkin);
+ return r;
+}
+
+void dss_pll_disable(struct dss_pll *pll)
+{
+ pll->ops->disable(pll);
+
+ if (pll->regulator)
+ regulator_disable(pll->regulator);
+
+ clk_disable_unprepare(pll->clkin);
+
+ memset(&pll->cinfo, 0, sizeof(pll->cinfo));
+}
+
+int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)
+{
+ int r;
+
+ r = pll->ops->set_config(pll, cinfo);
+ if (r)
+ return r;
+
+ pll->cinfo = *cinfo;
+
+ return 0;
+}
+
+bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
+ unsigned long out_min, unsigned long out_max,
+ dss_hsdiv_calc_func func, void *data)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ int m, m_start, m_stop;
+ unsigned long out;
+
+ out_min = out_min ? out_min : 1;
+ out_max = out_max ? out_max : ULONG_MAX;
+
+ m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);
+
+ m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);
+
+ for (m = m_start; m <= m_stop; ++m) {
+ out = clkdco / m;
+
+ if (func(m, out, data))
+ return true;
+ }
+
+ return false;
+}
+
+bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dss_pll_calc_func func, void *data)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ int n, n_start, n_stop;
+ int m, m_start, m_stop;
+ unsigned long fint, clkdco;
+ unsigned long pll_hw_max;
+ unsigned long fint_hw_min, fint_hw_max;
+
+ pll_hw_max = hw->clkdco_max;
+
+ fint_hw_min = hw->fint_min;
+ fint_hw_max = hw->fint_max;
+
+ n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+ n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
+
+ pll_max = pll_max ? pll_max : ULONG_MAX;
+
+ for (n = n_start; n <= n_stop; ++n) {
+ fint = clkin / n;
+
+ m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+ 1ul);
+ m_stop = min3((unsigned)(pll_max / fint / 2),
+ (unsigned)(pll_hw_max / fint / 2),
+ hw->m_max);
+
+ for (m = m_start; m <= m_stop; ++m) {
+ clkdco = 2 * m * fint;
+
+ if (func(n, m, fint, clkdco, data))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
+{
+ unsigned long timeout;
+ ktime_t wait;
+ int t;
+
+ /* first busyloop to see if the bit changes right away */
+ t = 100;
+ while (t-- > 0) {
+ if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
+ return value;
+ }
+
+ /* then loop for 500ms, sleeping for 1ms in between */
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (time_before(jiffies, timeout)) {
+ if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
+ return value;
+
+ wait = ns_to_ktime(1000 * 1000);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+ }
+
+ return !value;
+}
+
+int dss_pll_wait_reset_done(struct dss_pll *pll)
+{
+ void __iomem *base = pll->base;
+
+ if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)
+ return -ETIMEDOUT;
+ else
+ return 0;
+}
+
+static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
+{
+ int t = 100;
+
+ while (t-- > 0) {
+ u32 v = readl_relaxed(pll->base + PLL_STATUS);
+ v &= hsdiv_ack_mask;
+ if (v == hsdiv_ack_mask)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+int dss_pll_write_config_type_a(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ void __iomem *base = pll->base;
+ int r = 0;
+ u32 l;
+
+ l = 0;
+ if (hw->has_stopmode)
+ l = FLD_MOD(l, 1, 0, 0); /* PLL_STOPMODE */
+ l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb); /* PLL_REGN */
+ l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb); /* PLL_REGM */
+ /* M4 */
+ l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,
+ hw->mX_msb[0], hw->mX_lsb[0]);
+ /* M5 */
+ l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,
+ hw->mX_msb[1], hw->mX_lsb[1]);
+ writel_relaxed(l, base + PLL_CONFIGURATION1);
+
+ l = 0;
+ /* M6 */
+ l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,
+ hw->mX_msb[2], hw->mX_lsb[2]);
+ /* M7 */
+ l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,
+ hw->mX_msb[3], hw->mX_lsb[3]);
+ writel_relaxed(l, base + PLL_CONFIGURATION3);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION2);
+ if (hw->has_freqsel) {
+ u32 f = cinfo->fint < 1000000 ? 0x3 :
+ cinfo->fint < 1250000 ? 0x4 :
+ cinfo->fint < 1500000 ? 0x5 :
+ cinfo->fint < 1750000 ? 0x6 :
+ 0x7;
+
+ l = FLD_MOD(l, f, 4, 1); /* PLL_FREQSEL */
+ } else if (hw->has_selfreqdco) {
+ u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;
+
+ l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
+ }
+ l = FLD_MOD(l, 1, 13, 13); /* PLL_REFEN */
+ l = FLD_MOD(l, 0, 14, 14); /* PHY_CLKINEN */
+ l = FLD_MOD(l, 0, 16, 16); /* M4_CLOCK_EN */
+ l = FLD_MOD(l, 0, 18, 18); /* M5_CLOCK_EN */
+ l = FLD_MOD(l, 1, 20, 20); /* HSDIVBYPASS */
+ if (hw->has_refsel)
+ l = FLD_MOD(l, 3, 22, 21); /* REFSEL = sysclk */
+ l = FLD_MOD(l, 0, 23, 23); /* M6_CLOCK_EN */
+ l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
+ writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+ writel_relaxed(1, base + PLL_GO); /* PLL_GO */
+
+ if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+ DSSERR("DSS DPLL GO bit not going down.\n");
+ r = -EIO;
+ goto err;
+ }
+
+ if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+ DSSERR("cannot lock DSS DPLL\n");
+ r = -EIO;
+ goto err;
+ }
+
+ l = readl_relaxed(base + PLL_CONFIGURATION2);
+ l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
+ l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16); /* M4_CLOCK_EN */
+ l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18); /* M5_CLOCK_EN */
+ l = FLD_MOD(l, 0, 20, 20); /* HSDIVBYPASS */
+ l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23); /* M6_CLOCK_EN */
+ l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25); /* M7_CLOCK_EN */
+ writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+ r = dss_wait_hsdiv_ack(pll,
+ (cinfo->mX[0] ? BIT(7) : 0) |
+ (cinfo->mX[1] ? BIT(8) : 0) |
+ (cinfo->mX[2] ? BIT(10) : 0) |
+ (cinfo->mX[3] ? BIT(11) : 0));
+ if (r) {
+ DSSERR("failed to enable HSDIV clocks\n");
+ goto err;
+ }
+
+err:
+ return r;
+}
+
+int dss_pll_write_config_type_b(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ void __iomem *base = pll->base;
+ u32 l;
+
+ l = 0;
+ l = FLD_MOD(l, cinfo->m, 20, 9); /* PLL_REGM */
+ l = FLD_MOD(l, cinfo->n - 1, 8, 1); /* PLL_REGN */
+ writel_relaxed(l, base + PLL_CONFIGURATION1);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION2);
+ l = FLD_MOD(l, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
+ l = FLD_MOD(l, 0x1, 13, 13); /* PLL_REFEN */
+ l = FLD_MOD(l, 0x0, 14, 14); /* PHY_CLKINEN */
+ if (hw->has_refsel)
+ l = FLD_MOD(l, 0x3, 22, 21); /* REFSEL = SYSCLK */
+
+ /* PLL_SELFREQDCO */
+ if (cinfo->clkdco > hw->clkdco_low)
+ l = FLD_MOD(l, 0x4, 3, 1);
+ else
+ l = FLD_MOD(l, 0x2, 3, 1);
+ writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION3);
+ l = FLD_MOD(l, cinfo->sd, 17, 10); /* PLL_REGSD */
+ writel_relaxed(l, base + PLL_CONFIGURATION3);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION4);
+ l = FLD_MOD(l, cinfo->mX[0], 24, 18); /* PLL_REGM2 */
+ l = FLD_MOD(l, cinfo->mf, 17, 0); /* PLL_REGM_F */
+ writel_relaxed(l, base + PLL_CONFIGURATION4);
+
+ writel_relaxed(1, base + PLL_GO); /* PLL_GO */
+
+ if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+ DSSERR("DSS DPLL GO bit not going down.\n");
+ return -EIO;
+ }
+
+ if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+ DSSERR("cannot lock DSS DPLL\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c b/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c
new file mode 100644
index 000000000000..aea6a1d0fb20
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c
@@ -0,0 +1,1078 @@
+/*
+ * linux/drivers/video/omap2/dss/rfbi.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "RFBI"
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/kfifo.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/seq_file.h>
+#include <linux/semaphore.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+#include "dss.h"
+
+struct rfbi_reg { u16 idx; };
+
+#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
+
+#define RFBI_REVISION RFBI_REG(0x0000)
+#define RFBI_SYSCONFIG RFBI_REG(0x0010)
+#define RFBI_SYSSTATUS RFBI_REG(0x0014)
+#define RFBI_CONTROL RFBI_REG(0x0040)
+#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
+#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
+#define RFBI_CMD RFBI_REG(0x004c)
+#define RFBI_PARAM RFBI_REG(0x0050)
+#define RFBI_DATA RFBI_REG(0x0054)
+#define RFBI_READ RFBI_REG(0x0058)
+#define RFBI_STATUS RFBI_REG(0x005c)
+
+#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
+#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
+#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
+#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
+#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
+#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
+
+#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
+#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
+
+#define REG_FLD_MOD(idx, val, start, end) \
+ rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
+
+enum omap_rfbi_cycleformat {
+ OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
+ OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
+ OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
+ OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
+};
+
+enum omap_rfbi_datatype {
+ OMAP_DSS_RFBI_DATATYPE_12 = 0,
+ OMAP_DSS_RFBI_DATATYPE_16 = 1,
+ OMAP_DSS_RFBI_DATATYPE_18 = 2,
+ OMAP_DSS_RFBI_DATATYPE_24 = 3,
+};
+
+enum omap_rfbi_parallelmode {
+ OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
+ OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
+ OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
+ OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
+};
+
+static int rfbi_convert_timings(struct rfbi_timings *t);
+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
+
+static struct {
+ struct platform_device *pdev;
+ void __iomem *base;
+
+ unsigned long l4_khz;
+
+ enum omap_rfbi_datatype datatype;
+ enum omap_rfbi_parallelmode parallelmode;
+
+ enum omap_rfbi_te_mode te_mode;
+ int te_enabled;
+
+ void (*framedone_callback)(void *data);
+ void *framedone_callback_data;
+
+ struct omap_dss_device *dssdev[2];
+
+ struct semaphore bus_lock;
+
+ struct omap_video_timings timings;
+ int pixel_size;
+ int data_lines;
+ struct rfbi_timings intf_timings;
+
+ struct omap_dss_device output;
+} rfbi;
+
+static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
+{
+ __raw_writel(val, rfbi.base + idx.idx);
+}
+
+static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
+{
+ return __raw_readl(rfbi.base + idx.idx);
+}
+
+static int rfbi_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("rfbi_runtime_get\n");
+
+ r = pm_runtime_get_sync(&rfbi.pdev->dev);
+ WARN_ON(r < 0);
+ return r < 0 ? r : 0;
+}
+
+static void rfbi_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("rfbi_runtime_put\n");
+
+ r = pm_runtime_put_sync(&rfbi.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static void rfbi_bus_lock(void)
+{
+ down(&rfbi.bus_lock);
+}
+
+static void rfbi_bus_unlock(void)
+{
+ up(&rfbi.bus_lock);
+}
+
+static void rfbi_write_command(const void *buf, u32 len)
+{
+ switch (rfbi.parallelmode) {
+ case OMAP_DSS_RFBI_PARALLELMODE_8:
+ {
+ const u8 *b = buf;
+ for (; len; len--)
+ rfbi_write_reg(RFBI_CMD, *b++);
+ break;
+ }
+
+ case OMAP_DSS_RFBI_PARALLELMODE_16:
+ {
+ const u16 *w = buf;
+ BUG_ON(len & 1);
+ for (; len; len -= 2)
+ rfbi_write_reg(RFBI_CMD, *w++);
+ break;
+ }
+
+ case OMAP_DSS_RFBI_PARALLELMODE_9:
+ case OMAP_DSS_RFBI_PARALLELMODE_12:
+ default:
+ BUG();
+ }
+}
+
+static void rfbi_read_data(void *buf, u32 len)
+{
+ switch (rfbi.parallelmode) {
+ case OMAP_DSS_RFBI_PARALLELMODE_8:
+ {
+ u8 *b = buf;
+ for (; len; len--) {
+ rfbi_write_reg(RFBI_READ, 0);
+ *b++ = rfbi_read_reg(RFBI_READ);
+ }
+ break;
+ }
+
+ case OMAP_DSS_RFBI_PARALLELMODE_16:
+ {
+ u16 *w = buf;
+ BUG_ON(len & ~1);
+ for (; len; len -= 2) {
+ rfbi_write_reg(RFBI_READ, 0);
+ *w++ = rfbi_read_reg(RFBI_READ);
+ }
+ break;
+ }
+
+ case OMAP_DSS_RFBI_PARALLELMODE_9:
+ case OMAP_DSS_RFBI_PARALLELMODE_12:
+ default:
+ BUG();
+ }
+}
+
+static void rfbi_write_data(const void *buf, u32 len)
+{
+ switch (rfbi.parallelmode) {
+ case OMAP_DSS_RFBI_PARALLELMODE_8:
+ {
+ const u8 *b = buf;
+ for (; len; len--)
+ rfbi_write_reg(RFBI_PARAM, *b++);
+ break;
+ }
+
+ case OMAP_DSS_RFBI_PARALLELMODE_16:
+ {
+ const u16 *w = buf;
+ BUG_ON(len & 1);
+ for (; len; len -= 2)
+ rfbi_write_reg(RFBI_PARAM, *w++);
+ break;
+ }
+
+ case OMAP_DSS_RFBI_PARALLELMODE_9:
+ case OMAP_DSS_RFBI_PARALLELMODE_12:
+ default:
+ BUG();
+
+ }
+}
+
+static void rfbi_write_pixels(const void __iomem *buf, int scr_width,
+ u16 x, u16 y,
+ u16 w, u16 h)
+{
+ int start_offset = scr_width * y + x;
+ int horiz_offset = scr_width - w;
+ int i;
+
+ if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
+ rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
+ const u16 __iomem *pd = buf;
+ pd += start_offset;
+
+ for (; h; --h) {
+ for (i = 0; i < w; ++i) {
+ const u8 __iomem *b = (const u8 __iomem *)pd;
+ rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
+ rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
+ ++pd;
+ }
+ pd += horiz_offset;
+ }
+ } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
+ rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
+ const u32 __iomem *pd = buf;
+ pd += start_offset;
+
+ for (; h; --h) {
+ for (i = 0; i < w; ++i) {
+ const u8 __iomem *b = (const u8 __iomem *)pd;
+ rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
+ rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
+ rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
+ ++pd;
+ }
+ pd += horiz_offset;
+ }
+ } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
+ rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
+ const u16 __iomem *pd = buf;
+ pd += start_offset;
+
+ for (; h; --h) {
+ for (i = 0; i < w; ++i) {
+ rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
+ ++pd;
+ }
+ pd += horiz_offset;
+ }
+ } else {
+ BUG();
+ }
+}
+
+static int rfbi_transfer_area(struct omap_dss_device *dssdev,
+ void (*callback)(void *data), void *data)
+{
+ u32 l;
+ int r;
+ struct omap_overlay_manager *mgr = rfbi.output.manager;
+ u16 width = rfbi.timings.x_res;
+ u16 height = rfbi.timings.y_res;
+
+ /*BUG_ON(callback == 0);*/
+ BUG_ON(rfbi.framedone_callback != NULL);
+
+ DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
+
+ dss_mgr_set_timings(mgr, &rfbi.timings);
+
+ r = dss_mgr_enable(mgr);
+ if (r)
+ return r;
+
+ rfbi.framedone_callback = callback;
+ rfbi.framedone_callback_data = data;
+
+ rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
+
+ l = rfbi_read_reg(RFBI_CONTROL);
+ l = FLD_MOD(l, 1, 0, 0); /* enable */
+ if (!rfbi.te_enabled)
+ l = FLD_MOD(l, 1, 4, 4); /* ITE */
+
+ rfbi_write_reg(RFBI_CONTROL, l);
+
+ return 0;
+}
+
+static void framedone_callback(void *data)
+{
+ void (*callback)(void *data);
+
+ DSSDBG("FRAMEDONE\n");
+
+ REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
+
+ callback = rfbi.framedone_callback;
+ rfbi.framedone_callback = NULL;
+
+ if (callback != NULL)
+ callback(rfbi.framedone_callback_data);
+}
+
+#if 1 /* VERBOSE */
+static void rfbi_print_timings(void)
+{
+ u32 l;
+ u32 time;
+
+ l = rfbi_read_reg(RFBI_CONFIG(0));
+ time = 1000000000 / rfbi.l4_khz;
+ if (l & (1 << 4))
+ time *= 2;
+
+ DSSDBG("Tick time %u ps\n", time);
+ l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
+ DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
+ "REONTIME %d, REOFFTIME %d\n",
+ l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
+ (l >> 20) & 0x0f, (l >> 24) & 0x3f);
+
+ l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
+ DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
+ "ACCESSTIME %d\n",
+ (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
+ (l >> 22) & 0x3f);
+}
+#else
+static void rfbi_print_timings(void) {}
+#endif
+
+
+
+
+static u32 extif_clk_period;
+
+static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
+{
+ int bus_tick = extif_clk_period * div;
+ return (ps + bus_tick - 1) / bus_tick * bus_tick;
+}
+
+static int calc_reg_timing(struct rfbi_timings *t, int div)
+{
+ t->clk_div = div;
+
+ t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
+
+ t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
+ t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
+ t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
+
+ t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
+ t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
+ t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
+
+ t->access_time = round_to_extif_ticks(t->access_time, div);
+ t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
+ t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
+
+ DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ DSSDBG("[reg]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return rfbi_convert_timings(t);
+}
+
+static int calc_extif_timings(struct rfbi_timings *t)
+{
+ u32 max_clk_div;
+ int div;
+
+ rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
+ for (div = 1; div <= max_clk_div; div++) {
+ if (calc_reg_timing(t, div) == 0)
+ break;
+ }
+
+ if (div <= max_clk_div)
+ return 0;
+
+ DSSERR("can't setup timings\n");
+ return -1;
+}
+
+
+static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
+{
+ int r;
+
+ if (!t->converted) {
+ r = calc_extif_timings(t);
+ if (r < 0)
+ DSSERR("Failed to calc timings\n");
+ }
+
+ BUG_ON(!t->converted);
+
+ rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
+ rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
+
+ /* TIMEGRANULARITY */
+ REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
+ (t->tim[2] ? 1 : 0), 4, 4);
+
+ rfbi_print_timings();
+}
+
+static int ps_to_rfbi_ticks(int time, int div)
+{
+ unsigned long tick_ps;
+ int ret;
+
+ /* Calculate in picosecs to yield more exact results */
+ tick_ps = 1000000000 / (rfbi.l4_khz) * div;
+
+ ret = (time + tick_ps - 1) / tick_ps;
+
+ return ret;
+}
+
+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+ *clk_period = 1000000000 / rfbi.l4_khz;
+ *max_clk_div = 2;
+}
+
+static int rfbi_convert_timings(struct rfbi_timings *t)
+{
+ u32 l;
+ int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
+ int actim, recyc, wecyc;
+ int div = t->clk_div;
+
+ if (div <= 0 || div > 2)
+ return -1;
+
+ /* Make sure that after conversion it still holds that:
+ * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
+ * csoff > cson, csoff >= max(weoff, reoff), actim > reon
+ */
+ weon = ps_to_rfbi_ticks(t->we_on_time, div);
+ weoff = ps_to_rfbi_ticks(t->we_off_time, div);
+ if (weoff <= weon)
+ weoff = weon + 1;
+ if (weon > 0x0f)
+ return -1;
+ if (weoff > 0x3f)
+ return -1;
+
+ reon = ps_to_rfbi_ticks(t->re_on_time, div);
+ reoff = ps_to_rfbi_ticks(t->re_off_time, div);
+ if (reoff <= reon)
+ reoff = reon + 1;
+ if (reon > 0x0f)
+ return -1;
+ if (reoff > 0x3f)
+ return -1;
+
+ cson = ps_to_rfbi_ticks(t->cs_on_time, div);
+ csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
+ if (csoff <= cson)
+ csoff = cson + 1;
+ if (csoff < max(weoff, reoff))
+ csoff = max(weoff, reoff);
+ if (cson > 0x0f)
+ return -1;
+ if (csoff > 0x3f)
+ return -1;
+
+ l = cson;
+ l |= csoff << 4;
+ l |= weon << 10;
+ l |= weoff << 14;
+ l |= reon << 20;
+ l |= reoff << 24;
+
+ t->tim[0] = l;
+
+ actim = ps_to_rfbi_ticks(t->access_time, div);
+ if (actim <= reon)
+ actim = reon + 1;
+ if (actim > 0x3f)
+ return -1;
+
+ wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
+ if (wecyc < weoff)
+ wecyc = weoff;
+ if (wecyc > 0x3f)
+ return -1;
+
+ recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
+ if (recyc < reoff)
+ recyc = reoff;
+ if (recyc > 0x3f)
+ return -1;
+
+ cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
+ if (cs_pulse > 0x3f)
+ return -1;
+
+ l = wecyc;
+ l |= recyc << 6;
+ l |= cs_pulse << 12;
+ l |= actim << 22;
+
+ t->tim[1] = l;
+
+ t->tim[2] = div - 1;
+
+ t->converted = 1;
+
+ return 0;
+}
+
+/* xxx FIX module selection missing */
+static int rfbi_setup_te(enum omap_rfbi_te_mode mode,
+ unsigned hs_pulse_time, unsigned vs_pulse_time,
+ int hs_pol_inv, int vs_pol_inv, int extif_div)
+{
+ int hs, vs;
+ int min;
+ u32 l;
+
+ hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
+ vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
+ if (hs < 2)
+ return -EDOM;
+ if (mode == OMAP_DSS_RFBI_TE_MODE_2)
+ min = 2;
+ else /* OMAP_DSS_RFBI_TE_MODE_1 */
+ min = 4;
+ if (vs < min)
+ return -EDOM;
+ if (vs == hs)
+ return -EINVAL;
+ rfbi.te_mode = mode;
+ DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
+ mode, hs, vs, hs_pol_inv, vs_pol_inv);
+
+ rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
+ rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
+
+ l = rfbi_read_reg(RFBI_CONFIG(0));
+ if (hs_pol_inv)
+ l &= ~(1 << 21);
+ else
+ l |= 1 << 21;
+ if (vs_pol_inv)
+ l &= ~(1 << 20);
+ else
+ l |= 1 << 20;
+
+ return 0;
+}
+
+/* xxx FIX module selection missing */
+static int rfbi_enable_te(bool enable, unsigned line)
+{
+ u32 l;
+
+ DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
+ if (line > (1 << 11) - 1)
+ return -EINVAL;
+
+ l = rfbi_read_reg(RFBI_CONFIG(0));
+ l &= ~(0x3 << 2);
+ if (enable) {
+ rfbi.te_enabled = 1;
+ l |= rfbi.te_mode << 2;
+ } else
+ rfbi.te_enabled = 0;
+ rfbi_write_reg(RFBI_CONFIG(0), l);
+ rfbi_write_reg(RFBI_LINE_NUMBER, line);
+
+ return 0;
+}
+
+static int rfbi_configure_bus(int rfbi_module, int bpp, int lines)
+{
+ u32 l;
+ int cycle1 = 0, cycle2 = 0, cycle3 = 0;
+ enum omap_rfbi_cycleformat cycleformat;
+ enum omap_rfbi_datatype datatype;
+ enum omap_rfbi_parallelmode parallelmode;
+
+ switch (bpp) {
+ case 12:
+ datatype = OMAP_DSS_RFBI_DATATYPE_12;
+ break;
+ case 16:
+ datatype = OMAP_DSS_RFBI_DATATYPE_16;
+ break;
+ case 18:
+ datatype = OMAP_DSS_RFBI_DATATYPE_18;
+ break;
+ case 24:
+ datatype = OMAP_DSS_RFBI_DATATYPE_24;
+ break;
+ default:
+ BUG();
+ return 1;
+ }
+ rfbi.datatype = datatype;
+
+ switch (lines) {
+ case 8:
+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
+ break;
+ case 9:
+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
+ break;
+ case 12:
+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
+ break;
+ case 16:
+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
+ break;
+ default:
+ BUG();
+ return 1;
+ }
+ rfbi.parallelmode = parallelmode;
+
+ if ((bpp % lines) == 0) {
+ switch (bpp / lines) {
+ case 1:
+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
+ break;
+ case 2:
+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
+ break;
+ case 3:
+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
+ break;
+ default:
+ BUG();
+ return 1;
+ }
+ } else if ((2 * bpp % lines) == 0) {
+ if ((2 * bpp / lines) == 3)
+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
+ else {
+ BUG();
+ return 1;
+ }
+ } else {
+ BUG();
+ return 1;
+ }
+
+ switch (cycleformat) {
+ case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
+ cycle1 = lines;
+ break;
+
+ case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
+ cycle1 = lines;
+ cycle2 = lines;
+ break;
+
+ case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
+ cycle1 = lines;
+ cycle2 = lines;
+ cycle3 = lines;
+ break;
+
+ case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
+ cycle1 = lines;
+ cycle2 = (lines / 2) | ((lines / 2) << 16);
+ cycle3 = (lines << 16);
+ break;
+ }
+
+ REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
+
+ l = 0;
+ l |= FLD_VAL(parallelmode, 1, 0);
+ l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
+ l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
+ l |= FLD_VAL(datatype, 6, 5);
+ /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
+ l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
+ l |= FLD_VAL(cycleformat, 10, 9);
+ l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
+ l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
+ l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
+ l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
+ l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
+ l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
+ l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
+ rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
+
+ rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
+ rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
+ rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
+
+
+ l = rfbi_read_reg(RFBI_CONTROL);
+ l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
+ l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
+ rfbi_write_reg(RFBI_CONTROL, l);
+
+
+ DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
+ bpp, lines, cycle1, cycle2, cycle3);
+
+ return 0;
+}
+
+static int rfbi_configure(struct omap_dss_device *dssdev)
+{
+ return rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
+ rfbi.data_lines);
+}
+
+static int rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
+ void *data)
+{
+ return rfbi_transfer_area(dssdev, callback, data);
+}
+
+static void rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+ rfbi.timings.x_res = w;
+ rfbi.timings.y_res = h;
+}
+
+static void rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
+{
+ rfbi.pixel_size = pixel_size;
+}
+
+static void rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
+{
+ rfbi.data_lines = data_lines;
+}
+
+static void rfbi_set_interface_timings(struct omap_dss_device *dssdev,
+ struct rfbi_timings *timings)
+{
+ rfbi.intf_timings = *timings;
+}
+
+static void rfbi_dump_regs(struct seq_file *s)
+{
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
+
+ if (rfbi_runtime_get())
+ return;
+
+ DUMPREG(RFBI_REVISION);
+ DUMPREG(RFBI_SYSCONFIG);
+ DUMPREG(RFBI_SYSSTATUS);
+ DUMPREG(RFBI_CONTROL);
+ DUMPREG(RFBI_PIXEL_CNT);
+ DUMPREG(RFBI_LINE_NUMBER);
+ DUMPREG(RFBI_CMD);
+ DUMPREG(RFBI_PARAM);
+ DUMPREG(RFBI_DATA);
+ DUMPREG(RFBI_READ);
+ DUMPREG(RFBI_STATUS);
+
+ DUMPREG(RFBI_CONFIG(0));
+ DUMPREG(RFBI_ONOFF_TIME(0));
+ DUMPREG(RFBI_CYCLE_TIME(0));
+ DUMPREG(RFBI_DATA_CYCLE1(0));
+ DUMPREG(RFBI_DATA_CYCLE2(0));
+ DUMPREG(RFBI_DATA_CYCLE3(0));
+
+ DUMPREG(RFBI_CONFIG(1));
+ DUMPREG(RFBI_ONOFF_TIME(1));
+ DUMPREG(RFBI_CYCLE_TIME(1));
+ DUMPREG(RFBI_DATA_CYCLE1(1));
+ DUMPREG(RFBI_DATA_CYCLE2(1));
+ DUMPREG(RFBI_DATA_CYCLE3(1));
+
+ DUMPREG(RFBI_VSYNC_WIDTH);
+ DUMPREG(RFBI_HSYNC_WIDTH);
+
+ rfbi_runtime_put();
+#undef DUMPREG
+}
+
+static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = rfbi.output.manager;
+ struct dss_lcd_mgr_config mgr_config;
+
+ mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
+
+ mgr_config.stallmode = true;
+ /* Do we need fifohandcheck for RFBI? */
+ mgr_config.fifohandcheck = false;
+
+ mgr_config.video_port_width = rfbi.pixel_size;
+ mgr_config.lcden_sig_polarity = 0;
+
+ dss_mgr_set_lcd_config(mgr, &mgr_config);
+
+ /*
+ * Set rfbi.timings with default values, the x_res and y_res fields
+ * are expected to be already configured by the panel driver via
+ * omapdss_rfbi_set_size()
+ */
+ rfbi.timings.hsw = 1;
+ rfbi.timings.hfp = 1;
+ rfbi.timings.hbp = 1;
+ rfbi.timings.vsw = 1;
+ rfbi.timings.vfp = 0;
+ rfbi.timings.vbp = 0;
+
+ rfbi.timings.interlace = false;
+ rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
+
+ dss_mgr_set_timings(mgr, &rfbi.timings);
+}
+
+static int rfbi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &rfbi.output;
+ int r;
+
+ if (out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ return -ENODEV;
+ }
+
+ r = rfbi_runtime_get();
+ if (r)
+ return r;
+
+ r = dss_mgr_register_framedone_handler(out->manager,
+ framedone_callback, NULL);
+ if (r) {
+ DSSERR("can't get FRAMEDONE irq\n");
+ goto err1;
+ }
+
+ rfbi_config_lcd_manager(dssdev);
+
+ rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
+ rfbi.data_lines);
+
+ rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
+
+ return 0;
+err1:
+ rfbi_runtime_put();
+ return r;
+}
+
+static void rfbi_display_disable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &rfbi.output;
+
+ dss_mgr_unregister_framedone_handler(out->manager,
+ framedone_callback, NULL);
+
+ rfbi_runtime_put();
+}
+
+static int rfbi_init_display(struct omap_dss_device *dssdev)
+{
+ rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
+ return 0;
+}
+
+static void rfbi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &rfbi.output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_DBI;
+ out->output_type = OMAP_DISPLAY_TYPE_DBI;
+ out->name = "rfbi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void rfbi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &rfbi.output;
+
+ omapdss_unregister_output(out);
+}
+
+/* RFBI HW IP initialisation */
+static int rfbi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ u32 rev;
+ struct resource *rfbi_mem;
+ struct clk *clk;
+ int r;
+
+ rfbi.pdev = pdev;
+
+ sema_init(&rfbi.bus_lock, 1);
+
+ rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
+ if (!rfbi_mem) {
+ DSSERR("can't get IORESOURCE_MEM RFBI\n");
+ return -EINVAL;
+ }
+
+ rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start,
+ resource_size(rfbi_mem));
+ if (!rfbi.base) {
+ DSSERR("can't ioremap RFBI\n");
+ return -ENOMEM;
+ }
+
+ clk = clk_get(&pdev->dev, "ick");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get ick\n");
+ return PTR_ERR(clk);
+ }
+
+ rfbi.l4_khz = clk_get_rate(clk) / 1000;
+
+ clk_put(clk);
+
+ pm_runtime_enable(&pdev->dev);
+
+ r = rfbi_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ msleep(10);
+
+ rev = rfbi_read_reg(RFBI_REVISION);
+ dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ rfbi_runtime_put();
+
+ dss_debugfs_create_file("rfbi", rfbi_dump_regs);
+
+ rfbi_init_output(pdev);
+
+ return 0;
+
+err_runtime_get:
+ pm_runtime_disable(&pdev->dev);
+ return r;
+}
+
+static void rfbi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ rfbi_uninit_output(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct component_ops rfbi_component_ops = {
+ .bind = rfbi_bind,
+ .unbind = rfbi_unbind,
+};
+
+static int rfbi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &rfbi_component_ops);
+}
+
+static int rfbi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &rfbi_component_ops);
+ return 0;
+}
+
+static int rfbi_runtime_suspend(struct device *dev)
+{
+ dispc_runtime_put();
+
+ return 0;
+}
+
+static int rfbi_runtime_resume(struct device *dev)
+{
+ int r;
+
+ r = dispc_runtime_get();
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static const struct dev_pm_ops rfbi_pm_ops = {
+ .runtime_suspend = rfbi_runtime_suspend,
+ .runtime_resume = rfbi_runtime_resume,
+};
+
+static struct platform_driver omap_rfbihw_driver = {
+ .probe = rfbi_probe,
+ .remove = rfbi_remove,
+ .driver = {
+ .name = "omapdss_rfbi",
+ .pm = &rfbi_pm_ops,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init rfbi_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_rfbihw_driver);
+}
+
+void rfbi_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_rfbihw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c
new file mode 100644
index 000000000000..d747cc6b59e1
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c
@@ -0,0 +1,454 @@
+/*
+ * linux/drivers/video/omap2/dss/sdi.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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/>.
+ */
+
+#define DSS_SUBSYS_NAME "SDI"
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+#include "dss.h"
+
+static struct {
+ struct platform_device *pdev;
+
+ bool update_enabled;
+ struct regulator *vdds_sdi_reg;
+
+ struct dss_lcd_mgr_config mgr_config;
+ struct omap_video_timings timings;
+ int datapairs;
+
+ struct omap_dss_device output;
+
+ bool port_initialized;
+} sdi;
+
+struct sdi_clk_calc_ctx {
+ unsigned long pck_min, pck_max;
+
+ unsigned long fck;
+ struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct sdi_clk_calc_ctx *ctx = data;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ return true;
+}
+
+static bool dpi_calc_dss_cb(unsigned long fck, void *data)
+{
+ struct sdi_clk_calc_ctx *ctx = data;
+
+ ctx->fck = fck;
+
+ return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+static int sdi_calc_clock_div(unsigned long pclk,
+ unsigned long *fck,
+ struct dispc_clock_info *dispc_cinfo)
+{
+ int i;
+ struct sdi_clk_calc_ctx ctx;
+
+ /*
+ * DSS fclk gives us very few possibilities, so finding a good pixel
+ * clock may not be possible. We try multiple times to find the clock,
+ * each time widening the pixel clock range we look for, up to
+ * +/- 1MHz.
+ */
+
+ for (i = 0; i < 10; ++i) {
+ bool ok;
+
+ memset(&ctx, 0, sizeof(ctx));
+ if (pclk > 1000 * i * i * i)
+ ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
+ else
+ ctx.pck_min = 0;
+ ctx.pck_max = pclk + 1000 * i * i * i;
+
+ ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx);
+ if (ok) {
+ *fck = ctx.fck;
+ *dispc_cinfo = ctx.dispc_cinfo;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = sdi.output.manager;
+
+ sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
+
+ sdi.mgr_config.stallmode = false;
+ sdi.mgr_config.fifohandcheck = false;
+
+ sdi.mgr_config.video_port_width = 24;
+ sdi.mgr_config.lcden_sig_polarity = 1;
+
+ dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
+}
+
+static int sdi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &sdi.output;
+ struct omap_video_timings *t = &sdi.timings;
+ unsigned long fck;
+ struct dispc_clock_info dispc_cinfo;
+ unsigned long pck;
+ int r;
+
+ if (out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ return -ENODEV;
+ }
+
+ r = regulator_enable(sdi.vdds_sdi_reg);
+ if (r)
+ goto err_reg_enable;
+
+ r = dispc_runtime_get();
+ if (r)
+ goto err_get_dispc;
+
+ /* 15.5.9.1.2 */
+ t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+
+ r = sdi_calc_clock_div(t->pixelclock, &fck, &dispc_cinfo);
+ if (r)
+ goto err_calc_clock_div;
+
+ sdi.mgr_config.clock_info = dispc_cinfo;
+
+ pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
+
+ if (pck != t->pixelclock) {
+ DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
+ t->pixelclock, pck);
+
+ t->pixelclock = pck;
+ }
+
+
+ dss_mgr_set_timings(out->manager, t);
+
+ r = dss_set_fck_rate(fck);
+ if (r)
+ goto err_set_dss_clock_div;
+
+ sdi_config_lcd_manager(dssdev);
+
+ /*
+ * LCLK and PCLK divisors are located in shadow registers, and we
+ * normally write them to DISPC registers when enabling the output.
+ * However, SDI uses pck-free as source clock for its PLL, and pck-free
+ * is affected by the divisors. And as we need the PLL before enabling
+ * the output, we need to write the divisors early.
+ *
+ * It seems just writing to the DISPC register is enough, and we don't
+ * need to care about the shadow register mechanism for pck-free. The
+ * exact reason for this is unknown.
+ */
+ dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
+
+ dss_sdi_init(sdi.datapairs);
+ r = dss_sdi_enable();
+ if (r)
+ goto err_sdi_enable;
+ mdelay(2);
+
+ r = dss_mgr_enable(out->manager);
+ if (r)
+ goto err_mgr_enable;
+
+ return 0;
+
+err_mgr_enable:
+ dss_sdi_disable();
+err_sdi_enable:
+err_set_dss_clock_div:
+err_calc_clock_div:
+ dispc_runtime_put();
+err_get_dispc:
+ regulator_disable(sdi.vdds_sdi_reg);
+err_reg_enable:
+ return r;
+}
+
+static void sdi_display_disable(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = sdi.output.manager;
+
+ dss_mgr_disable(mgr);
+
+ dss_sdi_disable();
+
+ dispc_runtime_put();
+
+ regulator_disable(sdi.vdds_sdi_reg);
+}
+
+static void sdi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ sdi.timings = *timings;
+}
+
+static void sdi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = sdi.timings;
+}
+
+static int sdi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct omap_overlay_manager *mgr = sdi.output.manager;
+
+ if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
+ return -EINVAL;
+
+ if (timings->pixelclock == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
+{
+ sdi.datapairs = datapairs;
+}
+
+static int sdi_init_regulator(void)
+{
+ struct regulator *vdds_sdi;
+
+ if (sdi.vdds_sdi_reg)
+ return 0;
+
+ vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
+ if (IS_ERR(vdds_sdi)) {
+ if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
+ DSSERR("can't get VDDS_SDI regulator\n");
+ return PTR_ERR(vdds_sdi);
+ }
+
+ sdi.vdds_sdi_reg = vdds_sdi;
+
+ return 0;
+}
+
+static int sdi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = sdi_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void sdi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static const struct omapdss_sdi_ops sdi_ops = {
+ .connect = sdi_connect,
+ .disconnect = sdi_disconnect,
+
+ .enable = sdi_display_enable,
+ .disable = sdi_display_disable,
+
+ .check_timings = sdi_check_timings,
+ .set_timings = sdi_set_timings,
+ .get_timings = sdi_get_timings,
+
+ .set_datapairs = sdi_set_datapairs,
+};
+
+static void sdi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &sdi.output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_SDI;
+ out->output_type = OMAP_DISPLAY_TYPE_SDI;
+ out->name = "sdi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
+ /* We have SDI only on OMAP3, where it's on port 1 */
+ out->port_num = 1;
+ out->ops.sdi = &sdi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void sdi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &sdi.output;
+
+ omapdss_unregister_output(out);
+}
+
+static int sdi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ sdi.pdev = pdev;
+
+ sdi_init_output(pdev);
+
+ return 0;
+}
+
+static void sdi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ sdi_uninit_output(pdev);
+}
+
+static const struct component_ops sdi_component_ops = {
+ .bind = sdi_bind,
+ .unbind = sdi_unbind,
+};
+
+static int sdi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &sdi_component_ops);
+}
+
+static int sdi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &sdi_component_ops);
+ return 0;
+}
+
+static struct platform_driver omap_sdi_driver = {
+ .probe = sdi_probe,
+ .remove = sdi_remove,
+ .driver = {
+ .name = "omapdss_sdi",
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init sdi_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_sdi_driver);
+}
+
+void sdi_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_sdi_driver);
+}
+
+int sdi_init_port(struct platform_device *pdev, struct device_node *port)
+{
+ struct device_node *ep;
+ u32 datapairs;
+ int r;
+
+ ep = omapdss_of_get_next_endpoint(port, NULL);
+ if (!ep)
+ return 0;
+
+ r = of_property_read_u32(ep, "datapairs", &datapairs);
+ if (r) {
+ DSSERR("failed to parse datapairs\n");
+ goto err_datapairs;
+ }
+
+ sdi.datapairs = datapairs;
+
+ of_node_put(ep);
+
+ sdi.pdev = pdev;
+
+ sdi_init_output(pdev);
+
+ sdi.port_initialized = true;
+
+ return 0;
+
+err_datapairs:
+ of_node_put(ep);
+
+ return r;
+}
+
+void sdi_uninit_port(struct device_node *port)
+{
+ if (!sdi.port_initialized)
+ return;
+
+ sdi_uninit_output(sdi.pdev);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/venc.c b/drivers/video/fbdev/omap2/omapfb/dss/venc.c
new file mode 100644
index 000000000000..26e0ee30adf8
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/venc.c
@@ -0,0 +1,997 @@
+/*
+ * linux/drivers/video/omap2/dss/venc.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * VENC settings from TI's DSS driver
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "VENC"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/component.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+/* Venc registers */
+#define VENC_REV_ID 0x00
+#define VENC_STATUS 0x04
+#define VENC_F_CONTROL 0x08
+#define VENC_VIDOUT_CTRL 0x10
+#define VENC_SYNC_CTRL 0x14
+#define VENC_LLEN 0x1C
+#define VENC_FLENS 0x20
+#define VENC_HFLTR_CTRL 0x24
+#define VENC_CC_CARR_WSS_CARR 0x28
+#define VENC_C_PHASE 0x2C
+#define VENC_GAIN_U 0x30
+#define VENC_GAIN_V 0x34
+#define VENC_GAIN_Y 0x38
+#define VENC_BLACK_LEVEL 0x3C
+#define VENC_BLANK_LEVEL 0x40
+#define VENC_X_COLOR 0x44
+#define VENC_M_CONTROL 0x48
+#define VENC_BSTAMP_WSS_DATA 0x4C
+#define VENC_S_CARR 0x50
+#define VENC_LINE21 0x54
+#define VENC_LN_SEL 0x58
+#define VENC_L21__WC_CTL 0x5C
+#define VENC_HTRIGGER_VTRIGGER 0x60
+#define VENC_SAVID__EAVID 0x64
+#define VENC_FLEN__FAL 0x68
+#define VENC_LAL__PHASE_RESET 0x6C
+#define VENC_HS_INT_START_STOP_X 0x70
+#define VENC_HS_EXT_START_STOP_X 0x74
+#define VENC_VS_INT_START_X 0x78
+#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
+#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
+#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
+#define VENC_VS_EXT_STOP_Y 0x88
+#define VENC_AVID_START_STOP_X 0x90
+#define VENC_AVID_START_STOP_Y 0x94
+#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
+#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
+#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
+#define VENC_TVDETGP_INT_START_STOP_X 0xB0
+#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
+#define VENC_GEN_CTRL 0xB8
+#define VENC_OUTPUT_CONTROL 0xC4
+#define VENC_OUTPUT_TEST 0xC8
+#define VENC_DAC_B__DAC_C 0xC8
+
+struct venc_config {
+ u32 f_control;
+ u32 vidout_ctrl;
+ u32 sync_ctrl;
+ u32 llen;
+ u32 flens;
+ u32 hfltr_ctrl;
+ u32 cc_carr_wss_carr;
+ u32 c_phase;
+ u32 gain_u;
+ u32 gain_v;
+ u32 gain_y;
+ u32 black_level;
+ u32 blank_level;
+ u32 x_color;
+ u32 m_control;
+ u32 bstamp_wss_data;
+ u32 s_carr;
+ u32 line21;
+ u32 ln_sel;
+ u32 l21__wc_ctl;
+ u32 htrigger_vtrigger;
+ u32 savid__eavid;
+ u32 flen__fal;
+ u32 lal__phase_reset;
+ u32 hs_int_start_stop_x;
+ u32 hs_ext_start_stop_x;
+ u32 vs_int_start_x;
+ u32 vs_int_stop_x__vs_int_start_y;
+ u32 vs_int_stop_y__vs_ext_start_x;
+ u32 vs_ext_stop_x__vs_ext_start_y;
+ u32 vs_ext_stop_y;
+ u32 avid_start_stop_x;
+ u32 avid_start_stop_y;
+ u32 fid_int_start_x__fid_int_start_y;
+ u32 fid_int_offset_y__fid_ext_start_x;
+ u32 fid_ext_start_y__fid_ext_offset_y;
+ u32 tvdetgp_int_start_stop_x;
+ u32 tvdetgp_int_start_stop_y;
+ u32 gen_ctrl;
+};
+
+/* from TRM */
+static const struct venc_config venc_config_pal_trm = {
+ .f_control = 0,
+ .vidout_ctrl = 1,
+ .sync_ctrl = 0x40,
+ .llen = 0x35F, /* 863 */
+ .flens = 0x270, /* 624 */
+ .hfltr_ctrl = 0,
+ .cc_carr_wss_carr = 0x2F7225ED,
+ .c_phase = 0,
+ .gain_u = 0x111,
+ .gain_v = 0x181,
+ .gain_y = 0x140,
+ .black_level = 0x3B,
+ .blank_level = 0x3B,
+ .x_color = 0x7,
+ .m_control = 0x2,
+ .bstamp_wss_data = 0x3F,
+ .s_carr = 0x2A098ACB,
+ .line21 = 0,
+ .ln_sel = 0x01290015,
+ .l21__wc_ctl = 0x0000F603,
+ .htrigger_vtrigger = 0,
+
+ .savid__eavid = 0x06A70108,
+ .flen__fal = 0x00180270,
+ .lal__phase_reset = 0x00040135,
+ .hs_int_start_stop_x = 0x00880358,
+ .hs_ext_start_stop_x = 0x000F035F,
+ .vs_int_start_x = 0x01A70000,
+ .vs_int_stop_x__vs_int_start_y = 0x000001A7,
+ .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
+ .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
+ .vs_ext_stop_y = 0x00000025,
+ .avid_start_stop_x = 0x03530083,
+ .avid_start_stop_y = 0x026C002E,
+ .fid_int_start_x__fid_int_start_y = 0x0001008A,
+ .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
+ .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
+
+ .tvdetgp_int_start_stop_x = 0x00140001,
+ .tvdetgp_int_start_stop_y = 0x00010001,
+ .gen_ctrl = 0x00FF0000,
+};
+
+/* from TRM */
+static const struct venc_config venc_config_ntsc_trm = {
+ .f_control = 0,
+ .vidout_ctrl = 1,
+ .sync_ctrl = 0x8040,
+ .llen = 0x359,
+ .flens = 0x20C,
+ .hfltr_ctrl = 0,
+ .cc_carr_wss_carr = 0x043F2631,
+ .c_phase = 0,
+ .gain_u = 0x102,
+ .gain_v = 0x16C,
+ .gain_y = 0x12F,
+ .black_level = 0x43,
+ .blank_level = 0x38,
+ .x_color = 0x7,
+ .m_control = 0x1,
+ .bstamp_wss_data = 0x38,
+ .s_carr = 0x21F07C1F,
+ .line21 = 0,
+ .ln_sel = 0x01310011,
+ .l21__wc_ctl = 0x0000F003,
+ .htrigger_vtrigger = 0,
+
+ .savid__eavid = 0x069300F4,
+ .flen__fal = 0x0016020C,
+ .lal__phase_reset = 0x00060107,
+ .hs_int_start_stop_x = 0x008E0350,
+ .hs_ext_start_stop_x = 0x000F0359,
+ .vs_int_start_x = 0x01A00000,
+ .vs_int_stop_x__vs_int_start_y = 0x020701A0,
+ .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
+ .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
+ .vs_ext_stop_y = 0x00000006,
+ .avid_start_stop_x = 0x03480078,
+ .avid_start_stop_y = 0x02060024,
+ .fid_int_start_x__fid_int_start_y = 0x0001008A,
+ .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
+ .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
+
+ .tvdetgp_int_start_stop_x = 0x00140001,
+ .tvdetgp_int_start_stop_y = 0x00010001,
+ .gen_ctrl = 0x00F90000,
+};
+
+static const struct venc_config venc_config_pal_bdghi = {
+ .f_control = 0,
+ .vidout_ctrl = 0,
+ .sync_ctrl = 0,
+ .hfltr_ctrl = 0,
+ .x_color = 0,
+ .line21 = 0,
+ .ln_sel = 21,
+ .htrigger_vtrigger = 0,
+ .tvdetgp_int_start_stop_x = 0x00140001,
+ .tvdetgp_int_start_stop_y = 0x00010001,
+ .gen_ctrl = 0x00FB0000,
+
+ .llen = 864-1,
+ .flens = 625-1,
+ .cc_carr_wss_carr = 0x2F7625ED,
+ .c_phase = 0xDF,
+ .gain_u = 0x111,
+ .gain_v = 0x181,
+ .gain_y = 0x140,
+ .black_level = 0x3e,
+ .blank_level = 0x3e,
+ .m_control = 0<<2 | 1<<1,
+ .bstamp_wss_data = 0x42,
+ .s_carr = 0x2a098acb,
+ .l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
+ .savid__eavid = 0x06A70108,
+ .flen__fal = 23<<16 | 624<<0,
+ .lal__phase_reset = 2<<17 | 310<<0,
+ .hs_int_start_stop_x = 0x00920358,
+ .hs_ext_start_stop_x = 0x000F035F,
+ .vs_int_start_x = 0x1a7<<16,
+ .vs_int_stop_x__vs_int_start_y = 0x000601A7,
+ .vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
+ .vs_ext_stop_x__vs_ext_start_y = 0x27101af,
+ .vs_ext_stop_y = 0x05,
+ .avid_start_stop_x = 0x03530082,
+ .avid_start_stop_y = 0x0270002E,
+ .fid_int_start_x__fid_int_start_y = 0x0005008A,
+ .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
+ .fid_ext_start_y__fid_ext_offset_y = 0x01380005,
+};
+
+const struct omap_video_timings omap_dss_pal_timings = {
+ .x_res = 720,
+ .y_res = 574,
+ .pixelclock = 13500000,
+ .hsw = 64,
+ .hfp = 12,
+ .hbp = 68,
+ .vsw = 5,
+ .vfp = 5,
+ .vbp = 41,
+
+ .interlace = true,
+};
+EXPORT_SYMBOL(omap_dss_pal_timings);
+
+const struct omap_video_timings omap_dss_ntsc_timings = {
+ .x_res = 720,
+ .y_res = 482,
+ .pixelclock = 13500000,
+ .hsw = 64,
+ .hfp = 16,
+ .hbp = 58,
+ .vsw = 6,
+ .vfp = 6,
+ .vbp = 31,
+
+ .interlace = true,
+};
+EXPORT_SYMBOL(omap_dss_ntsc_timings);
+
+static struct {
+ struct platform_device *pdev;
+ void __iomem *base;
+ struct mutex venc_lock;
+ u32 wss_data;
+ struct regulator *vdda_dac_reg;
+
+ struct clk *tv_dac_clk;
+
+ struct omap_video_timings timings;
+ enum omap_dss_venc_type type;
+ bool invert_polarity;
+
+ struct omap_dss_device output;
+} venc;
+
+static inline void venc_write_reg(int idx, u32 val)
+{
+ __raw_writel(val, venc.base + idx);
+}
+
+static inline u32 venc_read_reg(int idx)
+{
+ u32 l = __raw_readl(venc.base + idx);
+ return l;
+}
+
+static void venc_write_config(const struct venc_config *config)
+{
+ DSSDBG("write venc conf\n");
+
+ venc_write_reg(VENC_LLEN, config->llen);
+ venc_write_reg(VENC_FLENS, config->flens);
+ venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
+ venc_write_reg(VENC_C_PHASE, config->c_phase);
+ venc_write_reg(VENC_GAIN_U, config->gain_u);
+ venc_write_reg(VENC_GAIN_V, config->gain_v);
+ venc_write_reg(VENC_GAIN_Y, config->gain_y);
+ venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
+ venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
+ venc_write_reg(VENC_M_CONTROL, config->m_control);
+ venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
+ venc.wss_data);
+ venc_write_reg(VENC_S_CARR, config->s_carr);
+ venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
+ venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
+ venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
+ venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
+ venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
+ venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
+ venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
+ venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
+ config->vs_int_stop_x__vs_int_start_y);
+ venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
+ config->vs_int_stop_y__vs_ext_start_x);
+ venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
+ config->vs_ext_stop_x__vs_ext_start_y);
+ venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
+ venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
+ venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
+ venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
+ config->fid_int_start_x__fid_int_start_y);
+ venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
+ config->fid_int_offset_y__fid_ext_start_x);
+ venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
+ config->fid_ext_start_y__fid_ext_offset_y);
+
+ venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
+ venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
+ venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
+ venc_write_reg(VENC_X_COLOR, config->x_color);
+ venc_write_reg(VENC_LINE21, config->line21);
+ venc_write_reg(VENC_LN_SEL, config->ln_sel);
+ venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
+ venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
+ config->tvdetgp_int_start_stop_x);
+ venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
+ config->tvdetgp_int_start_stop_y);
+ venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
+ venc_write_reg(VENC_F_CONTROL, config->f_control);
+ venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
+}
+
+static void venc_reset(void)
+{
+ int t = 1000;
+
+ venc_write_reg(VENC_F_CONTROL, 1<<8);
+ while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
+ if (--t == 0) {
+ DSSERR("Failed to reset venc\n");
+ return;
+ }
+ }
+
+#ifdef CONFIG_FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
+ /* the magical sleep that makes things work */
+ /* XXX more info? What bug this circumvents? */
+ msleep(20);
+#endif
+}
+
+static int venc_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("venc_runtime_get\n");
+
+ r = pm_runtime_get_sync(&venc.pdev->dev);
+ WARN_ON(r < 0);
+ return r < 0 ? r : 0;
+}
+
+static void venc_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("venc_runtime_put\n");
+
+ r = pm_runtime_put_sync(&venc.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static const struct venc_config *venc_timings_to_config(
+ struct omap_video_timings *timings)
+{
+ if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
+ return &venc_config_pal_trm;
+
+ if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
+ return &venc_config_ntsc_trm;
+
+ BUG();
+ return NULL;
+}
+
+static int venc_power_on(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = venc.output.manager;
+ u32 l;
+ int r;
+
+ r = venc_runtime_get();
+ if (r)
+ goto err0;
+
+ venc_reset();
+ venc_write_config(venc_timings_to_config(&venc.timings));
+
+ dss_set_venc_output(venc.type);
+ dss_set_dac_pwrdn_bgz(1);
+
+ l = 0;
+
+ if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
+ l |= 1 << 1;
+ else /* S-Video */
+ l |= (1 << 0) | (1 << 2);
+
+ if (venc.invert_polarity == false)
+ l |= 1 << 3;
+
+ venc_write_reg(VENC_OUTPUT_CONTROL, l);
+
+ dss_mgr_set_timings(mgr, &venc.timings);
+
+ r = regulator_enable(venc.vdda_dac_reg);
+ if (r)
+ goto err1;
+
+ r = dss_mgr_enable(mgr);
+ if (r)
+ goto err2;
+
+ return 0;
+
+err2:
+ regulator_disable(venc.vdda_dac_reg);
+err1:
+ venc_write_reg(VENC_OUTPUT_CONTROL, 0);
+ dss_set_dac_pwrdn_bgz(0);
+
+ venc_runtime_put();
+err0:
+ return r;
+}
+
+static void venc_power_off(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = venc.output.manager;
+
+ venc_write_reg(VENC_OUTPUT_CONTROL, 0);
+ dss_set_dac_pwrdn_bgz(0);
+
+ dss_mgr_disable(mgr);
+
+ regulator_disable(venc.vdda_dac_reg);
+
+ venc_runtime_put();
+}
+
+static int venc_display_enable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &venc.output;
+ int r;
+
+ DSSDBG("venc_display_enable\n");
+
+ mutex_lock(&venc.venc_lock);
+
+ if (out->manager == NULL) {
+ DSSERR("Failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err0;
+ }
+
+ r = venc_power_on(dssdev);
+ if (r)
+ goto err0;
+
+ venc.wss_data = 0;
+
+ mutex_unlock(&venc.venc_lock);
+
+ return 0;
+err0:
+ mutex_unlock(&venc.venc_lock);
+ return r;
+}
+
+static void venc_display_disable(struct omap_dss_device *dssdev)
+{
+ DSSDBG("venc_display_disable\n");
+
+ mutex_lock(&venc.venc_lock);
+
+ venc_power_off(dssdev);
+
+ mutex_unlock(&venc.venc_lock);
+}
+
+static void venc_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ DSSDBG("venc_set_timings\n");
+
+ mutex_lock(&venc.venc_lock);
+
+ /* Reset WSS data when the TV standard changes. */
+ if (memcmp(&venc.timings, timings, sizeof(*timings)))
+ venc.wss_data = 0;
+
+ venc.timings = *timings;
+
+ dispc_set_tv_pclk(13500000);
+
+ mutex_unlock(&venc.venc_lock);
+}
+
+static int venc_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ DSSDBG("venc_check_timings\n");
+
+ if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
+ return 0;
+
+ if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
+ return 0;
+
+ return -EINVAL;
+}
+
+static void venc_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ mutex_lock(&venc.venc_lock);
+
+ *timings = venc.timings;
+
+ mutex_unlock(&venc.venc_lock);
+}
+
+static u32 venc_get_wss(struct omap_dss_device *dssdev)
+{
+ /* Invert due to VENC_L21_WC_CTL:INV=1 */
+ return (venc.wss_data >> 8) ^ 0xfffff;
+}
+
+static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
+{
+ const struct venc_config *config;
+ int r;
+
+ DSSDBG("venc_set_wss\n");
+
+ mutex_lock(&venc.venc_lock);
+
+ config = venc_timings_to_config(&venc.timings);
+
+ /* Invert due to VENC_L21_WC_CTL:INV=1 */
+ venc.wss_data = (wss ^ 0xfffff) << 8;
+
+ r = venc_runtime_get();
+ if (r)
+ goto err;
+
+ venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
+ venc.wss_data);
+
+ venc_runtime_put();
+
+err:
+ mutex_unlock(&venc.venc_lock);
+
+ return r;
+}
+
+static void venc_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ mutex_lock(&venc.venc_lock);
+
+ venc.type = type;
+
+ mutex_unlock(&venc.venc_lock);
+}
+
+static void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
+ bool invert_polarity)
+{
+ mutex_lock(&venc.venc_lock);
+
+ venc.invert_polarity = invert_polarity;
+
+ mutex_unlock(&venc.venc_lock);
+}
+
+static int venc_init_regulator(void)
+{
+ struct regulator *vdda_dac;
+
+ if (venc.vdda_dac_reg != NULL)
+ return 0;
+
+ if (venc.pdev->dev.of_node)
+ vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
+ else
+ vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
+
+ if (IS_ERR(vdda_dac)) {
+ if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
+ DSSERR("can't get VDDA_DAC regulator\n");
+ return PTR_ERR(vdda_dac);
+ }
+
+ venc.vdda_dac_reg = vdda_dac;
+
+ return 0;
+}
+
+static void venc_dump_regs(struct seq_file *s)
+{
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
+
+ if (venc_runtime_get())
+ return;
+
+ DUMPREG(VENC_F_CONTROL);
+ DUMPREG(VENC_VIDOUT_CTRL);
+ DUMPREG(VENC_SYNC_CTRL);
+ DUMPREG(VENC_LLEN);
+ DUMPREG(VENC_FLENS);
+ DUMPREG(VENC_HFLTR_CTRL);
+ DUMPREG(VENC_CC_CARR_WSS_CARR);
+ DUMPREG(VENC_C_PHASE);
+ DUMPREG(VENC_GAIN_U);
+ DUMPREG(VENC_GAIN_V);
+ DUMPREG(VENC_GAIN_Y);
+ DUMPREG(VENC_BLACK_LEVEL);
+ DUMPREG(VENC_BLANK_LEVEL);
+ DUMPREG(VENC_X_COLOR);
+ DUMPREG(VENC_M_CONTROL);
+ DUMPREG(VENC_BSTAMP_WSS_DATA);
+ DUMPREG(VENC_S_CARR);
+ DUMPREG(VENC_LINE21);
+ DUMPREG(VENC_LN_SEL);
+ DUMPREG(VENC_L21__WC_CTL);
+ DUMPREG(VENC_HTRIGGER_VTRIGGER);
+ DUMPREG(VENC_SAVID__EAVID);
+ DUMPREG(VENC_FLEN__FAL);
+ DUMPREG(VENC_LAL__PHASE_RESET);
+ DUMPREG(VENC_HS_INT_START_STOP_X);
+ DUMPREG(VENC_HS_EXT_START_STOP_X);
+ DUMPREG(VENC_VS_INT_START_X);
+ DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
+ DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
+ DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
+ DUMPREG(VENC_VS_EXT_STOP_Y);
+ DUMPREG(VENC_AVID_START_STOP_X);
+ DUMPREG(VENC_AVID_START_STOP_Y);
+ DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
+ DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
+ DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
+ DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
+ DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
+ DUMPREG(VENC_GEN_CTRL);
+ DUMPREG(VENC_OUTPUT_CONTROL);
+ DUMPREG(VENC_OUTPUT_TEST);
+
+ venc_runtime_put();
+
+#undef DUMPREG
+}
+
+static int venc_get_clocks(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
+ clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get tv_dac_clk\n");
+ return PTR_ERR(clk);
+ }
+ } else {
+ clk = NULL;
+ }
+
+ venc.tv_dac_clk = clk;
+
+ return 0;
+}
+
+static int venc_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = venc_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void venc_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static const struct omapdss_atv_ops venc_ops = {
+ .connect = venc_connect,
+ .disconnect = venc_disconnect,
+
+ .enable = venc_display_enable,
+ .disable = venc_display_disable,
+
+ .check_timings = venc_check_timings,
+ .set_timings = venc_set_timings,
+ .get_timings = venc_get_timings,
+
+ .set_type = venc_set_type,
+ .invert_vid_out_polarity = venc_invert_vid_out_polarity,
+
+ .set_wss = venc_set_wss,
+ .get_wss = venc_get_wss,
+};
+
+static void venc_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &venc.output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_VENC;
+ out->output_type = OMAP_DISPLAY_TYPE_VENC;
+ out->name = "venc.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+ out->ops.atv = &venc_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void venc_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &venc.output;
+
+ omapdss_unregister_output(out);
+}
+
+static int venc_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *ep;
+ u32 channels;
+ int r;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return 0;
+
+ venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
+
+ r = of_property_read_u32(ep, "ti,channels", &channels);
+ if (r) {
+ dev_err(&pdev->dev,
+ "failed to read property 'ti,channels': %d\n", r);
+ goto err;
+ }
+
+ switch (channels) {
+ case 1:
+ venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+ break;
+ case 2:
+ venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
+ break;
+ default:
+ dev_err(&pdev->dev, "bad channel propert '%d'\n", channels);
+ r = -EINVAL;
+ goto err;
+ }
+
+ of_node_put(ep);
+
+ return 0;
+err:
+ of_node_put(ep);
+
+ return 0;
+}
+
+/* VENC HW IP initialisation */
+static int venc_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ u8 rev_id;
+ struct resource *venc_mem;
+ int r;
+
+ venc.pdev = pdev;
+
+ mutex_init(&venc.venc_lock);
+
+ venc.wss_data = 0;
+
+ venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
+ if (!venc_mem) {
+ DSSERR("can't get IORESOURCE_MEM VENC\n");
+ return -EINVAL;
+ }
+
+ venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
+ resource_size(venc_mem));
+ if (!venc.base) {
+ DSSERR("can't ioremap VENC\n");
+ return -ENOMEM;
+ }
+
+ r = venc_get_clocks(pdev);
+ if (r)
+ return r;
+
+ pm_runtime_enable(&pdev->dev);
+
+ r = venc_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
+ dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
+
+ venc_runtime_put();
+
+ if (pdev->dev.of_node) {
+ r = venc_probe_of(pdev);
+ if (r) {
+ DSSERR("Invalid DT data\n");
+ goto err_probe_of;
+ }
+ }
+
+ dss_debugfs_create_file("venc", venc_dump_regs);
+
+ venc_init_output(pdev);
+
+ return 0;
+
+err_probe_of:
+err_runtime_get:
+ pm_runtime_disable(&pdev->dev);
+ return r;
+}
+
+static void venc_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ venc_uninit_output(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+}
+
+static const struct component_ops venc_component_ops = {
+ .bind = venc_bind,
+ .unbind = venc_unbind,
+};
+
+static int venc_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &venc_component_ops);
+}
+
+static int venc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &venc_component_ops);
+ return 0;
+}
+
+static int venc_runtime_suspend(struct device *dev)
+{
+ if (venc.tv_dac_clk)
+ clk_disable_unprepare(venc.tv_dac_clk);
+
+ dispc_runtime_put();
+
+ return 0;
+}
+
+static int venc_runtime_resume(struct device *dev)
+{
+ int r;
+
+ r = dispc_runtime_get();
+ if (r < 0)
+ return r;
+
+ if (venc.tv_dac_clk)
+ clk_prepare_enable(venc.tv_dac_clk);
+
+ return 0;
+}
+
+static const struct dev_pm_ops venc_pm_ops = {
+ .runtime_suspend = venc_runtime_suspend,
+ .runtime_resume = venc_runtime_resume,
+};
+
+static const struct of_device_id venc_of_match[] = {
+ { .compatible = "ti,omap2-venc", },
+ { .compatible = "ti,omap3-venc", },
+ { .compatible = "ti,omap4-venc", },
+ {},
+};
+
+static struct platform_driver omap_venchw_driver = {
+ .probe = venc_probe,
+ .remove = venc_remove,
+ .driver = {
+ .name = "omapdss_venc",
+ .pm = &venc_pm_ops,
+ .of_match_table = venc_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+int __init venc_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_venchw_driver);
+}
+
+void venc_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omap_venchw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/video-pll.c b/drivers/video/fbdev/omap2/omapfb/dss/video-pll.c
new file mode 100644
index 000000000000..b1ec59e42940
--- /dev/null
+++ b/drivers/video/fbdev/omap2/omapfb/dss/video-pll.c
@@ -0,0 +1,211 @@
+/*
+* Copyright (C) 2014 Texas Instruments Ltd
+*
+* 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.
+*
+* 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+struct dss_video_pll {
+ struct dss_pll pll;
+
+ struct device *dev;
+
+ void __iomem *clkctrl_base;
+};
+
+#define REG_MOD(reg, val, start, end) \
+ writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg)
+
+static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dss_dpll_power_enable(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */
+
+ /*
+ * DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0,
+ * so we have to use fixed delay here.
+ */
+ msleep(1);
+}
+
+static void dss_dpll_power_disable(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */
+}
+
+static int dss_video_pll_enable(struct dss_pll *pll)
+{
+ struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
+ int r;
+
+ r = dss_runtime_get();
+ if (r)
+ return r;
+
+ dss_ctrl_pll_enable(pll->id, true);
+
+ dss_dpll_enable_scp_clk(vpll);
+
+ r = dss_pll_wait_reset_done(pll);
+ if (r)
+ goto err_reset;
+
+ dss_dpll_power_enable(vpll);
+
+ return 0;
+
+err_reset:
+ dss_dpll_disable_scp_clk(vpll);
+ dss_ctrl_pll_enable(pll->id, false);
+ dss_runtime_put();
+
+ return r;
+}
+
+static void dss_video_pll_disable(struct dss_pll *pll)
+{
+ struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
+
+ dss_dpll_power_disable(vpll);
+
+ dss_dpll_disable_scp_clk(vpll);
+
+ dss_ctrl_pll_enable(pll->id, false);
+
+ dss_runtime_put();
+}
+
+static const struct dss_pll_ops dss_pll_ops = {
+ .enable = dss_video_pll_enable,
+ .disable = dss_video_pll_disable,
+ .set_config = dss_pll_write_config_type_a,
+};
+
+static const struct dss_pll_hw dss_dra7_video_pll_hw = {
+ .n_max = (1 << 8) - 1,
+ .m_max = (1 << 12) - 1,
+ .mX_max = (1 << 5) - 1,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 25,
+ .mX_lsb[0] = 21,
+ .mX_msb[1] = 30,
+ .mX_lsb[1] = 26,
+
+ .has_refsel = true,
+};
+
+struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
+ struct regulator *regulator)
+{
+ const char * const reg_name[] = { "pll1", "pll2" };
+ const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" };
+ const char * const clkin_name[] = { "video1_clk", "video2_clk" };
+
+ struct resource *res;
+ struct dss_video_pll *vpll;
+ void __iomem *pll_base, *clkctrl_base;
+ struct clk *clk;
+ struct dss_pll *pll;
+ int r;
+
+ /* PLL CONTROL */
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "missing platform resource data for pll%d\n", id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ pll_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pll_base)) {
+ dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id);
+ return ERR_CAST(pll_base);
+ }
+
+ /* CLOCK CONTROL */
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ clkctrl_name[id]);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "missing platform resource data for pll%d\n", id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ clkctrl_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(clkctrl_base)) {
+ dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id);
+ return ERR_CAST(clkctrl_base);
+ }
+
+ /* CLKIN */
+
+ clk = devm_clk_get(&pdev->dev, clkin_name[id]);
+ if (IS_ERR(clk)) {
+ DSSERR("can't get video pll clkin\n");
+ return ERR_CAST(clk);
+ }
+
+ vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL);
+ if (!vpll)
+ return ERR_PTR(-ENOMEM);
+
+ vpll->dev = &pdev->dev;
+ vpll->clkctrl_base = clkctrl_base;
+
+ pll = &vpll->pll;
+
+ pll->name = id == 0 ? "video0" : "video1";
+ pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2;
+ pll->clkin = clk;
+ pll->regulator = regulator;
+ pll->base = pll_base;
+ pll->hw = &dss_dra7_video_pll_hw;
+ pll->ops = &dss_pll_ops;
+
+ r = dss_pll_register(pll);
+ if (r)
+ return ERR_PTR(r);
+
+ return pll;
+}
+
+void dss_video_pll_uninit(struct dss_pll *pll)
+{
+ dss_pll_unregister(pll);
+}
diff --git a/drivers/video/fbdev/omap2/vrfb.c b/drivers/video/fbdev/omap2/omapfb/vrfb.c
index f346b02eee1d..f346b02eee1d 100644
--- a/drivers/video/fbdev/omap2/vrfb.c
+++ b/drivers/video/fbdev/omap2/omapfb/vrfb.c
diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c
index 94813af97f09..33b2bb315a2a 100644
--- a/drivers/video/fbdev/pxafb.c
+++ b/drivers/video/fbdev/pxafb.c
@@ -55,6 +55,9 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/console.h>
+#include <linux/of_graph.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
#include <mach/hardware.h>
#include <asm/io.h>
@@ -457,7 +460,7 @@ static int pxafb_adjust_timing(struct pxafb_info *fbi,
static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
- struct pxafb_mach_info *inf = dev_get_platdata(fbi->dev);
+ struct pxafb_mach_info *inf = fbi->inf;
int err;
if (inf->fixed_modes) {
@@ -1230,7 +1233,7 @@ static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk)
static void setup_smart_timing(struct pxafb_info *fbi,
struct fb_var_screeninfo *var)
{
- struct pxafb_mach_info *inf = dev_get_platdata(fbi->dev);
+ struct pxafb_mach_info *inf = fbi->inf;
struct pxafb_mode_info *mode = &inf->modes[0];
unsigned long lclk = clk_get_rate(fbi->clk);
unsigned t1, t2, t3, t4;
@@ -1258,14 +1261,13 @@ static void setup_smart_timing(struct pxafb_info *fbi,
static int pxafb_smart_thread(void *arg)
{
struct pxafb_info *fbi = arg;
- struct pxafb_mach_info *inf = dev_get_platdata(fbi->dev);
+ struct pxafb_mach_info *inf = fbi->inf;
if (!inf->smart_update) {
pr_err("%s: not properly initialized, thread terminated\n",
__func__);
return -EINVAL;
}
- inf = dev_get_platdata(fbi->dev);
pr_debug("%s(): task starting\n", __func__);
@@ -1788,11 +1790,11 @@ decode_mode:
fbi->video_mem_size = video_mem_size;
}
-static struct pxafb_info *pxafb_init_fbinfo(struct device *dev)
+static struct pxafb_info *pxafb_init_fbinfo(struct device *dev,
+ struct pxafb_mach_info *inf)
{
struct pxafb_info *fbi;
void *addr;
- struct pxafb_mach_info *inf = dev_get_platdata(dev);
/* Alloc the pxafb_info and pseudo_palette in one step */
fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1801,6 +1803,7 @@ static struct pxafb_info *pxafb_init_fbinfo(struct device *dev)
memset(fbi, 0, sizeof(struct pxafb_info));
fbi->dev = dev;
+ fbi->inf = inf;
fbi->clk = clk_get(dev, NULL);
if (IS_ERR(fbi->clk)) {
@@ -1852,10 +1855,9 @@ static struct pxafb_info *pxafb_init_fbinfo(struct device *dev)
}
#ifdef CONFIG_FB_PXA_PARAMETERS
-static int parse_opt_mode(struct device *dev, const char *this_opt)
+static int parse_opt_mode(struct device *dev, const char *this_opt,
+ struct pxafb_mach_info *inf)
{
- struct pxafb_mach_info *inf = dev_get_platdata(dev);
-
const char *name = this_opt+5;
unsigned int namelen = strlen(name);
int res_specified = 0, bpp_specified = 0;
@@ -1911,9 +1913,9 @@ done:
return 0;
}
-static int parse_opt(struct device *dev, char *this_opt)
+static int parse_opt(struct device *dev, char *this_opt,
+ struct pxafb_mach_info *inf)
{
- struct pxafb_mach_info *inf = dev_get_platdata(dev);
struct pxafb_mode_info *mode = &inf->modes[0];
char s[64];
@@ -1922,7 +1924,7 @@ static int parse_opt(struct device *dev, char *this_opt)
if (!strncmp(this_opt, "vmem:", 5)) {
video_mem_size = memparse(this_opt + 5, NULL);
} else if (!strncmp(this_opt, "mode:", 5)) {
- return parse_opt_mode(dev, this_opt);
+ return parse_opt_mode(dev, this_opt, inf);
} else if (!strncmp(this_opt, "pixclock:", 9)) {
mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
sprintf(s, "pixclock: %ld\n", mode->pixclock);
@@ -2011,7 +2013,8 @@ static int parse_opt(struct device *dev, char *this_opt)
return 0;
}
-static int pxafb_parse_options(struct device *dev, char *options)
+static int pxafb_parse_options(struct device *dev, char *options,
+ struct pxafb_mach_info *inf)
{
char *this_opt;
int ret;
@@ -2023,7 +2026,7 @@ static int pxafb_parse_options(struct device *dev, char *options)
/* could be made table driven or similar?... */
while ((this_opt = strsep(&options, ",")) != NULL) {
- ret = parse_opt(dev, this_opt);
+ ret = parse_opt(dev, this_opt, inf);
if (ret)
return ret;
}
@@ -2092,22 +2095,180 @@ static void pxafb_check_options(struct device *dev, struct pxafb_mach_info *inf)
#define pxafb_check_options(...) do {} while (0)
#endif
+#if defined(CONFIG_OF)
+static const char * const lcd_types[] = {
+ "unknown", "mono-stn", "mono-dstn", "color-stn", "color-dstn",
+ "color-tft", "smart-panel", NULL
+};
+
+static int of_get_pxafb_display(struct device *dev, struct device_node *disp,
+ struct pxafb_mach_info *info, u32 bus_width)
+{
+ struct display_timings *timings;
+ struct videomode vm;
+ int i, ret = -EINVAL;
+ const char *s;
+
+ ret = of_property_read_string(disp, "lcd-type", &s);
+ if (ret)
+ s = "color-tft";
+
+ for (i = 0; lcd_types[i]; i++)
+ if (!strcmp(s, lcd_types[i]))
+ break;
+ if (!i || !lcd_types[i]) {
+ dev_err(dev, "lcd-type %s is unknown\n", s);
+ return -EINVAL;
+ }
+ info->lcd_conn |= LCD_CONN_TYPE(i);
+ info->lcd_conn |= LCD_CONN_WIDTH(bus_width);
+
+ timings = of_get_display_timings(disp);
+ if (!timings)
+ goto out;
+
+ ret = -ENOMEM;
+ info->modes = kmalloc_array(timings->num_timings,
+ sizeof(info->modes[0]), GFP_KERNEL);
+ if (!info->modes)
+ goto out;
+ info->num_modes = timings->num_timings;
+
+ for (i = 0; i < timings->num_timings; i++) {
+ ret = videomode_from_timings(timings, &vm, i);
+ if (ret) {
+ dev_err(dev, "videomode_from_timings %d failed: %d\n",
+ i, ret);
+ goto out;
+ }
+ if (vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+ info->lcd_conn |= LCD_PCLK_EDGE_RISE;
+ if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ info->lcd_conn |= LCD_PCLK_EDGE_FALL;
+ if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
+ info->lcd_conn |= LCD_BIAS_ACTIVE_HIGH;
+ if (vm.flags & DISPLAY_FLAGS_DE_LOW)
+ info->lcd_conn |= LCD_BIAS_ACTIVE_LOW;
+ if (vm.flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ info->modes[i].sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ info->modes[i].sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ info->modes[i].pixclock = 1000000000UL / (vm.pixelclock / 1000);
+ info->modes[i].xres = vm.hactive;
+ info->modes[i].yres = vm.vactive;
+ info->modes[i].hsync_len = vm.hsync_len;
+ info->modes[i].left_margin = vm.hback_porch;
+ info->modes[i].right_margin = vm.hfront_porch;
+ info->modes[i].vsync_len = vm.vsync_len;
+ info->modes[i].upper_margin = vm.vback_porch;
+ info->modes[i].lower_margin = vm.vfront_porch;
+ }
+ ret = 0;
+
+out:
+ display_timings_release(timings);
+ return ret;
+}
+
+static int of_get_pxafb_mode_info(struct device *dev,
+ struct pxafb_mach_info *info)
+{
+ struct device_node *display, *np;
+ u32 bus_width;
+ int ret, i;
+
+ np = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (!np) {
+ dev_err(dev, "could not find endpoint\n");
+ return -EINVAL;
+ }
+ ret = of_property_read_u32(np, "bus-width", &bus_width);
+ if (ret) {
+ dev_err(dev, "no bus-width specified: %d\n", ret);
+ return ret;
+ }
+
+ display = of_graph_get_remote_port_parent(np);
+ of_node_put(np);
+ if (!display) {
+ dev_err(dev, "no display defined\n");
+ return -EINVAL;
+ }
+
+ ret = of_get_pxafb_display(dev, display, info, bus_width);
+ of_node_put(display);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < info->num_modes; i++)
+ info->modes[i].bpp = bus_width;
+
+ return 0;
+}
+
+static struct pxafb_mach_info *of_pxafb_of_mach_info(struct device *dev)
+{
+ int ret;
+ struct pxafb_mach_info *info;
+
+ if (!dev->of_node)
+ return NULL;
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+ ret = of_get_pxafb_mode_info(dev, info);
+ if (ret) {
+ kfree(info->modes);
+ return ERR_PTR(ret);
+ }
+
+ /*
+ * On purpose, neither lccrX registers nor video memory size can be
+ * specified through device-tree, they are considered more a debug hack
+ * available through command line.
+ */
+ return info;
+}
+#else
+static struct pxafb_mach_info *of_pxafb_of_mach_info(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int pxafb_probe(struct platform_device *dev)
{
struct pxafb_info *fbi;
- struct pxafb_mach_info *inf;
+ struct pxafb_mach_info *inf, *pdata;
struct resource *r;
- int irq, ret;
+ int i, irq, ret;
dev_dbg(&dev->dev, "pxafb_probe\n");
- inf = dev_get_platdata(&dev->dev);
ret = -ENOMEM;
- fbi = NULL;
+ pdata = dev_get_platdata(&dev->dev);
+ inf = devm_kmalloc(&dev->dev, sizeof(*inf), GFP_KERNEL);
if (!inf)
goto failed;
- ret = pxafb_parse_options(&dev->dev, g_options);
+ if (pdata) {
+ *inf = *pdata;
+ inf->modes =
+ devm_kmalloc_array(&dev->dev, pdata->num_modes,
+ sizeof(inf->modes[0]), GFP_KERNEL);
+ if (!inf->modes)
+ goto failed;
+ for (i = 0; i < inf->num_modes; i++)
+ inf->modes[i] = pdata->modes[i];
+ }
+
+ if (!pdata)
+ inf = of_pxafb_of_mach_info(&dev->dev);
+ if (IS_ERR_OR_NULL(inf))
+ goto failed;
+
+ ret = pxafb_parse_options(&dev->dev, g_options, inf);
if (ret < 0)
goto failed;
@@ -2125,7 +2286,7 @@ static int pxafb_probe(struct platform_device *dev)
goto failed;
}
- fbi = pxafb_init_fbinfo(&dev->dev);
+ fbi = pxafb_init_fbinfo(&dev->dev, inf);
if (!fbi) {
/* only reason for pxafb_init_fbinfo to fail is kmalloc */
dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
@@ -2299,11 +2460,20 @@ static int pxafb_remove(struct platform_device *dev)
return 0;
}
+static const struct of_device_id pxafb_of_dev_id[] = {
+ { .compatible = "marvell,pxa270-lcdc", },
+ { .compatible = "marvell,pxa300-lcdc", },
+ { .compatible = "marvell,pxa2xx-lcdc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pxafb_of_dev_id);
+
static struct platform_driver pxafb_driver = {
.probe = pxafb_probe,
.remove = pxafb_remove,
.driver = {
.name = "pxa2xx-fb",
+ .of_match_table = pxafb_of_dev_id,
#ifdef CONFIG_PM
.pm = &pxafb_pm_ops,
#endif
diff --git a/drivers/video/fbdev/pxafb.h b/drivers/video/fbdev/pxafb.h
index 26ba9fa3f737..5dc414e26fc8 100644
--- a/drivers/video/fbdev/pxafb.h
+++ b/drivers/video/fbdev/pxafb.h
@@ -167,6 +167,8 @@ struct pxafb_info {
void (*lcd_power)(int, struct fb_var_screeninfo *);
void (*backlight_power)(int);
+
+ struct pxafb_mach_info *inf;
};
#define TO_INF(ptr,member) container_of(ptr,struct pxafb_info,member)
diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c
index f1ad2747064b..2ef26ad99341 100644
--- a/drivers/video/fbdev/riva/fbdev.c
+++ b/drivers/video/fbdev/riva/fbdev.c
@@ -1765,6 +1765,7 @@ static int riva_get_EDID_i2c(struct fb_info *info)
int i;
NVTRACE_ENTER();
+ par->riva.LockUnlock(&par->riva, 0);
riva_create_i2c_busses(par);
for (i = 0; i < 3; i++) {
if (!par->chan[i].par)
diff --git a/drivers/video/fbdev/sh_mobile_hdmi.c b/drivers/video/fbdev/sh_mobile_hdmi.c
deleted file mode 100644
index 7c72a3f02056..000000000000
--- a/drivers/video/fbdev/sh_mobile_hdmi.c
+++ /dev/null
@@ -1,1489 +0,0 @@
-/*
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/initval.h>
-
-#include <video/sh_mobile_hdmi.h>
-#include <video/sh_mobile_lcdc.h>
-
-#include "sh_mobile_lcdcfb.h"
-
-/* HDMI Core Control Register (HTOP0) */
-#define HDMI_SYSTEM_CTRL 0x00 /* System control */
-#define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control,
- bits 19..16 of 20-bit N for Audio Clock Regeneration packet */
-#define HDMI_20_BIT_N_FOR_AUDIO_RPKT_15_8 0x02 /* bits 15..8 of 20-bit N for Audio Clock Regeneration packet */
-#define HDMI_20_BIT_N_FOR_AUDIO_RPKT_7_0 0x03 /* bits 7..0 of 20-bit N for Audio Clock Regeneration packet */
-#define HDMI_SPDIF_AUDIO_SAMP_FREQ_CTS 0x04 /* SPDIF audio sampling frequency,
- bits 19..16 of Internal CTS */
-#define HDMI_INTERNAL_CTS_15_8 0x05 /* bits 15..8 of Internal CTS */
-#define HDMI_INTERNAL_CTS_7_0 0x06 /* bits 7..0 of Internal CTS */
-#define HDMI_EXTERNAL_CTS_19_16 0x07 /* External CTS */
-#define HDMI_EXTERNAL_CTS_15_8 0x08 /* External CTS */
-#define HDMI_EXTERNAL_CTS_7_0 0x09 /* External CTS */
-#define HDMI_AUDIO_SETTING_1 0x0A /* Audio setting.1 */
-#define HDMI_AUDIO_SETTING_2 0x0B /* Audio setting.2 */
-#define HDMI_I2S_AUDIO_SET 0x0C /* I2S audio setting */
-#define HDMI_DSD_AUDIO_SET 0x0D /* DSD audio setting */
-#define HDMI_DEBUG_MONITOR_1 0x0E /* Debug monitor.1 */
-#define HDMI_DEBUG_MONITOR_2 0x0F /* Debug monitor.2 */
-#define HDMI_I2S_INPUT_PIN_SWAP 0x10 /* I2S input pin swap */
-#define HDMI_AUDIO_STATUS_BITS_SETTING_1 0x11 /* Audio status bits setting.1 */
-#define HDMI_AUDIO_STATUS_BITS_SETTING_2 0x12 /* Audio status bits setting.2 */
-#define HDMI_CATEGORY_CODE 0x13 /* Category code */
-#define HDMI_SOURCE_NUM_AUDIO_WORD_LEN 0x14 /* Source number/Audio word length */
-#define HDMI_AUDIO_VIDEO_SETTING_1 0x15 /* Audio/Video setting.1 */
-#define HDMI_VIDEO_SETTING_1 0x16 /* Video setting.1 */
-#define HDMI_DEEP_COLOR_MODES 0x17 /* Deep Color Modes */
-
-/* 12 16- and 10-bit Color space conversion parameters: 0x18..0x2f */
-#define HDMI_COLOR_SPACE_CONVERSION_PARAMETERS 0x18
-
-#define HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS 0x30 /* External video parameter settings */
-#define HDMI_EXTERNAL_H_TOTAL_7_0 0x31 /* External horizontal total (LSB) */
-#define HDMI_EXTERNAL_H_TOTAL_11_8 0x32 /* External horizontal total (MSB) */
-#define HDMI_EXTERNAL_H_BLANK_7_0 0x33 /* External horizontal blank (LSB) */
-#define HDMI_EXTERNAL_H_BLANK_9_8 0x34 /* External horizontal blank (MSB) */
-#define HDMI_EXTERNAL_H_DELAY_7_0 0x35 /* External horizontal delay (LSB) */
-#define HDMI_EXTERNAL_H_DELAY_9_8 0x36 /* External horizontal delay (MSB) */
-#define HDMI_EXTERNAL_H_DURATION_7_0 0x37 /* External horizontal duration (LSB) */
-#define HDMI_EXTERNAL_H_DURATION_9_8 0x38 /* External horizontal duration (MSB) */
-#define HDMI_EXTERNAL_V_TOTAL_7_0 0x39 /* External vertical total (LSB) */
-#define HDMI_EXTERNAL_V_TOTAL_9_8 0x3A /* External vertical total (MSB) */
-#define HDMI_AUDIO_VIDEO_SETTING_2 0x3B /* Audio/Video setting.2 */
-#define HDMI_EXTERNAL_V_BLANK 0x3D /* External vertical blank */
-#define HDMI_EXTERNAL_V_DELAY 0x3E /* External vertical delay */
-#define HDMI_EXTERNAL_V_DURATION 0x3F /* External vertical duration */
-#define HDMI_CTRL_PKT_MANUAL_SEND_CONTROL 0x40 /* Control packet manual send control */
-#define HDMI_CTRL_PKT_AUTO_SEND 0x41 /* Control packet auto send with VSYNC control */
-#define HDMI_AUTO_CHECKSUM_OPTION 0x42 /* Auto checksum option */
-#define HDMI_VIDEO_SETTING_2 0x45 /* Video setting.2 */
-#define HDMI_OUTPUT_OPTION 0x46 /* Output option */
-#define HDMI_SLIPHDMIT_PARAM_OPTION 0x51 /* SLIPHDMIT parameter option */
-#define HDMI_HSYNC_PMENT_AT_EMB_7_0 0x52 /* HSYNC placement at embedded sync (LSB) */
-#define HDMI_HSYNC_PMENT_AT_EMB_15_8 0x53 /* HSYNC placement at embedded sync (MSB) */
-#define HDMI_VSYNC_PMENT_AT_EMB_7_0 0x54 /* VSYNC placement at embedded sync (LSB) */
-#define HDMI_VSYNC_PMENT_AT_EMB_14_8 0x55 /* VSYNC placement at embedded sync (MSB) */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_1 0x56 /* SLIPHDMIT parameter settings.1 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_2 0x57 /* SLIPHDMIT parameter settings.2 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_3 0x58 /* SLIPHDMIT parameter settings.3 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_5 0x59 /* SLIPHDMIT parameter settings.5 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_6 0x5A /* SLIPHDMIT parameter settings.6 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_7 0x5B /* SLIPHDMIT parameter settings.7 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_8 0x5C /* SLIPHDMIT parameter settings.8 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_9 0x5D /* SLIPHDMIT parameter settings.9 */
-#define HDMI_SLIPHDMIT_PARAM_SETTINGS_10 0x5E /* SLIPHDMIT parameter settings.10 */
-#define HDMI_CTRL_PKT_BUF_INDEX 0x5F /* Control packet buffer index */
-#define HDMI_CTRL_PKT_BUF_ACCESS_HB0 0x60 /* Control packet data buffer access window - HB0 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_HB1 0x61 /* Control packet data buffer access window - HB1 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_HB2 0x62 /* Control packet data buffer access window - HB2 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB0 0x63 /* Control packet data buffer access window - PB0 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB1 0x64 /* Control packet data buffer access window - PB1 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB2 0x65 /* Control packet data buffer access window - PB2 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB3 0x66 /* Control packet data buffer access window - PB3 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB4 0x67 /* Control packet data buffer access window - PB4 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB5 0x68 /* Control packet data buffer access window - PB5 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB6 0x69 /* Control packet data buffer access window - PB6 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB7 0x6A /* Control packet data buffer access window - PB7 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB8 0x6B /* Control packet data buffer access window - PB8 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB9 0x6C /* Control packet data buffer access window - PB9 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB10 0x6D /* Control packet data buffer access window - PB10 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB11 0x6E /* Control packet data buffer access window - PB11 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB12 0x6F /* Control packet data buffer access window - PB12 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB13 0x70 /* Control packet data buffer access window - PB13 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB14 0x71 /* Control packet data buffer access window - PB14 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB15 0x72 /* Control packet data buffer access window - PB15 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB16 0x73 /* Control packet data buffer access window - PB16 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB17 0x74 /* Control packet data buffer access window - PB17 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB18 0x75 /* Control packet data buffer access window - PB18 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB19 0x76 /* Control packet data buffer access window - PB19 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB20 0x77 /* Control packet data buffer access window - PB20 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB21 0x78 /* Control packet data buffer access window - PB21 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB22 0x79 /* Control packet data buffer access window - PB22 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB23 0x7A /* Control packet data buffer access window - PB23 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB24 0x7B /* Control packet data buffer access window - PB24 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB25 0x7C /* Control packet data buffer access window - PB25 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB26 0x7D /* Control packet data buffer access window - PB26 */
-#define HDMI_CTRL_PKT_BUF_ACCESS_PB27 0x7E /* Control packet data buffer access window - PB27 */
-#define HDMI_EDID_KSV_FIFO_ACCESS_WINDOW 0x80 /* EDID/KSV FIFO access window */
-#define HDMI_DDC_BUS_ACCESS_FREQ_CTRL_7_0 0x81 /* DDC bus access frequency control (LSB) */
-#define HDMI_DDC_BUS_ACCESS_FREQ_CTRL_15_8 0x82 /* DDC bus access frequency control (MSB) */
-#define HDMI_INTERRUPT_MASK_1 0x92 /* Interrupt mask.1 */
-#define HDMI_INTERRUPT_MASK_2 0x93 /* Interrupt mask.2 */
-#define HDMI_INTERRUPT_STATUS_1 0x94 /* Interrupt status.1 */
-#define HDMI_INTERRUPT_STATUS_2 0x95 /* Interrupt status.2 */
-#define HDMI_INTERRUPT_MASK_3 0x96 /* Interrupt mask.3 */
-#define HDMI_INTERRUPT_MASK_4 0x97 /* Interrupt mask.4 */
-#define HDMI_INTERRUPT_STATUS_3 0x98 /* Interrupt status.3 */
-#define HDMI_INTERRUPT_STATUS_4 0x99 /* Interrupt status.4 */
-#define HDMI_SOFTWARE_HDCP_CONTROL_1 0x9A /* Software HDCP control.1 */
-#define HDMI_FRAME_COUNTER 0x9C /* Frame counter */
-#define HDMI_FRAME_COUNTER_FOR_RI_CHECK 0x9D /* Frame counter for Ri check */
-#define HDMI_HDCP_CONTROL 0xAF /* HDCP control */
-#define HDMI_RI_FRAME_COUNT_REGISTER 0xB2 /* Ri frame count register */
-#define HDMI_DDC_BUS_CONTROL 0xB7 /* DDC bus control */
-#define HDMI_HDCP_STATUS 0xB8 /* HDCP status */
-#define HDMI_SHA0 0xB9 /* sha0 */
-#define HDMI_SHA1 0xBA /* sha1 */
-#define HDMI_SHA2 0xBB /* sha2 */
-#define HDMI_SHA3 0xBC /* sha3 */
-#define HDMI_SHA4 0xBD /* sha4 */
-#define HDMI_BCAPS_READ 0xBE /* BCAPS read / debug */
-#define HDMI_AKSV_BKSV_7_0_MONITOR 0xBF /* AKSV/BKSV[7:0] monitor */
-#define HDMI_AKSV_BKSV_15_8_MONITOR 0xC0 /* AKSV/BKSV[15:8] monitor */
-#define HDMI_AKSV_BKSV_23_16_MONITOR 0xC1 /* AKSV/BKSV[23:16] monitor */
-#define HDMI_AKSV_BKSV_31_24_MONITOR 0xC2 /* AKSV/BKSV[31:24] monitor */
-#define HDMI_AKSV_BKSV_39_32_MONITOR 0xC3 /* AKSV/BKSV[39:32] monitor */
-#define HDMI_EDID_SEGMENT_POINTER 0xC4 /* EDID segment pointer */
-#define HDMI_EDID_WORD_ADDRESS 0xC5 /* EDID word address */
-#define HDMI_EDID_DATA_FIFO_ADDRESS 0xC6 /* EDID data FIFO address */
-#define HDMI_NUM_OF_HDMI_DEVICES 0xC7 /* Number of HDMI devices */
-#define HDMI_HDCP_ERROR_CODE 0xC8 /* HDCP error code */
-#define HDMI_100MS_TIMER_SET 0xC9 /* 100ms timer setting */
-#define HDMI_5SEC_TIMER_SET 0xCA /* 5sec timer setting */
-#define HDMI_RI_READ_COUNT 0xCB /* Ri read count */
-#define HDMI_AN_SEED 0xCC /* An seed */
-#define HDMI_MAX_NUM_OF_RCIVRS_ALLOWED 0xCD /* Maximum number of receivers allowed */
-#define HDMI_HDCP_MEMORY_ACCESS_CONTROL_1 0xCE /* HDCP memory access control.1 */
-#define HDMI_HDCP_MEMORY_ACCESS_CONTROL_2 0xCF /* HDCP memory access control.2 */
-#define HDMI_HDCP_CONTROL_2 0xD0 /* HDCP Control 2 */
-#define HDMI_HDCP_KEY_MEMORY_CONTROL 0xD2 /* HDCP Key Memory Control */
-#define HDMI_COLOR_SPACE_CONV_CONFIG_1 0xD3 /* Color space conversion configuration.1 */
-#define HDMI_VIDEO_SETTING_3 0xD4 /* Video setting.3 */
-#define HDMI_RI_7_0 0xD5 /* Ri[7:0] */
-#define HDMI_RI_15_8 0xD6 /* Ri[15:8] */
-#define HDMI_PJ 0xD7 /* Pj */
-#define HDMI_SHA_RD 0xD8 /* sha_rd */
-#define HDMI_RI_7_0_SAVED 0xD9 /* Ri[7:0] saved */
-#define HDMI_RI_15_8_SAVED 0xDA /* Ri[15:8] saved */
-#define HDMI_PJ_SAVED 0xDB /* Pj saved */
-#define HDMI_NUM_OF_DEVICES 0xDC /* Number of devices */
-#define HDMI_HOT_PLUG_MSENS_STATUS 0xDF /* Hot plug/MSENS status */
-#define HDMI_BCAPS_WRITE 0xE0 /* bcaps */
-#define HDMI_BSTAT_7_0 0xE1 /* bstat[7:0] */
-#define HDMI_BSTAT_15_8 0xE2 /* bstat[15:8] */
-#define HDMI_BKSV_7_0 0xE3 /* bksv[7:0] */
-#define HDMI_BKSV_15_8 0xE4 /* bksv[15:8] */
-#define HDMI_BKSV_23_16 0xE5 /* bksv[23:16] */
-#define HDMI_BKSV_31_24 0xE6 /* bksv[31:24] */
-#define HDMI_BKSV_39_32 0xE7 /* bksv[39:32] */
-#define HDMI_AN_7_0 0xE8 /* An[7:0] */
-#define HDMI_AN_15_8 0xE9 /* An [15:8] */
-#define HDMI_AN_23_16 0xEA /* An [23:16] */
-#define HDMI_AN_31_24 0xEB /* An [31:24] */
-#define HDMI_AN_39_32 0xEC /* An [39:32] */
-#define HDMI_AN_47_40 0xED /* An [47:40] */
-#define HDMI_AN_55_48 0xEE /* An [55:48] */
-#define HDMI_AN_63_56 0xEF /* An [63:56] */
-#define HDMI_PRODUCT_ID 0xF0 /* Product ID */
-#define HDMI_REVISION_ID 0xF1 /* Revision ID */
-#define HDMI_TEST_MODE 0xFE /* Test mode */
-
-/* HDMI Control Register (HTOP1) */
-#define HDMI_HTOP1_TEST_MODE 0x0000 /* Test mode */
-#define HDMI_HTOP1_VIDEO_INPUT 0x0008 /* VideoInput */
-#define HDMI_HTOP1_CORE_RSTN 0x000C /* CoreResetn */
-#define HDMI_HTOP1_PLLBW 0x0018 /* PLLBW */
-#define HDMI_HTOP1_CLK_TO_PHY 0x001C /* Clk to Phy */
-#define HDMI_HTOP1_VIDEO_INPUT2 0x0020 /* VideoInput2 */
-#define HDMI_HTOP1_TISEMP0_1 0x0024 /* tisemp0-1 */
-#define HDMI_HTOP1_TISEMP2_C 0x0028 /* tisemp2-c */
-#define HDMI_HTOP1_TISIDRV 0x002C /* tisidrv */
-#define HDMI_HTOP1_TISEN 0x0034 /* tisen */
-#define HDMI_HTOP1_TISDREN 0x0038 /* tisdren */
-#define HDMI_HTOP1_CISRANGE 0x003C /* cisrange */
-#define HDMI_HTOP1_ENABLE_SELECTOR 0x0040 /* Enable Selector */
-#define HDMI_HTOP1_MACRO_RESET 0x0044 /* Macro reset */
-#define HDMI_HTOP1_PLL_CALIBRATION 0x0048 /* PLL calibration */
-#define HDMI_HTOP1_RE_CALIBRATION 0x004C /* Re-calibration */
-#define HDMI_HTOP1_CURRENT 0x0050 /* Current */
-#define HDMI_HTOP1_PLL_LOCK_DETECT 0x0054 /* PLL lock detect */
-#define HDMI_HTOP1_PHY_TEST_MODE 0x0058 /* PHY Test Mode */
-#define HDMI_HTOP1_CLK_SET 0x0080 /* Clock Set */
-#define HDMI_HTOP1_DDC_FAIL_SAFE 0x0084 /* DDC fail safe */
-#define HDMI_HTOP1_PRBS 0x0088 /* PRBS */
-#define HDMI_HTOP1_EDID_AINC_CONTROL 0x008C /* EDID ainc Control */
-#define HDMI_HTOP1_HTOP_DCL_MODE 0x00FC /* Deep Coloer Mode */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF0 0x0100 /* Deep Color:FRC COEF0 */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF1 0x0104 /* Deep Color:FRC COEF1 */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF2 0x0108 /* Deep Color:FRC COEF2 */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF3 0x010C /* Deep Color:FRC COEF3 */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF0_C 0x0110 /* Deep Color:FRC COEF0C */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF1_C 0x0114 /* Deep Color:FRC COEF1C */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF2_C 0x0118 /* Deep Color:FRC COEF2C */
-#define HDMI_HTOP1_HTOP_DCL_FRC_COEF3_C 0x011C /* Deep Color:FRC COEF3C */
-#define HDMI_HTOP1_HTOP_DCL_FRC_MODE 0x0120 /* Deep Color:FRC Mode */
-#define HDMI_HTOP1_HTOP_DCL_RECT_START1 0x0124 /* Deep Color:Rect Start1 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE1 0x0128 /* Deep Color:Rect Size1 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_START2 0x012C /* Deep Color:Rect Start2 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE2 0x0130 /* Deep Color:Rect Size2 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_START3 0x0134 /* Deep Color:Rect Start3 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE3 0x0138 /* Deep Color:Rect Size3 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_START4 0x013C /* Deep Color:Rect Start4 */
-#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE4 0x0140 /* Deep Color:Rect Size4 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1 0x0144 /* Deep Color:Fil Para Y1_1 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2 0x0148 /* Deep Color:Fil Para Y1_2 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1 0x014C /* Deep Color:Fil Para CB1_1 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2 0x0150 /* Deep Color:Fil Para CB1_2 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1 0x0154 /* Deep Color:Fil Para CR1_1 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2 0x0158 /* Deep Color:Fil Para CR1_2 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1 0x015C /* Deep Color:Fil Para Y2_1 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2 0x0160 /* Deep Color:Fil Para Y2_2 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1 0x0164 /* Deep Color:Fil Para CB2_1 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2 0x0168 /* Deep Color:Fil Para CB2_2 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1 0x016C /* Deep Color:Fil Para CR2_1 */
-#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2 0x0170 /* Deep Color:Fil Para CR2_2 */
-#define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1 0x0174 /* Deep Color:Cor Para Y1 */
-#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1 0x0178 /* Deep Color:Cor Para CB1 */
-#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1 0x017C /* Deep Color:Cor Para CR1 */
-#define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2 0x0180 /* Deep Color:Cor Para Y2 */
-#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2 0x0184 /* Deep Color:Cor Para CB2 */
-#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2 0x0188 /* Deep Color:Cor Para CR2 */
-#define HDMI_HTOP1_EDID_DATA_READ 0x0200 /* EDID Data Read 128Byte:0x03FC */
-
-enum hotplug_state {
- HDMI_HOTPLUG_DISCONNECTED,
- HDMI_HOTPLUG_CONNECTED,
- HDMI_HOTPLUG_EDID_DONE,
-};
-
-struct sh_hdmi {
- struct sh_mobile_lcdc_entity entity;
-
- void __iomem *base;
- void __iomem *htop1;
- enum hotplug_state hp_state; /* hot-plug status */
- u8 preprogrammed_vic; /* use a pre-programmed VIC or
- the external mode */
- u8 edid_block_addr;
- u8 edid_segment_nr;
- u8 edid_blocks;
- int irq;
- struct clk *hdmi_clk;
- struct device *dev;
- struct delayed_work edid_work;
- struct fb_videomode mode;
- struct fb_monspecs monspec;
-
- /* register access functions */
- void (*write)(struct sh_hdmi *hdmi, u8 data, u8 reg);
- u8 (*read)(struct sh_hdmi *hdmi, u8 reg);
-};
-
-#define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity)
-
-static void __hdmi_write8(struct sh_hdmi *hdmi, u8 data, u8 reg)
-{
- iowrite8(data, hdmi->base + reg);
-}
-
-static u8 __hdmi_read8(struct sh_hdmi *hdmi, u8 reg)
-{
- return ioread8(hdmi->base + reg);
-}
-
-static void __hdmi_write32(struct sh_hdmi *hdmi, u8 data, u8 reg)
-{
- iowrite32((u32)data, hdmi->base + (reg * 4));
- udelay(100);
-}
-
-static u8 __hdmi_read32(struct sh_hdmi *hdmi, u8 reg)
-{
- return (u8)ioread32(hdmi->base + (reg * 4));
-}
-
-static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
-{
- hdmi->write(hdmi, data, reg);
-}
-
-static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
-{
- return hdmi->read(hdmi, reg);
-}
-
-static void hdmi_bit_set(struct sh_hdmi *hdmi, u8 mask, u8 data, u8 reg)
-{
- u8 val = hdmi_read(hdmi, reg);
-
- val &= ~mask;
- val |= (data & mask);
-
- hdmi_write(hdmi, val, reg);
-}
-
-static void hdmi_htop1_write(struct sh_hdmi *hdmi, u32 data, u32 reg)
-{
- iowrite32(data, hdmi->htop1 + reg);
- udelay(100);
-}
-
-static u32 hdmi_htop1_read(struct sh_hdmi *hdmi, u32 reg)
-{
- return ioread32(hdmi->htop1 + reg);
-}
-
-/*
- * HDMI sound
- */
-static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
-
- return hdmi_read(hdmi, reg);
-}
-
-static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
- unsigned int reg,
- unsigned int value)
-{
- struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
-
- hdmi_write(hdmi, value, reg);
- return 0;
-}
-
-static struct snd_soc_dai_driver sh_hdmi_dai = {
- .name = "sh_mobile_hdmi-hifi",
- .playback = {
- .stream_name = "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,
- },
-};
-
-static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
-{
- dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
-
- return 0;
-}
-
-static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
- .probe = sh_hdmi_snd_probe,
- .read = sh_hdmi_snd_read,
- .write = sh_hdmi_snd_write,
-};
-
-/*
- * HDMI video
- */
-
-/* External video parameter settings */
-static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
-{
- struct fb_videomode *mode = &hdmi->mode;
- u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset;
- u8 sync = 0;
-
- htotal = mode->xres + mode->right_margin + mode->left_margin
- + mode->hsync_len;
- hdelay = mode->hsync_len + mode->left_margin;
- hblank = mode->right_margin + hdelay;
-
- /*
- * Vertical timing looks a bit different in Figure 18,
- * but let's try the same first by setting offset = 0
- */
- vtotal = mode->yres + mode->upper_margin + mode->lower_margin
- + mode->vsync_len;
- vdelay = mode->vsync_len + mode->upper_margin;
- vblank = mode->lower_margin + vdelay;
- voffset = min(mode->upper_margin / 2, 6U);
-
- /*
- * [3]: VSYNC polarity: Positive
- * [2]: HSYNC polarity: Positive
- * [1]: Interlace/Progressive: Progressive
- * [0]: External video settings enable: used.
- */
- if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
- sync |= 4;
- if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
- sync |= 8;
-
- dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n",
- htotal, hblank, hdelay, mode->hsync_len,
- vtotal, vblank, vdelay, mode->vsync_len, sync);
-
- hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS);
-
- hdmi_write(hdmi, htotal, HDMI_EXTERNAL_H_TOTAL_7_0);
- hdmi_write(hdmi, htotal >> 8, HDMI_EXTERNAL_H_TOTAL_11_8);
-
- hdmi_write(hdmi, hblank, HDMI_EXTERNAL_H_BLANK_7_0);
- hdmi_write(hdmi, hblank >> 8, HDMI_EXTERNAL_H_BLANK_9_8);
-
- hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0);
- hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8);
-
- hdmi_write(hdmi, mode->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0);
- hdmi_write(hdmi, mode->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8);
-
- hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0);
- hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8);
-
- hdmi_write(hdmi, vblank, HDMI_EXTERNAL_V_BLANK);
-
- hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY);
-
- hdmi_write(hdmi, mode->vsync_len, HDMI_EXTERNAL_V_DURATION);
-
- /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */
- if (!hdmi->preprogrammed_vic)
- hdmi_write(hdmi, sync | 1 | (voffset << 4),
- HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS);
-}
-
-/**
- * sh_hdmi_video_config()
- */
-static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
-{
- /*
- * [7:4]: Audio sampling frequency: 48kHz
- * [3:1]: Input video format: RGB and YCbCr 4:4:4 (Y on Green)
- * [0]: Internal/External DE select: internal
- */
- hdmi_write(hdmi, 0x20, HDMI_AUDIO_VIDEO_SETTING_1);
-
- /*
- * [7:6]: Video output format: RGB 4:4:4
- * [5:4]: Input video data width: 8 bit
- * [3:1]: EAV/SAV location: channel 1
- * [0]: Video input color space: RGB
- */
- hdmi_write(hdmi, 0x34, HDMI_VIDEO_SETTING_1);
-
- /*
- * [7:6]: Together with bit [6] of HDMI_AUDIO_VIDEO_SETTING_2, which is
- * left at 0 by default, this configures 24bpp and sets the Color Depth
- * (CD) field in the General Control Packet
- */
- hdmi_write(hdmi, 0x20, HDMI_DEEP_COLOR_MODES);
-}
-
-/**
- * sh_hdmi_audio_config()
- */
-static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
-{
- u8 data;
- struct sh_mobile_hdmi_info *pdata = dev_get_platdata(hdmi->dev);
-
- /*
- * [7:4] L/R data swap control
- * [3:0] appropriate N[19:16]
- */
- hdmi_write(hdmi, 0x00, HDMI_L_R_DATA_SWAP_CTRL_RPKT);
- /* appropriate N[15:8] */
- hdmi_write(hdmi, 0x18, HDMI_20_BIT_N_FOR_AUDIO_RPKT_15_8);
- /* appropriate N[7:0] */
- hdmi_write(hdmi, 0x00, HDMI_20_BIT_N_FOR_AUDIO_RPKT_7_0);
-
- /* [7:4] 48 kHz SPDIF not used */
- hdmi_write(hdmi, 0x20, HDMI_SPDIF_AUDIO_SAMP_FREQ_CTS);
-
- /*
- * [6:5] set required down sampling rate if required
- * [4:3] set required audio source
- */
- switch (pdata->flags & HDMI_SND_SRC_MASK) {
- default:
- /* fall through */
- case HDMI_SND_SRC_I2S:
- data = 0x0 << 3;
- break;
- case HDMI_SND_SRC_SPDIF:
- data = 0x1 << 3;
- break;
- case HDMI_SND_SRC_DSD:
- data = 0x2 << 3;
- break;
- case HDMI_SND_SRC_HBR:
- data = 0x3 << 3;
- break;
- }
- hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
-
- /* [3:0] set sending channel number for channel status */
- hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
-
- /*
- * [5:2] set valid I2S source input pin
- * [1:0] set input I2S source mode
- */
- hdmi_write(hdmi, 0x04, HDMI_I2S_AUDIO_SET);
-
- /* [7:4] set valid DSD source input pin */
- hdmi_write(hdmi, 0x00, HDMI_DSD_AUDIO_SET);
-
- /* [7:0] set appropriate I2S input pin swap settings if required */
- hdmi_write(hdmi, 0x00, HDMI_I2S_INPUT_PIN_SWAP);
-
- /*
- * [7] set validity bit for channel status
- * [3:0] set original sample frequency for channel status
- */
- hdmi_write(hdmi, 0x00, HDMI_AUDIO_STATUS_BITS_SETTING_1);
-
- /*
- * [7] set value for channel status
- * [6] set value for channel status
- * [5] set copyright bit for channel status
- * [4:2] set additional information for channel status
- * [1:0] set clock accuracy for channel status
- */
- hdmi_write(hdmi, 0x00, HDMI_AUDIO_STATUS_BITS_SETTING_2);
-
- /* [7:0] set category code for channel status */
- hdmi_write(hdmi, 0x00, HDMI_CATEGORY_CODE);
-
- /*
- * [7:4] set source number for channel status
- * [3:0] set word length for channel status
- */
- hdmi_write(hdmi, 0x00, HDMI_SOURCE_NUM_AUDIO_WORD_LEN);
-
- /* [7:4] set sample frequency for channel status */
- hdmi_write(hdmi, 0x20, HDMI_AUDIO_VIDEO_SETTING_1);
-}
-
-/**
- * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode
- */
-static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
-{
- if (hdmi->mode.pixclock < 10000) {
- /* for 1080p8bit 148MHz */
- hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3);
- hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5);
- hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6);
- hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7);
- hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
- hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
- hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
- } else if (hdmi->mode.pixclock < 30000) {
- /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */
- /*
- * [1:0] Speed_A
- * [3:2] Speed_B
- * [4] PLLA_Bypass
- * [6] DRV_TEST_EN
- * [7] DRV_TEST_IN
- */
- hdmi_write(hdmi, 0x0f, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
- /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
- /*
- * [2:0] BGR_I_OFFSET
- * [6:4] BGR_V_OFFSET
- */
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3);
- /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */
- hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5);
- /*
- * PLLA_CONFIG[15:8]: regulator voltage[0], CP current,
- * LPF capacitance, LPF resistance[1]
- */
- hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6);
- /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */
- hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7);
- /*
- * PLLB_CONFIG[15:8]: regulator voltage[0], CP current,
- * LPF capacitance, LPF resistance[1]
- */
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
- /* DRV_CONFIG, PE_CONFIG */
- hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
- /*
- * [2:0] AMON_SEL (4 == LPF voltage)
- * [4] PLLA_CONFIG[16]
- * [5] PLLB_CONFIG[16]
- */
- hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
- } else {
- /* for 480p8bit 27MHz */
- hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
- hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3);
- hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5);
- hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6);
- hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7);
- hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
- hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
- hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
- }
-}
-
-/**
- * sh_hdmi_avi_infoframe_setup() - Auxiliary Video Information InfoFrame CONTROL PACKET
- */
-static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi)
-{
- u8 vic;
-
- /* AVI InfoFrame */
- hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX);
-
- /* Packet Type = 0x82 */
- hdmi_write(hdmi, 0x82, HDMI_CTRL_PKT_BUF_ACCESS_HB0);
-
- /* Version = 0x02 */
- hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_ACCESS_HB1);
-
- /* Length = 13 (0x0D) */
- hdmi_write(hdmi, 0x0D, HDMI_CTRL_PKT_BUF_ACCESS_HB2);
-
- /* N. A. Checksum */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0);
-
- /*
- * Y = RGB
- * A0 = No Data
- * B = Bar Data not valid
- * S = No Data
- */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1);
-
- /*
- * [7:6] C = Colorimetry: no data
- * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio
- * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio
- */
- hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2);
-
- /*
- * ITC = No Data
- * EC = xvYCC601
- * Q = Default (depends on video format)
- * SC = No Known non_uniform Scaling
- */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3);
-
- /*
- * VIC should be ignored if external config is used, so, we could just use 0,
- * but play safe and use a valid value in any case just in case
- */
- if (hdmi->preprogrammed_vic)
- vic = hdmi->preprogrammed_vic;
- else
- vic = 4;
- hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4);
-
- /* PR = No Repetition */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5);
-
- /* Line Number of End of Top Bar (lower 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB6);
-
- /* Line Number of End of Top Bar (upper 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB7);
-
- /* Line Number of Start of Bottom Bar (lower 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB8);
-
- /* Line Number of Start of Bottom Bar (upper 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB9);
-
- /* Pixel Number of End of Left Bar (lower 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10);
-
- /* Pixel Number of End of Left Bar (upper 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB11);
-
- /* Pixel Number of Start of Right Bar (lower 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB12);
-
- /* Pixel Number of Start of Right Bar (upper 8 bits) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB13);
-}
-
-/**
- * sh_hdmi_audio_infoframe_setup() - Audio InfoFrame of CONTROL PACKET
- */
-static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi)
-{
- /* Audio InfoFrame */
- hdmi_write(hdmi, 0x08, HDMI_CTRL_PKT_BUF_INDEX);
-
- /* Packet Type = 0x84 */
- hdmi_write(hdmi, 0x84, HDMI_CTRL_PKT_BUF_ACCESS_HB0);
-
- /* Version Number = 0x01 */
- hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_ACCESS_HB1);
-
- /* 0 Length = 10 (0x0A) */
- hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB2);
-
- /* n. a. Checksum */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0);
-
- /* Audio Channel Count = Refer to Stream Header */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1);
-
- /* Refer to Stream Header */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB2);
-
- /* Format depends on coding type (i.e. CT0...CT3) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3);
-
- /* Speaker Channel Allocation = Front Right + Front Left */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB4);
-
- /* Level Shift Value = 0 dB, Down - mix is permitted or no information */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5);
-
- /* Reserved (0) */
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB6);
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB7);
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB8);
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB9);
- hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10);
-}
-
-/**
- * sh_hdmi_configure() - Initialise HDMI for output
- */
-static void sh_hdmi_configure(struct sh_hdmi *hdmi)
-{
- /* Configure video format */
- sh_hdmi_video_config(hdmi);
-
- /* Configure audio format */
- sh_hdmi_audio_config(hdmi);
-
- /* Configure PHY */
- sh_hdmi_phy_config(hdmi);
-
- /* Auxiliary Video Information (AVI) InfoFrame */
- sh_hdmi_avi_infoframe_setup(hdmi);
-
- /* Audio InfoFrame */
- sh_hdmi_audio_infoframe_setup(hdmi);
-
- /*
- * Control packet auto send with VSYNC control: auto send
- * General control, Gamut metadata, ISRC, and ACP packets
- */
- hdmi_write(hdmi, 0x8E, HDMI_CTRL_PKT_AUTO_SEND);
-
- /* FIXME */
- msleep(10);
-
- /* PS mode b->d, reset PLLA and PLLB */
- hdmi_bit_set(hdmi, 0xFC, 0x4C, HDMI_SYSTEM_CTRL);
-
- udelay(10);
-
- hdmi_bit_set(hdmi, 0xFC, 0x40, HDMI_SYSTEM_CTRL);
-}
-
-static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
- const struct fb_videomode *mode,
- unsigned long *hdmi_rate, unsigned long *parent_rate)
-{
- unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error;
- struct sh_mobile_hdmi_info *pdata = dev_get_platdata(hdmi->dev);
-
- *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target);
- if ((long)*hdmi_rate < 0)
- *hdmi_rate = clk_get_rate(hdmi->hdmi_clk);
-
- rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX;
- if (rate_error && pdata->clk_optimize_parent)
- rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate);
- else if (clk_get_parent(hdmi->hdmi_clk))
- *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
-
- dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n",
- mode->left_margin, mode->xres,
- mode->right_margin, mode->hsync_len,
- mode->upper_margin, mode->yres,
- mode->lower_margin, mode->vsync_len);
-
- dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target,
- rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0,
- mode->refresh, *parent_rate);
-
- return rate_error;
-}
-
-static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
- unsigned long *parent_rate)
-{
- struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
- const struct fb_videomode *mode, *found = NULL;
- unsigned int f_width = 0, f_height = 0, f_refresh = 0;
- unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
- bool scanning = false, preferred_bad = false;
- bool use_edid_mode = false;
- u8 edid[128];
- char *forced;
- int i;
-
- /* Read EDID */
- dev_dbg(hdmi->dev, "Read back EDID code:");
- for (i = 0; i < 128; i++) {
- edid[i] = (hdmi->htop1) ?
- (u8)hdmi_htop1_read(hdmi, HDMI_HTOP1_EDID_DATA_READ + (i * 4)) :
- hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW);
-#ifdef DEBUG
- if ((i % 16) == 0) {
- printk(KERN_CONT "\n");
- printk(KERN_DEBUG "%02X | %02X", i, edid[i]);
- } else {
- printk(KERN_CONT " %02X", edid[i]);
- }
-#endif
- }
-#ifdef DEBUG
- printk(KERN_CONT "\n");
-#endif
-
- if (!hdmi->edid_blocks) {
- fb_edid_to_monspecs(edid, &hdmi->monspec);
- hdmi->edid_blocks = edid[126] + 1;
-
- dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n",
- hdmi->monspec.modedb_len, hdmi->edid_blocks - 1);
- } else {
- dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n",
- edid[0], edid[2]);
- fb_edid_add_monspecs(edid, &hdmi->monspec);
- }
-
- if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 +
- (hdmi->edid_block_addr >> 7) + 1) {
- /* More blocks to read */
- if (hdmi->edid_block_addr) {
- hdmi->edid_block_addr = 0;
- hdmi->edid_segment_nr++;
- } else {
- hdmi->edid_block_addr = 0x80;
- }
- /* Set EDID word address */
- hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
- /* Enable EDID interrupt */
- hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
- /* Set EDID segment pointer - starts reading EDID */
- hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
- return -EAGAIN;
- }
-
- /* All E-EDID blocks ready */
- dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len);
-
- fb_get_options("sh_mobile_lcdc", &forced);
- if (forced && *forced) {
- /* Only primitive parsing so far */
- i = sscanf(forced, "%ux%u@%u",
- &f_width, &f_height, &f_refresh);
- if (i < 2) {
- f_width = 0;
- f_height = 0;
- } else {
- /* The user wants us to use the EDID data */
- scanning = true;
- }
- dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n",
- f_width, f_height, f_refresh);
- }
-
- /* Walk monitor modes to find the best or the exact match */
- for (i = 0, mode = hdmi->monspec.modedb;
- i < hdmi->monspec.modedb_len && scanning;
- i++, mode++) {
- unsigned long rate_error;
-
- if (!f_width && !f_height) {
- /*
- * A parameter string "video=sh_mobile_lcdc:0x0" means
- * use the preferred EDID mode. If it is rejected by
- * .fb_check_var(), keep looking, until an acceptable
- * one is found.
- */
- if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad)
- scanning = false;
- else
- continue;
- } else if (f_width != mode->xres || f_height != mode->yres) {
- /* No interest in unmatching modes */
- continue;
- }
-
- rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate);
-
- if (scanning) {
- if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
- /*
- * Exact match if either the refresh rate
- * matches or it hasn't been specified and we've
- * found a mode, for which we can configure the
- * clock precisely
- */
- scanning = false;
- else if (found && found_rate_error <= rate_error)
- /*
- * We otherwise search for the closest matching
- * clock rate - either if no refresh rate has
- * been specified or we cannot find an exactly
- * matching one
- */
- continue;
- }
-
- /* Check if supported: sufficient fb memory, supported clock-rate */
- if (ch && ch->notify &&
- ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, mode,
- NULL)) {
- scanning = true;
- preferred_bad = true;
- continue;
- }
-
- found = mode;
- found_rate_error = rate_error;
- use_edid_mode = true;
- }
-
- /*
- * TODO 1: if no default mode is present, postpone running the config
- * until after the LCDC channel is initialized.
- * TODO 2: consider registering the HDMI platform device from the LCDC
- * driver.
- */
- if (!found && hdmi->entity.def_mode.xres != 0) {
- found = &hdmi->entity.def_mode;
- found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate,
- parent_rate);
- }
-
- /* No cookie today */
- if (!found)
- return -ENXIO;
-
- if (found->xres == 640 && found->yres == 480 && found->refresh == 60)
- hdmi->preprogrammed_vic = 1;
- else if (found->xres == 720 && found->yres == 480 && found->refresh == 60)
- hdmi->preprogrammed_vic = 2;
- else if (found->xres == 720 && found->yres == 576 && found->refresh == 50)
- hdmi->preprogrammed_vic = 17;
- else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60)
- hdmi->preprogrammed_vic = 4;
- else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24)
- hdmi->preprogrammed_vic = 32;
- else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50)
- hdmi->preprogrammed_vic = 31;
- else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60)
- hdmi->preprogrammed_vic = 16;
- else
- hdmi->preprogrammed_vic = 0;
-
- dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), "
- "clock error %luHz\n", use_edid_mode ? "EDID" : "default",
- hdmi->preprogrammed_vic ? "VIC" : "external", found->xres,
- found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000,
- found_rate_error);
-
- hdmi->mode = *found;
- sh_hdmi_external_video_param(hdmi);
-
- return 0;
-}
-
-static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
-{
- struct sh_hdmi *hdmi = dev_id;
- u8 status1, status2, mask1, mask2;
-
- /* mode_b and PLLA and PLLB reset */
- hdmi_bit_set(hdmi, 0xFC, 0x2C, HDMI_SYSTEM_CTRL);
-
- /* How long shall reset be held? */
- udelay(10);
-
- /* mode_b and PLLA and PLLB reset release */
- hdmi_bit_set(hdmi, 0xFC, 0x20, HDMI_SYSTEM_CTRL);
-
- status1 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_1);
- status2 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_2);
-
- mask1 = hdmi_read(hdmi, HDMI_INTERRUPT_MASK_1);
- mask2 = hdmi_read(hdmi, HDMI_INTERRUPT_MASK_2);
-
- /* Correct would be to ack only set bits, but the datasheet requires 0xff */
- hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_1);
- hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2);
-
- if (printk_ratelimit())
- dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n",
- irq, status1, mask1, status2, mask2);
-
- if (!((status1 & mask1) | (status2 & mask2))) {
- return IRQ_NONE;
- } else if (status1 & 0xc0) {
- u8 msens;
-
- /* Datasheet specifies 10ms... */
- udelay(500);
-
- msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS);
- dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens);
- /* Check, if hot plug & MSENS pin status are both high */
- if ((msens & 0xC0) == 0xC0) {
- /* Display plug in */
- hdmi->edid_segment_nr = 0;
- hdmi->edid_block_addr = 0;
- hdmi->edid_blocks = 0;
- hdmi->hp_state = HDMI_HOTPLUG_CONNECTED;
-
- /* Set EDID word address */
- hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS);
- /* Enable EDID interrupt */
- hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
- /* Set EDID segment pointer - starts reading EDID */
- hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
- } else if (!(status1 & 0x80)) {
- /* Display unplug, beware multiple interrupts */
- if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) {
- hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
- schedule_delayed_work(&hdmi->edid_work, 0);
- }
- /* display_off will switch back to mode_a */
- }
- } else if (status1 & 2) {
- /* EDID error interrupt: retry */
- /* Set EDID word address */
- hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
- /* Set EDID segment pointer */
- hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
- } else if (status1 & 4) {
- /* Disable EDID interrupt */
- hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1);
- schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10));
- }
-
- return IRQ_HANDLED;
-}
-
-static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
-{
- struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
-
- dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi,
- hdmi->hp_state);
-
- /*
- * hp_state can be set to
- * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug
- * HDMI_HOTPLUG_CONNECTED: on monitor plug-in
- * HDMI_HOTPLUG_EDID_DONE: on EDID read completion
- */
- if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) {
- /* PS mode d->e. All functions are active */
- hdmi_bit_set(hdmi, 0xFC, 0x80, HDMI_SYSTEM_CTRL);
- dev_dbg(hdmi->dev, "HDMI running\n");
- }
-
- return hdmi->hp_state == HDMI_HOTPLUG_DISCONNECTED
- ? SH_MOBILE_LCDC_DISPLAY_DISCONNECTED
- : SH_MOBILE_LCDC_DISPLAY_CONNECTED;
-}
-
-static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
-{
- struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
-
- dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi);
- /* PS mode e->a */
- hdmi_bit_set(hdmi, 0xFC, 0x10, HDMI_SYSTEM_CTRL);
-}
-
-static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
- .display_on = sh_hdmi_display_on,
- .display_off = sh_hdmi_display_off,
-};
-
-/**
- * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
- * @hdmi: driver context
- * @hdmi_rate: HDMI clock frequency in Hz
- * @parent_rate: if != 0 - set parent clock rate for optimal precision
- * return: configured positive rate if successful
- * 0 if couldn't set the rate, but managed to enable the
- * clock, negative error, if couldn't enable the clock
- */
-static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
- unsigned long parent_rate)
-{
- int ret;
-
- if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
- ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
- if (ret < 0) {
- dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret);
- hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate);
- } else {
- dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate);
- }
- }
-
- ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate);
- if (ret < 0) {
- dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret);
- hdmi_rate = 0;
- } else {
- dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate);
- }
-
- return hdmi_rate;
-}
-
-/* Hotplug interrupt occurred, read EDID */
-static void sh_hdmi_edid_work_fn(struct work_struct *work)
-{
- struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
- struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
- int ret;
-
- dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi,
- hdmi->hp_state);
-
- if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
- unsigned long parent_rate = 0, hdmi_rate;
-
- ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
- if (ret < 0)
- goto out;
-
- hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
-
- /* Reconfigure the clock */
- ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
- if (ret < 0)
- goto out;
-
- msleep(10);
- sh_hdmi_configure(hdmi);
- /* Switched to another (d) power-save mode */
- msleep(10);
-
- if (ch && ch->notify)
- ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT,
- &hdmi->mode, &hdmi->monspec);
- } else {
- hdmi->monspec.modedb_len = 0;
- fb_destroy_modedb(hdmi->monspec.modedb);
- hdmi->monspec.modedb = NULL;
-
- if (ch && ch->notify)
- ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT,
- NULL, NULL);
-
- ret = 0;
- }
-
-out:
- if (ret < 0 && ret != -EAGAIN)
- hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
-
- dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi);
-}
-
-static void sh_hdmi_htop1_init(struct sh_hdmi *hdmi)
-{
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_MODE);
- hdmi_htop1_write(hdmi, 0x0000000b, 0x0010);
- hdmi_htop1_write(hdmi, 0x00006710, HDMI_HTOP1_HTOP_DCL_FRC_MODE);
- hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1);
- hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2);
- hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1);
- hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2);
- hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1);
- hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2);
- hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1);
- hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2);
- hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1);
- hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2);
- hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1);
- hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2);
- hdmi_htop1_write(hdmi, 0x00000008, HDMI_HTOP1_CURRENT);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP0_1);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP2_C);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PHY_TEST_MODE);
- hdmi_htop1_write(hdmi, 0x00000081, HDMI_HTOP1_TISIDRV);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PLLBW);
- hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN);
- hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN);
- hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR);
- hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET);
- hdmi_htop1_write(hdmi, 0x00000016, HDMI_HTOP1_CISRANGE);
- msleep(100);
- hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_ENABLE_SELECTOR);
- msleep(100);
- hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR);
- hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET);
- hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN);
- hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_CLK_TO_PHY);
- hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT2);
- hdmi_htop1_write(hdmi, 0x0000000a, HDMI_HTOP1_CLK_SET);
-}
-
-static int __init sh_hdmi_probe(struct platform_device *pdev)
-{
- struct sh_mobile_hdmi_info *pdata = dev_get_platdata(&pdev->dev);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct resource *htop1_res;
- int irq = platform_get_irq(pdev, 0), ret;
- struct sh_hdmi *hdmi;
- long rate;
-
- if (!res || !pdata || irq < 0)
- return -ENODEV;
-
- htop1_res = NULL;
- if (pdata->flags & HDMI_HAS_HTOP1) {
- htop1_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!htop1_res) {
- dev_err(&pdev->dev, "htop1 needs register base\n");
- return -EINVAL;
- }
- }
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi) {
- dev_err(&pdev->dev, "Cannot allocate device data\n");
- return -ENOMEM;
- }
-
- hdmi->dev = &pdev->dev;
- hdmi->entity.owner = THIS_MODULE;
- hdmi->entity.ops = &sh_hdmi_ops;
- hdmi->irq = irq;
-
- hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
- if (IS_ERR(hdmi->hdmi_clk)) {
- ret = PTR_ERR(hdmi->hdmi_clk);
- dev_err(&pdev->dev, "Unable to get clock: %d\n", ret);
- return ret;
- }
-
- /* select register access functions */
- if (pdata->flags & HDMI_32BIT_REG) {
- hdmi->write = __hdmi_write32;
- hdmi->read = __hdmi_read32;
- } else {
- hdmi->write = __hdmi_write8;
- hdmi->read = __hdmi_read8;
- }
-
- /* An arbitrary relaxed pixclock just to get things started: from standard 480p */
- rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037));
- if (rate > 0)
- rate = sh_hdmi_clk_configure(hdmi, rate, 0);
-
- if (rate < 0) {
- ret = rate;
- goto erate;
- }
-
- ret = clk_prepare_enable(hdmi->hdmi_clk);
- if (ret < 0) {
- dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret);
- goto erate;
- }
-
- dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate);
-
- if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) {
- dev_err(&pdev->dev, "HDMI register region already claimed\n");
- ret = -EBUSY;
- goto ereqreg;
- }
-
- hdmi->base = ioremap(res->start, resource_size(res));
- if (!hdmi->base) {
- dev_err(&pdev->dev, "HDMI register region already claimed\n");
- ret = -ENOMEM;
- goto emap;
- }
-
- platform_set_drvdata(pdev, &hdmi->entity);
-
- INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn);
-
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
-
- /* init interrupt polarity */
- if (pdata->flags & HDMI_OUTPUT_PUSH_PULL)
- hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL);
-
- if (pdata->flags & HDMI_OUTPUT_POLARITY_HI)
- hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL);
-
- /* enable htop1 register if needed */
- if (htop1_res) {
- hdmi->htop1 = ioremap(htop1_res->start, resource_size(htop1_res));
- if (!hdmi->htop1) {
- dev_err(&pdev->dev, "control register region already claimed\n");
- ret = -ENOMEM;
- goto emap_htop1;
- }
- sh_hdmi_htop1_init(hdmi);
- }
-
- /* Product and revision IDs are 0 in sh-mobile version */
- dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
- hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID));
-
- ret = request_irq(irq, sh_hdmi_hotplug, 0,
- dev_name(&pdev->dev), hdmi);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to request irq: %d\n", ret);
- goto ereqirq;
- }
-
- ret = snd_soc_register_codec(&pdev->dev,
- &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
- if (ret < 0) {
- dev_err(&pdev->dev, "codec registration failed\n");
- goto ecodec;
- }
-
- return 0;
-
-ecodec:
- free_irq(irq, hdmi);
-ereqirq:
- if (hdmi->htop1)
- iounmap(hdmi->htop1);
-emap_htop1:
- pm_runtime_put(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- iounmap(hdmi->base);
-emap:
- release_mem_region(res->start, resource_size(res));
-ereqreg:
- clk_disable_unprepare(hdmi->hdmi_clk);
-erate:
- clk_put(hdmi->hdmi_clk);
-
- return ret;
-}
-
-static int __exit sh_hdmi_remove(struct platform_device *pdev)
-{
- struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- snd_soc_unregister_codec(&pdev->dev);
-
- /* No new work will be scheduled, wait for running ISR */
- free_irq(hdmi->irq, hdmi);
- /* Wait for already scheduled work */
- cancel_delayed_work_sync(&hdmi->edid_work);
- pm_runtime_put(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(hdmi->hdmi_clk);
- clk_put(hdmi->hdmi_clk);
- if (hdmi->htop1)
- iounmap(hdmi->htop1);
- iounmap(hdmi->base);
- release_mem_region(res->start, resource_size(res));
-
- return 0;
-}
-
-static int sh_hdmi_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
-
- disable_irq(hdmi->irq);
- /* Wait for already scheduled work */
- cancel_delayed_work_sync(&hdmi->edid_work);
- return 0;
-}
-
-static int sh_hdmi_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sh_mobile_hdmi_info *pdata = dev_get_platdata(dev);
- struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
-
- /* Re-init interrupt polarity */
- if (pdata->flags & HDMI_OUTPUT_PUSH_PULL)
- hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL);
-
- if (pdata->flags & HDMI_OUTPUT_POLARITY_HI)
- hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL);
-
- /* Re-init htop1 */
- if (hdmi->htop1)
- sh_hdmi_htop1_init(hdmi);
-
- /* Now it's safe to enable interrupts again */
- enable_irq(hdmi->irq);
- return 0;
-}
-
-static const struct dev_pm_ops sh_hdmi_pm_ops = {
- .suspend = sh_hdmi_suspend,
- .resume = sh_hdmi_resume,
-};
-
-static struct platform_driver sh_hdmi_driver = {
- .remove = __exit_p(sh_hdmi_remove),
- .driver = {
- .name = "sh-mobile-hdmi",
- .pm = &sh_hdmi_pm_ops,
- },
-};
-
-module_platform_driver_probe(sh_hdmi_driver, sh_hdmi_probe);
-
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
-MODULE_DESCRIPTION("SuperH / ARM-shmobile HDMI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index 52c5c7e63b52..48ccf6db62a2 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -28,7 +28,10 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/parser.h>
+#include <linux/regulator/consumer.h>
static struct fb_fix_screeninfo simplefb_fix = {
.id = "simple",
@@ -174,6 +177,10 @@ struct simplefb_par {
int clk_count;
struct clk **clks;
#endif
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+ u32 regulator_count;
+ struct regulator **regulators;
+#endif
};
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
@@ -269,6 +276,110 @@ static int simplefb_clocks_init(struct simplefb_par *par,
static void simplefb_clocks_destroy(struct simplefb_par *par) { }
#endif
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+
+#define SUPPLY_SUFFIX "-supply"
+
+/*
+ * Regulator handling code.
+ *
+ * Here we handle the num-supplies and vin*-supply properties of our
+ * "simple-framebuffer" dt node. This is necessary so that we can make sure
+ * that any regulators needed by the display hardware that the bootloader
+ * set up for us (and for which it provided a simplefb dt node), stay up,
+ * for the life of the simplefb driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the
+ * regulators.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the regulator definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+static int simplefb_regulators_init(struct simplefb_par *par,
+ struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct property *prop;
+ struct regulator *regulator;
+ const char *p;
+ int count = 0, i = 0, ret;
+
+ if (dev_get_platdata(&pdev->dev) || !np)
+ return 0;
+
+ /* Count the number of regulator supplies */
+ for_each_property_of_node(np, prop) {
+ p = strstr(prop->name, SUPPLY_SUFFIX);
+ if (p && p != prop->name)
+ count++;
+ }
+
+ if (!count)
+ return 0;
+
+ par->regulators = devm_kcalloc(&pdev->dev, count,
+ sizeof(struct regulator *), GFP_KERNEL);
+ if (!par->regulators)
+ return -ENOMEM;
+
+ /* Get all the regulators */
+ for_each_property_of_node(np, prop) {
+ char name[32]; /* 32 is max size of property name */
+
+ p = strstr(prop->name, SUPPLY_SUFFIX);
+ if (!p || p == prop->name)
+ continue;
+
+ strlcpy(name, prop->name,
+ strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1);
+ regulator = devm_regulator_get_optional(&pdev->dev, name);
+ if (IS_ERR(regulator)) {
+ if (PTR_ERR(regulator) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_err(&pdev->dev, "regulator %s not found: %ld\n",
+ name, PTR_ERR(regulator));
+ continue;
+ }
+ par->regulators[i++] = regulator;
+ }
+ par->regulator_count = i;
+
+ /* Enable all the regulators */
+ for (i = 0; i < par->regulator_count; i++) {
+ ret = regulator_enable(par->regulators[i]);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to enable regulator %d: %d\n",
+ i, ret);
+ devm_regulator_put(par->regulators[i]);
+ par->regulators[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static void simplefb_regulators_destroy(struct simplefb_par *par)
+{
+ int i;
+
+ if (!par->regulators)
+ return;
+
+ for (i = 0; i < par->regulator_count; i++)
+ if (par->regulators[i])
+ regulator_disable(par->regulators[i]);
+}
+#else
+static int simplefb_regulators_init(struct simplefb_par *par,
+ struct platform_device *pdev) { return 0; }
+static void simplefb_regulators_destroy(struct simplefb_par *par) { }
+#endif
+
static int simplefb_probe(struct platform_device *pdev)
{
int ret;
@@ -340,6 +451,10 @@ static int simplefb_probe(struct platform_device *pdev)
if (ret < 0)
goto error_unmap;
+ ret = simplefb_regulators_init(par, pdev);
+ if (ret < 0)
+ goto error_clocks;
+
dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
info->fix.smem_start, info->fix.smem_len,
info->screen_base);
@@ -351,13 +466,15 @@ static int simplefb_probe(struct platform_device *pdev)
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
- goto error_clocks;
+ goto error_regulators;
}
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
return 0;
+error_regulators:
+ simplefb_regulators_destroy(par);
error_clocks:
simplefb_clocks_destroy(par);
error_unmap:
@@ -373,6 +490,7 @@ static int simplefb_remove(struct platform_device *pdev)
struct simplefb_par *par = info->par;
unregister_framebuffer(info);
+ simplefb_regulators_destroy(par);
simplefb_clocks_destroy(par);
framebuffer_release(info);
diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c
index 629bfa2d2f51..86ae1d4556fc 100644
--- a/drivers/video/fbdev/sm712fb.c
+++ b/drivers/video/fbdev/sm712fb.c
@@ -28,9 +28,7 @@
#include <linux/console.h>
#include <linux/screen_info.h>
-#ifdef CONFIG_PM
#include <linux/pm.h>
-#endif
#include "sm712.h"
@@ -1545,8 +1543,7 @@ static void smtcfb_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-#ifdef CONFIG_PM
-static int smtcfb_pci_suspend(struct device *device)
+static int __maybe_unused smtcfb_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct smtcfb_info *sfb;
@@ -1569,7 +1566,7 @@ static int smtcfb_pci_suspend(struct device *device)
return 0;
}
-static int smtcfb_pci_resume(struct device *device)
+static int __maybe_unused smtcfb_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct smtcfb_info *sfb;
@@ -1610,20 +1607,13 @@ static int smtcfb_pci_resume(struct device *device)
}
static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
-#define SM7XX_PM_OPS (&sm7xx_pm_ops)
-
-#else /* !CONFIG_PM */
-
-#define SM7XX_PM_OPS NULL
-
-#endif /* !CONFIG_PM */
static struct pci_driver smtcfb_driver = {
.name = "smtcfb",
.id_table = smtcfb_pci_table,
.probe = smtcfb_pci_probe,
.remove = smtcfb_pci_remove,
- .driver.pm = SM7XX_PM_OPS,
+ .driver.pm = &sm7xx_pm_ops,
};
static int __init sm712fb_init(void)
diff --git a/drivers/video/fbdev/via/via-gpio.c b/drivers/video/fbdev/via/via-gpio.c
index 6f433b8cee12..1e89c3434071 100644
--- a/drivers/video/fbdev/via/via-gpio.c
+++ b/drivers/video/fbdev/via/via-gpio.c
@@ -6,7 +6,7 @@
*/
#include <linux/spinlock.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/via-core.h>
#include <linux/via-gpio.h>
@@ -83,9 +83,7 @@ struct viafb_gpio_cfg {
static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
int value)
{
- struct viafb_gpio_cfg *cfg = container_of(chip,
- struct viafb_gpio_cfg,
- gpio_chip);
+ struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
u8 reg;
struct viafb_gpio *gpio;
unsigned long flags;
@@ -115,9 +113,7 @@ static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
*/
static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
{
- struct viafb_gpio_cfg *cfg = container_of(chip,
- struct viafb_gpio_cfg,
- gpio_chip);
+ struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
struct viafb_gpio *gpio;
unsigned long flags;
@@ -131,9 +127,7 @@ static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
{
- struct viafb_gpio_cfg *cfg = container_of(chip,
- struct viafb_gpio_cfg,
- gpio_chip);
+ struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
u8 reg;
struct viafb_gpio *gpio;
unsigned long flags;
@@ -142,7 +136,7 @@ static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
gpio = cfg->active_gpios[nr];
reg = via_read_reg(VIASR, gpio->vg_port_index);
spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
- return reg & (0x04 << gpio->vg_mask_shift);
+ return !!(reg & (0x04 << gpio->vg_mask_shift));
}
@@ -255,7 +249,8 @@ static int viafb_gpio_probe(struct platform_device *platdev)
* Get registered.
*/
viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */
- ret = gpiochip_add(&viafb_gpio_config.gpio_chip);
+ ret = gpiochip_add_data(&viafb_gpio_config.gpio_chip,
+ &viafb_gpio_config);
if (ret) {
printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
viafb_gpio_config.gpio_chip.ngpio = 0;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 7efc32945810..0c3691f46575 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -209,8 +209,8 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
*/
if (vb->num_pfns != 0)
tell_host(vb, vb->deflate_vq);
- mutex_unlock(&vb->balloon_lock);
release_pages_balloon(vb);
+ mutex_unlock(&vb->balloon_lock);
return num_freed_pages;
}
@@ -388,7 +388,7 @@ static int init_vqs(struct virtio_balloon *vb)
{
struct virtqueue *vqs[3];
vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
- const char *names[] = { "inflate", "deflate", "stats" };
+ static const char * const names[] = { "inflate", "deflate", "stats" };
int err, nvqs;
/*
diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
index c96944b59856..350a2a5a49db 100644
--- a/drivers/virtio/virtio_input.c
+++ b/drivers/virtio/virtio_input.c
@@ -170,7 +170,7 @@ static int virtinput_init_vqs(struct virtio_input *vi)
struct virtqueue *vqs[2];
vq_callback_t *cbs[] = { virtinput_recv_events,
virtinput_recv_status };
- static const char *names[] = { "events", "status" };
+ static const char * const names[] = { "events", "status" };
int err;
err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names);
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index f499d9da7237..745c6ee1bb3e 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -482,7 +482,7 @@ error_available:
static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
unsigned int irq = platform_get_irq(vm_dev->pdev, 0);
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
index 78f804af6c20..36205c27c4d0 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -296,7 +296,7 @@ void vp_del_vqs(struct virtio_device *vdev)
static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[],
+ const char * const names[],
bool use_msix,
bool per_vq_vectors)
{
@@ -376,7 +376,7 @@ error_find:
int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
int err;
diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h
index b976d968e793..2cc252270b2d 100644
--- a/drivers/virtio/virtio_pci_common.h
+++ b/drivers/virtio/virtio_pci_common.h
@@ -139,7 +139,7 @@ void vp_del_vqs(struct virtio_device *vdev);
int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[]);
+ const char * const names[]);
const char *vp_bus_name(struct virtio_device *vdev);
/* Setup the affinity for a virtqueue:
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index 8e5cf194cc0b..c0c11fad4611 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -418,7 +418,7 @@ err_new_queue:
static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[])
+ const char * const names[])
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
struct virtqueue *vq;
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index ee663c458b20..e12e385f7ac3 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -517,10 +517,10 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
/* If we expect an interrupt for the next entry, tell host
* by writing event index and flush out the write before
* the read in the next get_buf call. */
- if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
- vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx);
- virtio_mb(vq->weak_barriers);
- }
+ if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT))
+ virtio_store_mb(vq->weak_barriers,
+ &vring_used_event(&vq->vring),
+ cpu_to_virtio16(_vq->vdev, vq->last_used_idx));
#ifdef DEBUG
vq->last_add_time_valid = false;
@@ -653,8 +653,11 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
}
/* TODO: tune this threshold */
bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4;
- vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs);
- virtio_mb(vq->weak_barriers);
+
+ virtio_store_mb(vq->weak_barriers,
+ &vring_used_event(&vq->vring),
+ cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs));
+
if (unlikely((u16)(virtio16_to_cpu(_vq->vdev, vq->vring.used->idx) - vq->last_used_idx) > bufs)) {
END_USE(vq);
return false;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 1c427beffadd..4f0e7be0da34 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -46,6 +46,13 @@ config WATCHDOG_NOWAYOUT
get killed. If you say Y here, the watchdog cannot be stopped once
it has been started.
+config WATCHDOG_SYSFS
+ bool "Read different watchdog information through sysfs"
+ default n
+ help
+ Say Y here if you want to enable watchdog device status read through
+ sysfs attributes.
+
#
# General Watchdog drivers
#
@@ -135,6 +142,16 @@ config MENF21BMC_WATCHDOG
This driver can also be built as a module. If so the module
will be called menf21bmc_wdt.
+config TANGOX_WATCHDOG
+ tristate "Sigma Designs SMP86xx/SMP87xx watchdog"
+ select WATCHDOG_CORE
+ depends on ARCH_TANGOX || COMPILE_TEST
+ help
+ Support for the watchdog in Sigma Designs SMP86xx (tango3)
+ and SMP87xx (tango4) family chips.
+
+ This driver can be built as a module. The module name is tangox_wdt.
+
config WM831X_WATCHDOG
tristate "WM831x watchdog"
depends on MFD_WM831X
@@ -161,6 +178,17 @@ config XILINX_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called of_xilinx_wdt.
+config ZIIRAVE_WATCHDOG
+ tristate "Zodiac RAVE Watchdog Timer"
+ depends on I2C
+ select WATCHDOG_CORE
+ help
+ Watchdog driver for the Zodiac Aerospace RAVE Switch Watchdog
+ Processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ziirave_wdt.
+
# ALPHA Architecture
# ARM Architecture
@@ -173,6 +201,16 @@ config ARM_SP805_WATCHDOG
ARM Primecell SP805 Watchdog timer. This will reboot your system when
the timeout is reached.
+config ASM9260_WATCHDOG
+ tristate "Alphascale ASM9260 watchdog"
+ depends on MACH_ASM9260
+ depends on OF
+ select WATCHDOG_CORE
+ select RESET_CONTROLLER
+ help
+ Watchdog timer embedded into Alphascale asm9260 chips. This will reboot your
+ system when the timeout is reached.
+
config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog"
depends on SOC_AT91RM9200 && MFD_SYSCON
@@ -426,6 +464,16 @@ config NUC900_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called nuc900_wdt.
+config TS4800_WATCHDOG
+ tristate "TS-4800 Watchdog"
+ depends on HAS_IOMEM && OF
+ select WATCHDOG_CORE
+ select MFD_SYSCON
+ help
+ Technologic Systems TS-4800 has watchdog timer implemented in
+ an external FPGA. Say Y here if you want to support for the
+ watchdog timer on TS-4800 board.
+
config TS72XX_WATCHDOG
tristate "TS-72XX SBC Watchdog"
depends on MACH_TS72XX
@@ -578,6 +626,16 @@ config LPC18XX_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called lpc18xx_wdt.
+config ATLAS7_WATCHDOG
+ tristate "CSRatlas7 watchdog"
+ depends on ARCH_ATLAS7
+ help
+ Say Y here to include Watchdog timer support for the watchdog
+ existing on the CSRatlas7 series platforms.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atlas7_wdt.
+
# AVR32 Architecture
config AT32AP700X_WDT
@@ -1345,6 +1403,13 @@ config RALINK_WDT
help
Hardware driver for the Ralink SoC Watchdog Timer.
+config MT7621_WDT
+ tristate "Mediatek SoC watchdog"
+ select WATCHDOG_CORE
+ depends on SOC_MT7620 || SOC_MT7621
+ help
+ Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer.
+
# PARISC Architecture
# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 53d4827ddfe1..f566753256ab 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
+obj-$(CONFIG_ASM9260_WATCHDOG) += asm9260_wdt.o
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o
@@ -53,6 +54,7 @@ obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o
obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
+obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
@@ -69,6 +71,7 @@ obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
+obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -149,6 +152,7 @@ octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o
obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
+obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o
# PARISC Architecture
@@ -187,8 +191,10 @@ obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o
obj-$(CONFIG_DA9063_WATCHDOG) += da9063_wdt.o
obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
+obj-$(CONFIG_TANGOX_WATCHDOG) += tangox_wdt.o
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
+obj-$(CONFIG_ZIIRAVE_WATCHDOG) += ziirave_wdt.o
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c
new file mode 100644
index 000000000000..c9686b2fdafd
--- /dev/null
+++ b/drivers/watchdog/asm9260_wdt.c
@@ -0,0 +1,403 @@
+/*
+ * Watchdog driver for Alphascale ASM9260.
+ *
+ * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/reset.h>
+#include <linux/watchdog.h>
+
+#define CLOCK_FREQ 1000000
+
+/* Watchdog Mode register */
+#define HW_WDMOD 0x00
+/* Wake interrupt. Set by HW, can't be cleared. */
+#define BM_MOD_WDINT BIT(3)
+/* This bit set if timeout reached. Cleared by SW. */
+#define BM_MOD_WDTOF BIT(2)
+/* HW Reset on timeout */
+#define BM_MOD_WDRESET BIT(1)
+/* WD enable */
+#define BM_MOD_WDEN BIT(0)
+
+/*
+ * Watchdog Timer Constant register
+ * Minimal value is 0xff, the meaning of this value
+ * depends on used clock: T = WDCLK * (0xff + 1) * 4
+ */
+#define HW_WDTC 0x04
+#define BM_WDTC_MAX(freq) (0x7fffffff / (freq))
+
+/* Watchdog Feed register */
+#define HW_WDFEED 0x08
+
+/* Watchdog Timer Value register */
+#define HW_WDTV 0x0c
+
+#define ASM9260_WDT_DEFAULT_TIMEOUT 30
+
+enum asm9260_wdt_mode {
+ HW_RESET,
+ SW_RESET,
+ DEBUG,
+};
+
+struct asm9260_wdt_priv {
+ struct device *dev;
+ struct watchdog_device wdd;
+ struct clk *clk;
+ struct clk *clk_ahb;
+ struct reset_control *rst;
+ struct notifier_block restart_handler;
+
+ void __iomem *iobase;
+ int irq;
+ unsigned long wdt_freq;
+ enum asm9260_wdt_mode mode;
+};
+
+static int asm9260_wdt_feed(struct watchdog_device *wdd)
+{
+ struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+ iowrite32(0xaa, priv->iobase + HW_WDFEED);
+ iowrite32(0x55, priv->iobase + HW_WDFEED);
+
+ return 0;
+}
+
+static unsigned int asm9260_wdt_gettimeleft(struct watchdog_device *wdd)
+{
+ struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+ u32 counter;
+
+ counter = ioread32(priv->iobase + HW_WDTV);
+
+ return DIV_ROUND_CLOSEST(counter, priv->wdt_freq);
+}
+
+static int asm9260_wdt_updatetimeout(struct watchdog_device *wdd)
+{
+ struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+ u32 counter;
+
+ counter = wdd->timeout * priv->wdt_freq;
+
+ iowrite32(counter, priv->iobase + HW_WDTC);
+
+ return 0;
+}
+
+static int asm9260_wdt_enable(struct watchdog_device *wdd)
+{
+ struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+ u32 mode = 0;
+
+ if (priv->mode == HW_RESET)
+ mode = BM_MOD_WDRESET;
+
+ iowrite32(BM_MOD_WDEN | mode, priv->iobase + HW_WDMOD);
+
+ asm9260_wdt_updatetimeout(wdd);
+
+ asm9260_wdt_feed(wdd);
+
+ return 0;
+}
+
+static int asm9260_wdt_disable(struct watchdog_device *wdd)
+{
+ struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+ /* The only way to disable WD is to reset it. */
+ reset_control_assert(priv->rst);
+ reset_control_deassert(priv->rst);
+
+ return 0;
+}
+
+static int asm9260_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
+{
+ wdd->timeout = to;
+ asm9260_wdt_updatetimeout(wdd);
+
+ return 0;
+}
+
+static void asm9260_wdt_sys_reset(struct asm9260_wdt_priv *priv)
+{
+ /* init WD if it was not started */
+
+ iowrite32(BM_MOD_WDEN | BM_MOD_WDRESET, priv->iobase + HW_WDMOD);
+
+ iowrite32(0xff, priv->iobase + HW_WDTC);
+ /* first pass correct sequence */
+ asm9260_wdt_feed(&priv->wdd);
+ /*
+ * Then write wrong pattern to the feed to trigger reset
+ * ASAP.
+ */
+ iowrite32(0xff, priv->iobase + HW_WDFEED);
+
+ mdelay(1000);
+}
+
+static irqreturn_t asm9260_wdt_irq(int irq, void *devid)
+{
+ struct asm9260_wdt_priv *priv = devid;
+ u32 stat;
+
+ stat = ioread32(priv->iobase + HW_WDMOD);
+ if (!(stat & BM_MOD_WDINT))
+ return IRQ_NONE;
+
+ if (priv->mode == DEBUG) {
+ dev_info(priv->dev, "Watchdog Timeout. Do nothing.\n");
+ } else {
+ dev_info(priv->dev, "Watchdog Timeout. Doing SW Reset.\n");
+ asm9260_wdt_sys_reset(priv);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int asm9260_restart_handler(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ struct asm9260_wdt_priv *priv =
+ container_of(this, struct asm9260_wdt_priv, restart_handler);
+
+ asm9260_wdt_sys_reset(priv);
+
+ return NOTIFY_DONE;
+}
+
+static const struct watchdog_info asm9260_wdt_ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
+ | WDIOF_MAGICCLOSE,
+ .identity = "Alphascale asm9260 Watchdog",
+};
+
+static struct watchdog_ops asm9260_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = asm9260_wdt_enable,
+ .stop = asm9260_wdt_disable,
+ .get_timeleft = asm9260_wdt_gettimeleft,
+ .ping = asm9260_wdt_feed,
+ .set_timeout = asm9260_wdt_settimeout,
+};
+
+static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
+{
+ int err;
+ unsigned long clk;
+
+ priv->clk = devm_clk_get(priv->dev, "mod");
+ if (IS_ERR(priv->clk)) {
+ dev_err(priv->dev, "Failed to get \"mod\" clk\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ /* configure AHB clock */
+ priv->clk_ahb = devm_clk_get(priv->dev, "ahb");
+ if (IS_ERR(priv->clk_ahb)) {
+ dev_err(priv->dev, "Failed to get \"ahb\" clk\n");
+ return PTR_ERR(priv->clk_ahb);
+ }
+
+ err = clk_prepare_enable(priv->clk_ahb);
+ if (err) {
+ dev_err(priv->dev, "Failed to enable ahb_clk!\n");
+ return err;
+ }
+
+ err = clk_set_rate(priv->clk, CLOCK_FREQ);
+ if (err) {
+ clk_disable_unprepare(priv->clk_ahb);
+ dev_err(priv->dev, "Failed to set rate!\n");
+ return err;
+ }
+
+ err = clk_prepare_enable(priv->clk);
+ if (err) {
+ clk_disable_unprepare(priv->clk_ahb);
+ dev_err(priv->dev, "Failed to enable clk!\n");
+ return err;
+ }
+
+ /* wdt has internal divider */
+ clk = clk_get_rate(priv->clk);
+ if (!clk) {
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_ahb);
+ dev_err(priv->dev, "Failed, clk is 0!\n");
+ return -EINVAL;
+ }
+
+ priv->wdt_freq = clk / 2;
+
+ return 0;
+}
+
+static void asm9260_wdt_get_dt_mode(struct asm9260_wdt_priv *priv)
+{
+ const char *tmp;
+ int ret;
+
+ /* default mode */
+ priv->mode = HW_RESET;
+
+ ret = of_property_read_string(priv->dev->of_node,
+ "alphascale,mode", &tmp);
+ if (ret < 0)
+ return;
+
+ if (!strcmp(tmp, "hw"))
+ priv->mode = HW_RESET;
+ else if (!strcmp(tmp, "sw"))
+ priv->mode = SW_RESET;
+ else if (!strcmp(tmp, "debug"))
+ priv->mode = DEBUG;
+ else
+ dev_warn(priv->dev, "unknown reset-type: %s. Using default \"hw\" mode.",
+ tmp);
+}
+
+static int asm9260_wdt_probe(struct platform_device *pdev)
+{
+ struct asm9260_wdt_priv *priv;
+ struct watchdog_device *wdd;
+ struct resource *res;
+ int ret;
+ const char * const mode_name[] = { "hw", "sw", "debug", };
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct asm9260_wdt_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
+
+ ret = asm9260_wdt_get_dt_clks(priv);
+ if (ret)
+ return ret;
+
+ priv->rst = devm_reset_control_get(&pdev->dev, "wdt_rst");
+ if (IS_ERR(priv->rst))
+ return PTR_ERR(priv->rst);
+
+ wdd = &priv->wdd;
+ wdd->info = &asm9260_wdt_ident;
+ wdd->ops = &asm9260_wdt_ops;
+ wdd->min_timeout = 1;
+ wdd->max_timeout = BM_WDTC_MAX(priv->wdt_freq);
+ wdd->parent = &pdev->dev;
+
+ watchdog_set_drvdata(wdd, priv);
+
+ /*
+ * If 'timeout-sec' unspecified in devicetree, assume a 30 second
+ * default, unless the max timeout is less than 30 seconds, then use
+ * the max instead.
+ */
+ wdd->timeout = ASM9260_WDT_DEFAULT_TIMEOUT;
+ watchdog_init_timeout(wdd, 0, &pdev->dev);
+
+ asm9260_wdt_get_dt_mode(priv);
+
+ if (priv->mode != HW_RESET)
+ priv->irq = platform_get_irq(pdev, 0);
+
+ if (priv->irq > 0) {
+ /*
+ * Not all supported platforms specify an interrupt for the
+ * watchdog, so let's make it optional.
+ */
+ ret = devm_request_irq(&pdev->dev, priv->irq,
+ asm9260_wdt_irq, 0, pdev->name, priv);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "failed to request IRQ\n");
+ }
+
+ ret = watchdog_register_device(wdd);
+ if (ret)
+ goto clk_off;
+
+ platform_set_drvdata(pdev, priv);
+
+ priv->restart_handler.notifier_call = asm9260_restart_handler;
+ priv->restart_handler.priority = 128;
+ ret = register_restart_handler(&priv->restart_handler);
+ if (ret)
+ dev_warn(&pdev->dev, "cannot register restart handler\n");
+
+ dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
+ wdd->timeout, mode_name[priv->mode]);
+ return 0;
+
+clk_off:
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_ahb);
+ return ret;
+}
+
+static void asm9260_wdt_shutdown(struct platform_device *pdev)
+{
+ struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
+
+ asm9260_wdt_disable(&priv->wdd);
+}
+
+static int asm9260_wdt_remove(struct platform_device *pdev)
+{
+ struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
+
+ asm9260_wdt_disable(&priv->wdd);
+
+ unregister_restart_handler(&priv->restart_handler);
+
+ watchdog_unregister_device(&priv->wdd);
+
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_ahb);
+
+ return 0;
+}
+
+static const struct of_device_id asm9260_wdt_of_match[] = {
+ { .compatible = "alphascale,asm9260-wdt"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, asm9260_wdt_of_match);
+
+static struct platform_driver asm9260_wdt_driver = {
+ .driver = {
+ .name = "asm9260-wdt",
+ .owner = THIS_MODULE,
+ .of_match_table = asm9260_wdt_of_match,
+ },
+ .probe = asm9260_wdt_probe,
+ .remove = asm9260_wdt_remove,
+ .shutdown = asm9260_wdt_shutdown,
+};
+module_platform_driver(asm9260_wdt_driver);
+
+MODULE_DESCRIPTION("asm9260 WatchDog Timer Driver");
+MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/atlas7_wdt.c b/drivers/watchdog/atlas7_wdt.c
new file mode 100644
index 000000000000..df6d9242a319
--- /dev/null
+++ b/drivers/watchdog/atlas7_wdt.c
@@ -0,0 +1,242 @@
+/*
+ * Watchdog driver for CSR Atlas7
+ *
+ * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#define ATLAS7_TIMER_WDT_INDEX 5
+#define ATLAS7_WDT_DEFAULT_TIMEOUT 20
+
+#define ATLAS7_WDT_CNT_CTRL (0 + 4 * ATLAS7_TIMER_WDT_INDEX)
+#define ATLAS7_WDT_CNT_MATCH (0x18 + 4 * ATLAS7_TIMER_WDT_INDEX)
+#define ATLAS7_WDT_CNT (0x48 + 4 * ATLAS7_TIMER_WDT_INDEX)
+#define ATLAS7_WDT_CNT_EN (BIT(0) | BIT(1))
+#define ATLAS7_WDT_EN 0x64
+
+static unsigned int timeout = ATLAS7_WDT_DEFAULT_TIMEOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(timeout, uint, 0);
+module_param(nowayout, bool, 0);
+
+MODULE_PARM_DESC(timeout, "Default watchdog timeout (in seconds)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct atlas7_wdog {
+ struct device *dev;
+ void __iomem *base;
+ unsigned long tick_rate;
+ struct clk *clk;
+};
+
+static unsigned int atlas7_wdt_gettimeleft(struct watchdog_device *wdd)
+{
+ struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+ u32 counter, match, delta;
+
+ counter = readl(wdt->base + ATLAS7_WDT_CNT);
+ match = readl(wdt->base + ATLAS7_WDT_CNT_MATCH);
+ delta = match - counter;
+
+ return delta / wdt->tick_rate;
+}
+
+static int atlas7_wdt_ping(struct watchdog_device *wdd)
+{
+ struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+ u32 counter, match, delta;
+
+ counter = readl(wdt->base + ATLAS7_WDT_CNT);
+ delta = wdd->timeout * wdt->tick_rate;
+ match = counter + delta;
+
+ writel(match, wdt->base + ATLAS7_WDT_CNT_MATCH);
+
+ return 0;
+}
+
+static int atlas7_wdt_enable(struct watchdog_device *wdd)
+{
+ struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+ atlas7_wdt_ping(wdd);
+
+ writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) | ATLAS7_WDT_CNT_EN,
+ wdt->base + ATLAS7_WDT_CNT_CTRL);
+ writel(1, wdt->base + ATLAS7_WDT_EN);
+
+ return 0;
+}
+
+static int atlas7_wdt_disable(struct watchdog_device *wdd)
+{
+ struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+ writel(0, wdt->base + ATLAS7_WDT_EN);
+ writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) & ~ATLAS7_WDT_CNT_EN,
+ wdt->base + ATLAS7_WDT_CNT_CTRL);
+
+ return 0;
+}
+
+static int atlas7_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
+{
+ wdd->timeout = to;
+
+ return 0;
+}
+
+#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
+
+static const struct watchdog_info atlas7_wdt_ident = {
+ .options = OPTIONS,
+ .firmware_version = 0,
+ .identity = "atlas7 Watchdog",
+};
+
+static struct watchdog_ops atlas7_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = atlas7_wdt_enable,
+ .stop = atlas7_wdt_disable,
+ .get_timeleft = atlas7_wdt_gettimeleft,
+ .ping = atlas7_wdt_ping,
+ .set_timeout = atlas7_wdt_settimeout,
+};
+
+static struct watchdog_device atlas7_wdd = {
+ .info = &atlas7_wdt_ident,
+ .ops = &atlas7_wdt_ops,
+ .timeout = ATLAS7_WDT_DEFAULT_TIMEOUT,
+};
+
+static const struct of_device_id atlas7_wdt_ids[] = {
+ { .compatible = "sirf,atlas7-tick"},
+ {}
+};
+
+static int atlas7_wdt_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct atlas7_wdog *wdt;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ wdt->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wdt->base))
+ return PTR_ERR(wdt->base);
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk enable failed\n");
+ goto err;
+ }
+
+ /* disable watchdog hardware */
+ writel(0, wdt->base + ATLAS7_WDT_CNT_CTRL);
+
+ wdt->tick_rate = clk_get_rate(clk);
+ wdt->clk = clk;
+ atlas7_wdd.min_timeout = 1;
+ atlas7_wdd.max_timeout = UINT_MAX / wdt->tick_rate;
+
+ watchdog_init_timeout(&atlas7_wdd, 0, &pdev->dev);
+ watchdog_set_nowayout(&atlas7_wdd, nowayout);
+
+ watchdog_set_drvdata(&atlas7_wdd, wdt);
+ platform_set_drvdata(pdev, &atlas7_wdd);
+
+ ret = watchdog_register_device(&atlas7_wdd);
+ if (ret)
+ goto err1;
+
+ return 0;
+
+err1:
+ clk_disable_unprepare(clk);
+err:
+ clk_put(clk);
+ return ret;
+}
+
+static void atlas7_wdt_shutdown(struct platform_device *pdev)
+{
+ struct watchdog_device *wdd = platform_get_drvdata(pdev);
+ struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+ atlas7_wdt_disable(wdd);
+ clk_disable_unprepare(wdt->clk);
+}
+
+static int atlas7_wdt_remove(struct platform_device *pdev)
+{
+ struct watchdog_device *wdd = platform_get_drvdata(pdev);
+ struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+ atlas7_wdt_shutdown(pdev);
+ clk_put(wdt->clk);
+ return 0;
+}
+
+static int __maybe_unused atlas7_wdt_suspend(struct device *dev)
+{
+ /*
+ * NOTE:timer controller registers settings are saved
+ * and restored back by the timer-atlas7.c
+ */
+ return 0;
+}
+
+static int __maybe_unused atlas7_wdt_resume(struct device *dev)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ /*
+ * NOTE: Since timer controller registers settings are saved
+ * and restored back by the timer-atlas7.c, so we need not
+ * update WD settings except refreshing timeout.
+ */
+ atlas7_wdt_ping(wdd);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(atlas7_wdt_pm_ops,
+ atlas7_wdt_suspend, atlas7_wdt_resume);
+
+MODULE_DEVICE_TABLE(of, atlas7_wdt_ids);
+
+static struct platform_driver atlas7_wdt_driver = {
+ .driver = {
+ .name = "atlas7-wdt",
+ .pm = &atlas7_wdt_pm_ops,
+ .of_match_table = atlas7_wdt_ids,
+ },
+ .probe = atlas7_wdt_probe,
+ .remove = atlas7_wdt_remove,
+ .shutdown = atlas7_wdt_shutdown,
+};
+module_platform_driver(atlas7_wdt_driver);
+
+MODULE_DESCRIPTION("CSRatlas7 watchdog driver");
+MODULE_AUTHOR("Guo Zeng <Guo.Zeng@csr.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:atlas7-wdt");
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
index 8a5ce5b5a0b6..2e6164c4abc0 100644
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -79,7 +79,6 @@ static int bcm2835_wdt_stop(struct watchdog_device *wdog)
struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
writel_relaxed(PM_PASSWORD | PM_RSTC_RESET, wdt->base + PM_RSTC);
- dev_info(wdog->dev, "Watchdog timer stopped");
return 0;
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 4064a43f1360..df1c2a4b0165 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/timer.h>
@@ -88,12 +87,22 @@ static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
return 0;
}
+static int bcm47xx_wdt_restart(struct watchdog_device *wdd)
+{
+ struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
+
+ wdt->timer_set(wdt, 1);
+
+ return 0;
+}
+
static struct watchdog_ops bcm47xx_wdt_hard_ops = {
.owner = THIS_MODULE,
.start = bcm47xx_wdt_hard_start,
.stop = bcm47xx_wdt_hard_stop,
.ping = bcm47xx_wdt_hard_keepalive,
.set_timeout = bcm47xx_wdt_hard_set_timeout,
+ .restart = bcm47xx_wdt_restart,
};
static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
@@ -158,34 +167,13 @@ static const struct watchdog_info bcm47xx_wdt_info = {
WDIOF_MAGICCLOSE,
};
-static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- struct bcm47xx_wdt *wdt;
-
- wdt = container_of(this, struct bcm47xx_wdt, notifier);
- if (code == SYS_DOWN || code == SYS_HALT)
- wdt->wdd.ops->stop(&wdt->wdd);
- return NOTIFY_DONE;
-}
-
-static int bcm47xx_wdt_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
-{
- struct bcm47xx_wdt *wdt;
-
- wdt = container_of(this, struct bcm47xx_wdt, restart_handler);
- wdt->timer_set(wdt, 1);
-
- return NOTIFY_DONE;
-}
-
static struct watchdog_ops bcm47xx_wdt_soft_ops = {
.owner = THIS_MODULE,
.start = bcm47xx_wdt_soft_start,
.stop = bcm47xx_wdt_soft_stop,
.ping = bcm47xx_wdt_soft_keepalive,
.set_timeout = bcm47xx_wdt_soft_set_timeout,
+ .restart = bcm47xx_wdt_restart,
};
static int bcm47xx_wdt_probe(struct platform_device *pdev)
@@ -214,32 +202,18 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
if (ret)
goto err_timer;
watchdog_set_nowayout(&wdt->wdd, nowayout);
-
- wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys;
-
- ret = register_reboot_notifier(&wdt->notifier);
- if (ret)
- goto err_timer;
-
- wdt->restart_handler.notifier_call = &bcm47xx_wdt_restart;
- wdt->restart_handler.priority = 64;
- ret = register_restart_handler(&wdt->restart_handler);
- if (ret)
- goto err_notifier;
+ watchdog_set_restart_priority(&wdt->wdd, 64);
+ watchdog_stop_on_reboot(&wdt->wdd);
ret = watchdog_register_device(&wdt->wdd);
if (ret)
- goto err_handler;
+ goto err_timer;
dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
timeout, nowayout ? ", nowayout" : "",
soft ? ", Software Timer" : "");
return 0;
-err_handler:
- unregister_restart_handler(&wdt->restart_handler);
-err_notifier:
- unregister_reboot_notifier(&wdt->notifier);
err_timer:
if (soft)
del_timer_sync(&wdt->soft_timer);
@@ -255,7 +229,6 @@ static int bcm47xx_wdt_remove(struct platform_device *pdev)
return -ENXIO;
watchdog_unregister_device(&wdt->wdd);
- unregister_reboot_notifier(&wdt->notifier);
return 0;
}
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c
index bcfd2a22208f..4dda9024e229 100644
--- a/drivers/watchdog/cadence_wdt.c
+++ b/drivers/watchdog/cadence_wdt.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/watchdog.h>
#define CDNS_WDT_DEFAULT_TIMEOUT 10
@@ -72,7 +71,6 @@ MODULE_PARM_DESC(nowayout,
* @ctrl_clksel: counter clock prescaler selection
* @io_lock: spinlock for IO register access
* @cdns_wdt_device: watchdog device structure
- * @cdns_wdt_notifier: notifier structure
*
* Structure containing parameters specific to cadence watchdog.
*/
@@ -84,7 +82,6 @@ struct cdns_wdt {
u32 ctrl_clksel;
spinlock_t io_lock;
struct watchdog_device cdns_wdt_device;
- struct notifier_block cdns_wdt_notifier;
};
/* Write access to Registers */
@@ -280,29 +277,6 @@ static struct watchdog_ops cdns_wdt_ops = {
.set_timeout = cdns_wdt_settimeout,
};
-/**
- * cdns_wdt_notify_sys - Notifier for reboot or shutdown.
- *
- * @this: handle to notifier block
- * @code: turn off indicator
- * @unused: unused
- * Return: NOTIFY_DONE
- *
- * This notifier is invoked whenever the system reboot or shutdown occur
- * because we need to disable the WDT before system goes down as WDT might
- * reset on the next boot.
- */
-static int cdns_wdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- struct cdns_wdt *wdt = container_of(this, struct cdns_wdt,
- cdns_wdt_notifier);
- if (code == SYS_DOWN || code == SYS_HALT)
- cdns_wdt_stop(&wdt->cdns_wdt_device);
-
- return NOTIFY_DONE;
-}
-
/************************Platform Operations*****************************/
/**
* cdns_wdt_probe - Probe call for the device.
@@ -360,6 +334,7 @@ static int cdns_wdt_probe(struct platform_device *pdev)
}
watchdog_set_nowayout(cdns_wdt_device, nowayout);
+ watchdog_stop_on_reboot(cdns_wdt_device);
watchdog_set_drvdata(cdns_wdt_device, wdt);
wdt->clk = devm_clk_get(&pdev->dev, NULL);
@@ -386,14 +361,6 @@ static int cdns_wdt_probe(struct platform_device *pdev)
spin_lock_init(&wdt->io_lock);
- wdt->cdns_wdt_notifier.notifier_call = &cdns_wdt_notify_sys;
- ret = register_reboot_notifier(&wdt->cdns_wdt_notifier);
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot register reboot notifier err=%d)\n",
- ret);
- goto err_clk_disable;
- }
-
ret = watchdog_register_device(cdns_wdt_device);
if (ret) {
dev_err(&pdev->dev, "Failed to register wdt device\n");
@@ -427,7 +394,6 @@ static int cdns_wdt_remove(struct platform_device *pdev)
cdns_wdt_stop(&wdt->cdns_wdt_device);
watchdog_unregister_device(&wdt->cdns_wdt_device);
- unregister_reboot_notifier(&wdt->cdns_wdt_notifier);
clk_disable_unprepare(wdt->clk);
return 0;
@@ -455,8 +421,7 @@ static void cdns_wdt_shutdown(struct platform_device *pdev)
*/
static int __maybe_unused cdns_wdt_suspend(struct device *dev)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct cdns_wdt *wdt = platform_get_drvdata(pdev);
cdns_wdt_stop(&wdt->cdns_wdt_device);
@@ -474,8 +439,7 @@ static int __maybe_unused cdns_wdt_suspend(struct device *dev)
static int __maybe_unused cdns_wdt_resume(struct device *dev)
{
int ret;
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct cdns_wdt *wdt = platform_get_drvdata(pdev);
ret = clk_prepare_enable(wdt->clk);
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index 67e67977bd29..2fc19a32a320 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -31,7 +31,6 @@
struct da9052_wdt_data {
struct watchdog_device wdt;
struct da9052 *da9052;
- struct kref kref;
unsigned long jpast;
};
@@ -51,10 +50,6 @@ static const struct {
};
-static void da9052_wdt_release_resources(struct kref *r)
-{
-}
-
static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
unsigned int timeout)
{
@@ -104,20 +99,6 @@ static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
return 0;
}
-static void da9052_wdt_ref(struct watchdog_device *wdt_dev)
-{
- struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
- kref_get(&driver_data->kref);
-}
-
-static void da9052_wdt_unref(struct watchdog_device *wdt_dev)
-{
- struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
- kref_put(&driver_data->kref, da9052_wdt_release_resources);
-}
-
static int da9052_wdt_start(struct watchdog_device *wdt_dev)
{
return da9052_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
@@ -170,8 +151,6 @@ static const struct watchdog_ops da9052_wdt_ops = {
.stop = da9052_wdt_stop,
.ping = da9052_wdt_ping,
.set_timeout = da9052_wdt_set_timeout,
- .ref = da9052_wdt_ref,
- .unref = da9052_wdt_unref,
};
@@ -198,8 +177,6 @@ static int da9052_wdt_probe(struct platform_device *pdev)
da9052_wdt->parent = &pdev->dev;
watchdog_set_drvdata(da9052_wdt, driver_data);
- kref_init(&driver_data->kref);
-
ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
DA9052_CONTROLD_TWDSCALE, 0);
if (ret < 0) {
@@ -225,7 +202,6 @@ static int da9052_wdt_remove(struct platform_device *pdev)
struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev);
watchdog_unregister_device(&driver_data->wdt);
- kref_put(&driver_data->kref, da9052_wdt_release_resources);
return 0;
}
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
index 04d1430d93d2..8377c43f3f20 100644
--- a/drivers/watchdog/da9055_wdt.c
+++ b/drivers/watchdog/da9055_wdt.c
@@ -35,7 +35,6 @@ MODULE_PARM_DESC(nowayout,
struct da9055_wdt_data {
struct watchdog_device wdt;
struct da9055 *da9055;
- struct kref kref;
};
static const struct {
@@ -99,24 +98,6 @@ static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
DA9055_WATCHDOG_MASK, 1);
}
-static void da9055_wdt_release_resources(struct kref *r)
-{
-}
-
-static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
-{
- struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
- kref_get(&driver_data->kref);
-}
-
-static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
-{
- struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
- kref_put(&driver_data->kref, da9055_wdt_release_resources);
-}
-
static int da9055_wdt_start(struct watchdog_device *wdt_dev)
{
return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
@@ -138,8 +119,6 @@ static const struct watchdog_ops da9055_wdt_ops = {
.stop = da9055_wdt_stop,
.ping = da9055_wdt_ping,
.set_timeout = da9055_wdt_set_timeout,
- .ref = da9055_wdt_ref,
- .unref = da9055_wdt_unref,
};
static int da9055_wdt_probe(struct platform_device *pdev)
@@ -165,8 +144,6 @@ static int da9055_wdt_probe(struct platform_device *pdev)
watchdog_set_nowayout(da9055_wdt, nowayout);
watchdog_set_drvdata(da9055_wdt, driver_data);
- kref_init(&driver_data->kref);
-
ret = da9055_wdt_stop(da9055_wdt);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
@@ -189,7 +166,6 @@ static int da9055_wdt_remove(struct platform_device *pdev)
struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev);
watchdog_unregister_device(&driver_data->wdt);
- kref_put(&driver_data->kref, da9055_wdt_release_resources);
return 0;
}
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c
index 6bf130bd863d..11e887572649 100644
--- a/drivers/watchdog/da9063_wdt.c
+++ b/drivers/watchdog/da9063_wdt.c
@@ -20,7 +20,6 @@
#include <linux/delay.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9063/core.h>
-#include <linux/reboot.h>
#include <linux/regmap.h>
/*
@@ -39,7 +38,6 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };
struct da9063_watchdog {
struct da9063 *da9063;
struct watchdog_device wdtdev;
- struct notifier_block restart_handler;
};
static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)
@@ -121,12 +119,9 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd,
return ret;
}
-static int da9063_wdt_restart_handler(struct notifier_block *this,
- unsigned long mode, void *cmd)
+static int da9063_wdt_restart(struct watchdog_device *wdd)
{
- struct da9063_watchdog *wdt = container_of(this,
- struct da9063_watchdog,
- restart_handler);
+ struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);
int ret;
ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,
@@ -135,7 +130,7 @@ static int da9063_wdt_restart_handler(struct notifier_block *this,
dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n",
ret);
- return NOTIFY_DONE;
+ return ret;
}
static const struct watchdog_info da9063_watchdog_info = {
@@ -149,6 +144,7 @@ static const struct watchdog_ops da9063_watchdog_ops = {
.stop = da9063_wdt_stop,
.ping = da9063_wdt_ping,
.set_timeout = da9063_wdt_set_timeout,
+ .restart = da9063_wdt_restart,
};
static int da9063_wdt_probe(struct platform_device *pdev)
@@ -179,6 +175,8 @@ static int da9063_wdt_probe(struct platform_device *pdev)
wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
+ watchdog_set_restart_priority(&wdt->wdtdev, 128);
+
watchdog_set_drvdata(&wdt->wdtdev, wdt);
dev_set_drvdata(&pdev->dev, wdt);
@@ -186,13 +184,6 @@ static int da9063_wdt_probe(struct platform_device *pdev)
if (ret)
return ret;
- wdt->restart_handler.notifier_call = da9063_wdt_restart_handler;
- wdt->restart_handler.priority = 128;
- ret = register_restart_handler(&wdt->restart_handler);
- if (ret)
- dev_err(wdt->da9063->dev,
- "Failed to register restart handler (err = %d)\n", ret);
-
return 0;
}
@@ -200,8 +191,6 @@ static int da9063_wdt_remove(struct platform_device *pdev)
{
struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev);
- unregister_restart_handler(&wdt->restart_handler);
-
watchdog_unregister_device(&wdt->wdtdev);
return 0;
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c
index 3db9d0e0673d..861d3d3133f8 100644
--- a/drivers/watchdog/diag288_wdt.c
+++ b/drivers/watchdog/diag288_wdt.c
@@ -106,6 +106,10 @@ static int __diag288_lpar(unsigned int func, unsigned int timeout,
return __diag288(func, timeout, action, 0);
}
+static unsigned long wdt_status;
+
+#define DIAG_WDOG_BUSY 0
+
static int wdt_start(struct watchdog_device *dev)
{
char *ebc_cmd;
@@ -113,12 +117,17 @@ static int wdt_start(struct watchdog_device *dev)
int ret;
unsigned int func;
+ if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status))
+ return -EBUSY;
+
ret = -ENODEV;
if (MACHINE_IS_VM) {
ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
- if (!ebc_cmd)
+ if (!ebc_cmd) {
+ clear_bit(DIAG_WDOG_BUSY, &wdt_status);
return -ENOMEM;
+ }
len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN);
ASCEBC(ebc_cmd, MAX_CMDLEN);
EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
@@ -135,6 +144,7 @@ static int wdt_start(struct watchdog_device *dev)
if (ret) {
pr_err("The watchdog cannot be activated\n");
+ clear_bit(DIAG_WDOG_BUSY, &wdt_status);
return ret;
}
return 0;
@@ -146,6 +156,9 @@ static int wdt_stop(struct watchdog_device *dev)
diag_stat_inc(DIAG_STAT_X288);
ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0);
+
+ clear_bit(DIAG_WDOG_BUSY, &wdt_status);
+
return ret;
}
@@ -220,17 +233,10 @@ static struct watchdog_device wdt_dev = {
* It makes no sense to go into suspend while the watchdog is running.
* Depending on the memory size, the watchdog might trigger, while we
* are still saving the memory.
- * We reuse the open flag to ensure that suspend and watchdog open are
- * exclusive operations
*/
static int wdt_suspend(void)
{
- if (test_and_set_bit(WDOG_DEV_OPEN, &wdt_dev.status)) {
- pr_err("Linux cannot be suspended while the watchdog is in use\n");
- return notifier_from_errno(-EBUSY);
- }
- if (test_bit(WDOG_ACTIVE, &wdt_dev.status)) {
- clear_bit(WDOG_DEV_OPEN, &wdt_dev.status);
+ if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status)) {
pr_err("Linux cannot be suspended while the watchdog is in use\n");
return notifier_from_errno(-EBUSY);
}
@@ -239,7 +245,7 @@ static int wdt_suspend(void)
static int wdt_resume(void)
{
- clear_bit(WDOG_DEV_OPEN, &wdt_dev.status);
+ clear_bit(DIAG_WDOG_BUSY, &wdt_status);
return NOTIFY_DONE;
}
diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c
index 50abe1bf62a5..1ccb0b239348 100644
--- a/drivers/watchdog/digicolor_wdt.c
+++ b/drivers/watchdog/digicolor_wdt.c
@@ -15,7 +15,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/watchdog.h>
-#include <linux/reboot.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
@@ -28,7 +27,6 @@
struct dc_wdt {
void __iomem *base;
struct clk *clk;
- struct notifier_block restart_handler;
spinlock_t lock;
};
@@ -50,16 +48,15 @@ static void dc_wdt_set(struct dc_wdt *wdt, u32 ticks)
spin_unlock_irqrestore(&wdt->lock, flags);
}
-static int dc_restart_handler(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int dc_wdt_restart(struct watchdog_device *wdog)
{
- struct dc_wdt *wdt = container_of(this, struct dc_wdt, restart_handler);
+ struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
dc_wdt_set(wdt, 1);
/* wait for reset to assert... */
mdelay(500);
- return NOTIFY_DONE;
+ return 0;
}
static int dc_wdt_start(struct watchdog_device *wdog)
@@ -104,6 +101,7 @@ static struct watchdog_ops dc_wdt_ops = {
.stop = dc_wdt_stop,
.set_timeout = dc_wdt_set_timeout,
.get_timeleft = dc_wdt_get_timeleft,
+ .restart = dc_wdt_restart,
};
static struct watchdog_info dc_wdt_info = {
@@ -148,6 +146,7 @@ static int dc_wdt_probe(struct platform_device *pdev)
spin_lock_init(&wdt->lock);
watchdog_set_drvdata(&dc_wdt_wdd, wdt);
+ watchdog_set_restart_priority(&dc_wdt_wdd, 128);
watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
ret = watchdog_register_device(&dc_wdt_wdd);
if (ret) {
@@ -155,12 +154,6 @@ static int dc_wdt_probe(struct platform_device *pdev)
goto err_iounmap;
}
- wdt->restart_handler.notifier_call = dc_restart_handler;
- wdt->restart_handler.priority = 128;
- ret = register_restart_handler(&wdt->restart_handler);
- if (ret)
- dev_warn(&pdev->dev, "cannot register restart handler\n");
-
return 0;
err_iounmap:
@@ -172,7 +165,6 @@ static int dc_wdt_remove(struct platform_device *pdev)
{
struct dc_wdt *wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&wdt->restart_handler);
watchdog_unregister_device(&dc_wdt_wdd);
iounmap(wdt->base);
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 6ea0634345e9..8fefa4ad46d4 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -81,7 +81,7 @@ static inline int dw_wdt_top_in_seconds(unsigned top)
* There are 16 possible timeout values in 0..15 where the number of
* cycles is 2 ^ (16 + i) and the watchdog counts down.
*/
- return (1 << (16 + top)) / clk_get_rate(dw_wdt.clk);
+ return (1U << (16 + top)) / clk_get_rate(dw_wdt.clk);
}
static int dw_wdt_get_top(void)
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 90d59d3f38a3..ba066e4a707b 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -12,10 +12,8 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/notifier.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/watchdog.h>
#define SOFT_TIMEOUT_MIN 1
@@ -36,7 +34,6 @@ struct gpio_wdt_priv {
unsigned int hw_algo;
unsigned int hw_margin;
unsigned long last_jiffies;
- struct notifier_block notifier;
struct timer_list timer;
struct watchdog_device wdd;
};
@@ -57,7 +54,8 @@ static void gpio_wdt_hwping(unsigned long data)
if (priv->armed && time_after(jiffies, priv->last_jiffies +
msecs_to_jiffies(wdd->timeout * 1000))) {
- dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
+ dev_crit(wdd->parent,
+ "Timer expired. System will reboot soon!\n");
return;
}
@@ -126,26 +124,6 @@ static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
return gpio_wdt_ping(wdd);
}
-static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code,
- void *unused)
-{
- struct gpio_wdt_priv *priv = container_of(nb, struct gpio_wdt_priv,
- notifier);
-
- mod_timer(&priv->timer, 0);
-
- switch (code) {
- case SYS_HALT:
- case SYS_POWER_OFF:
- gpio_wdt_disable(priv);
- break;
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
static const struct watchdog_info gpio_wdt_ident = {
.options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT,
@@ -224,23 +202,16 @@ static int gpio_wdt_probe(struct platform_device *pdev)
setup_timer(&priv->timer, gpio_wdt_hwping, (unsigned long)&priv->wdd);
+ watchdog_stop_on_reboot(&priv->wdd);
+
ret = watchdog_register_device(&priv->wdd);
if (ret)
return ret;
- priv->notifier.notifier_call = gpio_wdt_notify_sys;
- ret = register_reboot_notifier(&priv->notifier);
- if (ret)
- goto error_unregister;
-
if (priv->always_running)
gpio_wdt_start_impl(priv);
return 0;
-
-error_unregister:
- watchdog_unregister_device(&priv->wdd);
- return ret;
}
static int gpio_wdt_remove(struct platform_device *pdev)
@@ -248,7 +219,6 @@ static int gpio_wdt_remove(struct platform_device *pdev)
struct gpio_wdt_priv *priv = platform_get_drvdata(pdev);
del_timer_sync(&priv->timer);
- unregister_reboot_notifier(&priv->notifier);
watchdog_unregister_device(&priv->wdd);
return 0;
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 286369d4f0f5..92443c319e59 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -1,11 +1,11 @@
/*
- * HP WatchDog Driver
+ * HPE WatchDog Driver
* based on
*
* SoftDog 0.05: A Software Watchdog Device
*
- * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
- * Thomas Mingarelli <thomas.mingarelli@hp.com>
+ * (c) Copyright 2015 Hewlett Packard Enterprise Development LP
+ * Thomas Mingarelli <thomas.mingarelli@hpe.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -580,7 +580,7 @@ static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
- .identity = "HP iLO2+ HW Watchdog Timer",
+ .identity = "HPE iLO2+ HW Watchdog Timer",
};
static long hpwdt_ioctl(struct file *file, unsigned int cmd,
@@ -758,7 +758,7 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
goto error2;
dev_info(&dev->dev,
- "HP Watchdog Timer Driver: NMI decoding initialized"
+ "HPE Watchdog Timer Driver: NMI decoding initialized"
", allow kernel dump: %s (default = 1/ON)\n",
(allow_kdump == 0) ? "OFF" : "ON");
return 0;
@@ -863,7 +863,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
goto error_misc_register;
}
- dev_info(&dev->dev, "HP Watchdog Timer Driver: %s"
+ dev_info(&dev->dev, "HPE Watchdog Timer Driver: %s"
", timer margin: %d seconds (nowayout=%d).\n",
HPWDT_VERSION, soft_margin, nowayout);
return 0;
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
index 15ab07230960..3679f2e1922f 100644
--- a/drivers/watchdog/imgpdc_wdt.c
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -45,7 +45,6 @@
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/watchdog.h>
@@ -87,7 +86,6 @@ struct pdc_wdt_dev {
struct clk *wdt_clk;
struct clk *sys_clk;
void __iomem *base;
- struct notifier_block restart_handler;
};
static int pdc_wdt_keepalive(struct watchdog_device *wdt_dev)
@@ -152,6 +150,16 @@ static int pdc_wdt_start(struct watchdog_device *wdt_dev)
return 0;
}
+static int pdc_wdt_restart(struct watchdog_device *wdt_dev)
+{
+ struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+
+ /* Assert SOFT_RESET */
+ writel(0x1, wdt->base + PDC_WDT_SOFT_RESET);
+
+ return 0;
+}
+
static struct watchdog_info pdc_wdt_info = {
.identity = "IMG PDC Watchdog",
.options = WDIOF_SETTIMEOUT |
@@ -165,20 +173,9 @@ static const struct watchdog_ops pdc_wdt_ops = {
.stop = pdc_wdt_stop,
.ping = pdc_wdt_keepalive,
.set_timeout = pdc_wdt_set_timeout,
+ .restart = pdc_wdt_restart,
};
-static int pdc_wdt_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
-{
- struct pdc_wdt_dev *wdt = container_of(this, struct pdc_wdt_dev,
- restart_handler);
-
- /* Assert SOFT_RESET */
- writel(0x1, wdt->base + PDC_WDT_SOFT_RESET);
-
- return NOTIFY_OK;
-}
-
static int pdc_wdt_probe(struct platform_device *pdev)
{
u64 div;
@@ -282,6 +279,7 @@ static int pdc_wdt_probe(struct platform_device *pdev)
}
watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
+ watchdog_set_restart_priority(&pdc_wdt->wdt_dev, 128);
platform_set_drvdata(pdev, pdc_wdt);
@@ -289,13 +287,6 @@ static int pdc_wdt_probe(struct platform_device *pdev)
if (ret)
goto disable_wdt_clk;
- pdc_wdt->restart_handler.notifier_call = pdc_wdt_restart;
- pdc_wdt->restart_handler.priority = 128;
- ret = register_restart_handler(&pdc_wdt->restart_handler);
- if (ret)
- dev_warn(&pdev->dev, "failed to register restart handler: %d\n",
- ret);
-
return 0;
disable_wdt_clk:
@@ -316,7 +307,6 @@ static int pdc_wdt_remove(struct platform_device *pdev)
{
struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&pdc_wdt->restart_handler);
pdc_wdt_stop(&pdc_wdt->wdt_dev);
watchdog_unregister_device(&pdc_wdt->wdt_dev);
clk_disable_unprepare(pdc_wdt->wdt_clk);
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 29ef719a6a3c..e47966aa2db0 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -29,10 +29,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/notifier.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/timer.h>
#include <linux/watchdog.h>
@@ -64,7 +62,6 @@ struct imx2_wdt_device {
struct regmap *regmap;
struct timer_list timer; /* Pings the watchdog when closed */
struct watchdog_device wdog;
- struct notifier_block restart_handler;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -83,13 +80,11 @@ static const struct watchdog_info imx2_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
};
-static int imx2_restart_handler(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int imx2_wdt_restart(struct watchdog_device *wdog)
{
+ struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
unsigned int wcr_enable = IMX2_WDT_WCR_WDE;
- struct imx2_wdt_device *wdev = container_of(this,
- struct imx2_wdt_device,
- restart_handler);
+
/* Assert SRS signal */
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
/*
@@ -105,7 +100,7 @@ static int imx2_restart_handler(struct notifier_block *this, unsigned long mode,
/* wait for reset to assert... */
mdelay(500);
- return NOTIFY_DONE;
+ return 0;
}
static inline void imx2_wdt_setup(struct watchdog_device *wdog)
@@ -213,6 +208,7 @@ static const struct watchdog_ops imx2_wdt_ops = {
.stop = imx2_wdt_stop,
.ping = imx2_wdt_ping,
.set_timeout = imx2_wdt_set_timeout,
+ .restart = imx2_wdt_restart,
};
static const struct regmap_config imx2_wdt_regmap_config = {
@@ -275,6 +271,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdog);
watchdog_set_drvdata(wdog, wdev);
watchdog_set_nowayout(wdog, nowayout);
+ watchdog_set_restart_priority(wdog, 128);
watchdog_init_timeout(wdog, timeout, &pdev->dev);
setup_timer(&wdev->timer, imx2_wdt_timer_ping, (unsigned long)wdog);
@@ -294,12 +291,6 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
goto disable_clk;
}
- wdev->restart_handler.notifier_call = imx2_restart_handler;
- wdev->restart_handler.priority = 128;
- ret = register_restart_handler(&wdev->restart_handler);
- if (ret)
- dev_err(&pdev->dev, "cannot register restart handler\n");
-
dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n",
wdog->timeout, nowayout);
@@ -315,8 +306,6 @@ static int __exit imx2_wdt_remove(struct platform_device *pdev)
struct watchdog_device *wdog = platform_get_drvdata(pdev);
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
- unregister_restart_handler(&wdev->restart_handler);
-
watchdog_unregister_device(wdog);
if (imx2_wdt_is_running(wdev)) {
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c
index ab7b8b185d99..6914c83aa6d9 100644
--- a/drivers/watchdog/lpc18xx_wdt.c
+++ b/drivers/watchdog/lpc18xx_wdt.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/watchdog.h>
/* Registers */
@@ -59,7 +58,6 @@ struct lpc18xx_wdt_dev {
unsigned long clk_rate;
void __iomem *base;
struct timer_list timer;
- struct notifier_block restart_handler;
spinlock_t lock;
};
@@ -155,27 +153,9 @@ static int lpc18xx_wdt_start(struct watchdog_device *wdt_dev)
return 0;
}
-static struct watchdog_info lpc18xx_wdt_info = {
- .identity = "NXP LPC18xx Watchdog",
- .options = WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
-};
-
-static const struct watchdog_ops lpc18xx_wdt_ops = {
- .owner = THIS_MODULE,
- .start = lpc18xx_wdt_start,
- .stop = lpc18xx_wdt_stop,
- .ping = lpc18xx_wdt_feed,
- .set_timeout = lpc18xx_wdt_set_timeout,
- .get_timeleft = lpc18xx_wdt_get_timeleft,
-};
-
-static int lpc18xx_wdt_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int lpc18xx_wdt_restart(struct watchdog_device *wdt_dev)
{
- struct lpc18xx_wdt_dev *lpc18xx_wdt = container_of(this,
- struct lpc18xx_wdt_dev, restart_handler);
+ struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
int val;
@@ -197,9 +177,26 @@ static int lpc18xx_wdt_restart(struct notifier_block *this, unsigned long mode,
spin_unlock_irqrestore(&lpc18xx_wdt->lock, flags);
- return NOTIFY_OK;
+ return 0;
}
+static struct watchdog_info lpc18xx_wdt_info = {
+ .identity = "NXP LPC18xx Watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops lpc18xx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = lpc18xx_wdt_start,
+ .stop = lpc18xx_wdt_stop,
+ .ping = lpc18xx_wdt_feed,
+ .set_timeout = lpc18xx_wdt_set_timeout,
+ .get_timeleft = lpc18xx_wdt_get_timeleft,
+ .restart = lpc18xx_wdt_restart,
+};
+
static int lpc18xx_wdt_probe(struct platform_device *pdev)
{
struct lpc18xx_wdt_dev *lpc18xx_wdt;
@@ -273,6 +270,7 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
(unsigned long)&lpc18xx_wdt->wdt_dev);
watchdog_set_nowayout(&lpc18xx_wdt->wdt_dev, nowayout);
+ watchdog_set_restart_priority(&lpc18xx_wdt->wdt_dev, 128);
platform_set_drvdata(pdev, lpc18xx_wdt);
@@ -280,12 +278,6 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
if (ret)
goto disable_wdt_clk;
- lpc18xx_wdt->restart_handler.notifier_call = lpc18xx_wdt_restart;
- lpc18xx_wdt->restart_handler.priority = 128;
- ret = register_restart_handler(&lpc18xx_wdt->restart_handler);
- if (ret)
- dev_warn(dev, "failed to register restart handler: %d\n", ret);
-
return 0;
disable_wdt_clk:
@@ -306,8 +298,6 @@ static int lpc18xx_wdt_remove(struct platform_device *pdev)
{
struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&lpc18xx_wdt->restart_handler);
-
dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n");
del_timer(&lpc18xx_wdt->timer);
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c
index 098fa9c34d6d..af6a7c489f08 100644
--- a/drivers/watchdog/mena21_wdt.c
+++ b/drivers/watchdog/mena21_wdt.c
@@ -100,12 +100,12 @@ static int a21_wdt_set_timeout(struct watchdog_device *wdt,
struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
if (timeout != 1 && timeout != 30) {
- dev_err(wdt->dev, "Only 1 and 30 allowed as timeout\n");
+ dev_err(wdt->parent, "Only 1 and 30 allowed as timeout\n");
return -EINVAL;
}
if (timeout == 30 && wdt->timeout == 1) {
- dev_err(wdt->dev,
+ dev_err(wdt->parent,
"Transition from fast to slow mode not allowed\n");
return -EINVAL;
}
diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c
index 1f4155ee3404..aea5d2f44ad7 100644
--- a/drivers/watchdog/meson_wdt.c
+++ b/drivers/watchdog/meson_wdt.c
@@ -17,51 +17,64 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/notifier.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#define DRV_NAME "meson_wdt"
#define MESON_WDT_TC 0x00
-#define MESON_WDT_TC_EN BIT(22)
-#define MESON_WDT_TC_TM_MASK 0x3fffff
#define MESON_WDT_DC_RESET (3 << 24)
#define MESON_WDT_RESET 0x04
#define MESON_WDT_TIMEOUT 30
#define MESON_WDT_MIN_TIMEOUT 1
-#define MESON_WDT_MAX_TIMEOUT (MESON_WDT_TC_TM_MASK / 100000)
-#define MESON_SEC_TO_TC(s) ((s) * 100000)
+#define MESON_SEC_TO_TC(s, c) ((s) * (c))
static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned int timeout = MESON_WDT_TIMEOUT;
+struct meson_wdt_data {
+ unsigned int enable;
+ unsigned int terminal_count_mask;
+ unsigned int count_unit;
+};
+
+static struct meson_wdt_data meson6_wdt_data = {
+ .enable = BIT(22),
+ .terminal_count_mask = 0x3fffff,
+ .count_unit = 100000, /* 10 us */
+};
+
+static struct meson_wdt_data meson8b_wdt_data = {
+ .enable = BIT(19),
+ .terminal_count_mask = 0xffff,
+ .count_unit = 7812, /* 128 us */
+};
+
struct meson_wdt_dev {
struct watchdog_device wdt_dev;
void __iomem *wdt_base;
- struct notifier_block restart_handler;
+ const struct meson_wdt_data *data;
};
-static int meson_restart_handle(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int meson_wdt_restart(struct watchdog_device *wdt_dev)
{
- u32 tc_reboot = MESON_WDT_DC_RESET | MESON_WDT_TC_EN;
- struct meson_wdt_dev *meson_wdt = container_of(this,
- struct meson_wdt_dev,
- restart_handler);
+ struct meson_wdt_dev *meson_wdt = watchdog_get_drvdata(wdt_dev);
+ u32 tc_reboot = MESON_WDT_DC_RESET;
+
+ tc_reboot |= meson_wdt->data->enable;
while (1) {
writel(tc_reboot, meson_wdt->wdt_base + MESON_WDT_TC);
mdelay(5);
}
- return NOTIFY_DONE;
+ return 0;
}
static int meson_wdt_ping(struct watchdog_device *wdt_dev)
@@ -80,8 +93,8 @@ static void meson_wdt_change_timeout(struct watchdog_device *wdt_dev,
u32 reg;
reg = readl(meson_wdt->wdt_base + MESON_WDT_TC);
- reg &= ~MESON_WDT_TC_TM_MASK;
- reg |= MESON_SEC_TO_TC(timeout);
+ reg &= ~meson_wdt->data->terminal_count_mask;
+ reg |= MESON_SEC_TO_TC(timeout, meson_wdt->data->count_unit);
writel(reg, meson_wdt->wdt_base + MESON_WDT_TC);
}
@@ -102,7 +115,7 @@ static int meson_wdt_stop(struct watchdog_device *wdt_dev)
u32 reg;
reg = readl(meson_wdt->wdt_base + MESON_WDT_TC);
- reg &= ~MESON_WDT_TC_EN;
+ reg &= ~meson_wdt->data->enable;
writel(reg, meson_wdt->wdt_base + MESON_WDT_TC);
return 0;
@@ -117,7 +130,7 @@ static int meson_wdt_start(struct watchdog_device *wdt_dev)
meson_wdt_ping(wdt_dev);
reg = readl(meson_wdt->wdt_base + MESON_WDT_TC);
- reg |= MESON_WDT_TC_EN;
+ reg |= meson_wdt->data->enable;
writel(reg, meson_wdt->wdt_base + MESON_WDT_TC);
return 0;
@@ -136,12 +149,21 @@ static const struct watchdog_ops meson_wdt_ops = {
.stop = meson_wdt_stop,
.ping = meson_wdt_ping,
.set_timeout = meson_wdt_set_timeout,
+ .restart = meson_wdt_restart,
+};
+
+static const struct of_device_id meson_wdt_dt_ids[] = {
+ { .compatible = "amlogic,meson6-wdt", .data = &meson6_wdt_data },
+ { .compatible = "amlogic,meson8b-wdt", .data = &meson8b_wdt_data },
+ { /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids);
static int meson_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
struct meson_wdt_dev *meson_wdt;
+ const struct of_device_id *of_id;
int err;
meson_wdt = devm_kzalloc(&pdev->dev, sizeof(*meson_wdt), GFP_KERNEL);
@@ -153,17 +175,28 @@ static int meson_wdt_probe(struct platform_device *pdev)
if (IS_ERR(meson_wdt->wdt_base))
return PTR_ERR(meson_wdt->wdt_base);
+ of_id = of_match_device(meson_wdt_dt_ids, &pdev->dev);
+ if (!of_id) {
+ dev_err(&pdev->dev, "Unable to initialize WDT data\n");
+ return -ENODEV;
+ }
+ meson_wdt->data = of_id->data;
+
meson_wdt->wdt_dev.parent = &pdev->dev;
meson_wdt->wdt_dev.info = &meson_wdt_info;
meson_wdt->wdt_dev.ops = &meson_wdt_ops;
- meson_wdt->wdt_dev.timeout = MESON_WDT_TIMEOUT;
- meson_wdt->wdt_dev.max_timeout = MESON_WDT_MAX_TIMEOUT;
+ meson_wdt->wdt_dev.max_timeout =
+ meson_wdt->data->terminal_count_mask / meson_wdt->data->count_unit;
meson_wdt->wdt_dev.min_timeout = MESON_WDT_MIN_TIMEOUT;
+ meson_wdt->wdt_dev.timeout = min_t(unsigned int,
+ MESON_WDT_TIMEOUT,
+ meson_wdt->wdt_dev.max_timeout);
watchdog_set_drvdata(&meson_wdt->wdt_dev, meson_wdt);
watchdog_init_timeout(&meson_wdt->wdt_dev, timeout, &pdev->dev);
watchdog_set_nowayout(&meson_wdt->wdt_dev, nowayout);
+ watchdog_set_restart_priority(&meson_wdt->wdt_dev, 128);
meson_wdt_stop(&meson_wdt->wdt_dev);
@@ -173,13 +206,6 @@ static int meson_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, meson_wdt);
- meson_wdt->restart_handler.notifier_call = meson_restart_handle;
- meson_wdt->restart_handler.priority = 128;
- err = register_restart_handler(&meson_wdt->restart_handler);
- if (err)
- dev_err(&pdev->dev,
- "cannot register restart handler (err=%d)\n", err);
-
dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
meson_wdt->wdt_dev.timeout, nowayout);
@@ -190,8 +216,6 @@ static int meson_wdt_remove(struct platform_device *pdev)
{
struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&meson_wdt->restart_handler);
-
watchdog_unregister_device(&meson_wdt->wdt_dev);
return 0;
@@ -204,12 +228,6 @@ static void meson_wdt_shutdown(struct platform_device *pdev)
meson_wdt_stop(&meson_wdt->wdt_dev);
}
-static const struct of_device_id meson_wdt_dt_ids[] = {
- { .compatible = "amlogic,meson6-wdt" },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids);
-
static struct platform_driver meson_wdt_driver = {
.probe = meson_wdt_probe,
.remove = meson_wdt_remove,
diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c
index 60b0605bd7e6..885c81bc4210 100644
--- a/drivers/watchdog/moxart_wdt.c
+++ b/drivers/watchdog/moxart_wdt.c
@@ -15,9 +15,7 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/kernel.h>
-#include <linux/notifier.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/watchdog.h>
#include <linux/moduleparam.h>
@@ -29,22 +27,19 @@ struct moxart_wdt_dev {
struct watchdog_device dev;
void __iomem *base;
unsigned int clock_frequency;
- struct notifier_block restart_handler;
};
static int heartbeat;
-static int moxart_restart_handle(struct notifier_block *this,
- unsigned long mode, void *cmd)
+static int moxart_wdt_restart(struct watchdog_device *wdt_dev)
{
- struct moxart_wdt_dev *moxart_wdt = container_of(this,
- struct moxart_wdt_dev,
- restart_handler);
+ struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
+
writel(1, moxart_wdt->base + REG_COUNT);
writel(0x5ab9, moxart_wdt->base + REG_MODE);
writel(0x03, moxart_wdt->base + REG_ENABLE);
- return NOTIFY_DONE;
+ return 0;
}
static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
@@ -87,6 +82,7 @@ static const struct watchdog_ops moxart_wdt_ops = {
.start = moxart_wdt_start,
.stop = moxart_wdt_stop,
.set_timeout = moxart_wdt_set_timeout,
+ .restart = moxart_wdt_restart,
};
static int moxart_wdt_probe(struct platform_device *pdev)
@@ -134,6 +130,7 @@ static int moxart_wdt_probe(struct platform_device *pdev)
watchdog_init_timeout(&moxart_wdt->dev, heartbeat, dev);
watchdog_set_nowayout(&moxart_wdt->dev, nowayout);
+ watchdog_set_restart_priority(&moxart_wdt->dev, 128);
watchdog_set_drvdata(&moxart_wdt->dev, moxart_wdt);
@@ -141,13 +138,6 @@ static int moxart_wdt_probe(struct platform_device *pdev)
if (err)
return err;
- moxart_wdt->restart_handler.notifier_call = moxart_restart_handle;
- moxart_wdt->restart_handler.priority = 128;
- err = register_restart_handler(&moxart_wdt->restart_handler);
- if (err)
- dev_err(dev, "cannot register restart notifier (err=%d)\n",
- err);
-
dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
moxart_wdt->dev.timeout, nowayout);
@@ -158,7 +148,6 @@ static int moxart_wdt_remove(struct platform_device *pdev)
{
struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&moxart_wdt->restart_handler);
moxart_wdt_stop(&moxart_wdt->dev);
return 0;
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c
new file mode 100644
index 000000000000..4a2290f900a8
--- /dev/null
+++ b/drivers/watchdog/mt7621_wdt.c
@@ -0,0 +1,186 @@
+/*
+ * Ralink MT7621/MT7628 built-in hardware watchdog timer
+ *
+ * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
+ *
+ * This driver was based on: drivers/watchdog/rt2880_wdt.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/watchdog.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define SYSC_RSTSTAT 0x38
+#define WDT_RST_CAUSE BIT(1)
+
+#define RALINK_WDT_TIMEOUT 30
+
+#define TIMER_REG_TMRSTAT 0x00
+#define TIMER_REG_TMR1LOAD 0x24
+#define TIMER_REG_TMR1CTL 0x20
+
+#define TMR1CTL_ENABLE BIT(7)
+#define TMR1CTL_RESTART BIT(9)
+#define TMR1CTL_PRESCALE_SHIFT 16
+
+static void __iomem *mt7621_wdt_base;
+static struct reset_control *mt7621_wdt_reset;
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static inline void rt_wdt_w32(unsigned reg, u32 val)
+{
+ iowrite32(val, mt7621_wdt_base + reg);
+}
+
+static inline u32 rt_wdt_r32(unsigned reg)
+{
+ return ioread32(mt7621_wdt_base + reg);
+}
+
+static int mt7621_wdt_ping(struct watchdog_device *w)
+{
+ rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART);
+
+ return 0;
+}
+
+static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
+{
+ w->timeout = t;
+ rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000);
+ mt7621_wdt_ping(w);
+
+ return 0;
+}
+
+static int mt7621_wdt_start(struct watchdog_device *w)
+{
+ u32 t;
+
+ /* set the prescaler to 1ms == 1000us */
+ rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT);
+
+ mt7621_wdt_set_timeout(w, w->timeout);
+
+ t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t |= TMR1CTL_ENABLE;
+ rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+ return 0;
+}
+
+static int mt7621_wdt_stop(struct watchdog_device *w)
+{
+ u32 t;
+
+ mt7621_wdt_ping(w);
+
+ t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t &= ~TMR1CTL_ENABLE;
+ rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+ return 0;
+}
+
+static int mt7621_wdt_bootcause(void)
+{
+ if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE)
+ return WDIOF_CARDRESET;
+
+ return 0;
+}
+
+static struct watchdog_info mt7621_wdt_info = {
+ .identity = "Mediatek Watchdog",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+};
+
+static struct watchdog_ops mt7621_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = mt7621_wdt_start,
+ .stop = mt7621_wdt_stop,
+ .ping = mt7621_wdt_ping,
+ .set_timeout = mt7621_wdt_set_timeout,
+};
+
+static struct watchdog_device mt7621_wdt_dev = {
+ .info = &mt7621_wdt_info,
+ .ops = &mt7621_wdt_ops,
+ .min_timeout = 1,
+ .max_timeout = 0xfffful / 1000,
+};
+
+static int mt7621_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mt7621_wdt_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mt7621_wdt_base))
+ return PTR_ERR(mt7621_wdt_base);
+
+ mt7621_wdt_reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (!IS_ERR(mt7621_wdt_reset))
+ reset_control_deassert(mt7621_wdt_reset);
+
+ mt7621_wdt_dev.dev = &pdev->dev;
+ mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause();
+
+ watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout,
+ &pdev->dev);
+ watchdog_set_nowayout(&mt7621_wdt_dev, nowayout);
+
+ ret = watchdog_register_device(&mt7621_wdt_dev);
+
+ return 0;
+}
+
+static int mt7621_wdt_remove(struct platform_device *pdev)
+{
+ watchdog_unregister_device(&mt7621_wdt_dev);
+
+ return 0;
+}
+
+static void mt7621_wdt_shutdown(struct platform_device *pdev)
+{
+ mt7621_wdt_stop(&mt7621_wdt_dev);
+}
+
+static const struct of_device_id mt7621_wdt_match[] = {
+ { .compatible = "mediatek,mt7621-wdt" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7621_wdt_match);
+
+static struct platform_driver mt7621_wdt_driver = {
+ .probe = mt7621_wdt_probe,
+ .remove = mt7621_wdt_remove,
+ .shutdown = mt7621_wdt_shutdown,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = mt7621_wdt_match,
+ },
+};
+
+module_platform_driver(mt7621_wdt_driver);
+
+MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index b751f43d76ed..b78776c05554 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -28,8 +28,6 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/delay.h>
#define WDT_MAX_TIMEOUT 31
@@ -64,16 +62,13 @@ static unsigned int timeout = WDT_MAX_TIMEOUT;
struct mtk_wdt_dev {
struct watchdog_device wdt_dev;
void __iomem *wdt_base;
- struct notifier_block restart_handler;
};
-static int mtk_reset_handler(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int mtk_wdt_restart(struct watchdog_device *wdt_dev)
{
- struct mtk_wdt_dev *mtk_wdt;
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
void __iomem *wdt_base;
- mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler);
wdt_base = mtk_wdt->wdt_base;
while (1) {
@@ -81,7 +76,7 @@ static int mtk_reset_handler(struct notifier_block *this, unsigned long mode,
mdelay(5);
}
- return NOTIFY_DONE;
+ return 0;
}
static int mtk_wdt_ping(struct watchdog_device *wdt_dev)
@@ -161,6 +156,7 @@ static const struct watchdog_ops mtk_wdt_ops = {
.stop = mtk_wdt_stop,
.ping = mtk_wdt_ping,
.set_timeout = mtk_wdt_set_timeout,
+ .restart = mtk_wdt_restart,
};
static int mtk_wdt_probe(struct platform_device *pdev)
@@ -189,6 +185,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev);
watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);
+ watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128);
watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
@@ -198,13 +195,6 @@ static int mtk_wdt_probe(struct platform_device *pdev)
if (unlikely(err))
return err;
- mtk_wdt->restart_handler.notifier_call = mtk_reset_handler;
- mtk_wdt->restart_handler.priority = 128;
- err = register_restart_handler(&mtk_wdt->restart_handler);
- if (err)
- dev_warn(&pdev->dev,
- "cannot register restart handler (err=%d)\n", err);
-
dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
mtk_wdt->wdt_dev.timeout, nowayout);
@@ -223,8 +213,6 @@ static int mtk_wdt_remove(struct platform_device *pdev)
{
struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&mtk_wdt->restart_handler);
-
watchdog_unregister_device(&mtk_wdt->wdt_dev);
return 0;
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 6f17c935a6cf..1b02bfa81b29 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -271,7 +271,8 @@ static int omap_wdt_probe(struct platform_device *pdev)
wdev->wdog.bootstatus = WDIOF_CARDRESET;
}
- omap_wdt_disable(wdev);
+ if (!early_enable)
+ omap_wdt_disable(wdev);
ret = watchdog_register_device(&wdev->wdog);
if (ret) {
@@ -283,11 +284,11 @@ static int omap_wdt_probe(struct platform_device *pdev)
readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
wdev->wdog.timeout);
- pm_runtime_put_sync(wdev->dev);
-
if (early_enable)
omap_wdt_start(&wdev->wdog);
+ pm_runtime_put(wdev->dev);
+
return 0;
}
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
index 773dcfaee7b2..424f9a952fee 100644
--- a/drivers/watchdog/qcom-wdt.c
+++ b/drivers/watchdog/qcom-wdt.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/watchdog.h>
#define WDT_RST 0x38
@@ -28,7 +27,6 @@ struct qcom_wdt {
struct watchdog_device wdd;
struct clk *clk;
unsigned long rate;
- struct notifier_block restart_nb;
void __iomem *base;
};
@@ -72,25 +70,9 @@ static int qcom_wdt_set_timeout(struct watchdog_device *wdd,
return qcom_wdt_start(wdd);
}
-static const struct watchdog_ops qcom_wdt_ops = {
- .start = qcom_wdt_start,
- .stop = qcom_wdt_stop,
- .ping = qcom_wdt_ping,
- .set_timeout = qcom_wdt_set_timeout,
- .owner = THIS_MODULE,
-};
-
-static const struct watchdog_info qcom_wdt_info = {
- .options = WDIOF_KEEPALIVEPING
- | WDIOF_MAGICCLOSE
- | WDIOF_SETTIMEOUT,
- .identity = KBUILD_MODNAME,
-};
-
-static int qcom_wdt_restart(struct notifier_block *nb, unsigned long action,
- void *data)
+static int qcom_wdt_restart(struct watchdog_device *wdd)
{
- struct qcom_wdt *wdt = container_of(nb, struct qcom_wdt, restart_nb);
+ struct qcom_wdt *wdt = to_qcom_wdt(wdd);
u32 timeout;
/*
@@ -110,9 +92,25 @@ static int qcom_wdt_restart(struct notifier_block *nb, unsigned long action,
wmb();
msleep(150);
- return NOTIFY_DONE;
+ return 0;
}
+static const struct watchdog_ops qcom_wdt_ops = {
+ .start = qcom_wdt_start,
+ .stop = qcom_wdt_stop,
+ .ping = qcom_wdt_ping,
+ .set_timeout = qcom_wdt_set_timeout,
+ .restart = qcom_wdt_restart,
+ .owner = THIS_MODULE,
+};
+
+static const struct watchdog_info qcom_wdt_info = {
+ .options = WDIOF_KEEPALIVEPING
+ | WDIOF_MAGICCLOSE
+ | WDIOF_SETTIMEOUT,
+ .identity = KBUILD_MODNAME,
+};
+
static int qcom_wdt_probe(struct platform_device *pdev)
{
struct qcom_wdt *wdt;
@@ -166,7 +164,6 @@ static int qcom_wdt_probe(struct platform_device *pdev)
goto err_clk_unprepare;
}
- wdt->wdd.dev = &pdev->dev;
wdt->wdd.info = &qcom_wdt_info;
wdt->wdd.ops = &qcom_wdt_ops;
wdt->wdd.min_timeout = 1;
@@ -187,14 +184,6 @@ static int qcom_wdt_probe(struct platform_device *pdev)
goto err_clk_unprepare;
}
- /*
- * WDT restart notifier has priority 0 (use as a last resort)
- */
- wdt->restart_nb.notifier_call = qcom_wdt_restart;
- ret = register_restart_handler(&wdt->restart_nb);
- if (ret)
- dev_err(&pdev->dev, "failed to setup restart handler\n");
-
platform_set_drvdata(pdev, wdt);
return 0;
@@ -207,7 +196,6 @@ static int qcom_wdt_remove(struct platform_device *pdev)
{
struct qcom_wdt *wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&wdt->restart_nb);
watchdog_unregister_device(&wdt->wdd);
clk_disable_unprepare(wdt->clk);
return 0;
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index d781000c7825..0093450441fe 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -41,7 +41,6 @@
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
-#include <linux/reboot.h>
#include <linux/delay.h>
#define S3C2410_WTCON 0x00
@@ -130,7 +129,6 @@ struct s3c2410_wdt {
unsigned long wtdat_save;
struct watchdog_device wdt_device;
struct notifier_block freq_transition;
- struct notifier_block restart_handler;
struct s3c2410_wdt_variant *drv_data;
struct regmap *pmureg;
};
@@ -351,6 +349,29 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
return 0;
}
+static int s3c2410wdt_restart(struct watchdog_device *wdd)
+{
+ struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
+ void __iomem *wdt_base = wdt->reg_base;
+
+ /* disable watchdog, to be safe */
+ writel(0, wdt_base + S3C2410_WTCON);
+
+ /* put initial values into count and data */
+ writel(0x80, wdt_base + S3C2410_WTCNT);
+ writel(0x80, wdt_base + S3C2410_WTDAT);
+
+ /* set the watchdog to go and reset... */
+ writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
+ S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
+ wdt_base + S3C2410_WTCON);
+
+ /* wait for reset to assert... */
+ mdelay(500);
+
+ return 0;
+}
+
#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
static const struct watchdog_info s3c2410_wdt_ident = {
@@ -365,6 +386,7 @@ static struct watchdog_ops s3c2410wdt_ops = {
.stop = s3c2410wdt_stop,
.ping = s3c2410wdt_keepalive,
.set_timeout = s3c2410wdt_set_heartbeat,
+ .restart = s3c2410wdt_restart,
};
static struct watchdog_device s3c2410_wdd = {
@@ -452,31 +474,6 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
}
#endif
-static int s3c2410wdt_restart(struct notifier_block *this,
- unsigned long mode, void *cmd)
-{
- struct s3c2410_wdt *wdt = container_of(this, struct s3c2410_wdt,
- restart_handler);
- void __iomem *wdt_base = wdt->reg_base;
-
- /* disable watchdog, to be safe */
- writel(0, wdt_base + S3C2410_WTCON);
-
- /* put initial values into count and data */
- writel(0x80, wdt_base + S3C2410_WTCNT);
- writel(0x80, wdt_base + S3C2410_WTDAT);
-
- /* set the watchdog to go and reset... */
- writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
- S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
- wdt_base + S3C2410_WTCON);
-
- /* wait for reset to assert... */
- mdelay(500);
-
- return NOTIFY_DONE;
-}
-
static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
{
unsigned int rst_stat;
@@ -605,6 +602,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
}
watchdog_set_nowayout(&wdt->wdt_device, nowayout);
+ watchdog_set_restart_priority(&wdt->wdt_device, 128);
wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt);
wdt->wdt_device.parent = &pdev->dev;
@@ -632,12 +630,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdt);
- wdt->restart_handler.notifier_call = s3c2410wdt_restart;
- wdt->restart_handler.priority = 128;
- ret = register_restart_handler(&wdt->restart_handler);
- if (ret)
- pr_err("cannot register restart handler, %d\n", ret);
-
/* print out a statement of readiness */
wtcon = readl(wdt->reg_base + S3C2410_WTCON);
@@ -667,8 +659,6 @@ static int s3c2410wdt_remove(struct platform_device *dev)
int ret;
struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
- unregister_restart_handler(&wdt->restart_handler);
-
ret = s3c2410wdt_mask_and_disable_reset(wdt, true);
if (ret < 0)
return ret;
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index 0dc5e323d59d..99a06f9e3930 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -43,7 +43,6 @@
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/watchdog.h>
-#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/jiffies.h>
@@ -87,6 +86,7 @@ static struct timer_list watchdog_ticktock =
static void watchdog_fire(unsigned long data)
{
+ module_put(THIS_MODULE);
if (soft_noboot)
pr_crit("Triggered - Reboot ignored\n");
else if (soft_panic) {
@@ -105,13 +105,16 @@ static void watchdog_fire(unsigned long data)
static int softdog_ping(struct watchdog_device *w)
{
- mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ));
+ if (!mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ)))
+ __module_get(THIS_MODULE);
return 0;
}
static int softdog_stop(struct watchdog_device *w)
{
- del_timer(&watchdog_ticktock);
+ if (del_timer(&watchdog_ticktock))
+ module_put(THIS_MODULE);
+
return 0;
}
@@ -122,26 +125,9 @@ static int softdog_set_timeout(struct watchdog_device *w, unsigned int t)
}
/*
- * Notifier for system down
- */
-
-static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT)
- /* Turn the WDT off */
- softdog_stop(NULL);
- return NOTIFY_DONE;
-}
-
-/*
* Kernel Interfaces
*/
-static struct notifier_block softdog_notifier = {
- .notifier_call = softdog_notify_sys,
-};
-
static struct watchdog_info softdog_info = {
.identity = "Software Watchdog",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
@@ -175,18 +161,11 @@ static int __init watchdog_init(void)
softdog_dev.timeout = soft_margin;
watchdog_set_nowayout(&softdog_dev, nowayout);
-
- ret = register_reboot_notifier(&softdog_notifier);
- if (ret) {
- pr_err("cannot register reboot notifier (err=%d)\n", ret);
- return ret;
- }
+ watchdog_stop_on_reboot(&softdog_dev);
ret = watchdog_register_device(&softdog_dev);
- if (ret) {
- unregister_reboot_notifier(&softdog_notifier);
+ if (ret)
return ret;
- }
pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
soft_noboot, soft_margin, soft_panic, nowayout);
@@ -197,7 +176,6 @@ static int __init watchdog_init(void)
static void __exit watchdog_exit(void)
{
watchdog_unregister_device(&softdog_dev);
- unregister_reboot_notifier(&softdog_notifier);
}
module_init(watchdog_init);
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index eb8044ef0ea0..6467b91f2245 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -306,6 +306,10 @@ static struct miscdevice sp5100_tco_miscdev = {
static const struct pci_device_id sp5100_tco_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
PCI_ANY_ID, },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, PCI_ANY_ID,
+ PCI_ANY_ID, },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, PCI_ANY_ID,
+ PCI_ANY_ID, },
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
@@ -331,21 +335,24 @@ static unsigned char sp5100_tco_setupdevice(void)
if (!sp5100_tco_pci)
return 0;
- pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision);
+ pr_info("PCI Vendor ID: 0x%x, Device ID: 0x%x, Revision ID: 0x%x\n",
+ sp5100_tco_pci->vendor, sp5100_tco_pci->device,
+ sp5100_tco_pci->revision);
/*
* Determine type of southbridge chipset.
*/
- if (sp5100_tco_pci->revision >= 0x40) {
- dev_name = SB800_DEVNAME;
- index_reg = SB800_IO_PM_INDEX_REG;
- data_reg = SB800_IO_PM_DATA_REG;
- base_addr = SB800_PM_WATCHDOG_BASE;
- } else {
+ if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+ sp5100_tco_pci->revision < 0x40) {
dev_name = SP5100_DEVNAME;
index_reg = SP5100_IO_PM_INDEX_REG;
data_reg = SP5100_IO_PM_DATA_REG;
base_addr = SP5100_PM_WATCHDOG_BASE;
+ } else {
+ dev_name = SB800_DEVNAME;
+ index_reg = SB800_IO_PM_INDEX_REG;
+ data_reg = SB800_IO_PM_DATA_REG;
+ base_addr = SB800_PM_WATCHDOG_BASE;
}
/* Request the IO ports used by this driver */
@@ -381,7 +388,12 @@ static unsigned char sp5100_tco_setupdevice(void)
* Secondly, Find the watchdog timer MMIO address
* from SBResource_MMIO register.
*/
- if (sp5100_tco_pci->revision >= 0x40) {
+ if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+ sp5100_tco_pci->revision < 0x40) {
+ /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+ pci_read_config_dword(sp5100_tco_pci,
+ SP5100_SB_RESOURCE_MMIO_BASE, &val);
+ } else {
/* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG);
val = inb(SB800_IO_PM_DATA_REG);
@@ -391,10 +403,6 @@ static unsigned char sp5100_tco_setupdevice(void)
val = val << 8 | inb(SB800_IO_PM_DATA_REG);
outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG);
val = val << 8 | inb(SB800_IO_PM_DATA_REG);
- } else {
- /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
- pci_read_config_dword(sp5100_tco_pci,
- SP5100_SB_RESOURCE_MMIO_BASE, &val);
}
/* The SBResource_MMIO is enabled and mapped memory space? */
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c
index 3ee6128a540e..d8b11eb269ad 100644
--- a/drivers/watchdog/stmp3xxx_rtc_wdt.c
+++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -14,6 +14,8 @@
#include <linux/watchdog.h>
#include <linux/platform_device.h>
#include <linux/stmp3xxx_rtc_wdt.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
#define WDOG_TICK_RATE 1000 /* 1 kHz clock */
#define STMP3XXX_DEFAULT_TIMEOUT 19
@@ -69,6 +71,25 @@ static struct watchdog_device stmp3xxx_wdd = {
.status = WATCHDOG_NOWAYOUT_INIT_STATUS,
};
+static int wdt_notify_sys(struct notifier_block *nb, unsigned long code,
+ void *unused)
+{
+ switch (code) {
+ case SYS_DOWN: /* keep enabled, system might crash while going down */
+ break;
+ case SYS_HALT: /* allow the system to actually halt */
+ case SYS_POWER_OFF:
+ wdt_stop(&stmp3xxx_wdd);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
static int stmp3xxx_wdt_probe(struct platform_device *pdev)
{
int ret;
@@ -84,6 +105,9 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
return ret;
}
+ if (register_reboot_notifier(&wdt_notifier))
+ dev_warn(&pdev->dev, "cannot register reboot notifier\n");
+
dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n",
stmp3xxx_wdd.timeout);
return 0;
@@ -91,6 +115,7 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
static int stmp3xxx_wdt_remove(struct platform_device *pdev)
{
+ unregister_reboot_notifier(&wdt_notifier);
watchdog_unregister_device(&stmp3xxx_wdd);
return 0;
}
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index 47bd8a14d01f..e027deb54740 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -21,11 +21,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
@@ -60,7 +58,6 @@ struct sunxi_wdt_dev {
struct watchdog_device wdt_dev;
void __iomem *wdt_base;
const struct sunxi_wdt_reg *wdt_regs;
- struct notifier_block restart_handler;
};
/*
@@ -86,12 +83,9 @@ static const int wdt_timeout_map[] = {
};
-static int sunxi_restart_handle(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int sunxi_wdt_restart(struct watchdog_device *wdt_dev)
{
- struct sunxi_wdt_dev *sunxi_wdt = container_of(this,
- struct sunxi_wdt_dev,
- restart_handler);
+ struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
void __iomem *wdt_base = sunxi_wdt->wdt_base;
const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs;
u32 val;
@@ -120,7 +114,7 @@ static int sunxi_restart_handle(struct notifier_block *this, unsigned long mode,
val |= WDT_MODE_EN;
writel(val, wdt_base + regs->wdt_mode);
}
- return NOTIFY_DONE;
+ return 0;
}
static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
@@ -208,6 +202,7 @@ static const struct watchdog_ops sunxi_wdt_ops = {
.stop = sunxi_wdt_stop,
.ping = sunxi_wdt_ping,
.set_timeout = sunxi_wdt_set_timeout,
+ .restart = sunxi_wdt_restart,
};
static const struct sunxi_wdt_reg sun4i_wdt_reg = {
@@ -268,6 +263,7 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
watchdog_init_timeout(&sunxi_wdt->wdt_dev, timeout, &pdev->dev);
watchdog_set_nowayout(&sunxi_wdt->wdt_dev, nowayout);
+ watchdog_set_restart_priority(&sunxi_wdt->wdt_dev, 128);
watchdog_set_drvdata(&sunxi_wdt->wdt_dev, sunxi_wdt);
@@ -277,13 +273,6 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
if (unlikely(err))
return err;
- sunxi_wdt->restart_handler.notifier_call = sunxi_restart_handle;
- sunxi_wdt->restart_handler.priority = 128;
- err = register_restart_handler(&sunxi_wdt->restart_handler);
- if (err)
- dev_err(&pdev->dev,
- "cannot register restart handler (err=%d)\n", err);
-
dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
sunxi_wdt->wdt_dev.timeout, nowayout);
@@ -294,8 +283,6 @@ static int sunxi_wdt_remove(struct platform_device *pdev)
{
struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
- unregister_restart_handler(&sunxi_wdt->restart_handler);
-
watchdog_unregister_device(&sunxi_wdt->wdt_dev);
watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
diff --git a/drivers/watchdog/tangox_wdt.c b/drivers/watchdog/tangox_wdt.c
new file mode 100644
index 000000000000..709c1ed6fd79
--- /dev/null
+++ b/drivers/watchdog/tangox_wdt.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
+ * SMP86xx/SMP87xx Watchdog driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define DEFAULT_TIMEOUT 30
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout");
+
+/*
+ * Counter counts down from programmed value. Reset asserts when
+ * the counter reaches 1.
+ */
+#define WD_COUNTER 0
+
+#define WD_CONFIG 4
+#define WD_CONFIG_XTAL_IN BIT(0)
+#define WD_CONFIG_DISABLE BIT(31)
+
+struct tangox_wdt_device {
+ struct watchdog_device wdt;
+ void __iomem *base;
+ unsigned long clk_rate;
+ struct clk *clk;
+ struct notifier_block restart;
+};
+
+static int tangox_wdt_set_timeout(struct watchdog_device *wdt,
+ unsigned int new_timeout)
+{
+ wdt->timeout = new_timeout;
+
+ return 0;
+}
+
+static int tangox_wdt_start(struct watchdog_device *wdt)
+{
+ struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+ u32 ticks;
+
+ ticks = 1 + wdt->timeout * dev->clk_rate;
+ writel(ticks, dev->base + WD_COUNTER);
+
+ return 0;
+}
+
+static int tangox_wdt_stop(struct watchdog_device *wdt)
+{
+ struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+
+ writel(0, dev->base + WD_COUNTER);
+
+ return 0;
+}
+
+static unsigned int tangox_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+ struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+ u32 count;
+
+ count = readl(dev->base + WD_COUNTER);
+
+ if (!count)
+ return 0;
+
+ return (count - 1) / dev->clk_rate;
+}
+
+static const struct watchdog_info tangox_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "tangox watchdog",
+};
+
+static const struct watchdog_ops tangox_wdt_ops = {
+ .start = tangox_wdt_start,
+ .stop = tangox_wdt_stop,
+ .set_timeout = tangox_wdt_set_timeout,
+ .get_timeleft = tangox_wdt_get_timeleft,
+};
+
+static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct tangox_wdt_device *dev =
+ container_of(nb, struct tangox_wdt_device, restart);
+
+ writel(1, dev->base + WD_COUNTER);
+
+ return NOTIFY_DONE;
+}
+
+static int tangox_wdt_probe(struct platform_device *pdev)
+{
+ struct tangox_wdt_device *dev;
+ struct resource *res;
+ u32 config;
+ int err;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ err = clk_prepare_enable(dev->clk);
+ if (err)
+ return err;
+
+ dev->clk_rate = clk_get_rate(dev->clk);
+
+ dev->wdt.parent = &pdev->dev;
+ dev->wdt.info = &tangox_wdt_info;
+ dev->wdt.ops = &tangox_wdt_ops;
+ dev->wdt.timeout = DEFAULT_TIMEOUT;
+ dev->wdt.min_timeout = 1;
+ dev->wdt.max_timeout = (U32_MAX - 1) / dev->clk_rate;
+
+ watchdog_init_timeout(&dev->wdt, timeout, &pdev->dev);
+ watchdog_set_nowayout(&dev->wdt, nowayout);
+ watchdog_set_drvdata(&dev->wdt, dev);
+
+ /*
+ * Deactivate counter if disable bit is set to avoid
+ * accidental reset.
+ */
+ config = readl(dev->base + WD_CONFIG);
+ if (config & WD_CONFIG_DISABLE)
+ writel(0, dev->base + WD_COUNTER);
+
+ writel(WD_CONFIG_XTAL_IN, dev->base + WD_CONFIG);
+
+ /*
+ * Mark as active and restart with configured timeout if
+ * already running.
+ */
+ if (readl(dev->base + WD_COUNTER)) {
+ set_bit(WDOG_ACTIVE, &dev->wdt.status);
+ tangox_wdt_start(&dev->wdt);
+ }
+
+ err = watchdog_register_device(&dev->wdt);
+ if (err) {
+ clk_disable_unprepare(dev->clk);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->restart.notifier_call = tangox_wdt_restart;
+ dev->restart.priority = 128;
+ err = register_restart_handler(&dev->restart);
+ if (err)
+ dev_warn(&pdev->dev, "failed to register restart handler\n");
+
+ dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n");
+
+ return 0;
+}
+
+static int tangox_wdt_remove(struct platform_device *pdev)
+{
+ struct tangox_wdt_device *dev = platform_get_drvdata(pdev);
+
+ tangox_wdt_stop(&dev->wdt);
+ clk_disable_unprepare(dev->clk);
+
+ unregister_restart_handler(&dev->restart);
+ watchdog_unregister_device(&dev->wdt);
+
+ return 0;
+}
+
+static const struct of_device_id tangox_wdt_dt_ids[] = {
+ { .compatible = "sigma,smp8642-wdt" },
+ { .compatible = "sigma,smp8759-wdt" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tangox_wdt_dt_ids);
+
+static struct platform_driver tangox_wdt_driver = {
+ .probe = tangox_wdt_probe,
+ .remove = tangox_wdt_remove,
+ .driver = {
+ .name = "tangox-wdt",
+ .of_match_table = tangox_wdt_dt_ids,
+ },
+};
+
+module_platform_driver(tangox_wdt_driver);
+
+MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
+MODULE_DESCRIPTION("SMP86xx/SMP87xx Watchdog driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ts4800_wdt.c b/drivers/watchdog/ts4800_wdt.c
new file mode 100644
index 000000000000..2b8de8602b67
--- /dev/null
+++ b/drivers/watchdog/ts4800_wdt.c
@@ -0,0 +1,215 @@
+/*
+ * Watchdog driver for TS-4800 based boards
+ *
+ * Copyright (c) 2015 - Savoir-faire Linux
+ *
+ * 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/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/watchdog.h>
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/* possible feed values */
+#define TS4800_WDT_FEED_2S 0x1
+#define TS4800_WDT_FEED_10S 0x2
+#define TS4800_WDT_DISABLE 0x3
+
+struct ts4800_wdt {
+ struct watchdog_device wdd;
+ struct regmap *regmap;
+ u32 feed_offset;
+ u32 feed_val;
+};
+
+/*
+ * TS-4800 supports the following timeout values:
+ *
+ * value desc
+ * ---------------------
+ * 0 feed for 338ms
+ * 1 feed for 2.706s
+ * 2 feed for 10.824s
+ * 3 disable watchdog
+ *
+ * Keep the regmap/timeout map ordered by timeout
+ */
+static const struct {
+ const int timeout;
+ const int regval;
+} ts4800_wdt_map[] = {
+ { 2, TS4800_WDT_FEED_2S },
+ { 10, TS4800_WDT_FEED_10S },
+};
+
+#define MAX_TIMEOUT_INDEX (ARRAY_SIZE(ts4800_wdt_map) - 1)
+
+static void ts4800_write_feed(struct ts4800_wdt *wdt, u32 val)
+{
+ regmap_write(wdt->regmap, wdt->feed_offset, val);
+}
+
+static int ts4800_wdt_start(struct watchdog_device *wdd)
+{
+ struct ts4800_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ ts4800_write_feed(wdt, wdt->feed_val);
+ return 0;
+}
+
+static int ts4800_wdt_stop(struct watchdog_device *wdd)
+{
+ struct ts4800_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ ts4800_write_feed(wdt, TS4800_WDT_DISABLE);
+ return 0;
+}
+
+static int ts4800_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ struct ts4800_wdt *wdt = watchdog_get_drvdata(wdd);
+ int i;
+
+ for (i = 0; i < MAX_TIMEOUT_INDEX; i++) {
+ if (ts4800_wdt_map[i].timeout >= timeout)
+ break;
+ }
+
+ wdd->timeout = ts4800_wdt_map[i].timeout;
+ wdt->feed_val = ts4800_wdt_map[i].regval;
+
+ return 0;
+}
+
+static const struct watchdog_ops ts4800_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = ts4800_wdt_start,
+ .stop = ts4800_wdt_stop,
+ .set_timeout = ts4800_wdt_set_timeout,
+};
+
+static const struct watchdog_info ts4800_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "TS-4800 Watchdog",
+};
+
+static int ts4800_wdt_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *syscon_np;
+ struct watchdog_device *wdd;
+ struct ts4800_wdt *wdt;
+ u32 reg;
+ int ret;
+
+ syscon_np = of_parse_phandle(np, "syscon", 0);
+ if (!syscon_np) {
+ dev_err(&pdev->dev, "no syscon property\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32_index(np, "syscon", 1, &reg);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "no offset in syscon\n");
+ return ret;
+ }
+
+ /* allocate memory for watchdog struct */
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ /* set regmap and offset to know where to write */
+ wdt->feed_offset = reg;
+ wdt->regmap = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(wdt->regmap)) {
+ dev_err(&pdev->dev, "cannot get parent's regmap\n");
+ return PTR_ERR(wdt->regmap);
+ }
+
+ /* Initialize struct watchdog_device */
+ wdd = &wdt->wdd;
+ wdd->parent = &pdev->dev;
+ wdd->info = &ts4800_wdt_info;
+ wdd->ops = &ts4800_wdt_ops;
+ wdd->min_timeout = ts4800_wdt_map[0].timeout;
+ wdd->max_timeout = ts4800_wdt_map[MAX_TIMEOUT_INDEX].timeout;
+
+ watchdog_set_drvdata(wdd, wdt);
+ watchdog_set_nowayout(wdd, nowayout);
+ watchdog_init_timeout(wdd, 0, &pdev->dev);
+
+ /*
+ * As this watchdog supports only a few values, ts4800_wdt_set_timeout
+ * must be called to initialize timeout and feed_val with valid values.
+ * Default to maximum timeout if none, or an invalid one, is provided in
+ * device tree.
+ */
+ if (!wdd->timeout)
+ wdd->timeout = wdd->max_timeout;
+ ts4800_wdt_set_timeout(wdd, wdd->timeout);
+
+ /*
+ * The feed register is write-only, so it is not possible to determine
+ * watchdog's state. Disable it to be in a known state.
+ */
+ ts4800_wdt_stop(wdd);
+
+ ret = watchdog_register_device(wdd);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to register watchdog device\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, wdt);
+
+ dev_info(&pdev->dev,
+ "initialized (timeout = %d sec, nowayout = %d)\n",
+ wdd->timeout, nowayout);
+
+ return 0;
+}
+
+static int ts4800_wdt_remove(struct platform_device *pdev)
+{
+ struct ts4800_wdt *wdt = platform_get_drvdata(pdev);
+
+ watchdog_unregister_device(&wdt->wdd);
+
+ return 0;
+}
+
+static const struct of_device_id ts4800_wdt_of_match[] = {
+ { .compatible = "technologic,ts4800-wdt", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ts4800_wdt_of_match);
+
+static struct platform_driver ts4800_wdt_driver = {
+ .probe = ts4800_wdt_probe,
+ .remove = ts4800_wdt_remove,
+ .driver = {
+ .name = "ts4800_wdt",
+ .of_match_table = ts4800_wdt_of_match,
+ },
+};
+
+module_platform_driver(ts4800_wdt_driver);
+
+MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ts4800_wdt");
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 5824e25eebbb..cab14bc9106c 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -36,8 +36,6 @@
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -288,18 +286,6 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog)
}
/*
- * Notifier for system down
- */
-static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT)
- wdt_set_time(0); /* Turn the WDT off */
-
- return NOTIFY_DONE;
-}
-
-/*
* Kernel Interfaces
*/
@@ -329,10 +315,6 @@ static struct watchdog_device wdt_dev = {
* turn the timebomb registers off.
*/
-static struct notifier_block wdt_notifier = {
- .notifier_call = wdt_notify_sys,
-};
-
static int wdt_find(int addr)
{
u8 val;
@@ -456,6 +438,7 @@ static int __init wdt_init(void)
watchdog_init_timeout(&wdt_dev, timeout, NULL);
watchdog_set_nowayout(&wdt_dev, nowayout);
+ watchdog_stop_on_reboot(&wdt_dev);
ret = w83627hf_init(&wdt_dev, chip);
if (ret) {
@@ -463,30 +446,19 @@ static int __init wdt_init(void)
return ret;
}
- ret = register_reboot_notifier(&wdt_notifier);
- if (ret != 0) {
- pr_err("cannot register reboot notifier (err=%d)\n", ret);
- return ret;
- }
-
ret = watchdog_register_device(&wdt_dev);
if (ret)
- goto unreg_reboot;
+ return ret;
pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
wdt_dev.timeout, nowayout);
return ret;
-
-unreg_reboot:
- unregister_reboot_notifier(&wdt_notifier);
- return ret;
}
static void __exit wdt_exit(void)
{
watchdog_unregister_device(&wdt_dev);
- unregister_reboot_notifier(&wdt_notifier);
}
module_init(wdt_init);
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 873f13972cf4..e600fd93b7de 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -32,6 +32,7 @@
#include <linux/types.h> /* For standard types */
#include <linux/errno.h> /* For the -ENODEV/... values */
#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/reboot.h> /* For restart handler */
#include <linux/watchdog.h> /* For watchdog specific items */
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/idr.h> /* For ida_* macros */
@@ -41,7 +42,6 @@
#include "watchdog_core.h" /* For watchdog_dev_register/... */
static DEFINE_IDA(watchdog_ida);
-static struct class *watchdog_class;
/*
* Deferred Registration infrastructure.
@@ -137,9 +137,63 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
}
EXPORT_SYMBOL_GPL(watchdog_init_timeout);
+static int watchdog_reboot_notifier(struct notifier_block *nb,
+ unsigned long code, void *data)
+{
+ struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
+ reboot_nb);
+
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ if (watchdog_active(wdd)) {
+ int ret;
+
+ ret = wdd->ops->stop(wdd);
+ if (ret)
+ return NOTIFY_BAD;
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int watchdog_restart_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
+ restart_nb);
+
+ int ret;
+
+ ret = wdd->ops->restart(wdd);
+ if (ret)
+ return NOTIFY_BAD;
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * watchdog_set_restart_priority - Change priority of restart handler
+ * @wdd: watchdog device
+ * @priority: priority of the restart handler, should follow these guidelines:
+ * 0: use watchdog's restart function as last resort, has limited restart
+ * capabilies
+ * 128: default restart handler, use if no other handler is expected to be
+ * available and/or if restart is sufficient to restart the entire system
+ * 255: preempt all other handlers
+ *
+ * If a wdd->ops->restart function is provided when watchdog_register_device is
+ * called, it will be registered as a restart handler with the priority given
+ * here.
+ */
+void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority)
+{
+ wdd->restart_nb.priority = priority;
+}
+EXPORT_SYMBOL_GPL(watchdog_set_restart_priority);
+
static int __watchdog_register_device(struct watchdog_device *wdd)
{
- int ret, id = -1, devno;
+ int ret, id = -1;
if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
return -EINVAL;
@@ -156,8 +210,6 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
* corrupted in a later stage then we expect a kernel panic!
*/
- mutex_init(&wdd->lock);
-
/* Use alias for watchdog id if possible */
if (wdd->parent) {
ret = of_alias_get_id(wdd->parent->of_node, "watchdog");
@@ -192,14 +244,26 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
}
}
- devno = wdd->cdev.dev;
- wdd->dev = device_create(watchdog_class, wdd->parent, devno,
- NULL, "watchdog%d", wdd->id);
- if (IS_ERR(wdd->dev)) {
- watchdog_dev_unregister(wdd);
- ida_simple_remove(&watchdog_ida, id);
- ret = PTR_ERR(wdd->dev);
- return ret;
+ if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
+ wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
+
+ ret = register_reboot_notifier(&wdd->reboot_nb);
+ if (ret) {
+ pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
+ wdd->id, ret);
+ watchdog_dev_unregister(wdd);
+ ida_simple_remove(&watchdog_ida, wdd->id);
+ return ret;
+ }
+ }
+
+ if (wdd->ops->restart) {
+ wdd->restart_nb.notifier_call = watchdog_restart_notifier;
+
+ ret = register_restart_handler(&wdd->restart_nb);
+ if (ret)
+ pr_warn("watchog%d: Cannot register restart handler (%d)\n",
+ wdd->id, ret);
}
return 0;
@@ -232,19 +296,17 @@ EXPORT_SYMBOL_GPL(watchdog_register_device);
static void __watchdog_unregister_device(struct watchdog_device *wdd)
{
- int ret;
- int devno;
-
if (wdd == NULL)
return;
- devno = wdd->cdev.dev;
- ret = watchdog_dev_unregister(wdd);
- if (ret)
- pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
- device_destroy(watchdog_class, devno);
+ if (wdd->ops->restart)
+ unregister_restart_handler(&wdd->restart_nb);
+
+ if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))
+ unregister_reboot_notifier(&wdd->reboot_nb);
+
+ watchdog_dev_unregister(wdd);
ida_simple_remove(&watchdog_ida, wdd->id);
- wdd->dev = NULL;
}
/**
@@ -287,17 +349,9 @@ static int __init watchdog_init(void)
{
int err;
- watchdog_class = class_create(THIS_MODULE, "watchdog");
- if (IS_ERR(watchdog_class)) {
- pr_err("couldn't create class\n");
- return PTR_ERR(watchdog_class);
- }
-
err = watchdog_dev_init();
- if (err < 0) {
- class_destroy(watchdog_class);
+ if (err < 0)
return err;
- }
watchdog_deferred_registration();
return 0;
@@ -306,7 +360,6 @@ static int __init watchdog_init(void)
static void __exit watchdog_exit(void)
{
watchdog_dev_exit();
- class_destroy(watchdog_class);
ida_destroy(&watchdog_ida);
}
diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h
index 6c951418fca7..86ff962d1e15 100644
--- a/drivers/watchdog/watchdog_core.h
+++ b/drivers/watchdog/watchdog_core.h
@@ -32,6 +32,6 @@
* Functions/procedures to be called by the core
*/
extern int watchdog_dev_register(struct watchdog_device *);
-extern int watchdog_dev_unregister(struct watchdog_device *);
+extern void watchdog_dev_unregister(struct watchdog_device *);
extern int __init watchdog_dev_init(void);
extern void __exit watchdog_dev_exit(void);
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 56a649e66eb2..ba2ecce4aae6 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -32,27 +32,51 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h> /* For module stuff/... */
-#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/cdev.h> /* For character device */
#include <linux/errno.h> /* For the -ENODEV/... values */
-#include <linux/kernel.h> /* For printk/panic/... */
#include <linux/fs.h> /* For file operations */
-#include <linux/watchdog.h> /* For watchdog specific items */
-#include <linux/miscdevice.h> /* For handling misc devices */
#include <linux/init.h> /* For __init/__exit/... */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/kref.h> /* For data references */
+#include <linux/miscdevice.h> /* For handling misc devices */
+#include <linux/module.h> /* For module stuff/... */
+#include <linux/mutex.h> /* For mutexes */
+#include <linux/slab.h> /* For memory functions */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/watchdog.h> /* For watchdog specific items */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include "watchdog_core.h"
+/*
+ * struct watchdog_core_data - watchdog core internal data
+ * @kref: Reference count.
+ * @cdev: The watchdog's Character device.
+ * @wdd: Pointer to watchdog device.
+ * @lock: Lock for watchdog core.
+ * @status: Watchdog core internal status bits.
+ */
+struct watchdog_core_data {
+ struct kref kref;
+ struct cdev cdev;
+ struct watchdog_device *wdd;
+ struct mutex lock;
+ unsigned long status; /* Internal status bits */
+#define _WDOG_DEV_OPEN 0 /* Opened ? */
+#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */
+};
+
/* the dev_t structure to store the dynamically allocated watchdog devices */
static dev_t watchdog_devt;
-/* the watchdog device behind /dev/watchdog */
-static struct watchdog_device *old_wdd;
+/* Reference to watchdog device behind /dev/watchdog */
+static struct watchdog_core_data *old_wd_data;
/*
* watchdog_ping: ping the watchdog.
* @wdd: the watchdog device to ping
*
+ * The caller must hold wd_data->lock.
+ *
* If the watchdog has no own ping operation then it needs to be
* restarted via the start operation. This wrapper function does
* exactly that.
@@ -61,25 +85,16 @@ static struct watchdog_device *old_wdd;
static int watchdog_ping(struct watchdog_device *wdd)
{
- int err = 0;
-
- mutex_lock(&wdd->lock);
-
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_ping;
- }
+ int err;
if (!watchdog_active(wdd))
- goto out_ping;
+ return 0;
if (wdd->ops->ping)
err = wdd->ops->ping(wdd); /* ping the watchdog */
else
err = wdd->ops->start(wdd); /* restart watchdog */
-out_ping:
- mutex_unlock(&wdd->lock);
return err;
}
@@ -87,6 +102,8 @@ out_ping:
* watchdog_start: wrapper to start the watchdog.
* @wdd: the watchdog device to start
*
+ * The caller must hold wd_data->lock.
+ *
* Start the watchdog if it is not active and mark it active.
* This function returns zero on success or a negative errno code for
* failure.
@@ -94,24 +111,15 @@ out_ping:
static int watchdog_start(struct watchdog_device *wdd)
{
- int err = 0;
-
- mutex_lock(&wdd->lock);
-
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_start;
- }
+ int err;
if (watchdog_active(wdd))
- goto out_start;
+ return 0;
err = wdd->ops->start(wdd);
if (err == 0)
set_bit(WDOG_ACTIVE, &wdd->status);
-out_start:
- mutex_unlock(&wdd->lock);
return err;
}
@@ -119,6 +127,8 @@ out_start:
* watchdog_stop: wrapper to stop the watchdog.
* @wdd: the watchdog device to stop
*
+ * The caller must hold wd_data->lock.
+ *
* Stop the watchdog if it is still active and unmark it active.
* This function returns zero on success or a negative errno code for
* failure.
@@ -127,93 +137,59 @@ out_start:
static int watchdog_stop(struct watchdog_device *wdd)
{
- int err = 0;
-
- mutex_lock(&wdd->lock);
-
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_stop;
- }
+ int err;
if (!watchdog_active(wdd))
- goto out_stop;
+ return 0;
if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
- dev_info(wdd->dev, "nowayout prevents watchdog being stopped!\n");
- err = -EBUSY;
- goto out_stop;
+ pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n",
+ wdd->id);
+ return -EBUSY;
}
err = wdd->ops->stop(wdd);
if (err == 0)
clear_bit(WDOG_ACTIVE, &wdd->status);
-out_stop:
- mutex_unlock(&wdd->lock);
return err;
}
/*
* watchdog_get_status: wrapper to get the watchdog status
* @wdd: the watchdog device to get the status from
- * @status: the status of the watchdog device
+ *
+ * The caller must hold wd_data->lock.
*
* Get the watchdog's status flags.
*/
-static int watchdog_get_status(struct watchdog_device *wdd,
- unsigned int *status)
+static unsigned int watchdog_get_status(struct watchdog_device *wdd)
{
- int err = 0;
-
- *status = 0;
if (!wdd->ops->status)
- return -EOPNOTSUPP;
-
- mutex_lock(&wdd->lock);
-
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_status;
- }
-
- *status = wdd->ops->status(wdd);
+ return 0;
-out_status:
- mutex_unlock(&wdd->lock);
- return err;
+ return wdd->ops->status(wdd);
}
/*
* watchdog_set_timeout: set the watchdog timer timeout
* @wdd: the watchdog device to set the timeout for
* @timeout: timeout to set in seconds
+ *
+ * The caller must hold wd_data->lock.
*/
static int watchdog_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
{
- int err;
-
if (!wdd->ops->set_timeout || !(wdd->info->options & WDIOF_SETTIMEOUT))
return -EOPNOTSUPP;
if (watchdog_timeout_invalid(wdd, timeout))
return -EINVAL;
- mutex_lock(&wdd->lock);
-
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_timeout;
- }
-
- err = wdd->ops->set_timeout(wdd, timeout);
-
-out_timeout:
- mutex_unlock(&wdd->lock);
- return err;
+ return wdd->ops->set_timeout(wdd, timeout);
}
/*
@@ -221,59 +197,156 @@ out_timeout:
* @wdd: the watchdog device to get the remaining time from
* @timeleft: the time that's left
*
+ * The caller must hold wd_data->lock.
+ *
* Get the time before a watchdog will reboot (if not pinged).
*/
static int watchdog_get_timeleft(struct watchdog_device *wdd,
unsigned int *timeleft)
{
- int err = 0;
-
*timeleft = 0;
+
if (!wdd->ops->get_timeleft)
return -EOPNOTSUPP;
- mutex_lock(&wdd->lock);
+ *timeleft = wdd->ops->get_timeleft(wdd);
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_timeleft;
- }
+ return 0;
+}
- *timeleft = wdd->ops->get_timeleft(wdd);
+#ifdef CONFIG_WATCHDOG_SYSFS
+static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
-out_timeleft:
- mutex_unlock(&wdd->lock);
- return err;
+ return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
+}
+static DEVICE_ATTR_RO(nowayout);
+
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+ struct watchdog_core_data *wd_data = wdd->wd_data;
+ unsigned int status;
+
+ mutex_lock(&wd_data->lock);
+ status = watchdog_get_status(wdd);
+ mutex_unlock(&wd_data->lock);
+
+ return sprintf(buf, "%u\n", status);
+}
+static DEVICE_ATTR_RO(status);
+
+static ssize_t bootstatus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", wdd->bootstatus);
+}
+static DEVICE_ATTR_RO(bootstatus);
+
+static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+ struct watchdog_core_data *wd_data = wdd->wd_data;
+ ssize_t status;
+ unsigned int val;
+
+ mutex_lock(&wd_data->lock);
+ status = watchdog_get_timeleft(wdd, &val);
+ mutex_unlock(&wd_data->lock);
+ if (!status)
+ status = sprintf(buf, "%u\n", val);
+
+ return status;
}
+static DEVICE_ATTR_RO(timeleft);
+
+static ssize_t timeout_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", wdd->timeout);
+}
+static DEVICE_ATTR_RO(timeout);
+
+static ssize_t identity_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", wdd->info->identity);
+}
+static DEVICE_ATTR_RO(identity);
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ if (watchdog_active(wdd))
+ return sprintf(buf, "active\n");
+
+ return sprintf(buf, "inactive\n");
+}
+static DEVICE_ATTR_RO(state);
+
+static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr,
+ int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+ umode_t mode = attr->mode;
+
+ if (attr == &dev_attr_status.attr && !wdd->ops->status)
+ mode = 0;
+ else if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft)
+ mode = 0;
+
+ return mode;
+}
+static struct attribute *wdt_attrs[] = {
+ &dev_attr_state.attr,
+ &dev_attr_identity.attr,
+ &dev_attr_timeout.attr,
+ &dev_attr_timeleft.attr,
+ &dev_attr_bootstatus.attr,
+ &dev_attr_status.attr,
+ &dev_attr_nowayout.attr,
+ NULL,
+};
+
+static const struct attribute_group wdt_group = {
+ .attrs = wdt_attrs,
+ .is_visible = wdt_is_visible,
+};
+__ATTRIBUTE_GROUPS(wdt);
+#else
+#define wdt_groups NULL
+#endif
/*
* watchdog_ioctl_op: call the watchdog drivers ioctl op if defined
* @wdd: the watchdog device to do the ioctl on
* @cmd: watchdog command
* @arg: argument pointer
+ *
+ * The caller must hold wd_data->lock.
*/
static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
unsigned long arg)
{
- int err;
-
if (!wdd->ops->ioctl)
return -ENOIOCTLCMD;
- mutex_lock(&wdd->lock);
-
- if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
- err = -ENODEV;
- goto out_ioctl;
- }
-
- err = wdd->ops->ioctl(wdd, cmd, arg);
-
-out_ioctl:
- mutex_unlock(&wdd->lock);
- return err;
+ return wdd->ops->ioctl(wdd, cmd, arg);
}
/*
@@ -291,10 +364,11 @@ out_ioctl:
static ssize_t watchdog_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
- struct watchdog_device *wdd = file->private_data;
+ struct watchdog_core_data *wd_data = file->private_data;
+ struct watchdog_device *wdd;
+ int err;
size_t i;
char c;
- int err;
if (len == 0)
return 0;
@@ -303,18 +377,25 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
* Note: just in case someone wrote the magic character
* five months ago...
*/
- clear_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+ clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
/* scan to see whether or not we got the magic character */
for (i = 0; i != len; i++) {
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
- set_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+ set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
}
/* someone wrote to us, so we send the watchdog a keepalive ping */
- err = watchdog_ping(wdd);
+
+ err = -ENODEV;
+ mutex_lock(&wd_data->lock);
+ wdd = wd_data->wdd;
+ if (wdd)
+ err = watchdog_ping(wdd);
+ mutex_unlock(&wd_data->lock);
+
if (err < 0)
return err;
@@ -334,71 +415,94 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
static long watchdog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct watchdog_device *wdd = file->private_data;
+ struct watchdog_core_data *wd_data = file->private_data;
void __user *argp = (void __user *)arg;
+ struct watchdog_device *wdd;
int __user *p = argp;
unsigned int val;
int err;
+ mutex_lock(&wd_data->lock);
+
+ wdd = wd_data->wdd;
+ if (!wdd) {
+ err = -ENODEV;
+ goto out_ioctl;
+ }
+
err = watchdog_ioctl_op(wdd, cmd, arg);
if (err != -ENOIOCTLCMD)
- return err;
+ goto out_ioctl;
switch (cmd) {
case WDIOC_GETSUPPORT:
- return copy_to_user(argp, wdd->info,
+ err = copy_to_user(argp, wdd->info,
sizeof(struct watchdog_info)) ? -EFAULT : 0;
+ break;
case WDIOC_GETSTATUS:
- err = watchdog_get_status(wdd, &val);
- if (err == -ENODEV)
- return err;
- return put_user(val, p);
+ val = watchdog_get_status(wdd);
+ err = put_user(val, p);
+ break;
case WDIOC_GETBOOTSTATUS:
- return put_user(wdd->bootstatus, p);
+ err = put_user(wdd->bootstatus, p);
+ break;
case WDIOC_SETOPTIONS:
- if (get_user(val, p))
- return -EFAULT;
+ if (get_user(val, p)) {
+ err = -EFAULT;
+ break;
+ }
if (val & WDIOS_DISABLECARD) {
err = watchdog_stop(wdd);
if (err < 0)
- return err;
+ break;
}
- if (val & WDIOS_ENABLECARD) {
+ if (val & WDIOS_ENABLECARD)
err = watchdog_start(wdd);
- if (err < 0)
- return err;
- }
- return 0;
+ break;
case WDIOC_KEEPALIVE:
- if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
- return -EOPNOTSUPP;
- return watchdog_ping(wdd);
+ if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) {
+ err = -EOPNOTSUPP;
+ break;
+ }
+ err = watchdog_ping(wdd);
+ break;
case WDIOC_SETTIMEOUT:
- if (get_user(val, p))
- return -EFAULT;
+ if (get_user(val, p)) {
+ err = -EFAULT;
+ break;
+ }
err = watchdog_set_timeout(wdd, val);
if (err < 0)
- return err;
+ break;
/* If the watchdog is active then we send a keepalive ping
* to make sure that the watchdog keep's running (and if
* possible that it takes the new timeout) */
err = watchdog_ping(wdd);
if (err < 0)
- return err;
+ break;
/* Fall */
case WDIOC_GETTIMEOUT:
/* timeout == 0 means that we don't know the timeout */
- if (wdd->timeout == 0)
- return -EOPNOTSUPP;
- return put_user(wdd->timeout, p);
+ if (wdd->timeout == 0) {
+ err = -EOPNOTSUPP;
+ break;
+ }
+ err = put_user(wdd->timeout, p);
+ break;
case WDIOC_GETTIMELEFT:
err = watchdog_get_timeleft(wdd, &val);
- if (err)
- return err;
- return put_user(val, p);
+ if (err < 0)
+ break;
+ err = put_user(val, p);
+ break;
default:
- return -ENOTTY;
+ err = -ENOTTY;
+ break;
}
+
+out_ioctl:
+ mutex_unlock(&wd_data->lock);
+ return err;
}
/*
@@ -413,45 +517,59 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
static int watchdog_open(struct inode *inode, struct file *file)
{
- int err = -EBUSY;
+ struct watchdog_core_data *wd_data;
struct watchdog_device *wdd;
+ int err;
/* Get the corresponding watchdog device */
if (imajor(inode) == MISC_MAJOR)
- wdd = old_wdd;
+ wd_data = old_wd_data;
else
- wdd = container_of(inode->i_cdev, struct watchdog_device, cdev);
+ wd_data = container_of(inode->i_cdev, struct watchdog_core_data,
+ cdev);
/* the watchdog is single open! */
- if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
+ if (test_and_set_bit(_WDOG_DEV_OPEN, &wd_data->status))
return -EBUSY;
+ wdd = wd_data->wdd;
+
/*
* If the /dev/watchdog device is open, we don't want the module
* to be unloaded.
*/
- if (!try_module_get(wdd->ops->owner))
- goto out;
+ if (!try_module_get(wdd->ops->owner)) {
+ err = -EBUSY;
+ goto out_clear;
+ }
err = watchdog_start(wdd);
if (err < 0)
goto out_mod;
- file->private_data = wdd;
+ file->private_data = wd_data;
- if (wdd->ops->ref)
- wdd->ops->ref(wdd);
+ kref_get(&wd_data->kref);
/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
return nonseekable_open(inode, file);
out_mod:
- module_put(wdd->ops->owner);
-out:
- clear_bit(WDOG_DEV_OPEN, &wdd->status);
+ module_put(wd_data->wdd->ops->owner);
+out_clear:
+ clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
return err;
}
+static void watchdog_core_data_release(struct kref *kref)
+{
+ struct watchdog_core_data *wd_data;
+
+ wd_data = container_of(kref, struct watchdog_core_data, kref);
+
+ kfree(wd_data);
+}
+
/*
* watchdog_release: release the watchdog device.
* @inode: inode of device
@@ -464,9 +582,16 @@ out:
static int watchdog_release(struct inode *inode, struct file *file)
{
- struct watchdog_device *wdd = file->private_data;
+ struct watchdog_core_data *wd_data = file->private_data;
+ struct watchdog_device *wdd;
int err = -EBUSY;
+ mutex_lock(&wd_data->lock);
+
+ wdd = wd_data->wdd;
+ if (!wdd)
+ goto done;
+
/*
* We only stop the watchdog if we received the magic character
* or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
@@ -474,29 +599,24 @@ static int watchdog_release(struct inode *inode, struct file *file)
*/
if (!test_bit(WDOG_ACTIVE, &wdd->status))
err = 0;
- else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
+ else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) ||
!(wdd->info->options & WDIOF_MAGICCLOSE))
err = watchdog_stop(wdd);
/* If the watchdog was not stopped, send a keepalive ping */
if (err < 0) {
- mutex_lock(&wdd->lock);
- if (!test_bit(WDOG_UNREGISTERED, &wdd->status))
- dev_crit(wdd->dev, "watchdog did not stop!\n");
- mutex_unlock(&wdd->lock);
+ pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id);
watchdog_ping(wdd);
}
- /* Allow the owner module to be unloaded again */
- module_put(wdd->ops->owner);
-
/* make sure that /dev/watchdog can be re-opened */
- clear_bit(WDOG_DEV_OPEN, &wdd->status);
-
- /* Note wdd may be gone after this, do not use after this! */
- if (wdd->ops->unref)
- wdd->ops->unref(wdd);
+ clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
+done:
+ mutex_unlock(&wd_data->lock);
+ /* Allow the owner module to be unloaded again */
+ module_put(wd_data->cdev.owner);
+ kref_put(&wd_data->kref, watchdog_core_data_release);
return 0;
}
@@ -515,20 +635,31 @@ static struct miscdevice watchdog_miscdev = {
};
/*
- * watchdog_dev_register: register a watchdog device
+ * watchdog_cdev_register: register watchdog character device
* @wdd: watchdog device
+ * @devno: character device number
*
- * Register a watchdog device including handling the legacy
+ * Register a watchdog character device including handling the legacy
* /dev/watchdog node. /dev/watchdog is actually a miscdevice and
* thus we set it up like that.
*/
-int watchdog_dev_register(struct watchdog_device *wdd)
+static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
{
- int err, devno;
+ struct watchdog_core_data *wd_data;
+ int err;
+
+ wd_data = kzalloc(sizeof(struct watchdog_core_data), GFP_KERNEL);
+ if (!wd_data)
+ return -ENOMEM;
+ kref_init(&wd_data->kref);
+ mutex_init(&wd_data->lock);
+
+ wd_data->wdd = wdd;
+ wdd->wd_data = wd_data;
if (wdd->id == 0) {
- old_wdd = wdd;
+ old_wd_data = wd_data;
watchdog_miscdev.parent = wdd->parent;
err = misc_register(&watchdog_miscdev);
if (err != 0) {
@@ -537,48 +668,106 @@ int watchdog_dev_register(struct watchdog_device *wdd)
if (err == -EBUSY)
pr_err("%s: a legacy watchdog module is probably present.\n",
wdd->info->identity);
- old_wdd = NULL;
+ old_wd_data = NULL;
+ kfree(wd_data);
return err;
}
}
/* Fill in the data structures */
- devno = MKDEV(MAJOR(watchdog_devt), wdd->id);
- cdev_init(&wdd->cdev, &watchdog_fops);
- wdd->cdev.owner = wdd->ops->owner;
+ cdev_init(&wd_data->cdev, &watchdog_fops);
+ wd_data->cdev.owner = wdd->ops->owner;
/* Add the device */
- err = cdev_add(&wdd->cdev, devno, 1);
+ err = cdev_add(&wd_data->cdev, devno, 1);
if (err) {
pr_err("watchdog%d unable to add device %d:%d\n",
wdd->id, MAJOR(watchdog_devt), wdd->id);
if (wdd->id == 0) {
misc_deregister(&watchdog_miscdev);
- old_wdd = NULL;
+ old_wd_data = NULL;
+ kref_put(&wd_data->kref, watchdog_core_data_release);
}
}
return err;
}
/*
- * watchdog_dev_unregister: unregister a watchdog device
+ * watchdog_cdev_unregister: unregister watchdog character device
* @watchdog: watchdog device
*
- * Unregister the watchdog and if needed the legacy /dev/watchdog device.
+ * Unregister watchdog character device and if needed the legacy
+ * /dev/watchdog device.
*/
-int watchdog_dev_unregister(struct watchdog_device *wdd)
+static void watchdog_cdev_unregister(struct watchdog_device *wdd)
{
- mutex_lock(&wdd->lock);
- set_bit(WDOG_UNREGISTERED, &wdd->status);
- mutex_unlock(&wdd->lock);
+ struct watchdog_core_data *wd_data = wdd->wd_data;
- cdev_del(&wdd->cdev);
+ cdev_del(&wd_data->cdev);
if (wdd->id == 0) {
misc_deregister(&watchdog_miscdev);
- old_wdd = NULL;
+ old_wd_data = NULL;
}
- return 0;
+
+ mutex_lock(&wd_data->lock);
+ wd_data->wdd = NULL;
+ wdd->wd_data = NULL;
+ mutex_unlock(&wd_data->lock);
+
+ kref_put(&wd_data->kref, watchdog_core_data_release);
+}
+
+static struct class watchdog_class = {
+ .name = "watchdog",
+ .owner = THIS_MODULE,
+ .dev_groups = wdt_groups,
+};
+
+/*
+ * watchdog_dev_register: register a watchdog device
+ * @wdd: watchdog device
+ *
+ * Register a watchdog device including handling the legacy
+ * /dev/watchdog node. /dev/watchdog is actually a miscdevice and
+ * thus we set it up like that.
+ */
+
+int watchdog_dev_register(struct watchdog_device *wdd)
+{
+ struct device *dev;
+ dev_t devno;
+ int ret;
+
+ devno = MKDEV(MAJOR(watchdog_devt), wdd->id);
+
+ ret = watchdog_cdev_register(wdd, devno);
+ if (ret)
+ return ret;
+
+ dev = device_create_with_groups(&watchdog_class, wdd->parent,
+ devno, wdd, wdd->groups,
+ "watchdog%d", wdd->id);
+ if (IS_ERR(dev)) {
+ watchdog_cdev_unregister(wdd);
+ return PTR_ERR(dev);
+ }
+
+ return ret;
+}
+
+/*
+ * watchdog_dev_unregister: unregister a watchdog device
+ * @watchdog: watchdog device
+ *
+ * Unregister watchdog device and if needed the legacy
+ * /dev/watchdog device.
+ */
+
+void watchdog_dev_unregister(struct watchdog_device *wdd)
+{
+ device_destroy(&watchdog_class, wdd->wd_data->cdev.dev);
+ watchdog_cdev_unregister(wdd);
}
/*
@@ -589,10 +778,22 @@ int watchdog_dev_unregister(struct watchdog_device *wdd)
int __init watchdog_dev_init(void)
{
- int err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
- if (err < 0)
+ int err;
+
+ err = class_register(&watchdog_class);
+ if (err < 0) {
+ pr_err("couldn't register class\n");
+ return err;
+ }
+
+ err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
+ if (err < 0) {
pr_err("watchdog: unable to allocate char dev region\n");
- return err;
+ class_unregister(&watchdog_class);
+ return err;
+ }
+
+ return 0;
}
/*
@@ -604,4 +805,5 @@ int __init watchdog_dev_init(void)
void __exit watchdog_dev_exit(void)
{
unregister_chrdev_region(watchdog_devt, MAX_DOGS);
+ class_unregister(&watchdog_class);
}
diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c
new file mode 100644
index 000000000000..0c7cb7302cf0
--- /dev/null
+++ b/drivers/watchdog/ziirave_wdt.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2015 Zodiac Inflight Innovations
+ *
+ * Author: Martyn Welch <martyn.welch@collabora.co.uk>
+ *
+ * Based on twl4030_wdt.c by Timo Kokkonen <timo.t.kokkonen at nokia.com>:
+ *
+ * Copyright (C) Nokia 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.
+ *
+ * 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/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/watchdog.h>
+
+#define ZIIRAVE_TIMEOUT_MIN 3
+#define ZIIRAVE_TIMEOUT_MAX 255
+
+#define ZIIRAVE_PING_VALUE 0x0
+
+#define ZIIRAVE_STATE_INITIAL 0x0
+#define ZIIRAVE_STATE_OFF 0x1
+#define ZIIRAVE_STATE_ON 0x2
+
+static char *ziirave_reasons[] = {"power cycle", "triggered", NULL, NULL,
+ "host request", NULL, "illegal configuration",
+ "illegal instruction", "illegal trap",
+ "unknown"};
+
+#define ZIIRAVE_WDT_FIRM_VER_MAJOR 0x1
+#define ZIIRAVE_WDT_BOOT_VER_MAJOR 0x3
+#define ZIIRAVE_WDT_RESET_REASON 0x5
+#define ZIIRAVE_WDT_STATE 0x6
+#define ZIIRAVE_WDT_TIMEOUT 0x7
+#define ZIIRAVE_WDT_TIME_LEFT 0x8
+#define ZIIRAVE_WDT_PING 0x9
+#define ZIIRAVE_WDT_RESET_DURATION 0xa
+
+struct ziirave_wdt_rev {
+ unsigned char major;
+ unsigned char minor;
+};
+
+struct ziirave_wdt_data {
+ struct watchdog_device wdd;
+ struct ziirave_wdt_rev bootloader_rev;
+ struct ziirave_wdt_rev firmware_rev;
+ int reset_reason;
+};
+
+static int wdt_timeout;
+module_param(wdt_timeout, int, 0);
+MODULE_PARM_DESC(wdt_timeout, "Watchdog timeout in seconds");
+
+static int reset_duration;
+module_param(reset_duration, int, 0);
+MODULE_PARM_DESC(reset_duration,
+ "Watchdog reset pulse duration in milliseconds");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int ziirave_wdt_revision(struct i2c_client *client,
+ struct ziirave_wdt_rev *rev, u8 command)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, command);
+ if (ret < 0)
+ return ret;
+
+ rev->major = ret;
+
+ ret = i2c_smbus_read_byte_data(client, command + 1);
+ if (ret < 0)
+ return ret;
+
+ rev->minor = ret;
+
+ return 0;
+}
+
+static int ziirave_wdt_set_state(struct watchdog_device *wdd, int state)
+{
+ struct i2c_client *client = to_i2c_client(wdd->parent);
+
+ return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_STATE, state);
+}
+
+static int ziirave_wdt_start(struct watchdog_device *wdd)
+{
+ return ziirave_wdt_set_state(wdd, ZIIRAVE_STATE_ON);
+}
+
+static int ziirave_wdt_stop(struct watchdog_device *wdd)
+{
+ return ziirave_wdt_set_state(wdd, ZIIRAVE_STATE_OFF);
+}
+
+static int ziirave_wdt_ping(struct watchdog_device *wdd)
+{
+ struct i2c_client *client = to_i2c_client(wdd->parent);
+
+ return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_PING,
+ ZIIRAVE_PING_VALUE);
+}
+
+static int ziirave_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ struct i2c_client *client = to_i2c_client(wdd->parent);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_TIMEOUT, timeout);
+ if (!ret)
+ wdd->timeout = timeout;
+
+ return ret;
+}
+
+static unsigned int ziirave_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+ struct i2c_client *client = to_i2c_client(wdd->parent);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIME_LEFT);
+ if (ret < 0)
+ ret = 0;
+
+ return ret;
+}
+
+static const struct watchdog_info ziirave_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "Zodiac RAVE Watchdog",
+};
+
+static const struct watchdog_ops ziirave_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = ziirave_wdt_start,
+ .stop = ziirave_wdt_stop,
+ .ping = ziirave_wdt_ping,
+ .set_timeout = ziirave_wdt_set_timeout,
+ .get_timeleft = ziirave_wdt_get_timeleft,
+};
+
+static ssize_t ziirave_wdt_sysfs_show_firm(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+ return sprintf(buf, "02.%02u.%02u", w_priv->firmware_rev.major,
+ w_priv->firmware_rev.minor);
+}
+
+static DEVICE_ATTR(firmware_version, S_IRUGO, ziirave_wdt_sysfs_show_firm,
+ NULL);
+
+static ssize_t ziirave_wdt_sysfs_show_boot(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+ return sprintf(buf, "01.%02u.%02u", w_priv->bootloader_rev.major,
+ w_priv->bootloader_rev.minor);
+}
+
+static DEVICE_ATTR(bootloader_version, S_IRUGO, ziirave_wdt_sysfs_show_boot,
+ NULL);
+
+static ssize_t ziirave_wdt_sysfs_show_reason(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]);
+}
+
+static DEVICE_ATTR(reset_reason, S_IRUGO, ziirave_wdt_sysfs_show_reason,
+ NULL);
+
+static struct attribute *ziirave_wdt_attrs[] = {
+ &dev_attr_firmware_version.attr,
+ &dev_attr_bootloader_version.attr,
+ &dev_attr_reset_reason.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(ziirave_wdt);
+
+static int ziirave_wdt_init_duration(struct i2c_client *client)
+{
+ int ret;
+
+ if (!reset_duration) {
+ /* See if the reset pulse duration is provided in an of_node */
+ if (!client->dev.of_node)
+ ret = -ENODEV;
+ else
+ ret = of_property_read_u32(client->dev.of_node,
+ "reset-duration-ms",
+ &reset_duration);
+ if (ret) {
+ dev_info(&client->dev,
+ "Unable to set reset pulse duration, using default\n");
+ return 0;
+ }
+ }
+
+ if (reset_duration < 1 || reset_duration > 255)
+ return -EINVAL;
+
+ dev_info(&client->dev, "Setting reset duration to %dms",
+ reset_duration);
+
+ return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_RESET_DURATION,
+ reset_duration);
+}
+
+static int ziirave_wdt_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct ziirave_wdt_data *w_priv;
+ int val;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ w_priv = devm_kzalloc(&client->dev, sizeof(*w_priv), GFP_KERNEL);
+ if (!w_priv)
+ return -ENOMEM;
+
+ w_priv->wdd.info = &ziirave_wdt_info;
+ w_priv->wdd.ops = &ziirave_wdt_ops;
+ w_priv->wdd.min_timeout = ZIIRAVE_TIMEOUT_MIN;
+ w_priv->wdd.max_timeout = ZIIRAVE_TIMEOUT_MAX;
+ w_priv->wdd.parent = &client->dev;
+ w_priv->wdd.groups = ziirave_wdt_groups;
+
+ ret = watchdog_init_timeout(&w_priv->wdd, wdt_timeout, &client->dev);
+ if (ret) {
+ dev_info(&client->dev,
+ "Unable to select timeout value, using default\n");
+ }
+
+ /*
+ * The default value set in the watchdog should be perfectly valid, so
+ * pass that in if we haven't provided one via the module parameter or
+ * of property.
+ */
+ if (w_priv->wdd.timeout == 0) {
+ val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIMEOUT);
+ if (val < 0)
+ return val;
+
+ if (val < ZIIRAVE_TIMEOUT_MIN)
+ return -ENODEV;
+
+ w_priv->wdd.timeout = val;
+ } else {
+ ret = ziirave_wdt_set_timeout(&w_priv->wdd,
+ w_priv->wdd.timeout);
+ if (ret)
+ return ret;
+
+ dev_info(&client->dev, "Timeout set to %ds.",
+ w_priv->wdd.timeout);
+ }
+
+ watchdog_set_nowayout(&w_priv->wdd, nowayout);
+
+ i2c_set_clientdata(client, w_priv);
+
+ /* If in unconfigured state, set to stopped */
+ val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_STATE);
+ if (val < 0)
+ return val;
+
+ if (val == ZIIRAVE_STATE_INITIAL)
+ ziirave_wdt_stop(&w_priv->wdd);
+
+ ret = ziirave_wdt_init_duration(client);
+ if (ret)
+ return ret;
+
+ ret = ziirave_wdt_revision(client, &w_priv->firmware_rev,
+ ZIIRAVE_WDT_FIRM_VER_MAJOR);
+ if (ret)
+ return ret;
+
+ ret = ziirave_wdt_revision(client, &w_priv->bootloader_rev,
+ ZIIRAVE_WDT_BOOT_VER_MAJOR);
+ if (ret)
+ return ret;
+
+ w_priv->reset_reason = i2c_smbus_read_byte_data(client,
+ ZIIRAVE_WDT_RESET_REASON);
+ if (w_priv->reset_reason < 0)
+ return w_priv->reset_reason;
+
+ if (w_priv->reset_reason >= ARRAY_SIZE(ziirave_reasons) ||
+ !ziirave_reasons[w_priv->reset_reason])
+ return -ENODEV;
+
+ ret = watchdog_register_device(&w_priv->wdd);
+
+ return ret;
+}
+
+static int ziirave_wdt_remove(struct i2c_client *client)
+{
+ struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+ watchdog_unregister_device(&w_priv->wdd);
+
+ return 0;
+}
+
+static struct i2c_device_id ziirave_wdt_id[] = {
+ { "ziirave-wdt", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ziirave_wdt_id);
+
+static const struct of_device_id zrv_wdt_of_match[] = {
+ { .compatible = "zii,rave-wdt", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, zrv_wdt_of_match);
+
+static struct i2c_driver ziirave_wdt_driver = {
+ .driver = {
+ .name = "ziirave_wdt",
+ .of_match_table = zrv_wdt_of_match,
+ },
+ .probe = ziirave_wdt_probe,
+ .remove = ziirave_wdt_remove,
+ .id_table = ziirave_wdt_id,
+};
+
+module_i2c_driver(ziirave_wdt_driver);
+
+MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk");
+MODULE_DESCRIPTION("Zodiac Aerospace RAVE Switch Watchdog Processor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c
index 96a1b8da5371..eff2b88003d9 100644
--- a/drivers/xen/events/events_fifo.c
+++ b/drivers/xen/events/events_fifo.c
@@ -41,6 +41,7 @@
#include <linux/percpu.h>
#include <linux/cpu.h>
+#include <asm/barrier.h>
#include <asm/sync_bitops.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
@@ -296,7 +297,7 @@ static void consume_one_event(unsigned cpu,
* control block.
*/
if (head == 0) {
- rmb(); /* Ensure word is up-to-date before reading head. */
+ virt_rmb(); /* Ensure word is up-to-date before reading head. */
head = control_block->head[priority];
}
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
index fdb0f339d0a7..ecdecce80a6c 100644
--- a/drivers/xen/xenbus/xenbus_comms.c
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -123,14 +123,14 @@ int xb_write(const void *data, unsigned len)
avail = len;
/* Must write data /after/ reading the consumer index. */
- mb();
+ virt_mb();
memcpy(dst, data, avail);
data += avail;
len -= avail;
/* Other side must not see new producer until data is there. */
- wmb();
+ virt_wmb();
intf->req_prod += avail;
/* Implies mb(): other side will see the updated producer. */
@@ -180,14 +180,14 @@ int xb_read(void *data, unsigned len)
avail = len;
/* Must read data /after/ reading the producer index. */
- rmb();
+ virt_rmb();
memcpy(data, src, avail);
data += avail;
len -= avail;
/* Other side must not see free space until we've copied out */
- mb();
+ virt_mb();
intf->rsp_cons += avail;
pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 6caca025019d..072e7599583a 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -575,7 +575,7 @@ static int v9fs_init_inode_cache(void)
v9fs_inode_cache = kmem_cache_create("v9fs_inode_cache",
sizeof(struct v9fs_inode),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
v9fs_inode_init_once);
if (!v9fs_inode_cache)
return -ENOMEM;
diff --git a/fs/Kconfig b/fs/Kconfig
index 2bb1ef86c411..9adee0d7536e 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -50,7 +50,8 @@ config FS_DAX_PMD
bool
default FS_DAX
depends on FS_DAX
- depends on BROKEN
+ depends on ZONE_DEVICE
+ depends on TRANSPARENT_HUGEPAGE
endif # BLOCK
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 4d4a0df8344f..c9fdfb112933 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -271,7 +271,7 @@ static int __init init_inodecache(void)
adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
sizeof(struct adfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (adfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 8836df5f1e11..2a6713b6b9f4 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -132,7 +132,7 @@ static int __init init_inodecache(void)
affs_inode_cachep = kmem_cache_create("affs_inode_cache",
sizeof(struct affs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (affs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 1fb4a5129f7d..81afefe7d8a6 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -91,7 +91,7 @@ int __init afs_fs_init(void)
afs_inode_cachep = kmem_cache_create("afs_inode_cache",
sizeof(struct afs_vnode),
0,
- SLAB_HWCACHE_ALIGN,
+ SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT,
afs_i_init_once);
if (!afs_inode_cachep) {
printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n");
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 25250fa87086..cc0e08252913 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -434,7 +434,7 @@ befs_init_inodecache(void)
befs_inode_cachep = kmem_cache_create("befs_inode_cache",
sizeof (struct befs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (befs_inode_cachep == NULL) {
pr_err("%s: Couldn't initialize inode slabcache\n", __func__);
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index fdcb4d69f430..1e5c896f6b79 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -270,7 +270,7 @@ static int __init init_inodecache(void)
bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
sizeof(struct bfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (bfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 01b8e0d4b4ff..ba762ea07f67 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -156,11 +156,16 @@ blkdev_get_block(struct inode *inode, sector_t iblock,
return 0;
}
+static struct inode *bdev_file_inode(struct file *file)
+{
+ return file->f_mapping->host;
+}
+
static ssize_t
blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_mapping->host;
+ struct inode *inode = bdev_file_inode(file);
if (IS_DAX(inode))
return dax_do_io(iocb, inode, iter, offset, blkdev_get_block,
@@ -338,7 +343,7 @@ static int blkdev_write_end(struct file *file, struct address_space *mapping,
*/
static loff_t block_llseek(struct file *file, loff_t offset, int whence)
{
- struct inode *bd_inode = file->f_mapping->host;
+ struct inode *bd_inode = bdev_file_inode(file);
loff_t retval;
mutex_lock(&bd_inode->i_mutex);
@@ -349,7 +354,7 @@ static loff_t block_llseek(struct file *file, loff_t offset, int whence)
int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
{
- struct inode *bd_inode = filp->f_mapping->host;
+ struct inode *bd_inode = bdev_file_inode(filp);
struct block_device *bdev = I_BDEV(bd_inode);
int error;
@@ -395,7 +400,7 @@ int bdev_read_page(struct block_device *bdev, sector_t sector,
if (!ops->rw_page || bdev_get_integrity(bdev))
return result;
- result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+ result = blk_queue_enter(bdev->bd_queue, false);
if (result)
return result;
result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
@@ -432,7 +437,7 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
if (!ops->rw_page || bdev_get_integrity(bdev))
return -EOPNOTSUPP;
- result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+ result = blk_queue_enter(bdev->bd_queue, false);
if (result)
return result;
@@ -450,10 +455,7 @@ EXPORT_SYMBOL_GPL(bdev_write_page);
/**
* bdev_direct_access() - Get the address for directly-accessibly memory
* @bdev: The device containing the memory
- * @sector: The offset within the device
- * @addr: Where to put the address of the memory
- * @pfn: The Page Frame Number for the memory
- * @size: The number of bytes requested
+ * @dax: control and output parameters for ->direct_access
*
* If a block device is made up of directly addressable memory, this function
* will tell the caller the PFN and the address of the memory. The address
@@ -464,10 +466,10 @@ EXPORT_SYMBOL_GPL(bdev_write_page);
* Return: negative errno if an error occurs, otherwise the number of bytes
* accessible at this address.
*/
-long bdev_direct_access(struct block_device *bdev, sector_t sector,
- void __pmem **addr, unsigned long *pfn, long size)
+long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax)
{
- long avail;
+ sector_t sector = dax->sector;
+ long avail, size = dax->size;
const struct block_device_operations *ops = bdev->bd_disk->fops;
/*
@@ -486,9 +488,11 @@ long bdev_direct_access(struct block_device *bdev, sector_t sector,
sector += get_start_sect(bdev);
if (sector % (PAGE_SIZE / 512))
return -EINVAL;
- avail = ops->direct_access(bdev, sector, addr, pfn);
+ avail = ops->direct_access(bdev, sector, &dax->addr, &dax->pfn);
if (!avail)
return -ERANGE;
+ if (avail > 0 && avail & ~PAGE_MASK)
+ return -ENXIO;
return min(avail, size);
}
EXPORT_SYMBOL_GPL(bdev_direct_access);
@@ -590,7 +594,7 @@ void __init bdev_cache_init(void)
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD|SLAB_PANIC),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT|SLAB_PANIC),
init_once);
err = register_filesystem(&bd_type);
if (err)
@@ -696,7 +700,7 @@ static struct block_device *bd_acquire(struct inode *inode)
spin_lock(&bdev_lock);
bdev = inode->i_bdev;
if (bdev) {
- ihold(bdev->bd_inode);
+ bdgrab(bdev);
spin_unlock(&bdev_lock);
return bdev;
}
@@ -712,7 +716,7 @@ static struct block_device *bd_acquire(struct inode *inode)
* So, we can access it via ->i_mapping always
* without igrab().
*/
- ihold(bdev->bd_inode);
+ bdgrab(bdev);
inode->i_bdev = bdev;
inode->i_mapping = bdev->bd_inode->i_mapping;
list_add(&inode->i_devices, &bdev->bd_inodes);
@@ -735,7 +739,7 @@ void bd_forget(struct inode *inode)
spin_unlock(&bdev_lock);
if (bdev)
- iput(bdev->bd_inode);
+ bdput(bdev);
}
/**
@@ -1224,8 +1228,11 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
}
}
- if (!ret)
+ if (!ret) {
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
+ if (!blkdev_dax_capable(bdev))
+ bdev->bd_inode->i_flags &= ~S_DAX;
+ }
/*
* If the device is invalidated, rescan partition
@@ -1239,6 +1246,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
else if (ret == -ENOMEDIUM)
invalidate_partitions(disk, bdev);
}
+
if (ret)
goto out_clear;
} else {
@@ -1259,12 +1267,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
goto out_clear;
}
bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
- /*
- * If the partition is not aligned on a page
- * boundary, we can't do dax I/O to it.
- */
- if ((bdev->bd_part->start_sect % (PAGE_SIZE / 512)) ||
- (bdev->bd_part->nr_sects % (PAGE_SIZE / 512)))
+ if (!blkdev_dax_capable(bdev))
bdev->bd_inode->i_flags &= ~S_DAX;
}
} else {
@@ -1599,14 +1602,14 @@ EXPORT_SYMBOL(blkdev_put);
static int blkdev_close(struct inode * inode, struct file * filp)
{
- struct block_device *bdev = I_BDEV(filp->f_mapping->host);
+ struct block_device *bdev = I_BDEV(bdev_file_inode(filp));
blkdev_put(bdev, filp->f_mode);
return 0;
}
static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
- struct block_device *bdev = I_BDEV(file->f_mapping->host);
+ struct block_device *bdev = I_BDEV(bdev_file_inode(file));
fmode_t mode = file->f_mode;
/*
@@ -1631,7 +1634,7 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
- struct inode *bd_inode = file->f_mapping->host;
+ struct inode *bd_inode = bdev_file_inode(file);
loff_t size = i_size_read(bd_inode);
struct blk_plug plug;
ssize_t ret;
@@ -1663,7 +1666,7 @@ EXPORT_SYMBOL_GPL(blkdev_write_iter);
ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *file = iocb->ki_filp;
- struct inode *bd_inode = file->f_mapping->host;
+ struct inode *bd_inode = bdev_file_inode(file);
loff_t size = i_size_read(bd_inode);
loff_t pos = iocb->ki_pos;
@@ -1702,13 +1705,101 @@ static const struct address_space_operations def_blk_aops = {
.is_dirty_writeback = buffer_check_dirty_writeback,
};
+#ifdef CONFIG_FS_DAX
+/*
+ * In the raw block case we do not need to contend with truncation nor
+ * unwritten file extents. Without those concerns there is no need for
+ * additional locking beyond the mmap_sem context that these routines
+ * are already executing under.
+ *
+ * Note, there is no protection if the block device is dynamically
+ * resized (partition grow/shrink) during a fault. A stable block device
+ * size is already not enforced in the blkdev_direct_IO path.
+ *
+ * For DAX, it is the responsibility of the block device driver to
+ * ensure the whole-disk device size is stable while requests are in
+ * flight.
+ *
+ * Finally, unlike the filemap_page_mkwrite() case there is no
+ * filesystem superblock to sync against freezing. We still include a
+ * pfn_mkwrite callback for dax drivers to receive write fault
+ * notifications.
+ */
+static int blkdev_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ return __dax_fault(vma, vmf, blkdev_get_block, NULL);
+}
+
+static int blkdev_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd, unsigned int flags)
+{
+ return __dax_pmd_fault(vma, addr, pmd, flags, blkdev_get_block, NULL);
+}
+
+static void blkdev_vm_open(struct vm_area_struct *vma)
+{
+ struct inode *bd_inode = bdev_file_inode(vma->vm_file);
+ struct block_device *bdev = I_BDEV(bd_inode);
+
+ mutex_lock(&bd_inode->i_mutex);
+ bdev->bd_map_count++;
+ mutex_unlock(&bd_inode->i_mutex);
+}
+
+static void blkdev_vm_close(struct vm_area_struct *vma)
+{
+ struct inode *bd_inode = bdev_file_inode(vma->vm_file);
+ struct block_device *bdev = I_BDEV(bd_inode);
+
+ mutex_lock(&bd_inode->i_mutex);
+ bdev->bd_map_count--;
+ mutex_unlock(&bd_inode->i_mutex);
+}
+
+static const struct vm_operations_struct blkdev_dax_vm_ops = {
+ .open = blkdev_vm_open,
+ .close = blkdev_vm_close,
+ .fault = blkdev_dax_fault,
+ .pmd_fault = blkdev_dax_pmd_fault,
+ .pfn_mkwrite = blkdev_dax_fault,
+};
+
+static const struct vm_operations_struct blkdev_default_vm_ops = {
+ .open = blkdev_vm_open,
+ .close = blkdev_vm_close,
+ .fault = filemap_fault,
+ .map_pages = filemap_map_pages,
+};
+
+static int blkdev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct inode *bd_inode = bdev_file_inode(file);
+ struct block_device *bdev = I_BDEV(bd_inode);
+
+ file_accessed(file);
+ mutex_lock(&bd_inode->i_mutex);
+ bdev->bd_map_count++;
+ if (IS_DAX(bd_inode)) {
+ vma->vm_ops = &blkdev_dax_vm_ops;
+ vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE;
+ } else {
+ vma->vm_ops = &blkdev_default_vm_ops;
+ }
+ mutex_unlock(&bd_inode->i_mutex);
+
+ return 0;
+}
+#else
+#define blkdev_mmap generic_file_mmap
+#endif
+
const struct file_operations def_blk_fops = {
.open = blkdev_open,
.release = blkdev_close,
.llseek = block_llseek,
.read_iter = blkdev_read_iter,
.write_iter = blkdev_write_iter,
- .mmap = generic_file_mmap,
+ .mmap = blkdev_mmap,
.fsync = blkdev_fsync,
.unlocked_ioctl = block_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index 6d1d0b93b1aa..128ce17a80b0 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -9,11 +9,12 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
export.o tree-log.o free-space-cache.o zlib.o lzo.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
- uuid-tree.o props.o hash.o
+ uuid-tree.o props.o hash.o free-space-tree.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
tests/extent-buffer-tests.o tests/btrfs-tests.o \
- tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o
+ tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o \
+ tests/free-space-tree-tests.o
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index f89db0c21b51..6d263bb1621c 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -48,7 +48,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
size = __btrfs_getxattr(inode, name, "", 0);
if (size > 0) {
- value = kzalloc(size, GFP_NOFS);
+ value = kzalloc(size, GFP_KERNEL);
if (!value)
return ERR_PTR(-ENOMEM);
size = __btrfs_getxattr(inode, name, value, size);
@@ -102,7 +102,7 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
if (acl) {
size = posix_acl_xattr_size(acl->a_count);
- value = kmalloc(size, GFP_NOFS);
+ value = kmalloc(size, GFP_KERNEL);
if (!value) {
ret = -ENOMEM;
goto out;
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
index 3e36e4adc4a3..88d9af3d4581 100644
--- a/fs/btrfs/async-thread.c
+++ b/fs/btrfs/async-thread.c
@@ -97,7 +97,7 @@ static struct __btrfs_workqueue *
__btrfs_alloc_workqueue(const char *name, unsigned int flags, int limit_active,
int thresh)
{
- struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS);
+ struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL);
if (!ret)
return NULL;
@@ -148,7 +148,7 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
int limit_active,
int thresh)
{
- struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS);
+ struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL);
if (!ret)
return NULL;
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index d453d62ab0c6..08405a3da6b1 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -520,13 +520,10 @@ static inline int ref_for_same_block(struct __prelim_ref *ref1,
static int __add_missing_keys(struct btrfs_fs_info *fs_info,
struct list_head *head)
{
- struct list_head *pos;
+ struct __prelim_ref *ref;
struct extent_buffer *eb;
- list_for_each(pos, head) {
- struct __prelim_ref *ref;
- ref = list_entry(pos, struct __prelim_ref, list);
-
+ list_for_each_entry(ref, head, list) {
if (ref->parent)
continue;
if (ref->key_for_search.type)
@@ -563,23 +560,15 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
*/
static void __merge_refs(struct list_head *head, int mode)
{
- struct list_head *pos1;
+ struct __prelim_ref *ref1;
- list_for_each(pos1, head) {
- struct list_head *n2;
- struct list_head *pos2;
- struct __prelim_ref *ref1;
+ list_for_each_entry(ref1, head, list) {
+ struct __prelim_ref *ref2 = ref1, *tmp;
- ref1 = list_entry(pos1, struct __prelim_ref, list);
-
- for (pos2 = pos1->next, n2 = pos2->next; pos2 != head;
- pos2 = n2, n2 = pos2->next) {
- struct __prelim_ref *ref2;
+ list_for_each_entry_safe_continue(ref2, tmp, head, list) {
struct __prelim_ref *xchg;
struct extent_inode_elem *eie;
- ref2 = list_entry(pos2, struct __prelim_ref, list);
-
if (!ref_for_same_block(ref1, ref2))
continue;
if (mode == 1) {
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 0ef5cc13fae2..61205e3bbefa 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -192,6 +192,10 @@ struct btrfs_inode {
/* File creation time. */
struct timespec i_otime;
+ /* Hook into fs_info->delayed_iputs */
+ struct list_head delayed_iput;
+ long delayed_iput_count;
+
struct inode vfs_inode;
};
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 0340c57bf377..861d472564c1 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -531,13 +531,9 @@ static struct btrfsic_block *btrfsic_block_hashtable_lookup(
(((unsigned int)(dev_bytenr >> 16)) ^
((unsigned int)((uintptr_t)bdev))) &
(BTRFSIC_BLOCK_HASHTABLE_SIZE - 1);
- struct list_head *elem;
-
- list_for_each(elem, h->table + hashval) {
- struct btrfsic_block *const b =
- list_entry(elem, struct btrfsic_block,
- collision_resolving_node);
+ struct btrfsic_block *b;
+ list_for_each_entry(b, h->table + hashval, collision_resolving_node) {
if (b->dev_state->bdev == bdev && b->dev_bytenr == dev_bytenr)
return b;
}
@@ -588,13 +584,9 @@ static struct btrfsic_block_link *btrfsic_block_link_hashtable_lookup(
((unsigned int)((uintptr_t)bdev_ref_to)) ^
((unsigned int)((uintptr_t)bdev_ref_from))) &
(BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE - 1);
- struct list_head *elem;
-
- list_for_each(elem, h->table + hashval) {
- struct btrfsic_block_link *const l =
- list_entry(elem, struct btrfsic_block_link,
- collision_resolving_node);
+ struct btrfsic_block_link *l;
+ list_for_each_entry(l, h->table + hashval, collision_resolving_node) {
BUG_ON(NULL == l->block_ref_to);
BUG_ON(NULL == l->block_ref_from);
if (l->block_ref_to->dev_state->bdev == bdev_ref_to &&
@@ -639,13 +631,9 @@ static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup(
const unsigned int hashval =
(((unsigned int)((uintptr_t)bdev)) &
(BTRFSIC_DEV2STATE_HASHTABLE_SIZE - 1));
- struct list_head *elem;
-
- list_for_each(elem, h->table + hashval) {
- struct btrfsic_dev_state *const ds =
- list_entry(elem, struct btrfsic_dev_state,
- collision_resolving_node);
+ struct btrfsic_dev_state *ds;
+ list_for_each_entry(ds, h->table + hashval, collision_resolving_node) {
if (ds->bdev == bdev)
return ds;
}
@@ -1720,29 +1708,20 @@ static int btrfsic_read_block(struct btrfsic_state *state,
static void btrfsic_dump_database(struct btrfsic_state *state)
{
- struct list_head *elem_all;
+ const struct btrfsic_block *b_all;
BUG_ON(NULL == state);
printk(KERN_INFO "all_blocks_list:\n");
- list_for_each(elem_all, &state->all_blocks_list) {
- const struct btrfsic_block *const b_all =
- list_entry(elem_all, struct btrfsic_block,
- all_blocks_node);
- struct list_head *elem_ref_to;
- struct list_head *elem_ref_from;
+ list_for_each_entry(b_all, &state->all_blocks_list, all_blocks_node) {
+ const struct btrfsic_block_link *l;
printk(KERN_INFO "%c-block @%llu (%s/%llu/%d)\n",
btrfsic_get_block_type(state, b_all),
b_all->logical_bytenr, b_all->dev_state->name,
b_all->dev_bytenr, b_all->mirror_num);
- list_for_each(elem_ref_to, &b_all->ref_to_list) {
- const struct btrfsic_block_link *const l =
- list_entry(elem_ref_to,
- struct btrfsic_block_link,
- node_ref_to);
-
+ list_for_each_entry(l, &b_all->ref_to_list, node_ref_to) {
printk(KERN_INFO " %c @%llu (%s/%llu/%d)"
" refers %u* to"
" %c @%llu (%s/%llu/%d)\n",
@@ -1757,12 +1736,7 @@ static void btrfsic_dump_database(struct btrfsic_state *state)
l->block_ref_to->mirror_num);
}
- list_for_each(elem_ref_from, &b_all->ref_from_list) {
- const struct btrfsic_block_link *const l =
- list_entry(elem_ref_from,
- struct btrfsic_block_link,
- node_ref_from);
-
+ list_for_each_entry(l, &b_all->ref_from_list, node_ref_from) {
printk(KERN_INFO " %c @%llu (%s/%llu/%d)"
" is ref %u* from"
" %c @%llu (%s/%llu/%d)\n",
@@ -1845,8 +1819,7 @@ again:
&state->block_hashtable);
if (NULL != block) {
u64 bytenr = 0;
- struct list_head *elem_ref_to;
- struct list_head *tmp_ref_to;
+ struct btrfsic_block_link *l, *tmp;
if (block->is_superblock) {
bytenr = btrfs_super_bytenr((struct btrfs_super_block *)
@@ -1967,13 +1940,8 @@ again:
* because it still carries valueable information
* like whether it was ever written and IO completed.
*/
- list_for_each_safe(elem_ref_to, tmp_ref_to,
- &block->ref_to_list) {
- struct btrfsic_block_link *const l =
- list_entry(elem_ref_to,
- struct btrfsic_block_link,
- node_ref_to);
-
+ list_for_each_entry_safe(l, tmp, &block->ref_to_list,
+ node_ref_to) {
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
btrfsic_print_rem_link(state, l);
l->ref_cnt--;
@@ -2436,7 +2404,7 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
struct btrfsic_block *const block,
int recursion_level)
{
- struct list_head *elem_ref_to;
+ const struct btrfsic_block_link *l;
int ret = 0;
if (recursion_level >= 3 + BTRFS_MAX_LEVEL) {
@@ -2464,11 +2432,7 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
* This algorithm is recursive because the amount of used stack
* space is very small and the max recursion depth is limited.
*/
- list_for_each(elem_ref_to, &block->ref_to_list) {
- const struct btrfsic_block_link *const l =
- list_entry(elem_ref_to, struct btrfsic_block_link,
- node_ref_to);
-
+ list_for_each_entry(l, &block->ref_to_list, node_ref_to) {
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO
"rl=%d, %c @%llu (%s/%llu/%d)"
@@ -2561,7 +2525,7 @@ static int btrfsic_is_block_ref_by_superblock(
const struct btrfsic_block *block,
int recursion_level)
{
- struct list_head *elem_ref_from;
+ const struct btrfsic_block_link *l;
if (recursion_level >= 3 + BTRFS_MAX_LEVEL) {
/* refer to comment at "abort cyclic linkage (case 1)" */
@@ -2576,11 +2540,7 @@ static int btrfsic_is_block_ref_by_superblock(
* This algorithm is recursive because the amount of used stack space
* is very small and the max recursion depth is limited.
*/
- list_for_each(elem_ref_from, &block->ref_from_list) {
- const struct btrfsic_block_link *const l =
- list_entry(elem_ref_from, struct btrfsic_block_link,
- node_ref_from);
-
+ list_for_each_entry(l, &block->ref_from_list, node_ref_from) {
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO
"rl=%d, %c @%llu (%s/%llu/%d)"
@@ -2669,7 +2629,7 @@ static void btrfsic_dump_tree_sub(const struct btrfsic_state *state,
const struct btrfsic_block *block,
int indent_level)
{
- struct list_head *elem_ref_to;
+ const struct btrfsic_block_link *l;
int indent_add;
static char buf[80];
int cursor_position;
@@ -2704,11 +2664,7 @@ static void btrfsic_dump_tree_sub(const struct btrfsic_state *state,
}
cursor_position = indent_level;
- list_for_each(elem_ref_to, &block->ref_to_list) {
- const struct btrfsic_block_link *const l =
- list_entry(elem_ref_to, struct btrfsic_block_link,
- node_ref_to);
-
+ list_for_each_entry(l, &block->ref_to_list, node_ref_to) {
while (cursor_position < indent_level) {
printk(" ");
cursor_position++;
@@ -3165,8 +3121,7 @@ int btrfsic_mount(struct btrfs_root *root,
void btrfsic_unmount(struct btrfs_root *root,
struct btrfs_fs_devices *fs_devices)
{
- struct list_head *elem_all;
- struct list_head *tmp_all;
+ struct btrfsic_block *b_all, *tmp_all;
struct btrfsic_state *state;
struct list_head *dev_head = &fs_devices->devices;
struct btrfs_device *device;
@@ -3206,20 +3161,12 @@ void btrfsic_unmount(struct btrfs_root *root,
* just free all memory that was allocated dynamically.
* Free the blocks and the block_links.
*/
- list_for_each_safe(elem_all, tmp_all, &state->all_blocks_list) {
- struct btrfsic_block *const b_all =
- list_entry(elem_all, struct btrfsic_block,
- all_blocks_node);
- struct list_head *elem_ref_to;
- struct list_head *tmp_ref_to;
-
- list_for_each_safe(elem_ref_to, tmp_ref_to,
- &b_all->ref_to_list) {
- struct btrfsic_block_link *const l =
- list_entry(elem_ref_to,
- struct btrfsic_block_link,
- node_ref_to);
+ list_for_each_entry_safe(b_all, tmp_all, &state->all_blocks_list,
+ all_blocks_node) {
+ struct btrfsic_block_link *l, *tmp;
+ list_for_each_entry_safe(l, tmp, &b_all->ref_to_list,
+ node_ref_to) {
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
btrfsic_print_rem_link(state, l);
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 5b8e235c4b6d..769e0ff1b4ce 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1555,7 +1555,7 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
return 0;
}
- search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1);
+ search_start = buf->start & ~((u64)SZ_1G - 1);
if (parent)
btrfs_set_lock_blocking(parent);
@@ -2248,7 +2248,6 @@ static void reada_for_search(struct btrfs_root *root,
u64 target;
u64 nread = 0;
u64 gen;
- int direction = path->reada;
struct extent_buffer *eb;
u32 nr;
u32 blocksize;
@@ -2276,16 +2275,16 @@ static void reada_for_search(struct btrfs_root *root,
nr = slot;
while (1) {
- if (direction < 0) {
+ if (path->reada == READA_BACK) {
if (nr == 0)
break;
nr--;
- } else if (direction > 0) {
+ } else if (path->reada == READA_FORWARD) {
nr++;
if (nr >= nritems)
break;
}
- if (path->reada < 0 && objectid) {
+ if (path->reada == READA_BACK && objectid) {
btrfs_node_key(node, &disk_key, nr);
if (btrfs_disk_key_objectid(&disk_key) != objectid)
break;
@@ -2493,7 +2492,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
btrfs_set_path_blocking(p);
free_extent_buffer(tmp);
- if (p->reada)
+ if (p->reada != READA_NONE)
reada_for_search(root, p, level, slot, key->objectid);
btrfs_release_path(p);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index b7e4e344e8e0..97ad9bbeb35d 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -35,6 +35,7 @@
#include <linux/btrfs.h>
#include <linux/workqueue.h>
#include <linux/security.h>
+#include <linux/sizes.h>
#include "extent_io.h"
#include "extent_map.h"
#include "async-thread.h"
@@ -96,6 +97,9 @@ struct btrfs_ordered_sum;
/* for storing items that use the BTRFS_UUID_KEY* types */
#define BTRFS_UUID_TREE_OBJECTID 9ULL
+/* tracks free space in block groups. */
+#define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL
+
/* for storing balance parameters in the root tree */
#define BTRFS_BALANCE_OBJECTID -4ULL
@@ -174,7 +178,7 @@ struct btrfs_ordered_sum;
/* csum types */
#define BTRFS_CSUM_TYPE_CRC32 0
-static int btrfs_csum_sizes[] = { 4 };
+static const int btrfs_csum_sizes[] = { 4 };
/* four bytes for CRC32 */
#define BTRFS_EMPTY_DIR_SIZE 0
@@ -196,9 +200,9 @@ static int btrfs_csum_sizes[] = { 4 };
/* ioprio of readahead is set to idle */
#define BTRFS_IOPRIO_READA (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0))
-#define BTRFS_DIRTY_METADATA_THRESH (32 * 1024 * 1024)
+#define BTRFS_DIRTY_METADATA_THRESH SZ_32M
-#define BTRFS_MAX_EXTENT_SIZE (128 * 1024 * 1024)
+#define BTRFS_MAX_EXTENT_SIZE SZ_128M
/*
* The key defines the order in the tree, and so it also defines (optimal)
@@ -500,6 +504,8 @@ struct btrfs_super_block {
* Compat flags that we support. If any incompat flags are set other than the
* ones specified below then we will fail to mount
*/
+#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0)
+
#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1)
#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2)
@@ -526,7 +532,10 @@ struct btrfs_super_block {
#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
#define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL
#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL
-#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
+
+#define BTRFS_FEATURE_COMPAT_RO_SUPP \
+ (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)
+
#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL
#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL
@@ -590,14 +599,15 @@ struct btrfs_node {
* The slots array records the index of the item or block pointer
* used while walking the tree.
*/
+enum { READA_NONE = 0, READA_BACK, READA_FORWARD };
struct btrfs_path {
struct extent_buffer *nodes[BTRFS_MAX_LEVEL];
int slots[BTRFS_MAX_LEVEL];
/* if there is real range locking, this locks field will change */
- int locks[BTRFS_MAX_LEVEL];
- int reada;
+ u8 locks[BTRFS_MAX_LEVEL];
+ u8 reada;
/* keep some upper locks as we walk down */
- int lowest_level;
+ u8 lowest_level;
/*
* set by btrfs_split_item, tells search_slot to keep all locks
@@ -1088,6 +1098,13 @@ struct btrfs_block_group_item {
__le64 flags;
} __attribute__ ((__packed__));
+struct btrfs_free_space_info {
+ __le32 extent_count;
+ __le32 flags;
+} __attribute__ ((__packed__));
+
+#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0)
+
#define BTRFS_QGROUP_LEVEL_SHIFT 48
static inline u64 btrfs_qgroup_level(u64 qgroupid)
{
@@ -1296,6 +1313,9 @@ struct btrfs_caching_control {
atomic_t count;
};
+/* Once caching_thread() finds this much free space, it will wake up waiters. */
+#define CACHING_CTL_WAKE_UP (1024 * 1024 * 2)
+
struct btrfs_io_ctl {
void *cur, *orig;
struct page *page;
@@ -1321,8 +1341,20 @@ struct btrfs_block_group_cache {
u64 delalloc_bytes;
u64 bytes_super;
u64 flags;
- u64 sectorsize;
u64 cache_generation;
+ u32 sectorsize;
+
+ /*
+ * If the free space extent count exceeds this number, convert the block
+ * group to bitmaps.
+ */
+ u32 bitmap_high_thresh;
+
+ /*
+ * If the free space extent count drops below this number, convert the
+ * block group back to extents.
+ */
+ u32 bitmap_low_thresh;
/*
* It is just used for the delayed data space allocation because
@@ -1378,6 +1410,15 @@ struct btrfs_block_group_cache {
struct list_head io_list;
struct btrfs_io_ctl io_ctl;
+
+ /* Lock for free space tree operations. */
+ struct mutex free_space_lock;
+
+ /*
+ * Does the block group need to be added to the free space tree?
+ * Protected by free_space_lock.
+ */
+ int needs_free_space;
};
/* delayed seq elem */
@@ -1429,6 +1470,7 @@ struct btrfs_fs_info {
struct btrfs_root *csum_root;
struct btrfs_root *quota_root;
struct btrfs_root *uuid_root;
+ struct btrfs_root *free_space_root;
/* the log root tree is a directory of all the other log roots */
struct btrfs_root *log_root_tree;
@@ -1816,6 +1858,8 @@ struct btrfs_fs_info {
* and will be latter freed. Protected by fs_info->chunk_mutex.
*/
struct list_head pinned_chunks;
+
+ int creating_free_space_tree;
};
struct btrfs_subvolume_writers {
@@ -2092,6 +2136,27 @@ struct btrfs_ioctl_defrag_range_args {
*/
#define BTRFS_BLOCK_GROUP_ITEM_KEY 192
+/*
+ * Every block group is represented in the free space tree by a free space info
+ * item, which stores some accounting information. It is keyed on
+ * (block_group_start, FREE_SPACE_INFO, block_group_length).
+ */
+#define BTRFS_FREE_SPACE_INFO_KEY 198
+
+/*
+ * A free space extent tracks an extent of space that is free in a block group.
+ * It is keyed on (start, FREE_SPACE_EXTENT, length).
+ */
+#define BTRFS_FREE_SPACE_EXTENT_KEY 199
+
+/*
+ * When a block group becomes very fragmented, we convert it to use bitmaps
+ * instead of extents. A free space bitmap is keyed on
+ * (start, FREE_SPACE_BITMAP, length); the corresponding item is a bitmap with
+ * (length / sectorsize) bits.
+ */
+#define BTRFS_FREE_SPACE_BITMAP_KEY 200
+
#define BTRFS_DEV_EXTENT_KEY 204
#define BTRFS_DEV_ITEM_KEY 216
#define BTRFS_CHUNK_ITEM_KEY 228
@@ -2184,6 +2249,7 @@ struct btrfs_ioctl_defrag_range_args {
#define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23)
#define BTRFS_MOUNT_FRAGMENT_DATA (1 << 24)
#define BTRFS_MOUNT_FRAGMENT_METADATA (1 << 25)
+#define BTRFS_MOUNT_FREE_SPACE_TREE (1 << 26)
#define BTRFS_DEFAULT_COMMIT_INTERVAL (30)
#define BTRFS_DEFAULT_MAX_INLINE (8192)
@@ -2506,6 +2572,11 @@ BTRFS_SETGET_FUNCS(disk_block_group_flags,
BTRFS_SETGET_STACK_FUNCS(block_group_flags,
struct btrfs_block_group_item, flags, 64);
+/* struct btrfs_free_space_info */
+BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info,
+ extent_count, 32);
+BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32);
+
/* struct btrfs_inode_ref */
BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
@@ -3573,6 +3644,9 @@ void btrfs_end_write_no_snapshoting(struct btrfs_root *root);
void check_system_chunk(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const u64 type);
+u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
+ struct btrfs_fs_info *info, u64 start, u64 end);
+
/* ctree.c */
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
int level, int *slot);
@@ -3737,6 +3811,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
kfree(fs_info->csum_root);
kfree(fs_info->quota_root);
kfree(fs_info->uuid_root);
+ kfree(fs_info->free_space_root);
kfree(fs_info->super_copy);
kfree(fs_info->super_for_commit);
security_free_mnt_opts(&fs_info->security_opts);
@@ -3906,7 +3981,6 @@ void btrfs_extent_item_to_extent_map(struct inode *inode,
/* inode.c */
struct btrfs_delalloc_work {
struct inode *inode;
- int wait;
int delay_iput;
struct completion completion;
struct list_head list;
@@ -3914,7 +3988,7 @@ struct btrfs_delalloc_work {
};
struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
- int wait, int delay_iput);
+ int delay_iput);
void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work);
struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
@@ -4253,16 +4327,98 @@ static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
}
}
+#define btrfs_clear_fs_incompat(__fs_info, opt) \
+ __btrfs_clear_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
+
+static inline void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info,
+ u64 flag)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_incompat_flags(disk_super);
+ if (features & flag) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_incompat_flags(disk_super);
+ if (features & flag) {
+ features &= ~flag;
+ btrfs_set_super_incompat_flags(disk_super, features);
+ btrfs_info(fs_info, "clearing %llu feature flag",
+ flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
+
#define btrfs_fs_incompat(fs_info, opt) \
__btrfs_fs_incompat((fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
-static inline int __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
+static inline bool __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
{
struct btrfs_super_block *disk_super;
disk_super = fs_info->super_copy;
return !!(btrfs_super_incompat_flags(disk_super) & flag);
}
+#define btrfs_set_fs_compat_ro(__fs_info, opt) \
+ __btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+
+static inline void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info,
+ u64 flag)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (!(features & flag)) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (!(features & flag)) {
+ features |= flag;
+ btrfs_set_super_compat_ro_flags(disk_super, features);
+ btrfs_info(fs_info, "setting %llu ro feature flag",
+ flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
+
+#define btrfs_clear_fs_compat_ro(__fs_info, opt) \
+ __btrfs_clear_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+
+static inline void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info,
+ u64 flag)
+{
+ struct btrfs_super_block *disk_super;
+ u64 features;
+
+ disk_super = fs_info->super_copy;
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (features & flag) {
+ spin_lock(&fs_info->super_lock);
+ features = btrfs_super_compat_ro_flags(disk_super);
+ if (features & flag) {
+ features &= ~flag;
+ btrfs_set_super_compat_ro_flags(disk_super, features);
+ btrfs_info(fs_info, "clearing %llu ro feature flag",
+ flag);
+ }
+ spin_unlock(&fs_info->super_lock);
+ }
+}
+
+#define btrfs_fs_compat_ro(fs_info, opt) \
+ __btrfs_fs_compat_ro((fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+
+static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
+{
+ struct btrfs_super_block *disk_super;
+ disk_super = fs_info->super_copy;
+ return !!(btrfs_super_compat_ro_flags(disk_super) & flag);
+}
+
/*
* Call btrfs_abort_transaction as early as possible when an error condition is
* detected, that way the exact line number is reported.
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index e0941fbb913c..0be47e4b8136 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -54,16 +54,11 @@ static inline void btrfs_init_delayed_node(
delayed_node->root = root;
delayed_node->inode_id = inode_id;
atomic_set(&delayed_node->refs, 0);
- delayed_node->count = 0;
- delayed_node->flags = 0;
delayed_node->ins_root = RB_ROOT;
delayed_node->del_root = RB_ROOT;
mutex_init(&delayed_node->mutex);
- delayed_node->index_cnt = 0;
INIT_LIST_HEAD(&delayed_node->n_list);
INIT_LIST_HEAD(&delayed_node->p_list);
- delayed_node->bytes_reserved = 0;
- memset(&delayed_node->inode_item, 0, sizeof(delayed_node->inode_item));
}
static inline int btrfs_is_continuous_delayed_item(
@@ -132,7 +127,7 @@ again:
if (node)
return node;
- node = kmem_cache_alloc(delayed_node_cache, GFP_NOFS);
+ node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
if (!node)
return ERR_PTR(-ENOMEM);
btrfs_init_delayed_node(node, root, ino);
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index e06dd75ad13f..914ac13bd92f 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -493,12 +493,12 @@ update_existing_head_ref(struct btrfs_delayed_ref_root *delayed_refs,
memcpy(&existing_ref->extent_op->key,
&ref->extent_op->key,
sizeof(ref->extent_op->key));
- existing_ref->extent_op->update_key = 1;
+ existing_ref->extent_op->update_key = true;
}
if (ref->extent_op->update_flags) {
existing_ref->extent_op->flags_to_set |=
ref->extent_op->flags_to_set;
- existing_ref->extent_op->update_flags = 1;
+ existing_ref->extent_op->update_flags = true;
}
btrfs_free_delayed_extent_op(ref->extent_op);
}
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
index 00ed02cbf3e9..c24b653c7343 100644
--- a/fs/btrfs/delayed-ref.h
+++ b/fs/btrfs/delayed-ref.h
@@ -75,11 +75,11 @@ struct btrfs_delayed_ref_node {
struct btrfs_delayed_extent_op {
struct btrfs_disk_key key;
+ u8 level;
+ bool update_key;
+ bool update_flags;
+ bool is_data;
u64 flags_to_set;
- int level;
- unsigned int update_key:1;
- unsigned int update_flags:1;
- unsigned int is_data:1;
};
/*
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 42a378a4eefb..e99ccd6ffb2c 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -42,6 +42,7 @@
#include "locking.h"
#include "tree-log.h"
#include "free-space-cache.h"
+#include "free-space-tree.h"
#include "inode-map.h"
#include "check-integrity.h"
#include "rcu-string.h"
@@ -362,7 +363,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
}
lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
- 0, &cached_state);
+ &cached_state);
if (extent_buffer_uptodate(eb) &&
btrfs_header_generation(eb) == parent_transid) {
ret = 0;
@@ -1650,6 +1651,9 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
if (location->objectid == BTRFS_UUID_TREE_OBJECTID)
return fs_info->uuid_root ? fs_info->uuid_root :
ERR_PTR(-ENOENT);
+ if (location->objectid == BTRFS_FREE_SPACE_TREE_OBJECTID)
+ return fs_info->free_space_root ? fs_info->free_space_root :
+ ERR_PTR(-ENOENT);
again:
root = btrfs_lookup_fs_root(fs_info, location->objectid);
if (root) {
@@ -2148,6 +2152,7 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
free_root_extent_buffers(info->uuid_root);
if (chunk_root)
free_root_extent_buffers(info->chunk_root);
+ free_root_extent_buffers(info->free_space_root);
}
void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
@@ -2448,6 +2453,15 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info,
fs_info->uuid_root = root;
}
+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+ location.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID;
+ root = btrfs_read_tree_root(tree_root, &location);
+ if (IS_ERR(root))
+ return PTR_ERR(root);
+ set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
+ fs_info->free_space_root = root;
+ }
+
return 0;
}
@@ -2668,6 +2682,7 @@ int open_ctree(struct super_block *sb,
if (btrfs_check_super_csum(bh->b_data)) {
printk(KERN_ERR "BTRFS: superblock checksum mismatch\n");
err = -EINVAL;
+ brelse(bh);
goto fail_alloc;
}
@@ -2809,7 +2824,7 @@ int open_ctree(struct super_block *sb,
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
- 4 * 1024 * 1024 / PAGE_CACHE_SIZE);
+ SZ_4M / PAGE_CACHE_SIZE);
tree_root->nodesize = nodesize;
tree_root->sectorsize = sectorsize;
@@ -3051,6 +3066,18 @@ retry_root_backup:
if (sb->s_flags & MS_RDONLY)
return 0;
+ if (btrfs_test_opt(tree_root, FREE_SPACE_TREE) &&
+ !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+ pr_info("BTRFS: creating free space tree\n");
+ ret = btrfs_create_free_space_tree(fs_info);
+ if (ret) {
+ pr_warn("BTRFS: failed to create free space tree %d\n",
+ ret);
+ close_ctree(tree_root);
+ return ret;
+ }
+ }
+
down_read(&fs_info->cleanup_work_sem);
if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) ||
(ret = btrfs_orphan_cleanup(fs_info->tree_root))) {
@@ -3076,6 +3103,18 @@ retry_root_backup:
btrfs_qgroup_rescan_resume(fs_info);
+ if (btrfs_test_opt(tree_root, CLEAR_CACHE) &&
+ btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+ pr_info("BTRFS: clearing free space tree\n");
+ ret = btrfs_clear_free_space_tree(fs_info);
+ if (ret) {
+ pr_warn("BTRFS: failed to clear free space tree %d\n",
+ ret);
+ close_ctree(tree_root);
+ return ret;
+ }
+ }
+
if (!fs_info->uuid_root) {
pr_info("BTRFS: creating UUID tree\n");
ret = btrfs_create_uuid_tree(fs_info);
@@ -3902,11 +3941,6 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
return !ret;
}
-int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
-{
- return set_extent_buffer_uptodate(buf);
-}
-
void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
{
struct btrfs_root *root;
@@ -3962,7 +3996,6 @@ static void __btrfs_btree_balance_dirty(struct btrfs_root *root,
balance_dirty_pages_ratelimited(
root->fs_info->btree_inode->i_mapping);
}
- return;
}
void btrfs_btree_balance_dirty(struct btrfs_root *root)
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index adeb31830b9c..8e79d0070bcf 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -19,7 +19,7 @@
#ifndef __DISKIO__
#define __DISKIO__
-#define BTRFS_SUPER_INFO_OFFSET (64 * 1024)
+#define BTRFS_SUPER_INFO_OFFSET SZ_64K
#define BTRFS_SUPER_INFO_SIZE 4096
#define BTRFS_SUPER_MIRROR_MAX 3
@@ -35,7 +35,7 @@ enum btrfs_wq_endio_type {
static inline u64 btrfs_sb_offset(int mirror)
{
- u64 start = 16 * 1024;
+ u64 start = SZ_16K;
if (mirror)
return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror);
return BTRFS_SUPER_INFO_OFFSET;
@@ -116,7 +116,6 @@ static inline void btrfs_put_fs_root(struct btrfs_root *root)
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
int atomic);
-int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
u32 btrfs_csum_data(char *data, u32 seed, size_t len);
void btrfs_csum_final(u32 crc, char *result);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c4661db2b72a..60cc1399c64f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -33,6 +33,7 @@
#include "raid56.h"
#include "locking.h"
#include "free-space-cache.h"
+#include "free-space-tree.h"
#include "math.h"
#include "sysfs.h"
#include "qgroup.h"
@@ -357,8 +358,8 @@ static void fragment_free_space(struct btrfs_root *root,
* we need to check the pinned_extents for any extents that can't be used yet
* since their free space will be released as soon as the transaction commits.
*/
-static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
- struct btrfs_fs_info *info, u64 start, u64 end)
+u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
+ struct btrfs_fs_info *info, u64 start, u64 end)
{
u64 extent_start, extent_end, size, total_added = 0;
int ret;
@@ -395,11 +396,10 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
return total_added;
}
-static noinline void caching_thread(struct btrfs_work *work)
+static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
{
struct btrfs_block_group_cache *block_group;
struct btrfs_fs_info *fs_info;
- struct btrfs_caching_control *caching_ctl;
struct btrfs_root *extent_root;
struct btrfs_path *path;
struct extent_buffer *leaf;
@@ -407,17 +407,16 @@ static noinline void caching_thread(struct btrfs_work *work)
u64 total_found = 0;
u64 last = 0;
u32 nritems;
- int ret = -ENOMEM;
+ int ret;
bool wakeup = true;
- caching_ctl = container_of(work, struct btrfs_caching_control, work);
block_group = caching_ctl->block_group;
fs_info = block_group->fs_info;
extent_root = fs_info->extent_root;
path = btrfs_alloc_path();
if (!path)
- goto out;
+ return -ENOMEM;
last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
@@ -438,20 +437,16 @@ static noinline void caching_thread(struct btrfs_work *work)
*/
path->skip_locking = 1;
path->search_commit_root = 1;
- path->reada = 1;
+ path->reada = READA_FORWARD;
key.objectid = last;
key.offset = 0;
key.type = BTRFS_EXTENT_ITEM_KEY;
-again:
- mutex_lock(&caching_ctl->mutex);
- /* need to make sure the commit_root doesn't disappear */
- down_read(&fs_info->commit_root_sem);
next:
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
if (ret < 0)
- goto err;
+ goto out;
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
@@ -477,12 +472,14 @@ next:
up_read(&fs_info->commit_root_sem);
mutex_unlock(&caching_ctl->mutex);
cond_resched();
- goto again;
+ mutex_lock(&caching_ctl->mutex);
+ down_read(&fs_info->commit_root_sem);
+ goto next;
}
ret = btrfs_next_leaf(extent_root, path);
if (ret < 0)
- goto err;
+ goto out;
if (ret)
break;
leaf = path->nodes[0];
@@ -521,7 +518,7 @@ next:
else
last = key.objectid + key.offset;
- if (total_found > (1024 * 1024 * 2)) {
+ if (total_found > CACHING_CTL_WAKE_UP) {
total_found = 0;
if (wakeup)
wake_up(&caching_ctl->wait);
@@ -534,9 +531,37 @@ next:
total_found += add_new_free_space(block_group, fs_info, last,
block_group->key.objectid +
block_group->key.offset);
+ caching_ctl->progress = (u64)-1;
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+static noinline void caching_thread(struct btrfs_work *work)
+{
+ struct btrfs_block_group_cache *block_group;
+ struct btrfs_fs_info *fs_info;
+ struct btrfs_caching_control *caching_ctl;
+ struct btrfs_root *extent_root;
+ int ret;
+
+ caching_ctl = container_of(work, struct btrfs_caching_control, work);
+ block_group = caching_ctl->block_group;
+ fs_info = block_group->fs_info;
+ extent_root = fs_info->extent_root;
+
+ mutex_lock(&caching_ctl->mutex);
+ down_read(&fs_info->commit_root_sem);
+
+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ ret = load_free_space_tree(caching_ctl);
+ else
+ ret = load_extent_tree_free(caching_ctl);
+
spin_lock(&block_group->lock);
block_group->caching_ctl = NULL;
- block_group->cached = BTRFS_CACHE_FINISHED;
+ block_group->cached = ret ? BTRFS_CACHE_ERROR : BTRFS_CACHE_FINISHED;
spin_unlock(&block_group->lock);
#ifdef CONFIG_BTRFS_DEBUG
@@ -555,20 +580,11 @@ next:
#endif
caching_ctl->progress = (u64)-1;
-err:
- btrfs_free_path(path);
- up_read(&fs_info->commit_root_sem);
-
- free_excluded_extents(extent_root, block_group);
+ up_read(&fs_info->commit_root_sem);
+ free_excluded_extents(fs_info->extent_root, block_group);
mutex_unlock(&caching_ctl->mutex);
-out:
- if (ret) {
- spin_lock(&block_group->lock);
- block_group->caching_ctl = NULL;
- block_group->cached = BTRFS_CACHE_ERROR;
- spin_unlock(&block_group->lock);
- }
+
wake_up(&caching_ctl->wait);
put_caching_control(caching_ctl);
@@ -680,8 +696,8 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
}
} else {
/*
- * We are not going to do the fast caching, set cached to the
- * appropriate value and wakeup any waiters.
+ * We're either using the free space tree or no caching at all.
+ * Set cached to the appropriate value and wakeup any waiters.
*/
spin_lock(&cache->lock);
if (load_cache_only) {
@@ -2115,7 +2131,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
path->leave_spinning = 1;
/* this will setup the path even if it fails to insert the back ref */
ret = insert_inline_extent_backref(trans, fs_info->extent_root, path,
@@ -2141,7 +2157,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
- path->reada = 1;
+ path->reada = READA_FORWARD;
path->leave_spinning = 1;
/* now insert the actual backref */
ret = insert_extent_backref(trans, root->fs_info->extent_root,
@@ -2254,7 +2270,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
}
again:
- path->reada = 1;
+ path->reada = READA_FORWARD;
path->leave_spinning = 1;
ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key,
path, 0, 1);
@@ -2910,6 +2926,9 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
if (trans->aborted)
return 0;
+ if (root->fs_info->creating_free_space_tree)
+ return 0;
+
if (root == root->fs_info->extent_root)
root = root->fs_info->tree_root;
@@ -2988,9 +3007,9 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
return -ENOMEM;
extent_op->flags_to_set = flags;
- extent_op->update_flags = 1;
- extent_op->update_key = 0;
- extent_op->is_data = is_data ? 1 : 0;
+ extent_op->update_flags = true;
+ extent_op->update_key = false;
+ extent_op->is_data = is_data ? true : false;
extent_op->level = level;
ret = btrfs_add_delayed_extent_op(root->fs_info, trans, bytenr,
@@ -3328,7 +3347,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
* If this block group is smaller than 100 megs don't bother caching the
* block group.
*/
- if (block_group->key.offset < (100 * 1024 * 1024)) {
+ if (block_group->key.offset < (100 * SZ_1M)) {
spin_lock(&block_group->lock);
block_group->disk_cache_state = BTRFS_DC_WRITTEN;
spin_unlock(&block_group->lock);
@@ -3428,7 +3447,7 @@ again:
* taking up quite a bit since it's not folded into the other space
* cache.
*/
- num_pages = div_u64(block_group->key.offset, 256 * 1024 * 1024);
+ num_pages = div_u64(block_group->key.offset, SZ_256M);
if (!num_pages)
num_pages = 1;
@@ -3684,11 +3703,21 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
return -ENOMEM;
/*
- * We don't need the lock here since we are protected by the transaction
- * commit. We want to do the cache_save_setup first and then run the
+ * Even though we are in the critical section of the transaction commit,
+ * we can still have concurrent tasks adding elements to this
+ * transaction's list of dirty block groups. These tasks correspond to
+ * endio free space workers started when writeback finishes for a
+ * space cache, which run inode.c:btrfs_finish_ordered_io(), and can
+ * allocate new block groups as a result of COWing nodes of the root
+ * tree when updating the free space inode. The writeback for the space
+ * caches is triggered by an earlier call to
+ * btrfs_start_dirty_block_groups() and iterations of the following
+ * loop.
+ * Also we want to do the cache_save_setup first and then run the
* delayed refs to make sure we have the best chance at doing this all
* in one shot.
*/
+ spin_lock(&cur_trans->dirty_bgs_lock);
while (!list_empty(&cur_trans->dirty_bgs)) {
cache = list_first_entry(&cur_trans->dirty_bgs,
struct btrfs_block_group_cache,
@@ -3700,11 +3729,13 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
* finish and then do it all again
*/
if (!list_empty(&cache->io_list)) {
+ spin_unlock(&cur_trans->dirty_bgs_lock);
list_del_init(&cache->io_list);
btrfs_wait_cache_io(root, trans, cache,
&cache->io_ctl, path,
cache->key.objectid);
btrfs_put_block_group(cache);
+ spin_lock(&cur_trans->dirty_bgs_lock);
}
/*
@@ -3712,6 +3743,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
* on any pending IO
*/
list_del_init(&cache->dirty_list);
+ spin_unlock(&cur_trans->dirty_bgs_lock);
should_put = 1;
cache_save_setup(cache, trans, path);
@@ -3736,6 +3768,25 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
}
if (!ret) {
ret = write_one_cache_group(trans, root, path, cache);
+ /*
+ * One of the free space endio workers might have
+ * created a new block group while updating a free space
+ * cache's inode (at inode.c:btrfs_finish_ordered_io())
+ * and hasn't released its transaction handle yet, in
+ * which case the new block group is still attached to
+ * its transaction handle and its creation has not
+ * finished yet (no block group item in the extent tree
+ * yet, etc). If this is the case, wait for all free
+ * space endio workers to finish and retry. This is a
+ * a very rare case so no need for a more efficient and
+ * complex approach.
+ */
+ if (ret == -ENOENT) {
+ wait_event(cur_trans->writer_wait,
+ atomic_read(&cur_trans->num_writers) == 1);
+ ret = write_one_cache_group(trans, root, path,
+ cache);
+ }
if (ret)
btrfs_abort_transaction(trans, root, ret);
}
@@ -3743,7 +3794,9 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
/* if its not on the io list, we need to put the block group */
if (should_put)
btrfs_put_block_group(cache);
+ spin_lock(&cur_trans->dirty_bgs_lock);
}
+ spin_unlock(&cur_trans->dirty_bgs_lock);
while (!list_empty(io)) {
cache = list_first_entry(io, struct btrfs_block_group_cache,
@@ -4239,14 +4292,13 @@ static int should_alloc_chunk(struct btrfs_root *root,
*/
if (force == CHUNK_ALLOC_LIMITED) {
thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
- thresh = max_t(u64, 64 * 1024 * 1024,
- div_factor_fine(thresh, 1));
+ thresh = max_t(u64, SZ_64M, div_factor_fine(thresh, 1));
if (num_bytes - num_allocated < thresh)
return 1;
}
- if (num_allocated + 2 * 1024 * 1024 < div_factor(num_bytes, 8))
+ if (num_allocated + SZ_2M < div_factor(num_bytes, 8))
return 0;
return 1;
}
@@ -4446,7 +4498,7 @@ out:
* transaction.
*/
if (trans->can_flush_pending_bgs &&
- trans->chunk_bytes_reserved >= (2 * 1024 * 1024ull)) {
+ trans->chunk_bytes_reserved >= (u64)SZ_2M) {
btrfs_create_pending_block_groups(trans, trans->root);
btrfs_trans_release_chunk_metadata(trans);
}
@@ -4544,7 +4596,7 @@ static inline int calc_reclaim_items_nr(struct btrfs_root *root, u64 to_reclaim)
return nr;
}
-#define EXTENT_SIZE_PER_ITEM (256 * 1024)
+#define EXTENT_SIZE_PER_ITEM SZ_256K
/*
* shrink metadata reservation for delalloc
@@ -4749,8 +4801,7 @@ btrfs_calc_reclaim_metadata_size(struct btrfs_root *root,
u64 expected;
u64 to_reclaim;
- to_reclaim = min_t(u64, num_online_cpus() * 1024 * 1024,
- 16 * 1024 * 1024);
+ to_reclaim = min_t(u64, num_online_cpus() * SZ_1M, SZ_16M);
spin_lock(&space_info->lock);
if (can_overcommit(root, space_info, to_reclaim,
BTRFS_RESERVE_FLUSH_ALL)) {
@@ -4761,8 +4812,7 @@ btrfs_calc_reclaim_metadata_size(struct btrfs_root *root,
used = space_info->bytes_used + space_info->bytes_reserved +
space_info->bytes_pinned + space_info->bytes_readonly +
space_info->bytes_may_use;
- if (can_overcommit(root, space_info, 1024 * 1024,
- BTRFS_RESERVE_FLUSH_ALL))
+ if (can_overcommit(root, space_info, SZ_1M, BTRFS_RESERVE_FLUSH_ALL))
expected = div_factor_fine(space_info->total_bytes, 95);
else
expected = div_factor_fine(space_info->total_bytes, 90);
@@ -5318,7 +5368,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
spin_lock(&sinfo->lock);
spin_lock(&block_rsv->lock);
- block_rsv->size = min_t(u64, num_bytes, 512 * 1024 * 1024);
+ block_rsv->size = min_t(u64, num_bytes, SZ_512M);
num_bytes = sinfo->bytes_used + sinfo->bytes_pinned +
sinfo->bytes_reserved + sinfo->bytes_readonly +
@@ -6222,11 +6272,11 @@ fetch_cluster_info(struct btrfs_root *root, struct btrfs_space_info *space_info,
return ret;
if (ssd)
- *empty_cluster = 2 * 1024 * 1024;
+ *empty_cluster = SZ_2M;
if (space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
ret = &root->fs_info->meta_alloc_cluster;
if (!ssd)
- *empty_cluster = 64 * 1024;
+ *empty_cluster = SZ_64K;
} else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) && ssd) {
ret = &root->fs_info->data_alloc_cluster;
}
@@ -6438,7 +6488,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
path->leave_spinning = 1;
is_data = owner_objectid >= BTRFS_FIRST_FREE_OBJECTID;
@@ -6661,6 +6711,13 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
}
}
+ ret = add_to_free_space_tree(trans, root->fs_info, bytenr,
+ num_bytes);
+ if (ret) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
+
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
if (ret) {
btrfs_abort_transaction(trans, extent_root, ret);
@@ -7672,6 +7729,11 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path);
+ ret = remove_from_free_space_tree(trans, fs_info, ins->objectid,
+ ins->offset);
+ if (ret)
+ return ret;
+
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
if (ret) { /* -ENOENT, logic error */
btrfs_err(fs_info, "update block group failed for %llu %llu",
@@ -7752,6 +7814,11 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf);
btrfs_free_path(path);
+ ret = remove_from_free_space_tree(trans, fs_info, ins->objectid,
+ num_bytes);
+ if (ret)
+ return ret;
+
ret = update_block_group(trans, root, ins->objectid, root->nodesize,
1);
if (ret) { /* -ENOENT, logic error */
@@ -7834,7 +7901,7 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
clear_bit(EXTENT_BUFFER_STALE, &buf->bflags);
btrfs_set_lock_blocking(buf);
- btrfs_set_buffer_uptodate(buf);
+ set_extent_buffer_uptodate(buf);
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
buf->log_index = root->log_transid % 2;
@@ -7980,12 +8047,9 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
else
memset(&extent_op->key, 0, sizeof(extent_op->key));
extent_op->flags_to_set = flags;
- if (skinny_metadata)
- extent_op->update_key = 0;
- else
- extent_op->update_key = 1;
- extent_op->update_flags = 1;
- extent_op->is_data = 0;
+ extent_op->update_key = skinny_metadata ? false : true;
+ extent_op->update_flags = true;
+ extent_op->is_data = false;
extent_op->level = level;
ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
@@ -9124,7 +9188,7 @@ static int inc_block_group_ro(struct btrfs_block_group_cache *cache, int force)
if ((sinfo->flags &
(BTRFS_BLOCK_GROUP_SYSTEM | BTRFS_BLOCK_GROUP_METADATA)) &&
!force)
- min_allocable_bytes = 1 * 1024 * 1024;
+ min_allocable_bytes = SZ_1M;
else
min_allocable_bytes = 0;
@@ -9656,6 +9720,8 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size)
cache->full_stripe_len = btrfs_full_stripe_len(root,
&root->fs_info->mapping_tree,
start);
+ set_free_space_tree_thresholds(cache);
+
atomic_set(&cache->count, 1);
spin_lock_init(&cache->lock);
init_rwsem(&cache->data_rwsem);
@@ -9667,6 +9733,7 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size)
INIT_LIST_HEAD(&cache->io_list);
btrfs_init_free_space_ctl(cache);
atomic_set(&cache->trimming, 0);
+ mutex_init(&cache->free_space_lock);
return cache;
}
@@ -9691,7 +9758,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
if (btrfs_test_opt(root, SPACE_CACHE) &&
@@ -9877,6 +9944,8 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
key.objectid, key.offset);
if (ret)
btrfs_abort_transaction(trans, extent_root, ret);
+ add_block_group_free_space(trans, root->fs_info, block_group);
+ /* already aborted the transaction if it failed. */
next:
list_del_init(&block_group->bg_list);
}
@@ -9907,6 +9976,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
cache->flags = type;
cache->last_byte_to_unpin = (u64)-1;
cache->cached = BTRFS_CACHE_FINISHED;
+ cache->needs_free_space = 1;
ret = exclude_super_stripes(root, cache);
if (ret) {
/*
@@ -10277,6 +10347,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
unlock_chunks(root);
+ ret = remove_block_group_free_space(trans, root->fs_info, block_group);
+ if (ret)
+ goto out;
+
btrfs_put_block_group(block_group);
btrfs_put_block_group(block_group);
diff --git a/fs/btrfs/extent-tree.h b/fs/btrfs/extent-tree.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/fs/btrfs/extent-tree.h
+++ /dev/null
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 9abe18763a7f..2e7c97a3f344 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1285,20 +1285,6 @@ search_again:
}
/* wrappers around set/clear extent bit */
-int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
- gfp_t mask)
-{
- return set_extent_bit(tree, start, end, EXTENT_DIRTY, NULL,
- NULL, mask);
-}
-
-int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
- unsigned bits, gfp_t mask)
-{
- return set_extent_bit(tree, start, end, bits, NULL,
- NULL, mask);
-}
-
int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, gfp_t mask,
struct extent_changeset *changeset)
@@ -1323,17 +1309,6 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
cached, mask, NULL);
}
-int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
- unsigned bits, gfp_t mask)
-{
- int wake = 0;
-
- if (bits & EXTENT_LOCKED)
- wake = 1;
-
- return clear_extent_bit(tree, start, end, bits, wake, 0, NULL, mask);
-}
-
int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, gfp_t mask,
struct extent_changeset *changeset)
@@ -1348,63 +1323,18 @@ int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
changeset);
}
-int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask)
-{
- return set_extent_bit(tree, start, end,
- EXTENT_DELALLOC | EXTENT_UPTODATE,
- NULL, cached_state, mask);
-}
-
-int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask)
-{
- return set_extent_bit(tree, start, end,
- EXTENT_DELALLOC | EXTENT_UPTODATE | EXTENT_DEFRAG,
- NULL, cached_state, mask);
-}
-
-int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
- gfp_t mask)
-{
- return clear_extent_bit(tree, start, end,
- EXTENT_DIRTY | EXTENT_DELALLOC |
- EXTENT_DO_ACCOUNTING, 0, 0, NULL, mask);
-}
-
-int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
- gfp_t mask)
-{
- return set_extent_bit(tree, start, end, EXTENT_NEW, NULL,
- NULL, mask);
-}
-
-int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask)
-{
- return set_extent_bit(tree, start, end, EXTENT_UPTODATE, NULL,
- cached_state, mask);
-}
-
-int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask)
-{
- return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0,
- cached_state, mask);
-}
-
/*
* either insert or lock state struct between start and end use mask to tell
* us if waiting is desired.
*/
int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
- unsigned bits, struct extent_state **cached_state)
+ struct extent_state **cached_state)
{
int err;
u64 failed_start;
while (1) {
- err = __set_extent_bit(tree, start, end, EXTENT_LOCKED | bits,
+ err = __set_extent_bit(tree, start, end, EXTENT_LOCKED,
EXTENT_LOCKED, &failed_start,
cached_state, GFP_NOFS, NULL);
if (err == -EEXIST) {
@@ -1417,11 +1347,6 @@ int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
return err;
}
-int lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
-{
- return lock_extent_bits(tree, start, end, 0, NULL);
-}
-
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
{
int err;
@@ -1438,20 +1363,7 @@ int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
return 1;
}
-int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached, gfp_t mask)
-{
- return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, cached,
- mask);
-}
-
-int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end)
-{
- return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL,
- GFP_NOFS);
-}
-
-int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
+void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
{
unsigned long index = start >> PAGE_CACHE_SHIFT;
unsigned long end_index = end >> PAGE_CACHE_SHIFT;
@@ -1464,10 +1376,9 @@ int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
page_cache_release(page);
index++;
}
- return 0;
}
-int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end)
+void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end)
{
unsigned long index = start >> PAGE_CACHE_SHIFT;
unsigned long end_index = end >> PAGE_CACHE_SHIFT;
@@ -1481,13 +1392,12 @@ int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end)
page_cache_release(page);
index++;
}
- return 0;
}
/*
* helper function to set both pages and extents in the tree writeback
*/
-static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
+static void set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
{
unsigned long index = start >> PAGE_CACHE_SHIFT;
unsigned long end_index = end >> PAGE_CACHE_SHIFT;
@@ -1500,7 +1410,6 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
page_cache_release(page);
index++;
}
- return 0;
}
/* find the first state struct with 'bits' set after 'start', and
@@ -1800,7 +1709,7 @@ again:
BUG_ON(ret); /* Only valid values are 0 and -EAGAIN */
/* step three, lock the state bits for the whole range */
- lock_extent_bits(tree, delalloc_start, delalloc_end, 0, &cached_state);
+ lock_extent_bits(tree, delalloc_start, delalloc_end, &cached_state);
/* then test to make sure it is all still delalloc */
ret = test_range_bit(tree, delalloc_start, delalloc_end,
@@ -1820,7 +1729,7 @@ out_failed:
return found;
}
-int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
+void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
struct page *locked_page,
unsigned clear_bits,
unsigned long page_ops)
@@ -1835,7 +1744,7 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS);
if (page_ops == 0)
- return 0;
+ return;
if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
mapping_set_error(inode->i_mapping, -EIO);
@@ -1869,7 +1778,6 @@ int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
index += ret;
cond_resched();
}
- return 0;
}
/*
@@ -2516,7 +2424,7 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
/* lots and lots of room for performance fixes in the end_bio funcs */
-int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
+void end_extent_writepage(struct page *page, int err, u64 start, u64 end)
{
int uptodate = (err == 0);
struct extent_io_tree *tree;
@@ -2537,7 +2445,6 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
ret = ret < 0 ? ret : -EIO;
mapping_set_error(page->mapping, ret);
}
- return 0;
}
/*
@@ -2579,9 +2486,7 @@ static void end_bio_extent_writepage(struct bio *bio)
start = page_offset(page);
end = start + bvec->bv_offset + bvec->bv_len - 1;
- if (end_extent_writepage(page, bio->bi_error, start, end))
- continue;
-
+ end_extent_writepage(page, bio->bi_error, start, end);
end_page_writeback(page);
}
@@ -4326,7 +4231,7 @@ int extent_invalidatepage(struct extent_io_tree *tree,
if (start > end)
return 0;
- lock_extent_bits(tree, start, end, 0, &cached_state);
+ lock_extent_bits(tree, start, end, &cached_state);
wait_on_page_writeback(page);
clear_extent_bit(tree, start, end,
EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
@@ -4387,7 +4292,7 @@ int try_release_extent_mapping(struct extent_map_tree *map,
u64 end = start + PAGE_CACHE_SIZE - 1;
if (gfpflags_allow_blocking(mask) &&
- page->mapping->host->i_size > 16 * 1024 * 1024) {
+ page->mapping->host->i_size > SZ_16M) {
u64 len;
while (start <= end) {
len = end - start + 1;
@@ -4536,7 +4441,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
last_for_get_extent = isize;
}
- lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len - 1, 0,
+ lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len - 1,
&cached_state);
em = get_extent_skip_holes(inode, start, last_for_get_extent,
@@ -4797,24 +4702,14 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src)
return new;
}
-struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
- u64 start)
+struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
+ u64 start, unsigned long len)
{
struct extent_buffer *eb;
- unsigned long len;
unsigned long num_pages;
unsigned long i;
- if (!fs_info) {
- /*
- * Called only from tests that don't always have a fs_info
- * available, but we know that nodesize is 4096
- */
- len = 4096;
- } else {
- len = fs_info->tree_root->nodesize;
- }
- num_pages = num_extent_pages(0, len);
+ num_pages = num_extent_pages(start, len);
eb = __alloc_extent_buffer(fs_info, start, len);
if (!eb)
@@ -4837,6 +4732,24 @@ err:
return NULL;
}
+struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
+ u64 start)
+{
+ unsigned long len;
+
+ if (!fs_info) {
+ /*
+ * Called only from tests that don't always have a fs_info
+ * available, but we know that nodesize is 4096
+ */
+ len = 4096;
+ } else {
+ len = fs_info->tree_root->nodesize;
+ }
+
+ return __alloc_dummy_extent_buffer(fs_info, start, len);
+}
+
static void check_buffer_tree_ref(struct extent_buffer *eb)
{
int refs;
@@ -5227,7 +5140,7 @@ int set_extent_buffer_dirty(struct extent_buffer *eb)
return was_dirty;
}
-int clear_extent_buffer_uptodate(struct extent_buffer *eb)
+void clear_extent_buffer_uptodate(struct extent_buffer *eb)
{
unsigned long i;
struct page *page;
@@ -5240,10 +5153,9 @@ int clear_extent_buffer_uptodate(struct extent_buffer *eb)
if (page)
ClearPageUptodate(page);
}
- return 0;
}
-int set_extent_buffer_uptodate(struct extent_buffer *eb)
+void set_extent_buffer_uptodate(struct extent_buffer *eb)
{
unsigned long i;
struct page *page;
@@ -5255,7 +5167,6 @@ int set_extent_buffer_uptodate(struct extent_buffer *eb)
page = eb->pages[i];
SetPageUptodate(page);
}
- return 0;
}
int extent_buffer_uptodate(struct extent_buffer *eb)
@@ -5594,6 +5505,155 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
}
}
+/*
+ * The extent buffer bitmap operations are done with byte granularity because
+ * bitmap items are not guaranteed to be aligned to a word and therefore a
+ * single word in a bitmap may straddle two pages in the extent buffer.
+ */
+#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
+#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1)
+#define BITMAP_FIRST_BYTE_MASK(start) \
+ ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK)
+#define BITMAP_LAST_BYTE_MASK(nbits) \
+ (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1)))
+
+/*
+ * eb_bitmap_offset() - calculate the page and offset of the byte containing the
+ * given bit number
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @nr: bit number
+ * @page_index: return index of the page in the extent buffer that contains the
+ * given bit number
+ * @page_offset: return offset into the page given by page_index
+ *
+ * This helper hides the ugliness of finding the byte in an extent buffer which
+ * contains a given bit.
+ */
+static inline void eb_bitmap_offset(struct extent_buffer *eb,
+ unsigned long start, unsigned long nr,
+ unsigned long *page_index,
+ size_t *page_offset)
+{
+ size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1);
+ size_t byte_offset = BIT_BYTE(nr);
+ size_t offset;
+
+ /*
+ * The byte we want is the offset of the extent buffer + the offset of
+ * the bitmap item in the extent buffer + the offset of the byte in the
+ * bitmap item.
+ */
+ offset = start_offset + start + byte_offset;
+
+ *page_index = offset >> PAGE_CACHE_SHIFT;
+ *page_offset = offset & (PAGE_CACHE_SIZE - 1);
+}
+
+/**
+ * extent_buffer_test_bit - determine whether a bit in a bitmap item is set
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @nr: bit number to test
+ */
+int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start,
+ unsigned long nr)
+{
+ char *kaddr;
+ struct page *page;
+ unsigned long i;
+ size_t offset;
+
+ eb_bitmap_offset(eb, start, nr, &i, &offset);
+ page = eb->pages[i];
+ WARN_ON(!PageUptodate(page));
+ kaddr = page_address(page);
+ return 1U & (kaddr[offset] >> (nr & (BITS_PER_BYTE - 1)));
+}
+
+/**
+ * extent_buffer_bitmap_set - set an area of a bitmap
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @pos: bit number of the first bit
+ * @len: number of bits to set
+ */
+void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start,
+ unsigned long pos, unsigned long len)
+{
+ char *kaddr;
+ struct page *page;
+ unsigned long i;
+ size_t offset;
+ const unsigned int size = pos + len;
+ int bits_to_set = BITS_PER_BYTE - (pos % BITS_PER_BYTE);
+ unsigned int mask_to_set = BITMAP_FIRST_BYTE_MASK(pos);
+
+ eb_bitmap_offset(eb, start, pos, &i, &offset);
+ page = eb->pages[i];
+ WARN_ON(!PageUptodate(page));
+ kaddr = page_address(page);
+
+ while (len >= bits_to_set) {
+ kaddr[offset] |= mask_to_set;
+ len -= bits_to_set;
+ bits_to_set = BITS_PER_BYTE;
+ mask_to_set = ~0U;
+ if (++offset >= PAGE_CACHE_SIZE && len > 0) {
+ offset = 0;
+ page = eb->pages[++i];
+ WARN_ON(!PageUptodate(page));
+ kaddr = page_address(page);
+ }
+ }
+ if (len) {
+ mask_to_set &= BITMAP_LAST_BYTE_MASK(size);
+ kaddr[offset] |= mask_to_set;
+ }
+}
+
+
+/**
+ * extent_buffer_bitmap_clear - clear an area of a bitmap
+ * @eb: the extent buffer
+ * @start: offset of the bitmap item in the extent buffer
+ * @pos: bit number of the first bit
+ * @len: number of bits to clear
+ */
+void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start,
+ unsigned long pos, unsigned long len)
+{
+ char *kaddr;
+ struct page *page;
+ unsigned long i;
+ size_t offset;
+ const unsigned int size = pos + len;
+ int bits_to_clear = BITS_PER_BYTE - (pos % BITS_PER_BYTE);
+ unsigned int mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos);
+
+ eb_bitmap_offset(eb, start, pos, &i, &offset);
+ page = eb->pages[i];
+ WARN_ON(!PageUptodate(page));
+ kaddr = page_address(page);
+
+ while (len >= bits_to_clear) {
+ kaddr[offset] &= ~mask_to_clear;
+ len -= bits_to_clear;
+ bits_to_clear = BITS_PER_BYTE;
+ mask_to_clear = ~0U;
+ if (++offset >= PAGE_CACHE_SIZE && len > 0) {
+ offset = 0;
+ page = eb->pages[++i];
+ WARN_ON(!PageUptodate(page));
+ kaddr = page_address(page);
+ }
+ }
+ if (len) {
+ mask_to_clear &= BITMAP_LAST_BYTE_MASK(size);
+ kaddr[offset] &= ~mask_to_clear;
+ }
+}
+
static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
{
unsigned long distance = (src > dst) ? src - dst : dst - src;
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index f4c1ae11855f..0377413bd4b9 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -199,12 +199,14 @@ int try_release_extent_mapping(struct extent_map_tree *map,
struct extent_io_tree *tree, struct page *page,
gfp_t mask);
int try_release_extent_buffer(struct page *page);
-int lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
- unsigned bits, struct extent_state **cached);
-int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end);
-int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached, gfp_t mask);
+ struct extent_state **cached);
+
+static inline int lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
+{
+ return lock_extent_bits(tree, start, end, NULL);
+}
+
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
get_extent_t *get_extent, int mirror_num);
@@ -221,39 +223,105 @@ void free_extent_state(struct extent_state *state);
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, int filled,
struct extent_state *cached_state);
-int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
- unsigned bits, gfp_t mask);
int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, gfp_t mask,
struct extent_changeset *changeset);
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, int wake, int delete,
struct extent_state **cached, gfp_t mask);
-int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
- unsigned bits, gfp_t mask);
+
+static inline int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end)
+{
+ return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL,
+ GFP_NOFS);
+}
+
+static inline int unlock_extent_cached(struct extent_io_tree *tree, u64 start,
+ u64 end, struct extent_state **cached, gfp_t mask)
+{
+ return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, cached,
+ mask);
+}
+
+static inline int clear_extent_bits(struct extent_io_tree *tree, u64 start,
+ u64 end, unsigned bits, gfp_t mask)
+{
+ int wake = 0;
+
+ if (bits & EXTENT_LOCKED)
+ wake = 1;
+
+ return clear_extent_bit(tree, start, end, bits, wake, 0, NULL, mask);
+}
+
int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, gfp_t mask,
struct extent_changeset *changeset);
int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, u64 *failed_start,
struct extent_state **cached_state, gfp_t mask);
-int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask);
-int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask);
-int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
- gfp_t mask);
-int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
- gfp_t mask);
-int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
- gfp_t mask);
+
+static inline int set_extent_bits(struct extent_io_tree *tree, u64 start,
+ u64 end, unsigned bits, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end, bits, NULL, NULL, mask);
+}
+
+static inline int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
+ u64 end, struct extent_state **cached_state, gfp_t mask)
+{
+ return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0,
+ cached_state, mask);
+}
+
+static inline int set_extent_dirty(struct extent_io_tree *tree, u64 start,
+ u64 end, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end, EXTENT_DIRTY, NULL,
+ NULL, mask);
+}
+
+static inline int clear_extent_dirty(struct extent_io_tree *tree, u64 start,
+ u64 end, gfp_t mask)
+{
+ return clear_extent_bit(tree, start, end,
+ EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING, 0, 0, NULL, mask);
+}
+
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
unsigned bits, unsigned clear_bits,
struct extent_state **cached_state, gfp_t mask);
-int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask);
-int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end,
- struct extent_state **cached_state, gfp_t mask);
+
+static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start,
+ u64 end, struct extent_state **cached_state, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end,
+ EXTENT_DELALLOC | EXTENT_UPTODATE,
+ NULL, cached_state, mask);
+}
+
+static inline int set_extent_defrag(struct extent_io_tree *tree, u64 start,
+ u64 end, struct extent_state **cached_state, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end,
+ EXTENT_DELALLOC | EXTENT_UPTODATE | EXTENT_DEFRAG,
+ NULL, cached_state, mask);
+}
+
+static inline int set_extent_new(struct extent_io_tree *tree, u64 start,
+ u64 end, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end, EXTENT_NEW, NULL, NULL, mask);
+}
+
+static inline int set_extent_uptodate(struct extent_io_tree *tree, u64 start,
+ u64 end, struct extent_state **cached_state, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end, EXTENT_UPTODATE, NULL,
+ cached_state, mask);
+}
+
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, unsigned bits,
struct extent_state **cached_state);
@@ -282,8 +350,10 @@ void set_page_extent_mapped(struct page *page);
struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
u64 start);
+struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
+ u64 start, unsigned long len);
struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
- u64 start);
+ u64 start);
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
u64 start);
@@ -328,19 +398,25 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
unsigned long src_offset, unsigned long len);
void memset_extent_buffer(struct extent_buffer *eb, char c,
unsigned long start, unsigned long len);
+int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start,
+ unsigned long pos);
+void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start,
+ unsigned long pos, unsigned long len);
+void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start,
+ unsigned long pos, unsigned long len);
void clear_extent_buffer_dirty(struct extent_buffer *eb);
int set_extent_buffer_dirty(struct extent_buffer *eb);
-int set_extent_buffer_uptodate(struct extent_buffer *eb);
-int clear_extent_buffer_uptodate(struct extent_buffer *eb);
+void set_extent_buffer_uptodate(struct extent_buffer *eb);
+void clear_extent_buffer_uptodate(struct extent_buffer *eb);
int extent_buffer_uptodate(struct extent_buffer *eb);
int extent_buffer_under_io(struct extent_buffer *eb);
int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
unsigned long min_len, char **map,
unsigned long *map_start,
unsigned long *map_len);
-int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
-int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
-int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
+void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
+void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
+void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
struct page *locked_page,
unsigned bits_to_clear,
unsigned long page_ops);
@@ -357,7 +433,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
int mirror_num);
int clean_io_failure(struct inode *inode, u64 start, struct page *page,
unsigned int pg_offset);
-int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
+void end_extent_writepage(struct page *page, int err, u64 start, u64 end);
int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
int mirror_num);
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 58ece6558430..a67e1c828d0f 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -202,7 +202,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
}
if (bio->bi_iter.bi_size > PAGE_CACHE_SIZE * 8)
- path->reada = 2;
+ path->reada = READA_FORWARD;
WARN_ON(bio->bi_vcnt <= 0);
@@ -328,7 +328,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
if (search_commit) {
path->skip_locking = 1;
- path->reada = 2;
+ path->reada = READA_FORWARD;
path->search_commit_root = 1;
}
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e3d9022bfd4e..83d7859d7619 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1394,7 +1394,7 @@ lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages,
if (start_pos < inode->i_size) {
struct btrfs_ordered_extent *ordered;
lock_extent_bits(&BTRFS_I(inode)->io_tree,
- start_pos, last_pos, 0, cached_state);
+ start_pos, last_pos, cached_state);
ordered = btrfs_lookup_ordered_range(inode, start_pos,
last_pos - start_pos + 1);
if (ordered &&
@@ -2398,7 +2398,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
truncate_pagecache_range(inode, lockstart, lockend);
lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
- 0, &cached_state);
+ &cached_state);
ordered = btrfs_lookup_first_ordered_extent(inode, lockend);
/*
@@ -2705,7 +2705,7 @@ static long btrfs_fallocate(struct file *file, int mode,
* transaction
*/
lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start,
- locked_end, 0, &cached_state);
+ locked_end, &cached_state);
ordered = btrfs_lookup_first_ordered_extent(inode,
alloc_end - 1);
if (ordered &&
@@ -2852,7 +2852,7 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
lockend--;
len = lockend - lockstart + 1;
- lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
+ lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
&cached_state);
while (start < inode->i_size) {
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index cfe99bec49de..8f835bfa1bdd 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -30,7 +30,7 @@
#include "volumes.h"
#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8)
-#define MAX_CACHE_BYTES_PER_GIG (32 * 1024)
+#define MAX_CACHE_BYTES_PER_GIG SZ_32K
struct btrfs_trim_range {
u64 start;
@@ -1086,14 +1086,11 @@ write_pinned_extent_entries(struct btrfs_root *root,
static noinline_for_stack int
write_bitmap_entries(struct btrfs_io_ctl *io_ctl, struct list_head *bitmap_list)
{
- struct list_head *pos, *n;
+ struct btrfs_free_space *entry, *next;
int ret;
/* Write out the bitmaps */
- list_for_each_safe(pos, n, bitmap_list) {
- struct btrfs_free_space *entry =
- list_entry(pos, struct btrfs_free_space, list);
-
+ list_for_each_entry_safe(entry, next, bitmap_list, list) {
ret = io_ctl_add_bitmap(io_ctl, entry->bitmap);
if (ret)
return -ENOSPC;
@@ -1119,13 +1116,10 @@ static int flush_dirty_cache(struct inode *inode)
static void noinline_for_stack
cleanup_bitmap_list(struct list_head *bitmap_list)
{
- struct list_head *pos, *n;
+ struct btrfs_free_space *entry, *next;
- list_for_each_safe(pos, n, bitmap_list) {
- struct btrfs_free_space *entry =
- list_entry(pos, struct btrfs_free_space, list);
+ list_for_each_entry_safe(entry, next, bitmap_list, list)
list_del_init(&entry->list);
- }
}
static void noinline_for_stack
@@ -1261,7 +1255,7 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
goto out;
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
- 0, &cached_state);
+ &cached_state);
io_ctl_set_generation(io_ctl, trans->transid);
@@ -1656,11 +1650,10 @@ static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
* at or below 32k, so we need to adjust how much memory we allow to be
* used by extent based free space tracking
*/
- if (size < 1024 * 1024 * 1024)
+ if (size < SZ_1G)
max_bytes = MAX_CACHE_BYTES_PER_GIG;
else
- max_bytes = MAX_CACHE_BYTES_PER_GIG *
- div_u64(size, 1024 * 1024 * 1024);
+ max_bytes = MAX_CACHE_BYTES_PER_GIG * div_u64(size, SZ_1G);
/*
* we want to account for 1 more bitmap than what we have so we can make
@@ -2016,7 +2009,7 @@ static bool use_bitmap(struct btrfs_free_space_ctl *ctl,
return true;
}
-static struct btrfs_free_space_op free_space_op = {
+static const struct btrfs_free_space_op free_space_op = {
.recalc_thresholds = recalculate_thresholds,
.use_bitmap = use_bitmap,
};
@@ -2489,8 +2482,7 @@ void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group)
* track of free space, and if we pass 1/2 of that we want to
* start converting things over to using bitmaps
*/
- ctl->extents_thresh = ((1024 * 32) / 2) /
- sizeof(struct btrfs_free_space);
+ ctl->extents_thresh = (SZ_32K / 2) / sizeof(struct btrfs_free_space);
}
/*
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index f251865eb6f3..33178c490ace 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -37,7 +37,7 @@ struct btrfs_free_space_ctl {
int total_bitmaps;
int unit;
u64 start;
- struct btrfs_free_space_op *op;
+ const struct btrfs_free_space_op *op;
void *private;
struct mutex cache_writeout_mutex;
struct list_head trimming_ranges;
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
new file mode 100644
index 000000000000..393e36bd5845
--- /dev/null
+++ b/fs/btrfs/free-space-tree.c
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (C) 2015 Facebook. 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 v2 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include "ctree.h"
+#include "disk-io.h"
+#include "locking.h"
+#include "free-space-tree.h"
+#include "transaction.h"
+
+static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path);
+
+void set_free_space_tree_thresholds(struct btrfs_block_group_cache *cache)
+{
+ u32 bitmap_range;
+ size_t bitmap_size;
+ u64 num_bitmaps, total_bitmap_size;
+
+ /*
+ * We convert to bitmaps when the disk space required for using extents
+ * exceeds that required for using bitmaps.
+ */
+ bitmap_range = cache->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS;
+ num_bitmaps = div_u64(cache->key.offset + bitmap_range - 1,
+ bitmap_range);
+ bitmap_size = sizeof(struct btrfs_item) + BTRFS_FREE_SPACE_BITMAP_SIZE;
+ total_bitmap_size = num_bitmaps * bitmap_size;
+ cache->bitmap_high_thresh = div_u64(total_bitmap_size,
+ sizeof(struct btrfs_item));
+
+ /*
+ * We allow for a small buffer between the high threshold and low
+ * threshold to avoid thrashing back and forth between the two formats.
+ */
+ if (cache->bitmap_high_thresh > 100)
+ cache->bitmap_low_thresh = cache->bitmap_high_thresh - 100;
+ else
+ cache->bitmap_low_thresh = 0;
+}
+
+static int add_new_free_space_info(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_free_space_info *info;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ int ret;
+
+ key.objectid = block_group->key.objectid;
+ key.type = BTRFS_FREE_SPACE_INFO_KEY;
+ key.offset = block_group->key.offset;
+
+ ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*info));
+ if (ret)
+ goto out;
+
+ leaf = path->nodes[0];
+ info = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_free_space_info);
+ btrfs_set_free_space_extent_count(leaf, info, 0);
+ btrfs_set_free_space_flags(leaf, info, 0);
+ btrfs_mark_buffer_dirty(leaf);
+
+ ret = 0;
+out:
+ btrfs_release_path(path);
+ return ret;
+}
+
+struct btrfs_free_space_info *
+search_free_space_info(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, int cow)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_key key;
+ int ret;
+
+ key.objectid = block_group->key.objectid;
+ key.type = BTRFS_FREE_SPACE_INFO_KEY;
+ key.offset = block_group->key.offset;
+
+ ret = btrfs_search_slot(trans, root, &key, path, 0, cow);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ if (ret != 0) {
+ btrfs_warn(fs_info, "missing free space info for %llu\n",
+ block_group->key.objectid);
+ ASSERT(0);
+ return ERR_PTR(-ENOENT);
+ }
+
+ return btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_free_space_info);
+}
+
+/*
+ * btrfs_search_slot() but we're looking for the greatest key less than the
+ * passed key.
+ */
+static int btrfs_search_prev_slot(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_key *key, struct btrfs_path *p,
+ int ins_len, int cow)
+{
+ int ret;
+
+ ret = btrfs_search_slot(trans, root, key, p, ins_len, cow);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0) {
+ ASSERT(0);
+ return -EIO;
+ }
+
+ if (p->slots[0] == 0) {
+ ASSERT(0);
+ return -EIO;
+ }
+ p->slots[0]--;
+
+ return 0;
+}
+
+static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize)
+{
+ return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE);
+}
+
+static unsigned long *alloc_bitmap(u32 bitmap_size)
+{
+ return __vmalloc(bitmap_size, GFP_NOFS | __GFP_HIGHMEM | __GFP_ZERO,
+ PAGE_KERNEL);
+}
+
+int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_free_space_info *info;
+ struct btrfs_key key, found_key;
+ struct extent_buffer *leaf;
+ unsigned long *bitmap;
+ char *bitmap_cursor;
+ u64 start, end;
+ u64 bitmap_range, i;
+ u32 bitmap_size, flags, expected_extent_count;
+ u32 extent_count = 0;
+ int done = 0, nr;
+ int ret;
+
+ bitmap_size = free_space_bitmap_size(block_group->key.offset,
+ block_group->sectorsize);
+ bitmap = alloc_bitmap(bitmap_size);
+ if (!bitmap) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ start = block_group->key.objectid;
+ end = block_group->key.objectid + block_group->key.offset;
+
+ key.objectid = end - 1;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ while (!done) {
+ ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
+ if (ret)
+ goto out;
+
+ leaf = path->nodes[0];
+ nr = 0;
+ path->slots[0]++;
+ while (path->slots[0] > 0) {
+ btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1);
+
+ if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
+ ASSERT(found_key.objectid == block_group->key.objectid);
+ ASSERT(found_key.offset == block_group->key.offset);
+ done = 1;
+ break;
+ } else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY) {
+ u64 first, last;
+
+ ASSERT(found_key.objectid >= start);
+ ASSERT(found_key.objectid < end);
+ ASSERT(found_key.objectid + found_key.offset <= end);
+
+ first = div_u64(found_key.objectid - start,
+ block_group->sectorsize);
+ last = div_u64(found_key.objectid + found_key.offset - start,
+ block_group->sectorsize);
+ bitmap_set(bitmap, first, last - first);
+
+ extent_count++;
+ nr++;
+ path->slots[0]--;
+ } else {
+ ASSERT(0);
+ }
+ }
+
+ ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
+ if (ret)
+ goto out;
+ btrfs_release_path(path);
+ }
+
+ info = search_free_space_info(trans, fs_info, block_group, path, 1);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+ goto out;
+ }
+ leaf = path->nodes[0];
+ flags = btrfs_free_space_flags(leaf, info);
+ flags |= BTRFS_FREE_SPACE_USING_BITMAPS;
+ btrfs_set_free_space_flags(leaf, info, flags);
+ expected_extent_count = btrfs_free_space_extent_count(leaf, info);
+ btrfs_mark_buffer_dirty(leaf);
+ btrfs_release_path(path);
+
+ if (extent_count != expected_extent_count) {
+ btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
+ block_group->key.objectid, extent_count,
+ expected_extent_count);
+ ASSERT(0);
+ ret = -EIO;
+ goto out;
+ }
+
+ bitmap_cursor = (char *)bitmap;
+ bitmap_range = block_group->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS;
+ i = start;
+ while (i < end) {
+ unsigned long ptr;
+ u64 extent_size;
+ u32 data_size;
+
+ extent_size = min(end - i, bitmap_range);
+ data_size = free_space_bitmap_size(extent_size,
+ block_group->sectorsize);
+
+ key.objectid = i;
+ key.type = BTRFS_FREE_SPACE_BITMAP_KEY;
+ key.offset = extent_size;
+
+ ret = btrfs_insert_empty_item(trans, root, path, &key,
+ data_size);
+ if (ret)
+ goto out;
+
+ leaf = path->nodes[0];
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+ write_extent_buffer(leaf, bitmap_cursor, ptr,
+ data_size);
+ btrfs_mark_buffer_dirty(leaf);
+ btrfs_release_path(path);
+
+ i += extent_size;
+ bitmap_cursor += data_size;
+ }
+
+ ret = 0;
+out:
+ vfree(bitmap);
+ if (ret)
+ btrfs_abort_transaction(trans, root, ret);
+ return ret;
+}
+
+int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_free_space_info *info;
+ struct btrfs_key key, found_key;
+ struct extent_buffer *leaf;
+ unsigned long *bitmap;
+ u64 start, end;
+ /* Initialize to silence GCC. */
+ u64 extent_start = 0;
+ u64 offset;
+ u32 bitmap_size, flags, expected_extent_count;
+ int prev_bit = 0, bit, bitnr;
+ u32 extent_count = 0;
+ int done = 0, nr;
+ int ret;
+
+ bitmap_size = free_space_bitmap_size(block_group->key.offset,
+ block_group->sectorsize);
+ bitmap = alloc_bitmap(bitmap_size);
+ if (!bitmap) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ start = block_group->key.objectid;
+ end = block_group->key.objectid + block_group->key.offset;
+
+ key.objectid = end - 1;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ while (!done) {
+ ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
+ if (ret)
+ goto out;
+
+ leaf = path->nodes[0];
+ nr = 0;
+ path->slots[0]++;
+ while (path->slots[0] > 0) {
+ btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1);
+
+ if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
+ ASSERT(found_key.objectid == block_group->key.objectid);
+ ASSERT(found_key.offset == block_group->key.offset);
+ done = 1;
+ break;
+ } else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) {
+ unsigned long ptr;
+ char *bitmap_cursor;
+ u32 bitmap_pos, data_size;
+
+ ASSERT(found_key.objectid >= start);
+ ASSERT(found_key.objectid < end);
+ ASSERT(found_key.objectid + found_key.offset <= end);
+
+ bitmap_pos = div_u64(found_key.objectid - start,
+ block_group->sectorsize *
+ BITS_PER_BYTE);
+ bitmap_cursor = ((char *)bitmap) + bitmap_pos;
+ data_size = free_space_bitmap_size(found_key.offset,
+ block_group->sectorsize);
+
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0] - 1);
+ read_extent_buffer(leaf, bitmap_cursor, ptr,
+ data_size);
+
+ nr++;
+ path->slots[0]--;
+ } else {
+ ASSERT(0);
+ }
+ }
+
+ ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
+ if (ret)
+ goto out;
+ btrfs_release_path(path);
+ }
+
+ info = search_free_space_info(trans, fs_info, block_group, path, 1);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+ goto out;
+ }
+ leaf = path->nodes[0];
+ flags = btrfs_free_space_flags(leaf, info);
+ flags &= ~BTRFS_FREE_SPACE_USING_BITMAPS;
+ btrfs_set_free_space_flags(leaf, info, flags);
+ expected_extent_count = btrfs_free_space_extent_count(leaf, info);
+ btrfs_mark_buffer_dirty(leaf);
+ btrfs_release_path(path);
+
+ offset = start;
+ bitnr = 0;
+ while (offset < end) {
+ bit = !!test_bit(bitnr, bitmap);
+ if (prev_bit == 0 && bit == 1) {
+ extent_start = offset;
+ } else if (prev_bit == 1 && bit == 0) {
+ key.objectid = extent_start;
+ key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
+ key.offset = offset - extent_start;
+
+ ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
+ if (ret)
+ goto out;
+ btrfs_release_path(path);
+
+ extent_count++;
+ }
+ prev_bit = bit;
+ offset += block_group->sectorsize;
+ bitnr++;
+ }
+ if (prev_bit == 1) {
+ key.objectid = extent_start;
+ key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
+ key.offset = end - extent_start;
+
+ ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
+ if (ret)
+ goto out;
+ btrfs_release_path(path);
+
+ extent_count++;
+ }
+
+ if (extent_count != expected_extent_count) {
+ btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
+ block_group->key.objectid, extent_count,
+ expected_extent_count);
+ ASSERT(0);
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ vfree(bitmap);
+ if (ret)
+ btrfs_abort_transaction(trans, root, ret);
+ return ret;
+}
+
+static int update_free_space_extent_count(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path,
+ int new_extents)
+{
+ struct btrfs_free_space_info *info;
+ u32 flags;
+ u32 extent_count;
+ int ret = 0;
+
+ if (new_extents == 0)
+ return 0;
+
+ info = search_free_space_info(trans, fs_info, block_group, path, 1);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+ goto out;
+ }
+ flags = btrfs_free_space_flags(path->nodes[0], info);
+ extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
+
+ extent_count += new_extents;
+ btrfs_set_free_space_extent_count(path->nodes[0], info, extent_count);
+ btrfs_mark_buffer_dirty(path->nodes[0]);
+ btrfs_release_path(path);
+
+ if (!(flags & BTRFS_FREE_SPACE_USING_BITMAPS) &&
+ extent_count > block_group->bitmap_high_thresh) {
+ ret = convert_free_space_to_bitmaps(trans, fs_info, block_group,
+ path);
+ } else if ((flags & BTRFS_FREE_SPACE_USING_BITMAPS) &&
+ extent_count < block_group->bitmap_low_thresh) {
+ ret = convert_free_space_to_extents(trans, fs_info, block_group,
+ path);
+ }
+
+out:
+ return ret;
+}
+
+int free_space_test_bit(struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 offset)
+{
+ struct extent_buffer *leaf;
+ struct btrfs_key key;
+ u64 found_start, found_end;
+ unsigned long ptr, i;
+
+ leaf = path->nodes[0];
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);
+
+ found_start = key.objectid;
+ found_end = key.objectid + key.offset;
+ ASSERT(offset >= found_start && offset < found_end);
+
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+ i = div_u64(offset - found_start, block_group->sectorsize);
+ return !!extent_buffer_test_bit(leaf, ptr, i);
+}
+
+static void free_space_set_bits(struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 *start, u64 *size,
+ int bit)
+{
+ struct extent_buffer *leaf;
+ struct btrfs_key key;
+ u64 end = *start + *size;
+ u64 found_start, found_end;
+ unsigned long ptr, first, last;
+
+ leaf = path->nodes[0];
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);
+
+ found_start = key.objectid;
+ found_end = key.objectid + key.offset;
+ ASSERT(*start >= found_start && *start < found_end);
+ ASSERT(end > found_start);
+
+ if (end > found_end)
+ end = found_end;
+
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+ first = div_u64(*start - found_start, block_group->sectorsize);
+ last = div_u64(end - found_start, block_group->sectorsize);
+ if (bit)
+ extent_buffer_bitmap_set(leaf, ptr, first, last - first);
+ else
+ extent_buffer_bitmap_clear(leaf, ptr, first, last - first);
+ btrfs_mark_buffer_dirty(leaf);
+
+ *size -= end - *start;
+ *start = end;
+}
+
+/*
+ * We can't use btrfs_next_item() in modify_free_space_bitmap() because
+ * btrfs_next_leaf() doesn't get the path for writing. We can forgo the fancy
+ * tree walking in btrfs_next_leaf() anyways because we know exactly what we're
+ * looking for.
+ */
+static int free_space_next_bitmap(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_path *p)
+{
+ struct btrfs_key key;
+
+ if (p->slots[0] + 1 < btrfs_header_nritems(p->nodes[0])) {
+ p->slots[0]++;
+ return 0;
+ }
+
+ btrfs_item_key_to_cpu(p->nodes[0], &key, p->slots[0]);
+ btrfs_release_path(p);
+
+ key.objectid += key.offset;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ return btrfs_search_prev_slot(trans, root, &key, p, 0, 1);
+}
+
+/*
+ * If remove is 1, then we are removing free space, thus clearing bits in the
+ * bitmap. If remove is 0, then we are adding free space, thus setting bits in
+ * the bitmap.
+ */
+static int modify_free_space_bitmap(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path,
+ u64 start, u64 size, int remove)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_key key;
+ u64 end = start + size;
+ u64 cur_start, cur_size;
+ int prev_bit, next_bit;
+ int new_extents;
+ int ret;
+
+ /*
+ * Read the bit for the block immediately before the extent of space if
+ * that block is within the block group.
+ */
+ if (start > block_group->key.objectid) {
+ u64 prev_block = start - block_group->sectorsize;
+
+ key.objectid = prev_block;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_prev_slot(trans, root, &key, path, 0, 1);
+ if (ret)
+ goto out;
+
+ prev_bit = free_space_test_bit(block_group, path, prev_block);
+
+ /* The previous block may have been in the previous bitmap. */
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (start >= key.objectid + key.offset) {
+ ret = free_space_next_bitmap(trans, root, path);
+ if (ret)
+ goto out;
+ }
+ } else {
+ key.objectid = start;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_prev_slot(trans, root, &key, path, 0, 1);
+ if (ret)
+ goto out;
+
+ prev_bit = -1;
+ }
+
+ /*
+ * Iterate over all of the bitmaps overlapped by the extent of space,
+ * clearing/setting bits as required.
+ */
+ cur_start = start;
+ cur_size = size;
+ while (1) {
+ free_space_set_bits(block_group, path, &cur_start, &cur_size,
+ !remove);
+ if (cur_size == 0)
+ break;
+ ret = free_space_next_bitmap(trans, root, path);
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * Read the bit for the block immediately after the extent of space if
+ * that block is within the block group.
+ */
+ if (end < block_group->key.objectid + block_group->key.offset) {
+ /* The next block may be in the next bitmap. */
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (end >= key.objectid + key.offset) {
+ ret = free_space_next_bitmap(trans, root, path);
+ if (ret)
+ goto out;
+ }
+
+ next_bit = free_space_test_bit(block_group, path, end);
+ } else {
+ next_bit = -1;
+ }
+
+ if (remove) {
+ new_extents = -1;
+ if (prev_bit == 1) {
+ /* Leftover on the left. */
+ new_extents++;
+ }
+ if (next_bit == 1) {
+ /* Leftover on the right. */
+ new_extents++;
+ }
+ } else {
+ new_extents = 1;
+ if (prev_bit == 1) {
+ /* Merging with neighbor on the left. */
+ new_extents--;
+ }
+ if (next_bit == 1) {
+ /* Merging with neighbor on the right. */
+ new_extents--;
+ }
+ }
+
+ btrfs_release_path(path);
+ ret = update_free_space_extent_count(trans, fs_info, block_group, path,
+ new_extents);
+
+out:
+ return ret;
+}
+
+static int remove_free_space_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path,
+ u64 start, u64 size)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_key key;
+ u64 found_start, found_end;
+ u64 end = start + size;
+ int new_extents = -1;
+ int ret;
+
+ key.objectid = start;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
+ if (ret)
+ goto out;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+
+ ASSERT(key.type == BTRFS_FREE_SPACE_EXTENT_KEY);
+
+ found_start = key.objectid;
+ found_end = key.objectid + key.offset;
+ ASSERT(start >= found_start && end <= found_end);
+
+ /*
+ * Okay, now that we've found the free space extent which contains the
+ * free space that we are removing, there are four cases:
+ *
+ * 1. We're using the whole extent: delete the key we found and
+ * decrement the free space extent count.
+ * 2. We are using part of the extent starting at the beginning: delete
+ * the key we found and insert a new key representing the leftover at
+ * the end. There is no net change in the number of extents.
+ * 3. We are using part of the extent ending at the end: delete the key
+ * we found and insert a new key representing the leftover at the
+ * beginning. There is no net change in the number of extents.
+ * 4. We are using part of the extent in the middle: delete the key we
+ * found and insert two new keys representing the leftovers on each
+ * side. Where we used to have one extent, we now have two, so increment
+ * the extent count. We may need to convert the block group to bitmaps
+ * as a result.
+ */
+
+ /* Delete the existing key (cases 1-4). */
+ ret = btrfs_del_item(trans, root, path);
+ if (ret)
+ goto out;
+
+ /* Add a key for leftovers at the beginning (cases 3 and 4). */
+ if (start > found_start) {
+ key.objectid = found_start;
+ key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
+ key.offset = start - found_start;
+
+ btrfs_release_path(path);
+ ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
+ if (ret)
+ goto out;
+ new_extents++;
+ }
+
+ /* Add a key for leftovers at the end (cases 2 and 4). */
+ if (end < found_end) {
+ key.objectid = end;
+ key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
+ key.offset = found_end - end;
+
+ btrfs_release_path(path);
+ ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
+ if (ret)
+ goto out;
+ new_extents++;
+ }
+
+ btrfs_release_path(path);
+ ret = update_free_space_extent_count(trans, fs_info, block_group, path,
+ new_extents);
+
+out:
+ return ret;
+}
+
+int __remove_from_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 start, u64 size)
+{
+ struct btrfs_free_space_info *info;
+ u32 flags;
+ int ret;
+
+ if (block_group->needs_free_space) {
+ ret = __add_block_group_free_space(trans, fs_info, block_group,
+ path);
+ if (ret)
+ return ret;
+ }
+
+ info = search_free_space_info(NULL, fs_info, block_group, path, 0);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+ flags = btrfs_free_space_flags(path->nodes[0], info);
+ btrfs_release_path(path);
+
+ if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
+ return modify_free_space_bitmap(trans, fs_info, block_group,
+ path, start, size, 1);
+ } else {
+ return remove_free_space_extent(trans, fs_info, block_group,
+ path, start, size);
+ }
+}
+
+int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 start, u64 size)
+{
+ struct btrfs_block_group_cache *block_group;
+ struct btrfs_path *path;
+ int ret;
+
+ if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ return 0;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ block_group = btrfs_lookup_block_group(fs_info, start);
+ if (!block_group) {
+ ASSERT(0);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ mutex_lock(&block_group->free_space_lock);
+ ret = __remove_from_free_space_tree(trans, fs_info, block_group, path,
+ start, size);
+ mutex_unlock(&block_group->free_space_lock);
+
+ btrfs_put_block_group(block_group);
+out:
+ btrfs_free_path(path);
+ if (ret)
+ btrfs_abort_transaction(trans, fs_info->free_space_root, ret);
+ return ret;
+}
+
+static int add_free_space_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path,
+ u64 start, u64 size)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_key key, new_key;
+ u64 found_start, found_end;
+ u64 end = start + size;
+ int new_extents = 1;
+ int ret;
+
+ /*
+ * We are adding a new extent of free space, but we need to merge
+ * extents. There are four cases here:
+ *
+ * 1. The new extent does not have any immediate neighbors to merge
+ * with: add the new key and increment the free space extent count. We
+ * may need to convert the block group to bitmaps as a result.
+ * 2. The new extent has an immediate neighbor before it: remove the
+ * previous key and insert a new key combining both of them. There is no
+ * net change in the number of extents.
+ * 3. The new extent has an immediate neighbor after it: remove the next
+ * key and insert a new key combining both of them. There is no net
+ * change in the number of extents.
+ * 4. The new extent has immediate neighbors on both sides: remove both
+ * of the keys and insert a new key combining all of them. Where we used
+ * to have two extents, we now have one, so decrement the extent count.
+ */
+
+ new_key.objectid = start;
+ new_key.type = BTRFS_FREE_SPACE_EXTENT_KEY;
+ new_key.offset = size;
+
+ /* Search for a neighbor on the left. */
+ if (start == block_group->key.objectid)
+ goto right;
+ key.objectid = start - 1;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
+ if (ret)
+ goto out;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+
+ if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY) {
+ ASSERT(key.type == BTRFS_FREE_SPACE_INFO_KEY);
+ btrfs_release_path(path);
+ goto right;
+ }
+
+ found_start = key.objectid;
+ found_end = key.objectid + key.offset;
+ ASSERT(found_start >= block_group->key.objectid &&
+ found_end > block_group->key.objectid);
+ ASSERT(found_start < start && found_end <= start);
+
+ /*
+ * Delete the neighbor on the left and absorb it into the new key (cases
+ * 2 and 4).
+ */
+ if (found_end == start) {
+ ret = btrfs_del_item(trans, root, path);
+ if (ret)
+ goto out;
+ new_key.objectid = found_start;
+ new_key.offset += key.offset;
+ new_extents--;
+ }
+ btrfs_release_path(path);
+
+right:
+ /* Search for a neighbor on the right. */
+ if (end == block_group->key.objectid + block_group->key.offset)
+ goto insert;
+ key.objectid = end;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
+ if (ret)
+ goto out;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+
+ if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY) {
+ ASSERT(key.type == BTRFS_FREE_SPACE_INFO_KEY);
+ btrfs_release_path(path);
+ goto insert;
+ }
+
+ found_start = key.objectid;
+ found_end = key.objectid + key.offset;
+ ASSERT(found_start >= block_group->key.objectid &&
+ found_end > block_group->key.objectid);
+ ASSERT((found_start < start && found_end <= start) ||
+ (found_start >= end && found_end > end));
+
+ /*
+ * Delete the neighbor on the right and absorb it into the new key
+ * (cases 3 and 4).
+ */
+ if (found_start == end) {
+ ret = btrfs_del_item(trans, root, path);
+ if (ret)
+ goto out;
+ new_key.offset += key.offset;
+ new_extents--;
+ }
+ btrfs_release_path(path);
+
+insert:
+ /* Insert the new key (cases 1-4). */
+ ret = btrfs_insert_empty_item(trans, root, path, &new_key, 0);
+ if (ret)
+ goto out;
+
+ btrfs_release_path(path);
+ ret = update_free_space_extent_count(trans, fs_info, block_group, path,
+ new_extents);
+
+out:
+ return ret;
+}
+
+int __add_to_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 start, u64 size)
+{
+ struct btrfs_free_space_info *info;
+ u32 flags;
+ int ret;
+
+ if (block_group->needs_free_space) {
+ ret = __add_block_group_free_space(trans, fs_info, block_group,
+ path);
+ if (ret)
+ return ret;
+ }
+
+ info = search_free_space_info(NULL, fs_info, block_group, path, 0);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+ flags = btrfs_free_space_flags(path->nodes[0], info);
+ btrfs_release_path(path);
+
+ if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
+ return modify_free_space_bitmap(trans, fs_info, block_group,
+ path, start, size, 0);
+ } else {
+ return add_free_space_extent(trans, fs_info, block_group, path,
+ start, size);
+ }
+}
+
+int add_to_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 start, u64 size)
+{
+ struct btrfs_block_group_cache *block_group;
+ struct btrfs_path *path;
+ int ret;
+
+ if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ return 0;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ block_group = btrfs_lookup_block_group(fs_info, start);
+ if (!block_group) {
+ ASSERT(0);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ mutex_lock(&block_group->free_space_lock);
+ ret = __add_to_free_space_tree(trans, fs_info, block_group, path, start,
+ size);
+ mutex_unlock(&block_group->free_space_lock);
+
+ btrfs_put_block_group(block_group);
+out:
+ btrfs_free_path(path);
+ if (ret)
+ btrfs_abort_transaction(trans, fs_info->free_space_root, ret);
+ return ret;
+}
+
+/*
+ * Populate the free space tree by walking the extent tree. Operations on the
+ * extent tree that happen as a result of writes to the free space tree will go
+ * through the normal add/remove hooks.
+ */
+static int populate_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group)
+{
+ struct btrfs_root *extent_root = fs_info->extent_root;
+ struct btrfs_path *path, *path2;
+ struct btrfs_key key;
+ u64 start, end;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ path->reada = 1;
+
+ path2 = btrfs_alloc_path();
+ if (!path2) {
+ btrfs_free_path(path);
+ return -ENOMEM;
+ }
+
+ ret = add_new_free_space_info(trans, fs_info, block_group, path2);
+ if (ret)
+ goto out;
+
+ mutex_lock(&block_group->free_space_lock);
+
+ /*
+ * Iterate through all of the extent and metadata items in this block
+ * group, adding the free space between them and the free space at the
+ * end. Note that EXTENT_ITEM and METADATA_ITEM are less than
+ * BLOCK_GROUP_ITEM, so an extent may precede the block group that it's
+ * contained in.
+ */
+ key.objectid = block_group->key.objectid;
+ key.type = BTRFS_EXTENT_ITEM_KEY;
+ key.offset = 0;
+
+ ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0);
+ if (ret < 0)
+ goto out_locked;
+ ASSERT(ret == 0);
+
+ start = block_group->key.objectid;
+ end = block_group->key.objectid + block_group->key.offset;
+ while (1) {
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+
+ if (key.type == BTRFS_EXTENT_ITEM_KEY ||
+ key.type == BTRFS_METADATA_ITEM_KEY) {
+ if (key.objectid >= end)
+ break;
+
+ if (start < key.objectid) {
+ ret = __add_to_free_space_tree(trans, fs_info,
+ block_group,
+ path2, start,
+ key.objectid -
+ start);
+ if (ret)
+ goto out_locked;
+ }
+ start = key.objectid;
+ if (key.type == BTRFS_METADATA_ITEM_KEY)
+ start += fs_info->tree_root->nodesize;
+ else
+ start += key.offset;
+ } else if (key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
+ if (key.objectid != block_group->key.objectid)
+ break;
+ }
+
+ ret = btrfs_next_item(extent_root, path);
+ if (ret < 0)
+ goto out_locked;
+ if (ret)
+ break;
+ }
+ if (start < end) {
+ ret = __add_to_free_space_tree(trans, fs_info, block_group,
+ path2, start, end - start);
+ if (ret)
+ goto out_locked;
+ }
+
+ ret = 0;
+out_locked:
+ mutex_unlock(&block_group->free_space_lock);
+out:
+ btrfs_free_path(path2);
+ btrfs_free_path(path);
+ return ret;
+}
+
+int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_root *tree_root = fs_info->tree_root;
+ struct btrfs_root *free_space_root;
+ struct btrfs_block_group_cache *block_group;
+ struct rb_node *node;
+ int ret;
+
+ trans = btrfs_start_transaction(tree_root, 0);
+ if (IS_ERR(trans))
+ return PTR_ERR(trans);
+
+ fs_info->creating_free_space_tree = 1;
+ free_space_root = btrfs_create_tree(trans, fs_info,
+ BTRFS_FREE_SPACE_TREE_OBJECTID);
+ if (IS_ERR(free_space_root)) {
+ ret = PTR_ERR(free_space_root);
+ goto abort;
+ }
+ fs_info->free_space_root = free_space_root;
+
+ node = rb_first(&fs_info->block_group_cache_tree);
+ while (node) {
+ block_group = rb_entry(node, struct btrfs_block_group_cache,
+ cache_node);
+ ret = populate_free_space_tree(trans, fs_info, block_group);
+ if (ret)
+ goto abort;
+ node = rb_next(node);
+ }
+
+ btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
+ fs_info->creating_free_space_tree = 0;
+
+ ret = btrfs_commit_transaction(trans, tree_root);
+ if (ret)
+ return ret;
+
+ return 0;
+
+abort:
+ fs_info->creating_free_space_tree = 0;
+ btrfs_abort_transaction(trans, tree_root, ret);
+ btrfs_end_transaction(trans, tree_root);
+ return ret;
+}
+
+static int clear_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ int nr;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ path->leave_spinning = 1;
+
+ key.objectid = 0;
+ key.type = 0;
+ key.offset = 0;
+
+ while (1) {
+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+ if (ret < 0)
+ goto out;
+
+ nr = btrfs_header_nritems(path->nodes[0]);
+ if (!nr)
+ break;
+
+ path->slots[0] = 0;
+ ret = btrfs_del_items(trans, root, path, 0, nr);
+ if (ret)
+ goto out;
+
+ btrfs_release_path(path);
+ }
+
+ ret = 0;
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_root *tree_root = fs_info->tree_root;
+ struct btrfs_root *free_space_root = fs_info->free_space_root;
+ int ret;
+
+ trans = btrfs_start_transaction(tree_root, 0);
+ if (IS_ERR(trans))
+ return PTR_ERR(trans);
+
+ btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE);
+ fs_info->free_space_root = NULL;
+
+ ret = clear_free_space_tree(trans, free_space_root);
+ if (ret)
+ goto abort;
+
+ ret = btrfs_del_root(trans, tree_root, &free_space_root->root_key);
+ if (ret)
+ goto abort;
+
+ list_del(&free_space_root->dirty_list);
+
+ btrfs_tree_lock(free_space_root->node);
+ clean_tree_block(trans, tree_root->fs_info, free_space_root->node);
+ btrfs_tree_unlock(free_space_root->node);
+ btrfs_free_tree_block(trans, free_space_root, free_space_root->node,
+ 0, 1);
+
+ free_extent_buffer(free_space_root->node);
+ free_extent_buffer(free_space_root->commit_root);
+ kfree(free_space_root);
+
+ ret = btrfs_commit_transaction(trans, tree_root);
+ if (ret)
+ return ret;
+
+ return 0;
+
+abort:
+ btrfs_abort_transaction(trans, tree_root, ret);
+ btrfs_end_transaction(trans, tree_root);
+ return ret;
+}
+
+static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path)
+{
+ u64 start, end;
+ int ret;
+
+ start = block_group->key.objectid;
+ end = block_group->key.objectid + block_group->key.offset;
+
+ block_group->needs_free_space = 0;
+
+ ret = add_new_free_space_info(trans, fs_info, block_group, path);
+ if (ret)
+ return ret;
+
+ return __add_to_free_space_tree(trans, fs_info, block_group, path,
+ block_group->key.objectid,
+ block_group->key.offset);
+}
+
+int add_block_group_free_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group)
+{
+ struct btrfs_path *path = NULL;
+ int ret = 0;
+
+ if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ return 0;
+
+ mutex_lock(&block_group->free_space_lock);
+ if (!block_group->needs_free_space)
+ goto out;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = __add_block_group_free_space(trans, fs_info, block_group, path);
+
+out:
+ btrfs_free_path(path);
+ mutex_unlock(&block_group->free_space_lock);
+ if (ret)
+ btrfs_abort_transaction(trans, fs_info->free_space_root, ret);
+ return ret;
+}
+
+int remove_block_group_free_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group)
+{
+ struct btrfs_root *root = fs_info->free_space_root;
+ struct btrfs_path *path;
+ struct btrfs_key key, found_key;
+ struct extent_buffer *leaf;
+ u64 start, end;
+ int done = 0, nr;
+ int ret;
+
+ if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
+ return 0;
+
+ if (block_group->needs_free_space) {
+ /* We never added this block group to the free space tree. */
+ return 0;
+ }
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ start = block_group->key.objectid;
+ end = block_group->key.objectid + block_group->key.offset;
+
+ key.objectid = end - 1;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ while (!done) {
+ ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
+ if (ret)
+ goto out;
+
+ leaf = path->nodes[0];
+ nr = 0;
+ path->slots[0]++;
+ while (path->slots[0] > 0) {
+ btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1);
+
+ if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
+ ASSERT(found_key.objectid == block_group->key.objectid);
+ ASSERT(found_key.offset == block_group->key.offset);
+ done = 1;
+ nr++;
+ path->slots[0]--;
+ break;
+ } else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY ||
+ found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) {
+ ASSERT(found_key.objectid >= start);
+ ASSERT(found_key.objectid < end);
+ ASSERT(found_key.objectid + found_key.offset <= end);
+ nr++;
+ path->slots[0]--;
+ } else {
+ ASSERT(0);
+ }
+ }
+
+ ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
+ if (ret)
+ goto out;
+ btrfs_release_path(path);
+ }
+
+ ret = 0;
+out:
+ btrfs_free_path(path);
+ if (ret)
+ btrfs_abort_transaction(trans, root, ret);
+ return ret;
+}
+
+static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl,
+ struct btrfs_path *path,
+ u32 expected_extent_count)
+{
+ struct btrfs_block_group_cache *block_group;
+ struct btrfs_fs_info *fs_info;
+ struct btrfs_root *root;
+ struct btrfs_key key;
+ int prev_bit = 0, bit;
+ /* Initialize to silence GCC. */
+ u64 extent_start = 0;
+ u64 end, offset;
+ u64 total_found = 0;
+ u32 extent_count = 0;
+ int ret;
+
+ block_group = caching_ctl->block_group;
+ fs_info = block_group->fs_info;
+ root = fs_info->free_space_root;
+
+ end = block_group->key.objectid + block_group->key.offset;
+
+ while (1) {
+ ret = btrfs_next_item(root, path);
+ if (ret < 0)
+ goto out;
+ if (ret)
+ break;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+
+ if (key.type == BTRFS_FREE_SPACE_INFO_KEY)
+ break;
+
+ ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);
+ ASSERT(key.objectid < end && key.objectid + key.offset <= end);
+
+ caching_ctl->progress = key.objectid;
+
+ offset = key.objectid;
+ while (offset < key.objectid + key.offset) {
+ bit = free_space_test_bit(block_group, path, offset);
+ if (prev_bit == 0 && bit == 1) {
+ extent_start = offset;
+ } else if (prev_bit == 1 && bit == 0) {
+ total_found += add_new_free_space(block_group,
+ fs_info,
+ extent_start,
+ offset);
+ if (total_found > CACHING_CTL_WAKE_UP) {
+ total_found = 0;
+ wake_up(&caching_ctl->wait);
+ }
+ extent_count++;
+ }
+ prev_bit = bit;
+ offset += block_group->sectorsize;
+ }
+ }
+ if (prev_bit == 1) {
+ total_found += add_new_free_space(block_group, fs_info,
+ extent_start, end);
+ extent_count++;
+ }
+
+ if (extent_count != expected_extent_count) {
+ btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
+ block_group->key.objectid, extent_count,
+ expected_extent_count);
+ ASSERT(0);
+ ret = -EIO;
+ goto out;
+ }
+
+ caching_ctl->progress = (u64)-1;
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int load_free_space_extents(struct btrfs_caching_control *caching_ctl,
+ struct btrfs_path *path,
+ u32 expected_extent_count)
+{
+ struct btrfs_block_group_cache *block_group;
+ struct btrfs_fs_info *fs_info;
+ struct btrfs_root *root;
+ struct btrfs_key key;
+ u64 end;
+ u64 total_found = 0;
+ u32 extent_count = 0;
+ int ret;
+
+ block_group = caching_ctl->block_group;
+ fs_info = block_group->fs_info;
+ root = fs_info->free_space_root;
+
+ end = block_group->key.objectid + block_group->key.offset;
+
+ while (1) {
+ ret = btrfs_next_item(root, path);
+ if (ret < 0)
+ goto out;
+ if (ret)
+ break;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+
+ if (key.type == BTRFS_FREE_SPACE_INFO_KEY)
+ break;
+
+ ASSERT(key.type == BTRFS_FREE_SPACE_EXTENT_KEY);
+ ASSERT(key.objectid < end && key.objectid + key.offset <= end);
+
+ caching_ctl->progress = key.objectid;
+
+ total_found += add_new_free_space(block_group, fs_info,
+ key.objectid,
+ key.objectid + key.offset);
+ if (total_found > CACHING_CTL_WAKE_UP) {
+ total_found = 0;
+ wake_up(&caching_ctl->wait);
+ }
+ extent_count++;
+ }
+
+ if (extent_count != expected_extent_count) {
+ btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
+ block_group->key.objectid, extent_count,
+ expected_extent_count);
+ ASSERT(0);
+ ret = -EIO;
+ goto out;
+ }
+
+ caching_ctl->progress = (u64)-1;
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
+{
+ struct btrfs_block_group_cache *block_group;
+ struct btrfs_fs_info *fs_info;
+ struct btrfs_free_space_info *info;
+ struct btrfs_path *path;
+ u32 extent_count, flags;
+ int ret;
+
+ block_group = caching_ctl->block_group;
+ fs_info = block_group->fs_info;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ /*
+ * Just like caching_thread() doesn't want to deadlock on the extent
+ * tree, we don't want to deadlock on the free space tree.
+ */
+ path->skip_locking = 1;
+ path->search_commit_root = 1;
+ path->reada = 1;
+
+ info = search_free_space_info(NULL, fs_info, block_group, path, 0);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+ goto out;
+ }
+ extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
+ flags = btrfs_free_space_flags(path->nodes[0], info);
+
+ /*
+ * We left path pointing to the free space info item, so now
+ * load_free_space_foo can just iterate through the free space tree from
+ * there.
+ */
+ if (flags & BTRFS_FREE_SPACE_USING_BITMAPS)
+ ret = load_free_space_bitmaps(caching_ctl, path, extent_count);
+ else
+ ret = load_free_space_extents(caching_ctl, path, extent_count);
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
diff --git a/fs/btrfs/free-space-tree.h b/fs/btrfs/free-space-tree.h
new file mode 100644
index 000000000000..54ffced3bce8
--- /dev/null
+++ b/fs/btrfs/free-space-tree.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 Facebook. 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 v2 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_FREE_SPACE_TREE
+#define __BTRFS_FREE_SPACE_TREE
+
+/*
+ * The default size for new free space bitmap items. The last bitmap in a block
+ * group may be truncated, and none of the free space tree code assumes that
+ * existing bitmaps are this size.
+ */
+#define BTRFS_FREE_SPACE_BITMAP_SIZE 256
+#define BTRFS_FREE_SPACE_BITMAP_BITS (BTRFS_FREE_SPACE_BITMAP_SIZE * BITS_PER_BYTE)
+
+void set_free_space_tree_thresholds(struct btrfs_block_group_cache *block_group);
+int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info);
+int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info);
+int load_free_space_tree(struct btrfs_caching_control *caching_ctl);
+int add_block_group_free_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group);
+int remove_block_group_free_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group);
+int add_to_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 start, u64 size);
+int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 start, u64 size);
+
+/* Exposed for testing. */
+struct btrfs_free_space_info *
+search_free_space_info(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, int cow);
+int __add_to_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 start, u64 size);
+int __remove_from_free_space_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 start, u64 size);
+int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path);
+int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path);
+int free_space_test_bit(struct btrfs_block_group_cache *block_group,
+ struct btrfs_path *path, u64 offset);
+
+#endif
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index 767a6056ac45..8b57c17b3fb3 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -48,7 +48,7 @@ static int caching_kthread(void *data)
/* Since the commit root is read-only, we can safely skip locking. */
path->skip_locking = 1;
path->search_commit_root = 1;
- path->reada = 2;
+ path->reada = READA_FORWARD;
key.objectid = BTRFS_FIRST_FREE_OBJECTID;
key.offset = 0;
@@ -282,7 +282,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
}
}
-#define INIT_THRESHOLD (((1024 * 32) / 2) / sizeof(struct btrfs_free_space))
+#define INIT_THRESHOLD ((SZ_32K / 2) / sizeof(struct btrfs_free_space))
#define INODES_PER_BITMAP (PAGE_CACHE_SIZE * 8)
/*
@@ -334,7 +334,7 @@ static bool use_bitmap(struct btrfs_free_space_ctl *ctl,
return true;
}
-static struct btrfs_free_space_op free_ino_op = {
+static const struct btrfs_free_space_op free_ino_op = {
.recalc_thresholds = recalculate_thresholds,
.use_bitmap = use_bitmap,
};
@@ -356,7 +356,7 @@ static bool pinned_use_bitmap(struct btrfs_free_space_ctl *ctl,
return false;
}
-static struct btrfs_free_space_op pinned_free_ino_op = {
+static const struct btrfs_free_space_op pinned_free_ino_op = {
.recalc_thresholds = pinned_recalc_thresholds,
.use_bitmap = pinned_use_bitmap,
};
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3b8856e182ae..247830107686 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -66,6 +66,13 @@ struct btrfs_iget_args {
struct btrfs_root *root;
};
+struct btrfs_dio_data {
+ u64 outstanding_extents;
+ u64 reserve;
+ u64 unsubmitted_oe_range_start;
+ u64 unsubmitted_oe_range_end;
+};
+
static const struct inode_operations btrfs_dir_inode_operations;
static const struct inode_operations btrfs_symlink_inode_operations;
static const struct inode_operations btrfs_dir_ro_inode_operations;
@@ -74,17 +81,16 @@ static const struct inode_operations btrfs_file_inode_operations;
static const struct address_space_operations btrfs_aops;
static const struct address_space_operations btrfs_symlink_aops;
static const struct file_operations btrfs_dir_file_operations;
-static struct extent_io_ops btrfs_extent_io_ops;
+static const struct extent_io_ops btrfs_extent_io_ops;
static struct kmem_cache *btrfs_inode_cachep;
-static struct kmem_cache *btrfs_delalloc_work_cachep;
struct kmem_cache *btrfs_trans_handle_cachep;
struct kmem_cache *btrfs_transaction_cachep;
struct kmem_cache *btrfs_path_cachep;
struct kmem_cache *btrfs_free_space_cachep;
#define S_SHIFT 12
-static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
+static const unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
[S_IFREG >> S_SHIFT] = BTRFS_FT_REG_FILE,
[S_IFDIR >> S_SHIFT] = BTRFS_FT_DIR,
[S_IFCHR >> S_SHIFT] = BTRFS_FT_CHRDEV,
@@ -414,15 +420,15 @@ static noinline void compress_file_range(struct inode *inode,
unsigned long nr_pages_ret = 0;
unsigned long total_compressed = 0;
unsigned long total_in = 0;
- unsigned long max_compressed = 128 * 1024;
- unsigned long max_uncompressed = 128 * 1024;
+ unsigned long max_compressed = SZ_128K;
+ unsigned long max_uncompressed = SZ_128K;
int i;
int will_compress;
int compress_type = root->fs_info->compress_type;
int redirty = 0;
/* if this is a small write inside eof, kick off a defrag */
- if ((end - start + 1) < 16 * 1024 &&
+ if ((end - start + 1) < SZ_16K &&
(start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
btrfs_add_inode_defrag(NULL, inode);
@@ -430,7 +436,7 @@ static noinline void compress_file_range(struct inode *inode,
again:
will_compress = 0;
nr_pages = (end >> PAGE_CACHE_SHIFT) - (start >> PAGE_CACHE_SHIFT) + 1;
- nr_pages = min(nr_pages, (128 * 1024UL) / PAGE_CACHE_SIZE);
+ nr_pages = min_t(unsigned long, nr_pages, SZ_128K / PAGE_CACHE_SIZE);
/*
* we don't want to send crud past the end of i_size through
@@ -944,7 +950,7 @@ static noinline int cow_file_range(struct inode *inode,
disk_num_bytes = num_bytes;
/* if this is a small write inside eof, kick off defrag */
- if (num_bytes < 64 * 1024 &&
+ if (num_bytes < SZ_64K &&
(start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
btrfs_add_inode_defrag(NULL, inode);
@@ -1107,7 +1113,7 @@ static noinline void async_cow_submit(struct btrfs_work *work)
* atomic_sub_return implies a barrier for waitqueue_active
*/
if (atomic_sub_return(nr_pages, &root->fs_info->async_delalloc_pages) <
- 5 * 1024 * 1024 &&
+ 5 * SZ_1M &&
waitqueue_active(&root->fs_info->async_submit_wait))
wake_up(&root->fs_info->async_submit_wait);
@@ -1132,7 +1138,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
struct btrfs_root *root = BTRFS_I(inode)->root;
unsigned long nr_pages;
u64 cur_end;
- int limit = 10 * 1024 * 1024;
+ int limit = 10 * SZ_1M;
clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED,
1, 0, NULL, GFP_NOFS);
@@ -1148,7 +1154,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
!btrfs_test_opt(root, FORCE_COMPRESS))
cur_end = end;
else
- cur_end = min(end, start + 512 * 1024 - 1);
+ cur_end = min(end, start + SZ_512K - 1);
async_cow->end = cur_end;
INIT_LIST_HEAD(&async_cow->extents);
@@ -1989,7 +1995,7 @@ again:
page_start = page_offset(page);
page_end = page_offset(page) + PAGE_CACHE_SIZE - 1;
- lock_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end, 0,
+ lock_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
&cached_state);
/* already ordered? We're done */
@@ -2482,7 +2488,7 @@ static noinline int relink_extent_backref(struct btrfs_path *path,
lock_start = backref->file_pos;
lock_end = backref->file_pos + backref->num_bytes - 1;
lock_extent_bits(&BTRFS_I(inode)->io_tree, lock_start, lock_end,
- 0, &cached);
+ &cached);
ordered = btrfs_lookup_first_ordered_extent(inode, lock_end);
if (ordered) {
@@ -2874,7 +2880,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
lock_extent_bits(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1,
- 0, &cached_state);
+ &cached_state);
ret = test_range_bit(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1,
@@ -3106,55 +3112,47 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
start, (size_t)(end - start + 1));
}
-struct delayed_iput {
- struct list_head list;
- struct inode *inode;
-};
-
-/* JDM: If this is fs-wide, why can't we add a pointer to
- * btrfs_inode instead and avoid the allocation? */
void btrfs_add_delayed_iput(struct inode *inode)
{
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
- struct delayed_iput *delayed;
+ struct btrfs_inode *binode = BTRFS_I(inode);
if (atomic_add_unless(&inode->i_count, -1, 1))
return;
- delayed = kmalloc(sizeof(*delayed), GFP_NOFS | __GFP_NOFAIL);
- delayed->inode = inode;
-
spin_lock(&fs_info->delayed_iput_lock);
- list_add_tail(&delayed->list, &fs_info->delayed_iputs);
+ if (binode->delayed_iput_count == 0) {
+ ASSERT(list_empty(&binode->delayed_iput));
+ list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
+ } else {
+ binode->delayed_iput_count++;
+ }
spin_unlock(&fs_info->delayed_iput_lock);
}
void btrfs_run_delayed_iputs(struct btrfs_root *root)
{
- LIST_HEAD(list);
struct btrfs_fs_info *fs_info = root->fs_info;
- struct delayed_iput *delayed;
- int empty;
-
- spin_lock(&fs_info->delayed_iput_lock);
- empty = list_empty(&fs_info->delayed_iputs);
- spin_unlock(&fs_info->delayed_iput_lock);
- if (empty)
- return;
down_read(&fs_info->delayed_iput_sem);
-
spin_lock(&fs_info->delayed_iput_lock);
- list_splice_init(&fs_info->delayed_iputs, &list);
- spin_unlock(&fs_info->delayed_iput_lock);
-
- while (!list_empty(&list)) {
- delayed = list_entry(list.next, struct delayed_iput, list);
- list_del(&delayed->list);
- iput(delayed->inode);
- kfree(delayed);
+ while (!list_empty(&fs_info->delayed_iputs)) {
+ struct btrfs_inode *inode;
+
+ inode = list_first_entry(&fs_info->delayed_iputs,
+ struct btrfs_inode, delayed_iput);
+ if (inode->delayed_iput_count) {
+ inode->delayed_iput_count--;
+ list_move_tail(&inode->delayed_iput,
+ &fs_info->delayed_iputs);
+ } else {
+ list_del_init(&inode->delayed_iput);
+ }
+ spin_unlock(&fs_info->delayed_iput_lock);
+ iput(&inode->vfs_inode);
+ spin_lock(&fs_info->delayed_iput_lock);
}
-
+ spin_unlock(&fs_info->delayed_iput_lock);
up_read(&root->fs_info->delayed_iput_sem);
}
@@ -3351,7 +3349,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
ret = -ENOMEM;
goto out;
}
- path->reada = -1;
+ path->reada = READA_BACK;
key.objectid = BTRFS_ORPHAN_OBJECTID;
key.type = BTRFS_ORPHAN_ITEM_KEY;
@@ -4318,7 +4316,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = -1;
+ path->reada = READA_BACK;
/*
* We want to drop from the next block forward in case this new size is
@@ -4349,7 +4347,7 @@ search_again:
* up a huge file in a single leaf. Most of the time that
* bytes_deleted is > 0, it will be huge by the time we get here
*/
- if (be_nice && bytes_deleted > 32 * 1024 * 1024) {
+ if (be_nice && bytes_deleted > SZ_32M) {
if (btrfs_should_end_transaction(trans, root)) {
err = -EAGAIN;
goto error;
@@ -4592,7 +4590,7 @@ error:
btrfs_free_path(path);
- if (be_nice && bytes_deleted > 32 * 1024 * 1024) {
+ if (be_nice && bytes_deleted > SZ_32M) {
unsigned long updates = trans->delayed_ref_updates;
if (updates) {
trans->delayed_ref_updates = 0;
@@ -4669,7 +4667,7 @@ again:
}
wait_on_page_writeback(page);
- lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state);
+ lock_extent_bits(io_tree, page_start, page_end, &cached_state);
set_page_extent_mapped(page);
ordered = btrfs_lookup_ordered_extent(inode, page_start);
@@ -4800,7 +4798,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
while (1) {
struct btrfs_ordered_extent *ordered;
- lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
+ lock_extent_bits(io_tree, hole_start, block_end - 1,
&cached_state);
ordered = btrfs_lookup_ordered_range(inode, hole_start,
block_end - hole_start);
@@ -5112,7 +5110,7 @@ static void evict_inode_truncate_pages(struct inode *inode)
end = state->end;
spin_unlock(&io_tree->lock);
- lock_extent_bits(io_tree, start, end, 0, &cached_state);
+ lock_extent_bits(io_tree, start, end, &cached_state);
/*
* If still has DELALLOC flag, the extent didn't reach disk,
@@ -5305,7 +5303,6 @@ void btrfs_evict_inode(struct inode *inode)
no_delete:
btrfs_remove_delayed_node(inode);
clear_inode(inode);
- return;
}
/*
@@ -5754,7 +5751,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
if (key_type == BTRFS_DIR_INDEX_KEY) {
INIT_LIST_HEAD(&ins_list);
@@ -6482,7 +6479,7 @@ out_unlock_inode:
static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
- struct btrfs_trans_handle *trans;
+ struct btrfs_trans_handle *trans = NULL;
struct btrfs_root *root = BTRFS_I(dir)->root;
struct inode *inode = d_inode(old_dentry);
u64 index;
@@ -6508,6 +6505,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
trans = btrfs_start_transaction(root, 5);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
+ trans = NULL;
goto fail;
}
@@ -6541,9 +6539,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
btrfs_log_new_name(trans, inode, NULL, parent);
}
- btrfs_end_transaction(trans, root);
btrfs_balance_delayed_items(root);
fail:
+ if (trans)
+ btrfs_end_transaction(trans, root);
if (drop_inode) {
inode_dec_link_count(inode);
iput(inode);
@@ -6688,7 +6687,7 @@ static int merge_extent_mapping(struct extent_map_tree *em_tree,
}
static noinline int uncompress_inline(struct btrfs_path *path,
- struct inode *inode, struct page *page,
+ struct page *page,
size_t pg_offset, u64 extent_offset,
struct btrfs_file_extent_item *item)
{
@@ -6785,7 +6784,7 @@ again:
* Chances are we'll be called again, so go ahead and do
* readahead
*/
- path->reada = 1;
+ path->reada = READA_FORWARD;
}
ret = btrfs_lookup_file_extent(trans, root, path,
@@ -6884,8 +6883,7 @@ next:
if (create == 0 && !PageUptodate(page)) {
if (btrfs_file_extent_compression(leaf, item) !=
BTRFS_COMPRESS_NONE) {
- ret = uncompress_inline(path, inode, page,
- pg_offset,
+ ret = uncompress_inline(path, page, pg_offset,
extent_offset, item);
if (ret) {
err = ret;
@@ -7381,7 +7379,7 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
while (1) {
lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
- 0, cached_state);
+ cached_state);
/*
* We're concerned with the entire range that we're going to be
* doing DIO to, so we need to make sure theres no ordered
@@ -7409,25 +7407,21 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
btrfs_start_ordered_extent(inode, ordered, 1);
btrfs_put_ordered_extent(ordered);
} else {
- /* Screw you mmap */
- ret = btrfs_fdatawrite_range(inode, lockstart, lockend);
- if (ret)
- break;
- ret = filemap_fdatawait_range(inode->i_mapping,
- lockstart,
- lockend);
- if (ret)
- break;
-
/*
- * If we found a page that couldn't be invalidated just
- * fall back to buffered.
+ * We could trigger writeback for this range (and wait
+ * for it to complete) and then invalidate the pages for
+ * this range (through invalidate_inode_pages2_range()),
+ * but that can lead us to a deadlock with a concurrent
+ * call to readpages() (a buffered read or a defrag call
+ * triggered a readahead) on a page lock due to an
+ * ordered dio extent we created before but did not have
+ * yet a corresponding bio submitted (whence it can not
+ * complete), which makes readpages() wait for that
+ * ordered extent to complete while holding a lock on
+ * that page.
*/
- ret = invalidate_inode_pages2_range(inode->i_mapping,
- lockstart >> PAGE_CACHE_SHIFT,
- lockend >> PAGE_CACHE_SHIFT);
- if (ret)
- break;
+ ret = -ENOTBLK;
+ break;
}
cond_resched();
@@ -7483,11 +7477,6 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
return em;
}
-struct btrfs_dio_data {
- u64 outstanding_extents;
- u64 reserve;
-};
-
static void adjust_dio_outstanding_extents(struct inode *inode,
struct btrfs_dio_data *dio_data,
const u64 len)
@@ -7671,6 +7660,7 @@ unlock:
btrfs_free_reserved_data_space(inode, start, len);
WARN_ON(dio_data->reserve < len);
dio_data->reserve -= len;
+ dio_data->unsubmitted_oe_range_end = start + len;
current->journal_info = dio_data;
}
@@ -7993,22 +7983,22 @@ static void btrfs_endio_direct_read(struct bio *bio)
bio_put(bio);
}
-static void btrfs_endio_direct_write(struct bio *bio)
+static void btrfs_endio_direct_write_update_ordered(struct inode *inode,
+ const u64 offset,
+ const u64 bytes,
+ const int uptodate)
{
- struct btrfs_dio_private *dip = bio->bi_private;
- struct inode *inode = dip->inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_ordered_extent *ordered = NULL;
- u64 ordered_offset = dip->logical_offset;
- u64 ordered_bytes = dip->bytes;
- struct bio *dio_bio;
+ u64 ordered_offset = offset;
+ u64 ordered_bytes = bytes;
int ret;
again:
ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
&ordered_offset,
ordered_bytes,
- !bio->bi_error);
+ uptodate);
if (!ret)
goto out_test;
@@ -8021,13 +8011,22 @@ out_test:
* our bio might span multiple ordered extents. If we haven't
* completed the accounting for the whole dio, go back and try again
*/
- if (ordered_offset < dip->logical_offset + dip->bytes) {
- ordered_bytes = dip->logical_offset + dip->bytes -
- ordered_offset;
+ if (ordered_offset < offset + bytes) {
+ ordered_bytes = offset + bytes - ordered_offset;
ordered = NULL;
goto again;
}
- dio_bio = dip->dio_bio;
+}
+
+static void btrfs_endio_direct_write(struct bio *bio)
+{
+ struct btrfs_dio_private *dip = bio->bi_private;
+ struct bio *dio_bio = dip->dio_bio;
+
+ btrfs_endio_direct_write_update_ordered(dip->inode,
+ dip->logical_offset,
+ dip->bytes,
+ !bio->bi_error);
kfree(dip);
@@ -8335,6 +8334,21 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
dip->subio_endio = btrfs_subio_endio_read;
}
+ /*
+ * Reset the range for unsubmitted ordered extents (to a 0 length range)
+ * even if we fail to submit a bio, because in such case we do the
+ * corresponding error handling below and it must not be done a second
+ * time by btrfs_direct_IO().
+ */
+ if (write) {
+ struct btrfs_dio_data *dio_data = current->journal_info;
+
+ dio_data->unsubmitted_oe_range_end = dip->logical_offset +
+ dip->bytes;
+ dio_data->unsubmitted_oe_range_start =
+ dio_data->unsubmitted_oe_range_end;
+ }
+
ret = btrfs_submit_direct_hook(rw, dip, skip_sum);
if (!ret)
return;
@@ -8363,24 +8377,15 @@ free_ordered:
dip = NULL;
io_bio = NULL;
} else {
- if (write) {
- struct btrfs_ordered_extent *ordered;
-
- ordered = btrfs_lookup_ordered_extent(inode,
- file_offset);
- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags);
- /*
- * Decrements our ref on the ordered extent and removes
- * the ordered extent from the inode's ordered tree,
- * doing all the proper resource cleanup such as for the
- * reserved space and waking up any waiters for this
- * ordered extent (through btrfs_remove_ordered_extent).
- */
- btrfs_finish_ordered_io(ordered);
- } else {
+ if (write)
+ btrfs_endio_direct_write_update_ordered(inode,
+ file_offset,
+ dio_bio->bi_iter.bi_size,
+ 0);
+ else
unlock_extent(&BTRFS_I(inode)->io_tree, file_offset,
file_offset + dio_bio->bi_iter.bi_size - 1);
- }
+
dio_bio->bi_error = -EIO;
/*
* Releases and cleans up our dio_bio, no need to bio_put()
@@ -8480,6 +8485,8 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
* originally calculated. Abuse current->journal_info for this.
*/
dio_data.reserve = round_up(count, root->sectorsize);
+ dio_data.unsubmitted_oe_range_start = (u64)offset;
+ dio_data.unsubmitted_oe_range_end = (u64)offset;
current->journal_info = &dio_data;
} else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
&BTRFS_I(inode)->runtime_flags)) {
@@ -8498,6 +8505,19 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
if (dio_data.reserve)
btrfs_delalloc_release_space(inode, offset,
dio_data.reserve);
+ /*
+ * On error we might have left some ordered extents
+ * without submitting corresponding bios for them, so
+ * cleanup them up to avoid other tasks getting them
+ * and waiting for them to complete forever.
+ */
+ if (dio_data.unsubmitted_oe_range_start <
+ dio_data.unsubmitted_oe_range_end)
+ btrfs_endio_direct_write_update_ordered(inode,
+ dio_data.unsubmitted_oe_range_start,
+ dio_data.unsubmitted_oe_range_end -
+ dio_data.unsubmitted_oe_range_start,
+ 0);
} else if (ret >= 0 && (size_t)ret < count)
btrfs_delalloc_release_space(inode, offset,
count - (size_t)ret);
@@ -8535,15 +8555,28 @@ int btrfs_readpage(struct file *file, struct page *page)
static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
{
struct extent_io_tree *tree;
-
+ struct inode *inode = page->mapping->host;
+ int ret;
if (current->flags & PF_MEMALLOC) {
redirty_page_for_writepage(wbc, page);
unlock_page(page);
return 0;
}
+
+ /*
+ * If we are under memory pressure we will call this directly from the
+ * VM, we need to make sure we have the inode referenced for the ordered
+ * extent. If not just return like we didn't do anything.
+ */
+ if (!igrab(inode)) {
+ redirty_page_for_writepage(wbc, page);
+ return AOP_WRITEPAGE_ACTIVATE;
+ }
tree = &BTRFS_I(page->mapping->host)->io_tree;
- return extent_write_full_page(tree, page, btrfs_get_extent, wbc);
+ ret = extent_write_full_page(tree, page, btrfs_get_extent, wbc);
+ btrfs_add_delayed_iput(inode);
+ return ret;
}
static int btrfs_writepages(struct address_space *mapping,
@@ -8615,7 +8648,7 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
}
if (!inode_evicting)
- lock_extent_bits(tree, page_start, page_end, 0, &cached_state);
+ lock_extent_bits(tree, page_start, page_end, &cached_state);
ordered = btrfs_lookup_ordered_extent(inode, page_start);
if (ordered) {
/*
@@ -8653,7 +8686,7 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
btrfs_put_ordered_extent(ordered);
if (!inode_evicting) {
cached_state = NULL;
- lock_extent_bits(tree, page_start, page_end, 0,
+ lock_extent_bits(tree, page_start, page_end,
&cached_state);
}
}
@@ -8751,7 +8784,7 @@ again:
}
wait_on_page_writeback(page);
- lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state);
+ lock_extent_bits(io_tree, page_start, page_end, &cached_state);
set_page_extent_mapped(page);
/*
@@ -9025,6 +9058,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->dir_index = 0;
ei->last_unlink_trans = 0;
ei->last_log_commit = 0;
+ ei->delayed_iput_count = 0;
spin_lock_init(&ei->lock);
ei->outstanding_extents = 0;
@@ -9049,6 +9083,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
mutex_init(&ei->delalloc_mutex);
btrfs_ordered_inode_tree_init(&ei->ordered_tree);
INIT_LIST_HEAD(&ei->delalloc_inodes);
+ INIT_LIST_HEAD(&ei->delayed_iput);
RB_CLEAR_NODE(&ei->rb_node);
return inode;
@@ -9153,15 +9188,14 @@ void btrfs_destroy_cachep(void)
kmem_cache_destroy(btrfs_path_cachep);
if (btrfs_free_space_cachep)
kmem_cache_destroy(btrfs_free_space_cachep);
- if (btrfs_delalloc_work_cachep)
- kmem_cache_destroy(btrfs_delalloc_work_cachep);
}
int btrfs_init_cachep(void)
{
btrfs_inode_cachep = kmem_cache_create("btrfs_inode",
sizeof(struct btrfs_inode), 0,
- SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, init_once);
+ SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT,
+ init_once);
if (!btrfs_inode_cachep)
goto fail;
@@ -9189,13 +9223,6 @@ int btrfs_init_cachep(void)
if (!btrfs_free_space_cachep)
goto fail;
- btrfs_delalloc_work_cachep = kmem_cache_create("btrfs_delalloc_work",
- sizeof(struct btrfs_delalloc_work), 0,
- SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
- NULL);
- if (!btrfs_delalloc_work_cachep)
- goto fail;
-
return 0;
fail:
btrfs_destroy_cachep();
@@ -9419,14 +9446,10 @@ static void btrfs_run_delalloc_work(struct btrfs_work *work)
delalloc_work = container_of(work, struct btrfs_delalloc_work,
work);
inode = delalloc_work->inode;
- if (delalloc_work->wait) {
- btrfs_wait_ordered_range(inode, 0, (u64)-1);
- } else {
+ filemap_flush(inode->i_mapping);
+ if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
+ &BTRFS_I(inode)->runtime_flags))
filemap_flush(inode->i_mapping);
- if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
- &BTRFS_I(inode)->runtime_flags))
- filemap_flush(inode->i_mapping);
- }
if (delalloc_work->delay_iput)
btrfs_add_delayed_iput(inode);
@@ -9436,18 +9459,17 @@ static void btrfs_run_delalloc_work(struct btrfs_work *work)
}
struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
- int wait, int delay_iput)
+ int delay_iput)
{
struct btrfs_delalloc_work *work;
- work = kmem_cache_zalloc(btrfs_delalloc_work_cachep, GFP_NOFS);
+ work = kmalloc(sizeof(*work), GFP_NOFS);
if (!work)
return NULL;
init_completion(&work->completion);
INIT_LIST_HEAD(&work->list);
work->inode = inode;
- work->wait = wait;
work->delay_iput = delay_iput;
WARN_ON_ONCE(!inode);
btrfs_init_work(&work->work, btrfs_flush_delalloc_helper,
@@ -9459,7 +9481,7 @@ struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work)
{
wait_for_completion(&work->completion);
- kmem_cache_free(btrfs_delalloc_work_cachep, work);
+ kfree(work);
}
/*
@@ -9495,7 +9517,7 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput,
}
spin_unlock(&root->delalloc_lock);
- work = btrfs_alloc_delalloc_work(inode, 0, delay_iput);
+ work = btrfs_alloc_delalloc_work(inode, delay_iput);
if (!work) {
if (delay_iput)
btrfs_add_delayed_iput(inode);
@@ -9637,9 +9659,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
/*
* 2 items for inode item and ref
* 2 items for dir items
+ * 1 item for updating parent inode item
+ * 1 item for the inline extent item
* 1 item for xattr if selinux is on
*/
- trans = btrfs_start_transaction(root, 5);
+ trans = btrfs_start_transaction(root, 7);
if (IS_ERR(trans))
return PTR_ERR(trans);
@@ -9670,10 +9694,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
if (err)
goto out_unlock_inode;
- err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
- if (err)
- goto out_unlock_inode;
-
path = btrfs_alloc_path();
if (!path) {
err = -ENOMEM;
@@ -9711,6 +9731,13 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
inode_set_bytes(inode, name_len);
btrfs_i_size_write(inode, name_len);
err = btrfs_update_inode(trans, root, inode);
+ /*
+ * Last step, add directory indexes for our symlink inode. This is the
+ * last step to avoid extra cleanup of these indexes if an error happens
+ * elsewhere above.
+ */
+ if (!err)
+ err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err) {
drop_inode = 1;
goto out_unlock_inode;
@@ -9761,7 +9788,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
}
}
- cur_bytes = min(num_bytes, 256ULL * 1024 * 1024);
+ cur_bytes = min_t(u64, num_bytes, SZ_256M);
cur_bytes = max(cur_bytes, min_size);
/*
* If we are severely fragmented we could end up with really
@@ -10025,7 +10052,7 @@ static const struct file_operations btrfs_dir_file_operations = {
.fsync = btrfs_sync_file,
};
-static struct extent_io_ops btrfs_extent_io_ops = {
+static const struct extent_io_ops btrfs_extent_io_ops = {
.fill_delalloc = run_delalloc_range,
.submit_bio_hook = btrfs_submit_bio_hook,
.merge_bio_hook = btrfs_merge_bio_hook,
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index e21997385d14..2a47a3148ec8 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -655,22 +655,28 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
return -EINVAL;
+ pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
+ if (!pending_snapshot)
+ return -ENOMEM;
+
+ pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item),
+ GFP_NOFS);
+ pending_snapshot->path = btrfs_alloc_path();
+ if (!pending_snapshot->root_item || !pending_snapshot->path) {
+ ret = -ENOMEM;
+ goto free_pending;
+ }
+
atomic_inc(&root->will_be_snapshoted);
smp_mb__after_atomic();
btrfs_wait_for_no_snapshoting_writes(root);
ret = btrfs_start_delalloc_inodes(root, 0);
if (ret)
- goto out;
+ goto dec_and_free;
btrfs_wait_ordered_extents(root, -1);
- pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
- if (!pending_snapshot) {
- ret = -ENOMEM;
- goto out;
- }
-
btrfs_init_block_rsv(&pending_snapshot->block_rsv,
BTRFS_BLOCK_RSV_TEMP);
/*
@@ -686,7 +692,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
&pending_snapshot->qgroup_reserved,
false);
if (ret)
- goto free;
+ goto dec_and_free;
pending_snapshot->dentry = dentry;
pending_snapshot->root = root;
@@ -737,11 +743,14 @@ fail:
btrfs_subvolume_release_metadata(BTRFS_I(dir)->root,
&pending_snapshot->block_rsv,
pending_snapshot->qgroup_reserved);
-free:
- kfree(pending_snapshot);
-out:
+dec_and_free:
if (atomic_dec_and_test(&root->will_be_snapshoted))
wake_up_atomic_t(&root->will_be_snapshoted);
+free_pending:
+ kfree(pending_snapshot->root_item);
+ btrfs_free_path(pending_snapshot->path);
+ kfree(pending_snapshot);
+
return ret;
}
@@ -992,7 +1001,7 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start)
u64 end = start + len - 1;
/* get the big lock and read metadata off disk */
- lock_extent_bits(io_tree, start, end, 0, &cached);
+ lock_extent_bits(io_tree, start, end, &cached);
em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
unlock_extent_cached(io_tree, start, end, &cached, GFP_NOFS);
@@ -1016,7 +1025,7 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em)
if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE)
ret = false;
else if ((em->block_start + em->block_len == next->block_start) &&
- (em->block_len > 128 * 1024 && next->block_len > 128 * 1024))
+ (em->block_len > SZ_128K && next->block_len > SZ_128K))
ret = false;
free_extent_map(next);
@@ -1140,7 +1149,7 @@ again:
page_end = page_start + PAGE_CACHE_SIZE - 1;
while (1) {
lock_extent_bits(tree, page_start, page_end,
- 0, &cached_state);
+ &cached_state);
ordered = btrfs_lookup_ordered_extent(inode,
page_start);
unlock_extent_cached(tree, page_start, page_end,
@@ -1200,7 +1209,7 @@ again:
page_end = page_offset(pages[i_done - 1]) + PAGE_CACHE_SIZE;
lock_extent_bits(&BTRFS_I(inode)->io_tree,
- page_start, page_end - 1, 0, &cached_state);
+ page_start, page_end - 1, &cached_state);
clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start,
page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0,
@@ -1262,9 +1271,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
int defrag_count = 0;
int compress_type = BTRFS_COMPRESS_ZLIB;
u32 extent_thresh = range->extent_thresh;
- unsigned long max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
+ unsigned long max_cluster = SZ_256K >> PAGE_CACHE_SHIFT;
unsigned long cluster = max_cluster;
- u64 new_align = ~((u64)128 * 1024 - 1);
+ u64 new_align = ~((u64)SZ_128K - 1);
struct page **pages = NULL;
if (isize == 0)
@@ -1281,7 +1290,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
}
if (extent_thresh == 0)
- extent_thresh = 256 * 1024;
+ extent_thresh = SZ_256K;
/*
* if we were not given a file, allocate a readahead
@@ -1313,7 +1322,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
if (newer_than) {
ret = find_new_extents(root, inode, newer_than,
- &newer_off, 64 * 1024);
+ &newer_off, SZ_64K);
if (!ret) {
range->start = newer_off;
/*
@@ -1403,9 +1412,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
newer_off = max(newer_off + 1,
(u64)i << PAGE_CACHE_SHIFT);
- ret = find_new_extents(root, inode,
- newer_than, &newer_off,
- 64 * 1024);
+ ret = find_new_extents(root, inode, newer_than,
+ &newer_off, SZ_64K);
if (!ret) {
range->start = newer_off;
i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
@@ -1571,7 +1579,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
new_size = old_size + new_size;
}
- if (new_size < 256 * 1024 * 1024) {
+ if (new_size < SZ_256M) {
ret = -EINVAL;
goto out_free;
}
@@ -2160,7 +2168,7 @@ static noinline int btrfs_ioctl_tree_search_v2(struct file *file,
struct inode *inode;
int ret;
size_t buf_size;
- const size_t buf_limit = 16 * 1024 * 1024;
+ const size_t buf_limit = SZ_16M;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -3096,7 +3104,7 @@ out_unlock:
return ret;
}
-#define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024)
+#define BTRFS_MAX_DEDUPE_LEN SZ_16M
ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
struct file *dst_file, u64 dst_loff)
@@ -3396,7 +3404,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
return ret;
}
- path->reada = 2;
+ path->reada = READA_FORWARD;
/* clone data */
key.objectid = btrfs_ino(src);
key.type = BTRFS_EXTENT_DATA_KEY;
@@ -4039,7 +4047,7 @@ static long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
return -ENOMEM;
space_args.total_spaces = 0;
- dest = kmalloc(alloc_size, GFP_NOFS);
+ dest = kmalloc(alloc_size, GFP_KERNEL);
if (!dest)
return -ENOMEM;
dest_orig = dest;
@@ -4416,7 +4424,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
goto out;
}
- size = min_t(u32, loi->size, 64 * 1024);
+ size = min_t(u32, loi->size, SZ_64K);
inodes = init_data_container(size);
if (IS_ERR(inodes)) {
ret = PTR_ERR(inodes);
@@ -4565,7 +4573,7 @@ locked:
goto out_bargs;
}
- bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
+ bctl = kzalloc(sizeof(*bctl), GFP_KERNEL);
if (!bctl) {
ret = -ENOMEM;
goto out_bargs;
@@ -4651,7 +4659,7 @@ static long btrfs_ioctl_balance_progress(struct btrfs_root *root,
goto out;
}
- bargs = kzalloc(sizeof(*bargs), GFP_NOFS);
+ bargs = kzalloc(sizeof(*bargs), GFP_KERNEL);
if (!bargs) {
ret = -ENOMEM;
goto out;
@@ -4911,7 +4919,7 @@ static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- qsa = kzalloc(sizeof(*qsa), GFP_NOFS);
+ qsa = kzalloc(sizeof(*qsa), GFP_KERNEL);
if (!qsa)
return -ENOMEM;
@@ -5041,7 +5049,7 @@ static long btrfs_ioctl_set_received_subvol_32(struct file *file,
goto out;
}
- args64 = kmalloc(sizeof(*args64), GFP_NOFS);
+ args64 = kmalloc(sizeof(*args64), GFP_KERNEL);
if (!args64) {
ret = -ENOMEM;
goto out;
@@ -5178,7 +5186,7 @@ out_unlock:
static int btrfs_ioctl_get_supported_features(struct file *file,
void __user *arg)
{
- static struct btrfs_ioctl_feature_flags features[3] = {
+ static const struct btrfs_ioctl_feature_flags features[3] = {
INIT_FEATURE_FLAGS(SUPP),
INIT_FEATURE_FLAGS(SAFE_SET),
INIT_FEATURE_FLAGS(SAFE_CLEAR)
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c
index 8077461fc56a..d13128c70ddd 100644
--- a/fs/btrfs/locking.c
+++ b/fs/btrfs/locking.c
@@ -56,7 +56,6 @@ void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw)
atomic_dec(&eb->spinning_readers);
read_unlock(&eb->lock);
}
- return;
}
/*
@@ -96,7 +95,6 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)
waitqueue_active(&eb->read_lock_wq))
wake_up(&eb->read_lock_wq);
}
- return;
}
/*
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 1a33d3eb36de..6d707545f775 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -503,7 +503,6 @@ static void cache_rbio(struct btrfs_raid_bio *rbio)
}
spin_unlock_irqrestore(&table->cache_lock, flags);
- return;
}
/*
@@ -906,7 +905,6 @@ static void raid_write_end_io(struct bio *bio)
err = -EIO;
rbio_orig_end_io(rbio, err);
- return;
}
/*
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index b4ca5454ef1a..ef6d8fc85853 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -708,8 +708,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
err = -ENOMEM;
goto out;
}
- path1->reada = 1;
- path2->reada = 2;
+ path1->reada = READA_FORWARD;
+ path2->reada = READA_FORWARD;
node = alloc_backref_node(cache);
if (!node) {
@@ -2130,7 +2130,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
reloc_root = root->reloc_root;
root_item = &reloc_root->root_item;
@@ -3527,7 +3527,7 @@ static int find_data_references(struct reloc_control *rc,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
root = read_fs_root(rc->extent_root->fs_info, ref_root);
if (IS_ERR(root)) {
@@ -3917,7 +3917,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
ret = prepare_to_relocate(rc);
if (ret) {
@@ -4343,7 +4343,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = -1;
+ path->reada = READA_BACK;
key.objectid = BTRFS_TREE_RELOC_OBJECTID;
key.type = BTRFS_ROOT_ITEM_KEY;
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index b091d94ceef6..0c981ebe2acb 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1514,8 +1514,6 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
if (sblock->no_io_error_seen)
scrub_recheck_block_checksum(sblock);
-
- return;
}
static inline int scrub_check_fsid(u8 fsid[],
@@ -3507,7 +3505,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
if (!path)
return -ENOMEM;
- path->reada = 2;
+ path->reada = READA_FORWARD;
path->search_commit_root = 1;
path->skip_locking = 1;
@@ -3735,27 +3733,27 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
if (fs_info->scrub_workers_refcnt == 0) {
if (is_dev_replace)
fs_info->scrub_workers =
- btrfs_alloc_workqueue("btrfs-scrub", flags,
+ btrfs_alloc_workqueue("scrub", flags,
1, 4);
else
fs_info->scrub_workers =
- btrfs_alloc_workqueue("btrfs-scrub", flags,
+ btrfs_alloc_workqueue("scrub", flags,
max_active, 4);
if (!fs_info->scrub_workers)
goto fail_scrub_workers;
fs_info->scrub_wr_completion_workers =
- btrfs_alloc_workqueue("btrfs-scrubwrc", flags,
+ btrfs_alloc_workqueue("scrubwrc", flags,
max_active, 2);
if (!fs_info->scrub_wr_completion_workers)
goto fail_scrub_wr_completion_workers;
fs_info->scrub_nocow_workers =
- btrfs_alloc_workqueue("btrfs-scrubnc", flags, 1, 0);
+ btrfs_alloc_workqueue("scrubnc", flags, 1, 0);
if (!fs_info->scrub_nocow_workers)
goto fail_scrub_nocow_workers;
fs_info->scrub_parity_workers =
- btrfs_alloc_workqueue("btrfs-scrubparity", flags,
+ btrfs_alloc_workqueue("scrubparity", flags,
max_active, 2);
if (!fs_info->scrub_parity_workers)
goto fail_scrub_parity_workers;
@@ -4211,7 +4209,7 @@ static int check_extent_to_block(struct inode *inode, u64 start, u64 len,
io_tree = &BTRFS_I(inode)->io_tree;
- lock_extent_bits(io_tree, lockstart, lockend, 0, &cached_state);
+ lock_extent_bits(io_tree, lockstart, lockend, &cached_state);
ordered = btrfs_lookup_ordered_range(inode, lockstart, len);
if (ordered) {
btrfs_put_ordered_extent(ordered);
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 355a458cba1a..63a6152be04b 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -1469,7 +1469,21 @@ static int read_symlink(struct btrfs_root *root,
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto out;
- BUG_ON(ret);
+ if (ret) {
+ /*
+ * An empty symlink inode. Can happen in rare error paths when
+ * creating a symlink (transaction committed before the inode
+ * eviction handler removed the symlink inode items and a crash
+ * happened in between or the subvol was snapshoted in between).
+ * Print an informative message to dmesg/syslog so that the user
+ * can delete the symlink.
+ */
+ btrfs_err(root->fs_info,
+ "Found empty symlink inode %llu at root %llu",
+ ino, root->root_key.objectid);
+ ret = -EIO;
+ goto out;
+ }
ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_file_extent_item);
diff --git a/fs/btrfs/send.h b/fs/btrfs/send.h
index 48d425aef05b..02e00166c4da 100644
--- a/fs/btrfs/send.h
+++ b/fs/btrfs/send.h
@@ -22,8 +22,8 @@
#define BTRFS_SEND_STREAM_MAGIC "btrfs-stream"
#define BTRFS_SEND_STREAM_VERSION 1
-#define BTRFS_SEND_BUF_SIZE (1024 * 64)
-#define BTRFS_SEND_READ_SIZE (1024 * 48)
+#define BTRFS_SEND_BUF_SIZE SZ_64K
+#define BTRFS_SEND_READ_SIZE (48 * SZ_1K)
enum btrfs_tlv_type {
BTRFS_TLV_U8,
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index a0434c179ea9..9b9eab6d048e 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -295,10 +295,11 @@ enum {
Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress,
Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
- Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
- Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache,
- Opt_no_space_cache, Opt_recovery, Opt_skip_balance,
- Opt_check_integrity, Opt_check_integrity_including_extent_data,
+ Opt_space_cache, Opt_space_cache_version, Opt_clear_cache,
+ Opt_user_subvol_rm_allowed, Opt_enospc_debug, Opt_subvolrootid,
+ Opt_defrag, Opt_inode_cache, Opt_no_space_cache, Opt_recovery,
+ Opt_skip_balance, Opt_check_integrity,
+ Opt_check_integrity_including_extent_data,
Opt_check_integrity_print_mask, Opt_fatal_errors, Opt_rescan_uuid_tree,
Opt_commit_interval, Opt_barrier, Opt_nodefrag, Opt_nodiscard,
Opt_noenospc_debug, Opt_noflushoncommit, Opt_acl, Opt_datacow,
@@ -309,7 +310,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_degraded, "degraded"},
{Opt_subvol, "subvol=%s"},
{Opt_subvolid, "subvolid=%s"},
@@ -340,6 +341,7 @@ static match_table_t tokens = {
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
{Opt_space_cache, "space_cache"},
+ {Opt_space_cache_version, "space_cache=%s"},
{Opt_clear_cache, "clear_cache"},
{Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
{Opt_enospc_debug, "enospc_debug"},
@@ -383,7 +385,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
bool compress_force = false;
cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
- if (cache_gen)
+ if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE))
+ btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE);
+ else if (cache_gen)
btrfs_set_opt(info->mount_opt, SPACE_CACHE);
if (!options)
@@ -617,15 +621,35 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
"turning off discard");
break;
case Opt_space_cache:
- btrfs_set_and_info(root, SPACE_CACHE,
- "enabling disk space caching");
+ case Opt_space_cache_version:
+ if (token == Opt_space_cache ||
+ strcmp(args[0].from, "v1") == 0) {
+ btrfs_clear_opt(root->fs_info->mount_opt,
+ FREE_SPACE_TREE);
+ btrfs_set_and_info(root, SPACE_CACHE,
+ "enabling disk space caching");
+ } else if (strcmp(args[0].from, "v2") == 0) {
+ btrfs_clear_opt(root->fs_info->mount_opt,
+ SPACE_CACHE);
+ btrfs_set_and_info(root, FREE_SPACE_TREE,
+ "enabling free space tree");
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
break;
case Opt_rescan_uuid_tree:
btrfs_set_opt(info->mount_opt, RESCAN_UUID_TREE);
break;
case Opt_no_space_cache:
- btrfs_clear_and_info(root, SPACE_CACHE,
- "disabling disk space caching");
+ if (btrfs_test_opt(root, SPACE_CACHE)) {
+ btrfs_clear_and_info(root, SPACE_CACHE,
+ "disabling disk space caching");
+ }
+ if (btrfs_test_opt(root, FREE_SPACE_TREE)) {
+ btrfs_clear_and_info(root, FREE_SPACE_TREE,
+ "disabling free space tree");
+ }
break;
case Opt_inode_cache:
btrfs_set_pending_and_info(info, INODE_MAP_CACHE,
@@ -754,8 +778,17 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
}
}
out:
+ if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE) &&
+ !btrfs_test_opt(root, FREE_SPACE_TREE) &&
+ !btrfs_test_opt(root, CLEAR_CACHE)) {
+ btrfs_err(root->fs_info, "cannot disable free space tree");
+ ret = -EINVAL;
+
+ }
if (!ret && btrfs_test_opt(root, SPACE_CACHE))
btrfs_info(root->fs_info, "disk space caching is enabled");
+ if (!ret && btrfs_test_opt(root, FREE_SPACE_TREE))
+ btrfs_info(root->fs_info, "using free space tree");
kfree(orig);
return ret;
}
@@ -1162,6 +1195,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
seq_puts(seq, ",noacl");
if (btrfs_test_opt(root, SPACE_CACHE))
seq_puts(seq, ",space_cache");
+ else if (btrfs_test_opt(root, FREE_SPACE_TREE))
+ seq_puts(seq, ",space_cache=v2");
else
seq_puts(seq, ",nospace_cache");
if (btrfs_test_opt(root, RESCAN_UUID_TREE))
@@ -1863,7 +1898,7 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
* btrfs starts at an offset of at least 1MB when doing chunk
* allocation.
*/
- skip_space = 1024 * 1024;
+ skip_space = SZ_1M;
/* user can set the offset in fs_info->alloc_start. */
if (fs_info->alloc_start &&
@@ -1954,6 +1989,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
* there are other factors that may change the result (like a new metadata
* chunk).
*
+ * If metadata is exhausted, f_bavail will be 0.
+ *
* FIXME: not accurate for mixed block groups, total and free/used are ok,
* available appears slightly larger.
*/
@@ -1965,11 +2002,13 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
struct btrfs_space_info *found;
u64 total_used = 0;
u64 total_free_data = 0;
+ u64 total_free_meta = 0;
int bits = dentry->d_sb->s_blocksize_bits;
__be32 *fsid = (__be32 *)fs_info->fsid;
unsigned factor = 1;
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
int ret;
+ u64 thresh = 0;
/*
* holding chunk_muext to avoid allocating new chunks, holding
@@ -1995,6 +2034,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
}
}
}
+ if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
+ total_free_meta += found->disk_total - found->disk_used;
total_used += found->disk_used;
}
@@ -2017,6 +2058,24 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_bavail += div_u64(total_free_data, factor);
buf->f_bavail = buf->f_bavail >> bits;
+ /*
+ * We calculate the remaining metadata space minus global reserve. If
+ * this is (supposedly) smaller than zero, there's no space. But this
+ * does not hold in practice, the exhausted state happens where's still
+ * some positive delta. So we apply some guesswork and compare the
+ * delta to a 4M threshold. (Practically observed delta was ~2M.)
+ *
+ * We probably cannot calculate the exact threshold value because this
+ * depends on the internal reservations requested by various
+ * operations, so some operations that consume a few metadata will
+ * succeed even if the Avail is zero. But this is better than the other
+ * way around.
+ */
+ thresh = 4 * 1024 * 1024;
+
+ if (total_free_meta - thresh < block_rsv->size)
+ buf->f_bavail = 0;
+
buf->f_type = BTRFS_SUPER_MAGIC;
buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_namelen = BTRFS_NAME_LEN;
@@ -2223,6 +2282,9 @@ static int btrfs_run_sanity_tests(void)
if (ret)
goto out;
ret = btrfs_test_qgroups();
+ if (ret)
+ goto out;
+ ret = btrfs_test_free_space_tree();
out:
btrfs_destroy_test_fs();
return ret;
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
index 9626252ee6b4..b1d920b30070 100644
--- a/fs/btrfs/tests/btrfs-tests.c
+++ b/fs/btrfs/tests/btrfs-tests.c
@@ -21,6 +21,9 @@
#include <linux/magic.h>
#include "btrfs-tests.h"
#include "../ctree.h"
+#include "../free-space-cache.h"
+#include "../free-space-tree.h"
+#include "../transaction.h"
#include "../volumes.h"
#include "../disk-io.h"
#include "../qgroup.h"
@@ -122,6 +125,9 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void)
INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
+ extent_io_tree_init(&fs_info->freed_extents[0], NULL);
+ extent_io_tree_init(&fs_info->freed_extents[1], NULL);
+ fs_info->pinned_extents = &fs_info->freed_extents[0];
return fs_info;
}
@@ -169,3 +175,55 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
kfree(root);
}
+struct btrfs_block_group_cache *
+btrfs_alloc_dummy_block_group(unsigned long length)
+{
+ struct btrfs_block_group_cache *cache;
+
+ cache = kzalloc(sizeof(*cache), GFP_NOFS);
+ if (!cache)
+ return NULL;
+ cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
+ GFP_NOFS);
+ if (!cache->free_space_ctl) {
+ kfree(cache);
+ return NULL;
+ }
+ cache->fs_info = btrfs_alloc_dummy_fs_info();
+ if (!cache->fs_info) {
+ kfree(cache->free_space_ctl);
+ kfree(cache);
+ return NULL;
+ }
+
+ cache->key.objectid = 0;
+ cache->key.offset = length;
+ cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+ cache->sectorsize = 4096;
+ cache->full_stripe_len = 4096;
+
+ INIT_LIST_HEAD(&cache->list);
+ INIT_LIST_HEAD(&cache->cluster_list);
+ INIT_LIST_HEAD(&cache->bg_list);
+ btrfs_init_free_space_ctl(cache);
+ mutex_init(&cache->free_space_lock);
+
+ return cache;
+}
+
+void btrfs_free_dummy_block_group(struct btrfs_block_group_cache *cache)
+{
+ if (!cache)
+ return;
+ __btrfs_remove_free_space_cache(cache->free_space_ctl);
+ kfree(cache->free_space_ctl);
+ kfree(cache);
+}
+
+void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans)
+{
+ memset(trans, 0, sizeof(*trans));
+ trans->transid = 1;
+ INIT_LIST_HEAD(&trans->qgroup_ref_list);
+ trans->type = __TRANS_DUMMY;
+}
diff --git a/fs/btrfs/tests/btrfs-tests.h b/fs/btrfs/tests/btrfs-tests.h
index fd3954224480..054b8c73c951 100644
--- a/fs/btrfs/tests/btrfs-tests.h
+++ b/fs/btrfs/tests/btrfs-tests.h
@@ -24,17 +24,23 @@
#define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__)
struct btrfs_root;
+struct btrfs_trans_handle;
int btrfs_test_free_space_cache(void);
int btrfs_test_extent_buffer_operations(void);
int btrfs_test_extent_io(void);
int btrfs_test_inodes(void);
int btrfs_test_qgroups(void);
+int btrfs_test_free_space_tree(void);
int btrfs_init_test_fs(void);
void btrfs_destroy_test_fs(void);
struct inode *btrfs_new_test_inode(void);
struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void);
void btrfs_free_dummy_root(struct btrfs_root *root);
+struct btrfs_block_group_cache *
+btrfs_alloc_dummy_block_group(unsigned long length);
+void btrfs_free_dummy_block_group(struct btrfs_block_group_cache *cache);
+void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans);
#else
static inline int btrfs_test_free_space_cache(void)
{
@@ -63,6 +69,10 @@ static inline int btrfs_test_qgroups(void)
{
return 0;
}
+static inline int btrfs_test_free_space_tree(void)
+{
+ return 0;
+}
#endif
#endif
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
index 9e9f2368177d..e29fa297e053 100644
--- a/fs/btrfs/tests/extent-io-tests.c
+++ b/fs/btrfs/tests/extent-io-tests.c
@@ -18,6 +18,8 @@
#include <linux/pagemap.h>
#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sizes.h>
#include "btrfs-tests.h"
#include "../extent_io.h"
@@ -70,12 +72,14 @@ static int test_find_delalloc(void)
struct page *page;
struct page *locked_page = NULL;
unsigned long index = 0;
- u64 total_dirty = 256 * 1024 * 1024;
- u64 max_bytes = 128 * 1024 * 1024;
+ u64 total_dirty = SZ_256M;
+ u64 max_bytes = SZ_128M;
u64 start, end, test_start;
u64 found;
int ret = -EINVAL;
+ test_msg("Running find delalloc tests\n");
+
inode = btrfs_new_test_inode();
if (!inode) {
test_msg("Failed to allocate test inode\n");
@@ -133,7 +137,7 @@ static int test_find_delalloc(void)
* |--- delalloc ---|
* |--- search ---|
*/
- test_start = 64 * 1024 * 1024;
+ test_start = SZ_64M;
locked_page = find_lock_page(inode->i_mapping,
test_start >> PAGE_CACHE_SHIFT);
if (!locked_page) {
@@ -220,8 +224,8 @@ static int test_find_delalloc(void)
* Now to test where we run into a page that is no longer dirty in the
* range we want to find.
*/
- page = find_get_page(inode->i_mapping, (max_bytes + (1 * 1024 * 1024))
- >> PAGE_CACHE_SHIFT);
+ page = find_get_page(inode->i_mapping,
+ (max_bytes + SZ_1M) >> PAGE_CACHE_SHIFT);
if (!page) {
test_msg("Couldn't find our page\n");
goto out_bits;
@@ -268,8 +272,139 @@ out:
return ret;
}
+static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
+ unsigned long len)
+{
+ unsigned long i, x;
+
+ memset(bitmap, 0, len);
+ memset_extent_buffer(eb, 0, 0, len);
+ if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
+ test_msg("Bitmap was not zeroed\n");
+ return -EINVAL;
+ }
+
+ bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
+ extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
+ if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
+ test_msg("Setting all bits failed\n");
+ return -EINVAL;
+ }
+
+ bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
+ extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
+ if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
+ test_msg("Clearing all bits failed\n");
+ return -EINVAL;
+ }
+
+ bitmap_set(bitmap, (PAGE_CACHE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
+ sizeof(long) * BITS_PER_BYTE);
+ extent_buffer_bitmap_set(eb, PAGE_CACHE_SIZE - sizeof(long) / 2, 0,
+ sizeof(long) * BITS_PER_BYTE);
+ if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
+ test_msg("Setting straddling pages failed\n");
+ return -EINVAL;
+ }
+
+ bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
+ bitmap_clear(bitmap,
+ (PAGE_CACHE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
+ sizeof(long) * BITS_PER_BYTE);
+ extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
+ extent_buffer_bitmap_clear(eb, PAGE_CACHE_SIZE - sizeof(long) / 2, 0,
+ sizeof(long) * BITS_PER_BYTE);
+ if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
+ test_msg("Clearing straddling pages failed\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Generate a wonky pseudo-random bit pattern for the sake of not using
+ * something repetitive that could miss some hypothetical off-by-n bug.
+ */
+ x = 0;
+ for (i = 0; i < len / sizeof(long); i++) {
+ x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffUL;
+ bitmap[i] = x;
+ }
+ write_extent_buffer(eb, bitmap, 0, len);
+
+ for (i = 0; i < len * BITS_PER_BYTE; i++) {
+ int bit, bit1;
+
+ bit = !!test_bit(i, bitmap);
+ bit1 = !!extent_buffer_test_bit(eb, 0, i);
+ if (bit1 != bit) {
+ test_msg("Testing bit pattern failed\n");
+ return -EINVAL;
+ }
+
+ bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE,
+ i % BITS_PER_BYTE);
+ if (bit1 != bit) {
+ test_msg("Testing bit pattern with offset failed\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int test_eb_bitmaps(void)
+{
+ unsigned long len = PAGE_CACHE_SIZE * 4;
+ unsigned long *bitmap;
+ struct extent_buffer *eb;
+ int ret;
+
+ test_msg("Running extent buffer bitmap tests\n");
+
+ bitmap = kmalloc(len, GFP_NOFS);
+ if (!bitmap) {
+ test_msg("Couldn't allocate test bitmap\n");
+ return -ENOMEM;
+ }
+
+ eb = __alloc_dummy_extent_buffer(NULL, 0, len);
+ if (!eb) {
+ test_msg("Couldn't allocate test extent buffer\n");
+ kfree(bitmap);
+ return -ENOMEM;
+ }
+
+ ret = __test_eb_bitmaps(bitmap, eb, len);
+ if (ret)
+ goto out;
+
+ /* Do it over again with an extent buffer which isn't page-aligned. */
+ free_extent_buffer(eb);
+ eb = __alloc_dummy_extent_buffer(NULL, PAGE_CACHE_SIZE / 2, len);
+ if (!eb) {
+ test_msg("Couldn't allocate test extent buffer\n");
+ kfree(bitmap);
+ return -ENOMEM;
+ }
+
+ ret = __test_eb_bitmaps(bitmap, eb, len);
+out:
+ free_extent_buffer(eb);
+ kfree(bitmap);
+ return ret;
+}
+
int btrfs_test_extent_io(void)
{
- test_msg("Running find delalloc tests\n");
- return test_find_delalloc();
+ int ret;
+
+ test_msg("Running extent I/O tests\n");
+
+ ret = test_find_delalloc();
+ if (ret)
+ goto out;
+
+ ret = test_eb_bitmaps();
+out:
+ test_msg("Extent I/O tests finished\n");
+ return ret;
}
diff --git a/fs/btrfs/tests/free-space-tests.c b/fs/btrfs/tests/free-space-tests.c
index 8b72b005bfb9..c9ad97b1e690 100644
--- a/fs/btrfs/tests/free-space-tests.c
+++ b/fs/btrfs/tests/free-space-tests.c
@@ -23,41 +23,6 @@
#include "../free-space-cache.h"
#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8)
-static struct btrfs_block_group_cache *init_test_block_group(void)
-{
- struct btrfs_block_group_cache *cache;
-
- cache = kzalloc(sizeof(*cache), GFP_NOFS);
- if (!cache)
- return NULL;
- cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
- GFP_NOFS);
- if (!cache->free_space_ctl) {
- kfree(cache);
- return NULL;
- }
- cache->fs_info = btrfs_alloc_dummy_fs_info();
- if (!cache->fs_info) {
- kfree(cache->free_space_ctl);
- kfree(cache);
- return NULL;
- }
-
- cache->key.objectid = 0;
- cache->key.offset = 1024 * 1024 * 1024;
- cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
- cache->sectorsize = 4096;
- cache->full_stripe_len = 4096;
-
- spin_lock_init(&cache->lock);
- INIT_LIST_HEAD(&cache->list);
- INIT_LIST_HEAD(&cache->cluster_list);
- INIT_LIST_HEAD(&cache->bg_list);
-
- btrfs_init_free_space_ctl(cache);
-
- return cache;
-}
/*
* This test just does basic sanity checking, making sure we can add an exten
@@ -71,59 +36,59 @@ static int test_extents(struct btrfs_block_group_cache *cache)
test_msg("Running extent only tests\n");
/* First just make sure we can remove an entire entry */
- ret = btrfs_add_free_space(cache, 0, 4 * 1024 * 1024);
+ ret = btrfs_add_free_space(cache, 0, SZ_4M);
if (ret) {
test_msg("Error adding initial extents %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 0, 4 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, 0, SZ_4M);
if (ret) {
test_msg("Error removing extent %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 0, 4 * 1024 * 1024)) {
+ if (test_check_exists(cache, 0, SZ_4M)) {
test_msg("Full remove left some lingering space\n");
return -1;
}
/* Ok edge and middle cases now */
- ret = btrfs_add_free_space(cache, 0, 4 * 1024 * 1024);
+ ret = btrfs_add_free_space(cache, 0, SZ_4M);
if (ret) {
test_msg("Error adding half extent %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 3 * 1024 * 1024, 1 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, 3 * SZ_1M, SZ_1M);
if (ret) {
test_msg("Error removing tail end %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 0, 1 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, 0, SZ_1M);
if (ret) {
test_msg("Error removing front end %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 2 * 1024 * 1024, 4096);
+ ret = btrfs_remove_free_space(cache, SZ_2M, 4096);
if (ret) {
test_msg("Error removing middle piece %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 0, 1 * 1024 * 1024)) {
+ if (test_check_exists(cache, 0, SZ_1M)) {
test_msg("Still have space at the front\n");
return -1;
}
- if (test_check_exists(cache, 2 * 1024 * 1024, 4096)) {
+ if (test_check_exists(cache, SZ_2M, 4096)) {
test_msg("Still have space in the middle\n");
return -1;
}
- if (test_check_exists(cache, 3 * 1024 * 1024, 1 * 1024 * 1024)) {
+ if (test_check_exists(cache, 3 * SZ_1M, SZ_1M)) {
test_msg("Still have space at the end\n");
return -1;
}
@@ -141,30 +106,30 @@ static int test_bitmaps(struct btrfs_block_group_cache *cache)
test_msg("Running bitmap only tests\n");
- ret = test_add_free_space_entry(cache, 0, 4 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, 0, SZ_4M, 1);
if (ret) {
test_msg("Couldn't create a bitmap entry %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 0, 4 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, 0, SZ_4M);
if (ret) {
test_msg("Error removing bitmap full range %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 0, 4 * 1024 * 1024)) {
+ if (test_check_exists(cache, 0, SZ_4M)) {
test_msg("Left some space in bitmap\n");
return -1;
}
- ret = test_add_free_space_entry(cache, 0, 4 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, 0, SZ_4M, 1);
if (ret) {
test_msg("Couldn't add to our bitmap entry %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 1 * 1024 * 1024, 2 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, SZ_1M, SZ_2M);
if (ret) {
test_msg("Couldn't remove middle chunk %d\n", ret);
return ret;
@@ -177,23 +142,21 @@ static int test_bitmaps(struct btrfs_block_group_cache *cache)
next_bitmap_offset = (u64)(BITS_PER_BITMAP * 4096);
/* Test a bit straddling two bitmaps */
- ret = test_add_free_space_entry(cache, next_bitmap_offset -
- (2 * 1024 * 1024), 4 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, next_bitmap_offset - SZ_2M,
+ SZ_4M, 1);
if (ret) {
test_msg("Couldn't add space that straddles two bitmaps %d\n",
ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, next_bitmap_offset -
- (1 * 1024 * 1024), 2 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, next_bitmap_offset - SZ_1M, SZ_2M);
if (ret) {
test_msg("Couldn't remove overlapping space %d\n", ret);
return ret;
}
- if (test_check_exists(cache, next_bitmap_offset - (1 * 1024 * 1024),
- 2 * 1024 * 1024)) {
+ if (test_check_exists(cache, next_bitmap_offset - SZ_1M, SZ_2M)) {
test_msg("Left some space when removing overlapping\n");
return -1;
}
@@ -216,43 +179,43 @@ static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
* bitmap, but the free space completely in the extent and then
* completely in the bitmap.
*/
- ret = test_add_free_space_entry(cache, 4 * 1024 * 1024, 1 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, SZ_4M, SZ_1M, 1);
if (ret) {
test_msg("Couldn't create bitmap entry %d\n", ret);
return ret;
}
- ret = test_add_free_space_entry(cache, 0, 1 * 1024 * 1024, 0);
+ ret = test_add_free_space_entry(cache, 0, SZ_1M, 0);
if (ret) {
test_msg("Couldn't add extent entry %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 0, 1 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, 0, SZ_1M);
if (ret) {
test_msg("Couldn't remove extent entry %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 0, 1 * 1024 * 1024)) {
+ if (test_check_exists(cache, 0, SZ_1M)) {
test_msg("Left remnants after our remove\n");
return -1;
}
/* Now to add back the extent entry and remove from the bitmap */
- ret = test_add_free_space_entry(cache, 0, 1 * 1024 * 1024, 0);
+ ret = test_add_free_space_entry(cache, 0, SZ_1M, 0);
if (ret) {
test_msg("Couldn't re-add extent entry %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 4 * 1024 * 1024, 1 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, SZ_4M, SZ_1M);
if (ret) {
test_msg("Couldn't remove from bitmap %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 4 * 1024 * 1024, 1 * 1024 * 1024)) {
+ if (test_check_exists(cache, SZ_4M, SZ_1M)) {
test_msg("Left remnants in the bitmap\n");
return -1;
}
@@ -261,19 +224,19 @@ static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
* Ok so a little more evil, extent entry and bitmap at the same offset,
* removing an overlapping chunk.
*/
- ret = test_add_free_space_entry(cache, 1 * 1024 * 1024, 4 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, SZ_1M, SZ_4M, 1);
if (ret) {
test_msg("Couldn't add to a bitmap %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 512 * 1024, 3 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, SZ_512K, 3 * SZ_1M);
if (ret) {
test_msg("Couldn't remove overlapping space %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 512 * 1024, 3 * 1024 * 1024)) {
+ if (test_check_exists(cache, SZ_512K, 3 * SZ_1M)) {
test_msg("Left over pieces after removing overlapping\n");
return -1;
}
@@ -281,25 +244,25 @@ static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
__btrfs_remove_free_space_cache(cache->free_space_ctl);
/* Now with the extent entry offset into the bitmap */
- ret = test_add_free_space_entry(cache, 4 * 1024 * 1024, 4 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, SZ_4M, SZ_4M, 1);
if (ret) {
test_msg("Couldn't add space to the bitmap %d\n", ret);
return ret;
}
- ret = test_add_free_space_entry(cache, 2 * 1024 * 1024, 2 * 1024 * 1024, 0);
+ ret = test_add_free_space_entry(cache, SZ_2M, SZ_2M, 0);
if (ret) {
test_msg("Couldn't add extent to the cache %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 3 * 1024 * 1024, 4 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, 3 * SZ_1M, SZ_4M);
if (ret) {
test_msg("Problem removing overlapping space %d\n", ret);
return ret;
}
- if (test_check_exists(cache, 3 * 1024 * 1024, 4 * 1024 * 1024)) {
+ if (test_check_exists(cache, 3 * SZ_1M, SZ_4M)) {
test_msg("Left something behind when removing space");
return -1;
}
@@ -315,29 +278,26 @@ static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
* [ del ]
*/
__btrfs_remove_free_space_cache(cache->free_space_ctl);
- ret = test_add_free_space_entry(cache, bitmap_offset + 4 * 1024 * 1024,
- 4 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, bitmap_offset + SZ_4M, SZ_4M, 1);
if (ret) {
test_msg("Couldn't add bitmap %d\n", ret);
return ret;
}
- ret = test_add_free_space_entry(cache, bitmap_offset - 1 * 1024 * 1024,
- 5 * 1024 * 1024, 0);
+ ret = test_add_free_space_entry(cache, bitmap_offset - SZ_1M,
+ 5 * SZ_1M, 0);
if (ret) {
test_msg("Couldn't add extent entry %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, bitmap_offset + 1 * 1024 * 1024,
- 5 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, bitmap_offset + SZ_1M, 5 * SZ_1M);
if (ret) {
test_msg("Failed to free our space %d\n", ret);
return ret;
}
- if (test_check_exists(cache, bitmap_offset + 1 * 1024 * 1024,
- 5 * 1024 * 1024)) {
+ if (test_check_exists(cache, bitmap_offset + SZ_1M, 5 * SZ_1M)) {
test_msg("Left stuff over\n");
return -1;
}
@@ -350,19 +310,19 @@ static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
* to return -EAGAIN back from btrfs_remove_extent, make sure this
* doesn't happen.
*/
- ret = test_add_free_space_entry(cache, 1 * 1024 * 1024, 2 * 1024 * 1024, 1);
+ ret = test_add_free_space_entry(cache, SZ_1M, SZ_2M, 1);
if (ret) {
test_msg("Couldn't add bitmap entry %d\n", ret);
return ret;
}
- ret = test_add_free_space_entry(cache, 3 * 1024 * 1024, 1 * 1024 * 1024, 0);
+ ret = test_add_free_space_entry(cache, 3 * SZ_1M, SZ_1M, 0);
if (ret) {
test_msg("Couldn't add extent entry %d\n", ret);
return ret;
}
- ret = btrfs_remove_free_space(cache, 1 * 1024 * 1024, 3 * 1024 * 1024);
+ ret = btrfs_remove_free_space(cache, SZ_1M, 3 * SZ_1M);
if (ret) {
test_msg("Error removing bitmap and extent overlapping %d\n", ret);
return ret;
@@ -445,9 +405,11 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
int ret;
u64 offset;
u64 max_extent_size;
-
- bool (*use_bitmap_op)(struct btrfs_free_space_ctl *,
- struct btrfs_free_space *);
+ const struct btrfs_free_space_op test_free_space_ops = {
+ .recalc_thresholds = cache->free_space_ctl->op->recalc_thresholds,
+ .use_bitmap = test_use_bitmap,
+ };
+ const struct btrfs_free_space_op *orig_free_space_ops;
test_msg("Running space stealing from bitmap to extent\n");
@@ -469,22 +431,21 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* that forces use of bitmaps as soon as we have at least 1
* extent entry.
*/
- use_bitmap_op = cache->free_space_ctl->op->use_bitmap;
- cache->free_space_ctl->op->use_bitmap = test_use_bitmap;
+ orig_free_space_ops = cache->free_space_ctl->op;
+ cache->free_space_ctl->op = &test_free_space_ops;
/*
* Extent entry covering free space range [128Mb - 256Kb, 128Mb - 128Kb[
*/
- ret = test_add_free_space_entry(cache, 128 * 1024 * 1024 - 256 * 1024,
- 128 * 1024, 0);
+ ret = test_add_free_space_entry(cache, SZ_128M - SZ_256K, SZ_128K, 0);
if (ret) {
test_msg("Couldn't add extent entry %d\n", ret);
return ret;
}
/* Bitmap entry covering free space range [128Mb + 512Kb, 256Mb[ */
- ret = test_add_free_space_entry(cache, 128 * 1024 * 1024 + 512 * 1024,
- 128 * 1024 * 1024 - 512 * 1024, 1);
+ ret = test_add_free_space_entry(cache, SZ_128M + SZ_512K,
+ SZ_128M - SZ_512K, 1);
if (ret) {
test_msg("Couldn't add bitmap entry %d\n", ret);
return ret;
@@ -502,21 +463,19 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* [128Mb + 512Kb, 128Mb + 768Kb[
*/
ret = btrfs_remove_free_space(cache,
- 128 * 1024 * 1024 + 768 * 1024,
- 128 * 1024 * 1024 - 768 * 1024);
+ SZ_128M + 768 * SZ_1K,
+ SZ_128M - 768 * SZ_1K);
if (ret) {
test_msg("Failed to free part of bitmap space %d\n", ret);
return ret;
}
/* Confirm that only those 2 ranges are marked as free. */
- if (!test_check_exists(cache, 128 * 1024 * 1024 - 256 * 1024,
- 128 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M - SZ_256K, SZ_128K)) {
test_msg("Free space range missing\n");
return -ENOENT;
}
- if (!test_check_exists(cache, 128 * 1024 * 1024 + 512 * 1024,
- 256 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M + SZ_512K, SZ_256K)) {
test_msg("Free space range missing\n");
return -ENOENT;
}
@@ -525,8 +484,8 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* Confirm that the bitmap range [128Mb + 768Kb, 256Mb[ isn't marked
* as free anymore.
*/
- if (test_check_exists(cache, 128 * 1024 * 1024 + 768 * 1024,
- 128 * 1024 * 1024 - 768 * 1024)) {
+ if (test_check_exists(cache, SZ_128M + 768 * SZ_1K,
+ SZ_128M - 768 * SZ_1K)) {
test_msg("Bitmap region not removed from space cache\n");
return -EINVAL;
}
@@ -535,8 +494,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* Confirm that the region [128Mb + 256Kb, 128Mb + 512Kb[, which is
* covered by the bitmap, isn't marked as free.
*/
- if (test_check_exists(cache, 128 * 1024 * 1024 + 256 * 1024,
- 256 * 1024)) {
+ if (test_check_exists(cache, SZ_128M + SZ_256K, SZ_256K)) {
test_msg("Invalid bitmap region marked as free\n");
return -EINVAL;
}
@@ -545,8 +503,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* Confirm that the region [128Mb, 128Mb + 256Kb[, which is covered
* by the bitmap too, isn't marked as free either.
*/
- if (test_check_exists(cache, 128 * 1024 * 1024,
- 256 * 1024)) {
+ if (test_check_exists(cache, SZ_128M, SZ_256K)) {
test_msg("Invalid bitmap region marked as free\n");
return -EINVAL;
}
@@ -556,13 +513,13 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* lets make sure the free space cache marks it as free in the bitmap,
* and doesn't insert a new extent entry to represent this region.
*/
- ret = btrfs_add_free_space(cache, 128 * 1024 * 1024, 512 * 1024);
+ ret = btrfs_add_free_space(cache, SZ_128M, SZ_512K);
if (ret) {
test_msg("Error adding free space: %d\n", ret);
return ret;
}
/* Confirm the region is marked as free. */
- if (!test_check_exists(cache, 128 * 1024 * 1024, 512 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M, SZ_512K)) {
test_msg("Bitmap region not marked as free\n");
return -ENOENT;
}
@@ -581,8 +538,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* The goal is to test that the bitmap entry space stealing doesn't
* steal this space region.
*/
- ret = btrfs_add_free_space(cache, 128 * 1024 * 1024 + 16 * 1024 * 1024,
- 4096);
+ ret = btrfs_add_free_space(cache, SZ_128M + SZ_16M, 4096);
if (ret) {
test_msg("Error adding free space: %d\n", ret);
return ret;
@@ -601,15 +557,13 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* expand the range covered by the existing extent entry that represents
* the free space [128Mb - 256Kb, 128Mb - 128Kb[.
*/
- ret = btrfs_add_free_space(cache, 128 * 1024 * 1024 - 128 * 1024,
- 128 * 1024);
+ ret = btrfs_add_free_space(cache, SZ_128M - SZ_128K, SZ_128K);
if (ret) {
test_msg("Error adding free space: %d\n", ret);
return ret;
}
/* Confirm the region is marked as free. */
- if (!test_check_exists(cache, 128 * 1024 * 1024 - 128 * 1024,
- 128 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M - SZ_128K, SZ_128K)) {
test_msg("Extent region not marked as free\n");
return -ENOENT;
}
@@ -637,21 +591,20 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* that represents the 1Mb free space, and therefore we're able to
* allocate the whole free space at once.
*/
- if (!test_check_exists(cache, 128 * 1024 * 1024 - 256 * 1024,
- 1 * 1024 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M - SZ_256K, SZ_1M)) {
test_msg("Expected region not marked as free\n");
return -ENOENT;
}
- if (cache->free_space_ctl->free_space != (1 * 1024 * 1024 + 4096)) {
+ if (cache->free_space_ctl->free_space != (SZ_1M + 4096)) {
test_msg("Cache free space is not 1Mb + 4Kb\n");
return -EINVAL;
}
offset = btrfs_find_space_for_alloc(cache,
- 0, 1 * 1024 * 1024, 0,
+ 0, SZ_1M, 0,
&max_extent_size);
- if (offset != (128 * 1024 * 1024 - 256 * 1024)) {
+ if (offset != (SZ_128M - SZ_256K)) {
test_msg("Failed to allocate 1Mb from space cache, returned offset is: %llu\n",
offset);
return -EINVAL;
@@ -670,7 +623,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
offset = btrfs_find_space_for_alloc(cache,
0, 4096, 0,
&max_extent_size);
- if (offset != (128 * 1024 * 1024 + 16 * 1024 * 1024)) {
+ if (offset != (SZ_128M + SZ_16M)) {
test_msg("Failed to allocate 4Kb from space cache, returned offset is: %llu\n",
offset);
return -EINVAL;
@@ -691,16 +644,14 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
/*
* Extent entry covering free space range [128Mb + 128Kb, 128Mb + 256Kb[
*/
- ret = test_add_free_space_entry(cache, 128 * 1024 * 1024 + 128 * 1024,
- 128 * 1024, 0);
+ ret = test_add_free_space_entry(cache, SZ_128M + SZ_128K, SZ_128K, 0);
if (ret) {
test_msg("Couldn't add extent entry %d\n", ret);
return ret;
}
/* Bitmap entry covering free space range [0, 128Mb - 512Kb[ */
- ret = test_add_free_space_entry(cache, 0,
- 128 * 1024 * 1024 - 512 * 1024, 1);
+ ret = test_add_free_space_entry(cache, 0, SZ_128M - SZ_512K, 1);
if (ret) {
test_msg("Couldn't add bitmap entry %d\n", ret);
return ret;
@@ -717,22 +668,18 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* [128Mb + 128b, 128Mb + 256Kb[
* [128Mb - 768Kb, 128Mb - 512Kb[
*/
- ret = btrfs_remove_free_space(cache,
- 0,
- 128 * 1024 * 1024 - 768 * 1024);
+ ret = btrfs_remove_free_space(cache, 0, SZ_128M - 768 * SZ_1K);
if (ret) {
test_msg("Failed to free part of bitmap space %d\n", ret);
return ret;
}
/* Confirm that only those 2 ranges are marked as free. */
- if (!test_check_exists(cache, 128 * 1024 * 1024 + 128 * 1024,
- 128 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M + SZ_128K, SZ_128K)) {
test_msg("Free space range missing\n");
return -ENOENT;
}
- if (!test_check_exists(cache, 128 * 1024 * 1024 - 768 * 1024,
- 256 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M - 768 * SZ_1K, SZ_256K)) {
test_msg("Free space range missing\n");
return -ENOENT;
}
@@ -741,8 +688,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* Confirm that the bitmap range [0, 128Mb - 768Kb[ isn't marked
* as free anymore.
*/
- if (test_check_exists(cache, 0,
- 128 * 1024 * 1024 - 768 * 1024)) {
+ if (test_check_exists(cache, 0, SZ_128M - 768 * SZ_1K)) {
test_msg("Bitmap region not removed from space cache\n");
return -EINVAL;
}
@@ -751,8 +697,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* Confirm that the region [128Mb - 512Kb, 128Mb[, which is
* covered by the bitmap, isn't marked as free.
*/
- if (test_check_exists(cache, 128 * 1024 * 1024 - 512 * 1024,
- 512 * 1024)) {
+ if (test_check_exists(cache, SZ_128M - SZ_512K, SZ_512K)) {
test_msg("Invalid bitmap region marked as free\n");
return -EINVAL;
}
@@ -762,15 +707,13 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* lets make sure the free space cache marks it as free in the bitmap,
* and doesn't insert a new extent entry to represent this region.
*/
- ret = btrfs_add_free_space(cache, 128 * 1024 * 1024 - 512 * 1024,
- 512 * 1024);
+ ret = btrfs_add_free_space(cache, SZ_128M - SZ_512K, SZ_512K);
if (ret) {
test_msg("Error adding free space: %d\n", ret);
return ret;
}
/* Confirm the region is marked as free. */
- if (!test_check_exists(cache, 128 * 1024 * 1024 - 512 * 1024,
- 512 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M - SZ_512K, SZ_512K)) {
test_msg("Bitmap region not marked as free\n");
return -ENOENT;
}
@@ -789,7 +732,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* The goal is to test that the bitmap entry space stealing doesn't
* steal this space region.
*/
- ret = btrfs_add_free_space(cache, 32 * 1024 * 1024, 8192);
+ ret = btrfs_add_free_space(cache, SZ_32M, 8192);
if (ret) {
test_msg("Error adding free space: %d\n", ret);
return ret;
@@ -800,13 +743,13 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* expand the range covered by the existing extent entry that represents
* the free space [128Mb + 128Kb, 128Mb + 256Kb[.
*/
- ret = btrfs_add_free_space(cache, 128 * 1024 * 1024, 128 * 1024);
+ ret = btrfs_add_free_space(cache, SZ_128M, SZ_128K);
if (ret) {
test_msg("Error adding free space: %d\n", ret);
return ret;
}
/* Confirm the region is marked as free. */
- if (!test_check_exists(cache, 128 * 1024 * 1024, 128 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M, SZ_128K)) {
test_msg("Extent region not marked as free\n");
return -ENOENT;
}
@@ -834,21 +777,19 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
* that represents the 1Mb free space, and therefore we're able to
* allocate the whole free space at once.
*/
- if (!test_check_exists(cache, 128 * 1024 * 1024 - 768 * 1024,
- 1 * 1024 * 1024)) {
+ if (!test_check_exists(cache, SZ_128M - 768 * SZ_1K, SZ_1M)) {
test_msg("Expected region not marked as free\n");
return -ENOENT;
}
- if (cache->free_space_ctl->free_space != (1 * 1024 * 1024 + 8192)) {
+ if (cache->free_space_ctl->free_space != (SZ_1M + 8192)) {
test_msg("Cache free space is not 1Mb + 8Kb\n");
return -EINVAL;
}
- offset = btrfs_find_space_for_alloc(cache,
- 0, 1 * 1024 * 1024, 0,
+ offset = btrfs_find_space_for_alloc(cache, 0, SZ_1M, 0,
&max_extent_size);
- if (offset != (128 * 1024 * 1024 - 768 * 1024)) {
+ if (offset != (SZ_128M - 768 * SZ_1K)) {
test_msg("Failed to allocate 1Mb from space cache, returned offset is: %llu\n",
offset);
return -EINVAL;
@@ -867,7 +808,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
offset = btrfs_find_space_for_alloc(cache,
0, 8192, 0,
&max_extent_size);
- if (offset != (32 * 1024 * 1024)) {
+ if (offset != SZ_32M) {
test_msg("Failed to allocate 8Kb from space cache, returned offset is: %llu\n",
offset);
return -EINVAL;
@@ -877,7 +818,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
if (ret)
return ret;
- cache->free_space_ctl->op->use_bitmap = use_bitmap_op;
+ cache->free_space_ctl->op = orig_free_space_ops;
__btrfs_remove_free_space_cache(cache->free_space_ctl);
return 0;
@@ -891,7 +832,7 @@ int btrfs_test_free_space_cache(void)
test_msg("Running btrfs free space cache tests\n");
- cache = init_test_block_group();
+ cache = btrfs_alloc_dummy_block_group(1024 * 1024 * 1024);
if (!cache) {
test_msg("Couldn't run the tests\n");
return 0;
@@ -922,9 +863,7 @@ int btrfs_test_free_space_cache(void)
ret = test_steal_space_from_bitmap_to_extent(cache);
out:
- __btrfs_remove_free_space_cache(cache->free_space_ctl);
- kfree(cache->free_space_ctl);
- kfree(cache);
+ btrfs_free_dummy_block_group(cache);
btrfs_free_dummy_root(root);
test_msg("Free space cache tests finished\n");
return ret;
diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c
new file mode 100644
index 000000000000..d05fe1ab4808
--- /dev/null
+++ b/fs/btrfs/tests/free-space-tree-tests.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2015 Facebook. 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 v2 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include "btrfs-tests.h"
+#include "../ctree.h"
+#include "../disk-io.h"
+#include "../free-space-tree.h"
+#include "../transaction.h"
+
+struct free_space_extent {
+ u64 start, length;
+};
+
+/*
+ * The test cases align their operations to this in order to hit some of the
+ * edge cases in the bitmap code.
+ */
+#define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * 4096)
+
+static int __check_free_space_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path,
+ struct free_space_extent *extents,
+ unsigned int num_extents)
+{
+ struct btrfs_free_space_info *info;
+ struct btrfs_key key;
+ int prev_bit = 0, bit;
+ u64 extent_start = 0, offset, end;
+ u32 flags, extent_count;
+ unsigned int i;
+ int ret;
+
+ info = search_free_space_info(trans, fs_info, cache, path, 0);
+ if (IS_ERR(info)) {
+ test_msg("Could not find free space info\n");
+ ret = PTR_ERR(info);
+ goto out;
+ }
+ flags = btrfs_free_space_flags(path->nodes[0], info);
+ extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
+
+ if (extent_count != num_extents) {
+ test_msg("Extent count is wrong\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
+ if (path->slots[0] != 0)
+ goto invalid;
+ end = cache->key.objectid + cache->key.offset;
+ i = 0;
+ while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY)
+ goto invalid;
+ offset = key.objectid;
+ while (offset < key.objectid + key.offset) {
+ bit = free_space_test_bit(cache, path, offset);
+ if (prev_bit == 0 && bit == 1) {
+ extent_start = offset;
+ } else if (prev_bit == 1 && bit == 0) {
+ if (i >= num_extents)
+ goto invalid;
+ if (i >= num_extents ||
+ extent_start != extents[i].start ||
+ offset - extent_start != extents[i].length)
+ goto invalid;
+ i++;
+ }
+ prev_bit = bit;
+ offset += cache->sectorsize;
+ }
+ }
+ if (prev_bit == 1) {
+ if (i >= num_extents ||
+ extent_start != extents[i].start ||
+ end - extent_start != extents[i].length)
+ goto invalid;
+ i++;
+ }
+ if (i != num_extents)
+ goto invalid;
+ } else {
+ if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 ||
+ path->slots[0] != 0)
+ goto invalid;
+ for (i = 0; i < num_extents; i++) {
+ path->slots[0]++;
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY ||
+ key.objectid != extents[i].start ||
+ key.offset != extents[i].length)
+ goto invalid;
+ }
+ }
+
+ ret = 0;
+out:
+ btrfs_release_path(path);
+ return ret;
+invalid:
+ test_msg("Free space tree is invalid\n");
+ ret = -EINVAL;
+ goto out;
+}
+
+static int check_free_space_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path,
+ struct free_space_extent *extents,
+ unsigned int num_extents)
+{
+ struct btrfs_free_space_info *info;
+ u32 flags;
+ int ret;
+
+ info = search_free_space_info(trans, fs_info, cache, path, 0);
+ if (IS_ERR(info)) {
+ test_msg("Could not find free space info\n");
+ btrfs_release_path(path);
+ return PTR_ERR(info);
+ }
+ flags = btrfs_free_space_flags(path->nodes[0], info);
+ btrfs_release_path(path);
+
+ ret = __check_free_space_extents(trans, fs_info, cache, path, extents,
+ num_extents);
+ if (ret)
+ return ret;
+
+ /* Flip it to the other format and check that for good measure. */
+ if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
+ ret = convert_free_space_to_extents(trans, fs_info, cache, path);
+ if (ret) {
+ test_msg("Could not convert to extents\n");
+ return ret;
+ }
+ } else {
+ ret = convert_free_space_to_bitmaps(trans, fs_info, cache, path);
+ if (ret) {
+ test_msg("Could not convert to bitmaps\n");
+ return ret;
+ }
+ }
+ return __check_free_space_extents(trans, fs_info, cache, path, extents,
+ num_extents);
+}
+
+static int test_empty_block_group(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid, cache->key.offset},
+ };
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_remove_all(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {};
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid,
+ cache->key.offset);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_remove_beginning(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid + BITMAP_RANGE,
+ cache->key.offset - BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid, BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+
+}
+
+static int test_remove_end(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid, cache->key.offset - BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid +
+ cache->key.offset - BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_remove_middle(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid, BITMAP_RANGE},
+ {cache->key.objectid + 2 * BITMAP_RANGE,
+ cache->key.offset - 2 * BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_merge_left(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid, 2 * BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid,
+ cache->key.offset);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid, BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_merge_right(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid + BITMAP_RANGE, 2 * BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid,
+ cache->key.offset);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + 2 * BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_merge_both(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid, 3 * BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid,
+ cache->key.offset);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid, BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + 2 * BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+static int test_merge_none(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_block_group_cache *cache,
+ struct btrfs_path *path)
+{
+ struct free_space_extent extents[] = {
+ {cache->key.objectid, BITMAP_RANGE},
+ {cache->key.objectid + 2 * BITMAP_RANGE, BITMAP_RANGE},
+ {cache->key.objectid + 4 * BITMAP_RANGE, BITMAP_RANGE},
+ };
+ int ret;
+
+ ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid,
+ cache->key.offset);
+ if (ret) {
+ test_msg("Could not remove free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid, BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + 4 * BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ ret = __add_to_free_space_tree(trans, fs_info, cache, path,
+ cache->key.objectid + 2 * BITMAP_RANGE,
+ BITMAP_RANGE);
+ if (ret) {
+ test_msg("Could not add free space\n");
+ return ret;
+ }
+
+ return check_free_space_extents(trans, fs_info, cache, path,
+ extents, ARRAY_SIZE(extents));
+}
+
+typedef int (*test_func_t)(struct btrfs_trans_handle *,
+ struct btrfs_fs_info *,
+ struct btrfs_block_group_cache *,
+ struct btrfs_path *);
+
+static int run_test(test_func_t test_func, int bitmaps)
+{
+ struct btrfs_root *root = NULL;
+ struct btrfs_block_group_cache *cache = NULL;
+ struct btrfs_trans_handle trans;
+ struct btrfs_path *path = NULL;
+ int ret;
+
+ root = btrfs_alloc_dummy_root();
+ if (IS_ERR(root)) {
+ test_msg("Couldn't allocate dummy root\n");
+ ret = PTR_ERR(root);
+ goto out;
+ }
+
+ root->fs_info = btrfs_alloc_dummy_fs_info();
+ if (!root->fs_info) {
+ test_msg("Couldn't allocate dummy fs info\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ btrfs_set_super_compat_ro_flags(root->fs_info->super_copy,
+ BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE);
+ root->fs_info->free_space_root = root;
+ root->fs_info->tree_root = root;
+
+ root->node = alloc_test_extent_buffer(root->fs_info, 4096);
+ if (!root->node) {
+ test_msg("Couldn't allocate dummy buffer\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ btrfs_set_header_level(root->node, 0);
+ btrfs_set_header_nritems(root->node, 0);
+ root->alloc_bytenr += 8192;
+
+ cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE);
+ if (!cache) {
+ test_msg("Couldn't allocate dummy block group cache\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ cache->bitmap_low_thresh = 0;
+ cache->bitmap_high_thresh = (u32)-1;
+ cache->needs_free_space = 1;
+
+ btrfs_init_dummy_trans(&trans);
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ test_msg("Couldn't allocate path\n");
+ return -ENOMEM;
+ }
+
+ ret = add_block_group_free_space(&trans, root->fs_info, cache);
+ if (ret) {
+ test_msg("Could not add block group free space\n");
+ goto out;
+ }
+
+ if (bitmaps) {
+ ret = convert_free_space_to_bitmaps(&trans, root->fs_info,
+ cache, path);
+ if (ret) {
+ test_msg("Could not convert block group to bitmaps\n");
+ goto out;
+ }
+ }
+
+ ret = test_func(&trans, root->fs_info, cache, path);
+ if (ret)
+ goto out;
+
+ ret = remove_block_group_free_space(&trans, root->fs_info, cache);
+ if (ret) {
+ test_msg("Could not remove block group free space\n");
+ goto out;
+ }
+
+ if (btrfs_header_nritems(root->node) != 0) {
+ test_msg("Free space tree has leftover items\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ btrfs_free_path(path);
+ btrfs_free_dummy_block_group(cache);
+ btrfs_free_dummy_root(root);
+ return ret;
+}
+
+static int run_test_both_formats(test_func_t test_func)
+{
+ int ret;
+
+ ret = run_test(test_func, 0);
+ if (ret)
+ return ret;
+ return run_test(test_func, 1);
+}
+
+int btrfs_test_free_space_tree(void)
+{
+ test_func_t tests[] = {
+ test_empty_block_group,
+ test_remove_all,
+ test_remove_beginning,
+ test_remove_end,
+ test_remove_middle,
+ test_merge_left,
+ test_merge_right,
+ test_merge_both,
+ test_merge_none,
+ };
+ int i;
+
+ test_msg("Running free space tree tests\n");
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ int ret = run_test_both_formats(tests[i]);
+ if (ret) {
+ test_msg("%pf failed\n", tests[i]);
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c
index 054fc0d97131..5de55fdd28bc 100644
--- a/fs/btrfs/tests/inode-tests.c
+++ b/fs/btrfs/tests/inode-tests.c
@@ -100,7 +100,7 @@ static void insert_inode_item_key(struct btrfs_root *root)
static void setup_file_extents(struct btrfs_root *root)
{
int slot = 0;
- u64 disk_bytenr = 1 * 1024 * 1024;
+ u64 disk_bytenr = SZ_1M;
u64 offset = 0;
/* First we want a hole */
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index 846d277b1901..8ea5d34bc5a2 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -23,14 +23,6 @@
#include "../qgroup.h"
#include "../backref.h"
-static void init_dummy_trans(struct btrfs_trans_handle *trans)
-{
- memset(trans, 0, sizeof(*trans));
- trans->transid = 1;
- INIT_LIST_HEAD(&trans->qgroup_ref_list);
- trans->type = __TRANS_DUMMY;
-}
-
static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
u64 num_bytes, u64 parent, u64 root_objectid)
{
@@ -44,7 +36,7 @@ static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
int ret;
- init_dummy_trans(&trans);
+ btrfs_init_dummy_trans(&trans);
ins.objectid = bytenr;
ins.type = BTRFS_EXTENT_ITEM_KEY;
@@ -94,7 +86,7 @@ static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
u64 refs;
int ret;
- init_dummy_trans(&trans);
+ btrfs_init_dummy_trans(&trans);
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -144,7 +136,7 @@ static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
struct btrfs_path *path;
int ret;
- init_dummy_trans(&trans);
+ btrfs_init_dummy_trans(&trans);
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -178,7 +170,7 @@ static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
u64 refs;
int ret;
- init_dummy_trans(&trans);
+ btrfs_init_dummy_trans(&trans);
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -232,7 +224,7 @@ static int test_no_shared_qgroup(struct btrfs_root *root)
struct ulist *new_roots = NULL;
int ret;
- init_dummy_trans(&trans);
+ btrfs_init_dummy_trans(&trans);
test_msg("Qgroup basic add\n");
ret = btrfs_create_qgroup(NULL, fs_info, 5);
@@ -326,7 +318,7 @@ static int test_multiple_refs(struct btrfs_root *root)
struct ulist *new_roots = NULL;
int ret;
- init_dummy_trans(&trans);
+ btrfs_init_dummy_trans(&trans);
test_msg("Qgroup multiple refs test\n");
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index be8eae80ff65..b6031ce474f7 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -75,6 +75,23 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
list_del_init(&em->list);
free_extent_map(em);
}
+ /*
+ * If any block groups are found in ->deleted_bgs then it's
+ * because the transaction was aborted and a commit did not
+ * happen (things failed before writing the new superblock
+ * and calling btrfs_finish_extent_commit()), so we can not
+ * discard the physical locations of the block groups.
+ */
+ while (!list_empty(&transaction->deleted_bgs)) {
+ struct btrfs_block_group_cache *cache;
+
+ cache = list_first_entry(&transaction->deleted_bgs,
+ struct btrfs_block_group_cache,
+ bg_list);
+ list_del_init(&cache->bg_list);
+ btrfs_put_block_group_trimming(cache);
+ btrfs_put_block_group(cache);
+ }
kmem_cache_free(btrfs_transaction_cachep, transaction);
}
}
@@ -634,17 +651,20 @@ struct btrfs_trans_handle *btrfs_start_transaction_lflush(
struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_JOIN, 0);
+ return start_transaction(root, 0, TRANS_JOIN,
+ BTRFS_RESERVE_NO_FLUSH);
}
struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_JOIN_NOLOCK, 0);
+ return start_transaction(root, 0, TRANS_JOIN_NOLOCK,
+ BTRFS_RESERVE_NO_FLUSH);
}
struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_USERSPACE, 0);
+ return start_transaction(root, 0, TRANS_USERSPACE,
+ BTRFS_RESERVE_NO_FLUSH);
}
/*
@@ -662,7 +682,8 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root
*/
struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_ATTACH, 0);
+ return start_transaction(root, 0, TRANS_ATTACH,
+ BTRFS_RESERVE_NO_FLUSH);
}
/*
@@ -677,7 +698,8 @@ btrfs_attach_transaction_barrier(struct btrfs_root *root)
{
struct btrfs_trans_handle *trans;
- trans = start_transaction(root, 0, TRANS_ATTACH, 0);
+ trans = start_transaction(root, 0, TRANS_ATTACH,
+ BTRFS_RESERVE_NO_FLUSH);
if (IS_ERR(trans) && PTR_ERR(trans) == -ENOENT)
btrfs_wait_for_commit(root, 0);
@@ -1319,17 +1341,11 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
u64 root_flags;
uuid_le new_uuid;
- path = btrfs_alloc_path();
- if (!path) {
- pending->error = -ENOMEM;
- return 0;
- }
+ ASSERT(pending->path);
+ path = pending->path;
- new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
- if (!new_root_item) {
- pending->error = -ENOMEM;
- goto root_item_alloc_fail;
- }
+ ASSERT(pending->root_item);
+ new_root_item = pending->root_item;
pending->error = btrfs_find_free_objectid(tree_root, &objectid);
if (pending->error)
@@ -1562,8 +1578,10 @@ clear_skip_qgroup:
btrfs_clear_skip_qgroup(trans);
no_free_objectid:
kfree(new_root_item);
-root_item_alloc_fail:
+ pending->root_item = NULL;
btrfs_free_path(path);
+ pending->path = NULL;
+
return ret;
}
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 64c8221b6165..72be51f7ca2f 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -137,8 +137,10 @@ struct btrfs_pending_snapshot {
struct dentry *dentry;
struct inode *dir;
struct btrfs_root *root;
+ struct btrfs_root_item *root_item;
struct btrfs_root *snap;
struct btrfs_qgroup_inherit *inherit;
+ struct btrfs_path *path;
/* block reservation for the operation */
struct btrfs_block_rsv block_rsv;
u64 qgroup_reserved;
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index f31db4325339..cb65089127cc 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -89,6 +89,12 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
goto out;
}
btrfs_release_path(path);
+ /*
+ * We don't need a lock on a leaf. btrfs_realloc_node() will lock all
+ * leafs from path->nodes[1], so set lowest_level to 1 to avoid later
+ * a deadlock (attempting to write lock an already write locked leaf).
+ */
+ path->lowest_level = 1;
wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (wret < 0) {
@@ -99,9 +105,12 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
ret = 0;
goto out;
}
- path->slots[1] = btrfs_header_nritems(path->nodes[1]);
- next_key_ret = btrfs_find_next_key(root, path, &key, 1,
- min_trans);
+ /*
+ * The node at level 1 must always be locked when our path has
+ * keep_locks set and lowest_level is 1, regardless of the value of
+ * path->slots[1].
+ */
+ BUG_ON(path->locks[1] == 0);
ret = btrfs_realloc_node(trans, root,
path->nodes[1], 0,
&last_ret,
@@ -110,6 +119,18 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
WARN_ON(ret == -EAGAIN);
goto out;
}
+ /*
+ * Now that we reallocated the node we can find the next key. Note that
+ * btrfs_find_next_key() can release our path and do another search
+ * without COWing, this is because even with path->keep_locks = 1,
+ * btrfs_search_slot() / ctree.c:unlock_up() does not keeps a lock on a
+ * node when path->slots[node_level - 1] does not point to the last
+ * item or a slot beyond the last item (ctree.c:unlock_up()). Therefore
+ * we search for the next key after reallocating our node.
+ */
+ path->slots[1] = btrfs_header_nritems(path->nodes[1]);
+ next_key_ret = btrfs_find_next_key(root, path, &key, 1,
+ min_trans);
if (next_key_ret == 0) {
memcpy(&root->defrag_progress, &key, sizeof(key));
ret = -EAGAIN;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index a23399e8e3ab..c32abbca9d77 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -125,6 +125,7 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root);
static void __btrfs_reset_dev_stats(struct btrfs_device *dev);
static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev);
static void btrfs_dev_stat_print_on_load(struct btrfs_device *device);
+static void btrfs_close_one_device(struct btrfs_device *device);
DEFINE_MUTEX(uuid_mutex);
static LIST_HEAD(fs_uuids);
@@ -1102,7 +1103,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 2;
+ path->reada = READA_FORWARD;
key.objectid = device->devid;
key.offset = start;
@@ -1257,6 +1258,15 @@ int find_free_dev_extent_start(struct btrfs_transaction *transaction,
int ret;
int slot;
struct extent_buffer *l;
+ u64 min_search_start;
+
+ /*
+ * We don't want to overwrite the superblock on the drive nor any area
+ * used by the boot loader (grub for example), so we make sure to start
+ * at an offset of at least 1MB.
+ */
+ min_search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
+ search_start = max(search_start, min_search_start);
path = btrfs_alloc_path();
if (!path)
@@ -1271,7 +1281,7 @@ again:
goto out;
}
- path->reada = 2;
+ path->reada = READA_FORWARD;
path->search_commit_root = 1;
path->skip_locking = 1;
@@ -1397,18 +1407,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 num_bytes,
u64 *start, u64 *len)
{
- struct btrfs_root *root = device->dev_root;
- u64 search_start;
-
/* FIXME use last free of some kind */
-
- /*
- * we don't want to overwrite the superblock on the drive,
- * so we make sure to start at an offset of at least 1MB
- */
- search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
return find_free_dev_extent_start(trans->transaction, device,
- num_bytes, search_start, start, len);
+ num_bytes, 0, start, len);
}
static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
@@ -1642,7 +1643,6 @@ static void update_dev_time(char *path_name)
return;
file_update_time(filp);
filp_close(filp, NULL);
- return;
}
static int btrfs_rm_dev_item(struct btrfs_root *root,
@@ -3406,7 +3406,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
list_for_each_entry(device, devices, dev_list) {
old_size = btrfs_device_get_total_bytes(device);
size_to_free = div_factor(old_size, 1);
- size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
+ size_to_free = min_t(u64, size_to_free, SZ_1M);
if (!device->writeable ||
btrfs_device_get_total_bytes(device) -
btrfs_device_get_bytes_used(device) > size_to_free ||
@@ -3723,14 +3723,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
goto out;
}
- /* allow dup'ed data chunks only in mixed mode */
- if (!mixed && (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
- (bctl->data.target & BTRFS_BLOCK_GROUP_DUP)) {
- btrfs_err(fs_info, "dup for data is not allowed");
- ret = -EINVAL;
- goto out;
- }
-
/* allow to reduce meta or sys integrity only if force set */
allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10 |
@@ -3756,6 +3748,13 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
}
} while (read_seqretry(&fs_info->profiles_lock, seq));
+ if (btrfs_get_num_tolerated_disk_barrier_failures(bctl->meta.target) <
+ btrfs_get_num_tolerated_disk_barrier_failures(bctl->data.target)) {
+ btrfs_warn(fs_info,
+ "metatdata profile 0x%llx has lower redundancy than data profile 0x%llx",
+ bctl->meta.target, bctl->data.target);
+ }
+
if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
fs_info->num_tolerated_disk_barrier_failures = min(
btrfs_calc_num_tolerated_disk_barrier_failures(fs_info),
@@ -4268,7 +4267,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
if (!path)
return -ENOMEM;
- path->reada = 2;
+ path->reada = READA_FORWARD;
lock_chunks(root);
@@ -4460,7 +4459,7 @@ static int btrfs_cmp_device_info(const void *a, const void *b)
static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target)
{
/* TODO allow them to set a preferred stripe size */
- return 64 * 1024;
+ return SZ_64K;
}
static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
@@ -4528,21 +4527,21 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
ncopies = btrfs_raid_array[index].ncopies;
if (type & BTRFS_BLOCK_GROUP_DATA) {
- max_stripe_size = 1024 * 1024 * 1024;
+ max_stripe_size = SZ_1G;
max_chunk_size = 10 * max_stripe_size;
if (!devs_max)
devs_max = BTRFS_MAX_DEVS(info->chunk_root);
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
/* for larger filesystems, use larger metadata chunks */
- if (fs_devices->total_rw_bytes > 50ULL * 1024 * 1024 * 1024)
- max_stripe_size = 1024 * 1024 * 1024;
+ if (fs_devices->total_rw_bytes > 50ULL * SZ_1G)
+ max_stripe_size = SZ_1G;
else
- max_stripe_size = 256 * 1024 * 1024;
+ max_stripe_size = SZ_256M;
max_chunk_size = max_stripe_size;
if (!devs_max)
devs_max = BTRFS_MAX_DEVS(info->chunk_root);
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
- max_stripe_size = 32 * 1024 * 1024;
+ max_stripe_size = SZ_32M;
max_chunk_size = 2 * max_stripe_size;
if (!devs_max)
devs_max = BTRFS_MAX_DEVS_SYS_CHUNK;
@@ -4793,7 +4792,7 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
u64 dev_offset;
u64 stripe_size;
int i = 0;
- int ret;
+ int ret = 0;
em_tree = &extent_root->fs_info->mapping_tree.map_tree;
read_lock(&em_tree->lock);
@@ -4824,20 +4823,32 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
goto out;
}
+ /*
+ * Take the device list mutex to prevent races with the final phase of
+ * a device replace operation that replaces the device object associated
+ * with the map's stripes, because the device object's id can change
+ * at any time during that final phase of the device replace operation
+ * (dev-replace.c:btrfs_dev_replace_finishing()).
+ */
+ mutex_lock(&chunk_root->fs_info->fs_devices->device_list_mutex);
for (i = 0; i < map->num_stripes; i++) {
device = map->stripes[i].dev;
dev_offset = map->stripes[i].physical;
ret = btrfs_update_device(trans, device);
if (ret)
- goto out;
+ break;
ret = btrfs_alloc_dev_extent(trans, device,
chunk_root->root_key.objectid,
BTRFS_FIRST_CHUNK_TREE_OBJECTID,
chunk_offset, dev_offset,
stripe_size);
if (ret)
- goto out;
+ break;
+ }
+ if (ret) {
+ mutex_unlock(&chunk_root->fs_info->fs_devices->device_list_mutex);
+ goto out;
}
stripe = &chunk->stripe;
@@ -4850,6 +4861,7 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE);
stripe++;
}
+ mutex_unlock(&chunk_root->fs_info->fs_devices->device_list_mutex);
btrfs_set_stack_chunk_length(chunk, chunk_size);
btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid);
@@ -6465,11 +6477,11 @@ int btrfs_read_sys_array(struct btrfs_root *root)
sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET);
if (!sb)
return -ENOMEM;
- btrfs_set_buffer_uptodate(sb);
+ set_extent_buffer_uptodate(sb);
btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0);
/*
* The sb extent buffer is artifical and just used to read the system array.
- * btrfs_set_buffer_uptodate() call does not properly mark all it's
+ * set_extent_buffer_uptodate() call does not properly mark all it's
* pages up-to-date when the page is larger: extent does not cover the
* whole page and consequently check_page_uptodate does not find all
* the page's extents up-to-date (the hole beyond sb),
@@ -6512,6 +6524,14 @@ int btrfs_read_sys_array(struct btrfs_root *root)
goto out_short_read;
num_stripes = btrfs_chunk_num_stripes(sb, chunk);
+ if (!num_stripes) {
+ printk(KERN_ERR
+ "BTRFS: invalid number of stripes %u in sys_array at offset %u\n",
+ num_stripes, cur_offset);
+ ret = -EIO;
+ break;
+ }
+
len = btrfs_chunk_item_size(num_stripes);
if (cur_offset + len > array_size)
goto out_short_read;
@@ -6520,6 +6540,9 @@ int btrfs_read_sys_array(struct btrfs_root *root)
if (ret)
break;
} else {
+ printk(KERN_ERR
+ "BTRFS: unexpected item type %u in sys_array at offset %u\n",
+ (u32)key.type, cur_offset);
ret = -EIO;
break;
}
@@ -6949,7 +6972,7 @@ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info)
}
}
-void btrfs_close_one_device(struct btrfs_device *device)
+static void btrfs_close_one_device(struct btrfs_device *device)
{
struct btrfs_fs_devices *fs_devices = device->fs_devices;
struct btrfs_device *new_device;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index d5c84f6b1353..1939ebde63df 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -26,7 +26,7 @@
extern struct mutex uuid_mutex;
-#define BTRFS_STRIPE_LEN (64 * 1024)
+#define BTRFS_STRIPE_LEN SZ_64K
struct buffer_head;
struct btrfs_pending_bios {
@@ -566,6 +566,5 @@ static inline void unlock_chunks(struct btrfs_root *root)
struct list_head *btrfs_get_fs_uuids(void);
void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
-void btrfs_close_one_device(struct btrfs_device *device);
#endif
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index 7cbef1a14fe1..fd953c361a43 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -283,7 +283,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 2;
+ path->reada = READA_FORWARD;
/* search for our xattrs */
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -446,7 +446,7 @@ static int btrfs_initxattrs(struct inode *inode,
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
- strlen(xattr->name) + 1, GFP_NOFS);
+ strlen(xattr->name) + 1, GFP_KERNEL);
if (!name) {
err = -ENOMEM;
break;
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index f446afada328..ca4d5e8457f1 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -639,8 +639,8 @@ static int __init init_caches(void)
ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
sizeof(struct ceph_inode_info),
__alignof__(struct ceph_inode_info),
- (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
- ceph_inode_init_once);
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
+ SLAB_ACCOUNT, ceph_inode_init_once);
if (ceph_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b7fcb3151103..c4c1169814b2 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1092,7 +1092,7 @@ cifs_init_inodecache(void)
cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
sizeof(struct cifsInodeInfo),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
cifs_init_once);
if (cifs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0068e82217c3..0a2752b79e72 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3391,13 +3391,13 @@ readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
* should have access to this page, we're safe to simply set
* PG_locked without checking it first.
*/
- __set_page_locked(page);
+ __SetPageLocked(page);
rc = add_to_page_cache_locked(page, mapping,
page->index, gfp);
/* give up if we can't stick it in the cache */
if (rc) {
- __clear_page_locked(page);
+ __ClearPageLocked(page);
return rc;
}
@@ -3418,9 +3418,9 @@ readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
if (*bytes + PAGE_CACHE_SIZE > rsize)
break;
- __set_page_locked(page);
+ __SetPageLocked(page);
if (add_to_page_cache_locked(page, mapping, page->index, gfp)) {
- __clear_page_locked(page);
+ __ClearPageLocked(page);
break;
}
list_move_tail(&page->lru, tmplist);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index cac1390b87a3..57e81cbba0fa 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -74,9 +74,9 @@ static void init_once(void *foo)
int __init coda_init_inodecache(void)
{
coda_inode_cachep = kmem_cache_create("coda_inode_cache",
- sizeof(struct coda_inode_info),
- 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once);
+ sizeof(struct coda_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
+ SLAB_ACCOUNT, init_once);
if (coda_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 7ae97e83f121..cab612b2ae76 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1070,11 +1070,55 @@ out:
return ret;
}
+static int configfs_do_depend_item(struct dentry *subsys_dentry,
+ struct config_item *target)
+{
+ struct configfs_dirent *p;
+ int ret;
+
+ spin_lock(&configfs_dirent_lock);
+ /* Scan the tree, return 0 if found */
+ ret = configfs_depend_prep(subsys_dentry, target);
+ if (ret)
+ goto out_unlock_dirent_lock;
+
+ /*
+ * We are sure that the item is not about to be removed by rmdir(), and
+ * not in the middle of attachment by mkdir().
+ */
+ p = target->ci_dentry->d_fsdata;
+ p->s_dependent_count += 1;
+
+out_unlock_dirent_lock:
+ spin_unlock(&configfs_dirent_lock);
+
+ return ret;
+}
+
+static inline struct configfs_dirent *
+configfs_find_subsys_dentry(struct configfs_dirent *root_sd,
+ struct config_item *subsys_item)
+{
+ struct configfs_dirent *p;
+ struct configfs_dirent *ret = NULL;
+
+ list_for_each_entry(p, &root_sd->s_children, s_sibling) {
+ if (p->s_type & CONFIGFS_DIR &&
+ p->s_element == subsys_item) {
+ ret = p;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
int configfs_depend_item(struct configfs_subsystem *subsys,
struct config_item *target)
{
int ret;
- struct configfs_dirent *p, *root_sd, *subsys_sd = NULL;
+ struct configfs_dirent *subsys_sd;
struct config_item *s_item = &subsys->su_group.cg_item;
struct dentry *root;
@@ -1093,39 +1137,15 @@ int configfs_depend_item(struct configfs_subsystem *subsys,
*/
mutex_lock(&d_inode(root)->i_mutex);
- root_sd = root->d_fsdata;
-
- list_for_each_entry(p, &root_sd->s_children, s_sibling) {
- if (p->s_type & CONFIGFS_DIR) {
- if (p->s_element == s_item) {
- subsys_sd = p;
- break;
- }
- }
- }
-
+ subsys_sd = configfs_find_subsys_dentry(root->d_fsdata, s_item);
if (!subsys_sd) {
ret = -ENOENT;
goto out_unlock_fs;
}
/* Ok, now we can trust subsys/s_item */
+ ret = configfs_do_depend_item(subsys_sd->s_dentry, target);
- spin_lock(&configfs_dirent_lock);
- /* Scan the tree, return 0 if found */
- ret = configfs_depend_prep(subsys_sd->s_dentry, target);
- if (ret)
- goto out_unlock_dirent_lock;
-
- /*
- * We are sure that the item is not about to be removed by rmdir(), and
- * not in the middle of attachment by mkdir().
- */
- p = target->ci_dentry->d_fsdata;
- p->s_dependent_count += 1;
-
-out_unlock_dirent_lock:
- spin_unlock(&configfs_dirent_lock);
out_unlock_fs:
mutex_unlock(&d_inode(root)->i_mutex);
@@ -1144,8 +1164,7 @@ EXPORT_SYMBOL(configfs_depend_item);
* configfs_depend_item() because we know that that the client driver is
* pinned, thus the subsystem is pinned, and therefore configfs is pinned.
*/
-void configfs_undepend_item(struct configfs_subsystem *subsys,
- struct config_item *target)
+void configfs_undepend_item(struct config_item *target)
{
struct configfs_dirent *sd;
@@ -1168,6 +1187,79 @@ void configfs_undepend_item(struct configfs_subsystem *subsys,
}
EXPORT_SYMBOL(configfs_undepend_item);
+/*
+ * caller_subsys is a caller's subsystem not target's. This is used to
+ * determine if we should lock root and check subsys or not. When we are
+ * in the same subsystem as our target there is no need to do locking as
+ * we know that subsys is valid and is not unregistered during this function
+ * as we are called from callback of one of his children and VFS holds a lock
+ * on some inode. Otherwise we have to lock our root to ensure that target's
+ * subsystem it is not unregistered during this function.
+ */
+int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys,
+ struct config_item *target)
+{
+ struct configfs_subsystem *target_subsys;
+ struct config_group *root, *parent;
+ struct configfs_dirent *subsys_sd;
+ int ret = -ENOENT;
+
+ /* Disallow this function for configfs root */
+ if (configfs_is_root(target))
+ return -EINVAL;
+
+ parent = target->ci_group;
+ /*
+ * This may happen when someone is trying to depend root
+ * directory of some subsystem
+ */
+ if (configfs_is_root(&parent->cg_item)) {
+ target_subsys = to_configfs_subsystem(to_config_group(target));
+ root = parent;
+ } else {
+ target_subsys = parent->cg_subsys;
+ /* Find a cofnigfs root as we may need it for locking */
+ for (root = parent; !configfs_is_root(&root->cg_item);
+ root = root->cg_item.ci_group)
+ ;
+ }
+
+ if (target_subsys != caller_subsys) {
+ /*
+ * We are in other configfs subsystem, so we have to do
+ * additional locking to prevent other subsystem from being
+ * unregistered
+ */
+ mutex_lock(&d_inode(root->cg_item.ci_dentry)->i_mutex);
+
+ /*
+ * As we are trying to depend item from other subsystem
+ * we have to check if this subsystem is still registered
+ */
+ subsys_sd = configfs_find_subsys_dentry(
+ root->cg_item.ci_dentry->d_fsdata,
+ &target_subsys->su_group.cg_item);
+ if (!subsys_sd)
+ goto out_root_unlock;
+ } else {
+ subsys_sd = target_subsys->su_group.cg_item.ci_dentry->d_fsdata;
+ }
+
+ /* Now we can execute core of depend item */
+ ret = configfs_do_depend_item(subsys_sd->s_dentry, target);
+
+ if (target_subsys != caller_subsys)
+out_root_unlock:
+ /*
+ * We were called from subsystem other than our target so we
+ * took some locks so now it's time to release them
+ */
+ mutex_unlock(&d_inode(root->cg_item.ci_dentry)->i_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(configfs_depend_item_unlocked);
+
static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int ret = 0;
diff --git a/fs/dax.c b/fs/dax.c
index 43671b68220e..7af879759064 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -28,54 +28,68 @@
#include <linux/sched.h>
#include <linux/uio.h>
#include <linux/vmstat.h>
+#include <linux/pfn_t.h>
+#include <linux/sizes.h>
+
+static long dax_map_atomic(struct block_device *bdev, struct blk_dax_ctl *dax)
+{
+ struct request_queue *q = bdev->bd_queue;
+ long rc = -EIO;
+
+ dax->addr = (void __pmem *) ERR_PTR(-EIO);
+ if (blk_queue_enter(q, true) != 0)
+ return rc;
+
+ rc = bdev_direct_access(bdev, dax);
+ if (rc < 0) {
+ dax->addr = (void __pmem *) ERR_PTR(rc);
+ blk_queue_exit(q);
+ return rc;
+ }
+ return rc;
+}
+
+static void dax_unmap_atomic(struct block_device *bdev,
+ const struct blk_dax_ctl *dax)
+{
+ if (IS_ERR(dax->addr))
+ return;
+ blk_queue_exit(bdev->bd_queue);
+}
/*
* dax_clear_blocks() is called from within transaction context from XFS,
* and hence this means the stack from this point must follow GFP_NOFS
* semantics for all operations.
*/
-int dax_clear_blocks(struct inode *inode, sector_t block, long size)
+int dax_clear_blocks(struct inode *inode, sector_t block, long _size)
{
struct block_device *bdev = inode->i_sb->s_bdev;
- sector_t sector = block << (inode->i_blkbits - 9);
+ struct blk_dax_ctl dax = {
+ .sector = block << (inode->i_blkbits - 9),
+ .size = _size,
+ };
might_sleep();
do {
- void __pmem *addr;
- unsigned long pfn;
- long count;
+ long count, sz;
- count = bdev_direct_access(bdev, sector, &addr, &pfn, size);
+ count = dax_map_atomic(bdev, &dax);
if (count < 0)
return count;
- BUG_ON(size < count);
- while (count > 0) {
- unsigned pgsz = PAGE_SIZE - offset_in_page(addr);
- if (pgsz > count)
- pgsz = count;
- clear_pmem(addr, pgsz);
- addr += pgsz;
- size -= pgsz;
- count -= pgsz;
- BUG_ON(pgsz & 511);
- sector += pgsz / 512;
- cond_resched();
- }
- } while (size);
+ sz = min_t(long, count, SZ_128K);
+ clear_pmem(dax.addr, sz);
+ dax.size -= sz;
+ dax.sector += sz / 512;
+ dax_unmap_atomic(bdev, &dax);
+ cond_resched();
+ } while (dax.size);
wmb_pmem();
return 0;
}
EXPORT_SYMBOL_GPL(dax_clear_blocks);
-static long dax_get_addr(struct buffer_head *bh, void __pmem **addr,
- unsigned blkbits)
-{
- unsigned long pfn;
- sector_t sector = bh->b_blocknr << (blkbits - 9);
- return bdev_direct_access(bh->b_bdev, sector, addr, &pfn, bh->b_size);
-}
-
/* the clear_pmem() calls are ordered by a wmb_pmem() in the caller */
static void dax_new_buf(void __pmem *addr, unsigned size, unsigned first,
loff_t pos, loff_t end)
@@ -105,19 +119,29 @@ static bool buffer_size_valid(struct buffer_head *bh)
return bh->b_state != 0;
}
+
+static sector_t to_sector(const struct buffer_head *bh,
+ const struct inode *inode)
+{
+ sector_t sector = bh->b_blocknr << (inode->i_blkbits - 9);
+
+ return sector;
+}
+
static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
loff_t start, loff_t end, get_block_t get_block,
struct buffer_head *bh)
{
- ssize_t retval = 0;
- loff_t pos = start;
- loff_t max = start;
- loff_t bh_max = start;
- void __pmem *addr;
- bool hole = false;
- bool need_wmb = false;
-
- if (iov_iter_rw(iter) != WRITE)
+ loff_t pos = start, max = start, bh_max = start;
+ bool hole = false, need_wmb = false;
+ struct block_device *bdev = NULL;
+ int rw = iov_iter_rw(iter), rc;
+ long map_len = 0;
+ struct blk_dax_ctl dax = {
+ .addr = (void __pmem *) ERR_PTR(-EIO),
+ };
+
+ if (rw == READ)
end = min(end, i_size_read(inode));
while (pos < end) {
@@ -132,13 +156,13 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
if (pos == bh_max) {
bh->b_size = PAGE_ALIGN(end - pos);
bh->b_state = 0;
- retval = get_block(inode, block, bh,
- iov_iter_rw(iter) == WRITE);
- if (retval)
+ rc = get_block(inode, block, bh, rw == WRITE);
+ if (rc)
break;
if (!buffer_size_valid(bh))
bh->b_size = 1 << blkbits;
bh_max = pos - first + bh->b_size;
+ bdev = bh->b_bdev;
} else {
unsigned done = bh->b_size -
(bh_max - (pos - first));
@@ -146,47 +170,53 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
bh->b_size -= done;
}
- hole = iov_iter_rw(iter) != WRITE && !buffer_written(bh);
+ hole = rw == READ && !buffer_written(bh);
if (hole) {
- addr = NULL;
size = bh->b_size - first;
} else {
- retval = dax_get_addr(bh, &addr, blkbits);
- if (retval < 0)
+ dax_unmap_atomic(bdev, &dax);
+ dax.sector = to_sector(bh, inode);
+ dax.size = bh->b_size;
+ map_len = dax_map_atomic(bdev, &dax);
+ if (map_len < 0) {
+ rc = map_len;
break;
+ }
if (buffer_unwritten(bh) || buffer_new(bh)) {
- dax_new_buf(addr, retval, first, pos,
- end);
+ dax_new_buf(dax.addr, map_len, first,
+ pos, end);
need_wmb = true;
}
- addr += first;
- size = retval - first;
+ dax.addr += first;
+ size = map_len - first;
}
max = min(pos + size, end);
}
if (iov_iter_rw(iter) == WRITE) {
- len = copy_from_iter_pmem(addr, max - pos, iter);
+ len = copy_from_iter_pmem(dax.addr, max - pos, iter);
need_wmb = true;
} else if (!hole)
- len = copy_to_iter((void __force *)addr, max - pos,
+ len = copy_to_iter((void __force *) dax.addr, max - pos,
iter);
else
len = iov_iter_zero(max - pos, iter);
if (!len) {
- retval = -EFAULT;
+ rc = -EFAULT;
break;
}
pos += len;
- addr += len;
+ if (!IS_ERR(dax.addr))
+ dax.addr += len;
}
if (need_wmb)
wmb_pmem();
+ dax_unmap_atomic(bdev, &dax);
- return (pos == start) ? retval : pos - start;
+ return (pos == start) ? rc : pos - start;
}
/**
@@ -275,28 +305,35 @@ static int dax_load_hole(struct address_space *mapping, struct page *page,
return VM_FAULT_LOCKED;
}
-static int copy_user_bh(struct page *to, struct buffer_head *bh,
- unsigned blkbits, unsigned long vaddr)
+static int copy_user_bh(struct page *to, struct inode *inode,
+ struct buffer_head *bh, unsigned long vaddr)
{
- void __pmem *vfrom;
+ struct blk_dax_ctl dax = {
+ .sector = to_sector(bh, inode),
+ .size = bh->b_size,
+ };
+ struct block_device *bdev = bh->b_bdev;
void *vto;
- if (dax_get_addr(bh, &vfrom, blkbits) < 0)
- return -EIO;
+ if (dax_map_atomic(bdev, &dax) < 0)
+ return PTR_ERR(dax.addr);
vto = kmap_atomic(to);
- copy_user_page(vto, (void __force *)vfrom, vaddr, to);
+ copy_user_page(vto, (void __force *)dax.addr, vaddr, to);
kunmap_atomic(vto);
+ dax_unmap_atomic(bdev, &dax);
return 0;
}
static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
struct vm_area_struct *vma, struct vm_fault *vmf)
{
- struct address_space *mapping = inode->i_mapping;
- sector_t sector = bh->b_blocknr << (inode->i_blkbits - 9);
unsigned long vaddr = (unsigned long)vmf->virtual_address;
- void __pmem *addr;
- unsigned long pfn;
+ struct address_space *mapping = inode->i_mapping;
+ struct block_device *bdev = bh->b_bdev;
+ struct blk_dax_ctl dax = {
+ .sector = to_sector(bh, inode),
+ .size = bh->b_size,
+ };
pgoff_t size;
int error;
@@ -315,20 +352,18 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
goto out;
}
- error = bdev_direct_access(bh->b_bdev, sector, &addr, &pfn, bh->b_size);
- if (error < 0)
- goto out;
- if (error < PAGE_SIZE) {
- error = -EIO;
+ if (dax_map_atomic(bdev, &dax) < 0) {
+ error = PTR_ERR(dax.addr);
goto out;
}
if (buffer_unwritten(bh) || buffer_new(bh)) {
- clear_pmem(addr, PAGE_SIZE);
+ clear_pmem(dax.addr, PAGE_SIZE);
wmb_pmem();
}
+ dax_unmap_atomic(bdev, &dax);
- error = vm_insert_mixed(vma, vaddr, pfn);
+ error = vm_insert_mixed(vma, vaddr, dax.pfn);
out:
i_mmap_unlock_read(mapping);
@@ -422,7 +457,7 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
if (vmf->cow_page) {
struct page *new_page = vmf->cow_page;
if (buffer_written(&bh))
- error = copy_user_bh(new_page, &bh, blkbits, vaddr);
+ error = copy_user_bh(new_page, inode, &bh, vaddr);
else
clear_user_highpage(new_page, vaddr);
if (error)
@@ -523,6 +558,24 @@ EXPORT_SYMBOL_GPL(dax_fault);
*/
#define PG_PMD_COLOUR ((PMD_SIZE >> PAGE_SHIFT) - 1)
+static void __dax_dbg(struct buffer_head *bh, unsigned long address,
+ const char *reason, const char *fn)
+{
+ if (bh) {
+ char bname[BDEVNAME_SIZE];
+ bdevname(bh->b_bdev, bname);
+ pr_debug("%s: %s addr: %lx dev %s state %lx start %lld "
+ "length %zd fallback: %s\n", fn, current->comm,
+ address, bname, bh->b_state, (u64)bh->b_blocknr,
+ bh->b_size, reason);
+ } else {
+ pr_debug("%s: %s addr: %lx fallback: %s\n", fn,
+ current->comm, address, reason);
+ }
+}
+
+#define dax_pmd_dbg(bh, address, reason) __dax_dbg(bh, address, reason, "dax_pmd")
+
int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmd, unsigned int flags, get_block_t get_block,
dax_iodone_t complete_unwritten)
@@ -534,41 +587,49 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
unsigned blkbits = inode->i_blkbits;
unsigned long pmd_addr = address & PMD_MASK;
bool write = flags & FAULT_FLAG_WRITE;
- long length;
- void __pmem *kaddr;
+ struct block_device *bdev;
pgoff_t size, pgoff;
- sector_t block, sector;
- unsigned long pfn;
+ sector_t block;
int result = 0;
- /* dax pmd mappings are broken wrt gup and fork */
+ /* dax pmd mappings require pfn_t_devmap() */
if (!IS_ENABLED(CONFIG_FS_DAX_PMD))
return VM_FAULT_FALLBACK;
/* Fall back to PTEs if we're going to COW */
- if (write && !(vma->vm_flags & VM_SHARED))
+ if (write && !(vma->vm_flags & VM_SHARED)) {
+ split_huge_pmd(vma, pmd, address);
+ dax_pmd_dbg(NULL, address, "cow write");
return VM_FAULT_FALLBACK;
+ }
/* If the PMD would extend outside the VMA */
- if (pmd_addr < vma->vm_start)
+ if (pmd_addr < vma->vm_start) {
+ dax_pmd_dbg(NULL, address, "vma start unaligned");
return VM_FAULT_FALLBACK;
- if ((pmd_addr + PMD_SIZE) > vma->vm_end)
+ }
+ if ((pmd_addr + PMD_SIZE) > vma->vm_end) {
+ dax_pmd_dbg(NULL, address, "vma end unaligned");
return VM_FAULT_FALLBACK;
+ }
pgoff = linear_page_index(vma, pmd_addr);
size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (pgoff >= size)
return VM_FAULT_SIGBUS;
/* If the PMD would cover blocks out of the file */
- if ((pgoff | PG_PMD_COLOUR) >= size)
+ if ((pgoff | PG_PMD_COLOUR) >= size) {
+ dax_pmd_dbg(NULL, address,
+ "offset + huge page size > file size");
return VM_FAULT_FALLBACK;
+ }
memset(&bh, 0, sizeof(bh));
block = (sector_t)pgoff << (PAGE_SHIFT - blkbits);
bh.b_size = PMD_SIZE;
- length = get_block(inode, block, &bh, write);
- if (length)
+ if (get_block(inode, block, &bh, write) != 0)
return VM_FAULT_SIGBUS;
+ bdev = bh.b_bdev;
i_mmap_lock_read(mapping);
/*
@@ -576,8 +637,10 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
* just fall back to PTEs. Calling get_block 512 times in a loop
* would be silly.
*/
- if (!buffer_size_valid(&bh) || bh.b_size < PMD_SIZE)
+ if (!buffer_size_valid(&bh) || bh.b_size < PMD_SIZE) {
+ dax_pmd_dbg(&bh, address, "allocated block too small");
goto fallback;
+ }
/*
* If we allocated new storage, make sure no process has any
@@ -600,57 +663,82 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
result = VM_FAULT_SIGBUS;
goto out;
}
- if ((pgoff | PG_PMD_COLOUR) >= size)
+ if ((pgoff | PG_PMD_COLOUR) >= size) {
+ dax_pmd_dbg(&bh, address, "pgoff unaligned");
goto fallback;
+ }
if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) {
spinlock_t *ptl;
pmd_t entry;
struct page *zero_page = get_huge_zero_page();
- if (unlikely(!zero_page))
+ if (unlikely(!zero_page)) {
+ dax_pmd_dbg(&bh, address, "no zero page");
goto fallback;
+ }
ptl = pmd_lock(vma->vm_mm, pmd);
if (!pmd_none(*pmd)) {
spin_unlock(ptl);
+ dax_pmd_dbg(&bh, address, "pmd already present");
goto fallback;
}
+ dev_dbg(part_to_dev(bdev->bd_part),
+ "%s: %s addr: %lx pfn: <zero> sect: %llx\n",
+ __func__, current->comm, address,
+ (unsigned long long) to_sector(&bh, inode));
+
entry = mk_pmd(zero_page, vma->vm_page_prot);
entry = pmd_mkhuge(entry);
set_pmd_at(vma->vm_mm, pmd_addr, pmd, entry);
result = VM_FAULT_NOPAGE;
spin_unlock(ptl);
} else {
- sector = bh.b_blocknr << (blkbits - 9);
- length = bdev_direct_access(bh.b_bdev, sector, &kaddr, &pfn,
- bh.b_size);
+ struct blk_dax_ctl dax = {
+ .sector = to_sector(&bh, inode),
+ .size = PMD_SIZE,
+ };
+ long length = dax_map_atomic(bdev, &dax);
+
if (length < 0) {
result = VM_FAULT_SIGBUS;
goto out;
}
- if ((length < PMD_SIZE) || (pfn & PG_PMD_COLOUR))
+ if (length < PMD_SIZE) {
+ dax_pmd_dbg(&bh, address, "dax-length too small");
+ dax_unmap_atomic(bdev, &dax);
goto fallback;
+ }
+ if (pfn_t_to_pfn(dax.pfn) & PG_PMD_COLOUR) {
+ dax_pmd_dbg(&bh, address, "pfn unaligned");
+ dax_unmap_atomic(bdev, &dax);
+ goto fallback;
+ }
- /*
- * TODO: teach vmf_insert_pfn_pmd() to support
- * 'pte_special' for pmds
- */
- if (pfn_valid(pfn))
+ if (!pfn_t_devmap(dax.pfn)) {
+ dax_unmap_atomic(bdev, &dax);
+ dax_pmd_dbg(&bh, address, "pfn not in memmap");
goto fallback;
+ }
if (buffer_unwritten(&bh) || buffer_new(&bh)) {
- int i;
- for (i = 0; i < PTRS_PER_PMD; i++)
- clear_pmem(kaddr + i * PAGE_SIZE, PAGE_SIZE);
+ clear_pmem(dax.addr, PMD_SIZE);
wmb_pmem();
count_vm_event(PGMAJFAULT);
mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
result |= VM_FAULT_MAJOR;
}
-
- result |= vmf_insert_pfn_pmd(vma, address, pmd, pfn, write);
+ dax_unmap_atomic(bdev, &dax);
+
+ dev_dbg(part_to_dev(bdev->bd_part),
+ "%s: %s addr: %lx pfn: %lx sect: %llx\n",
+ __func__, current->comm, address,
+ pfn_t_to_pfn(dax.pfn),
+ (unsigned long long) dax.sector);
+ result |= vmf_insert_pfn_pmd(vma, address, pmd,
+ dax.pfn, write);
}
out:
@@ -752,12 +840,17 @@ int dax_zero_page_range(struct inode *inode, loff_t from, unsigned length,
if (err < 0)
return err;
if (buffer_written(&bh)) {
- void __pmem *addr;
- err = dax_get_addr(&bh, &addr, inode->i_blkbits);
- if (err < 0)
- return err;
- clear_pmem(addr + offset, length);
+ struct block_device *bdev = bh.b_bdev;
+ struct blk_dax_ctl dax = {
+ .sector = to_sector(&bh, inode),
+ .size = PAGE_CACHE_SIZE,
+ };
+
+ if (dax_map_atomic(bdev, &dax) < 0)
+ return PTR_ERR(dax.addr);
+ clear_pmem(dax.addr + offset, length);
wmb_pmem();
+ dax_unmap_atomic(bdev, &dax);
}
return 0;
diff --git a/fs/dcache.c b/fs/dcache.c
index 8d38cd07b207..b4539e84e577 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1571,7 +1571,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
dentry->d_iname[DNAME_INLINE_LEN-1] = 0;
if (name->len > DNAME_INLINE_LEN-1) {
size_t size = offsetof(struct external_name, name[1]);
- struct external_name *p = kmalloc(size + name->len, GFP_KERNEL);
+ struct external_name *p = kmalloc(size + name->len,
+ GFP_KERNEL_ACCOUNT);
if (!p) {
kmem_cache_free(dentry_cache, dentry);
return NULL;
@@ -3415,7 +3416,7 @@ static void __init dcache_init(void)
* of the dcache.
*/
dentry_cache = KMEM_CACHE(dentry,
- SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
+ SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD|SLAB_ACCOUNT);
/* Hash may have been set up in dcache_init_early */
if (!hashdist)
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 4f4d0474bee9..e25b6b06bacf 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -663,6 +663,7 @@ static struct ecryptfs_cache_info {
struct kmem_cache **cache;
const char *name;
size_t size;
+ unsigned long flags;
void (*ctor)(void *obj);
} ecryptfs_cache_infos[] = {
{
@@ -684,6 +685,7 @@ static struct ecryptfs_cache_info {
.cache = &ecryptfs_inode_info_cache,
.name = "ecryptfs_inode_cache",
.size = sizeof(struct ecryptfs_inode_info),
+ .flags = SLAB_ACCOUNT,
.ctor = inode_info_init_once,
},
{
@@ -755,8 +757,8 @@ static int ecryptfs_init_kmem_caches(void)
struct ecryptfs_cache_info *info;
info = &ecryptfs_cache_infos[i];
- *(info->cache) = kmem_cache_create(info->name, info->size,
- 0, SLAB_HWCACHE_ALIGN, info->ctor);
+ *(info->cache) = kmem_cache_create(info->name, info->size, 0,
+ SLAB_HWCACHE_ALIGN | info->flags, info->ctor);
if (!*(info->cache)) {
ecryptfs_free_kmem_caches();
ecryptfs_printk(KERN_WARNING, "%s: "
diff --git a/fs/efs/super.c b/fs/efs/super.c
index c8411a30f7da..cb68dac4f9d3 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -94,9 +94,9 @@ static void init_once(void *foo)
static int __init init_inodecache(void)
{
efs_inode_cachep = kmem_cache_create("efs_inode_cache",
- sizeof(struct efs_inode_info),
- 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once);
+ sizeof(struct efs_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
+ SLAB_ACCOUNT, init_once);
if (efs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 8d0c0df01854..ed70cf9fdc7b 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -45,10 +45,10 @@ struct eventfd_ctx {
*
* This function is supposed to be called by the kernel in paths that do not
* allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
- * value, and we signal this as overflow condition by returining a POLLERR
+ * value, and we signal this as overflow condition by returning a POLLERR
* to poll(2).
*
- * Returns the amount by which the counter was incrememnted. This will be less
+ * Returns the amount by which the counter was incremented. This will be less
* than @n if the counter has overflowed.
*/
__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n)
diff --git a/fs/exofs/super.c b/fs/exofs/super.c
index b795c567b5e1..6658a50530a0 100644
--- a/fs/exofs/super.c
+++ b/fs/exofs/super.c
@@ -194,8 +194,8 @@ static int init_inodecache(void)
{
exofs_inode_cachep = kmem_cache_create("exofs_inode_cache",
sizeof(struct exofs_i_info), 0,
- SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
- exofs_init_once);
+ SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
+ SLAB_ACCOUNT, exofs_init_once);
if (exofs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 748d35afc902..2a188413a2b0 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -203,7 +203,7 @@ static int __init init_inodecache(void)
ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
sizeof(struct ext2_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (ext2_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c9ab67da6e5a..f1b56ff01208 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -966,7 +966,7 @@ static int __init init_inodecache(void)
ext4_inode_cachep = kmem_cache_create("ext4_inode_cache",
sizeof(struct ext4_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (ext4_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index f661d80474be..3842af954cd5 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -237,7 +237,7 @@ static int f2fs_write_meta_page(struct page *page,
dec_page_count(sbi, F2FS_DIRTY_META);
unlock_page(page);
- if (wbc->for_reclaim)
+ if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi)))
f2fs_submit_merged_bio(sbi, META, WRITE);
return 0;
@@ -410,13 +410,13 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
spin_unlock(&im->ino_lock);
}
-void add_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
+void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
/* add new dirty ino entry into list */
__add_ino_entry(sbi, ino, type);
}
-void remove_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
+void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
/* remove dirty ino entry from list */
__remove_ino_entry(sbi, ino, type);
@@ -434,7 +434,7 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
return e ? true : false;
}
-void release_dirty_inode(struct f2fs_sb_info *sbi)
+void release_ino_entry(struct f2fs_sb_info *sbi)
{
struct ino_entry *e, *tmp;
int i;
@@ -722,47 +722,48 @@ fail_no_cp:
return -EINVAL;
}
-static int __add_dirty_inode(struct inode *inode, struct inode_entry *new)
+static void __add_dirty_inode(struct inode *inode, enum inode_type type)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
- if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
- return -EEXIST;
+ if (is_inode_flag_set(fi, flag))
+ return;
- set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
- F2FS_I(inode)->dirty_dir = new;
- list_add_tail(&new->list, &sbi->dir_inode_list);
- stat_inc_dirty_dir(sbi);
- return 0;
+ set_inode_flag(fi, flag);
+ list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
+ stat_inc_dirty_inode(sbi, type);
+}
+
+static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
+
+ if (get_dirty_pages(inode) ||
+ !is_inode_flag_set(F2FS_I(inode), flag))
+ return;
+
+ list_del_init(&fi->dirty_list);
+ clear_inode_flag(fi, flag);
+ stat_dec_dirty_inode(F2FS_I_SB(inode), type);
}
void update_dirty_page(struct inode *inode, struct page *page)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct inode_entry *new;
- int ret = 0;
+ enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
!S_ISLNK(inode->i_mode))
return;
- if (!S_ISDIR(inode->i_mode)) {
- inode_inc_dirty_pages(inode);
- goto out;
- }
-
- new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
- new->inode = inode;
- INIT_LIST_HEAD(&new->list);
-
- spin_lock(&sbi->dir_inode_lock);
- ret = __add_dirty_inode(inode, new);
+ spin_lock(&sbi->inode_lock[type]);
+ __add_dirty_inode(inode, type);
inode_inc_dirty_pages(inode);
- spin_unlock(&sbi->dir_inode_lock);
+ spin_unlock(&sbi->inode_lock[type]);
- if (ret)
- kmem_cache_free(inode_entry_slab, new);
-out:
SetPagePrivate(page);
f2fs_trace_pid(page);
}
@@ -770,70 +771,60 @@ out:
void add_dirty_dir_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct inode_entry *new =
- f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
- int ret = 0;
-
- new->inode = inode;
- INIT_LIST_HEAD(&new->list);
- spin_lock(&sbi->dir_inode_lock);
- ret = __add_dirty_inode(inode, new);
- spin_unlock(&sbi->dir_inode_lock);
-
- if (ret)
- kmem_cache_free(inode_entry_slab, new);
+ spin_lock(&sbi->inode_lock[DIR_INODE]);
+ __add_dirty_inode(inode, DIR_INODE);
+ spin_unlock(&sbi->inode_lock[DIR_INODE]);
}
-void remove_dirty_dir_inode(struct inode *inode)
+void remove_dirty_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct inode_entry *entry;
-
- if (!S_ISDIR(inode->i_mode))
- return;
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
- spin_lock(&sbi->dir_inode_lock);
- if (get_dirty_pages(inode) ||
- !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
- spin_unlock(&sbi->dir_inode_lock);
+ if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
+ !S_ISLNK(inode->i_mode))
return;
- }
- entry = F2FS_I(inode)->dirty_dir;
- list_del(&entry->list);
- F2FS_I(inode)->dirty_dir = NULL;
- clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
- stat_dec_dirty_dir(sbi);
- spin_unlock(&sbi->dir_inode_lock);
- kmem_cache_free(inode_entry_slab, entry);
+ spin_lock(&sbi->inode_lock[type]);
+ __remove_dirty_inode(inode, type);
+ spin_unlock(&sbi->inode_lock[type]);
/* Only from the recovery routine */
- if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
- clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
+ if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
+ clear_inode_flag(fi, FI_DELAY_IPUT);
iput(inode);
}
}
-void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
+int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
{
struct list_head *head;
- struct inode_entry *entry;
struct inode *inode;
+ struct f2fs_inode_info *fi;
+ bool is_dir = (type == DIR_INODE);
+
+ trace_f2fs_sync_dirty_inodes_enter(sbi->sb, is_dir,
+ get_pages(sbi, is_dir ?
+ F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
retry:
if (unlikely(f2fs_cp_error(sbi)))
- return;
+ return -EIO;
- spin_lock(&sbi->dir_inode_lock);
+ spin_lock(&sbi->inode_lock[type]);
- head = &sbi->dir_inode_list;
+ head = &sbi->inode_list[type];
if (list_empty(head)) {
- spin_unlock(&sbi->dir_inode_lock);
- return;
+ spin_unlock(&sbi->inode_lock[type]);
+ trace_f2fs_sync_dirty_inodes_exit(sbi->sb, is_dir,
+ get_pages(sbi, is_dir ?
+ F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
+ return 0;
}
- entry = list_entry(head->next, struct inode_entry, list);
- inode = igrab(entry->inode);
- spin_unlock(&sbi->dir_inode_lock);
+ fi = list_entry(head->next, struct f2fs_inode_info, dirty_list);
+ inode = igrab(&fi->vfs_inode);
+ spin_unlock(&sbi->inode_lock[type]);
if (inode) {
filemap_fdatawrite(inode->i_mapping);
iput(inode);
@@ -868,11 +859,9 @@ retry_flush_dents:
/* write all the dirty dentry pages */
if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
f2fs_unlock_all(sbi);
- sync_dirty_dir_inodes(sbi);
- if (unlikely(f2fs_cp_error(sbi))) {
- err = -EIO;
+ err = sync_dirty_inodes(sbi, DIR_INODE);
+ if (err)
goto out;
- }
goto retry_flush_dents;
}
@@ -885,10 +874,9 @@ retry_flush_nodes:
if (get_pages(sbi, F2FS_DIRTY_NODES)) {
up_write(&sbi->node_write);
- sync_node_pages(sbi, 0, &wbc);
- if (unlikely(f2fs_cp_error(sbi))) {
+ err = sync_node_pages(sbi, 0, &wbc);
+ if (err) {
f2fs_unlock_all(sbi);
- err = -EIO;
goto out;
}
goto retry_flush_nodes;
@@ -919,7 +907,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
finish_wait(&sbi->cp_wait, &wait);
}
-static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
@@ -945,7 +933,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
while (get_pages(sbi, F2FS_DIRTY_META)) {
sync_meta_pages(sbi, META, LONG_MAX);
if (unlikely(f2fs_cp_error(sbi)))
- return;
+ return -EIO;
}
next_free_nid(sbi, &last_nid);
@@ -1030,7 +1018,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* need to wait for end_io results */
wait_on_all_pages_writeback(sbi);
if (unlikely(f2fs_cp_error(sbi)))
- return;
+ return -EIO;
/* write out checkpoint buffer at block 0 */
update_meta_page(sbi, ckpt, start_blk++);
@@ -1058,7 +1046,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
wait_on_all_pages_writeback(sbi);
if (unlikely(f2fs_cp_error(sbi)))
- return;
+ return -EIO;
filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX);
filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX);
@@ -1081,22 +1069,25 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
invalidate_mapping_pages(META_MAPPING(sbi), discard_blk,
discard_blk);
- release_dirty_inode(sbi);
+ release_ino_entry(sbi);
if (unlikely(f2fs_cp_error(sbi)))
- return;
+ return -EIO;
clear_prefree_segments(sbi, cpc);
clear_sbi_flag(sbi, SBI_IS_DIRTY);
+
+ return 0;
}
/*
* We guarantee that this checkpoint procedure will not fail.
*/
-void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
unsigned long long ckpt_ver;
+ int err = 0;
mutex_lock(&sbi->cp_mutex);
@@ -1104,14 +1095,19 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
(cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC ||
(cpc->reason == CP_DISCARD && !sbi->discard_blks)))
goto out;
- if (unlikely(f2fs_cp_error(sbi)))
+ if (unlikely(f2fs_cp_error(sbi))) {
+ err = -EIO;
goto out;
- if (f2fs_readonly(sbi->sb))
+ }
+ if (f2fs_readonly(sbi->sb)) {
+ err = -EROFS;
goto out;
+ }
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops");
- if (block_operations(sbi))
+ err = block_operations(sbi);
+ if (err)
goto out;
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops");
@@ -1133,7 +1129,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
flush_sit_entries(sbi, cpc);
/* unlock all the fs_lock[] in do_checkpoint() */
- do_checkpoint(sbi, cpc);
+ err = do_checkpoint(sbi, cpc);
unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info);
@@ -1143,10 +1139,11 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
"checkpoint: version = %llx", ckpt_ver);
/* do checkpoint periodically */
- sbi->cp_expires = round_jiffies_up(jiffies + HZ * sbi->cp_interval);
+ f2fs_update_time(sbi, CP_TIME);
+ trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
out:
mutex_unlock(&sbi->cp_mutex);
- trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
+ return err;
}
void init_ino_entry_info(struct f2fs_sb_info *sbi)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 972eab7ac071..ac9e7c6aac74 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -225,7 +225,8 @@ void set_data_blkaddr(struct dnode_of_data *dn)
/* Get physical address of data block */
addr_array = blkaddr_in_node(rn);
addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr);
- set_page_dirty(node_page);
+ if (set_page_dirty(node_page))
+ dn->node_changed = true;
}
int reserve_new_block(struct dnode_of_data *dn)
@@ -412,7 +413,7 @@ struct page *get_new_data_page(struct inode *inode,
struct page *page;
struct dnode_of_data dn;
int err;
-repeat:
+
page = f2fs_grab_cache_page(mapping, index, true);
if (!page) {
/*
@@ -441,12 +442,11 @@ repeat:
} else {
f2fs_put_page(page, 1);
- page = get_read_data_page(inode, index, READ_SYNC, true);
+ /* if ipage exists, blkaddr should be NEW_ADDR */
+ f2fs_bug_on(F2FS_I_SB(inode), ipage);
+ page = get_lock_data_page(inode, index, true);
if (IS_ERR(page))
- goto repeat;
-
- /* wait for read completion */
- lock_page(page);
+ return page;
}
got_it:
if (new_i_size && i_size_read(inode) <
@@ -494,14 +494,10 @@ alloc:
if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT))
i_size_write(dn->inode,
((loff_t)(fofs + 1) << PAGE_CACHE_SHIFT));
-
- /* direct IO doesn't use extent cache to maximize the performance */
- f2fs_drop_largest_extent(dn->inode, fofs);
-
return 0;
}
-static void __allocate_data_blocks(struct inode *inode, loff_t offset,
+static int __allocate_data_blocks(struct inode *inode, loff_t offset,
size_t count)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -510,14 +506,15 @@ static void __allocate_data_blocks(struct inode *inode, loff_t offset,
u64 len = F2FS_BYTES_TO_BLK(count);
bool allocated;
u64 end_offset;
+ int err = 0;
while (len) {
- f2fs_balance_fs(sbi);
f2fs_lock_op(sbi);
/* When reading holes, we need its node page */
set_new_dnode(&dn, inode, NULL, NULL, 0);
- if (get_dnode_of_data(&dn, start, ALLOC_NODE))
+ err = get_dnode_of_data(&dn, start, ALLOC_NODE);
+ if (err)
goto out;
allocated = false;
@@ -526,12 +523,15 @@ static void __allocate_data_blocks(struct inode *inode, loff_t offset,
while (dn.ofs_in_node < end_offset && len) {
block_t blkaddr;
- if (unlikely(f2fs_cp_error(sbi)))
+ if (unlikely(f2fs_cp_error(sbi))) {
+ err = -EIO;
goto sync_out;
+ }
blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
- if (__allocate_data_block(&dn))
+ err = __allocate_data_block(&dn);
+ if (err)
goto sync_out;
allocated = true;
}
@@ -545,8 +545,10 @@ static void __allocate_data_blocks(struct inode *inode, loff_t offset,
f2fs_put_dnode(&dn);
f2fs_unlock_op(sbi);
+
+ f2fs_balance_fs(sbi, dn.node_changed);
}
- return;
+ return err;
sync_out:
if (allocated)
@@ -554,7 +556,8 @@ sync_out:
f2fs_put_dnode(&dn);
out:
f2fs_unlock_op(sbi);
- return;
+ f2fs_balance_fs(sbi, dn.node_changed);
+ return err;
}
/*
@@ -566,7 +569,7 @@ out:
* b. do not use extent cache for better performance
* c. give the block addresses to blockdev
*/
-static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
+int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
int create, int flag)
{
unsigned int maxblocks = map->m_len;
@@ -577,6 +580,7 @@ static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
int err = 0, ofs = 1;
struct extent_info ei;
bool allocated = false;
+ block_t blkaddr;
map->m_len = 0;
map->m_flags = 0;
@@ -592,7 +596,7 @@ static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
}
if (create)
- f2fs_lock_op(F2FS_I_SB(inode));
+ f2fs_lock_op(sbi);
/* When reading holes, we need its node page */
set_new_dnode(&dn, inode, NULL, NULL, 0);
@@ -640,12 +644,21 @@ static int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
pgofs++;
get_next:
+ if (map->m_len >= maxblocks)
+ goto sync_out;
+
if (dn.ofs_in_node >= end_offset) {
if (allocated)
sync_inode_page(&dn);
allocated = false;
f2fs_put_dnode(&dn);
+ if (create) {
+ f2fs_unlock_op(sbi);
+ f2fs_balance_fs(sbi, dn.node_changed);
+ f2fs_lock_op(sbi);
+ }
+
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, pgofs, mode);
if (err) {
@@ -657,52 +670,53 @@ get_next:
end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
}
- if (maxblocks > map->m_len) {
- block_t blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+ blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
- if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
- if (create) {
- if (unlikely(f2fs_cp_error(sbi))) {
- err = -EIO;
- goto sync_out;
- }
- err = __allocate_data_block(&dn);
- if (err)
- goto sync_out;
- allocated = true;
- map->m_flags |= F2FS_MAP_NEW;
- blkaddr = dn.data_blkaddr;
- } else {
- /*
- * we only merge preallocated unwritten blocks
- * for fiemap.
- */
- if (flag != F2FS_GET_BLOCK_FIEMAP ||
- blkaddr != NEW_ADDR)
- goto sync_out;
+ if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
+ if (create) {
+ if (unlikely(f2fs_cp_error(sbi))) {
+ err = -EIO;
+ goto sync_out;
}
+ err = __allocate_data_block(&dn);
+ if (err)
+ goto sync_out;
+ allocated = true;
+ map->m_flags |= F2FS_MAP_NEW;
+ blkaddr = dn.data_blkaddr;
+ } else {
+ /*
+ * we only merge preallocated unwritten blocks
+ * for fiemap.
+ */
+ if (flag != F2FS_GET_BLOCK_FIEMAP ||
+ blkaddr != NEW_ADDR)
+ goto sync_out;
}
+ }
- /* Give more consecutive addresses for the readahead */
- if ((map->m_pblk != NEW_ADDR &&
- blkaddr == (map->m_pblk + ofs)) ||
- (map->m_pblk == NEW_ADDR &&
- blkaddr == NEW_ADDR)) {
- ofs++;
- dn.ofs_in_node++;
- pgofs++;
- map->m_len++;
- goto get_next;
- }
+ /* Give more consecutive addresses for the readahead */
+ if ((map->m_pblk != NEW_ADDR &&
+ blkaddr == (map->m_pblk + ofs)) ||
+ (map->m_pblk == NEW_ADDR &&
+ blkaddr == NEW_ADDR)) {
+ ofs++;
+ dn.ofs_in_node++;
+ pgofs++;
+ map->m_len++;
+ goto get_next;
}
+
sync_out:
if (allocated)
sync_inode_page(&dn);
put_out:
f2fs_put_dnode(&dn);
unlock_out:
- if (create)
- f2fs_unlock_op(F2FS_I_SB(inode));
+ if (create) {
+ f2fs_unlock_op(sbi);
+ f2fs_balance_fs(sbi, dn.node_changed);
+ }
out:
trace_f2fs_map_blocks(inode, map, err);
return err;
@@ -742,6 +756,10 @@ static int get_data_block_dio(struct inode *inode, sector_t iblock,
static int get_data_block_bmap(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
+ /* Block number less than F2FS MAX BLOCKS */
+ if (unlikely(iblock >= F2FS_I_SB(inode)->max_file_blocks))
+ return -EFBIG;
+
return __get_data_block(inode, iblock, bh_result, create,
F2FS_GET_BLOCK_BMAP);
}
@@ -761,10 +779,9 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
{
struct buffer_head map_bh;
sector_t start_blk, last_blk;
- loff_t isize = i_size_read(inode);
+ loff_t isize;
u64 logical = 0, phys = 0, size = 0;
u32 flags = 0;
- bool past_eof = false, whole_file = false;
int ret = 0;
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
@@ -779,16 +796,19 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
mutex_lock(&inode->i_mutex);
- if (len >= isize) {
- whole_file = true;
- len = isize;
- }
+ isize = i_size_read(inode);
+ if (start >= isize)
+ goto out;
+
+ if (start + len > isize)
+ len = isize - start;
if (logical_to_blk(inode, len) == 0)
len = blk_to_logical(inode, 1);
start_blk = logical_to_blk(inode, start);
last_blk = logical_to_blk(inode, start + len - 1);
+
next:
memset(&map_bh, 0, sizeof(struct buffer_head));
map_bh.b_size = len;
@@ -800,59 +820,37 @@ next:
/* HOLE */
if (!buffer_mapped(&map_bh)) {
- start_blk++;
-
- if (!past_eof && blk_to_logical(inode, start_blk) >= isize)
- past_eof = 1;
-
- if (past_eof && size) {
- flags |= FIEMAP_EXTENT_LAST;
- ret = fiemap_fill_next_extent(fieinfo, logical,
- phys, size, flags);
- } else if (size) {
- ret = fiemap_fill_next_extent(fieinfo, logical,
- phys, size, flags);
- size = 0;
- }
+ /* Go through holes util pass the EOF */
+ if (blk_to_logical(inode, start_blk++) < isize)
+ goto prep_next;
+ /* Found a hole beyond isize means no more extents.
+ * Note that the premise is that filesystems don't
+ * punch holes beyond isize and keep size unchanged.
+ */
+ flags |= FIEMAP_EXTENT_LAST;
+ }
- /* if we have holes up to/past EOF then we're done */
- if (start_blk > last_blk || past_eof || ret)
- goto out;
- } else {
- if (start_blk > last_blk && !whole_file) {
- ret = fiemap_fill_next_extent(fieinfo, logical,
- phys, size, flags);
- goto out;
- }
+ if (size) {
+ if (f2fs_encrypted_inode(inode))
+ flags |= FIEMAP_EXTENT_DATA_ENCRYPTED;
- /*
- * if size != 0 then we know we already have an extent
- * to add, so add it.
- */
- if (size) {
- ret = fiemap_fill_next_extent(fieinfo, logical,
- phys, size, flags);
- if (ret)
- goto out;
- }
+ ret = fiemap_fill_next_extent(fieinfo, logical,
+ phys, size, flags);
+ }
- logical = blk_to_logical(inode, start_blk);
- phys = blk_to_logical(inode, map_bh.b_blocknr);
- size = map_bh.b_size;
- flags = 0;
- if (buffer_unwritten(&map_bh))
- flags = FIEMAP_EXTENT_UNWRITTEN;
+ if (start_blk > last_blk || ret)
+ goto out;
- start_blk += logical_to_blk(inode, size);
+ logical = blk_to_logical(inode, start_blk);
+ phys = blk_to_logical(inode, map_bh.b_blocknr);
+ size = map_bh.b_size;
+ flags = 0;
+ if (buffer_unwritten(&map_bh))
+ flags = FIEMAP_EXTENT_UNWRITTEN;
- /*
- * If we are past the EOF, then we need to make sure as
- * soon as we find a hole that the last extent we found
- * is marked with FIEMAP_EXTENT_LAST
- */
- if (!past_eof && logical + size >= isize)
- past_eof = true;
- }
+ start_blk += logical_to_blk(inode, size);
+
+prep_next:
cond_resched();
if (fatal_signal_pending(current))
ret = -EINTR;
@@ -1083,6 +1081,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
*/
if (unlikely(fio->blk_addr != NEW_ADDR &&
!is_cold_data(page) &&
+ !IS_ATOMIC_WRITTEN_PAGE(page) &&
need_inplace_update(inode))) {
rewrite_data_page(fio);
set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE);
@@ -1179,10 +1178,11 @@ out:
if (err)
ClearPageUptodate(page);
unlock_page(page);
- if (need_balance_fs)
- f2fs_balance_fs(sbi);
- if (wbc->for_reclaim)
+ f2fs_balance_fs(sbi, need_balance_fs);
+ if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi))) {
f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ remove_dirty_inode(inode);
+ }
return 0;
redirty_out:
@@ -1354,6 +1354,10 @@ static int f2fs_write_data_pages(struct address_space *mapping,
available_free_memory(sbi, DIRTY_DENTS))
goto skip_write;
+ /* skip writing during file defragment */
+ if (is_inode_flag_set(F2FS_I(inode), FI_DO_DEFRAG))
+ goto skip_write;
+
/* during POR, we don't need to trigger writepage at all. */
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
goto skip_write;
@@ -1369,7 +1373,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
if (locked)
mutex_unlock(&sbi->writepages);
- remove_dirty_dir_inode(inode);
+ remove_dirty_inode(inode);
wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
return ret;
@@ -1382,13 +1386,85 @@ skip_write:
static void f2fs_write_failed(struct address_space *mapping, loff_t to)
{
struct inode *inode = mapping->host;
+ loff_t i_size = i_size_read(inode);
- if (to > inode->i_size) {
- truncate_pagecache(inode, inode->i_size);
- truncate_blocks(inode, inode->i_size, true);
+ if (to > i_size) {
+ truncate_pagecache(inode, i_size);
+ truncate_blocks(inode, i_size, true);
}
}
+static int prepare_write_begin(struct f2fs_sb_info *sbi,
+ struct page *page, loff_t pos, unsigned len,
+ block_t *blk_addr, bool *node_changed)
+{
+ struct inode *inode = page->mapping->host;
+ pgoff_t index = page->index;
+ struct dnode_of_data dn;
+ struct page *ipage;
+ bool locked = false;
+ struct extent_info ei;
+ int err = 0;
+
+ if (f2fs_has_inline_data(inode) ||
+ (pos & PAGE_CACHE_MASK) >= i_size_read(inode)) {
+ f2fs_lock_op(sbi);
+ locked = true;
+ }
+restart:
+ /* check inline_data */
+ ipage = get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(ipage)) {
+ err = PTR_ERR(ipage);
+ goto unlock_out;
+ }
+
+ set_new_dnode(&dn, inode, ipage, ipage, 0);
+
+ if (f2fs_has_inline_data(inode)) {
+ if (pos + len <= MAX_INLINE_DATA) {
+ read_inline_data(page, ipage);
+ set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
+ sync_inode_page(&dn);
+ } else {
+ err = f2fs_convert_inline_page(&dn, page);
+ if (err)
+ goto out;
+ if (dn.data_blkaddr == NULL_ADDR)
+ err = f2fs_get_block(&dn, index);
+ }
+ } else if (locked) {
+ err = f2fs_get_block(&dn, index);
+ } else {
+ if (f2fs_lookup_extent_cache(inode, index, &ei)) {
+ dn.data_blkaddr = ei.blk + index - ei.fofs;
+ } else {
+ bool restart = false;
+
+ /* hole case */
+ err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
+ if (err || (!err && dn.data_blkaddr == NULL_ADDR))
+ restart = true;
+ if (restart) {
+ f2fs_put_dnode(&dn);
+ f2fs_lock_op(sbi);
+ locked = true;
+ goto restart;
+ }
+ }
+ }
+
+ /* convert_inline_page can make node_changed */
+ *blk_addr = dn.data_blkaddr;
+ *node_changed = dn.node_changed;
+out:
+ f2fs_put_dnode(&dn);
+unlock_out:
+ if (locked)
+ f2fs_unlock_op(sbi);
+ return err;
+}
+
static int f2fs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
@@ -1396,15 +1472,13 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
struct inode *inode = mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *page = NULL;
- struct page *ipage;
pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
- struct dnode_of_data dn;
+ bool need_balance = false;
+ block_t blkaddr = NULL_ADDR;
int err = 0;
trace_f2fs_write_begin(inode, pos, len, flags);
- f2fs_balance_fs(sbi);
-
/*
* We should check this at this moment to avoid deadlock on inode page
* and #0 page. The locking rule for inline_data conversion should be:
@@ -1424,41 +1498,27 @@ repeat:
*pagep = page;
- f2fs_lock_op(sbi);
-
- /* check inline_data */
- ipage = get_node_page(sbi, inode->i_ino);
- if (IS_ERR(ipage)) {
- err = PTR_ERR(ipage);
- goto unlock_fail;
- }
-
- set_new_dnode(&dn, inode, ipage, ipage, 0);
+ err = prepare_write_begin(sbi, page, pos, len,
+ &blkaddr, &need_balance);
+ if (err)
+ goto fail;
- if (f2fs_has_inline_data(inode)) {
- if (pos + len <= MAX_INLINE_DATA) {
- read_inline_data(page, ipage);
- set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
- sync_inode_page(&dn);
- goto put_next;
+ if (need_balance && has_not_enough_free_secs(sbi, 0)) {
+ unlock_page(page);
+ f2fs_balance_fs(sbi, true);
+ lock_page(page);
+ if (page->mapping != mapping) {
+ /* The page got truncated from under us */
+ f2fs_put_page(page, 1);
+ goto repeat;
}
- err = f2fs_convert_inline_page(&dn, page);
- if (err)
- goto put_fail;
}
- err = f2fs_get_block(&dn, index);
- if (err)
- goto put_fail;
-put_next:
- f2fs_put_dnode(&dn);
- f2fs_unlock_op(sbi);
-
f2fs_wait_on_page_writeback(page, DATA);
/* wait for GCed encrypted page writeback */
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr);
+ f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
if (len == PAGE_CACHE_SIZE)
goto out_update;
@@ -1474,14 +1534,14 @@ put_next:
goto out_update;
}
- if (dn.data_blkaddr == NEW_ADDR) {
+ if (blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
} else {
struct f2fs_io_info fio = {
.sbi = sbi,
.type = DATA,
.rw = READ_SYNC,
- .blk_addr = dn.data_blkaddr,
+ .blk_addr = blkaddr,
.page = page,
.encrypted_page = NULL,
};
@@ -1512,10 +1572,6 @@ out_clear:
clear_cold_data(page);
return 0;
-put_fail:
- f2fs_put_dnode(&dn);
-unlock_fail:
- f2fs_unlock_op(sbi);
fail:
f2fs_put_page(page, 1);
f2fs_write_failed(mapping, pos + len);
@@ -1540,6 +1596,7 @@ static int f2fs_write_end(struct file *file,
}
f2fs_put_page(page, 1);
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return copied;
}
@@ -1567,11 +1624,9 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
int err;
/* we don't need to use inline_data strictly */
- if (f2fs_has_inline_data(inode)) {
- err = f2fs_convert_inline_inode(inode);
- if (err)
- return err;
- }
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
return 0;
@@ -1583,11 +1638,9 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
if (iov_iter_rw(iter) == WRITE) {
- __allocate_data_blocks(inode, offset, count);
- if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
- err = -EIO;
+ err = __allocate_data_blocks(inode, offset, count);
+ if (err)
goto out;
- }
}
err = blockdev_direct_IO(iocb, inode, iter, offset, get_data_block_dio);
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index ad1b18a7705b..4fb6ef88a34f 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -38,12 +38,15 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree);
si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree;
si->total_ext = atomic64_read(&sbi->total_hit_ext);
- si->ext_tree = sbi->total_ext_tree;
+ si->ext_tree = atomic_read(&sbi->total_ext_tree);
+ si->zombie_tree = atomic_read(&sbi->total_zombie_tree);
si->ext_node = atomic_read(&sbi->total_ext_node);
si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
- si->ndirty_dirs = sbi->n_dirty_dirs;
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
+ si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
+ si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
+ si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
si->wb_pages = get_pages(sbi, F2FS_WRITEBACK);
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
@@ -105,7 +108,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
bimodal = 0;
total_vblocks = 0;
- blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg);
+ blks_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg;
hblks_per_sec = blks_per_sec / 2;
for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
@@ -189,10 +192,10 @@ get_cache:
si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
sizeof(struct nat_entry_set);
si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
- si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry);
for (i = 0; i <= UPDATE_INO; i++)
si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
- si->cache_mem += sbi->total_ext_tree * sizeof(struct extent_tree);
+ si->cache_mem += atomic_read(&sbi->total_ext_tree) *
+ sizeof(struct extent_tree);
si->cache_mem += atomic_read(&sbi->total_ext_node) *
sizeof(struct extent_node);
@@ -267,7 +270,8 @@ static int stat_show(struct seq_file *s, void *v)
si->dirty_count);
seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n",
si->prefree_count, si->free_segs, si->free_secs);
- seq_printf(s, "CP calls: %d\n", si->cp_count);
+ seq_printf(s, "CP calls: %d (BG: %d)\n",
+ si->cp_count, si->bg_cp_count);
seq_printf(s, "GC calls: %d (BG: %d)\n",
si->call_count, si->bg_gc);
seq_printf(s, " - data segments : %d (%d)\n",
@@ -288,8 +292,8 @@ static int stat_show(struct seq_file *s, void *v)
!si->total_ext ? 0 :
div64_u64(si->hit_total * 100, si->total_ext),
si->hit_total, si->total_ext);
- seq_printf(s, " - Inner Struct Count: tree: %d, node: %d\n",
- si->ext_tree, si->ext_node);
+ seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
+ si->ext_tree, si->zombie_tree, si->ext_node);
seq_puts(s, "\nBalancing F2FS Async:\n");
seq_printf(s, " - inmem: %4d, wb: %4d\n",
si->inmem_pages, si->wb_pages);
@@ -297,6 +301,8 @@ static int stat_show(struct seq_file *s, void *v)
si->ndirty_node, si->node_pages);
seq_printf(s, " - dents: %4d in dirs:%4d\n",
si->ndirty_dent, si->ndirty_dirs);
+ seq_printf(s, " - datas: %4d in files:%4d\n",
+ si->ndirty_data, si->ndirty_files);
seq_printf(s, " - meta: %4d in %4d\n",
si->ndirty_meta, si->meta_pages);
seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
@@ -404,20 +410,23 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
kfree(si);
}
-void __init f2fs_create_root_stats(void)
+int __init f2fs_create_root_stats(void)
{
struct dentry *file;
f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);
if (!f2fs_debugfs_root)
- return;
+ return -ENOMEM;
file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root,
NULL, &stat_fops);
if (!file) {
debugfs_remove(f2fs_debugfs_root);
f2fs_debugfs_root = NULL;
+ return -ENOMEM;
}
+
+ return 0;
}
void f2fs_destroy_root_stats(void)
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 7c1678ba8f92..faa7495e2d7e 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -172,8 +172,6 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
namehash = f2fs_dentry_hash(&name);
- f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);
-
nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);
nblock = bucket_blocks(level);
@@ -238,6 +236,14 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
goto out;
max_depth = F2FS_I(dir)->i_current_depth;
+ if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) {
+ f2fs_msg(F2FS_I_SB(dir)->sb, KERN_WARNING,
+ "Corrupted max_depth of %lu: %u",
+ dir->i_ino, max_depth);
+ max_depth = MAX_DIR_HASH_DEPTH;
+ F2FS_I(dir)->i_current_depth = max_depth;
+ mark_inode_dirty(dir);
+ }
for (level = 0; level < max_depth; level++) {
de = find_in_level(dir, level, &fname, res_page);
@@ -444,7 +450,7 @@ error:
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */
truncate_inode_pages(&inode->i_data, 0);
truncate_blocks(inode, 0, false);
- remove_dirty_dir_inode(inode);
+ remove_dirty_inode(inode);
remove_inode_page(inode);
return ERR_PTR(err);
}
@@ -630,6 +636,7 @@ fail:
f2fs_put_page(dentry_page, 1);
out:
f2fs_fname_free_filename(&fname);
+ f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
return err;
}
@@ -651,6 +658,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
fail:
up_write(&F2FS_I(inode)->i_sem);
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return err;
}
@@ -695,6 +703,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
int i;
+ f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
+
if (f2fs_has_inline_dentry(dir))
return f2fs_delete_inline_entry(dentry, page, dir, inode);
@@ -855,25 +865,27 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
for (; n < npages; n++) {
dentry_page = get_lock_data_page(inode, n, false);
- if (IS_ERR(dentry_page))
- continue;
+ if (IS_ERR(dentry_page)) {
+ err = PTR_ERR(dentry_page);
+ if (err == -ENOENT)
+ continue;
+ else
+ goto out;
+ }
dentry_blk = kmap(dentry_page);
make_dentry_ptr(inode, &d, (void *)dentry_blk, 1);
- if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr))
- goto stop;
+ if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr)) {
+ kunmap(dentry_page);
+ f2fs_put_page(dentry_page, 1);
+ break;
+ }
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
- dentry_page = NULL;
- }
-stop:
- if (dentry_page && !IS_ERR(dentry_page)) {
- kunmap(dentry_page);
- f2fs_put_page(dentry_page, 1);
}
out:
f2fs_fname_crypto_free_buffer(&fstr);
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index 7ddba812e11b..ccd5c636d3fe 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -36,7 +36,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
rb_link_node(&en->rb_node, parent, p);
rb_insert_color(&en->rb_node, &et->root);
- et->count++;
+ atomic_inc(&et->node_cnt);
atomic_inc(&sbi->total_ext_node);
return en;
}
@@ -45,7 +45,7 @@ static void __detach_extent_node(struct f2fs_sb_info *sbi,
struct extent_tree *et, struct extent_node *en)
{
rb_erase(&en->rb_node, &et->root);
- et->count--;
+ atomic_dec(&et->node_cnt);
atomic_dec(&sbi->total_ext_node);
if (et->cached_en == en)
@@ -68,11 +68,13 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode)
et->root = RB_ROOT;
et->cached_en = NULL;
rwlock_init(&et->lock);
- atomic_set(&et->refcount, 0);
- et->count = 0;
- sbi->total_ext_tree++;
+ INIT_LIST_HEAD(&et->list);
+ atomic_set(&et->node_cnt, 0);
+ atomic_inc(&sbi->total_ext_tree);
+ } else {
+ atomic_dec(&sbi->total_zombie_tree);
+ list_del_init(&et->list);
}
- atomic_inc(&et->refcount);
up_write(&sbi->extent_tree_lock);
/* never died until evict_inode */
@@ -131,7 +133,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
{
struct rb_node *node, *next;
struct extent_node *en;
- unsigned int count = et->count;
+ unsigned int count = atomic_read(&et->node_cnt);
node = rb_first(&et->root);
while (node) {
@@ -152,7 +154,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
node = next;
}
- return count - et->count;
+ return count - atomic_read(&et->node_cnt);
}
static void __drop_largest_extent(struct inode *inode,
@@ -164,34 +166,33 @@ static void __drop_largest_extent(struct inode *inode,
largest->len = 0;
}
-void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs)
-{
- if (!f2fs_may_extent_tree(inode))
- return;
-
- __drop_largest_extent(inode, fofs, 1);
-}
-
-void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
+/* return true, if inode page is changed */
+bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct extent_tree *et;
struct extent_node *en;
struct extent_info ei;
- if (!f2fs_may_extent_tree(inode))
- return;
+ if (!f2fs_may_extent_tree(inode)) {
+ /* drop largest extent */
+ if (i_ext && i_ext->len) {
+ i_ext->len = 0;
+ return true;
+ }
+ return false;
+ }
et = __grab_extent_tree(inode);
- if (!i_ext || le32_to_cpu(i_ext->len) < F2FS_MIN_EXTENT_LEN)
- return;
+ if (!i_ext || !i_ext->len)
+ return false;
set_extent_info(&ei, le32_to_cpu(i_ext->fofs),
le32_to_cpu(i_ext->blk), le32_to_cpu(i_ext->len));
write_lock(&et->lock);
- if (et->count)
+ if (atomic_read(&et->node_cnt))
goto out;
en = __init_extent_tree(sbi, et, &ei);
@@ -202,6 +203,7 @@ void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
}
out:
write_unlock(&et->lock);
+ return false;
}
static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
@@ -549,45 +551,44 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
{
struct extent_tree *treevec[EXT_TREE_VEC_SIZE];
+ struct extent_tree *et, *next;
struct extent_node *en, *tmp;
unsigned long ino = F2FS_ROOT_INO(sbi);
- struct radix_tree_root *root = &sbi->extent_tree_root;
unsigned int found;
unsigned int node_cnt = 0, tree_cnt = 0;
int remained;
+ bool do_free = false;
if (!test_opt(sbi, EXTENT_CACHE))
return 0;
+ if (!atomic_read(&sbi->total_zombie_tree))
+ goto free_node;
+
if (!down_write_trylock(&sbi->extent_tree_lock))
goto out;
/* 1. remove unreferenced extent tree */
- while ((found = radix_tree_gang_lookup(root,
- (void **)treevec, ino, EXT_TREE_VEC_SIZE))) {
- unsigned i;
-
- ino = treevec[found - 1]->ino + 1;
- for (i = 0; i < found; i++) {
- struct extent_tree *et = treevec[i];
-
- if (!atomic_read(&et->refcount)) {
- write_lock(&et->lock);
- node_cnt += __free_extent_tree(sbi, et, true);
- write_unlock(&et->lock);
+ list_for_each_entry_safe(et, next, &sbi->zombie_list, list) {
+ if (atomic_read(&et->node_cnt)) {
+ write_lock(&et->lock);
+ node_cnt += __free_extent_tree(sbi, et, true);
+ write_unlock(&et->lock);
+ }
- radix_tree_delete(root, et->ino);
- kmem_cache_free(extent_tree_slab, et);
- sbi->total_ext_tree--;
- tree_cnt++;
+ list_del_init(&et->list);
+ radix_tree_delete(&sbi->extent_tree_root, et->ino);
+ kmem_cache_free(extent_tree_slab, et);
+ atomic_dec(&sbi->total_ext_tree);
+ atomic_dec(&sbi->total_zombie_tree);
+ tree_cnt++;
- if (node_cnt + tree_cnt >= nr_shrink)
- goto unlock_out;
- }
- }
+ if (node_cnt + tree_cnt >= nr_shrink)
+ goto unlock_out;
}
up_write(&sbi->extent_tree_lock);
+free_node:
/* 2. remove LRU extent entries */
if (!down_write_trylock(&sbi->extent_tree_lock))
goto out;
@@ -599,15 +600,19 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
if (!remained--)
break;
list_del_init(&en->list);
+ do_free = true;
}
spin_unlock(&sbi->extent_lock);
+ if (do_free == false)
+ goto unlock_out;
+
/*
* reset ino for searching victims from beginning of global extent tree.
*/
ino = F2FS_ROOT_INO(sbi);
- while ((found = radix_tree_gang_lookup(root,
+ while ((found = radix_tree_gang_lookup(&sbi->extent_tree_root,
(void **)treevec, ino, EXT_TREE_VEC_SIZE))) {
unsigned i;
@@ -615,9 +620,13 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
for (i = 0; i < found; i++) {
struct extent_tree *et = treevec[i];
- write_lock(&et->lock);
- node_cnt += __free_extent_tree(sbi, et, false);
- write_unlock(&et->lock);
+ if (!atomic_read(&et->node_cnt))
+ continue;
+
+ if (write_trylock(&et->lock)) {
+ node_cnt += __free_extent_tree(sbi, et, false);
+ write_unlock(&et->lock);
+ }
if (node_cnt + tree_cnt >= nr_shrink)
goto unlock_out;
@@ -637,7 +646,7 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode)
struct extent_tree *et = F2FS_I(inode)->extent_tree;
unsigned int node_cnt = 0;
- if (!et)
+ if (!et || !atomic_read(&et->node_cnt))
return 0;
write_lock(&et->lock);
@@ -656,8 +665,12 @@ void f2fs_destroy_extent_tree(struct inode *inode)
if (!et)
return;
- if (inode->i_nlink && !is_bad_inode(inode) && et->count) {
- atomic_dec(&et->refcount);
+ if (inode->i_nlink && !is_bad_inode(inode) &&
+ atomic_read(&et->node_cnt)) {
+ down_write(&sbi->extent_tree_lock);
+ list_add_tail(&et->list, &sbi->zombie_list);
+ atomic_inc(&sbi->total_zombie_tree);
+ up_write(&sbi->extent_tree_lock);
return;
}
@@ -666,11 +679,10 @@ void f2fs_destroy_extent_tree(struct inode *inode)
/* delete extent tree entry in radix tree */
down_write(&sbi->extent_tree_lock);
- atomic_dec(&et->refcount);
- f2fs_bug_on(sbi, atomic_read(&et->refcount) || et->count);
+ f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
radix_tree_delete(&sbi->extent_tree_root, inode->i_ino);
kmem_cache_free(extent_tree_slab, et);
- sbi->total_ext_tree--;
+ atomic_dec(&sbi->total_ext_tree);
up_write(&sbi->extent_tree_lock);
F2FS_I(inode)->extent_tree = NULL;
@@ -722,7 +734,9 @@ void init_extent_cache_info(struct f2fs_sb_info *sbi)
init_rwsem(&sbi->extent_tree_lock);
INIT_LIST_HEAD(&sbi->extent_list);
spin_lock_init(&sbi->extent_lock);
- sbi->total_ext_tree = 0;
+ atomic_set(&sbi->total_ext_tree, 0);
+ INIT_LIST_HEAD(&sbi->zombie_list);
+ atomic_set(&sbi->total_zombie_tree, 0);
atomic_set(&sbi->total_ext_node, 0);
}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index ec6067c33a3f..ff79054c6cf6 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -21,6 +21,7 @@
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/bio.h>
+#include <linux/blkdev.h>
#ifdef CONFIG_F2FS_CHECK_FS
#define f2fs_bug_on(sbi, condition) BUG_ON(condition)
@@ -54,6 +55,7 @@
#define F2FS_MOUNT_FASTBOOT 0x00001000
#define F2FS_MOUNT_EXTENT_CACHE 0x00002000
#define F2FS_MOUNT_FORCE_FG_GC 0x00004000
+#define F2FS_MOUNT_DATA_FLUSH 0x00008000
#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -125,6 +127,7 @@ enum {
#define BATCHED_TRIM_BLOCKS(sbi) \
(BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg)
#define DEF_CP_INTERVAL 60 /* 60 secs */
+#define DEF_IDLE_INTERVAL 120 /* 2 mins */
struct cp_control {
int reason;
@@ -158,13 +161,7 @@ struct ino_entry {
nid_t ino; /* inode number */
};
-/*
- * for the list of directory inodes or gc inodes.
- * NOTE: there are two slab users for this structure, if we add/modify/delete
- * fields in structure for one of slab users, it may affect fields or size of
- * other one, in this condition, it's better to split both of slab and related
- * data structure.
- */
+/* for the list of inodes to be GCed */
struct inode_entry {
struct list_head list; /* list head */
struct inode *inode; /* vfs inode pointer */
@@ -234,6 +231,7 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
#define F2FS_IOC_GARBAGE_COLLECT _IO(F2FS_IOCTL_MAGIC, 6)
#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7)
+#define F2FS_IOC_DEFRAGMENT _IO(F2FS_IOCTL_MAGIC, 8)
#define F2FS_IOC_SET_ENCRYPTION_POLICY \
_IOR('f', 19, struct f2fs_encryption_policy)
@@ -256,10 +254,16 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
/*
* ioctl commands in 32 bit emulation
*/
-#define F2FS_IOC32_GETFLAGS FS_IOC32_GETFLAGS
-#define F2FS_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define F2FS_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define F2FS_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define F2FS_IOC32_GETVERSION FS_IOC32_GETVERSION
#endif
+struct f2fs_defragment {
+ u64 start;
+ u64 len;
+};
+
/*
* For INODE and NODE manager
*/
@@ -357,9 +361,9 @@ struct extent_tree {
struct rb_root root; /* root of extent info rb-tree */
struct extent_node *cached_en; /* recently accessed extent node */
struct extent_info largest; /* largested extent info */
+ struct list_head list; /* to be used by sbi->zombie_list */
rwlock_t lock; /* protect extent info rb-tree */
- atomic_t refcount; /* reference count of rb-tree */
- unsigned int count; /* # of extent node in rb-tree*/
+ atomic_t node_cnt; /* # of extent node in rb-tree*/
};
/*
@@ -434,8 +438,8 @@ struct f2fs_inode_info {
unsigned int clevel; /* maximum level of given file name */
nid_t i_xattr_nid; /* node id that contains xattrs */
unsigned long long xattr_ver; /* cp version of xattr modification */
- struct inode_entry *dirty_dir; /* the pointer of dirty dir */
+ struct list_head dirty_list; /* linked in global dirty list */
struct list_head inmem_pages; /* inmemory pages managed by f2fs */
struct mutex inmem_lock; /* lock for inmemory pages */
@@ -544,6 +548,7 @@ struct dnode_of_data {
nid_t nid; /* node id of the direct node block */
unsigned int ofs_in_node; /* data offset in the node page */
bool inode_page_locked; /* inode page is locked or not */
+ bool node_changed; /* is node block changed */
block_t data_blkaddr; /* block address of the node block */
};
@@ -647,6 +652,7 @@ struct f2fs_sm_info {
enum count_type {
F2FS_WRITEBACK,
F2FS_DIRTY_DENTS,
+ F2FS_DIRTY_DATA,
F2FS_DIRTY_NODES,
F2FS_DIRTY_META,
F2FS_INMEM_PAGES,
@@ -695,6 +701,12 @@ struct f2fs_bio_info {
struct rw_semaphore io_rwsem; /* blocking op for bio */
};
+enum inode_type {
+ DIR_INODE, /* for dirty dir inode */
+ FILE_INODE, /* for dirty regular/symlink inode */
+ NR_INODE_TYPE,
+};
+
/* for inner inode cache management */
struct inode_management {
struct radix_tree_root ino_root; /* ino entry array */
@@ -711,11 +723,17 @@ enum {
SBI_POR_DOING, /* recovery is doing or not */
};
+enum {
+ CP_TIME,
+ REQ_TIME,
+ MAX_TIME,
+};
+
struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */
- struct buffer_head *raw_super_buf; /* buffer head of raw sb */
struct f2fs_super_block *raw_super; /* raw super block pointer */
+ int valid_super_block; /* valid super block no */
int s_flag; /* flags for sbi */
/* for node-related operations */
@@ -737,23 +755,26 @@ struct f2fs_sb_info {
struct rw_semaphore node_write; /* locking node writes */
struct mutex writepages; /* mutex for writepages() */
wait_queue_head_t cp_wait;
- long cp_expires, cp_interval; /* next expected periodic cp */
+ unsigned long last_time[MAX_TIME]; /* to store time in jiffies */
+ long interval_time[MAX_TIME]; /* to store thresholds */
struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */
/* for orphan inode, use 0'th array */
unsigned int max_orphans; /* max orphan inodes */
- /* for directory inode management */
- struct list_head dir_inode_list; /* dir inode list */
- spinlock_t dir_inode_lock; /* for dir inode list lock */
+ /* for inode management */
+ struct list_head inode_list[NR_INODE_TYPE]; /* dirty inode list */
+ spinlock_t inode_lock[NR_INODE_TYPE]; /* for dirty inode list lock */
/* for extent tree cache */
struct radix_tree_root extent_tree_root;/* cache extent cache entries */
struct rw_semaphore extent_tree_lock; /* locking extent radix tree */
struct list_head extent_list; /* lru list for shrinker */
spinlock_t extent_lock; /* locking extent lru list */
- int total_ext_tree; /* extent tree count */
+ atomic_t total_ext_tree; /* extent tree count */
+ struct list_head zombie_list; /* extent zombie tree list */
+ atomic_t total_zombie_tree; /* extent zombie tree count */
atomic_t total_ext_node; /* extent info count */
/* basic filesystem units */
@@ -771,6 +792,7 @@ struct f2fs_sb_info {
unsigned int total_node_count; /* total node block count */
unsigned int total_valid_node_count; /* valid node block count */
unsigned int total_valid_inode_count; /* valid inode count */
+ loff_t max_file_blocks; /* max block index of file */
int active_logs; /* # of active logs */
int dir_level; /* directory level */
@@ -809,7 +831,7 @@ struct f2fs_sb_info {
atomic_t inline_inode; /* # of inline_data inodes */
atomic_t inline_dir; /* # of inline_dentry inodes */
int bg_gc; /* background gc calls */
- unsigned int n_dirty_dirs; /* # of dir inodes */
+ unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */
#endif
unsigned int last_victim[2]; /* last victim segment # */
spinlock_t stat_lock; /* lock for stat operations */
@@ -824,6 +846,31 @@ struct f2fs_sb_info {
unsigned int shrinker_run_no;
};
+static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type)
+{
+ sbi->last_time[type] = jiffies;
+}
+
+static inline bool f2fs_time_over(struct f2fs_sb_info *sbi, int type)
+{
+ struct timespec ts = {sbi->interval_time[type], 0};
+ unsigned long interval = timespec_to_jiffies(&ts);
+
+ return time_after(jiffies, sbi->last_time[type] + interval);
+}
+
+static inline bool is_idle(struct f2fs_sb_info *sbi)
+{
+ struct block_device *bdev = sbi->sb->s_bdev;
+ struct request_queue *q = bdev_get_queue(bdev);
+ struct request_list *rl = &q->root_rl;
+
+ if (rl->count[BLK_RW_SYNC] || rl->count[BLK_RW_ASYNC])
+ return 0;
+
+ return f2fs_time_over(sbi, REQ_TIME);
+}
+
/*
* Inline functions
*/
@@ -1059,8 +1106,8 @@ static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
static inline void inode_inc_dirty_pages(struct inode *inode)
{
atomic_inc(&F2FS_I(inode)->dirty_pages);
- if (S_ISDIR(inode->i_mode))
- inc_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS);
+ inc_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
+ F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
}
static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
@@ -1075,9 +1122,8 @@ static inline void inode_dec_dirty_pages(struct inode *inode)
return;
atomic_dec(&F2FS_I(inode)->dirty_pages);
-
- if (S_ISDIR(inode->i_mode))
- dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_DENTS);
+ dec_page_count(F2FS_I_SB(inode), S_ISDIR(inode->i_mode) ?
+ F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA);
}
static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
@@ -1092,8 +1138,7 @@ static inline int get_dirty_pages(struct inode *inode)
static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type)
{
- unsigned int pages_per_sec = sbi->segs_per_sec *
- (1 << sbi->log_blocks_per_seg);
+ unsigned int pages_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg;
return ((get_pages(sbi, block_type) + pages_per_sec - 1)
>> sbi->log_blocks_per_seg) / sbi->segs_per_sec;
}
@@ -1416,6 +1461,8 @@ enum {
FI_DROP_CACHE, /* drop dirty page cache */
FI_DATA_EXIST, /* indicate data exists */
FI_INLINE_DOTS, /* indicate inline dot dentries */
+ FI_DO_DEFRAG, /* indicate defragment is running */
+ FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
};
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -1659,8 +1706,8 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);
void f2fs_set_inode_flags(struct inode *);
struct inode *f2fs_iget(struct super_block *, unsigned long);
int try_to_free_nats(struct f2fs_sb_info *, int);
-void update_inode(struct inode *, struct page *);
-void update_inode_page(struct inode *);
+int update_inode(struct inode *, struct page *);
+int update_inode_page(struct inode *);
int f2fs_write_inode(struct inode *, struct writeback_control *);
void f2fs_evict_inode(struct inode *);
void handle_failed_inode(struct inode *);
@@ -1765,7 +1812,7 @@ void destroy_node_manager_caches(void);
*/
void register_inmem_page(struct inode *, struct page *);
int commit_inmem_pages(struct inode *, bool);
-void f2fs_balance_fs(struct f2fs_sb_info *);
+void f2fs_balance_fs(struct f2fs_sb_info *, bool);
void f2fs_balance_fs_bg(struct f2fs_sb_info *);
int f2fs_issue_flush(struct f2fs_sb_info *);
int create_flush_cmd_control(struct f2fs_sb_info *);
@@ -1811,9 +1858,9 @@ bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int);
int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool);
void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
-void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
-void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
-void release_dirty_inode(struct f2fs_sb_info *);
+void add_ino_entry(struct f2fs_sb_info *, nid_t, int type);
+void remove_ino_entry(struct f2fs_sb_info *, nid_t, int type);
+void release_ino_entry(struct f2fs_sb_info *);
bool exist_written_data(struct f2fs_sb_info *, nid_t, int);
int acquire_orphan_inode(struct f2fs_sb_info *);
void release_orphan_inode(struct f2fs_sb_info *);
@@ -1823,9 +1870,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *);
int get_valid_checkpoint(struct f2fs_sb_info *);
void update_dirty_page(struct inode *, struct page *);
void add_dirty_dir_inode(struct inode *);
-void remove_dirty_dir_inode(struct inode *);
-void sync_dirty_dir_inodes(struct f2fs_sb_info *);
-void write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
+void remove_dirty_inode(struct inode *);
+int sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type);
+int write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
void init_ino_entry_info(struct f2fs_sb_info *);
int __init create_checkpoint_caches(void);
void destroy_checkpoint_caches(void);
@@ -1845,6 +1892,7 @@ struct page *find_data_page(struct inode *, pgoff_t);
struct page *get_lock_data_page(struct inode *, pgoff_t, bool);
struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool);
int do_write_data_page(struct f2fs_io_info *);
+int f2fs_map_blocks(struct inode *, struct f2fs_map_blocks *, int, int);
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64);
void f2fs_invalidate_page(struct page *, unsigned int, unsigned int);
int f2fs_release_page(struct page *, gfp_t);
@@ -1875,8 +1923,9 @@ struct f2fs_stat_info {
int main_area_segs, main_area_sections, main_area_zones;
unsigned long long hit_largest, hit_cached, hit_rbtree;
unsigned long long hit_total, total_ext;
- int ext_tree, ext_node;
- int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta;
+ int ext_tree, zombie_tree, ext_node;
+ int ndirty_node, ndirty_meta;
+ int ndirty_dent, ndirty_dirs, ndirty_data, ndirty_files;
int nats, dirty_nats, sits, dirty_sits, fnids;
int total_count, utilization;
int bg_gc, inmem_pages, wb_pages;
@@ -1886,7 +1935,7 @@ struct f2fs_stat_info {
int util_free, util_valid, util_invalid;
int rsvd_segs, overp_segs;
int dirty_count, node_pages, meta_pages;
- int prefree_count, call_count, cp_count;
+ int prefree_count, call_count, cp_count, bg_cp_count;
int tot_segs, node_segs, data_segs, free_segs, free_secs;
int bg_node_segs, bg_data_segs;
int tot_blks, data_blks, node_blks;
@@ -1907,10 +1956,11 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
}
#define stat_inc_cp_count(si) ((si)->cp_count++)
+#define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++)
#define stat_inc_call_count(si) ((si)->call_count++)
#define stat_inc_bggc_count(sbi) ((sbi)->bg_gc++)
-#define stat_inc_dirty_dir(sbi) ((sbi)->n_dirty_dirs++)
-#define stat_dec_dirty_dir(sbi) ((sbi)->n_dirty_dirs--)
+#define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++)
+#define stat_dec_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]--)
#define stat_inc_total_hit(sbi) (atomic64_inc(&(sbi)->total_hit_ext))
#define stat_inc_rbtree_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_rbtree))
#define stat_inc_largest_node_hit(sbi) (atomic64_inc(&(sbi)->read_hit_largest))
@@ -1985,14 +2035,15 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
int f2fs_build_stats(struct f2fs_sb_info *);
void f2fs_destroy_stats(struct f2fs_sb_info *);
-void __init f2fs_create_root_stats(void);
+int __init f2fs_create_root_stats(void);
void f2fs_destroy_root_stats(void);
#else
#define stat_inc_cp_count(si)
+#define stat_inc_bg_cp_count(si)
#define stat_inc_call_count(si)
#define stat_inc_bggc_count(si)
-#define stat_inc_dirty_dir(sbi)
-#define stat_dec_dirty_dir(sbi)
+#define stat_inc_dirty_inode(sbi, type)
+#define stat_dec_dirty_inode(sbi, type)
#define stat_inc_total_hit(sb)
#define stat_inc_rbtree_node_hit(sb)
#define stat_inc_largest_node_hit(sbi)
@@ -2013,7 +2064,7 @@ void f2fs_destroy_root_stats(void);
static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; }
static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { }
-static inline void __init f2fs_create_root_stats(void) { }
+static inline int __init f2fs_create_root_stats(void) { return 0; }
static inline void f2fs_destroy_root_stats(void) { }
#endif
@@ -2067,8 +2118,7 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *);
* extent_cache.c
*/
unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *, int);
-void f2fs_drop_largest_extent(struct inode *, pgoff_t);
-void f2fs_init_extent_tree(struct inode *, struct f2fs_extent *);
+bool f2fs_init_extent_tree(struct inode *, struct f2fs_extent *);
unsigned int f2fs_destroy_extent_node(struct inode *);
void f2fs_destroy_extent_tree(struct inode *);
bool f2fs_lookup_extent_cache(struct inode *, pgoff_t, struct extent_info *);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index a197215ad52b..18ddb1e5182a 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -40,8 +40,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
struct dnode_of_data dn;
int err;
- f2fs_balance_fs(sbi);
-
sb_start_pagefault(inode->i_sb);
f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
@@ -57,6 +55,8 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
f2fs_put_dnode(&dn);
f2fs_unlock_op(sbi);
+ f2fs_balance_fs(sbi, dn.node_changed);
+
file_update_time(vma->vm_file);
lock_page(page);
if (unlikely(page->mapping != inode->i_mapping ||
@@ -96,6 +96,7 @@ mapped:
clear_cold_data(page);
out:
sb_end_pagefault(inode->i_sb);
+ f2fs_update_time(sbi, REQ_TIME);
return block_page_mkwrite_return(err);
}
@@ -201,7 +202,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
trace_f2fs_sync_file_enter(inode);
/* if fdatasync is triggered, let's do in-place-update */
- if (get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
+ if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
set_inode_flag(fi, FI_NEED_IPU);
ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
clear_inode_flag(fi, FI_NEED_IPU);
@@ -233,9 +234,6 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
goto out;
}
go_write:
- /* guarantee free sections for fsync */
- f2fs_balance_fs(sbi);
-
/*
* Both of fdatasync() and fsync() are able to be recovered from
* sudden-power-off.
@@ -261,8 +259,10 @@ sync_nodes:
sync_node_pages(sbi, ino, &wbc);
/* if cp_error was enabled, we should avoid infinite loop */
- if (unlikely(f2fs_cp_error(sbi)))
+ if (unlikely(f2fs_cp_error(sbi))) {
+ ret = -EIO;
goto out;
+ }
if (need_inode_block_update(sbi, ino)) {
mark_inode_dirty_sync(inode);
@@ -275,12 +275,13 @@ sync_nodes:
goto out;
/* once recovery info is written, don't need to tack this */
- remove_dirty_inode(sbi, ino, APPEND_INO);
+ remove_ino_entry(sbi, ino, APPEND_INO);
clear_inode_flag(fi, FI_APPEND_WRITE);
flush_out:
- remove_dirty_inode(sbi, ino, UPDATE_INO);
+ remove_ino_entry(sbi, ino, UPDATE_INO);
clear_inode_flag(fi, FI_UPDATE_WRITE);
ret = f2fs_issue_flush(sbi);
+ f2fs_update_time(sbi, REQ_TIME);
out:
trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
f2fs_trace_ios(NULL, 1);
@@ -418,19 +419,18 @@ static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file_inode(file);
+ int err;
if (f2fs_encrypted_inode(inode)) {
- int err = f2fs_get_encryption_info(inode);
+ err = f2fs_get_encryption_info(inode);
if (err)
return 0;
}
/* we don't need to use inline_data strictly */
- if (f2fs_has_inline_data(inode)) {
- int err = f2fs_convert_inline_inode(inode);
- if (err)
- return err;
- }
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
file_accessed(file);
vma->vm_ops = &f2fs_file_vm_ops;
@@ -483,11 +483,11 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
F2FS_I(dn->inode)) + ofs;
f2fs_update_extent_cache_range(dn, fofs, 0, len);
dec_valid_block_count(sbi, dn->inode, nr_free);
- set_page_dirty(dn->node_page);
sync_inode_page(dn);
}
dn->ofs_in_node = ofs;
+ f2fs_update_time(sbi, REQ_TIME);
trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
dn->ofs_in_node, nr_free);
return nr_free;
@@ -604,7 +604,7 @@ int f2fs_truncate(struct inode *inode, bool lock)
trace_f2fs_truncate(inode);
/* we should check inline_data size */
- if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode)) {
+ if (!f2fs_may_inline_data(inode)) {
err = f2fs_convert_inline_inode(inode);
if (err)
return err;
@@ -679,13 +679,20 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
err = f2fs_truncate(inode, true);
if (err)
return err;
- f2fs_balance_fs(F2FS_I_SB(inode));
+ f2fs_balance_fs(F2FS_I_SB(inode), true);
} else {
/*
* do not trim all blocks after i_size if target size is
* larger than i_size.
*/
truncate_setsize(inode, attr->ia_size);
+
+ /* should convert inline inode here */
+ if (!f2fs_may_inline_data(inode)) {
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
+ }
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
}
@@ -727,7 +734,7 @@ static int fill_zero(struct inode *inode, pgoff_t index,
if (!len)
return 0;
- f2fs_balance_fs(sbi);
+ f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
page = get_new_data_page(inode, NULL, index, false);
@@ -778,13 +785,11 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
{
pgoff_t pg_start, pg_end;
loff_t off_start, off_end;
- int ret = 0;
+ int ret;
- if (f2fs_has_inline_data(inode)) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
- }
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
@@ -815,7 +820,7 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
loff_t blk_start, blk_end;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- f2fs_balance_fs(sbi);
+ f2fs_balance_fs(sbi, true);
blk_start = (loff_t)pg_start << PAGE_CACHE_SHIFT;
blk_end = (loff_t)pg_end << PAGE_CACHE_SHIFT;
@@ -918,7 +923,7 @@ static int f2fs_do_collapse(struct inode *inode, pgoff_t start, pgoff_t end)
int ret = 0;
for (; end < nrpages; start++, end++) {
- f2fs_balance_fs(sbi);
+ f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
ret = __exchange_data_block(inode, end, start, true);
f2fs_unlock_op(sbi);
@@ -941,13 +946,9 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
return -EINVAL;
- f2fs_balance_fs(F2FS_I_SB(inode));
-
- if (f2fs_has_inline_data(inode)) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
- }
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
pg_start = offset >> PAGE_CACHE_SHIFT;
pg_end = (offset + len) >> PAGE_CACHE_SHIFT;
@@ -991,13 +992,9 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
if (ret)
return ret;
- f2fs_balance_fs(sbi);
-
- if (f2fs_has_inline_data(inode)) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
- }
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
if (ret)
@@ -1104,13 +1101,11 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
return -EINVAL;
- f2fs_balance_fs(sbi);
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
- if (f2fs_has_inline_data(inode)) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
- }
+ f2fs_balance_fs(sbi, true);
ret = truncate_blocks(inode, i_size_read(inode), true);
if (ret)
@@ -1154,17 +1149,15 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
loff_t off_start, off_end;
int ret = 0;
- f2fs_balance_fs(sbi);
-
ret = inode_newsize_ok(inode, (len + offset));
if (ret)
return ret;
- if (f2fs_has_inline_data(inode)) {
- ret = f2fs_convert_inline_inode(inode);
- if (ret)
- return ret;
- }
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
+
+ f2fs_balance_fs(sbi, true);
pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
@@ -1246,6 +1239,7 @@ static long f2fs_fallocate(struct file *file, int mode,
if (!ret) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
}
out:
@@ -1353,8 +1347,6 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
if (!inode_owner_or_capable(inode))
return -EACCES;
- f2fs_balance_fs(F2FS_I_SB(inode));
-
if (f2fs_is_atomic_file(inode))
return 0;
@@ -1363,6 +1355,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
return ret;
set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+
return 0;
}
@@ -1384,8 +1378,10 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
if (f2fs_is_atomic_file(inode)) {
clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
ret = commit_inmem_pages(inode, false);
- if (ret)
+ if (ret) {
+ set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
goto err_out;
+ }
}
ret = f2fs_sync_file(filp, 0, LLONG_MAX, 0);
@@ -1410,6 +1406,7 @@ static int f2fs_ioc_start_volatile_write(struct file *filp)
return ret;
set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return 0;
}
@@ -1441,13 +1438,17 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
if (ret)
return ret;
- f2fs_balance_fs(F2FS_I_SB(inode));
-
- clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
- clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
- commit_inmem_pages(inode, true);
+ if (f2fs_is_atomic_file(inode)) {
+ clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+ commit_inmem_pages(inode, true);
+ }
+ if (f2fs_is_volatile_file(inode)) {
+ clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
+ ret = f2fs_sync_file(filp, 0, LLONG_MAX, 0);
+ }
mnt_drop_write_file(filp);
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return ret;
}
@@ -1487,6 +1488,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
default:
return -EINVAL;
}
+ f2fs_update_time(sbi, REQ_TIME);
return 0;
}
@@ -1517,6 +1519,7 @@ static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
if (copy_to_user((struct fstrim_range __user *)arg, &range,
sizeof(range)))
return -EFAULT;
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return 0;
}
@@ -1540,6 +1543,7 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
sizeof(policy)))
return -EFAULT;
+ f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return f2fs_process_policy(&policy, inode);
#else
return -EOPNOTSUPP;
@@ -1586,13 +1590,13 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
err = f2fs_commit_super(sbi, false);
-
- mnt_drop_write_file(filp);
if (err) {
/* undo new data */
memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
+ mnt_drop_write_file(filp);
return err;
}
+ mnt_drop_write_file(filp);
got_it:
if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt,
16))
@@ -1629,7 +1633,6 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct cp_control cpc;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1637,13 +1640,196 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
if (f2fs_readonly(sbi->sb))
return -EROFS;
- cpc.reason = __get_cp_reason(sbi);
+ return f2fs_sync_fs(sbi->sb, 1);
+}
- mutex_lock(&sbi->gc_mutex);
- write_checkpoint(sbi, &cpc);
- mutex_unlock(&sbi->gc_mutex);
+static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
+ struct file *filp,
+ struct f2fs_defragment *range)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_map_blocks map;
+ struct extent_info ei;
+ pgoff_t pg_start, pg_end;
+ unsigned int blk_per_seg = sbi->blocks_per_seg;
+ unsigned int total = 0, sec_num;
+ unsigned int pages_per_sec = sbi->segs_per_sec * blk_per_seg;
+ block_t blk_end = 0;
+ bool fragmented = false;
+ int err;
- return 0;
+ /* if in-place-update policy is enabled, don't waste time here */
+ if (need_inplace_update(inode))
+ return -EINVAL;
+
+ pg_start = range->start >> PAGE_CACHE_SHIFT;
+ pg_end = (range->start + range->len) >> PAGE_CACHE_SHIFT;
+
+ f2fs_balance_fs(sbi, true);
+
+ mutex_lock(&inode->i_mutex);
+
+ /* writeback all dirty pages in the range */
+ err = filemap_write_and_wait_range(inode->i_mapping, range->start,
+ range->start + range->len - 1);
+ if (err)
+ goto out;
+
+ /*
+ * lookup mapping info in extent cache, skip defragmenting if physical
+ * block addresses are continuous.
+ */
+ if (f2fs_lookup_extent_cache(inode, pg_start, &ei)) {
+ if (ei.fofs + ei.len >= pg_end)
+ goto out;
+ }
+
+ map.m_lblk = pg_start;
+
+ /*
+ * lookup mapping info in dnode page cache, skip defragmenting if all
+ * physical block addresses are continuous even if there are hole(s)
+ * in logical blocks.
+ */
+ while (map.m_lblk < pg_end) {
+ map.m_len = pg_end - map.m_lblk;
+ err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ);
+ if (err)
+ goto out;
+
+ if (!(map.m_flags & F2FS_MAP_FLAGS)) {
+ map.m_lblk++;
+ continue;
+ }
+
+ if (blk_end && blk_end != map.m_pblk) {
+ fragmented = true;
+ break;
+ }
+ blk_end = map.m_pblk + map.m_len;
+
+ map.m_lblk += map.m_len;
+ }
+
+ if (!fragmented)
+ goto out;
+
+ map.m_lblk = pg_start;
+ map.m_len = pg_end - pg_start;
+
+ sec_num = (map.m_len + pages_per_sec - 1) / pages_per_sec;
+
+ /*
+ * make sure there are enough free section for LFS allocation, this can
+ * avoid defragment running in SSR mode when free section are allocated
+ * intensively
+ */
+ if (has_not_enough_free_secs(sbi, sec_num)) {
+ err = -EAGAIN;
+ goto out;
+ }
+
+ while (map.m_lblk < pg_end) {
+ pgoff_t idx;
+ int cnt = 0;
+
+do_map:
+ map.m_len = pg_end - map.m_lblk;
+ err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ);
+ if (err)
+ goto clear_out;
+
+ if (!(map.m_flags & F2FS_MAP_FLAGS)) {
+ map.m_lblk++;
+ continue;
+ }
+
+ set_inode_flag(F2FS_I(inode), FI_DO_DEFRAG);
+
+ idx = map.m_lblk;
+ while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
+ struct page *page;
+
+ page = get_lock_data_page(inode, idx, true);
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto clear_out;
+ }
+
+ set_page_dirty(page);
+ f2fs_put_page(page, 1);
+
+ idx++;
+ cnt++;
+ total++;
+ }
+
+ map.m_lblk = idx;
+
+ if (idx < pg_end && cnt < blk_per_seg)
+ goto do_map;
+
+ clear_inode_flag(F2FS_I(inode), FI_DO_DEFRAG);
+
+ err = filemap_fdatawrite(inode->i_mapping);
+ if (err)
+ goto out;
+ }
+clear_out:
+ clear_inode_flag(F2FS_I(inode), FI_DO_DEFRAG);
+out:
+ mutex_unlock(&inode->i_mutex);
+ if (!err)
+ range->len = (u64)total << PAGE_CACHE_SHIFT;
+ return err;
+}
+
+static int f2fs_ioc_defragment(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_defragment range;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
+
+ if (f2fs_readonly(sbi->sb)) {
+ err = -EROFS;
+ goto out;
+ }
+
+ if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
+ sizeof(range))) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* verify alignment of offset & size */
+ if (range.start & (F2FS_BLKSIZE - 1) ||
+ range.len & (F2FS_BLKSIZE - 1)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = f2fs_defragment_range(sbi, filp, &range);
+ f2fs_update_time(sbi, REQ_TIME);
+ if (err < 0)
+ goto out;
+
+ if (copy_to_user((struct f2fs_defragment __user *)arg, &range,
+ sizeof(range)))
+ err = -EFAULT;
+out:
+ mnt_drop_write_file(filp);
+ return err;
}
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
@@ -1679,6 +1865,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return f2fs_ioc_gc(filp, arg);
case F2FS_IOC_WRITE_CHECKPOINT:
return f2fs_ioc_write_checkpoint(filp, arg);
+ case F2FS_IOC_DEFRAGMENT:
+ return f2fs_ioc_defragment(filp, arg);
default:
return -ENOTTY;
}
@@ -1706,6 +1894,22 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case F2FS_IOC32_SETFLAGS:
cmd = F2FS_IOC_SETFLAGS;
break;
+ case F2FS_IOC32_GETVERSION:
+ cmd = F2FS_IOC_GETVERSION;
+ break;
+ case F2FS_IOC_START_ATOMIC_WRITE:
+ case F2FS_IOC_COMMIT_ATOMIC_WRITE:
+ case F2FS_IOC_START_VOLATILE_WRITE:
+ case F2FS_IOC_RELEASE_VOLATILE_WRITE:
+ case F2FS_IOC_ABORT_VOLATILE_WRITE:
+ case F2FS_IOC_SHUTDOWN:
+ case F2FS_IOC_SET_ENCRYPTION_POLICY:
+ case F2FS_IOC_GET_ENCRYPTION_PWSALT:
+ case F2FS_IOC_GET_ENCRYPTION_POLICY:
+ case F2FS_IOC_GARBAGE_COLLECT:
+ case F2FS_IOC_WRITE_CHECKPOINT:
+ case F2FS_IOC_DEFRAGMENT:
+ break;
default:
return -ENOIOCTLCMD;
}
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index fedbf67a0842..f610c2a9bdde 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -16,7 +16,6 @@
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/freezer.h>
-#include <linux/blkdev.h>
#include "f2fs.h"
#include "node.h"
@@ -173,9 +172,9 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
{
/* SSR allocates in a segment unit */
if (p->alloc_mode == SSR)
- return 1 << sbi->log_blocks_per_seg;
+ return sbi->blocks_per_seg;
if (p->gc_mode == GC_GREEDY)
- return (1 << sbi->log_blocks_per_seg) * p->ofs_unit;
+ return sbi->blocks_per_seg * p->ofs_unit;
else if (p->gc_mode == GC_CB)
return UINT_MAX;
else /* No other gc_mode */
@@ -832,8 +831,10 @@ gc_more:
if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
goto stop;
- if (unlikely(f2fs_cp_error(sbi)))
+ if (unlikely(f2fs_cp_error(sbi))) {
+ ret = -EIO;
goto stop;
+ }
if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed)) {
gc_type = FG_GC;
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h
index b4a65be9f7d3..a993967dcdb9 100644
--- a/fs/f2fs/gc.h
+++ b/fs/f2fs/gc.h
@@ -100,11 +100,3 @@ static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
return true;
return false;
}
-
-static inline int is_idle(struct f2fs_sb_info *sbi)
-{
- struct block_device *bdev = sbi->sb->s_bdev;
- struct request_queue *q = bdev_get_queue(bdev);
- struct request_list *rl = &q->root_rl;
- return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]);
-}
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index bda7126466c0..c3f0b7d4cfca 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -16,9 +16,6 @@
bool f2fs_may_inline_data(struct inode *inode)
{
- if (!test_opt(F2FS_I_SB(inode), INLINE_DATA))
- return false;
-
if (f2fs_is_atomic_file(inode))
return false;
@@ -177,6 +174,9 @@ int f2fs_convert_inline_inode(struct inode *inode)
struct page *ipage, *page;
int err = 0;
+ if (!f2fs_has_inline_data(inode))
+ return 0;
+
page = grab_cache_page(inode->i_mapping, 0);
if (!page)
return -ENOMEM;
@@ -199,6 +199,9 @@ out:
f2fs_unlock_op(sbi);
f2fs_put_page(page, 1);
+
+ f2fs_balance_fs(sbi, dn.node_changed);
+
return err;
}
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 5528801a5baf..2adeff26be11 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -138,7 +138,8 @@ static int do_read_inode(struct inode *inode)
fi->i_pino = le32_to_cpu(ri->i_pino);
fi->i_dir_level = ri->i_dir_level;
- f2fs_init_extent_tree(inode, &ri->i_ext);
+ if (f2fs_init_extent_tree(inode, &ri->i_ext))
+ set_page_dirty(node_page);
get_inline_info(fi, ri);
@@ -222,7 +223,7 @@ bad_inode:
return ERR_PTR(ret);
}
-void update_inode(struct inode *inode, struct page *node_page)
+int update_inode(struct inode *inode, struct page *node_page)
{
struct f2fs_inode *ri;
@@ -260,15 +261,16 @@ void update_inode(struct inode *inode, struct page *node_page)
__set_inode_rdev(inode, ri);
set_cold_node(inode, node_page);
- set_page_dirty(node_page);
-
clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
+
+ return set_page_dirty(node_page);
}
-void update_inode_page(struct inode *inode)
+int update_inode_page(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *node_page;
+ int ret = 0;
retry:
node_page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(node_page)) {
@@ -279,10 +281,11 @@ retry:
} else if (err != -ENOENT) {
f2fs_stop_checkpoint(sbi);
}
- return;
+ return 0;
}
- update_inode(inode, node_page);
+ ret = update_inode(inode, node_page);
f2fs_put_page(node_page, 1);
+ return ret;
}
int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -300,9 +303,8 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
* We need to balance fs here to prevent from producing dirty node pages
* during the urgent cleaning time when runing out of free sections.
*/
- update_inode_page(inode);
-
- f2fs_balance_fs(sbi);
+ if (update_inode_page(inode))
+ f2fs_balance_fs(sbi, true);
return 0;
}
@@ -328,7 +330,7 @@ void f2fs_evict_inode(struct inode *inode)
goto out_clear;
f2fs_bug_on(sbi, get_dirty_pages(inode));
- remove_dirty_dir_inode(inode);
+ remove_dirty_inode(inode);
f2fs_destroy_extent_tree(inode);
@@ -358,9 +360,9 @@ no_delete:
if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
if (is_inode_flag_set(fi, FI_APPEND_WRITE))
- add_dirty_inode(sbi, inode->i_ino, APPEND_INO);
+ add_ino_entry(sbi, inode->i_ino, APPEND_INO);
if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
- add_dirty_inode(sbi, inode->i_ino, UPDATE_INO);
+ add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
if (is_inode_flag_set(fi, FI_FREE_NID)) {
if (err && err != -ENOENT)
alloc_nid_done(sbi, inode->i_ino);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index e7587fce1b80..6f944e5eb76e 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -60,7 +60,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
f2fs_set_encrypted_inode(inode);
- if (f2fs_may_inline_data(inode))
+ if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
if (f2fs_may_inline_dentry(inode))
set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
@@ -128,8 +128,6 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
nid_t ino = 0;
int err;
- f2fs_balance_fs(sbi);
-
inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -142,6 +140,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
inode->i_mapping->a_ops = &f2fs_dblock_aops;
ino = inode->i_ino;
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
@@ -172,7 +172,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
!f2fs_is_child_context_consistent_with_parent(dir, inode))
return -EPERM;
- f2fs_balance_fs(sbi);
+ f2fs_balance_fs(sbi, true);
inode->i_ctime = CURRENT_TIME;
ihold(inode);
@@ -214,6 +214,15 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
struct page *page;
int err = 0;
+ if (f2fs_readonly(sbi->sb)) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "skip recovering inline_dots inode (ino:%lu, pino:%u) "
+ "in readonly mountpoint", dir->i_ino, pino);
+ return 0;
+ }
+
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
de = f2fs_find_entry(dir, &dot, &page);
@@ -288,12 +297,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
int err = -ENOENT;
trace_f2fs_unlink_enter(dir, dentry);
- f2fs_balance_fs(sbi);
de = f2fs_find_entry(dir, &dentry->d_name, &page);
if (!de)
goto fail;
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi);
if (err) {
@@ -344,8 +354,6 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
if (len > dir->i_sb->s_blocksize)
return -ENAMETOOLONG;
- f2fs_balance_fs(sbi);
-
inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -357,6 +365,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
inode_nohighmem(inode);
inode->i_mapping->a_ops = &f2fs_dblock_aops;
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
@@ -437,8 +447,6 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *inode;
int err;
- f2fs_balance_fs(sbi);
-
inode = f2fs_new_inode(dir, S_IFDIR | mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -448,6 +456,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
inode->i_mapping->a_ops = &f2fs_dblock_aops;
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);
+ f2fs_balance_fs(sbi, true);
+
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
@@ -485,8 +495,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
struct inode *inode;
int err = 0;
- f2fs_balance_fs(sbi);
-
inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -494,6 +502,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
init_special_inode(inode, inode->i_mode, rdev);
inode->i_op = &f2fs_special_inode_operations;
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
@@ -520,9 +530,6 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
struct inode *inode;
int err;
- if (!whiteout)
- f2fs_balance_fs(sbi);
-
inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -536,6 +543,8 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
inode->i_mapping->a_ops = &f2fs_dblock_aops;
}
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi);
if (err)
@@ -608,8 +617,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out;
}
- f2fs_balance_fs(sbi);
-
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_entry)
goto out;
@@ -639,6 +646,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!new_entry)
goto out_whiteout;
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi);
@@ -670,6 +679,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
update_inode_page(old_inode);
update_inode_page(new_inode);
} else {
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = f2fs_add_link(new_dentry, old_inode);
@@ -767,8 +778,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
new_inode)))
return -EPERM;
- f2fs_balance_fs(sbi);
-
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_entry)
goto out;
@@ -811,6 +820,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out_new_dir;
}
+ f2fs_balance_fs(sbi, true);
+
f2fs_lock_op(sbi);
err = update_dent_inode(old_inode, new_inode, &new_dentry->d_name);
@@ -933,7 +944,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
{
struct page *cpage = NULL;
char *caddr, *paddr = NULL;
- struct f2fs_str cstr;
+ struct f2fs_str cstr = FSTR_INIT(NULL, 0);
struct f2fs_str pstr = FSTR_INIT(NULL, 0);
struct f2fs_encrypted_symlink_data *sd;
loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
@@ -956,6 +967,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
/* Symlink is encrypted */
sd = (struct f2fs_encrypted_symlink_data *)caddr;
cstr.len = le16_to_cpu(sd->len);
+
+ /* this is broken symlink case */
+ if (unlikely(cstr.len == 0)) {
+ res = -ENOENT;
+ goto errout;
+ }
cstr.name = kmalloc(cstr.len, GFP_NOFS);
if (!cstr.name) {
res = -ENOMEM;
@@ -964,7 +981,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
memcpy(cstr.name, sd->encrypted_path, cstr.len);
/* this is broken symlink case */
- if (cstr.name[0] == 0 && cstr.len == 0) {
+ if (unlikely(cstr.name[0] == 0)) {
res = -ENOENT;
goto errout;
}
@@ -1005,10 +1022,12 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.get_link = f2fs_encrypted_get_link,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
+#ifdef CONFIG_F2FS_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = f2fs_listxattr,
.removexattr = generic_removexattr,
+#endif
};
#endif
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 7bcbc6e9c40d..342597a5897f 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -65,13 +65,14 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
} else if (type == EXTENT_CACHE) {
- mem_size = (sbi->total_ext_tree * sizeof(struct extent_tree) +
+ mem_size = (atomic_read(&sbi->total_ext_tree) *
+ sizeof(struct extent_tree) +
atomic_read(&sbi->total_ext_node) *
sizeof(struct extent_node)) >> PAGE_CACHE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
} else {
- if (sbi->sb->s_bdi->wb.dirty_exceeded)
- return false;
+ if (!sbi->sb->s_bdi->wb.dirty_exceeded)
+ return true;
}
return res;
}
@@ -261,13 +262,11 @@ static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid,
{
struct nat_entry *e;
- down_write(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, nid);
if (!e) {
e = grab_nat_entry(nm_i, nid);
node_info_from_raw_nat(&e->ni, ne);
}
- up_write(&nm_i->nat_tree_lock);
}
static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
@@ -379,6 +378,8 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
memset(&ne, 0, sizeof(struct f2fs_nat_entry));
+ down_write(&nm_i->nat_tree_lock);
+
/* Check current segment summary */
mutex_lock(&curseg->curseg_mutex);
i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);
@@ -399,6 +400,7 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
cache:
/* cache nat entry */
cache_nat_entry(NM_I(sbi), nid, &ne);
+ up_write(&nm_i->nat_tree_lock);
}
/*
@@ -676,7 +678,8 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
ret = truncate_dnode(&rdn);
if (ret < 0)
goto out_err;
- set_nid(page, i, 0, false);
+ if (set_nid(page, i, 0, false))
+ dn->node_changed = true;
}
} else {
child_nofs = nofs + ofs * (NIDS_PER_BLOCK + 1) + 1;
@@ -689,7 +692,8 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
rdn.nid = child_nid;
ret = truncate_nodes(&rdn, child_nofs, 0, depth - 1);
if (ret == (NIDS_PER_BLOCK + 1)) {
- set_nid(page, i, 0, false);
+ if (set_nid(page, i, 0, false))
+ dn->node_changed = true;
child_nofs += ret;
} else if (ret < 0 && ret != -ENOENT) {
goto out_err;
@@ -750,7 +754,8 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
err = truncate_dnode(dn);
if (err < 0)
goto fail;
- set_nid(pages[idx], i, 0, false);
+ if (set_nid(pages[idx], i, 0, false))
+ dn->node_changed = true;
}
if (offset[idx + 1] == 0) {
@@ -975,7 +980,8 @@ struct page *new_node_page(struct dnode_of_data *dn,
fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
set_cold_node(dn->inode, page);
SetPageUptodate(page);
- set_page_dirty(page);
+ if (set_page_dirty(page))
+ dn->node_changed = true;
if (f2fs_has_xattr_block(ofs))
F2FS_I(dn->inode)->i_xattr_nid = dn->nid;
@@ -1035,6 +1041,10 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
struct page *apage;
int err;
+ if (!nid)
+ return;
+ f2fs_bug_on(sbi, check_nid_range(sbi, nid));
+
apage = find_get_page(NODE_MAPPING(sbi), nid);
if (apage && PageUptodate(apage)) {
f2fs_put_page(apage, 0);
@@ -1050,51 +1060,38 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
f2fs_put_page(apage, err ? 1 : 0);
}
-struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
+/*
+ * readahead MAX_RA_NODE number of node pages.
+ */
+void ra_node_pages(struct page *parent, int start)
{
- struct page *page;
- int err;
-repeat:
- page = grab_cache_page(NODE_MAPPING(sbi), nid);
- if (!page)
- return ERR_PTR(-ENOMEM);
+ struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
+ struct blk_plug plug;
+ int i, end;
+ nid_t nid;
- err = read_node_page(page, READ_SYNC);
- if (err < 0) {
- f2fs_put_page(page, 1);
- return ERR_PTR(err);
- } else if (err != LOCKED_PAGE) {
- lock_page(page);
- }
+ blk_start_plug(&plug);
- if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) {
- ClearPageUptodate(page);
- f2fs_put_page(page, 1);
- return ERR_PTR(-EIO);
- }
- if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
- f2fs_put_page(page, 1);
- goto repeat;
+ /* Then, try readahead for siblings of the desired node */
+ end = start + MAX_RA_NODE;
+ end = min(end, NIDS_PER_BLOCK);
+ for (i = start; i < end; i++) {
+ nid = get_nid(parent, i, false);
+ ra_node_page(sbi, nid);
}
- return page;
+
+ blk_finish_plug(&plug);
}
-/*
- * Return a locked page for the desired node page.
- * And, readahead MAX_RA_NODE number of node pages.
- */
-struct page *get_node_page_ra(struct page *parent, int start)
+struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
+ struct page *parent, int start)
{
- struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
- struct blk_plug plug;
struct page *page;
- int err, i, end;
- nid_t nid;
+ int err;
- /* First, try getting the desired direct node. */
- nid = get_nid(parent, start, false);
if (!nid)
return ERR_PTR(-ENOENT);
+ f2fs_bug_on(sbi, check_nid_range(sbi, nid));
repeat:
page = grab_cache_page(NODE_MAPPING(sbi), nid);
if (!page)
@@ -1108,46 +1105,53 @@ repeat:
goto page_hit;
}
- blk_start_plug(&plug);
-
- /* Then, try readahead for siblings of the desired node */
- end = start + MAX_RA_NODE;
- end = min(end, NIDS_PER_BLOCK);
- for (i = start + 1; i < end; i++) {
- nid = get_nid(parent, i, false);
- if (!nid)
- continue;
- ra_node_page(sbi, nid);
- }
-
- blk_finish_plug(&plug);
+ if (parent)
+ ra_node_pages(parent, start + 1);
lock_page(page);
+
+ if (unlikely(!PageUptodate(page))) {
+ f2fs_put_page(page, 1);
+ return ERR_PTR(-EIO);
+ }
if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
f2fs_put_page(page, 1);
goto repeat;
}
page_hit:
- if (unlikely(!PageUptodate(page))) {
- f2fs_put_page(page, 1);
- return ERR_PTR(-EIO);
- }
+ f2fs_bug_on(sbi, nid != nid_of_node(page));
return page;
}
+struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
+{
+ return __get_node_page(sbi, nid, NULL, 0);
+}
+
+struct page *get_node_page_ra(struct page *parent, int start)
+{
+ struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
+ nid_t nid = get_nid(parent, start, false);
+
+ return __get_node_page(sbi, nid, parent, start);
+}
+
void sync_inode_page(struct dnode_of_data *dn)
{
+ int ret = 0;
+
if (IS_INODE(dn->node_page) || dn->inode_page == dn->node_page) {
- update_inode(dn->inode, dn->node_page);
+ ret = update_inode(dn->inode, dn->node_page);
} else if (dn->inode_page) {
if (!dn->inode_page_locked)
lock_page(dn->inode_page);
- update_inode(dn->inode, dn->inode_page);
+ ret = update_inode(dn->inode, dn->inode_page);
if (!dn->inode_page_locked)
unlock_page(dn->inode_page);
} else {
- update_inode_page(dn->inode);
+ ret = update_inode_page(dn->inode);
}
+ dn->node_changed = ret ? true: false;
}
int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
@@ -1175,6 +1179,11 @@ next_step:
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
+ if (unlikely(f2fs_cp_error(sbi))) {
+ pagevec_release(&pvec);
+ return -EIO;
+ }
+
/*
* flushing sequence with step:
* 0. indirect nodes
@@ -1349,7 +1358,7 @@ static int f2fs_write_node_page(struct page *page,
up_read(&sbi->node_write);
unlock_page(page);
- if (wbc->for_reclaim)
+ if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi)))
f2fs_submit_merged_bio(sbi, NODE, WRITE);
return 0;
@@ -1440,13 +1449,10 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
if (build) {
/* do not add allocated nids */
- down_read(&nm_i->nat_tree_lock);
ne = __lookup_nat_cache(nm_i, nid);
- if (ne &&
- (!get_nat_flag(ne, IS_CHECKPOINTED) ||
+ if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
nat_get_blkaddr(ne) != NULL_ADDR))
allocated = true;
- up_read(&nm_i->nat_tree_lock);
if (allocated)
return 0;
}
@@ -1532,6 +1538,8 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
META_NAT, true);
+ down_read(&nm_i->nat_tree_lock);
+
while (1) {
struct page *page = get_current_nat_page(sbi, nid);
@@ -1560,6 +1568,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
remove_free_nid(nm_i, nid);
}
mutex_unlock(&curseg->curseg_mutex);
+ up_read(&nm_i->nat_tree_lock);
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
nm_i->ra_nid_pages, META_NAT, false);
@@ -1582,8 +1591,6 @@ retry:
/* We should not use stale free nids created by build_free_nids */
if (nm_i->fcnt && !on_build_free_nids(nm_i)) {
- struct node_info ni;
-
f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list));
list_for_each_entry(i, &nm_i->free_nid_list, list)
if (i->state == NID_NEW)
@@ -1594,13 +1601,6 @@ retry:
i->state = NID_ALLOC;
nm_i->fcnt--;
spin_unlock(&nm_i->free_nid_list_lock);
-
- /* check nid is allocated already */
- get_node_info(sbi, *nid, &ni);
- if (ni.blk_addr != NULL_ADDR) {
- alloc_nid_done(sbi, *nid);
- goto retry;
- }
return true;
}
spin_unlock(&nm_i->free_nid_list_lock);
@@ -1842,14 +1842,12 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
raw_ne = nat_in_journal(sum, i);
- down_write(&nm_i->nat_tree_lock);
ne = __lookup_nat_cache(nm_i, nid);
if (!ne) {
ne = grab_nat_entry(nm_i, nid);
node_info_from_raw_nat(&ne->ni, &raw_ne);
}
__set_nat_cache_dirty(nm_i, ne);
- up_write(&nm_i->nat_tree_lock);
}
update_nats_in_cursum(sum, -i);
mutex_unlock(&curseg->curseg_mutex);
@@ -1883,7 +1881,6 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
struct f2fs_nat_block *nat_blk;
struct nat_entry *ne, *cur;
struct page *page = NULL;
- struct f2fs_nm_info *nm_i = NM_I(sbi);
/*
* there are two steps to flush nat entries:
@@ -1920,12 +1917,8 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
raw_ne = &nat_blk->entries[nid - start_nid];
}
raw_nat_from_node_info(raw_ne, &ne->ni);
-
- down_write(&NM_I(sbi)->nat_tree_lock);
nat_reset_flag(ne);
__clear_nat_cache_dirty(NM_I(sbi), ne);
- up_write(&NM_I(sbi)->nat_tree_lock);
-
if (nat_get_blkaddr(ne) == NULL_ADDR)
add_free_nid(sbi, nid, false);
}
@@ -1937,9 +1930,7 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
f2fs_bug_on(sbi, set->entry_cnt);
- down_write(&nm_i->nat_tree_lock);
radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
- up_write(&nm_i->nat_tree_lock);
kmem_cache_free(nat_entry_set_slab, set);
}
@@ -1959,6 +1950,9 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
if (!nm_i->dirty_nat_cnt)
return;
+
+ down_write(&nm_i->nat_tree_lock);
+
/*
* if there are no enough space in journal to store dirty nat
* entries, remove all entries from journal and merge them
@@ -1967,7 +1961,6 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL))
remove_nats_in_journal(sbi);
- down_write(&nm_i->nat_tree_lock);
while ((found = __gang_lookup_nat_set(nm_i,
set_idx, SETVEC_SIZE, setvec))) {
unsigned idx;
@@ -1976,12 +1969,13 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
__adjust_nat_entry_set(setvec[idx], &sets,
MAX_NAT_JENTRIES(sum));
}
- up_write(&nm_i->nat_tree_lock);
/* flush dirty nats in nat entry set */
list_for_each_entry_safe(set, tmp, &sets, set_list)
__flush_nat_entry_set(sbi, set);
+ up_write(&nm_i->nat_tree_lock);
+
f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
}
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index e4fffd2d98c4..d4d1f636fe1c 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -183,7 +183,7 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
block_addr = (pgoff_t)(nm_i->nat_blkaddr +
(seg_off << sbi->log_blocks_per_seg << 1) +
- (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+ (block_off & (sbi->blocks_per_seg - 1)));
if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
block_addr += sbi->blocks_per_seg;
@@ -317,7 +317,7 @@ static inline bool IS_DNODE(struct page *node_page)
return true;
}
-static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
+static inline int set_nid(struct page *p, int off, nid_t nid, bool i)
{
struct f2fs_node *rn = F2FS_NODE(p);
@@ -327,7 +327,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
else
rn->in.nid[off] = cpu_to_le32(nid);
- set_page_dirty(p);
+ return set_page_dirty(p);
}
static inline nid_t get_nid(struct page *p, int off, bool i)
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index cbf74f47cce8..589b20b8677b 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -168,6 +168,32 @@ static void recover_inode(struct inode *inode, struct page *page)
ino_of_node(page), name);
}
+static bool is_same_inode(struct inode *inode, struct page *ipage)
+{
+ struct f2fs_inode *ri = F2FS_INODE(ipage);
+ struct timespec disk;
+
+ if (!IS_INODE(ipage))
+ return true;
+
+ disk.tv_sec = le64_to_cpu(ri->i_ctime);
+ disk.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
+ if (timespec_compare(&inode->i_ctime, &disk) > 0)
+ return false;
+
+ disk.tv_sec = le64_to_cpu(ri->i_atime);
+ disk.tv_nsec = le32_to_cpu(ri->i_atime_nsec);
+ if (timespec_compare(&inode->i_atime, &disk) > 0)
+ return false;
+
+ disk.tv_sec = le64_to_cpu(ri->i_mtime);
+ disk.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
+ if (timespec_compare(&inode->i_mtime, &disk) > 0)
+ return false;
+
+ return true;
+}
+
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
{
unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
@@ -197,7 +223,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
goto next;
entry = get_fsync_inode(head, ino_of_node(page));
- if (!entry) {
+ if (entry) {
+ if (!is_same_inode(entry->inode, page))
+ goto next;
+ } else {
if (IS_INODE(page) && is_dent_dnode(page)) {
err = recover_inode_page(sbi, page);
if (err)
@@ -459,8 +488,7 @@ out:
return err;
}
-static int recover_data(struct f2fs_sb_info *sbi,
- struct list_head *head, int type)
+static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
{
unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
struct curseg_info *curseg;
@@ -469,7 +497,7 @@ static int recover_data(struct f2fs_sb_info *sbi,
block_t blkaddr;
/* get node pages in the current segment */
- curseg = CURSEG_I(sbi, type);
+ curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
while (1) {
@@ -556,7 +584,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
need_writecp = true;
/* step #2: recover data */
- err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
+ err = recover_data(sbi, &inode_list);
if (!err)
f2fs_bug_on(sbi, !list_empty(&inode_list));
out:
@@ -595,7 +623,7 @@ out:
.reason = CP_RECOVERY,
};
mutex_unlock(&sbi->cp_mutex);
- write_checkpoint(sbi, &cpc);
+ err = write_checkpoint(sbi, &cpc);
} else {
mutex_unlock(&sbi->cp_mutex);
}
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index f77b3258454a..5904a411c86f 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -86,6 +86,7 @@ static inline unsigned long __reverse_ffs(unsigned long word)
/*
* __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because
* f2fs_set_bit makes MSB and LSB reversed in a byte.
+ * @size must be integral times of unsigned long.
* Example:
* MSB <--> LSB
* f2fs_set_bit(0, bitmap) => 1000 0000
@@ -95,94 +96,73 @@ static unsigned long __find_rev_next_bit(const unsigned long *addr,
unsigned long size, unsigned long offset)
{
const unsigned long *p = addr + BIT_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG - 1);
+ unsigned long result = size;
unsigned long tmp;
if (offset >= size)
return size;
- size -= result;
+ size -= (offset & ~(BITS_PER_LONG - 1));
offset %= BITS_PER_LONG;
- if (!offset)
- goto aligned;
-
- tmp = __reverse_ulong((unsigned char *)p);
- tmp &= ~0UL >> offset;
-
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp)
- goto found_middle;
-
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- p++;
-aligned:
- while (size & ~(BITS_PER_LONG-1)) {
+
+ while (1) {
+ if (*p == 0)
+ goto pass;
+
tmp = __reverse_ulong((unsigned char *)p);
+
+ tmp &= ~0UL >> offset;
+ if (size < BITS_PER_LONG)
+ tmp &= (~0UL << (BITS_PER_LONG - size));
if (tmp)
- goto found_middle;
- result += BITS_PER_LONG;
+ goto found;
+pass:
+ if (size <= BITS_PER_LONG)
+ break;
size -= BITS_PER_LONG;
+ offset = 0;
p++;
}
- if (!size)
- return result;
-
- tmp = __reverse_ulong((unsigned char *)p);
-found_first:
- tmp &= (~0UL << (BITS_PER_LONG - size));
- if (!tmp) /* Are any bits set? */
- return result + size; /* Nope. */
-found_middle:
- return result + __reverse_ffs(tmp);
+ return result;
+found:
+ return result - size + __reverse_ffs(tmp);
}
static unsigned long __find_rev_next_zero_bit(const unsigned long *addr,
unsigned long size, unsigned long offset)
{
const unsigned long *p = addr + BIT_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG - 1);
+ unsigned long result = size;
unsigned long tmp;
if (offset >= size)
return size;
- size -= result;
+ size -= (offset & ~(BITS_PER_LONG - 1));
offset %= BITS_PER_LONG;
- if (!offset)
- goto aligned;
-
- tmp = __reverse_ulong((unsigned char *)p);
- tmp |= ~((~0UL << offset) >> offset);
-
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp != ~0UL)
- goto found_middle;
-
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- p++;
-aligned:
- while (size & ~(BITS_PER_LONG - 1)) {
+
+ while (1) {
+ if (*p == ~0UL)
+ goto pass;
+
tmp = __reverse_ulong((unsigned char *)p);
+
+ if (offset)
+ tmp |= ~0UL << (BITS_PER_LONG - offset);
+ if (size < BITS_PER_LONG)
+ tmp |= ~0UL >> size;
if (tmp != ~0UL)
- goto found_middle;
- result += BITS_PER_LONG;
+ goto found;
+pass:
+ if (size <= BITS_PER_LONG)
+ break;
size -= BITS_PER_LONG;
+ offset = 0;
p++;
}
- if (!size)
- return result;
-
- tmp = __reverse_ulong((unsigned char *)p);
-found_first:
- tmp |= ~(~0UL << (BITS_PER_LONG - size));
- if (tmp == ~0UL) /* Are any bits zero? */
- return result + size; /* Nope. */
-found_middle:
- return result + __reverse_ffz(tmp);
+ return result;
+found:
+ return result - size + __reverse_ffz(tmp);
}
void register_inmem_page(struct inode *inode, struct page *page)
@@ -233,7 +213,7 @@ int commit_inmem_pages(struct inode *inode, bool abort)
* inode becomes free by iget_locked in f2fs_iget.
*/
if (!abort) {
- f2fs_balance_fs(sbi);
+ f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
}
@@ -257,6 +237,7 @@ int commit_inmem_pages(struct inode *inode, bool abort)
submit_bio = true;
}
} else {
+ ClearPageUptodate(cur->page);
trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP);
}
set_page_private(cur->page, 0);
@@ -281,8 +262,10 @@ int commit_inmem_pages(struct inode *inode, bool abort)
* This function balances dirty node and dentry pages.
* In addition, it controls garbage collection.
*/
-void f2fs_balance_fs(struct f2fs_sb_info *sbi)
+void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
{
+ if (!need)
+ return;
/*
* We should do GC or end up with checkpoint, if there are so many dirty
* dir/node pages without enough free segments.
@@ -310,8 +293,12 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
if (!available_free_memory(sbi, NAT_ENTRIES) ||
excess_prefree_segs(sbi) ||
!available_free_memory(sbi, INO_ENTRIES) ||
- jiffies > sbi->cp_expires)
+ (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) {
+ if (test_opt(sbi, DATA_FLUSH))
+ sync_dirty_inodes(sbi, FILE_INODE);
f2fs_sync_fs(sbi->sb, true);
+ stat_inc_bg_cp_count(sbi->stat_info);
+ }
}
static int issue_flush_thread(void *data)
@@ -1134,6 +1121,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
__u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
unsigned int start_segno, end_segno;
struct cp_control cpc;
+ int err = 0;
if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
return -EINVAL;
@@ -1164,12 +1152,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
sbi->segs_per_sec) - 1, end_segno);
mutex_lock(&sbi->gc_mutex);
- write_checkpoint(sbi, &cpc);
+ err = write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex);
}
out:
range->len = F2FS_BLK_TO_BYTES(cpc.trimmed);
- return 0;
+ return err;
}
static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
@@ -1749,13 +1737,13 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
if (le32_to_cpu(nid_in_journal(sum, i)) == val)
return i;
}
- if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES)
+ if (alloc && __has_cursum_space(sum, 1, NAT_JOURNAL))
return update_nats_in_cursum(sum, 1);
} else if (type == SIT_JOURNAL) {
for (i = 0; i < sits_in_cursum(sum); i++)
if (le32_to_cpu(segno_in_journal(sum, i)) == val)
return i;
- if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES)
+ if (alloc && __has_cursum_space(sum, 1, SIT_JOURNAL))
return update_sits_in_cursum(sum, 1);
}
return -1;
diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c
index da0d8e0b55a5..93606f281bf9 100644
--- a/fs/f2fs/shrinker.c
+++ b/fs/f2fs/shrinker.c
@@ -32,7 +32,8 @@ static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi)
{
- return sbi->total_ext_tree + atomic_read(&sbi->total_ext_node);
+ return atomic_read(&sbi->total_zombie_tree) +
+ atomic_read(&sbi->total_ext_node);
}
unsigned long f2fs_shrink_count(struct shrinker *shrink,
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 3a65e0132352..6134832baaaf 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -67,6 +67,7 @@ enum {
Opt_extent_cache,
Opt_noextent_cache,
Opt_noinline_data,
+ Opt_data_flush,
Opt_err,
};
@@ -91,6 +92,7 @@ static match_table_t f2fs_tokens = {
{Opt_extent_cache, "extent_cache"},
{Opt_noextent_cache, "noextent_cache"},
{Opt_noinline_data, "noinline_data"},
+ {Opt_data_flush, "data_flush"},
{Opt_err, NULL},
};
@@ -216,7 +218,8 @@ F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
-F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, cp_interval);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = {
@@ -235,6 +238,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(ram_thresh),
ATTR_LIST(ra_nid_pages),
ATTR_LIST(cp_interval),
+ ATTR_LIST(idle_interval),
NULL,
};
@@ -406,6 +410,9 @@ static int parse_options(struct super_block *sb, char *options)
case Opt_noinline_data:
clear_opt(sbi, INLINE_DATA);
break;
+ case Opt_data_flush:
+ set_opt(sbi, DATA_FLUSH);
+ break;
default:
f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing value",
@@ -432,6 +439,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
fi->i_current_depth = 1;
fi->i_advise = 0;
init_rwsem(&fi->i_sem);
+ INIT_LIST_HEAD(&fi->dirty_list);
INIT_LIST_HEAD(&fi->inmem_pages);
mutex_init(&fi->inmem_lock);
@@ -548,7 +556,7 @@ static void f2fs_put_super(struct super_block *sb)
* normally superblock is clean, so we need to release this.
* In addition, EIO will skip do checkpoint, we need this as well.
*/
- release_dirty_inode(sbi);
+ release_ino_entry(sbi);
release_discard_addrs(sbi);
f2fs_leave_shrinker(sbi);
@@ -566,13 +574,14 @@ static void f2fs_put_super(struct super_block *sb)
wait_for_completion(&sbi->s_kobj_unregister);
sb->s_fs_info = NULL;
- brelse(sbi->raw_super_buf);
+ kfree(sbi->raw_super);
kfree(sbi);
}
int f2fs_sync_fs(struct super_block *sb, int sync)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
+ int err = 0;
trace_f2fs_sync_fs(sb, sync);
@@ -582,14 +591,12 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
cpc.reason = __get_cp_reason(sbi);
mutex_lock(&sbi->gc_mutex);
- write_checkpoint(sbi, &cpc);
+ err = write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex);
- } else {
- f2fs_balance_fs(sbi);
}
f2fs_trace_ios(NULL, 1);
- return 0;
+ return err;
}
static int f2fs_freeze(struct super_block *sb)
@@ -686,6 +693,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",extent_cache");
else
seq_puts(seq, ",noextent_cache");
+ if (test_opt(sbi, DATA_FLUSH))
+ seq_puts(seq, ",data_flush");
seq_printf(seq, ",active_logs=%u", sbi->active_logs);
return 0;
@@ -898,7 +907,7 @@ static const struct export_operations f2fs_export_ops = {
.get_parent = f2fs_get_parent,
};
-static loff_t max_file_size(unsigned bits)
+static loff_t max_file_blocks(void)
{
loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS);
loff_t leaf_count = ADDRS_PER_BLOCK;
@@ -914,10 +923,82 @@ static loff_t max_file_size(unsigned bits)
leaf_count *= NIDS_PER_BLOCK;
result += leaf_count;
- result <<= bits;
return result;
}
+static inline bool sanity_check_area_boundary(struct super_block *sb,
+ struct f2fs_super_block *raw_super)
+{
+ u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
+ u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
+ u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
+ u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr);
+ u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
+ u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
+ u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt);
+ u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit);
+ u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat);
+ u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa);
+ u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
+ u32 segment_count = le32_to_cpu(raw_super->segment_count);
+ u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+
+ if (segment0_blkaddr != cp_blkaddr) {
+ f2fs_msg(sb, KERN_INFO,
+ "Mismatch start address, segment0(%u) cp_blkaddr(%u)",
+ segment0_blkaddr, cp_blkaddr);
+ return true;
+ }
+
+ if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) !=
+ sit_blkaddr) {
+ f2fs_msg(sb, KERN_INFO,
+ "Wrong CP boundary, start(%u) end(%u) blocks(%u)",
+ cp_blkaddr, sit_blkaddr,
+ segment_count_ckpt << log_blocks_per_seg);
+ return true;
+ }
+
+ if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) !=
+ nat_blkaddr) {
+ f2fs_msg(sb, KERN_INFO,
+ "Wrong SIT boundary, start(%u) end(%u) blocks(%u)",
+ sit_blkaddr, nat_blkaddr,
+ segment_count_sit << log_blocks_per_seg);
+ return true;
+ }
+
+ if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) !=
+ ssa_blkaddr) {
+ f2fs_msg(sb, KERN_INFO,
+ "Wrong NAT boundary, start(%u) end(%u) blocks(%u)",
+ nat_blkaddr, ssa_blkaddr,
+ segment_count_nat << log_blocks_per_seg);
+ return true;
+ }
+
+ if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) !=
+ main_blkaddr) {
+ f2fs_msg(sb, KERN_INFO,
+ "Wrong SSA boundary, start(%u) end(%u) blocks(%u)",
+ ssa_blkaddr, main_blkaddr,
+ segment_count_ssa << log_blocks_per_seg);
+ return true;
+ }
+
+ if (main_blkaddr + (segment_count_main << log_blocks_per_seg) !=
+ segment0_blkaddr + (segment_count << log_blocks_per_seg)) {
+ f2fs_msg(sb, KERN_INFO,
+ "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)",
+ main_blkaddr,
+ segment0_blkaddr + (segment_count << log_blocks_per_seg),
+ segment_count_main << log_blocks_per_seg);
+ return true;
+ }
+
+ return false;
+}
+
static int sanity_check_raw_super(struct super_block *sb,
struct f2fs_super_block *raw_super)
{
@@ -947,6 +1028,14 @@ static int sanity_check_raw_super(struct super_block *sb,
return 1;
}
+ /* check log blocks per segment */
+ if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
+ f2fs_msg(sb, KERN_INFO,
+ "Invalid log blocks per segment (%u)\n",
+ le32_to_cpu(raw_super->log_blocks_per_seg));
+ return 1;
+ }
+
/* Currently, support 512/1024/2048/4096 bytes sector size */
if (le32_to_cpu(raw_super->log_sectorsize) >
F2FS_MAX_LOG_SECTOR_SIZE ||
@@ -965,6 +1054,23 @@ static int sanity_check_raw_super(struct super_block *sb,
le32_to_cpu(raw_super->log_sectorsize));
return 1;
}
+
+ /* check reserved ino info */
+ if (le32_to_cpu(raw_super->node_ino) != 1 ||
+ le32_to_cpu(raw_super->meta_ino) != 2 ||
+ le32_to_cpu(raw_super->root_ino) != 3) {
+ f2fs_msg(sb, KERN_INFO,
+ "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
+ le32_to_cpu(raw_super->node_ino),
+ le32_to_cpu(raw_super->meta_ino),
+ le32_to_cpu(raw_super->root_ino));
+ return 1;
+ }
+
+ /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
+ if (sanity_check_area_boundary(sb, raw_super))
+ return 1;
+
return 0;
}
@@ -1018,7 +1124,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
atomic_set(&sbi->nr_pages[i], 0);
sbi->dir_level = DEF_DIR_LEVEL;
- sbi->cp_interval = DEF_CP_INTERVAL;
+ sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
+ sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL;
clear_sbi_flag(sbi, SBI_NEED_FSCK);
INIT_LIST_HEAD(&sbi->s_list);
@@ -1032,111 +1139,114 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
*/
static int read_raw_super_block(struct super_block *sb,
struct f2fs_super_block **raw_super,
- struct buffer_head **raw_super_buf,
- int *recovery)
+ int *valid_super_block, int *recovery)
{
int block = 0;
- struct buffer_head *buffer;
- struct f2fs_super_block *super;
+ struct buffer_head *bh;
+ struct f2fs_super_block *super, *buf;
int err = 0;
+ super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
+ if (!super)
+ return -ENOMEM;
retry:
- buffer = sb_bread(sb, block);
- if (!buffer) {
+ bh = sb_bread(sb, block);
+ if (!bh) {
*recovery = 1;
f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
block + 1);
- if (block == 0) {
- block++;
- goto retry;
- } else {
- err = -EIO;
- goto out;
- }
+ err = -EIO;
+ goto next;
}
- super = (struct f2fs_super_block *)
- ((char *)(buffer)->b_data + F2FS_SUPER_OFFSET);
+ buf = (struct f2fs_super_block *)(bh->b_data + F2FS_SUPER_OFFSET);
/* sanity checking of raw super */
- if (sanity_check_raw_super(sb, super)) {
- brelse(buffer);
+ if (sanity_check_raw_super(sb, buf)) {
+ brelse(bh);
*recovery = 1;
f2fs_msg(sb, KERN_ERR,
"Can't find valid F2FS filesystem in %dth superblock",
block + 1);
- if (block == 0) {
- block++;
- goto retry;
- } else {
- err = -EINVAL;
- goto out;
- }
+ err = -EINVAL;
+ goto next;
}
if (!*raw_super) {
- *raw_super_buf = buffer;
+ memcpy(super, buf, sizeof(*super));
+ *valid_super_block = block;
*raw_super = super;
- } else {
- /* already have a valid superblock */
- brelse(buffer);
}
+ brelse(bh);
+next:
/* check the validity of the second superblock */
if (block == 0) {
block++;
goto retry;
}
-out:
/* No valid superblock */
- if (!*raw_super)
+ if (!*raw_super) {
+ kfree(super);
return err;
+ }
return 0;
}
+static int __f2fs_commit_super(struct f2fs_sb_info *sbi, int block)
+{
+ struct f2fs_super_block *super = F2FS_RAW_SUPER(sbi);
+ struct buffer_head *bh;
+ int err;
+
+ bh = sb_getblk(sbi->sb, block);
+ if (!bh)
+ return -EIO;
+
+ lock_buffer(bh);
+ memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
+ set_buffer_uptodate(bh);
+ set_buffer_dirty(bh);
+ unlock_buffer(bh);
+
+ /* it's rare case, we can do fua all the time */
+ err = __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
+ brelse(bh);
+
+ return err;
+}
+
int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
{
- struct buffer_head *sbh = sbi->raw_super_buf;
- sector_t block = sbh->b_blocknr;
int err;
/* write back-up superblock first */
- sbh->b_blocknr = block ? 0 : 1;
- mark_buffer_dirty(sbh);
- err = sync_dirty_buffer(sbh);
-
- sbh->b_blocknr = block;
+ err = __f2fs_commit_super(sbi, sbi->valid_super_block ? 0 : 1);
/* if we are in recovery path, skip writing valid superblock */
if (recover || err)
- goto out;
+ return err;
/* write current valid superblock */
- mark_buffer_dirty(sbh);
- err = sync_dirty_buffer(sbh);
-out:
- clear_buffer_write_io_error(sbh);
- set_buffer_uptodate(sbh);
- return err;
+ return __f2fs_commit_super(sbi, sbi->valid_super_block);
}
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
{
struct f2fs_sb_info *sbi;
struct f2fs_super_block *raw_super;
- struct buffer_head *raw_super_buf;
struct inode *root;
long err;
bool retry = true, need_fsck = false;
char *options = NULL;
- int recovery, i;
+ int recovery, i, valid_super_block;
try_onemore:
err = -EINVAL;
raw_super = NULL;
- raw_super_buf = NULL;
+ valid_super_block = -1;
recovery = 0;
/* allocate memory for f2fs-specific super block info */
@@ -1150,7 +1260,8 @@ try_onemore:
goto free_sbi;
}
- err = read_raw_super_block(sb, &raw_super, &raw_super_buf, &recovery);
+ err = read_raw_super_block(sb, &raw_super, &valid_super_block,
+ &recovery);
if (err)
goto free_sbi;
@@ -1167,7 +1278,9 @@ try_onemore:
if (err)
goto free_options;
- sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize));
+ sbi->max_file_blocks = max_file_blocks();
+ sb->s_maxbytes = sbi->max_file_blocks <<
+ le32_to_cpu(raw_super->log_blocksize);
sb->s_max_links = F2FS_LINK_MAX;
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
@@ -1183,7 +1296,7 @@ try_onemore:
/* init f2fs-specific super block info */
sbi->sb = sb;
sbi->raw_super = raw_super;
- sbi->raw_super_buf = raw_super_buf;
+ sbi->valid_super_block = valid_super_block;
mutex_init(&sbi->gc_mutex);
mutex_init(&sbi->writepages);
mutex_init(&sbi->cp_mutex);
@@ -1236,8 +1349,10 @@ try_onemore:
le64_to_cpu(sbi->ckpt->valid_block_count);
sbi->last_valid_block_count = sbi->total_valid_block_count;
sbi->alloc_valid_block_count = 0;
- INIT_LIST_HEAD(&sbi->dir_inode_list);
- spin_lock_init(&sbi->dir_inode_lock);
+ for (i = 0; i < NR_INODE_TYPE; i++) {
+ INIT_LIST_HEAD(&sbi->inode_list[i]);
+ spin_lock_init(&sbi->inode_lock[i]);
+ }
init_extent_cache_info(sbi);
@@ -1355,12 +1470,14 @@ try_onemore:
f2fs_commit_super(sbi, true);
}
- sbi->cp_expires = round_jiffies_up(jiffies);
-
+ f2fs_update_time(sbi, CP_TIME);
+ f2fs_update_time(sbi, REQ_TIME);
return 0;
free_kobj:
kobject_del(&sbi->s_kobj);
+ kobject_put(&sbi->s_kobj);
+ wait_for_completion(&sbi->s_kobj_unregister);
free_proc:
if (sbi->s_proc) {
remove_proc_entry("segment_info", sbi->s_proc);
@@ -1387,7 +1504,7 @@ free_meta_inode:
free_options:
kfree(options);
free_sb_buf:
- brelse(raw_super_buf);
+ kfree(raw_super);
free_sbi:
kfree(sbi);
@@ -1424,8 +1541,9 @@ MODULE_ALIAS_FS("f2fs");
static int __init init_inodecache(void)
{
- f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache",
- sizeof(struct f2fs_inode_info));
+ f2fs_inode_cachep = kmem_cache_create("f2fs_inode_cache",
+ sizeof(struct f2fs_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT, NULL);
if (!f2fs_inode_cachep)
return -ENOMEM;
return 0;
@@ -1478,10 +1596,14 @@ static int __init init_f2fs_fs(void)
err = register_filesystem(&f2fs_fs_type);
if (err)
goto free_shrinker;
- f2fs_create_root_stats();
+ err = f2fs_create_root_stats();
+ if (err)
+ goto free_filesystem;
f2fs_proc_root = proc_mkdir("fs/f2fs", NULL);
return 0;
+free_filesystem:
+ unregister_filesystem(&f2fs_fs_type);
free_shrinker:
unregister_shrinker(&f2fs_shrinker_info);
free_crypto:
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 036952a945fa..10f1e784fa23 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -571,7 +571,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
if (ipage)
return __f2fs_setxattr(inode, index, name, value,
size, ipage, flags);
- f2fs_balance_fs(sbi);
+ f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
/* protect xattr_ver */
@@ -580,5 +580,6 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
up_write(&F2FS_I(inode)->i_sem);
f2fs_unlock_op(sbi);
+ f2fs_update_time(sbi, REQ_TIME);
return err;
}
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 509411dd3698..6aece96df19f 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -677,7 +677,7 @@ static int __init fat_init_inodecache(void)
fat_inode_cachep = kmem_cache_create("fat_inode_cache",
sizeof(struct msdos_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (fat_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/file.c b/fs/file.c
index 1aed0add16a2..1fbc5c0555a9 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -37,11 +37,12 @@ static void *alloc_fdmem(size_t size)
* vmalloc() if the allocation size will be considered "large" by the VM.
*/
if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
- void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY);
+ void *data = kmalloc(size, GFP_KERNEL_ACCOUNT |
+ __GFP_NOWARN | __GFP_NORETRY);
if (data != NULL)
return data;
}
- return vmalloc(size);
+ return __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_HIGHMEM, PAGE_KERNEL);
}
static void __free_fdtable(struct fdtable *fdt)
@@ -126,7 +127,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
if (unlikely(nr > sysctl_nr_open))
nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
- fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
+ fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL_ACCOUNT);
if (!fdt)
goto out;
fdt->max_fds = nr;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 023f6a1f23cd..6915c950e6e8 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -677,9 +677,7 @@ void wbc_account_io(struct writeback_control *wbc, struct page *page,
if (!wbc->wb)
return;
- rcu_read_lock();
id = mem_cgroup_css_from_page(page)->id;
- rcu_read_unlock();
if (id == wbc->wb_id) {
wbc->wb_bytes += bytes;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 2913db2a5b99..4d69d5c0bedc 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1255,8 +1255,8 @@ static int __init fuse_fs_init(void)
int err;
fuse_inode_cachep = kmem_cache_create("fuse_inode",
- sizeof(struct fuse_inode),
- 0, SLAB_HWCACHE_ALIGN,
+ sizeof(struct fuse_inode), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT,
fuse_inode_init_once);
err = -ENOMEM;
if (!fuse_inode_cachep)
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index f348cfb6b69a..437fd73e381e 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -13,6 +13,7 @@
#include <linux/gfs2_ondisk.h>
#include <linux/bio.h>
#include <linux/posix_acl.h>
+#include <linux/security.h>
#include "gfs2.h"
#include "incore.h"
@@ -262,6 +263,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
if (ip) {
set_bit(GIF_INVALID, &ip->i_flags);
forget_all_cached_acls(&ip->i_inode);
+ security_inode_invalidate_secctx(&ip->i_inode);
gfs2_dir_hash_inval(ip);
}
}
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 1d709d496364..f99f8e94de3f 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -114,7 +114,8 @@ static int __init init_gfs2_fs(void)
gfs2_inode_cachep = kmem_cache_create("gfs2_inode",
sizeof(struct gfs2_inode),
0, SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD,
+ SLAB_MEM_SPREAD|
+ SLAB_ACCOUNT,
gfs2_init_inode_once);
if (!gfs2_inode_cachep)
goto fail;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 4574fdd3d421..1ca95c232bb5 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -483,8 +483,8 @@ static int __init init_hfs_fs(void)
int err;
hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
- sizeof(struct hfs_inode_info), 0, SLAB_HWCACHE_ALIGN,
- hfs_init_once);
+ sizeof(struct hfs_inode_info), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, hfs_init_once);
if (!hfs_inode_cachep)
return -ENOMEM;
err = register_filesystem(&hfs_fs_type);
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 7302d96ae8bf..5d54490a136d 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -663,7 +663,7 @@ static int __init init_hfsplus_fs(void)
int err;
hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
- HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN,
+ HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT,
hfsplus_init_once);
if (!hfsplus_inode_cachep)
return -ENOMEM;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index f49be23e78aa..cfaa18c7a337 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -223,7 +223,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
{
struct hostfs_inode_info *hi;
- hi = kmalloc(sizeof(*hi), GFP_KERNEL);
+ hi = kmalloc(sizeof(*hi), GFP_KERNEL_ACCOUNT);
if (hi == NULL)
return NULL;
hi->fd = -1;
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index a561591896bd..458cf463047b 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -261,7 +261,7 @@ static int init_inodecache(void)
hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
sizeof(struct hpfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (hpfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index d8f51ee8126b..8bbf7f3e2a27 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -4,11 +4,11 @@
* Nadia Yvette Chambers, 2002
*
* Copyright (C) 2002 Linus Torvalds.
+ * License: GPL
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
#include <linux/thread_info.h>
#include <asm/current.h>
#include <linux/sched.h> /* remove ASAP */
@@ -324,11 +324,48 @@ static void remove_huge_page(struct page *page)
delete_from_page_cache(page);
}
+static void
+hugetlb_vmdelete_list(struct rb_root *root, pgoff_t start, pgoff_t end)
+{
+ struct vm_area_struct *vma;
+
+ /*
+ * end == 0 indicates that the entire range after
+ * start should be unmapped.
+ */
+ vma_interval_tree_foreach(vma, root, start, end ? end : ULONG_MAX) {
+ unsigned long v_offset;
+ unsigned long v_end;
+
+ /*
+ * Can the expression below overflow on 32-bit arches?
+ * No, because the interval tree returns us only those vmas
+ * which overlap the truncated area starting at pgoff,
+ * and no vma on a 32-bit arch can span beyond the 4GB.
+ */
+ if (vma->vm_pgoff < start)
+ v_offset = (start - vma->vm_pgoff) << PAGE_SHIFT;
+ else
+ v_offset = 0;
+
+ if (!end)
+ v_end = vma->vm_end;
+ else {
+ v_end = ((end - vma->vm_pgoff) << PAGE_SHIFT)
+ + vma->vm_start;
+ if (v_end > vma->vm_end)
+ v_end = vma->vm_end;
+ }
+
+ unmap_hugepage_range(vma, vma->vm_start + v_offset, v_end,
+ NULL);
+ }
+}
/*
* remove_inode_hugepages handles two distinct cases: truncation and hole
* punch. There are subtle differences in operation for each case.
-
+ *
* truncation is indicated by end of range being LLONG_MAX
* In this case, we first scan the range and release found pages.
* After releasing pages, hugetlb_unreserve_pages cleans up region/reserv
@@ -379,6 +416,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
for (i = 0; i < pagevec_count(&pvec); ++i) {
struct page *page = pvec.pages[i];
+ bool rsv_on_error;
u32 hash;
/*
@@ -395,37 +433,43 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
mapping, next, 0);
mutex_lock(&hugetlb_fault_mutex_table[hash]);
- lock_page(page);
- if (likely(!page_mapped(page))) {
- bool rsv_on_error = !PagePrivate(page);
- /*
- * We must free the huge page and remove
- * from page cache (remove_huge_page) BEFORE
- * removing the region/reserve map
- * (hugetlb_unreserve_pages). In rare out
- * of memory conditions, removal of the
- * region/reserve map could fail. Before
- * free'ing the page, note PagePrivate which
- * is used in case of error.
- */
- remove_huge_page(page);
- freed++;
- if (!truncate_op) {
- if (unlikely(hugetlb_unreserve_pages(
- inode, next,
- next + 1, 1)))
- hugetlb_fix_reserve_counts(
- inode, rsv_on_error);
- }
- } else {
- /*
- * If page is mapped, it was faulted in after
- * being unmapped. It indicates a race between
- * hole punch and page fault. Do nothing in
- * this case. Getting here in a truncate
- * operation is a bug.
- */
+ /*
+ * If page is mapped, it was faulted in after being
+ * unmapped in caller. Unmap (again) now after taking
+ * the fault mutex. The mutex will prevent faults
+ * until we finish removing the page.
+ *
+ * This race can only happen in the hole punch case.
+ * Getting here in a truncate operation is a bug.
+ */
+ if (unlikely(page_mapped(page))) {
BUG_ON(truncate_op);
+
+ i_mmap_lock_write(mapping);
+ hugetlb_vmdelete_list(&mapping->i_mmap,
+ next * pages_per_huge_page(h),
+ (next + 1) * pages_per_huge_page(h));
+ i_mmap_unlock_write(mapping);
+ }
+
+ lock_page(page);
+ /*
+ * We must free the huge page and remove from page
+ * cache (remove_huge_page) BEFORE removing the
+ * region/reserve map (hugetlb_unreserve_pages). In
+ * rare out of memory conditions, removal of the
+ * region/reserve map could fail. Before free'ing
+ * the page, note PagePrivate which is used in case
+ * of error.
+ */
+ rsv_on_error = !PagePrivate(page);
+ remove_huge_page(page);
+ freed++;
+ if (!truncate_op) {
+ if (unlikely(hugetlb_unreserve_pages(inode,
+ next, next + 1, 1)))
+ hugetlb_fix_reserve_counts(inode,
+ rsv_on_error);
}
unlock_page(page);
@@ -452,41 +496,6 @@ static void hugetlbfs_evict_inode(struct inode *inode)
clear_inode(inode);
}
-static inline void
-hugetlb_vmdelete_list(struct rb_root *root, pgoff_t start, pgoff_t end)
-{
- struct vm_area_struct *vma;
-
- /*
- * end == 0 indicates that the entire range after
- * start should be unmapped.
- */
- vma_interval_tree_foreach(vma, root, start, end ? end : ULONG_MAX) {
- unsigned long v_offset;
-
- /*
- * Can the expression below overflow on 32-bit arches?
- * No, because the interval tree returns us only those vmas
- * which overlap the truncated area starting at pgoff,
- * and no vma on a 32-bit arch can span beyond the 4GB.
- */
- if (vma->vm_pgoff < start)
- v_offset = (start - vma->vm_pgoff) << PAGE_SHIFT;
- else
- v_offset = 0;
-
- if (end) {
- end = ((end - start) << PAGE_SHIFT) +
- vma->vm_start + v_offset;
- if (end > vma->vm_end)
- end = vma->vm_end;
- } else
- end = vma->vm_end;
-
- unmap_hugepage_range(vma, vma->vm_start + v_offset, end, NULL);
- }
-}
-
static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
{
pgoff_t pgoff;
@@ -708,7 +717,7 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,
/*
* Hugetlbfs is not reclaimable; therefore its i_mmap_rwsem will never
* be taken from reclaim -- unlike regular filesystems. This needs an
- * annotation because huge_pmd_share() does an allocation under
+ * annotation because huge_pmd_share() does an allocation under hugetlb's
* i_mmap_rwsem.
*/
static struct lock_class_key hugetlbfs_i_mmap_rwsem_key;
@@ -738,7 +747,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
/*
* The policy is initialized here even if we are creating a
* private inode because initialization simply creates an
- * an empty rb tree and calls spin_lock_init(), later when we
+ * an empty rb tree and calls rwlock_init(), later when we
* call mpol_free_shared_policy() it will just return because
* the rb tree will still be empty.
*/
@@ -1202,7 +1211,6 @@ static struct file_system_type hugetlbfs_fs_type = {
.mount = hugetlbfs_mount,
.kill_sb = kill_litter_super,
};
-MODULE_ALIAS_FS("hugetlbfs");
static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE];
@@ -1322,7 +1330,7 @@ static int __init init_hugetlbfs_fs(void)
error = -ENOMEM;
hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache",
sizeof(struct hugetlbfs_inode_info),
- 0, 0, init_once);
+ 0, SLAB_ACCOUNT, init_once);
if (hugetlbfs_inode_cachep == NULL)
goto out2;
@@ -1356,26 +1364,4 @@ static int __init init_hugetlbfs_fs(void)
out2:
return error;
}
-
-static void __exit exit_hugetlbfs_fs(void)
-{
- struct hstate *h;
- int i;
-
-
- /*
- * Make sure all delayed rcu free inodes are flushed before we
- * destroy cache.
- */
- rcu_barrier();
- kmem_cache_destroy(hugetlbfs_inode_cachep);
- i = 0;
- for_each_hstate(h)
- kern_unmount(hugetlbfs_vfsmount[i++]);
- unregister_filesystem(&hugetlbfs_fs_type);
-}
-
-module_init(init_hugetlbfs_fs)
-module_exit(exit_hugetlbfs_fs)
-
-MODULE_LICENSE("GPL");
+fs_initcall(init_hugetlbfs_fs)
diff --git a/fs/inode.c b/fs/inode.c
index 4230f66b7410..e491e54d2430 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1883,7 +1883,7 @@ void __init inode_init(void)
sizeof(struct inode),
0,
(SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
/* Hash may have been set up in inode_init_early */
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 61abdc4920da..bcd2d41b318a 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -94,7 +94,7 @@ static int __init init_inodecache(void)
isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
sizeof(struct iso_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (isofs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index d86c5e3176a1..bb080c272149 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -387,7 +387,7 @@ static int __init init_jffs2_fs(void)
jffs2_inode_cachep = kmem_cache_create("jffs2_i",
sizeof(struct jffs2_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
jffs2_i_init_once);
if (!jffs2_inode_cachep) {
pr_err("error: Failed to initialise inode cache\n");
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index f3a4857ff071..5a3da3f52908 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1153,7 +1153,7 @@ static struct jffs2_sb_info *work_to_sb(struct work_struct *work)
{
struct delayed_work *dwork;
- dwork = container_of(work, struct delayed_work, work);
+ dwork = to_delayed_work(work);
return container_of(dwork, struct jffs2_sb_info, wbuf_dwork);
}
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 8f9176caf098..900925b5eb8c 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -898,7 +898,7 @@ static int __init init_jfs_fs(void)
jfs_inode_cachep =
kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
- SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
init_once);
if (jfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 742bf4a230e8..821973853340 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -541,14 +541,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
if (!kn)
goto err_out1;
- /*
- * If the ino of the sysfs entry created for a kmem cache gets
- * allocated from an ida layer, which is accounted to the memcg that
- * owns the cache, the memcg will get pinned forever. So do not account
- * ino ida allocations.
- */
- ret = ida_simple_get(&root->ino_ida, 1, 0,
- GFP_KERNEL | __GFP_NOACCOUNT);
+ ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL);
if (ret < 0)
goto err_out2;
kn->ino = ret;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 5f31ebd96c06..154a107cd376 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -25,13 +25,17 @@
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/inetdevice.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/svc_xprt.h>
#include <net/ip.h>
+#include <net/addrconf.h>
+#include <net/ipv6.h>
#include <linux/lockd/lockd.h>
#include <linux/nfs.h>
@@ -44,7 +48,7 @@
static struct svc_program nlmsvc_program;
-struct nlmsvc_binding * nlmsvc_ops;
+const struct nlmsvc_binding *nlmsvc_ops;
EXPORT_SYMBOL_GPL(nlmsvc_ops);
static DEFINE_MUTEX(nlmsvc_mutex);
@@ -90,8 +94,7 @@ static unsigned long get_lockd_grace_period(void)
static void grace_ender(struct work_struct *grace)
{
- struct delayed_work *dwork = container_of(grace, struct delayed_work,
- work);
+ struct delayed_work *dwork = to_delayed_work(grace);
struct lockd_net *ln = container_of(dwork, struct lockd_net,
grace_period_end);
@@ -279,6 +282,68 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)
}
}
+static int lockd_inetaddr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+ struct sockaddr_in sin;
+
+ if (event != NETDEV_DOWN)
+ goto out;
+
+ if (nlmsvc_rqst) {
+ dprintk("lockd_inetaddr_event: removed %pI4\n",
+ &ifa->ifa_local);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ifa->ifa_local;
+ svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
+ (struct sockaddr *)&sin);
+ }
+
+out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block lockd_inetaddr_notifier = {
+ .notifier_call = lockd_inetaddr_event,
+};
+
+#if IS_ENABLED(CONFIG_IPV6)
+static int lockd_inet6addr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+ struct sockaddr_in6 sin6;
+
+ if (event != NETDEV_DOWN)
+ goto out;
+
+ if (nlmsvc_rqst) {
+ dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = ifa->addr;
+ svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
+ (struct sockaddr *)&sin6);
+ }
+
+out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block lockd_inet6addr_notifier = {
+ .notifier_call = lockd_inet6addr_event,
+};
+#endif
+
+static void lockd_svc_exit_thread(void)
+{
+ unregister_inetaddr_notifier(&lockd_inetaddr_notifier);
+#if IS_ENABLED(CONFIG_IPV6)
+ unregister_inet6addr_notifier(&lockd_inet6addr_notifier);
+#endif
+ svc_exit_thread(nlmsvc_rqst);
+}
+
static int lockd_start_svc(struct svc_serv *serv)
{
int error;
@@ -315,7 +380,7 @@ static int lockd_start_svc(struct svc_serv *serv)
return 0;
out_task:
- svc_exit_thread(nlmsvc_rqst);
+ lockd_svc_exit_thread();
nlmsvc_task = NULL;
out_rqst:
nlmsvc_rqst = NULL;
@@ -360,6 +425,10 @@ static struct svc_serv *lockd_create_svc(void)
printk(KERN_WARNING "lockd_up: create service failed\n");
return ERR_PTR(-ENOMEM);
}
+ register_inetaddr_notifier(&lockd_inetaddr_notifier);
+#if IS_ENABLED(CONFIG_IPV6)
+ register_inet6addr_notifier(&lockd_inet6addr_notifier);
+#endif
dprintk("lockd_up: service created\n");
return serv;
}
@@ -428,7 +497,7 @@ lockd_down(struct net *net)
}
kthread_stop(nlmsvc_task);
dprintk("lockd_down: service stopped\n");
- svc_exit_thread(nlmsvc_rqst);
+ lockd_svc_exit_thread();
dprintk("lockd_down: service destroyed\n");
nlmsvc_task = NULL;
nlmsvc_rqst = NULL;
diff --git a/fs/logfs/Kconfig b/fs/logfs/Kconfig
index 09ed066c0221..2b4503163930 100644
--- a/fs/logfs/Kconfig
+++ b/fs/logfs/Kconfig
@@ -1,6 +1,6 @@
config LOGFS
tristate "LogFS file system"
- depends on (MTD || BLOCK)
+ depends on MTD || (!MTD && BLOCK)
select ZLIB_INFLATE
select ZLIB_DEFLATE
select CRC32
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c
index 0fce46d62b9c..db9cfc598883 100644
--- a/fs/logfs/inode.c
+++ b/fs/logfs/inode.c
@@ -409,7 +409,8 @@ const struct super_operations logfs_super_operations = {
int logfs_init_inode_cache(void)
{
logfs_inode_cache = kmem_cache_create("logfs_inode_cache",
- sizeof(struct logfs_inode), 0, SLAB_RECLAIM_ACCOUNT,
+ sizeof(struct logfs_inode), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,
logfs_init_once);
if (!logfs_inode_cache)
return -ENOMEM;
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h
index 39d91f86cd35..27d040e35faa 100644
--- a/fs/logfs/logfs.h
+++ b/fs/logfs/logfs.h
@@ -485,7 +485,7 @@ static inline int logfs_get_sb_bdev(struct logfs_super *s,
#endif
/* dev_mtd.c */
-#ifdef CONFIG_MTD
+#if IS_ENABLED(CONFIG_MTD)
int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr);
#else
static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index cb1789ca1ee6..f975d667c539 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -91,7 +91,7 @@ static int __init init_inodecache(void)
minix_inode_cachep = kmem_cache_create("minix_inode_cache",
sizeof(struct minix_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (minix_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index ce1eb3f9dfe8..1af15fcbe57b 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -82,7 +82,7 @@ static int init_inodecache(void)
ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
sizeof(struct ncp_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (ncp_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 807eb6ef4f91..f0939d097406 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -83,8 +83,11 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
res = htonl(NFS4ERR_BADHANDLE);
inode = nfs_delegation_find_inode(cps->clp, &args->fh);
- if (inode == NULL)
+ if (inode == NULL) {
+ trace_nfs4_cb_recall(cps->clp, &args->fh, NULL,
+ &args->stateid, -ntohl(res));
goto out;
+ }
/* Set up a helper thread to actually return the delegation */
switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
case 0:
@@ -96,7 +99,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
default:
res = htonl(NFS4ERR_RESOURCE);
}
- trace_nfs4_recall_delegation(inode, -ntohl(res));
+ trace_nfs4_cb_recall(cps->clp, &args->fh, inode,
+ &args->stateid, -ntohl(res));
iput(inode);
out:
dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
@@ -160,6 +164,22 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
return lo;
}
+/*
+ * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing)
+ */
+static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo,
+ const nfs4_stateid *new)
+{
+ u32 oldseq, newseq;
+
+ oldseq = be32_to_cpu(lo->plh_stateid.seqid);
+ newseq = be32_to_cpu(new->seqid);
+
+ if (newseq > oldseq + 1)
+ return false;
+ return true;
+}
+
static u32 initiate_file_draining(struct nfs_client *clp,
struct cb_layoutrecallargs *args)
{
@@ -169,34 +189,52 @@ static u32 initiate_file_draining(struct nfs_client *clp,
LIST_HEAD(free_me_list);
lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid);
- if (!lo)
+ if (!lo) {
+ trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL,
+ &args->cbl_stateid, -rv);
goto out;
+ }
ino = lo->plh_inode;
spin_lock(&ino->i_lock);
+ if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) {
+ rv = NFS4ERR_DELAY;
+ goto unlock;
+ }
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
spin_unlock(&ino->i_lock);
pnfs_layoutcommit_inode(ino, false);
spin_lock(&ino->i_lock);
- if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
- pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
- &args->cbl_range)) {
+ /*
+ * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return)
+ */
+ if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
rv = NFS4ERR_DELAY;
goto unlock;
}
+ if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
+ &args->cbl_range)) {
+ rv = NFS4_OK;
+ goto unlock;
+ }
+
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
&args->cbl_range);
}
+ pnfs_mark_layout_returned_if_empty(lo);
unlock:
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&free_me_list);
+ /* Free all lsegs that are attached to commit buckets */
+ nfs_commit_inode(ino, 0);
pnfs_put_layout_hdr(lo);
- trace_nfs4_cb_layoutrecall_inode(clp, &args->cbl_fh, ino, -rv);
+ trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
+ &args->cbl_stateid, -rv);
iput(ino);
out:
return rv;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index ce5a21861074..c82a21228a34 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1894,15 +1894,14 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
attr.ia_mode = S_IFLNK | S_IRWXUGO;
attr.ia_valid = ATTR_MODE;
- page = alloc_page(GFP_HIGHUSER);
+ page = alloc_page(GFP_USER);
if (!page)
return -ENOMEM;
- kaddr = kmap_atomic(page);
+ kaddr = page_address(page);
memcpy(kaddr, symname, pathlen);
if (pathlen < PAGE_SIZE)
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
- kunmap_atomic(kaddr);
trace_nfs_symlink_enter(dir, dentry);
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
@@ -2432,6 +2431,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
}
EXPORT_SYMBOL_GPL(nfs_may_open);
+static int nfs_execute_ok(struct inode *inode, int mask)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ int ret;
+
+ if (mask & MAY_NOT_BLOCK)
+ ret = nfs_revalidate_inode_rcu(server, inode);
+ else
+ ret = nfs_revalidate_inode(server, inode);
+ if (ret == 0 && !execute_ok(inode))
+ ret = -EACCES;
+ return ret;
+}
+
int nfs_permission(struct inode *inode, int mask)
{
struct rpc_cred *cred;
@@ -2449,6 +2462,9 @@ int nfs_permission(struct inode *inode, int mask)
case S_IFLNK:
goto out;
case S_IFREG:
+ if ((mask & MAY_OPEN) &&
+ nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN))
+ return 0;
break;
case S_IFDIR:
/*
@@ -2481,8 +2497,8 @@ force_lookup:
res = PTR_ERR(cred);
}
out:
- if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
- res = -EACCES;
+ if (!res && (mask & MAY_EXEC))
+ res = nfs_execute_ok(inode, mask);
dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res);
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 4b1d08f56aba..7ab7ec9f4eed 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -117,12 +117,6 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
return atomic_dec_and_test(&dreq->io_count);
}
-void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq)
-{
- dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
-}
-EXPORT_SYMBOL_GPL(nfs_direct_set_resched_writes);
-
static void
nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr)
{
@@ -670,6 +664,10 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
req = nfs_list_entry(reqs.next);
nfs_direct_setup_mirroring(dreq, &desc, req);
+ if (desc.pg_error < 0) {
+ list_splice_init(&reqs, &failed);
+ goto out_failed;
+ }
list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
if (!nfs_pageio_add_request(&desc, req)) {
@@ -677,13 +675,17 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
nfs_list_add_request(req, &failed);
spin_lock(cinfo.lock);
dreq->flags = 0;
- dreq->error = -EIO;
+ if (desc.pg_error < 0)
+ dreq->error = desc.pg_error;
+ else
+ dreq->error = -EIO;
spin_unlock(cinfo.lock);
}
nfs_release_request(req);
}
nfs_pageio_complete(&desc);
+out_failed:
while (!list_empty(&failed)) {
req = nfs_list_entry(failed.next);
nfs_list_remove_request(req);
@@ -727,14 +729,20 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
nfs_direct_write_complete(dreq, data->inode);
}
-static void nfs_direct_error_cleanup(struct nfs_inode *nfsi)
+static void nfs_direct_resched_write(struct nfs_commit_info *cinfo,
+ struct nfs_page *req)
{
- /* There is no lock to clear */
+ struct nfs_direct_req *dreq = cinfo->dreq;
+
+ spin_lock(&dreq->lock);
+ dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+ spin_unlock(&dreq->lock);
+ nfs_mark_request_commit(req, NULL, cinfo, 0);
}
static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = {
.completion = nfs_direct_commit_complete,
- .error_cleanup = nfs_direct_error_cleanup,
+ .resched_write = nfs_direct_resched_write,
};
static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
@@ -839,10 +847,25 @@ static void nfs_write_sync_pgio_error(struct list_head *head)
}
}
+static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr)
+{
+ struct nfs_direct_req *dreq = hdr->dreq;
+
+ spin_lock(&dreq->lock);
+ if (dreq->error == 0) {
+ dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+ /* fake unstable write to let common nfs resend pages */
+ hdr->verf.committed = NFS_UNSTABLE;
+ hdr->good_bytes = hdr->args.count;
+ }
+ spin_unlock(&dreq->lock);
+}
+
static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
.error_cleanup = nfs_write_sync_pgio_error,
.init_hdr = nfs_direct_pgio_init,
.completion = nfs_direct_write_completion,
+ .reschedule_io = nfs_direct_write_reschedule_io,
};
@@ -900,6 +923,11 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
}
nfs_direct_setup_mirroring(dreq, &desc, req);
+ if (desc.pg_error < 0) {
+ nfs_free_request(req);
+ result = desc.pg_error;
+ break;
+ }
nfs_lock_request(req);
req->wb_index = pos >> PAGE_SHIFT;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 93e236429c5d..4ef8f5addcad 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -514,7 +514,7 @@ static void nfs_check_dirty_writeback(struct page *page,
* so it will not block due to pages that will shortly be freeable.
*/
nfsi = NFS_I(mapping->host);
- if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) {
+ if (atomic_read(&nfsi->commit_info.rpcs_out)) {
*writeback = true;
return;
}
@@ -545,7 +545,7 @@ static int nfs_launder_page(struct page *page)
inode->i_ino, (long long)page_offset(page));
nfs_fscache_wait_on_page_write(nfsi, page);
- return nfs_wb_page(inode, page);
+ return nfs_wb_launder_page(inode, page);
}
static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
@@ -756,7 +756,7 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
l_ctx = nfs_get_lock_context(nfs_file_open_context(filp));
if (!IS_ERR(l_ctx)) {
- status = nfs_iocounter_wait(&l_ctx->io_count);
+ status = nfs_iocounter_wait(l_ctx);
nfs_put_lock_context(l_ctx);
if (status < 0)
return status;
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c
index 02ec07973bc4..bb1f4e7a3270 100644
--- a/fs/nfs/filelayout/filelayout.c
+++ b/fs/nfs/filelayout/filelayout.c
@@ -202,6 +202,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
task->tk_status);
nfs4_mark_deviceid_unavailable(devid);
pnfs_error_mark_layout_for_return(inode, lseg);
+ pnfs_set_lo_fail(lseg);
rpc_wake_up(&tbl->slot_tbl_waitq);
/* fall through */
default:
@@ -883,13 +884,19 @@ static void
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req)
{
- if (!pgio->pg_lseg)
+ if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
0,
NFS4_MAX_UINT64,
IOMODE_READ,
GFP_KERNEL);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ return;
+ }
+ }
/* If no lseg, fall back to read through mds */
if (pgio->pg_lseg == NULL)
nfs_pageio_reset_read_mds(pgio);
@@ -902,13 +909,20 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_commit_info cinfo;
int status;
- if (!pgio->pg_lseg)
+ if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
0,
NFS4_MAX_UINT64,
IOMODE_RW,
GFP_NOFS);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ return;
+ }
+ }
+
/* If no lseg, fall back to write through mds */
if (pgio->pg_lseg == NULL)
goto out_mds;
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 03516c80855a..6594e9f903a0 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -145,7 +145,7 @@ static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1,
return false;
for (i = 0; i < m1->fh_versions_cnt; i++) {
bool found_fh = false;
- for (j = 0; j < m2->fh_versions_cnt; i++) {
+ for (j = 0; j < m2->fh_versions_cnt; j++) {
if (nfs_compare_fh(&m1->fh_versions[i],
&m2->fh_versions[j]) == 0) {
found_fh = true;
@@ -505,9 +505,17 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
}
p = xdr_inline_decode(&stream, 4);
- if (p)
- fls->flags = be32_to_cpup(p);
+ if (!p)
+ goto out_sort_mirrors;
+ fls->flags = be32_to_cpup(p);
+
+ p = xdr_inline_decode(&stream, 4);
+ if (!p)
+ goto out_sort_mirrors;
+ for (i=0; i < fls->mirror_array_cnt; i++)
+ fls->mirror_array[i]->report_interval = be32_to_cpup(p);
+out_sort_mirrors:
ff_layout_sort_mirrors(fls);
rc = ff_layout_check_layout(lgr);
if (rc)
@@ -603,7 +611,9 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror,
mirror->start_time = now;
if (ktime_equal(mirror->last_report_time, notime))
mirror->last_report_time = now;
- if (layoutstats_timer != 0)
+ if (mirror->report_interval != 0)
+ report_interval = (s64)mirror->report_interval * 1000LL;
+ else if (layoutstats_timer != 0)
report_interval = (s64)layoutstats_timer * 1000LL;
if (ktime_to_ms(ktime_sub(now, mirror->last_report_time)) >=
report_interval) {
@@ -785,13 +795,19 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
int ds_idx;
/* Use full layout for now */
- if (!pgio->pg_lseg)
+ if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
0,
NFS4_MAX_UINT64,
IOMODE_READ,
GFP_KERNEL);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ return;
+ }
+ }
/* If no lseg, fall back to read through mds */
if (pgio->pg_lseg == NULL)
goto out_mds;
@@ -825,13 +841,19 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
int i;
int status;
- if (!pgio->pg_lseg)
+ if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
0,
NFS4_MAX_UINT64,
IOMODE_RW,
GFP_NOFS);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ return;
+ }
+ }
/* If no lseg, fall back to write through mds */
if (pgio->pg_lseg == NULL)
goto out_mds;
@@ -867,18 +889,25 @@ static unsigned int
ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req)
{
- if (!pgio->pg_lseg)
+ if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
0,
NFS4_MAX_UINT64,
IOMODE_RW,
GFP_NOFS);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ goto out;
+ }
+ }
if (pgio->pg_lseg)
return FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg);
/* no lseg means that pnfs is not in use, so no mirroring here */
nfs_pageio_reset_write_mds(pgio);
+out:
return 1;
}
@@ -912,18 +941,7 @@ static void ff_layout_reset_write(struct nfs_pgio_header *hdr, bool retry_pnfs)
hdr->args.count,
(unsigned long long)hdr->args.offset);
- if (!hdr->dreq) {
- struct nfs_open_context *ctx;
-
- ctx = nfs_list_entry(hdr->pages.next)->wb_context;
- set_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
- hdr->completion_ops->error_cleanup(&hdr->pages);
- } else {
- nfs_direct_set_resched_writes(hdr->dreq);
- /* fake unstable write to let common nfs resend pages */
- hdr->verf.committed = NFS_UNSTABLE;
- hdr->good_bytes = hdr->args.count;
- }
+ hdr->completion_ops->reschedule_io(hdr);
return;
}
@@ -1101,7 +1119,7 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
return -NFS4ERR_RESET_TO_PNFS;
out_retry:
task->tk_status = 0;
- rpc_restart_call(task);
+ rpc_restart_call_prepare(task);
rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
return -EAGAIN;
}
@@ -1159,6 +1177,14 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
}
}
+ switch (status) {
+ case NFS4ERR_DELAY:
+ case NFS4ERR_GRACE:
+ return;
+ default:
+ break;
+ }
+
mirror = FF_LAYOUT_COMP(lseg, idx);
err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, offset, length, status, opnum,
@@ -1242,14 +1268,31 @@ ff_layout_reset_to_mds(struct pnfs_layout_segment *lseg, int idx)
return ff_layout_test_devid_unavailable(node);
}
-static int ff_layout_read_prepare_common(struct rpc_task *task,
- struct nfs_pgio_header *hdr)
+static void ff_layout_read_record_layoutstats_start(struct rpc_task *task,
+ struct nfs_pgio_header *hdr)
{
+ if (test_and_set_bit(NFS_IOHDR_STAT, &hdr->flags))
+ return;
nfs4_ff_layout_stat_io_start_read(hdr->inode,
FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
hdr->args.count,
task->tk_start);
+}
+
+static void ff_layout_read_record_layoutstats_done(struct rpc_task *task,
+ struct nfs_pgio_header *hdr)
+{
+ if (!test_and_clear_bit(NFS_IOHDR_STAT, &hdr->flags))
+ return;
+ nfs4_ff_layout_stat_io_end_read(task,
+ FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
+ hdr->args.count,
+ hdr->res.count);
+}
+static int ff_layout_read_prepare_common(struct rpc_task *task,
+ struct nfs_pgio_header *hdr)
+{
if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
rpc_exit(task, -EIO);
return -EIO;
@@ -1265,6 +1308,7 @@ static int ff_layout_read_prepare_common(struct rpc_task *task,
}
hdr->pgio_done_cb = ff_layout_read_done_cb;
+ ff_layout_read_record_layoutstats_start(task, hdr);
return 0;
}
@@ -1323,10 +1367,6 @@ static void ff_layout_read_call_done(struct rpc_task *task, void *data)
dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
- nfs4_ff_layout_stat_io_end_read(task,
- FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
- hdr->args.count, hdr->res.count);
-
if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
task->tk_status == 0) {
nfs4_sequence_done(task, &hdr->res.seq_res);
@@ -1341,10 +1381,20 @@ static void ff_layout_read_count_stats(struct rpc_task *task, void *data)
{
struct nfs_pgio_header *hdr = data;
+ ff_layout_read_record_layoutstats_done(task, hdr);
rpc_count_iostats_metrics(task,
&NFS_CLIENT(hdr->inode)->cl_metrics[NFSPROC4_CLNT_READ]);
}
+static void ff_layout_read_release(void *data)
+{
+ struct nfs_pgio_header *hdr = data;
+
+ ff_layout_read_record_layoutstats_done(&hdr->task, hdr);
+ pnfs_generic_rw_release(data);
+}
+
+
static int ff_layout_write_done_cb(struct rpc_task *task,
struct nfs_pgio_header *hdr)
{
@@ -1362,15 +1412,12 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
switch (err) {
case -NFS4ERR_RESET_TO_PNFS:
- pnfs_set_retry_layoutget(hdr->lseg->pls_layout);
ff_layout_reset_write(hdr, true);
return task->tk_status;
case -NFS4ERR_RESET_TO_MDS:
- pnfs_clear_retry_layoutget(hdr->lseg->pls_layout);
ff_layout_reset_write(hdr, false);
return task->tk_status;
case -EAGAIN:
- rpc_restart_call_prepare(task);
return -EAGAIN;
}
@@ -1402,11 +1449,9 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
switch (err) {
case -NFS4ERR_RESET_TO_PNFS:
- pnfs_set_retry_layoutget(data->lseg->pls_layout);
pnfs_generic_prepare_to_resend_writes(data);
return -EAGAIN;
case -NFS4ERR_RESET_TO_MDS:
- pnfs_clear_retry_layoutget(data->lseg->pls_layout);
pnfs_generic_prepare_to_resend_writes(data);
return -EAGAIN;
case -EAGAIN:
@@ -1421,14 +1466,31 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
return 0;
}
-static int ff_layout_write_prepare_common(struct rpc_task *task,
- struct nfs_pgio_header *hdr)
+static void ff_layout_write_record_layoutstats_start(struct rpc_task *task,
+ struct nfs_pgio_header *hdr)
{
+ if (test_and_set_bit(NFS_IOHDR_STAT, &hdr->flags))
+ return;
nfs4_ff_layout_stat_io_start_write(hdr->inode,
FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
hdr->args.count,
task->tk_start);
+}
+
+static void ff_layout_write_record_layoutstats_done(struct rpc_task *task,
+ struct nfs_pgio_header *hdr)
+{
+ if (!test_and_clear_bit(NFS_IOHDR_STAT, &hdr->flags))
+ return;
+ nfs4_ff_layout_stat_io_end_write(task,
+ FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
+ hdr->args.count, hdr->res.count,
+ hdr->res.verf->committed);
+}
+static int ff_layout_write_prepare_common(struct rpc_task *task,
+ struct nfs_pgio_header *hdr)
+{
if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
rpc_exit(task, -EIO);
return -EIO;
@@ -1445,6 +1507,7 @@ static int ff_layout_write_prepare_common(struct rpc_task *task,
return -EAGAIN;
}
+ ff_layout_write_record_layoutstats_start(task, hdr);
return 0;
}
@@ -1480,11 +1543,6 @@ static void ff_layout_write_call_done(struct rpc_task *task, void *data)
{
struct nfs_pgio_header *hdr = data;
- nfs4_ff_layout_stat_io_end_write(task,
- FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx),
- hdr->args.count, hdr->res.count,
- hdr->res.verf->committed);
-
if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
task->tk_status == 0) {
nfs4_sequence_done(task, &hdr->res.seq_res);
@@ -1499,18 +1557,53 @@ static void ff_layout_write_count_stats(struct rpc_task *task, void *data)
{
struct nfs_pgio_header *hdr = data;
+ ff_layout_write_record_layoutstats_done(task, hdr);
rpc_count_iostats_metrics(task,
&NFS_CLIENT(hdr->inode)->cl_metrics[NFSPROC4_CLNT_WRITE]);
}
-static void ff_layout_commit_prepare_common(struct rpc_task *task,
+static void ff_layout_write_release(void *data)
+{
+ struct nfs_pgio_header *hdr = data;
+
+ ff_layout_write_record_layoutstats_done(&hdr->task, hdr);
+ pnfs_generic_rw_release(data);
+}
+
+static void ff_layout_commit_record_layoutstats_start(struct rpc_task *task,
struct nfs_commit_data *cdata)
{
+ if (test_and_set_bit(NFS_IOHDR_STAT, &cdata->flags))
+ return;
nfs4_ff_layout_stat_io_start_write(cdata->inode,
FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index),
0, task->tk_start);
}
+static void ff_layout_commit_record_layoutstats_done(struct rpc_task *task,
+ struct nfs_commit_data *cdata)
+{
+ struct nfs_page *req;
+ __u64 count = 0;
+
+ if (!test_and_clear_bit(NFS_IOHDR_STAT, &cdata->flags))
+ return;
+
+ if (task->tk_status == 0) {
+ list_for_each_entry(req, &cdata->pages, wb_list)
+ count += req->wb_bytes;
+ }
+ nfs4_ff_layout_stat_io_end_write(task,
+ FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index),
+ count, count, NFS_FILE_SYNC);
+}
+
+static void ff_layout_commit_prepare_common(struct rpc_task *task,
+ struct nfs_commit_data *cdata)
+{
+ ff_layout_commit_record_layoutstats_start(task, cdata);
+}
+
static void ff_layout_commit_prepare_v3(struct rpc_task *task, void *data)
{
ff_layout_commit_prepare_common(task, data);
@@ -1531,19 +1624,6 @@ static void ff_layout_commit_prepare_v4(struct rpc_task *task, void *data)
static void ff_layout_commit_done(struct rpc_task *task, void *data)
{
- struct nfs_commit_data *cdata = data;
- struct nfs_page *req;
- __u64 count = 0;
-
- if (task->tk_status == 0) {
- list_for_each_entry(req, &cdata->pages, wb_list)
- count += req->wb_bytes;
- }
-
- nfs4_ff_layout_stat_io_end_write(task,
- FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index),
- count, count, NFS_FILE_SYNC);
-
pnfs_generic_write_commit_done(task, data);
}
@@ -1551,50 +1631,59 @@ static void ff_layout_commit_count_stats(struct rpc_task *task, void *data)
{
struct nfs_commit_data *cdata = data;
+ ff_layout_commit_record_layoutstats_done(task, cdata);
rpc_count_iostats_metrics(task,
&NFS_CLIENT(cdata->inode)->cl_metrics[NFSPROC4_CLNT_COMMIT]);
}
+static void ff_layout_commit_release(void *data)
+{
+ struct nfs_commit_data *cdata = data;
+
+ ff_layout_commit_record_layoutstats_done(&cdata->task, cdata);
+ pnfs_generic_commit_release(data);
+}
+
static const struct rpc_call_ops ff_layout_read_call_ops_v3 = {
.rpc_call_prepare = ff_layout_read_prepare_v3,
.rpc_call_done = ff_layout_read_call_done,
.rpc_count_stats = ff_layout_read_count_stats,
- .rpc_release = pnfs_generic_rw_release,
+ .rpc_release = ff_layout_read_release,
};
static const struct rpc_call_ops ff_layout_read_call_ops_v4 = {
.rpc_call_prepare = ff_layout_read_prepare_v4,
.rpc_call_done = ff_layout_read_call_done,
.rpc_count_stats = ff_layout_read_count_stats,
- .rpc_release = pnfs_generic_rw_release,
+ .rpc_release = ff_layout_read_release,
};
static const struct rpc_call_ops ff_layout_write_call_ops_v3 = {
.rpc_call_prepare = ff_layout_write_prepare_v3,
.rpc_call_done = ff_layout_write_call_done,
.rpc_count_stats = ff_layout_write_count_stats,
- .rpc_release = pnfs_generic_rw_release,
+ .rpc_release = ff_layout_write_release,
};
static const struct rpc_call_ops ff_layout_write_call_ops_v4 = {
.rpc_call_prepare = ff_layout_write_prepare_v4,
.rpc_call_done = ff_layout_write_call_done,
.rpc_count_stats = ff_layout_write_count_stats,
- .rpc_release = pnfs_generic_rw_release,
+ .rpc_release = ff_layout_write_release,
};
static const struct rpc_call_ops ff_layout_commit_call_ops_v3 = {
.rpc_call_prepare = ff_layout_commit_prepare_v3,
.rpc_call_done = ff_layout_commit_done,
.rpc_count_stats = ff_layout_commit_count_stats,
- .rpc_release = pnfs_generic_commit_release,
+ .rpc_release = ff_layout_commit_release,
};
static const struct rpc_call_ops ff_layout_commit_call_ops_v4 = {
.rpc_call_prepare = ff_layout_commit_prepare_v4,
.rpc_call_done = ff_layout_commit_done,
.rpc_count_stats = ff_layout_commit_count_stats,
- .rpc_release = pnfs_generic_commit_release,
+ .rpc_release = ff_layout_commit_release,
};
static enum pnfs_try_status
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h
index 2bb08bc6aaf0..dd353bb7dc0a 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.h
+++ b/fs/nfs/flexfilelayout/flexfilelayout.h
@@ -85,6 +85,7 @@ struct nfs4_ff_layout_mirror {
struct nfs4_ff_layoutstat write_stat;
ktime_t start_time;
ktime_t last_report_time;
+ u32 report_interval;
};
struct nfs4_ff_layout_segment {
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index e125e55de86d..bd0327541366 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -429,22 +429,14 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
mirror, lseg->pls_range.offset,
lseg->pls_range.length, NFS4ERR_NXIO,
OP_ILLEGAL, GFP_NOIO);
- if (fail_return) {
- pnfs_error_mark_layout_for_return(ino, lseg);
- if (ff_layout_has_available_ds(lseg))
- pnfs_set_retry_layoutget(lseg->pls_layout);
- else
- pnfs_clear_retry_layoutget(lseg->pls_layout);
-
- } else {
+ if (!fail_return) {
if (ff_layout_has_available_ds(lseg))
set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
&lseg->pls_layout->plh_flags);
- else {
+ else
pnfs_error_mark_layout_for_return(ino, lseg);
- pnfs_clear_retry_layoutget(lseg->pls_layout);
- }
- }
+ } else
+ pnfs_error_mark_layout_for_return(ino, lseg);
}
out_update_creds:
if (ff_layout_update_mirror_cred(mirror, ds))
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index bdb4dc7b4ecd..8e24d886d2c5 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -71,19 +71,25 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
return nfs_fileid_to_ino_t(fattr->fileid);
}
-/**
- * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
- * @word: long word containing the bit lock
- */
-int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
+static int nfs_wait_killable(int mode)
{
freezable_schedule_unsafe();
if (signal_pending_state(mode, current))
return -ERESTARTSYS;
return 0;
}
+
+int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
+{
+ return nfs_wait_killable(mode);
+}
EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
+int nfs_wait_atomic_killable(atomic_t *p)
+{
+ return nfs_wait_killable(TASK_KILLABLE);
+}
+
/**
* nfs_compat_user_ino64 - returns the user-visible inode number
* @fileid: 64-bit fileid
@@ -700,7 +706,7 @@ static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
l_ctx->lockowner.l_owner = current->files;
l_ctx->lockowner.l_pid = current->tgid;
INIT_LIST_HEAD(&l_ctx->list);
- nfs_iocounter_init(&l_ctx->io_count);
+ atomic_set(&l_ctx->io_count, 0);
}
static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
@@ -913,6 +919,12 @@ void nfs_file_clear_open_context(struct file *filp)
if (ctx) {
struct inode *inode = d_inode(ctx->dentry);
+ /*
+ * We fatal error on write before. Try to writeback
+ * every page again.
+ */
+ if (ctx->error < 0)
+ invalidate_inode_pages2(inode->i_mapping);
filp->private_data = NULL;
spin_lock(&inode->i_lock);
list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
@@ -1663,6 +1675,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
unsigned long invalid = 0;
unsigned long now = jiffies;
unsigned long save_cache_validity;
+ bool cache_revalidated = true;
dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
__func__, inode->i_sb->s_id, inode->i_ino,
@@ -1724,22 +1737,28 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfs_force_lookup_revalidate(inode);
inode->i_version = fattr->change_attr;
}
- } else
+ } else {
nfsi->cache_validity |= save_cache_validity;
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
- } else if (server->caps & NFS_CAP_MTIME)
+ } else if (server->caps & NFS_CAP_MTIME) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
- } else if (server->caps & NFS_CAP_CTIME)
+ } else if (server->caps & NFS_CAP_CTIME) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
/* Check if our cached file size is stale */
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
@@ -1759,19 +1778,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
(long long)cur_isize,
(long long)new_isize);
}
- } else
+ } else {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_PAGECACHE
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_ATIME)
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
- else if (server->caps & NFS_CAP_ATIME)
+ else if (server->caps & NFS_CAP_ATIME) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATIME
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_MODE) {
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
@@ -1780,36 +1803,42 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_mode = newmode;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
}
- } else if (server->caps & NFS_CAP_MODE)
+ } else if (server->caps & NFS_CAP_MODE) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
if (!uid_eq(inode->i_uid, fattr->uid)) {
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
inode->i_uid = fattr->uid;
}
- } else if (server->caps & NFS_CAP_OWNER)
+ } else if (server->caps & NFS_CAP_OWNER) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
if (!gid_eq(inode->i_gid, fattr->gid)) {
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
inode->i_gid = fattr->gid;
}
- } else if (server->caps & NFS_CAP_OWNER_GROUP)
+ } else if (server->caps & NFS_CAP_OWNER_GROUP) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
if (inode->i_nlink != fattr->nlink) {
@@ -1818,19 +1847,22 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid |= NFS_INO_INVALID_DATA;
set_nlink(inode, fattr->nlink);
}
- } else if (server->caps & NFS_CAP_NLINK)
+ } else if (server->caps & NFS_CAP_NLINK) {
nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED);
+ cache_revalidated = false;
+ }
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
/*
* report the blocks in 512byte units
*/
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
- }
- if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
+ } else if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
inode->i_blocks = fattr->du.nfs2.blocks;
+ else
+ cache_revalidated = false;
/* Update attrtimeo value if we're out of the unstable period */
if (invalid & NFS_INO_INVALID_ATTR) {
@@ -1840,9 +1872,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Set barrier to be more recent than all outstanding updates */
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
} else {
- if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
- if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
- nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+ if (cache_revalidated) {
+ if (!time_in_range_open(now, nfsi->attrtimeo_timestamp,
+ nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
+ nfsi->attrtimeo <<= 1;
+ if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode))
+ nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+ }
nfsi->attrtimeo_timestamp = now;
}
/* Set the barrier to be more recent than this fattr */
@@ -1851,7 +1887,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
}
/* Don't declare attrcache up to date if there were no attrs! */
- if (fattr->valid != 0)
+ if (cache_revalidated)
invalid &= ~NFS_INO_INVALID_ATTR;
/* Don't invalidate the data if we were to blame */
@@ -1933,7 +1969,7 @@ static int __init nfs_init_inodecache(void)
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (nfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 9dea85f7f918..4e8cc942336c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -238,7 +238,7 @@ extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr,
void (*release)(struct nfs_pgio_header *hdr));
void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos);
-int nfs_iocounter_wait(struct nfs_io_counter *c);
+int nfs_iocounter_wait(struct nfs_lock_context *l_ctx);
extern const struct nfs_pageio_ops nfs_pgio_rw_ops;
struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
@@ -252,18 +252,18 @@ void nfs_free_request(struct nfs_page *req);
struct nfs_pgio_mirror *
nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc);
-static inline void nfs_iocounter_init(struct nfs_io_counter *c)
-{
- c->flags = 0;
- atomic_set(&c->io_count, 0);
-}
-
static inline bool nfs_pgio_has_mirroring(struct nfs_pageio_descriptor *desc)
{
WARN_ON_ONCE(desc->pg_mirror_count < 1);
return desc->pg_mirror_count > 1;
}
+static inline bool nfs_match_open_context(const struct nfs_open_context *ctx1,
+ const struct nfs_open_context *ctx2)
+{
+ return ctx1->cred == ctx2->cred && ctx1->state == ctx2->state;
+}
+
/* nfs2xdr.c */
extern struct rpc_procinfo nfs_procedures[];
extern int nfs2_decode_dirent(struct xdr_stream *,
@@ -380,6 +380,7 @@ extern void nfs_clear_inode(struct inode *);
extern void nfs_evict_inode(struct inode *);
void nfs_zap_acl_cache(struct inode *inode);
extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
+extern int nfs_wait_atomic_killable(atomic_t *p);
/* super.c */
extern const struct super_operations nfs_sops;
@@ -519,7 +520,6 @@ static inline void nfs_inode_dio_wait(struct inode *inode)
inode_dio_wait(inode);
}
extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq);
-extern void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq);
/* nfs4proc.c */
extern void __nfs4_read_done_cb(struct nfs_pgio_header *);
@@ -696,9 +696,32 @@ static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
{
return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size);
}
+static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid)
+{
+ return ~crc32_le(0xFFFFFFFF, &stateid->other[0],
+ NFS4_STATEID_OTHER_SIZE);
+}
#else
static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
{
return 0;
}
+static inline u32 nfs_stateid_hash(nfs4_stateid *stateid)
+{
+ return 0;
+}
#endif
+
+static inline bool nfs_error_is_fatal(int err)
+{
+ switch (err) {
+ case -ERESTARTSYS:
+ case -EIO:
+ case -ENOSPC:
+ case -EROFS:
+ case -E2BIG:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 6b1ce9825430..6e8174930a48 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -204,6 +204,8 @@ static void
nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
{
struct nfs42_layoutstat_data *data = calldata;
+ struct inode *inode = data->inode;
+ struct pnfs_layout_hdr *lo;
if (!nfs4_sequence_done(task, &data->res.seq_res))
return;
@@ -211,12 +213,35 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
switch (task->tk_status) {
case 0:
break;
+ case -NFS4ERR_EXPIRED:
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_OLD_STATEID:
+ case -NFS4ERR_BAD_STATEID:
+ spin_lock(&inode->i_lock);
+ lo = NFS_I(inode)->layout;
+ if (lo && nfs4_stateid_match(&data->args.stateid,
+ &lo->plh_stateid)) {
+ LIST_HEAD(head);
+
+ /*
+ * Mark the bad layout state as invalid, then retry
+ * with the current stateid.
+ */
+ set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+ pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
+ spin_unlock(&inode->i_lock);
+ pnfs_free_lseg_list(&head);
+ } else
+ spin_unlock(&inode->i_lock);
+ break;
case -ENOTSUPP:
case -EOPNOTSUPP:
- NFS_SERVER(data->inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
+ NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
default:
- dprintk("%s server returns %d\n", __func__, task->tk_status);
+ break;
}
+
+ dprintk("%s server returns %d\n", __func__, task->tk_status);
}
static void
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c57d1332c1c8..4bfc33ad0563 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -208,6 +208,9 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
| FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY,
FATTR4_WORD2_MDSTHRESHOLD
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ | FATTR4_WORD2_SECURITY_LABEL
+#endif
};
static const u32 nfs4_open_noattr_bitmap[3] = {
@@ -1385,6 +1388,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
* Protect the call to nfs4_state_set_mode_locked and
* serialise the stateid update
*/
+ spin_lock(&state->owner->so_lock);
write_seqlock(&state->seqlock);
if (deleg_stateid != NULL) {
nfs4_stateid_copy(&state->stateid, deleg_stateid);
@@ -1393,7 +1397,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
if (open_stateid != NULL)
nfs_set_open_stateid_locked(state, open_stateid, fmode);
write_sequnlock(&state->seqlock);
- spin_lock(&state->owner->so_lock);
update_open_stateflags(state, fmode);
spin_unlock(&state->owner->so_lock);
}
@@ -1598,6 +1601,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
if (!data->rpc_done) {
state = nfs4_try_open_cached(data);
+ trace_nfs4_cached_open(data->state);
goto out;
}
@@ -2015,6 +2019,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
}
return;
unlock_no_action:
+ trace_nfs4_cached_open(data->state);
rcu_read_unlock();
out_no_action:
task->tk_action = NULL;
@@ -2703,6 +2708,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (status == 0 && state != NULL)
renew_lease(server, timestamp);
+ trace_nfs4_setattr(inode, &arg.stateid, status);
return status;
}
@@ -2719,7 +2725,6 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
int err;
do {
err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
- trace_nfs4_setattr(inode, err);
switch (err) {
case -NFS4ERR_OPENMODE:
if (!(sattr->ia_valid & ATTR_SIZE)) {
@@ -5048,7 +5053,6 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
static int
nfs4_init_nonuniform_client_string(struct nfs_client *clp)
{
- int result;
size_t len;
char *str;
@@ -5076,7 +5080,7 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
return -ENOMEM;
rcu_read_lock();
- result = scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
+ scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
clp->cl_ipaddr,
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO));
@@ -5089,7 +5093,6 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
static int
nfs4_init_uniquifier_client_string(struct nfs_client *clp)
{
- int result;
size_t len;
char *str;
@@ -5109,7 +5112,7 @@ nfs4_init_uniquifier_client_string(struct nfs_client *clp)
if (!str)
return -ENOMEM;
- result = scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
+ scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
clp->rpc_ops->version, clp->cl_minorversion,
nfs4_client_id_uniquifier,
clp->cl_rpcclient->cl_nodename);
@@ -5120,7 +5123,6 @@ nfs4_init_uniquifier_client_string(struct nfs_client *clp)
static int
nfs4_init_uniform_client_string(struct nfs_client *clp)
{
- int result;
size_t len;
char *str;
@@ -5145,7 +5147,7 @@ nfs4_init_uniform_client_string(struct nfs_client *clp)
if (!str)
return -ENOMEM;
- result = scnprintf(str, len, "Linux NFSv%u.%u %s",
+ scnprintf(str, len, "Linux NFSv%u.%u %s",
clp->rpc_ops->version, clp->cl_minorversion,
clp->cl_rpcclient->cl_nodename);
clp->cl_owner_id = str;
@@ -5384,6 +5386,11 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
if (data == NULL)
return -ENOMEM;
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+
+ nfs4_state_protect(server->nfs_client,
+ NFS_SP4_MACH_CRED_CLEANUP,
+ &task_setup_data.rpc_client, &msg);
+
data->args.fhandle = &data->fh;
data->args.stateid = &data->stateid;
data->args.bitmask = server->cache_consistency_bitmask;
@@ -5426,7 +5433,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
int err;
do {
err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
- trace_nfs4_delegreturn(inode, err);
+ trace_nfs4_delegreturn(inode, stateid, err);
switch (err) {
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
@@ -5936,6 +5943,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
data->cancelled = 1;
rpc_put_task(task);
dprintk("%s: done, ret = %d!\n", __func__, ret);
+ trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
return ret;
}
@@ -5952,7 +5960,6 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
- trace_nfs4_lock_reclaim(request, state, F_SETLK, err);
if (err != -NFS4ERR_DELAY)
break;
nfs4_handle_exception(server, err, &exception);
@@ -5979,7 +5986,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
- trace_nfs4_lock_expired(request, state, F_SETLK, err);
switch (err) {
default:
goto out;
@@ -6087,7 +6093,6 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
do {
err = _nfs4_proc_setlk(state, cmd, request);
- trace_nfs4_set_lock(request, state, cmd, err);
if (err == -NFS4ERR_DENIED)
err = -EAGAIN;
err = nfs4_handle_exception(NFS_SERVER(state->inode),
@@ -6847,10 +6852,13 @@ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
},
.allow.u.words = {
[0] = 1 << (OP_CLOSE) |
+ 1 << (OP_OPEN_DOWNGRADE) |
1 << (OP_LOCKU) |
+ 1 << (OP_DELEGRETURN) |
1 << (OP_COMMIT),
[1] = 1 << (OP_SECINFO - 32) |
1 << (OP_SECINFO_NO_NAME - 32) |
+ 1 << (OP_LAYOUTRETURN - 32) |
1 << (OP_TEST_STATEID - 32) |
1 << (OP_FREE_STATEID - 32) |
1 << (OP_WRITE - 32)
@@ -6915,11 +6923,19 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
}
if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
+ test_bit(OP_OPEN_DOWNGRADE, sp->allow.u.longs) &&
+ test_bit(OP_DELEGRETURN, sp->allow.u.longs) &&
test_bit(OP_LOCKU, sp->allow.u.longs)) {
dfprintk(MOUNT, " cleanup mode enabled\n");
set_bit(NFS_SP4_MACH_CRED_CLEANUP, &clp->cl_sp4_flags);
}
+ if (test_bit(OP_LAYOUTRETURN, sp->allow.u.longs)) {
+ dfprintk(MOUNT, " pnfs cleanup mode enabled\n");
+ set_bit(NFS_SP4_MACH_CRED_PNFS_CLEANUP,
+ &clp->cl_sp4_flags);
+ }
+
if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
dfprintk(MOUNT, " secinfo mode enabled\n");
@@ -7748,6 +7764,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
struct nfs4_layoutget *lgp = calldata;
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
struct nfs4_session *session = nfs4_get_session(server);
+ int ret;
dprintk("--> %s\n", __func__);
/* Note the is a race here, where a CB_LAYOUTRECALL can come in
@@ -7758,12 +7775,12 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
if (nfs41_setup_sequence(session, &lgp->args.seq_args,
&lgp->res.seq_res, task))
return;
- if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
+ ret = pnfs_choose_layoutget_stateid(&lgp->args.stateid,
NFS_I(lgp->args.inode)->layout,
&lgp->args.range,
- lgp->args.ctx->state)) {
- rpc_exit(task, NFS4_OK);
- }
+ lgp->args.ctx->state);
+ if (ret < 0)
+ rpc_exit(task, ret);
}
static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
@@ -7783,6 +7800,15 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
switch (task->tk_status) {
case 0:
goto out;
+
+ /*
+ * NFS4ERR_LAYOUTUNAVAILABLE means we are not supposed to use pnfs
+ * on the file. set tk_status to -ENODATA to tell upper layer to
+ * retry go inband.
+ */
+ case -NFS4ERR_LAYOUTUNAVAILABLE:
+ task->tk_status = -ENODATA;
+ goto out;
/*
* NFS4ERR_BADLAYOUT means the MDS cannot return a layout of
* length lgp->args.minlength != 0 (see RFC5661 section 18.43.3).
@@ -7979,6 +8005,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
trace_nfs4_layoutget(lgp->args.ctx,
&lgp->args.range,
&lgp->res.range,
+ &lgp->res.stateid,
status);
/* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
if (status == 0 && lgp->res.layoutp->len)
@@ -8035,11 +8062,11 @@ static void nfs4_layoutreturn_release(void *calldata)
dprintk("--> %s\n", __func__);
spin_lock(&lo->plh_inode->i_lock);
+ pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
+ pnfs_mark_layout_returned_if_empty(lo);
if (lrp->res.lrs_present)
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
- pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
pnfs_clear_layoutreturn_waitbit(lo);
- lo->plh_block_lgets--;
spin_unlock(&lo->plh_inode->i_lock);
pnfs_free_lseg_list(&freeme);
pnfs_put_layout_hdr(lrp->args.layout);
@@ -8071,6 +8098,10 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
};
int status = 0;
+ nfs4_state_protect(NFS_SERVER(lrp->args.inode)->nfs_client,
+ NFS_SP4_MACH_CRED_PNFS_CLEANUP,
+ &task_setup_data.rpc_client, &msg);
+
dprintk("--> %s\n", __func__);
if (!sync) {
lrp->inode = nfs_igrab_and_active(lrp->args.inode);
@@ -8086,7 +8117,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
return PTR_ERR(task);
if (sync)
status = task->tk_status;
- trace_nfs4_layoutreturn(lrp->args.inode, status);
+ trace_nfs4_layoutreturn(lrp->args.inode, &lrp->args.stateid, status);
dprintk("<-- %s status=%d\n", __func__, status);
rpc_put_task(task);
return status;
@@ -8234,7 +8265,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
return PTR_ERR(task);
if (sync)
status = task->tk_status;
- trace_nfs4_layoutcommit(data->args.inode, status);
+ trace_nfs4_layoutcommit(data->args.inode, &data->args.stateid, status);
dprintk("%s: status %d\n", __func__, status);
rpc_put_task(task);
return status;
diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c
index 0fbd3ab1be22..8693d77c45ea 100644
--- a/fs/nfs/nfs4sysctl.c
+++ b/fs/nfs/nfs4sysctl.c
@@ -12,7 +12,7 @@
#include "nfs4idmap.h"
#include "callback.h"
-static const int nfs_set_port_min = 0;
+static const int nfs_set_port_min;
static const int nfs_set_port_max = 65535;
static struct ctl_table_header *nfs4_callback_sysctl_table;
diff --git a/fs/nfs/nfs4trace.c b/fs/nfs/nfs4trace.c
index d774335cc8bc..2850bce19244 100644
--- a/fs/nfs/nfs4trace.c
+++ b/fs/nfs/nfs4trace.c
@@ -6,6 +6,7 @@
#include "internal.h"
#include "nfs4session.h"
#include "callback.h"
+#include "pnfs.h"
#define CREATE_TRACE_POINTS
#include "nfs4trace.h"
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 671cf68fe56b..2c8d05dae5b1 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -321,6 +321,7 @@ TRACE_EVENT(nfs4_sequence_done,
__entry->highest_slotid = res->sr_highest_slotid;
__entry->target_highest_slotid =
res->sr_target_highest_slotid;
+ __entry->status_flags = res->sr_status_flags;
__entry->error = res->sr_status;
),
TP_printk(
@@ -399,6 +400,10 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
__field(u64, fileid)
__field(u64, dir)
__string(name, ctx->dentry->d_name.name)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
+ __field(int, openstateid_seq)
+ __field(u32, openstateid_hash)
),
TP_fast_assign(
@@ -409,8 +414,22 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
__entry->flags = flags;
__entry->fmode = (__force unsigned int)ctx->mode;
__entry->dev = ctx->dentry->d_sb->s_dev;
- if (!IS_ERR_OR_NULL(state))
+ if (!IS_ERR_OR_NULL(state)) {
inode = state->inode;
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
+ __entry->openstateid_seq =
+ be32_to_cpu(state->open_stateid.seqid);
+ __entry->openstateid_hash =
+ nfs_stateid_hash(&state->open_stateid);
+ } else {
+ __entry->stateid_seq = 0;
+ __entry->stateid_hash = 0;
+ __entry->openstateid_seq = 0;
+ __entry->openstateid_hash = 0;
+ }
if (inode != NULL) {
__entry->fileid = NFS_FILEID(inode);
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
@@ -425,7 +444,8 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
TP_printk(
"error=%d (%s) flags=%d (%s) fmode=%s "
"fileid=%02x:%02x:%llu fhandle=0x%08x "
- "name=%02x:%02x:%llu/%s",
+ "name=%02x:%02x:%llu/%s stateid=%d:0x%08x "
+ "openstateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
__entry->flags,
@@ -436,7 +456,9 @@ DECLARE_EVENT_CLASS(nfs4_open_event,
__entry->fhandle,
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->dir,
- __get_str(name)
+ __get_str(name),
+ __entry->stateid_seq, __entry->stateid_hash,
+ __entry->openstateid_seq, __entry->openstateid_hash
)
);
@@ -452,6 +474,45 @@ DEFINE_NFS4_OPEN_EVENT(nfs4_open_reclaim);
DEFINE_NFS4_OPEN_EVENT(nfs4_open_expired);
DEFINE_NFS4_OPEN_EVENT(nfs4_open_file);
+TRACE_EVENT(nfs4_cached_open,
+ TP_PROTO(
+ const struct nfs4_state *state
+ ),
+ TP_ARGS(state),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u32, fhandle)
+ __field(u64, fileid)
+ __field(unsigned int, fmode)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
+ ),
+
+ TP_fast_assign(
+ const struct inode *inode = state->inode;
+
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->fileid = NFS_FILEID(inode);
+ __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+ __entry->fmode = (__force unsigned int)state->state;
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
+ ),
+
+ TP_printk(
+ "fmode=%s fileid=%02x:%02x:%llu "
+ "fhandle=0x%08x stateid=%d:0x%08x",
+ __entry->fmode ? show_fmode_flags(__entry->fmode) :
+ "closed",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ (unsigned long long)__entry->fileid,
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash
+ )
+);
+
TRACE_EVENT(nfs4_close,
TP_PROTO(
const struct nfs4_state *state,
@@ -468,6 +529,8 @@ TRACE_EVENT(nfs4_close,
__field(u64, fileid)
__field(unsigned int, fmode)
__field(int, error)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
),
TP_fast_assign(
@@ -478,18 +541,23 @@ TRACE_EVENT(nfs4_close,
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
__entry->fmode = (__force unsigned int)state->state;
__entry->error = error;
+ __entry->stateid_seq =
+ be32_to_cpu(args->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&args->stateid);
),
TP_printk(
"error=%d (%s) fmode=%s fileid=%02x:%02x:%llu "
- "fhandle=0x%08x",
+ "fhandle=0x%08x openstateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
__entry->fmode ? show_fmode_flags(__entry->fmode) :
"closed",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
- __entry->fhandle
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash
)
);
@@ -523,6 +591,8 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
),
TP_fast_assign(
@@ -536,11 +606,16 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = NFS_FILEID(inode);
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
),
TP_printk(
"error=%d (%s) cmd=%s:%s range=%lld:%lld "
- "fileid=%02x:%02x:%llu fhandle=0x%08x",
+ "fileid=%02x:%02x:%llu fhandle=0x%08x "
+ "stateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
show_lock_cmd(__entry->cmd),
@@ -549,7 +624,8 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
(long long)__entry->end,
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
- __entry->fhandle
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash
)
);
@@ -563,11 +639,73 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
), \
TP_ARGS(request, state, cmd, error))
DEFINE_NFS4_LOCK_EVENT(nfs4_get_lock);
-DEFINE_NFS4_LOCK_EVENT(nfs4_set_lock);
-DEFINE_NFS4_LOCK_EVENT(nfs4_lock_reclaim);
-DEFINE_NFS4_LOCK_EVENT(nfs4_lock_expired);
DEFINE_NFS4_LOCK_EVENT(nfs4_unlock);
+TRACE_EVENT(nfs4_set_lock,
+ TP_PROTO(
+ const struct file_lock *request,
+ const struct nfs4_state *state,
+ const nfs4_stateid *lockstateid,
+ int cmd,
+ int error
+ ),
+
+ TP_ARGS(request, state, lockstateid, cmd, error),
+
+ TP_STRUCT__entry(
+ __field(int, error)
+ __field(int, cmd)
+ __field(char, type)
+ __field(loff_t, start)
+ __field(loff_t, end)
+ __field(dev_t, dev)
+ __field(u32, fhandle)
+ __field(u64, fileid)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
+ __field(int, lockstateid_seq)
+ __field(u32, lockstateid_hash)
+ ),
+
+ TP_fast_assign(
+ const struct inode *inode = state->inode;
+
+ __entry->error = error;
+ __entry->cmd = cmd;
+ __entry->type = request->fl_type;
+ __entry->start = request->fl_start;
+ __entry->end = request->fl_end;
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->fileid = NFS_FILEID(inode);
+ __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
+ __entry->lockstateid_seq =
+ be32_to_cpu(lockstateid->seqid);
+ __entry->lockstateid_hash =
+ nfs_stateid_hash(lockstateid);
+ ),
+
+ TP_printk(
+ "error=%d (%s) cmd=%s:%s range=%lld:%lld "
+ "fileid=%02x:%02x:%llu fhandle=0x%08x "
+ "stateid=%d:0x%08x lockstateid=%d:0x%08x",
+ __entry->error,
+ show_nfsv4_errors(__entry->error),
+ show_lock_cmd(__entry->cmd),
+ show_lock_type(__entry->type),
+ (long long)__entry->start,
+ (long long)__entry->end,
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ (unsigned long long)__entry->fileid,
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash,
+ __entry->lockstateid_seq, __entry->lockstateid_hash
+ )
+);
+
DECLARE_EVENT_CLASS(nfs4_set_delegation_event,
TP_PROTO(
const struct inode *inode,
@@ -621,20 +759,28 @@ TRACE_EVENT(nfs4_delegreturn_exit,
__field(dev_t, dev)
__field(u32, fhandle)
__field(int, error)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
),
TP_fast_assign(
__entry->dev = res->server->s_dev;
__entry->fhandle = nfs_fhandle_hash(args->fhandle);
__entry->error = error;
+ __entry->stateid_seq =
+ be32_to_cpu(args->stateid->seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(args->stateid);
),
TP_printk(
- "error=%d (%s) dev=%02x:%02x fhandle=0x%08x",
+ "error=%d (%s) dev=%02x:%02x fhandle=0x%08x "
+ "stateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
MAJOR(__entry->dev), MINOR(__entry->dev),
- __entry->fhandle
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash
)
);
@@ -653,6 +799,8 @@ DECLARE_EVENT_CLASS(nfs4_test_stateid_event,
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
),
TP_fast_assign(
@@ -662,15 +810,21 @@ DECLARE_EVENT_CLASS(nfs4_test_stateid_event,
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = NFS_FILEID(inode);
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
),
TP_printk(
- "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x",
+ "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+ "stateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
- __entry->fhandle
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash
)
);
@@ -820,7 +974,6 @@ DECLARE_EVENT_CLASS(nfs4_inode_event,
), \
TP_ARGS(inode, error))
-DEFINE_NFS4_INODE_EVENT(nfs4_setattr);
DEFINE_NFS4_INODE_EVENT(nfs4_access);
DEFINE_NFS4_INODE_EVENT(nfs4_readlink);
DEFINE_NFS4_INODE_EVENT(nfs4_readdir);
@@ -830,8 +983,59 @@ DEFINE_NFS4_INODE_EVENT(nfs4_set_acl);
DEFINE_NFS4_INODE_EVENT(nfs4_get_security_label);
DEFINE_NFS4_INODE_EVENT(nfs4_set_security_label);
#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
-DEFINE_NFS4_INODE_EVENT(nfs4_recall_delegation);
-DEFINE_NFS4_INODE_EVENT(nfs4_delegreturn);
+
+DECLARE_EVENT_CLASS(nfs4_inode_stateid_event,
+ TP_PROTO(
+ const struct inode *inode,
+ const nfs4_stateid *stateid,
+ int error
+ ),
+
+ TP_ARGS(inode, stateid, error),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u32, fhandle)
+ __field(u64, fileid)
+ __field(int, error)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->fileid = NFS_FILEID(inode);
+ __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+ __entry->error = error;
+ __entry->stateid_seq =
+ be32_to_cpu(stateid->seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(stateid);
+ ),
+
+ TP_printk(
+ "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+ "stateid=%d:0x%08x",
+ __entry->error,
+ show_nfsv4_errors(__entry->error),
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ (unsigned long long)__entry->fileid,
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash
+ )
+);
+
+#define DEFINE_NFS4_INODE_STATEID_EVENT(name) \
+ DEFINE_EVENT(nfs4_inode_stateid_event, name, \
+ TP_PROTO( \
+ const struct inode *inode, \
+ const nfs4_stateid *stateid, \
+ int error \
+ ), \
+ TP_ARGS(inode, stateid, error))
+
+DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_setattr);
+DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_delegreturn);
DECLARE_EVENT_CLASS(nfs4_getattr_event,
TP_PROTO(
@@ -941,8 +1145,74 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event,
), \
TP_ARGS(clp, fhandle, inode, error))
DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_getattr);
-DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_layoutrecall_inode);
+DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event,
+ TP_PROTO(
+ const struct nfs_client *clp,
+ const struct nfs_fh *fhandle,
+ const struct inode *inode,
+ const nfs4_stateid *stateid,
+ int error
+ ),
+
+ TP_ARGS(clp, fhandle, inode, stateid, error),
+
+ TP_STRUCT__entry(
+ __field(int, error)
+ __field(dev_t, dev)
+ __field(u32, fhandle)
+ __field(u64, fileid)
+ __string(dstaddr, clp ?
+ rpc_peeraddr2str(clp->cl_rpcclient,
+ RPC_DISPLAY_ADDR) : "unknown")
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
+ ),
+
+ TP_fast_assign(
+ __entry->error = error;
+ __entry->fhandle = nfs_fhandle_hash(fhandle);
+ if (inode != NULL) {
+ __entry->fileid = NFS_FILEID(inode);
+ __entry->dev = inode->i_sb->s_dev;
+ } else {
+ __entry->fileid = 0;
+ __entry->dev = 0;
+ }
+ __assign_str(dstaddr, clp ?
+ rpc_peeraddr2str(clp->cl_rpcclient,
+ RPC_DISPLAY_ADDR) : "unknown")
+ __entry->stateid_seq =
+ be32_to_cpu(stateid->seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(stateid);
+ ),
+
+ TP_printk(
+ "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+ "stateid=%d:0x%08x dstaddr=%s",
+ __entry->error,
+ show_nfsv4_errors(__entry->error),
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ (unsigned long long)__entry->fileid,
+ __entry->fhandle,
+ __entry->stateid_seq, __entry->stateid_hash,
+ __get_str(dstaddr)
+ )
+);
+
+#define DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(name) \
+ DEFINE_EVENT(nfs4_inode_stateid_callback_event, name, \
+ TP_PROTO( \
+ const struct nfs_client *clp, \
+ const struct nfs_fh *fhandle, \
+ const struct inode *inode, \
+ const nfs4_stateid *stateid, \
+ int error \
+ ), \
+ TP_ARGS(clp, fhandle, inode, stateid, error))
+DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_recall);
+DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_layoutrecall_file);
DECLARE_EVENT_CLASS(nfs4_idmap_event,
TP_PROTO(
@@ -1005,28 +1275,37 @@ DECLARE_EVENT_CLASS(nfs4_read_event,
__field(loff_t, offset)
__field(size_t, count)
__field(int, error)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
),
TP_fast_assign(
const struct inode *inode = hdr->inode;
+ const struct nfs4_state *state =
+ hdr->args.context->state;
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = NFS_FILEID(inode);
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
__entry->offset = hdr->args.offset;
__entry->count = hdr->args.count;
__entry->error = error;
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
),
TP_printk(
"error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
- "offset=%lld count=%zu",
+ "offset=%lld count=%zu stateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle,
(long long)__entry->offset,
- __entry->count
+ __entry->count,
+ __entry->stateid_seq, __entry->stateid_hash
)
);
#define DEFINE_NFS4_READ_EVENT(name) \
@@ -1056,28 +1335,37 @@ DECLARE_EVENT_CLASS(nfs4_write_event,
__field(loff_t, offset)
__field(size_t, count)
__field(int, error)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
),
TP_fast_assign(
const struct inode *inode = hdr->inode;
+ const struct nfs4_state *state =
+ hdr->args.context->state;
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = NFS_FILEID(inode);
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
__entry->offset = hdr->args.offset;
__entry->count = hdr->args.count;
__entry->error = error;
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
),
TP_printk(
"error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
- "offset=%lld count=%zu",
+ "offset=%lld count=%zu stateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle,
(long long)__entry->offset,
- __entry->count
+ __entry->count,
+ __entry->stateid_seq, __entry->stateid_hash
)
);
@@ -1154,10 +1442,11 @@ TRACE_EVENT(nfs4_layoutget,
const struct nfs_open_context *ctx,
const struct pnfs_layout_range *args,
const struct pnfs_layout_range *res,
+ const nfs4_stateid *layout_stateid,
int error
),
- TP_ARGS(ctx, args, res, error),
+ TP_ARGS(ctx, args, res, layout_stateid, error),
TP_STRUCT__entry(
__field(dev_t, dev)
@@ -1167,10 +1456,15 @@ TRACE_EVENT(nfs4_layoutget,
__field(u64, offset)
__field(u64, count)
__field(int, error)
+ __field(int, stateid_seq)
+ __field(u32, stateid_hash)
+ __field(int, layoutstateid_seq)
+ __field(u32, layoutstateid_hash)
),
TP_fast_assign(
const struct inode *inode = d_inode(ctx->dentry);
+ const struct nfs4_state *state = ctx->state;
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = NFS_FILEID(inode);
__entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
@@ -1178,11 +1472,25 @@ TRACE_EVENT(nfs4_layoutget,
__entry->offset = args->offset;
__entry->count = args->length;
__entry->error = error;
+ __entry->stateid_seq =
+ be32_to_cpu(state->stateid.seqid);
+ __entry->stateid_hash =
+ nfs_stateid_hash(&state->stateid);
+ if (!error) {
+ __entry->layoutstateid_seq =
+ be32_to_cpu(layout_stateid->seqid);
+ __entry->layoutstateid_hash =
+ nfs_stateid_hash(layout_stateid);
+ } else {
+ __entry->layoutstateid_seq = 0;
+ __entry->layoutstateid_hash = 0;
+ }
),
TP_printk(
"error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
- "iomode=%s offset=%llu count=%llu",
+ "iomode=%s offset=%llu count=%llu stateid=%d:0x%08x "
+ "layoutstateid=%d:0x%08x",
__entry->error,
show_nfsv4_errors(__entry->error),
MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -1190,14 +1498,83 @@ TRACE_EVENT(nfs4_layoutget,
__entry->fhandle,
show_pnfs_iomode(__entry->iomode),
(unsigned long long)__entry->offset,
- (unsigned long long)__entry->count
+ (unsigned long long)__entry->count,
+ __entry->stateid_seq, __entry->stateid_hash,
+ __entry->layoutstateid_seq, __entry->layoutstateid_hash
)
);
-DEFINE_NFS4_INODE_EVENT(nfs4_layoutcommit);
-DEFINE_NFS4_INODE_EVENT(nfs4_layoutreturn);
+DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_layoutcommit);
+DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_layoutreturn);
DEFINE_NFS4_INODE_EVENT(nfs4_layoutreturn_on_close);
+#define show_pnfs_update_layout_reason(reason) \
+ __print_symbolic(reason, \
+ { PNFS_UPDATE_LAYOUT_UNKNOWN, "unknown" }, \
+ { PNFS_UPDATE_LAYOUT_NO_PNFS, "no pnfs" }, \
+ { PNFS_UPDATE_LAYOUT_RD_ZEROLEN, "read+zerolen" }, \
+ { PNFS_UPDATE_LAYOUT_MDSTHRESH, "mdsthresh" }, \
+ { PNFS_UPDATE_LAYOUT_NOMEM, "nomem" }, \
+ { PNFS_UPDATE_LAYOUT_BULK_RECALL, "bulk recall" }, \
+ { PNFS_UPDATE_LAYOUT_IO_TEST_FAIL, "io test fail" }, \
+ { PNFS_UPDATE_LAYOUT_FOUND_CACHED, "found cached" }, \
+ { PNFS_UPDATE_LAYOUT_RETURN, "layoutreturn" }, \
+ { PNFS_UPDATE_LAYOUT_BLOCKED, "layouts blocked" }, \
+ { PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET, "sent layoutget" })
+
+TRACE_EVENT(pnfs_update_layout,
+ TP_PROTO(struct inode *inode,
+ loff_t pos,
+ u64 count,
+ enum pnfs_iomode iomode,
+ struct pnfs_layout_hdr *lo,
+ enum pnfs_update_layout_reason reason
+ ),
+ TP_ARGS(inode, pos, count, iomode, lo, reason),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u64, fileid)
+ __field(u32, fhandle)
+ __field(loff_t, pos)
+ __field(u64, count)
+ __field(enum pnfs_iomode, iomode)
+ __field(int, layoutstateid_seq)
+ __field(u32, layoutstateid_hash)
+ __field(enum pnfs_update_layout_reason, reason)
+ ),
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->fileid = NFS_FILEID(inode);
+ __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+ __entry->pos = pos;
+ __entry->count = count;
+ __entry->iomode = iomode;
+ __entry->reason = reason;
+ if (lo != NULL) {
+ __entry->layoutstateid_seq =
+ be32_to_cpu(lo->plh_stateid.seqid);
+ __entry->layoutstateid_hash =
+ nfs_stateid_hash(&lo->plh_stateid);
+ } else {
+ __entry->layoutstateid_seq = 0;
+ __entry->layoutstateid_hash = 0;
+ }
+ ),
+ TP_printk(
+ "fileid=%02x:%02x:%llu fhandle=0x%08x "
+ "iomode=%s pos=%llu count=%llu "
+ "layoutstateid=%d:0x%08x (%s)",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ (unsigned long long)__entry->fileid,
+ __entry->fhandle,
+ show_pnfs_iomode(__entry->iomode),
+ (unsigned long long)__entry->pos,
+ (unsigned long long)__entry->count,
+ __entry->layoutstateid_seq, __entry->layoutstateid_hash,
+ show_pnfs_update_layout_reason(__entry->reason)
+ )
+);
+
#endif /* CONFIG_NFS_V4_1 */
#endif /* _TRACE_NFS4_H */
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index 59f838cdc009..9f80a086b612 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -39,7 +39,6 @@
{ 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
{ 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
{ 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
- { 1 << NFS_INO_COMMIT, "COMMIT" }, \
{ 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
{ 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 452a011ba0d8..8ce4f61cbaa5 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -101,53 +101,18 @@ nfs_page_free(struct nfs_page *p)
kmem_cache_free(nfs_page_cachep, p);
}
-static void
-nfs_iocounter_inc(struct nfs_io_counter *c)
-{
- atomic_inc(&c->io_count);
-}
-
-static void
-nfs_iocounter_dec(struct nfs_io_counter *c)
-{
- if (atomic_dec_and_test(&c->io_count)) {
- clear_bit(NFS_IO_INPROGRESS, &c->flags);
- smp_mb__after_atomic();
- wake_up_bit(&c->flags, NFS_IO_INPROGRESS);
- }
-}
-
-static int
-__nfs_iocounter_wait(struct nfs_io_counter *c)
-{
- wait_queue_head_t *wq = bit_waitqueue(&c->flags, NFS_IO_INPROGRESS);
- DEFINE_WAIT_BIT(q, &c->flags, NFS_IO_INPROGRESS);
- int ret = 0;
-
- do {
- prepare_to_wait(wq, &q.wait, TASK_KILLABLE);
- set_bit(NFS_IO_INPROGRESS, &c->flags);
- if (atomic_read(&c->io_count) == 0)
- break;
- ret = nfs_wait_bit_killable(&q.key, TASK_KILLABLE);
- } while (atomic_read(&c->io_count) != 0 && !ret);
- finish_wait(wq, &q.wait);
- return ret;
-}
-
/**
* nfs_iocounter_wait - wait for i/o to complete
- * @c: nfs_io_counter to use
+ * @l_ctx: nfs_lock_context with io_counter to use
*
* returns -ERESTARTSYS if interrupted by a fatal signal.
* Otherwise returns 0 once the io_count hits 0.
*/
int
-nfs_iocounter_wait(struct nfs_io_counter *c)
+nfs_iocounter_wait(struct nfs_lock_context *l_ctx)
{
- if (atomic_read(&c->io_count) == 0)
- return 0;
- return __nfs_iocounter_wait(c);
+ return wait_on_atomic_t(&l_ctx->io_count, nfs_wait_atomic_killable,
+ TASK_KILLABLE);
}
/*
@@ -370,7 +335,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
return ERR_CAST(l_ctx);
}
req->wb_lock_context = l_ctx;
- nfs_iocounter_inc(&l_ctx->io_count);
+ atomic_inc(&l_ctx->io_count);
/* Initialize the request struct. Initially, we assume a
* long write-back delay. This will be adjusted in
@@ -431,7 +396,8 @@ static void nfs_clear_request(struct nfs_page *req)
req->wb_page = NULL;
}
if (l_ctx != NULL) {
- nfs_iocounter_dec(&l_ctx->io_count);
+ if (atomic_dec_and_test(&l_ctx->io_count))
+ wake_up_atomic_t(&l_ctx->io_count);
nfs_put_lock_context(l_ctx);
req->wb_lock_context = NULL;
}
@@ -664,22 +630,11 @@ EXPORT_SYMBOL_GPL(nfs_initiate_pgio);
* @desc: IO descriptor
* @hdr: pageio header
*/
-static int nfs_pgio_error(struct nfs_pageio_descriptor *desc,
- struct nfs_pgio_header *hdr)
+static void nfs_pgio_error(struct nfs_pgio_header *hdr)
{
- struct nfs_pgio_mirror *mirror;
- u32 midx;
-
set_bit(NFS_IOHDR_REDO, &hdr->flags);
nfs_pgio_data_destroy(hdr);
hdr->completion_ops->completion(hdr);
- /* TODO: Make sure it's right to clean up all mirrors here
- * and not just hdr->pgio_mirror_idx */
- for (midx = 0; midx < desc->pg_mirror_count; midx++) {
- mirror = &desc->pg_mirrors[midx];
- desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
- }
- return -ENOMEM;
}
/**
@@ -800,8 +755,11 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
unsigned int pagecount, pageused;
pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count);
- if (!nfs_pgarray_set(&hdr->page_array, pagecount))
- return nfs_pgio_error(desc, hdr);
+ if (!nfs_pgarray_set(&hdr->page_array, pagecount)) {
+ nfs_pgio_error(hdr);
+ desc->pg_error = -ENOMEM;
+ return desc->pg_error;
+ }
nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq);
pages = hdr->page_array.pagevec;
@@ -819,8 +777,11 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
*pages++ = last_page = req->wb_page;
}
}
- if (WARN_ON_ONCE(pageused != pagecount))
- return nfs_pgio_error(desc, hdr);
+ if (WARN_ON_ONCE(pageused != pagecount)) {
+ nfs_pgio_error(hdr);
+ desc->pg_error = -EINVAL;
+ return desc->pg_error;
+ }
if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
(desc->pg_moreio || nfs_reqs_to_commit(&cinfo)))
@@ -835,18 +796,13 @@ EXPORT_SYMBOL_GPL(nfs_generic_pgio);
static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
{
- struct nfs_pgio_mirror *mirror;
struct nfs_pgio_header *hdr;
int ret;
- mirror = nfs_pgio_current_mirror(desc);
-
hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
if (!hdr) {
- /* TODO: make sure this is right with mirroring - or
- * should it back out all mirrors? */
- desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
- return -ENOMEM;
+ desc->pg_error = -ENOMEM;
+ return desc->pg_error;
}
nfs_pgheader_init(desc, hdr, nfs_pgio_header_free);
ret = nfs_generic_pgio(desc, hdr);
@@ -874,6 +830,9 @@ static int nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio,
mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
+ if (pgio->pg_error < 0)
+ return pgio->pg_error;
+
if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX)
return -EINVAL;
@@ -903,12 +862,6 @@ static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio)
pgio->pg_mirrors_dynamic = NULL;
}
-static bool nfs_match_open_context(const struct nfs_open_context *ctx1,
- const struct nfs_open_context *ctx2)
-{
- return ctx1->cred == ctx2->cred && ctx1->state == ctx2->state;
-}
-
static bool nfs_match_lock_context(const struct nfs_lock_context *l1,
const struct nfs_lock_context *l2)
{
@@ -982,6 +935,8 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
} else {
if (desc->pg_ops->pg_init)
desc->pg_ops->pg_init(desc, req);
+ if (desc->pg_error < 0)
+ return 0;
mirror->pg_base = req->wb_pgbase;
}
if (!nfs_can_coalesce_requests(prev, req, desc))
@@ -1147,6 +1102,8 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
bytes = req->wb_bytes;
nfs_pageio_setup_mirroring(desc, req);
+ if (desc->pg_error < 0)
+ goto out_failed;
for (midx = 0; midx < desc->pg_mirror_count; midx++) {
if (midx) {
@@ -1163,7 +1120,8 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
if (IS_ERR(dupreq)) {
nfs_page_group_unlock(req);
- return 0;
+ desc->pg_error = PTR_ERR(dupreq);
+ goto out_failed;
}
nfs_lock_request(dupreq);
@@ -1176,10 +1134,32 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
if (nfs_pgio_has_mirroring(desc))
desc->pg_mirror_idx = midx;
if (!nfs_pageio_add_request_mirror(desc, dupreq))
- return 0;
+ goto out_failed;
}
return 1;
+
+out_failed:
+ /*
+ * We might have failed before sending any reqs over wire.
+ * Clean up rest of the reqs in mirror pg_list.
+ */
+ if (desc->pg_error) {
+ struct nfs_pgio_mirror *mirror;
+ void (*func)(struct list_head *);
+
+ /* remember fatal errors */
+ if (nfs_error_is_fatal(desc->pg_error))
+ mapping_set_error(desc->pg_inode->i_mapping,
+ desc->pg_error);
+
+ func = desc->pg_completion_ops->error_cleanup;
+ for (midx = 0; midx < desc->pg_mirror_count; midx++) {
+ mirror = &desc->pg_mirrors[midx];
+ func(&mirror->pg_list);
+ }
+ }
+ return 0;
}
/*
@@ -1232,7 +1212,7 @@ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
nfs_pageio_complete(desc);
if (!list_empty(&failed)) {
list_move(&failed, &hdr->pages);
- return -EIO;
+ return desc->pg_error < 0 ? desc->pg_error : -EIO;
}
return 0;
}
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index bec0384499f7..a3592cc34a20 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(pnfs_spinlock);
static LIST_HEAD(pnfs_modules_tbl);
static int
-pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, nfs4_stateid stateid,
+pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
enum pnfs_iomode iomode, bool sync);
/* Return the registered pnfs layout driver module matching given id */
@@ -385,13 +385,13 @@ static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
enum pnfs_iomode iomode;
bool send;
- stateid = lo->plh_stateid;
+ nfs4_stateid_copy(&stateid, &lo->plh_stateid);
iomode = lo->plh_return_iomode;
send = pnfs_prepare_layoutreturn(lo);
spin_unlock(&inode->i_lock);
if (send) {
/* Send an async layoutreturn so we dont deadlock */
- pnfs_send_layoutreturn(lo, stateid, iomode, false);
+ pnfs_send_layoutreturn(lo, &stateid, iomode, false);
}
} else
spin_unlock(&inode->i_lock);
@@ -566,10 +566,10 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
int
pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
struct list_head *tmp_list,
- struct pnfs_layout_range *recall_range)
+ const struct pnfs_layout_range *recall_range)
{
struct pnfs_layout_segment *lseg, *next;
- int invalid = 0, removed = 0;
+ int remaining = 0;
dprintk("%s:Begin lo %p\n", __func__, lo);
@@ -582,11 +582,11 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
"offset %llu length %llu\n", __func__,
lseg, lseg->pls_range.iomode, lseg->pls_range.offset,
lseg->pls_range.length);
- invalid++;
- removed += mark_lseg_invalid(lseg, tmp_list);
+ if (!mark_lseg_invalid(lseg, tmp_list))
+ remaining++;
}
- dprintk("%s:Return %i\n", __func__, invalid - removed);
- return invalid - removed;
+ dprintk("%s:Return %i\n", __func__, remaining);
+ return remaining;
}
/* note free_me must contain lsegs from a single layout_hdr */
@@ -618,7 +618,6 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
pnfs_get_layout_hdr(lo);
pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED);
pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED);
- pnfs_clear_retry_layoutget(lo);
spin_unlock(&nfsi->vfs_inode.i_lock);
pnfs_free_lseg_list(&tmp_list);
pnfs_put_layout_hdr(lo);
@@ -703,6 +702,8 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list,
ret = -EAGAIN;
spin_unlock(&inode->i_lock);
pnfs_free_lseg_list(&lseg_list);
+ /* Free all lsegs that are attached to commit buckets */
+ nfs_commit_inode(inode, 0);
pnfs_put_layout_hdr(lo);
iput(inode);
}
@@ -826,7 +827,7 @@ pnfs_layoutgets_blocked(const struct pnfs_layout_hdr *lo)
int
pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
- struct pnfs_layout_range *range,
+ const struct pnfs_layout_range *range,
struct nfs4_state *open_state)
{
int status = 0;
@@ -861,7 +862,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
static struct pnfs_layout_segment *
send_layoutget(struct pnfs_layout_hdr *lo,
struct nfs_open_context *ctx,
- struct pnfs_layout_range *range,
+ const struct pnfs_layout_range *range,
gfp_t gfp_flags)
{
struct inode *ino = lo->plh_inode;
@@ -894,7 +895,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
lgp->args.minlength = i_size - range->offset;
}
lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
- lgp->args.range = *range;
+ pnfs_copy_range(&lgp->args.range, range);
lgp->args.type = server->pnfs_curr_ld->id;
lgp->args.inode = ino;
lgp->args.ctx = get_nfs_open_context(ctx);
@@ -904,17 +905,9 @@ send_layoutget(struct pnfs_layout_hdr *lo,
lseg = nfs4_proc_layoutget(lgp, gfp_flags);
} while (lseg == ERR_PTR(-EAGAIN));
- if (IS_ERR(lseg)) {
- switch (PTR_ERR(lseg)) {
- case -ENOMEM:
- case -ERESTARTSYS:
- break;
- default:
- /* remember that LAYOUTGET failed and suspend trying */
- pnfs_layout_io_set_failed(lo, range->iomode);
- }
- return NULL;
- } else
+ if (IS_ERR(lseg) && !nfs_error_is_fatal(PTR_ERR(lseg)))
+ lseg = NULL;
+ else
pnfs_layout_clear_fail_bit(lo,
pnfs_iomode_to_fail_bit(range->iomode));
@@ -945,7 +938,7 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
}
static int
-pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, nfs4_stateid stateid,
+pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
enum pnfs_iomode iomode, bool sync)
{
struct inode *ino = lo->plh_inode;
@@ -962,7 +955,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, nfs4_stateid stateid,
goto out;
}
- lrp->args.stateid = stateid;
+ nfs4_stateid_copy(&lrp->args.stateid, stateid);
lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id;
lrp->args.inode = ino;
lrp->args.range.iomode = iomode;
@@ -1005,7 +998,7 @@ _pnfs_return_layout(struct inode *ino)
dprintk("NFS: %s no layout to return\n", __func__);
goto out;
}
- stateid = nfsi->layout->plh_stateid;
+ nfs4_stateid_copy(&stateid, &nfsi->layout->plh_stateid);
/* Reference matched in nfs4_layoutreturn_release */
pnfs_get_layout_hdr(lo);
empty = list_empty(&lo->plh_segs);
@@ -1033,7 +1026,7 @@ _pnfs_return_layout(struct inode *ino)
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&tmp_list);
if (send)
- status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
+ status = pnfs_send_layoutreturn(lo, &stateid, IOMODE_ANY, true);
out_put_layout_hdr:
pnfs_put_layout_hdr(lo);
out:
@@ -1096,13 +1089,12 @@ bool pnfs_roc(struct inode *ino)
goto out_noroc;
}
- stateid = lo->plh_stateid;
+ nfs4_stateid_copy(&stateid, &lo->plh_stateid);
/* always send layoutreturn if being marked so */
if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
&lo->plh_flags))
layoutreturn = pnfs_prepare_layoutreturn(lo);
- pnfs_clear_retry_layoutget(lo);
list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list)
/* If we are sending layoutreturn, invalidate all valid lsegs */
if (layoutreturn || test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
@@ -1124,7 +1116,7 @@ out_noroc:
pnfs_free_lseg_list(&tmp_list);
pnfs_layoutcommit_inode(ino, true);
if (layoutreturn)
- pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
+ pnfs_send_layoutreturn(lo, &stateid, IOMODE_ANY, true);
return roc;
}
@@ -1149,6 +1141,7 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
spin_lock(&ino->i_lock);
lo = NFS_I(ino)->layout;
+ pnfs_mark_layout_returned_if_empty(lo);
if (pnfs_seqid_is_newer(barrier, lo->plh_barrier))
lo->plh_barrier = barrier;
spin_unlock(&ino->i_lock);
@@ -1465,25 +1458,15 @@ static bool pnfs_within_mdsthreshold(struct nfs_open_context *ctx,
return ret;
}
-/* stop waiting if someone clears NFS_LAYOUT_RETRY_LAYOUTGET bit. */
-static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key, int mode)
-{
- if (!test_bit(NFS_LAYOUT_RETRY_LAYOUTGET, key->flags))
- return 1;
- return nfs_wait_bit_killable(key, mode);
-}
-
static bool pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo)
{
- if (!pnfs_should_retry_layoutget(lo))
- return false;
/*
* send layoutcommit as it can hold up layoutreturn due to lseg
* reference
*/
pnfs_layoutcommit_inode(lo->plh_inode, false);
return !wait_on_bit_action(&lo->plh_flags, NFS_LAYOUT_RETURN,
- pnfs_layoutget_retry_bit_wait,
+ nfs_wait_bit_killable,
TASK_UNINTERRUPTIBLE);
}
@@ -1520,14 +1503,23 @@ pnfs_update_layout(struct inode *ino,
struct pnfs_layout_segment *lseg = NULL;
bool first;
- if (!pnfs_enabled_sb(NFS_SERVER(ino)))
+ if (!pnfs_enabled_sb(NFS_SERVER(ino))) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+ PNFS_UPDATE_LAYOUT_NO_PNFS);
goto out;
+ }
- if (iomode == IOMODE_READ && i_size_read(ino) == 0)
+ if (iomode == IOMODE_READ && i_size_read(ino) == 0) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+ PNFS_UPDATE_LAYOUT_RD_ZEROLEN);
goto out;
+ }
- if (pnfs_within_mdsthreshold(ctx, ino, iomode))
+ if (pnfs_within_mdsthreshold(ctx, ino, iomode)) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+ PNFS_UPDATE_LAYOUT_MDSTHRESH);
goto out;
+ }
lookup_again:
first = false;
@@ -1535,19 +1527,25 @@ lookup_again:
lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
if (lo == NULL) {
spin_unlock(&ino->i_lock);
+ trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+ PNFS_UPDATE_LAYOUT_NOMEM);
goto out;
}
/* Do we even need to bother with this? */
if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+ PNFS_UPDATE_LAYOUT_BULK_RECALL);
dprintk("%s matches recall, use MDS\n", __func__);
goto out_unlock;
}
/* if LAYOUTGET already failed once we don't try again */
- if (pnfs_layout_io_test_failed(lo, iomode) &&
- !pnfs_should_retry_layoutget(lo))
+ if (pnfs_layout_io_test_failed(lo, iomode)) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+ PNFS_UPDATE_LAYOUT_IO_TEST_FAIL);
goto out_unlock;
+ }
first = list_empty(&lo->plh_segs);
if (first) {
@@ -1567,8 +1565,11 @@ lookup_again:
* already exists
*/
lseg = pnfs_find_lseg(lo, &arg);
- if (lseg)
+ if (lseg) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+ PNFS_UPDATE_LAYOUT_FOUND_CACHED);
goto out_unlock;
+ }
}
/*
@@ -1585,11 +1586,16 @@ lookup_again:
dprintk("%s retrying\n", __func__);
goto lookup_again;
}
+ trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+ PNFS_UPDATE_LAYOUT_RETURN);
goto out_put_layout_hdr;
}
- if (pnfs_layoutgets_blocked(lo))
+ if (pnfs_layoutgets_blocked(lo)) {
+ trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+ PNFS_UPDATE_LAYOUT_BLOCKED);
goto out_unlock;
+ }
atomic_inc(&lo->plh_outstanding);
spin_unlock(&ino->i_lock);
@@ -1612,8 +1618,9 @@ lookup_again:
arg.length = PAGE_CACHE_ALIGN(arg.length);
lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
- pnfs_clear_retry_layoutget(lo);
atomic_dec(&lo->plh_outstanding);
+ trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+ PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
out_put_layout_hdr:
if (first)
pnfs_clear_first_layoutget(lo);
@@ -1623,7 +1630,7 @@ out:
"(%s, offset: %llu, length: %llu)\n",
__func__, ino->i_sb->s_id,
(unsigned long long)NFS_FILEID(ino),
- lseg == NULL ? "not found" : "found",
+ IS_ERR_OR_NULL(lseg) ? "not found" : "found",
iomode==IOMODE_RW ? "read/write" : "read-only",
(unsigned long long)pos,
(unsigned long long)count);
@@ -1730,16 +1737,29 @@ out_forget_reply:
}
static void
+pnfs_set_plh_return_iomode(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode)
+{
+ if (lo->plh_return_iomode == iomode)
+ return;
+ if (lo->plh_return_iomode != 0)
+ iomode = IOMODE_ANY;
+ lo->plh_return_iomode = iomode;
+}
+
+int
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
struct list_head *tmp_list,
- struct pnfs_layout_range *return_range)
+ const struct pnfs_layout_range *return_range)
{
struct pnfs_layout_segment *lseg, *next;
+ int remaining = 0;
dprintk("%s:Begin lo %p\n", __func__, lo);
if (list_empty(&lo->plh_segs))
- return;
+ return 0;
+
+ assert_spin_locked(&lo->plh_inode->i_lock);
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
if (should_free_lseg(&lseg->pls_range, return_range)) {
@@ -1749,38 +1769,47 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
lseg->pls_range.offset,
lseg->pls_range.length);
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
- mark_lseg_invalid(lseg, tmp_list);
+ pnfs_set_plh_return_iomode(lo, return_range->iomode);
+ if (!mark_lseg_invalid(lseg, tmp_list))
+ remaining++;
set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
&lo->plh_flags);
}
+ return remaining;
}
void pnfs_error_mark_layout_for_return(struct inode *inode,
struct pnfs_layout_segment *lseg)
{
struct pnfs_layout_hdr *lo = NFS_I(inode)->layout;
- int iomode = pnfs_iomode_to_fail_bit(lseg->pls_range.iomode);
struct pnfs_layout_range range = {
.iomode = lseg->pls_range.iomode,
.offset = 0,
.length = NFS4_MAX_UINT64,
};
LIST_HEAD(free_me);
+ bool return_now = false;
spin_lock(&inode->i_lock);
- /* set failure bit so that pnfs path will be retried later */
- pnfs_layout_set_fail_bit(lo, iomode);
- if (lo->plh_return_iomode == 0)
- lo->plh_return_iomode = range.iomode;
- else if (lo->plh_return_iomode != range.iomode)
- lo->plh_return_iomode = IOMODE_ANY;
+ pnfs_set_plh_return_iomode(lo, range.iomode);
/*
* mark all matching lsegs so that we are sure to have no live
* segments at hand when sending layoutreturn. See pnfs_put_lseg()
* for how it works.
*/
- pnfs_mark_matching_lsegs_return(lo, &free_me, &range);
- spin_unlock(&inode->i_lock);
+ if (!pnfs_mark_matching_lsegs_return(lo, &free_me, &range)) {
+ nfs4_stateid stateid;
+ enum pnfs_iomode iomode = lo->plh_return_iomode;
+
+ nfs4_stateid_copy(&stateid, &lo->plh_stateid);
+ return_now = pnfs_prepare_layoutreturn(lo);
+ spin_unlock(&inode->i_lock);
+ if (return_now)
+ pnfs_send_layoutreturn(lo, &stateid, iomode, false);
+ } else {
+ spin_unlock(&inode->i_lock);
+ nfs_commit_inode(inode, 0);
+ }
pnfs_free_lseg_list(&free_me);
}
EXPORT_SYMBOL_GPL(pnfs_error_mark_layout_for_return);
@@ -1802,6 +1831,11 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
rd_size,
IOMODE_READ,
GFP_KERNEL);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ return;
+ }
}
/* If no lseg, fall back to read through mds */
if (pgio->pg_lseg == NULL)
@@ -1814,13 +1848,19 @@ void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
{
- if (pgio->pg_lseg == NULL)
+ if (pgio->pg_lseg == NULL) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
req_offset(req),
wb_size,
IOMODE_RW,
GFP_NOFS);
+ if (IS_ERR(pgio->pg_lseg)) {
+ pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+ pgio->pg_lseg = NULL;
+ return;
+ }
+ }
/* If no lseg, fall back to write through mds */
if (pgio->pg_lseg == NULL)
nfs_pageio_reset_write_mds(pgio);
@@ -1988,15 +2028,13 @@ static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
int
pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
{
- struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
-
struct nfs_pgio_header *hdr;
int ret;
hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
if (!hdr) {
- desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
- return -ENOMEM;
+ desc->pg_error = -ENOMEM;
+ return desc->pg_error;
}
nfs_pgheader_init(desc, hdr, pnfs_writehdr_free);
@@ -2119,15 +2157,13 @@ static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
int
pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
{
- struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
-
struct nfs_pgio_header *hdr;
int ret;
hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
if (!hdr) {
- desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
- return -ENOMEM;
+ desc->pg_error = -ENOMEM;
+ return desc->pg_error;
}
nfs_pgheader_init(desc, hdr, pnfs_readhdr_free);
hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index d1990e90e7a0..9f4e2a47f4aa 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -98,7 +98,6 @@ enum {
NFS_LAYOUT_RETURN_BEFORE_CLOSE, /* Return this layout before close */
NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */
NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */
- NFS_LAYOUT_RETRY_LAYOUTGET, /* Retry layoutget */
};
enum layoutdriver_policy_flags {
@@ -261,11 +260,14 @@ void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo,
bool update_barrier);
int pnfs_choose_layoutget_stateid(nfs4_stateid *dst,
struct pnfs_layout_hdr *lo,
- struct pnfs_layout_range *range,
+ const struct pnfs_layout_range *range,
struct nfs4_state *open_state);
int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
struct list_head *tmp_list,
- struct pnfs_layout_range *recall_range);
+ const struct pnfs_layout_range *recall_range);
+int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
+ struct list_head *tmp_list,
+ const struct pnfs_layout_range *recall_range);
bool pnfs_roc(struct inode *ino);
void pnfs_roc_release(struct inode *ino);
void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
@@ -379,26 +381,6 @@ nfs4_get_deviceid(struct nfs4_deviceid_node *d)
return d;
}
-static inline void pnfs_set_retry_layoutget(struct pnfs_layout_hdr *lo)
-{
- if (!test_and_set_bit(NFS_LAYOUT_RETRY_LAYOUTGET, &lo->plh_flags))
- atomic_inc(&lo->plh_refcount);
-}
-
-static inline void pnfs_clear_retry_layoutget(struct pnfs_layout_hdr *lo)
-{
- if (test_and_clear_bit(NFS_LAYOUT_RETRY_LAYOUTGET, &lo->plh_flags)) {
- atomic_dec(&lo->plh_refcount);
- /* wake up waiters for LAYOUTRETURN as that is not needed */
- wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN);
- }
-}
-
-static inline bool pnfs_should_retry_layoutget(struct pnfs_layout_hdr *lo)
-{
- return test_bit(NFS_LAYOUT_RETRY_LAYOUTGET, &lo->plh_flags);
-}
-
static inline struct pnfs_layout_segment *
pnfs_get_lseg(struct pnfs_layout_segment *lseg)
{
@@ -409,6 +391,12 @@ pnfs_get_lseg(struct pnfs_layout_segment *lseg)
return lseg;
}
+static inline bool
+pnfs_is_valid_lseg(struct pnfs_layout_segment *lseg)
+{
+ return test_bit(NFS_LSEG_VALID, &lseg->pls_flags) != 0;
+}
+
/* Return true if a layout driver is being used for this mountpoint */
static inline int pnfs_enabled_sb(struct nfs_server *nfss)
{
@@ -556,6 +544,26 @@ pnfs_calc_offset_length(u64 offset, u64 end)
return 1 + end - offset;
}
+/**
+ * pnfs_mark_layout_returned_if_empty - marks the layout as returned
+ * @lo: layout header
+ *
+ * Note: Caller must hold inode->i_lock
+ */
+static inline void
+pnfs_mark_layout_returned_if_empty(struct pnfs_layout_hdr *lo)
+{
+ if (list_empty(&lo->plh_segs))
+ set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+}
+
+static inline void
+pnfs_copy_range(struct pnfs_layout_range *dst,
+ const struct pnfs_layout_range *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
extern unsigned int layoutstats_timer;
#ifdef NFS_DEBUG
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
index 24655b807d44..81ac6480f9e7 100644
--- a/fs/nfs/pnfs_nfs.c
+++ b/fs/nfs/pnfs_nfs.c
@@ -266,17 +266,14 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
} else {
nfs_retry_commit(mds_pages, NULL, cinfo, 0);
pnfs_generic_retry_commit(cinfo, 0);
- cinfo->completion_ops->error_cleanup(NFS_I(inode));
return -ENOMEM;
}
}
nreq += pnfs_generic_alloc_ds_commits(cinfo, &list);
- if (nreq == 0) {
- cinfo->completion_ops->error_cleanup(NFS_I(inode));
+ if (nreq == 0)
goto out;
- }
atomic_add(nreq, &cinfo->mds->rpcs_out);
@@ -871,6 +868,11 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
buckets = cinfo->ds->buckets;
list = &buckets[ds_commit_idx].written;
if (list_empty(list)) {
+ if (!pnfs_is_valid_lseg(lseg)) {
+ spin_unlock(cinfo->lock);
+ cinfo->completion_ops->resched_write(cinfo, req);
+ return;
+ }
/* Non-empty buckets hold a reference on the lseg. That ref
* is normally transferred to the COMMIT call and released
* there. It could also be released if the last req is pulled
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 0a5e33f33b5c..eb31e23e7def 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -85,6 +85,23 @@ void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
}
EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
+static void nfs_readpage_release(struct nfs_page *req)
+{
+ struct inode *inode = d_inode(req->wb_context->dentry);
+
+ dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id,
+ (unsigned long long)NFS_FILEID(inode), req->wb_bytes,
+ (long long)req_offset(req));
+
+ if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) {
+ if (PageUptodate(req->wb_page))
+ nfs_readpage_to_fscache(inode, req->wb_page, 0);
+
+ unlock_page(req->wb_page);
+ }
+ nfs_release_request(req);
+}
+
int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
struct page *page)
{
@@ -106,7 +123,10 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
nfs_pageio_init_read(&pgio, inode, false,
&nfs_async_read_completion_ops);
- nfs_pageio_add_request(&pgio, new);
+ if (!nfs_pageio_add_request(&pgio, new)) {
+ nfs_list_remove_request(new);
+ nfs_readpage_release(new);
+ }
nfs_pageio_complete(&pgio);
/* It doesn't make sense to do mirrored reads! */
@@ -115,24 +135,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
pgm = &pgio.pg_mirrors[0];
NFS_I(inode)->read_io += pgm->pg_bytes_written;
- return 0;
-}
-
-static void nfs_readpage_release(struct nfs_page *req)
-{
- struct inode *inode = d_inode(req->wb_context->dentry);
-
- dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id,
- (unsigned long long)NFS_FILEID(inode), req->wb_bytes,
- (long long)req_offset(req));
-
- if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) {
- if (PageUptodate(req->wb_page))
- nfs_readpage_to_fscache(inode, req->wb_page, 0);
-
- unlock_page(req->wb_page);
- }
- nfs_release_request(req);
+ return pgio.pg_error < 0 ? pgio.pg_error : 0;
}
static void nfs_page_group_set_uptodate(struct nfs_page *req)
@@ -361,6 +364,8 @@ readpage_async_filler(void *data, struct page *page)
if (len < PAGE_CACHE_SIZE)
zero_user_segment(page, len, PAGE_CACHE_SIZE);
if (!nfs_pageio_add_request(desc->pgio, new)) {
+ nfs_list_remove_request(new);
+ nfs_readpage_release(new);
error = desc->pgio->pg_error;
goto out_unlock;
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 7b9316406930..ce43cd6d88c6 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -21,6 +21,8 @@
#include <linux/nfs_page.h>
#include <linux/backing-dev.h>
#include <linux/export.h>
+#include <linux/freezer.h>
+#include <linux/wait.h>
#include <asm/uaccess.h>
@@ -244,11 +246,9 @@ static int wb_priority(struct writeback_control *wbc)
{
int ret = 0;
if (wbc->for_reclaim)
- return FLUSH_HIGHPRI | FLUSH_STABLE;
+ return FLUSH_HIGHPRI | FLUSH_COND_STABLE;
if (wbc->sync_mode == WB_SYNC_ALL)
ret = FLUSH_COND_STABLE;
- if (wbc->for_kupdate || wbc->for_background)
- ret |= FLUSH_LOWPRI;
return ret;
}
@@ -545,12 +545,22 @@ try_again:
return head;
}
+static void nfs_write_error_remove_page(struct nfs_page *req)
+{
+ nfs_unlock_request(req);
+ nfs_end_page_writeback(req);
+ nfs_release_request(req);
+ generic_error_remove_page(page_file_mapping(req->wb_page),
+ req->wb_page);
+}
+
/*
* Find an associated nfs write request, and prepare to flush it out
* May return an error if the user signalled nfs_wait_on_request().
*/
static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
- struct page *page, bool nonblock)
+ struct page *page, bool nonblock,
+ bool launder)
{
struct nfs_page *req;
int ret = 0;
@@ -567,8 +577,21 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
ret = 0;
if (!nfs_pageio_add_request(pgio, req)) {
- nfs_redirty_request(req);
ret = pgio->pg_error;
+ /*
+ * Remove the problematic req upon fatal errors
+ * in launder case, while other dirty pages can
+ * still be around until they get flushed.
+ */
+ if (nfs_error_is_fatal(ret)) {
+ nfs_context_set_write_error(req->wb_context, ret);
+ if (launder) {
+ nfs_write_error_remove_page(req);
+ goto out;
+ }
+ }
+ nfs_redirty_request(req);
+ ret = -EAGAIN;
} else
nfs_add_stats(page_file_mapping(page)->host,
NFSIOS_WRITEPAGES, 1);
@@ -576,12 +599,14 @@ out:
return ret;
}
-static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
+static int nfs_do_writepage(struct page *page, struct writeback_control *wbc,
+ struct nfs_pageio_descriptor *pgio, bool launder)
{
int ret;
nfs_pageio_cond_complete(pgio, page_file_index(page));
- ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
+ ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE,
+ launder);
if (ret == -EAGAIN) {
redirty_page_for_writepage(wbc, page);
ret = 0;
@@ -592,7 +617,9 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, st
/*
* Write an mmapped page to the server.
*/
-static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+static int nfs_writepage_locked(struct page *page,
+ struct writeback_control *wbc,
+ bool launder)
{
struct nfs_pageio_descriptor pgio;
struct inode *inode = page_file_mapping(page)->host;
@@ -601,7 +628,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc),
false, &nfs_async_write_completion_ops);
- err = nfs_do_writepage(page, wbc, &pgio);
+ err = nfs_do_writepage(page, wbc, &pgio, launder);
nfs_pageio_complete(&pgio);
if (err < 0)
return err;
@@ -614,7 +641,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
{
int ret;
- ret = nfs_writepage_locked(page, wbc);
+ ret = nfs_writepage_locked(page, wbc, false);
unlock_page(page);
return ret;
}
@@ -623,7 +650,7 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
{
int ret;
- ret = nfs_do_writepage(page, wbc, data);
+ ret = nfs_do_writepage(page, wbc, data, false);
unlock_page(page);
return ret;
}
@@ -1128,7 +1155,8 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
if (req == NULL)
return 0;
l_ctx = req->wb_lock_context;
- do_flush = req->wb_page != page || req->wb_context != ctx;
+ do_flush = req->wb_page != page ||
+ !nfs_match_open_context(req->wb_context, ctx);
/* for now, flush if more than 1 request in page_group */
do_flush |= req->wb_this_page != req;
if (l_ctx && flctx &&
@@ -1326,9 +1354,15 @@ static void nfs_async_write_error(struct list_head *head)
}
}
+static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr)
+{
+ nfs_async_write_error(&hdr->pages);
+}
+
static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = {
.error_cleanup = nfs_async_write_error,
.completion = nfs_write_completion,
+ .reschedule_io = nfs_async_write_reschedule_io,
};
void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
@@ -1529,27 +1563,21 @@ static void nfs_writeback_result(struct rpc_task *task,
}
}
-
-static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait)
+static int wait_on_commit(struct nfs_mds_commit_info *cinfo)
{
- int ret;
+ return wait_on_atomic_t(&cinfo->rpcs_out,
+ nfs_wait_atomic_killable, TASK_KILLABLE);
+}
- if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags))
- return 1;
- if (!may_wait)
- return 0;
- ret = out_of_line_wait_on_bit_lock(&nfsi->flags,
- NFS_INO_COMMIT,
- nfs_wait_bit_killable,
- TASK_KILLABLE);
- return (ret < 0) ? ret : 1;
+static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
+{
+ atomic_inc(&cinfo->rpcs_out);
}
-static void nfs_commit_clear_lock(struct nfs_inode *nfsi)
+static void nfs_commit_end(struct nfs_mds_commit_info *cinfo)
{
- clear_bit(NFS_INO_COMMIT, &nfsi->flags);
- smp_mb__after_atomic();
- wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
+ if (atomic_dec_and_test(&cinfo->rpcs_out))
+ wake_up_atomic_t(&cinfo->rpcs_out);
}
void nfs_commitdata_release(struct nfs_commit_data *data)
@@ -1666,6 +1694,13 @@ void nfs_retry_commit(struct list_head *page_list,
}
EXPORT_SYMBOL_GPL(nfs_retry_commit);
+static void
+nfs_commit_resched_write(struct nfs_commit_info *cinfo,
+ struct nfs_page *req)
+{
+ __set_page_dirty_nobuffers(req->wb_page);
+}
+
/*
* Commit dirty pages
*/
@@ -1687,7 +1722,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
data->mds_ops, how, 0);
out_bad:
nfs_retry_commit(head, NULL, cinfo, 0);
- cinfo->completion_ops->error_cleanup(NFS_I(inode));
return -ENOMEM;
}
@@ -1749,8 +1783,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
nfs_init_cinfo(&cinfo, data->inode, data->dreq);
- if (atomic_dec_and_test(&cinfo.mds->rpcs_out))
- nfs_commit_clear_lock(NFS_I(data->inode));
+ nfs_commit_end(cinfo.mds);
}
static void nfs_commit_release(void *calldata)
@@ -1769,7 +1802,7 @@ static const struct rpc_call_ops nfs_commit_ops = {
static const struct nfs_commit_completion_ops nfs_commit_completion_ops = {
.completion = nfs_commit_release_pages,
- .error_cleanup = nfs_commit_clear_lock,
+ .resched_write = nfs_commit_resched_write,
};
int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
@@ -1788,30 +1821,25 @@ int nfs_commit_inode(struct inode *inode, int how)
LIST_HEAD(head);
struct nfs_commit_info cinfo;
int may_wait = how & FLUSH_SYNC;
+ int error = 0;
int res;
- res = nfs_commit_set_lock(NFS_I(inode), may_wait);
- if (res <= 0)
- goto out_mark_dirty;
nfs_init_cinfo_from_inode(&cinfo, inode);
+ nfs_commit_begin(cinfo.mds);
res = nfs_scan_commit(inode, &head, &cinfo);
- if (res) {
- int error;
-
+ if (res)
error = nfs_generic_commit_list(inode, &head, how, &cinfo);
- if (error < 0)
- return error;
- if (!may_wait)
- goto out_mark_dirty;
- error = wait_on_bit_action(&NFS_I(inode)->flags,
- NFS_INO_COMMIT,
- nfs_wait_bit_killable,
- TASK_KILLABLE);
- if (error < 0)
- return error;
- } else
- nfs_commit_clear_lock(NFS_I(inode));
+ nfs_commit_end(cinfo.mds);
+ if (error < 0)
+ goto out_error;
+ if (!may_wait)
+ goto out_mark_dirty;
+ error = wait_on_commit(cinfo.mds);
+ if (error < 0)
+ return error;
return res;
+out_error:
+ res = error;
/* Note: If we exit without ensuring that the commit is complete,
* we must mark the inode as dirty. Otherwise, future calls to
* sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
@@ -1821,6 +1849,7 @@ out_mark_dirty:
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
return res;
}
+EXPORT_SYMBOL_GPL(nfs_commit_inode);
int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
@@ -1911,7 +1940,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
/*
* Write back all requests on one page - we do this before reading it.
*/
-int nfs_wb_page(struct inode *inode, struct page *page)
+int nfs_wb_single_page(struct inode *inode, struct page *page, bool launder)
{
loff_t range_start = page_file_offset(page);
loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);
@@ -1928,7 +1957,7 @@ int nfs_wb_page(struct inode *inode, struct page *page)
for (;;) {
wait_on_page_writeback(page);
if (clear_page_dirty_for_io(page)) {
- ret = nfs_writepage_locked(page, &wbc);
+ ret = nfs_writepage_locked(page, &wbc, launder);
if (ret < 0)
goto out_error;
continue;
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 77e7a5cca888..1a03bc3059e8 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -58,7 +58,7 @@ nlm_fclose(struct file *filp)
fput(filp);
}
-static struct nlmsvc_binding nfsd_nlm_ops = {
+static const struct nlmsvc_binding nfsd_nlm_ops = {
.fopen = nlm_fopen, /* open file for locking */
.fclose = nlm_fclose, /* close file */
};
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index d8b16c2568f3..5fbf3bbd00d0 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -92,7 +92,7 @@ struct nfsd_net {
struct file *rec_file;
bool in_grace;
- struct nfsd4_client_tracking_ops *client_tracking_ops;
+ const struct nfsd4_client_tracking_ops *client_tracking_ops;
time_t nfsd4_lease;
time_t nfsd4_grace;
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index e7f50c4081d6..7389cb1d7409 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -792,12 +792,16 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
{
+ if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags))
+ return;
clp->cl_cb_state = NFSD4_CB_DOWN;
warn_no_callback_path(clp, reason);
}
static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
{
+ if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags))
+ return;
clp->cl_cb_state = NFSD4_CB_FAULT;
warn_no_callback_path(clp, reason);
}
@@ -1143,7 +1147,7 @@ nfsd4_run_cb_work(struct work_struct *work)
}
void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
- struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op)
+ const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op)
{
cb->cb_clp = clp;
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op];
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index c9d6c715c0fb..ce2d010d3b17 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -22,7 +22,7 @@ struct nfs4_layout {
static struct kmem_cache *nfs4_layout_cache;
static struct kmem_cache *nfs4_layout_stateid_cache;
-static struct nfsd4_callback_ops nfsd4_cb_layout_ops;
+static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
static const struct lock_manager_operations nfsd4_layouts_lm_ops;
const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = {
@@ -624,24 +624,39 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
{
struct nfs4_layout_stateid *ls =
container_of(cb, struct nfs4_layout_stateid, ls_recall);
+ struct nfsd_net *nn;
+ ktime_t now, cutoff;
LIST_HEAD(reaplist);
+
switch (task->tk_status) {
case 0:
- return 1;
+ case -NFS4ERR_DELAY:
+ /*
+ * Anything left? If not, then call it done. Note that we don't
+ * take the spinlock since this is an optimization and nothing
+ * should get added until the cb counter goes to zero.
+ */
+ if (list_empty(&ls->ls_layouts))
+ return 1;
+
+ /* Poll the client until it's done with the layout */
+ now = ktime_get();
+ nn = net_generic(ls->ls_stid.sc_client->net, nfsd_net_id);
+
+ /* Client gets 2 lease periods to return it */
+ cutoff = ktime_add_ns(task->tk_start,
+ nn->nfsd4_lease * NSEC_PER_SEC * 2);
+
+ if (ktime_before(now, cutoff)) {
+ rpc_delay(task, HZ/100); /* 10 mili-seconds */
+ return 0;
+ }
+ /* Fallthrough */
case -NFS4ERR_NOMATCHING_LAYOUT:
trace_layout_recall_done(&ls->ls_stid.sc_stateid);
task->tk_status = 0;
return 1;
- case -NFS4ERR_DELAY:
- /* Poll the client until it's done with the layout */
- /* FIXME: cap number of retries.
- * The pnfs standard states that we need to only expire
- * the client after at-least "lease time" .eg lease-time * 2
- * when failing to communicate a recall
- */
- rpc_delay(task, HZ/100); /* 10 mili-seconds */
- return 0;
default:
/*
* Unknown error or non-responding client, we'll need to fence.
@@ -665,7 +680,7 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
nfs4_put_stid(&ls->ls_stid);
}
-static struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
+static const struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
.prepare = nfsd4_cb_layout_prepare,
.done = nfsd4_cb_layout_done,
.release = nfsd4_cb_layout_release,
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index e3d47091b191..79f0307a5ec8 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -631,7 +631,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
return -ENOENT;
}
-static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
+static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
.init = nfsd4_legacy_tracking_init,
.exit = nfsd4_legacy_tracking_exit,
.create = nfsd4_create_clid_dir,
@@ -1050,7 +1050,7 @@ out_err:
printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
}
-static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
+static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
.init = nfsd4_init_cld_pipe,
.exit = nfsd4_remove_cld_pipe,
.create = nfsd4_cld_create,
@@ -1394,7 +1394,7 @@ nfsd4_umh_cltrack_grace_done(struct nfsd_net *nn)
kfree(legacy);
}
-static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
+static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
.init = nfsd4_umh_cltrack_init,
.exit = NULL,
.create = nfsd4_umh_cltrack_create,
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index df5dba687265..c484a2b6cd10 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -98,7 +98,7 @@ static struct kmem_cache *odstate_slab;
static void free_session(struct nfsd4_session *);
-static struct nfsd4_callback_ops nfsd4_cb_recall_ops;
+static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
static bool is_session_dead(struct nfsd4_session *ses)
{
@@ -1857,15 +1857,28 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
target->cl_clientid.cl_id = source->cl_clientid.cl_id;
}
-static int copy_cred(struct svc_cred *target, struct svc_cred *source)
+int strdup_if_nonnull(char **target, char *source)
{
- if (source->cr_principal) {
- target->cr_principal =
- kstrdup(source->cr_principal, GFP_KERNEL);
- if (target->cr_principal == NULL)
+ if (source) {
+ *target = kstrdup(source, GFP_KERNEL);
+ if (!*target)
return -ENOMEM;
} else
- target->cr_principal = NULL;
+ *target = NULL;
+ return 0;
+}
+
+static int copy_cred(struct svc_cred *target, struct svc_cred *source)
+{
+ int ret;
+
+ ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal);
+ if (ret)
+ return ret;
+ ret = strdup_if_nonnull(&target->cr_raw_principal,
+ source->cr_raw_principal);
+ if (ret)
+ return ret;
target->cr_flavor = source->cr_flavor;
target->cr_uid = source->cr_uid;
target->cr_gid = source->cr_gid;
@@ -1969,6 +1982,9 @@ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
return false;
if (!svc_rqst_integrity_protected(rqstp))
return false;
+ if (cl->cl_cred.cr_raw_principal)
+ return 0 == strcmp(cl->cl_cred.cr_raw_principal,
+ cr->cr_raw_principal);
if (!cr->cr_principal)
return false;
return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
@@ -2240,7 +2256,8 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
base = resp->cstate.data_offset;
slot->sl_datalen = buf->len - base;
if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
- WARN("%s: sessions DRC could not cache compound\n", __func__);
+ WARN(1, "%s: sessions DRC could not cache compound\n",
+ __func__);
return;
}
@@ -2365,10 +2382,27 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
return nfserr_inval;
+ new = create_client(exid->clname, rqstp, &verf);
+ if (new == NULL)
+ return nfserr_jukebox;
+
switch (exid->spa_how) {
case SP4_MACH_CRED:
- if (!svc_rqst_integrity_protected(rqstp))
- return nfserr_inval;
+ if (!svc_rqst_integrity_protected(rqstp)) {
+ status = nfserr_inval;
+ goto out_nolock;
+ }
+ /*
+ * Sometimes userspace doesn't give us a principal.
+ * Which is a bug, really. Anyway, we can't enforce
+ * MACH_CRED in that case, better to give up now:
+ */
+ if (!new->cl_cred.cr_principal &&
+ !new->cl_cred.cr_raw_principal) {
+ status = nfserr_serverfault;
+ goto out_nolock;
+ }
+ new->cl_mach_cred = true;
case SP4_NONE:
break;
default: /* checked by xdr code */
@@ -2377,10 +2411,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
return nfserr_encr_alg_unsupp;
}
- new = create_client(exid->clname, rqstp, &verf);
- if (new == NULL)
- return nfserr_jukebox;
-
/* Cases below refer to rfc 5661 section 18.35.4: */
spin_lock(&nn->client_lock);
conf = find_confirmed_client_by_name(&exid->clname, nn);
@@ -2442,7 +2472,6 @@ out_new:
goto out;
}
new->cl_minorversion = cstate->minorversion;
- new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
gen_clid(new, nn);
add_to_unconfirmed(new);
@@ -2460,6 +2489,7 @@ out_copy:
out:
spin_unlock(&nn->client_lock);
+out_nolock:
if (new)
expire_client(new);
if (unconf)
@@ -3648,7 +3678,7 @@ static void nfsd4_cb_recall_release(struct nfsd4_callback *cb)
nfs4_put_stid(&dp->dl_stid);
}
-static struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
+static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
.prepare = nfsd4_cb_recall_prepare,
.done = nfsd4_cb_recall_done,
.release = nfsd4_cb_recall_release,
@@ -4541,8 +4571,7 @@ static void
laundromat_main(struct work_struct *laundry)
{
time_t t;
- struct delayed_work *dwork = container_of(laundry, struct delayed_work,
- work);
+ struct delayed_work *dwork = to_delayed_work(laundry);
struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
laundromat_work);
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 2087bae17582..0770bcb543c8 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -7,6 +7,7 @@
#ifndef _LINUX_NFSD_NFSFH_H
#define _LINUX_NFSD_NFSFH_H
+#include <linux/crc32.h>
#include <linux/sunrpc/svc.h>
#include <uapi/linux/nfsd/nfsfh.h>
@@ -205,6 +206,28 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
return true;
}
+#ifdef CONFIG_CRC32
+/**
+ * knfsd_fh_hash - calculate the crc32 hash for the filehandle
+ * @fh - pointer to filehandle
+ *
+ * returns a crc32 hash for the filehandle that is compatible with
+ * the one displayed by "wireshark".
+ */
+
+static inline u32
+knfsd_fh_hash(struct knfsd_fh *fh)
+{
+ return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size);
+}
+#else
+static inline u32
+knfsd_fh_hash(struct knfsd_fh *fh)
+{
+ return 0;
+}
+#endif
+
#ifdef CONFIG_NFSD_V3
/*
* The wcc data stored in current_fh should be cleared
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ad4e2377dd63..45007acaf364 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -14,9 +14,13 @@
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/svc_xprt.h>
#include <linux/lockd/bind.h>
#include <linux/nfsacl.h>
#include <linux/seq_file.h>
+#include <linux/inetdevice.h>
+#include <net/addrconf.h>
+#include <net/ipv6.h>
#include <net/net_namespace.h>
#include "nfsd.h"
#include "cache.h"
@@ -306,22 +310,81 @@ static void nfsd_shutdown_net(struct net *net)
nfsd_shutdown_generic();
}
+static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct net *net = dev_net(dev);
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct sockaddr_in sin;
+
+ if (event != NETDEV_DOWN)
+ goto out;
+
+ if (nn->nfsd_serv) {
+ dprintk("nfsd_inetaddr_event: removed %pI4\n", &ifa->ifa_local);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ifa->ifa_local;
+ svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin);
+ }
+
+out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block nfsd_inetaddr_notifier = {
+ .notifier_call = nfsd_inetaddr_event,
+};
+
+#if IS_ENABLED(CONFIG_IPV6)
+static int nfsd_inet6addr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+ struct net_device *dev = ifa->idev->dev;
+ struct net *net = dev_net(dev);
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct sockaddr_in6 sin6;
+
+ if (event != NETDEV_DOWN)
+ goto out;
+
+ if (nn->nfsd_serv) {
+ dprintk("nfsd_inet6addr_event: removed %pI6\n", &ifa->addr);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = ifa->addr;
+ svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6);
+ }
+
+out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block nfsd_inet6addr_notifier = {
+ .notifier_call = nfsd_inet6addr_event,
+};
+#endif
+
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
+#if IS_ENABLED(CONFIG_IPV6)
+ unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
+#endif
/*
* write_ports can create the server without actually starting
* any threads--if we get shut down before any threads are
* started, then nfsd_last_thread will be run before any of this
- * other initialization has been done.
+ * other initialization has been done except the rpcb information.
*/
+ svc_rpcb_cleanup(serv, net);
if (!nn->nfsd_net_up)
return;
- nfsd_shutdown_net(net);
-
- svc_rpcb_cleanup(serv, net);
+ nfsd_shutdown_net(net);
printk(KERN_WARNING "nfsd: last server has exited, flushing export "
"cache\n");
nfsd_export_flush(net);
@@ -425,6 +488,10 @@ int nfsd_create_serv(struct net *net)
}
set_max_drc();
+ register_inetaddr_notifier(&nfsd_inetaddr_notifier);
+#if IS_ENABLED(CONFIG_IPV6)
+ register_inet6addr_notifier(&nfsd_inet6addr_notifier);
+#endif
do_gettimeofday(&nn->nfssvc_boot); /* record boot time */
return 0;
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 99432b7ecb9c..c050c53036a6 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -65,7 +65,7 @@ struct nfsd4_callback {
struct nfs4_client *cb_clp;
u32 cb_minorversion;
struct rpc_message cb_msg;
- struct nfsd4_callback_ops *cb_ops;
+ const struct nfsd4_callback_ops *cb_ops;
struct work_struct cb_work;
int cb_seq_status;
int cb_status;
@@ -599,7 +599,7 @@ extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
- struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
+ const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
extern void nfsd4_run_cb(struct nfsd4_callback *cb);
extern int nfsd4_create_callback_queue(void);
extern void nfsd4_destroy_callback_queue(void);
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 0befe762762b..3287041905da 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -8,6 +8,47 @@
#define _NFSD_TRACE_H
#include <linux/tracepoint.h>
+#include "nfsfh.h"
+
+DECLARE_EVENT_CLASS(nfsd_io_class,
+ TP_PROTO(struct svc_rqst *rqstp,
+ struct svc_fh *fhp,
+ loff_t offset,
+ int len),
+ TP_ARGS(rqstp, fhp, offset, len),
+ TP_STRUCT__entry(
+ __field(__be32, xid)
+ __field_struct(struct knfsd_fh, fh)
+ __field(loff_t, offset)
+ __field(int, len)
+ ),
+ TP_fast_assign(
+ __entry->xid = rqstp->rq_xid,
+ fh_copy_shallow(&__entry->fh, &fhp->fh_handle);
+ __entry->offset = offset;
+ __entry->len = len;
+ ),
+ TP_printk("xid=0x%x fh=0x%x offset=%lld len=%d",
+ __be32_to_cpu(__entry->xid), knfsd_fh_hash(&__entry->fh),
+ __entry->offset, __entry->len)
+)
+
+#define DEFINE_NFSD_IO_EVENT(name) \
+DEFINE_EVENT(nfsd_io_class, name, \
+ TP_PROTO(struct svc_rqst *rqstp, \
+ struct svc_fh *fhp, \
+ loff_t offset, \
+ int len), \
+ TP_ARGS(rqstp, fhp, offset, len))
+
+DEFINE_NFSD_IO_EVENT(read_start);
+DEFINE_NFSD_IO_EVENT(read_opened);
+DEFINE_NFSD_IO_EVENT(read_io_done);
+DEFINE_NFSD_IO_EVENT(read_done);
+DEFINE_NFSD_IO_EVENT(write_start);
+DEFINE_NFSD_IO_EVENT(write_opened);
+DEFINE_NFSD_IO_EVENT(write_io_done);
+DEFINE_NFSD_IO_EVENT(write_done);
#include "state.h"
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index d41c149fae75..6739077f17fe 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -43,6 +43,7 @@
#include "nfsd.h"
#include "vfs.h"
+#include "trace.h"
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
@@ -997,16 +998,23 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct raparms *ra;
__be32 err;
+ trace_read_start(rqstp, fhp, offset, vlen);
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
if (err)
return err;
ra = nfsd_init_raparms(file);
+
+ trace_read_opened(rqstp, fhp, offset, vlen);
err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
+ trace_read_io_done(rqstp, fhp, offset, vlen);
+
if (ra)
nfsd_put_raparams(file, ra);
fput(file);
+ trace_read_done(rqstp, fhp, offset, vlen);
+
return err;
}
@@ -1022,24 +1030,31 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
{
__be32 err = 0;
+ trace_write_start(rqstp, fhp, offset, vlen);
+
if (file) {
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE);
if (err)
goto out;
+ trace_write_opened(rqstp, fhp, offset, vlen);
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
stablep);
+ trace_write_io_done(rqstp, fhp, offset, vlen);
} else {
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
if (err)
goto out;
+ trace_write_opened(rqstp, fhp, offset, vlen);
if (cnt)
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,
cnt, stablep);
+ trace_write_io_done(rqstp, fhp, offset, vlen);
fput(file);
}
out:
+ trace_write_done(rqstp, fhp, offset, vlen);
return err;
}
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index c7343844e6b6..7f5d3d9f1c37 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1416,7 +1416,8 @@ static int __init nilfs_init_cachep(void)
{
nilfs_inode_cachep = kmem_cache_create("nilfs2_inode_cache",
sizeof(struct nilfs_inode_info), 0,
- SLAB_RECLAIM_ACCOUNT, nilfs_inode_init_once);
+ SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,
+ nilfs_inode_init_once);
if (!nilfs_inode_cachep)
goto fail;
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index e785fd954c30..741077deef3b 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -199,8 +199,7 @@ void fsnotify_unmount_inodes(struct super_block *sb)
break;
}
spin_unlock(&next_i->i_lock);
- next_i = list_entry(next_i->i_sb_list.next,
- struct inode, i_sb_list);
+ next_i = list_next_entry(next_i, i_sb_list);
}
/*
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index fc0df4442f7b..cfcbf114676e 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -92,9 +92,6 @@
#include "fsnotify.h"
struct srcu_struct fsnotify_mark_srcu;
-static DEFINE_SPINLOCK(destroy_lock);
-static LIST_HEAD(destroy_list);
-static DECLARE_WAIT_QUEUE_HEAD(destroy_waitq);
void fsnotify_get_mark(struct fsnotify_mark *mark)
{
@@ -168,10 +165,19 @@ void fsnotify_detach_mark(struct fsnotify_mark *mark)
atomic_dec(&group->num_marks);
}
+static void
+fsnotify_mark_free_rcu(struct rcu_head *rcu)
+{
+ struct fsnotify_mark *mark;
+
+ mark = container_of(rcu, struct fsnotify_mark, g_rcu);
+ fsnotify_put_mark(mark);
+}
+
/*
- * Free fsnotify mark. The freeing is actually happening from a kthread which
- * first waits for srcu period end. Caller must have a reference to the mark
- * or be protected by fsnotify_mark_srcu.
+ * Free fsnotify mark. The freeing is actually happening from a call_srcu
+ * callback. Caller must have a reference to the mark or be protected by
+ * fsnotify_mark_srcu.
*/
void fsnotify_free_mark(struct fsnotify_mark *mark)
{
@@ -186,10 +192,7 @@ void fsnotify_free_mark(struct fsnotify_mark *mark)
mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
spin_unlock(&mark->lock);
- spin_lock(&destroy_lock);
- list_add(&mark->g_list, &destroy_list);
- spin_unlock(&destroy_lock);
- wake_up(&destroy_waitq);
+ call_srcu(&fsnotify_mark_srcu, &mark->g_rcu, fsnotify_mark_free_rcu);
/*
* Some groups like to know that marks are being freed. This is a
@@ -385,11 +388,7 @@ err:
spin_unlock(&mark->lock);
- spin_lock(&destroy_lock);
- list_add(&mark->g_list, &destroy_list);
- spin_unlock(&destroy_lock);
- wake_up(&destroy_waitq);
-
+ call_srcu(&fsnotify_mark_srcu, &mark->g_rcu, fsnotify_mark_free_rcu);
return ret;
}
@@ -492,40 +491,3 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
atomic_set(&mark->refcnt, 1);
mark->free_mark = free_mark;
}
-
-static int fsnotify_mark_destroy(void *ignored)
-{
- struct fsnotify_mark *mark, *next;
- struct list_head private_destroy_list;
-
- for (;;) {
- spin_lock(&destroy_lock);
- /* exchange the list head */
- list_replace_init(&destroy_list, &private_destroy_list);
- spin_unlock(&destroy_lock);
-
- synchronize_srcu(&fsnotify_mark_srcu);
-
- list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
- list_del_init(&mark->g_list);
- fsnotify_put_mark(mark);
- }
-
- wait_event_interruptible(destroy_waitq, !list_empty(&destroy_list));
- }
-
- return 0;
-}
-
-static int __init fsnotify_mark_init(void)
-{
- struct task_struct *thread;
-
- thread = kthread_run(fsnotify_mark_destroy, NULL,
- "fsnotify_mark");
- if (IS_ERR(thread))
- panic("unable to start fsnotify mark destruction thread.");
-
- return 0;
-}
-device_initcall(fsnotify_mark_init);
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index d1a853585b53..2f77f8dfb861 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -3139,8 +3139,8 @@ static int __init init_ntfs_fs(void)
ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
sizeof(big_ntfs_inode), 0,
- SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- ntfs_big_inode_init_once);
+ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
+ SLAB_ACCOUNT, ntfs_big_inode_init_once);
if (!ntfs_big_inode_cache) {
pr_crit("Failed to create %s!\n", ntfs_big_inode_cache_name);
goto big_inode_err_out;
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 86181d6526dc..a3ded88718c9 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -164,7 +164,7 @@ static int ocfs2_dinode_insert_check(struct ocfs2_extent_tree *et,
struct ocfs2_extent_rec *rec);
static int ocfs2_dinode_sanity_check(struct ocfs2_extent_tree *et);
static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et);
-static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = {
+static const struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = {
.eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk,
.eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk,
.eo_update_clusters = ocfs2_dinode_update_clusters,
@@ -286,7 +286,7 @@ static void ocfs2_xattr_value_update_clusters(struct ocfs2_extent_tree *et,
le32_add_cpu(&vb->vb_xv->xr_clusters, clusters);
}
-static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = {
+static const struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = {
.eo_set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk,
.eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk,
.eo_update_clusters = ocfs2_xattr_value_update_clusters,
@@ -332,7 +332,7 @@ static void ocfs2_xattr_tree_update_clusters(struct ocfs2_extent_tree *et,
le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters);
}
-static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
+static const struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
.eo_set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk,
.eo_get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk,
.eo_update_clusters = ocfs2_xattr_tree_update_clusters,
@@ -379,7 +379,7 @@ static void ocfs2_dx_root_fill_root_el(struct ocfs2_extent_tree *et)
et->et_root_el = &dx_root->dr_list;
}
-static struct ocfs2_extent_tree_operations ocfs2_dx_root_et_ops = {
+static const struct ocfs2_extent_tree_operations ocfs2_dx_root_et_ops = {
.eo_set_last_eb_blk = ocfs2_dx_root_set_last_eb_blk,
.eo_get_last_eb_blk = ocfs2_dx_root_get_last_eb_blk,
.eo_update_clusters = ocfs2_dx_root_update_clusters,
@@ -425,7 +425,7 @@ ocfs2_refcount_tree_extent_contig(struct ocfs2_extent_tree *et,
return CONTIG_NONE;
}
-static struct ocfs2_extent_tree_operations ocfs2_refcount_tree_et_ops = {
+static const struct ocfs2_extent_tree_operations ocfs2_refcount_tree_et_ops = {
.eo_set_last_eb_blk = ocfs2_refcount_tree_set_last_eb_blk,
.eo_get_last_eb_blk = ocfs2_refcount_tree_get_last_eb_blk,
.eo_update_clusters = ocfs2_refcount_tree_update_clusters,
@@ -438,7 +438,7 @@ static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et,
struct buffer_head *bh,
ocfs2_journal_access_func access,
void *obj,
- struct ocfs2_extent_tree_operations *ops)
+ const struct ocfs2_extent_tree_operations *ops)
{
et->et_ops = ops;
et->et_root_bh = bh;
@@ -6174,8 +6174,7 @@ int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb,
}
bail:
- if (tl_inode)
- iput(tl_inode);
+ iput(tl_inode);
brelse(tl_bh);
if (status < 0) {
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index fb09b97db162..f3dc1b0dfffc 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -54,7 +54,7 @@
*/
struct ocfs2_extent_tree_operations;
struct ocfs2_extent_tree {
- struct ocfs2_extent_tree_operations *et_ops;
+ const struct ocfs2_extent_tree_operations *et_ops;
struct buffer_head *et_root_bh;
struct ocfs2_extent_list *et_root_el;
struct ocfs2_caching_info *et_ci;
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 709fbbd44c65..a3cc6d2fc896 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1780,8 +1780,8 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
}
++live_threshold;
atomic_set(&reg->hr_steady_iterations, live_threshold);
- /* unsteady_iterations is double the steady_iterations */
- atomic_set(&reg->hr_unsteady_iterations, (live_threshold << 1));
+ /* unsteady_iterations is triple the steady_iterations */
+ atomic_set(&reg->hr_unsteady_iterations, (live_threshold * 3));
hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
reg->hr_item.ci_name);
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 72afdca3cea7..ebe543894db0 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -757,7 +757,7 @@ int o2nm_depend_item(struct config_item *item)
void o2nm_undepend_item(struct config_item *item)
{
- configfs_undepend_item(&o2nm_cluster_group.cs_subsys, item);
+ configfs_undepend_item(item);
}
int o2nm_depend_this_node(void)
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index e88ccf8c83ff..68c607e63ff6 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -376,17 +376,6 @@ struct dlm_lock
lksb_kernel_allocated:1;
};
-
-#define DLM_LKSB_UNUSED1 0x01
-#define DLM_LKSB_PUT_LVB 0x02
-#define DLM_LKSB_GET_LVB 0x04
-#define DLM_LKSB_UNUSED2 0x08
-#define DLM_LKSB_UNUSED3 0x10
-#define DLM_LKSB_UNUSED4 0x20
-#define DLM_LKSB_UNUSED5 0x40
-#define DLM_LKSB_UNUSED6 0x80
-
-
enum dlm_lockres_list {
DLM_GRANTED_LIST = 0,
DLM_CONVERTING_LIST = 1,
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 84f2f8079466..9477d6e1de37 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -2388,8 +2388,8 @@ static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data)
spin_lock(&res->spinlock);
BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF);
+ __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
if (test_bit(node, res->refmap)) {
- __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
dlm_lockres_clear_refmap_bit(dlm, res, node);
cleared = 1;
}
@@ -2519,6 +2519,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
spin_lock(&dlm->master_lock);
ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name,
namelen, target, dlm->node_num);
+ /* get an extra reference on the mle.
+ * otherwise the assert_master from the new
+ * master will destroy this.
+ */
+ dlm_get_mle_inuse(mle);
spin_unlock(&dlm->master_lock);
spin_unlock(&dlm->spinlock);
@@ -2544,7 +2549,7 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
}
fail:
- if (oldmle) {
+ if (ret != -EEXIST && oldmle) {
/* master is known, detach if not already detached */
dlm_mle_detach_hb_events(dlm, oldmle);
dlm_put_mle(oldmle);
@@ -2554,6 +2559,7 @@ fail:
if (mle_added) {
dlm_mle_detach_hb_events(dlm, mle);
dlm_put_mle(mle);
+ dlm_put_mle_inuse(mle);
} else if (mle) {
kmem_cache_free(dlm_mle_cache, mle);
mle = NULL;
@@ -2571,17 +2577,6 @@ fail:
* ensure that all assert_master work is flushed. */
flush_workqueue(dlm->dlm_worker);
- /* get an extra reference on the mle.
- * otherwise the assert_master from the new
- * master will destroy this.
- * also, make sure that all callers of dlm_get_mle
- * take both dlm->spinlock and dlm->master_lock */
- spin_lock(&dlm->spinlock);
- spin_lock(&dlm->master_lock);
- dlm_get_mle_inuse(mle);
- spin_unlock(&dlm->master_lock);
- spin_unlock(&dlm->spinlock);
-
/* notify new node and send all lock state */
/* call send_one_lockres with migration flag.
* this serves as notice to the target node that a
@@ -3050,7 +3045,7 @@ int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data,
int ret = 0;
if (!dlm_grab(dlm))
- return -EINVAL;
+ return 0;
name = migrate->name;
namelen = migrate->namelen;
@@ -3141,7 +3136,8 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm,
mlog(0, "tried to migrate %.*s, but some "
"process beat me to it\n",
namelen, name);
- ret = -EEXIST;
+ spin_unlock(&tmp->spinlock);
+ return -EEXIST;
} else {
/* bad. 2 NODES are trying to migrate! */
mlog(ML_ERROR, "migration error mle: "
@@ -3312,6 +3308,15 @@ top:
mle->new_master != dead_node)
continue;
+ if (mle->new_master == dead_node && mle->inuse) {
+ mlog(ML_NOTICE, "%s: target %u died during "
+ "migration from %u, the MLE is "
+ "still keep used, ignore it!\n",
+ dlm->name, dead_node,
+ mle->master);
+ continue;
+ }
+
/* If we have reached this point, this mle needs to be
* removed from the list and freed. */
dlm_clean_migration_mle(dlm, mle);
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 9e4f862d20fe..c5bdf02c213b 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1373,6 +1373,7 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
char *buf = NULL;
struct dlm_work_item *item = NULL;
struct dlm_lock_resource *res = NULL;
+ unsigned int hash;
if (!dlm_grab(dlm))
return -EINVAL;
@@ -1400,7 +1401,10 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
/* lookup the lock to see if we have a secondary queue for this
* already... just add the locks in and this will have its owner
* and RECOVERY flag changed when it completes. */
- res = dlm_lookup_lockres(dlm, mres->lockname, mres->lockname_len);
+ hash = dlm_lockid_hash(mres->lockname, mres->lockname_len);
+ spin_lock(&dlm->spinlock);
+ res = __dlm_lookup_lockres(dlm, mres->lockname, mres->lockname_len,
+ hash);
if (res) {
/* this will get a ref on res */
/* mark it as recovering/migrating and hash it */
@@ -1421,13 +1425,16 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
mres->lockname_len, mres->lockname);
ret = -EFAULT;
spin_unlock(&res->spinlock);
+ spin_unlock(&dlm->spinlock);
dlm_lockres_put(res);
goto leave;
}
res->state |= DLM_LOCK_RES_MIGRATING;
}
spin_unlock(&res->spinlock);
+ spin_unlock(&dlm->spinlock);
} else {
+ spin_unlock(&dlm->spinlock);
/* need to allocate, just like if it was
* mastered here normally */
res = dlm_new_lockres(dlm, mres->lockname, mres->lockname_len);
@@ -2450,11 +2457,7 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
* perhaps later we can genericize this for other waiters. */
wake_up(&dlm->migration_wq);
- if (test_bit(idx, dlm->recovery_map))
- mlog(0, "domain %s, node %u already added "
- "to recovery map!\n", dlm->name, idx);
- else
- set_bit(idx, dlm->recovery_map);
+ set_bit(idx, dlm->recovery_map);
}
void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data)
diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c
index 2e3c9dbab68c..1082b2c3014b 100644
--- a/fs/ocfs2/dlm/dlmunlock.c
+++ b/fs/ocfs2/dlm/dlmunlock.c
@@ -421,7 +421,7 @@ int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
}
if (!dlm_grab(dlm))
- return DLM_REJECTED;
+ return DLM_FORWARD;
mlog_bug_on_msg(!dlm_domain_fully_joined(dlm),
"Domain %s not fully joined!\n", dlm->name);
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index b5cf27dcb18a..03768bb3aab1 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -638,7 +638,7 @@ static int __init init_dlmfs_fs(void)
dlmfs_inode_cache = kmem_cache_create("dlmfs_inode_cache",
sizeof(struct dlmfs_inode_private),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
dlmfs_init_once);
if (!dlmfs_inode_cache) {
status = -ENOMEM;
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 20276e340339..f92612e4b9d6 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2432,12 +2432,6 @@ bail:
* done this we have to return AOP_TRUNCATED_PAGE so the aop method
* that called us can bubble that back up into the VFS who will then
* immediately retry the aop call.
- *
- * We do a blocking lock and immediate unlock before returning, though, so that
- * the lock has a great chance of being cached on this node by the time the VFS
- * calls back to retry the aop. This has a potential to livelock as nodes
- * ping locks back and forth, but that's a risk we're willing to take to avoid
- * the lock inversion simply.
*/
int ocfs2_inode_lock_with_page(struct inode *inode,
struct buffer_head **ret_bh,
@@ -2449,8 +2443,6 @@ int ocfs2_inode_lock_with_page(struct inode *inode,
ret = ocfs2_inode_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
if (ret == -EAGAIN) {
unlock_page(page);
- if (ocfs2_inode_lock(inode, ret_bh, ex) == 0)
- ocfs2_inode_unlock(inode, ex);
ret = AOP_TRUNCATED_PAGE;
}
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 0e5b4515f92e..d63127932509 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1302,6 +1302,14 @@ int ocfs2_getattr(struct vfsmount *mnt,
}
generic_fillattr(inode, stat);
+ /*
+ * If there is inline data in the inode, the inode will normally not
+ * have data blocks allocated (it may have an external xattr block).
+ * Report at least one sector for such files, so tools like tar, rsync,
+ * others don't incorrectly think the file is completely sparse.
+ */
+ if (unlikely(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+ stat->blocks += (stat->size + 511)>>9;
/* We set the blksize from the cluster size for performance */
stat->blksize = osb->s_clustersize;
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 3cb097ccce60..16b0bb482ea7 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -606,9 +606,7 @@ bail:
if (gb_inode)
mutex_unlock(&gb_inode->i_mutex);
- if (gb_inode)
- iput(gb_inode);
-
+ iput(gb_inode);
brelse(bh);
return status;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 13534f4fe5b5..3772a2dbb980 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -1042,8 +1042,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
// up_write(&journal->j_trans_barrier);
done:
- if (inode)
- iput(inode);
+ iput(inode);
}
static void ocfs2_clear_journal_error(struct super_block *sb,
@@ -1687,9 +1686,7 @@ done:
if (got_lock)
ocfs2_inode_unlock(inode, 1);
- if (inode)
- iput(inode);
-
+ iput(inode);
brelse(bh);
return status;
@@ -1796,8 +1793,7 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb,
ocfs2_inode_unlock(inode, 1);
bail:
- if (inode)
- iput(inode);
+ iput(inode);
return status;
}
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 0a4457fb0711..e9c99e35f5ea 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -358,8 +358,7 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
bail:
if (status < 0)
brelse(alloc_bh);
- if (inode)
- iput(inode);
+ iput(inode);
trace_ocfs2_load_local_alloc(osb->local_alloc_bits);
@@ -473,8 +472,7 @@ out_mutex:
iput(main_bm_inode);
out:
- if (local_alloc_inode)
- iput(local_alloc_inode);
+ iput(local_alloc_inode);
kfree(alloc_copy);
}
@@ -1327,9 +1325,7 @@ bail:
brelse(main_bm_bh);
- if (main_bm_inode)
- iput(main_bm_inode);
-
+ iput(main_bm_inode);
kfree(alloc_copy);
if (ac)
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index afb81eae2c18..ab42c38031b1 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -1683,8 +1683,7 @@ bail:
if (new_inode)
sync_mapping_buffers(old_inode->i_mapping);
- if (new_inode)
- iput(new_inode);
+ iput(new_inode);
ocfs2_free_dir_lookup_result(&target_lookup_res);
ocfs2_free_dir_lookup_result(&old_entry_lookup);
@@ -2373,6 +2372,15 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
(unsigned long long)OCFS2_I(orphan_dir_inode)->ip_blkno,
name, strlen(name));
+ status = ocfs2_journal_access_di(handle,
+ INODE_CACHE(orphan_dir_inode),
+ orphan_dir_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto leave;
+ }
+
/* find it's spot in the orphan directory */
status = ocfs2_find_entry(name, strlen(name), orphan_dir_inode,
&lookup);
@@ -2388,15 +2396,6 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
goto leave;
}
- status = ocfs2_journal_access_di(handle,
- INODE_CACHE(orphan_dir_inode),
- orphan_dir_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
-
/* do the i_nlink dance! :) */
orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
if (S_ISDIR(inode->i_mode))
diff --git a/fs/ocfs2/quota.h b/fs/ocfs2/quota.h
index b6d51333ad02..d153e6e31529 100644
--- a/fs/ocfs2/quota.h
+++ b/fs/ocfs2/quota.h
@@ -82,7 +82,7 @@ struct ocfs2_quota_chunk {
extern struct kmem_cache *ocfs2_dquot_cachep;
extern struct kmem_cache *ocfs2_qf_chunk_cachep;
-extern struct qtree_fmt_operations ocfs2_global_ops;
+extern const struct qtree_fmt_operations ocfs2_global_ops;
struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
struct ocfs2_super *osb, int slot_num);
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index c93d67220887..fde9ef18cff3 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -123,7 +123,7 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
dquot->dq_id);
}
-struct qtree_fmt_operations ocfs2_global_ops = {
+const struct qtree_fmt_operations ocfs2_global_ops = {
.mem2disk_dqblk = ocfs2_global_mem2diskdqb,
.disk2mem_dqblk = ocfs2_global_disk2memdqb,
.is_id = ocfs2_global_is_id,
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index e78a203d44c8..1e09592148ad 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -322,8 +322,7 @@ static void __ocfs2_free_slot_info(struct ocfs2_slot_info *si)
if (si == NULL)
return;
- if (si->si_inode)
- iput(si->si_inode);
+ iput(si->si_inode);
if (si->si_bh) {
for (i = 0; i < si->si_blocks; i++) {
if (si->si_bh[i]) {
@@ -503,8 +502,17 @@ int ocfs2_find_slot(struct ocfs2_super *osb)
trace_ocfs2_find_slot(osb->slot_num);
status = ocfs2_update_disk_slot(osb, si, osb->slot_num);
- if (status < 0)
+ if (status < 0) {
mlog_errno(status);
+ /*
+ * if write block failed, invalidate slot to avoid overwrite
+ * slot during dismount in case another node rightly has mounted
+ */
+ spin_lock(&osb->osb_lock);
+ ocfs2_invalidate_slot(si, osb->slot_num);
+ osb->slot_num = OCFS2_INVALID_SLOT;
+ spin_unlock(&osb->osb_lock);
+ }
bail:
return status;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 2de4c8a9340c..faa1365097bc 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1280,6 +1280,8 @@ static int ocfs2_parse_options(struct super_block *sb,
int status, user_stack = 0;
char *p;
u32 tmp;
+ int token, option;
+ substring_t args[MAX_OPT_ARGS];
trace_ocfs2_parse_options(is_remount, options ? options : "(none)");
@@ -1298,9 +1300,6 @@ static int ocfs2_parse_options(struct super_block *sb,
}
while ((p = strsep(&options, ",")) != NULL) {
- int token, option;
- substring_t args[MAX_OPT_ARGS];
-
if (!*p)
continue;
@@ -1367,7 +1366,6 @@ static int ocfs2_parse_options(struct super_block *sb,
mopt->atime_quantum = option;
break;
case Opt_slot:
- option = 0;
if (match_int(&args[0], &option)) {
status = 0;
goto bail;
@@ -1376,7 +1374,6 @@ static int ocfs2_parse_options(struct super_block *sb,
mopt->slot = (s16)option;
break;
case Opt_commit:
- option = 0;
if (match_int(&args[0], &option)) {
status = 0;
goto bail;
@@ -1388,7 +1385,6 @@ static int ocfs2_parse_options(struct super_block *sb,
mopt->commit_interval = HZ * option;
break;
case Opt_localalloc:
- option = 0;
if (match_int(&args[0], &option)) {
status = 0;
goto bail;
@@ -1726,8 +1722,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
ocfs2_inode_unlock(inode, 0);
status = 0;
bail:
- if (inode)
- iput(inode);
+ iput(inode);
if (status)
mlog_errno(status);
@@ -1771,7 +1766,7 @@ static int ocfs2_initialize_mem_caches(void)
sizeof(struct ocfs2_inode_info),
0,
(SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
ocfs2_inode_init_once);
ocfs2_dquot_cachep = kmem_cache_create("ocfs2_dquot_cache",
sizeof(struct ocfs2_dquot),
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 15e4500cda3e..b61b883c8ff8 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -443,7 +443,7 @@ static int __init init_openprom_fs(void)
sizeof(struct op_inode_info),
0,
(SLAB_RECLAIM_ACCOUNT |
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD | SLAB_ACCOUNT),
op_inode_init_once);
if (!op_inode_cachep)
return -ENOMEM;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index d0e9b9b6223e..42305ddcbaa0 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -95,7 +95,8 @@ void __init proc_init_inodecache(void)
proc_inode_cachep = kmem_cache_create("proc_inode_cache",
sizeof(struct proc_inode),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD|SLAB_PANIC),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT|
+ SLAB_PANIC),
init_once);
}
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 9155a5a0d3b9..df4661abadc4 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -57,11 +57,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
/*
* Estimate the amount of memory available for userspace allocations,
* without causing swapping.
- *
- * Free memory cannot be taken below the low watermark, before the
- * system starts swapping.
*/
- available = i.freeram - wmark_low;
+ available = i.freeram - totalreserve_pages;
/*
* Not all the page cache can be freed, otherwise the system will
diff --git a/fs/proc/page.c b/fs/proc/page.c
index 93484034a03d..b2855eea5405 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -103,9 +103,9 @@ u64 stable_page_flags(struct page *page)
* pseudo flags for the well known (anonymous) memory mapped pages
*
* Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the
- * simple test in page_mapped() is not enough.
+ * simple test in page_mapcount() is not enough.
*/
- if (!PageSlab(page) && page_mapped(page))
+ if (!PageSlab(page) && page_mapcount(page))
u |= 1 << KPF_MMAP;
if (PageAnon(page))
u |= 1 << KPF_ANON;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 187b3b5f242e..65a1b6c69c11 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -14,6 +14,7 @@
#include <linux/swapops.h>
#include <linux/mmu_notifier.h>
#include <linux/page_idle.h>
+#include <linux/shmem_fs.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
@@ -22,9 +23,13 @@
void task_mem(struct seq_file *m, struct mm_struct *mm)
{
- unsigned long data, text, lib, swap, ptes, pmds;
+ unsigned long text, lib, swap, ptes, pmds, anon, file, shmem;
unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss;
+ anon = get_mm_counter(mm, MM_ANONPAGES);
+ file = get_mm_counter(mm, MM_FILEPAGES);
+ shmem = get_mm_counter(mm, MM_SHMEMPAGES);
+
/*
* Note: to minimize their overhead, mm maintains hiwater_vm and
* hiwater_rss only when about to *lower* total_vm or rss. Any
@@ -35,11 +40,10 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
hiwater_vm = total_vm = mm->total_vm;
if (hiwater_vm < mm->hiwater_vm)
hiwater_vm = mm->hiwater_vm;
- hiwater_rss = total_rss = get_mm_rss(mm);
+ hiwater_rss = total_rss = anon + file + shmem;
if (hiwater_rss < mm->hiwater_rss)
hiwater_rss = mm->hiwater_rss;
- data = mm->total_vm - mm->shared_vm - mm->stack_vm;
text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10;
lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text;
swap = get_mm_counter(mm, MM_SWAPENTS);
@@ -52,6 +56,9 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
"VmPin:\t%8lu kB\n"
"VmHWM:\t%8lu kB\n"
"VmRSS:\t%8lu kB\n"
+ "RssAnon:\t%8lu kB\n"
+ "RssFile:\t%8lu kB\n"
+ "RssShmem:\t%8lu kB\n"
"VmData:\t%8lu kB\n"
"VmStk:\t%8lu kB\n"
"VmExe:\t%8lu kB\n"
@@ -65,7 +72,10 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
mm->pinned_vm << (PAGE_SHIFT-10),
hiwater_rss << (PAGE_SHIFT-10),
total_rss << (PAGE_SHIFT-10),
- data << (PAGE_SHIFT-10),
+ anon << (PAGE_SHIFT-10),
+ file << (PAGE_SHIFT-10),
+ shmem << (PAGE_SHIFT-10),
+ mm->data_vm << (PAGE_SHIFT-10),
mm->stack_vm << (PAGE_SHIFT-10), text, lib,
ptes >> 10,
pmds >> 10,
@@ -82,10 +92,11 @@ unsigned long task_statm(struct mm_struct *mm,
unsigned long *shared, unsigned long *text,
unsigned long *data, unsigned long *resident)
{
- *shared = get_mm_counter(mm, MM_FILEPAGES);
+ *shared = get_mm_counter(mm, MM_FILEPAGES) +
+ get_mm_counter(mm, MM_SHMEMPAGES);
*text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
>> PAGE_SHIFT;
- *data = mm->total_vm - mm->shared_vm;
+ *data = mm->data_vm + mm->stack_vm;
*resident = *shared + get_mm_counter(mm, MM_ANONPAGES);
return mm->total_vm;
}
@@ -451,12 +462,14 @@ struct mem_size_stats {
unsigned long private_hugetlb;
u64 pss;
u64 swap_pss;
+ bool check_shmem_swap;
};
static void smaps_account(struct mem_size_stats *mss, struct page *page,
- unsigned long size, bool young, bool dirty)
+ bool compound, bool young, bool dirty)
{
- int mapcount;
+ int i, nr = compound ? HPAGE_PMD_NR : 1;
+ unsigned long size = nr * PAGE_SIZE;
if (PageAnon(page))
mss->anonymous += size;
@@ -465,26 +478,53 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
/* Accumulate the size in pages that have been accessed. */
if (young || page_is_young(page) || PageReferenced(page))
mss->referenced += size;
- mapcount = page_mapcount(page);
- if (mapcount >= 2) {
- u64 pss_delta;
- if (dirty || PageDirty(page))
- mss->shared_dirty += size;
- else
- mss->shared_clean += size;
- pss_delta = (u64)size << PSS_SHIFT;
- do_div(pss_delta, mapcount);
- mss->pss += pss_delta;
- } else {
+ /*
+ * page_count(page) == 1 guarantees the page is mapped exactly once.
+ * If any subpage of the compound page mapped with PTE it would elevate
+ * page_count().
+ */
+ if (page_count(page) == 1) {
if (dirty || PageDirty(page))
mss->private_dirty += size;
else
mss->private_clean += size;
mss->pss += (u64)size << PSS_SHIFT;
+ return;
+ }
+
+ for (i = 0; i < nr; i++, page++) {
+ int mapcount = page_mapcount(page);
+
+ if (mapcount >= 2) {
+ if (dirty || PageDirty(page))
+ mss->shared_dirty += PAGE_SIZE;
+ else
+ mss->shared_clean += PAGE_SIZE;
+ mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
+ } else {
+ if (dirty || PageDirty(page))
+ mss->private_dirty += PAGE_SIZE;
+ else
+ mss->private_clean += PAGE_SIZE;
+ mss->pss += PAGE_SIZE << PSS_SHIFT;
+ }
}
}
+#ifdef CONFIG_SHMEM
+static int smaps_pte_hole(unsigned long addr, unsigned long end,
+ struct mm_walk *walk)
+{
+ struct mem_size_stats *mss = walk->private;
+
+ mss->swap += shmem_partial_swap_usage(
+ walk->vma->vm_file->f_mapping, addr, end);
+
+ return 0;
+}
+#endif
+
static void smaps_pte_entry(pte_t *pte, unsigned long addr,
struct mm_walk *walk)
{
@@ -512,11 +552,25 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
}
} else if (is_migration_entry(swpent))
page = migration_entry_to_page(swpent);
+ } else if (unlikely(IS_ENABLED(CONFIG_SHMEM) && mss->check_shmem_swap
+ && pte_none(*pte))) {
+ page = find_get_entry(vma->vm_file->f_mapping,
+ linear_page_index(vma, addr));
+ if (!page)
+ return;
+
+ if (radix_tree_exceptional_entry(page))
+ mss->swap += PAGE_SIZE;
+ else
+ page_cache_release(page);
+
+ return;
}
if (!page)
return;
- smaps_account(mss, page, PAGE_SIZE, pte_young(*pte), pte_dirty(*pte));
+
+ smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte));
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -532,8 +586,7 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
if (IS_ERR_OR_NULL(page))
return;
mss->anonymous_thp += HPAGE_PMD_SIZE;
- smaps_account(mss, page, HPAGE_PMD_SIZE,
- pmd_young(*pmd), pmd_dirty(*pmd));
+ smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd));
}
#else
static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
@@ -549,7 +602,7 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
pte_t *pte;
spinlock_t *ptl;
- if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmd, vma, &ptl)) {
smaps_pmd_entry(pmd, addr, walk);
spin_unlock(ptl);
return 0;
@@ -671,6 +724,31 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
};
memset(&mss, 0, sizeof mss);
+
+#ifdef CONFIG_SHMEM
+ if (vma->vm_file && shmem_mapping(vma->vm_file->f_mapping)) {
+ /*
+ * For shared or readonly shmem mappings we know that all
+ * swapped out pages belong to the shmem object, and we can
+ * obtain the swap value much more efficiently. For private
+ * writable mappings, we might have COW pages that are
+ * not affected by the parent swapped out pages of the shmem
+ * object, so we have to distinguish them during the page walk.
+ * Unless we know that the shmem object (or the part mapped by
+ * our VMA) has no swapped out pages at all.
+ */
+ unsigned long shmem_swapped = shmem_swap_usage(vma);
+
+ if (!shmem_swapped || (vma->vm_flags & VM_SHARED) ||
+ !(vma->vm_flags & VM_WRITE)) {
+ mss.swap = shmem_swapped;
+ } else {
+ mss.check_shmem_swap = true;
+ smaps_walk.pte_hole = smaps_pte_hole;
+ }
+ }
+#endif
+
/* mmap_sem is held in m_start */
walk_page_vma(vma, &smaps_walk);
@@ -817,9 +895,6 @@ static inline void clear_soft_dirty_pmd(struct vm_area_struct *vma,
pmd = pmd_wrprotect(pmd);
pmd = pmd_clear_soft_dirty(pmd);
- if (vma->vm_flags & VM_SOFTDIRTY)
- vma->vm_flags &= ~VM_SOFTDIRTY;
-
set_pmd_at(vma->vm_mm, addr, pmdp, pmd);
}
#else
@@ -838,7 +913,7 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
spinlock_t *ptl;
struct page *page;
- if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmd, vma, &ptl)) {
if (cp->type == CLEAR_REFS_SOFT_DIRTY) {
clear_soft_dirty_pmd(vma, addr, pmd);
goto out;
@@ -1112,7 +1187,7 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
int err = 0;
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- if (pmd_trans_huge_lock(pmdp, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmdp, vma, &ptl)) {
u64 flags = 0, frame = 0;
pmd_t pmd = *pmdp;
@@ -1444,7 +1519,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
pte_t *orig_pte;
pte_t *pte;
- if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmd, vma, &ptl)) {
pte_t huge_pte = *(pte_t *)pmd;
struct page *page;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index f37b3deb01b4..3a67cfb142d8 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -365,7 +365,7 @@ static int init_inodecache(void)
qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache",
sizeof(struct qnx4_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (qnx4_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
index 9728b5499e1d..47bb1de07155 100644
--- a/fs/qnx6/inode.c
+++ b/fs/qnx6/inode.c
@@ -625,7 +625,7 @@ static int init_inodecache(void)
qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache",
sizeof(struct qnx6_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (!qnx6_inode_cachep)
return -ENOMEM;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index ef0d64b2a6d9..fbd70af98820 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2924,4 +2924,4 @@ static int __init dquot_init(void)
return 0;
}
-module_init(dquot_init);
+fs_initcall(dquot_init);
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index bb2869f5dfd8..d07a2f91d858 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -1,7 +1,5 @@
-
#include <linux/cred.h>
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/quotaops.h>
#include <linux/sched.h>
@@ -105,5 +103,4 @@ static int __init quota_init(void)
"VFS: Failed to create quota netlink interface.\n");
return 0;
};
-
-module_init(quota_init);
+fs_initcall(quota_init);
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index 2aa012a68e90..ed85d4f35c04 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -30,13 +30,13 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
static int v2r1_is_id(void *dp, struct dquot *dquot);
-static struct qtree_fmt_operations v2r0_qtree_ops = {
+static const struct qtree_fmt_operations v2r0_qtree_ops = {
.mem2disk_dqblk = v2r0_mem2diskdqb,
.disk2mem_dqblk = v2r0_disk2memdqb,
.is_id = v2r0_is_id,
};
-static struct qtree_fmt_operations v2r1_qtree_ops = {
+static const struct qtree_fmt_operations v2r1_qtree_ops = {
.mem2disk_dqblk = v2r1_mem2diskdqb,
.disk2mem_dqblk = v2r1_disk2memdqb,
.is_id = v2r1_is_id,
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 4a62fe8cc3bf..05db7473bcb5 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -626,7 +626,8 @@ static int __init init_inodecache(void)
sizeof(struct
reiserfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|
+ SLAB_ACCOUNT),
init_once);
if (reiserfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index bb894e78a821..6b00ca357c58 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -619,8 +619,8 @@ static int __init init_romfs_fs(void)
romfs_inode_cachep =
kmem_cache_create("romfs_i",
sizeof(struct romfs_inode_info), 0,
- SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
- romfs_i_init_once);
+ SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
+ SLAB_ACCOUNT, romfs_i_init_once);
if (!romfs_inode_cachep) {
pr_err("Failed to initialise inode cache\n");
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index dded920cbc8f..5e79bfa4f260 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -419,7 +419,8 @@ static int __init init_inodecache(void)
{
squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
sizeof(struct squashfs_inode_info), 0,
- SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
+ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,
+ init_once);
return squashfs_inode_cachep ? 0 : -ENOMEM;
}
diff --git a/fs/stat.c b/fs/stat.c
index d4a61d8dc021..bc045c7994e1 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -219,7 +219,7 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, stat
# define choose_32_64(a,b) b
#endif
-#define valid_dev(x) choose_32_64(old_valid_dev,new_valid_dev)(x)
+#define valid_dev(x) choose_32_64(old_valid_dev(x),true)
#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x)
#ifndef INIT_STRUCT_STAT_PADDING
diff --git a/fs/super.c b/fs/super.c
index cc658a20a29e..1182af8fd5ff 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1197,7 +1197,7 @@ int __sb_start_write(struct super_block *sb, int level, bool wait)
else
ret = percpu_down_read_trylock(sb->s_writers.rw_sem + level-1);
- WARN_ON(force_trylock & !ret);
+ WARN_ON(force_trylock && !ret);
return ret;
}
EXPORT_SYMBOL(__sb_start_write);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 07ac18c355e7..d62c423a5a2d 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -346,7 +346,7 @@ int __init sysv_init_icache(void)
{
sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
sizeof(struct sysv_inode_info), 0,
- SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
init_once);
if (!sysv_inode_cachep)
return -ENOMEM;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 1fd90c079537..a233ba913be4 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -2248,8 +2248,8 @@ static int __init ubifs_init(void)
ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab",
sizeof(struct ubifs_inode), 0,
- SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT,
- &inode_slab_ctor);
+ SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT |
+ SLAB_ACCOUNT, &inode_slab_ctor);
if (!ubifs_inode_slab)
return -ENOMEM;
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 6d6a96b4e73f..e0fd65fe73e8 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -447,9 +447,6 @@ static void udf_table_free_blocks(struct super_block *sb,
*/
int adsize;
- struct short_ad *sad = NULL;
- struct long_ad *lad = NULL;
- struct allocExtDesc *aed;
eloc.logicalBlockNum = start;
elen = EXT_RECORDED_ALLOCATED |
@@ -466,102 +463,17 @@ static void udf_table_free_blocks(struct super_block *sb,
}
if (epos.offset + (2 * adsize) > sb->s_blocksize) {
- unsigned char *sptr, *dptr;
- int loffset;
-
- brelse(oepos.bh);
- oepos = epos;
-
/* Steal a block from the extent being free'd */
- epos.block.logicalBlockNum = eloc.logicalBlockNum;
+ udf_setup_indirect_aext(table, eloc.logicalBlockNum,
+ &epos);
+
eloc.logicalBlockNum++;
elen -= sb->s_blocksize;
-
- epos.bh = udf_tread(sb,
- udf_get_lb_pblock(sb, &epos.block, 0));
- if (!epos.bh) {
- brelse(oepos.bh);
- goto error_return;
- }
- aed = (struct allocExtDesc *)(epos.bh->b_data);
- aed->previousAllocExtLocation =
- cpu_to_le32(oepos.block.logicalBlockNum);
- if (epos.offset + adsize > sb->s_blocksize) {
- loffset = epos.offset;
- aed->lengthAllocDescs = cpu_to_le32(adsize);
- sptr = iinfo->i_ext.i_data + epos.offset
- - adsize;
- dptr = epos.bh->b_data +
- sizeof(struct allocExtDesc);
- memcpy(dptr, sptr, adsize);
- epos.offset = sizeof(struct allocExtDesc) +
- adsize;
- } else {
- loffset = epos.offset + adsize;
- aed->lengthAllocDescs = cpu_to_le32(0);
- if (oepos.bh) {
- sptr = oepos.bh->b_data + epos.offset;
- aed = (struct allocExtDesc *)
- oepos.bh->b_data;
- le32_add_cpu(&aed->lengthAllocDescs,
- adsize);
- } else {
- sptr = iinfo->i_ext.i_data +
- epos.offset;
- iinfo->i_lenAlloc += adsize;
- mark_inode_dirty(table);
- }
- epos.offset = sizeof(struct allocExtDesc);
- }
- if (sbi->s_udfrev >= 0x0200)
- udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
- 3, 1, epos.block.logicalBlockNum,
- sizeof(struct tag));
- else
- udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
- 2, 1, epos.block.logicalBlockNum,
- sizeof(struct tag));
-
- switch (iinfo->i_alloc_type) {
- case ICBTAG_FLAG_AD_SHORT:
- sad = (struct short_ad *)sptr;
- sad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- sb->s_blocksize);
- sad->extPosition =
- cpu_to_le32(epos.block.logicalBlockNum);
- break;
- case ICBTAG_FLAG_AD_LONG:
- lad = (struct long_ad *)sptr;
- lad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- sb->s_blocksize);
- lad->extLocation =
- cpu_to_lelb(epos.block);
- break;
- }
- if (oepos.bh) {
- udf_update_tag(oepos.bh->b_data, loffset);
- mark_buffer_dirty(oepos.bh);
- } else {
- mark_inode_dirty(table);
- }
}
/* It's possible that stealing the block emptied the extent */
- if (elen) {
- udf_write_aext(table, &epos, &eloc, elen, 1);
-
- if (!epos.bh) {
- iinfo->i_lenAlloc += adsize;
- mark_inode_dirty(table);
- } else {
- aed = (struct allocExtDesc *)epos.bh->b_data;
- le32_add_cpu(&aed->lengthAllocDescs, adsize);
- udf_update_tag(epos.bh->b_data, epos.offset);
- mark_buffer_dirty(epos.bh);
- }
- }
+ if (elen)
+ __udf_add_aext(table, &epos, &eloc, elen, 1);
}
brelse(epos.bh);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 055746350d16..87dc16d15572 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -539,9 +539,18 @@ static int udf_do_extend_file(struct inode *inode,
udf_add_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1);
count++;
- } else
+ } else {
+ struct kernel_lb_addr tmploc;
+ uint32_t tmplen;
+
udf_write_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1);
+ /*
+ * We've rewritten the last extent but there may be empty
+ * indirect extent after it - enter it.
+ */
+ udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0);
+ }
/* Managed to do everything necessary? */
if (!blocks)
@@ -1867,22 +1876,90 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
return inode;
}
-int udf_add_aext(struct inode *inode, struct extent_position *epos,
- struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+int udf_setup_indirect_aext(struct inode *inode, int block,
+ struct extent_position *epos)
{
- int adsize;
- struct short_ad *sad = NULL;
- struct long_ad *lad = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct buffer_head *bh;
struct allocExtDesc *aed;
- uint8_t *ptr;
- struct udf_inode_info *iinfo = UDF_I(inode);
+ struct extent_position nepos;
+ struct kernel_lb_addr neloc;
+ int ver, adsize;
- if (!epos->bh)
- ptr = iinfo->i_ext.i_data + epos->offset -
- udf_file_entry_alloc_offset(inode) +
- iinfo->i_lenEAttr;
+ if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
- ptr = epos->bh->b_data + epos->offset;
+ return -EIO;
+
+ neloc.logicalBlockNum = block;
+ neloc.partitionReferenceNum = epos->block.partitionReferenceNum;
+
+ bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0));
+ if (!bh)
+ return -EIO;
+ lock_buffer(bh);
+ memset(bh->b_data, 0x00, sb->s_blocksize);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ mark_buffer_dirty_inode(bh, inode);
+
+ aed = (struct allocExtDesc *)(bh->b_data);
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) {
+ aed->previousAllocExtLocation =
+ cpu_to_le32(epos->block.logicalBlockNum);
+ }
+ aed->lengthAllocDescs = cpu_to_le32(0);
+ if (UDF_SB(sb)->s_udfrev >= 0x0200)
+ ver = 3;
+ else
+ ver = 2;
+ udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block,
+ sizeof(struct tag));
+
+ nepos.block = neloc;
+ nepos.offset = sizeof(struct allocExtDesc);
+ nepos.bh = bh;
+
+ /*
+ * Do we have to copy current last extent to make space for indirect
+ * one?
+ */
+ if (epos->offset + adsize > sb->s_blocksize) {
+ struct kernel_lb_addr cp_loc;
+ uint32_t cp_len;
+ int cp_type;
+
+ epos->offset -= adsize;
+ cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0);
+ cp_len |= ((uint32_t)cp_type) << 30;
+
+ __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1);
+ udf_write_aext(inode, epos, &nepos.block,
+ sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
+ } else {
+ __udf_add_aext(inode, epos, &nepos.block,
+ sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
+ }
+
+ brelse(epos->bh);
+ *epos = nepos;
+
+ return 0;
+}
+
+/*
+ * Append extent at the given position - should be the first free one in inode
+ * / indirect extent. This function assumes there is enough space in the inode
+ * or indirect extent. Use udf_add_aext() if you didn't check for this before.
+ */
+int __udf_add_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+{
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ struct allocExtDesc *aed;
+ int adsize;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
@@ -1891,88 +1968,14 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos,
else
return -EIO;
- if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
- unsigned char *sptr, *dptr;
- struct buffer_head *nbh;
- int err, loffset;
- struct kernel_lb_addr obloc = epos->block;
-
- epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
- obloc.partitionReferenceNum,
- obloc.logicalBlockNum, &err);
- if (!epos->block.logicalBlockNum)
- return -ENOSPC;
- nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
- &epos->block,
- 0));
- if (!nbh)
- return -EIO;
- lock_buffer(nbh);
- memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
- set_buffer_uptodate(nbh);
- unlock_buffer(nbh);
- mark_buffer_dirty_inode(nbh, inode);
-
- aed = (struct allocExtDesc *)(nbh->b_data);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
- aed->previousAllocExtLocation =
- cpu_to_le32(obloc.logicalBlockNum);
- if (epos->offset + adsize > inode->i_sb->s_blocksize) {
- loffset = epos->offset;
- aed->lengthAllocDescs = cpu_to_le32(adsize);
- sptr = ptr - adsize;
- dptr = nbh->b_data + sizeof(struct allocExtDesc);
- memcpy(dptr, sptr, adsize);
- epos->offset = sizeof(struct allocExtDesc) + adsize;
- } else {
- loffset = epos->offset + adsize;
- aed->lengthAllocDescs = cpu_to_le32(0);
- sptr = ptr;
- epos->offset = sizeof(struct allocExtDesc);
-
- if (epos->bh) {
- aed = (struct allocExtDesc *)epos->bh->b_data;
- le32_add_cpu(&aed->lengthAllocDescs, adsize);
- } else {
- iinfo->i_lenAlloc += adsize;
- mark_inode_dirty(inode);
- }
- }
- if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200)
- udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
- epos->block.logicalBlockNum, sizeof(struct tag));
- else
- udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
- epos->block.logicalBlockNum, sizeof(struct tag));
- switch (iinfo->i_alloc_type) {
- case ICBTAG_FLAG_AD_SHORT:
- sad = (struct short_ad *)sptr;
- sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
- inode->i_sb->s_blocksize);
- sad->extPosition =
- cpu_to_le32(epos->block.logicalBlockNum);
- break;
- case ICBTAG_FLAG_AD_LONG:
- lad = (struct long_ad *)sptr;
- lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
- inode->i_sb->s_blocksize);
- lad->extLocation = cpu_to_lelb(epos->block);
- memset(lad->impUse, 0x00, sizeof(lad->impUse));
- break;
- }
- if (epos->bh) {
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
- UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
- udf_update_tag(epos->bh->b_data, loffset);
- else
- udf_update_tag(epos->bh->b_data,
- sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(epos->bh, inode);
- brelse(epos->bh);
- } else {
- mark_inode_dirty(inode);
- }
- epos->bh = nbh;
+ if (!epos->bh) {
+ WARN_ON(iinfo->i_lenAlloc !=
+ epos->offset - udf_file_entry_alloc_offset(inode));
+ } else {
+ aed = (struct allocExtDesc *)epos->bh->b_data;
+ WARN_ON(le32_to_cpu(aed->lengthAllocDescs) !=
+ epos->offset - sizeof(struct allocExtDesc));
+ WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize);
}
udf_write_aext(inode, epos, eloc, elen, inc);
@@ -1996,6 +1999,41 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos,
return 0;
}
+/*
+ * Append extent at given position - should be the first free one in inode
+ * / indirect extent. Takes care of allocating and linking indirect blocks.
+ */
+int udf_add_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+{
+ int adsize;
+ struct super_block *sb = inode->i_sb;
+
+ if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
+ else
+ return -EIO;
+
+ if (epos->offset + (2 * adsize) > sb->s_blocksize) {
+ int err;
+ int new_block;
+
+ new_block = udf_new_block(sb, NULL,
+ epos->block.partitionReferenceNum,
+ epos->block.logicalBlockNum, &err);
+ if (!new_block)
+ return -ENOSPC;
+
+ err = udf_setup_indirect_aext(inode, new_block, epos);
+ if (err)
+ return err;
+ }
+
+ return __udf_add_aext(inode, epos, eloc, elen, inc);
+}
+
void udf_write_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
@@ -2048,14 +2086,29 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos,
epos->offset += adsize;
}
+/*
+ * Only 1 indirect extent in a row really makes sense but allow upto 16 in case
+ * someone does some weird stuff.
+ */
+#define UDF_MAX_INDIR_EXTS 16
+
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
{
int8_t etype;
+ unsigned int indirections = 0;
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
(EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
int block;
+
+ if (++indirections > UDF_MAX_INDIR_EXTS) {
+ udf_err(inode->i_sb,
+ "too many indirect extents in inode %lu\n",
+ inode->i_ino);
+ return -1;
+ }
+
epos->block = *eloc;
epos->offset = sizeof(struct allocExtDesc);
brelse(epos->bh);
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 81155b9b445b..0fbb4c7c72e8 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -179,7 +179,8 @@ static int __init init_inodecache(void)
udf_inode_cachep = kmem_cache_create("udf_inode_cache",
sizeof(struct udf_inode_info),
0, (SLAB_RECLAIM_ACCOUNT |
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD |
+ SLAB_ACCOUNT),
init_once);
if (!udf_inode_cachep)
return -ENOMEM;
@@ -1586,6 +1587,13 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
}
/*
+ * Maximum number of Terminating Descriptor redirections. The chosen number is
+ * arbitrary - just that we hopefully don't limit any real use of rewritten
+ * inode on write-once media but avoid looping for too long on corrupted media.
+ */
+#define UDF_MAX_TD_NESTING 64
+
+/*
* Process a main/reserve volume descriptor sequence.
* @block First block of first extent of the sequence.
* @lastblock Lastblock of first extent of the sequence.
@@ -1609,6 +1617,7 @@ static noinline int udf_process_sequence(
uint16_t ident;
long next_s = 0, next_e = 0;
int ret;
+ unsigned int indirections = 0;
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
@@ -1679,6 +1688,12 @@ static noinline int udf_process_sequence(
}
break;
case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
+ if (++indirections > UDF_MAX_TD_NESTING) {
+ udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING);
+ brelse(bh);
+ return -EIO;
+ }
+
vds[VDS_POS_TERMINATING_DESC].block = block;
if (next_e) {
block = next_s;
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index ce169b49429d..fa0044b6b81d 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -158,6 +158,10 @@ extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
extern long udf_block_map(struct inode *, sector_t);
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
struct kernel_lb_addr *, uint32_t *, sector_t *);
+extern int udf_setup_indirect_aext(struct inode *inode, int block,
+ struct extent_position *epos);
+extern int __udf_add_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc);
extern int udf_add_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int);
extern void udf_write_aext(struct inode *, struct extent_position *,
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index ab478e62baae..e788a05aab83 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -128,11 +128,15 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
if (c < 0x80U)
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
else if (c < 0x800U) {
+ if (utf_o->u_len > (UDF_NAME_LEN - 4))
+ break;
utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0xc0 | (c >> 6));
utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0x80 | (c & 0x3f));
} else {
+ if (utf_o->u_len > (UDF_NAME_LEN - 5))
+ break;
utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0xe0 | (c >> 12));
utf_o->u_name[utf_o->u_len++] =
@@ -173,17 +177,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
{
unsigned c, i, max_val, utf_char;
- int utf_cnt, u_len;
+ int utf_cnt, u_len, u_ch;
memset(ocu, 0, sizeof(dstring) * length);
ocu[0] = 8;
max_val = 0xffU;
+ u_ch = 1;
try_again:
u_len = 0U;
utf_char = 0U;
utf_cnt = 0U;
for (i = 0U; i < utf->u_len; i++) {
+ /* Name didn't fit? */
+ if (u_len + 1 + u_ch >= length)
+ return 0;
+
c = (uint8_t)utf->u_name[i];
/* Complete a multi-byte UTF-8 character */
@@ -225,6 +234,7 @@ try_again:
if (max_val == 0xffU) {
max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U;
+ u_ch = 2;
goto try_again;
}
goto error_out;
@@ -277,7 +287,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
c = (c << 8) | ocu[i++];
len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
- UDF_NAME_LEN - utf_o->u_len);
+ UDF_NAME_LEN - 2 - utf_o->u_len);
/* Valid character? */
if (len >= 0)
utf_o->u_len += len;
@@ -295,15 +305,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
int len;
unsigned i, max_val;
uint16_t uni_char;
- int u_len;
+ int u_len, u_ch;
memset(ocu, 0, sizeof(dstring) * length);
ocu[0] = 8;
max_val = 0xffU;
+ u_ch = 1;
try_again:
u_len = 0U;
for (i = 0U; i < uni->u_len; i++) {
+ /* Name didn't fit? */
+ if (u_len + 1 + u_ch >= length)
+ return 0;
len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
if (!len)
continue;
@@ -316,6 +330,7 @@ try_again:
if (uni_char > max_val) {
max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U;
+ u_ch = 2;
goto try_again;
}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index f6390eec02ca..442fd52ebffe 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1427,7 +1427,7 @@ static int __init init_inodecache(void)
ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
sizeof(struct ufs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (ufs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h
index cc6b768fc068..d1c66e465ca5 100644
--- a/fs/xfs/kmem.h
+++ b/fs/xfs/kmem.h
@@ -84,6 +84,7 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags)
#define KM_ZONE_HWALIGN SLAB_HWCACHE_ALIGN
#define KM_ZONE_RECLAIM SLAB_RECLAIM_ACCOUNT
#define KM_ZONE_SPREAD SLAB_MEM_SPREAD
+#define KM_ZONE_ACCOUNT SLAB_ACCOUNT
#define kmem_zone kmem_cache
#define kmem_zone_t struct kmem_cache
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 3479294c1d58..a708e38b494c 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -535,6 +535,7 @@ xfs_agfl_write_verify(
}
const struct xfs_buf_ops xfs_agfl_buf_ops = {
+ .name = "xfs_agfl",
.verify_read = xfs_agfl_read_verify,
.verify_write = xfs_agfl_write_verify,
};
@@ -1926,7 +1927,7 @@ xfs_alloc_space_available(
* Decide whether to use this allocation group for this allocation.
* If so, fix up the btree freelist's size.
*/
-STATIC int /* error */
+int /* error */
xfs_alloc_fix_freelist(
struct xfs_alloc_arg *args, /* allocation argument structure */
int flags) /* XFS_ALLOC_FLAG_... */
@@ -2339,6 +2340,7 @@ xfs_agf_write_verify(
}
const struct xfs_buf_ops xfs_agf_buf_ops = {
+ .name = "xfs_agf",
.verify_read = xfs_agf_read_verify,
.verify_write = xfs_agf_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
index 0ecde4d5cac8..135eb3d24db7 100644
--- a/fs/xfs/libxfs/xfs_alloc.h
+++ b/fs/xfs/libxfs/xfs_alloc.h
@@ -235,5 +235,6 @@ xfs_alloc_get_rec(
int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
+int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
#endif /* __XFS_ALLOC_H__ */
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 90de071dd4c2..444626ddbd1b 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -293,14 +293,7 @@ xfs_allocbt_verify(
level = be16_to_cpu(block->bb_level);
switch (block->bb_magic) {
case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
- if (!xfs_sb_version_hascrc(&mp->m_sb))
- return false;
- if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
- return false;
- if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
- return false;
- if (pag &&
- be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+ if (!xfs_btree_sblock_v5hdr_verify(bp))
return false;
/* fall through */
case cpu_to_be32(XFS_ABTB_MAGIC):
@@ -311,14 +304,7 @@ xfs_allocbt_verify(
return false;
break;
case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
- if (!xfs_sb_version_hascrc(&mp->m_sb))
- return false;
- if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
- return false;
- if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
- return false;
- if (pag &&
- be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+ if (!xfs_btree_sblock_v5hdr_verify(bp))
return false;
/* fall through */
case cpu_to_be32(XFS_ABTC_MAGIC):
@@ -332,21 +318,7 @@ xfs_allocbt_verify(
return false;
}
- /* numrecs verification */
- if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[level != 0])
- return false;
-
- /* sibling pointer verification */
- if (!block->bb_u.s.bb_leftsib ||
- (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
- block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
- return false;
- if (!block->bb_u.s.bb_rightsib ||
- (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
- block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
- return false;
-
- return true;
+ return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]);
}
static void
@@ -379,6 +351,7 @@ xfs_allocbt_write_verify(
}
const struct xfs_buf_ops xfs_allocbt_buf_ops = {
+ .name = "xfs_allocbt",
.verify_read = xfs_allocbt_read_verify,
.verify_write = xfs_allocbt_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index f949818fa1c7..fa3b948ef9c2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -207,7 +207,7 @@ xfs_attr_set(
struct xfs_trans_res tres;
xfs_fsblock_t firstblock;
int rsvd = (flags & ATTR_ROOT) != 0;
- int error, err2, committed, local;
+ int error, err2, local;
XFS_STATS_INC(mp, xs_attr_set);
@@ -334,25 +334,15 @@ xfs_attr_set(
*/
xfs_bmap_init(args.flist, args.firstblock);
error = xfs_attr_shortform_to_leaf(&args);
- if (!error) {
- error = xfs_bmap_finish(&args.trans, args.flist,
- &committed);
- }
+ if (!error)
+ error = xfs_bmap_finish(&args.trans, args.flist, dp);
if (error) {
- ASSERT(committed);
args.trans = NULL;
xfs_bmap_cancel(&flist);
goto out;
}
/*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args.trans, dp, 0);
-
- /*
* Commit the leaf transformation. We'll need another (linked)
* transaction to add the new attribute to the leaf.
*/
@@ -568,7 +558,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
{
xfs_inode_t *dp;
struct xfs_buf *bp;
- int retval, error, committed, forkoff;
+ int retval, error, forkoff;
trace_xfs_attr_leaf_addname(args);
@@ -628,25 +618,15 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
*/
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_attr3_leaf_to_node(args);
- if (!error) {
- error = xfs_bmap_finish(&args->trans, args->flist,
- &committed);
- }
+ if (!error)
+ error = xfs_bmap_finish(&args->trans, args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
return error;
}
/*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
-
- /*
* Commit the current trans (including the inode) and start
* a new one.
*/
@@ -729,25 +709,14 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
/* bp is gone due to xfs_da_shrink_inode */
- if (!error) {
+ if (!error)
error = xfs_bmap_finish(&args->trans,
- args->flist,
- &committed);
- }
+ args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
return error;
}
-
- /*
- * bmap_finish() may have committed the last trans
- * and started a new one. We need the inode to be
- * in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
}
/*
@@ -775,7 +744,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
{
xfs_inode_t *dp;
struct xfs_buf *bp;
- int error, committed, forkoff;
+ int error, forkoff;
trace_xfs_attr_leaf_removename(args);
@@ -803,23 +772,13 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
/* bp is gone due to xfs_da_shrink_inode */
- if (!error) {
- error = xfs_bmap_finish(&args->trans, args->flist,
- &committed);
- }
+ if (!error)
+ error = xfs_bmap_finish(&args->trans, args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
return error;
}
-
- /*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
}
return 0;
}
@@ -877,7 +836,7 @@ xfs_attr_node_addname(xfs_da_args_t *args)
xfs_da_state_blk_t *blk;
xfs_inode_t *dp;
xfs_mount_t *mp;
- int committed, retval, error;
+ int retval, error;
trace_xfs_attr_node_addname(args);
@@ -938,27 +897,16 @@ restart:
state = NULL;
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_attr3_leaf_to_node(args);
- if (!error) {
+ if (!error)
error = xfs_bmap_finish(&args->trans,
- args->flist,
- &committed);
- }
+ args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
goto out;
}
/*
- * bmap_finish() may have committed the last trans
- * and started a new one. We need the inode to be
- * in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
-
- /*
* Commit the node conversion and start the next
* trans in the chain.
*/
@@ -977,23 +925,13 @@ restart:
*/
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_da3_split(state);
- if (!error) {
- error = xfs_bmap_finish(&args->trans, args->flist,
- &committed);
- }
+ if (!error)
+ error = xfs_bmap_finish(&args->trans, args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
goto out;
}
-
- /*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
} else {
/*
* Addition succeeded, update Btree hashvals.
@@ -1086,25 +1024,14 @@ restart:
if (retval && (state->path.active > 1)) {
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_da3_join(state);
- if (!error) {
+ if (!error)
error = xfs_bmap_finish(&args->trans,
- args->flist,
- &committed);
- }
+ args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
goto out;
}
-
- /*
- * bmap_finish() may have committed the last trans
- * and started a new one. We need the inode to be
- * in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
}
/*
@@ -1146,7 +1073,7 @@ xfs_attr_node_removename(xfs_da_args_t *args)
xfs_da_state_blk_t *blk;
xfs_inode_t *dp;
struct xfs_buf *bp;
- int retval, error, committed, forkoff;
+ int retval, error, forkoff;
trace_xfs_attr_node_removename(args);
@@ -1220,24 +1147,13 @@ xfs_attr_node_removename(xfs_da_args_t *args)
if (retval && (state->path.active > 1)) {
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_da3_join(state);
- if (!error) {
- error = xfs_bmap_finish(&args->trans, args->flist,
- &committed);
- }
+ if (!error)
+ error = xfs_bmap_finish(&args->trans, args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
goto out;
}
-
- /*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
-
/*
* Commit the Btree join operation and start a new trans.
*/
@@ -1265,25 +1181,14 @@ xfs_attr_node_removename(xfs_da_args_t *args)
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
/* bp is gone due to xfs_da_shrink_inode */
- if (!error) {
+ if (!error)
error = xfs_bmap_finish(&args->trans,
- args->flist,
- &committed);
- }
+ args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
goto out;
}
-
- /*
- * bmap_finish() may have committed the last trans
- * and started a new one. We need the inode to be
- * in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
} else
xfs_trans_brelse(args->trans, bp);
}
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index aa187f7ba2dd..01a5ecfedfcf 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -328,6 +328,7 @@ xfs_attr3_leaf_read_verify(
}
const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = {
+ .name = "xfs_attr3_leaf",
.verify_read = xfs_attr3_leaf_read_verify,
.verify_write = xfs_attr3_leaf_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 5ab95ffa4ae9..a572532a55cd 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -201,6 +201,7 @@ xfs_attr3_rmt_write_verify(
}
const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
+ .name = "xfs_attr3_rmt",
.verify_read = xfs_attr3_rmt_read_verify,
.verify_write = xfs_attr3_rmt_write_verify,
};
@@ -447,8 +448,6 @@ xfs_attr_rmtval_set(
* Roll through the "value", allocating blocks on disk as required.
*/
while (blkcnt > 0) {
- int committed;
-
/*
* Allocate a single extent, up to the size of the value.
*
@@ -466,24 +465,14 @@ xfs_attr_rmtval_set(
error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
args->total, &map, &nmap, args->flist);
- if (!error) {
- error = xfs_bmap_finish(&args->trans, args->flist,
- &committed);
- }
+ if (!error)
+ error = xfs_bmap_finish(&args->trans, args->flist, dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
return error;
}
- /*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, dp, 0);
-
ASSERT(nmap == 1);
ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
(map.br_startblock != HOLESTARTBLOCK));
@@ -614,31 +603,20 @@ xfs_attr_rmtval_remove(
blkcnt = args->rmtblkcnt;
done = 0;
while (!done) {
- int committed;
-
xfs_bmap_init(args->flist, args->firstblock);
error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
XFS_BMAPI_ATTRFORK, 1, args->firstblock,
args->flist, &done);
- if (!error) {
+ if (!error)
error = xfs_bmap_finish(&args->trans, args->flist,
- &committed);
- }
+ args->dp);
if (error) {
- ASSERT(committed);
args->trans = NULL;
xfs_bmap_cancel(args->flist);
return error;
}
/*
- * bmap_finish() may have committed the last trans and started
- * a new one. We need the inode to be in all transactions.
- */
- if (committed)
- xfs_trans_ijoin(args->trans, args->dp, 0);
-
- /*
* Close out trans and start the next one in the chain.
*/
error = xfs_trans_roll(&args->trans, args->dp);
diff --git a/fs/xfs/libxfs/xfs_bit.c b/fs/xfs/libxfs/xfs_bit.c
index 0e8885a59646..0a94cce5ea35 100644
--- a/fs/xfs/libxfs/xfs_bit.c
+++ b/fs/xfs/libxfs/xfs_bit.c
@@ -32,13 +32,13 @@ int
xfs_bitmap_empty(uint *map, uint size)
{
uint i;
- uint ret = 0;
for (i = 0; i < size; i++) {
- ret |= map[i];
+ if (map[i] != 0)
+ return 0;
}
- return (ret == 0);
+ return 1;
}
/*
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 119c2422aac7..ef00156f4f96 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -325,9 +325,11 @@ xfs_check_block(
/*
* Check that the extents for the inode ip are in the right order in all
- * btree leaves.
+ * btree leaves. THis becomes prohibitively expensive for large extent count
+ * files, so don't bother with inodes that have more than 10,000 extents in
+ * them. The btree record ordering checks will still be done, so for such large
+ * bmapbt constructs that is going to catch most corruptions.
*/
-
STATIC void
xfs_bmap_check_leaf_extents(
xfs_btree_cur_t *cur, /* btree cursor or null */
@@ -352,6 +354,10 @@ xfs_bmap_check_leaf_extents(
return;
}
+ /* skip large extent count inodes */
+ if (ip->i_d.di_nextents > 10000)
+ return;
+
bno = NULLFSBLOCK;
mp = ip->i_mount;
ifp = XFS_IFORK_PTR(ip, whichfork);
@@ -1111,7 +1117,6 @@ xfs_bmap_add_attrfork(
xfs_trans_t *tp; /* transaction pointer */
int blks; /* space reservation */
int version = 1; /* superblock attr version */
- int committed; /* xaction was committed */
int logflags; /* logging flags */
int error; /* error return value */
@@ -1214,7 +1219,7 @@ xfs_bmap_add_attrfork(
xfs_log_sb(tp);
}
- error = xfs_bmap_finish(&tp, &flist, &committed);
+ error = xfs_bmap_finish(&tp, &flist, NULL);
if (error)
goto bmap_cancel;
error = xfs_trans_commit(tp);
@@ -1723,10 +1728,11 @@ xfs_bmap_add_extent_delay_real(
xfs_filblks_t temp=0; /* value for da_new calculations */
xfs_filblks_t temp2=0;/* value for da_new calculations */
int tmp_rval; /* partial logging flags */
+ int whichfork = XFS_DATA_FORK;
struct xfs_mount *mp;
- mp = bma->tp ? bma->tp->t_mountp : NULL;
- ifp = XFS_IFORK_PTR(bma->ip, XFS_DATA_FORK);
+ mp = bma->ip->i_mount;
+ ifp = XFS_IFORK_PTR(bma->ip, whichfork);
ASSERT(bma->idx >= 0);
ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
@@ -1785,7 +1791,7 @@ xfs_bmap_add_extent_delay_real(
* Don't set contiguous if the combined extent would be too large.
* Also check for all-three-contiguous being too large.
*/
- if (bma->idx < bma->ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
+ if (bma->idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
state |= BMAP_RIGHT_VALID;
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx + 1), &RIGHT);
@@ -2016,10 +2022,10 @@ xfs_bmap_add_extent_delay_real(
XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
}
- if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
+ if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
bma->firstblock, bma->flist,
- &bma->cur, 1, &tmp_rval, XFS_DATA_FORK);
+ &bma->cur, 1, &tmp_rval, whichfork);
rval |= tmp_rval;
if (error)
goto done;
@@ -2100,10 +2106,10 @@ xfs_bmap_add_extent_delay_real(
XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
}
- if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
+ if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
bma->firstblock, bma->flist, &bma->cur, 1,
- &tmp_rval, XFS_DATA_FORK);
+ &tmp_rval, whichfork);
rval |= tmp_rval;
if (error)
goto done;
@@ -2169,10 +2175,10 @@ xfs_bmap_add_extent_delay_real(
XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
}
- if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
+ if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
bma->firstblock, bma->flist, &bma->cur,
- 1, &tmp_rval, XFS_DATA_FORK);
+ 1, &tmp_rval, whichfork);
rval |= tmp_rval;
if (error)
goto done;
@@ -2215,13 +2221,13 @@ xfs_bmap_add_extent_delay_real(
}
/* convert to a btree if necessary */
- if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
+ if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
int tmp_logflags; /* partial log flag return val */
ASSERT(bma->cur == NULL);
error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
bma->firstblock, bma->flist, &bma->cur,
- da_old > 0, &tmp_logflags, XFS_DATA_FORK);
+ da_old > 0, &tmp_logflags, whichfork);
bma->logflags |= tmp_logflags;
if (error)
goto done;
@@ -2242,7 +2248,7 @@ xfs_bmap_add_extent_delay_real(
if (bma->cur)
bma->cur->bc_private.b.allocated = 0;
- xfs_bmap_check_leaf_extents(bma->cur, bma->ip, XFS_DATA_FORK);
+ xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork);
done:
bma->logflags |= rval;
return error;
@@ -2939,7 +2945,7 @@ xfs_bmap_add_extent_hole_real(
int state; /* state bits, accessed thru macros */
struct xfs_mount *mp;
- mp = bma->tp ? bma->tp->t_mountp : NULL;
+ mp = bma->ip->i_mount;
ifp = XFS_IFORK_PTR(bma->ip, whichfork);
ASSERT(bma->idx >= 0);
@@ -5950,7 +5956,6 @@ xfs_bmap_split_extent(
struct xfs_trans *tp;
struct xfs_bmap_free free_list;
xfs_fsblock_t firstfsb;
- int committed;
int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
@@ -5971,7 +5976,7 @@ xfs_bmap_split_extent(
if (error)
goto out;
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto out;
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index a160f8a5a3fc..423a34e832bd 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -195,7 +195,7 @@ void xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len,
struct xfs_bmap_free *flist, struct xfs_mount *mp);
void xfs_bmap_cancel(struct xfs_bmap_free *flist);
int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
- int *committed);
+ struct xfs_inode *ip);
void xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork);
int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork);
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 6b0cf6546a82..1637c37bfbaa 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -720,6 +720,7 @@ xfs_bmbt_write_verify(
}
const struct xfs_buf_ops xfs_bmbt_buf_ops = {
+ .name = "xfs_bmbt",
.verify_read = xfs_bmbt_read_verify,
.verify_write = xfs_bmbt_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index af1bbee5586e..a0eb18ce3ad3 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -4080,3 +4080,61 @@ xfs_btree_change_owner(
return 0;
}
+
+/**
+ * xfs_btree_sblock_v5hdr_verify() -- verify the v5 fields of a short-format
+ * btree block
+ *
+ * @bp: buffer containing the btree block
+ * @max_recs: pointer to the m_*_mxr max records field in the xfs mount
+ * @pag_max_level: pointer to the per-ag max level field
+ */
+bool
+xfs_btree_sblock_v5hdr_verify(
+ struct xfs_buf *bp)
+{
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ struct xfs_perag *pag = bp->b_pag;
+
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
+ return false;
+ if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
+ return false;
+ if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
+ return false;
+ if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+ return false;
+ return true;
+}
+
+/**
+ * xfs_btree_sblock_verify() -- verify a short-format btree block
+ *
+ * @bp: buffer containing the btree block
+ * @max_recs: maximum records allowed in this btree node
+ */
+bool
+xfs_btree_sblock_verify(
+ struct xfs_buf *bp,
+ unsigned int max_recs)
+{
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+
+ /* numrecs verification */
+ if (be16_to_cpu(block->bb_numrecs) > max_recs)
+ return false;
+
+ /* sibling pointer verification */
+ if (!block->bb_u.s.bb_leftsib ||
+ (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
+ block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
+ return false;
+ if (!block->bb_u.s.bb_rightsib ||
+ (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
+ block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
+ return false;
+
+ return true;
+}
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index 992dec0638f3..2e874be70209 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -472,4 +472,7 @@ static inline int xfs_btree_get_level(struct xfs_btree_block *block)
#define XFS_BTREE_TRACE_ARGR(c, r)
#define XFS_BTREE_TRACE_CURSOR(c, t)
+bool xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp);
+bool xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs);
+
#endif /* __XFS_BTREE_H__ */
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index e89a0f8f827c..097bf7717d80 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -245,6 +245,7 @@ xfs_da3_node_read_verify(
}
const struct xfs_buf_ops xfs_da3_node_buf_ops = {
+ .name = "xfs_da3_node",
.verify_read = xfs_da3_node_read_verify,
.verify_write = xfs_da3_node_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 9c10e2b8cfcb..aa17cb788946 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -123,6 +123,7 @@ xfs_dir3_block_write_verify(
}
const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
+ .name = "xfs_dir3_block",
.verify_read = xfs_dir3_block_read_verify,
.verify_write = xfs_dir3_block_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
index af71a84f343c..725fc7841fde 100644
--- a/fs/xfs/libxfs/xfs_dir2_data.c
+++ b/fs/xfs/libxfs/xfs_dir2_data.c
@@ -305,11 +305,13 @@ xfs_dir3_data_write_verify(
}
const struct xfs_buf_ops xfs_dir3_data_buf_ops = {
+ .name = "xfs_dir3_data",
.verify_read = xfs_dir3_data_read_verify,
.verify_write = xfs_dir3_data_write_verify,
};
static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
+ .name = "xfs_dir3_data_reada",
.verify_read = xfs_dir3_data_reada_verify,
.verify_write = xfs_dir3_data_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 3923e1f94697..b887fb2a2bcf 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -245,11 +245,13 @@ xfs_dir3_leafn_write_verify(
}
const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {
+ .name = "xfs_dir3_leaf1",
.verify_read = xfs_dir3_leaf1_read_verify,
.verify_write = xfs_dir3_leaf1_write_verify,
};
const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = {
+ .name = "xfs_dir3_leafn",
.verify_read = xfs_dir3_leafn_read_verify,
.verify_write = xfs_dir3_leafn_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 70b0cb2fd556..63ee03db796c 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -150,6 +150,7 @@ xfs_dir3_free_write_verify(
}
const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
+ .name = "xfs_dir3_free",
.verify_read = xfs_dir3_free_read_verify,
.verify_write = xfs_dir3_free_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index 5331b7f0460c..3cc3cf767474 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -54,7 +54,7 @@ xfs_dqcheck(
xfs_dqid_t id,
uint type, /* used only when IO_dorepair is true */
uint flags,
- char *str)
+ const char *str)
{
xfs_dqblk_t *d = (xfs_dqblk_t *)ddq;
int errs = 0;
@@ -207,7 +207,8 @@ xfs_dquot_buf_verify_crc(
STATIC bool
xfs_dquot_buf_verify(
struct xfs_mount *mp,
- struct xfs_buf *bp)
+ struct xfs_buf *bp,
+ int warn)
{
struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr;
xfs_dqid_t id = 0;
@@ -240,8 +241,7 @@ xfs_dquot_buf_verify(
if (i == 0)
id = be32_to_cpu(ddq->d_id);
- error = xfs_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN,
- "xfs_dquot_buf_verify");
+ error = xfs_dqcheck(mp, ddq, id + i, 0, warn, __func__);
if (error)
return false;
}
@@ -256,7 +256,7 @@ xfs_dquot_buf_read_verify(
if (!xfs_dquot_buf_verify_crc(mp, bp))
xfs_buf_ioerror(bp, -EFSBADCRC);
- else if (!xfs_dquot_buf_verify(mp, bp))
+ else if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN))
xfs_buf_ioerror(bp, -EFSCORRUPTED);
if (bp->b_error)
@@ -264,6 +264,25 @@ xfs_dquot_buf_read_verify(
}
/*
+ * readahead errors are silent and simply leave the buffer as !done so a real
+ * read will then be run with the xfs_dquot_buf_ops verifier. See
+ * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than
+ * reporting the failure.
+ */
+static void
+xfs_dquot_buf_readahead_verify(
+ struct xfs_buf *bp)
+{
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+
+ if (!xfs_dquot_buf_verify_crc(mp, bp) ||
+ !xfs_dquot_buf_verify(mp, bp, 0)) {
+ xfs_buf_ioerror(bp, -EIO);
+ bp->b_flags &= ~XBF_DONE;
+ }
+}
+
+/*
* we don't calculate the CRC here as that is done when the dquot is flushed to
* the buffer after the update is done. This ensures that the dquot in the
* buffer always has an up-to-date CRC value.
@@ -274,7 +293,7 @@ xfs_dquot_buf_write_verify(
{
struct xfs_mount *mp = bp->b_target->bt_mount;
- if (!xfs_dquot_buf_verify(mp, bp)) {
+ if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN)) {
xfs_buf_ioerror(bp, -EFSCORRUPTED);
xfs_verifier_error(bp);
return;
@@ -282,7 +301,13 @@ xfs_dquot_buf_write_verify(
}
const struct xfs_buf_ops xfs_dquot_buf_ops = {
+ .name = "xfs_dquot",
.verify_read = xfs_dquot_buf_read_verify,
.verify_write = xfs_dquot_buf_write_verify,
};
+const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
+ .name = "xfs_dquot_ra",
+ .verify_read = xfs_dquot_buf_readahead_verify,
+ .verify_write = xfs_dquot_buf_write_verify,
+};
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 8774498ce0ff..e2536bb1c760 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -786,7 +786,7 @@ typedef struct xfs_agfl {
__be64 agfl_lsn;
__be32 agfl_crc;
__be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */
-} xfs_agfl_t;
+} __attribute__((packed)) xfs_agfl_t;
#define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc)
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 70c1db99f6a7..66d702e6b9ff 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2572,6 +2572,7 @@ xfs_agi_write_verify(
}
const struct xfs_buf_ops xfs_agi_buf_ops = {
+ .name = "xfs_agi",
.verify_read = xfs_agi_read_verify,
.verify_write = xfs_agi_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index f39b285beb19..c679f3c05b63 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -221,7 +221,6 @@ xfs_inobt_verify(
{
struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
- struct xfs_perag *pag = bp->b_pag;
unsigned int level;
/*
@@ -237,14 +236,7 @@ xfs_inobt_verify(
switch (block->bb_magic) {
case cpu_to_be32(XFS_IBT_CRC_MAGIC):
case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
- if (!xfs_sb_version_hascrc(&mp->m_sb))
- return false;
- if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
- return false;
- if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
- return false;
- if (pag &&
- be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno)
+ if (!xfs_btree_sblock_v5hdr_verify(bp))
return false;
/* fall through */
case cpu_to_be32(XFS_IBT_MAGIC):
@@ -254,24 +246,12 @@ xfs_inobt_verify(
return 0;
}
- /* numrecs and level verification */
+ /* level verification */
level = be16_to_cpu(block->bb_level);
if (level >= mp->m_in_maxlevels)
return false;
- if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[level != 0])
- return false;
-
- /* sibling pointer verification */
- if (!block->bb_u.s.bb_leftsib ||
- (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks &&
- block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK)))
- return false;
- if (!block->bb_u.s.bb_rightsib ||
- (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks &&
- block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK)))
- return false;
- return true;
+ return xfs_btree_sblock_verify(bp, mp->m_inobt_mxr[level != 0]);
}
static void
@@ -304,6 +284,7 @@ xfs_inobt_write_verify(
}
const struct xfs_buf_ops xfs_inobt_buf_ops = {
+ .name = "xfs_inobt",
.verify_read = xfs_inobt_read_verify,
.verify_write = xfs_inobt_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 268c00f4f83a..1aabfda669b0 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -62,11 +62,14 @@ xfs_inobp_check(
* has not had the inode cores stamped into it. Hence for readahead, the buffer
* may be potentially invalid.
*
- * If the readahead buffer is invalid, we don't want to mark it with an error,
- * but we do want to clear the DONE status of the buffer so that a followup read
- * will re-read it from disk. This will ensure that we don't get an unnecessary
- * warnings during log recovery and we don't get unnecssary panics on debug
- * kernels.
+ * If the readahead buffer is invalid, we need to mark it with an error and
+ * clear the DONE status of the buffer so that a followup read will re-read it
+ * from disk. We don't report the error otherwise to avoid warnings during log
+ * recovery and we don't get unnecssary panics on debug kernels. We use EIO here
+ * because all we want to do is say readahead failed; there is no-one to report
+ * the error to, so this will distinguish it from a non-ra verifier failure.
+ * Changes to this readahead error behavour also need to be reflected in
+ * xfs_dquot_buf_readahead_verify().
*/
static void
xfs_inode_buf_verify(
@@ -93,6 +96,7 @@ xfs_inode_buf_verify(
XFS_RANDOM_ITOBP_INOTOBP))) {
if (readahead) {
bp->b_flags &= ~XBF_DONE;
+ xfs_buf_ioerror(bp, -EIO);
return;
}
@@ -132,11 +136,13 @@ xfs_inode_buf_write_verify(
}
const struct xfs_buf_ops xfs_inode_buf_ops = {
+ .name = "xfs_inode",
.verify_read = xfs_inode_buf_read_verify,
.verify_write = xfs_inode_buf_write_verify,
};
const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
+ .name = "xxfs_inode_ra",
.verify_read = xfs_inode_buf_readahead_verify,
.verify_write = xfs_inode_buf_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h
index 1c55ccbb379d..8e385f91d660 100644
--- a/fs/xfs/libxfs/xfs_log_recover.h
+++ b/fs/xfs/libxfs/xfs_log_recover.h
@@ -60,6 +60,7 @@ typedef struct xlog_recover {
*/
#define XLOG_BC_TABLE_SIZE 64
+#define XLOG_RECOVER_CRCPASS 0
#define XLOG_RECOVER_PASS1 1
#define XLOG_RECOVER_PASS2 2
diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index 1b0a08379759..f51078f1e92a 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -153,7 +153,7 @@ typedef __uint16_t xfs_qwarncnt_t;
#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq,
- xfs_dqid_t id, uint type, uint flags, char *str);
+ xfs_dqid_t id, uint type, uint flags, const char *str);
extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
#endif /* __XFS_QUOTA_H__ */
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index a0b071d881a0..8a53eaa349f4 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -679,11 +679,13 @@ xfs_sb_write_verify(
}
const struct xfs_buf_ops xfs_sb_buf_ops = {
+ .name = "xfs_sb",
.verify_read = xfs_sb_read_verify,
.verify_write = xfs_sb_write_verify,
};
const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
+ .name = "xfs_sb_quiet",
.verify_read = xfs_sb_quiet_read_verify,
.verify_write = xfs_sb_write_verify,
};
diff --git a/fs/xfs/libxfs/xfs_shared.h b/fs/xfs/libxfs/xfs_shared.h
index 5be529707903..15c3ceb845b9 100644
--- a/fs/xfs/libxfs/xfs_shared.h
+++ b/fs/xfs/libxfs/xfs_shared.h
@@ -49,6 +49,7 @@ extern const struct xfs_buf_ops xfs_inobt_buf_ops;
extern const struct xfs_buf_ops xfs_inode_buf_ops;
extern const struct xfs_buf_ops xfs_inode_buf_ra_ops;
extern const struct xfs_buf_ops xfs_dquot_buf_ops;
+extern const struct xfs_buf_ops xfs_dquot_buf_ra_ops;
extern const struct xfs_buf_ops xfs_sb_buf_ops;
extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
extern const struct xfs_buf_ops xfs_symlink_buf_ops;
diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
index cb6fd20a4d3d..2e2c6716b623 100644
--- a/fs/xfs/libxfs/xfs_symlink_remote.c
+++ b/fs/xfs/libxfs/xfs_symlink_remote.c
@@ -168,6 +168,7 @@ xfs_symlink_write_verify(
}
const struct xfs_buf_ops xfs_symlink_buf_ops = {
+ .name = "xfs_symlink",
.verify_read = xfs_symlink_read_verify,
.verify_write = xfs_symlink_write_verify,
};
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 29e7e5dd5178..379c089fb051 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1917,6 +1917,7 @@ xfs_vm_readpage(
struct file *unused,
struct page *page)
{
+ trace_xfs_vm_readpage(page->mapping->host, 1);
return mpage_readpage(page, xfs_get_blocks);
}
@@ -1927,6 +1928,7 @@ xfs_vm_readpages(
struct list_head *pages,
unsigned nr_pages)
{
+ trace_xfs_vm_readpages(mapping->host, nr_pages);
return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks);
}
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index dbae6490a79a..45ec9e40150c 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -91,32 +91,32 @@ xfs_zero_extent(
* last due to locking considerations. We never free any extents in
* the first transaction.
*
- * Return 1 if the given transaction was committed and a new one
- * started, and 0 otherwise in the committed parameter.
+ * If an inode *ip is provided, rejoin it to the transaction if
+ * the transaction was committed.
*/
int /* error */
xfs_bmap_finish(
struct xfs_trans **tp, /* transaction pointer addr */
struct xfs_bmap_free *flist, /* i/o: list extents to free */
- int *committed)/* xact committed or not */
+ struct xfs_inode *ip)
{
struct xfs_efd_log_item *efd; /* extent free data */
struct xfs_efi_log_item *efi; /* extent free intention */
int error; /* error return value */
+ int committed;/* xact committed or not */
struct xfs_bmap_free_item *free; /* free extent item */
struct xfs_bmap_free_item *next; /* next item on free list */
ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
- if (flist->xbf_count == 0) {
- *committed = 0;
+ if (flist->xbf_count == 0)
return 0;
- }
+
efi = xfs_trans_get_efi(*tp, flist->xbf_count);
for (free = flist->xbf_first; free; free = free->xbfi_next)
xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock,
free->xbfi_blockcount);
- error = __xfs_trans_roll(tp, NULL, committed);
+ error = __xfs_trans_roll(tp, ip, &committed);
if (error) {
/*
* If the transaction was committed, drop the EFD reference
@@ -128,16 +128,13 @@ xfs_bmap_finish(
* transaction so we should return committed=1 even though we're
* returning an error.
*/
- if (*committed) {
+ if (committed) {
xfs_efi_release(efi);
xfs_force_shutdown((*tp)->t_mountp,
(error == -EFSCORRUPTED) ?
SHUTDOWN_CORRUPT_INCORE :
SHUTDOWN_META_IO_ERROR);
- } else {
- *committed = 1;
}
-
return error;
}
@@ -969,7 +966,6 @@ xfs_alloc_file_space(
xfs_bmbt_irec_t imaps[1], *imapp;
xfs_bmap_free_t free_list;
uint qblocks, resblks, resrtextents;
- int committed;
int error;
trace_xfs_alloc_file_space(ip);
@@ -1064,23 +1060,20 @@ xfs_alloc_file_space(
error = xfs_bmapi_write(tp, ip, startoffset_fsb,
allocatesize_fsb, alloc_type, &firstfsb,
resblks, imapp, &nimaps, &free_list);
- if (error) {
+ if (error)
goto error0;
- }
/*
* Complete the transaction
*/
- error = xfs_bmap_finish(&tp, &free_list, &committed);
- if (error) {
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
+ if (error)
goto error0;
- }
error = xfs_trans_commit(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- if (error) {
+ if (error)
break;
- }
allocated_fsb = imapp->br_blockcount;
@@ -1206,7 +1199,6 @@ xfs_free_file_space(
xfs_off_t offset,
xfs_off_t len)
{
- int committed;
int done;
xfs_fileoff_t endoffset_fsb;
int error;
@@ -1346,17 +1338,15 @@ xfs_free_file_space(
error = xfs_bunmapi(tp, ip, startoffset_fsb,
endoffset_fsb - startoffset_fsb,
0, 2, &firstfsb, &free_list, &done);
- if (error) {
+ if (error)
goto error0;
- }
/*
* complete the transaction
*/
- error = xfs_bmap_finish(&tp, &free_list, &committed);
- if (error) {
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
+ if (error)
goto error0;
- }
error = xfs_trans_commit(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -1434,7 +1424,6 @@ xfs_shift_file_space(
int error;
struct xfs_bmap_free free_list;
xfs_fsblock_t first_block;
- int committed;
xfs_fileoff_t stop_fsb;
xfs_fileoff_t next_fsb;
xfs_fileoff_t shift_fsb;
@@ -1526,7 +1515,7 @@ xfs_shift_file_space(
if (error)
goto out_bmap_cancel;
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto out_bmap_cancel;
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index ace91e7c713e..daed4bfb85b2 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -604,6 +604,13 @@ found:
}
}
+ /*
+ * Clear b_error if this is a lookup from a caller that doesn't expect
+ * valid data to be found in the buffer.
+ */
+ if (!(flags & XBF_READ))
+ xfs_buf_ioerror(bp, 0);
+
XFS_STATS_INC(target->bt_mount, xb_get);
trace_xfs_buf_get(bp, flags, _RET_IP_);
return bp;
@@ -1045,7 +1052,7 @@ xfs_buf_ioend_work(
xfs_buf_ioend(bp);
}
-void
+static void
xfs_buf_ioend_async(
struct xfs_buf *bp)
{
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index c79b717d9b88..c75721acd867 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -132,6 +132,7 @@ struct xfs_buf_map {
struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) };
struct xfs_buf_ops {
+ char *name;
void (*verify_read)(struct xfs_buf *);
void (*verify_write)(struct xfs_buf *);
};
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 7ac6c5c586cb..9c44d38dcd1f 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -306,7 +306,7 @@ xfs_qm_dqalloc(
xfs_fsblock_t firstblock;
xfs_bmap_free_t flist;
xfs_bmbt_irec_t map;
- int nmaps, error, committed;
+ int nmaps, error;
xfs_buf_t *bp;
xfs_trans_t *tp = *tpp;
@@ -379,11 +379,12 @@ xfs_qm_dqalloc(
xfs_trans_bhold(tp, bp);
- if ((error = xfs_bmap_finish(tpp, &flist, &committed))) {
+ error = xfs_bmap_finish(tpp, &flist, NULL);
+ if (error)
goto error1;
- }
- if (committed) {
+ /* Transaction was committed? */
+ if (*tpp != tp) {
tp = *tpp;
xfs_trans_bjoin(tp, bp);
} else {
@@ -393,9 +394,9 @@ xfs_qm_dqalloc(
*O_bpp = bp;
return 0;
- error1:
+error1:
xfs_bmap_cancel(&flist);
- error0:
+error0:
xfs_iunlock(quotip, XFS_ILOCK_EXCL);
return error;
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 74d0e5966ebc..88693a98fac5 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -164,9 +164,9 @@ xfs_verifier_error(
{
struct xfs_mount *mp = bp->b_target->bt_mount;
- xfs_alert(mp, "Metadata %s detected at %pF, block 0x%llx",
+ xfs_alert(mp, "Metadata %s detected at %pF, %s block 0x%llx",
bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
- __return_address, bp->b_bn);
+ __return_address, bp->b_ops->name, bp->b_bn);
xfs_alert(mp, "Unmount and run xfs_repair");
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index f5392ab2def1..ebe9b8290a70 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -402,19 +402,26 @@ xfs_file_splice_read(
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
- xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
-
trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
- /* for dax, we need to avoid the page cache */
- if (IS_DAX(VFS_I(ip)))
- ret = default_file_splice_read(infilp, ppos, pipe, count, flags);
- else
- ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
- if (ret > 0)
- XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
+ /*
+ * DAX inodes cannot ues the page cache for splice, so we have to push
+ * them through the VFS IO path. This means it goes through
+ * ->read_iter, which for us takes the XFS_IOLOCK_SHARED. Hence we
+ * cannot lock the splice operation at this level for DAX inodes.
+ */
+ if (IS_DAX(VFS_I(ip))) {
+ ret = default_file_splice_read(infilp, ppos, pipe, count,
+ flags);
+ goto out;
+ }
+ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
+ ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
+out:
+ if (ret > 0)
+ XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
return ret;
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 8ee393996b7d..ae3758a90ed6 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1143,7 +1143,6 @@ xfs_create(
xfs_bmap_free_t free_list;
xfs_fsblock_t first_block;
bool unlock_dp_on_error = false;
- int committed;
prid_t prid;
struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL;
@@ -1226,7 +1225,7 @@ xfs_create(
* pointing to itself.
*/
error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
- prid, resblks > 0, &ip, &committed);
+ prid, resblks > 0, &ip, NULL);
if (error)
goto out_trans_cancel;
@@ -1275,7 +1274,7 @@ xfs_create(
*/
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto out_bmap_cancel;
@@ -1427,7 +1426,6 @@ xfs_link(
int error;
xfs_bmap_free_t free_list;
xfs_fsblock_t first_block;
- int committed;
int resblks;
trace_xfs_link(tdp, target_name);
@@ -1502,11 +1500,10 @@ xfs_link(
* link transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
xfs_trans_set_sync(tp);
- }
- error = xfs_bmap_finish (&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error) {
xfs_bmap_cancel(&free_list);
goto error_return;
@@ -1555,7 +1552,6 @@ xfs_itruncate_extents(
xfs_fileoff_t first_unmap_block;
xfs_fileoff_t last_block;
xfs_filblks_t unmap_len;
- int committed;
int error = 0;
int done = 0;
@@ -1601,9 +1597,7 @@ xfs_itruncate_extents(
* Duplicate the transaction that has the permanent
* reservation and commit the old transaction.
*/
- error = xfs_bmap_finish(&tp, &free_list, &committed);
- if (committed)
- xfs_trans_ijoin(tp, ip, 0);
+ error = xfs_bmap_finish(&tp, &free_list, ip);
if (error)
goto out_bmap_cancel;
@@ -1774,7 +1768,6 @@ xfs_inactive_ifree(
{
xfs_bmap_free_t free_list;
xfs_fsblock_t first_block;
- int committed;
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
int error;
@@ -1841,7 +1834,7 @@ xfs_inactive_ifree(
* Just ignore errors at this point. There is nothing we can do except
* to try to keep going. Make sure it's not a silent error.
*/
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error) {
xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
__func__, error);
@@ -2523,7 +2516,6 @@ xfs_remove(
int error = 0;
xfs_bmap_free_t free_list;
xfs_fsblock_t first_block;
- int committed;
uint resblks;
trace_xfs_remove(dp, name);
@@ -2624,7 +2616,7 @@ xfs_remove(
if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
xfs_trans_set_sync(tp);
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto out_bmap_cancel;
@@ -2701,7 +2693,6 @@ xfs_finish_rename(
struct xfs_trans *tp,
struct xfs_bmap_free *free_list)
{
- int committed = 0;
int error;
/*
@@ -2711,7 +2702,7 @@ xfs_finish_rename(
if (tp->t_mountp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
xfs_trans_set_sync(tp);
- error = xfs_bmap_finish(&tp, free_list, &committed);
+ error = xfs_bmap_finish(&tp, free_list, NULL);
if (error) {
xfs_bmap_cancel(free_list);
xfs_trans_cancel(tp);
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index f4f5b43cf647..d81bdc080370 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -129,7 +129,6 @@ xfs_iomap_write_direct(
xfs_trans_t *tp;
xfs_bmap_free_t free_list;
uint qblocks, resblks, resrtextents;
- int committed;
int error;
int lockmode;
int bmapi_flags = XFS_BMAPI_PREALLOC;
@@ -203,15 +202,20 @@ xfs_iomap_write_direct(
* this outside the transaction context, but if we commit and then crash
* we may not have zeroed the blocks and this will be exposed on
* recovery of the allocation. Hence we must zero before commit.
+ *
* Further, if we are mapping unwritten extents here, we need to zero
* and convert them to written so that we don't need an unwritten extent
* callback for DAX. This also means that we need to be able to dip into
- * the reserve block pool if there is no space left but we need to do
- * unwritten extent conversion.
+ * the reserve block pool for bmbt block allocation if there is no space
+ * left but we need to do unwritten extent conversion.
*/
+
if (IS_DAX(VFS_I(ip))) {
bmapi_flags = XFS_BMAPI_CONVERT | XFS_BMAPI_ZERO;
- tp->t_flags |= XFS_TRANS_RESERVE;
+ if (ISUNWRITTEN(imap)) {
+ tp->t_flags |= XFS_TRANS_RESERVE;
+ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;
+ }
}
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
resblks, resrtextents);
@@ -247,7 +251,7 @@ xfs_iomap_write_direct(
/*
* Complete the transaction
*/
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto out_bmap_cancel;
@@ -693,7 +697,7 @@ xfs_iomap_write_allocate(
xfs_bmap_free_t free_list;
xfs_filblks_t count_fsb;
xfs_trans_t *tp;
- int nimaps, committed;
+ int nimaps;
int error = 0;
int nres;
@@ -794,7 +798,7 @@ xfs_iomap_write_allocate(
if (error)
goto trans_cancel;
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto trans_cancel;
@@ -852,7 +856,6 @@ xfs_iomap_write_unwritten(
xfs_bmap_free_t free_list;
xfs_fsize_t i_size;
uint resblks;
- int committed;
int error;
trace_xfs_unwritten_convert(ip, offset, count);
@@ -924,7 +927,7 @@ xfs_iomap_write_unwritten(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
}
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto error_on_bmapi_transaction;
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index f52c72a1a06f..9c9a1c9bcc7f 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -1188,10 +1188,16 @@ xlog_iodone(xfs_buf_t *bp)
int aborted = 0;
/*
- * Race to shutdown the filesystem if we see an error.
+ * Race to shutdown the filesystem if we see an error or the iclog is in
+ * IOABORT state. The IOABORT state is only set in DEBUG mode to inject
+ * CRC errors into log recovery.
*/
- if (XFS_TEST_ERROR(bp->b_error, l->l_mp,
- XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
+ if (XFS_TEST_ERROR(bp->b_error, l->l_mp, XFS_ERRTAG_IODONE_IOERR,
+ XFS_RANDOM_IODONE_IOERR) ||
+ iclog->ic_state & XLOG_STATE_IOABORT) {
+ if (iclog->ic_state & XLOG_STATE_IOABORT)
+ iclog->ic_state &= ~XLOG_STATE_IOABORT;
+
xfs_buf_ioerror_alert(bp, __func__);
xfs_buf_stale(bp);
xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR);
@@ -1838,6 +1844,23 @@ xlog_sync(
/* calculcate the checksum */
iclog->ic_header.h_crc = xlog_cksum(log, &iclog->ic_header,
iclog->ic_datap, size);
+#ifdef DEBUG
+ /*
+ * Intentionally corrupt the log record CRC based on the error injection
+ * frequency, if defined. This facilitates testing log recovery in the
+ * event of torn writes. Hence, set the IOABORT state to abort the log
+ * write on I/O completion and shutdown the fs. The subsequent mount
+ * detects the bad CRC and attempts to recover.
+ */
+ if (log->l_badcrc_factor &&
+ (prandom_u32() % log->l_badcrc_factor == 0)) {
+ iclog->ic_header.h_crc &= 0xAAAAAAAA;
+ iclog->ic_state |= XLOG_STATE_IOABORT;
+ xfs_warn(log->l_mp,
+ "Intentionally corrupted log record at LSN 0x%llx. Shutdown imminent.",
+ be64_to_cpu(iclog->ic_header.h_lsn));
+ }
+#endif
bp->b_io_length = BTOBB(count);
bp->b_fspriv = iclog;
@@ -2045,12 +2068,14 @@ xlog_print_tic_res(
"QM_DQCLUSTER",
"QM_QINOCREATE",
"QM_QUOTAOFF_END",
- "SB_UNIT",
"FSYNC_TS",
"GROWFSRT_ALLOC",
"GROWFSRT_ZERO",
"GROWFSRT_FREE",
- "SWAPEXT"
+ "SWAPEXT",
+ "CHECKPOINT",
+ "ICREATE",
+ "CREATE_TMPFILE"
};
xfs_warn(mp, "xlog_write: reservation summary:");
@@ -2791,11 +2816,19 @@ xlog_state_do_callback(
}
} while (!ioerrors && loopdidcallbacks);
+#ifdef DEBUG
/*
- * make one last gasp attempt to see if iclogs are being left in
- * limbo..
+ * Make one last gasp attempt to see if iclogs are being left in limbo.
+ * If the above loop finds an iclog earlier than the current iclog and
+ * in one of the syncing states, the current iclog is put into
+ * DO_CALLBACK and the callbacks are deferred to the completion of the
+ * earlier iclog. Walk the iclogs in order and make sure that no iclog
+ * is in DO_CALLBACK unless an earlier iclog is in one of the syncing
+ * states.
+ *
+ * Note that SYNCING|IOABORT is a valid state so we cannot just check
+ * for ic_state == SYNCING.
*/
-#ifdef DEBUG
if (funcdidcallbacks) {
first_iclog = iclog = log->l_iclog;
do {
@@ -2810,7 +2843,7 @@ xlog_state_do_callback(
* IOERROR - give up hope all ye who enter here
*/
if (iclog->ic_state == XLOG_STATE_WANT_SYNC ||
- iclog->ic_state == XLOG_STATE_SYNCING ||
+ iclog->ic_state & XLOG_STATE_SYNCING ||
iclog->ic_state == XLOG_STATE_DONE_SYNC ||
iclog->ic_state == XLOG_STATE_IOERROR )
break;
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 8daba7491b13..ed8896310c00 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -62,6 +62,7 @@ static inline uint xlog_get_client_id(__be32 i)
#define XLOG_STATE_CALLBACK 0x0020 /* Callback functions now */
#define XLOG_STATE_DIRTY 0x0040 /* Dirty IC log, not ready for ACTIVE status*/
#define XLOG_STATE_IOERROR 0x0080 /* IO error happened in sync'ing log */
+#define XLOG_STATE_IOABORT 0x0100 /* force abort on I/O completion (debug) */
#define XLOG_STATE_ALL 0x7FFF /* All possible valid flags */
#define XLOG_STATE_NOTUSED 0x8000 /* This IC log not being used */
@@ -410,6 +411,8 @@ struct xlog {
/* The following field are used for debugging; need to hold icloglock */
#ifdef DEBUG
void *l_iclog_bak[XLOG_MAX_ICLOGS];
+ /* log record crc error injection factor */
+ uint32_t l_badcrc_factor;
#endif
};
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index c5ecaacdd218..da37beb76f6e 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -61,6 +61,9 @@ xlog_recover_check_summary(
#else
#define xlog_recover_check_summary(log)
#endif
+STATIC int
+xlog_do_recovery_pass(
+ struct xlog *, xfs_daddr_t, xfs_daddr_t, int, xfs_daddr_t *);
/*
* This structure is used during recovery to record the buf log items which
@@ -868,6 +871,351 @@ validate_head:
}
/*
+ * Seek backwards in the log for log record headers.
+ *
+ * Given a starting log block, walk backwards until we find the provided number
+ * of records or hit the provided tail block. The return value is the number of
+ * records encountered or a negative error code. The log block and buffer
+ * pointer of the last record seen are returned in rblk and rhead respectively.
+ */
+STATIC int
+xlog_rseek_logrec_hdr(
+ struct xlog *log,
+ xfs_daddr_t head_blk,
+ xfs_daddr_t tail_blk,
+ int count,
+ struct xfs_buf *bp,
+ xfs_daddr_t *rblk,
+ struct xlog_rec_header **rhead,
+ bool *wrapped)
+{
+ int i;
+ int error;
+ int found = 0;
+ char *offset = NULL;
+ xfs_daddr_t end_blk;
+
+ *wrapped = false;
+
+ /*
+ * Walk backwards from the head block until we hit the tail or the first
+ * block in the log.
+ */
+ end_blk = head_blk > tail_blk ? tail_blk : 0;
+ for (i = (int) head_blk - 1; i >= end_blk; i--) {
+ error = xlog_bread(log, i, 1, bp, &offset);
+ if (error)
+ goto out_error;
+
+ if (*(__be32 *) offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
+ *rblk = i;
+ *rhead = (struct xlog_rec_header *) offset;
+ if (++found == count)
+ break;
+ }
+ }
+
+ /*
+ * If we haven't hit the tail block or the log record header count,
+ * start looking again from the end of the physical log. Note that
+ * callers can pass head == tail if the tail is not yet known.
+ */
+ if (tail_blk >= head_blk && found != count) {
+ for (i = log->l_logBBsize - 1; i >= (int) tail_blk; i--) {
+ error = xlog_bread(log, i, 1, bp, &offset);
+ if (error)
+ goto out_error;
+
+ if (*(__be32 *)offset ==
+ cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
+ *wrapped = true;
+ *rblk = i;
+ *rhead = (struct xlog_rec_header *) offset;
+ if (++found == count)
+ break;
+ }
+ }
+ }
+
+ return found;
+
+out_error:
+ return error;
+}
+
+/*
+ * Seek forward in the log for log record headers.
+ *
+ * Given head and tail blocks, walk forward from the tail block until we find
+ * the provided number of records or hit the head block. The return value is the
+ * number of records encountered or a negative error code. The log block and
+ * buffer pointer of the last record seen are returned in rblk and rhead
+ * respectively.
+ */
+STATIC int
+xlog_seek_logrec_hdr(
+ struct xlog *log,
+ xfs_daddr_t head_blk,
+ xfs_daddr_t tail_blk,
+ int count,
+ struct xfs_buf *bp,
+ xfs_daddr_t *rblk,
+ struct xlog_rec_header **rhead,
+ bool *wrapped)
+{
+ int i;
+ int error;
+ int found = 0;
+ char *offset = NULL;
+ xfs_daddr_t end_blk;
+
+ *wrapped = false;
+
+ /*
+ * Walk forward from the tail block until we hit the head or the last
+ * block in the log.
+ */
+ end_blk = head_blk > tail_blk ? head_blk : log->l_logBBsize - 1;
+ for (i = (int) tail_blk; i <= end_blk; i++) {
+ error = xlog_bread(log, i, 1, bp, &offset);
+ if (error)
+ goto out_error;
+
+ if (*(__be32 *) offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
+ *rblk = i;
+ *rhead = (struct xlog_rec_header *) offset;
+ if (++found == count)
+ break;
+ }
+ }
+
+ /*
+ * If we haven't hit the head block or the log record header count,
+ * start looking again from the start of the physical log.
+ */
+ if (tail_blk > head_blk && found != count) {
+ for (i = 0; i < (int) head_blk; i++) {
+ error = xlog_bread(log, i, 1, bp, &offset);
+ if (error)
+ goto out_error;
+
+ if (*(__be32 *)offset ==
+ cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
+ *wrapped = true;
+ *rblk = i;
+ *rhead = (struct xlog_rec_header *) offset;
+ if (++found == count)
+ break;
+ }
+ }
+ }
+
+ return found;
+
+out_error:
+ return error;
+}
+
+/*
+ * Check the log tail for torn writes. This is required when torn writes are
+ * detected at the head and the head had to be walked back to a previous record.
+ * The tail of the previous record must now be verified to ensure the torn
+ * writes didn't corrupt the previous tail.
+ *
+ * Return an error if CRC verification fails as recovery cannot proceed.
+ */
+STATIC int
+xlog_verify_tail(
+ struct xlog *log,
+ xfs_daddr_t head_blk,
+ xfs_daddr_t tail_blk)
+{
+ struct xlog_rec_header *thead;
+ struct xfs_buf *bp;
+ xfs_daddr_t first_bad;
+ int count;
+ int error = 0;
+ bool wrapped;
+ xfs_daddr_t tmp_head;
+
+ bp = xlog_get_bp(log, 1);
+ if (!bp)
+ return -ENOMEM;
+
+ /*
+ * Seek XLOG_MAX_ICLOGS + 1 records past the current tail record to get
+ * a temporary head block that points after the last possible
+ * concurrently written record of the tail.
+ */
+ count = xlog_seek_logrec_hdr(log, head_blk, tail_blk,
+ XLOG_MAX_ICLOGS + 1, bp, &tmp_head, &thead,
+ &wrapped);
+ if (count < 0) {
+ error = count;
+ goto out;
+ }
+
+ /*
+ * If the call above didn't find XLOG_MAX_ICLOGS + 1 records, we ran
+ * into the actual log head. tmp_head points to the start of the record
+ * so update it to the actual head block.
+ */
+ if (count < XLOG_MAX_ICLOGS + 1)
+ tmp_head = head_blk;
+
+ /*
+ * We now have a tail and temporary head block that covers at least
+ * XLOG_MAX_ICLOGS records from the tail. We need to verify that these
+ * records were completely written. Run a CRC verification pass from
+ * tail to head and return the result.
+ */
+ error = xlog_do_recovery_pass(log, tmp_head, tail_blk,
+ XLOG_RECOVER_CRCPASS, &first_bad);
+
+out:
+ xlog_put_bp(bp);
+ return error;
+}
+
+/*
+ * Detect and trim torn writes from the head of the log.
+ *
+ * Storage without sector atomicity guarantees can result in torn writes in the
+ * log in the event of a crash. Our only means to detect this scenario is via
+ * CRC verification. While we can't always be certain that CRC verification
+ * failure is due to a torn write vs. an unrelated corruption, we do know that
+ * only a certain number (XLOG_MAX_ICLOGS) of log records can be written out at
+ * one time. Therefore, CRC verify up to XLOG_MAX_ICLOGS records at the head of
+ * the log and treat failures in this range as torn writes as a matter of
+ * policy. In the event of CRC failure, the head is walked back to the last good
+ * record in the log and the tail is updated from that record and verified.
+ */
+STATIC int
+xlog_verify_head(
+ struct xlog *log,
+ xfs_daddr_t *head_blk, /* in/out: unverified head */
+ xfs_daddr_t *tail_blk, /* out: tail block */
+ struct xfs_buf *bp,
+ xfs_daddr_t *rhead_blk, /* start blk of last record */
+ struct xlog_rec_header **rhead, /* ptr to last record */
+ bool *wrapped) /* last rec. wraps phys. log */
+{
+ struct xlog_rec_header *tmp_rhead;
+ struct xfs_buf *tmp_bp;
+ xfs_daddr_t first_bad;
+ xfs_daddr_t tmp_rhead_blk;
+ int found;
+ int error;
+ bool tmp_wrapped;
+
+ /*
+ * Search backwards through the log looking for the log record header
+ * block. This wraps all the way back around to the head so something is
+ * seriously wrong if we can't find it.
+ */
+ found = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp, rhead_blk,
+ rhead, wrapped);
+ if (found < 0)
+ return found;
+ if (!found) {
+ xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
+ return -EIO;
+ }
+
+ *tail_blk = BLOCK_LSN(be64_to_cpu((*rhead)->h_tail_lsn));
+
+ /*
+ * Now that we have a tail block, check the head of the log for torn
+ * writes. Search again until we hit the tail or the maximum number of
+ * log record I/Os that could have been in flight at one time. Use a
+ * temporary buffer so we don't trash the rhead/bp pointer from the
+ * call above.
+ */
+ tmp_bp = xlog_get_bp(log, 1);
+ if (!tmp_bp)
+ return -ENOMEM;
+ error = xlog_rseek_logrec_hdr(log, *head_blk, *tail_blk,
+ XLOG_MAX_ICLOGS, tmp_bp, &tmp_rhead_blk,
+ &tmp_rhead, &tmp_wrapped);
+ xlog_put_bp(tmp_bp);
+ if (error < 0)
+ return error;
+
+ /*
+ * Now run a CRC verification pass over the records starting at the
+ * block found above to the current head. If a CRC failure occurs, the
+ * log block of the first bad record is saved in first_bad.
+ */
+ error = xlog_do_recovery_pass(log, *head_blk, tmp_rhead_blk,
+ XLOG_RECOVER_CRCPASS, &first_bad);
+ if (error == -EFSBADCRC) {
+ /*
+ * We've hit a potential torn write. Reset the error and warn
+ * about it.
+ */
+ error = 0;
+ xfs_warn(log->l_mp,
+"Torn write (CRC failure) detected at log block 0x%llx. Truncating head block from 0x%llx.",
+ first_bad, *head_blk);
+
+ /*
+ * Get the header block and buffer pointer for the last good
+ * record before the bad record.
+ *
+ * Note that xlog_find_tail() clears the blocks at the new head
+ * (i.e., the records with invalid CRC) if the cycle number
+ * matches the the current cycle.
+ */
+ found = xlog_rseek_logrec_hdr(log, first_bad, *tail_blk, 1, bp,
+ rhead_blk, rhead, wrapped);
+ if (found < 0)
+ return found;
+ if (found == 0) /* XXX: right thing to do here? */
+ return -EIO;
+
+ /*
+ * Reset the head block to the starting block of the first bad
+ * log record and set the tail block based on the last good
+ * record.
+ *
+ * Bail out if the updated head/tail match as this indicates
+ * possible corruption outside of the acceptable
+ * (XLOG_MAX_ICLOGS) range. This is a job for xfs_repair...
+ */
+ *head_blk = first_bad;
+ *tail_blk = BLOCK_LSN(be64_to_cpu((*rhead)->h_tail_lsn));
+ if (*head_blk == *tail_blk) {
+ ASSERT(0);
+ return 0;
+ }
+
+ /*
+ * Now verify the tail based on the updated head. This is
+ * required because the torn writes trimmed from the head could
+ * have been written over the tail of a previous record. Return
+ * any errors since recovery cannot proceed if the tail is
+ * corrupt.
+ *
+ * XXX: This leaves a gap in truly robust protection from torn
+ * writes in the log. If the head is behind the tail, the tail
+ * pushes forward to create some space and then a crash occurs
+ * causing the writes into the previous record's tail region to
+ * tear, log recovery isn't able to recover.
+ *
+ * How likely is this to occur? If possible, can we do something
+ * more intelligent here? Is it safe to push the tail forward if
+ * we can determine that the tail is within the range of the
+ * torn write (e.g., the kernel can only overwrite the tail if
+ * it has actually been pushed forward)? Alternatively, could we
+ * somehow prevent this condition at runtime?
+ */
+ error = xlog_verify_tail(log, *head_blk, *tail_blk);
+ }
+
+ return error;
+}
+
+/*
* Find the sync block number or the tail of the log.
*
* This will be the block number of the last record to have its
@@ -893,13 +1241,13 @@ xlog_find_tail(
xlog_op_header_t *op_head;
char *offset = NULL;
xfs_buf_t *bp;
- int error, i, found;
+ int error;
xfs_daddr_t umount_data_blk;
xfs_daddr_t after_umount_blk;
+ xfs_daddr_t rhead_blk;
xfs_lsn_t tail_lsn;
int hblks;
-
- found = 0;
+ bool wrapped = false;
/*
* Find previous log record
@@ -923,48 +1271,16 @@ xlog_find_tail(
}
/*
- * Search backwards looking for log record header block
+ * Trim the head block back to skip over torn records. We can have
+ * multiple log I/Os in flight at any time, so we assume CRC failures
+ * back through the previous several records are torn writes and skip
+ * them.
*/
ASSERT(*head_blk < INT_MAX);
- for (i = (int)(*head_blk) - 1; i >= 0; i--) {
- error = xlog_bread(log, i, 1, bp, &offset);
- if (error)
- goto done;
-
- if (*(__be32 *)offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
- found = 1;
- break;
- }
- }
- /*
- * If we haven't found the log record header block, start looking
- * again from the end of the physical log. XXXmiken: There should be
- * a check here to make sure we didn't search more than N blocks in
- * the previous code.
- */
- if (!found) {
- for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) {
- error = xlog_bread(log, i, 1, bp, &offset);
- if (error)
- goto done;
-
- if (*(__be32 *)offset ==
- cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) {
- found = 2;
- break;
- }
- }
- }
- if (!found) {
- xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
- xlog_put_bp(bp);
- ASSERT(0);
- return -EIO;
- }
-
- /* find blk_no of tail of log */
- rhead = (xlog_rec_header_t *)offset;
- *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
+ error = xlog_verify_head(log, head_blk, tail_blk, bp, &rhead_blk,
+ &rhead, &wrapped);
+ if (error)
+ goto done;
/*
* Reset log values according to the state of the log when we
@@ -976,10 +1292,10 @@ xlog_find_tail(
* written was complete and ended exactly on the end boundary
* of the physical log.
*/
- log->l_prev_block = i;
+ log->l_prev_block = rhead_blk;
log->l_curr_block = (int)*head_blk;
log->l_curr_cycle = be32_to_cpu(rhead->h_cycle);
- if (found == 2)
+ if (wrapped)
log->l_curr_cycle++;
atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));
@@ -1014,12 +1330,13 @@ xlog_find_tail(
} else {
hblks = 1;
}
- after_umount_blk = (i + hblks + (int)
- BTOBB(be32_to_cpu(rhead->h_len))) % log->l_logBBsize;
+ after_umount_blk = rhead_blk + hblks + BTOBB(be32_to_cpu(rhead->h_len));
+ after_umount_blk = do_mod(after_umount_blk, log->l_logBBsize);
tail_lsn = atomic64_read(&log->l_tail_lsn);
if (*head_blk == after_umount_blk &&
be32_to_cpu(rhead->h_num_logops) == 1) {
- umount_data_blk = (i + hblks) % log->l_logBBsize;
+ umount_data_blk = rhead_blk + hblks;
+ umount_data_blk = do_mod(umount_data_blk, log->l_logBBsize);
error = xlog_bread(log, umount_data_blk, 1, bp, &offset);
if (error)
goto done;
@@ -3204,6 +3521,7 @@ xlog_recover_dquot_ra_pass2(
struct xfs_disk_dquot *recddq;
struct xfs_dq_logformat *dq_f;
uint type;
+ int len;
if (mp->m_qflags == 0)
@@ -3224,8 +3542,12 @@ xlog_recover_dquot_ra_pass2(
ASSERT(dq_f);
ASSERT(dq_f->qlf_len == 1);
- xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno,
- XFS_FSB_TO_BB(mp, dq_f->qlf_len), NULL);
+ len = XFS_FSB_TO_BB(mp, dq_f->qlf_len);
+ if (xlog_peek_buffer_cancelled(log, dq_f->qlf_blkno, len, 0))
+ return;
+
+ xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno, len,
+ &xfs_dquot_buf_ra_ops);
}
STATIC void
@@ -4118,26 +4440,69 @@ xlog_recover_process_iunlinks(
mp->m_dmevmask = mp_dmevmask;
}
+STATIC int
+xlog_unpack_data(
+ struct xlog_rec_header *rhead,
+ char *dp,
+ struct xlog *log)
+{
+ int i, j, k;
+
+ for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) &&
+ i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
+ *(__be32 *)dp = *(__be32 *)&rhead->h_cycle_data[i];
+ dp += BBSIZE;
+ }
+
+ if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
+ xlog_in_core_2_t *xhdr = (xlog_in_core_2_t *)rhead;
+ for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) {
+ j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
+ k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
+ *(__be32 *)dp = xhdr[j].hic_xheader.xh_cycle_data[k];
+ dp += BBSIZE;
+ }
+ }
+
+ return 0;
+}
+
/*
- * Upack the log buffer data and crc check it. If the check fails, issue a
- * warning if and only if the CRC in the header is non-zero. This makes the
- * check an advisory warning, and the zero CRC check will prevent failure
- * warnings from being emitted when upgrading the kernel from one that does not
- * add CRCs by default.
- *
- * When filesystems are CRC enabled, this CRC mismatch becomes a fatal log
- * corruption failure
+ * CRC check, unpack and process a log record.
*/
STATIC int
-xlog_unpack_data_crc(
+xlog_recover_process(
+ struct xlog *log,
+ struct hlist_head rhash[],
struct xlog_rec_header *rhead,
char *dp,
- struct xlog *log)
+ int pass)
{
+ int error;
__le32 crc;
crc = xlog_cksum(log, rhead, dp, be32_to_cpu(rhead->h_len));
- if (crc != rhead->h_crc) {
+
+ /*
+ * Nothing else to do if this is a CRC verification pass. Just return
+ * if this a record with a non-zero crc. Unfortunately, mkfs always
+ * sets h_crc to 0 so we must consider this valid even on v5 supers.
+ * Otherwise, return EFSBADCRC on failure so the callers up the stack
+ * know precisely what failed.
+ */
+ if (pass == XLOG_RECOVER_CRCPASS) {
+ if (rhead->h_crc && crc != le32_to_cpu(rhead->h_crc))
+ return -EFSBADCRC;
+ return 0;
+ }
+
+ /*
+ * We're in the normal recovery path. Issue a warning if and only if the
+ * CRC in the header is non-zero. This is an advisory warning and the
+ * zero CRC check prevents warnings from being emitted when upgrading
+ * the kernel from one that does not add CRCs by default.
+ */
+ if (crc != le32_to_cpu(rhead->h_crc)) {
if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
xfs_alert(log->l_mp,
"log record CRC mismatch: found 0x%x, expected 0x%x.",
@@ -4147,47 +4512,18 @@ xlog_unpack_data_crc(
}
/*
- * If we've detected a log record corruption, then we can't
- * recover past this point. Abort recovery if we are enforcing
- * CRC protection by punting an error back up the stack.
+ * If the filesystem is CRC enabled, this mismatch becomes a
+ * fatal log corruption failure.
*/
if (xfs_sb_version_hascrc(&log->l_mp->m_sb))
return -EFSCORRUPTED;
}
- return 0;
-}
-
-STATIC int
-xlog_unpack_data(
- struct xlog_rec_header *rhead,
- char *dp,
- struct xlog *log)
-{
- int i, j, k;
- int error;
-
- error = xlog_unpack_data_crc(rhead, dp, log);
+ error = xlog_unpack_data(rhead, dp, log);
if (error)
return error;
- for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) &&
- i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
- *(__be32 *)dp = *(__be32 *)&rhead->h_cycle_data[i];
- dp += BBSIZE;
- }
-
- if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
- xlog_in_core_2_t *xhdr = (xlog_in_core_2_t *)rhead;
- for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) {
- j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
- k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
- *(__be32 *)dp = xhdr[j].hic_xheader.xh_cycle_data[k];
- dp += BBSIZE;
- }
- }
-
- return 0;
+ return xlog_recover_process_data(log, rhash, rhead, dp, pass);
}
STATIC int
@@ -4239,18 +4575,21 @@ xlog_do_recovery_pass(
struct xlog *log,
xfs_daddr_t head_blk,
xfs_daddr_t tail_blk,
- int pass)
+ int pass,
+ xfs_daddr_t *first_bad) /* out: first bad log rec */
{
xlog_rec_header_t *rhead;
xfs_daddr_t blk_no;
+ xfs_daddr_t rhead_blk;
char *offset;
xfs_buf_t *hbp, *dbp;
- int error = 0, h_size;
+ int error = 0, h_size, h_len;
int bblks, split_bblks;
int hblks, split_hblks, wrapped_hblks;
struct hlist_head rhash[XLOG_RHASH_SIZE];
ASSERT(head_blk != tail_blk);
+ rhead_blk = 0;
/*
* Read the header of the tail block and get the iclog buffer size from
@@ -4274,7 +4613,31 @@ xlog_do_recovery_pass(
error = xlog_valid_rec_header(log, rhead, tail_blk);
if (error)
goto bread_err1;
+
+ /*
+ * xfsprogs has a bug where record length is based on lsunit but
+ * h_size (iclog size) is hardcoded to 32k. Now that we
+ * unconditionally CRC verify the unmount record, this means the
+ * log buffer can be too small for the record and cause an
+ * overrun.
+ *
+ * Detect this condition here. Use lsunit for the buffer size as
+ * long as this looks like the mkfs case. Otherwise, return an
+ * error to avoid a buffer overrun.
+ */
h_size = be32_to_cpu(rhead->h_size);
+ h_len = be32_to_cpu(rhead->h_len);
+ if (h_len > h_size) {
+ if (h_len <= log->l_mp->m_logbsize &&
+ be32_to_cpu(rhead->h_num_logops) == 1) {
+ xfs_warn(log->l_mp,
+ "invalid iclog size (%d bytes), using lsunit (%d bytes)",
+ h_size, log->l_mp->m_logbsize);
+ h_size = log->l_mp->m_logbsize;
+ } else
+ return -EFSCORRUPTED;
+ }
+
if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) &&
(h_size > XLOG_HEADER_CYCLE_SIZE)) {
hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
@@ -4301,7 +4664,7 @@ xlog_do_recovery_pass(
}
memset(rhash, 0, sizeof(rhash));
- blk_no = tail_blk;
+ blk_no = rhead_blk = tail_blk;
if (tail_blk > head_blk) {
/*
* Perform recovery around the end of the physical log.
@@ -4408,19 +4771,18 @@ xlog_do_recovery_pass(
goto bread_err2;
}
- error = xlog_unpack_data(rhead, offset, log);
+ error = xlog_recover_process(log, rhash, rhead, offset,
+ pass);
if (error)
goto bread_err2;
- error = xlog_recover_process_data(log, rhash,
- rhead, offset, pass);
- if (error)
- goto bread_err2;
blk_no += bblks;
+ rhead_blk = blk_no;
}
ASSERT(blk_no >= log->l_logBBsize);
blk_no -= log->l_logBBsize;
+ rhead_blk = blk_no;
}
/* read first part of physical log */
@@ -4441,21 +4803,22 @@ xlog_do_recovery_pass(
if (error)
goto bread_err2;
- error = xlog_unpack_data(rhead, offset, log);
+ error = xlog_recover_process(log, rhash, rhead, offset, pass);
if (error)
goto bread_err2;
- error = xlog_recover_process_data(log, rhash,
- rhead, offset, pass);
- if (error)
- goto bread_err2;
blk_no += bblks + hblks;
+ rhead_blk = blk_no;
}
bread_err2:
xlog_put_bp(dbp);
bread_err1:
xlog_put_bp(hbp);
+
+ if (error && first_bad)
+ *first_bad = rhead_blk;
+
return error;
}
@@ -4493,7 +4856,7 @@ xlog_do_log_recovery(
INIT_LIST_HEAD(&log->l_buf_cancel_table[i]);
error = xlog_do_recovery_pass(log, head_blk, tail_blk,
- XLOG_RECOVER_PASS1);
+ XLOG_RECOVER_PASS1, NULL);
if (error != 0) {
kmem_free(log->l_buf_cancel_table);
log->l_buf_cancel_table = NULL;
@@ -4504,7 +4867,7 @@ xlog_do_log_recovery(
* When it is complete free the table of buf cancel items.
*/
error = xlog_do_recovery_pass(log, head_blk, tail_blk,
- XLOG_RECOVER_PASS2);
+ XLOG_RECOVER_PASS2, NULL);
#ifdef DEBUG
if (!error) {
int i;
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index ab1bac6a3a1c..be02a68b2fe2 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -766,7 +766,6 @@ xfs_growfs_rt_alloc(
{
xfs_fileoff_t bno; /* block number in file */
struct xfs_buf *bp; /* temporary buffer for zeroing */
- int committed; /* transaction committed flag */
xfs_daddr_t d; /* disk block address */
int error; /* error return value */
xfs_fsblock_t firstblock;/* first block allocated in xaction */
@@ -811,7 +810,7 @@ xfs_growfs_rt_alloc(
/*
* Free any blocks freed up in the transaction, then commit.
*/
- error = xfs_bmap_finish(&tp, &flist, &committed);
+ error = xfs_bmap_finish(&tp, &flist, NULL);
if (error)
goto out_bmap_cancel;
error = xfs_trans_commit(tp);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 36bd8825bfb0..59c9b7bd958d 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -137,7 +137,7 @@ static const match_table_t tokens = {
};
-STATIC unsigned long
+STATIC int
suffix_kstrtoint(char *s, unsigned int base, int *res)
{
int last, shift_left_factor = 0, _res;
@@ -1714,8 +1714,8 @@ xfs_init_zones(void)
xfs_inode_zone =
kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode",
- KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | KM_ZONE_SPREAD,
- xfs_fs_inode_init_once);
+ KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | KM_ZONE_SPREAD |
+ KM_ZONE_ACCOUNT, xfs_fs_inode_init_once);
if (!xfs_inode_zone)
goto out_destroy_efi_zone;
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 996481eeb491..b44284c1adda 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -178,7 +178,6 @@ xfs_symlink(
struct xfs_bmap_free free_list;
xfs_fsblock_t first_block;
bool unlock_dp_on_error = false;
- int committed;
xfs_fileoff_t first_fsb;
xfs_filblks_t fs_blocks;
int nmaps;
@@ -387,7 +386,7 @@ xfs_symlink(
xfs_trans_set_sync(tp);
}
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, NULL);
if (error)
goto out_bmap_cancel;
@@ -434,7 +433,6 @@ xfs_inactive_symlink_rmt(
struct xfs_inode *ip)
{
xfs_buf_t *bp;
- int committed;
int done;
int error;
xfs_fsblock_t first_block;
@@ -510,16 +508,10 @@ xfs_inactive_symlink_rmt(
/*
* Commit the first transaction. This logs the EFI and the inode.
*/
- error = xfs_bmap_finish(&tp, &free_list, &committed);
+ error = xfs_bmap_finish(&tp, &free_list, ip);
if (error)
goto error_bmap_cancel;
/*
- * The transaction must have been committed, since there were
- * actually extents freed by xfs_bunmapi. See xfs_bmap_finish.
- * The new tp has the extent freeing and EFDs.
- */
- ASSERT(committed);
- /*
* The first xact was committed, so add the inode to the new one.
* Mark it dirty so it will be logged and moved forward in the log as
* part of every commit.
diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c
index ee70f5dec9dc..641d625eb334 100644
--- a/fs/xfs/xfs_sysfs.c
+++ b/fs/xfs/xfs_sysfs.c
@@ -255,11 +255,47 @@ write_grant_head_show(
}
XFS_SYSFS_ATTR_RO(write_grant_head);
+#ifdef DEBUG
+STATIC ssize_t
+log_badcrc_factor_store(
+ struct kobject *kobject,
+ const char *buf,
+ size_t count)
+{
+ struct xlog *log = to_xlog(kobject);
+ int ret;
+ uint32_t val;
+
+ ret = kstrtouint(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ log->l_badcrc_factor = val;
+
+ return count;
+}
+
+STATIC ssize_t
+log_badcrc_factor_show(
+ struct kobject *kobject,
+ char *buf)
+{
+ struct xlog *log = to_xlog(kobject);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", log->l_badcrc_factor);
+}
+
+XFS_SYSFS_ATTR_RW(log_badcrc_factor);
+#endif /* DEBUG */
+
static struct attribute *xfs_log_attrs[] = {
ATTR_LIST(log_head_lsn),
ATTR_LIST(log_tail_lsn),
ATTR_LIST(reserve_grant_head),
ATTR_LIST(write_grant_head),
+#ifdef DEBUG
+ ATTR_LIST(log_badcrc_factor),
+#endif
NULL,
};
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 877079eb0f8f..391d797cb53f 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1222,6 +1222,32 @@ DEFINE_PAGE_EVENT(xfs_writepage);
DEFINE_PAGE_EVENT(xfs_releasepage);
DEFINE_PAGE_EVENT(xfs_invalidatepage);
+DECLARE_EVENT_CLASS(xfs_readpage_class,
+ TP_PROTO(struct inode *inode, int nr_pages),
+ TP_ARGS(inode, nr_pages),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, ino)
+ __field(int, nr_pages)
+ ),
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = inode->i_ino;
+ __entry->nr_pages = nr_pages;
+ ),
+ TP_printk("dev %d:%d ino 0x%llx nr_pages %d",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino,
+ __entry->nr_pages)
+)
+
+#define DEFINE_READPAGE_EVENT(name) \
+DEFINE_EVENT(xfs_readpage_class, name, \
+ TP_PROTO(struct inode *inode, int nr_pages), \
+ TP_ARGS(inode, nr_pages))
+DEFINE_READPAGE_EVENT(xfs_vm_readpage);
+DEFINE_READPAGE_EVENT(xfs_vm_readpages);
+
DECLARE_EVENT_CLASS(xfs_imap_class,
TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count,
int type, struct xfs_bmbt_irec *irec),
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index ce78534a047e..995170194df0 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -572,12 +572,16 @@ xfs_quota_warn(
struct xfs_dquot *dqp,
int type)
{
- /* no warnings for project quotas - we just return ENOSPC later */
+ enum quota_type qtype;
+
if (dqp->dq_flags & XFS_DQ_PROJ)
- return;
- quota_send_warning(make_kqid(&init_user_ns,
- (dqp->dq_flags & XFS_DQ_USER) ?
- USRQUOTA : GRPQUOTA,
+ qtype = PRJQUOTA;
+ else if (dqp->dq_flags & XFS_DQ_USER)
+ qtype = USRQUOTA;
+ else
+ qtype = GRPQUOTA;
+
+ quota_send_warning(make_kqid(&init_user_ns, qtype,
be32_to_cpu(dqp->q_core.d_id)),
mp->m_super->s_dev, type);
}
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index 0f45f93ef692..1cceca146905 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -54,22 +54,38 @@
#define read_barrier_depends() do { } while (0)
#endif
+#ifndef __smp_mb
+#define __smp_mb() mb()
+#endif
+
+#ifndef __smp_rmb
+#define __smp_rmb() rmb()
+#endif
+
+#ifndef __smp_wmb
+#define __smp_wmb() wmb()
+#endif
+
+#ifndef __smp_read_barrier_depends
+#define __smp_read_barrier_depends() read_barrier_depends()
+#endif
+
#ifdef CONFIG_SMP
#ifndef smp_mb
-#define smp_mb() mb()
+#define smp_mb() __smp_mb()
#endif
#ifndef smp_rmb
-#define smp_rmb() rmb()
+#define smp_rmb() __smp_rmb()
#endif
#ifndef smp_wmb
-#define smp_wmb() wmb()
+#define smp_wmb() __smp_wmb()
#endif
#ifndef smp_read_barrier_depends
-#define smp_read_barrier_depends() read_barrier_depends()
+#define smp_read_barrier_depends() __smp_read_barrier_depends()
#endif
#else /* !CONFIG_SMP */
@@ -92,32 +108,104 @@
#endif /* CONFIG_SMP */
+#ifndef __smp_store_mb
+#define __smp_store_mb(var, value) do { WRITE_ONCE(var, value); __smp_mb(); } while (0)
+#endif
+
+#ifndef __smp_mb__before_atomic
+#define __smp_mb__before_atomic() __smp_mb()
+#endif
+
+#ifndef __smp_mb__after_atomic
+#define __smp_mb__after_atomic() __smp_mb()
+#endif
+
+#ifndef __smp_store_release
+#define __smp_store_release(p, v) \
+do { \
+ compiletime_assert_atomic_type(*p); \
+ __smp_mb(); \
+ WRITE_ONCE(*p, v); \
+} while (0)
+#endif
+
+#ifndef __smp_load_acquire
+#define __smp_load_acquire(p) \
+({ \
+ typeof(*p) ___p1 = READ_ONCE(*p); \
+ compiletime_assert_atomic_type(*p); \
+ __smp_mb(); \
+ ___p1; \
+})
+#endif
+
+#ifdef CONFIG_SMP
+
+#ifndef smp_store_mb
+#define smp_store_mb(var, value) __smp_store_mb(var, value)
+#endif
+
+#ifndef smp_mb__before_atomic
+#define smp_mb__before_atomic() __smp_mb__before_atomic()
+#endif
+
+#ifndef smp_mb__after_atomic
+#define smp_mb__after_atomic() __smp_mb__after_atomic()
+#endif
+
+#ifndef smp_store_release
+#define smp_store_release(p, v) __smp_store_release(p, v)
+#endif
+
+#ifndef smp_load_acquire
+#define smp_load_acquire(p) __smp_load_acquire(p)
+#endif
+
+#else /* !CONFIG_SMP */
+
#ifndef smp_store_mb
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
#endif
#ifndef smp_mb__before_atomic
-#define smp_mb__before_atomic() smp_mb()
+#define smp_mb__before_atomic() barrier()
#endif
#ifndef smp_mb__after_atomic
-#define smp_mb__after_atomic() smp_mb()
+#define smp_mb__after_atomic() barrier()
#endif
+#ifndef smp_store_release
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
- smp_mb(); \
+ barrier(); \
WRITE_ONCE(*p, v); \
} while (0)
+#endif
+#ifndef smp_load_acquire
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
- smp_mb(); \
+ barrier(); \
___p1; \
})
+#endif
+
+#endif
+
+/* Barriers for virtual machine guests when talking to an SMP host */
+#define virt_mb() __smp_mb()
+#define virt_rmb() __smp_rmb()
+#define virt_wmb() __smp_wmb()
+#define virt_read_barrier_depends() __smp_read_barrier_depends()
+#define virt_store_mb(var, value) __smp_store_mb(var, value)
+#define virt_mb__before_atomic() __smp_mb__before_atomic()
+#define virt_mb__after_atomic() __smp_mb__after_atomic()
+#define virt_store_release(p, v) __smp_store_release(p, v)
+#define virt_load_acquire(p) __smp_load_acquire(p)
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_GENERIC_BARRIER_H */
diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h
index 8f4e3193342e..163f77999ea4 100644
--- a/include/asm-generic/div64.h
+++ b/include/asm-generic/div64.h
@@ -4,6 +4,9 @@
* Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
* Based on former asm-ppc/div64.h and asm-m68knommu/div64.h
*
+ * Optimization for constant divisors on 32-bit machines:
+ * Copyright (C) 2006-2015 Nicolas Pitre
+ *
* The semantics of do_div() are:
*
* uint32_t do_div(uint64_t *n, uint32_t base)
@@ -32,7 +35,168 @@
#elif BITS_PER_LONG == 32
+#include <linux/log2.h>
+
+/*
+ * If the divisor happens to be constant, we determine the appropriate
+ * inverse at compile time to turn the division into a few inline
+ * multiplications which ought to be much faster. And yet only if compiling
+ * with a sufficiently recent gcc version to perform proper 64-bit constant
+ * propagation.
+ *
+ * (It is unfortunate that gcc doesn't perform all this internally.)
+ */
+
+#ifndef __div64_const32_is_OK
+#define __div64_const32_is_OK (__GNUC__ >= 4)
+#endif
+
+#define __div64_const32(n, ___b) \
+({ \
+ /* \
+ * Multiplication by reciprocal of b: n / b = n * (p / b) / p \
+ * \
+ * We rely on the fact that most of this code gets optimized \
+ * away at compile time due to constant propagation and only \
+ * a few multiplication instructions should remain. \
+ * Hence this monstrous macro (static inline doesn't always \
+ * do the trick here). \
+ */ \
+ uint64_t ___res, ___x, ___t, ___m, ___n = (n); \
+ uint32_t ___p, ___bias; \
+ \
+ /* determine MSB of b */ \
+ ___p = 1 << ilog2(___b); \
+ \
+ /* compute m = ((p << 64) + b - 1) / b */ \
+ ___m = (~0ULL / ___b) * ___p; \
+ ___m += (((~0ULL % ___b + 1) * ___p) + ___b - 1) / ___b; \
+ \
+ /* one less than the dividend with highest result */ \
+ ___x = ~0ULL / ___b * ___b - 1; \
+ \
+ /* test our ___m with res = m * x / (p << 64) */ \
+ ___res = ((___m & 0xffffffff) * (___x & 0xffffffff)) >> 32; \
+ ___t = ___res += (___m & 0xffffffff) * (___x >> 32); \
+ ___res += (___x & 0xffffffff) * (___m >> 32); \
+ ___t = (___res < ___t) ? (1ULL << 32) : 0; \
+ ___res = (___res >> 32) + ___t; \
+ ___res += (___m >> 32) * (___x >> 32); \
+ ___res /= ___p; \
+ \
+ /* Now sanitize and optimize what we've got. */ \
+ if (~0ULL % (___b / (___b & -___b)) == 0) { \
+ /* special case, can be simplified to ... */ \
+ ___n /= (___b & -___b); \
+ ___m = ~0ULL / (___b / (___b & -___b)); \
+ ___p = 1; \
+ ___bias = 1; \
+ } else if (___res != ___x / ___b) { \
+ /* \
+ * We can't get away without a bias to compensate \
+ * for bit truncation errors. To avoid it we'd need an \
+ * additional bit to represent m which would overflow \
+ * a 64-bit variable. \
+ * \
+ * Instead we do m = p / b and n / b = (n * m + m) / p. \
+ */ \
+ ___bias = 1; \
+ /* Compute m = (p << 64) / b */ \
+ ___m = (~0ULL / ___b) * ___p; \
+ ___m += ((~0ULL % ___b + 1) * ___p) / ___b; \
+ } else { \
+ /* \
+ * Reduce m / p, and try to clear bit 31 of m when \
+ * possible, otherwise that'll need extra overflow \
+ * handling later. \
+ */ \
+ uint32_t ___bits = -(___m & -___m); \
+ ___bits |= ___m >> 32; \
+ ___bits = (~___bits) << 1; \
+ /* \
+ * If ___bits == 0 then setting bit 31 is unavoidable. \
+ * Simply apply the maximum possible reduction in that \
+ * case. Otherwise the MSB of ___bits indicates the \
+ * best reduction we should apply. \
+ */ \
+ if (!___bits) { \
+ ___p /= (___m & -___m); \
+ ___m /= (___m & -___m); \
+ } else { \
+ ___p >>= ilog2(___bits); \
+ ___m >>= ilog2(___bits); \
+ } \
+ /* No bias needed. */ \
+ ___bias = 0; \
+ } \
+ \
+ /* \
+ * Now we have a combination of 2 conditions: \
+ * \
+ * 1) whether or not we need to apply a bias, and \
+ * \
+ * 2) whether or not there might be an overflow in the cross \
+ * product determined by (___m & ((1 << 63) | (1 << 31))). \
+ * \
+ * Select the best way to do (m_bias + m * n) / (1 << 64). \
+ * From now on there will be actual runtime code generated. \
+ */ \
+ ___res = __arch_xprod_64(___m, ___n, ___bias); \
+ \
+ ___res /= ___p; \
+})
+
+#ifndef __arch_xprod_64
+/*
+ * Default C implementation for __arch_xprod_64()
+ *
+ * Prototype: uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias)
+ * Semantic: retval = ((bias ? m : 0) + m * n) >> 64
+ *
+ * The product is a 128-bit value, scaled down to 64 bits.
+ * Assuming constant propagation to optimize away unused conditional code.
+ * Architectures may provide their own optimized assembly implementation.
+ */
+static inline uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias)
+{
+ uint32_t m_lo = m;
+ uint32_t m_hi = m >> 32;
+ uint32_t n_lo = n;
+ uint32_t n_hi = n >> 32;
+ uint64_t res, tmp;
+
+ if (!bias) {
+ res = ((uint64_t)m_lo * n_lo) >> 32;
+ } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
+ /* there can't be any overflow here */
+ res = (m + (uint64_t)m_lo * n_lo) >> 32;
+ } else {
+ res = m + (uint64_t)m_lo * n_lo;
+ tmp = (res < m) ? (1ULL << 32) : 0;
+ res = (res >> 32) + tmp;
+ }
+
+ if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
+ /* there can't be any overflow here */
+ res += (uint64_t)m_lo * n_hi;
+ res += (uint64_t)m_hi * n_lo;
+ res >>= 32;
+ } else {
+ tmp = res += (uint64_t)m_lo * n_hi;
+ res += (uint64_t)m_hi * n_lo;
+ tmp = (res < tmp) ? (1ULL << 32) : 0;
+ res = (res >> 32) + tmp;
+ }
+
+ res += (uint64_t)m_hi * n_hi;
+
+ return res;
+}
+#endif
+
+#ifndef __div64_32
extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
+#endif
/* The unnecessary pointer compare is there
* to check for type safety (n must be 64bit)
@@ -41,7 +205,19 @@ extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
uint32_t __base = (base); \
uint32_t __rem; \
(void)(((typeof((n)) *)0) == ((uint64_t *)0)); \
- if (likely(((n) >> 32) == 0)) { \
+ if (__builtin_constant_p(__base) && \
+ is_power_of_2(__base)) { \
+ __rem = (n) & (__base - 1); \
+ (n) >>= ilog2(__base); \
+ } else if (__div64_const32_is_OK && \
+ __builtin_constant_p(__base) && \
+ __base != 0) { \
+ uint32_t __res_lo, __n_lo = (n); \
+ (n) = __div64_const32(n, __base); \
+ /* the remainder can be computed with 32-bit regs */ \
+ __res_lo = (n); \
+ __rem = __n_lo - __res_lo * __base; \
+ } else if (likely(((n) >> 32) == 0)) { \
__rem = (uint32_t)(n) % __base; \
(n) = (uint32_t)(n) / __base; \
} else \
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index 4b4b056a6eb0..5148150cc80b 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -1,6 +1,8 @@
#ifndef __ASM_MEMORY_MODEL_H
#define __ASM_MEMORY_MODEL_H
+#include <linux/pfn.h>
+
#ifndef __ASSEMBLY__
#if defined(CONFIG_FLATMEM)
@@ -72,7 +74,7 @@
/*
* Convert a physical address to a Page Frame Number and back
*/
-#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT))
+#define __phys_to_pfn(paddr) PHYS_PFN(paddr)
#define __pfn_to_phys(pfn) PFN_PHYS(pfn)
#define page_to_pfn __page_to_pfn
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 3a6803cb0ec9..0b3c0d39ef75 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -1,6 +1,8 @@
#ifndef _ASM_GENERIC_PGTABLE_H
#define _ASM_GENERIC_PGTABLE_H
+#include <linux/pfn.h>
+
#ifndef __ASSEMBLY__
#ifdef CONFIG_MMU
@@ -207,11 +209,6 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif
-#ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-extern void pmdp_splitting_flush(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp);
-#endif
-
#ifndef pmdp_collapse_flush
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
@@ -554,7 +551,7 @@ static inline int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
* by vm_insert_pfn().
*/
static inline int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
- unsigned long pfn)
+ pfn_t pfn)
{
return 0;
}
@@ -589,7 +586,7 @@ extern int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
unsigned long pfn, unsigned long addr,
unsigned long size);
extern int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
- unsigned long pfn);
+ pfn_t pfn);
extern int track_pfn_copy(struct vm_area_struct *vma);
extern void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
unsigned long size);
@@ -627,10 +624,6 @@ static inline int pmd_trans_huge(pmd_t pmd)
{
return 0;
}
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- return 0;
-}
#ifndef __HAVE_ARCH_PMD_WRITE
static inline int pmd_write(pmd_t pmd)
{
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index b58fd667f87b..af0254c09424 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -4,6 +4,7 @@
/* References to section boundaries */
#include <linux/compiler.h>
+#include <linux/types.h>
/*
* Usage guidelines:
@@ -63,4 +64,68 @@ static inline int arch_is_kernel_data(unsigned long addr)
}
#endif
+/**
+ * memory_contains - checks if an object is contained within a memory region
+ * @begin: virtual address of the beginning of the memory region
+ * @end: virtual address of the end of the memory region
+ * @virt: virtual address of the memory object
+ * @size: size of the memory object
+ *
+ * Returns: true if the object specified by @virt and @size is entirely
+ * contained within the memory region defined by @begin and @end, false
+ * otherwise.
+ */
+static inline bool memory_contains(void *begin, void *end, void *virt,
+ size_t size)
+{
+ return virt >= begin && virt + size <= end;
+}
+
+/**
+ * memory_intersects - checks if the region occupied by an object intersects
+ * with another memory region
+ * @begin: virtual address of the beginning of the memory regien
+ * @end: virtual address of the end of the memory region
+ * @virt: virtual address of the memory object
+ * @size: size of the memory object
+ *
+ * Returns: true if an object's memory region, specified by @virt and @size,
+ * intersects with the region specified by @begin and @end, false otherwise.
+ */
+static inline bool memory_intersects(void *begin, void *end, void *virt,
+ size_t size)
+{
+ void *vend = virt + size;
+
+ return (virt >= begin && virt < end) || (vend >= begin && vend < end);
+}
+
+/**
+ * init_section_contains - checks if an object is contained within the init
+ * section
+ * @virt: virtual address of the memory object
+ * @size: size of the memory object
+ *
+ * Returns: true if the object specified by @virt and @size is entirely
+ * contained within the init section, false otherwise.
+ */
+static inline bool init_section_contains(void *virt, size_t size)
+{
+ return memory_contains(__init_begin, __init_end, virt, size);
+}
+
+/**
+ * init_section_intersects - checks if the region occupied by an object
+ * intersects with the init section
+ * @virt: virtual address of the memory object
+ * @size: size of the memory object
+ *
+ * Returns: true if an object's memory region, specified by @virt and @size,
+ * intersects with the init section, false otherwise.
+ */
+static inline bool init_section_intersects(void *virt, size_t size)
+{
+ return memory_intersects(__init_begin, __init_end, virt, size);
+}
+
#endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/crypto/hash_info.h b/include/crypto/hash_info.h
index e1e5a3e5dd1b..56f217d41f12 100644
--- a/include/crypto/hash_info.h
+++ b/include/crypto/hash_info.h
@@ -34,6 +34,9 @@
#define TGR160_DIGEST_SIZE 20
#define TGR192_DIGEST_SIZE 24
+/* not defined in include/crypto/ */
+#define SM3256_DIGEST_SIZE 32
+
extern const char *const hash_algo_name[HASH_ALGO__LAST];
extern const int hash_digest_size[HASH_ALGO__LAST];
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 0a271ca1f7c7..d7162cf1c3e1 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -349,6 +349,8 @@ struct drm_file {
struct list_head event_list;
int event_space;
+ struct mutex event_read_lock;
+
struct drm_prime_file_private prime;
};
@@ -585,6 +587,13 @@ struct drm_driver {
int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
+ /**
+ * Hook for allocating the GEM object struct, for use by core
+ * helpers.
+ */
+ struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
+ size_t size);
+
/* prime: */
/* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
@@ -1059,7 +1068,7 @@ void drm_dev_ref(struct drm_device *dev);
void drm_dev_unref(struct drm_device *dev);
int drm_dev_register(struct drm_device *dev, unsigned long flags);
void drm_dev_unregister(struct drm_device *dev);
-int drm_dev_set_unique(struct drm_device *dev, const char *fmt, ...);
+int drm_dev_set_unique(struct drm_device *dev, const char *name);
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
@@ -1108,6 +1117,7 @@ static inline int drm_pci_set_busid(struct drm_device *dev,
#define DRM_PCIE_SPEED_80 4
extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask);
+extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw);
/* platform section */
extern int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device);
@@ -1121,4 +1131,7 @@ static __inline__ bool drm_can_sleep(void)
return true;
}
+/* helper for handling conditionals in various for_each macros */
+#define for_each_if(condition) if (!(condition)) {} else
+
#endif
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 4b74c97d297a..d3eaa5df187a 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -130,10 +130,6 @@ int __must_check
drm_atomic_add_affected_planes(struct drm_atomic_state *state,
struct drm_crtc *crtc);
-int
-drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
- struct drm_crtc *crtc);
-
void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
void
@@ -149,7 +145,7 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
((connector) = (state)->connectors[__i], \
(connector_state) = (state)->connector_states[__i], 1); \
(__i)++) \
- if (connector)
+ for_each_if (connector)
#define for_each_crtc_in_state(state, crtc, crtc_state, __i) \
for ((__i) = 0; \
@@ -157,7 +153,7 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
((crtc) = (state)->crtcs[__i], \
(crtc_state) = (state)->crtc_states[__i], 1); \
(__i)++) \
- if (crtc_state)
+ for_each_if (crtc_state)
#define for_each_plane_in_state(state, plane, plane_state, __i) \
for ((__i) = 0; \
@@ -165,7 +161,7 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
((plane) = (state)->planes[__i], \
(plane_state) = (state)->plane_states[__i], 1); \
(__i)++) \
- if (plane_state)
+ for_each_if (plane_state)
static inline bool
drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state)
{
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 8cba54a2a0a0..89d008dc08e2 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -62,6 +62,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
struct drm_atomic_state *old_state);
void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state);
+void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
+ bool atomic);
void drm_atomic_helper_swap_state(struct drm_device *dev,
struct drm_atomic_state *state);
@@ -81,6 +83,12 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set);
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
struct drm_atomic_state *state);
+int drm_atomic_helper_disable_all(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_resume(struct drm_device *dev,
+ struct drm_atomic_state *state);
+
int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
struct drm_property *property,
uint64_t val);
@@ -118,6 +126,8 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
+void __drm_atomic_helper_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,
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3f0c6909dda1..c65a212db77e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -85,7 +85,11 @@ static inline uint64_t I642U64(int64_t val)
return (uint64_t)*((uint64_t *)&val);
}
-/* rotation property bits */
+/*
+ * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the
+ * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and
+ * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation
+ */
#define DRM_ROTATE_MASK 0x0f
#define DRM_ROTATE_0 0
#define DRM_ROTATE_90 1
@@ -158,23 +162,60 @@ struct drm_tile_group {
u8 group_data[8];
};
+/**
+ * struct drm_framebuffer_funcs - framebuffer hooks
+ */
struct drm_framebuffer_funcs {
- /* note: use drm_framebuffer_remove() */
+ /**
+ * @destroy:
+ *
+ * Clean up framebuffer resources, specifically also unreference the
+ * backing storage. The core guarantees to call this function for every
+ * framebuffer successfully created by ->fb_create() in
+ * &drm_mode_config_funcs. Drivers must also call
+ * drm_framebuffer_cleanup() to release DRM core resources for this
+ * framebuffer.
+ */
void (*destroy)(struct drm_framebuffer *framebuffer);
+
+ /**
+ * @create_handle:
+ *
+ * Create a buffer handle in the driver-specific buffer manager (either
+ * GEM or TTM) valid for the passed-in struct &drm_file. This is used by
+ * the core to implement the GETFB IOCTL, which returns (for
+ * sufficiently priviledged user) also a native buffer handle. This can
+ * be used for seamless transitions between modesetting clients by
+ * copying the current screen contents to a private buffer and blending
+ * between that and the new contents.
+ *
+ * GEM based drivers should call drm_gem_handle_create() to create the
+ * handle.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*create_handle)(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned int *handle);
- /*
- * Optional callback for the dirty fb ioctl.
+ /**
+ * @dirty:
+ *
+ * Optional callback for the dirty fb IOCTL.
+ *
+ * Userspace can notify the driver via this callback that an area of the
+ * framebuffer has changed and should be flushed to the display
+ * hardware. This can also be used internally, e.g. by the fbdev
+ * emulation, though that's not the case currently.
+ *
+ * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd
+ * for more information as all the semantics and arguments have a one to
+ * one mapping on this function.
*
- * Userspace can notify the driver via this callback
- * that a area of the framebuffer has changed and should
- * be flushed to the display hardware.
+ * RETURNS:
*
- * See documentation in drm_mode.h for the struct
- * drm_mode_fb_dirty_cmd for more information as all
- * the semantics and arguments have a one to one mapping
- * on this function.
+ * 0 on success or a negative error code on failure.
*/
int (*dirty)(struct drm_framebuffer *framebuffer,
struct drm_file *file_priv, unsigned flags,
@@ -250,6 +291,11 @@ struct drm_plane;
struct drm_bridge;
struct drm_atomic_state;
+struct drm_crtc_helper_funcs;
+struct drm_encoder_helper_funcs;
+struct drm_connector_helper_funcs;
+struct drm_plane_helper_funcs;
+
/**
* struct drm_crtc_state - mutable CRTC state
* @crtc: backpointer to the CRTC
@@ -260,6 +306,7 @@ struct drm_atomic_state;
* @active_changed: crtc_state->active has been toggled.
* @connectors_changed: connectors to this crtc have been updated
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
+ * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors
* @last_vblank_count: for helpers and drivers to capture the vblank of the
* update to ensure framebuffer cleanup isn't done too early
* @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
@@ -293,6 +340,8 @@ struct drm_crtc_state {
*/
u32 plane_mask;
+ u32 connector_mask;
+
/* last_vblank_count: for vblank waits before cleanup */
u32 last_vblank_count;
@@ -311,23 +360,6 @@ struct drm_crtc_state {
/**
* struct drm_crtc_funcs - control CRTCs for a given device
- * @save: save CRTC state
- * @restore: restore CRTC state
- * @reset: reset CRTC after state has been invalidated (e.g. resume)
- * @cursor_set: setup the cursor
- * @cursor_set2: setup the cursor with hotspot, superseeds @cursor_set if set
- * @cursor_move: move the cursor
- * @gamma_set: specify color ramp for CRTC
- * @destroy: deinit and free object
- * @set_property: called when a property is changed
- * @set_config: apply a new CRTC configuration
- * @page_flip: initiate a page flip
- * @atomic_duplicate_state: duplicate the atomic state for this CRTC
- * @atomic_destroy_state: destroy an atomic state for this CRTC
- * @atomic_set_property: set a property on an atomic state for this CRTC
- * (do not call directly, use drm_atomic_crtc_set_property())
- * @atomic_get_property: get a property on an atomic state for this CRTC
- * (do not call directly, use drm_atomic_crtc_get_property())
*
* The drm_crtc_funcs structure is the central CRTC management structure
* in the DRM. Each CRTC controls one or more connectors (note that the name
@@ -339,54 +371,317 @@ struct drm_crtc_state {
* bus accessors.
*/
struct drm_crtc_funcs {
- /* Save CRTC state */
- void (*save)(struct drm_crtc *crtc); /* suspend? */
- /* Restore CRTC state */
- void (*restore)(struct drm_crtc *crtc); /* resume? */
- /* Reset CRTC state */
+ /**
+ * @reset:
+ *
+ * Reset CRTC hardware and software state to off. This function isn't
+ * called by the core directly, only through drm_mode_config_reset().
+ * It's not a helper hook only for historical reasons.
+ *
+ * Atomic drivers can use drm_atomic_helper_crtc_reset() to reset
+ * atomic state using this hook.
+ */
void (*reset)(struct drm_crtc *crtc);
- /* cursor controls */
+ /**
+ * @cursor_set:
+ *
+ * Update the cursor image. The cursor position is relative to the CRTC
+ * and can be partially or fully outside of the visible area.
+ *
+ * Note that contrary to all other KMS functions the legacy cursor entry
+ * points don't take a framebuffer object, but instead take directly a
+ * raw buffer object id from the driver's buffer manager (which is
+ * either GEM or TTM for current drivers).
+ *
+ * This entry point is deprecated, drivers should instead implement
+ * universal plane support and register a proper cursor plane using
+ * drm_crtc_init_with_planes().
+ *
+ * This callback is optional
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height);
+
+ /**
+ * @cursor_set2:
+ *
+ * Update the cursor image, including hotspot information. The hotspot
+ * must not affect the cursor position in CRTC coordinates, but is only
+ * meant as a hint for virtualized display hardware to coordinate the
+ * guests and hosts cursor position. The cursor hotspot is relative to
+ * the cursor image. Otherwise this works exactly like @cursor_set.
+ *
+ * This entry point is deprecated, drivers should instead implement
+ * universal plane support and register a proper cursor plane using
+ * drm_crtc_init_with_planes().
+ *
+ * This callback is optional.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height,
int32_t hot_x, int32_t hot_y);
+
+ /**
+ * @cursor_move:
+ *
+ * Update the cursor position. The cursor does not need to be visible
+ * when this hook is called.
+ *
+ * This entry point is deprecated, drivers should instead implement
+ * universal plane support and register a proper cursor plane using
+ * drm_crtc_init_with_planes().
+ *
+ * This callback is optional.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
- /* Set gamma on the CRTC */
+ /**
+ * @gamma_set:
+ *
+ * Set gamma on the CRTC.
+ *
+ * This callback is optional.
+ *
+ * NOTE:
+ *
+ * Drivers that support gamma tables and also fbdev emulation through
+ * the provided helper library need to take care to fill out the gamma
+ * hooks for both. Currently there's a bit an unfortunate duplication
+ * going on, which should eventually be unified to just one set of
+ * hooks.
+ */
void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
uint32_t start, uint32_t size);
- /* Object destroy routine */
+
+ /**
+ * @destroy:
+ *
+ * Clean up plane resources. This is only called at driver unload time
+ * through drm_mode_config_cleanup() since a CRTC cannot be hotplugged
+ * in DRM.
+ */
void (*destroy)(struct drm_crtc *crtc);
+ /**
+ * @set_config:
+ *
+ * This is the main legacy entry point to change the modeset state on a
+ * CRTC. All the details of the desired configuration are passed in a
+ * struct &drm_mode_set - see there for details.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_set_config() to implement this hook.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*set_config)(struct drm_mode_set *set);
- /*
- * Flip to the given framebuffer. This implements the page
- * flip ioctl described in drm_mode.h, specifically, the
- * implementation must return immediately and block all
- * rendering to the current fb until the flip has completed.
- * If userspace set the event flag in the ioctl, the event
- * argument will point to an event to send back when the flip
- * completes, otherwise it will be NULL.
+ /**
+ * @page_flip:
+ *
+ * Legacy entry point to schedule a flip to the given framebuffer.
+ *
+ * Page flipping is a synchronization mechanism that replaces the frame
+ * buffer being scanned out by the CRTC with a new frame buffer during
+ * vertical blanking, avoiding tearing (except when requested otherwise
+ * through the DRM_MODE_PAGE_FLIP_ASYNC flag). When an application
+ * requests a page flip the DRM core verifies that the new frame buffer
+ * is large enough to be scanned out by the CRTC in the currently
+ * configured mode and then calls the CRTC ->page_flip() operation with a
+ * pointer to the new frame buffer.
+ *
+ * The driver must wait for any pending rendering to the new framebuffer
+ * to complete before executing the flip. It should also wait for any
+ * pending rendering from other drivers if the underlying buffer is a
+ * shared dma-buf.
+ *
+ * An application can request to be notified when the page flip has
+ * completed. The drm core will supply a struct &drm_event in the event
+ * parameter in this case. This can be handled by the
+ * drm_crtc_send_vblank_event() function, which the driver should call on
+ * the provided event upon completion of the flip. Note that if
+ * the driver supports vblank signalling and timestamping the vblank
+ * counters and timestamps must agree with the ones returned from page
+ * flip events. With the current vblank helper infrastructure this can
+ * be achieved by holding a vblank reference while the page flip is
+ * pending, acquired through drm_crtc_vblank_get() and released with
+ * drm_crtc_vblank_put(). Drivers are free to implement their own vblank
+ * counter and timestamp tracking though, e.g. if they have accurate
+ * timestamp registers in hardware.
+ *
+ * FIXME:
+ *
+ * Up to that point drivers need to manage events themselves and can use
+ * even->base.list freely for that. Specifically they need to ensure
+ * that they don't send out page flip (or vblank) events for which the
+ * corresponding drm file has been closed already. The drm core
+ * unfortunately does not (yet) take care of that. Therefore drivers
+ * currently must clean up and release pending events in their
+ * ->preclose driver function.
+ *
+ * This callback is optional.
+ *
+ * NOTE:
+ *
+ * Very early versions of the KMS ABI mandated that the driver must
+ * block (but not reject) any rendering to the old framebuffer until the
+ * flip operation has completed and the old framebuffer is no longer
+ * visible. This requirement has been lifted, and userspace is instead
+ * expected to request delivery of an event and wait with recycling old
+ * buffers until such has been received.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure. Note that if a
+ * ->page_flip() operation is already pending the callback should return
+ * -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode
+ * or just runtime disabled through DPMS respectively the new atomic
+ * "ACTIVE" state) should result in an -EINVAL error code. Note that
+ * drm_atomic_helper_page_flip() checks this already for atomic drivers.
*/
int (*page_flip)(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t flags);
+ /**
+ * @set_property:
+ *
+ * This is the legacy entry point to update a property attached to the
+ * CRTC.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_crtc_set_property() to implement this hook.
+ *
+ * This callback is optional if the driver does not support any legacy
+ * driver-private properties.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*set_property)(struct drm_crtc *crtc,
struct drm_property *property, uint64_t val);
- /* atomic update handling */
+ /**
+ * @atomic_duplicate_state:
+ *
+ * Duplicate the current atomic state for this CRTC and return it.
+ * The core and helpers gurantee that any atomic state duplicated with
+ * this hook and still owned by the caller (i.e. not transferred to the
+ * driver by calling ->atomic_commit() from struct
+ * &drm_mode_config_funcs) will be cleaned up by calling the
+ * @atomic_destroy_state hook in this structure.
+ *
+ * Atomic drivers which don't subclass struct &drm_crtc should use
+ * drm_atomic_helper_crtc_duplicate_state(). Drivers that subclass the
+ * state structure to extend it with driver-private state should use
+ * __drm_atomic_helper_crtc_duplicate_state() to make sure shared state is
+ * duplicated in a consistent fashion across drivers.
+ *
+ * It is an error to call this hook before crtc->state has been
+ * initialized correctly.
+ *
+ * NOTE:
+ *
+ * If the duplicate state references refcounted resources this hook must
+ * acquire a reference for each of them. The driver must release these
+ * references again in @atomic_destroy_state.
+ *
+ * RETURNS:
+ *
+ * Duplicated atomic state or NULL when the allocation failed.
+ */
struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
+
+ /**
+ * @atomic_destroy_state:
+ *
+ * Destroy a state duplicated with @atomic_duplicate_state and release
+ * or unreference all resources it references
+ */
void (*atomic_destroy_state)(struct drm_crtc *crtc,
struct drm_crtc_state *state);
+
+ /**
+ * @atomic_set_property:
+ *
+ * Decode a driver-private property value and store the decoded value
+ * into the passed-in state structure. Since the atomic core decodes all
+ * standardized properties (even for extensions beyond the core set of
+ * properties which might not be implemented by all drivers) this
+ * requires drivers to subclass the state structure.
+ *
+ * Such driver-private properties should really only be implemented for
+ * truly hardware/vendor specific state. Instead it is preferred to
+ * standardize atomic extension and decode the properties used to expose
+ * such an extension in the core.
+ *
+ * Do not call this function directly, use
+ * drm_atomic_crtc_set_property() instead.
+ *
+ * This callback is optional if the driver does not support any
+ * driver-private atomic properties.
+ *
+ * NOTE:
+ *
+ * This function is called in the state assembly phase of atomic
+ * modesets, which can be aborted for any reason (including on
+ * userspace's request to just check whether a configuration would be
+ * possible). Drivers MUST NOT touch any persistent state (hardware or
+ * software) or data structures except the passed in @state parameter.
+ *
+ * Also since userspace controls in which order properties are set this
+ * function must not do any input validation (since the state update is
+ * incomplete and hence likely inconsistent). Instead any such input
+ * validation must be done in the various atomic_check callbacks.
+ *
+ * RETURNS:
+ *
+ * 0 if the property has been found, -EINVAL if the property isn't
+ * implemented by the driver (which should never happen, the core only
+ * asks for properties attached to this CRTC). No other validation is
+ * allowed by the driver. The core already checks that the property
+ * value is within the range (integer, valid enum value, ...) the driver
+ * set when registering the property.
+ */
int (*atomic_set_property)(struct drm_crtc *crtc,
struct drm_crtc_state *state,
struct drm_property *property,
uint64_t val);
+ /**
+ * @atomic_get_property:
+ *
+ * Reads out the decoded driver-private property. This is used to
+ * implement the GETCRTC IOCTL.
+ *
+ * Do not call this function directly, use
+ * drm_atomic_crtc_get_property() instead.
+ *
+ * This callback is optional if the driver does not support any
+ * driver-private atomic properties.
+ *
+ * RETURNS:
+ *
+ * 0 on success, -EINVAL if the property isn't implemented by the
+ * driver (which should never happen, the core only asks for
+ * properties attached to this CRTC).
+ */
int (*atomic_get_property)(struct drm_crtc *crtc,
const struct drm_crtc_state *state,
struct drm_property *property,
@@ -416,7 +711,7 @@ struct drm_crtc_funcs {
* @properties: property tracking for this CRTC
* @state: current atomic state for this CRTC
* @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for
- * legacy ioctls
+ * legacy IOCTLs
*
* Each CRTC may have one or more connectors associated with it. This structure
* allows the CRTC to be controlled.
@@ -426,6 +721,8 @@ struct drm_crtc {
struct device_node *port;
struct list_head head;
+ char *name;
+
/*
* crtc mutex
*
@@ -463,14 +760,14 @@ struct drm_crtc {
uint16_t *gamma_store;
/* if you are using the helper */
- const void *helper_private;
+ const struct drm_crtc_helper_funcs *helper_private;
struct drm_object_properties properties;
struct drm_crtc_state *state;
/*
- * For legacy crtc ioctls so that atomic drivers can get at the locking
+ * For legacy crtc IOCTLs so that atomic drivers can get at the locking
* acquire context.
*/
struct drm_modeset_acquire_ctx *acquire_ctx;
@@ -495,54 +792,239 @@ struct drm_connector_state {
/**
* struct drm_connector_funcs - control connectors on a given device
- * @dpms: set power state
- * @save: save connector state
- * @restore: restore connector state
- * @reset: reset connector after state has been invalidated (e.g. resume)
- * @detect: is this connector active?
- * @fill_modes: fill mode list for this connector
- * @set_property: property for this connector may need an update
- * @destroy: make object go away
- * @force: notify the driver that the connector is forced on
- * @atomic_duplicate_state: duplicate the atomic state for this connector
- * @atomic_destroy_state: destroy an atomic state for this connector
- * @atomic_set_property: set a property on an atomic state for this connector
- * (do not call directly, use drm_atomic_connector_set_property())
- * @atomic_get_property: get a property on an atomic state for this connector
- * (do not call directly, use drm_atomic_connector_get_property())
*
* Each CRTC may have one or more connectors attached to it. The functions
* below allow the core DRM code to control connectors, enumerate available modes,
* etc.
*/
struct drm_connector_funcs {
+ /**
+ * @dpms:
+ *
+ * Legacy entry point to set the per-connector DPMS state. Legacy DPMS
+ * is exposed as a standard property on the connector, but diverted to
+ * this callback in the drm core. Note that atomic drivers don't
+ * implement the 4 level DPMS support on the connector any more, but
+ * instead only have an on/off "ACTIVE" property on the CRTC object.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_connector_dpms() to implement this hook.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*dpms)(struct drm_connector *connector, int mode);
- void (*save)(struct drm_connector *connector);
- void (*restore)(struct drm_connector *connector);
+
+ /**
+ * @reset:
+ *
+ * Reset connector hardware and software state to off. This function isn't
+ * called by the core directly, only through drm_mode_config_reset().
+ * It's not a helper hook only for historical reasons.
+ *
+ * Atomic drivers can use drm_atomic_helper_connector_reset() to reset
+ * atomic state using this hook.
+ */
void (*reset)(struct drm_connector *connector);
- /* Check to see if anything is attached to the connector.
- * @force is set to false whilst polling, true when checking the
- * connector due to user request. @force can be used by the driver
- * to avoid expensive, destructive operations during automated
- * probing.
+ /**
+ * @detect:
+ *
+ * Check to see if anything is attached to the connector. The parameter
+ * force is set to false whilst polling, true when checking the
+ * connector due to a user request. force can be used by the driver to
+ * avoid expensive, destructive operations during automated probing.
+ *
+ * FIXME:
+ *
+ * Note that this hook is only called by the probe helper. It's not in
+ * the helper library vtable purely for historical reasons. The only DRM
+ * core entry point to probe connector state is @fill_modes.
+ *
+ * RETURNS:
+ *
+ * drm_connector_status indicating the connector's status.
*/
enum drm_connector_status (*detect)(struct drm_connector *connector,
bool force);
+
+ /**
+ * @force:
+ *
+ * This function is called to update internal encoder state when the
+ * connector is forced to a certain state by userspace, either through
+ * the sysfs interfaces or on the kernel cmdline. In that case the
+ * @detect callback isn't called.
+ *
+ * FIXME:
+ *
+ * Note that this hook is only called by the probe helper. It's not in
+ * the helper library vtable purely for historical reasons. The only DRM
+ * core entry point to probe connector state is @fill_modes.
+ */
+ void (*force)(struct drm_connector *connector);
+
+ /**
+ * @fill_modes:
+ *
+ * Entry point for output detection and basic mode validation. The
+ * driver should reprobe the output if needed (e.g. when hotplug
+ * handling is unreliable), add all detected modes to connector->modes
+ * and filter out any the device can't support in any configuration. It
+ * also needs to filter out any modes wider or higher than the
+ * parameters max_width and max_height indicate.
+ *
+ * The drivers must also prune any modes no longer valid from
+ * connector->modes. Furthermore it must update connector->status and
+ * connector->edid. If no EDID has been received for this output
+ * connector->edid must be NULL.
+ *
+ * Drivers using the probe helpers should use
+ * drm_helper_probe_single_connector_modes() or
+ * drm_helper_probe_single_connector_modes_nomerge() to implement this
+ * function.
+ *
+ * RETURNS:
+ *
+ * The number of modes detected and filled into connector->modes.
+ */
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
+
+ /**
+ * @set_property:
+ *
+ * This is the legacy entry point to update a property attached to the
+ * connector.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_connector_set_property() to implement this hook.
+ *
+ * This callback is optional if the driver does not support any legacy
+ * driver-private properties.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
uint64_t val);
+
+ /**
+ * @destroy:
+ *
+ * Clean up connector resources. This is called at driver unload time
+ * through drm_mode_config_cleanup(). It can also be called at runtime
+ * when a connector is being hot-unplugged for drivers that support
+ * connector hotplugging (e.g. DisplayPort MST).
+ */
void (*destroy)(struct drm_connector *connector);
- void (*force)(struct drm_connector *connector);
- /* atomic update handling */
+ /**
+ * @atomic_duplicate_state:
+ *
+ * Duplicate the current atomic state for this connector and return it.
+ * The core and helpers gurantee that any atomic state duplicated with
+ * this hook and still owned by the caller (i.e. not transferred to the
+ * driver by calling ->atomic_commit() from struct
+ * &drm_mode_config_funcs) will be cleaned up by calling the
+ * @atomic_destroy_state hook in this structure.
+ *
+ * Atomic drivers which don't subclass struct &drm_connector_state should use
+ * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the
+ * state structure to extend it with driver-private state should use
+ * __drm_atomic_helper_connector_duplicate_state() to make sure shared state is
+ * duplicated in a consistent fashion across drivers.
+ *
+ * It is an error to call this hook before connector->state has been
+ * initialized correctly.
+ *
+ * NOTE:
+ *
+ * If the duplicate state references refcounted resources this hook must
+ * acquire a reference for each of them. The driver must release these
+ * references again in @atomic_destroy_state.
+ *
+ * RETURNS:
+ *
+ * Duplicated atomic state or NULL when the allocation failed.
+ */
struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
+
+ /**
+ * @atomic_destroy_state:
+ *
+ * Destroy a state duplicated with @atomic_duplicate_state and release
+ * or unreference all resources it references
+ */
void (*atomic_destroy_state)(struct drm_connector *connector,
struct drm_connector_state *state);
+
+ /**
+ * @atomic_set_property:
+ *
+ * Decode a driver-private property value and store the decoded value
+ * into the passed-in state structure. Since the atomic core decodes all
+ * standardized properties (even for extensions beyond the core set of
+ * properties which might not be implemented by all drivers) this
+ * requires drivers to subclass the state structure.
+ *
+ * Such driver-private properties should really only be implemented for
+ * truly hardware/vendor specific state. Instead it is preferred to
+ * standardize atomic extension and decode the properties used to expose
+ * such an extension in the core.
+ *
+ * Do not call this function directly, use
+ * drm_atomic_connector_set_property() instead.
+ *
+ * This callback is optional if the driver does not support any
+ * driver-private atomic properties.
+ *
+ * NOTE:
+ *
+ * This function is called in the state assembly phase of atomic
+ * modesets, which can be aborted for any reason (including on
+ * userspace's request to just check whether a configuration would be
+ * possible). Drivers MUST NOT touch any persistent state (hardware or
+ * software) or data structures except the passed in @state parameter.
+ *
+ * Also since userspace controls in which order properties are set this
+ * function must not do any input validation (since the state update is
+ * incomplete and hence likely inconsistent). Instead any such input
+ * validation must be done in the various atomic_check callbacks.
+ *
+ * RETURNS:
+ *
+ * 0 if the property has been found, -EINVAL if the property isn't
+ * implemented by the driver (which shouldn't ever happen, the core only
+ * asks for properties attached to this connector). No other validation
+ * is allowed by the driver. The core already checks that the property
+ * value is within the range (integer, valid enum value, ...) the driver
+ * set when registering the property.
+ */
int (*atomic_set_property)(struct drm_connector *connector,
struct drm_connector_state *state,
struct drm_property *property,
uint64_t val);
+
+ /**
+ * @atomic_get_property:
+ *
+ * Reads out the decoded driver-private property. This is used to
+ * implement the GETCONNECTOR IOCTL.
+ *
+ * Do not call this function directly, use
+ * drm_atomic_connector_get_property() instead.
+ *
+ * This callback is optional if the driver does not support any
+ * driver-private atomic properties.
+ *
+ * RETURNS:
+ *
+ * 0 on success, -EINVAL if the property isn't implemented by the
+ * driver (which shouldn't ever happen, the core only asks for
+ * properties attached to this connector).
+ */
int (*atomic_get_property)(struct drm_connector *connector,
const struct drm_connector_state *state,
struct drm_property *property,
@@ -551,13 +1033,26 @@ struct drm_connector_funcs {
/**
* struct drm_encoder_funcs - encoder controls
- * @reset: reset state (e.g. at init or resume time)
- * @destroy: cleanup and free associated data
*
* Encoders sit between CRTCs and connectors.
*/
struct drm_encoder_funcs {
+ /**
+ * @reset:
+ *
+ * Reset encoder hardware and software state to off. This function isn't
+ * called by the core directly, only through drm_mode_config_reset().
+ * It's not a helper hook only for historical reasons.
+ */
void (*reset)(struct drm_encoder *encoder);
+
+ /**
+ * @destroy:
+ *
+ * Clean up encoder resources. This is only called at driver unload time
+ * through drm_mode_config_cleanup() since an encoder cannot be
+ * hotplugged in DRM.
+ */
void (*destroy)(struct drm_encoder *encoder);
};
@@ -593,7 +1088,7 @@ struct drm_encoder {
struct drm_crtc *crtc;
struct drm_bridge *bridge;
const struct drm_encoder_funcs *funcs;
- const void *helper_private;
+ const struct drm_encoder_helper_funcs *helper_private;
};
/* should we poll this connector for connects and disconnects */
@@ -698,7 +1193,7 @@ struct drm_connector {
/* requested DPMS state */
int dpms;
- const void *helper_private;
+ const struct drm_connector_helper_funcs *helper_private;
/* forced on connector */
struct drm_cmdline_mode cmdline_mode;
@@ -778,40 +1273,203 @@ struct drm_plane_state {
/**
* struct drm_plane_funcs - driver plane control functions
- * @update_plane: update the plane configuration
- * @disable_plane: shut down the plane
- * @destroy: clean up plane resources
- * @reset: reset plane after state has been invalidated (e.g. resume)
- * @set_property: called when a property is changed
- * @atomic_duplicate_state: duplicate the atomic state for this plane
- * @atomic_destroy_state: destroy an atomic state for this plane
- * @atomic_set_property: set a property on an atomic state for this plane
- * (do not call directly, use drm_atomic_plane_set_property())
- * @atomic_get_property: get a property on an atomic state for this plane
- * (do not call directly, use drm_atomic_plane_get_property())
*/
struct drm_plane_funcs {
+ /**
+ * @update_plane:
+ *
+ * This is the legacy entry point to enable and configure the plane for
+ * the given CRTC and framebuffer. It is never called to disable the
+ * plane, i.e. the passed-in crtc and fb paramters are never NULL.
+ *
+ * The source rectangle in frame buffer memory coordinates is given by
+ * the src_x, src_y, src_w and src_h parameters (as 16.16 fixed point
+ * values). Devices that don't support subpixel plane coordinates can
+ * ignore the fractional part.
+ *
+ * The destination rectangle in CRTC coordinates is given by the
+ * crtc_x, crtc_y, crtc_w and crtc_h parameters (as integer values).
+ * Devices scale the source rectangle to the destination rectangle. If
+ * scaling is not supported, and the source rectangle size doesn't match
+ * the destination rectangle size, the driver must return a
+ * -<errorname>EINVAL</errorname> error.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_update_plane() to implement this hook.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*update_plane)(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
+
+ /**
+ * @disable_plane:
+ *
+ * This is the legacy entry point to disable the plane. The DRM core
+ * calls this method in response to a DRM_IOCTL_MODE_SETPLANE IOCTL call
+ * with the frame buffer ID set to 0. Disabled planes must not be
+ * processed by the CRTC.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_disable_plane() to implement this hook.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*disable_plane)(struct drm_plane *plane);
+
+ /**
+ * @destroy:
+ *
+ * Clean up plane resources. This is only called at driver unload time
+ * through drm_mode_config_cleanup() since a plane cannot be hotplugged
+ * in DRM.
+ */
void (*destroy)(struct drm_plane *plane);
+
+ /**
+ * @reset:
+ *
+ * Reset plane hardware and software state to off. This function isn't
+ * called by the core directly, only through drm_mode_config_reset().
+ * It's not a helper hook only for historical reasons.
+ *
+ * Atomic drivers can use drm_atomic_helper_plane_reset() to reset
+ * atomic state using this hook.
+ */
void (*reset)(struct drm_plane *plane);
+ /**
+ * @set_property:
+ *
+ * This is the legacy entry point to update a property attached to the
+ * plane.
+ *
+ * Drivers implementing atomic modeset should use
+ * drm_atomic_helper_plane_set_property() to implement this hook.
+ *
+ * This callback is optional if the driver does not support any legacy
+ * driver-private properties.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
int (*set_property)(struct drm_plane *plane,
struct drm_property *property, uint64_t val);
- /* atomic update handling */
+ /**
+ * @atomic_duplicate_state:
+ *
+ * Duplicate the current atomic state for this plane and return it.
+ * The core and helpers gurantee that any atomic state duplicated with
+ * this hook and still owned by the caller (i.e. not transferred to the
+ * driver by calling ->atomic_commit() from struct
+ * &drm_mode_config_funcs) will be cleaned up by calling the
+ * @atomic_destroy_state hook in this structure.
+ *
+ * Atomic drivers which don't subclass struct &drm_plane_state should use
+ * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the
+ * state structure to extend it with driver-private state should use
+ * __drm_atomic_helper_plane_duplicate_state() to make sure shared state is
+ * duplicated in a consistent fashion across drivers.
+ *
+ * It is an error to call this hook before plane->state has been
+ * initialized correctly.
+ *
+ * NOTE:
+ *
+ * If the duplicate state references refcounted resources this hook must
+ * acquire a reference for each of them. The driver must release these
+ * references again in @atomic_destroy_state.
+ *
+ * RETURNS:
+ *
+ * Duplicated atomic state or NULL when the allocation failed.
+ */
struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
+
+ /**
+ * @atomic_destroy_state:
+ *
+ * Destroy a state duplicated with @atomic_duplicate_state and release
+ * or unreference all resources it references
+ */
void (*atomic_destroy_state)(struct drm_plane *plane,
struct drm_plane_state *state);
+
+ /**
+ * @atomic_set_property:
+ *
+ * Decode a driver-private property value and store the decoded value
+ * into the passed-in state structure. Since the atomic core decodes all
+ * standardized properties (even for extensions beyond the core set of
+ * properties which might not be implemented by all drivers) this
+ * requires drivers to subclass the state structure.
+ *
+ * Such driver-private properties should really only be implemented for
+ * truly hardware/vendor specific state. Instead it is preferred to
+ * standardize atomic extension and decode the properties used to expose
+ * such an extension in the core.
+ *
+ * Do not call this function directly, use
+ * drm_atomic_plane_set_property() instead.
+ *
+ * This callback is optional if the driver does not support any
+ * driver-private atomic properties.
+ *
+ * NOTE:
+ *
+ * This function is called in the state assembly phase of atomic
+ * modesets, which can be aborted for any reason (including on
+ * userspace's request to just check whether a configuration would be
+ * possible). Drivers MUST NOT touch any persistent state (hardware or
+ * software) or data structures except the passed in @state parameter.
+ *
+ * Also since userspace controls in which order properties are set this
+ * function must not do any input validation (since the state update is
+ * incomplete and hence likely inconsistent). Instead any such input
+ * validation must be done in the various atomic_check callbacks.
+ *
+ * RETURNS:
+ *
+ * 0 if the property has been found, -EINVAL if the property isn't
+ * implemented by the driver (which shouldn't ever happen, the core only
+ * asks for properties attached to this plane). No other validation is
+ * allowed by the driver. The core already checks that the property
+ * value is within the range (integer, valid enum value, ...) the driver
+ * set when registering the property.
+ */
int (*atomic_set_property)(struct drm_plane *plane,
struct drm_plane_state *state,
struct drm_property *property,
uint64_t val);
+
+ /**
+ * @atomic_get_property:
+ *
+ * Reads out the decoded driver-private property. This is used to
+ * implement the GETPLANE IOCTL.
+ *
+ * Do not call this function directly, use
+ * drm_atomic_plane_get_property() instead.
+ *
+ * This callback is optional if the driver does not support any
+ * driver-private atomic properties.
+ *
+ * RETURNS:
+ *
+ * 0 on success, -EINVAL if the property isn't implemented by the
+ * driver (which should never happen, the core only asks for
+ * properties attached to this plane).
+ */
int (*atomic_get_property)(struct drm_plane *plane,
const struct drm_plane_state *state,
struct drm_property *property,
@@ -824,6 +1482,7 @@ enum drm_plane_type {
DRM_PLANE_TYPE_CURSOR,
};
+
/**
* struct drm_plane - central DRM plane control structure
* @dev: DRM device this plane belongs to
@@ -846,6 +1505,8 @@ struct drm_plane {
struct drm_device *dev;
struct list_head head;
+ char *name;
+
struct drm_modeset_lock mutex;
struct drm_mode_object base;
@@ -866,7 +1527,7 @@ struct drm_plane {
enum drm_plane_type type;
- const void *helper_private;
+ const struct drm_plane_helper_funcs *helper_private;
struct drm_plane_state *state;
};
@@ -874,24 +1535,114 @@ struct drm_plane {
/**
* struct drm_bridge_funcs - drm_bridge control functions
* @attach: Called during drm_bridge_attach
- * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
- * @disable: Called right before encoder prepare, disables the bridge
- * @post_disable: Called right after encoder prepare, for lockstepped disable
- * @mode_set: Set this mode to the bridge
- * @pre_enable: Called right before encoder commit, for lockstepped commit
- * @enable: Called right after encoder commit, enables the bridge
*/
struct drm_bridge_funcs {
int (*attach)(struct drm_bridge *bridge);
+
+ /**
+ * @mode_fixup:
+ *
+ * This callback is used to validate and adjust a mode. The paramater
+ * mode is the display mode that should be fed to the next element in
+ * the display chain, either the final &drm_connector or the next
+ * &drm_bridge. The parameter adjusted_mode is the input mode the bridge
+ * requires. It can be modified by this callback and does not need to
+ * match mode.
+ *
+ * This is the only hook that allows a bridge to reject a modeset. If
+ * this function passes all other callbacks must succeed for this
+ * configuration.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of atomic modesets, which
+ * can be aborted for any reason (including on userspace's request to
+ * just check whether a configuration would be possible). Drivers MUST
+ * NOT touch any persistent state (hardware or software) or data
+ * structures except the passed in @state parameter.
+ *
+ * RETURNS:
+ *
+ * True if an acceptable configuration is possible, false if the modeset
+ * operation should be rejected.
+ */
bool (*mode_fixup)(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
+ /**
+ * @disable:
+ *
+ * This callback should disable the bridge. It is called right before
+ * the preceding element in the display pipe is disabled. If the
+ * preceding element is a bridge this means it's called before that
+ * bridge's ->disable() function. If the preceding element is a
+ * &drm_encoder it's called right before the encoder's ->disable(),
+ * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+ *
+ * The bridge can assume that the display pipe (i.e. clocks and timing
+ * signals) feeding it is still running when this callback is called.
+ */
void (*disable)(struct drm_bridge *bridge);
+
+ /**
+ * @post_disable:
+ *
+ * This callback should disable the bridge. It is called right after
+ * the preceding element in the display pipe is disabled. If the
+ * preceding element is a bridge this means it's called after that
+ * bridge's ->post_disable() function. If the preceding element is a
+ * &drm_encoder it's called right after the encoder's ->disable(),
+ * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+ *
+ * The bridge must assume that the display pipe (i.e. clocks and timing
+ * singals) feeding it is no longer running when this callback is
+ * called.
+ */
void (*post_disable)(struct drm_bridge *bridge);
+
+ /**
+ * @mode_set:
+ *
+ * This callback should set the given mode on the bridge. It is called
+ * after the ->mode_set() callback for the preceding element in the
+ * display pipeline has been called already. The display pipe (i.e.
+ * clocks and timing signals) is off when this function is called.
+ */
void (*mode_set)(struct drm_bridge *bridge,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
+ /**
+ * @pre_enable:
+ *
+ * This callback should enable the bridge. It is called right before
+ * the preceding element in the display pipe is enabled. If the
+ * preceding element is a bridge this means it's called before that
+ * bridge's ->pre_enable() function. If the preceding element is a
+ * &drm_encoder it's called right before the encoder's ->enable(),
+ * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+ *
+ * The display pipe (i.e. clocks and timing signals) feeding this bridge
+ * will not yet be running when this callback is called. The bridge must
+ * not enable the display link feeding the next bridge in the chain (if
+ * there is one) when this callback is called.
+ */
void (*pre_enable)(struct drm_bridge *bridge);
+
+ /**
+ * @enable:
+ *
+ * This callback should enable the bridge. It is called right after
+ * the preceding element in the display pipe is enabled. If the
+ * preceding element is a bridge this means it's called after that
+ * bridge's ->enable() function. If the preceding element is a
+ * &drm_encoder it's called right after the encoder's ->enable(),
+ * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs.
+ *
+ * The bridge can assume that the display pipe (i.e. clocks and timing
+ * signals) feeding it is running when this callback is called. This
+ * callback must enable the display link feeding the next bridge in the
+ * chain if there is one.
+ */
void (*enable)(struct drm_bridge *bridge);
};
@@ -922,7 +1673,7 @@ struct drm_bridge {
* struct drm_atomic_state - the global state object for atomic updates
* @dev: parent DRM device
* @allow_modeset: allow full modeset
- * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
+ * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
* @planes: pointer to array of plane pointers
* @plane_states: pointer to array of plane states pointers
* @crtcs: pointer to array of CRTC pointers
@@ -977,31 +1728,265 @@ struct drm_mode_set {
/**
* struct drm_mode_config_funcs - basic driver provided mode setting functions
- * @fb_create: create a new framebuffer object
- * @output_poll_changed: function to handle output configuration changes
- * @atomic_check: check whether a given atomic state update is possible
- * @atomic_commit: commit an atomic state update previously verified with
- * atomic_check()
- * @atomic_state_alloc: allocate a new atomic state
- * @atomic_state_clear: clear the atomic state
- * @atomic_state_free: free the atomic state
*
* Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
* involve drivers.
*/
struct drm_mode_config_funcs {
+ /**
+ * @fb_create:
+ *
+ * Create a new framebuffer object. The core does basic checks on the
+ * requested metadata, but most of that is left to the driver. See
+ * struct &drm_mode_fb_cmd2 for details.
+ *
+ * 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
+ * driver-specific information (like the internal native buffer object
+ * references). It also needs to fill out all relevant metadata, which
+ * should be done by calling drm_helper_mode_fill_fb_struct().
+ *
+ * The initialization is finalized by calling drm_framebuffer_init(),
+ * which registers the framebuffer and makes it accessible to other
+ * threads.
+ *
+ * RETURNS:
+ *
+ * A new framebuffer with an initial reference count of 1 or a negative
+ * error code encoded with ERR_PTR().
+ */
struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd);
+ const struct drm_mode_fb_cmd2 *mode_cmd);
+
+ /**
+ * @output_poll_changed:
+ *
+ * Callback used by helpers to inform the driver of output configuration
+ * changes.
+ *
+ * Drivers implementing fbdev emulation with the helpers can call
+ * drm_fb_helper_hotplug_changed from this hook to inform the fbdev
+ * helper of output changes.
+ *
+ * FIXME:
+ *
+ * Except that there's no vtable for device-level helper callbacks
+ * there's no reason this is a core function.
+ */
void (*output_poll_changed)(struct drm_device *dev);
+ /**
+ * @atomic_check:
+ *
+ * This is the only hook to validate an atomic modeset update. This
+ * function must reject any modeset and state changes which the hardware
+ * or driver doesn't support. This includes but is of course not limited
+ * to:
+ *
+ * - Checking that the modes, framebuffers, scaling and placement
+ * requirements and so on are within the limits of the hardware.
+ *
+ * - Checking that any hidden shared resources are not oversubscribed.
+ * This can be shared PLLs, shared lanes, overall memory bandwidth,
+ * display fifo space (where shared between planes or maybe even
+ * CRTCs).
+ *
+ * - Checking that virtualized resources exported to userspace are not
+ * oversubscribed. For various reasons it can make sense to expose
+ * more planes, crtcs or encoders than which are physically there. One
+ * example is dual-pipe operations (which generally should be hidden
+ * from userspace if when lockstepped in hardware, exposed otherwise),
+ * where a plane might need 1 hardware plane (if it's just on one
+ * pipe), 2 hardware planes (when it spans both pipes) or maybe even
+ * shared a hardware plane with a 2nd plane (if there's a compatible
+ * plane requested on the area handled by the other pipe).
+ *
+ * - Check that any transitional state is possible and that if
+ * requested, the update can indeed be done in the vblank period
+ * without temporarily disabling some functions.
+ *
+ * - Check any other constraints the driver or hardware might have.
+ *
+ * - This callback also needs to correctly fill out the &drm_crtc_state
+ * in this update to make sure that drm_atomic_crtc_needs_modeset()
+ * reflects the nature of the possible update and returns true if and
+ * only if the update cannot be applied without tearing within one
+ * vblank on that CRTC. The core uses that information to reject
+ * updates which require a full modeset (i.e. blanking the screen, or
+ * at least pausing updates for a substantial amount of time) if
+ * userspace has disallowed that in its request.
+ *
+ * - The driver also does not need to repeat basic input validation
+ * like done for the corresponding legacy entry points. The core does
+ * that before calling this hook.
+ *
+ * See the documentation of @atomic_commit for an exhaustive list of
+ * error conditions which don't have to be checked at the
+ * ->atomic_check() stage?
+ *
+ * See the documentation for struct &drm_atomic_state for how exactly
+ * an atomic modeset update is described.
+ *
+ * Drivers using the atomic helpers can implement this hook using
+ * drm_atomic_helper_check(), or one of the exported sub-functions of
+ * it.
+ *
+ * RETURNS:
+ *
+ * 0 on success or one of the below negative error codes:
+ *
+ * - -EINVAL, if any of the above constraints are violated.
+ *
+ * - -EDEADLK, when returned from an attempt to acquire an additional
+ * &drm_modeset_lock through drm_modeset_lock().
+ *
+ * - -ENOMEM, if allocating additional state sub-structures failed due
+ * to lack of memory.
+ *
+ * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted.
+ * This can either be due to a pending signal, or because the driver
+ * needs to completely bail out to recover from an exceptional
+ * situation like a GPU hang. From a userspace point all errors are
+ * treated equally.
+ */
int (*atomic_check)(struct drm_device *dev,
- struct drm_atomic_state *a);
+ struct drm_atomic_state *state);
+
+ /**
+ * @atomic_commit:
+ *
+ * This is the only hook to commit an atomic modeset update. The core
+ * guarantees that @atomic_check has been called successfully before
+ * calling this function, and that nothing has been changed in the
+ * interim.
+ *
+ * See the documentation for struct &drm_atomic_state for how exactly
+ * an atomic modeset update is described.
+ *
+ * Drivers using the atomic helpers can implement this hook using
+ * drm_atomic_helper_commit(), or one of the exported sub-functions of
+ * it.
+ *
+ * Asynchronous commits (as indicated with the async parameter) must
+ * do any preparatory work which might result in an unsuccessful commit
+ * in the context of this callback. The only exceptions are hardware
+ * errors resulting in -EIO. But even in that case the driver must
+ * ensure that the display pipe is at least running, to avoid
+ * compositors crashing when pageflips don't work. Anything else,
+ * specifically committing the update to the hardware, should be done
+ * without blocking the caller. For updates which do not require a
+ * modeset this must be guaranteed.
+ *
+ * The driver must wait for any pending rendering to the new
+ * framebuffers to complete before executing the flip. It should also
+ * wait for any pending rendering from other drivers if the underlying
+ * buffer is a shared dma-buf. Asynchronous commits must not wait for
+ * rendering in the context of this callback.
+ *
+ * An application can request to be notified when the atomic commit has
+ * completed. These events are per-CRTC and can be distinguished by the
+ * CRTC index supplied in &drm_event to userspace.
+ *
+ * The drm core will supply a struct &drm_event in the event
+ * member of each CRTC's &drm_crtc_state structure. This can be handled by the
+ * drm_crtc_send_vblank_event() function, which the driver should call on
+ * the provided event upon completion of the atomic commit. Note that if
+ * the driver supports vblank signalling and timestamping the vblank
+ * counters and timestamps must agree with the ones returned from page
+ * flip events. With the current vblank helper infrastructure this can
+ * be achieved by holding a vblank reference while the page flip is
+ * pending, acquired through drm_crtc_vblank_get() and released with
+ * drm_crtc_vblank_put(). Drivers are free to implement their own vblank
+ * counter and timestamp tracking though, e.g. if they have accurate
+ * timestamp registers in hardware.
+ *
+ * NOTE:
+ *
+ * Drivers are not allowed to shut down any display pipe successfully
+ * enabled through an atomic commit on their own. Doing so can result in
+ * compositors crashing if a page flip is suddenly rejected because the
+ * pipe is off.
+ *
+ * RETURNS:
+ *
+ * 0 on success or one of the below negative error codes:
+ *
+ * - -EBUSY, if an asynchronous updated is requested and there is
+ * an earlier updated pending. Drivers are allowed to support a queue
+ * of outstanding updates, but currently no driver supports that.
+ * Note that drivers must wait for preceding updates to complete if a
+ * synchronous update is requested, they are not allowed to fail the
+ * commit in that case.
+ *
+ * - -ENOMEM, if the driver failed to allocate memory. Specifically
+ * this can happen when trying to pin framebuffers, which must only
+ * be done when committing the state.
+ *
+ * - -ENOSPC, as a refinement of the more generic -ENOMEM to indicate
+ * that the driver has run out of vram, iommu space or similar GPU
+ * address space needed for framebuffer.
+ *
+ * - -EIO, if the hardware completely died.
+ *
+ * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted.
+ * This can either be due to a pending signal, or because the driver
+ * needs to completely bail out to recover from an exceptional
+ * situation like a GPU hang. From a userspace point of view all errors are
+ * treated equally.
+ *
+ * This list is exhaustive. Specifically this hook is not allowed to
+ * return -EINVAL (any invalid requests should be caught in
+ * @atomic_check) or -EDEADLK (this function must not acquire
+ * additional modeset locks).
+ */
int (*atomic_commit)(struct drm_device *dev,
- struct drm_atomic_state *a,
+ struct drm_atomic_state *state,
bool async);
+
+ /**
+ * @atomic_state_alloc:
+ *
+ * This optional hook can be used by drivers that want to subclass struct
+ * &drm_atomic_state to be able to track their own driver-private global
+ * state easily. If this hook is implemented, drivers must also
+ * implement @atomic_state_clear and @atomic_state_free.
+ *
+ * RETURNS:
+ *
+ * A new &drm_atomic_state on success or NULL on failure.
+ */
struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev);
+
+ /**
+ * @atomic_state_clear:
+ *
+ * This hook must clear any driver private state duplicated into the
+ * passed-in &drm_atomic_state. This hook is called when the caller
+ * encountered a &drm_modeset_lock deadlock and needs to drop all
+ * already acquired locks as part of the deadlock avoidance dance
+ * implemented in drm_modeset_lock_backoff().
+ *
+ * Any duplicated state must be invalidated since a concurrent atomic
+ * update might change it, and the drm atomic interfaces always apply
+ * updates as relative changes to the current state.
+ *
+ * Drivers that implement this must call drm_atomic_state_default_clear()
+ * to clear common state.
+ */
void (*atomic_state_clear)(struct drm_atomic_state *state);
+
+ /**
+ * @atomic_state_free:
+ *
+ * This hook needs driver private resources and the &drm_atomic_state
+ * itself. Note that the core first calls drm_atomic_state_clear() to
+ * avoid code duplicate between the clear and free hooks.
+ *
+ * Drivers that implement this must call drm_atomic_state_default_free()
+ * to release common resources.
+ */
void (*atomic_state_free)(struct drm_atomic_state *state);
};
@@ -1010,7 +1995,7 @@ struct drm_mode_config_funcs {
* @mutex: mutex protecting KMS related lists and structures
* @connection_mutex: ww mutex protecting connector state and routing
* @acquire_ctx: global implicit acquire context used by atomic drivers for
- * legacy ioctls
+ * legacy IOCTLs
* @idr_mutex: mutex for KMS ID allocation and management
* @crtc_idr: main KMS ID tracking object
* @fb_lock: mutex to protect fb state and lists
@@ -1166,7 +2151,7 @@ struct drm_mode_config {
*/
#define drm_for_each_plane_mask(plane, dev, plane_mask) \
list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
- if ((plane_mask) & (1 << drm_plane_index(plane)))
+ for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
@@ -1183,11 +2168,13 @@ struct drm_prop_enum_list {
char *name;
};
-extern int drm_crtc_init_with_planes(struct drm_device *dev,
- struct drm_crtc *crtc,
- struct drm_plane *primary,
- struct drm_plane *cursor,
- const struct drm_crtc_funcs *funcs);
+extern __printf(6, 7)
+int drm_crtc_init_with_planes(struct drm_device *dev,
+ struct drm_crtc *crtc,
+ struct drm_plane *primary,
+ struct drm_plane *cursor,
+ const struct drm_crtc_funcs *funcs,
+ const char *name, ...);
extern void drm_crtc_cleanup(struct drm_crtc *crtc);
extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
@@ -1233,10 +2220,11 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
void drm_bridge_pre_enable(struct drm_bridge *bridge);
void drm_bridge_enable(struct drm_bridge *bridge);
-extern int drm_encoder_init(struct drm_device *dev,
- struct drm_encoder *encoder,
- const struct drm_encoder_funcs *funcs,
- int encoder_type);
+extern __printf(5, 6)
+int drm_encoder_init(struct drm_device *dev,
+ struct drm_encoder *encoder,
+ const struct drm_encoder_funcs *funcs,
+ int encoder_type, const char *name, ...);
/**
* drm_encoder_crtc_ok - can a given crtc drive a given encoder?
@@ -1251,13 +2239,15 @@ static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
return !!(encoder->possible_crtcs & drm_crtc_mask(crtc));
}
-extern int drm_universal_plane_init(struct drm_device *dev,
- struct drm_plane *plane,
- unsigned long possible_crtcs,
- const struct drm_plane_funcs *funcs,
- const uint32_t *formats,
- unsigned int format_count,
- enum drm_plane_type type);
+extern __printf(8, 9)
+int drm_universal_plane_init(struct drm_device *dev,
+ struct drm_plane *plane,
+ unsigned long possible_crtcs,
+ const struct drm_plane_funcs *funcs,
+ const uint32_t *formats,
+ unsigned int format_count,
+ enum drm_plane_type type,
+ const char *name, ...);
extern int drm_plane_init(struct drm_device *dev,
struct drm_plane *plane,
unsigned long possible_crtcs,
@@ -1543,7 +2533,7 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev,
/* Plane list iterator for legacy (overlay only) planes. */
#define drm_for_each_legacy_plane(plane, dev) \
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
- if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+ for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
#define drm_for_each_plane(plane, dev) \
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 3febb4b9fce9..4b37afa2b73b 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -40,148 +40,7 @@
#include <linux/fb.h>
#include <drm/drm_crtc.h>
-
-enum mode_set_atomic {
- LEAVE_ATOMIC_MODE_SET,
- ENTER_ATOMIC_MODE_SET,
-};
-
-/**
- * struct drm_crtc_helper_funcs - helper operations for CRTCs
- * @dpms: set power state
- * @prepare: prepare the CRTC, called before @mode_set
- * @commit: commit changes to CRTC, called after @mode_set
- * @mode_fixup: try to fixup proposed mode for this CRTC
- * @mode_set: set this mode
- * @mode_set_nofb: set mode only (no scanout buffer attached)
- * @mode_set_base: update the scanout buffer
- * @mode_set_base_atomic: non-blocking mode set (used for kgdb support)
- * @load_lut: load color palette
- * @disable: disable CRTC when no longer in use
- * @enable: enable CRTC
- * @atomic_check: check for validity of an atomic state
- * @atomic_begin: begin atomic update
- * @atomic_flush: flush atomic update
- *
- * The helper operations are called by the mid-layer CRTC helper.
- *
- * Note that with atomic helpers @dpms, @prepare and @commit hooks are
- * deprecated. Used @enable and @disable instead exclusively.
- *
- * With legacy crtc helpers there's a big semantic difference between @disable
- * and the other hooks: @disable also needs to release any resources acquired in
- * @mode_set (like shared PLLs).
- */
-struct drm_crtc_helper_funcs {
- /*
- * Control power levels on the CRTC. If the mode passed in is
- * unsupported, the provider must use the next lowest power level.
- */
- void (*dpms)(struct drm_crtc *crtc, int mode);
- void (*prepare)(struct drm_crtc *crtc);
- void (*commit)(struct drm_crtc *crtc);
-
- /* Provider can fixup or change mode timings before modeset occurs */
- bool (*mode_fixup)(struct drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
- /* Actually set the mode */
- int (*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);
- /* Actually set the mode for atomic helpers, optional */
- void (*mode_set_nofb)(struct drm_crtc *crtc);
-
- /* Move the crtc on the current fb to the given position *optional* */
- int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb);
- int (*mode_set_base_atomic)(struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int x, int y,
- enum mode_set_atomic);
-
- /* reload the current crtc LUT */
- void (*load_lut)(struct drm_crtc *crtc);
-
- void (*disable)(struct drm_crtc *crtc);
- void (*enable)(struct drm_crtc *crtc);
-
- /* atomic helpers */
- int (*atomic_check)(struct drm_crtc *crtc,
- struct drm_crtc_state *state);
- void (*atomic_begin)(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state);
- void (*atomic_flush)(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state);
-};
-
-/**
- * struct drm_encoder_helper_funcs - helper operations for encoders
- * @dpms: set power state
- * @save: save connector state
- * @restore: restore connector state
- * @mode_fixup: try to fixup proposed mode for this connector
- * @prepare: part of the disable sequence, called before the CRTC modeset
- * @commit: called after the CRTC modeset
- * @mode_set: set this mode, optional for atomic helpers
- * @get_crtc: return CRTC that the encoder is currently attached to
- * @detect: connection status detection
- * @disable: disable encoder when not in use (overrides DPMS off)
- * @enable: enable encoder
- * @atomic_check: check for validity of an atomic update
- *
- * The helper operations are called by the mid-layer CRTC helper.
- *
- * Note that with atomic helpers @dpms, @prepare and @commit hooks are
- * deprecated. Used @enable and @disable instead exclusively.
- *
- * With legacy crtc helpers there's a big semantic difference between @disable
- * and the other hooks: @disable also needs to release any resources acquired in
- * @mode_set (like shared PLLs).
- */
-struct drm_encoder_helper_funcs {
- void (*dpms)(struct drm_encoder *encoder, int mode);
- void (*save)(struct drm_encoder *encoder);
- void (*restore)(struct drm_encoder *encoder);
-
- bool (*mode_fixup)(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
- void (*prepare)(struct drm_encoder *encoder);
- void (*commit)(struct drm_encoder *encoder);
- void (*mode_set)(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
- struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder);
- /* detect for DAC style encoders */
- enum drm_connector_status (*detect)(struct drm_encoder *encoder,
- struct drm_connector *connector);
- void (*disable)(struct drm_encoder *encoder);
-
- void (*enable)(struct drm_encoder *encoder);
-
- /* atomic helpers */
- int (*atomic_check)(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state);
-};
-
-/**
- * struct drm_connector_helper_funcs - helper operations for connectors
- * @get_modes: get mode list for this connector
- * @mode_valid: is this mode valid on the given connector? (optional)
- * @best_encoder: return the preferred encoder for this connector
- * @atomic_best_encoder: atomic version of @best_encoder
- *
- * The helper operations are called by the mid-layer CRTC helper.
- */
-struct drm_connector_helper_funcs {
- int (*get_modes)(struct drm_connector *connector);
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
- struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
- struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
- struct drm_connector_state *connector_state);
-};
+#include <drm/drm_modeset_helper_vtables.h>
extern void drm_helper_disable_unused_functions(struct drm_device *dev);
extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
@@ -197,25 +56,7 @@ extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode);
extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
- struct drm_mode_fb_cmd2 *mode_cmd);
-
-static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
- const struct drm_crtc_helper_funcs *funcs)
-{
- crtc->helper_private = funcs;
-}
-
-static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
- const struct drm_encoder_helper_funcs *funcs)
-{
- encoder->helper_private = funcs;
-}
-
-static inline void drm_connector_helper_add(struct drm_connector *connector,
- const struct drm_connector_helper_funcs *funcs)
-{
- connector->helper_private = funcs;
-}
+ const struct drm_mode_fb_cmd2 *mode_cmd);
extern void drm_helper_resume_force_mode(struct drm_device *dev);
@@ -229,10 +70,6 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
extern int drm_helper_probe_single_connector_modes(struct drm_connector
*connector, uint32_t maxX,
uint32_t maxY);
-extern int drm_helper_probe_single_connector_modes_nomerge(struct drm_connector
- *connector,
- uint32_t maxX,
- uint32_t maxY);
extern void drm_kms_helper_poll_init(struct drm_device *dev);
extern void drm_kms_helper_poll_fini(struct drm_device *dev);
extern bool drm_helper_hpd_irq_event(struct drm_device *dev);
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index bb9d0deca07c..1252108da0ef 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -455,16 +455,52 @@
# define DP_EDP_14 0x03
#define DP_EDP_GENERAL_CAP_1 0x701
+# define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP (1 << 0)
+# define DP_EDP_BACKLIGHT_PIN_ENABLE_CAP (1 << 1)
+# define DP_EDP_BACKLIGHT_AUX_ENABLE_CAP (1 << 2)
+# define DP_EDP_PANEL_SELF_TEST_PIN_ENABLE_CAP (1 << 3)
+# define DP_EDP_PANEL_SELF_TEST_AUX_ENABLE_CAP (1 << 4)
+# define DP_EDP_FRC_ENABLE_CAP (1 << 5)
+# define DP_EDP_COLOR_ENGINE_CAP (1 << 6)
+# define DP_EDP_SET_POWER_CAP (1 << 7)
#define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP 0x702
+# define DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP (1 << 0)
+# define DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP (1 << 1)
+# define DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT (1 << 2)
+# define DP_EDP_BACKLIGHT_AUX_PWM_PRODUCT_CAP (1 << 3)
+# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_CAP (1 << 4)
+# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP (1 << 5)
+# define DP_EDP_DYNAMIC_BACKLIGHT_CAP (1 << 6)
+# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_CAP (1 << 7)
#define DP_EDP_GENERAL_CAP_2 0x703
+# define DP_EDP_OVERDRIVE_ENGINE_ENABLED (1 << 0)
#define DP_EDP_GENERAL_CAP_3 0x704 /* eDP 1.4 */
+# define DP_EDP_X_REGION_CAP_MASK (0xf << 0)
+# define DP_EDP_X_REGION_CAP_SHIFT 0
+# define DP_EDP_Y_REGION_CAP_MASK (0xf << 4)
+# define DP_EDP_Y_REGION_CAP_SHIFT 4
#define DP_EDP_DISPLAY_CONTROL_REGISTER 0x720
+# define DP_EDP_BACKLIGHT_ENABLE (1 << 0)
+# define DP_EDP_BLACK_VIDEO_ENABLE (1 << 1)
+# define DP_EDP_FRC_ENABLE (1 << 2)
+# define DP_EDP_COLOR_ENGINE_ENABLE (1 << 3)
+# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_ENABLE (1 << 7)
#define DP_EDP_BACKLIGHT_MODE_SET_REGISTER 0x721
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_MASK (3 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_PWM (0 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET (1 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD (2 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT (3 << 0)
+# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_ENABLE (1 << 2)
+# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE (1 << 3)
+# define DP_EDP_DYNAMIC_BACKLIGHT_ENABLE (1 << 4)
+# define DP_EDP_REGIONAL_BACKLIGHT_ENABLE (1 << 5)
+# define DP_EDP_UPDATE_REGION_BRIGHTNESS (1 << 6) /* eDP 1.4 */
#define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB 0x722
#define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB 0x723
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 5340099741ae..24ab1787b771 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -94,6 +94,7 @@ struct drm_dp_mst_port {
struct drm_dp_mst_topology_mgr *mgr;
struct edid *cached_edid; /* for DP logical ports - make tiling work */
+ bool has_audio;
};
/**
@@ -215,13 +216,13 @@ struct drm_dp_sideband_msg_rx {
struct drm_dp_sideband_msg_hdr initial_hdr;
};
-
+#define DRM_DP_MAX_SDP_STREAMS 16
struct drm_dp_allocate_payload {
u8 port_number;
u8 number_sdp_streams;
u8 vcpi;
u16 pbn;
- u8 sdp_stream_sink[8];
+ u8 sdp_stream_sink[DRM_DP_MAX_SDP_STREAMS];
};
struct drm_dp_allocate_payload_ack_reply {
@@ -420,7 +421,7 @@ struct drm_dp_payload {
struct drm_dp_mst_topology_mgr {
struct device *dev;
- struct drm_dp_mst_topology_cbs *cbs;
+ const struct drm_dp_mst_topology_cbs *cbs;
int max_dpcd_transaction_bytes;
struct drm_dp_aux *aux; /* auxch for this topology mgr to use */
int max_payloads;
@@ -450,9 +451,7 @@ struct drm_dp_mst_topology_mgr {
the mstb tx_slots and txmsg->state once they are queued */
struct mutex qlock;
struct list_head tx_msg_downq;
- struct list_head tx_msg_upq;
bool tx_down_in_progress;
- bool tx_up_in_progress;
/* payload info + lock for it */
struct mutex payload_lock;
@@ -484,6 +483,8 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handl
enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
+bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_port *port);
struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
diff --git a/include/drm/drm_encoder_slave.h b/include/drm/drm_encoder_slave.h
index 8b9cc3671858..82cdf611393d 100644
--- a/include/drm/drm_encoder_slave.h
+++ b/include/drm/drm_encoder_slave.h
@@ -95,7 +95,7 @@ struct drm_encoder_slave_funcs {
struct drm_encoder_slave {
struct drm_encoder base;
- struct drm_encoder_slave_funcs *slave_funcs;
+ const struct drm_encoder_slave_funcs *slave_funcs;
void *slave_priv;
void *bus_priv;
};
diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h
index c54cf3d4a03f..be62bd321e75 100644
--- a/include/drm/drm_fb_cma_helper.h
+++ b/include/drm/drm_fb_cma_helper.h
@@ -18,7 +18,7 @@ void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma);
void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma);
struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
- struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd);
+ struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
unsigned int plane);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 87b090c4b730..d8a40dff0d1d 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -34,6 +34,11 @@ struct drm_fb_helper;
#include <linux/kgdb.h>
+enum mode_set_atomic {
+ LEAVE_ATOMIC_MODE_SET,
+ ENTER_ATOMIC_MODE_SET,
+};
+
struct drm_fb_offset {
int x, y;
};
@@ -74,25 +79,76 @@ struct drm_fb_helper_surface_size {
/**
* struct drm_fb_helper_funcs - driver callbacks for the fbdev emulation library
- * @gamma_set: Set the given gamma lut register on the given crtc.
- * @gamma_get: Read the given gamma lut register on the given crtc, used to
- * save the current lut when force-restoring the fbdev for e.g.
- * kdbg.
- * @fb_probe: Driver callback to allocate and initialize the fbdev info
- * structure. Furthermore it also needs to allocate the drm
- * framebuffer used to back the fbdev.
- * @initial_config: Setup an initial fbdev display configuration
*
* Driver callbacks used by the fbdev emulation helper library.
*/
struct drm_fb_helper_funcs {
+ /**
+ * @gamma_set:
+ *
+ * Set the given gamma LUT register on the given CRTC.
+ *
+ * This callback is optional.
+ *
+ * FIXME:
+ *
+ * This callback is functionally redundant with the core gamma table
+ * support and simply exists because the fbdev hasn't yet been
+ * refactored to use the core gamma table interfaces.
+ */
void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
+ /**
+ * @gamma_get:
+ *
+ * Read the given gamma LUT register on the given CRTC, used to save the
+ * current LUT when force-restoring the fbdev for e.g. kdbg.
+ *
+ * This callback is optional.
+ *
+ * FIXME:
+ *
+ * This callback is functionally redundant with the core gamma table
+ * support and simply exists because the fbdev hasn't yet been
+ * refactored to use the core gamma table interfaces.
+ */
void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
+ /**
+ * @fb_probe:
+ *
+ * Driver callback to allocate and initialize the fbdev info structure.
+ * Furthermore it also needs to allocate the DRM framebuffer used to
+ * back the fbdev.
+ *
+ * This callback is mandatory.
+ *
+ * RETURNS:
+ *
+ * The driver should return 0 on success and a negative error code on
+ * failure.
+ */
int (*fb_probe)(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes);
+
+ /**
+ * @initial_config:
+ *
+ * Driver callback to setup an initial fbdev display configuration.
+ * Drivers can use this callback to tell the fbdev emulation what the
+ * preferred initial configuration is. This is useful to implement
+ * smooth booting where the fbdev (and subsequently all userspace) never
+ * changes the mode, but always inherits the existing configuration.
+ *
+ * This callback is optional.
+ *
+ * RETURNS:
+ *
+ * The driver should return true if a suitable initial configuration has
+ * been filled out and false when the fbdev helper should fall back to
+ * the default probing logic.
+ */
bool (*initial_config)(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_crtc **crtcs,
struct drm_display_mode **modes,
@@ -105,18 +161,22 @@ struct drm_fb_helper_connector {
};
/**
- * struct drm_fb_helper - helper to emulate fbdev on top of kms
- * @fb: Scanout framebuffer object
- * @dev: DRM device
+ * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
+ * @fb: Scanout framebuffer object
+ * @dev: DRM device
* @crtc_count: number of possible CRTCs
* @crtc_info: per-CRTC helper state (mode, x/y offset, etc)
* @connector_count: number of connected connectors
* @connector_info_alloc_count: size of connector_info
+ * @connector_info: array of per-connector information
* @funcs: driver callbacks for fb helper
* @fbdev: emulated fbdev device info struct
* @pseudo_palette: fake palette of 16 colors
- * @kernel_fb_list: list_head in kernel_fb_helper_list
- * @delayed_hotplug: was there a hotplug while kms master active?
+ *
+ * This is the main structure used by the fbdev helpers. Drivers supporting
+ * fbdev emulation should embedded this into their overall driver structure.
+ * Drivers must also fill out a struct &drm_fb_helper_funcs with a few
+ * operations.
*/
struct drm_fb_helper {
struct drm_framebuffer *fb;
@@ -129,10 +189,21 @@ struct drm_fb_helper {
const struct drm_fb_helper_funcs *funcs;
struct fb_info *fbdev;
u32 pseudo_palette[17];
+
+ /**
+ * @kernel_fb_list:
+ *
+ * Entry on the global kernel_fb_helper_list, used for kgdb entry/exit.
+ */
struct list_head kernel_fb_list;
- /* we got a hotplug but fbdev wasn't running the console
- delay until next set_par */
+ /**
+ * @delayed_hotplug:
+ *
+ * A hotplug was received while fbdev wasn't in control of the DRM
+ * device, i.e. another KMS master was active. The output configuration
+ * needs to be reprobe when fbdev is in control again.
+ */
bool delayed_hotplug;
/**
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 15e7f007380f..0b3e11ab8757 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -35,76 +35,129 @@
*/
/**
- * This structure defines the drm_mm memory object, which will be used by the
- * DRM for its buffer objects.
+ * struct drm_gem_object - GEM buffer object
+ *
+ * This structure defines the generic parts for GEM buffer objects, which are
+ * mostly around handling mmap and userspace handles.
+ *
+ * Buffer objects are often abbreviated to BO.
*/
struct drm_gem_object {
- /** Reference count of this object */
+ /**
+ * @refcount:
+ *
+ * Reference count of this object
+ *
+ * Please use drm_gem_object_reference() to acquire and
+ * drm_gem_object_unreference() or drm_gem_object_unreference_unlocked()
+ * to release a reference to a GEM buffer object.
+ */
struct kref refcount;
/**
- * handle_count - gem file_priv handle count of this object
+ * @handle_count:
+ *
+ * This is the GEM file_priv handle count of this object.
*
* Each handle also holds a reference. Note that when the handle_count
* drops to 0 any global names (e.g. the id in the flink namespace) will
* be cleared.
*
* Protected by dev->object_name_lock.
- * */
+ */
unsigned handle_count;
- /** Related drm device */
+ /**
+ * @dev: DRM dev this object belongs to.
+ */
struct drm_device *dev;
- /** File representing the shmem storage */
+ /**
+ * @filp:
+ *
+ * SHMEM file node used as backing storage for swappable buffer objects.
+ * GEM also supports driver private objects with driver-specific backing
+ * storage (contiguous CMA memory, special reserved blocks). In this
+ * case @filp is NULL.
+ */
struct file *filp;
- /* Mapping info for this object */
+ /**
+ * @vma_node:
+ *
+ * Mapping info for this object to support mmap. Drivers are supposed to
+ * allocate the mmap offset using drm_gem_create_mmap_offset(). The
+ * offset itself can be retrieved using drm_vma_node_offset_addr().
+ *
+ * Memory mapping itself is handled by drm_gem_mmap(), which also checks
+ * that userspace is allowed to access the object.
+ */
struct drm_vma_offset_node vma_node;
/**
+ * @size:
+ *
* Size of the object, in bytes. Immutable over the object's
* lifetime.
*/
size_t size;
/**
+ * @name:
+ *
* Global name for this object, starts at 1. 0 means unnamed.
- * Access is covered by the object_name_lock in the related drm_device
+ * Access is covered by dev->object_name_lock. This is used by the GEM_FLINK
+ * and GEM_OPEN ioctls.
*/
int name;
/**
- * Memory domains. These monitor which caches contain read/write data
+ * @read_domains:
+ *
+ * Read memory domains. These monitor which caches contain read/write data
* related to the object. When transitioning from one set of domains
* to another, the driver is called to ensure that caches are suitably
- * flushed and invalidated
+ * flushed and invalidated.
*/
uint32_t read_domains;
+
+ /**
+ * @write_domain: Corresponding unique write memory domain.
+ */
uint32_t write_domain;
/**
+ * @pending_read_domains:
+ *
* While validating an exec operation, the
* new read/write domain values are computed here.
* They will be transferred to the above values
* at the point that any cache flushing occurs
*/
uint32_t pending_read_domains;
+
+ /**
+ * @pending_write_domain: Write domain similar to @pending_read_domains.
+ */
uint32_t pending_write_domain;
/**
- * dma_buf - dma buf associated with this GEM object
+ * @dma_buf:
+ *
+ * dma-buf associated with this GEM object.
*
* Pointer to the dma-buf associated with this gem object (either
* through importing or exporting). We break the resulting reference
* loop when the last gem handle for this object is released.
*
- * Protected by obj->object_name_lock
+ * Protected by obj->object_name_lock.
*/
struct dma_buf *dma_buf;
/**
- * import_attach - dma buf attachment backing this object
+ * @import_attach:
+ *
+ * dma-buf attachment backing this object.
*
* Any foreign dma_buf imported as a gem object has this set to the
* attachment point for the device. This is invariant over the lifetime
@@ -133,12 +186,30 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
struct vm_area_struct *vma);
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+/**
+ * drm_gem_object_reference - acquire a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This acquires additional reference to @obj. It is illegal to call this
+ * without already holding a reference. No locks required.
+ */
static inline void
drm_gem_object_reference(struct drm_gem_object *obj)
{
kref_get(&obj->refcount);
}
+/**
+ * drm_gem_object_unreference - release a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This releases a reference to @obj. Callers must hold the dev->struct_mutex
+ * lock when calling this function, even when the driver doesn't use
+ * dev->struct_mutex for anything.
+ *
+ * For drivers not encumbered with legacy locking use
+ * drm_gem_object_unreference_unlocked() instead.
+ */
static inline void
drm_gem_object_unreference(struct drm_gem_object *obj)
{
@@ -149,6 +220,13 @@ drm_gem_object_unreference(struct drm_gem_object *obj)
}
}
+/**
+ * drm_gem_object_unreference_unlocked - release a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This releases a reference to @obj. Callers must not hold the
+ * dev->struct_mutex lock when calling this function.
+ */
static inline void
drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
{
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index f1d8d0dbb4f1..1b3b1f8c8cdf 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -163,9 +163,36 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
return container_of(dev, struct mipi_dsi_device, dev);
}
+/**
+ * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
+ * given pixel format defined by the MIPI DSI
+ * specification
+ * @fmt: MIPI DSI pixel format
+ *
+ * Returns: The number of bits per pixel of the given pixel format.
+ */
+static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
+{
+ switch (fmt) {
+ case MIPI_DSI_FMT_RGB888:
+ case MIPI_DSI_FMT_RGB666:
+ return 24;
+
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return 18;
+
+ case MIPI_DSI_FMT_RGB565:
+ return 16;
+ }
+
+ return -EINVAL;
+}
+
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
+int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
+int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
u16 value);
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 0de6290df4da..fc65118e5077 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -148,8 +148,7 @@ static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node)
static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
- return list_entry(hole_node->node_list.next,
- struct drm_mm_node, node_list)->start;
+ return list_next_entry(hole_node, node_list)->start;
}
/**
@@ -180,6 +179,14 @@ static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
&(mm)->head_node.node_list, \
node_list)
+#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \
+ for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
+ &entry->hole_stack != &(mm)->hole_stack ? \
+ hole_start = drm_mm_hole_node_start(entry), \
+ hole_end = drm_mm_hole_node_end(entry), \
+ 1 : 0; \
+ entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack))
+
/**
* drm_mm_for_each_hole - iterator to walk over all holes
* @entry: drm_mm_node used internally to track progress
@@ -200,20 +207,7 @@ static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
* going backwards.
*/
#define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \
- for (entry = list_entry((mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
- &entry->hole_stack != &(mm)->hole_stack ? \
- hole_start = drm_mm_hole_node_start(entry), \
- hole_end = drm_mm_hole_node_end(entry), \
- 1 : 0; \
- entry = list_entry(entry->hole_stack.next, struct drm_mm_node, hole_stack))
-
-#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \
- for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
- &entry->hole_stack != &(mm)->hole_stack ? \
- hole_start = drm_mm_hole_node_start(entry), \
- hole_end = drm_mm_hole_node_end(entry), \
- 1 : 0; \
- entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack))
+ __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, 0)
/*
* Basic range manager support (drm_mm.c)
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 08a8cac9e555..625966a906f2 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -35,46 +35,91 @@
* structures).
*/
+/**
+ * enum drm_mode_status - hardware support status of a mode
+ * @MODE_OK: Mode OK
+ * @MODE_HSYNC: hsync out of range
+ * @MODE_VSYNC: vsync out of range
+ * @MODE_H_ILLEGAL: mode has illegal horizontal timings
+ * @MODE_V_ILLEGAL: mode has illegal horizontal timings
+ * @MODE_BAD_WIDTH: requires an unsupported linepitch
+ * @MODE_NOMODE: no mode with a matching name
+ * @MODE_NO_INTERLACE: interlaced mode not supported
+ * @MODE_NO_DBLESCAN: doublescan mode not supported
+ * @MODE_NO_VSCAN: multiscan mode not supported
+ * @MODE_MEM: insufficient video memory
+ * @MODE_VIRTUAL_X: mode width too large for specified virtual size
+ * @MODE_VIRTUAL_Y: mode height too large for specified virtual size
+ * @MODE_MEM_VIRT: insufficient video memory given virtual size
+ * @MODE_NOCLOCK: no fixed clock available
+ * @MODE_CLOCK_HIGH: clock required is too high
+ * @MODE_CLOCK_LOW: clock required is too low
+ * @MODE_CLOCK_RANGE: clock/mode isn't in a ClockRange
+ * @MODE_BAD_HVALUE: horizontal timing was out of range
+ * @MODE_BAD_VVALUE: vertical timing was out of range
+ * @MODE_BAD_VSCAN: VScan value out of range
+ * @MODE_HSYNC_NARROW: horizontal sync too narrow
+ * @MODE_HSYNC_WIDE: horizontal sync too wide
+ * @MODE_HBLANK_NARROW: horizontal blanking too narrow
+ * @MODE_HBLANK_WIDE: horizontal blanking too wide
+ * @MODE_VSYNC_NARROW: vertical sync too narrow
+ * @MODE_VSYNC_WIDE: vertical sync too wide
+ * @MODE_VBLANK_NARROW: vertical blanking too narrow
+ * @MODE_VBLANK_WIDE: vertical blanking too wide
+ * @MODE_PANEL: exceeds panel dimensions
+ * @MODE_INTERLACE_WIDTH: width too large for interlaced mode
+ * @MODE_ONE_WIDTH: only one width is supported
+ * @MODE_ONE_HEIGHT: only one height is supported
+ * @MODE_ONE_SIZE: only one resolution is supported
+ * @MODE_NO_REDUCED: monitor doesn't accept reduced blanking
+ * @MODE_NO_STEREO: stereo modes not supported
+ * @MODE_STALE: mode has become stale
+ * @MODE_BAD: unspecified reason
+ * @MODE_ERROR: error condition
+ *
+ * This enum is used to filter out modes not supported by the driver/hardware
+ * combination.
+ */
enum drm_mode_status {
- MODE_OK = 0, /* Mode OK */
- MODE_HSYNC, /* hsync out of range */
- MODE_VSYNC, /* vsync out of range */
- MODE_H_ILLEGAL, /* mode has illegal horizontal timings */
- MODE_V_ILLEGAL, /* mode has illegal horizontal timings */
- MODE_BAD_WIDTH, /* requires an unsupported linepitch */
- MODE_NOMODE, /* no mode with a matching name */
- MODE_NO_INTERLACE, /* interlaced mode not supported */
- MODE_NO_DBLESCAN, /* doublescan mode not supported */
- MODE_NO_VSCAN, /* multiscan mode not supported */
- MODE_MEM, /* insufficient video memory */
- MODE_VIRTUAL_X, /* mode width too large for specified virtual size */
- MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */
- MODE_MEM_VIRT, /* insufficient video memory given virtual size */
- MODE_NOCLOCK, /* no fixed clock available */
- MODE_CLOCK_HIGH, /* clock required is too high */
- MODE_CLOCK_LOW, /* clock required is too low */
- MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */
- MODE_BAD_HVALUE, /* horizontal timing was out of range */
- MODE_BAD_VVALUE, /* vertical timing was out of range */
- MODE_BAD_VSCAN, /* VScan value out of range */
- MODE_HSYNC_NARROW, /* horizontal sync too narrow */
- MODE_HSYNC_WIDE, /* horizontal sync too wide */
- MODE_HBLANK_NARROW, /* horizontal blanking too narrow */
- MODE_HBLANK_WIDE, /* horizontal blanking too wide */
- MODE_VSYNC_NARROW, /* vertical sync too narrow */
- MODE_VSYNC_WIDE, /* vertical sync too wide */
- MODE_VBLANK_NARROW, /* vertical blanking too narrow */
- MODE_VBLANK_WIDE, /* vertical blanking too wide */
- MODE_PANEL, /* exceeds panel dimensions */
- MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
- MODE_ONE_WIDTH, /* only one width is supported */
- MODE_ONE_HEIGHT, /* only one height is supported */
- MODE_ONE_SIZE, /* only one resolution is supported */
- MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */
- MODE_NO_STEREO, /* stereo modes not supported */
- MODE_UNVERIFIED = -3, /* mode needs to reverified */
- MODE_BAD = -2, /* unspecified reason */
- MODE_ERROR = -1 /* error condition */
+ MODE_OK = 0,
+ MODE_HSYNC,
+ MODE_VSYNC,
+ MODE_H_ILLEGAL,
+ MODE_V_ILLEGAL,
+ MODE_BAD_WIDTH,
+ MODE_NOMODE,
+ MODE_NO_INTERLACE,
+ MODE_NO_DBLESCAN,
+ MODE_NO_VSCAN,
+ MODE_MEM,
+ MODE_VIRTUAL_X,
+ MODE_VIRTUAL_Y,
+ MODE_MEM_VIRT,
+ MODE_NOCLOCK,
+ MODE_CLOCK_HIGH,
+ MODE_CLOCK_LOW,
+ MODE_CLOCK_RANGE,
+ MODE_BAD_HVALUE,
+ MODE_BAD_VVALUE,
+ MODE_BAD_VSCAN,
+ MODE_HSYNC_NARROW,
+ MODE_HSYNC_WIDE,
+ MODE_HBLANK_NARROW,
+ MODE_HBLANK_WIDE,
+ MODE_VSYNC_NARROW,
+ MODE_VSYNC_WIDE,
+ MODE_VBLANK_NARROW,
+ MODE_VBLANK_WIDE,
+ MODE_PANEL,
+ MODE_INTERLACE_WIDTH,
+ MODE_ONE_WIDTH,
+ MODE_ONE_HEIGHT,
+ MODE_ONE_SIZE,
+ MODE_NO_REDUCED,
+ MODE_NO_STEREO,
+ MODE_STALE = -3,
+ MODE_BAD = -2,
+ MODE_ERROR = -1
};
#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
@@ -96,17 +141,125 @@ enum drm_mode_status {
#define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
+/**
+ * struct drm_display_mode - DRM kernel-internal display mode structure
+ * @hdisplay: horizontal display size
+ * @hsync_start: horizontal sync start
+ * @hsync_end: horizontal sync end
+ * @htotal: horizontal total size
+ * @hskew: horizontal skew?!
+ * @vdisplay: vertical display size
+ * @vsync_start: vertical sync start
+ * @vsync_end: vertical sync end
+ * @vtotal: vertical total size
+ * @vscan: vertical scan?!
+ * @crtc_hdisplay: hardware mode horizontal display size
+ * @crtc_hblank_start: hardware mode horizontal blank start
+ * @crtc_hblank_end: hardware mode horizontal blank end
+ * @crtc_hsync_start: hardware mode horizontal sync start
+ * @crtc_hsync_end: hardware mode horizontal sync end
+ * @crtc_htotal: hardware mode horizontal total size
+ * @crtc_hskew: hardware mode horizontal skew?!
+ * @crtc_vdisplay: hardware mode vertical display size
+ * @crtc_vblank_start: hardware mode vertical blank start
+ * @crtc_vblank_end: hardware mode vertical blank end
+ * @crtc_vsync_start: hardware mode vertical sync start
+ * @crtc_vsync_end: hardware mode vertical sync end
+ * @crtc_vtotal: hardware mode vertical total size
+ *
+ * The horizontal and vertical timings are defined per the following diagram.
+ *
+ *
+ * Active Front Sync Back
+ * Region Porch Porch
+ * <-----------------------><----------------><-------------><-------------->
+ * //////////////////////|
+ * ////////////////////// |
+ * ////////////////////// |.................. ................
+ * _______________
+ * <----- [hv]display ----->
+ * <------------- [hv]sync_start ------------>
+ * <--------------------- [hv]sync_end --------------------->
+ * <-------------------------------- [hv]total ----------------------------->*
+ *
+ * This structure contains two copies of timings. First are the plain timings,
+ * which specify the logical mode, as it would be for a progressive 1:1 scanout
+ * at the refresh rate userspace can observe through vblank timestamps. Then
+ * there's the hardware timings, which are corrected for interlacing,
+ * double-clocking and similar things. They are provided as a convenience, and
+ * can be appropriately computed using drm_mode_set_crtcinfo().
+ */
struct drm_display_mode {
- /* Header */
+ /**
+ * @head:
+ *
+ * struct list_head for mode lists.
+ */
struct list_head head;
+
+ /**
+ * @base:
+ *
+ * A display mode is a normal modeset object, possibly including public
+ * userspace id.
+ *
+ * FIXME:
+ *
+ * This can probably be removed since the entire concept of userspace
+ * managing modes explicitly has never landed in upstream kernel mode
+ * setting support.
+ */
struct drm_mode_object base;
+ /**
+ * @name:
+ *
+ * Human-readable name of the mode, filled out with drm_mode_set_name().
+ */
char name[DRM_DISPLAY_MODE_LEN];
+ /**
+ * @status:
+ *
+ * Status of the mode, used to filter out modes not supported by the
+ * hardware. See enum &drm_mode_status.
+ */
enum drm_mode_status status;
+
+ /**
+ * @type:
+ *
+ * A bitmask of flags, mostly about the source of a mode. Possible flags
+ * are:
+ *
+ * - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, effectively
+ * unused.
+ * - DRM_MODE_TYPE_PREFERRED: Preferred mode, usually the native
+ * resolution of an LCD panel. There should only be one preferred
+ * mode per connector at any given time.
+ * - DRM_MODE_TYPE_DRIVER: Mode created by the driver, which is all of
+ * them really. Drivers must set this bit for all modes they create
+ * and expose to userspace.
+ *
+ * Plus a big list of flags which shouldn't be used at all, but are
+ * still around since these flags are also used in the userspace ABI:
+ *
+ * - DRM_MODE_TYPE_DEFAULT: Again a leftover, use
+ * DRM_MODE_TYPE_PREFERRED instead.
+ * - DRM_MODE_TYPE_CLOCK_C and DRM_MODE_TYPE_CRTC_C: Define leftovers
+ * which are stuck around for hysterical raisins only. No one has an
+ * idea what they were meant for. Don't use.
+ * - DRM_MODE_TYPE_USERDEF: Mode defined by userspace, again a vestige
+ * from older kms designs where userspace had to first add a custom
+ * mode to the kernel's mode list before it could use it. Don't use.
+ */
unsigned int type;
- /* Proposed mode values */
+ /**
+ * @clock:
+ *
+ * Pixel clock in kHz.
+ */
int clock; /* in kHz */
int hdisplay;
int hsync_start;
@@ -118,14 +271,74 @@ struct drm_display_mode {
int vsync_end;
int vtotal;
int vscan;
+ /**
+ * @flags:
+ *
+ * Sync and timing flags:
+ *
+ * - DRM_MODE_FLAG_PHSYNC: horizontal sync is active high.
+ * - DRM_MODE_FLAG_NHSYNC: horizontal sync is active low.
+ * - DRM_MODE_FLAG_PVSYNC: vertical sync is active high.
+ * - DRM_MODE_FLAG_NVSYNC: vertical sync is active low.
+ * - DRM_MODE_FLAG_INTERLACE: mode is interlaced.
+ * - DRM_MODE_FLAG_DBLSCAN: mode uses doublescan.
+ * - DRM_MODE_FLAG_CSYNC: mode uses composite sync.
+ * - DRM_MODE_FLAG_PCSYNC: composite sync is active high.
+ * - DRM_MODE_FLAG_NCSYNC: composite sync is active low.
+ * - DRM_MODE_FLAG_HSKEW: hskew provided (not used?).
+ * - DRM_MODE_FLAG_BCAST: not used?
+ * - DRM_MODE_FLAG_PIXMUX: not used?
+ * - DRM_MODE_FLAG_DBLCLK: double-clocked mode.
+ * - DRM_MODE_FLAG_CLKDIV2: half-clocked mode.
+ *
+ * Additionally there's flags to specify how 3D modes are packed:
+ *
+ * - DRM_MODE_FLAG_3D_NONE: normal, non-3D mode.
+ * - DRM_MODE_FLAG_3D_FRAME_PACKING: 2 full frames for left and right.
+ * - DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: interleaved like fields.
+ * - DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: interleaved lines.
+ * - DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: side-by-side full frames.
+ * - DRM_MODE_FLAG_3D_L_DEPTH: ?
+ * - DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: ?
+ * - DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: frame split into top and bottom
+ * parts.
+ * - DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: frame split into left and
+ * right parts.
+ */
unsigned int flags;
- /* Addressable image size (may be 0 for projectors, etc.) */
+ /**
+ * @width_mm:
+ *
+ * Addressable size of the output in mm, projectors should set this to
+ * 0.
+ */
int width_mm;
+
+ /**
+ * @height_mm:
+ *
+ * Addressable size of the output in mm, projectors should set this to
+ * 0.
+ */
int height_mm;
- /* Actual mode we give to hw */
- int crtc_clock; /* in KHz */
+ /**
+ * @crtc_clock:
+ *
+ * Actual pixel or dot clock in the hardware. This differs from the
+ * logical @clock when e.g. using interlacing, double-clocking, stereo
+ * modes or other fancy stuff that changes the timings and signals
+ * actually sent over the wire.
+ *
+ * This is again in kHz.
+ *
+ * Note that with digital outputs like HDMI or DP there's usually a
+ * massive confusion between the dot clock and the signal clock at the
+ * bit encoding level. Especially when a 8b/10b encoding is used and the
+ * difference is exactly a factor of 10.
+ */
+ int crtc_clock;
int crtc_hdisplay;
int crtc_hblank_start;
int crtc_hblank_end;
@@ -140,12 +353,48 @@ struct drm_display_mode {
int crtc_vsync_end;
int crtc_vtotal;
- /* Driver private mode info */
+ /**
+ * @private:
+ *
+ * Pointer for driver private data. This can only be used for mode
+ * objects passed to drivers in modeset operations. It shouldn't be used
+ * by atomic drivers since they can store any additional data by
+ * subclassing state structures.
+ */
int *private;
+
+ /**
+ * @private_flags:
+ *
+ * Similar to @private, but just an integer.
+ */
int private_flags;
- int vrefresh; /* in Hz */
- int hsync; /* in kHz */
+ /**
+ * @vrefresh:
+ *
+ * Vertical refresh rate, for debug output in human readable form. Not
+ * used in a functional way.
+ *
+ * This value is in Hz.
+ */
+ int vrefresh;
+
+ /**
+ * @hsync:
+ *
+ * Horizontal refresh rate, for debug output in human readable form. Not
+ * used in a functional way.
+ *
+ * This value is in kHz.
+ */
+ int hsync;
+
+ /**
+ * @picture_aspect_ratio:
+ *
+ * Field for setting the HDMI picture aspect ratio of a mode.
+ */
enum hdmi_picture_aspect picture_aspect_ratio;
};
@@ -222,6 +471,8 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
const struct drm_display_mode *mode);
bool drm_mode_equal(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2);
+bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
+ const struct drm_display_mode *mode2);
bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
const struct drm_display_mode *mode2);
@@ -232,7 +483,7 @@ enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode,
void drm_mode_prune_invalid(struct drm_device *dev,
struct list_head *mode_list, bool verbose);
void drm_mode_sort(struct list_head *mode_list);
-void drm_mode_connector_list_update(struct drm_connector *connector, bool merge_type_bits);
+void drm_mode_connector_list_update(struct drm_connector *connector);
/* parsing cmdline modes */
bool
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
new file mode 100644
index 000000000000..a126a0d7aed4
--- /dev/null
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -0,0 +1,928 @@
+/*
+ * Copyright © 2006 Keith Packard
+ * Copyright © 2007-2008 Dave Airlie
+ * Copyright © 2007-2008 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright © 2011-2013 Intel Corporation
+ * Copyright © 2015 Intel Corporation
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * 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 __DRM_MODESET_HELPER_VTABLES_H__
+#define __DRM_MODESET_HELPER_VTABLES_H__
+
+#include <drm/drm_crtc.h>
+
+/**
+ * DOC: overview
+ *
+ * The DRM mode setting helper functions are common code for drivers to use if
+ * they wish. Drivers are not forced to use this code in their
+ * implementations but it would be useful if the code they do use at least
+ * provides a consistent interface and operation to userspace. Therefore it is
+ * highly recommended to use the provided helpers as much as possible.
+ *
+ * Because there is only one pointer per modeset object to hold a vfunc table
+ * for helper libraries they are by necessity shared among the different
+ * helpers.
+ *
+ * To make this clear all the helper vtables are pulled together in this location here.
+ */
+
+enum mode_set_atomic;
+
+/**
+ * struct drm_crtc_helper_funcs - helper operations for CRTCs
+ *
+ * These hooks are used by the legacy CRTC helpers, the transitional plane
+ * helpers and the new atomic modesetting helpers.
+ */
+struct drm_crtc_helper_funcs {
+ /**
+ * @dpms:
+ *
+ * Callback to control power levels on the CRTC. If the mode passed in
+ * is unsupported, the provider must use the next lowest power level.
+ * This is used by the legacy CRTC helpers to implement DPMS
+ * functionality in drm_helper_connector_dpms().
+ *
+ * This callback is also used to disable a CRTC by calling it with
+ * DRM_MODE_DPMS_OFF if the @disable hook isn't used.
+ *
+ * This callback is used by the legacy CRTC helpers. Atomic helpers
+ * also support using this hook for enabling and disabling a CRTC to
+ * facilitate transitions to atomic, but it is deprecated. Instead
+ * @enable and @disable should be used.
+ */
+ void (*dpms)(struct drm_crtc *crtc, int mode);
+
+ /**
+ * @prepare:
+ *
+ * This callback should prepare the CRTC for a subsequent modeset, which
+ * in practice means the driver should disable the CRTC if it is
+ * running. Most drivers ended up implementing this by calling their
+ * @dpms hook with DRM_MODE_DPMS_OFF.
+ *
+ * This callback is used by the legacy CRTC helpers. Atomic helpers
+ * also support using this hook for disabling a CRTC to facilitate
+ * transitions to atomic, but it is deprecated. Instead @disable should
+ * be used.
+ */
+ void (*prepare)(struct drm_crtc *crtc);
+
+ /**
+ * @commit:
+ *
+ * This callback should commit the new mode on the CRTC after a modeset,
+ * which in practice means the driver should enable the CRTC. Most
+ * drivers ended up implementing this by calling their @dpms hook with
+ * DRM_MODE_DPMS_ON.
+ *
+ * This callback is used by the legacy CRTC helpers. Atomic helpers
+ * also support using this hook for enabling a CRTC to facilitate
+ * transitions to atomic, but it is deprecated. Instead @enable should
+ * be used.
+ */
+ void (*commit)(struct drm_crtc *crtc);
+
+ /**
+ * @mode_fixup:
+ *
+ * This callback is used to validate a mode. The parameter mode is the
+ * display mode that userspace requested, adjusted_mode is the mode the
+ * encoders need to be fed with. Note that this is the inverse semantics
+ * of the meaning for the &drm_encoder and &drm_bridge
+ * ->mode_fixup() functions. If the CRTC cannot support the requested
+ * conversion from mode to adjusted_mode it should reject the modeset.
+ *
+ * This function is used by both legacy CRTC helpers and atomic helpers.
+ * With atomic helpers it is optional.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of atomic modesets, which
+ * can be aborted for any reason (including on userspace's request to
+ * just check whether a configuration would be possible). Atomic drivers
+ * MUST NOT touch any persistent state (hardware or software) or data
+ * structures except the passed in adjusted_mode parameter.
+ *
+ * This is in contrast to the legacy CRTC helpers where this was
+ * allowed.
+ *
+ * Atomic drivers which need to inspect and adjust more state should
+ * instead use the @atomic_check callback.
+ *
+ * Also beware that neither core nor helpers filter modes before
+ * passing them to the driver: While the list of modes that is
+ * advertised to userspace is filtered using the connector's
+ * ->mode_valid() callback, neither the core nor the helpers do any
+ * filtering on modes passed in from userspace when setting a mode. It
+ * is therefore possible for userspace to pass in a mode that was
+ * previously filtered out using ->mode_valid() or add a custom mode
+ * that wasn't probed from EDID or similar to begin with. Even though
+ * this is an advanced feature and rarely used nowadays, some users rely
+ * on being able to specify modes manually so drivers must be prepared
+ * to deal with it. Specifically this means that all drivers need not
+ * only validate modes in ->mode_valid() but also in ->mode_fixup() to
+ * make sure invalid modes passed in from userspace are rejected.
+ *
+ * RETURNS:
+ *
+ * True if an acceptable configuration is possible, false if the modeset
+ * operation should be rejected.
+ */
+ bool (*mode_fixup)(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+
+ /**
+ * @mode_set:
+ *
+ * This callback is used by the legacy CRTC helpers to set a new mode,
+ * position and framebuffer. Since it ties the primary plane to every
+ * mode change it is incompatible with universal plane support. And
+ * since it can't update other planes it's incompatible with atomic
+ * modeset support.
+ *
+ * This callback is only used by CRTC helpers and deprecated.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
+ int (*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);
+
+ /**
+ * @mode_set_nofb:
+ *
+ * This callback is used to update the display mode of a CRTC without
+ * changing anything of the primary plane configuration. This fits the
+ * requirement of atomic and hence is used by the atomic helpers. It is
+ * also used by the transitional plane helpers to implement a
+ * @mode_set hook in drm_helper_crtc_mode_set().
+ *
+ * Note that the display pipe is completely off when this function is
+ * called. Atomic drivers which need hardware to be running before they
+ * program the new display mode (e.g. because they implement runtime PM)
+ * should not use this hook. This is because the helper library calls
+ * this hook only once per mode change and not every time the display
+ * pipeline is suspended using either DPMS or the new "ACTIVE" property.
+ * Which means register values set in this callback might get reset when
+ * the CRTC is suspended, but not restored. Such drivers should instead
+ * move all their CRTC setup into the @enable callback.
+ *
+ * This callback is optional.
+ */
+ void (*mode_set_nofb)(struct drm_crtc *crtc);
+
+ /**
+ * @mode_set_base:
+ *
+ * This callback is used by the legacy CRTC helpers to set a new
+ * framebuffer and scanout position. It is optional and used as an
+ * optimized fast-path instead of a full mode set operation with all the
+ * resulting flickering. If it is not present
+ * drm_crtc_helper_set_config() will fall back to a full modeset, using
+ * the ->mode_set() callback. Since it can't update other planes it's
+ * incompatible with atomic modeset support.
+ *
+ * This callback is only used by the CRTC helpers and deprecated.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
+ int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb);
+
+ /**
+ * @mode_set_base_atomic:
+ *
+ * This callback is used by the fbdev helpers to set a new framebuffer
+ * and scanout without sleeping, i.e. from an atomic calling context. It
+ * is only used to implement kgdb support.
+ *
+ * This callback is optional and only needed for kgdb support in the fbdev
+ * helpers.
+ *
+ * RETURNS:
+ *
+ * 0 on success or a negative error code on failure.
+ */
+ int (*mode_set_base_atomic)(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int x, int y,
+ enum mode_set_atomic);
+
+ /**
+ * @load_lut:
+ *
+ * Load a LUT prepared with the @gamma_set functions from
+ * &drm_fb_helper_funcs.
+ *
+ * This callback is optional and is only used by the fbdev emulation
+ * helpers.
+ *
+ * FIXME:
+ *
+ * This callback is functionally redundant with the core gamma table
+ * support and simply exists because the fbdev hasn't yet been
+ * refactored to use the core gamma table interfaces.
+ */
+ void (*load_lut)(struct drm_crtc *crtc);
+
+ /**
+ * @disable:
+ *
+ * This callback should be used to disable the CRTC. With the atomic
+ * drivers it is called after all encoders connected to this CRTC have
+ * been shut off already using their own ->disable hook. If that
+ * sequence is too simple drivers can just add their own hooks and call
+ * it from this CRTC callback here by looping over all encoders
+ * connected to it using for_each_encoder_on_crtc().
+ *
+ * This hook is used both by legacy CRTC helpers and atomic helpers.
+ * Atomic drivers don't need to implement it if there's no need to
+ * disable anything at the CRTC level. To ensure that runtime PM
+ * handling (using either DPMS or the new "ACTIVE" property) works
+ * @disable must be the inverse of @enable for atomic drivers.
+ *
+ * NOTE:
+ *
+ * With legacy CRTC helpers there's a big semantic difference between
+ * @disable and other hooks (like @prepare or @dpms) used to shut down a
+ * CRTC: @disable is only called when also logically disabling the
+ * display pipeline and needs to release any resources acquired in
+ * @mode_set (like shared PLLs, or again release pinned framebuffers).
+ *
+ * Therefore @disable must be the inverse of @mode_set plus @commit for
+ * drivers still using legacy CRTC helpers, which is different from the
+ * rules under atomic.
+ */
+ void (*disable)(struct drm_crtc *crtc);
+
+ /**
+ * @enable:
+ *
+ * This callback should be used to enable the CRTC. With the atomic
+ * drivers it is called before all encoders connected to this CRTC are
+ * enabled through the encoder's own ->enable hook. If that sequence is
+ * too simple drivers can just add their own hooks and call it from this
+ * CRTC callback here by looping over all encoders connected to it using
+ * for_each_encoder_on_crtc().
+ *
+ * This hook is used only by atomic helpers, for symmetry with @disable.
+ * Atomic drivers don't need to implement it if there's no need to
+ * enable anything at the CRTC level. To ensure that runtime PM handling
+ * (using either DPMS or the new "ACTIVE" property) works
+ * @enable must be the inverse of @disable for atomic drivers.
+ */
+ void (*enable)(struct drm_crtc *crtc);
+
+ /**
+ * @atomic_check:
+ *
+ * Drivers should check plane-update related CRTC constraints in this
+ * hook. They can also check mode related limitations but need to be
+ * aware of the calling order, since this hook is used by
+ * drm_atomic_helper_check_planes() whereas the preparations needed to
+ * check output routing and the display mode is done in
+ * drm_atomic_helper_check_modeset(). Therefore drivers that want to
+ * check output routing and display mode constraints in this callback
+ * must ensure that drm_atomic_helper_check_modeset() has been called
+ * beforehand. This is calling order used by the default helper
+ * implementation in drm_atomic_helper_check().
+ *
+ * When using drm_atomic_helper_check_planes() CRTCs' ->atomic_check()
+ * hooks are called after the ones for planes, which allows drivers to
+ * assign shared resources requested by planes in the CRTC callback
+ * here. For more complicated dependencies the driver can call the provided
+ * check helpers multiple times until the computed state has a final
+ * configuration and everything has been checked.
+ *
+ * This function is also allowed to inspect any other object's state and
+ * can add more state objects to the atomic commit if needed. Care must
+ * be taken though to ensure that state check&compute functions for
+ * these added states are all called, and derived state in other objects
+ * all updated. Again the recommendation is to just call check helpers
+ * until a maximal configuration is reached.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of an atomic update. The
+ * driver is not allowed to change anything outside of the free-standing
+ * state objects passed-in or assembled in the overall &drm_atomic_state
+ * update tracking structure.
+ *
+ * RETURNS:
+ *
+ * 0 on success, -EINVAL if the state or the transition can't be
+ * supported, -ENOMEM on memory allocation failure and -EDEADLK if an
+ * attempt to obtain another state object ran into a &drm_modeset_lock
+ * deadlock.
+ */
+ int (*atomic_check)(struct drm_crtc *crtc,
+ struct drm_crtc_state *state);
+
+ /**
+ * @atomic_begin:
+ *
+ * Drivers should prepare for an atomic update of multiple planes on
+ * a CRTC in this hook. Depending upon hardware this might be vblank
+ * evasion, blocking updates by setting bits or doing preparatory work
+ * for e.g. manual update display.
+ *
+ * This hook is called before any plane commit functions are called.
+ *
+ * Note that the power state of the display pipe when this function is
+ * called depends upon the exact helpers and calling sequence the driver
+ * has picked. See drm_atomic_commit_planes() for a discussion of the
+ * tradeoffs and variants of plane commit helpers.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ */
+ void (*atomic_begin)(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state);
+ /**
+ * @atomic_flush:
+ *
+ * Drivers should finalize an atomic update of multiple planes on
+ * a CRTC in this hook. Depending upon hardware this might include
+ * checking that vblank evasion was successful, unblocking updates by
+ * setting bits or setting the GO bit to flush out all updates.
+ *
+ * Simple hardware or hardware with special requirements can commit and
+ * flush out all updates for all planes from this hook and forgo all the
+ * other commit hooks for plane updates.
+ *
+ * This hook is called after any plane commit functions are called.
+ *
+ * Note that the power state of the display pipe when this function is
+ * called depends upon the exact helpers and calling sequence the driver
+ * has picked. See drm_atomic_commit_planes() for a discussion of the
+ * tradeoffs and variants of plane commit helpers.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ */
+ void (*atomic_flush)(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state);
+};
+
+/**
+ * drm_crtc_helper_add - sets the helper vtable for a crtc
+ * @crtc: DRM CRTC
+ * @funcs: helper vtable to set for @crtc
+ */
+static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
+ const struct drm_crtc_helper_funcs *funcs)
+{
+ crtc->helper_private = funcs;
+}
+
+/**
+ * struct drm_encoder_helper_funcs - helper operations for encoders
+ *
+ * These hooks are used by the legacy CRTC helpers, the transitional plane
+ * helpers and the new atomic modesetting helpers.
+ */
+struct drm_encoder_helper_funcs {
+ /**
+ * @dpms:
+ *
+ * Callback to control power levels on the encoder. If the mode passed in
+ * is unsupported, the provider must use the next lowest power level.
+ * This is used by the legacy encoder helpers to implement DPMS
+ * functionality in drm_helper_connector_dpms().
+ *
+ * This callback is also used to disable an encoder by calling it with
+ * DRM_MODE_DPMS_OFF if the @disable hook isn't used.
+ *
+ * This callback is used by the legacy CRTC helpers. Atomic helpers
+ * also support using this hook for enabling and disabling an encoder to
+ * facilitate transitions to atomic, but it is deprecated. Instead
+ * @enable and @disable should be used.
+ */
+ void (*dpms)(struct drm_encoder *encoder, int mode);
+
+ /**
+ * @mode_fixup:
+ *
+ * This callback is used to validate and adjust a mode. The parameter
+ * mode is the display mode that should be fed to the next element in
+ * the display chain, either the final &drm_connector or a &drm_bridge.
+ * The parameter adjusted_mode is the input mode the encoder requires. It
+ * can be modified by this callback and does not need to match mode.
+ *
+ * This function is used by both legacy CRTC helpers and atomic helpers.
+ * With atomic helpers it is optional.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of atomic modesets, which
+ * can be aborted for any reason (including on userspace's request to
+ * just check whether a configuration would be possible). Atomic drivers
+ * MUST NOT touch any persistent state (hardware or software) or data
+ * structures except the passed in adjusted_mode parameter.
+ *
+ * This is in contrast to the legacy CRTC helpers where this was
+ * allowed.
+ *
+ * Atomic drivers which need to inspect and adjust more state should
+ * instead use the @atomic_check callback.
+ *
+ * Also beware that neither core nor helpers filter modes before
+ * passing them to the driver: While the list of modes that is
+ * advertised to userspace is filtered using the connector's
+ * ->mode_valid() callback, neither the core nor the helpers do any
+ * filtering on modes passed in from userspace when setting a mode. It
+ * is therefore possible for userspace to pass in a mode that was
+ * previously filtered out using ->mode_valid() or add a custom mode
+ * that wasn't probed from EDID or similar to begin with. Even though
+ * this is an advanced feature and rarely used nowadays, some users rely
+ * on being able to specify modes manually so drivers must be prepared
+ * to deal with it. Specifically this means that all drivers need not
+ * only validate modes in ->mode_valid() but also in ->mode_fixup() to
+ * make sure invalid modes passed in from userspace are rejected.
+ *
+ * RETURNS:
+ *
+ * True if an acceptable configuration is possible, false if the modeset
+ * operation should be rejected.
+ */
+ bool (*mode_fixup)(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+
+ /**
+ * @prepare:
+ *
+ * This callback should prepare the encoder for a subsequent modeset,
+ * which in practice means the driver should disable the encoder if it
+ * is running. Most drivers ended up implementing this by calling their
+ * @dpms hook with DRM_MODE_DPMS_OFF.
+ *
+ * This callback is used by the legacy CRTC helpers. Atomic helpers
+ * also support using this hook for disabling an encoder to facilitate
+ * transitions to atomic, but it is deprecated. Instead @disable should
+ * be used.
+ */
+ void (*prepare)(struct drm_encoder *encoder);
+
+ /**
+ * @commit:
+ *
+ * This callback should commit the new mode on the encoder after a modeset,
+ * which in practice means the driver should enable the encoder. Most
+ * drivers ended up implementing this by calling their @dpms hook with
+ * DRM_MODE_DPMS_ON.
+ *
+ * This callback is used by the legacy CRTC helpers. Atomic helpers
+ * also support using this hook for enabling an encoder to facilitate
+ * transitions to atomic, but it is deprecated. Instead @enable should
+ * be used.
+ */
+ void (*commit)(struct drm_encoder *encoder);
+
+ /**
+ * @mode_set:
+ *
+ * This callback is used to update the display mode of an encoder.
+ *
+ * Note that the display pipe is completely off when this function is
+ * called. Drivers which need hardware to be running before they program
+ * the new display mode (because they implement runtime PM) should not
+ * use this hook, because the helper library calls it only once and not
+ * every time the display pipeline is suspend using either DPMS or the
+ * new "ACTIVE" property. Such drivers should instead move all their
+ * encoder setup into the ->enable() callback.
+ *
+ * This callback is used both by the legacy CRTC helpers and the atomic
+ * modeset helpers. It is optional in the atomic helpers.
+ */
+ void (*mode_set)(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+
+ /**
+ * @get_crtc:
+ *
+ * This callback is used by the legacy CRTC helpers to work around
+ * deficiencies in its own book-keeping.
+ *
+ * Do not use, use atomic helpers instead, which get the book keeping
+ * right.
+ *
+ * FIXME:
+ *
+ * Currently only nouveau is using this, and as soon as nouveau is
+ * atomic we can ditch this hook.
+ */
+ struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder);
+
+ /**
+ * @detect:
+ *
+ * This callback can be used by drivers who want to do detection on the
+ * encoder object instead of in connector functions.
+ *
+ * It is not used by any helper and therefore has purely driver-specific
+ * semantics. New drivers shouldn't use this and instead just implement
+ * their own private callbacks.
+ *
+ * FIXME:
+ *
+ * This should just be converted into a pile of driver vfuncs.
+ * Currently radeon, amdgpu and nouveau are using it.
+ */
+ enum drm_connector_status (*detect)(struct drm_encoder *encoder,
+ struct drm_connector *connector);
+
+ /**
+ * @disable:
+ *
+ * This callback should be used to disable the encoder. With the atomic
+ * drivers it is called before this encoder's CRTC has been shut off
+ * using the CRTC's own ->disable hook. If that sequence is too simple
+ * drivers can just add their own driver private encoder hooks and call
+ * them from CRTC's callback by looping over all encoders connected to
+ * it using for_each_encoder_on_crtc().
+ *
+ * This hook is used both by legacy CRTC helpers and atomic helpers.
+ * Atomic drivers don't need to implement it if there's no need to
+ * disable anything at the encoder level. To ensure that runtime PM
+ * handling (using either DPMS or the new "ACTIVE" property) works
+ * @disable must be the inverse of @enable for atomic drivers.
+ *
+ * NOTE:
+ *
+ * With legacy CRTC helpers there's a big semantic difference between
+ * @disable and other hooks (like @prepare or @dpms) used to shut down a
+ * encoder: @disable is only called when also logically disabling the
+ * display pipeline and needs to release any resources acquired in
+ * @mode_set (like shared PLLs, or again release pinned framebuffers).
+ *
+ * Therefore @disable must be the inverse of @mode_set plus @commit for
+ * drivers still using legacy CRTC helpers, which is different from the
+ * rules under atomic.
+ */
+ void (*disable)(struct drm_encoder *encoder);
+
+ /**
+ * @enable:
+ *
+ * This callback should be used to enable the encoder. With the atomic
+ * drivers it is called after this encoder's CRTC has been enabled using
+ * the CRTC's own ->enable hook. If that sequence is too simple drivers
+ * can just add their own driver private encoder hooks and call them
+ * from CRTC's callback by looping over all encoders connected to it
+ * using for_each_encoder_on_crtc().
+ *
+ * This hook is used only by atomic helpers, for symmetry with @disable.
+ * Atomic drivers don't need to implement it if there's no need to
+ * enable anything at the encoder level. To ensure that runtime PM handling
+ * (using either DPMS or the new "ACTIVE" property) works
+ * @enable must be the inverse of @disable for atomic drivers.
+ */
+ void (*enable)(struct drm_encoder *encoder);
+
+ /**
+ * @atomic_check:
+ *
+ * This callback is used to validate encoder state for atomic drivers.
+ * Since the encoder is the object connecting the CRTC and connector it
+ * gets passed both states, to be able to validate interactions and
+ * update the CRTC to match what the encoder needs for the requested
+ * connector.
+ *
+ * This function is used by the atomic helpers, but it is optional.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of an atomic update. The
+ * driver is not allowed to change anything outside of the free-standing
+ * state objects passed-in or assembled in the overall &drm_atomic_state
+ * update tracking structure.
+ *
+ * RETURNS:
+ *
+ * 0 on success, -EINVAL if the state or the transition can't be
+ * supported, -ENOMEM on memory allocation failure and -EDEADLK if an
+ * attempt to obtain another state object ran into a &drm_modeset_lock
+ * deadlock.
+ */
+ int (*atomic_check)(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state);
+};
+
+/**
+ * drm_encoder_helper_add - sets the helper vtable for an encoder
+ * @encoder: DRM encoder
+ * @funcs: helper vtable to set for @encoder
+ */
+static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
+ const struct drm_encoder_helper_funcs *funcs)
+{
+ encoder->helper_private = funcs;
+}
+
+/**
+ * struct drm_connector_helper_funcs - helper operations for connectors
+ *
+ * These functions are used by the atomic and legacy modeset helpers and by the
+ * probe helpers.
+ */
+struct drm_connector_helper_funcs {
+ /**
+ * @get_modes:
+ *
+ * This function should fill in all modes currently valid for the sink
+ * into the connector->probed_modes list. It should also update the
+ * EDID property by calling drm_mode_connector_update_edid_property().
+ *
+ * The usual way to implement this is to cache the EDID retrieved in the
+ * probe callback somewhere in the driver-private connector structure.
+ * In this function drivers then parse the modes in the EDID and add
+ * them by calling drm_add_edid_modes(). But connectors that driver a
+ * fixed panel can also manually add specific modes using
+ * drm_mode_probed_add(). Drivers which manually add modes should also
+ * make sure that the @display_info, @width_mm and @height_mm fields of the
+ * struct #drm_connector are filled in.
+ *
+ * Virtual drivers that just want some standard VESA mode with a given
+ * resolution can call drm_add_modes_noedid(), and mark the preferred
+ * one using drm_set_preferred_mode().
+ *
+ * Finally drivers that support audio probably want to update the ELD
+ * data, too, using drm_edid_to_eld().
+ *
+ * This function is only called after the ->detect() hook has indicated
+ * that a sink is connected and when the EDID isn't overridden through
+ * sysfs or the kernel commandline.
+ *
+ * This callback is used by the probe helpers in e.g.
+ * drm_helper_probe_single_connector_modes().
+ *
+ * RETURNS:
+ *
+ * The number of modes added by calling drm_mode_probed_add().
+ */
+ int (*get_modes)(struct drm_connector *connector);
+
+ /**
+ * @mode_valid:
+ *
+ * Callback to validate a mode for a connector, irrespective of the
+ * specific display configuration.
+ *
+ * This callback is used by the probe helpers to filter the mode list
+ * (which is usually derived from the EDID data block from the sink).
+ * See e.g. drm_helper_probe_single_connector_modes().
+ *
+ * NOTE:
+ *
+ * This only filters the mode list supplied to userspace in the
+ * GETCONNECOTR IOCTL. Userspace is free to create modes of its own and
+ * ask the kernel to use them. It this case the atomic helpers or legacy
+ * CRTC helpers will not call this function. Drivers therefore must
+ * still fully validate any mode passed in in a modeset request.
+ *
+ * RETURNS:
+ *
+ * Either MODE_OK or one of the failure reasons in enum
+ * &drm_mode_status.
+ */
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ /**
+ * @best_encoder:
+ *
+ * This function should select the best encoder for the given connector.
+ *
+ * This function is used by both the atomic helpers (in the
+ * drm_atomic_helper_check_modeset() function) and in the legacy CRTC
+ * helpers.
+ *
+ * NOTE:
+ *
+ * In atomic drivers this function is called in the check phase of an
+ * atomic update. The driver is not allowed to change or inspect
+ * anything outside of arguments passed-in. Atomic drivers which need to
+ * inspect dynamic configuration state should instead use
+ * @atomic_best_encoder.
+ *
+ * RETURNS:
+ *
+ * Encoder that should be used for the given connector and connector
+ * state, or NULL if no suitable encoder exists. Note that the helpers
+ * will ensure that encoders aren't used twice, drivers should not check
+ * for this.
+ */
+ struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
+
+ /**
+ * @atomic_best_encoder:
+ *
+ * This is the atomic version of @best_encoder for atomic drivers which
+ * need to select the best encoder depending upon the desired
+ * configuration and can't select it statically.
+ *
+ * This function is used by drm_atomic_helper_check_modeset() and either
+ * this or @best_encoder is required.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of an atomic update. The
+ * driver is not allowed to change anything outside of the free-standing
+ * state objects passed-in or assembled in the overall &drm_atomic_state
+ * update tracking structure.
+ *
+ * RETURNS:
+ *
+ * Encoder that should be used for the given connector and connector
+ * state, or NULL if no suitable encoder exists. Note that the helpers
+ * will ensure that encoders aren't used twice, drivers should not check
+ * for this.
+ */
+ struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
+ struct drm_connector_state *connector_state);
+};
+
+/**
+ * drm_connector_helper_add - sets the helper vtable for a connector
+ * @connector: DRM connector
+ * @funcs: helper vtable to set for @connector
+ */
+static inline void drm_connector_helper_add(struct drm_connector *connector,
+ const struct drm_connector_helper_funcs *funcs)
+{
+ connector->helper_private = funcs;
+}
+
+/**
+ * struct drm_plane_helper_funcs - helper operations for planes
+ *
+ * These functions are used by the atomic helpers and by the transitional plane
+ * helpers.
+ */
+struct drm_plane_helper_funcs {
+ /**
+ * @prepare_fb:
+ *
+ * This hook is to prepare a framebuffer for scanout by e.g. pinning
+ * it's backing storage or relocating it into a contiguous block of
+ * VRAM. Other possible preparatory work includes flushing caches.
+ *
+ * This function must not block for outstanding rendering, since it is
+ * called in the context of the atomic IOCTL even for async commits to
+ * be able to return any errors to userspace. Instead the recommended
+ * way is to fill out the fence member of the passed-in
+ * &drm_plane_state. If the driver doesn't support native fences then
+ * equivalent functionality should be implemented through private
+ * members in the plane structure.
+ *
+ * The helpers will call @cleanup_fb with matching arguments for every
+ * successful call to this hook.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ *
+ * RETURNS:
+ *
+ * 0 on success or one of the following negative error codes allowed by
+ * the atomic_commit hook in &drm_mode_config_funcs. When using helpers
+ * this callback is the only one which can fail an atomic commit,
+ * everything else must complete successfully.
+ */
+ int (*prepare_fb)(struct drm_plane *plane,
+ const struct drm_plane_state *new_state);
+ /**
+ * @cleanup_fb:
+ *
+ * This hook is called to clean up any resources allocated for the given
+ * framebuffer and plane configuration in @prepare_fb.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ */
+ void (*cleanup_fb)(struct drm_plane *plane,
+ const struct drm_plane_state *old_state);
+
+ /**
+ * @atomic_check:
+ *
+ * Drivers should check plane specific constraints in this hook.
+ *
+ * When using drm_atomic_helper_check_planes() plane's ->atomic_check()
+ * hooks are called before the ones for CRTCs, which allows drivers to
+ * request shared resources that the CRTC controls here. For more
+ * complicated dependencies the driver can call the provided check helpers
+ * multiple times until the computed state has a final configuration and
+ * everything has been checked.
+ *
+ * This function is also allowed to inspect any other object's state and
+ * can add more state objects to the atomic commit if needed. Care must
+ * be taken though to ensure that state check&compute functions for
+ * these added states are all called, and derived state in other objects
+ * all updated. Again the recommendation is to just call check helpers
+ * until a maximal configuration is reached.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ *
+ * NOTE:
+ *
+ * This function is called in the check phase of an atomic update. The
+ * driver is not allowed to change anything outside of the free-standing
+ * state objects passed-in or assembled in the overall &drm_atomic_state
+ * update tracking structure.
+ *
+ * RETURNS:
+ *
+ * 0 on success, -EINVAL if the state or the transition can't be
+ * supported, -ENOMEM on memory allocation failure and -EDEADLK if an
+ * attempt to obtain another state object ran into a &drm_modeset_lock
+ * deadlock.
+ */
+ int (*atomic_check)(struct drm_plane *plane,
+ struct drm_plane_state *state);
+
+ /**
+ * @atomic_update:
+ *
+ * Drivers should use this function to update the plane state. This
+ * hook is called in-between the ->atomic_begin() and
+ * ->atomic_flush() of &drm_crtc_helper_funcs.
+ *
+ * Note that the power state of the display pipe when this function is
+ * called depends upon the exact helpers and calling sequence the driver
+ * has picked. See drm_atomic_commit_planes() for a discussion of the
+ * tradeoffs and variants of plane commit helpers.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ */
+ void (*atomic_update)(struct drm_plane *plane,
+ struct drm_plane_state *old_state);
+ /**
+ * @atomic_disable:
+ *
+ * Drivers should use this function to unconditionally disable a plane.
+ * This hook is called in-between the ->atomic_begin() and
+ * ->atomic_flush() of &drm_crtc_helper_funcs. It is an alternative to
+ * @atomic_update, which will be called for disabling planes, too, if
+ * the @atomic_disable hook isn't implemented.
+ *
+ * This hook is also useful to disable planes in preparation of a modeset,
+ * by calling drm_atomic_helper_disable_planes_on_crtc() from the
+ * ->disable() hook in &drm_crtc_helper_funcs.
+ *
+ * Note that the power state of the display pipe when this function is
+ * called depends upon the exact helpers and calling sequence the driver
+ * has picked. See drm_atomic_commit_planes() for a discussion of the
+ * tradeoffs and variants of plane commit helpers.
+ *
+ * This callback is used by the atomic modeset helpers and by the
+ * transitional plane helpers, but it is optional.
+ */
+ void (*atomic_disable)(struct drm_plane *plane,
+ struct drm_plane_state *old_state);
+};
+
+/**
+ * drm_plane_helper_add - sets the helper vtable for a plane
+ * @plane: DRM plane
+ * @funcs: helper vtable to set for @plane
+ */
+static inline void drm_plane_helper_add(struct drm_plane *plane,
+ const struct drm_plane_helper_funcs *funcs)
+{
+ plane->helper_private = funcs;
+}
+
+#endif
diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
index 94938d89347c..c5576fbcb909 100644
--- a/include/drm/drm_modeset_lock.h
+++ b/include/drm/drm_modeset_lock.h
@@ -138,7 +138,7 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
struct drm_modeset_acquire_ctx *
drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc);
-int drm_modeset_lock_all_crtcs(struct drm_device *dev,
- struct drm_modeset_acquire_ctx *ctx);
+int drm_modeset_lock_all_ctx(struct drm_device *dev,
+ struct drm_modeset_acquire_ctx *ctx);
#endif /* DRM_MODESET_LOCK_H_ */
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index 5a7f9d4efb1d..4421f3f4ca8d 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -26,6 +26,7 @@
#include <drm/drm_rect.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_modeset_helper_vtables.h>
/*
* Drivers that don't allow primary plane scaling may pass this macro in place
@@ -36,46 +37,9 @@
*/
#define DRM_PLANE_HELPER_NO_SCALING (1<<16)
-/**
- * DOC: plane helpers
- *
- * Helper functions to assist with creation and handling of CRTC primary
- * planes.
- */
-
int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
const struct drm_crtc_funcs *funcs);
-/**
- * drm_plane_helper_funcs - helper operations for CRTCs
- * @prepare_fb: prepare a framebuffer for use by the plane
- * @cleanup_fb: cleanup a framebuffer when it's no longer used by the plane
- * @atomic_check: check that a given atomic state is valid and can be applied
- * @atomic_update: apply an atomic state to the plane (mandatory)
- * @atomic_disable: disable the plane
- *
- * The helper operations are called by the mid-layer CRTC helper.
- */
-struct drm_plane_helper_funcs {
- int (*prepare_fb)(struct drm_plane *plane,
- const struct drm_plane_state *new_state);
- void (*cleanup_fb)(struct drm_plane *plane,
- const struct drm_plane_state *old_state);
-
- int (*atomic_check)(struct drm_plane *plane,
- struct drm_plane_state *state);
- void (*atomic_update)(struct drm_plane *plane,
- struct drm_plane_state *old_state);
- void (*atomic_disable)(struct drm_plane *plane,
- struct drm_plane_state *old_state);
-};
-
-static inline void drm_plane_helper_add(struct drm_plane *plane,
- const struct drm_plane_helper_funcs *funcs)
-{
- plane->helper_private = funcs;
-}
-
int drm_plane_helper_check_update(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h
index 26bb55e9e8b6..83bb156d4356 100644
--- a/include/drm/drm_rect.h
+++ b/include/drm/drm_rect.h
@@ -162,7 +162,8 @@ int drm_rect_calc_hscale_relaxed(struct drm_rect *src,
int drm_rect_calc_vscale_relaxed(struct drm_rect *src,
struct drm_rect *dst,
int min_vscale, int max_vscale);
-void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point);
+void drm_rect_debug_print(const char *prefix,
+ const struct drm_rect *r, bool fixed_point);
void drm_rect_rotate(struct drm_rect *r,
int width, int height,
unsigned int rotation);
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index 30d89e0da2c6..b46fa0ef3005 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -31,47 +31,94 @@
#define MAX_PORTS 5
/**
- * struct i915_audio_component_ops - callbacks defined in gfx driver
- * @owner: the module owner
- * @get_power: get the POWER_DOMAIN_AUDIO power well
- * @put_power: put the POWER_DOMAIN_AUDIO power well
- * @codec_wake_override: Enable/Disable generating the codec wake signal
- * @get_cdclk_freq: get the Core Display Clock in KHz
- * @sync_audio_rate: set n/cts based on the sample rate
+ * struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver
*/
struct i915_audio_component_ops {
+ /**
+ * @owner: i915 module
+ */
struct module *owner;
+ /**
+ * @get_power: get the POWER_DOMAIN_AUDIO power well
+ *
+ * Request the power well to be turned on.
+ */
void (*get_power)(struct device *);
+ /**
+ * @put_power: put the POWER_DOMAIN_AUDIO power well
+ *
+ * Allow the power well to be turned off.
+ */
void (*put_power)(struct device *);
+ /**
+ * @codec_wake_override: Enable/disable codec wake signal
+ */
void (*codec_wake_override)(struct device *, bool enable);
+ /**
+ * @get_cdclk_freq: Get the Core Display Clock in kHz
+ */
int (*get_cdclk_freq)(struct device *);
+ /**
+ * @sync_audio_rate: set n/cts based on the sample rate
+ *
+ * Called from audio driver. After audio driver sets the
+ * sample rate, it will call this function to set n/cts
+ */
int (*sync_audio_rate)(struct device *, int port, int rate);
+ /**
+ * @get_eld: fill the audio state and ELD bytes for the given port
+ *
+ * Called from audio driver to get the HDMI/DP audio state of the given
+ * digital port, and also fetch ELD bytes to the given pointer.
+ *
+ * It returns the byte size of the original ELD (not the actually
+ * copied size), zero for an invalid ELD, or a negative error code.
+ *
+ * Note that the returned size may be over @max_bytes. Then it
+ * implies that only a part of ELD has been copied to the buffer.
+ */
+ int (*get_eld)(struct device *, int port, bool *enabled,
+ unsigned char *buf, int max_bytes);
};
+/**
+ * struct i915_audio_component_audio_ops - Ops implemented by hda driver, called by i915 driver
+ */
struct i915_audio_component_audio_ops {
+ /**
+ * @audio_ptr: Pointer to be used in call to pin_eld_notify
+ */
void *audio_ptr;
/**
- * Call from i915 driver, notifying the HDA driver that
- * pin sense and/or ELD information has changed.
- * @audio_ptr: HDA driver object
- * @port: Which port has changed (PORTA / PORTB / PORTC etc)
+ * @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed
+ *
+ * Called when the i915 driver has set up audio pipeline or has just
+ * begun to tear it down. This allows the HDA driver to update its
+ * status accordingly (even when the HDA controller is in power save
+ * mode).
*/
void (*pin_eld_notify)(void *audio_ptr, int port);
};
/**
- * struct i915_audio_component - used for audio video interaction
- * @dev: the device from gfx driver
- * @aud_sample_rate: the array of audio sample rate per port
- * @ops: callback for audio driver calling
- * @audio_ops: Call from i915 driver
+ * struct i915_audio_component - Used for direct communication between i915 and hda drivers
*/
struct i915_audio_component {
+ /**
+ * @dev: i915 device, used as parameter for ops
+ */
struct device *dev;
+ /**
+ * @aud_sample_rate: the array of audio sample rate per port
+ */
int aud_sample_rate[MAX_PORTS];
-
+ /**
+ * @ops: Ops implemented by i915 driver, called by hda driver
+ */
const struct i915_audio_component_ops *ops;
-
+ /**
+ * @audio_ops: Ops implemented by hda driver, called by i915 driver
+ */
const struct i915_audio_component_audio_ops *audio_ops;
};
diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h
index 17c445612e01..f97020904717 100644
--- a/include/drm/i915_pciids.h
+++ b/include/drm/i915_pciids.h
@@ -279,16 +279,59 @@
#define INTEL_SKL_GT3_IDS(info) \
INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
- INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \
+ INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */
-#define INTEL_SKL_IDS(info) \
+#define INTEL_SKL_GT4_IDS(info) \
+ INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ \
+ INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */ \
+ INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */ \
+ INTEL_VGA_DEVICE(0x193A, info) /* SRV GT4 */
+
+#define INTEL_SKL_IDS(info) \
INTEL_SKL_GT1_IDS(info), \
INTEL_SKL_GT2_IDS(info), \
- INTEL_SKL_GT3_IDS(info)
+ INTEL_SKL_GT3_IDS(info), \
+ INTEL_SKL_GT4_IDS(info)
#define INTEL_BXT_IDS(info) \
INTEL_VGA_DEVICE(0x0A84, info), \
INTEL_VGA_DEVICE(0x1A84, info), \
INTEL_VGA_DEVICE(0x5A84, info)
+#define INTEL_KBL_GT1_IDS(info) \
+ INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
+ INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
+ INTEL_VGA_DEVICE(0x5917, info), /* DT GT1.5 */ \
+ INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
+ INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
+ INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ \
+ INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
+ INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
+
+#define INTEL_KBL_GT2_IDS(info) \
+ INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
+ INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
+ INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
+ INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \
+ INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
+ INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
+ INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
+
+#define INTEL_KBL_GT3_IDS(info) \
+ INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
+ INTEL_VGA_DEVICE(0x592B, info), /* Halo GT3 */ \
+ INTEL_VGA_DEVICE(0x592A, info) /* SRV GT3 */
+
+#define INTEL_KBL_GT4_IDS(info) \
+ INTEL_VGA_DEVICE(0x5932, info), /* DT GT4 */ \
+ INTEL_VGA_DEVICE(0x593B, info), /* Halo GT4 */ \
+ INTEL_VGA_DEVICE(0x593A, info), /* SRV GT4 */ \
+ INTEL_VGA_DEVICE(0x593D, info) /* WKS GT4 */
+
+#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)
+
#endif /* _I915_PCIIDS_H */
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index c768ddfbe53c..afae2316bd43 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -383,6 +383,16 @@ extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo);
*/
extern int ttm_bo_del_from_lru(struct ttm_buffer_object *bo);
+/**
+ * ttm_bo_move_to_lru_tail
+ *
+ * @bo: The buffer object.
+ *
+ * Move this BO to the tail of all lru lists used to lookup and reserve an
+ * object. This function must be called with struct ttm_bo_global::lru_lock
+ * held, and is used to make a BO less likely to be considered for eviction.
+ */
+extern void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo);
/**
* ttm_bo_lock_delayed_workqueue
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index 813042cede57..3d4bf08aa21f 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -826,10 +826,10 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo,
* reserved, the validation sequence is checked against the validation
* sequence of the process currently reserving the buffer,
* and if the current validation sequence is greater than that of the process
- * holding the reservation, the function returns -EAGAIN. Otherwise it sleeps
+ * holding the reservation, the function returns -EDEADLK. Otherwise it sleeps
* waiting for the buffer to become unreserved, after which it retries
* reserving.
- * The caller should, when receiving an -EAGAIN error
+ * The caller should, when receiving an -EDEADLK error
* release all its buffer reservations, wait for @bo to become unreserved, and
* then rerun the validation with the same validation sequence. This procedure
* will always guarantee that the process with the lowest validation sequence
diff --git a/include/dt-bindings/clock/bcm2835-aux.h b/include/dt-bindings/clock/bcm2835-aux.h
new file mode 100644
index 000000000000..d91156e2658d
--- /dev/null
+++ b/include/dt-bindings/clock/bcm2835-aux.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define BCM2835_AUX_CLOCK_UART 0
+#define BCM2835_AUX_CLOCK_SPI1 1
+#define BCM2835_AUX_CLOCK_SPI2 2
+#define BCM2835_AUX_CLOCK_COUNT 3
diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h
index d323efac7edf..61f1d20c2a67 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -43,5 +43,6 @@
#define BCM2835_CLOCK_TSENS 27
#define BCM2835_CLOCK_EMMC 28
#define BCM2835_CLOCK_PERI_IMAGE 29
+#define BCM2835_CLOCK_PWM 30
-#define BCM2835_CLOCK_COUNT 30
+#define BCM2835_CLOCK_COUNT 31
diff --git a/include/dt-bindings/clock/exynos4.h b/include/dt-bindings/clock/exynos4.h
index c4b1676ea674..c40111f36d5e 100644
--- a/include/dt-bindings/clock/exynos4.h
+++ b/include/dt-bindings/clock/exynos4.h
@@ -93,6 +93,7 @@
#define CLK_SCLK_FIMG2D 177
/* gate clocks */
+#define CLK_SSS 255
#define CLK_FIMC0 256
#define CLK_FIMC1 257
#define CLK_FIMC2 258
diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h
index 99da0d117a7d..7699ee9c16c0 100644
--- a/include/dt-bindings/clock/exynos5420.h
+++ b/include/dt-bindings/clock/exynos5420.h
@@ -25,6 +25,8 @@
#define CLK_FOUT_MPLL 10
#define CLK_FOUT_BPLL 11
#define CLK_FOUT_KPLL 12
+#define CLK_ARM_CLK 13
+#define CLK_KFC_CLK 14
/* gate for special clocks (sclk) */
#define CLK_SCLK_UART0 128
@@ -210,6 +212,8 @@
#define CLK_MOUT_SW_ACLK300 649
#define CLK_MOUT_USER_ACLK400_DISP1 650
#define CLK_MOUT_SW_ACLK400 651
+#define CLK_MOUT_USER_ACLK300_GSCL 652
+#define CLK_MOUT_SW_ACLK300_GSCL 653
/* divider clocks */
#define CLK_DOUT_PIXEL 768
diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h
index a4a7a9ce3457..edca8985c50e 100644
--- a/include/dt-bindings/clock/imx7d-clock.h
+++ b/include/dt-bindings/clock/imx7d-clock.h
@@ -447,5 +447,6 @@
#define IMX7D_SEMA4_HS_ROOT_CLK 434
#define IMX7D_PLL_DRAM_TEST_DIV 435
#define IMX7D_ADC_ROOT_CLK 436
-#define IMX7D_CLK_END 437
+#define IMX7D_CLK_ARM 437
+#define IMX7D_CLK_END 438
#endif /* __DT_BINDINGS_CLOCK_IMX7D_H */
diff --git a/include/dt-bindings/clock/lpc32xx-clock.h b/include/dt-bindings/clock/lpc32xx-clock.h
new file mode 100644
index 000000000000..bcb1c9a73519
--- /dev/null
+++ b/include/dt-bindings/clock/lpc32xx-clock.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Vladimir Zapolskiy <vz@mleia.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+#ifndef __DT_BINDINGS_LPC32XX_CLOCK_H
+#define __DT_BINDINGS_LPC32XX_CLOCK_H
+
+/* LPC32XX System Control Block clocks */
+#define LPC32XX_CLK_RTC 1
+#define LPC32XX_CLK_DMA 2
+#define LPC32XX_CLK_MLC 3
+#define LPC32XX_CLK_SLC 4
+#define LPC32XX_CLK_LCD 5
+#define LPC32XX_CLK_MAC 6
+#define LPC32XX_CLK_SD 7
+#define LPC32XX_CLK_DDRAM 8
+#define LPC32XX_CLK_SSP0 9
+#define LPC32XX_CLK_SSP1 10
+#define LPC32XX_CLK_UART3 11
+#define LPC32XX_CLK_UART4 12
+#define LPC32XX_CLK_UART5 13
+#define LPC32XX_CLK_UART6 14
+#define LPC32XX_CLK_IRDA 15
+#define LPC32XX_CLK_I2C1 16
+#define LPC32XX_CLK_I2C2 17
+#define LPC32XX_CLK_TIMER0 18
+#define LPC32XX_CLK_TIMER1 19
+#define LPC32XX_CLK_TIMER2 20
+#define LPC32XX_CLK_TIMER3 21
+#define LPC32XX_CLK_TIMER4 22
+#define LPC32XX_CLK_TIMER5 23
+#define LPC32XX_CLK_WDOG 24
+#define LPC32XX_CLK_I2S0 25
+#define LPC32XX_CLK_I2S1 26
+#define LPC32XX_CLK_SPI1 27
+#define LPC32XX_CLK_SPI2 28
+#define LPC32XX_CLK_MCPWM 29
+#define LPC32XX_CLK_HSTIMER 30
+#define LPC32XX_CLK_KEY 31
+#define LPC32XX_CLK_PWM1 32
+#define LPC32XX_CLK_PWM2 33
+#define LPC32XX_CLK_ADC 34
+
+/* LPC32XX USB clocks */
+#define LPC32XX_USB_CLK_I2C 1
+#define LPC32XX_USB_CLK_DEVICE 2
+#define LPC32XX_USB_CLK_HOST 3
+
+#endif /* __DT_BINDINGS_LPC32XX_CLOCK_H */
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8996.h b/include/dt-bindings/clock/qcom,gcc-msm8996.h
new file mode 100644
index 000000000000..888e75ce8fec
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-msm8996.h
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GCC_8996_H
+#define _DT_BINDINGS_CLK_MSM_GCC_8996_H
+
+#define GPLL0_EARLY 0
+#define GPLL0 1
+#define GPLL1_EARLY 2
+#define GPLL1 3
+#define GPLL2_EARLY 4
+#define GPLL2 5
+#define GPLL3_EARLY 6
+#define GPLL3 7
+#define GPLL4_EARLY 8
+#define GPLL4 9
+#define SYSTEM_NOC_CLK_SRC 10
+#define CONFIG_NOC_CLK_SRC 11
+#define PERIPH_NOC_CLK_SRC 12
+#define MMSS_BIMC_GFX_CLK_SRC 13
+#define USB30_MASTER_CLK_SRC 14
+#define USB30_MOCK_UTMI_CLK_SRC 15
+#define USB3_PHY_AUX_CLK_SRC 16
+#define USB20_MASTER_CLK_SRC 17
+#define USB20_MOCK_UTMI_CLK_SRC 18
+#define SDCC1_APPS_CLK_SRC 19
+#define SDCC1_ICE_CORE_CLK_SRC 20
+#define SDCC2_APPS_CLK_SRC 21
+#define SDCC3_APPS_CLK_SRC 22
+#define SDCC4_APPS_CLK_SRC 23
+#define BLSP1_QUP1_SPI_APPS_CLK_SRC 24
+#define BLSP1_QUP1_I2C_APPS_CLK_SRC 25
+#define BLSP1_UART1_APPS_CLK_SRC 26
+#define BLSP1_QUP2_SPI_APPS_CLK_SRC 27
+#define BLSP1_QUP2_I2C_APPS_CLK_SRC 28
+#define BLSP1_UART2_APPS_CLK_SRC 29
+#define BLSP1_QUP3_SPI_APPS_CLK_SRC 30
+#define BLSP1_QUP3_I2C_APPS_CLK_SRC 31
+#define BLSP1_UART3_APPS_CLK_SRC 32
+#define BLSP1_QUP4_SPI_APPS_CLK_SRC 33
+#define BLSP1_QUP4_I2C_APPS_CLK_SRC 34
+#define BLSP1_UART4_APPS_CLK_SRC 35
+#define BLSP1_QUP5_SPI_APPS_CLK_SRC 36
+#define BLSP1_QUP5_I2C_APPS_CLK_SRC 37
+#define BLSP1_UART5_APPS_CLK_SRC 38
+#define BLSP1_QUP6_SPI_APPS_CLK_SRC 39
+#define BLSP1_QUP6_I2C_APPS_CLK_SRC 40
+#define BLSP1_UART6_APPS_CLK_SRC 41
+#define BLSP2_QUP1_SPI_APPS_CLK_SRC 42
+#define BLSP2_QUP1_I2C_APPS_CLK_SRC 43
+#define BLSP2_UART1_APPS_CLK_SRC 44
+#define BLSP2_QUP2_SPI_APPS_CLK_SRC 45
+#define BLSP2_QUP2_I2C_APPS_CLK_SRC 46
+#define BLSP2_UART2_APPS_CLK_SRC 47
+#define BLSP2_QUP3_SPI_APPS_CLK_SRC 48
+#define BLSP2_QUP3_I2C_APPS_CLK_SRC 49
+#define BLSP2_UART3_APPS_CLK_SRC 50
+#define BLSP2_QUP4_SPI_APPS_CLK_SRC 51
+#define BLSP2_QUP4_I2C_APPS_CLK_SRC 52
+#define BLSP2_UART4_APPS_CLK_SRC 53
+#define BLSP2_QUP5_SPI_APPS_CLK_SRC 54
+#define BLSP2_QUP5_I2C_APPS_CLK_SRC 55
+#define BLSP2_UART5_APPS_CLK_SRC 56
+#define BLSP2_QUP6_SPI_APPS_CLK_SRC 57
+#define BLSP2_QUP6_I2C_APPS_CLK_SRC 58
+#define BLSP2_UART6_APPS_CLK_SRC 59
+#define PDM2_CLK_SRC 60
+#define TSIF_REF_CLK_SRC 61
+#define CE1_CLK_SRC 62
+#define GCC_SLEEP_CLK_SRC 63
+#define BIMC_CLK_SRC 64
+#define HMSS_AHB_CLK_SRC 65
+#define BIMC_HMSS_AXI_CLK_SRC 66
+#define HMSS_RBCPR_CLK_SRC 67
+#define HMSS_GPLL0_CLK_SRC 68
+#define GP1_CLK_SRC 69
+#define GP2_CLK_SRC 70
+#define GP3_CLK_SRC 71
+#define PCIE_AUX_CLK_SRC 72
+#define UFS_AXI_CLK_SRC 73
+#define UFS_ICE_CORE_CLK_SRC 74
+#define QSPI_SER_CLK_SRC 75
+#define GCC_SYS_NOC_AXI_CLK 76
+#define GCC_SYS_NOC_HMSS_AHB_CLK 77
+#define GCC_SNOC_CNOC_AHB_CLK 78
+#define GCC_SNOC_PNOC_AHB_CLK 79
+#define GCC_SYS_NOC_AT_CLK 80
+#define GCC_SYS_NOC_USB3_AXI_CLK 81
+#define GCC_SYS_NOC_UFS_AXI_CLK 82
+#define GCC_CFG_NOC_AHB_CLK 83
+#define GCC_PERIPH_NOC_AHB_CLK 84
+#define GCC_PERIPH_NOC_USB20_AHB_CLK 85
+#define GCC_TIC_CLK 86
+#define GCC_IMEM_AXI_CLK 87
+#define GCC_MMSS_SYS_NOC_AXI_CLK 88
+#define GCC_MMSS_NOC_CFG_AHB_CLK 89
+#define GCC_MMSS_BIMC_GFX_CLK 90
+#define GCC_USB30_MASTER_CLK 91
+#define GCC_USB30_SLEEP_CLK 92
+#define GCC_USB30_MOCK_UTMI_CLK 93
+#define GCC_USB3_PHY_AUX_CLK 94
+#define GCC_USB3_PHY_PIPE_CLK 95
+#define GCC_USB20_MASTER_CLK 96
+#define GCC_USB20_SLEEP_CLK 97
+#define GCC_USB20_MOCK_UTMI_CLK 98
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK 99
+#define GCC_SDCC1_APPS_CLK 100
+#define GCC_SDCC1_AHB_CLK 101
+#define GCC_SDCC1_ICE_CORE_CLK 102
+#define GCC_SDCC2_APPS_CLK 103
+#define GCC_SDCC2_AHB_CLK 104
+#define GCC_SDCC3_APPS_CLK 105
+#define GCC_SDCC3_AHB_CLK 106
+#define GCC_SDCC4_APPS_CLK 107
+#define GCC_SDCC4_AHB_CLK 108
+#define GCC_BLSP1_AHB_CLK 109
+#define GCC_BLSP1_SLEEP_CLK 110
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK 111
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK 112
+#define GCC_BLSP1_UART1_APPS_CLK 113
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK 114
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK 115
+#define GCC_BLSP1_UART2_APPS_CLK 116
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK 117
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK 118
+#define GCC_BLSP1_UART3_APPS_CLK 119
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK 120
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK 121
+#define GCC_BLSP1_UART4_APPS_CLK 122
+#define GCC_BLSP1_QUP5_SPI_APPS_CLK 123
+#define GCC_BLSP1_QUP5_I2C_APPS_CLK 124
+#define GCC_BLSP1_UART5_APPS_CLK 125
+#define GCC_BLSP1_QUP6_SPI_APPS_CLK 126
+#define GCC_BLSP1_QUP6_I2C_APPS_CLK 127
+#define GCC_BLSP1_UART6_APPS_CLK 128
+#define GCC_BLSP2_AHB_CLK 129
+#define GCC_BLSP2_SLEEP_CLK 130
+#define GCC_BLSP2_QUP1_SPI_APPS_CLK 131
+#define GCC_BLSP2_QUP1_I2C_APPS_CLK 132
+#define GCC_BLSP2_UART1_APPS_CLK 133
+#define GCC_BLSP2_QUP2_SPI_APPS_CLK 134
+#define GCC_BLSP2_QUP2_I2C_APPS_CLK 135
+#define GCC_BLSP2_UART2_APPS_CLK 136
+#define GCC_BLSP2_QUP3_SPI_APPS_CLK 137
+#define GCC_BLSP2_QUP3_I2C_APPS_CLK 138
+#define GCC_BLSP2_UART3_APPS_CLK 139
+#define GCC_BLSP2_QUP4_SPI_APPS_CLK 140
+#define GCC_BLSP2_QUP4_I2C_APPS_CLK 141
+#define GCC_BLSP2_UART4_APPS_CLK 142
+#define GCC_BLSP2_QUP5_SPI_APPS_CLK 143
+#define GCC_BLSP2_QUP5_I2C_APPS_CLK 144
+#define GCC_BLSP2_UART5_APPS_CLK 145
+#define GCC_BLSP2_QUP6_SPI_APPS_CLK 146
+#define GCC_BLSP2_QUP6_I2C_APPS_CLK 147
+#define GCC_BLSP2_UART6_APPS_CLK 148
+#define GCC_PDM_AHB_CLK 149
+#define GCC_PDM_XO4_CLK 150
+#define GCC_PDM2_CLK 151
+#define GCC_PRNG_AHB_CLK 152
+#define GCC_TSIF_AHB_CLK 153
+#define GCC_TSIF_REF_CLK 154
+#define GCC_TSIF_INACTIVITY_TIMERS_CLK 155
+#define GCC_TCSR_AHB_CLK 156
+#define GCC_BOOT_ROM_AHB_CLK 157
+#define GCC_MSG_RAM_AHB_CLK 158
+#define GCC_TLMM_AHB_CLK 159
+#define GCC_TLMM_CLK 160
+#define GCC_MPM_AHB_CLK 161
+#define GCC_SPMI_SER_CLK 162
+#define GCC_SPMI_CNOC_AHB_CLK 163
+#define GCC_CE1_CLK 164
+#define GCC_CE1_AXI_CLK 165
+#define GCC_CE1_AHB_CLK 166
+#define GCC_BIMC_HMSS_AXI_CLK 167
+#define GCC_BIMC_GFX_CLK 168
+#define GCC_HMSS_AHB_CLK 169
+#define GCC_HMSS_SLV_AXI_CLK 170
+#define GCC_HMSS_MSTR_AXI_CLK 171
+#define GCC_HMSS_RBCPR_CLK 172
+#define GCC_GP1_CLK 173
+#define GCC_GP2_CLK 174
+#define GCC_GP3_CLK 175
+#define GCC_PCIE_0_SLV_AXI_CLK 176
+#define GCC_PCIE_0_MSTR_AXI_CLK 177
+#define GCC_PCIE_0_CFG_AHB_CLK 178
+#define GCC_PCIE_0_AUX_CLK 179
+#define GCC_PCIE_0_PIPE_CLK 180
+#define GCC_PCIE_1_SLV_AXI_CLK 181
+#define GCC_PCIE_1_MSTR_AXI_CLK 182
+#define GCC_PCIE_1_CFG_AHB_CLK 183
+#define GCC_PCIE_1_AUX_CLK 184
+#define GCC_PCIE_1_PIPE_CLK 185
+#define GCC_PCIE_2_SLV_AXI_CLK 186
+#define GCC_PCIE_2_MSTR_AXI_CLK 187
+#define GCC_PCIE_2_CFG_AHB_CLK 188
+#define GCC_PCIE_2_AUX_CLK 189
+#define GCC_PCIE_2_PIPE_CLK 190
+#define GCC_PCIE_PHY_CFG_AHB_CLK 191
+#define GCC_PCIE_PHY_AUX_CLK 192
+#define GCC_UFS_AXI_CLK 193
+#define GCC_UFS_AHB_CLK 194
+#define GCC_UFS_TX_CFG_CLK 195
+#define GCC_UFS_RX_CFG_CLK 196
+#define GCC_UFS_TX_SYMBOL_0_CLK 197
+#define GCC_UFS_RX_SYMBOL_0_CLK 198
+#define GCC_UFS_RX_SYMBOL_1_CLK 199
+#define GCC_UFS_UNIPRO_CORE_CLK 200
+#define GCC_UFS_ICE_CORE_CLK 201
+#define GCC_UFS_SYS_CLK_CORE_CLK 202
+#define GCC_UFS_TX_SYMBOL_CLK_CORE_CLK 203
+#define GCC_AGGRE0_SNOC_AXI_CLK 204
+#define GCC_AGGRE0_CNOC_AHB_CLK 205
+#define GCC_SMMU_AGGRE0_AXI_CLK 206
+#define GCC_SMMU_AGGRE0_AHB_CLK 207
+#define GCC_AGGRE1_PNOC_AHB_CLK 208
+#define GCC_AGGRE2_UFS_AXI_CLK 209
+#define GCC_AGGRE2_USB3_AXI_CLK 210
+#define GCC_QSPI_AHB_CLK 211
+#define GCC_QSPI_SER_CLK 212
+#define GCC_USB3_CLKREF_CLK 213
+#define GCC_HDMI_CLKREF_CLK 214
+#define GCC_UFS_CLKREF_CLK 215
+#define GCC_PCIE_CLKREF_CLK 216
+#define GCC_RX2_USB2_CLKREF_CLK 217
+#define GCC_RX1_USB2_CLKREF_CLK 218
+
+#define GCC_SYSTEM_NOC_BCR 0
+#define GCC_CONFIG_NOC_BCR 1
+#define GCC_PERIPH_NOC_BCR 2
+#define GCC_IMEM_BCR 3
+#define GCC_MMSS_BCR 4
+#define GCC_PIMEM_BCR 5
+#define GCC_QDSS_BCR 6
+#define GCC_USB_30_BCR 7
+#define GCC_USB_20_BCR 8
+#define GCC_QUSB2PHY_PRIM_BCR 9
+#define GCC_QUSB2PHY_SEC_BCR 10
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR 11
+#define GCC_SDCC1_BCR 12
+#define GCC_SDCC2_BCR 13
+#define GCC_SDCC3_BCR 14
+#define GCC_SDCC4_BCR 15
+#define GCC_BLSP1_BCR 16
+#define GCC_BLSP1_QUP1_BCR 17
+#define GCC_BLSP1_UART1_BCR 18
+#define GCC_BLSP1_QUP2_BCR 19
+#define GCC_BLSP1_UART2_BCR 20
+#define GCC_BLSP1_QUP3_BCR 21
+#define GCC_BLSP1_UART3_BCR 22
+#define GCC_BLSP1_QUP4_BCR 23
+#define GCC_BLSP1_UART4_BCR 24
+#define GCC_BLSP1_QUP5_BCR 25
+#define GCC_BLSP1_UART5_BCR 26
+#define GCC_BLSP1_QUP6_BCR 27
+#define GCC_BLSP1_UART6_BCR 28
+#define GCC_BLSP2_BCR 29
+#define GCC_BLSP2_QUP1_BCR 30
+#define GCC_BLSP2_UART1_BCR 31
+#define GCC_BLSP2_QUP2_BCR 32
+#define GCC_BLSP2_UART2_BCR 33
+#define GCC_BLSP2_QUP3_BCR 34
+#define GCC_BLSP2_UART3_BCR 35
+#define GCC_BLSP2_QUP4_BCR 36
+#define GCC_BLSP2_UART4_BCR 37
+#define GCC_BLSP2_QUP5_BCR 38
+#define GCC_BLSP2_UART5_BCR 39
+#define GCC_BLSP2_QUP6_BCR 40
+#define GCC_BLSP2_UART6_BCR 41
+#define GCC_PDM_BCR 42
+#define GCC_PRNG_BCR 43
+#define GCC_TSIF_BCR 44
+#define GCC_TCSR_BCR 45
+#define GCC_BOOT_ROM_BCR 46
+#define GCC_MSG_RAM_BCR 47
+#define GCC_TLMM_BCR 48
+#define GCC_MPM_BCR 49
+#define GCC_SEC_CTRL_BCR 50
+#define GCC_SPMI_BCR 51
+#define GCC_SPDM_BCR 52
+#define GCC_CE1_BCR 53
+#define GCC_BIMC_BCR 54
+#define GCC_SNOC_BUS_TIMEOUT0_BCR 55
+#define GCC_SNOC_BUS_TIMEOUT2_BCR 56
+#define GCC_SNOC_BUS_TIMEOUT1_BCR 57
+#define GCC_SNOC_BUS_TIMEOUT3_BCR 58
+#define GCC_SNOC_BUS_TIMEOUT_EXTREF_BCR 59
+#define GCC_PNOC_BUS_TIMEOUT0_BCR 60
+#define GCC_PNOC_BUS_TIMEOUT1_BCR 61
+#define GCC_PNOC_BUS_TIMEOUT2_BCR 62
+#define GCC_PNOC_BUS_TIMEOUT3_BCR 63
+#define GCC_PNOC_BUS_TIMEOUT4_BCR 64
+#define GCC_CNOC_BUS_TIMEOUT0_BCR 65
+#define GCC_CNOC_BUS_TIMEOUT1_BCR 66
+#define GCC_CNOC_BUS_TIMEOUT2_BCR 67
+#define GCC_CNOC_BUS_TIMEOUT3_BCR 68
+#define GCC_CNOC_BUS_TIMEOUT4_BCR 69
+#define GCC_CNOC_BUS_TIMEOUT5_BCR 70
+#define GCC_CNOC_BUS_TIMEOUT6_BCR 71
+#define GCC_CNOC_BUS_TIMEOUT7_BCR 72
+#define GCC_CNOC_BUS_TIMEOUT8_BCR 73
+#define GCC_CNOC_BUS_TIMEOUT9_BCR 74
+#define GCC_CNOC_BUS_TIMEOUT_EXTREF_BCR 75
+#define GCC_APB2JTAG_BCR 76
+#define GCC_RBCPR_CX_BCR 77
+#define GCC_RBCPR_MX_BCR 78
+#define GCC_PCIE_0_BCR 79
+#define GCC_PCIE_0_PHY_BCR 80
+#define GCC_PCIE_1_BCR 81
+#define GCC_PCIE_1_PHY_BCR 82
+#define GCC_PCIE_2_BCR 83
+#define GCC_PCIE_2_PHY_BCR 84
+#define GCC_PCIE_PHY_BCR 85
+#define GCC_DCD_BCR 86
+#define GCC_OBT_ODT_BCR 87
+#define GCC_UFS_BCR 88
+#define GCC_SSC_BCR 89
+#define GCC_VS_BCR 90
+#define GCC_AGGRE0_NOC_BCR 91
+#define GCC_AGGRE1_NOC_BCR 92
+#define GCC_AGGRE2_NOC_BCR 93
+#define GCC_DCC_BCR 94
+#define GCC_IPA_BCR 95
+#define GCC_QSPI_BCR 96
+#define GCC_SKL_BCR 97
+#define GCC_MSMPU_BCR 98
+#define GCC_MSS_Q6_BCR 99
+#define GCC_QREFS_VBG_CAL_BCR 100
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,mmcc-msm8996.h b/include/dt-bindings/clock/qcom,mmcc-msm8996.h
new file mode 100644
index 000000000000..9b81ca65fcec
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,mmcc-msm8996.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_MMCC_8996_H
+#define _DT_BINDINGS_CLK_MSM_MMCC_8996_H
+
+#define MMPLL0_EARLY 0
+#define MMPLL0_PLL 1
+#define MMPLL1_EARLY 2
+#define MMPLL1_PLL 3
+#define MMPLL2_EARLY 4
+#define MMPLL2_PLL 5
+#define MMPLL3_EARLY 6
+#define MMPLL3_PLL 7
+#define MMPLL4_EARLY 8
+#define MMPLL4_PLL 9
+#define MMPLL5_EARLY 10
+#define MMPLL5_PLL 11
+#define MMPLL8_EARLY 12
+#define MMPLL8_PLL 13
+#define MMPLL9_EARLY 14
+#define MMPLL9_PLL 15
+#define AHB_CLK_SRC 16
+#define AXI_CLK_SRC 17
+#define MAXI_CLK_SRC 18
+#define DSA_CORE_CLK_SRC 19
+#define GFX3D_CLK_SRC 20
+#define RBBMTIMER_CLK_SRC 21
+#define ISENSE_CLK_SRC 22
+#define RBCPR_CLK_SRC 23
+#define VIDEO_CORE_CLK_SRC 24
+#define VIDEO_SUBCORE0_CLK_SRC 25
+#define VIDEO_SUBCORE1_CLK_SRC 26
+#define PCLK0_CLK_SRC 27
+#define PCLK1_CLK_SRC 28
+#define MDP_CLK_SRC 29
+#define EXTPCLK_CLK_SRC 30
+#define VSYNC_CLK_SRC 31
+#define HDMI_CLK_SRC 32
+#define BYTE0_CLK_SRC 33
+#define BYTE1_CLK_SRC 34
+#define ESC0_CLK_SRC 35
+#define ESC1_CLK_SRC 36
+#define CAMSS_GP0_CLK_SRC 37
+#define CAMSS_GP1_CLK_SRC 38
+#define MCLK0_CLK_SRC 39
+#define MCLK1_CLK_SRC 40
+#define MCLK2_CLK_SRC 41
+#define MCLK3_CLK_SRC 42
+#define CCI_CLK_SRC 43
+#define CSI0PHYTIMER_CLK_SRC 44
+#define CSI1PHYTIMER_CLK_SRC 45
+#define CSI2PHYTIMER_CLK_SRC 46
+#define CSIPHY0_3P_CLK_SRC 47
+#define CSIPHY1_3P_CLK_SRC 48
+#define CSIPHY2_3P_CLK_SRC 49
+#define JPEG0_CLK_SRC 50
+#define JPEG2_CLK_SRC 51
+#define JPEG_DMA_CLK_SRC 52
+#define VFE0_CLK_SRC 53
+#define VFE1_CLK_SRC 54
+#define CPP_CLK_SRC 55
+#define CSI0_CLK_SRC 56
+#define CSI1_CLK_SRC 57
+#define CSI2_CLK_SRC 58
+#define CSI3_CLK_SRC 59
+#define FD_CORE_CLK_SRC 60
+#define MMSS_CXO_CLK 61
+#define MMSS_SLEEPCLK_CLK 62
+#define MMSS_MMAGIC_AHB_CLK 63
+#define MMSS_MMAGIC_CFG_AHB_CLK 64
+#define MMSS_MISC_AHB_CLK 65
+#define MMSS_MISC_CXO_CLK 66
+#define MMSS_BTO_AHB_CLK 67
+#define MMSS_MMAGIC_AXI_CLK 68
+#define MMSS_S0_AXI_CLK 69
+#define MMSS_MMAGIC_MAXI_CLK 70
+#define DSA_CORE_CLK 71
+#define DSA_NOC_CFG_AHB_CLK 72
+#define MMAGIC_CAMSS_AXI_CLK 73
+#define MMAGIC_CAMSS_NOC_CFG_AHB_CLK 74
+#define THROTTLE_CAMSS_CXO_CLK 75
+#define THROTTLE_CAMSS_AHB_CLK 76
+#define THROTTLE_CAMSS_AXI_CLK 77
+#define SMMU_VFE_AHB_CLK 78
+#define SMMU_VFE_AXI_CLK 79
+#define SMMU_CPP_AHB_CLK 80
+#define SMMU_CPP_AXI_CLK 81
+#define SMMU_JPEG_AHB_CLK 82
+#define SMMU_JPEG_AXI_CLK 83
+#define MMAGIC_MDSS_AXI_CLK 84
+#define MMAGIC_MDSS_NOC_CFG_AHB_CLK 85
+#define THROTTLE_MDSS_CXO_CLK 86
+#define THROTTLE_MDSS_AHB_CLK 87
+#define THROTTLE_MDSS_AXI_CLK 88
+#define SMMU_ROT_AHB_CLK 89
+#define SMMU_ROT_AXI_CLK 90
+#define SMMU_MDP_AHB_CLK 91
+#define SMMU_MDP_AXI_CLK 92
+#define MMAGIC_VIDEO_AXI_CLK 93
+#define MMAGIC_VIDEO_NOC_CFG_AHB_CLK 94
+#define THROTTLE_VIDEO_CXO_CLK 95
+#define THROTTLE_VIDEO_AHB_CLK 96
+#define THROTTLE_VIDEO_AXI_CLK 97
+#define SMMU_VIDEO_AHB_CLK 98
+#define SMMU_VIDEO_AXI_CLK 99
+#define MMAGIC_BIMC_AXI_CLK 100
+#define MMAGIC_BIMC_NOC_CFG_AHB_CLK 101
+#define GPU_GX_GFX3D_CLK 102
+#define GPU_GX_RBBMTIMER_CLK 103
+#define GPU_AHB_CLK 104
+#define GPU_AON_ISENSE_CLK 105
+#define VMEM_MAXI_CLK 106
+#define VMEM_AHB_CLK 107
+#define MMSS_RBCPR_CLK 108
+#define MMSS_RBCPR_AHB_CLK 109
+#define VIDEO_CORE_CLK 110
+#define VIDEO_AXI_CLK 111
+#define VIDEO_MAXI_CLK 112
+#define VIDEO_AHB_CLK 113
+#define VIDEO_SUBCORE0_CLK 114
+#define VIDEO_SUBCORE1_CLK 115
+#define MDSS_AHB_CLK 116
+#define MDSS_HDMI_AHB_CLK 117
+#define MDSS_AXI_CLK 118
+#define MDSS_PCLK0_CLK 119
+#define MDSS_PCLK1_CLK 120
+#define MDSS_MDP_CLK 121
+#define MDSS_EXTPCLK_CLK 122
+#define MDSS_VSYNC_CLK 123
+#define MDSS_HDMI_CLK 124
+#define MDSS_BYTE0_CLK 125
+#define MDSS_BYTE1_CLK 126
+#define MDSS_ESC0_CLK 127
+#define MDSS_ESC1_CLK 128
+#define CAMSS_TOP_AHB_CLK 129
+#define CAMSS_AHB_CLK 130
+#define CAMSS_MICRO_AHB_CLK 131
+#define CAMSS_GP0_CLK 132
+#define CAMSS_GP1_CLK 133
+#define CAMSS_MCLK0_CLK 134
+#define CAMSS_MCLK1_CLK 135
+#define CAMSS_MCLK2_CLK 136
+#define CAMSS_MCLK3_CLK 137
+#define CAMSS_CCI_CLK 138
+#define CAMSS_CCI_AHB_CLK 139
+#define CAMSS_CSI0PHYTIMER_CLK 140
+#define CAMSS_CSI1PHYTIMER_CLK 141
+#define CAMSS_CSI2PHYTIMER_CLK 142
+#define CAMSS_CSIPHY0_3P_CLK 143
+#define CAMSS_CSIPHY1_3P_CLK 144
+#define CAMSS_CSIPHY2_3P_CLK 145
+#define CAMSS_JPEG0_CLK 146
+#define CAMSS_JPEG2_CLK 147
+#define CAMSS_JPEG_DMA_CLK 148
+#define CAMSS_JPEG_AHB_CLK 149
+#define CAMSS_JPEG_AXI_CLK 150
+#define CAMSS_VFE_AHB_CLK 151
+#define CAMSS_VFE_AXI_CLK 152
+#define CAMSS_VFE0_CLK 153
+#define CAMSS_VFE0_STREAM_CLK 154
+#define CAMSS_VFE0_AHB_CLK 155
+#define CAMSS_VFE1_CLK 156
+#define CAMSS_VFE1_STREAM_CLK 157
+#define CAMSS_VFE1_AHB_CLK 158
+#define CAMSS_CSI_VFE0_CLK 159
+#define CAMSS_CSI_VFE1_CLK 160
+#define CAMSS_CPP_VBIF_AHB_CLK 161
+#define CAMSS_CPP_AXI_CLK 162
+#define CAMSS_CPP_CLK 163
+#define CAMSS_CPP_AHB_CLK 164
+#define CAMSS_CSI0_CLK 165
+#define CAMSS_CSI0_AHB_CLK 166
+#define CAMSS_CSI0PHY_CLK 167
+#define CAMSS_CSI0RDI_CLK 168
+#define CAMSS_CSI0PIX_CLK 169
+#define CAMSS_CSI1_CLK 170
+#define CAMSS_CSI1_AHB_CLK 171
+#define CAMSS_CSI1PHY_CLK 172
+#define CAMSS_CSI1RDI_CLK 173
+#define CAMSS_CSI1PIX_CLK 174
+#define CAMSS_CSI2_CLK 175
+#define CAMSS_CSI2_AHB_CLK 176
+#define CAMSS_CSI2PHY_CLK 177
+#define CAMSS_CSI2RDI_CLK 178
+#define CAMSS_CSI2PIX_CLK 179
+#define CAMSS_CSI3_CLK 180
+#define CAMSS_CSI3_AHB_CLK 181
+#define CAMSS_CSI3PHY_CLK 182
+#define CAMSS_CSI3RDI_CLK 183
+#define CAMSS_CSI3PIX_CLK 184
+#define CAMSS_ISPIF_AHB_CLK 185
+#define FD_CORE_CLK 186
+#define FD_CORE_UAR_CLK 187
+#define FD_AHB_CLK 188
+#define MMSS_SPDM_CSI0_CLK 189
+#define MMSS_SPDM_JPEG_DMA_CLK 190
+#define MMSS_SPDM_CPP_CLK 191
+#define MMSS_SPDM_PCLK0_CLK 192
+#define MMSS_SPDM_AHB_CLK 193
+#define MMSS_SPDM_GFX3D_CLK 194
+#define MMSS_SPDM_PCLK1_CLK 195
+#define MMSS_SPDM_JPEG2_CLK 196
+#define MMSS_SPDM_DEBUG_CLK 197
+#define MMSS_SPDM_VFE1_CLK 198
+#define MMSS_SPDM_VFE0_CLK 199
+#define MMSS_SPDM_VIDEO_CORE_CLK 200
+#define MMSS_SPDM_AXI_CLK 201
+#define MMSS_SPDM_MDP_CLK 202
+#define MMSS_SPDM_JPEG0_CLK 203
+#define MMSS_SPDM_RM_AXI_CLK 204
+#define MMSS_SPDM_RM_MAXI_CLK 205
+
+#define MMAGICAHB_BCR 0
+#define MMAGIC_CFG_BCR 1
+#define MISC_BCR 2
+#define BTO_BCR 3
+#define MMAGICAXI_BCR 4
+#define MMAGICMAXI_BCR 5
+#define DSA_BCR 6
+#define MMAGIC_CAMSS_BCR 7
+#define THROTTLE_CAMSS_BCR 8
+#define SMMU_VFE_BCR 9
+#define SMMU_CPP_BCR 10
+#define SMMU_JPEG_BCR 11
+#define MMAGIC_MDSS_BCR 12
+#define THROTTLE_MDSS_BCR 13
+#define SMMU_ROT_BCR 14
+#define SMMU_MDP_BCR 15
+#define MMAGIC_VIDEO_BCR 16
+#define THROTTLE_VIDEO_BCR 17
+#define SMMU_VIDEO_BCR 18
+#define MMAGIC_BIMC_BCR 19
+#define GPU_GX_BCR 20
+#define GPU_BCR 21
+#define GPU_AON_BCR 22
+#define VMEM_BCR 23
+#define MMSS_RBCPR_BCR 24
+#define VIDEO_BCR 25
+#define MDSS_BCR 26
+#define CAMSS_TOP_BCR 27
+#define CAMSS_AHB_BCR 28
+#define CAMSS_MICRO_BCR 29
+#define CAMSS_CCI_BCR 30
+#define CAMSS_PHY0_BCR 31
+#define CAMSS_PHY1_BCR 32
+#define CAMSS_PHY2_BCR 33
+#define CAMSS_CSIPHY0_3P_BCR 34
+#define CAMSS_CSIPHY1_3P_BCR 35
+#define CAMSS_CSIPHY2_3P_BCR 36
+#define CAMSS_JPEG_BCR 37
+#define CAMSS_VFE_BCR 38
+#define CAMSS_VFE0_BCR 39
+#define CAMSS_VFE1_BCR 40
+#define CAMSS_CSI_VFE0_BCR 41
+#define CAMSS_CSI_VFE1_BCR 42
+#define CAMSS_CPP_TOP_BCR 43
+#define CAMSS_CPP_BCR 44
+#define CAMSS_CSI0_BCR 45
+#define CAMSS_CSI0RDI_BCR 46
+#define CAMSS_CSI0PIX_BCR 47
+#define CAMSS_CSI1_BCR 48
+#define CAMSS_CSI1RDI_BCR 49
+#define CAMSS_CSI1PIX_BCR 50
+#define CAMSS_CSI2_BCR 51
+#define CAMSS_CSI2RDI_BCR 52
+#define CAMSS_CSI2PIX_BCR 53
+#define CAMSS_CSI3_BCR 54
+#define CAMSS_CSI3RDI_BCR 55
+#define CAMSS_CSI3PIX_BCR 56
+#define CAMSS_ISPIF_BCR 57
+#define FD_BCR 58
+#define MMSS_SPDM_RM_BCR 59
+
+#endif
diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h
index dd09b73c4aaf..ffa11379b3f0 100644
--- a/include/dt-bindings/clock/r8a7791-clock.h
+++ b/include/dt-bindings/clock/r8a7791-clock.h
@@ -102,6 +102,7 @@
#define R8A7791_CLK_VIN2 9
#define R8A7791_CLK_VIN1 10
#define R8A7791_CLK_VIN0 11
+#define R8A7791_CLK_ETHERAVB 12
#define R8A7791_CLK_ETHER 13
#define R8A7791_CLK_SATA1 14
#define R8A7791_CLK_SATA0 15
diff --git a/include/dt-bindings/clock/r8a7794-clock.h b/include/dt-bindings/clock/r8a7794-clock.h
index 09da38a58776..a7a7e0370968 100644
--- a/include/dt-bindings/clock/r8a7794-clock.h
+++ b/include/dt-bindings/clock/r8a7794-clock.h
@@ -79,6 +79,7 @@
#define R8A7794_CLK_SCIF2 19
#define R8A7794_CLK_SCIF1 20
#define R8A7794_CLK_SCIF0 21
+#define R8A7794_CLK_DU0 24
/* MSTP8 */
#define R8A7794_CLK_VIN1 10
diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h
new file mode 100644
index 000000000000..ebc7a7b43f52
--- /dev/null
+++ b/include/dt-bindings/clock/rk3036-cru.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3036_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3036_H
+
+/* core clocks */
+#define PLL_APLL 1
+#define PLL_DPLL 2
+#define PLL_GPLL 3
+#define ARMCLK 4
+
+/* sclk gates (special clocks) */
+#define SCLK_GPU 64
+#define SCLK_SPI 65
+#define SCLK_SDMMC 68
+#define SCLK_SDIO 69
+#define SCLK_EMMC 71
+#define SCLK_NANDC 76
+#define SCLK_UART0 77
+#define SCLK_UART1 78
+#define SCLK_UART2 79
+#define SCLK_I2S 82
+#define SCLK_SPDIF 83
+#define SCLK_TIMER0 85
+#define SCLK_TIMER1 86
+#define SCLK_TIMER2 87
+#define SCLK_TIMER3 88
+#define SCLK_OTGPHY0 93
+#define SCLK_LCDC 100
+#define SCLK_HDMI 109
+#define SCLK_HEVC 111
+#define SCLK_I2S_OUT 113
+#define SCLK_SDMMC_DRV 114
+#define SCLK_SDIO_DRV 115
+#define SCLK_EMMC_DRV 117
+#define SCLK_SDMMC_SAMPLE 118
+#define SCLK_SDIO_SAMPLE 119
+#define SCLK_EMMC_SAMPLE 121
+#define SCLK_PVTM_CORE 123
+#define SCLK_PVTM_GPU 124
+#define SCLK_PVTM_VIDEO 125
+#define SCLK_MAC 151
+#define SCLK_MACREF 152
+#define SCLK_SFC 160
+
+/* aclk gates */
+#define ACLK_DMAC2 194
+#define ACLK_LCDC 197
+#define ACLK_VIO 203
+#define ACLK_VCODEC 208
+#define ACLK_CPU 209
+#define ACLK_PERI 210
+
+/* pclk gates */
+#define PCLK_GPIO0 320
+#define PCLK_GPIO1 321
+#define PCLK_GPIO2 322
+#define PCLK_GRF 329
+#define PCLK_I2C0 332
+#define PCLK_I2C1 333
+#define PCLK_I2C2 334
+#define PCLK_SPI 338
+#define PCLK_UART0 341
+#define PCLK_UART1 342
+#define PCLK_UART2 343
+#define PCLK_PWM 350
+#define PCLK_TIMER 353
+#define PCLK_HDMI 360
+#define PCLK_CPU 362
+#define PCLK_PERI 363
+#define PCLK_DDRUPCTL 364
+#define PCLK_WDT 368
+#define PCLK_ACODEC 369
+
+/* hclk gates */
+#define HCLK_OTG0 449
+#define HCLK_OTG1 450
+#define HCLK_NANDC 453
+#define HCLK_SDMMC 456
+#define HCLK_SDIO 457
+#define HCLK_EMMC 459
+#define HCLK_I2S 462
+#define HCLK_LCDC 465
+#define HCLK_ROM 467
+#define HCLK_VIO_BUS 472
+#define HCLK_VCODEC 476
+#define HCLK_CPU 477
+#define HCLK_PERI 478
+
+#define CLK_NR_CLKS (HCLK_PERI + 1)
+
+/* soft-reset indices */
+#define SRST_CORE0 0
+#define SRST_CORE1 1
+#define SRST_CORE0_DBG 4
+#define SRST_CORE1_DBG 5
+#define SRST_CORE0_POR 8
+#define SRST_CORE1_POR 9
+#define SRST_L2C 12
+#define SRST_TOPDBG 13
+#define SRST_STRC_SYS_A 14
+#define SRST_PD_CORE_NIU 15
+
+#define SRST_TIMER2 16
+#define SRST_CPUSYS_H 17
+#define SRST_AHB2APB_H 19
+#define SRST_TIMER3 20
+#define SRST_INTMEM 21
+#define SRST_ROM 22
+#define SRST_PERI_NIU 23
+#define SRST_I2S 24
+#define SRST_DDR_PLL 25
+#define SRST_GPU_DLL 26
+#define SRST_TIMER0 27
+#define SRST_TIMER1 28
+#define SRST_CORE_DLL 29
+#define SRST_EFUSE_P 30
+#define SRST_ACODEC_P 31
+
+#define SRST_GPIO0 32
+#define SRST_GPIO1 33
+#define SRST_GPIO2 34
+#define SRST_UART0 39
+#define SRST_UART1 40
+#define SRST_UART2 41
+#define SRST_I2C0 43
+#define SRST_I2C1 44
+#define SRST_I2C2 45
+#define SRST_SFC 47
+
+#define SRST_PWM0 48
+#define SRST_DAP 51
+#define SRST_DAP_SYS 52
+#define SRST_GRF 55
+#define SRST_PERIPHSYS_A 57
+#define SRST_PERIPHSYS_H 58
+#define SRST_PERIPHSYS_P 59
+#define SRST_CPU_PERI 61
+#define SRST_EMEM_PERI 62
+#define SRST_USB_PERI 63
+
+#define SRST_DMA2 64
+#define SRST_MAC 66
+#define SRST_NANDC 68
+#define SRST_USBOTG0 69
+#define SRST_OTGC0 71
+#define SRST_USBOTG1 72
+#define SRST_OTGC1 74
+#define SRST_DDRMSCH 79
+
+#define SRST_MMC0 81
+#define SRST_SDIO 82
+#define SRST_EMMC 83
+#define SRST_SPI0 84
+#define SRST_WDT 86
+#define SRST_DDRPHY 88
+#define SRST_DDRPHY_P 89
+#define SRST_DDRCTRL 90
+#define SRST_DDRCTRL_P 91
+
+#define SRST_HDMI_P 96
+#define SRST_VIO_BUS_H 99
+#define SRST_UTMI0 103
+#define SRST_UTMI1 104
+#define SRST_USBPOR 105
+
+#define SRST_VCODEC_A 112
+#define SRST_VCODEC_H 113
+#define SRST_VIO1_A 114
+#define SRST_HEVC 115
+#define SRST_VCODEC_NIU_A 116
+#define SRST_LCDC1_A 117
+#define SRST_LCDC1_H 118
+#define SRST_LCDC1_D 119
+#define SRST_GPU 120
+#define SRST_GPU_NIU_A 122
+
+#define SRST_DBG_P 131
+
+#endif
diff --git a/include/dt-bindings/clock/rk3228-cru.h b/include/dt-bindings/clock/rk3228-cru.h
new file mode 100644
index 000000000000..a78dd891e24a
--- /dev/null
+++ b/include/dt-bindings/clock/rk3228-cru.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Jeffy Chen <jeffy.chen@rock-chips.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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3228_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3228_H
+
+/* core clocks */
+#define PLL_APLL 1
+#define PLL_DPLL 2
+#define PLL_CPLL 3
+#define PLL_GPLL 4
+#define ARMCLK 5
+
+/* sclk gates (special clocks) */
+#define SCLK_SPI0 65
+#define SCLK_NANDC 67
+#define SCLK_SDMMC 68
+#define SCLK_SDIO 69
+#define SCLK_EMMC 71
+#define SCLK_UART0 77
+#define SCLK_UART1 78
+#define SCLK_UART2 79
+#define SCLK_I2S0 80
+#define SCLK_I2S1 81
+#define SCLK_I2S2 82
+#define SCLK_SPDIF 83
+#define SCLK_TIMER0 85
+#define SCLK_TIMER1 86
+#define SCLK_TIMER2 87
+#define SCLK_TIMER3 88
+#define SCLK_TIMER4 89
+#define SCLK_TIMER5 90
+#define SCLK_I2S_OUT 113
+#define SCLK_SDMMC_DRV 114
+#define SCLK_SDIO_DRV 115
+#define SCLK_EMMC_DRV 117
+#define SCLK_SDMMC_SAMPLE 118
+#define SCLK_SDIO_SAMPLE 119
+#define SCLK_EMMC_SAMPLE 121
+
+/* aclk gates */
+#define ACLK_DMAC 194
+#define ACLK_PERI 210
+
+/* pclk gates */
+#define PCLK_GPIO0 320
+#define PCLK_GPIO1 321
+#define PCLK_GPIO2 322
+#define PCLK_GPIO3 323
+#define PCLK_GRF 329
+#define PCLK_I2C0 332
+#define PCLK_I2C1 333
+#define PCLK_I2C2 334
+#define PCLK_I2C3 335
+#define PCLK_SPI0 338
+#define PCLK_UART0 341
+#define PCLK_UART1 342
+#define PCLK_UART2 343
+#define PCLK_PWM 350
+#define PCLK_TIMER 353
+#define PCLK_PERI 363
+
+/* hclk gates */
+#define HCLK_NANDC 453
+#define HCLK_SDMMC 456
+#define HCLK_SDIO 457
+#define HCLK_EMMC 459
+#define HCLK_PERI 478
+
+#define CLK_NR_CLKS (HCLK_PERI + 1)
+
+/* soft-reset indices */
+#define SRST_CORE0_PO 0
+#define SRST_CORE1_PO 1
+#define SRST_CORE2_PO 2
+#define SRST_CORE3_PO 3
+#define SRST_CORE0 4
+#define SRST_CORE1 5
+#define SRST_CORE2 6
+#define SRST_CORE3 7
+#define SRST_CORE0_DBG 8
+#define SRST_CORE1_DBG 9
+#define SRST_CORE2_DBG 10
+#define SRST_CORE3_DBG 11
+#define SRST_TOPDBG 12
+#define SRST_ACLK_CORE 13
+#define SRST_NOC 14
+#define SRST_L2C 15
+
+#define SRST_CPUSYS_H 18
+#define SRST_BUSSYS_H 19
+#define SRST_SPDIF 20
+#define SRST_INTMEM 21
+#define SRST_ROM 22
+#define SRST_OTG_ADP 23
+#define SRST_I2S0 24
+#define SRST_I2S1 25
+#define SRST_I2S2 26
+#define SRST_ACODEC_P 27
+#define SRST_DFIMON 28
+#define SRST_MSCH 29
+#define SRST_EFUSE1024 30
+#define SRST_EFUSE256 31
+
+#define SRST_GPIO0 32
+#define SRST_GPIO1 33
+#define SRST_GPIO2 34
+#define SRST_GPIO3 35
+#define SRST_PERIPH_NOC_A 36
+#define SRST_PERIPH_NOC_BUS_H 37
+#define SRST_PERIPH_NOC_P 38
+#define SRST_UART0 39
+#define SRST_UART1 40
+#define SRST_UART2 41
+#define SRST_PHYNOC 42
+#define SRST_I2C0 43
+#define SRST_I2C1 44
+#define SRST_I2C2 45
+#define SRST_I2C3 46
+
+#define SRST_PWM 48
+#define SRST_A53_GIC 49
+#define SRST_DAP 51
+#define SRST_DAP_NOC 52
+#define SRST_CRYPTO 53
+#define SRST_SGRF 54
+#define SRST_GRF 55
+#define SRST_GMAC 56
+#define SRST_PERIPH_NOC_H 58
+#define SRST_MACPHY 63
+
+#define SRST_DMA 64
+#define SRST_NANDC 68
+#define SRST_USBOTG 69
+#define SRST_OTGC 70
+#define SRST_USBHOST0 71
+#define SRST_HOST_CTRL0 72
+#define SRST_USBHOST1 73
+#define SRST_HOST_CTRL1 74
+#define SRST_USBHOST2 75
+#define SRST_HOST_CTRL2 76
+#define SRST_USBPOR0 77
+#define SRST_USBPOR1 78
+#define SRST_DDRMSCH 79
+
+#define SRST_SMART_CARD 80
+#define SRST_SDMMC 81
+#define SRST_SDIO 82
+#define SRST_EMMC 83
+#define SRST_SPI 84
+#define SRST_TSP_H 85
+#define SRST_TSP 86
+#define SRST_TSADC 87
+#define SRST_DDRPHY 88
+#define SRST_DDRPHY_P 89
+#define SRST_DDRCTRL 90
+#define SRST_DDRCTRL_P 91
+#define SRST_HOST0_ECHI 92
+#define SRST_HOST1_ECHI 93
+#define SRST_HOST2_ECHI 94
+#define SRST_VOP_NOC_A 95
+
+#define SRST_HDMI_P 96
+#define SRST_VIO_ARBI_H 97
+#define SRST_IEP_NOC_A 98
+#define SRST_VIO_NOC_H 99
+#define SRST_VOP_A 100
+#define SRST_VOP_H 101
+#define SRST_VOP_D 102
+#define SRST_UTMI0 103
+#define SRST_UTMI1 104
+#define SRST_UTMI2 105
+#define SRST_UTMI3 106
+#define SRST_RGA 107
+#define SRST_RGA_NOC_A 108
+#define SRST_RGA_A 109
+#define SRST_RGA_H 110
+#define SRST_HDCP_A 111
+
+#define SRST_VPU_A 112
+#define SRST_VPU_H 113
+#define SRST_VPU_NOC_A 116
+#define SRST_VPU_NOC_H 117
+#define SRST_RKVDEC_A 118
+#define SRST_RKVDEC_NOC_A 119
+#define SRST_RKVDEC_H 120
+#define SRST_RKVDEC_NOC_H 121
+#define SRST_RKVDEC_CORE 122
+#define SRST_RKVDEC_CABAC 123
+#define SRST_IEP_A 124
+#define SRST_IEP_H 125
+#define SRST_GPU_A 126
+#define SRST_GPU_NOC_A 127
+
+#define SRST_CORE_DBG 128
+#define SRST_DBG_P 129
+#define SRST_TIMER0 130
+#define SRST_TIMER1 131
+#define SRST_TIMER2 132
+#define SRST_TIMER3 133
+#define SRST_TIMER4 134
+#define SRST_TIMER5 135
+#define SRST_VIO_H2P 136
+#define SRST_HDMIPHY 139
+#define SRST_VDAC 140
+#define SRST_TIMER_6CH_P 141
+
+#endif
diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
index c719aacef14f..9a586e2d9c91 100644
--- a/include/dt-bindings/clock/rk3288-cru.h
+++ b/include/dt-bindings/clock/rk3288-cru.h
@@ -86,6 +86,8 @@
#define SCLK_USBPHY480M_SRC 122
#define SCLK_PVTM_CORE 123
#define SCLK_PVTM_GPU 124
+#define SCLK_CRYPTO 125
+#define SCLK_MIPIDSI_24M 126
#define SCLK_MAC 151
#define SCLK_MACREF_OUT 152
@@ -164,6 +166,8 @@
#define PCLK_DDRUPCTL1 366
#define PCLK_PUBL1 367
#define PCLK_WDT 368
+#define PCLK_EFUSE256 369
+#define PCLK_EFUSE1024 370
/* hclk gates */
#define HCLK_GPS 448
diff --git a/include/dt-bindings/clock/sh73a0-clock.h b/include/dt-bindings/clock/sh73a0-clock.h
index 53369568c24c..2eca353a29d7 100644
--- a/include/dt-bindings/clock/sh73a0-clock.h
+++ b/include/dt-bindings/clock/sh73a0-clock.h
@@ -28,7 +28,8 @@
#define SH73A0_CLK_HP 14
/* MSTP0 */
-#define SH73A0_CLK_IIC2 1
+#define SH73A0_CLK_IIC2 1
+#define SH73A0_CLK_MSIOF0 0
/* MSTP1 */
#define SH73A0_CLK_CEU1 29
@@ -45,8 +46,11 @@
#define SH73A0_CLK_SCIFA7 19
#define SH73A0_CLK_SY_DMAC 18
#define SH73A0_CLK_MP_DMAC 17
+#define SH73A0_CLK_MSIOF3 15
+#define SH73A0_CLK_MSIOF1 8
#define SH73A0_CLK_SCIFA5 7
#define SH73A0_CLK_SCIFB 6
+#define SH73A0_CLK_MSIOF2 5
#define SH73A0_CLK_SCIFA0 4
#define SH73A0_CLK_SCIFA1 3
#define SH73A0_CLK_SCIFA2 2
diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
new file mode 100644
index 000000000000..6f45aea49e4f
--- /dev/null
+++ b/include/dt-bindings/clock/tegra210-car.h
@@ -0,0 +1,401 @@
+/*
+ * This header provides constants for binding nvidia,tegra210-car.
+ *
+ * The first 224 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
+ * registers. These IDs often match those in the CAR's RST_DEVICES registers,
+ * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
+ * this case, those clocks are assigned IDs above 224 in order to highlight
+ * this issue. Implementations that interpret these clock IDs as bit values
+ * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
+ * explicitly handle these special cases.
+ *
+ * The balance of the clocks controlled by the CAR are assigned IDs of 224 and
+ * above.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_TEGRA210_CAR_H
+#define _DT_BINDINGS_CLOCK_TEGRA210_CAR_H
+
+/* 0 */
+/* 1 */
+/* 2 */
+#define TEGRA210_CLK_ISPB 3
+#define TEGRA210_CLK_RTC 4
+#define TEGRA210_CLK_TIMER 5
+#define TEGRA210_CLK_UARTA 6
+/* 7 (register bit affects uartb and vfir) */
+#define TEGRA210_CLK_GPIO 8
+#define TEGRA210_CLK_SDMMC2 9
+/* 10 (register bit affects spdif_in and spdif_out) */
+#define TEGRA210_CLK_I2S1 11
+#define TEGRA210_CLK_I2C1 12
+/* 13 */
+#define TEGRA210_CLK_SDMMC1 14
+#define TEGRA210_CLK_SDMMC4 15
+/* 16 */
+#define TEGRA210_CLK_PWM 17
+#define TEGRA210_CLK_I2S2 18
+/* 19 */
+/* 20 (register bit affects vi and vi_sensor) */
+/* 21 */
+#define TEGRA210_CLK_USBD 22
+#define TEGRA210_CLK_ISP 23
+/* 24 */
+/* 25 */
+#define TEGRA210_CLK_DISP2 26
+#define TEGRA210_CLK_DISP1 27
+#define TEGRA210_CLK_HOST1X 28
+/* 29 */
+#define TEGRA210_CLK_I2S0 30
+/* 31 */
+
+#define TEGRA210_CLK_MC 32
+#define TEGRA210_CLK_AHBDMA 33
+#define TEGRA210_CLK_APBDMA 34
+/* 35 */
+/* 36 */
+/* 37 */
+#define TEGRA210_CLK_PMC 38
+/* 39 (register bit affects fuse and fuse_burn) */
+#define TEGRA210_CLK_KFUSE 40
+#define TEGRA210_CLK_SBC1 41
+/* 42 */
+/* 43 */
+#define TEGRA210_CLK_SBC2 44
+/* 45 */
+#define TEGRA210_CLK_SBC3 46
+#define TEGRA210_CLK_I2C5 47
+#define TEGRA210_CLK_DSIA 48
+/* 49 */
+/* 50 */
+/* 51 */
+#define TEGRA210_CLK_CSI 52
+/* 53 */
+#define TEGRA210_CLK_I2C2 54
+#define TEGRA210_CLK_UARTC 55
+#define TEGRA210_CLK_MIPI_CAL 56
+#define TEGRA210_CLK_EMC 57
+#define TEGRA210_CLK_USB2 58
+/* 59 */
+/* 60 */
+/* 61 */
+/* 62 */
+#define TEGRA210_CLK_BSEV 63
+
+/* 64 */
+#define TEGRA210_CLK_UARTD 65
+/* 66 */
+#define TEGRA210_CLK_I2C3 67
+#define TEGRA210_CLK_SBC4 68
+#define TEGRA210_CLK_SDMMC3 69
+#define TEGRA210_CLK_PCIE 70
+#define TEGRA210_CLK_OWR 71
+#define TEGRA210_CLK_AFI 72
+#define TEGRA210_CLK_CSITE 73
+/* 74 */
+/* 75 */
+/* 76 */
+/* 77 */
+#define TEGRA210_CLK_SOC_THERM 78
+#define TEGRA210_CLK_DTV 79
+/* 80 */
+#define TEGRA210_CLK_I2CSLOW 81
+#define TEGRA210_CLK_DSIB 82
+#define TEGRA210_CLK_TSEC 83
+/* 84 */
+/* 85 */
+/* 86 */
+/* 87 */
+/* 88 */
+#define TEGRA210_CLK_XUSB_HOST 89
+/* 90 */
+/* 91 */
+#define TEGRA210_CLK_CSUS 92
+/* 93 */
+/* 94 */
+/* 95 (bit affects xusb_dev and xusb_dev_src) */
+
+/* 96 */
+/* 97 */
+/* 98 */
+#define TEGRA210_CLK_MSELECT 99
+#define TEGRA210_CLK_TSENSOR 100
+#define TEGRA210_CLK_I2S3 101
+#define TEGRA210_CLK_I2S4 102
+#define TEGRA210_CLK_I2C4 103
+/* 104 */
+/* 105 */
+#define TEGRA210_CLK_D_AUDIO 106
+/* 107 ( affects abp -> ape) */
+/* 108 */
+/* 109 */
+/* 110 */
+#define TEGRA210_CLK_HDA2CODEC_2X 111
+/* 112 */
+/* 113 */
+/* 114 */
+/* 115 */
+/* 116 */
+/* 117 */
+#define TEGRA210_CLK_SPDIF_2X 118
+#define TEGRA210_CLK_ACTMON 119
+#define TEGRA210_CLK_EXTERN1 120
+#define TEGRA210_CLK_EXTERN2 121
+#define TEGRA210_CLK_EXTERN3 122
+#define TEGRA210_CLK_SATA_OOB 123
+#define TEGRA210_CLK_SATA 124
+#define TEGRA210_CLK_HDA 125
+/* 126 */
+/* 127 */
+
+#define TEGRA210_CLK_HDA2HDMI 128
+/* 129 */
+/* 130 */
+/* 131 */
+/* 132 */
+/* 133 */
+/* 134 */
+/* 135 */
+/* 136 */
+/* 137 */
+/* 138 */
+/* 139 */
+/* 140 */
+/* 141 */
+/* 142 */
+/* (bit affects xusb_falcon_src, xusb_fs_src, xusb_host_src and xusb_ss_src) */
+#define TEGRA210_CLK_XUSB_GATE 143
+#define TEGRA210_CLK_CILAB 144
+#define TEGRA210_CLK_CILCD 145
+#define TEGRA210_CLK_CILE 146
+#define TEGRA210_CLK_DSIALP 147
+#define TEGRA210_CLK_DSIBLP 148
+#define TEGRA210_CLK_ENTROPY 149
+/* 150 */
+/* 151 */
+/* 152 */
+/* 153 */
+/* 154 */
+/* 155 (bit affects dfll_ref and dfll_soc) */
+#define TEGRA210_CLK_XUSB_SS 156
+/* 157 */
+/* 158 */
+/* 159 */
+
+/* 160 */
+#define TEGRA210_CLK_DMIC1 161
+#define TEGRA210_CLK_DMIC2 162
+/* 163 */
+/* 164 */
+/* 165 */
+#define TEGRA210_CLK_I2C6 166
+/* 167 */
+/* 168 */
+/* 169 */
+/* 170 */
+#define TEGRA210_CLK_VIM2_CLK 171
+/* 172 */
+#define TEGRA210_CLK_MIPIBIF 173
+/* 174 */
+/* 175 */
+/* 176 */
+#define TEGRA210_CLK_CLK72MHZ 177
+#define TEGRA210_CLK_VIC03 178
+/* 179 */
+/* 180 */
+#define TEGRA210_CLK_DPAUX 181
+#define TEGRA210_CLK_SOR0 182
+#define TEGRA210_CLK_SOR1 183
+#define TEGRA210_CLK_GPU 184
+#define TEGRA210_CLK_DBGAPB 185
+/* 186 */
+#define TEGRA210_CLK_PLL_P_OUT_ADSP 187
+/* 188 */
+#define TEGRA210_CLK_PLL_G_REF 189
+/* 190 */
+/* 191 */
+
+/* 192 */
+#define TEGRA210_CLK_SDMMC_LEGACY 193
+#define TEGRA210_CLK_NVDEC 194
+#define TEGRA210_CLK_NVJPG 195
+/* 196 */
+#define TEGRA210_CLK_DMIC3 197
+#define TEGRA210_CLK_APE 198
+/* 199 */
+/* 200 */
+/* 201 */
+#define TEGRA210_CLK_MAUD 202
+/* 203 */
+/* 204 */
+/* 205 */
+#define TEGRA210_CLK_TSECB 206
+#define TEGRA210_CLK_DPAUX1 207
+#define TEGRA210_CLK_VI_I2C 208
+#define TEGRA210_CLK_HSIC_TRK 209
+#define TEGRA210_CLK_USB2_TRK 210
+#define TEGRA210_CLK_QSPI 211
+#define TEGRA210_CLK_UARTAPE 212
+/* 213 */
+/* 214 */
+/* 215 */
+/* 216 */
+/* 217 */
+/* 218 */
+#define TEGRA210_CLK_NVENC 219
+/* 220 */
+/* 221 */
+#define TEGRA210_CLK_SOR_SAFE 222
+#define TEGRA210_CLK_PLL_P_OUT_CPU 223
+
+
+#define TEGRA210_CLK_UARTB 224
+#define TEGRA210_CLK_VFIR 225
+#define TEGRA210_CLK_SPDIF_IN 226
+#define TEGRA210_CLK_SPDIF_OUT 227
+#define TEGRA210_CLK_VI 228
+#define TEGRA210_CLK_VI_SENSOR 229
+#define TEGRA210_CLK_FUSE 230
+#define TEGRA210_CLK_FUSE_BURN 231
+#define TEGRA210_CLK_CLK_32K 232
+#define TEGRA210_CLK_CLK_M 233
+#define TEGRA210_CLK_CLK_M_DIV2 234
+#define TEGRA210_CLK_CLK_M_DIV4 235
+#define TEGRA210_CLK_PLL_REF 236
+#define TEGRA210_CLK_PLL_C 237
+#define TEGRA210_CLK_PLL_C_OUT1 238
+#define TEGRA210_CLK_PLL_C2 239
+#define TEGRA210_CLK_PLL_C3 240
+#define TEGRA210_CLK_PLL_M 241
+#define TEGRA210_CLK_PLL_M_OUT1 242
+#define TEGRA210_CLK_PLL_P 243
+#define TEGRA210_CLK_PLL_P_OUT1 244
+#define TEGRA210_CLK_PLL_P_OUT2 245
+#define TEGRA210_CLK_PLL_P_OUT3 246
+#define TEGRA210_CLK_PLL_P_OUT4 247
+#define TEGRA210_CLK_PLL_A 248
+#define TEGRA210_CLK_PLL_A_OUT0 249
+#define TEGRA210_CLK_PLL_D 250
+#define TEGRA210_CLK_PLL_D_OUT0 251
+#define TEGRA210_CLK_PLL_D2 252
+#define TEGRA210_CLK_PLL_D2_OUT0 253
+#define TEGRA210_CLK_PLL_U 254
+#define TEGRA210_CLK_PLL_U_480M 255
+
+#define TEGRA210_CLK_PLL_U_60M 256
+#define TEGRA210_CLK_PLL_U_48M 257
+/* 258 */
+#define TEGRA210_CLK_PLL_X 259
+#define TEGRA210_CLK_PLL_X_OUT0 260
+#define TEGRA210_CLK_PLL_RE_VCO 261
+#define TEGRA210_CLK_PLL_RE_OUT 262
+#define TEGRA210_CLK_PLL_E 263
+#define TEGRA210_CLK_SPDIF_IN_SYNC 264
+#define TEGRA210_CLK_I2S0_SYNC 265
+#define TEGRA210_CLK_I2S1_SYNC 266
+#define TEGRA210_CLK_I2S2_SYNC 267
+#define TEGRA210_CLK_I2S3_SYNC 268
+#define TEGRA210_CLK_I2S4_SYNC 269
+#define TEGRA210_CLK_VIMCLK_SYNC 270
+#define TEGRA210_CLK_AUDIO0 271
+#define TEGRA210_CLK_AUDIO1 272
+#define TEGRA210_CLK_AUDIO2 273
+#define TEGRA210_CLK_AUDIO3 274
+#define TEGRA210_CLK_AUDIO4 275
+#define TEGRA210_CLK_SPDIF 276
+#define TEGRA210_CLK_CLK_OUT_1 277
+#define TEGRA210_CLK_CLK_OUT_2 278
+#define TEGRA210_CLK_CLK_OUT_3 279
+#define TEGRA210_CLK_BLINK 280
+/* 281 */
+/* 282 */
+/* 283 */
+#define TEGRA210_CLK_XUSB_HOST_SRC 284
+#define TEGRA210_CLK_XUSB_FALCON_SRC 285
+#define TEGRA210_CLK_XUSB_FS_SRC 286
+#define TEGRA210_CLK_XUSB_SS_SRC 287
+
+#define TEGRA210_CLK_XUSB_DEV_SRC 288
+#define TEGRA210_CLK_XUSB_DEV 289
+#define TEGRA210_CLK_XUSB_HS_SRC 290
+#define TEGRA210_CLK_SCLK 291
+#define TEGRA210_CLK_HCLK 292
+#define TEGRA210_CLK_PCLK 293
+#define TEGRA210_CLK_CCLK_G 294
+#define TEGRA210_CLK_CCLK_LP 295
+#define TEGRA210_CLK_DFLL_REF 296
+#define TEGRA210_CLK_DFLL_SOC 297
+#define TEGRA210_CLK_VI_SENSOR2 298
+#define TEGRA210_CLK_PLL_P_OUT5 299
+#define TEGRA210_CLK_CML0 300
+#define TEGRA210_CLK_CML1 301
+#define TEGRA210_CLK_PLL_C4 302
+#define TEGRA210_CLK_PLL_DP 303
+#define TEGRA210_CLK_PLL_E_MUX 304
+#define TEGRA210_CLK_PLL_MB 305
+#define TEGRA210_CLK_PLL_A1 306
+#define TEGRA210_CLK_PLL_D_DSI_OUT 307
+#define TEGRA210_CLK_PLL_C4_OUT0 308
+#define TEGRA210_CLK_PLL_C4_OUT1 309
+#define TEGRA210_CLK_PLL_C4_OUT2 310
+#define TEGRA210_CLK_PLL_C4_OUT3 311
+#define TEGRA210_CLK_PLL_U_OUT 312
+#define TEGRA210_CLK_PLL_U_OUT1 313
+#define TEGRA210_CLK_PLL_U_OUT2 314
+#define TEGRA210_CLK_USB2_HSIC_TRK 315
+#define TEGRA210_CLK_PLL_P_OUT_HSIO 316
+#define TEGRA210_CLK_PLL_P_OUT_XUSB 317
+#define TEGRA210_CLK_XUSB_SSP_SRC 318
+/* 319 */
+/* 320 */
+/* 321 */
+/* 322 */
+/* 323 */
+/* 324 */
+/* 325 */
+/* 326 */
+/* 327 */
+/* 328 */
+/* 329 */
+/* 330 */
+/* 331 */
+/* 332 */
+/* 333 */
+/* 334 */
+/* 335 */
+/* 336 */
+/* 337 */
+/* 338 */
+/* 339 */
+/* 340 */
+/* 341 */
+/* 342 */
+/* 343 */
+/* 344 */
+/* 345 */
+/* 346 */
+/* 347 */
+/* 348 */
+/* 349 */
+
+#define TEGRA210_CLK_AUDIO0_MUX 350
+#define TEGRA210_CLK_AUDIO1_MUX 351
+#define TEGRA210_CLK_AUDIO2_MUX 352
+#define TEGRA210_CLK_AUDIO3_MUX 353
+#define TEGRA210_CLK_AUDIO4_MUX 354
+#define TEGRA210_CLK_SPDIF_MUX 355
+#define TEGRA210_CLK_CLK_OUT_1_MUX 356
+#define TEGRA210_CLK_CLK_OUT_2_MUX 357
+#define TEGRA210_CLK_CLK_OUT_3_MUX 358
+#define TEGRA210_CLK_DSIA_MUX 359
+#define TEGRA210_CLK_DSIB_MUX 360
+#define TEGRA210_CLK_SOR0_LVDS 361
+#define TEGRA210_CLK_XUSB_SS_DIV2 362
+
+#define TEGRA210_CLK_PLL_M_UD 363
+#define TEGRA210_CLK_PLL_C_UD 364
+#define TEGRA210_CLK_SCLK_MUX 365
+
+#define TEGRA210_CLK_CLK_MAX 366
+
+#endif /* _DT_BINDINGS_CLOCK_TEGRA210_CAR_H */
diff --git a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h
index 79fcef72ef57..7958bec7de8c 100644
--- a/include/dt-bindings/leds/common.h
+++ b/include/dt-bindings/leds/common.h
@@ -6,7 +6,7 @@
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
*/
-#ifndef __DT_BINDINGS_LEDS_H__
+#ifndef __DT_BINDINGS_LEDS_H
#define __DT_BINDINGS_LEDS_H
/* External trigger type */
diff --git a/include/dt-bindings/mfd/palmas.h b/include/dt-bindings/mfd/palmas.h
index 2c8ac4841385..cdb075aae4e1 100644
--- a/include/dt-bindings/mfd/palmas.h
+++ b/include/dt-bindings/mfd/palmas.h
@@ -7,7 +7,7 @@
*
*/
-#ifndef __DT_BINDINGS_PALMAS_H__
+#ifndef __DT_BINDINGS_PALMAS_H
#define __DT_BINDINGS_PALMAS_H
/* External control pins */
diff --git a/include/dt-bindings/pinctrl/am43xx.h b/include/dt-bindings/pinctrl/am43xx.h
index 774dc1e843c5..344bd1eb3386 100644
--- a/include/dt-bindings/pinctrl/am43xx.h
+++ b/include/dt-bindings/pinctrl/am43xx.h
@@ -31,5 +31,11 @@
#define PIN_INPUT_PULLUP (INPUT_EN | PULL_UP)
#define PIN_INPUT_PULLDOWN (INPUT_EN)
+/*
+ * Macro to allow using the absolute physical address instead of the
+ * padconf registers instead of the offset from padconf base.
+ */
+#define AM4372_IOPAD(pa, val) (((pa) & 0xffff) - 0x0800) (val)
+
#endif
diff --git a/include/dt-bindings/pinctrl/dm814x.h b/include/dt-bindings/pinctrl/dm814x.h
new file mode 100644
index 000000000000..0f484273da0d
--- /dev/null
+++ b/include/dt-bindings/pinctrl/dm814x.h
@@ -0,0 +1,48 @@
+/*
+ * This header provides constants specific to DM814X pinctrl bindings.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_DM814X_H
+#define _DT_BINDINGS_PINCTRL_DM814X_H
+
+#include <dt-bindings/pinctrl/omap.h>
+
+#undef INPUT_EN
+#undef PULL_UP
+#undef PULL_ENA
+
+/*
+ * Note that dm814x silicon revision 2.1 and older require input enabled
+ * (bit 18 set) for all 3.3V I/Os to avoid cumulative hardware damage. For
+ * more info, see errata advisory 2.1.87. We leave bit 18 out of
+ * function-mask in dm814x.h and rely on the bootloader for it.
+ */
+#define INPUT_EN (1 << 18)
+#define PULL_UP (1 << 17)
+#define PULL_DISABLE (1 << 16)
+
+/* update macro depending on INPUT_EN and PULL_ENA */
+#undef PIN_OUTPUT
+#undef PIN_OUTPUT_PULLUP
+#undef PIN_OUTPUT_PULLDOWN
+#undef PIN_INPUT
+#undef PIN_INPUT_PULLUP
+#undef PIN_INPUT_PULLDOWN
+
+#define PIN_OUTPUT (PULL_DISABLE)
+#define PIN_OUTPUT_PULLUP (PULL_UP)
+#define PIN_OUTPUT_PULLDOWN 0
+#define PIN_INPUT (INPUT_EN | PULL_DISABLE)
+#define PIN_INPUT_PULLUP (INPUT_EN | PULL_UP)
+#define PIN_INPUT_PULLDOWN (INPUT_EN)
+
+/* undef non-existing modes */
+#undef PIN_OFF_NONE
+#undef PIN_OFF_OUTPUT_HIGH
+#undef PIN_OFF_OUTPUT_LOW
+#undef PIN_OFF_INPUT_PULLUP
+#undef PIN_OFF_INPUT_PULLDOWN
+#undef PIN_OFF_WAKEUPENABLE
+
+#endif
+
diff --git a/include/dt-bindings/pinctrl/dra.h b/include/dt-bindings/pinctrl/dra.h
index 4379e29f0460..5c75e80915fc 100644
--- a/include/dt-bindings/pinctrl/dra.h
+++ b/include/dt-bindings/pinctrl/dra.h
@@ -67,5 +67,11 @@
#define PIN_INPUT_PULLUP (PULL_ENA | INPUT_EN | PULL_UP)
#define PIN_INPUT_PULLDOWN (PULL_ENA | INPUT_EN)
+/*
+ * Macro to allow using the absolute physical address instead of the
+ * padconf registers instead of the offset from padconf base.
+ */
+#define DRA7XX_CORE_IOPAD(pa, val) (((pa) & 0xffff) - 0x3400) (val)
+
#endif
diff --git a/include/dt-bindings/pinctrl/omap.h b/include/dt-bindings/pinctrl/omap.h
index 13949259705a..effadd05695b 100644
--- a/include/dt-bindings/pinctrl/omap.h
+++ b/include/dt-bindings/pinctrl/omap.h
@@ -61,10 +61,9 @@
#define OMAP3430_CORE2_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x25d8) (val)
#define OMAP3630_CORE2_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x25a0) (val)
#define OMAP3_WKUP_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x2a00) (val)
+#define DM814X_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
#define DM816X_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
#define AM33XX_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
-#define AM4372_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
-#define DRA7XX_CORE_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x3400) (val)
/*
* Macros to allow using the offset from the padconf physical address
diff --git a/include/dt-bindings/power/raspberrypi-power.h b/include/dt-bindings/power/raspberrypi-power.h
new file mode 100644
index 000000000000..b3ff8e09a78f
--- /dev/null
+++ b/include/dt-bindings/power/raspberrypi-power.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2015 Broadcom
+ *
+ * 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_ARM_BCM2835_RPI_POWER_H
+#define _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H
+
+/* These power domain indices are the firmware interface's indices
+ * minus one.
+ */
+#define RPI_POWER_DOMAIN_I2C0 0
+#define RPI_POWER_DOMAIN_I2C1 1
+#define RPI_POWER_DOMAIN_I2C2 2
+#define RPI_POWER_DOMAIN_VIDEO_SCALER 3
+#define RPI_POWER_DOMAIN_VPU1 4
+#define RPI_POWER_DOMAIN_HDMI 5
+#define RPI_POWER_DOMAIN_USB 6
+#define RPI_POWER_DOMAIN_VEC 7
+#define RPI_POWER_DOMAIN_JPEG 8
+#define RPI_POWER_DOMAIN_H264 9
+#define RPI_POWER_DOMAIN_V3D 10
+#define RPI_POWER_DOMAIN_ISP 11
+#define RPI_POWER_DOMAIN_UNICAM0 12
+#define RPI_POWER_DOMAIN_UNICAM1 13
+#define RPI_POWER_DOMAIN_CCP2RX 14
+#define RPI_POWER_DOMAIN_CSI2 15
+#define RPI_POWER_DOMAIN_CPI 16
+#define RPI_POWER_DOMAIN_DSI0 17
+#define RPI_POWER_DOMAIN_DSI1 18
+#define RPI_POWER_DOMAIN_TRANSPOSER 19
+#define RPI_POWER_DOMAIN_CCP2TX 20
+#define RPI_POWER_DOMAIN_CDP 21
+#define RPI_POWER_DOMAIN_ARM 22
+
+#define RPI_POWER_DOMAIN_COUNT 23
+
+#endif /* _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H */
diff --git a/include/dt-bindings/reset/hisi,hi6220-resets.h b/include/dt-bindings/reset/hisi,hi6220-resets.h
new file mode 100644
index 000000000000..ca08a7e5248e
--- /dev/null
+++ b/include/dt-bindings/reset/hisi,hi6220-resets.h
@@ -0,0 +1,67 @@
+/**
+ * This header provides index for the reset controller
+ * based on hi6220 SoC.
+ */
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_HI6220
+#define _DT_BINDINGS_RESET_CONTROLLER_HI6220
+
+#define PERIPH_RSTDIS0_MMC0 0x000
+#define PERIPH_RSTDIS0_MMC1 0x001
+#define PERIPH_RSTDIS0_MMC2 0x002
+#define PERIPH_RSTDIS0_NANDC 0x003
+#define PERIPH_RSTDIS0_USBOTG_BUS 0x004
+#define PERIPH_RSTDIS0_POR_PICOPHY 0x005
+#define PERIPH_RSTDIS0_USBOTG 0x006
+#define PERIPH_RSTDIS0_USBOTG_32K 0x007
+#define PERIPH_RSTDIS1_HIFI 0x100
+#define PERIPH_RSTDIS1_DIGACODEC 0x105
+#define PERIPH_RSTEN2_IPF 0x200
+#define PERIPH_RSTEN2_SOCP 0x201
+#define PERIPH_RSTEN2_DMAC 0x202
+#define PERIPH_RSTEN2_SECENG 0x203
+#define PERIPH_RSTEN2_ABB 0x204
+#define PERIPH_RSTEN2_HPM0 0x205
+#define PERIPH_RSTEN2_HPM1 0x206
+#define PERIPH_RSTEN2_HPM2 0x207
+#define PERIPH_RSTEN2_HPM3 0x208
+#define PERIPH_RSTEN3_CSSYS 0x300
+#define PERIPH_RSTEN3_I2C0 0x301
+#define PERIPH_RSTEN3_I2C1 0x302
+#define PERIPH_RSTEN3_I2C2 0x303
+#define PERIPH_RSTEN3_I2C3 0x304
+#define PERIPH_RSTEN3_UART1 0x305
+#define PERIPH_RSTEN3_UART2 0x306
+#define PERIPH_RSTEN3_UART3 0x307
+#define PERIPH_RSTEN3_UART4 0x308
+#define PERIPH_RSTEN3_SSP 0x309
+#define PERIPH_RSTEN3_PWM 0x30a
+#define PERIPH_RSTEN3_BLPWM 0x30b
+#define PERIPH_RSTEN3_TSENSOR 0x30c
+#define PERIPH_RSTEN3_DAPB 0x312
+#define PERIPH_RSTEN3_HKADC 0x313
+#define PERIPH_RSTEN3_CODEC_SSI 0x314
+#define PERIPH_RSTEN3_PMUSSI1 0x316
+#define PERIPH_RSTEN8_RS0 0x400
+#define PERIPH_RSTEN8_RS2 0x401
+#define PERIPH_RSTEN8_RS3 0x402
+#define PERIPH_RSTEN8_MS0 0x403
+#define PERIPH_RSTEN8_MS2 0x405
+#define PERIPH_RSTEN8_XG2RAM0 0x406
+#define PERIPH_RSTEN8_X2SRAM_TZMA 0x407
+#define PERIPH_RSTEN8_SRAM 0x408
+#define PERIPH_RSTEN8_HARQ 0x40a
+#define PERIPH_RSTEN8_DDRC 0x40c
+#define PERIPH_RSTEN8_DDRC_APB 0x40d
+#define PERIPH_RSTEN8_DDRPACK_APB 0x40e
+#define PERIPH_RSTEN8_DDRT 0x411
+#define PERIPH_RSDIST9_CARM_DAP 0x500
+#define PERIPH_RSDIST9_CARM_ATB 0x501
+#define PERIPH_RSDIST9_CARM_LBUS 0x502
+#define PERIPH_RSDIST9_CARM_POR 0x503
+#define PERIPH_RSDIST9_CARM_CORE 0x504
+#define PERIPH_RSDIST9_CARM_DBG 0x505
+#define PERIPH_RSDIST9_CARM_L2 0x506
+#define PERIPH_RSDIST9_CARM_SOCDBG 0x507
+#define PERIPH_RSDIST9_CARM_ETM 0x508
+
+#endif /*_DT_BINDINGS_RESET_CONTROLLER_HI6220*/
diff --git a/include/dt-bindings/reset-controller/mt8135-resets.h b/include/dt-bindings/reset/mt8135-resets.h
index 1fb629508db2..1fb629508db2 100644
--- a/include/dt-bindings/reset-controller/mt8135-resets.h
+++ b/include/dt-bindings/reset/mt8135-resets.h
diff --git a/include/dt-bindings/reset-controller/mt8173-resets.h b/include/dt-bindings/reset/mt8173-resets.h
index 9464b37cf68c..9464b37cf68c 100644
--- a/include/dt-bindings/reset-controller/mt8173-resets.h
+++ b/include/dt-bindings/reset/mt8173-resets.h
diff --git a/include/dt-bindings/reset/stih407-resets.h b/include/dt-bindings/reset/stih407-resets.h
index 02d4328fe479..4ab3a1c94958 100644
--- a/include/dt-bindings/reset/stih407-resets.h
+++ b/include/dt-bindings/reset/stih407-resets.h
@@ -52,6 +52,10 @@
#define STIH407_KEYSCAN_SOFTRESET 26
#define STIH407_USB2_PORT0_SOFTRESET 27
#define STIH407_USB2_PORT1_SOFTRESET 28
+#define STIH407_ST231_AUD_SOFTRESET 29
+#define STIH407_ST231_DMU_SOFTRESET 30
+#define STIH407_ST231_GP0_SOFTRESET 31
+#define STIH407_ST231_GP1_SOFTRESET 32
/* Picophy reset defines */
#define STIH407_PICOPHY0_RESET 0
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index b20cd885c1fd..39fd38cfa8c9 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -35,4 +35,28 @@ extern int system_verify_data(const void *data, unsigned long len,
enum key_being_used_for usage);
#endif
+#ifdef CONFIG_IMA_MOK_KEYRING
+extern struct key *ima_mok_keyring;
+extern struct key *ima_blacklist_keyring;
+
+static inline struct key *get_ima_mok_keyring(void)
+{
+ return ima_mok_keyring;
+}
+static inline struct key *get_ima_blacklist_keyring(void)
+{
+ return ima_blacklist_keyring;
+}
+#else
+static inline struct key *get_ima_mok_keyring(void)
+{
+ return NULL;
+}
+static inline struct key *get_ima_blacklist_keyring(void)
+{
+ return NULL;
+}
+#endif /* CONFIG_IMA_MOK_KEYRING */
+
+
#endif /* _KEYS_SYSTEM_KEYRING_H */
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index f91ecd9d1bb1..42cf2d991bf4 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -18,6 +18,7 @@
#define MAX_KEY_SIZE 128
#define MAX_BLOB_SIZE 512
#define MAX_PCRINFO_SIZE 64
+#define MAX_DIGEST_SIZE 64
struct trusted_key_payload {
struct rcu_head rcu;
@@ -36,6 +37,10 @@ struct trusted_key_options {
uint32_t pcrinfo_len;
unsigned char pcrinfo[MAX_PCRINFO_SIZE];
int pcrlock;
+ uint32_t hash;
+ uint32_t digest_len;
+ unsigned char policydigest[MAX_DIGEST_SIZE];
+ uint32_t policyhandle;
};
extern struct key_type key_type_trusted;
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 0ddb5c02ad8b..d76a19ba2cff 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -65,6 +65,24 @@
#define ST_UART011_ABCR 0x100 /* Autobaud control register. */
#define ST_UART011_ABIMSC 0x15C /* Autobaud interrupt mask/clear register. */
+/*
+ * ZTE UART register offsets. This UART has a radically different address
+ * allocation from the ARM and ST variants, so we list all registers here.
+ * We assume unlisted registers do not exist.
+ */
+#define ZX_UART011_DR 0x04
+#define ZX_UART011_FR 0x14
+#define ZX_UART011_IBRD 0x24
+#define ZX_UART011_FBRD 0x28
+#define ZX_UART011_LCRH 0x30
+#define ZX_UART011_CR 0x34
+#define ZX_UART011_IFLS 0x38
+#define ZX_UART011_IMSC 0x40
+#define ZX_UART011_RIS 0x44
+#define ZX_UART011_MIS 0x48
+#define ZX_UART011_ICR 0x4c
+#define ZX_UART011_DMACR 0x50
+
#define UART011_DR_OE (1 << 11)
#define UART011_DR_BE (1 << 10)
#define UART011_DR_PE (1 << 9)
diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h
index 9177947bf032..42a9e1884842 100644
--- a/include/linux/atmel-mci.h
+++ b/include/linux/atmel-mci.h
@@ -2,6 +2,7 @@
#define __LINUX_ATMEL_MCI_H
#include <linux/types.h>
+#include <linux/dmaengine.h>
#define ATMCI_MAX_NR_SLOTS 2
@@ -36,7 +37,8 @@ struct mci_slot_pdata {
* @slot: Per-slot configuration data.
*/
struct mci_platform_data {
- struct mci_dma_data *dma_slave;
+ void *dma_slave;
+ dma_filter_fn dma_filter;
struct mci_slot_pdata slot[ATMCI_MAX_NR_SLOTS];
};
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 20eba1eb0a3c..b40ed5df5542 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -113,6 +113,107 @@ struct filename;
extern void audit_log_session_info(struct audit_buffer *ab);
+#ifdef CONFIG_AUDIT
+/* These are defined in audit.c */
+ /* Public API */
+extern __printf(4, 5)
+void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
+ const char *fmt, ...);
+
+extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type);
+extern __printf(2, 3)
+void audit_log_format(struct audit_buffer *ab, const char *fmt, ...);
+extern void audit_log_end(struct audit_buffer *ab);
+extern bool audit_string_contains_control(const char *string,
+ size_t len);
+extern void audit_log_n_hex(struct audit_buffer *ab,
+ const unsigned char *buf,
+ size_t len);
+extern void audit_log_n_string(struct audit_buffer *ab,
+ const char *buf,
+ size_t n);
+extern void audit_log_n_untrustedstring(struct audit_buffer *ab,
+ const char *string,
+ size_t n);
+extern void audit_log_untrustedstring(struct audit_buffer *ab,
+ const char *string);
+extern void audit_log_d_path(struct audit_buffer *ab,
+ const char *prefix,
+ const struct path *path);
+extern void audit_log_key(struct audit_buffer *ab,
+ char *key);
+extern void audit_log_link_denied(const char *operation,
+ struct path *link);
+extern void audit_log_lost(const char *message);
+#ifdef CONFIG_SECURITY
+extern void audit_log_secctx(struct audit_buffer *ab, u32 secid);
+#else
+static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid)
+{ }
+#endif
+
+extern int audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_task_info(struct audit_buffer *ab,
+ struct task_struct *tsk);
+
+extern int audit_update_lsm_rules(void);
+
+ /* Private API (for audit.c only) */
+extern int audit_filter_user(int type);
+extern int audit_filter_type(int type);
+extern int audit_rule_change(int type, __u32 portid, int seq,
+ void *data, size_t datasz);
+extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
+
+extern u32 audit_enabled;
+#else /* CONFIG_AUDIT */
+static inline __printf(4, 5)
+void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
+ const char *fmt, ...)
+{ }
+static inline struct audit_buffer *audit_log_start(struct audit_context *ctx,
+ gfp_t gfp_mask, int type)
+{
+ return NULL;
+}
+static inline __printf(2, 3)
+void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
+{ }
+static inline void audit_log_end(struct audit_buffer *ab)
+{ }
+static inline void audit_log_n_hex(struct audit_buffer *ab,
+ const unsigned char *buf, size_t len)
+{ }
+static inline void audit_log_n_string(struct audit_buffer *ab,
+ const char *buf, size_t n)
+{ }
+static inline void audit_log_n_untrustedstring(struct audit_buffer *ab,
+ const char *string, size_t n)
+{ }
+static inline void audit_log_untrustedstring(struct audit_buffer *ab,
+ const char *string)
+{ }
+static inline void audit_log_d_path(struct audit_buffer *ab,
+ const char *prefix,
+ const struct path *path)
+{ }
+static inline void audit_log_key(struct audit_buffer *ab, char *key)
+{ }
+static inline void audit_log_link_denied(const char *string,
+ const struct path *link)
+{ }
+static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid)
+{ }
+static inline int audit_log_task_context(struct audit_buffer *ab)
+{
+ return 0;
+}
+static inline void audit_log_task_info(struct audit_buffer *ab,
+ struct task_struct *tsk)
+{ }
+#define audit_enabled 0
+#endif /* CONFIG_AUDIT */
+
#ifdef CONFIG_AUDIT_COMPAT_GENERIC
#define audit_is_compat(arch) (!((arch) & __AUDIT_ARCH_64BIT))
#else
@@ -137,7 +238,7 @@ extern void __audit_getname(struct filename *name);
extern void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int flags);
extern void __audit_file(const struct file *);
-extern void __audit_inode_child(const struct inode *parent,
+extern void __audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type);
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
@@ -202,7 +303,7 @@ static inline void audit_inode_parent_hidden(struct filename *name,
__audit_inode(name, dentry,
AUDIT_INODE_PARENT | AUDIT_INODE_HIDDEN);
}
-static inline void audit_inode_child(const struct inode *parent,
+static inline void audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type) {
if (unlikely(!audit_dummy_context()))
@@ -212,6 +313,9 @@ void audit_core_dumps(long signr);
static inline void audit_seccomp(unsigned long syscall, long signr, int code)
{
+ if (!audit_enabled)
+ return;
+
/* Force a record to be reported if a signal was delivered. */
if (signr || unlikely(!audit_dummy_context()))
__audit_seccomp(syscall, signr, code);
@@ -359,7 +463,7 @@ static inline void __audit_inode(struct filename *name,
const struct dentry *dentry,
unsigned int flags)
{ }
-static inline void __audit_inode_child(const struct inode *parent,
+static inline void __audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type)
{ }
@@ -373,7 +477,7 @@ static inline void audit_file(struct file *file)
static inline void audit_inode_parent_hidden(struct filename *name,
const struct dentry *dentry)
{ }
-static inline void audit_inode_child(const struct inode *parent,
+static inline void audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type)
{ }
@@ -446,106 +550,6 @@ static inline bool audit_loginuid_set(struct task_struct *tsk)
return uid_valid(audit_get_loginuid(tsk));
}
-#ifdef CONFIG_AUDIT
-/* These are defined in audit.c */
- /* Public API */
-extern __printf(4, 5)
-void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
- const char *fmt, ...);
-
-extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type);
-extern __printf(2, 3)
-void audit_log_format(struct audit_buffer *ab, const char *fmt, ...);
-extern void audit_log_end(struct audit_buffer *ab);
-extern bool audit_string_contains_control(const char *string,
- size_t len);
-extern void audit_log_n_hex(struct audit_buffer *ab,
- const unsigned char *buf,
- size_t len);
-extern void audit_log_n_string(struct audit_buffer *ab,
- const char *buf,
- size_t n);
-extern void audit_log_n_untrustedstring(struct audit_buffer *ab,
- const char *string,
- size_t n);
-extern void audit_log_untrustedstring(struct audit_buffer *ab,
- const char *string);
-extern void audit_log_d_path(struct audit_buffer *ab,
- const char *prefix,
- const struct path *path);
-extern void audit_log_key(struct audit_buffer *ab,
- char *key);
-extern void audit_log_link_denied(const char *operation,
- struct path *link);
-extern void audit_log_lost(const char *message);
-#ifdef CONFIG_SECURITY
-extern void audit_log_secctx(struct audit_buffer *ab, u32 secid);
-#else
-static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid)
-{ }
-#endif
-
-extern int audit_log_task_context(struct audit_buffer *ab);
-extern void audit_log_task_info(struct audit_buffer *ab,
- struct task_struct *tsk);
-
-extern int audit_update_lsm_rules(void);
-
- /* Private API (for audit.c only) */
-extern int audit_filter_user(int type);
-extern int audit_filter_type(int type);
-extern int audit_rule_change(int type, __u32 portid, int seq,
- void *data, size_t datasz);
-extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
-
-extern u32 audit_enabled;
-#else /* CONFIG_AUDIT */
-static inline __printf(4, 5)
-void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
- const char *fmt, ...)
-{ }
-static inline struct audit_buffer *audit_log_start(struct audit_context *ctx,
- gfp_t gfp_mask, int type)
-{
- return NULL;
-}
-static inline __printf(2, 3)
-void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
-{ }
-static inline void audit_log_end(struct audit_buffer *ab)
-{ }
-static inline void audit_log_n_hex(struct audit_buffer *ab,
- const unsigned char *buf, size_t len)
-{ }
-static inline void audit_log_n_string(struct audit_buffer *ab,
- const char *buf, size_t n)
-{ }
-static inline void audit_log_n_untrustedstring(struct audit_buffer *ab,
- const char *string, size_t n)
-{ }
-static inline void audit_log_untrustedstring(struct audit_buffer *ab,
- const char *string)
-{ }
-static inline void audit_log_d_path(struct audit_buffer *ab,
- const char *prefix,
- const struct path *path)
-{ }
-static inline void audit_log_key(struct audit_buffer *ab, char *key)
-{ }
-static inline void audit_log_link_denied(const char *string,
- const struct path *link)
-{ }
-static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid)
-{ }
-static inline int audit_log_task_context(struct audit_buffer *ab)
-{
- return 0;
-}
-static inline void audit_log_task_info(struct audit_buffer *ab,
- struct task_struct *tsk)
-{ }
-#define audit_enabled 0
-#endif /* CONFIG_AUDIT */
static inline void audit_log_string(struct audit_buffer *ab, const char *buf)
{
audit_log_n_string(ab, buf, strlen(buf));
diff --git a/include/linux/badblocks.h b/include/linux/badblocks.h
new file mode 100644
index 000000000000..c3bdf8c59480
--- /dev/null
+++ b/include/linux/badblocks.h
@@ -0,0 +1,65 @@
+#ifndef _LINUX_BADBLOCKS_H
+#define _LINUX_BADBLOCKS_H
+
+#include <linux/seqlock.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+#define BB_LEN_MASK (0x00000000000001FFULL)
+#define BB_OFFSET_MASK (0x7FFFFFFFFFFFFE00ULL)
+#define BB_ACK_MASK (0x8000000000000000ULL)
+#define BB_MAX_LEN 512
+#define BB_OFFSET(x) (((x) & BB_OFFSET_MASK) >> 9)
+#define BB_LEN(x) (((x) & BB_LEN_MASK) + 1)
+#define BB_ACK(x) (!!((x) & BB_ACK_MASK))
+#define BB_MAKE(a, l, ack) (((a)<<9) | ((l)-1) | ((u64)(!!(ack)) << 63))
+
+/* Bad block numbers are stored sorted in a single page.
+ * 64bits is used for each block or extent.
+ * 54 bits are sector number, 9 bits are extent size,
+ * 1 bit is an 'acknowledged' flag.
+ */
+#define MAX_BADBLOCKS (PAGE_SIZE/8)
+
+struct badblocks {
+ struct device *dev; /* set by devm_init_badblocks */
+ int count; /* count of bad blocks */
+ int unacked_exist; /* there probably are unacknowledged
+ * bad blocks. This is only cleared
+ * when a read discovers none
+ */
+ int shift; /* shift from sectors to block size
+ * a -ve shift means badblocks are
+ * disabled.*/
+ u64 *page; /* badblock list */
+ int changed;
+ seqlock_t lock;
+ sector_t sector;
+ sector_t size; /* in sectors */
+};
+
+int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
+ sector_t *first_bad, int *bad_sectors);
+int badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+ int acknowledged);
+int badblocks_clear(struct badblocks *bb, sector_t s, int sectors);
+void ack_all_badblocks(struct badblocks *bb);
+ssize_t badblocks_show(struct badblocks *bb, char *page, int unack);
+ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
+ int unack);
+int badblocks_init(struct badblocks *bb, int enable);
+void badblocks_exit(struct badblocks *bb);
+struct device;
+int devm_init_badblocks(struct device *dev, struct badblocks *bb);
+static inline void devm_exit_badblocks(struct device *dev, struct badblocks *bb)
+{
+ if (bb->dev != dev) {
+ dev_WARN_ONCE(dev, 1, "%s: badblocks instance not associated\n",
+ __func__);
+ return;
+ }
+ badblocks_exit(bb);
+}
+#endif
diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h
deleted file mode 100644
index ed3768f4ecc7..000000000000
--- a/include/linux/basic_mmio_gpio.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Basic memory-mapped GPIO controllers.
- *
- * Copyright 2008 MontaVista Software, Inc.
- * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.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 __BASIC_MMIO_GPIO_H
-#define __BASIC_MMIO_GPIO_H
-
-#include <linux/gpio.h>
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/spinlock_types.h>
-
-struct bgpio_pdata {
- const char *label;
- int base;
- int ngpio;
-};
-
-struct device;
-
-struct bgpio_chip {
- struct gpio_chip gc;
-
- unsigned long (*read_reg)(void __iomem *reg);
- void (*write_reg)(void __iomem *reg, unsigned long data);
-
- void __iomem *reg_dat;
- void __iomem *reg_set;
- void __iomem *reg_clr;
- void __iomem *reg_dir;
-
- /* Number of bits (GPIOs): <register width> * 8. */
- int bits;
-
- /*
- * Some GPIO controllers work with the big-endian bits notation,
- * e.g. in a 8-bits register, GPIO7 is the least significant bit.
- */
- unsigned long (*pin2mask)(struct bgpio_chip *bgc, unsigned int pin);
-
- /*
- * Used to lock bgpio_chip->data. Also, this is needed to keep
- * shadowed and real data registers writes together.
- */
- spinlock_t lock;
-
- /* Shadowed data register to clear/set bits safely. */
- unsigned long data;
-
- /* Shadowed direction registers to clear/set direction safely. */
- unsigned long dir;
-};
-
-static inline struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
-{
- return container_of(gc, struct bgpio_chip, gc);
-}
-
-int bgpio_remove(struct bgpio_chip *bgc);
-int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
- unsigned long sz, void __iomem *dat, void __iomem *set,
- void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
- unsigned long flags);
-
-#define BGPIOF_BIG_ENDIAN BIT(0)
-#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */
-#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
-#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3)
-#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
-#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
-
-#endif /* __BASIC_MMIO_GPIO_H */
diff --git a/include/linux/bcm47xx_wdt.h b/include/linux/bcm47xx_wdt.h
index 5582c211f594..8d9d07ec22a5 100644
--- a/include/linux/bcm47xx_wdt.h
+++ b/include/linux/bcm47xx_wdt.h
@@ -1,7 +1,6 @@
#ifndef LINUX_BCM47XX_WDT_H_
#define LINUX_BCM47XX_WDT_H_
-#include <linux/notifier.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/watchdog.h>
@@ -15,8 +14,6 @@ struct bcm47xx_wdt {
void *driver_data;
struct watchdog_device wdd;
- struct notifier_block notifier;
- struct notifier_block restart_handler;
struct timer_list soft_timer;
atomic_t soft_ticks;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index cf038431a5cc..db51a6ffb7d6 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -579,6 +579,8 @@ struct bcma_pflash {
};
#ifdef CONFIG_BCMA_SFLASH
+struct mtd_info;
+
struct bcma_sflash {
bool present;
u32 window;
@@ -592,13 +594,9 @@ struct bcma_sflash {
#endif
#ifdef CONFIG_BCMA_NFLASH
-struct mtd_info;
-
struct bcma_nflash {
bool present;
bool boot; /* This is the flash the SoC boots from */
-
- struct mtd_info *mtd;
};
#endif
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index daf17d70aeca..7fc9296b5742 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -188,8 +188,14 @@ void blk_mq_insert_request(struct request *, bool, bool, bool);
void blk_mq_free_request(struct request *rq);
void blk_mq_free_hctx_request(struct blk_mq_hw_ctx *, struct request *rq);
bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
+
+enum {
+ BLK_MQ_REQ_NOWAIT = (1 << 0), /* return when out of requests */
+ BLK_MQ_REQ_RESERVED = (1 << 1), /* allocate from reserved pool */
+};
+
struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
- gfp_t gfp, bool reserved);
+ unsigned int flags);
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag);
struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c70e3588a48c..d372ea87ead5 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -15,6 +15,7 @@
#include <linux/backing-dev-defs.h>
#include <linux/wait.h>
#include <linux/mempool.h>
+#include <linux/pfn.h>
#include <linux/bio.h>
#include <linux/stringify.h>
#include <linux/gfp.h>
@@ -794,7 +795,7 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
struct scsi_ioctl_command __user *);
-extern int blk_queue_enter(struct request_queue *q, gfp_t gfp);
+extern int blk_queue_enter(struct request_queue *q, bool nowait);
extern void blk_queue_exit(struct request_queue *q);
extern void blk_start_queue(struct request_queue *q);
extern void blk_start_queue_async(struct request_queue *q);
@@ -1617,6 +1618,20 @@ static inline bool integrity_req_gap_front_merge(struct request *req,
#endif /* CONFIG_BLK_DEV_INTEGRITY */
+/**
+ * struct blk_dax_ctl - control and output parameters for ->direct_access
+ * @sector: (input) offset relative to a block_device
+ * @addr: (output) kernel virtual address for @sector populated by driver
+ * @pfn: (output) page frame number for @addr populated by driver
+ * @size: (input) number of bytes requested
+ */
+struct blk_dax_ctl {
+ sector_t sector;
+ void __pmem *addr;
+ long size;
+ pfn_t pfn;
+};
+
struct block_device_operations {
int (*open) (struct block_device *, fmode_t);
void (*release) (struct gendisk *, fmode_t);
@@ -1624,7 +1639,7 @@ struct block_device_operations {
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
long (*direct_access)(struct block_device *, sector_t, void __pmem **,
- unsigned long *pfn);
+ pfn_t *);
unsigned int (*check_events) (struct gendisk *disk,
unsigned int clearing);
/* ->media_changed() is DEPRECATED, use ->check_events() instead */
@@ -1643,8 +1658,7 @@ extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
extern int bdev_read_page(struct block_device *, sector_t, struct page *);
extern int bdev_write_page(struct block_device *, sector_t, struct page *,
struct writeback_control *);
-extern long bdev_direct_access(struct block_device *, sector_t,
- void __pmem **addr, unsigned long *pfn, long size);
+extern long bdev_direct_access(struct block_device *, struct blk_dax_ctl *);
#else /* CONFIG_BLOCK */
struct block_device;
diff --git a/include/linux/capability.h b/include/linux/capability.h
index af9f0b9e80e6..f314275d4e3f 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -145,24 +145,24 @@ static inline kernel_cap_t cap_invert(const kernel_cap_t c)
return dest;
}
-static inline int cap_isclear(const kernel_cap_t a)
+static inline bool cap_isclear(const kernel_cap_t a)
{
unsigned __capi;
CAP_FOR_EACH_U32(__capi) {
if (a.cap[__capi] != 0)
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/*
* Check if "a" is a subset of "set".
- * return 1 if ALL of the capabilities in "a" are also in "set"
- * cap_issubset(0101, 1111) will return 1
- * return 0 if ANY of the capabilities in "a" are not in "set"
- * cap_issubset(1111, 0101) will return 0
+ * return true if ALL of the capabilities in "a" are also in "set"
+ * cap_issubset(0101, 1111) will return true
+ * return false if ANY of the capabilities in "a" are not in "set"
+ * cap_issubset(1111, 0101) will return false
*/
-static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
+static inline bool cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
{
kernel_cap_t dest;
dest = cap_drop(a, set);
@@ -171,12 +171,6 @@ static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
/* Used to decide between falling back on the old suser() or fsuser(). */
-static inline int cap_is_fs_cap(int cap)
-{
- const kernel_cap_t __cap_fs_set = CAP_FS_SET;
- return !!(CAP_TO_MASK(cap) & __cap_fs_set.cap[CAP_TO_INDEX(cap)]);
-}
-
static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a)
{
const kernel_cap_t __cap_fs_set = CAP_FS_SET;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c56988ac63f7..1143e38555a4 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -31,6 +31,7 @@
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
+#define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */
struct clk;
struct clk_hw;
@@ -44,7 +45,7 @@ struct dentry;
* @rate: Requested clock rate. This field will be adjusted by
* clock drivers according to hardware capabilities.
* @min_rate: Minimum rate imposed by clk users.
- * @max_rate: Maximum rate a imposed by clk users.
+ * @max_rate: Maximum rate imposed by clk users.
* @best_parent_rate: The best parent rate a parent can provide to fulfill the
* requested constraints.
* @best_parent_hw: The most appropriate parent clock that fulfills the
@@ -715,8 +716,7 @@ static inline int of_clk_add_provider(struct device_node *np,
{
return 0;
}
-#define of_clk_del_provider(np) \
- { while (0); }
+static inline void of_clk_del_provider(struct device_node *np) {}
static inline struct clk *of_clk_src_simple_get(
struct of_phandle_args *clkspec, void *data)
{
@@ -741,8 +741,7 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
{
return NULL;
}
-#define of_clk_init(matches) \
- { while (0); }
+static inline void of_clk_init(const struct of_device_id *matches) {}
#endif /* CONFIG_OF */
/*
diff --git a/include/linux/clk/mmp.h b/include/linux/clk/mmp.h
new file mode 100644
index 000000000000..607321fa2c2b
--- /dev/null
+++ b/include/linux/clk/mmp.h
@@ -0,0 +1,17 @@
+#ifndef __CLK_MMP_H
+#define __CLK_MMP_H
+
+#include <linux/types.h>
+
+extern void pxa168_clk_init(phys_addr_t mpmu_phys,
+ phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys);
+extern void pxa910_clk_init(phys_addr_t mpmu_phys,
+ phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys,
+ phys_addr_t apbcp_phys);
+extern void mmp2_clk_init(phys_addr_t mpmu_phys,
+ phys_addr_t apmu_phys,
+ phys_addr_t apbc_phys);
+
+#endif
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index 223be696df27..9a638601cb09 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -195,6 +195,7 @@ enum {
TI_CLKM_PRM,
TI_CLKM_SCRM,
TI_CLKM_CTRL,
+ TI_CLKM_PLLSS,
CLK_MAX_MEMMAPS
};
@@ -286,6 +287,7 @@ struct ti_clk_features {
#define TI_CLK_DPLL_HAS_FREQSEL BIT(0)
#define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1)
#define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2)
+#define TI_CLK_ERRATA_I810 BIT(3)
void ti_clk_setup_features(struct ti_clk_features *features);
const struct ti_clk_features *ti_clk_get_features(void);
diff --git a/include/linux/clksrc-dbx500-prcmu.h b/include/linux/clksrc-dbx500-prcmu.h
deleted file mode 100644
index 4fb8119c49e4..000000000000
--- a/include/linux/clksrc-dbx500-prcmu.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * License Terms: GNU General Public License v2
- * Author: Mattias Wallin <mattias.wallin@stericsson.com>
- *
- */
-#ifndef __CLKSRC_DBX500_PRCMU_H
-#define __CLKSRC_DBX500_PRCMU_H
-
-#include <linux/init.h>
-#include <linux/io.h>
-
-#ifdef CONFIG_CLKSRC_DBX500_PRCMU
-void __init clksrc_dbx500_prcmu_init(void __iomem *base);
-#else
-static inline void __init clksrc_dbx500_prcmu_init(void __iomem *base) {}
-#endif
-
-#endif
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index f7300d023dbe..f8165c129ccb 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -259,7 +259,24 @@ void configfs_unregister_default_group(struct config_group *group);
/* These functions can sleep and can alloc with GFP_KERNEL */
/* WARNING: These cannot be called underneath configfs callbacks!! */
-int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target);
-void configfs_undepend_item(struct configfs_subsystem *subsys, struct config_item *target);
+int configfs_depend_item(struct configfs_subsystem *subsys,
+ struct config_item *target);
+void configfs_undepend_item(struct config_item *target);
+
+/*
+ * These functions can sleep and can alloc with GFP_KERNEL
+ * NOTE: These should be called only underneath configfs callbacks.
+ * NOTE: First parameter is a caller's subsystem, not target's.
+ * WARNING: These cannot be called on newly created item
+ * (in make_group()/make_item() callback)
+ */
+int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys,
+ struct config_item *target);
+
+
+static inline void configfs_undepend_item_unlocked(struct config_item *target)
+{
+ configfs_undepend_item(target);
+}
#endif /* _CONFIGFS_H_ */
diff --git a/include/linux/console.h b/include/linux/console.h
index bd194343c346..ea731af2451e 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -150,6 +150,7 @@ extern int console_trylock(void);
extern void console_unlock(void);
extern void console_conditional_schedule(void);
extern void console_unblank(void);
+extern void console_flush_on_panic(void);
extern struct tty_driver *console_device(int *);
extern void console_stop(struct console *);
extern void console_start(struct console *);
diff --git a/include/linux/dca.h b/include/linux/dca.h
index d27a7a05718d..ad956c2e07a8 100644
--- a/include/linux/dca.h
+++ b/include/linux/dca.h
@@ -34,7 +34,7 @@ void dca_unregister_notify(struct notifier_block *nb);
struct dca_provider {
struct list_head node;
- struct dca_ops *ops;
+ const struct dca_ops *ops;
struct device *cd;
int id;
};
@@ -53,7 +53,8 @@ struct dca_ops {
int (*dev_managed) (struct dca_provider *, struct device *);
};
-struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size);
+struct dca_provider *alloc_dca_provider(const struct dca_ops *ops,
+ int priv_size);
void free_dca_provider(struct dca_provider *dca);
int register_dca_provider(struct dca_provider *dca, struct device *dev);
void unregister_dca_provider(struct dca_provider *dca, struct device *dev);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index d67ae119cf4e..7781ce110503 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -27,10 +27,10 @@ struct vfsmount;
/* The hash is always the low bits of hash_len */
#ifdef __LITTLE_ENDIAN
- #define HASH_LEN_DECLARE u32 hash; u32 len;
+ #define HASH_LEN_DECLARE u32 hash; u32 len
#define bytemask_from_count(cnt) (~(~0ul << (cnt)*8))
#else
- #define HASH_LEN_DECLARE u32 len; u32 hash;
+ #define HASH_LEN_DECLARE u32 len; u32 hash
#define bytemask_from_count(cnt) (~(~0ul >> (cnt)*8))
#endif
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c47c68e535e8..16a1cad30c33 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -607,11 +607,38 @@ enum dmaengine_alignment {
};
/**
+ * struct dma_slave_map - associates slave device and it's slave channel with
+ * parameter to be used by a filter function
+ * @devname: name of the device
+ * @slave: slave channel name
+ * @param: opaque parameter to pass to struct dma_filter.fn
+ */
+struct dma_slave_map {
+ const char *devname;
+ const char *slave;
+ void *param;
+};
+
+/**
+ * struct dma_filter - information for slave device/channel to filter_fn/param
+ * mapping
+ * @fn: filter function callback
+ * @mapcnt: number of slave device/channel in the map
+ * @map: array of channel to filter mapping data
+ */
+struct dma_filter {
+ dma_filter_fn fn;
+ int mapcnt;
+ const struct dma_slave_map *map;
+};
+
+/**
* struct dma_device - info on the entity supplying DMA services
* @chancnt: how many DMA channels are supported
* @privatecnt: how many DMA channels are requested by dma_request_channel
* @channels: the list of struct dma_chan
* @global_node: list_head for global dma_device_list
+ * @filter: information for device/slave to filter function/param mapping
* @cap_mask: one or more dma_capability flags
* @max_xor: maximum number of xor sources, 0 if no capability
* @max_pq: maximum number of PQ sources and PQ-continue capability
@@ -654,11 +681,14 @@ enum dmaengine_alignment {
* paused. Returns 0 or an error code
* @device_terminate_all: Aborts all transfers on a channel. Returns 0
* or an error code
+ * @device_synchronize: Synchronizes the termination of a transfers to the
+ * current context.
* @device_tx_status: poll for transaction completion, the optional
* txstate parameter can be supplied with a pointer to get a
* struct with auxiliary transfer status information, otherwise the call
* will just return a simple status code
* @device_issue_pending: push pending transactions to hardware
+ * @descriptor_reuse: a submitted transfer can be resubmitted after completion
*/
struct dma_device {
@@ -666,6 +696,7 @@ struct dma_device {
unsigned int privatecnt;
struct list_head channels;
struct list_head global_node;
+ struct dma_filter filter;
dma_cap_mask_t cap_mask;
unsigned short max_xor;
unsigned short max_pq;
@@ -681,6 +712,7 @@ struct dma_device {
u32 src_addr_widths;
u32 dst_addr_widths;
u32 directions;
+ bool descriptor_reuse;
enum dma_residue_granularity residue_granularity;
int (*device_alloc_chan_resources)(struct dma_chan *chan);
@@ -737,6 +769,7 @@ struct dma_device {
int (*device_pause)(struct dma_chan *chan);
int (*device_resume)(struct dma_chan *chan);
int (*device_terminate_all)(struct dma_chan *chan);
+ void (*device_synchronize)(struct dma_chan *chan);
enum dma_status (*device_tx_status)(struct dma_chan *chan,
dma_cookie_t cookie,
@@ -828,6 +861,13 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_sg(
src_sg, src_nents, flags);
}
+/**
+ * dmaengine_terminate_all() - Terminate all active DMA transfers
+ * @chan: The channel for which to terminate the transfers
+ *
+ * This function is DEPRECATED use either dmaengine_terminate_sync() or
+ * dmaengine_terminate_async() instead.
+ */
static inline int dmaengine_terminate_all(struct dma_chan *chan)
{
if (chan->device->device_terminate_all)
@@ -836,6 +876,88 @@ static inline int dmaengine_terminate_all(struct dma_chan *chan)
return -ENOSYS;
}
+/**
+ * dmaengine_terminate_async() - Terminate all active DMA transfers
+ * @chan: The channel for which to terminate the transfers
+ *
+ * Calling this function will terminate all active and pending descriptors
+ * that have previously been submitted to the channel. It is not guaranteed
+ * though that the transfer for the active descriptor has stopped when the
+ * function returns. Furthermore it is possible the complete callback of a
+ * submitted transfer is still running when this function returns.
+ *
+ * dmaengine_synchronize() needs to be called before it is safe to free
+ * any memory that is accessed by previously submitted descriptors or before
+ * freeing any resources accessed from within the completion callback of any
+ * perviously submitted descriptors.
+ *
+ * This function can be called from atomic context as well as from within a
+ * complete callback of a descriptor submitted on the same channel.
+ *
+ * If none of the two conditions above apply consider using
+ * dmaengine_terminate_sync() instead.
+ */
+static inline int dmaengine_terminate_async(struct dma_chan *chan)
+{
+ if (chan->device->device_terminate_all)
+ return chan->device->device_terminate_all(chan);
+
+ return -EINVAL;
+}
+
+/**
+ * dmaengine_synchronize() - Synchronize DMA channel termination
+ * @chan: The channel to synchronize
+ *
+ * Synchronizes to the DMA channel termination to the current context. When this
+ * function returns it is guaranteed that all transfers for previously issued
+ * descriptors have stopped and and it is safe to free the memory assoicated
+ * with them. Furthermore it is guaranteed that all complete callback functions
+ * for a previously submitted descriptor have finished running and it is safe to
+ * free resources accessed from within the complete callbacks.
+ *
+ * The behavior of this function is undefined if dma_async_issue_pending() has
+ * been called between dmaengine_terminate_async() and this function.
+ *
+ * This function must only be called from non-atomic context and must not be
+ * called from within a complete callback of a descriptor submitted on the same
+ * channel.
+ */
+static inline void dmaengine_synchronize(struct dma_chan *chan)
+{
+ might_sleep();
+
+ if (chan->device->device_synchronize)
+ chan->device->device_synchronize(chan);
+}
+
+/**
+ * dmaengine_terminate_sync() - Terminate all active DMA transfers
+ * @chan: The channel for which to terminate the transfers
+ *
+ * Calling this function will terminate all active and pending transfers
+ * that have previously been submitted to the channel. It is similar to
+ * dmaengine_terminate_async() but guarantees that the DMA transfer has actually
+ * stopped and that all complete callbacks have finished running when the
+ * function returns.
+ *
+ * This function must only be called from non-atomic context and must not be
+ * called from within a complete callback of a descriptor submitted on the same
+ * channel.
+ */
+static inline int dmaengine_terminate_sync(struct dma_chan *chan)
+{
+ int ret;
+
+ ret = dmaengine_terminate_async(chan);
+ if (ret)
+ return ret;
+
+ dmaengine_synchronize(chan);
+
+ return 0;
+}
+
static inline int dmaengine_pause(struct dma_chan *chan)
{
if (chan->device->device_pause)
@@ -1140,9 +1262,11 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
void dma_issue_pending_all(void);
struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
dma_filter_fn fn, void *fn_param);
-struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
- const char *name);
struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
+
+struct dma_chan *dma_request_chan(struct device *dev, const char *name);
+struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
+
void dma_release_channel(struct dma_chan *chan);
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
#else
@@ -1166,16 +1290,21 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
{
return NULL;
}
-static inline struct dma_chan *dma_request_slave_channel_reason(
- struct device *dev, const char *name)
-{
- return ERR_PTR(-ENODEV);
-}
static inline struct dma_chan *dma_request_slave_channel(struct device *dev,
const char *name)
{
return NULL;
}
+static inline struct dma_chan *dma_request_chan(struct device *dev,
+ const char *name)
+{
+ return ERR_PTR(-ENODEV);
+}
+static inline struct dma_chan *dma_request_chan_by_mask(
+ const dma_cap_mask_t *mask)
+{
+ return ERR_PTR(-ENODEV);
+}
static inline void dma_release_channel(struct dma_chan *chan)
{
}
@@ -1186,6 +1315,8 @@ static inline int dma_get_slave_caps(struct dma_chan *chan,
}
#endif
+#define dma_request_slave_channel_reason(dev, name) dma_request_chan(dev, name)
+
static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx)
{
struct dma_slave_caps caps;
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 5055ac34142d..5e9c74cf8894 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -22,6 +22,7 @@ enum dmi_device_type {
DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2,
DMI_DEV_TYPE_DEV_ONBOARD = -3,
+ DMI_DEV_TYPE_DEV_SLOT = -4,
};
enum dmi_entry_type {
diff --git a/include/linux/dqblk_qtree.h b/include/linux/dqblk_qtree.h
index 82a16527b367..ff8b55359648 100644
--- a/include/linux/dqblk_qtree.h
+++ b/include/linux/dqblk_qtree.h
@@ -34,7 +34,7 @@ struct qtree_mem_dqinfo {
unsigned int dqi_entry_size; /* Size of quota entry in quota file */
unsigned int dqi_usable_bs; /* Space usable in block for quota data */
unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */
- struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */
+ const struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */
};
int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
diff --git a/include/linux/err.h b/include/linux/err.h
index a729120644d5..56762ab41713 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -37,7 +37,7 @@ static inline bool __must_check IS_ERR(__force const void *ptr)
static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
{
- return !ptr || IS_ERR_VALUE((unsigned long)ptr);
+ return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
}
/**
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 1fcb88ca88de..35ed9a8a403a 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -14,6 +14,7 @@
struct integrity_iint_cache;
#ifdef CONFIG_EVM
+extern int evm_set_key(void *key, size_t keylen);
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
@@ -42,6 +43,12 @@ static inline int posix_xattr_acl(const char *xattrname)
}
#endif
#else
+
+static inline int evm_set_key(void *key, size_t keylen)
+{
+ return -EOPNOTSUPP;
+}
+
#ifdef CONFIG_INTEGRITY
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 25c6324a0dd0..e59c3be92106 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -51,6 +51,7 @@
#define MAX_ACTIVE_DATA_LOGS 8
#define VERSION_LEN 256
+#define MAX_VOLUME_NAME 512
/*
* For superblock
@@ -84,7 +85,7 @@ struct f2fs_super_block {
__le32 node_ino; /* node inode number */
__le32 meta_ino; /* meta inode number */
__u8 uuid[16]; /* 128-bit uuid for volume */
- __le16 volume_name[512]; /* volume name */
+ __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */
__le32 extension_count; /* # of extensions below */
__u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
__le32 cp_payload;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 3d003805aac3..55433f86f0a3 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -175,9 +175,27 @@ struct fb_blit_caps {
u32 flags;
};
+#ifdef CONFIG_FB_NOTIFY
extern int fb_register_client(struct notifier_block *nb);
extern int fb_unregister_client(struct notifier_block *nb);
extern int fb_notifier_call_chain(unsigned long val, void *v);
+#else
+static inline int fb_register_client(struct notifier_block *nb)
+{
+ return 0;
+};
+
+static inline int fb_unregister_client(struct notifier_block *nb)
+{
+ return 0;
+};
+
+static inline int fb_notifier_call_chain(unsigned long val, void *v)
+{
+ return 0;
+};
+#endif
+
/*
* Pixmap structure definition
*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 731262c3fbb7..eb73d74ed992 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -483,6 +483,9 @@ struct block_device {
int bd_fsfreeze_count;
/* Mutex for freeze */
struct mutex bd_fsfreeze_mutex;
+#ifdef CONFIG_FS_DAX
+ int bd_map_count;
+#endif
};
/*
@@ -2280,6 +2283,14 @@ extern struct super_block *freeze_bdev(struct block_device *);
extern void emergency_thaw_all(void);
extern int thaw_bdev(struct block_device *bdev, struct super_block *sb);
extern int fsync_bdev(struct block_device *);
+#ifdef CONFIG_FS_DAX
+extern bool blkdev_dax_capable(struct block_device *bdev);
+#else
+static inline bool blkdev_dax_capable(struct block_device *bdev)
+{
+ return false;
+}
+#endif
extern struct super_block *blockdev_superblock;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 533c4408529a..6b7e89f45aa4 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -220,7 +220,10 @@ struct fsnotify_mark {
/* List of marks by group->i_fsnotify_marks. Also reused for queueing
* mark into destroy_list when it's waiting for the end of SRCU period
* before it can be freed. [group->mark_mutex] */
- struct list_head g_list;
+ union {
+ struct list_head g_list;
+ struct rcu_head g_rcu;
+ };
/* Protects inode / mnt pointers, flags, masks */
spinlock_t lock;
/* List of marks for inode / vfsmount [obj_lock] */
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index 7ff168d06967..29d4385903d4 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -30,10 +30,12 @@
#ifndef __GENALLOC_H__
#define __GENALLOC_H__
+#include <linux/types.h>
#include <linux/spinlock_types.h>
struct device;
struct device_node;
+struct gen_pool;
/**
* Allocation callback function type definition
@@ -47,7 +49,7 @@ typedef unsigned long (*genpool_algo_t)(unsigned long *map,
unsigned long size,
unsigned long start,
unsigned int nr,
- void *data);
+ void *data, struct gen_pool *pool);
/*
* General purpose special memory pool descriptor.
@@ -75,6 +77,20 @@ struct gen_pool_chunk {
unsigned long bits[0]; /* bitmap for allocating memory chunk */
};
+/*
+ * gen_pool data descriptor for gen_pool_first_fit_align.
+ */
+struct genpool_data_align {
+ int align; /* alignment by bytes for starting address */
+};
+
+/*
+ * gen_pool data descriptor for gen_pool_fixed_alloc.
+ */
+struct genpool_data_fixed {
+ unsigned long offset; /* The offset of the specific region */
+};
+
extern struct gen_pool *gen_pool_create(int, int);
extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
@@ -98,6 +114,8 @@ static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
}
extern void gen_pool_destroy(struct gen_pool *);
extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
+extern unsigned long gen_pool_alloc_algo(struct gen_pool *, size_t,
+ genpool_algo_t algo, void *data);
extern void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size,
dma_addr_t *dma);
extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
@@ -110,14 +128,26 @@ extern void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo,
void *data);
extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
- unsigned long start, unsigned int nr, void *data);
+ unsigned long start, unsigned int nr, void *data,
+ struct gen_pool *pool);
+
+extern unsigned long gen_pool_fixed_alloc(unsigned long *map,
+ unsigned long size, unsigned long start, unsigned int nr,
+ void *data, struct gen_pool *pool);
+
+extern unsigned long gen_pool_first_fit_align(unsigned long *map,
+ unsigned long size, unsigned long start, unsigned int nr,
+ void *data, struct gen_pool *pool);
+
extern unsigned long gen_pool_first_fit_order_align(unsigned long *map,
unsigned long size, unsigned long start, unsigned int nr,
- void *data);
+ void *data, struct gen_pool *pool);
extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
- unsigned long start, unsigned int nr, void *data);
+ unsigned long start, unsigned int nr, void *data,
+ struct gen_pool *pool);
+
extern struct gen_pool *devm_gen_pool_create(struct device *dev,
int min_alloc_order, int nid, const char *name);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 847cc1d91634..5c706765404a 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -162,6 +162,7 @@ struct disk_part_tbl {
};
struct disk_events;
+struct badblocks;
#if defined(CONFIG_BLK_DEV_INTEGRITY)
@@ -213,6 +214,7 @@ struct gendisk {
struct kobject integrity_kobj;
#endif /* CONFIG_BLK_DEV_INTEGRITY */
int node_id;
+ struct badblocks *bb;
};
static inline struct gendisk *part_to_disk(struct hd_struct *part)
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 8942af0813e3..28ad5f6494b0 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -30,7 +30,7 @@ struct vm_area_struct;
#define ___GFP_HARDWALL 0x20000u
#define ___GFP_THISNODE 0x40000u
#define ___GFP_ATOMIC 0x80000u
-#define ___GFP_NOACCOUNT 0x100000u
+#define ___GFP_ACCOUNT 0x100000u
#define ___GFP_NOTRACK 0x200000u
#define ___GFP_DIRECT_RECLAIM 0x400000u
#define ___GFP_OTHER_NODE 0x800000u
@@ -73,11 +73,15 @@ struct vm_area_struct;
*
* __GFP_THISNODE forces the allocation to be satisified from the requested
* node with no fallbacks or placement policy enforcements.
+ *
+ * __GFP_ACCOUNT causes the allocation to be accounted to kmemcg (only relevant
+ * to kmem allocations).
*/
#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE)
#define __GFP_WRITE ((__force gfp_t)___GFP_WRITE)
#define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL)
#define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)
+#define __GFP_ACCOUNT ((__force gfp_t)___GFP_ACCOUNT)
/*
* Watermark modifiers -- controls access to emergency reserves
@@ -104,7 +108,6 @@ struct vm_area_struct;
#define __GFP_HIGH ((__force gfp_t)___GFP_HIGH)
#define __GFP_MEMALLOC ((__force gfp_t)___GFP_MEMALLOC)
#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC)
-#define __GFP_NOACCOUNT ((__force gfp_t)___GFP_NOACCOUNT)
/*
* Reclaim modifiers
@@ -197,6 +200,9 @@ struct vm_area_struct;
* GFP_KERNEL is typical for kernel-internal allocations. The caller requires
* ZONE_NORMAL or a lower zone for direct access but can direct reclaim.
*
+ * GFP_KERNEL_ACCOUNT is the same as GFP_KERNEL, except the allocation is
+ * accounted to kmemcg.
+ *
* GFP_NOWAIT is for kernel allocations that should not stall for direct
* reclaim, start physical IO or use any filesystem callback.
*
@@ -236,6 +242,7 @@ struct vm_area_struct;
*/
#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
+#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)
#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)
#define GFP_NOIO (__GFP_RECLAIM)
#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO)
@@ -271,7 +278,7 @@ static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)
static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
{
- return (bool __force)(gfp_flags & __GFP_DIRECT_RECLAIM);
+ return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
}
#ifdef CONFIG_HIGHMEM
@@ -377,10 +384,11 @@ static inline enum zone_type gfp_zone(gfp_t flags)
static inline int gfp_zonelist(gfp_t flags)
{
- if (IS_ENABLED(CONFIG_NUMA) && unlikely(flags & __GFP_THISNODE))
- return 1;
-
- return 0;
+#ifdef CONFIG_NUMA
+ if (unlikely(flags & __GFP_THISNODE))
+ return ZONELIST_NOFALLBACK;
+#endif
+ return ZONELIST_FALLBACK;
}
/*
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index d1baebf350d8..82fda487453f 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -8,6 +8,7 @@
#include <linux/irqdomain.h>
#include <linux/lockdep.h>
#include <linux/pinctrl/pinctrl.h>
+#include <linux/kconfig.h>
struct device;
struct gpio_desc;
@@ -20,9 +21,10 @@ struct seq_file;
/**
* struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics
- * @dev: optional device providing the GPIOs
+ * @parent: optional parent device providing the GPIOs
* @cdev: class device used by sysfs interface (may be NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
+ * @data: per-instance data assigned by the driver
* @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep
@@ -32,8 +34,7 @@ struct seq_file;
* (same as GPIOF_DIR_XXX), or negative error
* @direction_input: configures signal "offset" as input, or returns error
* @direction_output: configures signal "offset" as output, or returns error
- * @get: returns value for signal "offset"; for output signals this
- * returns either the value actually sensed, or zero
+ * @get: returns value for signal "offset", 0=low, 1=high, or negative error
* @set: assigns output value for signal "offset"
* @set_multiple: assigns output values for multiple signals defined by "mask"
* @set_debounce: optional hook for setting debounce time for specified gpio in
@@ -65,6 +66,23 @@ struct seq_file;
* registers.
* @irq_not_threaded: flag must be set if @can_sleep is set but the
* IRQs don't need to be threaded
+ * @read_reg: reader function for generic GPIO
+ * @write_reg: writer function for generic GPIO
+ * @pin2mask: some generic GPIO controllers work with the big-endian bits
+ * notation, e.g. in a 8-bits register, GPIO7 is the least significant
+ * bit. This callback assigns the right bit mask.
+ * @reg_dat: data (in) register for generic GPIO
+ * @reg_set: output set register (out=high) for generic GPIO
+ * @reg_clk: output clear register (out=low) for generic GPIO
+ * @reg_dir: direction setting register for generic GPIO
+ * @bgpio_bits: number of register bits used for a generic GPIO i.e.
+ * <register width> * 8
+ * @bgpio_lock: used to lock chip->bgpio_data. Also, this is needed to keep
+ * shadowed and real data registers writes together.
+ * @bgpio_data: shadowed data register for generic GPIO to clear/set bits
+ * safely.
+ * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
+ * direction safely.
* @irqchip: GPIO IRQ chip impl, provided by GPIO driver
* @irqdomain: Interrupt translation domain; responsible for mapping
* between GPIO hwirq number and linux irq number
@@ -89,9 +107,10 @@ struct seq_file;
*/
struct gpio_chip {
const char *label;
- struct device *dev;
+ struct device *parent;
struct device *cdev;
struct module *owner;
+ void *data;
struct list_head list;
int (*request)(struct gpio_chip *chip,
@@ -127,6 +146,20 @@ struct gpio_chip {
bool can_sleep;
bool irq_not_threaded;
+#if IS_ENABLED(CONFIG_GPIO_GENERIC)
+ unsigned long (*read_reg)(void __iomem *reg);
+ void (*write_reg)(void __iomem *reg, unsigned long data);
+ unsigned long (*pin2mask)(struct gpio_chip *gc, unsigned int pin);
+ void __iomem *reg_dat;
+ void __iomem *reg_set;
+ void __iomem *reg_clr;
+ void __iomem *reg_dir;
+ int bgpio_bits;
+ spinlock_t bgpio_lock;
+ unsigned long bgpio_data;
+ unsigned long bgpio_dir;
+#endif
+
#ifdef CONFIG_GPIOLIB_IRQCHIP
/*
* With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
@@ -166,7 +199,11 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
unsigned offset);
/* add/remove chips */
-extern int gpiochip_add(struct gpio_chip *chip);
+extern int gpiochip_add_data(struct gpio_chip *chip, void *data);
+static inline int gpiochip_add(struct gpio_chip *chip)
+{
+ return gpiochip_add_data(chip, NULL);
+}
extern void gpiochip_remove(struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));
@@ -175,8 +212,36 @@ extern struct gpio_chip *gpiochip_find(void *data,
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
+/* get driver data */
+static inline void *gpiochip_get_data(struct gpio_chip *chip)
+{
+ return chip->data;
+}
+
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
+struct bgpio_pdata {
+ const char *label;
+ int base;
+ int ngpio;
+};
+
+#if IS_ENABLED(CONFIG_GPIO_GENERIC)
+
+int bgpio_init(struct gpio_chip *gc, struct device *dev,
+ unsigned long sz, void __iomem *dat, void __iomem *set,
+ void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
+ unsigned long flags);
+
+#define BGPIOF_BIG_ENDIAN BIT(0)
+#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */
+#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
+#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3)
+#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
+#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
+
+#endif
+
#ifdef CONFIG_GPIOLIB_IRQCHIP
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 251a1d382e23..75b66eccc692 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -168,6 +168,8 @@ struct hid_item {
#define HID_UP_MSVENDOR 0xff000000
#define HID_UP_CUSTOM 0x00ff0000
#define HID_UP_LOGIVENDOR 0xffbc0000
+#define HID_UP_LOGIVENDOR2 0xff090000
+#define HID_UP_LOGIVENDOR3 0xff430000
#define HID_UP_LNVENDOR 0xffa00000
#define HID_UP_SENSOR 0x00200000
@@ -563,6 +565,9 @@ struct hid_device { /* device report descriptor */
wait_queue_head_t debug_wait;
};
+#define to_hid_device(pdev) \
+ container_of(pdev, struct hid_device, dev)
+
static inline void *hid_get_drvdata(struct hid_device *hdev)
{
return dev_get_drvdata(&hdev->dev);
@@ -712,6 +717,9 @@ struct hid_driver {
struct device_driver driver;
};
+#define to_hid_driver(pdrv) \
+ container_of(pdrv, struct hid_driver, driver)
+
/**
* hid_ll_driver - low level driver callbacks
* @start: called on probe to start the device
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
index 5dd60c2e120f..2790591c77cf 100644
--- a/include/linux/hsi/hsi.h
+++ b/include/linux/hsi/hsi.h
@@ -135,9 +135,6 @@ static inline int hsi_register_board_info(struct hsi_board_info const *info,
* @device: Driver model representation of the device
* @tx_cfg: HSI TX configuration
* @rx_cfg: HSI RX configuration
- * @e_handler: Callback for handling port events (RX Wake High/Low)
- * @pclaimed: Keeps tracks if the clients claimed its associated HSI port
- * @nb: Notifier block for port events
*/
struct hsi_client {
struct device device;
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index ecb080d6ff42..cfe81e10bd54 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -19,13 +19,16 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
unsigned long addr,
pmd_t *pmd,
unsigned int flags);
+extern int madvise_free_huge_pmd(struct mmu_gather *tlb,
+ struct vm_area_struct *vma,
+ pmd_t *pmd, unsigned long addr, unsigned long next);
extern int zap_huge_pmd(struct mmu_gather *tlb,
struct vm_area_struct *vma,
pmd_t *pmd, unsigned long addr);
extern int mincore_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
unsigned long addr, unsigned long end,
unsigned char *vec);
-extern int move_huge_pmd(struct vm_area_struct *vma,
+extern bool move_huge_pmd(struct vm_area_struct *vma,
struct vm_area_struct *new_vma,
unsigned long old_addr,
unsigned long new_addr, unsigned long old_end,
@@ -34,8 +37,7 @@ extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
unsigned long addr, pgprot_t newprot,
int prot_numa);
int vmf_insert_pfn_pmd(struct vm_area_struct *, unsigned long addr, pmd_t *,
- unsigned long pfn, bool write);
-
+ pfn_t pfn, bool write);
enum transparent_hugepage_flag {
TRANSPARENT_HUGEPAGE_FLAG,
TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,
@@ -48,21 +50,13 @@ enum transparent_hugepage_flag {
#endif
};
-enum page_check_address_pmd_flag {
- PAGE_CHECK_ADDRESS_PMD_FLAG,
- PAGE_CHECK_ADDRESS_PMD_NOTSPLITTING_FLAG,
- PAGE_CHECK_ADDRESS_PMD_SPLITTING_FLAG,
-};
-extern pmd_t *page_check_address_pmd(struct page *page,
- struct mm_struct *mm,
- unsigned long address,
- enum page_check_address_pmd_flag flag,
- spinlock_t **ptl);
-
#define HPAGE_PMD_ORDER (HPAGE_PMD_SHIFT-PAGE_SHIFT)
#define HPAGE_PMD_NR (1<<HPAGE_PMD_ORDER)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd, int flags);
+
#define HPAGE_PMD_SHIFT PMD_SHIFT
#define HPAGE_PMD_SIZE ((1UL) << HPAGE_PMD_SHIFT)
#define HPAGE_PMD_MASK (~(HPAGE_PMD_SIZE - 1))
@@ -95,30 +89,28 @@ extern bool is_vma_temporary_stack(struct vm_area_struct *vma);
#endif /* CONFIG_DEBUG_VM */
extern unsigned long transparent_hugepage_flags;
-extern int split_huge_page_to_list(struct page *page, struct list_head *list);
+
+extern void prep_transhuge_page(struct page *page);
+extern void free_transhuge_page(struct page *page);
+
+int split_huge_page_to_list(struct page *page, struct list_head *list);
static inline int split_huge_page(struct page *page)
{
return split_huge_page_to_list(page, NULL);
}
-extern void __split_huge_page_pmd(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmd);
-#define split_huge_page_pmd(__vma, __address, __pmd) \
+void deferred_split_huge_page(struct page *page);
+
+void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long address);
+
+#define split_huge_pmd(__vma, __pmd, __address) \
do { \
pmd_t *____pmd = (__pmd); \
- if (unlikely(pmd_trans_huge(*____pmd))) \
- __split_huge_page_pmd(__vma, __address, \
- ____pmd); \
+ if (pmd_trans_huge(*____pmd) \
+ || pmd_devmap(*____pmd)) \
+ __split_huge_pmd(__vma, __pmd, __address); \
} while (0)
-#define wait_split_huge_page(__anon_vma, __pmd) \
- do { \
- pmd_t *____pmd = (__pmd); \
- anon_vma_lock_write(__anon_vma); \
- anon_vma_unlock_write(__anon_vma); \
- BUG_ON(pmd_trans_splitting(*____pmd) || \
- pmd_trans_huge(*____pmd)); \
- } while (0)
-extern void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address,
- pmd_t *pmd);
+
#if HPAGE_PMD_ORDER >= MAX_ORDER
#error "hugepages can't be allocated by the buddy allocator"
#endif
@@ -128,17 +120,17 @@ extern void vma_adjust_trans_huge(struct vm_area_struct *vma,
unsigned long start,
unsigned long end,
long adjust_next);
-extern int __pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
+extern bool __pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
spinlock_t **ptl);
/* mmap_sem must be held on entry */
-static inline int pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
+static inline bool pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
spinlock_t **ptl)
{
VM_BUG_ON_VMA(!rwsem_is_locked(&vma->vm_mm->mmap_sem), vma);
- if (pmd_trans_huge(*pmd))
+ if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd))
return __pmd_trans_huge_lock(pmd, vma, ptl);
else
- return 0;
+ return false;
}
static inline int hpage_nr_pages(struct page *page)
{
@@ -183,11 +175,8 @@ static inline int split_huge_page(struct page *page)
{
return 0;
}
-#define split_huge_page_pmd(__vma, __address, __pmd) \
- do { } while (0)
-#define wait_split_huge_page(__anon_vma, __pmd) \
- do { } while (0)
-#define split_huge_page_pmd_mm(__mm, __address, __pmd) \
+static inline void deferred_split_huge_page(struct page *page) {}
+#define split_huge_pmd(__vma, __pmd, __address) \
do { } while (0)
static inline int hugepage_madvise(struct vm_area_struct *vma,
unsigned long *vm_flags, int advice)
@@ -201,10 +190,10 @@ static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
long adjust_next)
{
}
-static inline int pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
+static inline bool pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
spinlock_t **ptl)
{
- return 0;
+ return false;
}
static inline int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
@@ -218,6 +207,12 @@ static inline bool is_huge_zero_page(struct page *page)
return false;
}
+
+static inline struct page *follow_devmap_pmd(struct vm_area_struct *vma,
+ unsigned long addr, pmd_t *pmd, int flags)
+{
+ return NULL;
+}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif /* _LINUX_HUGE_MM_H */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index b0eb06423d5e..7d953c2542a8 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -8,6 +8,7 @@
#include <linux/cgroup.h>
#include <linux/list.h>
#include <linux/kref.h>
+#include <asm/pgtable.h>
struct ctl_table;
struct user_struct;
@@ -263,20 +264,18 @@ struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
struct user_struct **user, int creat_flags,
int page_size_log);
-static inline int is_file_hugepages(struct file *file)
+static inline bool is_file_hugepages(struct file *file)
{
if (file->f_op == &hugetlbfs_file_operations)
- return 1;
- if (is_file_shm_hugepages(file))
- return 1;
+ return true;
- return 0;
+ return is_file_shm_hugepages(file);
}
#else /* !CONFIG_HUGETLBFS */
-#define is_file_hugepages(file) 0
+#define is_file_hugepages(file) false
static inline struct file *
hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
struct user_struct **user, int creat_flags,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 8fdc17b84739..753dbad0bf94 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -141,8 +141,6 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
{
u32 read_loc, write_loc, dsize;
- smp_read_barrier_depends();
-
/* Capture the read/write indices before they changed */
read_loc = rbi->ring_buffer->read_index;
write_loc = rbi->ring_buffer->write_index;
@@ -630,6 +628,11 @@ struct hv_input_signal_event_buffer {
struct hv_input_signal_event event;
};
+enum hv_signal_policy {
+ HV_SIGNAL_POLICY_DEFAULT = 0,
+ HV_SIGNAL_POLICY_EXPLICIT,
+};
+
struct vmbus_channel {
/* Unique channel id */
int id;
@@ -757,8 +760,21 @@ struct vmbus_channel {
* link up channels based on their CPU affinity.
*/
struct list_head percpu_list;
+ /*
+ * Host signaling policy: The default policy will be
+ * based on the ring buffer state. We will also support
+ * a policy where the client driver can have explicit
+ * signaling control.
+ */
+ enum hv_signal_policy signal_policy;
};
+static inline void set_channel_signal_state(struct vmbus_channel *c,
+ enum hv_signal_policy policy)
+{
+ c->signal_policy = policy;
+}
+
static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
{
c->batched_reading = state;
@@ -983,16 +999,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
resource_size_t size, resource_size_t align,
bool fb_overlap_ok);
-/**
- * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device
- *
- * This macro is used to create a struct hv_vmbus_device_id that matches a
- * specific device.
- */
-#define VMBUS_DEVICE(g0, g1, g2, g3, g4, g5, g6, g7, \
- g8, g9, ga, gb, gc, gd, ge, gf) \
- .guid = { g0, g1, g2, g3, g4, g5, g6, g7, \
- g8, g9, ga, gb, gc, gd, ge, gf },
+int vmbus_cpu_number_to_vp_number(int cpu_number);
+u64 hv_do_hypercall(u64 control, void *input, void *output);
/*
* GUID definitions of various offer types - services offered to the guest.
@@ -1003,118 +1011,102 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
* {f8615163-df3e-46c5-913f-f2d2f965ed0e}
*/
#define HV_NIC_GUID \
- .guid = { \
- 0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, \
- 0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e \
- }
+ .guid = UUID_LE(0xf8615163, 0xdf3e, 0x46c5, 0x91, 0x3f, \
+ 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e)
/*
* IDE GUID
* {32412632-86cb-44a2-9b5c-50d1417354f5}
*/
#define HV_IDE_GUID \
- .guid = { \
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, \
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 \
- }
+ .guid = UUID_LE(0x32412632, 0x86cb, 0x44a2, 0x9b, 0x5c, \
+ 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5)
/*
* SCSI GUID
* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
*/
#define HV_SCSI_GUID \
- .guid = { \
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, \
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f \
- }
+ .guid = UUID_LE(0xba6163d9, 0x04a1, 0x4d29, 0xb6, 0x05, \
+ 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f)
/*
* Shutdown GUID
* {0e0b6031-5213-4934-818b-38d90ced39db}
*/
#define HV_SHUTDOWN_GUID \
- .guid = { \
- 0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, \
- 0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb \
- }
+ .guid = UUID_LE(0x0e0b6031, 0x5213, 0x4934, 0x81, 0x8b, \
+ 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb)
/*
* Time Synch GUID
* {9527E630-D0AE-497b-ADCE-E80AB0175CAF}
*/
#define HV_TS_GUID \
- .guid = { \
- 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, \
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf \
- }
+ .guid = UUID_LE(0x9527e630, 0xd0ae, 0x497b, 0xad, 0xce, \
+ 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)
/*
* Heartbeat GUID
* {57164f39-9115-4e78-ab55-382f3bd5422d}
*/
#define HV_HEART_BEAT_GUID \
- .guid = { \
- 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, \
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d \
- }
+ .guid = UUID_LE(0x57164f39, 0x9115, 0x4e78, 0xab, 0x55, \
+ 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)
/*
* KVP GUID
* {a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}
*/
#define HV_KVP_GUID \
- .guid = { \
- 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d, \
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6 \
- }
+ .guid = UUID_LE(0xa9a0f4e7, 0x5a45, 0x4d96, 0xb8, 0x27, \
+ 0x8a, 0x84, 0x1e, 0x8c, 0x03, 0xe6)
/*
* Dynamic memory GUID
* {525074dc-8985-46e2-8057-a307dc18a502}
*/
#define HV_DM_GUID \
- .guid = { \
- 0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, \
- 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02 \
- }
+ .guid = UUID_LE(0x525074dc, 0x8985, 0x46e2, 0x80, 0x57, \
+ 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02)
/*
* Mouse GUID
* {cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}
*/
#define HV_MOUSE_GUID \
- .guid = { \
- 0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c, \
- 0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a \
- }
+ .guid = UUID_LE(0xcfa8b69e, 0x5b4a, 0x4cc0, 0xb9, 0x8b, \
+ 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a)
+
+/*
+ * Keyboard GUID
+ * {f912ad6d-2b17-48ea-bd65-f927a61c7684}
+ */
+#define HV_KBD_GUID \
+ .guid = UUID_LE(0xf912ad6d, 0x2b17, 0x48ea, 0xbd, 0x65, \
+ 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84)
/*
* VSS (Backup/Restore) GUID
*/
#define HV_VSS_GUID \
- .guid = { \
- 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \
- 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40 \
- }
+ .guid = UUID_LE(0x35fa2e29, 0xea23, 0x4236, 0x96, 0xae, \
+ 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40)
/*
* Synthetic Video GUID
* {DA0A7802-E377-4aac-8E77-0558EB1073F8}
*/
#define HV_SYNTHVID_GUID \
- .guid = { \
- 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \
- 0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
- }
+ .guid = UUID_LE(0xda0a7802, 0xe377, 0x4aac, 0x8e, 0x77, \
+ 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8)
/*
* Synthetic FC GUID
* {2f9bcc4a-0069-4af3-b76b-6fd0be528cda}
*/
#define HV_SYNTHFC_GUID \
- .guid = { \
- 0x4A, 0xCC, 0x9B, 0x2F, 0x69, 0x00, 0xF3, 0x4A, \
- 0xB7, 0x6B, 0x6F, 0xD0, 0xBE, 0x52, 0x8C, 0xDA \
- }
+ .guid = UUID_LE(0x2f9bcc4a, 0x0069, 0x4af3, 0xb7, 0x6b, \
+ 0x6f, 0xd0, 0xbe, 0x52, 0x8c, 0xda)
/*
* Guest File Copy Service
@@ -1122,20 +1114,25 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
*/
#define HV_FCOPY_GUID \
- .guid = { \
- 0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \
- 0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \
- }
+ .guid = UUID_LE(0x34d14be3, 0xdee4, 0x41c8, 0x9a, 0xe7, \
+ 0x6b, 0x17, 0x49, 0x77, 0xc1, 0x92)
/*
* NetworkDirect. This is the guest RDMA service.
* {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}
*/
#define HV_ND_GUID \
- .guid = { \
- 0x3d, 0xaf, 0x2e, 0x8c, 0xa7, 0x32, 0x09, 0x4b, \
- 0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \
- }
+ .guid = UUID_LE(0x8c2eaf3d, 0x32a7, 0x4b09, 0xab, 0x99, \
+ 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01)
+
+/*
+ * PCI Express Pass Through
+ * {44C4F61D-4444-4400-9D52-802E27EDE19F}
+ */
+
+#define HV_PCIE_GUID \
+ .guid = UUID_LE(0x44c4f61d, 0x4444, 0x4400, 0x9d, 0x52, \
+ 0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)
/*
* Common header for Hyper-V ICs
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 768063baafbf..200cf13b00f6 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -414,6 +414,22 @@ struct i2c_algorithm {
};
/**
+ * struct i2c_timings - I2C timing information
+ * @bus_freq_hz: the bus frequency in Hz
+ * @scl_rise_ns: time SCL signal takes to rise in ns; t(r) in the I2C specification
+ * @scl_fall_ns: time SCL signal takes to fall in ns; t(f) in the I2C specification
+ * @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns
+ * @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification
+ */
+struct i2c_timings {
+ u32 bus_freq_hz;
+ u32 scl_rise_ns;
+ u32 scl_fall_ns;
+ u32 scl_int_delay_ns;
+ u32 sda_fall_ns;
+};
+
+/**
* struct i2c_bus_recovery_info - I2C bus recovery information
* @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or
* i2c_generic_scl_recovery() or i2c_generic_gpio_recovery().
@@ -493,6 +509,8 @@ struct i2c_adapter_quirks {
/* convenience macro for typical write-then read case */
#define I2C_AQ_COMB_WRITE_THEN_READ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \
I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
+/* clock stretching is not supported */
+#define I2C_AQ_NO_CLK_STRETCH BIT(4)
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
@@ -602,6 +620,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap,
extern struct i2c_adapter *i2c_get_adapter(int nr);
extern void i2c_put_adapter(struct i2c_adapter *adap);
+void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults);
/* Return the functionality mask */
static inline u32 i2c_get_functionality(struct i2c_adapter *adap)
@@ -615,6 +634,20 @@ static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
return (func & i2c_get_functionality(adap)) == func;
}
+/**
+ * i2c_check_quirks() - Function for checking the quirk flags in an i2c adapter
+ * @adap: i2c adapter
+ * @quirks: quirk flags
+ *
+ * Return: true if the adapter has all the specified quirk flags, false if not
+ */
+static inline bool i2c_check_quirks(struct i2c_adapter *adap, u64 quirks)
+{
+ if (!adap->quirks)
+ return false;
+ return (adap->quirks->flags & quirks) == quirks;
+}
+
/* Return the adapter number for a specific adapter */
static inline int i2c_adapter_id(struct i2c_adapter *adap)
{
@@ -622,7 +655,7 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
}
/**
- * module_i2c_driver() - Helper macro for registering a I2C driver
+ * module_i2c_driver() - Helper macro for registering a modular I2C driver
* @__i2c_driver: i2c_driver struct
*
* Helper macro for I2C drivers which do not do anything special in module
@@ -633,6 +666,17 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
module_driver(__i2c_driver, i2c_add_driver, \
i2c_del_driver)
+/**
+ * builtin_i2c_driver() - Helper macro for registering a builtin I2C driver
+ * @__i2c_driver: i2c_driver struct
+ *
+ * Helper macro for I2C drivers which do not do anything special in their
+ * init. This eliminates a lot of boilerplate. Each driver may only
+ * use this macro once, and calling it replaces device_initcall().
+ */
+#define builtin_i2c_driver(__i2c_driver) \
+ builtin_driver(__i2c_driver, i2c_add_driver)
+
#endif /* I2C */
#if IS_ENABLED(CONFIG_OF)
@@ -644,6 +688,7 @@ extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
/* must call i2c_put_adapter() when done with returned i2c_adapter device */
struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node);
+
#else
static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h
new file mode 100644
index 000000000000..767467d886de
--- /dev/null
+++ b/include/linux/iio/buffer-dma.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2013-2015 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __INDUSTRIALIO_DMA_BUFFER_H__
+#define __INDUSTRIALIO_DMA_BUFFER_H__
+
+#include <linux/list.h>
+#include <linux/kref.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/iio/buffer.h>
+
+struct iio_dma_buffer_queue;
+struct iio_dma_buffer_ops;
+struct device;
+
+struct iio_buffer_block {
+ u32 size;
+ u32 bytes_used;
+};
+
+/**
+ * enum iio_block_state - State of a struct iio_dma_buffer_block
+ * @IIO_BLOCK_STATE_DEQUEUED: Block is not queued
+ * @IIO_BLOCK_STATE_QUEUED: Block is on the incoming queue
+ * @IIO_BLOCK_STATE_ACTIVE: Block is currently being processed by the DMA
+ * @IIO_BLOCK_STATE_DONE: Block is on the outgoing queue
+ * @IIO_BLOCK_STATE_DEAD: Block has been marked as to be freed
+ */
+enum iio_block_state {
+ IIO_BLOCK_STATE_DEQUEUED,
+ IIO_BLOCK_STATE_QUEUED,
+ IIO_BLOCK_STATE_ACTIVE,
+ IIO_BLOCK_STATE_DONE,
+ IIO_BLOCK_STATE_DEAD,
+};
+
+/**
+ * struct iio_dma_buffer_block - IIO buffer block
+ * @head: List head
+ * @size: Total size of the block in bytes
+ * @bytes_used: Number of bytes that contain valid data
+ * @vaddr: Virutal address of the blocks memory
+ * @phys_addr: Physical address of the blocks memory
+ * @queue: Parent DMA buffer queue
+ * @kref: kref used to manage the lifetime of block
+ * @state: Current state of the block
+ */
+struct iio_dma_buffer_block {
+ /* May only be accessed by the owner of the block */
+ struct list_head head;
+ size_t bytes_used;
+
+ /*
+ * Set during allocation, constant thereafter. May be accessed read-only
+ * by anybody holding a reference to the block.
+ */
+ void *vaddr;
+ dma_addr_t phys_addr;
+ size_t size;
+ struct iio_dma_buffer_queue *queue;
+
+ /* Must not be accessed outside the core. */
+ struct kref kref;
+ /*
+ * Must not be accessed outside the core. Access needs to hold
+ * queue->list_lock if the block is not owned by the core.
+ */
+ enum iio_block_state state;
+};
+
+/**
+ * struct iio_dma_buffer_queue_fileio - FileIO state for the DMA buffer
+ * @blocks: Buffer blocks used for fileio
+ * @active_block: Block being used in read()
+ * @pos: Read offset in the active block
+ * @block_size: Size of each block
+ */
+struct iio_dma_buffer_queue_fileio {
+ struct iio_dma_buffer_block *blocks[2];
+ struct iio_dma_buffer_block *active_block;
+ size_t pos;
+ size_t block_size;
+};
+
+/**
+ * struct iio_dma_buffer_queue - DMA buffer base structure
+ * @buffer: IIO buffer base structure
+ * @dev: Parent device
+ * @ops: DMA buffer callbacks
+ * @lock: Protects the incoming list, active and the fields in the fileio
+ * substruct
+ * @list_lock: Protects lists that contain blocks which can be modified in
+ * atomic context as well as blocks on those lists. This is the outgoing queue
+ * list and typically also a list of active blocks in the part that handles
+ * the DMA controller
+ * @incoming: List of buffers on the incoming queue
+ * @outgoing: List of buffers on the outgoing queue
+ * @active: Whether the buffer is currently active
+ * @fileio: FileIO state
+ */
+struct iio_dma_buffer_queue {
+ struct iio_buffer buffer;
+ struct device *dev;
+ const struct iio_dma_buffer_ops *ops;
+
+ struct mutex lock;
+ spinlock_t list_lock;
+ struct list_head incoming;
+ struct list_head outgoing;
+
+ bool active;
+
+ struct iio_dma_buffer_queue_fileio fileio;
+};
+
+/**
+ * struct iio_dma_buffer_ops - DMA buffer callback operations
+ * @submit: Called when a block is submitted to the DMA controller
+ * @abort: Should abort all pending transfers
+ */
+struct iio_dma_buffer_ops {
+ int (*submit)(struct iio_dma_buffer_queue *queue,
+ struct iio_dma_buffer_block *block);
+ void (*abort)(struct iio_dma_buffer_queue *queue);
+};
+
+void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block);
+void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue,
+ struct list_head *list);
+
+int iio_dma_buffer_enable(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev);
+int iio_dma_buffer_disable(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev);
+int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n,
+ char __user *user_buffer);
+size_t iio_dma_buffer_data_available(struct iio_buffer *buffer);
+int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd);
+int iio_dma_buffer_set_length(struct iio_buffer *buffer, int length);
+int iio_dma_buffer_request_update(struct iio_buffer *buffer);
+
+int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue,
+ struct device *dma_dev, const struct iio_dma_buffer_ops *ops);
+void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue);
+void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue);
+
+#endif
diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h
new file mode 100644
index 000000000000..5dcddf427bb0
--- /dev/null
+++ b/include/linux/iio/buffer-dmaengine.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2014-2015 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __IIO_DMAENGINE_H__
+#define __IIO_DMAENGINE_H__
+
+struct iio_buffer;
+struct device;
+
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+ const char *channel);
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer);
+
+#endif
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index 1600c55828e0..2ec3ad58e8a0 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -18,6 +18,12 @@
struct iio_buffer;
/**
+ * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be
+ * configured. It has a fixed value which will be buffer specific.
+ */
+#define INDIO_BUFFER_FLAG_FIXED_WATERMARK BIT(0)
+
+/**
* struct iio_buffer_access_funcs - access functions for buffers.
* @store_to: actually store stuff to the buffer
* @read_first_n: try to get a specified number of bytes (must exist)
@@ -27,9 +33,15 @@ struct iio_buffer;
* storage.
* @set_bytes_per_datum:set number of bytes per datum
* @set_length: set number of datums in buffer
+ * @enable: called if the buffer is attached to a device and the
+ * device starts sampling. Calls are balanced with
+ * @disable.
+ * @disable: called if the buffer is attached to a device and the
+ * device stops sampling. Calles are balanced with @enable.
* @release: called when the last reference to the buffer is dropped,
* should free all resources allocated by the buffer.
* @modes: Supported operating modes by this buffer type
+ * @flags: A bitmask combination of INDIO_BUFFER_FLAG_*
*
* The purpose of this structure is to make the buffer element
* modular as event for a given driver, different usecases may require
@@ -51,9 +63,13 @@ struct iio_buffer_access_funcs {
int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
int (*set_length)(struct iio_buffer *buffer, int length);
+ int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
+ int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
+
void (*release)(struct iio_buffer *buffer);
unsigned int modes;
+ unsigned int flags;
};
/**
diff --git a/include/linux/iio/configfs.h b/include/linux/iio/configfs.h
new file mode 100644
index 000000000000..93befd67c15c
--- /dev/null
+++ b/include/linux/iio/configfs.h
@@ -0,0 +1,15 @@
+/*
+ * Industrial I/O configfs support
+ *
+ * Copyright (c) 2015 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 published by
+ * the Free Software Foundation.
+ */
+#ifndef __IIO_CONFIGFS
+#define __IIO_CONFIGFS
+
+extern struct configfs_subsystem iio_configfs_subsys;
+
+#endif /* __IIO_CONFIGFS */
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 19c94c9acc81..b5894118755f 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -636,6 +636,8 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
}
#endif
+ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
+
int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
int *fract);
diff --git a/include/linux/iio/sw_trigger.h b/include/linux/iio/sw_trigger.h
new file mode 100644
index 000000000000..5198f8ed08a4
--- /dev/null
+++ b/include/linux/iio/sw_trigger.h
@@ -0,0 +1,70 @@
+/*
+ * Industrial I/O software trigger interface
+ *
+ * Copyright (c) 2015 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 published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __IIO_SW_TRIGGER
+#define __IIO_SW_TRIGGER
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/configfs.h>
+
+#define module_iio_sw_trigger_driver(__iio_sw_trigger_type) \
+ module_driver(__iio_sw_trigger_type, iio_register_sw_trigger_type, \
+ iio_unregister_sw_trigger_type)
+
+struct iio_sw_trigger_ops;
+
+struct iio_sw_trigger_type {
+ const char *name;
+ struct module *owner;
+ const struct iio_sw_trigger_ops *ops;
+ struct list_head list;
+ struct config_group *group;
+};
+
+struct iio_sw_trigger {
+ struct iio_trigger *trigger;
+ struct iio_sw_trigger_type *trigger_type;
+ struct config_group group;
+};
+
+struct iio_sw_trigger_ops {
+ struct iio_sw_trigger* (*probe)(const char *);
+ int (*remove)(struct iio_sw_trigger *);
+};
+
+static inline
+struct iio_sw_trigger *to_iio_sw_trigger(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct iio_sw_trigger,
+ group);
+}
+
+int iio_register_sw_trigger_type(struct iio_sw_trigger_type *tt);
+void iio_unregister_sw_trigger_type(struct iio_sw_trigger_type *tt);
+
+struct iio_sw_trigger *iio_sw_trigger_create(const char *, const char *);
+void iio_sw_trigger_destroy(struct iio_sw_trigger *);
+
+int iio_sw_trigger_type_configfs_register(struct iio_sw_trigger_type *tt);
+void iio_sw_trigger_type_configfs_unregister(struct iio_sw_trigger_type *tt);
+
+static inline
+void iio_swt_group_init_type_name(struct iio_sw_trigger *t,
+ const char *name,
+ struct config_item_type *type)
+{
+#ifdef CONFIG_CONFIGFS_FS
+ config_group_init_type_name(&t->group, name, type);
+#endif
+}
+
+#endif /* __IIO_SW_TRIGGER */
diff --git a/include/linux/io.h b/include/linux/io.h
index de64c1e53612..fffd88d7f426 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -89,21 +89,6 @@ void devm_memunmap(struct device *dev, void *addr);
void *__devm_memremap_pages(struct device *dev, struct resource *res);
-#ifdef CONFIG_ZONE_DEVICE
-void *devm_memremap_pages(struct device *dev, struct resource *res);
-#else
-static inline void *devm_memremap_pages(struct device *dev, struct resource *res)
-{
- /*
- * Fail attempts to call devm_memremap_pages() without
- * ZONE_DEVICE support enabled, this requires callers to fall
- * back to plain devm_memremap() based on config
- */
- WARN_ON_ONCE(1);
- return ERR_PTR(-ENXIO);
-}
-#endif
-
/*
* Some systems do not have legacy ISA devices.
* /dev/port is not a valid interface on these systems.
diff --git a/include/linux/kdev_t.h b/include/linux/kdev_t.h
index 052c7b32cc91..8e9e288b08c1 100644
--- a/include/linux/kdev_t.h
+++ b/include/linux/kdev_t.h
@@ -35,11 +35,6 @@ static inline dev_t old_decode_dev(u16 val)
return MKDEV((val >> 8) & 255, val & 255);
}
-static inline bool new_valid_dev(dev_t dev)
-{
- return 1;
-}
-
static inline u32 new_encode_dev(dev_t dev)
{
unsigned major = MAJOR(dev);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 7311c3294e25..f31638c6e873 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -202,26 +202,26 @@ extern int _cond_resched(void);
/**
* abs - return absolute value of an argument
- * @x: the value. If it is unsigned type, it is converted to signed type first
- * (s64, long or int depending on its size).
+ * @x: the value. If it is unsigned type, it is converted to signed type first.
+ * char is treated as if it was signed (regardless of whether it really is)
+ * but the macro's return type is preserved as char.
*
- * Return: an absolute value of x. If x is 64-bit, macro's return type is s64,
- * otherwise it is signed long.
+ * Return: an absolute value of x.
*/
-#define abs(x) __builtin_choose_expr(sizeof(x) == sizeof(s64), ({ \
- s64 __x = (x); \
- (__x < 0) ? -__x : __x; \
- }), ({ \
- long ret; \
- if (sizeof(x) == sizeof(long)) { \
- long __x = (x); \
- ret = (__x < 0) ? -__x : __x; \
- } else { \
- int __x = (x); \
- ret = (__x < 0) ? -__x : __x; \
- } \
- ret; \
- }))
+#define abs(x) __abs_choose_expr(x, long long, \
+ __abs_choose_expr(x, long, \
+ __abs_choose_expr(x, int, \
+ __abs_choose_expr(x, short, \
+ __abs_choose_expr(x, char, \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), char), \
+ (char)({ signed char __x = (x); __x<0?-__x:__x; }), \
+ ((void)0)))))))
+
+#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), signed type) || \
+ __builtin_types_compatible_p(typeof(x), unsigned type), \
+ ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
/**
* reciprocal_scale - "scale" a value into range [0, ep_ro)
diff --git a/include/linux/key.h b/include/linux/key.h
index 66f705243985..7321ab8ef949 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -177,6 +177,7 @@ struct key {
#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
+#define KEY_FLAG_KEEP 12 /* set if key should not be removed */
/* the key type and key description string
* - the desc is used to match a key against search criteria
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index f707f74055c3..861f690aa791 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -66,7 +66,7 @@
* error pfns indicate that the gfn is in slot but faild to
* translate it to pfn on host.
*/
-static inline bool is_error_pfn(pfn_t pfn)
+static inline bool is_error_pfn(kvm_pfn_t pfn)
{
return !!(pfn & KVM_PFN_ERR_MASK);
}
@@ -76,13 +76,13 @@ static inline bool is_error_pfn(pfn_t pfn)
* translated to pfn - it is not in slot or failed to
* translate it to pfn.
*/
-static inline bool is_error_noslot_pfn(pfn_t pfn)
+static inline bool is_error_noslot_pfn(kvm_pfn_t pfn)
{
return !!(pfn & KVM_PFN_ERR_NOSLOT_MASK);
}
/* noslot pfn indicates that the gfn is not in slot. */
-static inline bool is_noslot_pfn(pfn_t pfn)
+static inline bool is_noslot_pfn(kvm_pfn_t pfn)
{
return pfn == KVM_PFN_NOSLOT;
}
@@ -591,19 +591,20 @@ void kvm_release_page_clean(struct page *page);
void kvm_release_page_dirty(struct page *page);
void kvm_set_page_accessed(struct page *page);
-pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn);
-pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
-pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
+kvm_pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn);
+kvm_pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
+kvm_pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
bool *writable);
-pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn);
-pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn);
-pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn, bool atomic,
- bool *async, bool write_fault, bool *writable);
+kvm_pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn);
+kvm_pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn);
+kvm_pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn,
+ bool atomic, bool *async, bool write_fault,
+ bool *writable);
-void kvm_release_pfn_clean(pfn_t pfn);
-void kvm_set_pfn_dirty(pfn_t pfn);
-void kvm_set_pfn_accessed(pfn_t pfn);
-void kvm_get_pfn(pfn_t pfn);
+void kvm_release_pfn_clean(kvm_pfn_t pfn);
+void kvm_set_pfn_dirty(kvm_pfn_t pfn);
+void kvm_set_pfn_accessed(kvm_pfn_t pfn);
+void kvm_get_pfn(kvm_pfn_t pfn);
int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
int len);
@@ -629,8 +630,8 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
struct kvm_memslots *kvm_vcpu_memslots(struct kvm_vcpu *vcpu);
struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn);
-pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
-pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
+kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
+kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
@@ -811,7 +812,7 @@ void kvm_arch_sync_events(struct kvm *kvm);
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
-bool kvm_is_reserved_pfn(pfn_t pfn);
+bool kvm_is_reserved_pfn(kvm_pfn_t pfn);
struct kvm_irq_ack_notifier {
struct hlist_node link;
@@ -965,7 +966,7 @@ static inline gfn_t gpa_to_gfn(gpa_t gpa)
return (gfn_t)(gpa >> PAGE_SHIFT);
}
-static inline hpa_t pfn_to_hpa(pfn_t pfn)
+static inline hpa_t pfn_to_hpa(kvm_pfn_t pfn)
{
return (hpa_t)pfn << PAGE_SHIFT;
}
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index 1b47a185c2f0..8bf259dae9f6 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -53,7 +53,7 @@ typedef unsigned long hva_t;
typedef u64 hpa_t;
typedef u64 hfn_t;
-typedef hfn_t pfn_t;
+typedef hfn_t kvm_pfn_t;
struct gfn_to_hva_cache {
u64 generation;
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 3f021dc5da8c..bed40dff0e86 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -116,6 +116,7 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
}
+int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length);
struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
struct nvdimm_bus_descriptor *nfit_desc, struct module *module);
#define nvdimm_bus_register(parent, desc) \
diff --git a/include/linux/list.h b/include/linux/list.h
index 5356f4d661a7..30cf4200ab40 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -113,6 +113,17 @@ extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif
+#ifdef CONFIG_DEBUG_LIST
+/*
+ * See devm_memremap_pages() which wants DEBUG_LIST=y to assert if one
+ * of the pages it allocates is ever passed to list_add()
+ */
+extern void list_force_poison(struct list_head *entry);
+#else
+/* fallback to the less strict LIST_POISON* definitions */
+#define list_force_poison list_del
+#endif
+
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 31db7a05dd36..a8828652f794 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -37,8 +37,9 @@ enum klp_state {
* struct klp_func - function structure for live patching
* @old_name: name of the function to be patched
* @new_func: pointer to the patched function code
- * @old_addr: a hint conveying at what address the old function
- * can be found (optional, vmlinux patches only)
+ * @old_sympos: a hint indicating which symbol position the old function
+ * can be found (optional)
+ * @old_addr: the address of the function being patched
* @kobj: kobject for sysfs resources
* @state: tracks function-level patch application state
* @stack_node: list node for klp_ops func_stack list
@@ -48,16 +49,16 @@ struct klp_func {
const char *old_name;
void *new_func;
/*
- * The old_addr field is optional and can be used to resolve
- * duplicate symbol names in the vmlinux object. If this
- * information is not present, the symbol is located by name
- * with kallsyms. If the name is not unique and old_addr is
- * not provided, the patch application fails as there is no
- * way to resolve the ambiguity.
+ * The old_sympos field is optional and can be used to resolve
+ * duplicate symbol names in livepatch objects. If this field is zero,
+ * it is expected the symbol is unique, otherwise patching fails. If
+ * this value is greater than zero then that occurrence of the symbol
+ * in kallsyms for the given object is used.
*/
- unsigned long old_addr;
+ unsigned long old_sympos;
/* internal */
+ unsigned long old_addr;
struct kobject kobj;
enum klp_state state;
struct list_head stack_node;
@@ -66,8 +67,7 @@ struct klp_func {
/**
* struct klp_reloc - relocation structure for live patching
* @loc: address where the relocation will be written
- * @val: address of the referenced symbol (optional,
- * vmlinux patches only)
+ * @sympos: position in kallsyms to disambiguate symbols (optional)
* @type: ELF relocation type
* @name: name of the referenced symbol (for lookup/verification)
* @addend: offset from the referenced symbol
@@ -75,7 +75,7 @@ struct klp_func {
*/
struct klp_reloc {
unsigned long loc;
- unsigned long val;
+ unsigned long sympos;
unsigned long type;
const char *name;
int addend;
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 4d24d64578c4..140edab64446 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -29,7 +29,7 @@ struct nlmsvc_binding {
void (*fclose)(struct file *);
};
-extern struct nlmsvc_binding * nlmsvc_ops;
+extern const struct nlmsvc_binding *nlmsvc_ops;
/*
* Similar to nfs_client_initdata, but without the NFS-specific
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index ec3a6bab29de..71969de4058c 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1261,6 +1261,10 @@
* audit_rule_init.
* @rule contains the allocated rule
*
+ * @inode_invalidate_secctx:
+ * Notify the security module that it must revalidate the security context
+ * of an inode.
+ *
* @inode_notifysecctx:
* Notify the security module of what the security context of an inode
* should be. Initializes the incore security context managed by the
@@ -1413,14 +1417,14 @@ union security_list_options {
int (*inode_removexattr)(struct dentry *dentry, const char *name);
int (*inode_need_killpriv)(struct dentry *dentry);
int (*inode_killpriv)(struct dentry *dentry);
- int (*inode_getsecurity)(const struct inode *inode, const char *name,
+ int (*inode_getsecurity)(struct inode *inode, const char *name,
void **buffer, bool alloc);
int (*inode_setsecurity)(struct inode *inode, const char *name,
const void *value, size_t size,
int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer,
size_t buffer_size);
- void (*inode_getsecid)(const struct inode *inode, u32 *secid);
+ void (*inode_getsecid)(struct inode *inode, u32 *secid);
int (*file_permission)(struct file *file, int mask);
int (*file_alloc_security)(struct file *file);
@@ -1516,6 +1520,7 @@ union security_list_options {
int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx)(char *secdata, u32 seclen);
+ void (*inode_invalidate_secctx)(struct inode *inode);
int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
@@ -1757,6 +1762,7 @@ struct security_hook_heads {
struct list_head secid_to_secctx;
struct list_head secctx_to_secid;
struct list_head release_secctx;
+ struct list_head inode_invalidate_secctx;
struct list_head inode_notifysecctx;
struct list_head inode_setsecctx;
struct list_head inode_getsecctx;
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index fec66f86eeff..3106ac1c895e 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -61,6 +61,14 @@ extern int memblock_debug;
extern bool movable_node_enabled;
#endif /* CONFIG_MOVABLE_NODE */
+#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+#define __init_memblock __meminit
+#define __initdata_memblock __meminitdata
+#else
+#define __init_memblock
+#define __initdata_memblock
+#endif
+
#define memblock_dbg(fmt, ...) \
if (memblock_debug) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
@@ -166,7 +174,7 @@ static inline bool memblock_is_hotpluggable(struct memblock_region *m)
return m->flags & MEMBLOCK_HOTPLUG;
}
-static inline bool movable_node_is_enabled(void)
+static inline bool __init_memblock movable_node_is_enabled(void)
{
return movable_node_enabled;
}
@@ -216,10 +224,10 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
* for_each_free_mem_range - iterate through free memblock areas
* @i: u64 used as loop variable
* @nid: node selector, %NUMA_NO_NODE for all nodes
+ * @flags: pick from blocks based on memory attributes
* @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
* @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
* @p_nid: ptr to int for nid of the range, can be %NULL
- * @flags: pick from blocks based on memory attributes
*
* Walks over free (memory && !reserved) areas of memblock. Available as
* soon as memblock is initialized.
@@ -232,10 +240,10 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
* for_each_free_mem_range_reverse - rev-iterate through free memblock areas
* @i: u64 used as loop variable
* @nid: node selector, %NUMA_NO_NODE for all nodes
+ * @flags: pick from blocks based on memory attributes
* @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
* @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
* @p_nid: ptr to int for nid of the range, can be %NULL
- * @flags: pick from blocks based on memory attributes
*
* Walks over free (memory && !reserved) areas of memblock in reverse
* order. Available as soon as memblock is initialized.
@@ -325,10 +333,10 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
phys_addr_t memblock_start_of_DRAM(void);
phys_addr_t memblock_end_of_DRAM(void);
void memblock_enforce_memory_limit(phys_addr_t memory_limit);
-int memblock_is_memory(phys_addr_t addr);
+bool memblock_is_memory(phys_addr_t addr);
int memblock_is_map_memory(phys_addr_t addr);
int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
-int memblock_is_reserved(phys_addr_t addr);
+bool memblock_is_reserved(phys_addr_t addr);
bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
extern void __memblock_dump_all(void);
@@ -399,14 +407,11 @@ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblo
region < (memblock.memblock_type.regions + memblock.memblock_type.cnt); \
region++)
-
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
-#define __init_memblock __meminit
-#define __initdata_memblock __meminitdata
-#else
-#define __init_memblock
-#define __initdata_memblock
-#endif
+#define for_each_memblock_type(memblock_type, rgn) \
+ idx = 0; \
+ rgn = &memblock_type->regions[idx]; \
+ for (idx = 0; idx < memblock_type->cnt; \
+ idx++,rgn = &memblock_type->regions[idx])
#ifdef CONFIG_MEMTEST
extern void early_memtest(phys_addr_t start, phys_addr_t end);
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index cd0e2413c358..189f04d4d2ec 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -85,32 +85,10 @@ enum mem_cgroup_events_target {
MEM_CGROUP_NTARGETS,
};
-/*
- * Bits in struct cg_proto.flags
- */
-enum cg_proto_flags {
- /* Currently active and new sockets should be assigned to cgroups */
- MEMCG_SOCK_ACTIVE,
- /* It was ever activated; we must disarm static keys on destruction */
- MEMCG_SOCK_ACTIVATED,
-};
-
struct cg_proto {
struct page_counter memory_allocated; /* Current allocated memory. */
- struct percpu_counter sockets_allocated; /* Current number of sockets. */
int memory_pressure;
- long sysctl_mem[3];
- unsigned long flags;
- /*
- * memcg field is used to find which memcg we belong directly
- * Each memcg struct can hold more than one cg_proto, so container_of
- * won't really cut.
- *
- * The elegant solution would be having an inverse function to
- * proto_cgroup in struct proto, but that means polluting the structure
- * for everybody, instead of just for memcg users.
- */
- struct mem_cgroup *memcg;
+ bool active;
};
#ifdef CONFIG_MEMCG
@@ -192,6 +170,9 @@ struct mem_cgroup {
unsigned long low;
unsigned long high;
+ /* Range enforcement for interrupt charges */
+ struct work_struct high_work;
+
unsigned long soft_limit;
/* vmpressure notifications */
@@ -268,6 +249,10 @@ struct mem_cgroup {
struct wb_domain cgwb_domain;
#endif
+#ifdef CONFIG_INET
+ unsigned long socket_pressure;
+#endif
+
/* List of events which userspace want to receive */
struct list_head event_list;
spinlock_t event_list_lock;
@@ -275,7 +260,8 @@ struct mem_cgroup {
struct mem_cgroup_per_node *nodeinfo[0];
/* WARNING: nodeinfo must be the last member here */
};
-extern struct cgroup_subsys_state *mem_cgroup_root_css;
+
+extern struct mem_cgroup *root_mem_cgroup;
/**
* mem_cgroup_events - count memory events against a cgroup
@@ -294,10 +280,12 @@ static inline void mem_cgroup_events(struct mem_cgroup *memcg,
bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg);
int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
- gfp_t gfp_mask, struct mem_cgroup **memcgp);
+ gfp_t gfp_mask, struct mem_cgroup **memcgp,
+ bool compound);
void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
- bool lrucare);
-void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg);
+ bool lrucare, bool compound);
+void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg,
+ bool compound);
void mem_cgroup_uncharge(struct page *page);
void mem_cgroup_uncharge_list(struct list_head *page_list);
@@ -308,18 +296,34 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *);
bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
-struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg);
static inline
struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
return css ? container_of(css, struct mem_cgroup, css) : NULL;
}
+#define mem_cgroup_from_counter(counter, member) \
+ container_of(counter, struct mem_cgroup, member)
+
struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
struct mem_cgroup *,
struct mem_cgroup_reclaim_cookie *);
void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
+/**
+ * parent_mem_cgroup - find the accounting parent of a memcg
+ * @memcg: memcg whose parent to find
+ *
+ * Returns the parent memcg, or NULL if this is the root or the memory
+ * controller is in legacy no-hierarchy mode.
+ */
+static inline struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
+{
+ if (!memcg->memory.parent)
+ return NULL;
+ return mem_cgroup_from_counter(memcg->memory.parent, memory);
+}
+
static inline bool mem_cgroup_is_descendant(struct mem_cgroup *memcg,
struct mem_cgroup *root)
{
@@ -513,7 +517,8 @@ static inline bool mem_cgroup_low(struct mem_cgroup *root,
static inline int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask,
- struct mem_cgroup **memcgp)
+ struct mem_cgroup **memcgp,
+ bool compound)
{
*memcgp = NULL;
return 0;
@@ -521,12 +526,13 @@ static inline int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
static inline void mem_cgroup_commit_charge(struct page *page,
struct mem_cgroup *memcg,
- bool lrucare)
+ bool lrucare, bool compound)
{
}
static inline void mem_cgroup_cancel_charge(struct page *page,
- struct mem_cgroup *memcg)
+ struct mem_cgroup *memcg,
+ bool compound)
{
}
@@ -671,12 +677,6 @@ void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
}
#endif /* CONFIG_MEMCG */
-enum {
- UNDER_LIMIT,
- SOFT_LIMIT,
- OVER_LIMIT,
-};
-
#ifdef CONFIG_CGROUP_WRITEBACK
struct list_head *mem_cgroup_cgwb_list(struct mem_cgroup *memcg);
@@ -703,20 +703,35 @@ static inline void mem_cgroup_wb_stats(struct bdi_writeback *wb,
#endif /* CONFIG_CGROUP_WRITEBACK */
struct sock;
-#if defined(CONFIG_INET) && defined(CONFIG_MEMCG_KMEM)
void sock_update_memcg(struct sock *sk);
void sock_release_memcg(struct sock *sk);
-#else
-static inline void sock_update_memcg(struct sock *sk)
+bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
+void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
+#if defined(CONFIG_MEMCG) && defined(CONFIG_INET)
+extern struct static_key_false memcg_sockets_enabled_key;
+#define mem_cgroup_sockets_enabled static_branch_unlikely(&memcg_sockets_enabled_key)
+static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
{
+#ifdef CONFIG_MEMCG_KMEM
+ if (memcg->tcp_mem.memory_pressure)
+ return true;
+#endif
+ do {
+ if (time_before(jiffies, memcg->socket_pressure))
+ return true;
+ } while ((memcg = parent_mem_cgroup(memcg)));
+ return false;
}
-static inline void sock_release_memcg(struct sock *sk)
+#else
+#define mem_cgroup_sockets_enabled 0
+static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
{
+ return false;
}
-#endif /* CONFIG_INET && CONFIG_MEMCG_KMEM */
+#endif
#ifdef CONFIG_MEMCG_KMEM
-extern struct static_key memcg_kmem_enabled_key;
+extern struct static_key_false memcg_kmem_enabled_key;
extern int memcg_nr_cache_ids;
void memcg_get_cache_ids(void);
@@ -732,7 +747,7 @@ void memcg_put_cache_ids(void);
static inline bool memcg_kmem_enabled(void)
{
- return static_key_false(&memcg_kmem_enabled_key);
+ return static_branch_unlikely(&memcg_kmem_enabled_key);
}
static inline bool memcg_kmem_is_active(struct mem_cgroup *memcg)
@@ -766,15 +781,13 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)
return memcg ? memcg->kmemcg_id : -1;
}
-struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep);
+struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp);
void __memcg_kmem_put_cache(struct kmem_cache *cachep);
-static inline bool __memcg_kmem_bypass(gfp_t gfp)
+static inline bool __memcg_kmem_bypass(void)
{
if (!memcg_kmem_enabled())
return true;
- if (gfp & __GFP_NOACCOUNT)
- return true;
if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD))
return true;
return false;
@@ -791,7 +804,9 @@ static inline bool __memcg_kmem_bypass(gfp_t gfp)
static __always_inline int memcg_kmem_charge(struct page *page,
gfp_t gfp, int order)
{
- if (__memcg_kmem_bypass(gfp))
+ if (__memcg_kmem_bypass())
+ return 0;
+ if (!(gfp & __GFP_ACCOUNT))
return 0;
return __memcg_kmem_charge(page, gfp, order);
}
@@ -810,16 +825,15 @@ static __always_inline void memcg_kmem_uncharge(struct page *page, int order)
/**
* memcg_kmem_get_cache: selects the correct per-memcg cache for allocation
* @cachep: the original global kmem cache
- * @gfp: allocation flags.
*
* All memory allocated from a per-memcg cache is charged to the owner memcg.
*/
static __always_inline struct kmem_cache *
memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
{
- if (__memcg_kmem_bypass(gfp))
+ if (__memcg_kmem_bypass())
return cachep;
- return __memcg_kmem_get_cache(cachep);
+ return __memcg_kmem_get_cache(cachep, gfp);
}
static __always_inline void memcg_kmem_put_cache(struct kmem_cache *cachep)
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 2ea574ff9714..43405992d027 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -275,7 +275,8 @@ extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
extern bool is_memblock_offlined(struct memory_block *mem);
extern void remove_memory(int nid, u64 start, u64 size);
extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn);
-extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms);
+extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms,
+ unsigned long map_offset);
extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
unsigned long pnum);
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 3d385c81c153..2696c1f05ed1 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -122,7 +122,7 @@ struct sp_node {
struct shared_policy {
struct rb_root root;
- spinlock_t lock;
+ rwlock_t lock;
};
int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst);
diff --git a/include/linux/memremap.h b/include/linux/memremap.h
new file mode 100644
index 000000000000..bcaa634139a9
--- /dev/null
+++ b/include/linux/memremap.h
@@ -0,0 +1,114 @@
+#ifndef _LINUX_MEMREMAP_H_
+#define _LINUX_MEMREMAP_H_
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/percpu-refcount.h>
+
+struct resource;
+struct device;
+
+/**
+ * struct vmem_altmap - pre-allocated storage for vmemmap_populate
+ * @base_pfn: base of the entire dev_pagemap mapping
+ * @reserve: pages mapped, but reserved for driver use (relative to @base)
+ * @free: free pages set aside in the mapping for memmap storage
+ * @align: pages reserved to meet allocation alignments
+ * @alloc: track pages consumed, private to vmemmap_populate()
+ */
+struct vmem_altmap {
+ const unsigned long base_pfn;
+ const unsigned long reserve;
+ unsigned long free;
+ unsigned long align;
+ unsigned long alloc;
+};
+
+unsigned long vmem_altmap_offset(struct vmem_altmap *altmap);
+void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns);
+
+#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_ZONE_DEVICE)
+struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start);
+#else
+static inline struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * struct dev_pagemap - metadata for ZONE_DEVICE mappings
+ * @altmap: pre-allocated/reserved memory for vmemmap allocations
+ * @res: physical address range covered by @ref
+ * @ref: reference count that pins the devm_memremap_pages() mapping
+ * @dev: host device of the mapping for debug
+ */
+struct dev_pagemap {
+ struct vmem_altmap *altmap;
+ const struct resource *res;
+ struct percpu_ref *ref;
+ struct device *dev;
+};
+
+#ifdef CONFIG_ZONE_DEVICE
+void *devm_memremap_pages(struct device *dev, struct resource *res,
+ struct percpu_ref *ref, struct vmem_altmap *altmap);
+struct dev_pagemap *find_dev_pagemap(resource_size_t phys);
+#else
+static inline void *devm_memremap_pages(struct device *dev,
+ struct resource *res, struct percpu_ref *ref,
+ struct vmem_altmap *altmap)
+{
+ /*
+ * Fail attempts to call devm_memremap_pages() without
+ * ZONE_DEVICE support enabled, this requires callers to fall
+ * back to plain devm_memremap() based on config
+ */
+ WARN_ON_ONCE(1);
+ return ERR_PTR(-ENXIO);
+}
+
+static inline struct dev_pagemap *find_dev_pagemap(resource_size_t phys)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * get_dev_pagemap() - take a new live reference on the dev_pagemap for @pfn
+ * @pfn: page frame number to lookup page_map
+ * @pgmap: optional known pgmap that already has a reference
+ *
+ * @pgmap allows the overhead of a lookup to be bypassed when @pfn lands in the
+ * same mapping.
+ */
+static inline struct dev_pagemap *get_dev_pagemap(unsigned long pfn,
+ struct dev_pagemap *pgmap)
+{
+ const struct resource *res = pgmap ? pgmap->res : NULL;
+ resource_size_t phys = PFN_PHYS(pfn);
+
+ /*
+ * In the cached case we're already holding a live reference so
+ * we can simply do a blind increment
+ */
+ if (res && phys >= res->start && phys <= res->end) {
+ percpu_ref_get(pgmap->ref);
+ return pgmap;
+ }
+
+ /* fall back to slow path lookup */
+ rcu_read_lock();
+ pgmap = find_dev_pagemap(phys);
+ if (pgmap && !percpu_ref_tryget_live(pgmap->ref))
+ pgmap = NULL;
+ rcu_read_unlock();
+
+ return pgmap;
+}
+
+static inline void put_dev_pagemap(struct dev_pagemap *pgmap)
+{
+ if (pgmap)
+ percpu_ref_put(pgmap->ref);
+}
+#endif /* _LINUX_MEMREMAP_H_ */
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
index 79e607e2f081..d55a42297d49 100644
--- a/include/linux/mfd/arizona/core.h
+++ b/include/linux/mfd/arizona/core.h
@@ -27,6 +27,8 @@ enum arizona_type {
WM8280 = 4,
WM8998 = 5,
WM1814 = 6,
+ WM1831 = 7,
+ CS47L24 = 8,
};
#define ARIZONA_IRQ_GP1 0
@@ -166,6 +168,7 @@ static inline int wm5102_patch(struct arizona *arizona)
#endif
int wm5110_patch(struct arizona *arizona);
+int cs47l24_patch(struct arizona *arizona);
int wm8997_patch(struct arizona *arizona);
int wm8998_patch(struct arizona *arizona);
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 57b45caaea80..64faeeff698c 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -171,7 +171,7 @@ struct arizona_pdata {
int inmode[ARIZONA_MAX_INPUT];
/** Mode for outputs */
- bool out_mono[ARIZONA_MAX_OUTPUT];
+ int out_mono[ARIZONA_MAX_OUTPUT];
/** PDM speaker mute setting */
unsigned int spk_mute[ARIZONA_MAX_PDM_SPK];
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index 13e1d96935ed..c800dbc42079 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -134,21 +134,32 @@ struct palmas_pmic_driver_data {
struct regulator_config config);
};
+struct palmas_adc_wakeup_property {
+ int adc_channel_number;
+ int adc_high_threshold;
+ int adc_low_threshold;
+};
+
struct palmas_gpadc_platform_data {
/* Channel 3 current source is only enabled during conversion */
- int ch3_current;
+ int ch3_current; /* 0: off; 1: 10uA; 2: 400uA; 3: 800 uA */
/* Channel 0 current source can be used for battery detection.
* If used for battery detection this will cause a permanent current
* consumption depending on current level set here.
*/
- int ch0_current;
+ int ch0_current; /* 0: off; 1: 5uA; 2: 15uA; 3: 20 uA */
+ bool extended_delay; /* use extended delay for conversion */
/* default BAT_REMOVAL_DAT setting on device probe */
int bat_removal;
/* Sets the START_POLARITY bit in the RT_CTRL register */
int start_polarity;
+
+ int auto_conversion_period_ms;
+ struct palmas_adc_wakeup_property *adc_wakeup1_data;
+ struct palmas_adc_wakeup_property *adc_wakeup2_data;
};
struct palmas_reg_init {
@@ -405,28 +416,7 @@ struct palmas_gpadc_calibration {
s32 offset_error;
};
-struct palmas_gpadc {
- struct device *dev;
- struct palmas *palmas;
-
- int ch3_current;
- int ch0_current;
-
- int gpadc_force;
-
- int bat_removal;
-
- struct mutex reading_lock;
- struct completion irq_complete;
-
- int eoc_sw_irq;
-
- struct palmas_gpadc_calibration *palmas_cal_tbl;
-
- int conv0_channel;
- int conv1_channel;
- int rt_channel;
-};
+#define PALMAS_DATASHEET_NAME(_name) "palmas-gpadc-chan-"#_name
struct palmas_gpadc_result {
s32 raw_code;
@@ -520,6 +510,43 @@ enum palmas_irqs {
PALMAS_NUM_IRQ,
};
+/* Palmas GPADC Channels */
+enum {
+ PALMAS_ADC_CH_IN0,
+ PALMAS_ADC_CH_IN1,
+ PALMAS_ADC_CH_IN2,
+ PALMAS_ADC_CH_IN3,
+ PALMAS_ADC_CH_IN4,
+ PALMAS_ADC_CH_IN5,
+ PALMAS_ADC_CH_IN6,
+ PALMAS_ADC_CH_IN7,
+ PALMAS_ADC_CH_IN8,
+ PALMAS_ADC_CH_IN9,
+ PALMAS_ADC_CH_IN10,
+ PALMAS_ADC_CH_IN11,
+ PALMAS_ADC_CH_IN12,
+ PALMAS_ADC_CH_IN13,
+ PALMAS_ADC_CH_IN14,
+ PALMAS_ADC_CH_IN15,
+ PALMAS_ADC_CH_MAX,
+};
+
+/* Palmas GPADC Channel0 Current Source */
+enum {
+ PALMAS_ADC_CH0_CURRENT_SRC_0,
+ PALMAS_ADC_CH0_CURRENT_SRC_5,
+ PALMAS_ADC_CH0_CURRENT_SRC_15,
+ PALMAS_ADC_CH0_CURRENT_SRC_20,
+};
+
+/* Palmas GPADC Channel3 Current Source */
+enum {
+ PALMAS_ADC_CH3_CURRENT_SRC_0,
+ PALMAS_ADC_CH3_CURRENT_SRC_10,
+ PALMAS_ADC_CH3_CURRENT_SRC_400,
+ PALMAS_ADC_CH3_CURRENT_SRC_800,
+};
+
struct palmas_pmic {
struct palmas *palmas;
struct device *dev;
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
index a06098639399..6bc4bcd488ac 100644
--- a/include/linux/mfd/samsung/core.h
+++ b/include/linux/mfd/samsung/core.h
@@ -44,6 +44,7 @@ enum sec_device_type {
S2MPS11X,
S2MPS13X,
S2MPS14X,
+ S2MPS15X,
S2MPU02,
};
diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h
index 29c30ac36020..48c3c5be7eb1 100644
--- a/include/linux/mfd/samsung/rtc.h
+++ b/include/linux/mfd/samsung/rtc.h
@@ -105,8 +105,12 @@ enum s2mps_rtc_reg {
#define S5M_RTC_UDR_MASK (1 << S5M_RTC_UDR_SHIFT)
#define S2MPS_RTC_WUDR_SHIFT 4
#define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT)
+#define S2MPS15_RTC_AUDR_SHIFT 4
+#define S2MPS15_RTC_AUDR_MASK (1 << S2MPS15_RTC_AUDR_SHIFT)
#define S2MPS13_RTC_AUDR_SHIFT 1
#define S2MPS13_RTC_AUDR_MASK (1 << S2MPS13_RTC_AUDR_SHIFT)
+#define S2MPS15_RTC_WUDR_SHIFT 1
+#define S2MPS15_RTC_WUDR_MASK (1 << S2MPS15_RTC_WUDR_SHIFT)
#define S2MPS_RTC_RUDR_SHIFT 0
#define S2MPS_RTC_RUDR_MASK (1 << S2MPS_RTC_RUDR_SHIFT)
#define RTC_TCON_SHIFT 1
diff --git a/include/linux/mfd/samsung/s2mps15.h b/include/linux/mfd/samsung/s2mps15.h
new file mode 100644
index 000000000000..36d35287c3c0
--- /dev/null
+++ b/include/linux/mfd/samsung/s2mps15.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd
+ * http://www.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.
+ *
+ * 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 __LINUX_MFD_S2MPS15_H
+#define __LINUX_MFD_S2MPS15_H
+
+/* S2MPS15 registers */
+enum s2mps15_reg {
+ S2MPS15_REG_ID,
+ S2MPS15_REG_INT1,
+ S2MPS15_REG_INT2,
+ S2MPS15_REG_INT3,
+ S2MPS15_REG_INT1M,
+ S2MPS15_REG_INT2M,
+ S2MPS15_REG_INT3M,
+ S2MPS15_REG_ST1,
+ S2MPS15_REG_ST2,
+ S2MPS15_REG_PWRONSRC,
+ S2MPS15_REG_OFFSRC,
+ S2MPS15_REG_BU_CHG,
+ S2MPS15_REG_RTC_BUF,
+ S2MPS15_REG_CTRL1,
+ S2MPS15_REG_CTRL2,
+ S2MPS15_REG_RSVD1,
+ S2MPS15_REG_RSVD2,
+ S2MPS15_REG_RSVD3,
+ S2MPS15_REG_RSVD4,
+ S2MPS15_REG_RSVD5,
+ S2MPS15_REG_RSVD6,
+ S2MPS15_REG_CTRL3,
+ S2MPS15_REG_RSVD7,
+ S2MPS15_REG_RSVD8,
+ S2MPS15_REG_RSVD9,
+ S2MPS15_REG_B1CTRL1,
+ S2MPS15_REG_B1CTRL2,
+ S2MPS15_REG_B2CTRL1,
+ S2MPS15_REG_B2CTRL2,
+ S2MPS15_REG_B3CTRL1,
+ S2MPS15_REG_B3CTRL2,
+ S2MPS15_REG_B4CTRL1,
+ S2MPS15_REG_B4CTRL2,
+ S2MPS15_REG_B5CTRL1,
+ S2MPS15_REG_B5CTRL2,
+ S2MPS15_REG_B6CTRL1,
+ S2MPS15_REG_B6CTRL2,
+ S2MPS15_REG_B7CTRL1,
+ S2MPS15_REG_B7CTRL2,
+ S2MPS15_REG_B8CTRL1,
+ S2MPS15_REG_B8CTRL2,
+ S2MPS15_REG_B9CTRL1,
+ S2MPS15_REG_B9CTRL2,
+ S2MPS15_REG_B10CTRL1,
+ S2MPS15_REG_B10CTRL2,
+ S2MPS15_REG_BBCTRL1,
+ S2MPS15_REG_BBCTRL2,
+ S2MPS15_REG_BRAMP,
+ S2MPS15_REG_LDODVS1,
+ S2MPS15_REG_LDODVS2,
+ S2MPS15_REG_LDODVS3,
+ S2MPS15_REG_LDODVS4,
+ S2MPS15_REG_L1CTRL,
+ S2MPS15_REG_L2CTRL,
+ S2MPS15_REG_L3CTRL,
+ S2MPS15_REG_L4CTRL,
+ S2MPS15_REG_L5CTRL,
+ S2MPS15_REG_L6CTRL,
+ S2MPS15_REG_L7CTRL,
+ S2MPS15_REG_L8CTRL,
+ S2MPS15_REG_L9CTRL,
+ S2MPS15_REG_L10CTRL,
+ S2MPS15_REG_L11CTRL,
+ S2MPS15_REG_L12CTRL,
+ S2MPS15_REG_L13CTRL,
+ S2MPS15_REG_L14CTRL,
+ S2MPS15_REG_L15CTRL,
+ S2MPS15_REG_L16CTRL,
+ S2MPS15_REG_L17CTRL,
+ S2MPS15_REG_L18CTRL,
+ S2MPS15_REG_L19CTRL,
+ S2MPS15_REG_L20CTRL,
+ S2MPS15_REG_L21CTRL,
+ S2MPS15_REG_L22CTRL,
+ S2MPS15_REG_L23CTRL,
+ S2MPS15_REG_L24CTRL,
+ S2MPS15_REG_L25CTRL,
+ S2MPS15_REG_L26CTRL,
+ S2MPS15_REG_L27CTRL,
+ S2MPS15_REG_LDODSCH1,
+ S2MPS15_REG_LDODSCH2,
+ S2MPS15_REG_LDODSCH3,
+ S2MPS15_REG_LDODSCH4,
+};
+
+/* S2MPS15 regulator ids */
+enum s2mps15_regulators {
+ S2MPS15_LDO1,
+ S2MPS15_LDO2,
+ S2MPS15_LDO3,
+ S2MPS15_LDO4,
+ S2MPS15_LDO5,
+ S2MPS15_LDO6,
+ S2MPS15_LDO7,
+ S2MPS15_LDO8,
+ S2MPS15_LDO9,
+ S2MPS15_LDO10,
+ S2MPS15_LDO11,
+ S2MPS15_LDO12,
+ S2MPS15_LDO13,
+ S2MPS15_LDO14,
+ S2MPS15_LDO15,
+ S2MPS15_LDO16,
+ S2MPS15_LDO17,
+ S2MPS15_LDO18,
+ S2MPS15_LDO19,
+ S2MPS15_LDO20,
+ S2MPS15_LDO21,
+ S2MPS15_LDO22,
+ S2MPS15_LDO23,
+ S2MPS15_LDO24,
+ S2MPS15_LDO25,
+ S2MPS15_LDO26,
+ S2MPS15_LDO27,
+ S2MPS15_BUCK1,
+ S2MPS15_BUCK2,
+ S2MPS15_BUCK3,
+ S2MPS15_BUCK4,
+ S2MPS15_BUCK5,
+ S2MPS15_BUCK6,
+ S2MPS15_BUCK7,
+ S2MPS15_BUCK8,
+ S2MPS15_BUCK9,
+ S2MPS15_BUCK10,
+ S2MPS15_BUCK11,
+ S2MPS15_REGULATOR_MAX,
+};
+
+#define S2MPS15_LDO_VSEL_MASK (0x3F)
+#define S2MPS15_BUCK_VSEL_MASK (0xFF)
+
+#define S2MPS15_ENABLE_SHIFT (0x06)
+#define S2MPS15_ENABLE_MASK (0x03 << S2MPS15_ENABLE_SHIFT)
+
+#define S2MPS15_LDO_N_VOLTAGES (S2MPS15_LDO_VSEL_MASK + 1)
+#define S2MPS15_BUCK_N_VOLTAGES (S2MPS15_BUCK_VSEL_MASK + 1)
+
+#endif /* __LINUX_MFD_S2MPS15_H */
diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h
index 2f9b593246ee..d58f3b5f585a 100644
--- a/include/linux/mfd/tps65218.h
+++ b/include/linux/mfd/tps65218.h
@@ -200,6 +200,8 @@ enum tps65218_regulator_id {
TPS65218_DCDC_4,
TPS65218_DCDC_5,
TPS65218_DCDC_6,
+ /* LS's */
+ TPS65218_LS_3,
/* LDOs */
TPS65218_LDO_1,
};
@@ -210,8 +212,11 @@ enum tps65218_regulator_id {
#define TPS65218_NUM_DCDC 6
/* Number of LDO voltage regulators available */
#define TPS65218_NUM_LDO 1
+/* Number of total LS current regulators available */
+#define TPS65218_NUM_LS 1
/* Number of total regulators available */
-#define TPS65218_NUM_REGULATOR (TPS65218_NUM_DCDC + TPS65218_NUM_LDO)
+#define TPS65218_NUM_REGULATOR (TPS65218_NUM_DCDC + TPS65218_NUM_LDO \
+ + TPS65218_NUM_LS)
/* Define the TPS65218 IRQ numbers */
enum tps65218_irqs {
diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h
index abc4767695e4..b2c9fada8eac 100644
--- a/include/linux/mlx5/cq.h
+++ b/include/linux/mlx5/cq.h
@@ -45,7 +45,7 @@ struct mlx5_core_cq {
atomic_t refcount;
struct completion free;
unsigned vector;
- int irqn;
+ unsigned int irqn;
void (*comp) (struct mlx5_core_cq *);
void (*event) (struct mlx5_core_cq *, enum mlx5_event);
struct mlx5_uar *uar;
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 2fd7019f69db..5162f3533042 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -303,7 +303,7 @@ struct mlx5_eq {
u32 cons_index;
struct mlx5_buf buf;
int size;
- u8 irqn;
+ unsigned int irqn;
u8 eqn;
int nent;
u64 mask;
@@ -783,7 +783,8 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
int mlx5_start_eqs(struct mlx5_core_dev *dev);
int mlx5_stop_eqs(struct mlx5_core_dev *dev);
-int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn);
+int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn,
+ unsigned int *irqn);
int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn);
int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 00bad7793788..f1cd22f2df1a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -16,6 +16,7 @@
#include <linux/mm_types.h>
#include <linux/range.h>
#include <linux/pfn.h>
+#include <linux/percpu-refcount.h>
#include <linux/bit_spinlock.h>
#include <linux/shrinker.h>
#include <linux/resource.h>
@@ -51,6 +52,17 @@ extern int sysctl_legacy_va_layout;
#define sysctl_legacy_va_layout 0
#endif
+#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS
+extern const int mmap_rnd_bits_min;
+extern const int mmap_rnd_bits_max;
+extern int mmap_rnd_bits __read_mostly;
+#endif
+#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
+extern const int mmap_rnd_compat_bits_min;
+extern const int mmap_rnd_compat_bits_max;
+extern int mmap_rnd_compat_bits __read_mostly;
+#endif
+
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -225,10 +237,14 @@ extern pgprot_t protection_map[16];
* ->fault function. The vma's ->fault is responsible for returning a bitmask
* of VM_FAULT_xxx flags that give details about how the fault was handled.
*
+ * MM layer fills up gfp_mask for page allocations but fault handler might
+ * alter it if its implementation requires a different allocation context.
+ *
* pgoff should be used in favour of virtual_address, if possible.
*/
struct vm_fault {
unsigned int flags; /* FAULT_FLAG_xxx flags */
+ gfp_t gfp_mask; /* gfp mask to be used for allocations */
pgoff_t pgoff; /* Logical page offset based on vma */
void __user *virtual_address; /* Faulting virtual address */
@@ -314,6 +330,13 @@ struct inode;
#define page_private(page) ((page)->private)
#define set_page_private(page, v) ((page)->private = (v))
+#if !defined(__HAVE_ARCH_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE)
+static inline int pmd_devmap(pmd_t pmd)
+{
+ return 0;
+}
+#endif
+
/*
* FIXME: take this include out, include page-flags.h in
* files which need it (119 of them)
@@ -395,39 +418,17 @@ static inline int is_vmalloc_or_module_addr(const void *x)
extern void kvfree(const void *addr);
-static inline void compound_lock(struct page *page)
-{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- VM_BUG_ON_PAGE(PageSlab(page), page);
- bit_spin_lock(PG_compound_lock, &page->flags);
-#endif
-}
-
-static inline void compound_unlock(struct page *page)
-{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- VM_BUG_ON_PAGE(PageSlab(page), page);
- bit_spin_unlock(PG_compound_lock, &page->flags);
-#endif
-}
-
-static inline unsigned long compound_lock_irqsave(struct page *page)
+static inline atomic_t *compound_mapcount_ptr(struct page *page)
{
- unsigned long uninitialized_var(flags);
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- local_irq_save(flags);
- compound_lock(page);
-#endif
- return flags;
+ return &page[1].compound_mapcount;
}
-static inline void compound_unlock_irqrestore(struct page *page,
- unsigned long flags)
+static inline int compound_mapcount(struct page *page)
{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- compound_unlock(page);
- local_irq_restore(flags);
-#endif
+ if (!PageCompound(page))
+ return 0;
+ page = compound_head(page);
+ return atomic_read(compound_mapcount_ptr(page)) + 1;
}
/*
@@ -440,61 +441,29 @@ static inline void page_mapcount_reset(struct page *page)
atomic_set(&(page)->_mapcount, -1);
}
+int __page_mapcount(struct page *page);
+
static inline int page_mapcount(struct page *page)
{
VM_BUG_ON_PAGE(PageSlab(page), page);
- return atomic_read(&page->_mapcount) + 1;
-}
-
-static inline int page_count(struct page *page)
-{
- return atomic_read(&compound_head(page)->_count);
-}
-
-static inline bool __compound_tail_refcounted(struct page *page)
-{
- return PageAnon(page) && !PageSlab(page) && !PageHeadHuge(page);
-}
-/*
- * This takes a head page as parameter and tells if the
- * tail page reference counting can be skipped.
- *
- * For this to be safe, PageSlab and PageHeadHuge must remain true on
- * any given page where they return true here, until all tail pins
- * have been released.
- */
-static inline bool compound_tail_refcounted(struct page *page)
-{
- VM_BUG_ON_PAGE(!PageHead(page), page);
- return __compound_tail_refcounted(page);
+ if (unlikely(PageCompound(page)))
+ return __page_mapcount(page);
+ return atomic_read(&page->_mapcount) + 1;
}
-static inline void get_huge_page_tail(struct page *page)
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+int total_mapcount(struct page *page);
+#else
+static inline int total_mapcount(struct page *page)
{
- /*
- * __split_huge_page_refcount() cannot run from under us.
- */
- VM_BUG_ON_PAGE(!PageTail(page), page);
- VM_BUG_ON_PAGE(page_mapcount(page) < 0, page);
- VM_BUG_ON_PAGE(atomic_read(&page->_count) != 0, page);
- if (compound_tail_refcounted(compound_head(page)))
- atomic_inc(&page->_mapcount);
+ return page_mapcount(page);
}
+#endif
-extern bool __get_page_tail(struct page *page);
-
-static inline void get_page(struct page *page)
+static inline int page_count(struct page *page)
{
- if (unlikely(PageTail(page)))
- if (likely(__get_page_tail(page)))
- return;
- /*
- * Getting a normal page or the head of a compound page
- * requires to already have an elevated page->_count.
- */
- VM_BUG_ON_PAGE(atomic_read(&page->_count) <= 0, page);
- atomic_inc(&page->_count);
+ return atomic_read(&compound_head(page)->_count);
}
static inline struct page *virt_to_head_page(const void *x)
@@ -513,7 +482,8 @@ static inline void init_page_count(struct page *page)
atomic_set(&page->_count, 1);
}
-void put_page(struct page *page);
+void __put_page(struct page *page);
+
void put_pages_list(struct list_head *pages);
void split_page(struct page *page, unsigned int order);
@@ -533,6 +503,9 @@ enum compound_dtor_id {
#ifdef CONFIG_HUGETLB_PAGE
HUGETLB_PAGE_DTOR,
#endif
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ TRANSHUGE_PAGE_DTOR,
+#endif
NR_COMPOUND_DTORS,
};
extern compound_page_dtor * const compound_page_dtors[];
@@ -562,6 +535,8 @@ static inline void set_compound_order(struct page *page, unsigned int order)
page[1].compound_order = order;
}
+void free_compound_page(struct page *page);
+
#ifdef CONFIG_MMU
/*
* Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when
@@ -689,6 +664,51 @@ static inline enum zone_type page_zonenum(const struct page *page)
return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK;
}
+#ifdef CONFIG_ZONE_DEVICE
+void get_zone_device_page(struct page *page);
+void put_zone_device_page(struct page *page);
+static inline bool is_zone_device_page(const struct page *page)
+{
+ return page_zonenum(page) == ZONE_DEVICE;
+}
+#else
+static inline void get_zone_device_page(struct page *page)
+{
+}
+static inline void put_zone_device_page(struct page *page)
+{
+}
+static inline bool is_zone_device_page(const struct page *page)
+{
+ return false;
+}
+#endif
+
+static inline void get_page(struct page *page)
+{
+ page = compound_head(page);
+ /*
+ * Getting a normal page or the head of a compound page
+ * requires to already have an elevated page->_count.
+ */
+ VM_BUG_ON_PAGE(atomic_read(&page->_count) <= 0, page);
+ atomic_inc(&page->_count);
+
+ if (unlikely(is_zone_device_page(page)))
+ get_zone_device_page(page);
+}
+
+static inline void put_page(struct page *page)
+{
+ page = compound_head(page);
+
+ if (put_page_testzero(page))
+ __put_page(page);
+
+ if (unlikely(is_zone_device_page(page)))
+ put_zone_device_page(page);
+}
+
#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
#define SECTION_IN_PAGE_FLAGS
#endif
@@ -978,10 +998,21 @@ static inline pgoff_t page_file_index(struct page *page)
/*
* Return true if this page is mapped into pagetables.
+ * For compound page it returns true if any subpage of compound page is mapped.
*/
-static inline int page_mapped(struct page *page)
-{
- return atomic_read(&(page)->_mapcount) >= 0;
+static inline bool page_mapped(struct page *page)
+{
+ int i;
+ if (likely(!PageCompound(page)))
+ return atomic_read(&page->_mapcount) >= 0;
+ page = compound_head(page);
+ if (atomic_read(compound_mapcount_ptr(page)) >= 0)
+ return true;
+ for (i = 0; i < hpage_nr_pages(page); i++) {
+ if (atomic_read(&page[i]._mapcount) >= 0)
+ return true;
+ }
+ return false;
}
/*
@@ -1069,7 +1100,7 @@ static inline bool shmem_mapping(struct address_space *mapping)
}
#endif
-extern int can_do_mlock(void);
+extern bool can_do_mlock(void);
extern int user_shm_lock(size_t, struct user_struct *);
extern void user_shm_unlock(size_t, struct user_struct *);
@@ -1163,7 +1194,8 @@ int invalidate_inode_page(struct page *page);
extern int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, unsigned int flags);
extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long address, unsigned int fault_flags);
+ unsigned long address, unsigned int fault_flags,
+ bool *unlocked);
#else
static inline int handle_mm_fault(struct mm_struct *mm,
struct vm_area_struct *vma, unsigned long address,
@@ -1175,7 +1207,7 @@ static inline int handle_mm_fault(struct mm_struct *mm,
}
static inline int fixup_user_fault(struct task_struct *tsk,
struct mm_struct *mm, unsigned long address,
- unsigned int fault_flags)
+ unsigned int fault_flags, bool *unlocked)
{
/* should never happen if there's no MMU */
BUG();
@@ -1361,10 +1393,26 @@ static inline void dec_mm_counter(struct mm_struct *mm, int member)
atomic_long_dec(&mm->rss_stat.count[member]);
}
+/* Optimized variant when page is already known not to be PageAnon */
+static inline int mm_counter_file(struct page *page)
+{
+ if (PageSwapBacked(page))
+ return MM_SHMEMPAGES;
+ return MM_FILEPAGES;
+}
+
+static inline int mm_counter(struct page *page)
+{
+ if (PageAnon(page))
+ return MM_ANONPAGES;
+ return mm_counter_file(page);
+}
+
static inline unsigned long get_mm_rss(struct mm_struct *mm)
{
return get_mm_counter(mm, MM_FILEPAGES) +
- get_mm_counter(mm, MM_ANONPAGES);
+ get_mm_counter(mm, MM_ANONPAGES) +
+ get_mm_counter(mm, MM_SHMEMPAGES);
}
static inline unsigned long get_mm_hiwater_rss(struct mm_struct *mm)
@@ -1413,6 +1461,13 @@ static inline void sync_mm_rss(struct mm_struct *mm)
}
#endif
+#ifndef __HAVE_ARCH_PTE_DEVMAP
+static inline int pte_devmap(pte_t pte)
+{
+ return 0;
+}
+#endif
+
int vma_wants_writenotify(struct vm_area_struct *vma);
extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
@@ -1898,7 +1953,9 @@ extern void mm_drop_all_locks(struct mm_struct *mm);
extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
extern struct file *get_mm_exe_file(struct mm_struct *mm);
-extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
+extern bool may_expand_vm(struct mm_struct *, vm_flags_t, unsigned long npages);
+extern void vm_stat_account(struct mm_struct *, vm_flags_t, long npages);
+
extern struct vm_area_struct *_install_special_mapping(struct mm_struct *mm,
unsigned long addr, unsigned long len,
unsigned long flags,
@@ -2081,7 +2138,7 @@ int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn);
int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn);
+ pfn_t pfn);
int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len);
@@ -2116,15 +2173,6 @@ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size, pte_fn_t fn, void *data);
-#ifdef CONFIG_PROC_FS
-void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
-#else
-static inline void vm_stat_account(struct mm_struct *mm,
- unsigned long flags, struct file *file, long pages)
-{
- mm->total_vm += pages;
-}
-#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_DEBUG_PAGEALLOC
extern bool _debug_pagealloc_enabled;
@@ -2200,7 +2248,14 @@ pud_t *vmemmap_pud_populate(pgd_t *pgd, unsigned long addr, int node);
pmd_t *vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node);
pte_t *vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node);
void *vmemmap_alloc_block(unsigned long size, int node);
-void *vmemmap_alloc_block_buf(unsigned long size, int node);
+struct vmem_altmap;
+void *__vmemmap_alloc_block_buf(unsigned long size, int node,
+ struct vmem_altmap *altmap);
+static inline void *vmemmap_alloc_block_buf(unsigned long size, int node)
+{
+ return __vmemmap_alloc_block_buf(size, node, NULL);
+}
+
void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);
int vmemmap_populate_basepages(unsigned long start, unsigned long end,
int node);
@@ -2222,7 +2277,7 @@ extern int memory_failure(unsigned long pfn, int trapno, int flags);
extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
extern int unpoison_memory(unsigned long pfn);
extern int get_hwpoison_page(struct page *page);
-extern void put_hwpoison_page(struct page *page);
+#define put_hwpoison_page(page) put_page(page)
extern int sysctl_memory_failure_early_kill;
extern int sysctl_memory_failure_recovery;
extern void shake_page(struct page *p, int access);
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index cf55945c83fb..712e8c37a200 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -100,4 +100,6 @@ static __always_inline enum lru_list page_lru(struct page *page)
return lru;
}
+#define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
+
#endif
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index f8d1492a114f..d3ebb9d21a53 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -54,6 +54,8 @@ struct page {
* see PAGE_MAPPING_ANON below.
*/
void *s_mem; /* slab first object */
+ atomic_t compound_mapcount; /* first tail page */
+ /* page_deferred_list().next -- second tail page */
};
/* Second double word */
@@ -61,6 +63,7 @@ struct page {
union {
pgoff_t index; /* Our offset within mapping. */
void *freelist; /* sl[aou]b first free object */
+ /* page_deferred_list().prev -- second tail page */
};
union {
@@ -81,20 +84,9 @@ struct page {
union {
/*
- * Count of ptes mapped in
- * mms, to show when page is
- * mapped & limit reverse map
- * searches.
- *
- * Used also for tail pages
- * refcounting instead of
- * _count. Tail pages cannot
- * be mapped and keeping the
- * tail page _count zero at
- * all times guarantees
- * get_page_unless_zero() will
- * never succeed on tail
- * pages.
+ * Count of ptes mapped in mms, to show
+ * when page is mapped & limit reverse
+ * map searches.
*/
atomic_t _mapcount;
@@ -124,6 +116,11 @@ struct page {
* Can be used as a generic list
* by the page owner.
*/
+ struct dev_pagemap *pgmap; /* ZONE_DEVICE pages are never on an
+ * lru or handled by a slab
+ * allocator, this points to the
+ * hosting device page map.
+ */
struct { /* slub per cpu partial pages */
struct page *next; /* Next partial slab */
#ifdef CONFIG_64BIT
@@ -369,9 +366,10 @@ struct core_state {
};
enum {
- MM_FILEPAGES,
- MM_ANONPAGES,
- MM_SWAPENTS,
+ MM_FILEPAGES, /* Resident file mapping pages */
+ MM_ANONPAGES, /* Resident anonymous pages */
+ MM_SWAPENTS, /* Anonymous swap entries */
+ MM_SHMEMPAGES, /* Resident shared memory pages */
NR_MM_COUNTERS
};
@@ -426,7 +424,7 @@ struct mm_struct {
unsigned long total_vm; /* Total pages mapped */
unsigned long locked_vm; /* Pages that have PG_mlocked set */
unsigned long pinned_vm; /* Refcount permanently increased */
- unsigned long shared_vm; /* Shared pages (files) */
+ unsigned long data_vm; /* VM_WRITE & ~VM_SHARED/GROWSDOWN */
unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE */
unsigned long stack_vm; /* VM_GROWSUP/DOWN */
unsigned long def_flags;
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 772362adf471..053824b0a412 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -56,4 +56,10 @@ void dump_mm(const struct mm_struct *mm);
#define VIRTUAL_BUG_ON(cond) do { } while (0)
#endif
+#ifdef CONFIG_DEBUG_VM_PGFLAGS
+#define VM_BUG_ON_PGFLAGS(cond, page) VM_BUG_ON_PAGE(cond, page)
+#else
+#define VM_BUG_ON_PGFLAGS(cond, page) BUILD_BUG_ON_INVALID(cond)
+#endif
+
#endif
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index e23a9e704536..33bb1b19273e 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -195,11 +195,6 @@ static inline int is_active_lru(enum lru_list lru)
return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE);
}
-static inline int is_unevictable_lru(enum lru_list lru)
-{
- return (lru == LRU_UNEVICTABLE);
-}
-
struct zone_reclaim_stat {
/*
* The pageout code in vmscan.c keeps track of how many of the
@@ -361,10 +356,10 @@ struct zone {
struct per_cpu_pageset __percpu *pageset;
/*
- * This is a per-zone reserve of pages that should not be
- * considered dirtyable memory.
+ * This is a per-zone reserve of pages that are not available
+ * to userspace allocations.
*/
- unsigned long dirty_balance_reserve;
+ unsigned long totalreserve_pages;
#ifndef CONFIG_SPARSEMEM
/*
@@ -576,19 +571,17 @@ static inline bool zone_is_empty(struct zone *zone)
/* Maximum number of zones on a zonelist */
#define MAX_ZONES_PER_ZONELIST (MAX_NUMNODES * MAX_NR_ZONES)
+enum {
+ ZONELIST_FALLBACK, /* zonelist with fallback */
#ifdef CONFIG_NUMA
-
-/*
- * The NUMA zonelists are doubled because we need zonelists that restrict the
- * allocations to a single node for __GFP_THISNODE.
- *
- * [0] : Zonelist with fallback
- * [1] : No fallback (__GFP_THISNODE)
- */
-#define MAX_ZONELISTS 2
-#else
-#define MAX_ZONELISTS 1
+ /*
+ * The NUMA zonelists are doubled because we need zonelists that
+ * restrict the allocations to a single node for __GFP_THISNODE.
+ */
+ ZONELIST_NOFALLBACK, /* zonelist without fallback (__GFP_THISNODE) */
#endif
+ MAX_ZONELISTS
+};
/*
* This struct contains information about a zone in a zonelist. It is stored
@@ -1207,13 +1200,13 @@ unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
* the zone and PFN linkages are still valid. This is expensive, but walkers
* of the full memmap are extremely rare.
*/
-int memmap_valid_within(unsigned long pfn,
+bool memmap_valid_within(unsigned long pfn,
struct page *page, struct zone *zone);
#else
-static inline int memmap_valid_within(unsigned long pfn,
+static inline bool memmap_valid_within(unsigned long pfn,
struct page *page, struct zone *zone)
{
- return 1;
+ return true;
}
#endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 64f36e09a790..6e4c645e1c0d 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -404,7 +404,7 @@ struct virtio_device_id {
* For Hyper-V devices we use the device guid as the id.
*/
struct hv_vmbus_device_id {
- __u8 guid[16];
+ uuid_le guid;
kernel_ulong_t driver_data; /* Data private to the driver */
};
diff --git a/include/linux/module.h b/include/linux/module.h
index 3a19c79918e0..4560d8f1545d 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -302,6 +302,28 @@ struct mod_tree_node {
struct latch_tree_node node;
};
+struct module_layout {
+ /* The actual code + data. */
+ void *base;
+ /* Total size. */
+ unsigned int size;
+ /* The size of the executable code. */
+ unsigned int text_size;
+ /* Size of RO section of the module (text+rodata) */
+ unsigned int ro_size;
+
+#ifdef CONFIG_MODULES_TREE_LOOKUP
+ struct mod_tree_node mtn;
+#endif
+};
+
+#ifdef CONFIG_MODULES_TREE_LOOKUP
+/* Only touch one cacheline for common rbtree-for-core-layout case. */
+#define __module_layout_align ____cacheline_aligned
+#else
+#define __module_layout_align
+#endif
+
struct module {
enum module_state state;
@@ -366,37 +388,9 @@ struct module {
/* Startup function. */
int (*init)(void);
- /*
- * If this is non-NULL, vfree() after init() returns.
- *
- * Cacheline align here, such that:
- * module_init, module_core, init_size, core_size,
- * init_text_size, core_text_size and mtn_core::{mod,node[0]}
- * are on the same cacheline.
- */
- void *module_init ____cacheline_aligned;
-
- /* Here is the actual code + data, vfree'd on unload. */
- void *module_core;
-
- /* Here are the sizes of the init and core sections */
- unsigned int init_size, core_size;
-
- /* The size of the executable code in each section. */
- unsigned int init_text_size, core_text_size;
-
-#ifdef CONFIG_MODULES_TREE_LOOKUP
- /*
- * We want mtn_core::{mod,node[0]} to be in the same cacheline as the
- * above entries such that a regular lookup will only touch one
- * cacheline.
- */
- struct mod_tree_node mtn_core;
- struct mod_tree_node mtn_init;
-#endif
-
- /* Size of RO sections of the module (text+rodata) */
- unsigned int init_ro_size, core_ro_size;
+ /* Core layout: rbtree is accessed frequently, so keep together. */
+ struct module_layout core_layout __module_layout_align;
+ struct module_layout init_layout;
/* Arch-specific module values */
struct mod_arch_specific arch;
@@ -505,15 +499,15 @@ bool is_module_text_address(unsigned long addr);
static inline bool within_module_core(unsigned long addr,
const struct module *mod)
{
- return (unsigned long)mod->module_core <= addr &&
- addr < (unsigned long)mod->module_core + mod->core_size;
+ return (unsigned long)mod->core_layout.base <= addr &&
+ addr < (unsigned long)mod->core_layout.base + mod->core_layout.size;
}
static inline bool within_module_init(unsigned long addr,
const struct module *mod)
{
- return (unsigned long)mod->module_init <= addr &&
- addr < (unsigned long)mod->module_init + mod->init_size;
+ return (unsigned long)mod->init_layout.base <= addr &&
+ addr < (unsigned long)mod->init_layout.base + mod->init_layout.size;
}
static inline bool within_module(unsigned long addr, const struct module *mod)
@@ -768,9 +762,13 @@ extern int module_sysfs_initialized;
#ifdef CONFIG_DEBUG_SET_MODULE_RONX
extern void set_all_modules_text_rw(void);
extern void set_all_modules_text_ro(void);
+extern void module_enable_ro(const struct module *mod);
+extern void module_disable_ro(const struct module *mod);
#else
static inline void set_all_modules_text_rw(void) { }
static inline void set_all_modules_text_ro(void) { }
+static inline void module_enable_ro(const struct module *mod) { }
+static inline void module_disable_ro(const struct module *mod) { }
#endif
#ifdef CONFIG_GENERIC_BUG
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 366cf77953b5..58f3ba709ade 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -142,7 +142,9 @@
#endif
#ifndef map_bankwidth
+#ifdef CONFIG_MTD
#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
+#endif
static inline int map_bankwidth(void *map)
{
BUG();
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index f17fa75809aa..cc84923011c0 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -254,6 +254,17 @@ struct mtd_info {
int usecount;
};
+static inline void mtd_set_of_node(struct mtd_info *mtd,
+ struct device_node *np)
+{
+ mtd->dev.of_node = np;
+}
+
+static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
+{
+ return mtd->dev.of_node;
+}
+
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
void **virt, resource_size_t *phys);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 5a9d1d4c2487..bdd68e22b5a5 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -129,6 +129,14 @@ typedef enum {
/* Enable Hardware ECC before syndrome is read back from flash */
#define NAND_ECC_READSYN 2
+/*
+ * Enable generic NAND 'page erased' check. This check is only done when
+ * ecc.correct() returns -EBADMSG.
+ * Set this flag if your implementation does not fix bitflips in erased
+ * pages and you want to rely on the default implementation.
+ */
+#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
+
/* Bit mask for flags passed to do_nand_read_ecc */
#define NAND_GET_DEVICE 0x80
@@ -276,15 +284,15 @@ struct nand_onfi_params {
__le16 t_r;
__le16 t_ccs;
__le16 src_sync_timing_mode;
- __le16 src_ssync_features;
+ u8 src_ssync_features;
__le16 clk_pin_capacitance_typ;
__le16 io_pin_capacitance_typ;
__le16 input_pin_capacitance_typ;
u8 input_pin_capacitance_max;
u8 driver_strength_support;
__le16 t_int_r;
- __le16 t_ald;
- u8 reserved4[7];
+ __le16 t_adl;
+ u8 reserved4[8];
/* vendor */
__le16 vendor_revision;
@@ -407,7 +415,7 @@ struct nand_jedec_params {
__le16 input_pin_capacitance_typ;
__le16 clk_pin_capacitance_typ;
u8 driver_strength_support;
- __le16 t_ald;
+ __le16 t_adl;
u8 reserved4[36];
/* ECC and endurance block */
@@ -451,12 +459,19 @@ struct nand_hw_control {
* @total: total number of ECC bytes per page
* @prepad: padding information for syndrome based ECC generators
* @postpad: padding information for syndrome based ECC generators
+ * @options: ECC specific options (see NAND_ECC_XXX flags defined above)
* @layout: ECC layout control struct pointer
* @priv: pointer to private ECC control data
* @hwctl: function to control hardware ECC generator. Must only
* be provided if an hardware ECC is available
* @calculate: function for ECC calculation or readback from ECC hardware
- * @correct: function for ECC correction, matching to ECC generator (sw/hw)
+ * @correct: function for ECC correction, matching to ECC generator (sw/hw).
+ * Should return a positive number representing the number of
+ * corrected bitflips, -EBADMSG if the number of bitflips exceed
+ * ECC strength, or any other error code if the error is not
+ * directly related to correction.
+ * If -EBADMSG is returned the input buffers should be left
+ * untouched.
* @read_page_raw: function to read a raw page without ECC. This function
* should hide the specific layout used by the ECC
* controller and always return contiguous in-band and
@@ -494,6 +509,7 @@ struct nand_ecc_ctrl {
int strength;
int prepad;
int postpad;
+ unsigned int options;
struct nand_ecclayout *layout;
void *priv;
void (*hwctl)(struct mtd_info *mtd, int mode);
@@ -540,11 +556,11 @@ struct nand_buffers {
/**
* struct nand_chip - NAND Private Flash Chip Data
+ * @mtd: MTD device registered to the MTD framework
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
* flash device
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
* flash device.
- * @flash_node: [BOARDSPECIFIC] device node describing this instance
* @read_byte: [REPLACEABLE] read one byte from the chip
* @read_word: [REPLACEABLE] read one word from the chip
* @write_byte: [REPLACEABLE] write a single byte to the chip on the
@@ -640,11 +656,10 @@ struct nand_buffers {
*/
struct nand_chip {
+ struct mtd_info mtd;
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
- struct device_node *flash_node;
-
uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
@@ -719,6 +734,37 @@ struct nand_chip {
void *priv;
};
+static inline void nand_set_flash_node(struct nand_chip *chip,
+ struct device_node *np)
+{
+ mtd_set_of_node(&chip->mtd, np);
+}
+
+static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
+{
+ return mtd_get_of_node(&chip->mtd);
+}
+
+static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
+{
+ return container_of(mtd, struct nand_chip, mtd);
+}
+
+static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
+{
+ return &chip->mtd;
+}
+
+static inline void *nand_get_controller_data(struct nand_chip *chip)
+{
+ return chip->priv;
+}
+
+static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
+{
+ chip->priv = priv;
+}
+
/*
* NAND Flash Manufacturer ID Codes
*/
@@ -907,15 +953,6 @@ struct platform_nand_data {
struct platform_nand_ctrl ctrl;
};
-/* Some helpers to access the data structures */
-static inline
-struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
-
- return chip->priv;
-}
-
/* return the supported features. */
static inline int onfi_feature(struct nand_chip *chip)
{
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
index 74acf5367556..fb0bc3420a10 100644
--- a/include/linux/mtd/nand_bch.h
+++ b/include/linux/mtd/nand_bch.h
@@ -55,7 +55,7 @@ static inline int
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- return -1;
+ return -ENOTSUPP;
}
static inline struct nand_bch_control *
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index 6a35e6de5da1..70736e1e6c8f 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -41,7 +41,6 @@ struct mtd_partition {
uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
- struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */
};
#define MTDPART_OFS_RETAIN (-3)
@@ -56,11 +55,9 @@ struct device_node;
/**
* struct mtd_part_parser_data - used to pass data to MTD partition parsers.
* @origin: for RedBoot, start address of MTD device
- * @of_node: for OF parsers, device node containing partitioning information
*/
struct mtd_part_parser_data {
unsigned long origin;
- struct device_node *of_node;
};
@@ -72,13 +69,33 @@ struct mtd_part_parser {
struct list_head list;
struct module *owner;
const char *name;
- int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
+ int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
struct mtd_part_parser_data *);
+ void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
};
-extern void register_mtd_parser(struct mtd_part_parser *parser);
+/* Container for passing around a set of parsed partitions */
+struct mtd_partitions {
+ const struct mtd_partition *parts;
+ int nr_parts;
+ const struct mtd_part_parser *parser;
+};
+
+extern int __register_mtd_parser(struct mtd_part_parser *parser,
+ struct module *owner);
+#define register_mtd_parser(parser) __register_mtd_parser(parser, THIS_MODULE)
+
extern void deregister_mtd_parser(struct mtd_part_parser *parser);
+/*
+ * module_mtd_part_parser() - Helper macro for MTD partition parsers that don't
+ * do anything special in module init/exit. Each driver may only use this macro
+ * once, and calling it replaces module_init() and module_exit().
+ */
+#define module_mtd_part_parser(__mtd_part_parser) \
+ module_driver(__mtd_part_parser, register_mtd_parser, \
+ deregister_mtd_parser)
+
int mtd_is_partition(const struct mtd_info *mtd);
int mtd_add_partition(struct mtd_info *master, const char *name,
long long offset, long long length);
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index 1c28f8879b1c..2251add65fa7 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -143,11 +143,11 @@ enum flctl_ecc_res_t {
struct dma_chan;
struct sh_flctl {
- struct mtd_info mtd;
struct nand_chip chip;
struct platform_device *pdev;
struct dev_pm_qos_request pm_qos;
void __iomem *reg;
+ resource_size_t fifo;
uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
int read_bytes;
@@ -186,7 +186,7 @@ struct sh_flctl_platform_data {
static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
{
- return container_of(mtdinfo, struct sh_flctl, mtd);
+ return container_of(mtd_to_nand(mtdinfo), struct sh_flctl, chip);
}
#endif /* __SH_FLCTL_H__ */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index bc742dac7d3a..62356d50815b 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/mtd/cfi.h>
+#include <linux/mtd/mtd.h>
/*
* Manufacturer IDs
@@ -117,14 +118,11 @@ enum spi_nor_option_flags {
SNOR_F_USE_FSR = BIT(0),
};
-struct mtd_info;
-
/**
* struct spi_nor - Structure for defining a the SPI NOR layer
* @mtd: point to a mtd_info structure
* @lock: the lock for the read/write/erase/lock/unlock operations
* @dev: point to a spi device, or a spi nor controller device.
- * @flash_node: point to a device node describing this flash instance.
* @page_size: the page size of the SPI NOR
* @addr_width: number of address bytes
* @erase_opcode: the opcode for erasing a sector
@@ -144,7 +142,8 @@ struct mtd_info;
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
- * at the offset @offs
+ * at the offset @offs; if not provided by the driver,
+ * spi-nor will send the erase opcode via write_reg()
* @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
* @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
@@ -155,7 +154,6 @@ struct spi_nor {
struct mtd_info mtd;
struct mutex lock;
struct device *dev;
- struct device_node *flash_node;
u32 page_size;
u8 addr_width;
u8 erase_opcode;
@@ -185,6 +183,17 @@ struct spi_nor {
void *priv;
};
+static inline void spi_nor_set_flash_node(struct spi_nor *nor,
+ struct device_node *np)
+{
+ mtd_set_of_node(&nor->mtd, np);
+}
+
+static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
+{
+ return mtd_get_of_node(&nor->mtd);
+}
+
/**
* spi_nor_scan() - scan the SPI NOR
* @nor: the spi_nor structure
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 43aeabd4b968..d6f9b4e6006d 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -592,4 +592,18 @@ enum data_content4 {
NFS4_CONTENT_HOLE = 1,
};
+enum pnfs_update_layout_reason {
+ PNFS_UPDATE_LAYOUT_UNKNOWN = 0,
+ PNFS_UPDATE_LAYOUT_NO_PNFS,
+ PNFS_UPDATE_LAYOUT_RD_ZEROLEN,
+ PNFS_UPDATE_LAYOUT_MDSTHRESH,
+ PNFS_UPDATE_LAYOUT_NOMEM,
+ PNFS_UPDATE_LAYOUT_BULK_RECALL,
+ PNFS_UPDATE_LAYOUT_IO_TEST_FAIL,
+ PNFS_UPDATE_LAYOUT_FOUND_CACHED,
+ PNFS_UPDATE_LAYOUT_RETURN,
+ PNFS_UPDATE_LAYOUT_BLOCKED,
+ PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET,
+};
+
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 37a3d2981352..48e0320cd643 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -60,18 +60,12 @@ struct nfs_lockowner {
pid_t l_pid;
};
-#define NFS_IO_INPROGRESS 0
-struct nfs_io_counter {
- unsigned long flags;
- atomic_t io_count;
-};
-
struct nfs_lock_context {
atomic_t count;
struct list_head list;
struct nfs_open_context *open_context;
struct nfs_lockowner lockowner;
- struct nfs_io_counter io_count;
+ atomic_t io_count;
};
struct nfs4_state;
@@ -216,7 +210,6 @@ struct nfs_inode {
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
-#define NFS_INO_COMMIT (7) /* inode is committing unstable writes */
#define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
@@ -518,13 +511,25 @@ extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned
*/
extern int nfs_sync_inode(struct inode *inode);
extern int nfs_wb_all(struct inode *inode);
-extern int nfs_wb_page(struct inode *inode, struct page* page);
+extern int nfs_wb_single_page(struct inode *inode, struct page *page, bool launder);
extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
extern int nfs_commit_inode(struct inode *, int);
extern struct nfs_commit_data *nfs_commitdata_alloc(void);
extern void nfs_commit_free(struct nfs_commit_data *data);
static inline int
+nfs_wb_launder_page(struct inode *inode, struct page *page)
+{
+ return nfs_wb_single_page(inode, page, true);
+}
+
+static inline int
+nfs_wb_page(struct inode *inode, struct page *page)
+{
+ return nfs_wb_single_page(inode, page, false);
+}
+
+static inline int
nfs_have_writebacks(struct inode *inode)
{
return NFS_I(inode)->nrequests != 0;
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 2469ab0bb3a1..7fcc13c8cf1f 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -102,6 +102,7 @@ struct nfs_client {
#define NFS_SP4_MACH_CRED_STATEID 4 /* TEST_STATEID and FREE_STATEID */
#define NFS_SP4_MACH_CRED_WRITE 5 /* WRITE */
#define NFS_SP4_MACH_CRED_COMMIT 6 /* COMMIT */
+#define NFS_SP4_MACH_CRED_PNFS_CLEANUP 7 /* LAYOUTRETURN */
#endif /* CONFIG_NFS_V4 */
/* Our own IP address, as a null-terminated string.
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 11bbae44f4cb..791098a08a87 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1375,6 +1375,7 @@ enum {
NFS_IOHDR_ERROR = 0,
NFS_IOHDR_EOF,
NFS_IOHDR_REDO,
+ NFS_IOHDR_STAT,
};
struct nfs_pgio_header {
@@ -1420,11 +1421,12 @@ struct nfs_mds_commit_info {
struct list_head list;
};
+struct nfs_commit_info;
struct nfs_commit_data;
struct nfs_inode;
struct nfs_commit_completion_ops {
- void (*error_cleanup) (struct nfs_inode *nfsi);
void (*completion) (struct nfs_commit_data *data);
+ void (*resched_write) (struct nfs_commit_info *, struct nfs_page *);
};
struct nfs_commit_info {
@@ -1454,12 +1456,14 @@ struct nfs_commit_data {
const struct rpc_call_ops *mds_ops;
const struct nfs_commit_completion_ops *completion_ops;
int (*commit_done_cb) (struct rpc_task *task, struct nfs_commit_data *data);
+ unsigned long flags;
};
struct nfs_pgio_completion_ops {
void (*error_cleanup)(struct list_head *head);
void (*init_hdr)(struct nfs_pgio_header *hdr);
void (*completion)(struct nfs_pgio_header *hdr);
+ void (*reschedule_io)(struct nfs_pgio_header *hdr);
};
struct nfs_unlinkdata {
diff --git a/include/linux/nwpserial.h b/include/linux/nwpserial.h
deleted file mode 100644
index 9acb21572eaf..000000000000
--- a/include/linux/nwpserial.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Serial Port driver for a NWP uart device
- *
- * Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.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.
- *
- */
-#ifndef _NWPSERIAL_H
-#define _NWPSERIAL_H
-
-int nwpserial_register_port(struct uart_port *port);
-void nwpserial_unregister_port(int line);
-
-#endif /* _NWPSERIAL_H */
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 507daad0bc8d..01c0a556448b 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -3,6 +3,7 @@
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/of.h>
+#include <linux/io.h>
struct of_pci_range_parser {
struct device_node *node;
@@ -36,6 +37,8 @@ extern struct device_node *of_find_matching_node_by_address(
const struct of_device_id *matches,
u64 base_address);
extern void __iomem *of_iomap(struct device_node *device, int index);
+void __iomem *of_io_request_and_map(struct device_node *device,
+ int index, const char *name);
/* Extract an address from a device, returns the region size and
* the address space flags too. The PCI version uses a BAR number
@@ -57,6 +60,11 @@ extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
u64 *paddr, u64 *size);
extern bool of_dma_is_coherent(struct device_node *np);
#else /* CONFIG_OF_ADDRESS */
+static inline void __iomem *of_io_request_and_map(struct device_node *device,
+ int index, const char *name)
+{
+ return IOMEM_ERR_PTR(-EINVAL);
+}
static inline u64 of_translate_address(struct device_node *np,
const __be32 *addr)
@@ -112,12 +120,7 @@ static inline bool of_dma_is_coherent(struct device_node *np)
extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
void __iomem *of_iomap(struct device_node *node, int index);
-void __iomem *of_io_request_and_map(struct device_node *device,
- int index, const char *name);
#else
-
-#include <linux/io.h>
-
static inline int of_address_to_resource(struct device_node *dev, int index,
struct resource *r)
{
@@ -128,12 +131,6 @@ static inline void __iomem *of_iomap(struct device_node *device, int index)
{
return NULL;
}
-
-static inline void __iomem *of_io_request_and_map(struct device_node *device,
- int index, const char *name)
-{
- return IOMEM_ERR_PTR(-EINVAL);
-}
#endif
#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 87d6d1632dd4..092186c62ff4 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -51,8 +51,14 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
extern int of_get_named_gpio_flags(struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags);
-extern int of_mm_gpiochip_add(struct device_node *np,
- struct of_mm_gpio_chip *mm_gc);
+extern int of_mm_gpiochip_add_data(struct device_node *np,
+ struct of_mm_gpio_chip *mm_gc,
+ void *data);
+static inline int of_mm_gpiochip_add(struct device_node *np,
+ struct of_mm_gpio_chip *mm_gc)
+{
+ return of_mm_gpiochip_add_data(np, mm_gc, NULL);
+}
extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
extern int of_gpiochip_add(struct gpio_chip *gc);
@@ -67,6 +73,9 @@ extern int of_gpio_simple_xlate(struct gpio_chip *gc,
static inline int of_get_named_gpio_flags(struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags)
{
+ if (flags)
+ *flags = 0;
+
return -ENOSYS;
}
diff --git a/include/linux/omap-dma.h b/include/linux/omap-dma.h
index 88fa8af2b937..1d99b61adc65 100644
--- a/include/linux/omap-dma.h
+++ b/include/linux/omap-dma.h
@@ -267,6 +267,9 @@ struct omap_dma_reg {
u8 type;
};
+#define SDMA_FILTER_PARAM(hw_req) ((int[]) { (hw_req) })
+struct dma_slave_map;
+
/* System DMA platform data structure */
struct omap_system_dma_plat_info {
const struct omap_dma_reg *reg_map;
@@ -278,6 +281,9 @@ struct omap_system_dma_plat_info {
void (*clear_dma)(int lch);
void (*dma_write)(u32 val, int reg, int lch);
u32 (*dma_read)(int reg, int lch);
+
+ const struct dma_slave_map *slave_map;
+ int slavecnt;
};
#ifdef CONFIG_ARCH_OMAP2PLUS
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index bb53c7b86315..19724e6ebd26 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -101,9 +101,6 @@ enum pageflags {
#ifdef CONFIG_MEMORY_FAILURE
PG_hwpoison, /* hardware poisoned page. Don't touch */
#endif
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- PG_compound_lock,
-#endif
#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
PG_young,
PG_idle,
@@ -129,53 +126,104 @@ enum pageflags {
/* SLOB */
PG_slob_free = PG_private,
+
+ /* Compound pages. Stored in first tail page's flags */
+ PG_double_map = PG_private_2,
};
#ifndef __GENERATING_BOUNDS_H
+struct page; /* forward declaration */
+
+static inline struct page *compound_head(struct page *page)
+{
+ unsigned long head = READ_ONCE(page->compound_head);
+
+ if (unlikely(head & 1))
+ return (struct page *) (head - 1);
+ return page;
+}
+
+static inline int PageTail(struct page *page)
+{
+ return READ_ONCE(page->compound_head) & 1;
+}
+
+static inline int PageCompound(struct page *page)
+{
+ return test_bit(PG_head, &page->flags) || PageTail(page);
+}
+
+/*
+ * Page flags policies wrt compound pages
+ *
+ * PF_ANY:
+ * the page flag is relevant for small, head and tail pages.
+ *
+ * PF_HEAD:
+ * for compound page all operations related to the page flag applied to
+ * head page.
+ *
+ * PF_NO_TAIL:
+ * modifications of the page flag must be done on small or head pages,
+ * checks can be done on tail pages too.
+ *
+ * PF_NO_COMPOUND:
+ * the page flag is not relevant for compound pages.
+ */
+#define PF_ANY(page, enforce) page
+#define PF_HEAD(page, enforce) compound_head(page)
+#define PF_NO_TAIL(page, enforce) ({ \
+ VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \
+ compound_head(page);})
+#define PF_NO_COMPOUND(page, enforce) ({ \
+ VM_BUG_ON_PGFLAGS(enforce && PageCompound(page), page); \
+ page;})
+
/*
* Macros to create function definitions for page flags
*/
-#define TESTPAGEFLAG(uname, lname) \
-static inline int Page##uname(const struct page *page) \
- { return test_bit(PG_##lname, &page->flags); }
+#define TESTPAGEFLAG(uname, lname, policy) \
+static inline int Page##uname(struct page *page) \
+ { return test_bit(PG_##lname, &policy(page, 0)->flags); }
-#define SETPAGEFLAG(uname, lname) \
+#define SETPAGEFLAG(uname, lname, policy) \
static inline void SetPage##uname(struct page *page) \
- { set_bit(PG_##lname, &page->flags); }
+ { set_bit(PG_##lname, &policy(page, 1)->flags); }
-#define CLEARPAGEFLAG(uname, lname) \
+#define CLEARPAGEFLAG(uname, lname, policy) \
static inline void ClearPage##uname(struct page *page) \
- { clear_bit(PG_##lname, &page->flags); }
+ { clear_bit(PG_##lname, &policy(page, 1)->flags); }
-#define __SETPAGEFLAG(uname, lname) \
+#define __SETPAGEFLAG(uname, lname, policy) \
static inline void __SetPage##uname(struct page *page) \
- { __set_bit(PG_##lname, &page->flags); }
+ { __set_bit(PG_##lname, &policy(page, 1)->flags); }
-#define __CLEARPAGEFLAG(uname, lname) \
+#define __CLEARPAGEFLAG(uname, lname, policy) \
static inline void __ClearPage##uname(struct page *page) \
- { __clear_bit(PG_##lname, &page->flags); }
+ { __clear_bit(PG_##lname, &policy(page, 1)->flags); }
-#define TESTSETFLAG(uname, lname) \
+#define TESTSETFLAG(uname, lname, policy) \
static inline int TestSetPage##uname(struct page *page) \
- { return test_and_set_bit(PG_##lname, &page->flags); }
+ { return test_and_set_bit(PG_##lname, &policy(page, 1)->flags); }
-#define TESTCLEARFLAG(uname, lname) \
+#define TESTCLEARFLAG(uname, lname, policy) \
static inline int TestClearPage##uname(struct page *page) \
- { return test_and_clear_bit(PG_##lname, &page->flags); }
-
-#define __TESTCLEARFLAG(uname, lname) \
-static inline int __TestClearPage##uname(struct page *page) \
- { return __test_and_clear_bit(PG_##lname, &page->flags); }
+ { return test_and_clear_bit(PG_##lname, &policy(page, 1)->flags); }
-#define PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \
- SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname)
+#define PAGEFLAG(uname, lname, policy) \
+ TESTPAGEFLAG(uname, lname, policy) \
+ SETPAGEFLAG(uname, lname, policy) \
+ CLEARPAGEFLAG(uname, lname, policy)
-#define __PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \
- __SETPAGEFLAG(uname, lname) __CLEARPAGEFLAG(uname, lname)
+#define __PAGEFLAG(uname, lname, policy) \
+ TESTPAGEFLAG(uname, lname, policy) \
+ __SETPAGEFLAG(uname, lname, policy) \
+ __CLEARPAGEFLAG(uname, lname, policy)
-#define TESTSCFLAG(uname, lname) \
- TESTSETFLAG(uname, lname) TESTCLEARFLAG(uname, lname)
+#define TESTSCFLAG(uname, lname, policy) \
+ TESTSETFLAG(uname, lname, policy) \
+ TESTCLEARFLAG(uname, lname, policy)
#define TESTPAGEFLAG_FALSE(uname) \
static inline int Page##uname(const struct page *page) { return 0; }
@@ -195,56 +243,62 @@ static inline int TestSetPage##uname(struct page *page) { return 0; }
#define TESTCLEARFLAG_FALSE(uname) \
static inline int TestClearPage##uname(struct page *page) { return 0; }
-#define __TESTCLEARFLAG_FALSE(uname) \
-static inline int __TestClearPage##uname(struct page *page) { return 0; }
-
#define PAGEFLAG_FALSE(uname) TESTPAGEFLAG_FALSE(uname) \
SETPAGEFLAG_NOOP(uname) CLEARPAGEFLAG_NOOP(uname)
#define TESTSCFLAG_FALSE(uname) \
TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname)
-struct page; /* forward declaration */
-
-TESTPAGEFLAG(Locked, locked)
-PAGEFLAG(Error, error) TESTCLEARFLAG(Error, error)
-PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced)
- __SETPAGEFLAG(Referenced, referenced)
-PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty)
-PAGEFLAG(LRU, lru) __CLEARPAGEFLAG(LRU, lru)
-PAGEFLAG(Active, active) __CLEARPAGEFLAG(Active, active)
- TESTCLEARFLAG(Active, active)
-__PAGEFLAG(Slab, slab)
-PAGEFLAG(Checked, checked) /* Used by some filesystems */
-PAGEFLAG(Pinned, pinned) TESTSCFLAG(Pinned, pinned) /* Xen */
-PAGEFLAG(SavePinned, savepinned); /* Xen */
-PAGEFLAG(Foreign, foreign); /* Xen */
-PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
-PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
- __SETPAGEFLAG(SwapBacked, swapbacked)
-
-__PAGEFLAG(SlobFree, slob_free)
+__PAGEFLAG(Locked, locked, PF_NO_TAIL)
+PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND)
+PAGEFLAG(Referenced, referenced, PF_HEAD)
+ TESTCLEARFLAG(Referenced, referenced, PF_HEAD)
+ __SETPAGEFLAG(Referenced, referenced, PF_HEAD)
+PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD)
+ __CLEARPAGEFLAG(Dirty, dirty, PF_HEAD)
+PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD)
+PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD)
+ TESTCLEARFLAG(Active, active, PF_HEAD)
+__PAGEFLAG(Slab, slab, PF_NO_TAIL)
+__PAGEFLAG(SlobFree, slob_free, PF_NO_TAIL)
+PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */
+
+/* Xen */
+PAGEFLAG(Pinned, pinned, PF_NO_COMPOUND)
+ TESTSCFLAG(Pinned, pinned, PF_NO_COMPOUND)
+PAGEFLAG(SavePinned, savepinned, PF_NO_COMPOUND);
+PAGEFLAG(Foreign, foreign, PF_NO_COMPOUND);
+
+PAGEFLAG(Reserved, reserved, PF_NO_COMPOUND)
+ __CLEARPAGEFLAG(Reserved, reserved, PF_NO_COMPOUND)
+PAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL)
+ __CLEARPAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL)
+ __SETPAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL)
/*
* Private page markings that may be used by the filesystem that owns the page
* for its own purposes.
* - PG_private and PG_private_2 cause releasepage() and co to be invoked
*/
-PAGEFLAG(Private, private) __SETPAGEFLAG(Private, private)
- __CLEARPAGEFLAG(Private, private)
-PAGEFLAG(Private2, private_2) TESTSCFLAG(Private2, private_2)
-PAGEFLAG(OwnerPriv1, owner_priv_1) TESTCLEARFLAG(OwnerPriv1, owner_priv_1)
+PAGEFLAG(Private, private, PF_ANY) __SETPAGEFLAG(Private, private, PF_ANY)
+ __CLEARPAGEFLAG(Private, private, PF_ANY)
+PAGEFLAG(Private2, private_2, PF_ANY) TESTSCFLAG(Private2, private_2, PF_ANY)
+PAGEFLAG(OwnerPriv1, owner_priv_1, PF_ANY)
+ TESTCLEARFLAG(OwnerPriv1, owner_priv_1, PF_ANY)
/*
* Only test-and-set exist for PG_writeback. The unconditional operators are
* risky: they bypass page accounting.
*/
-TESTPAGEFLAG(Writeback, writeback) TESTSCFLAG(Writeback, writeback)
-PAGEFLAG(MappedToDisk, mappedtodisk)
+TESTPAGEFLAG(Writeback, writeback, PF_NO_COMPOUND)
+ TESTSCFLAG(Writeback, writeback, PF_NO_COMPOUND)
+PAGEFLAG(MappedToDisk, mappedtodisk, PF_NO_COMPOUND)
/* PG_readahead is only used for reads; PG_reclaim is only for writes */
-PAGEFLAG(Reclaim, reclaim) TESTCLEARFLAG(Reclaim, reclaim)
-PAGEFLAG(Readahead, reclaim) TESTCLEARFLAG(Readahead, reclaim)
+PAGEFLAG(Reclaim, reclaim, PF_NO_COMPOUND)
+ TESTCLEARFLAG(Reclaim, reclaim, PF_NO_COMPOUND)
+PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND)
+ TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND)
#ifdef CONFIG_HIGHMEM
/*
@@ -257,31 +311,33 @@ PAGEFLAG_FALSE(HighMem)
#endif
#ifdef CONFIG_SWAP
-PAGEFLAG(SwapCache, swapcache)
+PAGEFLAG(SwapCache, swapcache, PF_NO_COMPOUND)
#else
PAGEFLAG_FALSE(SwapCache)
#endif
-PAGEFLAG(Unevictable, unevictable) __CLEARPAGEFLAG(Unevictable, unevictable)
- TESTCLEARFLAG(Unevictable, unevictable)
+PAGEFLAG(Unevictable, unevictable, PF_HEAD)
+ __CLEARPAGEFLAG(Unevictable, unevictable, PF_HEAD)
+ TESTCLEARFLAG(Unevictable, unevictable, PF_HEAD)
#ifdef CONFIG_MMU
-PAGEFLAG(Mlocked, mlocked) __CLEARPAGEFLAG(Mlocked, mlocked)
- TESTSCFLAG(Mlocked, mlocked) __TESTCLEARFLAG(Mlocked, mlocked)
+PAGEFLAG(Mlocked, mlocked, PF_NO_TAIL)
+ __CLEARPAGEFLAG(Mlocked, mlocked, PF_NO_TAIL)
+ TESTSCFLAG(Mlocked, mlocked, PF_NO_TAIL)
#else
PAGEFLAG_FALSE(Mlocked) __CLEARPAGEFLAG_NOOP(Mlocked)
- TESTSCFLAG_FALSE(Mlocked) __TESTCLEARFLAG_FALSE(Mlocked)
+ TESTSCFLAG_FALSE(Mlocked)
#endif
#ifdef CONFIG_ARCH_USES_PG_UNCACHED
-PAGEFLAG(Uncached, uncached)
+PAGEFLAG(Uncached, uncached, PF_NO_COMPOUND)
#else
PAGEFLAG_FALSE(Uncached)
#endif
#ifdef CONFIG_MEMORY_FAILURE
-PAGEFLAG(HWPoison, hwpoison)
-TESTSCFLAG(HWPoison, hwpoison)
+PAGEFLAG(HWPoison, hwpoison, PF_ANY)
+TESTSCFLAG(HWPoison, hwpoison, PF_ANY)
#define __PG_HWPOISON (1UL << PG_hwpoison)
#else
PAGEFLAG_FALSE(HWPoison)
@@ -289,10 +345,10 @@ PAGEFLAG_FALSE(HWPoison)
#endif
#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
-TESTPAGEFLAG(Young, young)
-SETPAGEFLAG(Young, young)
-TESTCLEARFLAG(Young, young)
-PAGEFLAG(Idle, idle)
+TESTPAGEFLAG(Young, young, PF_ANY)
+SETPAGEFLAG(Young, young, PF_ANY)
+TESTCLEARFLAG(Young, young, PF_ANY)
+PAGEFLAG(Idle, idle, PF_ANY)
#endif
/*
@@ -317,6 +373,7 @@ PAGEFLAG(Idle, idle)
static inline int PageAnon(struct page *page)
{
+ page = compound_head(page);
return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
}
@@ -329,6 +386,7 @@ static inline int PageAnon(struct page *page)
*/
static inline int PageKsm(struct page *page)
{
+ page = compound_head(page);
return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) ==
(PAGE_MAPPING_ANON | PAGE_MAPPING_KSM);
}
@@ -340,8 +398,9 @@ u64 stable_page_flags(struct page *page);
static inline int PageUptodate(struct page *page)
{
- int ret = test_bit(PG_uptodate, &(page)->flags);
-
+ int ret;
+ page = compound_head(page);
+ ret = test_bit(PG_uptodate, &(page)->flags);
/*
* Must ensure that the data we read out of the page is loaded
* _after_ we've loaded page->flags to check for PageUptodate.
@@ -358,22 +417,24 @@ static inline int PageUptodate(struct page *page)
static inline void __SetPageUptodate(struct page *page)
{
+ VM_BUG_ON_PAGE(PageTail(page), page);
smp_wmb();
- __set_bit(PG_uptodate, &(page)->flags);
+ __set_bit(PG_uptodate, &page->flags);
}
static inline void SetPageUptodate(struct page *page)
{
+ VM_BUG_ON_PAGE(PageTail(page), page);
/*
* Memory barrier must be issued before setting the PG_uptodate bit,
* so that all previous stores issued in order to bring the page
* uptodate are actually visible before PageUptodate becomes true.
*/
smp_wmb();
- set_bit(PG_uptodate, &(page)->flags);
+ set_bit(PG_uptodate, &page->flags);
}
-CLEARPAGEFLAG(Uptodate, uptodate)
+CLEARPAGEFLAG(Uptodate, uptodate, PF_NO_TAIL)
int test_clear_page_writeback(struct page *page);
int __test_set_page_writeback(struct page *page, bool keep_write);
@@ -393,12 +454,7 @@ static inline void set_page_writeback_keepwrite(struct page *page)
test_set_page_writeback_keepwrite(page);
}
-__PAGEFLAG(Head, head) CLEARPAGEFLAG(Head, head)
-
-static inline int PageTail(struct page *page)
-{
- return READ_ONCE(page->compound_head) & 1;
-}
+__PAGEFLAG(Head, head, PF_ANY) CLEARPAGEFLAG(Head, head, PF_ANY)
static inline void set_compound_head(struct page *page, struct page *head)
{
@@ -410,20 +466,6 @@ static inline void clear_compound_head(struct page *page)
WRITE_ONCE(page->compound_head, 0);
}
-static inline struct page *compound_head(struct page *page)
-{
- unsigned long head = READ_ONCE(page->compound_head);
-
- if (unlikely(head & 1))
- return (struct page *) (head - 1);
- return page;
-}
-
-static inline int PageCompound(struct page *page)
-{
- return PageHead(page) || PageTail(page);
-
-}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline void ClearPageCompound(struct page *page)
{
@@ -484,22 +526,43 @@ static inline int PageTransTail(struct page *page)
return PageTail(page);
}
-#else
-
-static inline int PageTransHuge(struct page *page)
+/*
+ * PageDoubleMap indicates that the compound page is mapped with PTEs as well
+ * as PMDs.
+ *
+ * This is required for optimization of rmap operations for THP: we can postpone
+ * per small page mapcount accounting (and its overhead from atomic operations)
+ * until the first PMD split.
+ *
+ * For the page PageDoubleMap means ->_mapcount in all sub-pages is offset up
+ * by one. This reference will go away with last compound_mapcount.
+ *
+ * See also __split_huge_pmd_locked() and page_remove_anon_compound_rmap().
+ */
+static inline int PageDoubleMap(struct page *page)
{
- return 0;
+ return PageHead(page) && test_bit(PG_double_map, &page[1].flags);
}
-static inline int PageTransCompound(struct page *page)
+static inline int TestSetPageDoubleMap(struct page *page)
{
- return 0;
+ VM_BUG_ON_PAGE(!PageHead(page), page);
+ return test_and_set_bit(PG_double_map, &page[1].flags);
}
-static inline int PageTransTail(struct page *page)
+static inline int TestClearPageDoubleMap(struct page *page)
{
- return 0;
+ VM_BUG_ON_PAGE(!PageHead(page), page);
+ return test_and_clear_bit(PG_double_map, &page[1].flags);
}
+
+#else
+TESTPAGEFLAG_FALSE(TransHuge)
+TESTPAGEFLAG_FALSE(TransCompound)
+TESTPAGEFLAG_FALSE(TransTail)
+TESTPAGEFLAG_FALSE(DoubleMap)
+ TESTSETFLAG_FALSE(DoubleMap)
+ TESTCLEARFLAG_FALSE(DoubleMap)
#endif
/*
@@ -583,12 +646,6 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
#define __PG_MLOCKED 0
#endif
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-#define __PG_COMPOUND_LOCK (1 << PG_compound_lock)
-#else
-#define __PG_COMPOUND_LOCK 0
-#endif
-
/*
* Flags checked when a page is freed. Pages being freed should not have
* these flags set. It they are, there is a problem.
@@ -598,8 +655,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
1 << PG_private | 1 << PG_private_2 | \
1 << PG_writeback | 1 << PG_reserved | \
1 << PG_slab | 1 << PG_swapcache | 1 << PG_active | \
- 1 << PG_unevictable | __PG_MLOCKED | \
- __PG_COMPOUND_LOCK)
+ 1 << PG_unevictable | __PG_MLOCKED)
/*
* Flags checked when a page is prepped for return by the page allocator.
@@ -626,6 +682,10 @@ static inline int page_has_private(struct page *page)
return !!(page->flags & PAGE_FLAGS_PRIVATE);
}
+#undef PF_ANY
+#undef PF_HEAD
+#undef PF_NO_TAIL
+#undef PF_NO_COMPOUND
#endif /* !__GENERATING_BOUNDS_H */
#endif /* PAGE_FLAGS_H */
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 26eabf5ec718..4d08b6c33557 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -394,10 +394,21 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
*/
static inline pgoff_t page_to_pgoff(struct page *page)
{
+ pgoff_t pgoff;
+
if (unlikely(PageHeadHuge(page)))
return page->index << compound_order(page);
- else
+
+ if (likely(!PageTransTail(page)))
return page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+
+ /*
+ * We don't initialize ->index for tail pages: calculate based on
+ * head page
+ */
+ pgoff = compound_head(page)->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+ pgoff += page - compound_head(page);
+ return pgoff;
}
/*
@@ -433,18 +444,9 @@ extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
unsigned int flags);
extern void unlock_page(struct page *page);
-static inline void __set_page_locked(struct page *page)
-{
- __set_bit(PG_locked, &page->flags);
-}
-
-static inline void __clear_page_locked(struct page *page)
-{
- __clear_bit(PG_locked, &page->flags);
-}
-
static inline int trylock_page(struct page *page)
{
+ page = compound_head(page);
return (likely(!test_and_set_bit_lock(PG_locked, &page->flags)));
}
@@ -497,9 +499,9 @@ extern int wait_on_page_bit_killable_timeout(struct page *page,
static inline int wait_on_page_locked_killable(struct page *page)
{
- if (PageLocked(page))
- return wait_on_page_bit_killable(page, PG_locked);
- return 0;
+ if (!PageLocked(page))
+ return 0;
+ return wait_on_page_bit_killable(compound_head(page), PG_locked);
}
extern wait_queue_head_t *page_waitqueue(struct page *page);
@@ -518,7 +520,7 @@ static inline void wake_up_page(struct page *page, int bit)
static inline void wait_on_page_locked(struct page *page)
{
if (PageLocked(page))
- wait_on_page_bit(page, PG_locked);
+ wait_on_page_bit(compound_head(page), PG_locked);
}
/*
@@ -664,17 +666,17 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask);
/*
* Like add_to_page_cache_locked, but used to add newly allocated pages:
- * the page is new, so we can just run __set_page_locked() against it.
+ * the page is new, so we can just run __SetPageLocked() against it.
*/
static inline int add_to_page_cache(struct page *page,
struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask)
{
int error;
- __set_page_locked(page);
+ __SetPageLocked(page);
error = add_to_page_cache_locked(page, mapping, offset, gfp_mask);
if (unlikely(error))
- __clear_page_locked(page);
+ __ClearPageLocked(page);
return error;
}
diff --git a/include/linux/pfn.h b/include/linux/pfn.h
index 7646637221f3..2d8e49711b63 100644
--- a/include/linux/pfn.h
+++ b/include/linux/pfn.h
@@ -3,11 +3,21 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
+
+/*
+ * pfn_t: encapsulates a page-frame number that is optionally backed
+ * by memmap (struct page). Whether a pfn_t has a 'struct page'
+ * backing is indicated by flags in the high bits of the value.
+ */
+typedef struct {
+ unsigned long val;
+} pfn_t;
#endif
#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT)
+#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
#endif
diff --git a/include/linux/pfn_t.h b/include/linux/pfn_t.h
new file mode 100644
index 000000000000..0703b5360d31
--- /dev/null
+++ b/include/linux/pfn_t.h
@@ -0,0 +1,102 @@
+#ifndef _LINUX_PFN_T_H_
+#define _LINUX_PFN_T_H_
+#include <linux/mm.h>
+
+/*
+ * PFN_FLAGS_MASK - mask of all the possible valid pfn_t flags
+ * PFN_SG_CHAIN - pfn is a pointer to the next scatterlist entry
+ * PFN_SG_LAST - pfn references a page and is the last scatterlist entry
+ * PFN_DEV - pfn is not covered by system memmap by default
+ * PFN_MAP - pfn has a dynamic page mapping established by a device driver
+ */
+#define PFN_FLAGS_MASK (((unsigned long) ~PAGE_MASK) \
+ << (BITS_PER_LONG - PAGE_SHIFT))
+#define PFN_SG_CHAIN (1UL << (BITS_PER_LONG - 1))
+#define PFN_SG_LAST (1UL << (BITS_PER_LONG - 2))
+#define PFN_DEV (1UL << (BITS_PER_LONG - 3))
+#define PFN_MAP (1UL << (BITS_PER_LONG - 4))
+
+static inline pfn_t __pfn_to_pfn_t(unsigned long pfn, unsigned long flags)
+{
+ pfn_t pfn_t = { .val = pfn | (flags & PFN_FLAGS_MASK), };
+
+ return pfn_t;
+}
+
+/* a default pfn to pfn_t conversion assumes that @pfn is pfn_valid() */
+static inline pfn_t pfn_to_pfn_t(unsigned long pfn)
+{
+ return __pfn_to_pfn_t(pfn, 0);
+}
+
+extern pfn_t phys_to_pfn_t(dma_addr_t addr, unsigned long flags);
+
+static inline bool pfn_t_has_page(pfn_t pfn)
+{
+ return (pfn.val & PFN_MAP) == PFN_MAP || (pfn.val & PFN_DEV) == 0;
+}
+
+static inline unsigned long pfn_t_to_pfn(pfn_t pfn)
+{
+ return pfn.val & ~PFN_FLAGS_MASK;
+}
+
+static inline struct page *pfn_t_to_page(pfn_t pfn)
+{
+ if (pfn_t_has_page(pfn))
+ return pfn_to_page(pfn_t_to_pfn(pfn));
+ return NULL;
+}
+
+static inline dma_addr_t pfn_t_to_phys(pfn_t pfn)
+{
+ return PFN_PHYS(pfn_t_to_pfn(pfn));
+}
+
+static inline void *pfn_t_to_virt(pfn_t pfn)
+{
+ if (pfn_t_has_page(pfn))
+ return __va(pfn_t_to_phys(pfn));
+ return NULL;
+}
+
+static inline pfn_t page_to_pfn_t(struct page *page)
+{
+ return pfn_to_pfn_t(page_to_pfn(page));
+}
+
+static inline int pfn_t_valid(pfn_t pfn)
+{
+ return pfn_valid(pfn_t_to_pfn(pfn));
+}
+
+#ifdef CONFIG_MMU
+static inline pte_t pfn_t_pte(pfn_t pfn, pgprot_t pgprot)
+{
+ return pfn_pte(pfn_t_to_pfn(pfn), pgprot);
+}
+#endif
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static inline pmd_t pfn_t_pmd(pfn_t pfn, pgprot_t pgprot)
+{
+ return pfn_pmd(pfn_t_to_pfn(pfn), pgprot);
+}
+#endif
+
+#ifdef __HAVE_ARCH_PTE_DEVMAP
+static inline bool pfn_t_devmap(pfn_t pfn)
+{
+ const unsigned long flags = PFN_DEV|PFN_MAP;
+
+ return (pfn.val & flags) == flags;
+}
+#else
+static inline bool pfn_t_devmap(pfn_t pfn)
+{
+ return false;
+}
+pte_t pte_mkdevmap(pte_t pte);
+pmd_t pmd_mkdevmap(pmd_t pmd);
+#endif
+#endif /* _LINUX_PFN_T_H_ */
diff --git a/include/linux/phy/omap_usb.h b/include/linux/phy/omap_usb.h
index dc2c541a619b..2e5fb870efa9 100644
--- a/include/linux/phy/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -30,6 +30,12 @@ struct usb_dpll_params {
u32 mf;
};
+enum omap_usb_phy_type {
+ TYPE_USB2, /* USB2_PHY, power down in CONTROL_DEV_CONF */
+ TYPE_DRA7USB2, /* USB2 PHY, power and power_aux e.g. DRA7 */
+ TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */
+};
+
struct omap_usb {
struct usb_phy phy;
struct phy_companion *comparator;
@@ -40,11 +46,20 @@ struct omap_usb {
struct clk *wkupclk;
struct clk *optclk;
u8 flags;
+ enum omap_usb_phy_type type;
+ struct regmap *syscon_phy_power; /* ctrl. reg. acces */
+ unsigned int power_reg; /* power reg. index within syscon */
+ u32 mask;
+ u32 power_on;
+ u32 power_off;
};
struct usb_phy_data {
const char *label;
u8 flags;
+ u32 mask;
+ u32 power_on;
+ u32 power_off;
};
/* Driver Flags */
@@ -52,6 +67,14 @@ struct usb_phy_data {
#define OMAP_USB2_HAS_SET_VBUS (1 << 1)
#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT (1 << 2)
+#define OMAP_DEV_PHY_PD BIT(0)
+#define OMAP_USB2_PHY_PD BIT(28)
+
+#define AM437X_USB2_PHY_PD BIT(0)
+#define AM437X_USB2_OTG_PD BIT(1)
+#define AM437X_USB2_OTGVDET_EN BIT(19)
+#define AM437X_USB2_OTGSESSEND_EN BIT(20)
+
#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h
index 5e0bc779e6c5..15bf56ee8af7 100644
--- a/include/linux/platform_data/asoc-s3c.h
+++ b/include/linux/platform_data/asoc-s3c.h
@@ -13,6 +13,9 @@
*/
#define S3C64XX_AC97_GPD 0
#define S3C64XX_AC97_GPE 1
+
+#include <linux/dmaengine.h>
+
extern void s3c64xx_ac97_setup_gpio(int);
struct samsung_i2s {
@@ -39,6 +42,11 @@ struct samsung_i2s {
*/
struct s3c_audio_pdata {
int (*cfg_gpio)(struct platform_device *);
+ dma_filter_fn dma_filter;
+ void *dma_playback;
+ void *dma_capture;
+ void *dma_play_sec;
+ void *dma_capture_mic;
union {
struct samsung_i2s i2s;
} type;
diff --git a/include/linux/platform_data/dma-rcar-hpbdma.h b/include/linux/platform_data/dma-rcar-hpbdma.h
deleted file mode 100644
index 648b8ea61a22..000000000000
--- a/include/linux/platform_data/dma-rcar-hpbdma.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2011-2013 Renesas Electronics Corporation
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * 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 __DMA_RCAR_HPBDMA_H
-#define __DMA_RCAR_HPBDMA_H
-
-#include <linux/bitops.h>
-#include <linux/types.h>
-
-/* Transmit sizes and respective register values */
-enum {
- XMIT_SZ_8BIT = 0,
- XMIT_SZ_16BIT = 1,
- XMIT_SZ_32BIT = 2,
- XMIT_SZ_MAX
-};
-
-/* DMA control register (DCR) bits */
-#define HPB_DMAE_DCR_DTAMD (1u << 26)
-#define HPB_DMAE_DCR_DTAC (1u << 25)
-#define HPB_DMAE_DCR_DTAU (1u << 24)
-#define HPB_DMAE_DCR_DTAU1 (1u << 23)
-#define HPB_DMAE_DCR_SWMD (1u << 22)
-#define HPB_DMAE_DCR_BTMD (1u << 21)
-#define HPB_DMAE_DCR_PKMD (1u << 20)
-#define HPB_DMAE_DCR_CT (1u << 18)
-#define HPB_DMAE_DCR_ACMD (1u << 17)
-#define HPB_DMAE_DCR_DIP (1u << 16)
-#define HPB_DMAE_DCR_SMDL (1u << 13)
-#define HPB_DMAE_DCR_SPDAM (1u << 12)
-#define HPB_DMAE_DCR_SDRMD_MASK (3u << 10)
-#define HPB_DMAE_DCR_SDRMD_MOD (0u << 10)
-#define HPB_DMAE_DCR_SDRMD_AUTO (1u << 10)
-#define HPB_DMAE_DCR_SDRMD_TIMER (2u << 10)
-#define HPB_DMAE_DCR_SPDS_MASK (3u << 8)
-#define HPB_DMAE_DCR_SPDS_8BIT (0u << 8)
-#define HPB_DMAE_DCR_SPDS_16BIT (1u << 8)
-#define HPB_DMAE_DCR_SPDS_32BIT (2u << 8)
-#define HPB_DMAE_DCR_DMDL (1u << 5)
-#define HPB_DMAE_DCR_DPDAM (1u << 4)
-#define HPB_DMAE_DCR_DDRMD_MASK (3u << 2)
-#define HPB_DMAE_DCR_DDRMD_MOD (0u << 2)
-#define HPB_DMAE_DCR_DDRMD_AUTO (1u << 2)
-#define HPB_DMAE_DCR_DDRMD_TIMER (2u << 2)
-#define HPB_DMAE_DCR_DPDS_MASK (3u << 0)
-#define HPB_DMAE_DCR_DPDS_8BIT (0u << 0)
-#define HPB_DMAE_DCR_DPDS_16BIT (1u << 0)
-#define HPB_DMAE_DCR_DPDS_32BIT (2u << 0)
-
-/* Asynchronous reset register (ASYNCRSTR) bits */
-#define HPB_DMAE_ASYNCRSTR_ASRST41 BIT(10)
-#define HPB_DMAE_ASYNCRSTR_ASRST40 BIT(9)
-#define HPB_DMAE_ASYNCRSTR_ASRST39 BIT(8)
-#define HPB_DMAE_ASYNCRSTR_ASRST27 BIT(7)
-#define HPB_DMAE_ASYNCRSTR_ASRST26 BIT(6)
-#define HPB_DMAE_ASYNCRSTR_ASRST25 BIT(5)
-#define HPB_DMAE_ASYNCRSTR_ASRST24 BIT(4)
-#define HPB_DMAE_ASYNCRSTR_ASRST23 BIT(3)
-#define HPB_DMAE_ASYNCRSTR_ASRST22 BIT(2)
-#define HPB_DMAE_ASYNCRSTR_ASRST21 BIT(1)
-#define HPB_DMAE_ASYNCRSTR_ASRST20 BIT(0)
-
-struct hpb_dmae_slave_config {
- unsigned int id;
- dma_addr_t addr;
- u32 dcr;
- u32 port;
- u32 rstr;
- u32 mdr;
- u32 mdm;
- u32 flags;
-#define HPB_DMAE_SET_ASYNC_RESET BIT(0)
-#define HPB_DMAE_SET_ASYNC_MODE BIT(1)
- u32 dma_ch;
-};
-
-#define HPB_DMAE_CHANNEL(_irq, _s_id) \
-{ \
- .ch_irq = _irq, \
- .s_id = _s_id, \
-}
-
-struct hpb_dmae_channel {
- unsigned int ch_irq;
- unsigned int s_id;
-};
-
-struct hpb_dmae_pdata {
- const struct hpb_dmae_slave_config *slaves;
- int num_slaves;
- const struct hpb_dmae_channel *channels;
- int num_channels;
- const unsigned int ts_shift[XMIT_SZ_MAX];
- int num_hw_channels;
-};
-
-#endif
diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h
index 4299f4ba03bd..0a533f94438f 100644
--- a/include/linux/platform_data/edma.h
+++ b/include/linux/platform_data/edma.h
@@ -53,12 +53,16 @@ enum dma_event_q {
#define EDMA_CTLR(i) ((i) >> 16)
#define EDMA_CHAN_SLOT(i) ((i) & 0xffff)
+#define EDMA_FILTER_PARAM(ctlr, chan) ((int[]) { EDMA_CTLR_CHAN(ctlr, chan) })
+
struct edma_rsv_info {
const s16 (*rsv_chans)[2];
const s16 (*rsv_slots)[2];
};
+struct dma_slave_map;
+
/* platform_data for EDMA driver */
struct edma_soc_info {
/*
@@ -76,6 +80,9 @@ struct edma_soc_info {
s8 (*queue_priority_mapping)[2];
const s16 (*xbar_chans)[2];
+
+ const struct dma_slave_map *slave_map;
+ int slavecnt;
};
#endif
diff --git a/include/linux/platform_data/gpio-rcar.h b/include/linux/platform_data/gpio-rcar.h
deleted file mode 100644
index 2d8d69432813..000000000000
--- a/include/linux/platform_data/gpio-rcar.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Renesas R-Car GPIO Support
- *
- * Copyright (C) 2013 Magnus Damm
- *
- * 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
- *
- * 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 __GPIO_RCAR_H__
-#define __GPIO_RCAR_H__
-
-struct gpio_rcar_config {
- int gpio_base;
- unsigned int irq_base;
- unsigned int number_of_pins;
- const char *pctl_name;
- unsigned has_both_edge_trigger:1;
-};
-
-#define RCAR_GP_PIN(bank, pin) (((bank) * 32) + (pin))
-
-#endif /* __GPIO_RCAR_H__ */
diff --git a/include/linux/platform_data/iommu-omap.h b/include/linux/platform_data/iommu-omap.h
index 54a0a9582fad..0496d171700a 100644
--- a/include/linux/platform_data/iommu-omap.h
+++ b/include/linux/platform_data/iommu-omap.h
@@ -29,15 +29,6 @@ struct omap_iommu_arch_data {
struct omap_iommu *iommu_dev;
};
-/**
- * struct omap_mmu_dev_attr - OMAP mmu device attributes for omap_hwmod
- * @nr_tlb_entries: number of entries supported by the translation
- * look-aside buffer (TLB).
- */
-struct omap_mmu_dev_attr {
- int nr_tlb_entries;
-};
-
struct iommu_platform_data {
const char *name;
const char *reset_name;
diff --git a/include/linux/platform_data/mmc-atmel-mci.h b/include/linux/platform_data/mmc-atmel-mci.h
deleted file mode 100644
index 399a2d5a14bd..000000000000
--- a/include/linux/platform_data/mmc-atmel-mci.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __MMC_ATMEL_MCI_H
-#define __MMC_ATMEL_MCI_H
-
-#include <linux/platform_data/dma-atmel.h>
-#include <linux/platform_data/dma-dw.h>
-
-/**
- * struct mci_dma_data - DMA data for MCI interface
- */
-struct mci_dma_data {
-#ifdef CONFIG_ARM
- struct at_dma_slave sdata;
-#else
- struct dw_dma_slave sdata;
-#endif
-};
-
-/* accessor macros */
-#define slave_data_ptr(s) (&(s)->sdata)
-#define find_slave_dev(s) ((s)->sdata.dma_dev)
-
-#endif /* __MMC_ATMEL_MCI_H */
diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h
index d3889b98a1a1..fb5625bcca9a 100644
--- a/include/linux/platform_data/spi-s3c64xx.h
+++ b/include/linux/platform_data/spi-s3c64xx.h
@@ -40,6 +40,8 @@ struct s3c64xx_spi_info {
int num_cs;
int (*cfg_gpio)(void);
dma_filter_fn filter;
+ void *dma_tx;
+ void *dma_rx;
};
/**
diff --git a/include/linux/platform_data/touchscreen-s3c2410.h b/include/linux/platform_data/touchscreen-s3c2410.h
index 58dc7c5ae63b..71eccaa9835d 100644
--- a/include/linux/platform_data/touchscreen-s3c2410.h
+++ b/include/linux/platform_data/touchscreen-s3c2410.h
@@ -17,6 +17,7 @@ struct s3c2410_ts_mach_info {
};
extern void s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *);
+extern void s3c64xx_ts_set_platdata(struct s3c2410_ts_mach_info *);
/* defined by architecture to configure gpio */
extern void s3c24xx_ts_cfg_gpio(struct platform_device *dev);
diff --git a/include/linux/platform_data/usb-rcar-phy.h b/include/linux/platform_data/usb-rcar-phy.h
deleted file mode 100644
index 8ec6964a32a5..000000000000
--- a/include/linux/platform_data/usb-rcar-phy.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * 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 __USB_RCAR_PHY_H
-#define __USB_RCAR_PHY_H
-
-#include <linux/types.h>
-
-struct rcar_phy_platform_data {
- bool ferrite_bead:1; /* (R8A7778 only) */
-
- bool port1_func:1; /* true: port 1 used by function, false: host */
- unsigned penc1:1; /* Output of the PENC1 pin in function mode */
- struct { /* Overcurrent pin control for ports 0..2 */
- bool select_3_3v:1; /* true: USB_OVCn pin, false: OVCn pin */
- /* Set to false on port 1 in function mode */
- bool active_high:1; /* true: active high, false: active low */
- /* Set to true on port 1 in function mode */
- } ovc_pin[3]; /* (R8A7778 only has 2 ports) */
-};
-
-#endif /* __USB_RCAR_PHY_H */
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 317e16de09e5..4a27153574e2 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -27,11 +27,15 @@
* Magic number "tsta" to indicate a static timer initializer
* for the object debugging code.
*/
-#define TIMER_ENTRY_STATIC ((void *) 0x74737461)
+#define TIMER_ENTRY_STATIC ((void *) 0x300 + POISON_POINTER_DELTA)
/********** mm/debug-pagealloc.c **********/
#define PAGE_POISON 0xaa
+/********** mm/page_alloc.c ************/
+
+#define TAIL_MAPPING ((void *) 0x400 + POISON_POINTER_DELTA)
+
/********** mm/slab.c **********/
/*
* Magic nums for obj red zoning.
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index 45f6a7b5b3cb..998d8f1c3c91 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -1,6 +1,16 @@
#ifndef __LINUX_BQ27X00_BATTERY_H__
#define __LINUX_BQ27X00_BATTERY_H__
+enum bq27xxx_chip {
+ BQ27000 = 1, /* bq27000, bq27200 */
+ BQ27010, /* bq27010, bq27210 */
+ BQ27500, /* bq27500, bq27510, bq27520 */
+ BQ27530, /* bq27530, bq27531 */
+ BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
+ BQ27545, /* bq27545 */
+ BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+};
+
/**
* struct bq27xxx_plaform_data - Platform data for bq27xxx devices
* @name: Name of the battery.
@@ -12,20 +22,47 @@
* register to be read. The return value should either be the content of
* the passed register or an error value.
*/
-enum bq27xxx_chip {
- BQ27000 = 1, /* bq27000, bq27200 */
- BQ27010, /* bq27010, bq27210 */
- BQ27500, /* bq27500, bq27510, bq27520 */
- BQ27530, /* bq27530, bq27531 */
- BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
- BQ27545, /* bq27545 */
- BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
-};
-
struct bq27xxx_platform_data {
const char *name;
enum bq27xxx_chip chip;
int (*read)(struct device *dev, unsigned int);
};
+struct bq27xxx_device_info;
+struct bq27xxx_access_methods {
+ int (*read)(struct bq27xxx_device_info *di, u8 reg, bool single);
+};
+
+struct bq27xxx_reg_cache {
+ int temperature;
+ int time_to_empty;
+ int time_to_empty_avg;
+ int time_to_full;
+ int charge_full;
+ int cycle_count;
+ int capacity;
+ int energy;
+ int flags;
+ int power_avg;
+ int health;
+};
+
+struct bq27xxx_device_info {
+ struct device *dev;
+ enum bq27xxx_chip chip;
+ const char *name;
+ struct bq27xxx_access_methods bus;
+ struct bq27xxx_reg_cache cache;
+ int charge_design_full;
+ unsigned long last_update;
+ struct delayed_work work;
+ struct power_supply *bat;
+ struct mutex lock;
+ u8 *regs;
+};
+
+void bq27xxx_battery_update(struct bq27xxx_device_info *di);
+int bq27xxx_battery_setup(struct bq27xxx_device_info *di);
+void bq27xxx_battery_teardown(struct bq27xxx_device_info *di);
+
#endif
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9729565c25ff..9ccbdf2c1453 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -106,13 +106,13 @@ struct va_format {
/*
* Dummy printk for disabled debugging statements to use whilst maintaining
- * gcc's format and side-effect checking.
+ * gcc's format checking.
*/
-static inline __printf(1, 2)
-int no_printk(const char *fmt, ...)
-{
- return 0;
-}
+#define no_printk(fmt, ...) \
+do { \
+ if (0) \
+ printk(fmt, ##__VA_ARGS__); \
+} while (0)
#ifdef CONFIG_EARLY_PRINTK
extern asmlinkage __printf(1, 2)
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 9e0e76992be0..48603506f8de 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -140,6 +140,8 @@ struct regulator;
*
* @supply: The name of the supply. Initialised by the user before
* using the bulk regulator APIs.
+ * @optional: The supply should be considered optional. Initialised by the user
+ * before using the bulk regulator APIs.
* @consumer: The regulator consumer for the supply. This will be managed
* by the bulk API.
*
@@ -149,6 +151,7 @@ struct regulator;
*/
struct regulator_bulk_data {
const char *supply;
+ bool optional;
struct regulator *consumer;
/* private: Internal use */
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 9c2903e58adb..16ac9e108806 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -302,6 +302,8 @@ struct regulator_desc {
unsigned int vsel_reg;
unsigned int vsel_mask;
+ unsigned int csel_reg;
+ unsigned int csel_mask;
unsigned int apply_reg;
unsigned int apply_bit;
unsigned int enable_reg;
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 7f65f9cff951..c4c097de0ba9 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -38,6 +38,9 @@ static inline struct reset_control *devm_reset_control_get_optional(
struct reset_control *of_reset_control_get(struct device_node *node,
const char *id);
+struct reset_control *of_reset_control_get_by_index(
+ struct device_node *node, int index);
+
#else
static inline int reset_control_reset(struct reset_control *rstc)
@@ -71,7 +74,7 @@ static inline void reset_control_put(struct reset_control *rstc)
static inline int device_reset_optional(struct device *dev)
{
- return -ENOSYS;
+ return -ENOTSUPP;
}
static inline struct reset_control *__must_check reset_control_get(
@@ -91,19 +94,25 @@ static inline struct reset_control *__must_check devm_reset_control_get(
static inline struct reset_control *reset_control_get_optional(
struct device *dev, const char *id)
{
- return ERR_PTR(-ENOSYS);
+ return ERR_PTR(-ENOTSUPP);
}
static inline struct reset_control *devm_reset_control_get_optional(
struct device *dev, const char *id)
{
- return ERR_PTR(-ENOSYS);
+ return ERR_PTR(-ENOTSUPP);
}
static inline struct reset_control *of_reset_control_get(
struct device_node *node, const char *id)
{
- return ERR_PTR(-ENOSYS);
+ return ERR_PTR(-ENOTSUPP);
+}
+
+static inline struct reset_control *of_reset_control_get_by_index(
+ struct device_node *node, int index)
+{
+ return ERR_PTR(-ENOTSUPP);
}
#endif /* CONFIG_RESET_CONTROLLER */
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 29446aeef36e..bdf597c4f0be 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -85,6 +85,7 @@ enum ttu_flags {
TTU_UNMAP = 1, /* unmap mode */
TTU_MIGRATION = 2, /* migration mode */
TTU_MUNLOCK = 4, /* munlock mode */
+ TTU_LZFREE = 8, /* lazy free mode */
TTU_IGNORE_MLOCK = (1 << 8), /* ignore mlock */
TTU_IGNORE_ACCESS = (1 << 9), /* don't age */
@@ -161,25 +162,31 @@ static inline void anon_vma_merge(struct vm_area_struct *vma,
struct anon_vma *page_get_anon_vma(struct page *page);
+/* bitflags for do_page_add_anon_rmap() */
+#define RMAP_EXCLUSIVE 0x01
+#define RMAP_COMPOUND 0x02
+
/*
* rmap interfaces called when adding or removing pte of page
*/
void page_move_anon_rmap(struct page *, struct vm_area_struct *, unsigned long);
-void page_add_anon_rmap(struct page *, struct vm_area_struct *, unsigned long);
+void page_add_anon_rmap(struct page *, struct vm_area_struct *,
+ unsigned long, bool);
void do_page_add_anon_rmap(struct page *, struct vm_area_struct *,
unsigned long, int);
-void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, unsigned long);
+void page_add_new_anon_rmap(struct page *, struct vm_area_struct *,
+ unsigned long, bool);
void page_add_file_rmap(struct page *);
-void page_remove_rmap(struct page *);
+void page_remove_rmap(struct page *, bool);
void hugepage_add_anon_rmap(struct page *, struct vm_area_struct *,
unsigned long);
void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *,
unsigned long);
-static inline void page_dup_rmap(struct page *page)
+static inline void page_dup_rmap(struct page *page, bool compound)
{
- atomic_inc(&page->_mapcount);
+ atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount);
}
/*
@@ -210,6 +217,25 @@ static inline pte_t *page_check_address(struct page *page, struct mm_struct *mm,
}
/*
+ * Used by idle page tracking to check if a page was referenced via page
+ * tables.
+ */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+bool page_check_address_transhuge(struct page *page, struct mm_struct *mm,
+ unsigned long address, pmd_t **pmdp,
+ pte_t **ptep, spinlock_t **ptlp);
+#else
+static inline bool page_check_address_transhuge(struct page *page,
+ struct mm_struct *mm, unsigned long address,
+ pmd_t **pmdp, pte_t **ptep, spinlock_t **ptlp)
+{
+ *ptep = page_check_address(page, mm, address, ptlp, 0);
+ *pmdp = NULL;
+ return !!*ptep;
+}
+#endif
+
+/*
* Used by swapoff to help locate where page is expected in vma.
*/
unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
@@ -286,5 +312,6 @@ static inline int page_mkclean(struct page *page)
#define SWAP_AGAIN 1
#define SWAP_FAIL 2
#define SWAP_MLOCK 3
+#define SWAP_LZFREE 4
#endif /* _LINUX_RMAP_H */
diff --git a/include/linux/security.h b/include/linux/security.h
index 2f4c1f7aa7db..4824a4ccaf1c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -270,10 +270,10 @@ int security_inode_listxattr(struct dentry *dentry);
int security_inode_removexattr(struct dentry *dentry, const char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
-int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
+int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
-void security_inode_getsecid(const struct inode *inode, u32 *secid);
+void security_inode_getsecid(struct inode *inode, u32 *secid);
int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_free(struct file *file);
@@ -353,6 +353,7 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
+void security_inode_invalidate_secctx(struct inode *inode);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
@@ -719,7 +720,7 @@ static inline int security_inode_killpriv(struct dentry *dentry)
return cap_inode_killpriv(dentry);
}
-static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
+static inline int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
@@ -734,7 +735,7 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,
return 0;
}
-static inline void security_inode_getsecid(const struct inode *inode, u32 *secid)
+static inline void security_inode_getsecid(struct inode *inode, u32 *secid)
{
*secid = 0;
}
@@ -1093,6 +1094,10 @@ static inline void security_release_secctx(char *secdata, u32 seclen)
{
}
+static inline void security_inode_invalidate_secctx(struct inode *inode)
+{
+}
+
static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
return -EOPNOTSUPP;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 297d4fa1cfe5..e03d6ba5e5b4 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -145,11 +145,12 @@ struct uart_port {
#define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */
#define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */
-#define UPIO_MEM (SERIAL_IO_MEM) /* 8b MMIO access */
+#define UPIO_MEM (SERIAL_IO_MEM) /* driver-specific */
#define UPIO_MEM32 (SERIAL_IO_MEM32) /* 32b little endian */
#define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */
#define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */
#define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */
+#define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */
unsigned int read_status_mask; /* driver specific */
unsigned int ignore_status_mask; /* driver specific */
diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h
index 7c536ac5be05..9f2bfd055742 100644
--- a/include/linux/serial_sci.h
+++ b/include/linux/serial_sci.h
@@ -32,6 +32,7 @@ enum {
SCIx_SH2_SCIF_FIFODATA_REGTYPE,
SCIx_SH3_SCIF_REGTYPE,
SCIx_SH4_SCIF_REGTYPE,
+ SCIx_SH4_SCIF_BRG_REGTYPE,
SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
SCIx_SH4_SCIF_FIFODATA_REGTYPE,
SCIx_SH7705_SCIF_REGTYPE,
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 1f208b2a1ed6..645896b81244 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -113,10 +113,6 @@ long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min,
unsigned int mult_max, unsigned long rate);
-long clk_round_parent(struct clk *clk, unsigned long target,
- unsigned long *best_freq, unsigned long *parent_freq,
- unsigned int div_min, unsigned int div_max);
-
#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _status_reg, _flags) \
{ \
.parent = _parent, \
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 50777b5b1e4c..a43f41cb3c43 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -60,6 +60,10 @@ extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end);
extern int shmem_unuse(swp_entry_t entry, struct page *page);
+extern unsigned long shmem_swap_usage(struct vm_area_struct *vma);
+extern unsigned long shmem_partial_swap_usage(struct address_space *mapping,
+ pgoff_t start, pgoff_t end);
+
static inline struct page *shmem_read_mapping_page(
struct address_space *mapping, pgoff_t index)
{
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 07f9ccd28654..11f935c1a090 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3551,7 +3551,8 @@ struct skb_gso_cb {
int encap_level;
__u16 csum_start;
};
-#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb)
+#define SKB_SGO_CB_OFFSET 32
+#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_SGO_CB_OFFSET))
static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
{
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2037a861e367..3ffee7422012 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -86,6 +86,11 @@
#else
# define SLAB_FAILSLAB 0x00000000UL
#endif
+#ifdef CONFIG_MEMCG_KMEM
+# define SLAB_ACCOUNT 0x04000000UL /* Account to memcg */
+#else
+# define SLAB_ACCOUNT 0x00000000UL
+#endif
/* The following flags affect the page allocator grouping pages by mobility */
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
diff --git a/include/linux/soc/dove/pmu.h b/include/linux/soc/dove/pmu.h
index 9c99f84bcc0e..765386972b55 100644
--- a/include/linux/soc/dove/pmu.h
+++ b/include/linux/soc/dove/pmu.h
@@ -1,6 +1,25 @@
#ifndef LINUX_SOC_DOVE_PMU_H
#define LINUX_SOC_DOVE_PMU_H
+#include <linux/types.h>
+
+struct dove_pmu_domain_initdata {
+ u32 pwr_mask;
+ u32 rst_mask;
+ u32 iso_mask;
+ const char *name;
+};
+
+struct dove_pmu_initdata {
+ void __iomem *pmc_base;
+ void __iomem *pmu_base;
+ int irq;
+ int irq_domain_start;
+ const struct dove_pmu_domain_initdata *domains;
+};
+
+int dove_init_pmu_legacy(const struct dove_pmu_initdata *);
+
int dove_init_pmu(void);
#endif
diff --git a/include/linux/soc/qcom/smem_state.h b/include/linux/soc/qcom/smem_state.h
new file mode 100644
index 000000000000..f35e1512fcaa
--- /dev/null
+++ b/include/linux/soc/qcom/smem_state.h
@@ -0,0 +1,18 @@
+#ifndef __QCOM_SMEM_STATE__
+#define __QCOM_SMEM_STATE__
+
+struct qcom_smem_state;
+
+struct qcom_smem_state_ops {
+ int (*update_bits)(void *, u32, u32);
+};
+
+struct qcom_smem_state *qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit);
+void qcom_smem_state_put(struct qcom_smem_state *);
+
+int qcom_smem_state_update_bits(struct qcom_smem_state *state, u32 mask, u32 value);
+
+struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node, const struct qcom_smem_state_ops *ops, void *data);
+void qcom_smem_state_unregister(struct qcom_smem_state *state);
+
+#endif
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index cce80e6dc7d1..53be3a4c60cb 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -425,6 +425,12 @@ struct spi_master {
#define SPI_MASTER_MUST_RX BIT(3) /* requires rx */
#define SPI_MASTER_MUST_TX BIT(4) /* requires tx */
+ /*
+ * on some hardware transfer size may be constrained
+ * the limit may depend on device transfer settings
+ */
+ size_t (*max_transfer_size)(struct spi_device *spi);
+
/* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock;
struct mutex bus_lock_mutex;
@@ -762,10 +768,15 @@ struct spi_message {
void *state;
};
+static inline void spi_message_init_no_memset(struct spi_message *m)
+{
+ INIT_LIST_HEAD(&m->transfers);
+}
+
static inline void spi_message_init(struct spi_message *m)
{
memset(m, 0, sizeof *m);
- INIT_LIST_HEAD(&m->transfers);
+ spi_message_init_no_memset(m);
}
static inline void
@@ -832,6 +843,15 @@ extern int spi_async(struct spi_device *spi, struct spi_message *message);
extern int spi_async_locked(struct spi_device *spi,
struct spi_message *message);
+static inline size_t
+spi_max_transfer_size(struct spi_device *spi)
+{
+ struct spi_master *master = spi->master;
+ if (!master->max_transfer_size)
+ return SIZE_MAX;
+ return master->max_transfer_size(spi);
+}
+
/*---------------------------------------------------------------------------*/
/* All these synchronous SPI transfer routines are utilities layered
@@ -1115,12 +1135,7 @@ spi_add_device(struct spi_device *spi);
extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);
-static inline void
-spi_unregister_device(struct spi_device *spi)
-{
- if (spi)
- device_unregister(&spi->dev);
-}
+extern void spi_unregister_device(struct spi_device *spi);
extern const struct spi_device_id *
spi_get_device_id(const struct spi_device *sdev);
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 78512cfe1fe6..b7dabc4baafd 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -128,6 +128,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
const unsigned short port);
int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt);
+void svc_age_temp_xprts_now(struct svc_serv *, struct sockaddr *);
static inline void svc_xprt_get(struct svc_xprt *xprt)
{
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 8d71d6577459..c00f53a4ccdd 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -23,13 +23,19 @@ struct svc_cred {
kgid_t cr_gid;
struct group_info *cr_group_info;
u32 cr_flavor; /* pseudoflavor */
- char *cr_principal; /* for gss */
+ /* name of form servicetype/hostname@REALM, passed down by
+ * gss-proxy: */
+ char *cr_raw_principal;
+ /* name of form servicetype@hostname, passed down by
+ * rpc.svcgssd, or computed from the above: */
+ char *cr_principal;
struct gss_api_mech *cr_gss_mech;
};
static inline void init_svc_cred(struct svc_cred *cred)
{
cred->cr_group_info = NULL;
+ cred->cr_raw_principal = NULL;
cred->cr_principal = NULL;
cred->cr_gss_mech = NULL;
}
@@ -38,6 +44,7 @@ static inline void free_svc_cred(struct svc_cred *cred)
{
if (cred->cr_group_info)
put_group_info(cred->cr_group_info);
+ kfree(cred->cr_raw_principal);
kfree(cred->cr_principal);
gss_mech_put(cred->cr_gss_mech);
init_svc_cred(cred);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 7ba7dccaf0e7..414e101cd061 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -287,7 +287,6 @@ static inline void workingset_node_shadows_dec(struct radix_tree_node *node)
/* linux/mm/page_alloc.c */
extern unsigned long totalram_pages;
extern unsigned long totalreserve_pages;
-extern unsigned long dirty_balance_reserve;
extern unsigned long nr_free_buffer_pages(void);
extern unsigned long nr_free_pagecache_pages(void);
@@ -308,6 +307,7 @@ extern void lru_add_drain_cpu(int cpu);
extern void lru_add_drain_all(void);
extern void rotate_reclaimable_page(struct page *page);
extern void deactivate_file_page(struct page *page);
+extern void deactivate_page(struct page *page);
extern void swap_setup(void);
extern void add_page_to_unevictable_list(struct page *page);
@@ -539,7 +539,8 @@ static inline int swp_swapcount(swp_entry_t entry)
return 0;
}
-#define reuse_swap_page(page) (page_mapcount(page) == 1)
+#define reuse_swap_page(page) \
+ (!PageTransCompound(page) && page_mapcount(page) == 1)
static inline int try_to_free_swap(struct page *page)
{
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index ff307b548ed3..b4c2a485b28a 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -56,9 +56,10 @@ extern long do_no_restart_syscall(struct restart_block *parm);
#ifdef __KERNEL__
#ifdef CONFIG_DEBUG_STACK_USAGE
-# define THREADINFO_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
+# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_NOTRACK | \
+ __GFP_ZERO)
#else
-# define THREADINFO_GFP (GFP_KERNEL | __GFP_NOTRACK)
+# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_NOTRACK)
#endif
/*
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 73ddad1e0fa3..afce69296ac0 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -34,10 +34,6 @@
#include <linux/percpu.h>
#include <asm/topology.h>
-#ifndef node_has_online_mem
-#define node_has_online_mem(nid) (1)
-#endif
-
#ifndef nr_cpus_node
#define nr_cpus_node(node) cpumask_weight(cpumask_of_node(node))
#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5e31f1b99037..2fd8708ea888 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -345,8 +345,6 @@ struct tty_file_private {
#define TTY_HUPPED 18 /* Post driver->hangup() */
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
-#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
-
/* Values for tty->flow_change */
#define TTY_THROTTLE_SAFE 1
#define TTY_UNTHROTTLE_SAFE 2
@@ -395,8 +393,6 @@ static inline int __init tty_init(void)
{ return 0; }
#endif
-extern void tty_write_flush(struct tty_struct *);
-
extern struct ktermios tty_std_termios;
extern int vcs_init(void);
@@ -419,9 +415,8 @@ static inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
return tty;
}
-extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
- const char *routine);
extern const char *tty_name(const struct tty_struct *tty);
+extern const char *tty_driver_name(const struct tty_struct *tty);
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
extern int __tty_check_change(struct tty_struct *tty, int sig);
extern int tty_check_change(struct tty_struct *tty);
@@ -667,10 +662,16 @@ static inline void proc_tty_register_driver(struct tty_driver *d) {}
static inline void proc_tty_unregister_driver(struct tty_driver *d) {}
#endif
-#define tty_debug(tty, f, args...) \
- do { \
- printk(KERN_DEBUG "%s: %s: " f, __func__, \
- tty_name(tty), ##args); \
- } while (0)
+#define tty_msg(fn, tty, f, ...) \
+ fn("%s %s: " f, tty_driver_name(tty), tty_name(tty), ##__VA_ARGS__)
+
+#define tty_debug(tty, f, ...) tty_msg(pr_debug, tty, f, ##__VA_ARGS__)
+#define tty_info(tty, f, ...) tty_msg(pr_info, tty, f, ##__VA_ARGS__)
+#define tty_notice(tty, f, ...) tty_msg(pr_notice, tty, f, ##__VA_ARGS__)
+#define tty_warn(tty, f, ...) tty_msg(pr_warn, tty, f, ##__VA_ARGS__)
+#define tty_err(tty, f, ...) tty_msg(pr_err, tty, f, ##__VA_ARGS__)
+
+#define tty_info_ratelimited(tty, f, ...) \
+ tty_msg(pr_info_ratelimited, tty, f, ##__VA_ARGS__)
#endif
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 0994c0d01a09..75de43da2301 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -20,6 +20,11 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
+ * 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
+ * Benjamin Tissoires <benjamin.tissoires@redhat.com>)
+ * - add UI_DEV_SETUP ioctl
+ * - add UI_ABS_SETUP ioctl
+ * - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
diff --git a/include/linux/usb.h b/include/linux/usb.h
index b9a28074210f..89533ba38691 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -510,7 +510,8 @@ struct usb3_lpm_parameters {
* @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM
* @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled
* @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled
- * @usb3_lpm_enabled: USB3 hardware LPM enabled
+ * @usb3_lpm_u1_enabled: USB3 hardware U1 LPM enabled
+ * @usb3_lpm_u2_enabled: USB3 hardware U2 LPM enabled
* @string_langid: language ID for strings
* @product: iProduct string, if present (static)
* @manufacturer: iManufacturer string, if present (static)
@@ -583,7 +584,8 @@ struct usb_device {
unsigned usb2_hw_lpm_besl_capable:1;
unsigned usb2_hw_lpm_enabled:1;
unsigned usb2_hw_lpm_allowed:1;
- unsigned usb3_lpm_enabled:1;
+ unsigned usb3_lpm_u1_enabled:1;
+ unsigned usb3_lpm_u2_enabled:1;
int string_langid;
/* static strings from the device */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 3d583a10b926..d82d0068872b 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -402,6 +402,9 @@ static inline void usb_ep_free_request(struct usb_ep *ep,
static inline int usb_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags)
{
+ if (WARN_ON_ONCE(!ep->enabled && ep->address))
+ return -ESHUTDOWN;
+
return ep->ops->queue(ep, req, gfp_flags);
}
@@ -1012,6 +1015,9 @@ static inline int usb_gadget_activate(struct usb_gadget *gadget)
* @reset: Invoked on USB bus reset. It is mandatory for all gadget drivers
* and should be called in_interrupt.
* @driver: Driver model state for this driver.
+ * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL,
+ * this driver will be bound to any available UDC.
+ * @pending: UDC core private data used for deferred probe of this driver.
*
* Devices are disabled till a gadget driver successfully bind()s, which
* means the driver will handle setup() requests needed to enumerate (and
@@ -1072,6 +1078,9 @@ struct usb_gadget_driver {
/* FIXME support safe rmmod */
struct device_driver driver;
+
+ char *udc_name;
+ struct list_head pending;
};
@@ -1117,8 +1126,6 @@ extern int usb_add_gadget_udc_release(struct device *parent,
struct usb_gadget *gadget, void (*release)(struct device *dev));
extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
extern void usb_del_gadget_udc(struct usb_gadget *gadget);
-extern int usb_udc_attach_driver(const char *name,
- struct usb_gadget_driver *driver);
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index f89c24bd53a4..4dcf8446dbcd 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -660,7 +660,7 @@ struct usb_mon_operations {
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
-extern struct usb_mon_operations *mon_ops;
+extern const struct usb_mon_operations *mon_ops;
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb)
{
@@ -682,7 +682,7 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_complete)(bus, urb, status);
}
-int usb_mon_register(struct usb_mon_operations *ops);
+int usb_mon_register(const struct usb_mon_operations *ops);
void usb_mon_deregister(void);
#else
diff --git a/include/linux/usb/musb-omap.h b/include/linux/usb/musb-omap.h
deleted file mode 100644
index 7774c5986f07..000000000000
--- a/include/linux/usb/musb-omap.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011-2012 by Texas Instruments
- *
- * The Inventra Controller Driver for Linux 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 __MUSB_OMAP_H__
-#define __MUSB_OMAP_H__
-
-enum omap_musb_vbus_id_status {
- OMAP_MUSB_UNKNOWN = 0,
- OMAP_MUSB_ID_GROUND,
- OMAP_MUSB_ID_FLOAT,
- OMAP_MUSB_VBUS_VALID,
- OMAP_MUSB_VBUS_OFF,
-};
-
-#if (defined(CONFIG_USB_MUSB_OMAP2PLUS) || \
- defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE))
-void omap_musb_mailbox(enum omap_musb_vbus_id_status status);
-#else
-static inline void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
-{
-}
-#endif
-
-#endif /* __MUSB_OMAP_H__ */
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
index fa6dc132bd1b..96ddfb7ab018 100644
--- a/include/linux/usb/musb.h
+++ b/include/linux/usb/musb.h
@@ -133,6 +133,21 @@ struct musb_hdrc_platform_data {
const void *platform_ops;
};
+enum musb_vbus_id_status {
+ MUSB_UNKNOWN = 0,
+ MUSB_ID_GROUND,
+ MUSB_ID_FLOAT,
+ MUSB_VBUS_VALID,
+ MUSB_VBUS_OFF,
+};
+
+#if IS_ENABLED(CONFIG_USB_MUSB_HDRC)
+void musb_mailbox(enum musb_vbus_id_status status);
+#else
+static inline void musb_mailbox(enum musb_vbus_id_status status)
+{
+}
+#endif
/* TUSB 6010 support */
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index c3fe9e48ce27..974bce93aa28 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -12,10 +12,16 @@
#include <linux/usb/phy.h>
#if IS_ENABLED(CONFIG_OF)
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np);
bool of_usb_host_tpl_support(struct device_node *np);
int of_usb_update_otg_caps(struct device_node *np,
struct usb_otg_caps *otg_caps);
#else
+static inline enum usb_dr_mode
+of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
+{
+ return USB_DR_MODE_UNKNOWN;
+}
static inline bool of_usb_host_tpl_support(struct device_node *np)
{
return false;
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index bfb74723f151..4db191fe8c2c 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -105,12 +105,26 @@ struct renesas_usbhs_platform_callback {
* some register needs USB chip specific parameters.
* This struct show it to driver
*/
+
+struct renesas_usbhs_driver_pipe_config {
+ u8 type; /* USB_ENDPOINT_XFER_xxx */
+ u16 bufsize;
+ u8 bufnum;
+ bool double_buf;
+};
+#define RENESAS_USBHS_PIPE(_type, _size, _num, _double_buf) { \
+ .type = (_type), \
+ .bufsize = (_size), \
+ .bufnum = (_num), \
+ .double_buf = (_double_buf), \
+ }
+
struct renesas_usbhs_driver_param {
/*
* pipe settings
*/
- u32 *pipe_type; /* array of USB_ENDPOINT_XFER_xxx (from ep0) */
- int pipe_size; /* pipe_type array size */
+ struct renesas_usbhs_driver_pipe_config *pipe_configs;
+ int pipe_size; /* pipe_configs array size */
/*
* option:
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index ddb440975382..610a86a892b8 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -44,6 +44,9 @@ struct vfio_device_ops {
void (*request)(void *device_data, unsigned int count);
};
+extern struct iommu_group *vfio_iommu_group_get(struct device *dev);
+extern void vfio_iommu_group_put(struct iommu_group *group, struct device *dev);
+
extern int vfio_add_group_dev(struct device *dev,
const struct vfio_device_ops *ops,
void *device_data);
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index e5ce8ab0b8b0..6e6cb0c9d7cb 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -70,7 +70,7 @@ struct virtio_config_ops {
int (*find_vqs)(struct virtio_device *, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
- const char *names[]);
+ const char * const names[]);
void (*del_vqs)(struct virtio_device *);
u64 (*get_features)(struct virtio_device *vdev);
int (*finalize_features)(struct virtio_device *vdev);
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index 8e50888a6d59..a156e2b6ccfe 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -12,7 +12,7 @@
* anyone care?
*
* For virtio_pci on SMP, we don't need to order with respect to MMIO
- * accesses through relaxed memory I/O windows, so smp_mb() et al are
+ * accesses through relaxed memory I/O windows, so virt_mb() et al are
* sufficient.
*
* For using virtio to talk to real devices (eg. other heterogeneous
@@ -23,18 +23,16 @@
static inline void virtio_mb(bool weak_barriers)
{
-#ifdef CONFIG_SMP
if (weak_barriers)
- smp_mb();
+ virt_mb();
else
-#endif
mb();
}
static inline void virtio_rmb(bool weak_barriers)
{
if (weak_barriers)
- dma_rmb();
+ virt_rmb();
else
rmb();
}
@@ -42,11 +40,22 @@ static inline void virtio_rmb(bool weak_barriers)
static inline void virtio_wmb(bool weak_barriers)
{
if (weak_barriers)
- dma_wmb();
+ virt_wmb();
else
wmb();
}
+static inline void virtio_store_mb(bool weak_barriers,
+ __virtio16 *p, __virtio16 v)
+{
+ if (weak_barriers) {
+ virt_store_mb(*p, v);
+ } else {
+ WRITE_ONCE(*p, v);
+ mb();
+ }
+}
+
struct virtio_device;
struct virtqueue;
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index e623d392db0c..67c1dbd19c6d 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -25,6 +25,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
FOR_ALL_ZONES(PGALLOC),
PGFREE, PGACTIVATE, PGDEACTIVATE,
PGFAULT, PGMAJFAULT,
+ PGLAZYFREED,
FOR_ALL_ZONES(PGREFILL),
FOR_ALL_ZONES(PGSTEAL_KSWAPD),
FOR_ALL_ZONES(PGSTEAL_DIRECT),
@@ -68,7 +69,9 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
THP_FAULT_FALLBACK,
THP_COLLAPSE_ALLOC,
THP_COLLAPSE_ALLOC_FAILED,
- THP_SPLIT,
+ THP_SPLIT_PAGE,
+ THP_SPLIT_PAGE_FAILED,
+ THP_SPLIT_PMD,
THP_ZERO_PAGE_ALLOC,
THP_ZERO_PAGE_ALLOC_FAILED,
#endif
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 3bff87a25a42..d1f1d338af20 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -14,7 +14,6 @@ struct vm_area_struct; /* vma defining user mapping in mm_types.h */
#define VM_ALLOC 0x00000002 /* vmalloc() */
#define VM_MAP 0x00000004 /* vmap()ed pages */
#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */
-#define VM_VPAGES 0x00000010 /* buffer for pages was vmalloc'ed */
#define VM_UNINITIALIZED 0x00000020 /* vm_struct is not fully initialized */
#define VM_NO_GUARD 0x00000040 /* don't add guard page */
#define VM_KASAN 0x00000080 /* has allocated kasan shadow memory */
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
index 3e4535876d37..3347cc3ec0ab 100644
--- a/include/linux/vmpressure.h
+++ b/include/linux/vmpressure.h
@@ -12,6 +12,9 @@
struct vmpressure {
unsigned long scanned;
unsigned long reclaimed;
+
+ unsigned long tree_scanned;
+ unsigned long tree_reclaimed;
/* The lock is used to keep the scanned/reclaimed above in sync. */
struct spinlock sr_lock;
@@ -26,7 +29,7 @@ struct vmpressure {
struct mem_cgroup;
#ifdef CONFIG_MEMCG
-extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed);
extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
@@ -40,7 +43,7 @@ extern int vmpressure_register_event(struct mem_cgroup *memcg,
extern void vmpressure_unregister_event(struct mem_cgroup *memcg,
struct eventfd_ctx *eventfd);
#else
-static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed) {}
static inline void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg,
int prio) {}
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 3e5d9075960f..73fae8c4a5fb 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -189,6 +189,7 @@ extern void __inc_zone_state(struct zone *, enum zone_stat_item);
extern void dec_zone_state(struct zone *, enum zone_stat_item);
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
+void quiet_vmstat(void);
void cpu_vm_stats_fold(int cpu);
void refresh_zone_stat_thresholds(void);
@@ -249,6 +250,7 @@ static inline void __dec_zone_page_state(struct page *page,
static inline void refresh_zone_stat_thresholds(void) { }
static inline void cpu_vm_stats_fold(int cpu) { }
+static inline void quiet_vmstat(void) { }
static inline void drain_zonestat(struct zone *zone,
struct per_cpu_pageset *pset) { }
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 027b1f43f12d..b585fa2507ee 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -12,10 +12,12 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/cdev.h>
+#include <linux/notifier.h>
#include <uapi/linux/watchdog.h>
struct watchdog_ops;
struct watchdog_device;
+struct watchdog_core_data;
/** struct watchdog_ops - The watchdog-devices operations
*
@@ -26,8 +28,7 @@ struct watchdog_device;
* @status: The routine that shows the status of the watchdog device.
* @set_timeout:The routine for setting the watchdog devices timeout value (in seconds).
* @get_timeleft:The routine that gets the time left before a reset (in seconds).
- * @ref: The ref operation for dyn. allocated watchdog_device structs
- * @unref: The unref operation for dyn. allocated watchdog_device structs
+ * @restart: The routine for restarting the machine.
* @ioctl: The routines that handles extra ioctl calls.
*
* The watchdog_ops structure contains a list of low-level operations
@@ -45,25 +46,26 @@ struct watchdog_ops {
unsigned int (*status)(struct watchdog_device *);
int (*set_timeout)(struct watchdog_device *, unsigned int);
unsigned int (*get_timeleft)(struct watchdog_device *);
- void (*ref)(struct watchdog_device *);
- void (*unref)(struct watchdog_device *);
+ int (*restart)(struct watchdog_device *);
long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
};
/** struct watchdog_device - The structure that defines a watchdog device
*
* @id: The watchdog's ID. (Allocated by watchdog_register_device)
- * @cdev: The watchdog's Character device.
- * @dev: The device for our watchdog
* @parent: The parent bus device
+ * @groups: List of sysfs attribute groups to create when creating the
+ * watchdog device.
* @info: Pointer to a watchdog_info structure.
* @ops: Pointer to the list of watchdog operations.
* @bootstatus: Status of the watchdog device at boot.
* @timeout: The watchdog devices timeout value (in seconds).
* @min_timeout:The watchdog devices minimum timeout value (in seconds).
* @max_timeout:The watchdog devices maximum timeout value (in seconds).
- * @driver-data:Pointer to the drivers private data.
- * @lock: Lock for watchdog core internal use only.
+ * @reboot_nb: The notifier block to stop watchdog on reboot.
+ * @restart_nb: The notifier block to register a restart function.
+ * @driver_data:Pointer to the drivers private data.
+ * @wd_data: Pointer to watchdog core internal data.
* @status: Field that contains the devices internal status bits.
* @deferred: entry in wtd_deferred_reg_list which is used to
* register early initialized watchdogs.
@@ -79,24 +81,23 @@ struct watchdog_ops {
*/
struct watchdog_device {
int id;
- struct cdev cdev;
- struct device *dev;
struct device *parent;
+ const struct attribute_group **groups;
const struct watchdog_info *info;
const struct watchdog_ops *ops;
unsigned int bootstatus;
unsigned int timeout;
unsigned int min_timeout;
unsigned int max_timeout;
+ struct notifier_block reboot_nb;
+ struct notifier_block restart_nb;
void *driver_data;
- struct mutex lock;
+ struct watchdog_core_data *wd_data;
unsigned long status;
/* Bit numbers for status flags */
#define WDOG_ACTIVE 0 /* Is the watchdog running/active */
-#define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */
-#define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
-#define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
-#define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
+#define WDOG_NO_WAY_OUT 1 /* Is 'nowayout' feature set ? */
+#define WDOG_STOP_ON_REBOOT 2 /* Should be stopped on reboot */
struct list_head deferred;
};
@@ -116,6 +117,12 @@ static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool noway
set_bit(WDOG_NO_WAY_OUT, &wdd->status);
}
+/* Use the following function to stop the watchdog on reboot */
+static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd)
+{
+ set_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
+}
+
/* Use the following function to check if a timeout value is invalid */
static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
{
@@ -142,6 +149,7 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
}
/* drivers/watchdog/watchdog_core.c */
+void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
extern int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev);
extern int watchdog_register_device(struct watchdog_device *);
diff --git a/include/linux/wkup_m3_ipc.h b/include/linux/wkup_m3_ipc.h
new file mode 100644
index 000000000000..d6ba7d39a62f
--- /dev/null
+++ b/include/linux/wkup_m3_ipc.h
@@ -0,0 +1,55 @@
+/*
+ * TI Wakeup M3 for AMx3 SoCs Power Management Routines
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach <d-gerlach@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 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.
+ */
+
+#ifndef _LINUX_WKUP_M3_IPC_H
+#define _LINUX_WKUP_M3_IPC_H
+
+#define WKUP_M3_DEEPSLEEP 1
+#define WKUP_M3_STANDBY 2
+#define WKUP_M3_IDLE 3
+
+#include <linux/mailbox_client.h>
+
+struct wkup_m3_ipc_ops;
+
+struct wkup_m3_ipc {
+ struct rproc *rproc;
+
+ void __iomem *ipc_mem_base;
+ struct device *dev;
+
+ int mem_type;
+ unsigned long resume_addr;
+ int state;
+
+ struct completion sync_complete;
+ struct mbox_client mbox_client;
+ struct mbox_chan *mbox;
+
+ struct wkup_m3_ipc_ops *ops;
+};
+
+struct wkup_m3_ipc_ops {
+ void (*set_mem_type)(struct wkup_m3_ipc *m3_ipc, int mem_type);
+ void (*set_resume_address)(struct wkup_m3_ipc *m3_ipc, void *addr);
+ int (*prepare_low_power)(struct wkup_m3_ipc *m3_ipc, int state);
+ int (*finish_low_power)(struct wkup_m3_ipc *m3_ipc);
+ int (*request_pm_status)(struct wkup_m3_ipc *m3_ipc);
+};
+
+struct wkup_m3_ipc *wkup_m3_ipc_get(void);
+void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc);
+#endif /* _LINUX_WKUP_M3_IPC_H */
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 6e6db78f1ee2..d3855898c3fc 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -30,6 +30,238 @@
#include <media/media-devnode.h>
#include <media/media-entity.h>
+/**
+ * DOC: Media Controller
+ *
+ * The media controller userspace API is documented in DocBook format in
+ * Documentation/DocBook/media/v4l/media-controller.xml. This document focus
+ * on the kernel-side implementation of the media framework.
+ *
+ * * Abstract media device model:
+ *
+ * Discovering a device internal topology, and configuring it at runtime, is one
+ * of the goals of the media framework. To achieve this, hardware devices are
+ * modelled as an oriented graph of building blocks called entities connected
+ * through pads.
+ *
+ * An entity is a basic media hardware building block. It can correspond to
+ * a large variety of logical blocks such as physical hardware devices
+ * (CMOS sensor for instance), logical hardware devices (a building block
+ * in a System-on-Chip image processing pipeline), DMA channels or physical
+ * connectors.
+ *
+ * A pad is a connection endpoint through which an entity can interact with
+ * other entities. Data (not restricted to video) produced by an entity
+ * flows from the entity's output to one or more entity inputs. Pads should
+ * not be confused with physical pins at chip boundaries.
+ *
+ * A link is a point-to-point oriented connection between two pads, either
+ * on the same entity or on different entities. Data flows from a source
+ * pad to a sink pad.
+ *
+ *
+ * * Media device:
+ *
+ * A media device is represented by a struct &media_device instance, defined in
+ * include/media/media-device.h. Allocation of the structure is handled by the
+ * media device driver, usually by embedding the &media_device instance in a
+ * larger driver-specific structure.
+ *
+ * Drivers register media device instances by calling
+ * __media_device_register() via the macro media_device_register()
+ * and unregistered by calling
+ * media_device_unregister().
+ *
+ * * Entities, pads and links:
+ *
+ * - Entities
+ *
+ * Entities are represented by a struct &media_entity instance, defined in
+ * include/media/media-entity.h. The structure is usually embedded into a
+ * higher-level structure, such as a v4l2_subdev or video_device instance,
+ * although drivers can allocate entities directly.
+ *
+ * Drivers initialize entity pads by calling
+ * media_entity_pads_init().
+ *
+ * Drivers register entities with a media device by calling
+ * media_device_register_entity()
+ * and unregistred by calling
+ * media_device_unregister_entity().
+ *
+ * - Interfaces
+ *
+ * Interfaces are represented by a struct &media_interface instance, defined in
+ * include/media/media-entity.h. Currently, only one type of interface is
+ * defined: a device node. Such interfaces are represented by a struct
+ * &media_intf_devnode.
+ *
+ * Drivers initialize and create device node interfaces by calling
+ * media_devnode_create()
+ * and remove them by calling:
+ * media_devnode_remove().
+ *
+ * - Pads
+ *
+ * Pads are represented by a struct &media_pad instance, defined in
+ * include/media/media-entity.h. Each entity stores its pads in a pads array
+ * managed by the entity driver. Drivers usually embed the array in a
+ * driver-specific structure.
+ *
+ * Pads are identified by their entity and their 0-based index in the pads
+ * array.
+ * Both information are stored in the &media_pad structure, making the
+ * &media_pad pointer the canonical way to store and pass link references.
+ *
+ * Pads have flags that describe the pad capabilities and state.
+ *
+ * %MEDIA_PAD_FL_SINK indicates that the pad supports sinking data.
+ * %MEDIA_PAD_FL_SOURCE indicates that the pad supports sourcing data.
+ *
+ * NOTE: One and only one of %MEDIA_PAD_FL_SINK and %MEDIA_PAD_FL_SOURCE must
+ * be set for each pad.
+ *
+ * - Links
+ *
+ * Links are represented by a struct &media_link instance, defined in
+ * include/media/media-entity.h. There are two types of links:
+ *
+ * 1. pad to pad links:
+ *
+ * Associate two entities via their PADs. Each entity has a list that points
+ * to all links originating at or targeting any of its pads.
+ * A given link is thus stored twice, once in the source entity and once in
+ * the target entity.
+ *
+ * Drivers create pad to pad links by calling:
+ * media_create_pad_link() and remove with media_entity_remove_links().
+ *
+ * 2. interface to entity links:
+ *
+ * Associate one interface to a Link.
+ *
+ * Drivers create interface to entity links by calling:
+ * media_create_intf_link() and remove with media_remove_intf_links().
+ *
+ * NOTE:
+ *
+ * Links can only be created after having both ends already created.
+ *
+ * Links have flags that describe the link capabilities and state. The
+ * valid values are described at media_create_pad_link() and
+ * media_create_intf_link().
+ *
+ * Graph traversal:
+ *
+ * The media framework provides APIs to iterate over entities in a graph.
+ *
+ * To iterate over all entities belonging to a media device, drivers can use
+ * the media_device_for_each_entity macro, defined in
+ * include/media/media-device.h.
+ *
+ * struct media_entity *entity;
+ *
+ * media_device_for_each_entity(entity, mdev) {
+ * // entity will point to each entity in turn
+ * ...
+ * }
+ *
+ * Drivers might also need to iterate over all entities in a graph that can be
+ * reached only through enabled links starting at a given entity. The media
+ * framework provides a depth-first graph traversal API for that purpose.
+ *
+ * Note that graphs with cycles (whether directed or undirected) are *NOT*
+ * supported by the graph traversal API. To prevent infinite loops, the graph
+ * traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
+ * currently defined as 16.
+ *
+ * Drivers initiate a graph traversal by calling
+ * media_entity_graph_walk_start()
+ *
+ * The graph structure, provided by the caller, is initialized to start graph
+ * traversal at the given entity.
+ *
+ * Drivers can then retrieve the next entity by calling
+ * media_entity_graph_walk_next()
+ *
+ * When the graph traversal is complete the function will return NULL.
+ *
+ * Graph traversal can be interrupted at any moment. No cleanup function call
+ * is required and the graph structure can be freed normally.
+ *
+ * Helper functions can be used to find a link between two given pads, or a pad
+ * connected to another pad through an enabled link
+ * media_entity_find_link() and media_entity_remote_pad()
+ *
+ * Use count and power handling:
+ *
+ * Due to the wide differences between drivers regarding power management
+ * needs, the media controller does not implement power management. However,
+ * the &media_entity structure includes a use_count field that media drivers
+ * can use to track the number of users of every entity for power management
+ * needs.
+ *
+ * The &media_entity.@use_count field is owned by media drivers and must not be
+ * touched by entity drivers. Access to the field must be protected by the
+ * &media_device.@graph_mutex lock.
+ *
+ * Links setup:
+ *
+ * Link properties can be modified at runtime by calling
+ * media_entity_setup_link()
+ *
+ * Pipelines and media streams:
+ *
+ * When starting streaming, drivers must notify all entities in the pipeline to
+ * prevent link states from being modified during streaming by calling
+ * media_entity_pipeline_start().
+ *
+ * The function will mark all entities connected to the given entity through
+ * enabled links, either directly or indirectly, as streaming.
+ *
+ * The &media_pipeline instance pointed to by the pipe argument will be stored
+ * in every entity in the pipeline. Drivers should embed the &media_pipeline
+ * structure in higher-level pipeline structures and can then access the
+ * pipeline through the &media_entity pipe field.
+ *
+ * Calls to media_entity_pipeline_start() can be nested. The pipeline pointer
+ * must be identical for all nested calls to the function.
+ *
+ * media_entity_pipeline_start() may return an error. In that case, it will
+ * clean up any of the changes it did by itself.
+ *
+ * When stopping the stream, drivers must notify the entities with
+ * media_entity_pipeline_stop().
+ *
+ * If multiple calls to media_entity_pipeline_start() have been made the same
+ * number of media_entity_pipeline_stop() calls are required to stop streaming.
+ * The &media_entity pipe field is reset to NULL on the last nested stop call.
+ *
+ * Link configuration will fail with -%EBUSY by default if either end of the
+ * link is a streaming entity. Links that can be modified while streaming must
+ * be marked with the %MEDIA_LNK_FL_DYNAMIC flag.
+ *
+ * If other operations need to be disallowed on streaming entities (such as
+ * changing entities configuration parameters) drivers can explicitly check the
+ * media_entity stream_count field to find out if an entity is streaming. This
+ * operation must be done with the media_device graph_mutex held.
+ *
+ * Link validation:
+ *
+ * Link validation is performed by media_entity_pipeline_start() for any
+ * entity which has sink pads in the pipeline. The
+ * &media_entity.@link_validate() callback is used for that purpose. In
+ * @link_validate() callback, entity driver should check that the properties of
+ * the source pad of the connected entity and its own sink pad match. It is up
+ * to the type of the entity (and in the end, the properties of the hardware)
+ * what matching actually means.
+ *
+ * Subsystems should facilitate link validation by providing subsystem specific
+ * helper functions to provide easy access for commonly needed information, and
+ * in the end provide a way to use driver-specific callbacks.
+ */
+
+struct ida;
struct device;
/**
@@ -41,8 +273,16 @@ struct device;
* @bus_info: Unique and stable device location identifier
* @hw_revision: Hardware device revision
* @driver_version: Device driver version
- * @entity_id: ID of the next entity to be registered
+ * @topology_version: Monotonic counter for storing the version of the graph
+ * topology. Should be incremented each time the topology changes.
+ * @id: Unique ID used on the last registered graph object
+ * @entity_internal_idx: Unique internal entity ID used by the graph traversal
+ * algorithms
+ * @entity_internal_idx_max: Allocated internal entity indices
* @entities: List of registered entities
+ * @interfaces: List of registered interfaces
+ * @pads: List of registered pads
+ * @links: List of registered links
* @lock: Entities list lock
* @graph_mutex: Entities graph operation lock
* @link_notify: Link state change notification callback
@@ -68,10 +308,18 @@ struct media_device {
u32 hw_revision;
u32 driver_version;
- u32 entity_id;
+ u32 topology_version;
+
+ u32 id;
+ struct ida entity_internal_idx;
+ int entity_internal_idx_max;
+
struct list_head entities;
+ struct list_head interfaces;
+ struct list_head pads;
+ struct list_head links;
- /* Protects the entities list */
+ /* Protects the graph objects creation/removal */
spinlock_t lock;
/* Serializes graph operations. */
struct mutex graph_mutex;
@@ -80,6 +328,8 @@ struct media_device {
unsigned int notification);
};
+#ifdef CONFIG_MEDIA_CONTROLLER
+
/* Supported link_notify @notification values. */
#define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0
#define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
@@ -87,17 +337,228 @@ struct media_device {
/* media_devnode to media_device */
#define to_media_device(node) container_of(node, struct media_device, devnode)
+/**
+ * media_entity_enum_init - Initialise an entity enumeration
+ *
+ * @ent_enum: Entity enumeration to be initialised
+ * @mdev: The related media device
+ *
+ * Returns zero on success or a negative error code.
+ */
+static inline __must_check int media_entity_enum_init(
+ struct media_entity_enum *ent_enum, struct media_device *mdev)
+{
+ return __media_entity_enum_init(ent_enum,
+ mdev->entity_internal_idx_max + 1);
+}
+
+/**
+ * media_device_init() - Initializes a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ *
+ * This function initializes the media device prior to its registration.
+ * The media device initialization and registration is split in two functions
+ * to avoid race conditions and make the media device available to user-space
+ * before the media graph has been completed.
+ *
+ * So drivers need to first initialize the media device, register any entity
+ * within the media device, create pad to pad links and then finally register
+ * the media device by calling media_device_register() as a final step.
+ */
+void media_device_init(struct media_device *mdev);
+
+/**
+ * media_device_cleanup() - Cleanups a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ *
+ * This function that will destroy the graph_mutex that is
+ * initialized in media_device_init().
+ */
+void media_device_cleanup(struct media_device *mdev);
+
+/**
+ * __media_device_register() - Registers a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ * @owner: should be filled with %THIS_MODULE
+ *
+ * Users, should, instead, call the media_device_register() macro.
+ *
+ * The caller is responsible for initializing the media_device structure before
+ * registration. The following fields must be set:
+ *
+ * - dev must point to the parent device (usually a &pci_dev, &usb_interface or
+ * &platform_device instance).
+ *
+ * - model must be filled with the device model name as a NUL-terminated UTF-8
+ * string. The device/model revision must not be stored in this field.
+ *
+ * The following fields are optional:
+ *
+ * - serial is a unique serial number stored as a NUL-terminated ASCII string.
+ * The field is big enough to store a GUID in text form. If the hardware
+ * doesn't provide a unique serial number this field must be left empty.
+ *
+ * - bus_info represents the location of the device in the system as a
+ * NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
+ * "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
+ * the usb_make_path() function must be used. This field is used by
+ * applications to distinguish between otherwise identical devices that don't
+ * provide a serial number.
+ *
+ * - hw_revision is the hardware device revision in a driver-specific format.
+ * When possible the revision should be formatted with the KERNEL_VERSION
+ * macro.
+ *
+ * - driver_version is formatted with the KERNEL_VERSION macro. The version
+ * minor must be incremented when new features are added to the userspace API
+ * without breaking binary compatibility. The version major must be
+ * incremented when binary compatibility is broken.
+ *
+ * Notes:
+ *
+ * Upon successful registration a character device named media[0-9]+ is created.
+ * The device major and minor numbers are dynamic. The model name is exported as
+ * a sysfs attribute.
+ *
+ * Unregistering a media device that hasn't been registered is *NOT* safe.
+ *
+ * Return: returns zero on success or a negative error code.
+ */
int __must_check __media_device_register(struct media_device *mdev,
struct module *owner);
#define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE)
+
+/**
+ * __media_device_unregister() - Unegisters a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ *
+ *
+ * It is safe to call this function on an unregistered (but initialised)
+ * media device.
+ */
void media_device_unregister(struct media_device *mdev);
+/**
+ * media_device_register_entity() - registers a media entity inside a
+ * previously registered media device.
+ *
+ * @mdev: pointer to struct &media_device
+ * @entity: pointer to struct &media_entity to be registered
+ *
+ * Entities are identified by a unique positive integer ID. The media
+ * controller framework will such ID automatically. IDs are not guaranteed
+ * to be contiguous, and the ID number can change on newer Kernel versions.
+ * So, neither the driver nor userspace should hardcode ID numbers to refer
+ * to the entities, but, instead, use the framework to find the ID, when
+ * needed.
+ *
+ * The media_entity name, type and flags fields should be initialized before
+ * calling media_device_register_entity(). Entities embedded in higher-level
+ * standard structures can have some of those fields set by the higher-level
+ * framework.
+ *
+ * If the device has pads, media_entity_pads_init() should be called before
+ * this function. Otherwise, the &media_entity.@pad and &media_entity.@num_pads
+ * should be zeroed before calling this function.
+ *
+ * Entities have flags that describe the entity capabilities and state:
+ *
+ * %MEDIA_ENT_FL_DEFAULT indicates the default entity for a given type.
+ * This can be used to report the default audio and video devices or the
+ * default camera sensor.
+ *
+ * NOTE: Drivers should set the entity function before calling this function.
+ * Please notice that the values %MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN and
+ * %MEDIA_ENT_F_UNKNOWN should not be used by the drivers.
+ */
int __must_check media_device_register_entity(struct media_device *mdev,
struct media_entity *entity);
+
+/*
+ * media_device_unregister_entity() - unregisters a media entity.
+ *
+ * @entity: pointer to struct &media_entity to be unregistered
+ *
+ * All links associated with the entity and all PADs are automatically
+ * unregistered from the media_device when this function is called.
+ *
+ * Unregistering an entity will not change the IDs of the other entities and
+ * the previoully used ID will never be reused for a newly registered entities.
+ *
+ * When a media device is unregistered, all its entities are unregistered
+ * automatically. No manual entities unregistration is then required.
+ *
+ * Note: the media_entity instance itself must be freed explicitly by
+ * the driver if required.
+ */
void media_device_unregister_entity(struct media_entity *entity);
+/**
+ * media_device_get_devres() - get media device as device resource
+ * creates if one doesn't exist
+ *
+ * @dev: pointer to struct &device.
+ *
+ * Sometimes, the media controller &media_device needs to be shared by more
+ * than one driver. This function adds support for that, by dynamically
+ * allocating the &media_device and allowing it to be obtained from the
+ * struct &device associated with the common device where all sub-device
+ * components belong. So, for example, on an USB device with multiple
+ * interfaces, each interface may be handled by a separate per-interface
+ * drivers. While each interface have its own &device, they all share a
+ * common &device associated with the hole USB device.
+ */
+struct media_device *media_device_get_devres(struct device *dev);
+
+/**
+ * media_device_find_devres() - find media device as device resource
+ *
+ * @dev: pointer to struct &device.
+ */
+struct media_device *media_device_find_devres(struct device *dev);
+
/* Iterate over all entities. */
#define media_device_for_each_entity(entity, mdev) \
- list_for_each_entry(entity, &(mdev)->entities, list)
+ list_for_each_entry(entity, &(mdev)->entities, graph_obj.list)
+
+/* Iterate over all interfaces. */
+#define media_device_for_each_intf(intf, mdev) \
+ list_for_each_entry(intf, &(mdev)->interfaces, graph_obj.list)
+
+/* Iterate over all pads. */
+#define media_device_for_each_pad(pad, mdev) \
+ list_for_each_entry(pad, &(mdev)->pads, graph_obj.list)
+/* Iterate over all links. */
+#define media_device_for_each_link(link, mdev) \
+ list_for_each_entry(link, &(mdev)->links, graph_obj.list)
+#else
+static inline int media_device_register(struct media_device *mdev)
+{
+ return 0;
+}
+static inline void media_device_unregister(struct media_device *mdev)
+{
+}
+static inline int media_device_register_entity(struct media_device *mdev,
+ struct media_entity *entity)
+{
+ return 0;
+}
+static inline void media_device_unregister_entity(struct media_entity *entity)
+{
+}
+static inline struct media_device *media_device_get_devres(struct device *dev)
+{
+ return NULL;
+}
+static inline struct media_device *media_device_find_devres(struct device *dev)
+{
+ return NULL;
+}
+#endif /* CONFIG_MEDIA_CONTROLLER */
#endif
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
index 17ddae32060d..fe42f08e72bd 100644
--- a/include/media/media-devnode.h
+++ b/include/media/media-devnode.h
@@ -40,6 +40,20 @@
*/
#define MEDIA_FLAG_REGISTERED 0
+/**
+ * struct media_file_operations - Media device file operations
+ *
+ * @owner: should be filled with %THIS_MODULE
+ * @read: pointer to the function that implements read() syscall
+ * @write: pointer to the function that implements write() syscall
+ * @poll: pointer to the function that implements poll() syscall
+ * @ioctl: pointer to the function that implements ioctl() syscall
+ * @compat_ioctl: pointer to the function that will handle 32 bits userspace
+ * calls to the the ioctl() syscall on a Kernel compiled with 64 bits.
+ * @open: pointer to the function that implements open() syscall
+ * @release: pointer to the function that will release the resources allocated
+ * by the @open function.
+ */
struct media_file_operations {
struct module *owner;
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
@@ -53,7 +67,7 @@ struct media_file_operations {
/**
* struct media_devnode - Media device node
- * @fops: pointer to struct media_file_operations with media device ops
+ * @fops: pointer to struct &media_file_operations with media device ops
* @dev: struct device pointer for the media controller device
* @cdev: struct cdev pointer character device
* @parent: parent device
@@ -86,15 +100,53 @@ struct media_devnode {
/* dev to media_devnode */
#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+/**
+ * media_devnode_register - register a media device node
+ *
+ * @mdev: media device node structure we want to register
+ * @owner: should be filled with %THIS_MODULE
+ *
+ * The registration code assigns minor numbers and registers the new device node
+ * with the kernel. An error is returned if no free minor number can be found,
+ * or if the registration of the device node fails.
+ *
+ * Zero is returned on success.
+ *
+ * Note that if the media_devnode_register call fails, the release() callback of
+ * the media_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
int __must_check media_devnode_register(struct media_devnode *mdev,
struct module *owner);
+
+/**
+ * media_devnode_unregister - unregister a media device node
+ * @mdev: the device node to unregister
+ *
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+ *
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
void media_devnode_unregister(struct media_devnode *mdev);
+/**
+ * media_devnode_data - returns a pointer to the &media_devnode
+ *
+ * @filp: pointer to struct &file
+ */
static inline struct media_devnode *media_devnode_data(struct file *filp)
{
return filp->private_data;
}
+/**
+ * media_devnode_is_registered - returns true if &media_devnode is registered;
+ * false otherwise.
+ *
+ * @mdev: pointer to struct &media_devnode.
+ */
static inline int media_devnode_is_registered(struct media_devnode *mdev)
{
return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 197f93799753..fe485d367985 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -23,25 +23,151 @@
#ifndef _MEDIA_ENTITY_H
#define _MEDIA_ENTITY_H
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/media.h>
+/* Enums used internally at the media controller to represent graphs */
+
+/**
+ * enum media_gobj_type - type of a graph object
+ *
+ * @MEDIA_GRAPH_ENTITY: Identify a media entity
+ * @MEDIA_GRAPH_PAD: Identify a media pad
+ * @MEDIA_GRAPH_LINK: Identify a media link
+ * @MEDIA_GRAPH_INTF_DEVNODE: Identify a media Kernel API interface via
+ * a device node
+ */
+enum media_gobj_type {
+ MEDIA_GRAPH_ENTITY,
+ MEDIA_GRAPH_PAD,
+ MEDIA_GRAPH_LINK,
+ MEDIA_GRAPH_INTF_DEVNODE,
+};
+
+#define MEDIA_BITS_PER_TYPE 8
+#define MEDIA_BITS_PER_ID (32 - MEDIA_BITS_PER_TYPE)
+#define MEDIA_ID_MASK GENMASK_ULL(MEDIA_BITS_PER_ID - 1, 0)
+
+/* Structs to represent the objects that belong to a media graph */
+
+/**
+ * struct media_gobj - Define a graph object.
+ *
+ * @mdev: Pointer to the struct media_device that owns the object
+ * @id: Non-zero object ID identifier. The ID should be unique
+ * inside a media_device, as it is composed by
+ * %MEDIA_BITS_PER_TYPE to store the type plus
+ * %MEDIA_BITS_PER_ID to store the ID
+ * @list: List entry stored in one of the per-type mdev object lists
+ *
+ * All objects on the media graph should have this struct embedded
+ */
+struct media_gobj {
+ struct media_device *mdev;
+ u32 id;
+ struct list_head list;
+};
+
+#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
+
+/**
+ * struct media_entity_enum - An enumeration of media entities.
+ *
+ * @bmap: Bit map in which each bit represents one entity at struct
+ * media_entity->internal_idx.
+ * @idx_max: Number of bits in bmap
+ */
+struct media_entity_enum {
+ unsigned long *bmap;
+ int idx_max;
+};
+
+/**
+ * struct media_entity_graph - Media graph traversal state
+ *
+ * @stack: Graph traversal stack; the stack contains information
+ * on the path the media entities to be walked and the
+ * links through which they were reached.
+ * @ent_enum: Visited entities
+ * @top: The top of the stack
+ */
+struct media_entity_graph {
+ struct {
+ struct media_entity *entity;
+ struct list_head *link;
+ } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
+
+ struct media_entity_enum ent_enum;
+ int top;
+};
+
+/*
+ * struct media_pipeline - Media pipeline related information
+ *
+ * @streaming_count: Streaming start count - streaming stop count
+ * @graph: Media graph walk during pipeline start / stop
+ */
struct media_pipeline {
+ int streaming_count;
+ struct media_entity_graph graph;
};
+/**
+ * struct media_link - A link object part of a media graph.
+ *
+ * @graph_obj: Embedded structure containing the media object common data
+ * @list: Linked list associated with an entity or an interface that
+ * owns the link.
+ * @gobj0: Part of a union. Used to get the pointer for the first
+ * graph_object of the link.
+ * @source: Part of a union. Used only if the first object (gobj0) is
+ * a pad. In that case, it represents the source pad.
+ * @intf: Part of a union. Used only if the first object (gobj0) is
+ * an interface.
+ * @gobj1: Part of a union. Used to get the pointer for the second
+ * graph_object of the link.
+ * @source: Part of a union. Used only if the second object (gobj1) is
+ * a pad. In that case, it represents the sink pad.
+ * @entity: Part of a union. Used only if the second object (gobj1) is
+ * an entity.
+ * @reverse: Pointer to the link for the reverse direction of a pad to pad
+ * link.
+ * @flags: Link flags, as defined in uapi/media.h (MEDIA_LNK_FL_*)
+ * @is_backlink: Indicate if the link is a backlink.
+ */
struct media_link {
- struct media_pad *source; /* Source pad */
- struct media_pad *sink; /* Sink pad */
- struct media_link *reverse; /* Link in the reverse direction */
- unsigned long flags; /* Link flags (MEDIA_LNK_FL_*) */
+ struct media_gobj graph_obj;
+ struct list_head list;
+ union {
+ struct media_gobj *gobj0;
+ struct media_pad *source;
+ struct media_interface *intf;
+ };
+ union {
+ struct media_gobj *gobj1;
+ struct media_pad *sink;
+ struct media_entity *entity;
+ };
+ struct media_link *reverse;
+ unsigned long flags;
+ bool is_backlink;
};
+/**
+ * struct media_pad - A media pad graph object.
+ *
+ * @graph_obj: Embedded structure containing the media object common data
+ * @entity: Entity this pad belongs to
+ * @index: Pad index in the entity pads array, numbered from 0 to n
+ * @flags: Pad flags, as defined in uapi/media.h (MEDIA_PAD_FL_*)
+ */
struct media_pad {
- struct media_entity *entity; /* Entity this pad belongs to */
- u16 index; /* Pad index in the entity pads array */
- unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */
+ struct media_gobj graph_obj; /* must be first field in struct */
+ struct media_entity *entity;
+ u16 index;
+ unsigned long flags;
};
/**
@@ -60,105 +186,763 @@ struct media_entity_operations {
int (*link_validate)(struct media_link *link);
};
+/**
+ * struct media_entity - A media entity graph object.
+ *
+ * @graph_obj: Embedded structure containing the media object common data.
+ * @name: Entity name.
+ * @function: Entity main function, as defined in uapi/media.h
+ * (MEDIA_ENT_F_*)
+ * @flags: Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*)
+ * @num_pads: Number of sink and source pads.
+ * @num_links: Total number of links, forward and back, enabled and disabled.
+ * @num_backlinks: Number of backlinks
+ * @internal_idx: An unique internal entity specific number. The numbers are
+ * re-used if entities are unregistered or registered again.
+ * @pads: Pads array with the size defined by @num_pads.
+ * @links: List of data links.
+ * @ops: Entity operations.
+ * @stream_count: Stream count for the entity.
+ * @use_count: Use count for the entity.
+ * @pipe: Pipeline this entity belongs to.
+ * @info: Union with devnode information. Kept just for backward
+ * compatibility.
+ * @major: Devnode major number (zero if not applicable). Kept just
+ * for backward compatibility.
+ * @minor: Devnode minor number (zero if not applicable). Kept just
+ * for backward compatibility.
+ *
+ * NOTE: @stream_count and @use_count reference counts must never be
+ * negative, but are signed integers on purpose: a simple WARN_ON(<0) check
+ * can be used to detect reference count bugs that would make them negative.
+ */
struct media_entity {
- struct list_head list;
- struct media_device *parent; /* Media device this entity belongs to*/
- u32 id; /* Entity ID, unique in the parent media
- * device context */
- const char *name; /* Entity name */
- u32 type; /* Entity type (MEDIA_ENT_T_*) */
- u32 revision; /* Entity revision, driver specific */
- unsigned long flags; /* Entity flags (MEDIA_ENT_FL_*) */
- u32 group_id; /* Entity group ID */
-
- u16 num_pads; /* Number of sink and source pads */
- u16 num_links; /* Number of existing links, both
- * enabled and disabled */
- u16 num_backlinks; /* Number of backlinks */
- u16 max_links; /* Maximum number of links */
-
- struct media_pad *pads; /* Pads array (num_pads elements) */
- struct media_link *links; /* Links array (max_links elements)*/
-
- const struct media_entity_operations *ops; /* Entity operations */
+ struct media_gobj graph_obj; /* must be first field in struct */
+ const char *name;
+ u32 function;
+ unsigned long flags;
+
+ u16 num_pads;
+ u16 num_links;
+ u16 num_backlinks;
+ int internal_idx;
+
+ struct media_pad *pads;
+ struct list_head links;
+
+ const struct media_entity_operations *ops;
/* Reference counts must never be negative, but are signed integers on
* purpose: a simple WARN_ON(<0) check can be used to detect reference
* count bugs that would make them negative.
*/
- int stream_count; /* Stream count for the entity. */
- int use_count; /* Use count for the entity. */
+ int stream_count;
+ int use_count;
- struct media_pipeline *pipe; /* Pipeline this entity belongs to. */
+ struct media_pipeline *pipe;
union {
- /* Node specifications */
struct {
u32 major;
u32 minor;
} dev;
-
- /* Sub-device specifications */
- /* Nothing needed yet */
} info;
};
-static inline u32 media_entity_type(struct media_entity *entity)
+/**
+ * struct media_interface - A media interface graph object.
+ *
+ * @graph_obj: embedded graph object
+ * @links: List of links pointing to graph entities
+ * @type: Type of the interface as defined in the
+ * uapi/media/media.h header, e. g.
+ * MEDIA_INTF_T_*
+ * @flags: Interface flags as defined in uapi/media/media.h
+ */
+struct media_interface {
+ struct media_gobj graph_obj;
+ struct list_head links;
+ u32 type;
+ u32 flags;
+};
+
+/**
+ * struct media_intf_devnode - A media interface via a device node.
+ *
+ * @intf: embedded interface object
+ * @major: Major number of a device node
+ * @minor: Minor number of a device node
+ */
+struct media_intf_devnode {
+ struct media_interface intf;
+
+ /* Should match the fields at media_v2_intf_devnode */
+ u32 major;
+ u32 minor;
+};
+
+/**
+ * media_entity_id() - return the media entity graph object id
+ *
+ * @entity: pointer to entity
+ */
+static inline u32 media_entity_id(struct media_entity *entity)
{
- return entity->type & MEDIA_ENT_TYPE_MASK;
+ return entity->graph_obj.id;
}
-static inline u32 media_entity_subtype(struct media_entity *entity)
+/**
+ * media_type() - return the media object type
+ *
+ * @gobj: pointer to the media graph object
+ */
+static inline enum media_gobj_type media_type(struct media_gobj *gobj)
{
- return entity->type & MEDIA_ENT_SUBTYPE_MASK;
+ return gobj->id >> MEDIA_BITS_PER_ID;
}
-#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
-#define MEDIA_ENTITY_ENUM_MAX_ID 64
+/**
+ * media_id() - return the media object ID
+ *
+ * @gobj: pointer to the media graph object
+ */
+static inline u32 media_id(struct media_gobj *gobj)
+{
+ return gobj->id & MEDIA_ID_MASK;
+}
-/*
- * The number of pads can't be bigger than the number of entities,
- * as the worse-case scenario is to have one entity linked up to
- * MEDIA_ENTITY_ENUM_MAX_ID - 1 entities.
+/**
+ * media_gobj_gen_id() - encapsulates type and ID on at the object ID
+ *
+ * @type: object type as define at enum &media_gobj_type.
+ * @local_id: next ID, from struct &media_device.@id.
*/
-#define MEDIA_ENTITY_MAX_PADS (MEDIA_ENTITY_ENUM_MAX_ID - 1)
+static inline u32 media_gobj_gen_id(enum media_gobj_type type, u64 local_id)
+{
+ u32 id;
-struct media_entity_graph {
- struct {
- struct media_entity *entity;
- int link;
- } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
+ id = type << MEDIA_BITS_PER_ID;
+ id |= local_id & MEDIA_ID_MASK;
- DECLARE_BITMAP(entities, MEDIA_ENTITY_ENUM_MAX_ID);
- int top;
-};
+ return id;
+}
+
+/**
+ * is_media_entity_v4l2_io() - identify if the entity main function
+ * is a V4L2 I/O
+ *
+ * @entity: pointer to entity
+ *
+ * Return: true if the entity main function is one of the V4L2 I/O types
+ * (video, VBI or SDR radio); false otherwise.
+ */
+static inline bool is_media_entity_v4l2_io(struct media_entity *entity)
+{
+ if (!entity)
+ return false;
+
+ switch (entity->function) {
+ case MEDIA_ENT_F_IO_V4L:
+ case MEDIA_ENT_F_IO_VBI:
+ case MEDIA_ENT_F_IO_SWRADIO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * is_media_entity_v4l2_subdev - return true if the entity main function is
+ * associated with the V4L2 API subdev usage
+ *
+ * @entity: pointer to entity
+ *
+ * This is an ancillary function used by subdev-based V4L2 drivers.
+ * It checks if the entity function is one of functions used by a V4L2 subdev,
+ * e. g. camera-relatef functions, analog TV decoder, TV tuner, V4L2 DSPs.
+ */
+static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity)
+{
+ if (!entity)
+ return false;
+
+ switch (entity->function) {
+ case MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
+ case MEDIA_ENT_F_CAM_SENSOR:
+ case MEDIA_ENT_F_FLASH:
+ case MEDIA_ENT_F_LENS:
+ case MEDIA_ENT_F_ATV_DECODER:
+ case MEDIA_ENT_F_TUNER:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * __media_entity_enum_init - Initialise an entity enumeration
+ *
+ * @ent_enum: Entity enumeration to be initialised
+ * @idx_max: Maximum number of entities in the enumeration
+ *
+ * Return: Returns zero on success or a negative error code.
+ */
+__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
+ int idx_max);
+
+/**
+ * media_entity_enum_cleanup - Release resources of an entity enumeration
+ *
+ * @ent_enum: Entity enumeration to be released
+ */
+void media_entity_enum_cleanup(struct media_entity_enum *ent_enum);
+
+/**
+ * media_entity_enum_zero - Clear the entire enum
+ *
+ * @ent_enum: Entity enumeration to be cleared
+ */
+static inline void media_entity_enum_zero(struct media_entity_enum *ent_enum)
+{
+ bitmap_zero(ent_enum->bmap, ent_enum->idx_max);
+}
+
+/**
+ * media_entity_enum_set - Mark a single entity in the enum
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be marked
+ */
+static inline void media_entity_enum_set(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return;
+
+ __set_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_clear - Unmark a single entity in the enum
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be unmarked
+ */
+static inline void media_entity_enum_clear(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return;
-int media_entity_init(struct media_entity *entity, u16 num_pads,
- struct media_pad *pads, u16 extra_links);
-void media_entity_cleanup(struct media_entity *entity);
+ __clear_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_test - Test whether the entity is marked
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be tested
+ *
+ * Returns true if the entity was marked.
+ */
+static inline bool media_entity_enum_test(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return true;
+
+ return test_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_test - Test whether the entity is marked, and mark it
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be tested
+ *
+ * Returns true if the entity was marked, and mark it before doing so.
+ */
+static inline bool
+media_entity_enum_test_and_set(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return true;
+
+ return __test_and_set_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_empty - Test whether the entire enum is empty
+ *
+ * @ent_enum: Entity enumeration
+ *
+ * Returns true if the entity was marked.
+ */
+static inline bool media_entity_enum_empty(struct media_entity_enum *ent_enum)
+{
+ return bitmap_empty(ent_enum->bmap, ent_enum->idx_max);
+}
+
+/**
+ * media_entity_enum_intersects - Test whether two enums intersect
+ *
+ * @ent_enum1: First entity enumeration
+ * @ent_enum2: Second entity enumeration
+ *
+ * Returns true if entity enumerations e and f intersect, otherwise false.
+ */
+static inline bool media_entity_enum_intersects(
+ struct media_entity_enum *ent_enum1,
+ struct media_entity_enum *ent_enum2)
+{
+ WARN_ON(ent_enum1->idx_max != ent_enum2->idx_max);
+
+ return bitmap_intersects(ent_enum1->bmap, ent_enum2->bmap,
+ min(ent_enum1->idx_max, ent_enum2->idx_max));
+}
+
+#define gobj_to_entity(gobj) \
+ container_of(gobj, struct media_entity, graph_obj)
+
+#define gobj_to_pad(gobj) \
+ container_of(gobj, struct media_pad, graph_obj)
+
+#define gobj_to_link(gobj) \
+ container_of(gobj, struct media_link, graph_obj)
+
+#define gobj_to_link(gobj) \
+ container_of(gobj, struct media_link, graph_obj)
+
+#define gobj_to_pad(gobj) \
+ container_of(gobj, struct media_pad, graph_obj)
+
+#define gobj_to_intf(gobj) \
+ container_of(gobj, struct media_interface, graph_obj)
+
+#define intf_to_devnode(intf) \
+ container_of(intf, struct media_intf_devnode, intf)
+
+/**
+ * media_gobj_create - Initialize a graph object
+ *
+ * @mdev: Pointer to the media_device that contains the object
+ * @type: Type of the object
+ * @gobj: Pointer to the graph object
+ *
+ * This routine initializes the embedded struct media_gobj inside a
+ * media graph object. It is called automatically if media_*_create()
+ * calls are used. However, if the object (entity, link, pad, interface)
+ * is embedded on some other object, this function should be called before
+ * registering the object at the media controller.
+ */
+void media_gobj_create(struct media_device *mdev,
+ enum media_gobj_type type,
+ struct media_gobj *gobj);
+
+/**
+ * media_gobj_destroy - Stop using a graph object on a media device
+ *
+ * @gobj: Pointer to the graph object
+ *
+ * This should be called by all routines like media_device_unregister()
+ * that remove/destroy media graph objects.
+ */
+void media_gobj_destroy(struct media_gobj *gobj);
+
+/**
+ * media_entity_pads_init() - Initialize the entity pads
+ *
+ * @entity: entity where the pads belong
+ * @num_pads: total number of sink and source pads
+ * @pads: Array of @num_pads pads.
+ *
+ * The pads array is managed by the entity driver and passed to
+ * media_entity_pads_init() where its pointer will be stored in the entity
+ * structure.
+ *
+ * If no pads are needed, drivers could either directly fill
+ * &media_entity->@num_pads with 0 and &media_entity->@pads with NULL or call
+ * this function that will do the same.
+ *
+ * As the number of pads is known in advance, the pads array is not allocated
+ * dynamically but is managed by the entity driver. Most drivers will embed the
+ * pads array in a driver-specific structure, avoiding dynamic allocation.
+ *
+ * Drivers must set the direction of every pad in the pads array before calling
+ * media_entity_pads_init(). The function will initialize the other pads fields.
+ */
+int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads);
+
+/**
+ * media_entity_cleanup() - free resources associated with an entity
+ *
+ * @entity: entity where the pads belong
+ *
+ * This function must be called during the cleanup phase after unregistering
+ * the entity (currently, it does nothing).
+ */
+static inline void media_entity_cleanup(struct media_entity *entity) {};
+
+/**
+ * media_create_pad_link() - creates a link between two entities.
+ *
+ * @source: pointer to &media_entity of the source pad.
+ * @source_pad: number of the source pad in the pads array
+ * @sink: pointer to &media_entity of the sink pad.
+ * @sink_pad: number of the sink pad in the pads array.
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ *
+ * Valid values for flags:
+ * A %MEDIA_LNK_FL_ENABLED flag indicates that the link is enabled and can be
+ * used to transfer media data. When two or more links target a sink pad,
+ * only one of them can be enabled at a time.
+ *
+ * A %MEDIA_LNK_FL_IMMUTABLE flag indicates that the link enabled state can't
+ * be modified at runtime. If %MEDIA_LNK_FL_IMMUTABLE is set, then
+ * %MEDIA_LNK_FL_ENABLED must also be set since an immutable link is
+ * always enabled.
+ *
+ * NOTE:
+ *
+ * Before calling this function, media_entity_pads_init() and
+ * media_device_register_entity() should be called previously for both ends.
+ */
+__must_check int media_create_pad_link(struct media_entity *source,
+ u16 source_pad, struct media_entity *sink,
+ u16 sink_pad, u32 flags);
+
+/**
+ * media_create_pad_links() - creates a link between two entities.
+ *
+ * @mdev: Pointer to the media_device that contains the object
+ * @source_function: Function of the source entities. Used only if @source is
+ * NULL.
+ * @source: pointer to &media_entity of the source pad. If NULL, it will use
+ * all entities that matches the @sink_function.
+ * @source_pad: number of the source pad in the pads array
+ * @sink_function: Function of the sink entities. Used only if @sink is NULL.
+ * @sink: pointer to &media_entity of the sink pad. If NULL, it will use
+ * all entities that matches the @sink_function.
+ * @sink_pad: number of the sink pad in the pads array.
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ * @allow_both_undefined: if true, then both @source and @sink can be NULL.
+ * In such case, it will create a crossbar between all entities that
+ * matches @source_function to all entities that matches @sink_function.
+ * If false, it will return 0 and won't create any link if both @source
+ * and @sink are NULL.
+ *
+ * Valid values for flags:
+ * A %MEDIA_LNK_FL_ENABLED flag indicates that the link is enabled and can be
+ * used to transfer media data. If multiple links are created and this
+ * flag is passed as an argument, only the first created link will have
+ * this flag.
+ *
+ * A %MEDIA_LNK_FL_IMMUTABLE flag indicates that the link enabled state can't
+ * be modified at runtime. If %MEDIA_LNK_FL_IMMUTABLE is set, then
+ * %MEDIA_LNK_FL_ENABLED must also be set since an immutable link is
+ * always enabled.
+ *
+ * It is common for some devices to have multiple source and/or sink entities
+ * of the same type that should be linked. While media_create_pad_link()
+ * creates link by link, this function is meant to allow 1:n, n:1 and even
+ * cross-bar (n:n) links.
+ *
+ * NOTE: Before calling this function, media_entity_pads_init() and
+ * media_device_register_entity() should be called previously for the entities
+ * to be linked.
+ */
+int media_create_pad_links(const struct media_device *mdev,
+ const u32 source_function,
+ struct media_entity *source,
+ const u16 source_pad,
+ const u32 sink_function,
+ struct media_entity *sink,
+ const u16 sink_pad,
+ u32 flags,
+ const bool allow_both_undefined);
-int media_entity_create_link(struct media_entity *source, u16 source_pad,
- struct media_entity *sink, u16 sink_pad, u32 flags);
void __media_entity_remove_links(struct media_entity *entity);
+
+/**
+ * media_entity_remove_links() - remove all links associated with an entity
+ *
+ * @entity: pointer to &media_entity
+ *
+ * Note: this is called automatically when an entity is unregistered via
+ * media_device_register_entity().
+ */
void media_entity_remove_links(struct media_entity *entity);
+/**
+ * __media_entity_setup_link - Configure a media link without locking
+ * @link: The link being configured
+ * @flags: Link configuration flags
+ *
+ * The bulk of link setup is handled by the two entities connected through the
+ * link. This function notifies both entities of the link configuration change.
+ *
+ * If the link is immutable or if the current and new configuration are
+ * identical, return immediately.
+ *
+ * The user is expected to hold link->source->parent->mutex. If not,
+ * media_entity_setup_link() should be used instead.
+ */
int __media_entity_setup_link(struct media_link *link, u32 flags);
+
+/**
+ * media_entity_setup_link() - changes the link flags properties in runtime
+ *
+ * @link: pointer to &media_link
+ * @flags: the requested new link flags
+ *
+ * The only configurable property is the %MEDIA_LNK_FL_ENABLED link flag
+ * flag to enable/disable a link. Links marked with the
+ * %MEDIA_LNK_FL_IMMUTABLE link flag can not be enabled or disabled.
+ *
+ * When a link is enabled or disabled, the media framework calls the
+ * link_setup operation for the two entities at the source and sink of the
+ * link, in that order. If the second link_setup call fails, another
+ * link_setup call is made on the first entity to restore the original link
+ * flags.
+ *
+ * Media device drivers can be notified of link setup operations by setting the
+ * media_device::link_notify pointer to a callback function. If provided, the
+ * notification callback will be called before enabling and after disabling
+ * links.
+ *
+ * Entity drivers must implement the link_setup operation if any of their links
+ * is non-immutable. The operation must either configure the hardware or store
+ * the configuration information to be applied later.
+ *
+ * Link configuration must not have any side effect on other links. If an
+ * enabled link at a sink pad prevents another link at the same pad from
+ * being enabled, the link_setup operation must return -EBUSY and can't
+ * implicitly disable the first enabled link.
+ *
+ * NOTE: the valid values of the flags for the link is the same as described
+ * on media_create_pad_link(), for pad to pad links or the same as described
+ * on media_create_intf_link(), for interface to entity links.
+ */
int media_entity_setup_link(struct media_link *link, u32 flags);
+
+/**
+ * media_entity_find_link - Find a link between two pads
+ * @source: Source pad
+ * @sink: Sink pad
+ *
+ * Return a pointer to the link between the two entities. If no such link
+ * exists, return NULL.
+ */
struct media_link *media_entity_find_link(struct media_pad *source,
struct media_pad *sink);
+
+/**
+ * media_entity_remote_pad - Find the pad at the remote end of a link
+ * @pad: Pad at the local end of the link
+ *
+ * Search for a remote pad connected to the given pad by iterating over all
+ * links originating or terminating at that pad until an enabled link is found.
+ *
+ * Return a pointer to the pad at the remote end of the first found enabled
+ * link, or NULL if no enabled link has been found.
+ */
struct media_pad *media_entity_remote_pad(struct media_pad *pad);
+/**
+ * media_entity_get - Get a reference to the parent module
+ *
+ * @entity: The entity
+ *
+ * Get a reference to the parent media device module.
+ *
+ * The function will return immediately if @entity is NULL.
+ *
+ * Return a pointer to the entity on success or NULL on failure.
+ */
struct media_entity *media_entity_get(struct media_entity *entity);
+
+__must_check int media_entity_graph_walk_init(
+ struct media_entity_graph *graph, struct media_device *mdev);
+
+/**
+ * media_entity_graph_walk_cleanup - Release resources used by graph walk.
+ *
+ * @graph: Media graph structure that will be used to walk the graph
+ */
+void media_entity_graph_walk_cleanup(struct media_entity_graph *graph);
+
+/**
+ * media_entity_put - Release the reference to the parent module
+ *
+ * @entity: The entity
+ *
+ * Release the reference count acquired by media_entity_get().
+ *
+ * The function will return immediately if @entity is NULL.
+ */
void media_entity_put(struct media_entity *entity);
+/**
+ * media_entity_graph_walk_start - Start walking the media graph at a given entity
+ * @graph: Media graph structure that will be used to walk the graph
+ * @entity: Starting entity
+ *
+ * Before using this function, media_entity_graph_walk_init() must be
+ * used to allocate resources used for walking the graph. This
+ * function initializes the graph traversal structure to walk the
+ * entities graph starting at the given entity. The traversal
+ * structure must not be modified by the caller during graph
+ * traversal. After the graph walk, the resources must be released
+ * using media_entity_graph_walk_cleanup().
+ */
void media_entity_graph_walk_start(struct media_entity_graph *graph,
- struct media_entity *entity);
+ struct media_entity *entity);
+
+/**
+ * media_entity_graph_walk_next - Get the next entity in the graph
+ * @graph: Media graph structure
+ *
+ * Perform a depth-first traversal of the given media entities graph.
+ *
+ * The graph structure must have been previously initialized with a call to
+ * media_entity_graph_walk_start().
+ *
+ * Return the next entity in the graph or NULL if the whole graph have been
+ * traversed.
+ */
struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph);
+
+/**
+ * media_entity_pipeline_start - Mark a pipeline as streaming
+ * @entity: Starting entity
+ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as streaming. The given pipeline object is assigned to
+ * every entity in the pipeline and stored in the media_entity pipe field.
+ *
+ * Calls to this function can be nested, in which case the same number of
+ * media_entity_pipeline_stop() calls will be required to stop streaming. The
+ * pipeline pointer must be identical for all nested calls to
+ * media_entity_pipeline_start().
+ */
__must_check int media_entity_pipeline_start(struct media_entity *entity,
struct media_pipeline *pipe);
+
+/**
+ * media_entity_pipeline_stop - Mark a pipeline as not streaming
+ * @entity: Starting entity
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as not streaming. The media_entity pipe field is
+ * reset to NULL.
+ *
+ * If multiple calls to media_entity_pipeline_start() have been made, the same
+ * number of calls to this function are required to mark the pipeline as not
+ * streaming.
+ */
void media_entity_pipeline_stop(struct media_entity *entity);
+/**
+ * media_devnode_create() - creates and initializes a device node interface
+ *
+ * @mdev: pointer to struct &media_device
+ * @type: type of the interface, as given by MEDIA_INTF_T_* macros
+ * as defined in the uapi/media/media.h header.
+ * @flags: Interface flags as defined in uapi/media/media.h.
+ * @major: Device node major number.
+ * @minor: Device node minor number.
+ *
+ * Return: if succeeded, returns a pointer to the newly allocated
+ * &media_intf_devnode pointer.
+ */
+struct media_intf_devnode *
+__must_check media_devnode_create(struct media_device *mdev,
+ u32 type, u32 flags,
+ u32 major, u32 minor);
+/**
+ * media_devnode_remove() - removes a device node interface
+ *
+ * @devnode: pointer to &media_intf_devnode to be freed.
+ *
+ * When a device node interface is removed, all links to it are automatically
+ * removed.
+ */
+void media_devnode_remove(struct media_intf_devnode *devnode);
+struct media_link *
+
+/**
+ * media_create_intf_link() - creates a link between an entity and an interface
+ *
+ * @entity: pointer to %media_entity
+ * @intf: pointer to %media_interface
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ *
+ *
+ * Valid values for flags:
+ * The %MEDIA_LNK_FL_ENABLED flag indicates that the interface is connected to
+ * the entity hardware. That's the default value for interfaces. An
+ * interface may be disabled if the hardware is busy due to the usage
+ * of some other interface that it is currently controlling the hardware.
+ * A typical example is an hybrid TV device that handle only one type of
+ * stream on a given time. So, when the digital TV is streaming,
+ * the V4L2 interfaces won't be enabled, as such device is not able to
+ * also stream analog TV or radio.
+ *
+ * Note:
+ *
+ * Before calling this function, media_devnode_create() should be called for
+ * the interface and media_device_register_entity() should be called for the
+ * interface that will be part of the link.
+ */
+__must_check media_create_intf_link(struct media_entity *entity,
+ struct media_interface *intf,
+ u32 flags);
+/**
+ * __media_remove_intf_link() - remove a single interface link
+ *
+ * @link: pointer to &media_link.
+ *
+ * Note: this is an unlocked version of media_remove_intf_link()
+ */
+void __media_remove_intf_link(struct media_link *link);
+
+/**
+ * media_remove_intf_link() - remove a single interface link
+ *
+ * @link: pointer to &media_link.
+ *
+ * Note: prefer to use this one, instead of __media_remove_intf_link()
+ */
+void media_remove_intf_link(struct media_link *link);
+
+/**
+ * __media_remove_intf_links() - remove all links associated with an interface
+ *
+ * @intf: pointer to &media_interface
+ *
+ * Note: this is an unlocked version of media_remove_intf_links().
+ */
+void __media_remove_intf_links(struct media_interface *intf);
+
+/**
+ * media_remove_intf_links() - remove all links associated with an interface
+ *
+ * @intf: pointer to &media_interface
+ *
+ * Notes:
+ *
+ * this is called automatically when an entity is unregistered via
+ * media_device_register_entity() and by media_devnode_remove().
+ *
+ * Prefer to use this one, instead of __media_remove_intf_links().
+ */
+void media_remove_intf_links(struct media_interface *intf);
+
#define media_entity_call(entity, operation, args...) \
(((entity)->ops && (entity)->ops->operation) ? \
(entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 486b6a54363b..e5321fda5489 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -21,6 +21,14 @@
#include <linux/videodev2.h>
+/* Tuner PADs */
+/* FIXME: is this the right place for it? */
+enum tuner_pad_index {
+ TUNER_PAD_RF_INPUT,
+ TUNER_PAD_IF_OUTPUT,
+ TUNER_NUM_PADS
+};
+
#define ADDR_UNSET (255)
#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index acbcd2f5fe7f..eeabf20e87a6 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -86,6 +86,7 @@ struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
+ struct media_intf_devnode *intf_devnode;
#endif
/* device ops */
const struct v4l2_file_operations *fops;
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
index 84b20835b736..0dc0a51da38f 100644
--- a/include/net/inet_ecn.h
+++ b/include/net/inet_ecn.h
@@ -111,11 +111,24 @@ static inline void ipv4_copy_dscp(unsigned int dscp, struct iphdr *inner)
struct ipv6hdr;
-static inline int IP6_ECN_set_ce(struct ipv6hdr *iph)
+/* Note:
+ * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE,
+ * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE
+ * In IPv6 case, no checksum compensates the change in IPv6 header,
+ * so we have to update skb->csum.
+ */
+static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph)
{
+ __be32 from, to;
+
if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
return 0;
- *(__be32*)iph |= htonl(INET_ECN_CE << 20);
+
+ from = *(__be32 *)iph;
+ to = from | htonl(INET_ECN_CE << 20);
+ *(__be32 *)iph = to;
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_add(csum_sub(skb->csum, from), to);
return 1;
}
@@ -142,7 +155,7 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb)
case cpu_to_be16(ETH_P_IPV6):
if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
skb_tail_pointer(skb))
- return IP6_ECN_set_ce(ipv6_hdr(skb));
+ return IP6_ECN_set_ce(skb, ipv6_hdr(skb));
break;
}
diff --git a/include/net/sock.h b/include/net/sock.h
index e830c1006935..b9e7b3d863a0 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -71,22 +71,6 @@
#include <net/tcp_states.h>
#include <linux/net_tstamp.h>
-struct cgroup;
-struct cgroup_subsys;
-#ifdef CONFIG_NET
-int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
-void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg);
-#else
-static inline
-int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
-{
- return 0;
-}
-static inline
-void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
-{
-}
-#endif
/*
* This structure really needs to be cleaned up.
* Most of it is for TCP, and not used by any of
@@ -245,7 +229,6 @@ struct sock_common {
/* public: */
};
-struct cg_proto;
/**
* struct sock - network layer representation of sockets
* @__sk_common: shared layout with inet_timewait_sock
@@ -310,7 +293,7 @@ struct cg_proto;
* @sk_security: used by security modules
* @sk_mark: generic packet mark
* @sk_cgrp_data: cgroup data for this cgroup
- * @sk_cgrp: this socket's cgroup-specific proto data
+ * @sk_memcg: this socket's memory cgroup association
* @sk_write_pending: a write to stream socket waits to start
* @sk_state_change: callback to indicate change in the state of the sock
* @sk_data_ready: callback to indicate there is data to be processed
@@ -446,7 +429,7 @@ struct sock {
void *sk_security;
#endif
struct sock_cgroup_data sk_cgrp_data;
- struct cg_proto *sk_cgrp;
+ struct mem_cgroup *sk_memcg;
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk);
void (*sk_write_space)(struct sock *sk);
@@ -1096,23 +1079,6 @@ static inline void sk_refcnt_debug_release(const struct sock *sk)
#define sk_refcnt_debug_release(sk) do { } while (0)
#endif /* SOCK_REFCNT_DEBUG */
-#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_NET)
-extern struct static_key memcg_socket_limit_enabled;
-static inline struct cg_proto *parent_cg_proto(struct proto *proto,
- struct cg_proto *cg_proto)
-{
- return proto->proto_cgroup(parent_mem_cgroup(cg_proto->memcg));
-}
-#define mem_cgroup_sockets_enabled static_key_false(&memcg_socket_limit_enabled)
-#else
-#define mem_cgroup_sockets_enabled 0
-static inline struct cg_proto *parent_cg_proto(struct proto *proto,
- struct cg_proto *cg_proto)
-{
- return NULL;
-}
-#endif
-
static inline bool sk_stream_memory_free(const struct sock *sk)
{
if (sk->sk_wmem_queued >= sk->sk_sndbuf)
@@ -1139,8 +1105,9 @@ static inline bool sk_under_memory_pressure(const struct sock *sk)
if (!sk->sk_prot->memory_pressure)
return false;
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- return !!sk->sk_cgrp->memory_pressure;
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
+ mem_cgroup_under_socket_pressure(sk->sk_memcg))
+ return true;
return !!*sk->sk_prot->memory_pressure;
}
@@ -1154,15 +1121,6 @@ static inline void sk_leave_memory_pressure(struct sock *sk)
if (*memory_pressure)
*memory_pressure = 0;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct cg_proto *cg_proto = sk->sk_cgrp;
- struct proto *prot = sk->sk_prot;
-
- for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto))
- cg_proto->memory_pressure = 0;
- }
-
}
static inline void sk_enter_memory_pressure(struct sock *sk)
@@ -1170,116 +1128,46 @@ static inline void sk_enter_memory_pressure(struct sock *sk)
if (!sk->sk_prot->enter_memory_pressure)
return;
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct cg_proto *cg_proto = sk->sk_cgrp;
- struct proto *prot = sk->sk_prot;
-
- for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto))
- cg_proto->memory_pressure = 1;
- }
-
sk->sk_prot->enter_memory_pressure(sk);
}
static inline long sk_prot_mem_limits(const struct sock *sk, int index)
{
- long *prot = sk->sk_prot->sysctl_mem;
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- prot = sk->sk_cgrp->sysctl_mem;
- return prot[index];
-}
-
-static inline void memcg_memory_allocated_add(struct cg_proto *prot,
- unsigned long amt,
- int *parent_status)
-{
- page_counter_charge(&prot->memory_allocated, amt);
-
- if (page_counter_read(&prot->memory_allocated) >
- prot->memory_allocated.limit)
- *parent_status = OVER_LIMIT;
-}
-
-static inline void memcg_memory_allocated_sub(struct cg_proto *prot,
- unsigned long amt)
-{
- page_counter_uncharge(&prot->memory_allocated, amt);
+ return sk->sk_prot->sysctl_mem[index];
}
static inline long
sk_memory_allocated(const struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- return page_counter_read(&sk->sk_cgrp->memory_allocated);
-
- return atomic_long_read(prot->memory_allocated);
+ return atomic_long_read(sk->sk_prot->memory_allocated);
}
static inline long
-sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status)
+sk_memory_allocated_add(struct sock *sk, int amt)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- memcg_memory_allocated_add(sk->sk_cgrp, amt, parent_status);
- /* update the root cgroup regardless */
- atomic_long_add_return(amt, prot->memory_allocated);
- return page_counter_read(&sk->sk_cgrp->memory_allocated);
- }
-
- return atomic_long_add_return(amt, prot->memory_allocated);
+ return atomic_long_add_return(amt, sk->sk_prot->memory_allocated);
}
static inline void
sk_memory_allocated_sub(struct sock *sk, int amt)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- memcg_memory_allocated_sub(sk->sk_cgrp, amt);
-
- atomic_long_sub(amt, prot->memory_allocated);
+ atomic_long_sub(amt, sk->sk_prot->memory_allocated);
}
static inline void sk_sockets_allocated_dec(struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct cg_proto *cg_proto = sk->sk_cgrp;
-
- for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto))
- percpu_counter_dec(&cg_proto->sockets_allocated);
- }
-
- percpu_counter_dec(prot->sockets_allocated);
+ percpu_counter_dec(sk->sk_prot->sockets_allocated);
}
static inline void sk_sockets_allocated_inc(struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct cg_proto *cg_proto = sk->sk_cgrp;
-
- for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto))
- percpu_counter_inc(&cg_proto->sockets_allocated);
- }
-
- percpu_counter_inc(prot->sockets_allocated);
+ percpu_counter_inc(sk->sk_prot->sockets_allocated);
}
static inline int
sk_sockets_allocated_read_positive(struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- return percpu_counter_read_positive(&sk->sk_cgrp->sockets_allocated);
-
- return percpu_counter_read_positive(prot->sockets_allocated);
+ return percpu_counter_read_positive(sk->sk_prot->sockets_allocated);
}
static inline int
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a80255f4ca33..8ea19977ea53 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -289,8 +289,9 @@ extern int tcp_memory_pressure;
/* optimized version of sk_under_memory_pressure() for TCP sockets */
static inline bool tcp_under_memory_pressure(const struct sock *sk)
{
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- return !!sk->sk_cgrp->memory_pressure;
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
+ mem_cgroup_under_socket_pressure(sk->sk_memcg))
+ return true;
return tcp_memory_pressure;
}
diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h
index 05b94d9453de..01ff7c6efada 100644
--- a/include/net/tcp_memcontrol.h
+++ b/include/net/tcp_memcontrol.h
@@ -1,7 +1,9 @@
#ifndef _TCP_MEMCG_H
#define _TCP_MEMCG_H
-struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
+struct cgroup_subsys;
+struct mem_cgroup;
+
int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
void tcp_destroy_cgroup(struct mem_cgroup *memcg);
#endif /* _TCP_MEMCG_H */
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
index 0d2607d12387..42a84ef42683 100644
--- a/include/scsi/sas.h
+++ b/include/scsi/sas.h
@@ -344,6 +344,43 @@ struct ssp_response_iu {
u8 sense_data[0];
} __attribute__ ((packed));
+struct ssp_command_iu {
+ u8 lun[8];
+ u8 _r_a;
+
+ union {
+ struct {
+ u8 attr:3;
+ u8 prio:4;
+ u8 efb:1;
+ };
+ u8 efb_prio_attr;
+ };
+
+ u8 _r_b;
+
+ u8 _r_c:2;
+ u8 add_cdb_len:6;
+
+ u8 cdb[16];
+ u8 add_cdb[0];
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+ __be32 requested_offset;
+ __be32 write_data_len;
+ __be32 _r_a;
+} __attribute__ ((packed));
+
+struct ssp_tmf_iu {
+ u8 lun[8];
+ u16 _r_a;
+ u8 tmf;
+ u8 _r_b;
+ __be16 tag;
+ u8 _r_c[14];
+} __attribute__ ((packed));
+
/* ---------- SMP ---------- */
struct report_general_resp {
@@ -538,6 +575,43 @@ struct ssp_response_iu {
u8 sense_data[0];
} __attribute__ ((packed));
+struct ssp_command_iu {
+ u8 lun[8];
+ u8 _r_a;
+
+ union {
+ struct {
+ u8 efb:1;
+ u8 prio:4;
+ u8 attr:3;
+ };
+ u8 efb_prio_attr;
+ };
+
+ u8 _r_b;
+
+ u8 add_cdb_len:6;
+ u8 _r_c:2;
+
+ u8 cdb[16];
+ u8 add_cdb[0];
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+ __be32 requested_offset;
+ __be32 write_data_len;
+ __be32 _r_a;
+} __attribute__ ((packed));
+
+struct ssp_tmf_iu {
+ u8 lun[8];
+ u16 _r_a;
+ u8 tmf;
+ u8 _r_b;
+ __be16 tag;
+ u8 _r_c[14];
+} __attribute__ ((packed));
+
/* ---------- SMP ---------- */
struct report_general_resp {
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index f8170e90b49d..56710e03101c 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -12,8 +12,6 @@ extern size_t __scsi_format_command(char *, size_t,
const unsigned char *, size_t);
extern void scsi_show_extd_sense(const struct scsi_device *, const char *,
unsigned char, unsigned char);
-extern void scsi_show_sense_hdr(const struct scsi_device *, const char *,
- const struct scsi_sense_hdr *);
extern void scsi_print_sense_hdr(const struct scsi_device *, const char *,
const struct scsi_sense_hdr *);
extern void scsi_print_sense(const struct scsi_cmnd *);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index fe89d7cd67b9..f63a16760ae9 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -109,6 +109,7 @@ struct scsi_device {
char type;
char scsi_level;
char inq_periph_qual; /* PQ from INQUIRY data */
+ struct mutex inquiry_mutex;
unsigned char inquiry_len; /* valid bytes in 'inquiry' */
unsigned char * inquiry; /* INQUIRY response data */
const char * vendor; /* [back_compat] point into 'inquiry' ... */
@@ -117,9 +118,9 @@ struct scsi_device {
#define SCSI_VPD_PG_LEN 255
int vpd_pg83_len;
- unsigned char *vpd_pg83;
+ unsigned char __rcu *vpd_pg83;
int vpd_pg80_len;
- unsigned char *vpd_pg80;
+ unsigned char __rcu *vpd_pg80;
unsigned char current_tag; /* current tag */
struct scsi_target *sdev_target; /* used only for single_lun */
@@ -414,6 +415,8 @@ static inline int scsi_execute_req(struct scsi_device *sdev,
}
extern void sdev_disable_disk_events(struct scsi_device *sdev);
extern void sdev_enable_disk_events(struct scsi_device *sdev);
+extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);
+extern int scsi_vpd_tpg_id(struct scsi_device *, int *);
#ifdef CONFIG_PM
extern int scsi_autopm_get_device(struct scsi_device *);
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 0bd71e2702e3..13c0b2ba1b6c 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -10,6 +10,15 @@ struct scsi_transport_template;
struct sas_rphy;
struct request;
+#if !IS_ENABLED(CONFIG_SCSI_SAS_ATTRS)
+static inline int is_sas_attached(struct scsi_device *sdev)
+{
+ return 0;
+}
+#else
+extern int is_sas_attached(struct scsi_device *sdev);
+#endif
+
static inline int sas_protocol_ata(enum sas_protocol proto)
{
return ((proto & SAS_PROTOCOL_SATA) ||
@@ -180,6 +189,7 @@ extern int sas_phy_add(struct sas_phy *);
extern void sas_phy_delete(struct sas_phy *);
extern int scsi_is_sas_phy(const struct device *);
+u64 sas_get_address(struct scsi_device *);
unsigned int sas_tlr_supported(struct scsi_device *);
unsigned int sas_is_tlr_enabled(struct scsi_device *);
void sas_disable_tlr(struct scsi_device *);
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
index c07d74aa39bf..3fb357193f09 100644
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -72,10 +72,12 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
+ RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
RPI_FIRMWARE_SET_TURBO = 0x00038009,
+ RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
/* Dispmanx TAGS */
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
diff --git a/arch/powerpc/include/asm/immap_qe.h b/include/soc/fsl/qe/immap_qe.h
index bedbff891423..bedbff891423 100644
--- a/arch/powerpc/include/asm/immap_qe.h
+++ b/include/soc/fsl/qe/immap_qe.h
diff --git a/arch/powerpc/include/asm/qe.h b/include/soc/fsl/qe/qe.h
index 32b9bfa0c9bd..c7fa36c335c9 100644
--- a/arch/powerpc/include/asm/qe.h
+++ b/include/soc/fsl/qe/qe.h
@@ -16,11 +16,16 @@
#define _ASM_POWERPC_QE_H
#ifdef __KERNEL__
+#include <linux/compiler.h>
+#include <linux/genalloc.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <asm/cpm.h>
-#include <asm/immap_qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/types.h>
#define QE_NUM_OF_SNUM 256 /* There are 256 serial number in QE */
#define QE_NUM_OF_BRGS 16
@@ -92,6 +97,51 @@ extern void qe_reset(void);
static inline void qe_reset(void) {}
#endif
+int cpm_muram_init(void);
+
+#if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE)
+unsigned long cpm_muram_alloc(unsigned long size, unsigned long align);
+int cpm_muram_free(unsigned long offset);
+unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size);
+unsigned long cpm_muram_alloc_common(unsigned long size, genpool_algo_t algo,
+ void *data);
+void __iomem *cpm_muram_addr(unsigned long offset);
+unsigned long cpm_muram_offset(void __iomem *addr);
+dma_addr_t cpm_muram_dma(void __iomem *addr);
+#else
+static inline unsigned long cpm_muram_alloc(unsigned long size,
+ unsigned long align)
+{
+ return -ENOSYS;
+}
+
+static inline int cpm_muram_free(unsigned long offset)
+{
+ return -ENOSYS;
+}
+
+static inline unsigned long cpm_muram_alloc_fixed(unsigned long offset,
+ unsigned long size)
+{
+ return -ENOSYS;
+}
+
+static inline void __iomem *cpm_muram_addr(unsigned long offset)
+{
+ return NULL;
+}
+
+static inline unsigned long cpm_muram_offset(void __iomem *addr)
+{
+ return -ENOSYS;
+}
+
+static inline dma_addr_t cpm_muram_dma(void __iomem *addr)
+{
+ return 0;
+}
+#endif /* defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) */
+
/* QE PIO */
#define QE_PIO_PINS 32
diff --git a/arch/powerpc/include/asm/qe_ic.h b/include/soc/fsl/qe/qe_ic.h
index 1e155ca6d33c..1e155ca6d33c 100644
--- a/arch/powerpc/include/asm/qe_ic.h
+++ b/include/soc/fsl/qe/qe_ic.h
diff --git a/arch/powerpc/include/asm/ucc.h b/include/soc/fsl/qe/ucc.h
index 6927ac26516e..894f14cbb044 100644
--- a/arch/powerpc/include/asm/ucc.h
+++ b/include/soc/fsl/qe/ucc.h
@@ -15,8 +15,8 @@
#ifndef __UCC_H__
#define __UCC_H__
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
#define STATISTICS
diff --git a/arch/powerpc/include/asm/ucc_fast.h b/include/soc/fsl/qe/ucc_fast.h
index 72ea9bab07df..df8ea7958c63 100644
--- a/arch/powerpc/include/asm/ucc_fast.h
+++ b/include/soc/fsl/qe/ucc_fast.h
@@ -16,10 +16,10 @@
#include <linux/kernel.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
-#include <asm/ucc.h>
+#include <soc/fsl/qe/ucc.h>
/* Receive BD's status */
#define R_E 0x80000000 /* buffer empty */
diff --git a/arch/powerpc/include/asm/ucc_slow.h b/include/soc/fsl/qe/ucc_slow.h
index 233ef5fe5fde..6c0573a0825c 100644
--- a/arch/powerpc/include/asm/ucc_slow.h
+++ b/include/soc/fsl/qe/ucc_slow.h
@@ -17,10 +17,10 @@
#include <linux/kernel.h>
-#include <asm/immap_qe.h>
-#include <asm/qe.h>
+#include <soc/fsl/qe/immap_qe.h>
+#include <soc/fsl/qe/qe.h>
-#include <asm/ucc.h>
+#include <soc/fsl/qe/ucc.h>
/* transmit BD's status */
#define T_R 0x80000000 /* ready bit */
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 74bc85473b58..15aa5f07c955 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -417,11 +417,13 @@
#define AC97_RATES_MIC_ADC 4
#define AC97_RATES_SPDIF 5
+#define AC97_NUM_GPIOS 16
/*
*
*/
struct snd_ac97;
+struct snd_ac97_gpio_priv;
struct snd_pcm_chmap;
struct snd_ac97_build_ops {
@@ -529,6 +531,7 @@ struct snd_ac97 {
struct delayed_work power_work;
#endif
struct device dev;
+ struct snd_ac97_gpio_priv *gpio_priv;
struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */
};
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index fa1d05512c09..c0abcdc11470 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -152,13 +152,18 @@ struct snd_compr {
unsigned int direction;
struct mutex lock;
int device;
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+ char id[64];
+ struct snd_info_entry *proc_root;
+ struct snd_info_entry *proc_info_entry;
+#endif
};
/* compress device register APIs */
int snd_compress_register(struct snd_compr *device);
int snd_compress_deregister(struct snd_compr *device);
int snd_compress_new(struct snd_card *card, int device,
- int type, struct snd_compr *compr);
+ int type, const char *id, struct snd_compr *compr);
/* dsp driver callback apis
* For playback: driver should call snd_compress_fragment_elapsed() to let the
diff --git a/include/sound/core.h b/include/sound/core.h
index cdfecafff0f4..31079ea5e484 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -99,6 +99,7 @@ struct snd_card {
char driver[16]; /* driver name */
char shortname[32]; /* short name of this soundcard */
char longname[80]; /* name of this soundcard */
+ char irq_descr[32]; /* Interrupt description */
char mixername[80]; /* mixer name */
char components[128]; /* card components delimited with
space */
diff --git a/include/sound/da7218.h b/include/sound/da7218.h
new file mode 100644
index 000000000000..0dbb818ac116
--- /dev/null
+++ b/include/sound/da7218.h
@@ -0,0 +1,109 @@
+/*
+ * da7218.h - DA7218 ASoC Codec Driver Platform Data
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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 _DA7218_PDATA_H
+#define _DA7218_PDATA_H
+
+/* Mic Bias */
+enum da7218_micbias_voltage {
+ DA7218_MICBIAS_1_2V = -1,
+ DA7218_MICBIAS_1_6V,
+ DA7218_MICBIAS_1_8V,
+ DA7218_MICBIAS_2_0V,
+ DA7218_MICBIAS_2_2V,
+ DA7218_MICBIAS_2_4V,
+ DA7218_MICBIAS_2_6V,
+ DA7218_MICBIAS_2_8V,
+ DA7218_MICBIAS_3_0V,
+};
+
+enum da7218_mic_amp_in_sel {
+ DA7218_MIC_AMP_IN_SEL_DIFF = 0,
+ DA7218_MIC_AMP_IN_SEL_SE_P,
+ DA7218_MIC_AMP_IN_SEL_SE_N,
+};
+
+/* DMIC */
+enum da7218_dmic_data_sel {
+ DA7218_DMIC_DATA_LRISE_RFALL = 0,
+ DA7218_DMIC_DATA_LFALL_RRISE,
+};
+
+enum da7218_dmic_samplephase {
+ DA7218_DMIC_SAMPLE_ON_CLKEDGE = 0,
+ DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE,
+};
+
+enum da7218_dmic_clk_rate {
+ DA7218_DMIC_CLK_3_0MHZ = 0,
+ DA7218_DMIC_CLK_1_5MHZ,
+};
+
+/* Headphone Detect */
+enum da7218_hpldet_jack_rate {
+ DA7218_HPLDET_JACK_RATE_5US = 0,
+ DA7218_HPLDET_JACK_RATE_10US,
+ DA7218_HPLDET_JACK_RATE_20US,
+ DA7218_HPLDET_JACK_RATE_40US,
+ DA7218_HPLDET_JACK_RATE_80US,
+ DA7218_HPLDET_JACK_RATE_160US,
+ DA7218_HPLDET_JACK_RATE_320US,
+ DA7218_HPLDET_JACK_RATE_640US,
+};
+
+enum da7218_hpldet_jack_debounce {
+ DA7218_HPLDET_JACK_DEBOUNCE_OFF = 0,
+ DA7218_HPLDET_JACK_DEBOUNCE_2,
+ DA7218_HPLDET_JACK_DEBOUNCE_3,
+ DA7218_HPLDET_JACK_DEBOUNCE_4,
+};
+
+enum da7218_hpldet_jack_thr {
+ DA7218_HPLDET_JACK_THR_84PCT = 0,
+ DA7218_HPLDET_JACK_THR_88PCT,
+ DA7218_HPLDET_JACK_THR_92PCT,
+ DA7218_HPLDET_JACK_THR_96PCT,
+};
+
+struct da7218_hpldet_pdata {
+ enum da7218_hpldet_jack_rate jack_rate;
+ enum da7218_hpldet_jack_debounce jack_debounce;
+ enum da7218_hpldet_jack_thr jack_thr;
+ bool comp_inv;
+ bool hyst;
+ bool discharge;
+};
+
+struct da7218_pdata {
+ /* Mic */
+ enum da7218_micbias_voltage micbias1_lvl;
+ enum da7218_micbias_voltage micbias2_lvl;
+ enum da7218_mic_amp_in_sel mic1_amp_in_sel;
+ enum da7218_mic_amp_in_sel mic2_amp_in_sel;
+
+ /* DMIC */
+ enum da7218_dmic_data_sel dmic1_data_sel;
+ enum da7218_dmic_data_sel dmic2_data_sel;
+ enum da7218_dmic_samplephase dmic1_samplephase;
+ enum da7218_dmic_samplephase dmic2_samplephase;
+ enum da7218_dmic_clk_rate dmic1_clk_rate;
+ enum da7218_dmic_clk_rate dmic2_clk_rate;
+
+ /* HP Diff Supply - DA7217 only */
+ bool hp_diff_single_supply;
+
+ /* HP Detect - DA7218 only */
+ struct da7218_hpldet_pdata *hpldet_pdata;
+};
+
+#endif /* _DA7218_PDATA_H */
diff --git a/include/sound/da7219.h b/include/sound/da7219.h
index 3f39e135312d..02876acdc840 100644
--- a/include/sound/da7219.h
+++ b/include/sound/da7219.h
@@ -14,17 +14,10 @@
#ifndef __DA7219_PDATA_H
#define __DA7219_PDATA_H
-/* LDO */
-enum da7219_ldo_lvl_sel {
- DA7219_LDO_LVL_SEL_1_05V = 0,
- DA7219_LDO_LVL_SEL_1_10V,
- DA7219_LDO_LVL_SEL_1_20V,
- DA7219_LDO_LVL_SEL_1_40V,
-};
-
/* Mic Bias */
enum da7219_micbias_voltage {
- DA7219_MICBIAS_1_8V = 1,
+ DA7219_MICBIAS_1_6V = 0,
+ DA7219_MICBIAS_1_8V,
DA7219_MICBIAS_2_0V,
DA7219_MICBIAS_2_2V,
DA7219_MICBIAS_2_4V,
@@ -41,9 +34,6 @@ enum da7219_mic_amp_in_sel {
struct da7219_aad_pdata;
struct da7219_pdata {
- /* Internal LDO */
- enum da7219_ldo_lvl_sel ldo_lvl_sel;
-
/* Mic */
enum da7219_micbias_voltage micbias_lvl;
enum da7219_mic_amp_in_sel mic_amp_in_sel;
diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h
index 8966ba7c9629..5681855396c4 100644
--- a/include/sound/designware_i2s.h
+++ b/include/sound/designware_i2s.h
@@ -45,6 +45,12 @@ struct i2s_platform_data {
u32 snd_fmts;
u32 snd_rates;
+ #define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0)
+ #define DW_I2S_QUIRK_COMP_PARAM1 (1 << 1)
+ unsigned int quirks;
+ unsigned int i2s_reg_comp1;
+ unsigned int i2s_reg_comp2;
+
void *play_dma_data;
void *capture_dma_data;
bool (*filter)(struct dma_chan *chan, void *slave);
diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
index 930b41e5acf4..fa341fcb5829 100644
--- a/include/sound/hda_i915.h
+++ b/include/sound/hda_i915.h
@@ -10,6 +10,9 @@
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
int snd_hdac_get_display_clk(struct hdac_bus *bus);
+int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate);
+int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+ bool *audio_enabled, char *buffer, int max_bytes);
int snd_hdac_i915_init(struct hdac_bus *bus);
int snd_hdac_i915_exit(struct hdac_bus *bus);
int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *);
@@ -26,6 +29,17 @@ static inline int snd_hdac_get_display_clk(struct hdac_bus *bus)
{
return 0;
}
+static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid,
+ int rate)
+{
+ return 0;
+}
+static inline int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+ bool *audio_enabled, char *buffer,
+ int max_bytes)
+{
+ return -ENODEV;
+}
static inline int snd_hdac_i915_init(struct hdac_bus *bus)
{
return -ENODEV;
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h
index 94dc6a9772e0..ff1aecf325e8 100644
--- a/include/sound/hda_register.h
+++ b/include/sound/hda_register.h
@@ -233,6 +233,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_MLCTL_SPA (1<<16)
#define AZX_MLCTL_CPA 23
+
+/* registers for DMA Resume Capability Structure */
+#define AZX_DRSM_CAP_ID 0x5
+#define AZX_REG_DRSM_CTL 0x4
+/* Base used to calculate the iterating register offset */
+#define AZX_DRSM_BASE 0x08
+/* Interval used to calculate the iterating register offset */
+#define AZX_DRSM_INTERVAL 0x08
+
/*
* helpers to read the stream position
*/
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index a4cadd9c297a..07fa59237feb 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -12,6 +12,7 @@
* @spbcap: SPIB capabilities pointer
* @mlcap: MultiLink capabilities pointer
* @gtscap: gts capabilities pointer
+ * @drsmcap: dma resume capabilities pointer
* @hlink_list: link list of HDA links
*/
struct hdac_ext_bus {
@@ -23,6 +24,7 @@ struct hdac_ext_bus {
void __iomem *spbcap;
void __iomem *mlcap;
void __iomem *gtscap;
+ void __iomem *drsmcap;
struct list_head hlink_list;
};
@@ -72,6 +74,9 @@ enum hdac_ext_stream_type {
* @pplc_addr: processing pipe link stream pointer
* @spib_addr: software position in buffers stream pointer
* @fifo_addr: software position Max fifos stream pointer
+ * @dpibr_addr: DMA position in buffer resume pointer
+ * @dpib: DMA position in buffer
+ * @lpib: Linear position in buffer
* @decoupled: stream host and link is decoupled
* @link_locked: link is locked
* @link_prepared: link is prepared
@@ -86,6 +91,10 @@ struct hdac_ext_stream {
void __iomem *spib_addr;
void __iomem *fifo_addr;
+ void __iomem *dpibr_addr;
+
+ u32 dpib;
+ u32 lpib;
bool decoupled:1;
bool link_locked:1;
bool link_prepared;
@@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *stream);
+void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+ bool enable, int index);
+int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+ struct hdac_ext_stream *stream, u32 value);
+int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);
void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
@@ -133,6 +147,7 @@ struct hdac_ext_link {
int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
int stream);
@@ -186,9 +201,15 @@ struct hdac_ext_device {
/* codec ops */
struct hdac_ext_codec_ops ops;
+ struct snd_card *card;
+ void *scodec;
void *private_data;
};
+struct hdac_ext_dma_params {
+ u32 format;
+ u8 stream_tag;
+};
#define to_ehdac_device(dev) (container_of((dev), \
struct hdac_ext_device, hdac))
/*
diff --git a/include/sound/i2c.h b/include/sound/i2c.h
index d125ff8c85e8..835254de2039 100644
--- a/include/sound/i2c.h
+++ b/include/sound/i2c.h
@@ -66,7 +66,7 @@ struct snd_i2c_bus {
struct snd_i2c_bit_ops *bit;
void *ops;
} hw_ops; /* lowlevel operations */
- struct snd_i2c_ops *ops; /* midlevel operations */
+ const struct snd_i2c_ops *ops; /* midlevel operations */
unsigned long private_value;
void *private_data;
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index f6cbef78db62..fdabbb4ddba9 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -130,7 +130,7 @@ struct snd_rawmidi {
int ossreg;
#endif
- struct snd_rawmidi_global_ops *ops;
+ const struct snd_rawmidi_global_ops *ops;
struct snd_rawmidi_str streams[2];
diff --git a/include/sound/rt5659.h b/include/sound/rt5659.h
new file mode 100644
index 000000000000..656c4d58948d
--- /dev/null
+++ b/include/sound/rt5659.h
@@ -0,0 +1,49 @@
+/*
+ * linux/sound/rt5659.h -- Platform data for RT5659
+ *
+ * Copyright 2013 Realtek Microelectronics
+ *
+ * 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 __LINUX_SND_RT5659_H
+#define __LINUX_SND_RT5659_H
+
+enum rt5659_dmic1_data_pin {
+ RT5659_DMIC1_NULL,
+ RT5659_DMIC1_DATA_IN2N,
+ RT5659_DMIC1_DATA_GPIO5,
+ RT5659_DMIC1_DATA_GPIO9,
+ RT5659_DMIC1_DATA_GPIO11,
+};
+
+enum rt5659_dmic2_data_pin {
+ RT5659_DMIC2_NULL,
+ RT5659_DMIC2_DATA_IN2P,
+ RT5659_DMIC2_DATA_GPIO6,
+ RT5659_DMIC2_DATA_GPIO10,
+ RT5659_DMIC2_DATA_GPIO12,
+};
+
+enum rt5659_jd_src {
+ RT5659_JD_NULL,
+ RT5659_JD3,
+};
+
+struct rt5659_platform_data {
+ bool in1_diff;
+ bool in3_diff;
+ bool in4_diff;
+
+ int ldo1_en; /* GPIO for LDO1_EN */
+ int reset; /* GPIO for RESET */
+
+ enum rt5659_dmic1_data_pin dmic1_data_pin;
+ enum rt5659_dmic2_data_pin dmic2_data_pin;
+ enum rt5659_jd_src jd_src;
+};
+
+#endif
+
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 212eaaf172ed..964b7de1a1cc 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -222,6 +222,7 @@ struct snd_soc_dai_driver {
const char *name;
unsigned int id;
unsigned int base;
+ struct snd_soc_dobj dobj;
/* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 95a937eafb79..97069466c38d 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -49,6 +49,9 @@ struct device;
#define SND_SOC_DAPM_SIGGEN(wname) \
{ .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM }
+#define SND_SOC_DAPM_SINK(wname) \
+{ .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
+ .num_kcontrols = 0, .reg = SND_SOC_NOPM }
#define SND_SOC_DAPM_INPUT(wname) \
{ .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM }
@@ -485,6 +488,7 @@ enum snd_soc_dapm_type {
snd_soc_dapm_aif_in, /* audio interface input */
snd_soc_dapm_aif_out, /* audio interface output */
snd_soc_dapm_siggen, /* signal generator */
+ snd_soc_dapm_sink,
snd_soc_dapm_dai_in, /* link to DAI structure */
snd_soc_dapm_dai_out,
snd_soc_dapm_dai_link, /* link between two DAI structures */
diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
index 086cd7ff6ddc..5b68e3f5aa85 100644
--- a/include/sound/soc-topology.h
+++ b/include/sound/soc-topology.h
@@ -92,8 +92,10 @@ struct snd_soc_tplg_kcontrol_ops {
/* Bytes ext operations, for TLV byte controls */
struct snd_soc_tplg_bytes_ext_ops {
u32 id;
- int (*get)(unsigned int __user *bytes, unsigned int size);
- int (*put)(const unsigned int __user *bytes, unsigned int size);
+ int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes,
+ unsigned int size);
+ int (*put)(struct snd_kcontrol *kcontrol,
+ const unsigned int __user *bytes, unsigned int size);
};
/*
diff --git a/include/sound/soc.h b/include/sound/soc.h
index fb955e69a78e..7afb72ceac56 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -110,6 +110,14 @@
.put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert, 0) }
+#define SOC_DOUBLE_STS(xname, reg, shift_left, shift_right, max, invert) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
+ max, invert, 0) }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, \
@@ -293,6 +301,9 @@
{.base = xbase, .num_regs = xregs, \
.mask = xmask }) }
+/*
+ * SND_SOC_BYTES_EXT is deprecated, please USE SND_SOC_BYTES_TLV instead
+ */
#define SND_SOC_BYTES_EXT(xname, xcount, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info_ext, \
@@ -787,6 +798,7 @@ struct snd_soc_component {
unsigned int registered_as_component:1;
struct list_head list;
+ struct list_head list_aux; /* for auxiliary component of the card */
struct snd_soc_dai_driver *dai_drv;
int num_dai;
@@ -830,6 +842,9 @@ struct snd_soc_component {
int (*probe)(struct snd_soc_component *);
void (*remove)(struct snd_soc_component *);
+ /* machine specific init */
+ int (*init)(struct snd_soc_component *component);
+
#ifdef CONFIG_DEBUG_FS
void (*init_debugfs)(struct snd_soc_component *component);
const char *debugfs_prefix;
@@ -1037,6 +1052,9 @@ struct snd_soc_dai_link {
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time:1;
+
+ struct list_head list; /* DAI link list of the soc card */
+ struct snd_soc_dobj dobj; /* For topology */
};
struct snd_soc_codec_conf {
@@ -1101,12 +1119,20 @@ struct snd_soc_card {
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);
+ int (*add_dai_link)(struct snd_soc_card *,
+ struct snd_soc_dai_link *link);
+ void (*remove_dai_link)(struct snd_soc_card *,
+ struct snd_soc_dai_link *link);
+
long pmdown_time;
/* CPU <--> Codec DAI links */
- struct snd_soc_dai_link *dai_link;
- int num_links;
- struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai_link *dai_link; /* predefined links only */
+ int num_links; /* predefined links only */
+ struct list_head dai_link_list; /* all links */
+ int num_dai_links;
+
+ struct list_head rtd_list;
int num_rtd;
/* optional codec specific configuration */
@@ -1119,8 +1145,7 @@ struct snd_soc_card {
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
- struct snd_soc_pcm_runtime *rtd_aux;
- int num_aux_rtd;
+ struct list_head aux_comp_list;
const struct snd_kcontrol_new *controls;
int num_controls;
@@ -1201,6 +1226,9 @@ struct snd_soc_pcm_runtime {
struct dentry *debugfs_dpcm_root;
struct dentry *debugfs_dpcm_state;
#endif
+
+ unsigned int num; /* 0-based and monotonic increasing */
+ struct list_head list; /* rtd list of the soc card */
};
/* mixer control */
@@ -1225,8 +1253,10 @@ struct soc_bytes_ext {
struct snd_soc_dobj dobj;
/* used for TLV byte control */
- int (*get)(unsigned int __user *bytes, unsigned int size);
- int (*put)(const unsigned int __user *bytes, unsigned int size);
+ int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes,
+ unsigned int size);
+ int (*put)(struct snd_kcontrol *kcontrol, const unsigned int __user *bytes,
+ unsigned int size);
};
/* multi register control */
@@ -1523,6 +1553,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths);
INIT_LIST_HEAD(&card->dapm_list);
+ INIT_LIST_HEAD(&card->aux_comp_list);
}
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
@@ -1644,6 +1675,14 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
struct device_node *of_node,
struct snd_soc_dai_link *dai_link);
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link);
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link);
+
+int snd_soc_register_dai(struct snd_soc_component *component,
+ struct snd_soc_dai_driver *dai_drv);
+
#include <sound/soc-dai.h>
#ifdef CONFIG_DEBUG_FS
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index aabf0aca0171..5d82816cc4e3 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -63,6 +63,8 @@
#define DA_UNMAP_GRANULARITY_DEFAULT 0
/* Default unmap_granularity_alignment */
#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
+/* Default unmap_zeroes_data */
+#define DA_UNMAP_ZEROES_DATA_DEFAULT 0
/* Default max_write_same_len, disabled by default */
#define DA_MAX_WRITE_SAME_LEN 0
/* Use a model alias based on the configfs backend device name */
@@ -526,6 +528,7 @@ struct se_cmd {
unsigned int t_prot_nents;
sense_reason_t pi_err;
sector_t bad_sector;
+ int cpuid;
};
struct se_ua {
@@ -674,6 +677,7 @@ struct se_dev_attrib {
int force_pr_aptpl;
int is_nonrot;
int emulate_rest_reord;
+ int unmap_zeroes_data;
u32 hw_block_size;
u32 block_size;
u32 hw_max_sectors;
@@ -864,8 +868,6 @@ struct se_portal_group {
* Negative values can be used by fabric drivers for internal use TPGs.
*/
int proto_id;
- /* Number of ACLed Initiator Nodes for this TPG */
- u32 num_node_acls;
/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
atomic_t tpg_pr_ref_count;
/* Spinlock for adding/removing ACLed Nodes */
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 7fb2557a760e..56653408f53b 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -117,7 +117,7 @@ void __transport_register_session(struct se_portal_group *,
struct se_node_acl *, struct se_session *, void *);
void transport_register_session(struct se_portal_group *,
struct se_node_acl *, struct se_session *, void *);
-void target_get_session(struct se_session *);
+int target_get_session(struct se_session *);
void target_put_session(struct se_session *);
ssize_t target_show_dynamic_sessions(struct se_portal_group *, char *);
void transport_free_session(struct se_session *);
@@ -140,7 +140,7 @@ int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
unsigned char *sense, u64 unpacked_lun,
void *fabric_tmr_ptr, unsigned char tm_type,
- gfp_t, unsigned int, int);
+ gfp_t, u64, int);
int transport_handle_cdb_direct(struct se_cmd *);
sense_reason_t transport_generic_new_cmd(struct se_cmd *);
@@ -169,10 +169,11 @@ void core_allocate_nexus_loss_ua(struct se_node_acl *acl);
struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
unsigned char *);
+bool target_tpg_has_node_acl(struct se_portal_group *tpg,
+ const char *);
struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
unsigned char *);
-int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
- unsigned char *, u32, int);
+int core_tpg_set_initiator_node_queue_depth(struct se_node_acl *, u32);
int core_tpg_set_initiator_node_tag(struct se_portal_group *,
struct se_node_acl *, const char *);
int core_tpg_register(struct se_wwn *, struct se_portal_group *, int);
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index b4473dab39d6..d866f21efbbf 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -45,7 +45,8 @@ struct btrfs_qgroup_operation;
{ BTRFS_TREE_LOG_OBJECTID, "TREE_LOG" }, \
{ BTRFS_QUOTA_TREE_OBJECTID, "QUOTA_TREE" }, \
{ BTRFS_TREE_RELOC_OBJECTID, "TREE_RELOC" }, \
- { BTRFS_UUID_TREE_OBJECTID, "UUID_RELOC" }, \
+ { BTRFS_UUID_TREE_OBJECTID, "UUID_TREE" }, \
+ { BTRFS_FREE_SPACE_TREE_OBJECTID, "FREE_SPACE_TREE" }, \
{ BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" })
#define show_root_type(obj) \
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 00b4a6308249..a1b488809f06 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -1265,6 +1265,44 @@ TRACE_EVENT(f2fs_destroy_extent_tree,
__entry->node_cnt)
);
+DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes,
+
+ TP_PROTO(struct super_block *sb, int type, int count),
+
+ TP_ARGS(sb, type, count),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(int, type)
+ __field(int, count)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = sb->s_dev;
+ __entry->type = type;
+ __entry->count = count;
+ ),
+
+ TP_printk("dev = (%d,%d), %s, dirty count = %d",
+ show_dev(__entry),
+ show_file_type(__entry->type),
+ __entry->count)
+);
+
+DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_enter,
+
+ TP_PROTO(struct super_block *sb, int type, int count),
+
+ TP_ARGS(sb, type, count)
+);
+
+DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_exit,
+
+ TP_PROTO(struct super_block *sb, int type, int count),
+
+ TP_ARGS(sb, type, count)
+);
+
#endif /* _TRACE_F2FS_H */
/* This part must be outside protection */
diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h
new file mode 100644
index 000000000000..0f803d2783e3
--- /dev/null
+++ b/include/trace/events/huge_memory.h
@@ -0,0 +1,137 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM huge_memory
+
+#if !defined(__HUGE_MEMORY_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HUGE_MEMORY_H
+
+#include <linux/tracepoint.h>
+
+#include <trace/events/gfpflags.h>
+
+#define SCAN_STATUS \
+ EM( SCAN_FAIL, "failed") \
+ EM( SCAN_SUCCEED, "succeeded") \
+ EM( SCAN_PMD_NULL, "pmd_null") \
+ EM( SCAN_EXCEED_NONE_PTE, "exceed_none_pte") \
+ EM( SCAN_PTE_NON_PRESENT, "pte_non_present") \
+ EM( SCAN_PAGE_RO, "no_writable_page") \
+ EM( SCAN_NO_REFERENCED_PAGE, "no_referenced_page") \
+ EM( SCAN_PAGE_NULL, "page_null") \
+ EM( SCAN_SCAN_ABORT, "scan_aborted") \
+ EM( SCAN_PAGE_COUNT, "not_suitable_page_count") \
+ EM( SCAN_PAGE_LRU, "page_not_in_lru") \
+ EM( SCAN_PAGE_LOCK, "page_locked") \
+ EM( SCAN_PAGE_ANON, "page_not_anon") \
+ EM( SCAN_PAGE_COMPOUND, "page_compound") \
+ EM( SCAN_ANY_PROCESS, "no_process_for_page") \
+ EM( SCAN_VMA_NULL, "vma_null") \
+ EM( SCAN_VMA_CHECK, "vma_check_failed") \
+ EM( SCAN_ADDRESS_RANGE, "not_suitable_address_range") \
+ EM( SCAN_SWAP_CACHE_PAGE, "page_swap_cache") \
+ EM( SCAN_DEL_PAGE_LRU, "could_not_delete_page_from_lru")\
+ EM( SCAN_ALLOC_HUGE_PAGE_FAIL, "alloc_huge_page_failed") \
+ EMe( SCAN_CGROUP_CHARGE_FAIL, "ccgroup_charge_failed")
+
+#undef EM
+#undef EMe
+#define EM(a, b) TRACE_DEFINE_ENUM(a);
+#define EMe(a, b) TRACE_DEFINE_ENUM(a);
+
+SCAN_STATUS
+
+#undef EM
+#undef EMe
+#define EM(a, b) {a, b},
+#define EMe(a, b) {a, b}
+
+TRACE_EVENT(mm_khugepaged_scan_pmd,
+
+ TP_PROTO(struct mm_struct *mm, unsigned long pfn, bool writable,
+ bool referenced, int none_or_zero, int status),
+
+ TP_ARGS(mm, pfn, writable, referenced, none_or_zero, status),
+
+ TP_STRUCT__entry(
+ __field(struct mm_struct *, mm)
+ __field(unsigned long, pfn)
+ __field(bool, writable)
+ __field(bool, referenced)
+ __field(int, none_or_zero)
+ __field(int, status)
+ ),
+
+ TP_fast_assign(
+ __entry->mm = mm;
+ __entry->pfn = pfn;
+ __entry->writable = writable;
+ __entry->referenced = referenced;
+ __entry->none_or_zero = none_or_zero;
+ __entry->status = status;
+ ),
+
+ TP_printk("mm=%p, scan_pfn=0x%lx, writable=%d, referenced=%d, none_or_zero=%d, status=%s",
+ __entry->mm,
+ __entry->pfn,
+ __entry->writable,
+ __entry->referenced,
+ __entry->none_or_zero,
+ __print_symbolic(__entry->status, SCAN_STATUS))
+);
+
+TRACE_EVENT(mm_collapse_huge_page,
+
+ TP_PROTO(struct mm_struct *mm, int isolated, int status),
+
+ TP_ARGS(mm, isolated, status),
+
+ TP_STRUCT__entry(
+ __field(struct mm_struct *, mm)
+ __field(int, isolated)
+ __field(int, status)
+ ),
+
+ TP_fast_assign(
+ __entry->mm = mm;
+ __entry->isolated = isolated;
+ __entry->status = status;
+ ),
+
+ TP_printk("mm=%p, isolated=%d, status=%s",
+ __entry->mm,
+ __entry->isolated,
+ __print_symbolic(__entry->status, SCAN_STATUS))
+);
+
+TRACE_EVENT(mm_collapse_huge_page_isolate,
+
+ TP_PROTO(unsigned long pfn, int none_or_zero,
+ bool referenced, bool writable, int status),
+
+ TP_ARGS(pfn, none_or_zero, referenced, writable, status),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, pfn)
+ __field(int, none_or_zero)
+ __field(bool, referenced)
+ __field(bool, writable)
+ __field(int, status)
+ ),
+
+ TP_fast_assign(
+ __entry->pfn = pfn;
+ __entry->none_or_zero = none_or_zero;
+ __entry->referenced = referenced;
+ __entry->writable = writable;
+ __entry->status = status;
+ ),
+
+ TP_printk("scan_pfn=0x%lx, none_or_zero=%d, referenced=%d, writable=%d, status=%s",
+ __entry->pfn,
+ __entry->none_or_zero,
+ __entry->referenced,
+ __entry->writable,
+ __print_symbolic(__entry->status, SCAN_STATUS))
+);
+
+#endif /* __HUGE_MEMORY_H */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/page_isolation.h b/include/trace/events/page_isolation.h
new file mode 100644
index 000000000000..6fb644029c80
--- /dev/null
+++ b/include/trace/events/page_isolation.h
@@ -0,0 +1,38 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM page_isolation
+
+#if !defined(_TRACE_PAGE_ISOLATION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PAGE_ISOLATION_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(test_pages_isolated,
+
+ TP_PROTO(
+ unsigned long start_pfn,
+ unsigned long end_pfn,
+ unsigned long fin_pfn),
+
+ TP_ARGS(start_pfn, end_pfn, fin_pfn),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, start_pfn)
+ __field(unsigned long, end_pfn)
+ __field(unsigned long, fin_pfn)
+ ),
+
+ TP_fast_assign(
+ __entry->start_pfn = start_pfn;
+ __entry->end_pfn = end_pfn;
+ __entry->fin_pfn = fin_pfn;
+ ),
+
+ TP_printk("start_pfn=0x%lx end_pfn=0x%lx fin_pfn=0x%lx ret=%s",
+ __entry->start_pfn, __entry->end_pfn, __entry->fin_pfn,
+ __entry->end_pfn == __entry->fin_pfn ? "success" : "fail")
+);
+
+#endif /* _TRACE_PAGE_ISOLATION_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index f66476b96264..31763dd8db1c 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -330,10 +330,9 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
TRACE_EVENT(mm_vmscan_writepage,
- TP_PROTO(struct page *page,
- int reclaim_flags),
+ TP_PROTO(struct page *page),
- TP_ARGS(page, reclaim_flags),
+ TP_ARGS(page),
TP_STRUCT__entry(
__field(unsigned long, pfn)
@@ -342,7 +341,7 @@ TRACE_EVENT(mm_vmscan_writepage,
TP_fast_assign(
__entry->pfn = page_to_pfn(page);
- __entry->reclaim_flags = reclaim_flags;
+ __entry->reclaim_flags = trace_reclaim_flags(page);
),
TP_printk("page=%p pfn=%lu flags=%s",
@@ -353,11 +352,11 @@ TRACE_EVENT(mm_vmscan_writepage,
TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
- TP_PROTO(int nid, int zid,
- unsigned long nr_scanned, unsigned long nr_reclaimed,
- int priority, int reclaim_flags),
+ TP_PROTO(struct zone *zone,
+ unsigned long nr_scanned, unsigned long nr_reclaimed,
+ int priority, int file),
- TP_ARGS(nid, zid, nr_scanned, nr_reclaimed, priority, reclaim_flags),
+ TP_ARGS(zone, nr_scanned, nr_reclaimed, priority, file),
TP_STRUCT__entry(
__field(int, nid)
@@ -369,12 +368,12 @@ TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
),
TP_fast_assign(
- __entry->nid = nid;
- __entry->zid = zid;
+ __entry->nid = zone_to_nid(zone);
+ __entry->zid = zone_idx(zone);
__entry->nr_scanned = nr_scanned;
__entry->nr_reclaimed = nr_reclaimed;
__entry->priority = priority;
- __entry->reclaim_flags = reclaim_flags;
+ __entry->reclaim_flags = trace_shrink_flags(file);
),
TP_printk("nid=%d zid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index a74dd84bbb6d..58274382a616 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -41,6 +41,7 @@
#define MADV_DONTNEED 4 /* don't need these pages */
/* common parameters: try to keep these consistent across architectures */
+#define MADV_FREE 8 /* free pages only if memory pressure */
#define MADV_REMOVE 9 /* remove these pages & resources */
#define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */
diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild
index 38d437096c35..9355dd8eff3b 100644
--- a/include/uapi/drm/Kbuild
+++ b/include/uapi/drm/Kbuild
@@ -3,6 +3,7 @@ header-y += drm.h
header-y += drm_fourcc.h
header-y += drm_mode.h
header-y += drm_sarea.h
+header-y += amdgpu_drm.h
header-y += exynos_drm.h
header-y += i810_drm.h
header-y += i915_drm.h
@@ -17,4 +18,5 @@ header-y += tegra_drm.h
header-y += via_drm.h
header-y += vmwgfx_drm.h
header-y += msm_drm.h
+header-y += vc4_drm.h
header-y += virtgpu_drm.h
diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
index e52933a73580..453a76af123c 100644
--- a/include/uapi/drm/amdgpu_drm.h
+++ b/include/uapi/drm/amdgpu_drm.h
@@ -76,19 +76,19 @@
struct drm_amdgpu_gem_create_in {
/** the requested memory size */
- uint64_t bo_size;
+ __u64 bo_size;
/** physical start_addr alignment in bytes for some HW requirements */
- uint64_t alignment;
+ __u64 alignment;
/** the requested memory domains */
- uint64_t domains;
+ __u64 domains;
/** allocation flags */
- uint64_t domain_flags;
+ __u64 domain_flags;
};
struct drm_amdgpu_gem_create_out {
/** returned GEM object handle */
- uint32_t handle;
- uint32_t _pad;
+ __u32 handle;
+ __u32 _pad;
};
union drm_amdgpu_gem_create {
@@ -105,28 +105,28 @@ union drm_amdgpu_gem_create {
struct drm_amdgpu_bo_list_in {
/** Type of operation */
- uint32_t operation;
+ __u32 operation;
/** Handle of list or 0 if we want to create one */
- uint32_t list_handle;
+ __u32 list_handle;
/** Number of BOs in list */
- uint32_t bo_number;
+ __u32 bo_number;
/** Size of each element describing BO */
- uint32_t bo_info_size;
+ __u32 bo_info_size;
/** Pointer to array describing BOs */
- uint64_t bo_info_ptr;
+ __u64 bo_info_ptr;
};
struct drm_amdgpu_bo_list_entry {
/** Handle of BO */
- uint32_t bo_handle;
+ __u32 bo_handle;
/** New (if specified) BO priority to be used during migration */
- uint32_t bo_priority;
+ __u32 bo_priority;
};
struct drm_amdgpu_bo_list_out {
/** Handle of resource list */
- uint32_t list_handle;
- uint32_t _pad;
+ __u32 list_handle;
+ __u32 _pad;
};
union drm_amdgpu_bo_list {
@@ -150,26 +150,26 @@ union drm_amdgpu_bo_list {
struct drm_amdgpu_ctx_in {
/** AMDGPU_CTX_OP_* */
- uint32_t op;
+ __u32 op;
/** For future use, no flags defined so far */
- uint32_t flags;
- uint32_t ctx_id;
- uint32_t _pad;
+ __u32 flags;
+ __u32 ctx_id;
+ __u32 _pad;
};
union drm_amdgpu_ctx_out {
struct {
- uint32_t ctx_id;
- uint32_t _pad;
+ __u32 ctx_id;
+ __u32 _pad;
} alloc;
struct {
/** For future use, no flags defined so far */
- uint64_t flags;
+ __u64 flags;
/** Number of resets caused by this context so far. */
- uint32_t hangs;
+ __u32 hangs;
/** Reset status since the last call of the ioctl. */
- uint32_t reset_status;
+ __u32 reset_status;
} state;
};
@@ -189,12 +189,12 @@ union drm_amdgpu_ctx {
#define AMDGPU_GEM_USERPTR_REGISTER (1 << 3)
struct drm_amdgpu_gem_userptr {
- uint64_t addr;
- uint64_t size;
+ __u64 addr;
+ __u64 size;
/* AMDGPU_GEM_USERPTR_* */
- uint32_t flags;
+ __u32 flags;
/* Resulting GEM handle */
- uint32_t handle;
+ __u32 handle;
};
/* same meaning as the GB_TILE_MODE and GL_MACRO_TILE_MODE fields */
@@ -226,28 +226,28 @@ struct drm_amdgpu_gem_userptr {
/** The same structure is shared for input/output */
struct drm_amdgpu_gem_metadata {
/** GEM Object handle */
- uint32_t handle;
+ __u32 handle;
/** Do we want get or set metadata */
- uint32_t op;
+ __u32 op;
struct {
/** For future use, no flags defined so far */
- uint64_t flags;
+ __u64 flags;
/** family specific tiling info */
- uint64_t tiling_info;
- uint32_t data_size_bytes;
- uint32_t data[64];
+ __u64 tiling_info;
+ __u32 data_size_bytes;
+ __u32 data[64];
} data;
};
struct drm_amdgpu_gem_mmap_in {
/** the GEM object handle */
- uint32_t handle;
- uint32_t _pad;
+ __u32 handle;
+ __u32 _pad;
};
struct drm_amdgpu_gem_mmap_out {
/** mmap offset from the vma offset manager */
- uint64_t addr_ptr;
+ __u64 addr_ptr;
};
union drm_amdgpu_gem_mmap {
@@ -257,18 +257,18 @@ union drm_amdgpu_gem_mmap {
struct drm_amdgpu_gem_wait_idle_in {
/** GEM object handle */
- uint32_t handle;
+ __u32 handle;
/** For future use, no flags defined so far */
- uint32_t flags;
+ __u32 flags;
/** Absolute timeout to wait */
- uint64_t timeout;
+ __u64 timeout;
};
struct drm_amdgpu_gem_wait_idle_out {
/** BO status: 0 - BO is idle, 1 - BO is busy */
- uint32_t status;
+ __u32 status;
/** Returned current memory domain */
- uint32_t domain;
+ __u32 domain;
};
union drm_amdgpu_gem_wait_idle {
@@ -278,18 +278,18 @@ union drm_amdgpu_gem_wait_idle {
struct drm_amdgpu_wait_cs_in {
/** Command submission handle */
- uint64_t handle;
+ __u64 handle;
/** Absolute timeout to wait */
- uint64_t timeout;
- uint32_t ip_type;
- uint32_t ip_instance;
- uint32_t ring;
- uint32_t ctx_id;
+ __u64 timeout;
+ __u32 ip_type;
+ __u32 ip_instance;
+ __u32 ring;
+ __u32 ctx_id;
};
struct drm_amdgpu_wait_cs_out {
/** CS status: 0 - CS completed, 1 - CS still busy */
- uint64_t status;
+ __u64 status;
};
union drm_amdgpu_wait_cs {
@@ -303,11 +303,11 @@ union drm_amdgpu_wait_cs {
/* Sets or returns a value associated with a buffer. */
struct drm_amdgpu_gem_op {
/** GEM object handle */
- uint32_t handle;
+ __u32 handle;
/** AMDGPU_GEM_OP_* */
- uint32_t op;
+ __u32 op;
/** Input or return value */
- uint64_t value;
+ __u64 value;
};
#define AMDGPU_VA_OP_MAP 1
@@ -326,18 +326,18 @@ struct drm_amdgpu_gem_op {
struct drm_amdgpu_gem_va {
/** GEM object handle */
- uint32_t handle;
- uint32_t _pad;
+ __u32 handle;
+ __u32 _pad;
/** AMDGPU_VA_OP_* */
- uint32_t operation;
+ __u32 operation;
/** AMDGPU_VM_PAGE_* */
- uint32_t flags;
+ __u32 flags;
/** va address to assign . Must be correctly aligned.*/
- uint64_t va_address;
+ __u64 va_address;
/** Specify offset inside of BO to assign. Must be correctly aligned.*/
- uint64_t offset_in_bo;
+ __u64 offset_in_bo;
/** Specify mapping size. Must be correctly aligned. */
- uint64_t map_size;
+ __u64 map_size;
};
#define AMDGPU_HW_IP_GFX 0
@@ -354,24 +354,24 @@ struct drm_amdgpu_gem_va {
#define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03
struct drm_amdgpu_cs_chunk {
- uint32_t chunk_id;
- uint32_t length_dw;
- uint64_t chunk_data;
+ __u32 chunk_id;
+ __u32 length_dw;
+ __u64 chunk_data;
};
struct drm_amdgpu_cs_in {
/** Rendering context id */
- uint32_t ctx_id;
+ __u32 ctx_id;
/** Handle of resource list associated with CS */
- uint32_t bo_list_handle;
- uint32_t num_chunks;
- uint32_t _pad;
- /** this points to uint64_t * which point to cs chunks */
- uint64_t chunks;
+ __u32 bo_list_handle;
+ __u32 num_chunks;
+ __u32 _pad;
+ /** this points to __u64 * which point to cs chunks */
+ __u64 chunks;
};
struct drm_amdgpu_cs_out {
- uint64_t handle;
+ __u64 handle;
};
union drm_amdgpu_cs {
@@ -388,32 +388,32 @@ union drm_amdgpu_cs {
#define AMDGPU_IB_FLAG_PREAMBLE (1<<1)
struct drm_amdgpu_cs_chunk_ib {
- uint32_t _pad;
+ __u32 _pad;
/** AMDGPU_IB_FLAG_* */
- uint32_t flags;
+ __u32 flags;
/** Virtual address to begin IB execution */
- uint64_t va_start;
+ __u64 va_start;
/** Size of submission */
- uint32_t ib_bytes;
+ __u32 ib_bytes;
/** HW IP to submit to */
- uint32_t ip_type;
+ __u32 ip_type;
/** HW IP index of the same type to submit to */
- uint32_t ip_instance;
+ __u32 ip_instance;
/** Ring index to submit to */
- uint32_t ring;
+ __u32 ring;
};
struct drm_amdgpu_cs_chunk_dep {
- uint32_t ip_type;
- uint32_t ip_instance;
- uint32_t ring;
- uint32_t ctx_id;
- uint64_t handle;
+ __u32 ip_type;
+ __u32 ip_instance;
+ __u32 ring;
+ __u32 ctx_id;
+ __u64 handle;
};
struct drm_amdgpu_cs_chunk_fence {
- uint32_t handle;
- uint32_t offset;
+ __u32 handle;
+ __u32 offset;
};
struct drm_amdgpu_cs_chunk_data {
@@ -486,83 +486,83 @@ struct drm_amdgpu_cs_chunk_data {
/* Input structure for the INFO ioctl */
struct drm_amdgpu_info {
/* Where the return value will be stored */
- uint64_t return_pointer;
+ __u64 return_pointer;
/* The size of the return value. Just like "size" in "snprintf",
* it limits how many bytes the kernel can write. */
- uint32_t return_size;
+ __u32 return_size;
/* The query request id. */
- uint32_t query;
+ __u32 query;
union {
struct {
- uint32_t id;
- uint32_t _pad;
+ __u32 id;
+ __u32 _pad;
} mode_crtc;
struct {
/** AMDGPU_HW_IP_* */
- uint32_t type;
+ __u32 type;
/**
* Index of the IP if there are more IPs of the same
* type. Ignored by AMDGPU_INFO_HW_IP_COUNT.
*/
- uint32_t ip_instance;
+ __u32 ip_instance;
} query_hw_ip;
struct {
- uint32_t dword_offset;
+ __u32 dword_offset;
/** number of registers to read */
- uint32_t count;
- uint32_t instance;
+ __u32 count;
+ __u32 instance;
/** For future use, no flags defined so far */
- uint32_t flags;
+ __u32 flags;
} read_mmr_reg;
struct {
/** AMDGPU_INFO_FW_* */
- uint32_t fw_type;
+ __u32 fw_type;
/**
* Index of the IP if there are more IPs of
* the same type.
*/
- uint32_t ip_instance;
+ __u32 ip_instance;
/**
* Index of the engine. Whether this is used depends
* on the firmware type. (e.g. MEC, SDMA)
*/
- uint32_t index;
- uint32_t _pad;
+ __u32 index;
+ __u32 _pad;
} query_fw;
};
};
struct drm_amdgpu_info_gds {
/** GDS GFX partition size */
- uint32_t gds_gfx_partition_size;
+ __u32 gds_gfx_partition_size;
/** GDS compute partition size */
- uint32_t compute_partition_size;
+ __u32 compute_partition_size;
/** total GDS memory size */
- uint32_t gds_total_size;
+ __u32 gds_total_size;
/** GWS size per GFX partition */
- uint32_t gws_per_gfx_partition;
+ __u32 gws_per_gfx_partition;
/** GSW size per compute partition */
- uint32_t gws_per_compute_partition;
+ __u32 gws_per_compute_partition;
/** OA size per GFX partition */
- uint32_t oa_per_gfx_partition;
+ __u32 oa_per_gfx_partition;
/** OA size per compute partition */
- uint32_t oa_per_compute_partition;
- uint32_t _pad;
+ __u32 oa_per_compute_partition;
+ __u32 _pad;
};
struct drm_amdgpu_info_vram_gtt {
- uint64_t vram_size;
- uint64_t vram_cpu_accessible_size;
- uint64_t gtt_size;
+ __u64 vram_size;
+ __u64 vram_cpu_accessible_size;
+ __u64 gtt_size;
};
struct drm_amdgpu_info_firmware {
- uint32_t ver;
- uint32_t feature;
+ __u32 ver;
+ __u32 feature;
};
#define AMDGPU_VRAM_TYPE_UNKNOWN 0
@@ -576,61 +576,61 @@ struct drm_amdgpu_info_firmware {
struct drm_amdgpu_info_device {
/** PCI Device ID */
- uint32_t device_id;
+ __u32 device_id;
/** Internal chip revision: A0, A1, etc.) */
- uint32_t chip_rev;
- uint32_t external_rev;
+ __u32 chip_rev;
+ __u32 external_rev;
/** Revision id in PCI Config space */
- uint32_t pci_rev;
- uint32_t family;
- uint32_t num_shader_engines;
- uint32_t num_shader_arrays_per_engine;
+ __u32 pci_rev;
+ __u32 family;
+ __u32 num_shader_engines;
+ __u32 num_shader_arrays_per_engine;
/* in KHz */
- uint32_t gpu_counter_freq;
- uint64_t max_engine_clock;
- uint64_t max_memory_clock;
+ __u32 gpu_counter_freq;
+ __u64 max_engine_clock;
+ __u64 max_memory_clock;
/* cu information */
- uint32_t cu_active_number;
- uint32_t cu_ao_mask;
- uint32_t cu_bitmap[4][4];
+ __u32 cu_active_number;
+ __u32 cu_ao_mask;
+ __u32 cu_bitmap[4][4];
/** Render backend pipe mask. One render backend is CB+DB. */
- uint32_t enabled_rb_pipes_mask;
- uint32_t num_rb_pipes;
- uint32_t num_hw_gfx_contexts;
- uint32_t _pad;
- uint64_t ids_flags;
+ __u32 enabled_rb_pipes_mask;
+ __u32 num_rb_pipes;
+ __u32 num_hw_gfx_contexts;
+ __u32 _pad;
+ __u64 ids_flags;
/** Starting virtual address for UMDs. */
- uint64_t virtual_address_offset;
+ __u64 virtual_address_offset;
/** The maximum virtual address */
- uint64_t virtual_address_max;
+ __u64 virtual_address_max;
/** Required alignment of virtual addresses. */
- uint32_t virtual_address_alignment;
+ __u32 virtual_address_alignment;
/** Page table entry - fragment size */
- uint32_t pte_fragment_size;
- uint32_t gart_page_size;
+ __u32 pte_fragment_size;
+ __u32 gart_page_size;
/** constant engine ram size*/
- uint32_t ce_ram_size;
+ __u32 ce_ram_size;
/** video memory type info*/
- uint32_t vram_type;
+ __u32 vram_type;
/** video memory bit width*/
- uint32_t vram_bit_width;
+ __u32 vram_bit_width;
/* vce harvesting instance */
- uint32_t vce_harvest_config;
+ __u32 vce_harvest_config;
};
struct drm_amdgpu_info_hw_ip {
/** Version of h/w IP */
- uint32_t hw_ip_version_major;
- uint32_t hw_ip_version_minor;
+ __u32 hw_ip_version_major;
+ __u32 hw_ip_version_minor;
/** Capabilities */
- uint64_t capabilities_flags;
+ __u64 capabilities_flags;
/** command buffer address start alignment*/
- uint32_t ib_start_alignment;
+ __u32 ib_start_alignment;
/** command buffer size alignment*/
- uint32_t ib_size_alignment;
+ __u32 ib_size_alignment;
/** Bitmask of available rings. Bit 0 means ring 0, etc. */
- uint32_t available_rings;
- uint32_t _pad;
+ __u32 available_rings;
+ __u32 _pad;
};
/*
diff --git a/include/uapi/drm/armada_drm.h b/include/uapi/drm/armada_drm.h
index 8dec3fdc99c7..6de7f0196ca0 100644
--- a/include/uapi/drm/armada_drm.h
+++ b/include/uapi/drm/armada_drm.h
@@ -9,6 +9,8 @@
#ifndef DRM_ARMADA_IOCTL_H
#define DRM_ARMADA_IOCTL_H
+#include "drm.h"
+
#define DRM_ARMADA_GEM_CREATE 0x00
#define DRM_ARMADA_GEM_MMAP 0x02
#define DRM_ARMADA_GEM_PWRITE 0x03
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 3801584a0c53..b4e92eb12044 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -54,6 +54,7 @@ typedef int32_t __s32;
typedef uint32_t __u32;
typedef int64_t __s64;
typedef uint64_t __u64;
+typedef size_t __kernel_size_t;
typedef unsigned long drm_handle_t;
#endif
@@ -129,11 +130,11 @@ struct drm_version {
int version_major; /**< Major version */
int version_minor; /**< Minor version */
int version_patchlevel; /**< Patch level */
- size_t name_len; /**< Length of name buffer */
+ __kernel_size_t name_len; /**< Length of name buffer */
char __user *name; /**< Name of driver */
- size_t date_len; /**< Length of date buffer */
+ __kernel_size_t date_len; /**< Length of date buffer */
char __user *date; /**< User-space buffer to hold date */
- size_t desc_len; /**< Length of desc buffer */
+ __kernel_size_t desc_len; /**< Length of desc buffer */
char __user *desc; /**< User-space buffer to hold desc */
};
@@ -143,7 +144,7 @@ struct drm_version {
* \sa drmGetBusid() and drmSetBusId().
*/
struct drm_unique {
- size_t unique_len; /**< Length of unique */
+ __kernel_size_t unique_len; /**< Length of unique */
char __user *unique; /**< Unique name for driver instantiation */
};
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index ee2d542c65f5..4d8da699a623 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -24,7 +24,7 @@
#ifndef DRM_FOURCC_H
#define DRM_FOURCC_H
-#include <linux/types.h>
+#include "drm.h"
#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
((__u32)(c) << 16) | ((__u32)(d) << 24))
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 6c11ca401de8..50adb46204c2 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -27,7 +27,7 @@
#ifndef _DRM_MODE_H
#define _DRM_MODE_H
-#include <linux/types.h>
+#include "drm.h"
#define DRM_DISPLAY_INFO_LEN 32
#define DRM_CONNECTOR_NAME_LEN 32
@@ -526,14 +526,14 @@ struct drm_mode_crtc_page_flip {
/* create a dumb scanout buffer */
struct drm_mode_create_dumb {
- uint32_t height;
- uint32_t width;
- uint32_t bpp;
- uint32_t flags;
+ __u32 height;
+ __u32 width;
+ __u32 bpp;
+ __u32 flags;
/* handle, pitch, size will be returned */
- uint32_t handle;
- uint32_t pitch;
- uint64_t size;
+ __u32 handle;
+ __u32 pitch;
+ __u64 size;
};
/* set up for mmap of a dumb scanout buffer */
@@ -550,7 +550,7 @@ struct drm_mode_map_dumb {
};
struct drm_mode_destroy_dumb {
- uint32_t handle;
+ __u32 handle;
};
/* page-flip flags are valid, plus: */
diff --git a/include/uapi/drm/drm_sarea.h b/include/uapi/drm/drm_sarea.h
index 413a5642d49f..1d1a858a203d 100644
--- a/include/uapi/drm/drm_sarea.h
+++ b/include/uapi/drm/drm_sarea.h
@@ -32,7 +32,7 @@
#ifndef _DRM_SAREA_H_
#define _DRM_SAREA_H_
-#include <drm/drm.h>
+#include "drm.h"
/* SAREA area needs to be at least a page */
#if defined(__alpha__)
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
new file mode 100644
index 000000000000..4cc989ad6851
--- /dev/null
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2015 Etnaviv Project
+ *
+ * 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/>.
+ */
+
+#ifndef __ETNAVIV_DRM_H__
+#define __ETNAVIV_DRM_H__
+
+#include "drm.h"
+
+/* Please note that modifications to all structs defined here are
+ * subject to backwards-compatibility constraints:
+ * 1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
+ * user/kernel compatibility
+ * 2) Keep fields aligned to their size
+ * 3) Because of how drm_ioctl() works, we can add new fields at
+ * the end of an ioctl if some care is taken: drm_ioctl() will
+ * zero out the new fields at the tail of the ioctl, so a zero
+ * value should have a backwards compatible meaning. And for
+ * output params, userspace won't see the newly added output
+ * fields.. so that has to be somehow ok.
+ */
+
+/* timeouts are specified in clock-monotonic absolute times (to simplify
+ * restarting interrupted ioctls). The following struct is logically the
+ * same as 'struct timespec' but 32/64b ABI safe.
+ */
+struct drm_etnaviv_timespec {
+ __s64 tv_sec; /* seconds */
+ __s64 tv_nsec; /* nanoseconds */
+};
+
+#define ETNAVIV_PARAM_GPU_MODEL 0x01
+#define ETNAVIV_PARAM_GPU_REVISION 0x02
+#define ETNAVIV_PARAM_GPU_FEATURES_0 0x03
+#define ETNAVIV_PARAM_GPU_FEATURES_1 0x04
+#define ETNAVIV_PARAM_GPU_FEATURES_2 0x05
+#define ETNAVIV_PARAM_GPU_FEATURES_3 0x06
+#define ETNAVIV_PARAM_GPU_FEATURES_4 0x07
+
+#define ETNAVIV_PARAM_GPU_STREAM_COUNT 0x10
+#define ETNAVIV_PARAM_GPU_REGISTER_MAX 0x11
+#define ETNAVIV_PARAM_GPU_THREAD_COUNT 0x12
+#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE 0x13
+#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT 0x14
+#define ETNAVIV_PARAM_GPU_PIXEL_PIPES 0x15
+#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16
+#define ETNAVIV_PARAM_GPU_BUFFER_SIZE 0x17
+#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18
+#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19
+
+#define ETNA_MAX_PIPES 4
+
+struct drm_etnaviv_param {
+ __u32 pipe; /* in */
+ __u32 param; /* in, ETNAVIV_PARAM_x */
+ __u64 value; /* out (get_param) or in (set_param) */
+};
+
+/*
+ * GEM buffers:
+ */
+
+#define ETNA_BO_CACHE_MASK 0x000f0000
+/* cache modes */
+#define ETNA_BO_CACHED 0x00010000
+#define ETNA_BO_WC 0x00020000
+#define ETNA_BO_UNCACHED 0x00040000
+/* map flags */
+#define ETNA_BO_FORCE_MMU 0x00100000
+
+struct drm_etnaviv_gem_new {
+ __u64 size; /* in */
+ __u32 flags; /* in, mask of ETNA_BO_x */
+ __u32 handle; /* out */
+};
+
+struct drm_etnaviv_gem_info {
+ __u32 handle; /* in */
+ __u32 pad;
+ __u64 offset; /* out, offset to pass to mmap() */
+};
+
+#define ETNA_PREP_READ 0x01
+#define ETNA_PREP_WRITE 0x02
+#define ETNA_PREP_NOSYNC 0x04
+
+struct drm_etnaviv_gem_cpu_prep {
+ __u32 handle; /* in */
+ __u32 op; /* in, mask of ETNA_PREP_x */
+ struct drm_etnaviv_timespec timeout; /* in */
+};
+
+struct drm_etnaviv_gem_cpu_fini {
+ __u32 handle; /* in */
+ __u32 flags; /* in, placeholder for now, no defined values */
+};
+
+/*
+ * Cmdstream Submission:
+ */
+
+/* The value written into the cmdstream is logically:
+ * relocbuf->gpuaddr + reloc_offset
+ *
+ * NOTE that reloc's must be sorted by order of increasing submit_offset,
+ * otherwise EINVAL.
+ */
+struct drm_etnaviv_gem_submit_reloc {
+ __u32 submit_offset; /* in, offset from submit_bo */
+ __u32 reloc_idx; /* in, index of reloc_bo buffer */
+ __u64 reloc_offset; /* in, offset from start of reloc_bo */
+ __u32 flags; /* in, placeholder for now, no defined values */
+};
+
+/* Each buffer referenced elsewhere in the cmdstream submit (ie. the
+ * cmdstream buffer(s) themselves or reloc entries) has one (and only
+ * one) entry in the submit->bos[] table.
+ *
+ * As a optimization, the current buffer (gpu virtual address) can be
+ * passed back through the 'presumed' field. If on a subsequent reloc,
+ * userspace passes back a 'presumed' address that is still valid,
+ * then patching the cmdstream for this entry is skipped. This can
+ * avoid kernel needing to map/access the cmdstream bo in the common
+ * case.
+ */
+#define ETNA_SUBMIT_BO_READ 0x0001
+#define ETNA_SUBMIT_BO_WRITE 0x0002
+struct drm_etnaviv_gem_submit_bo {
+ __u32 flags; /* in, mask of ETNA_SUBMIT_BO_x */
+ __u32 handle; /* in, GEM handle */
+ __u64 presumed; /* in/out, presumed buffer address */
+};
+
+/* Each cmdstream submit consists of a table of buffers involved, and
+ * one or more cmdstream buffers. This allows for conditional execution
+ * (context-restore), and IB buffers needed for per tile/bin draw cmds.
+ */
+#define ETNA_PIPE_3D 0x00
+#define ETNA_PIPE_2D 0x01
+#define ETNA_PIPE_VG 0x02
+struct drm_etnaviv_gem_submit {
+ __u32 fence; /* out */
+ __u32 pipe; /* in */
+ __u32 exec_state; /* in, initial execution state (ETNA_PIPE_x) */
+ __u32 nr_bos; /* in, number of submit_bo's */
+ __u32 nr_relocs; /* in, number of submit_reloc's */
+ __u32 stream_size; /* in, cmdstream size */
+ __u64 bos; /* in, ptr to array of submit_bo's */
+ __u64 relocs; /* in, ptr to array of submit_reloc's */
+ __u64 stream; /* in, ptr to cmdstream */
+};
+
+/* The normal way to synchronize with the GPU is just to CPU_PREP on
+ * a buffer if you need to access it from the CPU (other cmdstream
+ * submission from same or other contexts, PAGE_FLIP ioctl, etc, all
+ * handle the required synchronization under the hood). This ioctl
+ * mainly just exists as a way to implement the gallium pipe_fence
+ * APIs without requiring a dummy bo to synchronize on.
+ */
+#define ETNA_WAIT_NONBLOCK 0x01
+struct drm_etnaviv_wait_fence {
+ __u32 pipe; /* in */
+ __u32 fence; /* in */
+ __u32 flags; /* in, mask of ETNA_WAIT_x */
+ __u32 pad;
+ struct drm_etnaviv_timespec timeout; /* in */
+};
+
+#define ETNA_USERPTR_READ 0x01
+#define ETNA_USERPTR_WRITE 0x02
+struct drm_etnaviv_gem_userptr {
+ __u64 user_ptr; /* in, page aligned user pointer */
+ __u64 user_size; /* in, page aligned user size */
+ __u32 flags; /* in, flags */
+ __u32 handle; /* out, non-zero handle */
+};
+
+struct drm_etnaviv_gem_wait {
+ __u32 pipe; /* in */
+ __u32 handle; /* in, bo to be waited for */
+ __u32 flags; /* in, mask of ETNA_WAIT_x */
+ __u32 pad;
+ struct drm_etnaviv_timespec timeout; /* in */
+};
+
+#define DRM_ETNAVIV_GET_PARAM 0x00
+/* placeholder:
+#define DRM_ETNAVIV_SET_PARAM 0x01
+ */
+#define DRM_ETNAVIV_GEM_NEW 0x02
+#define DRM_ETNAVIV_GEM_INFO 0x03
+#define DRM_ETNAVIV_GEM_CPU_PREP 0x04
+#define DRM_ETNAVIV_GEM_CPU_FINI 0x05
+#define DRM_ETNAVIV_GEM_SUBMIT 0x06
+#define DRM_ETNAVIV_WAIT_FENCE 0x07
+#define DRM_ETNAVIV_GEM_USERPTR 0x08
+#define DRM_ETNAVIV_GEM_WAIT 0x09
+#define DRM_ETNAVIV_NUM_IOCTLS 0x0a
+
+#define DRM_IOCTL_ETNAVIV_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
+#define DRM_IOCTL_ETNAVIV_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
+#define DRM_IOCTL_ETNAVIV_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info)
+#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep)
+#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini)
+#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
+#define DRM_IOCTL_ETNAVIV_WAIT_FENCE DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
+#define DRM_IOCTL_ETNAVIV_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
+#define DRM_IOCTL_ETNAVIV_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
+
+#endif /* __ETNAVIV_DRM_H__ */
diff --git a/include/uapi/drm/exynos_drm.h b/include/uapi/drm/exynos_drm.h
index 5575ed1598bd..312c67d744ae 100644
--- a/include/uapi/drm/exynos_drm.h
+++ b/include/uapi/drm/exynos_drm.h
@@ -15,7 +15,7 @@
#ifndef _UAPI_EXYNOS_DRM_H_
#define _UAPI_EXYNOS_DRM_H_
-#include <drm/drm.h>
+#include "drm.h"
/**
* User-desired buffer creation information structure.
@@ -27,7 +27,7 @@
* - this handle will be set by gem module of kernel side.
*/
struct drm_exynos_gem_create {
- uint64_t size;
+ __u64 size;
unsigned int flags;
unsigned int handle;
};
@@ -44,7 +44,7 @@ struct drm_exynos_gem_create {
struct drm_exynos_gem_info {
unsigned int handle;
unsigned int flags;
- uint64_t size;
+ __u64 size;
};
/**
@@ -58,7 +58,7 @@ struct drm_exynos_gem_info {
struct drm_exynos_vidi_connection {
unsigned int connection;
unsigned int extensions;
- uint64_t edid;
+ __u64 edid;
};
/* memory type definitions. */
diff --git a/include/uapi/drm/i810_drm.h b/include/uapi/drm/i810_drm.h
index 34736efd5824..bdb028723ded 100644
--- a/include/uapi/drm/i810_drm.h
+++ b/include/uapi/drm/i810_drm.h
@@ -1,7 +1,7 @@
#ifndef _I810_DRM_H_
#define _I810_DRM_H_
-#include <drm/drm.h>
+#include "drm.h"
/* WARNING: These defines must be the same as what the Xserver uses.
* if you change them, you must change the defines in the Xserver.
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 484a9fb20479..acf21026c78a 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -27,7 +27,7 @@
#ifndef _UAPI_I915_DRM_H_
#define _UAPI_I915_DRM_H_
-#include <drm/drm.h>
+#include "drm.h"
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
@@ -356,6 +356,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_EU_TOTAL 34
#define I915_PARAM_HAS_GPU_RESET 35
#define I915_PARAM_HAS_RESOURCE_STREAMER 36
+#define I915_PARAM_HAS_EXEC_SOFTPIN 37
typedef struct drm_i915_getparam {
__s32 param;
@@ -682,8 +683,12 @@ struct drm_i915_gem_exec_object2 {
__u64 alignment;
/**
- * Returned value of the updated offset of the object, for future
- * presumed_offset writes.
+ * When the EXEC_OBJECT_PINNED flag is specified this is populated by
+ * the user with the GTT offset at which this object will be pinned.
+ * When the I915_EXEC_NO_RELOC flag is specified this must contain the
+ * presumed_offset of the object.
+ * During execbuffer2 the kernel populates it with the value of the
+ * current GTT offset of the object, for future presumed_offset writes.
*/
__u64 offset;
@@ -691,7 +696,8 @@ struct drm_i915_gem_exec_object2 {
#define EXEC_OBJECT_NEEDS_GTT (1<<1)
#define EXEC_OBJECT_WRITE (1<<2)
#define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
-#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_SUPPORTS_48B_ADDRESS<<1)
+#define EXEC_OBJECT_PINNED (1<<4)
+#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_PINNED<<1)
__u64 flags;
__u64 rsvd1;
@@ -1079,6 +1085,12 @@ struct drm_i915_gem_context_destroy {
};
struct drm_i915_reg_read {
+ /*
+ * Register offset.
+ * For 64bit wide registers where the upper 32bits don't immediately
+ * follow the lower 32bits, the offset of the lower 32bits must
+ * be specified
+ */
__u64 offset;
__u64 val; /* Return value */
};
@@ -1125,8 +1137,9 @@ struct drm_i915_gem_context_param {
__u32 ctx_id;
__u32 size;
__u64 param;
-#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1
-#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2
+#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1
+#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2
+#define I915_CONTEXT_PARAM_GTT_SIZE 0x3
__u64 value;
};
diff --git a/include/uapi/drm/mga_drm.h b/include/uapi/drm/mga_drm.h
index 2375bfd6e5e9..fca817009e13 100644
--- a/include/uapi/drm/mga_drm.h
+++ b/include/uapi/drm/mga_drm.h
@@ -35,7 +35,7 @@
#ifndef __MGA_DRM_H__
#define __MGA_DRM_H__
-#include <drm/drm.h>
+#include "drm.h"
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (mga_sarea.h)
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 75a232b9a970..81e6e0d1d360 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -18,8 +18,7 @@
#ifndef __MSM_DRM_H__
#define __MSM_DRM_H__
-#include <stddef.h>
-#include <drm/drm.h>
+#include "drm.h"
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints:
@@ -122,7 +121,7 @@ struct drm_msm_gem_cpu_fini {
struct drm_msm_gem_submit_reloc {
__u32 submit_offset; /* in, offset from submit_bo */
__u32 or; /* in, value OR'd with result */
- __s32 shift; /* in, amount of left shift (can be negative) */
+ __s32 shift; /* in, amount of left shift (can be negative) */
__u32 reloc_idx; /* in, index of reloc_bo buffer */
__u64 reloc_offset; /* in, offset from start of reloc_bo */
};
diff --git a/include/uapi/drm/nouveau_drm.h b/include/uapi/drm/nouveau_drm.h
index fd594cc73cc0..500d82aecbe4 100644
--- a/include/uapi/drm/nouveau_drm.h
+++ b/include/uapi/drm/nouveau_drm.h
@@ -27,6 +27,8 @@
#define DRM_NOUVEAU_EVENT_NVIF 0x80000000
+#include <drm/drm.h>
+
#define NOUVEAU_GEM_DOMAIN_CPU (1 << 0)
#define NOUVEAU_GEM_DOMAIN_VRAM (1 << 1)
#define NOUVEAU_GEM_DOMAIN_GART (1 << 2)
@@ -41,34 +43,34 @@
#define NOUVEAU_GEM_TILE_NONCONTIG 0x00000008
struct drm_nouveau_gem_info {
- uint32_t handle;
- uint32_t domain;
- uint64_t size;
- uint64_t offset;
- uint64_t map_handle;
- uint32_t tile_mode;
- uint32_t tile_flags;
+ __u32 handle;
+ __u32 domain;
+ __u64 size;
+ __u64 offset;
+ __u64 map_handle;
+ __u32 tile_mode;
+ __u32 tile_flags;
};
struct drm_nouveau_gem_new {
struct drm_nouveau_gem_info info;
- uint32_t channel_hint;
- uint32_t align;
+ __u32 channel_hint;
+ __u32 align;
};
#define NOUVEAU_GEM_MAX_BUFFERS 1024
struct drm_nouveau_gem_pushbuf_bo_presumed {
- uint32_t valid;
- uint32_t domain;
- uint64_t offset;
+ __u32 valid;
+ __u32 domain;
+ __u64 offset;
};
struct drm_nouveau_gem_pushbuf_bo {
- uint64_t user_priv;
- uint32_t handle;
- uint32_t read_domains;
- uint32_t write_domains;
- uint32_t valid_domains;
+ __u64 user_priv;
+ __u32 handle;
+ __u32 read_domains;
+ __u32 write_domains;
+ __u32 valid_domains;
struct drm_nouveau_gem_pushbuf_bo_presumed presumed;
};
@@ -77,46 +79,46 @@ struct drm_nouveau_gem_pushbuf_bo {
#define NOUVEAU_GEM_RELOC_OR (1 << 2)
#define NOUVEAU_GEM_MAX_RELOCS 1024
struct drm_nouveau_gem_pushbuf_reloc {
- uint32_t reloc_bo_index;
- uint32_t reloc_bo_offset;
- uint32_t bo_index;
- uint32_t flags;
- uint32_t data;
- uint32_t vor;
- uint32_t tor;
+ __u32 reloc_bo_index;
+ __u32 reloc_bo_offset;
+ __u32 bo_index;
+ __u32 flags;
+ __u32 data;
+ __u32 vor;
+ __u32 tor;
};
#define NOUVEAU_GEM_MAX_PUSH 512
struct drm_nouveau_gem_pushbuf_push {
- uint32_t bo_index;
- uint32_t pad;
- uint64_t offset;
- uint64_t length;
+ __u32 bo_index;
+ __u32 pad;
+ __u64 offset;
+ __u64 length;
};
struct drm_nouveau_gem_pushbuf {
- uint32_t channel;
- uint32_t nr_buffers;
- uint64_t buffers;
- uint32_t nr_relocs;
- uint32_t nr_push;
- uint64_t relocs;
- uint64_t push;
- uint32_t suffix0;
- uint32_t suffix1;
- uint64_t vram_available;
- uint64_t gart_available;
+ __u32 channel;
+ __u32 nr_buffers;
+ __u64 buffers;
+ __u32 nr_relocs;
+ __u32 nr_push;
+ __u64 relocs;
+ __u64 push;
+ __u32 suffix0;
+ __u32 suffix1;
+ __u64 vram_available;
+ __u64 gart_available;
};
#define NOUVEAU_GEM_CPU_PREP_NOWAIT 0x00000001
#define NOUVEAU_GEM_CPU_PREP_WRITE 0x00000004
struct drm_nouveau_gem_cpu_prep {
- uint32_t handle;
- uint32_t flags;
+ __u32 handle;
+ __u32 flags;
};
struct drm_nouveau_gem_cpu_fini {
- uint32_t handle;
+ __u32 handle;
};
#define DRM_NOUVEAU_GETPARAM 0x00 /* deprecated */
diff --git a/include/uapi/drm/omap_drm.h b/include/uapi/drm/omap_drm.h
index 1d0b1172664e..38a3bd847e15 100644
--- a/include/uapi/drm/omap_drm.h
+++ b/include/uapi/drm/omap_drm.h
@@ -20,7 +20,7 @@
#ifndef __OMAP_DRM_H__
#define __OMAP_DRM_H__
-#include <drm/drm.h>
+#include "drm.h"
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
@@ -101,9 +101,6 @@ struct drm_omap_gem_info {
#define DRM_OMAP_GET_PARAM 0x00
#define DRM_OMAP_SET_PARAM 0x01
-/* placeholder for plugin-api
-#define DRM_OMAP_GET_BASE 0x02
-*/
#define DRM_OMAP_GEM_NEW 0x03
#define DRM_OMAP_GEM_CPU_PREP 0x04
#define DRM_OMAP_GEM_CPU_FINI 0x05
@@ -112,9 +109,6 @@ struct drm_omap_gem_info {
#define DRM_IOCTL_OMAP_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_PARAM, struct drm_omap_param)
#define DRM_IOCTL_OMAP_SET_PARAM DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_SET_PARAM, struct drm_omap_param)
-/* placeholder for plugin-api
-#define DRM_IOCTL_OMAP_GET_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_BASE, struct drm_omap_get_base)
-*/
#define DRM_IOCTL_OMAP_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_NEW, struct drm_omap_gem_new)
#define DRM_IOCTL_OMAP_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_PREP, struct drm_omap_gem_cpu_prep)
#define DRM_IOCTL_OMAP_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_FINI, struct drm_omap_gem_cpu_fini)
diff --git a/include/uapi/drm/qxl_drm.h b/include/uapi/drm/qxl_drm.h
index ebebd36c4117..4d1e32640463 100644
--- a/include/uapi/drm/qxl_drm.h
+++ b/include/uapi/drm/qxl_drm.h
@@ -24,13 +24,12 @@
#ifndef QXL_DRM_H
#define QXL_DRM_H
-#include <stddef.h>
-#include "drm/drm.h"
+#include "drm.h"
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
*
- * Do not use pointers, use uint64_t instead for 32 bit / 64 bit user/kernel
+ * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel
* compatibility Keep fields aligned to their size
*/
@@ -48,14 +47,14 @@
#define DRM_QXL_ALLOC_SURF 0x06
struct drm_qxl_alloc {
- uint32_t size;
- uint32_t handle; /* 0 is an invalid handle */
+ __u32 size;
+ __u32 handle; /* 0 is an invalid handle */
};
struct drm_qxl_map {
- uint64_t offset; /* use for mmap system call */
- uint32_t handle;
- uint32_t pad;
+ __u64 offset; /* use for mmap system call */
+ __u32 handle;
+ __u32 pad;
};
/*
@@ -68,59 +67,59 @@ struct drm_qxl_map {
#define QXL_RELOC_TYPE_SURF 2
struct drm_qxl_reloc {
- uint64_t src_offset; /* offset into src_handle or src buffer */
- uint64_t dst_offset; /* offset in dest handle */
- uint32_t src_handle; /* dest handle to compute address from */
- uint32_t dst_handle; /* 0 if to command buffer */
- uint32_t reloc_type;
- uint32_t pad;
+ __u64 src_offset; /* offset into src_handle or src buffer */
+ __u64 dst_offset; /* offset in dest handle */
+ __u32 src_handle; /* dest handle to compute address from */
+ __u32 dst_handle; /* 0 if to command buffer */
+ __u32 reloc_type;
+ __u32 pad;
};
struct drm_qxl_command {
- uint64_t __user command; /* void* */
- uint64_t __user relocs; /* struct drm_qxl_reloc* */
- uint32_t type;
- uint32_t command_size;
- uint32_t relocs_num;
- uint32_t pad;
+ __u64 __user command; /* void* */
+ __u64 __user relocs; /* struct drm_qxl_reloc* */
+ __u32 type;
+ __u32 command_size;
+ __u32 relocs_num;
+ __u32 pad;
};
/* XXX: call it drm_qxl_commands? */
struct drm_qxl_execbuffer {
- uint32_t flags; /* for future use */
- uint32_t commands_num;
- uint64_t __user commands; /* struct drm_qxl_command* */
+ __u32 flags; /* for future use */
+ __u32 commands_num;
+ __u64 __user commands; /* struct drm_qxl_command* */
};
struct drm_qxl_update_area {
- uint32_t handle;
- uint32_t top;
- uint32_t left;
- uint32_t bottom;
- uint32_t right;
- uint32_t pad;
+ __u32 handle;
+ __u32 top;
+ __u32 left;
+ __u32 bottom;
+ __u32 right;
+ __u32 pad;
};
#define QXL_PARAM_NUM_SURFACES 1 /* rom->n_surfaces */
#define QXL_PARAM_MAX_RELOCS 2
struct drm_qxl_getparam {
- uint64_t param;
- uint64_t value;
+ __u64 param;
+ __u64 value;
};
/* these are one bit values */
struct drm_qxl_clientcap {
- uint32_t index;
- uint32_t pad;
+ __u32 index;
+ __u32 pad;
};
struct drm_qxl_alloc_surf {
- uint32_t format;
- uint32_t width;
- uint32_t height;
- int32_t stride;
- uint32_t handle;
- uint32_t pad;
+ __u32 format;
+ __u32 width;
+ __u32 height;
+ __s32 stride;
+ __u32 handle;
+ __u32 pad;
};
#define DRM_IOCTL_QXL_ALLOC \
diff --git a/include/uapi/drm/r128_drm.h b/include/uapi/drm/r128_drm.h
index 76b0aa3e8210..7a44c6500a7e 100644
--- a/include/uapi/drm/r128_drm.h
+++ b/include/uapi/drm/r128_drm.h
@@ -33,7 +33,7 @@
#ifndef __R128_DRM_H__
#define __R128_DRM_H__
-#include <drm/drm.h>
+#include "drm.h"
/* WARNING: If you change any of these defines, make sure to change the
* defines in the X server file (r128_sarea.h)
diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h
index 01aa2a8e3f8d..ccb9bcd82685 100644
--- a/include/uapi/drm/radeon_drm.h
+++ b/include/uapi/drm/radeon_drm.h
@@ -793,9 +793,9 @@ typedef struct drm_radeon_surface_free {
#define RADEON_GEM_DOMAIN_VRAM 0x4
struct drm_radeon_gem_info {
- uint64_t gart_size;
- uint64_t vram_size;
- uint64_t vram_visible;
+ __u64 gart_size;
+ __u64 vram_size;
+ __u64 vram_visible;
};
#define RADEON_GEM_NO_BACKING_STORE (1 << 0)
@@ -807,11 +807,11 @@ struct drm_radeon_gem_info {
#define RADEON_GEM_NO_CPU_ACCESS (1 << 4)
struct drm_radeon_gem_create {
- uint64_t size;
- uint64_t alignment;
- uint32_t handle;
- uint32_t initial_domain;
- uint32_t flags;
+ __u64 size;
+ __u64 alignment;
+ __u32 handle;
+ __u32 initial_domain;
+ __u32 flags;
};
/*
@@ -825,10 +825,10 @@ struct drm_radeon_gem_create {
#define RADEON_GEM_USERPTR_REGISTER (1 << 3)
struct drm_radeon_gem_userptr {
- uint64_t addr;
- uint64_t size;
- uint32_t flags;
- uint32_t handle;
+ __u64 addr;
+ __u64 size;
+ __u32 flags;
+ __u32 handle;
};
#define RADEON_TILING_MACRO 0x1
@@ -850,72 +850,72 @@ struct drm_radeon_gem_userptr {
#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK 0xf
struct drm_radeon_gem_set_tiling {
- uint32_t handle;
- uint32_t tiling_flags;
- uint32_t pitch;
+ __u32 handle;
+ __u32 tiling_flags;
+ __u32 pitch;
};
struct drm_radeon_gem_get_tiling {
- uint32_t handle;
- uint32_t tiling_flags;
- uint32_t pitch;
+ __u32 handle;
+ __u32 tiling_flags;
+ __u32 pitch;
};
struct drm_radeon_gem_mmap {
- uint32_t handle;
- uint32_t pad;
- uint64_t offset;
- uint64_t size;
- uint64_t addr_ptr;
+ __u32 handle;
+ __u32 pad;
+ __u64 offset;
+ __u64 size;
+ __u64 addr_ptr;
};
struct drm_radeon_gem_set_domain {
- uint32_t handle;
- uint32_t read_domains;
- uint32_t write_domain;
+ __u32 handle;
+ __u32 read_domains;
+ __u32 write_domain;
};
struct drm_radeon_gem_wait_idle {
- uint32_t handle;
- uint32_t pad;
+ __u32 handle;
+ __u32 pad;
};
struct drm_radeon_gem_busy {
- uint32_t handle;
- uint32_t domain;
+ __u32 handle;
+ __u32 domain;
};
struct drm_radeon_gem_pread {
/** Handle for the object being read. */
- uint32_t handle;
- uint32_t pad;
+ __u32 handle;
+ __u32 pad;
/** Offset into the object to read from */
- uint64_t offset;
+ __u64 offset;
/** Length of data to read */
- uint64_t size;
+ __u64 size;
/** Pointer to write the data into. */
/* void *, but pointers are not 32/64 compatible */
- uint64_t data_ptr;
+ __u64 data_ptr;
};
struct drm_radeon_gem_pwrite {
/** Handle for the object being written to. */
- uint32_t handle;
- uint32_t pad;
+ __u32 handle;
+ __u32 pad;
/** Offset into the object to write to */
- uint64_t offset;
+ __u64 offset;
/** Length of data to write */
- uint64_t size;
+ __u64 size;
/** Pointer to read the data from. */
/* void *, but pointers are not 32/64 compatible */
- uint64_t data_ptr;
+ __u64 data_ptr;
};
/* Sets or returns a value associated with a buffer. */
struct drm_radeon_gem_op {
- uint32_t handle; /* buffer */
- uint32_t op; /* RADEON_GEM_OP_* */
- uint64_t value; /* input or return value */
+ __u32 handle; /* buffer */
+ __u32 op; /* RADEON_GEM_OP_* */
+ __u64 value; /* input or return value */
};
#define RADEON_GEM_OP_GET_INITIAL_DOMAIN 0
@@ -935,11 +935,11 @@ struct drm_radeon_gem_op {
#define RADEON_VM_PAGE_SNOOPED (1 << 4)
struct drm_radeon_gem_va {
- uint32_t handle;
- uint32_t operation;
- uint32_t vm_id;
- uint32_t flags;
- uint64_t offset;
+ __u32 handle;
+ __u32 operation;
+ __u32 vm_id;
+ __u32 flags;
+ __u64 offset;
};
#define RADEON_CHUNK_ID_RELOCS 0x01
@@ -961,29 +961,29 @@ struct drm_radeon_gem_va {
/* 0 = normal, + = higher priority, - = lower priority */
struct drm_radeon_cs_chunk {
- uint32_t chunk_id;
- uint32_t length_dw;
- uint64_t chunk_data;
+ __u32 chunk_id;
+ __u32 length_dw;
+ __u64 chunk_data;
};
/* drm_radeon_cs_reloc.flags */
#define RADEON_RELOC_PRIO_MASK (0xf << 0)
struct drm_radeon_cs_reloc {
- uint32_t handle;
- uint32_t read_domains;
- uint32_t write_domain;
- uint32_t flags;
+ __u32 handle;
+ __u32 read_domains;
+ __u32 write_domain;
+ __u32 flags;
};
struct drm_radeon_cs {
- uint32_t num_chunks;
- uint32_t cs_id;
- /* this points to uint64_t * which point to cs chunks */
- uint64_t chunks;
+ __u32 num_chunks;
+ __u32 cs_id;
+ /* this points to __u64 * which point to cs chunks */
+ __u64 chunks;
/* updates to the limits after this CS ioctl */
- uint64_t gart_limit;
- uint64_t vram_limit;
+ __u64 gart_limit;
+ __u64 vram_limit;
};
#define RADEON_INFO_DEVICE_ID 0x00
@@ -1042,9 +1042,9 @@ struct drm_radeon_cs {
#define RADEON_INFO_GPU_RESET_COUNTER 0x26
struct drm_radeon_info {
- uint32_t request;
- uint32_t pad;
- uint64_t value;
+ __u32 request;
+ __u32 pad;
+ __u64 value;
};
/* Those correspond to the tile index to use, this is to explicitly state
diff --git a/include/uapi/drm/savage_drm.h b/include/uapi/drm/savage_drm.h
index 9dc9dc1a7753..574147489c60 100644
--- a/include/uapi/drm/savage_drm.h
+++ b/include/uapi/drm/savage_drm.h
@@ -26,7 +26,7 @@
#ifndef __SAVAGE_DRM_H__
#define __SAVAGE_DRM_H__
-#include <drm/drm.h>
+#include "drm.h"
#ifndef __SAVAGE_SAREA_DEFINES__
#define __SAVAGE_SAREA_DEFINES__
diff --git a/include/uapi/drm/tegra_drm.h b/include/uapi/drm/tegra_drm.h
index 5391780c2b05..27d0b054aed0 100644
--- a/include/uapi/drm/tegra_drm.h
+++ b/include/uapi/drm/tegra_drm.h
@@ -23,7 +23,7 @@
#ifndef _UAPI_TEGRA_DRM_H_
#define _UAPI_TEGRA_DRM_H_
-#include <drm/drm.h>
+#include "drm.h"
#define DRM_TEGRA_GEM_CREATE_TILED (1 << 0)
#define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1)
diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h
new file mode 100644
index 000000000000..eeb37e394f13
--- /dev/null
+++ b/include/uapi/drm/vc4_drm.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright © 2014-2015 Broadcom
+ *
+ * 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.
+ */
+
+#ifndef _UAPI_VC4_DRM_H_
+#define _UAPI_VC4_DRM_H_
+
+#include "drm.h"
+
+#define DRM_VC4_SUBMIT_CL 0x00
+#define DRM_VC4_WAIT_SEQNO 0x01
+#define DRM_VC4_WAIT_BO 0x02
+#define DRM_VC4_CREATE_BO 0x03
+#define DRM_VC4_MMAP_BO 0x04
+#define DRM_VC4_CREATE_SHADER_BO 0x05
+#define DRM_VC4_GET_HANG_STATE 0x06
+
+#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
+#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
+#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo)
+#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo)
+#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo)
+#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo)
+#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state)
+
+struct drm_vc4_submit_rcl_surface {
+ __u32 hindex; /* Handle index, or ~0 if not present. */
+ __u32 offset; /* Offset to start of buffer. */
+ /*
+ * Bits for either render config (color_write) or load/store packet.
+ * Bits should all be 0 for MSAA load/stores.
+ */
+ __u16 bits;
+
+#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0)
+ __u16 flags;
+};
+
+/**
+ * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D
+ * engine.
+ *
+ * Drivers typically use GPU BOs to store batchbuffers / command lists and
+ * their associated state. However, because the VC4 lacks an MMU, we have to
+ * do validation of memory accesses by the GPU commands. If we were to store
+ * our commands in BOs, we'd need to do uncached readback from them to do the
+ * validation process, which is too expensive. Instead, userspace accumulates
+ * commands and associated state in plain memory, then the kernel copies the
+ * data to its own address space, and then validates and stores it in a GPU
+ * BO.
+ */
+struct drm_vc4_submit_cl {
+ /* Pointer to the binner command list.
+ *
+ * This is the first set of commands executed, which runs the
+ * 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.
+ */
+ __u64 bin_cl;
+
+ /* Pointer to the shader records.
+ *
+ * Shader records are the structures read by the hardware that contain
+ * pointers to uniforms, shaders, and vertex attributes. The
+ * reference to the shader record has enough information to determine
+ * how many pointers are necessary (fixed number for shaders/uniforms,
+ * and an attribute count), so those BO indices into bo_handles are
+ * just stored as __u32s before each shader record passed in.
+ */
+ __u64 shader_rec;
+
+ /* Pointer to uniform data and texture handles for the textures
+ * referenced by the shader.
+ *
+ * For each shader state record, there is a set of uniform data in the
+ * order referenced by the record (FS, VS, then CS). Each set of
+ * uniform data has a __u32 index into bo_handles per texture
+ * sample operation, in the order the QPU_W_TMUn_S writes appear in
+ * the program. Following the texture BO handle indices is the actual
+ * uniform data.
+ *
+ * The individual uniform state blocks don't have sizes passed in,
+ * because the kernel has to determine the sizes anyway during shader
+ * code validation.
+ */
+ __u64 uniforms;
+ __u64 bo_handles;
+
+ /* Size in bytes of the binner command list. */
+ __u32 bin_cl_size;
+ /* Size in bytes of the set of shader records. */
+ __u32 shader_rec_size;
+ /* Number of shader records.
+ *
+ * This could just be computed from the contents of shader_records and
+ * the address bits of references to them from the bin CL, but it
+ * keeps the kernel from having to resize some allocations it makes.
+ */
+ __u32 shader_rec_count;
+ /* Size in bytes of the uniform state. */
+ __u32 uniforms_size;
+
+ /* Number of BO handles passed in (size is that times 4). */
+ __u32 bo_handle_count;
+
+ /* RCL setup: */
+ __u16 width;
+ __u16 height;
+ __u8 min_x_tile;
+ __u8 min_y_tile;
+ __u8 max_x_tile;
+ __u8 max_y_tile;
+ struct drm_vc4_submit_rcl_surface color_read;
+ struct drm_vc4_submit_rcl_surface color_write;
+ struct drm_vc4_submit_rcl_surface zs_read;
+ struct drm_vc4_submit_rcl_surface zs_write;
+ struct drm_vc4_submit_rcl_surface msaa_color_write;
+ struct drm_vc4_submit_rcl_surface msaa_zs_write;
+ __u32 clear_color[2];
+ __u32 clear_z;
+ __u8 clear_s;
+
+ __u32 pad:24;
+
+#define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0)
+ __u32 flags;
+
+ /* Returned value of the seqno of this render job (for the
+ * wait ioctl).
+ */
+ __u64 seqno;
+};
+
+/**
+ * struct drm_vc4_wait_seqno - ioctl argument for waiting for
+ * DRM_VC4_SUBMIT_CL completion using its returned seqno.
+ *
+ * timeout_ns is the timeout in nanoseconds, where "0" means "don't
+ * block, just return the status."
+ */
+struct drm_vc4_wait_seqno {
+ __u64 seqno;
+ __u64 timeout_ns;
+};
+
+/**
+ * struct drm_vc4_wait_bo - ioctl argument for waiting for
+ * completion of the last DRM_VC4_SUBMIT_CL on a BO.
+ *
+ * This is useful for cases where multiple processes might be
+ * rendering to a BO and you want to wait for all rendering to be
+ * completed.
+ */
+struct drm_vc4_wait_bo {
+ __u32 handle;
+ __u32 pad;
+ __u64 timeout_ns;
+};
+
+/**
+ * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs.
+ *
+ * There are currently no values for the flags argument, but it may be
+ * used in a future extension.
+ */
+struct drm_vc4_create_bo {
+ __u32 size;
+ __u32 flags;
+ /** Returned GEM handle for the BO. */
+ __u32 handle;
+ __u32 pad;
+};
+
+/**
+ * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs.
+ *
+ * This doesn't actually perform an mmap. Instead, it returns the
+ * offset you need to use in an mmap on the DRM device node. This
+ * means that tools like valgrind end up knowing about the mapped
+ * memory.
+ *
+ * There are currently no values for the flags argument, but it may be
+ * used in a future extension.
+ */
+struct drm_vc4_mmap_bo {
+ /** Handle for the object being mapped. */
+ __u32 handle;
+ __u32 flags;
+ /** offset into the drm node to use for subsequent mmap call. */
+ __u64 offset;
+};
+
+/**
+ * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4
+ * shader BOs.
+ *
+ * Since allowing a shader to be overwritten while it's also being
+ * executed from would allow privlege escalation, shaders must be
+ * created using this ioctl, and they can't be mmapped later.
+ */
+struct drm_vc4_create_shader_bo {
+ /* Size of the data argument. */
+ __u32 size;
+ /* Flags, currently must be 0. */
+ __u32 flags;
+
+ /* Pointer to the data. */
+ __u64 data;
+
+ /** Returned GEM handle for the BO. */
+ __u32 handle;
+ /* Pad, must be 0. */
+ __u32 pad;
+};
+
+struct drm_vc4_get_hang_state_bo {
+ __u32 handle;
+ __u32 paddr;
+ __u32 size;
+ __u32 pad;
+};
+
+/**
+ * struct drm_vc4_hang_state - ioctl argument for collecting state
+ * from a GPU hang for analysis.
+*/
+struct drm_vc4_get_hang_state {
+ /** Pointer to array of struct drm_vc4_get_hang_state_bo. */
+ __u64 bo;
+ /**
+ * On input, the size of the bo array. Output is the number
+ * of bos to be returned.
+ */
+ __u32 bo_count;
+
+ __u32 start_bin, start_render;
+
+ __u32 ct0ca, ct0ea;
+ __u32 ct1ca, ct1ea;
+ __u32 ct0cs, ct1cs;
+ __u32 ct0ra0, ct1ra0;
+
+ __u32 bpca, bpcs;
+ __u32 bpoa, bpos;
+
+ __u32 vpmbase;
+
+ __u32 dbge;
+ __u32 fdbgo;
+ __u32 fdbgb;
+ __u32 fdbgr;
+ __u32 fdbgs;
+ __u32 errstat;
+
+ /* Pad that we may save more registers into in the future. */
+ __u32 pad[16];
+};
+
+#endif /* _UAPI_VC4_DRM_H_ */
diff --git a/include/uapi/drm/via_drm.h b/include/uapi/drm/via_drm.h
index 45bc80c3714b..fa21ed185520 100644
--- a/include/uapi/drm/via_drm.h
+++ b/include/uapi/drm/via_drm.h
@@ -24,7 +24,7 @@
#ifndef _VIA_DRM_H_
#define _VIA_DRM_H_
-#include <drm/drm.h>
+#include "drm.h"
/* WARNING: These defines must be the same as what the Xserver uses.
* if you change them, you must change the defines in the Xserver.
@@ -33,9 +33,6 @@
#ifndef _VIA_DEFINES_
#define _VIA_DEFINES_
-#ifndef __KERNEL__
-#include "via_drmclient.h"
-#endif
#define VIA_NR_SAREA_CLIPRECTS 8
#define VIA_NR_XVMC_PORTS 10
diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h
index fc9e2d6e5e2f..c74f1f90cb37 100644
--- a/include/uapi/drm/virtgpu_drm.h
+++ b/include/uapi/drm/virtgpu_drm.h
@@ -24,13 +24,12 @@
#ifndef VIRTGPU_DRM_H
#define VIRTGPU_DRM_H
-#include <stddef.h>
-#include "drm/drm.h"
+#include "drm.h"
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
*
- * Do not use pointers, use uint64_t instead for 32 bit / 64 bit user/kernel
+ * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel
* compatibility Keep fields aligned to their size
*/
@@ -45,88 +44,88 @@
#define DRM_VIRTGPU_GET_CAPS 0x09
struct drm_virtgpu_map {
- uint64_t offset; /* use for mmap system call */
- uint32_t handle;
- uint32_t pad;
+ __u64 offset; /* use for mmap system call */
+ __u32 handle;
+ __u32 pad;
};
struct drm_virtgpu_execbuffer {
- uint32_t flags; /* for future use */
- uint32_t size;
- uint64_t command; /* void* */
- uint64_t bo_handles;
- uint32_t num_bo_handles;
- uint32_t pad;
+ __u32 flags; /* for future use */
+ __u32 size;
+ __u64 command; /* void* */
+ __u64 bo_handles;
+ __u32 num_bo_handles;
+ __u32 pad;
};
#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
struct drm_virtgpu_getparam {
- uint64_t param;
- uint64_t value;
+ __u64 param;
+ __u64 value;
};
/* NO_BO flags? NO resource flag? */
/* resource flag for y_0_top */
struct drm_virtgpu_resource_create {
- uint32_t target;
- uint32_t format;
- uint32_t bind;
- uint32_t width;
- uint32_t height;
- uint32_t depth;
- uint32_t array_size;
- uint32_t last_level;
- uint32_t nr_samples;
- uint32_t flags;
- uint32_t bo_handle; /* if this is set - recreate a new resource attached to this bo ? */
- uint32_t res_handle; /* returned by kernel */
- uint32_t size; /* validate transfer in the host */
- uint32_t stride; /* validate transfer in the host */
+ __u32 target;
+ __u32 format;
+ __u32 bind;
+ __u32 width;
+ __u32 height;
+ __u32 depth;
+ __u32 array_size;
+ __u32 last_level;
+ __u32 nr_samples;
+ __u32 flags;
+ __u32 bo_handle; /* if this is set - recreate a new resource attached to this bo ? */
+ __u32 res_handle; /* returned by kernel */
+ __u32 size; /* validate transfer in the host */
+ __u32 stride; /* validate transfer in the host */
};
struct drm_virtgpu_resource_info {
- uint32_t bo_handle;
- uint32_t res_handle;
- uint32_t size;
- uint32_t stride;
+ __u32 bo_handle;
+ __u32 res_handle;
+ __u32 size;
+ __u32 stride;
};
struct drm_virtgpu_3d_box {
- uint32_t x;
- uint32_t y;
- uint32_t z;
- uint32_t w;
- uint32_t h;
- uint32_t d;
+ __u32 x;
+ __u32 y;
+ __u32 z;
+ __u32 w;
+ __u32 h;
+ __u32 d;
};
struct drm_virtgpu_3d_transfer_to_host {
- uint32_t bo_handle;
+ __u32 bo_handle;
struct drm_virtgpu_3d_box box;
- uint32_t level;
- uint32_t offset;
+ __u32 level;
+ __u32 offset;
};
struct drm_virtgpu_3d_transfer_from_host {
- uint32_t bo_handle;
+ __u32 bo_handle;
struct drm_virtgpu_3d_box box;
- uint32_t level;
- uint32_t offset;
+ __u32 level;
+ __u32 offset;
};
#define VIRTGPU_WAIT_NOWAIT 1 /* like it */
struct drm_virtgpu_3d_wait {
- uint32_t handle; /* 0 is an invalid handle */
- uint32_t flags;
+ __u32 handle; /* 0 is an invalid handle */
+ __u32 flags;
};
struct drm_virtgpu_get_caps {
- uint32_t cap_set_id;
- uint32_t cap_set_ver;
- uint64_t addr;
- uint32_t size;
- uint32_t pad;
+ __u32 cap_set_id;
+ __u32 cap_set_ver;
+ __u64 addr;
+ __u32 size;
+ __u32 pad;
};
#define DRM_IOCTL_VIRTGPU_MAP \
diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h
index 05b204954d16..5b68b4d10884 100644
--- a/include/uapi/drm/vmwgfx_drm.h
+++ b/include/uapi/drm/vmwgfx_drm.h
@@ -28,9 +28,7 @@
#ifndef __VMWGFX_DRM_H__
#define __VMWGFX_DRM_H__
-#ifndef __KERNEL__
-#include <drm/drm.h>
-#endif
+#include "drm.h"
#define DRM_VMW_MAX_SURFACE_FACES 6
#define DRM_VMW_MAX_MIP_LEVELS 24
@@ -111,9 +109,9 @@ enum drm_vmw_handle_type {
*/
struct drm_vmw_getparam_arg {
- uint64_t value;
- uint32_t param;
- uint32_t pad64;
+ __u64 value;
+ __u32 param;
+ __u32 pad64;
};
/*************************************************************************/
@@ -134,8 +132,8 @@ struct drm_vmw_getparam_arg {
*/
struct drm_vmw_context_arg {
- int32_t cid;
- uint32_t pad64;
+ __s32 cid;
+ __u32 pad64;
};
/*************************************************************************/
@@ -165,7 +163,7 @@ struct drm_vmw_context_arg {
* @mip_levels: Number of mip levels for each face.
* An unused face should have 0 encoded.
* @size_addr: Address of a user-space array of sruct drm_vmw_size
- * cast to an uint64_t for 32-64 bit compatibility.
+ * cast to an __u64 for 32-64 bit compatibility.
* The size of the array should equal the total number of mipmap levels.
* @shareable: Boolean whether other clients (as identified by file descriptors)
* may reference this surface.
@@ -177,12 +175,12 @@ struct drm_vmw_context_arg {
*/
struct drm_vmw_surface_create_req {
- uint32_t flags;
- uint32_t format;
- uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES];
- uint64_t size_addr;
- int32_t shareable;
- int32_t scanout;
+ __u32 flags;
+ __u32 format;
+ __u32 mip_levels[DRM_VMW_MAX_SURFACE_FACES];
+ __u64 size_addr;
+ __s32 shareable;
+ __s32 scanout;
};
/**
@@ -197,7 +195,7 @@ struct drm_vmw_surface_create_req {
*/
struct drm_vmw_surface_arg {
- int32_t sid;
+ __s32 sid;
enum drm_vmw_handle_type handle_type;
};
@@ -213,10 +211,10 @@ struct drm_vmw_surface_arg {
*/
struct drm_vmw_size {
- uint32_t width;
- uint32_t height;
- uint32_t depth;
- uint32_t pad64;
+ __u32 width;
+ __u32 height;
+ __u32 depth;
+ __u32 pad64;
};
/**
@@ -284,13 +282,13 @@ union drm_vmw_surface_reference_arg {
/**
* struct drm_vmw_execbuf_arg
*
- * @commands: User-space address of a command buffer cast to an uint64_t.
+ * @commands: User-space address of a command buffer cast to an __u64.
* @command-size: Size in bytes of the command buffer.
* @throttle-us: Sleep until software is less than @throttle_us
* microseconds ahead of hardware. The driver may round this value
* to the nearest kernel tick.
* @fence_rep: User-space address of a struct drm_vmw_fence_rep cast to an
- * uint64_t.
+ * __u64.
* @version: Allows expanding the execbuf ioctl parameters without breaking
* backwards compatibility, since user-space will always tell the kernel
* which version it uses.
@@ -302,14 +300,14 @@ union drm_vmw_surface_reference_arg {
#define DRM_VMW_EXECBUF_VERSION 2
struct drm_vmw_execbuf_arg {
- uint64_t commands;
- uint32_t command_size;
- uint32_t throttle_us;
- uint64_t fence_rep;
- uint32_t version;
- uint32_t flags;
- uint32_t context_handle;
- uint32_t pad64;
+ __u64 commands;
+ __u32 command_size;
+ __u32 throttle_us;
+ __u64 fence_rep;
+ __u32 version;
+ __u32 flags;
+ __u32 context_handle;
+ __u32 pad64;
};
/**
@@ -338,12 +336,12 @@ struct drm_vmw_execbuf_arg {
*/
struct drm_vmw_fence_rep {
- uint32_t handle;
- uint32_t mask;
- uint32_t seqno;
- uint32_t passed_seqno;
- uint32_t pad64;
- int32_t error;
+ __u32 handle;
+ __u32 mask;
+ __u32 seqno;
+ __u32 passed_seqno;
+ __u32 pad64;
+ __s32 error;
};
/*************************************************************************/
@@ -373,8 +371,8 @@ struct drm_vmw_fence_rep {
*/
struct drm_vmw_alloc_dmabuf_req {
- uint32_t size;
- uint32_t pad64;
+ __u32 size;
+ __u32 pad64;
};
/**
@@ -391,11 +389,11 @@ struct drm_vmw_alloc_dmabuf_req {
*/
struct drm_vmw_dmabuf_rep {
- uint64_t map_handle;
- uint32_t handle;
- uint32_t cur_gmr_id;
- uint32_t cur_gmr_offset;
- uint32_t pad64;
+ __u64 map_handle;
+ __u32 handle;
+ __u32 cur_gmr_id;
+ __u32 cur_gmr_offset;
+ __u32 pad64;
};
/**
@@ -428,8 +426,8 @@ union drm_vmw_alloc_dmabuf_arg {
*/
struct drm_vmw_unref_dmabuf_arg {
- uint32_t handle;
- uint32_t pad64;
+ __u32 handle;
+ __u32 pad64;
};
/*************************************************************************/
@@ -452,10 +450,10 @@ struct drm_vmw_unref_dmabuf_arg {
*/
struct drm_vmw_rect {
- int32_t x;
- int32_t y;
- uint32_t w;
- uint32_t h;
+ __s32 x;
+ __s32 y;
+ __u32 w;
+ __u32 h;
};
/**
@@ -477,21 +475,21 @@ struct drm_vmw_rect {
*/
struct drm_vmw_control_stream_arg {
- uint32_t stream_id;
- uint32_t enabled;
+ __u32 stream_id;
+ __u32 enabled;
- uint32_t flags;
- uint32_t color_key;
+ __u32 flags;
+ __u32 color_key;
- uint32_t handle;
- uint32_t offset;
- int32_t format;
- uint32_t size;
- uint32_t width;
- uint32_t height;
- uint32_t pitch[3];
+ __u32 handle;
+ __u32 offset;
+ __s32 format;
+ __u32 size;
+ __u32 width;
+ __u32 height;
+ __u32 pitch[3];
- uint32_t pad64;
+ __u32 pad64;
struct drm_vmw_rect src;
struct drm_vmw_rect dst;
};
@@ -519,12 +517,12 @@ struct drm_vmw_control_stream_arg {
*/
struct drm_vmw_cursor_bypass_arg {
- uint32_t flags;
- uint32_t crtc_id;
- int32_t xpos;
- int32_t ypos;
- int32_t xhot;
- int32_t yhot;
+ __u32 flags;
+ __u32 crtc_id;
+ __s32 xpos;
+ __s32 ypos;
+ __s32 xhot;
+ __s32 yhot;
};
/*************************************************************************/
@@ -542,8 +540,8 @@ struct drm_vmw_cursor_bypass_arg {
*/
struct drm_vmw_stream_arg {
- uint32_t stream_id;
- uint32_t pad64;
+ __u32 stream_id;
+ __u32 pad64;
};
/*************************************************************************/
@@ -565,7 +563,7 @@ struct drm_vmw_stream_arg {
/**
* struct drm_vmw_get_3d_cap_arg
*
- * @buffer: Pointer to a buffer for capability data, cast to an uint64_t
+ * @buffer: Pointer to a buffer for capability data, cast to an __u64
* @size: Max size to copy
*
* Input argument to the DRM_VMW_GET_3D_CAP_IOCTL
@@ -573,9 +571,9 @@ struct drm_vmw_stream_arg {
*/
struct drm_vmw_get_3d_cap_arg {
- uint64_t buffer;
- uint32_t max_size;
- uint32_t pad64;
+ __u64 buffer;
+ __u32 max_size;
+ __u32 pad64;
};
/*************************************************************************/
@@ -624,14 +622,14 @@ struct drm_vmw_get_3d_cap_arg {
*/
struct drm_vmw_fence_wait_arg {
- uint32_t handle;
- int32_t cookie_valid;
- uint64_t kernel_cookie;
- uint64_t timeout_us;
- int32_t lazy;
- int32_t flags;
- int32_t wait_options;
- int32_t pad64;
+ __u32 handle;
+ __s32 cookie_valid;
+ __u64 kernel_cookie;
+ __u64 timeout_us;
+ __s32 lazy;
+ __s32 flags;
+ __s32 wait_options;
+ __s32 pad64;
};
/*************************************************************************/
@@ -655,12 +653,12 @@ struct drm_vmw_fence_wait_arg {
*/
struct drm_vmw_fence_signaled_arg {
- uint32_t handle;
- uint32_t flags;
- int32_t signaled;
- uint32_t passed_seqno;
- uint32_t signaled_flags;
- uint32_t pad64;
+ __u32 handle;
+ __u32 flags;
+ __s32 signaled;
+ __u32 passed_seqno;
+ __u32 signaled_flags;
+ __u32 pad64;
};
/*************************************************************************/
@@ -681,8 +679,8 @@ struct drm_vmw_fence_signaled_arg {
*/
struct drm_vmw_fence_arg {
- uint32_t handle;
- uint32_t pad64;
+ __u32 handle;
+ __u32 pad64;
};
@@ -703,9 +701,9 @@ struct drm_vmw_fence_arg {
struct drm_vmw_event_fence {
struct drm_event base;
- uint64_t user_data;
- uint32_t tv_sec;
- uint32_t tv_usec;
+ __u64 user_data;
+ __u32 tv_sec;
+ __u32 tv_usec;
};
/*
@@ -717,17 +715,17 @@ struct drm_vmw_event_fence {
/**
* struct drm_vmw_fence_event_arg
*
- * @fence_rep: Pointer to fence_rep structure cast to uint64_t or 0 if
+ * @fence_rep: Pointer to fence_rep structure cast to __u64 or 0 if
* the fence is not supposed to be referenced by user-space.
* @user_info: Info to be delivered with the event.
* @handle: Attach the event to this fence only.
* @flags: A set of flags as defined above.
*/
struct drm_vmw_fence_event_arg {
- uint64_t fence_rep;
- uint64_t user_data;
- uint32_t handle;
- uint32_t flags;
+ __u64 fence_rep;
+ __u64 user_data;
+ __u32 handle;
+ __u32 flags;
};
@@ -747,7 +745,7 @@ struct drm_vmw_fence_event_arg {
* @sid: Surface id to present from.
* @dest_x: X placement coordinate for surface.
* @dest_y: Y placement coordinate for surface.
- * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t.
+ * @clips_ptr: Pointer to an array of clip rects cast to an __u64.
* @num_clips: Number of cliprects given relative to the framebuffer origin,
* in the same coordinate space as the frame buffer.
* @pad64: Unused 64-bit padding.
@@ -756,13 +754,13 @@ struct drm_vmw_fence_event_arg {
*/
struct drm_vmw_present_arg {
- uint32_t fb_id;
- uint32_t sid;
- int32_t dest_x;
- int32_t dest_y;
- uint64_t clips_ptr;
- uint32_t num_clips;
- uint32_t pad64;
+ __u32 fb_id;
+ __u32 sid;
+ __s32 dest_x;
+ __s32 dest_y;
+ __u64 clips_ptr;
+ __u32 num_clips;
+ __u32 pad64;
};
@@ -780,16 +778,16 @@ struct drm_vmw_present_arg {
* struct drm_vmw_present_arg
* @fb_id: fb_id to present / read back from.
* @num_clips: Number of cliprects.
- * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t.
- * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an uint64_t.
+ * @clips_ptr: Pointer to an array of clip rects cast to an __u64.
+ * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an __u64.
* If this member is NULL, then the ioctl should not return a fence.
*/
struct drm_vmw_present_readback_arg {
- uint32_t fb_id;
- uint32_t num_clips;
- uint64_t clips_ptr;
- uint64_t fence_rep;
+ __u32 fb_id;
+ __u32 num_clips;
+ __u64 clips_ptr;
+ __u64 fence_rep;
};
/*************************************************************************/
@@ -805,14 +803,14 @@ struct drm_vmw_present_readback_arg {
* struct drm_vmw_update_layout_arg
*
* @num_outputs: number of active connectors
- * @rects: pointer to array of drm_vmw_rect cast to an uint64_t
+ * @rects: pointer to array of drm_vmw_rect cast to an __u64
*
* Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
*/
struct drm_vmw_update_layout_arg {
- uint32_t num_outputs;
- uint32_t pad64;
- uint64_t rects;
+ __u32 num_outputs;
+ __u32 pad64;
+ __u64 rects;
};
@@ -849,10 +847,10 @@ enum drm_vmw_shader_type {
*/
struct drm_vmw_shader_create_arg {
enum drm_vmw_shader_type shader_type;
- uint32_t size;
- uint32_t buffer_handle;
- uint32_t shader_handle;
- uint64_t offset;
+ __u32 size;
+ __u32 buffer_handle;
+ __u32 shader_handle;
+ __u64 offset;
};
/*************************************************************************/
@@ -871,8 +869,8 @@ struct drm_vmw_shader_create_arg {
* Input argument to the DRM_VMW_UNREF_SHADER ioctl.
*/
struct drm_vmw_shader_arg {
- uint32_t handle;
- uint32_t pad64;
+ __u32 handle;
+ __u32 pad64;
};
/*************************************************************************/
@@ -918,14 +916,14 @@ enum drm_vmw_surface_flags {
* Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl.
*/
struct drm_vmw_gb_surface_create_req {
- uint32_t svga3d_flags;
- uint32_t format;
- uint32_t mip_levels;
+ __u32 svga3d_flags;
+ __u32 format;
+ __u32 mip_levels;
enum drm_vmw_surface_flags drm_surface_flags;
- uint32_t multisample_count;
- uint32_t autogen_filter;
- uint32_t buffer_handle;
- uint32_t array_size;
+ __u32 multisample_count;
+ __u32 autogen_filter;
+ __u32 buffer_handle;
+ __u32 array_size;
struct drm_vmw_size base_size;
};
@@ -944,11 +942,11 @@ struct drm_vmw_gb_surface_create_req {
* Output argument for the DRM_VMW_GB_SURFACE_CREATE ioctl.
*/
struct drm_vmw_gb_surface_create_rep {
- uint32_t handle;
- uint32_t backup_size;
- uint32_t buffer_handle;
- uint32_t buffer_size;
- uint64_t buffer_map_handle;
+ __u32 handle;
+ __u32 backup_size;
+ __u32 buffer_handle;
+ __u32 buffer_size;
+ __u64 buffer_map_handle;
};
/**
@@ -1061,8 +1059,8 @@ enum drm_vmw_synccpu_op {
struct drm_vmw_synccpu_arg {
enum drm_vmw_synccpu_op op;
enum drm_vmw_synccpu_flags flags;
- uint32_t handle;
- uint32_t pad64;
+ __u32 handle;
+ __u32 pad64;
};
/*************************************************************************/
diff --git a/include/uapi/linux/agpgart.h b/include/uapi/linux/agpgart.h
index 4e828cf487bc..f5251045181a 100644
--- a/include/uapi/linux/agpgart.h
+++ b/include/uapi/linux/agpgart.h
@@ -52,6 +52,7 @@
#ifndef __KERNEL__
#include <linux/types.h>
+#include <stdlib.h>
struct agp_version {
__u16 major;
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index b38e647664a0..b8a5b3b86ad6 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -188,6 +188,8 @@ struct inodes_stat_t {
#define BLKSECDISCARD _IO(0x12,125)
#define BLKROTATIONAL _IO(0x12,126)
#define BLKZEROOUT _IO(0x12,127)
+#define BLKDAXSET _IO(0x12,128)
+#define BLKDAXGET _IO(0x12,129)
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP _IO(0x00,1) /* bmap access */
diff --git a/include/uapi/linux/hash_info.h b/include/uapi/linux/hash_info.h
index ca18c45f8304..ebf8fd885dd5 100644
--- a/include/uapi/linux/hash_info.h
+++ b/include/uapi/linux/hash_info.h
@@ -31,6 +31,7 @@ enum hash_algo {
HASH_ALGO_TGR_128,
HASH_ALGO_TGR_160,
HASH_ALGO_TGR_192,
+ HASH_ALGO_SM3_256,
HASH_ALGO__LAST
};
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
index e4c0a35d6417..e347b24ef9fb 100644
--- a/include/uapi/linux/hyperv.h
+++ b/include/uapi/linux/hyperv.h
@@ -313,6 +313,7 @@ enum hv_kvp_exchg_pool {
#define HV_INVALIDARG 0x80070057
#define HV_GUID_NOTFOUND 0x80041002
#define HV_ERROR_ALREADY_EXISTS 0x80070050
+#define HV_ERROR_DISK_FULL 0x80070070
#define ADDR_FAMILY_NONE 0x00
#define ADDR_FAMILY_IPV4 0x01
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 4e816be3de39..1e3c8cb43bd7 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -23,6 +23,9 @@
#ifndef __LINUX_MEDIA_H
#define __LINUX_MEDIA_H
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/version.h>
@@ -42,33 +45,107 @@ struct media_device_info {
#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31)
+/*
+ * Initial value to be used when a new entity is created
+ * Drivers should change it to something useful
+ */
+#define MEDIA_ENT_F_UNKNOWN 0x00000000
+
+/*
+ * Base number ranges for entity functions
+ *
+ * NOTE: those ranges and entity function number are phased just to
+ * make it easier to maintain this file. Userspace should not rely on
+ * the ranges to identify a group of function types, as newer
+ * functions can be added with any name within the full u32 range.
+ */
+#define MEDIA_ENT_F_BASE 0x00000000
+#define MEDIA_ENT_F_OLD_BASE 0x00010000
+#define MEDIA_ENT_F_OLD_SUBDEV_BASE 0x00020000
+
+/*
+ * DVB entities
+ */
+#define MEDIA_ENT_F_DTV_DEMOD (MEDIA_ENT_F_BASE + 1)
+#define MEDIA_ENT_F_TS_DEMUX (MEDIA_ENT_F_BASE + 2)
+#define MEDIA_ENT_F_DTV_CA (MEDIA_ENT_F_BASE + 3)
+#define MEDIA_ENT_F_DTV_NET_DECAP (MEDIA_ENT_F_BASE + 4)
+
+/*
+ * Connectors
+ */
+/* It is a responsibility of the entity drivers to add connectors and links */
+#define MEDIA_ENT_F_CONN_RF (MEDIA_ENT_F_BASE + 21)
+#define MEDIA_ENT_F_CONN_SVIDEO (MEDIA_ENT_F_BASE + 22)
+#define MEDIA_ENT_F_CONN_COMPOSITE (MEDIA_ENT_F_BASE + 23)
+/* For internal test signal generators and other debug connectors */
+#define MEDIA_ENT_F_CONN_TEST (MEDIA_ENT_F_BASE + 24)
+
+/*
+ * I/O entities
+ */
+#define MEDIA_ENT_F_IO_DTV (MEDIA_ENT_F_BASE + 31)
+#define MEDIA_ENT_F_IO_VBI (MEDIA_ENT_F_BASE + 32)
+#define MEDIA_ENT_F_IO_SWRADIO (MEDIA_ENT_F_BASE + 33)
+
+/*
+ * Don't touch on those. The ranges MEDIA_ENT_F_OLD_BASE and
+ * MEDIA_ENT_F_OLD_SUBDEV_BASE are kept to keep backward compatibility
+ * with the legacy v1 API.The number range is out of range by purpose:
+ * several previously reserved numbers got excluded from this range.
+ *
+ * Subdevs are initialized with MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN,
+ * in order to preserve backward compatibility.
+ * Drivers must change to the proper subdev type before
+ * registering the entity.
+ */
+
+#define MEDIA_ENT_F_IO_V4L (MEDIA_ENT_F_OLD_BASE + 1)
+
+#define MEDIA_ENT_F_CAM_SENSOR (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1)
+#define MEDIA_ENT_F_FLASH (MEDIA_ENT_F_OLD_SUBDEV_BASE + 2)
+#define MEDIA_ENT_F_LENS (MEDIA_ENT_F_OLD_SUBDEV_BASE + 3)
+#define MEDIA_ENT_F_ATV_DECODER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 4)
+/*
+ * It is a responsibility of the entity drivers to add connectors and links
+ * for the tuner entities.
+ */
+#define MEDIA_ENT_F_TUNER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 5)
+
+#define MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN MEDIA_ENT_F_OLD_SUBDEV_BASE
+
+#ifndef __KERNEL__
+
+/*
+ * Legacy symbols used to avoid userspace compilation breakages
+ *
+ * Those symbols map the entity function into types and should be
+ * used only on legacy programs for legacy hardware. Don't rely
+ * on those for MEDIA_IOC_G_TOPOLOGY.
+ */
#define MEDIA_ENT_TYPE_SHIFT 16
#define MEDIA_ENT_TYPE_MASK 0x00ff0000
#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
-#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENT_TYPE_SHIFT)
-#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1)
+#define MEDIA_ENT_T_DEVNODE MEDIA_ENT_F_OLD_BASE
+#define MEDIA_ENT_T_DEVNODE_V4L MEDIA_ENT_F_IO_V4L
#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2)
#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3)
-#define MEDIA_ENT_T_DEVNODE_DVB_FE (MEDIA_ENT_T_DEVNODE + 4)
-#define MEDIA_ENT_T_DEVNODE_DVB_DEMUX (MEDIA_ENT_T_DEVNODE + 5)
-#define MEDIA_ENT_T_DEVNODE_DVB_DVR (MEDIA_ENT_T_DEVNODE + 6)
-#define MEDIA_ENT_T_DEVNODE_DVB_CA (MEDIA_ENT_T_DEVNODE + 7)
-#define MEDIA_ENT_T_DEVNODE_DVB_NET (MEDIA_ENT_T_DEVNODE + 8)
-
-/* Legacy symbol. Use it to avoid userspace compilation breakages */
-#define MEDIA_ENT_T_DEVNODE_DVB MEDIA_ENT_T_DEVNODE_DVB_FE
-
-#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT)
-#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1)
-#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2)
-#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3)
-/* A converter of analogue video to its digital representation. */
-#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4)
+#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4)
-#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER (MEDIA_ENT_T_V4L2_SUBDEV + 5)
+#define MEDIA_ENT_T_UNKNOWN MEDIA_ENT_F_UNKNOWN
+#define MEDIA_ENT_T_V4L2_VIDEO MEDIA_ENT_F_IO_V4L
+#define MEDIA_ENT_T_V4L2_SUBDEV MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN
+#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR MEDIA_ENT_F_CAM_SENSOR
+#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH MEDIA_ENT_F_FLASH
+#define MEDIA_ENT_T_V4L2_SUBDEV_LENS MEDIA_ENT_F_LENS
+#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER MEDIA_ENT_F_ATV_DECODER
+#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER MEDIA_ENT_F_TUNER
+#endif
+/* Entity flags */
#define MEDIA_ENT_FL_DEFAULT (1 << 0)
+#define MEDIA_ENT_FL_CONNECTOR (1 << 1)
struct media_entity_desc {
__u32 id;
@@ -151,6 +228,10 @@ struct media_pad_desc {
#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
#define MEDIA_LNK_FL_DYNAMIC (1 << 2)
+#define MEDIA_LNK_FL_LINK_TYPE (0xf << 28)
+# define MEDIA_LNK_FL_DATA_LINK (0 << 28)
+# define MEDIA_LNK_FL_INTERFACE_LINK (1 << 28)
+
struct media_link_desc {
struct media_pad_desc source;
struct media_pad_desc sink;
@@ -167,9 +248,120 @@ struct media_links_enum {
__u32 reserved[4];
};
+/* Interface type ranges */
+
+#define MEDIA_INTF_T_DVB_BASE 0x00000100
+#define MEDIA_INTF_T_V4L_BASE 0x00000200
+
+/* Interface types */
+
+#define MEDIA_INTF_T_DVB_FE (MEDIA_INTF_T_DVB_BASE)
+#define MEDIA_INTF_T_DVB_DEMUX (MEDIA_INTF_T_DVB_BASE + 1)
+#define MEDIA_INTF_T_DVB_DVR (MEDIA_INTF_T_DVB_BASE + 2)
+#define MEDIA_INTF_T_DVB_CA (MEDIA_INTF_T_DVB_BASE + 3)
+#define MEDIA_INTF_T_DVB_NET (MEDIA_INTF_T_DVB_BASE + 4)
+
+#define MEDIA_INTF_T_V4L_VIDEO (MEDIA_INTF_T_V4L_BASE)
+#define MEDIA_INTF_T_V4L_VBI (MEDIA_INTF_T_V4L_BASE + 1)
+#define MEDIA_INTF_T_V4L_RADIO (MEDIA_INTF_T_V4L_BASE + 2)
+#define MEDIA_INTF_T_V4L_SUBDEV (MEDIA_INTF_T_V4L_BASE + 3)
+#define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4)
+
+/*
+ * MC next gen API definitions
+ *
+ * NOTE: The declarations below are close to the MC RFC for the Media
+ * Controller, the next generation. Yet, there are a few adjustments
+ * to do, as we want to be able to have a functional API before
+ * the MC properties change. Those will be properly marked below.
+ * Please also notice that I removed "num_pads", "num_links",
+ * from the proposal, as a proper userspace application will likely
+ * use lists for pads/links, just as we intend to do in Kernelspace.
+ * The API definition should be freed from fields that are bound to
+ * some specific data structure.
+ *
+ * FIXME: Currently, I opted to name the new types as "media_v2", as this
+ * won't cause any conflict with the Kernelspace namespace, nor with
+ * the previous kAPI media_*_desc namespace. This can be changed
+ * later, before the adding this API upstream.
+ */
+
+#if 0 /* Let's postpone it to Kernel 4.6 */
+struct media_v2_entity {
+ __u32 id;
+ char name[64]; /* FIXME: move to a property? (RFC says so) */
+ __u32 function; /* Main function of the entity */
+ __u16 reserved[12];
+};
+
+/* Should match the specific fields at media_intf_devnode */
+struct media_v2_intf_devnode {
+ __u32 major;
+ __u32 minor;
+};
+
+struct media_v2_interface {
+ __u32 id;
+ __u32 intf_type;
+ __u32 flags;
+ __u32 reserved[9];
+
+ union {
+ struct media_v2_intf_devnode devnode;
+ __u32 raw[16];
+ };
+};
+
+struct media_v2_pad {
+ __u32 id;
+ __u32 entity_id;
+ __u32 flags;
+ __u16 reserved[9];
+};
+
+struct media_v2_link {
+ __u32 id;
+ __u32 source_id;
+ __u32 sink_id;
+ __u32 flags;
+ __u32 reserved[5];
+};
+
+struct media_v2_topology {
+ __u64 topology_version;
+
+ __u32 num_entities;
+ __u32 reserved1;
+ __u64 ptr_entities;
+
+ __u32 num_interfaces;
+ __u32 reserved2;
+ __u64 ptr_interfaces;
+
+ __u32 num_pads;
+ __u32 reserved3;
+ __u64 ptr_pads;
+
+ __u32 num_links;
+ __u32 reserved4;
+ __u64 ptr_links;
+};
+
+static inline void __user *media_get_uptr(__u64 arg)
+{
+ return (void __user *)(uintptr_t)arg;
+}
+#endif
+
+/* ioctls */
+
#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info)
#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc)
#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum)
#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc)
+#if 0 /* Let's postpone it to Kernel 4.6 */
+#define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology)
+#endif
+
#endif /* __LINUX_MEDIA_H */
diff --git a/include/uapi/linux/raid/md_u.h b/include/uapi/linux/raid/md_u.h
index 1cb8aa6850b5..36cd8210a5d1 100644
--- a/include/uapi/linux/raid/md_u.h
+++ b/include/uapi/linux/raid/md_u.h
@@ -80,7 +80,7 @@ typedef struct mdu_array_info_s {
int major_version;
int minor_version;
int patch_version;
- int ctime;
+ unsigned int ctime;
int level;
int size;
int nr_disks;
@@ -91,7 +91,7 @@ typedef struct mdu_array_info_s {
/*
* Generic state information
*/
- int utime; /* 0 Superblock update time */
+ unsigned int utime; /* 0 Superblock update time */
int state; /* 1 State bits (clean, ...) */
int active_disks; /* 2 Number of currently active disks */
int working_disks; /* 3 Number of working disks */
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 25331f9faa76..5d59c3ebf459 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -69,6 +69,7 @@ struct serial_struct {
#define SERIAL_IO_AU 4
#define SERIAL_IO_TSI 5
#define SERIAL_IO_MEM32BE 6
+#define SERIAL_IO_MEM16 7
#define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 93ba148f923e..3e5d757407fb 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -176,7 +176,7 @@
#define PORT_S3C6400 84
-/* NWPSERIAL */
+/* NWPSERIAL, now removed */
#define PORT_NWPSERIAL 85
/* MAX3100 */
diff --git a/include/uapi/linux/serio.h b/include/uapi/linux/serio.h
index becdd78295cc..c2ea1698257f 100644
--- a/include/uapi/linux/serio.h
+++ b/include/uapi/linux/serio.h
@@ -77,5 +77,6 @@
#define SERIO_PS2MULT 0x3c
#define SERIO_TSC40 0x3d
#define SERIO_WACOM_IV 0x3e
+#define SERIO_EGALAX 0x3f
#endif /* _UAPI_SERIO_H */
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index 013c9d8db372..dc652e224b67 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -20,6 +20,11 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
+ * 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
+ * Benjamin Tissoires <benjamin.tissoires@redhat.com>)
+ * - add UI_DEV_SETUP ioctl
+ * - add UI_ABS_SETUP ioctl
+ * - add UI_GET_VERSION ioctl
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
@@ -37,8 +42,8 @@
#include <linux/types.h>
#include <linux/input.h>
-#define UINPUT_VERSION 4
-
+#define UINPUT_VERSION 5
+#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload {
__u32 request_id;
@@ -58,6 +63,76 @@ struct uinput_ff_erase {
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
+struct uinput_setup {
+ struct input_id id;
+ char name[UINPUT_MAX_NAME_SIZE];
+ __u32 ff_effects_max;
+};
+
+/**
+ * UI_DEV_SETUP - Set device parameters for setup
+ *
+ * This ioctl sets parameters for the input device to be created. It
+ * supersedes the old "struct uinput_user_dev" method, which wrote this data
+ * via write(). To actually set the absolute axes UI_ABS_SETUP should be
+ * used.
+ *
+ * The ioctl takes a "struct uinput_setup" object as argument. The fields of
+ * this object are as follows:
+ * id: See the description of "struct input_id". This field is
+ * copied unchanged into the new device.
+ * name: This is used unchanged as name for the new device.
+ * ff_effects_max: This limits the maximum numbers of force-feedback effects.
+ * See below for a description of FF with uinput.
+ *
+ * This ioctl can be called multiple times and will overwrite previous values.
+ * If this ioctl fails with -EINVAL, it is recommended to use the old
+ * "uinput_user_dev" method via write() as a fallback, in case you run on an
+ * old kernel that does not support this ioctl.
+ *
+ * This ioctl may fail with -EINVAL if it is not supported or if you passed
+ * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
+ * passed uinput_setup object cannot be read/written.
+ * If this call fails, partial data may have already been applied to the
+ * internal device.
+ */
+#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
+
+struct uinput_abs_setup {
+ __u16 code; /* axis code */
+ /* __u16 filler; */
+ struct input_absinfo absinfo;
+};
+
+/**
+ * UI_ABS_SETUP - Set absolute axis information for the device to setup
+ *
+ * This ioctl sets one absolute axis information for the input device to be
+ * created. It supersedes the old "struct uinput_user_dev" method, which wrote
+ * part of this data and the content of UI_DEV_SETUP via write().
+ *
+ * The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
+ * of this object are as follows:
+ * code: The corresponding input code associated with this axis
+ * (ABS_X, ABS_Y, etc...)
+ * absinfo: See "struct input_absinfo" for a description of this field.
+ * This field is copied unchanged into the kernel for the
+ * specified axis. If the axis is not enabled via
+ * UI_SET_ABSBIT, this ioctl will enable it.
+ *
+ * This ioctl can be called multiple times and will overwrite previous values.
+ * If this ioctl fails with -EINVAL, it is recommended to use the old
+ * "uinput_user_dev" method via write() as a fallback, in case you run on an
+ * old kernel that does not support this ioctl.
+ *
+ * This ioctl may fail with -EINVAL if it is not supported or if you passed
+ * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
+ * passed uinput_setup object cannot be read/written.
+ * If this call fails, partial data may have already been applied to the
+ * internal device.
+ */
+#define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
+
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
@@ -144,7 +219,6 @@ struct uinput_ff_erase {
#define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2
-#define UINPUT_MAX_NAME_SIZE 80
struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE];
struct input_id id;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 9fd7b5d8df2f..7d7a4c6f2090 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -39,6 +39,13 @@
#define VFIO_SPAPR_TCE_v2_IOMMU 7
/*
+ * The No-IOMMU IOMMU offers no translation or isolation for devices and
+ * supports no ioctls outside of VFIO_CHECK_EXTENSION. Use of VFIO's No-IOMMU
+ * code will taint the host kernel and should be used with extreme caution.
+ */
+#define VFIO_NOIOMMU_IOMMU 8
+
+/*
* The IOCTL interface is designed for extensibility by embedding the
* structure length (argsz) and flags into structures passed between
* kernel and userspace. We therefore use the _IO() macro for these
@@ -568,8 +575,10 @@ struct vfio_iommu_spapr_tce_create {
__u32 flags;
/* in */
__u32 page_shift;
+ __u32 __resv1;
__u64 window_size;
__u32 levels;
+ __u32 __resv2;
/* out */
__u64 start_addr;
};
diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h
index 7a63faa9065c..4b04ead26cd9 100644
--- a/include/uapi/linux/virtio_gpu.h
+++ b/include/uapi/linux/virtio_gpu.h
@@ -287,7 +287,7 @@ struct virtio_gpu_get_capset {
/* VIRTIO_GPU_RESP_OK_CAPSET */
struct virtio_gpu_resp_capset {
struct virtio_gpu_ctrl_hdr hdr;
- uint8_t capset_data[];
+ __u8 capset_data[];
};
#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
diff --git a/include/uapi/rdma/hfi/hfi1_user.h b/include/uapi/rdma/hfi/hfi1_user.h
index 599562fe5d57..288694e422fb 100644
--- a/include/uapi/rdma/hfi/hfi1_user.h
+++ b/include/uapi/rdma/hfi/hfi1_user.h
@@ -127,35 +127,33 @@
#define HFI1_CMD_TID_UPDATE 4 /* update expected TID entries */
#define HFI1_CMD_TID_FREE 5 /* free expected TID entries */
#define HFI1_CMD_CREDIT_UPD 6 /* force an update of PIO credit */
-#define HFI1_CMD_SDMA_STATUS_UPD 7 /* force update of SDMA status ring */
+#define HFI1_CMD_SDMA_STATUS_UPD 7 /* force update of SDMA status ring */
#define HFI1_CMD_RECV_CTRL 8 /* control receipt of packets */
#define HFI1_CMD_POLL_TYPE 9 /* set the kind of polling we want */
#define HFI1_CMD_ACK_EVENT 10 /* ack & clear user status bits */
-#define HFI1_CMD_SET_PKEY 11 /* set context's pkey */
-#define HFI1_CMD_CTXT_RESET 12 /* reset context's HW send context */
+#define HFI1_CMD_SET_PKEY 11 /* set context's pkey */
+#define HFI1_CMD_CTXT_RESET 12 /* reset context's HW send context */
/* separate EPROM commands from normal PSM commands */
#define HFI1_CMD_EP_INFO 64 /* read EPROM device ID */
#define HFI1_CMD_EP_ERASE_CHIP 65 /* erase whole EPROM */
-#define HFI1_CMD_EP_ERASE_P0 66 /* erase EPROM partition 0 */
-#define HFI1_CMD_EP_ERASE_P1 67 /* erase EPROM partition 1 */
-#define HFI1_CMD_EP_READ_P0 68 /* read EPROM partition 0 */
-#define HFI1_CMD_EP_READ_P1 69 /* read EPROM partition 1 */
-#define HFI1_CMD_EP_WRITE_P0 70 /* write EPROM partition 0 */
-#define HFI1_CMD_EP_WRITE_P1 71 /* write EPROM partition 1 */
-
-#define _HFI1_EVENT_FROZEN_BIT 0
-#define _HFI1_EVENT_LINKDOWN_BIT 1
-#define _HFI1_EVENT_LID_CHANGE_BIT 2
-#define _HFI1_EVENT_LMC_CHANGE_BIT 3
-#define _HFI1_EVENT_SL2VL_CHANGE_BIT 4
+/* range 66-74 no longer used */
+#define HFI1_CMD_EP_ERASE_RANGE 75 /* erase EPROM range */
+#define HFI1_CMD_EP_READ_RANGE 76 /* read EPROM range */
+#define HFI1_CMD_EP_WRITE_RANGE 77 /* write EPROM range */
+
+#define _HFI1_EVENT_FROZEN_BIT 0
+#define _HFI1_EVENT_LINKDOWN_BIT 1
+#define _HFI1_EVENT_LID_CHANGE_BIT 2
+#define _HFI1_EVENT_LMC_CHANGE_BIT 3
+#define _HFI1_EVENT_SL2VL_CHANGE_BIT 4
#define _HFI1_MAX_EVENT_BIT _HFI1_EVENT_SL2VL_CHANGE_BIT
-#define HFI1_EVENT_FROZEN (1UL << _HFI1_EVENT_FROZEN_BIT)
-#define HFI1_EVENT_LINKDOWN_BIT (1UL << _HFI1_EVENT_LINKDOWN_BIT)
-#define HFI1_EVENT_LID_CHANGE_BIT (1UL << _HFI1_EVENT_LID_CHANGE_BIT)
-#define HFI1_EVENT_LMC_CHANGE_BIT (1UL << _HFI1_EVENT_LMC_CHANGE_BIT)
-#define HFI1_EVENT_SL2VL_CHANGE_BIT (1UL << _HFI1_EVENT_SL2VL_CHANGE_BIT)
+#define HFI1_EVENT_FROZEN (1UL << _HFI1_EVENT_FROZEN_BIT)
+#define HFI1_EVENT_LINKDOWN (1UL << _HFI1_EVENT_LINKDOWN_BIT)
+#define HFI1_EVENT_LID_CHANGE (1UL << _HFI1_EVENT_LID_CHANGE_BIT)
+#define HFI1_EVENT_LMC_CHANGE (1UL << _HFI1_EVENT_LMC_CHANGE_BIT)
+#define HFI1_EVENT_SL2VL_CHANGE (1UL << _HFI1_EVENT_SL2VL_CHANGE_BIT)
/*
* These are the status bits readable (in ASCII form, 64bit value)
diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h
index 831351b2e660..2302f3ce5f86 100644
--- a/include/uapi/scsi/cxlflash_ioctl.h
+++ b/include/uapi/scsi/cxlflash_ioctl.h
@@ -31,6 +31,16 @@ struct dk_cxlflash_hdr {
};
/*
+ * Return flag definitions available to all ioctls
+ *
+ * Similar to the input flags, these are grown from the bottom-up with the
+ * intention that ioctl-specific return flag definitions would grow from the
+ * top-down, allowing the two sets to co-exist. While not required/enforced
+ * at this time, this provides future flexibility.
+ */
+#define DK_CXLFLASH_ALL_PORTS_ACTIVE 0x0000000000000001ULL
+
+/*
* Notes:
* -----
* The 'context_id' field of all ioctl structures contains the context
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h
index 26539a7e4880..c4cc1e40b35c 100644
--- a/include/uapi/sound/asoc.h
+++ b/include/uapi/sound/asoc.h
@@ -243,7 +243,7 @@ struct snd_soc_tplg_manifest {
__le32 control_elems; /* number of control elements */
__le32 widget_elems; /* number of widget elements */
__le32 graph_elems; /* number of graph elements */
- __le32 dai_elems; /* number of DAI elements */
+ __le32 pcm_elems; /* number of PCM elements */
__le32 dai_link_elems; /* number of DAI link elements */
struct snd_soc_tplg_private priv;
} __attribute__((packed));
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index d9bd9ca0d5b0..9625484a4a2a 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -73,7 +73,8 @@
#define SND_AUDIOCODEC_IEC61937 ((__u32) 0x0000000B)
#define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C)
#define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D)
-#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_G729
+#define SND_AUDIOCODEC_BESPOKE ((__u32) 0x0000000E)
+#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_BESPOKE
/*
* Profile and modes are listed with bit masks. This allows for a
@@ -312,7 +313,7 @@ struct snd_enc_flac {
struct snd_enc_generic {
__u32 bw; /* encoder bandwidth */
- __s32 reserved[15];
+ __s32 reserved[15]; /* Can be used for SND_AUDIOCODEC_BESPOKE */
} __attribute__((packed, aligned(4)));
union snd_codec_options {
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index f001a356fd98..295b41e20d8e 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -87,6 +87,7 @@ enum omap_channel {
OMAP_DSS_CHANNEL_DIGIT = 1,
OMAP_DSS_CHANNEL_LCD2 = 2,
OMAP_DSS_CHANNEL_LCD3 = 3,
+ OMAP_DSS_CHANNEL_WB = 4,
};
enum omap_color_mode {
@@ -367,14 +368,12 @@ struct omap_video_timings {
enum omap_dss_signal_edge sync_pclk_edge;
};
-#ifdef CONFIG_OMAP2_DSS_VENC
/* Hardcoded timings for tv modes. Venc only uses these to
* identify the mode, and does not actually use the configs
* itself. However, the configs should be something that
* a normal monitor can also show */
extern const struct omap_video_timings omap_dss_pal_timings;
extern const struct omap_video_timings omap_dss_ntsc_timings;
-#endif
struct omap_dss_cpr_coefs {
s16 rr, rg, rb;
@@ -866,8 +865,6 @@ void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
-enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
-enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
diff --git a/include/video/sh_mobile_hdmi.h b/include/video/sh_mobile_hdmi.h
deleted file mode 100644
index 63d20efa254a..000000000000
--- a/include/video/sh_mobile_hdmi.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SH-Mobile High-Definition Multimedia Interface (HDMI)
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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 SH_MOBILE_HDMI_H
-#define SH_MOBILE_HDMI_H
-
-struct sh_mobile_lcdc_chan_cfg;
-struct device;
-struct clk;
-
-/*
- * flags format
- *
- * 0x00000CBA
- *
- * A: Audio source select
- * B: Int output option
- * C: Chip specific option
- */
-
-/* Audio source select */
-#define HDMI_SND_SRC_MASK (0xF << 0)
-#define HDMI_SND_SRC_I2S (0 << 0) /* default */
-#define HDMI_SND_SRC_SPDIF (1 << 0)
-#define HDMI_SND_SRC_DSD (2 << 0)
-#define HDMI_SND_SRC_HBR (3 << 0)
-
-/* Int output option */
-#define HDMI_OUTPUT_PUSH_PULL (1 << 4) /* System control : output mode */
-#define HDMI_OUTPUT_POLARITY_HI (1 << 5) /* System control : output polarity */
-
-/* Chip specific option */
-#define HDMI_32BIT_REG (1 << 8)
-#define HDMI_HAS_HTOP1 (1 << 9)
-
-struct sh_mobile_hdmi_info {
- unsigned int flags;
- long (*clk_optimize_parent)(unsigned long target, unsigned long *best_freq,
- unsigned long *parent_freq);
-};
-
-#endif
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
index 7dc685b4057d..21f4fbd55e48 100644
--- a/include/xen/interface/io/ring.h
+++ b/include/xen/interface/io/ring.h
@@ -208,12 +208,12 @@ struct __name##_back_ring { \
#define RING_PUSH_REQUESTS(_r) do { \
- wmb(); /* back sees requests /before/ updated producer index */ \
+ virt_wmb(); /* back sees requests /before/ updated producer index */ \
(_r)->sring->req_prod = (_r)->req_prod_pvt; \
} while (0)
#define RING_PUSH_RESPONSES(_r) do { \
- wmb(); /* front sees responses /before/ updated producer index */ \
+ virt_wmb(); /* front sees responses /before/ updated producer index */ \
(_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
} while (0)
@@ -250,9 +250,9 @@ struct __name##_back_ring { \
#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \
RING_IDX __old = (_r)->sring->req_prod; \
RING_IDX __new = (_r)->req_prod_pvt; \
- wmb(); /* back sees requests /before/ updated producer index */ \
+ virt_wmb(); /* back sees requests /before/ updated producer index */ \
(_r)->sring->req_prod = __new; \
- mb(); /* back sees new requests /before/ we check req_event */ \
+ virt_mb(); /* back sees new requests /before/ we check req_event */ \
(_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \
(RING_IDX)(__new - __old)); \
} while (0)
@@ -260,9 +260,9 @@ struct __name##_back_ring { \
#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \
RING_IDX __old = (_r)->sring->rsp_prod; \
RING_IDX __new = (_r)->rsp_prod_pvt; \
- wmb(); /* front sees responses /before/ updated producer index */ \
+ virt_wmb(); /* front sees responses /before/ updated producer index */ \
(_r)->sring->rsp_prod = __new; \
- mb(); /* front sees new responses /before/ we check rsp_event */ \
+ virt_mb(); /* front sees new responses /before/ we check rsp_event */ \
(_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \
(RING_IDX)(__new - __old)); \
} while (0)
@@ -271,7 +271,7 @@ struct __name##_back_ring { \
(_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
if (_work_to_do) break; \
(_r)->sring->req_event = (_r)->req_cons + 1; \
- mb(); \
+ virt_mb(); \
(_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
} while (0)
@@ -279,7 +279,7 @@ struct __name##_back_ring { \
(_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
if (_work_to_do) break; \
(_r)->sring->rsp_event = (_r)->rsp_cons + 1; \
- mb(); \
+ virt_mb(); \
(_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
} while (0)
diff --git a/init/Kconfig b/init/Kconfig
index 5481b49e8c3f..5b86082fa238 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -285,7 +285,7 @@ config FHANDLE
config USELIB
bool "uselib syscall"
- default y
+ def_bool ALPHA || M68K || SPARC || X86_32 || IA32_EMULATION
help
This option enables the uselib syscall, a system call used in the
dynamic linker from libc5 and earlier. glibc does not use this
@@ -299,20 +299,15 @@ config AUDIT
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
- logging of avc messages output). Does not do system-call
- auditing without CONFIG_AUDITSYSCALL.
+ logging of avc messages output). System call auditing is included
+ on architectures which support it.
config HAVE_ARCH_AUDITSYSCALL
bool
config AUDITSYSCALL
- bool "Enable system-call auditing support"
+ def_bool y
depends on AUDIT && HAVE_ARCH_AUDITSYSCALL
- default y if SECURITY_SELINUX
- help
- Enable low-overhead system-call auditing infrastructure that
- can be used independently or with another kernel subsystem,
- such as SELinux.
config AUDIT_WATCH
def_bool y
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index e5d059e8aa11..8a09b32e07d6 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -216,13 +216,6 @@ int __init rd_load_image(char *from)
/*
* NOTE NOTE: nblocks is not actually blocks but
* the number of kibibytes of data to load into a ramdisk.
- * So any ramdisk block size that is a multiple of 1KiB should
- * work when the appropriate ramdisk_blocksize is specified
- * on the command line.
- *
- * The default ramdisk_blocksize is 1KiB and it is generally
- * silly to use anything else, so make sure to use 1KiB
- * blocksize while generating ext2fs ramdisk-images.
*/
if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
rd_blocks = 0;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 161a1807e6ef..f4617cf07069 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1438,7 +1438,7 @@ static int __init init_mqueue_fs(void)
mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
sizeof(struct mqueue_inode_info), 0,
- SLAB_HWCACHE_ALIGN, init_once);
+ SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, init_once);
if (mqueue_inode_cachep == NULL)
return -ENOMEM;
diff --git a/kernel/async.c b/kernel/async.c
index 4c3773c0bf63..d2edd6efec56 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -326,3 +326,4 @@ bool current_is_async(void)
return worker && worker->current_func == async_run_entry_fn;
}
+EXPORT_SYMBOL_GPL(current_is_async);
diff --git a/kernel/audit.c b/kernel/audit.c
index 5ffcbd354a52..3a3e5deeda8d 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -110,7 +110,6 @@ static u32 audit_backlog_limit = 64;
#define AUDIT_BACKLOG_WAIT_TIME (60 * HZ)
static u32 audit_backlog_wait_time_master = AUDIT_BACKLOG_WAIT_TIME;
static u32 audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
-static u32 audit_backlog_wait_overflow = 0;
/* The identity of the user shutting down the audit system. */
kuid_t audit_sig_uid = INVALID_UID;
@@ -509,8 +508,7 @@ static void flush_hold_queue(void)
* if auditd just disappeared but we
* dequeued an skb we need to drop ref
*/
- if (skb)
- consume_skb(skb);
+ consume_skb(skb);
}
static int kauditd_thread(void *dummy)
@@ -524,7 +522,8 @@ static int kauditd_thread(void *dummy)
skb = skb_dequeue(&audit_skb_queue);
if (skb) {
- if (skb_queue_len(&audit_skb_queue) <= audit_backlog_limit)
+ if (!audit_backlog_limit ||
+ (skb_queue_len(&audit_skb_queue) <= audit_backlog_limit))
wake_up(&audit_backlog_wait);
if (audit_pid)
kauditd_send_skb(skb);
@@ -1232,9 +1231,7 @@ static void audit_buffer_free(struct audit_buffer *ab)
if (!ab)
return;
- if (ab->skb)
- kfree_skb(ab->skb);
-
+ kfree_skb(ab->skb);
spin_lock_irqsave(&audit_freelist_lock, flags);
if (audit_freelist_count > AUDIT_MAXFREE)
kfree(ab);
@@ -1372,7 +1369,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
return NULL;
if (gfp_mask & __GFP_DIRECT_RECLAIM) {
- if (audit_pid && audit_pid == current->pid)
+ if (audit_pid && audit_pid == current->tgid)
gfp_mask &= ~__GFP_DIRECT_RECLAIM;
else
reserve = 0;
@@ -1395,12 +1392,12 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
skb_queue_len(&audit_skb_queue),
audit_backlog_limit);
audit_log_lost("backlog limit exceeded");
- audit_backlog_wait_time = audit_backlog_wait_overflow;
+ audit_backlog_wait_time = 0;
wake_up(&audit_backlog_wait);
return NULL;
}
- if (!reserve)
+ if (!reserve && !audit_backlog_wait_time)
audit_backlog_wait_time = audit_backlog_wait_time_master;
ab = audit_buffer_alloc(ctx, gfp_mask, type);
@@ -1722,7 +1719,7 @@ static inline int audit_copy_fcaps(struct audit_names *name,
/* Copy inode data into an audit_names. */
void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
- const struct inode *inode)
+ struct inode *inode)
{
name->ino = inode->i_ino;
name->dev = inode->i_sb->s_dev;
diff --git a/kernel/audit.h b/kernel/audit.h
index de6cbb7cf547..cbbe6bb6496e 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -207,7 +207,7 @@ extern u32 audit_ever_enabled;
extern void audit_copy_inode(struct audit_names *name,
const struct dentry *dentry,
- const struct inode *inode);
+ struct inode *inode);
extern void audit_log_cap(struct audit_buffer *ab, char *prefix,
kernel_cap_t *cap);
extern void audit_log_name(struct audit_context *context,
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b86cc04959de..195ffaee50b9 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1754,7 +1754,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int flags)
{
struct audit_context *context = current->audit_context;
- const struct inode *inode = d_backing_inode(dentry);
+ struct inode *inode = d_backing_inode(dentry);
struct audit_names *n;
bool parent = flags & AUDIT_INODE_PARENT;
@@ -1848,12 +1848,12 @@ void __audit_file(const struct file *file)
* must be hooked prior, in order to capture the target inode during
* unsuccessful attempts.
*/
-void __audit_inode_child(const struct inode *parent,
+void __audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type)
{
struct audit_context *context = current->audit_context;
- const struct inode *inode = d_backing_inode(dentry);
+ struct inode *inode = d_backing_inode(dentry);
const char *dname = dentry->d_name.name;
struct audit_names *n, *found_parent = NULL, *found_child = NULL;
diff --git a/kernel/cred.c b/kernel/cred.c
index 71179a09c1d6..0c0cd8a62285 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -569,8 +569,8 @@ EXPORT_SYMBOL(revert_creds);
void __init cred_init(void)
{
/* allocate a slab in which we can store credentials */
- cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
}
/**
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index 4121345498e0..2a20c0dfdafc 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -2021,7 +2021,7 @@ static int kdb_lsmod(int argc, const char **argv)
continue;
kdb_printf("%-20s%8u 0x%p ", mod->name,
- mod->core_size, (void *)mod);
+ mod->core_layout.size, (void *)mod);
#ifdef CONFIG_MODULE_UNLOAD
kdb_printf("%4d ", module_refcount(mod));
#endif
@@ -2031,7 +2031,7 @@ static int kdb_lsmod(int argc, const char **argv)
kdb_printf(" (Loading)");
else
kdb_printf(" (Live)");
- kdb_printf(" 0x%p", mod->module_core);
+ kdb_printf(" 0x%p", mod->core_layout.base);
#ifdef CONFIG_MODULE_UNLOAD
{
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index ef90b04d783f..435c14a45118 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -34,7 +34,7 @@ __setup("nodelayacct", delayacct_setup_disable);
void delayacct_init(void)
{
- delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC);
+ delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT);
delayacct_tsk_init(&init_task);
}
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 7dad84913abf..0167679182c0 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -161,7 +161,8 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
const unsigned long mmun_end = addr + PAGE_SIZE;
struct mem_cgroup *memcg;
- err = mem_cgroup_try_charge(kpage, vma->vm_mm, GFP_KERNEL, &memcg);
+ err = mem_cgroup_try_charge(kpage, vma->vm_mm, GFP_KERNEL, &memcg,
+ false);
if (err)
return err;
@@ -175,12 +176,12 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
goto unlock;
get_page(kpage);
- page_add_new_anon_rmap(kpage, vma, addr);
- mem_cgroup_commit_charge(kpage, memcg, false);
+ page_add_new_anon_rmap(kpage, vma, addr, false);
+ mem_cgroup_commit_charge(kpage, memcg, false, false);
lru_cache_add_active_or_unevictable(kpage, vma);
if (!PageAnon(page)) {
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter_file(page));
inc_mm_counter(mm, MM_ANONPAGES);
}
@@ -188,7 +189,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
ptep_clear_flush_notify(vma, addr, ptep);
set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
- page_remove_rmap(page);
+ page_remove_rmap(page, false);
if (!page_mapped(page))
try_to_free_swap(page);
pte_unmap_unlock(ptep, ptl);
@@ -199,7 +200,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
err = 0;
unlock:
- mem_cgroup_cancel_charge(kpage, memcg);
+ mem_cgroup_cancel_charge(kpage, memcg, false);
mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
unlock_page(page);
return err;
diff --git a/kernel/fork.c b/kernel/fork.c
index 6774e6b2e96d..2e391c754ae7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -300,9 +300,9 @@ void __init fork_init(void)
#define ARCH_MIN_TASKALIGN L1_CACHE_BYTES
#endif
/* create a slab on which task_structs can be allocated */
- task_struct_cachep =
- kmem_cache_create("task_struct", arch_task_struct_size,
- ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);
+ task_struct_cachep = kmem_cache_create("task_struct",
+ arch_task_struct_size, ARCH_MIN_TASKALIGN,
+ SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, NULL);
#endif
/* do the arch specific task caches init */
@@ -414,7 +414,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm));
mm->total_vm = oldmm->total_vm;
- mm->shared_vm = oldmm->shared_vm;
+ mm->data_vm = oldmm->data_vm;
mm->exec_vm = oldmm->exec_vm;
mm->stack_vm = oldmm->stack_vm;
@@ -433,8 +433,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
struct file *file;
if (mpnt->vm_flags & VM_DONTCOPY) {
- vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,
- -vma_pages(mpnt));
+ vm_stat_account(mm, mpnt->vm_flags, -vma_pages(mpnt));
continue;
}
charge = 0;
@@ -1848,16 +1847,19 @@ void __init proc_caches_init(void)
sighand_cachep = kmem_cache_create("sighand_cache",
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU|
- SLAB_NOTRACK, sighand_ctor);
+ SLAB_NOTRACK|SLAB_ACCOUNT, sighand_ctor);
signal_cachep = kmem_cache_create("signal_cache",
sizeof(struct signal_struct), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT,
+ NULL);
files_cachep = kmem_cache_create("files_cache",
sizeof(struct files_struct), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT,
+ NULL);
fs_cachep = kmem_cache_create("fs_cache",
sizeof(struct fs_struct), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT,
+ NULL);
/*
* FIXME! The "sizeof(struct mm_struct)" currently includes the
* whole struct cpumask for the OFFSTACK case. We could change
@@ -1867,8 +1869,9 @@ void __init proc_caches_init(void)
*/
mm_cachep = kmem_cache_create("mm_struct",
sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
- vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT,
+ NULL);
+ vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC|SLAB_ACCOUNT);
mmap_init();
nsproxy_cache_init();
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 8a310e240cda..c6f514573b28 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -469,7 +469,8 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
{
unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm;
- struct page *page, *page_head;
+ struct page *page;
+ struct address_space *mapping;
int err, ro = 0;
/*
@@ -519,46 +520,9 @@ again:
else
err = 0;
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- page_head = page;
- if (unlikely(PageTail(page))) {
- put_page(page);
- /* serialize against __split_huge_page_splitting() */
- local_irq_disable();
- if (likely(__get_user_pages_fast(address, 1, !ro, &page) == 1)) {
- page_head = compound_head(page);
- /*
- * page_head is valid pointer but we must pin
- * it before taking the PG_lock and/or
- * PG_compound_lock. The moment we re-enable
- * irqs __split_huge_page_splitting() can
- * return and the head page can be freed from
- * under us. We can't take the PG_lock and/or
- * PG_compound_lock on a page that could be
- * freed from under us.
- */
- if (page != page_head) {
- get_page(page_head);
- put_page(page);
- }
- local_irq_enable();
- } else {
- local_irq_enable();
- goto again;
- }
- }
-#else
- page_head = compound_head(page);
- if (page != page_head) {
- get_page(page_head);
- put_page(page);
- }
-#endif
-
- lock_page(page_head);
-
+ lock_page(page);
/*
- * If page_head->mapping is NULL, then it cannot be a PageAnon
+ * If page->mapping is NULL, then it cannot be a PageAnon
* page; but it might be the ZERO_PAGE or in the gate area or
* in a special mapping (all cases which we are happy to fail);
* or it may have been a good file page when get_user_pages_fast
@@ -570,12 +534,13 @@ again:
*
* The case we do have to guard against is when memory pressure made
* shmem_writepage move it from filecache to swapcache beneath us:
- * an unlikely race, but we do need to retry for page_head->mapping.
+ * an unlikely race, but we do need to retry for page->mapping.
*/
- if (!page_head->mapping) {
- int shmem_swizzled = PageSwapCache(page_head);
- unlock_page(page_head);
- put_page(page_head);
+ mapping = compound_head(page)->mapping;
+ if (!mapping) {
+ int shmem_swizzled = PageSwapCache(page);
+ unlock_page(page);
+ put_page(page);
if (shmem_swizzled)
goto again;
return -EFAULT;
@@ -588,7 +553,7 @@ again:
* it's a read-only handle, it's expected that futexes attach to
* the object not the particular process.
*/
- if (PageAnon(page_head)) {
+ if (PageAnon(page)) {
/*
* A RO anonymous page will never change and thus doesn't make
* sense for futex operations.
@@ -603,15 +568,15 @@ again:
key->private.address = address;
} else {
key->both.offset |= FUT_OFF_INODE; /* inode-based key */
- key->shared.inode = page_head->mapping->host;
+ key->shared.inode = mapping->host;
key->shared.pgoff = basepage_index(page);
}
get_futex_key_refs(key); /* implies MB (B) */
out:
- unlock_page(page_head);
- put_page(page_head);
+ unlock_page(page);
+ put_page(page);
return err;
}
@@ -639,7 +604,7 @@ static int fault_in_user_writeable(u32 __user *uaddr)
down_read(&mm->mmap_sem);
ret = fixup_user_fault(current, mm, (unsigned long)uaddr,
- FAULT_FLAG_WRITE);
+ FAULT_FLAG_WRITE, NULL);
up_read(&mm->mmap_sem);
return ret < 0 ? ret : 0;
diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c
index 7080ae1eb6c1..2f9df37940a0 100644
--- a/kernel/gcov/base.c
+++ b/kernel/gcov/base.c
@@ -123,11 +123,6 @@ void gcov_enable_events(void)
}
#ifdef CONFIG_MODULES
-static inline int within(void *addr, void *start, unsigned long size)
-{
- return ((addr >= start) && (addr < start + size));
-}
-
/* Update list and generate events when modules are unloaded. */
static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
void *data)
@@ -142,7 +137,7 @@ static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
/* Remove entries located in module from linked list. */
while ((info = gcov_info_next(info))) {
- if (within(info, mod->module_core, mod->core_size)) {
+ if (within_module((unsigned long)info, mod)) {
gcov_info_unlink(prev, info);
if (gcov_events_enabled)
gcov_event(GCOV_REMOVE, info);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index db545cbcdb89..bc2c85c064c1 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -28,6 +28,7 @@
#include <linux/list.h>
#include <linux/kallsyms.h>
#include <linux/livepatch.h>
+#include <asm/cacheflush.h>
/**
* struct klp_ops - structure for tracking registered ftrace ops structs
@@ -135,13 +136,8 @@ struct klp_find_arg {
const char *objname;
const char *name;
unsigned long addr;
- /*
- * If count == 0, the symbol was not found. If count == 1, a unique
- * match was found and addr is set. If count > 1, there is
- * unresolvable ambiguity among "count" number of symbols with the same
- * name in the same object.
- */
unsigned long count;
+ unsigned long pos;
};
static int klp_find_callback(void *data, const char *name,
@@ -158,37 +154,48 @@ static int klp_find_callback(void *data, const char *name,
if (args->objname && strcmp(args->objname, mod->name))
return 0;
- /*
- * args->addr might be overwritten if another match is found
- * but klp_find_object_symbol() handles this and only returns the
- * addr if count == 1.
- */
args->addr = addr;
args->count++;
+ /*
+ * Finish the search when the symbol is found for the desired position
+ * or the position is not defined for a non-unique symbol.
+ */
+ if ((args->pos && (args->count == args->pos)) ||
+ (!args->pos && (args->count > 1)))
+ return 1;
+
return 0;
}
static int klp_find_object_symbol(const char *objname, const char *name,
- unsigned long *addr)
+ unsigned long sympos, unsigned long *addr)
{
struct klp_find_arg args = {
.objname = objname,
.name = name,
.addr = 0,
- .count = 0
+ .count = 0,
+ .pos = sympos,
};
mutex_lock(&module_mutex);
kallsyms_on_each_symbol(klp_find_callback, &args);
mutex_unlock(&module_mutex);
- if (args.count == 0)
+ /*
+ * Ensure an address was found. If sympos is 0, ensure symbol is unique;
+ * otherwise ensure the symbol position count matches sympos.
+ */
+ if (args.addr == 0)
pr_err("symbol '%s' not found in symbol table\n", name);
- else if (args.count > 1)
+ else if (args.count > 1 && sympos == 0) {
pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n",
args.count, name, objname);
- else {
+ } else if (sympos != args.count && sympos > 0) {
+ pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
+ sympos, name, objname ? objname : "vmlinux");
+ } else {
*addr = args.addr;
return 0;
}
@@ -197,66 +204,6 @@ static int klp_find_object_symbol(const char *objname, const char *name,
return -EINVAL;
}
-struct klp_verify_args {
- const char *name;
- const unsigned long addr;
-};
-
-static int klp_verify_callback(void *data, const char *name,
- struct module *mod, unsigned long addr)
-{
- struct klp_verify_args *args = data;
-
- if (!mod &&
- !strcmp(args->name, name) &&
- args->addr == addr)
- return 1;
-
- return 0;
-}
-
-static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr)
-{
- struct klp_verify_args args = {
- .name = name,
- .addr = addr,
- };
- int ret;
-
- mutex_lock(&module_mutex);
- ret = kallsyms_on_each_symbol(klp_verify_callback, &args);
- mutex_unlock(&module_mutex);
-
- if (!ret) {
- pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
- name, addr);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int klp_find_verify_func_addr(struct klp_object *obj,
- struct klp_func *func)
-{
- int ret;
-
-#if defined(CONFIG_RANDOMIZE_BASE)
- /* If KASLR has been enabled, adjust old_addr accordingly */
- if (kaslr_enabled() && func->old_addr)
- func->old_addr += kaslr_offset();
-#endif
-
- if (!func->old_addr || klp_is_module(obj))
- ret = klp_find_object_symbol(obj->name, func->old_name,
- &func->old_addr);
- else
- ret = klp_verify_vmlinux_symbol(func->old_name,
- func->old_addr);
-
- return ret;
-}
-
/*
* external symbols are located outside the parent object (where the parent
* object is either vmlinux or the kmod being patched).
@@ -276,14 +223,18 @@ static int klp_find_external_symbol(struct module *pmod, const char *name,
}
preempt_enable();
- /* otherwise check if it's in another .o within the patch module */
- return klp_find_object_symbol(pmod->name, name, addr);
+ /*
+ * Check if it's in another .o within the patch module. This also
+ * checks that the external symbol is unique.
+ */
+ return klp_find_object_symbol(pmod->name, name, 0, addr);
}
static int klp_write_object_relocations(struct module *pmod,
struct klp_object *obj)
{
- int ret;
+ int ret = 0;
+ unsigned long val;
struct klp_reloc *reloc;
if (WARN_ON(!klp_is_object_loaded(obj)))
@@ -292,41 +243,38 @@ static int klp_write_object_relocations(struct module *pmod,
if (WARN_ON(!obj->relocs))
return -EINVAL;
+ module_disable_ro(pmod);
+
for (reloc = obj->relocs; reloc->name; reloc++) {
- if (!klp_is_module(obj)) {
-
-#if defined(CONFIG_RANDOMIZE_BASE)
- /* If KASLR has been enabled, adjust old value accordingly */
- if (kaslr_enabled())
- reloc->val += kaslr_offset();
-#endif
- ret = klp_verify_vmlinux_symbol(reloc->name,
- reloc->val);
- if (ret)
- return ret;
- } else {
- /* module, reloc->val needs to be discovered */
- if (reloc->external)
- ret = klp_find_external_symbol(pmod,
- reloc->name,
- &reloc->val);
- else
- ret = klp_find_object_symbol(obj->mod->name,
- reloc->name,
- &reloc->val);
- if (ret)
- return ret;
- }
+ /* discover the address of the referenced symbol */
+ if (reloc->external) {
+ if (reloc->sympos > 0) {
+ pr_err("non-zero sympos for external reloc symbol '%s' is not supported\n",
+ reloc->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = klp_find_external_symbol(pmod, reloc->name, &val);
+ } else
+ ret = klp_find_object_symbol(obj->name,
+ reloc->name,
+ reloc->sympos,
+ &val);
+ if (ret)
+ goto out;
+
ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc,
- reloc->val + reloc->addend);
+ val + reloc->addend);
if (ret) {
pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n",
- reloc->name, reloc->val, ret);
- return ret;
+ reloc->name, val, ret);
+ goto out;
}
}
- return 0;
+out:
+ module_enable_ro(pmod);
+ return ret;
}
static void notrace klp_ftrace_handler(unsigned long ip,
@@ -593,7 +541,7 @@ EXPORT_SYMBOL_GPL(klp_enable_patch);
* /sys/kernel/livepatch/<patch>
* /sys/kernel/livepatch/<patch>/enabled
* /sys/kernel/livepatch/<patch>/<object>
- * /sys/kernel/livepatch/<patch>/<object>/<func>
+ * /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
*/
static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
@@ -738,8 +686,14 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
INIT_LIST_HEAD(&func->stack_node);
func->state = KLP_DISABLED;
+ /* The format for the sysfs directory is <function,sympos> where sympos
+ * is the nth occurrence of this symbol in kallsyms for the patched
+ * object. If the user selects 0 for old_sympos, then 1 will be used
+ * since a unique symbol will be the first occurrence.
+ */
return kobject_init_and_add(&func->kobj, &klp_ktype_func,
- &obj->kobj, "%s", func->old_name);
+ &obj->kobj, "%s,%lu", func->old_name,
+ func->old_sympos ? func->old_sympos : 1);
}
/* parts of the initialization that is done only when the object is loaded */
@@ -756,7 +710,9 @@ static int klp_init_object_loaded(struct klp_patch *patch,
}
klp_for_each_func(obj, func) {
- ret = klp_find_verify_func_addr(obj, func);
+ ret = klp_find_object_symbol(obj->name, func->old_name,
+ func->old_sympos,
+ &func->old_addr);
if (ret)
return ret;
}
diff --git a/kernel/memremap.c b/kernel/memremap.c
index 7658d32c5c78..e517a16cb426 100644
--- a/kernel/memremap.c
+++ b/kernel/memremap.c
@@ -10,8 +10,11 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
+#include <linux/radix-tree.h>
+#include <linux/memremap.h>
#include <linux/device.h>
#include <linux/types.h>
+#include <linux/pfn_t.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/memory_hotplug.h>
@@ -147,24 +150,127 @@ void devm_memunmap(struct device *dev, void *addr)
}
EXPORT_SYMBOL(devm_memunmap);
+pfn_t phys_to_pfn_t(dma_addr_t addr, unsigned long flags)
+{
+ return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags);
+}
+EXPORT_SYMBOL(phys_to_pfn_t);
+
#ifdef CONFIG_ZONE_DEVICE
+static DEFINE_MUTEX(pgmap_lock);
+static RADIX_TREE(pgmap_radix, GFP_KERNEL);
+#define SECTION_MASK ~((1UL << PA_SECTION_SHIFT) - 1)
+#define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
+
struct page_map {
struct resource res;
+ struct percpu_ref *ref;
+ struct dev_pagemap pgmap;
+ struct vmem_altmap altmap;
};
-static void devm_memremap_pages_release(struct device *dev, void *res)
+void get_zone_device_page(struct page *page)
+{
+ percpu_ref_get(page->pgmap->ref);
+}
+EXPORT_SYMBOL(get_zone_device_page);
+
+void put_zone_device_page(struct page *page)
+{
+ put_dev_pagemap(page->pgmap);
+}
+EXPORT_SYMBOL(put_zone_device_page);
+
+static void pgmap_radix_release(struct resource *res)
+{
+ resource_size_t key;
+
+ mutex_lock(&pgmap_lock);
+ for (key = res->start; key <= res->end; key += SECTION_SIZE)
+ radix_tree_delete(&pgmap_radix, key >> PA_SECTION_SHIFT);
+ mutex_unlock(&pgmap_lock);
+}
+
+static unsigned long pfn_first(struct page_map *page_map)
+{
+ struct dev_pagemap *pgmap = &page_map->pgmap;
+ const struct resource *res = &page_map->res;
+ struct vmem_altmap *altmap = pgmap->altmap;
+ unsigned long pfn;
+
+ pfn = res->start >> PAGE_SHIFT;
+ if (altmap)
+ pfn += vmem_altmap_offset(altmap);
+ return pfn;
+}
+
+static unsigned long pfn_end(struct page_map *page_map)
+{
+ const struct resource *res = &page_map->res;
+
+ return (res->start + resource_size(res)) >> PAGE_SHIFT;
+}
+
+#define for_each_device_pfn(pfn, map) \
+ for (pfn = pfn_first(map); pfn < pfn_end(map); pfn++)
+
+static void devm_memremap_pages_release(struct device *dev, void *data)
{
- struct page_map *page_map = res;
+ struct page_map *page_map = data;
+ struct resource *res = &page_map->res;
+ resource_size_t align_start, align_size;
+ struct dev_pagemap *pgmap = &page_map->pgmap;
+
+ if (percpu_ref_tryget_live(pgmap->ref)) {
+ dev_WARN(dev, "%s: page mapping is still live!\n", __func__);
+ percpu_ref_put(pgmap->ref);
+ }
+
+ pgmap_radix_release(res);
/* pages are dead and unused, undo the arch mapping */
- arch_remove_memory(page_map->res.start, resource_size(&page_map->res));
+ align_start = res->start & ~(SECTION_SIZE - 1);
+ align_size = ALIGN(resource_size(res), SECTION_SIZE);
+ arch_remove_memory(align_start, align_size);
+ dev_WARN_ONCE(dev, pgmap->altmap && pgmap->altmap->alloc,
+ "%s: failed to free all reserved pages\n", __func__);
+}
+
+/* assumes rcu_read_lock() held at entry */
+struct dev_pagemap *find_dev_pagemap(resource_size_t phys)
+{
+ struct page_map *page_map;
+
+ WARN_ON_ONCE(!rcu_read_lock_held());
+
+ page_map = radix_tree_lookup(&pgmap_radix, phys >> PA_SECTION_SHIFT);
+ return page_map ? &page_map->pgmap : NULL;
}
-void *devm_memremap_pages(struct device *dev, struct resource *res)
+/**
+ * devm_memremap_pages - remap and provide memmap backing for the given resource
+ * @dev: hosting device for @res
+ * @res: "host memory" address range
+ * @ref: a live per-cpu reference count
+ * @altmap: optional descriptor for allocating the memmap from @res
+ *
+ * Notes:
+ * 1/ @ref must be 'live' on entry and 'dead' before devm_memunmap_pages() time
+ * (or devm release event).
+ *
+ * 2/ @res is expected to be a host memory range that could feasibly be
+ * treated as a "System RAM" range, i.e. not a device mmio range, but
+ * this is not enforced.
+ */
+void *devm_memremap_pages(struct device *dev, struct resource *res,
+ struct percpu_ref *ref, struct vmem_altmap *altmap)
{
int is_ram = region_intersects(res->start, resource_size(res),
"System RAM");
+ resource_size_t key, align_start, align_size;
+ struct dev_pagemap *pgmap;
struct page_map *page_map;
+ unsigned long pfn;
int error, nid;
if (is_ram == REGION_MIXED) {
@@ -176,25 +282,120 @@ void *devm_memremap_pages(struct device *dev, struct resource *res)
if (is_ram == REGION_INTERSECTS)
return __va(res->start);
+ if (altmap && !IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP)) {
+ dev_err(dev, "%s: altmap requires CONFIG_SPARSEMEM_VMEMMAP=y\n",
+ __func__);
+ return ERR_PTR(-ENXIO);
+ }
+
+ if (!ref)
+ return ERR_PTR(-EINVAL);
+
page_map = devres_alloc_node(devm_memremap_pages_release,
sizeof(*page_map), GFP_KERNEL, dev_to_node(dev));
if (!page_map)
return ERR_PTR(-ENOMEM);
+ pgmap = &page_map->pgmap;
memcpy(&page_map->res, res, sizeof(*res));
+ pgmap->dev = dev;
+ if (altmap) {
+ memcpy(&page_map->altmap, altmap, sizeof(*altmap));
+ pgmap->altmap = &page_map->altmap;
+ }
+ pgmap->ref = ref;
+ pgmap->res = &page_map->res;
+
+ mutex_lock(&pgmap_lock);
+ error = 0;
+ for (key = res->start; key <= res->end; key += SECTION_SIZE) {
+ struct dev_pagemap *dup;
+
+ rcu_read_lock();
+ dup = find_dev_pagemap(key);
+ rcu_read_unlock();
+ if (dup) {
+ dev_err(dev, "%s: %pr collides with mapping for %s\n",
+ __func__, res, dev_name(dup->dev));
+ error = -EBUSY;
+ break;
+ }
+ error = radix_tree_insert(&pgmap_radix, key >> PA_SECTION_SHIFT,
+ page_map);
+ if (error) {
+ dev_err(dev, "%s: failed: %d\n", __func__, error);
+ break;
+ }
+ }
+ mutex_unlock(&pgmap_lock);
+ if (error)
+ goto err_radix;
+
nid = dev_to_node(dev);
if (nid < 0)
nid = numa_mem_id();
- error = arch_add_memory(nid, res->start, resource_size(res), true);
- if (error) {
- devres_free(page_map);
- return ERR_PTR(error);
- }
+ align_start = res->start & ~(SECTION_SIZE - 1);
+ align_size = ALIGN(resource_size(res), SECTION_SIZE);
+ error = arch_add_memory(nid, align_start, align_size, true);
+ if (error)
+ goto err_add_memory;
+ for_each_device_pfn(pfn, page_map) {
+ struct page *page = pfn_to_page(pfn);
+
+ /* ZONE_DEVICE pages must never appear on a slab lru */
+ list_force_poison(&page->lru);
+ page->pgmap = pgmap;
+ }
devres_add(dev, page_map);
return __va(res->start);
+
+ err_add_memory:
+ err_radix:
+ pgmap_radix_release(res);
+ devres_free(page_map);
+ return ERR_PTR(error);
}
EXPORT_SYMBOL(devm_memremap_pages);
+
+unsigned long vmem_altmap_offset(struct vmem_altmap *altmap)
+{
+ /* number of pfns from base where pfn_to_page() is valid */
+ return altmap->reserve + altmap->free;
+}
+
+void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns)
+{
+ altmap->alloc -= nr_pfns;
+}
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start)
+{
+ /*
+ * 'memmap_start' is the virtual address for the first "struct
+ * page" in this range of the vmemmap array. In the case of
+ * CONFIG_SPARSE_VMEMMAP a page_to_pfn conversion is simple
+ * pointer arithmetic, so we can perform this to_vmem_altmap()
+ * conversion without concern for the initialization state of
+ * the struct page fields.
+ */
+ struct page *page = (struct page *) memmap_start;
+ struct dev_pagemap *pgmap;
+
+ /*
+ * Uncoditionally retrieve a dev_pagemap associated with the
+ * given physical address, this is only for use in the
+ * arch_{add|remove}_memory() for setting up and tearing down
+ * the memmap.
+ */
+ rcu_read_lock();
+ pgmap = find_dev_pagemap(__pfn_to_phys(page_to_pfn(page)));
+ rcu_read_unlock();
+
+ return pgmap ? pgmap->altmap : NULL;
+}
+#endif /* CONFIG_SPARSEMEM_VMEMMAP */
#endif /* CONFIG_ZONE_DEVICE */
diff --git a/kernel/module.c b/kernel/module.c
index 38c7bd5583ff..8358f4697c0c 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -80,15 +80,6 @@
# define debug_align(X) (X)
#endif
-/*
- * Given BASE and SIZE this macro calculates the number of pages the
- * memory regions occupies
- */
-#define MOD_NUMBER_OF_PAGES(BASE, SIZE) (((SIZE) > 0) ? \
- (PFN_DOWN((unsigned long)(BASE) + (SIZE) - 1) - \
- PFN_DOWN((unsigned long)BASE) + 1) \
- : (0UL))
-
/* If this is set, the section belongs in the init part of the module */
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
@@ -108,13 +99,6 @@ static LIST_HEAD(modules);
* Use a latched RB-tree for __module_address(); this allows us to use
* RCU-sched lookups of the address from any context.
*
- * Because modules have two address ranges: init and core, we need two
- * latch_tree_nodes entries. Therefore we need the back-pointer from
- * mod_tree_node.
- *
- * Because init ranges are short lived we mark them unlikely and have placed
- * them outside the critical cacheline in struct module.
- *
* This is conditional on PERF_EVENTS || TRACING because those can really hit
* __module_address() hard by doing a lot of stack unwinding; potentially from
* NMI context.
@@ -122,24 +106,16 @@ static LIST_HEAD(modules);
static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
{
- struct mod_tree_node *mtn = container_of(n, struct mod_tree_node, node);
- struct module *mod = mtn->mod;
+ struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
- if (unlikely(mtn == &mod->mtn_init))
- return (unsigned long)mod->module_init;
-
- return (unsigned long)mod->module_core;
+ return (unsigned long)layout->base;
}
static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
{
- struct mod_tree_node *mtn = container_of(n, struct mod_tree_node, node);
- struct module *mod = mtn->mod;
-
- if (unlikely(mtn == &mod->mtn_init))
- return (unsigned long)mod->init_size;
+ struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
- return (unsigned long)mod->core_size;
+ return (unsigned long)layout->size;
}
static __always_inline bool
@@ -197,23 +173,23 @@ static void __mod_tree_remove(struct mod_tree_node *node)
*/
static void mod_tree_insert(struct module *mod)
{
- mod->mtn_core.mod = mod;
- mod->mtn_init.mod = mod;
+ mod->core_layout.mtn.mod = mod;
+ mod->init_layout.mtn.mod = mod;
- __mod_tree_insert(&mod->mtn_core);
- if (mod->init_size)
- __mod_tree_insert(&mod->mtn_init);
+ __mod_tree_insert(&mod->core_layout.mtn);
+ if (mod->init_layout.size)
+ __mod_tree_insert(&mod->init_layout.mtn);
}
static void mod_tree_remove_init(struct module *mod)
{
- if (mod->init_size)
- __mod_tree_remove(&mod->mtn_init);
+ if (mod->init_layout.size)
+ __mod_tree_remove(&mod->init_layout.mtn);
}
static void mod_tree_remove(struct module *mod)
{
- __mod_tree_remove(&mod->mtn_core);
+ __mod_tree_remove(&mod->core_layout.mtn);
mod_tree_remove_init(mod);
}
@@ -267,9 +243,9 @@ static void __mod_update_bounds(void *base, unsigned int size)
static void mod_update_bounds(struct module *mod)
{
- __mod_update_bounds(mod->module_core, mod->core_size);
- if (mod->init_size)
- __mod_update_bounds(mod->module_init, mod->init_size);
+ __mod_update_bounds(mod->core_layout.base, mod->core_layout.size);
+ if (mod->init_layout.size)
+ __mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
}
#ifdef CONFIG_KGDB_KDB
@@ -1214,7 +1190,7 @@ struct module_attribute module_uevent =
static ssize_t show_coresize(struct module_attribute *mattr,
struct module_kobject *mk, char *buffer)
{
- return sprintf(buffer, "%u\n", mk->mod->core_size);
+ return sprintf(buffer, "%u\n", mk->mod->core_layout.size);
}
static struct module_attribute modinfo_coresize =
@@ -1223,7 +1199,7 @@ static struct module_attribute modinfo_coresize =
static ssize_t show_initsize(struct module_attribute *mattr,
struct module_kobject *mk, char *buffer)
{
- return sprintf(buffer, "%u\n", mk->mod->init_size);
+ return sprintf(buffer, "%u\n", mk->mod->init_layout.size);
}
static struct module_attribute modinfo_initsize =
@@ -1873,64 +1849,75 @@ static void mod_sysfs_teardown(struct module *mod)
/*
* LKM RO/NX protection: protect module's text/ro-data
* from modification and any data from execution.
+ *
+ * General layout of module is:
+ * [text] [read-only-data] [writable data]
+ * text_size -----^ ^ ^
+ * ro_size ------------------------| |
+ * size -------------------------------------------|
+ *
+ * These values are always page-aligned (as is base)
*/
-void set_page_attributes(void *start, void *end, int (*set)(unsigned long start, int num_pages))
+static void frob_text(const struct module_layout *layout,
+ int (*set_memory)(unsigned long start, int num_pages))
{
- unsigned long begin_pfn = PFN_DOWN((unsigned long)start);
- unsigned long end_pfn = PFN_DOWN((unsigned long)end);
+ BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+ BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
+ set_memory((unsigned long)layout->base,
+ layout->text_size >> PAGE_SHIFT);
+}
- if (end_pfn > begin_pfn)
- set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
+static void frob_rodata(const struct module_layout *layout,
+ int (*set_memory)(unsigned long start, int num_pages))
+{
+ BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+ BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
+ BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
+ set_memory((unsigned long)layout->base + layout->text_size,
+ (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
}
-static void set_section_ro_nx(void *base,
- unsigned long text_size,
- unsigned long ro_size,
- unsigned long total_size)
+static void frob_writable_data(const struct module_layout *layout,
+ int (*set_memory)(unsigned long start, int num_pages))
{
- /* begin and end PFNs of the current subsection */
- unsigned long begin_pfn;
- unsigned long end_pfn;
+ BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+ BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
+ BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
+ set_memory((unsigned long)layout->base + layout->ro_size,
+ (layout->size - layout->ro_size) >> PAGE_SHIFT);
+}
- /*
- * Set RO for module text and RO-data:
- * - Always protect first page.
- * - Do not protect last partial page.
- */
- if (ro_size > 0)
- set_page_attributes(base, base + ro_size, set_memory_ro);
+/* livepatching wants to disable read-only so it can frob module. */
+void module_disable_ro(const struct module *mod)
+{
+ frob_text(&mod->core_layout, set_memory_rw);
+ frob_rodata(&mod->core_layout, set_memory_rw);
+ frob_text(&mod->init_layout, set_memory_rw);
+ frob_rodata(&mod->init_layout, set_memory_rw);
+}
- /*
- * Set NX permissions for module data:
- * - Do not protect first partial page.
- * - Always protect last page.
- */
- if (total_size > text_size) {
- begin_pfn = PFN_UP((unsigned long)base + text_size);
- end_pfn = PFN_UP((unsigned long)base + total_size);
- if (end_pfn > begin_pfn)
- set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);
- }
+void module_enable_ro(const struct module *mod)
+{
+ frob_text(&mod->core_layout, set_memory_ro);
+ frob_rodata(&mod->core_layout, set_memory_ro);
+ frob_text(&mod->init_layout, set_memory_ro);
+ frob_rodata(&mod->init_layout, set_memory_ro);
}
-static void unset_module_core_ro_nx(struct module *mod)
+static void module_enable_nx(const struct module *mod)
{
- set_page_attributes(mod->module_core + mod->core_text_size,
- mod->module_core + mod->core_size,
- set_memory_x);
- set_page_attributes(mod->module_core,
- mod->module_core + mod->core_ro_size,
- set_memory_rw);
+ frob_rodata(&mod->core_layout, set_memory_nx);
+ frob_writable_data(&mod->core_layout, set_memory_nx);
+ frob_rodata(&mod->init_layout, set_memory_nx);
+ frob_writable_data(&mod->init_layout, set_memory_nx);
}
-static void unset_module_init_ro_nx(struct module *mod)
+static void module_disable_nx(const struct module *mod)
{
- set_page_attributes(mod->module_init + mod->init_text_size,
- mod->module_init + mod->init_size,
- set_memory_x);
- set_page_attributes(mod->module_init,
- mod->module_init + mod->init_ro_size,
- set_memory_rw);
+ frob_rodata(&mod->core_layout, set_memory_x);
+ frob_writable_data(&mod->core_layout, set_memory_x);
+ frob_rodata(&mod->init_layout, set_memory_x);
+ frob_writable_data(&mod->init_layout, set_memory_x);
}
/* Iterate through all modules and set each module's text as RW */
@@ -1942,16 +1929,9 @@ void set_all_modules_text_rw(void)
list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED)
continue;
- if ((mod->module_core) && (mod->core_text_size)) {
- set_page_attributes(mod->module_core,
- mod->module_core + mod->core_text_size,
- set_memory_rw);
- }
- if ((mod->module_init) && (mod->init_text_size)) {
- set_page_attributes(mod->module_init,
- mod->module_init + mod->init_text_size,
- set_memory_rw);
- }
+
+ frob_text(&mod->core_layout, set_memory_rw);
+ frob_text(&mod->init_layout, set_memory_rw);
}
mutex_unlock(&module_mutex);
}
@@ -1965,23 +1945,25 @@ void set_all_modules_text_ro(void)
list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED)
continue;
- if ((mod->module_core) && (mod->core_text_size)) {
- set_page_attributes(mod->module_core,
- mod->module_core + mod->core_text_size,
- set_memory_ro);
- }
- if ((mod->module_init) && (mod->init_text_size)) {
- set_page_attributes(mod->module_init,
- mod->module_init + mod->init_text_size,
- set_memory_ro);
- }
+
+ frob_text(&mod->core_layout, set_memory_ro);
+ frob_text(&mod->init_layout, set_memory_ro);
}
mutex_unlock(&module_mutex);
}
+
+static void disable_ro_nx(const struct module_layout *layout)
+{
+ frob_text(layout, set_memory_rw);
+ frob_rodata(layout, set_memory_rw);
+ frob_rodata(layout, set_memory_x);
+ frob_writable_data(layout, set_memory_x);
+}
+
#else
-static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
-static void unset_module_core_ro_nx(struct module *mod) { }
-static void unset_module_init_ro_nx(struct module *mod) { }
+static void disable_ro_nx(const struct module_layout *layout) { }
+static void module_enable_nx(const struct module *mod) { }
+static void module_disable_nx(const struct module *mod) { }
#endif
void __weak module_memfree(void *module_region)
@@ -2033,19 +2015,19 @@ static void free_module(struct module *mod)
synchronize_sched();
mutex_unlock(&module_mutex);
- /* This may be NULL, but that's OK */
- unset_module_init_ro_nx(mod);
+ /* This may be empty, but that's OK */
+ disable_ro_nx(&mod->init_layout);
module_arch_freeing_init(mod);
- module_memfree(mod->module_init);
+ module_memfree(mod->init_layout.base);
kfree(mod->args);
percpu_modfree(mod);
/* Free lock-classes; relies on the preceding sync_rcu(). */
- lockdep_free_key_range(mod->module_core, mod->core_size);
+ lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
/* Finally, free the core (containing the module structure) */
- unset_module_core_ro_nx(mod);
- module_memfree(mod->module_core);
+ disable_ro_nx(&mod->core_layout);
+ module_memfree(mod->core_layout.base);
#ifdef CONFIG_MPU
update_protections(current->mm);
@@ -2248,20 +2230,20 @@ static void layout_sections(struct module *mod, struct load_info *info)
|| s->sh_entsize != ~0UL
|| strstarts(sname, ".init"))
continue;
- s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
+ s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
pr_debug("\t%s\n", sname);
}
switch (m) {
case 0: /* executable */
- mod->core_size = debug_align(mod->core_size);
- mod->core_text_size = mod->core_size;
+ mod->core_layout.size = debug_align(mod->core_layout.size);
+ mod->core_layout.text_size = mod->core_layout.size;
break;
case 1: /* RO: text and ro-data */
- mod->core_size = debug_align(mod->core_size);
- mod->core_ro_size = mod->core_size;
+ mod->core_layout.size = debug_align(mod->core_layout.size);
+ mod->core_layout.ro_size = mod->core_layout.size;
break;
case 3: /* whole core */
- mod->core_size = debug_align(mod->core_size);
+ mod->core_layout.size = debug_align(mod->core_layout.size);
break;
}
}
@@ -2277,21 +2259,21 @@ static void layout_sections(struct module *mod, struct load_info *info)
|| s->sh_entsize != ~0UL
|| !strstarts(sname, ".init"))
continue;
- s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
+ s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
| INIT_OFFSET_MASK);
pr_debug("\t%s\n", sname);
}
switch (m) {
case 0: /* executable */
- mod->init_size = debug_align(mod->init_size);
- mod->init_text_size = mod->init_size;
+ mod->init_layout.size = debug_align(mod->init_layout.size);
+ mod->init_layout.text_size = mod->init_layout.size;
break;
case 1: /* RO: text and ro-data */
- mod->init_size = debug_align(mod->init_size);
- mod->init_ro_size = mod->init_size;
+ mod->init_layout.size = debug_align(mod->init_layout.size);
+ mod->init_layout.ro_size = mod->init_layout.size;
break;
case 3: /* whole init */
- mod->init_size = debug_align(mod->init_size);
+ mod->init_layout.size = debug_align(mod->init_layout.size);
break;
}
}
@@ -2401,7 +2383,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info)
}
if (sym->st_shndx == SHN_UNDEF)
return 'U';
- if (sym->st_shndx == SHN_ABS)
+ if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
return 'a';
if (sym->st_shndx >= SHN_LORESERVE)
return '?';
@@ -2430,7 +2412,7 @@ static char elf_type(const Elf_Sym *sym, const struct load_info *info)
}
static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
- unsigned int shnum)
+ unsigned int shnum, unsigned int pcpundx)
{
const Elf_Shdr *sec;
@@ -2439,6 +2421,11 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
|| !src->st_name)
return false;
+#ifdef CONFIG_KALLSYMS_ALL
+ if (src->st_shndx == pcpundx)
+ return true;
+#endif
+
sec = sechdrs + src->st_shndx;
if (!(sec->sh_flags & SHF_ALLOC)
#ifndef CONFIG_KALLSYMS_ALL
@@ -2466,7 +2453,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
/* Put symbol section at end of init part of module. */
symsect->sh_flags |= SHF_ALLOC;
- symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
+ symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
info->index.sym) | INIT_OFFSET_MASK;
pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
@@ -2476,23 +2463,24 @@ static void layout_symtab(struct module *mod, struct load_info *info)
/* Compute total space required for the core symbols' strtab. */
for (ndst = i = 0; i < nsrc; i++) {
if (i == 0 ||
- is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
+ is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
+ info->index.pcpu)) {
strtab_size += strlen(&info->strtab[src[i].st_name])+1;
ndst++;
}
}
/* Append room for core symbols at end of core part. */
- info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
- info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
- mod->core_size += strtab_size;
- mod->core_size = debug_align(mod->core_size);
+ info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
+ info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
+ mod->core_layout.size += strtab_size;
+ mod->core_layout.size = debug_align(mod->core_layout.size);
/* Put string table section at end of init part of module. */
strsect->sh_flags |= SHF_ALLOC;
- strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
+ strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
info->index.str) | INIT_OFFSET_MASK;
- mod->init_size = debug_align(mod->init_size);
+ mod->init_layout.size = debug_align(mod->init_layout.size);
pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
}
@@ -2513,12 +2501,13 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
for (i = 0; i < mod->num_symtab; i++)
mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
- mod->core_symtab = dst = mod->module_core + info->symoffs;
- mod->core_strtab = s = mod->module_core + info->stroffs;
+ mod->core_symtab = dst = mod->core_layout.base + info->symoffs;
+ mod->core_strtab = s = mod->core_layout.base + info->stroffs;
src = mod->symtab;
for (ndst = i = 0; i < mod->num_symtab; i++) {
if (i == 0 ||
- is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
+ is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
+ info->index.pcpu)) {
dst[ndst] = src[i];
dst[ndst++].st_name = s - mod->core_strtab;
s += strlcpy(s, &mod->strtab[src[i].st_name],
@@ -2964,7 +2953,7 @@ static int move_module(struct module *mod, struct load_info *info)
void *ptr;
/* Do the allocs. */
- ptr = module_alloc(mod->core_size);
+ ptr = module_alloc(mod->core_layout.size);
/*
* The pointer to this block is stored in the module structure
* which is inside the block. Just mark it as not being a
@@ -2974,11 +2963,11 @@ static int move_module(struct module *mod, struct load_info *info)
if (!ptr)
return -ENOMEM;
- memset(ptr, 0, mod->core_size);
- mod->module_core = ptr;
+ memset(ptr, 0, mod->core_layout.size);
+ mod->core_layout.base = ptr;
- if (mod->init_size) {
- ptr = module_alloc(mod->init_size);
+ if (mod->init_layout.size) {
+ ptr = module_alloc(mod->init_layout.size);
/*
* The pointer to this block is stored in the module structure
* which is inside the block. This block doesn't need to be
@@ -2987,13 +2976,13 @@ static int move_module(struct module *mod, struct load_info *info)
*/
kmemleak_ignore(ptr);
if (!ptr) {
- module_memfree(mod->module_core);
+ module_memfree(mod->core_layout.base);
return -ENOMEM;
}
- memset(ptr, 0, mod->init_size);
- mod->module_init = ptr;
+ memset(ptr, 0, mod->init_layout.size);
+ mod->init_layout.base = ptr;
} else
- mod->module_init = NULL;
+ mod->init_layout.base = NULL;
/* Transfer each section which specifies SHF_ALLOC */
pr_debug("final section addresses:\n");
@@ -3005,10 +2994,10 @@ static int move_module(struct module *mod, struct load_info *info)
continue;
if (shdr->sh_entsize & INIT_OFFSET_MASK)
- dest = mod->module_init
+ dest = mod->init_layout.base
+ (shdr->sh_entsize & ~INIT_OFFSET_MASK);
else
- dest = mod->module_core + shdr->sh_entsize;
+ dest = mod->core_layout.base + shdr->sh_entsize;
if (shdr->sh_type != SHT_NOBITS)
memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
@@ -3070,12 +3059,12 @@ static void flush_module_icache(const struct module *mod)
* Do it before processing of module parameters, so the module
* can provide parameter accessor functions of its own.
*/
- if (mod->module_init)
- flush_icache_range((unsigned long)mod->module_init,
- (unsigned long)mod->module_init
- + mod->init_size);
- flush_icache_range((unsigned long)mod->module_core,
- (unsigned long)mod->module_core + mod->core_size);
+ if (mod->init_layout.base)
+ flush_icache_range((unsigned long)mod->init_layout.base,
+ (unsigned long)mod->init_layout.base
+ + mod->init_layout.size);
+ flush_icache_range((unsigned long)mod->core_layout.base,
+ (unsigned long)mod->core_layout.base + mod->core_layout.size);
set_fs(old_fs);
}
@@ -3133,8 +3122,8 @@ static void module_deallocate(struct module *mod, struct load_info *info)
{
percpu_modfree(mod);
module_arch_freeing_init(mod);
- module_memfree(mod->module_init);
- module_memfree(mod->module_core);
+ module_memfree(mod->init_layout.base);
+ module_memfree(mod->core_layout.base);
}
int __weak module_finalize(const Elf_Ehdr *hdr,
@@ -3221,7 +3210,7 @@ static noinline int do_init_module(struct module *mod)
ret = -ENOMEM;
goto fail;
}
- freeinit->module_init = mod->module_init;
+ freeinit->module_init = mod->init_layout.base;
/*
* We want to find out whether @mod uses async during init. Clear
@@ -3279,12 +3268,12 @@ static noinline int do_init_module(struct module *mod)
mod->strtab = mod->core_strtab;
#endif
mod_tree_remove_init(mod);
- unset_module_init_ro_nx(mod);
+ disable_ro_nx(&mod->init_layout);
module_arch_freeing_init(mod);
- mod->module_init = NULL;
- mod->init_size = 0;
- mod->init_ro_size = 0;
- mod->init_text_size = 0;
+ mod->init_layout.base = NULL;
+ mod->init_layout.size = 0;
+ mod->init_layout.ro_size = 0;
+ mod->init_layout.text_size = 0;
/*
* We want to free module_init, but be aware that kallsyms may be
* walking this with preempt disabled. In all the failure paths, we
@@ -3373,17 +3362,9 @@ static int complete_formation(struct module *mod, struct load_info *info)
/* This relies on module_mutex for list integrity. */
module_bug_finalize(info->hdr, info->sechdrs, mod);
- /* Set RO and NX regions for core */
- set_section_ro_nx(mod->module_core,
- mod->core_text_size,
- mod->core_ro_size,
- mod->core_size);
-
- /* Set RO and NX regions for init */
- set_section_ro_nx(mod->module_init,
- mod->init_text_size,
- mod->init_ro_size,
- mod->init_size);
+ /* Set RO and NX regions */
+ module_enable_ro(mod);
+ module_enable_nx(mod);
/* Mark state as coming so strong_try_module_get() ignores us,
* but kallsyms etc. can see us. */
@@ -3548,8 +3529,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
MODULE_STATE_GOING, mod);
/* we can't deallocate the module until we clear memory protection */
- unset_module_init_ro_nx(mod);
- unset_module_core_ro_nx(mod);
+ module_disable_ro(mod);
+ module_disable_nx(mod);
ddebug_cleanup:
dynamic_debug_remove(info->debug);
@@ -3578,7 +3559,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
*/
ftrace_release_mod(mod);
/* Free lock-classes; relies on the preceding sync_rcu() */
- lockdep_free_key_range(mod->module_core, mod->core_size);
+ lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
module_deallocate(mod, info);
free_copy:
@@ -3656,9 +3637,9 @@ static const char *get_ksymbol(struct module *mod,
/* At worse, next value is at end of module */
if (within_module_init(addr, mod))
- nextval = (unsigned long)mod->module_init+mod->init_text_size;
+ nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
else
- nextval = (unsigned long)mod->module_core+mod->core_text_size;
+ nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
/* Scan for closest preceding symbol, and next symbol. (ELF
starts real symbols at 1). */
@@ -3905,7 +3886,7 @@ static int m_show(struct seq_file *m, void *p)
return 0;
seq_printf(m, "%s %u",
- mod->name, mod->init_size + mod->core_size);
+ mod->name, mod->init_layout.size + mod->core_layout.size);
print_unload_info(m, mod);
/* Informative for users. */
@@ -3914,7 +3895,7 @@ static int m_show(struct seq_file *m, void *p)
mod->state == MODULE_STATE_COMING ? "Loading" :
"Live");
/* Used by oprofile and other similar tools. */
- seq_printf(m, " 0x%pK", mod->module_core);
+ seq_printf(m, " 0x%pK", mod->core_layout.base);
/* Taints info */
if (mod->taints)
@@ -4057,8 +4038,8 @@ struct module *__module_text_address(unsigned long addr)
struct module *mod = __module_address(addr);
if (mod) {
/* Make sure it's within the text section. */
- if (!within(addr, mod->module_init, mod->init_text_size)
- && !within(addr, mod->module_core, mod->core_text_size))
+ if (!within(addr, mod->init_layout.base, mod->init_layout.text_size)
+ && !within(addr, mod->core_layout.base, mod->core_layout.text_size))
mod = NULL;
}
return mod;
diff --git a/kernel/panic.c b/kernel/panic.c
index b333380c6bb2..d96469de72dc 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -180,8 +180,7 @@ void panic(const char *fmt, ...)
* panic() is not being callled from OOPS.
*/
debug_locks_off();
- console_trylock();
- console_unlock();
+ console_flush_on_panic();
if (!panic_blink)
panic_blink = no_blink;
diff --git a/kernel/pid.c b/kernel/pid.c
index 78b3d9f80d44..f4ad91b746f1 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -604,5 +604,5 @@ void __init pidmap_init(void)
atomic_dec(&init_pid_ns.pidmap[0].nr_free);
init_pid_ns.pid_cachep = KMEM_CACHE(pid,
- SLAB_HWCACHE_ALIGN | SLAB_PANIC);
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2ce8826f1053..e79439134978 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -48,6 +48,7 @@
#include <linux/uio.h>
#include <asm/uaccess.h>
+#include <asm-generic/sections.h>
#define CREATE_TRACE_POINTS
#include <trace/events/printk.h>
@@ -1660,7 +1661,7 @@ asmlinkage int vprintk_emit(int facility, int level,
const char *dict, size_t dictlen,
const char *fmt, va_list args)
{
- static int recursion_bug;
+ static bool recursion_bug;
static char textbuf[LOG_LINE_MAX];
char *text = textbuf;
size_t text_len = 0;
@@ -1696,7 +1697,7 @@ asmlinkage int vprintk_emit(int facility, int level,
* it can be printed at the next appropriate moment:
*/
if (!oops_in_progress && !lockdep_recursing(current)) {
- recursion_bug = 1;
+ recursion_bug = true;
local_irq_restore(flags);
return 0;
}
@@ -1711,7 +1712,7 @@ asmlinkage int vprintk_emit(int facility, int level,
static const char recursion_msg[] =
"BUG: recent printk recursion!";
- recursion_bug = 0;
+ recursion_bug = false;
/* emit KERN_CRIT message */
printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
NULL, 0, recursion_msg,
@@ -2233,13 +2234,24 @@ void console_unlock(void)
static u64 seen_seq;
unsigned long flags;
bool wake_klogd = false;
- bool retry;
+ bool do_cond_resched, retry;
if (console_suspended) {
up_console_sem();
return;
}
+ /*
+ * Console drivers are called under logbuf_lock, so
+ * @console_may_schedule should be cleared before; however, we may
+ * end up dumping a lot of lines, for example, if called from
+ * console registration path, and should invoke cond_resched()
+ * between lines if allowable. Not doing so can cause a very long
+ * scheduling stall on a slow console leading to RCU stall and
+ * softlockup warnings which exacerbate the issue with more
+ * messages practically incapacitating the system.
+ */
+ do_cond_resched = console_may_schedule;
console_may_schedule = 0;
/* flush buffered message fragment immediately to console */
@@ -2311,6 +2323,9 @@ skip:
call_console_drivers(level, ext_text, ext_len, text, len);
start_critical_timings();
local_irq_restore(flags);
+
+ if (do_cond_resched)
+ cond_resched();
}
console_locked = 0;
@@ -2378,6 +2393,25 @@ void console_unblank(void)
console_unlock();
}
+/**
+ * console_flush_on_panic - flush console content on panic
+ *
+ * Immediately output all pending messages no matter what.
+ */
+void console_flush_on_panic(void)
+{
+ /*
+ * If someone else is holding the console lock, trylock will fail
+ * and may_schedule may be set. Ignore and proceed to unlock so
+ * that messages are flushed out. As this can be called from any
+ * context and we don't want to get preempted while flushing,
+ * ensure may_schedule is cleared.
+ */
+ console_trylock();
+ console_may_schedule = 0;
+ console_unlock();
+}
+
/*
* Return the console tty driver structure and its associated index
*/
@@ -2658,13 +2692,36 @@ int unregister_console(struct console *console)
}
EXPORT_SYMBOL(unregister_console);
+/*
+ * Some boot consoles access data that is in the init section and which will
+ * be discarded after the initcalls have been run. To make sure that no code
+ * will access this data, unregister the boot consoles in a late initcall.
+ *
+ * If for some reason, such as deferred probe or the driver being a loadable
+ * module, the real console hasn't registered yet at this point, there will
+ * be a brief interval in which no messages are logged to the console, which
+ * makes it difficult to diagnose problems that occur during this time.
+ *
+ * To mitigate this problem somewhat, only unregister consoles whose memory
+ * intersects with the init section. Note that code exists elsewhere to get
+ * rid of the boot console as soon as the proper console shows up, so there
+ * won't be side-effects from postponing the removal.
+ */
static int __init printk_late_init(void)
{
struct console *con;
for_each_console(con) {
if (!keep_bootcon && con->flags & CON_BOOT) {
- unregister_console(con);
+ /*
+ * Make sure to unregister boot consoles whose data
+ * resides in the init section before the init section
+ * is discarded. Boot consoles whose data will stick
+ * around will automatically be unregistered when the
+ * proper console replaces them.
+ */
+ if (init_section_intersects(con, sizeof(*con)))
+ unregister_console(con);
}
}
hotcpu_notifier(console_cpu_notify, 0);
diff --git a/kernel/resource.c b/kernel/resource.c
index f150dbbe6f62..09c0597840b0 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1498,8 +1498,15 @@ int iomem_is_exclusive(u64 addr)
break;
if (p->end < addr)
continue;
- if (p->flags & IORESOURCE_BUSY &&
- p->flags & IORESOURCE_EXCLUSIVE) {
+ /*
+ * A resource is exclusive if IORESOURCE_EXCLUSIVE is set
+ * or CONFIG_IO_STRICT_DEVMEM is enabled and the
+ * resource is busy.
+ */
+ if ((p->flags & IORESOURCE_BUSY) == 0)
+ continue;
+ if (IS_ENABLED(CONFIG_IO_STRICT_DEVMEM)
+ || p->flags & IORESOURCE_EXCLUSIVE) {
err = 1;
break;
}
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 34852ee70d54..de0e786b2667 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -213,6 +213,7 @@ static void cpu_idle_loop(void)
*/
__current_set_polling();
+ quiet_vmstat();
tick_nohz_idle_enter();
while (!need_resched()) {
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index edb6de4f5908..a467e6c28a3b 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -529,8 +529,6 @@ static int __init cpu_stop_init(void)
}
early_initcall(cpu_stop_init);
-#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
-
static int __stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
{
struct multi_stop_data msdata = {
@@ -628,5 +626,3 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
mutex_unlock(&stop_cpus_mutex);
return ret ?: done.ret;
}
-
-#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 5faf89ac9ec0..c810f8afdb7f 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1568,6 +1568,28 @@ static struct ctl_table vm_table[] = {
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
+#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS
+ {
+ .procname = "mmap_rnd_bits",
+ .data = &mmap_rnd_bits,
+ .maxlen = sizeof(mmap_rnd_bits),
+ .mode = 0600,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = (void *)&mmap_rnd_bits_min,
+ .extra2 = (void *)&mmap_rnd_bits_max,
+ },
+#endif
+#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
+ {
+ .procname = "mmap_rnd_compat_bits",
+ .data = &mmap_rnd_compat_bits,
+ .maxlen = sizeof(mmap_rnd_compat_bits),
+ .mode = 0600,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = (void *)&mmap_rnd_compat_bits_min,
+ .extra2 = (void *)&mmap_rnd_compat_bits_max,
+ },
+#endif
{ }
};
diff --git a/lib/Kconfig b/lib/Kconfig
index f0df318104e7..5a0c1c83cdf0 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -512,9 +512,9 @@ source "lib/fonts/Kconfig"
config SG_SPLIT
def_bool n
help
- Provides a heler to split scatterlists into chunks, each chunk being a
- scatterlist. This should be selected by a driver or an API which
- whishes to split a scatterlist amongst multiple DMA channel.
+ Provides a helper to split scatterlists into chunks, each chunk being
+ a scatterlist. This should be selected by a driver or an API which
+ whishes to split a scatterlist amongst multiple DMA channels.
#
# sg chaining option
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e2a236a7341f..7d0b49c536c5 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -580,6 +580,14 @@ config DEBUG_VM_RB
If unsure, say N.
+config DEBUG_VM_PGFLAGS
+ bool "Debug page-flags operations"
+ depends on DEBUG_VM
+ help
+ Enables extra validation on page flags operations.
+
+ If unsure, say N.
+
config DEBUG_VIRTUAL
bool "Debug VM translations"
depends on DEBUG_KERNEL && X86
@@ -1589,7 +1597,6 @@ config FAULT_INJECTION_STACKTRACE_FILTER
config LATENCYTOP
bool "Latency measuring infrastructure"
- depends on HAVE_LATENCYTOP_SUPPORT
depends on DEBUG_KERNEL
depends on STACKTRACE_SUPPORT
depends on PROC_FS
@@ -1886,3 +1893,41 @@ source "samples/Kconfig"
source "lib/Kconfig.kgdb"
+config ARCH_HAS_DEVMEM_IS_ALLOWED
+ bool
+
+config STRICT_DEVMEM
+ bool "Filter access to /dev/mem"
+ depends on MMU
+ depends on ARCH_HAS_DEVMEM_IS_ALLOWED
+ default y if TILE || PPC
+ ---help---
+ If this option is disabled, you allow userspace (root) access to all
+ of memory, including kernel and userspace memory. Accidental
+ access to this is obviously disastrous, but specific access can
+ be used by people debugging the kernel. Note that with PAT support
+ enabled, even in this case there are restrictions on /dev/mem
+ use due to the cache aliasing requirements.
+
+ If this option is switched on, and IO_STRICT_DEVMEM=n, the /dev/mem
+ file only allows userspace access to PCI space and the BIOS code and
+ data regions. This is sufficient for dosemu and X and all common
+ users of /dev/mem.
+
+ If in doubt, say Y.
+
+config IO_STRICT_DEVMEM
+ bool "Filter I/O access to /dev/mem"
+ depends on STRICT_DEVMEM
+ ---help---
+ If this option is disabled, you allow userspace (root) access to all
+ io-memory regardless of whether a driver is actively using that
+ range. Accidental access to this is obviously disastrous, but
+ specific access can be used by people debugging kernel drivers.
+
+ If this option is switched on, the /dev/mem file only allows
+ userspace access to *idle* io-memory ranges (see /proc/iomem) This
+ may break traditional users of /dev/mem (dosemu, legacy X, etc...)
+ if the driver using a given range cannot be disabled.
+
+ If in doubt, say Y.
diff --git a/lib/div64.c b/lib/div64.c
index 62a698a432bc..7f345259c32f 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -13,7 +13,8 @@
*
* Code generated for this function might be very inefficient
* for some CPUs. __div64_32() can be overridden by linking arch-specific
- * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
+ * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S
+ * or by defining a preprocessor macro in arch/include/asm/div64.h.
*/
#include <linux/export.h>
@@ -23,6 +24,7 @@
/* Not needed on 64bit architectures */
#if BITS_PER_LONG == 32
+#ifndef __div64_32
uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
{
uint64_t rem = *n;
@@ -55,8 +57,8 @@ uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
*n = res;
return rem;
}
-
EXPORT_SYMBOL(__div64_32);
+#endif
#ifndef div_s64_rem
s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index d34bd24c2c84..4a1515f4b452 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -1181,7 +1181,7 @@ static inline bool overlap(void *addr, unsigned long len, void *start, void *end
static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len)
{
- if (overlap(addr, len, _text, _etext) ||
+ if (overlap(addr, len, _stext, _etext) ||
overlap(addr, len, __start_rodata, __end_rodata))
err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);
}
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 116a166b096f..0a1139644d32 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -270,6 +270,25 @@ EXPORT_SYMBOL(gen_pool_destroy);
*/
unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
{
+ return gen_pool_alloc_algo(pool, size, pool->algo, pool->data);
+}
+EXPORT_SYMBOL(gen_pool_alloc);
+
+/**
+ * gen_pool_alloc_algo - allocate special memory from the pool
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ * @algo: algorithm passed from caller
+ * @data: data passed to algorithm
+ *
+ * Allocate the requested number of bytes from the specified pool.
+ * Uses the pool allocation function (with first-fit algorithm by default).
+ * Can not be used in NMI handler on architectures without
+ * NMI-safe cmpxchg implementation.
+ */
+unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size,
+ genpool_algo_t algo, void *data)
+{
struct gen_pool_chunk *chunk;
unsigned long addr = 0;
int order = pool->min_alloc_order;
@@ -290,8 +309,8 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
end_bit = chunk_size(chunk) >> order;
retry:
- start_bit = pool->algo(chunk->bits, end_bit, start_bit, nbits,
- pool->data);
+ start_bit = algo(chunk->bits, end_bit, start_bit,
+ nbits, data, pool);
if (start_bit >= end_bit)
continue;
remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
@@ -310,7 +329,7 @@ retry:
rcu_read_unlock();
return addr;
}
-EXPORT_SYMBOL(gen_pool_alloc);
+EXPORT_SYMBOL(gen_pool_alloc_algo);
/**
* gen_pool_dma_alloc - allocate special memory from the pool for DMA usage
@@ -501,15 +520,74 @@ EXPORT_SYMBOL(gen_pool_set_algo);
* @start: The bitnumber to start searching at
* @nr: The number of zeroed bits we're looking for
* @data: additional data - unused
+ * @pool: pool to find the fit region memory from
*/
unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
- unsigned long start, unsigned int nr, void *data)
+ unsigned long start, unsigned int nr, void *data,
+ struct gen_pool *pool)
{
return bitmap_find_next_zero_area(map, size, start, nr, 0);
}
EXPORT_SYMBOL(gen_pool_first_fit);
/**
+ * gen_pool_first_fit_align - find the first available region
+ * of memory matching the size requirement (alignment constraint)
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @data: data for alignment
+ * @pool: pool to get order from
+ */
+unsigned long gen_pool_first_fit_align(unsigned long *map, unsigned long size,
+ unsigned long start, unsigned int nr, void *data,
+ struct gen_pool *pool)
+{
+ struct genpool_data_align *alignment;
+ unsigned long align_mask;
+ int order;
+
+ alignment = data;
+ order = pool->min_alloc_order;
+ align_mask = ((alignment->align + (1UL << order) - 1) >> order) - 1;
+ return bitmap_find_next_zero_area(map, size, start, nr, align_mask);
+}
+EXPORT_SYMBOL(gen_pool_first_fit_align);
+
+/**
+ * gen_pool_fixed_alloc - reserve a specific region
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @data: data for alignment
+ * @pool: pool to get order from
+ */
+unsigned long gen_pool_fixed_alloc(unsigned long *map, unsigned long size,
+ unsigned long start, unsigned int nr, void *data,
+ struct gen_pool *pool)
+{
+ struct genpool_data_fixed *fixed_data;
+ int order;
+ unsigned long offset_bit;
+ unsigned long start_bit;
+
+ fixed_data = data;
+ order = pool->min_alloc_order;
+ offset_bit = fixed_data->offset >> order;
+ if (WARN_ON(fixed_data->offset & ((1UL << order) - 1)))
+ return size;
+
+ start_bit = bitmap_find_next_zero_area(map, size,
+ start + offset_bit, nr, 0);
+ if (start_bit != offset_bit)
+ start_bit = size;
+ return start_bit;
+}
+EXPORT_SYMBOL(gen_pool_fixed_alloc);
+
+/**
* gen_pool_first_fit_order_align - find the first available region
* of memory matching the size requirement. The region will be aligned
* to the order of the size specified.
@@ -518,10 +596,11 @@ EXPORT_SYMBOL(gen_pool_first_fit);
* @start: The bitnumber to start searching at
* @nr: The number of zeroed bits we're looking for
* @data: additional data - unused
+ * @pool: pool to find the fit region memory from
*/
unsigned long gen_pool_first_fit_order_align(unsigned long *map,
unsigned long size, unsigned long start,
- unsigned int nr, void *data)
+ unsigned int nr, void *data, struct gen_pool *pool)
{
unsigned long align_mask = roundup_pow_of_two(nr) - 1;
@@ -537,12 +616,14 @@ EXPORT_SYMBOL(gen_pool_first_fit_order_align);
* @start: The bitnumber to start searching at
* @nr: The number of zeroed bits we're looking for
* @data: additional data - unused
+ * @pool: pool to find the fit region memory from
*
* Iterate over the bitmap to find the smallest free region
* which we can allocate the memory.
*/
unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
- unsigned long start, unsigned int nr, void *data)
+ unsigned long start, unsigned int nr, void *data,
+ struct gen_pool *pool)
{
unsigned long start_bit = size;
unsigned long len = size + 1;
diff --git a/lib/kasprintf.c b/lib/kasprintf.c
index f194e6e593e1..7f6c506a4942 100644
--- a/lib/kasprintf.c
+++ b/lib/kasprintf.c
@@ -13,19 +13,21 @@
/* Simplified asprintf. */
char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
{
- unsigned int len;
+ unsigned int first, second;
char *p;
va_list aq;
va_copy(aq, ap);
- len = vsnprintf(NULL, 0, fmt, aq);
+ first = vsnprintf(NULL, 0, fmt, aq);
va_end(aq);
- p = kmalloc_track_caller(len+1, gfp);
+ p = kmalloc_track_caller(first+1, gfp);
if (!p)
return NULL;
- vsnprintf(p, len+1, fmt, ap);
+ second = vsnprintf(p, first+1, fmt, ap);
+ WARN(first != second, "different return values (%u and %u) from vsnprintf(\"%s\", ...)",
+ first, second, fmt);
return p;
}
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 3859bf63561c..3345a089ef7b 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -12,6 +12,13 @@
#include <linux/kernel.h>
#include <linux/rculist.h>
+static struct list_head force_poison;
+void list_force_poison(struct list_head *entry)
+{
+ entry->next = &force_poison;
+ entry->prev = &force_poison;
+}
+
/*
* Insert a new entry between two known consecutive entries.
*
@@ -23,6 +30,8 @@ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
+ WARN(new->next == &force_poison || new->prev == &force_poison,
+ "list_add attempted on force-poisoned entry\n");
WARN(next->prev != prev,
"list_add corruption. next->prev should be "
"prev (%p), but was %p. (next=%p).\n",
diff --git a/lib/raid6/altivec.uc b/lib/raid6/altivec.uc
index bec27fce7501..682aae8a1fef 100644
--- a/lib/raid6/altivec.uc
+++ b/lib/raid6/altivec.uc
@@ -101,6 +101,7 @@ static void raid6_altivec$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
raid6_altivec$#_gen_syndrome_real(disks, bytes, ptrs);
+ disable_kernel_altivec();
preempt_enable();
}
diff --git a/lib/test_firmware.c b/lib/test_firmware.c
index 86374c1c49a4..a3e8ec3fb1c5 100644
--- a/lib/test_firmware.c
+++ b/lib/test_firmware.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
+#include <linux/completion.h>
#include <linux/firmware.h>
#include <linux/device.h>
#include <linux/fs.h>
@@ -54,10 +55,9 @@ static ssize_t trigger_request_store(struct device *dev,
int rc;
char *name;
- name = kzalloc(count + 1, GFP_KERNEL);
+ name = kstrndup(buf, count, GFP_KERNEL);
if (!name)
return -ENOSPC;
- memcpy(name, buf, count);
pr_info("loading '%s'\n", name);
@@ -65,17 +65,73 @@ static ssize_t trigger_request_store(struct device *dev,
release_firmware(test_firmware);
test_firmware = NULL;
rc = request_firmware(&test_firmware, name, dev);
- if (rc)
+ if (rc) {
pr_info("load of '%s' failed: %d\n", name, rc);
- pr_info("loaded: %zu\n", test_firmware ? test_firmware->size : 0);
+ goto out;
+ }
+ pr_info("loaded: %zu\n", test_firmware->size);
+ rc = count;
+
+out:
mutex_unlock(&test_fw_mutex);
kfree(name);
- return count;
+ return rc;
}
static DEVICE_ATTR_WO(trigger_request);
+static DECLARE_COMPLETION(async_fw_done);
+
+static void trigger_async_request_cb(const struct firmware *fw, void *context)
+{
+ test_firmware = fw;
+ complete(&async_fw_done);
+}
+
+static ssize_t trigger_async_request_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ char *name;
+
+ name = kstrndup(buf, count, GFP_KERNEL);
+ if (!name)
+ return -ENOSPC;
+
+ pr_info("loading '%s'\n", name);
+
+ mutex_lock(&test_fw_mutex);
+ release_firmware(test_firmware);
+ test_firmware = NULL;
+ rc = request_firmware_nowait(THIS_MODULE, 1, name, dev, GFP_KERNEL,
+ NULL, trigger_async_request_cb);
+ if (rc) {
+ pr_info("async load of '%s' failed: %d\n", name, rc);
+ kfree(name);
+ goto out;
+ }
+ /* Free 'name' ASAP, to test for race conditions */
+ kfree(name);
+
+ wait_for_completion(&async_fw_done);
+
+ if (test_firmware) {
+ pr_info("loaded: %zu\n", test_firmware->size);
+ rc = count;
+ } else {
+ pr_err("failed to async load firmware\n");
+ rc = -ENODEV;
+ }
+
+out:
+ mutex_unlock(&test_fw_mutex);
+
+ return rc;
+}
+static DEVICE_ATTR_WO(trigger_async_request);
+
static int __init test_firmware_init(void)
{
int rc;
@@ -92,9 +148,20 @@ static int __init test_firmware_init(void)
goto dereg;
}
+ rc = device_create_file(test_fw_misc_device.this_device,
+ &dev_attr_trigger_async_request);
+ if (rc) {
+ pr_err("could not create async sysfs interface: %d\n", rc);
+ goto remove_file;
+ }
+
pr_warn("interface ready\n");
return 0;
+
+remove_file:
+ device_remove_file(test_fw_misc_device.this_device,
+ &dev_attr_trigger_async_request);
dereg:
misc_deregister(&test_fw_misc_device);
return rc;
@@ -106,6 +173,8 @@ static void __exit test_firmware_exit(void)
{
release_firmware(test_firmware);
device_remove_file(test_fw_misc_device.this_device,
+ &dev_attr_trigger_async_request);
+ device_remove_file(test_fw_misc_device.this_device,
&dev_attr_trigger_request);
misc_deregister(&test_fw_misc_device);
pr_warn("removed interface\n");
diff --git a/lib/test_printf.c b/lib/test_printf.c
index c5a666af9ba5..4f6ae60433bc 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -12,10 +12,13 @@
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/bitmap.h>
+#include <linux/dcache.h>
#include <linux/socket.h>
#include <linux/in.h>
#define BUF_SIZE 256
+#define PAD_SIZE 16
#define FILL_CHAR '$'
#define PTR1 ((void*)0x01234567)
@@ -39,6 +42,7 @@
static unsigned total_tests __initdata;
static unsigned failed_tests __initdata;
static char *test_buffer __initdata;
+static char *alloced_buffer __initdata;
static int __printf(4, 0) __init
do_test(int bufsize, const char *expect, int elen,
@@ -49,7 +53,7 @@ do_test(int bufsize, const char *expect, int elen,
total_tests++;
- memset(test_buffer, FILL_CHAR, BUF_SIZE);
+ memset(alloced_buffer, FILL_CHAR, BUF_SIZE + 2*PAD_SIZE);
va_copy(aq, ap);
ret = vsnprintf(test_buffer, bufsize, fmt, aq);
va_end(aq);
@@ -60,8 +64,13 @@ do_test(int bufsize, const char *expect, int elen,
return 1;
}
+ if (memchr_inv(alloced_buffer, FILL_CHAR, PAD_SIZE)) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n", bufsize, fmt);
+ return 1;
+ }
+
if (!bufsize) {
- if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE)) {
+ if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE + PAD_SIZE)) {
pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n",
fmt);
return 1;
@@ -76,6 +85,12 @@ do_test(int bufsize, const char *expect, int elen,
return 1;
}
+ if (memchr_inv(test_buffer + written + 1, FILL_CHAR, BUF_SIZE + PAD_SIZE - (written + 1))) {
+ pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n",
+ bufsize, fmt);
+ return 1;
+ }
+
if (memcmp(test_buffer, expect, written)) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
bufsize, fmt, test_buffer, written, expect);
@@ -91,7 +106,12 @@ __test(const char *expect, int elen, const char *fmt, ...)
int rand;
char *p;
- BUG_ON(elen >= BUF_SIZE);
+ if (elen >= BUF_SIZE) {
+ pr_err("error in test suite: expected output length %d too long. Format was '%s'.\n",
+ elen, fmt);
+ failed_tests++;
+ return;
+ }
va_start(ap, fmt);
@@ -109,6 +129,7 @@ __test(const char *expect, int elen, const char *fmt, ...)
p = kvasprintf(GFP_KERNEL, fmt, ap);
if (p) {
+ total_tests++;
if (memcmp(p, expect, elen+1)) {
pr_warn("kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n",
fmt, p, expect);
@@ -140,6 +161,30 @@ test_number(void)
test("0x1234abcd ", "%#-12x", 0x1234abcd);
test(" 0x1234abcd", "%#12x", 0x1234abcd);
test("0|001| 12|+123| 1234|-123|-1234", "%d|%03d|%3d|%+d|% d|%+d|% d", 0, 1, 12, 123, 1234, -123, -1234);
+ test("0|1|1|128|255", "%hhu|%hhu|%hhu|%hhu|%hhu", 0, 1, 257, 128, -1);
+ test("0|1|1|-128|-1", "%hhd|%hhd|%hhd|%hhd|%hhd", 0, 1, 257, 128, -1);
+ test("2015122420151225", "%ho%ho%#ho", 1037, 5282, -11627);
+ /*
+ * POSIX/C99: »The result of converting zero with an explicit
+ * precision of zero shall be no characters.« Hence the output
+ * from the below test should really be "00|0||| ". However,
+ * the kernel's printf also produces a single 0 in that
+ * case. This test case simply documents the current
+ * behaviour.
+ */
+ test("00|0|0|0|0", "%.2d|%.1d|%.0d|%.*d|%1.0d", 0, 0, 0, 0, 0, 0);
+#ifndef __CHAR_UNSIGNED__
+ {
+ /*
+ * Passing a 'char' to a %02x specifier doesn't do
+ * what was presumably the intention when char is
+ * signed and the value is negative. One must either &
+ * with 0xff or cast to u8.
+ */
+ char val = -16;
+ test("0xfffffff0|0xf0|0xf0", "%#02x|%#02x|%#02x", val, val & 0xff, (u8)val);
+ }
+#endif
}
static void __init
@@ -148,14 +193,23 @@ test_string(void)
test("", "%s%.0s", "", "123");
test("ABCD|abc|123", "%s|%.3s|%.*s", "ABCD", "abcdef", 3, "123456");
test("1 | 2|3 | 4|5 ", "%-3s|%3s|%-*s|%*s|%*s", "1", "2", 3, "3", 3, "4", -3, "5");
+ test("1234 ", "%-10.4s", "123456");
+ test(" 1234", "%10.4s", "123456");
/*
- * POSIX and C99 say that a missing precision should be
- * treated as a precision of 0. However, the kernel's printf
- * implementation treats this case as if the . wasn't
- * present. Let's add a test case documenting the current
- * behaviour; should anyone ever feel the need to follow the
- * standards more closely, this can be revisited.
+ * POSIX and C99 say that a negative precision (which is only
+ * possible to pass via a * argument) should be treated as if
+ * the precision wasn't present, and that if the precision is
+ * omitted (as in %.s), the precision should be taken to be
+ * 0. However, the kernel's printf behave exactly opposite,
+ * treating a negative precision as 0 and treating an omitted
+ * precision specifier as if no precision was given.
+ *
+ * These test cases document the current behaviour; should
+ * anyone ever feel the need to follow the standards more
+ * closely, this can be revisited.
*/
+ test(" ", "%4.*s", -5, "123456");
+ test("123456", "%.s", "123456");
test("a||", "%.s|%.0s|%.*s", "a", "b", 0, "c");
test("a | | ", "%-3.s|%-3.0s|%-3.*s", "a", "b", 0, "c");
}
@@ -273,9 +327,35 @@ uuid(void)
test("03020100-0504-0706-0809-0A0B0C0D0E0F", "%pUL", uuid);
}
+static struct dentry test_dentry[4] __initdata = {
+ { .d_parent = &test_dentry[0],
+ .d_name = QSTR_INIT(test_dentry[0].d_iname, 3),
+ .d_iname = "foo" },
+ { .d_parent = &test_dentry[0],
+ .d_name = QSTR_INIT(test_dentry[1].d_iname, 5),
+ .d_iname = "bravo" },
+ { .d_parent = &test_dentry[1],
+ .d_name = QSTR_INIT(test_dentry[2].d_iname, 4),
+ .d_iname = "alfa" },
+ { .d_parent = &test_dentry[2],
+ .d_name = QSTR_INIT(test_dentry[3].d_iname, 5),
+ .d_iname = "romeo" },
+};
+
static void __init
dentry(void)
{
+ test("foo", "%pd", &test_dentry[0]);
+ test("foo", "%pd2", &test_dentry[0]);
+
+ test("romeo", "%pd", &test_dentry[3]);
+ test("alfa/romeo", "%pd2", &test_dentry[3]);
+ test("bravo/alfa/romeo", "%pd3", &test_dentry[3]);
+ test("/bravo/alfa/romeo", "%pd4", &test_dentry[3]);
+ test("/bravo/alfa", "%pd4", &test_dentry[2]);
+
+ test("bravo/alfa |bravo/alfa ", "%-12pd2|%*pd2", &test_dentry[2], -12, &test_dentry[2]);
+ test(" bravo/alfa| bravo/alfa", "%12pd2|%*pd2", &test_dentry[2], 12, &test_dentry[2]);
}
static void __init
@@ -289,6 +369,20 @@ struct_clk(void)
}
static void __init
+large_bitmap(void)
+{
+ const int nbits = 1 << 16;
+ unsigned long *bits = kcalloc(BITS_TO_LONGS(nbits), sizeof(long), GFP_KERNEL);
+ if (!bits)
+ return;
+
+ bitmap_set(bits, 1, 20);
+ bitmap_set(bits, 60000, 15);
+ test("1-20,60000-60014", "%*pbl", nbits, bits);
+ kfree(bits);
+}
+
+static void __init
bitmap(void)
{
DECLARE_BITMAP(bits, 20);
@@ -307,6 +401,8 @@ bitmap(void)
bitmap_fill(bits, 20);
test("fffff|fffff", "%20pb|%*pb", bits, 20, bits);
test("0-19|0-19", "%20pbl|%*pbl", bits, 20, bits);
+
+ large_bitmap();
}
static void __init
@@ -337,16 +433,17 @@ test_pointer(void)
static int __init
test_printf_init(void)
{
- test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
- if (!test_buffer)
+ alloced_buffer = kmalloc(BUF_SIZE + 2*PAD_SIZE, GFP_KERNEL);
+ if (!alloced_buffer)
return -ENOMEM;
+ test_buffer = alloced_buffer + PAD_SIZE;
test_basic();
test_number();
test_string();
test_pointer();
- kfree(test_buffer);
+ kfree(alloced_buffer);
if (failed_tests == 0)
pr_info("all %u tests passed\n", total_tests);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index ac3f9476b776..48ff9c36644d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -383,13 +383,14 @@ enum format_type {
};
struct printf_spec {
- u8 type; /* format_type enum */
- u8 flags; /* flags to number() */
- u8 base; /* number base, 8, 10 or 16 only */
- u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */
- s16 field_width; /* width of output field */
- s16 precision; /* # of digits/chars */
-};
+ unsigned int type:8; /* format_type enum */
+ signed int field_width:24; /* width of output field */
+ unsigned int flags:8; /* flags to number() */
+ unsigned int base:8; /* number base, 8, 10 or 16 only */
+ signed int precision:16; /* # of digits/chars */
+} __packed;
+#define FIELD_WIDTH_MAX ((1 << 23) - 1)
+#define PRECISION_MAX ((1 << 15) - 1)
static noinline_for_stack
char *number(char *buf, char *end, unsigned long long num,
@@ -402,6 +403,10 @@ char *number(char *buf, char *end, unsigned long long num,
int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
int i;
bool is_zero = num == 0LL;
+ int field_width = spec.field_width;
+ int precision = spec.precision;
+
+ BUILD_BUG_ON(sizeof(struct printf_spec) != 8);
/* locase = 0 or 0x20. ORing digits or letters with 'locase'
* produces same digits or (maybe lowercased) letters */
@@ -413,20 +418,20 @@ char *number(char *buf, char *end, unsigned long long num,
if ((signed long long)num < 0) {
sign = '-';
num = -(signed long long)num;
- spec.field_width--;
+ field_width--;
} else if (spec.flags & PLUS) {
sign = '+';
- spec.field_width--;
+ field_width--;
} else if (spec.flags & SPACE) {
sign = ' ';
- spec.field_width--;
+ field_width--;
}
}
if (need_pfx) {
if (spec.base == 16)
- spec.field_width -= 2;
+ field_width -= 2;
else if (!is_zero)
- spec.field_width--;
+ field_width--;
}
/* generate full string in tmp[], in reverse order */
@@ -448,12 +453,12 @@ char *number(char *buf, char *end, unsigned long long num,
}
/* printing 100 using %2d gives "100", not "00" */
- if (i > spec.precision)
- spec.precision = i;
+ if (i > precision)
+ precision = i;
/* leading space padding */
- spec.field_width -= spec.precision;
+ field_width -= precision;
if (!(spec.flags & (ZEROPAD | LEFT))) {
- while (--spec.field_width >= 0) {
+ while (--field_width >= 0) {
if (buf < end)
*buf = ' ';
++buf;
@@ -482,14 +487,14 @@ char *number(char *buf, char *end, unsigned long long num,
if (!(spec.flags & LEFT)) {
char c = ' ' + (spec.flags & ZEROPAD);
BUILD_BUG_ON(' ' + ZEROPAD != '0');
- while (--spec.field_width >= 0) {
+ while (--field_width >= 0) {
if (buf < end)
*buf = c;
++buf;
}
}
/* hmm even more zero padding? */
- while (i <= --spec.precision) {
+ while (i <= --precision) {
if (buf < end)
*buf = '0';
++buf;
@@ -501,7 +506,7 @@ char *number(char *buf, char *end, unsigned long long num,
++buf;
}
/* trailing space padding */
- while (--spec.field_width >= 0) {
+ while (--field_width >= 0) {
if (buf < end)
*buf = ' ';
++buf;
@@ -511,37 +516,20 @@ char *number(char *buf, char *end, unsigned long long num,
}
static noinline_for_stack
-char *string(char *buf, char *end, const char *s, struct printf_spec spec)
+char *special_hex_number(char *buf, char *end, unsigned long long num, int size)
{
- int len, i;
-
- if ((unsigned long)s < PAGE_SIZE)
- s = "(null)";
+ struct printf_spec spec;
- len = strnlen(s, spec.precision);
-
- if (!(spec.flags & LEFT)) {
- while (len < spec.field_width--) {
- if (buf < end)
- *buf = ' ';
- ++buf;
- }
- }
- for (i = 0; i < len; ++i) {
- if (buf < end)
- *buf = *s;
- ++buf; ++s;
- }
- while (len < spec.field_width--) {
- if (buf < end)
- *buf = ' ';
- ++buf;
- }
+ spec.type = FORMAT_TYPE_PTR;
+ spec.field_width = 2 + 2 * size; /* 0x + hex */
+ spec.flags = SPECIAL | SMALL | ZEROPAD;
+ spec.base = 16;
+ spec.precision = -1;
- return buf;
+ return number(buf, end, num, spec);
}
-static void widen(char *buf, char *end, unsigned len, unsigned spaces)
+static void move_right(char *buf, char *end, unsigned len, unsigned spaces)
{
size_t size;
if (buf >= end) /* nowhere to put anything */
@@ -559,6 +547,56 @@ static void widen(char *buf, char *end, unsigned len, unsigned spaces)
memset(buf, ' ', spaces);
}
+/*
+ * Handle field width padding for a string.
+ * @buf: current buffer position
+ * @n: length of string
+ * @end: end of output buffer
+ * @spec: for field width and flags
+ * Returns: new buffer position after padding.
+ */
+static noinline_for_stack
+char *widen_string(char *buf, int n, char *end, struct printf_spec spec)
+{
+ unsigned spaces;
+
+ if (likely(n >= spec.field_width))
+ return buf;
+ /* we want to pad the sucker */
+ spaces = spec.field_width - n;
+ if (!(spec.flags & LEFT)) {
+ move_right(buf - n, end, n, spaces);
+ return buf + spaces;
+ }
+ while (spaces--) {
+ if (buf < end)
+ *buf = ' ';
+ ++buf;
+ }
+ return buf;
+}
+
+static noinline_for_stack
+char *string(char *buf, char *end, const char *s, struct printf_spec spec)
+{
+ int len = 0;
+ size_t lim = spec.precision;
+
+ if ((unsigned long)s < PAGE_SIZE)
+ s = "(null)";
+
+ while (lim--) {
+ char c = *s++;
+ if (!c)
+ break;
+ if (buf < end)
+ *buf = c;
+ ++buf;
+ ++len;
+ }
+ return widen_string(buf, len, end, spec);
+}
+
static noinline_for_stack
char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec,
const char *fmt)
@@ -600,20 +638,7 @@ char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_sp
*buf = c;
}
rcu_read_unlock();
- if (n < spec.field_width) {
- /* we want to pad the sucker */
- unsigned spaces = spec.field_width - n;
- if (!(spec.flags & LEFT)) {
- widen(buf - n, end, n, spaces);
- return buf + spaces;
- }
- while (spaces--) {
- if (buf < end)
- *buf = ' ';
- ++buf;
- }
- }
- return buf;
+ return widen_string(buf, n, end, spec);
}
#ifdef CONFIG_BLOCK
@@ -659,11 +684,7 @@ char *symbol_string(char *buf, char *end, void *ptr,
return string(buf, end, sym, spec);
#else
- spec.field_width = 2 * sizeof(void *);
- spec.flags |= SPECIAL | SMALL | ZEROPAD;
- spec.base = 16;
-
- return number(buf, end, value, spec);
+ return special_hex_number(buf, end, value, sizeof(void *));
#endif
}
@@ -1324,40 +1345,45 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
return string(buf, end, uuid, spec);
}
-static
-char *netdev_feature_string(char *buf, char *end, const u8 *addr,
- struct printf_spec spec)
+static noinline_for_stack
+char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt)
{
- spec.flags |= SPECIAL | SMALL | ZEROPAD;
- if (spec.field_width == -1)
- spec.field_width = 2 + 2 * sizeof(netdev_features_t);
- spec.base = 16;
+ unsigned long long num;
+ int size;
- return number(buf, end, *(const netdev_features_t *)addr, spec);
+ switch (fmt[1]) {
+ case 'F':
+ num = *(const netdev_features_t *)addr;
+ size = sizeof(netdev_features_t);
+ break;
+ default:
+ num = (unsigned long)addr;
+ size = sizeof(unsigned long);
+ break;
+ }
+
+ return special_hex_number(buf, end, num, size);
}
static noinline_for_stack
-char *address_val(char *buf, char *end, const void *addr,
- struct printf_spec spec, const char *fmt)
+char *address_val(char *buf, char *end, const void *addr, const char *fmt)
{
unsigned long long num;
-
- spec.flags |= SPECIAL | SMALL | ZEROPAD;
- spec.base = 16;
+ int size;
switch (fmt[1]) {
case 'd':
num = *(const dma_addr_t *)addr;
- spec.field_width = sizeof(dma_addr_t) * 2 + 2;
+ size = sizeof(dma_addr_t);
break;
case 'p':
default:
num = *(const phys_addr_t *)addr;
- spec.field_width = sizeof(phys_addr_t) * 2 + 2;
+ size = sizeof(phys_addr_t);
break;
}
- return number(buf, end, num, spec);
+ return special_hex_number(buf, end, num, size);
}
static noinline_for_stack
@@ -1376,10 +1402,7 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
#ifdef CONFIG_COMMON_CLK
return string(buf, end, __clk_get_name(clk), spec);
#else
- spec.base = 16;
- spec.field_width = sizeof(unsigned long) * 2 + 2;
- spec.flags |= SPECIAL | SMALL | ZEROPAD;
- return number(buf, end, (unsigned long)clk, spec);
+ return special_hex_number(buf, end, (unsigned long)clk, sizeof(unsigned long));
#endif
}
}
@@ -1609,13 +1632,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
break;
case 'N':
- switch (fmt[1]) {
- case 'F':
- return netdev_feature_string(buf, end, ptr, spec);
- }
- break;
+ return netdev_bits(buf, end, ptr, fmt);
case 'a':
- return address_val(buf, end, ptr, spec, fmt);
+ return address_val(buf, end, ptr, fmt);
case 'd':
return dentry_name(buf, end, ptr, spec, fmt);
case 'C':
@@ -1664,6 +1683,7 @@ static noinline_for_stack
int format_decode(const char *fmt, struct printf_spec *spec)
{
const char *start = fmt;
+ char qualifier;
/* we finished early by reading the field width */
if (spec->type == FORMAT_TYPE_WIDTH) {
@@ -1746,16 +1766,16 @@ precision:
qualifier:
/* get the conversion qualifier */
- spec->qualifier = -1;
+ qualifier = 0;
if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
_tolower(*fmt) == 'z' || *fmt == 't') {
- spec->qualifier = *fmt++;
- if (unlikely(spec->qualifier == *fmt)) {
- if (spec->qualifier == 'l') {
- spec->qualifier = 'L';
+ qualifier = *fmt++;
+ if (unlikely(qualifier == *fmt)) {
+ if (qualifier == 'l') {
+ qualifier = 'L';
++fmt;
- } else if (spec->qualifier == 'h') {
- spec->qualifier = 'H';
+ } else if (qualifier == 'h') {
+ qualifier = 'H';
++fmt;
}
}
@@ -1812,19 +1832,19 @@ qualifier:
return fmt - start;
}
- if (spec->qualifier == 'L')
+ if (qualifier == 'L')
spec->type = FORMAT_TYPE_LONG_LONG;
- else if (spec->qualifier == 'l') {
+ else if (qualifier == 'l') {
BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG);
spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN);
- } else if (_tolower(spec->qualifier) == 'z') {
+ } else if (_tolower(qualifier) == 'z') {
spec->type = FORMAT_TYPE_SIZE_T;
- } else if (spec->qualifier == 't') {
+ } else if (qualifier == 't') {
spec->type = FORMAT_TYPE_PTRDIFF;
- } else if (spec->qualifier == 'H') {
+ } else if (qualifier == 'H') {
BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE);
spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN);
- } else if (spec->qualifier == 'h') {
+ } else if (qualifier == 'h') {
BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT);
spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN);
} else {
@@ -1835,6 +1855,24 @@ qualifier:
return ++fmt - start;
}
+static void
+set_field_width(struct printf_spec *spec, int width)
+{
+ spec->field_width = width;
+ if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
+ spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
+ }
+}
+
+static void
+set_precision(struct printf_spec *spec, int prec)
+{
+ spec->precision = prec;
+ if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
+ spec->precision = clamp(prec, 0, PRECISION_MAX);
+ }
+}
+
/**
* vsnprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
@@ -1902,11 +1940,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
}
case FORMAT_TYPE_WIDTH:
- spec.field_width = va_arg(args, int);
+ set_field_width(&spec, va_arg(args, int));
break;
case FORMAT_TYPE_PRECISION:
- spec.precision = va_arg(args, int);
+ set_precision(&spec, va_arg(args, int));
break;
case FORMAT_TYPE_CHAR: {
@@ -2346,11 +2384,11 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
}
case FORMAT_TYPE_WIDTH:
- spec.field_width = get_arg(int);
+ set_field_width(&spec, get_arg(int));
break;
case FORMAT_TYPE_PRECISION:
- spec.precision = get_arg(int);
+ set_precision(&spec, get_arg(int));
break;
case FORMAT_TYPE_CHAR: {
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 7340353f8aea..cc5d29d2da9b 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -672,7 +672,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
if (!ret) {
- bdi->wb.memcg_css = mem_cgroup_root_css;
+ bdi->wb.memcg_css = &root_mem_cgroup->css;
bdi->wb.blkcg_css = blkcg_root_css;
}
return ret;
diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c
index d3116be5a00f..300117f1a08f 100644
--- a/mm/balloon_compaction.c
+++ b/mm/balloon_compaction.c
@@ -61,6 +61,7 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
bool dequeued_page;
dequeued_page = false;
+ spin_lock_irqsave(&b_dev_info->pages_lock, flags);
list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
/*
* Block others from accessing the 'page' while we get around
@@ -75,15 +76,14 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
continue;
}
#endif
- spin_lock_irqsave(&b_dev_info->pages_lock, flags);
balloon_page_delete(page);
__count_vm_event(BALLOON_DEFLATE);
- spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
unlock_page(page);
dequeued_page = true;
break;
}
}
+ spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
if (!dequeued_page) {
/*
diff --git a/mm/compaction.c b/mm/compaction.c
index de3e1e71cd9f..585de54dbe8c 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1658,14 +1658,15 @@ static void __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
!compaction_deferred(zone, cc->order))
compact_zone(zone, cc);
- if (cc->order > 0) {
- if (zone_watermark_ok(zone, cc->order,
- low_wmark_pages(zone), 0, 0))
- compaction_defer_reset(zone, cc->order, false);
- }
-
VM_BUG_ON(!list_empty(&cc->freepages));
VM_BUG_ON(!list_empty(&cc->migratepages));
+
+ if (is_via_compact_memory(cc->order))
+ continue;
+
+ if (zone_watermark_ok(zone, cc->order,
+ low_wmark_pages(zone), 0, 0))
+ compaction_defer_reset(zone, cc->order, false);
}
}
@@ -1708,7 +1709,10 @@ static void compact_nodes(void)
/* The written value is actually unused, all memory is compacted */
int sysctl_compact_memory;
-/* This is the entry point for compacting all nodes via /proc/sys/vm */
+/*
+ * This is the entry point for compacting all nodes via
+ * /proc/sys/vm/compact_memory
+ */
int sysctl_compaction_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos)
{
diff --git a/mm/debug.c b/mm/debug.c
index 668aa35191ca..f05b2d5d6481 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -40,9 +40,6 @@ static const struct trace_print_flags pageflag_names[] = {
#ifdef CONFIG_MEMORY_FAILURE
{1UL << PG_hwpoison, "hwpoison" },
#endif
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- {1UL << PG_compound_lock, "compound_lock" },
-#endif
#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
{1UL << PG_young, "young" },
{1UL << PG_idle, "idle" },
@@ -82,9 +79,12 @@ static void dump_flags(unsigned long flags,
void dump_page_badflags(struct page *page, const char *reason,
unsigned long badflags)
{
- pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
+ pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
page, atomic_read(&page->_count), page_mapcount(page),
page->mapping, page->index);
+ if (PageCompound(page))
+ pr_cont(" compound_mapcount: %d", compound_mapcount(page));
+ pr_cont("\n");
BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
dump_flags(page->flags, pageflag_names, ARRAY_SIZE(pageflag_names));
if (reason)
@@ -175,7 +175,7 @@ void dump_mm(const struct mm_struct *mm)
"mmap_base %lu mmap_legacy_base %lu highest_vm_end %lu\n"
"pgd %p mm_users %d mm_count %d nr_ptes %lu nr_pmds %lu map_count %d\n"
"hiwater_rss %lx hiwater_vm %lx total_vm %lx locked_vm %lx\n"
- "pinned_vm %lx shared_vm %lx exec_vm %lx stack_vm %lx\n"
+ "pinned_vm %lx data_vm %lx exec_vm %lx stack_vm %lx\n"
"start_code %lx end_code %lx start_data %lx end_data %lx\n"
"start_brk %lx brk %lx start_stack %lx\n"
"arg_start %lx arg_end %lx env_start %lx env_end %lx\n"
@@ -209,7 +209,7 @@ void dump_mm(const struct mm_struct *mm)
mm_nr_pmds((struct mm_struct *)mm),
mm->map_count,
mm->hiwater_rss, mm->hiwater_vm, mm->total_vm, mm->locked_vm,
- mm->pinned_vm, mm->shared_vm, mm->exec_vm, mm->stack_vm,
+ mm->pinned_vm, mm->data_vm, mm->exec_vm, mm->stack_vm,
mm->start_code, mm->end_code, mm->start_data, mm->end_data,
mm->start_brk, mm->brk, mm->start_stack,
mm->arg_start, mm->arg_end, mm->env_start, mm->env_end,
diff --git a/mm/filemap.c b/mm/filemap.c
index 1bb007624b53..847ee43c2806 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -204,7 +204,7 @@ void __delete_from_page_cache(struct page *page, void *shadow,
__dec_zone_page_state(page, NR_FILE_PAGES);
if (PageSwapBacked(page))
__dec_zone_page_state(page, NR_SHMEM);
- BUG_ON(page_mapped(page));
+ VM_BUG_ON_PAGE(page_mapped(page), page);
/*
* At this point page must be either written or cleaned by truncate.
@@ -618,7 +618,7 @@ static int __add_to_page_cache_locked(struct page *page,
if (!huge) {
error = mem_cgroup_try_charge(page, current->mm,
- gfp_mask, &memcg);
+ gfp_mask, &memcg, false);
if (error)
return error;
}
@@ -626,7 +626,7 @@ static int __add_to_page_cache_locked(struct page *page,
error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
if (error) {
if (!huge)
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
return error;
}
@@ -645,7 +645,7 @@ static int __add_to_page_cache_locked(struct page *page,
__inc_zone_page_state(page, NR_FILE_PAGES);
spin_unlock_irq(&mapping->tree_lock);
if (!huge)
- mem_cgroup_commit_charge(page, memcg, false);
+ mem_cgroup_commit_charge(page, memcg, false, false);
trace_mm_filemap_add_to_page_cache(page);
return 0;
err_insert:
@@ -653,7 +653,7 @@ err_insert:
/* Leave page->index set: truncation relies upon it */
spin_unlock_irq(&mapping->tree_lock);
if (!huge)
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
page_cache_release(page);
return error;
}
@@ -682,11 +682,11 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
void *shadow = NULL;
int ret;
- __set_page_locked(page);
+ __SetPageLocked(page);
ret = __add_to_page_cache_locked(page, mapping, offset,
gfp_mask, &shadow);
if (unlikely(ret))
- __clear_page_locked(page);
+ __ClearPageLocked(page);
else {
/*
* The page might have been evicted from cache only
@@ -809,6 +809,7 @@ EXPORT_SYMBOL_GPL(add_page_wait_queue);
*/
void unlock_page(struct page *page)
{
+ page = compound_head(page);
VM_BUG_ON_PAGE(!PageLocked(page), page);
clear_bit_unlock(PG_locked, &page->flags);
smp_mb__after_atomic();
@@ -873,18 +874,20 @@ EXPORT_SYMBOL_GPL(page_endio);
*/
void __lock_page(struct page *page)
{
- DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
+ struct page *page_head = compound_head(page);
+ DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked);
- __wait_on_bit_lock(page_waitqueue(page), &wait, bit_wait_io,
+ __wait_on_bit_lock(page_waitqueue(page_head), &wait, bit_wait_io,
TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(__lock_page);
int __lock_page_killable(struct page *page)
{
- DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
+ struct page *page_head = compound_head(page);
+ DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked);
- return __wait_on_bit_lock(page_waitqueue(page), &wait,
+ return __wait_on_bit_lock(page_waitqueue(page_head), &wait,
bit_wait_io, TASK_KILLABLE);
}
EXPORT_SYMBOL_GPL(__lock_page_killable);
@@ -1812,19 +1815,18 @@ EXPORT_SYMBOL(generic_file_read_iter);
* This adds the requested page to the page cache if it isn't already there,
* and schedules an I/O to read in its contents from disk.
*/
-static int page_cache_read(struct file *file, pgoff_t offset)
+static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask)
{
struct address_space *mapping = file->f_mapping;
struct page *page;
int ret;
do {
- page = page_cache_alloc_cold(mapping);
+ page = __page_cache_alloc(gfp_mask|__GFP_COLD);
if (!page)
return -ENOMEM;
- ret = add_to_page_cache_lru(page, mapping, offset,
- mapping_gfp_constraint(mapping, GFP_KERNEL));
+ ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL);
if (ret == 0)
ret = mapping->a_ops->readpage(file, page);
else if (ret == -EEXIST)
@@ -2005,7 +2007,7 @@ no_cached_page:
* We're only likely to ever get here if MADV_RANDOM is in
* effect.
*/
- error = page_cache_read(file, offset);
+ error = page_cache_read(file, offset, vmf->gfp_mask);
/*
* The page we want has now been added to the page cache.
diff --git a/mm/gup.c b/mm/gup.c
index deafa2c91b36..b64a36175884 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -4,6 +4,7 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
+#include <linux/memremap.h>
#include <linux/pagemap.h>
#include <linux/rmap.h>
#include <linux/swap.h>
@@ -62,6 +63,7 @@ static struct page *follow_page_pte(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd, unsigned int flags)
{
struct mm_struct *mm = vma->vm_mm;
+ struct dev_pagemap *pgmap = NULL;
struct page *page;
spinlock_t *ptl;
pte_t *ptep, pte;
@@ -98,7 +100,17 @@ retry:
}
page = vm_normal_page(vma, address, pte);
- if (unlikely(!page)) {
+ if (!page && pte_devmap(pte) && (flags & FOLL_GET)) {
+ /*
+ * Only return device mapping pages in the FOLL_GET case since
+ * they are only valid while holding the pgmap reference.
+ */
+ pgmap = get_dev_pagemap(pte_pfn(pte), NULL);
+ if (pgmap)
+ page = pte_page(pte);
+ else
+ goto no_page;
+ } else if (unlikely(!page)) {
if (flags & FOLL_DUMP) {
/* Avoid special (like zero) pages in core dumps */
page = ERR_PTR(-EFAULT);
@@ -116,8 +128,28 @@ retry:
}
}
- if (flags & FOLL_GET)
- get_page_foll(page);
+ if (flags & FOLL_SPLIT && PageTransCompound(page)) {
+ int ret;
+ get_page(page);
+ pte_unmap_unlock(ptep, ptl);
+ lock_page(page);
+ ret = split_huge_page(page);
+ unlock_page(page);
+ put_page(page);
+ if (ret)
+ return ERR_PTR(ret);
+ goto retry;
+ }
+
+ if (flags & FOLL_GET) {
+ get_page(page);
+
+ /* drop the pgmap reference now that we hold the page */
+ if (pgmap) {
+ put_dev_pagemap(pgmap);
+ pgmap = NULL;
+ }
+ }
if (flags & FOLL_TOUCH) {
if ((flags & FOLL_WRITE) &&
!pte_dirty(pte) && !PageDirty(page))
@@ -130,6 +162,10 @@ retry:
mark_page_accessed(page);
}
if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) {
+ /* Do not mlock pte-mapped THP */
+ if (PageTransCompound(page))
+ goto out;
+
/*
* The preliminary mapping check is mainly to avoid the
* pointless overhead of lock_page on the ZERO_PAGE
@@ -220,27 +256,45 @@ struct page *follow_page_mask(struct vm_area_struct *vma,
}
if ((flags & FOLL_NUMA) && pmd_protnone(*pmd))
return no_page_table(vma, flags);
- if (pmd_trans_huge(*pmd)) {
- if (flags & FOLL_SPLIT) {
- split_huge_page_pmd(vma, address, pmd);
- return follow_page_pte(vma, address, pmd, flags);
- }
+ if (pmd_devmap(*pmd)) {
ptl = pmd_lock(mm, pmd);
- if (likely(pmd_trans_huge(*pmd))) {
- if (unlikely(pmd_trans_splitting(*pmd))) {
- spin_unlock(ptl);
- wait_split_huge_page(vma->anon_vma, pmd);
- } else {
- page = follow_trans_huge_pmd(vma, address,
- pmd, flags);
- spin_unlock(ptl);
- *page_mask = HPAGE_PMD_NR - 1;
- return page;
- }
- } else
+ page = follow_devmap_pmd(vma, address, pmd, flags);
+ spin_unlock(ptl);
+ if (page)
+ return page;
+ }
+ if (likely(!pmd_trans_huge(*pmd)))
+ return follow_page_pte(vma, address, pmd, flags);
+
+ ptl = pmd_lock(mm, pmd);
+ if (unlikely(!pmd_trans_huge(*pmd))) {
+ spin_unlock(ptl);
+ return follow_page_pte(vma, address, pmd, flags);
+ }
+ if (flags & FOLL_SPLIT) {
+ int ret;
+ page = pmd_page(*pmd);
+ if (is_huge_zero_page(page)) {
+ spin_unlock(ptl);
+ ret = 0;
+ split_huge_pmd(vma, pmd, address);
+ } else {
+ get_page(page);
spin_unlock(ptl);
+ lock_page(page);
+ ret = split_huge_page(page);
+ unlock_page(page);
+ put_page(page);
+ }
+
+ return ret ? ERR_PTR(ret) :
+ follow_page_pte(vma, address, pmd, flags);
}
- return follow_page_pte(vma, address, pmd, flags);
+
+ page = follow_trans_huge_pmd(vma, address, pmd, flags);
+ spin_unlock(ptl);
+ *page_mask = HPAGE_PMD_NR - 1;
+ return page;
}
static int get_gate_page(struct mm_struct *mm, unsigned long address,
@@ -564,6 +618,8 @@ EXPORT_SYMBOL(__get_user_pages);
* @mm: mm_struct of target mm
* @address: user address
* @fault_flags:flags to pass down to handle_mm_fault()
+ * @unlocked: did we unlock the mmap_sem while retrying, maybe NULL if caller
+ * does not allow retry
*
* This is meant to be called in the specific scenario where for locking reasons
* we try to access user memory in atomic context (within a pagefault_disable()
@@ -575,22 +631,28 @@ EXPORT_SYMBOL(__get_user_pages);
* The main difference with get_user_pages() is that this function will
* unconditionally call handle_mm_fault() which will in turn perform all the
* necessary SW fixup of the dirty and young bits in the PTE, while
- * handle_mm_fault() only guarantees to update these in the struct page.
+ * get_user_pages() only guarantees to update these in the struct page.
*
* This is important for some architectures where those bits also gate the
* access permission to the page because they are maintained in software. On
* such architectures, gup() will not be enough to make a subsequent access
* succeed.
*
- * This has the same semantics wrt the @mm->mmap_sem as does filemap_fault().
+ * This function will not return with an unlocked mmap_sem. So it has not the
+ * same semantics wrt the @mm->mmap_sem as does filemap_fault().
*/
int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long address, unsigned int fault_flags)
+ unsigned long address, unsigned int fault_flags,
+ bool *unlocked)
{
struct vm_area_struct *vma;
vm_flags_t vm_flags;
- int ret;
+ int ret, major = 0;
+ if (unlocked)
+ fault_flags |= FAULT_FLAG_ALLOW_RETRY;
+
+retry:
vma = find_extend_vma(mm, address);
if (!vma || address < vma->vm_start)
return -EFAULT;
@@ -600,6 +662,7 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
return -EFAULT;
ret = handle_mm_fault(mm, vma, address, fault_flags);
+ major |= ret & VM_FAULT_MAJOR;
if (ret & VM_FAULT_ERROR) {
if (ret & VM_FAULT_OOM)
return -ENOMEM;
@@ -609,8 +672,19 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
return -EFAULT;
BUG();
}
+
+ if (ret & VM_FAULT_RETRY) {
+ down_read(&mm->mmap_sem);
+ if (!(fault_flags & FAULT_FLAG_TRIED)) {
+ *unlocked = true;
+ fault_flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ fault_flags |= FAULT_FLAG_TRIED;
+ goto retry;
+ }
+ }
+
if (tsk) {
- if (ret & VM_FAULT_MAJOR)
+ if (major)
tsk->maj_flt++;
else
tsk->min_flt++;
@@ -896,7 +970,6 @@ long populate_vma_page_range(struct vm_area_struct *vma,
gup_flags = FOLL_TOUCH | FOLL_POPULATE | FOLL_MLOCK;
if (vma->vm_flags & VM_LOCKONFAULT)
gup_flags &= ~FOLL_POPULATE;
-
/*
* We want to touch writable mappings with a write fault in order
* to break COW, except for shared mappings because these don't COW
@@ -1036,9 +1109,6 @@ struct page *get_dump_page(unsigned long addr)
* *) HAVE_RCU_TABLE_FREE is enabled, and tlb_remove_table is used to free
* pages containing page tables.
*
- * *) THP splits will broadcast an IPI, this can be achieved by overriding
- * pmdp_splitting_flush.
- *
* *) ptes can be read atomically by the architecture.
*
* *) access_ok is sufficient to validate userspace address ranges.
@@ -1066,7 +1136,7 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
* for an example see gup_get_pte in arch/x86/mm/gup.c
*/
pte_t pte = READ_ONCE(*ptep);
- struct page *page;
+ struct page *head, *page;
/*
* Similar to the PMD case below, NUMA hinting must take slow
@@ -1078,15 +1148,17 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
page = pte_page(pte);
+ head = compound_head(page);
- if (!page_cache_get_speculative(page))
+ if (!page_cache_get_speculative(head))
goto pte_unmap;
if (unlikely(pte_val(pte) != pte_val(*ptep))) {
- put_page(page);
+ put_page(head);
goto pte_unmap;
}
+ VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
(*nr)++;
@@ -1119,7 +1191,7 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
- struct page *head, *page, *tail;
+ struct page *head, *page;
int refs;
if (write && !pmd_write(orig))
@@ -1128,7 +1200,6 @@ static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
refs = 0;
head = pmd_page(orig);
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
- tail = page;
do {
VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
@@ -1149,24 +1220,13 @@ static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
return 0;
}
- /*
- * Any tail pages need their mapcount reference taken before we
- * return. (This allows the THP code to bump their ref count when
- * they are split into base pages).
- */
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
return 1;
}
static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
- struct page *head, *page, *tail;
+ struct page *head, *page;
int refs;
if (write && !pud_write(orig))
@@ -1175,7 +1235,6 @@ static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
refs = 0;
head = pud_page(orig);
page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
- tail = page;
do {
VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
@@ -1196,12 +1255,6 @@ static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
return 0;
}
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
return 1;
}
@@ -1210,7 +1263,7 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr,
struct page **pages, int *nr)
{
int refs;
- struct page *head, *page, *tail;
+ struct page *head, *page;
if (write && !pgd_write(orig))
return 0;
@@ -1218,7 +1271,6 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr,
refs = 0;
head = pgd_page(orig);
page = head + ((addr & ~PGDIR_MASK) >> PAGE_SHIFT);
- tail = page;
do {
VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
@@ -1239,12 +1291,6 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr,
return 0;
}
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
return 1;
}
@@ -1259,7 +1305,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmd_t pmd = READ_ONCE(*pmdp);
next = pmd_addr_end(addr, end);
- if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+ if (pmd_none(pmd))
return 0;
if (unlikely(pmd_trans_huge(pmd) || pmd_huge(pmd))) {
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 62fe06bb7d04..b1cf73bc3b12 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -16,12 +16,16 @@
#include <linux/swap.h>
#include <linux/shrinker.h>
#include <linux/mm_inline.h>
+#include <linux/swapops.h>
#include <linux/dax.h>
#include <linux/kthread.h>
#include <linux/khugepaged.h>
#include <linux/freezer.h>
+#include <linux/pfn_t.h>
#include <linux/mman.h>
+#include <linux/memremap.h>
#include <linux/pagemap.h>
+#include <linux/debugfs.h>
#include <linux/migrate.h>
#include <linux/hashtable.h>
#include <linux/userfaultfd_k.h>
@@ -31,6 +35,34 @@
#include <asm/pgalloc.h>
#include "internal.h"
+enum scan_result {
+ SCAN_FAIL,
+ SCAN_SUCCEED,
+ SCAN_PMD_NULL,
+ SCAN_EXCEED_NONE_PTE,
+ SCAN_PTE_NON_PRESENT,
+ SCAN_PAGE_RO,
+ SCAN_NO_REFERENCED_PAGE,
+ SCAN_PAGE_NULL,
+ SCAN_SCAN_ABORT,
+ SCAN_PAGE_COUNT,
+ SCAN_PAGE_LRU,
+ SCAN_PAGE_LOCK,
+ SCAN_PAGE_ANON,
+ SCAN_PAGE_COMPOUND,
+ SCAN_ANY_PROCESS,
+ SCAN_VMA_NULL,
+ SCAN_VMA_CHECK,
+ SCAN_ADDRESS_RANGE,
+ SCAN_SWAP_CACHE_PAGE,
+ SCAN_DEL_PAGE_LRU,
+ SCAN_ALLOC_HUGE_PAGE_FAIL,
+ SCAN_CGROUP_CHARGE_FAIL
+};
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/huge_memory.h>
+
/*
* By default transparent hugepage support is disabled in order that avoid
* to risk increase the memory footprint of applications without a guaranteed
@@ -106,6 +138,10 @@ static struct khugepaged_scan khugepaged_scan = {
.mm_head = LIST_HEAD_INIT(khugepaged_scan.mm_head),
};
+static DEFINE_SPINLOCK(split_queue_lock);
+static LIST_HEAD(split_queue);
+static unsigned long split_queue_len;
+static struct shrinker deferred_split_shrinker;
static void set_recommended_min_free_kbytes(void)
{
@@ -638,6 +674,9 @@ static int __init hugepage_init(void)
err = register_shrinker(&huge_zero_page_shrinker);
if (err)
goto err_hzp_shrinker;
+ err = register_shrinker(&deferred_split_shrinker);
+ if (err)
+ goto err_split_shrinker;
/*
* By default disable transparent hugepages on smaller systems,
@@ -655,6 +694,8 @@ static int __init hugepage_init(void)
return 0;
err_khugepaged:
+ unregister_shrinker(&deferred_split_shrinker);
+err_split_shrinker:
unregister_shrinker(&huge_zero_page_shrinker);
err_hzp_shrinker:
khugepaged_slab_exit();
@@ -711,6 +752,27 @@ static inline pmd_t mk_huge_pmd(struct page *page, pgprot_t prot)
return entry;
}
+static inline struct list_head *page_deferred_list(struct page *page)
+{
+ /*
+ * ->lru in the tail pages is occupied by compound_head.
+ * Let's use ->mapping + ->index in the second tail page as list_head.
+ */
+ return (struct list_head *)&page[2].mapping;
+}
+
+void prep_transhuge_page(struct page *page)
+{
+ /*
+ * we use page->mapping and page->indexlru in second tail page
+ * as list_head: assuming THP order >= 2
+ */
+ BUILD_BUG_ON(HPAGE_PMD_ORDER < 2);
+
+ INIT_LIST_HEAD(page_deferred_list(page));
+ set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR);
+}
+
static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd,
@@ -724,7 +786,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
VM_BUG_ON_PAGE(!PageCompound(page), page);
- if (mem_cgroup_try_charge(page, mm, gfp, &memcg)) {
+ if (mem_cgroup_try_charge(page, mm, gfp, &memcg, true)) {
put_page(page);
count_vm_event(THP_FAULT_FALLBACK);
return VM_FAULT_FALLBACK;
@@ -732,7 +794,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
pgtable = pte_alloc_one(mm, haddr);
if (unlikely(!pgtable)) {
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, true);
put_page(page);
return VM_FAULT_OOM;
}
@@ -748,7 +810,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
ptl = pmd_lock(mm, pmd);
if (unlikely(!pmd_none(*pmd))) {
spin_unlock(ptl);
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, true);
put_page(page);
pte_free(mm, pgtable);
} else {
@@ -759,7 +821,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
int ret;
spin_unlock(ptl);
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, true);
put_page(page);
pte_free(mm, pgtable);
ret = handle_userfault(vma, address, flags,
@@ -770,8 +832,8 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
entry = mk_huge_pmd(page, vma->vm_page_prot);
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
- page_add_new_anon_rmap(page, vma, haddr);
- mem_cgroup_commit_charge(page, memcg, false);
+ page_add_new_anon_rmap(page, vma, haddr, true);
+ mem_cgroup_commit_charge(page, memcg, false, true);
lru_cache_add_active_or_unevictable(page, vma);
pgtable_trans_huge_deposit(mm, pmd, pgtable);
set_pmd_at(mm, haddr, pmd, entry);
@@ -865,32 +927,33 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
count_vm_event(THP_FAULT_FALLBACK);
return VM_FAULT_FALLBACK;
}
+ prep_transhuge_page(page);
return __do_huge_pmd_anonymous_page(mm, vma, address, pmd, page, gfp,
flags);
}
static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
- pmd_t *pmd, unsigned long pfn, pgprot_t prot, bool write)
+ pmd_t *pmd, pfn_t pfn, pgprot_t prot, bool write)
{
struct mm_struct *mm = vma->vm_mm;
pmd_t entry;
spinlock_t *ptl;
ptl = pmd_lock(mm, pmd);
- if (pmd_none(*pmd)) {
- entry = pmd_mkhuge(pfn_pmd(pfn, prot));
- if (write) {
- entry = pmd_mkyoung(pmd_mkdirty(entry));
- entry = maybe_pmd_mkwrite(entry, vma);
- }
- set_pmd_at(mm, addr, pmd, entry);
- update_mmu_cache_pmd(vma, addr, pmd);
- }
+ entry = pmd_mkhuge(pfn_t_pmd(pfn, prot));
+ if (pfn_t_devmap(pfn))
+ entry = pmd_mkdevmap(entry);
+ if (write) {
+ entry = pmd_mkyoung(pmd_mkdirty(entry));
+ entry = maybe_pmd_mkwrite(entry, vma);
+ }
+ set_pmd_at(mm, addr, pmd, entry);
+ update_mmu_cache_pmd(vma, addr, pmd);
spin_unlock(ptl);
}
int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
- pmd_t *pmd, unsigned long pfn, bool write)
+ pmd_t *pmd, pfn_t pfn, bool write)
{
pgprot_t pgprot = vma->vm_page_prot;
/*
@@ -902,7 +965,7 @@ int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
BUG_ON((vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) ==
(VM_PFNMAP|VM_MIXEDMAP));
BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags));
- BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn));
+ BUG_ON(!pfn_t_devmap(pfn));
if (addr < vma->vm_start || addr >= vma->vm_end)
return VM_FAULT_SIGBUS;
@@ -912,6 +975,63 @@ int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
return VM_FAULT_NOPAGE;
}
+static void touch_pmd(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd)
+{
+ pmd_t _pmd;
+
+ /*
+ * We should set the dirty bit only for FOLL_WRITE but for now
+ * the dirty bit in the pmd is meaningless. And if the dirty
+ * bit will become meaningful and we'll only set it with
+ * FOLL_WRITE, an atomic set_bit will be required on the pmd to
+ * set the young bit, instead of the current set_pmd_at.
+ */
+ _pmd = pmd_mkyoung(pmd_mkdirty(*pmd));
+ if (pmdp_set_access_flags(vma, addr & HPAGE_PMD_MASK,
+ pmd, _pmd, 1))
+ update_mmu_cache_pmd(vma, addr, pmd);
+}
+
+struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd, int flags)
+{
+ unsigned long pfn = pmd_pfn(*pmd);
+ struct mm_struct *mm = vma->vm_mm;
+ struct dev_pagemap *pgmap;
+ struct page *page;
+
+ assert_spin_locked(pmd_lockptr(mm, pmd));
+
+ if (flags & FOLL_WRITE && !pmd_write(*pmd))
+ return NULL;
+
+ if (pmd_present(*pmd) && pmd_devmap(*pmd))
+ /* pass */;
+ else
+ return NULL;
+
+ if (flags & FOLL_TOUCH)
+ touch_pmd(vma, addr, pmd);
+
+ /*
+ * device mapped pages can only be returned if the
+ * caller will manage the page reference count.
+ */
+ if (!(flags & FOLL_GET))
+ return ERR_PTR(-EEXIST);
+
+ pfn += (addr & ~PMD_MASK) >> PAGE_SHIFT;
+ pgmap = get_dev_pagemap(pfn, NULL);
+ if (!pgmap)
+ return ERR_PTR(-EFAULT);
+ page = pfn_to_page(pfn);
+ get_page(page);
+ put_dev_pagemap(pgmap);
+
+ return page;
+}
+
int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long addr,
struct vm_area_struct *vma)
@@ -933,7 +1053,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
ret = -EAGAIN;
pmd = *src_pmd;
- if (unlikely(!pmd_trans_huge(pmd))) {
+ if (unlikely(!pmd_trans_huge(pmd) && !pmd_devmap(pmd))) {
pte_free(dst_mm, pgtable);
goto out_unlock;
}
@@ -956,26 +1076,20 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
goto out_unlock;
}
- if (unlikely(pmd_trans_splitting(pmd))) {
- /* split huge page running from under us */
- spin_unlock(src_ptl);
- spin_unlock(dst_ptl);
- pte_free(dst_mm, pgtable);
-
- wait_split_huge_page(vma->anon_vma, src_pmd); /* src_vma */
- goto out;
+ if (pmd_trans_huge(pmd)) {
+ /* thp accounting separate from pmd_devmap accounting */
+ src_page = pmd_page(pmd);
+ VM_BUG_ON_PAGE(!PageHead(src_page), src_page);
+ get_page(src_page);
+ page_dup_rmap(src_page, true);
+ add_mm_counter(dst_mm, MM_ANONPAGES, HPAGE_PMD_NR);
+ atomic_long_inc(&dst_mm->nr_ptes);
+ pgtable_trans_huge_deposit(dst_mm, dst_pmd, pgtable);
}
- src_page = pmd_page(pmd);
- VM_BUG_ON_PAGE(!PageHead(src_page), src_page);
- get_page(src_page);
- page_dup_rmap(src_page);
- add_mm_counter(dst_mm, MM_ANONPAGES, HPAGE_PMD_NR);
pmdp_set_wrprotect(src_mm, addr, src_pmd);
pmd = pmd_mkold(pmd_wrprotect(pmd));
- pgtable_trans_huge_deposit(dst_mm, dst_pmd, pgtable);
set_pmd_at(dst_mm, addr, dst_pmd, pmd);
- atomic_long_inc(&dst_mm->nr_ptes);
ret = 0;
out_unlock:
@@ -1008,37 +1122,6 @@ unlock:
spin_unlock(ptl);
}
-/*
- * Save CONFIG_DEBUG_PAGEALLOC from faulting falsely on tail pages
- * during copy_user_huge_page()'s copy_page_rep(): in the case when
- * the source page gets split and a tail freed before copy completes.
- * Called under pmd_lock of checked pmd, so safe from splitting itself.
- */
-static void get_user_huge_page(struct page *page)
-{
- if (IS_ENABLED(CONFIG_DEBUG_PAGEALLOC)) {
- struct page *endpage = page + HPAGE_PMD_NR;
-
- atomic_add(HPAGE_PMD_NR, &page->_count);
- while (++page < endpage)
- get_huge_page_tail(page);
- } else {
- get_page(page);
- }
-}
-
-static void put_user_huge_page(struct page *page)
-{
- if (IS_ENABLED(CONFIG_DEBUG_PAGEALLOC)) {
- struct page *endpage = page + HPAGE_PMD_NR;
-
- while (page < endpage)
- put_page(page++);
- } else {
- put_page(page);
- }
-}
-
static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
struct vm_area_struct *vma,
unsigned long address,
@@ -1068,13 +1151,14 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
vma, address, page_to_nid(page));
if (unlikely(!pages[i] ||
mem_cgroup_try_charge(pages[i], mm, GFP_KERNEL,
- &memcg))) {
+ &memcg, false))) {
if (pages[i])
put_page(pages[i]);
while (--i >= 0) {
memcg = (void *)page_private(pages[i]);
set_page_private(pages[i], 0);
- mem_cgroup_cancel_charge(pages[i], memcg);
+ mem_cgroup_cancel_charge(pages[i], memcg,
+ false);
put_page(pages[i]);
}
kfree(pages);
@@ -1112,8 +1196,8 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
memcg = (void *)page_private(pages[i]);
set_page_private(pages[i], 0);
- page_add_new_anon_rmap(pages[i], vma, haddr);
- mem_cgroup_commit_charge(pages[i], memcg, false);
+ page_add_new_anon_rmap(pages[i], vma, haddr, false);
+ mem_cgroup_commit_charge(pages[i], memcg, false, false);
lru_cache_add_active_or_unevictable(pages[i], vma);
pte = pte_offset_map(&_pmd, haddr);
VM_BUG_ON(!pte_none(*pte));
@@ -1124,7 +1208,7 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
smp_wmb(); /* make pte visible before pmd */
pmd_populate(mm, pmd, pgtable);
- page_remove_rmap(page);
+ page_remove_rmap(page, true);
spin_unlock(ptl);
mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
@@ -1141,7 +1225,7 @@ out_free_pages:
for (i = 0; i < HPAGE_PMD_NR; i++) {
memcg = (void *)page_private(pages[i]);
set_page_private(pages[i], 0);
- mem_cgroup_cancel_charge(pages[i], memcg);
+ mem_cgroup_cancel_charge(pages[i], memcg, false);
put_page(pages[i]);
}
kfree(pages);
@@ -1171,7 +1255,17 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
page = pmd_page(orig_pmd);
VM_BUG_ON_PAGE(!PageCompound(page) || !PageHead(page), page);
- if (page_mapcount(page) == 1) {
+ /*
+ * We can only reuse the page if nobody else maps the huge page or it's
+ * part. We can do it by checking page_mapcount() on each sub-page, but
+ * it's expensive.
+ * The cheaper way is to check page_count() to be equal 1: every
+ * mapcount takes page reference reference, so this way we can
+ * guarantee, that the PMD is the only mapping.
+ * This can give false negative if somebody pinned the page, but that's
+ * fine.
+ */
+ if (page_mapcount(page) == 1 && page_count(page) == 1) {
pmd_t entry;
entry = pmd_mkyoung(orig_pmd);
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
@@ -1180,7 +1274,7 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
ret |= VM_FAULT_WRITE;
goto out_unlock;
}
- get_user_huge_page(page);
+ get_page(page);
spin_unlock(ptl);
alloc:
if (transparent_hugepage_enabled(vma) &&
@@ -1190,30 +1284,33 @@ alloc:
} else
new_page = NULL;
- if (unlikely(!new_page)) {
+ if (likely(new_page)) {
+ prep_transhuge_page(new_page);
+ } else {
if (!page) {
- split_huge_page_pmd(vma, address, pmd);
+ split_huge_pmd(vma, pmd, address);
ret |= VM_FAULT_FALLBACK;
} else {
ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
pmd, orig_pmd, page, haddr);
if (ret & VM_FAULT_OOM) {
- split_huge_page(page);
+ split_huge_pmd(vma, pmd, address);
ret |= VM_FAULT_FALLBACK;
}
- put_user_huge_page(page);
+ put_page(page);
}
count_vm_event(THP_FAULT_FALLBACK);
goto out;
}
- if (unlikely(mem_cgroup_try_charge(new_page, mm, huge_gfp, &memcg))) {
+ if (unlikely(mem_cgroup_try_charge(new_page, mm, huge_gfp, &memcg,
+ true))) {
put_page(new_page);
if (page) {
- split_huge_page(page);
- put_user_huge_page(page);
+ split_huge_pmd(vma, pmd, address);
+ put_page(page);
} else
- split_huge_page_pmd(vma, address, pmd);
+ split_huge_pmd(vma, pmd, address);
ret |= VM_FAULT_FALLBACK;
count_vm_event(THP_FAULT_FALLBACK);
goto out;
@@ -1233,10 +1330,10 @@ alloc:
spin_lock(ptl);
if (page)
- put_user_huge_page(page);
+ put_page(page);
if (unlikely(!pmd_same(*pmd, orig_pmd))) {
spin_unlock(ptl);
- mem_cgroup_cancel_charge(new_page, memcg);
+ mem_cgroup_cancel_charge(new_page, memcg, true);
put_page(new_page);
goto out_mn;
} else {
@@ -1244,8 +1341,8 @@ alloc:
entry = mk_huge_pmd(new_page, vma->vm_page_prot);
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
pmdp_huge_clear_flush_notify(vma, haddr, pmd);
- page_add_new_anon_rmap(new_page, vma, haddr);
- mem_cgroup_commit_charge(new_page, memcg, false);
+ page_add_new_anon_rmap(new_page, vma, haddr, true);
+ mem_cgroup_commit_charge(new_page, memcg, false, true);
lru_cache_add_active_or_unevictable(new_page, vma);
set_pmd_at(mm, haddr, pmd, entry);
update_mmu_cache_pmd(vma, address, pmd);
@@ -1254,7 +1351,7 @@ alloc:
put_huge_zero_page();
} else {
VM_BUG_ON_PAGE(!PageHead(page), page);
- page_remove_rmap(page);
+ page_remove_rmap(page, true);
put_page(page);
}
ret |= VM_FAULT_WRITE;
@@ -1292,23 +1389,23 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
page = pmd_page(*pmd);
VM_BUG_ON_PAGE(!PageHead(page), page);
- if (flags & FOLL_TOUCH) {
- pmd_t _pmd;
+ if (flags & FOLL_TOUCH)
+ touch_pmd(vma, addr, pmd);
+ if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) {
/*
- * We should set the dirty bit only for FOLL_WRITE but
- * for now the dirty bit in the pmd is meaningless.
- * And if the dirty bit will become meaningful and
- * we'll only set it with FOLL_WRITE, an atomic
- * set_bit will be required on the pmd to set the
- * young bit, instead of the current set_pmd_at.
+ * We don't mlock() pte-mapped THPs. This way we can avoid
+ * leaking mlocked pages into non-VM_LOCKED VMAs.
+ *
+ * In most cases the pmd is the only mapping of the page as we
+ * break COW for the mlock() -- see gup_flags |= FOLL_WRITE for
+ * writable private mappings in populate_vma_page_range().
+ *
+ * The only scenario when we have the page shared here is if we
+ * mlocking read-only mapping shared over fork(). We skip
+ * mlocking such pages.
*/
- _pmd = pmd_mkyoung(pmd_mkdirty(*pmd));
- if (pmdp_set_access_flags(vma, addr & HPAGE_PMD_MASK,
- pmd, _pmd, 1))
- update_mmu_cache_pmd(vma, addr, pmd);
- }
- if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) {
- if (page->mapping && trylock_page(page)) {
+ if (compound_mapcount(page) == 1 && !PageDoubleMap(page) &&
+ page->mapping && trylock_page(page)) {
lru_add_drain();
if (page->mapping)
mlock_vma_page(page);
@@ -1318,7 +1415,7 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
page += (addr & ~HPAGE_PMD_MASK) >> PAGE_SHIFT;
VM_BUG_ON_PAGE(!PageCompound(page), page);
if (flags & FOLL_GET)
- get_page_foll(page);
+ get_page(page);
out:
return page;
@@ -1453,13 +1550,84 @@ out:
return 0;
}
+int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ pmd_t *pmd, unsigned long addr, unsigned long next)
+
+{
+ spinlock_t *ptl;
+ pmd_t orig_pmd;
+ struct page *page;
+ struct mm_struct *mm = tlb->mm;
+ int ret = 0;
+
+ if (!pmd_trans_huge_lock(pmd, vma, &ptl))
+ goto out_unlocked;
+
+ orig_pmd = *pmd;
+ if (is_huge_zero_pmd(orig_pmd)) {
+ ret = 1;
+ goto out;
+ }
+
+ page = pmd_page(orig_pmd);
+ /*
+ * If other processes are mapping this page, we couldn't discard
+ * the page unless they all do MADV_FREE so let's skip the page.
+ */
+ if (page_mapcount(page) != 1)
+ goto out;
+
+ if (!trylock_page(page))
+ goto out;
+
+ /*
+ * If user want to discard part-pages of THP, split it so MADV_FREE
+ * will deactivate only them.
+ */
+ if (next - addr != HPAGE_PMD_SIZE) {
+ get_page(page);
+ spin_unlock(ptl);
+ if (split_huge_page(page)) {
+ put_page(page);
+ unlock_page(page);
+ goto out_unlocked;
+ }
+ put_page(page);
+ unlock_page(page);
+ ret = 1;
+ goto out_unlocked;
+ }
+
+ if (PageDirty(page))
+ ClearPageDirty(page);
+ unlock_page(page);
+
+ if (PageActive(page))
+ deactivate_page(page);
+
+ if (pmd_young(orig_pmd) || pmd_dirty(orig_pmd)) {
+ orig_pmd = pmdp_huge_get_and_clear_full(tlb->mm, addr, pmd,
+ tlb->fullmm);
+ orig_pmd = pmd_mkold(orig_pmd);
+ orig_pmd = pmd_mkclean(orig_pmd);
+
+ set_pmd_at(mm, addr, pmd, orig_pmd);
+ tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
+ }
+ ret = 1;
+out:
+ spin_unlock(ptl);
+out_unlocked:
+ return ret;
+}
+
int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
pmd_t *pmd, unsigned long addr)
{
pmd_t orig_pmd;
spinlock_t *ptl;
- if (__pmd_trans_huge_lock(pmd, vma, &ptl) != 1)
+ if (!__pmd_trans_huge_lock(pmd, vma, &ptl))
return 0;
/*
* For architectures like ppc64 we look at deposited pgtable
@@ -1481,7 +1649,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
put_huge_zero_page();
} else {
struct page *page = pmd_page(orig_pmd);
- page_remove_rmap(page);
+ page_remove_rmap(page, true);
VM_BUG_ON_PAGE(page_mapcount(page) < 0, page);
add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
VM_BUG_ON_PAGE(!PageHead(page), page);
@@ -1493,13 +1661,12 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
return 1;
}
-int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
+bool move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
unsigned long old_addr,
unsigned long new_addr, unsigned long old_end,
pmd_t *old_pmd, pmd_t *new_pmd)
{
spinlock_t *old_ptl, *new_ptl;
- int ret = 0;
pmd_t pmd;
struct mm_struct *mm = vma->vm_mm;
@@ -1508,7 +1675,7 @@ int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
(new_addr & ~HPAGE_PMD_MASK) ||
old_end - old_addr < HPAGE_PMD_SIZE ||
(new_vma->vm_flags & VM_NOHUGEPAGE))
- goto out;
+ return false;
/*
* The destination pmd shouldn't be established, free_pgtables()
@@ -1516,15 +1683,14 @@ int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
*/
if (WARN_ON(!pmd_none(*new_pmd))) {
VM_BUG_ON(pmd_trans_huge(*new_pmd));
- goto out;
+ return false;
}
/*
* We don't have to worry about the ordering of src and dst
* ptlocks because exclusive mmap_sem prevents deadlock.
*/
- ret = __pmd_trans_huge_lock(old_pmd, vma, &old_ptl);
- if (ret == 1) {
+ if (__pmd_trans_huge_lock(old_pmd, vma, &old_ptl)) {
new_ptl = pmd_lockptr(mm, new_pmd);
if (new_ptl != old_ptl)
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
@@ -1540,9 +1706,9 @@ int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
if (new_ptl != old_ptl)
spin_unlock(new_ptl);
spin_unlock(old_ptl);
+ return true;
}
-out:
- return ret;
+ return false;
}
/*
@@ -1558,7 +1724,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
spinlock_t *ptl;
int ret = 0;
- if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (__pmd_trans_huge_lock(pmd, vma, &ptl)) {
pmd_t entry;
bool preserve_write = prot_numa && pmd_write(*pmd);
ret = 1;
@@ -1589,405 +1755,19 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
}
/*
- * Returns 1 if a given pmd maps a stable (not under splitting) thp.
- * Returns -1 if it maps a thp under splitting. Returns 0 otherwise.
+ * Returns true if a given pmd maps a thp, false otherwise.
*
- * Note that if it returns 1, this routine returns without unlocking page
- * table locks. So callers must unlock them.
+ * Note that if it returns true, this routine returns without unlocking page
+ * table lock. So callers must unlock it.
*/
-int __pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
+bool __pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma,
spinlock_t **ptl)
{
*ptl = pmd_lock(vma->vm_mm, pmd);
- if (likely(pmd_trans_huge(*pmd))) {
- if (unlikely(pmd_trans_splitting(*pmd))) {
- spin_unlock(*ptl);
- wait_split_huge_page(vma->anon_vma, pmd);
- return -1;
- } else {
- /* Thp mapped by 'pmd' is stable, so we can
- * handle it as it is. */
- return 1;
- }
- }
+ if (likely(pmd_trans_huge(*pmd) || pmd_devmap(*pmd)))
+ return true;
spin_unlock(*ptl);
- return 0;
-}
-
-/*
- * This function returns whether a given @page is mapped onto the @address
- * in the virtual space of @mm.
- *
- * When it's true, this function returns *pmd with holding the page table lock
- * and passing it back to the caller via @ptl.
- * If it's false, returns NULL without holding the page table lock.
- */
-pmd_t *page_check_address_pmd(struct page *page,
- struct mm_struct *mm,
- unsigned long address,
- enum page_check_address_pmd_flag flag,
- spinlock_t **ptl)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
-
- if (address & ~HPAGE_PMD_MASK)
- return NULL;
-
- pgd = pgd_offset(mm, address);
- if (!pgd_present(*pgd))
- return NULL;
- pud = pud_offset(pgd, address);
- if (!pud_present(*pud))
- return NULL;
- pmd = pmd_offset(pud, address);
-
- *ptl = pmd_lock(mm, pmd);
- if (!pmd_present(*pmd))
- goto unlock;
- if (pmd_page(*pmd) != page)
- goto unlock;
- /*
- * split_vma() may create temporary aliased mappings. There is
- * no risk as long as all huge pmd are found and have their
- * splitting bit set before __split_huge_page_refcount
- * runs. Finding the same huge pmd more than once during the
- * same rmap walk is not a problem.
- */
- if (flag == PAGE_CHECK_ADDRESS_PMD_NOTSPLITTING_FLAG &&
- pmd_trans_splitting(*pmd))
- goto unlock;
- if (pmd_trans_huge(*pmd)) {
- VM_BUG_ON(flag == PAGE_CHECK_ADDRESS_PMD_SPLITTING_FLAG &&
- !pmd_trans_splitting(*pmd));
- return pmd;
- }
-unlock:
- spin_unlock(*ptl);
- return NULL;
-}
-
-static int __split_huge_page_splitting(struct page *page,
- struct vm_area_struct *vma,
- unsigned long address)
-{
- struct mm_struct *mm = vma->vm_mm;
- spinlock_t *ptl;
- pmd_t *pmd;
- int ret = 0;
- /* For mmu_notifiers */
- const unsigned long mmun_start = address;
- const unsigned long mmun_end = address + HPAGE_PMD_SIZE;
-
- mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
- pmd = page_check_address_pmd(page, mm, address,
- PAGE_CHECK_ADDRESS_PMD_NOTSPLITTING_FLAG, &ptl);
- if (pmd) {
- /*
- * We can't temporarily set the pmd to null in order
- * to split it, the pmd must remain marked huge at all
- * times or the VM won't take the pmd_trans_huge paths
- * and it won't wait on the anon_vma->root->rwsem to
- * serialize against split_huge_page*.
- */
- pmdp_splitting_flush(vma, address, pmd);
-
- ret = 1;
- spin_unlock(ptl);
- }
- mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
-
- return ret;
-}
-
-static void __split_huge_page_refcount(struct page *page,
- struct list_head *list)
-{
- int i;
- struct zone *zone = page_zone(page);
- struct lruvec *lruvec;
- int tail_count = 0;
-
- /* prevent PageLRU to go away from under us, and freeze lru stats */
- spin_lock_irq(&zone->lru_lock);
- lruvec = mem_cgroup_page_lruvec(page, zone);
-
- compound_lock(page);
- /* complete memcg works before add pages to LRU */
- mem_cgroup_split_huge_fixup(page);
-
- for (i = HPAGE_PMD_NR - 1; i >= 1; i--) {
- struct page *page_tail = page + i;
-
- /* tail_page->_mapcount cannot change */
- BUG_ON(page_mapcount(page_tail) < 0);
- tail_count += page_mapcount(page_tail);
- /* check for overflow */
- BUG_ON(tail_count < 0);
- BUG_ON(atomic_read(&page_tail->_count) != 0);
- /*
- * tail_page->_count is zero and not changing from
- * under us. But get_page_unless_zero() may be running
- * from under us on the tail_page. If we used
- * atomic_set() below instead of atomic_add(), we
- * would then run atomic_set() concurrently with
- * get_page_unless_zero(), and atomic_set() is
- * implemented in C not using locked ops. spin_unlock
- * on x86 sometime uses locked ops because of PPro
- * errata 66, 92, so unless somebody can guarantee
- * atomic_set() here would be safe on all archs (and
- * not only on x86), it's safer to use atomic_add().
- */
- atomic_add(page_mapcount(page) + page_mapcount(page_tail) + 1,
- &page_tail->_count);
-
- /* after clearing PageTail the gup refcount can be released */
- smp_mb__after_atomic();
-
- page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
- page_tail->flags |= (page->flags &
- ((1L << PG_referenced) |
- (1L << PG_swapbacked) |
- (1L << PG_mlocked) |
- (1L << PG_uptodate) |
- (1L << PG_active) |
- (1L << PG_unevictable)));
- page_tail->flags |= (1L << PG_dirty);
-
- clear_compound_head(page_tail);
-
- if (page_is_young(page))
- set_page_young(page_tail);
- if (page_is_idle(page))
- set_page_idle(page_tail);
-
- /*
- * __split_huge_page_splitting() already set the
- * splitting bit in all pmd that could map this
- * hugepage, that will ensure no CPU can alter the
- * mapcount on the head page. The mapcount is only
- * accounted in the head page and it has to be
- * transferred to all tail pages in the below code. So
- * for this code to be safe, the split the mapcount
- * can't change. But that doesn't mean userland can't
- * keep changing and reading the page contents while
- * we transfer the mapcount, so the pmd splitting
- * status is achieved setting a reserved bit in the
- * pmd, not by clearing the present bit.
- */
- page_tail->_mapcount = page->_mapcount;
-
- BUG_ON(page_tail->mapping);
- page_tail->mapping = page->mapping;
-
- page_tail->index = page->index + i;
- page_cpupid_xchg_last(page_tail, page_cpupid_last(page));
-
- BUG_ON(!PageAnon(page_tail));
- BUG_ON(!PageUptodate(page_tail));
- BUG_ON(!PageDirty(page_tail));
- BUG_ON(!PageSwapBacked(page_tail));
-
- lru_add_page_tail(page, page_tail, lruvec, list);
- }
- atomic_sub(tail_count, &page->_count);
- BUG_ON(atomic_read(&page->_count) <= 0);
-
- __mod_zone_page_state(zone, NR_ANON_TRANSPARENT_HUGEPAGES, -1);
-
- ClearPageCompound(page);
- compound_unlock(page);
- spin_unlock_irq(&zone->lru_lock);
-
- for (i = 1; i < HPAGE_PMD_NR; i++) {
- struct page *page_tail = page + i;
- BUG_ON(page_count(page_tail) <= 0);
- /*
- * Tail pages may be freed if there wasn't any mapping
- * like if add_to_swap() is running on a lru page that
- * had its mapping zapped. And freeing these pages
- * requires taking the lru_lock so we do the put_page
- * of the tail pages after the split is complete.
- */
- put_page(page_tail);
- }
-
- /*
- * Only the head page (now become a regular page) is required
- * to be pinned by the caller.
- */
- BUG_ON(page_count(page) <= 0);
-}
-
-static int __split_huge_page_map(struct page *page,
- struct vm_area_struct *vma,
- unsigned long address)
-{
- struct mm_struct *mm = vma->vm_mm;
- spinlock_t *ptl;
- pmd_t *pmd, _pmd;
- int ret = 0, i;
- pgtable_t pgtable;
- unsigned long haddr;
-
- pmd = page_check_address_pmd(page, mm, address,
- PAGE_CHECK_ADDRESS_PMD_SPLITTING_FLAG, &ptl);
- if (pmd) {
- pgtable = pgtable_trans_huge_withdraw(mm, pmd);
- pmd_populate(mm, &_pmd, pgtable);
- if (pmd_write(*pmd))
- BUG_ON(page_mapcount(page) != 1);
-
- haddr = address;
- for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
- pte_t *pte, entry;
- BUG_ON(PageCompound(page+i));
- /*
- * Note that NUMA hinting access restrictions are not
- * transferred to avoid any possibility of altering
- * permissions across VMAs.
- */
- entry = mk_pte(page + i, vma->vm_page_prot);
- entry = maybe_mkwrite(pte_mkdirty(entry), vma);
- if (!pmd_write(*pmd))
- entry = pte_wrprotect(entry);
- if (!pmd_young(*pmd))
- entry = pte_mkold(entry);
- pte = pte_offset_map(&_pmd, haddr);
- BUG_ON(!pte_none(*pte));
- set_pte_at(mm, haddr, pte, entry);
- pte_unmap(pte);
- }
-
- smp_wmb(); /* make pte visible before pmd */
- /*
- * Up to this point the pmd is present and huge and
- * userland has the whole access to the hugepage
- * during the split (which happens in place). If we
- * overwrite the pmd with the not-huge version
- * pointing to the pte here (which of course we could
- * if all CPUs were bug free), userland could trigger
- * a small page size TLB miss on the small sized TLB
- * while the hugepage TLB entry is still established
- * in the huge TLB. Some CPU doesn't like that. See
- * http://support.amd.com/us/Processor_TechDocs/41322.pdf,
- * Erratum 383 on page 93. Intel should be safe but is
- * also warns that it's only safe if the permission
- * and cache attributes of the two entries loaded in
- * the two TLB is identical (which should be the case
- * here). But it is generally safer to never allow
- * small and huge TLB entries for the same virtual
- * address to be loaded simultaneously. So instead of
- * doing "pmd_populate(); flush_pmd_tlb_range();" we first
- * mark the current pmd notpresent (atomically because
- * here the pmd_trans_huge and pmd_trans_splitting
- * must remain set at all times on the pmd until the
- * split is complete for this pmd), then we flush the
- * SMP TLB and finally we write the non-huge version
- * of the pmd entry with pmd_populate.
- */
- pmdp_invalidate(vma, address, pmd);
- pmd_populate(mm, pmd, pgtable);
- ret = 1;
- spin_unlock(ptl);
- }
-
- return ret;
-}
-
-/* must be called with anon_vma->root->rwsem held */
-static void __split_huge_page(struct page *page,
- struct anon_vma *anon_vma,
- struct list_head *list)
-{
- int mapcount, mapcount2;
- pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
- struct anon_vma_chain *avc;
-
- BUG_ON(!PageHead(page));
- BUG_ON(PageTail(page));
-
- mapcount = 0;
- anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
- struct vm_area_struct *vma = avc->vma;
- unsigned long addr = vma_address(page, vma);
- BUG_ON(is_vma_temporary_stack(vma));
- mapcount += __split_huge_page_splitting(page, vma, addr);
- }
- /*
- * It is critical that new vmas are added to the tail of the
- * anon_vma list. This guarantes that if copy_huge_pmd() runs
- * and establishes a child pmd before
- * __split_huge_page_splitting() freezes the parent pmd (so if
- * we fail to prevent copy_huge_pmd() from running until the
- * whole __split_huge_page() is complete), we will still see
- * the newly established pmd of the child later during the
- * walk, to be able to set it as pmd_trans_splitting too.
- */
- if (mapcount != page_mapcount(page)) {
- pr_err("mapcount %d page_mapcount %d\n",
- mapcount, page_mapcount(page));
- BUG();
- }
-
- __split_huge_page_refcount(page, list);
-
- mapcount2 = 0;
- anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
- struct vm_area_struct *vma = avc->vma;
- unsigned long addr = vma_address(page, vma);
- BUG_ON(is_vma_temporary_stack(vma));
- mapcount2 += __split_huge_page_map(page, vma, addr);
- }
- if (mapcount != mapcount2) {
- pr_err("mapcount %d mapcount2 %d page_mapcount %d\n",
- mapcount, mapcount2, page_mapcount(page));
- BUG();
- }
-}
-
-/*
- * Split a hugepage into normal pages. This doesn't change the position of head
- * page. If @list is null, tail pages will be added to LRU list, otherwise, to
- * @list. Both head page and tail pages will inherit mapping, flags, and so on
- * from the hugepage.
- * Return 0 if the hugepage is split successfully otherwise return 1.
- */
-int split_huge_page_to_list(struct page *page, struct list_head *list)
-{
- struct anon_vma *anon_vma;
- int ret = 1;
-
- BUG_ON(is_huge_zero_page(page));
- BUG_ON(!PageAnon(page));
-
- /*
- * The caller does not necessarily hold an mmap_sem that would prevent
- * the anon_vma disappearing so we first we take a reference to it
- * and then lock the anon_vma for write. This is similar to
- * page_lock_anon_vma_read except the write lock is taken to serialise
- * against parallel split or collapse operations.
- */
- anon_vma = page_get_anon_vma(page);
- if (!anon_vma)
- goto out;
- anon_vma_lock_write(anon_vma);
-
- ret = 0;
- if (!PageCompound(page))
- goto out_unlock;
-
- BUG_ON(!PageSwapBacked(page));
- __split_huge_page(page, anon_vma, list);
- count_vm_event(THP_SPLIT);
-
- BUG_ON(PageCompound(page));
-out_unlock:
- anon_vma_unlock_write(anon_vma);
- put_anon_vma(anon_vma);
-out:
- return ret;
+ return false;
}
#define VM_NO_THP (VM_SPECIAL | VM_HUGETLB | VM_SHARED | VM_MAYSHARE)
@@ -2198,26 +1978,33 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
unsigned long address,
pte_t *pte)
{
- struct page *page;
+ struct page *page = NULL;
pte_t *_pte;
- int none_or_zero = 0;
+ int none_or_zero = 0, result = 0;
bool referenced = false, writable = false;
+
for (_pte = pte; _pte < pte+HPAGE_PMD_NR;
_pte++, address += PAGE_SIZE) {
pte_t pteval = *_pte;
if (pte_none(pteval) || (pte_present(pteval) &&
is_zero_pfn(pte_pfn(pteval)))) {
if (!userfaultfd_armed(vma) &&
- ++none_or_zero <= khugepaged_max_ptes_none)
+ ++none_or_zero <= khugepaged_max_ptes_none) {
continue;
- else
+ } else {
+ result = SCAN_EXCEED_NONE_PTE;
goto out;
+ }
}
- if (!pte_present(pteval))
+ if (!pte_present(pteval)) {
+ result = SCAN_PTE_NON_PRESENT;
goto out;
+ }
page = vm_normal_page(vma, address, pteval);
- if (unlikely(!page))
+ if (unlikely(!page)) {
+ result = SCAN_PAGE_NULL;
goto out;
+ }
VM_BUG_ON_PAGE(PageCompound(page), page);
VM_BUG_ON_PAGE(!PageAnon(page), page);
@@ -2229,8 +2016,10 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
* is needed to serialize against split_huge_page
* when invoked from the VM.
*/
- if (!trylock_page(page))
+ if (!trylock_page(page)) {
+ result = SCAN_PAGE_LOCK;
goto out;
+ }
/*
* cannot use mapcount: can't collapse if there's a gup pin.
@@ -2239,6 +2028,7 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
*/
if (page_count(page) != 1 + !!PageSwapCache(page)) {
unlock_page(page);
+ result = SCAN_PAGE_COUNT;
goto out;
}
if (pte_write(pteval)) {
@@ -2246,6 +2036,7 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
} else {
if (PageSwapCache(page) && !reuse_swap_page(page)) {
unlock_page(page);
+ result = SCAN_SWAP_CACHE_PAGE;
goto out;
}
/*
@@ -2260,6 +2051,7 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
*/
if (isolate_lru_page(page)) {
unlock_page(page);
+ result = SCAN_DEL_PAGE_LRU;
goto out;
}
/* 0 stands for page_is_file_cache(page) == false */
@@ -2273,10 +2065,21 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
mmu_notifier_test_young(vma->vm_mm, address))
referenced = true;
}
- if (likely(referenced && writable))
- return 1;
+ if (likely(writable)) {
+ if (likely(referenced)) {
+ result = SCAN_SUCCEED;
+ trace_mm_collapse_huge_page_isolate(page_to_pfn(page), none_or_zero,
+ referenced, writable, result);
+ return 1;
+ }
+ } else {
+ result = SCAN_PAGE_RO;
+ }
+
out:
release_pte_pages(pte, _pte);
+ trace_mm_collapse_huge_page_isolate(page_to_pfn(page), none_or_zero,
+ referenced, writable, result);
return 0;
}
@@ -2321,7 +2124,7 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page,
* superfluous.
*/
pte_clear(vma->vm_mm, address, _pte);
- page_remove_rmap(src_page);
+ page_remove_rmap(src_page, false);
spin_unlock(ptl);
free_page_and_swap_cache(src_page);
}
@@ -2431,6 +2234,7 @@ khugepaged_alloc_page(struct page **hpage, gfp_t gfp, struct mm_struct *mm,
return NULL;
}
+ prep_transhuge_page(*hpage);
count_vm_event(THP_COLLAPSE_ALLOC);
return *hpage;
}
@@ -2442,8 +2246,12 @@ static int khugepaged_find_target_node(void)
static inline struct page *alloc_hugepage(int defrag)
{
- return alloc_pages(alloc_hugepage_gfpmask(defrag, 0),
- HPAGE_PMD_ORDER);
+ struct page *page;
+
+ page = alloc_pages(alloc_hugepage_gfpmask(defrag, 0), HPAGE_PMD_ORDER);
+ if (page)
+ prep_transhuge_page(page);
+ return page;
}
static struct page *khugepaged_alloc_hugepage(bool *wait)
@@ -2493,7 +2301,6 @@ static bool hugepage_vma_check(struct vm_area_struct *vma)
if ((!(vma->vm_flags & VM_HUGEPAGE) && !khugepaged_always()) ||
(vma->vm_flags & VM_NOHUGEPAGE))
return false;
-
if (!vma->anon_vma || vma->vm_ops)
return false;
if (is_vma_temporary_stack(vma))
@@ -2513,7 +2320,7 @@ static void collapse_huge_page(struct mm_struct *mm,
pgtable_t pgtable;
struct page *new_page;
spinlock_t *pmd_ptl, *pte_ptl;
- int isolated;
+ int isolated = 0, result = 0;
unsigned long hstart, hend;
struct mem_cgroup *memcg;
unsigned long mmun_start; /* For mmu_notifiers */
@@ -2528,12 +2335,15 @@ static void collapse_huge_page(struct mm_struct *mm,
/* release the mmap_sem read lock. */
new_page = khugepaged_alloc_page(hpage, gfp, mm, address, node);
- if (!new_page)
- return;
+ if (!new_page) {
+ result = SCAN_ALLOC_HUGE_PAGE_FAIL;
+ goto out_nolock;
+ }
- if (unlikely(mem_cgroup_try_charge(new_page, mm,
- gfp, &memcg)))
- return;
+ if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
+ result = SCAN_CGROUP_CHARGE_FAIL;
+ goto out_nolock;
+ }
/*
* Prevent all access to pagetables with the exception of
@@ -2541,21 +2351,31 @@ static void collapse_huge_page(struct mm_struct *mm,
* handled by the anon_vma lock + PG_lock.
*/
down_write(&mm->mmap_sem);
- if (unlikely(khugepaged_test_exit(mm)))
+ if (unlikely(khugepaged_test_exit(mm))) {
+ result = SCAN_ANY_PROCESS;
goto out;
+ }
vma = find_vma(mm, address);
- if (!vma)
+ if (!vma) {
+ result = SCAN_VMA_NULL;
goto out;
+ }
hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
hend = vma->vm_end & HPAGE_PMD_MASK;
- if (address < hstart || address + HPAGE_PMD_SIZE > hend)
+ if (address < hstart || address + HPAGE_PMD_SIZE > hend) {
+ result = SCAN_ADDRESS_RANGE;
goto out;
- if (!hugepage_vma_check(vma))
+ }
+ if (!hugepage_vma_check(vma)) {
+ result = SCAN_VMA_CHECK;
goto out;
+ }
pmd = mm_find_pmd(mm, address);
- if (!pmd)
+ if (!pmd) {
+ result = SCAN_PMD_NULL;
goto out;
+ }
anon_vma_lock_write(vma->anon_vma);
@@ -2592,6 +2412,7 @@ static void collapse_huge_page(struct mm_struct *mm,
pmd_populate(mm, pmd, pmd_pgtable(_pmd));
spin_unlock(pmd_ptl);
anon_vma_unlock_write(vma->anon_vma);
+ result = SCAN_FAIL;
goto out;
}
@@ -2618,8 +2439,8 @@ static void collapse_huge_page(struct mm_struct *mm,
spin_lock(pmd_ptl);
BUG_ON(!pmd_none(*pmd));
- page_add_new_anon_rmap(new_page, vma, address);
- mem_cgroup_commit_charge(new_page, memcg, false);
+ page_add_new_anon_rmap(new_page, vma, address, true);
+ mem_cgroup_commit_charge(new_page, memcg, false, true);
lru_cache_add_active_or_unevictable(new_page, vma);
pgtable_trans_huge_deposit(mm, pmd, pgtable);
set_pmd_at(mm, address, pmd, _pmd);
@@ -2629,12 +2450,17 @@ static void collapse_huge_page(struct mm_struct *mm,
*hpage = NULL;
khugepaged_pages_collapsed++;
+ result = SCAN_SUCCEED;
out_up_write:
up_write(&mm->mmap_sem);
+ trace_mm_collapse_huge_page(mm, isolated, result);
return;
+out_nolock:
+ trace_mm_collapse_huge_page(mm, isolated, result);
+ return;
out:
- mem_cgroup_cancel_charge(new_page, memcg);
+ mem_cgroup_cancel_charge(new_page, memcg, true);
goto out_up_write;
}
@@ -2645,8 +2471,8 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
{
pmd_t *pmd;
pte_t *pte, *_pte;
- int ret = 0, none_or_zero = 0;
- struct page *page;
+ int ret = 0, none_or_zero = 0, result = 0;
+ struct page *page = NULL;
unsigned long _address;
spinlock_t *ptl;
int node = NUMA_NO_NODE;
@@ -2655,8 +2481,10 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
pmd = mm_find_pmd(mm, address);
- if (!pmd)
+ if (!pmd) {
+ result = SCAN_PMD_NULL;
goto out;
+ }
memset(khugepaged_node_load, 0, sizeof(khugepaged_node_load));
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
@@ -2665,19 +2493,32 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
pte_t pteval = *_pte;
if (pte_none(pteval) || is_zero_pfn(pte_pfn(pteval))) {
if (!userfaultfd_armed(vma) &&
- ++none_or_zero <= khugepaged_max_ptes_none)
+ ++none_or_zero <= khugepaged_max_ptes_none) {
continue;
- else
+ } else {
+ result = SCAN_EXCEED_NONE_PTE;
goto out_unmap;
+ }
}
- if (!pte_present(pteval))
+ if (!pte_present(pteval)) {
+ result = SCAN_PTE_NON_PRESENT;
goto out_unmap;
+ }
if (pte_write(pteval))
writable = true;
page = vm_normal_page(vma, _address, pteval);
- if (unlikely(!page))
+ if (unlikely(!page)) {
+ result = SCAN_PAGE_NULL;
+ goto out_unmap;
+ }
+
+ /* TODO: teach khugepaged to collapse THP mapped with pte */
+ if (PageCompound(page)) {
+ result = SCAN_PAGE_COMPOUND;
goto out_unmap;
+ }
+
/*
* Record which node the original page is from and save this
* information to khugepaged_node_load[].
@@ -2685,26 +2526,48 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
* hit record.
*/
node = page_to_nid(page);
- if (khugepaged_scan_abort(node))
+ if (khugepaged_scan_abort(node)) {
+ result = SCAN_SCAN_ABORT;
goto out_unmap;
+ }
khugepaged_node_load[node]++;
- VM_BUG_ON_PAGE(PageCompound(page), page);
- if (!PageLRU(page) || PageLocked(page) || !PageAnon(page))
+ if (!PageLRU(page)) {
+ result = SCAN_SCAN_ABORT;
goto out_unmap;
+ }
+ if (PageLocked(page)) {
+ result = SCAN_PAGE_LOCK;
+ goto out_unmap;
+ }
+ if (!PageAnon(page)) {
+ result = SCAN_PAGE_ANON;
+ goto out_unmap;
+ }
+
/*
* cannot use mapcount: can't collapse if there's a gup pin.
* The page must only be referenced by the scanned process
* and page swap cache.
*/
- if (page_count(page) != 1 + !!PageSwapCache(page))
+ if (page_count(page) != 1 + !!PageSwapCache(page)) {
+ result = SCAN_PAGE_COUNT;
goto out_unmap;
+ }
if (pte_young(pteval) ||
page_is_young(page) || PageReferenced(page) ||
mmu_notifier_test_young(vma->vm_mm, address))
referenced = true;
}
- if (referenced && writable)
- ret = 1;
+ if (writable) {
+ if (referenced) {
+ result = SCAN_SUCCEED;
+ ret = 1;
+ } else {
+ result = SCAN_NO_REFERENCED_PAGE;
+ }
+ } else {
+ result = SCAN_PAGE_RO;
+ }
out_unmap:
pte_unmap_unlock(pte, ptl);
if (ret) {
@@ -2713,6 +2576,8 @@ out_unmap:
collapse_huge_page(mm, address, hpage, vma, node);
}
out:
+ trace_mm_khugepaged_scan_pmd(mm, page_to_pfn(page), writable, referenced,
+ none_or_zero, result);
return ret;
}
@@ -2938,8 +2803,8 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
pmd_t _pmd;
int i;
- pmdp_huge_clear_flush_notify(vma, haddr, pmd);
/* leave pmd empty until pte is filled */
+ pmdp_huge_clear_flush_notify(vma, haddr, pmd);
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
pmd_populate(mm, &_pmd, pgtable);
@@ -2958,66 +2823,153 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
put_huge_zero_page();
}
-void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmd)
+static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long haddr, bool freeze)
{
- spinlock_t *ptl;
- struct page *page = NULL;
struct mm_struct *mm = vma->vm_mm;
- unsigned long haddr = address & HPAGE_PMD_MASK;
- unsigned long mmun_start; /* For mmu_notifiers */
- unsigned long mmun_end; /* For mmu_notifiers */
+ struct page *page;
+ pgtable_t pgtable;
+ pmd_t _pmd;
+ bool young, write, dirty;
+ int i;
- BUG_ON(vma->vm_start > haddr || vma->vm_end < haddr + HPAGE_PMD_SIZE);
+ VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
+ VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
+ VM_BUG_ON_VMA(vma->vm_end < haddr + HPAGE_PMD_SIZE, vma);
+ VM_BUG_ON(!pmd_trans_huge(*pmd) && !pmd_devmap(*pmd));
+
+ count_vm_event(THP_SPLIT_PMD);
- mmun_start = haddr;
- mmun_end = haddr + HPAGE_PMD_SIZE;
-again:
- mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
- ptl = pmd_lock(mm, pmd);
- if (unlikely(!pmd_trans_huge(*pmd)))
- goto unlock;
if (vma_is_dax(vma)) {
pmd_t _pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd);
if (is_huge_zero_pmd(_pmd))
put_huge_zero_page();
+ return;
} else if (is_huge_zero_pmd(*pmd)) {
- __split_huge_zero_page_pmd(vma, haddr, pmd);
- } else {
- page = pmd_page(*pmd);
- VM_BUG_ON_PAGE(!page_count(page), page);
- get_page(page);
+ return __split_huge_zero_page_pmd(vma, haddr, pmd);
}
- unlock:
- spin_unlock(ptl);
- mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
- if (!page)
- return;
+ page = pmd_page(*pmd);
+ VM_BUG_ON_PAGE(!page_count(page), page);
+ atomic_add(HPAGE_PMD_NR - 1, &page->_count);
+ write = pmd_write(*pmd);
+ young = pmd_young(*pmd);
+ dirty = pmd_dirty(*pmd);
- split_huge_page(page);
- put_page(page);
+ pgtable = pgtable_trans_huge_withdraw(mm, pmd);
+ pmd_populate(mm, &_pmd, pgtable);
+
+ for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
+ pte_t entry, *pte;
+ /*
+ * Note that NUMA hinting access restrictions are not
+ * transferred to avoid any possibility of altering
+ * permissions across VMAs.
+ */
+ if (freeze) {
+ swp_entry_t swp_entry;
+ swp_entry = make_migration_entry(page + i, write);
+ entry = swp_entry_to_pte(swp_entry);
+ } else {
+ entry = mk_pte(page + i, vma->vm_page_prot);
+ entry = maybe_mkwrite(entry, vma);
+ if (!write)
+ entry = pte_wrprotect(entry);
+ if (!young)
+ entry = pte_mkold(entry);
+ }
+ if (dirty)
+ SetPageDirty(page + i);
+ pte = pte_offset_map(&_pmd, haddr);
+ BUG_ON(!pte_none(*pte));
+ set_pte_at(mm, haddr, pte, entry);
+ atomic_inc(&page[i]._mapcount);
+ pte_unmap(pte);
+ }
+
+ /*
+ * Set PG_double_map before dropping compound_mapcount to avoid
+ * false-negative page_mapped().
+ */
+ if (compound_mapcount(page) > 1 && !TestSetPageDoubleMap(page)) {
+ for (i = 0; i < HPAGE_PMD_NR; i++)
+ atomic_inc(&page[i]._mapcount);
+ }
+
+ if (atomic_add_negative(-1, compound_mapcount_ptr(page))) {
+ /* Last compound_mapcount is gone. */
+ __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
+ if (TestClearPageDoubleMap(page)) {
+ /* No need in mapcount reference anymore */
+ for (i = 0; i < HPAGE_PMD_NR; i++)
+ atomic_dec(&page[i]._mapcount);
+ }
+ }
+ smp_wmb(); /* make pte visible before pmd */
/*
- * We don't always have down_write of mmap_sem here: a racing
- * do_huge_pmd_wp_page() might have copied-on-write to another
- * huge page before our split_huge_page() got the anon_vma lock.
+ * Up to this point the pmd is present and huge and userland has the
+ * whole access to the hugepage during the split (which happens in
+ * place). If we overwrite the pmd with the not-huge version pointing
+ * to the pte here (which of course we could if all CPUs were bug
+ * free), userland could trigger a small page size TLB miss on the
+ * small sized TLB while the hugepage TLB entry is still established in
+ * the huge TLB. Some CPU doesn't like that.
+ * See http://support.amd.com/us/Processor_TechDocs/41322.pdf, Erratum
+ * 383 on page 93. Intel should be safe but is also warns that it's
+ * only safe if the permission and cache attributes of the two entries
+ * loaded in the two TLB is identical (which should be the case here).
+ * But it is generally safer to never allow small and huge TLB entries
+ * for the same virtual address to be loaded simultaneously. So instead
+ * of doing "pmd_populate(); flush_pmd_tlb_range();" we first mark the
+ * current pmd notpresent (atomically because here the pmd_trans_huge
+ * and pmd_trans_splitting must remain set at all times on the pmd
+ * until the split is complete for this pmd), then we flush the SMP TLB
+ * and finally we write the non-huge version of the pmd entry with
+ * pmd_populate.
*/
- if (unlikely(pmd_trans_huge(*pmd)))
- goto again;
+ pmdp_invalidate(vma, haddr, pmd);
+ pmd_populate(mm, pmd, pgtable);
+
+ if (freeze) {
+ for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
+ page_remove_rmap(page + i, false);
+ put_page(page + i);
+ }
+ }
}
-void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address,
- pmd_t *pmd)
+void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long address)
{
- struct vm_area_struct *vma;
+ spinlock_t *ptl;
+ struct mm_struct *mm = vma->vm_mm;
+ struct page *page = NULL;
+ unsigned long haddr = address & HPAGE_PMD_MASK;
- vma = find_vma(mm, address);
- BUG_ON(vma == NULL);
- split_huge_page_pmd(vma, address, pmd);
+ mmu_notifier_invalidate_range_start(mm, haddr, haddr + HPAGE_PMD_SIZE);
+ ptl = pmd_lock(mm, pmd);
+ if (pmd_trans_huge(*pmd)) {
+ page = pmd_page(*pmd);
+ if (PageMlocked(page))
+ get_page(page);
+ else
+ page = NULL;
+ } else if (!pmd_devmap(*pmd))
+ goto out;
+ __split_huge_pmd_locked(vma, pmd, haddr, false);
+out:
+ spin_unlock(ptl);
+ mmu_notifier_invalidate_range_end(mm, haddr, haddr + HPAGE_PMD_SIZE);
+ if (page) {
+ lock_page(page);
+ munlock_vma_page(page);
+ unlock_page(page);
+ put_page(page);
+ }
}
-static void split_huge_page_address(struct mm_struct *mm,
+static void split_huge_pmd_address(struct vm_area_struct *vma,
unsigned long address)
{
pgd_t *pgd;
@@ -3026,7 +2978,7 @@ static void split_huge_page_address(struct mm_struct *mm,
VM_BUG_ON(!(address & ~HPAGE_PMD_MASK));
- pgd = pgd_offset(mm, address);
+ pgd = pgd_offset(vma->vm_mm, address);
if (!pgd_present(*pgd))
return;
@@ -3035,13 +2987,13 @@ static void split_huge_page_address(struct mm_struct *mm,
return;
pmd = pmd_offset(pud, address);
- if (!pmd_present(*pmd))
+ if (!pmd_present(*pmd) || (!pmd_trans_huge(*pmd) && !pmd_devmap(*pmd)))
return;
/*
* Caller holds the mmap_sem write mode, so a huge pmd cannot
* materialize from under us.
*/
- split_huge_page_pmd_mm(mm, address, pmd);
+ split_huge_pmd(vma, pmd, address);
}
void vma_adjust_trans_huge(struct vm_area_struct *vma,
@@ -3057,7 +3009,7 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma,
if (start & ~HPAGE_PMD_MASK &&
(start & HPAGE_PMD_MASK) >= vma->vm_start &&
(start & HPAGE_PMD_MASK) + HPAGE_PMD_SIZE <= vma->vm_end)
- split_huge_page_address(vma->vm_mm, start);
+ split_huge_pmd_address(vma, start);
/*
* If the new end address isn't hpage aligned and it could
@@ -3067,7 +3019,7 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma,
if (end & ~HPAGE_PMD_MASK &&
(end & HPAGE_PMD_MASK) >= vma->vm_start &&
(end & HPAGE_PMD_MASK) + HPAGE_PMD_SIZE <= vma->vm_end)
- split_huge_page_address(vma->vm_mm, end);
+ split_huge_pmd_address(vma, end);
/*
* If we're also updating the vma->vm_next->vm_start, if the new
@@ -3081,6 +3033,540 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma,
if (nstart & ~HPAGE_PMD_MASK &&
(nstart & HPAGE_PMD_MASK) >= next->vm_start &&
(nstart & HPAGE_PMD_MASK) + HPAGE_PMD_SIZE <= next->vm_end)
- split_huge_page_address(next->vm_mm, nstart);
+ split_huge_pmd_address(next, nstart);
}
}
+
+static void freeze_page_vma(struct vm_area_struct *vma, struct page *page,
+ unsigned long address)
+{
+ unsigned long haddr = address & HPAGE_PMD_MASK;
+ spinlock_t *ptl;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ int i, nr = HPAGE_PMD_NR;
+
+ /* Skip pages which doesn't belong to the VMA */
+ if (address < vma->vm_start) {
+ int off = (vma->vm_start - address) >> PAGE_SHIFT;
+ page += off;
+ nr -= off;
+ address = vma->vm_start;
+ }
+
+ pgd = pgd_offset(vma->vm_mm, address);
+ if (!pgd_present(*pgd))
+ return;
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ return;
+ pmd = pmd_offset(pud, address);
+ ptl = pmd_lock(vma->vm_mm, pmd);
+ if (!pmd_present(*pmd)) {
+ spin_unlock(ptl);
+ return;
+ }
+ if (pmd_trans_huge(*pmd)) {
+ if (page == pmd_page(*pmd))
+ __split_huge_pmd_locked(vma, pmd, haddr, true);
+ spin_unlock(ptl);
+ return;
+ }
+ spin_unlock(ptl);
+
+ pte = pte_offset_map_lock(vma->vm_mm, pmd, address, &ptl);
+ for (i = 0; i < nr; i++, address += PAGE_SIZE, page++, pte++) {
+ pte_t entry, swp_pte;
+ swp_entry_t swp_entry;
+
+ /*
+ * We've just crossed page table boundary: need to map next one.
+ * It can happen if THP was mremaped to non PMD-aligned address.
+ */
+ if (unlikely(address == haddr + HPAGE_PMD_SIZE)) {
+ pte_unmap_unlock(pte - 1, ptl);
+ pmd = mm_find_pmd(vma->vm_mm, address);
+ if (!pmd)
+ return;
+ pte = pte_offset_map_lock(vma->vm_mm, pmd,
+ address, &ptl);
+ }
+
+ if (!pte_present(*pte))
+ continue;
+ if (page_to_pfn(page) != pte_pfn(*pte))
+ continue;
+ flush_cache_page(vma, address, page_to_pfn(page));
+ entry = ptep_clear_flush(vma, address, pte);
+ if (pte_dirty(entry))
+ SetPageDirty(page);
+ swp_entry = make_migration_entry(page, pte_write(entry));
+ swp_pte = swp_entry_to_pte(swp_entry);
+ if (pte_soft_dirty(entry))
+ swp_pte = pte_swp_mksoft_dirty(swp_pte);
+ set_pte_at(vma->vm_mm, address, pte, swp_pte);
+ page_remove_rmap(page, false);
+ put_page(page);
+ }
+ pte_unmap_unlock(pte - 1, ptl);
+}
+
+static void freeze_page(struct anon_vma *anon_vma, struct page *page)
+{
+ struct anon_vma_chain *avc;
+ pgoff_t pgoff = page_to_pgoff(page);
+
+ VM_BUG_ON_PAGE(!PageHead(page), page);
+
+ anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff,
+ pgoff + HPAGE_PMD_NR - 1) {
+ unsigned long address = __vma_address(page, avc->vma);
+
+ mmu_notifier_invalidate_range_start(avc->vma->vm_mm,
+ address, address + HPAGE_PMD_SIZE);
+ freeze_page_vma(avc->vma, page, address);
+ mmu_notifier_invalidate_range_end(avc->vma->vm_mm,
+ address, address + HPAGE_PMD_SIZE);
+ }
+}
+
+static void unfreeze_page_vma(struct vm_area_struct *vma, struct page *page,
+ unsigned long address)
+{
+ spinlock_t *ptl;
+ pmd_t *pmd;
+ pte_t *pte, entry;
+ swp_entry_t swp_entry;
+ unsigned long haddr = address & HPAGE_PMD_MASK;
+ int i, nr = HPAGE_PMD_NR;
+
+ /* Skip pages which doesn't belong to the VMA */
+ if (address < vma->vm_start) {
+ int off = (vma->vm_start - address) >> PAGE_SHIFT;
+ page += off;
+ nr -= off;
+ address = vma->vm_start;
+ }
+
+ pmd = mm_find_pmd(vma->vm_mm, address);
+ if (!pmd)
+ return;
+
+ pte = pte_offset_map_lock(vma->vm_mm, pmd, address, &ptl);
+ for (i = 0; i < nr; i++, address += PAGE_SIZE, page++, pte++) {
+ /*
+ * We've just crossed page table boundary: need to map next one.
+ * It can happen if THP was mremaped to non-PMD aligned address.
+ */
+ if (unlikely(address == haddr + HPAGE_PMD_SIZE)) {
+ pte_unmap_unlock(pte - 1, ptl);
+ pmd = mm_find_pmd(vma->vm_mm, address);
+ if (!pmd)
+ return;
+ pte = pte_offset_map_lock(vma->vm_mm, pmd,
+ address, &ptl);
+ }
+
+ if (!is_swap_pte(*pte))
+ continue;
+
+ swp_entry = pte_to_swp_entry(*pte);
+ if (!is_migration_entry(swp_entry))
+ continue;
+ if (migration_entry_to_page(swp_entry) != page)
+ continue;
+
+ get_page(page);
+ page_add_anon_rmap(page, vma, address, false);
+
+ entry = pte_mkold(mk_pte(page, vma->vm_page_prot));
+ if (PageDirty(page))
+ entry = pte_mkdirty(entry);
+ if (is_write_migration_entry(swp_entry))
+ entry = maybe_mkwrite(entry, vma);
+
+ flush_dcache_page(page);
+ set_pte_at(vma->vm_mm, address, pte, entry);
+
+ /* No need to invalidate - it was non-present before */
+ update_mmu_cache(vma, address, pte);
+ }
+ pte_unmap_unlock(pte - 1, ptl);
+}
+
+static void unfreeze_page(struct anon_vma *anon_vma, struct page *page)
+{
+ struct anon_vma_chain *avc;
+ pgoff_t pgoff = page_to_pgoff(page);
+
+ anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root,
+ pgoff, pgoff + HPAGE_PMD_NR - 1) {
+ unsigned long address = __vma_address(page, avc->vma);
+
+ mmu_notifier_invalidate_range_start(avc->vma->vm_mm,
+ address, address + HPAGE_PMD_SIZE);
+ unfreeze_page_vma(avc->vma, page, address);
+ mmu_notifier_invalidate_range_end(avc->vma->vm_mm,
+ address, address + HPAGE_PMD_SIZE);
+ }
+}
+
+static int __split_huge_page_tail(struct page *head, int tail,
+ struct lruvec *lruvec, struct list_head *list)
+{
+ int mapcount;
+ struct page *page_tail = head + tail;
+
+ mapcount = atomic_read(&page_tail->_mapcount) + 1;
+ VM_BUG_ON_PAGE(atomic_read(&page_tail->_count) != 0, page_tail);
+
+ /*
+ * tail_page->_count is zero and not changing from under us. But
+ * get_page_unless_zero() may be running from under us on the
+ * tail_page. If we used atomic_set() below instead of atomic_add(), we
+ * would then run atomic_set() concurrently with
+ * get_page_unless_zero(), and atomic_set() is implemented in C not
+ * using locked ops. spin_unlock on x86 sometime uses locked ops
+ * because of PPro errata 66, 92, so unless somebody can guarantee
+ * atomic_set() here would be safe on all archs (and not only on x86),
+ * it's safer to use atomic_add().
+ */
+ atomic_add(mapcount + 1, &page_tail->_count);
+
+
+ page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
+ page_tail->flags |= (head->flags &
+ ((1L << PG_referenced) |
+ (1L << PG_swapbacked) |
+ (1L << PG_mlocked) |
+ (1L << PG_uptodate) |
+ (1L << PG_active) |
+ (1L << PG_locked) |
+ (1L << PG_unevictable) |
+ (1L << PG_dirty)));
+
+ /*
+ * After clearing PageTail the gup refcount can be released.
+ * Page flags also must be visible before we make the page non-compound.
+ */
+ smp_wmb();
+
+ clear_compound_head(page_tail);
+
+ if (page_is_young(head))
+ set_page_young(page_tail);
+ if (page_is_idle(head))
+ set_page_idle(page_tail);
+
+ /* ->mapping in first tail page is compound_mapcount */
+ VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING,
+ page_tail);
+ page_tail->mapping = head->mapping;
+
+ page_tail->index = head->index + tail;
+ page_cpupid_xchg_last(page_tail, page_cpupid_last(head));
+ lru_add_page_tail(head, page_tail, lruvec, list);
+
+ return mapcount;
+}
+
+static void __split_huge_page(struct page *page, struct list_head *list)
+{
+ struct page *head = compound_head(page);
+ struct zone *zone = page_zone(head);
+ struct lruvec *lruvec;
+ int i, tail_mapcount;
+
+ /* prevent PageLRU to go away from under us, and freeze lru stats */
+ spin_lock_irq(&zone->lru_lock);
+ lruvec = mem_cgroup_page_lruvec(head, zone);
+
+ /* complete memcg works before add pages to LRU */
+ mem_cgroup_split_huge_fixup(head);
+
+ tail_mapcount = 0;
+ for (i = HPAGE_PMD_NR - 1; i >= 1; i--)
+ tail_mapcount += __split_huge_page_tail(head, i, lruvec, list);
+ atomic_sub(tail_mapcount, &head->_count);
+
+ ClearPageCompound(head);
+ spin_unlock_irq(&zone->lru_lock);
+
+ unfreeze_page(page_anon_vma(head), head);
+
+ for (i = 0; i < HPAGE_PMD_NR; i++) {
+ struct page *subpage = head + i;
+ if (subpage == page)
+ continue;
+ unlock_page(subpage);
+
+ /*
+ * Subpages may be freed if there wasn't any mapping
+ * like if add_to_swap() is running on a lru page that
+ * had its mapping zapped. And freeing these pages
+ * requires taking the lru_lock so we do the put_page
+ * of the tail pages after the split is complete.
+ */
+ put_page(subpage);
+ }
+}
+
+int total_mapcount(struct page *page)
+{
+ int i, ret;
+
+ VM_BUG_ON_PAGE(PageTail(page), page);
+
+ if (likely(!PageCompound(page)))
+ return atomic_read(&page->_mapcount) + 1;
+
+ ret = compound_mapcount(page);
+ if (PageHuge(page))
+ return ret;
+ for (i = 0; i < HPAGE_PMD_NR; i++)
+ ret += atomic_read(&page[i]._mapcount) + 1;
+ if (PageDoubleMap(page))
+ ret -= HPAGE_PMD_NR;
+ return ret;
+}
+
+/*
+ * This function splits huge page into normal pages. @page can point to any
+ * subpage of huge page to split. Split doesn't change the position of @page.
+ *
+ * Only caller must hold pin on the @page, otherwise split fails with -EBUSY.
+ * The huge page must be locked.
+ *
+ * If @list is null, tail pages will be added to LRU list, otherwise, to @list.
+ *
+ * Both head page and tail pages will inherit mapping, flags, and so on from
+ * the hugepage.
+ *
+ * GUP pin and PG_locked transferred to @page. Rest subpages can be freed if
+ * they are not mapped.
+ *
+ * Returns 0 if the hugepage is split successfully.
+ * Returns -EBUSY if the page is pinned or if anon_vma disappeared from under
+ * us.
+ */
+int split_huge_page_to_list(struct page *page, struct list_head *list)
+{
+ struct page *head = compound_head(page);
+ struct anon_vma *anon_vma;
+ int count, mapcount, ret;
+ bool mlocked;
+
+ VM_BUG_ON_PAGE(is_huge_zero_page(page), page);
+ VM_BUG_ON_PAGE(!PageAnon(page), page);
+ VM_BUG_ON_PAGE(!PageLocked(page), page);
+ VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
+ VM_BUG_ON_PAGE(!PageCompound(page), page);
+
+ /*
+ * The caller does not necessarily hold an mmap_sem that would prevent
+ * the anon_vma disappearing so we first we take a reference to it
+ * and then lock the anon_vma for write. This is similar to
+ * page_lock_anon_vma_read except the write lock is taken to serialise
+ * against parallel split or collapse operations.
+ */
+ anon_vma = page_get_anon_vma(head);
+ if (!anon_vma) {
+ ret = -EBUSY;
+ goto out;
+ }
+ anon_vma_lock_write(anon_vma);
+
+ /*
+ * Racy check if we can split the page, before freeze_page() will
+ * split PMDs
+ */
+ if (total_mapcount(head) != page_count(head) - 1) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ mlocked = PageMlocked(page);
+ freeze_page(anon_vma, head);
+ VM_BUG_ON_PAGE(compound_mapcount(head), head);
+
+ /* Make sure the page is not on per-CPU pagevec as it takes pin */
+ if (mlocked)
+ lru_add_drain();
+
+ /* Prevent deferred_split_scan() touching ->_count */
+ spin_lock(&split_queue_lock);
+ count = page_count(head);
+ mapcount = total_mapcount(head);
+ if (!mapcount && count == 1) {
+ if (!list_empty(page_deferred_list(head))) {
+ split_queue_len--;
+ list_del(page_deferred_list(head));
+ }
+ spin_unlock(&split_queue_lock);
+ __split_huge_page(page, list);
+ ret = 0;
+ } else if (IS_ENABLED(CONFIG_DEBUG_VM) && mapcount) {
+ spin_unlock(&split_queue_lock);
+ pr_alert("total_mapcount: %u, page_count(): %u\n",
+ mapcount, count);
+ if (PageTail(page))
+ dump_page(head, NULL);
+ dump_page(page, "total_mapcount(head) > 0");
+ BUG();
+ } else {
+ spin_unlock(&split_queue_lock);
+ unfreeze_page(anon_vma, head);
+ ret = -EBUSY;
+ }
+
+out_unlock:
+ anon_vma_unlock_write(anon_vma);
+ put_anon_vma(anon_vma);
+out:
+ count_vm_event(!ret ? THP_SPLIT_PAGE : THP_SPLIT_PAGE_FAILED);
+ return ret;
+}
+
+void free_transhuge_page(struct page *page)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&split_queue_lock, flags);
+ if (!list_empty(page_deferred_list(page))) {
+ split_queue_len--;
+ list_del(page_deferred_list(page));
+ }
+ spin_unlock_irqrestore(&split_queue_lock, flags);
+ free_compound_page(page);
+}
+
+void deferred_split_huge_page(struct page *page)
+{
+ unsigned long flags;
+
+ VM_BUG_ON_PAGE(!PageTransHuge(page), page);
+
+ spin_lock_irqsave(&split_queue_lock, flags);
+ if (list_empty(page_deferred_list(page))) {
+ list_add_tail(page_deferred_list(page), &split_queue);
+ split_queue_len++;
+ }
+ spin_unlock_irqrestore(&split_queue_lock, flags);
+}
+
+static unsigned long deferred_split_count(struct shrinker *shrink,
+ struct shrink_control *sc)
+{
+ /*
+ * Split a page from split_queue will free up at least one page,
+ * at most HPAGE_PMD_NR - 1. We don't track exact number.
+ * Let's use HPAGE_PMD_NR / 2 as ballpark.
+ */
+ return ACCESS_ONCE(split_queue_len) * HPAGE_PMD_NR / 2;
+}
+
+static unsigned long deferred_split_scan(struct shrinker *shrink,
+ struct shrink_control *sc)
+{
+ unsigned long flags;
+ LIST_HEAD(list), *pos, *next;
+ struct page *page;
+ int split = 0;
+
+ spin_lock_irqsave(&split_queue_lock, flags);
+ list_splice_init(&split_queue, &list);
+
+ /* Take pin on all head pages to avoid freeing them under us */
+ list_for_each_safe(pos, next, &list) {
+ page = list_entry((void *)pos, struct page, mapping);
+ page = compound_head(page);
+ /* race with put_compound_page() */
+ if (!get_page_unless_zero(page)) {
+ list_del_init(page_deferred_list(page));
+ split_queue_len--;
+ }
+ }
+ spin_unlock_irqrestore(&split_queue_lock, flags);
+
+ list_for_each_safe(pos, next, &list) {
+ page = list_entry((void *)pos, struct page, mapping);
+ lock_page(page);
+ /* split_huge_page() removes page from list on success */
+ if (!split_huge_page(page))
+ split++;
+ unlock_page(page);
+ put_page(page);
+ }
+
+ spin_lock_irqsave(&split_queue_lock, flags);
+ list_splice_tail(&list, &split_queue);
+ spin_unlock_irqrestore(&split_queue_lock, flags);
+
+ return split * HPAGE_PMD_NR / 2;
+}
+
+static struct shrinker deferred_split_shrinker = {
+ .count_objects = deferred_split_count,
+ .scan_objects = deferred_split_scan,
+ .seeks = DEFAULT_SEEKS,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int split_huge_pages_set(void *data, u64 val)
+{
+ struct zone *zone;
+ struct page *page;
+ unsigned long pfn, max_zone_pfn;
+ unsigned long total = 0, split = 0;
+
+ if (val != 1)
+ return -EINVAL;
+
+ for_each_populated_zone(zone) {
+ max_zone_pfn = zone_end_pfn(zone);
+ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) {
+ if (!pfn_valid(pfn))
+ continue;
+
+ page = pfn_to_page(pfn);
+ if (!get_page_unless_zero(page))
+ continue;
+
+ if (zone != page_zone(page))
+ goto next;
+
+ if (!PageHead(page) || !PageAnon(page) ||
+ PageHuge(page))
+ goto next;
+
+ total++;
+ lock_page(page);
+ if (!split_huge_page(page))
+ split++;
+ unlock_page(page);
+next:
+ put_page(page);
+ }
+ }
+
+ pr_info("%lu of %lu THP split", split, total);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(split_huge_pages_fops, NULL, split_huge_pages_set,
+ "%llu\n");
+
+static int __init split_huge_pages_debugfs(void)
+{
+ void *ret;
+
+ ret = debugfs_create_file("split_huge_pages", 0644, NULL, NULL,
+ &split_huge_pages_fops);
+ if (!ret)
+ pr_warn("Failed to create split_huge_pages in debugfs");
+ return 0;
+}
+late_initcall(split_huge_pages_debugfs);
+#endif
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ef6963b577fd..12908dcf5831 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4,7 +4,6 @@
*/
#include <linux/list.h>
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/sysctl.h>
@@ -1268,8 +1267,8 @@ static void prep_compound_gigantic_page(struct page *page, unsigned int order)
/* we rely on prep_new_huge_page to set the destructor */
set_compound_order(page, order);
- __SetPageHead(page);
__ClearPageReserved(page);
+ __SetPageHead(page);
for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
/*
* For gigantic hugepages allocated through bootmem at
@@ -2549,25 +2548,6 @@ static void hugetlb_unregister_node(struct node *node)
nhs->hugepages_kobj = NULL;
}
-/*
- * hugetlb module exit: unregister hstate attributes from node devices
- * that have them.
- */
-static void hugetlb_unregister_all_nodes(void)
-{
- int nid;
-
- /*
- * disable node device registrations.
- */
- register_hugetlbfs_with_node(NULL, NULL);
-
- /*
- * remove hstate attributes from any nodes that have them.
- */
- for (nid = 0; nid < nr_node_ids; nid++)
- hugetlb_unregister_node(node_devices[nid]);
-}
/*
* Register hstate attributes for a single node device.
@@ -2632,27 +2612,10 @@ static struct hstate *kobj_to_node_hstate(struct kobject *kobj, int *nidp)
return NULL;
}
-static void hugetlb_unregister_all_nodes(void) { }
-
static void hugetlb_register_all_nodes(void) { }
#endif
-static void __exit hugetlb_exit(void)
-{
- struct hstate *h;
-
- hugetlb_unregister_all_nodes();
-
- for_each_hstate(h) {
- kobject_put(hstate_kobjs[hstate_index(h)]);
- }
-
- kobject_put(hugepages_kobj);
- kfree(hugetlb_fault_mutex_table);
-}
-module_exit(hugetlb_exit);
-
static int __init hugetlb_init(void)
{
int i;
@@ -2690,7 +2653,7 @@ static int __init hugetlb_init(void)
mutex_init(&hugetlb_fault_mutex_table[i]);
return 0;
}
-module_init(hugetlb_init);
+subsys_initcall(hugetlb_init);
/* Should be called on processing a hugepagesz=... option */
void __init hugetlb_add_hstate(unsigned int order)
@@ -3139,7 +3102,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
entry = huge_ptep_get(src_pte);
ptepage = pte_page(entry);
get_page(ptepage);
- page_dup_rmap(ptepage);
+ page_dup_rmap(ptepage, true);
set_huge_pte_at(dst, addr, dst_pte, entry);
hugetlb_count_add(pages_per_huge_page(h), dst);
}
@@ -3223,7 +3186,7 @@ again:
set_page_dirty(page);
hugetlb_count_sub(pages_per_huge_page(h), mm);
- page_remove_rmap(page);
+ page_remove_rmap(page, true);
force_flush = !__tlb_remove_page(tlb, page);
if (force_flush) {
address += sz;
@@ -3452,7 +3415,7 @@ retry_avoidcopy:
mmu_notifier_invalidate_range(mm, mmun_start, mmun_end);
set_huge_pte_at(mm, address, ptep,
make_huge_pte(vma, new_page, 1));
- page_remove_rmap(old_page);
+ page_remove_rmap(old_page, true);
hugepage_add_new_anon_rmap(new_page, vma, address);
/* Make the old page be freed below */
new_page = old_page;
@@ -3622,7 +3585,7 @@ retry:
ClearPagePrivate(page);
hugepage_add_new_anon_rmap(page, vma, address);
} else
- page_dup_rmap(page);
+ page_dup_rmap(page, true);
new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)
&& (vma->vm_flags & VM_SHARED)));
set_huge_pte_at(mm, address, ptep, new_pte);
@@ -3902,7 +3865,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
same_page:
if (pages) {
pages[i] = mem_map_offset(page, pfn_offset);
- get_page_foll(pages[i]);
+ get_page(pages[i]);
}
if (vmas)
diff --git a/mm/internal.h b/mm/internal.h
index 38e24b89e4c4..ed8b5ffcf9b1 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/pagemap.h>
/*
* The set of flags that only affect watermark checking and reclaim
@@ -66,50 +67,6 @@ static inline void set_page_refcounted(struct page *page)
set_page_count(page, 1);
}
-static inline void __get_page_tail_foll(struct page *page,
- bool get_page_head)
-{
- /*
- * If we're getting a tail page, the elevated page->_count is
- * required only in the head page and we will elevate the head
- * page->_count and tail page->_mapcount.
- *
- * We elevate page_tail->_mapcount for tail pages to force
- * page_tail->_count to be zero at all times to avoid getting
- * false positives from get_page_unless_zero() with
- * speculative page access (like in
- * page_cache_get_speculative()) on tail pages.
- */
- VM_BUG_ON_PAGE(atomic_read(&compound_head(page)->_count) <= 0, page);
- if (get_page_head)
- atomic_inc(&compound_head(page)->_count);
- get_huge_page_tail(page);
-}
-
-/*
- * This is meant to be called as the FOLL_GET operation of
- * follow_page() and it must be called while holding the proper PT
- * lock while the pte (or pmd_trans_huge) is still mapping the page.
- */
-static inline void get_page_foll(struct page *page)
-{
- if (unlikely(PageTail(page)))
- /*
- * This is safe only because
- * __split_huge_page_refcount() can't run under
- * get_page_foll() because we hold the proper PT lock.
- */
- __get_page_tail_foll(page, true);
- else {
- /*
- * Getting a normal page or the head of a compound page
- * requires to already have an elevated page->_count.
- */
- VM_BUG_ON_PAGE(atomic_read(&page->_count) <= 0, page);
- atomic_inc(&page->_count);
- }
-}
-
extern unsigned long highest_memmap_pfn;
/*
@@ -309,10 +266,27 @@ static inline void mlock_migrate_page(struct page *newpage, struct page *page)
extern pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma);
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-extern unsigned long vma_address(struct page *page,
- struct vm_area_struct *vma);
-#endif
+/*
+ * At what user virtual address is page expected in @vma?
+ */
+static inline unsigned long
+__vma_address(struct page *page, struct vm_area_struct *vma)
+{
+ pgoff_t pgoff = page_to_pgoff(page);
+ return vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+}
+
+static inline unsigned long
+vma_address(struct page *page, struct vm_area_struct *vma)
+{
+ unsigned long address = __vma_address(page, vma);
+
+ /* page should be within @vma mapping range */
+ VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);
+
+ return address;
+}
+
#else /* !CONFIG_MMU */
static inline void clear_page_mlock(struct page *page) { }
static inline void mlock_vma_page(struct page *page) { }
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 19423a45d7d7..25c0ad36fe38 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -122,8 +122,7 @@
#define BYTES_PER_POINTER sizeof(void *)
/* GFP bitmask for kmemleak internal allocations */
-#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC | \
- __GFP_NOACCOUNT)) | \
+#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC)) | \
__GFP_NORETRY | __GFP_NOMEMALLOC | \
__GFP_NOWARN)
diff --git a/mm/ksm.c b/mm/ksm.c
index b5cd647daa52..ca6d2a06a615 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -441,20 +441,6 @@ static void break_cow(struct rmap_item *rmap_item)
up_read(&mm->mmap_sem);
}
-static struct page *page_trans_compound_anon(struct page *page)
-{
- if (PageTransCompound(page)) {
- struct page *head = compound_head(page);
- /*
- * head may actually be splitted and freed from under
- * us but it's ok here.
- */
- if (PageAnon(head))
- return head;
- }
- return NULL;
-}
-
static struct page *get_mergeable_page(struct rmap_item *rmap_item)
{
struct mm_struct *mm = rmap_item->mm;
@@ -470,7 +456,7 @@ static struct page *get_mergeable_page(struct rmap_item *rmap_item)
page = follow_page(vma, addr, FOLL_GET);
if (IS_ERR_OR_NULL(page))
goto out;
- if (PageAnon(page) || page_trans_compound_anon(page)) {
+ if (PageAnon(page)) {
flush_anon_page(vma, page, addr);
flush_dcache_page(page);
} else {
@@ -740,8 +726,7 @@ static int remove_stable_node(struct stable_node *stable_node)
static int remove_all_stable_nodes(void)
{
- struct stable_node *stable_node;
- struct list_head *this, *next;
+ struct stable_node *stable_node, *next;
int nid;
int err = 0;
@@ -756,8 +741,7 @@ static int remove_all_stable_nodes(void)
cond_resched();
}
}
- list_for_each_safe(this, next, &migrate_nodes) {
- stable_node = list_entry(this, struct stable_node, list);
+ list_for_each_entry_safe(stable_node, next, &migrate_nodes, list) {
if (remove_stable_node(stable_node))
err = -EBUSY;
cond_resched();
@@ -958,13 +942,13 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
}
get_page(kpage);
- page_add_anon_rmap(kpage, vma, addr);
+ page_add_anon_rmap(kpage, vma, addr, false);
flush_cache_page(vma, addr, pte_pfn(*ptep));
ptep_clear_flush_notify(vma, addr, ptep);
set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
- page_remove_rmap(page);
+ page_remove_rmap(page, false);
if (!page_mapped(page))
try_to_free_swap(page);
put_page(page);
@@ -977,33 +961,6 @@ out:
return err;
}
-static int page_trans_compound_anon_split(struct page *page)
-{
- int ret = 0;
- struct page *transhuge_head = page_trans_compound_anon(page);
- if (transhuge_head) {
- /* Get the reference on the head to split it. */
- if (get_page_unless_zero(transhuge_head)) {
- /*
- * Recheck we got the reference while the head
- * was still anonymous.
- */
- if (PageAnon(transhuge_head))
- ret = split_huge_page(transhuge_head);
- else
- /*
- * Retry later if split_huge_page run
- * from under us.
- */
- ret = 1;
- put_page(transhuge_head);
- } else
- /* Retry later if split_huge_page run from under us. */
- ret = 1;
- }
- return ret;
-}
-
/*
* try_to_merge_one_page - take two pages and merge them into one
* @vma: the vma that holds the pte pointing to page
@@ -1022,9 +979,6 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
if (page == kpage) /* ksm page forked */
return 0;
- if (PageTransCompound(page) && page_trans_compound_anon_split(page))
- goto out;
- BUG_ON(PageTransCompound(page));
if (!PageAnon(page))
goto out;
@@ -1037,6 +991,13 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
*/
if (!trylock_page(page))
goto out;
+
+ if (PageTransCompound(page)) {
+ err = split_huge_page(page);
+ if (err)
+ goto out_unlock;
+ }
+
/*
* If this anonymous page is mapped only here, its pte may need
* to be write-protected. If it's mapped elsewhere, all of its
@@ -1052,6 +1013,12 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
*/
set_page_stable_node(page, NULL);
mark_page_accessed(page);
+ /*
+ * Page reclaim just frees a clean page with no dirty
+ * ptes: make sure that the ksm page would be swapped.
+ */
+ if (!PageDirty(page))
+ SetPageDirty(page);
err = 0;
} else if (pages_identical(page, kpage))
err = replace_page(vma, page, kpage, orig_pte);
@@ -1067,6 +1034,7 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,
}
}
+out_unlock:
unlock_page(page);
out:
return err;
@@ -1583,13 +1551,11 @@ static struct rmap_item *scan_get_next_rmap_item(struct page **page)
* so prune them once before each full scan.
*/
if (!ksm_merge_across_nodes) {
- struct stable_node *stable_node;
- struct list_head *this, *next;
+ struct stable_node *stable_node, *next;
struct page *page;
- list_for_each_safe(this, next, &migrate_nodes) {
- stable_node = list_entry(this,
- struct stable_node, list);
+ list_for_each_entry_safe(stable_node, next,
+ &migrate_nodes, list) {
page = get_ksm_page(stable_node, false);
if (page)
put_page(page);
@@ -1639,8 +1605,7 @@ next_mm:
cond_resched();
continue;
}
- if (PageAnon(*page) ||
- page_trans_compound_anon(*page)) {
+ if (PageAnon(*page)) {
flush_anon_page(vma, *page, ksm_scan.address);
flush_dcache_page(*page);
rmap_item = get_next_rmap_item(slot,
@@ -1903,7 +1868,7 @@ struct page *ksm_might_need_to_copy(struct page *page,
SetPageDirty(new_page);
__SetPageUptodate(new_page);
- __set_page_locked(new_page);
+ __SetPageLocked(new_page);
}
return new_page;
@@ -2012,8 +1977,7 @@ static void wait_while_offlining(void)
static void ksm_check_stable_tree(unsigned long start_pfn,
unsigned long end_pfn)
{
- struct stable_node *stable_node;
- struct list_head *this, *next;
+ struct stable_node *stable_node, *next;
struct rb_node *node;
int nid;
@@ -2034,8 +1998,7 @@ static void ksm_check_stable_tree(unsigned long start_pfn,
cond_resched();
}
}
- list_for_each_safe(this, next, &migrate_nodes) {
- stable_node = list_entry(this, struct stable_node, list);
+ list_for_each_entry_safe(stable_node, next, &migrate_nodes, list) {
if (stable_node->kpfn >= start_pfn &&
stable_node->kpfn < end_pfn)
remove_node_from_stable_tree(stable_node);
diff --git a/mm/madvise.c b/mm/madvise.c
index c889fcbb530e..f56825b6d2e1 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -20,6 +20,9 @@
#include <linux/backing-dev.h>
#include <linux/swap.h>
#include <linux/swapops.h>
+#include <linux/mmu_notifier.h>
+
+#include <asm/tlb.h>
/*
* Any behaviour which results in changes to the vma->vm_flags needs to
@@ -32,6 +35,7 @@ static int madvise_need_mmap_write(int behavior)
case MADV_REMOVE:
case MADV_WILLNEED:
case MADV_DONTNEED:
+ case MADV_FREE:
return 0;
default:
/* be safe, default to 1. list exceptions explicitly */
@@ -256,6 +260,194 @@ static long madvise_willneed(struct vm_area_struct *vma,
return 0;
}
+static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
+ unsigned long end, struct mm_walk *walk)
+
+{
+ struct mmu_gather *tlb = walk->private;
+ struct mm_struct *mm = tlb->mm;
+ struct vm_area_struct *vma = walk->vma;
+ spinlock_t *ptl;
+ pte_t *orig_pte, *pte, ptent;
+ struct page *page;
+ int nr_swap = 0;
+ unsigned long next;
+
+ next = pmd_addr_end(addr, end);
+ if (pmd_trans_huge(*pmd))
+ if (madvise_free_huge_pmd(tlb, vma, pmd, addr, next))
+ goto next;
+
+ if (pmd_trans_unstable(pmd))
+ return 0;
+
+ orig_pte = pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ arch_enter_lazy_mmu_mode();
+ for (; addr != end; pte++, addr += PAGE_SIZE) {
+ ptent = *pte;
+
+ if (pte_none(ptent))
+ continue;
+ /*
+ * If the pte has swp_entry, just clear page table to
+ * prevent swap-in which is more expensive rather than
+ * (page allocation + zeroing).
+ */
+ if (!pte_present(ptent)) {
+ swp_entry_t entry;
+
+ entry = pte_to_swp_entry(ptent);
+ if (non_swap_entry(entry))
+ continue;
+ nr_swap--;
+ free_swap_and_cache(entry);
+ pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
+ continue;
+ }
+
+ page = vm_normal_page(vma, addr, ptent);
+ if (!page)
+ continue;
+
+ /*
+ * If pmd isn't transhuge but the page is THP and
+ * is owned by only this process, split it and
+ * deactivate all pages.
+ */
+ if (PageTransCompound(page)) {
+ if (page_mapcount(page) != 1)
+ goto out;
+ get_page(page);
+ if (!trylock_page(page)) {
+ put_page(page);
+ goto out;
+ }
+ pte_unmap_unlock(orig_pte, ptl);
+ if (split_huge_page(page)) {
+ unlock_page(page);
+ put_page(page);
+ pte_offset_map_lock(mm, pmd, addr, &ptl);
+ goto out;
+ }
+ put_page(page);
+ unlock_page(page);
+ pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ pte--;
+ addr -= PAGE_SIZE;
+ continue;
+ }
+
+ VM_BUG_ON_PAGE(PageTransCompound(page), page);
+
+ if (PageSwapCache(page) || PageDirty(page)) {
+ if (!trylock_page(page))
+ continue;
+ /*
+ * If page is shared with others, we couldn't clear
+ * PG_dirty of the page.
+ */
+ if (page_mapcount(page) != 1) {
+ unlock_page(page);
+ continue;
+ }
+
+ if (PageSwapCache(page) && !try_to_free_swap(page)) {
+ unlock_page(page);
+ continue;
+ }
+
+ ClearPageDirty(page);
+ unlock_page(page);
+ }
+
+ if (pte_young(ptent) || pte_dirty(ptent)) {
+ /*
+ * Some of architecture(ex, PPC) don't update TLB
+ * with set_pte_at and tlb_remove_tlb_entry so for
+ * the portability, remap the pte with old|clean
+ * after pte clearing.
+ */
+ ptent = ptep_get_and_clear_full(mm, addr, pte,
+ tlb->fullmm);
+
+ ptent = pte_mkold(ptent);
+ ptent = pte_mkclean(ptent);
+ set_pte_at(mm, addr, pte, ptent);
+ if (PageActive(page))
+ deactivate_page(page);
+ tlb_remove_tlb_entry(tlb, pte, addr);
+ }
+ }
+out:
+ if (nr_swap) {
+ if (current->mm == mm)
+ sync_mm_rss(mm);
+
+ add_mm_counter(mm, MM_SWAPENTS, nr_swap);
+ }
+ arch_leave_lazy_mmu_mode();
+ pte_unmap_unlock(orig_pte, ptl);
+ cond_resched();
+next:
+ return 0;
+}
+
+static void madvise_free_page_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma,
+ unsigned long addr, unsigned long end)
+{
+ struct mm_walk free_walk = {
+ .pmd_entry = madvise_free_pte_range,
+ .mm = vma->vm_mm,
+ .private = tlb,
+ };
+
+ tlb_start_vma(tlb, vma);
+ walk_page_range(addr, end, &free_walk);
+ tlb_end_vma(tlb, vma);
+}
+
+static int madvise_free_single_vma(struct vm_area_struct *vma,
+ unsigned long start_addr, unsigned long end_addr)
+{
+ unsigned long start, end;
+ struct mm_struct *mm = vma->vm_mm;
+ struct mmu_gather tlb;
+
+ if (vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP))
+ return -EINVAL;
+
+ /* MADV_FREE works for only anon vma at the moment */
+ if (!vma_is_anonymous(vma))
+ return -EINVAL;
+
+ start = max(vma->vm_start, start_addr);
+ if (start >= vma->vm_end)
+ return -EINVAL;
+ end = min(vma->vm_end, end_addr);
+ if (end <= vma->vm_start)
+ return -EINVAL;
+
+ lru_add_drain();
+ tlb_gather_mmu(&tlb, mm, start, end);
+ update_hiwater_rss(mm);
+
+ mmu_notifier_invalidate_range_start(mm, start, end);
+ madvise_free_page_range(&tlb, vma, start, end);
+ mmu_notifier_invalidate_range_end(mm, start, end);
+ tlb_finish_mmu(&tlb, start, end);
+
+ return 0;
+}
+
+static long madvise_free(struct vm_area_struct *vma,
+ struct vm_area_struct **prev,
+ unsigned long start, unsigned long end)
+{
+ *prev = vma;
+ return madvise_free_single_vma(vma, start, end);
+}
+
/*
* Application no longer needs these pages. If the pages are dirty,
* it's OK to just throw them away. The app will be more careful about
@@ -379,6 +571,14 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
return madvise_remove(vma, prev, start, end);
case MADV_WILLNEED:
return madvise_willneed(vma, prev, start, end);
+ case MADV_FREE:
+ /*
+ * XXX: In this implementation, MADV_FREE works like
+ * MADV_DONTNEED on swapless system or full swap.
+ */
+ if (get_nr_swap_pages() > 0)
+ return madvise_free(vma, prev, start, end);
+ /* passthrough */
case MADV_DONTNEED:
return madvise_dontneed(vma, prev, start, end);
default:
@@ -398,6 +598,7 @@ madvise_behavior_valid(int behavior)
case MADV_REMOVE:
case MADV_WILLNEED:
case MADV_DONTNEED:
+ case MADV_FREE:
#ifdef CONFIG_KSM
case MADV_MERGEABLE:
case MADV_UNMERGEABLE:
diff --git a/mm/memblock.c b/mm/memblock.c
index 07ff069fef25..d2ed81e59a94 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -96,13 +96,10 @@ bool __init_memblock memblock_overlaps_region(struct memblock_type *type,
{
unsigned long i;
- for (i = 0; i < type->cnt; i++) {
- phys_addr_t rgnbase = type->regions[i].base;
- phys_addr_t rgnsize = type->regions[i].size;
- if (memblock_addrs_overlap(base, size, rgnbase, rgnsize))
+ for (i = 0; i < type->cnt; i++)
+ if (memblock_addrs_overlap(base, size, type->regions[i].base,
+ type->regions[i].size))
break;
- }
-
return i < type->cnt;
}
@@ -528,7 +525,8 @@ int __init_memblock memblock_add_range(struct memblock_type *type,
bool insert = false;
phys_addr_t obase = base;
phys_addr_t end = base + memblock_cap_size(base, &size);
- int i, nr_new;
+ int idx, nr_new;
+ struct memblock_region *rgn;
if (!size)
return 0;
@@ -552,8 +550,7 @@ repeat:
base = obase;
nr_new = 0;
- for (i = 0; i < type->cnt; i++) {
- struct memblock_region *rgn = &type->regions[i];
+ for_each_memblock_type(type, rgn) {
phys_addr_t rbase = rgn->base;
phys_addr_t rend = rbase + rgn->size;
@@ -572,7 +569,7 @@ repeat:
WARN_ON(flags != rgn->flags);
nr_new++;
if (insert)
- memblock_insert_region(type, i++, base,
+ memblock_insert_region(type, idx++, base,
rbase - base, nid,
flags);
}
@@ -584,7 +581,7 @@ repeat:
if (base < end) {
nr_new++;
if (insert)
- memblock_insert_region(type, i, base, end - base,
+ memblock_insert_region(type, idx, base, end - base,
nid, flags);
}
@@ -651,7 +648,8 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
int *start_rgn, int *end_rgn)
{
phys_addr_t end = base + memblock_cap_size(base, &size);
- int i;
+ int idx;
+ struct memblock_region *rgn;
*start_rgn = *end_rgn = 0;
@@ -663,8 +661,7 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
if (memblock_double_array(type, base, size) < 0)
return -ENOMEM;
- for (i = 0; i < type->cnt; i++) {
- struct memblock_region *rgn = &type->regions[i];
+ for_each_memblock_type(type, rgn) {
phys_addr_t rbase = rgn->base;
phys_addr_t rend = rbase + rgn->size;
@@ -681,7 +678,7 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
rgn->base = base;
rgn->size -= base - rbase;
type->total_size -= base - rbase;
- memblock_insert_region(type, i, rbase, base - rbase,
+ memblock_insert_region(type, idx, rbase, base - rbase,
memblock_get_region_node(rgn),
rgn->flags);
} else if (rend > end) {
@@ -692,14 +689,14 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
rgn->base = end;
rgn->size -= end - rbase;
type->total_size -= end - rbase;
- memblock_insert_region(type, i--, rbase, end - rbase,
+ memblock_insert_region(type, idx--, rbase, end - rbase,
memblock_get_region_node(rgn),
rgn->flags);
} else {
/* @rgn is fully contained, record it */
if (!*end_rgn)
- *start_rgn = i;
- *end_rgn = i + 1;
+ *start_rgn = idx;
+ *end_rgn = idx + 1;
}
}
@@ -1528,12 +1525,12 @@ static int __init_memblock memblock_search(struct memblock_type *type, phys_addr
return -1;
}
-int __init memblock_is_reserved(phys_addr_t addr)
+bool __init memblock_is_reserved(phys_addr_t addr)
{
return memblock_search(&memblock.reserved, addr) != -1;
}
-int __init_memblock memblock_is_memory(phys_addr_t addr)
+bool __init_memblock memblock_is_memory(phys_addr_t addr)
{
return memblock_search(&memblock.memory, addr) != -1;
}
@@ -1641,12 +1638,12 @@ static void __init_memblock memblock_dump(struct memblock_type *type, char *name
{
unsigned long long base, size;
unsigned long flags;
- int i;
+ int idx;
+ struct memblock_region *rgn;
pr_info(" %s.cnt = 0x%lx\n", name, type->cnt);
- for (i = 0; i < type->cnt; i++) {
- struct memblock_region *rgn = &type->regions[i];
+ for_each_memblock_type(type, rgn) {
char nid_buf[32] = "";
base = rgn->base;
@@ -1658,7 +1655,7 @@ static void __init_memblock memblock_dump(struct memblock_type *type, char *name
memblock_get_region_node(rgn));
#endif
pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes%s flags: %#lx\n",
- name, i, base, base + size - 1, size, nid_buf, flags);
+ name, idx, base, base + size - 1, size, nid_buf, flags);
}
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 14cb1db4c52b..0eda67376df4 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -76,9 +76,12 @@
struct cgroup_subsys memory_cgrp_subsys __read_mostly;
EXPORT_SYMBOL(memory_cgrp_subsys);
+struct mem_cgroup *root_mem_cgroup __read_mostly;
+
#define MEM_CGROUP_RECLAIM_RETRIES 5
-static struct mem_cgroup *root_mem_cgroup __read_mostly;
-struct cgroup_subsys_state *mem_cgroup_root_css __read_mostly;
+
+/* Socket memory accounting disabled? */
+static bool cgroup_memory_nosocket;
/* Whether the swap controller is active */
#ifdef CONFIG_MEMCG_SWAP
@@ -87,6 +90,12 @@ int do_swap_account __read_mostly;
#define do_swap_account 0
#endif
+/* Whether legacy memory+swap accounting is active */
+static bool do_memsw_account(void)
+{
+ return !cgroup_subsys_on_dfl(memory_cgrp_subsys) && do_swap_account;
+}
+
static const char * const mem_cgroup_stat_names[] = {
"cache",
"rss",
@@ -288,64 +297,6 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
return mem_cgroup_from_css(css);
}
-/* Writing them here to avoid exposing memcg's inner layout */
-#if defined(CONFIG_INET) && defined(CONFIG_MEMCG_KMEM)
-
-void sock_update_memcg(struct sock *sk)
-{
- if (mem_cgroup_sockets_enabled) {
- struct mem_cgroup *memcg;
- struct cg_proto *cg_proto;
-
- BUG_ON(!sk->sk_prot->proto_cgroup);
-
- /* Socket cloning can throw us here with sk_cgrp already
- * filled. It won't however, necessarily happen from
- * process context. So the test for root memcg given
- * the current task's memcg won't help us in this case.
- *
- * Respecting the original socket's memcg is a better
- * decision in this case.
- */
- if (sk->sk_cgrp) {
- BUG_ON(mem_cgroup_is_root(sk->sk_cgrp->memcg));
- css_get(&sk->sk_cgrp->memcg->css);
- return;
- }
-
- rcu_read_lock();
- memcg = mem_cgroup_from_task(current);
- cg_proto = sk->sk_prot->proto_cgroup(memcg);
- if (cg_proto && test_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags) &&
- css_tryget_online(&memcg->css)) {
- sk->sk_cgrp = cg_proto;
- }
- rcu_read_unlock();
- }
-}
-EXPORT_SYMBOL(sock_update_memcg);
-
-void sock_release_memcg(struct sock *sk)
-{
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct mem_cgroup *memcg;
- WARN_ON(!sk->sk_cgrp->memcg);
- memcg = sk->sk_cgrp->memcg;
- css_put(&sk->sk_cgrp->memcg->css);
- }
-}
-
-struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg)
-{
- if (!memcg || mem_cgroup_is_root(memcg))
- return NULL;
-
- return &memcg->tcp_mem;
-}
-EXPORT_SYMBOL(tcp_proto_cgroup);
-
-#endif
-
#ifdef CONFIG_MEMCG_KMEM
/*
* This will be the memcg's index in each cache's ->memcg_params.memcg_caches.
@@ -395,7 +346,7 @@ void memcg_put_cache_ids(void)
* conditional to this static branch, we'll have to allow modules that does
* kmem_cache_alloc and the such to see this symbol as well
*/
-struct static_key memcg_kmem_enabled_key;
+DEFINE_STATIC_KEY_FALSE(memcg_kmem_enabled_key);
EXPORT_SYMBOL(memcg_kmem_enabled_key);
#endif /* CONFIG_MEMCG_KMEM */
@@ -431,14 +382,11 @@ struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page)
{
struct mem_cgroup *memcg;
- rcu_read_lock();
-
memcg = page->mem_cgroup;
if (!memcg || !cgroup_subsys_on_dfl(memory_cgrp_subsys))
memcg = root_mem_cgroup;
- rcu_read_unlock();
return &memcg->css;
}
@@ -696,7 +644,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
struct page *page,
- int nr_pages)
+ bool compound, int nr_pages)
{
/*
* Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is
@@ -709,9 +657,11 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE],
nr_pages);
- if (PageTransHuge(page))
+ if (compound) {
+ VM_BUG_ON_PAGE(!PageTransHuge(page), page);
__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE],
nr_pages);
+ }
/* pagein of a big page is an event. So, ignore page size */
if (nr_pages > 0)
@@ -1162,9 +1112,6 @@ bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg)
return ret;
}
-#define mem_cgroup_from_counter(counter, member) \
- container_of(counter, struct mem_cgroup, member)
-
/**
* mem_cgroup_margin - calculate chargeable space of a memory cgroup
* @memcg: the memory cgroup
@@ -1183,7 +1130,7 @@ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg)
if (count < limit)
margin = limit - count;
- if (do_swap_account) {
+ if (do_memsw_account()) {
count = page_counter_read(&memcg->memsw);
limit = READ_ONCE(memcg->memsw.limit);
if (count <= limit)
@@ -1286,7 +1233,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
pr_cont(":");
for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
- if (i == MEM_CGROUP_STAT_SWAP && !do_swap_account)
+ if (i == MEM_CGROUP_STAT_SWAP && !do_memsw_account())
continue;
pr_cont(" %s:%luKB", mem_cgroup_stat_names[i],
K(mem_cgroup_read_stat(iter, i)));
@@ -1909,7 +1856,7 @@ static void drain_stock(struct memcg_stock_pcp *stock)
if (stock->nr_pages) {
page_counter_uncharge(&old->memory, stock->nr_pages);
- if (do_swap_account)
+ if (do_memsw_account())
page_counter_uncharge(&old->memsw, stock->nr_pages);
css_put_many(&old->css, stock->nr_pages);
stock->nr_pages = 0;
@@ -1997,6 +1944,26 @@ static int memcg_cpu_hotplug_callback(struct notifier_block *nb,
return NOTIFY_OK;
}
+static void reclaim_high(struct mem_cgroup *memcg,
+ unsigned int nr_pages,
+ gfp_t gfp_mask)
+{
+ do {
+ if (page_counter_read(&memcg->memory) <= memcg->high)
+ continue;
+ mem_cgroup_events(memcg, MEMCG_HIGH, 1);
+ try_to_free_mem_cgroup_pages(memcg, nr_pages, gfp_mask, true);
+ } while ((memcg = parent_mem_cgroup(memcg)));
+}
+
+static void high_work_func(struct work_struct *work)
+{
+ struct mem_cgroup *memcg;
+
+ memcg = container_of(work, struct mem_cgroup, high_work);
+ reclaim_high(memcg, CHARGE_BATCH, GFP_KERNEL);
+}
+
/*
* Scheduled by try_charge() to be executed from the userland return path
* and reclaims memory over the high limit.
@@ -2004,20 +1971,13 @@ static int memcg_cpu_hotplug_callback(struct notifier_block *nb,
void mem_cgroup_handle_over_high(void)
{
unsigned int nr_pages = current->memcg_nr_pages_over_high;
- struct mem_cgroup *memcg, *pos;
+ struct mem_cgroup *memcg;
if (likely(!nr_pages))
return;
- pos = memcg = get_mem_cgroup_from_mm(current->mm);
-
- do {
- if (page_counter_read(&pos->memory) <= pos->high)
- continue;
- mem_cgroup_events(pos, MEMCG_HIGH, 1);
- try_to_free_mem_cgroup_pages(pos, nr_pages, GFP_KERNEL, true);
- } while ((pos = parent_mem_cgroup(pos)));
-
+ memcg = get_mem_cgroup_from_mm(current->mm);
+ reclaim_high(memcg, nr_pages, GFP_KERNEL);
css_put(&memcg->css);
current->memcg_nr_pages_over_high = 0;
}
@@ -2039,11 +1999,11 @@ retry:
if (consume_stock(memcg, nr_pages))
return 0;
- if (!do_swap_account ||
+ if (!do_memsw_account() ||
page_counter_try_charge(&memcg->memsw, batch, &counter)) {
if (page_counter_try_charge(&memcg->memory, batch, &counter))
goto done_restock;
- if (do_swap_account)
+ if (do_memsw_account())
page_counter_uncharge(&memcg->memsw, batch);
mem_over_limit = mem_cgroup_from_counter(counter, memory);
} else {
@@ -2130,7 +2090,7 @@ force:
* temporarily by force charging it.
*/
page_counter_charge(&memcg->memory, nr_pages);
- if (do_swap_account)
+ if (do_memsw_account())
page_counter_charge(&memcg->memsw, nr_pages);
css_get_many(&memcg->css, nr_pages);
@@ -2152,6 +2112,11 @@ done_restock:
*/
do {
if (page_counter_read(&memcg->memory) > memcg->high) {
+ /* Don't bother a random interrupted task */
+ if (in_interrupt()) {
+ schedule_work(&memcg->high_work);
+ break;
+ }
current->memcg_nr_pages_over_high += batch;
set_notify_resume(current);
break;
@@ -2167,7 +2132,7 @@ static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages)
return;
page_counter_uncharge(&memcg->memory, nr_pages);
- if (do_swap_account)
+ if (do_memsw_account())
page_counter_uncharge(&memcg->memsw, nr_pages);
css_put_many(&memcg->css, nr_pages);
@@ -2356,7 +2321,7 @@ static void memcg_schedule_kmem_cache_create(struct mem_cgroup *memcg,
* Can't be called in interrupt context or from kernel threads.
* This function needs to be called with rcu_read_lock() held.
*/
-struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep)
+struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
{
struct mem_cgroup *memcg;
struct kmem_cache *memcg_cachep;
@@ -2364,6 +2329,12 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep)
VM_BUG_ON(!is_root_cache(cachep));
+ if (cachep->flags & SLAB_ACCOUNT)
+ gfp |= __GFP_ACCOUNT;
+
+ if (!(gfp & __GFP_ACCOUNT))
+ return cachep;
+
if (current->memcg_kmem_skip_account)
return cachep;
@@ -2447,7 +2418,7 @@ void __memcg_kmem_uncharge(struct page *page, int order)
page_counter_uncharge(&memcg->kmem, nr_pages);
page_counter_uncharge(&memcg->memory, nr_pages);
- if (do_swap_account)
+ if (do_memsw_account())
page_counter_uncharge(&memcg->memsw, nr_pages);
page->mem_cgroup = NULL;
@@ -2459,9 +2430,7 @@ void __memcg_kmem_uncharge(struct page *page, int order)
/*
* Because tail pages are not marked as "used", set it. We're under
- * zone->lru_lock, 'splitting on pmd' and compound_lock.
- * charge/uncharge will be never happen and move_account() is done under
- * compound_lock(), so we don't have to take care of races.
+ * zone->lru_lock and migration entries setup in all page mappings.
*/
void mem_cgroup_split_huge_fixup(struct page *head)
{
@@ -2935,7 +2904,7 @@ static int memcg_activate_kmem(struct mem_cgroup *memcg,
err = page_counter_limit(&memcg->kmem, nr_pages);
VM_BUG_ON(err);
- static_key_slow_inc(&memcg_kmem_enabled_key);
+ static_branch_inc(&memcg_kmem_enabled_key);
/*
* A memory cgroup is considered kmem-active as soon as it gets
* kmemcg_id. Setting the id after enabling static branching will
@@ -3162,7 +3131,7 @@ static int memcg_stat_show(struct seq_file *m, void *v)
BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS);
for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
- if (i == MEM_CGROUP_STAT_SWAP && !do_swap_account)
+ if (i == MEM_CGROUP_STAT_SWAP && !do_memsw_account())
continue;
seq_printf(m, "%s %lu\n", mem_cgroup_stat_names[i],
mem_cgroup_read_stat(memcg, i) * PAGE_SIZE);
@@ -3184,14 +3153,14 @@ static int memcg_stat_show(struct seq_file *m, void *v)
}
seq_printf(m, "hierarchical_memory_limit %llu\n",
(u64)memory * PAGE_SIZE);
- if (do_swap_account)
+ if (do_memsw_account())
seq_printf(m, "hierarchical_memsw_limit %llu\n",
(u64)memsw * PAGE_SIZE);
for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
unsigned long long val = 0;
- if (i == MEM_CGROUP_STAT_SWAP && !do_swap_account)
+ if (i == MEM_CGROUP_STAT_SWAP && !do_memsw_account())
continue;
for_each_mem_cgroup_tree(mi, memcg)
val += mem_cgroup_read_stat(mi, i) * PAGE_SIZE;
@@ -3322,7 +3291,7 @@ static void mem_cgroup_threshold(struct mem_cgroup *memcg)
{
while (memcg) {
__mem_cgroup_threshold(memcg, false);
- if (do_swap_account)
+ if (do_memsw_account())
__mem_cgroup_threshold(memcg, true);
memcg = parent_mem_cgroup(memcg);
@@ -3522,16 +3491,17 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
swap_buffers:
/* Swap primary and spare array */
thresholds->spare = thresholds->primary;
- /* If all events are unregistered, free the spare array */
- if (!new) {
- kfree(thresholds->spare);
- thresholds->spare = NULL;
- }
rcu_assign_pointer(thresholds->primary, new);
/* To be sure that nobody uses thresholds */
synchronize_rcu();
+
+ /* If all events are unregistered, free the spare array */
+ if (!new) {
+ kfree(thresholds->spare);
+ thresholds->spare = NULL;
+ }
unlock:
mutex_unlock(&memcg->thresholds_lock);
}
@@ -3621,7 +3591,7 @@ static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
if (ret)
return ret;
- return mem_cgroup_sockets_init(memcg, ss);
+ return tcp_init_cgroup(memcg, ss);
}
static void memcg_deactivate_kmem(struct mem_cgroup *memcg)
@@ -3674,10 +3644,10 @@ static void memcg_destroy_kmem(struct mem_cgroup *memcg)
{
if (memcg->kmem_acct_activated) {
memcg_destroy_kmem_caches(memcg);
- static_key_slow_dec(&memcg_kmem_enabled_key);
+ static_branch_dec(&memcg_kmem_enabled_key);
WARN_ON(page_counter_read(&memcg->kmem));
}
- mem_cgroup_sockets_destroy(memcg);
+ tcp_destroy_cgroup(memcg);
}
#else
static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
@@ -4196,6 +4166,8 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
{
int node;
+ cancel_work_sync(&memcg->high_work);
+
mem_cgroup_remove_from_trees(memcg);
for_each_node(node)
@@ -4206,17 +4178,6 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
kfree(memcg);
}
-/*
- * Returns the parent mem_cgroup in memcgroup hierarchy with hierarchy enabled.
- */
-struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
-{
- if (!memcg->memory.parent)
- return NULL;
- return mem_cgroup_from_counter(memcg->memory.parent, memory);
-}
-EXPORT_SYMBOL(parent_mem_cgroup);
-
static struct cgroup_subsys_state * __ref
mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
{
@@ -4235,7 +4196,6 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
/* root ? */
if (parent_css == NULL) {
root_mem_cgroup = memcg;
- mem_cgroup_root_css = &memcg->css;
page_counter_init(&memcg->memory, NULL);
memcg->high = PAGE_COUNTER_MAX;
memcg->soft_limit = PAGE_COUNTER_MAX;
@@ -4243,6 +4203,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
page_counter_init(&memcg->kmem, NULL);
}
+ INIT_WORK(&memcg->high_work, high_work_func);
memcg->last_scanned_node = MAX_NUMNODES;
INIT_LIST_HEAD(&memcg->oom_notify);
memcg->move_charge_at_immigrate = 0;
@@ -4257,6 +4218,9 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
#ifdef CONFIG_CGROUP_WRITEBACK
INIT_LIST_HEAD(&memcg->cgwb_list);
#endif
+#ifdef CONFIG_INET
+ memcg->socket_pressure = jiffies;
+#endif
return &memcg->css;
free_out:
@@ -4314,6 +4278,11 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
if (ret)
return ret;
+#ifdef CONFIG_INET
+ if (cgroup_subsys_on_dfl(memory_cgrp_subsys) && !cgroup_memory_nosocket)
+ static_branch_inc(&memcg_sockets_enabled_key);
+#endif
+
/*
* Make sure the memcg is initialized: mem_cgroup_iter()
* orders reading memcg->initialized against its callers
@@ -4360,6 +4329,10 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
memcg_destroy_kmem(memcg);
+#ifdef CONFIG_INET
+ if (cgroup_subsys_on_dfl(memory_cgrp_subsys) && !cgroup_memory_nosocket)
+ static_branch_dec(&memcg_sockets_enabled_key);
+#endif
__mem_cgroup_free(memcg);
}
@@ -4476,7 +4449,7 @@ static struct page *mc_handle_swap_pte(struct vm_area_struct *vma,
* we call find_get_page() with swapper_space directly.
*/
page = find_get_page(swap_address_space(ent), ent.val);
- if (do_swap_account)
+ if (do_memsw_account())
entry->val = ent.val;
return page;
@@ -4511,7 +4484,7 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
page = find_get_entry(mapping, pgoff);
if (radix_tree_exceptional_entry(page)) {
swp_entry_t swp = radix_to_swp_entry(page);
- if (do_swap_account)
+ if (do_memsw_account())
*entry = swp;
page = find_get_page(swap_address_space(swp), swp.val);
}
@@ -4530,38 +4503,30 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
* @from: mem_cgroup which the page is moved from.
* @to: mem_cgroup which the page is moved to. @from != @to.
*
- * The caller must confirm following.
- * - page is not on LRU (isolate_page() is useful.)
- * - compound_lock is held when nr_pages > 1
+ * The caller must make sure the page is not on LRU (isolate_page() is useful.)
*
* This function doesn't do "charge" to new cgroup and doesn't do "uncharge"
* from old cgroup.
*/
static int mem_cgroup_move_account(struct page *page,
- unsigned int nr_pages,
+ bool compound,
struct mem_cgroup *from,
struct mem_cgroup *to)
{
unsigned long flags;
+ unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
int ret;
bool anon;
VM_BUG_ON(from == to);
VM_BUG_ON_PAGE(PageLRU(page), page);
- /*
- * The page is isolated from LRU. So, collapse function
- * will not handle this page. But page splitting can happen.
- * Do this check under compound_page_lock(). The caller should
- * hold it.
- */
- ret = -EBUSY;
- if (nr_pages > 1 && !PageTransHuge(page))
- goto out;
+ VM_BUG_ON(compound && !PageTransHuge(page));
/*
* Prevent mem_cgroup_replace_page() from looking at
* page->mem_cgroup of its source page while we change it.
*/
+ ret = -EBUSY;
if (!trylock_page(page))
goto out;
@@ -4616,9 +4581,9 @@ static int mem_cgroup_move_account(struct page *page,
ret = 0;
local_irq_disable();
- mem_cgroup_charge_statistics(to, page, nr_pages);
+ mem_cgroup_charge_statistics(to, page, compound, nr_pages);
memcg_check_events(to, page);
- mem_cgroup_charge_statistics(from, page, -nr_pages);
+ mem_cgroup_charge_statistics(from, page, compound, -nr_pages);
memcg_check_events(from, page);
local_irq_enable();
out_unlock:
@@ -4708,7 +4673,7 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
pte_t *pte;
spinlock_t *ptl;
- if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmd, vma, &ptl)) {
if (get_mctgt_type_thp(vma, addr, *pmd, NULL) == MC_TARGET_PAGE)
mc.precharge += HPAGE_PMD_NR;
spin_unlock(ptl);
@@ -4896,17 +4861,7 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
union mc_target target;
struct page *page;
- /*
- * We don't take compound_lock() here but no race with splitting thp
- * happens because:
- * - if pmd_trans_huge_lock() returns 1, the relevant thp is not
- * under splitting, which means there's no concurrent thp split,
- * - if another thread runs into split_huge_page() just after we
- * entered this if-block, the thread must wait for page table lock
- * to be unlocked in __split_huge_page_splitting(), where the main
- * part of thp split is not executed yet.
- */
- if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmd, vma, &ptl)) {
if (mc.precharge < HPAGE_PMD_NR) {
spin_unlock(ptl);
return 0;
@@ -4915,7 +4870,7 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
if (target_type == MC_TARGET_PAGE) {
page = target.page;
if (!isolate_lru_page(page)) {
- if (!mem_cgroup_move_account(page, HPAGE_PMD_NR,
+ if (!mem_cgroup_move_account(page, true,
mc.from, mc.to)) {
mc.precharge -= HPAGE_PMD_NR;
mc.moved_charge += HPAGE_PMD_NR;
@@ -4942,9 +4897,18 @@ retry:
switch (get_mctgt_type(vma, addr, ptent, &target)) {
case MC_TARGET_PAGE:
page = target.page;
+ /*
+ * We can have a part of the split pmd here. Moving it
+ * can be done but it would be too convoluted so simply
+ * ignore such a partial THP and keep it in original
+ * memcg. There should be somebody mapping the head.
+ */
+ if (PageTransCompound(page))
+ goto put;
if (isolate_lru_page(page))
goto put;
- if (!mem_cgroup_move_account(page, 1, mc.from, mc.to)) {
+ if (!mem_cgroup_move_account(page, false,
+ mc.from, mc.to)) {
mc.precharge--;
/* we uncharge from mc.from later. */
mc.moved_charge++;
@@ -5283,10 +5247,11 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
* with mem_cgroup_cancel_charge() in case page instantiation fails.
*/
int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
- gfp_t gfp_mask, struct mem_cgroup **memcgp)
+ gfp_t gfp_mask, struct mem_cgroup **memcgp,
+ bool compound)
{
struct mem_cgroup *memcg = NULL;
- unsigned int nr_pages = 1;
+ unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
int ret = 0;
if (mem_cgroup_disabled())
@@ -5304,7 +5269,7 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
if (page->mem_cgroup)
goto out;
- if (do_swap_account) {
+ if (do_memsw_account()) {
swp_entry_t ent = { .val = page_private(page), };
unsigned short id = lookup_swap_cgroup_id(ent);
@@ -5316,11 +5281,6 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
}
}
- if (PageTransHuge(page)) {
- nr_pages <<= compound_order(page);
- VM_BUG_ON_PAGE(!PageTransHuge(page), page);
- }
-
if (!memcg)
memcg = get_mem_cgroup_from_mm(mm);
@@ -5349,9 +5309,9 @@ out:
* Use mem_cgroup_cancel_charge() to cancel the transaction instead.
*/
void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
- bool lrucare)
+ bool lrucare, bool compound)
{
- unsigned int nr_pages = 1;
+ unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
VM_BUG_ON_PAGE(!page->mapping, page);
VM_BUG_ON_PAGE(PageLRU(page) && !lrucare, page);
@@ -5368,17 +5328,12 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
commit_charge(page, memcg, lrucare);
- if (PageTransHuge(page)) {
- nr_pages <<= compound_order(page);
- VM_BUG_ON_PAGE(!PageTransHuge(page), page);
- }
-
local_irq_disable();
- mem_cgroup_charge_statistics(memcg, page, nr_pages);
+ mem_cgroup_charge_statistics(memcg, page, compound, nr_pages);
memcg_check_events(memcg, page);
local_irq_enable();
- if (do_swap_account && PageSwapCache(page)) {
+ if (do_memsw_account() && PageSwapCache(page)) {
swp_entry_t entry = { .val = page_private(page) };
/*
* The swap entry might not get freed for a long time,
@@ -5396,9 +5351,10 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
*
* Cancel a charge transaction started by mem_cgroup_try_charge().
*/
-void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg)
+void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg,
+ bool compound)
{
- unsigned int nr_pages = 1;
+ unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
if (mem_cgroup_disabled())
return;
@@ -5410,11 +5366,6 @@ void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg)
if (!memcg)
return;
- if (PageTransHuge(page)) {
- nr_pages <<= compound_order(page);
- VM_BUG_ON_PAGE(!PageTransHuge(page), page);
- }
-
cancel_charge(memcg, nr_pages);
}
@@ -5427,7 +5378,7 @@ static void uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout,
if (!mem_cgroup_is_root(memcg)) {
page_counter_uncharge(&memcg->memory, nr_pages);
- if (do_swap_account)
+ if (do_memsw_account())
page_counter_uncharge(&memcg->memsw, nr_pages);
memcg_oom_recover(memcg);
}
@@ -5580,6 +5531,121 @@ void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage)
commit_charge(newpage, memcg, true);
}
+#ifdef CONFIG_INET
+
+DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);
+EXPORT_SYMBOL(memcg_sockets_enabled_key);
+
+void sock_update_memcg(struct sock *sk)
+{
+ struct mem_cgroup *memcg;
+
+ /* Socket cloning can throw us here with sk_cgrp already
+ * filled. It won't however, necessarily happen from
+ * process context. So the test for root memcg given
+ * the current task's memcg won't help us in this case.
+ *
+ * Respecting the original socket's memcg is a better
+ * decision in this case.
+ */
+ if (sk->sk_memcg) {
+ BUG_ON(mem_cgroup_is_root(sk->sk_memcg));
+ css_get(&sk->sk_memcg->css);
+ return;
+ }
+
+ rcu_read_lock();
+ memcg = mem_cgroup_from_task(current);
+ if (memcg == root_mem_cgroup)
+ goto out;
+#ifdef CONFIG_MEMCG_KMEM
+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && !memcg->tcp_mem.active)
+ goto out;
+#endif
+ if (css_tryget_online(&memcg->css))
+ sk->sk_memcg = memcg;
+out:
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(sock_update_memcg);
+
+void sock_release_memcg(struct sock *sk)
+{
+ WARN_ON(!sk->sk_memcg);
+ css_put(&sk->sk_memcg->css);
+}
+
+/**
+ * mem_cgroup_charge_skmem - charge socket memory
+ * @memcg: memcg to charge
+ * @nr_pages: number of pages to charge
+ *
+ * Charges @nr_pages to @memcg. Returns %true if the charge fit within
+ * @memcg's configured limit, %false if the charge had to be forced.
+ */
+bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)
+{
+ gfp_t gfp_mask = GFP_KERNEL;
+
+#ifdef CONFIG_MEMCG_KMEM
+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) {
+ struct page_counter *counter;
+
+ if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,
+ nr_pages, &counter)) {
+ memcg->tcp_mem.memory_pressure = 0;
+ return true;
+ }
+ page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);
+ memcg->tcp_mem.memory_pressure = 1;
+ return false;
+ }
+#endif
+ /* Don't block in the packet receive path */
+ if (in_softirq())
+ gfp_mask = GFP_NOWAIT;
+
+ if (try_charge(memcg, gfp_mask, nr_pages) == 0)
+ return true;
+
+ try_charge(memcg, gfp_mask|__GFP_NOFAIL, nr_pages);
+ return false;
+}
+
+/**
+ * mem_cgroup_uncharge_skmem - uncharge socket memory
+ * @memcg - memcg to uncharge
+ * @nr_pages - number of pages to uncharge
+ */
+void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)
+{
+#ifdef CONFIG_MEMCG_KMEM
+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) {
+ page_counter_uncharge(&memcg->tcp_mem.memory_allocated,
+ nr_pages);
+ return;
+ }
+#endif
+ page_counter_uncharge(&memcg->memory, nr_pages);
+ css_put_many(&memcg->css, nr_pages);
+}
+
+#endif /* CONFIG_INET */
+
+static int __init cgroup_memory(char *s)
+{
+ char *token;
+
+ while ((token = strsep(&s, ",")) != NULL) {
+ if (!*token)
+ continue;
+ if (!strcmp(token, "nosocket"))
+ cgroup_memory_nosocket = true;
+ }
+ return 0;
+}
+__setup("cgroup.memory=", cgroup_memory);
+
/*
* subsys_initcall() for memory controller.
*
@@ -5635,7 +5701,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
VM_BUG_ON_PAGE(PageLRU(page), page);
VM_BUG_ON_PAGE(page_count(page), page);
- if (!do_swap_account)
+ if (!do_memsw_account())
return;
memcg = page->mem_cgroup;
@@ -5660,7 +5726,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
* only synchronisation we have for udpating the per-CPU variables.
*/
VM_BUG_ON(!irqs_disabled());
- mem_cgroup_charge_statistics(memcg, page, -1);
+ mem_cgroup_charge_statistics(memcg, page, false, -1);
memcg_check_events(memcg, page);
}
@@ -5675,7 +5741,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
struct mem_cgroup *memcg;
unsigned short id;
- if (!do_swap_account)
+ if (!do_memsw_account())
return;
id = swap_cgroup_record(entry, 0);
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8424b64711ac..ac595e7a3a95 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -882,15 +882,7 @@ int get_hwpoison_page(struct page *page)
{
struct page *head = compound_head(page);
- if (PageHuge(head))
- return get_page_unless_zero(head);
-
- /*
- * Thp tail page has special refcounting rule (refcount of tail pages
- * is stored in ->_mapcount,) so we can't call get_page_unless_zero()
- * directly for tail pages.
- */
- if (PageTransHuge(head)) {
+ if (!PageHuge(head) && PageTransHuge(head)) {
/*
* Non anonymous thp exists only in allocation/free time. We
* can't handle such a case correctly, so let's give it up.
@@ -902,41 +894,12 @@ int get_hwpoison_page(struct page *page)
page_to_pfn(page));
return 0;
}
-
- if (get_page_unless_zero(head)) {
- if (PageTail(page))
- get_page(page);
- return 1;
- } else {
- return 0;
- }
}
- return get_page_unless_zero(page);
+ return get_page_unless_zero(head);
}
EXPORT_SYMBOL_GPL(get_hwpoison_page);
-/**
- * put_hwpoison_page() - Put refcount for memory error handling:
- * @page: raw error page (hit by memory error)
- */
-void put_hwpoison_page(struct page *page)
-{
- struct page *head = compound_head(page);
-
- if (PageHuge(head)) {
- put_page(head);
- return;
- }
-
- if (PageTransHuge(head))
- if (page != head)
- put_page(head);
-
- put_page(page);
-}
-EXPORT_SYMBOL_GPL(put_hwpoison_page);
-
/*
* Do all that is necessary to remove user space mappings. Unmap
* the pages and send SIGBUS to the processes if the data was dirty.
@@ -1149,7 +1112,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
}
if (!PageHuge(p) && PageTransHuge(hpage)) {
+ lock_page(hpage);
if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+ unlock_page(hpage);
if (!PageAnon(hpage))
pr_err("MCE: %#lx: non anonymous thp\n", pfn);
else
@@ -1159,6 +1124,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
put_hwpoison_page(p);
return -EBUSY;
}
+ unlock_page(hpage);
+ get_hwpoison_page(p);
+ put_hwpoison_page(hpage);
VM_BUG_ON_PAGE(!page_count(p), p);
hpage = compound_head(p);
}
@@ -1166,7 +1134,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
/*
* We ignore non-LRU pages for good reasons.
* - PG_locked is only well defined for LRU pages and a few others
- * - to avoid races with __set_page_locked()
+ * - to avoid races with __SetPageLocked()
* - to avoid races with __SetPageSlab*() (and more non-atomic ops)
* The check (unnecessarily) ignores LRU pages being isolated and
* walked by the page reclaim code, however that's not a big loss.
@@ -1572,7 +1540,7 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags)
* Did it turn free?
*/
ret = __get_any_page(page, pfn, 0);
- if (!PageLRU(page)) {
+ if (ret == 1 && !PageLRU(page)) {
/* Drop page reference which is from __get_any_page() */
put_hwpoison_page(page);
pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
@@ -1716,6 +1684,49 @@ static int __soft_offline_page(struct page *page, int flags)
return ret;
}
+static int soft_offline_in_use_page(struct page *page, int flags)
+{
+ int ret;
+ struct page *hpage = compound_head(page);
+
+ if (!PageHuge(page) && PageTransHuge(hpage)) {
+ lock_page(hpage);
+ if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+ unlock_page(hpage);
+ if (!PageAnon(hpage))
+ pr_info("soft offline: %#lx: non anonymous thp\n", page_to_pfn(page));
+ else
+ pr_info("soft offline: %#lx: thp split failed\n", page_to_pfn(page));
+ put_hwpoison_page(hpage);
+ return -EBUSY;
+ }
+ unlock_page(hpage);
+ get_hwpoison_page(page);
+ put_hwpoison_page(hpage);
+ }
+
+ if (PageHuge(page))
+ ret = soft_offline_huge_page(page, flags);
+ else
+ ret = __soft_offline_page(page, flags);
+
+ return ret;
+}
+
+static void soft_offline_free_page(struct page *page)
+{
+ if (PageHuge(page)) {
+ struct page *hpage = compound_head(page);
+
+ set_page_hwpoison_huge_page(hpage);
+ if (!dequeue_hwpoisoned_huge_page(hpage))
+ num_poisoned_pages_add(1 << compound_order(hpage));
+ } else {
+ if (!TestSetPageHWPoison(page))
+ num_poisoned_pages_inc();
+ }
+}
+
/**
* soft_offline_page - Soft offline a page.
* @page: page to offline
@@ -1742,7 +1753,6 @@ int soft_offline_page(struct page *page, int flags)
{
int ret;
unsigned long pfn = page_to_pfn(page);
- struct page *hpage = compound_head(page);
if (PageHWPoison(page)) {
pr_info("soft offline: %#lx page already poisoned\n", pfn);
@@ -1750,34 +1760,15 @@ int soft_offline_page(struct page *page, int flags)
put_hwpoison_page(page);
return -EBUSY;
}
- if (!PageHuge(page) && PageTransHuge(hpage)) {
- if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
- pr_info("soft offline: %#lx: failed to split THP\n",
- pfn);
- if (flags & MF_COUNT_INCREASED)
- put_hwpoison_page(page);
- return -EBUSY;
- }
- }
get_online_mems();
-
ret = get_any_page(page, pfn, flags);
put_online_mems();
- if (ret > 0) { /* for in-use pages */
- if (PageHuge(page))
- ret = soft_offline_huge_page(page, flags);
- else
- ret = __soft_offline_page(page, flags);
- } else if (ret == 0) { /* for free pages */
- if (PageHuge(page)) {
- set_page_hwpoison_huge_page(hpage);
- if (!dequeue_hwpoisoned_huge_page(hpage))
- num_poisoned_pages_add(1 << compound_order(hpage));
- } else {
- if (!TestSetPageHWPoison(page))
- num_poisoned_pages_inc();
- }
- }
+
+ if (ret > 0)
+ ret = soft_offline_in_use_page(page, flags);
+ else if (ret == 0)
+ soft_offline_free_page(page);
+
return ret;
}
diff --git a/mm/memory.c b/mm/memory.c
index c387430f06c3..ff17850a52d9 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -50,6 +50,7 @@
#include <linux/export.h>
#include <linux/delayacct.h>
#include <linux/init.h>
+#include <linux/pfn_t.h>
#include <linux/writeback.h>
#include <linux/memcontrol.h>
#include <linux/mmu_notifier.h>
@@ -566,7 +567,6 @@ int __pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
{
spinlock_t *ptl;
pgtable_t new = pte_alloc_one(mm, address);
- int wait_split_huge_page;
if (!new)
return -ENOMEM;
@@ -586,18 +586,14 @@ int __pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */
ptl = pmd_lock(mm, pmd);
- wait_split_huge_page = 0;
if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
atomic_long_inc(&mm->nr_ptes);
pmd_populate(mm, pmd, new);
new = NULL;
- } else if (unlikely(pmd_trans_splitting(*pmd)))
- wait_split_huge_page = 1;
+ }
spin_unlock(ptl);
if (new)
pte_free(mm, new);
- if (wait_split_huge_page)
- wait_split_huge_page(vma->anon_vma, pmd);
return 0;
}
@@ -613,8 +609,7 @@ int __pte_alloc_kernel(pmd_t *pmd, unsigned long address)
if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
pmd_populate_kernel(&init_mm, pmd, new);
new = NULL;
- } else
- VM_BUG_ON(pmd_trans_splitting(*pmd));
+ }
spin_unlock(&init_mm.page_table_lock);
if (new)
pte_free_kernel(&init_mm, new);
@@ -832,10 +827,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
} else if (is_migration_entry(entry)) {
page = migration_entry_to_page(entry);
- if (PageAnon(page))
- rss[MM_ANONPAGES]++;
- else
- rss[MM_FILEPAGES]++;
+ rss[mm_counter(page)]++;
if (is_write_migration_entry(entry) &&
is_cow_mapping(vm_flags)) {
@@ -873,11 +865,8 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
page = vm_normal_page(vma, addr, pte);
if (page) {
get_page(page);
- page_dup_rmap(page);
- if (PageAnon(page))
- rss[MM_ANONPAGES]++;
- else
- rss[MM_FILEPAGES]++;
+ page_dup_rmap(page, false);
+ rss[mm_counter(page)]++;
}
out_set_pte:
@@ -961,7 +950,7 @@ static inline int copy_pmd_range(struct mm_struct *dst_mm, struct mm_struct *src
src_pmd = pmd_offset(src_pud, addr);
do {
next = pmd_addr_end(addr, end);
- if (pmd_trans_huge(*src_pmd)) {
+ if (pmd_trans_huge(*src_pmd) || pmd_devmap(*src_pmd)) {
int err;
VM_BUG_ON(next-addr != HPAGE_PMD_SIZE);
err = copy_huge_pmd(dst_mm, src_mm,
@@ -1113,9 +1102,8 @@ again:
tlb_remove_tlb_entry(tlb, pte, addr);
if (unlikely(!page))
continue;
- if (PageAnon(page))
- rss[MM_ANONPAGES]--;
- else {
+
+ if (!PageAnon(page)) {
if (pte_dirty(ptent)) {
force_flush = 1;
set_page_dirty(page);
@@ -1123,9 +1111,9 @@ again:
if (pte_young(ptent) &&
likely(!(vma->vm_flags & VM_SEQ_READ)))
mark_page_accessed(page);
- rss[MM_FILEPAGES]--;
}
- page_remove_rmap(page);
+ rss[mm_counter(page)]--;
+ page_remove_rmap(page, false);
if (unlikely(page_mapcount(page) < 0))
print_bad_pte(vma, addr, ptent, page);
if (unlikely(!__tlb_remove_page(tlb, page))) {
@@ -1146,11 +1134,7 @@ again:
struct page *page;
page = migration_entry_to_page(entry);
-
- if (PageAnon(page))
- rss[MM_ANONPAGES]--;
- else
- rss[MM_FILEPAGES]--;
+ rss[mm_counter(page)]--;
}
if (unlikely(!free_swap_and_cache(entry)))
print_bad_pte(vma, addr, ptent, NULL);
@@ -1193,7 +1177,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
pmd = pmd_offset(pud, addr);
do {
next = pmd_addr_end(addr, end);
- if (pmd_trans_huge(*pmd)) {
+ if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) {
if (next - addr != HPAGE_PMD_SIZE) {
#ifdef CONFIG_DEBUG_VM
if (!rwsem_is_locked(&tlb->mm->mmap_sem)) {
@@ -1204,7 +1188,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
BUG();
}
#endif
- split_huge_page_pmd(vma, addr, pmd);
+ split_huge_pmd(vma, pmd, addr);
} else if (zap_huge_pmd(tlb, vma, pmd, addr))
goto next;
/* fall through */
@@ -1460,7 +1444,7 @@ static int insert_page(struct vm_area_struct *vma, unsigned long addr,
/* Ok, finally just insert the thing.. */
get_page(page);
- inc_mm_counter_fast(mm, MM_FILEPAGES);
+ inc_mm_counter_fast(mm, mm_counter_file(page));
page_add_file_rmap(page);
set_pte_at(mm, addr, pte, mk_pte(page, prot));
@@ -1517,7 +1501,7 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
EXPORT_SYMBOL(vm_insert_page);
static int insert_pfn(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn, pgprot_t prot)
+ pfn_t pfn, pgprot_t prot)
{
struct mm_struct *mm = vma->vm_mm;
int retval;
@@ -1533,7 +1517,10 @@ static int insert_pfn(struct vm_area_struct *vma, unsigned long addr,
goto out_unlock;
/* Ok, finally just insert the thing.. */
- entry = pte_mkspecial(pfn_pte(pfn, prot));
+ if (pfn_t_devmap(pfn))
+ entry = pte_mkdevmap(pfn_t_pte(pfn, prot));
+ else
+ entry = pte_mkspecial(pfn_t_pte(pfn, prot));
set_pte_at(mm, addr, pte, entry);
update_mmu_cache(vma, addr, pte); /* XXX: why not for insert_page? */
@@ -1580,17 +1567,17 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
if (addr < vma->vm_start || addr >= vma->vm_end)
return -EFAULT;
- if (track_pfn_insert(vma, &pgprot, pfn))
+ if (track_pfn_insert(vma, &pgprot, __pfn_to_pfn_t(pfn, PFN_DEV)))
return -EINVAL;
- ret = insert_pfn(vma, addr, pfn, pgprot);
+ ret = insert_pfn(vma, addr, __pfn_to_pfn_t(pfn, PFN_DEV), pgprot);
return ret;
}
EXPORT_SYMBOL(vm_insert_pfn);
int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn)
+ pfn_t pfn)
{
BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
@@ -1604,10 +1591,10 @@ int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
* than insert_pfn). If a zero_pfn were inserted into a VM_MIXEDMAP
* without pte special, it would there be refcounted as a normal page.
*/
- if (!HAVE_PTE_SPECIAL && pfn_valid(pfn)) {
+ if (!HAVE_PTE_SPECIAL && pfn_t_valid(pfn)) {
struct page *page;
- page = pfn_to_page(pfn);
+ page = pfn_t_to_page(pfn);
return insert_page(vma, addr, page, vma->vm_page_prot);
}
return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
@@ -1949,6 +1936,20 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
copy_user_highpage(dst, src, va, vma);
}
+static gfp_t __get_fault_gfp_mask(struct vm_area_struct *vma)
+{
+ struct file *vm_file = vma->vm_file;
+
+ if (vm_file)
+ return mapping_gfp_mask(vm_file->f_mapping) | __GFP_FS | __GFP_IO;
+
+ /*
+ * Special mappings (e.g. VDSO) do not have any file so fake
+ * a default GFP_KERNEL for them.
+ */
+ return GFP_KERNEL;
+}
+
/*
* Notify the address space that the page is about to become writable so that
* it can prohibit this or wait for the page to get into an appropriate state.
@@ -1964,6 +1965,7 @@ static int do_page_mkwrite(struct vm_area_struct *vma, struct page *page,
vmf.virtual_address = (void __user *)(address & PAGE_MASK);
vmf.pgoff = page->index;
vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
+ vmf.gfp_mask = __get_fault_gfp_mask(vma);
vmf.page = page;
vmf.cow_page = NULL;
@@ -2083,7 +2085,7 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,
cow_user_page(new_page, old_page, address, vma);
}
- if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg))
+ if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg, false))
goto oom_free_new;
__SetPageUptodate(new_page);
@@ -2097,7 +2099,8 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,
if (likely(pte_same(*page_table, orig_pte))) {
if (old_page) {
if (!PageAnon(old_page)) {
- dec_mm_counter_fast(mm, MM_FILEPAGES);
+ dec_mm_counter_fast(mm,
+ mm_counter_file(old_page));
inc_mm_counter_fast(mm, MM_ANONPAGES);
}
} else {
@@ -2113,8 +2116,8 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,
* thread doing COW.
*/
ptep_clear_flush_notify(vma, address, page_table);
- page_add_new_anon_rmap(new_page, vma, address);
- mem_cgroup_commit_charge(new_page, memcg, false);
+ page_add_new_anon_rmap(new_page, vma, address, false);
+ mem_cgroup_commit_charge(new_page, memcg, false, false);
lru_cache_add_active_or_unevictable(new_page, vma);
/*
* We call the notify macro here because, when using secondary
@@ -2146,14 +2149,14 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,
* mapcount is visible. So transitively, TLBs to
* old page will be flushed before it can be reused.
*/
- page_remove_rmap(old_page);
+ page_remove_rmap(old_page, false);
}
/* Free the old page.. */
new_page = old_page;
page_copied = 1;
} else {
- mem_cgroup_cancel_charge(new_page, memcg);
+ mem_cgroup_cancel_charge(new_page, memcg, false);
}
if (new_page)
@@ -2168,7 +2171,8 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,
*/
if (page_copied && (vma->vm_flags & VM_LOCKED)) {
lock_page(old_page); /* LRU manipulation */
- munlock_vma_page(old_page);
+ if (PageMlocked(old_page))
+ munlock_vma_page(old_page);
unlock_page(old_page);
}
page_cache_release(old_page);
@@ -2528,7 +2532,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
goto out_page;
}
- if (mem_cgroup_try_charge(page, mm, GFP_KERNEL, &memcg)) {
+ if (mem_cgroup_try_charge(page, mm, GFP_KERNEL, &memcg, false)) {
ret = VM_FAULT_OOM;
goto out_page;
}
@@ -2562,7 +2566,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
pte = maybe_mkwrite(pte_mkdirty(pte), vma);
flags &= ~FAULT_FLAG_WRITE;
ret |= VM_FAULT_WRITE;
- exclusive = 1;
+ exclusive = RMAP_EXCLUSIVE;
}
flush_icache_page(vma, page);
if (pte_swp_soft_dirty(orig_pte))
@@ -2570,10 +2574,10 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
set_pte_at(mm, address, page_table, pte);
if (page == swapcache) {
do_page_add_anon_rmap(page, vma, address, exclusive);
- mem_cgroup_commit_charge(page, memcg, true);
+ mem_cgroup_commit_charge(page, memcg, true, false);
} else { /* ksm created a completely new copy */
- page_add_new_anon_rmap(page, vma, address);
- mem_cgroup_commit_charge(page, memcg, false);
+ page_add_new_anon_rmap(page, vma, address, false);
+ mem_cgroup_commit_charge(page, memcg, false, false);
lru_cache_add_active_or_unevictable(page, vma);
}
@@ -2608,7 +2612,7 @@ unlock:
out:
return ret;
out_nomap:
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
pte_unmap_unlock(page_table, ptl);
out_page:
unlock_page(page);
@@ -2702,7 +2706,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
if (!page)
goto oom;
- if (mem_cgroup_try_charge(page, mm, GFP_KERNEL, &memcg))
+ if (mem_cgroup_try_charge(page, mm, GFP_KERNEL, &memcg, false))
goto oom_free_page;
/*
@@ -2723,15 +2727,15 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
/* Deliver the page fault to userland, check inside PT lock */
if (userfaultfd_missing(vma)) {
pte_unmap_unlock(page_table, ptl);
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
page_cache_release(page);
return handle_userfault(vma, address, flags,
VM_UFFD_MISSING);
}
inc_mm_counter_fast(mm, MM_ANONPAGES);
- page_add_new_anon_rmap(page, vma, address);
- mem_cgroup_commit_charge(page, memcg, false);
+ page_add_new_anon_rmap(page, vma, address, false);
+ mem_cgroup_commit_charge(page, memcg, false, false);
lru_cache_add_active_or_unevictable(page, vma);
setpte:
set_pte_at(mm, address, page_table, entry);
@@ -2742,7 +2746,7 @@ unlock:
pte_unmap_unlock(page_table, ptl);
return 0;
release:
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
page_cache_release(page);
goto unlock;
oom_free_page:
@@ -2767,6 +2771,7 @@ static int __do_fault(struct vm_area_struct *vma, unsigned long address,
vmf.pgoff = pgoff;
vmf.flags = flags;
vmf.page = NULL;
+ vmf.gfp_mask = __get_fault_gfp_mask(vma);
vmf.cow_page = cow_page;
ret = vma->vm_ops->fault(vma, &vmf);
@@ -2818,9 +2823,9 @@ void do_set_pte(struct vm_area_struct *vma, unsigned long address,
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
if (anon) {
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
- page_add_new_anon_rmap(page, vma, address);
+ page_add_new_anon_rmap(page, vma, address, false);
} else {
- inc_mm_counter_fast(vma->vm_mm, MM_FILEPAGES);
+ inc_mm_counter_fast(vma->vm_mm, mm_counter_file(page));
page_add_file_rmap(page);
}
set_pte_at(vma->vm_mm, address, pte, entry);
@@ -2933,6 +2938,7 @@ static void do_fault_around(struct vm_area_struct *vma, unsigned long address,
vmf.pgoff = pgoff;
vmf.max_pgoff = max_pgoff;
vmf.flags = flags;
+ vmf.gfp_mask = __get_fault_gfp_mask(vma);
vma->vm_ops->map_pages(vma, &vmf);
}
@@ -2993,7 +2999,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
if (!new_page)
return VM_FAULT_OOM;
- if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg)) {
+ if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg, false)) {
page_cache_release(new_page);
return VM_FAULT_OOM;
}
@@ -3022,7 +3028,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
goto uncharge_out;
}
do_set_pte(vma, address, new_page, pte, true, true);
- mem_cgroup_commit_charge(new_page, memcg, false);
+ mem_cgroup_commit_charge(new_page, memcg, false, false);
lru_cache_add_active_or_unevictable(new_page, vma);
pte_unmap_unlock(pte, ptl);
if (fault_page) {
@@ -3037,7 +3043,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
}
return ret;
uncharge_out:
- mem_cgroup_cancel_charge(new_page, memcg);
+ mem_cgroup_cancel_charge(new_page, memcg, false);
page_cache_release(new_page);
return ret;
}
@@ -3089,7 +3095,7 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma,
* pinned by vma->vm_file's reference. We rely on unlock_page()'s
* release semantics to prevent the compiler from undoing this copying.
*/
- mapping = fault_page->mapping;
+ mapping = page_rmapping(fault_page);
unlock_page(fault_page);
if ((dirtied || vma->vm_ops->page_mkwrite) && mapping) {
/*
@@ -3191,6 +3197,12 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
return 0;
}
+ /* TODO: handle PTE-mapped THP */
+ if (PageCompound(page)) {
+ pte_unmap_unlock(ptep, ptl);
+ return 0;
+ }
+
/*
* Avoid grouping on RO pages in general. RO pages shouldn't hurt as
* much anyway since they can be in shared cache state. This misses
@@ -3363,17 +3375,9 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
int ret;
barrier();
- if (pmd_trans_huge(orig_pmd)) {
+ if (pmd_trans_huge(orig_pmd) || pmd_devmap(orig_pmd)) {
unsigned int dirty = flags & FAULT_FLAG_WRITE;
- /*
- * If the pmd is splitting, return and retry the
- * the fault. Alternative: wait until the split
- * is done, and goto retry.
- */
- if (pmd_trans_splitting(orig_pmd))
- return 0;
-
if (pmd_protnone(orig_pmd))
return do_huge_pmd_numa_page(mm, vma, address,
orig_pmd, pmd);
@@ -3400,7 +3404,7 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unlikely(__pte_alloc(mm, vma, pmd, address)))
return VM_FAULT_OOM;
/* if an huge pmd materialized from under us just retry later */
- if (unlikely(pmd_trans_huge(*pmd)))
+ if (unlikely(pmd_trans_huge(*pmd) || pmd_devmap(*pmd)))
return 0;
/*
* A regular pmd is established and it can't morph into a huge pmd
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index a042a9d537bb..4af58a3a8ffa 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -17,6 +17,7 @@
#include <linux/sysctl.h>
#include <linux/cpu.h>
#include <linux/memory.h>
+#include <linux/memremap.h>
#include <linux/memory_hotplug.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
@@ -131,7 +132,8 @@ static struct resource *register_memory_resource(u64 start, u64 size)
{
struct resource *res;
res = kzalloc(sizeof(struct resource), GFP_KERNEL);
- BUG_ON(!res);
+ if (!res)
+ return ERR_PTR(-ENOMEM);
res->name = "System RAM";
res->start = start;
@@ -140,7 +142,7 @@ static struct resource *register_memory_resource(u64 start, u64 size)
if (request_resource(&iomem_resource, res) < 0) {
pr_debug("System RAM resource %pR cannot be added\n", res);
kfree(res);
- res = NULL;
+ return ERR_PTR(-EEXIST);
}
return res;
}
@@ -505,10 +507,25 @@ int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
unsigned long i;
int err = 0;
int start_sec, end_sec;
+ struct vmem_altmap *altmap;
+
/* during initialize mem_map, align hot-added range to section */
start_sec = pfn_to_section_nr(phys_start_pfn);
end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
+ altmap = to_vmem_altmap((unsigned long) pfn_to_page(phys_start_pfn));
+ if (altmap) {
+ /*
+ * Validate altmap is within bounds of the total request
+ */
+ if (altmap->base_pfn != phys_start_pfn
+ || vmem_altmap_offset(altmap) > nr_pages) {
+ pr_warn_once("memory add fail, invalid altmap\n");
+ return -EINVAL;
+ }
+ altmap->alloc = 0;
+ }
+
for (i = start_sec; i <= end_sec; i++) {
err = __add_section(nid, zone, section_nr_to_pfn(i));
@@ -730,7 +747,8 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn)
pgdat_resize_unlock(zone->zone_pgdat, &flags);
}
-static int __remove_section(struct zone *zone, struct mem_section *ms)
+static int __remove_section(struct zone *zone, struct mem_section *ms,
+ unsigned long map_offset)
{
unsigned long start_pfn;
int scn_nr;
@@ -747,7 +765,7 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
start_pfn = section_nr_to_pfn(scn_nr);
__remove_zone(zone, start_pfn);
- sparse_remove_one_section(zone, ms);
+ sparse_remove_one_section(zone, ms, map_offset);
return 0;
}
@@ -766,9 +784,32 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
unsigned long nr_pages)
{
unsigned long i;
- int sections_to_remove;
- resource_size_t start, size;
- int ret = 0;
+ unsigned long map_offset = 0;
+ int sections_to_remove, ret = 0;
+
+ /* In the ZONE_DEVICE case device driver owns the memory region */
+ if (is_dev_zone(zone)) {
+ struct page *page = pfn_to_page(phys_start_pfn);
+ struct vmem_altmap *altmap;
+
+ altmap = to_vmem_altmap((unsigned long) page);
+ if (altmap)
+ map_offset = vmem_altmap_offset(altmap);
+ } else {
+ resource_size_t start, size;
+
+ start = phys_start_pfn << PAGE_SHIFT;
+ size = nr_pages * PAGE_SIZE;
+
+ ret = release_mem_region_adjustable(&iomem_resource, start,
+ size);
+ if (ret) {
+ resource_size_t endres = start + size - 1;
+
+ pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
+ &start, &endres, ret);
+ }
+ }
/*
* We can only remove entire sections
@@ -776,23 +817,12 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
BUG_ON(nr_pages % PAGES_PER_SECTION);
- start = phys_start_pfn << PAGE_SHIFT;
- size = nr_pages * PAGE_SIZE;
-
- /* in the ZONE_DEVICE case device driver owns the memory region */
- if (!is_dev_zone(zone))
- ret = release_mem_region_adjustable(&iomem_resource, start, size);
- if (ret) {
- resource_size_t endres = start + size - 1;
-
- pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
- &start, &endres, ret);
- }
-
sections_to_remove = nr_pages / PAGES_PER_SECTION;
for (i = 0; i < sections_to_remove; i++) {
unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
- ret = __remove_section(zone, __pfn_to_section(pfn));
+
+ ret = __remove_section(zone, __pfn_to_section(pfn), map_offset);
+ map_offset = 0;
if (ret)
break;
}
@@ -1312,8 +1342,8 @@ int __ref add_memory(int nid, u64 start, u64 size)
int ret;
res = register_memory_resource(start, size);
- if (!res)
- return -EEXIST;
+ if (IS_ERR(res))
+ return PTR_ERR(res);
ret = add_memory_resource(nid, res);
if (ret < 0)
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 87a177917cb2..27d135408a22 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -489,14 +489,33 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
struct page *page;
struct queue_pages *qp = walk->private;
unsigned long flags = qp->flags;
- int nid;
+ int nid, ret;
pte_t *pte;
spinlock_t *ptl;
- split_huge_page_pmd(vma, addr, pmd);
- if (pmd_trans_unstable(pmd))
- return 0;
+ if (pmd_trans_huge(*pmd)) {
+ ptl = pmd_lock(walk->mm, pmd);
+ if (pmd_trans_huge(*pmd)) {
+ page = pmd_page(*pmd);
+ if (is_huge_zero_page(page)) {
+ spin_unlock(ptl);
+ split_huge_pmd(vma, pmd, addr);
+ } else {
+ get_page(page);
+ spin_unlock(ptl);
+ lock_page(page);
+ ret = split_huge_page(page);
+ unlock_page(page);
+ put_page(page);
+ if (ret)
+ return 0;
+ }
+ } else {
+ spin_unlock(ptl);
+ }
+ }
+retry:
pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
for (; addr != end; pte++, addr += PAGE_SIZE) {
if (!pte_present(*pte))
@@ -513,6 +532,21 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
nid = page_to_nid(page);
if (node_isset(nid, *qp->nmask) == !!(flags & MPOL_MF_INVERT))
continue;
+ if (PageTail(page) && PageAnon(page)) {
+ get_page(page);
+ pte_unmap_unlock(pte, ptl);
+ lock_page(page);
+ ret = split_huge_page(page);
+ unlock_page(page);
+ put_page(page);
+ /* Failed to split -- skip. */
+ if (ret) {
+ pte = pte_offset_map_lock(walk->mm, pmd,
+ addr, &ptl);
+ continue;
+ }
+ goto retry;
+ }
if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
migrate_page_add(page, qp->pagelist, flags);
@@ -610,7 +644,8 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
if (flags & MPOL_MF_LAZY) {
/* Similar to task_numa_work, skip inaccessible VMAs */
- if (vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))
+ if (vma_migratable(vma) &&
+ vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))
change_prot_numa(vma, start, endvma);
return 1;
}
@@ -2142,12 +2177,14 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
*
* Remember policies even when nobody has shared memory mapped.
* The policies are kept in Red-Black tree linked from the inode.
- * They are protected by the sp->lock spinlock, which should be held
+ * They are protected by the sp->lock rwlock, which should be held
* for any accesses to the tree.
*/
-/* lookup first element intersecting start-end */
-/* Caller holds sp->lock */
+/*
+ * lookup first element intersecting start-end. Caller holds sp->lock for
+ * reading or for writing
+ */
static struct sp_node *
sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
{
@@ -2178,8 +2215,10 @@ sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
return rb_entry(n, struct sp_node, nd);
}
-/* Insert a new shared policy into the list. */
-/* Caller holds sp->lock */
+/*
+ * Insert a new shared policy into the list. Caller holds sp->lock for
+ * writing.
+ */
static void sp_insert(struct shared_policy *sp, struct sp_node *new)
{
struct rb_node **p = &sp->root.rb_node;
@@ -2211,13 +2250,13 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
if (!sp->root.rb_node)
return NULL;
- spin_lock(&sp->lock);
+ read_lock(&sp->lock);
sn = sp_lookup(sp, idx, idx+1);
if (sn) {
mpol_get(sn->policy);
pol = sn->policy;
}
- spin_unlock(&sp->lock);
+ read_unlock(&sp->lock);
return pol;
}
@@ -2360,7 +2399,7 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
int ret = 0;
restart:
- spin_lock(&sp->lock);
+ write_lock(&sp->lock);
n = sp_lookup(sp, start, end);
/* Take care of old policies in the same range. */
while (n && n->start < end) {
@@ -2393,7 +2432,7 @@ restart:
}
if (new)
sp_insert(sp, new);
- spin_unlock(&sp->lock);
+ write_unlock(&sp->lock);
ret = 0;
err_out:
@@ -2405,7 +2444,7 @@ err_out:
return ret;
alloc_new:
- spin_unlock(&sp->lock);
+ write_unlock(&sp->lock);
ret = -ENOMEM;
n_new = kmem_cache_alloc(sn_cache, GFP_KERNEL);
if (!n_new)
@@ -2431,7 +2470,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
int ret;
sp->root = RB_ROOT; /* empty tree == default mempolicy */
- spin_lock_init(&sp->lock);
+ rwlock_init(&sp->lock);
if (mpol) {
struct vm_area_struct pvma;
@@ -2497,14 +2536,14 @@ void mpol_free_shared_policy(struct shared_policy *p)
if (!p->root.rb_node)
return;
- spin_lock(&p->lock);
+ write_lock(&p->lock);
next = rb_first(&p->root);
while (next) {
n = rb_entry(next, struct sp_node, nd);
next = rb_next(&n->nd);
sp_delete(p, n);
}
- spin_unlock(&p->lock);
+ write_unlock(&p->lock);
}
#ifdef CONFIG_NUMA_BALANCING
diff --git a/mm/migrate.c b/mm/migrate.c
index 7890d0bb5e23..b1034f9c77e7 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -165,9 +165,9 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
if (PageAnon(new))
hugepage_add_anon_rmap(new, vma, addr);
else
- page_dup_rmap(new);
+ page_dup_rmap(new, true);
} else if (PageAnon(new))
- page_add_anon_rmap(new, vma, addr);
+ page_add_anon_rmap(new, vma, addr, false);
else
page_add_file_rmap(new);
@@ -943,9 +943,13 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
goto out;
}
- if (unlikely(PageTransHuge(page)))
- if (unlikely(split_huge_page(page)))
+ if (unlikely(PageTransHuge(page))) {
+ lock_page(page);
+ rc = split_huge_page(page);
+ unlock_page(page);
+ if (rc)
goto out;
+ }
rc = __unmap_and_move(page, newpage, force, mode);
if (rc == MIGRATEPAGE_SUCCESS)
@@ -1756,6 +1760,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
HPAGE_PMD_ORDER);
if (!new_page)
goto out_fail;
+ prep_transhuge_page(new_page);
isolated = numamigrate_isolate_page(pgdat, page);
if (!isolated) {
@@ -1767,7 +1772,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
flush_tlb_range(vma, mmun_start, mmun_end);
/* Prepare a page as a migration target */
- __set_page_locked(new_page);
+ __SetPageLocked(new_page);
SetPageSwapBacked(new_page);
/* anon mapping, we can simply copy page->mapping to the new page: */
@@ -1815,7 +1820,7 @@ fail_putback:
* guarantee the copy is visible before the pagetable update.
*/
flush_cache_range(vma, mmun_start, mmun_end);
- page_add_anon_rmap(new_page, vma, mmun_start);
+ page_add_anon_rmap(new_page, vma, mmun_start, true);
pmdp_huge_clear_flush_notify(vma, mmun_start, pmd);
set_pmd_at(mm, mmun_start, pmd, entry);
flush_tlb_range(vma, mmun_start, mmun_end);
@@ -1826,14 +1831,14 @@ fail_putback:
flush_tlb_range(vma, mmun_start, mmun_end);
mmu_notifier_invalidate_range(mm, mmun_start, mmun_end);
update_mmu_cache_pmd(vma, address, &entry);
- page_remove_rmap(new_page);
+ page_remove_rmap(new_page, true);
goto fail_putback;
}
mlock_migrate_page(new_page, page);
set_page_memcg(new_page, page_memcg(page));
set_page_memcg(page, NULL);
- page_remove_rmap(page);
+ page_remove_rmap(page, true);
spin_unlock(ptl);
mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
diff --git a/mm/mincore.c b/mm/mincore.c
index 14bb9fb37f0c..2a565ed8bb49 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -117,7 +117,7 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
unsigned char *vec = walk->private;
int nr = (end - addr) >> PAGE_SHIFT;
- if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
+ if (pmd_trans_huge_lock(pmd, vma, &ptl)) {
memset(vec, 1, nr);
spin_unlock(ptl);
goto out;
diff --git a/mm/mlock.c b/mm/mlock.c
index 339d9e0949b6..e1e2b1207bf2 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -24,13 +24,13 @@
#include "internal.h"
-int can_do_mlock(void)
+bool can_do_mlock(void)
{
if (rlimit(RLIMIT_MEMLOCK) != 0)
- return 1;
+ return true;
if (capable(CAP_IPC_LOCK))
- return 1;
- return 0;
+ return true;
+ return false;
}
EXPORT_SYMBOL(can_do_mlock);
@@ -82,6 +82,9 @@ void mlock_vma_page(struct page *page)
/* Serialize with page migration */
BUG_ON(!PageLocked(page));
+ VM_BUG_ON_PAGE(PageTail(page), page);
+ VM_BUG_ON_PAGE(PageCompound(page) && PageDoubleMap(page), page);
+
if (!TestSetPageMlocked(page)) {
mod_zone_page_state(page_zone(page), NR_MLOCK,
hpage_nr_pages(page));
@@ -178,6 +181,8 @@ unsigned int munlock_vma_page(struct page *page)
/* For try_to_munlock() and to serialize with page migration */
BUG_ON(!PageLocked(page));
+ VM_BUG_ON_PAGE(PageTail(page), page);
+
/*
* Serialize with any parallel __split_huge_page_refcount() which
* might otherwise copy PageMlocked to part of the tail pages before
@@ -388,6 +393,13 @@ static unsigned long __munlock_pagevec_fill(struct pagevec *pvec,
if (!page || page_zone_id(page) != zoneid)
break;
+ /*
+ * Do not use pagevec for PTE-mapped THP,
+ * munlock_vma_pages_range() will handle them.
+ */
+ if (PageTransCompound(page))
+ break;
+
get_page(page);
/*
* Increase the address that will be returned *before* the
@@ -425,7 +437,7 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
vma->vm_flags &= VM_LOCKED_CLEAR_MASK;
while (start < end) {
- struct page *page = NULL;
+ struct page *page;
unsigned int page_mask;
unsigned long page_increm;
struct pagevec pvec;
@@ -444,7 +456,10 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
&page_mask);
if (page && !IS_ERR(page)) {
- if (PageTransHuge(page)) {
+ if (PageTransTail(page)) {
+ VM_BUG_ON_PAGE(PageMlocked(page), page);
+ put_page(page); /* follow_page_mask() */
+ } else if (PageTransHuge(page)) {
lock_page(page);
/*
* Any THP page found by follow_page_mask() may
@@ -477,8 +492,6 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
goto next;
}
}
- /* It's a bug to munlock in the middle of a THP page */
- VM_BUG_ON((start >> PAGE_SHIFT) & page_mask);
page_increm = 1 + page_mask;
start += page_increm * PAGE_SIZE;
next:
diff --git a/mm/mmap.c b/mm/mmap.c
index 2ce04a649f6b..84b12624ceb0 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -58,6 +58,18 @@
#define arch_rebalance_pgtables(addr, len) (addr)
#endif
+#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS
+const int mmap_rnd_bits_min = CONFIG_ARCH_MMAP_RND_BITS_MIN;
+const int mmap_rnd_bits_max = CONFIG_ARCH_MMAP_RND_BITS_MAX;
+int mmap_rnd_bits __read_mostly = CONFIG_ARCH_MMAP_RND_BITS;
+#endif
+#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
+const int mmap_rnd_compat_bits_min = CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN;
+const int mmap_rnd_compat_bits_max = CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX;
+int mmap_rnd_compat_bits __read_mostly = CONFIG_ARCH_MMAP_RND_COMPAT_BITS;
+#endif
+
+
static void unmap_region(struct mm_struct *mm,
struct vm_area_struct *vma, struct vm_area_struct *prev,
unsigned long start, unsigned long end);
@@ -1208,24 +1220,6 @@ none:
return NULL;
}
-#ifdef CONFIG_PROC_FS
-void vm_stat_account(struct mm_struct *mm, unsigned long flags,
- struct file *file, long pages)
-{
- const unsigned long stack_flags
- = VM_STACK_FLAGS & (VM_GROWSUP|VM_GROWSDOWN);
-
- mm->total_vm += pages;
-
- if (file) {
- mm->shared_vm += pages;
- if ((flags & (VM_EXEC|VM_WRITE)) == VM_EXEC)
- mm->exec_vm += pages;
- } else if (flags & stack_flags)
- mm->stack_vm += pages;
-}
-#endif /* CONFIG_PROC_FS */
-
/*
* If a hint addr is less than mmap_min_addr change hint to be as
* low as possible but still greater than mmap_min_addr
@@ -1544,19 +1538,17 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long charged = 0;
/* Check against address space limit. */
- if (!may_expand_vm(mm, len >> PAGE_SHIFT)) {
+ if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) {
unsigned long nr_pages;
/*
* MAP_FIXED may remove pages of mappings that intersects with
* requested mapping. Account for the pages it would unmap.
*/
- if (!(vm_flags & MAP_FIXED))
- return -ENOMEM;
-
nr_pages = count_vma_pages_range(mm, addr, addr + len);
- if (!may_expand_vm(mm, (len >> PAGE_SHIFT) - nr_pages))
+ if (!may_expand_vm(mm, vm_flags,
+ (len >> PAGE_SHIFT) - nr_pages))
return -ENOMEM;
}
@@ -1655,7 +1647,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
out:
perf_event_mmap(vma);
- vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT);
+ vm_stat_account(mm, vm_flags, len >> PAGE_SHIFT);
if (vm_flags & VM_LOCKED) {
if (!((vm_flags & VM_SPECIAL) || is_vm_hugetlb_page(vma) ||
vma == get_gate_vma(current->mm)))
@@ -2102,7 +2094,7 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
unsigned long new_start, actual_size;
/* address space limit tests */
- if (!may_expand_vm(mm, grow))
+ if (!may_expand_vm(mm, vma->vm_flags, grow))
return -ENOMEM;
/* Stack limit test */
@@ -2199,8 +2191,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
spin_lock(&mm->page_table_lock);
if (vma->vm_flags & VM_LOCKED)
mm->locked_vm += grow;
- vm_stat_account(mm, vma->vm_flags,
- vma->vm_file, grow);
+ vm_stat_account(mm, vma->vm_flags, grow);
anon_vma_interval_tree_pre_update_vma(vma);
vma->vm_end = address;
anon_vma_interval_tree_post_update_vma(vma);
@@ -2275,8 +2266,7 @@ int expand_downwards(struct vm_area_struct *vma,
spin_lock(&mm->page_table_lock);
if (vma->vm_flags & VM_LOCKED)
mm->locked_vm += grow;
- vm_stat_account(mm, vma->vm_flags,
- vma->vm_file, grow);
+ vm_stat_account(mm, vma->vm_flags, grow);
anon_vma_interval_tree_pre_update_vma(vma);
vma->vm_start = address;
vma->vm_pgoff -= grow;
@@ -2390,7 +2380,7 @@ static void remove_vma_list(struct mm_struct *mm, struct vm_area_struct *vma)
if (vma->vm_flags & VM_ACCOUNT)
nr_accounted += nrpages;
- vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages);
+ vm_stat_account(mm, vma->vm_flags, -nrpages);
vma = remove_vma(vma);
} while (vma);
vm_unacct_memory(nr_accounted);
@@ -2760,7 +2750,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len)
}
/* Check against address space limits *after* clearing old maps... */
- if (!may_expand_vm(mm, len >> PAGE_SHIFT))
+ if (!may_expand_vm(mm, flags, len >> PAGE_SHIFT))
return -ENOMEM;
if (mm->map_count > sysctl_max_map_count)
@@ -2795,6 +2785,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len)
out:
perf_event_mmap(vma);
mm->total_vm += len >> PAGE_SHIFT;
+ mm->data_vm += len >> PAGE_SHIFT;
if (flags & VM_LOCKED)
mm->locked_vm += (len >> PAGE_SHIFT);
vma->vm_flags |= VM_SOFTDIRTY;
@@ -2986,16 +2977,28 @@ out:
* Return true if the calling process may expand its vm space by the passed
* number of pages
*/
-int may_expand_vm(struct mm_struct *mm, unsigned long npages)
+bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
{
- unsigned long cur = mm->total_vm; /* pages */
- unsigned long lim;
+ if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT)
+ return false;
- lim = rlimit(RLIMIT_AS) >> PAGE_SHIFT;
+ if ((flags & (VM_WRITE | VM_SHARED | (VM_STACK_FLAGS &
+ (VM_GROWSUP | VM_GROWSDOWN)))) == VM_WRITE)
+ return mm->data_vm + npages <= rlimit(RLIMIT_DATA);
- if (cur + npages > lim)
- return 0;
- return 1;
+ return true;
+}
+
+void vm_stat_account(struct mm_struct *mm, vm_flags_t flags, long npages)
+{
+ mm->total_vm += npages;
+
+ if ((flags & (VM_EXEC | VM_WRITE)) == VM_EXEC)
+ mm->exec_vm += npages;
+ else if (flags & (VM_STACK_FLAGS & (VM_GROWSUP | VM_GROWSDOWN)))
+ mm->stack_vm += npages;
+ else if ((flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
+ mm->data_vm += npages;
}
static int special_mapping_fault(struct vm_area_struct *vma,
@@ -3077,7 +3080,7 @@ static struct vm_area_struct *__install_special_mapping(
if (ret)
goto out;
- mm->total_vm += len >> PAGE_SHIFT;
+ vm_stat_account(mm, vma->vm_flags, len >> PAGE_SHIFT);
perf_event_mmap(vma);
@@ -3181,10 +3184,16 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
* mapping->flags avoid to take the same lock twice, if more than one
* vma in this mm is backed by the same anon_vma or address_space.
*
- * We can take all the locks in random order because the VM code
- * taking i_mmap_rwsem or anon_vma->rwsem outside the mmap_sem never
- * takes more than one of them in a row. Secondly we're protected
- * against a concurrent mm_take_all_locks() by the mm_all_locks_mutex.
+ * We take locks in following order, accordingly to comment at beginning
+ * of mm/rmap.c:
+ * - all hugetlbfs_i_mmap_rwsem_key locks (aka mapping->i_mmap_rwsem for
+ * hugetlb mapping);
+ * - all i_mmap_rwsem locks;
+ * - all anon_vma->rwseml
+ *
+ * We can take all locks within these types randomly because the VM code
+ * doesn't nest them and we protected from parallel mm_take_all_locks() by
+ * mm_all_locks_mutex.
*
* mm_take_all_locks() and mm_drop_all_locks are expensive operations
* that may have to take thousand of locks.
@@ -3203,7 +3212,16 @@ int mm_take_all_locks(struct mm_struct *mm)
for (vma = mm->mmap; vma; vma = vma->vm_next) {
if (signal_pending(current))
goto out_unlock;
- if (vma->vm_file && vma->vm_file->f_mapping)
+ if (vma->vm_file && vma->vm_file->f_mapping &&
+ is_vm_hugetlb_page(vma))
+ vm_lock_mapping(mm, vma->vm_file->f_mapping);
+ }
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (signal_pending(current))
+ goto out_unlock;
+ if (vma->vm_file && vma->vm_file->f_mapping &&
+ !is_vm_hugetlb_page(vma))
vm_lock_mapping(mm, vma->vm_file->f_mapping);
}
diff --git a/mm/mmzone.c b/mm/mmzone.c
index 7d87ebb0d632..52687fb4de6f 100644
--- a/mm/mmzone.c
+++ b/mm/mmzone.c
@@ -72,16 +72,16 @@ struct zoneref *next_zones_zonelist(struct zoneref *z,
}
#ifdef CONFIG_ARCH_HAS_HOLES_MEMORYMODEL
-int memmap_valid_within(unsigned long pfn,
+bool memmap_valid_within(unsigned long pfn,
struct page *page, struct zone *zone)
{
if (page_to_pfn(page) != pfn)
- return 0;
+ return false;
if (page_zone(page) != zone)
- return 0;
+ return false;
- return 1;
+ return true;
}
#endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */
diff --git a/mm/mprotect.c b/mm/mprotect.c
index ef5be8eaab00..8eb7bb40dc40 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -149,7 +149,8 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
unsigned long this_pages;
next = pmd_addr_end(addr, end);
- if (!pmd_trans_huge(*pmd) && pmd_none_or_clear_bad(pmd))
+ if (!pmd_trans_huge(*pmd) && !pmd_devmap(*pmd)
+ && pmd_none_or_clear_bad(pmd))
continue;
/* invoke the mmu notifier if the pmd is populated */
@@ -158,9 +159,9 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
mmu_notifier_invalidate_range_start(mm, mni_start, end);
}
- if (pmd_trans_huge(*pmd)) {
+ if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) {
if (next - addr != HPAGE_PMD_SIZE)
- split_huge_page_pmd(vma, addr, pmd);
+ split_huge_pmd(vma, pmd, addr);
else {
int nr_ptes = change_huge_pmd(vma, pmd, addr,
newprot, prot_numa);
@@ -278,6 +279,10 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
* even if read-only so there is no need to account for them here
*/
if (newflags & VM_WRITE) {
+ /* Check space limits when area turns into data. */
+ if (!may_expand_vm(mm, newflags, nrpages) &&
+ may_expand_vm(mm, oldflags, nrpages))
+ return -ENOMEM;
if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_HUGETLB|
VM_SHARED|VM_NORESERVE))) {
charged = nrpages;
@@ -334,8 +339,8 @@ success:
populate_vma_page_range(vma, start, end, NULL);
}
- vm_stat_account(mm, oldflags, vma->vm_file, -nrpages);
- vm_stat_account(mm, newflags, vma->vm_file, nrpages);
+ vm_stat_account(mm, oldflags, -nrpages);
+ vm_stat_account(mm, newflags, nrpages);
perf_event_mmap(vma);
return 0;
diff --git a/mm/mremap.c b/mm/mremap.c
index de824e72c3e8..d77946a997f7 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -192,25 +192,24 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
if (!new_pmd)
break;
if (pmd_trans_huge(*old_pmd)) {
- int err = 0;
if (extent == HPAGE_PMD_SIZE) {
+ bool moved;
VM_BUG_ON_VMA(vma->vm_file || !vma->anon_vma,
vma);
/* See comment in move_ptes() */
if (need_rmap_locks)
anon_vma_lock_write(vma->anon_vma);
- err = move_huge_pmd(vma, new_vma, old_addr,
+ moved = move_huge_pmd(vma, new_vma, old_addr,
new_addr, old_end,
old_pmd, new_pmd);
if (need_rmap_locks)
anon_vma_unlock_write(vma->anon_vma);
+ if (moved) {
+ need_flush = true;
+ continue;
+ }
}
- if (err > 0) {
- need_flush = true;
- continue;
- } else if (!err) {
- split_huge_page_pmd(vma, old_addr, old_pmd);
- }
+ split_huge_pmd(vma, old_pmd, old_addr);
VM_BUG_ON(pmd_trans_huge(*old_pmd));
}
if (pmd_none(*new_pmd) && __pte_alloc(new_vma->vm_mm, new_vma,
@@ -317,7 +316,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
* If this were a serious issue, we'd add a flag to do_munmap().
*/
hiwater_vm = mm->hiwater_vm;
- vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT);
+ vm_stat_account(mm, vma->vm_flags, new_len >> PAGE_SHIFT);
/* Tell pfnmap has moved from this vma */
if (unlikely(vma->vm_flags & VM_PFNMAP))
@@ -383,7 +382,8 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
return ERR_PTR(-EAGAIN);
}
- if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT))
+ if (!may_expand_vm(mm, vma->vm_flags,
+ (new_len - old_len) >> PAGE_SHIFT))
return ERR_PTR(-ENOMEM);
if (vma->vm_flags & VM_ACCOUNT) {
@@ -545,7 +545,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
goto out;
}
- vm_stat_account(mm, vma->vm_flags, vma->vm_file, pages);
+ vm_stat_account(mm, vma->vm_flags, pages);
if (vma->vm_flags & VM_LOCKED) {
mm->locked_vm += pages;
locked = true;
diff --git a/mm/nommu.c b/mm/nommu.c
index 92be862c859b..fbf6f0f1d6c9 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -560,7 +560,7 @@ void __init mmap_init(void)
ret = percpu_counter_init(&vm_committed_as, 0, GFP_KERNEL);
VM_BUG_ON(ret);
- vm_region_jar = KMEM_CACHE(vm_region, SLAB_PANIC);
+ vm_region_jar = KMEM_CACHE(vm_region, SLAB_PANIC|SLAB_ACCOUNT);
}
/*
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index c12680993ff3..dc490c06941b 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -585,10 +585,11 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
*/
do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);
mark_oom_victim(victim);
- pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",
+ pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
task_pid_nr(victim), victim->comm, K(victim->mm->total_vm),
K(get_mm_counter(victim->mm, MM_ANONPAGES)),
- K(get_mm_counter(victim->mm, MM_FILEPAGES)));
+ K(get_mm_counter(victim->mm, MM_FILEPAGES)),
+ K(get_mm_counter(victim->mm, MM_SHMEMPAGES)));
task_unlock(victim);
/*
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index d15d88c8efa1..6fe7d15bd1f7 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -278,7 +278,12 @@ static unsigned long zone_dirtyable_memory(struct zone *zone)
unsigned long nr_pages;
nr_pages = zone_page_state(zone, NR_FREE_PAGES);
- nr_pages -= min(nr_pages, zone->dirty_balance_reserve);
+ /*
+ * Pages reserved for the kernel should not be considered
+ * dirtyable, to prevent a situation where reclaim has to
+ * clean pages in order to balance the zones.
+ */
+ nr_pages -= min(nr_pages, zone->totalreserve_pages);
nr_pages += zone_page_state(zone, NR_INACTIVE_FILE);
nr_pages += zone_page_state(zone, NR_ACTIVE_FILE);
@@ -332,7 +337,12 @@ static unsigned long global_dirtyable_memory(void)
unsigned long x;
x = global_page_state(NR_FREE_PAGES);
- x -= min(x, dirty_balance_reserve);
+ /*
+ * Pages reserved for the kernel should not be considered
+ * dirtyable, to prevent a situation where reclaim has to
+ * clean pages in order to balance the zones.
+ */
+ x -= min(x, totalreserve_pages);
x += global_page_state(NR_INACTIVE_FILE);
x += global_page_state(NR_ACTIVE_FILE);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9d666df5ef95..63358d9f9aa9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -43,6 +43,7 @@
#include <linux/vmalloc.h>
#include <linux/vmstat.h>
#include <linux/mempolicy.h>
+#include <linux/memremap.h>
#include <linux/stop_machine.h>
#include <linux/sort.h>
#include <linux/pfn.h>
@@ -114,13 +115,6 @@ static DEFINE_SPINLOCK(managed_page_count_lock);
unsigned long totalram_pages __read_mostly;
unsigned long totalreserve_pages __read_mostly;
unsigned long totalcma_pages __read_mostly;
-/*
- * When calculating the number of globally allowed dirty pages, there
- * is a certain number of per-zone reserves that should not be
- * considered dirtyable memory. This is the sum of those reserves
- * over all existing zones that contribute dirtyable memory.
- */
-unsigned long dirty_balance_reserve __read_mostly;
int percpu_pagelist_fraction;
gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
@@ -229,13 +223,15 @@ static char * const zone_names[MAX_NR_ZONES] = {
#endif
};
-static void free_compound_page(struct page *page);
compound_page_dtor * const compound_page_dtors[] = {
NULL,
free_compound_page,
#ifdef CONFIG_HUGETLB_PAGE
free_huge_page,
#endif
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ free_transhuge_page,
+#endif
};
int min_free_kbytes = 1024;
@@ -457,7 +453,7 @@ out:
* This usage means that zero-order pages may not be compound.
*/
-static void free_compound_page(struct page *page)
+void free_compound_page(struct page *page)
{
__free_pages_ok(page, compound_order(page));
}
@@ -473,8 +469,10 @@ void prep_compound_page(struct page *page, unsigned int order)
for (i = 1; i < nr_pages; i++) {
struct page *p = page + i;
set_page_count(p, 0);
+ p->mapping = TAIL_MAPPING;
set_compound_head(p, page);
}
+ atomic_set(compound_mapcount_ptr(page), -1);
}
#ifdef CONFIG_DEBUG_PAGEALLOC
@@ -739,7 +737,7 @@ static inline int free_pages_check(struct page *page)
const char *bad_reason = NULL;
unsigned long bad_flags = 0;
- if (unlikely(page_mapcount(page)))
+ if (unlikely(atomic_read(&page->_mapcount) != -1))
bad_reason = "nonzero mapcount";
if (unlikely(page->mapping != NULL))
bad_reason = "non-NULL mapping";
@@ -812,7 +810,7 @@ static void free_pcppages_bulk(struct zone *zone, int count,
do {
int mt; /* migratetype of the to-be-freed page */
- page = list_entry(list->prev, struct page, lru);
+ page = list_last_entry(list, struct page, lru);
/* must delete as __free_one_page list manipulates */
list_del(&page->lru);
@@ -863,6 +861,27 @@ static int free_tail_pages_check(struct page *head_page, struct page *page)
ret = 0;
goto out;
}
+ switch (page - head_page) {
+ case 1:
+ /* the first tail page: ->mapping is compound_mapcount() */
+ if (unlikely(compound_mapcount(page))) {
+ bad_page(page, "nonzero compound_mapcount", 0);
+ goto out;
+ }
+ break;
+ case 2:
+ /*
+ * the second tail page: ->mapping is
+ * page_deferred_list().next -- ignore value.
+ */
+ break;
+ default:
+ if (page->mapping != TAIL_MAPPING) {
+ bad_page(page, "corrupted mapping in tail page", 0);
+ goto out;
+ }
+ break;
+ }
if (unlikely(!PageTail(page))) {
bad_page(page, "PageTail not set", 0);
goto out;
@@ -873,6 +892,7 @@ static int free_tail_pages_check(struct page *head_page, struct page *page)
}
ret = 0;
out:
+ page->mapping = NULL;
clear_compound_head(page);
return ret;
}
@@ -1336,7 +1356,7 @@ static inline int check_new_page(struct page *page)
const char *bad_reason = NULL;
unsigned long bad_flags = 0;
- if (unlikely(page_mapcount(page)))
+ if (unlikely(atomic_read(&page->_mapcount) != -1))
bad_reason = "nonzero mapcount";
if (unlikely(page->mapping != NULL))
bad_reason = "non-NULL mapping";
@@ -1417,11 +1437,10 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
/* Find a page of the appropriate size in the preferred list */
for (current_order = order; current_order < MAX_ORDER; ++current_order) {
area = &(zone->free_area[current_order]);
- if (list_empty(&area->free_list[migratetype]))
- continue;
-
- page = list_entry(area->free_list[migratetype].next,
+ page = list_first_entry_or_null(&area->free_list[migratetype],
struct page, lru);
+ if (!page)
+ continue;
list_del(&page->lru);
rmv_page_order(page);
area->nr_free--;
@@ -1700,12 +1719,12 @@ static void unreserve_highatomic_pageblock(const struct alloc_context *ac)
for (order = 0; order < MAX_ORDER; order++) {
struct free_area *area = &(zone->free_area[order]);
- if (list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
+ page = list_first_entry_or_null(
+ &area->free_list[MIGRATE_HIGHATOMIC],
+ struct page, lru);
+ if (!page)
continue;
- page = list_entry(area->free_list[MIGRATE_HIGHATOMIC].next,
- struct page, lru);
-
/*
* It should never happen but changes to locking could
* inadvertently allow a per-cpu drain to add pages
@@ -1753,7 +1772,7 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)
if (fallback_mt == -1)
continue;
- page = list_entry(area->free_list[fallback_mt].next,
+ page = list_first_entry(&area->free_list[fallback_mt],
struct page, lru);
if (can_steal)
steal_suitable_fallback(zone, page, start_migratetype);
@@ -1788,7 +1807,7 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)
* Call me with the zone->lock already held.
*/
static struct page *__rmqueue(struct zone *zone, unsigned int order,
- int migratetype, gfp_t gfp_flags)
+ int migratetype)
{
struct page *page;
@@ -1818,7 +1837,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
spin_lock(&zone->lock);
for (i = 0; i < count; ++i) {
- struct page *page = __rmqueue(zone, order, migratetype, 0);
+ struct page *page = __rmqueue(zone, order, migratetype);
if (unlikely(page == NULL))
break;
@@ -1988,7 +2007,7 @@ void mark_free_pages(struct zone *zone)
unsigned long pfn, max_zone_pfn;
unsigned long flags;
unsigned int order, t;
- struct list_head *curr;
+ struct page *page;
if (zone_is_empty(zone))
return;
@@ -1998,17 +2017,17 @@ void mark_free_pages(struct zone *zone)
max_zone_pfn = zone_end_pfn(zone);
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
if (pfn_valid(pfn)) {
- struct page *page = pfn_to_page(pfn);
-
+ page = pfn_to_page(pfn);
if (!swsusp_page_is_forbidden(page))
swsusp_unset_page_free(page);
}
for_each_migratetype_order(order, t) {
- list_for_each(curr, &zone->free_area[order].free_list[t]) {
+ list_for_each_entry(page,
+ &zone->free_area[order].free_list[t], lru) {
unsigned long i;
- pfn = page_to_pfn(list_entry(curr, struct page, lru));
+ pfn = page_to_pfn(page);
for (i = 0; i < (1UL << order); i++)
swsusp_set_page_free(pfn_to_page(pfn + i));
}
@@ -2212,9 +2231,9 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
}
if (cold)
- page = list_entry(list->prev, struct page, lru);
+ page = list_last_entry(list, struct page, lru);
else
- page = list_entry(list->next, struct page, lru);
+ page = list_first_entry(list, struct page, lru);
list_del(&page->lru);
pcp->count--;
@@ -2241,7 +2260,7 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
trace_mm_page_alloc_zone_locked(page, order, migratetype);
}
if (!page)
- page = __rmqueue(zone, order, migratetype, gfp_flags);
+ page = __rmqueue(zone, order, migratetype);
spin_unlock(&zone->lock);
if (!page)
goto failed;
@@ -2740,8 +2759,21 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
goto out;
}
/* Exhausted what can be done so it's blamo time */
- if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL))
+ if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) {
*did_some_progress = 1;
+
+ if (gfp_mask & __GFP_NOFAIL) {
+ page = get_page_from_freelist(gfp_mask, order,
+ ALLOC_NO_WATERMARKS|ALLOC_CPUSET, ac);
+ /*
+ * fallback to ignore cpuset restriction if our nodes
+ * are depleted
+ */
+ if (!page)
+ page = get_page_from_freelist(gfp_mask, order,
+ ALLOC_NO_WATERMARKS, ac);
+ }
+ }
out:
mutex_unlock(&oom_lock);
return page;
@@ -2876,28 +2908,6 @@ retry:
return page;
}
-/*
- * This is called in the allocator slow-path if the allocation request is of
- * sufficient urgency to ignore watermarks and take other desperate measures
- */
-static inline struct page *
-__alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
- const struct alloc_context *ac)
-{
- struct page *page;
-
- do {
- page = get_page_from_freelist(gfp_mask, order,
- ALLOC_NO_WATERMARKS, ac);
-
- if (!page && gfp_mask & __GFP_NOFAIL)
- wait_iff_congested(ac->preferred_zone, BLK_RW_ASYNC,
- HZ/50);
- } while (!page && (gfp_mask & __GFP_NOFAIL));
-
- return page;
-}
-
static void wake_all_kswapds(unsigned int order, const struct alloc_context *ac)
{
struct zoneref *z;
@@ -3042,28 +3052,36 @@ retry:
* allocations are system rather than user orientated
*/
ac->zonelist = node_zonelist(numa_node_id(), gfp_mask);
-
- page = __alloc_pages_high_priority(gfp_mask, order, ac);
-
- if (page) {
+ page = get_page_from_freelist(gfp_mask, order,
+ ALLOC_NO_WATERMARKS, ac);
+ if (page)
goto got_pg;
- }
}
/* Caller is not willing to reclaim, we can't balance anything */
if (!can_direct_reclaim) {
/*
- * All existing users of the deprecated __GFP_NOFAIL are
- * blockable, so warn of any new users that actually allow this
- * type of allocation to fail.
+ * All existing users of the __GFP_NOFAIL are blockable, so warn
+ * of any new users that actually allow this type of allocation
+ * to fail.
*/
WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL);
goto nopage;
}
/* Avoid recursion of direct reclaim */
- if (current->flags & PF_MEMALLOC)
+ if (current->flags & PF_MEMALLOC) {
+ /*
+ * __GFP_NOFAIL request from this context is rather bizarre
+ * because we cannot reclaim anything and only can loop waiting
+ * for somebody to do a work for us.
+ */
+ if (WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) {
+ cond_resched();
+ goto retry;
+ }
goto nopage;
+ }
/* Avoid allocations with no watermarks from looping endlessly */
if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL))
@@ -3402,7 +3420,8 @@ EXPORT_SYMBOL(__free_page_frag);
/*
* alloc_kmem_pages charges newly allocated pages to the kmem resource counter
- * of the current memory cgroup.
+ * of the current memory cgroup if __GFP_ACCOUNT is set, other than that it is
+ * equivalent to alloc_pages.
*
* It should be used when the caller would like to use kmalloc, but since the
* allocation is large, it has to fall back to the page allocator.
@@ -4147,8 +4166,7 @@ static void set_zonelist_order(void)
static void build_zonelists(pg_data_t *pgdat)
{
- int j, node, load;
- enum zone_type i;
+ int i, node, load;
nodemask_t used_mask;
int local_node, prev_node;
struct zonelist *zonelist;
@@ -4168,7 +4186,7 @@ static void build_zonelists(pg_data_t *pgdat)
nodes_clear(used_mask);
memset(node_order, 0, sizeof(node_order));
- j = 0;
+ i = 0;
while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
/*
@@ -4185,12 +4203,12 @@ static void build_zonelists(pg_data_t *pgdat)
if (order == ZONELIST_ORDER_NODE)
build_zonelists_in_node_order(pgdat, node);
else
- node_order[j++] = node; /* remember order */
+ node_order[i++] = node; /* remember order */
}
if (order == ZONELIST_ORDER_ZONE) {
/* calculate node order -- i.e., DMA last! */
- build_zonelists_in_zone_order(pgdat, j);
+ build_zonelists_in_zone_order(pgdat, i);
}
build_thisnode_zonelists(pgdat);
@@ -4468,16 +4486,22 @@ static inline unsigned long wait_table_bits(unsigned long size)
void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
unsigned long start_pfn, enum memmap_context context)
{
- pg_data_t *pgdat = NODE_DATA(nid);
+ struct vmem_altmap *altmap = to_vmem_altmap(__pfn_to_phys(start_pfn));
unsigned long end_pfn = start_pfn + size;
+ pg_data_t *pgdat = NODE_DATA(nid);
unsigned long pfn;
- struct zone *z;
unsigned long nr_initialised = 0;
if (highest_memmap_pfn < end_pfn - 1)
highest_memmap_pfn = end_pfn - 1;
- z = &pgdat->node_zones[zone];
+ /*
+ * Honor reservation requested by the driver for this ZONE_DEVICE
+ * memory
+ */
+ if (altmap && start_pfn == altmap->base_pfn)
+ start_pfn += altmap->reserve;
+
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
/*
* There can be holes in boot-time mem_map[]s
@@ -5956,20 +5980,12 @@ static void calculate_totalreserve_pages(void)
if (max > zone->managed_pages)
max = zone->managed_pages;
+
+ zone->totalreserve_pages = max;
+
reserve_pages += max;
- /*
- * Lowmem reserves are not available to
- * GFP_HIGHUSER page cache allocations and
- * kswapd tries to balance zones to their high
- * watermark. As a result, neither should be
- * regarded as dirtyable memory, to prevent a
- * situation where reclaim has to clean pages
- * in order to balance the zones.
- */
- zone->dirty_balance_reserve = max;
}
}
- dirty_balance_reserve = reserve_pages;
totalreserve_pages = reserve_pages;
}
@@ -6724,8 +6740,12 @@ int alloc_contig_range(unsigned long start, unsigned long end,
if (ret)
return ret;
+ /*
+ * In case of -EBUSY, we'd like to know which page causes problem.
+ * So, just fall through. We will check it in test_pages_isolated().
+ */
ret = __alloc_contig_migrate_range(&cc, start, end);
- if (ret)
+ if (ret && ret != -EBUSY)
goto done;
/*
@@ -6752,12 +6772,25 @@ int alloc_contig_range(unsigned long start, unsigned long end,
outer_start = start;
while (!PageBuddy(pfn_to_page(outer_start))) {
if (++order >= MAX_ORDER) {
- ret = -EBUSY;
- goto done;
+ outer_start = start;
+ break;
}
outer_start &= ~0UL << order;
}
+ if (outer_start != start) {
+ order = page_order(pfn_to_page(outer_start));
+
+ /*
+ * outer_start page could be small order buddy page and
+ * it doesn't include start page. Adjust outer_start
+ * in this case to report failed page properly
+ * on tracepoint in test_pages_isolated()
+ */
+ if (outer_start + (1UL << order) <= start)
+ outer_start = start;
+ }
+
/* Make sure the range is really isolated. */
if (test_pages_isolated(outer_start, end, false)) {
pr_info("%s: [%lx, %lx) PFNs busy\n",
diff --git a/mm/page_idle.c b/mm/page_idle.c
index d5dd79041484..4ea9c4ef5146 100644
--- a/mm/page_idle.c
+++ b/mm/page_idle.c
@@ -55,25 +55,26 @@ static int page_idle_clear_pte_refs_one(struct page *page,
unsigned long addr, void *arg)
{
struct mm_struct *mm = vma->vm_mm;
- spinlock_t *ptl;
pmd_t *pmd;
pte_t *pte;
+ spinlock_t *ptl;
bool referenced = false;
- if (unlikely(PageTransHuge(page))) {
- pmd = page_check_address_pmd(page, mm, addr,
- PAGE_CHECK_ADDRESS_PMD_FLAG, &ptl);
- if (pmd) {
- referenced = pmdp_clear_young_notify(vma, addr, pmd);
- spin_unlock(ptl);
- }
+ if (!page_check_address_transhuge(page, mm, addr, &pmd, &pte, &ptl))
+ return SWAP_AGAIN;
+
+ if (pte) {
+ referenced = ptep_clear_young_notify(vma, addr, pte);
+ pte_unmap(pte);
+ } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
+ referenced = pmdp_clear_young_notify(vma, addr, pmd);
} else {
- pte = page_check_address(page, mm, addr, &ptl, 0);
- if (pte) {
- referenced = ptep_clear_young_notify(vma, addr, pte);
- pte_unmap_unlock(pte, ptl);
- }
+ /* unexpected pmd-mapped page? */
+ WARN_ON_ONCE(1);
}
+
+ spin_unlock(ptl);
+
if (referenced) {
clear_page_idle(page);
/*
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 4568fd58f70a..92c4c36501e7 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -9,6 +9,9 @@
#include <linux/hugetlb.h>
#include "internal.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/page_isolation.h>
+
static int set_migratetype_isolate(struct page *page,
bool skip_hwpoisoned_pages)
{
@@ -162,8 +165,8 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
unsigned long undo_pfn;
struct page *page;
- BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
- BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
+ BUG_ON(!IS_ALIGNED(start_pfn, pageblock_nr_pages));
+ BUG_ON(!IS_ALIGNED(end_pfn, pageblock_nr_pages));
for (pfn = start_pfn;
pfn < end_pfn;
@@ -193,8 +196,10 @@ int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
{
unsigned long pfn;
struct page *page;
- BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
- BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
+
+ BUG_ON(!IS_ALIGNED(start_pfn, pageblock_nr_pages));
+ BUG_ON(!IS_ALIGNED(end_pfn, pageblock_nr_pages));
+
for (pfn = start_pfn;
pfn < end_pfn;
pfn += pageblock_nr_pages) {
@@ -212,7 +217,7 @@ int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
*
* Returns 1 if all pages in the range are isolated.
*/
-static int
+static unsigned long
__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
bool skip_hwpoisoned_pages)
{
@@ -237,9 +242,8 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
else
break;
}
- if (pfn < end_pfn)
- return 0;
- return 1;
+
+ return pfn;
}
int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
@@ -248,7 +252,6 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
unsigned long pfn, flags;
struct page *page;
struct zone *zone;
- int ret;
/*
* Note: pageblock_nr_pages != MAX_ORDER. Then, chunks of free pages
@@ -266,10 +269,13 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
/* Check all pages are free or marked as ISOLATED */
zone = page_zone(page);
spin_lock_irqsave(&zone->lock, flags);
- ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn,
+ pfn = __test_page_isolated_in_pageblock(start_pfn, end_pfn,
skip_hwpoisoned_pages);
spin_unlock_irqrestore(&zone->lock, flags);
- return ret ? 0 : -EBUSY;
+
+ trace_test_pages_isolated(start_pfn, end_pfn, pfn);
+
+ return pfn < end_pfn ? -EBUSY : 0;
}
struct page *alloc_migrate_target(struct page *page, unsigned long private,
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 29f2f8b853ae..207244489a68 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -58,7 +58,7 @@ again:
if (!walk->pte_entry)
continue;
- split_huge_page_pmd_mm(walk->mm, addr, pmd);
+ split_huge_pmd(walk->vma, pmd, addr);
if (pmd_trans_unstable(pmd))
goto again;
err = walk_pte_range(pmd, addr, next, walk);
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index 7d3db0247983..9d4767698a1c 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -132,25 +132,13 @@ pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address,
{
pmd_t pmd;
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
- VM_BUG_ON(!pmd_trans_huge(*pmdp));
+ VM_BUG_ON(!pmd_trans_huge(*pmdp) && !pmd_devmap(*pmdp));
pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
return pmd;
}
#endif
-#ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp)
-{
- pmd_t pmd = pmd_mksplitting(*pmdp);
- VM_BUG_ON(address & ~HPAGE_PMD_MASK);
- set_pmd_at(vma->vm_mm, address, pmdp, pmd);
- /* tlb flush only to serialize against gup-fast */
- flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
-}
-#endif
-
#ifndef __HAVE_ARCH_PGTABLE_DEPOSIT
void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
pgtable_t pgtable)
@@ -176,13 +164,10 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
/* FIFO */
pgtable = pmd_huge_pte(mm, pmdp);
- if (list_empty(&pgtable->lru))
- pmd_huge_pte(mm, pmdp) = NULL;
- else {
- pmd_huge_pte(mm, pmdp) = list_entry(pgtable->lru.next,
- struct page, lru);
+ pmd_huge_pte(mm, pmdp) = list_first_entry_or_null(&pgtable->lru,
+ struct page, lru);
+ if (pmd_huge_pte(mm, pmdp))
list_del(&pgtable->lru);
- }
return pgtable;
}
#endif
diff --git a/mm/readahead.c b/mm/readahead.c
index ba22d7fe0afb..20e58e820e44 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -17,6 +17,7 @@
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/file.h>
+#include <linux/mm_inline.h>
#include "internal.h"
@@ -32,8 +33,6 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
}
EXPORT_SYMBOL_GPL(file_ra_state_init);
-#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
-
/*
* see if a page needs releasing upon read_cache_pages() failure
* - the caller of read_cache_pages() may have set PG_private or PG_fscache
@@ -64,7 +63,7 @@ static void read_cache_pages_invalidate_pages(struct address_space *mapping,
struct page *victim;
while (!list_empty(pages)) {
- victim = list_to_page(pages);
+ victim = lru_to_page(pages);
list_del(&victim->lru);
read_cache_pages_invalidate_page(mapping, victim);
}
@@ -87,7 +86,7 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages,
int ret = 0;
while (!list_empty(pages)) {
- page = list_to_page(pages);
+ page = lru_to_page(pages);
list_del(&page->lru);
if (add_to_page_cache_lru(page, mapping, page->index,
mapping_gfp_constraint(mapping, GFP_KERNEL))) {
@@ -125,7 +124,7 @@ static int read_pages(struct address_space *mapping, struct file *filp,
}
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
- struct page *page = list_to_page(pages);
+ struct page *page = lru_to_page(pages);
list_del(&page->lru);
if (!add_to_page_cache_lru(page, mapping, page->index,
mapping_gfp_constraint(mapping, GFP_KERNEL))) {
diff --git a/mm/rmap.c b/mm/rmap.c
index b577fbb98d4b..79f3bf047f38 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -23,21 +23,22 @@
* inode->i_mutex (while writing or truncating, not reading or faulting)
* mm->mmap_sem
* page->flags PG_locked (lock_page)
- * mapping->i_mmap_rwsem
- * anon_vma->rwsem
- * mm->page_table_lock or pte_lock
- * zone->lru_lock (in mark_page_accessed, isolate_lru_page)
- * swap_lock (in swap_duplicate, swap_info_get)
- * mmlist_lock (in mmput, drain_mmlist and others)
- * mapping->private_lock (in __set_page_dirty_buffers)
- * mem_cgroup_{begin,end}_page_stat (memcg->move_lock)
- * mapping->tree_lock (widely used)
- * inode->i_lock (in set_page_dirty's __mark_inode_dirty)
- * bdi.wb->list_lock (in set_page_dirty's __mark_inode_dirty)
- * sb_lock (within inode_lock in fs/fs-writeback.c)
- * mapping->tree_lock (widely used, in set_page_dirty,
- * in arch-dependent flush_dcache_mmap_lock,
- * within bdi.wb->list_lock in __sync_single_inode)
+ * hugetlbfs_i_mmap_rwsem_key (in huge_pmd_share)
+ * mapping->i_mmap_rwsem
+ * anon_vma->rwsem
+ * mm->page_table_lock or pte_lock
+ * zone->lru_lock (in mark_page_accessed, isolate_lru_page)
+ * swap_lock (in swap_duplicate, swap_info_get)
+ * mmlist_lock (in mmput, drain_mmlist and others)
+ * mapping->private_lock (in __set_page_dirty_buffers)
+ * mem_cgroup_{begin,end}_page_stat (memcg->move_lock)
+ * mapping->tree_lock (widely used)
+ * inode->i_lock (in set_page_dirty's __mark_inode_dirty)
+ * bdi.wb->list_lock (in set_page_dirty's __mark_inode_dirty)
+ * sb_lock (within inode_lock in fs/fs-writeback.c)
+ * mapping->tree_lock (widely used, in set_page_dirty,
+ * in arch-dependent flush_dcache_mmap_lock,
+ * within bdi.wb->list_lock in __sync_single_inode)
*
* anon_vma->rwsem,mapping->i_mutex (memory_failure, collect_procs_anon)
* ->tasklist_lock
@@ -428,8 +429,10 @@ static void anon_vma_ctor(void *data)
void __init anon_vma_init(void)
{
anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma),
- 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor);
- anon_vma_chain_cachep = KMEM_CACHE(anon_vma_chain, SLAB_PANIC);
+ 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC|SLAB_ACCOUNT,
+ anon_vma_ctor);
+ anon_vma_chain_cachep = KMEM_CACHE(anon_vma_chain,
+ SLAB_PANIC|SLAB_ACCOUNT);
}
/*
@@ -565,27 +568,6 @@ void page_unlock_anon_vma_read(struct anon_vma *anon_vma)
anon_vma_unlock_read(anon_vma);
}
-/*
- * At what user virtual address is page expected in @vma?
- */
-static inline unsigned long
-__vma_address(struct page *page, struct vm_area_struct *vma)
-{
- pgoff_t pgoff = page_to_pgoff(page);
- return vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
-}
-
-inline unsigned long
-vma_address(struct page *page, struct vm_area_struct *vma)
-{
- unsigned long address = __vma_address(page, vma);
-
- /* page should be within @vma mapping range */
- VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);
-
- return address;
-}
-
#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
static void percpu_flush_tlb_batch_pages(void *data)
{
@@ -817,6 +799,96 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma)
return 1;
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+/*
+ * Check that @page is mapped at @address into @mm. In contrast to
+ * page_check_address(), this function can handle transparent huge pages.
+ *
+ * On success returns true with pte mapped and locked. For PMD-mapped
+ * transparent huge pages *@ptep is set to NULL.
+ */
+bool page_check_address_transhuge(struct page *page, struct mm_struct *mm,
+ unsigned long address, pmd_t **pmdp,
+ pte_t **ptep, spinlock_t **ptlp)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ spinlock_t *ptl;
+
+ if (unlikely(PageHuge(page))) {
+ /* when pud is not present, pte will be NULL */
+ pte = huge_pte_offset(mm, address);
+ if (!pte)
+ return false;
+
+ ptl = huge_pte_lockptr(page_hstate(page), mm, pte);
+ pmd = NULL;
+ goto check_pte;
+ }
+
+ pgd = pgd_offset(mm, address);
+ if (!pgd_present(*pgd))
+ return false;
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ return false;
+ pmd = pmd_offset(pud, address);
+
+ if (pmd_trans_huge(*pmd)) {
+ ptl = pmd_lock(mm, pmd);
+ if (!pmd_present(*pmd))
+ goto unlock_pmd;
+ if (unlikely(!pmd_trans_huge(*pmd))) {
+ spin_unlock(ptl);
+ goto map_pte;
+ }
+
+ if (pmd_page(*pmd) != page)
+ goto unlock_pmd;
+
+ pte = NULL;
+ goto found;
+unlock_pmd:
+ spin_unlock(ptl);
+ return false;
+ } else {
+ pmd_t pmde = *pmd;
+
+ barrier();
+ if (!pmd_present(pmde) || pmd_trans_huge(pmde))
+ return false;
+ }
+map_pte:
+ pte = pte_offset_map(pmd, address);
+ if (!pte_present(*pte)) {
+ pte_unmap(pte);
+ return false;
+ }
+
+ ptl = pte_lockptr(mm, pmd);
+check_pte:
+ spin_lock(ptl);
+
+ if (!pte_present(*pte)) {
+ pte_unmap_unlock(pte, ptl);
+ return false;
+ }
+
+ /* THP can be referenced by any subpage */
+ if (pte_pfn(*pte) - page_to_pfn(page) >= hpage_nr_pages(page)) {
+ pte_unmap_unlock(pte, ptl);
+ return false;
+ }
+found:
+ *ptep = pte;
+ *pmdp = pmd;
+ *ptlp = ptl;
+ return true;
+}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
struct page_referenced_arg {
int mapcount;
int referenced;
@@ -830,49 +902,24 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
unsigned long address, void *arg)
{
struct mm_struct *mm = vma->vm_mm;
+ struct page_referenced_arg *pra = arg;
+ pmd_t *pmd;
+ pte_t *pte;
spinlock_t *ptl;
int referenced = 0;
- struct page_referenced_arg *pra = arg;
- if (unlikely(PageTransHuge(page))) {
- pmd_t *pmd;
+ if (!page_check_address_transhuge(page, mm, address, &pmd, &pte, &ptl))
+ return SWAP_AGAIN;
- /*
- * rmap might return false positives; we must filter
- * these out using page_check_address_pmd().
- */
- pmd = page_check_address_pmd(page, mm, address,
- PAGE_CHECK_ADDRESS_PMD_FLAG, &ptl);
- if (!pmd)
- return SWAP_AGAIN;
-
- if (vma->vm_flags & VM_LOCKED) {
- spin_unlock(ptl);
- pra->vm_flags |= VM_LOCKED;
- return SWAP_FAIL; /* To break the loop */
- }
-
- /* go ahead even if the pmd is pmd_trans_splitting() */
- if (pmdp_clear_flush_young_notify(vma, address, pmd))
- referenced++;
+ if (vma->vm_flags & VM_LOCKED) {
+ if (pte)
+ pte_unmap(pte);
spin_unlock(ptl);
- } else {
- pte_t *pte;
-
- /*
- * rmap might return false positives; we must filter
- * these out using page_check_address().
- */
- pte = page_check_address(page, mm, address, &ptl, 0);
- if (!pte)
- return SWAP_AGAIN;
-
- if (vma->vm_flags & VM_LOCKED) {
- pte_unmap_unlock(pte, ptl);
- pra->vm_flags |= VM_LOCKED;
- return SWAP_FAIL; /* To break the loop */
- }
+ pra->vm_flags |= VM_LOCKED;
+ return SWAP_FAIL; /* To break the loop */
+ }
+ if (pte) {
if (ptep_clear_flush_young_notify(vma, address, pte)) {
/*
* Don't treat a reference through a sequentially read
@@ -884,8 +931,15 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
if (likely(!(vma->vm_flags & VM_SEQ_READ)))
referenced++;
}
- pte_unmap_unlock(pte, ptl);
+ pte_unmap(pte);
+ } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
+ if (pmdp_clear_flush_young_notify(vma, address, pmd))
+ referenced++;
+ } else {
+ /* unexpected pmd-mapped page? */
+ WARN_ON_ONCE(1);
}
+ spin_unlock(ptl);
if (referenced)
clear_page_idle(page);
@@ -933,7 +987,7 @@ int page_referenced(struct page *page,
int ret;
int we_locked = 0;
struct page_referenced_arg pra = {
- .mapcount = page_mapcount(page),
+ .mapcount = total_mapcount(page),
.memcg = memcg,
};
struct rmap_walk_control rwc = {
@@ -1122,7 +1176,7 @@ static void __page_check_anon_rmap(struct page *page,
* over the call to page_add_new_anon_rmap.
*/
BUG_ON(page_anon_vma(page)->root != vma->anon_vma->root);
- BUG_ON(page->index != linear_page_index(vma, address));
+ BUG_ON(page_to_pgoff(page) != linear_page_index(vma, address));
#endif
}
@@ -1131,6 +1185,7 @@ static void __page_check_anon_rmap(struct page *page,
* @page: the page to add the mapping to
* @vma: the vm area in which the mapping is added
* @address: the user virtual address mapped
+ * @compound: charge the page as compound or small page
*
* The caller needs to hold the pte lock, and the page must be locked in
* the anon_vma case: to serialize mapping,index checking after setting,
@@ -1138,9 +1193,9 @@ static void __page_check_anon_rmap(struct page *page,
* (but PageKsm is never downgraded to PageAnon).
*/
void page_add_anon_rmap(struct page *page,
- struct vm_area_struct *vma, unsigned long address)
+ struct vm_area_struct *vma, unsigned long address, bool compound)
{
- do_page_add_anon_rmap(page, vma, address, 0);
+ do_page_add_anon_rmap(page, vma, address, compound ? RMAP_COMPOUND : 0);
}
/*
@@ -1149,29 +1204,44 @@ void page_add_anon_rmap(struct page *page,
* Everybody else should continue to use page_add_anon_rmap above.
*/
void do_page_add_anon_rmap(struct page *page,
- struct vm_area_struct *vma, unsigned long address, int exclusive)
+ struct vm_area_struct *vma, unsigned long address, int flags)
{
- int first = atomic_inc_and_test(&page->_mapcount);
+ bool compound = flags & RMAP_COMPOUND;
+ bool first;
+
+ if (compound) {
+ atomic_t *mapcount;
+ VM_BUG_ON_PAGE(!PageLocked(page), page);
+ VM_BUG_ON_PAGE(!PageTransHuge(page), page);
+ mapcount = compound_mapcount_ptr(page);
+ first = atomic_inc_and_test(mapcount);
+ } else {
+ first = atomic_inc_and_test(&page->_mapcount);
+ }
+
if (first) {
+ int nr = compound ? hpage_nr_pages(page) : 1;
/*
* We use the irq-unsafe __{inc|mod}_zone_page_stat because
* these counters are not modified in interrupt context, and
* pte lock(a spinlock) is held, which implies preemption
* disabled.
*/
- if (PageTransHuge(page))
+ if (compound) {
__inc_zone_page_state(page,
NR_ANON_TRANSPARENT_HUGEPAGES);
- __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
- hpage_nr_pages(page));
+ }
+ __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
}
if (unlikely(PageKsm(page)))
return;
VM_BUG_ON_PAGE(!PageLocked(page), page);
+
/* address might be in next vma when migration races vma_adjust */
if (first)
- __page_set_anon_rmap(page, vma, address, exclusive);
+ __page_set_anon_rmap(page, vma, address,
+ flags & RMAP_EXCLUSIVE);
else
__page_check_anon_rmap(page, vma, address);
}
@@ -1181,21 +1251,31 @@ void do_page_add_anon_rmap(struct page *page,
* @page: the page to add the mapping to
* @vma: the vm area in which the mapping is added
* @address: the user virtual address mapped
+ * @compound: charge the page as compound or small page
*
* Same as page_add_anon_rmap but must only be called on *new* pages.
* This means the inc-and-test can be bypassed.
* Page does not have to be locked.
*/
void page_add_new_anon_rmap(struct page *page,
- struct vm_area_struct *vma, unsigned long address)
+ struct vm_area_struct *vma, unsigned long address, bool compound)
{
+ int nr = compound ? hpage_nr_pages(page) : 1;
+
VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);
SetPageSwapBacked(page);
- atomic_set(&page->_mapcount, 0); /* increment count (starts at -1) */
- if (PageTransHuge(page))
+ if (compound) {
+ VM_BUG_ON_PAGE(!PageTransHuge(page), page);
+ /* increment count (starts at -1) */
+ atomic_set(compound_mapcount_ptr(page), 0);
__inc_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
- __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
- hpage_nr_pages(page));
+ } else {
+ /* Anon THP always mapped first with PMD */
+ VM_BUG_ON_PAGE(PageTransCompound(page), page);
+ /* increment count (starts at -1) */
+ atomic_set(&page->_mapcount, 0);
+ }
+ __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
__page_set_anon_rmap(page, vma, address, 1);
}
@@ -1223,12 +1303,15 @@ static void page_remove_file_rmap(struct page *page)
memcg = mem_cgroup_begin_page_stat(page);
- /* page still mapped by someone else? */
- if (!atomic_add_negative(-1, &page->_mapcount))
+ /* Hugepages are not counted in NR_FILE_MAPPED for now. */
+ if (unlikely(PageHuge(page))) {
+ /* hugetlb pages are always mapped with pmds */
+ atomic_dec(compound_mapcount_ptr(page));
goto out;
+ }
- /* Hugepages are not counted in NR_FILE_MAPPED for now. */
- if (unlikely(PageHuge(page)))
+ /* page still mapped by someone else? */
+ if (!atomic_add_negative(-1, &page->_mapcount))
goto out;
/*
@@ -1245,41 +1328,79 @@ out:
mem_cgroup_end_page_stat(memcg);
}
+static void page_remove_anon_compound_rmap(struct page *page)
+{
+ int i, nr;
+
+ if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
+ return;
+
+ /* Hugepages are not counted in NR_ANON_PAGES for now. */
+ if (unlikely(PageHuge(page)))
+ return;
+
+ if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+ return;
+
+ __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
+
+ if (TestClearPageDoubleMap(page)) {
+ /*
+ * Subpages can be mapped with PTEs too. Check how many of
+ * themi are still mapped.
+ */
+ for (i = 0, nr = 0; i < HPAGE_PMD_NR; i++) {
+ if (atomic_add_negative(-1, &page[i]._mapcount))
+ nr++;
+ }
+ } else {
+ nr = HPAGE_PMD_NR;
+ }
+
+ if (unlikely(PageMlocked(page)))
+ clear_page_mlock(page);
+
+ if (nr) {
+ __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, -nr);
+ deferred_split_huge_page(page);
+ }
+}
+
/**
* page_remove_rmap - take down pte mapping from a page
- * @page: page to remove mapping from
+ * @page: page to remove mapping from
+ * @compound: uncharge the page as compound or small page
*
* The caller needs to hold the pte lock.
*/
-void page_remove_rmap(struct page *page)
+void page_remove_rmap(struct page *page, bool compound)
{
if (!PageAnon(page)) {
+ VM_BUG_ON_PAGE(compound && !PageHuge(page), page);
page_remove_file_rmap(page);
return;
}
+ if (compound)
+ return page_remove_anon_compound_rmap(page);
+
/* page still mapped by someone else? */
if (!atomic_add_negative(-1, &page->_mapcount))
return;
- /* Hugepages are not counted in NR_ANON_PAGES for now. */
- if (unlikely(PageHuge(page)))
- return;
-
/*
* We use the irq-unsafe __{inc|mod}_zone_page_stat because
* these counters are not modified in interrupt context, and
* pte lock(a spinlock) is held, which implies preemption disabled.
*/
- if (PageTransHuge(page))
- __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
-
- __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
- -hpage_nr_pages(page));
+ __dec_zone_page_state(page, NR_ANON_PAGES);
if (unlikely(PageMlocked(page)))
clear_page_mlock(page);
+ if (PageTransCompound(page))
+ deferred_split_huge_page(compound_head(page));
+
/*
* It would be tidy to reset the PageAnon mapping here,
* but that might overwrite a racing page_add_anon_rmap
@@ -1291,6 +1412,11 @@ void page_remove_rmap(struct page *page)
*/
}
+struct rmap_private {
+ enum ttu_flags flags;
+ int lazyfreed;
+};
+
/*
* @arg: enum ttu_flags will be passed to this argument
*/
@@ -1302,7 +1428,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
pte_t pteval;
spinlock_t *ptl;
int ret = SWAP_AGAIN;
- enum ttu_flags flags = (enum ttu_flags)arg;
+ struct rmap_private *rp = arg;
+ enum ttu_flags flags = rp->flags;
/* munlock has nothing to gain from examining un-locked vmas */
if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
@@ -1362,10 +1489,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
if (PageHuge(page)) {
hugetlb_count_sub(1 << compound_order(page), mm);
} else {
- if (PageAnon(page))
- dec_mm_counter(mm, MM_ANONPAGES);
- else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter(page));
}
set_pte_at(mm, address, pte,
swp_entry_to_pte(make_hwpoison_entry(page)));
@@ -1375,10 +1499,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
* interest anymore. Simply discard the pte, vmscan
* will take care of the rest.
*/
- if (PageAnon(page))
- dec_mm_counter(mm, MM_ANONPAGES);
- else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter(page));
} else if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATION)) {
swp_entry_t entry;
pte_t swp_pte;
@@ -1400,6 +1521,14 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
* See handle_pte_fault() ...
*/
VM_BUG_ON_PAGE(!PageSwapCache(page), page);
+
+ if (!PageDirty(page) && (flags & TTU_LZFREE)) {
+ /* It's a freeable page by MADV_FREE */
+ dec_mm_counter(mm, MM_ANONPAGES);
+ rp->lazyfreed++;
+ goto discard;
+ }
+
if (swap_duplicate(entry) < 0) {
set_pte_at(mm, address, pte, pteval);
ret = SWAP_FAIL;
@@ -1418,9 +1547,10 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
swp_pte = pte_swp_mksoft_dirty(swp_pte);
set_pte_at(mm, address, pte, swp_pte);
} else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter_file(page));
- page_remove_rmap(page);
+discard:
+ page_remove_rmap(page, PageHuge(page));
page_cache_release(page);
out_unmap:
@@ -1472,9 +1602,14 @@ static int page_not_mapped(struct page *page)
int try_to_unmap(struct page *page, enum ttu_flags flags)
{
int ret;
+ struct rmap_private rp = {
+ .flags = flags,
+ .lazyfreed = 0,
+ };
+
struct rmap_walk_control rwc = {
.rmap_one = try_to_unmap_one,
- .arg = (void *)flags,
+ .arg = &rp,
.done = page_not_mapped,
.anon_lock = page_lock_anon_vma_read,
};
@@ -1494,8 +1629,11 @@ int try_to_unmap(struct page *page, enum ttu_flags flags)
ret = rmap_walk(page, &rwc);
- if (ret != SWAP_MLOCK && !page_mapped(page))
+ if (ret != SWAP_MLOCK && !page_mapped(page)) {
ret = SWAP_SUCCESS;
+ if (rp.lazyfreed && !PageDirty(page))
+ ret = SWAP_LZFREE;
+ }
return ret;
}
@@ -1517,9 +1655,14 @@ int try_to_unmap(struct page *page, enum ttu_flags flags)
int try_to_munlock(struct page *page)
{
int ret;
+ struct rmap_private rp = {
+ .flags = TTU_MUNLOCK,
+ .lazyfreed = 0,
+ };
+
struct rmap_walk_control rwc = {
.rmap_one = try_to_unmap_one,
- .arg = (void *)TTU_MUNLOCK,
+ .arg = &rp,
.done = page_not_mapped,
.anon_lock = page_lock_anon_vma_read,
@@ -1702,7 +1845,7 @@ void hugepage_add_anon_rmap(struct page *page,
BUG_ON(!PageLocked(page));
BUG_ON(!anon_vma);
/* address might be in next vma when migration races vma_adjust */
- first = atomic_inc_and_test(&page->_mapcount);
+ first = atomic_inc_and_test(compound_mapcount_ptr(page));
if (first)
__hugepage_set_anon_rmap(page, vma, address, 0);
}
@@ -1711,7 +1854,7 @@ void hugepage_add_new_anon_rmap(struct page *page,
struct vm_area_struct *vma, unsigned long address)
{
BUG_ON(address < vma->vm_start || address >= vma->vm_end);
- atomic_set(&page->_mapcount, 0);
+ atomic_set(compound_mapcount_ptr(page), 0);
__hugepage_set_anon_rmap(page, vma, address, 1);
}
#endif /* CONFIG_HUGETLB_PAGE */
diff --git a/mm/shmem.c b/mm/shmem.c
index 5813b7fa85b6..b98e1011858c 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -360,6 +360,87 @@ static int shmem_free_swap(struct address_space *mapping,
}
/*
+ * Determine (in bytes) how many of the shmem object's pages mapped by the
+ * given offsets are swapped out.
+ *
+ * This is safe to call without i_mutex or mapping->tree_lock thanks to RCU,
+ * as long as the inode doesn't go away and racy results are not a problem.
+ */
+unsigned long shmem_partial_swap_usage(struct address_space *mapping,
+ pgoff_t start, pgoff_t end)
+{
+ struct radix_tree_iter iter;
+ void **slot;
+ struct page *page;
+ unsigned long swapped = 0;
+
+ rcu_read_lock();
+
+restart:
+ radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
+ if (iter.index >= end)
+ break;
+
+ page = radix_tree_deref_slot(slot);
+
+ /*
+ * This should only be possible to happen at index 0, so we
+ * don't need to reset the counter, nor do we risk infinite
+ * restarts.
+ */
+ if (radix_tree_deref_retry(page))
+ goto restart;
+
+ if (radix_tree_exceptional_entry(page))
+ swapped++;
+
+ if (need_resched()) {
+ cond_resched_rcu();
+ start = iter.index + 1;
+ goto restart;
+ }
+ }
+
+ rcu_read_unlock();
+
+ return swapped << PAGE_SHIFT;
+}
+
+/*
+ * Determine (in bytes) how many of the shmem object's pages mapped by the
+ * given vma is swapped out.
+ *
+ * This is safe to call without i_mutex or mapping->tree_lock thanks to RCU,
+ * as long as the inode doesn't go away and racy results are not a problem.
+ */
+unsigned long shmem_swap_usage(struct vm_area_struct *vma)
+{
+ struct inode *inode = file_inode(vma->vm_file);
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ struct address_space *mapping = inode->i_mapping;
+ unsigned long swapped;
+
+ /* Be careful as we don't hold info->lock */
+ swapped = READ_ONCE(info->swapped);
+
+ /*
+ * The easier cases are when the shmem object has nothing in swap, or
+ * the vma maps it whole. Then we can simply use the stats that we
+ * already track.
+ */
+ if (!swapped)
+ return 0;
+
+ if (!vma->vm_pgoff && vma->vm_end - vma->vm_start >= inode->i_size)
+ return swapped << PAGE_SHIFT;
+
+ /* Here comes the more involved part */
+ return shmem_partial_swap_usage(mapping,
+ linear_page_index(vma, vma->vm_start),
+ linear_page_index(vma, vma->vm_end));
+}
+
+/*
* SysV IPC SHM_UNLOCK restore Unevictable pages to their evictable lists.
*/
void shmem_unlock_mapping(struct address_space *mapping)
@@ -729,7 +810,8 @@ int shmem_unuse(swp_entry_t swap, struct page *page)
* the shmem_swaplist_mutex which might hold up shmem_writepage().
* Charged back to the user (not to caller) when swap account is used.
*/
- error = mem_cgroup_try_charge(page, current->mm, GFP_KERNEL, &memcg);
+ error = mem_cgroup_try_charge(page, current->mm, GFP_KERNEL, &memcg,
+ false);
if (error)
goto out;
/* No radix_tree_preload: swap entry keeps a place for page in tree */
@@ -752,9 +834,9 @@ int shmem_unuse(swp_entry_t swap, struct page *page)
if (error) {
if (error != -ENOMEM)
error = 0;
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
} else
- mem_cgroup_commit_charge(page, memcg, true);
+ mem_cgroup_commit_charge(page, memcg, true, false);
out:
unlock_page(page);
page_cache_release(page);
@@ -1004,7 +1086,7 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
copy_highpage(newpage, oldpage);
flush_dcache_page(newpage);
- __set_page_locked(newpage);
+ __SetPageLocked(newpage);
SetPageUptodate(newpage);
SetPageSwapBacked(newpage);
set_page_private(newpage, swap_index);
@@ -1137,7 +1219,8 @@ repeat:
goto failed;
}
- error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg);
+ error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg,
+ false);
if (!error) {
error = shmem_add_to_page_cache(page, mapping, index,
swp_to_radix_entry(swap));
@@ -1154,14 +1237,14 @@ repeat:
* "repeat": reading a hole and writing should succeed.
*/
if (error) {
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
delete_from_swap_cache(page);
}
}
if (error)
goto failed;
- mem_cgroup_commit_charge(page, memcg, true);
+ mem_cgroup_commit_charge(page, memcg, true, false);
spin_lock(&info->lock);
info->swapped--;
@@ -1196,11 +1279,12 @@ repeat:
}
__SetPageSwapBacked(page);
- __set_page_locked(page);
+ __SetPageLocked(page);
if (sgp == SGP_WRITE)
__SetPageReferenced(page);
- error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg);
+ error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg,
+ false);
if (error)
goto decused;
error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK);
@@ -1210,10 +1294,10 @@ repeat:
radix_tree_preload_end();
}
if (error) {
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
goto decused;
}
- mem_cgroup_commit_charge(page, memcg, false);
+ mem_cgroup_commit_charge(page, memcg, false, false);
lru_cache_add_anon(page);
spin_lock(&info->lock);
@@ -2469,6 +2553,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
inode->i_op = &shmem_short_symlink_operations;
inode->i_link = info->symlink;
} else {
+ inode_nohighmem(inode);
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
if (error) {
iput(inode);
@@ -2476,7 +2561,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
}
inode->i_mapping->a_ops = &shmem_aops;
inode->i_op = &shmem_symlink_inode_operations;
- inode_nohighmem(inode);
memcpy(page_address(page), symname, len);
SetPageUptodate(page);
set_page_dirty(page);
@@ -3064,7 +3148,7 @@ static int shmem_init_inodecache(void)
{
shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
sizeof(struct shmem_inode_info),
- 0, SLAB_PANIC, shmem_init_inode);
+ 0, SLAB_PANIC|SLAB_ACCOUNT, shmem_init_inode);
return 0;
}
diff --git a/mm/slab.c b/mm/slab.c
index 4765c97ce690..6ecc697a8bc4 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2756,6 +2756,21 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
#define cache_free_debugcheck(x,objp,z) (objp)
#endif
+static struct page *get_first_slab(struct kmem_cache_node *n)
+{
+ struct page *page;
+
+ page = list_first_entry_or_null(&n->slabs_partial,
+ struct page, lru);
+ if (!page) {
+ n->free_touched = 1;
+ page = list_first_entry_or_null(&n->slabs_free,
+ struct page, lru);
+ }
+
+ return page;
+}
+
static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
bool force_refill)
{
@@ -2791,18 +2806,12 @@ retry:
}
while (batchcount > 0) {
- struct list_head *entry;
struct page *page;
/* Get slab alloc is to come from. */
- entry = n->slabs_partial.next;
- if (entry == &n->slabs_partial) {
- n->free_touched = 1;
- entry = n->slabs_free.next;
- if (entry == &n->slabs_free)
- goto must_grow;
- }
+ page = get_first_slab(n);
+ if (!page)
+ goto must_grow;
- page = list_entry(entry, struct page, lru);
check_spinlock_acquired(cachep);
/*
@@ -3085,7 +3094,6 @@ retry:
static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
int nodeid)
{
- struct list_head *entry;
struct page *page;
struct kmem_cache_node *n;
void *obj;
@@ -3098,15 +3106,10 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
retry:
check_irq_off();
spin_lock(&n->list_lock);
- entry = n->slabs_partial.next;
- if (entry == &n->slabs_partial) {
- n->free_touched = 1;
- entry = n->slabs_free.next;
- if (entry == &n->slabs_free)
- goto must_grow;
- }
+ page = get_first_slab(n);
+ if (!page)
+ goto must_grow;
- page = list_entry(entry, struct page, lru);
check_spinlock_acquired_node(cachep, nodeid);
STATS_INC_NODEALLOCS(cachep);
@@ -3338,17 +3341,12 @@ free_done:
#if STATS
{
int i = 0;
- struct list_head *p;
-
- p = n->slabs_free.next;
- while (p != &(n->slabs_free)) {
- struct page *page;
+ struct page *page;
- page = list_entry(p, struct page, lru);
+ list_for_each_entry(page, &n->slabs_free, lru) {
BUG_ON(page->active);
i++;
- p = p->next;
}
STATS_SET_FREEABLE(cachep, i);
}
diff --git a/mm/slab.h b/mm/slab.h
index 7b6087197997..c63b8699cfa3 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -128,10 +128,11 @@ static inline unsigned long kmem_cache_flags(unsigned long object_size,
#if defined(CONFIG_SLAB)
#define SLAB_CACHE_FLAGS (SLAB_MEM_SPREAD | SLAB_NOLEAKTRACE | \
- SLAB_RECLAIM_ACCOUNT | SLAB_TEMPORARY | SLAB_NOTRACK)
+ SLAB_RECLAIM_ACCOUNT | SLAB_TEMPORARY | \
+ SLAB_NOTRACK | SLAB_ACCOUNT)
#elif defined(CONFIG_SLUB)
#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE | SLAB_RECLAIM_ACCOUNT | \
- SLAB_TEMPORARY | SLAB_NOTRACK)
+ SLAB_TEMPORARY | SLAB_NOTRACK | SLAB_ACCOUNT)
#else
#define SLAB_CACHE_FLAGS (0)
#endif
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 3c6a86b4ec25..e016178063e1 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -37,7 +37,8 @@ struct kmem_cache *kmem_cache;
SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \
SLAB_FAILSLAB)
-#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | SLAB_NOTRACK)
+#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | \
+ SLAB_NOTRACK | SLAB_ACCOUNT)
/*
* Merge control. If this is set then no merging of slab caches will occur.
diff --git a/mm/slub.c b/mm/slub.c
index 46997517406e..b21fd24b08b1 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -338,11 +338,13 @@ static inline int oo_objects(struct kmem_cache_order_objects x)
*/
static __always_inline void slab_lock(struct page *page)
{
+ VM_BUG_ON_PAGE(PageTail(page), page);
bit_spin_lock(PG_locked, &page->flags);
}
static __always_inline void slab_unlock(struct page *page)
{
+ VM_BUG_ON_PAGE(PageTail(page), page);
__bit_spin_unlock(PG_locked, &page->flags);
}
@@ -5362,6 +5364,8 @@ static char *create_unique_id(struct kmem_cache *s)
*p++ = 'F';
if (!(s->flags & SLAB_NOTRACK))
*p++ = 't';
+ if (s->flags & SLAB_ACCOUNT)
+ *p++ = 'A';
if (p != name + 1)
*p++ = '-';
p += sprintf(p, "%07d", s->size);
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 4cba9c2783a1..b60802b3e5ea 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <linux/bootmem.h>
+#include <linux/memremap.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -70,7 +71,7 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node)
}
/* need to make sure size is all the same during early stage */
-void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node)
+static void * __meminit alloc_block_buf(unsigned long size, int node)
{
void *ptr;
@@ -87,6 +88,77 @@ void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node)
return ptr;
}
+static unsigned long __meminit vmem_altmap_next_pfn(struct vmem_altmap *altmap)
+{
+ return altmap->base_pfn + altmap->reserve + altmap->alloc
+ + altmap->align;
+}
+
+static unsigned long __meminit vmem_altmap_nr_free(struct vmem_altmap *altmap)
+{
+ unsigned long allocated = altmap->alloc + altmap->align;
+
+ if (altmap->free > allocated)
+ return altmap->free - allocated;
+ return 0;
+}
+
+/**
+ * vmem_altmap_alloc - allocate pages from the vmem_altmap reservation
+ * @altmap - reserved page pool for the allocation
+ * @nr_pfns - size (in pages) of the allocation
+ *
+ * Allocations are aligned to the size of the request
+ */
+static unsigned long __meminit vmem_altmap_alloc(struct vmem_altmap *altmap,
+ unsigned long nr_pfns)
+{
+ unsigned long pfn = vmem_altmap_next_pfn(altmap);
+ unsigned long nr_align;
+
+ nr_align = 1UL << find_first_bit(&nr_pfns, BITS_PER_LONG);
+ nr_align = ALIGN(pfn, nr_align) - pfn;
+
+ if (nr_pfns + nr_align > vmem_altmap_nr_free(altmap))
+ return ULONG_MAX;
+ altmap->alloc += nr_pfns;
+ altmap->align += nr_align;
+ return pfn + nr_align;
+}
+
+static void * __meminit altmap_alloc_block_buf(unsigned long size,
+ struct vmem_altmap *altmap)
+{
+ unsigned long pfn, nr_pfns;
+ void *ptr;
+
+ if (size & ~PAGE_MASK) {
+ pr_warn_once("%s: allocations must be multiple of PAGE_SIZE (%ld)\n",
+ __func__, size);
+ return NULL;
+ }
+
+ nr_pfns = size >> PAGE_SHIFT;
+ pfn = vmem_altmap_alloc(altmap, nr_pfns);
+ if (pfn < ULONG_MAX)
+ ptr = __va(__pfn_to_phys(pfn));
+ else
+ ptr = NULL;
+ pr_debug("%s: pfn: %#lx alloc: %ld align: %ld nr: %#lx\n",
+ __func__, pfn, altmap->alloc, altmap->align, nr_pfns);
+
+ return ptr;
+}
+
+/* need to make sure size is all the same during early stage */
+void * __meminit __vmemmap_alloc_block_buf(unsigned long size, int node,
+ struct vmem_altmap *altmap)
+{
+ if (altmap)
+ return altmap_alloc_block_buf(size, altmap);
+ return alloc_block_buf(size, node);
+}
+
void __meminit vmemmap_verify(pte_t *pte, int node,
unsigned long start, unsigned long end)
{
@@ -103,7 +175,7 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node)
pte_t *pte = pte_offset_kernel(pmd, addr);
if (pte_none(*pte)) {
pte_t entry;
- void *p = vmemmap_alloc_block_buf(PAGE_SIZE, node);
+ void *p = alloc_block_buf(PAGE_SIZE, node);
if (!p)
return NULL;
entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL);
diff --git a/mm/sparse.c b/mm/sparse.c
index d1b48b691ac8..3717ceed4177 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -748,7 +748,7 @@ static void clear_hwpoisoned_pages(struct page *memmap, int nr_pages)
if (!memmap)
return;
- for (i = 0; i < PAGES_PER_SECTION; i++) {
+ for (i = 0; i < nr_pages; i++) {
if (PageHWPoison(&memmap[i])) {
atomic_long_sub(1, &num_poisoned_pages);
ClearPageHWPoison(&memmap[i]);
@@ -788,7 +788,8 @@ static void free_section_usemap(struct page *memmap, unsigned long *usemap)
free_map_bootmem(memmap);
}
-void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
+void sparse_remove_one_section(struct zone *zone, struct mem_section *ms,
+ unsigned long map_offset)
{
struct page *memmap = NULL;
unsigned long *usemap = NULL, flags;
@@ -804,7 +805,8 @@ void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
}
pgdat_resize_unlock(pgdat, &flags);
- clear_hwpoisoned_pages(memmap, PAGES_PER_SECTION);
+ clear_hwpoisoned_pages(memmap + map_offset,
+ PAGES_PER_SECTION - map_offset);
free_section_usemap(memmap, usemap);
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
diff --git a/mm/swap.c b/mm/swap.c
index 39395fb549c0..09fe5e97714a 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -24,6 +24,7 @@
#include <linux/export.h>
#include <linux/mm_inline.h>
#include <linux/percpu_counter.h>
+#include <linux/memremap.h>
#include <linux/percpu.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
@@ -45,6 +46,7 @@ int page_cluster;
static DEFINE_PER_CPU(struct pagevec, lru_add_pvec);
static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs);
+static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs);
/*
* This path almost never happens for VM activity - pages are normally
@@ -89,260 +91,14 @@ static void __put_compound_page(struct page *page)
(*dtor)(page);
}
-/**
- * Two special cases here: we could avoid taking compound_lock_irqsave
- * and could skip the tail refcounting(in _mapcount).
- *
- * 1. Hugetlbfs page:
- *
- * PageHeadHuge will remain true until the compound page
- * is released and enters the buddy allocator, and it could
- * not be split by __split_huge_page_refcount().
- *
- * So if we see PageHeadHuge set, and we have the tail page pin,
- * then we could safely put head page.
- *
- * 2. Slab THP page:
- *
- * PG_slab is cleared before the slab frees the head page, and
- * tail pin cannot be the last reference left on the head page,
- * because the slab code is free to reuse the compound page
- * after a kfree/kmem_cache_free without having to check if
- * there's any tail pin left. In turn all tail pinsmust be always
- * released while the head is still pinned by the slab code
- * and so we know PG_slab will be still set too.
- *
- * So if we see PageSlab set, and we have the tail page pin,
- * then we could safely put head page.
- */
-static __always_inline
-void put_unrefcounted_compound_page(struct page *page_head, struct page *page)
-{
- /*
- * If @page is a THP tail, we must read the tail page
- * flags after the head page flags. The
- * __split_huge_page_refcount side enforces write memory barriers
- * between clearing PageTail and before the head page
- * can be freed and reallocated.
- */
- smp_rmb();
- if (likely(PageTail(page))) {
- /*
- * __split_huge_page_refcount cannot race
- * here, see the comment above this function.
- */
- VM_BUG_ON_PAGE(!PageHead(page_head), page_head);
- if (put_page_testzero(page_head)) {
- /*
- * If this is the tail of a slab THP page,
- * the tail pin must not be the last reference
- * held on the page, because the PG_slab cannot
- * be cleared before all tail pins (which skips
- * the _mapcount tail refcounting) have been
- * released.
- *
- * If this is the tail of a hugetlbfs page,
- * the tail pin may be the last reference on
- * the page instead, because PageHeadHuge will
- * not go away until the compound page enters
- * the buddy allocator.
- */
- VM_BUG_ON_PAGE(PageSlab(page_head), page_head);
- __put_compound_page(page_head);
- }
- } else
- /*
- * __split_huge_page_refcount run before us,
- * @page was a THP tail. The split @page_head
- * has been freed and reallocated as slab or
- * hugetlbfs page of smaller order (only
- * possible if reallocated as slab on x86).
- */
- if (put_page_testzero(page))
- __put_single_page(page);
-}
-
-static __always_inline
-void put_refcounted_compound_page(struct page *page_head, struct page *page)
-{
- if (likely(page != page_head && get_page_unless_zero(page_head))) {
- unsigned long flags;
-
- /*
- * @page_head wasn't a dangling pointer but it may not
- * be a head page anymore by the time we obtain the
- * lock. That is ok as long as it can't be freed from
- * under us.
- */
- flags = compound_lock_irqsave(page_head);
- if (unlikely(!PageTail(page))) {
- /* __split_huge_page_refcount run before us */
- compound_unlock_irqrestore(page_head, flags);
- if (put_page_testzero(page_head)) {
- /*
- * The @page_head may have been freed
- * and reallocated as a compound page
- * of smaller order and then freed
- * again. All we know is that it
- * cannot have become: a THP page, a
- * compound page of higher order, a
- * tail page. That is because we
- * still hold the refcount of the
- * split THP tail and page_head was
- * the THP head before the split.
- */
- if (PageHead(page_head))
- __put_compound_page(page_head);
- else
- __put_single_page(page_head);
- }
-out_put_single:
- if (put_page_testzero(page))
- __put_single_page(page);
- return;
- }
- VM_BUG_ON_PAGE(page_head != compound_head(page), page);
- /*
- * We can release the refcount taken by
- * get_page_unless_zero() now that
- * __split_huge_page_refcount() is blocked on the
- * compound_lock.
- */
- if (put_page_testzero(page_head))
- VM_BUG_ON_PAGE(1, page_head);
- /* __split_huge_page_refcount will wait now */
- VM_BUG_ON_PAGE(page_mapcount(page) <= 0, page);
- atomic_dec(&page->_mapcount);
- VM_BUG_ON_PAGE(atomic_read(&page_head->_count) <= 0, page_head);
- VM_BUG_ON_PAGE(atomic_read(&page->_count) != 0, page);
- compound_unlock_irqrestore(page_head, flags);
-
- if (put_page_testzero(page_head)) {
- if (PageHead(page_head))
- __put_compound_page(page_head);
- else
- __put_single_page(page_head);
- }
- } else {
- /* @page_head is a dangling pointer */
- VM_BUG_ON_PAGE(PageTail(page), page);
- goto out_put_single;
- }
-}
-
-static void put_compound_page(struct page *page)
-{
- struct page *page_head;
-
- /*
- * We see the PageCompound set and PageTail not set, so @page maybe:
- * 1. hugetlbfs head page, or
- * 2. THP head page.
- */
- if (likely(!PageTail(page))) {
- if (put_page_testzero(page)) {
- /*
- * By the time all refcounts have been released
- * split_huge_page cannot run anymore from under us.
- */
- if (PageHead(page))
- __put_compound_page(page);
- else
- __put_single_page(page);
- }
- return;
- }
-
- /*
- * We see the PageCompound set and PageTail set, so @page maybe:
- * 1. a tail hugetlbfs page, or
- * 2. a tail THP page, or
- * 3. a split THP page.
- *
- * Case 3 is possible, as we may race with
- * __split_huge_page_refcount tearing down a THP page.
- */
- page_head = compound_head(page);
- if (!__compound_tail_refcounted(page_head))
- put_unrefcounted_compound_page(page_head, page);
- else
- put_refcounted_compound_page(page_head, page);
-}
-
-void put_page(struct page *page)
+void __put_page(struct page *page)
{
if (unlikely(PageCompound(page)))
- put_compound_page(page);
- else if (put_page_testzero(page))
+ __put_compound_page(page);
+ else
__put_single_page(page);
}
-EXPORT_SYMBOL(put_page);
-
-/*
- * This function is exported but must not be called by anything other
- * than get_page(). It implements the slow path of get_page().
- */
-bool __get_page_tail(struct page *page)
-{
- /*
- * This takes care of get_page() if run on a tail page
- * returned by one of the get_user_pages/follow_page variants.
- * get_user_pages/follow_page itself doesn't need the compound
- * lock because it runs __get_page_tail_foll() under the
- * proper PT lock that already serializes against
- * split_huge_page().
- */
- unsigned long flags;
- bool got;
- struct page *page_head = compound_head(page);
-
- /* Ref to put_compound_page() comment. */
- if (!__compound_tail_refcounted(page_head)) {
- smp_rmb();
- if (likely(PageTail(page))) {
- /*
- * This is a hugetlbfs page or a slab
- * page. __split_huge_page_refcount
- * cannot race here.
- */
- VM_BUG_ON_PAGE(!PageHead(page_head), page_head);
- __get_page_tail_foll(page, true);
- return true;
- } else {
- /*
- * __split_huge_page_refcount run
- * before us, "page" was a THP
- * tail. The split page_head has been
- * freed and reallocated as slab or
- * hugetlbfs page of smaller order
- * (only possible if reallocated as
- * slab on x86).
- */
- return false;
- }
- }
-
- got = false;
- if (likely(page != page_head && get_page_unless_zero(page_head))) {
- /*
- * page_head wasn't a dangling pointer but it
- * may not be a head page anymore by the time
- * we obtain the lock. That is ok as long as it
- * can't be freed from under us.
- */
- flags = compound_lock_irqsave(page_head);
- /* here __split_huge_page_refcount won't run anymore */
- if (likely(PageTail(page))) {
- __get_page_tail_foll(page, false);
- got = true;
- }
- compound_unlock_irqrestore(page_head, flags);
- if (unlikely(!got))
- put_page(page_head);
- }
- return got;
-}
-EXPORT_SYMBOL(__get_page_tail);
+EXPORT_SYMBOL(__put_page);
/**
* put_pages_list() - release a list of pages
@@ -604,6 +360,7 @@ static void __lru_cache_activate_page(struct page *page)
*/
void mark_page_accessed(struct page *page)
{
+ page = compound_head(page);
if (!PageActive(page) && !PageUnevictable(page) &&
PageReferenced(page)) {
@@ -799,6 +556,24 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec,
update_page_reclaim_stat(lruvec, file, 0);
}
+
+static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec,
+ void *arg)
+{
+ if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) {
+ int file = page_is_file_cache(page);
+ int lru = page_lru_base_type(page);
+
+ del_page_from_lru_list(page, lruvec, lru + LRU_ACTIVE);
+ ClearPageActive(page);
+ ClearPageReferenced(page);
+ add_page_to_lru_list(page, lruvec, lru);
+
+ __count_vm_event(PGDEACTIVATE);
+ update_page_reclaim_stat(lruvec, file, 0);
+ }
+}
+
/*
* Drain pages out of the cpu's pagevecs.
* Either "cpu" is the current CPU, and preemption has already been
@@ -825,6 +600,10 @@ void lru_add_drain_cpu(int cpu)
if (pagevec_count(pvec))
pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL);
+ pvec = &per_cpu(lru_deactivate_pvecs, cpu);
+ if (pagevec_count(pvec))
+ pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
+
activate_page_drain(cpu);
}
@@ -854,6 +633,26 @@ void deactivate_file_page(struct page *page)
}
}
+/**
+ * deactivate_page - deactivate a page
+ * @page: page to deactivate
+ *
+ * deactivate_page() moves @page to the inactive list if @page was on the active
+ * list and was not an unevictable page. This is done to accelerate the reclaim
+ * of @page.
+ */
+void deactivate_page(struct page *page)
+{
+ if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) {
+ struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs);
+
+ page_cache_get(page);
+ if (!pagevec_add(pvec, page))
+ pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
+ put_cpu_var(lru_deactivate_pvecs);
+ }
+}
+
void lru_add_drain(void)
{
lru_add_drain_cpu(get_cpu());
@@ -883,6 +682,7 @@ void lru_add_drain_all(void)
if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) ||
pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) ||
pagevec_count(&per_cpu(lru_deactivate_file_pvecs, cpu)) ||
+ pagevec_count(&per_cpu(lru_deactivate_pvecs, cpu)) ||
need_activate_page_drain(cpu)) {
INIT_WORK(work, lru_add_drain_per_cpu);
schedule_work_on(cpu, work);
@@ -918,15 +718,6 @@ void release_pages(struct page **pages, int nr, bool cold)
for (i = 0; i < nr; i++) {
struct page *page = pages[i];
- if (unlikely(PageCompound(page))) {
- if (zone) {
- spin_unlock_irqrestore(&zone->lru_lock, flags);
- zone = NULL;
- }
- put_compound_page(page);
- continue;
- }
-
/*
* Make sure the IRQ-safe lock-holding time does not get
* excessive with a continuous string of pages from the
@@ -937,9 +728,19 @@ void release_pages(struct page **pages, int nr, bool cold)
zone = NULL;
}
+ page = compound_head(page);
if (!put_page_testzero(page))
continue;
+ if (PageCompound(page)) {
+ if (zone) {
+ spin_unlock_irqrestore(&zone->lru_lock, flags);
+ zone = NULL;
+ }
+ __put_compound_page(page);
+ continue;
+ }
+
if (PageLRU(page)) {
struct zone *pagezone = page_zone(page);
diff --git a/mm/swap_state.c b/mm/swap_state.c
index d504adb7fa5f..676ff2991380 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -185,13 +185,12 @@ int add_to_swap(struct page *page, struct list_head *list)
* deadlock in the swap out path.
*/
/*
- * Add it to the swap cache and mark it dirty
+ * Add it to the swap cache.
*/
err = add_to_swap_cache(page, entry,
__GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN);
- if (!err) { /* Success */
- SetPageDirty(page);
+ if (!err) {
return 1;
} else { /* -ENOMEM radix-tree allocation failure */
/*
@@ -353,7 +352,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
}
/* May fail (-ENOMEM) if radix-tree node allocation failed. */
- __set_page_locked(new_page);
+ __SetPageLocked(new_page);
SetPageSwapBacked(new_page);
err = __add_to_swap_cache(new_page, entry);
if (likely(!err)) {
@@ -367,7 +366,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
}
radix_tree_preload_end();
ClearPageSwapBacked(new_page);
- __clear_page_locked(new_page);
+ __ClearPageLocked(new_page);
/*
* add_to_swap_cache() doesn't return -EEXIST, so we can safely
* clear SWAP_HAS_CACHE flag.
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 58877312cf6b..2bb30aa3a412 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -165,8 +165,6 @@ static void discard_swap_cluster(struct swap_info_struct *si,
int found_extent = 0;
while (nr_pages) {
- struct list_head *lh;
-
if (se->start_page <= start_page &&
start_page < se->start_page + se->nr_pages) {
pgoff_t offset = start_page - se->start_page;
@@ -188,8 +186,7 @@ static void discard_swap_cluster(struct swap_info_struct *si,
break;
}
- lh = se->list.next;
- se = list_entry(lh, struct swap_extent, list);
+ se = list_next_entry(se, list);
}
}
@@ -903,7 +900,7 @@ int swp_swapcount(swp_entry_t entry)
VM_BUG_ON(page_private(page) != SWP_CONTINUED);
do {
- page = list_entry(page->lru.next, struct page, lru);
+ page = list_next_entry(page, lru);
map = kmap_atomic(page);
tmp_count = map[offset];
kunmap_atomic(map);
@@ -929,6 +926,9 @@ int reuse_swap_page(struct page *page)
VM_BUG_ON_PAGE(!PageLocked(page), page);
if (unlikely(PageKsm(page)))
return 0;
+ /* The page is part of THP and cannot be reused */
+ if (PageTransCompound(page))
+ return 0;
count = page_mapcount(page);
if (count <= 1 && PageSwapCache(page)) {
count += page_swapcount(page);
@@ -1111,19 +1111,9 @@ unsigned int count_swap_pages(int type, int free)
}
#endif /* CONFIG_HIBERNATION */
-static inline int maybe_same_pte(pte_t pte, pte_t swp_pte)
+static inline int pte_same_as_swp(pte_t pte, pte_t swp_pte)
{
-#ifdef CONFIG_MEM_SOFT_DIRTY
- /*
- * When pte keeps soft dirty bit the pte generated
- * from swap entry does not has it, still it's same
- * pte from logical point of view.
- */
- pte_t swp_pte_dirty = pte_swp_mksoft_dirty(swp_pte);
- return pte_same(pte, swp_pte) || pte_same(pte, swp_pte_dirty);
-#else
- return pte_same(pte, swp_pte);
-#endif
+ return pte_same(pte_swp_clear_soft_dirty(pte), swp_pte);
}
/*
@@ -1145,14 +1135,15 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
if (unlikely(!page))
return -ENOMEM;
- if (mem_cgroup_try_charge(page, vma->vm_mm, GFP_KERNEL, &memcg)) {
+ if (mem_cgroup_try_charge(page, vma->vm_mm, GFP_KERNEL,
+ &memcg, false)) {
ret = -ENOMEM;
goto out_nolock;
}
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
- if (unlikely(!maybe_same_pte(*pte, swp_entry_to_pte(entry)))) {
- mem_cgroup_cancel_charge(page, memcg);
+ if (unlikely(!pte_same_as_swp(*pte, swp_entry_to_pte(entry)))) {
+ mem_cgroup_cancel_charge(page, memcg, false);
ret = 0;
goto out;
}
@@ -1163,11 +1154,11 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
set_pte_at(vma->vm_mm, addr, pte,
pte_mkold(mk_pte(page, vma->vm_page_prot)));
if (page == swapcache) {
- page_add_anon_rmap(page, vma, addr);
- mem_cgroup_commit_charge(page, memcg, true);
+ page_add_anon_rmap(page, vma, addr, false);
+ mem_cgroup_commit_charge(page, memcg, true, false);
} else { /* ksm created a completely new copy */
- page_add_new_anon_rmap(page, vma, addr);
- mem_cgroup_commit_charge(page, memcg, false);
+ page_add_new_anon_rmap(page, vma, addr, false);
+ mem_cgroup_commit_charge(page, memcg, false, false);
lru_cache_add_active_or_unevictable(page, vma);
}
swap_free(entry);
@@ -1209,7 +1200,7 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
* swapoff spends a _lot_ of time in this loop!
* Test inline before going to call unuse_pte.
*/
- if (unlikely(maybe_same_pte(*pte, swp_pte))) {
+ if (unlikely(pte_same_as_swp(*pte, swp_pte))) {
pte_unmap(pte);
ret = unuse_pte(vma, pmd, addr, entry, page);
if (ret)
@@ -1633,14 +1624,11 @@ static sector_t map_swap_entry(swp_entry_t entry, struct block_device **bdev)
se = start_se;
for ( ; ; ) {
- struct list_head *lh;
-
if (se->start_page <= offset &&
offset < (se->start_page + se->nr_pages)) {
return se->start_block + (offset - se->start_page);
}
- lh = se->list.next;
- se = list_entry(lh, struct swap_extent, list);
+ se = list_next_entry(se, list);
sis->curr_swap_extent = se;
BUG_ON(se == start_se); /* It *must* be present */
}
@@ -1664,7 +1652,7 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
while (!list_empty(&sis->first_swap_extent.list)) {
struct swap_extent *se;
- se = list_entry(sis->first_swap_extent.list.next,
+ se = list_first_entry(&sis->first_swap_extent.list,
struct swap_extent, list);
list_del(&se->list);
kfree(se);
@@ -2959,11 +2947,10 @@ static void free_swap_count_continuations(struct swap_info_struct *si)
struct page *head;
head = vmalloc_to_page(si->swap_map + offset);
if (page_private(head)) {
- struct list_head *this, *next;
- list_for_each_safe(this, next, &head->lru) {
- struct page *page;
- page = list_entry(this, struct page, lru);
- list_del(this);
+ struct page *page, *next;
+
+ list_for_each_entry_safe(page, next, &head->lru, lru) {
+ list_del(&page->lru);
__free_page(page);
}
}
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 77fee9325a57..806b0c758c5b 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -63,7 +63,7 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm,
__SetPageUptodate(page);
ret = -ENOMEM;
- if (mem_cgroup_try_charge(page, dst_mm, GFP_KERNEL, &memcg))
+ if (mem_cgroup_try_charge(page, dst_mm, GFP_KERNEL, &memcg, false))
goto out_release;
_dst_pte = mk_pte(page, dst_vma->vm_page_prot);
@@ -76,8 +76,8 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm,
goto out_release_uncharge_unlock;
inc_mm_counter(dst_mm, MM_ANONPAGES);
- page_add_new_anon_rmap(page, dst_vma, dst_addr);
- mem_cgroup_commit_charge(page, memcg, false);
+ page_add_new_anon_rmap(page, dst_vma, dst_addr, false);
+ mem_cgroup_commit_charge(page, memcg, false, false);
lru_cache_add_active_or_unevictable(page, dst_vma);
set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
@@ -91,7 +91,7 @@ out:
return ret;
out_release_uncharge_unlock:
pte_unmap_unlock(dst_pte, ptl);
- mem_cgroup_cancel_charge(page, memcg);
+ mem_cgroup_cancel_charge(page, memcg, false);
out_release:
page_cache_release(page);
goto out;
diff --git a/mm/util.c b/mm/util.c
index 2d28f7930043..6d1f9200f74e 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -386,7 +386,9 @@ struct anon_vma *page_anon_vma(struct page *page)
struct address_space *page_mapping(struct page *page)
{
- unsigned long mapping;
+ struct address_space *mapping;
+
+ page = compound_head(page);
/* This happens if someone calls flush_dcache_page on slab page */
if (unlikely(PageSlab(page)))
@@ -399,11 +401,25 @@ struct address_space *page_mapping(struct page *page)
return swap_address_space(entry);
}
- mapping = (unsigned long)page->mapping;
- if (mapping & PAGE_MAPPING_FLAGS)
+ mapping = page->mapping;
+ if ((unsigned long)mapping & PAGE_MAPPING_FLAGS)
return NULL;
- return page->mapping;
+ return mapping;
+}
+
+/* Slow path of page_mapcount() for compound pages */
+int __page_mapcount(struct page *page)
+{
+ int ret;
+
+ ret = atomic_read(&page->_mapcount) + 1;
+ page = compound_head(page);
+ ret += atomic_read(compound_mapcount_ptr(page)) + 1;
+ if (PageDoubleMap(page))
+ ret--;
+ return ret;
}
+EXPORT_SYMBOL_GPL(__page_mapcount);
int overcommit_ratio_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 8e3c9c5a3042..fb42a5bffe47 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -441,8 +441,7 @@ nocache:
if (list_is_last(&first->list, &vmap_area_list))
goto found;
- first = list_entry(first->list.next,
- struct vmap_area, list);
+ first = list_next_entry(first, list);
}
found:
@@ -456,7 +455,7 @@ found:
free_vmap_cache = &va->rb_node;
spin_unlock(&vmap_area_lock);
- BUG_ON(va->va_start & (align-1));
+ BUG_ON(!IS_ALIGNED(va->va_start, align));
BUG_ON(va->va_start < vstart);
BUG_ON(va->va_end > vend);
@@ -1087,7 +1086,7 @@ void vm_unmap_ram(const void *mem, unsigned int count)
BUG_ON(!addr);
BUG_ON(addr < VMALLOC_START);
BUG_ON(addr > VMALLOC_END);
- BUG_ON(addr & (PAGE_SIZE-1));
+ BUG_ON(!IS_ALIGNED(addr, PAGE_SIZE));
debug_check_no_locks_freed(mem, size);
vmap_debug_free_range(addr, addr+size);
@@ -1477,13 +1476,10 @@ static void __vunmap(const void *addr, int deallocate_pages)
struct page *page = area->pages[i];
BUG_ON(!page);
- __free_page(page);
+ __free_kmem_pages(page, 0);
}
- if (area->flags & VM_VPAGES)
- vfree(area->pages);
- else
- kfree(area->pages);
+ kvfree(area->pages);
}
kfree(area);
@@ -1593,7 +1589,6 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
if (array_size > PAGE_SIZE) {
pages = __vmalloc_node(array_size, 1, nested_gfp|__GFP_HIGHMEM,
PAGE_KERNEL, node, area->caller);
- area->flags |= VM_VPAGES;
} else {
pages = kmalloc_node(array_size, nested_gfp, node);
}
@@ -1608,9 +1603,9 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
struct page *page;
if (node == NUMA_NO_NODE)
- page = alloc_page(alloc_mask);
+ page = alloc_kmem_pages(alloc_mask, order);
else
- page = alloc_pages_node(node, alloc_mask, order);
+ page = alloc_kmem_pages_node(node, alloc_mask, order);
if (unlikely(!page)) {
/* Successfully allocated i pages, free them in __vunmap() */
@@ -2559,10 +2554,10 @@ static void *s_start(struct seq_file *m, loff_t *pos)
struct vmap_area *va;
spin_lock(&vmap_area_lock);
- va = list_entry((&vmap_area_list)->next, typeof(*va), list);
+ va = list_first_entry(&vmap_area_list, typeof(*va), list);
while (n > 0 && &va->list != &vmap_area_list) {
n--;
- va = list_entry(va->list.next, typeof(*va), list);
+ va = list_next_entry(va, list);
}
if (!n && &va->list != &vmap_area_list)
return va;
@@ -2576,7 +2571,7 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos)
struct vmap_area *va = p, *next;
++*pos;
- next = list_entry(va->list.next, typeof(*va), list);
+ next = list_next_entry(va, list);
if (&next->list != &vmap_area_list)
return next;
@@ -2651,7 +2646,7 @@ static int s_show(struct seq_file *m, void *p)
if (v->flags & VM_USERMAP)
seq_puts(m, " user");
- if (v->flags & VM_VPAGES)
+ if (is_vmalloc_addr(v->pages))
seq_puts(m, " vpages");
show_numa_info(m, v);
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index c5afd573d7da..9a6c0704211c 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -137,14 +137,11 @@ struct vmpressure_event {
};
static bool vmpressure_event(struct vmpressure *vmpr,
- unsigned long scanned, unsigned long reclaimed)
+ enum vmpressure_levels level)
{
struct vmpressure_event *ev;
- enum vmpressure_levels level;
bool signalled = false;
- level = vmpressure_calc_level(scanned, reclaimed);
-
mutex_lock(&vmpr->events_lock);
list_for_each_entry(ev, &vmpr->events, node) {
@@ -164,6 +161,7 @@ static void vmpressure_work_fn(struct work_struct *work)
struct vmpressure *vmpr = work_to_vmpressure(work);
unsigned long scanned;
unsigned long reclaimed;
+ enum vmpressure_levels level;
spin_lock(&vmpr->sr_lock);
/*
@@ -174,19 +172,21 @@ static void vmpressure_work_fn(struct work_struct *work)
* here. No need for any locks here since we don't care if
* vmpr->reclaimed is in sync.
*/
- scanned = vmpr->scanned;
+ scanned = vmpr->tree_scanned;
if (!scanned) {
spin_unlock(&vmpr->sr_lock);
return;
}
- reclaimed = vmpr->reclaimed;
- vmpr->scanned = 0;
- vmpr->reclaimed = 0;
+ reclaimed = vmpr->tree_reclaimed;
+ vmpr->tree_scanned = 0;
+ vmpr->tree_reclaimed = 0;
spin_unlock(&vmpr->sr_lock);
+ level = vmpressure_calc_level(scanned, reclaimed);
+
do {
- if (vmpressure_event(vmpr, scanned, reclaimed))
+ if (vmpressure_event(vmpr, level))
break;
/*
* If not handled, propagate the event upward into the
@@ -199,6 +199,7 @@ static void vmpressure_work_fn(struct work_struct *work)
* vmpressure() - Account memory pressure through scanned/reclaimed ratio
* @gfp: reclaimer's gfp mask
* @memcg: cgroup memory controller handle
+ * @tree: legacy subtree mode
* @scanned: number of pages scanned
* @reclaimed: number of pages reclaimed
*
@@ -206,9 +207,16 @@ static void vmpressure_work_fn(struct work_struct *work)
* "instantaneous" memory pressure (scanned/reclaimed ratio). The raw
* pressure index is then further refined and averaged over time.
*
+ * If @tree is set, vmpressure is in traditional userspace reporting
+ * mode: @memcg is considered the pressure root and userspace is
+ * notified of the entire subtree's reclaim efficiency.
+ *
+ * If @tree is not set, reclaim efficiency is recorded for @memcg, and
+ * only in-kernel users are notified.
+ *
* This function does not return any value.
*/
-void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed)
{
struct vmpressure *vmpr = memcg_to_vmpressure(memcg);
@@ -238,15 +246,47 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
if (!scanned)
return;
- spin_lock(&vmpr->sr_lock);
- vmpr->scanned += scanned;
- vmpr->reclaimed += reclaimed;
- scanned = vmpr->scanned;
- spin_unlock(&vmpr->sr_lock);
+ if (tree) {
+ spin_lock(&vmpr->sr_lock);
+ vmpr->tree_scanned += scanned;
+ vmpr->tree_reclaimed += reclaimed;
+ scanned = vmpr->scanned;
+ spin_unlock(&vmpr->sr_lock);
- if (scanned < vmpressure_win)
- return;
- schedule_work(&vmpr->work);
+ if (scanned < vmpressure_win)
+ return;
+ schedule_work(&vmpr->work);
+ } else {
+ enum vmpressure_levels level;
+
+ /* For now, no users for root-level efficiency */
+ if (!memcg || memcg == root_mem_cgroup)
+ return;
+
+ spin_lock(&vmpr->sr_lock);
+ scanned = vmpr->scanned += scanned;
+ reclaimed = vmpr->reclaimed += reclaimed;
+ if (scanned < vmpressure_win) {
+ spin_unlock(&vmpr->sr_lock);
+ return;
+ }
+ vmpr->scanned = vmpr->reclaimed = 0;
+ spin_unlock(&vmpr->sr_lock);
+
+ level = vmpressure_calc_level(scanned, reclaimed);
+
+ if (level > VMPRESSURE_LOW) {
+ /*
+ * Let the socket buffer allocator know that
+ * we are having trouble reclaiming LRU pages.
+ *
+ * For hysteresis keep the pressure state
+ * asserted for a second in which subsequent
+ * pressure events can occur.
+ */
+ memcg->socket_pressure = jiffies + HZ;
+ }
+ }
}
/**
@@ -276,7 +316,7 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio)
* to the vmpressure() basically means that we signal 'critical'
* level.
*/
- vmpressure(gfp, memcg, vmpressure_win, 0);
+ vmpressure(gfp, memcg, true, vmpressure_win, 0);
}
/**
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 2aec4241b42a..5ac86956ff9d 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -106,8 +106,6 @@ struct scan_control {
unsigned long nr_reclaimed;
};
-#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
-
#ifdef ARCH_HAS_PREFETCH
#define prefetch_prev_lru_page(_page, _base, _field) \
do { \
@@ -197,11 +195,13 @@ static unsigned long zone_reclaimable_pages(struct zone *zone)
unsigned long nr;
nr = zone_page_state(zone, NR_ACTIVE_FILE) +
- zone_page_state(zone, NR_INACTIVE_FILE);
+ zone_page_state(zone, NR_INACTIVE_FILE) +
+ zone_page_state(zone, NR_ISOLATED_FILE);
if (get_nr_swap_pages() > 0)
nr += zone_page_state(zone, NR_ACTIVE_ANON) +
- zone_page_state(zone, NR_INACTIVE_ANON);
+ zone_page_state(zone, NR_INACTIVE_ANON) +
+ zone_page_state(zone, NR_ISOLATED_ANON);
return nr;
}
@@ -594,7 +594,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
/* synchronous write or broken a_ops? */
ClearPageReclaim(page);
}
- trace_mm_vmscan_writepage(page, trace_reclaim_flags(page));
+ trace_mm_vmscan_writepage(page);
inc_zone_page_state(page, NR_VMSCAN_WRITE);
return PAGE_SUCCESS;
}
@@ -906,6 +906,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
int may_enter_fs;
enum page_references references = PAGEREF_RECLAIM_CLEAN;
bool dirty, writeback;
+ bool lazyfree = false;
+ int ret = SWAP_SUCCESS;
cond_resched();
@@ -1049,6 +1051,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
goto keep_locked;
if (!add_to_swap(page, page_list))
goto activate_locked;
+ lazyfree = true;
may_enter_fs = 1;
/* Adding to swap updated mapping */
@@ -1060,14 +1063,17 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* processes. Try to unmap it here.
*/
if (page_mapped(page) && mapping) {
- switch (try_to_unmap(page,
- ttu_flags|TTU_BATCH_FLUSH)) {
+ switch (ret = try_to_unmap(page, lazyfree ?
+ (ttu_flags | TTU_BATCH_FLUSH | TTU_LZFREE) :
+ (ttu_flags | TTU_BATCH_FLUSH))) {
case SWAP_FAIL:
goto activate_locked;
case SWAP_AGAIN:
goto keep_locked;
case SWAP_MLOCK:
goto cull_mlocked;
+ case SWAP_LZFREE:
+ goto lazyfree;
case SWAP_SUCCESS:
; /* try to free the page below */
}
@@ -1174,6 +1180,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
}
}
+lazyfree:
if (!mapping || !__remove_mapping(mapping, page, true))
goto keep_locked;
@@ -1184,8 +1191,11 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* we obviously don't have to worry about waking up a process
* waiting on the page lock, because there are no references.
*/
- __clear_page_locked(page);
+ __ClearPageLocked(page);
free_it:
+ if (ret == SWAP_LZFREE)
+ count_vm_event(PGLAZYFREED);
+
nr_reclaimed++;
/*
@@ -1426,6 +1436,7 @@ int isolate_lru_page(struct page *page)
int ret = -EBUSY;
VM_BUG_ON_PAGE(!page_count(page), page);
+ VM_BUG_ON_PAGE(PageTail(page), page);
if (PageLRU(page)) {
struct zone *zone = page_zone(page);
@@ -1691,11 +1702,8 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
current_may_throttle())
wait_iff_congested(zone, BLK_RW_ASYNC, HZ/10);
- trace_mm_vmscan_lru_shrink_inactive(zone->zone_pgdat->node_id,
- zone_idx(zone),
- nr_scanned, nr_reclaimed,
- sc->priority,
- trace_shrink_flags(file));
+ trace_mm_vmscan_lru_shrink_inactive(zone, nr_scanned, nr_reclaimed,
+ sc->priority, file);
return nr_reclaimed;
}
@@ -2046,10 +2054,16 @@ static void get_scan_count(struct lruvec *lruvec, int swappiness,
}
/*
- * There is enough inactive page cache, do not reclaim
- * anything from the anonymous working set right now.
+ * If there is enough inactive page cache, i.e. if the size of the
+ * inactive list is greater than that of the active list *and* the
+ * inactive list actually has some pages to scan on this priority, we
+ * do not reclaim anything from the anonymous working set right now.
+ * Without the second condition we could end up never scanning an
+ * lruvec even if it has plenty of old anonymous pages unless the
+ * system is under heavy pressure.
*/
- if (!inactive_file_is_low(lruvec)) {
+ if (!inactive_file_is_low(lruvec) &&
+ get_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) {
scan_balance = SCAN_FILE;
goto out;
}
@@ -2393,6 +2407,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
memcg = mem_cgroup_iter(root, NULL, &reclaim);
do {
unsigned long lru_pages;
+ unsigned long reclaimed;
unsigned long scanned;
struct lruvec *lruvec;
int swappiness;
@@ -2405,6 +2420,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
lruvec = mem_cgroup_zone_lruvec(zone, memcg);
swappiness = mem_cgroup_swappiness(memcg);
+ reclaimed = sc->nr_reclaimed;
scanned = sc->nr_scanned;
shrink_lruvec(lruvec, swappiness, sc, &lru_pages);
@@ -2415,6 +2431,11 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
memcg, sc->nr_scanned - scanned,
lru_pages);
+ /* Record the group's reclaim efficiency */
+ vmpressure(sc->gfp_mask, memcg, false,
+ sc->nr_scanned - scanned,
+ sc->nr_reclaimed - reclaimed);
+
/*
* Direct reclaim and kswapd have to scan all memory
* cgroups to fulfill the overall scan target for the
@@ -2446,7 +2467,8 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
reclaim_state->reclaimed_slab = 0;
}
- vmpressure(sc->gfp_mask, sc->target_mem_cgroup,
+ /* Record the subtree's reclaim efficiency */
+ vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
sc->nr_scanned - nr_scanned,
sc->nr_reclaimed - nr_reclaimed);
diff --git a/mm/vmstat.c b/mm/vmstat.c
index c54fd2924f25..64bd0aa13f75 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -460,7 +460,7 @@ static int fold_diff(int *diff)
*
* The function returns the number of global counters updated.
*/
-static int refresh_cpu_vm_stats(void)
+static int refresh_cpu_vm_stats(bool do_pagesets)
{
struct zone *zone;
int i;
@@ -484,33 +484,35 @@ static int refresh_cpu_vm_stats(void)
#endif
}
}
- cond_resched();
#ifdef CONFIG_NUMA
- /*
- * Deal with draining the remote pageset of this
- * processor
- *
- * Check if there are pages remaining in this pageset
- * if not then there is nothing to expire.
- */
- if (!__this_cpu_read(p->expire) ||
+ if (do_pagesets) {
+ cond_resched();
+ /*
+ * Deal with draining the remote pageset of this
+ * processor
+ *
+ * Check if there are pages remaining in this pageset
+ * if not then there is nothing to expire.
+ */
+ if (!__this_cpu_read(p->expire) ||
!__this_cpu_read(p->pcp.count))
- continue;
+ continue;
- /*
- * We never drain zones local to this processor.
- */
- if (zone_to_nid(zone) == numa_node_id()) {
- __this_cpu_write(p->expire, 0);
- continue;
- }
+ /*
+ * We never drain zones local to this processor.
+ */
+ if (zone_to_nid(zone) == numa_node_id()) {
+ __this_cpu_write(p->expire, 0);
+ continue;
+ }
- if (__this_cpu_dec_return(p->expire))
- continue;
+ if (__this_cpu_dec_return(p->expire))
+ continue;
- if (__this_cpu_read(p->pcp.count)) {
- drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
- changes++;
+ if (__this_cpu_read(p->pcp.count)) {
+ drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
+ changes++;
+ }
}
#endif
}
@@ -781,6 +783,7 @@ const char * const vmstat_text[] = {
"pgfault",
"pgmajfault",
+ "pglazyfreed",
TEXTS_FOR_ZONES("pgrefill")
TEXTS_FOR_ZONES("pgsteal_kswapd")
@@ -842,7 +845,9 @@ const char * const vmstat_text[] = {
"thp_fault_fallback",
"thp_collapse_alloc",
"thp_collapse_alloc_failed",
- "thp_split",
+ "thp_split_page",
+ "thp_split_page_failed",
+ "thp_split_pmd",
"thp_zero_page_alloc",
"thp_zero_page_alloc_failed",
#endif
@@ -1386,7 +1391,7 @@ static cpumask_var_t cpu_stat_off;
static void vmstat_update(struct work_struct *w)
{
- if (refresh_cpu_vm_stats()) {
+ if (refresh_cpu_vm_stats(true)) {
/*
* Counters were updated so we expect more updates
* to occur in the future. Keep on running the
@@ -1418,6 +1423,23 @@ static void vmstat_update(struct work_struct *w)
}
/*
+ * Switch off vmstat processing and then fold all the remaining differentials
+ * until the diffs stay at zero. The function is used by NOHZ and can only be
+ * invoked when tick processing is not active.
+ */
+void quiet_vmstat(void)
+{
+ if (system_state != SYSTEM_RUNNING)
+ return;
+
+ do {
+ if (!cpumask_test_and_set_cpu(smp_processor_id(), cpu_stat_off))
+ cancel_delayed_work(this_cpu_ptr(&vmstat_work));
+
+ } while (refresh_cpu_vm_stats(false));
+}
+
+/*
* Check if the diffs for a certain cpu indicate that
* an update is needed.
*/
@@ -1449,7 +1471,7 @@ static bool need_update(int cpu)
*/
static void vmstat_shepherd(struct work_struct *w);
-static DECLARE_DELAYED_WORK(shepherd, vmstat_shepherd);
+static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
static void vmstat_shepherd(struct work_struct *w)
{
diff --git a/mm/zbud.c b/mm/zbud.c
index d8a181fd779b..b42322e50f63 100644
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -463,9 +463,6 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
spin_unlock(&pool->lock);
}
-#define list_tail_entry(ptr, type, member) \
- list_entry((ptr)->prev, type, member)
-
/**
* zbud_reclaim_page() - evicts allocations from a pool page and frees it
* @pool: pool from which a page will attempt to be evicted
@@ -514,7 +511,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
return -EINVAL;
}
for (i = 0; i < retries; i++) {
- zhdr = list_tail_entry(&pool->lru, struct zbud_header, lru);
+ zhdr = list_last_entry(&pool->lru, struct zbud_header, lru);
list_del(&zhdr->lru);
list_del(&zhdr->buddy);
/* Protect zbud page against free */
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index 9f15bdd9163c..e7414cec220b 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -213,10 +213,10 @@ struct size_class {
int size;
unsigned int index;
- /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int pages_per_zspage;
struct zs_size_stat stats;
+ /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+ int pages_per_zspage;
/* huge object: pages_per_zspage == 1 && maxobj_per_zspage == 1 */
bool huge;
};
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index d5d71ac96c8a..c24c481b666f 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -127,21 +127,17 @@ batadv_backbone_gw_free_ref(struct batadv_bla_backbone_gw *backbone_gw)
}
/* finally deinitialize the claim */
-static void batadv_claim_free_rcu(struct rcu_head *rcu)
+static void batadv_claim_release(struct batadv_bla_claim *claim)
{
- struct batadv_bla_claim *claim;
-
- claim = container_of(rcu, struct batadv_bla_claim, rcu);
-
batadv_backbone_gw_free_ref(claim->backbone_gw);
- kfree(claim);
+ kfree_rcu(claim, rcu);
}
/* free a claim, call claim_free_rcu if its the last reference */
static void batadv_claim_free_ref(struct batadv_bla_claim *claim)
{
if (atomic_dec_and_test(&claim->refcount))
- call_rcu(&claim->rcu, batadv_claim_free_rcu);
+ batadv_claim_release(claim);
}
/**
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 5a31420513e1..7b12ea8ea29d 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -75,18 +75,6 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu);
}
-/**
- * batadv_hardif_free_ref_now - decrement the hard interface refcounter and
- * possibly free it (without rcu callback)
- * @hard_iface: the hard interface to free
- */
-static inline void
-batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface)
-{
- if (atomic_dec_and_test(&hard_iface->refcount))
- batadv_hardif_free_rcu(&hard_iface->rcu);
-}
-
static inline struct batadv_hard_iface *
batadv_primary_if_get_selected(struct batadv_priv *bat_priv)
{
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index eb76386f8d4b..75fa5013af72 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -802,7 +802,9 @@ void batadv_mcast_free(struct batadv_priv *bat_priv)
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
+ spin_lock_bh(&bat_priv->tt.commit_lock);
batadv_mcast_mla_tt_retract(bat_priv, NULL);
+ spin_unlock_bh(&bat_priv->tt.commit_lock);
}
/**
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index c98b0ab85449..cc63b44f0d2e 100644
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -203,28 +203,25 @@ void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
}
/**
- * batadv_nc_node_free_rcu - rcu callback to free an nc node and remove
- * its refcount on the orig_node
- * @rcu: rcu pointer of the nc node
+ * batadv_nc_node_release - release nc_node from lists and queue for free after
+ * rcu grace period
+ * @nc_node: the nc node to free
*/
-static void batadv_nc_node_free_rcu(struct rcu_head *rcu)
+static void batadv_nc_node_release(struct batadv_nc_node *nc_node)
{
- struct batadv_nc_node *nc_node;
-
- nc_node = container_of(rcu, struct batadv_nc_node, rcu);
batadv_orig_node_free_ref(nc_node->orig_node);
- kfree(nc_node);
+ kfree_rcu(nc_node, rcu);
}
/**
- * batadv_nc_node_free_ref - decrements the nc node refcounter and possibly
- * frees it
+ * batadv_nc_node_free_ref - decrement the nc node refcounter and possibly
+ * release it
* @nc_node: the nc node to free
*/
static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node)
{
if (atomic_dec_and_test(&nc_node->refcount))
- call_rcu(&nc_node->rcu, batadv_nc_node_free_rcu);
+ batadv_nc_node_release(nc_node);
}
/**
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 3c782a33bdac..fe578f75c391 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -163,142 +163,101 @@ err:
}
/**
- * batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object
- * @rcu: rcu pointer of the neigh_ifinfo object
- */
-static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu)
-{
- struct batadv_neigh_ifinfo *neigh_ifinfo;
-
- neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu);
-
- if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
- batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing);
-
- kfree(neigh_ifinfo);
-}
-
-/**
- * batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free
- * the neigh_ifinfo (without rcu callback)
+ * batadv_neigh_ifinfo_release - release neigh_ifinfo from lists and queue for
+ * free after rcu grace period
* @neigh_ifinfo: the neigh_ifinfo object to release
*/
static void
-batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo)
+batadv_neigh_ifinfo_release(struct batadv_neigh_ifinfo *neigh_ifinfo)
{
- if (atomic_dec_and_test(&neigh_ifinfo->refcount))
- batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu);
+ if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
+ batadv_hardif_free_ref(neigh_ifinfo->if_outgoing);
+
+ kfree_rcu(neigh_ifinfo, rcu);
}
/**
- * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
+ * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly release
* the neigh_ifinfo
* @neigh_ifinfo: the neigh_ifinfo object to release
*/
void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
{
if (atomic_dec_and_test(&neigh_ifinfo->refcount))
- call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
+ batadv_neigh_ifinfo_release(neigh_ifinfo);
}
/**
- * batadv_hardif_neigh_free_rcu - free the hardif neigh_node
- * @rcu: rcu pointer of the neigh_node
+ * batadv_hardif_neigh_release - release hardif neigh node from lists and
+ * queue for free after rcu grace period
+ * @hardif_neigh: hardif neigh neighbor to free
*/
-static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu)
+static void
+batadv_hardif_neigh_release(struct batadv_hardif_neigh_node *hardif_neigh)
{
- struct batadv_hardif_neigh_node *hardif_neigh;
-
- hardif_neigh = container_of(rcu, struct batadv_hardif_neigh_node, rcu);
-
spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
hlist_del_init_rcu(&hardif_neigh->list);
spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
- batadv_hardif_free_ref_now(hardif_neigh->if_incoming);
- kfree(hardif_neigh);
-}
-
-/**
- * batadv_hardif_neigh_free_now - decrement the hardif neighbors refcounter
- * and possibly free it (without rcu callback)
- * @hardif_neigh: hardif neigh neighbor to free
- */
-static void
-batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh)
-{
- if (atomic_dec_and_test(&hardif_neigh->refcount))
- batadv_hardif_neigh_free_rcu(&hardif_neigh->rcu);
+ batadv_hardif_free_ref(hardif_neigh->if_incoming);
+ kfree_rcu(hardif_neigh, rcu);
}
/**
* batadv_hardif_neigh_free_ref - decrement the hardif neighbors refcounter
- * and possibly free it
+ * and possibly release it
* @hardif_neigh: hardif neigh neighbor to free
*/
void batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh)
{
if (atomic_dec_and_test(&hardif_neigh->refcount))
- call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu);
+ batadv_hardif_neigh_release(hardif_neigh);
}
/**
- * batadv_neigh_node_free_rcu - free the neigh_node
- * @rcu: rcu pointer of the neigh_node
+ * batadv_neigh_node_release - release neigh_node from lists and queue for
+ * free after rcu grace period
+ * @neigh_node: neigh neighbor to free
*/
-static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
+static void batadv_neigh_node_release(struct batadv_neigh_node *neigh_node)
{
struct hlist_node *node_tmp;
- struct batadv_neigh_node *neigh_node;
struct batadv_hardif_neigh_node *hardif_neigh;
struct batadv_neigh_ifinfo *neigh_ifinfo;
struct batadv_algo_ops *bao;
- neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
bao = neigh_node->orig_node->bat_priv->bat_algo_ops;
hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
&neigh_node->ifinfo_list, list) {
- batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
+ batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
}
hardif_neigh = batadv_hardif_neigh_get(neigh_node->if_incoming,
neigh_node->addr);
if (hardif_neigh) {
/* batadv_hardif_neigh_get() increases refcount too */
- batadv_hardif_neigh_free_now(hardif_neigh);
- batadv_hardif_neigh_free_now(hardif_neigh);
+ batadv_hardif_neigh_free_ref(hardif_neigh);
+ batadv_hardif_neigh_free_ref(hardif_neigh);
}
if (bao->bat_neigh_free)
bao->bat_neigh_free(neigh_node);
- batadv_hardif_free_ref_now(neigh_node->if_incoming);
-
- kfree(neigh_node);
-}
+ batadv_hardif_free_ref(neigh_node->if_incoming);
-/**
- * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter
- * and possibly free it (without rcu callback)
- * @neigh_node: neigh neighbor to free
- */
-static void
-batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node)
-{
- if (atomic_dec_and_test(&neigh_node->refcount))
- batadv_neigh_node_free_rcu(&neigh_node->rcu);
+ kfree_rcu(neigh_node, rcu);
}
/**
* batadv_neigh_node_free_ref - decrement the neighbors refcounter
- * and possibly free it
+ * and possibly release it
* @neigh_node: neigh neighbor to free
*/
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node)
{
if (atomic_dec_and_test(&neigh_node->refcount))
- call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
+ batadv_neigh_node_release(neigh_node);
}
/**
@@ -727,108 +686,99 @@ int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset)
}
/**
- * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
- * @rcu: rcu pointer of the orig_ifinfo object
+ * batadv_orig_ifinfo_release - release orig_ifinfo from lists and queue for
+ * free after rcu grace period
+ * @orig_ifinfo: the orig_ifinfo object to release
*/
-static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu)
+static void batadv_orig_ifinfo_release(struct batadv_orig_ifinfo *orig_ifinfo)
{
- struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *router;
- orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
-
if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
- batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
+ batadv_hardif_free_ref(orig_ifinfo->if_outgoing);
/* this is the last reference to this object */
router = rcu_dereference_protected(orig_ifinfo->router, true);
if (router)
- batadv_neigh_node_free_ref_now(router);
- kfree(orig_ifinfo);
+ batadv_neigh_node_free_ref(router);
+
+ kfree_rcu(orig_ifinfo, rcu);
}
/**
- * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
- * the orig_ifinfo (without rcu callback)
+ * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly release
+ * the orig_ifinfo
* @orig_ifinfo: the orig_ifinfo object to release
*/
-static void
-batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo)
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo)
{
if (atomic_dec_and_test(&orig_ifinfo->refcount))
- batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu);
+ batadv_orig_ifinfo_release(orig_ifinfo);
}
/**
- * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
- * the orig_ifinfo
- * @orig_ifinfo: the orig_ifinfo object to release
+ * batadv_orig_node_free_rcu - free the orig_node
+ * @rcu: rcu pointer of the orig_node
*/
-void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo)
+static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
{
- if (atomic_dec_and_test(&orig_ifinfo->refcount))
- call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu);
+ struct batadv_orig_node *orig_node;
+
+ orig_node = container_of(rcu, struct batadv_orig_node, rcu);
+
+ batadv_mcast_purge_orig(orig_node);
+
+ batadv_frag_purge_orig(orig_node, NULL);
+
+ if (orig_node->bat_priv->bat_algo_ops->bat_orig_free)
+ orig_node->bat_priv->bat_algo_ops->bat_orig_free(orig_node);
+
+ kfree(orig_node->tt_buff);
+ kfree(orig_node);
}
-static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
+/**
+ * batadv_orig_node_release - release orig_node from lists and queue for
+ * free after rcu grace period
+ * @orig_node: the orig node to free
+ */
+static void batadv_orig_node_release(struct batadv_orig_node *orig_node)
{
struct hlist_node *node_tmp;
struct batadv_neigh_node *neigh_node;
- struct batadv_orig_node *orig_node;
struct batadv_orig_ifinfo *orig_ifinfo;
- orig_node = container_of(rcu, struct batadv_orig_node, rcu);
-
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node_tmp,
&orig_node->neigh_list, list) {
hlist_del_rcu(&neigh_node->list);
- batadv_neigh_node_free_ref_now(neigh_node);
+ batadv_neigh_node_free_ref(neigh_node);
}
hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
hlist_del_rcu(&orig_ifinfo->list);
- batadv_orig_ifinfo_free_ref_now(orig_ifinfo);
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
}
spin_unlock_bh(&orig_node->neigh_list_lock);
- batadv_mcast_purge_orig(orig_node);
-
/* Free nc_nodes */
batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
- batadv_frag_purge_orig(orig_node, NULL);
-
- if (orig_node->bat_priv->bat_algo_ops->bat_orig_free)
- orig_node->bat_priv->bat_algo_ops->bat_orig_free(orig_node);
-
- kfree(orig_node->tt_buff);
- kfree(orig_node);
+ call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
}
/**
* batadv_orig_node_free_ref - decrement the orig node refcounter and possibly
- * schedule an rcu callback for freeing it
+ * release it
* @orig_node: the orig node to free
*/
void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node)
{
if (atomic_dec_and_test(&orig_node->refcount))
- call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
-}
-
-/**
- * batadv_orig_node_free_ref_now - decrement the orig node refcounter and
- * possibly free it (without rcu callback)
- * @orig_node: the orig node to free
- */
-void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node)
-{
- if (atomic_dec_and_test(&orig_node->refcount))
- batadv_orig_node_free_rcu(&orig_node->rcu);
+ batadv_orig_node_release(orig_node);
}
void batadv_originator_free(struct batadv_priv *bat_priv)
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 29557753d552..cf0730414ed2 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -38,7 +38,6 @@ int batadv_originator_init(struct batadv_priv *bat_priv);
void batadv_originator_free(struct batadv_priv *bat_priv);
void batadv_purge_orig_ref(struct batadv_priv *bat_priv);
void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node);
-void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node);
struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
const u8 *addr);
struct batadv_hardif_neigh_node *
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index a22080c53401..cdfc85fa2743 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -240,20 +240,6 @@ int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
return count;
}
-static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
-{
- struct batadv_tt_orig_list_entry *orig_entry;
-
- orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
-
- /* We are in an rcu callback here, therefore we cannot use
- * batadv_orig_node_free_ref() and its call_rcu():
- * An rcu_barrier() wouldn't wait for that to finish
- */
- batadv_orig_node_free_ref_now(orig_entry->orig_node);
- kfree(orig_entry);
-}
-
/**
* batadv_tt_local_size_mod - change the size by v of the local table identified
* by vid
@@ -349,13 +335,25 @@ static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
batadv_tt_global_size_mod(orig_node, vid, -1);
}
+/**
+ * batadv_tt_orig_list_entry_release - release tt orig entry from lists and
+ * queue for free after rcu grace period
+ * @orig_entry: tt orig entry to be free'd
+ */
+static void
+batadv_tt_orig_list_entry_release(struct batadv_tt_orig_list_entry *orig_entry)
+{
+ batadv_orig_node_free_ref(orig_entry->orig_node);
+ kfree_rcu(orig_entry, rcu);
+}
+
static void
batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
{
if (!atomic_dec_and_test(&orig_entry->refcount))
return;
- call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
+ batadv_tt_orig_list_entry_release(orig_entry);
}
/**
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 5e88d3e17546..2c8095a5d824 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -28,6 +28,8 @@
const struct nf_br_ops __rcu *nf_br_ops __read_mostly;
EXPORT_SYMBOL_GPL(nf_br_ops);
+static struct lock_class_key bridge_netdev_addr_lock_key;
+
/* net device transmit always called with BH disabled */
netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -87,6 +89,11 @@ out:
return NETDEV_TX_OK;
}
+static void br_set_lockdep_class(struct net_device *dev)
+{
+ lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key);
+}
+
static int br_dev_init(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
@@ -99,6 +106,7 @@ static int br_dev_init(struct net_device *dev)
err = br_vlan_init(br);
if (err)
free_percpu(br->stats);
+ br_set_lockdep_class(dev);
return err;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 0ca95d5d7af0..cc9e3652cf93 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2695,6 +2695,8 @@ static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path)
*
* It may return NULL if the skb requires no segmentation. This is
* only possible when GSO is used for verifying header integrity.
+ *
+ * Segmentation preserves SKB_SGO_CB_OFFSET bytes of previous skb cb.
*/
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path)
@@ -2709,6 +2711,9 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
return ERR_PTR(err);
}
+ BUILD_BUG_ON(SKB_SGO_CB_OFFSET +
+ sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb));
+
SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb);
SKB_GSO_CB(skb)->encap_level = 0;
diff --git a/net/core/sock.c b/net/core/sock.c
index 51270238e269..6c1c8bc93412 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -195,44 +195,6 @@ bool sk_net_capable(const struct sock *sk, int cap)
}
EXPORT_SYMBOL(sk_net_capable);
-
-#ifdef CONFIG_MEMCG_KMEM
-int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
-{
- struct proto *proto;
- int ret = 0;
-
- mutex_lock(&proto_list_mutex);
- list_for_each_entry(proto, &proto_list, node) {
- if (proto->init_cgroup) {
- ret = proto->init_cgroup(memcg, ss);
- if (ret)
- goto out;
- }
- }
-
- mutex_unlock(&proto_list_mutex);
- return ret;
-out:
- list_for_each_entry_continue_reverse(proto, &proto_list, node)
- if (proto->destroy_cgroup)
- proto->destroy_cgroup(memcg);
- mutex_unlock(&proto_list_mutex);
- return ret;
-}
-
-void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
-{
- struct proto *proto;
-
- mutex_lock(&proto_list_mutex);
- list_for_each_entry_reverse(proto, &proto_list, node)
- if (proto->destroy_cgroup)
- proto->destroy_cgroup(memcg);
- mutex_unlock(&proto_list_mutex);
-}
-#endif
-
/*
* Each address family might have different locking rules, so we have
* one slock key per address family:
@@ -240,11 +202,6 @@ void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
static struct lock_class_key af_family_keys[AF_MAX];
static struct lock_class_key af_family_slock_keys[AF_MAX];
-#if defined(CONFIG_MEMCG_KMEM)
-struct static_key memcg_socket_limit_enabled;
-EXPORT_SYMBOL(memcg_socket_limit_enabled);
-#endif
-
/*
* Make lock validator output more readable. (we pre-construct these
* strings build-time, so that runtime initialization of socket
@@ -1507,12 +1464,6 @@ void sk_free(struct sock *sk)
}
EXPORT_SYMBOL(sk_free);
-static void sk_update_clone(const struct sock *sk, struct sock *newsk)
-{
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- sock_update_memcg(newsk);
-}
-
/**
* sk_clone_lock - clone a socket, and lock its clone
* @sk: the socket to clone
@@ -1607,7 +1558,8 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
sk_set_socket(newsk, NULL);
newsk->sk_wq = NULL;
- sk_update_clone(sk, newsk);
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ sock_update_memcg(newsk);
if (newsk->sk_prot->sockets_allocated)
sk_sockets_allocated_inc(newsk);
@@ -2089,27 +2041,27 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)
struct proto *prot = sk->sk_prot;
int amt = sk_mem_pages(size);
long allocated;
- int parent_status = UNDER_LIMIT;
sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
- allocated = sk_memory_allocated_add(sk, amt, &parent_status);
+ allocated = sk_memory_allocated_add(sk, amt);
+
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
+ !mem_cgroup_charge_skmem(sk->sk_memcg, amt))
+ goto suppress_allocation;
/* Under limit. */
- if (parent_status == UNDER_LIMIT &&
- allocated <= sk_prot_mem_limits(sk, 0)) {
+ if (allocated <= sk_prot_mem_limits(sk, 0)) {
sk_leave_memory_pressure(sk);
return 1;
}
- /* Under pressure. (we or our parents) */
- if ((parent_status > SOFT_LIMIT) ||
- allocated > sk_prot_mem_limits(sk, 1))
+ /* Under pressure. */
+ if (allocated > sk_prot_mem_limits(sk, 1))
sk_enter_memory_pressure(sk);
- /* Over hard limit (we or our parents) */
- if ((parent_status == OVER_LIMIT) ||
- (allocated > sk_prot_mem_limits(sk, 2)))
+ /* Over hard limit. */
+ if (allocated > sk_prot_mem_limits(sk, 2))
goto suppress_allocation;
/* guarantee minimum buffer size under pressure */
@@ -2158,6 +2110,9 @@ suppress_allocation:
sk_memory_allocated_sub(sk, amt);
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ mem_cgroup_uncharge_skmem(sk->sk_memcg, amt);
+
return 0;
}
EXPORT_SYMBOL(__sk_mem_schedule);
@@ -2173,6 +2128,9 @@ void __sk_mem_reclaim(struct sock *sk, int amount)
sk_memory_allocated_sub(sk, amount);
sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT;
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ mem_cgroup_uncharge_skmem(sk->sk_memcg, amount);
+
if (sk_under_memory_pressure(sk) &&
(sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)))
sk_leave_memory_pressure(sk);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 512a44778cf2..64878efa045c 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -239,6 +239,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
* from host network stack.
*/
features = netif_skb_features(skb);
+ BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
if (IS_ERR_OR_NULL(segs)) {
kfree_skb(skb);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 7bb1b091efd1..fd17eec93525 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -422,7 +422,8 @@ void tcp_init_sock(struct sock *sk)
sk->sk_rcvbuf = sysctl_tcp_rmem[1];
local_bh_disable();
- sock_update_memcg(sk);
+ if (mem_cgroup_sockets_enabled)
+ sock_update_memcg(sk);
sk_sockets_allocated_inc(sk);
local_bh_enable();
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 65947c1f4733..c7d1fb50f381 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1818,7 +1818,9 @@ void tcp_v4_destroy_sock(struct sock *sk)
tcp_saved_syn_free(tp);
sk_sockets_allocated_dec(sk);
- sock_release_memcg(sk);
+
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ sock_release_memcg(sk);
}
EXPORT_SYMBOL(tcp_v4_destroy_sock);
@@ -2342,11 +2344,6 @@ struct proto tcp_prot = {
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
-#ifdef CONFIG_MEMCG_KMEM
- .init_cgroup = tcp_init_cgroup,
- .destroy_cgroup = tcp_destroy_cgroup,
- .proto_cgroup = tcp_proto_cgroup,
-#endif
.diag_destroy = tcp_abort,
};
EXPORT_SYMBOL(tcp_prot);
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index 2379c1b4efb2..18bc7f745e9c 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -8,75 +8,49 @@
int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
+ struct mem_cgroup *parent = parent_mem_cgroup(memcg);
+ struct page_counter *counter_parent = NULL;
/*
* The root cgroup does not use page_counters, but rather,
* rely on the data already collected by the network
* subsystem
*/
- struct mem_cgroup *parent = parent_mem_cgroup(memcg);
- struct page_counter *counter_parent = NULL;
- struct cg_proto *cg_proto, *parent_cg;
-
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return 0;
- cg_proto->sysctl_mem[0] = sysctl_tcp_mem[0];
- cg_proto->sysctl_mem[1] = sysctl_tcp_mem[1];
- cg_proto->sysctl_mem[2] = sysctl_tcp_mem[2];
- cg_proto->memory_pressure = 0;
- cg_proto->memcg = memcg;
+ memcg->tcp_mem.memory_pressure = 0;
- parent_cg = tcp_prot.proto_cgroup(parent);
- if (parent_cg)
- counter_parent = &parent_cg->memory_allocated;
+ if (parent)
+ counter_parent = &parent->tcp_mem.memory_allocated;
- page_counter_init(&cg_proto->memory_allocated, counter_parent);
- percpu_counter_init(&cg_proto->sockets_allocated, 0, GFP_KERNEL);
+ page_counter_init(&memcg->tcp_mem.memory_allocated, counter_parent);
return 0;
}
-EXPORT_SYMBOL(tcp_init_cgroup);
void tcp_destroy_cgroup(struct mem_cgroup *memcg)
{
- struct cg_proto *cg_proto;
-
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return;
- percpu_counter_destroy(&cg_proto->sockets_allocated);
-
- if (test_bit(MEMCG_SOCK_ACTIVATED, &cg_proto->flags))
- static_key_slow_dec(&memcg_socket_limit_enabled);
-
+ if (memcg->tcp_mem.active)
+ static_branch_dec(&memcg_sockets_enabled_key);
}
-EXPORT_SYMBOL(tcp_destroy_cgroup);
static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
{
- struct cg_proto *cg_proto;
- int i;
int ret;
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return -EINVAL;
- ret = page_counter_limit(&cg_proto->memory_allocated, nr_pages);
+ ret = page_counter_limit(&memcg->tcp_mem.memory_allocated, nr_pages);
if (ret)
return ret;
- for (i = 0; i < 3; i++)
- cg_proto->sysctl_mem[i] = min_t(long, nr_pages,
- sysctl_tcp_mem[i]);
-
- if (nr_pages == PAGE_COUNTER_MAX)
- clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags);
- else {
+ if (!memcg->tcp_mem.active) {
/*
- * The active bit needs to be written after the static_key
+ * The active flag needs to be written after the static_key
* update. This is what guarantees that the socket activation
* function is the last one to run. See sock_update_memcg() for
* details, and note that we don't mark any socket as belonging
@@ -90,14 +64,9 @@ static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
* We never race with the readers in sock_update_memcg(),
* because when this value change, the code to process it is not
* patched in yet.
- *
- * The activated bit is used to guarantee that no two writers
- * will do the update in the same memcg. Without that, we can't
- * properly shutdown the static key.
*/
- if (!test_and_set_bit(MEMCG_SOCK_ACTIVATED, &cg_proto->flags))
- static_key_slow_inc(&memcg_socket_limit_enabled);
- set_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags);
+ static_branch_inc(&memcg_sockets_enabled_key);
+ memcg->tcp_mem.active = true;
}
return 0;
@@ -141,32 +110,32 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
- struct cg_proto *cg_proto = tcp_prot.proto_cgroup(memcg);
u64 val;
switch (cft->private) {
case RES_LIMIT:
- if (!cg_proto)
- return PAGE_COUNTER_MAX;
- val = cg_proto->memory_allocated.limit;
+ if (memcg == root_mem_cgroup)
+ val = PAGE_COUNTER_MAX;
+ else
+ val = memcg->tcp_mem.memory_allocated.limit;
val *= PAGE_SIZE;
break;
case RES_USAGE:
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
val = atomic_long_read(&tcp_memory_allocated);
else
- val = page_counter_read(&cg_proto->memory_allocated);
+ val = page_counter_read(&memcg->tcp_mem.memory_allocated);
val *= PAGE_SIZE;
break;
case RES_FAILCNT:
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return 0;
- val = cg_proto->memory_allocated.failcnt;
+ val = memcg->tcp_mem.memory_allocated.failcnt;
break;
case RES_MAX_USAGE:
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return 0;
- val = cg_proto->memory_allocated.watermark;
+ val = memcg->tcp_mem.memory_allocated.watermark;
val *= PAGE_SIZE;
break;
default:
@@ -179,19 +148,17 @@ static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg;
- struct cg_proto *cg_proto;
memcg = mem_cgroup_from_css(of_css(of));
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return nbytes;
switch (of_cft(of)->private) {
case RES_MAX_USAGE:
- page_counter_reset_watermark(&cg_proto->memory_allocated);
+ page_counter_reset_watermark(&memcg->tcp_mem.memory_allocated);
break;
case RES_FAILCNT:
- cg_proto->memory_allocated.failcnt = 0;
+ memcg->tcp_mem.memory_allocated.failcnt = 0;
break;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 412a920fe0ec..fda379cd600d 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2813,13 +2813,16 @@ begin_fwd:
*/
void sk_forced_mem_schedule(struct sock *sk, int size)
{
- int amt, status;
+ int amt;
if (size <= sk->sk_forward_alloc)
return;
amt = sk_mem_pages(size);
sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
- sk_memory_allocated_add(sk, amt, &status);
+ sk_memory_allocated_add(sk, amt);
+
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ mem_cgroup_charge_skmem(sk->sk_memcg, amt);
}
/* Send a FIN. The caller locks the socket for us.
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index db9f1c318afc..4ad8edb46f7c 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1889,9 +1889,6 @@ struct proto tcpv6_prot = {
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
-#ifdef CONFIG_MEMCG_KMEM
- .proto_cgroup = tcp_proto_cgroup,
-#endif
.clear_sk = tcp_v6_clear_sk,
.diag_destroy = tcp_abort,
};
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index f7fbdbabe50e..372855eeaf42 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -23,7 +23,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
- IP6_ECN_set_ce(inner_iph);
+ IP6_ECN_set_ce(skb, inner_iph);
}
/* Add encapsulation header.
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 8e63662c6fb0..f830326b3b1d 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -185,7 +185,7 @@ static int genl_allocate_reserve_groups(int n_groups, int *first_id)
}
}
- if (id >= mc_groups_longs * BITS_PER_LONG) {
+ if (id + n_groups > mc_groups_longs * BITS_PER_LONG) {
unsigned long new_longs = mc_groups_longs +
BITS_TO_LONGS(n_groups);
size_t nlen = new_longs * sizeof(unsigned long);
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index c88d0f2d3e01..2d59df521915 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1160,17 +1160,26 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct sw_flow_actions *acts,
struct sw_flow_key *key)
{
- int level = this_cpu_read(exec_actions_level);
- int err;
+ static const int ovs_recursion_limit = 5;
+ int err, level;
+
+ level = __this_cpu_inc_return(exec_actions_level);
+ if (unlikely(level > ovs_recursion_limit)) {
+ net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
+ ovs_dp_name(dp));
+ kfree_skb(skb);
+ err = -ENETDOWN;
+ goto out;
+ }
- this_cpu_inc(exec_actions_level);
err = do_execute_actions(dp, skb, key,
acts->actions, acts->actions_len);
- if (!level)
+ if (level == 1)
process_deferred_actions(dp);
- this_cpu_dec(exec_actions_level);
+out:
+ __this_cpu_dec(exec_actions_level);
return err;
}
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 91a8b004dc51..deadfdab1bc3 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -336,12 +336,10 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
unsigned short gso_type = skb_shinfo(skb)->gso_type;
struct sw_flow_key later_key;
struct sk_buff *segs, *nskb;
- struct ovs_skb_cb ovs_cb;
int err;
- ovs_cb = *OVS_CB(skb);
+ BUILD_BUG_ON(sizeof(*OVS_CB(skb)) > SKB_SGO_CB_OFFSET);
segs = __skb_gso_segment(skb, NETIF_F_SG, false);
- *OVS_CB(skb) = ovs_cb;
if (IS_ERR(segs))
return PTR_ERR(segs);
if (segs == NULL)
@@ -359,7 +357,6 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
/* Queue all of the segments. */
skb = segs;
do {
- *OVS_CB(skb) = ovs_cb;
if (gso_type & SKB_GSO_UDP && skb != segs)
key = &later_key;
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 52838eaa1582..2522a6175291 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -333,7 +333,7 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
if (!ep->base.bind_addr.port)
goto out;
t = sctp_epaddr_lookup_transport(ep, paddr);
- if (!t || t->asoc->temp)
+ if (!t)
goto out;
*transport = t;
diff --git a/net/sctp/input.c b/net/sctp/input.c
index d9a6e66c5c8a..bf61dfb8e09e 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -784,6 +784,7 @@ hit:
/* rhashtable for transport */
struct sctp_hash_cmp_arg {
+ const struct sctp_endpoint *ep;
const union sctp_addr *laddr;
const union sctp_addr *paddr;
const struct net *net;
@@ -797,15 +798,20 @@ static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg,
struct sctp_association *asoc = t->asoc;
const struct net *net = x->net;
- if (x->laddr->v4.sin_port != htons(asoc->base.bind_addr.port))
- return 1;
if (!sctp_cmp_addr_exact(&t->ipaddr, x->paddr))
return 1;
if (!net_eq(sock_net(asoc->base.sk), net))
return 1;
- if (!sctp_bind_addr_match(&asoc->base.bind_addr,
- x->laddr, sctp_sk(asoc->base.sk)))
- return 1;
+ if (x->ep) {
+ if (x->ep != asoc->ep)
+ return 1;
+ } else {
+ if (x->laddr->v4.sin_port != htons(asoc->base.bind_addr.port))
+ return 1;
+ if (!sctp_bind_addr_match(&asoc->base.bind_addr,
+ x->laddr, sctp_sk(asoc->base.sk)))
+ return 1;
+ }
return 0;
}
@@ -832,9 +838,11 @@ static inline u32 sctp_hash_key(const void *data, u32 len, u32 seed)
const struct sctp_hash_cmp_arg *x = data;
const union sctp_addr *paddr = x->paddr;
const struct net *net = x->net;
- u16 lport = x->laddr->v4.sin_port;
+ u16 lport;
u32 addr;
+ lport = x->ep ? htons(x->ep->base.bind_addr.port) :
+ x->laddr->v4.sin_port;
if (paddr->sa.sa_family == AF_INET6)
addr = jhash(&paddr->v6.sin6_addr, 16, seed);
else
@@ -864,12 +872,12 @@ void sctp_transport_hashtable_destroy(void)
void sctp_hash_transport(struct sctp_transport *t)
{
- struct sctp_sockaddr_entry *addr;
struct sctp_hash_cmp_arg arg;
- addr = list_entry(t->asoc->base.bind_addr.address_list.next,
- struct sctp_sockaddr_entry, list);
- arg.laddr = &addr->a;
+ if (t->asoc->temp)
+ return;
+
+ arg.ep = t->asoc->ep;
arg.paddr = &t->ipaddr;
arg.net = sock_net(t->asoc->base.sk);
@@ -881,6 +889,9 @@ reinsert:
void sctp_unhash_transport(struct sctp_transport *t)
{
+ if (t->asoc->temp)
+ return;
+
rhashtable_remove_fast(&sctp_transport_hashtable, &t->node,
sctp_hash_params);
}
@@ -891,6 +902,7 @@ struct sctp_transport *sctp_addrs_lookup_transport(
const union sctp_addr *paddr)
{
struct sctp_hash_cmp_arg arg = {
+ .ep = NULL,
.laddr = laddr,
.paddr = paddr,
.net = net,
@@ -904,13 +916,15 @@ struct sctp_transport *sctp_epaddr_lookup_transport(
const struct sctp_endpoint *ep,
const union sctp_addr *paddr)
{
- struct sctp_sockaddr_entry *addr;
struct net *net = sock_net(ep->base.sk);
+ struct sctp_hash_cmp_arg arg = {
+ .ep = ep,
+ .paddr = paddr,
+ .net = net,
+ };
- addr = list_entry(ep->base.bind_addr.address_list.next,
- struct sctp_sockaddr_entry, list);
-
- return sctp_addrs_lookup_transport(net, &addr->a, paddr);
+ return rhashtable_lookup_fast(&sctp_transport_hashtable, &arg,
+ sctp_hash_params);
}
/* Look up an association. */
@@ -923,7 +937,7 @@ static struct sctp_association *__sctp_lookup_association(
struct sctp_transport *t;
t = sctp_addrs_lookup_transport(net, local, peer);
- if (!t || t->dead || t->asoc->temp)
+ if (!t || t->dead)
return NULL;
sctp_association_hold(t->asoc);
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index dfa7eeccb537..684c5b31563b 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -310,7 +310,7 @@ static struct sctp_transport *sctp_transport_get_next(struct seq_file *seq)
static struct sctp_transport *sctp_transport_get_idx(struct seq_file *seq,
loff_t pos)
{
- void *obj;
+ void *obj = SEQ_START_TOKEN;
while (pos && (obj = sctp_transport_get_next(seq)) && !IS_ERR(obj))
pos--;
@@ -347,7 +347,7 @@ static void *sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
if (err)
return ERR_PTR(err);
- return *pos ? sctp_transport_get_idx(seq, *pos) : SEQ_START_TOKEN;
+ return sctp_transport_get_idx(seq, *pos);
}
static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
@@ -462,7 +462,7 @@ static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos)
if (err)
return ERR_PTR(err);
- return *pos ? sctp_transport_get_idx(seq, *pos) : SEQ_START_TOKEN;
+ return sctp_transport_get_idx(seq, *pos);
}
static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos)
diff --git a/net/socket.c b/net/socket.c
index 91c2de6f5020..c044d1e8508c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -294,7 +294,7 @@ static int init_inodecache(void)
0,
(SLAB_HWCACHE_ALIGN |
SLAB_RECLAIM_ACCOUNT |
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD | SLAB_ACCOUNT),
init_once);
if (sock_inode_cachep == NULL)
return -ENOMEM;
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c
index 59eeed43eda2..f0c6a8c78a56 100644
--- a/net/sunrpc/auth_gss/gss_rpc_upcall.c
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
@@ -326,6 +326,9 @@ int gssp_accept_sec_context_upcall(struct net *net,
if (data->found_creds && client_name.data != NULL) {
char *c;
+ data->creds.cr_raw_principal = kstrndup(client_name.data,
+ client_name.len, GFP_KERNEL);
+
data->creds.cr_principal = kstrndup(client_name.data,
client_name.len, GFP_KERNEL);
if (data->creds.cr_principal) {
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 23608eb0ded2..b7f21044f4d8 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1217,6 +1217,7 @@ static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
return -EINVAL;
memcpy(buf, &rpc_in6addr_loopback,
sizeof(rpc_in6addr_loopback));
+ break;
default:
dprintk("RPC: %s: address family not supported\n",
__func__);
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index d81186d34558..14f45bf0410c 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1500,7 +1500,7 @@ int register_rpc_pipefs(void)
rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
sizeof(struct rpc_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
+ SLAB_MEM_SPREAD|SLAB_ACCOUNT),
init_once);
if (!rpc_inode_cachep)
return -ENOMEM;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index a6cbb2104667..7422f28818b2 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -10,11 +10,13 @@
#include <linux/kthread.h>
#include <linux/slab.h>
#include <net/sock.h>
+#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/xprt.h>
#include <linux/module.h>
+#include <linux/netdevice.h>
#include <trace/events/sunrpc.h>
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
@@ -938,6 +940,49 @@ static void svc_age_temp_xprts(unsigned long closure)
mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
}
+/* Close temporary transports whose xpt_local matches server_addr immediately
+ * instead of waiting for them to be picked up by the timer.
+ *
+ * This is meant to be called from a notifier_block that runs when an ip
+ * address is deleted.
+ */
+void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
+{
+ struct svc_xprt *xprt;
+ struct svc_sock *svsk;
+ struct socket *sock;
+ struct list_head *le, *next;
+ LIST_HEAD(to_be_closed);
+ struct linger no_linger = {
+ .l_onoff = 1,
+ .l_linger = 0,
+ };
+
+ spin_lock_bh(&serv->sv_lock);
+ list_for_each_safe(le, next, &serv->sv_tempsocks) {
+ xprt = list_entry(le, struct svc_xprt, xpt_list);
+ if (rpc_cmp_addr(server_addr, (struct sockaddr *)
+ &xprt->xpt_local)) {
+ dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
+ list_move(le, &to_be_closed);
+ }
+ }
+ spin_unlock_bh(&serv->sv_lock);
+
+ while (!list_empty(&to_be_closed)) {
+ le = to_be_closed.next;
+ list_del_init(le);
+ xprt = list_entry(le, struct svc_xprt, xpt_list);
+ dprintk("svc_age_temp_xprts_now: closing %p\n", xprt);
+ svsk = container_of(xprt, struct svc_sock, sk_xprt);
+ sock = svsk->sk_sock;
+ kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
+ (char *)&no_linger, sizeof(no_linger));
+ svc_close_xprt(xprt);
+ }
+}
+EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
+
static void call_xpt_users(struct svc_xprt *xprt)
{
struct svc_xpt_user *u;
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index 79c0f3459b5c..69841db1f533 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -55,6 +55,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
spin_unlock(&authtab_lock);
rqstp->rq_auth_slack = 0;
+ init_svc_cred(&rqstp->rq_cred);
rqstp->rq_authop = aops;
return aops->accept(rqstp, authp);
@@ -63,6 +64,7 @@ EXPORT_SYMBOL_GPL(svc_authenticate);
int svc_set_client(struct svc_rqst *rqstp)
{
+ rqstp->rq_client = NULL;
return rqstp->rq_authop->set_client(rqstp);
}
EXPORT_SYMBOL_GPL(svc_set_client);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 621ca7b4a155..dfacdc95b3f5 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -728,10 +728,6 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
struct kvec *resv = &rqstp->rq_res.head[0];
struct svc_cred *cred = &rqstp->rq_cred;
- cred->cr_group_info = NULL;
- cred->cr_principal = NULL;
- rqstp->rq_client = NULL;
-
if (argv->iov_len < 3*4)
return SVC_GARBAGE;
@@ -794,10 +790,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
u32 slen, i;
int len = argv->iov_len;
- cred->cr_group_info = NULL;
- cred->cr_principal = NULL;
- rqstp->rq_client = NULL;
-
if ((len -= 3*4) < 0)
return SVC_GARBAGE;
diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c
index 2dcb44f69e53..cc1251d07297 100644
--- a/net/sunrpc/xprtrdma/backchannel.c
+++ b/net/sunrpc/xprtrdma/backchannel.c
@@ -15,7 +15,7 @@
# define RPCDBG_FACILITY RPCDBG_TRANS
#endif
-#define RPCRDMA_BACKCHANNEL_DEBUG
+#undef RPCRDMA_BACKCHANNEL_DEBUG
static void rpcrdma_bc_free_rqst(struct rpcrdma_xprt *r_xprt,
struct rpc_rqst *rqst)
@@ -42,8 +42,8 @@ static int rpcrdma_bc_setup_rqst(struct rpcrdma_xprt *r_xprt,
size_t size;
req = rpcrdma_create_req(r_xprt);
- if (!req)
- return -ENOMEM;
+ if (IS_ERR(req))
+ return PTR_ERR(req);
req->rl_backchannel = true;
size = RPCRDMA_INLINE_WRITE_THRESHOLD(rqst);
@@ -84,9 +84,7 @@ out_fail:
static int rpcrdma_bc_setup_reps(struct rpcrdma_xprt *r_xprt,
unsigned int count)
{
- struct rpcrdma_buffer *buffers = &r_xprt->rx_buf;
struct rpcrdma_rep *rep;
- unsigned long flags;
int rc = 0;
while (count--) {
@@ -98,9 +96,7 @@ static int rpcrdma_bc_setup_reps(struct rpcrdma_xprt *r_xprt,
break;
}
- spin_lock_irqsave(&buffers->rb_lock, flags);
- list_add(&rep->rr_list, &buffers->rb_recv_bufs);
- spin_unlock_irqrestore(&buffers->rb_lock, flags);
+ rpcrdma_recv_buffer_put(rep);
}
return rc;
@@ -140,6 +136,7 @@ int xprt_rdma_bc_setup(struct rpc_xprt *xprt, unsigned int reqs)
__func__);
goto out_free;
}
+ dprintk("RPC: %s: new rqst %p\n", __func__, rqst);
rqst->rq_xprt = &r_xprt->rx_xprt;
INIT_LIST_HEAD(&rqst->rq_list);
@@ -220,12 +217,14 @@ int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
rpclen = rqst->rq_svec[0].iov_len;
+#ifdef RPCRDMA_BACKCHANNEL_DEBUG
pr_info("RPC: %s: rpclen %zd headerp 0x%p lkey 0x%x\n",
__func__, rpclen, headerp, rdmab_lkey(req->rl_rdmabuf));
pr_info("RPC: %s: RPC/RDMA: %*ph\n",
__func__, (int)RPCRDMA_HDRLEN_MIN, headerp);
pr_info("RPC: %s: RPC: %*ph\n",
__func__, (int)rpclen, rqst->rq_svec[0].iov_base);
+#endif
req->rl_send_iov[0].addr = rdmab_addr(req->rl_rdmabuf);
req->rl_send_iov[0].length = RPCRDMA_HDRLEN_MIN;
@@ -269,6 +268,9 @@ void xprt_rdma_bc_free_rqst(struct rpc_rqst *rqst)
{
struct rpc_xprt *xprt = rqst->rq_xprt;
+ dprintk("RPC: %s: freeing rqst %p (req %p)\n",
+ __func__, rqst, rpcr_to_rdmar(rqst));
+
smp_mb__before_atomic();
WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state));
clear_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state);
@@ -333,9 +335,7 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
struct rpc_rqst, rq_bc_pa_list);
list_del(&rqst->rq_bc_pa_list);
spin_unlock(&xprt->bc_pa_lock);
-#ifdef RPCRDMA_BACKCHANNEL_DEBUG
- pr_info("RPC: %s: using rqst %p\n", __func__, rqst);
-#endif
+ dprintk("RPC: %s: using rqst %p\n", __func__, rqst);
/* Prepare rqst */
rqst->rq_reply_bytes_recvd = 0;
@@ -355,10 +355,8 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
* direction reply.
*/
req = rpcr_to_rdmar(rqst);
-#ifdef RPCRDMA_BACKCHANNEL_DEBUG
- pr_info("RPC: %s: attaching rep %p to req %p\n",
+ dprintk("RPC: %s: attaching rep %p to req %p\n",
__func__, rep, req);
-#endif
req->rl_reply = rep;
/* Defeat the retransmit detection logic in send_request */
diff --git a/net/sunrpc/xprtrdma/fmr_ops.c b/net/sunrpc/xprtrdma/fmr_ops.c
index f1e8dafbd507..c14f3a4bff68 100644
--- a/net/sunrpc/xprtrdma/fmr_ops.c
+++ b/net/sunrpc/xprtrdma/fmr_ops.c
@@ -179,6 +179,69 @@ out_maperr:
return rc;
}
+static void
+__fmr_dma_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg)
+{
+ struct ib_device *device = r_xprt->rx_ia.ri_device;
+ struct rpcrdma_mw *mw = seg->rl_mw;
+ int nsegs = seg->mr_nsegs;
+
+ seg->rl_mw = NULL;
+
+ while (nsegs--)
+ rpcrdma_unmap_one(device, seg++);
+
+ rpcrdma_put_mw(r_xprt, mw);
+}
+
+/* Invalidate all memory regions that were registered for "req".
+ *
+ * Sleeps until it is safe for the host CPU to access the
+ * previously mapped memory regions.
+ */
+static void
+fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
+{
+ struct rpcrdma_mr_seg *seg;
+ unsigned int i, nchunks;
+ struct rpcrdma_mw *mw;
+ LIST_HEAD(unmap_list);
+ int rc;
+
+ dprintk("RPC: %s: req %p\n", __func__, req);
+
+ /* ORDER: Invalidate all of the req's MRs first
+ *
+ * ib_unmap_fmr() is slow, so use a single call instead
+ * of one call per mapped MR.
+ */
+ for (i = 0, nchunks = req->rl_nchunks; nchunks; nchunks--) {
+ seg = &req->rl_segments[i];
+ mw = seg->rl_mw;
+
+ list_add(&mw->r.fmr.fmr->list, &unmap_list);
+
+ i += seg->mr_nsegs;
+ }
+ rc = ib_unmap_fmr(&unmap_list);
+ if (rc)
+ pr_warn("%s: ib_unmap_fmr failed (%i)\n", __func__, rc);
+
+ /* ORDER: Now DMA unmap all of the req's MRs, and return
+ * them to the free MW list.
+ */
+ for (i = 0, nchunks = req->rl_nchunks; nchunks; nchunks--) {
+ seg = &req->rl_segments[i];
+
+ __fmr_dma_unmap(r_xprt, seg);
+
+ i += seg->mr_nsegs;
+ seg->mr_nsegs = 0;
+ }
+
+ req->rl_nchunks = 0;
+}
+
/* Use the ib_unmap_fmr() verb to prevent further remote
* access via RDMA READ or RDMA WRITE.
*/
@@ -231,6 +294,7 @@ fmr_op_destroy(struct rpcrdma_buffer *buf)
const struct rpcrdma_memreg_ops rpcrdma_fmr_memreg_ops = {
.ro_map = fmr_op_map,
+ .ro_unmap_sync = fmr_op_unmap_sync,
.ro_unmap = fmr_op_unmap,
.ro_open = fmr_op_open,
.ro_maxpages = fmr_op_maxpages,
diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c
index 88cf9e7269c2..c6836844bd0e 100644
--- a/net/sunrpc/xprtrdma/frwr_ops.c
+++ b/net/sunrpc/xprtrdma/frwr_ops.c
@@ -245,12 +245,14 @@ frwr_op_maxpages(struct rpcrdma_xprt *r_xprt)
rpcrdma_max_segments(r_xprt) * ia->ri_max_frmr_depth);
}
-/* If FAST_REG or LOCAL_INV failed, indicate the frmr needs to be reset. */
+/* If FAST_REG or LOCAL_INV failed, indicate the frmr needs
+ * to be reset.
+ *
+ * WARNING: Only wr_id and status are reliable at this point
+ */
static void
-frwr_sendcompletion(struct ib_wc *wc)
+__frwr_sendcompletion_flush(struct ib_wc *wc, struct rpcrdma_mw *r)
{
- struct rpcrdma_mw *r;
-
if (likely(wc->status == IB_WC_SUCCESS))
return;
@@ -261,9 +263,23 @@ frwr_sendcompletion(struct ib_wc *wc)
else
pr_warn("RPC: %s: frmr %p error, status %s (%d)\n",
__func__, r, ib_wc_status_msg(wc->status), wc->status);
+
r->r.frmr.fr_state = FRMR_IS_STALE;
}
+static void
+frwr_sendcompletion(struct ib_wc *wc)
+{
+ struct rpcrdma_mw *r = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
+ struct rpcrdma_frmr *f = &r->r.frmr;
+
+ if (unlikely(wc->status != IB_WC_SUCCESS))
+ __frwr_sendcompletion_flush(wc, r);
+
+ if (f->fr_waiter)
+ complete(&f->fr_linv_done);
+}
+
static int
frwr_op_init(struct rpcrdma_xprt *r_xprt)
{
@@ -319,7 +335,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
struct rpcrdma_mw *mw;
struct rpcrdma_frmr *frmr;
struct ib_mr *mr;
- struct ib_reg_wr reg_wr;
+ struct ib_reg_wr *reg_wr;
struct ib_send_wr *bad_wr;
int rc, i, n, dma_nents;
u8 key;
@@ -335,7 +351,9 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
} while (mw->r.frmr.fr_state != FRMR_IS_INVALID);
frmr = &mw->r.frmr;
frmr->fr_state = FRMR_IS_VALID;
+ frmr->fr_waiter = false;
mr = frmr->fr_mr;
+ reg_wr = &frmr->fr_regwr;
if (nsegs > ia->ri_max_frmr_depth)
nsegs = ia->ri_max_frmr_depth;
@@ -381,19 +399,19 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
key = (u8)(mr->rkey & 0x000000FF);
ib_update_fast_reg_key(mr, ++key);
- reg_wr.wr.next = NULL;
- reg_wr.wr.opcode = IB_WR_REG_MR;
- reg_wr.wr.wr_id = (uintptr_t)mw;
- reg_wr.wr.num_sge = 0;
- reg_wr.wr.send_flags = 0;
- reg_wr.mr = mr;
- reg_wr.key = mr->rkey;
- reg_wr.access = writing ?
- IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
- IB_ACCESS_REMOTE_READ;
+ reg_wr->wr.next = NULL;
+ reg_wr->wr.opcode = IB_WR_REG_MR;
+ reg_wr->wr.wr_id = (uintptr_t)mw;
+ reg_wr->wr.num_sge = 0;
+ reg_wr->wr.send_flags = 0;
+ reg_wr->mr = mr;
+ reg_wr->key = mr->rkey;
+ reg_wr->access = writing ?
+ IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
+ IB_ACCESS_REMOTE_READ;
DECR_CQCOUNT(&r_xprt->rx_ep);
- rc = ib_post_send(ia->ri_id->qp, &reg_wr.wr, &bad_wr);
+ rc = ib_post_send(ia->ri_id->qp, &reg_wr->wr, &bad_wr);
if (rc)
goto out_senderr;
@@ -413,6 +431,116 @@ out_senderr:
return rc;
}
+static struct ib_send_wr *
+__frwr_prepare_linv_wr(struct rpcrdma_mr_seg *seg)
+{
+ struct rpcrdma_mw *mw = seg->rl_mw;
+ struct rpcrdma_frmr *f = &mw->r.frmr;
+ struct ib_send_wr *invalidate_wr;
+
+ f->fr_waiter = false;
+ f->fr_state = FRMR_IS_INVALID;
+ invalidate_wr = &f->fr_invwr;
+
+ memset(invalidate_wr, 0, sizeof(*invalidate_wr));
+ invalidate_wr->wr_id = (unsigned long)(void *)mw;
+ invalidate_wr->opcode = IB_WR_LOCAL_INV;
+ invalidate_wr->ex.invalidate_rkey = f->fr_mr->rkey;
+
+ return invalidate_wr;
+}
+
+static void
+__frwr_dma_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
+ int rc)
+{
+ struct ib_device *device = r_xprt->rx_ia.ri_device;
+ struct rpcrdma_mw *mw = seg->rl_mw;
+ struct rpcrdma_frmr *f = &mw->r.frmr;
+
+ seg->rl_mw = NULL;
+
+ ib_dma_unmap_sg(device, f->sg, f->sg_nents, seg->mr_dir);
+
+ if (!rc)
+ rpcrdma_put_mw(r_xprt, mw);
+ else
+ __frwr_queue_recovery(mw);
+}
+
+/* Invalidate all memory regions that were registered for "req".
+ *
+ * Sleeps until it is safe for the host CPU to access the
+ * previously mapped memory regions.
+ */
+static void
+frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
+{
+ struct ib_send_wr *invalidate_wrs, *pos, *prev, *bad_wr;
+ struct rpcrdma_ia *ia = &r_xprt->rx_ia;
+ struct rpcrdma_mr_seg *seg;
+ unsigned int i, nchunks;
+ struct rpcrdma_frmr *f;
+ int rc;
+
+ dprintk("RPC: %s: req %p\n", __func__, req);
+
+ /* ORDER: Invalidate all of the req's MRs first
+ *
+ * Chain the LOCAL_INV Work Requests and post them with
+ * a single ib_post_send() call.
+ */
+ invalidate_wrs = pos = prev = NULL;
+ seg = NULL;
+ for (i = 0, nchunks = req->rl_nchunks; nchunks; nchunks--) {
+ seg = &req->rl_segments[i];
+
+ pos = __frwr_prepare_linv_wr(seg);
+
+ if (!invalidate_wrs)
+ invalidate_wrs = pos;
+ else
+ prev->next = pos;
+ prev = pos;
+
+ i += seg->mr_nsegs;
+ }
+ f = &seg->rl_mw->r.frmr;
+
+ /* Strong send queue ordering guarantees that when the
+ * last WR in the chain completes, all WRs in the chain
+ * are complete.
+ */
+ f->fr_invwr.send_flags = IB_SEND_SIGNALED;
+ f->fr_waiter = true;
+ init_completion(&f->fr_linv_done);
+ INIT_CQCOUNT(&r_xprt->rx_ep);
+
+ /* Transport disconnect drains the receive CQ before it
+ * replaces the QP. The RPC reply handler won't call us
+ * unless ri_id->qp is a valid pointer.
+ */
+ rc = ib_post_send(ia->ri_id->qp, invalidate_wrs, &bad_wr);
+ if (rc)
+ pr_warn("%s: ib_post_send failed %i\n", __func__, rc);
+
+ wait_for_completion(&f->fr_linv_done);
+
+ /* ORDER: Now DMA unmap all of the req's MRs, and return
+ * them to the free MW list.
+ */
+ for (i = 0, nchunks = req->rl_nchunks; nchunks; nchunks--) {
+ seg = &req->rl_segments[i];
+
+ __frwr_dma_unmap(r_xprt, seg, rc);
+
+ i += seg->mr_nsegs;
+ seg->mr_nsegs = 0;
+ }
+
+ req->rl_nchunks = 0;
+}
+
/* Post a LOCAL_INV Work Request to prevent further remote access
* via RDMA READ or RDMA WRITE.
*/
@@ -423,23 +551,24 @@ frwr_op_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg)
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
struct rpcrdma_mw *mw = seg1->rl_mw;
struct rpcrdma_frmr *frmr = &mw->r.frmr;
- struct ib_send_wr invalidate_wr, *bad_wr;
+ struct ib_send_wr *invalidate_wr, *bad_wr;
int rc, nsegs = seg->mr_nsegs;
dprintk("RPC: %s: FRMR %p\n", __func__, mw);
seg1->rl_mw = NULL;
frmr->fr_state = FRMR_IS_INVALID;
+ invalidate_wr = &mw->r.frmr.fr_invwr;
- memset(&invalidate_wr, 0, sizeof(invalidate_wr));
- invalidate_wr.wr_id = (unsigned long)(void *)mw;
- invalidate_wr.opcode = IB_WR_LOCAL_INV;
- invalidate_wr.ex.invalidate_rkey = frmr->fr_mr->rkey;
+ memset(invalidate_wr, 0, sizeof(*invalidate_wr));
+ invalidate_wr->wr_id = (uintptr_t)mw;
+ invalidate_wr->opcode = IB_WR_LOCAL_INV;
+ invalidate_wr->ex.invalidate_rkey = frmr->fr_mr->rkey;
DECR_CQCOUNT(&r_xprt->rx_ep);
ib_dma_unmap_sg(ia->ri_device, frmr->sg, frmr->sg_nents, seg1->mr_dir);
read_lock(&ia->ri_qplock);
- rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
+ rc = ib_post_send(ia->ri_id->qp, invalidate_wr, &bad_wr);
read_unlock(&ia->ri_qplock);
if (rc)
goto out_err;
@@ -471,6 +600,7 @@ frwr_op_destroy(struct rpcrdma_buffer *buf)
const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = {
.ro_map = frwr_op_map,
+ .ro_unmap_sync = frwr_op_unmap_sync,
.ro_unmap = frwr_op_unmap,
.ro_open = frwr_op_open,
.ro_maxpages = frwr_op_maxpages,
diff --git a/net/sunrpc/xprtrdma/physical_ops.c b/net/sunrpc/xprtrdma/physical_ops.c
index 617b76f22154..dbb302ecf590 100644
--- a/net/sunrpc/xprtrdma/physical_ops.c
+++ b/net/sunrpc/xprtrdma/physical_ops.c
@@ -83,6 +83,18 @@ physical_op_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg)
return 1;
}
+/* DMA unmap all memory regions that were mapped for "req".
+ */
+static void
+physical_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
+{
+ struct ib_device *device = r_xprt->rx_ia.ri_device;
+ unsigned int i;
+
+ for (i = 0; req->rl_nchunks; --req->rl_nchunks)
+ rpcrdma_unmap_one(device, &req->rl_segments[i++]);
+}
+
static void
physical_op_destroy(struct rpcrdma_buffer *buf)
{
@@ -90,6 +102,7 @@ physical_op_destroy(struct rpcrdma_buffer *buf)
const struct rpcrdma_memreg_ops rpcrdma_physical_memreg_ops = {
.ro_map = physical_op_map,
+ .ro_unmap_sync = physical_op_unmap_sync,
.ro_unmap = physical_op_unmap,
.ro_open = physical_op_open,
.ro_maxpages = physical_op_maxpages,
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index c10d9699441c..0f28f2d743ed 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -804,6 +804,11 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
if (req->rl_reply)
goto out_duplicate;
+ /* Sanity checking has passed. We are now committed
+ * to complete this transaction.
+ */
+ list_del_init(&rqst->rq_list);
+ spin_unlock_bh(&xprt->transport_lock);
dprintk("RPC: %s: reply 0x%p completes request 0x%p\n"
" RPC request 0x%p xid 0x%08x\n",
__func__, rep, req, rqst,
@@ -888,12 +893,23 @@ badheader:
break;
}
+ /* Invalidate and flush the data payloads before waking the
+ * waiting application. This guarantees the memory region is
+ * properly fenced from the server before the application
+ * accesses the data. It also ensures proper send flow
+ * control: waking the next RPC waits until this RPC has
+ * relinquished all its Send Queue entries.
+ */
+ if (req->rl_nchunks)
+ r_xprt->rx_ia.ri_ops->ro_unmap_sync(r_xprt, req);
+
credits = be32_to_cpu(headerp->rm_credit);
if (credits == 0)
credits = 1; /* don't deadlock */
else if (credits > r_xprt->rx_buf.rb_max_requests)
credits = r_xprt->rx_buf.rb_max_requests;
+ spin_lock_bh(&xprt->transport_lock);
cwnd = xprt->cwnd;
xprt->cwnd = credits << RPC_CWNDSHIFT;
if (xprt->cwnd > cwnd)
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 8c545f7d7525..740bddcf3488 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -576,6 +576,9 @@ xprt_rdma_free(void *buffer)
rb = container_of(buffer, struct rpcrdma_regbuf, rg_base[0]);
req = rb->rg_owner;
+ if (req->rl_backchannel)
+ return;
+
r_xprt = container_of(req->rl_buffer, struct rpcrdma_xprt, rx_buf);
dprintk("RPC: %s: called on 0x%p\n", __func__, req->rl_reply);
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index eadd1655145a..732c71ce5dca 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -616,10 +616,8 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
/* set trigger for requesting send completion */
ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 - 1;
- if (ep->rep_cqinit > RPCRDMA_MAX_UNSIGNALED_SENDS)
- ep->rep_cqinit = RPCRDMA_MAX_UNSIGNALED_SENDS;
- else if (ep->rep_cqinit <= 2)
- ep->rep_cqinit = 0;
+ if (ep->rep_cqinit <= 2)
+ ep->rep_cqinit = 0; /* always signal? */
INIT_CQCOUNT(ep);
init_waitqueue_head(&ep->rep_connect_wait);
INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker);
@@ -852,10 +850,11 @@ retry:
if (extras) {
rc = rpcrdma_ep_post_extra_recv(r_xprt, extras);
- if (rc)
+ if (rc) {
pr_warn("%s: rpcrdma_ep_post_extra_recv: %i\n",
__func__, rc);
rc = 0;
+ }
}
}
@@ -1337,15 +1336,14 @@ rpcrdma_ep_post_extra_recv(struct rpcrdma_xprt *r_xprt, unsigned int count)
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
struct rpcrdma_ep *ep = &r_xprt->rx_ep;
struct rpcrdma_rep *rep;
- unsigned long flags;
int rc;
while (count--) {
- spin_lock_irqsave(&buffers->rb_lock, flags);
+ spin_lock(&buffers->rb_lock);
if (list_empty(&buffers->rb_recv_bufs))
goto out_reqbuf;
rep = rpcrdma_buffer_get_rep_locked(buffers);
- spin_unlock_irqrestore(&buffers->rb_lock, flags);
+ spin_unlock(&buffers->rb_lock);
rc = rpcrdma_ep_post_recv(ia, ep, rep);
if (rc)
@@ -1355,7 +1353,7 @@ rpcrdma_ep_post_extra_recv(struct rpcrdma_xprt *r_xprt, unsigned int count)
return 0;
out_reqbuf:
- spin_unlock_irqrestore(&buffers->rb_lock, flags);
+ spin_unlock(&buffers->rb_lock);
pr_warn("%s: no extra receive buffers\n", __func__);
return -ENOMEM;
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index ac7f8d4f632a..728101ddc44b 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -88,12 +88,6 @@ struct rpcrdma_ep {
struct delayed_work rep_connect_worker;
};
-/*
- * Force a signaled SEND Work Request every so often,
- * in case the provider needs to do some housekeeping.
- */
-#define RPCRDMA_MAX_UNSIGNALED_SENDS (32)
-
#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
#define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount)
@@ -207,6 +201,12 @@ struct rpcrdma_frmr {
enum rpcrdma_frmr_state fr_state;
struct work_struct fr_work;
struct rpcrdma_xprt *fr_xprt;
+ bool fr_waiter;
+ struct completion fr_linv_done;;
+ union {
+ struct ib_reg_wr fr_regwr;
+ struct ib_send_wr fr_invwr;
+ };
};
struct rpcrdma_fmr {
@@ -364,6 +364,8 @@ struct rpcrdma_xprt;
struct rpcrdma_memreg_ops {
int (*ro_map)(struct rpcrdma_xprt *,
struct rpcrdma_mr_seg *, int, bool);
+ void (*ro_unmap_sync)(struct rpcrdma_xprt *,
+ struct rpcrdma_req *);
int (*ro_unmap)(struct rpcrdma_xprt *,
struct rpcrdma_mr_seg *);
int (*ro_open)(struct rpcrdma_ia *,
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 2ffaf6a79499..fde2138b81e7 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -398,7 +398,6 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
if (unlikely(!sock))
return -ENOTSOCK;
- clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags);
if (base != 0) {
addr = NULL;
addrlen = 0;
@@ -442,7 +441,6 @@ static void xs_nospace_callback(struct rpc_task *task)
struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
transport->inet->sk_write_pending--;
- clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
}
/**
@@ -467,20 +465,11 @@ static int xs_nospace(struct rpc_task *task)
/* Don't race with disconnect */
if (xprt_connected(xprt)) {
- if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) {
- /*
- * Notify TCP that we're limited by the application
- * window size
- */
- set_bit(SOCK_NOSPACE, &transport->sock->flags);
- sk->sk_write_pending++;
- /* ...and wait for more buffer space */
- xprt_wait_for_buffer_space(task, xs_nospace_callback);
- }
- } else {
- clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
+ /* wait for more buffer space */
+ sk->sk_write_pending++;
+ xprt_wait_for_buffer_space(task, xs_nospace_callback);
+ } else
ret = -ENOTCONN;
- }
spin_unlock_bh(&xprt->transport_lock);
@@ -616,9 +605,6 @@ process_status:
case -EAGAIN:
status = xs_nospace(task);
break;
- default:
- dprintk("RPC: sendmsg returned unrecognized error %d\n",
- -status);
case -ENETUNREACH:
case -ENOBUFS:
case -EPIPE:
@@ -626,7 +612,10 @@ process_status:
case -EPERM:
/* When the server has died, an ICMP port unreachable message
* prompts ECONNREFUSED. */
- clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
+ break;
+ default:
+ dprintk("RPC: sendmsg returned unrecognized error %d\n",
+ -status);
}
return status;
@@ -706,16 +695,16 @@ static int xs_tcp_send_request(struct rpc_task *task)
case -EAGAIN:
status = xs_nospace(task);
break;
- default:
- dprintk("RPC: sendmsg returned unrecognized error %d\n",
- -status);
case -ECONNRESET:
case -ECONNREFUSED:
case -ENOTCONN:
case -EADDRINUSE:
case -ENOBUFS:
case -EPIPE:
- clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
+ break;
+ default:
+ dprintk("RPC: sendmsg returned unrecognized error %d\n",
+ -status);
}
return status;
@@ -1609,19 +1598,23 @@ static void xs_tcp_state_change(struct sock *sk)
static void xs_write_space(struct sock *sk)
{
- struct socket *sock;
+ struct socket_wq *wq;
struct rpc_xprt *xprt;
- if (unlikely(!(sock = sk->sk_socket)))
+ if (!sk->sk_socket)
return;
- clear_bit(SOCK_NOSPACE, &sock->flags);
+ clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
if (unlikely(!(xprt = xprt_from_sock(sk))))
return;
- if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0)
- return;
+ rcu_read_lock();
+ wq = rcu_dereference(sk->sk_wq);
+ if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
+ goto out;
xprt_write_space(xprt);
+out:
+ rcu_read_unlock();
}
/**
@@ -1907,18 +1900,6 @@ static inline void xs_reclassify_socket(int family, struct socket *sock)
}
}
#else
-static inline void xs_reclassify_socketu(struct socket *sock)
-{
-}
-
-static inline void xs_reclassify_socket4(struct socket *sock)
-{
-}
-
-static inline void xs_reclassify_socket6(struct socket *sock)
-{
-}
-
static inline void xs_reclassify_socket(int family, struct socket *sock)
{
}
@@ -2008,7 +1989,7 @@ static int xs_local_setup_socket(struct sock_xprt *transport)
"transport socket (%d).\n", -status);
goto out;
}
- xs_reclassify_socketu(sock);
+ xs_reclassify_socket(AF_LOCAL, sock);
dprintk("RPC: worker connecting xprt %p via AF_LOCAL to %s\n",
xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index cc3676eb6239..ff4a91fcab9f 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -167,6 +167,8 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb
{
struct sk_buff *segs;
+ BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
+ BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET);
segs = skb_gso_segment(skb, 0);
kfree_skb(skb);
if (IS_ERR(segs))
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 01df30af4d4a..2c47f9c305aa 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -372,10 +372,14 @@ endif
# <composite-object>-objs := <list of .o files>
# or
# <composite-object>-y := <list of .o files>
+# or
+# <composite-object>-m := <list of .o files>
+# The -m syntax only works if <composite object> is a module
link_multi_deps = \
$(filter $(addprefix $(obj)/, \
$($(subst $(obj)/,,$(@:.o=-objs))) \
-$($(subst $(obj)/,,$(@:.o=-y)))), $^)
+$($(subst $(obj)/,,$(@:.o=-y))) \
+$($(subst $(obj)/,,$(@:.o=-m)))), $^)
quiet_cmd_link_multi-y = LD $@
cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
@@ -390,7 +394,7 @@ $(call multi_depend, $(multi-used-y), .o, -objs -y)
$(multi-used-m): FORCE
$(call if_changed,link_multi-m)
@{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
-$(call multi_depend, $(multi-used-m), .o, -objs -y)
+$(call multi_depend, $(multi-used-m), .o, -objs -y -m)
targets += $(multi-used-y) $(multi-used-m)
diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn
index 4efedcbe4165..f9e47a70509c 100644
--- a/scripts/Makefile.extrawarn
+++ b/scripts/Makefile.extrawarn
@@ -25,6 +25,7 @@ warning-1 += -Wold-style-definition
warning-1 += $(call cc-option, -Wmissing-include-dirs)
warning-1 += $(call cc-option, -Wunused-but-set-variable)
warning-1 += $(call cc-disable-warning, missing-field-initializers)
+warning-1 += $(call cc-disable-warning, sign-compare)
warning-2 := -Waggregate-return
warning-2 += -Wcast-align
@@ -33,6 +34,7 @@ warning-2 += -Wnested-externs
warning-2 += -Wshadow
warning-2 += $(call cc-option, -Wlogical-op)
warning-2 += $(call cc-option, -Wmissing-field-initializers)
+warning-2 += $(call cc-option, -Wsign-compare)
warning-3 := -Wbad-function-cast
warning-3 += -Wcast-qual
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 79e86613712f..39d6bb18ce76 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -48,7 +48,7 @@ subdir-ym := $(sort $(subdir-y) $(subdir-m))
# if $(foo-objs) exists, foo.o is a composite object
multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
-multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
+multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))), $(m))))
multi-used := $(multi-used-y) $(multi-used-m)
single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
@@ -67,7 +67,7 @@ obj-dirs := $(dir $(multi-objs) $(obj-y))
# Replace multi-part objects by their individual parts, look at local dir only
real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y)
-real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
+real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m)))
# Add subdir path
@@ -104,8 +104,9 @@ modname_flags = $(if $(filter 1,$(words $(modname))),\
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
$(ccflags-y) $(CFLAGS_$(basetarget).o)
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
-_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
+orig_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
$(asflags-y) $(AFLAGS_$(basetarget).o)
+_a_flags = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags))
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
#
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index c68fd61fdc42..5b327c67a828 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -251,7 +251,7 @@ static void parse_config_file(const char *map, size_t len)
}
/* test is s ends in sub */
-static int strrcmp(char *s, char *sub)
+static int strrcmp(const char *s, const char *sub)
{
int slen = strlen(s);
int sublen = strlen(sub);
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index 23e78dcd12bf..38b64f487315 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -58,8 +58,8 @@ for name in common:
delta.sort()
delta.reverse()
-print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
- (add, remove, grow, shrink, up, -down, up-down)
-print "%-40s %7s %7s %+7s" % ("function", "old", "new", "delta")
+print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
+ (add, remove, grow, shrink, up, -down, up-down))
+print("%-40s %7s %7s %+7s" % ("function", "old", "new", "delta"))
for d, n in delta:
- if d: print "%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d)
+ if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d))
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py
index 2f4b7ffd5570..d8f6c094cce5 100755
--- a/scripts/checkkconfigsymbols.py
+++ b/scripts/checkkconfigsymbols.py
@@ -8,11 +8,14 @@
# Licensed under the terms of the GNU GPL License version 2
+import difflib
import os
import re
+import signal
import sys
-from subprocess import Popen, PIPE, STDOUT
+from multiprocessing import Pool, cpu_count
from optparse import OptionParser
+from subprocess import Popen, PIPE, STDOUT
# regex expressions
@@ -26,7 +29,7 @@ SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")"
# regex objects
REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
-REGEX_FEATURE = re.compile(r'(?!\B"[^"]*)' + FEATURE + r'(?![^"]*"\B)')
+REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)')
REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE)
REGEX_KCONFIG_DEF = re.compile(DEF)
REGEX_KCONFIG_EXPR = re.compile(EXPR)
@@ -34,6 +37,7 @@ REGEX_KCONFIG_STMT = re.compile(STMT)
REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$")
REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$")
REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+")
+REGEX_QUOTES = re.compile("(\"(.*?)\")")
def parse_options():
@@ -71,6 +75,9 @@ def parse_options():
"the pattern needs to be a Python regex. To "
"ignore defconfigs, specify -i '.*defconfig'.")
+ parser.add_option('-s', '--sim', dest='sim', action='store', default="",
+ help="Print a list of maximum 10 string-similar symbols.")
+
parser.add_option('', '--force', dest='force', action='store_true',
default=False,
help="Reset current Git tree even when it's dirty.")
@@ -109,6 +116,18 @@ def main():
"""Main function of this module."""
opts = parse_options()
+ if opts.sim and not opts.commit and not opts.diff:
+ sims = find_sims(opts.sim, opts.ignore)
+ if sims:
+ print "%s: %s" % (yel("Similar symbols"), ', '.join(sims))
+ else:
+ print "%s: no similar symbols found" % yel("Similar symbols")
+ sys.exit(0)
+
+ # dictionary of (un)defined symbols
+ defined = {}
+ undefined = {}
+
if opts.commit or opts.diff:
head = get_head()
@@ -127,40 +146,56 @@ def main():
# get undefined items before the commit
execute("git reset --hard %s" % commit_a)
- undefined_a = check_symbols(opts.ignore)
+ undefined_a, _ = check_symbols(opts.ignore)
# get undefined items for the commit
execute("git reset --hard %s" % commit_b)
- undefined_b = check_symbols(opts.ignore)
+ undefined_b, defined = check_symbols(opts.ignore)
# report cases that are present for the commit but not before
for feature in sorted(undefined_b):
# feature has not been undefined before
if not feature in undefined_a:
files = sorted(undefined_b.get(feature))
- print "%s\t%s" % (yel(feature), ", ".join(files))
- if opts.find:
- commits = find_commits(feature, opts.diff)
- print red(commits)
+ undefined[feature] = files
# check if there are new files that reference the undefined feature
else:
files = sorted(undefined_b.get(feature) -
undefined_a.get(feature))
if files:
- print "%s\t%s" % (yel(feature), ", ".join(files))
- if opts.find:
- commits = find_commits(feature, opts.diff)
- print red(commits)
+ undefined[feature] = files
# reset to head
execute("git reset --hard %s" % head)
# default to check the entire tree
else:
- undefined = check_symbols(opts.ignore)
- for feature in sorted(undefined):
- files = sorted(undefined.get(feature))
- print "%s\t%s" % (yel(feature), ", ".join(files))
+ undefined, defined = check_symbols(opts.ignore)
+
+ # now print the output
+ for feature in sorted(undefined):
+ print red(feature)
+
+ files = sorted(undefined.get(feature))
+ print "%s: %s" % (yel("Referencing files"), ", ".join(files))
+
+ sims = find_sims(feature, opts.ignore, defined)
+ sims_out = yel("Similar symbols")
+ if sims:
+ print "%s: %s" % (sims_out, ', '.join(sims))
+ else:
+ print "%s: %s" % (sims_out, "no similar symbols found")
+
+ if opts.find:
+ print "%s:" % yel("Commits changing symbol")
+ commits = find_commits(feature, opts.diff)
+ if commits:
+ for commit in commits:
+ commit = commit.split(" ", 1)
+ print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1])
+ else:
+ print "\t- no commit found"
+ print # new line
def yel(string):
@@ -190,7 +225,7 @@ def find_commits(symbol, diff):
"""Find commits changing %symbol in the given range of %diff."""
commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s"
% (symbol, diff))
- return commits
+ return [x for x in commits.split("\n") if x]
def tree_is_dirty():
@@ -209,43 +244,107 @@ def get_head():
return stdout.strip('\n')
-def check_symbols(ignore):
- """Find undefined Kconfig symbols and return a dict with the symbol as key
- and a list of referencing files as value. Files matching %ignore are not
- checked for undefined symbols."""
- source_files = []
- kconfig_files = []
- defined_features = set()
- referenced_features = dict() # {feature: [files]}
+def partition(lst, size):
+ """Partition list @lst into eveni-sized lists of size @size."""
+ return [lst[i::size] for i in xrange(size)]
+
+
+def init_worker():
+ """Set signal handler to ignore SIGINT."""
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+
+def find_sims(symbol, ignore, defined = []):
+ """Return a list of max. ten Kconfig symbols that are string-similar to
+ @symbol."""
+ if defined:
+ return sorted(difflib.get_close_matches(symbol, set(defined), 10))
+
+ pool = Pool(cpu_count(), init_worker)
+ kfiles = []
+ for gitfile in get_files():
+ if REGEX_FILE_KCONFIG.match(gitfile):
+ kfiles.append(gitfile)
+ arglist = []
+ for part in partition(kfiles, cpu_count()):
+ arglist.append((part, ignore))
+
+ for res in pool.map(parse_kconfig_files, arglist):
+ defined.extend(res[0])
+
+ return sorted(difflib.get_close_matches(symbol, set(defined), 10))
+
+
+def get_files():
+ """Return a list of all files in the current git directory."""
# use 'git ls-files' to get the worklist
stdout = execute("git ls-files")
if len(stdout) > 0 and stdout[-1] == "\n":
stdout = stdout[:-1]
+ files = []
for gitfile in stdout.rsplit("\n"):
if ".git" in gitfile or "ChangeLog" in gitfile or \
".log" in gitfile or os.path.isdir(gitfile) or \
gitfile.startswith("tools/"):
continue
+ files.append(gitfile)
+ return files
+
+
+def check_symbols(ignore):
+ """Find undefined Kconfig symbols and return a dict with the symbol as key
+ and a list of referencing files as value. Files matching %ignore are not
+ checked for undefined symbols."""
+ pool = Pool(cpu_count(), init_worker)
+ try:
+ return check_symbols_helper(pool, ignore)
+ except KeyboardInterrupt:
+ pool.terminate()
+ pool.join()
+ sys.exit(1)
+
+
+def check_symbols_helper(pool, ignore):
+ """Helper method for check_symbols(). Used to catch keyboard interrupts in
+ check_symbols() in order to properly terminate running worker processes."""
+ source_files = []
+ kconfig_files = []
+ defined_features = []
+ referenced_features = dict() # {file: [features]}
+
+ for gitfile in get_files():
if REGEX_FILE_KCONFIG.match(gitfile):
kconfig_files.append(gitfile)
else:
- # all non-Kconfig files are checked for consistency
+ if ignore and not re.match(ignore, gitfile):
+ continue
+ # add source files that do not match the ignore pattern
source_files.append(gitfile)
- for sfile in source_files:
- if ignore and re.match(ignore, sfile):
- # do not check files matching %ignore
- continue
- parse_source_file(sfile, referenced_features)
+ # parse source files
+ arglist = partition(source_files, cpu_count())
+ for res in pool.map(parse_source_files, arglist):
+ referenced_features.update(res)
- for kfile in kconfig_files:
- if ignore and re.match(ignore, kfile):
- # do not collect references for files matching %ignore
- parse_kconfig_file(kfile, defined_features, dict())
- else:
- parse_kconfig_file(kfile, defined_features, referenced_features)
+
+ # parse kconfig files
+ arglist = []
+ for part in partition(kconfig_files, cpu_count()):
+ arglist.append((part, ignore))
+ for res in pool.map(parse_kconfig_files, arglist):
+ defined_features.extend(res[0])
+ referenced_features.update(res[1])
+ defined_features = set(defined_features)
+
+ # inverse mapping of referenced_features to dict(feature: [files])
+ inv_map = dict()
+ for _file, features in referenced_features.iteritems():
+ for feature in features:
+ inv_map[feature] = inv_map.get(feature, set())
+ inv_map[feature].add(_file)
+ referenced_features = inv_map
undefined = {} # {feature: [files]}
for feature in sorted(referenced_features):
@@ -259,12 +358,26 @@ def check_symbols(ignore):
if feature[:-len("_MODULE")] in defined_features:
continue
undefined[feature] = referenced_features.get(feature)
- return undefined
+ return undefined, defined_features
-def parse_source_file(sfile, referenced_features):
- """Parse @sfile for referenced Kconfig features."""
+def parse_source_files(source_files):
+ """Parse each source file in @source_files and return dictionary with source
+ files as keys and lists of references Kconfig symbols as values."""
+ referenced_features = dict()
+ for sfile in source_files:
+ referenced_features[sfile] = parse_source_file(sfile)
+ return referenced_features
+
+
+def parse_source_file(sfile):
+ """Parse @sfile and return a list of referenced Kconfig features."""
lines = []
+ references = []
+
+ if not os.path.exists(sfile):
+ return references
+
with open(sfile, "r") as stream:
lines = stream.readlines()
@@ -275,9 +388,9 @@ def parse_source_file(sfile, referenced_features):
for feature in features:
if not REGEX_FILTER_FEATURES.search(feature):
continue
- sfiles = referenced_features.get(feature, set())
- sfiles.add(sfile)
- referenced_features[feature] = sfiles
+ references.append(feature)
+
+ return references
def get_features_in_line(line):
@@ -285,11 +398,35 @@ def get_features_in_line(line):
return REGEX_FEATURE.findall(line)
-def parse_kconfig_file(kfile, defined_features, referenced_features):
+def parse_kconfig_files(args):
+ """Parse kconfig files and return tuple of defined and references Kconfig
+ symbols. Note, @args is a tuple of a list of files and the @ignore
+ pattern."""
+ kconfig_files = args[0]
+ ignore = args[1]
+ defined_features = []
+ referenced_features = dict()
+
+ for kfile in kconfig_files:
+ defined, references = parse_kconfig_file(kfile)
+ defined_features.extend(defined)
+ if ignore and re.match(ignore, kfile):
+ # do not collect references for files that match the ignore pattern
+ continue
+ referenced_features[kfile] = references
+ return (defined_features, referenced_features)
+
+
+def parse_kconfig_file(kfile):
"""Parse @kfile and update feature definitions and references."""
lines = []
+ defined = []
+ references = []
skip = False
+ if not os.path.exists(kfile):
+ return defined, references
+
with open(kfile, "r") as stream:
lines = stream.readlines()
@@ -300,7 +437,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
if REGEX_KCONFIG_DEF.match(line):
feature_def = REGEX_KCONFIG_DEF.findall(line)
- defined_features.add(feature_def[0])
+ defined.append(feature_def[0])
skip = False
elif REGEX_KCONFIG_HELP.match(line):
skip = True
@@ -308,6 +445,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
# ignore content of help messages
pass
elif REGEX_KCONFIG_STMT.match(line):
+ line = REGEX_QUOTES.sub("", line)
features = get_features_in_line(line)
# multi-line statements
while line.endswith("\\"):
@@ -319,9 +457,9 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
if REGEX_NUMERIC.match(feature):
# ignore numeric values
continue
- paths = referenced_features.get(feature, set())
- paths.add(kfile)
- referenced_features[feature] = paths
+ references.append(feature)
+
+ return defined, references
if __name__ == "__main__":
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 2b3c22808c3b..c7bf1aa2eeb3 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -5116,13 +5116,44 @@ sub process {
}
}
# check for memory barriers without a comment.
- if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+
+ my $barriers = qr{
+ mb|
+ rmb|
+ wmb|
+ read_barrier_depends
+ }x;
+ my $barrier_stems = qr{
+ mb__before_atomic|
+ mb__after_atomic|
+ store_release|
+ load_acquire|
+ store_mb|
+ (?:$barriers)
+ }x;
+ my $all_barriers = qr{
+ (?:$barriers)|
+ smp_(?:$barrier_stems)|
+ virt_(?:$barrier_stems)
+ }x;
+
+ if ($line =~ /\b(?:$all_barriers)\s*\(/) {
if (!ctx_has_comment($first_line, $linenr)) {
WARN("MEMORY_BARRIER",
"memory barrier without comment\n" . $herecurr);
}
}
+ my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x;
+
+ if ($realfile !~ m@^include/asm-generic/@ &&
+ $realfile !~ m@/barrier\.h$@ &&
+ $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ &&
+ $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) {
+ WARN("MEMORY_BARRIER",
+ "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr);
+ }
+
# check for waitqueue_active without a comment.
if ($line =~ /\bwaitqueue_active\s*\(/) {
if (!ctx_has_comment($first_line, $linenr)) {
diff --git a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci
new file mode 100644
index 000000000000..8fa5a3c7b784
--- /dev/null
+++ b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci
@@ -0,0 +1,75 @@
+/// Unsigned expressions cannot be lesser than zero. Presence of
+/// comparisons 'unsigned (<|<=|>|>=) 0' often indicates a bug,
+/// usually wrong type of variable.
+///
+/// To reduce number of false positives following tests have been added:
+/// - parts of range checks are skipped, eg. "if (u < 0 || u > 15) ...",
+/// developers prefer to keep such code,
+/// - comparisons "<= 0" and "> 0" are performed only on results of
+/// signed functions/macros,
+/// - hardcoded list of signed functions/macros with always non-negative
+/// result is used to avoid false positives difficult to detect by other ways
+///
+// Confidence: Average
+// Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: --all-includes
+
+virtual context
+virtual org
+virtual report
+
+@r_cmp@
+position p;
+typedef bool, u8, u16, u32, u64;
+{unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long,
+ size_t, bool, u8, u16, u32, u64} v;
+expression e;
+@@
+
+ \( v = e \| &v \)
+ ...
+ (\( v@p < 0 \| v@p <= 0 \| v@p >= 0 \| v@p > 0 \))
+
+@r@
+position r_cmp.p;
+typedef s8, s16, s32, s64;
+{char, short, int, long, long long, ssize_t, s8, s16, s32, s64} vs;
+expression c, e, v;
+identifier f !~ "^(ata_id_queue_depth|btrfs_copy_from_user|dma_map_sg|dma_map_sg_attrs|fls|fls64|gameport_time|get_write_extents|nla_len|ntoh24|of_flat_dt_match|of_get_child_count|uart_circ_chars_pending|[A-Z0-9_]+)$";
+@@
+
+(
+ v = f(...)@vs;
+ ... when != v = e;
+* (\( v@p <=@e 0 \| v@p >@e 0 \))
+ ... when any
+|
+(
+ (\( v@p < 0 \| v@p <= 0 \)) || ... || (\( v >= c \| v > c \))
+|
+ (\( v >= c \| v > c \)) || ... || (\( v@p < 0 \| v@p <= 0 \))
+|
+ (\( v@p >= 0 \| v@p > 0 \)) && ... && (\( v < c \| v <= c \))
+|
+ ((\( v < c \| v <= c \) && ... && \( v@p >= 0 \| v@p > 0 \)))
+|
+* (\( v@p <@e 0 \| v@p >=@e 0 \))
+)
+)
+
+@script:python depends on org@
+p << r_cmp.p;
+e << r.e;
+@@
+
+msg = "WARNING: Unsigned expression compared with zero: %s" % (e)
+coccilib.org.print_todo(p[0], msg)
+
+@script:python depends on report@
+p << r_cmp.p;
+e << r.e;
+@@
+
+msg = "WARNING: Unsigned expression compared with zero: %s" % (e)
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index 88632df4381b..dafaf96e0a34 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -423,13 +423,15 @@ static struct string_list *read_node(FILE *f)
struct string_list node = {
.string = buffer,
.tag = SYM_NORMAL };
- int c;
+ int c, in_string = 0;
while ((c = fgetc(f)) != EOF) {
- if (c == ' ') {
+ if (!in_string && c == ' ') {
if (node.string == buffer)
continue;
break;
+ } else if (c == '"') {
+ in_string = !in_string;
} else if (c == '\n') {
if (node.string == buffer)
return NULL;
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 6c204318bc94..866369f10ff8 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -5,6 +5,7 @@
#include <locale.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,7 +42,7 @@ static int tty_stdio;
static int valid_stdin = 1;
static int sync_kconfig;
static int conf_cnt;
-static char line[128];
+static char line[PATH_MAX];
static struct menu *rootEntry;
static void print_help(struct menu *menu)
@@ -109,7 +110,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
/* fall through */
case oldaskconfig:
fflush(stdout);
- xfgets(line, 128, stdin);
+ xfgets(line, sizeof(line), stdin);
if (!tty_stdio)
printf("\n");
return 1;
@@ -311,7 +312,7 @@ static int conf_choice(struct menu *menu)
/* fall through */
case oldaskconfig:
fflush(stdout);
- xfgets(line, 128, stdin);
+ xfgets(line, sizeof(line), stdin);
strip(line);
if (line[0] == '?') {
print_help(menu);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index b05cc3d4a9be..aed678e8a777 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -477,7 +477,7 @@ bool menu_is_visible(struct menu *menu)
if (menu->visibility) {
if (expr_calc_value(menu->visibility) == no)
- return no;
+ return false;
}
sym = menu->sym;
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 91b7e6fbc364..fc5555992220 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1863,6 +1863,8 @@ int main(int ac, char** av)
configSettings->endGroup();
delete configSettings;
+ delete v;
+ delete configApp;
return 0;
}
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 638a38e1b419..c37255bb620d 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1816,6 +1816,8 @@ sub dump_struct($$) {
$members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
$members =~ s/__aligned\s*\([^;]*\)//gos;
$members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
+ # replace DECLARE_BITMAP
+ $members =~ s/DECLARE_BITMAP\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
create_parameterlist($members, ';', $file);
check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
@@ -1844,7 +1846,8 @@ sub dump_enum($$) {
my $file = shift;
$x =~ s@/\*.*?\*/@@gos; # strip comments.
- $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums
+ # strip #define macros inside enums
+ $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
$declaration_name = $1;
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 5b96206e9aab..161dd0d67da8 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -125,7 +125,7 @@ do { \
sprintf(str + strlen(str), "*"); \
} while(0)
-/* Always end in a wildcard, for future extension */
+/* End in a wildcard, for future extension */
static inline void add_wildcard(char *str)
{
int len = strlen(str);
@@ -704,7 +704,6 @@ static int do_of_entry (const char *filename, void *symval, char *alias)
if (isspace (*tmp))
*tmp = '_';
- add_wildcard(alias);
return 1;
}
ADD_TO_DEVTABLE("of", of_device_id, do_of_entry);
@@ -917,7 +916,7 @@ static int do_vmbus_entry(const char *filename, void *symval,
char guid_name[(sizeof(*guid) + 1) * 2];
for (i = 0; i < (sizeof(*guid) * 2); i += 2)
- sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2]));
+ sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2]));
strcpy(alias, "vmbus:");
strcat(alias, guid_name);
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
index 1aca224e8597..c2c7389bfbab 100644
--- a/scripts/package/Makefile
+++ b/scripts/package/Makefile
@@ -118,12 +118,12 @@ quiet_cmd_perf_tar = TAR
cmd_perf_tar = \
git --git-dir=$(srctree)/.git archive --prefix=$(perf-tar)/ \
HEAD^{tree} $$(cd $(srctree); \
- echo $$(cat $(srctree)/tools/perf/MANIFEST)) \
+ echo $$(cat tools/perf/MANIFEST)) \
-o $(perf-tar).tar; \
mkdir -p $(perf-tar); \
git --git-dir=$(srctree)/.git rev-parse HEAD > $(perf-tar)/HEAD; \
(cd $(srctree)/tools/perf; \
-util/PERF-VERSION-GEN ../../$(perf-tar)/ 2>/dev/null); \
+util/PERF-VERSION-GEN $(CURDIR)/$(perf-tar)/); \
tar rf $(perf-tar).tar $(perf-tar)/HEAD $(perf-tar)/PERF-VERSION-FILE; \
rm -r $(perf-tar); \
$(if $(findstring tar-src,$@),, \
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 826470d7f000..96e2486a6fc4 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -263,7 +263,8 @@ if ($arch eq "x86_64") {
} elsif ($arch eq "powerpc") {
$local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)";
- $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:";
+ # See comment in the sparc64 section for why we use '\w'.
+ $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?\\w*?)>:";
$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$";
if ($bits == 64) {
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 262889046703..23ba1c6a0a59 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# Generate tags or cscope files
# Usage tags.sh <mode>
#
@@ -134,11 +134,6 @@ all_kconfigs()
find_other_sources 'Kconfig*'
}
-all_defconfigs()
-{
- find_sources $ALLSOURCE_ARCHS "defconfig"
-}
-
docscope()
{
(echo \-k; echo \-q; all_target_sources) > cscope.files
@@ -150,8 +145,107 @@ dogtags()
all_target_sources | gtags -i -f -
}
+# Basic regular expressions with an optional /kind-spec/ for ctags and
+# the following limitations:
+# - No regex modifiers
+# - Use \{0,1\} instead of \?, because etags expects an unescaped ?
+# - \s is not working with etags, use a space or [ \t]
+# - \w works, but does not match underscores in etags
+# - etags regular expressions have to match at the start of a line;
+# a ^[^#] is prepended by setup_regex unless an anchor is already present
+regex_asm=(
+ '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/'
+)
+regex_c=(
+ '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/'
+ '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/'
+ '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/'
+ '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
+ '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/'
+ '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
+ '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
+ '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
+ '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
+ '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
+ '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
+ '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
+ '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
+ '/\<TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/\<__TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/\<CLEARPAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
+ '/\<__CLEARPAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
+ '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/^PAGEFLAG_FALSE(\([[:alnum:]_]*\).*/Page\1/'
+ '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
+ '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/\<SETPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/SetPage\1/'
+ '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/'
+ '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/'
+ '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/'
+ '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/'
+ '/^DEF_MMIO_\(IN\|OUT\)_[XD](\([[:alnum:]_]*\),[^)]*)/\2/'
+ '/^DEBUGGER_BOILERPLATE(\([[:alnum:]_]*\))/\1/'
+ '/^DEF_PCI_AC_\(\|NO\)RET(\([[:alnum:]_]*\).*/\2/'
+ '/^PCI_OP_READ(\(\w*\).*[1-4])/pci_bus_read_config_\1/'
+ '/^PCI_OP_WRITE(\(\w*\).*[1-4])/pci_bus_write_config_\1/'
+ '/\<DEFINE_\(MUTEX\|SEMAPHORE\|SPINLOCK\)(\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)(\([[:alnum:]_]*\)/\2/v/'
+ '/\<DECLARE_\(RWSEM\|COMPLETION\)(\([[:alnum:]_]\+\)/\2/v/'
+ '/\<DECLARE_BITMAP(\([[:alnum:]_]*\)/\1/v/'
+ '/\(^\|\s\)\(\|L\|H\)LIST_HEAD(\([[:alnum:]_]*\)/\3/v/'
+ '/\(^\|\s\)RADIX_TREE(\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_PER_CPU([^,]*, *\([[:alnum:]_]*\)/\1/v/'
+ '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*, *\([[:alnum:]_]*\)/\1/v/'
+ '/\<DECLARE_WAIT_QUEUE_HEAD(\([[:alnum:]_]*\)/\1/v/'
+ '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_PCI_DEVICE_TABLE(\([[:alnum:]_]*\)/\1/v/'
+ '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/'
+ '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_HASHTABLE(\([[:alnum:]_]*\)/\1/v/'
+)
+regex_kconfig=(
+ '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'
+ '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/CONFIG_\2/'
+)
+setup_regex()
+{
+ local mode=$1 lang tmp=() r
+ shift
+
+ regex=()
+ for lang; do
+ case "$lang" in
+ asm) tmp=("${regex_asm[@]}") ;;
+ c) tmp=("${regex_c[@]}") ;;
+ kconfig) tmp=("${regex_kconfig[@]}") ;;
+ esac
+ for r in "${tmp[@]}"; do
+ if test "$mode" = "exuberant"; then
+ regex[${#regex[@]}]="--regex-$lang=${r}b"
+ else
+ # Remove ctags /kind-spec/
+ case "$r" in
+ /*/*/?/)
+ r=${r%?/}
+ esac
+ # Prepend ^[^#] unless already anchored
+ case "$r" in
+ /^*) ;;
+ *)
+ r="/^[^#]*${r#/}"
+ esac
+ regex[${#regex[@]}]="--regex=$r"
+ fi
+ done
+ done
+}
+
exuberant()
{
+ setup_regex exuberant asm c
all_target_sources | xargs $1 -a \
-I __initdata,__exitdata,__initconst, \
-I __initdata_memblock \
@@ -165,118 +259,21 @@ exuberant()
-I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \
-I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \
-I static,const \
- --extra=+f --c-kinds=+px \
- --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/' \
- --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \
- --regex-c='/^COMPAT_SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/compat_sys_\1/' \
- --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \
- --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1_rcuidle/' \
- --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/' \
- --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1_rcuidle/' \
- --regex-c++='/PAGEFLAG\(([^,)]*).*/Page\1/' \
- --regex-c++='/PAGEFLAG\(([^,)]*).*/SetPage\1/' \
- --regex-c++='/PAGEFLAG\(([^,)]*).*/ClearPage\1/' \
- --regex-c++='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/' \
- --regex-c++='/TESTPAGEFLAG\(([^,)]*).*/Page\1/' \
- --regex-c++='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/' \
- --regex-c++='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/' \
- --regex-c++='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \
- --regex-c++='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \
- --regex-c++='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/' \
- --regex-c++='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/' \
- --regex-c++='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/' \
- --regex-c++='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/' \
- --regex-c++='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/' \
- --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/' \
- --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/' \
- --regex-c++='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/' \
- --regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \
- --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
- --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
- --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
- --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \
- --regex-c++='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \
- --regex-c++='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \
- --regex-c++='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'\
- --regex-c++='/DEF_MMIO_(IN|OUT)_(X|D)\(([^,]*),\s*[^)]*\)/\3/' \
- --regex-c++='/DEBUGGER_BOILERPLATE\(([^,]*)\)/\1/' \
- --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \
- --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \
- --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \
- --regex-c='/DEFINE_(RAW_SPINLOCK|RWLOCK|SEQLOCK)\((\w*)/\2/v/' \
- --regex-c='/DECLARE_(RWSEM|COMPLETION)\((\w*)/\2/v/' \
- --regex-c='/DECLARE_BITMAP\((\w*)/\1/v/' \
- --regex-c='/(^|\s)(|L|H)LIST_HEAD\((\w*)/\3/v/' \
- --regex-c='/(^|\s)RADIX_TREE\((\w*)/\2/v/' \
- --regex-c='/DEFINE_PER_CPU\(([^,]*,\s*)(\w*).*\)/\2/v/' \
- --regex-c='/DEFINE_PER_CPU_SHARED_ALIGNED\(([^,]*,\s*)(\w*).*\)/\2/v/' \
- --regex-c='/DECLARE_WAIT_QUEUE_HEAD\((\w*)/\1/v/' \
- --regex-c='/DECLARE_(TASKLET|WORK|DELAYED_WORK)\((\w*)/\2/v/' \
- --regex-c='/DEFINE_PCI_DEVICE_TABLE\((\w*)/\1/v/' \
- --regex-c='/(^\s)OFFSET\((\w*)/\2/v/' \
- --regex-c='/(^\s)DEFINE\((\w*)/\2/v/' \
- --regex-c='/DEFINE_HASHTABLE\((\w*)/\1/v/'
+ --extra=+f --c-kinds=+px --langmap=c:+.h "${regex[@]}"
+ setup_regex exuberant kconfig
all_kconfigs | xargs $1 -a \
- --langdef=kconfig --language-force=kconfig \
- --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/'
+ --langdef=kconfig --language-force=kconfig "${regex[@]}"
- all_kconfigs | xargs $1 -a \
- --langdef=kconfig --language-force=kconfig \
- --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/CONFIG_\2/'
-
- all_defconfigs | xargs -r $1 -a \
- --langdef=dotconfig --language-force=dotconfig \
- --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'
}
emacs()
{
- all_target_sources | xargs $1 -a \
- --regex='/^\(ENTRY\|_GLOBAL\)(\([^)]*\)).*/\2/' \
- --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \
- --regex='/^COMPAT_SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/compat_sys_\1/' \
- --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \
- --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1_rcuidle/' \
- --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' \
- --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1_rcuidle/' \
- --regex='/PAGEFLAG(\([^,)]*\).*/Page\1/' \
- --regex='/PAGEFLAG(\([^,)]*\).*/SetPage\1/' \
- --regex='/PAGEFLAG(\([^,)]*\).*/ClearPage\1/' \
- --regex='/TESTSETFLAG(\([^,)]*\).*/TestSetPage\1/' \
- --regex='/TESTPAGEFLAG(\([^,)]*\).*/Page\1/' \
- --regex='/SETPAGEFLAG(\([^,)]*\).*/SetPage\1/' \
- --regex='/__SETPAGEFLAG(\([^,)]*\).*/__SetPage\1/' \
- --regex='/TESTCLEARFLAG(\([^,)]*\).*/TestClearPage\1/' \
- --regex='/__TESTCLEARFLAG(\([^,)]*\).*/TestClearPage\1/' \
- --regex='/CLEARPAGEFLAG(\([^,)]*\).*/ClearPage\1/' \
- --regex='/__CLEARPAGEFLAG(\([^,)]*\).*/__ClearPage\1/' \
- --regex='/__PAGEFLAG(\([^,)]*\).*/__SetPage\1/' \
- --regex='/__PAGEFLAG(\([^,)]*\).*/__ClearPage\1/' \
- --regex='/PAGEFLAG_FALSE(\([^,)]*\).*/Page\1/' \
- --regex='/TESTSCFLAG(\([^,)]*\).*/TestSetPage\1/' \
- --regex='/TESTSCFLAG(\([^,)]*\).*/TestClearPage\1/' \
- --regex='/SETPAGEFLAG_NOOP(\([^,)]*\).*/SetPage\1/' \
- --regex='/CLEARPAGEFLAG_NOOP(\([^,)]*\).*/ClearPage\1/' \
- --regex='/__CLEARPAGEFLAG_NOOP(\([^,)]*\).*/__ClearPage\1/' \
- --regex='/TESTCLEARFLAG_FALSE(\([^,)]*\).*/TestClearPage\1/' \
- --regex='/__TESTCLEARFLAG_FALSE(\([^,)]*\).*/__TestClearPage\1/' \
- --regex='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \
- --regex='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \
- --regex='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/' \
- --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \
- --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \
- --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\
- --regex='/[^#]*DEFINE_HASHTABLE(\([^,)]*\)/\1/'
-
- all_kconfigs | xargs $1 -a \
- --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
-
- all_kconfigs | xargs $1 -a \
- --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/CONFIG_\3/'
+ setup_regex emacs asm c
+ all_target_sources | xargs $1 -a "${regex[@]}"
- all_defconfigs | xargs -r $1 -a \
- --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'
+ setup_regex emacs kconfig
+ all_kconfigs | xargs $1 -a "${regex[@]}"
}
xtags()
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 73c457bf5a4a..21d756832b75 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -41,6 +41,17 @@ config INTEGRITY_ASYMMETRIC_KEYS
This option enables digital signature verification using
asymmetric keys.
+config INTEGRITY_TRUSTED_KEYRING
+ bool "Require all keys on the integrity keyrings be signed"
+ depends on SYSTEM_TRUSTED_KEYRING
+ depends on INTEGRITY_ASYMMETRIC_KEYS
+ select KEYS_DEBUG_PROC_KEYS
+ default y
+ help
+ This option requires that all keys added to the .ima and
+ .evm keyrings be signed by a key on the system trusted
+ keyring.
+
config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
depends on AUDIT
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 5be9ffbe90ba..8ef15118cc78 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -24,15 +24,22 @@
static struct key *keyring[INTEGRITY_KEYRING_MAX];
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
+#ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING
"_evm",
- "_module",
-#ifndef CONFIG_IMA_TRUSTED_KEYRING
"_ima",
#else
+ ".evm",
".ima",
#endif
+ "_module",
};
+#ifdef CONFIG_INTEGRITY_TRUSTED_KEYRING
+static bool init_keyring __initdata = true;
+#else
+static bool init_keyring __initdata;
+#endif
+
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen)
{
@@ -68,6 +75,9 @@ int __init integrity_init_keyring(const unsigned int id)
const struct cred *cred = current_cred();
int err = 0;
+ if (!init_keyring)
+ return 0;
+
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 4fec1816a2b3..5ade2a7517a6 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -17,6 +17,7 @@
#include <linux/key-type.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
#include "integrity.h"
@@ -32,9 +33,22 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
pr_debug("key search: \"%s\"\n", name);
+ key = get_ima_blacklist_keyring();
+ if (key) {
+ key_ref_t kref;
+
+ kref = keyring_search(make_key_ref(key, 1),
+ &key_type_asymmetric, name);
+ if (!IS_ERR(kref)) {
+ pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
+ return ERR_PTR(-EKEYREJECTED);
+ }
+ }
+
if (keyring) {
/* search in specific keyring */
key_ref_t kref;
+
kref = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, name);
if (IS_ERR(kref))
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index bf19723cf117..e825e0ae78e7 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -42,3 +42,20 @@ config EVM_EXTRA_SMACK_XATTRS
additional info to the calculation, requires existing EVM
labeled file systems to be relabeled.
+config EVM_LOAD_X509
+ bool "Load an X509 certificate onto the '.evm' trusted keyring"
+ depends on EVM && INTEGRITY_TRUSTED_KEYRING
+ default n
+ help
+ Load an X509 certificate onto the '.evm' trusted keyring.
+
+ This option enables X509 certificate loading from the kernel
+ onto the '.evm' trusted keyring. A public key can be used to
+ verify EVM integrity starting from the 'init' process.
+
+config EVM_X509_PATH
+ string "EVM X509 certificate path"
+ depends on EVM_LOAD_X509
+ default "/etc/keys/x509_evm.der"
+ help
+ This option defines X509 certificate path.
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 88bfe77efa1c..f5f12727771a 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -21,6 +21,9 @@
#include "../integrity.h"
+#define EVM_INIT_HMAC 0x0001
+#define EVM_INIT_X509 0x0002
+
extern int evm_initialized;
extern char *evm_hmac;
extern char *evm_hash;
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 461f8d891579..30b6b7d0429f 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/xattr.h>
+#include <linux/evm.h>
#include <keys/encrypted-type.h>
#include <crypto/hash.h>
#include "evm.h"
@@ -32,6 +33,44 @@ struct crypto_shash *hash_tfm;
static DEFINE_MUTEX(mutex);
+#define EVM_SET_KEY_BUSY 0
+
+static unsigned long evm_set_key_flags;
+
+/**
+ * evm_set_key() - set EVM HMAC key from the kernel
+ * @key: pointer to a buffer with the key data
+ * @size: length of the key data
+ *
+ * This function allows setting the EVM HMAC key from the kernel
+ * without using the "encrypted" key subsystem keys. It can be used
+ * by the crypto HW kernel module which has its own way of managing
+ * keys.
+ *
+ * key length should be between 32 and 128 bytes long
+ */
+int evm_set_key(void *key, size_t keylen)
+{
+ int rc;
+
+ rc = -EBUSY;
+ if (test_and_set_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags))
+ goto busy;
+ rc = -EINVAL;
+ if (keylen > MAX_KEY_SIZE)
+ goto inval;
+ memcpy(evmkey, key, keylen);
+ evm_initialized |= EVM_INIT_HMAC;
+ pr_info("key initialized\n");
+ return 0;
+inval:
+ clear_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags);
+busy:
+ pr_err("key initialization failed\n");
+ return rc;
+}
+EXPORT_SYMBOL_GPL(evm_set_key);
+
static struct shash_desc *init_desc(char type)
{
long rc;
@@ -40,6 +79,10 @@ static struct shash_desc *init_desc(char type)
struct shash_desc *desc;
if (type == EVM_XATTR_HMAC) {
+ if (!(evm_initialized & EVM_INIT_HMAC)) {
+ pr_err("HMAC key is not set\n");
+ return ERR_PTR(-ENOKEY);
+ }
tfm = &hmac_tfm;
algo = evm_hmac;
} else {
@@ -240,7 +283,7 @@ int evm_init_key(void)
{
struct key *evm_key;
struct encrypted_key_payload *ekp;
- int rc = 0;
+ int rc;
evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
if (IS_ERR(evm_key))
@@ -248,12 +291,9 @@ int evm_init_key(void)
down_read(&evm_key->sem);
ekp = evm_key->payload.data[0];
- if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
- rc = -EINVAL;
- goto out;
- }
- memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
-out:
+
+ rc = evm_set_key(ekp->decrypted_data, ekp->decrypted_datalen);
+
/* burn the original key contents */
memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
up_read(&evm_key->sem);
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 1334e02ae8f4..f7160253f17f 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -358,6 +358,15 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
return evm_protect_xattr(dentry, xattr_name, NULL, 0);
}
+static void evm_reset_status(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+
+ iint = integrity_iint_find(inode);
+ if (iint)
+ iint->evm_status = INTEGRITY_UNKNOWN;
+}
+
/**
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
* @dentry: pointer to the affected dentry
@@ -378,6 +387,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
&& !posix_xattr_acl(xattr_name)))
return;
+ evm_reset_status(dentry->d_inode);
+
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}
@@ -396,6 +407,8 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
if (!evm_initialized || !evm_protected_xattr(xattr_name))
return;
+ evm_reset_status(dentry->d_inode);
+
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
@@ -472,21 +485,34 @@ out:
}
EXPORT_SYMBOL_GPL(evm_inode_init_security);
+#ifdef CONFIG_EVM_LOAD_X509
+void __init evm_load_x509(void)
+{
+ int rc;
+
+ rc = integrity_load_x509(INTEGRITY_KEYRING_EVM, CONFIG_EVM_X509_PATH);
+ if (!rc)
+ evm_initialized |= EVM_INIT_X509;
+}
+#endif
+
static int __init init_evm(void)
{
int error;
evm_init_config();
+ error = integrity_init_keyring(INTEGRITY_KEYRING_EVM);
+ if (error)
+ return error;
+
error = evm_init_secfs();
if (error < 0) {
pr_info("Error registering secfs\n");
- goto err;
+ return error;
}
return 0;
-err:
- return error;
}
/*
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index cf12a04717d3..c8dccd54d501 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -62,9 +62,9 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char temp[80];
- int i, error;
+ int i;
- if (!capable(CAP_SYS_ADMIN) || evm_initialized)
+ if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC))
return -EPERM;
if (count >= sizeof(temp) || count == 0)
@@ -78,12 +78,8 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
return -EINVAL;
- error = evm_init_key();
- if (!error) {
- evm_initialized = 1;
- pr_info("initialized\n");
- } else
- pr_err("initialization failed\n");
+ evm_init_key();
+
return count;
}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index c2e3ccd4b510..8f1ab37f2897 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -255,4 +255,5 @@ out:
void __init integrity_load_keys(void)
{
ima_load_x509();
+ evm_load_x509();
}
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index df303346029b..e54a8a8dae94 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -107,6 +107,27 @@ config IMA_DEFAULT_HASH
default "sha512" if IMA_DEFAULT_HASH_SHA512
default "wp512" if IMA_DEFAULT_HASH_WP512
+config IMA_WRITE_POLICY
+ bool "Enable multiple writes to the IMA policy"
+ depends on IMA
+ default n
+ help
+ IMA policy can now be updated multiple times. The new rules get
+ appended to the original policy. Have in mind that the rules are
+ scanned in FIFO order so be careful when you design and add new ones.
+
+ If unsure, say N.
+
+config IMA_READ_POLICY
+ bool "Enable reading back the current IMA policy"
+ depends on IMA
+ default y if IMA_WRITE_POLICY
+ default n if !IMA_WRITE_POLICY
+ help
+ It is often useful to be able to read back the IMA policy. It is
+ even more important after introducing CONFIG_IMA_WRITE_POLICY.
+ This option allows the root user to see the current policy rules.
+
config IMA_APPRAISE
bool "Appraise integrity measurements"
depends on IMA
@@ -123,14 +144,35 @@ config IMA_APPRAISE
If unsure, say N.
config IMA_TRUSTED_KEYRING
- bool "Require all keys on the .ima keyring be signed"
+ bool "Require all keys on the .ima keyring be signed (deprecated)"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
+ select INTEGRITY_TRUSTED_KEYRING
default y
help
This option requires that all keys added to the .ima
keyring be signed by a key on the system trusted keyring.
+ This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING
+
+config IMA_MOK_KEYRING
+ bool "Create IMA machine owner keys (MOK) and blacklist keyrings"
+ depends on SYSTEM_TRUSTED_KEYRING
+ depends on IMA_TRUSTED_KEYRING
+ default n
+ help
+ This option creates IMA MOK and blacklist keyrings. IMA MOK is an
+ intermediate keyring that sits between .system and .ima keyrings,
+ effectively forming a simple CA hierarchy. To successfully import a
+ key into .ima_mok it must be signed by a key which CA is in .system
+ keyring. On turn any key that needs to go in .ima keyring must be
+ signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty
+ at kernel boot.
+
+ IMA blacklist keyring contains all revoked IMA keys. It is consulted
+ before any other keyring. If the search is successful the requested
+ operation is rejected and error is returned to the caller.
+
config IMA_LOAD_X509
bool "Load X509 certificate onto the '.ima' trusted keyring"
depends on IMA_TRUSTED_KEYRING
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index d79263d2fdbf..a8539f9e060f 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o ima_template.o ima_template_lib.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
+obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index e2a60c30df44..585af61ed399 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -166,6 +166,11 @@ void ima_update_policy(void);
void ima_update_policy_flag(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
+int ima_check_policy(void);
+void *ima_policy_start(struct seq_file *m, loff_t *pos);
+void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
+void ima_policy_stop(struct seq_file *m, void *v);
+int ima_policy_show(struct seq_file *m, void *v);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
@@ -250,17 +255,12 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
{
return -EINVAL;
}
-#endif /* CONFIG_IMA_LSM_RULES */
+#endif /* CONFIG_IMA_TRUSTED_KEYRING */
-#ifdef CONFIG_IMA_TRUSTED_KEYRING
-static inline int ima_init_keyring(const unsigned int id)
-{
- return integrity_init_keyring(id);
-}
+#ifdef CONFIG_IMA_READ_POLICY
+#define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
#else
-static inline int ima_init_keyring(const unsigned int id)
-{
- return 0;
-}
-#endif /* CONFIG_IMA_TRUSTED_KEYRING */
-#endif
+#define POLICY_FILE_FLAGS S_IWUSR
+#endif /* CONFIG_IMA_WRITE_POLICY */
+
+#endif /* __LINUX_IMA_H */
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 816d175da79a..f355231997b4 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -25,6 +25,8 @@
#include "ima.h"
+static DEFINE_MUTEX(ima_write_mutex);
+
static int valid_policy = 1;
#define TMPBUFLEN 12
static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -259,7 +261,7 @@ static const struct file_operations ima_ascii_measurements_ops = {
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
- char *data = NULL;
+ char *data;
ssize_t result;
if (datalen >= PAGE_SIZE)
@@ -279,13 +281,20 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
result = -EFAULT;
if (copy_from_user(data, buf, datalen))
- goto out;
+ goto out_free;
+ result = mutex_lock_interruptible(&ima_write_mutex);
+ if (result < 0)
+ goto out_free;
result = ima_parse_add_rule(data);
+ mutex_unlock(&ima_write_mutex);
+
+out_free:
+ kfree(data);
out:
if (result < 0)
valid_policy = 0;
- kfree(data);
+
return result;
}
@@ -302,14 +311,31 @@ enum ima_fs_flags {
static unsigned long ima_fs_flags;
+#ifdef CONFIG_IMA_READ_POLICY
+static const struct seq_operations ima_policy_seqops = {
+ .start = ima_policy_start,
+ .next = ima_policy_next,
+ .stop = ima_policy_stop,
+ .show = ima_policy_show,
+};
+#endif
+
/*
* ima_open_policy: sequentialize access to the policy file
*/
static int ima_open_policy(struct inode *inode, struct file *filp)
{
- /* No point in being allowed to open it if you aren't going to write */
- if (!(filp->f_flags & O_WRONLY))
+ if (!(filp->f_flags & O_WRONLY)) {
+#ifndef CONFIG_IMA_READ_POLICY
return -EACCES;
+#else
+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+ return -EACCES;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return seq_open(filp, &ima_policy_seqops);
+#endif
+ }
if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
return -EBUSY;
return 0;
@@ -326,6 +352,14 @@ static int ima_release_policy(struct inode *inode, struct file *file)
{
const char *cause = valid_policy ? "completed" : "failed";
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return 0;
+
+ if (valid_policy && ima_check_policy() < 0) {
+ cause = "failed";
+ valid_policy = 0;
+ }
+
pr_info("IMA: policy update %s\n", cause);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
"policy_update", cause, !valid_policy, 0);
@@ -336,15 +370,21 @@ static int ima_release_policy(struct inode *inode, struct file *file)
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
return 0;
}
+
ima_update_policy();
+#ifndef CONFIG_IMA_WRITE_POLICY
securityfs_remove(ima_policy);
ima_policy = NULL;
+#else
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#endif
return 0;
}
static const struct file_operations ima_measure_policy_ops = {
.open = ima_open_policy,
.write = ima_write_policy,
+ .read = seq_read,
.release = ima_release_policy,
.llseek = generic_file_llseek,
};
@@ -382,8 +422,7 @@ int __init ima_fs_init(void)
if (IS_ERR(violations))
goto out;
- ima_policy = securityfs_create_file("policy",
- S_IWUSR,
+ ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
&ima_measure_policy_ops);
if (IS_ERR(ima_policy))
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index e600cadd231c..bd79f254d204 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -116,7 +116,7 @@ int __init ima_init(void)
if (!ima_used_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n");
- rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+ rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA);
if (rc)
return rc;
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
new file mode 100644
index 000000000000..676885e4320e
--- /dev/null
+++ b/security/integrity/ima/ima_mok.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Juniper Networks, Inc.
+ *
+ * Author:
+ * Petko Manolov <petko.manolov@konsulko.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <keys/asymmetric-type.h>
+
+
+struct key *ima_mok_keyring;
+struct key *ima_blacklist_keyring;
+
+/*
+ * Allocate the IMA MOK and blacklist keyrings
+ */
+__init int ima_mok_init(void)
+{
+ pr_notice("Allocating IMA MOK and blacklist keyrings.\n");
+
+ ima_mok_keyring = keyring_alloc(".ima_mok",
+ KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ |
+ KEY_USR_WRITE | KEY_USR_SEARCH,
+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
+
+ ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
+ KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ |
+ KEY_USR_WRITE | KEY_USR_SEARCH,
+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
+
+ if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
+ panic("Can't allocate IMA MOK or blacklist keyrings.");
+ set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
+
+ set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
+ set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
+ return 0;
+}
+device_initcall(ima_mok_init);
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 3997e206f82d..0a3b781f18e5 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -16,7 +16,9 @@
#include <linux/magic.h>
#include <linux/parser.h>
#include <linux/slab.h>
+#include <linux/rculist.h>
#include <linux/genhd.h>
+#include <linux/seq_file.h>
#include "ima.h"
@@ -38,6 +40,7 @@
#define AUDIT 0x0040
int ima_policy_flag;
+static int temp_ima_appraise;
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
@@ -135,11 +138,11 @@ static struct ima_rule_entry default_appraise_rules[] = {
static LIST_HEAD(ima_default_rules);
static LIST_HEAD(ima_policy_rules);
+static LIST_HEAD(ima_temp_rules);
static struct list_head *ima_rules;
-static DEFINE_MUTEX(ima_rules_mutex);
-
static int ima_policy __initdata;
+
static int __init default_measure_policy_setup(char *str)
{
if (ima_policy)
@@ -171,21 +174,18 @@ static int __init default_appraise_policy_setup(char *str)
__setup("ima_appraise_tcb", default_appraise_policy_setup);
/*
- * Although the IMA policy does not change, the LSM policy can be
- * reloaded, leaving the IMA LSM based rules referring to the old,
- * stale LSM policy.
- *
- * Update the IMA LSM based rules to reflect the reloaded LSM policy.
- * We assume the rules still exist; and BUG_ON() if they don't.
+ * The LSM policy can be reloaded, leaving the IMA LSM based rules referring
+ * to the old, stale LSM policy. Update the IMA LSM based rules to reflect
+ * the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if
+ * they don't.
*/
static void ima_lsm_update_rules(void)
{
- struct ima_rule_entry *entry, *tmp;
+ struct ima_rule_entry *entry;
int result;
int i;
- mutex_lock(&ima_rules_mutex);
- list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+ list_for_each_entry(entry, &ima_policy_rules, list) {
for (i = 0; i < MAX_LSM_RULES; i++) {
if (!entry->lsm[i].rule)
continue;
@@ -196,7 +196,6 @@ static void ima_lsm_update_rules(void)
BUG_ON(!entry->lsm[i].rule);
}
}
- mutex_unlock(&ima_rules_mutex);
}
/**
@@ -319,9 +318,9 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions.
*
- * (There is no need for locking when walking the policy list,
- * as elements in the list are never deleted, nor does the list
- * change.)
+ * Since the IMA policy may be updated multiple times we need to lock the
+ * list when walking it. Reads are many orders of magnitude more numerous
+ * than writes so ima_match_policy() is classical RCU candidate.
*/
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags)
@@ -329,7 +328,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1);
- list_for_each_entry(entry, ima_rules, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, ima_rules, list) {
if (!(entry->action & actmask))
continue;
@@ -351,6 +351,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
if (!actmask)
break;
}
+ rcu_read_unlock();
return action;
}
@@ -365,12 +366,12 @@ void ima_update_policy_flag(void)
{
struct ima_rule_entry *entry;
- ima_policy_flag = 0;
list_for_each_entry(entry, ima_rules, list) {
if (entry->action & IMA_DO_MASK)
ima_policy_flag |= entry->action;
}
+ ima_appraise |= temp_ima_appraise;
if (!ima_appraise)
ima_policy_flag &= ~IMA_APPRAISE;
}
@@ -415,16 +416,48 @@ void __init ima_init_policy(void)
ima_rules = &ima_default_rules;
}
+/* Make sure we have a valid policy, at least containing some rules. */
+int ima_check_policy()
+{
+ if (list_empty(&ima_temp_rules))
+ return -EINVAL;
+ return 0;
+}
+
/**
* ima_update_policy - update default_rules with new measure rules
*
* Called on file .release to update the default rules with a complete new
- * policy. Once updated, the policy is locked, no additional rules can be
- * added to the policy.
+ * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so
+ * they make a queue. The policy may be updated multiple times and this is the
+ * RCU updater.
+ *
+ * Policy rules are never deleted so ima_policy_flag gets zeroed only once when
+ * we switch from the default policy to user defined.
*/
void ima_update_policy(void)
{
- ima_rules = &ima_policy_rules;
+ struct list_head *first, *last, *policy;
+
+ /* append current policy with the new rules */
+ first = (&ima_temp_rules)->next;
+ last = (&ima_temp_rules)->prev;
+ policy = &ima_policy_rules;
+
+ synchronize_rcu();
+
+ last->next = policy;
+ rcu_assign_pointer(list_next_rcu(policy->prev), first);
+ first->prev = policy->prev;
+ policy->prev = last;
+
+ /* prepare for the next policy rules addition */
+ INIT_LIST_HEAD(&ima_temp_rules);
+
+ if (ima_rules != policy) {
+ ima_policy_flag = 0;
+ ima_rules = policy;
+ }
ima_update_policy_flag();
}
@@ -436,8 +469,8 @@ enum {
Opt_obj_user, Opt_obj_role, Opt_obj_type,
Opt_subj_user, Opt_subj_role, Opt_subj_type,
Opt_func, Opt_mask, Opt_fsmagic,
- Opt_uid, Opt_euid, Opt_fowner,
- Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
+ Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner,
+ Opt_appraise_type, Opt_permit_directio
};
static match_table_t policy_tokens = {
@@ -734,9 +767,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
if (!result && (entry->action == UNKNOWN))
result = -EINVAL;
else if (entry->func == MODULE_CHECK)
- ima_appraise |= IMA_APPRAISE_MODULES;
+ temp_ima_appraise |= IMA_APPRAISE_MODULES;
else if (entry->func == FIRMWARE_CHECK)
- ima_appraise |= IMA_APPRAISE_FIRMWARE;
+ temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
audit_log_format(ab, "res=%d", !result);
audit_log_end(ab);
return result;
@@ -746,7 +779,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
* ima_parse_add_rule - add a rule to ima_policy_rules
* @rule - ima measurement policy rule
*
- * Uses a mutex to protect the policy list from multiple concurrent writers.
+ * Avoid locking by allowing just one writer at a time in ima_write_policy()
* Returns the length of the rule parsed, an error code on failure
*/
ssize_t ima_parse_add_rule(char *rule)
@@ -782,26 +815,230 @@ ssize_t ima_parse_add_rule(char *rule)
return result;
}
- mutex_lock(&ima_rules_mutex);
- list_add_tail(&entry->list, &ima_policy_rules);
- mutex_unlock(&ima_rules_mutex);
+ list_add_tail(&entry->list, &ima_temp_rules);
return len;
}
-/* ima_delete_rules called to cleanup invalid policy */
+/**
+ * ima_delete_rules() called to cleanup invalid in-flight policy.
+ * We don't need locking as we operate on the temp list, which is
+ * different from the active one. There is also only one user of
+ * ima_delete_rules() at a time.
+ */
void ima_delete_rules(void)
{
struct ima_rule_entry *entry, *tmp;
int i;
- mutex_lock(&ima_rules_mutex);
- list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+ temp_ima_appraise = 0;
+ list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
for (i = 0; i < MAX_LSM_RULES; i++)
kfree(entry->lsm[i].args_p);
list_del(&entry->list);
kfree(entry);
}
- mutex_unlock(&ima_rules_mutex);
}
+
+#ifdef CONFIG_IMA_READ_POLICY
+enum {
+ mask_exec = 0, mask_write, mask_read, mask_append
+};
+
+static char *mask_tokens[] = {
+ "MAY_EXEC",
+ "MAY_WRITE",
+ "MAY_READ",
+ "MAY_APPEND"
+};
+
+enum {
+ func_file = 0, func_mmap, func_bprm,
+ func_module, func_firmware, func_post
+};
+
+static char *func_tokens[] = {
+ "FILE_CHECK",
+ "MMAP_CHECK",
+ "BPRM_CHECK",
+ "MODULE_CHECK",
+ "FIRMWARE_CHECK",
+ "POST_SETATTR"
+};
+
+void *ima_policy_start(struct seq_file *m, loff_t *pos)
+{
+ loff_t l = *pos;
+ struct ima_rule_entry *entry;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, ima_rules, list) {
+ if (!l--) {
+ rcu_read_unlock();
+ return entry;
+ }
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+
+void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct ima_rule_entry *entry = v;
+
+ rcu_read_lock();
+ entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
+ rcu_read_unlock();
+ (*pos)++;
+
+ return (&entry->list == ima_rules) ? NULL : entry;
+}
+
+void ima_policy_stop(struct seq_file *m, void *v)
+{
+}
+
+#define pt(token) policy_tokens[token + Opt_err].pattern
+#define mt(token) mask_tokens[token]
+#define ft(token) func_tokens[token]
+
+int ima_policy_show(struct seq_file *m, void *v)
+{
+ struct ima_rule_entry *entry = v;
+ int i = 0;
+ char tbuf[64] = {0,};
+
+ rcu_read_lock();
+
+ if (entry->action & MEASURE)
+ seq_puts(m, pt(Opt_measure));
+ if (entry->action & DONT_MEASURE)
+ seq_puts(m, pt(Opt_dont_measure));
+ if (entry->action & APPRAISE)
+ seq_puts(m, pt(Opt_appraise));
+ if (entry->action & DONT_APPRAISE)
+ seq_puts(m, pt(Opt_dont_appraise));
+ if (entry->action & AUDIT)
+ seq_puts(m, pt(Opt_audit));
+
+ seq_puts(m, " ");
+
+ if (entry->flags & IMA_FUNC) {
+ switch (entry->func) {
+ case FILE_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_file));
+ break;
+ case MMAP_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_mmap));
+ break;
+ case BPRM_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_bprm));
+ break;
+ case MODULE_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_module));
+ break;
+ case FIRMWARE_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_firmware));
+ break;
+ case POST_SETATTR:
+ seq_printf(m, pt(Opt_func), ft(func_post));
+ break;
+ default:
+ snprintf(tbuf, sizeof(tbuf), "%d", entry->func);
+ seq_printf(m, pt(Opt_func), tbuf);
+ break;
+ }
+ seq_puts(m, " ");
+ }
+
+ if (entry->flags & IMA_MASK) {
+ if (entry->mask & MAY_EXEC)
+ seq_printf(m, pt(Opt_mask), mt(mask_exec));
+ if (entry->mask & MAY_WRITE)
+ seq_printf(m, pt(Opt_mask), mt(mask_write));
+ if (entry->mask & MAY_READ)
+ seq_printf(m, pt(Opt_mask), mt(mask_read));
+ if (entry->mask & MAY_APPEND)
+ seq_printf(m, pt(Opt_mask), mt(mask_append));
+ seq_puts(m, " ");
+ }
+
+ if (entry->flags & IMA_FSMAGIC) {
+ snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic);
+ seq_printf(m, pt(Opt_fsmagic), tbuf);
+ seq_puts(m, " ");
+ }
+
+ if (entry->flags & IMA_FSUUID) {
+ seq_puts(m, "fsuuid=");
+ for (i = 0; i < ARRAY_SIZE(entry->fsuuid); ++i) {
+ switch (i) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ seq_puts(m, "-");
+ }
+ seq_printf(m, "%x", entry->fsuuid[i]);
+ }
+ seq_puts(m, " ");
+ }
+
+ if (entry->flags & IMA_UID) {
+ snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
+ seq_printf(m, pt(Opt_uid), tbuf);
+ seq_puts(m, " ");
+ }
+
+ if (entry->flags & IMA_EUID) {
+ snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
+ seq_printf(m, pt(Opt_euid), tbuf);
+ seq_puts(m, " ");
+ }
+
+ if (entry->flags & IMA_FOWNER) {
+ snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
+ seq_printf(m, pt(Opt_fowner), tbuf);
+ seq_puts(m, " ");
+ }
+
+ for (i = 0; i < MAX_LSM_RULES; i++) {
+ if (entry->lsm[i].rule) {
+ switch (i) {
+ case LSM_OBJ_USER:
+ seq_printf(m, pt(Opt_obj_user),
+ (char *)entry->lsm[i].args_p);
+ break;
+ case LSM_OBJ_ROLE:
+ seq_printf(m, pt(Opt_obj_role),
+ (char *)entry->lsm[i].args_p);
+ break;
+ case LSM_OBJ_TYPE:
+ seq_printf(m, pt(Opt_obj_type),
+ (char *)entry->lsm[i].args_p);
+ break;
+ case LSM_SUBJ_USER:
+ seq_printf(m, pt(Opt_subj_user),
+ (char *)entry->lsm[i].args_p);
+ break;
+ case LSM_SUBJ_ROLE:
+ seq_printf(m, pt(Opt_subj_role),
+ (char *)entry->lsm[i].args_p);
+ break;
+ case LSM_SUBJ_TYPE:
+ seq_printf(m, pt(Opt_subj_type),
+ (char *)entry->lsm[i].args_p);
+ break;
+ }
+ }
+ }
+ if (entry->flags & IMA_DIGSIG_REQUIRED)
+ seq_puts(m, "appraise_type=imasig ");
+ if (entry->flags & IMA_PERMIT_DIRECTIO)
+ seq_puts(m, "permit_directio ");
+ rcu_read_unlock();
+ seq_puts(m, "\n");
+ return 0;
+}
+#endif /* CONFIG_IMA_READ_POLICY */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 9c6168709d3b..5efe2ecc538d 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -125,8 +125,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
int __init integrity_read_file(const char *path, char **data);
#define INTEGRITY_KEYRING_EVM 0
-#define INTEGRITY_KEYRING_MODULE 1
-#define INTEGRITY_KEYRING_IMA 2
+#define INTEGRITY_KEYRING_IMA 1
+#define INTEGRITY_KEYRING_MODULE 2
#define INTEGRITY_KEYRING_MAX 3
#ifdef CONFIG_INTEGRITY_SIGNATURE
@@ -149,7 +149,6 @@ static inline int integrity_init_keyring(const unsigned int id)
{
return 0;
}
-
#endif /* CONFIG_INTEGRITY_SIGNATURE */
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
@@ -171,6 +170,14 @@ static inline void ima_load_x509(void)
}
#endif
+#ifdef CONFIG_EVM_LOAD_X509
+void __init evm_load_x509(void);
+#else
+static inline void evm_load_x509(void)
+{
+}
+#endif
+
#ifdef CONFIG_INTEGRITY_AUDIT
/* declarations */
void integrity_audit_msg(int audit_msgno, struct inode *inode,
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 72483b8f1be5..fe4d74e126a7 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -54,6 +54,7 @@ config TRUSTED_KEYS
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_SHA1
+ select CRYPTO_HASH_INFO
help
This option provides support for creating, sealing, and unsealing
keys in the kernel. Trusted keys are random number symmetric keys,
diff --git a/security/keys/key.c b/security/keys/key.c
index ab7997ded725..07a87311055c 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -429,8 +429,11 @@ static int __key_instantiate_and_link(struct key *key,
awaken = 1;
/* and link it into the destination keyring */
- if (keyring)
+ if (keyring) {
+ set_bit(KEY_FLAG_KEEP, &key->flags);
+
__key_link(key, _edit);
+ }
/* disable the authorisation key */
if (authkey)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 1c3872aeed14..ed73c6c1c326 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -358,11 +358,14 @@ error:
* and any links to the key will be automatically garbage collected after a
* certain amount of time (/proc/sys/kernel/keys/gc_delay).
*
+ * Keys with KEY_FLAG_KEEP set should not be revoked.
+ *
* If successful, 0 is returned.
*/
long keyctl_revoke_key(key_serial_t id)
{
key_ref_t key_ref;
+ struct key *key;
long ret;
key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
@@ -377,8 +380,12 @@ long keyctl_revoke_key(key_serial_t id)
}
}
- key_revoke(key_ref_to_ptr(key_ref));
+ key = key_ref_to_ptr(key_ref);
ret = 0;
+ if (test_bit(KEY_FLAG_KEEP, &key->flags))
+ ret = -EPERM;
+ else
+ key_revoke(key);
key_ref_put(key_ref);
error:
@@ -392,11 +399,14 @@ error:
* The key and any links to the key will be automatically garbage collected
* immediately.
*
+ * Keys with KEY_FLAG_KEEP set should not be invalidated.
+ *
* If successful, 0 is returned.
*/
long keyctl_invalidate_key(key_serial_t id)
{
key_ref_t key_ref;
+ struct key *key;
long ret;
kenter("%d", id);
@@ -420,8 +430,12 @@ long keyctl_invalidate_key(key_serial_t id)
}
invalidate:
- key_invalidate(key_ref_to_ptr(key_ref));
+ key = key_ref_to_ptr(key_ref);
ret = 0;
+ if (test_bit(KEY_FLAG_KEEP, &key->flags))
+ ret = -EPERM;
+ else
+ key_invalidate(key);
error_put:
key_ref_put(key_ref);
error:
@@ -433,12 +447,13 @@ error:
* Clear the specified keyring, creating an empty process keyring if one of the
* special keyring IDs is used.
*
- * The keyring must grant the caller Write permission for this to work. If
- * successful, 0 will be returned.
+ * The keyring must grant the caller Write permission and not have
+ * KEY_FLAG_KEEP set for this to work. If successful, 0 will be returned.
*/
long keyctl_keyring_clear(key_serial_t ringid)
{
key_ref_t keyring_ref;
+ struct key *keyring;
long ret;
keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
@@ -460,7 +475,11 @@ long keyctl_keyring_clear(key_serial_t ringid)
}
clear:
- ret = keyring_clear(key_ref_to_ptr(keyring_ref));
+ keyring = key_ref_to_ptr(keyring_ref);
+ if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
+ ret = -EPERM;
+ else
+ ret = keyring_clear(keyring);
error_put:
key_ref_put(keyring_ref);
error:
@@ -511,11 +530,14 @@ error:
* itself need not grant the caller anything. If the last link to a key is
* removed then that key will be scheduled for destruction.
*
+ * Keys or keyrings with KEY_FLAG_KEEP set should not be unlinked.
+ *
* If successful, 0 will be returned.
*/
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
{
key_ref_t keyring_ref, key_ref;
+ struct key *keyring, *key;
long ret;
keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
@@ -530,7 +552,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
goto error2;
}
- ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
+ keyring = key_ref_to_ptr(keyring_ref);
+ key = key_ref_to_ptr(key_ref);
+ if (test_bit(KEY_FLAG_KEEP, &keyring->flags) &&
+ test_bit(KEY_FLAG_KEEP, &key->flags))
+ ret = -EPERM;
+ else
+ ret = key_unlink(keyring, key);
key_ref_put(key_ref);
error2:
@@ -1289,6 +1317,8 @@ error:
* the current time. The key and any links to the key will be automatically
* garbage collected after the timeout expires.
*
+ * Keys with KEY_FLAG_KEEP set should not be timed out.
+ *
* If successful, 0 is returned.
*/
long keyctl_set_timeout(key_serial_t id, unsigned timeout)
@@ -1320,10 +1350,13 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
okay:
key = key_ref_to_ptr(key_ref);
- key_set_timeout(key, timeout);
+ ret = 0;
+ if (test_bit(KEY_FLAG_KEEP, &key->flags))
+ ret = -EPERM;
+ else
+ key_set_timeout(key, timeout);
key_put(key);
- ret = 0;
error:
return ret;
}
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index a3f85d2a00bb..e6d50172872f 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -794,6 +794,7 @@ long join_session_keyring(const char *name)
ret = PTR_ERR(keyring);
goto error2;
} else if (keyring == new->session_keyring) {
+ key_put(keyring);
ret = 0;
goto error2;
}
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 16dec53184b6..0dcab20cdacd 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -11,6 +11,7 @@
* See Documentation/security/keys-trusted-encrypted.txt
*/
+#include <crypto/hash_info.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -710,7 +711,10 @@ enum {
Opt_err = -1,
Opt_new, Opt_load, Opt_update,
Opt_keyhandle, Opt_keyauth, Opt_blobauth,
- Opt_pcrinfo, Opt_pcrlock, Opt_migratable
+ Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
+ Opt_hash,
+ Opt_policydigest,
+ Opt_policyhandle,
};
static const match_table_t key_tokens = {
@@ -723,6 +727,9 @@ static const match_table_t key_tokens = {
{Opt_pcrinfo, "pcrinfo=%s"},
{Opt_pcrlock, "pcrlock=%s"},
{Opt_migratable, "migratable=%s"},
+ {Opt_hash, "hash=%s"},
+ {Opt_policydigest, "policydigest=%s"},
+ {Opt_policyhandle, "policyhandle=%s"},
{Opt_err, NULL}
};
@@ -736,11 +743,23 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
int res;
unsigned long handle;
unsigned long lock;
+ unsigned long token_mask = 0;
+ int i;
+ int tpm2;
+
+ tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+ if (tpm2 < 0)
+ return tpm2;
+
+ opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
+ opt->digest_len = hash_digest_size[opt->hash];
while ((p = strsep(&c, " \t"))) {
if (*p == '\0' || *p == ' ' || *p == '\t')
continue;
token = match_token(p, key_tokens, args);
+ if (test_and_set_bit(token, &token_mask))
+ return -EINVAL;
switch (token) {
case Opt_pcrinfo:
@@ -787,6 +806,41 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
return -EINVAL;
opt->pcrlock = lock;
break;
+ case Opt_hash:
+ if (test_bit(Opt_policydigest, &token_mask))
+ return -EINVAL;
+ for (i = 0; i < HASH_ALGO__LAST; i++) {
+ if (!strcmp(args[0].from, hash_algo_name[i])) {
+ opt->hash = i;
+ opt->digest_len =
+ hash_digest_size[opt->hash];
+ break;
+ }
+ }
+ if (i == HASH_ALGO__LAST)
+ return -EINVAL;
+ if (!tpm2 && i != HASH_ALGO_SHA1) {
+ pr_info("trusted_key: TPM 1.x only supports SHA-1.\n");
+ return -EINVAL;
+ }
+ break;
+ case Opt_policydigest:
+ if (!tpm2 ||
+ strlen(args[0].from) != (2 * opt->digest_len))
+ return -EINVAL;
+ res = hex2bin(opt->policydigest, args[0].from,
+ opt->digest_len);
+ if (res < 0)
+ return -EINVAL;
+ break;
+ case Opt_policyhandle:
+ if (!tpm2)
+ return -EINVAL;
+ res = kstrtoul(args[0].from, 16, &handle);
+ if (res < 0)
+ return -EINVAL;
+ opt->policyhandle = handle;
+ break;
default:
return -EINVAL;
}
diff --git a/security/security.c b/security/security.c
index 46f405ce6b0f..e8ffd92ae2eb 100644
--- a/security/security.c
+++ b/security/security.c
@@ -697,7 +697,7 @@ int security_inode_killpriv(struct dentry *dentry)
return call_int_hook(inode_killpriv, 0, dentry);
}
-int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
+int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
{
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
@@ -721,7 +721,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
}
EXPORT_SYMBOL(security_inode_listsecurity);
-void security_inode_getsecid(const struct inode *inode, u32 *secid)
+void security_inode_getsecid(struct inode *inode, u32 *secid)
{
call_void_hook(inode_getsecid, inode, secid);
}
@@ -1161,6 +1161,12 @@ void security_release_secctx(char *secdata, u32 seclen)
}
EXPORT_SYMBOL(security_release_secctx);
+void security_inode_invalidate_secctx(struct inode *inode)
+{
+ call_void_hook(inode_invalidate_secctx, inode);
+}
+EXPORT_SYMBOL(security_inode_invalidate_secctx);
+
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
return call_int_hook(inode_notifysecctx, 0, inode, ctx, ctxlen);
@@ -1763,6 +1769,8 @@ struct security_hook_heads security_hook_heads = {
LIST_HEAD_INIT(security_hook_heads.secctx_to_secid),
.release_secctx =
LIST_HEAD_INIT(security_hook_heads.release_secctx),
+ .inode_invalidate_secctx =
+ LIST_HEAD_INIT(security_hook_heads.inode_invalidate_secctx),
.inode_notifysecctx =
LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx),
.inode_setsecctx =
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d0cfaa9f19d0..f8110cfd80ff 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -242,6 +242,72 @@ static int inode_alloc_security(struct inode *inode)
return 0;
}
+static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
+
+/*
+ * Try reloading inode security labels that have been marked as invalid. The
+ * @may_sleep parameter indicates when sleeping and thus reloading labels is
+ * allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is
+ * invalid. The @opt_dentry parameter should be set to a dentry of the inode;
+ * when no dentry is available, set it to NULL instead.
+ */
+static int __inode_security_revalidate(struct inode *inode,
+ struct dentry *opt_dentry,
+ bool may_sleep)
+{
+ struct inode_security_struct *isec = inode->i_security;
+
+ might_sleep_if(may_sleep);
+
+ if (isec->initialized == LABEL_INVALID) {
+ if (!may_sleep)
+ return -ECHILD;
+
+ /*
+ * Try reloading the inode security label. This will fail if
+ * @opt_dentry is NULL and no dentry for this inode can be
+ * found; in that case, continue using the old label.
+ */
+ inode_doinit_with_dentry(inode, opt_dentry);
+ }
+ return 0;
+}
+
+static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
+{
+ return inode->i_security;
+}
+
+static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
+{
+ int error;
+
+ error = __inode_security_revalidate(inode, NULL, !rcu);
+ if (error)
+ return ERR_PTR(error);
+ return inode->i_security;
+}
+
+/*
+ * Get the security label of an inode.
+ */
+static struct inode_security_struct *inode_security(struct inode *inode)
+{
+ __inode_security_revalidate(inode, NULL, true);
+ return inode->i_security;
+}
+
+/*
+ * Get the security label of a dentry's backing inode.
+ */
+static struct inode_security_struct *backing_inode_security(struct dentry *dentry)
+{
+ struct inode *inode = d_backing_inode(dentry);
+
+ __inode_security_revalidate(inode, dentry, true);
+ return inode->i_security;
+}
+
static void inode_free_rcu(struct rcu_head *head)
{
struct inode_security_struct *isec;
@@ -345,8 +411,6 @@ static const char *labeling_behaviors[7] = {
"uses native labeling",
};
-static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
-
static inline int inode_doinit(struct inode *inode)
{
return inode_doinit_with_dentry(inode, NULL);
@@ -565,8 +629,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
}
if (sbsec->flags & ROOTCONTEXT_MNT) {
- struct inode *root = d_backing_inode(sbsec->sb->s_root);
- struct inode_security_struct *isec = root->i_security;
+ struct dentry *root = sbsec->sb->s_root;
+ struct inode_security_struct *isec = backing_inode_security(root);
rc = security_sid_to_context(isec->sid, &context, &len);
if (rc)
@@ -621,8 +685,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
int rc = 0, i;
struct superblock_security_struct *sbsec = sb->s_security;
const char *name = sb->s_type->name;
- struct inode *inode = d_backing_inode(sbsec->sb->s_root);
- struct inode_security_struct *root_isec = inode->i_security;
+ struct dentry *root = sbsec->sb->s_root;
+ struct inode_security_struct *root_isec = backing_inode_security(root);
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0;
char **mount_options = opts->mnt_opts;
@@ -802,7 +866,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
goto out;
root_isec->sid = rootcontext_sid;
- root_isec->initialized = 1;
+ root_isec->initialized = LABEL_INITIALIZED;
}
if (defcontext_sid) {
@@ -852,8 +916,8 @@ static int selinux_cmp_sb_context(const struct super_block *oldsb,
if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
goto mismatch;
if (oldflags & ROOTCONTEXT_MNT) {
- struct inode_security_struct *oldroot = d_backing_inode(oldsb->s_root)->i_security;
- struct inode_security_struct *newroot = d_backing_inode(newsb->s_root)->i_security;
+ struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root);
+ struct inode_security_struct *newroot = backing_inode_security(newsb->s_root);
if (oldroot->sid != newroot->sid)
goto mismatch;
}
@@ -903,17 +967,14 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (!set_fscontext)
newsbsec->sid = sid;
if (!set_rootcontext) {
- struct inode *newinode = d_backing_inode(newsb->s_root);
- struct inode_security_struct *newisec = newinode->i_security;
+ struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
newisec->sid = sid;
}
newsbsec->mntpoint_sid = sid;
}
if (set_rootcontext) {
- const struct inode *oldinode = d_backing_inode(oldsb->s_root);
- const struct inode_security_struct *oldisec = oldinode->i_security;
- struct inode *newinode = d_backing_inode(newsb->s_root);
- struct inode_security_struct *newisec = newinode->i_security;
+ const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root);
+ struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
newisec->sid = oldisec->sid;
}
@@ -1293,11 +1354,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
unsigned len = 0;
int rc = 0;
- if (isec->initialized)
+ if (isec->initialized == LABEL_INITIALIZED)
goto out;
mutex_lock(&isec->lock);
- if (isec->initialized)
+ if (isec->initialized == LABEL_INITIALIZED)
goto out_unlock;
sbsec = inode->i_sb->s_security;
@@ -1469,7 +1530,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
break;
}
- isec->initialized = 1;
+ isec->initialized = LABEL_INITIALIZED;
out_unlock:
mutex_unlock(&isec->lock);
@@ -1640,6 +1701,7 @@ static inline int dentry_has_perm(const struct cred *cred,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
+ __inode_security_revalidate(inode, dentry, true);
return inode_has_perm(cred, inode, av, &ad);
}
@@ -1655,6 +1717,7 @@ static inline int path_has_perm(const struct cred *cred,
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = *path;
+ __inode_security_revalidate(inode, path->dentry, true);
return inode_has_perm(cred, inode, av, &ad);
}
@@ -1712,13 +1775,13 @@ out:
/*
* Determine the label for an inode that might be unioned.
*/
-static int selinux_determine_inode_label(const struct inode *dir,
+static int selinux_determine_inode_label(struct inode *dir,
const struct qstr *name,
u16 tclass,
u32 *_new_isid)
{
const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
- const struct inode_security_struct *dsec = dir->i_security;
+ const struct inode_security_struct *dsec = inode_security(dir);
const struct task_security_struct *tsec = current_security();
if ((sbsec->flags & SE_SBINITIALIZED) &&
@@ -1747,7 +1810,7 @@ static int may_create(struct inode *dir,
struct common_audit_data ad;
int rc;
- dsec = dir->i_security;
+ dsec = inode_security(dir);
sbsec = dir->i_sb->s_security;
sid = tsec->sid;
@@ -1800,8 +1863,8 @@ static int may_link(struct inode *dir,
u32 av;
int rc;
- dsec = dir->i_security;
- isec = d_backing_inode(dentry)->i_security;
+ dsec = inode_security(dir);
+ isec = backing_inode_security(dentry);
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
@@ -1844,10 +1907,10 @@ static inline int may_rename(struct inode *old_dir,
int old_is_dir, new_is_dir;
int rc;
- old_dsec = old_dir->i_security;
- old_isec = d_backing_inode(old_dentry)->i_security;
+ old_dsec = inode_security(old_dir);
+ old_isec = backing_inode_security(old_dentry);
old_is_dir = d_is_dir(old_dentry);
- new_dsec = new_dir->i_security;
+ new_dsec = inode_security(new_dir);
ad.type = LSM_AUDIT_DATA_DENTRY;
@@ -1875,7 +1938,7 @@ static inline int may_rename(struct inode *old_dir,
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
- new_isec = d_backing_inode(new_dentry)->i_security;
+ new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry);
rc = avc_has_perm(sid, new_isec->sid,
new_isec->sclass,
@@ -2011,8 +2074,8 @@ static int selinux_binder_transfer_file(struct task_struct *from,
{
u32 sid = task_sid(to);
struct file_security_struct *fsec = file->f_security;
- struct inode *inode = d_backing_inode(file->f_path.dentry);
- struct inode_security_struct *isec = inode->i_security;
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode_security_struct *isec = backing_inode_security(dentry);
struct common_audit_data ad;
int rc;
@@ -2028,7 +2091,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
return rc;
}
- if (unlikely(IS_PRIVATE(inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
@@ -2217,7 +2280,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
old_tsec = current_security();
new_tsec = bprm->cred->security;
- isec = inode->i_security;
+ isec = inode_security(inode);
/* Default to the current task SID. */
new_tsec->sid = old_tsec->sid;
@@ -2639,7 +2702,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
break;
case ROOTCONTEXT_MNT: {
struct inode_security_struct *root_isec;
- root_isec = d_backing_inode(sb->s_root)->i_security;
+ root_isec = backing_inode_security(sb->s_root);
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
goto out_bad_option;
@@ -2753,13 +2816,11 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
void **value, size_t *len)
{
const struct task_security_struct *tsec = current_security();
- struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
u32 sid, newsid, clen;
int rc;
char *context;
- dsec = dir->i_security;
sbsec = dir->i_sb->s_security;
sid = tsec->sid;
@@ -2777,7 +2838,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
struct inode_security_struct *isec = inode->i_security;
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
- isec->initialized = 1;
+ isec->initialized = LABEL_INITIALIZED;
}
if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT))
@@ -2858,7 +2919,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
sid = cred_sid(cred);
- isec = inode->i_security;
+ isec = inode_security_rcu(inode, rcu);
+ if (IS_ERR(isec))
+ return PTR_ERR(isec);
return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
rcu ? MAY_NOT_BLOCK : 0);
@@ -2910,7 +2973,9 @@ static int selinux_inode_permission(struct inode *inode, int mask)
perms = file_mask_to_av(inode->i_mode, mask);
sid = cred_sid(cred);
- isec = inode->i_security;
+ isec = inode_security_rcu(inode, flags & MAY_NOT_BLOCK);
+ if (IS_ERR(isec))
+ return PTR_ERR(isec);
rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
audited = avc_audit_required(perms, &avd, rc,
@@ -2980,7 +3045,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = d_backing_inode(dentry);
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = backing_inode_security(dentry);
struct superblock_security_struct *sbsec;
struct common_audit_data ad;
u32 newsid, sid = current_sid();
@@ -3057,7 +3122,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
int flags)
{
struct inode *inode = d_backing_inode(dentry);
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = backing_inode_security(dentry);
u32 newsid;
int rc;
@@ -3076,7 +3141,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
- isec->initialized = 1;
+ isec->initialized = LABEL_INITIALIZED;
return;
}
@@ -3110,12 +3175,12 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
*
* Permission check is handled by selinux_inode_getxattr hook.
*/
-static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
+static int selinux_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
{
u32 size;
int error;
char *context = NULL;
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = inode_security(inode);
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
@@ -3154,7 +3219,7 @@ out_nofree:
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = inode_security(inode);
u32 newsid;
int rc;
@@ -3170,7 +3235,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
- isec->initialized = 1;
+ isec->initialized = LABEL_INITIALIZED;
return 0;
}
@@ -3182,9 +3247,9 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
return len;
}
-static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
+static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = inode_security(inode);
*secid = isec->sid;
}
@@ -3207,13 +3272,14 @@ static int selinux_file_permission(struct file *file, int mask)
{
struct inode *inode = file_inode(file);
struct file_security_struct *fsec = file->f_security;
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec;
u32 sid = current_sid();
if (!mask)
/* No permission to check. Existence test. */
return 0;
+ isec = inode_security(inode);
if (sid == fsec->sid && fsec->isid == isec->sid &&
fsec->pseqno == avc_policy_seqno())
/* No change since file_open check. */
@@ -3242,7 +3308,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
struct common_audit_data ad;
struct file_security_struct *fsec = file->f_security;
struct inode *inode = file_inode(file);
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = inode_security(inode);
struct lsm_ioctlop_audit ioctl;
u32 ssid = cred_sid(cred);
int rc;
@@ -3506,7 +3572,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
struct inode_security_struct *isec;
fsec = file->f_security;
- isec = file_inode(file)->i_security;
+ isec = inode_security(file_inode(file));
/*
* Save inode label and policy sequence number
* at open-time so that selinux_file_permission
@@ -3624,7 +3690,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
*/
static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = inode_security(inode);
struct task_security_struct *tsec = new->security;
u32 sid = current_sid();
int ret;
@@ -3748,7 +3814,7 @@ static void selinux_task_to_inode(struct task_struct *p,
u32 sid = task_sid(p);
isec->sid = sid;
- isec->initialized = 1;
+ isec->initialized = LABEL_INITIALIZED;
}
/* Returns error only if unable to parse addresses */
@@ -4065,7 +4131,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
const struct task_security_struct *tsec = current_security();
- struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+ struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
struct sk_security_struct *sksec;
int err = 0;
@@ -4079,7 +4145,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
return err;
}
- isec->initialized = 1;
+ isec->initialized = LABEL_INITIALIZED;
if (sock->sk) {
sksec = sock->sk->sk_security;
@@ -4265,12 +4331,12 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
if (err)
return err;
- newisec = SOCK_INODE(newsock)->i_security;
+ newisec = inode_security_novalidate(SOCK_INODE(newsock));
- isec = SOCK_INODE(sock)->i_security;
+ isec = inode_security_novalidate(SOCK_INODE(sock));
newisec->sclass = isec->sclass;
newisec->sid = isec->sid;
- newisec->initialized = 1;
+ newisec->initialized = LABEL_INITIALIZED;
return 0;
}
@@ -4605,7 +4671,8 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
static void selinux_sock_graft(struct sock *sk, struct socket *parent)
{
- struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
+ struct inode_security_struct *isec =
+ inode_security_novalidate(SOCK_INODE(parent));
struct sk_security_struct *sksec = sk->sk_security;
if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
@@ -4785,11 +4852,12 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
if (err) {
if (err == -EINVAL) {
- printk(KERN_WARNING
- "SELinux: unrecognized netlink message:"
- " protocol=%hu nlmsg_type=%hu sclass=%s\n",
+ pr_warn_ratelimited("SELinux: unrecognized netlink"
+ " message: protocol=%hu nlmsg_type=%hu sclass=%s"
+ " pig=%d comm=%s\n",
sk->sk_protocol, nlh->nlmsg_type,
- secclass_map[sksec->sclass - 1].name);
+ secclass_map[sksec->sclass - 1].name,
+ task_pid_nr(current), current->comm);
if (!selinux_enforcing || security_get_allow_unknown())
err = 0;
}
@@ -5762,6 +5830,15 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
kfree(secdata);
}
+static void selinux_inode_invalidate_secctx(struct inode *inode)
+{
+ struct inode_security_struct *isec = inode->i_security;
+
+ mutex_lock(&isec->lock);
+ isec->initialized = LABEL_INVALID;
+ mutex_unlock(&isec->lock);
+}
+
/*
* called with inode->i_mutex locked
*/
@@ -5993,6 +6070,7 @@ static struct security_hook_list selinux_hooks[] = {
LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
+ LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 5a4eef59aeff..ef83c4b85a33 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -21,7 +21,7 @@ struct security_class_mapping secclass_map[] = {
{ "compute_av", "compute_create", "compute_member",
"check_context", "load_policy", "compute_relabel",
"compute_user", "setenforce", "setbool", "setsecparam",
- "setcheckreqprot", "read_policy", NULL } },
+ "setcheckreqprot", "read_policy", "validate_trans", NULL } },
{ "process",
{ "fork", "transition", "sigchld", "sigkill",
"sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 81fa718d5cb3..a2ae05414ba1 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -37,6 +37,12 @@ struct task_security_struct {
u32 sockcreate_sid; /* fscreate SID */
};
+enum label_initialized {
+ LABEL_MISSING, /* not initialized */
+ LABEL_INITIALIZED, /* inizialized */
+ LABEL_INVALID /* invalid */
+};
+
struct inode_security_struct {
struct inode *inode; /* back pointer to inode object */
union {
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 223e9fd15d66..38feb55d531a 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -187,6 +187,9 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass);
+int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 tclass);
+
int security_bounded_transition(u32 oldsid, u32 newsid);
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 73c60baa90a4..732c1c77dccd 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -116,6 +116,7 @@ enum sel_inos {
SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
SEL_STATUS, /* export current status using mmap() */
SEL_POLICY, /* allow userspace to read the in kernel policy */
+ SEL_VALIDATE_TRANS, /* compute validatetrans decision */
SEL_INO_NEXT, /* The next inode number to use */
};
@@ -632,6 +633,83 @@ static const struct file_operations sel_checkreqprot_ops = {
.llseek = generic_file_llseek,
};
+static ssize_t sel_write_validatetrans(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
+ char *req = NULL;
+ u32 osid, nsid, tsid;
+ u16 tclass;
+ int rc;
+
+ rc = task_has_security(current, SECURITY__VALIDATE_TRANS);
+ if (rc)
+ goto out;
+
+ rc = -ENOMEM;
+ if (count >= PAGE_SIZE)
+ goto out;
+
+ /* No partial writes. */
+ rc = -EINVAL;
+ if (*ppos != 0)
+ goto out;
+
+ rc = -ENOMEM;
+ req = kzalloc(count + 1, GFP_KERNEL);
+ if (!req)
+ goto out;
+
+ rc = -EFAULT;
+ if (copy_from_user(req, buf, count))
+ goto out;
+
+ rc = -ENOMEM;
+ oldcon = kzalloc(count + 1, GFP_KERNEL);
+ if (!oldcon)
+ goto out;
+
+ newcon = kzalloc(count + 1, GFP_KERNEL);
+ if (!newcon)
+ goto out;
+
+ taskcon = kzalloc(count + 1, GFP_KERNEL);
+ if (!taskcon)
+ goto out;
+
+ rc = -EINVAL;
+ if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
+ goto out;
+
+ rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL);
+ if (rc)
+ goto out;
+
+ rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL);
+ if (rc)
+ goto out;
+
+ rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL);
+ if (rc)
+ goto out;
+
+ rc = security_validate_transition_user(osid, nsid, tsid, tclass);
+ if (!rc)
+ rc = count;
+out:
+ kfree(req);
+ kfree(oldcon);
+ kfree(newcon);
+ kfree(taskcon);
+ return rc;
+}
+
+static const struct file_operations sel_transition_ops = {
+ .write = sel_write_validatetrans,
+ .llseek = generic_file_llseek,
+};
+
/*
* Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
*/
@@ -1727,6 +1805,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
+ [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
+ S_IWUGO},
/* last one */ {""}
};
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ebb5eb3c318c..ebda97333f1b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -778,8 +778,8 @@ out:
return -EPERM;
}
-int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
- u16 orig_tclass)
+static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 orig_tclass, bool user)
{
struct context *ocontext;
struct context *ncontext;
@@ -794,11 +794,12 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
read_lock(&policy_rwlock);
- tclass = unmap_class(orig_tclass);
+ if (!user)
+ tclass = unmap_class(orig_tclass);
+ else
+ tclass = orig_tclass;
if (!tclass || tclass > policydb.p_classes.nprim) {
- printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
- __func__, tclass);
rc = -EINVAL;
goto out;
}
@@ -832,8 +833,13 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
while (constraint) {
if (!constraint_expr_eval(ocontext, ncontext, tcontext,
constraint->expr)) {
- rc = security_validtrans_handle_fail(ocontext, ncontext,
- tcontext, tclass);
+ if (user)
+ rc = -EPERM;
+ else
+ rc = security_validtrans_handle_fail(ocontext,
+ ncontext,
+ tcontext,
+ tclass);
goto out;
}
constraint = constraint->next;
@@ -844,6 +850,20 @@ out:
return rc;
}
+int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 tclass)
+{
+ return security_compute_validatetrans(oldsid, newsid, tasksid,
+ tclass, true);
+}
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 orig_tclass)
+{
+ return security_compute_validatetrans(oldsid, newsid, tasksid,
+ orig_tclass, false);
+}
+
/*
* security_bounded_transition - check whether the given
* transition is directed to bounded, or not.
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 37fdd5416a64..8d85435a45d7 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1465,7 +1465,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
*
* Returns the size of the attribute or an error code
*/
-static int smack_inode_getsecurity(const struct inode *inode,
+static int smack_inode_getsecurity(struct inode *inode,
const char *name, void **buffer,
bool alloc)
{
@@ -1536,7 +1536,7 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
* @inode: inode to extract the info from
* @secid: where result will be saved
*/
-static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
+static void smack_inode_getsecid(struct inode *inode, u32 *secid)
{
struct inode_smack *isp = inode->i_security;
@@ -1858,12 +1858,34 @@ static int smack_file_receive(struct file *file)
int may = 0;
struct smk_audit_info ad;
struct inode *inode = file_inode(file);
+ struct socket *sock;
+ struct task_smack *tsp;
+ struct socket_smack *ssp;
if (unlikely(IS_PRIVATE(inode)))
return 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
+
+ if (S_ISSOCK(inode->i_mode)) {
+ sock = SOCKET_I(inode);
+ ssp = sock->sk->sk_security;
+ tsp = current_security();
+ /*
+ * If the receiving process can't write to the
+ * passed socket or if the passed socket can't
+ * write to the receiving process don't accept
+ * the passed socket.
+ */
+ rc = smk_access(tsp->smk_task, ssp->smk_out, MAY_WRITE, &ad);
+ rc = smk_bu_file(file, may, rc);
+ if (rc < 0)
+ return rc;
+ rc = smk_access(ssp->smk_in, tsp->smk_task, MAY_WRITE, &ad);
+ rc = smk_bu_file(file, may, rc);
+ return rc;
+ }
/*
* This code relies on bitmasks.
*/
@@ -3756,7 +3778,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
if (sip == NULL)
return 0;
- switch (sip->sin_family) {
+ switch (sock->sk->sk_family) {
case AF_INET:
rc = smack_netlabel_send(sock->sk, sip);
break;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index b123c42e7dc8..18b8dc45bb8f 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -38,8 +38,10 @@
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/module.h>
+#include <linux/compat.h>
#include <sound/core.h>
#include <sound/initval.h>
+#include <sound/info.h>
#include <sound/compress_params.h>
#include <sound/compress_offload.h>
#include <sound/compress_driver.h>
@@ -847,6 +849,15 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return retval;
}
+/* support of 32bit userspace on 64bit platforms */
+#ifdef CONFIG_COMPAT
+static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return snd_compr_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static const struct file_operations snd_compr_file_ops = {
.owner = THIS_MODULE,
.open = snd_compr_open,
@@ -854,6 +865,9 @@ static const struct file_operations snd_compr_file_ops = {
.write = snd_compr_write,
.read = snd_compr_read,
.unlocked_ioctl = snd_compr_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = snd_compr_ioctl_compat,
+#endif
.mmap = snd_compr_mmap,
.poll = snd_compr_poll,
};
@@ -891,11 +905,85 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
return 0;
}
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+static void snd_compress_proc_info_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_compr *compr = (struct snd_compr *)entry->private_data;
+
+ snd_iprintf(buffer, "card: %d\n", compr->card->number);
+ snd_iprintf(buffer, "device: %d\n", compr->device);
+ snd_iprintf(buffer, "stream: %s\n",
+ compr->direction == SND_COMPRESS_PLAYBACK
+ ? "PLAYBACK" : "CAPTURE");
+ snd_iprintf(buffer, "id: %s\n", compr->id);
+}
+
+static int snd_compress_proc_init(struct snd_compr *compr)
+{
+ struct snd_info_entry *entry;
+ char name[16];
+
+ sprintf(name, "compr%i", compr->device);
+ entry = snd_info_create_card_entry(compr->card, name,
+ compr->card->proc_root);
+ if (!entry)
+ return -ENOMEM;
+ entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ return -ENOMEM;
+ }
+ compr->proc_root = entry;
+
+ entry = snd_info_create_card_entry(compr->card, "info",
+ compr->proc_root);
+ if (entry) {
+ snd_info_set_text_ops(entry, compr,
+ snd_compress_proc_info_read);
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
+ }
+ }
+ compr->proc_info_entry = entry;
+
+ return 0;
+}
+
+static void snd_compress_proc_done(struct snd_compr *compr)
+{
+ snd_info_free_entry(compr->proc_info_entry);
+ compr->proc_info_entry = NULL;
+ snd_info_free_entry(compr->proc_root);
+ compr->proc_root = NULL;
+}
+
+static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)
+{
+ strlcpy(compr->id, id, sizeof(compr->id));
+}
+#else
+static inline int snd_compress_proc_init(struct snd_compr *compr)
+{
+ return 0;
+}
+
+static inline void snd_compress_proc_done(struct snd_compr *compr)
+{
+}
+
+static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)
+{
+}
+#endif
+
static int snd_compress_dev_free(struct snd_device *device)
{
struct snd_compr *compr;
compr = device->device_data;
+ snd_compress_proc_done(compr);
put_device(&compr->dev);
return 0;
}
@@ -908,22 +996,29 @@ static int snd_compress_dev_free(struct snd_device *device)
* @compr: compress device pointer
*/
int snd_compress_new(struct snd_card *card, int device,
- int dirn, struct snd_compr *compr)
+ int dirn, const char *id, struct snd_compr *compr)
{
static struct snd_device_ops ops = {
.dev_free = snd_compress_dev_free,
.dev_register = snd_compress_dev_register,
.dev_disconnect = snd_compress_dev_disconnect,
};
+ int ret;
compr->card = card;
compr->device = device;
compr->direction = dirn;
+ snd_compress_set_id(compr, id);
+
snd_device_initialize(&compr->dev, card);
dev_set_name(&compr->dev, "comprC%iD%i", card->number, device);
- return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
+ ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
+ if (ret == 0)
+ snd_compress_proc_init(compr);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_compress_new);
diff --git a/sound/core/init.c b/sound/core/init.c
index 20f37fb3800e..6bda8436d765 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -268,6 +268,9 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
if (err < 0)
goto __error;
+ snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s",
+ dev_driver_string(card->dev), dev_name(&card->card_dev));
+
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 7a8c79dd9734..2ff9c12d664a 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -24,6 +24,7 @@
#include <linux/time.h>
#include <linux/string.h>
#include <linux/module.h>
+#include <linux/compat.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/control.h>
@@ -397,7 +398,12 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l
#ifdef CONFIG_COMPAT
/* all compatible */
-#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl
+static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return snd_mixer_oss_ioctl1(file->private_data, cmd,
+ (unsigned long)compat_ptr(arg));
+}
#else
#define snd_mixer_oss_ioctl_compat NULL
#endif
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 58550cc93f28..0e73d03b30e3 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -33,6 +33,7 @@
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/string.h>
+#include <linux/compat.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/pcm.h>
@@ -850,7 +851,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
if (mutex_lock_interruptible(&runtime->oss.params_lock))
return -EINTR;
- sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
+ sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
params = kmalloc(sizeof(*params), GFP_KERNEL);
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
if (!sw_params || !params || !sparams) {
@@ -988,7 +989,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
goto failure;
}
- memset(sw_params, 0, sizeof(*sw_params));
if (runtime->oss.trigger) {
sw_params->start_threshold = 1;
} else {
@@ -2648,7 +2648,11 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
#ifdef CONFIG_COMPAT
/* all compatible */
-#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl
+static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
#else
#define snd_pcm_oss_ioctl_compat NULL
#endif
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index fba365a78390..697c166acf05 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -202,13 +202,13 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (runtime->info & SNDRV_PCM_INFO_PAUSE)
dmaengine_pause(prtd->dma_chan);
else
- dmaengine_terminate_all(prtd->dma_chan);
+ dmaengine_terminate_async(prtd->dma_chan);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dmaengine_pause(prtd->dma_chan);
break;
case SNDRV_PCM_TRIGGER_STOP:
- dmaengine_terminate_all(prtd->dma_chan);
+ dmaengine_terminate_async(prtd->dma_chan);
break;
default:
return -EINVAL;
@@ -346,6 +346,7 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ dmaengine_synchronize(prtd->dma_chan);
kfree(prtd);
return 0;
@@ -362,9 +363,11 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ dmaengine_synchronize(prtd->dma_chan);
dma_release_channel(prtd->dma_chan);
+ kfree(prtd);
- return snd_dmaengine_pcm_close(substream);
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a8b27cdc2844..fadd3eb8e8bb 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -875,7 +875,7 @@ struct action_ops {
* Note: the stream state might be changed also on failure
* Note2: call with calling stream lock + link lock
*/
-static int snd_pcm_action_group(struct action_ops *ops,
+static int snd_pcm_action_group(const struct action_ops *ops,
struct snd_pcm_substream *substream,
int state, int do_lock)
{
@@ -932,7 +932,7 @@ static int snd_pcm_action_group(struct action_ops *ops,
/*
* Note: call with stream lock
*/
-static int snd_pcm_action_single(struct action_ops *ops,
+static int snd_pcm_action_single(const struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
@@ -952,7 +952,7 @@ static int snd_pcm_action_single(struct action_ops *ops,
/*
* Note: call with stream lock
*/
-static int snd_pcm_action(struct action_ops *ops,
+static int snd_pcm_action(const struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
@@ -984,7 +984,7 @@ static int snd_pcm_action(struct action_ops *ops,
/*
* Note: don't use any locks before
*/
-static int snd_pcm_action_lock_irq(struct action_ops *ops,
+static int snd_pcm_action_lock_irq(const struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
@@ -998,7 +998,7 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
/*
*/
-static int snd_pcm_action_nonatomic(struct action_ops *ops,
+static int snd_pcm_action_nonatomic(const struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
@@ -1056,7 +1056,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
-static struct action_ops snd_pcm_action_start = {
+static const struct action_ops snd_pcm_action_start = {
.pre_action = snd_pcm_pre_start,
.do_action = snd_pcm_do_start,
.undo_action = snd_pcm_undo_start,
@@ -1107,7 +1107,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
wake_up(&runtime->tsleep);
}
-static struct action_ops snd_pcm_action_stop = {
+static const struct action_ops snd_pcm_action_stop = {
.pre_action = snd_pcm_pre_stop,
.do_action = snd_pcm_do_stop,
.post_action = snd_pcm_post_stop
@@ -1224,7 +1224,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
}
}
-static struct action_ops snd_pcm_action_pause = {
+static const struct action_ops snd_pcm_action_pause = {
.pre_action = snd_pcm_pre_pause,
.do_action = snd_pcm_do_pause,
.undo_action = snd_pcm_undo_pause,
@@ -1273,7 +1273,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
wake_up(&runtime->tsleep);
}
-static struct action_ops snd_pcm_action_suspend = {
+static const struct action_ops snd_pcm_action_suspend = {
.pre_action = snd_pcm_pre_suspend,
.do_action = snd_pcm_do_suspend,
.post_action = snd_pcm_post_suspend
@@ -1375,7 +1375,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
}
-static struct action_ops snd_pcm_action_resume = {
+static const struct action_ops snd_pcm_action_resume = {
.pre_action = snd_pcm_pre_resume,
.do_action = snd_pcm_do_resume,
.undo_action = snd_pcm_undo_resume,
@@ -1478,7 +1478,7 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state)
snd_pcm_playback_silence(substream, ULONG_MAX);
}
-static struct action_ops snd_pcm_action_reset = {
+static const struct action_ops snd_pcm_action_reset = {
.pre_action = snd_pcm_pre_reset,
.do_action = snd_pcm_do_reset,
.post_action = snd_pcm_post_reset
@@ -1522,7 +1522,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
}
-static struct action_ops snd_pcm_action_prepare = {
+static const struct action_ops snd_pcm_action_prepare = {
.pre_action = snd_pcm_pre_prepare,
.do_action = snd_pcm_do_prepare,
.post_action = snd_pcm_post_prepare
@@ -1618,7 +1618,7 @@ static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int sta
{
}
-static struct action_ops snd_pcm_action_drain_init = {
+static const struct action_ops snd_pcm_action_drain_init = {
.pre_action = snd_pcm_pre_drain_init,
.do_action = snd_pcm_do_drain_init,
.post_action = snd_pcm_post_drain_init
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 7354b8bed860..8db156b207f1 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/compat.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/initval.h>
@@ -189,7 +190,11 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
#ifdef CONFIG_COMPAT
-#define odev_ioctl_compat odev_ioctl
+static long odev_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return odev_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
#else
#define odev_ioctl_compat NULL
#endif
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index b64f20deba90..13cfa815732d 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1962,7 +1962,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client,
* No restrictions so for a user client we can clear
* the whole fifo
*/
- if (client->type == USER_CLIENT)
+ if (client->type == USER_CLIENT && client->data.user.fifo)
snd_seq_fifo_clear(client->data.user.fifo);
}
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 7dfd0f429410..0bec02e89d51 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -142,8 +142,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked)
static void queue_delete(struct snd_seq_queue *q)
{
/* stop and release the timer */
+ mutex_lock(&q->timer_mutex);
snd_seq_timer_stop(q->timer);
snd_seq_timer_close(q);
+ mutex_unlock(&q->timer_mutex);
/* wait until access free */
snd_use_lock_sync(&q->use_lock);
/* release resources... */
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 56e0f4cd3f82..3da2d48610b3 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -468,7 +468,7 @@ static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi)
/*
*
*/
-static struct snd_rawmidi_global_ops snd_virmidi_global_ops = {
+static const struct snd_rawmidi_global_ops snd_virmidi_global_ops = {
.dev_register = snd_virmidi_dev_register,
.dev_unregister = snd_virmidi_dev_unregister,
};
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 31f40f03e5b7..cb25aded5349 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -73,7 +73,7 @@ struct snd_timer_user {
struct timespec tstamp; /* trigger tstamp */
wait_queue_head_t qchange_sleep;
struct fasync_struct *fasync;
- struct mutex tread_sem;
+ struct mutex ioctl_lock;
};
/* list of timers */
@@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
slave->slave_id == master->slave_id) {
list_move_tail(&slave->open_list, &master->slave_list_head);
spin_lock_irq(&slave_active_lock);
+ spin_lock(&master->timer->lock);
slave->master = master;
slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
list_add_tail(&slave->active_list,
&master->slave_active_head);
+ spin_unlock(&master->timer->lock);
spin_unlock_irq(&slave_active_lock);
}
}
@@ -299,8 +301,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
return 0;
}
-static int _snd_timer_stop(struct snd_timer_instance *timeri,
- int keep_flag, int event);
+static int _snd_timer_stop(struct snd_timer_instance *timeri, int event);
/*
* close a timer instance
@@ -342,19 +343,22 @@ int snd_timer_close(struct snd_timer_instance *timeri)
spin_unlock_irq(&timer->lock);
mutex_lock(&register_mutex);
list_del(&timeri->open_list);
- if (timer && list_empty(&timer->open_list_head) &&
+ if (list_empty(&timer->open_list_head) &&
timer->hw.close)
timer->hw.close(timer);
/* remove slave links */
+ spin_lock_irq(&slave_active_lock);
+ spin_lock(&timer->lock);
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) {
- spin_lock_irq(&slave_active_lock);
- _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
list_move_tail(&slave->open_list, &snd_timer_slave_list);
slave->master = NULL;
slave->timer = NULL;
- spin_unlock_irq(&slave_active_lock);
+ list_del_init(&slave->ack_list);
+ list_del_init(&slave->active_list);
}
+ spin_unlock(&timer->lock);
+ spin_unlock_irq(&slave_active_lock);
mutex_unlock(&register_mutex);
}
out:
@@ -441,9 +445,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri)
spin_lock_irqsave(&slave_active_lock, flags);
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
- if (timeri->master)
+ if (timeri->master && timeri->timer) {
+ spin_lock(&timeri->timer->lock);
list_add_tail(&timeri->active_list,
&timeri->master->slave_active_head);
+ spin_unlock(&timeri->timer->lock);
+ }
spin_unlock_irqrestore(&slave_active_lock, flags);
return 1; /* delayed start */
}
@@ -476,8 +483,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
return result;
}
-static int _snd_timer_stop(struct snd_timer_instance * timeri,
- int keep_flag, int event)
+static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
{
struct snd_timer *timer;
unsigned long flags;
@@ -486,11 +492,11 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri,
return -ENXIO;
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
- if (!keep_flag) {
- spin_lock_irqsave(&slave_active_lock, flags);
- timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
- spin_unlock_irqrestore(&slave_active_lock, flags);
- }
+ spin_lock_irqsave(&slave_active_lock, flags);
+ timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
+ list_del_init(&timeri->ack_list);
+ list_del_init(&timeri->active_list);
+ spin_unlock_irqrestore(&slave_active_lock, flags);
goto __end;
}
timer = timeri->timer;
@@ -511,9 +517,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri,
}
}
}
- if (!keep_flag)
- timeri->flags &=
- ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
+ timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
spin_unlock_irqrestore(&timer->lock, flags);
__end:
if (event != SNDRV_TIMER_EVENT_RESOLUTION)
@@ -532,7 +536,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri)
unsigned long flags;
int err;
- err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP);
+ err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP);
if (err < 0)
return err;
timer = timeri->timer;
@@ -576,7 +580,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri)
*/
int snd_timer_pause(struct snd_timer_instance * timeri)
{
- return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);
+ return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE);
}
/*
@@ -694,7 +698,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
} else {
ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (--timer->running)
- list_del(&ti->active_list);
+ list_del_init(&ti->active_list);
}
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
(ti->flags & SNDRV_TIMER_IFLG_FAST))
@@ -1253,7 +1257,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)
return -ENOMEM;
spin_lock_init(&tu->qlock);
init_waitqueue_head(&tu->qchange_sleep);
- mutex_init(&tu->tread_sem);
+ mutex_init(&tu->ioctl_lock);
tu->ticks = 1;
tu->queue_size = 128;
tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
@@ -1273,8 +1277,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
if (file->private_data) {
tu = file->private_data;
file->private_data = NULL;
+ mutex_lock(&tu->ioctl_lock);
if (tu->timeri)
snd_timer_close(tu->timeri);
+ mutex_unlock(&tu->ioctl_lock);
kfree(tu->queue);
kfree(tu->tqueue);
kfree(tu);
@@ -1512,7 +1518,6 @@ static int snd_timer_user_tselect(struct file *file,
int err = 0;
tu = file->private_data;
- mutex_lock(&tu->tread_sem);
if (tu->timeri) {
snd_timer_close(tu->timeri);
tu->timeri = NULL;
@@ -1556,7 +1561,6 @@ static int snd_timer_user_tselect(struct file *file,
}
__err:
- mutex_unlock(&tu->tread_sem);
return err;
}
@@ -1769,7 +1773,7 @@ enum {
SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
};
-static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
+static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct snd_timer_user *tu;
@@ -1786,17 +1790,11 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
{
int xarg;
- mutex_lock(&tu->tread_sem);
- if (tu->timeri) { /* too late */
- mutex_unlock(&tu->tread_sem);
+ if (tu->timeri) /* too late */
return -EBUSY;
- }
- if (get_user(xarg, p)) {
- mutex_unlock(&tu->tread_sem);
+ if (get_user(xarg, p))
return -EFAULT;
- }
tu->tread = xarg ? 1 : 0;
- mutex_unlock(&tu->tread_sem);
return 0;
}
case SNDRV_TIMER_IOCTL_GINFO:
@@ -1829,6 +1827,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
return -ENOTTY;
}
+static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct snd_timer_user *tu = file->private_data;
+ long ret;
+
+ mutex_lock(&tu->ioctl_lock);
+ ret = __snd_timer_user_ioctl(file, cmd, arg);
+ mutex_unlock(&tu->ioctl_lock);
+ return ret;
+}
+
static int snd_timer_user_fasync(int fd, struct file * file, int on)
{
struct snd_timer_user *tu;
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 016e451ed506..75b74850c005 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -351,7 +351,7 @@ static void dummy_systimer_free(struct snd_pcm_substream *substream)
kfree(substream->runtime->private_data);
}
-static struct dummy_timer_ops dummy_systimer_ops = {
+static const struct dummy_timer_ops dummy_systimer_ops = {
.create = dummy_systimer_create,
.free = dummy_systimer_free,
.prepare = dummy_systimer_prepare,
@@ -475,7 +475,7 @@ static void dummy_hrtimer_free(struct snd_pcm_substream *substream)
kfree(dpcm);
}
-static struct dummy_timer_ops dummy_hrtimer_ops = {
+static const struct dummy_timer_ops dummy_hrtimer_ops = {
.create = dummy_hrtimer_create,
.free = dummy_hrtimer_free,
.prepare = dummy_hrtimer_prepare,
diff --git a/sound/drivers/pcm-indirect2.c b/sound/drivers/pcm-indirect2.c
index e73fafd761b3..d16bc14a0f0e 100644
--- a/sound/drivers/pcm-indirect2.c
+++ b/sound/drivers/pcm-indirect2.c
@@ -47,7 +47,7 @@ void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ;
snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, "
- "irq_occured: %d\n",
+ "irq_occurred: %d\n",
rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured);
snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n",
rec->min_multiple);
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index e92a6d949847..2a779c2f63ab 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -39,6 +39,7 @@ config SND_OXFW
* Mackie(Loud) d.2 pro/d.4 pro
* Mackie(Loud) U.420/U.420d
* TASCAM FireOne
+ * Stanton Controllers & Systems 1 Deck/Mixer
To compile this driver as a module, choose M here: the module
will be called snd-oxfw.
@@ -53,17 +54,6 @@ config SND_ISIGHT
To compile this driver as a module, choose M here: the module
will be called snd-isight.
-config SND_SCS1X
- tristate "Stanton Control System 1 MIDI"
- select SND_FIREWIRE_LIB
- help
- Say Y here to include support for the MIDI ports of the Stanton
- SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled
- by FFADO.)
-
- To compile this driver as a module, choose M here: the module
- will be called snd-scs1x.
-
config SND_FIREWORKS
tristate "Echo Fireworks board module support"
select SND_FIREWIRE_LIB
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index f5fb62551c60..003c09029786 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -1,13 +1,11 @@
snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp-stream.o amdtp-am824.o
snd-isight-objs := isight.o
-snd-scs1x-objs := scs1x.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
obj-$(CONFIG_SND_DICE) += dice/
obj-$(CONFIG_SND_OXFW) += oxfw/
obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
-obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
obj-$(CONFIG_SND_FIREWORKS) += fireworks/
obj-$(CONFIG_SND_BEBOB) += bebob/
obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/
diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c
index aee746187665..a4ff4e0bc0af 100644
--- a/sound/firewire/dice/dice-transaction.c
+++ b/sound/firewire/dice/dice-transaction.c
@@ -9,7 +9,7 @@
#include "dice.h"
-#define NOTIFICATION_TIMEOUT_MS 100
+#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC)
static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
u64 offset)
@@ -65,16 +65,15 @@ static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
static int set_clock_info(struct snd_dice *dice,
unsigned int rate, unsigned int source)
{
- unsigned int retries = 3;
unsigned int i;
__be32 info;
u32 mask;
u32 clock;
int err;
-retry:
+
err = get_clock_info(dice, &info);
if (err < 0)
- goto end;
+ return err;
clock = be32_to_cpu(info);
if (source != UINT_MAX) {
@@ -87,10 +86,8 @@ retry:
if (snd_dice_rates[i] == rate)
break;
}
- if (i == ARRAY_SIZE(snd_dice_rates)) {
- err = -EINVAL;
- goto end;
- }
+ if (i == ARRAY_SIZE(snd_dice_rates))
+ return -EINVAL;
mask = CLOCK_RATE_MASK;
clock &= ~mask;
@@ -104,25 +101,13 @@ retry:
err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
&info, 4);
if (err < 0)
- goto end;
+ return err;
- /* Timeout means it's invalid request, probably bus reset occurred. */
if (wait_for_completion_timeout(&dice->clock_accepted,
- msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
- if (retries-- == 0) {
- err = -ETIMEDOUT;
- goto end;
- }
+ msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
+ return -ETIMEDOUT;
- err = snd_dice_transaction_reinit(dice);
- if (err < 0)
- goto end;
-
- msleep(500); /* arbitrary */
- goto retry;
- }
-end:
- return err;
+ return 0;
}
int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
@@ -331,39 +316,60 @@ int snd_dice_transaction_reinit(struct snd_dice *dice)
return register_notification_address(dice, false);
}
-int snd_dice_transaction_init(struct snd_dice *dice)
+static int get_subaddrs(struct snd_dice *dice)
{
- struct fw_address_handler *handler = &dice->notification_handler;
+ static const int min_values[10] = {
+ 10, 0x64 / 4,
+ 10, 0x18 / 4,
+ 10, 0x18 / 4,
+ 0, 0,
+ 0, 0,
+ };
__be32 *pointers;
+ __be32 version;
+ u32 data;
+ unsigned int i;
int err;
- /* Use the same way which dice_interface_check() does. */
- pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL);
+ pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
+ GFP_KERNEL);
if (pointers == NULL)
return -ENOMEM;
- /* Get offsets for sub-addresses */
+ /*
+ * Check that the sub address spaces exist and are located inside the
+ * private address space. The minimum values are chosen so that all
+ * minimally required registers are included.
+ */
err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE,
- pointers, sizeof(__be32) * 10, 0);
+ DICE_PRIVATE_SPACE, pointers,
+ sizeof(__be32) * ARRAY_SIZE(min_values), 0);
if (err < 0)
goto end;
- /* Allocation callback in address space over host controller */
- handler->length = 4;
- handler->address_callback = dice_notification;
- handler->callback_data = dice;
- err = fw_core_add_address_handler(handler, &fw_high_memory_region);
- if (err < 0) {
- handler->callback_data = NULL;
- goto end;
+ for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
+ data = be32_to_cpu(pointers[i]);
+ if (data < min_values[i] || data >= 0x40000) {
+ err = -ENODEV;
+ goto end;
+ }
}
- /* Register the address space */
- err = register_notification_address(dice, true);
- if (err < 0) {
- fw_core_remove_address_handler(handler);
- handler->callback_data = NULL;
+ /*
+ * Check that the implemented DICE driver specification major version
+ * number matches.
+ */
+ err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
+ DICE_PRIVATE_SPACE +
+ be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
+ &version, sizeof(version), 0);
+ if (err < 0)
+ goto end;
+
+ if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
+ dev_err(&dice->unit->device,
+ "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
+ err = -ENODEV;
goto end;
}
@@ -380,3 +386,32 @@ end:
kfree(pointers);
return err;
}
+
+int snd_dice_transaction_init(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+ int err;
+
+ err = get_subaddrs(dice);
+ if (err < 0)
+ return err;
+
+ /* Allocation callback in address space over host controller */
+ handler->length = 4;
+ handler->address_callback = dice_notification;
+ handler->callback_data = dice;
+ err = fw_core_add_address_handler(handler, &fw_high_memory_region);
+ if (err < 0) {
+ handler->callback_data = NULL;
+ return err;
+ }
+
+ /* Register the address space */
+ err = register_notification_address(dice, true);
+ if (err < 0) {
+ fw_core_remove_address_handler(handler);
+ handler->callback_data = NULL;
+ }
+
+ return err;
+}
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 0cda05c72f50..b91b3739c810 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -18,27 +18,14 @@ MODULE_LICENSE("GPL v2");
#define WEISS_CATEGORY_ID 0x00
#define LOUD_CATEGORY_ID 0x10
-static int dice_interface_check(struct fw_unit *unit)
+#define PROBE_DELAY_MS (2 * MSEC_PER_SEC)
+
+static int check_dice_category(struct fw_unit *unit)
{
- static const int min_values[10] = {
- 10, 0x64 / 4,
- 10, 0x18 / 4,
- 10, 0x18 / 4,
- 0, 0,
- 0, 0,
- };
struct fw_device *device = fw_parent_device(unit);
struct fw_csr_iterator it;
- int key, val, vendor = -1, model = -1, err;
- unsigned int category, i;
- __be32 *pointers;
- u32 value;
- __be32 version;
-
- pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
- GFP_KERNEL);
- if (pointers == NULL)
- return -ENOMEM;
+ int key, val, vendor = -1, model = -1;
+ unsigned int category;
/*
* Check that GUID and unit directory are constructed according to DICE
@@ -64,51 +51,10 @@ static int dice_interface_check(struct fw_unit *unit)
else
category = DICE_CATEGORY_ID;
if (device->config_rom[3] != ((vendor << 8) | category) ||
- device->config_rom[4] >> 22 != model) {
- err = -ENODEV;
- goto end;
- }
-
- /*
- * Check that the sub address spaces exist and are located inside the
- * private address space. The minimum values are chosen so that all
- * minimally required registers are included.
- */
- err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE, pointers,
- sizeof(__be32) * ARRAY_SIZE(min_values), 0);
- if (err < 0) {
- err = -ENODEV;
- goto end;
- }
- for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
- value = be32_to_cpu(pointers[i]);
- if (value < min_values[i] || value >= 0x40000) {
- err = -ENODEV;
- goto end;
- }
- }
+ device->config_rom[4] >> 22 != model)
+ return -ENODEV;
- /*
- * Check that the implemented DICE driver specification major version
- * number matches.
- */
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- DICE_PRIVATE_SPACE +
- be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
- &version, 4, 0);
- if (err < 0) {
- err = -ENODEV;
- goto end;
- }
- if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
- dev_err(&unit->device,
- "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
- err = -ENODEV;
- goto end;
- }
-end:
- return err;
+ return 0;
}
static int highest_supported_mode_rate(struct snd_dice *dice,
@@ -231,6 +177,16 @@ static void dice_card_strings(struct snd_dice *dice)
strcpy(card->mixername, "DICE");
}
+static void dice_free(struct snd_dice *dice)
+{
+ snd_dice_stream_destroy_duplex(dice);
+ snd_dice_transaction_destroy(dice);
+ fw_unit_put(dice->unit);
+
+ mutex_destroy(&dice->mutex);
+ kfree(dice);
+}
+
/*
* This module releases the FireWire unit data after all ALSA character devices
* are released by applications. This is for releasing stream data or finishing
@@ -239,39 +195,21 @@ static void dice_card_strings(struct snd_dice *dice)
*/
static void dice_card_free(struct snd_card *card)
{
- struct snd_dice *dice = card->private_data;
-
- snd_dice_stream_destroy_duplex(dice);
- snd_dice_transaction_destroy(dice);
- fw_unit_put(dice->unit);
-
- mutex_destroy(&dice->mutex);
+ dice_free(card->private_data);
}
-static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+static void do_registration(struct work_struct *work)
{
- struct snd_card *card;
- struct snd_dice *dice;
+ struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work);
int err;
- err = dice_interface_check(unit);
- if (err < 0)
- goto end;
+ if (dice->registered)
+ return;
- err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
- sizeof(*dice), &card);
+ err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0,
+ &dice->card);
if (err < 0)
- goto end;
-
- dice = card->private_data;
- dice->card = card;
- dice->unit = fw_unit_get(unit);
- card->private_free = dice_card_free;
-
- spin_lock_init(&dice->lock);
- mutex_init(&dice->mutex);
- init_completion(&dice->clock_accepted);
- init_waitqueue_head(&dice->hwdep_wait);
+ return;
err = snd_dice_transaction_init(dice);
if (err < 0)
@@ -283,56 +221,131 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
dice_card_strings(dice);
+ snd_dice_create_proc(dice);
+
err = snd_dice_create_pcm(dice);
if (err < 0)
goto error;
- err = snd_dice_create_hwdep(dice);
+ err = snd_dice_create_midi(dice);
if (err < 0)
goto error;
- snd_dice_create_proc(dice);
-
- err = snd_dice_create_midi(dice);
+ err = snd_dice_create_hwdep(dice);
if (err < 0)
goto error;
- err = snd_dice_stream_init_duplex(dice);
+ err = snd_card_register(dice->card);
if (err < 0)
goto error;
- err = snd_card_register(card);
+ /*
+ * After registered, dice instance can be released corresponding to
+ * releasing the sound card instance.
+ */
+ dice->card->private_free = dice_card_free;
+ dice->card->private_data = dice;
+ dice->registered = true;
+
+ return;
+error:
+ snd_dice_transaction_destroy(dice);
+ snd_card_free(dice->card);
+ dev_info(&dice->unit->device,
+ "Sound card registration failed: %d\n", err);
+}
+
+static void schedule_registration(struct snd_dice *dice)
+{
+ struct fw_card *fw_card = fw_parent_device(dice->unit)->card;
+ u64 now, delay;
+
+ now = get_jiffies_64();
+ delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS);
+
+ if (time_after64(delay, now))
+ delay -= now;
+ else
+ delay = 0;
+
+ mod_delayed_work(system_wq, &dice->dwork, delay);
+}
+
+static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+{
+ struct snd_dice *dice;
+ int err;
+
+ err = check_dice_category(unit);
+ if (err < 0)
+ return -ENODEV;
+
+ /* Allocate this independent of sound card instance. */
+ dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
+ if (dice == NULL)
+ return -ENOMEM;
+
+ dice->unit = fw_unit_get(unit);
+ dev_set_drvdata(&unit->device, dice);
+
+ spin_lock_init(&dice->lock);
+ mutex_init(&dice->mutex);
+ init_completion(&dice->clock_accepted);
+ init_waitqueue_head(&dice->hwdep_wait);
+
+ err = snd_dice_stream_init_duplex(dice);
if (err < 0) {
- snd_dice_stream_destroy_duplex(dice);
- goto error;
+ dice_free(dice);
+ return err;
}
- dev_set_drvdata(&unit->device, dice);
-end:
- return err;
-error:
- snd_card_free(card);
- return err;
+ /* Allocate and register this sound card later. */
+ INIT_DEFERRABLE_WORK(&dice->dwork, do_registration);
+ schedule_registration(dice);
+
+ return 0;
}
static void dice_remove(struct fw_unit *unit)
{
struct snd_dice *dice = dev_get_drvdata(&unit->device);
- /* No need to wait for releasing card object in this context. */
- snd_card_free_when_closed(dice->card);
+ /*
+ * Confirm to stop the work for registration before the sound card is
+ * going to be released. The work is not scheduled again because bus
+ * reset handler is not called anymore.
+ */
+ cancel_delayed_work_sync(&dice->dwork);
+
+ if (dice->registered) {
+ /* No need to wait for releasing card object in this context. */
+ snd_card_free_when_closed(dice->card);
+ } else {
+ /* Don't forget this case. */
+ dice_free(dice);
+ }
}
static void dice_bus_reset(struct fw_unit *unit)
{
struct snd_dice *dice = dev_get_drvdata(&unit->device);
+ /* Postpone a workqueue for deferred registration. */
+ if (!dice->registered)
+ schedule_registration(dice);
+
/* The handler address register becomes initialized. */
snd_dice_transaction_reinit(dice);
- mutex_lock(&dice->mutex);
- snd_dice_stream_update_duplex(dice);
- mutex_unlock(&dice->mutex);
+ /*
+ * After registration, userspace can start packet streaming, then this
+ * code block works fine.
+ */
+ if (dice->registered) {
+ mutex_lock(&dice->mutex);
+ snd_dice_stream_update_duplex(dice);
+ mutex_unlock(&dice->mutex);
+ }
}
#define DICE_INTERFACE 0x000001
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index 101550ac1a24..3d5ebebe61ea 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -45,6 +45,9 @@ struct snd_dice {
spinlock_t lock;
struct mutex mutex;
+ bool registered;
+ struct delayed_work dwork;
+
/* Offsets for sub-addresses */
unsigned int global_offset;
unsigned int rx_offset;
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index c7cb7deafe48..96c4e0c6a9bd 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -86,8 +86,8 @@ struct snd_efw {
struct amdtp_stream rx_stream;
struct cmp_connection out_conn;
struct cmp_connection in_conn;
- atomic_t capture_substreams;
- atomic_t playback_substreams;
+ unsigned int capture_substreams;
+ unsigned int playback_substreams;
/* hardware metering parameters */
unsigned int phys_out;
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c
index fba01bbba456..3e8c4cf9fe1e 100644
--- a/sound/firewire/fireworks/fireworks_midi.c
+++ b/sound/firewire/fireworks/fireworks_midi.c
@@ -17,8 +17,10 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
if (err < 0)
goto end;
- atomic_inc(&efw->capture_substreams);
+ mutex_lock(&efw->mutex);
+ efw->capture_substreams++;
err = snd_efw_stream_start_duplex(efw, 0);
+ mutex_unlock(&efw->mutex);
if (err < 0)
snd_efw_stream_lock_release(efw);
@@ -35,8 +37,10 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
if (err < 0)
goto end;
- atomic_inc(&efw->playback_substreams);
+ mutex_lock(&efw->mutex);
+ efw->playback_substreams++;
err = snd_efw_stream_start_duplex(efw, 0);
+ mutex_unlock(&efw->mutex);
if (err < 0)
snd_efw_stream_lock_release(efw);
end:
@@ -47,8 +51,10 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
{
struct snd_efw *efw = substream->rmidi->private_data;
- atomic_dec(&efw->capture_substreams);
+ mutex_lock(&efw->mutex);
+ efw->capture_substreams--;
snd_efw_stream_stop_duplex(efw);
+ mutex_unlock(&efw->mutex);
snd_efw_stream_lock_release(efw);
return 0;
@@ -58,8 +64,10 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
{
struct snd_efw *efw = substream->rmidi->private_data;
- atomic_dec(&efw->playback_substreams);
+ mutex_lock(&efw->mutex);
+ efw->playback_substreams--;
snd_efw_stream_stop_duplex(efw);
+ mutex_unlock(&efw->mutex);
snd_efw_stream_lock_release(efw);
return 0;
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index d27135bac513..f4fbf75ed198 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -251,8 +251,11 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
- atomic_inc(&efw->capture_substreams);
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&efw->mutex);
+ efw->capture_substreams++;
+ mutex_unlock(&efw->mutex);
+ }
amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params));
@@ -269,8 +272,11 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
- atomic_inc(&efw->playback_substreams);
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&efw->mutex);
+ efw->playback_substreams++;
+ mutex_unlock(&efw->mutex);
+ }
amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params));
@@ -281,8 +287,11 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_efw *efw = substream->private_data;
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- atomic_dec(&efw->capture_substreams);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&efw->mutex);
+ efw->capture_substreams--;
+ mutex_unlock(&efw->mutex);
+ }
snd_efw_stream_stop_duplex(efw);
@@ -292,8 +301,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
{
struct snd_efw *efw = substream->private_data;
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- atomic_dec(&efw->playback_substreams);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&efw->mutex);
+ efw->playback_substreams--;
+ mutex_unlock(&efw->mutex);
+ }
snd_efw_stream_stop_duplex(efw);
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 759f6e3ed44a..968a40a1beb2 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -209,16 +209,13 @@ end:
int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
{
struct amdtp_stream *master, *slave;
- atomic_t *slave_substreams;
+ unsigned int slave_substreams;
enum cip_flags sync_mode;
unsigned int curr_rate;
int err = 0;
- mutex_lock(&efw->mutex);
-
/* Need no substreams */
- if ((atomic_read(&efw->playback_substreams) == 0) &&
- (atomic_read(&efw->capture_substreams) == 0))
+ if (efw->playback_substreams == 0 && efw->capture_substreams == 0)
goto end;
err = get_sync_mode(efw, &sync_mode);
@@ -227,11 +224,11 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
if (sync_mode == CIP_SYNC_TO_DEVICE) {
master = &efw->tx_stream;
slave = &efw->rx_stream;
- slave_substreams = &efw->playback_substreams;
+ slave_substreams = efw->playback_substreams;
} else {
master = &efw->rx_stream;
slave = &efw->tx_stream;
- slave_substreams = &efw->capture_substreams;
+ slave_substreams = efw->capture_substreams;
}
/*
@@ -277,7 +274,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
}
/* start slave if needed */
- if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) {
+ if (slave_substreams > 0 && !amdtp_stream_running(slave)) {
err = start_stream(efw, slave, rate);
if (err < 0) {
dev_err(&efw->unit->device,
@@ -286,37 +283,32 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
}
}
end:
- mutex_unlock(&efw->mutex);
return err;
}
void snd_efw_stream_stop_duplex(struct snd_efw *efw)
{
struct amdtp_stream *master, *slave;
- atomic_t *master_substreams, *slave_substreams;
+ unsigned int master_substreams, slave_substreams;
if (efw->master == &efw->rx_stream) {
slave = &efw->tx_stream;
master = &efw->rx_stream;
- slave_substreams = &efw->capture_substreams;
- master_substreams = &efw->playback_substreams;
+ slave_substreams = efw->capture_substreams;
+ master_substreams = efw->playback_substreams;
} else {
slave = &efw->rx_stream;
master = &efw->tx_stream;
- slave_substreams = &efw->playback_substreams;
- master_substreams = &efw->capture_substreams;
+ slave_substreams = efw->playback_substreams;
+ master_substreams = efw->capture_substreams;
}
- mutex_lock(&efw->mutex);
-
- if (atomic_read(slave_substreams) == 0) {
+ if (slave_substreams == 0) {
stop_stream(efw, slave);
- if (atomic_read(master_substreams) == 0)
+ if (master_substreams == 0)
stop_stream(efw, master);
}
-
- mutex_unlock(&efw->mutex);
}
void snd_efw_stream_update_duplex(struct snd_efw *efw)
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
index 06ff50f4e6c0..b474da7c6a1f 100644
--- a/sound/firewire/oxfw/Makefile
+++ b/sound/firewire/oxfw/Makefile
@@ -1,3 +1,3 @@
-snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \
- oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o
+snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \
+ oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw-scs1x.o oxfw.o
obj-$(CONFIG_SND_OXFW) += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c
new file mode 100644
index 000000000000..bb53eb35721b
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-scs1x.c
@@ -0,0 +1,406 @@
+/*
+ * oxfw-scs1x.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+#define HSS1394_ADDRESS 0xc007dedadadaULL
+#define HSS1394_MAX_PACKET_SIZE 64
+#define HSS1394_TAG_USER_DATA 0x00
+#define HSS1394_TAG_CHANGE_ADDRESS 0xf1
+
+struct fw_scs1x {
+ struct fw_address_handler hss_handler;
+ u8 input_escape_count;
+ struct snd_rawmidi_substream *input;
+
+ /* For MIDI playback. */
+ struct snd_rawmidi_substream *output;
+ bool output_idle;
+ u8 output_status;
+ u8 output_bytes;
+ bool output_escaped;
+ bool output_escape_high_nibble;
+ struct tasklet_struct tasklet;
+ wait_queue_head_t idle_wait;
+ u8 buffer[HSS1394_MAX_PACKET_SIZE];
+ bool transaction_running;
+ struct fw_transaction transaction;
+ struct fw_device *fw_dev;
+};
+
+static const u8 sysex_escape_prefix[] = {
+ 0xf0, /* SysEx begin */
+ 0x00, 0x01, 0x60, /* Stanton DJ */
+ 0x48, 0x53, 0x53, /* "HSS" */
+};
+
+static void midi_input_escaped_byte(struct snd_rawmidi_substream *stream,
+ u8 byte)
+{
+ u8 nibbles[2];
+
+ nibbles[0] = byte >> 4;
+ nibbles[1] = byte & 0x0f;
+ snd_rawmidi_receive(stream, nibbles, 2);
+}
+
+static void midi_input_byte(struct fw_scs1x *scs,
+ struct snd_rawmidi_substream *stream, u8 byte)
+{
+ const u8 eox = 0xf7;
+
+ if (scs->input_escape_count > 0) {
+ midi_input_escaped_byte(stream, byte);
+ scs->input_escape_count--;
+ if (scs->input_escape_count == 0)
+ snd_rawmidi_receive(stream, &eox, sizeof(eox));
+ } else if (byte == 0xf9) {
+ snd_rawmidi_receive(stream, sysex_escape_prefix,
+ ARRAY_SIZE(sysex_escape_prefix));
+ midi_input_escaped_byte(stream, 0x00);
+ midi_input_escaped_byte(stream, 0xf9);
+ scs->input_escape_count = 3;
+ } else {
+ snd_rawmidi_receive(stream, &byte, 1);
+ }
+}
+
+static void midi_input_packet(struct fw_scs1x *scs,
+ struct snd_rawmidi_substream *stream,
+ const u8 *data, unsigned int bytes)
+{
+ unsigned int i;
+ const u8 eox = 0xf7;
+
+ if (data[0] == HSS1394_TAG_USER_DATA) {
+ for (i = 1; i < bytes; ++i)
+ midi_input_byte(scs, stream, data[i]);
+ } else {
+ snd_rawmidi_receive(stream, sysex_escape_prefix,
+ ARRAY_SIZE(sysex_escape_prefix));
+ for (i = 0; i < bytes; ++i)
+ midi_input_escaped_byte(stream, data[i]);
+ snd_rawmidi_receive(stream, &eox, sizeof(eox));
+ }
+}
+
+static void handle_hss(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source, int generation,
+ unsigned long long offset, void *data, size_t length,
+ void *callback_data)
+{
+ struct fw_scs1x *scs = callback_data;
+ struct snd_rawmidi_substream *stream;
+ int rcode;
+
+ if (offset != scs->hss_handler.offset) {
+ rcode = RCODE_ADDRESS_ERROR;
+ goto end;
+ }
+ if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
+ tcode != TCODE_WRITE_BLOCK_REQUEST) {
+ rcode = RCODE_TYPE_ERROR;
+ goto end;
+ }
+
+ if (length >= 1) {
+ stream = ACCESS_ONCE(scs->input);
+ if (stream)
+ midi_input_packet(scs, stream, data, length);
+ }
+
+ rcode = RCODE_COMPLETE;
+end:
+ fw_send_response(card, request, rcode);
+}
+
+static void scs_write_callback(struct fw_card *card, int rcode,
+ void *data, size_t length, void *callback_data)
+{
+ struct fw_scs1x *scs = callback_data;
+
+ if (rcode == RCODE_GENERATION)
+ ; /* TODO: retry this packet */
+
+ scs->transaction_running = false;
+ tasklet_schedule(&scs->tasklet);
+}
+
+static bool is_valid_running_status(u8 status)
+{
+ return status >= 0x80 && status <= 0xef;
+}
+
+static bool is_one_byte_cmd(u8 status)
+{
+ return status == 0xf6 ||
+ status >= 0xf8;
+}
+
+static bool is_two_bytes_cmd(u8 status)
+{
+ return (status >= 0xc0 && status <= 0xdf) ||
+ status == 0xf1 ||
+ status == 0xf3;
+}
+
+static bool is_three_bytes_cmd(u8 status)
+{
+ return (status >= 0x80 && status <= 0xbf) ||
+ (status >= 0xe0 && status <= 0xef) ||
+ status == 0xf2;
+}
+
+static bool is_invalid_cmd(u8 status)
+{
+ return status == 0xf4 ||
+ status == 0xf5 ||
+ status == 0xf9 ||
+ status == 0xfd;
+}
+
+static void scs_output_tasklet(unsigned long data)
+{
+ struct fw_scs1x *scs = (struct fw_scs1x *)data;
+ struct snd_rawmidi_substream *stream;
+ unsigned int i;
+ u8 byte;
+ int generation;
+
+ if (scs->transaction_running)
+ return;
+
+ stream = ACCESS_ONCE(scs->output);
+ if (!stream) {
+ scs->output_idle = true;
+ wake_up(&scs->idle_wait);
+ return;
+ }
+
+ i = scs->output_bytes;
+ for (;;) {
+ if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
+ scs->output_bytes = i;
+ scs->output_idle = true;
+ wake_up(&scs->idle_wait);
+ return;
+ }
+ /*
+ * Convert from real MIDI to what I think the device expects (no
+ * running status, one command per packet, unescaped SysExs).
+ */
+ if (scs->output_escaped && byte < 0x80) {
+ if (scs->output_escape_high_nibble) {
+ if (i < HSS1394_MAX_PACKET_SIZE) {
+ scs->buffer[i] = byte << 4;
+ scs->output_escape_high_nibble = false;
+ }
+ } else {
+ scs->buffer[i++] |= byte & 0x0f;
+ scs->output_escape_high_nibble = true;
+ }
+ } else if (byte < 0x80) {
+ if (i == 1) {
+ if (!is_valid_running_status(
+ scs->output_status))
+ continue;
+ scs->buffer[0] = HSS1394_TAG_USER_DATA;
+ scs->buffer[i++] = scs->output_status;
+ }
+ scs->buffer[i++] = byte;
+ if ((i == 3 && is_two_bytes_cmd(scs->output_status)) ||
+ (i == 4 && is_three_bytes_cmd(scs->output_status)))
+ break;
+ if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) &&
+ !memcmp(scs->buffer + 1, sysex_escape_prefix,
+ ARRAY_SIZE(sysex_escape_prefix))) {
+ scs->output_escaped = true;
+ scs->output_escape_high_nibble = true;
+ i = 0;
+ }
+ if (i >= HSS1394_MAX_PACKET_SIZE)
+ i = 1;
+ } else if (byte == 0xf7) {
+ if (scs->output_escaped) {
+ if (i >= 1 && scs->output_escape_high_nibble &&
+ scs->buffer[0] !=
+ HSS1394_TAG_CHANGE_ADDRESS)
+ break;
+ } else {
+ if (i > 1 && scs->output_status == 0xf0) {
+ scs->buffer[i++] = 0xf7;
+ break;
+ }
+ }
+ i = 1;
+ scs->output_escaped = false;
+ } else if (!is_invalid_cmd(byte) && byte < 0xf8) {
+ i = 1;
+ scs->buffer[0] = HSS1394_TAG_USER_DATA;
+ scs->buffer[i++] = byte;
+ scs->output_status = byte;
+ scs->output_escaped = false;
+ if (is_one_byte_cmd(byte))
+ break;
+ }
+ }
+ scs->output_bytes = 1;
+ scs->output_escaped = false;
+
+ scs->transaction_running = true;
+ generation = scs->fw_dev->generation;
+ smp_rmb(); /* node_id vs. generation */
+ fw_send_request(scs->fw_dev->card, &scs->transaction,
+ TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id,
+ generation, scs->fw_dev->max_speed, HSS1394_ADDRESS,
+ scs->buffer, i, scs_write_callback, scs);
+}
+
+static int midi_capture_open(struct snd_rawmidi_substream *stream)
+{
+ return 0;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *stream)
+{
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up)
+{
+ struct fw_scs1x *scs = stream->rmidi->private_data;
+
+ if (up) {
+ scs->input_escape_count = 0;
+ ACCESS_ONCE(scs->input) = stream;
+ } else {
+ ACCESS_ONCE(scs->input) = NULL;
+ }
+}
+
+static struct snd_rawmidi_ops midi_capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+};
+
+static int midi_playback_open(struct snd_rawmidi_substream *stream)
+{
+ return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *stream)
+{
+ return 0;
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up)
+{
+ struct fw_scs1x *scs = stream->rmidi->private_data;
+
+ if (up) {
+ scs->output_status = 0;
+ scs->output_bytes = 1;
+ scs->output_escaped = false;
+ scs->output_idle = false;
+
+ ACCESS_ONCE(scs->output) = stream;
+ tasklet_schedule(&scs->tasklet);
+ } else {
+ ACCESS_ONCE(scs->output) = NULL;
+ }
+}
+static void midi_playback_drain(struct snd_rawmidi_substream *stream)
+{
+ struct fw_scs1x *scs = stream->rmidi->private_data;
+
+ wait_event(scs->idle_wait, scs->output_idle);
+}
+
+static struct snd_rawmidi_ops midi_playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ .drain = midi_playback_drain,
+};
+static int register_address(struct snd_oxfw *oxfw)
+{
+ struct fw_scs1x *scs = oxfw->spec;
+ __be64 data;
+
+ data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
+ scs->hss_handler.offset);
+ return snd_fw_transaction(oxfw->unit, TCODE_WRITE_BLOCK_REQUEST,
+ HSS1394_ADDRESS, &data, sizeof(data), 0);
+}
+
+static void remove_scs1x(struct snd_rawmidi *rmidi)
+{
+ struct fw_scs1x *scs = rmidi->private_data;
+
+ fw_core_remove_address_handler(&scs->hss_handler);
+}
+
+void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw)
+{
+ register_address(oxfw);
+}
+
+int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
+{
+ struct snd_rawmidi *rmidi;
+ struct fw_scs1x *scs;
+ int err;
+
+ scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL);
+ if (scs == NULL)
+ return -ENOMEM;
+ scs->fw_dev = fw_parent_device(oxfw->unit);
+ oxfw->spec = scs;
+
+ /* Allocate own handler for imcoming asynchronous transaction. */
+ scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
+ scs->hss_handler.address_callback = handle_hss;
+ scs->hss_handler.callback_data = scs;
+ err = fw_core_add_address_handler(&scs->hss_handler,
+ &fw_high_memory_region);
+ if (err < 0)
+ return err;
+
+ err = register_address(oxfw);
+ if (err < 0)
+ goto err_allocated;
+
+ /* Use unique name for backward compatibility to scs1x module. */
+ err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 1, 1, &rmidi);
+ if (err < 0)
+ goto err_allocated;
+ rmidi->private_data = scs;
+ rmidi->private_free = remove_scs1x;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", oxfw->card->shortname);
+
+ rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &midi_capture_ops);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &midi_playback_ops);
+
+ tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
+ init_waitqueue_head(&scs->idle_wait);
+ scs->output_idle = true;
+
+ return 0;
+err_allocated:
+ fw_core_remove_address_handler(&scs->hss_handler);
+ return err;
+}
diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-spkr.c
index 02a1cb90f20d..cb905af0660d 100644
--- a/sound/firewire/oxfw/oxfw-control.c
+++ b/sound/firewire/oxfw/oxfw-spkr.c
@@ -1,5 +1,5 @@
/*
- * oxfw_stream.c - a part of driver for OXFW970/971 based devices
+ * oxfw-spkr.c - a part of driver for OXFW970/971 based devices
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
* Licensed under the terms of the GNU General Public License, version 2.
@@ -7,6 +7,17 @@
#include "oxfw.h"
+struct fw_spkr {
+ bool mute;
+ s16 volume[6];
+ s16 volume_min;
+ s16 volume_max;
+
+ unsigned int mixer_channels;
+ u8 mute_fb_id;
+ u8 volume_fb_id;
+};
+
enum control_action { CTL_READ, CTL_WRITE };
enum control_attribute {
CTL_MIN = 0x02,
@@ -14,8 +25,8 @@ enum control_attribute {
CTL_CURRENT = 0x10,
};
-static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value,
- enum control_action action)
+static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value,
+ enum control_action action)
{
u8 *buf;
u8 response_ok;
@@ -35,7 +46,7 @@ static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value,
buf[1] = 0x08; /* audio unit 0 */
buf[2] = 0xb8; /* FUNCTION BLOCK */
buf[3] = 0x81; /* function block type: feature */
- buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */
+ buf[4] = fb_id; /* function block ID */
buf[5] = 0x10; /* control attribute: current */
buf[6] = 0x02; /* selector length */
buf[7] = 0x00; /* audio channel number */
@@ -46,16 +57,16 @@ static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value,
else
buf[10] = *value ? 0x70 : 0x60;
- err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe);
+ err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe);
if (err < 0)
goto error;
if (err < 11) {
- dev_err(&oxfw->unit->device, "short FCP response\n");
+ dev_err(&unit->device, "short FCP response\n");
err = -EIO;
goto error;
}
if (buf[0] != response_ok) {
- dev_err(&oxfw->unit->device, "mute command failed\n");
+ dev_err(&unit->device, "mute command failed\n");
err = -EIO;
goto error;
}
@@ -70,10 +81,10 @@ error:
return err;
}
-static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value,
- unsigned int channel,
- enum control_attribute attribute,
- enum control_action action)
+static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value,
+ unsigned int channel,
+ enum control_attribute attribute,
+ enum control_action action)
{
u8 *buf;
u8 response_ok;
@@ -93,7 +104,7 @@ static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value,
buf[1] = 0x08; /* audio unit 0 */
buf[2] = 0xb8; /* FUNCTION BLOCK */
buf[3] = 0x81; /* function block type: feature */
- buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */
+ buf[4] = fb_id; /* function block ID */
buf[5] = attribute; /* control attribute */
buf[6] = 0x02; /* selector length */
buf[7] = channel; /* audio channel number */
@@ -107,16 +118,16 @@ static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value,
buf[11] = *value;
}
- err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe);
+ err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe);
if (err < 0)
goto error;
if (err < 12) {
- dev_err(&oxfw->unit->device, "short FCP response\n");
+ dev_err(&unit->device, "short FCP response\n");
err = -EIO;
goto error;
}
if (buf[0] != response_ok) {
- dev_err(&oxfw->unit->device, "volume command failed\n");
+ dev_err(&unit->device, "volume command failed\n");
err = -EIO;
goto error;
}
@@ -131,75 +142,81 @@ error:
return err;
}
-static int oxfw_mute_get(struct snd_kcontrol *control,
+static int spkr_mute_get(struct snd_kcontrol *control,
struct snd_ctl_elem_value *value)
{
struct snd_oxfw *oxfw = control->private_data;
+ struct fw_spkr *spkr = oxfw->spec;
- value->value.integer.value[0] = !oxfw->mute;
+ value->value.integer.value[0] = !spkr->mute;
return 0;
}
-static int oxfw_mute_put(struct snd_kcontrol *control,
+static int spkr_mute_put(struct snd_kcontrol *control,
struct snd_ctl_elem_value *value)
{
struct snd_oxfw *oxfw = control->private_data;
+ struct fw_spkr *spkr = oxfw->spec;
bool mute;
int err;
mute = !value->value.integer.value[0];
- if (mute == oxfw->mute)
+ if (mute == spkr->mute)
return 0;
- err = oxfw_mute_command(oxfw, &mute, CTL_WRITE);
+ err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute,
+ CTL_WRITE);
if (err < 0)
return err;
- oxfw->mute = mute;
+ spkr->mute = mute;
return 1;
}
-static int oxfw_volume_info(struct snd_kcontrol *control,
+static int spkr_volume_info(struct snd_kcontrol *control,
struct snd_ctl_elem_info *info)
{
struct snd_oxfw *oxfw = control->private_data;
+ struct fw_spkr *spkr = oxfw->spec;
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = oxfw->device_info->mixer_channels;
- info->value.integer.min = oxfw->volume_min;
- info->value.integer.max = oxfw->volume_max;
+ info->count = spkr->mixer_channels;
+ info->value.integer.min = spkr->volume_min;
+ info->value.integer.max = spkr->volume_max;
return 0;
}
static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
-static int oxfw_volume_get(struct snd_kcontrol *control,
+static int spkr_volume_get(struct snd_kcontrol *control,
struct snd_ctl_elem_value *value)
{
struct snd_oxfw *oxfw = control->private_data;
+ struct fw_spkr *spkr = oxfw->spec;
unsigned int i;
- for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
- value->value.integer.value[channel_map[i]] = oxfw->volume[i];
+ for (i = 0; i < spkr->mixer_channels; ++i)
+ value->value.integer.value[channel_map[i]] = spkr->volume[i];
return 0;
}
-static int oxfw_volume_put(struct snd_kcontrol *control,
+static int spkr_volume_put(struct snd_kcontrol *control,
struct snd_ctl_elem_value *value)
{
struct snd_oxfw *oxfw = control->private_data;
+ struct fw_spkr *spkr = oxfw->spec;
unsigned int i, changed_channels;
bool equal_values = true;
s16 volume;
int err;
- for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
- if (value->value.integer.value[i] < oxfw->volume_min ||
- value->value.integer.value[i] > oxfw->volume_max)
+ for (i = 0; i < spkr->mixer_channels; ++i) {
+ if (value->value.integer.value[i] < spkr->volume_min ||
+ value->value.integer.value[i] > spkr->volume_max)
return -EINVAL;
if (value->value.integer.value[i] !=
value->value.integer.value[0])
@@ -207,67 +224,86 @@ static int oxfw_volume_put(struct snd_kcontrol *control,
}
changed_channels = 0;
- for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
+ for (i = 0; i < spkr->mixer_channels; ++i)
if (value->value.integer.value[channel_map[i]] !=
- oxfw->volume[i])
+ spkr->volume[i])
changed_channels |= 1 << (i + 1);
if (equal_values && changed_channels != 0)
changed_channels = 1 << 0;
- for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) {
+ for (i = 0; i <= spkr->mixer_channels; ++i) {
volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
if (changed_channels & (1 << i)) {
- err = oxfw_volume_command(oxfw, &volume, i,
- CTL_CURRENT, CTL_WRITE);
+ err = avc_audio_feature_volume(oxfw->unit,
+ spkr->volume_fb_id, &volume,
+ i, CTL_CURRENT, CTL_WRITE);
if (err < 0)
return err;
}
if (i > 0)
- oxfw->volume[i - 1] = volume;
+ spkr->volume[i - 1] = volume;
}
return changed_channels != 0;
}
-int snd_oxfw_create_mixer(struct snd_oxfw *oxfw)
+int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
{
static const struct snd_kcontrol_new controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
.info = snd_ctl_boolean_mono_info,
- .get = oxfw_mute_get,
- .put = oxfw_mute_put,
+ .get = spkr_mute_get,
+ .put = spkr_mute_put,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
- .info = oxfw_volume_info,
- .get = oxfw_volume_get,
- .put = oxfw_volume_put,
+ .info = spkr_volume_info,
+ .get = spkr_volume_get,
+ .put = spkr_volume_put,
},
};
+ struct fw_spkr *spkr;
unsigned int i, first_ch;
int err;
- err = oxfw_volume_command(oxfw, &oxfw->volume_min,
- 0, CTL_MIN, CTL_READ);
+ spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL);
+ if (spkr == NULL)
+ return -ENOMEM;
+ oxfw->spec = spkr;
+
+ if (is_lacie) {
+ spkr->mixer_channels = 1;
+ spkr->mute_fb_id = 0x01;
+ spkr->volume_fb_id = 0x01;
+ } else {
+ spkr->mixer_channels = 6;
+ spkr->mute_fb_id = 0x01;
+ spkr->volume_fb_id = 0x02;
+ }
+
+ err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
+ &spkr->volume_min, 0, CTL_MIN, CTL_READ);
if (err < 0)
return err;
- err = oxfw_volume_command(oxfw, &oxfw->volume_max,
- 0, CTL_MAX, CTL_READ);
+ err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
+ &spkr->volume_max, 0, CTL_MAX, CTL_READ);
if (err < 0)
return err;
- err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ);
+ err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute,
+ CTL_READ);
if (err < 0)
return err;
- first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1;
- for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
- err = oxfw_volume_command(oxfw, &oxfw->volume[i],
- first_ch + i, CTL_CURRENT, CTL_READ);
+ first_ch = spkr->mixer_channels == 1 ? 0 : 1;
+ for (i = 0; i < spkr->mixer_channels; ++i) {
+ err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
+ &spkr->volume[i], first_ch + i,
+ CTL_CURRENT, CTL_READ);
if (err < 0)
return err;
}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 588b93f20c2e..abedc2207261 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -19,6 +19,7 @@
#define VENDOR_BEHRINGER 0x001564
#define VENDOR_LACIE 0x00d04b
#define VENDOR_TASCAM 0x00022e
+#define OUI_STANTON 0x001260
#define MODEL_SATELLITE 0x00200f
@@ -29,6 +30,13 @@ MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("snd-firewire-speakers");
+MODULE_ALIAS("snd-scs1x");
+
+struct compat_info {
+ const char *driver_name;
+ const char *vendor_name;
+ const char *model_name;
+};
static bool detect_loud_models(struct fw_unit *unit)
{
@@ -59,6 +67,7 @@ static bool detect_loud_models(struct fw_unit *unit)
static int name_card(struct snd_oxfw *oxfw)
{
struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
+ const struct compat_info *info;
char vendor[24];
char model[32];
const char *d, *v, *m;
@@ -84,10 +93,12 @@ static int name_card(struct snd_oxfw *oxfw)
be32_to_cpus(&firmware);
/* to apply card definitions */
- if (oxfw->device_info) {
- d = oxfw->device_info->driver_name;
- v = oxfw->device_info->vendor_name;
- m = oxfw->device_info->model_name;
+ if (oxfw->entry->vendor_id == VENDOR_GRIFFIN ||
+ oxfw->entry->vendor_id == VENDOR_LACIE) {
+ info = (const struct compat_info *)oxfw->entry->driver_data;
+ d = info->driver_name;
+ v = info->vendor_name;
+ m = info->model_name;
} else {
d = "OXFW";
v = vendor;
@@ -129,16 +140,51 @@ static void oxfw_card_free(struct snd_card *card)
kfree(oxfw->rx_stream_formats[i]);
}
+ kfree(oxfw->spec);
mutex_destroy(&oxfw->mutex);
}
-static void detect_quirks(struct snd_oxfw *oxfw)
+static int detect_quirks(struct snd_oxfw *oxfw)
{
struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
struct fw_csr_iterator it;
int key, val;
int vendor, model;
+ /*
+ * Add ALSA control elements for two models to keep compatibility to
+ * old firewire-speaker module.
+ */
+ if (oxfw->entry->vendor_id == VENDOR_GRIFFIN)
+ return snd_oxfw_add_spkr(oxfw, false);
+ if (oxfw->entry->vendor_id == VENDOR_LACIE)
+ return snd_oxfw_add_spkr(oxfw, true);
+
+ /*
+ * Stanton models supports asynchronous transactions for unique MIDI
+ * messages.
+ */
+ if (oxfw->entry->vendor_id == OUI_STANTON) {
+ /* No physical MIDI ports. */
+ oxfw->midi_input_ports = 0;
+ oxfw->midi_output_ports = 0;
+
+ /* Output stream exists but no data channels are useful. */
+ oxfw->has_output = false;
+
+ return snd_oxfw_scs1x_add(oxfw);
+ }
+
+ /*
+ * TASCAM FireOne has physical control and requires a pair of additional
+ * MIDI ports.
+ */
+ if (oxfw->entry->vendor_id == VENDOR_TASCAM) {
+ oxfw->midi_input_ports++;
+ oxfw->midi_output_ports++;
+ return 0;
+ }
+
/* Seek from Root Directory of Config ROM. */
vendor = model = 0;
fw_csr_iterator_init(&it, fw_dev->config_rom + 5);
@@ -156,24 +202,17 @@ static void detect_quirks(struct snd_oxfw *oxfw)
if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE)
oxfw->wrong_dbs = true;
- /*
- * TASCAM FireOne has physical control and requires a pair of additional
- * MIDI ports.
- */
- if (vendor == VENDOR_TASCAM) {
- oxfw->midi_input_ports++;
- oxfw->midi_output_ports++;
- }
+ return 0;
}
static int oxfw_probe(struct fw_unit *unit,
- const struct ieee1394_device_id *id)
+ const struct ieee1394_device_id *entry)
{
struct snd_card *card;
struct snd_oxfw *oxfw;
int err;
- if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit))
+ if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit))
return -ENODEV;
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
@@ -186,7 +225,7 @@ static int oxfw_probe(struct fw_unit *unit,
oxfw->card = card;
mutex_init(&oxfw->mutex);
oxfw->unit = fw_unit_get(unit);
- oxfw->device_info = (const struct device_info *)id->driver_data;
+ oxfw->entry = entry;
spin_lock_init(&oxfw->lock);
init_waitqueue_head(&oxfw->hwdep_wait);
@@ -194,21 +233,17 @@ static int oxfw_probe(struct fw_unit *unit,
if (err < 0)
goto error;
- detect_quirks(oxfw);
-
err = name_card(oxfw);
if (err < 0)
goto error;
- err = snd_oxfw_create_pcm(oxfw);
+ err = detect_quirks(oxfw);
if (err < 0)
goto error;
- if (oxfw->device_info) {
- err = snd_oxfw_create_mixer(oxfw);
- if (err < 0)
- goto error;
- }
+ err = snd_oxfw_create_pcm(oxfw);
+ if (err < 0)
+ goto error;
snd_oxfw_proc_init(oxfw);
@@ -257,6 +292,9 @@ static void oxfw_bus_reset(struct fw_unit *unit)
snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
mutex_unlock(&oxfw->mutex);
+
+ if (oxfw->entry->vendor_id == OUI_STANTON)
+ snd_oxfw_scs1x_update(oxfw);
}
static void oxfw_remove(struct fw_unit *unit)
@@ -267,22 +305,16 @@ static void oxfw_remove(struct fw_unit *unit)
snd_card_free_when_closed(oxfw->card);
}
-static const struct device_info griffin_firewave = {
+static const struct compat_info griffin_firewave = {
.driver_name = "FireWave",
.vendor_name = "Griffin",
.model_name = "FireWave",
- .mixer_channels = 6,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x02,
};
-static const struct device_info lacie_speakers = {
+static const struct compat_info lacie_speakers = {
.driver_name = "FWSpeakers",
.vendor_name = "LaCie",
.model_name = "FireWire Speakers",
- .mixer_channels = 1,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x01,
};
static const struct ieee1394_device_id oxfw_id_table[] = {
@@ -340,6 +372,20 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
.vendor_id = VENDOR_TASCAM,
.model_id = 0x800007,
},
+ /* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_STANTON,
+ .model_id = 0x001000,
+ },
+ /* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_STANTON,
+ .model_id = 0x002000,
+ },
{ }
};
MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 8392c424ad1d..9beecc214767 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -31,15 +31,6 @@
#include "../amdtp-am824.h"
#include "../cmp.h"
-struct device_info {
- const char *driver_name;
- const char *vendor_name;
- const char *model_name;
- unsigned int mixer_channels;
- u8 mute_fb_id;
- u8 volume_fb_id;
-};
-
/* This is an arbitrary number for convinience. */
#define SND_OXFW_STREAM_FORMAT_ENTRIES 10
struct snd_oxfw {
@@ -64,14 +55,12 @@ struct snd_oxfw {
unsigned int midi_input_ports;
unsigned int midi_output_ports;
- bool mute;
- s16 volume[6];
- s16 volume_min;
- s16 volume_max;
-
int dev_lock_count;
bool dev_lock_changed;
wait_queue_head_t hwdep_wait;
+
+ const struct ieee1394_device_id *entry;
+ void *spec;
};
/*
@@ -138,10 +127,12 @@ void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw);
int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);
-int snd_oxfw_create_mixer(struct snd_oxfw *oxfw);
-
void snd_oxfw_proc_init(struct snd_oxfw *oxfw);
int snd_oxfw_create_midi(struct snd_oxfw *oxfw);
int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
+
+int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie);
+int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw);
+void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw);
diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c
deleted file mode 100644
index 2dba848a781f..000000000000
--- a/sound/firewire/scs1x.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Stanton Control System 1 MIDI driver
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/wait.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/rawmidi.h>
-#include "lib.h"
-
-#define OUI_STANTON 0x001260
-#define MODEL_SCS_1M 0x001000
-#define MODEL_SCS_1D 0x002000
-
-#define HSS1394_ADDRESS 0xc007dedadadaULL
-#define HSS1394_MAX_PACKET_SIZE 64
-
-#define HSS1394_TAG_USER_DATA 0x00
-#define HSS1394_TAG_CHANGE_ADDRESS 0xf1
-
-struct scs {
- struct snd_card *card;
- struct fw_unit *unit;
- struct fw_address_handler hss_handler;
- struct fw_transaction transaction;
- bool transaction_running;
- bool output_idle;
- u8 output_status;
- u8 output_bytes;
- bool output_escaped;
- bool output_escape_high_nibble;
- u8 input_escape_count;
- struct snd_rawmidi_substream *output;
- struct snd_rawmidi_substream *input;
- struct tasklet_struct tasklet;
- wait_queue_head_t idle_wait;
- u8 *buffer;
-};
-
-static const u8 sysex_escape_prefix[] = {
- 0xf0, /* SysEx begin */
- 0x00, 0x01, 0x60, /* Stanton DJ */
- 0x48, 0x53, 0x53, /* "HSS" */
-};
-
-static int scs_output_open(struct snd_rawmidi_substream *stream)
-{
- struct scs *scs = stream->rmidi->private_data;
-
- scs->output_status = 0;
- scs->output_bytes = 1;
- scs->output_escaped = false;
-
- return 0;
-}
-
-static int scs_output_close(struct snd_rawmidi_substream *stream)
-{
- return 0;
-}
-
-static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up)
-{
- struct scs *scs = stream->rmidi->private_data;
-
- ACCESS_ONCE(scs->output) = up ? stream : NULL;
- if (up) {
- scs->output_idle = false;
- tasklet_schedule(&scs->tasklet);
- }
-}
-
-static void scs_write_callback(struct fw_card *card, int rcode,
- void *data, size_t length, void *callback_data)
-{
- struct scs *scs = callback_data;
-
- if (rcode == RCODE_GENERATION) {
- /* TODO: retry this packet */
- }
-
- scs->transaction_running = false;
- tasklet_schedule(&scs->tasklet);
-}
-
-static bool is_valid_running_status(u8 status)
-{
- return status >= 0x80 && status <= 0xef;
-}
-
-static bool is_one_byte_cmd(u8 status)
-{
- return status == 0xf6 ||
- status >= 0xf8;
-}
-
-static bool is_two_bytes_cmd(u8 status)
-{
- return (status >= 0xc0 && status <= 0xdf) ||
- status == 0xf1 ||
- status == 0xf3;
-}
-
-static bool is_three_bytes_cmd(u8 status)
-{
- return (status >= 0x80 && status <= 0xbf) ||
- (status >= 0xe0 && status <= 0xef) ||
- status == 0xf2;
-}
-
-static bool is_invalid_cmd(u8 status)
-{
- return status == 0xf4 ||
- status == 0xf5 ||
- status == 0xf9 ||
- status == 0xfd;
-}
-
-static void scs_output_tasklet(unsigned long data)
-{
- struct scs *scs = (void *)data;
- struct snd_rawmidi_substream *stream;
- unsigned int i;
- u8 byte;
- struct fw_device *dev;
- int generation;
-
- if (scs->transaction_running)
- return;
-
- stream = ACCESS_ONCE(scs->output);
- if (!stream) {
- scs->output_idle = true;
- wake_up(&scs->idle_wait);
- return;
- }
-
- i = scs->output_bytes;
- for (;;) {
- if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
- scs->output_bytes = i;
- scs->output_idle = true;
- wake_up(&scs->idle_wait);
- return;
- }
- /*
- * Convert from real MIDI to what I think the device expects (no
- * running status, one command per packet, unescaped SysExs).
- */
- if (scs->output_escaped && byte < 0x80) {
- if (scs->output_escape_high_nibble) {
- if (i < HSS1394_MAX_PACKET_SIZE) {
- scs->buffer[i] = byte << 4;
- scs->output_escape_high_nibble = false;
- }
- } else {
- scs->buffer[i++] |= byte & 0x0f;
- scs->output_escape_high_nibble = true;
- }
- } else if (byte < 0x80) {
- if (i == 1) {
- if (!is_valid_running_status(scs->output_status))
- continue;
- scs->buffer[0] = HSS1394_TAG_USER_DATA;
- scs->buffer[i++] = scs->output_status;
- }
- scs->buffer[i++] = byte;
- if ((i == 3 && is_two_bytes_cmd(scs->output_status)) ||
- (i == 4 && is_three_bytes_cmd(scs->output_status)))
- break;
- if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) &&
- !memcmp(scs->buffer + 1, sysex_escape_prefix,
- ARRAY_SIZE(sysex_escape_prefix))) {
- scs->output_escaped = true;
- scs->output_escape_high_nibble = true;
- i = 0;
- }
- if (i >= HSS1394_MAX_PACKET_SIZE)
- i = 1;
- } else if (byte == 0xf7) {
- if (scs->output_escaped) {
- if (i >= 1 && scs->output_escape_high_nibble &&
- scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS)
- break;
- } else {
- if (i > 1 && scs->output_status == 0xf0) {
- scs->buffer[i++] = 0xf7;
- break;
- }
- }
- i = 1;
- scs->output_escaped = false;
- } else if (!is_invalid_cmd(byte) &&
- byte < 0xf8) {
- i = 1;
- scs->buffer[0] = HSS1394_TAG_USER_DATA;
- scs->buffer[i++] = byte;
- scs->output_status = byte;
- scs->output_escaped = false;
- if (is_one_byte_cmd(byte))
- break;
- }
- }
- scs->output_bytes = 1;
- scs->output_escaped = false;
-
- scs->transaction_running = true;
- dev = fw_parent_device(scs->unit);
- generation = dev->generation;
- smp_rmb(); /* node_id vs. generation */
- fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST,
- dev->node_id, generation, dev->max_speed,
- HSS1394_ADDRESS, scs->buffer, i,
- scs_write_callback, scs);
-}
-
-static void scs_output_drain(struct snd_rawmidi_substream *stream)
-{
- struct scs *scs = stream->rmidi->private_data;
-
- wait_event(scs->idle_wait, scs->output_idle);
-}
-
-static struct snd_rawmidi_ops output_ops = {
- .open = scs_output_open,
- .close = scs_output_close,
- .trigger = scs_output_trigger,
- .drain = scs_output_drain,
-};
-
-static int scs_input_open(struct snd_rawmidi_substream *stream)
-{
- struct scs *scs = stream->rmidi->private_data;
-
- scs->input_escape_count = 0;
-
- return 0;
-}
-
-static int scs_input_close(struct snd_rawmidi_substream *stream)
-{
- return 0;
-}
-
-static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up)
-{
- struct scs *scs = stream->rmidi->private_data;
-
- ACCESS_ONCE(scs->input) = up ? stream : NULL;
-}
-
-static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream,
- u8 byte)
-{
- u8 nibbles[2];
-
- nibbles[0] = byte >> 4;
- nibbles[1] = byte & 0x0f;
- snd_rawmidi_receive(stream, nibbles, 2);
-}
-
-static void scs_input_midi_byte(struct scs *scs,
- struct snd_rawmidi_substream *stream,
- u8 byte)
-{
- if (scs->input_escape_count > 0) {
- scs_input_escaped_byte(stream, byte);
- scs->input_escape_count--;
- if (scs->input_escape_count == 0)
- snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1);
- } else if (byte == 0xf9) {
- snd_rawmidi_receive(stream, sysex_escape_prefix,
- ARRAY_SIZE(sysex_escape_prefix));
- scs_input_escaped_byte(stream, 0x00);
- scs_input_escaped_byte(stream, 0xf9);
- scs->input_escape_count = 3;
- } else {
- snd_rawmidi_receive(stream, &byte, 1);
- }
-}
-
-static void scs_input_packet(struct scs *scs,
- struct snd_rawmidi_substream *stream,
- const u8 *data, unsigned int bytes)
-{
- unsigned int i;
-
- if (data[0] == HSS1394_TAG_USER_DATA) {
- for (i = 1; i < bytes; ++i)
- scs_input_midi_byte(scs, stream, data[i]);
- } else {
- snd_rawmidi_receive(stream, sysex_escape_prefix,
- ARRAY_SIZE(sysex_escape_prefix));
- for (i = 0; i < bytes; ++i)
- scs_input_escaped_byte(stream, data[i]);
- snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1);
- }
-}
-
-static struct snd_rawmidi_ops input_ops = {
- .open = scs_input_open,
- .close = scs_input_close,
- .trigger = scs_input_trigger,
-};
-
-static int scs_create_midi(struct scs *scs)
-{
- struct snd_rawmidi *rmidi;
- int err;
-
- err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi);
- if (err < 0)
- return err;
- snprintf(rmidi->name, sizeof(rmidi->name),
- "%s MIDI", scs->card->shortname);
- rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT |
- SNDRV_RAWMIDI_INFO_DUPLEX;
- rmidi->private_data = scs;
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops);
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops);
-
- return 0;
-}
-
-static void handle_hss(struct fw_card *card, struct fw_request *request,
- int tcode, int destination, int source, int generation,
- unsigned long long offset, void *data, size_t length,
- void *callback_data)
-{
- struct scs *scs = callback_data;
- struct snd_rawmidi_substream *stream;
-
- if (offset != scs->hss_handler.offset) {
- fw_send_response(card, request, RCODE_ADDRESS_ERROR);
- return;
- }
- if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
- tcode != TCODE_WRITE_BLOCK_REQUEST) {
- fw_send_response(card, request, RCODE_TYPE_ERROR);
- return;
- }
-
- if (length >= 1) {
- stream = ACCESS_ONCE(scs->input);
- if (stream)
- scs_input_packet(scs, stream, data, length);
- }
-
- fw_send_response(card, request, RCODE_COMPLETE);
-}
-
-static int scs_init_hss_address(struct scs *scs)
-{
- __be64 data;
- int err;
-
- data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
- scs->hss_handler.offset);
- err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
- HSS1394_ADDRESS, &data, 8, 0);
- if (err < 0)
- dev_err(&scs->unit->device, "HSS1394 communication failed\n");
-
- return err;
-}
-
-static void scs_card_free(struct snd_card *card)
-{
- struct scs *scs = card->private_data;
-
- fw_core_remove_address_handler(&scs->hss_handler);
- kfree(scs->buffer);
-}
-
-static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
-{
- struct fw_device *fw_dev = fw_parent_device(unit);
- struct snd_card *card;
- struct scs *scs;
- int err;
-
- err = snd_card_new(&unit->device, -16, NULL, THIS_MODULE,
- sizeof(*scs), &card);
- if (err < 0)
- return err;
-
- scs = card->private_data;
- scs->card = card;
- scs->unit = unit;
- tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
- init_waitqueue_head(&scs->idle_wait);
- scs->output_idle = true;
-
- scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL);
- if (!scs->buffer) {
- err = -ENOMEM;
- goto err_card;
- }
-
- scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
- scs->hss_handler.address_callback = handle_hss;
- scs->hss_handler.callback_data = scs;
- err = fw_core_add_address_handler(&scs->hss_handler,
- &fw_high_memory_region);
- if (err < 0)
- goto err_buffer;
-
- card->private_free = scs_card_free;
-
- strcpy(card->driver, "SCS.1x");
- strcpy(card->shortname, "SCS.1x");
- fw_csr_string(unit->directory, CSR_MODEL,
- card->shortname, sizeof(card->shortname));
- snprintf(card->longname, sizeof(card->longname),
- "Stanton DJ %s (GUID %08x%08x) at %s, S%d",
- card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4],
- dev_name(&unit->device), 100 << fw_dev->max_speed);
- strcpy(card->mixername, card->shortname);
-
- err = scs_init_hss_address(scs);
- if (err < 0)
- goto err_card;
-
- err = scs_create_midi(scs);
- if (err < 0)
- goto err_card;
-
- err = snd_card_register(card);
- if (err < 0)
- goto err_card;
-
- dev_set_drvdata(&unit->device, scs);
-
- return 0;
-
-err_buffer:
- kfree(scs->buffer);
-err_card:
- snd_card_free(card);
- return err;
-}
-
-static void scs_update(struct fw_unit *unit)
-{
- struct scs *scs = dev_get_drvdata(&unit->device);
- int generation;
- __be64 data;
-
- data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
- scs->hss_handler.offset);
- generation = fw_parent_device(unit)->generation;
- smp_rmb(); /* node_id vs. generation */
- snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
- HSS1394_ADDRESS, &data, 8,
- FW_FIXED_GENERATION | generation);
-}
-
-static void scs_remove(struct fw_unit *unit)
-{
- struct scs *scs = dev_get_drvdata(&unit->device);
-
- snd_card_disconnect(scs->card);
-
- ACCESS_ONCE(scs->output) = NULL;
- ACCESS_ONCE(scs->input) = NULL;
-
- wait_event(scs->idle_wait, scs->output_idle);
-
- tasklet_kill(&scs->tasklet);
-
- snd_card_free_when_closed(scs->card);
-}
-
-static const struct ieee1394_device_id scs_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_VENDOR_ID |
- IEEE1394_MATCH_MODEL_ID,
- .vendor_id = OUI_STANTON,
- .model_id = MODEL_SCS_1M,
- },
- {
- .match_flags = IEEE1394_MATCH_VENDOR_ID |
- IEEE1394_MATCH_MODEL_ID,
- .vendor_id = OUI_STANTON,
- .model_id = MODEL_SCS_1D,
- },
- {}
-};
-MODULE_DEVICE_TABLE(ieee1394, scs_id_table);
-
-MODULE_DESCRIPTION("SCS.1x MIDI driver");
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
-
-static struct fw_driver scs_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = KBUILD_MODNAME,
- .bus = &fw_bus_type,
- },
- .probe = scs_probe,
- .update = scs_update,
- .remove = scs_remove,
- .id_table = scs_id_table,
-};
-
-static int __init alsa_scs1x_init(void)
-{
- return driver_register(&scs_driver.driver);
-}
-
-static void __exit alsa_scs1x_exit(void)
-{
- driver_unregister(&scs_driver.driver);
-}
-
-module_init(alsa_scs1x_init);
-module_exit(alsa_scs1x_exit);
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 63215b17247c..548cc1e4114b 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
ebus->spbcap = bus->remap_addr + offset;
break;
+ case AZX_DRSM_CAP_ID:
+ /* DMA resume capability found, handler function */
+ dev_dbg(bus->dev, "Found DRSM capability\n");
+ ebus->drsmcap = bus->remap_addr + offset;
+ break;
+
default:
dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
break;
@@ -240,7 +246,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
int mask = (1 << AZX_MLCTL_CPA);
udelay(3);
- timeout = 50;
+ timeout = 150;
do {
val = readl(link->ml_addr + AZX_REG_ML_LCTL);
@@ -282,6 +288,27 @@ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
/**
+ * snd_hdac_ext_bus_link_power_up_all -power up all hda link
+ * @ebus: HD-audio extended bus
+ */
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
+{
+ struct hdac_ext_link *hlink = NULL;
+ int ret;
+
+ list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ snd_hdac_updatel(hlink->ml_addr,
+ AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+ ret = check_hdac_link_power_active(hlink, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
+
+/**
* snd_hdac_ext_bus_link_power_down_all -power down all hda link
* @ebus: HD-audio extended bus
*/
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index cb89ec7c8147..023cc4cad5c1 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
AZX_SPB_MAXFIFO;
}
+ if (ebus->drsmcap)
+ stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
+ AZX_DRSM_INTERVAL * idx;
+
stream->decoupled = false;
snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
}
@@ -107,6 +111,7 @@ void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus)
while (!list_empty(&bus->stream_list)) {
s = list_first_entry(&bus->stream_list, struct hdac_stream, list);
stream = stream_to_hdac_ext_stream(s);
+ snd_hdac_ext_stream_decouple(ebus, stream, false);
list_del(&s->list);
kfree(stream);
}
@@ -497,3 +502,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
}
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
+
+/**
+ * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
+ * @ebus: HD-audio ext core bus
+ * @enable: flag to enable/disable DRSM
+ * @index: stream index for which DRSM need to be enabled
+ */
+void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+ bool enable, int index)
+{
+ u32 mask = 0;
+ u32 register_mask = 0;
+ struct hdac_bus *bus = &ebus->bus;
+
+ if (!ebus->drsmcap) {
+ dev_err(bus->dev, "Address of DRSM capability is NULL");
+ return;
+ }
+
+ mask |= (1 << index);
+
+ register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
+
+ mask |= register_mask;
+
+ if (enable)
+ snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
+ else
+ snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
+
+/**
+ * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: dpib value to set
+ */
+int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+ struct hdac_ext_stream *stream, u32 value)
+{
+ struct hdac_bus *bus = &ebus->bus;
+
+ if (!ebus->drsmcap) {
+ dev_err(bus->dev, "Address of DRSM capability is NULL");
+ return -EINVAL;
+ }
+
+ writel(value, stream->dpibr_addr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
+
+/**
+ * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: lpib value to set
+ */
+int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value)
+{
+ snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index 8fef1b8d1fd8..c50177fb469f 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -118,6 +118,72 @@ int snd_hdac_get_display_clk(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk);
+/* There is a fixed mapping between audio pin node and display port
+ * on current Intel platforms:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ */
+static int pin2port(hda_nid_t pin_nid)
+{
+ return pin_nid - 4;
+}
+
+/**
+ * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
+ * @bus: HDA core bus
+ * @nid: the pin widget NID
+ * @rate: the sample rate to set
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function sets N/CTS value based on the given sample rate.
+ * Returns zero for success, or a negative error code.
+ */
+int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate)
+{
+ struct i915_audio_component *acomp = bus->audio_component;
+
+ if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
+ return -ENODEV;
+ return acomp->ops->sync_audio_rate(acomp->dev, pin2port(nid), rate);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
+
+/**
+ * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
+ * @bus: HDA core bus
+ * @nid: the pin widget NID
+ * @audio_enabled: the pointer to store the current audio state
+ * @buffer: the buffer pointer to store ELD bytes
+ * @max_bytes: the max bytes to be stored on @buffer
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function queries the current state of the audio on the given
+ * digital port and fetches the ELD bytes onto the given buffer.
+ * It returns the number of bytes for the total ELD data, zero for
+ * invalid ELD, or a negative error code.
+ *
+ * The return size is the total bytes required for the whole ELD bytes,
+ * thus it may be over @max_bytes. If it's over @max_bytes, it implies
+ * that only a part of ELD bytes have been fetched.
+ */
+int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+ bool *audio_enabled, char *buffer, int max_bytes)
+{
+ struct i915_audio_component *acomp = bus->audio_component;
+
+ if (!acomp || !acomp->ops || !acomp->ops->get_eld)
+ return -ENODEV;
+
+ return acomp->ops->get_eld(acomp->dev, pin2port(nid), audio_enabled,
+ buffer, max_bytes);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
+
static int hdac_component_master_bind(struct device *dev)
{
struct i915_audio_component *acomp = hdac_acomp;
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index 4677037f0c8e..ef2a9afe9e19 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -39,7 +39,7 @@ static int snd_i2c_bit_readbytes(struct snd_i2c_device *device,
static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus,
unsigned short addr);
-static struct snd_i2c_ops snd_i2c_bit_ops = {
+static const struct snd_i2c_ops snd_i2c_bit_ops = {
.sendbytes = snd_i2c_bit_sendbytes,
.readbytes = snd_i2c_bit_readbytes,
.probeaddr = snd_i2c_bit_probeaddr,
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 48568fdf847f..4033fe58f0cf 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -240,7 +240,7 @@ config MSND_FIFOSIZE
menuconfig SOUND_OSS
tristate "OSS sound modules"
- depends on ISA_DMA_API && VIRT_TO_BUS
+ depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER)
depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN
help
OSS is the Open Sound System suite of sound card drivers. They make
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 1028fc8bdff5..2ce0022dbc46 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1219,7 +1219,7 @@ static struct ac97_pcm atiixp_pcm_defs[] = {
},
};
-static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
.type = ATI_DMA_PLAYBACK,
.llp_offset = ATI_REG_OUT_DMA_LINKPTR,
.dt_cur = ATI_REG_OUT_DMA_DT_CUR,
@@ -1228,7 +1228,7 @@ static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
.flush_dma = atiixp_out_flush_dma,
};
-static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
.type = ATI_DMA_CAPTURE,
.llp_offset = ATI_REG_IN_DMA_LINKPTR,
.dt_cur = ATI_REG_IN_DMA_DT_CUR,
@@ -1237,7 +1237,7 @@ static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
.flush_dma = atiixp_in_flush_dma,
};
-static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {
.type = ATI_DMA_SPDIF,
.llp_offset = ATI_REG_SPDF_DMA_LINKPTR,
.dt_cur = ATI_REG_SPDF_DMA_DT_CUR,
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 27ed678a46df..c534552963e7 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -970,7 +970,7 @@ static struct snd_pcm_ops snd_atiixp_capture_ops = {
.pointer = snd_atiixp_pcm_pointer,
};
-static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
.type = ATI_DMA_PLAYBACK,
.llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR,
.dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR,
@@ -979,7 +979,7 @@ static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
.flush_dma = atiixp_out_flush_dma,
};
-static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
.type = ATI_DMA_CAPTURE,
.llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR,
.dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 07a4acc99541..5e2ef0bb7057 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2294,8 +2294,6 @@ snd_azf3328_free(struct snd_azf3328 *chip)
snd_azf3328_timer_stop(chip->timer);
snd_azf3328_gameport_free(chip);
- if (chip->irq >= 0)
- synchronize_irq(chip->irq);
__end_hw:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 9c2dc911d8d7..27fa57da8dc4 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -402,7 +402,7 @@ static struct snd_pcm_ops snd_cs5535audio_capture_ops = {
.pointer = snd_cs5535audio_pcm_pointer,
};
-static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
+static const struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
.type = CS5535AUDIO_DMA_PLAYBACK,
.enable_dma = cs5535audio_playback_enable_dma,
.disable_dma = cs5535audio_playback_disable_dma,
@@ -412,7 +412,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
.read_dma_pntr = cs5535audio_playback_read_dma_pntr,
};
-static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
+static const struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
.type = CS5535AUDIO_DMA_CAPTURE,
.enable_dma = cs5535audio_capture_enable_dma,
.disable_dma = cs5535audio_capture_disable_dma,
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 759295aa8366..bade9b907b92 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -163,6 +163,7 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers");
* @cap_ctrl: capture control
*/
struct fm801 {
+ struct device *dev;
int irq;
unsigned long port;
@@ -190,7 +191,6 @@ struct fm801 {
struct snd_ac97 *ac97;
struct snd_ac97 *ac97_sec;
- struct pci_dev *pci;
struct snd_card *card;
struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
@@ -212,6 +212,20 @@ struct fm801 {
#endif
};
+/*
+ * IO accessors
+ */
+
+static inline void fm801_iowrite16(struct fm801 *chip, unsigned short offset, u16 value)
+{
+ outw(value, chip->port + offset);
+}
+
+static inline u16 fm801_ioread16(struct fm801 *chip, unsigned short offset)
+{
+ return inw(chip->port + offset);
+}
+
static const struct pci_device_id snd_fm801_ids[] = {
{ 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */
{ 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */
@@ -256,11 +270,11 @@ static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg,
unsigned short old, new;
spin_lock_irqsave(&chip->reg_lock, flags);
- old = inw(chip->port + reg);
+ old = fm801_ioread16(chip, reg);
new = (old & ~mask) | value;
change = old != new;
if (change)
- outw(new, chip->port + reg);
+ fm801_iowrite16(chip, reg, new);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -578,8 +592,9 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
}
if (chip->rmidi && (status & FM801_IRQ_MPU))
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
- if (status & FM801_IRQ_VOLUME)
- ;/* TODO */
+ if (status & FM801_IRQ_VOLUME) {
+ /* TODO */
+ }
return IRQ_HANDLED;
}
@@ -700,6 +715,7 @@ static struct snd_pcm_ops snd_fm801_capture_ops = {
static int snd_fm801_pcm(struct fm801 *chip, int device)
{
+ struct pci_dev *pdev = to_pci_dev(chip->dev);
struct snd_pcm *pcm;
int err;
@@ -715,7 +731,7 @@ static int snd_fm801_pcm(struct fm801 *chip, int device)
chip->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
+ snd_dma_pci_data(pdev),
chip->multichannel ? 128*1024 : 64*1024, 128*1024);
return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -851,10 +867,11 @@ static int snd_fm801_get_single(struct snd_kcontrol *kcontrol,
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
+ long *value = ucontrol->value.integer.value;
- ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift) & mask;
+ value[0] = (fm801_ioread16(chip, reg) >> shift) & mask;
if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+ value[0] = mask - value[0];
return 0;
}
@@ -907,14 +924,15 @@ static int snd_fm801_get_double(struct snd_kcontrol *kcontrol,
int shift_right = (kcontrol->private_value >> 12) & 0x0f;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
+ long *value = ucontrol->value.integer.value;
spin_lock_irq(&chip->reg_lock);
- ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift_left) & mask;
- ucontrol->value.integer.value[1] = (inw(chip->port + reg) >> shift_right) & mask;
+ value[0] = (fm801_ioread16(chip, reg) >> shift_left) & mask;
+ value[1] = (fm801_ioread16(chip, reg) >> shift_right) & mask;
spin_unlock_irq(&chip->reg_lock);
if (invert) {
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
+ value[0] = mask - value[0];
+ value[1] = mask - value[1];
}
return 0;
}
@@ -1080,26 +1098,20 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id,
return -EIO;
}
-static int snd_fm801_chip_init(struct fm801 *chip, int resume)
+static int reset_codec(struct fm801 *chip)
{
- unsigned short cmdw;
-
- if (chip->tea575x_tuner & TUNER_ONLY)
- goto __ac97_ok;
-
/* codec cold reset + AC'97 warm reset */
fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6));
fm801_readw(chip, CODEC_CTRL); /* flush posting data */
udelay(100);
fm801_writew(chip, CODEC_CTRL, 0);
- if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
- if (!resume) {
- dev_info(chip->card->dev,
- "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
- chip->tea575x_tuner = 3 | TUNER_ONLY;
- goto __ac97_ok;
- }
+ return wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750));
+}
+
+static void snd_fm801_chip_multichannel_init(struct fm801 *chip)
+{
+ unsigned short cmdw;
if (chip->multichannel) {
if (chip->secondary_addr) {
@@ -1126,8 +1138,11 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
/* cause timeout problems */
wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750));
}
+}
- __ac97_ok:
+static void snd_fm801_chip_init(struct fm801 *chip)
+{
+ unsigned short cmdw;
/* init volume */
fm801_writew(chip, PCM_VOL, 0x0808);
@@ -1148,11 +1163,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
/* interrupt clear */
fm801_writew(chip, IRQ_STATUS,
FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU);
-
- return 0;
}
-
static int snd_fm801_free(struct fm801 *chip)
{
unsigned short cmdw;
@@ -1165,6 +1177,8 @@ static int snd_fm801_free(struct fm801 *chip)
cmdw |= 0x00c3;
fm801_writew(chip, IRQ_MASK, cmdw);
+ devm_free_irq(chip->dev, chip->irq, chip);
+
__end_hw:
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
@@ -1201,13 +1215,29 @@ static int snd_fm801_create(struct snd_card *card,
return -ENOMEM;
spin_lock_init(&chip->reg_lock);
chip->card = card;
- chip->pci = pci;
+ chip->dev = &pci->dev;
chip->irq = -1;
chip->tea575x_tuner = tea575x_tuner;
if ((err = pci_request_regions(pci, "FM801")) < 0)
return err;
chip->port = pci_resource_start(pci, 0);
- if ((tea575x_tuner & TUNER_ONLY) == 0) {
+
+ if (pci->revision >= 0xb1) /* FM801-AU */
+ chip->multichannel = 1;
+
+ if (!(chip->tea575x_tuner & TUNER_ONLY)) {
+ if (reset_codec(chip) < 0) {
+ dev_info(chip->card->dev,
+ "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
+ chip->tea575x_tuner = 3 | TUNER_ONLY;
+ } else {
+ snd_fm801_chip_multichannel_init(chip);
+ }
+ }
+
+ snd_fm801_chip_init(chip);
+
+ if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
@@ -1218,13 +1248,6 @@ static int snd_fm801_create(struct snd_card *card,
pci_set_master(pci);
}
- if (pci->revision >= 0xb1) /* FM801-AU */
- chip->multichannel = 1;
-
- snd_fm801_chip_init(chip, 0);
- /* init might set tuner access method */
- tea575x_tuner = chip->tea575x_tuner;
-
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_fm801_free(chip);
return err;
@@ -1241,14 +1264,16 @@ static int snd_fm801_create(struct snd_card *card,
chip->tea.private_data = chip;
chip->tea.ops = &snd_fm801_tea_ops;
sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
- if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
- (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
+ if ((chip->tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
+ (chip->tea575x_tuner & TUNER_TYPE_MASK) < 4) {
if (snd_tea575x_init(&chip->tea, THIS_MODULE)) {
dev_err(card->dev, "TEA575x radio not found\n");
snd_fm801_free(chip);
return -ENODEV;
}
- } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
+ } else if ((chip->tea575x_tuner & TUNER_TYPE_MASK) == 0) {
+ unsigned int tuner_only = chip->tea575x_tuner & TUNER_ONLY;
+
/* autodetect tuner connection */
for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
chip->tea575x_tuner = tea575x_tuner;
@@ -1263,6 +1288,8 @@ static int snd_fm801_create(struct snd_card *card,
dev_err(card->dev, "TEA575x radio not found\n");
chip->tea575x_tuner = TUNER_DISABLED;
}
+
+ chip->tea575x_tuner |= tuner_only;
}
if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
@@ -1366,12 +1393,18 @@ static int snd_fm801_suspend(struct device *dev)
int i;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
- snd_ac97_suspend(chip->ac97);
- snd_ac97_suspend(chip->ac97_sec);
+
for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
- chip->saved_regs[i] = inw(chip->port + saved_regs[i]);
- /* FIXME: tea575x suspend */
+ chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]);
+
+ if (chip->tea575x_tuner & TUNER_ONLY) {
+ /* FIXME: tea575x suspend */
+ } else {
+ snd_pcm_suspend_all(chip->pcm);
+ snd_ac97_suspend(chip->ac97);
+ snd_ac97_suspend(chip->ac97_sec);
+ }
+
return 0;
}
@@ -1381,11 +1414,23 @@ static int snd_fm801_resume(struct device *dev)
struct fm801 *chip = card->private_data;
int i;
- snd_fm801_chip_init(chip, 1);
- snd_ac97_resume(chip->ac97);
- snd_ac97_resume(chip->ac97_sec);
+ if (chip->tea575x_tuner & TUNER_ONLY) {
+ snd_fm801_chip_init(chip);
+ } else {
+ reset_codec(chip);
+ snd_fm801_chip_multichannel_init(chip);
+ snd_fm801_chip_init(chip);
+ snd_ac97_resume(chip->ac97);
+ snd_ac97_resume(chip->ac97_sec);
+ }
+
for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
- outw(chip->saved_regs[i], chip->port + saved_regs[i]);
+ fm801_iowrite16(chip, saved_regs[i], chip->saved_regs[i]);
+
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+ if (!(chip->tea575x_tuner & TUNER_DISABLED))
+ snd_tea575x_set_freq(&chip->tea);
+#endif
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 22dbfa563919..37cf9cee9835 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -956,7 +956,7 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
status = azx_readb(chip, RIRBSTS);
if (status & RIRB_INT_MASK) {
if (status & RIRB_INT_RESPONSE) {
- if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
+ if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
udelay(80);
snd_hdac_bus_update_rirb(bus);
}
@@ -1050,16 +1050,10 @@ int azx_bus_init(struct azx *chip, const char *model,
if (chip->get_position[0] != azx_get_pos_lpib ||
chip->get_position[1] != azx_get_pos_lpib)
bus->core.use_posbuf = true;
- if (chip->bdl_pos_adj)
- bus->core.bdl_pos_adj = chip->bdl_pos_adj[chip->dev_index];
+ bus->core.bdl_pos_adj = chip->bdl_pos_adj;
if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)
bus->core.corbrp_self_clear = true;
- if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
- dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
- bus->needs_damn_long_delay = 1;
- }
-
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY)
bus->core.align_bdle_4k = true;
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index 7b635d68cfe1..ec63bbf1ec6d 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -32,21 +32,25 @@
#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */
#define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */
#define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */
-#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */
+/* 13 unused */
+/* 14 unused */
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */
+/* 17 unused */
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */
/* 22 unused */
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
-#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */
+/* 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
#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 */
@@ -143,7 +147,7 @@ struct azx {
#endif
/* flags */
- const int *bdl_pos_adj;
+ int bdl_pos_adj;
int poll_count;
unsigned int running:1;
unsigned int single_cmd:1;
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 563984dd2562..bc2e08257c2e 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -253,6 +253,7 @@ int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e,
int mnl;
int i;
+ memset(e, 0, sizeof(*e));
e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
if (e->eld_ver != ELD_VER_CEA_861D &&
e->eld_ver != ELD_VER_PARTIAL) {
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index c6e8a651cea1..30c8efe0f80a 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -279,22 +279,6 @@ static struct nid_path *get_nid_path(struct hda_codec *codec,
}
/**
- * snd_hda_get_nid_path - get the path between the given NIDs
- * @codec: the HDA codec
- * @from_nid: the NID where the path start from
- * @to_nid: the NID where the path ends at
- *
- * Return the found nid_path object or NULL for error.
- * Passing 0 to either @from_nid or @to_nid behaves as a wildcard.
- */
-struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
- hda_nid_t from_nid, hda_nid_t to_nid)
-{
- return get_nid_path(codec, from_nid, to_nid, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_nid_path);
-
-/**
* snd_hda_get_path_idx - get the index number corresponding to the path
* instance
* @codec: the HDA codec
@@ -451,7 +435,7 @@ static bool __parse_nid_path(struct hda_codec *codec,
return true;
}
-/**
+/*
* snd_hda_parse_nid_path - parse the widget path from the given nid to
* the target nid
* @codec: the HDA codec
@@ -470,7 +454,7 @@ static bool __parse_nid_path(struct hda_codec *codec,
* with the negative of given value are excluded, only other paths are chosen.
* when @anchor_nid is zero, no special handling about path selection.
*/
-bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
+static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
hda_nid_t to_nid, int anchor_nid,
struct nid_path *path)
{
@@ -481,7 +465,6 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
}
return false;
}
-EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path);
/**
* snd_hda_add_new_path - parse the path between the given NIDs and
@@ -771,9 +754,6 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps;
unsigned int mask, val;
- if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
- return;
-
caps = query_amp_caps(codec, nid, dir);
val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
@@ -784,12 +764,22 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
update_amp(codec, nid, dir, idx, mask, val);
}
+static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid,
+ int dir, int idx, int idx_to_check,
+ bool enable)
+{
+ /* check whether the given amp is still used by others */
+ if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
+ return;
+ activate_amp(codec, nid, dir, idx, idx_to_check, enable);
+}
+
static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
int i, bool enable)
{
hda_nid_t nid = path->path[i];
init_amp(codec, nid, HDA_OUTPUT, 0);
- activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
+ check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
}
static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
@@ -817,9 +807,16 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
* when aa-mixer is available, we need to enable the path as well
*/
for (n = 0; n < nums; n++) {
- if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid))
- continue;
- activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
+ if (n != idx) {
+ if (conn[n] != spec->mixer_merge_nid)
+ continue;
+ /* when aamix is disabled, force to off */
+ if (!add_aamix) {
+ activate_amp(codec, nid, HDA_INPUT, n, n, false);
+ continue;
+ }
+ }
+ check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
}
}
@@ -1580,6 +1577,12 @@ static bool map_singles(struct hda_codec *codec, int outs,
return found;
}
+static inline bool has_aamix_out_paths(struct hda_gen_spec *spec)
+{
+ return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
+ spec->aamix_out_paths[2];
+}
+
/* create a new path including aamix if available, and return its index */
static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
{
@@ -2422,25 +2425,51 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
}
}
+/* re-initialize the output paths; only called from loopback_mixing_put() */
+static void update_output_paths(struct hda_codec *codec, int num_outs,
+ const int *paths)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ struct nid_path *path;
+ int i;
+
+ for (i = 0; i < num_outs; i++) {
+ path = snd_hda_get_path_from_idx(codec, paths[i]);
+ if (path)
+ snd_hda_activate_path(codec, path, path->active,
+ spec->aamix_mode);
+ }
+}
+
static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hda_gen_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int val = ucontrol->value.enumerated.item[0];
if (val == spec->aamix_mode)
return 0;
spec->aamix_mode = val;
- update_aamix_paths(codec, val, spec->out_paths[0],
- spec->aamix_out_paths[0],
- spec->autocfg.line_out_type);
- update_aamix_paths(codec, val, spec->hp_paths[0],
- spec->aamix_out_paths[1],
- AUTO_PIN_HP_OUT);
- update_aamix_paths(codec, val, spec->speaker_paths[0],
- spec->aamix_out_paths[2],
- AUTO_PIN_SPEAKER_OUT);
+ if (has_aamix_out_paths(spec)) {
+ update_aamix_paths(codec, val, spec->out_paths[0],
+ spec->aamix_out_paths[0],
+ cfg->line_out_type);
+ update_aamix_paths(codec, val, spec->hp_paths[0],
+ spec->aamix_out_paths[1],
+ AUTO_PIN_HP_OUT);
+ update_aamix_paths(codec, val, spec->speaker_paths[0],
+ spec->aamix_out_paths[2],
+ AUTO_PIN_SPEAKER_OUT);
+ } else {
+ update_output_paths(codec, cfg->line_outs, spec->out_paths);
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+ update_output_paths(codec, cfg->hp_outs, spec->hp_paths);
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+ update_output_paths(codec, cfg->speaker_outs,
+ spec->speaker_paths);
+ }
return 1;
}
@@ -2458,12 +2487,13 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec)
if (!spec->mixer_nid)
return 0;
- if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
- spec->aamix_out_paths[2]))
- return 0;
if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
return -ENOMEM;
spec->have_aamix_ctl = 1;
+ /* if no explicit aamix path is present (e.g. for Realtek codecs),
+ * enable aamix as default -- just for compatibility
+ */
+ spec->aamix_mode = !has_aamix_out_paths(spec);
return 0;
}
@@ -5664,6 +5694,8 @@ static void init_aamix_paths(struct hda_codec *codec)
if (!spec->have_aamix_ctl)
return;
+ if (!has_aamix_out_paths(spec))
+ return;
update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
spec->aamix_out_paths[0],
spec->autocfg.line_out_type);
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 56e4139b9032..f66fc7e25e07 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -306,13 +306,8 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
int snd_hda_gen_init(struct hda_codec *codec);
void snd_hda_gen_free(struct hda_codec *codec);
-struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
- hda_nid_t from_nid, hda_nid_t to_nid);
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
-bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
- hda_nid_t to_nid, int anchor_nid,
- struct nid_path *path);
struct nid_path *
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
hda_nid_t to_nid, int anchor_nid);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 3b3658297070..c0bef11afa7e 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -284,13 +284,19 @@ enum {
(AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE)
/* quirks for Intel PCH */
-#define AZX_DCAPS_INTEL_PCH_NOPM \
+#define AZX_DCAPS_INTEL_PCH_BASE \
(AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\
- AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH))
+ AZX_DCAPS_SNOOP_TYPE(SCH))
+
+/* PCH up to IVB; no runtime PM */
+#define AZX_DCAPS_INTEL_PCH_NOPM \
+ (AZX_DCAPS_INTEL_PCH_BASE)
+/* PCH for HSW/BDW; with runtime PM */
#define AZX_DCAPS_INTEL_PCH \
- (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME)
+ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME)
+/* HSW HDMI */
#define AZX_DCAPS_INTEL_HASWELL \
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
@@ -332,7 +338,7 @@ enum {
/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
- (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
+ (AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\
AZX_DCAPS_SNOOP_TYPE(NVIDIA))
@@ -649,7 +655,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 &&
pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2)
/* NG - it's below the first next period boundary */
- return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1;
+ return chip->bdl_pos_adj ? 0 : -1;
azx_dev->core.start_wallclk += wallclk;
return 1; /* OK, it's fine */
}
@@ -719,7 +725,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
if (request_irq(chip->pci->irq, azx_interrupt,
chip->msi ? 0 : IRQF_SHARED,
- KBUILD_MODNAME, chip)) {
+ chip->card->irq_descr, chip)) {
dev_err(chip->card->dev,
"unable to grab IRQ %d, disabling device\n",
chip->pci->irq);
@@ -1376,7 +1382,7 @@ static int check_position_fix(struct azx *chip, int fix)
}
/* Check VIA/ATI HD Audio Controller exist */
- if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
+ if (chip->driver_type == AZX_DRIVER_VIA) {
dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
return POS_FIX_VIACOMBO;
}
@@ -1539,6 +1545,26 @@ static void azx_probe_work(struct work_struct *work)
azx_probe_continue(&hda->chip);
}
+static int default_bdl_pos_adj(struct azx *chip)
+{
+ /* some exceptions: Atoms seem problematic with value 1 */
+ if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) {
+ switch (chip->pci->device) {
+ case 0x0f04: /* Baytrail */
+ case 0x2284: /* Braswell */
+ return 32;
+ }
+ }
+
+ switch (chip->driver_type) {
+ case AZX_DRIVER_ICH:
+ case AZX_DRIVER_PCH:
+ return 1;
+ default:
+ return 32;
+ }
+}
+
/*
* constructor
*/
@@ -1592,18 +1618,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
chip->single_cmd = single_cmd;
azx_check_snoop_available(chip);
- if (bdl_pos_adj[dev] < 0) {
- switch (chip->driver_type) {
- case AZX_DRIVER_ICH:
- case AZX_DRIVER_PCH:
- bdl_pos_adj[dev] = 1;
- break;
- default:
- bdl_pos_adj[dev] = 32;
- break;
- }
- }
- chip->bdl_pos_adj = bdl_pos_adj;
+ if (bdl_pos_adj[dev] < 0)
+ chip->bdl_pos_adj = default_bdl_pos_adj(chip);
+ else
+ chip->bdl_pos_adj = bdl_pos_adj[dev];
err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
if (err < 0) {
@@ -1612,6 +1630,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
+ if (chip->driver_type == AZX_DRIVER_NVIDIA) {
+ dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
+ chip->bus.needs_damn_long_delay = 1;
+ }
+
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
dev_err(card->dev, "Error creating device [card]!\n");
@@ -2005,8 +2028,8 @@ static int azx_probe(struct pci_dev *pci,
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
#ifndef CONFIG_SND_HDA_I915
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n");
+ if (CONTROLLER_IN_GPU(pci))
+ dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
#endif
if (schedule_probe)
@@ -2203,10 +2226,10 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Poulsbo */
{ PCI_DEVICE(0x8086, 0x811b),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
/* Oaktrail */
{ PCI_DEVICE(0x8086, 0x080a),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
/* BayTrail */
{ PCI_DEVICE(0x8086, 0x0f04),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL },
@@ -2318,8 +2341,7 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x1002, 0xaae8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
/* VIA VT8251/VT8237A */
- { PCI_DEVICE(0x1106, 0x3288),
- .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
+ { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
/* VIA GFX VT7122/VX900 */
{ PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
/* VIA GFX VT6122/VX11 */
@@ -2353,14 +2375,12 @@ static const struct pci_device_id azx_ids[] = {
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
- AZX_DCAPS_NO_64BIT |
- AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
+ AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
#else
/* this entry seems still valid -- i.e. without emu20kx chip */
{ PCI_DEVICE(0x1102, 0x0009),
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
- AZX_DCAPS_NO_64BIT |
- AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
+ AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
#endif
/* CM8888 */
{ PCI_DEVICE(0x13f6, 0x5011),
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 58c0aad37284..17fd81736d3d 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -464,6 +464,8 @@ static int hda_tegra_create(struct snd_card *card,
if (err < 0)
return err;
+ chip->bus.needs_damn_long_delay = 1;
+
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
dev_err(card->dev, "Error creating device\n");
@@ -481,8 +483,7 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match);
static int hda_tegra_probe(struct platform_device *pdev)
{
- const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY |
- AZX_DCAPS_CORBRP_SELF_CLEAR;
+ const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR;
struct snd_card *card;
struct azx *chip;
struct hda_tegra *hda;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ef198903c0c3..6122b8ca872f 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -901,6 +901,9 @@ static int patch_conexant_auto(struct hda_codec *codec)
snd_hda_pick_fixup(codec, cxt5051_fixup_models,
cxt5051_fixups, cxt_fixups);
break;
+ case 0x14f150f2:
+ codec->power_save_node = 1;
+ /* Fall through */
default:
codec->pin_amp_workaround = 1;
snd_hda_pick_fixup(codec, cxt5066_fixup_models,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 4b6fb668c91c..426a29a1c19b 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -51,8 +51,10 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
#define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808)
#define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809)
#define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a)
+#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b)
#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
- || is_skylake(codec) || is_broxton(codec))
+ || is_skylake(codec) || is_broxton(codec) \
+ || is_kabylake(codec))
#define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
#define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
@@ -83,6 +85,7 @@ struct hdmi_spec_per_pin {
struct mutex lock;
struct delayed_work work;
struct snd_kcontrol *eld_ctl;
+ struct snd_jack *acomp_jack; /* jack via audio component */
int repoll_count;
bool setup; /* the stream has been set up by prepare callback */
int channels; /* current number of channels */
@@ -150,8 +153,15 @@ struct hdmi_spec {
/* i915/powerwell (Haswell+/Valleyview+) specific */
struct i915_audio_component_audio_ops i915_audio_ops;
+ bool i915_bound; /* was i915 bound in this driver? */
};
+#ifdef CONFIG_SND_HDA_I915
+#define codec_has_acomp(codec) \
+ ((codec)->bus->core.audio_component != NULL)
+#else
+#define codec_has_acomp(codec) false
+#endif
struct hdmi_audio_infoframe {
u8 type; /* 0x84 */
@@ -1530,7 +1540,59 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
return 0;
}
-static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+/* update per_pin ELD from the given new ELD;
+ * setup info frame and notification accordingly
+ */
+static void update_eld(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ struct hdmi_eld *eld)
+{
+ struct hdmi_eld *pin_eld = &per_pin->sink_eld;
+ bool old_eld_valid = pin_eld->eld_valid;
+ bool eld_changed;
+
+ if (eld->eld_valid)
+ snd_hdmi_show_eld(codec, &eld->info);
+
+ eld_changed = (pin_eld->eld_valid != eld->eld_valid);
+ if (eld->eld_valid && pin_eld->eld_valid)
+ if (pin_eld->eld_size != eld->eld_size ||
+ memcmp(pin_eld->eld_buffer, eld->eld_buffer,
+ eld->eld_size) != 0)
+ eld_changed = true;
+
+ pin_eld->eld_valid = eld->eld_valid;
+ pin_eld->eld_size = eld->eld_size;
+ if (eld->eld_valid)
+ memcpy(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size);
+ pin_eld->info = eld->info;
+
+ /*
+ * Re-setup pin and infoframe. This is needed e.g. when
+ * - sink is first plugged-in
+ * - transcoder can change during stream playback on Haswell
+ * and this can make HW reset converter selection on a pin.
+ */
+ if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
+ if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
+ intel_verify_pin_cvt_connect(codec, per_pin);
+ intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+ per_pin->mux_idx);
+ }
+
+ hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+ }
+
+ if (eld_changed)
+ snd_ctl_notify(codec->card,
+ SNDRV_CTL_EVENT_MASK_VALUE |
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &per_pin->eld_ctl->id);
+}
+
+/* update ELD and jack state via HD-audio verbs */
+static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
+ int repoll)
{
struct hda_jack_tbl *jack;
struct hda_codec *codec = per_pin->codec;
@@ -1547,9 +1609,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
* the unsolicited response to avoid custom WARs.
*/
int present;
- bool update_eld = false;
- bool eld_changed = false;
bool ret;
+ bool do_repoll = false;
snd_hda_power_up_pm(codec);
present = snd_hda_pin_sense(codec, pin_nid);
@@ -1570,66 +1631,19 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
&eld->eld_size) < 0)
eld->eld_valid = false;
else {
- memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld));
if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
eld->eld_size) < 0)
eld->eld_valid = false;
}
-
- if (eld->eld_valid) {
- snd_hdmi_show_eld(codec, &eld->info);
- update_eld = true;
- }
- else if (repoll) {
- schedule_delayed_work(&per_pin->work,
- msecs_to_jiffies(300));
- goto unlock;
- }
+ if (!eld->eld_valid && repoll)
+ do_repoll = true;
}
- if (pin_eld->eld_valid != eld->eld_valid)
- eld_changed = true;
-
- if (pin_eld->eld_valid && !eld->eld_valid)
- update_eld = true;
-
- if (update_eld) {
- bool old_eld_valid = pin_eld->eld_valid;
- pin_eld->eld_valid = eld->eld_valid;
- if (pin_eld->eld_size != eld->eld_size ||
- memcmp(pin_eld->eld_buffer, eld->eld_buffer,
- eld->eld_size) != 0) {
- memcpy(pin_eld->eld_buffer, eld->eld_buffer,
- eld->eld_size);
- eld_changed = true;
- }
- pin_eld->eld_size = eld->eld_size;
- pin_eld->info = eld->info;
-
- /*
- * Re-setup pin and infoframe. This is needed e.g. when
- * - sink is first plugged-in (infoframe is not set up if !monitor_present)
- * - transcoder can change during stream playback on Haswell
- * and this can make HW reset converter selection on a pin.
- */
- if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
- if (is_haswell_plus(codec) ||
- is_valleyview_plus(codec)) {
- intel_verify_pin_cvt_connect(codec, per_pin);
- intel_not_share_assigned_cvt(codec, pin_nid,
- per_pin->mux_idx);
- }
-
- hdmi_setup_audio_infoframe(codec, per_pin,
- per_pin->non_pcm);
- }
- }
+ if (do_repoll)
+ schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300));
+ else
+ update_eld(codec, per_pin, eld);
- if (eld_changed)
- snd_ctl_notify(codec->card,
- SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
- &per_pin->eld_ctl->id);
- unlock:
ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid;
jack = snd_hda_jack_tbl_get(codec, pin_nid);
@@ -1641,6 +1655,54 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
return ret;
}
+/* update ELD and jack state via audio component */
+static void sync_eld_via_acomp(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_eld *eld = &spec->temp_eld;
+ int size;
+
+ mutex_lock(&per_pin->lock);
+ size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid,
+ &eld->monitor_present, eld->eld_buffer,
+ ELD_MAX_SIZE);
+ if (size < 0)
+ goto unlock;
+ if (size > 0) {
+ size = min(size, ELD_MAX_SIZE);
+ if (snd_hdmi_parse_eld(codec, &eld->info,
+ eld->eld_buffer, size) < 0)
+ size = -EINVAL;
+ }
+
+ if (size > 0) {
+ eld->eld_valid = true;
+ eld->eld_size = size;
+ } else {
+ eld->eld_valid = false;
+ eld->eld_size = 0;
+ }
+
+ update_eld(codec, per_pin, eld);
+ snd_jack_report(per_pin->acomp_jack,
+ eld->monitor_present ? SND_JACK_AVOUT : 0);
+ unlock:
+ mutex_unlock(&per_pin->lock);
+}
+
+static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+{
+ struct hda_codec *codec = per_pin->codec;
+
+ if (codec_has_acomp(codec)) {
+ sync_eld_via_acomp(codec, per_pin);
+ return false; /* don't call snd_hda_jack_report_sync() */
+ } else {
+ return hdmi_present_sense_via_verbs(per_pin, repoll);
+ }
+}
+
static void hdmi_repoll_eld(struct work_struct *work)
{
struct hdmi_spec_per_pin *per_pin =
@@ -1776,17 +1838,6 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
return non_pcm;
}
-/* There is a fixed mapping between audio pin node and display port
- * on current Intel platforms:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- */
-static int intel_pin2port(hda_nid_t pin_nid)
-{
- return pin_nid - 4;
-}
-
/*
* HDMI callbacks
*/
@@ -1803,7 +1854,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct i915_audio_component *acomp = codec->bus->core.audio_component;
bool non_pcm;
int pinctl;
@@ -1822,10 +1872,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
/* Todo: add DP1.2 MST audio support later */
- if (acomp && acomp->ops && acomp->ops->sync_audio_rate)
- acomp->ops->sync_audio_rate(acomp->dev,
- intel_pin2port(pin_nid),
- runtime->rate);
+ snd_hdac_sync_audio_rate(&codec->bus->core, pin_nid, runtime->rate);
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
mutex_lock(&per_pin->lock);
@@ -2091,6 +2138,30 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
return 0;
}
+static void free_acomp_jack_priv(struct snd_jack *jack)
+{
+ struct hdmi_spec_per_pin *per_pin = jack->private_data;
+
+ per_pin->acomp_jack = NULL;
+}
+
+static int add_acomp_jack_kctl(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ const char *name)
+{
+ struct snd_jack *jack;
+ int err;
+
+ err = snd_jack_new(codec->card, name, SND_JACK_AVOUT, &jack,
+ true, false);
+ if (err < 0)
+ return err;
+ per_pin->acomp_jack = jack;
+ jack->private_data = per_pin;
+ jack->private_free = free_acomp_jack_priv;
+ return 0;
+}
+
static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
{
char hdmi_str[32] = "HDMI/DP";
@@ -2101,6 +2172,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
if (pcmdev > 0)
sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+ if (codec_has_acomp(codec))
+ return add_acomp_jack_kctl(codec, per_pin, hdmi_str);
phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid);
if (phantom_jack)
strncat(hdmi_str, " Phantom",
@@ -2196,8 +2269,10 @@ static int generic_hdmi_init(struct hda_codec *codec)
hda_nid_t pin_nid = per_pin->pin_nid;
hdmi_init_pin(codec, pin_nid);
- snd_hda_jack_detect_enable_callback(codec, pin_nid,
- codec->jackpoll_interval > 0 ? jack_callback : NULL);
+ if (!codec_has_acomp(codec))
+ snd_hda_jack_detect_enable_callback(codec, pin_nid,
+ codec->jackpoll_interval > 0 ?
+ jack_callback : NULL);
}
return 0;
}
@@ -2219,7 +2294,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
struct hdmi_spec *spec = codec->spec;
int pin_idx;
- if (is_haswell_plus(codec) || is_valleyview_plus(codec))
+ if (codec_has_acomp(codec))
snd_hdac_i915_register_notifier(NULL);
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
@@ -2227,8 +2302,12 @@ static void generic_hdmi_free(struct hda_codec *codec)
cancel_delayed_work_sync(&per_pin->work);
eld_proc_free(per_pin);
+ if (per_pin->acomp_jack)
+ snd_device_free(codec->card, per_pin->acomp_jack);
}
+ if (spec->i915_bound)
+ snd_hdac_i915_exit(&codec->bus->core);
hdmi_array_free(spec);
kfree(spec);
}
@@ -2357,6 +2436,9 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
*/
if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
return;
+ /* ditto during suspend/resume process itself */
+ if (atomic_read(&(codec)->core.in_pm))
+ return;
check_presence_and_report(codec, pin_nid);
}
@@ -2373,6 +2455,12 @@ static int patch_generic_hdmi(struct hda_codec *codec)
codec->spec = spec;
hdmi_array_init(spec, 4);
+ /* Try to bind with i915 for any Intel codecs (if not done yet) */
+ if (!codec_has_acomp(codec) &&
+ (codec->core.vendor_id >> 16) == 0x8086)
+ if (!snd_hdac_i915_init(&codec->bus->core))
+ spec->i915_bound = true;
+
if (is_haswell_plus(codec)) {
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
@@ -2388,7 +2476,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
is_broxton(codec))
codec->core.link_power_control = 1;
- if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
+ if (codec_has_acomp(codec)) {
codec->depop_delay = 0;
spec->i915_audio_ops.audio_ptr = codec;
spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
@@ -2396,6 +2484,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
}
if (hdmi_parse_codec(codec) < 0) {
+ if (spec->i915_bound)
+ snd_hdac_i915_exit(&codec->bus->core);
codec->spec = NULL;
kfree(spec);
return -EINVAL;
@@ -3579,6 +3669,7 @@ HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_generic_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3a89d82f8057..8143c0e24a27 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4666,6 +4666,7 @@ enum {
ALC290_FIXUP_SUBWOOFER,
ALC290_FIXUP_SUBWOOFER_HSJACK,
ALC269_FIXUP_THINKPAD_ACPI,
+ ALC269_FIXUP_DMIC_THINKPAD_ACPI,
ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC255_FIXUP_HEADSET_MODE,
@@ -5103,6 +5104,12 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = hda_fixup_thinkpad_acpi,
},
+ [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_inv_dmic,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+ },
[ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -5324,6 +5331,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
+ SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
@@ -5332,6 +5340,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
+ SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -5457,6 +5466,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+ SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5617,6 +5627,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x21, 0x02211040}),
SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60170},
+ {0x14, 0x90171130},
+ {0x21, 0x02211040}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ {0x12, 0x90a60170},
{0x14, 0x90170140},
{0x21, 0x02211050}),
SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 496dbd0ad5db..3bfdc78cbc5f 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -174,7 +174,7 @@ static int ap_cs8427_probeaddr(struct snd_i2c_bus *bus, unsigned short addr)
return -ENOENT;
}
-static struct snd_i2c_ops ap_cs8427_i2c_ops = {
+static const struct snd_i2c_ops ap_cs8427_i2c_ops = {
.sendbytes = ap_cs8427_sendbytes,
.readbytes = ap_cs8427_readbytes,
.probeaddr = ap_cs8427_probeaddr,
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 7ff7d88e46dd..7ea66ee3653f 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -38,6 +38,7 @@ config SND_SOC_TOPOLOGY
# All the supported SoCs
source "sound/soc/adi/Kconfig"
+source "sound/soc/amd/Kconfig"
source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
@@ -50,6 +51,7 @@ 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"
source "sound/soc/mediatek/Kconfig"
source "sound/soc/mxs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 8eb06db32fa0..9a30f21d16ee 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
obj-$(CONFIG_SND_SOC) += adi/
+obj-$(CONFIG_SND_SOC) += amd/
obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += jz4740/
+obj-$(CONFIG_SND_SOC) += img/
obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mediatek/
obj-$(CONFIG_SND_SOC) += mxs/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
new file mode 100644
index 000000000000..78187eb24f56
--- /dev/null
+++ b/sound/soc/amd/Kconfig
@@ -0,0 +1,4 @@
+config SND_SOC_AMD_ACP
+ tristate "AMD Audio Coprocessor support"
+ help
+ This option enables ACP DMA support on AMD platform.
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
new file mode 100644
index 000000000000..1a66ec0366b2
--- /dev/null
+++ b/sound/soc/amd/Makefile
@@ -0,0 +1,3 @@
+snd-soc-acp-pcm-objs := acp-pcm-dma.o
+
+obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
new file mode 100644
index 000000000000..3191e0a7d273
--- /dev/null
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -0,0 +1,1043 @@
+/*
+ * AMD ALSA SoC PCM Driver for ACP 2.x
+ *
+ * Copyright 2014-2015 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/soc.h>
+
+#include "acp.h"
+
+#define PLAYBACK_MIN_NUM_PERIODS 2
+#define PLAYBACK_MAX_NUM_PERIODS 2
+#define PLAYBACK_MAX_PERIOD_SIZE 16384
+#define PLAYBACK_MIN_PERIOD_SIZE 1024
+#define CAPTURE_MIN_NUM_PERIODS 2
+#define CAPTURE_MAX_NUM_PERIODS 2
+#define CAPTURE_MAX_PERIOD_SIZE 16384
+#define CAPTURE_MIN_PERIOD_SIZE 1024
+
+#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define MIN_BUFFER MAX_BUFFER
+
+static const struct snd_pcm_hardware acp_pcm_hardware_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .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 acp_pcm_hardware_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .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,
+};
+
+struct audio_drv_data {
+ struct snd_pcm_substream *play_stream;
+ struct snd_pcm_substream *capture_stream;
+ void __iomem *acp_mmio;
+};
+
+static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg)
+{
+ return readl(acp_mmio + (reg * 4));
+}
+
+static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg)
+{
+ writel(val, acp_mmio + (reg * 4));
+}
+
+/* Configure a given dma channel parameters - enable/disble,
+ * number of descriptors, priority
+ */
+static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num,
+ u16 dscr_strt_idx, u16 num_dscrs,
+ enum acp_dma_priority_level priority_level)
+{
+ u32 dma_ctrl;
+
+ /* disable the channel run field */
+ dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
+ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+ /* program a DMA channel with first descriptor to be processed. */
+ acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK
+ & dscr_strt_idx),
+ acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num);
+
+ /* program a DMA channel with the number of descriptors to be
+ * processed in the transfer
+ */
+ acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs,
+ acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num);
+
+ /* set DMA channel priority */
+ acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num);
+}
+
+/* Initialize a dma descriptor in SRAM based on descritor information passed */
+static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
+ u16 descr_idx,
+ acp_dma_dscr_transfer_t *descr_info)
+{
+ u32 sram_offset;
+
+ sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t));
+
+ /* program the source base address. */
+ acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+ acp_reg_write(descr_info->src, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+ /* program the destination base address. */
+ acp_reg_write(sram_offset + 4, acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+ acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+ /* program the number of bytes to be transferred for this descriptor. */
+ acp_reg_write(sram_offset + 8, acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+ acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+}
+
+/* Initialize the DMA descriptor information for transfer between
+ * system memory <-> ACP SRAM
+ */
+static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
+ u32 size, int direction,
+ u32 pte_offset)
+{
+ u16 i;
+ u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+ acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
+
+ for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
+ dmadscr[i].xfer_val = 0;
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
+ dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS +
+ (size / 2) - (i * (size/2));
+ dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+ + (pte_offset * SZ_4K) + (i * (size/2));
+ dmadscr[i].xfer_val |=
+ (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) |
+ (size / 2);
+ } else {
+ dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
+ dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
+ (i * (size/2));
+ dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+ + (pte_offset * SZ_4K) +
+ (i * (size/2));
+ dmadscr[i].xfer_val |=
+ BIT(22) |
+ (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
+ (size / 2);
+ }
+ config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
+ &dmadscr[i]);
+ }
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+ PLAYBACK_START_DMA_DESCR_CH12,
+ NUM_DSCRS_PER_CHANNEL,
+ ACP_DMA_PRIORITY_LEVEL_NORMAL);
+ else
+ config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM,
+ CAPTURE_START_DMA_DESCR_CH14,
+ NUM_DSCRS_PER_CHANNEL,
+ ACP_DMA_PRIORITY_LEVEL_NORMAL);
+}
+
+/* Initialize the DMA descriptor information for transfer between
+ * ACP SRAM <-> I2S
+ */
+static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
+ u32 size, int direction)
+{
+
+ u16 i;
+ u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
+ acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
+
+ for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
+ dmadscr[i].xfer_val = 0;
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i;
+ dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS +
+ (i * (size/2));
+ /* dmadscr[i].dest is unused by hardware. */
+ dmadscr[i].dest = 0;
+ dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) |
+ (size / 2);
+ } else {
+ dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
+ /* dmadscr[i].src is unused by hardware. */
+ dmadscr[i].src = 0;
+ dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS +
+ (i * (size / 2));
+ dmadscr[i].xfer_val |= BIT(22) |
+ (FROM_ACP_I2S_1 << 16) | (size / 2);
+ }
+ config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
+ &dmadscr[i]);
+ }
+ /* Configure the DMA channel with the above descriptore */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
+ PLAYBACK_START_DMA_DESCR_CH13,
+ NUM_DSCRS_PER_CHANNEL,
+ ACP_DMA_PRIORITY_LEVEL_NORMAL);
+ else
+ config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
+ CAPTURE_START_DMA_DESCR_CH15,
+ NUM_DSCRS_PER_CHANNEL,
+ ACP_DMA_PRIORITY_LEVEL_NORMAL);
+}
+
+/* Create page table entries in ACP SRAM for the allocated memory */
+static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
+ u16 num_of_pages, u32 pte_offset)
+{
+ u16 page_idx;
+ u64 addr;
+ u32 low;
+ u32 high;
+ u32 offset;
+
+ offset = ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8);
+ for (page_idx = 0; page_idx < (num_of_pages); page_idx++) {
+ /* 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);
+
+ acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+ /* Load the High address of page int ACP SRAM through SRBM */
+ acp_reg_write((offset + (page_idx * 8) + 4),
+ acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+
+ /* page enable in ACP */
+ high |= BIT(31);
+ acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+ /* Move to next physically contiguos page */
+ pg++;
+ }
+}
+
+static void config_acp_dma(void __iomem *acp_mmio,
+ struct audio_substream_data *audio_config)
+{
+ u32 pte_offset;
+
+ if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ pte_offset = ACP_PLAYBACK_PTE_OFFSET;
+ else
+ pte_offset = ACP_CAPTURE_PTE_OFFSET;
+
+ acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
+ pte_offset);
+
+ /* Configure System memory <-> ACP SRAM DMA descriptors */
+ set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
+ audio_config->direction, pte_offset);
+
+ /* Configure ACP SRAM <-> I2S DMA descriptors */
+ set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
+ audio_config->direction);
+}
+
+/* Start a given DMA channel transfer */
+static void acp_dma_start(void __iomem *acp_mmio,
+ u16 ch_num, bool is_circular)
+{
+ u32 dma_ctrl;
+
+ /* read the dma control register and disable the channel run field */
+ dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+ /* Invalidating the DAGB cache */
+ acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL);
+
+ /* configure the DMA channel and start the DMA transfer
+ * set dmachrun bit to start the transfer and enable the
+ * interrupt on completion of the dma transfer
+ */
+ dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK;
+
+ switch (ch_num) {
+ case ACP_TO_I2S_DMA_CH_NUM:
+ case ACP_TO_SYSRAM_CH_NUM:
+ case I2S_TO_ACP_DMA_CH_NUM:
+ dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+ break;
+ default:
+ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+ break;
+ }
+
+ /* enable for ACP SRAM to/from I2S DMA channel */
+ if (is_circular == true)
+ dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+ else
+ dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+
+ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+}
+
+/* Stop a given DMA channel transfer */
+static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
+{
+ u32 dma_ctrl;
+ u32 dma_ch_sts;
+ u32 count = ACP_DMA_RESET_TIME;
+
+ dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+ /* clear the dma control register fields before writing zero
+ * in reset bit
+ */
+ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
+ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+
+ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+ dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
+
+ if (dma_ch_sts & BIT(ch_num)) {
+ /* set the reset bit for this channel to stop the dma
+ * transfer
+ */
+ dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK;
+ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+ }
+
+ /* check the channel status bit for some time and return the status */
+ while (true) {
+ dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
+ if (!(dma_ch_sts & BIT(ch_num))) {
+ /* clear the reset flag after successfully stopping
+ * the dma transfer and break from the loop
+ */
+ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK;
+
+ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0
+ + ch_num);
+ break;
+ }
+ if (--count == 0) {
+ pr_err("Failed to stop ACP DMA channel : %d\n", ch_num);
+ return -ETIMEDOUT;
+ }
+ udelay(100);
+ }
+ return 0;
+}
+
+static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
+ bool power_on)
+{
+ u32 val, req_reg, sts_reg, sts_reg_mask;
+ u32 loops = 1000;
+
+ if (bank < 32) {
+ req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO;
+ sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO;
+ sts_reg_mask = 0xFFFFFFFF;
+
+ } else {
+ bank -= 32;
+ req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI;
+ sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI;
+ sts_reg_mask = 0x0000FFFF;
+ }
+
+ val = acp_reg_read(acp_mmio, req_reg);
+ if (val & (1 << bank)) {
+ /* bank is in off state */
+ if (power_on == true)
+ /* request to on */
+ val &= ~(1 << bank);
+ else
+ /* request to off */
+ return;
+ } else {
+ /* bank is in on state */
+ if (power_on == false)
+ /* request to off */
+ val |= 1 << bank;
+ else
+ /* request to on */
+ return;
+ }
+ acp_reg_write(val, acp_mmio, req_reg);
+
+ while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) {
+ if (!loops--) {
+ pr_err("ACP SRAM bank %d state change failed\n", bank);
+ break;
+ }
+ cpu_relax();
+ }
+}
+
+/* Initialize and bring ACP hardware to default state. */
+static int acp_init(void __iomem *acp_mmio)
+{
+ u16 bank;
+ u32 val, count, sram_pte_offset;
+
+ /* Assert Soft reset of ACP */
+ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+
+ val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+ acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+ count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+ while (true) {
+ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+ if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+ (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+ break;
+ if (--count == 0) {
+ pr_err("Failed to reset ACP\n");
+ return -ETIMEDOUT;
+ }
+ udelay(100);
+ }
+
+ /* Enable clock to ACP and wait until the clock is enabled */
+ val = acp_reg_read(acp_mmio, mmACP_CONTROL);
+ val = val | ACP_CONTROL__ClkEn_MASK;
+ acp_reg_write(val, acp_mmio, mmACP_CONTROL);
+
+ count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+ while (true) {
+ val = acp_reg_read(acp_mmio, mmACP_STATUS);
+ if (val & (u32) 0x1)
+ break;
+ if (--count == 0) {
+ pr_err("Failed to reset ACP\n");
+ return -ETIMEDOUT;
+ }
+ udelay(100);
+ }
+
+ /* Deassert the SOFT RESET flags */
+ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+ val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
+ acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+ /* initiailize Onion control DAGB register */
+ acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio,
+ mmACP_AXI2DAGB_ONION_CNTL);
+
+ /* initiailize Garlic control DAGB registers */
+ acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio,
+ mmACP_AXI2DAGB_GARLIC_CNTL);
+
+ sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS |
+ ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK |
+ ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK |
+ ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK;
+ acp_reg_write(sram_pte_offset, acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1);
+ acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio,
+ mmACP_DAGB_PAGE_SIZE_GRP_1);
+
+ acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio,
+ mmACP_DMA_DESC_BASE_ADDR);
+
+ /* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */
+ acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR);
+ acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK,
+ acp_mmio, mmACP_EXTERNAL_INTR_CNTL);
+
+ /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
+ * Now, turn off all of them. This can't be done in 'poweron' of
+ * ACP pm domain, as this requires ACP to be initialized.
+ */
+ for (bank = 1; bank < 48; bank++)
+ acp_set_sram_bank_state(acp_mmio, bank, false);
+
+ return 0;
+}
+
+/* Deintialize ACP */
+static int acp_deinit(void __iomem *acp_mmio)
+{
+ u32 val;
+ u32 count;
+
+ /* Assert Soft reset of ACP */
+ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+
+ val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+ acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+ count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+ while (true) {
+ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+ if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+ (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+ break;
+ if (--count == 0) {
+ pr_err("Failed to reset ACP\n");
+ return -ETIMEDOUT;
+ }
+ udelay(100);
+ }
+ /** Disable ACP clock */
+ val = acp_reg_read(acp_mmio, mmACP_CONTROL);
+ val &= ~ACP_CONTROL__ClkEn_MASK;
+ acp_reg_write(val, acp_mmio, mmACP_CONTROL);
+
+ count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+ while (true) {
+ val = acp_reg_read(acp_mmio, mmACP_STATUS);
+ if (!(val & (u32) 0x1))
+ break;
+ if (--count == 0) {
+ pr_err("Failed to reset ACP\n");
+ return -ETIMEDOUT;
+ }
+ udelay(100);
+ }
+ return 0;
+}
+
+/* ACP DMA irq handler routine for playback, capture usecases */
+static irqreturn_t dma_irq_handler(int irq, void *arg)
+{
+ u16 dscr_idx;
+ u32 intr_flag, ext_intr_status;
+ struct audio_drv_data *irq_data;
+ void __iomem *acp_mmio;
+ struct device *dev = arg;
+ bool valid_irq = false;
+
+ irq_data = dev_get_drvdata(dev);
+ acp_mmio = irq_data->acp_mmio;
+
+ ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+ intr_flag = (((ext_intr_status &
+ ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >>
+ ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT));
+
+ if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) {
+ valid_irq = true;
+ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) ==
+ PLAYBACK_START_DMA_DESCR_CH13)
+ dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+ else
+ dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
+ config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
+ 1, 0);
+ acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
+
+ snd_pcm_period_elapsed(irq_data->play_stream);
+
+ acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
+ acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+ }
+
+ if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
+ valid_irq = true;
+ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) ==
+ CAPTURE_START_DMA_DESCR_CH15)
+ dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
+ else
+ dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
+ config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
+ 1, 0);
+ acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
+
+ acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
+ acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+ }
+
+ if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
+ valid_irq = true;
+ snd_pcm_period_elapsed(irq_data->capture_stream);
+ acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
+ acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+ }
+
+ if (valid_irq)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+static int acp_dma_open(struct snd_pcm_substream *substream)
+{
+ u16 bank;
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev);
+
+ struct audio_substream_data *adata =
+ kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
+ if (adata == NULL)
+ return -ENOMEM;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = acp_pcm_hardware_playback;
+ else
+ runtime->hw = acp_pcm_hardware_capture;
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ dev_err(prtd->platform->dev, "set integer constraint failed\n");
+ return ret;
+ }
+
+ adata->acp_mmio = intr_data->acp_mmio;
+ runtime->private_data = adata;
+
+ /* Enable ACP irq, when neither playback or capture streams are
+ * active by the time when a new stream is being opened.
+ * This enablement is not required for another stream, if current
+ * stream is not closed
+ */
+ if (!intr_data->play_stream && !intr_data->capture_stream)
+ acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ intr_data->play_stream = substream;
+ for (bank = 1; bank <= 4; bank++)
+ acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+ true);
+ } else {
+ intr_data->capture_stream = substream;
+ for (bank = 5; bank <= 8; bank++)
+ acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+ true);
+ }
+
+ return 0;
+}
+
+static int acp_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int status;
+ uint64_t size;
+ struct snd_dma_buffer *dma_buffer;
+ struct page *pg;
+ struct snd_pcm_runtime *runtime;
+ struct audio_substream_data *rtd;
+
+ dma_buffer = &substream->dma_buffer;
+
+ runtime = substream->runtime;
+ rtd = runtime->private_data;
+
+ if (WARN_ON(!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 != NULL) {
+ acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
+ /* Save for runtime private data */
+ rtd->pg = pg;
+ 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;
+
+ config_acp_dma(rtd->acp_mmio, rtd);
+ status = 0;
+ } else {
+ status = -ENOMEM;
+ }
+ return status;
+}
+
+static int acp_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
+{
+ u16 dscr;
+ u32 mul, dma_config, period_bytes;
+ u32 pos = 0;
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_substream_data *rtd = runtime->private_data;
+
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13);
+
+ if (dscr == PLAYBACK_START_DMA_DESCR_CH13)
+ mul = 0;
+ else
+ mul = 1;
+ pos = (mul * period_bytes);
+ } else {
+ dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14);
+ if (dma_config != 0) {
+ dscr = acp_reg_read(rtd->acp_mmio,
+ mmACP_DMA_CUR_DSCR_14);
+ if (dscr == CAPTURE_START_DMA_DESCR_CH14)
+ mul = 1;
+ else
+ mul = 2;
+ pos = (mul * period_bytes);
+ }
+
+ if (pos >= (2 * period_bytes))
+ pos = 0;
+
+ }
+ return bytes_to_frames(runtime, pos);
+}
+
+static int acp_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static int acp_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_substream_data *rtd = runtime->private_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+ PLAYBACK_START_DMA_DESCR_CH12,
+ NUM_DSCRS_PER_CHANNEL, 0);
+ config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
+ PLAYBACK_START_DMA_DESCR_CH13,
+ NUM_DSCRS_PER_CHANNEL, 0);
+ /* Fill ACP SRAM (2 periods) with zeros from System RAM
+ * which is zero-ed in hw_params
+ */
+ acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
+
+ /* ACP SRAM (2 periods of buffer size) is intially filled with
+ * zeros. Before rendering starts, 2nd half of SRAM will be
+ * filled with valid audio data DMA'ed from first half of system
+ * RAM and 1st half of SRAM will be filled with Zeros. This is
+ * the initial scenario when redering starts from SRAM. Later
+ * on, 2nd half of system memory will be DMA'ed to 1st half of
+ * SRAM, 1st half of system memory will be DMA'ed to 2nd half of
+ * SRAM in ping-pong way till rendering stops.
+ */
+ config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+ PLAYBACK_START_DMA_DESCR_CH12,
+ 1, 0);
+ } else {
+ config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM,
+ CAPTURE_START_DMA_DESCR_CH14,
+ NUM_DSCRS_PER_CHANNEL, 0);
+ config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
+ CAPTURE_START_DMA_DESCR_CH15,
+ NUM_DSCRS_PER_CHANNEL, 0);
+ }
+ return 0;
+}
+
+static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret;
+ u32 loops = 1000;
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct audio_substream_data *rtd = runtime->private_data;
+
+ if (!rtd)
+ return -EINVAL;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ acp_dma_start(rtd->acp_mmio,
+ SYSRAM_TO_ACP_CH_NUM, false);
+ while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
+ BIT(SYSRAM_TO_ACP_CH_NUM)) {
+ if (!loops--) {
+ dev_err(prtd->platform->dev,
+ "acp dma start timeout\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ acp_dma_start(rtd->acp_mmio,
+ ACP_TO_I2S_DMA_CH_NUM, true);
+
+ } else {
+ acp_dma_start(rtd->acp_mmio,
+ I2S_TO_ACP_DMA_CH_NUM, true);
+ }
+ ret = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* Need to stop only circular DMA channels :
+ * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular
+ * channels will stopped automatically after its transfer
+ * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = acp_dma_stop(rtd->acp_mmio,
+ ACP_TO_I2S_DMA_CH_NUM);
+ else
+ ret = acp_dma_stop(rtd->acp_mmio,
+ I2S_TO_ACP_DMA_CH_NUM);
+ break;
+ default:
+ ret = -EINVAL;
+
+ }
+ return ret;
+}
+
+static int acp_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 acp_dma_close(struct snd_pcm_substream *substream)
+{
+ u16 bank;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_substream_data *rtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
+
+ kfree(rtd);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ adata->play_stream = NULL;
+ for (bank = 1; bank <= 4; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
+ false);
+ } else {
+ adata->capture_stream = NULL;
+ for (bank = 5; bank <= 8; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
+ false);
+ }
+
+ /* Disable ACP irq, when the current stream is being closed and
+ * another stream is also not active.
+ */
+ if (!adata->play_stream && !adata->capture_stream)
+ acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+
+ return 0;
+}
+
+static struct snd_pcm_ops acp_dma_ops = {
+ .open = acp_dma_open,
+ .close = acp_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = acp_dma_hw_params,
+ .hw_free = acp_dma_hw_free,
+ .trigger = acp_dma_trigger,
+ .pointer = acp_dma_pointer,
+ .mmap = acp_dma_mmap,
+ .prepare = acp_dma_prepare,
+};
+
+static struct snd_soc_platform_driver acp_asoc_platform = {
+ .ops = &acp_dma_ops,
+ .pcm_new = acp_dma_new,
+};
+
+static int acp_audio_probe(struct platform_device *pdev)
+{
+ int status;
+ struct audio_drv_data *audio_drv_data;
+ struct resource *res;
+
+ audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
+ GFP_KERNEL);
+ if (audio_drv_data == NULL)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res);
+
+ /* The following members gets populated in device 'open'
+ * function. Till then interrupts are disabled in 'acp_init'
+ * and device doesn't generate any interrupts.
+ */
+
+ audio_drv_data->play_stream = NULL;
+ audio_drv_data->capture_stream = NULL;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ return -ENODEV;
+ }
+
+ status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler,
+ 0, "ACP_IRQ", &pdev->dev);
+ if (status) {
+ dev_err(&pdev->dev, "ACP IRQ request failed\n");
+ return status;
+ }
+
+ dev_set_drvdata(&pdev->dev, audio_drv_data);
+
+ /* Initialize the ACP */
+ acp_init(audio_drv_data->acp_mmio);
+
+ status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
+ if (status != 0) {
+ dev_err(&pdev->dev, "Fail to register ALSA platform device\n");
+ return status;
+ }
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return status;
+}
+
+static int acp_audio_remove(struct platform_device *pdev)
+{
+ struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev);
+
+ acp_deinit(adata->acp_mmio);
+ snd_soc_unregister_platform(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int acp_pcm_resume(struct device *dev)
+{
+ u16 bank;
+ struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+ acp_init(adata->acp_mmio);
+
+ if (adata->play_stream && adata->play_stream->runtime) {
+ for (bank = 1; bank <= 4; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
+ true);
+ config_acp_dma(adata->acp_mmio,
+ adata->play_stream->runtime->private_data);
+ }
+ if (adata->capture_stream && adata->capture_stream->runtime) {
+ for (bank = 5; bank <= 8; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
+ true);
+ config_acp_dma(adata->acp_mmio,
+ adata->capture_stream->runtime->private_data);
+ }
+ acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+static int acp_pcm_runtime_suspend(struct device *dev)
+{
+ struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+ acp_deinit(adata->acp_mmio);
+ acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+static int acp_pcm_runtime_resume(struct device *dev)
+{
+ struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+ acp_init(adata->acp_mmio);
+ acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+static const struct dev_pm_ops acp_pm_ops = {
+ .resume = acp_pcm_resume,
+ .runtime_suspend = acp_pcm_runtime_suspend,
+ .runtime_resume = acp_pcm_runtime_resume,
+};
+
+static struct platform_driver acp_dma_driver = {
+ .probe = acp_audio_probe,
+ .remove = acp_audio_remove,
+ .driver = {
+ .name = "acp_audio_dma",
+ .pm = &acp_pm_ops,
+ },
+};
+
+module_platform_driver(acp_dma_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_DESCRIPTION("AMD ACP PCM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:acp-dma-audio");
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
new file mode 100644
index 000000000000..330832ef4e5e
--- /dev/null
+++ b/sound/soc/amd/acp.h
@@ -0,0 +1,118 @@
+#ifndef __ACP_HW_H
+#define __ACP_HW_H
+
+#include "include/acp_2_2_d.h"
+#include "include/acp_2_2_sh_mask.h"
+
+#define ACP_PAGE_SIZE_4K_ENABLE 0x02
+
+#define ACP_PLAYBACK_PTE_OFFSET 10
+#define ACP_CAPTURE_PTE_OFFSET 0
+
+#define ACP_GARLIC_CNTL_DEFAULT 0x00000FB4
+#define ACP_ONION_CNTL_DEFAULT 0x00000FB4
+
+#define ACP_PHYSICAL_BASE 0x14000
+
+/* Playback SRAM address (as a destination in dma descriptor) */
+#define ACP_SHARED_RAM_BANK_1_ADDRESS 0x4002000
+
+/* Capture SRAM address (as a source in dma descriptor) */
+#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000
+
+#define ACP_DMA_RESET_TIME 10000
+#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
+#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF
+#define ACP_DMA_COMPLETE_TIME_OUT_VALUE 0x000000FF
+
+#define ACP_SRAM_BASE_ADDRESS 0x4000000
+#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS 0x4001000
+#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET 0x1000
+#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000
+#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000
+
+#define TO_ACP_I2S_1 0x2
+#define TO_ACP_I2S_2 0x4
+#define FROM_ACP_I2S_1 0xa
+#define FROM_ACP_I2S_2 0xb
+
+#define ACP_TILE_ON_MASK 0x03
+#define ACP_TILE_OFF_MASK 0x02
+#define ACP_TILE_ON_RETAIN_REG_MASK 0x1f
+#define ACP_TILE_OFF_RETAIN_REG_MASK 0x20
+
+#define ACP_TILE_P1_MASK 0x3e
+#define ACP_TILE_P2_MASK 0x3d
+#define ACP_TILE_DSP0_MASK 0x3b
+#define ACP_TILE_DSP1_MASK 0x37
+
+#define ACP_TILE_DSP2_MASK 0x2f
+/* Playback DMA channels */
+#define SYSRAM_TO_ACP_CH_NUM 12
+#define ACP_TO_I2S_DMA_CH_NUM 13
+
+/* Capture DMA channels */
+#define ACP_TO_SYSRAM_CH_NUM 14
+#define I2S_TO_ACP_DMA_CH_NUM 15
+
+#define NUM_DSCRS_PER_CHANNEL 2
+
+#define PLAYBACK_START_DMA_DESCR_CH12 0
+#define PLAYBACK_END_DMA_DESCR_CH12 1
+#define PLAYBACK_START_DMA_DESCR_CH13 2
+#define PLAYBACK_END_DMA_DESCR_CH13 3
+
+#define CAPTURE_START_DMA_DESCR_CH14 4
+#define CAPTURE_END_DMA_DESCR_CH14 5
+#define CAPTURE_START_DMA_DESCR_CH15 6
+#define CAPTURE_END_DMA_DESCR_CH15 7
+
+enum acp_dma_priority_level {
+ /* 0x0 Specifies the DMA channel is given normal priority */
+ ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
+ /* 0x1 Specifies the DMA channel is given high priority */
+ ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1,
+ ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF
+};
+
+struct audio_substream_data {
+ struct page *pg;
+ unsigned int order;
+ u16 num_of_pages;
+ u16 direction;
+ uint64_t size;
+ void __iomem *acp_mmio;
+};
+
+enum {
+ ACP_TILE_P1 = 0,
+ ACP_TILE_P2,
+ ACP_TILE_DSP0,
+ ACP_TILE_DSP1,
+ ACP_TILE_DSP2,
+};
+
+enum {
+ ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
+ ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
+ ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
+ ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
+ ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF
+};
+
+typedef struct acp_dma_dscr_transfer {
+ /* Specifies the source memory location for the DMA data transfer. */
+ u32 src;
+ /* Specifies the destination memory location to where the data will
+ * be transferred.
+ */
+ u32 dest;
+ /* Specifies the number of bytes need to be transferred
+ * from source to destination memory.Transfer direction & IOC enable
+ */
+ u32 xfer_val;
+ /* Reserved for future use */
+ u32 reserved;
+} acp_dma_dscr_transfer_t;
+
+#endif /*__ACP_HW_H */
diff --git a/sound/soc/amd/include/acp_2_2_d.h b/sound/soc/amd/include/acp_2_2_d.h
new file mode 100644
index 000000000000..0118fe9e6a87
--- /dev/null
+++ b/sound/soc/amd/include/acp_2_2_d.h
@@ -0,0 +1,609 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 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) 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 ACP_2_2_D_H
+#define ACP_2_2_D_H
+
+#define mmACP_DMA_CNTL_0 0x5000
+#define mmACP_DMA_CNTL_1 0x5001
+#define mmACP_DMA_CNTL_2 0x5002
+#define mmACP_DMA_CNTL_3 0x5003
+#define mmACP_DMA_CNTL_4 0x5004
+#define mmACP_DMA_CNTL_5 0x5005
+#define mmACP_DMA_CNTL_6 0x5006
+#define mmACP_DMA_CNTL_7 0x5007
+#define mmACP_DMA_CNTL_8 0x5008
+#define mmACP_DMA_CNTL_9 0x5009
+#define mmACP_DMA_CNTL_10 0x500a
+#define mmACP_DMA_CNTL_11 0x500b
+#define mmACP_DMA_CNTL_12 0x500c
+#define mmACP_DMA_CNTL_13 0x500d
+#define mmACP_DMA_CNTL_14 0x500e
+#define mmACP_DMA_CNTL_15 0x500f
+#define mmACP_DMA_DSCR_STRT_IDX_0 0x5010
+#define mmACP_DMA_DSCR_STRT_IDX_1 0x5011
+#define mmACP_DMA_DSCR_STRT_IDX_2 0x5012
+#define mmACP_DMA_DSCR_STRT_IDX_3 0x5013
+#define mmACP_DMA_DSCR_STRT_IDX_4 0x5014
+#define mmACP_DMA_DSCR_STRT_IDX_5 0x5015
+#define mmACP_DMA_DSCR_STRT_IDX_6 0x5016
+#define mmACP_DMA_DSCR_STRT_IDX_7 0x5017
+#define mmACP_DMA_DSCR_STRT_IDX_8 0x5018
+#define mmACP_DMA_DSCR_STRT_IDX_9 0x5019
+#define mmACP_DMA_DSCR_STRT_IDX_10 0x501a
+#define mmACP_DMA_DSCR_STRT_IDX_11 0x501b
+#define mmACP_DMA_DSCR_STRT_IDX_12 0x501c
+#define mmACP_DMA_DSCR_STRT_IDX_13 0x501d
+#define mmACP_DMA_DSCR_STRT_IDX_14 0x501e
+#define mmACP_DMA_DSCR_STRT_IDX_15 0x501f
+#define mmACP_DMA_DSCR_CNT_0 0x5020
+#define mmACP_DMA_DSCR_CNT_1 0x5021
+#define mmACP_DMA_DSCR_CNT_2 0x5022
+#define mmACP_DMA_DSCR_CNT_3 0x5023
+#define mmACP_DMA_DSCR_CNT_4 0x5024
+#define mmACP_DMA_DSCR_CNT_5 0x5025
+#define mmACP_DMA_DSCR_CNT_6 0x5026
+#define mmACP_DMA_DSCR_CNT_7 0x5027
+#define mmACP_DMA_DSCR_CNT_8 0x5028
+#define mmACP_DMA_DSCR_CNT_9 0x5029
+#define mmACP_DMA_DSCR_CNT_10 0x502a
+#define mmACP_DMA_DSCR_CNT_11 0x502b
+#define mmACP_DMA_DSCR_CNT_12 0x502c
+#define mmACP_DMA_DSCR_CNT_13 0x502d
+#define mmACP_DMA_DSCR_CNT_14 0x502e
+#define mmACP_DMA_DSCR_CNT_15 0x502f
+#define mmACP_DMA_PRIO_0 0x5030
+#define mmACP_DMA_PRIO_1 0x5031
+#define mmACP_DMA_PRIO_2 0x5032
+#define mmACP_DMA_PRIO_3 0x5033
+#define mmACP_DMA_PRIO_4 0x5034
+#define mmACP_DMA_PRIO_5 0x5035
+#define mmACP_DMA_PRIO_6 0x5036
+#define mmACP_DMA_PRIO_7 0x5037
+#define mmACP_DMA_PRIO_8 0x5038
+#define mmACP_DMA_PRIO_9 0x5039
+#define mmACP_DMA_PRIO_10 0x503a
+#define mmACP_DMA_PRIO_11 0x503b
+#define mmACP_DMA_PRIO_12 0x503c
+#define mmACP_DMA_PRIO_13 0x503d
+#define mmACP_DMA_PRIO_14 0x503e
+#define mmACP_DMA_PRIO_15 0x503f
+#define mmACP_DMA_CUR_DSCR_0 0x5040
+#define mmACP_DMA_CUR_DSCR_1 0x5041
+#define mmACP_DMA_CUR_DSCR_2 0x5042
+#define mmACP_DMA_CUR_DSCR_3 0x5043
+#define mmACP_DMA_CUR_DSCR_4 0x5044
+#define mmACP_DMA_CUR_DSCR_5 0x5045
+#define mmACP_DMA_CUR_DSCR_6 0x5046
+#define mmACP_DMA_CUR_DSCR_7 0x5047
+#define mmACP_DMA_CUR_DSCR_8 0x5048
+#define mmACP_DMA_CUR_DSCR_9 0x5049
+#define mmACP_DMA_CUR_DSCR_10 0x504a
+#define mmACP_DMA_CUR_DSCR_11 0x504b
+#define mmACP_DMA_CUR_DSCR_12 0x504c
+#define mmACP_DMA_CUR_DSCR_13 0x504d
+#define mmACP_DMA_CUR_DSCR_14 0x504e
+#define mmACP_DMA_CUR_DSCR_15 0x504f
+#define mmACP_DMA_CUR_TRANS_CNT_0 0x5050
+#define mmACP_DMA_CUR_TRANS_CNT_1 0x5051
+#define mmACP_DMA_CUR_TRANS_CNT_2 0x5052
+#define mmACP_DMA_CUR_TRANS_CNT_3 0x5053
+#define mmACP_DMA_CUR_TRANS_CNT_4 0x5054
+#define mmACP_DMA_CUR_TRANS_CNT_5 0x5055
+#define mmACP_DMA_CUR_TRANS_CNT_6 0x5056
+#define mmACP_DMA_CUR_TRANS_CNT_7 0x5057
+#define mmACP_DMA_CUR_TRANS_CNT_8 0x5058
+#define mmACP_DMA_CUR_TRANS_CNT_9 0x5059
+#define mmACP_DMA_CUR_TRANS_CNT_10 0x505a
+#define mmACP_DMA_CUR_TRANS_CNT_11 0x505b
+#define mmACP_DMA_CUR_TRANS_CNT_12 0x505c
+#define mmACP_DMA_CUR_TRANS_CNT_13 0x505d
+#define mmACP_DMA_CUR_TRANS_CNT_14 0x505e
+#define mmACP_DMA_CUR_TRANS_CNT_15 0x505f
+#define mmACP_DMA_ERR_STS_0 0x5060
+#define mmACP_DMA_ERR_STS_1 0x5061
+#define mmACP_DMA_ERR_STS_2 0x5062
+#define mmACP_DMA_ERR_STS_3 0x5063
+#define mmACP_DMA_ERR_STS_4 0x5064
+#define mmACP_DMA_ERR_STS_5 0x5065
+#define mmACP_DMA_ERR_STS_6 0x5066
+#define mmACP_DMA_ERR_STS_7 0x5067
+#define mmACP_DMA_ERR_STS_8 0x5068
+#define mmACP_DMA_ERR_STS_9 0x5069
+#define mmACP_DMA_ERR_STS_10 0x506a
+#define mmACP_DMA_ERR_STS_11 0x506b
+#define mmACP_DMA_ERR_STS_12 0x506c
+#define mmACP_DMA_ERR_STS_13 0x506d
+#define mmACP_DMA_ERR_STS_14 0x506e
+#define mmACP_DMA_ERR_STS_15 0x506f
+#define mmACP_DMA_DESC_BASE_ADDR 0x5070
+#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x5071
+#define mmACP_DMA_CH_STS 0x5072
+#define mmACP_DMA_CH_GROUP 0x5073
+#define mmACP_DSP0_CACHE_OFFSET0 0x5078
+#define mmACP_DSP0_CACHE_SIZE0 0x5079
+#define mmACP_DSP0_CACHE_OFFSET1 0x507a
+#define mmACP_DSP0_CACHE_SIZE1 0x507b
+#define mmACP_DSP0_CACHE_OFFSET2 0x507c
+#define mmACP_DSP0_CACHE_SIZE2 0x507d
+#define mmACP_DSP0_CACHE_OFFSET3 0x507e
+#define mmACP_DSP0_CACHE_SIZE3 0x507f
+#define mmACP_DSP0_CACHE_OFFSET4 0x5080
+#define mmACP_DSP0_CACHE_SIZE4 0x5081
+#define mmACP_DSP0_CACHE_OFFSET5 0x5082
+#define mmACP_DSP0_CACHE_SIZE5 0x5083
+#define mmACP_DSP0_CACHE_OFFSET6 0x5084
+#define mmACP_DSP0_CACHE_SIZE6 0x5085
+#define mmACP_DSP0_CACHE_OFFSET7 0x5086
+#define mmACP_DSP0_CACHE_SIZE7 0x5087
+#define mmACP_DSP0_CACHE_OFFSET8 0x5088
+#define mmACP_DSP0_CACHE_SIZE8 0x5089
+#define mmACP_DSP0_NONCACHE_OFFSET0 0x508a
+#define mmACP_DSP0_NONCACHE_SIZE0 0x508b
+#define mmACP_DSP0_NONCACHE_OFFSET1 0x508c
+#define mmACP_DSP0_NONCACHE_SIZE1 0x508d
+#define mmACP_DSP0_DEBUG_PC 0x508e
+#define mmACP_DSP0_NMI_SEL 0x508f
+#define mmACP_DSP0_CLKRST_CNTL 0x5090
+#define mmACP_DSP0_RUNSTALL 0x5091
+#define mmACP_DSP0_OCD_HALT_ON_RST 0x5092
+#define mmACP_DSP0_WAIT_MODE 0x5093
+#define mmACP_DSP0_VECT_SEL 0x5094
+#define mmACP_DSP0_DEBUG_REG1 0x5095
+#define mmACP_DSP0_DEBUG_REG2 0x5096
+#define mmACP_DSP0_DEBUG_REG3 0x5097
+#define mmACP_DSP1_CACHE_OFFSET0 0x509d
+#define mmACP_DSP1_CACHE_SIZE0 0x509e
+#define mmACP_DSP1_CACHE_OFFSET1 0x509f
+#define mmACP_DSP1_CACHE_SIZE1 0x50a0
+#define mmACP_DSP1_CACHE_OFFSET2 0x50a1
+#define mmACP_DSP1_CACHE_SIZE2 0x50a2
+#define mmACP_DSP1_CACHE_OFFSET3 0x50a3
+#define mmACP_DSP1_CACHE_SIZE3 0x50a4
+#define mmACP_DSP1_CACHE_OFFSET4 0x50a5
+#define mmACP_DSP1_CACHE_SIZE4 0x50a6
+#define mmACP_DSP1_CACHE_OFFSET5 0x50a7
+#define mmACP_DSP1_CACHE_SIZE5 0x50a8
+#define mmACP_DSP1_CACHE_OFFSET6 0x50a9
+#define mmACP_DSP1_CACHE_SIZE6 0x50aa
+#define mmACP_DSP1_CACHE_OFFSET7 0x50ab
+#define mmACP_DSP1_CACHE_SIZE7 0x50ac
+#define mmACP_DSP1_CACHE_OFFSET8 0x50ad
+#define mmACP_DSP1_CACHE_SIZE8 0x50ae
+#define mmACP_DSP1_NONCACHE_OFFSET0 0x50af
+#define mmACP_DSP1_NONCACHE_SIZE0 0x50b0
+#define mmACP_DSP1_NONCACHE_OFFSET1 0x50b1
+#define mmACP_DSP1_NONCACHE_SIZE1 0x50b2
+#define mmACP_DSP1_DEBUG_PC 0x50b3
+#define mmACP_DSP1_NMI_SEL 0x50b4
+#define mmACP_DSP1_CLKRST_CNTL 0x50b5
+#define mmACP_DSP1_RUNSTALL 0x50b6
+#define mmACP_DSP1_OCD_HALT_ON_RST 0x50b7
+#define mmACP_DSP1_WAIT_MODE 0x50b8
+#define mmACP_DSP1_VECT_SEL 0x50b9
+#define mmACP_DSP1_DEBUG_REG1 0x50ba
+#define mmACP_DSP1_DEBUG_REG2 0x50bb
+#define mmACP_DSP1_DEBUG_REG3 0x50bc
+#define mmACP_DSP2_CACHE_OFFSET0 0x50c2
+#define mmACP_DSP2_CACHE_SIZE0 0x50c3
+#define mmACP_DSP2_CACHE_OFFSET1 0x50c4
+#define mmACP_DSP2_CACHE_SIZE1 0x50c5
+#define mmACP_DSP2_CACHE_OFFSET2 0x50c6
+#define mmACP_DSP2_CACHE_SIZE2 0x50c7
+#define mmACP_DSP2_CACHE_OFFSET3 0x50c8
+#define mmACP_DSP2_CACHE_SIZE3 0x50c9
+#define mmACP_DSP2_CACHE_OFFSET4 0x50ca
+#define mmACP_DSP2_CACHE_SIZE4 0x50cb
+#define mmACP_DSP2_CACHE_OFFSET5 0x50cc
+#define mmACP_DSP2_CACHE_SIZE5 0x50cd
+#define mmACP_DSP2_CACHE_OFFSET6 0x50ce
+#define mmACP_DSP2_CACHE_SIZE6 0x50cf
+#define mmACP_DSP2_CACHE_OFFSET7 0x50d0
+#define mmACP_DSP2_CACHE_SIZE7 0x50d1
+#define mmACP_DSP2_CACHE_OFFSET8 0x50d2
+#define mmACP_DSP2_CACHE_SIZE8 0x50d3
+#define mmACP_DSP2_NONCACHE_OFFSET0 0x50d4
+#define mmACP_DSP2_NONCACHE_SIZE0 0x50d5
+#define mmACP_DSP2_NONCACHE_OFFSET1 0x50d6
+#define mmACP_DSP2_NONCACHE_SIZE1 0x50d7
+#define mmACP_DSP2_DEBUG_PC 0x50d8
+#define mmACP_DSP2_NMI_SEL 0x50d9
+#define mmACP_DSP2_CLKRST_CNTL 0x50da
+#define mmACP_DSP2_RUNSTALL 0x50db
+#define mmACP_DSP2_OCD_HALT_ON_RST 0x50dc
+#define mmACP_DSP2_WAIT_MODE 0x50dd
+#define mmACP_DSP2_VECT_SEL 0x50de
+#define mmACP_DSP2_DEBUG_REG1 0x50df
+#define mmACP_DSP2_DEBUG_REG2 0x50e0
+#define mmACP_DSP2_DEBUG_REG3 0x50e1
+#define mmACP_AXI2DAGB_ONION_CNTL 0x50e7
+#define mmACP_AXI2DAGB_ONION_ERR_STATUS_WR 0x50e8
+#define mmACP_AXI2DAGB_ONION_ERR_STATUS_RD 0x50e9
+#define mmACP_DAGB_Onion_TransPerf_Counter_Control 0x50ea
+#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Current 0x50eb
+#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Peak 0x50ec
+#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Current 0x50ed
+#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Peak 0x50ee
+#define mmACP_AXI2DAGB_GARLIC_CNTL 0x50f3
+#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_WR 0x50f4
+#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_RD 0x50f5
+#define mmACP_DAGB_Garlic_TransPerf_Counter_Control 0x50f6
+#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Current 0x50f7
+#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak 0x50f8
+#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Current 0x50f9
+#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak 0x50fa
+#define mmACP_DAGB_PAGE_SIZE_GRP_1 0x50ff
+#define mmACP_DAGB_BASE_ADDR_GRP_1 0x5100
+#define mmACP_DAGB_PAGE_SIZE_GRP_2 0x5101
+#define mmACP_DAGB_BASE_ADDR_GRP_2 0x5102
+#define mmACP_DAGB_PAGE_SIZE_GRP_3 0x5103
+#define mmACP_DAGB_BASE_ADDR_GRP_3 0x5104
+#define mmACP_DAGB_PAGE_SIZE_GRP_4 0x5105
+#define mmACP_DAGB_BASE_ADDR_GRP_4 0x5106
+#define mmACP_DAGB_PAGE_SIZE_GRP_5 0x5107
+#define mmACP_DAGB_BASE_ADDR_GRP_5 0x5108
+#define mmACP_DAGB_PAGE_SIZE_GRP_6 0x5109
+#define mmACP_DAGB_BASE_ADDR_GRP_6 0x510a
+#define mmACP_DAGB_PAGE_SIZE_GRP_7 0x510b
+#define mmACP_DAGB_BASE_ADDR_GRP_7 0x510c
+#define mmACP_DAGB_PAGE_SIZE_GRP_8 0x510d
+#define mmACP_DAGB_BASE_ADDR_GRP_8 0x510e
+#define mmACP_DAGB_ATU_CTRL 0x510f
+#define mmACP_CONTROL 0x5131
+#define mmACP_STATUS 0x5133
+#define mmACP_SOFT_RESET 0x5134
+#define mmACP_PwrMgmt_CNTL 0x5135
+#define mmACP_CAC_INDICATOR_CONTROL 0x5136
+#define mmACP_SMU_MAILBOX 0x5137
+#define mmACP_FUTURE_REG_SCLK_0 0x5138
+#define mmACP_FUTURE_REG_SCLK_1 0x5139
+#define mmACP_FUTURE_REG_SCLK_2 0x513a
+#define mmACP_FUTURE_REG_SCLK_3 0x513b
+#define mmACP_FUTURE_REG_SCLK_4 0x513c
+#define mmACP_DAGB_DEBUG_CNT_ENABLE 0x513d
+#define mmACP_DAGBG_WR_ASK_CNT 0x513e
+#define mmACP_DAGBG_WR_GO_CNT 0x513f
+#define mmACP_DAGBG_WR_EXP_RESP_CNT 0x5140
+#define mmACP_DAGBG_WR_ACTUAL_RESP_CNT 0x5141
+#define mmACP_DAGBG_RD_ASK_CNT 0x5142
+#define mmACP_DAGBG_RD_GO_CNT 0x5143
+#define mmACP_DAGBG_RD_EXP_RESP_CNT 0x5144
+#define mmACP_DAGBG_RD_ACTUAL_RESP_CNT 0x5145
+#define mmACP_DAGBO_WR_ASK_CNT 0x5146
+#define mmACP_DAGBO_WR_GO_CNT 0x5147
+#define mmACP_DAGBO_WR_EXP_RESP_CNT 0x5148
+#define mmACP_DAGBO_WR_ACTUAL_RESP_CNT 0x5149
+#define mmACP_DAGBO_RD_ASK_CNT 0x514a
+#define mmACP_DAGBO_RD_GO_CNT 0x514b
+#define mmACP_DAGBO_RD_EXP_RESP_CNT 0x514c
+#define mmACP_DAGBO_RD_ACTUAL_RESP_CNT 0x514d
+#define mmACP_BRB_CONTROL 0x5156
+#define mmACP_EXTERNAL_INTR_ENB 0x5157
+#define mmACP_EXTERNAL_INTR_CNTL 0x5158
+#define mmACP_ERROR_SOURCE_STS 0x5159
+#define mmACP_DSP_SW_INTR_TRIG 0x515a
+#define mmACP_DSP_SW_INTR_CNTL 0x515b
+#define mmACP_DAGBG_TIMEOUT_CNTL 0x515c
+#define mmACP_DAGBO_TIMEOUT_CNTL 0x515d
+#define mmACP_EXTERNAL_INTR_STAT 0x515e
+#define mmACP_DSP_SW_INTR_STAT 0x515f
+#define mmACP_DSP0_INTR_CNTL 0x5160
+#define mmACP_DSP0_INTR_STAT 0x5161
+#define mmACP_DSP0_TIMEOUT_CNTL 0x5162
+#define mmACP_DSP1_INTR_CNTL 0x5163
+#define mmACP_DSP1_INTR_STAT 0x5164
+#define mmACP_DSP1_TIMEOUT_CNTL 0x5165
+#define mmACP_DSP2_INTR_CNTL 0x5166
+#define mmACP_DSP2_INTR_STAT 0x5167
+#define mmACP_DSP2_TIMEOUT_CNTL 0x5168
+#define mmACP_DSP0_EXT_TIMER_CNTL 0x5169
+#define mmACP_DSP1_EXT_TIMER_CNTL 0x516a
+#define mmACP_DSP2_EXT_TIMER_CNTL 0x516b
+#define mmACP_AXI2DAGB_SEM_0 0x516c
+#define mmACP_AXI2DAGB_SEM_1 0x516d
+#define mmACP_AXI2DAGB_SEM_2 0x516e
+#define mmACP_AXI2DAGB_SEM_3 0x516f
+#define mmACP_AXI2DAGB_SEM_4 0x5170
+#define mmACP_AXI2DAGB_SEM_5 0x5171
+#define mmACP_AXI2DAGB_SEM_6 0x5172
+#define mmACP_AXI2DAGB_SEM_7 0x5173
+#define mmACP_AXI2DAGB_SEM_8 0x5174
+#define mmACP_AXI2DAGB_SEM_9 0x5175
+#define mmACP_AXI2DAGB_SEM_10 0x5176
+#define mmACP_AXI2DAGB_SEM_11 0x5177
+#define mmACP_AXI2DAGB_SEM_12 0x5178
+#define mmACP_AXI2DAGB_SEM_13 0x5179
+#define mmACP_AXI2DAGB_SEM_14 0x517a
+#define mmACP_AXI2DAGB_SEM_15 0x517b
+#define mmACP_AXI2DAGB_SEM_16 0x517c
+#define mmACP_AXI2DAGB_SEM_17 0x517d
+#define mmACP_AXI2DAGB_SEM_18 0x517e
+#define mmACP_AXI2DAGB_SEM_19 0x517f
+#define mmACP_AXI2DAGB_SEM_20 0x5180
+#define mmACP_AXI2DAGB_SEM_21 0x5181
+#define mmACP_AXI2DAGB_SEM_22 0x5182
+#define mmACP_AXI2DAGB_SEM_23 0x5183
+#define mmACP_AXI2DAGB_SEM_24 0x5184
+#define mmACP_AXI2DAGB_SEM_25 0x5185
+#define mmACP_AXI2DAGB_SEM_26 0x5186
+#define mmACP_AXI2DAGB_SEM_27 0x5187
+#define mmACP_AXI2DAGB_SEM_28 0x5188
+#define mmACP_AXI2DAGB_SEM_29 0x5189
+#define mmACP_AXI2DAGB_SEM_30 0x518a
+#define mmACP_AXI2DAGB_SEM_31 0x518b
+#define mmACP_AXI2DAGB_SEM_32 0x518c
+#define mmACP_AXI2DAGB_SEM_33 0x518d
+#define mmACP_AXI2DAGB_SEM_34 0x518e
+#define mmACP_AXI2DAGB_SEM_35 0x518f
+#define mmACP_AXI2DAGB_SEM_36 0x5190
+#define mmACP_AXI2DAGB_SEM_37 0x5191
+#define mmACP_AXI2DAGB_SEM_38 0x5192
+#define mmACP_AXI2DAGB_SEM_39 0x5193
+#define mmACP_AXI2DAGB_SEM_40 0x5194
+#define mmACP_AXI2DAGB_SEM_41 0x5195
+#define mmACP_AXI2DAGB_SEM_42 0x5196
+#define mmACP_AXI2DAGB_SEM_43 0x5197
+#define mmACP_AXI2DAGB_SEM_44 0x5198
+#define mmACP_AXI2DAGB_SEM_45 0x5199
+#define mmACP_AXI2DAGB_SEM_46 0x519a
+#define mmACP_AXI2DAGB_SEM_47 0x519b
+#define mmACP_SRBM_Client_Base_Addr 0x519c
+#define mmACP_SRBM_Client_RDDATA 0x519d
+#define mmACP_SRBM_Cycle_Sts 0x519e
+#define mmACP_SRBM_Targ_Idx_Addr 0x519f
+#define mmACP_SRBM_Targ_Idx_Data 0x51a0
+#define mmACP_SEMA_ADDR_LOW 0x51a1
+#define mmACP_SEMA_ADDR_HIGH 0x51a2
+#define mmACP_SEMA_CMD 0x51a3
+#define mmACP_SEMA_STS 0x51a4
+#define mmACP_SEMA_REQ 0x51a5
+#define mmACP_FW_STATUS 0x51a6
+#define mmACP_FUTURE_REG_ACLK_0 0x51a7
+#define mmACP_FUTURE_REG_ACLK_1 0x51a8
+#define mmACP_FUTURE_REG_ACLK_2 0x51a9
+#define mmACP_FUTURE_REG_ACLK_3 0x51aa
+#define mmACP_FUTURE_REG_ACLK_4 0x51ab
+#define mmACP_TIMER 0x51ac
+#define mmACP_TIMER_CNTL 0x51ad
+#define mmACP_DSP0_TIMER 0x51ae
+#define mmACP_DSP1_TIMER 0x51af
+#define mmACP_DSP2_TIMER 0x51b0
+#define mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH 0x51b1
+#define mmACP_I2S_TRANSMIT_BYTE_CNT_LOW 0x51b2
+#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH 0x51b3
+#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW 0x51b4
+#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH 0x51b5
+#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW 0x51b6
+#define mmACP_DSP0_CS_STATE 0x51b7
+#define mmACP_DSP1_CS_STATE 0x51b8
+#define mmACP_DSP2_CS_STATE 0x51b9
+#define mmACP_SCRATCH_REG_BASE_ADDR 0x51ba
+#define mmCC_ACP_EFUSE 0x51c8
+#define mmACP_PGFSM_RETAIN_REG 0x51c9
+#define mmACP_PGFSM_CONFIG_REG 0x51ca
+#define mmACP_PGFSM_WRITE_REG 0x51cb
+#define mmACP_PGFSM_READ_REG_0 0x51cc
+#define mmACP_PGFSM_READ_REG_1 0x51cd
+#define mmACP_PGFSM_READ_REG_2 0x51ce
+#define mmACP_PGFSM_READ_REG_3 0x51cf
+#define mmACP_PGFSM_READ_REG_4 0x51d0
+#define mmACP_PGFSM_READ_REG_5 0x51d1
+#define mmACP_IP_PGFSM_ENABLE 0x51d2
+#define mmACP_I2S_PIN_CONFIG 0x51d3
+#define mmACP_AZALIA_I2S_SELECT 0x51d4
+#define mmACP_CHIP_PKG_FOR_PAD_ISOLATION 0x51d5
+#define mmACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL 0x51d6
+#define mmACP_BT_UART_PAD_SEL 0x51d7
+#define mmACP_SCRATCH_REG_0 0x52c0
+#define mmACP_SCRATCH_REG_1 0x52c1
+#define mmACP_SCRATCH_REG_2 0x52c2
+#define mmACP_SCRATCH_REG_3 0x52c3
+#define mmACP_SCRATCH_REG_4 0x52c4
+#define mmACP_SCRATCH_REG_5 0x52c5
+#define mmACP_SCRATCH_REG_6 0x52c6
+#define mmACP_SCRATCH_REG_7 0x52c7
+#define mmACP_SCRATCH_REG_8 0x52c8
+#define mmACP_SCRATCH_REG_9 0x52c9
+#define mmACP_SCRATCH_REG_10 0x52ca
+#define mmACP_SCRATCH_REG_11 0x52cb
+#define mmACP_SCRATCH_REG_12 0x52cc
+#define mmACP_SCRATCH_REG_13 0x52cd
+#define mmACP_SCRATCH_REG_14 0x52ce
+#define mmACP_SCRATCH_REG_15 0x52cf
+#define mmACP_SCRATCH_REG_16 0x52d0
+#define mmACP_SCRATCH_REG_17 0x52d1
+#define mmACP_SCRATCH_REG_18 0x52d2
+#define mmACP_SCRATCH_REG_19 0x52d3
+#define mmACP_SCRATCH_REG_20 0x52d4
+#define mmACP_SCRATCH_REG_21 0x52d5
+#define mmACP_SCRATCH_REG_22 0x52d6
+#define mmACP_SCRATCH_REG_23 0x52d7
+#define mmACP_SCRATCH_REG_24 0x52d8
+#define mmACP_SCRATCH_REG_25 0x52d9
+#define mmACP_SCRATCH_REG_26 0x52da
+#define mmACP_SCRATCH_REG_27 0x52db
+#define mmACP_SCRATCH_REG_28 0x52dc
+#define mmACP_SCRATCH_REG_29 0x52dd
+#define mmACP_SCRATCH_REG_30 0x52de
+#define mmACP_SCRATCH_REG_31 0x52df
+#define mmACP_SCRATCH_REG_32 0x52e0
+#define mmACP_SCRATCH_REG_33 0x52e1
+#define mmACP_SCRATCH_REG_34 0x52e2
+#define mmACP_SCRATCH_REG_35 0x52e3
+#define mmACP_SCRATCH_REG_36 0x52e4
+#define mmACP_SCRATCH_REG_37 0x52e5
+#define mmACP_SCRATCH_REG_38 0x52e6
+#define mmACP_SCRATCH_REG_39 0x52e7
+#define mmACP_SCRATCH_REG_40 0x52e8
+#define mmACP_SCRATCH_REG_41 0x52e9
+#define mmACP_SCRATCH_REG_42 0x52ea
+#define mmACP_SCRATCH_REG_43 0x52eb
+#define mmACP_SCRATCH_REG_44 0x52ec
+#define mmACP_SCRATCH_REG_45 0x52ed
+#define mmACP_SCRATCH_REG_46 0x52ee
+#define mmACP_SCRATCH_REG_47 0x52ef
+#define mmACP_VOICE_WAKEUP_ENABLE 0x51e8
+#define mmACP_VOICE_WAKEUP_STATUS 0x51e9
+#define mmI2S_VOICE_WAKEUP_LOWER_THRESHOLD 0x51ea
+#define mmI2S_VOICE_WAKEUP_HIGHER_THRESHOLD 0x51eb
+#define mmI2S_VOICE_WAKEUP_NO_OF_SAMPLES 0x51ec
+#define mmI2S_VOICE_WAKEUP_NO_OF_PEAKS 0x51ed
+#define mmI2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS 0x51ee
+#define mmI2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION 0x51ef
+#define mmI2S_VOICE_WAKEUP_DATA_PATH_SWITCH 0x51f0
+#define mmI2S_VOICE_WAKEUP_DATA_POINTER 0x51f1
+#define mmI2S_VOICE_WAKEUP_AUTH_MATCH 0x51f2
+#define mmI2S_VOICE_WAKEUP_8KB_WRAP 0x51f3
+#define mmACP_I2S_RECEIVED_BYTE_CNT_HIGH 0x51f4
+#define mmACP_I2S_RECEIVED_BYTE_CNT_LOW 0x51f5
+#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH 0x51f6
+#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW 0x51f7
+#define mmACP_MEM_SHUT_DOWN_REQ_LO 0x51f8
+#define mmACP_MEM_SHUT_DOWN_REQ_HI 0x51f9
+#define mmACP_MEM_SHUT_DOWN_STS_LO 0x51fa
+#define mmACP_MEM_SHUT_DOWN_STS_HI 0x51fb
+#define mmACP_MEM_DEEP_SLEEP_REQ_LO 0x51fc
+#define mmACP_MEM_DEEP_SLEEP_REQ_HI 0x51fd
+#define mmACP_MEM_DEEP_SLEEP_STS_LO 0x51fe
+#define mmACP_MEM_DEEP_SLEEP_STS_HI 0x51ff
+#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO 0x5200
+#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI 0x5201
+#define mmACP_MEM_WAKEUP_FROM_SLEEP_LO 0x5202
+#define mmACP_MEM_WAKEUP_FROM_SLEEP_HI 0x5203
+#define mmACP_I2SSP_IER 0x5210
+#define mmACP_I2SSP_IRER 0x5211
+#define mmACP_I2SSP_ITER 0x5212
+#define mmACP_I2SSP_CER 0x5213
+#define mmACP_I2SSP_CCR 0x5214
+#define mmACP_I2SSP_RXFFR 0x5215
+#define mmACP_I2SSP_TXFFR 0x5216
+#define mmACP_I2SSP_LRBR0 0x5218
+#define mmACP_I2SSP_RRBR0 0x5219
+#define mmACP_I2SSP_RER0 0x521a
+#define mmACP_I2SSP_TER0 0x521b
+#define mmACP_I2SSP_RCR0 0x521c
+#define mmACP_I2SSP_TCR0 0x521d
+#define mmACP_I2SSP_ISR0 0x521e
+#define mmACP_I2SSP_IMR0 0x521f
+#define mmACP_I2SSP_ROR0 0x5220
+#define mmACP_I2SSP_TOR0 0x5221
+#define mmACP_I2SSP_RFCR0 0x5222
+#define mmACP_I2SSP_TFCR0 0x5223
+#define mmACP_I2SSP_RFF0 0x5224
+#define mmACP_I2SSP_TFF0 0x5225
+#define mmACP_I2SSP_RXDMA 0x5226
+#define mmACP_I2SSP_RRXDMA 0x5227
+#define mmACP_I2SSP_TXDMA 0x5228
+#define mmACP_I2SSP_RTXDMA 0x5229
+#define mmACP_I2SSP_COMP_PARAM_2 0x522a
+#define mmACP_I2SSP_COMP_PARAM_1 0x522b
+#define mmACP_I2SSP_COMP_VERSION 0x522c
+#define mmACP_I2SSP_COMP_TYPE 0x522d
+#define mmACP_I2SMICSP_IER 0x522e
+#define mmACP_I2SMICSP_IRER 0x522f
+#define mmACP_I2SMICSP_ITER 0x5230
+#define mmACP_I2SMICSP_CER 0x5231
+#define mmACP_I2SMICSP_CCR 0x5232
+#define mmACP_I2SMICSP_RXFFR 0x5233
+#define mmACP_I2SMICSP_TXFFR 0x5234
+#define mmACP_I2SMICSP_LRBR0 0x5236
+#define mmACP_I2SMICSP_RRBR0 0x5237
+#define mmACP_I2SMICSP_RER0 0x5238
+#define mmACP_I2SMICSP_TER0 0x5239
+#define mmACP_I2SMICSP_RCR0 0x523a
+#define mmACP_I2SMICSP_TCR0 0x523b
+#define mmACP_I2SMICSP_ISR0 0x523c
+#define mmACP_I2SMICSP_IMR0 0x523d
+#define mmACP_I2SMICSP_ROR0 0x523e
+#define mmACP_I2SMICSP_TOR0 0x523f
+#define mmACP_I2SMICSP_RFCR0 0x5240
+#define mmACP_I2SMICSP_TFCR0 0x5241
+#define mmACP_I2SMICSP_RFF0 0x5242
+#define mmACP_I2SMICSP_TFF0 0x5243
+#define mmACP_I2SMICSP_LRBR1 0x5246
+#define mmACP_I2SMICSP_RRBR1 0x5247
+#define mmACP_I2SMICSP_RER1 0x5248
+#define mmACP_I2SMICSP_TER1 0x5249
+#define mmACP_I2SMICSP_RCR1 0x524a
+#define mmACP_I2SMICSP_TCR1 0x524b
+#define mmACP_I2SMICSP_ISR1 0x524c
+#define mmACP_I2SMICSP_IMR1 0x524d
+#define mmACP_I2SMICSP_ROR1 0x524e
+#define mmACP_I2SMICSP_TOR1 0x524f
+#define mmACP_I2SMICSP_RFCR1 0x5250
+#define mmACP_I2SMICSP_TFCR1 0x5251
+#define mmACP_I2SMICSP_RFF1 0x5252
+#define mmACP_I2SMICSP_TFF1 0x5253
+#define mmACP_I2SMICSP_RXDMA 0x5254
+#define mmACP_I2SMICSP_RRXDMA 0x5255
+#define mmACP_I2SMICSP_TXDMA 0x5256
+#define mmACP_I2SMICSP_RTXDMA 0x5257
+#define mmACP_I2SMICSP_COMP_PARAM_2 0x5258
+#define mmACP_I2SMICSP_COMP_PARAM_1 0x5259
+#define mmACP_I2SMICSP_COMP_VERSION 0x525a
+#define mmACP_I2SMICSP_COMP_TYPE 0x525b
+#define mmACP_I2SBT_IER 0x525c
+#define mmACP_I2SBT_IRER 0x525d
+#define mmACP_I2SBT_ITER 0x525e
+#define mmACP_I2SBT_CER 0x525f
+#define mmACP_I2SBT_CCR 0x5260
+#define mmACP_I2SBT_RXFFR 0x5261
+#define mmACP_I2SBT_TXFFR 0x5262
+#define mmACP_I2SBT_LRBR0 0x5264
+#define mmACP_I2SBT_RRBR0 0x5265
+#define mmACP_I2SBT_RER0 0x5266
+#define mmACP_I2SBT_TER0 0x5267
+#define mmACP_I2SBT_RCR0 0x5268
+#define mmACP_I2SBT_TCR0 0x5269
+#define mmACP_I2SBT_ISR0 0x526a
+#define mmACP_I2SBT_IMR0 0x526b
+#define mmACP_I2SBT_ROR0 0x526c
+#define mmACP_I2SBT_TOR0 0x526d
+#define mmACP_I2SBT_RFCR0 0x526e
+#define mmACP_I2SBT_TFCR0 0x526f
+#define mmACP_I2SBT_RFF0 0x5270
+#define mmACP_I2SBT_TFF0 0x5271
+#define mmACP_I2SBT_LRBR1 0x5274
+#define mmACP_I2SBT_RRBR1 0x5275
+#define mmACP_I2SBT_RER1 0x5276
+#define mmACP_I2SBT_TER1 0x5277
+#define mmACP_I2SBT_RCR1 0x5278
+#define mmACP_I2SBT_TCR1 0x5279
+#define mmACP_I2SBT_ISR1 0x527a
+#define mmACP_I2SBT_IMR1 0x527b
+#define mmACP_I2SBT_ROR1 0x527c
+#define mmACP_I2SBT_TOR1 0x527d
+#define mmACP_I2SBT_RFCR1 0x527e
+#define mmACP_I2SBT_TFCR1 0x527f
+#define mmACP_I2SBT_RFF1 0x5280
+#define mmACP_I2SBT_TFF1 0x5281
+#define mmACP_I2SBT_RXDMA 0x5282
+#define mmACP_I2SBT_RRXDMA 0x5283
+#define mmACP_I2SBT_TXDMA 0x5284
+#define mmACP_I2SBT_RTXDMA 0x5285
+#define mmACP_I2SBT_COMP_PARAM_2 0x5286
+#define mmACP_I2SBT_COMP_PARAM_1 0x5287
+#define mmACP_I2SBT_COMP_VERSION 0x5288
+#define mmACP_I2SBT_COMP_TYPE 0x5289
+
+#endif /* ACP_2_2_D_H */
diff --git a/sound/soc/amd/include/acp_2_2_enum.h b/sound/soc/amd/include/acp_2_2_enum.h
new file mode 100644
index 000000000000..f3577c851086
--- /dev/null
+++ b/sound/soc/amd/include/acp_2_2_enum.h
@@ -0,0 +1,1068 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 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) 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 ACP_2_2_ENUM_H
+#define ACP_2_2_ENUM_H
+
+typedef enum DebugBlockId {
+ DBG_BLOCK_ID_RESERVED = 0x0,
+ DBG_BLOCK_ID_DBG = 0x1,
+ DBG_BLOCK_ID_VMC = 0x2,
+ DBG_BLOCK_ID_PDMA = 0x3,
+ DBG_BLOCK_ID_CG = 0x4,
+ DBG_BLOCK_ID_SRBM = 0x5,
+ DBG_BLOCK_ID_GRBM = 0x6,
+ DBG_BLOCK_ID_RLC = 0x7,
+ DBG_BLOCK_ID_CSC = 0x8,
+ DBG_BLOCK_ID_SEM = 0x9,
+ DBG_BLOCK_ID_IH = 0xa,
+ DBG_BLOCK_ID_SC = 0xb,
+ DBG_BLOCK_ID_SQ = 0xc,
+ DBG_BLOCK_ID_UVDU = 0xd,
+ DBG_BLOCK_ID_SQA = 0xe,
+ DBG_BLOCK_ID_SDMA0 = 0xf,
+ DBG_BLOCK_ID_SDMA1 = 0x10,
+ DBG_BLOCK_ID_SPIM = 0x11,
+ DBG_BLOCK_ID_GDS = 0x12,
+ DBG_BLOCK_ID_VC0 = 0x13,
+ DBG_BLOCK_ID_VC1 = 0x14,
+ DBG_BLOCK_ID_PA0 = 0x15,
+ DBG_BLOCK_ID_PA1 = 0x16,
+ DBG_BLOCK_ID_CP0 = 0x17,
+ DBG_BLOCK_ID_CP1 = 0x18,
+ DBG_BLOCK_ID_CP2 = 0x19,
+ DBG_BLOCK_ID_XBR = 0x1a,
+ DBG_BLOCK_ID_UVDM = 0x1b,
+ DBG_BLOCK_ID_VGT0 = 0x1c,
+ DBG_BLOCK_ID_VGT1 = 0x1d,
+ DBG_BLOCK_ID_IA = 0x1e,
+ DBG_BLOCK_ID_SXM0 = 0x1f,
+ DBG_BLOCK_ID_SXM1 = 0x20,
+ DBG_BLOCK_ID_SCT0 = 0x21,
+ DBG_BLOCK_ID_SCT1 = 0x22,
+ DBG_BLOCK_ID_SPM0 = 0x23,
+ DBG_BLOCK_ID_SPM1 = 0x24,
+ DBG_BLOCK_ID_UNUSED0 = 0x25,
+ DBG_BLOCK_ID_UNUSED1 = 0x26,
+ DBG_BLOCK_ID_TCAA = 0x27,
+ DBG_BLOCK_ID_TCAB = 0x28,
+ DBG_BLOCK_ID_TCCA = 0x29,
+ DBG_BLOCK_ID_TCCB = 0x2a,
+ DBG_BLOCK_ID_MCC0 = 0x2b,
+ DBG_BLOCK_ID_MCC1 = 0x2c,
+ DBG_BLOCK_ID_MCC2 = 0x2d,
+ DBG_BLOCK_ID_MCC3 = 0x2e,
+ DBG_BLOCK_ID_SXS0 = 0x2f,
+ DBG_BLOCK_ID_SXS1 = 0x30,
+ DBG_BLOCK_ID_SXS2 = 0x31,
+ DBG_BLOCK_ID_SXS3 = 0x32,
+ DBG_BLOCK_ID_SXS4 = 0x33,
+ DBG_BLOCK_ID_SXS5 = 0x34,
+ DBG_BLOCK_ID_SXS6 = 0x35,
+ DBG_BLOCK_ID_SXS7 = 0x36,
+ DBG_BLOCK_ID_SXS8 = 0x37,
+ DBG_BLOCK_ID_SXS9 = 0x38,
+ DBG_BLOCK_ID_BCI0 = 0x39,
+ DBG_BLOCK_ID_BCI1 = 0x3a,
+ DBG_BLOCK_ID_BCI2 = 0x3b,
+ DBG_BLOCK_ID_BCI3 = 0x3c,
+ DBG_BLOCK_ID_MCB = 0x3d,
+ DBG_BLOCK_ID_UNUSED6 = 0x3e,
+ DBG_BLOCK_ID_SQA00 = 0x3f,
+ DBG_BLOCK_ID_SQA01 = 0x40,
+ DBG_BLOCK_ID_SQA02 = 0x41,
+ DBG_BLOCK_ID_SQA10 = 0x42,
+ DBG_BLOCK_ID_SQA11 = 0x43,
+ DBG_BLOCK_ID_SQA12 = 0x44,
+ DBG_BLOCK_ID_UNUSED7 = 0x45,
+ DBG_BLOCK_ID_UNUSED8 = 0x46,
+ DBG_BLOCK_ID_SQB00 = 0x47,
+ DBG_BLOCK_ID_SQB01 = 0x48,
+ DBG_BLOCK_ID_SQB10 = 0x49,
+ DBG_BLOCK_ID_SQB11 = 0x4a,
+ DBG_BLOCK_ID_SQ00 = 0x4b,
+ DBG_BLOCK_ID_SQ01 = 0x4c,
+ DBG_BLOCK_ID_SQ10 = 0x4d,
+ DBG_BLOCK_ID_SQ11 = 0x4e,
+ DBG_BLOCK_ID_CB00 = 0x4f,
+ DBG_BLOCK_ID_CB01 = 0x50,
+ DBG_BLOCK_ID_CB02 = 0x51,
+ DBG_BLOCK_ID_CB03 = 0x52,
+ DBG_BLOCK_ID_CB04 = 0x53,
+ DBG_BLOCK_ID_UNUSED9 = 0x54,
+ DBG_BLOCK_ID_UNUSED10 = 0x55,
+ DBG_BLOCK_ID_UNUSED11 = 0x56,
+ DBG_BLOCK_ID_CB10 = 0x57,
+ DBG_BLOCK_ID_CB11 = 0x58,
+ DBG_BLOCK_ID_CB12 = 0x59,
+ DBG_BLOCK_ID_CB13 = 0x5a,
+ DBG_BLOCK_ID_CB14 = 0x5b,
+ DBG_BLOCK_ID_UNUSED12 = 0x5c,
+ DBG_BLOCK_ID_UNUSED13 = 0x5d,
+ DBG_BLOCK_ID_UNUSED14 = 0x5e,
+ DBG_BLOCK_ID_TCP0 = 0x5f,
+ DBG_BLOCK_ID_TCP1 = 0x60,
+ DBG_BLOCK_ID_TCP2 = 0x61,
+ DBG_BLOCK_ID_TCP3 = 0x62,
+ DBG_BLOCK_ID_TCP4 = 0x63,
+ DBG_BLOCK_ID_TCP5 = 0x64,
+ DBG_BLOCK_ID_TCP6 = 0x65,
+ DBG_BLOCK_ID_TCP7 = 0x66,
+ DBG_BLOCK_ID_TCP8 = 0x67,
+ DBG_BLOCK_ID_TCP9 = 0x68,
+ DBG_BLOCK_ID_TCP10 = 0x69,
+ DBG_BLOCK_ID_TCP11 = 0x6a,
+ DBG_BLOCK_ID_TCP12 = 0x6b,
+ DBG_BLOCK_ID_TCP13 = 0x6c,
+ DBG_BLOCK_ID_TCP14 = 0x6d,
+ DBG_BLOCK_ID_TCP15 = 0x6e,
+ DBG_BLOCK_ID_TCP16 = 0x6f,
+ DBG_BLOCK_ID_TCP17 = 0x70,
+ DBG_BLOCK_ID_TCP18 = 0x71,
+ DBG_BLOCK_ID_TCP19 = 0x72,
+ DBG_BLOCK_ID_TCP20 = 0x73,
+ DBG_BLOCK_ID_TCP21 = 0x74,
+ DBG_BLOCK_ID_TCP22 = 0x75,
+ DBG_BLOCK_ID_TCP23 = 0x76,
+ DBG_BLOCK_ID_TCP_RESERVED0 = 0x77,
+ DBG_BLOCK_ID_TCP_RESERVED1 = 0x78,
+ DBG_BLOCK_ID_TCP_RESERVED2 = 0x79,
+ DBG_BLOCK_ID_TCP_RESERVED3 = 0x7a,
+ DBG_BLOCK_ID_TCP_RESERVED4 = 0x7b,
+ DBG_BLOCK_ID_TCP_RESERVED5 = 0x7c,
+ DBG_BLOCK_ID_TCP_RESERVED6 = 0x7d,
+ DBG_BLOCK_ID_TCP_RESERVED7 = 0x7e,
+ DBG_BLOCK_ID_DB00 = 0x7f,
+ DBG_BLOCK_ID_DB01 = 0x80,
+ DBG_BLOCK_ID_DB02 = 0x81,
+ DBG_BLOCK_ID_DB03 = 0x82,
+ DBG_BLOCK_ID_DB04 = 0x83,
+ DBG_BLOCK_ID_UNUSED15 = 0x84,
+ DBG_BLOCK_ID_UNUSED16 = 0x85,
+ DBG_BLOCK_ID_UNUSED17 = 0x86,
+ DBG_BLOCK_ID_DB10 = 0x87,
+ DBG_BLOCK_ID_DB11 = 0x88,
+ DBG_BLOCK_ID_DB12 = 0x89,
+ DBG_BLOCK_ID_DB13 = 0x8a,
+ DBG_BLOCK_ID_DB14 = 0x8b,
+ DBG_BLOCK_ID_UNUSED18 = 0x8c,
+ DBG_BLOCK_ID_UNUSED19 = 0x8d,
+ DBG_BLOCK_ID_UNUSED20 = 0x8e,
+ DBG_BLOCK_ID_TCC0 = 0x8f,
+ DBG_BLOCK_ID_TCC1 = 0x90,
+ DBG_BLOCK_ID_TCC2 = 0x91,
+ DBG_BLOCK_ID_TCC3 = 0x92,
+ DBG_BLOCK_ID_TCC4 = 0x93,
+ DBG_BLOCK_ID_TCC5 = 0x94,
+ DBG_BLOCK_ID_TCC6 = 0x95,
+ DBG_BLOCK_ID_TCC7 = 0x96,
+ DBG_BLOCK_ID_SPS00 = 0x97,
+ DBG_BLOCK_ID_SPS01 = 0x98,
+ DBG_BLOCK_ID_SPS02 = 0x99,
+ DBG_BLOCK_ID_SPS10 = 0x9a,
+ DBG_BLOCK_ID_SPS11 = 0x9b,
+ DBG_BLOCK_ID_SPS12 = 0x9c,
+ DBG_BLOCK_ID_UNUSED21 = 0x9d,
+ DBG_BLOCK_ID_UNUSED22 = 0x9e,
+ DBG_BLOCK_ID_TA00 = 0x9f,
+ DBG_BLOCK_ID_TA01 = 0xa0,
+ DBG_BLOCK_ID_TA02 = 0xa1,
+ DBG_BLOCK_ID_TA03 = 0xa2,
+ DBG_BLOCK_ID_TA04 = 0xa3,
+ DBG_BLOCK_ID_TA05 = 0xa4,
+ DBG_BLOCK_ID_TA06 = 0xa5,
+ DBG_BLOCK_ID_TA07 = 0xa6,
+ DBG_BLOCK_ID_TA08 = 0xa7,
+ DBG_BLOCK_ID_TA09 = 0xa8,
+ DBG_BLOCK_ID_TA0A = 0xa9,
+ DBG_BLOCK_ID_TA0B = 0xaa,
+ DBG_BLOCK_ID_UNUSED23 = 0xab,
+ DBG_BLOCK_ID_UNUSED24 = 0xac,
+ DBG_BLOCK_ID_UNUSED25 = 0xad,
+ DBG_BLOCK_ID_UNUSED26 = 0xae,
+ DBG_BLOCK_ID_TA10 = 0xaf,
+ DBG_BLOCK_ID_TA11 = 0xb0,
+ DBG_BLOCK_ID_TA12 = 0xb1,
+ DBG_BLOCK_ID_TA13 = 0xb2,
+ DBG_BLOCK_ID_TA14 = 0xb3,
+ DBG_BLOCK_ID_TA15 = 0xb4,
+ DBG_BLOCK_ID_TA16 = 0xb5,
+ DBG_BLOCK_ID_TA17 = 0xb6,
+ DBG_BLOCK_ID_TA18 = 0xb7,
+ DBG_BLOCK_ID_TA19 = 0xb8,
+ DBG_BLOCK_ID_TA1A = 0xb9,
+ DBG_BLOCK_ID_TA1B = 0xba,
+ DBG_BLOCK_ID_UNUSED27 = 0xbb,
+ DBG_BLOCK_ID_UNUSED28 = 0xbc,
+ DBG_BLOCK_ID_UNUSED29 = 0xbd,
+ DBG_BLOCK_ID_UNUSED30 = 0xbe,
+ DBG_BLOCK_ID_TD00 = 0xbf,
+ DBG_BLOCK_ID_TD01 = 0xc0,
+ DBG_BLOCK_ID_TD02 = 0xc1,
+ DBG_BLOCK_ID_TD03 = 0xc2,
+ DBG_BLOCK_ID_TD04 = 0xc3,
+ DBG_BLOCK_ID_TD05 = 0xc4,
+ DBG_BLOCK_ID_TD06 = 0xc5,
+ DBG_BLOCK_ID_TD07 = 0xc6,
+ DBG_BLOCK_ID_TD08 = 0xc7,
+ DBG_BLOCK_ID_TD09 = 0xc8,
+ DBG_BLOCK_ID_TD0A = 0xc9,
+ DBG_BLOCK_ID_TD0B = 0xca,
+ DBG_BLOCK_ID_UNUSED31 = 0xcb,
+ DBG_BLOCK_ID_UNUSED32 = 0xcc,
+ DBG_BLOCK_ID_UNUSED33 = 0xcd,
+ DBG_BLOCK_ID_UNUSED34 = 0xce,
+ DBG_BLOCK_ID_TD10 = 0xcf,
+ DBG_BLOCK_ID_TD11 = 0xd0,
+ DBG_BLOCK_ID_TD12 = 0xd1,
+ DBG_BLOCK_ID_TD13 = 0xd2,
+ DBG_BLOCK_ID_TD14 = 0xd3,
+ DBG_BLOCK_ID_TD15 = 0xd4,
+ DBG_BLOCK_ID_TD16 = 0xd5,
+ DBG_BLOCK_ID_TD17 = 0xd6,
+ DBG_BLOCK_ID_TD18 = 0xd7,
+ DBG_BLOCK_ID_TD19 = 0xd8,
+ DBG_BLOCK_ID_TD1A = 0xd9,
+ DBG_BLOCK_ID_TD1B = 0xda,
+ DBG_BLOCK_ID_UNUSED35 = 0xdb,
+ DBG_BLOCK_ID_UNUSED36 = 0xdc,
+ DBG_BLOCK_ID_UNUSED37 = 0xdd,
+ DBG_BLOCK_ID_UNUSED38 = 0xde,
+ DBG_BLOCK_ID_LDS00 = 0xdf,
+ DBG_BLOCK_ID_LDS01 = 0xe0,
+ DBG_BLOCK_ID_LDS02 = 0xe1,
+ DBG_BLOCK_ID_LDS03 = 0xe2,
+ DBG_BLOCK_ID_LDS04 = 0xe3,
+ DBG_BLOCK_ID_LDS05 = 0xe4,
+ DBG_BLOCK_ID_LDS06 = 0xe5,
+ DBG_BLOCK_ID_LDS07 = 0xe6,
+ DBG_BLOCK_ID_LDS08 = 0xe7,
+ DBG_BLOCK_ID_LDS09 = 0xe8,
+ DBG_BLOCK_ID_LDS0A = 0xe9,
+ DBG_BLOCK_ID_LDS0B = 0xea,
+ DBG_BLOCK_ID_UNUSED39 = 0xeb,
+ DBG_BLOCK_ID_UNUSED40 = 0xec,
+ DBG_BLOCK_ID_UNUSED41 = 0xed,
+ DBG_BLOCK_ID_UNUSED42 = 0xee,
+ DBG_BLOCK_ID_LDS10 = 0xef,
+ DBG_BLOCK_ID_LDS11 = 0xf0,
+ DBG_BLOCK_ID_LDS12 = 0xf1,
+ DBG_BLOCK_ID_LDS13 = 0xf2,
+ DBG_BLOCK_ID_LDS14 = 0xf3,
+ DBG_BLOCK_ID_LDS15 = 0xf4,
+ DBG_BLOCK_ID_LDS16 = 0xf5,
+ DBG_BLOCK_ID_LDS17 = 0xf6,
+ DBG_BLOCK_ID_LDS18 = 0xf7,
+ DBG_BLOCK_ID_LDS19 = 0xf8,
+ DBG_BLOCK_ID_LDS1A = 0xf9,
+ DBG_BLOCK_ID_LDS1B = 0xfa,
+ DBG_BLOCK_ID_UNUSED43 = 0xfb,
+ DBG_BLOCK_ID_UNUSED44 = 0xfc,
+ DBG_BLOCK_ID_UNUSED45 = 0xfd,
+ DBG_BLOCK_ID_UNUSED46 = 0xfe,
+} DebugBlockId;
+typedef enum DebugBlockId_BY2 {
+ DBG_BLOCK_ID_RESERVED_BY2 = 0x0,
+ DBG_BLOCK_ID_VMC_BY2 = 0x1,
+ DBG_BLOCK_ID_UNUSED0_BY2 = 0x2,
+ DBG_BLOCK_ID_GRBM_BY2 = 0x3,
+ DBG_BLOCK_ID_CSC_BY2 = 0x4,
+ DBG_BLOCK_ID_IH_BY2 = 0x5,
+ DBG_BLOCK_ID_SQ_BY2 = 0x6,
+ DBG_BLOCK_ID_UVD_BY2 = 0x7,
+ DBG_BLOCK_ID_SDMA0_BY2 = 0x8,
+ DBG_BLOCK_ID_SPIM_BY2 = 0x9,
+ DBG_BLOCK_ID_VC0_BY2 = 0xa,
+ DBG_BLOCK_ID_PA_BY2 = 0xb,
+ DBG_BLOCK_ID_CP0_BY2 = 0xc,
+ DBG_BLOCK_ID_CP2_BY2 = 0xd,
+ DBG_BLOCK_ID_PC0_BY2 = 0xe,
+ DBG_BLOCK_ID_BCI0_BY2 = 0xf,
+ DBG_BLOCK_ID_SXM0_BY2 = 0x10,
+ DBG_BLOCK_ID_SCT0_BY2 = 0x11,
+ DBG_BLOCK_ID_SPM0_BY2 = 0x12,
+ DBG_BLOCK_ID_BCI2_BY2 = 0x13,
+ DBG_BLOCK_ID_TCA_BY2 = 0x14,
+ DBG_BLOCK_ID_TCCA_BY2 = 0x15,
+ DBG_BLOCK_ID_MCC_BY2 = 0x16,
+ DBG_BLOCK_ID_MCC2_BY2 = 0x17,
+ DBG_BLOCK_ID_MCD_BY2 = 0x18,
+ DBG_BLOCK_ID_MCD2_BY2 = 0x19,
+ DBG_BLOCK_ID_MCD4_BY2 = 0x1a,
+ DBG_BLOCK_ID_MCB_BY2 = 0x1b,
+ DBG_BLOCK_ID_SQA_BY2 = 0x1c,
+ DBG_BLOCK_ID_SQA02_BY2 = 0x1d,
+ DBG_BLOCK_ID_SQA11_BY2 = 0x1e,
+ DBG_BLOCK_ID_UNUSED8_BY2 = 0x1f,
+ DBG_BLOCK_ID_SQB_BY2 = 0x20,
+ DBG_BLOCK_ID_SQB10_BY2 = 0x21,
+ DBG_BLOCK_ID_UNUSED10_BY2 = 0x22,
+ DBG_BLOCK_ID_UNUSED12_BY2 = 0x23,
+ DBG_BLOCK_ID_CB_BY2 = 0x24,
+ DBG_BLOCK_ID_CB02_BY2 = 0x25,
+ DBG_BLOCK_ID_CB10_BY2 = 0x26,
+ DBG_BLOCK_ID_CB12_BY2 = 0x27,
+ DBG_BLOCK_ID_SXS_BY2 = 0x28,
+ DBG_BLOCK_ID_SXS2_BY2 = 0x29,
+ DBG_BLOCK_ID_SXS4_BY2 = 0x2a,
+ DBG_BLOCK_ID_SXS6_BY2 = 0x2b,
+ DBG_BLOCK_ID_DB_BY2 = 0x2c,
+ DBG_BLOCK_ID_DB02_BY2 = 0x2d,
+ DBG_BLOCK_ID_DB10_BY2 = 0x2e,
+ DBG_BLOCK_ID_DB12_BY2 = 0x2f,
+ DBG_BLOCK_ID_TCP_BY2 = 0x30,
+ DBG_BLOCK_ID_TCP2_BY2 = 0x31,
+ DBG_BLOCK_ID_TCP4_BY2 = 0x32,
+ DBG_BLOCK_ID_TCP6_BY2 = 0x33,
+ DBG_BLOCK_ID_TCP8_BY2 = 0x34,
+ DBG_BLOCK_ID_TCP10_BY2 = 0x35,
+ DBG_BLOCK_ID_TCP12_BY2 = 0x36,
+ DBG_BLOCK_ID_TCP14_BY2 = 0x37,
+ DBG_BLOCK_ID_TCP16_BY2 = 0x38,
+ DBG_BLOCK_ID_TCP18_BY2 = 0x39,
+ DBG_BLOCK_ID_TCP20_BY2 = 0x3a,
+ DBG_BLOCK_ID_TCP22_BY2 = 0x3b,
+ DBG_BLOCK_ID_TCP_RESERVED0_BY2 = 0x3c,
+ DBG_BLOCK_ID_TCP_RESERVED2_BY2 = 0x3d,
+ DBG_BLOCK_ID_TCP_RESERVED4_BY2 = 0x3e,
+ DBG_BLOCK_ID_TCP_RESERVED6_BY2 = 0x3f,
+ DBG_BLOCK_ID_TCC_BY2 = 0x40,
+ DBG_BLOCK_ID_TCC2_BY2 = 0x41,
+ DBG_BLOCK_ID_TCC4_BY2 = 0x42,
+ DBG_BLOCK_ID_TCC6_BY2 = 0x43,
+ DBG_BLOCK_ID_SPS_BY2 = 0x44,
+ DBG_BLOCK_ID_SPS02_BY2 = 0x45,
+ DBG_BLOCK_ID_SPS11_BY2 = 0x46,
+ DBG_BLOCK_ID_UNUSED14_BY2 = 0x47,
+ DBG_BLOCK_ID_TA_BY2 = 0x48,
+ DBG_BLOCK_ID_TA02_BY2 = 0x49,
+ DBG_BLOCK_ID_TA04_BY2 = 0x4a,
+ DBG_BLOCK_ID_TA06_BY2 = 0x4b,
+ DBG_BLOCK_ID_TA08_BY2 = 0x4c,
+ DBG_BLOCK_ID_TA0A_BY2 = 0x4d,
+ DBG_BLOCK_ID_UNUSED20_BY2 = 0x4e,
+ DBG_BLOCK_ID_UNUSED22_BY2 = 0x4f,
+ DBG_BLOCK_ID_TA10_BY2 = 0x50,
+ DBG_BLOCK_ID_TA12_BY2 = 0x51,
+ DBG_BLOCK_ID_TA14_BY2 = 0x52,
+ DBG_BLOCK_ID_TA16_BY2 = 0x53,
+ DBG_BLOCK_ID_TA18_BY2 = 0x54,
+ DBG_BLOCK_ID_TA1A_BY2 = 0x55,
+ DBG_BLOCK_ID_UNUSED24_BY2 = 0x56,
+ DBG_BLOCK_ID_UNUSED26_BY2 = 0x57,
+ DBG_BLOCK_ID_TD_BY2 = 0x58,
+ DBG_BLOCK_ID_TD02_BY2 = 0x59,
+ DBG_BLOCK_ID_TD04_BY2 = 0x5a,
+ DBG_BLOCK_ID_TD06_BY2 = 0x5b,
+ DBG_BLOCK_ID_TD08_BY2 = 0x5c,
+ DBG_BLOCK_ID_TD0A_BY2 = 0x5d,
+ DBG_BLOCK_ID_UNUSED28_BY2 = 0x5e,
+ DBG_BLOCK_ID_UNUSED30_BY2 = 0x5f,
+ DBG_BLOCK_ID_TD10_BY2 = 0x60,
+ DBG_BLOCK_ID_TD12_BY2 = 0x61,
+ DBG_BLOCK_ID_TD14_BY2 = 0x62,
+ DBG_BLOCK_ID_TD16_BY2 = 0x63,
+ DBG_BLOCK_ID_TD18_BY2 = 0x64,
+ DBG_BLOCK_ID_TD1A_BY2 = 0x65,
+ DBG_BLOCK_ID_UNUSED32_BY2 = 0x66,
+ DBG_BLOCK_ID_UNUSED34_BY2 = 0x67,
+ DBG_BLOCK_ID_LDS_BY2 = 0x68,
+ DBG_BLOCK_ID_LDS02_BY2 = 0x69,
+ DBG_BLOCK_ID_LDS04_BY2 = 0x6a,
+ DBG_BLOCK_ID_LDS06_BY2 = 0x6b,
+ DBG_BLOCK_ID_LDS08_BY2 = 0x6c,
+ DBG_BLOCK_ID_LDS0A_BY2 = 0x6d,
+ DBG_BLOCK_ID_UNUSED36_BY2 = 0x6e,
+ DBG_BLOCK_ID_UNUSED38_BY2 = 0x6f,
+ DBG_BLOCK_ID_LDS10_BY2 = 0x70,
+ DBG_BLOCK_ID_LDS12_BY2 = 0x71,
+ DBG_BLOCK_ID_LDS14_BY2 = 0x72,
+ DBG_BLOCK_ID_LDS16_BY2 = 0x73,
+ DBG_BLOCK_ID_LDS18_BY2 = 0x74,
+ DBG_BLOCK_ID_LDS1A_BY2 = 0x75,
+ DBG_BLOCK_ID_UNUSED40_BY2 = 0x76,
+ DBG_BLOCK_ID_UNUSED42_BY2 = 0x77,
+} DebugBlockId_BY2;
+typedef enum DebugBlockId_BY4 {
+ DBG_BLOCK_ID_RESERVED_BY4 = 0x0,
+ DBG_BLOCK_ID_UNUSED0_BY4 = 0x1,
+ DBG_BLOCK_ID_CSC_BY4 = 0x2,
+ DBG_BLOCK_ID_SQ_BY4 = 0x3,
+ DBG_BLOCK_ID_SDMA0_BY4 = 0x4,
+ DBG_BLOCK_ID_VC0_BY4 = 0x5,
+ DBG_BLOCK_ID_CP0_BY4 = 0x6,
+ DBG_BLOCK_ID_UNUSED1_BY4 = 0x7,
+ DBG_BLOCK_ID_SXM0_BY4 = 0x8,
+ DBG_BLOCK_ID_SPM0_BY4 = 0x9,
+ DBG_BLOCK_ID_TCAA_BY4 = 0xa,
+ DBG_BLOCK_ID_MCC_BY4 = 0xb,
+ DBG_BLOCK_ID_MCD_BY4 = 0xc,
+ DBG_BLOCK_ID_MCD4_BY4 = 0xd,
+ DBG_BLOCK_ID_SQA_BY4 = 0xe,
+ DBG_BLOCK_ID_SQA11_BY4 = 0xf,
+ DBG_BLOCK_ID_SQB_BY4 = 0x10,
+ DBG_BLOCK_ID_UNUSED10_BY4 = 0x11,
+ DBG_BLOCK_ID_CB_BY4 = 0x12,
+ DBG_BLOCK_ID_CB10_BY4 = 0x13,
+ DBG_BLOCK_ID_SXS_BY4 = 0x14,
+ DBG_BLOCK_ID_SXS4_BY4 = 0x15,
+ DBG_BLOCK_ID_DB_BY4 = 0x16,
+ DBG_BLOCK_ID_DB10_BY4 = 0x17,
+ DBG_BLOCK_ID_TCP_BY4 = 0x18,
+ DBG_BLOCK_ID_TCP4_BY4 = 0x19,
+ DBG_BLOCK_ID_TCP8_BY4 = 0x1a,
+ DBG_BLOCK_ID_TCP12_BY4 = 0x1b,
+ DBG_BLOCK_ID_TCP16_BY4 = 0x1c,
+ DBG_BLOCK_ID_TCP20_BY4 = 0x1d,
+ DBG_BLOCK_ID_TCP_RESERVED0_BY4 = 0x1e,
+ DBG_BLOCK_ID_TCP_RESERVED4_BY4 = 0x1f,
+ DBG_BLOCK_ID_TCC_BY4 = 0x20,
+ DBG_BLOCK_ID_TCC4_BY4 = 0x21,
+ DBG_BLOCK_ID_SPS_BY4 = 0x22,
+ DBG_BLOCK_ID_SPS11_BY4 = 0x23,
+ DBG_BLOCK_ID_TA_BY4 = 0x24,
+ DBG_BLOCK_ID_TA04_BY4 = 0x25,
+ DBG_BLOCK_ID_TA08_BY4 = 0x26,
+ DBG_BLOCK_ID_UNUSED20_BY4 = 0x27,
+ DBG_BLOCK_ID_TA10_BY4 = 0x28,
+ DBG_BLOCK_ID_TA14_BY4 = 0x29,
+ DBG_BLOCK_ID_TA18_BY4 = 0x2a,
+ DBG_BLOCK_ID_UNUSED24_BY4 = 0x2b,
+ DBG_BLOCK_ID_TD_BY4 = 0x2c,
+ DBG_BLOCK_ID_TD04_BY4 = 0x2d,
+ DBG_BLOCK_ID_TD08_BY4 = 0x2e,
+ DBG_BLOCK_ID_UNUSED28_BY4 = 0x2f,
+ DBG_BLOCK_ID_TD10_BY4 = 0x30,
+ DBG_BLOCK_ID_TD14_BY4 = 0x31,
+ DBG_BLOCK_ID_TD18_BY4 = 0x32,
+ DBG_BLOCK_ID_UNUSED32_BY4 = 0x33,
+ DBG_BLOCK_ID_LDS_BY4 = 0x34,
+ DBG_BLOCK_ID_LDS04_BY4 = 0x35,
+ DBG_BLOCK_ID_LDS08_BY4 = 0x36,
+ DBG_BLOCK_ID_UNUSED36_BY4 = 0x37,
+ DBG_BLOCK_ID_LDS10_BY4 = 0x38,
+ DBG_BLOCK_ID_LDS14_BY4 = 0x39,
+ DBG_BLOCK_ID_LDS18_BY4 = 0x3a,
+ DBG_BLOCK_ID_UNUSED40_BY4 = 0x3b,
+} DebugBlockId_BY4;
+typedef enum DebugBlockId_BY8 {
+ DBG_BLOCK_ID_RESERVED_BY8 = 0x0,
+ DBG_BLOCK_ID_CSC_BY8 = 0x1,
+ DBG_BLOCK_ID_SDMA0_BY8 = 0x2,
+ DBG_BLOCK_ID_CP0_BY8 = 0x3,
+ DBG_BLOCK_ID_SXM0_BY8 = 0x4,
+ DBG_BLOCK_ID_TCA_BY8 = 0x5,
+ DBG_BLOCK_ID_MCD_BY8 = 0x6,
+ DBG_BLOCK_ID_SQA_BY8 = 0x7,
+ DBG_BLOCK_ID_SQB_BY8 = 0x8,
+ DBG_BLOCK_ID_CB_BY8 = 0x9,
+ DBG_BLOCK_ID_SXS_BY8 = 0xa,
+ DBG_BLOCK_ID_DB_BY8 = 0xb,
+ DBG_BLOCK_ID_TCP_BY8 = 0xc,
+ DBG_BLOCK_ID_TCP8_BY8 = 0xd,
+ DBG_BLOCK_ID_TCP16_BY8 = 0xe,
+ DBG_BLOCK_ID_TCP_RESERVED0_BY8 = 0xf,
+ DBG_BLOCK_ID_TCC_BY8 = 0x10,
+ DBG_BLOCK_ID_SPS_BY8 = 0x11,
+ DBG_BLOCK_ID_TA_BY8 = 0x12,
+ DBG_BLOCK_ID_TA08_BY8 = 0x13,
+ DBG_BLOCK_ID_TA10_BY8 = 0x14,
+ DBG_BLOCK_ID_TA18_BY8 = 0x15,
+ DBG_BLOCK_ID_TD_BY8 = 0x16,
+ DBG_BLOCK_ID_TD08_BY8 = 0x17,
+ DBG_BLOCK_ID_TD10_BY8 = 0x18,
+ DBG_BLOCK_ID_TD18_BY8 = 0x19,
+ DBG_BLOCK_ID_LDS_BY8 = 0x1a,
+ DBG_BLOCK_ID_LDS08_BY8 = 0x1b,
+ DBG_BLOCK_ID_LDS10_BY8 = 0x1c,
+ DBG_BLOCK_ID_LDS18_BY8 = 0x1d,
+} DebugBlockId_BY8;
+typedef enum DebugBlockId_BY16 {
+ DBG_BLOCK_ID_RESERVED_BY16 = 0x0,
+ DBG_BLOCK_ID_SDMA0_BY16 = 0x1,
+ DBG_BLOCK_ID_SXM_BY16 = 0x2,
+ DBG_BLOCK_ID_MCD_BY16 = 0x3,
+ DBG_BLOCK_ID_SQB_BY16 = 0x4,
+ DBG_BLOCK_ID_SXS_BY16 = 0x5,
+ DBG_BLOCK_ID_TCP_BY16 = 0x6,
+ DBG_BLOCK_ID_TCP16_BY16 = 0x7,
+ DBG_BLOCK_ID_TCC_BY16 = 0x8,
+ DBG_BLOCK_ID_TA_BY16 = 0x9,
+ DBG_BLOCK_ID_TA10_BY16 = 0xa,
+ DBG_BLOCK_ID_TD_BY16 = 0xb,
+ DBG_BLOCK_ID_TD10_BY16 = 0xc,
+ DBG_BLOCK_ID_LDS_BY16 = 0xd,
+ DBG_BLOCK_ID_LDS10_BY16 = 0xe,
+} DebugBlockId_BY16;
+typedef enum SurfaceEndian {
+ ENDIAN_NONE = 0x0,
+ ENDIAN_8IN16 = 0x1,
+ ENDIAN_8IN32 = 0x2,
+ ENDIAN_8IN64 = 0x3,
+} SurfaceEndian;
+typedef enum ArrayMode {
+ ARRAY_LINEAR_GENERAL = 0x0,
+ ARRAY_LINEAR_ALIGNED = 0x1,
+ ARRAY_1D_TILED_THIN1 = 0x2,
+ ARRAY_1D_TILED_THICK = 0x3,
+ ARRAY_2D_TILED_THIN1 = 0x4,
+ ARRAY_PRT_TILED_THIN1 = 0x5,
+ ARRAY_PRT_2D_TILED_THIN1 = 0x6,
+ ARRAY_2D_TILED_THICK = 0x7,
+ ARRAY_2D_TILED_XTHICK = 0x8,
+ ARRAY_PRT_TILED_THICK = 0x9,
+ ARRAY_PRT_2D_TILED_THICK = 0xa,
+ ARRAY_PRT_3D_TILED_THIN1 = 0xb,
+ ARRAY_3D_TILED_THIN1 = 0xc,
+ ARRAY_3D_TILED_THICK = 0xd,
+ ARRAY_3D_TILED_XTHICK = 0xe,
+ ARRAY_PRT_3D_TILED_THICK = 0xf,
+} ArrayMode;
+typedef enum PipeTiling {
+ CONFIG_1_PIPE = 0x0,
+ CONFIG_2_PIPE = 0x1,
+ CONFIG_4_PIPE = 0x2,
+ CONFIG_8_PIPE = 0x3,
+} PipeTiling;
+typedef enum BankTiling {
+ CONFIG_4_BANK = 0x0,
+ CONFIG_8_BANK = 0x1,
+} BankTiling;
+typedef enum GroupInterleave {
+ CONFIG_256B_GROUP = 0x0,
+ CONFIG_512B_GROUP = 0x1,
+} GroupInterleave;
+typedef enum RowTiling {
+ CONFIG_1KB_ROW = 0x0,
+ CONFIG_2KB_ROW = 0x1,
+ CONFIG_4KB_ROW = 0x2,
+ CONFIG_8KB_ROW = 0x3,
+ CONFIG_1KB_ROW_OPT = 0x4,
+ CONFIG_2KB_ROW_OPT = 0x5,
+ CONFIG_4KB_ROW_OPT = 0x6,
+ CONFIG_8KB_ROW_OPT = 0x7,
+} RowTiling;
+typedef enum BankSwapBytes {
+ CONFIG_128B_SWAPS = 0x0,
+ CONFIG_256B_SWAPS = 0x1,
+ CONFIG_512B_SWAPS = 0x2,
+ CONFIG_1KB_SWAPS = 0x3,
+} BankSwapBytes;
+typedef enum SampleSplitBytes {
+ CONFIG_1KB_SPLIT = 0x0,
+ CONFIG_2KB_SPLIT = 0x1,
+ CONFIG_4KB_SPLIT = 0x2,
+ CONFIG_8KB_SPLIT = 0x3,
+} SampleSplitBytes;
+typedef enum NumPipes {
+ ADDR_CONFIG_1_PIPE = 0x0,
+ ADDR_CONFIG_2_PIPE = 0x1,
+ ADDR_CONFIG_4_PIPE = 0x2,
+ ADDR_CONFIG_8_PIPE = 0x3,
+} NumPipes;
+typedef enum PipeInterleaveSize {
+ ADDR_CONFIG_PIPE_INTERLEAVE_256B = 0x0,
+ ADDR_CONFIG_PIPE_INTERLEAVE_512B = 0x1,
+} PipeInterleaveSize;
+typedef enum BankInterleaveSize {
+ ADDR_CONFIG_BANK_INTERLEAVE_1 = 0x0,
+ ADDR_CONFIG_BANK_INTERLEAVE_2 = 0x1,
+ ADDR_CONFIG_BANK_INTERLEAVE_4 = 0x2,
+ ADDR_CONFIG_BANK_INTERLEAVE_8 = 0x3,
+} BankInterleaveSize;
+typedef enum NumShaderEngines {
+ ADDR_CONFIG_1_SHADER_ENGINE = 0x0,
+ ADDR_CONFIG_2_SHADER_ENGINE = 0x1,
+} NumShaderEngines;
+typedef enum ShaderEngineTileSize {
+ ADDR_CONFIG_SE_TILE_16 = 0x0,
+ ADDR_CONFIG_SE_TILE_32 = 0x1,
+} ShaderEngineTileSize;
+typedef enum NumGPUs {
+ ADDR_CONFIG_1_GPU = 0x0,
+ ADDR_CONFIG_2_GPU = 0x1,
+ ADDR_CONFIG_4_GPU = 0x2,
+} NumGPUs;
+typedef enum MultiGPUTileSize {
+ ADDR_CONFIG_GPU_TILE_16 = 0x0,
+ ADDR_CONFIG_GPU_TILE_32 = 0x1,
+ ADDR_CONFIG_GPU_TILE_64 = 0x2,
+ ADDR_CONFIG_GPU_TILE_128 = 0x3,
+} MultiGPUTileSize;
+typedef enum RowSize {
+ ADDR_CONFIG_1KB_ROW = 0x0,
+ ADDR_CONFIG_2KB_ROW = 0x1,
+ ADDR_CONFIG_4KB_ROW = 0x2,
+} RowSize;
+typedef enum NumLowerPipes {
+ ADDR_CONFIG_1_LOWER_PIPES = 0x0,
+ ADDR_CONFIG_2_LOWER_PIPES = 0x1,
+} NumLowerPipes;
+typedef enum ColorTransform {
+ DCC_CT_AUTO = 0x0,
+ DCC_CT_NONE = 0x1,
+ ABGR_TO_A_BG_G_RB = 0x2,
+ BGRA_TO_BG_G_RB_A = 0x3,
+} ColorTransform;
+typedef enum CompareRef {
+ REF_NEVER = 0x0,
+ REF_LESS = 0x1,
+ REF_EQUAL = 0x2,
+ REF_LEQUAL = 0x3,
+ REF_GREATER = 0x4,
+ REF_NOTEQUAL = 0x5,
+ REF_GEQUAL = 0x6,
+ REF_ALWAYS = 0x7,
+} CompareRef;
+typedef enum ReadSize {
+ READ_256_BITS = 0x0,
+ READ_512_BITS = 0x1,
+} ReadSize;
+typedef enum DepthFormat {
+ DEPTH_INVALID = 0x0,
+ DEPTH_16 = 0x1,
+ DEPTH_X8_24 = 0x2,
+ DEPTH_8_24 = 0x3,
+ DEPTH_X8_24_FLOAT = 0x4,
+ DEPTH_8_24_FLOAT = 0x5,
+ DEPTH_32_FLOAT = 0x6,
+ DEPTH_X24_8_32_FLOAT = 0x7,
+} DepthFormat;
+typedef enum ZFormat {
+ Z_INVALID = 0x0,
+ Z_16 = 0x1,
+ Z_24 = 0x2,
+ Z_32_FLOAT = 0x3,
+} ZFormat;
+typedef enum StencilFormat {
+ STENCIL_INVALID = 0x0,
+ STENCIL_8 = 0x1,
+} StencilFormat;
+typedef enum CmaskMode {
+ CMASK_CLEAR_NONE = 0x0,
+ CMASK_CLEAR_ONE = 0x1,
+ CMASK_CLEAR_ALL = 0x2,
+ CMASK_ANY_EXPANDED = 0x3,
+ CMASK_ALPHA0_FRAG1 = 0x4,
+ CMASK_ALPHA0_FRAG2 = 0x5,
+ CMASK_ALPHA0_FRAG4 = 0x6,
+ CMASK_ALPHA0_FRAGS = 0x7,
+ CMASK_ALPHA1_FRAG1 = 0x8,
+ CMASK_ALPHA1_FRAG2 = 0x9,
+ CMASK_ALPHA1_FRAG4 = 0xa,
+ CMASK_ALPHA1_FRAGS = 0xb,
+ CMASK_ALPHAX_FRAG1 = 0xc,
+ CMASK_ALPHAX_FRAG2 = 0xd,
+ CMASK_ALPHAX_FRAG4 = 0xe,
+ CMASK_ALPHAX_FRAGS = 0xf,
+} CmaskMode;
+typedef enum QuadExportFormat {
+ EXPORT_UNUSED = 0x0,
+ EXPORT_32_R = 0x1,
+ EXPORT_32_GR = 0x2,
+ EXPORT_32_AR = 0x3,
+ EXPORT_FP16_ABGR = 0x4,
+ EXPORT_UNSIGNED16_ABGR = 0x5,
+ EXPORT_SIGNED16_ABGR = 0x6,
+ EXPORT_32_ABGR = 0x7,
+} QuadExportFormat;
+typedef enum QuadExportFormatOld {
+ EXPORT_4P_32BPC_ABGR = 0x0,
+ EXPORT_4P_16BPC_ABGR = 0x1,
+ EXPORT_4P_32BPC_GR = 0x2,
+ EXPORT_4P_32BPC_AR = 0x3,
+ EXPORT_2P_32BPC_ABGR = 0x4,
+ EXPORT_8P_32BPC_R = 0x5,
+} QuadExportFormatOld;
+typedef enum ColorFormat {
+ COLOR_INVALID = 0x0,
+ COLOR_8 = 0x1,
+ COLOR_16 = 0x2,
+ COLOR_8_8 = 0x3,
+ COLOR_32 = 0x4,
+ COLOR_16_16 = 0x5,
+ COLOR_10_11_11 = 0x6,
+ COLOR_11_11_10 = 0x7,
+ COLOR_10_10_10_2 = 0x8,
+ COLOR_2_10_10_10 = 0x9,
+ COLOR_8_8_8_8 = 0xa,
+ COLOR_32_32 = 0xb,
+ COLOR_16_16_16_16 = 0xc,
+ COLOR_RESERVED_13 = 0xd,
+ COLOR_32_32_32_32 = 0xe,
+ COLOR_RESERVED_15 = 0xf,
+ COLOR_5_6_5 = 0x10,
+ COLOR_1_5_5_5 = 0x11,
+ COLOR_5_5_5_1 = 0x12,
+ COLOR_4_4_4_4 = 0x13,
+ COLOR_8_24 = 0x14,
+ COLOR_24_8 = 0x15,
+ COLOR_X24_8_32_FLOAT = 0x16,
+ COLOR_RESERVED_23 = 0x17,
+} ColorFormat;
+typedef enum SurfaceFormat {
+ FMT_INVALID = 0x0,
+ FMT_8 = 0x1,
+ FMT_16 = 0x2,
+ FMT_8_8 = 0x3,
+ FMT_32 = 0x4,
+ FMT_16_16 = 0x5,
+ FMT_10_11_11 = 0x6,
+ FMT_11_11_10 = 0x7,
+ FMT_10_10_10_2 = 0x8,
+ FMT_2_10_10_10 = 0x9,
+ FMT_8_8_8_8 = 0xa,
+ FMT_32_32 = 0xb,
+ FMT_16_16_16_16 = 0xc,
+ FMT_32_32_32 = 0xd,
+ FMT_32_32_32_32 = 0xe,
+ FMT_RESERVED_4 = 0xf,
+ FMT_5_6_5 = 0x10,
+ FMT_1_5_5_5 = 0x11,
+ FMT_5_5_5_1 = 0x12,
+ FMT_4_4_4_4 = 0x13,
+ FMT_8_24 = 0x14,
+ FMT_24_8 = 0x15,
+ FMT_X24_8_32_FLOAT = 0x16,
+ FMT_RESERVED_33 = 0x17,
+ FMT_11_11_10_FLOAT = 0x18,
+ FMT_16_FLOAT = 0x19,
+ FMT_32_FLOAT = 0x1a,
+ FMT_16_16_FLOAT = 0x1b,
+ FMT_8_24_FLOAT = 0x1c,
+ FMT_24_8_FLOAT = 0x1d,
+ FMT_32_32_FLOAT = 0x1e,
+ FMT_10_11_11_FLOAT = 0x1f,
+ FMT_16_16_16_16_FLOAT = 0x20,
+ FMT_3_3_2 = 0x21,
+ FMT_6_5_5 = 0x22,
+ FMT_32_32_32_32_FLOAT = 0x23,
+ FMT_RESERVED_36 = 0x24,
+ FMT_1 = 0x25,
+ FMT_1_REVERSED = 0x26,
+ FMT_GB_GR = 0x27,
+ FMT_BG_RG = 0x28,
+ FMT_32_AS_8 = 0x29,
+ FMT_32_AS_8_8 = 0x2a,
+ FMT_5_9_9_9_SHAREDEXP = 0x2b,
+ FMT_8_8_8 = 0x2c,
+ FMT_16_16_16 = 0x2d,
+ FMT_16_16_16_FLOAT = 0x2e,
+ FMT_4_4 = 0x2f,
+ FMT_32_32_32_FLOAT = 0x30,
+ FMT_BC1 = 0x31,
+ FMT_BC2 = 0x32,
+ FMT_BC3 = 0x33,
+ FMT_BC4 = 0x34,
+ FMT_BC5 = 0x35,
+ FMT_BC6 = 0x36,
+ FMT_BC7 = 0x37,
+ FMT_32_AS_32_32_32_32 = 0x38,
+ FMT_APC3 = 0x39,
+ FMT_APC4 = 0x3a,
+ FMT_APC5 = 0x3b,
+ FMT_APC6 = 0x3c,
+ FMT_APC7 = 0x3d,
+ FMT_CTX1 = 0x3e,
+ FMT_RESERVED_63 = 0x3f,
+} SurfaceFormat;
+typedef enum BUF_DATA_FORMAT {
+ BUF_DATA_FORMAT_INVALID = 0x0,
+ BUF_DATA_FORMAT_8 = 0x1,
+ BUF_DATA_FORMAT_16 = 0x2,
+ BUF_DATA_FORMAT_8_8 = 0x3,
+ BUF_DATA_FORMAT_32 = 0x4,
+ BUF_DATA_FORMAT_16_16 = 0x5,
+ BUF_DATA_FORMAT_10_11_11 = 0x6,
+ BUF_DATA_FORMAT_11_11_10 = 0x7,
+ BUF_DATA_FORMAT_10_10_10_2 = 0x8,
+ BUF_DATA_FORMAT_2_10_10_10 = 0x9,
+ BUF_DATA_FORMAT_8_8_8_8 = 0xa,
+ BUF_DATA_FORMAT_32_32 = 0xb,
+ BUF_DATA_FORMAT_16_16_16_16 = 0xc,
+ BUF_DATA_FORMAT_32_32_32 = 0xd,
+ BUF_DATA_FORMAT_32_32_32_32 = 0xe,
+ BUF_DATA_FORMAT_RESERVED_15 = 0xf,
+} BUF_DATA_FORMAT;
+typedef enum IMG_DATA_FORMAT {
+ IMG_DATA_FORMAT_INVALID = 0x0,
+ IMG_DATA_FORMAT_8 = 0x1,
+ IMG_DATA_FORMAT_16 = 0x2,
+ IMG_DATA_FORMAT_8_8 = 0x3,
+ IMG_DATA_FORMAT_32 = 0x4,
+ IMG_DATA_FORMAT_16_16 = 0x5,
+ IMG_DATA_FORMAT_10_11_11 = 0x6,
+ IMG_DATA_FORMAT_11_11_10 = 0x7,
+ IMG_DATA_FORMAT_10_10_10_2 = 0x8,
+ IMG_DATA_FORMAT_2_10_10_10 = 0x9,
+ IMG_DATA_FORMAT_8_8_8_8 = 0xa,
+ IMG_DATA_FORMAT_32_32 = 0xb,
+ IMG_DATA_FORMAT_16_16_16_16 = 0xc,
+ IMG_DATA_FORMAT_32_32_32 = 0xd,
+ IMG_DATA_FORMAT_32_32_32_32 = 0xe,
+ IMG_DATA_FORMAT_RESERVED_15 = 0xf,
+ IMG_DATA_FORMAT_5_6_5 = 0x10,
+ IMG_DATA_FORMAT_1_5_5_5 = 0x11,
+ IMG_DATA_FORMAT_5_5_5_1 = 0x12,
+ IMG_DATA_FORMAT_4_4_4_4 = 0x13,
+ IMG_DATA_FORMAT_8_24 = 0x14,
+ IMG_DATA_FORMAT_24_8 = 0x15,
+ IMG_DATA_FORMAT_X24_8_32 = 0x16,
+ IMG_DATA_FORMAT_RESERVED_23 = 0x17,
+ IMG_DATA_FORMAT_RESERVED_24 = 0x18,
+ IMG_DATA_FORMAT_RESERVED_25 = 0x19,
+ IMG_DATA_FORMAT_RESERVED_26 = 0x1a,
+ IMG_DATA_FORMAT_RESERVED_27 = 0x1b,
+ IMG_DATA_FORMAT_RESERVED_28 = 0x1c,
+ IMG_DATA_FORMAT_RESERVED_29 = 0x1d,
+ IMG_DATA_FORMAT_RESERVED_30 = 0x1e,
+ IMG_DATA_FORMAT_RESERVED_31 = 0x1f,
+ IMG_DATA_FORMAT_GB_GR = 0x20,
+ IMG_DATA_FORMAT_BG_RG = 0x21,
+ IMG_DATA_FORMAT_5_9_9_9 = 0x22,
+ IMG_DATA_FORMAT_BC1 = 0x23,
+ IMG_DATA_FORMAT_BC2 = 0x24,
+ IMG_DATA_FORMAT_BC3 = 0x25,
+ IMG_DATA_FORMAT_BC4 = 0x26,
+ IMG_DATA_FORMAT_BC5 = 0x27,
+ IMG_DATA_FORMAT_BC6 = 0x28,
+ IMG_DATA_FORMAT_BC7 = 0x29,
+ IMG_DATA_FORMAT_RESERVED_42 = 0x2a,
+ IMG_DATA_FORMAT_RESERVED_43 = 0x2b,
+ IMG_DATA_FORMAT_FMASK8_S2_F1 = 0x2c,
+ IMG_DATA_FORMAT_FMASK8_S4_F1 = 0x2d,
+ IMG_DATA_FORMAT_FMASK8_S8_F1 = 0x2e,
+ IMG_DATA_FORMAT_FMASK8_S2_F2 = 0x2f,
+ IMG_DATA_FORMAT_FMASK8_S4_F2 = 0x30,
+ IMG_DATA_FORMAT_FMASK8_S4_F4 = 0x31,
+ IMG_DATA_FORMAT_FMASK16_S16_F1 = 0x32,
+ IMG_DATA_FORMAT_FMASK16_S8_F2 = 0x33,
+ IMG_DATA_FORMAT_FMASK32_S16_F2 = 0x34,
+ IMG_DATA_FORMAT_FMASK32_S8_F4 = 0x35,
+ IMG_DATA_FORMAT_FMASK32_S8_F8 = 0x36,
+ IMG_DATA_FORMAT_FMASK64_S16_F4 = 0x37,
+ IMG_DATA_FORMAT_FMASK64_S16_F8 = 0x38,
+ IMG_DATA_FORMAT_4_4 = 0x39,
+ IMG_DATA_FORMAT_6_5_5 = 0x3a,
+ IMG_DATA_FORMAT_1 = 0x3b,
+ IMG_DATA_FORMAT_1_REVERSED = 0x3c,
+ IMG_DATA_FORMAT_32_AS_8 = 0x3d,
+ IMG_DATA_FORMAT_32_AS_8_8 = 0x3e,
+ IMG_DATA_FORMAT_32_AS_32_32_32_32 = 0x3f,
+} IMG_DATA_FORMAT;
+typedef enum BUF_NUM_FORMAT {
+ BUF_NUM_FORMAT_UNORM = 0x0,
+ BUF_NUM_FORMAT_SNORM = 0x1,
+ BUF_NUM_FORMAT_USCALED = 0x2,
+ BUF_NUM_FORMAT_SSCALED = 0x3,
+ BUF_NUM_FORMAT_UINT = 0x4,
+ BUF_NUM_FORMAT_SINT = 0x5,
+ BUF_NUM_FORMAT_RESERVED_6 = 0x6,
+ BUF_NUM_FORMAT_FLOAT = 0x7,
+} BUF_NUM_FORMAT;
+typedef enum IMG_NUM_FORMAT {
+ IMG_NUM_FORMAT_UNORM = 0x0,
+ IMG_NUM_FORMAT_SNORM = 0x1,
+ IMG_NUM_FORMAT_USCALED = 0x2,
+ IMG_NUM_FORMAT_SSCALED = 0x3,
+ IMG_NUM_FORMAT_UINT = 0x4,
+ IMG_NUM_FORMAT_SINT = 0x5,
+ IMG_NUM_FORMAT_RESERVED_6 = 0x6,
+ IMG_NUM_FORMAT_FLOAT = 0x7,
+ IMG_NUM_FORMAT_RESERVED_8 = 0x8,
+ IMG_NUM_FORMAT_SRGB = 0x9,
+ IMG_NUM_FORMAT_RESERVED_10 = 0xa,
+ IMG_NUM_FORMAT_RESERVED_11 = 0xb,
+ IMG_NUM_FORMAT_RESERVED_12 = 0xc,
+ IMG_NUM_FORMAT_RESERVED_13 = 0xd,
+ IMG_NUM_FORMAT_RESERVED_14 = 0xe,
+ IMG_NUM_FORMAT_RESERVED_15 = 0xf,
+} IMG_NUM_FORMAT;
+typedef enum TileType {
+ ARRAY_COLOR_TILE = 0x0,
+ ARRAY_DEPTH_TILE = 0x1,
+} TileType;
+typedef enum NonDispTilingOrder {
+ ADDR_SURF_MICRO_TILING_DISPLAY = 0x0,
+ ADDR_SURF_MICRO_TILING_NON_DISPLAY = 0x1,
+} NonDispTilingOrder;
+typedef enum MicroTileMode {
+ ADDR_SURF_DISPLAY_MICRO_TILING = 0x0,
+ ADDR_SURF_THIN_MICRO_TILING = 0x1,
+ ADDR_SURF_DEPTH_MICRO_TILING = 0x2,
+ ADDR_SURF_ROTATED_MICRO_TILING = 0x3,
+ ADDR_SURF_THICK_MICRO_TILING = 0x4,
+} MicroTileMode;
+typedef enum TileSplit {
+ ADDR_SURF_TILE_SPLIT_64B = 0x0,
+ ADDR_SURF_TILE_SPLIT_128B = 0x1,
+ ADDR_SURF_TILE_SPLIT_256B = 0x2,
+ ADDR_SURF_TILE_SPLIT_512B = 0x3,
+ ADDR_SURF_TILE_SPLIT_1KB = 0x4,
+ ADDR_SURF_TILE_SPLIT_2KB = 0x5,
+ ADDR_SURF_TILE_SPLIT_4KB = 0x6,
+} TileSplit;
+typedef enum SampleSplit {
+ ADDR_SURF_SAMPLE_SPLIT_1 = 0x0,
+ ADDR_SURF_SAMPLE_SPLIT_2 = 0x1,
+ ADDR_SURF_SAMPLE_SPLIT_4 = 0x2,
+ ADDR_SURF_SAMPLE_SPLIT_8 = 0x3,
+} SampleSplit;
+typedef enum PipeConfig {
+ ADDR_SURF_P2 = 0x0,
+ ADDR_SURF_P2_RESERVED0 = 0x1,
+ ADDR_SURF_P2_RESERVED1 = 0x2,
+ ADDR_SURF_P2_RESERVED2 = 0x3,
+ ADDR_SURF_P4_8x16 = 0x4,
+ ADDR_SURF_P4_16x16 = 0x5,
+ ADDR_SURF_P4_16x32 = 0x6,
+ ADDR_SURF_P4_32x32 = 0x7,
+ ADDR_SURF_P8_16x16_8x16 = 0x8,
+ ADDR_SURF_P8_16x32_8x16 = 0x9,
+ ADDR_SURF_P8_32x32_8x16 = 0xa,
+ ADDR_SURF_P8_16x32_16x16 = 0xb,
+ ADDR_SURF_P8_32x32_16x16 = 0xc,
+ ADDR_SURF_P8_32x32_16x32 = 0xd,
+ ADDR_SURF_P8_32x64_32x32 = 0xe,
+ ADDR_SURF_P8_RESERVED0 = 0xf,
+ ADDR_SURF_P16_32x32_8x16 = 0x10,
+ ADDR_SURF_P16_32x32_16x16 = 0x11,
+} PipeConfig;
+typedef enum NumBanks {
+ ADDR_SURF_2_BANK = 0x0,
+ ADDR_SURF_4_BANK = 0x1,
+ ADDR_SURF_8_BANK = 0x2,
+ ADDR_SURF_16_BANK = 0x3,
+} NumBanks;
+typedef enum BankWidth {
+ ADDR_SURF_BANK_WIDTH_1 = 0x0,
+ ADDR_SURF_BANK_WIDTH_2 = 0x1,
+ ADDR_SURF_BANK_WIDTH_4 = 0x2,
+ ADDR_SURF_BANK_WIDTH_8 = 0x3,
+} BankWidth;
+typedef enum BankHeight {
+ ADDR_SURF_BANK_HEIGHT_1 = 0x0,
+ ADDR_SURF_BANK_HEIGHT_2 = 0x1,
+ ADDR_SURF_BANK_HEIGHT_4 = 0x2,
+ ADDR_SURF_BANK_HEIGHT_8 = 0x3,
+} BankHeight;
+typedef enum BankWidthHeight {
+ ADDR_SURF_BANK_WH_1 = 0x0,
+ ADDR_SURF_BANK_WH_2 = 0x1,
+ ADDR_SURF_BANK_WH_4 = 0x2,
+ ADDR_SURF_BANK_WH_8 = 0x3,
+} BankWidthHeight;
+typedef enum MacroTileAspect {
+ ADDR_SURF_MACRO_ASPECT_1 = 0x0,
+ ADDR_SURF_MACRO_ASPECT_2 = 0x1,
+ ADDR_SURF_MACRO_ASPECT_4 = 0x2,
+ ADDR_SURF_MACRO_ASPECT_8 = 0x3,
+} MacroTileAspect;
+typedef enum GATCL1RequestType {
+ GATCL1_TYPE_NORMAL = 0x0,
+ GATCL1_TYPE_SHOOTDOWN = 0x1,
+ GATCL1_TYPE_BYPASS = 0x2,
+} GATCL1RequestType;
+typedef enum TCC_CACHE_POLICIES {
+ TCC_CACHE_POLICY_LRU = 0x0,
+ TCC_CACHE_POLICY_STREAM = 0x1,
+} TCC_CACHE_POLICIES;
+typedef enum MTYPE {
+ MTYPE_NC_NV = 0x0,
+ MTYPE_NC = 0x1,
+ MTYPE_CC = 0x2,
+ MTYPE_UC = 0x3,
+} MTYPE;
+typedef enum PERFMON_COUNTER_MODE {
+ PERFMON_COUNTER_MODE_ACCUM = 0x0,
+ PERFMON_COUNTER_MODE_ACTIVE_CYCLES = 0x1,
+ PERFMON_COUNTER_MODE_MAX = 0x2,
+ PERFMON_COUNTER_MODE_DIRTY = 0x3,
+ PERFMON_COUNTER_MODE_SAMPLE = 0x4,
+ PERFMON_COUNTER_MODE_CYCLES_SINCE_FIRST_EVENT = 0x5,
+ PERFMON_COUNTER_MODE_CYCLES_SINCE_LAST_EVENT = 0x6,
+ PERFMON_COUNTER_MODE_CYCLES_GE_HI = 0x7,
+ PERFMON_COUNTER_MODE_CYCLES_EQ_HI = 0x8,
+ PERFMON_COUNTER_MODE_INACTIVE_CYCLES = 0x9,
+ PERFMON_COUNTER_MODE_RESERVED = 0xf,
+} PERFMON_COUNTER_MODE;
+typedef enum PERFMON_SPM_MODE {
+ PERFMON_SPM_MODE_OFF = 0x0,
+ PERFMON_SPM_MODE_16BIT_CLAMP = 0x1,
+ PERFMON_SPM_MODE_16BIT_NO_CLAMP = 0x2,
+ PERFMON_SPM_MODE_32BIT_CLAMP = 0x3,
+ PERFMON_SPM_MODE_32BIT_NO_CLAMP = 0x4,
+ PERFMON_SPM_MODE_RESERVED_5 = 0x5,
+ PERFMON_SPM_MODE_RESERVED_6 = 0x6,
+ PERFMON_SPM_MODE_RESERVED_7 = 0x7,
+ PERFMON_SPM_MODE_TEST_MODE_0 = 0x8,
+ PERFMON_SPM_MODE_TEST_MODE_1 = 0x9,
+ PERFMON_SPM_MODE_TEST_MODE_2 = 0xa,
+} PERFMON_SPM_MODE;
+typedef enum SurfaceTiling {
+ ARRAY_LINEAR = 0x0,
+ ARRAY_TILED = 0x1,
+} SurfaceTiling;
+typedef enum SurfaceArray {
+ ARRAY_1D = 0x0,
+ ARRAY_2D = 0x1,
+ ARRAY_3D = 0x2,
+ ARRAY_3D_SLICE = 0x3,
+} SurfaceArray;
+typedef enum ColorArray {
+ ARRAY_2D_ALT_COLOR = 0x0,
+ ARRAY_2D_COLOR = 0x1,
+ ARRAY_3D_SLICE_COLOR = 0x3,
+} ColorArray;
+typedef enum DepthArray {
+ ARRAY_2D_ALT_DEPTH = 0x0,
+ ARRAY_2D_DEPTH = 0x1,
+} DepthArray;
+typedef enum ENUM_NUM_SIMD_PER_CU {
+ NUM_SIMD_PER_CU = 0x4,
+} ENUM_NUM_SIMD_PER_CU;
+typedef enum MEM_PWR_FORCE_CTRL {
+ NO_FORCE_REQUEST = 0x0,
+ FORCE_LIGHT_SLEEP_REQUEST = 0x1,
+ FORCE_DEEP_SLEEP_REQUEST = 0x2,
+ FORCE_SHUT_DOWN_REQUEST = 0x3,
+} MEM_PWR_FORCE_CTRL;
+typedef enum MEM_PWR_FORCE_CTRL2 {
+ NO_FORCE_REQ = 0x0,
+ FORCE_LIGHT_SLEEP_REQ = 0x1,
+} MEM_PWR_FORCE_CTRL2;
+typedef enum MEM_PWR_DIS_CTRL {
+ ENABLE_MEM_PWR_CTRL = 0x0,
+ DISABLE_MEM_PWR_CTRL = 0x1,
+} MEM_PWR_DIS_CTRL;
+typedef enum MEM_PWR_SEL_CTRL {
+ DYNAMIC_SHUT_DOWN_ENABLE = 0x0,
+ DYNAMIC_DEEP_SLEEP_ENABLE = 0x1,
+ DYNAMIC_LIGHT_SLEEP_ENABLE = 0x2,
+} MEM_PWR_SEL_CTRL;
+typedef enum MEM_PWR_SEL_CTRL2 {
+ DYNAMIC_DEEP_SLEEP_EN = 0x0,
+ DYNAMIC_LIGHT_SLEEP_EN = 0x1,
+} MEM_PWR_SEL_CTRL2;
+
+#endif /* ACP_2_2_ENUM_H */
diff --git a/sound/soc/amd/include/acp_2_2_sh_mask.h b/sound/soc/amd/include/acp_2_2_sh_mask.h
new file mode 100644
index 000000000000..32d2d4104309
--- /dev/null
+++ b/sound/soc/amd/include/acp_2_2_sh_mask.h
@@ -0,0 +1,2292 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 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) 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 ACP_2_2_SH_MASK_H
+#define ACP_2_2_SH_MASK_H
+
+#define ACP_DMA_CNTL_0__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_0__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_0__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_0__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_0__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_0__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_0__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_0__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_0__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_0__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_1__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_1__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_1__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_1__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_1__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_1__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_1__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_1__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_1__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_1__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_2__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_2__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_2__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_2__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_2__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_2__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_2__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_2__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_2__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_2__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_3__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_3__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_3__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_3__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_3__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_3__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_3__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_3__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_3__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_3__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_4__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_4__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_4__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_4__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_4__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_4__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_4__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_4__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_4__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_4__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_5__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_5__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_5__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_5__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_5__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_5__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_5__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_5__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_5__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_5__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_6__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_6__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_6__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_6__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_6__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_6__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_6__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_6__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_6__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_6__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_7__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_7__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_7__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_7__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_7__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_7__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_7__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_7__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_7__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_7__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_8__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_8__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_8__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_8__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_8__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_8__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_8__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_8__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_8__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_8__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_9__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_9__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_9__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_9__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_9__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_9__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_9__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_9__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_9__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_9__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_10__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_10__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_10__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_10__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_10__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_10__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_10__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_10__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_10__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_10__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_11__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_11__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_11__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_11__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_11__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_11__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_11__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_11__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_11__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_11__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_12__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_12__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_12__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_12__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_12__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_12__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_12__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_12__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_12__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_12__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_13__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_13__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_13__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_13__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_13__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_13__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_13__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_13__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_13__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_13__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_14__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_14__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_14__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_14__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_14__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_14__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_14__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_14__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_14__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_14__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_15__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_15__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_15__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_15__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_15__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_15__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_15__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_15__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_15__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_15__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_PRIO_0__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_0__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_1__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_1__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_2__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_2__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_3__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_3__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_4__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_4__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_5__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_5__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_6__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_6__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_7__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_7__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_8__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_8__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_9__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_9__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_10__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_10__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_11__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_11__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_12__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_12__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_13__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_13__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_14__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_14__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_15__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_15__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_ERR_STS_0__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_0__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_0__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_0__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_1__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_1__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_1__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_1__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_2__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_2__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_2__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_2__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_3__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_3__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_3__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_3__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_4__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_4__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_4__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_4__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_5__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_5__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_5__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_5__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_6__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_6__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_6__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_6__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_7__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_7__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_7__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_7__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_8__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_8__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_8__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_8__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_9__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_9__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_9__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_9__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_10__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_10__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_10__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_10__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_11__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_11__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_11__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_11__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_12__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_12__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_12__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_12__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_13__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_13__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_13__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_13__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_14__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_14__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_14__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_14__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_15__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_15__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_15__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_15__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr_MASK 0xffffffff
+#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr__SHIFT 0x0
+#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr_MASK 0xf
+#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr__SHIFT 0x0
+#define ACP_DMA_CH_STS__DMAChSts_MASK 0xffff
+#define ACP_DMA_CH_STS__DMAChSts__SHIFT 0x0
+#define ACP_DMA_CH_GROUP__DMAChanelGrouping_MASK 0x1
+#define ACP_DMA_CH_GROUP__DMAChanelGrouping__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP0_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP0_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP0_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP0_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP0_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP0_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP0_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP0_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP0_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP0_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP0_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP0_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP0_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP0_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP1_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP1_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP1_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP1_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP1_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP1_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP1_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP1_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP1_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP1_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP1_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP1_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP1_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP1_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP2_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP2_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP2_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP2_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP2_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP2_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP2_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP2_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP2_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP2_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP2_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP2_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP2_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP2_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap_MASK 0x3
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap__SHIFT 0x0
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb_MASK 0x80
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb__SHIFT 0x7
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb_MASK 0x100
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb_MASK 0x400
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode_MASK 0x2000
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode__SHIFT 0xd
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1
+#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap_MASK 0x3
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap__SHIFT 0x0
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb_MASK 0x80
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb__SHIFT 0x7
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb_MASK 0x100
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb_MASK 0x400
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode_MASK 0x2000
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode__SHIFT 0xd
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1
+#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate_MASK 0x1
+#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate__SHIFT 0x0
+#define ACP_CONTROL__ClkEn_MASK 0x1
+#define ACP_CONTROL__ClkEn__SHIFT 0x0
+#define ACP_CONTROL__JtagEn_MASK 0x400
+#define ACP_CONTROL__JtagEn__SHIFT 0xa
+#define ACP_STATUS__ClkOn_MASK 0x1
+#define ACP_STATUS__ClkOn__SHIFT 0x0
+#define ACP_STATUS__ACPRefClkSpd_MASK 0x2
+#define ACP_STATUS__ACPRefClkSpd__SHIFT 0x1
+#define ACP_STATUS__SMUStutterLastEdge_MASK 0x4
+#define ACP_STATUS__SMUStutterLastEdge__SHIFT 0x2
+#define ACP_STATUS__MCStutterLastEdge_MASK 0x8
+#define ACP_STATUS__MCStutterLastEdge__SHIFT 0x3
+#define ACP_SOFT_RESET__SoftResetAud_MASK 0x100
+#define ACP_SOFT_RESET__SoftResetAud__SHIFT 0x8
+#define ACP_SOFT_RESET__SoftResetDMA_MASK 0x200
+#define ACP_SOFT_RESET__SoftResetDMA__SHIFT 0x9
+#define ACP_SOFT_RESET__InternalSoftResetMode_MASK 0x4000
+#define ACP_SOFT_RESET__InternalSoftResetMode__SHIFT 0xe
+#define ACP_SOFT_RESET__ExternalSoftResetMode_MASK 0x8000
+#define ACP_SOFT_RESET__ExternalSoftResetMode__SHIFT 0xf
+#define ACP_SOFT_RESET__SoftResetAudDone_MASK 0x1000000
+#define ACP_SOFT_RESET__SoftResetAudDone__SHIFT 0x18
+#define ACP_SOFT_RESET__SoftResetDMADone_MASK 0x2000000
+#define ACP_SOFT_RESET__SoftResetDMADone__SHIFT 0x19
+#define ACP_PwrMgmt_CNTL__SCLKSleepCntl_MASK 0x3
+#define ACP_PwrMgmt_CNTL__SCLKSleepCntl__SHIFT 0x0
+#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter_MASK 0xffff
+#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter__SHIFT 0x0
+#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox_MASK 0xffffffff
+#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg__SHIFT 0x0
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable_MASK 0x1
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable__SHIFT 0x0
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable_MASK 0x2
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable__SHIFT 0x1
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable_MASK 0x4
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable__SHIFT 0x2
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable_MASK 0x8
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable__SHIFT 0x3
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable_MASK 0x10
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable__SHIFT 0x4
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable_MASK 0x20
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable__SHIFT 0x5
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable_MASK 0x40
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable__SHIFT 0x6
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable_MASK 0x80
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable__SHIFT 0x7
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable_MASK 0x100
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable__SHIFT 0x8
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable_MASK 0x200
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable__SHIFT 0x9
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable_MASK 0x400
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable__SHIFT 0xa
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable_MASK 0x800
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable__SHIFT 0xb
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable_MASK 0x1000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable__SHIFT 0xc
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable_MASK 0x2000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable__SHIFT 0xd
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable_MASK 0x4000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable__SHIFT 0xe
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable_MASK 0x8000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable__SHIFT 0xf
+#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt__SHIFT 0x0
+#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl_MASK 0xf
+#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb_MASK 0x1
+#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask_MASK 0x100
+#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask_MASK 0x200
+#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask_MASK 0x400
+#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x800
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr_MASK 0x1
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr__SHIFT 0x0
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource_MASK 0xe
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource__SHIFT 0x1
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver_MASK 0x10
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver__SHIFT 0x4
+#define ACP_ERROR_SOURCE_STS__BRBAddrErr_MASK 0x20
+#define ACP_ERROR_SOURCE_STS__BRBAddrErr__SHIFT 0x5
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource_MASK 0x3c0
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource__SHIFT 0x6
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver_MASK 0x400
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver__SHIFT 0xa
+#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr_MASK 0x800
+#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr__SHIFT 0xb
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr_MASK 0x1000
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr__SHIFT 0xc
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr_MASK 0x2000
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr__SHIFT 0xd
+#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr_MASK 0x4000
+#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr__SHIFT 0xe
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr_MASK 0x8000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr__SHIFT 0xf
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource_MASK 0x70000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource__SHIFT 0x10
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver_MASK 0x80000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver__SHIFT 0x13
+#define ACP_ERROR_SOURCE_STS__DAGBErr_MASK 0x100000
+#define ACP_ERROR_SOURCE_STS__DAGBErr__SHIFT 0x14
+#define ACP_ERROR_SOURCE_STS__DAGBErrSource_MASK 0x1e00000
+#define ACP_ERROR_SOURCE_STS__DAGBErrSource__SHIFT 0x15
+#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver_MASK 0x2000000
+#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver__SHIFT 0x19
+#define ACP_ERROR_SOURCE_STS__DMATermOnErr_MASK 0x4000000
+#define ACP_ERROR_SOURCE_STS__DMATermOnErr__SHIFT 0x1a
+#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr_MASK 0x10000000
+#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr__SHIFT 0x1c
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0_MASK 0x1
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0__SHIFT 0x0
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1_MASK 0x2
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1__SHIFT 0x1
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2_MASK 0x4
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2__SHIFT 0x2
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0_MASK 0x100
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0__SHIFT 0x8
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1_MASK 0x200
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1__SHIFT 0x9
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2_MASK 0x400
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2__SHIFT 0xa
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host_MASK 0x10000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host__SHIFT 0x10
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host_MASK 0x20000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host__SHIFT 0x11
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host_MASK 0x40000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host__SHIFT 0x12
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0_MASK 0x1
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0__SHIFT 0x0
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1_MASK 0x2
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1__SHIFT 0x1
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2_MASK 0x4
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2__SHIFT 0x2
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0_MASK 0x100
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0__SHIFT 0x8
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1_MASK 0x200
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1__SHIFT 0x9
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2_MASK 0x400
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2__SHIFT 0xa
+#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask_MASK 0x10000
+#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask__SHIFT 0x10
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask_MASK 0x20000
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask__SHIFT 0x11
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask_MASK 0x40000
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask__SHIFT 0x12
+#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue_MASK 0x3ffff
+#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue__SHIFT 0x0
+#define ACP_DAGBG_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DAGBG_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue_MASK 0x3ffff
+#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue__SHIFT 0x0
+#define ACP_DAGBO_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DAGBO_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_EXTERNAL_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_EXTERNAL_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_EXTERNAL_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat_MASK 0x100
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck_MASK 0x100
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat_MASK 0x200
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck_MASK 0x200
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat_MASK 0x400
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck_MASK 0x400
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat_MASK 0x800
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck_MASK 0x800
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat_MASK 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat__SHIFT 0x0
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack_MASK 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack__SHIFT 0x0
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat_MASK 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat__SHIFT 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack_MASK 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack__SHIFT 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat_MASK 0x4
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat__SHIFT 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack_MASK 0x4
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack__SHIFT 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat_MASK 0x100
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat__SHIFT 0x8
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack_MASK 0x100
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack__SHIFT 0x8
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat_MASK 0x200
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat__SHIFT 0x9
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack_MASK 0x200
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack__SHIFT 0x9
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat_MASK 0x400
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat__SHIFT 0xa
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack_MASK 0x400
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack__SHIFT 0xa
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat_MASK 0x10000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack_MASK 0x10000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat_MASK 0x20000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat__SHIFT 0x11
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack_MASK 0x20000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack__SHIFT 0x11
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat_MASK 0x40000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat__SHIFT 0x12
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack_MASK 0x40000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack__SHIFT 0x12
+#define ACP_DSP0_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP0_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP0_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP0_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP0_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP0_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP0_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP0_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP0_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP0_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP0_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP0_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP0_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP0_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP0_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP0_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP0_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP0_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP0_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP0_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP0_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP0_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP0_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP0_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP0_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP0_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP0_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP0_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP0_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP0_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue_MASK 0x3ffff
+#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue__SHIFT 0x0
+#define ACP_DSP0_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP0_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP1_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP1_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP1_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP1_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP1_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP1_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP1_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP1_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP1_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP1_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP1_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP1_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP1_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP1_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP1_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP1_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP1_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP1_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP1_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP1_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP1_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP1_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP1_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP1_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP1_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP1_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP1_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP1_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP1_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP1_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue_MASK 0x3ffff
+#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue__SHIFT 0x0
+#define ACP_DSP1_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP1_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP2_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP2_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP2_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP2_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP2_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP2_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP2_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP2_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP2_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP2_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP2_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP2_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP2_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP2_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP2_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP2_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP2_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP2_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP2_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP2_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP2_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP2_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP2_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP2_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP2_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP2_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP2_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP2_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP2_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP2_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue_MASK 0x3ffff
+#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue__SHIFT 0x0
+#define ACP_DSP2_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP2_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr_MASK 0xff
+#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr__SHIFT 0x0
+#define ACP_SRBM_Client_RDDATA__ReadData_MASK 0xffffffff
+#define ACP_SRBM_Client_RDDATA__ReadData__SHIFT 0x0
+#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts_MASK 0x1
+#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts__SHIFT 0x0
+#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr_MASK 0x7ffffff
+#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr__SHIFT 0x0
+#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data_MASK 0xffffffff
+#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data__SHIFT 0x0
+#define ACP_SEMA_ADDR_LOW__ADDR_9_3_MASK 0x7f
+#define ACP_SEMA_ADDR_LOW__ADDR_9_3__SHIFT 0x0
+#define ACP_SEMA_ADDR_HIGH__ADDR_39_10_MASK 0x3fffffff
+#define ACP_SEMA_ADDR_HIGH__ADDR_39_10__SHIFT 0x0
+#define ACP_SEMA_CMD__REQ_CMD_MASK 0xf
+#define ACP_SEMA_CMD__REQ_CMD__SHIFT 0x0
+#define ACP_SEMA_CMD__WR_PHASE_MASK 0x30
+#define ACP_SEMA_CMD__WR_PHASE__SHIFT 0x4
+#define ACP_SEMA_CMD__VMID_EN_MASK 0x80
+#define ACP_SEMA_CMD__VMID_EN__SHIFT 0x7
+#define ACP_SEMA_CMD__VMID_MASK 0xf00
+#define ACP_SEMA_CMD__VMID__SHIFT 0x8
+#define ACP_SEMA_CMD__ATC_MASK 0x1000
+#define ACP_SEMA_CMD__ATC__SHIFT 0xc
+#define ACP_SEMA_STS__REQ_STS_MASK 0x3
+#define ACP_SEMA_STS__REQ_STS__SHIFT 0x0
+#define ACP_SEMA_STS__REQ_RESP_AVAIL_MASK 0x100
+#define ACP_SEMA_STS__REQ_RESP_AVAIL__SHIFT 0x8
+#define ACP_SEMA_REQ__ISSUE_POLL_REQ_MASK 0x1
+#define ACP_SEMA_REQ__ISSUE_POLL_REQ__SHIFT 0x0
+#define ACP_FW_STATUS__RUN_MASK 0x1
+#define ACP_FW_STATUS__RUN__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg__SHIFT 0x0
+#define ACP_TIMER__ACP_Timer_count_MASK 0xffffffff
+#define ACP_TIMER__ACP_Timer_count__SHIFT 0x0
+#define ACP_TIMER_CNTL__ACP_Timer_control_MASK 0x1
+#define ACP_TIMER_CNTL__ACP_Timer_control__SHIFT 0x0
+#define ACP_DSP0_TIMER__ACP_DSP0_timer_MASK 0xffffff
+#define ACP_DSP0_TIMER__ACP_DSP0_timer__SHIFT 0x0
+#define ACP_DSP1_TIMER__ACP_DSP1_timer_MASK 0xffffff
+#define ACP_DSP1_TIMER__ACP_DSP1_timer__SHIFT 0x0
+#define ACP_DSP2_TIMER__ACP_DSP2_timer_MASK 0xffffff
+#define ACP_DSP2_TIMER__ACP_DSP2_timer__SHIFT 0x0
+#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low__SHIFT 0x0
+#define ACP_DSP0_CS_STATE__DSP0_CS_state_MASK 0x1
+#define ACP_DSP0_CS_STATE__DSP0_CS_state__SHIFT 0x0
+#define ACP_DSP1_CS_STATE__DSP1_CS_state_MASK 0x1
+#define ACP_DSP1_CS_STATE__DSP1_CS_state__SHIFT 0x0
+#define ACP_DSP2_CS_STATE__DSP2_CS_state_MASK 0x1
+#define ACP_DSP2_CS_STATE__DSP2_CS_state__SHIFT 0x0
+#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR_MASK 0x7ffff
+#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR__SHIFT 0x0
+#define CC_ACP_EFUSE__DSP0_DISABLE_MASK 0x2
+#define CC_ACP_EFUSE__DSP0_DISABLE__SHIFT 0x1
+#define CC_ACP_EFUSE__DSP1_DISABLE_MASK 0x4
+#define CC_ACP_EFUSE__DSP1_DISABLE__SHIFT 0x2
+#define CC_ACP_EFUSE__DSP2_DISABLE_MASK 0x8
+#define CC_ACP_EFUSE__DSP2_DISABLE__SHIFT 0x3
+#define CC_ACP_EFUSE__ACP_DISABLE_MASK 0x10
+#define CC_ACP_EFUSE__ACP_DISABLE__SHIFT 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF_MASK 0x1
+#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF__SHIFT 0x0
+#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF_MASK 0x2
+#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF__SHIFT 0x1
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF_MASK 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF__SHIFT 0x2
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF_MASK 0x8
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF__SHIFT 0x3
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF_MASK 0x10
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF__SHIFT 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF_MASK 0x20
+#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF__SHIFT 0x5
+#define ACP_PGFSM_CONFIG_REG__FSM_ADDR_MASK 0xff
+#define ACP_PGFSM_CONFIG_REG__FSM_ADDR__SHIFT 0x0
+#define ACP_PGFSM_CONFIG_REG__Power_Down_MASK 0x100
+#define ACP_PGFSM_CONFIG_REG__Power_Down__SHIFT 0x8
+#define ACP_PGFSM_CONFIG_REG__Power_Up_MASK 0x200
+#define ACP_PGFSM_CONFIG_REG__Power_Up__SHIFT 0x9
+#define ACP_PGFSM_CONFIG_REG__P1_Select_MASK 0x400
+#define ACP_PGFSM_CONFIG_REG__P1_Select__SHIFT 0xa
+#define ACP_PGFSM_CONFIG_REG__P2_Select_MASK 0x800
+#define ACP_PGFSM_CONFIG_REG__P2_Select__SHIFT 0xb
+#define ACP_PGFSM_CONFIG_REG__Wr_MASK 0x1000
+#define ACP_PGFSM_CONFIG_REG__Wr__SHIFT 0xc
+#define ACP_PGFSM_CONFIG_REG__Rd_MASK 0x2000
+#define ACP_PGFSM_CONFIG_REG__Rd__SHIFT 0xd
+#define ACP_PGFSM_CONFIG_REG__RdData_Reset_MASK 0x4000
+#define ACP_PGFSM_CONFIG_REG__RdData_Reset__SHIFT 0xe
+#define ACP_PGFSM_CONFIG_REG__Short_Format_MASK 0x8000
+#define ACP_PGFSM_CONFIG_REG__Short_Format__SHIFT 0xf
+#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG_MASK 0x3ff0000
+#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG__SHIFT 0x10
+#define ACP_PGFSM_CONFIG_REG__SRBM_override_MASK 0x4000000
+#define ACP_PGFSM_CONFIG_REG__SRBM_override__SHIFT 0x1a
+#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr_MASK 0x8000000
+#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr__SHIFT 0x1b
+#define ACP_PGFSM_CONFIG_REG__REG_ADDR_MASK 0xf0000000
+#define ACP_PGFSM_CONFIG_REG__REG_ADDR__SHIFT 0x1c
+#define ACP_PGFSM_WRITE_REG__Write_value_MASK 0xffffffff
+#define ACP_PGFSM_WRITE_REG__Write_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_0__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_0__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_1__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_1__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_2__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_2__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_3__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_3__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_4__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_4__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_5__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_5__Read_value__SHIFT 0x0
+#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS_MASK 0x1
+#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS__SHIFT 0x0
+#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG_MASK 0x3
+#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG__SHIFT 0x0
+#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT_MASK 0x1
+#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT__SHIFT 0x0
+#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package_MASK 0x1
+#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package__SHIFT 0x0
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable_MASK 0x7ff
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable__SHIFT 0x0
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable_MASK 0x7ff0000
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable__SHIFT 0x10
+#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL_MASK 0x1
+#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL__SHIFT 0x0
+#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable_MASK 0x1
+#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable__SHIFT 0x0
+#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status_MASK 0x1
+#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples_MASK 0xffff
+#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks_MASK 0xffff
+#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en_MASK 0x1
+#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req_MASK 0x1
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack_MASK 0x2
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack__SHIFT 0x1
+#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid_MASK 0x1
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match_MASK 0x2
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match__SHIFT 0x1
+#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap_MASK 0x1
+#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap__SHIFT 0x0
+#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML_MASK 0xffffffff
+#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH_MASK 0xffff
+#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML_MASK 0xffffffff
+#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH_MASK 0xffff
+#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML_MASK 0xffffffff
+#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH_MASK 0xffff
+#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML_MASK 0xffffffff
+#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH_MASK 0xffff
+#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo_MASK 0xffffffff
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi_MASK 0xffff
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo_MASK 0xffffffff
+#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi_MASK 0xffff
+#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi__SHIFT 0x0
+#define ACP_I2SSP_IER__I2SSP_IEN_MASK 0x1
+#define ACP_I2SSP_IER__I2SSP_IEN__SHIFT 0x0
+#define ACP_I2SSP_IRER__I2SSP_RXEN_MASK 0x1
+#define ACP_I2SSP_IRER__I2SSP_RXEN__SHIFT 0x0
+#define ACP_I2SSP_ITER__I2SSP_TXEN_MASK 0x1
+#define ACP_I2SSP_ITER__I2SSP_TXEN__SHIFT 0x0
+#define ACP_I2SSP_CER__I2SSP_CLKEN_MASK 0x1
+#define ACP_I2SSP_CER__I2SSP_CLKEN__SHIFT 0x0
+#define ACP_I2SSP_CCR__I2SSP_SCLKG_MASK 0x7
+#define ACP_I2SSP_CCR__I2SSP_SCLKG__SHIFT 0x0
+#define ACP_I2SSP_CCR__I2SSP_WSS_MASK 0x18
+#define ACP_I2SSP_CCR__I2SSP_WSS__SHIFT 0x3
+#define ACP_I2SSP_RXFFR__I2SSP_RXFFR_MASK 0x1
+#define ACP_I2SSP_RXFFR__I2SSP_RXFFR__SHIFT 0x0
+#define ACP_I2SSP_TXFFR__I2SSP_TXFFR_MASK 0x1
+#define ACP_I2SSP_TXFFR__I2SSP_TXFFR__SHIFT 0x0
+#define ACP_I2SSP_LRBR0__I2SSP_LRBR0_MASK 0xffffffff
+#define ACP_I2SSP_LRBR0__I2SSP_LRBR0__SHIFT 0x0
+#define ACP_I2SSP_RRBR0__I2SSP_RRBR0_MASK 0xffffffff
+#define ACP_I2SSP_RRBR0__I2SSP_RRBR0__SHIFT 0x0
+#define ACP_I2SSP_RER0__I2SSP_RXCHEN0_MASK 0x1
+#define ACP_I2SSP_RER0__I2SSP_RXCHEN0__SHIFT 0x0
+#define ACP_I2SSP_TER0__I2SSP_TXCHEN0_MASK 0x1
+#define ACP_I2SSP_TER0__I2SSP_TXCHEN0__SHIFT 0x0
+#define ACP_I2SSP_RCR0__I2SSP_WLEN_MASK 0x7
+#define ACP_I2SSP_RCR0__I2SSP_WLEN__SHIFT 0x0
+#define ACP_I2SSP_TCR0__I2SSP_WLEN_MASK 0x7
+#define ACP_I2SSP_TCR0__I2SSP_WLEN__SHIFT 0x0
+#define ACP_I2SSP_ISR0__I2SSP_RXDA_MASK 0x1
+#define ACP_I2SSP_ISR0__I2SSP_RXDA__SHIFT 0x0
+#define ACP_I2SSP_ISR0__I2SSP_RXFO_MASK 0x2
+#define ACP_I2SSP_ISR0__I2SSP_RXFO__SHIFT 0x1
+#define ACP_I2SSP_ISR0__I2SSP_TXFE_MASK 0x10
+#define ACP_I2SSP_ISR0__I2SSP_TXFE__SHIFT 0x4
+#define ACP_I2SSP_ISR0__I2SSP_TXFO_MASK 0x20
+#define ACP_I2SSP_ISR0__I2SSP_TXFO__SHIFT 0x5
+#define ACP_I2SSP_IMR0__I2SSP_RXDAM_MASK 0x1
+#define ACP_I2SSP_IMR0__I2SSP_RXDAM__SHIFT 0x0
+#define ACP_I2SSP_IMR0__I2SSP_RXFOM_MASK 0x2
+#define ACP_I2SSP_IMR0__I2SSP_RXFOM__SHIFT 0x1
+#define ACP_I2SSP_IMR0__I2SSP_TXFEM_MASK 0x10
+#define ACP_I2SSP_IMR0__I2SSP_TXFEM__SHIFT 0x4
+#define ACP_I2SSP_IMR0__I2SSP_TXFOM_MASK 0x20
+#define ACP_I2SSP_IMR0__I2SSP_TXFOM__SHIFT 0x5
+#define ACP_I2SSP_ROR0__I2SSP_RXCHO_MASK 0x1
+#define ACP_I2SSP_ROR0__I2SSP_RXCHO__SHIFT 0x0
+#define ACP_I2SSP_TOR0__I2SSP_TXCHO_MASK 0x1
+#define ACP_I2SSP_TOR0__I2SSP_TXCHO__SHIFT 0x0
+#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT_MASK 0xf
+#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SSP_TFCR0__I2SSP_TXCHET_MASK 0xf
+#define ACP_I2SSP_TFCR0__I2SSP_TXCHET__SHIFT 0x0
+#define ACP_I2SSP_RFF0__I2SSP_RXCHFR_MASK 0x1
+#define ACP_I2SSP_RFF0__I2SSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SSP_TFF0__I2SSP_TXCHFR_MASK 0x1
+#define ACP_I2SSP_TFF0__I2SSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SSP_RXDMA__I2SSP_RXDMA_MASK 0xffffffff
+#define ACP_I2SSP_RXDMA__I2SSP_RXDMA__SHIFT 0x0
+#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA_MASK 0x1
+#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA__SHIFT 0x0
+#define ACP_I2SSP_TXDMA__I2SSP_TXDMA_MASK 0xffffffff
+#define ACP_I2SSP_TXDMA__I2SSP_TXDMA__SHIFT 0x0
+#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA_MASK 0x1
+#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN_MASK 0x10
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN__SHIFT 0x4
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES_MASK 0x180
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES_MASK 0x600
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE__SHIFT 0x0
+#define ACP_I2SMICSP_IER__I2SMICSP_IEN_MASK 0x1
+#define ACP_I2SMICSP_IER__I2SMICSP_IEN__SHIFT 0x0
+#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN_MASK 0x1
+#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN__SHIFT 0x0
+#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN_MASK 0x1
+#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN__SHIFT 0x0
+#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN_MASK 0x1
+#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN__SHIFT 0x0
+#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG_MASK 0x7
+#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG__SHIFT 0x0
+#define ACP_I2SMICSP_CCR__I2SMICSP_WSS_MASK 0x18
+#define ACP_I2SMICSP_CCR__I2SMICSP_WSS__SHIFT 0x3
+#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR_MASK 0x1
+#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR__SHIFT 0x0
+#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR_MASK 0x1
+#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR__SHIFT 0x0
+#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0_MASK 0xffffffff
+#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0__SHIFT 0x0
+#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0_MASK 0xffffffff
+#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0__SHIFT 0x0
+#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0_MASK 0x1
+#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0__SHIFT 0x0
+#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0_MASK 0x1
+#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0__SHIFT 0x0
+#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA_MASK 0x1
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA__SHIFT 0x0
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO_MASK 0x2
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO__SHIFT 0x1
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE_MASK 0x10
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE__SHIFT 0x4
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO_MASK 0x20
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO__SHIFT 0x5
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM_MASK 0x1
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM__SHIFT 0x0
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM_MASK 0x2
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM__SHIFT 0x1
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM_MASK 0x10
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM__SHIFT 0x4
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM_MASK 0x20
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM__SHIFT 0x5
+#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO_MASK 0x1
+#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO_MASK 0x1
+#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT_MASK 0xf
+#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET_MASK 0xf
+#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET__SHIFT 0x0
+#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR_MASK 0x1
+#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR_MASK 0x1
+#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1_MASK 0xffffffff
+#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1__SHIFT 0x0
+#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1_MASK 0xffffffff
+#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1__SHIFT 0x0
+#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1_MASK 0x1
+#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1__SHIFT 0x0
+#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1_MASK 0x1
+#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1__SHIFT 0x0
+#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA_MASK 0x1
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA__SHIFT 0x0
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO_MASK 0x2
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO__SHIFT 0x1
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE_MASK 0x10
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE__SHIFT 0x4
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO_MASK 0x20
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO__SHIFT 0x5
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK 0x1
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM__SHIFT 0x0
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK 0x2
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM__SHIFT 0x1
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM_MASK 0x10
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM__SHIFT 0x4
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM_MASK 0x20
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM__SHIFT 0x5
+#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO_MASK 0x1
+#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO_MASK 0x1
+#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT_MASK 0xf
+#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET_MASK 0xf
+#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET__SHIFT 0x0
+#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR_MASK 0x1
+#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR_MASK 0x1
+#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA_MASK 0xffffffff
+#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA_MASK 0x1
+#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA_MASK 0xffffffff
+#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA_MASK 0x1
+#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN_MASK 0x10
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN__SHIFT 0x4
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES_MASK 0x180
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES_MASK 0x600
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE__SHIFT 0x0
+#define ACP_I2SBT_IER__I2SBT_IEN_MASK 0x1
+#define ACP_I2SBT_IER__I2SBT_IEN__SHIFT 0x0
+#define ACP_I2SBT_IRER__I2SBT_RXEN_MASK 0x1
+#define ACP_I2SBT_IRER__I2SBT_RXEN__SHIFT 0x0
+#define ACP_I2SBT_ITER__I2SBT_TXEN_MASK 0x1
+#define ACP_I2SBT_ITER__I2SBT_TXEN__SHIFT 0x0
+#define ACP_I2SBT_CER__I2SBT_CLKEN_MASK 0x1
+#define ACP_I2SBT_CER__I2SBT_CLKEN__SHIFT 0x0
+#define ACP_I2SBT_CCR__I2SBT_SCLKG_MASK 0x7
+#define ACP_I2SBT_CCR__I2SBT_SCLKG__SHIFT 0x0
+#define ACP_I2SBT_CCR__I2SBT_WSS_MASK 0x18
+#define ACP_I2SBT_CCR__I2SBT_WSS__SHIFT 0x3
+#define ACP_I2SBT_RXFFR__I2SBT_RXFFR_MASK 0x1
+#define ACP_I2SBT_RXFFR__I2SBT_RXFFR__SHIFT 0x0
+#define ACP_I2SBT_TXFFR__I2SBT_TXFFR_MASK 0x1
+#define ACP_I2SBT_TXFFR__I2SBT_TXFFR__SHIFT 0x0
+#define ACP_I2SBT_LRBR0__I2SBT_LRBR0_MASK 0xffffffff
+#define ACP_I2SBT_LRBR0__I2SBT_LRBR0__SHIFT 0x0
+#define ACP_I2SBT_RRBR0__I2SBT_RRBR0_MASK 0xffffffff
+#define ACP_I2SBT_RRBR0__I2SBT_RRBR0__SHIFT 0x0
+#define ACP_I2SBT_RER0__I2SBT_RXCHEN0_MASK 0x1
+#define ACP_I2SBT_RER0__I2SBT_RXCHEN0__SHIFT 0x0
+#define ACP_I2SBT_TER0__I2SBT_TXCHEN0_MASK 0x1
+#define ACP_I2SBT_TER0__I2SBT_TXCHEN0__SHIFT 0x0
+#define ACP_I2SBT_RCR0__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_RCR0__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_TCR0__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_TCR0__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_ISR0__I2SBT_RXDA_MASK 0x1
+#define ACP_I2SBT_ISR0__I2SBT_RXDA__SHIFT 0x0
+#define ACP_I2SBT_ISR0__I2SBT_RXFO_MASK 0x2
+#define ACP_I2SBT_ISR0__I2SBT_RXFO__SHIFT 0x1
+#define ACP_I2SBT_ISR0__I2SBT_TXFE_MASK 0x10
+#define ACP_I2SBT_ISR0__I2SBT_TXFE__SHIFT 0x4
+#define ACP_I2SBT_ISR0__I2SBT_TXFO_MASK 0x20
+#define ACP_I2SBT_ISR0__I2SBT_TXFO__SHIFT 0x5
+#define ACP_I2SBT_IMR0__I2SBT_RXDAM_MASK 0x1
+#define ACP_I2SBT_IMR0__I2SBT_RXDAM__SHIFT 0x0
+#define ACP_I2SBT_IMR0__I2SBT_RXFOM_MASK 0x2
+#define ACP_I2SBT_IMR0__I2SBT_RXFOM__SHIFT 0x1
+#define ACP_I2SBT_IMR0__I2SBT_TXFEM_MASK 0x10
+#define ACP_I2SBT_IMR0__I2SBT_TXFEM__SHIFT 0x4
+#define ACP_I2SBT_IMR0__I2SBT_TXFOM_MASK 0x20
+#define ACP_I2SBT_IMR0__I2SBT_TXFOM__SHIFT 0x5
+#define ACP_I2SBT_ROR0__I2SBT_RXCHO_MASK 0x1
+#define ACP_I2SBT_ROR0__I2SBT_RXCHO__SHIFT 0x0
+#define ACP_I2SBT_TOR0__I2SBT_TXCHO_MASK 0x1
+#define ACP_I2SBT_TOR0__I2SBT_TXCHO__SHIFT 0x0
+#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT_MASK 0xf
+#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT__SHIFT 0x0
+#define ACP_I2SBT_TFCR0__I2SBT_TXCHET_MASK 0xf
+#define ACP_I2SBT_TFCR0__I2SBT_TXCHET__SHIFT 0x0
+#define ACP_I2SBT_RFF0__I2SBT_RXCHFR_MASK 0x1
+#define ACP_I2SBT_RFF0__I2SBT_RXCHFR__SHIFT 0x0
+#define ACP_I2SBT_TFF0__I2SBT_TXCHFR_MASK 0x1
+#define ACP_I2SBT_TFF0__I2SBT_TXCHFR__SHIFT 0x0
+#define ACP_I2SBT_LRBR1__I2SBT_LRBR1_MASK 0xffffffff
+#define ACP_I2SBT_LRBR1__I2SBT_LRBR1__SHIFT 0x0
+#define ACP_I2SBT_RRBR1__I2SBT_RRBR1_MASK 0xffffffff
+#define ACP_I2SBT_RRBR1__I2SBT_RRBR1__SHIFT 0x0
+#define ACP_I2SBT_RER1__I2SBT_RXCHEN1_MASK 0x1
+#define ACP_I2SBT_RER1__I2SBT_RXCHEN1__SHIFT 0x0
+#define ACP_I2SBT_TER1__I2SBT_TXCHEN1_MASK 0x1
+#define ACP_I2SBT_TER1__I2SBT_TXCHEN1__SHIFT 0x0
+#define ACP_I2SBT_RCR1__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_RCR1__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_TCR1__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_TCR1__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_ISR1__I2SBT_RXDA_MASK 0x1
+#define ACP_I2SBT_ISR1__I2SBT_RXDA__SHIFT 0x0
+#define ACP_I2SBT_ISR1__I2SBT_RXFO_MASK 0x2
+#define ACP_I2SBT_ISR1__I2SBT_RXFO__SHIFT 0x1
+#define ACP_I2SBT_ISR1__I2SBT_TXFE_MASK 0x10
+#define ACP_I2SBT_ISR1__I2SBT_TXFE__SHIFT 0x4
+#define ACP_I2SBT_ISR1__I2SBT_TXFO_MASK 0x20
+#define ACP_I2SBT_ISR1__I2SBT_TXFO__SHIFT 0x5
+#define ACP_I2SBT_IMR1__I2SBT_RXDAM_MASK 0x1
+#define ACP_I2SBT_IMR1__I2SBT_RXDAM__SHIFT 0x0
+#define ACP_I2SBT_IMR1__I2SBT_RXFOM_MASK 0x2
+#define ACP_I2SBT_IMR1__I2SBT_RXFOM__SHIFT 0x1
+#define ACP_I2SBT_IMR1__I2SBT_TXFEM_MASK 0x10
+#define ACP_I2SBT_IMR1__I2SBT_TXFEM__SHIFT 0x4
+#define ACP_I2SBT_IMR1__I2SBT_TXFOM_MASK 0x20
+#define ACP_I2SBT_IMR1__I2SBT_TXFOM__SHIFT 0x5
+#define ACP_I2SBT_ROR1__I2SBT_RXCHO_MASK 0x1
+#define ACP_I2SBT_ROR1__I2SBT_RXCHO__SHIFT 0x0
+#define ACP_I2SBT_TOR1__I2SBT_TXCHO_MASK 0x1
+#define ACP_I2SBT_TOR1__I2SBT_TXCHO__SHIFT 0x0
+#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT_MASK 0xf
+#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT__SHIFT 0x0
+#define ACP_I2SBT_TFCR1__I2SBT_TXCHET_MASK 0xf
+#define ACP_I2SBT_TFCR1__I2SBT_TXCHET__SHIFT 0x0
+#define ACP_I2SBT_RFF1__I2SBT_RXCHFR_MASK 0x1
+#define ACP_I2SBT_RFF1__I2SBT_RXCHFR__SHIFT 0x0
+#define ACP_I2SBT_TFF1__I2SBT_TXCHFR_MASK 0x1
+#define ACP_I2SBT_TFF1__I2SBT_TXCHFR__SHIFT 0x0
+#define ACP_I2SBT_RXDMA__I2SBT_RXDMA_MASK 0xffffffff
+#define ACP_I2SBT_RXDMA__I2SBT_RXDMA__SHIFT 0x0
+#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA_MASK 0x1
+#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA__SHIFT 0x0
+#define ACP_I2SBT_TXDMA__I2SBT_TXDMA_MASK 0xffffffff
+#define ACP_I2SBT_TXDMA__I2SBT_TXDMA__SHIFT 0x0
+#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA_MASK 0x1
+#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN_MASK 0x10
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN__SHIFT 0x4
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES_MASK 0x180
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES_MASK 0x600
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE__SHIFT 0x0
+
+#endif /* ACP_2_2_SH_MASK_H */
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 2d30464b81ce..06e099e802df 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -68,4 +68,13 @@ config SND_ATMEL_SOC_CLASSD
help
Say Y if you want to add support for Atmel ASoC driver for boards using
CLASSD.
+
+config SND_ATMEL_SOC_PDMIC
+ tristate "Atmel ASoC driver for boards using PDMIC"
+ depends on OF && (ARCH_AT91 || COMPILE_TEST)
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y if you want to add support for Atmel ASoC driver for boards using
+ PDMIC.
endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index f6f7db428216..a2b127bd9c87 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -12,8 +12,10 @@ snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
snd-atmel-soc-wm8904-objs := atmel_wm8904.o
snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
snd-atmel-soc-classd-objs := atmel-classd.o
+snd-atmel-soc-pdmic-objs := atmel-pdmic.o
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
+obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 8276675730ef..6107de9c538b 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -106,7 +106,7 @@ static const struct snd_pcm_hardware atmel_classd_hw = {
.rates = ATMEL_CLASSD_RATES,
.rate_min = 8000,
.rate_max = 96000,
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 256,
@@ -145,7 +145,7 @@ static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = {
static struct snd_soc_dai_driver atmel_classd_cpu_dai = {
.playback = {
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = ATMEL_CLASSD_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
@@ -171,9 +171,13 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ if (params_channels(params) == 1)
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ else
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
slave_config->direction = DMA_MEM_TO_DEV;
slave_config->dst_addr = dd->phy_base + CLASSD_THR;
- slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config->dst_maxburst = 1;
slave_config->src_maxburst = 1;
slave_config->device_fc = false;
@@ -486,7 +490,7 @@ static struct snd_soc_dai_driver atmel_classd_codec_dai = {
.name = ATMEL_CLASSD_CODEC_DAI_NAME,
.playback = {
.stream_name = "Playback",
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = ATMEL_CLASSD_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -636,8 +640,10 @@ static int atmel_classd_probe(struct platform_device *pdev)
/* register sound card */
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
- if (!card)
- return -ENOMEM;
+ if (!card) {
+ ret = -ENOMEM;
+ goto unregister_codec;
+ }
snd_soc_card_set_drvdata(card, dd);
platform_set_drvdata(pdev, card);
@@ -645,16 +651,20 @@ static int atmel_classd_probe(struct platform_device *pdev)
ret = atmel_classd_asoc_card_init(dev, card);
if (ret) {
dev_err(dev, "failed to init sound card\n");
- return ret;
+ goto unregister_codec;
}
ret = devm_snd_soc_register_card(dev, card);
if (ret) {
dev_err(dev, "failed to register sound card: %d\n", ret);
- return ret;
+ goto unregister_codec;
}
return 0;
+
+unregister_codec:
+ snd_soc_unregister_codec(dev);
+ return ret;
}
static int atmel_classd_remove(struct platform_device *pdev)
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
new file mode 100644
index 000000000000..aee4787a0b89
--- /dev/null
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -0,0 +1,738 @@
+/* Atmel PDMIC driver
+ *
+ * Copyright (C) 2015 Atmel
+ *
+ * Author: Songjun Wu <songjun.wu@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 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "atmel-pdmic.h"
+
+struct atmel_pdmic_pdata {
+ u32 mic_min_freq;
+ u32 mic_max_freq;
+ s32 mic_offset;
+ const char *card_name;
+};
+
+struct atmel_pdmic {
+ dma_addr_t phy_base;
+ struct regmap *regmap;
+ struct clk *pclk;
+ struct clk *gclk;
+ int irq;
+ struct snd_pcm_substream *substream;
+ const struct atmel_pdmic_pdata *pdata;
+};
+
+static const struct of_device_id atmel_pdmic_of_match[] = {
+ {
+ .compatible = "atmel,sama5d2-pdmic",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, atmel_pdmic_of_match);
+
+#define PDMIC_OFFSET_MAX_VAL S16_MAX
+#define PDMIC_OFFSET_MIN_VAL S16_MIN
+
+static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct atmel_pdmic_pdata *pdata;
+
+ if (!np) {
+ dev_err(dev, "device node not found\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ if (of_property_read_string(np, "atmel,model", &pdata->card_name))
+ pdata->card_name = "PDMIC";
+
+ if (of_property_read_u32(np, "atmel,mic-min-freq",
+ &pdata->mic_min_freq)) {
+ dev_err(dev, "failed to get mic-min-freq\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(np, "atmel,mic-max-freq",
+ &pdata->mic_max_freq)) {
+ dev_err(dev, "failed to get mic-max-freq\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (pdata->mic_max_freq < pdata->mic_min_freq) {
+ dev_err(dev,
+ "mic-max-freq should not less than mic-min-freq\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_s32(np, "atmel,mic-offset", &pdata->mic_offset))
+ pdata->mic_offset = 0;
+
+ if (pdata->mic_offset > PDMIC_OFFSET_MAX_VAL) {
+ dev_warn(dev,
+ "mic-offset value %d is larger than the max value %d, the max value is specified\n",
+ pdata->mic_offset, PDMIC_OFFSET_MAX_VAL);
+ pdata->mic_offset = PDMIC_OFFSET_MAX_VAL;
+ } else if (pdata->mic_offset < PDMIC_OFFSET_MIN_VAL) {
+ dev_warn(dev,
+ "mic-offset value %d is less than the min value %d, the min value is specified\n",
+ pdata->mic_offset, PDMIC_OFFSET_MIN_VAL);
+ pdata->mic_offset = PDMIC_OFFSET_MIN_VAL;
+ }
+
+ return pdata;
+}
+
+/* cpu dai component */
+static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+ int ret;
+
+ ret = clk_prepare_enable(dd->gclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(dd->pclk);
+ if (ret)
+ return ret;
+
+ /* Clear all bits in the Control Register(PDMIC_CR) */
+ regmap_write(dd->regmap, PDMIC_CR, 0);
+
+ dd->substream = substream;
+
+ /* Enable the overrun error interrupt */
+ regmap_write(dd->regmap, PDMIC_IER, PDMIC_IER_OVRE);
+
+ return 0;
+}
+
+static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+
+ /* Disable the overrun error interrupt */
+ regmap_write(dd->regmap, PDMIC_IDR, PDMIC_IDR_OVRE);
+
+ clk_disable_unprepare(dd->gclk);
+ clk_disable_unprepare(dd->pclk);
+}
+
+static int atmel_pdmic_cpu_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+ u32 val;
+
+ /* Clean the PDMIC Converted Data Register */
+ return regmap_read(dd->regmap, PDMIC_CDR, &val);
+}
+
+static const struct snd_soc_dai_ops atmel_pdmic_cpu_dai_ops = {
+ .startup = atmel_pdmic_cpu_dai_startup,
+ .shutdown = atmel_pdmic_cpu_dai_shutdown,
+ .prepare = atmel_pdmic_cpu_dai_prepare,
+};
+
+#define ATMEL_PDMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver atmel_pdmic_cpu_dai = {
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = ATMEL_PDMIC_FORMATS,},
+ .ops = &atmel_pdmic_cpu_dai_ops,
+};
+
+static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = {
+ .name = "atmel-pdmic",
+};
+
+/* platform */
+#define ATMEL_PDMIC_MAX_BUF_SIZE (64 * 1024)
+#define ATMEL_PDMIC_PREALLOC_BUF_SIZE ATMEL_PDMIC_MAX_BUF_SIZE
+
+static const struct snd_pcm_hardware atmel_pdmic_hw = {
+ .info = SNDRV_PCM_INFO_MMAP
+ | SNDRV_PCM_INFO_MMAP_VALID
+ | SNDRV_PCM_INFO_INTERLEAVED
+ | SNDRV_PCM_INFO_RESUME
+ | SNDRV_PCM_INFO_PAUSE,
+ .formats = ATMEL_PDMIC_FORMATS,
+ .buffer_bytes_max = ATMEL_PDMIC_MAX_BUF_SIZE,
+ .period_bytes_min = 256,
+ .period_bytes_max = 32 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+};
+
+static int
+atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct dma_slave_config *slave_config)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+ int ret;
+
+ ret = snd_hwparams_to_dma_slave_config(substream, params,
+ slave_config);
+ if (ret) {
+ dev_err(rtd->platform->dev,
+ "hw params to dma slave configure failed\n");
+ return ret;
+ }
+
+ slave_config->src_addr = dd->phy_base + PDMIC_CDR;
+ slave_config->src_maxburst = 1;
+ slave_config->dst_maxburst = 1;
+
+ return 0;
+}
+
+static const struct snd_dmaengine_pcm_config
+atmel_pdmic_dmaengine_pcm_config = {
+ .prepare_slave_config = atmel_pdmic_platform_configure_dma,
+ .pcm_hardware = &atmel_pdmic_hw,
+ .prealloc_buffer_size = ATMEL_PDMIC_PREALLOC_BUF_SIZE,
+};
+
+/* codec */
+/* Mic Gain = dgain * 2^(-scale) */
+struct mic_gain {
+ unsigned int dgain;
+ unsigned int scale;
+};
+
+/* range from -90 dB to 90 dB */
+static const struct mic_gain mic_gain_table[] = {
+{ 1, 15}, { 1, 14}, /* -90, -84 dB */
+{ 3, 15}, { 1, 13}, { 3, 14}, { 1, 12}, /* -81, -78, -75, -72 dB */
+{ 5, 14}, { 13, 15}, /* -70, -68 dB */
+{ 9, 14}, { 21, 15}, { 23, 15}, { 13, 14}, /* -65 ~ -62 dB */
+{ 29, 15}, { 33, 15}, { 37, 15}, { 41, 15}, /* -61 ~ -58 dB */
+{ 23, 14}, { 13, 13}, { 58, 15}, { 65, 15}, /* -57 ~ -54 dB */
+{ 73, 15}, { 41, 14}, { 23, 13}, { 13, 12}, /* -53 ~ -50 dB */
+{ 29, 13}, { 65, 14}, { 73, 14}, { 41, 13}, /* -49 ~ -46 dB */
+{ 23, 12}, { 207, 15}, { 29, 12}, { 65, 13}, /* -45 ~ -42 dB */
+{ 73, 13}, { 41, 12}, { 23, 11}, { 413, 15}, /* -41 ~ -38 dB */
+{ 463, 15}, { 519, 15}, { 583, 15}, { 327, 14}, /* -37 ~ -34 dB */
+{ 367, 14}, { 823, 15}, { 231, 13}, { 1036, 15}, /* -33 ~ -30 dB */
+{ 1163, 15}, { 1305, 15}, { 183, 12}, { 1642, 15}, /* -29 ~ -26 dB */
+{ 1843, 15}, { 2068, 15}, { 145, 11}, { 2603, 15}, /* -25 ~ -22 dB */
+{ 365, 12}, { 3277, 15}, { 3677, 15}, { 4125, 15}, /* -21 ~ -18 dB */
+{ 4629, 15}, { 5193, 15}, { 5827, 15}, { 3269, 14}, /* -17 ~ -14 dB */
+{ 917, 12}, { 8231, 15}, { 9235, 15}, { 5181, 14}, /* -13 ~ -10 dB */
+{11627, 15}, {13045, 15}, {14637, 15}, {16423, 15}, /* -9 ~ -6 dB */
+{18427, 15}, {20675, 15}, { 5799, 13}, {26029, 15}, /* -5 ~ -2 dB */
+{ 7301, 13}, { 1, 0}, {18383, 14}, {10313, 13}, /* -1 ~ 2 dB */
+{23143, 14}, {25967, 14}, {29135, 14}, {16345, 13}, /* 3 ~ 6 dB */
+{ 4585, 11}, {20577, 13}, { 1443, 9}, {25905, 13}, /* 7 ~ 10 dB */
+{14533, 12}, { 8153, 11}, { 2287, 9}, {20529, 12}, /* 11 ~ 14 dB */
+{11517, 11}, { 6461, 10}, {28997, 12}, { 4067, 9}, /* 15 ~ 18 dB */
+{18253, 11}, { 10, 0}, {22979, 11}, {25783, 11}, /* 19 ~ 22 dB */
+{28929, 11}, {32459, 11}, { 9105, 9}, {20431, 10}, /* 23 ~ 26 dB */
+{22925, 10}, {12861, 9}, { 7215, 8}, {16191, 9}, /* 27 ~ 30 dB */
+{ 9083, 8}, {20383, 9}, {11435, 8}, { 6145, 7}, /* 31 ~ 34 dB */
+{ 3599, 6}, {32305, 9}, {18123, 8}, {20335, 8}, /* 35 ~ 38 dB */
+{ 713, 3}, { 100, 0}, { 7181, 6}, { 8057, 6}, /* 39 ~ 42 dB */
+{ 565, 2}, {20287, 7}, {11381, 6}, {25539, 7}, /* 43 ~ 46 dB */
+{ 1791, 3}, { 4019, 4}, { 9019, 5}, {20239, 6}, /* 47 ~ 50 dB */
+{ 5677, 4}, {25479, 6}, { 7147, 4}, { 8019, 4}, /* 51 ~ 54 dB */
+{17995, 5}, {20191, 5}, {11327, 4}, {12709, 4}, /* 55 ~ 58 dB */
+{ 3565, 2}, { 1000, 0}, { 1122, 0}, { 1259, 0}, /* 59 ~ 62 dB */
+{ 2825, 1}, {12679, 3}, { 7113, 2}, { 7981, 2}, /* 63 ~ 66 dB */
+{ 8955, 2}, {20095, 3}, {22547, 3}, {12649, 2}, /* 67 ~ 70 dB */
+{28385, 3}, { 3981, 0}, {17867, 2}, {20047, 2}, /* 71 ~ 74 dB */
+{11247, 1}, {12619, 1}, {14159, 1}, {31773, 2}, /* 75 ~ 78 dB */
+{17825, 1}, {10000, 0}, {11220, 0}, {12589, 0}, /* 79 ~ 82 dB */
+{28251, 1}, {15849, 0}, {17783, 0}, {19953, 0}, /* 83 ~ 86 dB */
+{22387, 0}, {25119, 0}, {28184, 0}, {31623, 0}, /* 87 ~ 90 dB */
+};
+
+static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(-9000, 600, 0),
+ 2, 5, TLV_DB_SCALE_ITEM(-8100, 300, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-7000, 200, 0),
+ 8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0),
+);
+
+int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ unsigned int dgain_val, scale_val;
+ int i;
+
+ dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
+ >> PDMIC_DSPR1_DGAIN_SHIFT;
+
+ scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
+ >> PDMIC_DSPR0_SCALE_SHIFT;
+
+ for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) {
+ if ((mic_gain_table[i].dgain == dgain_val) &&
+ (mic_gain_table[i].scale == scale_val))
+ ucontrol->value.integer.value[0] = i;
+ }
+
+ return 0;
+}
+
+static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int max = mc->max;
+ unsigned int val;
+ int ret;
+
+ val = ucontrol->value.integer.value[0];
+
+ if (val > max)
+ return -EINVAL;
+
+ ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
+ mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
+ mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new atmel_pdmic_snd_controls[] = {
+SOC_SINGLE_EXT_TLV("Mic Capture Volume", PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_SHIFT,
+ ARRAY_SIZE(mic_gain_table)-1, 0,
+ pdmic_get_mic_volsw, pdmic_put_mic_volsw, mic_gain_tlv),
+
+SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0,
+ PDMIC_DSPR0_HPFBYP_SHIFT, 1, 1),
+
+SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1),
+};
+
+static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
+
+ snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
+ (u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT));
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
+ .probe = atmel_pdmic_codec_probe,
+ .controls = atmel_pdmic_snd_controls,
+ .num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls),
+};
+
+/* codec dai component */
+#define PDMIC_MR_PRESCAL_MAX_VAL 127
+
+static int
+atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_codec *codec = codec_dai->codec;
+ unsigned int rate_min = substream->runtime->hw.rate_min;
+ unsigned int rate_max = substream->runtime->hw.rate_max;
+ int fs = params_rate(params);
+ int bits = params_width(params);
+ unsigned long pclk_rate, gclk_rate;
+ unsigned int f_pdmic;
+ u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal;
+
+ if (params_channels(params) != 1) {
+ dev_err(codec->dev,
+ "only supports one channel\n");
+ return -EINVAL;
+ }
+
+ if ((fs < rate_min) || (fs > rate_max)) {
+ dev_err(codec->dev,
+ "sample rate is %dHz, min rate is %dHz, max rate is %dHz\n",
+ fs, rate_min, rate_max);
+
+ return -EINVAL;
+ }
+
+ switch (bits) {
+ case 16:
+ dspr0_val = (PDMIC_DSPR0_SIZE_16_BITS
+ << PDMIC_DSPR0_SIZE_SHIFT);
+ break;
+ case 32:
+ dspr0_val = (PDMIC_DSPR0_SIZE_32_BITS
+ << PDMIC_DSPR0_SIZE_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((fs << 7) > (rate_max << 6)) {
+ f_pdmic = fs << 6;
+ dspr0_val |= PDMIC_DSPR0_OSR_64 << PDMIC_DSPR0_OSR_SHIFT;
+ } else {
+ f_pdmic = fs << 7;
+ dspr0_val |= PDMIC_DSPR0_OSR_128 << PDMIC_DSPR0_OSR_SHIFT;
+ }
+
+ pclk_rate = clk_get_rate(dd->pclk);
+ gclk_rate = clk_get_rate(dd->gclk);
+
+ /* PRESCAL = SELCK/(2*f_pdmic) - 1*/
+ pclk_prescal = (u32)(pclk_rate/(f_pdmic << 1)) - 1;
+ gclk_prescal = (u32)(gclk_rate/(f_pdmic << 1)) - 1;
+
+ if ((pclk_prescal > PDMIC_MR_PRESCAL_MAX_VAL) ||
+ (gclk_rate/((gclk_prescal + 1) << 1) <
+ pclk_rate/((pclk_prescal + 1) << 1))) {
+ mr_val = gclk_prescal << PDMIC_MR_PRESCAL_SHIFT;
+ mr_val |= PDMIC_MR_CLKS_GCK << PDMIC_MR_CLKS_SHIFT;
+ } else {
+ mr_val = pclk_prescal << PDMIC_MR_PRESCAL_SHIFT;
+ mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT;
+ }
+
+ snd_soc_update_bits(codec, PDMIC_MR,
+ PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val);
+
+ snd_soc_update_bits(codec, PDMIC_DSPR0,
+ PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val);
+
+ return 0;
+}
+
+static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+ PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
+
+ return 0;
+}
+
+static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u32 val;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ val = PDMIC_CR_ENPDM_EN << PDMIC_CR_ENPDM_SHIFT;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ val = PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops atmel_pdmic_codec_dai_ops = {
+ .hw_params = atmel_pdmic_codec_dai_hw_params,
+ .prepare = atmel_pdmic_codec_dai_prepare,
+ .trigger = atmel_pdmic_codec_dai_trigger,
+};
+
+#define ATMEL_PDMIC_CODEC_DAI_NAME "atmel-pdmic-hifi"
+
+static struct snd_soc_dai_driver atmel_pdmic_codec_dai = {
+ .name = ATMEL_PDMIC_CODEC_DAI_NAME,
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = ATMEL_PDMIC_FORMATS,
+ },
+ .ops = &atmel_pdmic_codec_dai_ops,
+};
+
+/* ASoC sound card */
+static int atmel_pdmic_asoc_card_init(struct device *dev,
+ struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
+
+ dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL);
+ if (!dai_link)
+ return -ENOMEM;
+
+ dai_link->name = "PDMIC";
+ dai_link->stream_name = "PDMIC PCM";
+ dai_link->codec_dai_name = ATMEL_PDMIC_CODEC_DAI_NAME;
+ dai_link->cpu_dai_name = dev_name(dev);
+ dai_link->codec_name = dev_name(dev);
+ dai_link->platform_name = dev_name(dev);
+
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->name = dd->pdata->card_name;
+ card->dev = dev;
+
+ return 0;
+}
+
+static void atmel_pdmic_get_sample_rate(struct atmel_pdmic *dd,
+ unsigned int *rate_min, unsigned int *rate_max)
+{
+ u32 mic_min_freq = dd->pdata->mic_min_freq;
+ u32 mic_max_freq = dd->pdata->mic_max_freq;
+ u32 clk_max_rate = (u32)(clk_get_rate(dd->pclk) >> 1);
+ u32 clk_min_rate = (u32)(clk_get_rate(dd->gclk) >> 8);
+
+ if (mic_max_freq > clk_max_rate)
+ mic_max_freq = clk_max_rate;
+
+ if (mic_min_freq < clk_min_rate)
+ mic_min_freq = clk_min_rate;
+
+ *rate_min = DIV_ROUND_CLOSEST(mic_min_freq, 128);
+ *rate_max = mic_max_freq >> 6;
+}
+
+/* PDMIC interrupt handler */
+static irqreturn_t atmel_pdmic_interrupt(int irq, void *dev_id)
+{
+ struct atmel_pdmic *dd = (struct atmel_pdmic *)dev_id;
+ u32 pdmic_isr;
+ irqreturn_t ret = IRQ_NONE;
+
+ regmap_read(dd->regmap, PDMIC_ISR, &pdmic_isr);
+
+ if (pdmic_isr & PDMIC_ISR_OVRE) {
+ regmap_update_bits(dd->regmap, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+ PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
+
+ snd_pcm_stop_xrun(dd->substream);
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+/* regmap configuration */
+#define ATMEL_PDMIC_REG_MAX 0x124
+static const struct regmap_config atmel_pdmic_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = ATMEL_PDMIC_REG_MAX,
+};
+
+static int atmel_pdmic_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct atmel_pdmic *dd;
+ struct resource *res;
+ void __iomem *io_base;
+ const struct atmel_pdmic_pdata *pdata;
+ struct snd_soc_card *card;
+ unsigned int rate_min, rate_max;
+ int ret;
+
+ pdata = atmel_pdmic_dt_init(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+
+ dd->pdata = pdata;
+
+ dd->irq = platform_get_irq(pdev, 0);
+ if (dd->irq < 0) {
+ ret = dd->irq;
+ dev_err(dev, "failed to could not get irq: %d\n", ret);
+ return ret;
+ }
+
+ dd->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(dd->pclk)) {
+ ret = PTR_ERR(dd->pclk);
+ dev_err(dev, "failed to get peripheral clock: %d\n", ret);
+ return ret;
+ }
+
+ dd->gclk = devm_clk_get(dev, "gclk");
+ if (IS_ERR(dd->gclk)) {
+ ret = PTR_ERR(dd->gclk);
+ dev_err(dev, "failed to get GCK: %d\n", ret);
+ return ret;
+ }
+
+ /* The gclk clock frequency must always be tree times
+ * lower than the pclk clock frequency
+ */
+ ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3);
+ if (ret) {
+ dev_err(dev, "failed to set GCK clock rate: %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "no memory resource\n");
+ return -ENXIO;
+ }
+
+ io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(io_base)) {
+ ret = PTR_ERR(io_base);
+ dev_err(dev, "failed to remap register memory: %d\n", ret);
+ return ret;
+ }
+
+ dd->phy_base = res->start;
+
+ dd->regmap = devm_regmap_init_mmio(dev, io_base,
+ &atmel_pdmic_regmap_config);
+ if (IS_ERR(dd->regmap)) {
+ ret = PTR_ERR(dd->regmap);
+ dev_err(dev, "failed to init register map: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_irq(dev, dd->irq, atmel_pdmic_interrupt, 0,
+ "PDMIC", (void *)dd);
+ if (ret < 0) {
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+ dd->irq, ret);
+ return ret;
+ }
+
+ /* Get the minimal and maximal sample rate that micphone supports */
+ atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max);
+
+ /* register cpu dai */
+ atmel_pdmic_cpu_dai.capture.rate_min = rate_min;
+ atmel_pdmic_cpu_dai.capture.rate_max = rate_max;
+ ret = devm_snd_soc_register_component(dev,
+ &atmel_pdmic_cpu_dai_component,
+ &atmel_pdmic_cpu_dai, 1);
+ if (ret) {
+ dev_err(dev, "could not register CPU DAI: %d\n", ret);
+ return ret;
+ }
+
+ /* register platform */
+ ret = devm_snd_dmaengine_pcm_register(dev,
+ &atmel_pdmic_dmaengine_pcm_config,
+ 0);
+ if (ret) {
+ dev_err(dev, "could not register platform: %d\n", ret);
+ return ret;
+ }
+
+ /* register codec and codec dai */
+ atmel_pdmic_codec_dai.capture.rate_min = rate_min;
+ atmel_pdmic_codec_dai.capture.rate_max = rate_max;
+ ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic,
+ &atmel_pdmic_codec_dai, 1);
+ if (ret) {
+ dev_err(dev, "could not register codec: %d\n", ret);
+ return ret;
+ }
+
+ /* register sound card */
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card) {
+ ret = -ENOMEM;
+ goto unregister_codec;
+ }
+
+ snd_soc_card_set_drvdata(card, dd);
+ platform_set_drvdata(pdev, card);
+
+ ret = atmel_pdmic_asoc_card_init(dev, card);
+ if (ret) {
+ dev_err(dev, "failed to init sound card: %d\n", ret);
+ goto unregister_codec;
+ }
+
+ ret = devm_snd_soc_register_card(dev, card);
+ if (ret) {
+ dev_err(dev, "failed to register sound card: %d\n", ret);
+ goto unregister_codec;
+ }
+
+ return 0;
+
+unregister_codec:
+ snd_soc_unregister_codec(dev);
+ return ret;
+}
+
+static int atmel_pdmic_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver atmel_pdmic_driver = {
+ .driver = {
+ .name = "atmel-pdmic",
+ .of_match_table = of_match_ptr(atmel_pdmic_of_match),
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = atmel_pdmic_probe,
+ .remove = atmel_pdmic_remove,
+};
+module_platform_driver(atmel_pdmic_driver);
+
+MODULE_DESCRIPTION("Atmel PDMIC driver under ALSA SoC architecture");
+MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/atmel-pdmic.h b/sound/soc/atmel/atmel-pdmic.h
new file mode 100644
index 000000000000..4527ac741919
--- /dev/null
+++ b/sound/soc/atmel/atmel-pdmic.h
@@ -0,0 +1,80 @@
+#ifndef __ATMEL_PDMIC_H_
+#define __ATMEL_PDMIC_H_
+
+#include <linux/bitops.h>
+
+#define PDMIC_CR 0x00000000
+
+#define PDMIC_CR_SWRST 0x1
+#define PDMIC_CR_SWRST_MASK BIT(0)
+#define PDMIC_CR_SWRST_SHIFT (0)
+
+#define PDMIC_CR_ENPDM_DIS 0x0
+#define PDMIC_CR_ENPDM_EN 0x1
+#define PDMIC_CR_ENPDM_MASK BIT(4)
+#define PDMIC_CR_ENPDM_SHIFT (4)
+
+#define PDMIC_MR 0x00000004
+
+#define PDMIC_MR_CLKS_PCK 0x0
+#define PDMIC_MR_CLKS_GCK 0x1
+#define PDMIC_MR_CLKS_MASK BIT(4)
+#define PDMIC_MR_CLKS_SHIFT (4)
+
+#define PDMIC_MR_PRESCAL_MASK GENMASK(14, 8)
+#define PDMIC_MR_PRESCAL_SHIFT (8)
+
+#define PDMIC_CDR 0x00000014
+
+#define PDMIC_IER 0x00000018
+#define PDMIC_IER_OVRE BIT(25)
+
+#define PDMIC_IDR 0x0000001c
+#define PDMIC_IDR_OVRE BIT(25)
+
+#define PDMIC_IMR 0x00000020
+
+#define PDMIC_ISR 0x00000024
+#define PDMIC_ISR_OVRE BIT(25)
+
+#define PDMIC_DSPR0 0x00000058
+
+#define PDMIC_DSPR0_HPFBYP_DIS 0x1
+#define PDMIC_DSPR0_HPFBYP_EN 0x0
+#define PDMIC_DSPR0_HPFBYP_MASK BIT(1)
+#define PDMIC_DSPR0_HPFBYP_SHIFT (1)
+
+#define PDMIC_DSPR0_SINBYP_DIS 0x1
+#define PDMIC_DSPR0_SINBYP_EN 0x0
+#define PDMIC_DSPR0_SINBYP_MASK BIT(2)
+#define PDMIC_DSPR0_SINBYP_SHIFT (2)
+
+#define PDMIC_DSPR0_SIZE_16_BITS 0x0
+#define PDMIC_DSPR0_SIZE_32_BITS 0x1
+#define PDMIC_DSPR0_SIZE_MASK BIT(3)
+#define PDMIC_DSPR0_SIZE_SHIFT (3)
+
+#define PDMIC_DSPR0_OSR_128 0x0
+#define PDMIC_DSPR0_OSR_64 0x1
+#define PDMIC_DSPR0_OSR_MASK GENMASK(6, 4)
+#define PDMIC_DSPR0_OSR_SHIFT (4)
+
+#define PDMIC_DSPR0_SCALE_MASK GENMASK(11, 8)
+#define PDMIC_DSPR0_SCALE_SHIFT (8)
+
+#define PDMIC_DSPR0_SHIFT_MASK GENMASK(15, 12)
+#define PDMIC_DSPR0_SHIFT_SHIFT (12)
+
+#define PDMIC_DSPR1 0x0000005c
+
+#define PDMIC_DSPR1_DGAIN_MASK GENMASK(14, 0)
+#define PDMIC_DSPR1_DGAIN_SHIFT (0)
+
+#define PDMIC_DSPR1_OFFSET_MASK GENMASK(31, 16)
+#define PDMIC_DSPR1_OFFSET_SHIFT (16)
+
+#define PDMIC_WPMR 0x000000e4
+
+#define PDMIC_WPSR 0x000000e8
+
+#endif
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index 1933bcd46cca..fdd28ed3e0b9 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -183,6 +183,7 @@ static struct platform_driver atmel_asoc_wm8904_driver = {
.driver = {
.name = "atmel-wm8904-audio",
.of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
+ .pm = &snd_soc_pm_ops,
},
.probe = atmel_asoc_wm8904_probe,
.remove = atmel_asoc_wm8904_remove,
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 8c435beb263d..3303d5f58082 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -31,20 +31,20 @@
* General Public License for more details.
*/
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/init.h>
+#include <linux/io.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 <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
/* Clock registers */
#define BCM2835_CLK_PCMCTL_REG 0x00
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfdafc4c11ea..50693c867e71 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -55,9 +55,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271_SPI if SPI_MASTER
select SND_SOC_CS42XX8_I2C if I2C
select SND_SOC_CS4349 if I2C
+ select SND_SOC_CS47L24 if MFD_CS47L24
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
select SND_SOC_DA7213 if I2C
+ select SND_SOC_DA7218 if I2C
select SND_SOC_DA7219 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
@@ -66,7 +68,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_GTM601
+ select SND_SOC_HDAC_HDMI
select SND_SOC_ICS43432
+ select SND_SOC_INNO_RK3036
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
@@ -83,16 +87,20 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ML26124 if I2C
select SND_SOC_NAU8825 if I2C
select SND_SOC_PCM1681 if I2C
- select SND_SOC_PCM1792A if SPI_MASTER
+ select SND_SOC_PCM179X if SPI_MASTER
select SND_SOC_PCM3008
+ select SND_SOC_PCM3168A_I2C if I2C
+ select SND_SOC_PCM3168A_SPI if SPI_MASTER
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
+ select SND_SOC_RT5616 if I2C
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
select SND_SOC_RT5645 if I2C
select SND_SOC_RT5651 if I2C
+ select SND_SOC_RT5659 if I2C
select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C
@@ -195,10 +203,12 @@ config SND_SOC_88PM860X
config SND_SOC_ARIZONA
tristate
+ default y if SND_SOC_CS47L24=y
default y if SND_SOC_WM5102=y
default y if SND_SOC_WM5110=y
default y if SND_SOC_WM8997=y
default y if SND_SOC_WM8998=y
+ default m if SND_SOC_CS47L24=m
default m if SND_SOC_WM5102=m
default m if SND_SOC_WM5110=m
default m if SND_SOC_WM8997=m
@@ -211,9 +221,12 @@ config SND_SOC_WM_HUBS
config SND_SOC_WM_ADSP
tristate
+ select SND_SOC_COMPRESS
+ default y if SND_SOC_CS47L24=y
default y if SND_SOC_WM5102=y
default y if SND_SOC_WM5110=y
default y if SND_SOC_WM2200=y
+ default m if SND_SOC_CS47L24=m
default m if SND_SOC_WM5102=m
default m if SND_SOC_WM5110=m
default m if SND_SOC_WM2200=m
@@ -422,6 +435,9 @@ config SND_SOC_CS4349
tristate "Cirrus Logic CS4349 CODEC"
depends on I2C
+config SND_SOC_CS47L24
+ tristate
+
config SND_SOC_CX20442
tristate
depends on TTY
@@ -439,6 +455,9 @@ config SND_SOC_DA7210
config SND_SOC_DA7213
tristate
+config SND_SOC_DA7218
+ tristate
+
config SND_SOC_DA7219
tristate
@@ -468,9 +487,17 @@ config SND_SOC_ES8328_SPI
config SND_SOC_GTM601
tristate 'GTM601 UMTS modem audio codec'
+config SND_SOC_HDAC_HDMI
+ tristate
+ select SND_HDA_EXT_CORE
+ select HDMI
+
config SND_SOC_ICS43432
tristate
+config SND_SOC_INNO_RK3036
+ tristate "Inno codec driver for RK3036 SoC"
+
config SND_SOC_ISABELLE
tristate
@@ -499,13 +526,28 @@ config SND_SOC_PCM1681
tristate "Texas Instruments PCM1681 CODEC"
depends on I2C
-config SND_SOC_PCM1792A
- tristate "Texas Instruments PCM1792A CODEC"
+config SND_SOC_PCM179X
+ tristate "Texas Instruments PCM179X CODEC"
depends on SPI_MASTER
config SND_SOC_PCM3008
tristate
+config SND_SOC_PCM3168A
+ tristate
+
+config SND_SOC_PCM3168A_I2C
+ tristate "Texas Instruments PCM3168A CODEC - I2C"
+ depends on I2C
+ select SND_SOC_PCM3168A
+ select REGMAP_I2C
+
+config SND_SOC_PCM3168A_SPI
+ tristate "Texas Instruments PCM3168A CODEC - SPI"
+ depends on SPI_MASTER
+ select SND_SOC_PCM3168A
+ select REGMAP_SPI
+
config SND_SOC_PCM512x
tristate
@@ -523,14 +565,18 @@ config SND_SOC_PCM512x_SPI
config SND_SOC_RL6231
tristate
+ default y if SND_SOC_RT5616=y
default y if SND_SOC_RT5640=y
default y if SND_SOC_RT5645=y
default y if SND_SOC_RT5651=y
+ default y if SND_SOC_RT5659=y
default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y
+ default m if SND_SOC_RT5616=m
default m if SND_SOC_RT5640=m
default m if SND_SOC_RT5645=m
default m if SND_SOC_RT5651=m
+ default m if SND_SOC_RT5659=m
default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m
@@ -549,6 +595,9 @@ config SND_SOC_RT298
tristate
depends on I2C
+config SND_SOC_RT5616
+ tristate
+
config SND_SOC_RT5631
tristate "Realtek ALC5631/RT5631 CODEC"
depends on I2C
@@ -562,6 +611,9 @@ config SND_SOC_RT5645
config SND_SOC_RT5651
tristate
+config SND_SOC_RT5659
+ tristate
+
config SND_SOC_RT5670
tristate
@@ -838,7 +890,8 @@ config SND_SOC_WM8971
tristate
config SND_SOC_WM8974
- tristate
+ tristate "Wolfson Microelectronics WM8974 codec"
+ depends on I2C
config SND_SOC_WM8978
tristate "Wolfson Microelectronics WM8978 codec"
@@ -891,6 +944,7 @@ config SND_SOC_WM9712
config SND_SOC_WM9713
tristate
+ select REGMAP_AC97
# Amp
config SND_SOC_LM4857
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f632fc42f59f..d44f7d347183 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -47,9 +47,11 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o
snd-soc-cs42xx8-objs := cs42xx8.o
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
snd-soc-cs4349-objs := cs4349.o
+snd-soc-cs47l24-objs := cs47l24.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
+snd-soc-da7218-objs := da7218.o
snd-soc-da7219-objs := da7219.o da7219-aad.o
snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
@@ -59,7 +61,9 @@ snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
snd-soc-gtm601-objs := gtm601.o
+snd-soc-hdac-hdmi-objs := hdac_hdmi.o
snd-soc-ics43432-objs := ics43432.o
+snd-soc-inno-rk3036-objs := inno_rk3036.o
snd-soc-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o
@@ -76,8 +80,11 @@ snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-nau8825-objs := nau8825.o
snd-soc-pcm1681-objs := pcm1681.o
-snd-soc-pcm1792a-codec-objs := pcm1792a.o
+snd-soc-pcm179x-codec-objs := pcm179x.o
snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm3168a-objs := pcm3168a.o
+snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
+snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
snd-soc-pcm512x-objs := pcm512x.o
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
@@ -85,10 +92,12 @@ snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
+snd-soc-rt5616-objs := rt5616.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
snd-soc-rt5645-objs := rt5645.o
snd-soc-rt5651-objs := rt5651.o
+snd-soc-rt5659-objs := rt5659.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -242,9 +251,11 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
+obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
+obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o
obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
@@ -254,7 +265,9 @@ obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
+obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
+obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
@@ -271,8 +284,11 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
-obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
+obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
+obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
+obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
@@ -280,10 +296,12 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
+obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
+obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 07a266460ec3..647f69de6baa 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -70,18 +70,11 @@
#define FMT_MASK (0xf8)
/* CTRL2 */
+#define DFS_MASK (3 << 2)
#define DFS_NORMAL_SPEED (0 << 2)
#define DFS_DOUBLE_SPEED (1 << 2)
#define DFS_QUAD_SPEED (2 << 2)
-struct ak4613_priv {
- struct mutex lock;
-
- unsigned int fmt;
- u8 fmt_ctrl;
- int cnt;
-};
-
struct ak4613_formats {
unsigned int width;
unsigned int fmt;
@@ -92,6 +85,16 @@ struct ak4613_interface {
struct ak4613_formats playback;
};
+struct ak4613_priv {
+ struct mutex lock;
+ const struct ak4613_interface *iface;
+
+ unsigned int fmt;
+ u8 oc;
+ u8 ic;
+ int cnt;
+};
+
/*
* Playback Volume
*
@@ -126,7 +129,7 @@ static const struct reg_default ak4613_reg[] = {
{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
};
-#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
+#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3)
#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
static const struct ak4613_interface ak4613_iface[] = {
/* capture */ /* playback */
@@ -240,7 +243,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
priv->cnt = 0;
}
if (!priv->cnt)
- priv->fmt_ctrl = NO_FMT;
+ priv->iface = NULL;
mutex_unlock(&priv->lock);
}
@@ -265,13 +268,35 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
+ int is_play,
+ unsigned int fmt, unsigned int width)
+{
+ const struct ak4613_formats *fmts;
+
+ fmts = (is_play) ? &iface->playback : &iface->capture;
+
+ if (fmts->fmt != fmt)
+ return false;
+
+ if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
+ if (fmts->width != width)
+ return false;
+ } else {
+ if (fmts->width < width)
+ return false;
+ }
+
+ return true;
+}
+
static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
- const struct ak4613_formats *fmts;
+ const struct ak4613_interface *iface;
struct device *dev = codec->dev;
unsigned int width = params_width(params);
unsigned int fmt = priv->fmt;
@@ -305,33 +330,27 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
* It doesn't support TDM at this point
*/
fmt_ctrl = NO_FMT;
- for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
- fmts = (is_play) ? &ak4613_iface[i].playback :
- &ak4613_iface[i].capture;
-
- if (fmts->fmt != fmt)
- continue;
+ ret = -EINVAL;
+ iface = NULL;
- if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
- if (fmts->width != width)
- continue;
- } else {
- if (fmts->width < width)
+ mutex_lock(&priv->lock);
+ if (priv->iface) {
+ if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
+ iface = priv->iface;
+ } else {
+ for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) {
+ if (!ak4613_dai_fmt_matching(ak4613_iface + i,
+ is_play,
+ fmt, width))
continue;
+ iface = ak4613_iface + i;
+ break;
}
-
- fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
- break;
}
- ret = -EINVAL;
- if (fmt_ctrl == NO_FMT)
- goto hw_params_end;
-
- mutex_lock(&priv->lock);
- if ((priv->fmt_ctrl == NO_FMT) ||
- (priv->fmt_ctrl == fmt_ctrl)) {
- priv->fmt_ctrl = fmt_ctrl;
+ if ((priv->iface == NULL) ||
+ (priv->iface == iface)) {
+ priv->iface = iface;
priv->cnt++;
ret = 0;
}
@@ -340,8 +359,13 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
goto hw_params_end;
+ fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
+
snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
- snd_soc_write(codec, CTRL2, ctrl2);
+ snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2);
+
+ snd_soc_write(codec, ICTRL, priv->ic);
+ snd_soc_write(codec, OCTRL, priv->oc);
hw_params_end:
if (ret < 0)
@@ -431,6 +455,28 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
.num_dapm_routes = ARRAY_SIZE(ak4613_intercon),
};
+static void ak4613_parse_of(struct ak4613_priv *priv,
+ struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ char prop[32];
+ int i;
+
+ /* Input 1 - 2 */
+ for (i = 0; i < 2; i++) {
+ snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
+ if (!of_get_property(np, prop, NULL))
+ priv->ic |= 1 << i;
+ }
+
+ /* Output 1 - 6 */
+ for (i = 0; i < 6; i++) {
+ snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
+ if (!of_get_property(np, prop, NULL))
+ priv->oc |= 1 << i;
+ }
+}
+
static int ak4613_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -458,7 +504,9 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
if (!priv)
return -ENOMEM;
- priv->fmt_ctrl = NO_FMT;
+ ak4613_parse_of(priv, dev);
+
+ priv->iface = NULL;
priv->cnt = 0;
mutex_init(&priv->lock);
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 93b400800905..33143fe1de0b 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -310,7 +310,7 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(arizona_init_gpio);
-const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
+const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
"Tone Generator 1",
"Tone Generator 2",
@@ -418,7 +418,7 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
};
EXPORT_SYMBOL_GPL(arizona_mixer_texts);
-int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
+unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x00, /* None */
0x04, /* Tone */
0x05,
@@ -555,12 +555,12 @@ const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
}
EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
-const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
"SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
};
EXPORT_SYMBOL_GPL(arizona_rate_text);
-const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
0, 1, 2, 8,
};
EXPORT_SYMBOL_GPL(arizona_rate_val);
@@ -702,6 +702,100 @@ const struct soc_enum arizona_in_dmic_osr[] = {
};
EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
+static const char * const arizona_anc_input_src_text[] = {
+ "None", "IN1", "IN2", "IN3", "IN4",
+};
+
+static const char * const arizona_anc_channel_src_text[] = {
+ "None", "Left", "Right", "Combine",
+};
+
+const struct soc_enum arizona_anc_input_src[] = {
+ SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+ ARIZONA_IN_RXANCL_SEL_SHIFT,
+ ARRAY_SIZE(arizona_anc_input_src_text),
+ arizona_anc_input_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
+ ARIZONA_FCL_MIC_MODE_SEL,
+ ARRAY_SIZE(arizona_anc_channel_src_text),
+ arizona_anc_channel_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+ ARIZONA_IN_RXANCR_SEL_SHIFT,
+ ARRAY_SIZE(arizona_anc_input_src_text),
+ arizona_anc_input_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
+ ARIZONA_FCR_MIC_MODE_SEL,
+ ARRAY_SIZE(arizona_anc_channel_src_text),
+ arizona_anc_channel_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_anc_input_src);
+
+static const char * const arizona_anc_ng_texts[] = {
+ "None",
+ "Internal",
+ "External",
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
+ arizona_anc_ng_texts);
+EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
+
+static const char * const arizona_output_anc_src_text[] = {
+ "None", "RXANCL", "RXANCR",
+};
+
+const struct soc_enum arizona_output_anc_src[] = {
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+ ARIZONA_OUT1L_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
+ ARIZONA_OUT1R_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+ ARIZONA_OUT2L_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
+ ARIZONA_OUT2R_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+ ARIZONA_OUT3L_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
+ ARIZONA_OUT3R_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
+ ARIZONA_OUT4L_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
+ ARIZONA_OUT4R_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
+ ARIZONA_OUT5L_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
+ ARIZONA_OUT5R_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
+ ARIZONA_OUT6L_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+ SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
+ ARIZONA_OUT6R_ANC_SRC_SHIFT,
+ ARRAY_SIZE(arizona_output_anc_src_text),
+ arizona_output_anc_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_output_anc_src);
+
static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
@@ -1023,6 +1117,31 @@ void arizona_init_dvfs(struct arizona_priv *priv)
}
EXPORT_SYMBOL_GPL(arizona_init_dvfs);
+int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ unsigned int mask = 0x3 << w->shift;
+ unsigned int val;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ val = 1 << w->shift;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ val = 1 << (w->shift + 1);
+ break;
+ default:
+ return 0;
+ }
+
+ snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_anc_ev);
+
static unsigned int arizona_opclk_ref_48k_rates[] = {
6144000,
12288000,
@@ -1095,7 +1214,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
unsigned int reg;
unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
- unsigned int *clk;
+ int *clk;
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
@@ -1375,6 +1494,9 @@ static int arizona_startup(struct snd_pcm_substream *substream,
const struct snd_pcm_hw_constraint_list *constraint;
unsigned int base_rate;
+ if (!substream->runtime)
+ return 0;
+
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
base_rate = priv->sysclk;
@@ -1901,18 +2023,18 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
}
switch (fll->arizona->type) {
+ case WM5102:
+ case WM8997:
+ return init_ratio;
case WM5110:
case WM8280:
if (fll->arizona->rev < 3 || sync)
return init_ratio;
break;
- case WM8998:
- case WM1814:
+ default:
if (sync)
return init_ratio;
break;
- default:
- return init_ratio;
}
cfg->fratio = init_ratio - 1;
@@ -2093,9 +2215,9 @@ static int arizona_enable_fll(struct arizona_fll *fll)
/* Facilitate smooth refclk across the transition */
regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
ARIZONA_FLL1_GAIN_MASK, 0);
- regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
- ARIZONA_FLL1_FREERUN,
- ARIZONA_FLL1_FREERUN);
+ regmap_update_bits(fll->arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
+ udelay(32);
}
/*
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index fea8b8ae8e1a..8b6adb5419bb 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -57,7 +57,7 @@
#define ARIZONA_CLK_98MHZ 5
#define ARIZONA_CLK_147MHZ 6
-#define ARIZONA_MAX_DAI 6
+#define ARIZONA_MAX_DAI 8
#define ARIZONA_MAX_ADSP 4
#define ARIZONA_DVFS_SR1_RQ 0x001
@@ -96,8 +96,8 @@ struct arizona_priv {
#define ARIZONA_NUM_MIXER_INPUTS 104
extern const unsigned int arizona_mixer_tlv[];
-extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
-extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
+extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
+extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_GAINMUX_CONTROLS(name, base) \
SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1, \
@@ -216,8 +216,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_RATE_ENUM_SIZE 4
#define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
-extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
-extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
@@ -242,6 +242,10 @@ extern const struct soc_enum arizona_in_dmic_osr[];
extern const struct snd_kcontrol_new arizona_adsp2_rate_controls[];
+extern const struct soc_enum arizona_anc_input_src[];
+extern const struct soc_enum arizona_anc_ng_enum;
+extern const struct soc_enum arizona_output_anc_src[];
+
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
@@ -251,6 +255,9 @@ extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
+extern int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event);
extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
new file mode 100644
index 000000000000..dc5ae7f7a1bd
--- /dev/null
+++ b/sound/soc/codecs/cs47l24.c
@@ -0,0 +1,1148 @@
+/*
+ * cs47l24.h -- ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm_adsp.h"
+#include "cs47l24.h"
+
+struct cs47l24_priv {
+ struct arizona_priv core;
+ struct arizona_fll fll[2];
+};
+
+static const struct wm_adsp_region cs47l24_dsp2_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x200000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x290000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region cs47l24_dsp3_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x300000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x390000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
+ cs47l24_dsp2_regions,
+ cs47l24_dsp3_regions,
+};
+
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define CS47L24_NG_SRC(name, base) \
+ SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
+ SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
+ SOC_SINGLE(name " NG SPKOUT Switch", base, 6, 1, 0)
+
+static const struct snd_kcontrol_new cs47l24_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+ ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+ ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+ ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+ ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+ ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+ ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+ ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+ ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+ ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
+ ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+ ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
+ ARIZONA_HP1_SC_ENA_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+ ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+ ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+ ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+ 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+ ARIZONA_OUT4L_VOL_SHIFT,
+ 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+ ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+ ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+CS47L24_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+CS47L24_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+CS47L24_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
+static const char * const cs47l24_aec_loopback_texts[] = {
+ "HPOUT1L", "HPOUT1R", "SPKOUT",
+};
+
+static const unsigned int cs47l24_aec_loopback_values[] = {
+ 0, 1, 6,
+};
+
+static const struct soc_enum cs47l24_aec_loopback =
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+ ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+ ARRAY_SIZE(cs47l24_aec_loopback_texts),
+ cs47l24_aec_loopback_texts,
+ cs47l24_aec_loopback_values);
+
+static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =
+ SOC_DAPM_ENUM("AEC Loopback", cs47l24_aec_loopback);
+
+static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
+ ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+ ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+ ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+ ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+ 0, NULL, 0, arizona_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+ 0, NULL, 0, arizona_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+ 0, NULL, 0, arizona_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+ 0, NULL, 0, arizona_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+ ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+ ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+ ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+ ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+ ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+ 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+ 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+ NULL, 0),
+
+WM_ADSP2("DSP2", 1),
+WM_ADSP2("DSP3", 2),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+ ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+ &cs47l24_aec_loopback_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+ ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+ ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+ ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+ ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+ ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+ ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+ ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+ ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
+ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name) \
+ { name, "Noise Generator", "Noise Generator" }, \
+ { name, "Tone Generator 1", "Tone Generator 1" }, \
+ { name, "Tone Generator 2", "Tone Generator 2" }, \
+ { name, "Haptics", "HAPTICS" }, \
+ { name, "AEC", "AEC Loopback" }, \
+ { name, "IN1L", "IN1L PGA" }, \
+ { name, "IN1R", "IN1R PGA" }, \
+ { name, "IN2L", "IN2L PGA" }, \
+ { name, "IN2R", "IN2R PGA" }, \
+ { name, "AIF1RX1", "AIF1RX1" }, \
+ { name, "AIF1RX2", "AIF1RX2" }, \
+ { name, "AIF1RX3", "AIF1RX3" }, \
+ { name, "AIF1RX4", "AIF1RX4" }, \
+ { name, "AIF1RX5", "AIF1RX5" }, \
+ { name, "AIF1RX6", "AIF1RX6" }, \
+ { name, "AIF1RX7", "AIF1RX7" }, \
+ { name, "AIF1RX8", "AIF1RX8" }, \
+ { name, "AIF2RX1", "AIF2RX1" }, \
+ { name, "AIF2RX2", "AIF2RX2" }, \
+ { name, "AIF2RX3", "AIF2RX3" }, \
+ { name, "AIF2RX4", "AIF2RX4" }, \
+ { name, "AIF2RX5", "AIF2RX5" }, \
+ { name, "AIF2RX6", "AIF2RX6" }, \
+ { name, "AIF3RX1", "AIF3RX1" }, \
+ { name, "AIF3RX2", "AIF3RX2" }, \
+ { name, "EQ1", "EQ1" }, \
+ { name, "EQ2", "EQ2" }, \
+ { name, "DRC1L", "DRC1L" }, \
+ { name, "DRC1R", "DRC1R" }, \
+ { name, "DRC2L", "DRC2L" }, \
+ { name, "DRC2R", "DRC2R" }, \
+ { name, "LHPF1", "LHPF1" }, \
+ { name, "LHPF2", "LHPF2" }, \
+ { name, "LHPF3", "LHPF3" }, \
+ { name, "LHPF4", "LHPF4" }, \
+ { name, "ASRC1L", "ASRC1L" }, \
+ { name, "ASRC1R", "ASRC1R" }, \
+ { name, "ASRC2L", "ASRC2L" }, \
+ { name, "ASRC2R", "ASRC2R" }, \
+ { name, "ISRC1DEC1", "ISRC1DEC1" }, \
+ { name, "ISRC1DEC2", "ISRC1DEC2" }, \
+ { name, "ISRC1DEC3", "ISRC1DEC3" }, \
+ { name, "ISRC1DEC4", "ISRC1DEC4" }, \
+ { name, "ISRC1INT1", "ISRC1INT1" }, \
+ { name, "ISRC1INT2", "ISRC1INT2" }, \
+ { name, "ISRC1INT3", "ISRC1INT3" }, \
+ { name, "ISRC1INT4", "ISRC1INT4" }, \
+ { name, "ISRC2DEC1", "ISRC2DEC1" }, \
+ { name, "ISRC2DEC2", "ISRC2DEC2" }, \
+ { name, "ISRC2DEC3", "ISRC2DEC3" }, \
+ { name, "ISRC2DEC4", "ISRC2DEC4" }, \
+ { name, "ISRC2INT1", "ISRC2INT1" }, \
+ { name, "ISRC2INT2", "ISRC2INT2" }, \
+ { name, "ISRC2INT3", "ISRC2INT3" }, \
+ { name, "ISRC2INT4", "ISRC2INT4" }, \
+ { name, "ISRC3DEC1", "ISRC3DEC1" }, \
+ { name, "ISRC3DEC2", "ISRC3DEC2" }, \
+ { name, "ISRC3DEC3", "ISRC3DEC3" }, \
+ { name, "ISRC3DEC4", "ISRC3DEC4" }, \
+ { name, "ISRC3INT1", "ISRC3INT1" }, \
+ { name, "ISRC3INT2", "ISRC3INT2" }, \
+ { name, "ISRC3INT3", "ISRC3INT3" }, \
+ { name, "ISRC3INT4", "ISRC3INT4" }, \
+ { name, "DSP2.1", "DSP2" }, \
+ { name, "DSP2.2", "DSP2" }, \
+ { name, "DSP2.3", "DSP2" }, \
+ { name, "DSP2.4", "DSP2" }, \
+ { name, "DSP2.5", "DSP2" }, \
+ { name, "DSP2.6", "DSP2" }, \
+ { name, "DSP3.1", "DSP3" }, \
+ { name, "DSP3.2", "DSP3" }, \
+ { name, "DSP3.3", "DSP3" }, \
+ { name, "DSP3.4", "DSP3" }, \
+ { name, "DSP3.5", "DSP3" }, \
+ { name, "DSP3.6", "DSP3" }
+
+static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
+ { "OUT1L", NULL, "CPVDD" },
+ { "OUT1R", NULL, "CPVDD" },
+
+ { "OUT4L", NULL, "SPKVDD" },
+
+ { "OUT1L", NULL, "SYSCLK" },
+ { "OUT1R", NULL, "SYSCLK" },
+ { "OUT4L", NULL, "SYSCLK" },
+
+ { "IN1L", NULL, "SYSCLK" },
+ { "IN1R", NULL, "SYSCLK" },
+ { "IN2L", NULL, "SYSCLK" },
+ { "IN2R", NULL, "SYSCLK" },
+
+ { "MICBIAS1", NULL, "MICVDD" },
+ { "MICBIAS2", NULL, "MICVDD" },
+
+ { "Noise Generator", NULL, "SYSCLK" },
+ { "Tone Generator 1", NULL, "SYSCLK" },
+ { "Tone Generator 2", NULL, "SYSCLK" },
+
+ { "Noise Generator", NULL, "NOISE" },
+ { "Tone Generator 1", NULL, "TONE" },
+ { "Tone Generator 2", NULL, "TONE" },
+
+ { "AIF1 Capture", NULL, "AIF1TX1" },
+ { "AIF1 Capture", NULL, "AIF1TX2" },
+ { "AIF1 Capture", NULL, "AIF1TX3" },
+ { "AIF1 Capture", NULL, "AIF1TX4" },
+ { "AIF1 Capture", NULL, "AIF1TX5" },
+ { "AIF1 Capture", NULL, "AIF1TX6" },
+ { "AIF1 Capture", NULL, "AIF1TX7" },
+ { "AIF1 Capture", NULL, "AIF1TX8" },
+
+ { "AIF1RX1", NULL, "AIF1 Playback" },
+ { "AIF1RX2", NULL, "AIF1 Playback" },
+ { "AIF1RX3", NULL, "AIF1 Playback" },
+ { "AIF1RX4", NULL, "AIF1 Playback" },
+ { "AIF1RX5", NULL, "AIF1 Playback" },
+ { "AIF1RX6", NULL, "AIF1 Playback" },
+ { "AIF1RX7", NULL, "AIF1 Playback" },
+ { "AIF1RX8", NULL, "AIF1 Playback" },
+
+ { "AIF2 Capture", NULL, "AIF2TX1" },
+ { "AIF2 Capture", NULL, "AIF2TX2" },
+ { "AIF2 Capture", NULL, "AIF2TX3" },
+ { "AIF2 Capture", NULL, "AIF2TX4" },
+ { "AIF2 Capture", NULL, "AIF2TX5" },
+ { "AIF2 Capture", NULL, "AIF2TX6" },
+
+ { "AIF2RX1", NULL, "AIF2 Playback" },
+ { "AIF2RX2", NULL, "AIF2 Playback" },
+ { "AIF2RX3", NULL, "AIF2 Playback" },
+ { "AIF2RX4", NULL, "AIF2 Playback" },
+ { "AIF2RX5", NULL, "AIF2 Playback" },
+ { "AIF2RX6", NULL, "AIF2 Playback" },
+
+ { "AIF3 Capture", NULL, "AIF3TX1" },
+ { "AIF3 Capture", NULL, "AIF3TX2" },
+
+ { "AIF3RX1", NULL, "AIF3 Playback" },
+ { "AIF3RX2", NULL, "AIF3 Playback" },
+
+ { "AIF1 Playback", NULL, "SYSCLK" },
+ { "AIF2 Playback", NULL, "SYSCLK" },
+ { "AIF3 Playback", NULL, "SYSCLK" },
+
+ { "AIF1 Capture", NULL, "SYSCLK" },
+ { "AIF2 Capture", NULL, "SYSCLK" },
+ { "AIF3 Capture", NULL, "SYSCLK" },
+
+ { "IN1L PGA", NULL, "IN1L" },
+ { "IN1R PGA", NULL, "IN1R" },
+
+ { "IN2L PGA", NULL, "IN2L" },
+ { "IN2R PGA", NULL, "IN2R" },
+
+ ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+ ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+
+ ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+
+ ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+ ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+ ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+ ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+ ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+ ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+ ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+ ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+ ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+ ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+ ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+ ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+ ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+ ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+ ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+ ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+ ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+ ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+ ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+ ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+
+ ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+ ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+ ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
+ ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+ ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+ ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+ ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+ ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+ ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+ ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+ ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+ ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+ ARIZONA_DSP_ROUTES("DSP2"),
+ ARIZONA_DSP_ROUTES("DSP3"),
+
+ ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+ ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+ ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+ ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+ ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+ ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+ ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+ ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+ ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+ ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+ ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+ ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+ ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+ ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+ ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+ ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+ ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+ ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+ ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+ ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+ ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+ ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+ ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+ ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
+ { "AEC Loopback", "HPOUT1L", "OUT1L" },
+ { "AEC Loopback", "HPOUT1R", "OUT1R" },
+ { "HPOUT1L", NULL, "OUT1L" },
+ { "HPOUT1R", NULL, "OUT1R" },
+
+ { "AEC Loopback", "SPKOUT", "OUT4L" },
+ { "SPKOUTN", NULL, "OUT4L" },
+ { "SPKOUTP", NULL, "OUT4L" },
+
+ { "MICSUPP", NULL, "SYSCLK" },
+
+ { "DRC1 Signal Activity", NULL, "DRC1L" },
+ { "DRC1 Signal Activity", NULL, "DRC1R" },
+ { "DRC2 Signal Activity", NULL, "DRC2L" },
+ { "DRC2 Signal Activity", NULL, "DRC2R" },
+};
+
+static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+ unsigned int Fref, unsigned int Fout)
+{
+ struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec);
+
+ switch (fll_id) {
+ case CS47L24_FLL1:
+ return arizona_set_fll(&cs47l24->fll[0], source, Fref, Fout);
+ case CS47L24_FLL2:
+ return arizona_set_fll(&cs47l24->fll[1], source, Fref, Fout);
+ case CS47L24_FLL1_REFCLK:
+ return arizona_set_fll_refclk(&cs47l24->fll[0], source, Fref,
+ Fout);
+ case CS47L24_FLL2_REFCLK:
+ return arizona_set_fll_refclk(&cs47l24->fll[1], source, Fref,
+ Fout);
+ default:
+ return -EINVAL;
+ }
+}
+
+#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000
+
+#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver cs47l24_dai[] = {
+ {
+ .name = "cs47l24-aif1",
+ .id = 1,
+ .base = ARIZONA_AIF1_BCLK_CTRL,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .ops = &arizona_dai_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+ {
+ .name = "cs47l24-aif2",
+ .id = 2,
+ .base = ARIZONA_AIF2_BCLK_CTRL,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .ops = &arizona_dai_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+ {
+ .name = "cs47l24-aif3",
+ .id = 3,
+ .base = ARIZONA_AIF3_BCLK_CTRL,
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .ops = &arizona_dai_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
+ },
+};
+
+static int cs47l24_codec_probe(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ priv->core.arizona->dapm = dapm;
+
+ arizona_init_spk(codec);
+ arizona_init_gpio(codec);
+ arizona_init_mono(codec);
+
+ ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
+ if (ret)
+ goto err_adsp2_codec_probe;
+
+ ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec);
+ if (ret)
+ goto err_adsp2_codec_probe;
+
+ ret = snd_soc_add_codec_controls(codec,
+ &arizona_adsp2_rate_controls[1], 2);
+ if (ret)
+ goto err_adsp2_codec_probe;
+
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+
+ return 0;
+
+err_adsp2_codec_probe:
+ wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
+ wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+
+ return ret;
+}
+
+static int cs47l24_codec_remove(struct snd_soc_codec *codec)
+{
+ struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+
+ wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
+ wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+
+ priv->core.arizona->dapm = NULL;
+
+ return 0;
+}
+
+#define CS47L24_DIG_VU 0x0200
+
+static unsigned int cs47l24_digital_vu[] = {
+ ARIZONA_DAC_DIGITAL_VOLUME_1L,
+ ARIZONA_DAC_DIGITAL_VOLUME_1R,
+ ARIZONA_DAC_DIGITAL_VOLUME_4L,
+};
+
+static struct regmap *cs47l24_get_regmap(struct device *dev)
+{
+ struct cs47l24_priv *priv = dev_get_drvdata(dev);
+
+ return priv->core.arizona->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
+ .probe = cs47l24_codec_probe,
+ .remove = cs47l24_codec_remove,
+ .get_regmap = cs47l24_get_regmap,
+
+ .idle_bias_off = true,
+
+ .set_sysclk = arizona_set_sysclk,
+ .set_pll = cs47l24_set_fll,
+
+ .controls = cs47l24_snd_controls,
+ .num_controls = ARRAY_SIZE(cs47l24_snd_controls),
+ .dapm_widgets = cs47l24_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets),
+ .dapm_routes = cs47l24_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
+};
+
+static int cs47l24_probe(struct platform_device *pdev)
+{
+ struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+ struct cs47l24_priv *cs47l24;
+ int i, ret;
+
+ BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI);
+
+ cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv),
+ GFP_KERNEL);
+ if (!cs47l24)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, cs47l24);
+
+ cs47l24->core.arizona = arizona;
+ cs47l24->core.num_inputs = 4;
+
+ for (i = 1; i <= 2; i++) {
+ cs47l24->core.adsp[i].part = "cs47l24";
+ cs47l24->core.adsp[i].num = i + 1;
+ cs47l24->core.adsp[i].type = WMFW_ADSP2;
+ cs47l24->core.adsp[i].dev = arizona->dev;
+ cs47l24->core.adsp[i].regmap = arizona->regmap;
+
+ cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 +
+ (0x100 * i);
+ cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1];
+ cs47l24->core.adsp[i].num_mems =
+ ARRAY_SIZE(cs47l24_dsp2_regions);
+
+ ret = wm_adsp2_init(&cs47l24->core.adsp[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs47l24->fll); i++)
+ cs47l24->fll[i].vco_mult = 3;
+
+ arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+ ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+ &cs47l24->fll[0]);
+ arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+ ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+ &cs47l24->fll[1]);
+
+ /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+ regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+ ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+ regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+ ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+ for (i = 0; i < ARRAY_SIZE(cs47l24_dai); i++)
+ arizona_init_dai(&cs47l24->core, i);
+
+ /* Latch volume update bits */
+ for (i = 0; i < ARRAY_SIZE(cs47l24_digital_vu); i++)
+ regmap_update_bits(arizona->regmap, cs47l24_digital_vu[i],
+ CS47L24_DIG_VU, CS47L24_DIG_VU);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
+ cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
+}
+
+static int cs47l24_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver cs47l24_codec_driver = {
+ .driver = {
+ .name = "cs47l24-codec",
+ },
+ .probe = cs47l24_probe,
+ .remove = cs47l24_remove,
+};
+
+module_platform_driver(cs47l24_codec_driver);
+
+MODULE_DESCRIPTION("ASoC CS47L24 driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cs47l24-codec");
diff --git a/sound/soc/codecs/cs47l24.h b/sound/soc/codecs/cs47l24.h
new file mode 100644
index 000000000000..77ab2b77b2e6
--- /dev/null
+++ b/sound/soc/codecs/cs47l24.h
@@ -0,0 +1,23 @@
+/*
+ * cs47l24.h -- ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.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 _CS47L24_H
+#define _CS47L24_H
+
+#include "arizona.h"
+
+#define CS47L24_FLL1 1
+#define CS47L24_FLL2 2
+#define CS47L24_FLL1_REFCLK 3
+#define CS47L24_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
new file mode 100644
index 000000000000..93575f251866
--- /dev/null
+++ b/sound/soc/codecs/da7218.c
@@ -0,0 +1,3341 @@
+/*
+ * da7218.c - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include <sound/da7218.h>
+#include "da7218.h"
+
+
+/*
+ * TLVs and Enums
+ */
+
+/* Input TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_mic_gain_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_in_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_trigger_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_att_max_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_ana_gain_tlv, 0, 600, 0);
+
+/* Input/Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dmix_gain_tlv, -4200, 150, 0);
+
+/* Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_trigger_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_anticlip_tlv, -4200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_signal_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_eq_band_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dac_ng_threshold_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixout_gain_tlv, -100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_hp_gain_tlv, -5700, 150, 0);
+
+/* Input Enums */
+static const char * const da7218_alc_attack_rate_txt[] = {
+ "7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs",
+ "469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs",
+ "30024/fs",
+};
+
+static const struct soc_enum da7218_alc_attack_rate =
+ SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_ATTACK_SHIFT,
+ DA7218_ALC_ATTACK_MAX, da7218_alc_attack_rate_txt);
+
+static const char * const da7218_alc_release_rate_txt[] = {
+ "28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs",
+ "1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs",
+};
+
+static const struct soc_enum da7218_alc_release_rate =
+ SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_RELEASE_SHIFT,
+ DA7218_ALC_RELEASE_MAX, da7218_alc_release_rate_txt);
+
+static const char * const da7218_alc_hold_time_txt[] = {
+ "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+ "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+ "253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da7218_alc_hold_time =
+ SOC_ENUM_SINGLE(DA7218_ALC_CTRL3, DA7218_ALC_HOLD_SHIFT,
+ DA7218_ALC_HOLD_MAX, da7218_alc_hold_time_txt);
+
+static const char * const da7218_alc_anticlip_step_txt[] = {
+ "0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs",
+};
+
+static const struct soc_enum da7218_alc_anticlip_step =
+ SOC_ENUM_SINGLE(DA7218_ALC_ANTICLIP_CTRL,
+ DA7218_ALC_ANTICLIP_STEP_SHIFT,
+ DA7218_ALC_ANTICLIP_STEP_MAX,
+ da7218_alc_anticlip_step_txt);
+
+static const char * const da7218_integ_rate_txt[] = {
+ "1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da7218_integ_attack_rate =
+ SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_ATTACK_SHIFT,
+ DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+static const struct soc_enum da7218_integ_release_rate =
+ SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_RELEASE_SHIFT,
+ DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+/* Input/Output Enums */
+static const char * const da7218_gain_ramp_rate_txt[] = {
+ "Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8",
+ "Nominal Rate / 16",
+};
+
+static const struct soc_enum da7218_gain_ramp_rate =
+ SOC_ENUM_SINGLE(DA7218_GAIN_RAMP_CTRL, DA7218_GAIN_RAMP_RATE_SHIFT,
+ DA7218_GAIN_RAMP_RATE_MAX, da7218_gain_ramp_rate_txt);
+
+static const char * const da7218_hpf_mode_txt[] = {
+ "Disabled", "Audio", "Voice",
+};
+
+static const unsigned int da7218_hpf_mode_val[] = {
+ DA7218_HPF_DISABLED, DA7218_HPF_AUDIO_EN, DA7218_HPF_VOICE_EN,
+};
+
+static const struct soc_enum da7218_in1_hpf_mode =
+ SOC_VALUE_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+ DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+ DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+ da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_in2_hpf_mode =
+ SOC_VALUE_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+ DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+ DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+ da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_out1_hpf_mode =
+ SOC_VALUE_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+ DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+ DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+ da7218_hpf_mode_val);
+
+static const char * const da7218_audio_hpf_corner_txt[] = {
+ "2Hz", "4Hz", "8Hz", "16Hz",
+};
+
+static const struct soc_enum da7218_in1_audio_hpf_corner =
+ SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+ DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT,
+ DA7218_AUDIO_HPF_CORNER_MAX,
+ da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_audio_hpf_corner =
+ SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+ DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT,
+ DA7218_AUDIO_HPF_CORNER_MAX,
+ da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_audio_hpf_corner =
+ SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+ DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT,
+ DA7218_AUDIO_HPF_CORNER_MAX,
+ da7218_audio_hpf_corner_txt);
+
+static const char * const da7218_voice_hpf_corner_txt[] = {
+ "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz",
+};
+
+static const struct soc_enum da7218_in1_voice_hpf_corner =
+ SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+ DA7218_IN_1_VOICE_HPF_CORNER_SHIFT,
+ DA7218_VOICE_HPF_CORNER_MAX,
+ da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_voice_hpf_corner =
+ SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+ DA7218_IN_2_VOICE_HPF_CORNER_SHIFT,
+ DA7218_VOICE_HPF_CORNER_MAX,
+ da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_voice_hpf_corner =
+ SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+ DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT,
+ DA7218_VOICE_HPF_CORNER_MAX,
+ da7218_voice_hpf_corner_txt);
+
+static const char * const da7218_tonegen_dtmf_key_txt[] = {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+ "*", "#"
+};
+
+static const struct soc_enum da7218_tonegen_dtmf_key =
+ SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG1, DA7218_DTMF_REG_SHIFT,
+ DA7218_DTMF_REG_MAX, da7218_tonegen_dtmf_key_txt);
+
+static const char * const da7218_tonegen_swg_sel_txt[] = {
+ "Sum", "SWG1", "SWG2", "SWG1_1-Cos"
+};
+
+static const struct soc_enum da7218_tonegen_swg_sel =
+ SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG2, DA7218_SWG_SEL_SHIFT,
+ DA7218_SWG_SEL_MAX, da7218_tonegen_swg_sel_txt);
+
+/* Output Enums */
+static const char * const da7218_dgs_rise_coeff_txt[] = {
+ "1/1", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384",
+};
+
+static const struct soc_enum da7218_dgs_rise_coeff =
+ SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_RISE_COEFF_SHIFT,
+ DA7218_DGS_RISE_COEFF_MAX, da7218_dgs_rise_coeff_txt);
+
+static const char * const da7218_dgs_fall_coeff_txt[] = {
+ "1/4", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", "1/65536",
+};
+
+static const struct soc_enum da7218_dgs_fall_coeff =
+ SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_FALL_COEFF_SHIFT,
+ DA7218_DGS_FALL_COEFF_MAX, da7218_dgs_fall_coeff_txt);
+
+static const char * const da7218_dac_ng_setup_time_txt[] = {
+ "256 Samples", "512 Samples", "1024 Samples", "2048 Samples"
+};
+
+static const struct soc_enum da7218_dac_ng_setup_time =
+ SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+ DA7218_DAC_NG_SETUP_TIME_SHIFT,
+ DA7218_DAC_NG_SETUP_TIME_MAX,
+ da7218_dac_ng_setup_time_txt);
+
+static const char * const da7218_dac_ng_rampup_txt[] = {
+ "0.22ms/dB", "0.0138ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampup_rate =
+ SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+ DA7218_DAC_NG_RAMPUP_RATE_SHIFT,
+ DA7218_DAC_NG_RAMPUP_RATE_MAX,
+ da7218_dac_ng_rampup_txt);
+
+static const char * const da7218_dac_ng_rampdown_txt[] = {
+ "0.88ms/dB", "14.08ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampdown_rate =
+ SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+ DA7218_DAC_NG_RAMPDN_RATE_SHIFT,
+ DA7218_DAC_NG_RAMPDN_RATE_MAX,
+ da7218_dac_ng_rampdown_txt);
+
+static const char * const da7218_cp_mchange_txt[] = {
+ "Largest Volume", "DAC Volume", "Signal Magnitude"
+};
+
+static const unsigned int da7218_cp_mchange_val[] = {
+ DA7218_CP_MCHANGE_LARGEST_VOL, DA7218_CP_MCHANGE_DAC_VOL,
+ DA7218_CP_MCHANGE_SIG_MAG
+};
+
+static const struct soc_enum da7218_cp_mchange =
+ SOC_VALUE_ENUM_SINGLE(DA7218_CP_CTRL, DA7218_CP_MCHANGE_SHIFT,
+ DA7218_CP_MCHANGE_REL_MASK, DA7218_CP_MCHANGE_MAX,
+ da7218_cp_mchange_txt, da7218_cp_mchange_val);
+
+static const char * const da7218_cp_fcontrol_txt[] = {
+ "1MHz", "500KHz", "250KHz", "125KHz", "63KHz", "0KHz"
+};
+
+static const struct soc_enum da7218_cp_fcontrol =
+ SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_FCONTROL_SHIFT,
+ DA7218_CP_FCONTROL_MAX, da7218_cp_fcontrol_txt);
+
+static const char * const da7218_cp_tau_delay_txt[] = {
+ "0ms", "2ms", "4ms", "16ms", "64ms", "128ms", "256ms", "512ms"
+};
+
+static const struct soc_enum da7218_cp_tau_delay =
+ SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_TAU_DELAY_SHIFT,
+ DA7218_CP_TAU_DELAY_MAX, da7218_cp_tau_delay_txt);
+
+/*
+ * Control Functions
+ */
+
+/* ALC */
+static void da7218_alc_calib(struct snd_soc_codec *codec)
+{
+ u8 mic_1_ctrl, mic_2_ctrl;
+ u8 mixin_1_ctrl, mixin_2_ctrl;
+ u8 in_1l_filt_ctrl, in_1r_filt_ctrl, in_2l_filt_ctrl, in_2r_filt_ctrl;
+ u8 in_1_hpf_ctrl, in_2_hpf_ctrl;
+ u8 calib_ctrl;
+ int i = 0;
+ bool calibrated = false;
+
+ /* Save current state of MIC control registers */
+ mic_1_ctrl = snd_soc_read(codec, DA7218_MIC_1_CTRL);
+ mic_2_ctrl = snd_soc_read(codec, DA7218_MIC_2_CTRL);
+
+ /* Save current state of input mixer control registers */
+ mixin_1_ctrl = snd_soc_read(codec, DA7218_MIXIN_1_CTRL);
+ mixin_2_ctrl = snd_soc_read(codec, DA7218_MIXIN_2_CTRL);
+
+ /* Save current state of input filter control registers */
+ in_1l_filt_ctrl = snd_soc_read(codec, DA7218_IN_1L_FILTER_CTRL);
+ in_1r_filt_ctrl = snd_soc_read(codec, DA7218_IN_1R_FILTER_CTRL);
+ in_2l_filt_ctrl = snd_soc_read(codec, DA7218_IN_2L_FILTER_CTRL);
+ in_2r_filt_ctrl = snd_soc_read(codec, DA7218_IN_2R_FILTER_CTRL);
+
+ /* Save current state of input HPF control registers */
+ in_1_hpf_ctrl = snd_soc_read(codec, DA7218_IN_1_HPF_FILTER_CTRL);
+ in_2_hpf_ctrl = snd_soc_read(codec, DA7218_IN_2_HPF_FILTER_CTRL);
+
+ /* Enable then Mute MIC PGAs */
+ snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK,
+ DA7218_MIC_1_AMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK,
+ DA7218_MIC_2_AMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_MIC_1_CTRL,
+ DA7218_MIC_1_AMP_MUTE_EN_MASK,
+ DA7218_MIC_1_AMP_MUTE_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_MIC_2_CTRL,
+ DA7218_MIC_2_AMP_MUTE_EN_MASK,
+ DA7218_MIC_2_AMP_MUTE_EN_MASK);
+
+ /* Enable input mixers unmuted */
+ snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_AMP_EN_MASK |
+ DA7218_MIXIN_1_AMP_MUTE_EN_MASK,
+ DA7218_MIXIN_1_AMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_AMP_EN_MASK |
+ DA7218_MIXIN_2_AMP_MUTE_EN_MASK,
+ DA7218_MIXIN_2_AMP_EN_MASK);
+
+ /* Enable input filters unmuted */
+ snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+ DA7218_IN_1L_FILTER_EN_MASK |
+ DA7218_IN_1L_MUTE_EN_MASK,
+ DA7218_IN_1L_FILTER_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+ DA7218_IN_1R_FILTER_EN_MASK |
+ DA7218_IN_1R_MUTE_EN_MASK,
+ DA7218_IN_1R_FILTER_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+ DA7218_IN_2L_FILTER_EN_MASK |
+ DA7218_IN_2L_MUTE_EN_MASK,
+ DA7218_IN_2L_FILTER_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+ DA7218_IN_2R_FILTER_EN_MASK |
+ DA7218_IN_2R_MUTE_EN_MASK,
+ DA7218_IN_2R_FILTER_EN_MASK);
+
+ /*
+ * Make sure input HPFs voice mode is disabled, otherwise for sampling
+ * rates above 32KHz the ADC signals will be stopped and will cause
+ * calibration to lock up.
+ */
+ snd_soc_update_bits(codec, DA7218_IN_1_HPF_FILTER_CTRL,
+ DA7218_IN_1_VOICE_EN_MASK, 0);
+ snd_soc_update_bits(codec, DA7218_IN_2_HPF_FILTER_CTRL,
+ DA7218_IN_2_VOICE_EN_MASK, 0);
+
+ /* Perform auto calibration */
+ snd_soc_update_bits(codec, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK,
+ DA7218_CALIB_AUTO_EN_MASK);
+ do {
+ calib_ctrl = snd_soc_read(codec, DA7218_CALIB_CTRL);
+ if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) {
+ ++i;
+ usleep_range(DA7218_ALC_CALIB_DELAY_MIN,
+ DA7218_ALC_CALIB_DELAY_MAX);
+ } else {
+ calibrated = true;
+ }
+
+ } while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated));
+
+ /* If auto calibration fails, disable DC offset, hybrid ALC */
+ if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) {
+ dev_warn(codec->dev,
+ "ALC auto calibration failed - %s\n",
+ (calibrated) ? "overflow" : "timeout");
+ snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+ DA7218_CALIB_OFFSET_EN_MASK, 0);
+ snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+ DA7218_ALC_SYNC_MODE_MASK, 0);
+
+ } else {
+ /* Enable DC offset cancellation */
+ snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+ DA7218_CALIB_OFFSET_EN_MASK,
+ DA7218_CALIB_OFFSET_EN_MASK);
+
+ /* Enable ALC hybrid mode */
+ snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+ DA7218_ALC_SYNC_MODE_MASK,
+ DA7218_ALC_SYNC_MODE_CH1 |
+ DA7218_ALC_SYNC_MODE_CH2);
+ }
+
+ /* Restore input HPF control registers to original states */
+ snd_soc_write(codec, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
+ snd_soc_write(codec, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);
+
+ /* Restore input filter control registers to original states */
+ snd_soc_write(codec, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
+ snd_soc_write(codec, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
+ snd_soc_write(codec, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
+ snd_soc_write(codec, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);
+
+ /* Restore input mixer control registers to original state */
+ snd_soc_write(codec, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
+ snd_soc_write(codec, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);
+
+ /* Restore MIC control registers to original states */
+ snd_soc_write(codec, DA7218_MIC_1_CTRL, mic_1_ctrl);
+ snd_soc_write(codec, DA7218_MIC_2_CTRL, mic_2_ctrl);
+}
+
+static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+ /*
+ * If ALC in operation and value of control has been updated,
+ * make sure calibrated offsets are updated.
+ */
+ if ((ret == 1) && (da7218->alc_en))
+ da7218_alc_calib(codec);
+
+ return ret;
+}
+
+static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ unsigned int lvalue = ucontrol->value.integer.value[0];
+ unsigned int rvalue = ucontrol->value.integer.value[1];
+ unsigned int lshift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ unsigned int mask = (mc->max << lshift) | (mc->max << rshift);
+
+ /* Force ALC offset calibration if enabling ALC */
+ if ((lvalue || rvalue) && (!da7218->alc_en))
+ da7218_alc_calib(codec);
+
+ /* Update bits to detail which channels are enabled/disabled */
+ da7218->alc_en &= ~mask;
+ da7218->alc_en |= (lvalue << lshift) | (rvalue << rshift);
+
+ return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* ToneGen */
+static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct soc_mixer_control *mixer_ctrl =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ unsigned int reg = mixer_ctrl->reg;
+ u16 val;
+ int ret;
+
+ /*
+ * Frequency value spans two 8-bit registers, lower then upper byte.
+ * Therefore we need to convert to host endianness here.
+ */
+ ret = regmap_raw_read(da7218->regmap, reg, &val, 2);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+ return 0;
+}
+
+static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct soc_mixer_control *mixer_ctrl =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ unsigned int reg = mixer_ctrl->reg;
+ u16 val;
+
+ /*
+ * Frequency value spans two 8-bit registers, lower then upper byte.
+ * Therefore we need to convert to little endian here to align with
+ * HW registers.
+ */
+ val = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+ return regmap_raw_write(da7218->regmap, reg, &val, 2);
+}
+
+static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct soc_mixer_control *mixer_ctrl =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ unsigned int lvalue = ucontrol->value.integer.value[0];
+ unsigned int rvalue = ucontrol->value.integer.value[1];
+ unsigned int lshift = mixer_ctrl->shift;
+ unsigned int rshift = mixer_ctrl->rshift;
+ unsigned int mask = (mixer_ctrl->max << lshift) |
+ (mixer_ctrl->max << rshift);
+ da7218->mic_lvl_det_en &= ~mask;
+ da7218->mic_lvl_det_en |= (lvalue << lshift) | (rvalue << rshift);
+
+ /*
+ * Here we only enable the feature on paths which are already
+ * powered. If a channel is enabled here for level detect, but that path
+ * isn't powered, then the channel will actually be enabled when we do
+ * power the path (IN_FILTER widget events). This handling avoids
+ * unwanted level detect events.
+ */
+ return snd_soc_write(codec, mixer_ctrl->reg,
+ (da7218->in_filt_en & da7218->mic_lvl_det_en));
+}
+
+static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct soc_mixer_control *mixer_ctrl =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ unsigned int lshift = mixer_ctrl->shift;
+ unsigned int rshift = mixer_ctrl->rshift;
+ unsigned int lmask = (mixer_ctrl->max << lshift);
+ unsigned int rmask = (mixer_ctrl->max << rshift);
+
+ ucontrol->value.integer.value[0] =
+ (da7218->mic_lvl_det_en & lmask) >> lshift;
+ ucontrol->value.integer.value[1] =
+ (da7218->mic_lvl_det_en & rmask) >> rshift;
+
+ return 0;
+}
+
+static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+
+ /* Determine which BiQuads we're setting based on size of config data */
+ switch (bytes_ext->max) {
+ case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+ memcpy(ucontrol->value.bytes.data, da7218->biq_5stage_coeff,
+ bytes_ext->max);
+ break;
+ case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+ memcpy(ucontrol->value.bytes.data, da7218->stbiq_3stage_coeff,
+ bytes_ext->max);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ u8 reg, out_filt1l;
+ u8 cfg[DA7218_BIQ_CFG_SIZE];
+ int i;
+
+ /*
+ * Determine which BiQuads we're setting based on size of config data,
+ * and stored the data for use by get function.
+ */
+ switch (bytes_ext->max) {
+ case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+ reg = DA7218_OUT_1_BIQ_5STAGE_DATA;
+ memcpy(da7218->biq_5stage_coeff, ucontrol->value.bytes.data,
+ bytes_ext->max);
+ break;
+ case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+ reg = DA7218_SIDETONE_BIQ_3STAGE_DATA;
+ memcpy(da7218->stbiq_3stage_coeff, ucontrol->value.bytes.data,
+ bytes_ext->max);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Make sure at least out filter1 enabled to allow programming */
+ out_filt1l = snd_soc_read(codec, DA7218_OUT_1L_FILTER_CTRL);
+ snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL,
+ out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK);
+
+ for (i = 0; i < bytes_ext->max; ++i) {
+ cfg[DA7218_BIQ_CFG_DATA] = ucontrol->value.bytes.data[i];
+ cfg[DA7218_BIQ_CFG_ADDR] = i;
+ regmap_raw_write(da7218->regmap, reg, cfg, DA7218_BIQ_CFG_SIZE);
+ }
+
+ /* Restore filter to previous setting */
+ snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, out_filt1l);
+
+ return 0;
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7218_snd_controls[] = {
+ /* Mics */
+ SOC_SINGLE_TLV("Mic1 Volume", DA7218_MIC_1_GAIN,
+ DA7218_MIC_1_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_mic_gain_tlv),
+ SOC_SINGLE("Mic1 Switch", DA7218_MIC_1_CTRL,
+ DA7218_MIC_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE_TLV("Mic2 Volume", DA7218_MIC_2_GAIN,
+ DA7218_MIC_2_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_mic_gain_tlv),
+ SOC_SINGLE("Mic2 Switch", DA7218_MIC_2_CTRL,
+ DA7218_MIC_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+
+ /* Mixer Input */
+ SOC_SINGLE_EXT_TLV("Mixin1 Volume", DA7218_MIXIN_1_GAIN,
+ DA7218_MIXIN_1_AMP_GAIN_SHIFT,
+ DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+ snd_soc_get_volsw, da7218_mixin_gain_put,
+ da7218_mixin_gain_tlv),
+ SOC_SINGLE("Mixin1 Switch", DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE("Mixin1 Gain Ramp Switch", DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("Mixin1 ZC Gain Switch", DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE_EXT_TLV("Mixin2 Volume", DA7218_MIXIN_2_GAIN,
+ DA7218_MIXIN_2_AMP_GAIN_SHIFT,
+ DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+ snd_soc_get_volsw, da7218_mixin_gain_put,
+ da7218_mixin_gain_tlv),
+ SOC_SINGLE("Mixin2 Switch", DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE("Mixin2 Gain Ramp Switch", DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("Mixin2 ZC Gain Switch", DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+
+ /* ADCs */
+ SOC_SINGLE("ADC1 AAF Switch", DA7218_ADC_1_CTRL,
+ DA7218_ADC_1_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("ADC2 AAF Switch", DA7218_ADC_2_CTRL,
+ DA7218_ADC_2_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("ADC LP Mode Switch", DA7218_ADC_MODE,
+ DA7218_ADC_LP_MODE_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+
+ /* Input Filters */
+ SOC_SINGLE_TLV("In Filter1L Volume", DA7218_IN_1L_GAIN,
+ DA7218_IN_1L_DIGITAL_GAIN_SHIFT,
+ DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_in_dig_gain_tlv),
+ SOC_SINGLE("In Filter1L Switch", DA7218_IN_1L_FILTER_CTRL,
+ DA7218_IN_1L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE("In Filter1L Gain Ramp Switch", DA7218_IN_1L_FILTER_CTRL,
+ DA7218_IN_1L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE_TLV("In Filter1R Volume", DA7218_IN_1R_GAIN,
+ DA7218_IN_1R_DIGITAL_GAIN_SHIFT,
+ DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_in_dig_gain_tlv),
+ SOC_SINGLE("In Filter1R Switch", DA7218_IN_1R_FILTER_CTRL,
+ DA7218_IN_1R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE("In Filter1R Gain Ramp Switch",
+ DA7218_IN_1R_FILTER_CTRL, DA7218_IN_1R_RAMP_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+ SOC_SINGLE_TLV("In Filter2L Volume", DA7218_IN_2L_GAIN,
+ DA7218_IN_2L_DIGITAL_GAIN_SHIFT,
+ DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_in_dig_gain_tlv),
+ SOC_SINGLE("In Filter2L Switch", DA7218_IN_2L_FILTER_CTRL,
+ DA7218_IN_2L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE("In Filter2L Gain Ramp Switch", DA7218_IN_2L_FILTER_CTRL,
+ DA7218_IN_2L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE_TLV("In Filter2R Volume", DA7218_IN_2R_GAIN,
+ DA7218_IN_2R_DIGITAL_GAIN_SHIFT,
+ DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_in_dig_gain_tlv),
+ SOC_SINGLE("In Filter2R Switch", DA7218_IN_2R_FILTER_CTRL,
+ DA7218_IN_2R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_SINGLE("In Filter2R Gain Ramp Switch",
+ DA7218_IN_2R_FILTER_CTRL, DA7218_IN_2R_RAMP_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+ /* AGS */
+ SOC_SINGLE_TLV("AGS Trigger", DA7218_AGS_TRIGGER,
+ DA7218_AGS_TRIGGER_SHIFT, DA7218_AGS_TRIGGER_MAX,
+ DA7218_INVERT, da7218_ags_trigger_tlv),
+ SOC_SINGLE_TLV("AGS Max Attenuation", DA7218_AGS_ATT_MAX,
+ DA7218_AGS_ATT_MAX_SHIFT, DA7218_AGS_ATT_MAX_MAX,
+ DA7218_NO_INVERT, da7218_ags_att_max_tlv),
+ SOC_SINGLE("AGS Anticlip Switch", DA7218_AGS_ANTICLIP_CTRL,
+ DA7218_AGS_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("AGS Channel1 Switch", DA7218_AGS_ENABLE,
+ DA7218_AGS_ENABLE_CHAN1_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("AGS Channel2 Switch", DA7218_AGS_ENABLE,
+ DA7218_AGS_ENABLE_CHAN2_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+
+ /* ALC */
+ SOC_ENUM("ALC Attack Rate", da7218_alc_attack_rate),
+ SOC_ENUM("ALC Release Rate", da7218_alc_release_rate),
+ SOC_ENUM("ALC Hold Time", da7218_alc_hold_time),
+ SOC_SINGLE_TLV("ALC Noise Threshold", DA7218_ALC_NOISE,
+ DA7218_ALC_NOISE_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+ DA7218_INVERT, da7218_alc_threshold_tlv),
+ SOC_SINGLE_TLV("ALC Min Threshold", DA7218_ALC_TARGET_MIN,
+ DA7218_ALC_THRESHOLD_MIN_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+ DA7218_INVERT, da7218_alc_threshold_tlv),
+ SOC_SINGLE_TLV("ALC Max Threshold", DA7218_ALC_TARGET_MAX,
+ DA7218_ALC_THRESHOLD_MAX_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+ DA7218_INVERT, da7218_alc_threshold_tlv),
+ SOC_SINGLE_TLV("ALC Max Attenuation", DA7218_ALC_GAIN_LIMITS,
+ DA7218_ALC_ATTEN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_alc_gain_tlv),
+ SOC_SINGLE_TLV("ALC Max Gain", DA7218_ALC_GAIN_LIMITS,
+ DA7218_ALC_GAIN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("ALC Min Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+ DA7218_ALC_ANA_GAIN_MIN_SHIFT,
+ DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("ALC Max Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+ DA7218_ALC_ANA_GAIN_MAX_SHIFT,
+ DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+ SOC_ENUM("ALC Anticlip Step", da7218_alc_anticlip_step),
+ SOC_SINGLE("ALC Anticlip Switch", DA7218_ALC_ANTICLIP_CTRL,
+ DA7218_ALC_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_DOUBLE_EXT("ALC Channel1 Switch", DA7218_ALC_CTRL1,
+ DA7218_ALC_CHAN1_L_EN_SHIFT, DA7218_ALC_CHAN1_R_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+ snd_soc_get_volsw, da7218_alc_sw_put),
+ SOC_DOUBLE_EXT("ALC Channel2 Switch", DA7218_ALC_CTRL1,
+ DA7218_ALC_CHAN2_L_EN_SHIFT, DA7218_ALC_CHAN2_R_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+ snd_soc_get_volsw, da7218_alc_sw_put),
+
+ /* Envelope Tracking */
+ SOC_ENUM("Envelope Tracking Attack Rate", da7218_integ_attack_rate),
+ SOC_ENUM("Envelope Tracking Release Rate", da7218_integ_release_rate),
+
+ /* Input High-Pass Filters */
+ SOC_ENUM("In Filter1 HPF Mode", da7218_in1_hpf_mode),
+ SOC_ENUM("In Filter1 HPF Corner Audio", da7218_in1_audio_hpf_corner),
+ SOC_ENUM("In Filter1 HPF Corner Voice", da7218_in1_voice_hpf_corner),
+ SOC_ENUM("In Filter2 HPF Mode", da7218_in2_hpf_mode),
+ SOC_ENUM("In Filter2 HPF Corner Audio", da7218_in2_audio_hpf_corner),
+ SOC_ENUM("In Filter2 HPF Corner Voice", da7218_in2_voice_hpf_corner),
+
+ /* Mic Level Detect */
+ SOC_DOUBLE_EXT("Mic Level Detect Channel1 Switch", DA7218_LVL_DET_CTRL,
+ DA7218_LVL_DET_EN_CHAN1L_SHIFT,
+ DA7218_LVL_DET_EN_CHAN1R_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+ da7218_mic_lvl_det_sw_put),
+ SOC_DOUBLE_EXT("Mic Level Detect Channel2 Switch", DA7218_LVL_DET_CTRL,
+ DA7218_LVL_DET_EN_CHAN2L_SHIFT,
+ DA7218_LVL_DET_EN_CHAN2R_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+ da7218_mic_lvl_det_sw_put),
+ SOC_SINGLE("Mic Level Detect Level", DA7218_LVL_DET_LEVEL,
+ DA7218_LVL_DET_LEVEL_SHIFT, DA7218_LVL_DET_LEVEL_MAX,
+ DA7218_NO_INVERT),
+
+ /* Digital Mixer (Input) */
+ SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN,
+ DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN,
+ DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN,
+ DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN,
+ DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN,
+ DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN,
+ DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN,
+ DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN,
+ DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN,
+ DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN,
+ DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN,
+ DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN,
+ DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN,
+ DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN,
+ DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN,
+ DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN,
+ DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix ToneGen Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN,
+ DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix ToneGen Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN,
+ DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix ToneGen Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN,
+ DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix ToneGen Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN,
+ DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In DAIL Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN,
+ DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIL Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN,
+ DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIL Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN,
+ DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIL Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN,
+ DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In DAIR Out1 DAIL Volume",
+ DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN,
+ DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIR Out1 DAIR Volume",
+ DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN,
+ DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIR Out2 DAIL Volume",
+ DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN,
+ DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIR Out2 DAIR Volume",
+ DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN,
+ DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ /* Digital Mixer (Output) */
+ SOC_SINGLE_TLV("DMix In Filter1L Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN,
+ DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1L Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN,
+ DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In Filter1R Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN,
+ DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter1R Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN,
+ DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In Filter2L Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN,
+ DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2L Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN,
+ DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In Filter2R Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN,
+ DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In Filter2R Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN,
+ DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix ToneGen Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN,
+ DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix ToneGen Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN,
+ DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In DAIL Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN,
+ DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIL Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN,
+ DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ SOC_SINGLE_TLV("DMix In DAIR Out FilterL Volume",
+ DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN,
+ DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+ SOC_SINGLE_TLV("DMix In DAIR Out FilterR Volume",
+ DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN,
+ DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT,
+ DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_dmix_gain_tlv),
+
+ /* Sidetone Filter */
+ SND_SOC_BYTES_EXT("Sidetone BiQuad Coefficients",
+ DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE,
+ da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+ SOC_SINGLE_TLV("Sidetone Volume", DA7218_SIDETONE_GAIN,
+ DA7218_SIDETONE_GAIN_SHIFT, DA7218_DMIX_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_dmix_gain_tlv),
+ SOC_SINGLE("Sidetone Switch", DA7218_SIDETONE_CTRL,
+ DA7218_SIDETONE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+
+ /* Tone Generator */
+ SOC_ENUM("ToneGen DTMF Key", da7218_tonegen_dtmf_key),
+ SOC_SINGLE("ToneGen DTMF Switch", DA7218_TONE_GEN_CFG1,
+ DA7218_DTMF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_ENUM("ToneGen Sinewave Gen Type", da7218_tonegen_swg_sel),
+ SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7218_TONE_GEN_FREQ1_L,
+ DA7218_FREQ1_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+ da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+ SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7218_TONE_GEN_FREQ2_L,
+ DA7218_FREQ2_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+ da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+ SOC_SINGLE("ToneGen On Time", DA7218_TONE_GEN_ON_PER,
+ DA7218_BEEP_ON_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("ToneGen Off Time", DA7218_TONE_GEN_OFF_PER,
+ DA7218_BEEP_OFF_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+ DA7218_NO_INVERT),
+
+ /* Gain ramping */
+ SOC_ENUM("Gain Ramp Rate", da7218_gain_ramp_rate),
+
+ /* DGS */
+ SOC_SINGLE_TLV("DGS Trigger", DA7218_DGS_TRIGGER,
+ DA7218_DGS_TRIGGER_LVL_SHIFT, DA7218_DGS_TRIGGER_MAX,
+ DA7218_INVERT, da7218_dgs_trigger_tlv),
+ SOC_ENUM("DGS Rise Coefficient", da7218_dgs_rise_coeff),
+ SOC_ENUM("DGS Fall Coefficient", da7218_dgs_fall_coeff),
+ SOC_SINGLE("DGS Sync Delay", DA7218_DGS_SYNC_DELAY,
+ DA7218_DGS_SYNC_DELAY_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("DGS Fast SR Sync Delay", DA7218_DGS_SYNC_DELAY2,
+ DA7218_DGS_SYNC_DELAY2_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("DGS Voice Filter Sync Delay", DA7218_DGS_SYNC_DELAY3,
+ DA7218_DGS_SYNC_DELAY3_SHIFT, DA7218_DGS_SYNC_DELAY3_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE_TLV("DGS Anticlip Level", DA7218_DGS_LEVELS,
+ DA7218_DGS_ANTICLIP_LVL_SHIFT,
+ DA7218_DGS_ANTICLIP_LVL_MAX, DA7218_INVERT,
+ da7218_dgs_anticlip_tlv),
+ SOC_SINGLE_TLV("DGS Signal Level", DA7218_DGS_LEVELS,
+ DA7218_DGS_SIGNAL_LVL_SHIFT, DA7218_DGS_SIGNAL_LVL_MAX,
+ DA7218_INVERT, da7218_dgs_signal_tlv),
+ SOC_SINGLE("DGS Gain Subrange Switch", DA7218_DGS_GAIN_CTRL,
+ DA7218_DGS_SUBR_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("DGS Gain Ramp Switch", DA7218_DGS_GAIN_CTRL,
+ DA7218_DGS_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_SINGLE("DGS Gain Steps", DA7218_DGS_GAIN_CTRL,
+ DA7218_DGS_STEPS_SHIFT, DA7218_DGS_STEPS_MAX,
+ DA7218_NO_INVERT),
+ SOC_DOUBLE("DGS Switch", DA7218_DGS_ENABLE, DA7218_DGS_ENABLE_L_SHIFT,
+ DA7218_DGS_ENABLE_R_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+
+ /* Output High-Pass Filter */
+ SOC_ENUM("Out Filter HPF Mode", da7218_out1_hpf_mode),
+ SOC_ENUM("Out Filter HPF Corner Audio", da7218_out1_audio_hpf_corner),
+ SOC_ENUM("Out Filter HPF Corner Voice", da7218_out1_voice_hpf_corner),
+
+ /* 5-Band Equaliser */
+ SOC_SINGLE_TLV("Out EQ Band1 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+ DA7218_OUT_1_EQ_BAND1_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+ DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+ SOC_SINGLE_TLV("Out EQ Band2 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+ DA7218_OUT_1_EQ_BAND2_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+ DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+ SOC_SINGLE_TLV("Out EQ Band3 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+ DA7218_OUT_1_EQ_BAND3_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+ DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+ SOC_SINGLE_TLV("Out EQ Band4 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+ DA7218_OUT_1_EQ_BAND4_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+ DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+ SOC_SINGLE_TLV("Out EQ Band5 Volume", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+ DA7218_OUT_1_EQ_BAND5_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+ DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+ SOC_SINGLE("Out EQ Switch", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+ DA7218_OUT_1_EQ_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+
+ /* BiQuad Filters */
+ SND_SOC_BYTES_EXT("BiQuad Coefficients",
+ DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE,
+ da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+ SOC_SINGLE("BiQuad Filter Switch", DA7218_OUT_1_BIQ_5STAGE_CTRL,
+ DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+
+ /* Output Filters */
+ SOC_DOUBLE_R_RANGE_TLV("Out Filter Volume", DA7218_OUT_1L_GAIN,
+ DA7218_OUT_1R_GAIN,
+ DA7218_OUT_1L_DIGITAL_GAIN_SHIFT,
+ DA7218_OUT_DIGITAL_GAIN_MIN,
+ DA7218_OUT_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_out_dig_gain_tlv),
+ SOC_DOUBLE_R("Out Filter Switch", DA7218_OUT_1L_FILTER_CTRL,
+ DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_MUTE_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_INVERT),
+ SOC_DOUBLE_R("Out Filter Gain Subrange Switch",
+ DA7218_OUT_1L_FILTER_CTRL, DA7218_OUT_1R_FILTER_CTRL,
+ DA7218_OUT_1L_SUBRANGE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_NO_INVERT),
+ SOC_DOUBLE_R("Out Filter Gain Ramp Switch", DA7218_OUT_1L_FILTER_CTRL,
+ DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_RAMP_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+ /* Mixer Output */
+ SOC_DOUBLE_R_RANGE_TLV("Mixout Volume", DA7218_MIXOUT_L_GAIN,
+ DA7218_MIXOUT_R_GAIN,
+ DA7218_MIXOUT_L_AMP_GAIN_SHIFT,
+ DA7218_MIXOUT_AMP_GAIN_MIN,
+ DA7218_MIXOUT_AMP_GAIN_MAX, DA7218_NO_INVERT,
+ da7218_mixout_gain_tlv),
+
+ /* DAC Noise Gate */
+ SOC_ENUM("DAC NG Setup Time", da7218_dac_ng_setup_time),
+ SOC_ENUM("DAC NG Rampup Rate", da7218_dac_ng_rampup_rate),
+ SOC_ENUM("DAC NG Rampdown Rate", da7218_dac_ng_rampdown_rate),
+ SOC_SINGLE_TLV("DAC NG Off Threshold", DA7218_DAC_NG_OFF_THRESH,
+ DA7218_DAC_NG_OFF_THRESHOLD_SHIFT,
+ DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+ da7218_dac_ng_threshold_tlv),
+ SOC_SINGLE_TLV("DAC NG On Threshold", DA7218_DAC_NG_ON_THRESH,
+ DA7218_DAC_NG_ON_THRESHOLD_SHIFT,
+ DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+ da7218_dac_ng_threshold_tlv),
+ SOC_SINGLE("DAC NG Switch", DA7218_DAC_NG_CTRL, DA7218_DAC_NG_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+ /* CP */
+ SOC_ENUM("Charge Pump Track Mode", da7218_cp_mchange),
+ SOC_ENUM("Charge Pump Frequency", da7218_cp_fcontrol),
+ SOC_ENUM("Charge Pump Decay Rate", da7218_cp_tau_delay),
+ SOC_SINGLE("Charge Pump Threshold", DA7218_CP_VOL_THRESHOLD1,
+ DA7218_CP_THRESH_VDD2_SHIFT, DA7218_CP_THRESH_VDD2_MAX,
+ DA7218_NO_INVERT),
+
+ /* Headphones */
+ SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", DA7218_HP_L_GAIN,
+ DA7218_HP_R_GAIN, DA7218_HP_L_AMP_GAIN_SHIFT,
+ DA7218_HP_AMP_GAIN_MIN, DA7218_HP_AMP_GAIN_MAX,
+ DA7218_NO_INVERT, da7218_hp_gain_tlv),
+ SOC_DOUBLE_R("Headphone Switch", DA7218_HP_L_CTRL, DA7218_HP_R_CTRL,
+ DA7218_HP_L_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+ DA7218_INVERT),
+ SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7218_HP_L_CTRL,
+ DA7218_HP_R_CTRL, DA7218_HP_L_AMP_RAMP_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+ SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7218_HP_L_CTRL,
+ DA7218_HP_R_CTRL, DA7218_HP_L_AMP_ZC_EN_SHIFT,
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+};
+
+
+/*
+ * DAPM Mux Controls
+ */
+
+static const char * const da7218_mic_sel_text[] = { "Analog", "Digital" };
+
+static const struct soc_enum da7218_mic1_sel =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+ da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic1_sel_mux =
+ SOC_DAPM_ENUM("Mic1 Mux", da7218_mic1_sel);
+
+static const struct soc_enum da7218_mic2_sel =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+ da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic2_sel_mux =
+ SOC_DAPM_ENUM("Mic2 Mux", da7218_mic2_sel);
+
+static const char * const da7218_sidetone_in_sel_txt[] = {
+ "In Filter1L", "In Filter1R", "In Filter2L", "In Filter2R"
+};
+
+static const struct soc_enum da7218_sidetone_in_sel =
+ SOC_ENUM_SINGLE(DA7218_SIDETONE_IN_SELECT,
+ DA7218_SIDETONE_IN_SELECT_SHIFT,
+ DA7218_SIDETONE_IN_SELECT_MAX,
+ da7218_sidetone_in_sel_txt);
+
+static const struct snd_kcontrol_new da7218_sidetone_in_sel_mux =
+ SOC_DAPM_ENUM("Sidetone Mux", da7218_sidetone_in_sel);
+
+static const char * const da7218_out_filt_biq_sel_txt[] = {
+ "Bypass", "Enabled"
+};
+
+static const struct soc_enum da7218_out_filtl_biq_sel =
+ SOC_ENUM_SINGLE(DA7218_OUT_1L_FILTER_CTRL,
+ DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT,
+ DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+ da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtl_biq_sel_mux =
+ SOC_DAPM_ENUM("Out FilterL BiQuad Mux", da7218_out_filtl_biq_sel);
+
+static const struct soc_enum da7218_out_filtr_biq_sel =
+ SOC_ENUM_SINGLE(DA7218_OUT_1R_FILTER_CTRL,
+ DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT,
+ DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+ da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtr_biq_sel_mux =
+ SOC_DAPM_ENUM("Out FilterR BiQuad Mux", da7218_out_filtr_biq_sel);
+
+
+/*
+ * DAPM Mixer Controls
+ */
+
+#define DA7218_DMIX_CTRLS(reg) \
+ SOC_DAPM_SINGLE("In Filter1L Switch", reg, \
+ DA7218_DMIX_SRC_INFILT1L, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("In Filter1R Switch", reg, \
+ DA7218_DMIX_SRC_INFILT1R, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("In Filter2L Switch", reg, \
+ DA7218_DMIX_SRC_INFILT2L, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("In Filter2R Switch", reg, \
+ DA7218_DMIX_SRC_INFILT2R, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("ToneGen Switch", reg, \
+ DA7218_DMIX_SRC_TONEGEN, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("DAIL Switch", reg, DA7218_DMIX_SRC_DAIL, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("DAIR Switch", reg, DA7218_DMIX_SRC_DAIR, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)
+
+static const struct snd_kcontrol_new da7218_out_dai1l_mix_controls[] = {
+ DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai1r_mix_controls[] = {
+ DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1R),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2l_mix_controls[] = {
+ DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2r_mix_controls[] = {
+ DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2R),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtl_mix_controls[] = {
+ DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtr_mix_controls[] = {
+ DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1R),
+};
+
+#define DA7218_DMIX_ST_CTRLS(reg) \
+ SOC_DAPM_SINGLE("Out FilterL Switch", reg, \
+ DA7218_DMIX_ST_SRC_OUTFILT1L, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("Out FilterR Switch", reg, \
+ DA7218_DMIX_ST_SRC_OUTFILT1R, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \
+ SOC_DAPM_SINGLE("Sidetone Switch", reg, \
+ DA7218_DMIX_ST_SRC_SIDETONE, \
+ DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT) \
+
+static const struct snd_kcontrol_new da7218_st_out_filtl_mix_controls[] = {
+ DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = {
+ DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1R),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+/*
+ * We keep track of which input filters are enabled. This is used in the logic
+ * for controlling the mic level detect feature.
+ */
+static int da7218_in_filter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ u8 mask;
+
+ switch (w->reg) {
+ case DA7218_IN_1L_FILTER_CTRL:
+ mask = (1 << DA7218_LVL_DET_EN_CHAN1L_SHIFT);
+ break;
+ case DA7218_IN_1R_FILTER_CTRL:
+ mask = (1 << DA7218_LVL_DET_EN_CHAN1R_SHIFT);
+ break;
+ case DA7218_IN_2L_FILTER_CTRL:
+ mask = (1 << DA7218_LVL_DET_EN_CHAN2L_SHIFT);
+ break;
+ case DA7218_IN_2R_FILTER_CTRL:
+ mask = (1 << DA7218_LVL_DET_EN_CHAN2R_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ da7218->in_filt_en |= mask;
+ /*
+ * If we're enabling path for mic level detect, wait for path
+ * to settle before enabling feature to avoid incorrect and
+ * unwanted detect events.
+ */
+ if (mask & da7218->mic_lvl_det_en)
+ msleep(DA7218_MIC_LVL_DET_DELAY);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ da7218->in_filt_en &= ~mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Enable configured level detection paths */
+ snd_soc_write(codec, DA7218_LVL_DET_CTRL,
+ (da7218->in_filt_en & da7218->mic_lvl_det_en));
+
+ return 0;
+}
+
+static int da7218_dai_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ u8 pll_ctrl, pll_status, refosc_cal;
+ int i;
+ bool success;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (da7218->master)
+ /* Enable DAI clks for master mode */
+ snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+ DA7218_DAI_CLK_EN_MASK,
+ DA7218_DAI_CLK_EN_MASK);
+
+ /* Tune reference oscillator */
+ snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+ DA7218_PLL_REFOSC_CAL_START_MASK);
+ snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+ DA7218_PLL_REFOSC_CAL_START_MASK |
+ DA7218_PLL_REFOSC_CAL_EN_MASK);
+
+ /* Check tuning complete */
+ i = 0;
+ success = false;
+ do {
+ refosc_cal = snd_soc_read(codec, DA7218_PLL_REFOSC_CAL);
+ if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) {
+ success = true;
+ } else {
+ ++i;
+ usleep_range(DA7218_REF_OSC_CHECK_DELAY_MIN,
+ DA7218_REF_OSC_CHECK_DELAY_MAX);
+ }
+ } while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success));
+
+ if (!success)
+ dev_warn(codec->dev,
+ "Reference oscillator failed calibration\n");
+
+ /* PC synchronised to DAI */
+ snd_soc_write(codec, DA7218_PC_COUNT,
+ DA7218_PC_RESYNC_AUTO_MASK);
+
+ /* If SRM not enabled, we don't need to check status */
+ pll_ctrl = snd_soc_read(codec, DA7218_PLL_CTRL);
+ if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM)
+ return 0;
+
+ /* Check SRM has locked */
+ i = 0;
+ success = false;
+ do {
+ pll_status = snd_soc_read(codec, DA7218_PLL_STATUS);
+ if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) {
+ success = true;
+ } else {
+ ++i;
+ msleep(DA7218_SRM_CHECK_DELAY);
+ }
+ } while ((i < DA7218_SRM_CHECK_TRIES) & (!success));
+
+ if (!success)
+ dev_warn(codec->dev, "SRM failed to lock\n");
+
+ return 0;
+ case SND_SOC_DAPM_POST_PMD:
+ /* PC free-running */
+ snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+ if (da7218->master)
+ /* Disable DAI clks for master mode */
+ snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+ DA7218_DAI_CLK_EN_MASK, 0);
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int da7218_cp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+ /*
+ * If this is DA7217 and we're using single supply for differential
+ * output, we really don't want to touch the charge pump.
+ */
+ if (da7218->hp_single_supply)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+ DA7218_CP_EN_MASK);
+ return 0;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+ 0);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int da7218_hp_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Enable headphone output */
+ snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK,
+ DA7218_HP_AMP_OE_MASK);
+ return 0;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Headphone output high impedance */
+ snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, 0);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/*
+ * DAPM Widgets
+ */
+
+static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
+ /* Input Supplies */
+ SND_SOC_DAPM_SUPPLY("Mic Bias1", DA7218_MICBIAS_EN,
+ DA7218_MICBIAS_1_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Mic Bias2", DA7218_MICBIAS_EN,
+ DA7218_MICBIAS_2_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMic1 Left", DA7218_DMIC_1_CTRL,
+ DA7218_DMIC_1L_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMic1 Right", DA7218_DMIC_1_CTRL,
+ DA7218_DMIC_1R_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMic2 Left", DA7218_DMIC_2_CTRL,
+ DA7218_DMIC_2L_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMic2 Right", DA7218_DMIC_2_CTRL,
+ DA7218_DMIC_2R_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("DMIC1L"),
+ SND_SOC_DAPM_INPUT("DMIC1R"),
+ SND_SOC_DAPM_INPUT("DMIC2L"),
+ SND_SOC_DAPM_INPUT("DMIC2R"),
+
+ /* Input Mixer Supplies */
+ SND_SOC_DAPM_SUPPLY("Mixin1 Supply", DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Mixin2 Supply", DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+
+ /* Input PGAs */
+ SND_SOC_DAPM_PGA("Mic1 PGA", DA7218_MIC_1_CTRL,
+ DA7218_MIC_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("Mic2 PGA", DA7218_MIC_2_CTRL,
+ DA7218_MIC_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("Mixin1 PGA", DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("Mixin2 PGA", DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+
+ /* Mic/DMic Muxes */
+ SND_SOC_DAPM_MUX("Mic1 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic1_sel_mux),
+ SND_SOC_DAPM_MUX("Mic2 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic2_sel_mux),
+
+ /* Input Filters */
+ SND_SOC_DAPM_ADC_E("In Filter1L", NULL, DA7218_IN_1L_FILTER_CTRL,
+ DA7218_IN_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+ da7218_in_filter_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("In Filter1R", NULL, DA7218_IN_1R_FILTER_CTRL,
+ DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+ da7218_in_filter_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("In Filter2L", NULL, DA7218_IN_2L_FILTER_CTRL,
+ DA7218_IN_2L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+ da7218_in_filter_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("In Filter2R", NULL, DA7218_IN_2R_FILTER_CTRL,
+ DA7218_IN_2R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+ da7218_in_filter_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* Tone Generator */
+ SND_SOC_DAPM_SIGGEN("TONE"),
+ SND_SOC_DAPM_PGA("Tone Generator", DA7218_TONE_GEN_CFG1,
+ DA7218_START_STOPN_SHIFT, DA7218_NO_INVERT, NULL, 0),
+
+ /* Sidetone Input */
+ SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+ &da7218_sidetone_in_sel_mux),
+ SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7218_SIDETONE_CTRL,
+ DA7218_SIDETONE_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+ /* Input Mixers */
+ SND_SOC_DAPM_MIXER("Mixer DAI1L", SND_SOC_NOPM, 0, 0,
+ da7218_out_dai1l_mix_controls,
+ ARRAY_SIZE(da7218_out_dai1l_mix_controls)),
+ SND_SOC_DAPM_MIXER("Mixer DAI1R", SND_SOC_NOPM, 0, 0,
+ da7218_out_dai1r_mix_controls,
+ ARRAY_SIZE(da7218_out_dai1r_mix_controls)),
+ SND_SOC_DAPM_MIXER("Mixer DAI2L", SND_SOC_NOPM, 0, 0,
+ da7218_out_dai2l_mix_controls,
+ ARRAY_SIZE(da7218_out_dai2l_mix_controls)),
+ SND_SOC_DAPM_MIXER("Mixer DAI2R", SND_SOC_NOPM, 0, 0,
+ da7218_out_dai2r_mix_controls,
+ ARRAY_SIZE(da7218_out_dai2r_mix_controls)),
+
+ /* DAI Supply */
+ SND_SOC_DAPM_SUPPLY("DAI", DA7218_DAI_CTRL, DA7218_DAI_EN_SHIFT,
+ DA7218_NO_INVERT, da7218_dai_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* DAI */
+ SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Output Mixers */
+ SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+ da7218_out_filtl_mix_controls,
+ ARRAY_SIZE(da7218_out_filtl_mix_controls)),
+ SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+ da7218_out_filtr_mix_controls,
+ ARRAY_SIZE(da7218_out_filtr_mix_controls)),
+
+ /* BiQuad Filters */
+ SND_SOC_DAPM_MUX("Out FilterL BiQuad Mux", SND_SOC_NOPM, 0, 0,
+ &da7218_out_filtl_biq_sel_mux),
+ SND_SOC_DAPM_MUX("Out FilterR BiQuad Mux", SND_SOC_NOPM, 0, 0,
+ &da7218_out_filtr_biq_sel_mux),
+ SND_SOC_DAPM_DAC("BiQuad Filter", NULL, DA7218_OUT_1_BIQ_5STAGE_CTRL,
+ DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT,
+ DA7218_NO_INVERT),
+
+ /* Sidetone Mixers */
+ SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+ da7218_st_out_filtl_mix_controls,
+ ARRAY_SIZE(da7218_st_out_filtl_mix_controls)),
+ SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+ da7218_st_out_filtr_mix_controls,
+ ARRAY_SIZE(da7218_st_out_filtr_mix_controls)),
+
+ /* Output Filters */
+ SND_SOC_DAPM_DAC("Out FilterL", NULL, DA7218_OUT_1L_FILTER_CTRL,
+ DA7218_OUT_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+ SND_SOC_DAPM_DAC("Out FilterR", NULL, DA7218_OUT_1R_FILTER_CTRL,
+ DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+ /* Output PGAs */
+ SND_SOC_DAPM_PGA("Mixout Left PGA", DA7218_MIXOUT_L_CTRL,
+ DA7218_MIXOUT_L_AMP_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("Mixout Right PGA", DA7218_MIXOUT_R_CTRL,
+ DA7218_MIXOUT_R_AMP_EN_SHIFT, DA7218_NO_INVERT,
+ NULL, 0),
+ SND_SOC_DAPM_PGA_E("Headphone Left PGA", DA7218_HP_L_CTRL,
+ DA7218_HP_L_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+ da7218_hp_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("Headphone Right PGA", DA7218_HP_R_CTRL,
+ DA7218_HP_R_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+ da7218_hp_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* Output Supplies */
+ SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, da7218_cp_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+
+/*
+ * DAPM Mixer Routes
+ */
+
+#define DA7218_DMIX_ROUTES(name) \
+ {name, "In Filter1L Switch", "In Filter1L"}, \
+ {name, "In Filter1R Switch", "In Filter1R"}, \
+ {name, "In Filter2L Switch", "In Filter2L"}, \
+ {name, "In Filter2R Switch", "In Filter2R"}, \
+ {name, "ToneGen Switch", "Tone Generator"}, \
+ {name, "DAIL Switch", "DAIIN"}, \
+ {name, "DAIR Switch", "DAIIN"}
+
+#define DA7218_DMIX_ST_ROUTES(name) \
+ {name, "Out FilterL Switch", "Out FilterL BiQuad Mux"}, \
+ {name, "Out FilterR Switch", "Out FilterR BiQuad Mux"}, \
+ {name, "Sidetone Switch", "Sidetone Filter"}
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7218_audio_map[] = {
+ /* Input paths */
+ {"MIC1", NULL, "Mic Bias1"},
+ {"MIC2", NULL, "Mic Bias2"},
+ {"DMIC1L", NULL, "Mic Bias1"},
+ {"DMIC1L", NULL, "DMic1 Left"},
+ {"DMIC1R", NULL, "Mic Bias1"},
+ {"DMIC1R", NULL, "DMic1 Right"},
+ {"DMIC2L", NULL, "Mic Bias2"},
+ {"DMIC2L", NULL, "DMic2 Left"},
+ {"DMIC2R", NULL, "Mic Bias2"},
+ {"DMIC2R", NULL, "DMic2 Right"},
+
+ {"Mic1 PGA", NULL, "MIC1"},
+ {"Mic2 PGA", NULL, "MIC2"},
+
+ {"Mixin1 PGA", NULL, "Mixin1 Supply"},
+ {"Mixin2 PGA", NULL, "Mixin2 Supply"},
+
+ {"Mixin1 PGA", NULL, "Mic1 PGA"},
+ {"Mixin2 PGA", NULL, "Mic2 PGA"},
+
+ {"Mic1 Mux", "Analog", "Mixin1 PGA"},
+ {"Mic1 Mux", "Digital", "DMIC1L"},
+ {"Mic1 Mux", "Digital", "DMIC1R"},
+ {"Mic2 Mux", "Analog", "Mixin2 PGA"},
+ {"Mic2 Mux", "Digital", "DMIC2L"},
+ {"Mic2 Mux", "Digital", "DMIC2R"},
+
+ {"In Filter1L", NULL, "Mic1 Mux"},
+ {"In Filter1R", NULL, "Mic1 Mux"},
+ {"In Filter2L", NULL, "Mic2 Mux"},
+ {"In Filter2R", NULL, "Mic2 Mux"},
+
+ {"Tone Generator", NULL, "TONE"},
+
+ {"Sidetone Mux", "In Filter1L", "In Filter1L"},
+ {"Sidetone Mux", "In Filter1R", "In Filter1R"},
+ {"Sidetone Mux", "In Filter2L", "In Filter2L"},
+ {"Sidetone Mux", "In Filter2R", "In Filter2R"},
+ {"Sidetone Filter", NULL, "Sidetone Mux"},
+
+ DA7218_DMIX_ROUTES("Mixer DAI1L"),
+ DA7218_DMIX_ROUTES("Mixer DAI1R"),
+ DA7218_DMIX_ROUTES("Mixer DAI2L"),
+ DA7218_DMIX_ROUTES("Mixer DAI2R"),
+
+ {"DAIOUT", NULL, "Mixer DAI1L"},
+ {"DAIOUT", NULL, "Mixer DAI1R"},
+ {"DAIOUT", NULL, "Mixer DAI2L"},
+ {"DAIOUT", NULL, "Mixer DAI2R"},
+
+ {"DAIOUT", NULL, "DAI"},
+
+ /* Output paths */
+ {"DAIIN", NULL, "DAI"},
+
+ DA7218_DMIX_ROUTES("Mixer Out FilterL"),
+ DA7218_DMIX_ROUTES("Mixer Out FilterR"),
+
+ {"BiQuad Filter", NULL, "Mixer Out FilterL"},
+ {"BiQuad Filter", NULL, "Mixer Out FilterR"},
+
+ {"Out FilterL BiQuad Mux", "Bypass", "Mixer Out FilterL"},
+ {"Out FilterL BiQuad Mux", "Enabled", "BiQuad Filter"},
+ {"Out FilterR BiQuad Mux", "Bypass", "Mixer Out FilterR"},
+ {"Out FilterR BiQuad Mux", "Enabled", "BiQuad Filter"},
+
+ DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterL"),
+ DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterR"),
+
+ {"Out FilterL", NULL, "ST Mixer Out FilterL"},
+ {"Out FilterR", NULL, "ST Mixer Out FilterR"},
+
+ {"Mixout Left PGA", NULL, "Out FilterL"},
+ {"Mixout Right PGA", NULL, "Out FilterR"},
+
+ {"Headphone Left PGA", NULL, "Mixout Left PGA"},
+ {"Headphone Right PGA", NULL, "Mixout Right PGA"},
+
+ {"HPL", NULL, "Headphone Left PGA"},
+ {"HPR", NULL, "Headphone Right PGA"},
+
+ {"HPL", NULL, "Charge Pump"},
+ {"HPR", NULL, "Charge Pump"},
+};
+
+
+/*
+ * DAI operations
+ */
+
+static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ if (da7218->mclk_rate == freq)
+ return 0;
+
+ if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) {
+ dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+ freq);
+ return -EINVAL;
+ }
+
+ switch (clk_id) {
+ case DA7218_CLKSRC_MCLK_SQR:
+ snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+ DA7218_PLL_MCLK_SQR_EN_MASK,
+ DA7218_PLL_MCLK_SQR_EN_MASK);
+ break;
+ case DA7218_CLKSRC_MCLK:
+ snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+ DA7218_PLL_MCLK_SQR_EN_MASK, 0);
+ break;
+ default:
+ dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ if (da7218->mclk) {
+ freq = clk_round_rate(da7218->mclk, freq);
+ ret = clk_set_rate(da7218->mclk, freq);
+ if (ret) {
+ dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+ freq);
+ return ret;
+ }
+ }
+
+ da7218->mclk_rate = freq;
+
+ return 0;
+}
+
+static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int fref, unsigned int fout)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+ u8 pll_ctrl, indiv_bits, indiv;
+ u8 pll_frac_top, pll_frac_bot, pll_integer;
+ u32 freq_ref;
+ u64 frac_div;
+
+ /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
+ if (da7218->mclk_rate == 32768) {
+ indiv_bits = DA7218_PLL_INDIV_2_5_MHZ;
+ indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+ } else if (da7218->mclk_rate < 2000000) {
+ dev_err(codec->dev, "PLL input clock %d below valid range\n",
+ da7218->mclk_rate);
+ return -EINVAL;
+ } else if (da7218->mclk_rate <= 5000000) {
+ indiv_bits = DA7218_PLL_INDIV_2_5_MHZ;
+ indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+ } else if (da7218->mclk_rate <= 10000000) {
+ indiv_bits = DA7218_PLL_INDIV_5_10_MHZ;
+ indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+ } else if (da7218->mclk_rate <= 20000000) {
+ indiv_bits = DA7218_PLL_INDIV_10_20_MHZ;
+ indiv = DA7218_PLL_INDIV_10_20_MHZ_VAL;
+ } else if (da7218->mclk_rate <= 40000000) {
+ indiv_bits = DA7218_PLL_INDIV_20_40_MHZ;
+ indiv = DA7218_PLL_INDIV_20_40_MHZ_VAL;
+ } else if (da7218->mclk_rate <= 54000000) {
+ indiv_bits = DA7218_PLL_INDIV_40_54_MHZ;
+ indiv = DA7218_PLL_INDIV_40_54_MHZ_VAL;
+ } else {
+ dev_err(codec->dev, "PLL input clock %d above valid range\n",
+ da7218->mclk_rate);
+ return -EINVAL;
+ }
+ freq_ref = (da7218->mclk_rate / indiv);
+ pll_ctrl = indiv_bits;
+
+ /* Configure PLL */
+ switch (source) {
+ case DA7218_SYSCLK_MCLK:
+ pll_ctrl |= DA7218_PLL_MODE_BYPASS;
+ snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+ DA7218_PLL_INDIV_MASK |
+ DA7218_PLL_MODE_MASK, pll_ctrl);
+ return 0;
+ case DA7218_SYSCLK_PLL:
+ pll_ctrl |= DA7218_PLL_MODE_NORMAL;
+ break;
+ case DA7218_SYSCLK_PLL_SRM:
+ pll_ctrl |= DA7218_PLL_MODE_SRM;
+ break;
+ case DA7218_SYSCLK_PLL_32KHZ:
+ pll_ctrl |= DA7218_PLL_MODE_32KHZ;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid PLL config\n");
+ return -EINVAL;
+ }
+
+ /* Calculate dividers for PLL */
+ pll_integer = fout / freq_ref;
+ frac_div = (u64)(fout % freq_ref) * 8192ULL;
+ do_div(frac_div, freq_ref);
+ pll_frac_top = (frac_div >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK;
+ pll_frac_bot = (frac_div) & DA7218_BYTE_MASK;
+
+ /* Write PLL config & dividers */
+ snd_soc_write(codec, DA7218_PLL_FRAC_TOP, pll_frac_top);
+ snd_soc_write(codec, DA7218_PLL_FRAC_BOT, pll_frac_bot);
+ snd_soc_write(codec, DA7218_PLL_INTEGER, pll_integer);
+ snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+ DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK,
+ pll_ctrl);
+
+ return 0;
+}
+
+static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ u8 dai_clk_mode = 0, dai_ctrl = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ da7218->master = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ da7218->master = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+ DA7218_DAI_CLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+ DA7218_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dai_ctrl |= DA7218_DAI_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dai_ctrl |= DA7218_DAI_FORMAT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dai_ctrl |= DA7218_DAI_FORMAT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ dai_ctrl |= DA7218_DAI_FORMAT_DSP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* By default 64 BCLKs per WCLK is supported */
+ dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64;
+
+ snd_soc_write(codec, DA7218_DAI_CLK_MODE, dai_clk_mode);
+ snd_soc_update_bits(codec, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK,
+ dai_ctrl);
+
+ return 0;
+}
+
+static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 dai_bclks_per_wclk;
+ u32 frame_size;
+
+ /* No channels enabled so disable TDM, revert to 64-bit frames */
+ if (!tx_mask) {
+ snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+ DA7218_DAI_TDM_CH_EN_MASK |
+ DA7218_DAI_TDM_MODE_EN_MASK, 0);
+ snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+ DA7218_DAI_BCLKS_PER_WCLK_MASK,
+ DA7218_DAI_BCLKS_PER_WCLK_64);
+ return 0;
+ }
+
+ /* Check we have valid slots */
+ if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) {
+ dev_err(codec->dev, "Invalid number of slots, max = %d\n",
+ DA7218_DAI_TDM_MAX_SLOTS);
+ return -EINVAL;
+ }
+
+ /* Check we have a valid offset given (first 2 bytes of rx_mask) */
+ if (rx_mask >> DA7218_2BYTE_SHIFT) {
+ dev_err(codec->dev, "Invalid slot offset, max = %d\n",
+ DA7218_2BYTE_MASK);
+ return -EINVAL;
+ }
+
+ /* Calculate & validate frame size based on slot info provided. */
+ frame_size = slots * slot_width;
+ switch (frame_size) {
+ case 32:
+ dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_32;
+ break;
+ case 64:
+ dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_64;
+ break;
+ case 128:
+ dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_128;
+ break;
+ case 256:
+ dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid frame size\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+ DA7218_DAI_BCLKS_PER_WCLK_MASK,
+ dai_bclks_per_wclk);
+ snd_soc_write(codec, DA7218_DAI_OFFSET_LOWER,
+ (rx_mask & DA7218_BYTE_MASK));
+ snd_soc_write(codec, DA7218_DAI_OFFSET_UPPER,
+ ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK));
+ snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+ DA7218_DAI_TDM_CH_EN_MASK |
+ DA7218_DAI_TDM_MODE_EN_MASK,
+ (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) |
+ DA7218_DAI_TDM_MODE_EN_MASK);
+
+ return 0;
+}
+
+static int da7218_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 dai_ctrl = 0, fs;
+ unsigned int channels;
+
+ switch (params_width(params)) {
+ case 16:
+ dai_ctrl |= DA7218_DAI_WORD_LENGTH_S16_LE;
+ break;
+ case 20:
+ dai_ctrl |= DA7218_DAI_WORD_LENGTH_S20_LE;
+ break;
+ case 24:
+ dai_ctrl |= DA7218_DAI_WORD_LENGTH_S24_LE;
+ break;
+ case 32:
+ dai_ctrl |= DA7218_DAI_WORD_LENGTH_S32_LE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ channels = params_channels(params);
+ if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) {
+ dev_err(codec->dev,
+ "Invalid number of channels, only 1 to %d supported\n",
+ DA7218_DAI_CH_NUM_MAX);
+ return -EINVAL;
+ }
+ dai_ctrl |= channels << DA7218_DAI_CH_NUM_SHIFT;
+
+ switch (params_rate(params)) {
+ case 8000:
+ fs = DA7218_SR_8000;
+ break;
+ case 11025:
+ fs = DA7218_SR_11025;
+ break;
+ case 12000:
+ fs = DA7218_SR_12000;
+ break;
+ case 16000:
+ fs = DA7218_SR_16000;
+ break;
+ case 22050:
+ fs = DA7218_SR_22050;
+ break;
+ case 24000:
+ fs = DA7218_SR_24000;
+ break;
+ case 32000:
+ fs = DA7218_SR_32000;
+ break;
+ case 44100:
+ fs = DA7218_SR_44100;
+ break;
+ case 48000:
+ fs = DA7218_SR_48000;
+ break;
+ case 88200:
+ fs = DA7218_SR_88200;
+ break;
+ case 96000:
+ fs = DA7218_SR_96000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, DA7218_DAI_CTRL,
+ DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK,
+ dai_ctrl);
+ /* SRs tied for ADCs and DACs. */
+ snd_soc_write(codec, DA7218_SR,
+ (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT));
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops da7218_dai_ops = {
+ .hw_params = da7218_hw_params,
+ .set_sysclk = da7218_set_dai_sysclk,
+ .set_pll = da7218_set_dai_pll,
+ .set_fmt = da7218_set_dai_fmt,
+ .set_tdm_slot = da7218_set_dai_tdm_slot,
+};
+
+#define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver da7218_dai = {
+ .name = "da7218-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 4, /* Only 2 channels of data */
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = DA7218_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = DA7218_FORMATS,
+ },
+ .ops = &da7218_dai_ops,
+ .symmetric_rates = 1,
+ .symmetric_channels = 1,
+ .symmetric_samplebits = 1,
+};
+
+
+/*
+ * HP Detect
+ */
+
+int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+ if (da7218->dev_id == DA7217_DEV_ID)
+ return -EINVAL;
+
+ da7218->jack = jack;
+ snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+ DA7218_HPLDET_JACK_EN_MASK,
+ jack ? DA7218_HPLDET_JACK_EN_MASK : 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(da7218_hpldet);
+
+static void da7218_micldet_irq(struct snd_soc_codec *codec)
+{
+ char *envp[] = {
+ "EVENT=MIC_LEVEL_DETECT",
+ NULL,
+ };
+
+ kobject_uevent_env(&codec->dev->kobj, KOBJ_CHANGE, envp);
+}
+
+static void da7218_hpldet_irq(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ u8 jack_status;
+ int report;
+
+ jack_status = snd_soc_read(codec, DA7218_EVENT_STATUS);
+
+ if (jack_status & DA7218_HPLDET_JACK_STS_MASK)
+ report = SND_JACK_HEADPHONE;
+ else
+ report = 0;
+
+ snd_soc_jack_report(da7218->jack, report, SND_JACK_HEADPHONE);
+}
+
+/*
+ * IRQ
+ */
+
+static irqreturn_t da7218_irq_thread(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ u8 status;
+
+ /* Read IRQ status reg */
+ status = snd_soc_read(codec, DA7218_EVENT);
+ if (!status)
+ return IRQ_NONE;
+
+ /* Mic level detect */
+ if (status & DA7218_LVL_DET_EVENT_MASK)
+ da7218_micldet_irq(codec);
+
+ /* HP detect */
+ if (status & DA7218_HPLDET_JACK_EVENT_MASK)
+ da7218_hpldet_irq(codec);
+
+ /* Clear interrupts */
+ snd_soc_write(codec, DA7218_EVENT, status);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * DT
+ */
+
+static const struct of_device_id da7218_of_match[] = {
+ { .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
+ { .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da7218_of_match);
+
+static inline int da7218_of_get_id(struct device *dev)
+{
+ const struct of_device_id *id = of_match_device(da7218_of_match, dev);
+
+ if (id)
+ return (uintptr_t)id->data;
+ else
+ return -EINVAL;
+}
+
+static enum da7218_micbias_voltage
+ da7218_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+{
+ switch (val) {
+ case 1200:
+ return DA7218_MICBIAS_1_2V;
+ case 1600:
+ return DA7218_MICBIAS_1_6V;
+ case 1800:
+ return DA7218_MICBIAS_1_8V;
+ case 2000:
+ return DA7218_MICBIAS_2_0V;
+ case 2200:
+ return DA7218_MICBIAS_2_2V;
+ case 2400:
+ return DA7218_MICBIAS_2_4V;
+ case 2600:
+ return DA7218_MICBIAS_2_6V;
+ case 2800:
+ return DA7218_MICBIAS_2_8V;
+ case 3000:
+ return DA7218_MICBIAS_3_0V;
+ default:
+ dev_warn(codec->dev, "Invalid micbias level");
+ return DA7218_MICBIAS_1_6V;
+ }
+}
+
+static enum da7218_mic_amp_in_sel
+ da7218_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str)
+{
+ if (!strcmp(str, "diff")) {
+ return DA7218_MIC_AMP_IN_SEL_DIFF;
+ } else if (!strcmp(str, "se_p")) {
+ return DA7218_MIC_AMP_IN_SEL_SE_P;
+ } else if (!strcmp(str, "se_n")) {
+ return DA7218_MIC_AMP_IN_SEL_SE_N;
+ } else {
+ dev_warn(codec->dev, "Invalid mic input type selection");
+ return DA7218_MIC_AMP_IN_SEL_DIFF;
+ }
+}
+
+static enum da7218_dmic_data_sel
+ da7218_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str)
+{
+ if (!strcmp(str, "lrise_rfall")) {
+ return DA7218_DMIC_DATA_LRISE_RFALL;
+ } else if (!strcmp(str, "lfall_rrise")) {
+ return DA7218_DMIC_DATA_LFALL_RRISE;
+ } else {
+ dev_warn(codec->dev, "Invalid DMIC data type selection");
+ return DA7218_DMIC_DATA_LRISE_RFALL;
+ }
+}
+
+static enum da7218_dmic_samplephase
+ da7218_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str)
+{
+ if (!strcmp(str, "on_clkedge")) {
+ return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+ } else if (!strcmp(str, "between_clkedge")) {
+ return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE;
+ } else {
+ dev_warn(codec->dev, "Invalid DMIC sample phase");
+ return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+ }
+}
+
+static enum da7218_dmic_clk_rate
+ da7218_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val)
+{
+ switch (val) {
+ case 1500000:
+ return DA7218_DMIC_CLK_1_5MHZ;
+ case 3000000:
+ return DA7218_DMIC_CLK_3_0MHZ;
+ default:
+ dev_warn(codec->dev, "Invalid DMIC clock rate");
+ return DA7218_DMIC_CLK_3_0MHZ;
+ }
+}
+
+static enum da7218_hpldet_jack_rate
+ da7218_of_jack_rate(struct snd_soc_codec *codec, u32 val)
+{
+ switch (val) {
+ case 5:
+ return DA7218_HPLDET_JACK_RATE_5US;
+ case 10:
+ return DA7218_HPLDET_JACK_RATE_10US;
+ case 20:
+ return DA7218_HPLDET_JACK_RATE_20US;
+ case 40:
+ return DA7218_HPLDET_JACK_RATE_40US;
+ case 80:
+ return DA7218_HPLDET_JACK_RATE_80US;
+ case 160:
+ return DA7218_HPLDET_JACK_RATE_160US;
+ case 320:
+ return DA7218_HPLDET_JACK_RATE_320US;
+ case 640:
+ return DA7218_HPLDET_JACK_RATE_640US;
+ default:
+ dev_warn(codec->dev, "Invalid jack detect rate");
+ return DA7218_HPLDET_JACK_RATE_40US;
+ }
+}
+
+static enum da7218_hpldet_jack_debounce
+ da7218_of_jack_debounce(struct snd_soc_codec *codec, u32 val)
+{
+ switch (val) {
+ case 0:
+ return DA7218_HPLDET_JACK_DEBOUNCE_OFF;
+ case 2:
+ return DA7218_HPLDET_JACK_DEBOUNCE_2;
+ case 3:
+ return DA7218_HPLDET_JACK_DEBOUNCE_3;
+ case 4:
+ return DA7218_HPLDET_JACK_DEBOUNCE_4;
+ default:
+ dev_warn(codec->dev, "Invalid jack debounce");
+ return DA7218_HPLDET_JACK_DEBOUNCE_2;
+ }
+}
+
+static enum da7218_hpldet_jack_thr
+ da7218_of_jack_thr(struct snd_soc_codec *codec, u32 val)
+{
+ switch (val) {
+ case 84:
+ return DA7218_HPLDET_JACK_THR_84PCT;
+ case 88:
+ return DA7218_HPLDET_JACK_THR_88PCT;
+ case 92:
+ return DA7218_HPLDET_JACK_THR_92PCT;
+ case 96:
+ return DA7218_HPLDET_JACK_THR_96PCT;
+ default:
+ dev_warn(codec->dev, "Invalid jack threshold level");
+ return DA7218_HPLDET_JACK_THR_84PCT;
+ }
+}
+
+static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct device_node *np = codec->dev->of_node;
+ struct device_node *hpldet_np;
+ struct da7218_pdata *pdata;
+ struct da7218_hpldet_pdata *hpldet_pdata;
+ const char *of_str;
+ u32 of_val32;
+
+ pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_warn(codec->dev, "Failed to allocate memory for pdata\n");
+ return NULL;
+ }
+
+ if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0)
+ pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32);
+ else
+ pdata->micbias1_lvl = DA7218_MICBIAS_1_6V;
+
+ if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0)
+ pdata->micbias2_lvl = da7218_of_micbias_lvl(codec, of_val32);
+ else
+ pdata->micbias2_lvl = DA7218_MICBIAS_1_6V;
+
+ if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str))
+ pdata->mic1_amp_in_sel =
+ da7218_of_mic_amp_in_sel(codec, of_str);
+ else
+ pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+ if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str))
+ pdata->mic2_amp_in_sel =
+ da7218_of_mic_amp_in_sel(codec, of_str);
+ else
+ pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+ if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str))
+ pdata->dmic1_data_sel = da7218_of_dmic_data_sel(codec, of_str);
+ else
+ pdata->dmic1_data_sel = DA7218_DMIC_DATA_LRISE_RFALL;
+
+ if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str))
+ pdata->dmic1_samplephase =
+ da7218_of_dmic_samplephase(codec, of_str);
+ else
+ pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+ if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0)
+ pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+ else
+ pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+ if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str))
+ pdata->dmic2_data_sel = da7218_of_dmic_data_sel(codec, of_str);
+ else
+ pdata->dmic2_data_sel = DA7218_DMIC_DATA_LRISE_RFALL;
+
+ if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str))
+ pdata->dmic2_samplephase =
+ da7218_of_dmic_samplephase(codec, of_str);
+ else
+ pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+ if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0)
+ pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+ else
+ pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+ if (da7218->dev_id == DA7217_DEV_ID) {
+ if (of_property_read_bool(np, "dlg,hp-diff-single-supply"))
+ pdata->hp_diff_single_supply = true;
+ }
+
+ if (da7218->dev_id == DA7218_DEV_ID) {
+ hpldet_np = of_find_node_by_name(np, "da7218_hpldet");
+ if (!hpldet_np)
+ return pdata;
+
+ hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata),
+ GFP_KERNEL);
+ if (!hpldet_pdata) {
+ dev_warn(codec->dev,
+ "Failed to allocate memory for hpldet pdata\n");
+ of_node_put(hpldet_np);
+ return pdata;
+ }
+ pdata->hpldet_pdata = hpldet_pdata;
+
+ if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us",
+ &of_val32) >= 0)
+ hpldet_pdata->jack_rate =
+ da7218_of_jack_rate(codec, of_val32);
+ else
+ hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US;
+
+ if (of_property_read_u32(hpldet_np, "dlg,jack-debounce",
+ &of_val32) >= 0)
+ hpldet_pdata->jack_debounce =
+ da7218_of_jack_debounce(codec, of_val32);
+ else
+ hpldet_pdata->jack_debounce =
+ DA7218_HPLDET_JACK_DEBOUNCE_2;
+
+ if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct",
+ &of_val32) >= 0)
+ hpldet_pdata->jack_thr =
+ da7218_of_jack_thr(codec, of_val32);
+ else
+ hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT;
+
+ if (of_property_read_bool(hpldet_np, "dlg,comp-inv"))
+ hpldet_pdata->comp_inv = true;
+
+ if (of_property_read_bool(hpldet_np, "dlg,hyst"))
+ hpldet_pdata->hyst = true;
+
+ if (of_property_read_bool(hpldet_np, "dlg,discharge"))
+ hpldet_pdata->discharge = true;
+
+ of_node_put(hpldet_np);
+ }
+
+ return pdata;
+}
+
+
+/*
+ * Codec driver functions
+ */
+
+static int da7218_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ /* MCLK */
+ if (da7218->mclk) {
+ ret = clk_prepare_enable(da7218->mclk);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable mclk\n");
+ return ret;
+ }
+ }
+
+ /* Master bias */
+ snd_soc_update_bits(codec, DA7218_REFERENCES,
+ DA7218_BIAS_EN_MASK,
+ DA7218_BIAS_EN_MASK);
+
+ /* Internal LDO */
+ snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+ DA7218_LDO_EN_MASK,
+ DA7218_LDO_EN_MASK);
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* Only disable if jack detection disabled */
+ if (!da7218->jack) {
+ /* Internal LDO */
+ snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+ DA7218_LDO_EN_MASK, 0);
+
+ /* Master bias */
+ snd_soc_update_bits(codec, DA7218_REFERENCES,
+ DA7218_BIAS_EN_MASK, 0);
+ }
+
+ /* MCLK */
+ if (da7218->mclk)
+ clk_disable_unprepare(da7218->mclk);
+ break;
+ }
+
+ return 0;
+}
+
+static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = {
+ [DA7218_SUPPLY_VDD] = "VDD",
+ [DA7218_SUPPLY_VDDMIC] = "VDDMIC",
+ [DA7218_SUPPLY_VDDIO] = "VDDIO",
+};
+
+static int da7218_handle_supplies(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct regulator *vddio;
+ u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V;
+ int i, ret;
+
+ /* Get required supplies */
+ for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
+ da7218->supplies[i].supply = da7218_supply_names[i];
+
+ ret = devm_regulator_bulk_get(codec->dev, DA7218_NUM_SUPPLIES,
+ da7218->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to get supplies\n");
+ return ret;
+ }
+
+ /* Determine VDDIO voltage provided */
+ vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer;
+ ret = regulator_get_voltage(vddio);
+ if (ret < 1500000)
+ dev_warn(codec->dev, "Invalid VDDIO voltage\n");
+ else if (ret < 2500000)
+ io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V;
+
+ /* Enable main supplies */
+ ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable supplies\n");
+ return ret;
+ }
+
+ /* Ensure device in active mode */
+ snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK);
+
+ /* Update IO voltage level range */
+ snd_soc_write(codec, DA7218_IO_CTRL, io_voltage_lvl);
+
+ return 0;
+}
+
+static void da7218_handle_pdata(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ struct da7218_pdata *pdata = da7218->pdata;
+
+ if (pdata) {
+ u8 micbias_lvl = 0, dmic_cfg = 0;
+
+ /* Mic Bias voltages */
+ switch (pdata->micbias1_lvl) {
+ case DA7218_MICBIAS_1_2V:
+ micbias_lvl |= DA7218_MICBIAS_1_LP_MODE_MASK;
+ break;
+ case DA7218_MICBIAS_1_6V:
+ case DA7218_MICBIAS_1_8V:
+ case DA7218_MICBIAS_2_0V:
+ case DA7218_MICBIAS_2_2V:
+ case DA7218_MICBIAS_2_4V:
+ case DA7218_MICBIAS_2_6V:
+ case DA7218_MICBIAS_2_8V:
+ case DA7218_MICBIAS_3_0V:
+ micbias_lvl |= (pdata->micbias1_lvl <<
+ DA7218_MICBIAS_1_LEVEL_SHIFT);
+ break;
+ }
+
+ switch (pdata->micbias2_lvl) {
+ case DA7218_MICBIAS_1_2V:
+ micbias_lvl |= DA7218_MICBIAS_2_LP_MODE_MASK;
+ break;
+ case DA7218_MICBIAS_1_6V:
+ case DA7218_MICBIAS_1_8V:
+ case DA7218_MICBIAS_2_0V:
+ case DA7218_MICBIAS_2_2V:
+ case DA7218_MICBIAS_2_4V:
+ case DA7218_MICBIAS_2_6V:
+ case DA7218_MICBIAS_2_8V:
+ case DA7218_MICBIAS_3_0V:
+ micbias_lvl |= (pdata->micbias2_lvl <<
+ DA7218_MICBIAS_2_LEVEL_SHIFT);
+ break;
+ }
+
+ snd_soc_write(codec, DA7218_MICBIAS_CTRL, micbias_lvl);
+
+ /* Mic */
+ switch (pdata->mic1_amp_in_sel) {
+ case DA7218_MIC_AMP_IN_SEL_DIFF:
+ case DA7218_MIC_AMP_IN_SEL_SE_P:
+ case DA7218_MIC_AMP_IN_SEL_SE_N:
+ snd_soc_write(codec, DA7218_MIC_1_SELECT,
+ pdata->mic1_amp_in_sel);
+ break;
+ }
+
+ switch (pdata->mic2_amp_in_sel) {
+ case DA7218_MIC_AMP_IN_SEL_DIFF:
+ case DA7218_MIC_AMP_IN_SEL_SE_P:
+ case DA7218_MIC_AMP_IN_SEL_SE_N:
+ snd_soc_write(codec, DA7218_MIC_2_SELECT,
+ pdata->mic2_amp_in_sel);
+ break;
+ }
+
+ /* DMic */
+ switch (pdata->dmic1_data_sel) {
+ case DA7218_DMIC_DATA_LFALL_RRISE:
+ case DA7218_DMIC_DATA_LRISE_RFALL:
+ dmic_cfg |= (pdata->dmic1_data_sel <<
+ DA7218_DMIC_1_DATA_SEL_SHIFT);
+ break;
+ }
+
+ switch (pdata->dmic1_samplephase) {
+ case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+ case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+ dmic_cfg |= (pdata->dmic1_samplephase <<
+ DA7218_DMIC_1_SAMPLEPHASE_SHIFT);
+ break;
+ }
+
+ switch (pdata->dmic1_clk_rate) {
+ case DA7218_DMIC_CLK_3_0MHZ:
+ case DA7218_DMIC_CLK_1_5MHZ:
+ dmic_cfg |= (pdata->dmic1_clk_rate <<
+ DA7218_DMIC_1_CLK_RATE_SHIFT);
+ break;
+ }
+
+ snd_soc_update_bits(codec, DA7218_DMIC_1_CTRL,
+ DA7218_DMIC_1_DATA_SEL_MASK |
+ DA7218_DMIC_1_SAMPLEPHASE_MASK |
+ DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg);
+
+ dmic_cfg = 0;
+ switch (pdata->dmic2_data_sel) {
+ case DA7218_DMIC_DATA_LFALL_RRISE:
+ case DA7218_DMIC_DATA_LRISE_RFALL:
+ dmic_cfg |= (pdata->dmic2_data_sel <<
+ DA7218_DMIC_2_DATA_SEL_SHIFT);
+ break;
+ }
+
+ switch (pdata->dmic2_samplephase) {
+ case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+ case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+ dmic_cfg |= (pdata->dmic2_samplephase <<
+ DA7218_DMIC_2_SAMPLEPHASE_SHIFT);
+ break;
+ }
+
+ switch (pdata->dmic2_clk_rate) {
+ case DA7218_DMIC_CLK_3_0MHZ:
+ case DA7218_DMIC_CLK_1_5MHZ:
+ dmic_cfg |= (pdata->dmic2_clk_rate <<
+ DA7218_DMIC_2_CLK_RATE_SHIFT);
+ break;
+ }
+
+ snd_soc_update_bits(codec, DA7218_DMIC_2_CTRL,
+ DA7218_DMIC_2_DATA_SEL_MASK |
+ DA7218_DMIC_2_SAMPLEPHASE_MASK |
+ DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg);
+
+ /* DA7217 Specific */
+ if (da7218->dev_id == DA7217_DEV_ID) {
+ da7218->hp_single_supply =
+ pdata->hp_diff_single_supply;
+
+ if (da7218->hp_single_supply) {
+ snd_soc_write(codec, DA7218_HP_DIFF_UNLOCK,
+ DA7218_HP_DIFF_UNLOCK_VAL);
+ snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+ DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK,
+ DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK);
+ }
+ }
+
+ /* DA7218 Specific */
+ if ((da7218->dev_id == DA7218_DEV_ID) &&
+ (pdata->hpldet_pdata)) {
+ struct da7218_hpldet_pdata *hpldet_pdata =
+ pdata->hpldet_pdata;
+ u8 hpldet_cfg = 0;
+
+ switch (hpldet_pdata->jack_rate) {
+ case DA7218_HPLDET_JACK_RATE_5US:
+ case DA7218_HPLDET_JACK_RATE_10US:
+ case DA7218_HPLDET_JACK_RATE_20US:
+ case DA7218_HPLDET_JACK_RATE_40US:
+ case DA7218_HPLDET_JACK_RATE_80US:
+ case DA7218_HPLDET_JACK_RATE_160US:
+ case DA7218_HPLDET_JACK_RATE_320US:
+ case DA7218_HPLDET_JACK_RATE_640US:
+ hpldet_cfg |=
+ (hpldet_pdata->jack_rate <<
+ DA7218_HPLDET_JACK_RATE_SHIFT);
+ break;
+ }
+
+ switch (hpldet_pdata->jack_debounce) {
+ case DA7218_HPLDET_JACK_DEBOUNCE_OFF:
+ case DA7218_HPLDET_JACK_DEBOUNCE_2:
+ case DA7218_HPLDET_JACK_DEBOUNCE_3:
+ case DA7218_HPLDET_JACK_DEBOUNCE_4:
+ hpldet_cfg |=
+ (hpldet_pdata->jack_debounce <<
+ DA7218_HPLDET_JACK_DEBOUNCE_SHIFT);
+ break;
+ }
+
+ switch (hpldet_pdata->jack_thr) {
+ case DA7218_HPLDET_JACK_THR_84PCT:
+ case DA7218_HPLDET_JACK_THR_88PCT:
+ case DA7218_HPLDET_JACK_THR_92PCT:
+ case DA7218_HPLDET_JACK_THR_96PCT:
+ hpldet_cfg |=
+ (hpldet_pdata->jack_thr <<
+ DA7218_HPLDET_JACK_THR_SHIFT);
+ break;
+ }
+ snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+ DA7218_HPLDET_JACK_RATE_MASK |
+ DA7218_HPLDET_JACK_DEBOUNCE_MASK |
+ DA7218_HPLDET_JACK_THR_MASK,
+ hpldet_cfg);
+
+ hpldet_cfg = 0;
+ if (hpldet_pdata->comp_inv)
+ hpldet_cfg |= DA7218_HPLDET_COMP_INV_MASK;
+
+ if (hpldet_pdata->hyst)
+ hpldet_cfg |= DA7218_HPLDET_HYST_EN_MASK;
+
+ if (hpldet_pdata->discharge)
+ hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK;
+
+ snd_soc_write(codec, DA7218_HPLDET_CTRL, hpldet_cfg);
+ }
+ }
+}
+
+static int da7218_probe(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ /* Regulator configuration */
+ ret = da7218_handle_supplies(codec);
+ if (ret)
+ return ret;
+
+ /* Handle DT/Platform data */
+ if (codec->dev->of_node)
+ da7218->pdata = da7218_of_to_pdata(codec);
+ else
+ da7218->pdata = dev_get_platdata(codec->dev);
+
+ da7218_handle_pdata(codec);
+
+ /* Check if MCLK provided, if not the clock is NULL */
+ da7218->mclk = devm_clk_get(codec->dev, "mclk");
+ if (IS_ERR(da7218->mclk)) {
+ if (PTR_ERR(da7218->mclk) != -ENOENT) {
+ ret = PTR_ERR(da7218->mclk);
+ goto err_disable_reg;
+ } else {
+ da7218->mclk = NULL;
+ }
+ }
+
+ /* Default PC to free-running */
+ snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+ /*
+ * Default Output Filter mixers to off otherwise DAPM will power
+ * Mic to HP passthrough paths by default at startup.
+ */
+ snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1L, 0);
+ snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1R, 0);
+
+ /* Default CP to normal load, power mode */
+ snd_soc_update_bits(codec, DA7218_CP_CTRL,
+ DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0);
+
+ /* Default gain ramping */
+ snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+ DA7218_MIXIN_1_AMP_RAMP_EN_MASK,
+ DA7218_MIXIN_1_AMP_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+ DA7218_MIXIN_2_AMP_RAMP_EN_MASK,
+ DA7218_MIXIN_2_AMP_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+ DA7218_IN_1L_RAMP_EN_MASK,
+ DA7218_IN_1L_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+ DA7218_IN_1R_RAMP_EN_MASK,
+ DA7218_IN_1R_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+ DA7218_IN_2L_RAMP_EN_MASK,
+ DA7218_IN_2L_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+ DA7218_IN_2R_RAMP_EN_MASK,
+ DA7218_IN_2R_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_DGS_GAIN_CTRL,
+ DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_OUT_1L_FILTER_CTRL,
+ DA7218_OUT_1L_RAMP_EN_MASK,
+ DA7218_OUT_1L_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_OUT_1R_FILTER_CTRL,
+ DA7218_OUT_1R_RAMP_EN_MASK,
+ DA7218_OUT_1R_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_HP_L_CTRL,
+ DA7218_HP_L_AMP_RAMP_EN_MASK,
+ DA7218_HP_L_AMP_RAMP_EN_MASK);
+ snd_soc_update_bits(codec, DA7218_HP_R_CTRL,
+ DA7218_HP_R_AMP_RAMP_EN_MASK,
+ DA7218_HP_R_AMP_RAMP_EN_MASK);
+
+ /* Default infinite tone gen, start/stop by Kcontrol */
+ snd_soc_write(codec, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK);
+
+ /* DA7217 specific config */
+ if (da7218->dev_id == DA7217_DEV_ID) {
+ snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+ DA7218_HP_AMP_DIFF_MODE_EN_MASK,
+ DA7218_HP_AMP_DIFF_MODE_EN_MASK);
+
+ /* Only DA7218 supports HP detect, mask off for DA7217 */
+ snd_soc_write(codec, DA7218_EVENT_MASK,
+ DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK);
+ }
+
+ if (da7218->irq) {
+ ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL,
+ da7218_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "da7218", codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+ da7218->irq, ret);
+ goto err_disable_reg;
+ }
+
+ }
+
+ return 0;
+
+err_disable_reg:
+ regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+ return ret;
+}
+
+static int da7218_remove(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+ regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int da7218_suspend(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+ da7218_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ /* Put device into standby mode if jack detection disabled */
+ if (!da7218->jack)
+ snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, 0);
+
+ return 0;
+}
+
+static int da7218_resume(struct snd_soc_codec *codec)
+{
+ struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+ /* Put device into active mode if previously moved to standby */
+ if (!da7218->jack)
+ snd_soc_write(codec, DA7218_SYSTEM_ACTIVE,
+ DA7218_SYSTEM_ACTIVE_MASK);
+
+ da7218_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define da7218_suspend NULL
+#define da7218_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_da7218 = {
+ .probe = da7218_probe,
+ .remove = da7218_remove,
+ .suspend = da7218_suspend,
+ .resume = da7218_resume,
+ .set_bias_level = da7218_set_bias_level,
+
+ .controls = da7218_snd_controls,
+ .num_controls = ARRAY_SIZE(da7218_snd_controls),
+
+ .dapm_widgets = da7218_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(da7218_dapm_widgets),
+ .dapm_routes = da7218_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(da7218_audio_map),
+};
+
+
+/*
+ * Regmap configs
+ */
+
+static struct reg_default da7218_reg_defaults[] = {
+ { DA7218_SYSTEM_ACTIVE, 0x00 },
+ { DA7218_CIF_CTRL, 0x00 },
+ { DA7218_SPARE1, 0x00 },
+ { DA7218_SR, 0xAA },
+ { DA7218_PC_COUNT, 0x02 },
+ { DA7218_GAIN_RAMP_CTRL, 0x00 },
+ { DA7218_CIF_TIMEOUT_CTRL, 0x01 },
+ { DA7218_SYSTEM_MODES_INPUT, 0x00 },
+ { DA7218_SYSTEM_MODES_OUTPUT, 0x00 },
+ { DA7218_IN_1L_FILTER_CTRL, 0x00 },
+ { DA7218_IN_1R_FILTER_CTRL, 0x00 },
+ { DA7218_IN_2L_FILTER_CTRL, 0x00 },
+ { DA7218_IN_2R_FILTER_CTRL, 0x00 },
+ { DA7218_OUT_1L_FILTER_CTRL, 0x40 },
+ { DA7218_OUT_1R_FILTER_CTRL, 0x40 },
+ { DA7218_OUT_1_HPF_FILTER_CTRL, 0x80 },
+ { DA7218_OUT_1_EQ_12_FILTER_CTRL, 0x77 },
+ { DA7218_OUT_1_EQ_34_FILTER_CTRL, 0x77 },
+ { DA7218_OUT_1_EQ_5_FILTER_CTRL, 0x07 },
+ { DA7218_OUT_1_BIQ_5STAGE_CTRL, 0x40 },
+ { DA7218_OUT_1_BIQ_5STAGE_DATA, 0x00 },
+ { DA7218_OUT_1_BIQ_5STAGE_ADDR, 0x00 },
+ { DA7218_MIXIN_1_CTRL, 0x48 },
+ { DA7218_MIXIN_1_GAIN, 0x03 },
+ { DA7218_MIXIN_2_CTRL, 0x48 },
+ { DA7218_MIXIN_2_GAIN, 0x03 },
+ { DA7218_ALC_CTRL1, 0x00 },
+ { DA7218_ALC_CTRL2, 0x00 },
+ { DA7218_ALC_CTRL3, 0x00 },
+ { DA7218_ALC_NOISE, 0x3F },
+ { DA7218_ALC_TARGET_MIN, 0x3F },
+ { DA7218_ALC_TARGET_MAX, 0x00 },
+ { DA7218_ALC_GAIN_LIMITS, 0xFF },
+ { DA7218_ALC_ANA_GAIN_LIMITS, 0x71 },
+ { DA7218_ALC_ANTICLIP_CTRL, 0x00 },
+ { DA7218_AGS_ENABLE, 0x00 },
+ { DA7218_AGS_TRIGGER, 0x09 },
+ { DA7218_AGS_ATT_MAX, 0x00 },
+ { DA7218_AGS_TIMEOUT, 0x00 },
+ { DA7218_AGS_ANTICLIP_CTRL, 0x00 },
+ { DA7218_ENV_TRACK_CTRL, 0x00 },
+ { DA7218_LVL_DET_CTRL, 0x00 },
+ { DA7218_LVL_DET_LEVEL, 0x7F },
+ { DA7218_DGS_TRIGGER, 0x24 },
+ { DA7218_DGS_ENABLE, 0x00 },
+ { DA7218_DGS_RISE_FALL, 0x50 },
+ { DA7218_DGS_SYNC_DELAY, 0xA3 },
+ { DA7218_DGS_SYNC_DELAY2, 0x31 },
+ { DA7218_DGS_SYNC_DELAY3, 0x11 },
+ { DA7218_DGS_LEVELS, 0x01 },
+ { DA7218_DGS_GAIN_CTRL, 0x74 },
+ { DA7218_DROUTING_OUTDAI_1L, 0x01 },
+ { DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, 0x1C },
+ { DA7218_DROUTING_OUTDAI_1R, 0x04 },
+ { DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, 0x1C },
+ { DA7218_DROUTING_OUTFILT_1L, 0x01 },
+ { DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, 0x1C },
+ { DA7218_DROUTING_OUTFILT_1R, 0x04 },
+ { DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, 0x1C },
+ { DA7218_DROUTING_OUTDAI_2L, 0x04 },
+ { DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, 0x1C },
+ { DA7218_DROUTING_OUTDAI_2R, 0x08 },
+ { DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, 0x1C },
+ { DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, 0x1C },
+ { DA7218_DAI_CTRL, 0x28 },
+ { DA7218_DAI_TDM_CTRL, 0x40 },
+ { DA7218_DAI_OFFSET_LOWER, 0x00 },
+ { DA7218_DAI_OFFSET_UPPER, 0x00 },
+ { DA7218_DAI_CLK_MODE, 0x01 },
+ { DA7218_PLL_CTRL, 0x04 },
+ { DA7218_PLL_FRAC_TOP, 0x00 },
+ { DA7218_PLL_FRAC_BOT, 0x00 },
+ { DA7218_PLL_INTEGER, 0x20 },
+ { DA7218_DAC_NG_CTRL, 0x00 },
+ { DA7218_DAC_NG_SETUP_TIME, 0x00 },
+ { DA7218_DAC_NG_OFF_THRESH, 0x00 },
+ { DA7218_DAC_NG_ON_THRESH, 0x00 },
+ { DA7218_TONE_GEN_CFG2, 0x00 },
+ { DA7218_TONE_GEN_FREQ1_L, 0x55 },
+ { DA7218_TONE_GEN_FREQ1_U, 0x15 },
+ { DA7218_TONE_GEN_FREQ2_L, 0x00 },
+ { DA7218_TONE_GEN_FREQ2_U, 0x40 },
+ { DA7218_TONE_GEN_CYCLES, 0x00 },
+ { DA7218_TONE_GEN_ON_PER, 0x02 },
+ { DA7218_TONE_GEN_OFF_PER, 0x01 },
+ { DA7218_CP_CTRL, 0x60 },
+ { DA7218_CP_DELAY, 0x11 },
+ { DA7218_CP_VOL_THRESHOLD1, 0x0E },
+ { DA7218_MIC_1_CTRL, 0x40 },
+ { DA7218_MIC_1_GAIN, 0x01 },
+ { DA7218_MIC_1_SELECT, 0x00 },
+ { DA7218_MIC_2_CTRL, 0x40 },
+ { DA7218_MIC_2_GAIN, 0x01 },
+ { DA7218_MIC_2_SELECT, 0x00 },
+ { DA7218_IN_1_HPF_FILTER_CTRL, 0x80 },
+ { DA7218_IN_2_HPF_FILTER_CTRL, 0x80 },
+ { DA7218_ADC_1_CTRL, 0x07 },
+ { DA7218_ADC_2_CTRL, 0x07 },
+ { DA7218_MIXOUT_L_CTRL, 0x00 },
+ { DA7218_MIXOUT_L_GAIN, 0x03 },
+ { DA7218_MIXOUT_R_CTRL, 0x00 },
+ { DA7218_MIXOUT_R_GAIN, 0x03 },
+ { DA7218_HP_L_CTRL, 0x40 },
+ { DA7218_HP_L_GAIN, 0x3B },
+ { DA7218_HP_R_CTRL, 0x40 },
+ { DA7218_HP_R_GAIN, 0x3B },
+ { DA7218_HP_DIFF_CTRL, 0x00 },
+ { DA7218_HP_DIFF_UNLOCK, 0xC3 },
+ { DA7218_HPLDET_JACK, 0x0B },
+ { DA7218_HPLDET_CTRL, 0x00 },
+ { DA7218_REFERENCES, 0x08 },
+ { DA7218_IO_CTRL, 0x00 },
+ { DA7218_LDO_CTRL, 0x00 },
+ { DA7218_SIDETONE_CTRL, 0x40 },
+ { DA7218_SIDETONE_IN_SELECT, 0x00 },
+ { DA7218_SIDETONE_GAIN, 0x1C },
+ { DA7218_DROUTING_ST_OUTFILT_1L, 0x01 },
+ { DA7218_DROUTING_ST_OUTFILT_1R, 0x02 },
+ { DA7218_SIDETONE_BIQ_3STAGE_DATA, 0x00 },
+ { DA7218_SIDETONE_BIQ_3STAGE_ADDR, 0x00 },
+ { DA7218_EVENT_MASK, 0x00 },
+ { DA7218_DMIC_1_CTRL, 0x00 },
+ { DA7218_DMIC_2_CTRL, 0x00 },
+ { DA7218_IN_1L_GAIN, 0x6F },
+ { DA7218_IN_1R_GAIN, 0x6F },
+ { DA7218_IN_2L_GAIN, 0x6F },
+ { DA7218_IN_2R_GAIN, 0x6F },
+ { DA7218_OUT_1L_GAIN, 0x6F },
+ { DA7218_OUT_1R_GAIN, 0x6F },
+ { DA7218_MICBIAS_CTRL, 0x00 },
+ { DA7218_MICBIAS_EN, 0x00 },
+};
+
+static bool da7218_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA7218_STATUS1:
+ case DA7218_SOFT_RESET:
+ case DA7218_SYSTEM_STATUS:
+ case DA7218_CALIB_CTRL:
+ case DA7218_CALIB_OFFSET_AUTO_M_1:
+ case DA7218_CALIB_OFFSET_AUTO_U_1:
+ case DA7218_CALIB_OFFSET_AUTO_M_2:
+ case DA7218_CALIB_OFFSET_AUTO_U_2:
+ case DA7218_PLL_STATUS:
+ case DA7218_PLL_REFOSC_CAL:
+ case DA7218_TONE_GEN_CFG1:
+ case DA7218_ADC_MODE:
+ case DA7218_HP_SNGL_CTRL:
+ case DA7218_HPLDET_TEST:
+ case DA7218_EVENT_STATUS:
+ case DA7218_EVENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config da7218_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = DA7218_MICBIAS_EN,
+ .reg_defaults = da7218_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(da7218_reg_defaults),
+ .volatile_reg = da7218_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+
+/*
+ * I2C layer
+ */
+
+static int da7218_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct da7218_priv *da7218;
+ int ret;
+
+ da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv),
+ GFP_KERNEL);
+ if (!da7218)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, da7218);
+
+ if (i2c->dev.of_node)
+ da7218->dev_id = da7218_of_get_id(&i2c->dev);
+ else
+ da7218->dev_id = id->driver_data;
+
+ if ((da7218->dev_id != DA7217_DEV_ID) &&
+ (da7218->dev_id != DA7218_DEV_ID)) {
+ dev_err(&i2c->dev, "Invalid device Id\n");
+ return -EINVAL;
+ }
+
+ da7218->irq = i2c->irq;
+
+ da7218->regmap = devm_regmap_init_i2c(i2c, &da7218_regmap_config);
+ if (IS_ERR(da7218->regmap)) {
+ ret = PTR_ERR(da7218->regmap);
+ dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_da7218, &da7218_dai, 1);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to register da7218 codec: %d\n",
+ ret);
+ }
+ return ret;
+}
+
+static int da7218_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id da7218_i2c_id[] = {
+ { "da7217", DA7217_DEV_ID },
+ { "da7218", DA7218_DEV_ID },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, da7218_i2c_id);
+
+static struct i2c_driver da7218_i2c_driver = {
+ .driver = {
+ .name = "da7218",
+ .of_match_table = of_match_ptr(da7218_of_match),
+ },
+ .probe = da7218_i2c_probe,
+ .remove = da7218_i2c_remove,
+ .id_table = da7218_i2c_id,
+};
+
+module_i2c_driver(da7218_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7218 Codec driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
new file mode 100644
index 000000000000..c2c59049a2ad
--- /dev/null
+++ b/sound/soc/codecs/da7218.h
@@ -0,0 +1,1414 @@
+/*
+ * da7218.h - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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 _DA7218_H
+#define _DA7218_H
+
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/da7218.h>
+
+
+/*
+ * Registers
+ */
+#define DA7218_SYSTEM_ACTIVE 0x0
+#define DA7218_CIF_CTRL 0x1
+#define DA7218_CHIP_ID1 0x4
+#define DA7218_CHIP_ID2 0x5
+#define DA7218_CHIP_REVISION 0x6
+#define DA7218_SPARE1 0x7
+#define DA7218_STATUS1 0x8
+#define DA7218_SOFT_RESET 0x9
+#define DA7218_SR 0xB
+#define DA7218_PC_COUNT 0xC
+#define DA7218_GAIN_RAMP_CTRL 0xD
+#define DA7218_CIF_TIMEOUT_CTRL 0x10
+#define DA7218_SYSTEM_MODES_INPUT 0x14
+#define DA7218_SYSTEM_MODES_OUTPUT 0x15
+#define DA7218_SYSTEM_STATUS 0x16
+#define DA7218_IN_1L_FILTER_CTRL 0x18
+#define DA7218_IN_1R_FILTER_CTRL 0x19
+#define DA7218_IN_2L_FILTER_CTRL 0x1A
+#define DA7218_IN_2R_FILTER_CTRL 0x1B
+#define DA7218_OUT_1L_FILTER_CTRL 0x20
+#define DA7218_OUT_1R_FILTER_CTRL 0x21
+#define DA7218_OUT_1_HPF_FILTER_CTRL 0x24
+#define DA7218_OUT_1_EQ_12_FILTER_CTRL 0x25
+#define DA7218_OUT_1_EQ_34_FILTER_CTRL 0x26
+#define DA7218_OUT_1_EQ_5_FILTER_CTRL 0x27
+#define DA7218_OUT_1_BIQ_5STAGE_CTRL 0x28
+#define DA7218_OUT_1_BIQ_5STAGE_DATA 0x29
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR 0x2A
+#define DA7218_MIXIN_1_CTRL 0x2C
+#define DA7218_MIXIN_1_GAIN 0x2D
+#define DA7218_MIXIN_2_CTRL 0x2E
+#define DA7218_MIXIN_2_GAIN 0x2F
+#define DA7218_ALC_CTRL1 0x30
+#define DA7218_ALC_CTRL2 0x31
+#define DA7218_ALC_CTRL3 0x32
+#define DA7218_ALC_NOISE 0x33
+#define DA7218_ALC_TARGET_MIN 0x34
+#define DA7218_ALC_TARGET_MAX 0x35
+#define DA7218_ALC_GAIN_LIMITS 0x36
+#define DA7218_ALC_ANA_GAIN_LIMITS 0x37
+#define DA7218_ALC_ANTICLIP_CTRL 0x38
+#define DA7218_AGS_ENABLE 0x3C
+#define DA7218_AGS_TRIGGER 0x3D
+#define DA7218_AGS_ATT_MAX 0x3E
+#define DA7218_AGS_TIMEOUT 0x3F
+#define DA7218_AGS_ANTICLIP_CTRL 0x40
+#define DA7218_CALIB_CTRL 0x44
+#define DA7218_CALIB_OFFSET_AUTO_M_1 0x45
+#define DA7218_CALIB_OFFSET_AUTO_U_1 0x46
+#define DA7218_CALIB_OFFSET_AUTO_M_2 0x47
+#define DA7218_CALIB_OFFSET_AUTO_U_2 0x48
+#define DA7218_ENV_TRACK_CTRL 0x4C
+#define DA7218_LVL_DET_CTRL 0x50
+#define DA7218_LVL_DET_LEVEL 0x51
+#define DA7218_DGS_TRIGGER 0x54
+#define DA7218_DGS_ENABLE 0x55
+#define DA7218_DGS_RISE_FALL 0x56
+#define DA7218_DGS_SYNC_DELAY 0x57
+#define DA7218_DGS_SYNC_DELAY2 0x58
+#define DA7218_DGS_SYNC_DELAY3 0x59
+#define DA7218_DGS_LEVELS 0x5A
+#define DA7218_DGS_GAIN_CTRL 0x5B
+#define DA7218_DROUTING_OUTDAI_1L 0x5C
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN 0x5D
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN 0x5E
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN 0x5F
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN 0x60
+#define DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN 0x61
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN 0x62
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN 0x63
+#define DA7218_DROUTING_OUTDAI_1R 0x64
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN 0x65
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN 0x66
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN 0x67
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN 0x68
+#define DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN 0x69
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN 0x6A
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN 0x6B
+#define DA7218_DROUTING_OUTFILT_1L 0x6C
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN 0x6D
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN 0x6E
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN 0x6F
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN 0x70
+#define DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN 0x71
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN 0x72
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN 0x73
+#define DA7218_DROUTING_OUTFILT_1R 0x74
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN 0x75
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN 0x76
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN 0x77
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN 0x78
+#define DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN 0x79
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN 0x7A
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN 0x7B
+#define DA7218_DROUTING_OUTDAI_2L 0x7C
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN 0x7D
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN 0x7E
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN 0x7F
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN 0x80
+#define DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN 0x81
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN 0x82
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN 0x83
+#define DA7218_DROUTING_OUTDAI_2R 0x84
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN 0x85
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN 0x86
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN 0x87
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN 0x88
+#define DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN 0x89
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN 0x8A
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN 0x8B
+#define DA7218_DAI_CTRL 0x8C
+#define DA7218_DAI_TDM_CTRL 0x8D
+#define DA7218_DAI_OFFSET_LOWER 0x8E
+#define DA7218_DAI_OFFSET_UPPER 0x8F
+#define DA7218_DAI_CLK_MODE 0x90
+#define DA7218_PLL_CTRL 0x91
+#define DA7218_PLL_FRAC_TOP 0x92
+#define DA7218_PLL_FRAC_BOT 0x93
+#define DA7218_PLL_INTEGER 0x94
+#define DA7218_PLL_STATUS 0x95
+#define DA7218_PLL_REFOSC_CAL 0x98
+#define DA7218_DAC_NG_CTRL 0x9C
+#define DA7218_DAC_NG_SETUP_TIME 0x9D
+#define DA7218_DAC_NG_OFF_THRESH 0x9E
+#define DA7218_DAC_NG_ON_THRESH 0x9F
+#define DA7218_TONE_GEN_CFG1 0xA0
+#define DA7218_TONE_GEN_CFG2 0xA1
+#define DA7218_TONE_GEN_FREQ1_L 0xA2
+#define DA7218_TONE_GEN_FREQ1_U 0xA3
+#define DA7218_TONE_GEN_FREQ2_L 0xA4
+#define DA7218_TONE_GEN_FREQ2_U 0xA5
+#define DA7218_TONE_GEN_CYCLES 0xA6
+#define DA7218_TONE_GEN_ON_PER 0xA7
+#define DA7218_TONE_GEN_OFF_PER 0xA8
+#define DA7218_CP_CTRL 0xAC
+#define DA7218_CP_DELAY 0xAD
+#define DA7218_CP_VOL_THRESHOLD1 0xAE
+#define DA7218_MIC_1_CTRL 0xB4
+#define DA7218_MIC_1_GAIN 0xB5
+#define DA7218_MIC_1_SELECT 0xB7
+#define DA7218_MIC_2_CTRL 0xB8
+#define DA7218_MIC_2_GAIN 0xB9
+#define DA7218_MIC_2_SELECT 0xBB
+#define DA7218_IN_1_HPF_FILTER_CTRL 0xBC
+#define DA7218_IN_2_HPF_FILTER_CTRL 0xBD
+#define DA7218_ADC_1_CTRL 0xC0
+#define DA7218_ADC_2_CTRL 0xC1
+#define DA7218_ADC_MODE 0xC2
+#define DA7218_MIXOUT_L_CTRL 0xCC
+#define DA7218_MIXOUT_L_GAIN 0xCD
+#define DA7218_MIXOUT_R_CTRL 0xCE
+#define DA7218_MIXOUT_R_GAIN 0xCF
+#define DA7218_HP_L_CTRL 0xD0
+#define DA7218_HP_L_GAIN 0xD1
+#define DA7218_HP_R_CTRL 0xD2
+#define DA7218_HP_R_GAIN 0xD3
+#define DA7218_HP_SNGL_CTRL 0xD4
+#define DA7218_HP_DIFF_CTRL 0xD5
+#define DA7218_HP_DIFF_UNLOCK 0xD7
+#define DA7218_HPLDET_JACK 0xD8
+#define DA7218_HPLDET_CTRL 0xD9
+#define DA7218_HPLDET_TEST 0xDA
+#define DA7218_REFERENCES 0xDC
+#define DA7218_IO_CTRL 0xE0
+#define DA7218_LDO_CTRL 0xE1
+#define DA7218_SIDETONE_CTRL 0xE4
+#define DA7218_SIDETONE_IN_SELECT 0xE5
+#define DA7218_SIDETONE_GAIN 0xE6
+#define DA7218_DROUTING_ST_OUTFILT_1L 0xE8
+#define DA7218_DROUTING_ST_OUTFILT_1R 0xE9
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA 0xEA
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR 0xEB
+#define DA7218_EVENT_STATUS 0xEC
+#define DA7218_EVENT 0xED
+#define DA7218_EVENT_MASK 0xEE
+#define DA7218_DMIC_1_CTRL 0xF0
+#define DA7218_DMIC_2_CTRL 0xF1
+#define DA7218_IN_1L_GAIN 0xF4
+#define DA7218_IN_1R_GAIN 0xF5
+#define DA7218_IN_2L_GAIN 0xF6
+#define DA7218_IN_2R_GAIN 0xF7
+#define DA7218_OUT_1L_GAIN 0xF8
+#define DA7218_OUT_1R_GAIN 0xF9
+#define DA7218_MICBIAS_CTRL 0xFC
+#define DA7218_MICBIAS_EN 0xFD
+
+
+/*
+ * Bit Fields
+ */
+
+#define DA7218_SWITCH_EN_MAX 0x1
+
+/* DA7218_SYSTEM_ACTIVE = 0x0 */
+#define DA7218_SYSTEM_ACTIVE_SHIFT 0
+#define DA7218_SYSTEM_ACTIVE_MASK (0x1 << 0)
+
+/* DA7218_CIF_CTRL = 0x1 */
+#define DA7218_CIF_I2C_WRITE_MODE_SHIFT 0
+#define DA7218_CIF_I2C_WRITE_MODE_MASK (0x1 << 0)
+
+/* DA7218_CHIP_ID1 = 0x4 */
+#define DA7218_CHIP_ID1_SHIFT 0
+#define DA7218_CHIP_ID1_MASK (0xFF << 0)
+
+/* DA7218_CHIP_ID2 = 0x5 */
+#define DA7218_CHIP_ID2_SHIFT 0
+#define DA7218_CHIP_ID2_MASK (0xFF << 0)
+
+/* DA7218_CHIP_REVISION = 0x6 */
+#define DA7218_CHIP_MINOR_SHIFT 0
+#define DA7218_CHIP_MINOR_MASK (0xF << 0)
+#define DA7218_CHIP_MAJOR_SHIFT 4
+#define DA7218_CHIP_MAJOR_MASK (0xF << 4)
+
+/* DA7218_SPARE1 = 0x7 */
+#define DA7218_SPARE1_SHIFT 0
+#define DA7218_SPARE1_MASK (0xFF << 0)
+
+/* DA7218_STATUS1 = 0x8 */
+#define DA7218_STATUS_SPARE1_SHIFT 0
+#define DA7218_STATUS_SPARE1_MASK (0xFF << 0)
+
+/* DA7218_SOFT_RESET = 0x9 */
+#define DA7218_CIF_REG_SOFT_RESET_SHIFT 7
+#define DA7218_CIF_REG_SOFT_RESET_MASK (0x1 << 7)
+
+/* DA7218_SR = 0xB */
+#define DA7218_SR_ADC_SHIFT 0
+#define DA7218_SR_ADC_MASK (0xF << 0)
+#define DA7218_SR_DAC_SHIFT 4
+#define DA7218_SR_DAC_MASK (0xF << 4)
+#define DA7218_SR_8000 0x01
+#define DA7218_SR_11025 0x02
+#define DA7218_SR_12000 0x03
+#define DA7218_SR_16000 0x05
+#define DA7218_SR_22050 0x06
+#define DA7218_SR_24000 0x07
+#define DA7218_SR_32000 0x09
+#define DA7218_SR_44100 0x0A
+#define DA7218_SR_48000 0x0B
+#define DA7218_SR_88200 0x0E
+#define DA7218_SR_96000 0x0F
+
+/* DA7218_PC_COUNT = 0xC */
+#define DA7218_PC_FREERUN_SHIFT 0
+#define DA7218_PC_FREERUN_MASK (0x1 << 0)
+#define DA7218_PC_RESYNC_AUTO_SHIFT 1
+#define DA7218_PC_RESYNC_AUTO_MASK (0x1 << 1)
+
+/* DA7218_GAIN_RAMP_CTRL = 0xD */
+#define DA7218_GAIN_RAMP_RATE_SHIFT 0
+#define DA7218_GAIN_RAMP_RATE_MASK (0x3 << 0)
+#define DA7218_GAIN_RAMP_RATE_MAX 4
+
+/* DA7218_CIF_TIMEOUT_CTRL = 0x10 */
+#define DA7218_I2C_TIMEOUT_EN_SHIFT 0
+#define DA7218_I2C_TIMEOUT_EN_MASK (0x1 << 0)
+
+/* DA7218_SYSTEM_MODES_INPUT = 0x14 */
+#define DA7218_MODE_SUBMIT_SHIFT 0
+#define DA7218_MODE_SUBMIT_MASK (0x1 << 0)
+#define DA7218_ADC_MODE_SHIFT 1
+#define DA7218_ADC_MODE_MASK (0x7F << 1)
+
+/* DA7218_SYSTEM_MODES_OUTPUT = 0x15 */
+#define DA7218_MODE_SUBMIT_SHIFT 0
+#define DA7218_MODE_SUBMIT_MASK (0x1 << 0)
+#define DA7218_DAC_MODE_SHIFT 1
+#define DA7218_DAC_MODE_MASK (0x7F << 1)
+
+/* DA7218_SYSTEM_STATUS = 0x16 */
+#define DA7218_SC1_BUSY_SHIFT 0
+#define DA7218_SC1_BUSY_MASK (0x1 << 0)
+#define DA7218_SC2_BUSY_SHIFT 1
+#define DA7218_SC2_BUSY_MASK (0x1 << 1)
+
+/* DA7218_IN_1L_FILTER_CTRL = 0x18 */
+#define DA7218_IN_1L_RAMP_EN_SHIFT 5
+#define DA7218_IN_1L_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_IN_1L_MUTE_EN_SHIFT 6
+#define DA7218_IN_1L_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_IN_1L_FILTER_EN_SHIFT 7
+#define DA7218_IN_1L_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_IN_1R_FILTER_CTRL = 0x19 */
+#define DA7218_IN_1R_RAMP_EN_SHIFT 5
+#define DA7218_IN_1R_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_IN_1R_MUTE_EN_SHIFT 6
+#define DA7218_IN_1R_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_IN_1R_FILTER_EN_SHIFT 7
+#define DA7218_IN_1R_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_IN_2L_FILTER_CTRL = 0x1A */
+#define DA7218_IN_2L_RAMP_EN_SHIFT 5
+#define DA7218_IN_2L_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_IN_2L_MUTE_EN_SHIFT 6
+#define DA7218_IN_2L_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_IN_2L_FILTER_EN_SHIFT 7
+#define DA7218_IN_2L_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_IN_2R_FILTER_CTRL = 0x1B */
+#define DA7218_IN_2R_RAMP_EN_SHIFT 5
+#define DA7218_IN_2R_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_IN_2R_MUTE_EN_SHIFT 6
+#define DA7218_IN_2R_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_IN_2R_FILTER_EN_SHIFT 7
+#define DA7218_IN_2R_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_OUT_1L_FILTER_CTRL = 0x20 */
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT 3
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_MASK (0x1 << 3)
+#define DA7218_OUT_BIQ_5STAGE_SEL_MAX 2
+#define DA7218_OUT_1L_SUBRANGE_EN_SHIFT 4
+#define DA7218_OUT_1L_SUBRANGE_EN_MASK (0x1 << 4)
+#define DA7218_OUT_1L_RAMP_EN_SHIFT 5
+#define DA7218_OUT_1L_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_OUT_1L_MUTE_EN_SHIFT 6
+#define DA7218_OUT_1L_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_OUT_1L_FILTER_EN_SHIFT 7
+#define DA7218_OUT_1L_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_OUT_1R_FILTER_CTRL = 0x21 */
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT 3
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_MASK (0x1 << 3)
+#define DA7218_OUT_1R_SUBRANGE_EN_SHIFT 4
+#define DA7218_OUT_1R_SUBRANGE_EN_MASK (0x1 << 4)
+#define DA7218_OUT_1R_RAMP_EN_SHIFT 5
+#define DA7218_OUT_1R_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_OUT_1R_MUTE_EN_SHIFT 6
+#define DA7218_OUT_1R_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_OUT_1R_FILTER_EN_SHIFT 7
+#define DA7218_OUT_1R_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_OUT_1_HPF_FILTER_CTRL = 0x24 */
+#define DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT 0
+#define DA7218_OUT_1_VOICE_HPF_CORNER_MASK (0x7 << 0)
+#define DA7218_VOICE_HPF_CORNER_MAX 8
+#define DA7218_OUT_1_VOICE_EN_SHIFT 3
+#define DA7218_OUT_1_VOICE_EN_MASK (0x1 << 3)
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT 4
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_MASK (0x3 << 4)
+#define DA7218_AUDIO_HPF_CORNER_MAX 4
+#define DA7218_OUT_1_HPF_EN_SHIFT 7
+#define DA7218_OUT_1_HPF_EN_MASK (0x1 << 7)
+#define DA7218_HPF_MODE_SHIFT 0
+#define DA7218_HPF_DISABLED ((0x0 << 3) | (0x0 << 7))
+#define DA7218_HPF_AUDIO_EN ((0x0 << 3) | (0x1 << 7))
+#define DA7218_HPF_VOICE_EN ((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MASK ((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MAX 3
+
+/* DA7218_OUT_1_EQ_12_FILTER_CTRL = 0x25 */
+#define DA7218_OUT_1_EQ_BAND1_SHIFT 0
+#define DA7218_OUT_1_EQ_BAND1_MASK (0xF << 0)
+#define DA7218_OUT_EQ_BAND_MAX 0xF
+#define DA7218_OUT_1_EQ_BAND2_SHIFT 4
+#define DA7218_OUT_1_EQ_BAND2_MASK (0xF << 4)
+
+/* DA7218_OUT_1_EQ_34_FILTER_CTRL = 0x26 */
+#define DA7218_OUT_1_EQ_BAND3_SHIFT 0
+#define DA7218_OUT_1_EQ_BAND3_MASK (0xF << 0)
+#define DA7218_OUT_1_EQ_BAND4_SHIFT 4
+#define DA7218_OUT_1_EQ_BAND4_MASK (0xF << 4)
+
+/* DA7218_OUT_1_EQ_5_FILTER_CTRL = 0x27 */
+#define DA7218_OUT_1_EQ_BAND5_SHIFT 0
+#define DA7218_OUT_1_EQ_BAND5_MASK (0xF << 0)
+#define DA7218_OUT_1_EQ_EN_SHIFT 7
+#define DA7218_OUT_1_EQ_EN_MASK (0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_CTRL = 0x28 */
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT 6
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT 7
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_DATA = 0x29 */
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_SHIFT 0
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_MASK (0xFF << 0)
+
+/* DA7218_OUT_1_BIQ_5STAGE_ADDR = 0x2A */
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_SHIFT 0
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_MASK (0x3F << 0)
+#define DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE 50
+
+/* DA7218_MIXIN_1_CTRL = 0x2C */
+#define DA7218_MIXIN_1_MIX_SEL_SHIFT 3
+#define DA7218_MIXIN_1_MIX_SEL_MASK (0x1 << 3)
+#define DA7218_MIXIN_1_AMP_ZC_EN_SHIFT 4
+#define DA7218_MIXIN_1_AMP_ZC_EN_MASK (0x1 << 4)
+#define DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT 5
+#define DA7218_MIXIN_1_AMP_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT 6
+#define DA7218_MIXIN_1_AMP_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_MIXIN_1_AMP_EN_SHIFT 7
+#define DA7218_MIXIN_1_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_MIXIN_1_GAIN = 0x2D */
+#define DA7218_MIXIN_1_AMP_GAIN_SHIFT 0
+#define DA7218_MIXIN_1_AMP_GAIN_MASK (0xF << 0)
+#define DA7218_MIXIN_AMP_GAIN_MAX 0xF
+
+/* DA7218_MIXIN_2_CTRL = 0x2E */
+#define DA7218_MIXIN_2_MIX_SEL_SHIFT 3
+#define DA7218_MIXIN_2_MIX_SEL_MASK (0x1 << 3)
+#define DA7218_MIXIN_2_AMP_ZC_EN_SHIFT 4
+#define DA7218_MIXIN_2_AMP_ZC_EN_MASK (0x1 << 4)
+#define DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT 5
+#define DA7218_MIXIN_2_AMP_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT 6
+#define DA7218_MIXIN_2_AMP_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_MIXIN_2_AMP_EN_SHIFT 7
+#define DA7218_MIXIN_2_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_MIXIN_2_GAIN = 0x2F */
+#define DA7218_MIXIN_2_AMP_GAIN_SHIFT 0
+#define DA7218_MIXIN_2_AMP_GAIN_MASK (0xF << 0)
+
+/* DA7218_ALC_CTRL1 = 0x30 */
+#define DA7218_ALC_EN_SHIFT 0
+#define DA7218_ALC_EN_MASK (0xF << 0)
+#define DA7218_ALC_CHAN1_L_EN_SHIFT 0
+#define DA7218_ALC_CHAN1_R_EN_SHIFT 1
+#define DA7218_ALC_CHAN2_L_EN_SHIFT 2
+#define DA7218_ALC_CHAN2_R_EN_SHIFT 3
+#define DA7218_ALC_SYNC_MODE_SHIFT 4
+#define DA7218_ALC_SYNC_MODE_MASK (0xF << 4)
+#define DA7218_ALC_SYNC_MODE_CH1 (0x1 << 4)
+#define DA7218_ALC_SYNC_MODE_CH2 (0x4 << 4)
+
+/* DA7218_ALC_CTRL2 = 0x31 */
+#define DA7218_ALC_ATTACK_SHIFT 0
+#define DA7218_ALC_ATTACK_MASK (0xF << 0)
+#define DA7218_ALC_ATTACK_MAX 13
+#define DA7218_ALC_RELEASE_SHIFT 4
+#define DA7218_ALC_RELEASE_MASK (0xF << 4)
+#define DA7218_ALC_RELEASE_MAX 11
+
+/* DA7218_ALC_CTRL3 = 0x32 */
+#define DA7218_ALC_HOLD_SHIFT 0
+#define DA7218_ALC_HOLD_MASK (0xF << 0)
+#define DA7218_ALC_HOLD_MAX 16
+
+/* DA7218_ALC_NOISE = 0x33 */
+#define DA7218_ALC_NOISE_SHIFT 0
+#define DA7218_ALC_NOISE_MASK (0x3F << 0)
+#define DA7218_ALC_THRESHOLD_MAX 0x3F
+
+/* DA7218_ALC_TARGET_MIN = 0x34 */
+#define DA7218_ALC_THRESHOLD_MIN_SHIFT 0
+#define DA7218_ALC_THRESHOLD_MIN_MASK (0x3F << 0)
+
+/* DA7218_ALC_TARGET_MAX = 0x35 */
+#define DA7218_ALC_THRESHOLD_MAX_SHIFT 0
+#define DA7218_ALC_THRESHOLD_MAX_MASK (0x3F << 0)
+
+/* DA7218_ALC_GAIN_LIMITS = 0x36 */
+#define DA7218_ALC_ATTEN_MAX_SHIFT 0
+#define DA7218_ALC_ATTEN_MAX_MASK (0xF << 0)
+#define DA7218_ALC_ATTEN_GAIN_MAX 0xF
+#define DA7218_ALC_GAIN_MAX_SHIFT 4
+#define DA7218_ALC_GAIN_MAX_MASK (0xF << 4)
+
+/* DA7218_ALC_ANA_GAIN_LIMITS = 0x37 */
+#define DA7218_ALC_ANA_GAIN_MIN_SHIFT 0
+#define DA7218_ALC_ANA_GAIN_MIN_MASK (0x7 << 0)
+#define DA7218_ALC_ANA_GAIN_MIN 0x1
+#define DA7218_ALC_ANA_GAIN_MAX 0x7
+#define DA7218_ALC_ANA_GAIN_MAX_SHIFT 4
+#define DA7218_ALC_ANA_GAIN_MAX_MASK (0x7 << 4)
+
+/* DA7218_ALC_ANTICLIP_CTRL = 0x38 */
+#define DA7218_ALC_ANTICLIP_STEP_SHIFT 0
+#define DA7218_ALC_ANTICLIP_STEP_MASK (0x3 << 0)
+#define DA7218_ALC_ANTICLIP_STEP_MAX 4
+#define DA7218_ALC_ANTICLIP_EN_SHIFT 7
+#define DA7218_ALC_ANTICLIP_EN_MASK (0x1 << 7)
+
+/* DA7218_AGS_ENABLE = 0x3C */
+#define DA7218_AGS_ENABLE_SHIFT 0
+#define DA7218_AGS_ENABLE_MASK (0x3 << 0)
+#define DA7218_AGS_ENABLE_CHAN1_SHIFT 0
+#define DA7218_AGS_ENABLE_CHAN2_SHIFT 1
+
+/* DA7218_AGS_TRIGGER = 0x3D */
+#define DA7218_AGS_TRIGGER_SHIFT 0
+#define DA7218_AGS_TRIGGER_MASK (0xF << 0)
+#define DA7218_AGS_TRIGGER_MAX 0xF
+
+/* DA7218_AGS_ATT_MAX = 0x3E */
+#define DA7218_AGS_ATT_MAX_SHIFT 0
+#define DA7218_AGS_ATT_MAX_MASK (0x7 << 0)
+#define DA7218_AGS_ATT_MAX_MAX 0x7
+
+/* DA7218_AGS_TIMEOUT = 0x3F */
+#define DA7218_AGS_TIMEOUT_EN_SHIFT 0
+#define DA7218_AGS_TIMEOUT_EN_MASK (0x1 << 0)
+
+/* DA7218_AGS_ANTICLIP_CTRL = 0x40 */
+#define DA7218_AGS_ANTICLIP_EN_SHIFT 7
+#define DA7218_AGS_ANTICLIP_EN_MASK (0x1 << 7)
+
+/* DA7218_CALIB_CTRL = 0x44 */
+#define DA7218_CALIB_OFFSET_EN_SHIFT 0
+#define DA7218_CALIB_OFFSET_EN_MASK (0x1 << 0)
+#define DA7218_CALIB_AUTO_EN_SHIFT 2
+#define DA7218_CALIB_AUTO_EN_MASK (0x1 << 2)
+#define DA7218_CALIB_OVERFLOW_SHIFT 3
+#define DA7218_CALIB_OVERFLOW_MASK (0x1 << 3)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_1 = 0x45 */
+#define DA7218_CALIB_OFFSET_AUTO_M_1_SHIFT 0
+#define DA7218_CALIB_OFFSET_AUTO_M_1_MASK (0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_1 = 0x46 */
+#define DA7218_CALIB_OFFSET_AUTO_U_1_SHIFT 0
+#define DA7218_CALIB_OFFSET_AUTO_U_1_MASK (0xF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_2 = 0x47 */
+#define DA7218_CALIB_OFFSET_AUTO_M_2_SHIFT 0
+#define DA7218_CALIB_OFFSET_AUTO_M_2_MASK (0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_2 = 0x48 */
+#define DA7218_CALIB_OFFSET_AUTO_U_2_SHIFT 0
+#define DA7218_CALIB_OFFSET_AUTO_U_2_MASK (0xF << 0)
+
+/* DA7218_ENV_TRACK_CTRL = 0x4C */
+#define DA7218_INTEG_ATTACK_SHIFT 0
+#define DA7218_INTEG_ATTACK_MASK (0x3 << 0)
+#define DA7218_INTEG_RELEASE_SHIFT 4
+#define DA7218_INTEG_RELEASE_MASK (0x3 << 4)
+#define DA7218_INTEG_MAX 4
+
+/* DA7218_LVL_DET_CTRL = 0x50 */
+#define DA7218_LVL_DET_EN_SHIFT 0
+#define DA7218_LVL_DET_EN_MASK (0xF << 0)
+#define DA7218_LVL_DET_EN_CHAN1L_SHIFT 0
+#define DA7218_LVL_DET_EN_CHAN1R_SHIFT 1
+#define DA7218_LVL_DET_EN_CHAN2L_SHIFT 2
+#define DA7218_LVL_DET_EN_CHAN2R_SHIFT 3
+
+/* DA7218_LVL_DET_LEVEL = 0x51 */
+#define DA7218_LVL_DET_LEVEL_SHIFT 0
+#define DA7218_LVL_DET_LEVEL_MASK (0x7F << 0)
+#define DA7218_LVL_DET_LEVEL_MAX 0x7F
+
+/* DA7218_DGS_TRIGGER = 0x54 */
+#define DA7218_DGS_TRIGGER_LVL_SHIFT 0
+#define DA7218_DGS_TRIGGER_LVL_MASK (0x3F << 0)
+#define DA7218_DGS_TRIGGER_MAX 0x3F
+
+/* DA7218_DGS_ENABLE = 0x55 */
+#define DA7218_DGS_ENABLE_SHIFT 0
+#define DA7218_DGS_ENABLE_MASK (0x3 << 0)
+#define DA7218_DGS_ENABLE_L_SHIFT 0
+#define DA7218_DGS_ENABLE_R_SHIFT 1
+
+/* DA7218_DGS_RISE_FALL = 0x56 */
+#define DA7218_DGS_RISE_COEFF_SHIFT 0
+#define DA7218_DGS_RISE_COEFF_MASK (0x7 << 0)
+#define DA7218_DGS_RISE_COEFF_MAX 7
+#define DA7218_DGS_FALL_COEFF_SHIFT 4
+#define DA7218_DGS_FALL_COEFF_MASK (0x7 << 4)
+#define DA7218_DGS_FALL_COEFF_MAX 8
+
+/* DA7218_DGS_SYNC_DELAY = 0x57 */
+#define DA7218_DGS_SYNC_DELAY_SHIFT 0
+#define DA7218_DGS_SYNC_DELAY_MASK (0xFF << 0)
+#define DA7218_DGS_SYNC_DELAY_MAX 0xFF
+
+/* DA7218_DGS_SYNC_DELAY2 = 0x58 */
+#define DA7218_DGS_SYNC_DELAY2_SHIFT 0
+#define DA7218_DGS_SYNC_DELAY2_MASK (0xFF << 0)
+
+/* DA7218_DGS_SYNC_DELAY3 = 0x59 */
+#define DA7218_DGS_SYNC_DELAY3_SHIFT 0
+#define DA7218_DGS_SYNC_DELAY3_MASK (0x7F << 0)
+#define DA7218_DGS_SYNC_DELAY3_MAX 0x7F
+
+/* DA7218_DGS_LEVELS = 0x5A */
+#define DA7218_DGS_ANTICLIP_LVL_SHIFT 0
+#define DA7218_DGS_ANTICLIP_LVL_MASK (0x7 << 0)
+#define DA7218_DGS_ANTICLIP_LVL_MAX 0x7
+#define DA7218_DGS_SIGNAL_LVL_SHIFT 4
+#define DA7218_DGS_SIGNAL_LVL_MASK (0xF << 4)
+#define DA7218_DGS_SIGNAL_LVL_MAX 0xF
+
+/* DA7218_DGS_GAIN_CTRL = 0x5B */
+#define DA7218_DGS_STEPS_SHIFT 0
+#define DA7218_DGS_STEPS_MASK (0x1F << 0)
+#define DA7218_DGS_STEPS_MAX 0x1F
+#define DA7218_DGS_RAMP_EN_SHIFT 5
+#define DA7218_DGS_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_DGS_SUBR_EN_SHIFT 6
+#define DA7218_DGS_SUBR_EN_MASK (0x1 << 6)
+
+/* DA7218_DROUTING_OUTDAI_1L = 0x5C */
+#define DA7218_OUTDAI_1L_SRC_SHIFT 0
+#define DA7218_OUTDAI_1L_SRC_MASK (0x7F << 0)
+#define DA7218_DMIX_SRC_INFILT1L 0
+#define DA7218_DMIX_SRC_INFILT1R 1
+#define DA7218_DMIX_SRC_INFILT2L 2
+#define DA7218_DMIX_SRC_INFILT2R 3
+#define DA7218_DMIX_SRC_TONEGEN 4
+#define DA7218_DMIX_SRC_DAIL 5
+#define DA7218_DMIX_SRC_DAIR 6
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN = 0x5D */
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_MASK (0x1F << 0)
+#define DA7218_DMIX_GAIN_MAX 0x1F
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN = 0x5E */
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN = 0x5F */
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN = 0x60 */
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN = 0x61 */
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN = 0x62 */
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN = 0x63 */
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_1R = 0x64 */
+#define DA7218_OUTDAI_1R_SRC_SHIFT 0
+#define DA7218_OUTDAI_1R_SRC_MASK (0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN = 0x65 */
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN = 0x66 */
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN = 0x67 */
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN = 0x68 */
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN = 0x69 */
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN = 0x6A */
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN = 0x6B */
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1L = 0x6C */
+#define DA7218_OUTFILT_1L_SRC_SHIFT 0
+#define DA7218_OUTFILT_1L_SRC_MASK (0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN = 0x6D */
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN = 0x6E */
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN = 0x6F */
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN = 0x70 */
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN = 0x71 */
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN = 0x72 */
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN = 0x73 */
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1R = 0x74 */
+#define DA7218_OUTFILT_1R_SRC_SHIFT 0
+#define DA7218_OUTFILT_1R_SRC_MASK (0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN = 0x75 */
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN = 0x76 */
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN = 0x77 */
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN = 0x78 */
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN = 0x79 */
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN = 0x7A */
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN = 0x7B */
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT 0
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2L = 0x7C */
+#define DA7218_OUTDAI_2L_SRC_SHIFT 0
+#define DA7218_OUTDAI_2L_SRC_MASK (0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN = 0x7D */
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN = 0x7E */
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN = 0x7F */
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN = 0x80 */
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN = 0x81 */
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN = 0x82 */
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN = 0x83 */
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2R = 0x84 */
+#define DA7218_OUTDAI_2R_SRC_SHIFT 0
+#define DA7218_OUTDAI_2R_SRC_MASK (0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN = 0x85 */
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN = 0x86 */
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN = 0x87 */
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN = 0x88 */
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN = 0x89 */
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN = 0x8A */
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN = 0x8B */
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT 0
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DAI_CTRL = 0x8C */
+#define DA7218_DAI_FORMAT_SHIFT 0
+#define DA7218_DAI_FORMAT_MASK (0x3 << 0)
+#define DA7218_DAI_FORMAT_I2S (0x0 << 0)
+#define DA7218_DAI_FORMAT_LEFT_J (0x1 << 0)
+#define DA7218_DAI_FORMAT_RIGHT_J (0x2 << 0)
+#define DA7218_DAI_FORMAT_DSP (0x3 << 0)
+#define DA7218_DAI_WORD_LENGTH_SHIFT 2
+#define DA7218_DAI_WORD_LENGTH_MASK (0x3 << 2)
+#define DA7218_DAI_WORD_LENGTH_S16_LE (0x0 << 2)
+#define DA7218_DAI_WORD_LENGTH_S20_LE (0x1 << 2)
+#define DA7218_DAI_WORD_LENGTH_S24_LE (0x2 << 2)
+#define DA7218_DAI_WORD_LENGTH_S32_LE (0x3 << 2)
+#define DA7218_DAI_CH_NUM_SHIFT 4
+#define DA7218_DAI_CH_NUM_MASK (0x7 << 4)
+#define DA7218_DAI_CH_NUM_MAX 4
+#define DA7218_DAI_EN_SHIFT 7
+#define DA7218_DAI_EN_MASK (0x1 << 7)
+
+/* DA7218_DAI_TDM_CTRL = 0x8D */
+#define DA7218_DAI_TDM_CH_EN_SHIFT 0
+#define DA7218_DAI_TDM_CH_EN_MASK (0xF << 0)
+#define DA7218_DAI_TDM_MAX_SLOTS 4
+#define DA7218_DAI_OE_SHIFT 6
+#define DA7218_DAI_OE_MASK (0x1 << 6)
+#define DA7218_DAI_TDM_MODE_EN_SHIFT 7
+#define DA7218_DAI_TDM_MODE_EN_MASK (0x1 << 7)
+
+/* DA7218_DAI_OFFSET_LOWER = 0x8E */
+#define DA7218_DAI_OFFSET_LOWER_SHIFT 0
+#define DA7218_DAI_OFFSET_LOWER_MASK (0xFF << 0)
+
+/* DA7218_DAI_OFFSET_UPPER = 0x8F */
+#define DA7218_DAI_OFFSET_UPPER_SHIFT 0
+#define DA7218_DAI_OFFSET_UPPER_MASK (0x7 << 0)
+
+/* DA7218_DAI_CLK_MODE = 0x90 */
+#define DA7218_DAI_BCLKS_PER_WCLK_SHIFT 0
+#define DA7218_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_32 (0x0 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_64 (0x1 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_128 (0x2 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_256 (0x3 << 0)
+#define DA7218_DAI_CLK_POL_SHIFT 2
+#define DA7218_DAI_CLK_POL_MASK (0x1 << 2)
+#define DA7218_DAI_CLK_POL_INV (0x1 << 2)
+#define DA7218_DAI_WCLK_POL_SHIFT 3
+#define DA7218_DAI_WCLK_POL_MASK (0x1 << 3)
+#define DA7218_DAI_WCLK_POL_INV (0x1 << 3)
+#define DA7218_DAI_WCLK_TRI_STATE_SHIFT 4
+#define DA7218_DAI_WCLK_TRI_STATE_MASK (0x1 << 4)
+#define DA7218_DAI_CLK_EN_SHIFT 7
+#define DA7218_DAI_CLK_EN_MASK (0x1 << 7)
+
+/* DA7218_PLL_CTRL = 0x91 */
+#define DA7218_PLL_INDIV_SHIFT 0
+#define DA7218_PLL_INDIV_MASK (0x7 << 0)
+#define DA7218_PLL_INDIV_2_5_MHZ (0x0 << 0)
+#define DA7218_PLL_INDIV_5_10_MHZ (0x1 << 0)
+#define DA7218_PLL_INDIV_10_20_MHZ (0x2 << 0)
+#define DA7218_PLL_INDIV_20_40_MHZ (0x3 << 0)
+#define DA7218_PLL_INDIV_40_54_MHZ (0x4 << 0)
+#define DA7218_PLL_INDIV_2_10_MHZ_VAL 2
+#define DA7218_PLL_INDIV_10_20_MHZ_VAL 4
+#define DA7218_PLL_INDIV_20_40_MHZ_VAL 8
+#define DA7218_PLL_INDIV_40_54_MHZ_VAL 16
+#define DA7218_PLL_MCLK_SQR_EN_SHIFT 4
+#define DA7218_PLL_MCLK_SQR_EN_MASK (0x1 << 4)
+#define DA7218_PLL_MODE_SHIFT 6
+#define DA7218_PLL_MODE_MASK (0x3 << 6)
+#define DA7218_PLL_MODE_BYPASS (0x0 << 6)
+#define DA7218_PLL_MODE_NORMAL (0x1 << 6)
+#define DA7218_PLL_MODE_SRM (0x2 << 6)
+#define DA7218_PLL_MODE_32KHZ (0x3 << 6)
+
+/* DA7218_PLL_FRAC_TOP = 0x92 */
+#define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT 0
+#define DA7218_PLL_FBDIV_FRAC_TOP_MASK (0x1F << 0)
+
+/* DA7218_PLL_FRAC_BOT = 0x93 */
+#define DA7218_PLL_FBDIV_FRAC_BOT_SHIFT 0
+#define DA7218_PLL_FBDIV_FRAC_BOT_MASK (0xFF << 0)
+
+/* DA7218_PLL_INTEGER = 0x94 */
+#define DA7218_PLL_FBDIV_INTEGER_SHIFT 0
+#define DA7218_PLL_FBDIV_INTEGER_MASK (0x7F << 0)
+
+/* DA7218_PLL_STATUS = 0x95 */
+#define DA7218_PLL_SRM_STATUS_SHIFT 0
+#define DA7218_PLL_SRM_STATUS_MASK (0xFF << 0)
+#define DA7218_PLL_SRM_STATUS_SRM_LOCK (0x1 << 7)
+
+/* DA7218_PLL_REFOSC_CAL = 0x98 */
+#define DA7218_PLL_REFOSC_CAL_CTRL_SHIFT 0
+#define DA7218_PLL_REFOSC_CAL_CTRL_MASK (0x1F << 0)
+#define DA7218_PLL_REFOSC_CAL_START_SHIFT 6
+#define DA7218_PLL_REFOSC_CAL_START_MASK (0x1 << 6)
+#define DA7218_PLL_REFOSC_CAL_EN_SHIFT 7
+#define DA7218_PLL_REFOSC_CAL_EN_MASK (0x1 << 7)
+
+/* DA7218_DAC_NG_CTRL = 0x9C */
+#define DA7218_DAC_NG_EN_SHIFT 7
+#define DA7218_DAC_NG_EN_MASK (0x1 << 7)
+
+/* DA7218_DAC_NG_SETUP_TIME = 0x9D */
+#define DA7218_DAC_NG_SETUP_TIME_SHIFT 0
+#define DA7218_DAC_NG_SETUP_TIME_MASK (0x3 << 0)
+#define DA7218_DAC_NG_SETUP_TIME_MAX 4
+#define DA7218_DAC_NG_RAMPUP_RATE_SHIFT 2
+#define DA7218_DAC_NG_RAMPUP_RATE_MASK (0x1 << 2)
+#define DA7218_DAC_NG_RAMPUP_RATE_MAX 2
+#define DA7218_DAC_NG_RAMPDN_RATE_SHIFT 3
+#define DA7218_DAC_NG_RAMPDN_RATE_MASK (0x1 << 3)
+#define DA7218_DAC_NG_RAMPDN_RATE_MAX 2
+
+/* DA7218_DAC_NG_OFF_THRESH = 0x9E */
+#define DA7218_DAC_NG_OFF_THRESHOLD_SHIFT 0
+#define DA7218_DAC_NG_OFF_THRESHOLD_MASK (0x7 << 0)
+#define DA7218_DAC_NG_THRESHOLD_MAX 0x7
+
+/* DA7218_DAC_NG_ON_THRESH = 0x9F */
+#define DA7218_DAC_NG_ON_THRESHOLD_SHIFT 0
+#define DA7218_DAC_NG_ON_THRESHOLD_MASK (0x7 << 0)
+
+/* DA7218_TONE_GEN_CFG1 = 0xA0 */
+#define DA7218_DTMF_REG_SHIFT 0
+#define DA7218_DTMF_REG_MASK (0xF << 0)
+#define DA7218_DTMF_REG_MAX 16
+#define DA7218_DTMF_EN_SHIFT 4
+#define DA7218_DTMF_EN_MASK (0x1 << 4)
+#define DA7218_START_STOPN_SHIFT 7
+#define DA7218_START_STOPN_MASK (0x1 << 7)
+
+/* DA7218_TONE_GEN_CFG2 = 0xA1 */
+#define DA7218_SWG_SEL_SHIFT 0
+#define DA7218_SWG_SEL_MASK (0x3 << 0)
+#define DA7218_SWG_SEL_MAX 4
+
+/* DA7218_TONE_GEN_FREQ1_L = 0xA2 */
+#define DA7218_FREQ1_L_SHIFT 0
+#define DA7218_FREQ1_L_MASK (0xFF << 0)
+#define DA7218_FREQ_MAX 0xFFFF
+
+/* DA7218_TONE_GEN_FREQ1_U = 0xA3 */
+#define DA7218_FREQ1_U_SHIFT 0
+#define DA7218_FREQ1_U_MASK (0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_L = 0xA4 */
+#define DA7218_FREQ2_L_SHIFT 0
+#define DA7218_FREQ2_L_MASK (0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_U = 0xA5 */
+#define DA7218_FREQ2_U_SHIFT 0
+#define DA7218_FREQ2_U_MASK (0xFF << 0)
+
+/* DA7218_TONE_GEN_CYCLES = 0xA6 */
+#define DA7218_BEEP_CYCLES_SHIFT 0
+#define DA7218_BEEP_CYCLES_MASK (0x7 << 0)
+
+/* DA7218_TONE_GEN_ON_PER = 0xA7 */
+#define DA7218_BEEP_ON_PER_SHIFT 0
+#define DA7218_BEEP_ON_PER_MASK (0x3F << 0)
+
+/* DA7218_TONE_GEN_OFF_PER = 0xA8 */
+#define DA7218_BEEP_OFF_PER_SHIFT 0
+#define DA7218_BEEP_OFF_PER_MASK (0x3F << 0)
+#define DA7218_BEEP_ON_OFF_MAX 0x3F
+
+/* DA7218_CP_CTRL = 0xAC */
+#define DA7218_CP_MOD_SHIFT 2
+#define DA7218_CP_MOD_MASK (0x3 << 2)
+#define DA7218_CP_MCHANGE_SHIFT 4
+#define DA7218_CP_MCHANGE_MASK (0x3 << 4)
+#define DA7218_CP_MCHANGE_REL_MASK 0x3
+#define DA7218_CP_MCHANGE_MAX 3
+#define DA7218_CP_MCHANGE_LARGEST_VOL 0x1
+#define DA7218_CP_MCHANGE_DAC_VOL 0x2
+#define DA7218_CP_MCHANGE_SIG_MAG 0x3
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_SHIFT 6
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK (0x1 << 6)
+#define DA7218_CP_EN_SHIFT 7
+#define DA7218_CP_EN_MASK (0x1 << 7)
+
+/* DA7218_CP_DELAY = 0xAD */
+#define DA7218_CP_FCONTROL_SHIFT 0
+#define DA7218_CP_FCONTROL_MASK (0x7 << 0)
+#define DA7218_CP_FCONTROL_MAX 6
+#define DA7218_CP_TAU_DELAY_SHIFT 3
+#define DA7218_CP_TAU_DELAY_MASK (0x7 << 3)
+#define DA7218_CP_TAU_DELAY_MAX 8
+
+/* DA7218_CP_VOL_THRESHOLD1 = 0xAE */
+#define DA7218_CP_THRESH_VDD2_SHIFT 0
+#define DA7218_CP_THRESH_VDD2_MASK (0x3F << 0)
+#define DA7218_CP_THRESH_VDD2_MAX 0x3F
+
+/* DA7218_MIC_1_CTRL = 0xB4 */
+#define DA7218_MIC_1_AMP_MUTE_EN_SHIFT 6
+#define DA7218_MIC_1_AMP_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_MIC_1_AMP_EN_SHIFT 7
+#define DA7218_MIC_1_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_MIC_1_GAIN = 0xB5 */
+#define DA7218_MIC_1_AMP_GAIN_SHIFT 0
+#define DA7218_MIC_1_AMP_GAIN_MASK (0x7 << 0)
+#define DA7218_MIC_AMP_GAIN_MAX 0x7
+
+/* DA7218_MIC_1_SELECT = 0xB7 */
+#define DA7218_MIC_1_AMP_IN_SEL_SHIFT 0
+#define DA7218_MIC_1_AMP_IN_SEL_MASK (0x3 << 0)
+
+/* DA7218_MIC_2_CTRL = 0xB8 */
+#define DA7218_MIC_2_AMP_MUTE_EN_SHIFT 6
+#define DA7218_MIC_2_AMP_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_MIC_2_AMP_EN_SHIFT 7
+#define DA7218_MIC_2_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_MIC_2_GAIN = 0xB9 */
+#define DA7218_MIC_2_AMP_GAIN_SHIFT 0
+#define DA7218_MIC_2_AMP_GAIN_MASK (0x7 << 0)
+
+/* DA7218_MIC_2_SELECT = 0xBB */
+#define DA7218_MIC_2_AMP_IN_SEL_SHIFT 0
+#define DA7218_MIC_2_AMP_IN_SEL_MASK (0x3 << 0)
+
+/* DA7218_IN_1_HPF_FILTER_CTRL = 0xBC */
+#define DA7218_IN_1_VOICE_HPF_CORNER_SHIFT 0
+#define DA7218_IN_1_VOICE_HPF_CORNER_MASK (0x7 << 0)
+#define DA7218_IN_VOICE_HPF_CORNER_MAX 8
+#define DA7218_IN_1_VOICE_EN_SHIFT 3
+#define DA7218_IN_1_VOICE_EN_MASK (0x1 << 3)
+#define DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT 4
+#define DA7218_IN_1_AUDIO_HPF_CORNER_MASK (0x3 << 4)
+#define DA7218_IN_1_HPF_EN_SHIFT 7
+#define DA7218_IN_1_HPF_EN_MASK (0x1 << 7)
+
+/* DA7218_IN_2_HPF_FILTER_CTRL = 0xBD */
+#define DA7218_IN_2_VOICE_HPF_CORNER_SHIFT 0
+#define DA7218_IN_2_VOICE_HPF_CORNER_MASK (0x7 << 0)
+#define DA7218_IN_2_VOICE_EN_SHIFT 3
+#define DA7218_IN_2_VOICE_EN_MASK (0x1 << 3)
+#define DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT 4
+#define DA7218_IN_2_AUDIO_HPF_CORNER_MASK (0x3 << 4)
+#define DA7218_IN_2_HPF_EN_SHIFT 7
+#define DA7218_IN_2_HPF_EN_MASK (0x1 << 7)
+
+/* DA7218_ADC_1_CTRL = 0xC0 */
+#define DA7218_ADC_1_AAF_EN_SHIFT 2
+#define DA7218_ADC_1_AAF_EN_MASK (0x1 << 2)
+
+/* DA7218_ADC_2_CTRL = 0xC1 */
+#define DA7218_ADC_2_AAF_EN_SHIFT 2
+#define DA7218_ADC_2_AAF_EN_MASK (0x1 << 2)
+
+/* DA7218_ADC_MODE = 0xC2 */
+#define DA7218_ADC_LP_MODE_SHIFT 0
+#define DA7218_ADC_LP_MODE_MASK (0x1 << 0)
+#define DA7218_ADC_LVLDET_MODE_SHIFT 1
+#define DA7218_ADC_LVLDET_MODE_MASK (0x1 << 1)
+#define DA7218_ADC_LVLDET_AUTO_EXIT_SHIFT 2
+#define DA7218_ADC_LVLDET_AUTO_EXIT_MASK (0x1 << 2)
+
+/* DA7218_MIXOUT_L_CTRL = 0xCC */
+#define DA7218_MIXOUT_L_AMP_EN_SHIFT 7
+#define DA7218_MIXOUT_L_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_MIXOUT_L_GAIN = 0xCD */
+#define DA7218_MIXOUT_L_AMP_GAIN_SHIFT 0
+#define DA7218_MIXOUT_L_AMP_GAIN_MASK (0x3 << 0)
+#define DA7218_MIXOUT_AMP_GAIN_MIN 0x1
+#define DA7218_MIXOUT_AMP_GAIN_MAX 0x3
+
+/* DA7218_MIXOUT_R_CTRL = 0xCE */
+#define DA7218_MIXOUT_R_AMP_EN_SHIFT 7
+#define DA7218_MIXOUT_R_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_MIXOUT_R_GAIN = 0xCF */
+#define DA7218_MIXOUT_R_AMP_GAIN_SHIFT 0
+#define DA7218_MIXOUT_R_AMP_GAIN_MASK (0x3 << 0)
+
+/* DA7218_HP_L_CTRL = 0xD0 */
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_SHIFT 2
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_MASK (0x1 << 2)
+#define DA7218_HP_L_AMP_OE_SHIFT 3
+#define DA7218_HP_L_AMP_OE_MASK (0x1 << 3)
+#define DA7218_HP_L_AMP_ZC_EN_SHIFT 4
+#define DA7218_HP_L_AMP_ZC_EN_MASK (0x1 << 4)
+#define DA7218_HP_L_AMP_RAMP_EN_SHIFT 5
+#define DA7218_HP_L_AMP_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_HP_L_AMP_MUTE_EN_SHIFT 6
+#define DA7218_HP_L_AMP_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_HP_L_AMP_EN_SHIFT 7
+#define DA7218_HP_L_AMP_EN_MASK (0x1 << 7)
+#define DA7218_HP_AMP_OE_MASK (0x1 << 3)
+
+/* DA7218_HP_L_GAIN = 0xD1 */
+#define DA7218_HP_L_AMP_GAIN_SHIFT 0
+#define DA7218_HP_L_AMP_GAIN_MASK (0x3F << 0)
+#define DA7218_HP_AMP_GAIN_MIN 0x15
+#define DA7218_HP_AMP_GAIN_MAX 0x3F
+
+/* DA7218_HP_R_CTRL = 0xD2 */
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_SHIFT 2
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_MASK (0x1 << 2)
+#define DA7218_HP_R_AMP_OE_SHIFT 3
+#define DA7218_HP_R_AMP_OE_MASK (0x1 << 3)
+#define DA7218_HP_R_AMP_ZC_EN_SHIFT 4
+#define DA7218_HP_R_AMP_ZC_EN_MASK (0x1 << 4)
+#define DA7218_HP_R_AMP_RAMP_EN_SHIFT 5
+#define DA7218_HP_R_AMP_RAMP_EN_MASK (0x1 << 5)
+#define DA7218_HP_R_AMP_MUTE_EN_SHIFT 6
+#define DA7218_HP_R_AMP_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_HP_R_AMP_EN_SHIFT 7
+#define DA7218_HP_R_AMP_EN_MASK (0x1 << 7)
+
+/* DA7218_HP_R_GAIN = 0xD3 */
+#define DA7218_HP_R_AMP_GAIN_SHIFT 0
+#define DA7218_HP_R_AMP_GAIN_MASK (0x3F << 0)
+
+/* DA7218_HP_SNGL_CTRL = 0xD4 */
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_SHIFT 0
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_MASK (0x1 << 0)
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_SHIFT 1
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_MASK (0x1 << 1)
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_SHIFT 2
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_MASK (0x1 << 2)
+#define DA7218_HP_AMP_LOAD_DETECT_EN_SHIFT 6
+#define DA7218_HP_AMP_LOAD_DETECT_EN_MASK (0x1 << 6)
+#define DA7218_HP_AMP_STEREO_DETECT_EN_SHIFT 7
+#define DA7218_HP_AMP_STEREO_DETECT_EN_MASK (0x1 << 7)
+
+/* DA7218_HP_DIFF_CTRL = 0xD5 */
+#define DA7218_HP_AMP_DIFF_MODE_EN_SHIFT 0
+#define DA7218_HP_AMP_DIFF_MODE_EN_MASK (0x1 << 0)
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_SHIFT 4
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK (0x1 << 4)
+
+/* DA7218_HP_DIFF_UNLOCK = 0xD7 */
+#define DA7218_HP_DIFF_UNLOCK_SHIFT 0
+#define DA7218_HP_DIFF_UNLOCK_MASK (0x1 << 0)
+#define DA7218_HP_DIFF_UNLOCK_VAL 0xC3
+
+/* DA7218_HPLDET_JACK = 0xD8 */
+#define DA7218_HPLDET_JACK_RATE_SHIFT 0
+#define DA7218_HPLDET_JACK_RATE_MASK (0x7 << 0)
+#define DA7218_HPLDET_JACK_DEBOUNCE_SHIFT 3
+#define DA7218_HPLDET_JACK_DEBOUNCE_MASK (0x3 << 3)
+#define DA7218_HPLDET_JACK_THR_SHIFT 5
+#define DA7218_HPLDET_JACK_THR_MASK (0x3 << 5)
+#define DA7218_HPLDET_JACK_EN_SHIFT 7
+#define DA7218_HPLDET_JACK_EN_MASK (0x1 << 7)
+
+/* DA7218_HPLDET_CTRL = 0xD9 */
+#define DA7218_HPLDET_COMP_INV_SHIFT 0
+#define DA7218_HPLDET_COMP_INV_MASK (0x1 << 0)
+#define DA7218_HPLDET_HYST_EN_SHIFT 1
+#define DA7218_HPLDET_HYST_EN_MASK (0x1 << 1)
+#define DA7218_HPLDET_DISCHARGE_EN_SHIFT 7
+#define DA7218_HPLDET_DISCHARGE_EN_MASK (0x1 << 7)
+
+/* DA7218_HPLDET_TEST = 0xDA */
+#define DA7218_HPLDET_COMP_STS_SHIFT 4
+#define DA7218_HPLDET_COMP_STS_MASK (0x1 << 4)
+
+/* DA7218_REFERENCES = 0xDC */
+#define DA7218_BIAS_EN_SHIFT 3
+#define DA7218_BIAS_EN_MASK (0x1 << 3)
+
+/* DA7218_IO_CTRL = 0xE0 */
+#define DA7218_IO_VOLTAGE_LEVEL_SHIFT 0
+#define DA7218_IO_VOLTAGE_LEVEL_MASK (0x1 << 0)
+#define DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V 0
+#define DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V 1
+
+/* DA7218_LDO_CTRL = 0xE1 */
+#define DA7218_LDO_LEVEL_SELECT_SHIFT 4
+#define DA7218_LDO_LEVEL_SELECT_MASK (0x3 << 4)
+#define DA7218_LDO_EN_SHIFT 7
+#define DA7218_LDO_EN_MASK (0x1 << 7)
+
+/* DA7218_SIDETONE_CTRL = 0xE4 */
+#define DA7218_SIDETONE_MUTE_EN_SHIFT 6
+#define DA7218_SIDETONE_MUTE_EN_MASK (0x1 << 6)
+#define DA7218_SIDETONE_FILTER_EN_SHIFT 7
+#define DA7218_SIDETONE_FILTER_EN_MASK (0x1 << 7)
+
+/* DA7218_SIDETONE_IN_SELECT = 0xE5 */
+#define DA7218_SIDETONE_IN_SELECT_SHIFT 0
+#define DA7218_SIDETONE_IN_SELECT_MASK (0x3 << 0)
+#define DA7218_SIDETONE_IN_SELECT_MAX 4
+
+/* DA7218_SIDETONE_GAIN = 0xE6 */
+#define DA7218_SIDETONE_GAIN_SHIFT 0
+#define DA7218_SIDETONE_GAIN_MASK (0x1F << 0)
+
+/* DA7218_DROUTING_ST_OUTFILT_1L = 0xE8 */
+#define DA7218_OUTFILT_ST_1L_SRC_SHIFT 0
+#define DA7218_OUTFILT_ST_1L_SRC_MASK (0x7 << 0)
+#define DA7218_DMIX_ST_SRC_OUTFILT1L 0
+#define DA7218_DMIX_ST_SRC_OUTFILT1R 1
+#define DA7218_DMIX_ST_SRC_SIDETONE 2
+
+/* DA7218_DROUTING_ST_OUTFILT_1R = 0xE9 */
+#define DA7218_OUTFILT_ST_1R_SRC_SHIFT 0
+#define DA7218_OUTFILT_ST_1R_SRC_MASK (0x7 << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_DATA = 0xEA */
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_SHIFT 0
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_MASK (0xFF << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_ADDR = 0xEB */
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_SHIFT 0
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_MASK (0x1F << 0)
+#define DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE 30
+
+/* DA7218_EVENT_STATUS = 0xEC */
+#define DA7218_HPLDET_JACK_STS_SHIFT 7
+#define DA7218_HPLDET_JACK_STS_MASK (0x1 << 7)
+
+/* DA7218_EVENT = 0xED */
+#define DA7218_LVL_DET_EVENT_SHIFT 0
+#define DA7218_LVL_DET_EVENT_MASK (0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_SHIFT 7
+#define DA7218_HPLDET_JACK_EVENT_MASK (0x1 << 7)
+
+/* DA7218_EVENT_MASK = 0xEE */
+#define DA7218_LVL_DET_EVENT_MSK_SHIFT 0
+#define DA7218_LVL_DET_EVENT_MSK_MASK (0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_SHIFT 7
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK (0x1 << 7)
+
+/* DA7218_DMIC_1_CTRL = 0xF0 */
+#define DA7218_DMIC_1_DATA_SEL_SHIFT 0
+#define DA7218_DMIC_1_DATA_SEL_MASK (0x1 << 0)
+#define DA7218_DMIC_1_SAMPLEPHASE_SHIFT 1
+#define DA7218_DMIC_1_SAMPLEPHASE_MASK (0x1 << 1)
+#define DA7218_DMIC_1_CLK_RATE_SHIFT 2
+#define DA7218_DMIC_1_CLK_RATE_MASK (0x1 << 2)
+#define DA7218_DMIC_1L_EN_SHIFT 6
+#define DA7218_DMIC_1L_EN_MASK (0x1 << 6)
+#define DA7218_DMIC_1R_EN_SHIFT 7
+#define DA7218_DMIC_1R_EN_MASK (0x1 << 7)
+
+/* DA7218_DMIC_2_CTRL = 0xF1 */
+#define DA7218_DMIC_2_DATA_SEL_SHIFT 0
+#define DA7218_DMIC_2_DATA_SEL_MASK (0x1 << 0)
+#define DA7218_DMIC_2_SAMPLEPHASE_SHIFT 1
+#define DA7218_DMIC_2_SAMPLEPHASE_MASK (0x1 << 1)
+#define DA7218_DMIC_2_CLK_RATE_SHIFT 2
+#define DA7218_DMIC_2_CLK_RATE_MASK (0x1 << 2)
+#define DA7218_DMIC_2L_EN_SHIFT 6
+#define DA7218_DMIC_2L_EN_MASK (0x1 << 6)
+#define DA7218_DMIC_2R_EN_SHIFT 7
+#define DA7218_DMIC_2R_EN_MASK (0x1 << 7)
+
+/* DA7218_IN_1L_GAIN = 0xF4 */
+#define DA7218_IN_1L_DIGITAL_GAIN_SHIFT 0
+#define DA7218_IN_1L_DIGITAL_GAIN_MASK (0x7F << 0)
+#define DA7218_IN_DIGITAL_GAIN_MAX 0x7F
+
+/* DA7218_IN_1R_GAIN = 0xF5 */
+#define DA7218_IN_1R_DIGITAL_GAIN_SHIFT 0
+#define DA7218_IN_1R_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7218_IN_2L_GAIN = 0xF6 */
+#define DA7218_IN_2L_DIGITAL_GAIN_SHIFT 0
+#define DA7218_IN_2L_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7218_IN_2R_GAIN = 0xF7 */
+#define DA7218_IN_2R_DIGITAL_GAIN_SHIFT 0
+#define DA7218_IN_2R_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7218_OUT_1L_GAIN = 0xF8 */
+#define DA7218_OUT_1L_DIGITAL_GAIN_SHIFT 0
+#define DA7218_OUT_1L_DIGITAL_GAIN_MASK (0xFF << 0)
+#define DA7218_OUT_DIGITAL_GAIN_MIN 0x0
+#define DA7218_OUT_DIGITAL_GAIN_MAX 0x97
+
+/* DA7218_OUT_1R_GAIN = 0xF9 */
+#define DA7218_OUT_1R_DIGITAL_GAIN_SHIFT 0
+#define DA7218_OUT_1R_DIGITAL_GAIN_MASK (0xFF << 0)
+
+/* DA7218_MICBIAS_CTRL = 0xFC */
+#define DA7218_MICBIAS_1_LEVEL_SHIFT 0
+#define DA7218_MICBIAS_1_LEVEL_MASK (0x7 << 0)
+#define DA7218_MICBIAS_1_LP_MODE_SHIFT 3
+#define DA7218_MICBIAS_1_LP_MODE_MASK (0x1 << 3)
+#define DA7218_MICBIAS_2_LEVEL_SHIFT 4
+#define DA7218_MICBIAS_2_LEVEL_MASK (0x7 << 4)
+#define DA7218_MICBIAS_2_LP_MODE_SHIFT 7
+#define DA7218_MICBIAS_2_LP_MODE_MASK (0x1 << 7)
+
+/* DA7218_MICBIAS_EN = 0xFD */
+#define DA7218_MICBIAS_1_EN_SHIFT 0
+#define DA7218_MICBIAS_1_EN_MASK (0x1 << 0)
+#define DA7218_MICBIAS_2_EN_SHIFT 4
+#define DA7218_MICBIAS_2_EN_MASK (0x1 << 4)
+
+
+/*
+ * General defines & data
+ */
+
+/* Register inversion */
+#define DA7218_NO_INVERT 0
+#define DA7218_INVERT 1
+
+/* Byte related defines */
+#define DA7218_BYTE_SHIFT 8
+#define DA7218_BYTE_MASK 0xFF
+#define DA7218_2BYTE_SHIFT 16
+#define DA7218_2BYTE_MASK 0xFFFF
+
+/* PLL Output Frequencies */
+#define DA7218_PLL_FREQ_OUT_90316 90316800
+#define DA7218_PLL_FREQ_OUT_98304 98304000
+
+/* ALC Calibration */
+#define DA7218_ALC_CALIB_DELAY_MIN 2500
+#define DA7218_ALC_CALIB_DELAY_MAX 5000
+#define DA7218_ALC_CALIB_MAX_TRIES 5
+
+/* Ref Oscillator */
+#define DA7218_REF_OSC_CHECK_DELAY_MIN 5000
+#define DA7218_REF_OSC_CHECK_DELAY_MAX 10000
+#define DA7218_REF_OSC_CHECK_TRIES 4
+
+/* SRM */
+#define DA7218_SRM_CHECK_DELAY 50
+#define DA7218_SRM_CHECK_TRIES 8
+
+/* Mic Level Detect */
+#define DA7218_MIC_LVL_DET_DELAY 50
+
+enum da7218_biq_cfg {
+ DA7218_BIQ_CFG_DATA = 0,
+ DA7218_BIQ_CFG_ADDR,
+ DA7218_BIQ_CFG_SIZE,
+};
+
+enum da7218_clk_src {
+ DA7218_CLKSRC_MCLK = 0,
+ DA7218_CLKSRC_MCLK_SQR,
+};
+
+enum da7218_sys_clk {
+ DA7218_SYSCLK_MCLK = 0,
+ DA7218_SYSCLK_PLL,
+ DA7218_SYSCLK_PLL_SRM,
+ DA7218_SYSCLK_PLL_32KHZ
+};
+
+enum da7218_dev_id {
+ DA7217_DEV_ID = 0,
+ DA7218_DEV_ID,
+};
+
+/* Regulators */
+enum da7218_supplies {
+ DA7218_SUPPLY_VDD = 0,
+ DA7218_SUPPLY_VDDMIC,
+ DA7218_SUPPLY_VDDIO,
+ DA7218_NUM_SUPPLIES,
+};
+
+/* Private data */
+struct da7218_priv {
+ struct da7218_pdata *pdata;
+
+ struct regulator_bulk_data supplies[DA7218_NUM_SUPPLIES];
+ struct regmap *regmap;
+ int dev_id;
+
+ struct snd_soc_jack *jack;
+ int irq;
+
+ struct clk *mclk;
+ unsigned int mclk_rate;
+
+ bool hp_single_supply;
+ bool master;
+ u8 alc_en;
+ u8 in_filt_en;
+ u8 mic_lvl_det_en;
+
+ u8 biq_5stage_coeff[DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE];
+ u8 stbiq_3stage_coeff[DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE];
+};
+
+/* HP detect control */
+int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif /* _DA7218_H */
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f238c1e8a69c..81c0708b85c1 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -968,10 +968,11 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = {
{"Mixin PGA", NULL, "Mic PGA"},
{"ADC", NULL, "Mixin PGA"},
- {"Sidetone Filter", NULL, "ADC"},
{"Mixer In", NULL, "Mixer In Supply"},
{"Mixer In", "Mic Switch", "ADC"},
+ {"Sidetone Filter", NULL, "Mixer In"},
+
{"Tone Generator", NULL, "TONE"},
DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"),
@@ -1073,11 +1074,8 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
u32 freq_ref;
u64 frac_div;
- /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
- if (da7219->mclk_rate == 32768) {
- indiv_bits = DA7219_PLL_INDIV_2_5_MHZ;
- indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL;
- } else if (da7219->mclk_rate < 2000000) {
+ /* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+ if (da7219->mclk_rate < 2000000) {
dev_err(codec->dev, "PLL input clock %d below valid range\n",
da7219->mclk_rate);
return -EINVAL;
@@ -1118,9 +1116,6 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
case DA7219_SYSCLK_PLL_SRM:
pll_ctrl |= DA7219_PLL_MODE_SRM;
break;
- case DA7219_SYSCLK_PLL_32KHZ:
- pll_ctrl |= DA7219_PLL_MODE_32KHZ;
- break;
default:
dev_err(codec->dev, "Invalid PLL config\n");
return -EINVAL;
@@ -1161,18 +1156,44 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- break;
- case SND_SOC_DAIFMT_NB_IF:
- dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+ DA7219_DAI_CLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
- case SND_SOC_DAIFMT_IB_IF:
- dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
- DA7219_DAI_CLK_POL_INV;
+ case SND_SOC_DAIFMT_DSP_B:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+ DA7219_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
@@ -1306,7 +1327,7 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
}
channels = params_channels(params);
- if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) {
+ if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
dev_err(codec->dev,
"Invalid number of channels, only 1 to %d supported\n",
DA7219_DAI_CH_NUM_MAX);
@@ -1405,28 +1426,12 @@ static const struct of_device_id da7219_of_match[] = {
};
MODULE_DEVICE_TABLE(of, da7219_of_match);
-static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec,
- u32 val)
-{
- switch (val) {
- case 1050:
- return DA7219_LDO_LVL_SEL_1_05V;
- case 1100:
- return DA7219_LDO_LVL_SEL_1_10V;
- case 1200:
- return DA7219_LDO_LVL_SEL_1_20V;
- case 1400:
- return DA7219_LDO_LVL_SEL_1_40V;
- default:
- dev_warn(codec->dev, "Invalid LDO level");
- return DA7219_LDO_LVL_SEL_1_05V;
- }
-}
-
static enum da7219_micbias_voltage
da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
{
switch (val) {
+ case 1600:
+ return DA7219_MICBIAS_1_6V;
case 1800:
return DA7219_MICBIAS_1_8V;
case 2000:
@@ -1469,9 +1474,6 @@ static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec)
if (!pdata)
return NULL;
- if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0)
- pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32);
-
if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0)
pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32);
else
@@ -1516,24 +1518,13 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, DA7219_REFERENCES,
DA7219_BIAS_EN_MASK,
DA7219_BIAS_EN_MASK);
-
- /* Enable Internal Digital LDO */
- snd_soc_update_bits(codec, DA7219_LDO_CTRL,
- DA7219_LDO_EN_MASK,
- DA7219_LDO_EN_MASK);
}
break;
case SND_SOC_BIAS_OFF:
- /* Only disable if jack detection not active */
- if (!da7219->aad->jack) {
- /* Bypass Internal Digital LDO */
- snd_soc_update_bits(codec, DA7219_LDO_CTRL,
- DA7219_LDO_EN_MASK, 0);
-
- /* Master bias */
+ /* Only disable master bias if jack detection not active */
+ if (!da7219->aad->jack)
snd_soc_update_bits(codec, DA7219_REFERENCES,
DA7219_BIAS_EN_MASK, 0);
- }
/* MCLK */
if (da7219->mclk)
@@ -1600,21 +1591,9 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
if (pdata) {
u8 micbias_lvl = 0;
- /* Internal LDO */
- switch (pdata->ldo_lvl_sel) {
- case DA7219_LDO_LVL_SEL_1_05V:
- case DA7219_LDO_LVL_SEL_1_10V:
- case DA7219_LDO_LVL_SEL_1_20V:
- case DA7219_LDO_LVL_SEL_1_40V:
- snd_soc_update_bits(codec, DA7219_LDO_CTRL,
- DA7219_LDO_LEVEL_SELECT_MASK,
- (pdata->ldo_lvl_sel <<
- DA7219_LDO_LEVEL_SELECT_SHIFT));
- break;
- }
-
/* Mic Bias voltages */
switch (pdata->micbias_lvl) {
+ case DA7219_MICBIAS_1_6V:
case DA7219_MICBIAS_1_8V:
case DA7219_MICBIAS_2_0V:
case DA7219_MICBIAS_2_2V:
@@ -1639,9 +1618,14 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
}
}
+static struct reg_sequence da7219_rev_aa_patch[] = {
+ { DA7219_REFERENCES, 0x08 },
+};
+
static int da7219_probe(struct snd_soc_codec *codec)
{
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+ unsigned int rev;
int ret;
mutex_init(&da7219->lock);
@@ -1651,6 +1635,26 @@ static int da7219_probe(struct snd_soc_codec *codec)
if (ret)
return ret;
+ ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev);
+ if (ret) {
+ dev_err(codec->dev, "Failed to read chip revision: %d\n", ret);
+ goto err_disable_reg;
+ }
+
+ switch (rev & DA7219_CHIP_MINOR_MASK) {
+ case 0:
+ ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch,
+ ARRAY_SIZE(da7219_rev_aa_patch));
+ if (ret) {
+ dev_err(codec->dev, "Failed to register AA patch: %d\n",
+ ret);
+ goto err_disable_reg;
+ }
+ break;
+ default:
+ break;
+ }
+
/* Handle DT/Platform data */
if (codec->dev->of_node)
da7219->pdata = da7219_of_to_pdata(codec);
@@ -1662,10 +1666,12 @@ static int da7219_probe(struct snd_soc_codec *codec)
/* Check if MCLK provided */
da7219->mclk = devm_clk_get(codec->dev, "mclk");
if (IS_ERR(da7219->mclk)) {
- if (PTR_ERR(da7219->mclk) != -ENOENT)
- return PTR_ERR(da7219->mclk);
- else
+ if (PTR_ERR(da7219->mclk) != -ENOENT) {
+ ret = PTR_ERR(da7219->mclk);
+ goto err_disable_reg;
+ } else {
da7219->mclk = NULL;
+ }
}
/* Default PC counter to free-running */
@@ -1693,7 +1699,16 @@ static int da7219_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
/* Initialise AAD block */
- return da7219_aad_init(codec);
+ ret = da7219_aad_init(codec);
+ if (ret)
+ goto err_disable_reg;
+
+ return 0;
+
+err_disable_reg:
+ regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+
+ return ret;
}
static int da7219_remove(struct snd_soc_codec *codec)
@@ -1776,7 +1791,7 @@ static struct reg_default da7219_reg_defaults[] = {
{ DA7219_DIG_ROUTING_DAC, 0x32 },
{ DA7219_DAI_OFFSET_LOWER, 0x00 },
{ DA7219_DAI_OFFSET_UPPER, 0x00 },
- { DA7219_REFERENCES, 0x00 },
+ { DA7219_REFERENCES, 0x08 },
{ DA7219_MIXIN_L_SELECT, 0x00 },
{ DA7219_MIXIN_L_GAIN, 0x03 },
{ DA7219_ADC_L_GAIN, 0x6F },
@@ -1810,8 +1825,6 @@ static struct reg_default da7219_reg_defaults[] = {
{ DA7219_MIXOUT_R_CTRL, 0x10 },
{ DA7219_CHIP_ID1, 0x23 },
{ DA7219_CHIP_ID2, 0x93 },
- { DA7219_CHIP_REVISION, 0x00 },
- { DA7219_LDO_CTRL, 0x00 },
{ DA7219_IO_CTRL, 0x00 },
{ DA7219_GAIN_RAMP_CTRL, 0x00 },
{ DA7219_PC_COUNT, 0x02 },
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index b514268c6c56..5a787e738084 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -85,7 +85,6 @@
#define DA7219_CHIP_ID1 0x81
#define DA7219_CHIP_ID2 0x82
#define DA7219_CHIP_REVISION 0x83
-#define DA7219_LDO_CTRL 0x90
#define DA7219_IO_CTRL 0x91
#define DA7219_GAIN_RAMP_CTRL 0x92
#define DA7219_PC_COUNT 0x94
@@ -207,7 +206,6 @@
#define DA7219_PLL_MODE_BYPASS (0x0 << 6)
#define DA7219_PLL_MODE_NORMAL (0x1 << 6)
#define DA7219_PLL_MODE_SRM (0x2 << 6)
-#define DA7219_PLL_MODE_32KHZ (0x3 << 6)
/* DA7219_PLL_FRAC_TOP = 0x22 */
#define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT 0
@@ -569,12 +567,6 @@
#define DA7219_CHIP_MAJOR_SHIFT 4
#define DA7219_CHIP_MAJOR_MASK (0xF << 4)
-/* DA7219_LDO_CTRL = 0x90 */
-#define DA7219_LDO_LEVEL_SELECT_SHIFT 4
-#define DA7219_LDO_LEVEL_SELECT_MASK (0x3 << 4)
-#define DA7219_LDO_EN_SHIFT 7
-#define DA7219_LDO_EN_MASK (0x1 << 7)
-
/* DA7219_IO_CTRL = 0x91 */
#define DA7219_IO_VOLTAGE_LEVEL_SHIFT 0
#define DA7219_IO_VOLTAGE_LEVEL_MASK (0x1 << 0)
@@ -787,7 +779,6 @@ enum da7219_sys_clk {
DA7219_SYSCLK_MCLK = 0,
DA7219_SYSCLK_PLL,
DA7219_SYSCLK_PLL_SRM,
- DA7219_SYSCLK_PLL_32KHZ
};
/* Regulators */
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
new file mode 100644
index 000000000000..5a1ec0f7a1a6
--- /dev/null
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -0,0 +1,697 @@
+/*
+ * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms
+ *
+ * Copyright (C) 2014-2015 Intel Corp
+ * Author: Samreen Nilofer <samreen.nilofer@intel.com>
+ * Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/hdmi.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include "../../hda/local.h"
+
+#define AMP_OUT_MUTE 0xb080
+#define AMP_OUT_UNMUTE 0xb000
+#define PIN_OUT (AC_PINCTL_OUT_EN)
+
+#define HDA_MAX_CONNECTIONS 32
+
+struct hdac_hdmi_cvt_params {
+ unsigned int channels_min;
+ unsigned int channels_max;
+ u32 rates;
+ u64 formats;
+ unsigned int maxbps;
+};
+
+struct hdac_hdmi_cvt {
+ struct list_head head;
+ hda_nid_t nid;
+ struct hdac_hdmi_cvt_params params;
+};
+
+struct hdac_hdmi_pin {
+ struct list_head head;
+ hda_nid_t nid;
+ int num_mux_nids;
+ hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+};
+
+struct hdac_hdmi_dai_pin_map {
+ int dai_id;
+ struct hdac_hdmi_pin *pin;
+ struct hdac_hdmi_cvt *cvt;
+};
+
+struct hdac_hdmi_priv {
+ struct hdac_hdmi_dai_pin_map dai_map[3];
+ struct list_head pin_list;
+ struct list_head cvt_list;
+ int num_pin;
+ int num_cvt;
+};
+
+static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
+{
+ struct hdac_device *hdac = dev_to_hdac_dev(dev);
+
+ return to_ehdac_device(hdac);
+}
+
+static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
+ hda_nid_t cvt_nid, hda_nid_t pin_nid,
+ u32 stream_tag, int format)
+{
+ unsigned int val;
+
+ dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
+ cvt_nid, pin_nid, stream_tag, format);
+
+ val = (stream_tag << 4);
+
+ snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, val);
+ snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+ AC_VERB_SET_STREAM_FORMAT, format);
+
+ return 0;
+}
+
+static void
+hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
+ int packet_index, int byte_index)
+{
+ int val;
+
+ val = (packet_index << 5) | (byte_index & 0x1f);
+
+ snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
+ hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+ uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
+ struct hdmi_audio_infoframe frame;
+ u8 *dip = (u8 *)&frame;
+ int ret;
+ int i;
+
+ hdmi_audio_infoframe_init(&frame);
+
+ /* Default stereo for now */
+ frame.channels = 2;
+
+ /* setup channel count */
+ snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+ AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
+
+ ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
+ if (ret < 0)
+ return ret;
+
+ /* stop infoframe transmission */
+ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+ snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
+
+
+ /* Fill infoframe. Index auto-incremented */
+ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+ for (i = 0; i < sizeof(frame); i++)
+ snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
+
+ /* Start infoframe */
+ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+ snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
+
+ return 0;
+}
+
+static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
+ struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
+{
+ /* Power up pin widget */
+ if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
+ pwr_state))
+ snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
+ AC_VERB_SET_POWER_STATE, pwr_state);
+
+ /* Power up converter */
+ if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
+ pwr_state))
+ snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+ AC_VERB_SET_POWER_STATE, pwr_state);
+}
+
+static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_ext_dma_params *dd;
+ int ret;
+
+ if (dai->id > 0) {
+ dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+ return -ENODEV;
+ }
+
+ dai_map = &hdmi->dai_map[dai->id];
+
+ dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+ dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
+ dd->stream_tag, dd->format);
+
+ ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
+ dai_map->pin->nid);
+ if (ret < 0)
+ return ret;
+
+ return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
+ dai_map->pin->nid, dd->stream_tag, dd->format);
+}
+
+static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
+{
+ struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+ struct hdac_ext_dma_params *dd;
+
+ if (dai->id > 0) {
+ dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+ return -ENODEV;
+ }
+
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+ dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
+ params_channels(hparams), params_format(hparams),
+ 24, 0);
+
+ snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
+
+ return 0;
+}
+
+static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+ struct hdac_ext_dma_params *dd;
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map;
+
+ dai_map = &hdmi->dai_map[dai->id];
+
+ snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, 0);
+ snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+ AC_VERB_SET_STREAM_FORMAT, 0);
+
+ dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+
+ kfree(dd);
+
+ return 0;
+}
+
+static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map;
+ int val;
+
+ if (dai->id > 0) {
+ dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+ return -ENODEV;
+ }
+
+ dai_map = &hdmi->dai_map[dai->id];
+
+ val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
+
+ if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
+ dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
+ return -ENODEV;
+ }
+
+ hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+
+ snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+
+ return 0;
+}
+
+static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map;
+
+ dai_map = &hdmi->dai_map[dai->id];
+
+ hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
+
+ snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+}
+
+static int
+hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
+{
+ int err;
+
+ /* Only stereo supported as of now */
+ cvt->params.channels_min = cvt->params.channels_max = 2;
+
+ err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
+ &cvt->params.rates,
+ &cvt->params.formats,
+ &cvt->params.maxbps);
+ if (err < 0)
+ dev_err(&hdac->dev,
+ "Failed to query pcm params for nid %d: %d\n",
+ cvt->nid, err);
+
+ return err;
+}
+
+static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
+ enum snd_soc_dapm_type id,
+ const char *wname, const char *stream)
+{
+ w->id = id;
+ w->name = wname;
+ w->sname = stream;
+ w->reg = SND_SOC_NOPM;
+ w->shift = 0;
+ w->kcontrol_news = NULL;
+ w->num_kcontrols = 0;
+ w->priv = NULL;
+}
+
+static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
+ const char *sink, const char *control, const char *src)
+{
+ route->sink = sink;
+ route->source = src;
+ route->control = control;
+ route->connected = NULL;
+}
+
+static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
+ struct hdac_hdmi_dai_pin_map *dai_map)
+{
+ struct snd_soc_dapm_route route[1];
+ struct snd_soc_dapm_widget widgets[2] = { {0} };
+
+ memset(&route, 0, sizeof(route));
+
+ hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
+ "hif1 Output", NULL);
+ hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
+ "Coverter 1", "hif1");
+
+ hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
+
+ snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
+ snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
+}
+
+static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
+{
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
+ struct hdac_hdmi_cvt *cvt;
+ struct hdac_hdmi_pin *pin;
+
+ if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
+ return -EINVAL;
+
+ /*
+ * Currently on board only 1 pin and 1 converter is enabled for
+ * simplification, more will be added eventually
+ * So using fixed map for dai_id:pin:cvt
+ */
+ cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
+ pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
+
+ dai_map->dai_id = 0;
+ dai_map->pin = pin;
+
+ dai_map->cvt = cvt;
+
+ /* Enable out path for this pin widget */
+ snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+ /* Enable transmission */
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_DIGI_CONVERT_1, 1);
+
+ /* Category Code (CC) to zero */
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_DIGI_CONVERT_2, 0);
+
+ snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
+ AC_VERB_SET_CONNECT_SEL, 0);
+
+ return 0;
+}
+
+static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
+{
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_cvt *cvt;
+
+ cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
+ if (!cvt)
+ return -ENOMEM;
+
+ cvt->nid = nid;
+
+ list_add_tail(&cvt->head, &hdmi->cvt_list);
+ hdmi->num_cvt++;
+
+ return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
+}
+
+static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
+{
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pin *pin;
+
+ pin = kzalloc(sizeof(*pin), GFP_KERNEL);
+ if (!pin)
+ return -ENOMEM;
+
+ pin->nid = nid;
+
+ list_add_tail(&pin->head, &hdmi->pin_list);
+ hdmi->num_pin++;
+
+ return 0;
+}
+
+/*
+ * Parse all nodes and store the cvt/pin nids in array
+ * Add one time initialization for pin and cvt widgets
+ */
+static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
+{
+ hda_nid_t nid;
+ int i, num_nodes;
+ struct hdac_device *hdac = &edev->hdac;
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ int ret;
+
+ num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
+ if (!nid || num_nodes <= 0) {
+ dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
+ return -EINVAL;
+ }
+
+ hdac->num_nodes = num_nodes;
+ hdac->start_nid = nid;
+
+ for (i = 0; i < hdac->num_nodes; i++, nid++) {
+ unsigned int caps;
+ unsigned int type;
+
+ caps = get_wcaps(hdac, nid);
+ type = get_wcaps_type(caps);
+
+ if (!(caps & AC_WCAP_DIGITAL))
+ continue;
+
+ switch (type) {
+
+ case AC_WID_AUD_OUT:
+ ret = hdac_hdmi_add_cvt(edev, nid);
+ if (ret < 0)
+ return ret;
+ break;
+
+ case AC_WID_PIN:
+ ret = hdac_hdmi_add_pin(edev, nid);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+ }
+
+ hdac->end_nid = nid;
+
+ if (!hdmi->num_pin || !hdmi->num_cvt)
+ return -EIO;
+
+ return hdac_hdmi_init_dai_map(edev);
+}
+
+static int hdmi_codec_probe(struct snd_soc_codec *codec)
+{
+ struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(&codec->component);
+
+ edev->scodec = codec;
+
+ create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
+
+ /* Imp: Store the card pointer in hda_codec */
+ edev->card = dapm->card->snd_card;
+
+ /*
+ * hdac_device core already sets the state to active and calls
+ * get_noresume. So enable runtime and set the device to suspend.
+ */
+ pm_runtime_enable(&edev->hdac.dev);
+ pm_runtime_put(&edev->hdac.dev);
+ pm_runtime_suspend(&edev->hdac.dev);
+
+ return 0;
+}
+
+static int hdmi_codec_remove(struct snd_soc_codec *codec)
+{
+ struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+
+ pm_runtime_disable(&edev->hdac.dev);
+ return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_hda_codec = {
+ .probe = hdmi_codec_probe,
+ .remove = hdmi_codec_remove,
+ .idle_bias_off = true,
+};
+
+static struct snd_soc_dai_ops hdmi_dai_ops = {
+ .startup = hdac_hdmi_pcm_open,
+ .shutdown = hdac_hdmi_pcm_close,
+ .hw_params = hdac_hdmi_set_hw_params,
+ .prepare = hdac_hdmi_playback_prepare,
+ .hw_free = hdac_hdmi_playback_cleanup,
+};
+
+static struct snd_soc_dai_driver hdmi_dais[] = {
+ { .name = "intel-hdmi-hif1",
+ .playback = {
+ .stream_name = "hif1",
+ .channels_min = 2,
+ .channels_max = 2,
+ .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_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+
+ },
+ .ops = &hdmi_dai_ops,
+ },
+};
+
+static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
+{
+ struct hdac_device *codec = &edev->hdac;
+ struct hdac_hdmi_priv *hdmi_priv;
+ int ret = 0;
+
+ hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
+ if (hdmi_priv == NULL)
+ return -ENOMEM;
+
+ edev->private_data = hdmi_priv;
+
+ dev_set_drvdata(&codec->dev, edev);
+
+ INIT_LIST_HEAD(&hdmi_priv->pin_list);
+ INIT_LIST_HEAD(&hdmi_priv->cvt_list);
+
+ ret = hdac_hdmi_parse_and_map_nid(edev);
+ if (ret < 0)
+ return ret;
+
+ /* ASoC specific initialization */
+ return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
+ hdmi_dais, ARRAY_SIZE(hdmi_dais));
+}
+
+static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
+{
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pin *pin, *pin_next;
+ struct hdac_hdmi_cvt *cvt, *cvt_next;
+
+ snd_soc_unregister_codec(&edev->hdac.dev);
+
+ list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
+ list_del(&cvt->head);
+ kfree(cvt);
+ }
+
+ list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
+ list_del(&pin->head);
+ kfree(pin);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hdac_hdmi_runtime_suspend(struct device *dev)
+{
+ struct hdac_ext_device *edev = to_hda_ext_device(dev);
+ struct hdac_device *hdac = &edev->hdac;
+ struct hdac_bus *bus = hdac->bus;
+ int err;
+
+ dev_dbg(dev, "Enter: %s\n", __func__);
+
+ /* controller may not have been initialized for the first time */
+ if (!bus)
+ return 0;
+
+ /* Power down afg */
+ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
+ snd_hdac_codec_write(hdac, hdac->afg, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+ err = snd_hdac_display_power(bus, false);
+ if (err < 0) {
+ dev_err(bus->dev, "Cannot turn on display power on i915\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int hdac_hdmi_runtime_resume(struct device *dev)
+{
+ struct hdac_ext_device *edev = to_hda_ext_device(dev);
+ struct hdac_device *hdac = &edev->hdac;
+ struct hdac_bus *bus = hdac->bus;
+ int err;
+
+ dev_dbg(dev, "Enter: %s\n", __func__);
+
+ /* controller may not have been initialized for the first time */
+ if (!bus)
+ return 0;
+
+ err = snd_hdac_display_power(bus, true);
+ if (err < 0) {
+ dev_err(bus->dev, "Cannot turn on display power on i915\n");
+ return err;
+ }
+
+ /* Power up afg */
+ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
+ snd_hdac_codec_write(hdac, hdac->afg, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+ return 0;
+}
+#else
+#define hdac_hdmi_runtime_suspend NULL
+#define hdac_hdmi_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops hdac_hdmi_pm = {
+ SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
+};
+
+static const struct hda_device_id hdmi_list[] = {
+ HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
+ {}
+};
+
+MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
+
+static struct hdac_ext_driver hdmi_driver = {
+ . hdac = {
+ .driver = {
+ .name = "HDMI HDA Codec",
+ .pm = &hdac_hdmi_pm,
+ },
+ .id_table = hdmi_list,
+ },
+ .probe = hdac_hdmi_dev_probe,
+ .remove = hdac_hdmi_dev_remove,
+};
+
+static int __init hdmi_init(void)
+{
+ return snd_hda_ext_driver_register(&hdmi_driver);
+}
+
+static void __exit hdmi_exit(void)
+{
+ snd_hda_ext_driver_unregister(&hdmi_driver);
+}
+
+module_init(hdmi_init);
+module_exit(hdmi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HDMI HD codec");
+MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
+MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
new file mode 100644
index 000000000000..9b6e8840a1b5
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -0,0 +1,490 @@
+/*
+ * Driver of Inno codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Rockchip Inc.
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/io.h>
+
+#include "inno_rk3036.h"
+
+struct rk3036_codec_priv {
+ void __iomem *base;
+ struct clk *pclk;
+ struct regmap *regmap;
+ struct device *dev;
+};
+
+static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
+
+static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int val, ret, regval;
+
+ ret = snd_soc_component_read(component, INNO_R09, &regval);
+ if (ret)
+ return ret;
+ val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) &
+ INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+ ucontrol->value.integer.value[0] = val;
+
+ val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) &
+ INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+ ucontrol->value.integer.value[1] = val;
+
+ return 0;
+}
+
+static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ int val, ret, regmsk;
+
+ val = (ucontrol->value.integer.value[0] ?
+ INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+ INNO_R09_HPL_ANITPOP_SHIFT;
+ val |= (ucontrol->value.integer.value[1] ?
+ INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+ INNO_R09_HPR_ANITPOP_SHIFT;
+
+ regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT |
+ INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT;
+
+ ret = snd_soc_component_update_bits(component, INNO_R09,
+ regmsk, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+#define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \
+ .put = rk3036_codec_antipop_put, }
+
+static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
+ SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+ INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+ INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+ SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+ INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
+ SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+ INNO_R09_HPR_MUTE_SHIFT, 1, 0),
+ SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
+ INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
+ INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
+ SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
+ INNO_R05_HPL_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
+ SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
+ INNO_R05_HPR_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
+ INNO_R06_DAC_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04,
+ INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04,
+ INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06,
+ INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06,
+ INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04,
+ INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04,
+ INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04,
+ INNO_R04_DACL_SW_SHIFT, 0),
+ SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04,
+ INNO_R04_DACR_SW_SHIFT, 0),
+
+ SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+ rk3036_codec_hpl_mixer_controls,
+ ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+ rk3036_codec_hpr_mixer_controls,
+ ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)),
+
+ SND_SOC_DAPM_PGA("HP Left Out", INNO_R05,
+ INNO_R05_HPL_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HP Right Out", INNO_R05,
+ INNO_R05_HPR_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("HP Left Switch", SND_SOC_NOPM, 0, 0,
+ rk3036_codec_hpl_switch_controls,
+ ARRAY_SIZE(rk3036_codec_hpl_switch_controls)),
+ SND_SOC_DAPM_MIXER("HP Right Switch", SND_SOC_NOPM, 0, 0,
+ rk3036_codec_hpr_switch_controls,
+ ARRAY_SIZE(rk3036_codec_hpr_switch_controls)),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = {
+ {"DACL VREF", NULL, "DAC PWR"},
+ {"DACR VREF", NULL, "DAC PWR"},
+ {"DACL HiLo VREF", NULL, "DAC PWR"},
+ {"DACR HiLo VREF", NULL, "DAC PWR"},
+ {"DACL CLK", NULL, "DAC PWR"},
+ {"DACR CLK", NULL, "DAC PWR"},
+
+ {"DACL", NULL, "DACL VREF"},
+ {"DACL", NULL, "DACL HiLo VREF"},
+ {"DACL", NULL, "DACL CLK"},
+ {"DACR", NULL, "DACR VREF"},
+ {"DACR", NULL, "DACR HiLo VREF"},
+ {"DACR", NULL, "DACR CLK"},
+
+ {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"},
+ {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"},
+ {"HP Left Out", NULL, "Left Headphone Mixer"},
+ {"HP Right Out", NULL, "Right Headphone Mixer"},
+
+ {"HP Left Switch", "HP Left Out Switch", "HP Left Out"},
+ {"HP Right Switch", "HP Right Out Switch", "HP Right Out"},
+
+ {"HPL", NULL, "HP Left Switch"},
+ {"HPR", NULL, "HP Right Switch"},
+};
+
+static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int reg01_val = 0, reg02_val = 0, reg03_val = 0;
+
+ dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg01_val |= INNO_R01_PINDIR_IN_SLAVE |
+ INNO_R01_I2SMODE_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ reg01_val |= INNO_R01_PINDIR_OUT_MASTER |
+ INNO_R01_I2SMODE_MASTER;
+ break;
+ default:
+ dev_err(codec->dev, "invalid fmt\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ reg02_val |= INNO_R02_DACM_PCM;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ reg02_val |= INNO_R02_DACM_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ reg02_val |= INNO_R02_DACM_RJM;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg02_val |= INNO_R02_DACM_LJM;
+ break;
+ default:
+ dev_err(codec->dev, "set dai format failed\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ reg02_val |= INNO_R02_LRCP_NORMAL;
+ reg03_val |= INNO_R03_BCP_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg02_val |= INNO_R02_LRCP_REVERSAL;
+ reg03_val |= INNO_R03_BCP_REVERSAL;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg02_val |= INNO_R02_LRCP_REVERSAL;
+ reg03_val |= INNO_R03_BCP_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg02_val |= INNO_R02_LRCP_NORMAL;
+ reg03_val |= INNO_R03_BCP_REVERSAL;
+ break;
+ default:
+ dev_err(codec->dev, "set dai format failed\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK |
+ INNO_R01_PINDIR_MSK, reg01_val);
+ snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+ INNO_R02_DACM_MSK, reg02_val);
+ snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
+
+ return 0;
+}
+
+static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int reg02_val = 0, reg03_val = 0;
+
+ switch (params_format(hw_params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ reg02_val |= INNO_R02_VWL_16BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ reg02_val |= INNO_R02_VWL_20BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ reg02_val |= INNO_R02_VWL_24BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ reg02_val |= INNO_R02_VWL_32BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg02_val |= INNO_R02_LRCP_NORMAL;
+ reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK;
+
+ snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+ INNO_R02_VWL_MSK, reg02_val);
+ snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK |
+ INNO_R03_FWL_MSK, reg03_val);
+ return 0;
+}
+
+#define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000 | \
+ SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000 | \
+ SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000)
+
+#define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops rk3036_codec_dai_ops = {
+ .set_fmt = rk3036_codec_dai_set_fmt,
+ .hw_params = rk3036_codec_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
+ {
+ .name = "rk3036-codec-dai",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RK3036_CODEC_RATES,
+ .formats = RK3036_CODEC_FMTS,
+ },
+ .ops = &rk3036_codec_dai_ops,
+ .symmetric_rates = 1,
+ },
+};
+
+static void rk3036_codec_reset(struct snd_soc_codec *codec)
+{
+ snd_soc_write(codec, INNO_R00,
+ INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET);
+ snd_soc_write(codec, INNO_R00,
+ INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK);
+}
+
+static int rk3036_codec_probe(struct snd_soc_codec *codec)
+{
+ rk3036_codec_reset(codec);
+ return 0;
+}
+
+static int rk3036_codec_remove(struct snd_soc_codec *codec)
+{
+ rk3036_codec_reset(codec);
+ return 0;
+}
+
+static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ /* set a big current for capacitor charging. */
+ snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+ /* start precharge */
+ snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE);
+
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ /* set a big current for capacitor discharging. */
+ snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+ /* start discharge. */
+ snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE);
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver rk3036_codec_driver = {
+ .probe = rk3036_codec_probe,
+ .remove = rk3036_codec_remove,
+ .set_bias_level = rk3036_codec_set_bias_level,
+ .controls = rk3036_codec_dapm_controls,
+ .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls),
+ .dapm_routes = rk3036_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes),
+ .dapm_widgets = rk3036_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets),
+};
+
+static const struct regmap_config rk3036_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+};
+
+#define GRF_SOC_CON0 0x00140
+#define GRF_ACODEC_SEL (BIT(10) | BIT(16 + 10))
+
+static int rk3036_codec_platform_probe(struct platform_device *pdev)
+{
+ struct rk3036_codec_priv *priv;
+ struct device_node *of_node = pdev->dev.of_node;
+ struct resource *res;
+ void __iomem *base;
+ struct regmap *grf;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ 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);
+
+ priv->base = base;
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base,
+ &rk3036_codec_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(&pdev->dev, "init regmap failed\n");
+ return PTR_ERR(priv->regmap);
+ }
+
+ grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf");
+ if (IS_ERR(grf)) {
+ dev_err(&pdev->dev, "needs 'rockchip,grf' property\n");
+ return PTR_ERR(grf);
+ }
+ ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret);
+ return ret;
+ }
+
+ priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk");
+ if (IS_ERR(priv->pclk))
+ return PTR_ERR(priv->pclk);
+
+ ret = clk_prepare_enable(priv->pclk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable clk\n");
+ return ret;
+ }
+
+ priv->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, priv);
+
+ ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver,
+ rk3036_codec_dai_driver,
+ ARRAY_SIZE(rk3036_codec_dai_driver));
+ if (ret) {
+ clk_disable_unprepare(priv->pclk);
+ dev_set_drvdata(&pdev->dev, NULL);
+ }
+
+ return ret;
+}
+
+static int rk3036_codec_platform_remove(struct platform_device *pdev)
+{
+ struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_codec(&pdev->dev);
+ clk_disable_unprepare(priv->pclk);
+
+ return 0;
+}
+
+static const struct of_device_id rk3036_codec_of_match[] = {
+ { .compatible = "rockchip,rk3036-codec", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rk3036_codec_of_match);
+
+static struct platform_driver rk3036_codec_platform_driver = {
+ .driver = {
+ .name = "rk3036-codec-platform",
+ .of_match_table = of_match_ptr(rk3036_codec_of_match),
+ },
+ .probe = rk3036_codec_platform_probe,
+ .remove = rk3036_codec_platform_remove,
+};
+
+module_platform_driver(rk3036_codec_platform_driver);
+
+MODULE_AUTHOR("Rockchip Inc.");
+MODULE_DESCRIPTION("Rockchip rk3036 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h
new file mode 100644
index 000000000000..da759c6c7501
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.h
@@ -0,0 +1,123 @@
+/*
+ * Driver of Inno Codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#ifndef _INNO_RK3036_CODEC_H
+#define _INNO_RK3036_CODEC_H
+
+/* codec registers */
+#define INNO_R00 0x00
+#define INNO_R01 0x0c
+#define INNO_R02 0x10
+#define INNO_R03 0x14
+#define INNO_R04 0x88
+#define INNO_R05 0x8c
+#define INNO_R06 0x90
+#define INNO_R07 0x94
+#define INNO_R08 0x98
+#define INNO_R09 0x9c
+#define INNO_R10 0xa0
+
+/* register bit filed */
+#define INNO_R00_CSR_RESET (0x0 << 0) /*codec system reset*/
+#define INNO_R00_CSR_WORK (0x1 << 0)
+#define INNO_R00_CDCR_RESET (0x0 << 1) /*codec digital core reset*/
+#define INNO_R00_CDCR_WORK (0x1 << 1)
+#define INNO_R00_PRB_DISABLE (0x0 << 6) /*power reset bypass*/
+#define INNO_R00_PRB_ENABLE (0x1 << 6)
+
+#define INNO_R01_I2SMODE_MSK (0x1 << 4)
+#define INNO_R01_I2SMODE_SLAVE (0x0 << 4)
+#define INNO_R01_I2SMODE_MASTER (0x1 << 4)
+#define INNO_R01_PINDIR_MSK (0x1 << 5)
+#define INNO_R01_PINDIR_IN_SLAVE (0x0 << 5) /*direction of pin*/
+#define INNO_R01_PINDIR_OUT_MASTER (0x1 << 5)
+
+#define INNO_R02_LRS_MSK (0x1 << 2)
+#define INNO_R02_LRS_NORMAL (0x0 << 2) /*DAC Left Right Swap*/
+#define INNO_R02_LRS_SWAP (0x1 << 2)
+#define INNO_R02_DACM_MSK (0x3 << 3)
+#define INNO_R02_DACM_PCM (0x3 << 3) /*DAC Mode*/
+#define INNO_R02_DACM_I2S (0x2 << 3)
+#define INNO_R02_DACM_LJM (0x1 << 3)
+#define INNO_R02_DACM_RJM (0x0 << 3)
+#define INNO_R02_VWL_MSK (0x3 << 5)
+#define INNO_R02_VWL_32BIT (0x3 << 5) /*1/2Frame Valid Word Len*/
+#define INNO_R02_VWL_24BIT (0x2 << 5)
+#define INNO_R02_VWL_20BIT (0x1 << 5)
+#define INNO_R02_VWL_16BIT (0x0 << 5)
+#define INNO_R02_LRCP_MSK (0x1 << 7)
+#define INNO_R02_LRCP_NORMAL (0x0 << 7) /*Left Right Polarity*/
+#define INNO_R02_LRCP_REVERSAL (0x1 << 7)
+
+#define INNO_R03_BCP_MSK (0x1 << 0)
+#define INNO_R03_BCP_NORMAL (0x0 << 0) /*DAC bit clock polarity*/
+#define INNO_R03_BCP_REVERSAL (0x1 << 0)
+#define INNO_R03_DACR_MSK (0x1 << 1)
+#define INNO_R03_DACR_RESET (0x0 << 1) /*DAC Reset*/
+#define INNO_R03_DACR_WORK (0x1 << 1)
+#define INNO_R03_FWL_MSK (0x3 << 2)
+#define INNO_R03_FWL_32BIT (0x3 << 2) /*1/2Frame Word Length*/
+#define INNO_R03_FWL_24BIT (0x2 << 2)
+#define INNO_R03_FWL_20BIT (0x1 << 2)
+#define INNO_R03_FWL_16BIT (0x0 << 2)
+
+#define INNO_R04_DACR_SW_SHIFT 0
+#define INNO_R04_DACL_SW_SHIFT 1
+#define INNO_R04_DACR_CLK_SHIFT 2
+#define INNO_R04_DACL_CLK_SHIFT 3
+#define INNO_R04_DACR_VREF_SHIFT 4
+#define INNO_R04_DACL_VREF_SHIFT 5
+
+#define INNO_R05_HPR_EN_SHIFT 0
+#define INNO_R05_HPL_EN_SHIFT 1
+#define INNO_R05_HPR_WORK_SHIFT 2
+#define INNO_R05_HPL_WORK_SHIFT 3
+
+#define INNO_R06_VOUTR_CZ_SHIFT 0
+#define INNO_R06_VOUTL_CZ_SHIFT 1
+#define INNO_R06_DACR_HILO_VREF_SHIFT 2
+#define INNO_R06_DACL_HILO_VREF_SHIFT 3
+#define INNO_R06_DAC_EN_SHIFT 5
+
+#define INNO_R06_DAC_PRECHARGE (0x0 << 4) /*PreCharge control for DAC*/
+#define INNO_R06_DAC_DISCHARGE (0x1 << 4)
+
+#define INNO_HP_GAIN_SHIFT 0
+/* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */
+#define INNO_HP_GAIN_0DB 0x1a
+#define INNO_HP_GAIN_N39DB 0x0
+
+#define INNO_R09_HP_ANTIPOP_MSK 0x3
+#define INNO_R09_HP_ANTIPOP_OFF 0x1
+#define INNO_R09_HP_ANTIPOP_ON 0x2
+#define INNO_R09_HPR_ANITPOP_SHIFT 0
+#define INNO_R09_HPL_ANITPOP_SHIFT 2
+#define INNO_R09_HPR_MUTE_SHIFT 4
+#define INNO_R09_HPL_MUTE_SHIFT 5
+#define INNO_R09_DACR_SWITCH_SHIFT 6
+#define INNO_R09_DACL_SWITCH_SHIFT 7
+
+#define INNO_R10_CHARGE_SEL_CUR_400I_YES (0x0 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_400I_NO (0x1 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_260I_YES (0x0 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_260I_NO (0x1 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_130I_YES (0x0 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_130I_NO (0x1 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_100I_YES (0x0 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_100I_NO (0x1 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_050I_YES (0x0 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_050I_NO (0x1 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_027I_YES (0x0 << 5)
+#define INNO_R10_CHARGE_SEL_CUR_027I_NO (0x1 << 5)
+
+#define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \
+ INNO_R10_CHARGE_SEL_CUR_260I_YES | \
+ INNO_R10_CHARGE_SEL_CUR_130I_YES | \
+ INNO_R10_CHARGE_SEL_CUR_100I_YES | \
+ INNO_R10_CHARGE_SEL_CUR_050I_YES | \
+ INNO_R10_CHARGE_SEL_CUR_027I_YES)
+
+#endif
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index f5e3dce2633a..5b1dfb1518fb 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -12,6 +12,7 @@
* max98357a.c -- MAX98357A ALSA SoC Codec driver
*/
+#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio.h>
@@ -123,10 +124,19 @@ static const struct of_device_id max98357a_device_id[] = {
MODULE_DEVICE_TABLE(of, max98357a_device_id);
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98357a_acpi_match[] = {
+ { "MX98357A", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match);
+#endif
+
static struct platform_driver max98357a_platform_driver = {
.driver = {
.name = "max98357a",
.of_match_table = of_match_ptr(max98357a_device_id),
+ .acpi_match_table = ACPI_PTR(max98357a_acpi_match),
},
.probe = max98357a_platform_probe,
.remove = max98357a_platform_remove,
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
deleted file mode 100644
index 08bb4863e96f..000000000000
--- a/sound/soc/codecs/pcm1792a.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * PCM1792A ASoC codec driver
- *
- * Copyright (c) Amarula Solutions B.V. 2013
- *
- * Michael Trimarchi <michael@amarulasolutions.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include "pcm1792a.h"
-
-#define PCM1792A_DAC_VOL_LEFT 0x10
-#define PCM1792A_DAC_VOL_RIGHT 0x11
-#define PCM1792A_FMT_CONTROL 0x12
-#define PCM1792A_MODE_CONTROL 0x13
-#define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL
-
-#define PCM1792A_FMT_MASK 0x70
-#define PCM1792A_FMT_SHIFT 4
-#define PCM1792A_MUTE_MASK 0x01
-#define PCM1792A_MUTE_SHIFT 0
-#define PCM1792A_ATLD_ENABLE (1 << 7)
-
-static const struct reg_default pcm1792a_reg_defaults[] = {
- { 0x10, 0xff },
- { 0x11, 0xff },
- { 0x12, 0x50 },
- { 0x13, 0x00 },
- { 0x14, 0x00 },
- { 0x15, 0x01 },
- { 0x16, 0x00 },
- { 0x17, 0x00 },
-};
-
-static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg)
-{
- return reg >= 0x10 && reg <= 0x17;
-}
-
-static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg)
-{
- bool accessible;
-
- accessible = pcm1792a_accessible_reg(dev, reg);
-
- return accessible && reg != 0x16 && reg != 0x17;
-}
-
-struct pcm1792a_private {
- struct regmap *regmap;
- unsigned int format;
- unsigned int rate;
-};
-
-static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int format)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-
- priv->format = format;
-
- return 0;
-}
-
-static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE,
- PCM1792A_MUTE_MASK, !!mute);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
- int val = 0, ret;
-
- priv->rate = params_rate(params);
-
- switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_RIGHT_J:
- switch (params_width(params)) {
- case 24:
- case 32:
- val = 2;
- break;
- case 16:
- val = 0;
- break;
- default:
- return -EINVAL;
- }
- break;
- case SND_SOC_DAIFMT_I2S:
- switch (params_width(params)) {
- case 24:
- case 32:
- val = 5;
- break;
- case 16:
- val = 4;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- dev_err(codec->dev, "Invalid DAI format\n");
- return -EINVAL;
- }
-
- val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE;
-
- ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL,
- PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops pcm1792a_dai_ops = {
- .set_fmt = pcm1792a_set_dai_fmt,
- .hw_params = pcm1792a_hw_params,
- .digital_mute = pcm1792a_digital_mute,
-};
-
-static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1);
-
-static const struct snd_kcontrol_new pcm1792a_controls[] = {
- SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT,
- PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
- pcm1792a_dac_tlv),
- SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0),
- SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = {
-SND_SOC_DAPM_OUTPUT("IOUTL+"),
-SND_SOC_DAPM_OUTPUT("IOUTL-"),
-SND_SOC_DAPM_OUTPUT("IOUTR+"),
-SND_SOC_DAPM_OUTPUT("IOUTR-"),
-};
-
-static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = {
- { "IOUTL+", NULL, "Playback" },
- { "IOUTL-", NULL, "Playback" },
- { "IOUTR+", NULL, "Playback" },
- { "IOUTR-", NULL, "Playback" },
-};
-
-static struct snd_soc_dai_driver pcm1792a_dai = {
- .name = "pcm1792a-hifi",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 2,
- .channels_max = 2,
- .rates = PCM1792A_RATES,
- .formats = PCM1792A_FORMATS, },
- .ops = &pcm1792a_dai_ops,
-};
-
-static const struct of_device_id pcm1792a_of_match[] = {
- { .compatible = "ti,pcm1792a", },
- { }
-};
-MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
-
-static const struct regmap_config pcm1792a_regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 23,
- .reg_defaults = pcm1792a_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults),
- .writeable_reg = pcm1792a_writeable_reg,
- .readable_reg = pcm1792a_accessible_reg,
-};
-
-static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = {
- .controls = pcm1792a_controls,
- .num_controls = ARRAY_SIZE(pcm1792a_controls),
- .dapm_widgets = pcm1792a_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(pcm1792a_dapm_widgets),
- .dapm_routes = pcm1792a_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(pcm1792a_dapm_routes),
-};
-
-static int pcm1792a_spi_probe(struct spi_device *spi)
-{
- struct pcm1792a_private *pcm1792a;
- int ret;
-
- pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private),
- GFP_KERNEL);
- if (!pcm1792a)
- return -ENOMEM;
-
- spi_set_drvdata(spi, pcm1792a);
-
- pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap);
- if (IS_ERR(pcm1792a->regmap)) {
- ret = PTR_ERR(pcm1792a->regmap);
- dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
- return ret;
- }
-
- return snd_soc_register_codec(&spi->dev,
- &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1);
-}
-
-static int pcm1792a_spi_remove(struct spi_device *spi)
-{
- snd_soc_unregister_codec(&spi->dev);
- return 0;
-}
-
-static const struct spi_device_id pcm1792a_spi_ids[] = {
- { "pcm1792a", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids);
-
-static struct spi_driver pcm1792a_codec_driver = {
- .driver = {
- .name = "pcm1792a",
- .of_match_table = of_match_ptr(pcm1792a_of_match),
- },
- .id_table = pcm1792a_spi_ids,
- .probe = pcm1792a_spi_probe,
- .remove = pcm1792a_spi_remove,
-};
-
-module_spi_driver(pcm1792a_codec_driver);
-
-MODULE_DESCRIPTION("ASoC PCM1792A driver");
-MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
new file mode 100644
index 000000000000..a56c7b767d90
--- /dev/null
+++ b/sound/soc/codecs/pcm179x.c
@@ -0,0 +1,271 @@
+/*
+ * PCM179X ASoC codec driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ * Michael Trimarchi <michael@amarulasolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "pcm179x.h"
+
+#define PCM179X_DAC_VOL_LEFT 0x10
+#define PCM179X_DAC_VOL_RIGHT 0x11
+#define PCM179X_FMT_CONTROL 0x12
+#define PCM179X_MODE_CONTROL 0x13
+#define PCM179X_SOFT_MUTE PCM179X_FMT_CONTROL
+
+#define PCM179X_FMT_MASK 0x70
+#define PCM179X_FMT_SHIFT 4
+#define PCM179X_MUTE_MASK 0x01
+#define PCM179X_MUTE_SHIFT 0
+#define PCM179X_ATLD_ENABLE (1 << 7)
+
+static const struct reg_default pcm179x_reg_defaults[] = {
+ { 0x10, 0xff },
+ { 0x11, 0xff },
+ { 0x12, 0x50 },
+ { 0x13, 0x00 },
+ { 0x14, 0x00 },
+ { 0x15, 0x01 },
+ { 0x16, 0x00 },
+ { 0x17, 0x00 },
+};
+
+static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg)
+{
+ return reg >= 0x10 && reg <= 0x17;
+}
+
+static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg)
+{
+ bool accessible;
+
+ accessible = pcm179x_accessible_reg(dev, reg);
+
+ return accessible && reg != 0x16 && reg != 0x17;
+}
+
+struct pcm179x_private {
+ struct regmap *regmap;
+ unsigned int format;
+ unsigned int rate;
+};
+
+static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+
+ priv->format = format;
+
+ return 0;
+}
+
+static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE,
+ PCM179X_MUTE_MASK, !!mute);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int pcm179x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+ int val = 0, ret;
+
+ priv->rate = params_rate(params);
+
+ switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 24:
+ case 32:
+ val = 2;
+ break;
+ case 16:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ switch (params_width(params)) {
+ case 24:
+ case 32:
+ val = 5;
+ break;
+ case 16:
+ val = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI format\n");
+ return -EINVAL;
+ }
+
+ val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE;
+
+ ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL,
+ PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops pcm179x_dai_ops = {
+ .set_fmt = pcm179x_set_dai_fmt,
+ .hw_params = pcm179x_hw_params,
+ .digital_mute = pcm179x_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm179x_controls[] = {
+ SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT,
+ PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+ pcm179x_dac_tlv),
+ SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0),
+ SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("IOUTL+"),
+SND_SOC_DAPM_OUTPUT("IOUTL-"),
+SND_SOC_DAPM_OUTPUT("IOUTR+"),
+SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = {
+ { "IOUTL+", NULL, "Playback" },
+ { "IOUTL-", NULL, "Playback" },
+ { "IOUTR+", NULL, "Playback" },
+ { "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm179x_dai = {
+ .name = "pcm179x-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PCM1792A_RATES,
+ .formats = PCM1792A_FORMATS, },
+ .ops = &pcm179x_dai_ops,
+};
+
+static const struct of_device_id pcm179x_of_match[] = {
+ { .compatible = "ti,pcm1792a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct regmap_config pcm179x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 23,
+ .reg_defaults = pcm179x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(pcm179x_reg_defaults),
+ .writeable_reg = pcm179x_writeable_reg,
+ .readable_reg = pcm179x_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
+ .controls = pcm179x_controls,
+ .num_controls = ARRAY_SIZE(pcm179x_controls),
+ .dapm_widgets = pcm179x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets),
+ .dapm_routes = pcm179x_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes),
+};
+
+static int pcm179x_spi_probe(struct spi_device *spi)
+{
+ struct pcm179x_private *pcm179x;
+ int ret;
+
+ pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private),
+ GFP_KERNEL);
+ if (!pcm179x)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, pcm179x);
+
+ pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap);
+ if (IS_ERR(pcm179x->regmap)) {
+ ret = PTR_ERR(pcm179x->regmap);
+ dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_pcm179x, &pcm179x_dai, 1);
+}
+
+static int pcm179x_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static const struct spi_device_id pcm179x_spi_ids[] = {
+ { "pcm179x", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
+
+static struct spi_driver pcm179x_codec_driver = {
+ .driver = {
+ .name = "pcm179x",
+ .of_match_table = of_match_ptr(pcm179x_of_match),
+ },
+ .id_table = pcm179x_spi_ids,
+ .probe = pcm179x_spi_probe,
+ .remove = pcm179x_spi_remove,
+};
+
+module_spi_driver(pcm179x_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm179x.h
index 51d5470fee16..c6fdc062a497 100644
--- a/sound/soc/codecs/pcm1792a.h
+++ b/sound/soc/codecs/pcm179x.h
@@ -1,5 +1,5 @@
/*
- * definitions for PCM1792A
+ * definitions for PCM179X
*
* Copyright 2013 Amarula Solutions
*
@@ -14,8 +14,8 @@
* GNU General Public License for more details.
*/
-#ifndef __PCM1792A_H__
-#define __PCM1792A_H__
+#ifndef __PCM179X_H__
+#define __PCM179X_H__
#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
new file mode 100644
index 000000000000..6feb0901dfeb
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a-i2c.c
@@ -0,0 +1,66 @@
+/*
+ * PCM3168A codec i2c driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcm3168a_probe(&i2c->dev, regmap);
+}
+
+static int pcm3168a_i2c_remove(struct i2c_client *i2c)
+{
+ pcm3168a_remove(&i2c->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id pcm3168a_i2c_id[] = {
+ { "pcm3168a", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+ { .compatible = "ti,pcm3168a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct i2c_driver pcm3168a_i2c_driver = {
+ .probe = pcm3168a_i2c_probe,
+ .remove = pcm3168a_i2c_remove,
+ .id_table = pcm3168a_i2c_id,
+ .driver = {
+ .name = "pcm3168a",
+ .of_match_table = pcm3168a_of_match,
+ .pm = &pcm3168a_pm_ops,
+ },
+};
+module_i2c_driver(pcm3168a_i2c_driver);
+
+MODULE_DESCRIPTION("PCM3168A I2C codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c
new file mode 100644
index 000000000000..03945a27ae40
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a-spi.c
@@ -0,0 +1,65 @@
+/*
+ * PCM3168A codec spi driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcm3168a_probe(&spi->dev, regmap);
+}
+
+static int pcm3168a_spi_remove(struct spi_device *spi)
+{
+ pcm3168a_remove(&spi->dev);
+
+ return 0;
+}
+
+static const struct spi_device_id pcm3168a_spi_id[] = {
+ { "pcm3168a", },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+ { .compatible = "ti,pcm3168a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct spi_driver pcm3168a_spi_driver = {
+ .probe = pcm3168a_spi_probe,
+ .remove = pcm3168a_spi_remove,
+ .id_table = pcm3168a_spi_id,
+ .driver = {
+ .name = "pcm3168a",
+ .of_match_table = pcm3168a_of_match,
+ .pm = &pcm3168a_pm_ops,
+ },
+};
+module_spi_driver(pcm3168a_spi_driver);
+
+MODULE_DESCRIPTION("PCM3168A SPI codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
new file mode 100644
index 000000000000..44b268aa4dd8
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a.c
@@ -0,0 +1,767 @@
+/*
+ * PCM3168A codec driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm3168a.h"
+
+#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define PCM3168A_FMT_I2S 0x0
+#define PCM3168A_FMT_LEFT_J 0x1
+#define PCM3168A_FMT_RIGHT_J 0x2
+#define PCM3168A_FMT_RIGHT_J_16 0x3
+#define PCM3168A_FMT_DSP_A 0x4
+#define PCM3168A_FMT_DSP_B 0x5
+#define PCM3168A_FMT_DSP_MASK 0x4
+
+#define PCM3168A_NUM_SUPPLIES 6
+static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+ "VDD1",
+ "VDD2",
+ "VCCAD1",
+ "VCCAD2",
+ "VCCDA1",
+ "VCCDA2"
+};
+
+struct pcm3168a_priv {
+ struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+ struct regmap *regmap;
+ struct clk *scki;
+ bool adc_master_mode;
+ bool dac_master_mode;
+ unsigned long sysclk;
+ unsigned int adc_fmt;
+ unsigned int dac_fmt;
+};
+
+static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off);
+
+static const char *const pcm3168a_volume_type[] = {
+ "Individual", "Master + Individual" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF,
+ PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type);
+
+static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF,
+ PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult);
+
+static const char *const pcm3168a_demp[] = {
+ "Disabled", "48khz", "44.1khz", "32khz" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF,
+ PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp);
+
+static const char *const pcm3168a_zf_func[] = {
+ "DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND",
+ "DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,
+ PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func);
+
+static const char *const pcm3168a_pol[] = { "Active High", "Active Low" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF,
+ PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol);
+
+static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" };
+
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD,
+ 0, 1, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD,
+ 2, 3, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD,
+ 4, 5, pcm3168a_con);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF,
+ PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF,
+ PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF,
+ PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol);
+
+/* -100db to 0db, register values 0-54 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1);
+
+/* -100db to 20db, register values 0-14 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1);
+
+static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
+ SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT,
+ PCM3168A_DAC_PSMDA_SHIFT, 1, 1),
+ SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off),
+ SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off),
+ SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off),
+ SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off),
+ SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0),
+ 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),
+ SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func),
+ SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol),
+ SOC_SINGLE_RANGE_TLV("Master Playback Volume",
+ PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0,
+ pcm3168a_dac_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume",
+ PCM3168A_DAC_VOL_CHAN_START,
+ PCM3168A_DAC_VOL_CHAN_START + 1,
+ 0, 54, 255, 0, pcm3168a_dac_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume",
+ PCM3168A_DAC_VOL_CHAN_START + 2,
+ PCM3168A_DAC_VOL_CHAN_START + 3,
+ 0, 54, 255, 0, pcm3168a_dac_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume",
+ PCM3168A_DAC_VOL_CHAN_START + 4,
+ PCM3168A_DAC_VOL_CHAN_START + 5,
+ 0, 54, 255, 0, pcm3168a_dac_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume",
+ PCM3168A_DAC_VOL_CHAN_START + 6,
+ PCM3168A_DAC_VOL_CHAN_START + 7,
+ 0, 54, 255, 0, pcm3168a_dac_tlv),
+ SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+ PCM3168A_ADC_BYP_SHIFT, 1, 1),
+ SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+ PCM3168A_ADC_BYP_SHIFT + 1, 1, 1),
+ SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+ PCM3168A_ADC_BYP_SHIFT + 2, 1, 1),
+ SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con),
+ SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con),
+ SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con),
+ SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0),
+ SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0),
+ SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0),
+ 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),
+ SOC_SINGLE_RANGE_TLV("Master Capture Volume",
+ PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0,
+ pcm3168a_adc_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume",
+ PCM3168A_ADC_VOL_CHAN_START,
+ PCM3168A_ADC_VOL_CHAN_START + 1,
+ 0, 14, 255, 0, pcm3168a_adc_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume",
+ PCM3168A_ADC_VOL_CHAN_START + 2,
+ PCM3168A_ADC_VOL_CHAN_START + 3,
+ 0, 14, 255, 0, pcm3168a_adc_tlv),
+ SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume",
+ PCM3168A_ADC_VOL_CHAN_START + 4,
+ PCM3168A_ADC_VOL_CHAN_START + 5,
+ 0, 14, 255, 0, pcm3168a_adc_tlv)
+};
+
+static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_OPEDA_SHIFT, 1),
+ SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_OPEDA_SHIFT + 1, 1),
+ SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_OPEDA_SHIFT + 2, 1),
+ SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT,
+ PCM3168A_DAC_OPEDA_SHIFT + 3, 1),
+
+ SND_SOC_DAPM_OUTPUT("AOUT1L"),
+ SND_SOC_DAPM_OUTPUT("AOUT1R"),
+ SND_SOC_DAPM_OUTPUT("AOUT2L"),
+ SND_SOC_DAPM_OUTPUT("AOUT2R"),
+ SND_SOC_DAPM_OUTPUT("AOUT3L"),
+ SND_SOC_DAPM_OUTPUT("AOUT3R"),
+ SND_SOC_DAPM_OUTPUT("AOUT4L"),
+ SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+ SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB,
+ PCM3168A_ADC_PSVAD_SHIFT, 1),
+ SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB,
+ PCM3168A_ADC_PSVAD_SHIFT + 1, 1),
+ SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB,
+ PCM3168A_ADC_PSVAD_SHIFT + 2, 1),
+
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("AIN3L"),
+ SND_SOC_DAPM_INPUT("AIN3R")
+};
+
+static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = {
+ /* Playback */
+ { "AOUT1L", NULL, "DAC1" },
+ { "AOUT1R", NULL, "DAC1" },
+
+ { "AOUT2L", NULL, "DAC2" },
+ { "AOUT2R", NULL, "DAC2" },
+
+ { "AOUT3L", NULL, "DAC3" },
+ { "AOUT3R", NULL, "DAC3" },
+
+ { "AOUT4L", NULL, "DAC4" },
+ { "AOUT4R", NULL, "DAC4" },
+
+ /* Capture */
+ { "ADC1", NULL, "AIN1L" },
+ { "ADC1", NULL, "AIN1R" },
+
+ { "ADC2", NULL, "AIN2L" },
+ { "ADC2", NULL, "AIN2R" },
+
+ { "ADC3", NULL, "AIN3L" },
+ { "ADC3", NULL, "AIN3R" }
+};
+
+static unsigned int pcm3168a_scki_ratios[] = {
+ 768,
+ 512,
+ 384,
+ 256,
+ 192,
+ 128
+};
+
+#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios)
+#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
+
+#define PCM1368A_MAX_SYSCLK 36864000
+
+static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
+{
+ int ret;
+
+ ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0);
+ if (ret)
+ return ret;
+
+ /* Internal reset is de-asserted after 3846 SCKI cycles */
+ msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
+
+ return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE,
+ PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
+}
+
+static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+
+ regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
+
+ return 0;
+}
+
+static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec);
+
+ if (freq > PCM1368A_MAX_SYSCLK)
+ return -EINVAL;
+
+ pcm3168a->sysclk = freq;
+
+ return 0;
+}
+
+static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format, bool dac)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+ u32 fmt, reg, mask, shift;
+ bool master_mode;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ fmt = PCM3168A_FMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ fmt = PCM3168A_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ fmt = PCM3168A_FMT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ fmt = PCM3168A_FMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ fmt = PCM3168A_FMT_DSP_B;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported dai format\n");
+ return -EINVAL;
+ }
+
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ master_mode = false;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ master_mode = true;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported master/slave mode\n");
+ return -EINVAL;
+ }
+
+ switch (format & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (dac) {
+ reg = PCM3168A_DAC_PWR_MST_FMT;
+ mask = PCM3168A_DAC_FMT_MASK;
+ shift = PCM3168A_DAC_FMT_SHIFT;
+ pcm3168a->dac_master_mode = master_mode;
+ pcm3168a->dac_fmt = fmt;
+ } else {
+ reg = PCM3168A_ADC_MST_FMT;
+ mask = PCM3168A_ADC_FMTAD_MASK;
+ shift = PCM3168A_ADC_FMTAD_SHIFT;
+ pcm3168a->adc_master_mode = master_mode;
+ pcm3168a->adc_fmt = fmt;
+ }
+
+ regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+ return 0;
+}
+
+static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
+ unsigned int format)
+{
+ return pcm3168a_set_dai_fmt(dai, format, true);
+}
+
+static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
+ unsigned int format)
+{
+ return pcm3168a_set_dai_fmt(dai, format, false);
+}
+
+static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+ bool tx, master_mode;
+ u32 val, mask, shift, reg;
+ unsigned int rate, channels, fmt, ratio, max_ratio;
+ int i, min_frame_size;
+ snd_pcm_format_t format;
+
+ rate = params_rate(params);
+ format = params_format(params);
+ channels = params_channels(params);
+
+ ratio = pcm3168a->sysclk / rate;
+
+ tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ if (tx) {
+ max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
+ reg = PCM3168A_DAC_PWR_MST_FMT;
+ mask = PCM3168A_DAC_MSDA_MASK;
+ shift = PCM3168A_DAC_MSDA_SHIFT;
+ master_mode = pcm3168a->dac_master_mode;
+ fmt = pcm3168a->dac_fmt;
+ } else {
+ max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
+ reg = PCM3168A_ADC_MST_FMT;
+ mask = PCM3168A_ADC_MSAD_MASK;
+ shift = PCM3168A_ADC_MSAD_SHIFT;
+ master_mode = pcm3168a->adc_master_mode;
+ fmt = pcm3168a->adc_fmt;
+ }
+
+ for (i = 0; i < max_ratio; i++) {
+ if (pcm3168a_scki_ratios[i] == ratio)
+ break;
+ }
+
+ if (i == max_ratio) {
+ dev_err(codec->dev, "unsupported sysclk ratio\n");
+ return -EINVAL;
+ }
+
+ min_frame_size = params_width(params) * 2;
+ switch (min_frame_size) {
+ case 32:
+ if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
+ dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
+ return -EINVAL;
+ }
+ fmt = PCM3168A_FMT_RIGHT_J_16;
+ break;
+ case 48:
+ if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
+ dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
+ return -EINVAL;
+ }
+ break;
+ case 64:
+ break;
+ default:
+ dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
+ return -EINVAL;
+ }
+
+ if (master_mode)
+ val = ((i + 1) << shift);
+ else
+ val = 0;
+
+ regmap_update_bits(pcm3168a->regmap, reg, mask, val);
+
+ if (tx) {
+ mask = PCM3168A_DAC_FMT_MASK;
+ shift = PCM3168A_DAC_FMT_SHIFT;
+ } else {
+ mask = PCM3168A_ADC_FMTAD_MASK;
+ shift = PCM3168A_ADC_FMTAD_SHIFT;
+ }
+
+ regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+ .set_fmt = pcm3168a_set_dai_fmt_dac,
+ .set_sysclk = pcm3168a_set_dai_sysclk,
+ .hw_params = pcm3168a_hw_params,
+ .digital_mute = pcm3168a_digital_mute
+};
+
+static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
+ .set_fmt = pcm3168a_set_dai_fmt_adc,
+ .set_sysclk = pcm3168a_set_dai_sysclk,
+ .hw_params = pcm3168a_hw_params
+};
+
+static struct snd_soc_dai_driver pcm3168a_dais[] = {
+ {
+ .name = "pcm3168a-dac",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = PCM3168A_FORMATS
+ },
+ .ops = &pcm3168a_dac_dai_ops
+ },
+ {
+ .name = "pcm3168a-adc",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = PCM3168A_FORMATS
+ },
+ .ops = &pcm3168a_adc_dai_ops
+ },
+};
+
+static const struct reg_default pcm3168a_reg_default[] = {
+ { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
+ { PCM3168A_DAC_PWR_MST_FMT, 0x00 },
+ { PCM3168A_DAC_OP_FLT, 0x00 },
+ { PCM3168A_DAC_INV, 0x00 },
+ { PCM3168A_DAC_MUTE, 0x00 },
+ { PCM3168A_DAC_ZERO, 0x00 },
+ { PCM3168A_DAC_ATT_DEMP_ZF, 0x00 },
+ { PCM3168A_DAC_VOL_MASTER, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 1, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 2, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 3, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 4, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 5, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 6, 0xff },
+ { PCM3168A_DAC_VOL_CHAN_START + 7, 0xff },
+ { PCM3168A_ADC_SMODE, 0x00 },
+ { PCM3168A_ADC_MST_FMT, 0x00 },
+ { PCM3168A_ADC_PWR_HPFB, 0x00 },
+ { PCM3168A_ADC_SEAD, 0x00 },
+ { PCM3168A_ADC_INV, 0x00 },
+ { PCM3168A_ADC_MUTE, 0x00 },
+ { PCM3168A_ADC_OV, 0x00 },
+ { PCM3168A_ADC_ATT_OVF, 0x00 },
+ { PCM3168A_ADC_VOL_MASTER, 0xd3 },
+ { PCM3168A_ADC_VOL_CHAN_START, 0xd3 },
+ { PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 },
+ { PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 },
+ { PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 },
+ { PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 },
+ { PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 }
+};
+
+static bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg >= PCM3168A_RST_SMODE)
+ return true;
+ else
+ return false;
+}
+
+static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PCM3168A_DAC_ZERO:
+ case PCM3168A_ADC_OV:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg < PCM3168A_RST_SMODE)
+ return false;
+
+ switch (reg) {
+ case PCM3168A_DAC_ZERO:
+ case PCM3168A_ADC_OV:
+ return false;
+ default:
+ return true;
+ }
+}
+
+const struct regmap_config pcm3168a_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = PCM3168A_ADC_VOL_CHAN_START + 5,
+ .reg_defaults = pcm3168a_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default),
+ .readable_reg = pcm3168a_readable_register,
+ .volatile_reg = pcm3168a_volatile_register,
+ .writeable_reg = pcm3168a_writeable_register,
+ .cache_type = REGCACHE_FLAT
+};
+EXPORT_SYMBOL_GPL(pcm3168a_regmap);
+
+static const struct snd_soc_codec_driver pcm3168a_driver = {
+ .idle_bias_off = true,
+ .controls = pcm3168a_snd_controls,
+ .num_controls = ARRAY_SIZE(pcm3168a_snd_controls),
+ .dapm_widgets = pcm3168a_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets),
+ .dapm_routes = pcm3168a_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes)
+};
+
+int pcm3168a_probe(struct device *dev, struct regmap *regmap)
+{
+ struct pcm3168a_priv *pcm3168a;
+ int ret, i;
+
+ pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL);
+ if (pcm3168a == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, pcm3168a);
+
+ pcm3168a->scki = devm_clk_get(dev, "scki");
+ if (IS_ERR(pcm3168a->scki)) {
+ ret = PTR_ERR(pcm3168a->scki);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to acquire clock 'scki': %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(pcm3168a->scki);
+ if (ret) {
+ dev_err(dev, "Failed to enable mclk: %d\n", ret);
+ return ret;
+ }
+
+ pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
+
+ for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
+ pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev,
+ ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to request supplies: %d\n", ret);
+ goto err_clk;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+ pcm3168a->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable supplies: %d\n", ret);
+ goto err_clk;
+ }
+
+ pcm3168a->regmap = regmap;
+ if (IS_ERR(pcm3168a->regmap)) {
+ ret = PTR_ERR(pcm3168a->regmap);
+ dev_err(dev, "failed to allocate regmap: %d\n", ret);
+ goto err_regulator;
+ }
+
+ ret = pcm3168a_reset(pcm3168a);
+ if (ret) {
+ dev_err(dev, "Failed to reset device: %d\n", ret);
+ goto err_regulator;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais,
+ ARRAY_SIZE(pcm3168a_dais));
+ if (ret) {
+ dev_err(dev, "failed to register codec: %d\n", ret);
+ goto err_regulator;
+ }
+
+ return 0;
+
+err_regulator:
+ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+ pcm3168a->supplies);
+err_clk:
+ clk_disable_unprepare(pcm3168a->scki);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcm3168a_probe);
+
+void pcm3168a_remove(struct device *dev)
+{
+ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+ snd_soc_unregister_codec(dev);
+ pm_runtime_disable(dev);
+ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+ pcm3168a->supplies);
+ clk_disable_unprepare(pcm3168a->scki);
+}
+EXPORT_SYMBOL_GPL(pcm3168a_remove);
+
+#ifdef CONFIG_PM
+static int pcm3168a_rt_resume(struct device *dev)
+{
+ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(pcm3168a->scki);
+ if (ret) {
+ dev_err(dev, "Failed to enable mclk: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+ pcm3168a->supplies);
+ if (ret) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ goto err_clk;
+ }
+
+ ret = pcm3168a_reset(pcm3168a);
+ if (ret) {
+ dev_err(dev, "Failed to reset device: %d\n", ret);
+ goto err_regulator;
+ }
+
+ regcache_cache_only(pcm3168a->regmap, false);
+
+ regcache_mark_dirty(pcm3168a->regmap);
+
+ ret = regcache_sync(pcm3168a->regmap);
+ if (ret) {
+ dev_err(dev, "Failed to sync regmap: %d\n", ret);
+ goto err_regulator;
+ }
+
+ return 0;
+
+err_regulator:
+ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+ pcm3168a->supplies);
+err_clk:
+ clk_disable_unprepare(pcm3168a->scki);
+
+ return ret;
+}
+
+static int pcm3168a_rt_suspend(struct device *dev)
+{
+ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+ regcache_cache_only(pcm3168a->regmap, true);
+
+ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+ pcm3168a->supplies);
+
+ clk_disable_unprepare(pcm3168a->scki);
+
+ return 0;
+}
+#endif
+
+const struct dev_pm_ops pcm3168a_pm_ops = {
+ SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
+
+MODULE_DESCRIPTION("PCM3168A codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h
new file mode 100644
index 000000000000..56c8332d82fb
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a.h
@@ -0,0 +1,100 @@
+/*
+ * PCM3168A codec driver header
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __PCM3168A_H__
+#define __PCM3168A_H__
+
+extern const struct dev_pm_ops pcm3168a_pm_ops;
+extern const struct regmap_config pcm3168a_regmap;
+
+extern int pcm3168a_probe(struct device *dev, struct regmap *regmap);
+extern void pcm3168a_remove(struct device *dev);
+
+#define PCM3168A_RST_SMODE 0x40
+#define PCM3168A_MRST_MASK 0x80
+#define PCM3168A_SRST_MASK 0x40
+#define PCM3168A_DAC_SRDA_SHIFT 0
+#define PCM3168A_DAC_SRDA_MASK 0x3
+
+#define PCM3168A_DAC_PWR_MST_FMT 0x41
+#define PCM3168A_DAC_PSMDA_SHIFT 7
+#define PCM3168A_DAC_PSMDA_MASK 0x80
+#define PCM3168A_DAC_MSDA_SHIFT 4
+#define PCM3168A_DAC_MSDA_MASK 0x70
+#define PCM3168A_DAC_FMT_SHIFT 0
+#define PCM3168A_DAC_FMT_MASK 0xf
+
+#define PCM3168A_DAC_OP_FLT 0x42
+#define PCM3168A_DAC_OPEDA_SHIFT 4
+#define PCM3168A_DAC_OPEDA_MASK 0xf0
+#define PCM3168A_DAC_FLT_SHIFT 0
+#define PCM3168A_DAC_FLT_MASK 0xf
+
+#define PCM3168A_DAC_INV 0x43
+
+#define PCM3168A_DAC_MUTE 0x44
+
+#define PCM3168A_DAC_ZERO 0x45
+
+#define PCM3168A_DAC_ATT_DEMP_ZF 0x46
+#define PCM3168A_DAC_ATMDDA_MASK 0x80
+#define PCM3168A_DAC_ATMDDA_SHIFT 7
+#define PCM3168A_DAC_ATSPDA_MASK 0x40
+#define PCM3168A_DAC_ATSPDA_SHIFT 6
+#define PCM3168A_DAC_DEMP_SHIFT 4
+#define PCM3168A_DAC_DEMP_MASK 0x30
+#define PCM3168A_DAC_AZRO_SHIFT 1
+#define PCM3168A_DAC_AZRO_MASK 0xe
+#define PCM3168A_DAC_ZREV_MASK 0x1
+#define PCM3168A_DAC_ZREV_SHIFT 0
+
+#define PCM3168A_DAC_VOL_MASTER 0x47
+
+#define PCM3168A_DAC_VOL_CHAN_START 0x48
+
+#define PCM3168A_ADC_SMODE 0x50
+#define PCM3168A_ADC_SRAD_SHIFT 0
+#define PCM3168A_ADC_SRAD_MASK 0x3
+
+#define PCM3168A_ADC_MST_FMT 0x51
+#define PCM3168A_ADC_MSAD_SHIFT 4
+#define PCM3168A_ADC_MSAD_MASK 0x70
+#define PCM3168A_ADC_FMTAD_SHIFT 0
+#define PCM3168A_ADC_FMTAD_MASK 0x7
+
+#define PCM3168A_ADC_PWR_HPFB 0x52
+#define PCM3168A_ADC_PSVAD_SHIFT 4
+#define PCM3168A_ADC_PSVAD_MASK 0x70
+#define PCM3168A_ADC_BYP_SHIFT 0
+#define PCM3168A_ADC_BYP_MASK 0x7
+
+#define PCM3168A_ADC_SEAD 0x53
+
+#define PCM3168A_ADC_INV 0x54
+
+#define PCM3168A_ADC_MUTE 0x55
+
+#define PCM3168A_ADC_OV 0x56
+
+#define PCM3168A_ADC_ATT_OVF 0x57
+#define PCM3168A_ADC_ATMDAD_MASK 0x80
+#define PCM3168A_ADC_ATMDAD_SHIFT 7
+#define PCM3168A_ADC_ATSPAD_MASK 0x40
+#define PCM3168A_ADC_ATSPAD_SHIFT 6
+#define PCM3168A_ADC_OVFP_MASK 0x1
+#define PCM3168A_ADC_OVFP_SHIFT 0
+
+#define PCM3168A_ADC_VOL_MASTER 0x58
+
+#define PCM3168A_ADC_VOL_CHAN_START 0x59
+
+#endif
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index af2ed774b552..bc08f0c5a5f6 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1114,6 +1114,12 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
}
},
+ {
+ .ident = "Intel Skylake RVP",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform")
+ }
+ },
{ }
};
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index b3f795c60749..30c6de62ae6c 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -855,8 +855,6 @@ static int rt298_set_dai_sysclk(struct snd_soc_dai *dai,
snd_soc_update_bits(codec,
RT298_I2S_CTRL2, 0x0100, 0x0100);
snd_soc_update_bits(codec,
- RT298_PLL_CTRL, 0x4, 0x4);
- snd_soc_update_bits(codec,
RT298_PLL_CTRL1, 0x20, 0x0);
}
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
new file mode 100644
index 000000000000..1c10d8ed39d2
--- /dev/null
+++ b/sound/soc/codecs/rt5616.c
@@ -0,0 +1,1381 @@
+/*
+ * rt5616.c -- RT5616 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5616.h"
+
+#define RT5616_PR_RANGE_BASE (0xff + 1)
+#define RT5616_PR_SPACING 0x100
+
+#define RT5616_PR_BASE (RT5616_PR_RANGE_BASE + (0 * RT5616_PR_SPACING))
+
+static const struct regmap_range_cfg rt5616_ranges[] = {
+ {
+ .name = "PR",
+ .range_min = RT5616_PR_BASE,
+ .range_max = RT5616_PR_BASE + 0xf8,
+ .selector_reg = RT5616_PRIV_INDEX,
+ .selector_mask = 0xff,
+ .selector_shift = 0x0,
+ .window_start = RT5616_PRIV_DATA,
+ .window_len = 0x1,
+ },
+};
+
+static const struct reg_sequence init_list[] = {
+ {RT5616_PR_BASE + 0x3d, 0x3e00},
+ {RT5616_PR_BASE + 0x25, 0x6110},
+ {RT5616_PR_BASE + 0x20, 0x611f},
+ {RT5616_PR_BASE + 0x21, 0x4040},
+ {RT5616_PR_BASE + 0x23, 0x0004},
+};
+#define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5616_reg[] = {
+ { 0x00, 0x0021 },
+ { 0x02, 0xc8c8 },
+ { 0x03, 0xc8c8 },
+ { 0x05, 0x0000 },
+ { 0x0d, 0x0000 },
+ { 0x0f, 0x0808 },
+ { 0x19, 0xafaf },
+ { 0x1c, 0x2f2f },
+ { 0x1e, 0x0000 },
+ { 0x27, 0x7860 },
+ { 0x29, 0x8080 },
+ { 0x2a, 0x5252 },
+ { 0x3b, 0x0000 },
+ { 0x3c, 0x006f },
+ { 0x3d, 0x0000 },
+ { 0x3e, 0x006f },
+ { 0x45, 0x6000 },
+ { 0x4d, 0x0000 },
+ { 0x4e, 0x0000 },
+ { 0x4f, 0x0279 },
+ { 0x50, 0x0000 },
+ { 0x51, 0x0000 },
+ { 0x52, 0x0279 },
+ { 0x53, 0xf000 },
+ { 0x61, 0x0000 },
+ { 0x62, 0x0000 },
+ { 0x63, 0x00c0 },
+ { 0x64, 0x0000 },
+ { 0x65, 0x0000 },
+ { 0x66, 0x0000 },
+ { 0x70, 0x8000 },
+ { 0x73, 0x1104 },
+ { 0x74, 0x0c00 },
+ { 0x80, 0x0000 },
+ { 0x81, 0x0000 },
+ { 0x82, 0x0000 },
+ { 0x8b, 0x0600 },
+ { 0x8e, 0x0004 },
+ { 0x8f, 0x1100 },
+ { 0x90, 0x0000 },
+ { 0x91, 0x0000 },
+ { 0x92, 0x0000 },
+ { 0x93, 0x2000 },
+ { 0x94, 0x0200 },
+ { 0x95, 0x0000 },
+ { 0xb0, 0x2080 },
+ { 0xb1, 0x0000 },
+ { 0xb2, 0x0000 },
+ { 0xb4, 0x2206 },
+ { 0xb5, 0x1f00 },
+ { 0xb6, 0x0000 },
+ { 0xb7, 0x0000 },
+ { 0xbb, 0x0000 },
+ { 0xbc, 0x0000 },
+ { 0xbd, 0x0000 },
+ { 0xbe, 0x0000 },
+ { 0xbf, 0x0000 },
+ { 0xc0, 0x0100 },
+ { 0xc1, 0x0000 },
+ { 0xc2, 0x0000 },
+ { 0xc8, 0x0000 },
+ { 0xc9, 0x0000 },
+ { 0xca, 0x0000 },
+ { 0xcb, 0x0000 },
+ { 0xcc, 0x0000 },
+ { 0xcd, 0x0000 },
+ { 0xce, 0x0000 },
+ { 0xcf, 0x0013 },
+ { 0xd0, 0x0680 },
+ { 0xd1, 0x1c17 },
+ { 0xd3, 0xb320 },
+ { 0xd4, 0x0000 },
+ { 0xd6, 0x0000 },
+ { 0xd7, 0x0000 },
+ { 0xd9, 0x0809 },
+ { 0xda, 0x0000 },
+ { 0xfa, 0x0010 },
+ { 0xfb, 0x0000 },
+ { 0xfc, 0x0000 },
+ { 0xfe, 0x10ec },
+ { 0xff, 0x6281 },
+};
+
+struct rt5616_priv {
+ struct snd_soc_codec *codec;
+ struct delayed_work patch_work;
+ struct regmap *regmap;
+
+ int sysclk;
+ int sysclk_src;
+ int lrck[RT5616_AIFS];
+ int bclk[RT5616_AIFS];
+ int master[RT5616_AIFS];
+
+ int pll_src;
+ int pll_in;
+ int pll_out;
+
+};
+
+static bool rt5616_volatile_register(struct device *dev, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+ if (reg >= rt5616_ranges[i].range_min &&
+ reg <= rt5616_ranges[i].range_max) {
+ return true;
+ }
+ }
+
+ switch (reg) {
+ case RT5616_RESET:
+ case RT5616_PRIV_DATA:
+ case RT5616_EQ_CTRL1:
+ case RT5616_DRC_AGC_1:
+ case RT5616_IRQ_CTRL2:
+ case RT5616_INT_IRQ_ST:
+ case RT5616_PGM_REG_ARR1:
+ case RT5616_PGM_REG_ARR3:
+ case RT5616_VENDOR_ID:
+ case RT5616_DEVICE_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt5616_readable_register(struct device *dev, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+ if (reg >= rt5616_ranges[i].range_min &&
+ reg <= rt5616_ranges[i].range_max) {
+ return true;
+ }
+ }
+
+ switch (reg) {
+ case RT5616_RESET:
+ case RT5616_VERSION_ID:
+ case RT5616_VENDOR_ID:
+ case RT5616_DEVICE_ID:
+ case RT5616_HP_VOL:
+ case RT5616_LOUT_CTRL1:
+ case RT5616_LOUT_CTRL2:
+ case RT5616_IN1_IN2:
+ case RT5616_INL1_INR1_VOL:
+ case RT5616_DAC1_DIG_VOL:
+ case RT5616_ADC_DIG_VOL:
+ case RT5616_ADC_BST_VOL:
+ case RT5616_STO1_ADC_MIXER:
+ case RT5616_AD_DA_MIXER:
+ case RT5616_STO_DAC_MIXER:
+ case RT5616_REC_L1_MIXER:
+ case RT5616_REC_L2_MIXER:
+ case RT5616_REC_R1_MIXER:
+ case RT5616_REC_R2_MIXER:
+ case RT5616_HPO_MIXER:
+ case RT5616_OUT_L1_MIXER:
+ case RT5616_OUT_L2_MIXER:
+ case RT5616_OUT_L3_MIXER:
+ case RT5616_OUT_R1_MIXER:
+ case RT5616_OUT_R2_MIXER:
+ case RT5616_OUT_R3_MIXER:
+ case RT5616_LOUT_MIXER:
+ case RT5616_PWR_DIG1:
+ case RT5616_PWR_DIG2:
+ case RT5616_PWR_ANLG1:
+ case RT5616_PWR_ANLG2:
+ case RT5616_PWR_MIXER:
+ case RT5616_PWR_VOL:
+ case RT5616_PRIV_INDEX:
+ case RT5616_PRIV_DATA:
+ case RT5616_I2S1_SDP:
+ case RT5616_ADDA_CLK1:
+ case RT5616_ADDA_CLK2:
+ case RT5616_GLB_CLK:
+ case RT5616_PLL_CTRL1:
+ case RT5616_PLL_CTRL2:
+ case RT5616_HP_OVCD:
+ case RT5616_DEPOP_M1:
+ case RT5616_DEPOP_M2:
+ case RT5616_DEPOP_M3:
+ case RT5616_CHARGE_PUMP:
+ case RT5616_PV_DET_SPK_G:
+ case RT5616_MICBIAS:
+ case RT5616_A_JD_CTL1:
+ case RT5616_A_JD_CTL2:
+ case RT5616_EQ_CTRL1:
+ case RT5616_EQ_CTRL2:
+ case RT5616_WIND_FILTER:
+ case RT5616_DRC_AGC_1:
+ case RT5616_DRC_AGC_2:
+ case RT5616_DRC_AGC_3:
+ case RT5616_SVOL_ZC:
+ case RT5616_JD_CTRL1:
+ case RT5616_JD_CTRL2:
+ case RT5616_IRQ_CTRL1:
+ case RT5616_IRQ_CTRL2:
+ case RT5616_INT_IRQ_ST:
+ case RT5616_GPIO_CTRL1:
+ case RT5616_GPIO_CTRL2:
+ case RT5616_GPIO_CTRL3:
+ case RT5616_PGM_REG_ARR1:
+ case RT5616_PGM_REG_ARR2:
+ case RT5616_PGM_REG_ARR3:
+ case RT5616_PGM_REG_ARR4:
+ case RT5616_PGM_REG_ARR5:
+ case RT5616_SCB_FUNC:
+ case RT5616_SCB_CTRL:
+ case RT5616_BASE_BACK:
+ case RT5616_MP3_PLUS1:
+ case RT5616_MP3_PLUS2:
+ case RT5616_ADJ_HPF_CTRL1:
+ case RT5616_ADJ_HPF_CTRL2:
+ case RT5616_HP_CALIB_AMP_DET:
+ case RT5616_HP_CALIB2:
+ case RT5616_SV_ZCD1:
+ case RT5616_SV_ZCD2:
+ case RT5616_D_MISC:
+ case RT5616_DUMMY2:
+ case RT5616_DUMMY3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+ 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+ 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+};
+
+static const struct snd_kcontrol_new rt5616_snd_controls[] = {
+ /* Headphone Output Volume */
+ SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL,
+ RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL,
+ RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+ /* OUTPUT Control */
+ SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1,
+ RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1,
+ RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1),
+ SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1,
+ RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* DAC Digital Volume */
+ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL,
+ RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+ 175, 0, dac_vol_tlv),
+ /* IN1/IN2 Control */
+ SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2,
+ RT5616_BST_SFT1, 8, 0, bst_tlv),
+ SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2,
+ RT5616_BST_SFT2, 8, 0, bst_tlv),
+ /* INL/INR Volume Control */
+ SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL,
+ RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT,
+ 31, 1, in_vol_tlv),
+ /* ADC Digital Volume Control */
+ SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL,
+ RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL,
+ RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+ 127, 0, adc_vol_tlv),
+
+ /* ADC Boost Volume Control */
+ SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL,
+ RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT,
+ 3, 0, adc_bst_tlv),
+};
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int val;
+
+ val = snd_soc_read(snd_soc_dapm_to_codec(source->dapm), RT5616_GLB_CLK);
+ val &= RT5616_SCLK_SRC_MASK;
+ if (val == RT5616_SCLK_SRC_PLL1)
+ return 1;
+ else
+ return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5616_sto1_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+ RT5616_M_STO1_ADC_L1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto1_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+ RT5616_M_STO1_ADC_R1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+ RT5616_M_ADCMIX_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+ RT5616_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+ RT5616_M_ADCMIX_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+ RT5616_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+ RT5616_M_DAC_L1_MIXL_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+ RT5616_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+ RT5616_M_DAC_R1_MIXR_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+ RT5616_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5616_rec_l_mix[] = {
+ SOC_DAPM_SINGLE("INL1 Switch", RT5616_REC_L2_MIXER,
+ RT5616_M_IN1_L_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_L2_MIXER,
+ RT5616_M_BST2_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_L2_MIXER,
+ RT5616_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_rec_r_mix[] = {
+ SOC_DAPM_SINGLE("INR1 Switch", RT5616_REC_R2_MIXER,
+ RT5616_M_IN1_R_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_R2_MIXER,
+ RT5616_M_BST2_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_R2_MIXER,
+ RT5616_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5616_out_l_mix[] = {
+ SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_L3_MIXER,
+ RT5616_M_BST1_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_L3_MIXER,
+ RT5616_M_BST2_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL1 Switch", RT5616_OUT_L3_MIXER,
+ RT5616_M_IN1_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("REC MIXL Switch", RT5616_OUT_L3_MIXER,
+ RT5616_M_RM_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_OUT_L3_MIXER,
+ RT5616_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_out_r_mix[] = {
+ SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_R3_MIXER,
+ RT5616_M_BST2_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_R3_MIXER,
+ RT5616_M_BST1_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR1 Switch", RT5616_OUT_R3_MIXER,
+ RT5616_M_IN1_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("REC MIXR Switch", RT5616_OUT_R3_MIXER,
+ RT5616_M_RM_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_OUT_R3_MIXER,
+ RT5616_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_hpo_mix[] = {
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5616_HPO_MIXER,
+ RT5616_M_DAC1_HM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("HPVOL Switch", RT5616_HPO_MIXER,
+ RT5616_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_lout_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_LOUT_MIXER,
+ RT5616_M_DAC_L1_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_LOUT_MIXER,
+ RT5616_M_DAC_R1_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOL L Switch", RT5616_LOUT_MIXER,
+ RT5616_M_OV_L_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOL R Switch", RT5616_LOUT_MIXER,
+ RT5616_M_OV_R_LM_SFT, 1, 1),
+};
+
+static int rt5616_adc_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+ RT5616_L_MUTE | RT5616_R_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+ RT5616_L_MUTE | RT5616_R_MUTE,
+ RT5616_L_MUTE | RT5616_R_MUTE);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* depop parameters */
+ snd_soc_update_bits(codec, RT5616_DEPOP_M2,
+ RT5616_DEPOP_MASK, RT5616_DEPOP_MAN);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
+ RT5616_HP_CB_MASK, RT5616_HP_CP_PU |
+ RT5616_HP_SG_DIS | RT5616_HP_CB_PU);
+ snd_soc_write(codec, RT5616_PR_BASE +
+ RT5616_HP_DCC_INT1, 0x9f00);
+ /* headphone amp power on */
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2, 0);
+ snd_soc_update_bits(codec, RT5616_PWR_VOL,
+ RT5616_PWR_HV_L | RT5616_PWR_HV_R,
+ RT5616_PWR_HV_L | RT5616_PWR_HV_R);
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+ RT5616_PWR_HA, RT5616_PWR_HP_L |
+ RT5616_PWR_HP_R | RT5616_PWR_HA);
+ msleep(50);
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+ snd_soc_update_bits(codec, RT5616_CHARGE_PUMP,
+ RT5616_PM_HP_MASK, RT5616_PM_HP_HV);
+ snd_soc_update_bits(codec, RT5616_PR_BASE +
+ RT5616_CHOP_DAC_ADC, 0x0200, 0x0200);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_HP_CO_MASK | RT5616_HP_SG_MASK,
+ RT5616_HP_CO_EN | RT5616_HP_SG_EN);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5616_PR_BASE +
+ RT5616_CHOP_DAC_ADC, 0x0200, 0x0);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+ RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+ RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+ /* headphone amp power down */
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_SMT_TRIG_MASK | RT5616_HP_CD_PD_MASK |
+ RT5616_HP_CO_MASK | RT5616_HP_CP_MASK |
+ RT5616_HP_SG_MASK | RT5616_HP_CB_MASK,
+ RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN |
+ RT5616_HP_CO_DIS | RT5616_HP_CP_PD |
+ RT5616_HP_SG_EN | RT5616_HP_CB_PD);
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+ RT5616_PWR_HA, 0);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5616_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* headphone unmute sequence */
+ snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+ RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+ RT5616_CP_FQ3_MASK,
+ (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT) |
+ (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) |
+ (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT));
+ snd_soc_write(codec, RT5616_PR_BASE +
+ RT5616_MAMP_INT_REG2, 0xfc00);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_RSTN_MASK, RT5616_RSTN_EN);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK |
+ RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS |
+ RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+ snd_soc_update_bits(codec, RT5616_HP_VOL,
+ RT5616_L_MUTE | RT5616_R_MUTE, 0);
+ msleep(100);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+ RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+ RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+ msleep(20);
+ snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+ RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ /* headphone mute sequence */
+ snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+ RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+ RT5616_CP_FQ3_MASK,
+ (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT) |
+ (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) |
+ (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT));
+ snd_soc_write(codec, RT5616_PR_BASE +
+ RT5616_MAMP_INT_REG2, 0xfc00);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_HP_SG_MASK, RT5616_HP_SG_EN);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_RSTP_MASK, RT5616_RSTP_EN);
+ snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+ RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK |
+ RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS |
+ RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+ snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+ RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS);
+ msleep(90);
+ snd_soc_update_bits(codec, RT5616_HP_VOL,
+ RT5616_L_MUTE | RT5616_R_MUTE,
+ RT5616_L_MUTE | RT5616_R_MUTE);
+ msleep(30);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5616_lout_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_LM, RT5616_PWR_LM);
+ snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+ RT5616_L_MUTE | RT5616_R_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+ RT5616_L_MUTE | RT5616_R_MUTE,
+ RT5616_L_MUTE | RT5616_R_MUTE);
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_LM, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5616_bst1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+ RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+ RT5616_PWR_BST1_OP2, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5616_bst2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+ RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+ RT5616_PWR_BST2_OP2, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2,
+ RT5616_PWR_PLL_BIT, 0, NULL, 0),
+ /* Input Side */
+ /* micbias */
+ SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1,
+ RT5616_PWR_LDO_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2,
+ RT5616_PWR_MB1_BIT, 0, NULL, 0),
+
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+
+ SND_SOC_DAPM_INPUT("IN1P"),
+ SND_SOC_DAPM_INPUT("IN2P"),
+ SND_SOC_DAPM_INPUT("IN2N"),
+
+ /* Boost */
+ SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2,
+ RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2,
+ RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ /* Input Volume */
+ SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL,
+ RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL,
+ RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL,
+ RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL,
+ RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0,
+ rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)),
+ SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0,
+ rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)),
+ /* ADCs */
+ SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1,
+ RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1,
+ RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+ /* ADC Mixer */
+ SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2,
+ RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5616_sto1_adc_l_mix, ARRAY_SIZE(rt5616_sto1_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5616_sto1_adc_r_mix, ARRAY_SIZE(rt5616_sto1_adc_r_mix)),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1,
+ RT5616_PWR_I2S1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Interface Select */
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Audio DSP */
+ SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Output Side */
+ /* DAC mixer before sound effect */
+ SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)),
+
+ SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2,
+ RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+
+ /* DAC Mixer */
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5616_sto_dac_l_mix, ARRAY_SIZE(rt5616_sto_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5616_sto_dac_r_mix, ARRAY_SIZE(rt5616_sto_dac_r_mix)),
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1,
+ RT5616_PWR_DAC_L1_BIT, 0),
+ SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1,
+ RT5616_PWR_DAC_R1_BIT, 0),
+ /* OUT Mixer */
+ SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT,
+ 0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT,
+ 0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)),
+ /* Output Volume */
+ SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL,
+ RT5616_PWR_OV_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL,
+ RT5616_PWR_OV_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL,
+ RT5616_PWR_HV_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL,
+ RT5616_PWR_HV_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL,
+ RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL,
+ RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL,
+ RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL,
+ RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+ /* HPO/LOUT/Mono Mixer */
+ SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0,
+ rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)),
+ SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+ rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)),
+
+ SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0,
+ rt5616_hp_event, SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
+ rt5616_lout_event, SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0,
+ rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+ SND_SOC_DAPM_OUTPUT("LOUTL"),
+ SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_route rt5616_dapm_routes[] = {
+ {"IN1P", NULL, "LDO"},
+ {"IN2P", NULL, "LDO"},
+
+ {"IN1P", NULL, "MIC1"},
+ {"IN2P", NULL, "MIC2"},
+ {"IN2N", NULL, "MIC2"},
+
+ {"BST1", NULL, "IN1P"},
+ {"BST2", NULL, "IN2P"},
+ {"BST2", NULL, "IN2N"},
+ {"BST1", NULL, "micbias1"},
+ {"BST2", NULL, "micbias1"},
+
+ {"INL1 VOL", NULL, "IN2P"},
+ {"INR1 VOL", NULL, "IN2N"},
+
+ {"RECMIXL", "INL1 Switch", "INL1 VOL"},
+ {"RECMIXL", "BST2 Switch", "BST2"},
+ {"RECMIXL", "BST1 Switch", "BST1"},
+
+ {"RECMIXR", "INR1 Switch", "INR1 VOL"},
+ {"RECMIXR", "BST2 Switch", "BST2"},
+ {"RECMIXR", "BST1 Switch", "BST1"},
+
+ {"ADC L", NULL, "RECMIXL"},
+ {"ADC R", NULL, "RECMIXR"},
+
+ {"Stereo1 ADC MIXL", "ADC1 Switch", "ADC L"},
+ {"Stereo1 ADC MIXL", NULL, "stereo1 filter"},
+ {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+ {"Stereo1 ADC MIXR", "ADC1 Switch", "ADC R"},
+ {"Stereo1 ADC MIXR", NULL, "stereo1 filter"},
+ {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+ {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+ {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+ {"IF1 ADC1", NULL, "I2S1"},
+
+ {"AIF1TX", NULL, "IF1 ADC1"},
+
+ {"IF1 DAC", NULL, "AIF1RX"},
+ {"IF1 DAC", NULL, "I2S1"},
+
+ {"IF1 DAC1 L", NULL, "IF1 DAC"},
+ {"IF1 DAC1 R", NULL, "IF1 DAC"},
+
+ {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+ {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+ {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+ {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+ {"Audio DSP", NULL, "DAC MIXL"},
+ {"Audio DSP", NULL, "DAC MIXR"},
+
+ {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+ {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+ {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+ {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+ {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+ {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+
+ {"DAC L1", NULL, "Stereo DAC MIXL"},
+ {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
+ {"DAC R1", NULL, "Stereo DAC MIXR"},
+ {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
+
+ {"OUT MIXL", "BST1 Switch", "BST1"},
+ {"OUT MIXL", "BST2 Switch", "BST2"},
+ {"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+ {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+ {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+ {"OUT MIXR", "BST2 Switch", "BST2"},
+ {"OUT MIXR", "BST1 Switch", "BST1"},
+ {"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+ {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+ {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+ {"HPOVOL L", NULL, "OUT MIXL"},
+ {"HPOVOL R", NULL, "OUT MIXR"},
+ {"OUTVOL L", NULL, "OUT MIXL"},
+ {"OUTVOL R", NULL, "OUT MIXR"},
+
+ {"DAC 1", NULL, "DAC L1"},
+ {"DAC 1", NULL, "DAC R1"},
+ {"HPOVOL", NULL, "HPOVOL L"},
+ {"HPOVOL", NULL, "HPOVOL R"},
+ {"HPO MIX", "DAC1 Switch", "DAC 1"},
+ {"HPO MIX", "HPVOL Switch", "HPOVOL"},
+
+ {"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+ {"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+ {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+ {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+ {"HP amp", NULL, "HPO MIX"},
+ {"HP amp", NULL, "Charge Pump"},
+ {"HPOL", NULL, "HP amp"},
+ {"HPOR", NULL, "HP amp"},
+
+ {"LOUT amp", NULL, "LOUT MIX"},
+ {"LOUT amp", NULL, "Charge Pump"},
+ {"LOUTL", NULL, "LOUT amp"},
+ {"LOUTR", NULL, "LOUT amp"},
+
+};
+
+static int rt5616_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val_len = 0, val_clk, mask_clk;
+ int pre_div, bclk_ms, frame_size;
+
+ rt5616->lrck[dai->id] = params_rate(params);
+
+ pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]);
+
+ if (pre_div < 0) {
+ dev_err(codec->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+ return -EINVAL;
+ }
+ bclk_ms = frame_size > 32 ? 1 : 0;
+ rt5616->bclk[dai->id] = rt5616->lrck[dai->id] * (32 << bclk_ms);
+
+ dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+ rt5616->bclk[dai->id], rt5616->lrck[dai->id]);
+ dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+ bclk_ms, pre_div, dai->id);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ val_len |= RT5616_I2S_DL_20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val_len |= RT5616_I2S_DL_24;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ val_len |= RT5616_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mask_clk = RT5616_I2S_PD1_MASK;
+ val_clk = pre_div << RT5616_I2S_PD1_SFT;
+ snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+ RT5616_I2S_DL_MASK, val_len);
+ snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk);
+
+
+ return 0;
+}
+
+static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5616->master[dai->id] = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg_val |= RT5616_I2S_MS_S;
+ rt5616->master[dai->id] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT5616_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT5616_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT5616_I2S_DF_PCM_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT5616_I2S_DF_PCM_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+ RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK |
+ RT5616_I2S_DF_MASK, reg_val);
+
+
+ return 0;
+}
+
+static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT5616_SCLK_S_MCLK:
+ reg_val |= RT5616_SCLK_SRC_MCLK;
+ break;
+ case RT5616_SCLK_S_PLL1:
+ reg_val |= RT5616_SCLK_SRC_PLL1;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, RT5616_GLB_CLK,
+ RT5616_SCLK_SRC_MASK, reg_val);
+ rt5616->sysclk = freq;
+ rt5616->sysclk_src = clk_id;
+
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+ return 0;
+}
+
+static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (source == rt5616->pll_src && freq_in == rt5616->pll_in &&
+ freq_out == rt5616->pll_out)
+ return 0;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(codec->dev, "PLL disabled\n");
+
+ rt5616->pll_in = 0;
+ rt5616->pll_out = 0;
+ snd_soc_update_bits(codec, RT5616_GLB_CLK,
+ RT5616_SCLK_SRC_MASK, RT5616_SCLK_SRC_MCLK);
+ return 0;
+ }
+
+ switch (source) {
+ case RT5616_PLL1_S_MCLK:
+ snd_soc_update_bits(codec, RT5616_GLB_CLK,
+ RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_MCLK);
+ break;
+ case RT5616_PLL1_S_BCLK1:
+ case RT5616_PLL1_S_BCLK2:
+ snd_soc_update_bits(codec, RT5616_GLB_CLK,
+ RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_BCLK1);
+ break;
+ default:
+ dev_err(codec->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ snd_soc_write(codec, RT5616_PLL_CTRL1,
+ pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code);
+ snd_soc_write(codec, RT5616_PLL_CTRL2,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT5616_PLL_M_SFT |
+ pll_code.m_bp << RT5616_PLL_M_BP_SFT);
+
+ rt5616->pll_in = freq_in;
+ rt5616->pll_out = freq_out;
+ rt5616->pll_src = source;
+
+ return 0;
+}
+
+static int rt5616_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_VREF1 | RT5616_PWR_MB |
+ RT5616_PWR_BG | RT5616_PWR_VREF2,
+ RT5616_PWR_VREF1 | RT5616_PWR_MB |
+ RT5616_PWR_BG | RT5616_PWR_VREF2);
+ mdelay(10);
+ snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2);
+ snd_soc_update_bits(codec, RT5616_D_MISC,
+ RT5616_D_GATE_EN, RT5616_D_GATE_EN);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, RT5616_D_MISC, RT5616_D_GATE_EN, 0);
+ snd_soc_write(codec, RT5616_PWR_DIG1, 0x0000);
+ snd_soc_write(codec, RT5616_PWR_DIG2, 0x0000);
+ snd_soc_write(codec, RT5616_PWR_VOL, 0x0000);
+ snd_soc_write(codec, RT5616_PWR_MIXER, 0x0000);
+ snd_soc_write(codec, RT5616_PWR_ANLG1, 0x0000);
+ snd_soc_write(codec, RT5616_PWR_ANLG2, 0x0000);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt5616_probe(struct snd_soc_codec *codec)
+{
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+ rt5616->codec = codec;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5616_suspend(struct snd_soc_codec *codec)
+{
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5616->regmap, true);
+ regcache_mark_dirty(rt5616->regmap);
+
+ return 0;
+}
+
+static int rt5616_resume(struct snd_soc_codec *codec)
+{
+ struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5616->regmap, false);
+ regcache_sync(rt5616->regmap);
+ return 0;
+}
+#else
+#define rt5616_suspend NULL
+#define rt5616_resume NULL
+#endif
+
+#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+
+struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+ .hw_params = rt5616_hw_params,
+ .set_fmt = rt5616_set_dai_fmt,
+ .set_sysclk = rt5616_set_dai_sysclk,
+ .set_pll = rt5616_set_dai_pll,
+};
+
+struct snd_soc_dai_driver rt5616_dai[] = {
+ {
+ .name = "rt5616-aif1",
+ .id = RT5616_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5616_STEREO_RATES,
+ .formats = RT5616_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5616_STEREO_RATES,
+ .formats = RT5616_FORMATS,
+ },
+ .ops = &rt5616_aif_dai_ops,
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
+ .probe = rt5616_probe,
+ .suspend = rt5616_suspend,
+ .resume = rt5616_resume,
+ .set_bias_level = rt5616_set_bias_level,
+ .idle_bias_off = true,
+ .controls = rt5616_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5616_snd_controls),
+ .dapm_widgets = rt5616_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets),
+ .dapm_routes = rt5616_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes),
+};
+
+static const struct regmap_config rt5616_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .use_single_rw = true,
+ .max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) *
+ RT5616_PR_SPACING),
+ .volatile_reg = rt5616_volatile_register,
+ .readable_reg = rt5616_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5616_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5616_reg),
+ .ranges = rt5616_ranges,
+ .num_ranges = ARRAY_SIZE(rt5616_ranges),
+};
+
+static const struct i2c_device_id rt5616_i2c_id[] = {
+ { "rt5616", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5616_of_match[] = {
+ { .compatible = "realtek,rt5616", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt5616_of_match);
+#endif
+
+static int rt5616_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5616_priv *rt5616;
+ unsigned int val;
+ int ret;
+
+ rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv),
+ GFP_KERNEL);
+ if (rt5616 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5616);
+
+ rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap);
+ if (IS_ERR(rt5616->regmap)) {
+ ret = PTR_ERR(rt5616->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt5616->regmap, RT5616_DEVICE_ID, &val);
+ if (val != 0x6281) {
+ dev_err(&i2c->dev,
+ "Device with ID register %#x is not rt5616\n",
+ val);
+ return -ENODEV;
+ }
+ regmap_write(rt5616->regmap, RT5616_RESET, 0);
+ regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+ RT5616_PWR_VREF1 | RT5616_PWR_MB |
+ RT5616_PWR_BG | RT5616_PWR_VREF2,
+ RT5616_PWR_VREF1 | RT5616_PWR_MB |
+ RT5616_PWR_BG | RT5616_PWR_VREF2);
+ mdelay(10);
+ regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2,
+ RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+ ret = regmap_register_patch(rt5616->regmap, init_list,
+ ARRAY_SIZE(init_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+ RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V);
+
+ return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616,
+ rt5616_dai, ARRAY_SIZE(rt5616_dai));
+
+}
+
+static int rt5616_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+static void rt5616_i2c_shutdown(struct i2c_client *client)
+{
+ struct rt5616_priv *rt5616 = i2c_get_clientdata(client);
+
+ regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8);
+ regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8);
+
+}
+
+static struct i2c_driver rt5616_i2c_driver = {
+ .driver = {
+ .name = "rt5616",
+ .of_match_table = of_match_ptr(rt5616_of_match),
+ },
+ .probe = rt5616_i2c_probe,
+ .remove = rt5616_i2c_remove,
+ .shutdown = rt5616_i2c_shutdown,
+ .id_table = rt5616_i2c_id,
+};
+module_i2c_driver(rt5616_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5616 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5616.h b/sound/soc/codecs/rt5616.h
new file mode 100644
index 000000000000..f88cdddbc34a
--- /dev/null
+++ b/sound/soc/codecs/rt5616.h
@@ -0,0 +1,1819 @@
+/*
+ * rt5616.h -- RT5616 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.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 __RT5616_H__
+#define __RT5616_H__
+
+/* Info */
+#define RT5616_RESET 0x00
+#define RT5616_VERSION_ID 0xfd
+#define RT5616_VENDOR_ID 0xfe
+#define RT5616_DEVICE_ID 0xff
+/* I/O - Output */
+#define RT5616_HP_VOL 0x02
+#define RT5616_LOUT_CTRL1 0x03
+#define RT5616_LOUT_CTRL2 0x05
+/* I/O - Input */
+#define RT5616_IN1_IN2 0x0d
+#define RT5616_INL1_INR1_VOL 0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5616_DAC1_DIG_VOL 0x19
+#define RT5616_ADC_DIG_VOL 0x1c
+#define RT5616_ADC_BST_VOL 0x1e
+/* Mixer - D-D */
+#define RT5616_STO1_ADC_MIXER 0x27
+#define RT5616_AD_DA_MIXER 0x29
+#define RT5616_STO_DAC_MIXER 0x2a
+
+/* Mixer - ADC */
+#define RT5616_REC_L1_MIXER 0x3b
+#define RT5616_REC_L2_MIXER 0x3c
+#define RT5616_REC_R1_MIXER 0x3d
+#define RT5616_REC_R2_MIXER 0x3e
+/* Mixer - DAC */
+#define RT5616_HPO_MIXER 0x45
+#define RT5616_OUT_L1_MIXER 0x4d
+#define RT5616_OUT_L2_MIXER 0x4e
+#define RT5616_OUT_L3_MIXER 0x4f
+#define RT5616_OUT_R1_MIXER 0x50
+#define RT5616_OUT_R2_MIXER 0x51
+#define RT5616_OUT_R3_MIXER 0x52
+#define RT5616_LOUT_MIXER 0x53
+/* Power */
+#define RT5616_PWR_DIG1 0x61
+#define RT5616_PWR_DIG2 0x62
+#define RT5616_PWR_ANLG1 0x63
+#define RT5616_PWR_ANLG2 0x64
+#define RT5616_PWR_MIXER 0x65
+#define RT5616_PWR_VOL 0x66
+/* Private Register Control */
+#define RT5616_PRIV_INDEX 0x6a
+#define RT5616_PRIV_DATA 0x6c
+/* Format - ADC/DAC */
+#define RT5616_I2S1_SDP 0x70
+#define RT5616_ADDA_CLK1 0x73
+#define RT5616_ADDA_CLK2 0x74
+
+/* Function - Analog */
+#define RT5616_GLB_CLK 0x80
+#define RT5616_PLL_CTRL1 0x81
+#define RT5616_PLL_CTRL2 0x82
+#define RT5616_HP_OVCD 0x8b
+#define RT5616_DEPOP_M1 0x8e
+#define RT5616_DEPOP_M2 0x8f
+#define RT5616_DEPOP_M3 0x90
+#define RT5616_CHARGE_PUMP 0x91
+#define RT5616_PV_DET_SPK_G 0x92
+#define RT5616_MICBIAS 0x93
+#define RT5616_A_JD_CTL1 0x94
+#define RT5616_A_JD_CTL2 0x95
+/* Function - Digital */
+#define RT5616_EQ_CTRL1 0xb0
+#define RT5616_EQ_CTRL2 0xb1
+#define RT5616_WIND_FILTER 0xb2
+#define RT5616_DRC_AGC_1 0xb4
+#define RT5616_DRC_AGC_2 0xb5
+#define RT5616_DRC_AGC_3 0xb6
+#define RT5616_SVOL_ZC 0xb7
+#define RT5616_JD_CTRL1 0xbb
+#define RT5616_JD_CTRL2 0xbc
+#define RT5616_IRQ_CTRL1 0xbd
+#define RT5616_IRQ_CTRL2 0xbe
+#define RT5616_INT_IRQ_ST 0xbf
+#define RT5616_GPIO_CTRL1 0xc0
+#define RT5616_GPIO_CTRL2 0xc1
+#define RT5616_GPIO_CTRL3 0xc2
+#define RT5616_PGM_REG_ARR1 0xc8
+#define RT5616_PGM_REG_ARR2 0xc9
+#define RT5616_PGM_REG_ARR3 0xca
+#define RT5616_PGM_REG_ARR4 0xcb
+#define RT5616_PGM_REG_ARR5 0xcc
+#define RT5616_SCB_FUNC 0xcd
+#define RT5616_SCB_CTRL 0xce
+#define RT5616_BASE_BACK 0xcf
+#define RT5616_MP3_PLUS1 0xd0
+#define RT5616_MP3_PLUS2 0xd1
+#define RT5616_ADJ_HPF_CTRL1 0xd3
+#define RT5616_ADJ_HPF_CTRL2 0xd4
+#define RT5616_HP_CALIB_AMP_DET 0xd6
+#define RT5616_HP_CALIB2 0xd7
+#define RT5616_SV_ZCD1 0xd9
+#define RT5616_SV_ZCD2 0xda
+#define RT5616_D_MISC 0xfa
+/* Dummy Register */
+#define RT5616_DUMMY2 0xfb
+#define RT5616_DUMMY3 0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5616_BIAS_CUR1 0x12
+#define RT5616_BIAS_CUR3 0x14
+#define RT5616_CLSD_INT_REG1 0x1c
+#define RT5616_MAMP_INT_REG2 0x37
+#define RT5616_CHOP_DAC_ADC 0x3d
+#define RT5616_3D_SPK 0x63
+#define RT5616_WND_1 0x6c
+#define RT5616_WND_2 0x6d
+#define RT5616_WND_3 0x6e
+#define RT5616_WND_4 0x6f
+#define RT5616_WND_5 0x70
+#define RT5616_WND_8 0x73
+#define RT5616_DIP_SPK_INF 0x75
+#define RT5616_HP_DCC_INT1 0x77
+#define RT5616_EQ_BW_LOP 0xa0
+#define RT5616_EQ_GN_LOP 0xa1
+#define RT5616_EQ_FC_BP1 0xa2
+#define RT5616_EQ_BW_BP1 0xa3
+#define RT5616_EQ_GN_BP1 0xa4
+#define RT5616_EQ_FC_BP2 0xa5
+#define RT5616_EQ_BW_BP2 0xa6
+#define RT5616_EQ_GN_BP2 0xa7
+#define RT5616_EQ_FC_BP3 0xa8
+#define RT5616_EQ_BW_BP3 0xa9
+#define RT5616_EQ_GN_BP3 0xaa
+#define RT5616_EQ_FC_BP4 0xab
+#define RT5616_EQ_BW_BP4 0xac
+#define RT5616_EQ_GN_BP4 0xad
+#define RT5616_EQ_FC_HIP1 0xae
+#define RT5616_EQ_GN_HIP1 0xaf
+#define RT5616_EQ_FC_HIP2 0xb0
+#define RT5616_EQ_BW_HIP2 0xb1
+#define RT5616_EQ_GN_HIP2 0xb2
+#define RT5616_EQ_PRE_VOL 0xb3
+#define RT5616_EQ_PST_VOL 0xb4
+
+
+/* global definition */
+#define RT5616_L_MUTE (0x1 << 15)
+#define RT5616_L_MUTE_SFT 15
+#define RT5616_VOL_L_MUTE (0x1 << 14)
+#define RT5616_VOL_L_SFT 14
+#define RT5616_R_MUTE (0x1 << 7)
+#define RT5616_R_MUTE_SFT 7
+#define RT5616_VOL_R_MUTE (0x1 << 6)
+#define RT5616_VOL_R_SFT 6
+#define RT5616_L_VOL_MASK (0x3f << 8)
+#define RT5616_L_VOL_SFT 8
+#define RT5616_R_VOL_MASK (0x3f)
+#define RT5616_R_VOL_SFT 0
+
+/* LOUT Control 2(0x05) */
+#define RT5616_EN_DFO (0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5616_BST_MASK1 (0xf<<12)
+#define RT5616_BST_SFT1 12
+#define RT5616_BST_MASK2 (0xf<<8)
+#define RT5616_BST_SFT2 8
+#define RT5616_IN_DF1 (0x1 << 7)
+#define RT5616_IN_SFT1 7
+#define RT5616_IN_DF2 (0x1 << 6)
+#define RT5616_IN_SFT2 6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+#define RT5616_INL_VOL_MASK (0x1f << 8)
+#define RT5616_INL_VOL_SFT 8
+#define RT5616_INR_SEL_MASK (0x1 << 7)
+#define RT5616_INR_SEL_SFT 7
+#define RT5616_INR_SEL_IN4N (0x0 << 7)
+#define RT5616_INR_SEL_MONON (0x1 << 7)
+#define RT5616_INR_VOL_MASK (0x1f)
+#define RT5616_INR_VOL_SFT 0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5616_DAC_L1_VOL_MASK (0xff << 8)
+#define RT5616_DAC_L1_VOL_SFT 8
+#define RT5616_DAC_R1_VOL_MASK (0xff)
+#define RT5616_DAC_R1_VOL_SFT 0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5616_DAC_L2_VOL_MASK (0xff << 8)
+#define RT5616_DAC_L2_VOL_SFT 8
+#define RT5616_DAC_R2_VOL_MASK (0xff)
+#define RT5616_DAC_R2_VOL_SFT 0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5616_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5616_ADC_L_VOL_SFT 8
+#define RT5616_ADC_R_VOL_MASK (0x7f)
+#define RT5616_ADC_R_VOL_SFT 0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5616_M_MONO_ADC_L (0x1 << 15)
+#define RT5616_M_MONO_ADC_L_SFT 15
+#define RT5616_MONO_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5616_MONO_ADC_L_VOL_SFT 8
+#define RT5616_M_MONO_ADC_R (0x1 << 7)
+#define RT5616_M_MONO_ADC_R_SFT 7
+#define RT5616_MONO_ADC_R_VOL_MASK (0x7f)
+#define RT5616_MONO_ADC_R_VOL_SFT 0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5616_ADC_L_BST_MASK (0x3 << 14)
+#define RT5616_ADC_L_BST_SFT 14
+#define RT5616_ADC_R_BST_MASK (0x3 << 12)
+#define RT5616_ADC_R_BST_SFT 12
+#define RT5616_ADC_COMP_MASK (0x3 << 10)
+#define RT5616_ADC_COMP_SFT 10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5616_M_STO1_ADC_L1 (0x1 << 14)
+#define RT5616_M_STO1_ADC_L1_SFT 14
+#define RT5616_M_STO1_ADC_R1 (0x1 << 6)
+#define RT5616_M_STO1_ADC_R1_SFT 6
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5616_M_ADCMIX_L (0x1 << 15)
+#define RT5616_M_ADCMIX_L_SFT 15
+#define RT5616_M_IF1_DAC_L (0x1 << 14)
+#define RT5616_M_IF1_DAC_L_SFT 14
+#define RT5616_M_ADCMIX_R (0x1 << 7)
+#define RT5616_M_ADCMIX_R_SFT 7
+#define RT5616_M_IF1_DAC_R (0x1 << 6)
+#define RT5616_M_IF1_DAC_R_SFT 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5616_M_DAC_L1_MIXL (0x1 << 14)
+#define RT5616_M_DAC_L1_MIXL_SFT 14
+#define RT5616_DAC_L1_STO_L_VOL_MASK (0x1 << 13)
+#define RT5616_DAC_L1_STO_L_VOL_SFT 13
+#define RT5616_M_DAC_R1_MIXL (0x1 << 9)
+#define RT5616_M_DAC_R1_MIXL_SFT 9
+#define RT5616_DAC_R1_STO_L_VOL_MASK (0x1 << 8)
+#define RT5616_DAC_R1_STO_L_VOL_SFT 8
+#define RT5616_M_DAC_R1_MIXR (0x1 << 6)
+#define RT5616_M_DAC_R1_MIXR_SFT 6
+#define RT5616_DAC_R1_STO_R_VOL_MASK (0x1 << 5)
+#define RT5616_DAC_R1_STO_R_VOL_SFT 5
+#define RT5616_M_DAC_L1_MIXR (0x1 << 1)
+#define RT5616_M_DAC_L1_MIXR_SFT 1
+#define RT5616_DAC_L1_STO_R_VOL_MASK (0x1)
+#define RT5616_DAC_L1_STO_R_VOL_SFT 0
+
+/* DD Mixer Control (0x2b) */
+#define RT5616_M_STO_DD_L1 (0x1 << 14)
+#define RT5616_M_STO_DD_L1_SFT 14
+#define RT5616_STO_DD_L1_VOL_MASK (0x1 << 13)
+#define RT5616_DAC_DD_L1_VOL_SFT 13
+#define RT5616_M_STO_DD_L2 (0x1 << 12)
+#define RT5616_M_STO_DD_L2_SFT 12
+#define RT5616_STO_DD_L2_VOL_MASK (0x1 << 11)
+#define RT5616_STO_DD_L2_VOL_SFT 11
+#define RT5616_M_STO_DD_R2_L (0x1 << 10)
+#define RT5616_M_STO_DD_R2_L_SFT 10
+#define RT5616_STO_DD_R2_L_VOL_MASK (0x1 << 9)
+#define RT5616_STO_DD_R2_L_VOL_SFT 9
+#define RT5616_M_STO_DD_R1 (0x1 << 6)
+#define RT5616_M_STO_DD_R1_SFT 6
+#define RT5616_STO_DD_R1_VOL_MASK (0x1 << 5)
+#define RT5616_STO_DD_R1_VOL_SFT 5
+#define RT5616_M_STO_DD_R2 (0x1 << 4)
+#define RT5616_M_STO_DD_R2_SFT 4
+#define RT5616_STO_DD_R2_VOL_MASK (0x1 << 3)
+#define RT5616_STO_DD_R2_VOL_SFT 3
+#define RT5616_M_STO_DD_L2_R (0x1 << 2)
+#define RT5616_M_STO_DD_L2_R_SFT 2
+#define RT5616_STO_DD_L2_R_VOL_MASK (0x1 << 1)
+#define RT5616_STO_DD_L2_R_VOL_SFT 1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5616_M_STO_L_DAC_L (0x1 << 15)
+#define RT5616_M_STO_L_DAC_L_SFT 15
+#define RT5616_STO_L_DAC_L_VOL_MASK (0x1 << 14)
+#define RT5616_STO_L_DAC_L_VOL_SFT 14
+#define RT5616_M_DAC_L2_DAC_L (0x1 << 13)
+#define RT5616_M_DAC_L2_DAC_L_SFT 13
+#define RT5616_DAC_L2_DAC_L_VOL_MASK (0x1 << 12)
+#define RT5616_DAC_L2_DAC_L_VOL_SFT 12
+#define RT5616_M_STO_R_DAC_R (0x1 << 11)
+#define RT5616_M_STO_R_DAC_R_SFT 11
+#define RT5616_STO_R_DAC_R_VOL_MASK (0x1 << 10)
+#define RT5616_STO_R_DAC_R_VOL_SFT 10
+#define RT5616_M_DAC_R2_DAC_R (0x1 << 9)
+#define RT5616_M_DAC_R2_DAC_R_SFT 9
+#define RT5616_DAC_R2_DAC_R_VOL_MASK (0x1 << 8)
+#define RT5616_DAC_R2_DAC_R_VOL_SFT 8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5616_RXDP_SRC_MASK (0x1 << 15)
+#define RT5616_RXDP_SRC_SFT 15
+#define RT5616_RXDP_SRC_NOR (0x0 << 15)
+#define RT5616_RXDP_SRC_DIV3 (0x1 << 15)
+#define RT5616_TXDP_SRC_MASK (0x1 << 14)
+#define RT5616_TXDP_SRC_SFT 14
+#define RT5616_TXDP_SRC_NOR (0x0 << 14)
+#define RT5616_TXDP_SRC_DIV3 (0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5616_DAC_L2_SEL_MASK (0x3 << 14)
+#define RT5616_DAC_L2_SEL_SFT 14
+#define RT5616_DAC_L2_SEL_IF2 (0x0 << 14)
+#define RT5616_DAC_L2_SEL_IF3 (0x1 << 14)
+#define RT5616_DAC_L2_SEL_TXDC (0x2 << 14)
+#define RT5616_DAC_L2_SEL_BASS (0x3 << 14)
+#define RT5616_DAC_R2_SEL_MASK (0x3 << 12)
+#define RT5616_DAC_R2_SEL_SFT 12
+#define RT5616_DAC_R2_SEL_IF2 (0x0 << 12)
+#define RT5616_DAC_R2_SEL_IF3 (0x1 << 12)
+#define RT5616_DAC_R2_SEL_TXDC (0x2 << 12)
+#define RT5616_IF2_ADC_L_SEL_MASK (0x1 << 11)
+#define RT5616_IF2_ADC_L_SEL_SFT 11
+#define RT5616_IF2_ADC_L_SEL_TXDP (0x0 << 11)
+#define RT5616_IF2_ADC_L_SEL_PASS (0x1 << 11)
+#define RT5616_IF2_ADC_R_SEL_MASK (0x1 << 10)
+#define RT5616_IF2_ADC_R_SEL_SFT 10
+#define RT5616_IF2_ADC_R_SEL_TXDP (0x0 << 10)
+#define RT5616_IF2_ADC_R_SEL_PASS (0x1 << 10)
+#define RT5616_RXDC_SEL_MASK (0x3 << 8)
+#define RT5616_RXDC_SEL_SFT 8
+#define RT5616_RXDC_SEL_NOR (0x0 << 8)
+#define RT5616_RXDC_SEL_L2R (0x1 << 8)
+#define RT5616_RXDC_SEL_R2L (0x2 << 8)
+#define RT5616_RXDC_SEL_SWAP (0x3 << 8)
+#define RT5616_RXDP_SEL_MASK (0x3 << 6)
+#define RT5616_RXDP_SEL_SFT 6
+#define RT5616_RXDP_SEL_NOR (0x0 << 6)
+#define RT5616_RXDP_SEL_L2R (0x1 << 6)
+#define RT5616_RXDP_SEL_R2L (0x2 << 6)
+#define RT5616_RXDP_SEL_SWAP (0x3 << 6)
+#define RT5616_TXDC_SEL_MASK (0x3 << 4)
+#define RT5616_TXDC_SEL_SFT 4
+#define RT5616_TXDC_SEL_NOR (0x0 << 4)
+#define RT5616_TXDC_SEL_L2R (0x1 << 4)
+#define RT5616_TXDC_SEL_R2L (0x2 << 4)
+#define RT5616_TXDC_SEL_SWAP (0x3 << 4)
+#define RT5616_TXDP_SEL_MASK (0x3 << 2)
+#define RT5616_TXDP_SEL_SFT 2
+#define RT5616_TXDP_SEL_NOR (0x0 << 2)
+#define RT5616_TXDP_SEL_L2R (0x1 << 2)
+#define RT5616_TXDP_SEL_R2L (0x2 << 2)
+#define RT5616_TRXDP_SEL_SWAP (0x3 << 2)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5616_G_LN_L2_RM_L_MASK (0x7 << 13)
+#define RT5616_G_IN_L2_RM_L_SFT 13
+#define RT5616_G_LN_L1_RM_L_MASK (0x7 << 10)
+#define RT5616_G_IN_L1_RM_L_SFT 10
+#define RT5616_G_BST3_RM_L_MASK (0x7 << 4)
+#define RT5616_G_BST3_RM_L_SFT 4
+#define RT5616_G_BST2_RM_L_MASK (0x7 << 1)
+#define RT5616_G_BST2_RM_L_SFT 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5616_G_BST1_RM_L_MASK (0x7 << 13)
+#define RT5616_G_BST1_RM_L_SFT 13
+#define RT5616_G_OM_L_RM_L_MASK (0x7 << 10)
+#define RT5616_G_OM_L_RM_L_SFT 10
+#define RT5616_M_IN2_L_RM_L (0x1 << 6)
+#define RT5616_M_IN2_L_RM_L_SFT 6
+#define RT5616_M_IN1_L_RM_L (0x1 << 5)
+#define RT5616_M_IN1_L_RM_L_SFT 5
+#define RT5616_M_BST3_RM_L (0x1 << 3)
+#define RT5616_M_BST3_RM_L_SFT 3
+#define RT5616_M_BST2_RM_L (0x1 << 2)
+#define RT5616_M_BST2_RM_L_SFT 2
+#define RT5616_M_BST1_RM_L (0x1 << 1)
+#define RT5616_M_BST1_RM_L_SFT 1
+#define RT5616_M_OM_L_RM_L (0x1)
+#define RT5616_M_OM_L_RM_L_SFT 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5616_G_IN2_R_RM_R_MASK (0x7 << 13)
+#define RT5616_G_IN2_R_RM_R_SFT 13
+#define RT5616_G_IN1_R_RM_R_MASK (0x7 << 10)
+#define RT5616_G_IN1_R_RM_R_SFT 10
+#define RT5616_G_BST3_RM_R_MASK (0x7 << 4)
+#define RT5616_G_BST3_RM_R_SFT 4
+#define RT5616_G_BST2_RM_R_MASK (0x7 << 1)
+#define RT5616_G_BST2_RM_R_SFT 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5616_G_BST1_RM_R_MASK (0x7 << 13)
+#define RT5616_G_BST1_RM_R_SFT 13
+#define RT5616_G_OM_R_RM_R_MASK (0x7 << 10)
+#define RT5616_G_OM_R_RM_R_SFT 10
+#define RT5616_M_IN2_R_RM_R (0x1 << 6)
+#define RT5616_M_IN2_R_RM_R_SFT 6
+#define RT5616_M_IN1_R_RM_R (0x1 << 5)
+#define RT5616_M_IN1_R_RM_R_SFT 5
+#define RT5616_M_BST3_RM_R (0x1 << 3)
+#define RT5616_M_BST3_RM_R_SFT 3
+#define RT5616_M_BST2_RM_R (0x1 << 2)
+#define RT5616_M_BST2_RM_R_SFT 2
+#define RT5616_M_BST1_RM_R (0x1 << 1)
+#define RT5616_M_BST1_RM_R_SFT 1
+#define RT5616_M_OM_R_RM_R (0x1)
+#define RT5616_M_OM_R_RM_R_SFT 0
+
+/* HPMIX Control (0x45) */
+#define RT5616_M_DAC1_HM (0x1 << 14)
+#define RT5616_M_DAC1_HM_SFT 14
+#define RT5616_M_HPVOL_HM (0x1 << 13)
+#define RT5616_M_HPVOL_HM_SFT 13
+#define RT5616_G_HPOMIX_MASK (0x1 << 12)
+#define RT5616_G_HPOMIX_SFT 12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5616_G_RM_L_SM_L_MASK (0x3 << 14)
+#define RT5616_G_RM_L_SM_L_SFT 14
+#define RT5616_G_IN_L_SM_L_MASK (0x3 << 12)
+#define RT5616_G_IN_L_SM_L_SFT 12
+#define RT5616_G_DAC_L1_SM_L_MASK (0x3 << 10)
+#define RT5616_G_DAC_L1_SM_L_SFT 10
+#define RT5616_G_DAC_L2_SM_L_MASK (0x3 << 8)
+#define RT5616_G_DAC_L2_SM_L_SFT 8
+#define RT5616_G_OM_L_SM_L_MASK (0x3 << 6)
+#define RT5616_G_OM_L_SM_L_SFT 6
+#define RT5616_M_RM_L_SM_L (0x1 << 5)
+#define RT5616_M_RM_L_SM_L_SFT 5
+#define RT5616_M_IN_L_SM_L (0x1 << 4)
+#define RT5616_M_IN_L_SM_L_SFT 4
+#define RT5616_M_DAC_L1_SM_L (0x1 << 3)
+#define RT5616_M_DAC_L1_SM_L_SFT 3
+#define RT5616_M_DAC_L2_SM_L (0x1 << 2)
+#define RT5616_M_DAC_L2_SM_L_SFT 2
+#define RT5616_M_OM_L_SM_L (0x1 << 1)
+#define RT5616_M_OM_L_SM_L_SFT 1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5616_G_RM_R_SM_R_MASK (0x3 << 14)
+#define RT5616_G_RM_R_SM_R_SFT 14
+#define RT5616_G_IN_R_SM_R_MASK (0x3 << 12)
+#define RT5616_G_IN_R_SM_R_SFT 12
+#define RT5616_G_DAC_R1_SM_R_MASK (0x3 << 10)
+#define RT5616_G_DAC_R1_SM_R_SFT 10
+#define RT5616_G_DAC_R2_SM_R_MASK (0x3 << 8)
+#define RT5616_G_DAC_R2_SM_R_SFT 8
+#define RT5616_G_OM_R_SM_R_MASK (0x3 << 6)
+#define RT5616_G_OM_R_SM_R_SFT 6
+#define RT5616_M_RM_R_SM_R (0x1 << 5)
+#define RT5616_M_RM_R_SM_R_SFT 5
+#define RT5616_M_IN_R_SM_R (0x1 << 4)
+#define RT5616_M_IN_R_SM_R_SFT 4
+#define RT5616_M_DAC_R1_SM_R (0x1 << 3)
+#define RT5616_M_DAC_R1_SM_R_SFT 3
+#define RT5616_M_DAC_R2_SM_R (0x1 << 2)
+#define RT5616_M_DAC_R2_SM_R_SFT 2
+#define RT5616_M_OM_R_SM_R (0x1 << 1)
+#define RT5616_M_OM_R_SM_R_SFT 1
+
+/* SPOLMIX Control (0x48) */
+#define RT5616_M_DAC_R1_SPM_L (0x1 << 15)
+#define RT5616_M_DAC_R1_SPM_L_SFT 15
+#define RT5616_M_DAC_L1_SPM_L (0x1 << 14)
+#define RT5616_M_DAC_L1_SPM_L_SFT 14
+#define RT5616_M_SV_R_SPM_L (0x1 << 13)
+#define RT5616_M_SV_R_SPM_L_SFT 13
+#define RT5616_M_SV_L_SPM_L (0x1 << 12)
+#define RT5616_M_SV_L_SPM_L_SFT 12
+#define RT5616_M_BST1_SPM_L (0x1 << 11)
+#define RT5616_M_BST1_SPM_L_SFT 11
+
+/* SPORMIX Control (0x49) */
+#define RT5616_M_DAC_R1_SPM_R (0x1 << 13)
+#define RT5616_M_DAC_R1_SPM_R_SFT 13
+#define RT5616_M_SV_R_SPM_R (0x1 << 12)
+#define RT5616_M_SV_R_SPM_R_SFT 12
+#define RT5616_M_BST1_SPM_R (0x1 << 11)
+#define RT5616_M_BST1_SPM_R_SFT 11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5616_SPO_CLSD_RATIO_MASK (0x7)
+#define RT5616_SPO_CLSD_RATIO_SFT 0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5616_M_DAC_R2_MM (0x1 << 15)
+#define RT5616_M_DAC_R2_MM_SFT 15
+#define RT5616_M_DAC_L2_MM (0x1 << 14)
+#define RT5616_M_DAC_L2_MM_SFT 14
+#define RT5616_M_OV_R_MM (0x1 << 13)
+#define RT5616_M_OV_R_MM_SFT 13
+#define RT5616_M_OV_L_MM (0x1 << 12)
+#define RT5616_M_OV_L_MM_SFT 12
+#define RT5616_M_BST1_MM (0x1 << 11)
+#define RT5616_M_BST1_MM_SFT 11
+#define RT5616_G_MONOMIX_MASK (0x1 << 10)
+#define RT5616_G_MONOMIX_SFT 10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5616_G_BST2_OM_L_MASK (0x7 << 10)
+#define RT5616_G_BST2_OM_L_SFT 10
+#define RT5616_G_BST1_OM_L_MASK (0x7 << 7)
+#define RT5616_G_BST1_OM_L_SFT 7
+#define RT5616_G_IN1_L_OM_L_MASK (0x7 << 4)
+#define RT5616_G_IN1_L_OM_L_SFT 4
+#define RT5616_G_RM_L_OM_L_MASK (0x7 << 1)
+#define RT5616_G_RM_L_OM_L_SFT 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5616_G_DAC_L1_OM_L_MASK (0x7 << 7)
+#define RT5616_G_DAC_L1_OM_L_SFT 7
+#define RT5616_G_IN2_L_OM_L_MASK (0x7 << 4)
+#define RT5616_G_IN2_L_OM_L_SFT 4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5616_M_IN2_L_OM_L (0x1 << 9)
+#define RT5616_M_IN2_L_OM_L_SFT 9
+#define RT5616_M_BST2_OM_L (0x1 << 6)
+#define RT5616_M_BST2_OM_L_SFT 6
+#define RT5616_M_BST1_OM_L (0x1 << 5)
+#define RT5616_M_BST1_OM_L_SFT 5
+#define RT5616_M_IN1_L_OM_L (0x1 << 4)
+#define RT5616_M_IN1_L_OM_L_SFT 4
+#define RT5616_M_RM_L_OM_L (0x1 << 3)
+#define RT5616_M_RM_L_OM_L_SFT 3
+#define RT5616_M_DAC_L1_OM_L (0x1)
+#define RT5616_M_DAC_L1_OM_L_SFT 0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5616_G_BST2_OM_R_MASK (0x7 << 10)
+#define RT5616_G_BST2_OM_R_SFT 10
+#define RT5616_G_BST1_OM_R_MASK (0x7 << 7)
+#define RT5616_G_BST1_OM_R_SFT 7
+#define RT5616_G_IN1_R_OM_R_MASK (0x7 << 4)
+#define RT5616_G_IN1_R_OM_R_SFT 4
+#define RT5616_G_RM_R_OM_R_MASK (0x7 << 1)
+#define RT5616_G_RM_R_OM_R_SFT 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5616_G_DAC_R1_OM_R_MASK (0x7 << 7)
+#define RT5616_G_DAC_R1_OM_R_SFT 7
+#define RT5616_G_IN2_R_OM_R_MASK (0x7 << 4)
+#define RT5616_G_IN2_R_OM_R_SFT 4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5616_M_IN2_R_OM_R (0x1 << 9)
+#define RT5616_M_IN2_R_OM_R_SFT 9
+#define RT5616_M_BST2_OM_R (0x1 << 6)
+#define RT5616_M_BST2_OM_R_SFT 6
+#define RT5616_M_BST1_OM_R (0x1 << 5)
+#define RT5616_M_BST1_OM_R_SFT 5
+#define RT5616_M_IN1_R_OM_R (0x1 << 4)
+#define RT5616_M_IN1_R_OM_R_SFT 4
+#define RT5616_M_RM_R_OM_R (0x1 << 3)
+#define RT5616_M_RM_R_OM_R_SFT 3
+#define RT5616_M_DAC_R1_OM_R (0x1)
+#define RT5616_M_DAC_R1_OM_R_SFT 0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5616_M_DAC_L1_LM (0x1 << 15)
+#define RT5616_M_DAC_L1_LM_SFT 15
+#define RT5616_M_DAC_R1_LM (0x1 << 14)
+#define RT5616_M_DAC_R1_LM_SFT 14
+#define RT5616_M_OV_L_LM (0x1 << 13)
+#define RT5616_M_OV_L_LM_SFT 13
+#define RT5616_M_OV_R_LM (0x1 << 12)
+#define RT5616_M_OV_R_LM_SFT 12
+#define RT5616_G_LOUTMIX_MASK (0x1 << 11)
+#define RT5616_G_LOUTMIX_SFT 11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5616_PWR_I2S1 (0x1 << 15)
+#define RT5616_PWR_I2S1_BIT 15
+#define RT5616_PWR_I2S2 (0x1 << 14)
+#define RT5616_PWR_I2S2_BIT 14
+#define RT5616_PWR_DAC_L1 (0x1 << 12)
+#define RT5616_PWR_DAC_L1_BIT 12
+#define RT5616_PWR_DAC_R1 (0x1 << 11)
+#define RT5616_PWR_DAC_R1_BIT 11
+#define RT5616_PWR_ADC_L (0x1 << 2)
+#define RT5616_PWR_ADC_L_BIT 2
+#define RT5616_PWR_ADC_R (0x1 << 1)
+#define RT5616_PWR_ADC_R_BIT 1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5616_PWR_ADC_STO1_F (0x1 << 15)
+#define RT5616_PWR_ADC_STO1_F_BIT 15
+#define RT5616_PWR_DAC_STO1_F (0x1 << 11)
+#define RT5616_PWR_DAC_STO1_F_BIT 11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5616_PWR_VREF1 (0x1 << 15)
+#define RT5616_PWR_VREF1_BIT 15
+#define RT5616_PWR_FV1 (0x1 << 14)
+#define RT5616_PWR_FV1_BIT 14
+#define RT5616_PWR_MB (0x1 << 13)
+#define RT5616_PWR_MB_BIT 13
+#define RT5616_PWR_LM (0x1 << 12)
+#define RT5616_PWR_LM_BIT 12
+#define RT5616_PWR_BG (0x1 << 11)
+#define RT5616_PWR_BG_BIT 11
+#define RT5616_PWR_HP_L (0x1 << 7)
+#define RT5616_PWR_HP_L_BIT 7
+#define RT5616_PWR_HP_R (0x1 << 6)
+#define RT5616_PWR_HP_R_BIT 6
+#define RT5616_PWR_HA (0x1 << 5)
+#define RT5616_PWR_HA_BIT 5
+#define RT5616_PWR_VREF2 (0x1 << 4)
+#define RT5616_PWR_VREF2_BIT 4
+#define RT5616_PWR_FV2 (0x1 << 3)
+#define RT5616_PWR_FV2_BIT 3
+#define RT5616_PWR_LDO (0x1 << 2)
+#define RT5616_PWR_LDO_BIT 2
+#define RT5616_PWR_LDO_DVO_MASK (0x3)
+#define RT5616_PWR_LDO_DVO_1_0V 0
+#define RT5616_PWR_LDO_DVO_1_1V 1
+#define RT5616_PWR_LDO_DVO_1_2V 2
+#define RT5616_PWR_LDO_DVO_1_3V 3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5616_PWR_BST1 (0x1 << 15)
+#define RT5616_PWR_BST1_BIT 15
+#define RT5616_PWR_BST2 (0x1 << 14)
+#define RT5616_PWR_BST2_BIT 14
+#define RT5616_PWR_MB1 (0x1 << 11)
+#define RT5616_PWR_MB1_BIT 11
+#define RT5616_PWR_PLL (0x1 << 9)
+#define RT5616_PWR_PLL_BIT 9
+#define RT5616_PWR_BST1_OP2 (0x1 << 5)
+#define RT5616_PWR_BST1_OP2_BIT 5
+#define RT5616_PWR_BST2_OP2 (0x1 << 4)
+#define RT5616_PWR_BST2_OP2_BIT 4
+#define RT5616_PWR_BST3_OP2 (0x1 << 3)
+#define RT5616_PWR_BST3_OP2_BIT 3
+#define RT5616_PWR_JD_M (0x1 << 2)
+#define RT5616_PWM_JD_M_BIT 2
+#define RT5616_PWR_JD2 (0x1 << 1)
+#define RT5616_PWM_JD2_BIT 1
+#define RT5616_PWR_JD3 (0x1)
+#define RT5616_PWM_JD3_BIT 0
+
+/* Power Management for Mixer (0x65) */
+#define RT5616_PWR_OM_L (0x1 << 15)
+#define RT5616_PWR_OM_L_BIT 15
+#define RT5616_PWR_OM_R (0x1 << 14)
+#define RT5616_PWR_OM_R_BIT 14
+#define RT5616_PWR_RM_L (0x1 << 11)
+#define RT5616_PWR_RM_L_BIT 11
+#define RT5616_PWR_RM_R (0x1 << 10)
+#define RT5616_PWR_RM_R_BIT 10
+
+/* Power Management for Volume (0x66) */
+#define RT5616_PWR_OV_L (0x1 << 13)
+#define RT5616_PWR_OV_L_BIT 13
+#define RT5616_PWR_OV_R (0x1 << 12)
+#define RT5616_PWR_OV_R_BIT 12
+#define RT5616_PWR_HV_L (0x1 << 11)
+#define RT5616_PWR_HV_L_BIT 11
+#define RT5616_PWR_HV_R (0x1 << 10)
+#define RT5616_PWR_HV_R_BIT 10
+#define RT5616_PWR_IN1_L (0x1 << 9)
+#define RT5616_PWR_IN1_L_BIT 9
+#define RT5616_PWR_IN1_R (0x1 << 8)
+#define RT5616_PWR_IN1_R_BIT 8
+#define RT5616_PWR_IN2_L (0x1 << 7)
+#define RT5616_PWR_IN2_L_BIT 7
+#define RT5616_PWR_IN2_R (0x1 << 6)
+#define RT5616_PWR_IN2_R_BIT 6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5616_I2S_MS_MASK (0x1 << 15)
+#define RT5616_I2S_MS_SFT 15
+#define RT5616_I2S_MS_M (0x0 << 15)
+#define RT5616_I2S_MS_S (0x1 << 15)
+#define RT5616_I2S_O_CP_MASK (0x3 << 10)
+#define RT5616_I2S_O_CP_SFT 10
+#define RT5616_I2S_O_CP_OFF (0x0 << 10)
+#define RT5616_I2S_O_CP_U_LAW (0x1 << 10)
+#define RT5616_I2S_O_CP_A_LAW (0x2 << 10)
+#define RT5616_I2S_I_CP_MASK (0x3 << 8)
+#define RT5616_I2S_I_CP_SFT 8
+#define RT5616_I2S_I_CP_OFF (0x0 << 8)
+#define RT5616_I2S_I_CP_U_LAW (0x1 << 8)
+#define RT5616_I2S_I_CP_A_LAW (0x2 << 8)
+#define RT5616_I2S_BP_MASK (0x1 << 7)
+#define RT5616_I2S_BP_SFT 7
+#define RT5616_I2S_BP_NOR (0x0 << 7)
+#define RT5616_I2S_BP_INV (0x1 << 7)
+#define RT5616_I2S_DL_MASK (0x3 << 2)
+#define RT5616_I2S_DL_SFT 2
+#define RT5616_I2S_DL_16 (0x0 << 2)
+#define RT5616_I2S_DL_20 (0x1 << 2)
+#define RT5616_I2S_DL_24 (0x2 << 2)
+#define RT5616_I2S_DL_8 (0x3 << 2)
+#define RT5616_I2S_DF_MASK (0x3)
+#define RT5616_I2S_DF_SFT 0
+#define RT5616_I2S_DF_I2S (0x0)
+#define RT5616_I2S_DF_LEFT (0x1)
+#define RT5616_I2S_DF_PCM_A (0x2)
+#define RT5616_I2S_DF_PCM_B (0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5616_I2S_PD1_MASK (0x7 << 12)
+#define RT5616_I2S_PD1_SFT 12
+#define RT5616_I2S_PD1_1 (0x0 << 12)
+#define RT5616_I2S_PD1_2 (0x1 << 12)
+#define RT5616_I2S_PD1_3 (0x2 << 12)
+#define RT5616_I2S_PD1_4 (0x3 << 12)
+#define RT5616_I2S_PD1_6 (0x4 << 12)
+#define RT5616_I2S_PD1_8 (0x5 << 12)
+#define RT5616_I2S_PD1_12 (0x6 << 12)
+#define RT5616_I2S_PD1_16 (0x7 << 12)
+#define RT5616_I2S_BCLK_MS2_MASK (0x1 << 11)
+#define RT5616_DAC_OSR_MASK (0x3 << 2)
+#define RT5616_DAC_OSR_SFT 2
+#define RT5616_DAC_OSR_128 (0x0 << 2)
+#define RT5616_DAC_OSR_64 (0x1 << 2)
+#define RT5616_DAC_OSR_32 (0x2 << 2)
+#define RT5616_DAC_OSR_128_3 (0x3 << 2)
+#define RT5616_ADC_OSR_MASK (0x3)
+#define RT5616_ADC_OSR_SFT 0
+#define RT5616_ADC_OSR_128 (0x0)
+#define RT5616_ADC_OSR_64 (0x1)
+#define RT5616_ADC_OSR_32 (0x2)
+#define RT5616_ADC_OSR_128_3 (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5616_DAHPF_EN (0x1 << 11)
+#define RT5616_DAHPF_EN_SFT 11
+#define RT5616_ADHPF_EN (0x1 << 10)
+#define RT5616_ADHPF_EN_SFT 10
+
+/* TDM Control 1 (0x77) */
+#define RT5616_TDM_INTEL_SEL_MASK (0x1 << 15)
+#define RT5616_TDM_INTEL_SEL_SFT 15
+#define RT5616_TDM_INTEL_SEL_64 (0x0 << 15)
+#define RT5616_TDM_INTEL_SEL_50 (0x1 << 15)
+#define RT5616_TDM_MODE_SEL_MASK (0x1 << 14)
+#define RT5616_TDM_MODE_SEL_SFT 14
+#define RT5616_TDM_MODE_SEL_NOR (0x0 << 14)
+#define RT5616_TDM_MODE_SEL_TDM (0x1 << 14)
+#define RT5616_TDM_CH_NUM_SEL_MASK (0x3 << 12)
+#define RT5616_TDM_CH_NUM_SEL_SFT 12
+#define RT5616_TDM_CH_NUM_SEL_2 (0x0 << 12)
+#define RT5616_TDM_CH_NUM_SEL_4 (0x1 << 12)
+#define RT5616_TDM_CH_NUM_SEL_6 (0x2 << 12)
+#define RT5616_TDM_CH_NUM_SEL_8 (0x3 << 12)
+#define RT5616_TDM_CH_LEN_SEL_MASK (0x3 << 10)
+#define RT5616_TDM_CH_LEN_SEL_SFT 10
+#define RT5616_TDM_CH_LEN_SEL_16 (0x0 << 10)
+#define RT5616_TDM_CH_LEN_SEL_20 (0x1 << 10)
+#define RT5616_TDM_CH_LEN_SEL_24 (0x2 << 10)
+#define RT5616_TDM_CH_LEN_SEL_32 (0x3 << 10)
+#define RT5616_TDM_ADC_SEL_MASK (0x1 << 9)
+#define RT5616_TDM_ADC_SEL_SFT 9
+#define RT5616_TDM_ADC_SEL_NOR (0x0 << 9)
+#define RT5616_TDM_ADC_SEL_SWAP (0x1 << 9)
+#define RT5616_TDM_ADC_START_SEL_MASK (0x1 << 8)
+#define RT5616_TDM_ADC_START_SEL_SFT 8
+#define RT5616_TDM_ADC_START_SEL_SL0 (0x0 << 8)
+#define RT5616_TDM_ADC_START_SEL_SL4 (0x1 << 8)
+#define RT5616_TDM_I2S_CH2_SEL_MASK (0x3 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_SFT 6
+#define RT5616_TDM_I2S_CH2_SEL_LR (0x0 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RL (0x1 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_LL (0x2 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RR (0x3 << 6)
+#define RT5616_TDM_I2S_CH4_SEL_MASK (0x3 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_SFT 4
+#define RT5616_TDM_I2S_CH4_SEL_LR (0x0 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RL (0x1 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_LL (0x2 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RR (0x3 << 4)
+#define RT5616_TDM_I2S_CH6_SEL_MASK (0x3 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_SFT 2
+#define RT5616_TDM_I2S_CH6_SEL_LR (0x0 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RL (0x1 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_LL (0x2 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RR (0x3 << 2)
+#define RT5616_TDM_I2S_CH8_SEL_MASK (0x3)
+#define RT5616_TDM_I2S_CH8_SEL_SFT 0
+#define RT5616_TDM_I2S_CH8_SEL_LR (0x0)
+#define RT5616_TDM_I2S_CH8_SEL_RL (0x1)
+#define RT5616_TDM_I2S_CH8_SEL_LL (0x2)
+#define RT5616_TDM_I2S_CH8_SEL_RR (0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5616_TDM_LRCK_POL_SEL_MASK (0x1 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_SFT 15
+#define RT5616_TDM_LRCK_POL_SEL_NOR (0x0 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_INV (0x1 << 15)
+#define RT5616_TDM_CH_VAL_SEL_MASK (0x1 << 14)
+#define RT5616_TDM_CH_VAL_SEL_SFT 14
+#define RT5616_TDM_CH_VAL_SEL_CH01 (0x0 << 14)
+#define RT5616_TDM_CH_VAL_SEL_CH0123 (0x1 << 14)
+#define RT5616_TDM_CH_VAL_EN (0x1 << 13)
+#define RT5616_TDM_CH_VAL_SFT 13
+#define RT5616_TDM_LPBK_EN (0x1 << 12)
+#define RT5616_TDM_LPBK_SFT 12
+#define RT5616_TDM_LRCK_PULSE_SEL_MASK (0x1 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_SFT 11
+#define RT5616_TDM_LRCK_PULSE_SEL_BCLK (0x0 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_CH (0x1 << 11)
+#define RT5616_TDM_END_EDGE_SEL_MASK (0x1 << 10)
+#define RT5616_TDM_END_EDGE_SEL_SFT 10
+#define RT5616_TDM_END_EDGE_SEL_POS (0x0 << 10)
+#define RT5616_TDM_END_EDGE_SEL_NEG (0x1 << 10)
+#define RT5616_TDM_END_EDGE_EN (0x1 << 9)
+#define RT5616_TDM_END_EDGE_EN_SFT 9
+#define RT5616_TDM_TRAN_EDGE_SEL_MASK (0x1 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_SFT 8
+#define RT5616_TDM_TRAN_EDGE_SEL_POS (0x0 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_NEG (0x1 << 8)
+#define RT5616_M_TDM2_L (0x1 << 7)
+#define RT5616_M_TDM2_L_SFT 7
+#define RT5616_M_TDM2_R (0x1 << 6)
+#define RT5616_M_TDM2_R_SFT 6
+#define RT5616_M_TDM4_L (0x1 << 5)
+#define RT5616_M_TDM4_L_SFT 5
+#define RT5616_M_TDM4_R (0x1 << 4)
+#define RT5616_M_TDM4_R_SFT 4
+
+/* Global Clock Control (0x80) */
+#define RT5616_SCLK_SRC_MASK (0x3 << 14)
+#define RT5616_SCLK_SRC_SFT 14
+#define RT5616_SCLK_SRC_MCLK (0x0 << 14)
+#define RT5616_SCLK_SRC_PLL1 (0x1 << 14)
+#define RT5616_PLL1_SRC_MASK (0x3 << 12)
+#define RT5616_PLL1_SRC_SFT 12
+#define RT5616_PLL1_SRC_MCLK (0x0 << 12)
+#define RT5616_PLL1_SRC_BCLK1 (0x1 << 12)
+#define RT5616_PLL1_SRC_BCLK2 (0x2 << 12)
+#define RT5616_PLL1_PD_MASK (0x1 << 3)
+#define RT5616_PLL1_PD_SFT 3
+#define RT5616_PLL1_PD_1 (0x0 << 3)
+#define RT5616_PLL1_PD_2 (0x1 << 3)
+
+#define RT5616_PLL_INP_MAX 40000000
+#define RT5616_PLL_INP_MIN 256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5616_PLL_N_MAX 0x1ff
+#define RT5616_PLL_N_MASK (RT5616_PLL_N_MAX << 7)
+#define RT5616_PLL_N_SFT 7
+#define RT5616_PLL_K_MAX 0x1f
+#define RT5616_PLL_K_MASK (RT5616_PLL_K_MAX)
+#define RT5616_PLL_K_SFT 0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5616_PLL_M_MAX 0xf
+#define RT5616_PLL_M_MASK (RT5616_PLL_M_MAX << 12)
+#define RT5616_PLL_M_SFT 12
+#define RT5616_PLL_M_BP (0x1 << 11)
+#define RT5616_PLL_M_BP_SFT 11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5616_STO1_T_MASK (0x1 << 15)
+#define RT5616_STO1_T_SFT 15
+#define RT5616_STO1_T_SCLK (0x0 << 15)
+#define RT5616_STO1_T_LRCK1 (0x1 << 15)
+#define RT5616_STO2_T_MASK (0x1 << 12)
+#define RT5616_STO2_T_SFT 12
+#define RT5616_STO2_T_I2S2 (0x0 << 12)
+#define RT5616_STO2_T_LRCK2 (0x1 << 12)
+#define RT5616_ASRC2_REF_MASK (0x1 << 11)
+#define RT5616_ASRC2_REF_SFT 11
+#define RT5616_ASRC2_REF_LRCK2 (0x0 << 11)
+#define RT5616_ASRC2_REF_LRCK1 (0x1 << 11)
+#define RT5616_DMIC_1_M_MASK (0x1 << 9)
+#define RT5616_DMIC_1_M_SFT 9
+#define RT5616_DMIC_1_M_NOR (0x0 << 9)
+#define RT5616_DMIC_1_M_ASYN (0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5616_STO1_ASRC_EN (0x1 << 15)
+#define RT5616_STO1_ASRC_EN_SFT 15
+#define RT5616_STO2_ASRC_EN (0x1 << 14)
+#define RT5616_STO2_ASRC_EN_SFT 14
+#define RT5616_STO1_DAC_M_MASK (0x1 << 13)
+#define RT5616_STO1_DAC_M_SFT 13
+#define RT5616_STO1_DAC_M_NOR (0x0 << 13)
+#define RT5616_STO1_DAC_M_ASRC (0x1 << 13)
+#define RT5616_STO2_DAC_M_MASK (0x1 << 12)
+#define RT5616_STO2_DAC_M_SFT 12
+#define RT5616_STO2_DAC_M_NOR (0x0 << 12)
+#define RT5616_STO2_DAC_M_ASRC (0x1 << 12)
+#define RT5616_ADC_M_MASK (0x1 << 11)
+#define RT5616_ADC_M_SFT 11
+#define RT5616_ADC_M_NOR (0x0 << 11)
+#define RT5616_ADC_M_ASRC (0x1 << 11)
+#define RT5616_I2S1_R_D_MASK (0x1 << 4)
+#define RT5616_I2S1_R_D_SFT 4
+#define RT5616_I2S1_R_D_DIS (0x0 << 4)
+#define RT5616_I2S1_R_D_EN (0x1 << 4)
+#define RT5616_I2S2_R_D_MASK (0x1 << 3)
+#define RT5616_I2S2_R_D_SFT 3
+#define RT5616_I2S2_R_D_DIS (0x0 << 3)
+#define RT5616_I2S2_R_D_EN (0x1 << 3)
+#define RT5616_PRE_SCLK_MASK (0x3)
+#define RT5616_PRE_SCLK_SFT 0
+#define RT5616_PRE_SCLK_512 (0x0)
+#define RT5616_PRE_SCLK_1024 (0x1)
+#define RT5616_PRE_SCLK_2048 (0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5616_I2S1_RATE_MASK (0xf << 12)
+#define RT5616_I2S1_RATE_SFT 12
+#define RT5616_I2S2_RATE_MASK (0xf << 8)
+#define RT5616_I2S2_RATE_SFT 8
+#define RT5616_G_ASRC_LP_MASK (0x1 << 3)
+#define RT5616_G_ASRC_LP_SFT 3
+#define RT5616_ASRC_LP_F_M (0x1 << 2)
+#define RT5616_ASRC_LP_F_SFT 2
+#define RT5616_ASRC_LP_F_NOR (0x0 << 2)
+#define RT5616_ASRC_LP_F_SB (0x1 << 2)
+#define RT5616_FTK_PH_DET_MASK (0x3)
+#define RT5616_FTK_PH_DET_SFT 0
+#define RT5616_FTK_PH_DET_DIV1 (0x0)
+#define RT5616_FTK_PH_DET_DIV2 (0x1)
+#define RT5616_FTK_PH_DET_DIV4 (0x2)
+#define RT5616_FTK_PH_DET_DIV8 (0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5616_I2S1_PD_MASK (0x7 << 12)
+#define RT5616_I2S1_PD_SFT 12
+#define RT5616_I2S2_PD_MASK (0x7 << 8)
+#define RT5616_I2S2_PD_SFT 8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5616_FSI1_RATE_MASK (0xf << 12)
+#define RT5616_FSI1_RATE_SFT 12
+#define RT5616_FSI2_RATE_MASK (0xf << 8)
+#define RT5616_FSI2_RATE_SFT 8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5616_HP_OVCD_MASK (0x1 << 10)
+#define RT5616_HP_OVCD_SFT 10
+#define RT5616_HP_OVCD_DIS (0x0 << 10)
+#define RT5616_HP_OVCD_EN (0x1 << 10)
+#define RT5616_HP_OC_TH_MASK (0x3 << 8)
+#define RT5616_HP_OC_TH_SFT 8
+#define RT5616_HP_OC_TH_90 (0x0 << 8)
+#define RT5616_HP_OC_TH_105 (0x1 << 8)
+#define RT5616_HP_OC_TH_120 (0x2 << 8)
+#define RT5616_HP_OC_TH_135 (0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5616_SMT_TRIG_MASK (0x1 << 15)
+#define RT5616_SMT_TRIG_SFT 15
+#define RT5616_SMT_TRIG_DIS (0x0 << 15)
+#define RT5616_SMT_TRIG_EN (0x1 << 15)
+#define RT5616_HP_L_SMT_MASK (0x1 << 9)
+#define RT5616_HP_L_SMT_SFT 9
+#define RT5616_HP_L_SMT_DIS (0x0 << 9)
+#define RT5616_HP_L_SMT_EN (0x1 << 9)
+#define RT5616_HP_R_SMT_MASK (0x1 << 8)
+#define RT5616_HP_R_SMT_SFT 8
+#define RT5616_HP_R_SMT_DIS (0x0 << 8)
+#define RT5616_HP_R_SMT_EN (0x1 << 8)
+#define RT5616_HP_CD_PD_MASK (0x1 << 7)
+#define RT5616_HP_CD_PD_SFT 7
+#define RT5616_HP_CD_PD_DIS (0x0 << 7)
+#define RT5616_HP_CD_PD_EN (0x1 << 7)
+#define RT5616_RSTN_MASK (0x1 << 6)
+#define RT5616_RSTN_SFT 6
+#define RT5616_RSTN_DIS (0x0 << 6)
+#define RT5616_RSTN_EN (0x1 << 6)
+#define RT5616_RSTP_MASK (0x1 << 5)
+#define RT5616_RSTP_SFT 5
+#define RT5616_RSTP_DIS (0x0 << 5)
+#define RT5616_RSTP_EN (0x1 << 5)
+#define RT5616_HP_CO_MASK (0x1 << 4)
+#define RT5616_HP_CO_SFT 4
+#define RT5616_HP_CO_DIS (0x0 << 4)
+#define RT5616_HP_CO_EN (0x1 << 4)
+#define RT5616_HP_CP_MASK (0x1 << 3)
+#define RT5616_HP_CP_SFT 3
+#define RT5616_HP_CP_PD (0x0 << 3)
+#define RT5616_HP_CP_PU (0x1 << 3)
+#define RT5616_HP_SG_MASK (0x1 << 2)
+#define RT5616_HP_SG_SFT 2
+#define RT5616_HP_SG_DIS (0x0 << 2)
+#define RT5616_HP_SG_EN (0x1 << 2)
+#define RT5616_HP_DP_MASK (0x1 << 1)
+#define RT5616_HP_DP_SFT 1
+#define RT5616_HP_DP_PD (0x0 << 1)
+#define RT5616_HP_DP_PU (0x1 << 1)
+#define RT5616_HP_CB_MASK (0x1)
+#define RT5616_HP_CB_SFT 0
+#define RT5616_HP_CB_PD (0x0)
+#define RT5616_HP_CB_PU (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5616_DEPOP_MASK (0x1 << 13)
+#define RT5616_DEPOP_SFT 13
+#define RT5616_DEPOP_AUTO (0x0 << 13)
+#define RT5616_DEPOP_MAN (0x1 << 13)
+#define RT5616_RAMP_MASK (0x1 << 12)
+#define RT5616_RAMP_SFT 12
+#define RT5616_RAMP_DIS (0x0 << 12)
+#define RT5616_RAMP_EN (0x1 << 12)
+#define RT5616_BPS_MASK (0x1 << 11)
+#define RT5616_BPS_SFT 11
+#define RT5616_BPS_DIS (0x0 << 11)
+#define RT5616_BPS_EN (0x1 << 11)
+#define RT5616_FAST_UPDN_MASK (0x1 << 10)
+#define RT5616_FAST_UPDN_SFT 10
+#define RT5616_FAST_UPDN_DIS (0x0 << 10)
+#define RT5616_FAST_UPDN_EN (0x1 << 10)
+#define RT5616_MRES_MASK (0x3 << 8)
+#define RT5616_MRES_SFT 8
+#define RT5616_MRES_15MO (0x0 << 8)
+#define RT5616_MRES_25MO (0x1 << 8)
+#define RT5616_MRES_35MO (0x2 << 8)
+#define RT5616_MRES_45MO (0x3 << 8)
+#define RT5616_VLO_MASK (0x1 << 7)
+#define RT5616_VLO_SFT 7
+#define RT5616_VLO_3V (0x0 << 7)
+#define RT5616_VLO_32V (0x1 << 7)
+#define RT5616_DIG_DP_MASK (0x1 << 6)
+#define RT5616_DIG_DP_SFT 6
+#define RT5616_DIG_DP_DIS (0x0 << 6)
+#define RT5616_DIG_DP_EN (0x1 << 6)
+#define RT5616_DP_TH_MASK (0x3 << 4)
+#define RT5616_DP_TH_SFT 4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5616_CP_SYS_MASK (0x7 << 12)
+#define RT5616_CP_SYS_SFT 12
+#define RT5616_CP_FQ1_MASK (0x7 << 8)
+#define RT5616_CP_FQ1_SFT 8
+#define RT5616_CP_FQ2_MASK (0x7 << 4)
+#define RT5616_CP_FQ2_SFT 4
+#define RT5616_CP_FQ3_MASK (0x7)
+#define RT5616_CP_FQ3_SFT 0
+#define RT5616_CP_FQ_1_5_KHZ 0
+#define RT5616_CP_FQ_3_KHZ 1
+#define RT5616_CP_FQ_6_KHZ 2
+#define RT5616_CP_FQ_12_KHZ 3
+#define RT5616_CP_FQ_24_KHZ 4
+#define RT5616_CP_FQ_48_KHZ 5
+#define RT5616_CP_FQ_96_KHZ 6
+#define RT5616_CP_FQ_192_KHZ 7
+
+/* HPOUT charge pump (0x91) */
+#define RT5616_OSW_L_MASK (0x1 << 11)
+#define RT5616_OSW_L_SFT 11
+#define RT5616_OSW_L_DIS (0x0 << 11)
+#define RT5616_OSW_L_EN (0x1 << 11)
+#define RT5616_OSW_R_MASK (0x1 << 10)
+#define RT5616_OSW_R_SFT 10
+#define RT5616_OSW_R_DIS (0x0 << 10)
+#define RT5616_OSW_R_EN (0x1 << 10)
+#define RT5616_PM_HP_MASK (0x3 << 8)
+#define RT5616_PM_HP_SFT 8
+#define RT5616_PM_HP_LV (0x0 << 8)
+#define RT5616_PM_HP_MV (0x1 << 8)
+#define RT5616_PM_HP_HV (0x2 << 8)
+#define RT5616_IB_HP_MASK (0x3 << 6)
+#define RT5616_IB_HP_SFT 6
+#define RT5616_IB_HP_125IL (0x0 << 6)
+#define RT5616_IB_HP_25IL (0x1 << 6)
+#define RT5616_IB_HP_5IL (0x2 << 6)
+#define RT5616_IB_HP_1IL (0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5616_MIC1_BS_MASK (0x1 << 15)
+#define RT5616_MIC1_BS_SFT 15
+#define RT5616_MIC1_BS_9AV (0x0 << 15)
+#define RT5616_MIC1_BS_75AV (0x1 << 15)
+#define RT5616_MIC1_CLK_MASK (0x1 << 13)
+#define RT5616_MIC1_CLK_SFT 13
+#define RT5616_MIC1_CLK_DIS (0x0 << 13)
+#define RT5616_MIC1_CLK_EN (0x1 << 13)
+#define RT5616_MIC1_OVCD_MASK (0x1 << 11)
+#define RT5616_MIC1_OVCD_SFT 11
+#define RT5616_MIC1_OVCD_DIS (0x0 << 11)
+#define RT5616_MIC1_OVCD_EN (0x1 << 11)
+#define RT5616_MIC1_OVTH_MASK (0x3 << 9)
+#define RT5616_MIC1_OVTH_SFT 9
+#define RT5616_MIC1_OVTH_600UA (0x0 << 9)
+#define RT5616_MIC1_OVTH_1500UA (0x1 << 9)
+#define RT5616_MIC1_OVTH_2000UA (0x2 << 9)
+#define RT5616_PWR_MB_MASK (0x1 << 5)
+#define RT5616_PWR_MB_SFT 5
+#define RT5616_PWR_MB_PD (0x0 << 5)
+#define RT5616_PWR_MB_PU (0x1 << 5)
+#define RT5616_PWR_CLK12M_MASK (0x1 << 4)
+#define RT5616_PWR_CLK12M_SFT 4
+#define RT5616_PWR_CLK12M_PD (0x0 << 4)
+#define RT5616_PWR_CLK12M_PU (0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5616_JD2_CMP_MASK (0x7 << 12)
+#define RT5616_JD2_CMP_SFT 12
+#define RT5616_JD_PU (0x1 << 11)
+#define RT5616_JD_PU_SFT 11
+#define RT5616_JD_PD (0x1 << 10)
+#define RT5616_JD_PD_SFT 10
+#define RT5616_JD_MODE_SEL_MASK (0x3 << 8)
+#define RT5616_JD_MODE_SEL_SFT 8
+#define RT5616_JD_MODE_SEL_M0 (0x0 << 8)
+#define RT5616_JD_MODE_SEL_M1 (0x1 << 8)
+#define RT5616_JD_MODE_SEL_M2 (0x2 << 8)
+#define RT5616_JD_M_CMP (0x7 << 4)
+#define RT5616_JD_M_CMP_SFT 4
+#define RT5616_JD_M_PU (0x1 << 3)
+#define RT5616_JD_M_PU_SFT 3
+#define RT5616_JD_M_PD (0x1 << 2)
+#define RT5616_JD_M_PD_SFT 2
+#define RT5616_JD_M_MODE_SEL_MASK (0x3)
+#define RT5616_JD_M_MODE_SEL_SFT 0
+#define RT5616_JD_M_MODE_SEL_M0 (0x0)
+#define RT5616_JD_M_MODE_SEL_M1 (0x1)
+#define RT5616_JD_M_MODE_SEL_M2 (0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5616_JD3_CMP_MASK (0x7 << 12)
+#define RT5616_JD3_CMP_SFT 12
+
+/* EQ Control 1 (0xb0) */
+#define RT5616_EQ_SRC_MASK (0x1 << 15)
+#define RT5616_EQ_SRC_SFT 15
+#define RT5616_EQ_SRC_DAC (0x0 << 15)
+#define RT5616_EQ_SRC_ADC (0x1 << 15)
+#define RT5616_EQ_UPD (0x1 << 14)
+#define RT5616_EQ_UPD_BIT 14
+#define RT5616_EQ_CD_MASK (0x1 << 13)
+#define RT5616_EQ_CD_SFT 13
+#define RT5616_EQ_CD_DIS (0x0 << 13)
+#define RT5616_EQ_CD_EN (0x1 << 13)
+#define RT5616_EQ_DITH_MASK (0x3 << 8)
+#define RT5616_EQ_DITH_SFT 8
+#define RT5616_EQ_DITH_NOR (0x0 << 8)
+#define RT5616_EQ_DITH_LSB (0x1 << 8)
+#define RT5616_EQ_DITH_LSB_1 (0x2 << 8)
+#define RT5616_EQ_DITH_LSB_2 (0x3 << 8)
+#define RT5616_EQ_CD_F (0x1 << 7)
+#define RT5616_EQ_CD_F_BIT 7
+#define RT5616_EQ_STA_HP2 (0x1 << 6)
+#define RT5616_EQ_STA_HP2_BIT 6
+#define RT5616_EQ_STA_HP1 (0x1 << 5)
+#define RT5616_EQ_STA_HP1_BIT 5
+#define RT5616_EQ_STA_BP4 (0x1 << 4)
+#define RT5616_EQ_STA_BP4_BIT 4
+#define RT5616_EQ_STA_BP3 (0x1 << 3)
+#define RT5616_EQ_STA_BP3_BIT 3
+#define RT5616_EQ_STA_BP2 (0x1 << 2)
+#define RT5616_EQ_STA_BP2_BIT 2
+#define RT5616_EQ_STA_BP1 (0x1 << 1)
+#define RT5616_EQ_STA_BP1_BIT 1
+#define RT5616_EQ_STA_LP (0x1)
+#define RT5616_EQ_STA_LP_BIT 0
+
+/* EQ Control 2 (0xb1) */
+#define RT5616_EQ_HPF1_M_MASK (0x1 << 8)
+#define RT5616_EQ_HPF1_M_SFT 8
+#define RT5616_EQ_HPF1_M_HI (0x0 << 8)
+#define RT5616_EQ_HPF1_M_1ST (0x1 << 8)
+#define RT5616_EQ_LPF1_M_MASK (0x1 << 7)
+#define RT5616_EQ_LPF1_M_SFT 7
+#define RT5616_EQ_LPF1_M_LO (0x0 << 7)
+#define RT5616_EQ_LPF1_M_1ST (0x1 << 7)
+#define RT5616_EQ_HPF2_MASK (0x1 << 6)
+#define RT5616_EQ_HPF2_SFT 6
+#define RT5616_EQ_HPF2_DIS (0x0 << 6)
+#define RT5616_EQ_HPF2_EN (0x1 << 6)
+#define RT5616_EQ_HPF1_MASK (0x1 << 5)
+#define RT5616_EQ_HPF1_SFT 5
+#define RT5616_EQ_HPF1_DIS (0x0 << 5)
+#define RT5616_EQ_HPF1_EN (0x1 << 5)
+#define RT5616_EQ_BPF4_MASK (0x1 << 4)
+#define RT5616_EQ_BPF4_SFT 4
+#define RT5616_EQ_BPF4_DIS (0x0 << 4)
+#define RT5616_EQ_BPF4_EN (0x1 << 4)
+#define RT5616_EQ_BPF3_MASK (0x1 << 3)
+#define RT5616_EQ_BPF3_SFT 3
+#define RT5616_EQ_BPF3_DIS (0x0 << 3)
+#define RT5616_EQ_BPF3_EN (0x1 << 3)
+#define RT5616_EQ_BPF2_MASK (0x1 << 2)
+#define RT5616_EQ_BPF2_SFT 2
+#define RT5616_EQ_BPF2_DIS (0x0 << 2)
+#define RT5616_EQ_BPF2_EN (0x1 << 2)
+#define RT5616_EQ_BPF1_MASK (0x1 << 1)
+#define RT5616_EQ_BPF1_SFT 1
+#define RT5616_EQ_BPF1_DIS (0x0 << 1)
+#define RT5616_EQ_BPF1_EN (0x1 << 1)
+#define RT5616_EQ_LPF_MASK (0x1)
+#define RT5616_EQ_LPF_SFT 0
+#define RT5616_EQ_LPF_DIS (0x0)
+#define RT5616_EQ_LPF_EN (0x1)
+#define RT5616_EQ_CTRL_MASK (0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5616_MT_MASK (0x1 << 15)
+#define RT5616_MT_SFT 15
+#define RT5616_MT_DIS (0x0 << 15)
+#define RT5616_MT_EN (0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5616_DRC_AGC_P_MASK (0x1 << 15)
+#define RT5616_DRC_AGC_P_SFT 15
+#define RT5616_DRC_AGC_P_DAC (0x0 << 15)
+#define RT5616_DRC_AGC_P_ADC (0x1 << 15)
+#define RT5616_DRC_AGC_MASK (0x1 << 14)
+#define RT5616_DRC_AGC_SFT 14
+#define RT5616_DRC_AGC_DIS (0x0 << 14)
+#define RT5616_DRC_AGC_EN (0x1 << 14)
+#define RT5616_DRC_AGC_UPD (0x1 << 13)
+#define RT5616_DRC_AGC_UPD_BIT 13
+#define RT5616_DRC_AGC_AR_MASK (0x1f << 8)
+#define RT5616_DRC_AGC_AR_SFT 8
+#define RT5616_DRC_AGC_R_MASK (0x7 << 5)
+#define RT5616_DRC_AGC_R_SFT 5
+#define RT5616_DRC_AGC_R_48K (0x1 << 5)
+#define RT5616_DRC_AGC_R_96K (0x2 << 5)
+#define RT5616_DRC_AGC_R_192K (0x3 << 5)
+#define RT5616_DRC_AGC_R_441K (0x5 << 5)
+#define RT5616_DRC_AGC_R_882K (0x6 << 5)
+#define RT5616_DRC_AGC_R_1764K (0x7 << 5)
+#define RT5616_DRC_AGC_RC_MASK (0x1f)
+#define RT5616_DRC_AGC_RC_SFT 0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5616_DRC_AGC_POB_MASK (0x3f << 8)
+#define RT5616_DRC_AGC_POB_SFT 8
+#define RT5616_DRC_AGC_CP_MASK (0x1 << 7)
+#define RT5616_DRC_AGC_CP_SFT 7
+#define RT5616_DRC_AGC_CP_DIS (0x0 << 7)
+#define RT5616_DRC_AGC_CP_EN (0x1 << 7)
+#define RT5616_DRC_AGC_CPR_MASK (0x3 << 5)
+#define RT5616_DRC_AGC_CPR_SFT 5
+#define RT5616_DRC_AGC_CPR_1_1 (0x0 << 5)
+#define RT5616_DRC_AGC_CPR_1_2 (0x1 << 5)
+#define RT5616_DRC_AGC_CPR_1_3 (0x2 << 5)
+#define RT5616_DRC_AGC_CPR_1_4 (0x3 << 5)
+#define RT5616_DRC_AGC_PRB_MASK (0x1f)
+#define RT5616_DRC_AGC_PRB_SFT 0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5616_DRC_AGC_NGB_MASK (0xf << 12)
+#define RT5616_DRC_AGC_NGB_SFT 12
+#define RT5616_DRC_AGC_TAR_MASK (0x1f << 7)
+#define RT5616_DRC_AGC_TAR_SFT 7
+#define RT5616_DRC_AGC_NG_MASK (0x1 << 6)
+#define RT5616_DRC_AGC_NG_SFT 6
+#define RT5616_DRC_AGC_NG_DIS (0x0 << 6)
+#define RT5616_DRC_AGC_NG_EN (0x1 << 6)
+#define RT5616_DRC_AGC_NGH_MASK (0x1 << 5)
+#define RT5616_DRC_AGC_NGH_SFT 5
+#define RT5616_DRC_AGC_NGH_DIS (0x0 << 5)
+#define RT5616_DRC_AGC_NGH_EN (0x1 << 5)
+#define RT5616_DRC_AGC_NGT_MASK (0x1f)
+#define RT5616_DRC_AGC_NGT_SFT 0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5616_JD_MASK (0x7 << 13)
+#define RT5616_JD_SFT 13
+#define RT5616_JD_DIS (0x0 << 13)
+#define RT5616_JD_GPIO1 (0x1 << 13)
+#define RT5616_JD_GPIO2 (0x2 << 13)
+#define RT5616_JD_GPIO3 (0x3 << 13)
+#define RT5616_JD_GPIO4 (0x4 << 13)
+#define RT5616_JD_GPIO5 (0x5 << 13)
+#define RT5616_JD_GPIO6 (0x6 << 13)
+#define RT5616_JD_HP_MASK (0x1 << 11)
+#define RT5616_JD_HP_SFT 11
+#define RT5616_JD_HP_DIS (0x0 << 11)
+#define RT5616_JD_HP_EN (0x1 << 11)
+#define RT5616_JD_HP_TRG_MASK (0x1 << 10)
+#define RT5616_JD_HP_TRG_SFT 10
+#define RT5616_JD_HP_TRG_LO (0x0 << 10)
+#define RT5616_JD_HP_TRG_HI (0x1 << 10)
+#define RT5616_JD_SPL_MASK (0x1 << 9)
+#define RT5616_JD_SPL_SFT 9
+#define RT5616_JD_SPL_DIS (0x0 << 9)
+#define RT5616_JD_SPL_EN (0x1 << 9)
+#define RT5616_JD_SPL_TRG_MASK (0x1 << 8)
+#define RT5616_JD_SPL_TRG_SFT 8
+#define RT5616_JD_SPL_TRG_LO (0x0 << 8)
+#define RT5616_JD_SPL_TRG_HI (0x1 << 8)
+#define RT5616_JD_SPR_MASK (0x1 << 7)
+#define RT5616_JD_SPR_SFT 7
+#define RT5616_JD_SPR_DIS (0x0 << 7)
+#define RT5616_JD_SPR_EN (0x1 << 7)
+#define RT5616_JD_SPR_TRG_MASK (0x1 << 6)
+#define RT5616_JD_SPR_TRG_SFT 6
+#define RT5616_JD_SPR_TRG_LO (0x0 << 6)
+#define RT5616_JD_SPR_TRG_HI (0x1 << 6)
+#define RT5616_JD_LO_MASK (0x1 << 3)
+#define RT5616_JD_LO_SFT 3
+#define RT5616_JD_LO_DIS (0x0 << 3)
+#define RT5616_JD_LO_EN (0x1 << 3)
+#define RT5616_JD_LO_TRG_MASK (0x1 << 2)
+#define RT5616_JD_LO_TRG_SFT 2
+#define RT5616_JD_LO_TRG_LO (0x0 << 2)
+#define RT5616_JD_LO_TRG_HI (0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5616_JD_TRG_SEL_MASK (0x7 << 9)
+#define RT5616_JD_TRG_SEL_SFT 9
+#define RT5616_JD_TRG_SEL_GPIO (0x0 << 9)
+#define RT5616_JD_TRG_SEL_JD1_1 (0x1 << 9)
+#define RT5616_JD_TRG_SEL_JD1_2 (0x2 << 9)
+#define RT5616_JD_TRG_SEL_JD2 (0x3 << 9)
+#define RT5616_JD_TRG_SEL_JD3 (0x4 << 9)
+#define RT5616_JD3_IRQ_EN (0x1 << 8)
+#define RT5616_JD3_IRQ_EN_SFT 8
+#define RT5616_JD3_EN_STKY (0x1 << 7)
+#define RT5616_JD3_EN_STKY_SFT 7
+#define RT5616_JD3_INV (0x1 << 6)
+#define RT5616_JD3_INV_SFT 6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5616_IRQ_JD_MASK (0x1 << 15)
+#define RT5616_IRQ_JD_SFT 15
+#define RT5616_IRQ_JD_BP (0x0 << 15)
+#define RT5616_IRQ_JD_NOR (0x1 << 15)
+#define RT5616_JD_STKY_MASK (0x1 << 13)
+#define RT5616_JD_STKY_SFT 13
+#define RT5616_JD_STKY_DIS (0x0 << 13)
+#define RT5616_JD_STKY_EN (0x1 << 13)
+#define RT5616_JD_P_MASK (0x1 << 11)
+#define RT5616_JD_P_SFT 11
+#define RT5616_JD_P_NOR (0x0 << 11)
+#define RT5616_JD_P_INV (0x1 << 11)
+#define RT5616_JD1_1_IRQ_EN (0x1 << 9)
+#define RT5616_JD1_1_IRQ_EN_SFT 9
+#define RT5616_JD1_1_EN_STKY (0x1 << 8)
+#define RT5616_JD1_1_EN_STKY_SFT 8
+#define RT5616_JD1_1_INV (0x1 << 7)
+#define RT5616_JD1_1_INV_SFT 7
+#define RT5616_JD1_2_IRQ_EN (0x1 << 6)
+#define RT5616_JD1_2_IRQ_EN_SFT 6
+#define RT5616_JD1_2_EN_STKY (0x1 << 5)
+#define RT5616_JD1_2_EN_STKY_SFT 5
+#define RT5616_JD1_2_INV (0x1 << 4)
+#define RT5616_JD1_2_INV_SFT 4
+#define RT5616_JD2_IRQ_EN (0x1 << 3)
+#define RT5616_JD2_IRQ_EN_SFT 3
+#define RT5616_JD2_EN_STKY (0x1 << 2)
+#define RT5616_JD2_EN_STKY_SFT 2
+#define RT5616_JD2_INV (0x1 << 1)
+#define RT5616_JD2_INV_SFT 1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5616_IRQ_MB1_OC_MASK (0x1 << 15)
+#define RT5616_IRQ_MB1_OC_SFT 15
+#define RT5616_IRQ_MB1_OC_BP (0x0 << 15)
+#define RT5616_IRQ_MB1_OC_NOR (0x1 << 15)
+#define RT5616_MB1_OC_STKY_MASK (0x1 << 11)
+#define RT5616_MB1_OC_STKY_SFT 11
+#define RT5616_MB1_OC_STKY_DIS (0x0 << 11)
+#define RT5616_MB1_OC_STKY_EN (0x1 << 11)
+#define RT5616_MB1_OC_P_MASK (0x1 << 7)
+#define RT5616_MB1_OC_P_SFT 7
+#define RT5616_MB1_OC_P_NOR (0x0 << 7)
+#define RT5616_MB1_OC_P_INV (0x1 << 7)
+#define RT5616_MB2_OC_P_MASK (0x1 << 6)
+#define RT5616_MB1_OC_CLR (0x1 << 3)
+#define RT5616_MB1_OC_CLR_SFT 3
+#define RT5616_STA_GPIO8 (0x1)
+#define RT5616_STA_GPIO8_BIT 0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5616_STA_JD3 (0x1 << 15)
+#define RT5616_STA_JD3_BIT 15
+#define RT5616_STA_JD2 (0x1 << 14)
+#define RT5616_STA_JD2_BIT 14
+#define RT5616_STA_JD1_2 (0x1 << 13)
+#define RT5616_STA_JD1_2_BIT 13
+#define RT5616_STA_JD1_1 (0x1 << 12)
+#define RT5616_STA_JD1_1_BIT 12
+#define RT5616_STA_GP7 (0x1 << 11)
+#define RT5616_STA_GP7_BIT 11
+#define RT5616_STA_GP6 (0x1 << 10)
+#define RT5616_STA_GP6_BIT 10
+#define RT5616_STA_GP5 (0x1 << 9)
+#define RT5616_STA_GP5_BIT 9
+#define RT5616_STA_GP1 (0x1 << 8)
+#define RT5616_STA_GP1_BIT 8
+#define RT5616_STA_GP2 (0x1 << 7)
+#define RT5616_STA_GP2_BIT 7
+#define RT5616_STA_GP3 (0x1 << 6)
+#define RT5616_STA_GP3_BIT 6
+#define RT5616_STA_GP4 (0x1 << 5)
+#define RT5616_STA_GP4_BIT 5
+#define RT5616_STA_GP_JD (0x1 << 4)
+#define RT5616_STA_GP_JD_BIT 4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5616_GP1_PIN_MASK (0x1 << 15)
+#define RT5616_GP1_PIN_SFT 15
+#define RT5616_GP1_PIN_GPIO1 (0x0 << 15)
+#define RT5616_GP1_PIN_IRQ (0x1 << 15)
+#define RT5616_GP2_PIN_MASK (0x1 << 14)
+#define RT5616_GP2_PIN_SFT 14
+#define RT5616_GP2_PIN_GPIO2 (0x0 << 14)
+#define RT5616_GP2_PIN_DMIC1_SCL (0x1 << 14)
+#define RT5616_GPIO_M_MASK (0x1 << 9)
+#define RT5616_GPIO_M_SFT 9
+#define RT5616_GPIO_M_FLT (0x0 << 9)
+#define RT5616_GPIO_M_PH (0x1 << 9)
+#define RT5616_I2S2_SEL_MASK (0x1 << 8)
+#define RT5616_I2S2_SEL_SFT 8
+#define RT5616_I2S2_SEL_I2S (0x0 << 8)
+#define RT5616_I2S2_SEL_GPIO (0x1 << 8)
+#define RT5616_GP5_PIN_MASK (0x1 << 7)
+#define RT5616_GP5_PIN_SFT 7
+#define RT5616_GP5_PIN_GPIO5 (0x0 << 7)
+#define RT5616_GP5_PIN_IRQ (0x1 << 7)
+#define RT5616_GP6_PIN_MASK (0x1 << 6)
+#define RT5616_GP6_PIN_SFT 6
+#define RT5616_GP6_PIN_GPIO6 (0x0 << 6)
+#define RT5616_GP6_PIN_DMIC_SDA (0x1 << 6)
+#define RT5616_GP7_PIN_MASK (0x1 << 5)
+#define RT5616_GP7_PIN_SFT 5
+#define RT5616_GP7_PIN_GPIO7 (0x0 << 5)
+#define RT5616_GP7_PIN_IRQ (0x1 << 5)
+#define RT5616_GP8_PIN_MASK (0x1 << 4)
+#define RT5616_GP8_PIN_SFT 4
+#define RT5616_GP8_PIN_GPIO8 (0x0 << 4)
+#define RT5616_GP8_PIN_DMIC_SDA (0x1 << 4)
+#define RT5616_GPIO_PDM_SEL_MASK (0x1 << 3)
+#define RT5616_GPIO_PDM_SEL_SFT 3
+#define RT5616_GPIO_PDM_SEL_GPIO (0x0 << 3)
+#define RT5616_GPIO_PDM_SEL_PDM (0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5616_GP5_DR_MASK (0x1 << 14)
+#define RT5616_GP5_DR_SFT 14
+#define RT5616_GP5_DR_IN (0x0 << 14)
+#define RT5616_GP5_DR_OUT (0x1 << 14)
+#define RT5616_GP5_OUT_MASK (0x1 << 13)
+#define RT5616_GP5_OUT_SFT 13
+#define RT5616_GP5_OUT_LO (0x0 << 13)
+#define RT5616_GP5_OUT_HI (0x1 << 13)
+#define RT5616_GP5_P_MASK (0x1 << 12)
+#define RT5616_GP5_P_SFT 12
+#define RT5616_GP5_P_NOR (0x0 << 12)
+#define RT5616_GP5_P_INV (0x1 << 12)
+#define RT5616_GP4_DR_MASK (0x1 << 11)
+#define RT5616_GP4_DR_SFT 11
+#define RT5616_GP4_DR_IN (0x0 << 11)
+#define RT5616_GP4_DR_OUT (0x1 << 11)
+#define RT5616_GP4_OUT_MASK (0x1 << 10)
+#define RT5616_GP4_OUT_SFT 10
+#define RT5616_GP4_OUT_LO (0x0 << 10)
+#define RT5616_GP4_OUT_HI (0x1 << 10)
+#define RT5616_GP4_P_MASK (0x1 << 9)
+#define RT5616_GP4_P_SFT 9
+#define RT5616_GP4_P_NOR (0x0 << 9)
+#define RT5616_GP4_P_INV (0x1 << 9)
+#define RT5616_GP3_DR_MASK (0x1 << 8)
+#define RT5616_GP3_DR_SFT 8
+#define RT5616_GP3_DR_IN (0x0 << 8)
+#define RT5616_GP3_DR_OUT (0x1 << 8)
+#define RT5616_GP3_OUT_MASK (0x1 << 7)
+#define RT5616_GP3_OUT_SFT 7
+#define RT5616_GP3_OUT_LO (0x0 << 7)
+#define RT5616_GP3_OUT_HI (0x1 << 7)
+#define RT5616_GP3_P_MASK (0x1 << 6)
+#define RT5616_GP3_P_SFT 6
+#define RT5616_GP3_P_NOR (0x0 << 6)
+#define RT5616_GP3_P_INV (0x1 << 6)
+#define RT5616_GP2_DR_MASK (0x1 << 5)
+#define RT5616_GP2_DR_SFT 5
+#define RT5616_GP2_DR_IN (0x0 << 5)
+#define RT5616_GP2_DR_OUT (0x1 << 5)
+#define RT5616_GP2_OUT_MASK (0x1 << 4)
+#define RT5616_GP2_OUT_SFT 4
+#define RT5616_GP2_OUT_LO (0x0 << 4)
+#define RT5616_GP2_OUT_HI (0x1 << 4)
+#define RT5616_GP2_P_MASK (0x1 << 3)
+#define RT5616_GP2_P_SFT 3
+#define RT5616_GP2_P_NOR (0x0 << 3)
+#define RT5616_GP2_P_INV (0x1 << 3)
+#define RT5616_GP1_DR_MASK (0x1 << 2)
+#define RT5616_GP1_DR_SFT 2
+#define RT5616_GP1_DR_IN (0x0 << 2)
+#define RT5616_GP1_DR_OUT (0x1 << 2)
+#define RT5616_GP1_OUT_MASK (0x1 << 1)
+#define RT5616_GP1_OUT_SFT 1
+#define RT5616_GP1_OUT_LO (0x0 << 1)
+#define RT5616_GP1_OUT_HI (0x1 << 1)
+#define RT5616_GP1_P_MASK (0x1)
+#define RT5616_GP1_P_SFT 0
+#define RT5616_GP1_P_NOR (0x0)
+#define RT5616_GP1_P_INV (0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5616_GP8_DR_MASK (0x1 << 8)
+#define RT5616_GP8_DR_SFT 8
+#define RT5616_GP8_DR_IN (0x0 << 8)
+#define RT5616_GP8_DR_OUT (0x1 << 8)
+#define RT5616_GP8_OUT_MASK (0x1 << 7)
+#define RT5616_GP8_OUT_SFT 7
+#define RT5616_GP8_OUT_LO (0x0 << 7)
+#define RT5616_GP8_OUT_HI (0x1 << 7)
+#define RT5616_GP8_P_MASK (0x1 << 6)
+#define RT5616_GP8_P_SFT 6
+#define RT5616_GP8_P_NOR (0x0 << 6)
+#define RT5616_GP8_P_INV (0x1 << 6)
+#define RT5616_GP7_DR_MASK (0x1 << 5)
+#define RT5616_GP7_DR_SFT 5
+#define RT5616_GP7_DR_IN (0x0 << 5)
+#define RT5616_GP7_DR_OUT (0x1 << 5)
+#define RT5616_GP7_OUT_MASK (0x1 << 4)
+#define RT5616_GP7_OUT_SFT 4
+#define RT5616_GP7_OUT_LO (0x0 << 4)
+#define RT5616_GP7_OUT_HI (0x1 << 4)
+#define RT5616_GP7_P_MASK (0x1 << 3)
+#define RT5616_GP7_P_SFT 3
+#define RT5616_GP7_P_NOR (0x0 << 3)
+#define RT5616_GP7_P_INV (0x1 << 3)
+#define RT5616_GP6_DR_MASK (0x1 << 2)
+#define RT5616_GP6_DR_SFT 2
+#define RT5616_GP6_DR_IN (0x0 << 2)
+#define RT5616_GP6_DR_OUT (0x1 << 2)
+#define RT5616_GP6_OUT_MASK (0x1 << 1)
+#define RT5616_GP6_OUT_SFT 1
+#define RT5616_GP6_OUT_LO (0x0 << 1)
+#define RT5616_GP6_OUT_HI (0x1 << 1)
+#define RT5616_GP6_P_MASK (0x1)
+#define RT5616_GP6_P_SFT 0
+#define RT5616_GP6_P_NOR (0x0)
+#define RT5616_GP6_P_INV (0x1)
+
+/* Scramble Control (0xce) */
+#define RT5616_SCB_SWAP_MASK (0x1 << 15)
+#define RT5616_SCB_SWAP_SFT 15
+#define RT5616_SCB_SWAP_DIS (0x0 << 15)
+#define RT5616_SCB_SWAP_EN (0x1 << 15)
+#define RT5616_SCB_MASK (0x1 << 14)
+#define RT5616_SCB_SFT 14
+#define RT5616_SCB_DIS (0x0 << 14)
+#define RT5616_SCB_EN (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5616_BB_MASK (0x1 << 15)
+#define RT5616_BB_SFT 15
+#define RT5616_BB_DIS (0x0 << 15)
+#define RT5616_BB_EN (0x1 << 15)
+#define RT5616_BB_CT_MASK (0x7 << 12)
+#define RT5616_BB_CT_SFT 12
+#define RT5616_BB_CT_A (0x0 << 12)
+#define RT5616_BB_CT_B (0x1 << 12)
+#define RT5616_BB_CT_C (0x2 << 12)
+#define RT5616_BB_CT_D (0x3 << 12)
+#define RT5616_M_BB_L_MASK (0x1 << 9)
+#define RT5616_M_BB_L_SFT 9
+#define RT5616_M_BB_R_MASK (0x1 << 8)
+#define RT5616_M_BB_R_SFT 8
+#define RT5616_M_BB_HPF_L_MASK (0x1 << 7)
+#define RT5616_M_BB_HPF_L_SFT 7
+#define RT5616_M_BB_HPF_R_MASK (0x1 << 6)
+#define RT5616_M_BB_HPF_R_SFT 6
+#define RT5616_G_BB_BST_MASK (0x3f)
+#define RT5616_G_BB_BST_SFT 0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5616_M_MP3_L_MASK (0x1 << 15)
+#define RT5616_M_MP3_L_SFT 15
+#define RT5616_M_MP3_R_MASK (0x1 << 14)
+#define RT5616_M_MP3_R_SFT 14
+#define RT5616_M_MP3_MASK (0x1 << 13)
+#define RT5616_M_MP3_SFT 13
+#define RT5616_M_MP3_DIS (0x0 << 13)
+#define RT5616_M_MP3_EN (0x1 << 13)
+#define RT5616_EG_MP3_MASK (0x1f << 8)
+#define RT5616_EG_MP3_SFT 8
+#define RT5616_MP3_HLP_MASK (0x1 << 7)
+#define RT5616_MP3_HLP_SFT 7
+#define RT5616_MP3_HLP_DIS (0x0 << 7)
+#define RT5616_MP3_HLP_EN (0x1 << 7)
+#define RT5616_M_MP3_ORG_L_MASK (0x1 << 6)
+#define RT5616_M_MP3_ORG_L_SFT 6
+#define RT5616_M_MP3_ORG_R_MASK (0x1 << 5)
+#define RT5616_M_MP3_ORG_R_SFT 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5616_MP3_WT_MASK (0x1 << 13)
+#define RT5616_MP3_WT_SFT 13
+#define RT5616_MP3_WT_1_4 (0x0 << 13)
+#define RT5616_MP3_WT_1_2 (0x1 << 13)
+#define RT5616_OG_MP3_MASK (0x1f << 8)
+#define RT5616_OG_MP3_SFT 8
+#define RT5616_HG_MP3_MASK (0x3f)
+#define RT5616_HG_MP3_SFT 0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5616_3D_CF_MASK (0x1 << 15)
+#define RT5616_3D_CF_SFT 15
+#define RT5616_3D_CF_DIS (0x0 << 15)
+#define RT5616_3D_CF_EN (0x1 << 15)
+#define RT5616_3D_HP_MASK (0x1 << 14)
+#define RT5616_3D_HP_SFT 14
+#define RT5616_3D_HP_DIS (0x0 << 14)
+#define RT5616_3D_HP_EN (0x1 << 14)
+#define RT5616_3D_BT_MASK (0x1 << 13)
+#define RT5616_3D_BT_SFT 13
+#define RT5616_3D_BT_DIS (0x0 << 13)
+#define RT5616_3D_BT_EN (0x1 << 13)
+#define RT5616_3D_1F_MIX_MASK (0x3 << 11)
+#define RT5616_3D_1F_MIX_SFT 11
+#define RT5616_3D_HP_M_MASK (0x1 << 10)
+#define RT5616_3D_HP_M_SFT 10
+#define RT5616_3D_HP_M_SUR (0x0 << 10)
+#define RT5616_3D_HP_M_FRO (0x1 << 10)
+#define RT5616_M_3D_HRTF_MASK (0x1 << 9)
+#define RT5616_M_3D_HRTF_SFT 9
+#define RT5616_M_3D_D2H_MASK (0x1 << 8)
+#define RT5616_M_3D_D2H_SFT 8
+#define RT5616_M_3D_D2R_MASK (0x1 << 7)
+#define RT5616_M_3D_D2R_SFT 7
+#define RT5616_M_3D_REVB_MASK (0x1 << 6)
+#define RT5616_M_3D_REVB_SFT 6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5616_2ND_HPF_MASK (0x1 << 15)
+#define RT5616_2ND_HPF_SFT 15
+#define RT5616_2ND_HPF_DIS (0x0 << 15)
+#define RT5616_2ND_HPF_EN (0x1 << 15)
+#define RT5616_HPF_CF_L_MASK (0x7 << 12)
+#define RT5616_HPF_CF_L_SFT 12
+#define RT5616_HPF_CF_R_MASK (0x7 << 8)
+#define RT5616_HPF_CF_R_SFT 8
+#define RT5616_ZD_T_MASK (0x3 << 6)
+#define RT5616_ZD_T_SFT 6
+#define RT5616_ZD_F_MASK (0x3 << 4)
+#define RT5616_ZD_F_SFT 4
+#define RT5616_ZD_F_IM (0x0 << 4)
+#define RT5616_ZD_F_ZC_IM (0x1 << 4)
+#define RT5616_ZD_F_ZC_IOD (0x2 << 4)
+#define RT5616_ZD_F_UN (0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5616_HPF_CF_L_NUM_MASK (0x3f << 8)
+#define RT5616_HPF_CF_L_NUM_SFT 8
+#define RT5616_HPF_CF_R_NUM_MASK (0x3f)
+#define RT5616_HPF_CF_R_NUM_SFT 0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5616_SI_DAC_MASK (0x1 << 11)
+#define RT5616_SI_DAC_SFT 11
+#define RT5616_SI_DAC_AUTO (0x0 << 11)
+#define RT5616_SI_DAC_TEST (0x1 << 11)
+#define RT5616_DC_CAL_M_MASK (0x1 << 10)
+#define RT5616_DC_CAL_M_SFT 10
+#define RT5616_DC_CAL_M_NOR (0x0 << 10)
+#define RT5616_DC_CAL_M_CAL (0x1 << 10)
+#define RT5616_DC_CAL_MASK (0x1 << 9)
+#define RT5616_DC_CAL_SFT 9
+#define RT5616_DC_CAL_DIS (0x0 << 9)
+#define RT5616_DC_CAL_EN (0x1 << 9)
+#define RT5616_HPD_RCV_MASK (0x7 << 6)
+#define RT5616_HPD_RCV_SFT 6
+#define RT5616_HPD_PS_MASK (0x1 << 5)
+#define RT5616_HPD_PS_SFT 5
+#define RT5616_HPD_PS_DIS (0x0 << 5)
+#define RT5616_HPD_PS_EN (0x1 << 5)
+#define RT5616_CAL_M_MASK (0x1 << 4)
+#define RT5616_CAL_M_SFT 4
+#define RT5616_CAL_M_DEP (0x0 << 4)
+#define RT5616_CAL_M_CAL (0x1 << 4)
+#define RT5616_CAL_MASK (0x1 << 3)
+#define RT5616_CAL_SFT 3
+#define RT5616_CAL_DIS (0x0 << 3)
+#define RT5616_CAL_EN (0x1 << 3)
+#define RT5616_CAL_TEST_MASK (0x1 << 2)
+#define RT5616_CAL_TEST_SFT 2
+#define RT5616_CAL_TEST_DIS (0x0 << 2)
+#define RT5616_CAL_TEST_EN (0x1 << 2)
+#define RT5616_CAL_P_MASK (0x3)
+#define RT5616_CAL_P_SFT 0
+#define RT5616_CAL_P_NONE (0x0)
+#define RT5616_CAL_P_CAL (0x1)
+#define RT5616_CAL_P_DAC_CAL (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5616_SV_MASK (0x1 << 15)
+#define RT5616_SV_SFT 15
+#define RT5616_SV_DIS (0x0 << 15)
+#define RT5616_SV_EN (0x1 << 15)
+#define RT5616_OUT_SV_MASK (0x1 << 13)
+#define RT5616_OUT_SV_SFT 13
+#define RT5616_OUT_SV_DIS (0x0 << 13)
+#define RT5616_OUT_SV_EN (0x1 << 13)
+#define RT5616_HP_SV_MASK (0x1 << 12)
+#define RT5616_HP_SV_SFT 12
+#define RT5616_HP_SV_DIS (0x0 << 12)
+#define RT5616_HP_SV_EN (0x1 << 12)
+#define RT5616_ZCD_DIG_MASK (0x1 << 11)
+#define RT5616_ZCD_DIG_SFT 11
+#define RT5616_ZCD_DIG_DIS (0x0 << 11)
+#define RT5616_ZCD_DIG_EN (0x1 << 11)
+#define RT5616_ZCD_MASK (0x1 << 10)
+#define RT5616_ZCD_SFT 10
+#define RT5616_ZCD_PD (0x0 << 10)
+#define RT5616_ZCD_PU (0x1 << 10)
+#define RT5616_M_ZCD_MASK (0x3f << 4)
+#define RT5616_M_ZCD_SFT 4
+#define RT5616_M_ZCD_OM_L (0x1 << 7)
+#define RT5616_M_ZCD_OM_R (0x1 << 6)
+#define RT5616_M_ZCD_RM_L (0x1 << 5)
+#define RT5616_M_ZCD_RM_R (0x1 << 4)
+#define RT5616_SV_DLY_MASK (0xf)
+#define RT5616_SV_DLY_SFT 0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5616_ZCD_HP_MASK (0x1 << 15)
+#define RT5616_ZCD_HP_SFT 15
+#define RT5616_ZCD_HP_DIS (0x0 << 15)
+#define RT5616_ZCD_HP_EN (0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5616_I2S2_MS_SP_MASK (0x1 << 8)
+#define RT5616_I2S2_MS_SP_SEL 8
+#define RT5616_I2S2_MS_SP_64 (0x0 << 8)
+#define RT5616_I2S2_MS_SP_50 (0x1 << 8)
+#define RT5616_CLK_DET_EN (0x1 << 3)
+#define RT5616_CLK_DET_EN_SFT 3
+#define RT5616_AMP_DET_EN (0x1 << 1)
+#define RT5616_AMP_DET_EN_SFT 1
+#define RT5616_D_GATE_EN (0x1)
+#define RT5616_D_GATE_EN_SFT 0
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5616_3D_SPK_MASK (0x1 << 15)
+#define RT5616_3D_SPK_SFT 15
+#define RT5616_3D_SPK_DIS (0x0 << 15)
+#define RT5616_3D_SPK_EN (0x1 << 15)
+#define RT5616_3D_SPK_M_MASK (0x3 << 13)
+#define RT5616_3D_SPK_M_SFT 13
+#define RT5616_3D_SPK_CG_MASK (0x1f << 8)
+#define RT5616_3D_SPK_CG_SFT 8
+#define RT5616_3D_SPK_SG_MASK (0x1f)
+#define RT5616_3D_SPK_SG_SFT 0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5616_WND_MASK (0x1 << 15)
+#define RT5616_WND_SFT 15
+#define RT5616_WND_DIS (0x0 << 15)
+#define RT5616_WND_EN (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5616_WND_FC_NW_MASK (0x3f << 10)
+#define RT5616_WND_FC_NW_SFT 10
+#define RT5616_WND_FC_WK_MASK (0x3f << 4)
+#define RT5616_WND_FC_WK_SFT 4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5616_HPF_FC_MASK (0x3f << 6)
+#define RT5616_HPF_FC_SFT 6
+#define RT5616_WND_FC_ST_MASK (0x3f)
+#define RT5616_WND_FC_ST_SFT 0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5616_WND_TH_LO_MASK (0x3ff)
+#define RT5616_WND_TH_LO_SFT 0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5616_WND_TH_HI_MASK (0x3ff)
+#define RT5616_WND_TH_HI_SFT 0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5616_WND_WIND_MASK (0x1 << 13) /* Read-Only */
+#define RT5616_WND_WIND_SFT 13
+#define RT5616_WND_STRONG_MASK (0x1 << 12) /* Read-Only */
+#define RT5616_WND_STRONG_SFT 12
+enum {
+ RT5616_NO_WIND,
+ RT5616_BREEZE,
+ RT5616_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5616_DP_ATT_MASK (0x3 << 14)
+#define RT5616_DP_ATT_SFT 14
+#define RT5616_DP_SPK_MASK (0x1 << 10)
+#define RT5616_DP_SPK_SFT 10
+#define RT5616_DP_SPK_DIS (0x0 << 10)
+#define RT5616_DP_SPK_EN (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5616_EQ_PRE_VOL_MASK (0xffff)
+#define RT5616_EQ_PRE_VOL_SFT 0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5616_EQ_PST_VOL_MASK (0xffff)
+#define RT5616_EQ_PST_VOL_SFT 0
+
+/* System Clock Source */
+enum {
+ RT5616_SCLK_S_MCLK,
+ RT5616_SCLK_S_PLL1,
+};
+
+/* PLL1 Source */
+enum {
+ RT5616_PLL1_S_MCLK,
+ RT5616_PLL1_S_BCLK1,
+ RT5616_PLL1_S_BCLK2,
+};
+
+enum {
+ RT5616_AIF1,
+ RT5616_AIFS,
+};
+
+#endif /* __RT5616_H__ */
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index f2beb1aa5763..11d032cdc658 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -488,6 +488,18 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
return 0;
}
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ if (!rt5640->asrc_en)
+ return 0;
+
+ return 1;
+}
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
@@ -1059,6 +1071,20 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
+
+ /* ASRC */
+ SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
+ 15, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1,
+ 12, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1,
+ 11, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1,
+ 9, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1,
+ 8, 0, NULL, 0),
+
+
/* Input Side */
/* micbias */
SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
@@ -1319,6 +1345,12 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
+ { "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc },
+ { "I2S2", NULL, "I2S2 ASRC", is_using_asrc },
+ { "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc },
+ { "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc },
+ { "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc },
+
{"IN1P", NULL, "LDO2"},
{"IN2P", NULL, "LDO2"},
{"IN3P", NULL, "LDO2"},
@@ -1981,6 +2013,76 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
+int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int asrc2_mask = 0;
+ unsigned int asrc2_value = 0;
+
+ switch (clk_src) {
+ case RT5640_CLK_SEL_SYS:
+ case RT5640_CLK_SEL_ASRC:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (!filter_mask)
+ return -EINVAL;
+
+ if (filter_mask & RT5640_DA_STEREO_FILTER) {
+ asrc2_mask |= RT5640_STO_DAC_M_MASK;
+ asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK)
+ | (clk_src << RT5640_STO_DAC_M_SFT);
+ }
+
+ if (filter_mask & RT5640_DA_MONO_L_FILTER) {
+ asrc2_mask |= RT5640_MDA_L_M_MASK;
+ asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK)
+ | (clk_src << RT5640_MDA_L_M_SFT);
+ }
+
+ if (filter_mask & RT5640_DA_MONO_R_FILTER) {
+ asrc2_mask |= RT5640_MDA_R_M_MASK;
+ asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK)
+ | (clk_src << RT5640_MDA_R_M_SFT);
+ }
+
+ if (filter_mask & RT5640_AD_STEREO_FILTER) {
+ asrc2_mask |= RT5640_ADC_M_MASK;
+ asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK)
+ | (clk_src << RT5640_ADC_M_SFT);
+ }
+
+ if (filter_mask & RT5640_AD_MONO_L_FILTER) {
+ asrc2_mask |= RT5640_MAD_L_M_MASK;
+ asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK)
+ | (clk_src << RT5640_MAD_L_M_SFT);
+ }
+
+ if (filter_mask & RT5640_AD_MONO_R_FILTER) {
+ asrc2_mask |= RT5640_MAD_R_M_MASK;
+ asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK)
+ | (clk_src << RT5640_MAD_R_M_SFT);
+ }
+
+ snd_soc_update_bits(codec, RT5640_ASRC_2,
+ asrc2_mask, asrc2_value);
+
+ if (snd_soc_read(codec, RT5640_ASRC_2)) {
+ rt5640->asrc_en = true;
+ snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3);
+ } else {
+ rt5640->asrc_en = false;
+ snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
+
static int rt5640_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -2175,6 +2277,7 @@ static const struct acpi_device_id rt5640_acpi_match[] = {
{ "INT33CA", 0 },
{ "10EC5640", 0 },
{ "10EC5642", 0 },
+ { "INTCCFFD", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 3deb8babeabb..83a7150ddc24 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -1033,6 +1033,10 @@
#define RT5640_DMIC_2_M_NOR (0x0 << 8)
#define RT5640_DMIC_2_M_ASYN (0x1 << 8)
+/* ASRC clock source selection (0x84) */
+#define RT5640_CLK_SEL_SYS (0x0)
+#define RT5640_CLK_SEL_ASRC (0x1)
+
/* ASRC Control 2 (0x84) */
#define RT5640_MDA_L_M_MASK (0x1 << 15)
#define RT5640_MDA_L_M_SFT 15
@@ -2079,6 +2083,16 @@ enum {
RT5640_DMIC2,
};
+/* filter mask */
+enum {
+ RT5640_DA_STEREO_FILTER = 0x1,
+ RT5640_DA_MONO_L_FILTER = (0x1 << 1),
+ RT5640_DA_MONO_R_FILTER = (0x1 << 2),
+ RT5640_AD_STEREO_FILTER = (0x1 << 3),
+ RT5640_AD_MONO_L_FILTER = (0x1 << 4),
+ RT5640_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
struct rt5640_priv {
struct snd_soc_codec *codec;
struct rt5640_platform_data pdata;
@@ -2095,9 +2109,12 @@ struct rt5640_priv {
int pll_out;
bool hp_mute;
+ bool asrc_en;
};
int rt5640_dmic_enable(struct snd_soc_codec *codec,
bool dmic1_data_pin, bool dmic2_data_pin);
+int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src);
#endif
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 3e3c7f6be29d..c61d38b585fb 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -64,7 +64,6 @@ static const struct reg_sequence init_list[] = {
{RT5645_PR_BASE + 0x21, 0x4040},
{RT5645_PR_BASE + 0x23, 0x0004},
};
-#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
static const struct reg_sequence rt5650_init_list[] = {
{0xf6, 0x0100},
@@ -226,6 +225,163 @@ static const struct reg_default rt5645_reg[] = {
{ 0xff, 0x6308 },
};
+static const struct reg_default rt5650_reg[] = {
+ { 0x00, 0x0000 },
+ { 0x01, 0xc8c8 },
+ { 0x02, 0xc8c8 },
+ { 0x03, 0xc8c8 },
+ { 0x0a, 0x0002 },
+ { 0x0b, 0x2827 },
+ { 0x0c, 0xe000 },
+ { 0x0d, 0x0000 },
+ { 0x0e, 0x0000 },
+ { 0x0f, 0x0808 },
+ { 0x14, 0x3333 },
+ { 0x16, 0x4b00 },
+ { 0x18, 0x018b },
+ { 0x19, 0xafaf },
+ { 0x1a, 0xafaf },
+ { 0x1b, 0x0001 },
+ { 0x1c, 0x2f2f },
+ { 0x1d, 0x2f2f },
+ { 0x1e, 0x0000 },
+ { 0x20, 0x0000 },
+ { 0x27, 0x7060 },
+ { 0x28, 0x7070 },
+ { 0x29, 0x8080 },
+ { 0x2a, 0x5656 },
+ { 0x2b, 0x5454 },
+ { 0x2c, 0xaaa0 },
+ { 0x2d, 0x0000 },
+ { 0x2f, 0x1002 },
+ { 0x31, 0x5000 },
+ { 0x32, 0x0000 },
+ { 0x33, 0x0000 },
+ { 0x34, 0x0000 },
+ { 0x35, 0x0000 },
+ { 0x3b, 0x0000 },
+ { 0x3c, 0x007f },
+ { 0x3d, 0x0000 },
+ { 0x3e, 0x007f },
+ { 0x3f, 0x0000 },
+ { 0x40, 0x001f },
+ { 0x41, 0x0000 },
+ { 0x42, 0x001f },
+ { 0x45, 0x6000 },
+ { 0x46, 0x003e },
+ { 0x47, 0x003e },
+ { 0x48, 0xf807 },
+ { 0x4a, 0x0004 },
+ { 0x4d, 0x0000 },
+ { 0x4e, 0x0000 },
+ { 0x4f, 0x01ff },
+ { 0x50, 0x0000 },
+ { 0x51, 0x0000 },
+ { 0x52, 0x01ff },
+ { 0x53, 0xf000 },
+ { 0x56, 0x0111 },
+ { 0x57, 0x0064 },
+ { 0x58, 0xef0e },
+ { 0x59, 0xf0f0 },
+ { 0x5a, 0xef0e },
+ { 0x5b, 0xf0f0 },
+ { 0x5c, 0xef0e },
+ { 0x5d, 0xf0f0 },
+ { 0x5e, 0xf000 },
+ { 0x5f, 0x0000 },
+ { 0x61, 0x0300 },
+ { 0x62, 0x0000 },
+ { 0x63, 0x00c2 },
+ { 0x64, 0x0000 },
+ { 0x65, 0x0000 },
+ { 0x66, 0x0000 },
+ { 0x6a, 0x0000 },
+ { 0x6c, 0x0aaa },
+ { 0x70, 0x8000 },
+ { 0x71, 0x8000 },
+ { 0x72, 0x8000 },
+ { 0x73, 0x7770 },
+ { 0x74, 0x3e00 },
+ { 0x75, 0x2409 },
+ { 0x76, 0x000a },
+ { 0x77, 0x0c00 },
+ { 0x78, 0x0000 },
+ { 0x79, 0x0123 },
+ { 0x7a, 0x0123 },
+ { 0x80, 0x0000 },
+ { 0x81, 0x0000 },
+ { 0x82, 0x0000 },
+ { 0x83, 0x0000 },
+ { 0x84, 0x0000 },
+ { 0x85, 0x0000 },
+ { 0x8a, 0x0000 },
+ { 0x8e, 0x0004 },
+ { 0x8f, 0x1100 },
+ { 0x90, 0x0646 },
+ { 0x91, 0x0c06 },
+ { 0x93, 0x0000 },
+ { 0x94, 0x0200 },
+ { 0x95, 0x0000 },
+ { 0x9a, 0x2184 },
+ { 0x9b, 0x010a },
+ { 0x9c, 0x0aea },
+ { 0x9d, 0x000c },
+ { 0x9e, 0x0400 },
+ { 0xa0, 0xa0a8 },
+ { 0xa1, 0x0059 },
+ { 0xa2, 0x0001 },
+ { 0xae, 0x6000 },
+ { 0xaf, 0x0000 },
+ { 0xb0, 0x6000 },
+ { 0xb1, 0x0000 },
+ { 0xb2, 0x0000 },
+ { 0xb3, 0x001f },
+ { 0xb4, 0x020c },
+ { 0xb5, 0x1f00 },
+ { 0xb6, 0x0000 },
+ { 0xbb, 0x0000 },
+ { 0xbc, 0x0000 },
+ { 0xbd, 0x0000 },
+ { 0xbe, 0x0000 },
+ { 0xbf, 0x3100 },
+ { 0xc0, 0x0000 },
+ { 0xc1, 0x0000 },
+ { 0xc2, 0x0000 },
+ { 0xc3, 0x2000 },
+ { 0xcd, 0x0000 },
+ { 0xce, 0x0000 },
+ { 0xcf, 0x1813 },
+ { 0xd0, 0x0690 },
+ { 0xd1, 0x1c17 },
+ { 0xd3, 0xb320 },
+ { 0xd4, 0x0000 },
+ { 0xd6, 0x0400 },
+ { 0xd9, 0x0809 },
+ { 0xda, 0x0000 },
+ { 0xdb, 0x0003 },
+ { 0xdc, 0x0049 },
+ { 0xdd, 0x001b },
+ { 0xdf, 0x0008 },
+ { 0xe0, 0x4000 },
+ { 0xe6, 0x8000 },
+ { 0xe7, 0x0200 },
+ { 0xec, 0xb300 },
+ { 0xed, 0x0000 },
+ { 0xf0, 0x001f },
+ { 0xf1, 0x020c },
+ { 0xf2, 0x1f00 },
+ { 0xf3, 0x0000 },
+ { 0xf4, 0x4000 },
+ { 0xf8, 0x0000 },
+ { 0xf9, 0x0000 },
+ { 0xfa, 0x2060 },
+ { 0xfb, 0x4040 },
+ { 0xfc, 0x0000 },
+ { 0xfd, 0x0002 },
+ { 0xfe, 0x10ec },
+ { 0xff, 0x6308 },
+};
+
struct rt5645_eq_param_s {
unsigned short reg;
unsigned short val;
@@ -248,6 +404,7 @@ struct rt5645_priv {
struct delayed_work jack_detect_work, rcclock_work;
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
struct rt5645_eq_param_s *eq_param;
+ struct timer_list btn_check_timer;
int codec_type;
int sysclk;
@@ -572,14 +729,12 @@ static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol,
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
int ret;
- cancel_delayed_work_sync(&rt5645->rcclock_work);
-
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU);
ret = snd_soc_put_volsw(kcontrol, ucontrol);
- queue_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
+ mod_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
msecs_to_jiffies(200));
return ret;
@@ -2911,6 +3066,7 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
snd_soc_dapm_sync(dapm);
+ snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
snd_soc_update_bits(codec,
RT5645_INT_IRQ_ST, 0x8, 0x8);
snd_soc_update_bits(codec,
@@ -2979,7 +3135,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
}
if (rt5645->pdata.jd_invert)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
- RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+ RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
} else { /* jack out */
rt5645->jack_type = 0;
@@ -3000,7 +3156,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
snd_soc_dapm_sync(dapm);
if (rt5645->pdata.jd_invert)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
- RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+ RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
}
return rt5645->jack_type;
@@ -3124,6 +3280,12 @@ static void rt5645_jack_detect_work(struct work_struct *work)
}
if (btn_type == 0)/* button release */
report = rt5645->jack_type;
+ else {
+ if (rt5645->pdata.jd_invert) {
+ mod_timer(&rt5645->btn_check_timer,
+ msecs_to_jiffies(100));
+ }
+ }
break;
/* jack out */
@@ -3166,6 +3328,14 @@ static irqreturn_t rt5645_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static void rt5645_btn_check_callback(unsigned long data)
+{
+ struct rt5645_priv *rt5645 = (struct rt5645_priv *)data;
+
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5645->jack_detect_work, msecs_to_jiffies(5));
+}
+
static int rt5645_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -3322,6 +3492,31 @@ static const struct regmap_config rt5645_regmap = {
.num_ranges = ARRAY_SIZE(rt5645_ranges),
};
+static const struct regmap_config rt5650_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .use_single_rw = true,
+ .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) *
+ RT5645_PR_SPACING),
+ .volatile_reg = rt5645_volatile_register,
+ .readable_reg = rt5645_readable_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5650_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5650_reg),
+ .ranges = rt5645_ranges,
+ .num_ranges = ARRAY_SIZE(rt5645_ranges),
+};
+
+static const struct regmap_config temp_regmap = {
+ .name="nocache",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .use_single_rw = true,
+ .max_register = RT5645_VENDOR_ID2 + 1,
+ .cache_type = REGCACHE_NONE,
+};
+
static const struct i2c_device_id rt5645_i2c_id[] = {
{ "rt5645", 0 },
{ "rt5650", 0 },
@@ -3330,7 +3525,7 @@ static const struct i2c_device_id rt5645_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
#ifdef CONFIG_ACPI
-static struct acpi_device_id rt5645_acpi_match[] = {
+static const struct acpi_device_id rt5645_acpi_match[] = {
{ "10EC5645", 0 },
{ "10EC5650", 0 },
{},
@@ -3338,69 +3533,23 @@ static struct acpi_device_id rt5645_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
#endif
-static struct rt5645_platform_data *rt5645_pdata;
-
-static struct rt5645_platform_data strago_platform_data = {
+static struct rt5645_platform_data general_platform_data = {
.dmic1_data_pin = RT5645_DMIC1_DISABLE,
.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
.jd_mode = 3,
};
-static int strago_quirk_cb(const struct dmi_system_id *id)
-{
- rt5645_pdata = &strago_platform_data;
-
- return 1;
-}
-
static const struct dmi_system_id dmi_platform_intel_braswell[] = {
{
.ident = "Intel Strago",
- .callback = strago_quirk_cb,
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
},
},
{
- .ident = "Google Celes",
- .callback = strago_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
- },
- },
- {
- .ident = "Google Ultima",
- .callback = strago_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Ultima"),
- },
- },
- {
- .ident = "Google Reks",
- .callback = strago_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Reks"),
- },
- },
- {
- .ident = "Google Edgar",
- .callback = strago_quirk_cb,
+ .ident = "Google Chrome",
.matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"),
- },
- },
- {
- .ident = "Google Wizpig",
- .callback = strago_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"),
- },
- },
- {
- .ident = "Google Terra",
- .callback = strago_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Terra"),
+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
},
},
{ }
@@ -3413,17 +3562,9 @@ static struct rt5645_platform_data buddy_platform_data = {
.jd_invert = true,
};
-static int buddy_quirk_cb(const struct dmi_system_id *id)
-{
- rt5645_pdata = &buddy_platform_data;
-
- return 1;
-}
-
static struct dmi_system_id dmi_platform_intel_broadwell[] = {
{
.ident = "Chrome Buddy",
- .callback = buddy_quirk_cb,
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
},
@@ -3431,6 +3572,16 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = {
{ }
};
+static bool rt5645_check_dp(struct device *dev)
+{
+ if (device_property_present(dev, "realtek,in2-differential") ||
+ device_property_present(dev, "realtek,dmic1-data-pin") ||
+ device_property_present(dev, "realtek,dmic2-data-pin") ||
+ device_property_present(dev, "realtek,jd-mode"))
+ return true;
+
+ return false;
+}
static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
{
@@ -3453,6 +3604,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
struct rt5645_priv *rt5645;
int ret, i;
unsigned int val;
+ struct regmap *regmap;
rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
GFP_KERNEL);
@@ -3464,11 +3616,12 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5645->pdata = *pdata;
- else if (dmi_check_system(dmi_platform_intel_braswell) ||
- dmi_check_system(dmi_platform_intel_broadwell))
- rt5645->pdata = *rt5645_pdata;
- else
+ else if (dmi_check_system(dmi_platform_intel_broadwell))
+ rt5645->pdata = buddy_platform_data;
+ else if (rt5645_check_dp(&i2c->dev))
rt5645_parse_dt(rt5645, &i2c->dev);
+ else if (dmi_check_system(dmi_platform_intel_braswell))
+ rt5645->pdata = general_platform_data;
rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
GPIOD_IN);
@@ -3478,14 +3631,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
return PTR_ERR(rt5645->gpiod_hp_det);
}
- rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
- if (IS_ERR(rt5645->regmap)) {
- ret = PTR_ERR(rt5645->regmap);
- dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
- ret);
- return ret;
- }
-
for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
rt5645->supplies[i].supply = rt5645_supply_names[i];
@@ -3504,13 +3649,22 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
return ret;
}
- regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
+ 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;
+ }
+ regmap_read(regmap, RT5645_VENDOR_ID2, &val);
switch (val) {
case RT5645_DEVICE_ID:
+ rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
rt5645->codec_type = CODEC_TYPE_RT5645;
break;
case RT5650_DEVICE_ID:
+ rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5650_regmap);
rt5645->codec_type = CODEC_TYPE_RT5650;
break;
default:
@@ -3521,6 +3675,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
goto err_enable;
}
+ if (IS_ERR(rt5645->regmap)) {
+ ret = PTR_ERR(rt5645->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
regmap_write(rt5645->regmap, RT5645_RESET, 0);
ret = regmap_register_patch(rt5645->regmap, init_list,
@@ -3641,6 +3802,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
}
}
+ if (rt5645->pdata.jd_invert) {
+ regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+ RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+ setup_timer(&rt5645->btn_check_timer,
+ rt5645_btn_check_callback, (unsigned long)rt5645);
+ }
+
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 1d4031818966..7a6197042423 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -18,6 +18,7 @@
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -1735,12 +1736,38 @@ static const struct regmap_config rt5651_regmap = {
.num_ranges = ARRAY_SIZE(rt5651_ranges),
};
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5651_of_match[] = {
+ { .compatible = "realtek,rt5651", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt5651_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5651_acpi_match[] = {
+ { "10EC5651", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match);
+#endif
+
static const struct i2c_device_id rt5651_i2c_id[] = {
{ "rt5651", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
+static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np)
+{
+ rt5651->pdata.in2_diff = of_property_read_bool(np,
+ "realtek,in2-differential");
+ rt5651->pdata.dmic_en = of_property_read_bool(np,
+ "realtek,dmic-en");
+
+ return 0;
+}
+
static int rt5651_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1757,6 +1784,8 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5651->pdata = *pdata;
+ else if (i2c->dev.of_node)
+ rt5651_parse_dt(rt5651, i2c->dev.of_node);
rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
if (IS_ERR(rt5651->regmap)) {
@@ -1806,6 +1835,8 @@ static int rt5651_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt5651_i2c_driver = {
.driver = {
.name = "rt5651",
+ .acpi_match_table = ACPI_PTR(rt5651_acpi_match),
+ .of_match_table = of_match_ptr(rt5651_of_match),
},
.probe = rt5651_i2c_probe,
.remove = rt5651_i2c_remove,
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
new file mode 100644
index 000000000000..820d8fa62b5e
--- /dev/null
+++ b/sound/soc/codecs/rt5659.c
@@ -0,0 +1,4223 @@
+/*
+ * rt5659.c -- RT5659/RT5658 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5659.h>
+
+#include "rl6231.h"
+#include "rt5659.h"
+
+static const struct reg_default rt5659_reg[] = {
+ { 0x0000, 0x0000 },
+ { 0x0001, 0x4848 },
+ { 0x0002, 0x8080 },
+ { 0x0003, 0xc8c8 },
+ { 0x0004, 0xc80a },
+ { 0x0005, 0x0000 },
+ { 0x0006, 0x0000 },
+ { 0x0007, 0x0103 },
+ { 0x0008, 0x0080 },
+ { 0x0009, 0x0000 },
+ { 0x000a, 0x0000 },
+ { 0x000c, 0x0000 },
+ { 0x000d, 0x0000 },
+ { 0x000f, 0x0808 },
+ { 0x0010, 0x3080 },
+ { 0x0011, 0x4a00 },
+ { 0x0012, 0x4e00 },
+ { 0x0015, 0x42c1 },
+ { 0x0016, 0x0000 },
+ { 0x0018, 0x000b },
+ { 0x0019, 0xafaf },
+ { 0x001a, 0xafaf },
+ { 0x001b, 0x0011 },
+ { 0x001c, 0x2f2f },
+ { 0x001d, 0x2f2f },
+ { 0x001e, 0x2f2f },
+ { 0x001f, 0x0000 },
+ { 0x0020, 0x0000 },
+ { 0x0021, 0x0000 },
+ { 0x0022, 0x5757 },
+ { 0x0023, 0x0039 },
+ { 0x0026, 0xc060 },
+ { 0x0027, 0xd8d8 },
+ { 0x0029, 0x8080 },
+ { 0x002a, 0xaaaa },
+ { 0x002b, 0xaaaa },
+ { 0x002c, 0x00af },
+ { 0x002d, 0x0000 },
+ { 0x002f, 0x1002 },
+ { 0x0031, 0x5000 },
+ { 0x0032, 0x0000 },
+ { 0x0033, 0x0000 },
+ { 0x0034, 0x0000 },
+ { 0x0035, 0x0000 },
+ { 0x0036, 0x0000 },
+ { 0x003a, 0x0000 },
+ { 0x003b, 0x0000 },
+ { 0x003c, 0x007f },
+ { 0x003d, 0x0000 },
+ { 0x003e, 0x007f },
+ { 0x0040, 0x0808 },
+ { 0x0046, 0x001f },
+ { 0x0047, 0x001f },
+ { 0x0048, 0x0003 },
+ { 0x0049, 0xe061 },
+ { 0x004a, 0x0000 },
+ { 0x004b, 0x031f },
+ { 0x004d, 0x0000 },
+ { 0x004e, 0x001f },
+ { 0x004f, 0x0000 },
+ { 0x0050, 0x001f },
+ { 0x0052, 0xf000 },
+ { 0x0053, 0x0111 },
+ { 0x0054, 0x0064 },
+ { 0x0055, 0x0080 },
+ { 0x0056, 0xef0e },
+ { 0x0057, 0xf0f0 },
+ { 0x0058, 0xef0e },
+ { 0x0059, 0xf0f0 },
+ { 0x005a, 0xef0e },
+ { 0x005b, 0xf0f0 },
+ { 0x005c, 0xf000 },
+ { 0x005d, 0x0000 },
+ { 0x005e, 0x1f2c },
+ { 0x005f, 0x1f2c },
+ { 0x0060, 0x2717 },
+ { 0x0061, 0x0000 },
+ { 0x0062, 0x0000 },
+ { 0x0063, 0x003e },
+ { 0x0064, 0x0000 },
+ { 0x0065, 0x0000 },
+ { 0x0066, 0x0000 },
+ { 0x0067, 0x0000 },
+ { 0x006a, 0x0000 },
+ { 0x006b, 0x0000 },
+ { 0x006c, 0x0000 },
+ { 0x006e, 0x0000 },
+ { 0x006f, 0x0000 },
+ { 0x0070, 0x8000 },
+ { 0x0071, 0x8000 },
+ { 0x0072, 0x8000 },
+ { 0x0073, 0x1110 },
+ { 0x0074, 0xfe00 },
+ { 0x0075, 0x2409 },
+ { 0x0076, 0x000a },
+ { 0x0077, 0x00f0 },
+ { 0x0078, 0x0000 },
+ { 0x0079, 0x0000 },
+ { 0x007a, 0x0123 },
+ { 0x007b, 0x8003 },
+ { 0x0080, 0x0000 },
+ { 0x0081, 0x0000 },
+ { 0x0082, 0x0000 },
+ { 0x0083, 0x0000 },
+ { 0x0084, 0x0000 },
+ { 0x0085, 0x0000 },
+ { 0x0086, 0x0008 },
+ { 0x0087, 0x0000 },
+ { 0x0088, 0x0000 },
+ { 0x0089, 0x0000 },
+ { 0x008a, 0x0000 },
+ { 0x008b, 0x0000 },
+ { 0x008c, 0x0003 },
+ { 0x008e, 0x0000 },
+ { 0x008f, 0x1000 },
+ { 0x0090, 0x0646 },
+ { 0x0091, 0x0c16 },
+ { 0x0092, 0x0073 },
+ { 0x0093, 0x0000 },
+ { 0x0094, 0x0080 },
+ { 0x0097, 0x0000 },
+ { 0x0098, 0x0000 },
+ { 0x0099, 0x0000 },
+ { 0x009a, 0x0000 },
+ { 0x009b, 0x0000 },
+ { 0x009c, 0x007f },
+ { 0x009d, 0x0000 },
+ { 0x009e, 0x007f },
+ { 0x009f, 0x0000 },
+ { 0x00a0, 0x0060 },
+ { 0x00a1, 0x90a1 },
+ { 0x00ae, 0x2000 },
+ { 0x00af, 0x0000 },
+ { 0x00b0, 0x2000 },
+ { 0x00b1, 0x0000 },
+ { 0x00b2, 0x0000 },
+ { 0x00b6, 0x0000 },
+ { 0x00b7, 0x0000 },
+ { 0x00b8, 0x0000 },
+ { 0x00b9, 0x0000 },
+ { 0x00ba, 0x0000 },
+ { 0x00bb, 0x0000 },
+ { 0x00be, 0x0000 },
+ { 0x00bf, 0x0000 },
+ { 0x00c0, 0x0000 },
+ { 0x00c1, 0x0000 },
+ { 0x00c2, 0x0000 },
+ { 0x00c3, 0x0000 },
+ { 0x00c4, 0x0003 },
+ { 0x00c5, 0x0000 },
+ { 0x00cb, 0xa02f },
+ { 0x00cc, 0x0000 },
+ { 0x00cd, 0x0e02 },
+ { 0x00d6, 0x0000 },
+ { 0x00d7, 0x2244 },
+ { 0x00d9, 0x0809 },
+ { 0x00da, 0x0000 },
+ { 0x00db, 0x0008 },
+ { 0x00dc, 0x00c0 },
+ { 0x00dd, 0x6724 },
+ { 0x00de, 0x3131 },
+ { 0x00df, 0x0008 },
+ { 0x00e0, 0x4000 },
+ { 0x00e1, 0x3131 },
+ { 0x00e4, 0x400c },
+ { 0x00e5, 0x8031 },
+ { 0x00ea, 0xb320 },
+ { 0x00eb, 0x0000 },
+ { 0x00ec, 0xb300 },
+ { 0x00ed, 0x0000 },
+ { 0x00f0, 0x0000 },
+ { 0x00f1, 0x0202 },
+ { 0x00f2, 0x0ddd },
+ { 0x00f3, 0x0ddd },
+ { 0x00f4, 0x0ddd },
+ { 0x00f6, 0x0000 },
+ { 0x00f7, 0x0000 },
+ { 0x00f8, 0x0000 },
+ { 0x00f9, 0x0000 },
+ { 0x00fa, 0x8000 },
+ { 0x00fb, 0x0000 },
+ { 0x00fc, 0x0000 },
+ { 0x00fd, 0x0001 },
+ { 0x00fe, 0x10ec },
+ { 0x00ff, 0x6311 },
+ { 0x0100, 0xaaaa },
+ { 0x010a, 0xaaaa },
+ { 0x010b, 0x00a0 },
+ { 0x010c, 0xaeae },
+ { 0x010d, 0xaaaa },
+ { 0x010e, 0xaaa8 },
+ { 0x010f, 0xa0aa },
+ { 0x0110, 0xe02a },
+ { 0x0111, 0xa702 },
+ { 0x0112, 0xaaaa },
+ { 0x0113, 0x2800 },
+ { 0x0116, 0x0000 },
+ { 0x0117, 0x0f00 },
+ { 0x011a, 0x0020 },
+ { 0x011b, 0x0011 },
+ { 0x011c, 0x0150 },
+ { 0x011d, 0x0000 },
+ { 0x011e, 0x0000 },
+ { 0x011f, 0x0000 },
+ { 0x0120, 0x0000 },
+ { 0x0121, 0x009b },
+ { 0x0122, 0x5014 },
+ { 0x0123, 0x0421 },
+ { 0x0124, 0x7cea },
+ { 0x0125, 0x0420 },
+ { 0x0126, 0x5550 },
+ { 0x0132, 0x0000 },
+ { 0x0133, 0x0000 },
+ { 0x0137, 0x5055 },
+ { 0x0138, 0x3700 },
+ { 0x0139, 0x79a1 },
+ { 0x013a, 0x2020 },
+ { 0x013b, 0x2020 },
+ { 0x013c, 0x2005 },
+ { 0x013e, 0x1f00 },
+ { 0x013f, 0x0000 },
+ { 0x0145, 0x0002 },
+ { 0x0146, 0x0000 },
+ { 0x0147, 0x0000 },
+ { 0x0148, 0x0000 },
+ { 0x0150, 0x1813 },
+ { 0x0151, 0x0690 },
+ { 0x0152, 0x1c17 },
+ { 0x0153, 0x6883 },
+ { 0x0154, 0xd3ce },
+ { 0x0155, 0x352d },
+ { 0x0156, 0x00eb },
+ { 0x0157, 0x3717 },
+ { 0x0158, 0x4c6a },
+ { 0x0159, 0xe41b },
+ { 0x015a, 0x2a13 },
+ { 0x015b, 0xb600 },
+ { 0x015c, 0xc730 },
+ { 0x015d, 0x35d4 },
+ { 0x015e, 0x00bf },
+ { 0x0160, 0x0ec0 },
+ { 0x0161, 0x0020 },
+ { 0x0162, 0x0080 },
+ { 0x0163, 0x0800 },
+ { 0x0164, 0x0000 },
+ { 0x0165, 0x0000 },
+ { 0x0166, 0x0000 },
+ { 0x0167, 0x001f },
+ { 0x0170, 0x4e80 },
+ { 0x0171, 0x0020 },
+ { 0x0172, 0x0080 },
+ { 0x0173, 0x0800 },
+ { 0x0174, 0x000c },
+ { 0x0175, 0x0000 },
+ { 0x0190, 0x3300 },
+ { 0x0191, 0x2200 },
+ { 0x0192, 0x0000 },
+ { 0x01b0, 0x4b38 },
+ { 0x01b1, 0x0000 },
+ { 0x01b2, 0x0000 },
+ { 0x01b3, 0x0000 },
+ { 0x01c0, 0x0045 },
+ { 0x01c1, 0x0540 },
+ { 0x01c2, 0x0000 },
+ { 0x01c3, 0x0030 },
+ { 0x01c7, 0x0000 },
+ { 0x01c8, 0x5757 },
+ { 0x01c9, 0x5757 },
+ { 0x01ca, 0x5757 },
+ { 0x01cb, 0x5757 },
+ { 0x01cc, 0x5757 },
+ { 0x01cd, 0x5757 },
+ { 0x01ce, 0x006f },
+ { 0x01da, 0x0000 },
+ { 0x01db, 0x0000 },
+ { 0x01de, 0x7d00 },
+ { 0x01df, 0x10c0 },
+ { 0x01e0, 0x06a1 },
+ { 0x01e1, 0x0000 },
+ { 0x01e2, 0x0000 },
+ { 0x01e3, 0x0000 },
+ { 0x01e4, 0x0001 },
+ { 0x01e6, 0x0000 },
+ { 0x01e7, 0x0000 },
+ { 0x01e8, 0x0000 },
+ { 0x01ea, 0x0000 },
+ { 0x01eb, 0x0000 },
+ { 0x01ec, 0x0000 },
+ { 0x01ed, 0x0000 },
+ { 0x01ee, 0x0000 },
+ { 0x01ef, 0x0000 },
+ { 0x01f0, 0x0000 },
+ { 0x01f1, 0x0000 },
+ { 0x01f2, 0x0000 },
+ { 0x01f6, 0x1e04 },
+ { 0x01f7, 0x01a1 },
+ { 0x01f8, 0x0000 },
+ { 0x01f9, 0x0000 },
+ { 0x01fa, 0x0002 },
+ { 0x01fb, 0x0000 },
+ { 0x01fc, 0x0000 },
+ { 0x01fd, 0x0000 },
+ { 0x01fe, 0x0000 },
+ { 0x0200, 0x066c },
+ { 0x0201, 0x7fff },
+ { 0x0202, 0x7fff },
+ { 0x0203, 0x0000 },
+ { 0x0204, 0x0000 },
+ { 0x0205, 0x0000 },
+ { 0x0206, 0x0000 },
+ { 0x0207, 0x0000 },
+ { 0x0208, 0x0000 },
+ { 0x0256, 0x0000 },
+ { 0x0257, 0x0000 },
+ { 0x0258, 0x0000 },
+ { 0x0259, 0x0000 },
+ { 0x025a, 0x0000 },
+ { 0x025b, 0x3333 },
+ { 0x025c, 0x3333 },
+ { 0x025d, 0x3333 },
+ { 0x025e, 0x0000 },
+ { 0x025f, 0x0000 },
+ { 0x0260, 0x0000 },
+ { 0x0261, 0x0022 },
+ { 0x0262, 0x0300 },
+ { 0x0265, 0x1e80 },
+ { 0x0266, 0x0131 },
+ { 0x0267, 0x0003 },
+ { 0x0268, 0x0000 },
+ { 0x0269, 0x0000 },
+ { 0x026a, 0x0000 },
+ { 0x026b, 0x0000 },
+ { 0x026c, 0x0000 },
+ { 0x026d, 0x0000 },
+ { 0x026e, 0x0000 },
+ { 0x026f, 0x0000 },
+ { 0x0270, 0x0000 },
+ { 0x0271, 0x0000 },
+ { 0x0272, 0x0000 },
+ { 0x0273, 0x0000 },
+ { 0x0280, 0x0000 },
+ { 0x0281, 0x0000 },
+ { 0x0282, 0x0418 },
+ { 0x0283, 0x7fff },
+ { 0x0284, 0x7000 },
+ { 0x0290, 0x01d0 },
+ { 0x0291, 0x0100 },
+ { 0x02fa, 0x0000 },
+ { 0x02fb, 0x0000 },
+ { 0x02fc, 0x0000 },
+ { 0x0300, 0x001f },
+ { 0x0301, 0x032c },
+ { 0x0302, 0x5f21 },
+ { 0x0303, 0x4000 },
+ { 0x0304, 0x4000 },
+ { 0x0305, 0x0600 },
+ { 0x0306, 0x8000 },
+ { 0x0307, 0x0700 },
+ { 0x0308, 0x001f },
+ { 0x0309, 0x032c },
+ { 0x030a, 0x5f21 },
+ { 0x030b, 0x4000 },
+ { 0x030c, 0x4000 },
+ { 0x030d, 0x0600 },
+ { 0x030e, 0x8000 },
+ { 0x030f, 0x0700 },
+ { 0x0310, 0x4560 },
+ { 0x0311, 0xa4a8 },
+ { 0x0312, 0x7418 },
+ { 0x0313, 0x0000 },
+ { 0x0314, 0x0006 },
+ { 0x0315, 0x00ff },
+ { 0x0316, 0xc400 },
+ { 0x0317, 0x4560 },
+ { 0x0318, 0xa4a8 },
+ { 0x0319, 0x7418 },
+ { 0x031a, 0x0000 },
+ { 0x031b, 0x0006 },
+ { 0x031c, 0x00ff },
+ { 0x031d, 0xc400 },
+ { 0x0320, 0x0f20 },
+ { 0x0321, 0x8700 },
+ { 0x0322, 0x7dc2 },
+ { 0x0323, 0xa178 },
+ { 0x0324, 0x5383 },
+ { 0x0325, 0x7dc2 },
+ { 0x0326, 0xa178 },
+ { 0x0327, 0x5383 },
+ { 0x0328, 0x003e },
+ { 0x0329, 0x02c1 },
+ { 0x032a, 0xd37d },
+ { 0x0330, 0x00a6 },
+ { 0x0331, 0x04c3 },
+ { 0x0332, 0x27c8 },
+ { 0x0333, 0xbf50 },
+ { 0x0334, 0x0045 },
+ { 0x0335, 0x2007 },
+ { 0x0336, 0x7418 },
+ { 0x0337, 0x0501 },
+ { 0x0338, 0x0000 },
+ { 0x0339, 0x0010 },
+ { 0x033a, 0x1010 },
+ { 0x0340, 0x0800 },
+ { 0x0341, 0x0800 },
+ { 0x0342, 0x0800 },
+ { 0x0343, 0x0800 },
+ { 0x0344, 0x0000 },
+ { 0x0345, 0x0000 },
+ { 0x0346, 0x0000 },
+ { 0x0347, 0x0000 },
+ { 0x0348, 0x0000 },
+ { 0x0349, 0x0000 },
+ { 0x034a, 0x0000 },
+ { 0x034b, 0x0000 },
+ { 0x034c, 0x0000 },
+ { 0x034d, 0x0000 },
+ { 0x034e, 0x0000 },
+ { 0x034f, 0x0000 },
+ { 0x0350, 0x0000 },
+ { 0x0351, 0x0000 },
+ { 0x0352, 0x0000 },
+ { 0x0353, 0x0000 },
+ { 0x0354, 0x0000 },
+ { 0x0355, 0x0000 },
+ { 0x0356, 0x0000 },
+ { 0x0357, 0x0000 },
+ { 0x0358, 0x0000 },
+ { 0x0359, 0x0000 },
+ { 0x035a, 0x0000 },
+ { 0x035b, 0x0000 },
+ { 0x035c, 0x0000 },
+ { 0x035d, 0x0000 },
+ { 0x035e, 0x2000 },
+ { 0x035f, 0x0000 },
+ { 0x0360, 0x2000 },
+ { 0x0361, 0x2000 },
+ { 0x0362, 0x0000 },
+ { 0x0363, 0x2000 },
+ { 0x0364, 0x0200 },
+ { 0x0365, 0x0000 },
+ { 0x0366, 0x0000 },
+ { 0x0367, 0x0000 },
+ { 0x0368, 0x0000 },
+ { 0x0369, 0x0000 },
+ { 0x036a, 0x0000 },
+ { 0x036b, 0x0000 },
+ { 0x036c, 0x0000 },
+ { 0x036d, 0x0000 },
+ { 0x036e, 0x0200 },
+ { 0x036f, 0x0000 },
+ { 0x0370, 0x0000 },
+ { 0x0371, 0x0000 },
+ { 0x0372, 0x0000 },
+ { 0x0373, 0x0000 },
+ { 0x0374, 0x0000 },
+ { 0x0375, 0x0000 },
+ { 0x0376, 0x0000 },
+ { 0x0377, 0x0000 },
+ { 0x03d0, 0x0000 },
+ { 0x03d1, 0x0000 },
+ { 0x03d2, 0x0000 },
+ { 0x03d3, 0x0000 },
+ { 0x03d4, 0x2000 },
+ { 0x03d5, 0x2000 },
+ { 0x03d6, 0x0000 },
+ { 0x03d7, 0x0000 },
+ { 0x03d8, 0x2000 },
+ { 0x03d9, 0x2000 },
+ { 0x03da, 0x2000 },
+ { 0x03db, 0x2000 },
+ { 0x03dc, 0x0000 },
+ { 0x03dd, 0x0000 },
+ { 0x03de, 0x0000 },
+ { 0x03df, 0x2000 },
+ { 0x03e0, 0x0000 },
+ { 0x03e1, 0x0000 },
+ { 0x03e2, 0x0000 },
+ { 0x03e3, 0x0000 },
+ { 0x03e4, 0x0000 },
+ { 0x03e5, 0x0000 },
+ { 0x03e6, 0x0000 },
+ { 0x03e7, 0x0000 },
+ { 0x03e8, 0x0000 },
+ { 0x03e9, 0x0000 },
+ { 0x03ea, 0x0000 },
+ { 0x03eb, 0x0000 },
+ { 0x03ec, 0x0000 },
+ { 0x03ed, 0x0000 },
+ { 0x03ee, 0x0000 },
+ { 0x03ef, 0x0000 },
+ { 0x03f0, 0x0800 },
+ { 0x03f1, 0x0800 },
+ { 0x03f2, 0x0800 },
+ { 0x03f3, 0x0800 },
+};
+
+static bool rt5659_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5659_RESET:
+ case RT5659_EJD_CTRL_2:
+ case RT5659_SILENCE_CTRL:
+ case RT5659_DAC2_DIG_VOL:
+ case RT5659_HP_IMP_GAIN_2:
+ case RT5659_PDM_OUT_CTRL:
+ case RT5659_PDM_DATA_CTRL_1:
+ case RT5659_PDM_DATA_CTRL_4:
+ case RT5659_HAPTIC_GEN_CTRL_1:
+ case RT5659_HAPTIC_GEN_CTRL_3:
+ case RT5659_HAPTIC_LPF_CTRL_3:
+ case RT5659_CLK_DET:
+ case RT5659_MICBIAS_1:
+ case RT5659_ASRC_11:
+ case RT5659_ADC_EQ_CTRL_1:
+ case RT5659_DAC_EQ_CTRL_1:
+ case RT5659_INT_ST_1:
+ case RT5659_INT_ST_2:
+ case RT5659_GPIO_STA:
+ case RT5659_SINE_GEN_CTRL_1:
+ case RT5659_IL_CMD_1:
+ case RT5659_4BTN_IL_CMD_1:
+ case RT5659_PSV_IL_CMD_1:
+ case RT5659_AJD1_CTRL:
+ case RT5659_AJD2_AJD3_CTRL:
+ case RT5659_JD_CTRL_3:
+ case RT5659_VENDOR_ID:
+ case RT5659_VENDOR_ID_1:
+ case RT5659_DEVICE_ID:
+ case RT5659_MEMORY_TEST:
+ case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+ case RT5659_VOL_TEST:
+ case RT5659_STO_NG2_CTRL_1:
+ case RT5659_STO_NG2_CTRL_5:
+ case RT5659_STO_NG2_CTRL_6:
+ case RT5659_STO_NG2_CTRL_7:
+ case RT5659_MONO_NG2_CTRL_1:
+ case RT5659_MONO_NG2_CTRL_5:
+ case RT5659_MONO_NG2_CTRL_6:
+ case RT5659_HP_IMP_SENS_CTRL_1:
+ case RT5659_HP_IMP_SENS_CTRL_3:
+ case RT5659_HP_IMP_SENS_CTRL_4:
+ case RT5659_HP_CALIB_CTRL_1:
+ case RT5659_HP_CALIB_CTRL_9:
+ case RT5659_HP_CALIB_STA_1:
+ case RT5659_HP_CALIB_STA_2:
+ case RT5659_HP_CALIB_STA_3:
+ case RT5659_HP_CALIB_STA_4:
+ case RT5659_HP_CALIB_STA_5:
+ case RT5659_HP_CALIB_STA_6:
+ case RT5659_HP_CALIB_STA_7:
+ case RT5659_HP_CALIB_STA_8:
+ case RT5659_HP_CALIB_STA_9:
+ case RT5659_MONO_AMP_CALIB_CTRL_1:
+ case RT5659_MONO_AMP_CALIB_CTRL_3:
+ case RT5659_MONO_AMP_CALIB_STA_1:
+ case RT5659_MONO_AMP_CALIB_STA_2:
+ case RT5659_MONO_AMP_CALIB_STA_3:
+ case RT5659_MONO_AMP_CALIB_STA_4:
+ case RT5659_SPK_PWR_LMT_STA_1:
+ case RT5659_SPK_PWR_LMT_STA_2:
+ case RT5659_SPK_PWR_LMT_STA_3:
+ case RT5659_SPK_PWR_LMT_STA_4:
+ case RT5659_SPK_PWR_LMT_STA_5:
+ case RT5659_SPK_PWR_LMT_STA_6:
+ case RT5659_SPK_DC_CAILB_CTRL_1:
+ case RT5659_SPK_DC_CAILB_STA_1:
+ case RT5659_SPK_DC_CAILB_STA_2:
+ case RT5659_SPK_DC_CAILB_STA_3:
+ case RT5659_SPK_DC_CAILB_STA_4:
+ case RT5659_SPK_DC_CAILB_STA_5:
+ case RT5659_SPK_DC_CAILB_STA_6:
+ case RT5659_SPK_DC_CAILB_STA_7:
+ case RT5659_SPK_DC_CAILB_STA_8:
+ case RT5659_SPK_DC_CAILB_STA_9:
+ case RT5659_SPK_DC_CAILB_STA_10:
+ case RT5659_SPK_VDD_STA_1:
+ case RT5659_SPK_VDD_STA_2:
+ case RT5659_SPK_DC_DET_CTRL_1:
+ case RT5659_PURE_DC_DET_CTRL_1:
+ case RT5659_PURE_DC_DET_CTRL_2:
+ case RT5659_DRC1_PRIV_1:
+ case RT5659_DRC1_PRIV_4:
+ case RT5659_DRC1_PRIV_5:
+ case RT5659_DRC1_PRIV_6:
+ case RT5659_DRC1_PRIV_7:
+ case RT5659_DRC2_PRIV_1:
+ case RT5659_DRC2_PRIV_4:
+ case RT5659_DRC2_PRIV_5:
+ case RT5659_DRC2_PRIV_6:
+ case RT5659_DRC2_PRIV_7:
+ case RT5659_ALC_PGA_STA_1:
+ case RT5659_ALC_PGA_STA_2:
+ case RT5659_ALC_PGA_STA_3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt5659_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5659_RESET:
+ case RT5659_SPO_VOL:
+ case RT5659_HP_VOL:
+ case RT5659_LOUT:
+ case RT5659_MONO_OUT:
+ case RT5659_HPL_GAIN:
+ case RT5659_HPR_GAIN:
+ case RT5659_MONO_GAIN:
+ case RT5659_SPDIF_CTRL_1:
+ case RT5659_SPDIF_CTRL_2:
+ case RT5659_CAL_BST_CTRL:
+ case RT5659_IN1_IN2:
+ case RT5659_IN3_IN4:
+ case RT5659_INL1_INR1_VOL:
+ case RT5659_EJD_CTRL_1:
+ case RT5659_EJD_CTRL_2:
+ case RT5659_EJD_CTRL_3:
+ case RT5659_SILENCE_CTRL:
+ case RT5659_PSV_CTRL:
+ case RT5659_SIDETONE_CTRL:
+ case RT5659_DAC1_DIG_VOL:
+ case RT5659_DAC2_DIG_VOL:
+ case RT5659_DAC_CTRL:
+ case RT5659_STO1_ADC_DIG_VOL:
+ case RT5659_MONO_ADC_DIG_VOL:
+ case RT5659_STO2_ADC_DIG_VOL:
+ case RT5659_STO1_BOOST:
+ case RT5659_MONO_BOOST:
+ case RT5659_STO2_BOOST:
+ case RT5659_HP_IMP_GAIN_1:
+ case RT5659_HP_IMP_GAIN_2:
+ case RT5659_STO1_ADC_MIXER:
+ case RT5659_MONO_ADC_MIXER:
+ case RT5659_AD_DA_MIXER:
+ case RT5659_STO_DAC_MIXER:
+ case RT5659_MONO_DAC_MIXER:
+ case RT5659_DIG_MIXER:
+ case RT5659_A_DAC_MUX:
+ case RT5659_DIG_INF23_DATA:
+ case RT5659_PDM_OUT_CTRL:
+ case RT5659_PDM_DATA_CTRL_1:
+ case RT5659_PDM_DATA_CTRL_2:
+ case RT5659_PDM_DATA_CTRL_3:
+ case RT5659_PDM_DATA_CTRL_4:
+ case RT5659_SPDIF_CTRL:
+ case RT5659_REC1_GAIN:
+ case RT5659_REC1_L1_MIXER:
+ case RT5659_REC1_L2_MIXER:
+ case RT5659_REC1_R1_MIXER:
+ case RT5659_REC1_R2_MIXER:
+ case RT5659_CAL_REC:
+ case RT5659_REC2_L1_MIXER:
+ case RT5659_REC2_L2_MIXER:
+ case RT5659_REC2_R1_MIXER:
+ case RT5659_REC2_R2_MIXER:
+ case RT5659_SPK_L_MIXER:
+ case RT5659_SPK_R_MIXER:
+ case RT5659_SPO_AMP_GAIN:
+ case RT5659_ALC_BACK_GAIN:
+ case RT5659_MONOMIX_GAIN:
+ case RT5659_MONOMIX_IN_GAIN:
+ case RT5659_OUT_L_GAIN:
+ case RT5659_OUT_L_MIXER:
+ case RT5659_OUT_R_GAIN:
+ case RT5659_OUT_R_MIXER:
+ case RT5659_LOUT_MIXER:
+ case RT5659_HAPTIC_GEN_CTRL_1:
+ case RT5659_HAPTIC_GEN_CTRL_2:
+ case RT5659_HAPTIC_GEN_CTRL_3:
+ case RT5659_HAPTIC_GEN_CTRL_4:
+ case RT5659_HAPTIC_GEN_CTRL_5:
+ case RT5659_HAPTIC_GEN_CTRL_6:
+ case RT5659_HAPTIC_GEN_CTRL_7:
+ case RT5659_HAPTIC_GEN_CTRL_8:
+ case RT5659_HAPTIC_GEN_CTRL_9:
+ case RT5659_HAPTIC_GEN_CTRL_10:
+ case RT5659_HAPTIC_GEN_CTRL_11:
+ case RT5659_HAPTIC_LPF_CTRL_1:
+ case RT5659_HAPTIC_LPF_CTRL_2:
+ case RT5659_HAPTIC_LPF_CTRL_3:
+ case RT5659_PWR_DIG_1:
+ case RT5659_PWR_DIG_2:
+ case RT5659_PWR_ANLG_1:
+ case RT5659_PWR_ANLG_2:
+ case RT5659_PWR_ANLG_3:
+ case RT5659_PWR_MIXER:
+ case RT5659_PWR_VOL:
+ case RT5659_PRIV_INDEX:
+ case RT5659_CLK_DET:
+ case RT5659_PRIV_DATA:
+ case RT5659_PRE_DIV_1:
+ case RT5659_PRE_DIV_2:
+ case RT5659_I2S1_SDP:
+ case RT5659_I2S2_SDP:
+ case RT5659_I2S3_SDP:
+ case RT5659_ADDA_CLK_1:
+ case RT5659_ADDA_CLK_2:
+ case RT5659_DMIC_CTRL_1:
+ case RT5659_DMIC_CTRL_2:
+ case RT5659_TDM_CTRL_1:
+ case RT5659_TDM_CTRL_2:
+ case RT5659_TDM_CTRL_3:
+ case RT5659_TDM_CTRL_4:
+ case RT5659_TDM_CTRL_5:
+ case RT5659_GLB_CLK:
+ case RT5659_PLL_CTRL_1:
+ case RT5659_PLL_CTRL_2:
+ case RT5659_ASRC_1:
+ case RT5659_ASRC_2:
+ case RT5659_ASRC_3:
+ case RT5659_ASRC_4:
+ case RT5659_ASRC_5:
+ case RT5659_ASRC_6:
+ case RT5659_ASRC_7:
+ case RT5659_ASRC_8:
+ case RT5659_ASRC_9:
+ case RT5659_ASRC_10:
+ case RT5659_DEPOP_1:
+ case RT5659_DEPOP_2:
+ case RT5659_DEPOP_3:
+ case RT5659_HP_CHARGE_PUMP_1:
+ case RT5659_HP_CHARGE_PUMP_2:
+ case RT5659_MICBIAS_1:
+ case RT5659_MICBIAS_2:
+ case RT5659_ASRC_11:
+ case RT5659_ASRC_12:
+ case RT5659_ASRC_13:
+ case RT5659_REC_M1_M2_GAIN_CTRL:
+ case RT5659_RC_CLK_CTRL:
+ case RT5659_CLASSD_CTRL_1:
+ case RT5659_CLASSD_CTRL_2:
+ case RT5659_ADC_EQ_CTRL_1:
+ case RT5659_ADC_EQ_CTRL_2:
+ case RT5659_DAC_EQ_CTRL_1:
+ case RT5659_DAC_EQ_CTRL_2:
+ case RT5659_DAC_EQ_CTRL_3:
+ case RT5659_IRQ_CTRL_1:
+ case RT5659_IRQ_CTRL_2:
+ case RT5659_IRQ_CTRL_3:
+ case RT5659_IRQ_CTRL_4:
+ case RT5659_IRQ_CTRL_5:
+ case RT5659_IRQ_CTRL_6:
+ case RT5659_INT_ST_1:
+ case RT5659_INT_ST_2:
+ case RT5659_GPIO_CTRL_1:
+ case RT5659_GPIO_CTRL_2:
+ case RT5659_GPIO_CTRL_3:
+ case RT5659_GPIO_CTRL_4:
+ case RT5659_GPIO_CTRL_5:
+ case RT5659_GPIO_STA:
+ case RT5659_SINE_GEN_CTRL_1:
+ case RT5659_SINE_GEN_CTRL_2:
+ case RT5659_SINE_GEN_CTRL_3:
+ case RT5659_HP_AMP_DET_CTRL_1:
+ case RT5659_HP_AMP_DET_CTRL_2:
+ case RT5659_SV_ZCD_1:
+ case RT5659_SV_ZCD_2:
+ case RT5659_IL_CMD_1:
+ case RT5659_IL_CMD_2:
+ case RT5659_IL_CMD_3:
+ case RT5659_IL_CMD_4:
+ case RT5659_4BTN_IL_CMD_1:
+ case RT5659_4BTN_IL_CMD_2:
+ case RT5659_4BTN_IL_CMD_3:
+ case RT5659_PSV_IL_CMD_1:
+ case RT5659_PSV_IL_CMD_2:
+ case RT5659_ADC_STO1_HP_CTRL_1:
+ case RT5659_ADC_STO1_HP_CTRL_2:
+ case RT5659_ADC_MONO_HP_CTRL_1:
+ case RT5659_ADC_MONO_HP_CTRL_2:
+ case RT5659_AJD1_CTRL:
+ case RT5659_AJD2_AJD3_CTRL:
+ case RT5659_JD1_THD:
+ case RT5659_JD2_THD:
+ case RT5659_JD3_THD:
+ case RT5659_JD_CTRL_1:
+ case RT5659_JD_CTRL_2:
+ case RT5659_JD_CTRL_3:
+ case RT5659_JD_CTRL_4:
+ case RT5659_DIG_MISC:
+ case RT5659_DUMMY_2:
+ case RT5659_DUMMY_3:
+ case RT5659_VENDOR_ID:
+ case RT5659_VENDOR_ID_1:
+ case RT5659_DEVICE_ID:
+ case RT5659_DAC_ADC_DIG_VOL:
+ case RT5659_BIAS_CUR_CTRL_1:
+ case RT5659_BIAS_CUR_CTRL_2:
+ case RT5659_BIAS_CUR_CTRL_3:
+ case RT5659_BIAS_CUR_CTRL_4:
+ case RT5659_BIAS_CUR_CTRL_5:
+ case RT5659_BIAS_CUR_CTRL_6:
+ case RT5659_BIAS_CUR_CTRL_7:
+ case RT5659_BIAS_CUR_CTRL_8:
+ case RT5659_BIAS_CUR_CTRL_9:
+ case RT5659_BIAS_CUR_CTRL_10:
+ case RT5659_MEMORY_TEST:
+ case RT5659_VREF_REC_OP_FB_CAP_CTRL:
+ case RT5659_CLASSD_0:
+ case RT5659_CLASSD_1:
+ case RT5659_CLASSD_2:
+ case RT5659_CLASSD_3:
+ case RT5659_CLASSD_4:
+ case RT5659_CLASSD_5:
+ case RT5659_CLASSD_6:
+ case RT5659_CLASSD_7:
+ case RT5659_CLASSD_8:
+ case RT5659_CLASSD_9:
+ case RT5659_CLASSD_10:
+ case RT5659_CHARGE_PUMP_1:
+ case RT5659_CHARGE_PUMP_2:
+ case RT5659_DIG_IN_CTRL_1:
+ case RT5659_DIG_IN_CTRL_2:
+ case RT5659_PAD_DRIVING_CTRL:
+ case RT5659_SOFT_RAMP_DEPOP:
+ case RT5659_PLL:
+ case RT5659_CHOP_DAC:
+ case RT5659_CHOP_ADC:
+ case RT5659_CALIB_ADC_CTRL:
+ case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+ case RT5659_VOL_TEST:
+ case RT5659_TEST_MODE_CTRL_1:
+ case RT5659_TEST_MODE_CTRL_2:
+ case RT5659_TEST_MODE_CTRL_3:
+ case RT5659_TEST_MODE_CTRL_4:
+ case RT5659_BASSBACK_CTRL:
+ case RT5659_MP3_PLUS_CTRL_1:
+ case RT5659_MP3_PLUS_CTRL_2:
+ case RT5659_MP3_HPF_A1:
+ case RT5659_MP3_HPF_A2:
+ case RT5659_MP3_HPF_H0:
+ case RT5659_MP3_LPF_H0:
+ case RT5659_3D_SPK_CTRL:
+ case RT5659_3D_SPK_COEF_1:
+ case RT5659_3D_SPK_COEF_2:
+ case RT5659_3D_SPK_COEF_3:
+ case RT5659_3D_SPK_COEF_4:
+ case RT5659_3D_SPK_COEF_5:
+ case RT5659_3D_SPK_COEF_6:
+ case RT5659_3D_SPK_COEF_7:
+ case RT5659_STO_NG2_CTRL_1:
+ case RT5659_STO_NG2_CTRL_2:
+ case RT5659_STO_NG2_CTRL_3:
+ case RT5659_STO_NG2_CTRL_4:
+ case RT5659_STO_NG2_CTRL_5:
+ case RT5659_STO_NG2_CTRL_6:
+ case RT5659_STO_NG2_CTRL_7:
+ case RT5659_STO_NG2_CTRL_8:
+ case RT5659_MONO_NG2_CTRL_1:
+ case RT5659_MONO_NG2_CTRL_2:
+ case RT5659_MONO_NG2_CTRL_3:
+ case RT5659_MONO_NG2_CTRL_4:
+ case RT5659_MONO_NG2_CTRL_5:
+ case RT5659_MONO_NG2_CTRL_6:
+ case RT5659_MID_HP_AMP_DET:
+ case RT5659_LOW_HP_AMP_DET:
+ case RT5659_LDO_CTRL:
+ case RT5659_HP_DECROSS_CTRL_1:
+ case RT5659_HP_DECROSS_CTRL_2:
+ case RT5659_HP_DECROSS_CTRL_3:
+ case RT5659_HP_DECROSS_CTRL_4:
+ case RT5659_HP_IMP_SENS_CTRL_1:
+ case RT5659_HP_IMP_SENS_CTRL_2:
+ case RT5659_HP_IMP_SENS_CTRL_3:
+ case RT5659_HP_IMP_SENS_CTRL_4:
+ case RT5659_HP_IMP_SENS_MAP_1:
+ case RT5659_HP_IMP_SENS_MAP_2:
+ case RT5659_HP_IMP_SENS_MAP_3:
+ case RT5659_HP_IMP_SENS_MAP_4:
+ case RT5659_HP_IMP_SENS_MAP_5:
+ case RT5659_HP_IMP_SENS_MAP_6:
+ case RT5659_HP_IMP_SENS_MAP_7:
+ case RT5659_HP_IMP_SENS_MAP_8:
+ case RT5659_HP_LOGIC_CTRL_1:
+ case RT5659_HP_LOGIC_CTRL_2:
+ case RT5659_HP_CALIB_CTRL_1:
+ case RT5659_HP_CALIB_CTRL_2:
+ case RT5659_HP_CALIB_CTRL_3:
+ case RT5659_HP_CALIB_CTRL_4:
+ case RT5659_HP_CALIB_CTRL_5:
+ case RT5659_HP_CALIB_CTRL_6:
+ case RT5659_HP_CALIB_CTRL_7:
+ case RT5659_HP_CALIB_CTRL_9:
+ case RT5659_HP_CALIB_CTRL_10:
+ case RT5659_HP_CALIB_CTRL_11:
+ case RT5659_HP_CALIB_STA_1:
+ case RT5659_HP_CALIB_STA_2:
+ case RT5659_HP_CALIB_STA_3:
+ case RT5659_HP_CALIB_STA_4:
+ case RT5659_HP_CALIB_STA_5:
+ case RT5659_HP_CALIB_STA_6:
+ case RT5659_HP_CALIB_STA_7:
+ case RT5659_HP_CALIB_STA_8:
+ case RT5659_HP_CALIB_STA_9:
+ case RT5659_MONO_AMP_CALIB_CTRL_1:
+ case RT5659_MONO_AMP_CALIB_CTRL_2:
+ case RT5659_MONO_AMP_CALIB_CTRL_3:
+ case RT5659_MONO_AMP_CALIB_CTRL_4:
+ case RT5659_MONO_AMP_CALIB_CTRL_5:
+ case RT5659_MONO_AMP_CALIB_STA_1:
+ case RT5659_MONO_AMP_CALIB_STA_2:
+ case RT5659_MONO_AMP_CALIB_STA_3:
+ case RT5659_MONO_AMP_CALIB_STA_4:
+ case RT5659_SPK_PWR_LMT_CTRL_1:
+ case RT5659_SPK_PWR_LMT_CTRL_2:
+ case RT5659_SPK_PWR_LMT_CTRL_3:
+ case RT5659_SPK_PWR_LMT_STA_1:
+ case RT5659_SPK_PWR_LMT_STA_2:
+ case RT5659_SPK_PWR_LMT_STA_3:
+ case RT5659_SPK_PWR_LMT_STA_4:
+ case RT5659_SPK_PWR_LMT_STA_5:
+ case RT5659_SPK_PWR_LMT_STA_6:
+ case RT5659_FLEX_SPK_BST_CTRL_1:
+ case RT5659_FLEX_SPK_BST_CTRL_2:
+ case RT5659_FLEX_SPK_BST_CTRL_3:
+ case RT5659_FLEX_SPK_BST_CTRL_4:
+ case RT5659_SPK_EX_LMT_CTRL_1:
+ case RT5659_SPK_EX_LMT_CTRL_2:
+ case RT5659_SPK_EX_LMT_CTRL_3:
+ case RT5659_SPK_EX_LMT_CTRL_4:
+ case RT5659_SPK_EX_LMT_CTRL_5:
+ case RT5659_SPK_EX_LMT_CTRL_6:
+ case RT5659_SPK_EX_LMT_CTRL_7:
+ case RT5659_ADJ_HPF_CTRL_1:
+ case RT5659_ADJ_HPF_CTRL_2:
+ case RT5659_SPK_DC_CAILB_CTRL_1:
+ case RT5659_SPK_DC_CAILB_CTRL_2:
+ case RT5659_SPK_DC_CAILB_CTRL_3:
+ case RT5659_SPK_DC_CAILB_CTRL_4:
+ case RT5659_SPK_DC_CAILB_CTRL_5:
+ case RT5659_SPK_DC_CAILB_STA_1:
+ case RT5659_SPK_DC_CAILB_STA_2:
+ case RT5659_SPK_DC_CAILB_STA_3:
+ case RT5659_SPK_DC_CAILB_STA_4:
+ case RT5659_SPK_DC_CAILB_STA_5:
+ case RT5659_SPK_DC_CAILB_STA_6:
+ case RT5659_SPK_DC_CAILB_STA_7:
+ case RT5659_SPK_DC_CAILB_STA_8:
+ case RT5659_SPK_DC_CAILB_STA_9:
+ case RT5659_SPK_DC_CAILB_STA_10:
+ case RT5659_SPK_VDD_STA_1:
+ case RT5659_SPK_VDD_STA_2:
+ case RT5659_SPK_DC_DET_CTRL_1:
+ case RT5659_SPK_DC_DET_CTRL_2:
+ case RT5659_SPK_DC_DET_CTRL_3:
+ case RT5659_PURE_DC_DET_CTRL_1:
+ case RT5659_PURE_DC_DET_CTRL_2:
+ case RT5659_DUMMY_4:
+ case RT5659_DUMMY_5:
+ case RT5659_DUMMY_6:
+ case RT5659_DRC1_CTRL_1:
+ case RT5659_DRC1_CTRL_2:
+ case RT5659_DRC1_CTRL_3:
+ case RT5659_DRC1_CTRL_4:
+ case RT5659_DRC1_CTRL_5:
+ case RT5659_DRC1_CTRL_6:
+ case RT5659_DRC1_HARD_LMT_CTRL_1:
+ case RT5659_DRC1_HARD_LMT_CTRL_2:
+ case RT5659_DRC2_CTRL_1:
+ case RT5659_DRC2_CTRL_2:
+ case RT5659_DRC2_CTRL_3:
+ case RT5659_DRC2_CTRL_4:
+ case RT5659_DRC2_CTRL_5:
+ case RT5659_DRC2_CTRL_6:
+ case RT5659_DRC2_HARD_LMT_CTRL_1:
+ case RT5659_DRC2_HARD_LMT_CTRL_2:
+ case RT5659_DRC1_PRIV_1:
+ case RT5659_DRC1_PRIV_2:
+ case RT5659_DRC1_PRIV_3:
+ case RT5659_DRC1_PRIV_4:
+ case RT5659_DRC1_PRIV_5:
+ case RT5659_DRC1_PRIV_6:
+ case RT5659_DRC1_PRIV_7:
+ case RT5659_DRC2_PRIV_1:
+ case RT5659_DRC2_PRIV_2:
+ case RT5659_DRC2_PRIV_3:
+ case RT5659_DRC2_PRIV_4:
+ case RT5659_DRC2_PRIV_5:
+ case RT5659_DRC2_PRIV_6:
+ case RT5659_DRC2_PRIV_7:
+ case RT5659_MULTI_DRC_CTRL:
+ case RT5659_CROSS_OVER_1:
+ case RT5659_CROSS_OVER_2:
+ case RT5659_CROSS_OVER_3:
+ case RT5659_CROSS_OVER_4:
+ case RT5659_CROSS_OVER_5:
+ case RT5659_CROSS_OVER_6:
+ case RT5659_CROSS_OVER_7:
+ case RT5659_CROSS_OVER_8:
+ case RT5659_CROSS_OVER_9:
+ case RT5659_CROSS_OVER_10:
+ case RT5659_ALC_PGA_CTRL_1:
+ case RT5659_ALC_PGA_CTRL_2:
+ case RT5659_ALC_PGA_CTRL_3:
+ case RT5659_ALC_PGA_CTRL_4:
+ case RT5659_ALC_PGA_CTRL_5:
+ case RT5659_ALC_PGA_CTRL_6:
+ case RT5659_ALC_PGA_CTRL_7:
+ case RT5659_ALC_PGA_CTRL_8:
+ case RT5659_ALC_PGA_STA_1:
+ case RT5659_ALC_PGA_STA_2:
+ case RT5659_ALC_PGA_STA_3:
+ case RT5659_DAC_L_EQ_PRE_VOL:
+ case RT5659_DAC_R_EQ_PRE_VOL:
+ case RT5659_DAC_L_EQ_POST_VOL:
+ case RT5659_DAC_R_EQ_POST_VOL:
+ case RT5659_DAC_L_EQ_LPF1_A1:
+ case RT5659_DAC_L_EQ_LPF1_H0:
+ case RT5659_DAC_R_EQ_LPF1_A1:
+ case RT5659_DAC_R_EQ_LPF1_H0:
+ case RT5659_DAC_L_EQ_BPF2_A1:
+ case RT5659_DAC_L_EQ_BPF2_A2:
+ case RT5659_DAC_L_EQ_BPF2_H0:
+ case RT5659_DAC_R_EQ_BPF2_A1:
+ case RT5659_DAC_R_EQ_BPF2_A2:
+ case RT5659_DAC_R_EQ_BPF2_H0:
+ case RT5659_DAC_L_EQ_BPF3_A1:
+ case RT5659_DAC_L_EQ_BPF3_A2:
+ case RT5659_DAC_L_EQ_BPF3_H0:
+ case RT5659_DAC_R_EQ_BPF3_A1:
+ case RT5659_DAC_R_EQ_BPF3_A2:
+ case RT5659_DAC_R_EQ_BPF3_H0:
+ case RT5659_DAC_L_EQ_BPF4_A1:
+ case RT5659_DAC_L_EQ_BPF4_A2:
+ case RT5659_DAC_L_EQ_BPF4_H0:
+ case RT5659_DAC_R_EQ_BPF4_A1:
+ case RT5659_DAC_R_EQ_BPF4_A2:
+ case RT5659_DAC_R_EQ_BPF4_H0:
+ case RT5659_DAC_L_EQ_HPF1_A1:
+ case RT5659_DAC_L_EQ_HPF1_H0:
+ case RT5659_DAC_R_EQ_HPF1_A1:
+ case RT5659_DAC_R_EQ_HPF1_H0:
+ case RT5659_DAC_L_EQ_HPF2_A1:
+ case RT5659_DAC_L_EQ_HPF2_A2:
+ case RT5659_DAC_L_EQ_HPF2_H0:
+ case RT5659_DAC_R_EQ_HPF2_A1:
+ case RT5659_DAC_R_EQ_HPF2_A2:
+ case RT5659_DAC_R_EQ_HPF2_H0:
+ case RT5659_DAC_L_BI_EQ_BPF1_H0_1:
+ case RT5659_DAC_L_BI_EQ_BPF1_H0_2:
+ case RT5659_DAC_L_BI_EQ_BPF1_B1_1:
+ case RT5659_DAC_L_BI_EQ_BPF1_B1_2:
+ case RT5659_DAC_L_BI_EQ_BPF1_B2_1:
+ case RT5659_DAC_L_BI_EQ_BPF1_B2_2:
+ case RT5659_DAC_L_BI_EQ_BPF1_A1_1:
+ case RT5659_DAC_L_BI_EQ_BPF1_A1_2:
+ case RT5659_DAC_L_BI_EQ_BPF1_A2_1:
+ case RT5659_DAC_L_BI_EQ_BPF1_A2_2:
+ case RT5659_DAC_R_BI_EQ_BPF1_H0_1:
+ case RT5659_DAC_R_BI_EQ_BPF1_H0_2:
+ case RT5659_DAC_R_BI_EQ_BPF1_B1_1:
+ case RT5659_DAC_R_BI_EQ_BPF1_B1_2:
+ case RT5659_DAC_R_BI_EQ_BPF1_B2_1:
+ case RT5659_DAC_R_BI_EQ_BPF1_B2_2:
+ case RT5659_DAC_R_BI_EQ_BPF1_A1_1:
+ case RT5659_DAC_R_BI_EQ_BPF1_A1_2:
+ case RT5659_DAC_R_BI_EQ_BPF1_A2_1:
+ case RT5659_DAC_R_BI_EQ_BPF1_A2_2:
+ case RT5659_ADC_L_EQ_LPF1_A1:
+ case RT5659_ADC_R_EQ_LPF1_A1:
+ case RT5659_ADC_L_EQ_LPF1_H0:
+ case RT5659_ADC_R_EQ_LPF1_H0:
+ case RT5659_ADC_L_EQ_BPF1_A1:
+ case RT5659_ADC_R_EQ_BPF1_A1:
+ case RT5659_ADC_L_EQ_BPF1_A2:
+ case RT5659_ADC_R_EQ_BPF1_A2:
+ case RT5659_ADC_L_EQ_BPF1_H0:
+ case RT5659_ADC_R_EQ_BPF1_H0:
+ case RT5659_ADC_L_EQ_BPF2_A1:
+ case RT5659_ADC_R_EQ_BPF2_A1:
+ case RT5659_ADC_L_EQ_BPF2_A2:
+ case RT5659_ADC_R_EQ_BPF2_A2:
+ case RT5659_ADC_L_EQ_BPF2_H0:
+ case RT5659_ADC_R_EQ_BPF2_H0:
+ case RT5659_ADC_L_EQ_BPF3_A1:
+ case RT5659_ADC_R_EQ_BPF3_A1:
+ case RT5659_ADC_L_EQ_BPF3_A2:
+ case RT5659_ADC_R_EQ_BPF3_A2:
+ case RT5659_ADC_L_EQ_BPF3_H0:
+ case RT5659_ADC_R_EQ_BPF3_H0:
+ case RT5659_ADC_L_EQ_BPF4_A1:
+ case RT5659_ADC_R_EQ_BPF4_A1:
+ case RT5659_ADC_L_EQ_BPF4_A2:
+ case RT5659_ADC_R_EQ_BPF4_A2:
+ case RT5659_ADC_L_EQ_BPF4_H0:
+ case RT5659_ADC_R_EQ_BPF4_H0:
+ case RT5659_ADC_L_EQ_HPF1_A1:
+ case RT5659_ADC_R_EQ_HPF1_A1:
+ case RT5659_ADC_L_EQ_HPF1_H0:
+ case RT5659_ADC_R_EQ_HPF1_H0:
+ case RT5659_ADC_L_EQ_PRE_VOL:
+ case RT5659_ADC_R_EQ_PRE_VOL:
+ case RT5659_ADC_L_EQ_POST_VOL:
+ case RT5659_ADC_R_EQ_POST_VOL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0);
+
+/* Interface data select */
+static const char * const rt5659_data_select[] = {
+ "L/R", "R/L", "L/L", "R/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum,
+ RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum,
+ RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum,
+ RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum,
+ RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum,
+ RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum,
+ RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum,
+ RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum,
+ RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select);
+
+static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 01 ADC Swap Source", rt5659_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_23_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 23 ADC1 Swap Source", rt5659_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_45_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 45 ADC1 Swap Source", rt5659_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_67_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 67 ADC1 Swap Source", rt5659_if1_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_dac_swap_mux =
+ SOC_DAPM_ENUM("IF2 DAC Swap Source", rt5659_if2_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_swap_mux =
+ SOC_DAPM_ENUM("IF2 ADC Swap Source", rt5659_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_dac_swap_mux =
+ SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5659_if3_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux =
+ SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5659_if3_adc_enum);
+
+static const char * const rt5659_asrc_clk_src[] = {
+ "clk_sysy_div_out", "clk_i2s1_track", "clk_i2s2_track",
+ "clk_i2s3_track", "clk_sys2", "clk_sys3"
+};
+
+static unsigned int rt5659_asrc_clk_map_values[] = {
+ 0, 1, 2, 3, 5, 6,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+ rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7,
+ rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+ if (snd_soc_read(codec, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
+ snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+ RT5659_NG2_EN_MASK, RT5659_NG2_DIS);
+ snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+ RT5659_NG2_EN_MASK, RT5659_NG2_EN);
+ }
+
+ return ret;
+}
+
+static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
+ bool enable)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+ if (enable) {
+ snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, 0x000b);
+
+ /* MICBIAS1 and Mic Det Power for button detect*/
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+ snd_soc_dapm_force_enable_pin(dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
+
+ snd_soc_update_bits(codec, RT5659_PWR_ANLG_2,
+ RT5659_PWR_MB1, RT5659_PWR_MB1);
+ snd_soc_update_bits(codec, RT5659_PWR_VOL,
+ RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET);
+
+ snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+ RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
+ snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+ RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
+ } else {
+ snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+ RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS);
+ snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+ RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS);
+ /* MICBIAS1 and Mic Det Power for button detect*/
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+ snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
+ }
+}
+
+/**
+ * rt5659_headset_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+ int reg_63;
+
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ if (jack_insert) {
+ snd_soc_dapm_force_enable_pin(dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
+ reg_63 = snd_soc_read(codec, RT5659_PWR_ANLG_1);
+
+ snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+ RT5659_PWR_VREF2 | RT5659_PWR_MB,
+ RT5659_PWR_VREF2 | RT5659_PWR_MB);
+ msleep(20);
+ snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+ RT5659_PWR_FV2, RT5659_PWR_FV2);
+
+ snd_soc_write(codec, RT5659_EJD_CTRL_2, 0x4160);
+ snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+ 0x20, 0x0);
+ msleep(20);
+ snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+ 0x20, 0x20);
+
+ while (i < 5) {
+ msleep(sleep_time[i]);
+ val = snd_soc_read(codec, RT5659_EJD_CTRL_2) & 0x0003;
+ i++;
+ if (val == 0x1 || val == 0x2 || val == 0x3)
+ break;
+ }
+
+ switch (val) {
+ case 1:
+ rt5659->jack_type = SND_JACK_HEADSET;
+ rt5659_enable_push_button_irq(codec, true);
+ break;
+ default:
+ snd_soc_write(codec, RT5659_PWR_ANLG_1, reg_63);
+ rt5659->jack_type = SND_JACK_HEADPHONE;
+ snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
+ break;
+ }
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
+ if (rt5659->jack_type == SND_JACK_HEADSET)
+ rt5659_enable_push_button_irq(codec, false);
+ rt5659->jack_type = 0;
+ }
+
+ dev_dbg(codec->dev, "jack_type = %d\n", rt5659->jack_type);
+ return rt5659->jack_type;
+}
+
+static int rt5659_button_detect(struct snd_soc_codec *codec)
+{
+ int btn_type, val;
+
+ val = snd_soc_read(codec, RT5659_4BTN_IL_CMD_1);
+ btn_type = val & 0xfff0;
+ snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, val);
+
+ return btn_type;
+}
+
+static irqreturn_t rt5659_irq(int irq, void *data)
+{
+ struct rt5659_priv *rt5659 = data;
+
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5659->jack_detect_work, msecs_to_jiffies(250));
+
+ return IRQ_HANDLED;
+}
+
+int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hs_jack)
+{
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ rt5659->hs_jack = hs_jack;
+
+ rt5659_irq(0, rt5659);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5659_set_jack_detect);
+
+static void rt5659_jack_detect_work(struct work_struct *work)
+{
+ struct rt5659_priv *rt5659 =
+ container_of(work, struct rt5659_priv, jack_detect_work.work);
+ int val, btn_type, report = 0;
+
+ if (!rt5659->codec)
+ return;
+
+ val = snd_soc_read(rt5659->codec, RT5659_INT_ST_1) & 0x0080;
+ if (!val) {
+ /* jack in */
+ if (rt5659->jack_type == 0) {
+ /* jack was out, report jack type */
+ report = rt5659_headset_detect(rt5659->codec, 1);
+ } else {
+ /* jack is already in, report button event */
+ report = SND_JACK_HEADSET;
+ btn_type = rt5659_button_detect(rt5659->codec);
+ /**
+ * rt5659 can report three kinds of button behavior,
+ * one click, double click and hold. However,
+ * currently we will report button pressed/released
+ * event. So all the three button behaviors are
+ * treated as button pressed.
+ */
+ switch (btn_type) {
+ case 0x8000:
+ case 0x4000:
+ case 0x2000:
+ report |= SND_JACK_BTN_0;
+ break;
+ case 0x1000:
+ case 0x0800:
+ case 0x0400:
+ report |= SND_JACK_BTN_1;
+ break;
+ case 0x0200:
+ case 0x0100:
+ case 0x0080:
+ report |= SND_JACK_BTN_2;
+ break;
+ case 0x0040:
+ case 0x0020:
+ case 0x0010:
+ report |= SND_JACK_BTN_3;
+ break;
+ case 0x0000: /* unpressed */
+ break;
+ default:
+ btn_type = 0;
+ dev_err(rt5659->codec->dev,
+ "Unexpected button code 0x%04x\n",
+ btn_type);
+ break;
+ }
+
+ /* button release or spurious interrput*/
+ if (btn_type == 0)
+ report = rt5659->jack_type;
+ }
+ } else {
+ /* jack out */
+ report = rt5659_headset_detect(rt5659->codec, 0);
+ }
+
+ snd_soc_jack_report(rt5659->hs_jack, report, SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static const struct snd_kcontrol_new rt5659_snd_controls[] = {
+ /* Speaker Output Volume */
+ SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* Headphone Output Volume */
+ SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5659_HPL_GAIN,
+ RT5659_HPR_GAIN, RT5659_G_HP_SFT, 31, 1, snd_soc_get_volsw,
+ rt5659_hp_vol_put, hp_vol_tlv),
+
+ /* Mono Output Volume */
+ SOC_SINGLE_TLV("Mono Playback Volume", RT5659_MONO_OUT,
+ RT5659_L_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* Output Volume */
+ SOC_DOUBLE_TLV("OUT Playback Volume", RT5659_LOUT,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* DAC Digital Volume */
+ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5659_DAC1_DIG_VOL,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ SOC_DOUBLE("DAC1 Playback Switch", RT5659_AD_DA_MIXER,
+ RT5659_M_DAC1_L_SFT, RT5659_M_DAC1_R_SFT, 1, 1),
+
+ SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5659_DAC2_DIG_VOL,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ SOC_DOUBLE("DAC2 Playback Switch", RT5659_DAC_CTRL,
+ RT5659_M_DAC2_L_VOL_SFT, RT5659_M_DAC2_R_VOL_SFT, 1, 1),
+
+ /* IN1/IN2/IN3/IN4 Volume */
+ SOC_SINGLE_TLV("IN1 Boost Volume", RT5659_IN1_IN2,
+ RT5659_BST1_SFT, 69, 0, in_bst_tlv),
+ SOC_SINGLE_TLV("IN2 Boost Volume", RT5659_IN1_IN2,
+ RT5659_BST2_SFT, 69, 0, in_bst_tlv),
+ SOC_SINGLE_TLV("IN3 Boost Volume", RT5659_IN3_IN4,
+ RT5659_BST3_SFT, 69, 0, in_bst_tlv),
+ SOC_SINGLE_TLV("IN4 Boost Volume", RT5659_IN3_IN4,
+ RT5659_BST4_SFT, 69, 0, in_bst_tlv),
+
+ /* INL/INR Volume Control */
+ SOC_DOUBLE_TLV("IN Capture Volume", RT5659_INL1_INR1_VOL,
+ RT5659_INL_VOL_SFT, RT5659_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+ /* ADC Digital Volume Control */
+ SOC_DOUBLE("STO1 ADC Capture Switch", RT5659_STO1_ADC_DIG_VOL,
+ RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5659_STO1_ADC_DIG_VOL,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+ SOC_DOUBLE("Mono ADC Capture Switch", RT5659_MONO_ADC_DIG_VOL,
+ RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5659_MONO_ADC_DIG_VOL,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+ SOC_DOUBLE("STO2 ADC Capture Switch", RT5659_STO2_ADC_DIG_VOL,
+ RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5659_STO2_ADC_DIG_VOL,
+ RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+ /* ADC Boost Volume Control */
+ SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5659_STO1_BOOST,
+ RT5659_STO1_ADC_L_BST_SFT, RT5659_STO1_ADC_R_BST_SFT,
+ 3, 0, adc_bst_tlv),
+
+ SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5659_MONO_BOOST,
+ RT5659_MONO_ADC_L_BST_SFT, RT5659_MONO_ADC_R_BST_SFT,
+ 3, 0, adc_bst_tlv),
+
+ SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5659_STO2_BOOST,
+ RT5659_STO2_ADC_L_BST_SFT, RT5659_STO2_ADC_R_BST_SFT,
+ 3, 0, adc_bst_tlv),
+
+ SOC_SINGLE("DAC IF1 DAC1 L Data Switch", RT5659_TDM_CTRL_4, 12, 7, 0),
+ SOC_SINGLE("DAC IF1 DAC1 R Data Switch", RT5659_TDM_CTRL_4, 8, 7, 0),
+ SOC_SINGLE("DAC IF1 DAC2 L Data Switch", RT5659_TDM_CTRL_4, 4, 7, 0),
+ SOC_SINGLE("DAC IF1 DAC2 R Data Switch", RT5659_TDM_CTRL_4, 0, 7, 0),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+ int pd, idx = -EINVAL;
+
+ pd = rl6231_get_pre_div(rt5659->regmap,
+ RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT);
+ idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd);
+
+ if (idx < 0)
+ dev_err(codec->dev, "Failed to set DMIC clock\n");
+ else {
+ snd_soc_update_bits(codec, RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT);
+ }
+ return idx;
+}
+
+static int set_adc_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+ RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK,
+ RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+ RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+
+}
+
+static int rt5659_charge_pump_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Depop */
+ snd_soc_write(codec, RT5659_DEPOP_1, 0x0009);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int val;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ val = snd_soc_read(codec, RT5659_GLB_CLK);
+ val &= RT5659_SCLK_SRC_MASK;
+ if (val == RT5659_SCLK_SRC_PLL1)
+ return 1;
+ else
+ return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg, shift, val;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (w->shift) {
+ case RT5659_ADC_MONO_R_ASRC_SFT:
+ reg = RT5659_ASRC_3;
+ shift = RT5659_AD_MONO_R_T_SFT;
+ break;
+ case RT5659_ADC_MONO_L_ASRC_SFT:
+ reg = RT5659_ASRC_3;
+ shift = RT5659_AD_MONO_L_T_SFT;
+ break;
+ case RT5659_ADC_STO1_ASRC_SFT:
+ reg = RT5659_ASRC_2;
+ shift = RT5659_AD_STO1_T_SFT;
+ break;
+ case RT5659_DAC_MONO_R_ASRC_SFT:
+ reg = RT5659_ASRC_2;
+ shift = RT5659_DA_MONO_R_T_SFT;
+ break;
+ case RT5659_DAC_MONO_L_ASRC_SFT:
+ reg = RT5659_ASRC_2;
+ shift = RT5659_DA_MONO_L_T_SFT;
+ break;
+ case RT5659_DAC_STO_ASRC_SFT:
+ reg = RT5659_ASRC_2;
+ shift = RT5659_DA_STO_T_SFT;
+ break;
+ default:
+ return 0;
+ }
+
+ val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+ switch (val) {
+ case 1:
+ case 2:
+ case 3:
+ /* I2S_Pre_Div1 should be 1 in asrc mode */
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+ RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2);
+ return 1;
+ default:
+ return 0;
+ }
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5659_sto1_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+ RT5659_M_STO1_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+ RT5659_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+ RT5659_M_STO1_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+ RT5659_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+ RT5659_M_MONO_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+ RT5659_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+ RT5659_M_MONO_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+ RT5659_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+ RT5659_M_ADCMIX_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+ RT5659_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+ RT5659_M_ADCMIX_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+ RT5659_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_L1_STO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_R1_STO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_L2_STO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_R2_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_L1_STO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_R1_STO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_L2_STO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+ RT5659_M_DAC_R2_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_L1_MONO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_R1_MONO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_L2_MONO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_L1_MONO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_R1_MONO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_L2_MONO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+ RT5659_M_DAC_R2_MONO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5659_rec1_l_mix[] = {
+ SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_SPKVOLL_RM1_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_INL_RM1_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_BST4_RM1_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_BST3_RM1_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_BST2_RM1_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_BST1_RM1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec1_r_mix[] = {
+ SOC_DAPM_SINGLE("HPOVOLR Switch", RT5659_REC1_L2_MIXER,
+ RT5659_M_HPOVOLR_RM1_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5659_REC1_R2_MIXER,
+ RT5659_M_INR_RM1_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_R2_MIXER,
+ RT5659_M_BST4_RM1_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_R2_MIXER,
+ RT5659_M_BST3_RM1_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_R2_MIXER,
+ RT5659_M_BST2_RM1_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_R2_MIXER,
+ RT5659_M_BST1_RM1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_l_mix[] = {
+ SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC2_L2_MIXER,
+ RT5659_M_SPKVOL_RM2_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOLL Switch", RT5659_REC2_L2_MIXER,
+ RT5659_M_OUTVOLL_RM2_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_L2_MIXER,
+ RT5659_M_BST4_RM2_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_L2_MIXER,
+ RT5659_M_BST3_RM2_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_L2_MIXER,
+ RT5659_M_BST2_RM2_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_L2_MIXER,
+ RT5659_M_BST1_RM2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_r_mix[] = {
+ SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_REC2_R2_MIXER,
+ RT5659_M_MONOVOL_RM2_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOLR Switch", RT5659_REC2_R2_MIXER,
+ RT5659_M_OUTVOLR_RM2_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_R2_MIXER,
+ RT5659_M_BST4_RM2_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_R2_MIXER,
+ RT5659_M_BST3_RM2_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_R2_MIXER,
+ RT5659_M_BST2_RM2_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_R2_MIXER,
+ RT5659_M_BST1_RM2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPK_L_MIXER,
+ RT5659_M_DAC_L2_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_SPK_L_MIXER,
+ RT5659_M_BST1_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_L_MIXER,
+ RT5659_M_IN_L_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_L_MIXER,
+ RT5659_M_IN_R_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_L_MIXER,
+ RT5659_M_BST3_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPK_R_MIXER,
+ RT5659_M_DAC_R2_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST4 Switch", RT5659_SPK_R_MIXER,
+ RT5659_M_BST4_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_R_MIXER,
+ RT5659_M_IN_L_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_R_MIXER,
+ RT5659_M_IN_R_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_R_MIXER,
+ RT5659_M_BST3_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_monovol_mix[] = {
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_DAC_L2_MM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_DAC_R2_MM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_BST1_MM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_BST2_MM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_BST3_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_OUT_L_MIXER,
+ RT5659_M_DAC_L2_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5659_OUT_L_MIXER,
+ RT5659_M_IN_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5659_OUT_L_MIXER,
+ RT5659_M_BST1_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_L_MIXER,
+ RT5659_M_BST2_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_L_MIXER,
+ RT5659_M_BST3_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_OUT_R_MIXER,
+ RT5659_M_DAC_R2_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5659_OUT_R_MIXER,
+ RT5659_M_IN_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_R_MIXER,
+ RT5659_M_BST2_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_R_MIXER,
+ RT5659_M_BST3_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST4 Switch", RT5659_OUT_R_MIXER,
+ RT5659_M_BST4_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPO_AMP_GAIN,
+ RT5659_M_DAC_L2_SPKOMIX_SFT, 1, 0),
+ SOC_DAPM_SINGLE("SPKVOL L Switch", RT5659_SPO_AMP_GAIN,
+ RT5659_M_SPKVOLL_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPO_AMP_GAIN,
+ RT5659_M_DAC_R2_SPKOMIX_SFT, 1, 0),
+ SOC_DAPM_SINGLE("SPKVOL R Switch", RT5659_SPO_AMP_GAIN,
+ RT5659_M_SPKVOLR_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_mix[] = {
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_DAC_L2_MA_SFT, 1, 1),
+ SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_MONOMIX_IN_GAIN,
+ RT5659_M_MONOVOL_MA_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_LOUT_MIXER,
+ RT5659_M_DAC_L2_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOL L Switch", RT5659_LOUT_MIXER,
+ RT5659_M_OV_L_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_LOUT_MIXER,
+ RT5659_M_DAC_R2_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOL R Switch", RT5659_LOUT_MIXER,
+ RT5659_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC L2, DAC R2*/
+/*MX-1B [6:4], MX-1B [2:0]*/
+static const char * const rt5659_dac2_src[] = {
+ "IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_dac_l2_enum, RT5659_DAC_CTRL,
+ RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l2_mux =
+ SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_dac_r2_enum, RT5659_DAC_CTRL,
+ RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r2_mux =
+ SOC_DAPM_ENUM("DAC R2 Source", rt5659_dac_r2_enum);
+
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] */
+static const char * const rt5659_sto1_adc1_src[] = {
+ "DAC MIX", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER,
+ RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc1_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5659_sto1_adc1_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [12] */
+static const char * const rt5659_sto1_adc_src[] = {
+ "ADC1", "ADC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER,
+ RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC Source", rt5659_sto1_adc_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [11] */
+static const char * const rt5659_sto1_adc2_src[] = {
+ "DAC MIX", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER,
+ RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc2_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5659_sto1_adc2_enum);
+
+/* STO1 DMIC Source */
+/* MX-26 [8] */
+static const char * const rt5659_sto1_dmic_src[] = {
+ "DMIC1", "DMIC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER,
+ RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_dmic_mux =
+ SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5659_sto1_dmic_enum);
+
+
+/* MONO ADC L2 Source */
+/* MX-27 [12] */
+static const char * const rt5659_mono_adc_l2_src[] = {
+ "Mono DAC MIXL", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l2_mux =
+ SOC_DAPM_ENUM("Mono ADC L2 Source", rt5659_mono_adc_l2_enum);
+
+
+/* MONO ADC L1 Source */
+/* MX-27 [11] */
+static const char * const rt5659_mono_adc_l1_src[] = {
+ "Mono DAC MIXL", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l1_mux =
+ SOC_DAPM_ENUM("Mono ADC L1 Source", rt5659_mono_adc_l1_enum);
+
+/* MONO ADC L Source, MONO ADC R Source*/
+/* MX-27 [10:9], MX-27 [2:1] */
+static const char * const rt5659_mono_adc_src[] = {
+ "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mux =
+ SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mux =
+ SOC_DAPM_ENUM("Mono ADC R Source", rt5659_mono_adcr_enum);
+
+/* MONO DMIC L Source */
+/* MX-27 [8] */
+static const char * const rt5659_mono_dmic_l_src[] = {
+ "DMIC1 L", "DMIC2 L"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_l_mux =
+ SOC_DAPM_ENUM("Mono DMIC L Source", rt5659_mono_dmic_l_enum);
+
+/* MONO ADC R2 Source */
+/* MX-27 [4] */
+static const char * const rt5659_mono_adc_r2_src[] = {
+ "Mono DAC MIXR", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r2_mux =
+ SOC_DAPM_ENUM("Mono ADC R2 Source", rt5659_mono_adc_r2_enum);
+
+/* MONO ADC R1 Source */
+/* MX-27 [3] */
+static const char * const rt5659_mono_adc_r1_src[] = {
+ "Mono DAC MIXR", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r1_mux =
+ SOC_DAPM_ENUM("Mono ADC R1 Source", rt5659_mono_adc_r1_enum);
+
+/* MONO DMIC R Source */
+/* MX-27 [0] */
+static const char * const rt5659_mono_dmic_r_src[] = {
+ "DMIC1 R", "DMIC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER,
+ RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_r_mux =
+ SOC_DAPM_ENUM("Mono DMIC R Source", rt5659_mono_dmic_r_enum);
+
+
+/* DAC R1 Source, DAC L1 Source*/
+/* MX-29 [11:10], MX-29 [9:8]*/
+static const char * const rt5659_dac1_src[] = {
+ "IF1 DAC1", "IF2 DAC", "IF3 DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_dac_r1_enum, RT5659_AD_DA_MIXER,
+ RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r1_mux =
+ SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_dac_l1_enum, RT5659_AD_DA_MIXER,
+ RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l1_mux =
+ SOC_DAPM_ENUM("DAC L1 Source", rt5659_dac_l1_enum);
+
+/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/
+/* MX-2C [6], MX-2C [4]*/
+static const char * const rt5659_dig_dac_mix_src[] = {
+ "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER,
+ RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux =
+ SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER,
+ RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixr_mux =
+ SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5659_dig_dac_mixr_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2D [3], MX-2D [2]*/
+static const char * const rt5659_alg_dac1_src[] = {
+ "DAC", "Stereo DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX,
+ RT5659_A_DACL1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux =
+ SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX,
+ RT5659_A_DACR1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r1_mux =
+ SOC_DAPM_ENUM("Analog DACR1 Source", rt5659_alg_dac_r1_enum);
+
+/* Analog DAC LR Source, Analog DAC R2 Source*/
+/* MX-2D [1], MX-2D [0]*/
+static const char * const rt5659_alg_dac2_src[] = {
+ "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX,
+ RT5659_A_DACL2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux =
+ SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX,
+ RT5659_A_DACR2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r2_mux =
+ SOC_DAPM_ENUM("Analog DAC R2 Source", rt5659_alg_dac_r2_enum);
+
+/* Interface2 ADC Data Input*/
+/* MX-2F [13:12] */
+static const char * const rt5659_if2_adc_in_src[] = {
+ "IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA,
+ RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_in_mux =
+ SOC_DAPM_ENUM("IF2 ADC IN Source", rt5659_if2_adc_in_enum);
+
+/* Interface3 ADC Data Input*/
+/* MX-2F [1:0] */
+static const char * const rt5659_if3_adc_in_src[] = {
+ "IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA,
+ RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_in_mux =
+ SOC_DAPM_ENUM("IF3 ADC IN Source", rt5659_if3_adc_in_enum);
+
+/* PDM 1 L/R*/
+/* MX-31 [15] [13] */
+static const char * const rt5659_pdm_src[] = {
+ "Mono DAC", "Stereo DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL,
+ RT5659_PDM1_L_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_l_mux =
+ SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL,
+ RT5659_PDM1_R_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_r_mux =
+ SOC_DAPM_ENUM("PDM R Source", rt5659_pdm_r_enum);
+
+/* SPDIF Output source*/
+/* MX-36 [1:0] */
+static const char * const rt5659_spdif_src[] = {
+ "IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_spdif_enum, RT5659_SPDIF_CTRL,
+ RT5659_SPDIF_SEL_SFT, rt5659_spdif_src);
+
+static const struct snd_kcontrol_new rt5659_spdif_mux =
+ SOC_DAPM_ENUM("SPDIF Source", rt5659_spdif_enum);
+
+/* I2S1 TDM ADCDAT Source */
+/* MX-78[4:0] */
+static const char * const rt5659_rx_adc_data_src[] = {
+ "AD1:AD2:DAC:NUL", "AD1:AD2:NUL:DAC", "AD1:DAC:AD2:NUL",
+ "AD1:DAC:NUL:AD2", "AD1:NUL:DAC:AD2", "AD1:NUL:AD2:DAC",
+ "AD2:AD1:DAC:NUL", "AD2:AD1:NUL:DAC", "AD2:DAC:AD1:NUL",
+ "AD2:DAC:NUL:AD1", "AD2:NUL:DAC:AD1", "AD1:NUL:AD1:DAC",
+ "DAC:AD1:AD2:NUL", "DAC:AD1:NUL:AD2", "DAC:AD2:AD1:NUL",
+ "DAC:AD2:NUL:AD1", "DAC:NUL:DAC:AD2", "DAC:NUL:AD2:DAC",
+ "NUL:AD1:AD2:DAC", "NUL:AD1:DAC:AD2", "NUL:AD2:AD1:DAC",
+ "NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2,
+ RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src);
+
+static const struct snd_kcontrol_new rt5659_rx_adc_dac_mux =
+ SOC_DAPM_ENUM("TDM ADCDAT Source", rt5659_rx_adc_data_enum);
+
+/* Out Volume Switch */
+static const struct snd_kcontrol_new spkvol_l_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spkvol_r_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new monovol_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_l_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_R_SFT, 1, 1);
+
+/* Out Switch */
+static const struct snd_kcontrol_new spo_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_CLASSD_2, RT5659_M_RF_DIG_SFT, 1, 1);
+
+static const struct snd_kcontrol_new mono_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_l_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_L_SFT, 1,
+ 1);
+
+static const struct snd_kcontrol_new pdm_r_switch =
+ SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_R_SFT, 1,
+ 1);
+
+static int rt5659_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+ RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN);
+ snd_soc_update_bits(codec, RT5659_CLASSD_2,
+ RT5659_M_RI_DIG, RT5659_M_RI_DIG);
+ snd_soc_write(codec, RT5659_CLASSD_1, 0x0803);
+ snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, RT5659_CLASSD_1, 0x0011);
+ snd_soc_update_bits(codec, RT5659_CLASSD_2,
+ RT5659_M_RI_DIG, 0x0);
+ snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+ snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+ RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+
+}
+
+static int rt5659_mono_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+
+}
+
+static int rt5659_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0e1e);
+ snd_soc_update_bits(codec, RT5659_DEPOP_1, 0x0010, 0x0010);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_write(codec, RT5659_DEPOP_1, 0x0000);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /*Add delay to avoid pop noise*/
+ msleep(450);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5659_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("LDO2", RT5659_PWR_ANLG_3, RT5659_PWR_LDO2_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL", RT5659_PWR_ANLG_3, RT5659_PWR_PLL_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5659_PWR_VOL,
+ RT5659_PWR_MIC_DET_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Mono Vref", RT5659_PWR_ANLG_1,
+ RT5659_PWR_VREF3_BIT, 0, NULL, 0),
+
+ /* ASRC */
+ SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5659_ASRC_1,
+ RT5659_I2S1_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5659_ASRC_1,
+ RT5659_I2S2_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5659_ASRC_1,
+ RT5659_I2S3_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5659_ASRC_1,
+ RT5659_DAC_STO_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5659_ASRC_1,
+ RT5659_DAC_MONO_L_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5659_ASRC_1,
+ RT5659_DAC_MONO_R_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5659_ASRC_1,
+ RT5659_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5659_ASRC_1,
+ RT5659_ADC_MONO_L_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5659_ASRC_1,
+ RT5659_ADC_MONO_R_ASRC_SFT, 0, NULL, 0),
+
+ /* Input Side */
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5659_PWR_ANLG_2, RT5659_PWR_MB1_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5659_PWR_ANLG_2, RT5659_PWR_MB2_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5659_PWR_ANLG_2, RT5659_PWR_MB3_BIT,
+ 0, NULL, 0),
+
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("DMIC L1"),
+ SND_SOC_DAPM_INPUT("DMIC R1"),
+ SND_SOC_DAPM_INPUT("DMIC L2"),
+ SND_SOC_DAPM_INPUT("DMIC R2"),
+
+ SND_SOC_DAPM_INPUT("IN1P"),
+ SND_SOC_DAPM_INPUT("IN1N"),
+ SND_SOC_DAPM_INPUT("IN2P"),
+ SND_SOC_DAPM_INPUT("IN2N"),
+ SND_SOC_DAPM_INPUT("IN3P"),
+ SND_SOC_DAPM_INPUT("IN3N"),
+ SND_SOC_DAPM_INPUT("IN4P"),
+ SND_SOC_DAPM_INPUT("IN4N"),
+
+ SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+ set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+ /* Boost */
+ SND_SOC_DAPM_PGA("BST1", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST1_P_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("BST2", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST2_P_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("BST3", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST3_P_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("BST4", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST4_P_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BST1 Power", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BST2 Power", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BST3 Power", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST3_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BST4 Power", RT5659_PWR_ANLG_2,
+ RT5659_PWR_BST4_BIT, 0, NULL, 0),
+
+
+ /* Input Volume */
+ SND_SOC_DAPM_PGA("INL VOL", RT5659_PWR_VOL, RT5659_PWR_IN_L_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR VOL", RT5659_PWR_VOL, RT5659_PWR_IN_R_BIT,
+ 0, NULL, 0),
+
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIX1L", RT5659_PWR_MIXER, RT5659_PWR_RM1_L_BIT,
+ 0, rt5659_rec1_l_mix, ARRAY_SIZE(rt5659_rec1_l_mix)),
+ SND_SOC_DAPM_MIXER("RECMIX1R", RT5659_PWR_MIXER, RT5659_PWR_RM1_R_BIT,
+ 0, rt5659_rec1_r_mix, ARRAY_SIZE(rt5659_rec1_r_mix)),
+ SND_SOC_DAPM_MIXER("RECMIX2L", RT5659_PWR_MIXER, RT5659_PWR_RM2_L_BIT,
+ 0, rt5659_rec2_l_mix, ARRAY_SIZE(rt5659_rec2_l_mix)),
+ SND_SOC_DAPM_MIXER("RECMIX2R", RT5659_PWR_MIXER, RT5659_PWR_RM2_R_BIT,
+ 0, rt5659_rec2_r_mix, ARRAY_SIZE(rt5659_rec2_r_mix)),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5659_PWR_DIG_1,
+ RT5659_PWR_ADC_L1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5659_PWR_DIG_1,
+ RT5659_PWR_ADC_R1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5659_PWR_DIG_2,
+ RT5659_PWR_ADC_L2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5659_PWR_DIG_2,
+ RT5659_PWR_ADC_R2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC1 clock", SND_SOC_NOPM, 0, 0, set_adc_clk,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("ADC2 clock", SND_SOC_NOPM, 0, 0, set_adc_clk,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_dmic_mux),
+ SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_dmic_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_adc1_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_adc1_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_adc2_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_adc2_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_adc_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_sto1_adc_mux),
+ SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_adc_l2_mux),
+ SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_adc_r2_mux),
+ SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_adc_l1_mux),
+ SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_adc_r1_mux),
+ SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_dmic_l_mux),
+ SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_dmic_r_mux),
+ SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_adc_l_mux),
+ SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_mono_adc_r_mux),
+ /* ADC Mixer */
+ SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_ADC_S1F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_ADC_S2F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM,
+ 0, 0, rt5659_sto1_adc_l_mix,
+ ARRAY_SIZE(rt5659_sto1_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM,
+ 0, 0, rt5659_sto1_adc_r_mix,
+ ARRAY_SIZE(rt5659_sto1_adc_r_mix)),
+ SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5659_MONO_ADC_DIG_VOL,
+ RT5659_L_MUTE_SFT, 1, rt5659_mono_adc_l_mix,
+ ARRAY_SIZE(rt5659_mono_adc_l_mix)),
+ SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5659_MONO_ADC_DIG_VOL,
+ RT5659_R_MUTE_SFT, 1, rt5659_mono_adc_r_mix,
+ ARRAY_SIZE(rt5659_mono_adc_r_mix)),
+
+ /* ADC PGA */
+ SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Stereo2 ADC LR", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Stereo1 ADC Volume L", RT5659_STO1_ADC_DIG_VOL,
+ RT5659_L_MUTE_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Stereo1 ADC Volume R", RT5659_STO1_ADC_DIG_VOL,
+ RT5659_R_MUTE_SFT, 1, NULL, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SUPPLY("I2S1", RT5659_PWR_DIG_1, RT5659_PWR_I2S1_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("I2S2", RT5659_PWR_DIG_1, RT5659_PWR_I2S2_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("I2S3", RT5659_PWR_DIG_1, RT5659_PWR_I2S3_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Interface Select */
+ SND_SOC_DAPM_PGA("TDM AD1:AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("TDM AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_rx_adc_dac_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if2_adc_in_mux),
+ SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if3_adc_in_mux),
+ SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if1_01_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if1_23_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if1_45_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if1_67_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if2_dac_swap_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if2_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if3_dac_swap_mux),
+ SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5659_if3_adc_swap_mux),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Output Side */
+ /* DAC mixer before sound effect */
+ SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+ rt5659_dac_l_mix, ARRAY_SIZE(rt5659_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+ rt5659_dac_r_mix, ARRAY_SIZE(rt5659_dac_r_mix)),
+
+ /* DAC channel Mux */
+ SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l1_mux),
+ SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r1_mux),
+ SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l2_mux),
+ SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r2_mux),
+
+ SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+ &rt5659_alg_dac_l1_mux),
+ SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+ &rt5659_alg_dac_r1_mux),
+ SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0,
+ &rt5659_alg_dac_l2_mux),
+ SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0,
+ &rt5659_alg_dac_r2_mux),
+
+ /* DAC Mixer */
+ SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_DAC_S1F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5659_PWR_DIG_2,
+ RT5659_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5659_sto_dac_l_mix, ARRAY_SIZE(rt5659_sto_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5659_sto_dac_r_mix, ARRAY_SIZE(rt5659_sto_dac_r_mix)),
+ SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5659_mono_dac_l_mix, ARRAY_SIZE(rt5659_mono_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5659_mono_dac_r_mix, ARRAY_SIZE(rt5659_mono_dac_r_mix)),
+ SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0,
+ &rt5659_dig_dac_mixl_mux),
+ SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0,
+ &rt5659_dig_dac_mixr_mux),
+
+ /* DACs */
+ SND_SOC_DAPM_SUPPLY_S("DAC L1 Power", 1, RT5659_PWR_DIG_1,
+ RT5659_PWR_DAC_L1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC R1 Power", 1, RT5659_PWR_DIG_1,
+ RT5659_PWR_DAC_R1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5659_PWR_DIG_1,
+ RT5659_PWR_DAC_L2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5659_PWR_DIG_1,
+ RT5659_PWR_DAC_R2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA("DAC_REF", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* OUT Mixer */
+ SND_SOC_DAPM_MIXER("SPK MIXL", RT5659_PWR_MIXER, RT5659_PWR_SM_L_BIT,
+ 0, rt5659_spk_l_mix, ARRAY_SIZE(rt5659_spk_l_mix)),
+ SND_SOC_DAPM_MIXER("SPK MIXR", RT5659_PWR_MIXER, RT5659_PWR_SM_R_BIT,
+ 0, rt5659_spk_r_mix, ARRAY_SIZE(rt5659_spk_r_mix)),
+ SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5659_PWR_MIXER, RT5659_PWR_MM_BIT,
+ 0, rt5659_monovol_mix, ARRAY_SIZE(rt5659_monovol_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXL", RT5659_PWR_MIXER, RT5659_PWR_OM_L_BIT,
+ 0, rt5659_out_l_mix, ARRAY_SIZE(rt5659_out_l_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXR", RT5659_PWR_MIXER, RT5659_PWR_OM_R_BIT,
+ 0, rt5659_out_r_mix, ARRAY_SIZE(rt5659_out_r_mix)),
+
+ /* Output Volume */
+ SND_SOC_DAPM_SWITCH("SPKVOL L", RT5659_PWR_VOL, RT5659_PWR_SV_L_BIT, 0,
+ &spkvol_l_switch),
+ SND_SOC_DAPM_SWITCH("SPKVOL R", RT5659_PWR_VOL, RT5659_PWR_SV_R_BIT, 0,
+ &spkvol_r_switch),
+ SND_SOC_DAPM_SWITCH("MONOVOL", RT5659_PWR_VOL, RT5659_PWR_MV_BIT, 0,
+ &monovol_switch),
+ SND_SOC_DAPM_SWITCH("OUTVOL L", RT5659_PWR_VOL, RT5659_PWR_OV_L_BIT, 0,
+ &outvol_l_switch),
+ SND_SOC_DAPM_SWITCH("OUTVOL R", RT5659_PWR_VOL, RT5659_PWR_OV_R_BIT, 0,
+ &outvol_r_switch),
+
+ /* SPO/MONO/HPO/LOUT */
+ SND_SOC_DAPM_MIXER("SPO L MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_l_mix,
+ ARRAY_SIZE(rt5659_spo_l_mix)),
+ SND_SOC_DAPM_MIXER("SPO R MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_r_mix,
+ ARRAY_SIZE(rt5659_spo_r_mix)),
+ SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5659_mono_mix,
+ ARRAY_SIZE(rt5659_mono_mix)),
+ SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_l_mix,
+ ARRAY_SIZE(rt5659_lout_l_mix)),
+ SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_r_mix,
+ ARRAY_SIZE(rt5659_lout_r_mix)),
+
+ SND_SOC_DAPM_PGA_S("SPK Amp", 1, RT5659_PWR_DIG_1, RT5659_PWR_CLS_D_BIT,
+ 0, rt5659_spk_event, SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5659_PWR_ANLG_1, RT5659_PWR_MA_BIT,
+ 0, rt5659_mono_event, SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5659_hp_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0,
+ rt5659_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SWITCH("SPO Playback", SND_SOC_NOPM, 0, 0, &spo_switch),
+ SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0,
+ &mono_switch),
+ SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+ &hpo_l_switch),
+ SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+ &hpo_r_switch),
+ SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+ &lout_l_switch),
+ SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+ &lout_r_switch),
+ SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0,
+ &pdm_l_switch),
+ SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0,
+ &pdm_r_switch),
+
+ /* PDM */
+ SND_SOC_DAPM_SUPPLY("PDM Power", RT5659_PWR_DIG_2,
+ RT5659_PWR_PDM1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("PDM L Mux", RT5659_PDM_OUT_CTRL,
+ RT5659_M_PDM1_L_SFT, 1, &rt5659_pdm_l_mux),
+ SND_SOC_DAPM_MUX("PDM R Mux", RT5659_PDM_OUT_CTRL,
+ RT5659_M_PDM1_R_SFT, 1, &rt5659_pdm_r_mux),
+
+ /* SPDIF */
+ SND_SOC_DAPM_MUX("SPDIF Mux", SND_SOC_NOPM, 0, 0, &rt5659_spdif_mux),
+
+ SND_SOC_DAPM_SUPPLY("SYS CLK DET", RT5659_CLK_DET, 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLKDET", RT5659_CLK_DET, 0, 0, NULL, 0),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ SND_SOC_DAPM_OUTPUT("LOUTL"),
+ SND_SOC_DAPM_OUTPUT("LOUTR"),
+ SND_SOC_DAPM_OUTPUT("MONOOUT"),
+ SND_SOC_DAPM_OUTPUT("PDML"),
+ SND_SOC_DAPM_OUTPUT("PDMR"),
+ SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt5659_dapm_routes[] = {
+ /*PLL*/
+ { "ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+ { "ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll },
+ { "ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+ { "ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+ { "DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+ { "DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+ { "DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+
+ /*ASRC*/
+ { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+ { "ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc },
+ { "ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc },
+ { "DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc },
+ { "DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc },
+ { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+ { "SYS CLK DET", NULL, "CLKDET" },
+
+ { "I2S1", NULL, "I2S1 ASRC" },
+ { "I2S2", NULL, "I2S2 ASRC" },
+ { "I2S3", NULL, "I2S3 ASRC" },
+
+ { "IN1P", NULL, "LDO2" },
+ { "IN2P", NULL, "LDO2" },
+ { "IN3P", NULL, "LDO2" },
+ { "IN4P", NULL, "LDO2" },
+
+ { "DMIC1", NULL, "DMIC L1" },
+ { "DMIC1", NULL, "DMIC R1" },
+ { "DMIC2", NULL, "DMIC L2" },
+ { "DMIC2", NULL, "DMIC R2" },
+
+ { "BST1", NULL, "IN1P" },
+ { "BST1", NULL, "IN1N" },
+ { "BST1", NULL, "BST1 Power" },
+ { "BST2", NULL, "IN2P" },
+ { "BST2", NULL, "IN2N" },
+ { "BST2", NULL, "BST2 Power" },
+ { "BST3", NULL, "IN3P" },
+ { "BST3", NULL, "IN3N" },
+ { "BST3", NULL, "BST3 Power" },
+ { "BST4", NULL, "IN4P" },
+ { "BST4", NULL, "IN4N" },
+ { "BST4", NULL, "BST4 Power" },
+
+ { "INL VOL", NULL, "IN2P" },
+ { "INR VOL", NULL, "IN2N" },
+
+ { "RECMIX1L", "SPKVOLL Switch", "SPKVOL L" },
+ { "RECMIX1L", "INL Switch", "INL VOL" },
+ { "RECMIX1L", "BST4 Switch", "BST4" },
+ { "RECMIX1L", "BST3 Switch", "BST3" },
+ { "RECMIX1L", "BST2 Switch", "BST2" },
+ { "RECMIX1L", "BST1 Switch", "BST1" },
+
+ { "RECMIX1R", "HPOVOLR Switch", "HPO R Playback" },
+ { "RECMIX1R", "INR Switch", "INR VOL" },
+ { "RECMIX1R", "BST4 Switch", "BST4" },
+ { "RECMIX1R", "BST3 Switch", "BST3" },
+ { "RECMIX1R", "BST2 Switch", "BST2" },
+ { "RECMIX1R", "BST1 Switch", "BST1" },
+
+ { "RECMIX2L", "SPKVOLL Switch", "SPKVOL L" },
+ { "RECMIX2L", "OUTVOLL Switch", "OUTVOL L" },
+ { "RECMIX2L", "BST4 Switch", "BST4" },
+ { "RECMIX2L", "BST3 Switch", "BST3" },
+ { "RECMIX2L", "BST2 Switch", "BST2" },
+ { "RECMIX2L", "BST1 Switch", "BST1" },
+
+ { "RECMIX2R", "MONOVOL Switch", "MONOVOL" },
+ { "RECMIX2R", "OUTVOLR Switch", "OUTVOL R" },
+ { "RECMIX2R", "BST4 Switch", "BST4" },
+ { "RECMIX2R", "BST3 Switch", "BST3" },
+ { "RECMIX2R", "BST2 Switch", "BST2" },
+ { "RECMIX2R", "BST1 Switch", "BST1" },
+
+ { "ADC1 L", NULL, "RECMIX1L" },
+ { "ADC1 L", NULL, "ADC1 L Power" },
+ { "ADC1 L", NULL, "ADC1 clock" },
+ { "ADC1 R", NULL, "RECMIX1R" },
+ { "ADC1 R", NULL, "ADC1 R Power" },
+ { "ADC1 R", NULL, "ADC1 clock" },
+
+ { "ADC2 L", NULL, "RECMIX2L" },
+ { "ADC2 L", NULL, "ADC2 L Power" },
+ { "ADC2 L", NULL, "ADC2 clock" },
+ { "ADC2 R", NULL, "RECMIX2R" },
+ { "ADC2 R", NULL, "ADC2 R Power" },
+ { "ADC2 R", NULL, "ADC2 clock" },
+
+ { "DMIC L1", NULL, "DMIC CLK" },
+ { "DMIC L1", NULL, "DMIC1 Power" },
+ { "DMIC R1", NULL, "DMIC CLK" },
+ { "DMIC R1", NULL, "DMIC1 Power" },
+ { "DMIC L2", NULL, "DMIC CLK" },
+ { "DMIC L2", NULL, "DMIC2 Power" },
+ { "DMIC R2", NULL, "DMIC CLK" },
+ { "DMIC R2", NULL, "DMIC2 Power" },
+
+ { "Stereo1 DMIC L Mux", "DMIC1", "DMIC L1" },
+ { "Stereo1 DMIC L Mux", "DMIC2", "DMIC L2" },
+
+ { "Stereo1 DMIC R Mux", "DMIC1", "DMIC R1" },
+ { "Stereo1 DMIC R Mux", "DMIC2", "DMIC R2" },
+
+ { "Mono DMIC L Mux", "DMIC1 L", "DMIC L1" },
+ { "Mono DMIC L Mux", "DMIC2 L", "DMIC L2" },
+
+ { "Mono DMIC R Mux", "DMIC1 R", "DMIC R1" },
+ { "Mono DMIC R Mux", "DMIC2 R", "DMIC R2" },
+
+ { "Stereo1 ADC L Mux", "ADC1", "ADC1 L" },
+ { "Stereo1 ADC L Mux", "ADC2", "ADC2 L" },
+ { "Stereo1 ADC R Mux", "ADC1", "ADC1 R" },
+ { "Stereo1 ADC R Mux", "ADC2", "ADC2 R" },
+
+ { "Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux" },
+ { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+ { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux" },
+ { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+
+ { "Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux" },
+ { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+ { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux" },
+ { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+ { "Mono ADC L Mux", "ADC1 L", "ADC1 L" },
+ { "Mono ADC L Mux", "ADC1 R", "ADC1 R" },
+ { "Mono ADC L Mux", "ADC2 L", "ADC2 L" },
+ { "Mono ADC L Mux", "ADC2 R", "ADC2 R" },
+
+ { "Mono ADC R Mux", "ADC1 L", "ADC1 L" },
+ { "Mono ADC R Mux", "ADC1 R", "ADC1 R" },
+ { "Mono ADC R Mux", "ADC2 L", "ADC2 L" },
+ { "Mono ADC R Mux", "ADC2 R", "ADC2 R" },
+
+ { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+ { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+ { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+ { "Mono ADC L1 Mux", "ADC", "Mono ADC L Mux" },
+
+ { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+ { "Mono ADC R1 Mux", "ADC", "Mono ADC R Mux" },
+ { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+ { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+ { "Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+ { "Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+ { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" },
+
+ { "Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+ { "Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+ { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" },
+
+ { "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+ { "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+ { "Mono ADC MIXL", NULL, "ADC Mono Left Filter" },
+
+ { "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+ { "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+ { "Mono ADC MIXR", NULL, "ADC Mono Right Filter" },
+
+ { "Stereo1 ADC Volume L", NULL, "Stereo1 ADC MIXL" },
+ { "Stereo1 ADC Volume R", NULL, "Stereo1 ADC MIXR" },
+
+ { "IF_ADC1", NULL, "Stereo1 ADC Volume L" },
+ { "IF_ADC1", NULL, "Stereo1 ADC Volume R" },
+ { "IF_ADC2", NULL, "Mono ADC MIXL" },
+ { "IF_ADC2", NULL, "Mono ADC MIXR" },
+
+ { "TDM AD1:AD2:DAC", NULL, "IF_ADC1" },
+ { "TDM AD1:AD2:DAC", NULL, "IF_ADC2" },
+ { "TDM AD1:AD2:DAC", NULL, "DAC_REF" },
+ { "TDM AD2:DAC", NULL, "IF_ADC2" },
+ { "TDM AD2:DAC", NULL, "DAC_REF" },
+ { "TDM Data Mux", "AD1:AD2:DAC:NUL", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD1:AD2:NUL:DAC", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD1:DAC:AD2:NUL", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD1:DAC:NUL:AD2", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD1:NUL:DAC:AD2", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD1:NUL:AD2:DAC", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD2:AD1:DAC:NUL", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD2:AD1:NUL:DAC", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD2:DAC:AD1:NUL", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD2:DAC:NUL:AD1", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD2:NUL:DAC:AD1", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "AD1:NUL:AD1:DAC", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "DAC:AD1:AD2:NUL", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "DAC:AD1:NUL:AD2", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "DAC:AD2:AD1:NUL", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "DAC:AD2:NUL:AD1", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "DAC:NUL:DAC:AD2", "TDM AD2:DAC" },
+ { "TDM Data Mux", "DAC:NUL:AD2:DAC", "TDM AD2:DAC" },
+ { "TDM Data Mux", "NUL:AD1:AD2:DAC", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "NUL:AD1:DAC:AD2", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "NUL:AD2:AD1:DAC", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "NUL:AD2:DAC:AD1", "TDM AD1:AD2:DAC" },
+ { "TDM Data Mux", "NUL:DAC:DAC:AD2", "TDM AD2:DAC" },
+ { "TDM Data Mux", "NUL:DAC:AD2:DAC", "TDM AD2:DAC" },
+ { "IF1 01 ADC Swap Mux", "L/R", "TDM Data Mux" },
+ { "IF1 01 ADC Swap Mux", "R/L", "TDM Data Mux" },
+ { "IF1 01 ADC Swap Mux", "L/L", "TDM Data Mux" },
+ { "IF1 01 ADC Swap Mux", "R/R", "TDM Data Mux" },
+ { "IF1 23 ADC Swap Mux", "L/R", "TDM Data Mux" },
+ { "IF1 23 ADC Swap Mux", "R/L", "TDM Data Mux" },
+ { "IF1 23 ADC Swap Mux", "L/L", "TDM Data Mux" },
+ { "IF1 23 ADC Swap Mux", "R/R", "TDM Data Mux" },
+ { "IF1 45 ADC Swap Mux", "L/R", "TDM Data Mux" },
+ { "IF1 45 ADC Swap Mux", "R/L", "TDM Data Mux" },
+ { "IF1 45 ADC Swap Mux", "L/L", "TDM Data Mux" },
+ { "IF1 45 ADC Swap Mux", "R/R", "TDM Data Mux" },
+ { "IF1 67 ADC Swap Mux", "L/R", "TDM Data Mux" },
+ { "IF1 67 ADC Swap Mux", "R/L", "TDM Data Mux" },
+ { "IF1 67 ADC Swap Mux", "L/L", "TDM Data Mux" },
+ { "IF1 67 ADC Swap Mux", "R/R", "TDM Data Mux" },
+ { "IF1 ADC", NULL, "IF1 01 ADC Swap Mux" },
+ { "IF1 ADC", NULL, "IF1 23 ADC Swap Mux" },
+ { "IF1 ADC", NULL, "IF1 45 ADC Swap Mux" },
+ { "IF1 ADC", NULL, "IF1 67 ADC Swap Mux" },
+ { "IF1 ADC", NULL, "I2S1" },
+
+ { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+ { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+ { "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" },
+ { "IF2 ADC Mux", "DAC_REF", "DAC_REF" },
+ { "IF2 ADC", NULL, "IF2 ADC Mux"},
+ { "IF2 ADC", NULL, "I2S2" },
+
+ { "IF3 ADC Mux", "IF_ADC1", "IF_ADC1" },
+ { "IF3 ADC Mux", "IF_ADC2", "IF_ADC2" },
+ { "IF3 ADC Mux", "Stereo2_ADC_L/R", "Stereo2 ADC LR" },
+ { "IF3 ADC Mux", "DAC_REF", "DAC_REF" },
+ { "IF3 ADC", NULL, "IF3 ADC Mux"},
+ { "IF3 ADC", NULL, "I2S3" },
+
+ { "AIF1TX", NULL, "IF1 ADC" },
+ { "IF2 ADC Swap Mux", "L/R", "IF2 ADC" },
+ { "IF2 ADC Swap Mux", "R/L", "IF2 ADC" },
+ { "IF2 ADC Swap Mux", "L/L", "IF2 ADC" },
+ { "IF2 ADC Swap Mux", "R/R", "IF2 ADC" },
+ { "AIF2TX", NULL, "IF2 ADC Swap Mux" },
+ { "IF3 ADC Swap Mux", "L/R", "IF3 ADC" },
+ { "IF3 ADC Swap Mux", "R/L", "IF3 ADC" },
+ { "IF3 ADC Swap Mux", "L/L", "IF3 ADC" },
+ { "IF3 ADC Swap Mux", "R/R", "IF3 ADC" },
+ { "AIF3TX", NULL, "IF3 ADC Swap Mux" },
+
+ { "IF1 DAC1", NULL, "AIF1RX" },
+ { "IF1 DAC2", NULL, "AIF1RX" },
+ { "IF2 DAC Swap Mux", "L/R", "AIF2RX" },
+ { "IF2 DAC Swap Mux", "R/L", "AIF2RX" },
+ { "IF2 DAC Swap Mux", "L/L", "AIF2RX" },
+ { "IF2 DAC Swap Mux", "R/R", "AIF2RX" },
+ { "IF2 DAC", NULL, "IF2 DAC Swap Mux" },
+ { "IF3 DAC Swap Mux", "L/R", "AIF3RX" },
+ { "IF3 DAC Swap Mux", "R/L", "AIF3RX" },
+ { "IF3 DAC Swap Mux", "L/L", "AIF3RX" },
+ { "IF3 DAC Swap Mux", "R/R", "AIF3RX" },
+ { "IF3 DAC", NULL, "IF3 DAC Swap Mux" },
+
+ { "IF1 DAC1", NULL, "I2S1" },
+ { "IF1 DAC2", NULL, "I2S1" },
+ { "IF2 DAC", NULL, "I2S2" },
+ { "IF3 DAC", NULL, "I2S3" },
+
+ { "IF1 DAC2 L", NULL, "IF1 DAC2" },
+ { "IF1 DAC2 R", NULL, "IF1 DAC2" },
+ { "IF1 DAC1 L", NULL, "IF1 DAC1" },
+ { "IF1 DAC1 R", NULL, "IF1 DAC1" },
+ { "IF2 DAC L", NULL, "IF2 DAC" },
+ { "IF2 DAC R", NULL, "IF2 DAC" },
+ { "IF3 DAC L", NULL, "IF3 DAC" },
+ { "IF3 DAC R", NULL, "IF3 DAC" },
+
+ { "DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L" },
+ { "DAC L1 Mux", "IF2 DAC", "IF2 DAC L" },
+ { "DAC L1 Mux", "IF3 DAC", "IF3 DAC L" },
+ { "DAC L1 Mux", NULL, "DAC Stereo1 Filter" },
+
+ { "DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R" },
+ { "DAC R1 Mux", "IF2 DAC", "IF2 DAC R" },
+ { "DAC R1 Mux", "IF3 DAC", "IF3 DAC R" },
+ { "DAC R1 Mux", NULL, "DAC Stereo1 Filter" },
+
+ { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC Volume L" },
+ { "DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux" },
+ { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC Volume R" },
+ { "DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux" },
+
+ { "DAC_REF", NULL, "DAC1 MIXL" },
+ { "DAC_REF", NULL, "DAC1 MIXR" },
+
+ { "DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L" },
+ { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+ { "DAC L2 Mux", "IF3 DAC", "IF3 DAC L" },
+ { "DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL" },
+ { "DAC L2 Mux", NULL, "DAC Mono Left Filter" },
+
+ { "DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R" },
+ { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+ { "DAC R2 Mux", "IF3 DAC", "IF3 DAC R" },
+ { "DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR" },
+ { "DAC R2 Mux", NULL, "DAC Mono Right Filter" },
+
+ { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+ { "Stereo DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+
+ { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Stereo DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+ { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+
+ { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+ { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+ { "Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+ { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+
+ { "DAC MIXL", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+ { "DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL" },
+ { "DAC MIXR", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+ { "DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR" },
+
+ { "DAC L1 Source", NULL, "DAC L1 Power" },
+ { "DAC L1 Source", "DAC", "DAC1 MIXL" },
+ { "DAC L1 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+ { "DAC R1 Source", NULL, "DAC R1 Power" },
+ { "DAC R1 Source", "DAC", "DAC1 MIXR" },
+ { "DAC R1 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+ { "DAC L2 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+ { "DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL" },
+ { "DAC L2 Source", NULL, "DAC L2 Power" },
+ { "DAC R2 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+ { "DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR" },
+ { "DAC R2 Source", NULL, "DAC R2 Power" },
+
+ { "DAC L1", NULL, "DAC L1 Source" },
+ { "DAC R1", NULL, "DAC R1 Source" },
+ { "DAC L2", NULL, "DAC L2 Source" },
+ { "DAC R2", NULL, "DAC R2 Source" },
+
+ { "SPK MIXL", "DAC L2 Switch", "DAC L2" },
+ { "SPK MIXL", "BST1 Switch", "BST1" },
+ { "SPK MIXL", "INL Switch", "INL VOL" },
+ { "SPK MIXL", "INR Switch", "INR VOL" },
+ { "SPK MIXL", "BST3 Switch", "BST3" },
+ { "SPK MIXR", "DAC R2 Switch", "DAC R2" },
+ { "SPK MIXR", "BST4 Switch", "BST4" },
+ { "SPK MIXR", "INL Switch", "INL VOL" },
+ { "SPK MIXR", "INR Switch", "INR VOL" },
+ { "SPK MIXR", "BST3 Switch", "BST3" },
+
+ { "MONOVOL MIX", "DAC L2 Switch", "DAC L2" },
+ { "MONOVOL MIX", "DAC R2 Switch", "DAC R2" },
+ { "MONOVOL MIX", "BST1 Switch", "BST1" },
+ { "MONOVOL MIX", "BST2 Switch", "BST2" },
+ { "MONOVOL MIX", "BST3 Switch", "BST3" },
+
+ { "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+ { "OUT MIXL", "INL Switch", "INL VOL" },
+ { "OUT MIXL", "BST1 Switch", "BST1" },
+ { "OUT MIXL", "BST2 Switch", "BST2" },
+ { "OUT MIXL", "BST3 Switch", "BST3" },
+ { "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+ { "OUT MIXR", "INR Switch", "INR VOL" },
+ { "OUT MIXR", "BST2 Switch", "BST2" },
+ { "OUT MIXR", "BST3 Switch", "BST3" },
+ { "OUT MIXR", "BST4 Switch", "BST4" },
+
+ { "SPKVOL L", "Switch", "SPK MIXL" },
+ { "SPKVOL R", "Switch", "SPK MIXR" },
+ { "SPO L MIX", "DAC L2 Switch", "DAC L2" },
+ { "SPO L MIX", "SPKVOL L Switch", "SPKVOL L" },
+ { "SPO R MIX", "DAC R2 Switch", "DAC R2" },
+ { "SPO R MIX", "SPKVOL R Switch", "SPKVOL R" },
+ { "SPK Amp", NULL, "SPO L MIX" },
+ { "SPK Amp", NULL, "SPO R MIX" },
+ { "SPK Amp", NULL, "SYS CLK DET" },
+ { "SPO Playback", "Switch", "SPK Amp" },
+ { "SPOL", NULL, "SPO Playback" },
+ { "SPOR", NULL, "SPO Playback" },
+
+ { "MONOVOL", "Switch", "MONOVOL MIX" },
+ { "Mono MIX", "DAC L2 Switch", "DAC L2" },
+ { "Mono MIX", "MONOVOL Switch", "MONOVOL" },
+ { "Mono Amp", NULL, "Mono MIX" },
+ { "Mono Amp", NULL, "Mono Vref" },
+ { "Mono Amp", NULL, "SYS CLK DET" },
+ { "Mono Playback", "Switch", "Mono Amp" },
+ { "MONOOUT", NULL, "Mono Playback" },
+
+ { "HP Amp", NULL, "DAC L1" },
+ { "HP Amp", NULL, "DAC R1" },
+ { "HP Amp", NULL, "Charge Pump" },
+ { "HP Amp", NULL, "SYS CLK DET" },
+ { "HPO L Playback", "Switch", "HP Amp"},
+ { "HPO R Playback", "Switch", "HP Amp"},
+ { "HPOL", NULL, "HPO L Playback" },
+ { "HPOR", NULL, "HPO R Playback" },
+
+ { "OUTVOL L", "Switch", "OUT MIXL" },
+ { "OUTVOL R", "Switch", "OUT MIXR" },
+ { "LOUT L MIX", "DAC L2 Switch", "DAC L2" },
+ { "LOUT L MIX", "OUTVOL L Switch", "OUTVOL L" },
+ { "LOUT R MIX", "DAC R2 Switch", "DAC R2" },
+ { "LOUT R MIX", "OUTVOL R Switch", "OUTVOL R" },
+ { "LOUT Amp", NULL, "LOUT L MIX" },
+ { "LOUT Amp", NULL, "LOUT R MIX" },
+ { "LOUT Amp", NULL, "SYS CLK DET" },
+ { "LOUT L Playback", "Switch", "LOUT Amp" },
+ { "LOUT R Playback", "Switch", "LOUT Amp" },
+ { "LOUTL", NULL, "LOUT L Playback" },
+ { "LOUTR", NULL, "LOUT R Playback" },
+
+ { "PDM L Mux", "Mono DAC", "Mono DAC MIXL" },
+ { "PDM L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+ { "PDM L Mux", NULL, "PDM Power" },
+ { "PDM R Mux", "Mono DAC", "Mono DAC MIXR" },
+ { "PDM R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+ { "PDM R Mux", NULL, "PDM Power" },
+ { "PDM L Playback", "Switch", "PDM L Mux" },
+ { "PDM R Playback", "Switch", "PDM R Mux" },
+ { "PDML", NULL, "PDM L Playback" },
+ { "PDMR", NULL, "PDM R Playback" },
+
+ { "SPDIF Mux", "IF3_DAC", "IF3 DAC" },
+ { "SPDIF Mux", "IF2_DAC", "IF2 DAC" },
+ { "SPDIF Mux", "IF1_DAC2", "IF1 DAC2" },
+ { "SPDIF Mux", "IF1_DAC1", "IF1 DAC1" },
+ { "SPDIF", NULL, "SPDIF Mux" },
+};
+
+static int rt5659_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val_len = 0, val_clk, mask_clk;
+ int pre_div, frame_size;
+
+ rt5659->lrck[dai->id] = params_rate(params);
+ pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]);
+ if (pre_div < 0) {
+ dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+ rt5659->lrck[dai->id], dai->id);
+ return -EINVAL;
+ }
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+ rt5659->lrck[dai->id], pre_div, dai->id);
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ val_len |= RT5659_I2S_DL_20;
+ break;
+ case 24:
+ val_len |= RT5659_I2S_DL_24;
+ break;
+ case 8:
+ val_len |= RT5659_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5659_AIF1:
+ mask_clk = RT5659_I2S_PD1_MASK;
+ val_clk = pre_div << RT5659_I2S_PD1_SFT;
+ snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+ RT5659_I2S_DL_MASK, val_len);
+ break;
+ case RT5659_AIF2:
+ mask_clk = RT5659_I2S_PD2_MASK;
+ val_clk = pre_div << RT5659_I2S_PD2_SFT;
+ snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+ RT5659_I2S_DL_MASK, val_len);
+ break;
+ case RT5659_AIF3:
+ mask_clk = RT5659_I2S_PD3_MASK;
+ val_clk = pre_div << RT5659_I2S_PD3_SFT;
+ snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+ RT5659_I2S_DL_MASK, val_len);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, mask_clk, val_clk);
+
+ switch (rt5659->lrck[dai->id]) {
+ case 192000:
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+ RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32);
+ break;
+ case 96000:
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+ RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64);
+ break;
+ default:
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+ RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128);
+ break;
+ }
+
+ return 0;
+}
+
+static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5659->master[dai->id] = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg_val |= RT5659_I2S_MS_S;
+ rt5659->master[dai->id] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT5659_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT5659_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT5659_I2S_DF_PCM_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT5659_I2S_DF_PCM_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5659_AIF1:
+ snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+ RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+ RT5659_I2S_DF_MASK, reg_val);
+ break;
+ case RT5659_AIF2:
+ snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+ RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+ RT5659_I2S_DF_MASK, reg_val);
+ break;
+ case RT5659_AIF3:
+ snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+ RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+ RT5659_I2S_DF_MASK, reg_val);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT5659_SCLK_S_MCLK:
+ reg_val |= RT5659_SCLK_SRC_MCLK;
+ break;
+ case RT5659_SCLK_S_PLL1:
+ reg_val |= RT5659_SCLK_SRC_PLL1;
+ break;
+ case RT5659_SCLK_S_RCCLK:
+ reg_val |= RT5659_SCLK_SRC_RCCLK;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, RT5659_GLB_CLK,
+ RT5659_SCLK_SRC_MASK, reg_val);
+ rt5659->sysclk = freq;
+ rt5659->sysclk_src = clk_id;
+
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+ return 0;
+}
+
+static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (Source == rt5659->pll_src && freq_in == rt5659->pll_in &&
+ freq_out == rt5659->pll_out)
+ return 0;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(codec->dev, "PLL disabled\n");
+
+ rt5659->pll_in = 0;
+ rt5659->pll_out = 0;
+ snd_soc_update_bits(codec, RT5659_GLB_CLK,
+ RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK);
+ return 0;
+ }
+
+ switch (Source) {
+ case RT5659_PLL1_S_MCLK:
+ snd_soc_update_bits(codec, RT5659_GLB_CLK,
+ RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
+ break;
+ case RT5659_PLL1_S_BCLK1:
+ snd_soc_update_bits(codec, RT5659_GLB_CLK,
+ RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1);
+ break;
+ case RT5659_PLL1_S_BCLK2:
+ snd_soc_update_bits(codec, RT5659_GLB_CLK,
+ RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2);
+ break;
+ case RT5659_PLL1_S_BCLK3:
+ snd_soc_update_bits(codec, RT5659_GLB_CLK,
+ RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
+ break;
+ default:
+ dev_err(codec->dev, "Unknown PLL Source %d\n", Source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ snd_soc_write(codec, RT5659_PLL_CTRL_1,
+ pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code);
+ snd_soc_write(codec, RT5659_PLL_CTRL_2,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT |
+ pll_code.m_bp << RT5659_PLL_M_BP_SFT);
+
+ rt5659->pll_in = freq_in;
+ rt5659->pll_out = freq_out;
+ rt5659->pll_src = Source;
+
+ return 0;
+}
+
+static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int val = 0;
+
+ if (rx_mask || tx_mask)
+ val |= (1 << 15);
+
+ switch (slots) {
+ case 4:
+ val |= (1 << 10);
+ val |= (1 << 8);
+ break;
+ case 6:
+ val |= (2 << 10);
+ val |= (2 << 8);
+ break;
+ case 8:
+ val |= (3 << 10);
+ val |= (3 << 8);
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (slot_width) {
+ case 20:
+ val |= (1 << 6);
+ val |= (1 << 4);
+ break;
+ case 24:
+ val |= (2 << 6);
+ val |= (2 << 4);
+ break;
+ case 32:
+ val |= (3 << 6);
+ val |= (3 << 4);
+ break;
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, RT5659_TDM_CTRL_1, 0x8ff0, val);
+
+ return 0;
+}
+
+static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+
+ rt5659->bclk[dai->id] = ratio;
+
+ if (ratio == 64) {
+ switch (dai->id) {
+ case RT5659_AIF2:
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+ RT5659_I2S_BCLK_MS2_MASK,
+ RT5659_I2S_BCLK_MS2_64);
+ break;
+ case RT5659_AIF3:
+ snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+ RT5659_I2S_BCLK_MS3_MASK,
+ RT5659_I2S_BCLK_MS3_64);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int rt5659_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+ RT5659_DIG_GATE_CTRL, RT5659_DIG_GATE_CTRL);
+ regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+ RT5659_PWR_LDO, RT5659_PWR_LDO);
+ regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+ RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2,
+ RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2);
+ msleep(20);
+ regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+ RT5659_PWR_FV1 | RT5659_PWR_FV2,
+ RT5659_PWR_FV1 | RT5659_PWR_FV2);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+ RT5659_PWR_LDO, 0);
+ regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+ RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2
+ | RT5659_PWR_FV1 | RT5659_PWR_FV2,
+ RT5659_PWR_MB | RT5659_PWR_VREF2);
+ regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+ RT5659_DIG_GATE_CTRL, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt5659_probe(struct snd_soc_codec *codec)
+{
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ rt5659->codec = codec;
+
+ return 0;
+}
+
+static int rt5659_remove(struct snd_soc_codec *codec)
+{
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5659_suspend(struct snd_soc_codec *codec)
+{
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5659->regmap, true);
+ regcache_mark_dirty(rt5659->regmap);
+ return 0;
+}
+
+static int rt5659_resume(struct snd_soc_codec *codec)
+{
+ struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5659->regmap, false);
+ regcache_sync(rt5659->regmap);
+
+ return 0;
+}
+#else
+#define rt5659_suspend NULL
+#define rt5659_resume NULL
+#endif
+
+#define RT5659_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5659_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5659_aif_dai_ops = {
+ .hw_params = rt5659_hw_params,
+ .set_fmt = rt5659_set_dai_fmt,
+ .set_sysclk = rt5659_set_dai_sysclk,
+ .set_tdm_slot = rt5659_set_tdm_slot,
+ .set_pll = rt5659_set_dai_pll,
+ .set_bclk_ratio = rt5659_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5659_dai[] = {
+ {
+ .name = "rt5659-aif1",
+ .id = RT5659_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5659_STEREO_RATES,
+ .formats = RT5659_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5659_STEREO_RATES,
+ .formats = RT5659_FORMATS,
+ },
+ .ops = &rt5659_aif_dai_ops,
+ },
+ {
+ .name = "rt5659-aif2",
+ .id = RT5659_AIF2,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5659_STEREO_RATES,
+ .formats = RT5659_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5659_STEREO_RATES,
+ .formats = RT5659_FORMATS,
+ },
+ .ops = &rt5659_aif_dai_ops,
+ },
+ {
+ .name = "rt5659-aif3",
+ .id = RT5659_AIF3,
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5659_STEREO_RATES,
+ .formats = RT5659_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5659_STEREO_RATES,
+ .formats = RT5659_FORMATS,
+ },
+ .ops = &rt5659_aif_dai_ops,
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
+ .probe = rt5659_probe,
+ .remove = rt5659_remove,
+ .suspend = rt5659_suspend,
+ .resume = rt5659_resume,
+ .set_bias_level = rt5659_set_bias_level,
+ .idle_bias_off = true,
+ .controls = rt5659_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5659_snd_controls),
+ .dapm_widgets = rt5659_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets),
+ .dapm_routes = rt5659_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes),
+};
+
+
+static const struct regmap_config rt5659_regmap = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = 0x0400,
+ .volatile_reg = rt5659_volatile_register,
+ .readable_reg = rt5659_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5659_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5659_reg),
+};
+
+static const struct i2c_device_id rt5659_i2c_id[] = {
+ { "rt5658", 0 },
+ { "rt5659", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id);
+
+static int rt5659_parse_dt(struct rt5659_priv *rt5659, struct device *dev)
+{
+ rt5659->pdata.in1_diff = device_property_read_bool(dev,
+ "realtek,in1-differential");
+ rt5659->pdata.in3_diff = device_property_read_bool(dev,
+ "realtek,in3-differential");
+ rt5659->pdata.in4_diff = device_property_read_bool(dev,
+ "realtek,in4-differential");
+
+
+ device_property_read_u32(dev, "realtek,dmic1-data-pin",
+ &rt5659->pdata.dmic1_data_pin);
+ device_property_read_u32(dev, "realtek,dmic2-data-pin",
+ &rt5659->pdata.dmic2_data_pin);
+ device_property_read_u32(dev, "realtek,jd-src",
+ &rt5659->pdata.jd_src);
+
+ return 0;
+}
+
+static void rt5659_calibrate(struct rt5659_priv *rt5659)
+{
+ int value, count;
+
+ /* Calibrate HPO Start */
+ /* Fine tune HP Performance */
+ regmap_write(rt5659->regmap, RT5659_BIAS_CUR_CTRL_8, 0xa502);
+ regmap_write(rt5659->regmap, RT5659_CHOP_DAC, 0x3030);
+
+ regmap_write(rt5659->regmap, RT5659_PRE_DIV_1, 0xef00);
+ regmap_write(rt5659->regmap, RT5659_PRE_DIV_2, 0xeffc);
+ regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0280);
+ regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0001);
+ regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x8000);
+
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xaa7e);
+ msleep(60);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe7e);
+ msleep(50);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0004);
+ regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0400);
+ msleep(50);
+ regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0080);
+ usleep_range(10000, 10005);
+ regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0009);
+ msleep(50);
+ regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0f80);
+ msleep(50);
+ regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0e16);
+ msleep(50);
+
+ /* Enalbe K ADC Power And Clock */
+ regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0505);
+ msleep(50);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0184);
+ regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x3c05);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c1);
+
+ /* K Headphone */
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x5100);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0014);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0xd100);
+ msleep(60);
+
+ /* Manual K ADC Offset */
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4900);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0016);
+ regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+ 0x8000, 0x8000);
+
+ count = 0;
+ while (true) {
+ regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+ if (value & 0x8000)
+ usleep_range(10000, 10005);
+ else
+ break;
+
+ if (count > 30) {
+ dev_err(rt5659->codec->dev,
+ "HP Calibration 1 Failure\n");
+ return;
+ }
+
+ count++;
+ }
+
+ /* Manual K Internal Path Offset */
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+ regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4500);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x001f);
+ regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+ 0x8000, 0x8000);
+
+ count = 0;
+ while (true) {
+ regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+ if (value & 0x8000)
+ usleep_range(10000, 10005);
+ else
+ break;
+
+ if (count > 85) {
+ dev_err(rt5659->codec->dev,
+ "HP Calibration 2 Failure\n");
+ return;
+ }
+
+ count++;
+ }
+
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+ /* Calibrate HPO End */
+
+ /* Calibrate SPO Start */
+ regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0260);
+ regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x3000);
+ regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0xc000);
+ regmap_write(rt5659->regmap, RT5659_A_DAC_MUX, 0x000c);
+ regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x8000);
+ regmap_write(rt5659->regmap, RT5659_SPO_VOL, 0x0808);
+ regmap_write(rt5659->regmap, RT5659_SPK_L_MIXER, 0x001e);
+ regmap_write(rt5659->regmap, RT5659_SPK_R_MIXER, 0x001e);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0803);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0554);
+ regmap_write(rt5659->regmap, RT5659_SPO_AMP_GAIN, 0x1103);
+
+ /* Enalbe K ADC Power And Clock */
+ regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0909);
+ regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x0001,
+ 0x0001);
+
+ /* Start Calibration */
+ regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x0021);
+ regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, 0x3e80);
+ regmap_update_bits(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1,
+ 0x8000, 0x8000);
+
+ count = 0;
+ while (true) {
+ regmap_read(rt5659->regmap,
+ RT5659_SPK_DC_CAILB_CTRL_1, &value);
+ if (value & 0x8000)
+ usleep_range(10000, 10005);
+ else
+ break;
+
+ if (count > 10) {
+ dev_err(rt5659->codec->dev,
+ "SPK Calibration Failure\n");
+ return;
+ }
+
+ count++;
+ }
+ /* Calibrate SPO End */
+
+ /* Calibrate MONO Start */
+ regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_MONOMIX_IN_GAIN, 0x021f);
+ regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0x480a);
+ /* MONO NG2 GAIN 5dB */
+ regmap_write(rt5659->regmap, RT5659_MONO_GAIN, 0x0003);
+ regmap_write(rt5659->regmap, RT5659_MONO_NG2_CTRL_5, 0x0009);
+
+ /* Start Calibration */
+ regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x000f);
+ regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+ regmap_update_bits(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+ 0x8000, 0x8000);
+
+ count = 0;
+ while (true) {
+ regmap_read(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+ &value);
+ if (value & 0x8000)
+ usleep_range(10000, 10005);
+ else
+ break;
+
+ if (count > 35) {
+ dev_err(rt5659->codec->dev,
+ "Mono Calibration Failure\n");
+ return;
+ }
+
+ count++;
+ }
+
+ regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+ /* Calibrate MONO End */
+
+ /* Power Off */
+ regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0808);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x2005);
+ regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+ regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0011);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0150);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe3e);
+ regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0xc80a);
+ regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+ regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0x003e);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0060);
+ regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+ regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x0000);
+ regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0080);
+ regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x8080);
+ regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+}
+
+static int rt5659_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt5659_priv *rt5659;
+ int ret;
+ unsigned int val;
+
+ rt5659 = devm_kzalloc(&i2c->dev, sizeof(struct rt5659_priv),
+ GFP_KERNEL);
+
+ if (rt5659 == NULL)
+ return -ENOMEM;
+
+ rt5659->i2c = i2c;
+ i2c_set_clientdata(i2c, rt5659);
+
+ if (pdata)
+ rt5659->pdata = *pdata;
+ else
+ rt5659_parse_dt(rt5659, &i2c->dev);
+
+ rt5659->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, "ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5659->gpiod_ldo1_en))
+ dev_warn(&i2c->dev, "Request ldo1-en GPIO failed\n");
+
+ rt5659->gpiod_reset = devm_gpiod_get_optional(&i2c->dev, "reset",
+ GPIOD_OUT_HIGH);
+
+ /* Sleep for 300 ms miniumum */
+ usleep_range(300000, 350000);
+
+ rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap);
+ if (IS_ERR(rt5659->regmap)) {
+ ret = PTR_ERR(rt5659->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt5659->regmap, RT5659_DEVICE_ID, &val);
+ if (val != DEVICE_ID) {
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt5659\n", val);
+ return -ENODEV;
+ }
+
+ regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+ rt5659_calibrate(rt5659);
+
+ /* line in diff mode*/
+ if (rt5659->pdata.in1_diff)
+ regmap_update_bits(rt5659->regmap, RT5659_IN1_IN2,
+ RT5659_IN1_DF_MASK, RT5659_IN1_DF_MASK);
+ if (rt5659->pdata.in3_diff)
+ regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+ RT5659_IN3_DF_MASK, RT5659_IN3_DF_MASK);
+ if (rt5659->pdata.in4_diff)
+ regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+ RT5659_IN4_DF_MASK, RT5659_IN4_DF_MASK);
+
+ /* DMIC pin*/
+ if (rt5659->pdata.dmic1_data_pin != RT5659_DMIC1_NULL ||
+ rt5659->pdata.dmic2_data_pin != RT5659_DMIC2_NULL) {
+ regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+ RT5659_GP2_PIN_MASK, RT5659_GP2_PIN_DMIC1_SCL);
+
+ switch (rt5659->pdata.dmic1_data_pin) {
+ case RT5659_DMIC1_DATA_IN2N:
+ regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_IN2N);
+ break;
+
+ case RT5659_DMIC1_DATA_GPIO5:
+ regmap_update_bits(rt5659->regmap,
+ RT5659_GPIO_CTRL_3,
+ RT5659_I2S2_PIN_MASK,
+ RT5659_I2S2_PIN_GPIO);
+ regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO5);
+ regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+ RT5659_GP5_PIN_MASK, RT5659_GP5_PIN_DMIC1_SDA);
+ break;
+
+ case RT5659_DMIC1_DATA_GPIO9:
+ regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO9);
+ regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+ RT5659_GP9_PIN_MASK, RT5659_GP9_PIN_DMIC1_SDA);
+ break;
+
+ case RT5659_DMIC1_DATA_GPIO11:
+ regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO11);
+ regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+ RT5659_GP11_PIN_MASK,
+ RT5659_GP11_PIN_DMIC1_SDA);
+ break;
+
+ default:
+ dev_dbg(&i2c->dev, "no DMIC1\n");
+ break;
+ }
+
+ switch (rt5659->pdata.dmic2_data_pin) {
+ case RT5659_DMIC2_DATA_IN2P:
+ regmap_update_bits(rt5659->regmap,
+ RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_2_DP_MASK,
+ RT5659_DMIC_2_DP_IN2P);
+ break;
+
+ case RT5659_DMIC2_DATA_GPIO6:
+ regmap_update_bits(rt5659->regmap,
+ RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_2_DP_MASK,
+ RT5659_DMIC_2_DP_GPIO6);
+ regmap_update_bits(rt5659->regmap,
+ RT5659_GPIO_CTRL_1,
+ RT5659_GP6_PIN_MASK,
+ RT5659_GP6_PIN_DMIC2_SDA);
+ break;
+
+ case RT5659_DMIC2_DATA_GPIO10:
+ regmap_update_bits(rt5659->regmap,
+ RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_2_DP_MASK,
+ RT5659_DMIC_2_DP_GPIO10);
+ regmap_update_bits(rt5659->regmap,
+ RT5659_GPIO_CTRL_1,
+ RT5659_GP10_PIN_MASK,
+ RT5659_GP10_PIN_DMIC2_SDA);
+ break;
+
+ case RT5659_DMIC2_DATA_GPIO12:
+ regmap_update_bits(rt5659->regmap,
+ RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_2_DP_MASK,
+ RT5659_DMIC_2_DP_GPIO12);
+ regmap_update_bits(rt5659->regmap,
+ RT5659_GPIO_CTRL_1,
+ RT5659_GP12_PIN_MASK,
+ RT5659_GP12_PIN_DMIC2_SDA);
+ break;
+
+ default:
+ dev_dbg(&i2c->dev, "no DMIC2\n");
+ break;
+
+ }
+ } else {
+ regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+ RT5659_GP2_PIN_MASK | RT5659_GP5_PIN_MASK |
+ RT5659_GP9_PIN_MASK | RT5659_GP11_PIN_MASK |
+ RT5659_GP6_PIN_MASK | RT5659_GP10_PIN_MASK |
+ RT5659_GP12_PIN_MASK,
+ RT5659_GP2_PIN_GPIO2 | RT5659_GP5_PIN_GPIO5 |
+ RT5659_GP9_PIN_GPIO9 | RT5659_GP11_PIN_GPIO11 |
+ RT5659_GP6_PIN_GPIO6 | RT5659_GP10_PIN_GPIO10 |
+ RT5659_GP12_PIN_GPIO12);
+ regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+ RT5659_DMIC_1_DP_MASK | RT5659_DMIC_2_DP_MASK,
+ RT5659_DMIC_1_DP_IN2N | RT5659_DMIC_2_DP_IN2P);
+ }
+
+ switch (rt5659->pdata.jd_src) {
+ case RT5659_JD3:
+ regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1, 0xa880);
+ regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x9000);
+ regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_1, 0xc800);
+ regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+ RT5659_PWR_MB, RT5659_PWR_MB);
+ regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001);
+ regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040);
+ break;
+ case RT5659_JD_NULL:
+ break;
+ default:
+ dev_warn(&i2c->dev, "Currently, support JD3 only\n");
+ break;
+ }
+
+ INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work);
+
+ if (rt5659->i2c->irq) {
+ ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_ONESHOT, "rt5659", rt5659);
+ if (ret)
+ dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
+ rt5659_dai, ARRAY_SIZE(rt5659_dai));
+
+ if (ret) {
+ if (rt5659->i2c->irq)
+ free_irq(rt5659->i2c->irq, rt5659);
+ }
+
+ return 0;
+}
+
+static int rt5659_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+void rt5659_i2c_shutdown(struct i2c_client *client)
+{
+ struct rt5659_priv *rt5659 = i2c_get_clientdata(client);
+
+ regmap_write(rt5659->regmap, RT5659_RESET, 0);
+}
+
+static const struct of_device_id rt5659_of_match[] = {
+ { .compatible = "realtek,rt5658", },
+ { .compatible = "realtek,rt5659", },
+ {},
+};
+
+static struct acpi_device_id rt5659_acpi_match[] = {
+ { "10EC5658", 0},
+ { "10EC5659", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
+
+struct i2c_driver rt5659_i2c_driver = {
+ .driver = {
+ .name = "rt5659",
+ .owner = THIS_MODULE,
+ .of_match_table = rt5659_of_match,
+ .acpi_match_table = ACPI_PTR(rt5659_acpi_match),
+ },
+ .probe = rt5659_i2c_probe,
+ .remove = rt5659_i2c_remove,
+ .shutdown = rt5659_i2c_shutdown,
+ .id_table = rt5659_i2c_id,
+};
+module_i2c_driver(rt5659_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5659 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
new file mode 100644
index 000000000000..8f07ee903eaa
--- /dev/null
+++ b/sound/soc/codecs/rt5659.h
@@ -0,0 +1,1819 @@
+/*
+ * rt5659.h -- RT5659/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2015 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.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 __RT5659_H__
+#define __RT5659_H__
+
+#include <sound/rt5659.h>
+
+#define DEVICE_ID 0x6311
+
+/* Info */
+#define RT5659_RESET 0x0000
+#define RT5659_VENDOR_ID 0x00fd
+#define RT5659_VENDOR_ID_1 0x00fe
+#define RT5659_DEVICE_ID 0x00ff
+/* I/O - Output */
+#define RT5659_SPO_VOL 0x0001
+#define RT5659_HP_VOL 0x0002
+#define RT5659_LOUT 0x0003
+#define RT5659_MONO_OUT 0x0004
+#define RT5659_HPL_GAIN 0x0005
+#define RT5659_HPR_GAIN 0x0006
+#define RT5659_MONO_GAIN 0x0007
+#define RT5659_SPDIF_CTRL_1 0x0008
+#define RT5659_SPDIF_CTRL_2 0x0009
+/* I/O - Input */
+#define RT5659_CAL_BST_CTRL 0x000a
+#define RT5659_IN1_IN2 0x000c
+#define RT5659_IN3_IN4 0x000d
+#define RT5659_INL1_INR1_VOL 0x000f
+/* I/O - Speaker */
+#define RT5659_EJD_CTRL_1 0x0010
+#define RT5659_EJD_CTRL_2 0x0011
+#define RT5659_EJD_CTRL_3 0x0012
+#define RT5659_SILENCE_CTRL 0x0015
+#define RT5659_PSV_CTRL 0x0016
+/* I/O - Sidetone */
+#define RT5659_SIDETONE_CTRL 0x0018
+/* I/O - ADC/DAC/DMIC */
+#define RT5659_DAC1_DIG_VOL 0x0019
+#define RT5659_DAC2_DIG_VOL 0x001a
+#define RT5659_DAC_CTRL 0x001b
+#define RT5659_STO1_ADC_DIG_VOL 0x001c
+#define RT5659_MONO_ADC_DIG_VOL 0x001d
+#define RT5659_STO2_ADC_DIG_VOL 0x001e
+#define RT5659_STO1_BOOST 0x001f
+#define RT5659_MONO_BOOST 0x0020
+#define RT5659_STO2_BOOST 0x0021
+#define RT5659_HP_IMP_GAIN_1 0x0022
+#define RT5659_HP_IMP_GAIN_2 0x0023
+/* Mixer - D-D */
+#define RT5659_STO1_ADC_MIXER 0x0026
+#define RT5659_MONO_ADC_MIXER 0x0027
+#define RT5659_AD_DA_MIXER 0x0029
+#define RT5659_STO_DAC_MIXER 0x002a
+#define RT5659_MONO_DAC_MIXER 0x002b
+#define RT5659_DIG_MIXER 0x002c
+#define RT5659_A_DAC_MUX 0x002d
+#define RT5659_DIG_INF23_DATA 0x002f
+/* Mixer - PDM */
+#define RT5659_PDM_OUT_CTRL 0x0031
+#define RT5659_PDM_DATA_CTRL_1 0x0032
+#define RT5659_PDM_DATA_CTRL_2 0x0033
+#define RT5659_PDM_DATA_CTRL_3 0x0034
+#define RT5659_PDM_DATA_CTRL_4 0x0035
+#define RT5659_SPDIF_CTRL 0x0036
+
+/* Mixer - ADC */
+#define RT5659_REC1_GAIN 0x003a
+#define RT5659_REC1_L1_MIXER 0x003b
+#define RT5659_REC1_L2_MIXER 0x003c
+#define RT5659_REC1_R1_MIXER 0x003d
+#define RT5659_REC1_R2_MIXER 0x003e
+#define RT5659_CAL_REC 0x0040
+#define RT5659_REC2_L1_MIXER 0x009b
+#define RT5659_REC2_L2_MIXER 0x009c
+#define RT5659_REC2_R1_MIXER 0x009d
+#define RT5659_REC2_R2_MIXER 0x009e
+#define RT5659_RC_CLK_CTRL 0x009f
+/* Mixer - DAC */
+#define RT5659_SPK_L_MIXER 0x0046
+#define RT5659_SPK_R_MIXER 0x0047
+#define RT5659_SPO_AMP_GAIN 0x0048
+#define RT5659_ALC_BACK_GAIN 0x0049
+#define RT5659_MONOMIX_GAIN 0x004a
+#define RT5659_MONOMIX_IN_GAIN 0x004b
+#define RT5659_OUT_L_GAIN 0x004d
+#define RT5659_OUT_L_MIXER 0x004e
+#define RT5659_OUT_R_GAIN 0x004f
+#define RT5659_OUT_R_MIXER 0x0050
+#define RT5659_LOUT_MIXER 0x0052
+
+#define RT5659_HAPTIC_GEN_CTRL_1 0x0053
+#define RT5659_HAPTIC_GEN_CTRL_2 0x0054
+#define RT5659_HAPTIC_GEN_CTRL_3 0x0055
+#define RT5659_HAPTIC_GEN_CTRL_4 0x0056
+#define RT5659_HAPTIC_GEN_CTRL_5 0x0057
+#define RT5659_HAPTIC_GEN_CTRL_6 0x0058
+#define RT5659_HAPTIC_GEN_CTRL_7 0x0059
+#define RT5659_HAPTIC_GEN_CTRL_8 0x005a
+#define RT5659_HAPTIC_GEN_CTRL_9 0x005b
+#define RT5659_HAPTIC_GEN_CTRL_10 0x005c
+#define RT5659_HAPTIC_GEN_CTRL_11 0x005d
+#define RT5659_HAPTIC_LPF_CTRL_1 0x005e
+#define RT5659_HAPTIC_LPF_CTRL_2 0x005f
+#define RT5659_HAPTIC_LPF_CTRL_3 0x0060
+/* Power */
+#define RT5659_PWR_DIG_1 0x0061
+#define RT5659_PWR_DIG_2 0x0062
+#define RT5659_PWR_ANLG_1 0x0063
+#define RT5659_PWR_ANLG_2 0x0064
+#define RT5659_PWR_ANLG_3 0x0065
+#define RT5659_PWR_MIXER 0x0066
+#define RT5659_PWR_VOL 0x0067
+/* Private Register Control */
+#define RT5659_PRIV_INDEX 0x006a
+#define RT5659_CLK_DET 0x006b
+#define RT5659_PRIV_DATA 0x006c
+/* System Clock Pre Divider Gating Control */
+#define RT5659_PRE_DIV_1 0x006e
+#define RT5659_PRE_DIV_2 0x006f
+/* Format - ADC/DAC */
+#define RT5659_I2S1_SDP 0x0070
+#define RT5659_I2S2_SDP 0x0071
+#define RT5659_I2S3_SDP 0x0072
+#define RT5659_ADDA_CLK_1 0x0073
+#define RT5659_ADDA_CLK_2 0x0074
+#define RT5659_DMIC_CTRL_1 0x0075
+#define RT5659_DMIC_CTRL_2 0x0076
+/* Format - TDM Control */
+#define RT5659_TDM_CTRL_1 0x0077
+#define RT5659_TDM_CTRL_2 0x0078
+#define RT5659_TDM_CTRL_3 0x0079
+#define RT5659_TDM_CTRL_4 0x007a
+#define RT5659_TDM_CTRL_5 0x007b
+
+/* Function - Analog */
+#define RT5659_GLB_CLK 0x0080
+#define RT5659_PLL_CTRL_1 0x0081
+#define RT5659_PLL_CTRL_2 0x0082
+#define RT5659_ASRC_1 0x0083
+#define RT5659_ASRC_2 0x0084
+#define RT5659_ASRC_3 0x0085
+#define RT5659_ASRC_4 0x0086
+#define RT5659_ASRC_5 0x0087
+#define RT5659_ASRC_6 0x0088
+#define RT5659_ASRC_7 0x0089
+#define RT5659_ASRC_8 0x008a
+#define RT5659_ASRC_9 0x008b
+#define RT5659_ASRC_10 0x008c
+#define RT5659_DEPOP_1 0x008e
+#define RT5659_DEPOP_2 0x008f
+#define RT5659_DEPOP_3 0x0090
+#define RT5659_HP_CHARGE_PUMP_1 0x0091
+#define RT5659_HP_CHARGE_PUMP_2 0x0092
+#define RT5659_MICBIAS_1 0x0093
+#define RT5659_MICBIAS_2 0x0094
+#define RT5659_ASRC_11 0x0097
+#define RT5659_ASRC_12 0x0098
+#define RT5659_ASRC_13 0x0099
+#define RT5659_REC_M1_M2_GAIN_CTRL 0x009a
+#define RT5659_CLASSD_CTRL_1 0x00a0
+#define RT5659_CLASSD_CTRL_2 0x00a1
+
+/* Function - Digital */
+#define RT5659_ADC_EQ_CTRL_1 0x00ae
+#define RT5659_ADC_EQ_CTRL_2 0x00af
+#define RT5659_DAC_EQ_CTRL_1 0x00b0
+#define RT5659_DAC_EQ_CTRL_2 0x00b1
+#define RT5659_DAC_EQ_CTRL_3 0x00b2
+
+#define RT5659_IRQ_CTRL_1 0x00b6
+#define RT5659_IRQ_CTRL_2 0x00b7
+#define RT5659_IRQ_CTRL_3 0x00b8
+#define RT5659_IRQ_CTRL_4 0x00b9
+#define RT5659_IRQ_CTRL_5 0x00ba
+#define RT5659_IRQ_CTRL_6 0x00bb
+#define RT5659_INT_ST_1 0x00be
+#define RT5659_INT_ST_2 0x00bf
+#define RT5659_GPIO_CTRL_1 0x00c0
+#define RT5659_GPIO_CTRL_2 0x00c1
+#define RT5659_GPIO_CTRL_3 0x00c2
+#define RT5659_GPIO_CTRL_4 0x00c3
+#define RT5659_GPIO_CTRL_5 0x00c4
+#define RT5659_GPIO_STA 0x00c5
+#define RT5659_SINE_GEN_CTRL_1 0x00cb
+#define RT5659_SINE_GEN_CTRL_2 0x00cc
+#define RT5659_SINE_GEN_CTRL_3 0x00cd
+#define RT5659_HP_AMP_DET_CTRL_1 0x00d6
+#define RT5659_HP_AMP_DET_CTRL_2 0x00d7
+#define RT5659_SV_ZCD_1 0x00d9
+#define RT5659_SV_ZCD_2 0x00da
+#define RT5659_IL_CMD_1 0x00db
+#define RT5659_IL_CMD_2 0x00dc
+#define RT5659_IL_CMD_3 0x00dd
+#define RT5659_IL_CMD_4 0x00de
+#define RT5659_4BTN_IL_CMD_1 0x00df
+#define RT5659_4BTN_IL_CMD_2 0x00e0
+#define RT5659_4BTN_IL_CMD_3 0x00e1
+#define RT5659_PSV_IL_CMD_1 0x00e4
+#define RT5659_PSV_IL_CMD_2 0x00e5
+
+#define RT5659_ADC_STO1_HP_CTRL_1 0x00ea
+#define RT5659_ADC_STO1_HP_CTRL_2 0x00eb
+#define RT5659_ADC_MONO_HP_CTRL_1 0x00ec
+#define RT5659_ADC_MONO_HP_CTRL_2 0x00ed
+#define RT5659_AJD1_CTRL 0x00f0
+#define RT5659_AJD2_AJD3_CTRL 0x00f1
+#define RT5659_JD1_THD 0x00f2
+#define RT5659_JD2_THD 0x00f3
+#define RT5659_JD3_THD 0x00f4
+#define RT5659_JD_CTRL_1 0x00f6
+#define RT5659_JD_CTRL_2 0x00f7
+#define RT5659_JD_CTRL_3 0x00f8
+#define RT5659_JD_CTRL_4 0x00f9
+/* General Control */
+#define RT5659_DIG_MISC 0x00fa
+#define RT5659_DUMMY_2 0x00fb
+#define RT5659_DUMMY_3 0x00fc
+
+#define RT5659_DAC_ADC_DIG_VOL 0x0100
+#define RT5659_BIAS_CUR_CTRL_1 0x010a
+#define RT5659_BIAS_CUR_CTRL_2 0x010b
+#define RT5659_BIAS_CUR_CTRL_3 0x010c
+#define RT5659_BIAS_CUR_CTRL_4 0x010d
+#define RT5659_BIAS_CUR_CTRL_5 0x010e
+#define RT5659_BIAS_CUR_CTRL_6 0x010f
+#define RT5659_BIAS_CUR_CTRL_7 0x0110
+#define RT5659_BIAS_CUR_CTRL_8 0x0111
+#define RT5659_BIAS_CUR_CTRL_9 0x0112
+#define RT5659_BIAS_CUR_CTRL_10 0x0113
+#define RT5659_MEMORY_TEST 0x0116
+#define RT5659_VREF_REC_OP_FB_CAP_CTRL 0x0117
+#define RT5659_CLASSD_0 0x011a
+#define RT5659_CLASSD_1 0x011b
+#define RT5659_CLASSD_2 0x011c
+#define RT5659_CLASSD_3 0x011d
+#define RT5659_CLASSD_4 0x011e
+#define RT5659_CLASSD_5 0x011f
+#define RT5659_CLASSD_6 0x0120
+#define RT5659_CLASSD_7 0x0121
+#define RT5659_CLASSD_8 0x0122
+#define RT5659_CLASSD_9 0x0123
+#define RT5659_CLASSD_10 0x0124
+#define RT5659_CHARGE_PUMP_1 0x0125
+#define RT5659_CHARGE_PUMP_2 0x0126
+#define RT5659_DIG_IN_CTRL_1 0x0132
+#define RT5659_DIG_IN_CTRL_2 0x0133
+#define RT5659_PAD_DRIVING_CTRL 0x0137
+#define RT5659_SOFT_RAMP_DEPOP 0x0138
+#define RT5659_PLL 0x0139
+#define RT5659_CHOP_DAC 0x013a
+#define RT5659_CHOP_ADC 0x013b
+#define RT5659_CALIB_ADC_CTRL 0x013c
+#define RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL 0x013e
+#define RT5659_VOL_TEST 0x013f
+#define RT5659_TEST_MODE_CTRL_1 0x0145
+#define RT5659_TEST_MODE_CTRL_2 0x0146
+#define RT5659_TEST_MODE_CTRL_3 0x0147
+#define RT5659_TEST_MODE_CTRL_4 0x0148
+#define RT5659_BASSBACK_CTRL 0x0150
+#define RT5659_MP3_PLUS_CTRL_1 0x0151
+#define RT5659_MP3_PLUS_CTRL_2 0x0152
+#define RT5659_MP3_HPF_A1 0x0153
+#define RT5659_MP3_HPF_A2 0x0154
+#define RT5659_MP3_HPF_H0 0x0155
+#define RT5659_MP3_LPF_H0 0x0156
+#define RT5659_3D_SPK_CTRL 0x0157
+#define RT5659_3D_SPK_COEF_1 0x0158
+#define RT5659_3D_SPK_COEF_2 0x0159
+#define RT5659_3D_SPK_COEF_3 0x015a
+#define RT5659_3D_SPK_COEF_4 0x015b
+#define RT5659_3D_SPK_COEF_5 0x015c
+#define RT5659_3D_SPK_COEF_6 0x015d
+#define RT5659_3D_SPK_COEF_7 0x015e
+#define RT5659_STO_NG2_CTRL_1 0x0160
+#define RT5659_STO_NG2_CTRL_2 0x0161
+#define RT5659_STO_NG2_CTRL_3 0x0162
+#define RT5659_STO_NG2_CTRL_4 0x0163
+#define RT5659_STO_NG2_CTRL_5 0x0164
+#define RT5659_STO_NG2_CTRL_6 0x0165
+#define RT5659_STO_NG2_CTRL_7 0x0166
+#define RT5659_STO_NG2_CTRL_8 0x0167
+#define RT5659_MONO_NG2_CTRL_1 0x0170
+#define RT5659_MONO_NG2_CTRL_2 0x0171
+#define RT5659_MONO_NG2_CTRL_3 0x0172
+#define RT5659_MONO_NG2_CTRL_4 0x0173
+#define RT5659_MONO_NG2_CTRL_5 0x0174
+#define RT5659_MONO_NG2_CTRL_6 0x0175
+#define RT5659_MID_HP_AMP_DET 0x0190
+#define RT5659_LOW_HP_AMP_DET 0x0191
+#define RT5659_LDO_CTRL 0x0192
+#define RT5659_HP_DECROSS_CTRL_1 0x01b0
+#define RT5659_HP_DECROSS_CTRL_2 0x01b1
+#define RT5659_HP_DECROSS_CTRL_3 0x01b2
+#define RT5659_HP_DECROSS_CTRL_4 0x01b3
+#define RT5659_HP_IMP_SENS_CTRL_1 0x01c0
+#define RT5659_HP_IMP_SENS_CTRL_2 0x01c1
+#define RT5659_HP_IMP_SENS_CTRL_3 0x01c2
+#define RT5659_HP_IMP_SENS_CTRL_4 0x01c3
+#define RT5659_HP_IMP_SENS_MAP_1 0x01c7
+#define RT5659_HP_IMP_SENS_MAP_2 0x01c8
+#define RT5659_HP_IMP_SENS_MAP_3 0x01c9
+#define RT5659_HP_IMP_SENS_MAP_4 0x01ca
+#define RT5659_HP_IMP_SENS_MAP_5 0x01cb
+#define RT5659_HP_IMP_SENS_MAP_6 0x01cc
+#define RT5659_HP_IMP_SENS_MAP_7 0x01cd
+#define RT5659_HP_IMP_SENS_MAP_8 0x01ce
+#define RT5659_HP_LOGIC_CTRL_1 0x01da
+#define RT5659_HP_LOGIC_CTRL_2 0x01db
+#define RT5659_HP_CALIB_CTRL_1 0x01de
+#define RT5659_HP_CALIB_CTRL_2 0x01df
+#define RT5659_HP_CALIB_CTRL_3 0x01e0
+#define RT5659_HP_CALIB_CTRL_4 0x01e1
+#define RT5659_HP_CALIB_CTRL_5 0x01e2
+#define RT5659_HP_CALIB_CTRL_6 0x01e3
+#define RT5659_HP_CALIB_CTRL_7 0x01e4
+#define RT5659_HP_CALIB_CTRL_9 0x01e6
+#define RT5659_HP_CALIB_CTRL_10 0x01e7
+#define RT5659_HP_CALIB_CTRL_11 0x01e8
+#define RT5659_HP_CALIB_STA_1 0x01ea
+#define RT5659_HP_CALIB_STA_2 0x01eb
+#define RT5659_HP_CALIB_STA_3 0x01ec
+#define RT5659_HP_CALIB_STA_4 0x01ed
+#define RT5659_HP_CALIB_STA_5 0x01ee
+#define RT5659_HP_CALIB_STA_6 0x01ef
+#define RT5659_HP_CALIB_STA_7 0x01f0
+#define RT5659_HP_CALIB_STA_8 0x01f1
+#define RT5659_HP_CALIB_STA_9 0x01f2
+#define RT5659_MONO_AMP_CALIB_CTRL_1 0x01f6
+#define RT5659_MONO_AMP_CALIB_CTRL_2 0x01f7
+#define RT5659_MONO_AMP_CALIB_CTRL_3 0x01f8
+#define RT5659_MONO_AMP_CALIB_CTRL_4 0x01f9
+#define RT5659_MONO_AMP_CALIB_CTRL_5 0x01fa
+#define RT5659_MONO_AMP_CALIB_STA_1 0x01fb
+#define RT5659_MONO_AMP_CALIB_STA_2 0x01fc
+#define RT5659_MONO_AMP_CALIB_STA_3 0x01fd
+#define RT5659_MONO_AMP_CALIB_STA_4 0x01fe
+#define RT5659_SPK_PWR_LMT_CTRL_1 0x0200
+#define RT5659_SPK_PWR_LMT_CTRL_2 0x0201
+#define RT5659_SPK_PWR_LMT_CTRL_3 0x0202
+#define RT5659_SPK_PWR_LMT_STA_1 0x0203
+#define RT5659_SPK_PWR_LMT_STA_2 0x0204
+#define RT5659_SPK_PWR_LMT_STA_3 0x0205
+#define RT5659_SPK_PWR_LMT_STA_4 0x0206
+#define RT5659_SPK_PWR_LMT_STA_5 0x0207
+#define RT5659_SPK_PWR_LMT_STA_6 0x0208
+#define RT5659_FLEX_SPK_BST_CTRL_1 0x0256
+#define RT5659_FLEX_SPK_BST_CTRL_2 0x0257
+#define RT5659_FLEX_SPK_BST_CTRL_3 0x0258
+#define RT5659_FLEX_SPK_BST_CTRL_4 0x0259
+#define RT5659_SPK_EX_LMT_CTRL_1 0x025a
+#define RT5659_SPK_EX_LMT_CTRL_2 0x025b
+#define RT5659_SPK_EX_LMT_CTRL_3 0x025c
+#define RT5659_SPK_EX_LMT_CTRL_4 0x025d
+#define RT5659_SPK_EX_LMT_CTRL_5 0x025e
+#define RT5659_SPK_EX_LMT_CTRL_6 0x025f
+#define RT5659_SPK_EX_LMT_CTRL_7 0x0260
+#define RT5659_ADJ_HPF_CTRL_1 0x0261
+#define RT5659_ADJ_HPF_CTRL_2 0x0262
+#define RT5659_SPK_DC_CAILB_CTRL_1 0x0265
+#define RT5659_SPK_DC_CAILB_CTRL_2 0x0266
+#define RT5659_SPK_DC_CAILB_CTRL_3 0x0267
+#define RT5659_SPK_DC_CAILB_CTRL_4 0x0268
+#define RT5659_SPK_DC_CAILB_CTRL_5 0x0269
+#define RT5659_SPK_DC_CAILB_STA_1 0x026a
+#define RT5659_SPK_DC_CAILB_STA_2 0x026b
+#define RT5659_SPK_DC_CAILB_STA_3 0x026c
+#define RT5659_SPK_DC_CAILB_STA_4 0x026d
+#define RT5659_SPK_DC_CAILB_STA_5 0x026e
+#define RT5659_SPK_DC_CAILB_STA_6 0x026f
+#define RT5659_SPK_DC_CAILB_STA_7 0x0270
+#define RT5659_SPK_DC_CAILB_STA_8 0x0271
+#define RT5659_SPK_DC_CAILB_STA_9 0x0272
+#define RT5659_SPK_DC_CAILB_STA_10 0x0273
+#define RT5659_SPK_VDD_STA_1 0x0280
+#define RT5659_SPK_VDD_STA_2 0x0281
+#define RT5659_SPK_DC_DET_CTRL_1 0x0282
+#define RT5659_SPK_DC_DET_CTRL_2 0x0283
+#define RT5659_SPK_DC_DET_CTRL_3 0x0284
+#define RT5659_PURE_DC_DET_CTRL_1 0x0290
+#define RT5659_PURE_DC_DET_CTRL_2 0x0291
+#define RT5659_DUMMY_4 0x02fa
+#define RT5659_DUMMY_5 0x02fb
+#define RT5659_DUMMY_6 0x02fc
+#define RT5659_DRC1_CTRL_1 0x0300
+#define RT5659_DRC1_CTRL_2 0x0301
+#define RT5659_DRC1_CTRL_3 0x0302
+#define RT5659_DRC1_CTRL_4 0x0303
+#define RT5659_DRC1_CTRL_5 0x0304
+#define RT5659_DRC1_CTRL_6 0x0305
+#define RT5659_DRC1_HARD_LMT_CTRL_1 0x0306
+#define RT5659_DRC1_HARD_LMT_CTRL_2 0x0307
+#define RT5659_DRC2_CTRL_1 0x0308
+#define RT5659_DRC2_CTRL_2 0x0309
+#define RT5659_DRC2_CTRL_3 0x030a
+#define RT5659_DRC2_CTRL_4 0x030b
+#define RT5659_DRC2_CTRL_5 0x030c
+#define RT5659_DRC2_CTRL_6 0x030d
+#define RT5659_DRC2_HARD_LMT_CTRL_1 0x030e
+#define RT5659_DRC2_HARD_LMT_CTRL_2 0x030f
+#define RT5659_DRC1_PRIV_1 0x0310
+#define RT5659_DRC1_PRIV_2 0x0311
+#define RT5659_DRC1_PRIV_3 0x0312
+#define RT5659_DRC1_PRIV_4 0x0313
+#define RT5659_DRC1_PRIV_5 0x0314
+#define RT5659_DRC1_PRIV_6 0x0315
+#define RT5659_DRC1_PRIV_7 0x0316
+#define RT5659_DRC2_PRIV_1 0x0317
+#define RT5659_DRC2_PRIV_2 0x0318
+#define RT5659_DRC2_PRIV_3 0x0319
+#define RT5659_DRC2_PRIV_4 0x031a
+#define RT5659_DRC2_PRIV_5 0x031b
+#define RT5659_DRC2_PRIV_6 0x031c
+#define RT5659_DRC2_PRIV_7 0x031d
+#define RT5659_MULTI_DRC_CTRL 0x0320
+#define RT5659_CROSS_OVER_1 0x0321
+#define RT5659_CROSS_OVER_2 0x0322
+#define RT5659_CROSS_OVER_3 0x0323
+#define RT5659_CROSS_OVER_4 0x0324
+#define RT5659_CROSS_OVER_5 0x0325
+#define RT5659_CROSS_OVER_6 0x0326
+#define RT5659_CROSS_OVER_7 0x0327
+#define RT5659_CROSS_OVER_8 0x0328
+#define RT5659_CROSS_OVER_9 0x0329
+#define RT5659_CROSS_OVER_10 0x032a
+#define RT5659_ALC_PGA_CTRL_1 0x0330
+#define RT5659_ALC_PGA_CTRL_2 0x0331
+#define RT5659_ALC_PGA_CTRL_3 0x0332
+#define RT5659_ALC_PGA_CTRL_4 0x0333
+#define RT5659_ALC_PGA_CTRL_5 0x0334
+#define RT5659_ALC_PGA_CTRL_6 0x0335
+#define RT5659_ALC_PGA_CTRL_7 0x0336
+#define RT5659_ALC_PGA_CTRL_8 0x0337
+#define RT5659_ALC_PGA_STA_1 0x0338
+#define RT5659_ALC_PGA_STA_2 0x0339
+#define RT5659_ALC_PGA_STA_3 0x033a
+#define RT5659_DAC_L_EQ_PRE_VOL 0x0340
+#define RT5659_DAC_R_EQ_PRE_VOL 0x0341
+#define RT5659_DAC_L_EQ_POST_VOL 0x0342
+#define RT5659_DAC_R_EQ_POST_VOL 0x0343
+#define RT5659_DAC_L_EQ_LPF1_A1 0x0344
+#define RT5659_DAC_L_EQ_LPF1_H0 0x0345
+#define RT5659_DAC_R_EQ_LPF1_A1 0x0346
+#define RT5659_DAC_R_EQ_LPF1_H0 0x0347
+#define RT5659_DAC_L_EQ_BPF2_A1 0x0348
+#define RT5659_DAC_L_EQ_BPF2_A2 0x0349
+#define RT5659_DAC_L_EQ_BPF2_H0 0x034a
+#define RT5659_DAC_R_EQ_BPF2_A1 0x034b
+#define RT5659_DAC_R_EQ_BPF2_A2 0x034c
+#define RT5659_DAC_R_EQ_BPF2_H0 0x034d
+#define RT5659_DAC_L_EQ_BPF3_A1 0x034e
+#define RT5659_DAC_L_EQ_BPF3_A2 0x034f
+#define RT5659_DAC_L_EQ_BPF3_H0 0x0350
+#define RT5659_DAC_R_EQ_BPF3_A1 0x0351
+#define RT5659_DAC_R_EQ_BPF3_A2 0x0352
+#define RT5659_DAC_R_EQ_BPF3_H0 0x0353
+#define RT5659_DAC_L_EQ_BPF4_A1 0x0354
+#define RT5659_DAC_L_EQ_BPF4_A2 0x0355
+#define RT5659_DAC_L_EQ_BPF4_H0 0x0356
+#define RT5659_DAC_R_EQ_BPF4_A1 0x0357
+#define RT5659_DAC_R_EQ_BPF4_A2 0x0358
+#define RT5659_DAC_R_EQ_BPF4_H0 0x0359
+#define RT5659_DAC_L_EQ_HPF1_A1 0x035a
+#define RT5659_DAC_L_EQ_HPF1_H0 0x035b
+#define RT5659_DAC_R_EQ_HPF1_A1 0x035c
+#define RT5659_DAC_R_EQ_HPF1_H0 0x035d
+#define RT5659_DAC_L_EQ_HPF2_A1 0x035e
+#define RT5659_DAC_L_EQ_HPF2_A2 0x035f
+#define RT5659_DAC_L_EQ_HPF2_H0 0x0360
+#define RT5659_DAC_R_EQ_HPF2_A1 0x0361
+#define RT5659_DAC_R_EQ_HPF2_A2 0x0362
+#define RT5659_DAC_R_EQ_HPF2_H0 0x0363
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_1 0x0364
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_2 0x0365
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_1 0x0366
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_2 0x0367
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_1 0x0368
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_2 0x0369
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_1 0x036a
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_2 0x036b
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_1 0x036c
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_2 0x036d
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_1 0x036e
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_2 0x036f
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_1 0x0370
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_2 0x0371
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_1 0x0372
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_2 0x0373
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_1 0x0374
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_2 0x0375
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_1 0x0376
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_2 0x0377
+#define RT5659_ADC_L_EQ_LPF1_A1 0x03d0
+#define RT5659_ADC_R_EQ_LPF1_A1 0x03d1
+#define RT5659_ADC_L_EQ_LPF1_H0 0x03d2
+#define RT5659_ADC_R_EQ_LPF1_H0 0x03d3
+#define RT5659_ADC_L_EQ_BPF1_A1 0x03d4
+#define RT5659_ADC_R_EQ_BPF1_A1 0x03d5
+#define RT5659_ADC_L_EQ_BPF1_A2 0x03d6
+#define RT5659_ADC_R_EQ_BPF1_A2 0x03d7
+#define RT5659_ADC_L_EQ_BPF1_H0 0x03d8
+#define RT5659_ADC_R_EQ_BPF1_H0 0x03d9
+#define RT5659_ADC_L_EQ_BPF2_A1 0x03da
+#define RT5659_ADC_R_EQ_BPF2_A1 0x03db
+#define RT5659_ADC_L_EQ_BPF2_A2 0x03dc
+#define RT5659_ADC_R_EQ_BPF2_A2 0x03dd
+#define RT5659_ADC_L_EQ_BPF2_H0 0x03de
+#define RT5659_ADC_R_EQ_BPF2_H0 0x03df
+#define RT5659_ADC_L_EQ_BPF3_A1 0x03e0
+#define RT5659_ADC_R_EQ_BPF3_A1 0x03e1
+#define RT5659_ADC_L_EQ_BPF3_A2 0x03e2
+#define RT5659_ADC_R_EQ_BPF3_A2 0x03e3
+#define RT5659_ADC_L_EQ_BPF3_H0 0x03e4
+#define RT5659_ADC_R_EQ_BPF3_H0 0x03e5
+#define RT5659_ADC_L_EQ_BPF4_A1 0x03e6
+#define RT5659_ADC_R_EQ_BPF4_A1 0x03e7
+#define RT5659_ADC_L_EQ_BPF4_A2 0x03e8
+#define RT5659_ADC_R_EQ_BPF4_A2 0x03e9
+#define RT5659_ADC_L_EQ_BPF4_H0 0x03ea
+#define RT5659_ADC_R_EQ_BPF4_H0 0x03eb
+#define RT5659_ADC_L_EQ_HPF1_A1 0x03ec
+#define RT5659_ADC_R_EQ_HPF1_A1 0x03ed
+#define RT5659_ADC_L_EQ_HPF1_H0 0x03ee
+#define RT5659_ADC_R_EQ_HPF1_H0 0x03ef
+#define RT5659_ADC_L_EQ_PRE_VOL 0x03f0
+#define RT5659_ADC_R_EQ_PRE_VOL 0x03f1
+#define RT5659_ADC_L_EQ_POST_VOL 0x03f2
+#define RT5659_ADC_R_EQ_POST_VOL 0x03f3
+
+
+
+/* global definition */
+#define RT5659_L_MUTE (0x1 << 15)
+#define RT5659_L_MUTE_SFT 15
+#define RT5659_VOL_L_MUTE (0x1 << 14)
+#define RT5659_VOL_L_SFT 14
+#define RT5659_R_MUTE (0x1 << 7)
+#define RT5659_R_MUTE_SFT 7
+#define RT5659_VOL_R_MUTE (0x1 << 6)
+#define RT5659_VOL_R_SFT 6
+#define RT5659_L_VOL_MASK (0x3f << 8)
+#define RT5659_L_VOL_SFT 8
+#define RT5659_R_VOL_MASK (0x3f)
+#define RT5659_R_VOL_SFT 0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5659_G_HP (0x1f << 8)
+#define RT5659_G_HP_SFT 8
+#define RT5659_G_STO_DA_DMIX (0x1f)
+#define RT5659_G_STO_DA_SFT 0
+
+/* IN1/IN2 Control (0x000c) */
+#define RT5659_IN1_DF_MASK (0x1 << 15)
+#define RT5659_IN1_DF 15
+#define RT5659_BST1_MASK (0x7f << 8)
+#define RT5659_BST1_SFT 8
+#define RT5659_BST2_MASK (0x7f)
+#define RT5659_BST2_SFT 0
+
+/* IN3/IN4 Control (0x000d) */
+#define RT5659_IN3_DF_MASK (0x1 << 15)
+#define RT5659_IN3_DF 15
+#define RT5659_BST3_MASK (0x7f << 8)
+#define RT5659_BST3_SFT 8
+#define RT5659_IN4_DF_MASK (0x1 << 7)
+#define RT5659_IN4_DF 7
+#define RT5659_BST4_MASK (0x7f)
+#define RT5659_BST4_SFT 0
+
+/* INL and INR Volume Control (0x000f) */
+#define RT5659_INL_VOL_MASK (0x1f << 8)
+#define RT5659_INL_VOL_SFT 8
+#define RT5659_INR_VOL_MASK (0x1f)
+#define RT5659_INR_VOL_SFT 0
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5659_EMB_JD_EN (0x1 << 15)
+#define RT5659_EMB_JD_EN_SFT 15
+#define RT5659_JD_MODE (0x1 << 13)
+#define RT5659_JD_MODE_SFT 13
+#define RT5659_EXT_JD_EN (0x1 << 11)
+#define RT5659_EXT_JD_EN_SFT 11
+#define RT5659_EXT_JD_DIG (0x1 << 9)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5659_EXT_JD_SRC (0x7 << 4)
+#define RT5659_EXT_JD_SRC_SFT 4
+#define RT5659_EXT_JD_SRC_GPIO_JD1 (0x0 << 4)
+#define RT5659_EXT_JD_SRC_GPIO_JD2 (0x1 << 4)
+#define RT5659_EXT_JD_SRC_JD1_1 (0x2 << 4)
+#define RT5659_EXT_JD_SRC_JD1_2 (0x3 << 4)
+#define RT5659_EXT_JD_SRC_JD2 (0x4 << 4)
+#define RT5659_EXT_JD_SRC_JD3 (0x5 << 4)
+#define RT5659_EXT_JD_SRC_MANUAL (0x6 << 4)
+
+/* Slience Detection Control (0x0015) */
+#define RT5659_SIL_DET_MASK (0x1 << 15)
+#define RT5659_SIL_DET_DIS (0x0 << 15)
+#define RT5659_SIL_DET_EN (0x1 << 15)
+
+/* Sidetone Control (0x0018) */
+#define RT5659_ST_SEL_MASK (0x7 << 9)
+#define RT5659_ST_SEL_SFT 9
+#define RT5659_ST_EN (0x1 << 6)
+#define RT5659_ST_EN_SFT 6
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5659_DAC_L1_VOL_MASK (0xff << 8)
+#define RT5659_DAC_L1_VOL_SFT 8
+#define RT5659_DAC_R1_VOL_MASK (0xff)
+#define RT5659_DAC_R1_VOL_SFT 0
+
+/* DAC2 Digital Volume (0x001a) */
+#define RT5659_DAC_L2_VOL_MASK (0xff << 8)
+#define RT5659_DAC_L2_VOL_SFT 8
+#define RT5659_DAC_R2_VOL_MASK (0xff)
+#define RT5659_DAC_R2_VOL_SFT 0
+
+/* DAC2 Control (0x001b) */
+#define RT5659_M_DAC2_L_VOL (0x1 << 13)
+#define RT5659_M_DAC2_L_VOL_SFT 13
+#define RT5659_M_DAC2_R_VOL (0x1 << 12)
+#define RT5659_M_DAC2_R_VOL_SFT 12
+#define RT5659_DAC_L2_SEL_MASK (0x7 << 4)
+#define RT5659_DAC_L2_SEL_SFT 4
+#define RT5659_DAC_R2_SEL_MASK (0x7 << 0)
+#define RT5659_DAC_R2_SEL_SFT 0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5659_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5659_ADC_L_VOL_SFT 8
+#define RT5659_ADC_R_VOL_MASK (0x7f)
+#define RT5659_ADC_R_VOL_SFT 0
+
+/* Mono ADC Digital Volume Control (0x001d) */
+#define RT5659_MONO_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5659_MONO_ADC_L_VOL_SFT 8
+#define RT5659_MONO_ADC_R_VOL_MASK (0x7f)
+#define RT5659_MONO_ADC_R_VOL_SFT 0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO1_ADC_L_BST_MASK (0x3 << 14)
+#define RT5659_STO1_ADC_L_BST_SFT 14
+#define RT5659_STO1_ADC_R_BST_MASK (0x3 << 12)
+#define RT5659_STO1_ADC_R_BST_SFT 12
+
+/* Mono ADC Boost Gain Control (0x0020) */
+#define RT5659_MONO_ADC_L_BST_MASK (0x3 << 14)
+#define RT5659_MONO_ADC_L_BST_SFT 14
+#define RT5659_MONO_ADC_R_BST_MASK (0x3 << 12)
+#define RT5659_MONO_ADC_R_BST_SFT 12
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO2_ADC_L_BST_MASK (0x3 << 14)
+#define RT5659_STO2_ADC_L_BST_SFT 14
+#define RT5659_STO2_ADC_R_BST_MASK (0x3 << 12)
+#define RT5659_STO2_ADC_R_BST_SFT 12
+
+/* Stereo ADC Mixer Control (0x0026) */
+#define RT5659_M_STO1_ADC_L1 (0x1 << 15)
+#define RT5659_M_STO1_ADC_L1_SFT 15
+#define RT5659_M_STO1_ADC_L2 (0x1 << 14)
+#define RT5659_M_STO1_ADC_L2_SFT 14
+#define RT5659_STO1_ADC1_SRC_MASK (0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_SFT 13
+#define RT5659_STO1_ADC1_SRC_ADC (0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_DACMIX (0x0 << 13)
+#define RT5659_STO1_ADC_SRC_MASK (0x1 << 12)
+#define RT5659_STO1_ADC_SRC_SFT 12
+#define RT5659_STO1_ADC_SRC_ADC1 (0x1 << 12)
+#define RT5659_STO1_ADC_SRC_ADC2 (0x0 << 12)
+#define RT5659_STO1_ADC2_SRC_MASK (0x1 << 11)
+#define RT5659_STO1_ADC2_SRC_SFT 11
+#define RT5659_STO1_DMIC_SRC_MASK (0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_SFT 8
+#define RT5659_STO1_DMIC_SRC_DMIC2 (0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_DMIC1 (0x0 << 8)
+#define RT5659_M_STO1_ADC_R1 (0x1 << 6)
+#define RT5659_M_STO1_ADC_R1_SFT 6
+#define RT5659_M_STO1_ADC_R2 (0x1 << 5)
+#define RT5659_M_STO1_ADC_R2_SFT 5
+
+/* Mono1 ADC Mixer control (0x0027) */
+#define RT5659_M_MONO_ADC_L1 (0x1 << 15)
+#define RT5659_M_MONO_ADC_L1_SFT 15
+#define RT5659_M_MONO_ADC_L2 (0x1 << 14)
+#define RT5659_M_MONO_ADC_L2_SFT 14
+#define RT5659_MONO_ADC_L2_SRC_MASK (0x1 << 12)
+#define RT5659_MONO_ADC_L2_SRC_SFT 12
+#define RT5659_MONO_ADC_L1_SRC_MASK (0x1 << 11)
+#define RT5659_MONO_ADC_L1_SRC_SFT 11
+#define RT5659_MONO_ADC_L_SRC_MASK (0x3 << 9)
+#define RT5659_MONO_ADC_L_SRC_SFT 9
+#define RT5659_MONO_DMIC_L_SRC_MASK (0x1 << 8)
+#define RT5659_MONO_DMIC_L_SRC_SFT 8
+#define RT5659_M_MONO_ADC_R1 (0x1 << 7)
+#define RT5659_M_MONO_ADC_R1_SFT 7
+#define RT5659_M_MONO_ADC_R2 (0x1 << 6)
+#define RT5659_M_MONO_ADC_R2_SFT 6
+#define RT5659_STO2_ADC_SRC_MASK (0x1 << 5)
+#define RT5659_STO2_ADC_SRC_SFT 5
+#define RT5659_MONO_ADC_R2_SRC_MASK (0x1 << 4)
+#define RT5659_MONO_ADC_R2_SRC_SFT 4
+#define RT5659_MONO_ADC_R1_SRC_MASK (0x1 << 3)
+#define RT5659_MONO_ADC_R1_SRC_SFT 3
+#define RT5659_MONO_ADC_R_SRC_MASK (0x3 << 1)
+#define RT5659_MONO_ADC_R_SRC_SFT 1
+#define RT5659_MONO_DMIC_R_SRC_MASK 0x1
+#define RT5659_MONO_DMIC_R_SRC_SFT 0
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5659_M_ADCMIX_L (0x1 << 15)
+#define RT5659_M_ADCMIX_L_SFT 15
+#define RT5659_M_DAC1_L (0x1 << 14)
+#define RT5659_M_DAC1_L_SFT 14
+#define RT5659_DAC1_R_SEL_MASK (0x3 << 10)
+#define RT5659_DAC1_R_SEL_SFT 10
+#define RT5659_DAC1_R_SEL_IF1 (0x0 << 10)
+#define RT5659_DAC1_R_SEL_IF2 (0x1 << 10)
+#define RT5659_DAC1_R_SEL_IF3 (0x2 << 10)
+#define RT5659_DAC1_L_SEL_MASK (0x3 << 8)
+#define RT5659_DAC1_L_SEL_SFT 8
+#define RT5659_DAC1_L_SEL_IF1 (0x0 << 8)
+#define RT5659_DAC1_L_SEL_IF2 (0x1 << 8)
+#define RT5659_DAC1_L_SEL_IF3 (0x2 << 8)
+#define RT5659_M_ADCMIX_R (0x1 << 7)
+#define RT5659_M_ADCMIX_R_SFT 7
+#define RT5659_M_DAC1_R (0x1 << 6)
+#define RT5659_M_DAC1_R_SFT 6
+
+/* Stereo DAC Mixer Control (0x002a) */
+#define RT5659_M_DAC_L1_STO_L (0x1 << 15)
+#define RT5659_M_DAC_L1_STO_L_SFT 15
+#define RT5659_G_DAC_L1_STO_L_MASK (0x1 << 14)
+#define RT5659_G_DAC_L1_STO_L_SFT 14
+#define RT5659_M_DAC_R1_STO_L (0x1 << 13)
+#define RT5659_M_DAC_R1_STO_L_SFT 13
+#define RT5659_G_DAC_R1_STO_L_MASK (0x1 << 12)
+#define RT5659_G_DAC_R1_STO_L_SFT 12
+#define RT5659_M_DAC_L2_STO_L (0x1 << 11)
+#define RT5659_M_DAC_L2_STO_L_SFT 11
+#define RT5659_G_DAC_L2_STO_L_MASK (0x1 << 10)
+#define RT5659_G_DAC_L2_STO_L_SFT 10
+#define RT5659_M_DAC_R2_STO_L (0x1 << 9)
+#define RT5659_M_DAC_R2_STO_L_SFT 9
+#define RT5659_G_DAC_R2_STO_L_MASK (0x1 << 8)
+#define RT5659_G_DAC_R2_STO_L_SFT 8
+#define RT5659_M_DAC_L1_STO_R (0x1 << 7)
+#define RT5659_M_DAC_L1_STO_R_SFT 7
+#define RT5659_G_DAC_L1_STO_R_MASK (0x1 << 6)
+#define RT5659_G_DAC_L1_STO_R_SFT 6
+#define RT5659_M_DAC_R1_STO_R (0x1 << 5)
+#define RT5659_M_DAC_R1_STO_R_SFT 5
+#define RT5659_G_DAC_R1_STO_R_MASK (0x1 << 4)
+#define RT5659_G_DAC_R1_STO_R_SFT 4
+#define RT5659_M_DAC_L2_STO_R (0x1 << 3)
+#define RT5659_M_DAC_L2_STO_R_SFT 3
+#define RT5659_G_DAC_L2_STO_R_MASK (0x1 << 2)
+#define RT5659_G_DAC_L2_STO_R_SFT 2
+#define RT5659_M_DAC_R2_STO_R (0x1 << 1)
+#define RT5659_M_DAC_R2_STO_R_SFT 1
+#define RT5659_G_DAC_R2_STO_R_MASK (0x1)
+#define RT5659_G_DAC_R2_STO_R_SFT 0
+
+/* Mono DAC Mixer Control (0x002b) */
+#define RT5659_M_DAC_L1_MONO_L (0x1 << 15)
+#define RT5659_M_DAC_L1_MONO_L_SFT 15
+#define RT5659_G_DAC_L1_MONO_L_MASK (0x1 << 14)
+#define RT5659_G_DAC_L1_MONO_L_SFT 14
+#define RT5659_M_DAC_R1_MONO_L (0x1 << 13)
+#define RT5659_M_DAC_R1_MONO_L_SFT 13
+#define RT5659_G_DAC_R1_MONO_L_MASK (0x1 << 12)
+#define RT5659_G_DAC_R1_MONO_L_SFT 12
+#define RT5659_M_DAC_L2_MONO_L (0x1 << 11)
+#define RT5659_M_DAC_L2_MONO_L_SFT 11
+#define RT5659_G_DAC_L2_MONO_L_MASK (0x1 << 10)
+#define RT5659_G_DAC_L2_MONO_L_SFT 10
+#define RT5659_M_DAC_R2_MONO_L (0x1 << 9)
+#define RT5659_M_DAC_R2_MONO_L_SFT 9
+#define RT5659_G_DAC_R2_MONO_L_MASK (0x1 << 8)
+#define RT5659_G_DAC_R2_MONO_L_SFT 8
+#define RT5659_M_DAC_L1_MONO_R (0x1 << 7)
+#define RT5659_M_DAC_L1_MONO_R_SFT 7
+#define RT5659_G_DAC_L1_MONO_R_MASK (0x1 << 6)
+#define RT5659_G_DAC_L1_MONO_R_SFT 6
+#define RT5659_M_DAC_R1_MONO_R (0x1 << 5)
+#define RT5659_M_DAC_R1_MONO_R_SFT 5
+#define RT5659_G_DAC_R1_MONO_R_MASK (0x1 << 4)
+#define RT5659_G_DAC_R1_MONO_R_SFT 4
+#define RT5659_M_DAC_L2_MONO_R (0x1 << 3)
+#define RT5659_M_DAC_L2_MONO_R_SFT 3
+#define RT5659_G_DAC_L2_MONO_R_MASK (0x1 << 2)
+#define RT5659_G_DAC_L2_MONO_R_SFT 2
+#define RT5659_M_DAC_R2_MONO_R (0x1 << 1)
+#define RT5659_M_DAC_R2_MONO_R_SFT 1
+#define RT5659_G_DAC_R2_MONO_R_MASK (0x1)
+#define RT5659_G_DAC_R2_MONO_R_SFT 0
+
+/* Digital Mixer Control (0x002c) */
+#define RT5659_M_DAC_MIX_L (0x1 << 7)
+#define RT5659_M_DAC_MIX_L_SFT 7
+#define RT5659_DAC_MIX_L_MASK (0x1 << 6)
+#define RT5659_DAC_MIX_L_SFT 6
+#define RT5659_M_DAC_MIX_R (0x1 << 5)
+#define RT5659_M_DAC_MIX_R_SFT 5
+#define RT5659_DAC_MIX_R_MASK (0x1 << 4)
+#define RT5659_DAC_MIX_R_SFT 4
+
+/* Analog DAC Input Source Control (0x002d) */
+#define RT5659_A_DACL1_SEL (0x1 << 3)
+#define RT5659_A_DACL1_SFT 3
+#define RT5659_A_DACR1_SEL (0x1 << 2)
+#define RT5659_A_DACR1_SFT 2
+#define RT5659_A_DACL2_SEL (0x1 << 1)
+#define RT5659_A_DACL2_SFT 1
+#define RT5659_A_DACR2_SEL (0x1 << 0)
+#define RT5659_A_DACR2_SFT 0
+
+/* Digital Interface Data Control (0x002f) */
+#define RT5659_IF2_ADC3_IN_MASK (0x3 << 14)
+#define RT5659_IF2_ADC3_IN_SFT 14
+#define RT5659_IF2_ADC_IN_MASK (0x3 << 12)
+#define RT5659_IF2_ADC_IN_SFT 12
+#define RT5659_IF2_DAC_SEL_MASK (0x3 << 10)
+#define RT5659_IF2_DAC_SEL_SFT 10
+#define RT5659_IF2_ADC_SEL_MASK (0x3 << 8)
+#define RT5659_IF2_ADC_SEL_SFT 8
+#define RT5659_IF3_DAC_SEL_MASK (0x3 << 6)
+#define RT5659_IF3_DAC_SEL_SFT 6
+#define RT5659_IF3_ADC_SEL_MASK (0x3 << 4)
+#define RT5659_IF3_ADC_SEL_SFT 4
+#define RT5659_IF3_ADC_IN_MASK (0x3 << 0)
+#define RT5659_IF3_ADC_IN_SFT 0
+
+/* PDM Output Control (0x0031) */
+#define RT5659_PDM1_L_MASK (0x1 << 15)
+#define RT5659_PDM1_L_SFT 15
+#define RT5659_M_PDM1_L (0x1 << 14)
+#define RT5659_M_PDM1_L_SFT 14
+#define RT5659_PDM1_R_MASK (0x1 << 13)
+#define RT5659_PDM1_R_SFT 13
+#define RT5659_M_PDM1_R (0x1 << 12)
+#define RT5659_M_PDM1_R_SFT 12
+#define RT5659_PDM2_BUSY (0x1 << 7)
+#define RT5659_PDM1_BUSY (0x1 << 6)
+#define RT5659_PDM_PATTERN (0x1 << 5)
+#define RT5659_PDM_GAIN (0x1 << 4)
+#define RT5659_PDM_DIV_MASK (0x3)
+
+/*S/PDIF Output Control (0x0036) */
+#define RT5659_SPDIF_SEL_MASK (0x3 << 0)
+#define RT5659_SPDIF_SEL_SFT 0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5659_M_BST1_RM1_L (0x1 << 5)
+#define RT5659_M_BST1_RM1_L_SFT 5
+#define RT5659_M_BST2_RM1_L (0x1 << 4)
+#define RT5659_M_BST2_RM1_L_SFT 4
+#define RT5659_M_BST3_RM1_L (0x1 << 3)
+#define RT5659_M_BST3_RM1_L_SFT 3
+#define RT5659_M_BST4_RM1_L (0x1 << 2)
+#define RT5659_M_BST4_RM1_L_SFT 2
+#define RT5659_M_INL_RM1_L (0x1 << 1)
+#define RT5659_M_INL_RM1_L_SFT 1
+#define RT5659_M_SPKVOLL_RM1_L (0x1)
+#define RT5659_M_SPKVOLL_RM1_L_SFT 0
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5659_M_BST1_RM1_R (0x1 << 5)
+#define RT5659_M_BST1_RM1_R_SFT 5
+#define RT5659_M_BST2_RM1_R (0x1 << 4)
+#define RT5659_M_BST2_RM1_R_SFT 4
+#define RT5659_M_BST3_RM1_R (0x1 << 3)
+#define RT5659_M_BST3_RM1_R_SFT 3
+#define RT5659_M_BST4_RM1_R (0x1 << 2)
+#define RT5659_M_BST4_RM1_R_SFT 2
+#define RT5659_M_INR_RM1_R (0x1 << 1)
+#define RT5659_M_INR_RM1_R_SFT 1
+#define RT5659_M_HPOVOLR_RM1_R (0x1)
+#define RT5659_M_HPOVOLR_RM1_R_SFT 0
+
+/* SPK Left Mixer Control (0x0046) */
+#define RT5659_M_BST3_SM_L (0x1 << 4)
+#define RT5659_M_BST3_SM_L_SFT 4
+#define RT5659_M_IN_R_SM_L (0x1 << 3)
+#define RT5659_M_IN_R_SM_L_SFT 3
+#define RT5659_M_IN_L_SM_L (0x1 << 2)
+#define RT5659_M_IN_L_SM_L_SFT 2
+#define RT5659_M_BST1_SM_L (0x1 << 1)
+#define RT5659_M_BST1_SM_L_SFT 1
+#define RT5659_M_DAC_L2_SM_L (0x1)
+#define RT5659_M_DAC_L2_SM_L_SFT 0
+
+/* SPK Right Mixer Control (0x0047) */
+#define RT5659_M_BST3_SM_R (0x1 << 4)
+#define RT5659_M_BST3_SM_R_SFT 4
+#define RT5659_M_IN_R_SM_R (0x1 << 3)
+#define RT5659_M_IN_R_SM_R_SFT 3
+#define RT5659_M_IN_L_SM_R (0x1 << 2)
+#define RT5659_M_IN_L_SM_R_SFT 2
+#define RT5659_M_BST4_SM_R (0x1 << 1)
+#define RT5659_M_BST4_SM_R_SFT 1
+#define RT5659_M_DAC_R2_SM_R (0x1)
+#define RT5659_M_DAC_R2_SM_R_SFT 0
+
+/* SPO Amp Input and Gain Control (0x0048) */
+#define RT5659_M_DAC_L2_SPKOMIX (0x1 << 13)
+#define RT5659_M_DAC_L2_SPKOMIX_SFT 13
+#define RT5659_M_SPKVOLL_SPKOMIX (0x1 << 12)
+#define RT5659_M_SPKVOLL_SPKOMIX_SFT 12
+#define RT5659_M_DAC_R2_SPKOMIX (0x1 << 9)
+#define RT5659_M_DAC_R2_SPKOMIX_SFT 9
+#define RT5659_M_SPKVOLR_SPKOMIX (0x1 << 8)
+#define RT5659_M_SPKVOLR_SPKOMIX_SFT 8
+
+/* MONOMIX Input and Gain Control (0x004b) */
+#define RT5659_M_MONOVOL_MA (0x1 << 9)
+#define RT5659_M_MONOVOL_MA_SFT 9
+#define RT5659_M_DAC_L2_MA (0x1 << 8)
+#define RT5659_M_DAC_L2_MA_SFT 8
+#define RT5659_M_BST3_MM (0x1 << 4)
+#define RT5659_M_BST3_MM_SFT 4
+#define RT5659_M_BST2_MM (0x1 << 3)
+#define RT5659_M_BST2_MM_SFT 3
+#define RT5659_M_BST1_MM (0x1 << 2)
+#define RT5659_M_BST1_MM_SFT 2
+#define RT5659_M_DAC_R2_MM (0x1 << 1)
+#define RT5659_M_DAC_R2_MM_SFT 1
+#define RT5659_M_DAC_L2_MM (0x1)
+#define RT5659_M_DAC_L2_MM_SFT 0
+
+/* Output Left Mixer Control 1 (0x004d) */
+#define RT5659_G_BST3_OM_L_MASK (0x7 << 12)
+#define RT5659_G_BST3_OM_L_SFT 12
+#define RT5659_G_BST2_OM_L_MASK (0x7 << 9)
+#define RT5659_G_BST2_OM_L_SFT 9
+#define RT5659_G_BST1_OM_L_MASK (0x7 << 6)
+#define RT5659_G_BST1_OM_L_SFT 6
+#define RT5659_G_IN_L_OM_L_MASK (0x7 << 3)
+#define RT5659_G_IN_L_OM_L_SFT 3
+#define RT5659_G_DAC_L2_OM_L_MASK (0x7 << 0)
+#define RT5659_G_DAC_L2_OM_L_SFT 0
+
+/* Output Left Mixer Input Control (0x004e) */
+#define RT5659_M_BST3_OM_L (0x1 << 4)
+#define RT5659_M_BST3_OM_L_SFT 4
+#define RT5659_M_BST2_OM_L (0x1 << 3)
+#define RT5659_M_BST2_OM_L_SFT 3
+#define RT5659_M_BST1_OM_L (0x1 << 2)
+#define RT5659_M_BST1_OM_L_SFT 2
+#define RT5659_M_IN_L_OM_L (0x1 << 1)
+#define RT5659_M_IN_L_OM_L_SFT 1
+#define RT5659_M_DAC_L2_OM_L (0x1)
+#define RT5659_M_DAC_L2_OM_L_SFT 0
+
+/* Output Right Mixer Input Control (0x0050) */
+#define RT5659_M_BST4_OM_R (0x1 << 4)
+#define RT5659_M_BST4_OM_R_SFT 4
+#define RT5659_M_BST3_OM_R (0x1 << 3)
+#define RT5659_M_BST3_OM_R_SFT 3
+#define RT5659_M_BST2_OM_R (0x1 << 2)
+#define RT5659_M_BST2_OM_R_SFT 2
+#define RT5659_M_IN_R_OM_R (0x1 << 1)
+#define RT5659_M_IN_R_OM_R_SFT 1
+#define RT5659_M_DAC_R2_OM_R (0x1)
+#define RT5659_M_DAC_R2_OM_R_SFT 0
+
+/* LOUT Mixer Control (0x0052) */
+#define RT5659_M_DAC_L2_LM (0x1 << 15)
+#define RT5659_M_DAC_L2_LM_SFT 15
+#define RT5659_M_DAC_R2_LM (0x1 << 14)
+#define RT5659_M_DAC_R2_LM_SFT 14
+#define RT5659_M_OV_L_LM (0x1 << 13)
+#define RT5659_M_OV_L_LM_SFT 13
+#define RT5659_M_OV_R_LM (0x1 << 12)
+#define RT5659_M_OV_R_LM_SFT 12
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5659_PWR_I2S1 (0x1 << 15)
+#define RT5659_PWR_I2S1_BIT 15
+#define RT5659_PWR_I2S2 (0x1 << 14)
+#define RT5659_PWR_I2S2_BIT 14
+#define RT5659_PWR_I2S3 (0x1 << 13)
+#define RT5659_PWR_I2S3_BIT 13
+#define RT5659_PWR_SPDIF (0x1 << 12)
+#define RT5659_PWR_SPDIF_BIT 12
+#define RT5659_PWR_DAC_L1 (0x1 << 11)
+#define RT5659_PWR_DAC_L1_BIT 11
+#define RT5659_PWR_DAC_R1 (0x1 << 10)
+#define RT5659_PWR_DAC_R1_BIT 10
+#define RT5659_PWR_DAC_L2 (0x1 << 9)
+#define RT5659_PWR_DAC_L2_BIT 9
+#define RT5659_PWR_DAC_R2 (0x1 << 8)
+#define RT5659_PWR_DAC_R2_BIT 8
+#define RT5659_PWR_LDO (0x1 << 7)
+#define RT5659_PWR_LDO_BIT 7
+#define RT5659_PWR_ADC_L1 (0x1 << 4)
+#define RT5659_PWR_ADC_L1_BIT 4
+#define RT5659_PWR_ADC_R1 (0x1 << 3)
+#define RT5659_PWR_ADC_R1_BIT 3
+#define RT5659_PWR_ADC_L2 (0x1 << 2)
+#define RT5659_PWR_ADC_L2_BIT 4
+#define RT5659_PWR_ADC_R2 (0x1 << 1)
+#define RT5659_PWR_ADC_R2_BIT 1
+#define RT5659_PWR_CLS_D (0x1)
+#define RT5659_PWR_CLS_D_BIT 0
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5659_PWR_ADC_S1F (0x1 << 15)
+#define RT5659_PWR_ADC_S1F_BIT 15
+#define RT5659_PWR_ADC_S2F (0x1 << 14)
+#define RT5659_PWR_ADC_S2F_BIT 14
+#define RT5659_PWR_ADC_MF_L (0x1 << 13)
+#define RT5659_PWR_ADC_MF_L_BIT 13
+#define RT5659_PWR_ADC_MF_R (0x1 << 12)
+#define RT5659_PWR_ADC_MF_R_BIT 12
+#define RT5659_PWR_DAC_S1F (0x1 << 10)
+#define RT5659_PWR_DAC_S1F_BIT 10
+#define RT5659_PWR_DAC_MF_L (0x1 << 9)
+#define RT5659_PWR_DAC_MF_L_BIT 9
+#define RT5659_PWR_DAC_MF_R (0x1 << 8)
+#define RT5659_PWR_DAC_MF_R_BIT 8
+#define RT5659_PWR_PDM1 (0x1 << 7)
+#define RT5659_PWR_PDM1_BIT 7
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5659_PWR_VREF1 (0x1 << 15)
+#define RT5659_PWR_VREF1_BIT 15
+#define RT5659_PWR_FV1 (0x1 << 14)
+#define RT5659_PWR_FV1_BIT 14
+#define RT5659_PWR_VREF2 (0x1 << 13)
+#define RT5659_PWR_VREF2_BIT 13
+#define RT5659_PWR_FV2 (0x1 << 12)
+#define RT5659_PWR_FV2_BIT 12
+#define RT5659_PWR_VREF3 (0x1 << 11)
+#define RT5659_PWR_VREF3_BIT 11
+#define RT5659_PWR_FV3 (0x1 << 10)
+#define RT5659_PWR_FV3_BIT 10
+#define RT5659_PWR_MB (0x1 << 9)
+#define RT5659_PWR_MB_BIT 9
+#define RT5659_PWR_LM (0x1 << 8)
+#define RT5659_PWR_LM_BIT 8
+#define RT5659_PWR_BG (0x1 << 7)
+#define RT5659_PWR_BG_BIT 7
+#define RT5659_PWR_MA (0x1 << 6)
+#define RT5659_PWR_MA_BIT 6
+#define RT5659_PWR_HA_L (0x1 << 5)
+#define RT5659_PWR_HA_L_BIT 5
+#define RT5659_PWR_HA_R (0x1 << 4)
+#define RT5659_PWR_HA_R_BIT 4
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5659_PWR_BST1 (0x1 << 15)
+#define RT5659_PWR_BST1_BIT 15
+#define RT5659_PWR_BST2 (0x1 << 14)
+#define RT5659_PWR_BST2_BIT 14
+#define RT5659_PWR_BST3 (0x1 << 13)
+#define RT5659_PWR_BST3_BIT 13
+#define RT5659_PWR_BST4 (0x1 << 12)
+#define RT5659_PWR_BST4_BIT 12
+#define RT5659_PWR_MB1 (0x1 << 11)
+#define RT5659_PWR_MB1_BIT 11
+#define RT5659_PWR_MB2 (0x1 << 10)
+#define RT5659_PWR_MB2_BIT 10
+#define RT5659_PWR_MB3 (0x1 << 9)
+#define RT5659_PWR_MB3_BIT 9
+#define RT5659_PWR_BST1_P (0x1 << 6)
+#define RT5659_PWR_BST1_P_BIT 6
+#define RT5659_PWR_BST2_P (0x1 << 5)
+#define RT5659_PWR_BST2_P_BIT 5
+#define RT5659_PWR_BST3_P (0x1 << 4)
+#define RT5659_PWR_BST3_P_BIT 4
+#define RT5659_PWR_BST4_P (0x1 << 3)
+#define RT5659_PWR_BST4_P_BIT 3
+#define RT5659_PWR_JD1 (0x1 << 2)
+#define RT5659_PWR_JD1_BIT 2
+#define RT5659_PWR_JD2 (0x1 << 1)
+#define RT5659_PWR_JD2_BIT 1
+#define RT5659_PWR_JD3 (0x1)
+#define RT5659_PWR_JD3_BIT 0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5659_PWR_BST_L (0x1 << 8)
+#define RT5659_PWR_BST_L_BIT 8
+#define RT5659_PWR_BST_R (0x1 << 7)
+#define RT5659_PWR_BST_R_BIT 7
+#define RT5659_PWR_PLL (0x1 << 6)
+#define RT5659_PWR_PLL_BIT 6
+#define RT5659_PWR_LDO5 (0x1 << 5)
+#define RT5659_PWR_LDO5_BIT 5
+#define RT5659_PWR_LDO4 (0x1 << 4)
+#define RT5659_PWR_LDO4_BIT 4
+#define RT5659_PWR_LDO3 (0x1 << 3)
+#define RT5659_PWR_LDO3_BIT 3
+#define RT5659_PWR_LDO2 (0x1 << 2)
+#define RT5659_PWR_LDO2_BIT 2
+#define RT5659_PWR_SVD (0x1 << 1)
+#define RT5659_PWR_SVD_BIT 1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5659_PWR_OM_L (0x1 << 15)
+#define RT5659_PWR_OM_L_BIT 15
+#define RT5659_PWR_OM_R (0x1 << 14)
+#define RT5659_PWR_OM_R_BIT 14
+#define RT5659_PWR_SM_L (0x1 << 13)
+#define RT5659_PWR_SM_L_BIT 13
+#define RT5659_PWR_SM_R (0x1 << 12)
+#define RT5659_PWR_SM_R_BIT 12
+#define RT5659_PWR_RM1_L (0x1 << 11)
+#define RT5659_PWR_RM1_L_BIT 11
+#define RT5659_PWR_RM1_R (0x1 << 10)
+#define RT5659_PWR_RM1_R_BIT 10
+#define RT5659_PWR_MM (0x1 << 8)
+#define RT5659_PWR_MM_BIT 8
+#define RT5659_PWR_RM2_L (0x1 << 3)
+#define RT5659_PWR_RM2_L_BIT 3
+#define RT5659_PWR_RM2_R (0x1 << 2)
+#define RT5659_PWR_RM2_R_BIT 2
+
+/* Power Management for Volume (0x0067) */
+#define RT5659_PWR_SV_L (0x1 << 15)
+#define RT5659_PWR_SV_L_BIT 15
+#define RT5659_PWR_SV_R (0x1 << 14)
+#define RT5659_PWR_SV_R_BIT 14
+#define RT5659_PWR_OV_L (0x1 << 13)
+#define RT5659_PWR_OV_L_BIT 13
+#define RT5659_PWR_OV_R (0x1 << 12)
+#define RT5659_PWR_OV_R_BIT 12
+#define RT5659_PWR_IN_L (0x1 << 9)
+#define RT5659_PWR_IN_L_BIT 9
+#define RT5659_PWR_IN_R (0x1 << 8)
+#define RT5659_PWR_IN_R_BIT 8
+#define RT5659_PWR_MV (0x1 << 7)
+#define RT5659_PWR_MV_BIT 7
+#define RT5659_PWR_MIC_DET (0x1 << 5)
+#define RT5659_PWR_MIC_DET_BIT 5
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */
+#define RT5659_I2S_MS_MASK (0x1 << 15)
+#define RT5659_I2S_MS_SFT 15
+#define RT5659_I2S_MS_M (0x0 << 15)
+#define RT5659_I2S_MS_S (0x1 << 15)
+#define RT5659_I2S_O_CP_MASK (0x3 << 12)
+#define RT5659_I2S_O_CP_SFT 12
+#define RT5659_I2S_O_CP_OFF (0x0 << 12)
+#define RT5659_I2S_O_CP_U_LAW (0x1 << 12)
+#define RT5659_I2S_O_CP_A_LAW (0x2 << 12)
+#define RT5659_I2S_I_CP_MASK (0x3 << 10)
+#define RT5659_I2S_I_CP_SFT 10
+#define RT5659_I2S_I_CP_OFF (0x0 << 10)
+#define RT5659_I2S_I_CP_U_LAW (0x1 << 10)
+#define RT5659_I2S_I_CP_A_LAW (0x2 << 10)
+#define RT5659_I2S_BP_MASK (0x1 << 8)
+#define RT5659_I2S_BP_SFT 8
+#define RT5659_I2S_BP_NOR (0x0 << 8)
+#define RT5659_I2S_BP_INV (0x1 << 8)
+#define RT5659_I2S_DL_MASK (0x3 << 4)
+#define RT5659_I2S_DL_SFT 4
+#define RT5659_I2S_DL_16 (0x0 << 4)
+#define RT5659_I2S_DL_20 (0x1 << 4)
+#define RT5659_I2S_DL_24 (0x2 << 4)
+#define RT5659_I2S_DL_8 (0x3 << 4)
+#define RT5659_I2S_DF_MASK (0x7)
+#define RT5659_I2S_DF_SFT 0
+#define RT5659_I2S_DF_I2S (0x0)
+#define RT5659_I2S_DF_LEFT (0x1)
+#define RT5659_I2S_DF_PCM_A (0x2)
+#define RT5659_I2S_DF_PCM_B (0x3)
+#define RT5659_I2S_DF_PCM_A_N (0x6)
+#define RT5659_I2S_DF_PCM_B_N (0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5659_I2S_PD1_MASK (0x7 << 12)
+#define RT5659_I2S_PD1_SFT 12
+#define RT5659_I2S_PD1_1 (0x0 << 12)
+#define RT5659_I2S_PD1_2 (0x1 << 12)
+#define RT5659_I2S_PD1_3 (0x2 << 12)
+#define RT5659_I2S_PD1_4 (0x3 << 12)
+#define RT5659_I2S_PD1_6 (0x4 << 12)
+#define RT5659_I2S_PD1_8 (0x5 << 12)
+#define RT5659_I2S_PD1_12 (0x6 << 12)
+#define RT5659_I2S_PD1_16 (0x7 << 12)
+#define RT5659_I2S_BCLK_MS2_MASK (0x1 << 11)
+#define RT5659_I2S_BCLK_MS2_SFT 11
+#define RT5659_I2S_BCLK_MS2_32 (0x0 << 11)
+#define RT5659_I2S_BCLK_MS2_64 (0x1 << 11)
+#define RT5659_I2S_PD2_MASK (0x7 << 8)
+#define RT5659_I2S_PD2_SFT 8
+#define RT5659_I2S_PD2_1 (0x0 << 8)
+#define RT5659_I2S_PD2_2 (0x1 << 8)
+#define RT5659_I2S_PD2_3 (0x2 << 8)
+#define RT5659_I2S_PD2_4 (0x3 << 8)
+#define RT5659_I2S_PD2_6 (0x4 << 8)
+#define RT5659_I2S_PD2_8 (0x5 << 8)
+#define RT5659_I2S_PD2_12 (0x6 << 8)
+#define RT5659_I2S_PD2_16 (0x7 << 8)
+#define RT5659_I2S_BCLK_MS3_MASK (0x1 << 7)
+#define RT5659_I2S_BCLK_MS3_SFT 7
+#define RT5659_I2S_BCLK_MS3_32 (0x0 << 7)
+#define RT5659_I2S_BCLK_MS3_64 (0x1 << 7)
+#define RT5659_I2S_PD3_MASK (0x7 << 4)
+#define RT5659_I2S_PD3_SFT 4
+#define RT5659_I2S_PD3_1 (0x0 << 4)
+#define RT5659_I2S_PD3_2 (0x1 << 4)
+#define RT5659_I2S_PD3_3 (0x2 << 4)
+#define RT5659_I2S_PD3_4 (0x3 << 4)
+#define RT5659_I2S_PD3_6 (0x4 << 4)
+#define RT5659_I2S_PD3_8 (0x5 << 4)
+#define RT5659_I2S_PD3_12 (0x6 << 4)
+#define RT5659_I2S_PD3_16 (0x7 << 4)
+#define RT5659_DAC_OSR_MASK (0x3 << 2)
+#define RT5659_DAC_OSR_SFT 2
+#define RT5659_DAC_OSR_128 (0x0 << 2)
+#define RT5659_DAC_OSR_64 (0x1 << 2)
+#define RT5659_DAC_OSR_32 (0x2 << 2)
+#define RT5659_DAC_OSR_16 (0x3 << 2)
+#define RT5659_ADC_OSR_MASK (0x3)
+#define RT5659_ADC_OSR_SFT 0
+#define RT5659_ADC_OSR_128 (0x0)
+#define RT5659_ADC_OSR_64 (0x1)
+#define RT5659_ADC_OSR_32 (0x2)
+#define RT5659_ADC_OSR_16 (0x3)
+
+/* Digital Microphone Control (0x0075) */
+#define RT5659_DMIC_1_EN_MASK (0x1 << 15)
+#define RT5659_DMIC_1_EN_SFT 15
+#define RT5659_DMIC_1_DIS (0x0 << 15)
+#define RT5659_DMIC_1_EN (0x1 << 15)
+#define RT5659_DMIC_2_EN_MASK (0x1 << 14)
+#define RT5659_DMIC_2_EN_SFT 14
+#define RT5659_DMIC_2_DIS (0x0 << 14)
+#define RT5659_DMIC_2_EN (0x1 << 14)
+#define RT5659_DMIC_1L_LH_MASK (0x1 << 13)
+#define RT5659_DMIC_1L_LH_SFT 13
+#define RT5659_DMIC_1L_LH_RISING (0x0 << 13)
+#define RT5659_DMIC_1L_LH_FALLING (0x1 << 13)
+#define RT5659_DMIC_1R_LH_MASK (0x1 << 12)
+#define RT5659_DMIC_1R_LH_SFT 12
+#define RT5659_DMIC_1R_LH_RISING (0x0 << 12)
+#define RT5659_DMIC_1R_LH_FALLING (0x1 << 12)
+#define RT5659_DMIC_2_DP_MASK (0x3 << 10)
+#define RT5659_DMIC_2_DP_SFT 10
+#define RT5659_DMIC_2_DP_GPIO6 (0x0 << 10)
+#define RT5659_DMIC_2_DP_GPIO10 (0x1 << 10)
+#define RT5659_DMIC_2_DP_GPIO12 (0x2 << 10)
+#define RT5659_DMIC_2_DP_IN2P (0x3 << 10)
+#define RT5659_DMIC_CLK_MASK (0x7 << 5)
+#define RT5659_DMIC_CLK_SFT 5
+#define RT5659_DMIC_1_DP_MASK (0x3 << 0)
+#define RT5659_DMIC_1_DP_SFT 0
+#define RT5659_DMIC_1_DP_GPIO5 (0x0 << 0)
+#define RT5659_DMIC_1_DP_GPIO9 (0x1 << 0)
+#define RT5659_DMIC_1_DP_GPIO11 (0x2 << 0)
+#define RT5659_DMIC_1_DP_IN2N (0x3 << 0)
+
+/* TDM control 1 (0x0078)*/
+#define RT5659_DS_ADC_SLOT01_SFT 14
+#define RT5659_DS_ADC_SLOT23_SFT 12
+#define RT5659_DS_ADC_SLOT45_SFT 10
+#define RT5659_DS_ADC_SLOT67_SFT 8
+#define RT5659_ADCDAT_SRC_MASK 0x1f
+#define RT5659_ADCDAT_SRC_SFT 0
+
+/* Global Clock Control (0x0080) */
+#define RT5659_SCLK_SRC_MASK (0x3 << 14)
+#define RT5659_SCLK_SRC_SFT 14
+#define RT5659_SCLK_SRC_MCLK (0x0 << 14)
+#define RT5659_SCLK_SRC_PLL1 (0x1 << 14)
+#define RT5659_SCLK_SRC_RCCLK (0x2 << 14)
+#define RT5659_PLL1_SRC_MASK (0x7 << 11)
+#define RT5659_PLL1_SRC_SFT 11
+#define RT5659_PLL1_SRC_MCLK (0x0 << 11)
+#define RT5659_PLL1_SRC_BCLK1 (0x1 << 11)
+#define RT5659_PLL1_SRC_BCLK2 (0x2 << 11)
+#define RT5659_PLL1_SRC_BCLK3 (0x3 << 11)
+#define RT5659_PLL1_PD_MASK (0x1 << 3)
+#define RT5659_PLL1_PD_SFT 3
+#define RT5659_PLL1_PD_1 (0x0 << 3)
+#define RT5659_PLL1_PD_2 (0x1 << 3)
+
+#define RT5659_PLL_INP_MAX 40000000
+#define RT5659_PLL_INP_MIN 256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5659_PLL_N_MAX 0x001ff
+#define RT5659_PLL_N_MASK (RT5659_PLL_N_MAX << 7)
+#define RT5659_PLL_N_SFT 7
+#define RT5659_PLL_K_MAX 0x001f
+#define RT5659_PLL_K_MASK (RT5659_PLL_K_MAX)
+#define RT5659_PLL_K_SFT 0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5659_PLL_M_MAX 0x00f
+#define RT5659_PLL_M_MASK (RT5659_PLL_M_MAX << 12)
+#define RT5659_PLL_M_SFT 12
+#define RT5659_PLL_M_BP (0x1 << 11)
+#define RT5659_PLL_M_BP_SFT 11
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5659_I2S3_ASRC_MASK (0x1 << 13)
+#define RT5659_I2S3_ASRC_SFT 13
+#define RT5659_I2S2_ASRC_MASK (0x1 << 12)
+#define RT5659_I2S2_ASRC_SFT 12
+#define RT5659_I2S1_ASRC_MASK (0x1 << 11)
+#define RT5659_I2S1_ASRC_SFT 11
+#define RT5659_DAC_STO_ASRC_MASK (0x1 << 10)
+#define RT5659_DAC_STO_ASRC_SFT 10
+#define RT5659_DAC_MONO_L_ASRC_MASK (0x1 << 9)
+#define RT5659_DAC_MONO_L_ASRC_SFT 9
+#define RT5659_DAC_MONO_R_ASRC_MASK (0x1 << 8)
+#define RT5659_DAC_MONO_R_ASRC_SFT 8
+#define RT5659_DMIC_STO1_ASRC_MASK (0x1 << 7)
+#define RT5659_DMIC_STO1_ASRC_SFT 7
+#define RT5659_DMIC_MONO_L_ASRC_MASK (0x1 << 5)
+#define RT5659_DMIC_MONO_L_ASRC_SFT 5
+#define RT5659_DMIC_MONO_R_ASRC_MASK (0x1 << 4)
+#define RT5659_DMIC_MONO_R_ASRC_SFT 4
+#define RT5659_ADC_STO1_ASRC_MASK (0x1 << 3)
+#define RT5659_ADC_STO1_ASRC_SFT 3
+#define RT5659_ADC_MONO_L_ASRC_MASK (0x1 << 1)
+#define RT5659_ADC_MONO_L_ASRC_SFT 1
+#define RT5659_ADC_MONO_R_ASRC_MASK (0x1)
+#define RT5659_ADC_MONO_R_ASRC_SFT 0
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5659_DA_STO_T_MASK (0x7 << 12)
+#define RT5659_DA_STO_T_SFT 12
+#define RT5659_DA_MONO_L_T_MASK (0x7 << 8)
+#define RT5659_DA_MONO_L_T_SFT 8
+#define RT5659_DA_MONO_R_T_MASK (0x7 << 4)
+#define RT5659_DA_MONO_R_T_SFT 4
+#define RT5659_AD_STO1_T_MASK (0x7)
+#define RT5659_AD_STO1_T_SFT 0
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5659_AD_STO2_T_MASK (0x7 << 8)
+#define RT5659_AD_STO2_T_SFT 8
+#define RT5659_AD_MONO_L_T_MASK (0x7 << 4)
+#define RT5659_AD_MONO_L_T_SFT 4
+#define RT5659_AD_MONO_R_T_MASK (0x7)
+#define RT5659_AD_MONO_R_T_SFT 0
+
+/* ASRC Control 4 (0x0086) */
+#define RT5659_I2S1_RATE_MASK (0xf << 12)
+#define RT5659_I2S1_RATE_SFT 12
+#define RT5659_I2S2_RATE_MASK (0xf << 8)
+#define RT5659_I2S2_RATE_SFT 8
+#define RT5659_I2S3_RATE_MASK (0xf << 4)
+#define RT5659_I2S3_RATE_SFT 4
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5659_SMT_TRIG_MASK (0x1 << 15)
+#define RT5659_SMT_TRIG_SFT 15
+#define RT5659_SMT_TRIG_DIS (0x0 << 15)
+#define RT5659_SMT_TRIG_EN (0x1 << 15)
+#define RT5659_HP_L_SMT_MASK (0x1 << 9)
+#define RT5659_HP_L_SMT_SFT 9
+#define RT5659_HP_L_SMT_DIS (0x0 << 9)
+#define RT5659_HP_L_SMT_EN (0x1 << 9)
+#define RT5659_HP_R_SMT_MASK (0x1 << 8)
+#define RT5659_HP_R_SMT_SFT 8
+#define RT5659_HP_R_SMT_DIS (0x0 << 8)
+#define RT5659_HP_R_SMT_EN (0x1 << 8)
+#define RT5659_HP_CD_PD_MASK (0x1 << 7)
+#define RT5659_HP_CD_PD_SFT 7
+#define RT5659_HP_CD_PD_DIS (0x0 << 7)
+#define RT5659_HP_CD_PD_EN (0x1 << 7)
+#define RT5659_RSTN_MASK (0x1 << 6)
+#define RT5659_RSTN_SFT 6
+#define RT5659_RSTN_DIS (0x0 << 6)
+#define RT5659_RSTN_EN (0x1 << 6)
+#define RT5659_RSTP_MASK (0x1 << 5)
+#define RT5659_RSTP_SFT 5
+#define RT5659_RSTP_DIS (0x0 << 5)
+#define RT5659_RSTP_EN (0x1 << 5)
+#define RT5659_HP_CO_MASK (0x1 << 4)
+#define RT5659_HP_CO_SFT 4
+#define RT5659_HP_CO_DIS (0x0 << 4)
+#define RT5659_HP_CO_EN (0x1 << 4)
+#define RT5659_HP_CP_MASK (0x1 << 3)
+#define RT5659_HP_CP_SFT 3
+#define RT5659_HP_CP_PD (0x0 << 3)
+#define RT5659_HP_CP_PU (0x1 << 3)
+#define RT5659_HP_SG_MASK (0x1 << 2)
+#define RT5659_HP_SG_SFT 2
+#define RT5659_HP_SG_DIS (0x0 << 2)
+#define RT5659_HP_SG_EN (0x1 << 2)
+#define RT5659_HP_DP_MASK (0x1 << 1)
+#define RT5659_HP_DP_SFT 1
+#define RT5659_HP_DP_PD (0x0 << 1)
+#define RT5659_HP_DP_PU (0x1 << 1)
+#define RT5659_HP_CB_MASK (0x1)
+#define RT5659_HP_CB_SFT 0
+#define RT5659_HP_CB_PD (0x0)
+#define RT5659_HP_CB_PU (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5659_DEPOP_MASK (0x1 << 13)
+#define RT5659_DEPOP_SFT 13
+#define RT5659_DEPOP_AUTO (0x0 << 13)
+#define RT5659_DEPOP_MAN (0x1 << 13)
+#define RT5659_RAMP_MASK (0x1 << 12)
+#define RT5659_RAMP_SFT 12
+#define RT5659_RAMP_DIS (0x0 << 12)
+#define RT5659_RAMP_EN (0x1 << 12)
+#define RT5659_BPS_MASK (0x1 << 11)
+#define RT5659_BPS_SFT 11
+#define RT5659_BPS_DIS (0x0 << 11)
+#define RT5659_BPS_EN (0x1 << 11)
+#define RT5659_FAST_UPDN_MASK (0x1 << 10)
+#define RT5659_FAST_UPDN_SFT 10
+#define RT5659_FAST_UPDN_DIS (0x0 << 10)
+#define RT5659_FAST_UPDN_EN (0x1 << 10)
+#define RT5659_MRES_MASK (0x3 << 8)
+#define RT5659_MRES_SFT 8
+#define RT5659_MRES_15MO (0x0 << 8)
+#define RT5659_MRES_25MO (0x1 << 8)
+#define RT5659_MRES_35MO (0x2 << 8)
+#define RT5659_MRES_45MO (0x3 << 8)
+#define RT5659_VLO_MASK (0x1 << 7)
+#define RT5659_VLO_SFT 7
+#define RT5659_VLO_3V (0x0 << 7)
+#define RT5659_VLO_32V (0x1 << 7)
+#define RT5659_DIG_DP_MASK (0x1 << 6)
+#define RT5659_DIG_DP_SFT 6
+#define RT5659_DIG_DP_DIS (0x0 << 6)
+#define RT5659_DIG_DP_EN (0x1 << 6)
+#define RT5659_DP_TH_MASK (0x3 << 4)
+#define RT5659_DP_TH_SFT 4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5659_CP_SYS_MASK (0x7 << 12)
+#define RT5659_CP_SYS_SFT 12
+#define RT5659_CP_FQ1_MASK (0x7 << 8)
+#define RT5659_CP_FQ1_SFT 8
+#define RT5659_CP_FQ2_MASK (0x7 << 4)
+#define RT5659_CP_FQ2_SFT 4
+#define RT5659_CP_FQ3_MASK (0x7)
+#define RT5659_CP_FQ3_SFT 0
+#define RT5659_CP_FQ_1_5_KHZ 0
+#define RT5659_CP_FQ_3_KHZ 1
+#define RT5659_CP_FQ_6_KHZ 2
+#define RT5659_CP_FQ_12_KHZ 3
+#define RT5659_CP_FQ_24_KHZ 4
+#define RT5659_CP_FQ_48_KHZ 5
+#define RT5659_CP_FQ_96_KHZ 6
+#define RT5659_CP_FQ_192_KHZ 7
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5659_OSW_L_MASK (0x1 << 11)
+#define RT5659_OSW_L_SFT 11
+#define RT5659_OSW_L_DIS (0x0 << 11)
+#define RT5659_OSW_L_EN (0x1 << 11)
+#define RT5659_OSW_R_MASK (0x1 << 10)
+#define RT5659_OSW_R_SFT 10
+#define RT5659_OSW_R_DIS (0x0 << 10)
+#define RT5659_OSW_R_EN (0x1 << 10)
+#define RT5659_PM_HP_MASK (0x3 << 8)
+#define RT5659_PM_HP_SFT 8
+#define RT5659_PM_HP_LV (0x0 << 8)
+#define RT5659_PM_HP_MV (0x1 << 8)
+#define RT5659_PM_HP_HV (0x2 << 8)
+#define RT5659_IB_HP_MASK (0x3 << 6)
+#define RT5659_IB_HP_SFT 6
+#define RT5659_IB_HP_125IL (0x0 << 6)
+#define RT5659_IB_HP_25IL (0x1 << 6)
+#define RT5659_IB_HP_5IL (0x2 << 6)
+#define RT5659_IB_HP_1IL (0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5659_PVDD_DET_MASK (0x1 << 15)
+#define RT5659_PVDD_DET_SFT 15
+#define RT5659_PVDD_DET_DIS (0x0 << 15)
+#define RT5659_PVDD_DET_EN (0x1 << 15)
+#define RT5659_SPK_AG_MASK (0x1 << 14)
+#define RT5659_SPK_AG_SFT 14
+#define RT5659_SPK_AG_DIS (0x0 << 14)
+#define RT5659_SPK_AG_EN (0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5659_MIC1_BS_MASK (0x1 << 15)
+#define RT5659_MIC1_BS_SFT 15
+#define RT5659_MIC1_BS_9AV (0x0 << 15)
+#define RT5659_MIC1_BS_75AV (0x1 << 15)
+#define RT5659_MIC2_BS_MASK (0x1 << 14)
+#define RT5659_MIC2_BS_SFT 14
+#define RT5659_MIC2_BS_9AV (0x0 << 14)
+#define RT5659_MIC2_BS_75AV (0x1 << 14)
+#define RT5659_MIC1_CLK_MASK (0x1 << 13)
+#define RT5659_MIC1_CLK_SFT 13
+#define RT5659_MIC1_CLK_DIS (0x0 << 13)
+#define RT5659_MIC1_CLK_EN (0x1 << 13)
+#define RT5659_MIC2_CLK_MASK (0x1 << 12)
+#define RT5659_MIC2_CLK_SFT 12
+#define RT5659_MIC2_CLK_DIS (0x0 << 12)
+#define RT5659_MIC2_CLK_EN (0x1 << 12)
+#define RT5659_MIC1_OVCD_MASK (0x1 << 11)
+#define RT5659_MIC1_OVCD_SFT 11
+#define RT5659_MIC1_OVCD_DIS (0x0 << 11)
+#define RT5659_MIC1_OVCD_EN (0x1 << 11)
+#define RT5659_MIC1_OVTH_MASK (0x3 << 9)
+#define RT5659_MIC1_OVTH_SFT 9
+#define RT5659_MIC1_OVTH_600UA (0x0 << 9)
+#define RT5659_MIC1_OVTH_1500UA (0x1 << 9)
+#define RT5659_MIC1_OVTH_2000UA (0x2 << 9)
+#define RT5659_MIC2_OVCD_MASK (0x1 << 8)
+#define RT5659_MIC2_OVCD_SFT 8
+#define RT5659_MIC2_OVCD_DIS (0x0 << 8)
+#define RT5659_MIC2_OVCD_EN (0x1 << 8)
+#define RT5659_MIC2_OVTH_MASK (0x3 << 6)
+#define RT5659_MIC2_OVTH_SFT 6
+#define RT5659_MIC2_OVTH_600UA (0x0 << 6)
+#define RT5659_MIC2_OVTH_1500UA (0x1 << 6)
+#define RT5659_MIC2_OVTH_2000UA (0x2 << 6)
+#define RT5659_PWR_MB_MASK (0x1 << 5)
+#define RT5659_PWR_MB_SFT 5
+#define RT5659_PWR_MB_PD (0x0 << 5)
+#define RT5659_PWR_MB_PU (0x1 << 5)
+#define RT5659_PWR_CLK25M_MASK (0x1 << 4)
+#define RT5659_PWR_CLK25M_SFT 4
+#define RT5659_PWR_CLK25M_PD (0x0 << 4)
+#define RT5659_PWR_CLK25M_PU (0x1 << 4)
+
+/* REC Mixer 2 Left Control 2 (0x009c) */
+#define RT5659_M_BST1_RM2_L (0x1 << 5)
+#define RT5659_M_BST1_RM2_L_SFT 5
+#define RT5659_M_BST2_RM2_L (0x1 << 4)
+#define RT5659_M_BST2_RM2_L_SFT 4
+#define RT5659_M_BST3_RM2_L (0x1 << 3)
+#define RT5659_M_BST3_RM2_L_SFT 3
+#define RT5659_M_BST4_RM2_L (0x1 << 2)
+#define RT5659_M_BST4_RM2_L_SFT 2
+#define RT5659_M_OUTVOLL_RM2_L (0x1 << 1)
+#define RT5659_M_OUTVOLL_RM2_L_SFT 1
+#define RT5659_M_SPKVOL_RM2_L (0x1)
+#define RT5659_M_SPKVOL_RM2_L_SFT 0
+
+/* REC Mixer 2 Right Control 2 (0x009e) */
+#define RT5659_M_BST1_RM2_R (0x1 << 5)
+#define RT5659_M_BST1_RM2_R_SFT 5
+#define RT5659_M_BST2_RM2_R (0x1 << 4)
+#define RT5659_M_BST2_RM2_R_SFT 4
+#define RT5659_M_BST3_RM2_R (0x1 << 3)
+#define RT5659_M_BST3_RM2_R_SFT 3
+#define RT5659_M_BST4_RM2_R (0x1 << 2)
+#define RT5659_M_BST4_RM2_R_SFT 2
+#define RT5659_M_OUTVOLR_RM2_R (0x1 << 1)
+#define RT5659_M_OUTVOLR_RM2_R_SFT 1
+#define RT5659_M_MONOVOL_RM2_R (0x1)
+#define RT5659_M_MONOVOL_RM2_R_SFT 0
+
+/* Class D Output Control (0x00a0) */
+#define RT5659_POW_CLSD_DB_MASK (0x1 << 9)
+#define RT5659_POW_CLSD_DB_EN (0x1 << 9)
+#define RT5659_POW_CLSD_DB_DIS (0x0 << 9)
+
+/* EQ Control 1 (0x00b0) */
+#define RT5659_EQ_SRC_DAC (0x0 << 15)
+#define RT5659_EQ_SRC_ADC (0x1 << 15)
+#define RT5659_EQ_UPD (0x1 << 14)
+#define RT5659_EQ_UPD_BIT 14
+#define RT5659_EQ_CD_MASK (0x1 << 13)
+#define RT5659_EQ_CD_SFT 13
+#define RT5659_EQ_CD_DIS (0x0 << 13)
+#define RT5659_EQ_CD_EN (0x1 << 13)
+#define RT5659_EQ_DITH_MASK (0x3 << 8)
+#define RT5659_EQ_DITH_SFT 8
+#define RT5659_EQ_DITH_NOR (0x0 << 8)
+#define RT5659_EQ_DITH_LSB (0x1 << 8)
+#define RT5659_EQ_DITH_LSB_1 (0x2 << 8)
+#define RT5659_EQ_DITH_LSB_2 (0x3 << 8)
+
+/* IRQ Control 1 (0x00b7) */
+#define RT5659_JD1_1_EN_MASK (0x1 << 15)
+#define RT5659_JD1_1_EN_SFT 15
+#define RT5659_JD1_1_DIS (0x0 << 15)
+#define RT5659_JD1_1_EN (0x1 << 15)
+#define RT5659_JD1_2_EN_MASK (0x1 << 12)
+#define RT5659_JD1_2_EN_SFT 12
+#define RT5659_JD1_2_DIS (0x0 << 12)
+#define RT5659_JD1_2_EN (0x1 << 12)
+#define RT5659_IL_IRQ_MASK (0x1 << 3)
+#define RT5659_IL_IRQ_DIS (0x0 << 3)
+#define RT5659_IL_IRQ_EN (0x1 << 3)
+
+/* IRQ Control 5 (0x00ba) */
+#define RT5659_IRQ_JD_EN (0x1 << 3)
+#define RT5659_IRQ_JD_EN_SFT 3
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5659_GP1_PIN_MASK (0x1 << 15)
+#define RT5659_GP1_PIN_SFT 15
+#define RT5659_GP1_PIN_GPIO1 (0x0 << 15)
+#define RT5659_GP1_PIN_IRQ (0x1 << 15)
+#define RT5659_GP2_PIN_MASK (0x1 << 14)
+#define RT5659_GP2_PIN_SFT 14
+#define RT5659_GP2_PIN_GPIO2 (0x0 << 14)
+#define RT5659_GP2_PIN_DMIC1_SCL (0x1 << 14)
+#define RT5659_GP3_PIN_MASK (0x1 << 13)
+#define RT5659_GP3_PIN_SFT 13
+#define RT5659_GP3_PIN_GPIO3 (0x0 << 13)
+#define RT5659_GP3_PIN_PDM_SCL (0x1 << 13)
+#define RT5659_GP4_PIN_MASK (0x1 << 12)
+#define RT5659_GP4_PIN_SFT 12
+#define RT5659_GP4_PIN_GPIO4 (0x0 << 12)
+#define RT5659_GP4_PIN_PDM_SDA (0x1 << 12)
+#define RT5659_GP5_PIN_MASK (0x1 << 11)
+#define RT5659_GP5_PIN_SFT 11
+#define RT5659_GP5_PIN_GPIO5 (0x0 << 11)
+#define RT5659_GP5_PIN_DMIC1_SDA (0x1 << 11)
+#define RT5659_GP6_PIN_MASK (0x1 << 10)
+#define RT5659_GP6_PIN_SFT 10
+#define RT5659_GP6_PIN_GPIO6 (0x0 << 10)
+#define RT5659_GP6_PIN_DMIC2_SDA (0x1 << 10)
+#define RT5659_GP7_PIN_MASK (0x1 << 9)
+#define RT5659_GP7_PIN_SFT 9
+#define RT5659_GP7_PIN_GPIO7 (0x0 << 9)
+#define RT5659_GP7_PIN_PDM_SCL (0x1 << 9)
+#define RT5659_GP8_PIN_MASK (0x1 << 8)
+#define RT5659_GP8_PIN_SFT 8
+#define RT5659_GP8_PIN_GPIO8 (0x0 << 8)
+#define RT5659_GP8_PIN_PDM_SDA (0x1 << 8)
+#define RT5659_GP9_PIN_MASK (0x1 << 7)
+#define RT5659_GP9_PIN_SFT 7
+#define RT5659_GP9_PIN_GPIO9 (0x0 << 7)
+#define RT5659_GP9_PIN_DMIC1_SDA (0x1 << 7)
+#define RT5659_GP10_PIN_MASK (0x1 << 6)
+#define RT5659_GP10_PIN_SFT 6
+#define RT5659_GP10_PIN_GPIO10 (0x0 << 6)
+#define RT5659_GP10_PIN_DMIC2_SDA (0x1 << 6)
+#define RT5659_GP11_PIN_MASK (0x1 << 5)
+#define RT5659_GP11_PIN_SFT 5
+#define RT5659_GP11_PIN_GPIO11 (0x0 << 5)
+#define RT5659_GP11_PIN_DMIC1_SDA (0x1 << 5)
+#define RT5659_GP12_PIN_MASK (0x1 << 4)
+#define RT5659_GP12_PIN_SFT 4
+#define RT5659_GP12_PIN_GPIO12 (0x0 << 4)
+#define RT5659_GP12_PIN_DMIC2_SDA (0x1 << 4)
+#define RT5659_GP13_PIN_MASK (0x3 << 2)
+#define RT5659_GP13_PIN_SFT 2
+#define RT5659_GP13_PIN_GPIO13 (0x0 << 2)
+#define RT5659_GP13_PIN_SPDIF_SDA (0x1 << 2)
+#define RT5659_GP13_PIN_DMIC2_SCL (0x2 << 2)
+#define RT5659_GP13_PIN_PDM_SCL (0x3 << 2)
+#define RT5659_GP15_PIN_MASK (0x3)
+#define RT5659_GP15_PIN_SFT 0
+#define RT5659_GP15_PIN_GPIO15 (0x0)
+#define RT5659_GP15_PIN_DMIC3_SCL (0x1)
+#define RT5659_GP15_PIN_PDM_SDA (0x2)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5659_GP1_PF_IN (0x0 << 2)
+#define RT5659_GP1_PF_OUT (0x1 << 2)
+#define RT5659_GP1_PF_MASK (0x1 << 2)
+#define RT5659_GP1_PF_SFT 2
+
+/* GPIO Control 3 (0x00c2) */
+#define RT5659_I2S2_PIN_MASK (0x1 << 15)
+#define RT5659_I2S2_PIN_SFT 15
+#define RT5659_I2S2_PIN_I2S (0x0 << 15)
+#define RT5659_I2S2_PIN_GPIO (0x1 << 15)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5659_SV_MASK (0x1 << 15)
+#define RT5659_SV_SFT 15
+#define RT5659_SV_DIS (0x0 << 15)
+#define RT5659_SV_EN (0x1 << 15)
+#define RT5659_OUT_SV_MASK (0x1 << 13)
+#define RT5659_OUT_SV_SFT 13
+#define RT5659_OUT_SV_DIS (0x0 << 13)
+#define RT5659_OUT_SV_EN (0x1 << 13)
+#define RT5659_HP_SV_MASK (0x1 << 12)
+#define RT5659_HP_SV_SFT 12
+#define RT5659_HP_SV_DIS (0x0 << 12)
+#define RT5659_HP_SV_EN (0x1 << 12)
+#define RT5659_ZCD_DIG_MASK (0x1 << 11)
+#define RT5659_ZCD_DIG_SFT 11
+#define RT5659_ZCD_DIG_DIS (0x0 << 11)
+#define RT5659_ZCD_DIG_EN (0x1 << 11)
+#define RT5659_ZCD_MASK (0x1 << 10)
+#define RT5659_ZCD_SFT 10
+#define RT5659_ZCD_PD (0x0 << 10)
+#define RT5659_ZCD_PU (0x1 << 10)
+#define RT5659_SV_DLY_MASK (0xf)
+#define RT5659_SV_DLY_SFT 0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5659_ZCD_HP_MASK (0x1 << 15)
+#define RT5659_ZCD_HP_SFT 15
+#define RT5659_ZCD_HP_DIS (0x0 << 15)
+#define RT5659_ZCD_HP_EN (0x1 << 15)
+
+/* 4 Button Inline Command Control 2 (0x00e0) */
+#define RT5659_4BTN_IL_MASK (0x1 << 15)
+#define RT5659_4BTN_IL_EN (0x1 << 15)
+#define RT5659_4BTN_IL_DIS (0x0 << 15)
+
+/* Analog JD Control 1 (0x00f0) */
+#define RT5659_JD1_MODE_MASK (0x3 << 0)
+#define RT5659_JD1_MODE_0 (0x0 << 0)
+#define RT5659_JD1_MODE_1 (0x1 << 0)
+#define RT5659_JD1_MODE_2 (0x2 << 0)
+
+/* Jack Detect Control 3 (0x00f8) */
+#define RT5659_JD_TRI_HPO_SEL_MASK (0x7)
+#define RT5659_JD_TRI_HPO_SEL_SFT (0)
+#define RT5659_JD_HPO_GPIO_JD1 (0x0)
+#define RT5659_JD_HPO_JD1_1 (0x1)
+#define RT5659_JD_HPO_JD1_2 (0x2)
+#define RT5659_JD_HPO_JD2 (0x3)
+#define RT5659_JD_HPO_GPIO_JD2 (0x4)
+#define RT5659_JD_HPO_JD3 (0x5)
+#define RT5659_JD_HPO_JD_D (0x6)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5659_AM_MASK (0x1 << 7)
+#define RT5659_AM_EN (0x1 << 7)
+#define RT5659_AM_DIS (0x1 << 7)
+#define RT5659_DIG_GATE_CTRL 0x1
+#define RT5659_DIG_GATE_CTRL_SFT (0)
+
+/* Chopper and Clock control for ADC (0x011c)*/
+#define RT5659_M_RF_DIG_MASK (0x1 << 12)
+#define RT5659_M_RF_DIG_SFT 12
+#define RT5659_M_RI_DIG (0x1 << 11)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5659_CKXEN_DAC1_MASK (0x1 << 13)
+#define RT5659_CKXEN_DAC1_SFT 13
+#define RT5659_CKGEN_DAC1_MASK (0x1 << 12)
+#define RT5659_CKGEN_DAC1_SFT 12
+#define RT5659_CKXEN_DAC2_MASK (0x1 << 5)
+#define RT5659_CKXEN_DAC2_SFT 5
+#define RT5659_CKGEN_DAC2_MASK (0x1 << 4)
+#define RT5659_CKGEN_DAC2_SFT 4
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5659_CKXEN_ADCC_MASK (0x1 << 13)
+#define RT5659_CKXEN_ADCC_SFT 13
+#define RT5659_CKGEN_ADCC_MASK (0x1 << 12)
+#define RT5659_CKGEN_ADCC_SFT 12
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5659_AD2DA_LB_MASK (0x1 << 9)
+#define RT5659_AD2DA_LB_SFT 9
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5659_NG2_EN_MASK (0x1 << 15)
+#define RT5659_NG2_EN (0x1 << 15)
+#define RT5659_NG2_DIS (0x0 << 15)
+
+/* System Clock Source */
+enum {
+ RT5659_SCLK_S_MCLK,
+ RT5659_SCLK_S_PLL1,
+ RT5659_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+ RT5659_PLL1_S_MCLK,
+ RT5659_PLL1_S_BCLK1,
+ RT5659_PLL1_S_BCLK2,
+ RT5659_PLL1_S_BCLK3,
+ RT5659_PLL1_S_BCLK4,
+};
+
+enum {
+ RT5659_AIF1,
+ RT5659_AIF2,
+ RT5659_AIF3,
+ RT5659_AIF4,
+ RT5659_AIFS,
+};
+
+struct rt5659_pll_code {
+ bool m_bp;
+ int m_code;
+ int n_code;
+ int k_code;
+};
+
+struct rt5659_priv {
+ struct snd_soc_codec *codec;
+ struct rt5659_platform_data pdata;
+ struct regmap *regmap;
+ struct i2c_client *i2c;
+ struct gpio_desc *gpiod_ldo1_en;
+ struct gpio_desc *gpiod_reset;
+ struct snd_soc_jack *hs_jack;
+ struct delayed_work jack_detect_work;
+
+ int sysclk;
+ int sysclk_src;
+ int lrck[RT5659_AIFS];
+ int bclk[RT5659_AIFS];
+ int master[RT5659_AIFS];
+ int v_id;
+
+ int pll_src;
+ int pll_in;
+ int pll_out;
+
+ int jack_type;
+
+};
+
+int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hs_jack);
+
+#endif /* __RT5659_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 69d987a9935c..33e290b703df 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -297,8 +297,6 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg)
case RT5677_HAP_GENE_CTRL2:
case RT5677_PWR_DSP_ST:
case RT5677_PRIV_DATA:
- case RT5677_PLL1_CTRL2:
- case RT5677_PLL2_CTRL2:
case RT5677_ASRC_22:
case RT5677_ASRC_23:
case RT5677_VAD_CTRL5:
@@ -4696,7 +4694,7 @@ static void rt5677_init_gpio(struct i2c_client *i2c)
rt5677->gpio_chip = rt5677_template_chip;
rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM;
- rt5677->gpio_chip.dev = &i2c->dev;
+ rt5677->gpio_chip.parent = &i2c->dev;
rt5677->gpio_chip.base = -1;
ret = gpiochip_add(&rt5677->gpio_chip);
@@ -4788,7 +4786,7 @@ static int rt5677_remove(struct snd_soc_codec *codec)
regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
- gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 1);
return 0;
}
@@ -4803,7 +4801,7 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
regcache_mark_dirty(rt5677->regmap);
gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
- gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 1);
}
return 0;
@@ -4814,8 +4812,11 @@ static int rt5677_resume(struct snd_soc_codec *codec)
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
if (!rt5677->dsp_vad_en) {
+ rt5677->pll_src = 0;
+ rt5677->pll_in = 0;
+ rt5677->pll_out = 0;
gpiod_set_value_cansleep(rt5677->pow_ldo2, 1);
- gpiod_set_value_cansleep(rt5677->reset_pin, 1);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 0);
if (rt5677->pow_ldo2 || rt5677->reset_pin)
msleep(10);
@@ -5160,7 +5161,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
return ret;
}
rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev,
- "realtek,reset", GPIOD_OUT_HIGH);
+ "realtek,reset", GPIOD_OUT_LOW);
if (IS_ERR(rt5677->reset_pin)) {
ret = PTR_ERR(rt5677->reset_pin);
dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret);
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 86b81a60ac52..e2e0bfa7ec20 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -309,7 +309,7 @@ static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = {
.count = ARRAY_SIZE(ssm2518_rates_12288000),
};
-static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
+static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
unsigned int rate)
{
const unsigned int *sysclks = NULL;
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 4cad8929d262..bc3de2e844e6 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1097,8 +1097,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
{
struct twl6040_data *priv;
struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
- struct platform_device *pdev = container_of(codec->dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(codec->dev);
int ret = 0;
priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index c2cdcae18ff6..171a23ddd15d 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2306,7 +2306,7 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
wm5100->gpio_chip = wm5100_template_chip;
wm5100->gpio_chip.ngpio = 6;
- wm5100->gpio_chip.dev = &i2c->dev;
+ wm5100->gpio_chip.parent = &i2c->dev;
if (wm5100->pdata.gpio_base)
wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index c04c0bc6f58a..6088d30962a9 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -360,15 +360,13 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
{
- struct reg_sequence clear_pga = {
- ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
- };
+ unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4;
int ret;
- ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
+ ret = regmap_write(arizona->regmap, reg, 0x80);
if (ret)
dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
- clear_pga.reg, ret);
+ reg, ret);
return ret;
}
@@ -439,18 +437,17 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
- struct snd_soc_card *card = dapm->card;
int ret;
/*
* PGA Volume is also used as part of the enable sequence, so
* usage of it should be avoided whilst that is running.
*/
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
- mutex_unlock(&card->dapm_mutex);
+ snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
@@ -460,18 +457,17 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
- struct snd_soc_card *card = dapm->card;
int ret;
/*
* PGA Volume is also used as part of the enable sequence, so
* usage of it should be avoided whilst that is running.
*/
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
- mutex_unlock(&card->dapm_mutex);
+ snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
@@ -575,6 +571,33 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
+#define WM5110_RXANC_INPUT_ROUTES(widget, name) \
+ { widget, NULL, name " NG Mux" }, \
+ { name " NG Internal", NULL, "RXANC NG Clock" }, \
+ { name " NG Internal", NULL, name " Channel" }, \
+ { name " NG External", NULL, "RXANC NG External Clock" }, \
+ { name " NG External", NULL, name " Channel" }, \
+ { name " NG Mux", "None", name " Channel" }, \
+ { name " NG Mux", "Internal", name " NG Internal" }, \
+ { name " NG Mux", "External", name " NG External" }, \
+ { name " Channel", "Left", name " Left Input" }, \
+ { name " Channel", "Combine", name " Left Input" }, \
+ { name " Channel", "Right", name " Right Input" }, \
+ { name " Channel", "Combine", name " Right Input" }, \
+ { name " Left Input", "IN1", "IN1L PGA" }, \
+ { name " Right Input", "IN1", "IN1R PGA" }, \
+ { name " Left Input", "IN2", "IN2L PGA" }, \
+ { name " Right Input", "IN2", "IN2R PGA" }, \
+ { name " Left Input", "IN3", "IN3L PGA" }, \
+ { name " Right Input", "IN3", "IN3R PGA" }, \
+ { name " Left Input", "IN4", "IN4L PGA" }, \
+ { name " Right Input", "IN4", "IN4R PGA" }
+
+#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \
+ { widget, NULL, name " ANC Source" }, \
+ { name " ANC Source", "RXANCL", "RXANCL" }, \
+ { name " ANC Source", "RXANCR", "RXANCR" }
+
static const struct snd_kcontrol_new wm5110_snd_controls[] = {
SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
@@ -639,6 +662,15 @@ SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R,
SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START,
+ ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1),
+SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START,
+ ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1),
+SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START,
+ ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1),
+
ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
@@ -995,6 +1027,31 @@ static const struct soc_enum wm5110_aec_loopback =
static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
+static const struct snd_kcontrol_new wm5110_anc_input_mux[] = {
+ SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]),
+ SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]),
+ SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]),
+ SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]),
+};
+
+static const struct snd_kcontrol_new wm5110_anc_ng_mux =
+ SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum);
+
+static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
+ SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]),
+ SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]),
+ SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]),
+ SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]),
+ SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]),
+ SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]),
+ SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]),
+ SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]),
+ SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]),
+ SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]),
+ SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]),
+ SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]),
+};
+
static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
@@ -1185,6 +1242,65 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5110_aec_loopback_mux),
+SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
+ ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
+ ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[1]),
+SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[3]),
+SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+
+SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT,
+ 0, NULL, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT,
+ 0, NULL, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[0]),
+SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[1]),
+SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[2]),
+SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[3]),
+SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[4]),
+SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[5]),
+SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[6]),
+SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[7]),
+SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[8]),
+SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[9]),
+SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[10]),
+SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[11]),
+
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -1690,6 +1806,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "Slim2 Capture", NULL, "SYSCLK" },
{ "Slim3 Capture", NULL, "SYSCLK" },
+ { "Voice Control DSP", NULL, "DSP3" },
+ { "Voice Control DSP", NULL, "SYSCLK" },
+
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
@@ -1838,6 +1957,22 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "SPKDAT2L", NULL, "OUT6L" },
{ "SPKDAT2R", NULL, "OUT6R" },
+ WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"),
+ WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"),
+
+ WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"),
+
{ "MICSUPP", NULL, "SYSCLK" },
{ "DRC1 Signal Activity", NULL, "DRC1L" },
@@ -1996,12 +2131,65 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
},
.ops = &arizona_simple_dai_ops,
},
+ {
+ .name = "wm5110-cpu-voicectrl",
+ .capture = {
+ .stream_name = "Voice Control CPU",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = WM5110_RATES,
+ .formats = WM5110_FORMATS,
+ },
+ .compress_new = snd_soc_new_compress,
+ },
+ {
+ .name = "wm5110-dsp-voicectrl",
+ .capture = {
+ .stream_name = "Voice Control DSP",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = WM5110_RATES,
+ .formats = WM5110_FORMATS,
+ },
+ },
};
+static int wm5110_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+ struct arizona *arizona = priv->core.arizona;
+ int n_adsp;
+
+ if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
+ n_adsp = 2;
+ } else {
+ dev_err(arizona->dev,
+ "No suitable compressed stream for DAI '%s'\n",
+ rtd->codec_dai->name);
+ return -EINVAL;
+ }
+
+ return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
+static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
+{
+ struct wm5110_priv *florida = data;
+ int ret;
+
+ ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
+ if (ret == -ENODEV)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
static int wm5110_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct arizona *arizona = priv->core.arizona;
int i, ret;
priv->core.arizona->dapm = dapm;
@@ -2010,6 +2198,14 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+ "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
+ priv);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
+ return ret;
+ }
+
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
if (ret)
@@ -2030,12 +2226,15 @@ err_adsp2_codec_probe:
for (--i; i >= 0; --i)
wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
+
return ret;
}
static int wm5110_codec_remove(struct snd_soc_codec *codec)
{
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct arizona *arizona = priv->core.arizona;
int i;
for (i = 0; i < WM5110_NUM_ADSP; ++i)
@@ -2043,6 +2242,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
priv->core.arizona->dapm = NULL;
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
+
return 0;
}
@@ -2088,6 +2289,20 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
};
+static struct snd_compr_ops wm5110_compr_ops = {
+ .open = wm5110_open,
+ .free = wm_adsp_compr_free,
+ .set_params = wm_adsp_compr_set_params,
+ .get_caps = wm_adsp_compr_get_caps,
+ .trigger = wm_adsp_compr_trigger,
+ .pointer = wm_adsp_compr_pointer,
+ .copy = wm_adsp_compr_copy,
+};
+
+static struct snd_soc_platform_driver wm5110_compr_platform = {
+ .compr_ops = &wm5110_compr_ops,
+};
+
static int wm5110_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -2148,8 +2363,21 @@ static int wm5110_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
+ ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
+ goto error;
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
wm5110_dai, ARRAY_SIZE(wm5110_dai));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+ snd_soc_unregister_platform(&pdev->dev);
+ }
+
+error:
+ return ret;
}
static int wm5110_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index e4cc41e6c23e..a82b8bc2cfc0 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1804,7 +1804,7 @@ static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
- return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
+ return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT);
}
static int wm8903_gpio_direction_out(struct gpio_chip *chip,
@@ -1853,7 +1853,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903)
wm8903->gpio_chip = wm8903_template_chip;
wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
- wm8903->gpio_chip.dev = wm8903->dev;
+ wm8903->gpio_chip.parent = wm8903->dev;
if (pdata->gpio_base)
wm8903->gpio_chip.base = pdata->gpio_base;
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 2aa23f1b9e3c..8172e499e6ed 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -312,7 +312,7 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg)
case WM8904_FLL_NCO_TEST_1:
return true;
default:
- return true;
+ return false;
}
}
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 5380798883b5..ff237726775a 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -147,6 +147,13 @@ static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
+static const char *wm8960_adc_data_output_sel[] = {
+ "Left Data = Left ADC; Right Data = Right ADC",
+ "Left Data = Left ADC; Right Data = Left ADC",
+ "Left Data = Right ADC; Right Data = Right ADC",
+ "Left Data = Right ADC; Right Data = Left ADC",
+};
+static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
@@ -155,6 +162,8 @@ static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
+ SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
+ SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
};
static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
@@ -295,6 +304,9 @@ SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume",
WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
+
+SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
+SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
};
static const struct snd_kcontrol_new wm8960_lin_boost[] = {
@@ -401,8 +413,8 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
{ "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
- { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
- { "Left Input Mixer", NULL, "LINPUT1", }, /* Really Boost Switch */
+ { "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
+ { "Left Input Mixer", "Boost Switch", "LINPUT1" }, /* Really Boost Switch */
{ "Left Input Mixer", NULL, "LINPUT2" },
{ "Left Input Mixer", NULL, "LINPUT3" },
@@ -410,8 +422,8 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
{ "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
- { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
- { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */
+ { "Right Input Mixer", "Boost Switch", "Right Boost Mixer" },
+ { "Right Input Mixer", "Boost Switch", "RINPUT1" }, /* Really Boost Switch */
{ "Right Input Mixer", NULL, "RINPUT2" },
{ "Right Input Mixer", NULL, "RINPUT3" },
@@ -419,11 +431,11 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Right ADC", NULL, "Right Input Mixer" },
{ "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
- { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} ,
+ { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" },
{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
{ "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
- { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
+ { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" },
{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
{ "LOUT1 PGA", NULL, "Left Output Mixer" },
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index a7e79784fc16..88223608a33f 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -131,7 +131,7 @@ static const struct reg_default wm8962_reg[] = {
{ 15, 0x6243 }, /* R15 - Software Reset */
{ 17, 0x007B }, /* R17 - ALC1 */
-
+ { 18, 0x0000 }, /* R18 - ALC2 */
{ 19, 0x1C32 }, /* R19 - ALC3 */
{ 20, 0x3200 }, /* R20 - Noise Gate */
{ 21, 0x00C0 }, /* R21 - Left ADC volume */
@@ -794,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
case WM8962_CLOCKING1:
case WM8962_CLOCKING2:
case WM8962_SOFTWARE_RESET:
- case WM8962_ALC2:
case WM8962_THERMAL_SHUTDOWN_STATUS:
case WM8962_ADDITIONAL_CONTROL_4:
case WM8962_DC_SERVO_6:
@@ -3380,7 +3379,7 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
wm8962->gpio_chip = wm8962_template_chip;
wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
- wm8962->gpio_chip.dev = codec->dev;
+ wm8962->gpio_chip.parent = codec->dev;
if (pdata->gpio_base)
wm8962->gpio_chip.base = pdata->gpio_base;
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 4c29bd2ae75c..c284c7b6db8b 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -632,9 +632,16 @@ static const struct i2c_device_id wm8974_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
+static const struct of_device_id wm8974_of_match[] = {
+ { .compatible = "wlf,wm8974", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8974_of_match);
+
static struct i2c_driver wm8974_i2c_driver = {
.driver = {
.name = "wm8974",
+ .of_match_table = wm8974_of_match,
},
.probe = wm8974_i2c_probe,
.remove = wm8974_i2c_remove,
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index f7ccd9fc5808..8d7d6c01a2f7 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2204,7 +2204,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
wm8996->gpio_chip = wm8996_template_chip;
wm8996->gpio_chip.ngpio = 5;
- wm8996->gpio_chip.dev = wm8996->dev;
+ wm8996->gpio_chip.parent = wm8996->dev;
if (wm8996->pdata.gpio_base)
wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 8782dfb628ab..7719bc509e50 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -199,20 +199,20 @@ static const char * const wm8998_inmux_texts[] = {
"B",
};
-static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
- ARIZONA_ADC_DIGITAL_VOLUME_1L,
- ARIZONA_IN1L_SRC_SHIFT,
- wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
+ ARIZONA_ADC_DIGITAL_VOLUME_1L,
+ ARIZONA_IN1L_SRC_SHIFT,
+ wm8998_inmux_texts);
-static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
- ARIZONA_ADC_DIGITAL_VOLUME_1R,
- ARIZONA_IN1R_SRC_SHIFT,
- wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
+ ARIZONA_ADC_DIGITAL_VOLUME_1R,
+ ARIZONA_IN1R_SRC_SHIFT,
+ wm8998_inmux_texts);
-static const SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
- ARIZONA_ADC_DIGITAL_VOLUME_2L,
- ARIZONA_IN2L_SRC_SHIFT,
- wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
+ ARIZONA_ADC_DIGITAL_VOLUME_2L,
+ ARIZONA_IN2L_SRC_SHIFT,
+ wm8998_inmux_texts);
static const struct snd_kcontrol_new wm8998_in1mux[2] = {
SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
@@ -522,17 +522,17 @@ static const unsigned int wm8998_aec_loopback_values[] = {
0, 1, 2, 3, 4, 6, 7, 8, 9,
};
-static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
- ARIZONA_DAC_AEC_CONTROL_1,
- ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
- wm8998_aec_loopback_texts,
- wm8998_aec_loopback_values);
-
-static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
- ARIZONA_DAC_AEC_CONTROL_2,
- ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
- wm8998_aec_loopback_texts,
- wm8998_aec_loopback_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
+ ARIZONA_DAC_AEC_CONTROL_1,
+ ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+ wm8998_aec_loopback_texts,
+ wm8998_aec_loopback_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
+ ARIZONA_DAC_AEC_CONTROL_2,
+ ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+ wm8998_aec_loopback_texts,
+ wm8998_aec_loopback_values);
static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback),
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 4083a5130cbd..79e143625ac3 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
@@ -39,34 +40,6 @@ struct wm9713_priv {
struct mutex lock;
};
-static unsigned int ac97_read(struct snd_soc_codec *codec,
- unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int val);
-
-/*
- * WM9713 register cache
- * Reg 0x3c bit 15 is used by touch driver.
- */
-static const u16 wm9713_reg[] = {
- 0x6174, 0x8080, 0x8080, 0x8080,
- 0xc880, 0xe808, 0xe808, 0x0808,
- 0x00da, 0x8000, 0xd600, 0xaaa0,
- 0xaaa0, 0xaaa0, 0x0000, 0x0000,
- 0x0f0f, 0x0040, 0x0000, 0x7f00,
- 0x0405, 0x0410, 0xbb80, 0xbb80,
- 0x0000, 0xbb80, 0x0000, 0x4523,
- 0x0000, 0x2000, 0x7eff, 0xffff,
- 0x0000, 0x0000, 0x0080, 0x0000,
- 0x0000, 0x0000, 0xfffe, 0xffff,
- 0x0000, 0x0000, 0x0000, 0xfffe,
- 0x4000, 0x0000, 0x0000, 0x0000,
- 0xb032, 0x3e00, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0006,
- 0x0001, 0x0000, 0x574d, 0x4c13,
-};
-
#define HPL_MIXER 0
#define HPR_MIXER 1
@@ -220,18 +193,15 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- u16 status, rate;
if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
return -EINVAL;
/* Gracefully shut down the voice interface. */
- status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000;
- rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
- ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0200);
schedule_timeout_interruptible(msecs_to_jiffies(1));
- ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
- ac97_write(codec, AC97_EXTENDED_MID, status);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
+ snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x1000, 0x1000);
return 0;
}
@@ -674,39 +644,97 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = {
{"Capture Mono Mux", "Right", "Right Capture Source"},
};
-static unsigned int ac97_read(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool wm9713_readable_reg(struct device *dev, unsigned int reg)
{
- struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- u16 *cache = codec->reg_cache;
-
- if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
- reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
- reg == AC97_CD)
- return soc_ac97_ops->read(wm9713->ac97, reg);
- else {
- reg = reg >> 1;
-
- if (reg >= (ARRAY_SIZE(wm9713_reg)))
- return -EIO;
-
- return cache[reg];
+ switch (reg) {
+ case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
+ case AC97_PCM_LR_ADC_RATE:
+ case AC97_CENTER_LFE_MASTER:
+ case AC97_SPDIF ... AC97_LINE1_LEVEL:
+ case AC97_GPIO_CFG ... 0x5c:
+ case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
+ case 0x74 ... AC97_VENDOR_ID2:
+ return true;
+ default:
+ return false;
}
}
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int val)
+static bool wm9713_writeable_reg(struct device *dev, unsigned int reg)
{
- struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+ switch (reg) {
+ case AC97_VENDOR_ID1:
+ case AC97_VENDOR_ID2:
+ return false;
+ default:
+ return wm9713_readable_reg(dev, reg);
+ }
+}
- u16 *cache = codec->reg_cache;
- soc_ac97_ops->write(wm9713->ac97, reg, val);
- reg = reg >> 1;
- if (reg < (ARRAY_SIZE(wm9713_reg)))
- cache[reg] = val;
+static const struct reg_default wm9713_reg_defaults[] = {
+ { 0x02, 0x8080 }, /* Speaker Output Volume */
+ { 0x04, 0x8080 }, /* Headphone Output Volume */
+ { 0x06, 0x8080 }, /* Out3/OUT4 Volume */
+ { 0x08, 0xc880 }, /* Mono Volume */
+ { 0x0a, 0xe808 }, /* LINEIN Volume */
+ { 0x0c, 0xe808 }, /* DAC PGA Volume */
+ { 0x0e, 0x0808 }, /* MIC PGA Volume */
+ { 0x10, 0x00da }, /* MIC Routing Control */
+ { 0x12, 0x8000 }, /* Record PGA Volume */
+ { 0x14, 0xd600 }, /* Record Routing */
+ { 0x16, 0xaaa0 }, /* PCBEEP Volume */
+ { 0x18, 0xaaa0 }, /* VxDAC Volume */
+ { 0x1a, 0xaaa0 }, /* AUXDAC Volume */
+ { 0x1c, 0x0000 }, /* Output PGA Mux */
+ { 0x1e, 0x0000 }, /* DAC 3D control */
+ { 0x20, 0x0f0f }, /* DAC Tone Control*/
+ { 0x22, 0x0040 }, /* MIC Input Select & Bias */
+ { 0x24, 0x0000 }, /* Output Volume Mapping & Jack */
+ { 0x26, 0x7f00 }, /* Powerdown Ctrl/Stat*/
+ { 0x28, 0x0405 }, /* Extended Audio ID */
+ { 0x2a, 0x0410 }, /* Extended Audio Start/Ctrl */
+ { 0x2c, 0xbb80 }, /* Audio DACs Sample Rate */
+ { 0x2e, 0xbb80 }, /* AUXDAC Sample Rate */
+ { 0x32, 0xbb80 }, /* Audio ADCs Sample Rate */
+ { 0x36, 0x4523 }, /* PCM codec control */
+ { 0x3a, 0x2000 }, /* SPDIF control */
+ { 0x3c, 0xfdff }, /* Powerdown 1 */
+ { 0x3e, 0xffff }, /* Powerdown 2 */
+ { 0x40, 0x0000 }, /* General Purpose */
+ { 0x42, 0x0000 }, /* Fast Power-Up Control */
+ { 0x44, 0x0080 }, /* MCLK/PLL Control */
+ { 0x46, 0x0000 }, /* MCLK/PLL Control */
+ { 0x4c, 0xfffe }, /* GPIO Pin Configuration */
+ { 0x4e, 0xffff }, /* GPIO Pin Polarity / Type */
+ { 0x50, 0x0000 }, /* GPIO Pin Sticky */
+ { 0x52, 0x0000 }, /* GPIO Pin Wake-Up */
+ /* GPIO Pin Status */
+ { 0x56, 0xfffe }, /* GPIO Pin Sharing */
+ { 0x58, 0x4000 }, /* GPIO PullUp/PullDown */
+ { 0x5a, 0x0000 }, /* Additional Functions 1 */
+ { 0x5c, 0x0000 }, /* Additional Functions 2 */
+ { 0x60, 0xb032 }, /* ALC Control */
+ { 0x62, 0x3e00 }, /* ALC / Noise Gate Control */
+ { 0x64, 0x0000 }, /* AUXDAC input control */
+ { 0x74, 0x0000 }, /* Digitiser Reg 1 */
+ { 0x76, 0x0006 }, /* Digitiser Reg 2 */
+ { 0x78, 0x0001 }, /* Digitiser Reg 3 */
+ { 0x7a, 0x0000 }, /* Digitiser Read Back */
+};
- return 0;
-}
+static const struct regmap_config wm9713_regmap_config = {
+ .reg_bits = 16,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .max_register = 0x7e,
+ .cache_type = REGCACHE_RBTREE,
+
+ .reg_defaults = wm9713_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
+ .volatile_reg = regmap_ac97_default_volatile,
+ .readable_reg = wm9713_readable_reg,
+ .writeable_reg = wm9713_writeable_reg,
+};
/* PLL divisors */
struct _pll_div {
@@ -793,10 +821,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
/* turn PLL off ? */
if (freq_in == 0) {
/* disable PLL power and select ext source */
- reg = ac97_read(codec, AC97_HANDSET_RATE);
- ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080);
- reg = ac97_read(codec, AC97_EXTENDED_MID);
- ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0080);
+ snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0200);
wm9713->pll_in = 0;
return 0;
}
@@ -806,7 +832,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
if (pll_div.k == 0) {
reg = (pll_div.n << 12) | (pll_div.lf << 11) |
(pll_div.divsel << 9) | (pll_div.divctl << 8);
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
} else {
/* write the fractional k to the reg 0x46 pages */
reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) |
@@ -814,33 +840,31 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
/* K [21:20] */
reg = reg2 | (0x5 << 4) | (pll_div.k >> 20);
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
/* K [19:16] */
reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf);
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
/* K [15:12] */
reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf);
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
/* K [11:8] */
reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf);
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
/* K [7:4] */
reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf);
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */
- ac97_write(codec, AC97_LINE1_LEVEL, reg);
+ snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
}
/* turn PLL on and select as source */
- reg = ac97_read(codec, AC97_EXTENDED_MID);
- ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff);
- reg = ac97_read(codec, AC97_HANDSET_RATE);
- ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f);
+ snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0000);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0000);
wm9713->pll_in = freq_in;
/* wait 10ms AC97 link frames for the link to stabilise */
@@ -863,10 +887,10 @@ static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai,
int tristate)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0x9fff;
if (tristate)
- ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+ snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+ 0x6000, 0x0000);
return 0;
}
@@ -879,36 +903,30 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 reg;
switch (div_id) {
case WM9713_PCMCLK_DIV:
- reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xf0ff;
- ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, div);
break;
case WM9713_CLKA_MULT:
- reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffd;
- ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0002, div);
break;
case WM9713_CLKB_MULT:
- reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffb;
- ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0004, div);
break;
case WM9713_HIFI_DIV:
- reg = ac97_read(codec, AC97_HANDSET_RATE) & 0x8fff;
- ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+ snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x7000, div);
break;
case WM9713_PCMBCLK_DIV:
- reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xf1ff;
- ac97_write(codec, AC97_CENTER_LFE_MASTER, reg | div);
+ snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, 0x0e00, div);
break;
case WM9713_PCMCLK_PLL_DIV:
- reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
- ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x60 | div);
+ snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+ 0x007f, div | 0x60);
break;
case WM9713_HIFI_PLL_DIV:
- reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
- ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x70 | div);
+ snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+ 0x007f, div | 0x70);
break;
default:
return -EINVAL;
@@ -921,7 +939,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 gpio = ac97_read(codec, AC97_GPIO_CFG) & 0xffc5;
+ u16 gpio = snd_soc_read(codec, AC97_GPIO_CFG) & 0xffc5;
u16 reg = 0x8000;
/* clock masters */
@@ -974,8 +992,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
}
- ac97_write(codec, AC97_GPIO_CFG, gpio);
- ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+ snd_soc_write(codec, AC97_GPIO_CFG, gpio);
+ snd_soc_write(codec, AC97_CENTER_LFE_MASTER, reg);
return 0;
}
@@ -984,24 +1002,24 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3;
+ /* enable PCM interface in master mode */
switch (params_width(params)) {
case 16:
break;
case 20:
- reg |= 0x0004;
+ snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+ 0x000c, 0x0004);
break;
case 24:
- reg |= 0x0008;
+ snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+ 0x000c, 0x0008);
break;
case 32:
- reg |= 0x000c;
+ snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+ 0x000c, 0x000c);
break;
}
-
- /* enable PCM interface in master mode */
- ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
return 0;
}
@@ -1011,17 +1029,15 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct snd_pcm_runtime *runtime = substream->runtime;
int reg;
- u16 vra;
- vra = ac97_read(codec, AC97_EXTENDED_STATUS);
- ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+ snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = AC97_PCM_FRONT_DAC_RATE;
else
reg = AC97_PCM_LR_ADC_RATE;
- return ac97_write(codec, reg, runtime->rate);
+ return snd_soc_write(codec, reg, runtime->rate);
}
static int ac97_aux_prepare(struct snd_pcm_substream *substream,
@@ -1029,17 +1045,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
{
struct snd_soc_codec *codec = dai->codec;
struct snd_pcm_runtime *runtime = substream->runtime;
- u16 vra, xsle;
- vra = ac97_read(codec, AC97_EXTENDED_STATUS);
- ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
- xsle = ac97_read(codec, AC97_PCI_SID);
- ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
+ snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+ snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000);
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
- return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+ return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
}
#define WM9713_RATES (SNDRV_PCM_RATE_8000 | \
@@ -1128,27 +1141,23 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
static int wm9713_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg;
-
switch (level) {
case SND_SOC_BIAS_ON:
/* enable thermal shutdown */
- reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff;
- ac97_write(codec, AC97_EXTENDED_MID, reg);
+ snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xe400, 0x0000);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* enable master bias and vmid */
- reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff;
- ac97_write(codec, AC97_EXTENDED_MID, reg);
- ac97_write(codec, AC97_POWERDOWN, 0x0000);
+ snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xc400, 0x0000);
+ snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
break;
case SND_SOC_BIAS_OFF:
/* disable everything including AC link */
- ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
- ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
- ac97_write(codec, AC97_POWERDOWN, 0xffff);
+ snd_soc_write(codec, AC97_EXTENDED_MID, 0xffff);
+ snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+ snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
return 0;
@@ -1156,16 +1165,14 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
static int wm9713_soc_suspend(struct snd_soc_codec *codec)
{
- u16 reg;
-
/* Disable everything except touchpanel - that will be handled
* by the touch driver and left disabled if touch is not in
* use. */
- reg = ac97_read(codec, AC97_EXTENDED_MID);
- ac97_write(codec, AC97_EXTENDED_MID, reg | 0x7fff);
- ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
- ac97_write(codec, AC97_POWERDOWN, 0x6f00);
- ac97_write(codec, AC97_POWERDOWN, 0xffff);
+ snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x7fff,
+ 0x7fff);
+ snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+ snd_soc_write(codec, AC97_POWERDOWN, 0x6f00);
+ snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
return 0;
}
@@ -1173,8 +1180,7 @@ static int wm9713_soc_suspend(struct snd_soc_codec *codec)
static int wm9713_soc_resume(struct snd_soc_codec *codec)
{
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- int i, ret;
- u16 *cache = codec->reg_cache;
+ int ret;
ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
WM9713_VENDOR_ID_MASK);
@@ -1189,12 +1195,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
/* only synchronise the codec if warm reset failed */
if (ret == 0) {
- for (i = 2; i < ARRAY_SIZE(wm9713_reg) << 1; i += 2) {
- if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
- i == AC97_EXTENDED_MSTATUS || i > 0x66)
- continue;
- soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]);
- }
+ regcache_mark_dirty(codec->component.regmap);
+ snd_soc_cache_sync(codec);
}
return ret;
@@ -1203,16 +1205,23 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
static int wm9713_soc_probe(struct snd_soc_codec *codec)
{
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- int reg;
+ struct regmap *regmap;
wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
WM9713_VENDOR_ID_MASK);
if (IS_ERR(wm9713->ac97))
return PTR_ERR(wm9713->ac97);
+ regmap = devm_regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
+ if (IS_ERR(regmap)) {
+ snd_soc_free_ac97_codec(wm9713->ac97);
+ return PTR_ERR(regmap);
+ }
+
+ snd_soc_codec_init_regmap(codec, regmap);
+
/* unmute the adc - move to kcontrol */
- reg = ac97_read(codec, AC97_CD) & 0x7fff;
- ac97_write(codec, AC97_CD, reg);
+ snd_soc_update_bits(codec, AC97_CD, 0x7fff, 0x0000);
return 0;
}
@@ -1221,6 +1230,7 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec)
{
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+ snd_soc_codec_exit_regmap(codec);
snd_soc_free_ac97_codec(wm9713->ac97);
return 0;
}
@@ -1230,13 +1240,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
.remove = wm9713_soc_remove,
.suspend = wm9713_soc_suspend,
.resume = wm9713_soc_resume,
- .read = ac97_read,
- .write = ac97_write,
.set_bias_level = wm9713_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(wm9713_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_step = 2,
- .reg_cache_default = wm9713_reg,
.controls = wm9713_snd_ac97_controls,
.num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls),
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 0bb415a28723..33806d487b8a 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -201,27 +201,194 @@ static void wm_adsp_buf_free(struct list_head *list)
}
}
-#define WM_ADSP_NUM_FW 4
-
-#define WM_ADSP_FW_MBC_VSS 0
-#define WM_ADSP_FW_TX 1
-#define WM_ADSP_FW_TX_SPK 2
-#define WM_ADSP_FW_RX_ANC 3
+#define WM_ADSP_FW_MBC_VSS 0
+#define WM_ADSP_FW_HIFI 1
+#define WM_ADSP_FW_TX 2
+#define WM_ADSP_FW_TX_SPK 3
+#define WM_ADSP_FW_RX 4
+#define WM_ADSP_FW_RX_ANC 5
+#define WM_ADSP_FW_CTRL 6
+#define WM_ADSP_FW_ASR 7
+#define WM_ADSP_FW_TRACE 8
+#define WM_ADSP_FW_SPK_PROT 9
+#define WM_ADSP_FW_MISC 10
+
+#define WM_ADSP_NUM_FW 11
static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
- [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
- [WM_ADSP_FW_TX] = "Tx",
- [WM_ADSP_FW_TX_SPK] = "Tx Speaker",
- [WM_ADSP_FW_RX_ANC] = "Rx ANC",
+ [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
+ [WM_ADSP_FW_HIFI] = "MasterHiFi",
+ [WM_ADSP_FW_TX] = "Tx",
+ [WM_ADSP_FW_TX_SPK] = "Tx Speaker",
+ [WM_ADSP_FW_RX] = "Rx",
+ [WM_ADSP_FW_RX_ANC] = "Rx ANC",
+ [WM_ADSP_FW_CTRL] = "Voice Ctrl",
+ [WM_ADSP_FW_ASR] = "ASR Assist",
+ [WM_ADSP_FW_TRACE] = "Dbg Trace",
+ [WM_ADSP_FW_SPK_PROT] = "Protection",
+ [WM_ADSP_FW_MISC] = "Misc",
+};
+
+struct wm_adsp_system_config_xm_hdr {
+ __be32 sys_enable;
+ __be32 fw_id;
+ __be32 fw_rev;
+ __be32 boot_status;
+ __be32 watchdog;
+ __be32 dma_buffer_size;
+ __be32 rdma[6];
+ __be32 wdma[8];
+ __be32 build_job_name[3];
+ __be32 build_job_number;
+};
+
+struct wm_adsp_alg_xm_struct {
+ __be32 magic;
+ __be32 smoothing;
+ __be32 threshold;
+ __be32 host_buf_ptr;
+ __be32 start_seq;
+ __be32 high_water_mark;
+ __be32 low_water_mark;
+ __be64 smoothed_power;
+};
+
+struct wm_adsp_buffer {
+ __be32 X_buf_base; /* XM base addr of first X area */
+ __be32 X_buf_size; /* Size of 1st X area in words */
+ __be32 X_buf_base2; /* XM base addr of 2nd X area */
+ __be32 X_buf_brk; /* Total X size in words */
+ __be32 Y_buf_base; /* YM base addr of Y area */
+ __be32 wrap; /* Total size X and Y in words */
+ __be32 high_water_mark; /* Point at which IRQ is asserted */
+ __be32 irq_count; /* bits 1-31 count IRQ assertions */
+ __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */
+ __be32 next_write_index; /* word index of next write */
+ __be32 next_read_index; /* word index of next read */
+ __be32 error; /* error if any */
+ __be32 oldest_block_index; /* word index of oldest surviving */
+ __be32 requested_rewind; /* how many blocks rewind was done */
+ __be32 reserved_space; /* internal */
+ __be32 min_free; /* min free space since stream start */
+ __be32 blocks_written[2]; /* total blocks written (64 bit) */
+ __be32 words_written[2]; /* total words written (64 bit) */
+};
+
+struct wm_adsp_compr_buf {
+ struct wm_adsp *dsp;
+
+ struct wm_adsp_buffer_region *regions;
+ u32 host_buf_ptr;
+
+ u32 error;
+ u32 irq_count;
+ int read_index;
+ int avail;
+};
+
+struct wm_adsp_compr {
+ struct wm_adsp *dsp;
+ struct wm_adsp_compr_buf *buf;
+
+ struct snd_compr_stream *stream;
+ struct snd_compressed_buffer size;
+
+ u32 *raw_buf;
+ unsigned int copied_total;
+};
+
+#define WM_ADSP_DATA_WORD_SIZE 3
+
+#define WM_ADSP_MIN_FRAGMENTS 1
+#define WM_ADSP_MAX_FRAGMENTS 256
+#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE)
+#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE)
+
+#define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7
+
+#define HOST_BUFFER_FIELD(field) \
+ (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
+
+#define ALG_XM_FIELD(field) \
+ (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp);
+static int wm_adsp_buffer_free(struct wm_adsp *dsp);
+
+struct wm_adsp_buffer_region {
+ unsigned int offset;
+ unsigned int cumulative_size;
+ unsigned int mem_type;
+ unsigned int base_addr;
+};
+
+struct wm_adsp_buffer_region_def {
+ unsigned int mem_type;
+ unsigned int base_offset;
+ unsigned int size_offset;
};
-static struct {
+static struct wm_adsp_buffer_region_def ez2control_regions[] = {
+ {
+ .mem_type = WMFW_ADSP2_XM,
+ .base_offset = HOST_BUFFER_FIELD(X_buf_base),
+ .size_offset = HOST_BUFFER_FIELD(X_buf_size),
+ },
+ {
+ .mem_type = WMFW_ADSP2_XM,
+ .base_offset = HOST_BUFFER_FIELD(X_buf_base2),
+ .size_offset = HOST_BUFFER_FIELD(X_buf_brk),
+ },
+ {
+ .mem_type = WMFW_ADSP2_YM,
+ .base_offset = HOST_BUFFER_FIELD(Y_buf_base),
+ .size_offset = HOST_BUFFER_FIELD(wrap),
+ },
+};
+
+struct wm_adsp_fw_caps {
+ u32 id;
+ struct snd_codec_desc desc;
+ int num_regions;
+ struct wm_adsp_buffer_region_def *region_defs;
+};
+
+static const struct wm_adsp_fw_caps ez2control_caps[] = {
+ {
+ .id = SND_AUDIOCODEC_BESPOKE,
+ .desc = {
+ .max_ch = 1,
+ .sample_rates = { 16000 },
+ .num_sample_rates = 1,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .num_regions = ARRAY_SIZE(ez2control_regions),
+ .region_defs = ez2control_regions,
+ },
+};
+
+static const struct {
const char *file;
+ int compr_direction;
+ int num_caps;
+ const struct wm_adsp_fw_caps *caps;
} wm_adsp_fw[WM_ADSP_NUM_FW] = {
- [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
- [WM_ADSP_FW_TX] = { .file = "tx" },
- [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
- [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
+ [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
+ [WM_ADSP_FW_HIFI] = { .file = "hifi" },
+ [WM_ADSP_FW_TX] = { .file = "tx" },
+ [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
+ [WM_ADSP_FW_RX] = { .file = "rx" },
+ [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
+ [WM_ADSP_FW_CTRL] = {
+ .file = "ctrl",
+ .compr_direction = SND_COMPRESS_CAPTURE,
+ .num_caps = ARRAY_SIZE(ez2control_caps),
+ .caps = ez2control_caps,
+ },
+ [WM_ADSP_FW_ASR] = { .file = "asr" },
+ [WM_ADSP_FW_TRACE] = { .file = "trace" },
+ [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
+ [WM_ADSP_FW_MISC] = { .file = "misc" },
};
struct wm_coeff_ctl_ops {
@@ -254,30 +421,24 @@ static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
{
char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
- mutex_lock(&dsp->debugfs_lock);
kfree(dsp->wmfw_file_name);
dsp->wmfw_file_name = tmp;
- mutex_unlock(&dsp->debugfs_lock);
}
static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
{
char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
- mutex_lock(&dsp->debugfs_lock);
kfree(dsp->bin_file_name);
dsp->bin_file_name = tmp;
- mutex_unlock(&dsp->debugfs_lock);
}
static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
{
- mutex_lock(&dsp->debugfs_lock);
kfree(dsp->wmfw_file_name);
kfree(dsp->bin_file_name);
dsp->wmfw_file_name = NULL;
dsp->bin_file_name = NULL;
- mutex_unlock(&dsp->debugfs_lock);
}
static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
@@ -287,7 +448,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
struct wm_adsp *dsp = file->private_data;
ssize_t ret;
- mutex_lock(&dsp->debugfs_lock);
+ mutex_lock(&dsp->pwr_lock);
if (!dsp->wmfw_file_name || !dsp->running)
ret = 0;
@@ -296,7 +457,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
dsp->wmfw_file_name,
strlen(dsp->wmfw_file_name));
- mutex_unlock(&dsp->debugfs_lock);
+ mutex_unlock(&dsp->pwr_lock);
return ret;
}
@@ -307,7 +468,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
struct wm_adsp *dsp = file->private_data;
ssize_t ret;
- mutex_lock(&dsp->debugfs_lock);
+ mutex_lock(&dsp->pwr_lock);
if (!dsp->bin_file_name || !dsp->running)
ret = 0;
@@ -316,7 +477,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
dsp->bin_file_name,
strlen(dsp->bin_file_name));
- mutex_unlock(&dsp->debugfs_lock);
+ mutex_unlock(&dsp->pwr_lock);
return ret;
}
@@ -436,6 +597,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
return 0;
@@ -443,12 +605,16 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
return -EINVAL;
- if (dsp[e->shift_l].running)
- return -EBUSY;
+ mutex_lock(&dsp[e->shift_l].pwr_lock);
- dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+ if (dsp[e->shift_l].running || dsp[e->shift_l].compr)
+ ret = -EBUSY;
+ else
+ dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
- return 0;
+ mutex_unlock(&dsp[e->shift_l].pwr_lock);
+
+ return ret;
}
static const struct soc_enum wm_adsp_fw_enum[] = {
@@ -523,10 +689,10 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
be16_to_cpu(scratch[3]));
}
-static int wm_coeff_info(struct snd_kcontrol *kcontrol,
+static int wm_coeff_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uinfo)
{
- struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+ struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = ctl->len;
@@ -572,19 +738,24 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
return 0;
}
-static int wm_coeff_put(struct snd_kcontrol *kcontrol,
+static int wm_coeff_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
- struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+ struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
char *p = ucontrol->value.bytes.data;
+ int ret = 0;
+
+ mutex_lock(&ctl->dsp->pwr_lock);
memcpy(ctl->cache, p, ctl->len);
ctl->set = 1;
- if (!ctl->enabled)
- return 0;
+ if (ctl->enabled)
+ ret = wm_coeff_write_control(ctl, p, ctl->len);
+
+ mutex_unlock(&ctl->dsp->pwr_lock);
- return wm_coeff_write_control(ctl, p, ctl->len);
+ return ret;
}
static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
@@ -626,22 +797,30 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
return 0;
}
-static int wm_coeff_get(struct snd_kcontrol *kcontrol,
+static int wm_coeff_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
- struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+ struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
char *p = ucontrol->value.bytes.data;
+ int ret = 0;
+
+ mutex_lock(&ctl->dsp->pwr_lock);
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
if (ctl->enabled)
- return wm_coeff_read_control(ctl, p, ctl->len);
+ ret = wm_coeff_read_control(ctl, p, ctl->len);
else
- return -EPERM;
+ ret = -EPERM;
+ } else {
+ if (!ctl->flags && ctl->enabled)
+ ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+
+ memcpy(p, ctl->cache, ctl->len);
}
- memcpy(p, ctl->cache, ctl->len);
+ mutex_unlock(&ctl->dsp->pwr_lock);
- return 0;
+ return ret;
}
struct wmfw_ctl_work {
@@ -808,8 +987,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
break;
}
- list_for_each_entry(ctl, &dsp->ctl_list,
- list) {
+ list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (!strcmp(ctl->name, name)) {
if (!ctl->enabled)
ctl->enabled = 1;
@@ -1088,7 +1266,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
goto out_fw;
}
- header = (void*)&firmware->data[0];
+ header = (void *)&firmware->data[0];
if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
adsp_err(dsp, "%s: invalid magic\n", file);
@@ -1168,7 +1346,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
offset = le32_to_cpu(region->offset) & 0xffffff;
type = be32_to_cpu(region->type) & 0xff;
mem = wm_adsp_find_region(dsp, type);
-
+
switch (type) {
case WMFW_NAME_TEXT:
region_name = "Firmware name";
@@ -1333,6 +1511,19 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
return alg;
}
+static struct wm_adsp_alg_region *
+ wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
+{
+ struct wm_adsp_alg_region *alg_region;
+
+ list_for_each_entry(alg_region, &dsp->alg_regions, list) {
+ if (id == alg_region->alg && type == alg_region->type)
+ return alg_region;
+ }
+
+ return NULL;
+}
+
static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
int type, __be32 id,
__be32 base)
@@ -1625,7 +1816,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
goto out_fw;
}
- hdr = (void*)&firmware->data[0];
+ hdr = (void *)&firmware->data[0];
if (memcmp(hdr->magic, "WMDR", 4) != 0) {
adsp_err(dsp, "%s: invalid magic\n", file);
goto out_fw;
@@ -1651,7 +1842,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
blocks = 0;
while (pos < firmware->size &&
pos - firmware->size > sizeof(*blk)) {
- blk = (void*)(&firmware->data[pos]);
+ blk = (void *)(&firmware->data[pos]);
type = le16_to_cpu(blk->type);
offset = le16_to_cpu(blk->offset);
@@ -1705,22 +1896,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
break;
}
- reg = 0;
- list_for_each_entry(alg_region,
- &dsp->alg_regions, list) {
- if (le32_to_cpu(blk->id) == alg_region->alg &&
- type == alg_region->type) {
- reg = alg_region->base;
- reg = wm_adsp_region_to_reg(mem,
- reg);
- reg += offset;
- break;
- }
- }
-
- if (reg == 0)
+ alg_region = wm_adsp_find_alg_region(dsp, type,
+ le32_to_cpu(blk->id));
+ if (alg_region) {
+ reg = alg_region->base;
+ reg = wm_adsp_region_to_reg(mem, reg);
+ reg += offset;
+ } else {
adsp_err(dsp, "No %x for algorithm %x\n",
type, le32_to_cpu(blk->id));
+ }
break;
default:
@@ -1778,9 +1963,8 @@ int wm_adsp1_init(struct wm_adsp *dsp)
{
INIT_LIST_HEAD(&dsp->alg_regions);
-#ifdef CONFIG_DEBUG_FS
- mutex_init(&dsp->debugfs_lock);
-#endif
+ mutex_init(&dsp->pwr_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
@@ -1795,10 +1979,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct wm_adsp_alg_region *alg_region;
struct wm_coeff_ctl *ctl;
int ret;
- int val;
+ unsigned int val;
dsp->card = codec->component.card;
+ mutex_lock(&dsp->pwr_lock);
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1808,12 +1994,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
* For simplicity set the DSP clock rate to be the
* SYSCLK rate rather than making it configurable.
*/
- if(dsp->sysclk_reg) {
+ if (dsp->sysclk_reg) {
ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
if (ret != 0) {
adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
ret);
- return ret;
+ goto err_mutex;
}
val = (val & dsp->sysclk_mask)
@@ -1825,31 +2011,31 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
if (ret != 0) {
adsp_err(dsp, "Failed to set clock rate: %d\n",
ret);
- return ret;
+ goto err_mutex;
}
}
ret = wm_adsp_load(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
ret = wm_adsp1_setup_algs(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
ret = wm_adsp_load_coeff(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
/* Initialize caches for enabled and unset controls */
ret = wm_coeff_init_control_caches(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
/* Sync set controls */
ret = wm_coeff_sync_controls(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
/* Start the core running */
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1884,11 +2070,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
break;
}
+ mutex_unlock(&dsp->pwr_lock);
+
return 0;
-err:
+err_ena:
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
ADSP1_SYS_ENA, 0);
+err_mutex:
+ mutex_unlock(&dsp->pwr_lock);
+
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp1_event);
@@ -1934,6 +2125,8 @@ static void wm_adsp2_boot_work(struct work_struct *work)
int ret;
unsigned int val;
+ mutex_lock(&dsp->pwr_lock);
+
/*
* For simplicity set the DSP clock rate to be the
* SYSCLK rate rather than making it configurable.
@@ -1941,7 +2134,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
if (ret != 0) {
adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
- return;
+ goto err_mutex;
}
val = (val & ARIZONA_SYSCLK_FREQ_MASK)
>> ARIZONA_SYSCLK_FREQ_SHIFT;
@@ -1951,42 +2144,46 @@ static void wm_adsp2_boot_work(struct work_struct *work)
ADSP2_CLK_SEL_MASK, val);
if (ret != 0) {
adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
- return;
+ goto err_mutex;
}
ret = wm_adsp2_ena(dsp);
if (ret != 0)
- return;
+ goto err_mutex;
ret = wm_adsp_load(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
ret = wm_adsp2_setup_algs(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
ret = wm_adsp_load_coeff(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
/* Initialize caches for enabled and unset controls */
ret = wm_coeff_init_control_caches(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
/* Sync set controls */
ret = wm_coeff_sync_controls(dsp);
if (ret != 0)
- goto err;
+ goto err_ena;
dsp->running = true;
+ mutex_unlock(&dsp->pwr_lock);
+
return;
-err:
+err_ena:
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+err_mutex:
+ mutex_unlock(&dsp->pwr_lock);
}
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
@@ -2033,12 +2230,18 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
ADSP2_CORE_ENA | ADSP2_START);
if (ret != 0)
goto err;
+
+ if (wm_adsp_fw[dsp->fw].num_caps != 0)
+ ret = wm_adsp_buffer_init(dsp);
+
break;
case SND_SOC_DAPM_PRE_PMD:
/* Log firmware state, it can be useful for analysis */
wm_adsp2_show_fw_status(dsp);
+ mutex_lock(&dsp->pwr_lock);
+
wm_adsp_debugfs_clear(dsp);
dsp->fw_id = 0;
@@ -2065,6 +2268,11 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
kfree(alg_region);
}
+ if (wm_adsp_fw[dsp->fw].num_caps != 0)
+ wm_adsp_buffer_free(dsp);
+
+ mutex_unlock(&dsp->pwr_lock);
+
adsp_dbg(dsp, "Shutdown complete\n");
break;
@@ -2117,11 +2325,724 @@ int wm_adsp2_init(struct wm_adsp *dsp)
INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
-#ifdef CONFIG_DEBUG_FS
- mutex_init(&dsp->debugfs_lock);
-#endif
+ mutex_init(&dsp->pwr_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);
+int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
+{
+ struct wm_adsp_compr *compr;
+ int ret = 0;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ if (wm_adsp_fw[dsp->fw].num_caps == 0) {
+ adsp_err(dsp, "Firmware does not support compressed API\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
+ adsp_err(dsp, "Firmware does not support stream direction\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (dsp->compr) {
+ /* It is expect this limitation will be removed in future */
+ adsp_err(dsp, "Only a single stream supported per DSP\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ compr = kzalloc(sizeof(*compr), GFP_KERNEL);
+ if (!compr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ compr->dsp = dsp;
+ compr->stream = stream;
+
+ dsp->compr = compr;
+
+ stream->runtime->private_data = compr;
+
+out:
+ mutex_unlock(&dsp->pwr_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
+
+int wm_adsp_compr_free(struct snd_compr_stream *stream)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ struct wm_adsp *dsp = compr->dsp;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ dsp->compr = NULL;
+
+ kfree(compr->raw_buf);
+ kfree(compr);
+
+ mutex_unlock(&dsp->pwr_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
+
+static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ struct wm_adsp *dsp = compr->dsp;
+ const struct wm_adsp_fw_caps *caps;
+ const struct snd_codec_desc *desc;
+ int i, j;
+
+ if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
+ params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
+ params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
+ params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
+ params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
+ adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
+ params->buffer.fragment_size,
+ params->buffer.fragments);
+
+ return -EINVAL;
+ }
+
+ for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
+ caps = &wm_adsp_fw[dsp->fw].caps[i];
+ desc = &caps->desc;
+
+ if (caps->id != params->codec.id)
+ continue;
+
+ if (stream->direction == SND_COMPRESS_PLAYBACK) {
+ if (desc->max_ch < params->codec.ch_out)
+ continue;
+ } else {
+ if (desc->max_ch < params->codec.ch_in)
+ continue;
+ }
+
+ if (!(desc->formats & (1 << params->codec.format)))
+ continue;
+
+ for (j = 0; j < desc->num_sample_rates; ++j)
+ if (desc->sample_rates[j] == params->codec.sample_rate)
+ return 0;
+ }
+
+ adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
+ params->codec.id, params->codec.ch_in, params->codec.ch_out,
+ params->codec.sample_rate, params->codec.format);
+ return -EINVAL;
+}
+
+static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
+{
+ return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
+}
+
+int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ unsigned int size;
+ int ret;
+
+ ret = wm_adsp_compr_check_params(stream, params);
+ if (ret)
+ return ret;
+
+ compr->size = params->buffer;
+
+ adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
+ compr->size.fragment_size, compr->size.fragments);
+
+ size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
+ compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
+ if (!compr->raw_buf)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
+
+int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ int fw = compr->dsp->fw;
+ int i;
+
+ if (wm_adsp_fw[fw].caps) {
+ for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
+ caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
+
+ caps->num_codecs = i;
+ caps->direction = wm_adsp_fw[fw].compr_direction;
+
+ caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
+ caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
+ caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
+ caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
+
+static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
+ unsigned int mem_addr,
+ unsigned int num_words, u32 *data)
+{
+ struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+ unsigned int i, reg;
+ int ret;
+
+ if (!mem)
+ return -EINVAL;
+
+ reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+ ret = regmap_raw_read(dsp->regmap, reg, data,
+ sizeof(*data) * num_words);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num_words; ++i)
+ data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
+
+ return 0;
+}
+
+static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
+ unsigned int mem_addr, u32 *data)
+{
+ return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
+}
+
+static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
+ unsigned int mem_addr, u32 data)
+{
+ struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+ unsigned int reg;
+
+ if (!mem)
+ return -EINVAL;
+
+ reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+ data = cpu_to_be32(data & 0x00ffffffu);
+
+ return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
+}
+
+static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
+ unsigned int field_offset, u32 *data)
+{
+ return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM,
+ buf->host_buf_ptr + field_offset, data);
+}
+
+static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
+ unsigned int field_offset, u32 data)
+{
+ return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM,
+ buf->host_buf_ptr + field_offset, data);
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+ struct wm_adsp_alg_region *alg_region;
+ struct wm_adsp *dsp = buf->dsp;
+ u32 xmalg, addr, magic;
+ int i, ret;
+
+ alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+ xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32);
+
+ addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
+ ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
+ if (ret < 0)
+ return ret;
+
+ if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
+ return -EINVAL;
+
+ addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
+ for (i = 0; i < 5; ++i) {
+ ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
+ &buf->host_buf_ptr);
+ if (ret < 0)
+ return ret;
+
+ if (buf->host_buf_ptr)
+ break;
+
+ usleep_range(1000, 2000);
+ }
+
+ if (!buf->host_buf_ptr)
+ return -EIO;
+
+ adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+ return 0;
+}
+
+static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
+{
+ const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
+ struct wm_adsp_buffer_region *region;
+ u32 offset = 0;
+ int i, ret;
+
+ for (i = 0; i < caps->num_regions; ++i) {
+ region = &buf->regions[i];
+
+ region->offset = offset;
+ region->mem_type = caps->region_defs[i].mem_type;
+
+ ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
+ &region->base_addr);
+ if (ret < 0)
+ return ret;
+
+ ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
+ &offset);
+ if (ret < 0)
+ return ret;
+
+ region->cumulative_size = offset;
+
+ adsp_dbg(buf->dsp,
+ "region=%d type=%d base=%04x off=%04x size=%04x\n",
+ i, region->mem_type, region->base_addr,
+ region->offset, region->cumulative_size);
+ }
+
+ return 0;
+}
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp)
+{
+ struct wm_adsp_compr_buf *buf;
+ int ret;
+
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ buf->dsp = dsp;
+ buf->read_index = -1;
+ buf->irq_count = 0xFFFFFFFF;
+
+ ret = wm_adsp_buffer_locate(buf);
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret);
+ goto err_buffer;
+ }
+
+ buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions,
+ sizeof(*buf->regions), GFP_KERNEL);
+ if (!buf->regions) {
+ ret = -ENOMEM;
+ goto err_buffer;
+ }
+
+ ret = wm_adsp_buffer_populate(buf);
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to populate host buffer: %d\n", ret);
+ goto err_regions;
+ }
+
+ dsp->buffer = buf;
+
+ return 0;
+
+err_regions:
+ kfree(buf->regions);
+err_buffer:
+ kfree(buf);
+ return ret;
+}
+
+static int wm_adsp_buffer_free(struct wm_adsp *dsp)
+{
+ if (dsp->buffer) {
+ kfree(dsp->buffer->regions);
+ kfree(dsp->buffer);
+
+ dsp->buffer = NULL;
+ }
+
+ return 0;
+}
+
+static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
+{
+ return compr->buf != NULL;
+}
+
+static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
+{
+ /*
+ * Note this will be more complex once each DSP can support multiple
+ * streams
+ */
+ if (!compr->dsp->buffer)
+ return -EINVAL;
+
+ compr->buf = compr->dsp->buffer;
+
+ return 0;
+}
+
+int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ struct wm_adsp *dsp = compr->dsp;
+ int ret = 0;
+
+ adsp_dbg(dsp, "Trigger: %d\n", cmd);
+
+ mutex_lock(&dsp->pwr_lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (wm_adsp_compr_attached(compr))
+ break;
+
+ ret = wm_adsp_compr_attach(compr);
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to link buffer and stream: %d\n",
+ ret);
+ break;
+ }
+
+ /* Trigger the IRQ at one fragment of data */
+ ret = wm_adsp_buffer_write(compr->buf,
+ HOST_BUFFER_FIELD(high_water_mark),
+ wm_adsp_compr_frag_words(compr));
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to set high water mark: %d\n",
+ ret);
+ break;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&dsp->pwr_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
+
+static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
+{
+ int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
+
+ return buf->regions[last_region].cumulative_size;
+}
+
+static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
+{
+ u32 next_read_index, next_write_index;
+ int write_index, read_index, avail;
+ int ret;
+
+ /* Only sync read index if we haven't already read a valid index */
+ if (buf->read_index < 0) {
+ ret = wm_adsp_buffer_read(buf,
+ HOST_BUFFER_FIELD(next_read_index),
+ &next_read_index);
+ if (ret < 0)
+ return ret;
+
+ read_index = sign_extend32(next_read_index, 23);
+
+ if (read_index < 0) {
+ adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
+ return 0;
+ }
+
+ buf->read_index = read_index;
+ }
+
+ ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
+ &next_write_index);
+ if (ret < 0)
+ return ret;
+
+ write_index = sign_extend32(next_write_index, 23);
+
+ avail = write_index - buf->read_index;
+ if (avail < 0)
+ avail += wm_adsp_buffer_size(buf);
+
+ adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
+ buf->read_index, write_index, avail);
+
+ buf->avail = avail;
+
+ return 0;
+}
+
+int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
+{
+ struct wm_adsp_compr_buf *buf = dsp->buffer;
+ struct wm_adsp_compr *compr = dsp->compr;
+ int ret = 0;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ if (!buf) {
+ adsp_err(dsp, "Spurious buffer IRQ\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ adsp_dbg(dsp, "Handling buffer IRQ\n");
+
+ ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to check buffer error: %d\n", ret);
+ goto out;
+ }
+ if (buf->error != 0) {
+ adsp_err(dsp, "Buffer error occurred: %d\n", buf->error);
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
+ &buf->irq_count);
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
+ goto out;
+ }
+
+ ret = wm_adsp_buffer_update_avail(buf);
+ if (ret < 0) {
+ adsp_err(dsp, "Error reading avail: %d\n", ret);
+ goto out;
+ }
+
+ if (compr->stream)
+ snd_compr_fragment_elapsed(compr->stream);
+
+out:
+ mutex_unlock(&dsp->pwr_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
+
+static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
+{
+ if (buf->irq_count & 0x01)
+ return 0;
+
+ adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
+ buf->irq_count);
+
+ buf->irq_count |= 0x01;
+
+ return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
+ buf->irq_count);
+}
+
+int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ struct wm_adsp_compr_buf *buf = compr->buf;
+ struct wm_adsp *dsp = compr->dsp;
+ int ret = 0;
+
+ adsp_dbg(dsp, "Pointer request\n");
+
+ mutex_lock(&dsp->pwr_lock);
+
+ if (!compr->buf) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (compr->buf->error) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+ ret = wm_adsp_buffer_update_avail(buf);
+ if (ret < 0) {
+ adsp_err(dsp, "Error reading avail: %d\n", ret);
+ goto out;
+ }
+
+ /*
+ * If we really have less than 1 fragment available tell the
+ * DSP to inform us once a whole fragment is available.
+ */
+ if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+ ret = wm_adsp_buffer_reenable_irq(buf);
+ if (ret < 0) {
+ adsp_err(dsp,
+ "Failed to re-enable buffer IRQ: %d\n",
+ ret);
+ goto out;
+ }
+ }
+ }
+
+ tstamp->copied_total = compr->copied_total;
+ tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
+
+out:
+ mutex_unlock(&dsp->pwr_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
+
+static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
+{
+ struct wm_adsp_compr_buf *buf = compr->buf;
+ u8 *pack_in = (u8 *)compr->raw_buf;
+ u8 *pack_out = (u8 *)compr->raw_buf;
+ unsigned int adsp_addr;
+ int mem_type, nwords, max_read;
+ int i, j, ret;
+
+ /* Calculate read parameters */
+ for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
+ if (buf->read_index < buf->regions[i].cumulative_size)
+ break;
+
+ if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
+ return -EINVAL;
+
+ mem_type = buf->regions[i].mem_type;
+ adsp_addr = buf->regions[i].base_addr +
+ (buf->read_index - buf->regions[i].offset);
+
+ max_read = wm_adsp_compr_frag_words(compr);
+ nwords = buf->regions[i].cumulative_size - buf->read_index;
+
+ if (nwords > target)
+ nwords = target;
+ if (nwords > buf->avail)
+ nwords = buf->avail;
+ if (nwords > max_read)
+ nwords = max_read;
+ if (!nwords)
+ return 0;
+
+ /* Read data from DSP */
+ ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
+ nwords, compr->raw_buf);
+ if (ret < 0)
+ return ret;
+
+ /* Remove the padding bytes from the data read from the DSP */
+ for (i = 0; i < nwords; i++) {
+ for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
+ *pack_out++ = *pack_in++;
+
+ pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
+ }
+
+ /* update read index to account for words read */
+ buf->read_index += nwords;
+ if (buf->read_index == wm_adsp_buffer_size(buf))
+ buf->read_index = 0;
+
+ ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
+ buf->read_index);
+ if (ret < 0)
+ return ret;
+
+ /* update avail to account for words read */
+ buf->avail -= nwords;
+
+ return nwords;
+}
+
+static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
+ char __user *buf, size_t count)
+{
+ struct wm_adsp *dsp = compr->dsp;
+ int ntotal = 0;
+ int nwords, nbytes;
+
+ adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
+
+ if (!compr->buf)
+ return -ENXIO;
+
+ if (compr->buf->error)
+ return -EIO;
+
+ count /= WM_ADSP_DATA_WORD_SIZE;
+
+ do {
+ nwords = wm_adsp_buffer_capture_block(compr, count);
+ if (nwords < 0) {
+ adsp_err(dsp, "Failed to capture block: %d\n", nwords);
+ return nwords;
+ }
+
+ nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
+
+ adsp_dbg(dsp, "Read %d bytes\n", nbytes);
+
+ if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
+ adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
+ ntotal, nbytes);
+ return -EFAULT;
+ }
+
+ count -= nwords;
+ ntotal += nbytes;
+ } while (nwords > 0 && count > 0);
+
+ compr->copied_total += ntotal;
+
+ return ntotal;
+}
+
+int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
+ size_t count)
+{
+ struct wm_adsp_compr *compr = stream->runtime->private_data;
+ struct wm_adsp *dsp = compr->dsp;
+ int ret;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ if (stream->direction == SND_COMPRESS_CAPTURE)
+ ret = wm_adsp_compr_read(compr, buf, count);
+ else
+ ret = -ENOTSUPP;
+
+ mutex_unlock(&dsp->pwr_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
+
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 2d117cf0e953..1a928ec54741 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -15,6 +15,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <sound/compress_driver.h>
#include "wmfw.h"
@@ -30,6 +31,9 @@ struct wm_adsp_alg_region {
unsigned int base;
};
+struct wm_adsp_compr;
+struct wm_adsp_compr_buf;
+
struct wm_adsp {
const char *part;
int num;
@@ -45,8 +49,8 @@ struct wm_adsp {
struct list_head alg_regions;
- int fw_id;
- int fw_id_version;
+ unsigned int fw_id;
+ unsigned int fw_id_version;
const struct wm_adsp_region *mem;
int num_mems;
@@ -59,9 +63,13 @@ struct wm_adsp {
struct work_struct boot_work;
+ struct wm_adsp_compr *compr;
+ struct wm_adsp_compr_buf *buffer;
+
+ struct mutex pwr_lock;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
- struct mutex debugfs_lock;
char *wmfw_file_name;
char *bin_file_name;
#endif
@@ -96,4 +104,18 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
+extern int wm_adsp_compr_open(struct wm_adsp *dsp,
+ struct snd_compr_stream *stream);
+extern int wm_adsp_compr_free(struct snd_compr_stream *stream);
+extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params);
+extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps);
+extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
+extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
+extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp);
+extern int wm_adsp_compr_copy(struct snd_compr_stream *stream,
+ char __user *buf, size_t count);
+
#endif
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 6e6a70c5c2bd..ce664c239be3 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <sound/designware_i2s.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -93,7 +94,12 @@ struct dw_i2s_dev {
struct clk *clk;
int active;
unsigned int capability;
+ unsigned int quirks;
+ unsigned int i2s_reg_comp1;
+ unsigned int i2s_reg_comp2;
struct device *dev;
+ u32 ccr;
+ u32 xfer_resolution;
/* data related to DMA transfers b/w i2s and DMAC */
union dw_i2s_snd_dma_data play_dma_data;
@@ -213,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
return 0;
}
+static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
+{
+ u32 ch_reg, irq;
+ struct i2s_clk_config_data *config = &dev->config;
+
+
+ i2s_disable_channels(dev, stream);
+
+ for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ i2s_write_reg(dev->i2s_base, TCR(ch_reg),
+ dev->xfer_resolution);
+ i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
+ irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+ i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
+ i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+ } else {
+ i2s_write_reg(dev->i2s_base, RCR(ch_reg),
+ dev->xfer_resolution);
+ i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
+ irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+ i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
+ i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+ }
+
+ }
+}
+
static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
struct i2s_clk_config_data *config = &dev->config;
- u32 ccr, xfer_resolution, ch_reg, irq;
int ret;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
config->data_width = 16;
- ccr = 0x00;
- xfer_resolution = 0x02;
+ dev->ccr = 0x00;
+ dev->xfer_resolution = 0x02;
break;
case SNDRV_PCM_FORMAT_S24_LE:
config->data_width = 24;
- ccr = 0x08;
- xfer_resolution = 0x04;
+ dev->ccr = 0x08;
+ dev->xfer_resolution = 0x04;
break;
case SNDRV_PCM_FORMAT_S32_LE:
config->data_width = 32;
- ccr = 0x10;
- xfer_resolution = 0x05;
+ dev->ccr = 0x10;
+ dev->xfer_resolution = 0x05;
break;
default:
@@ -258,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- i2s_disable_channels(dev, substream->stream);
-
- for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- i2s_write_reg(dev->i2s_base, TCR(ch_reg),
- xfer_resolution);
- i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
- irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
- i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
- i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
- } else {
- i2s_write_reg(dev->i2s_base, RCR(ch_reg),
- xfer_resolution);
- i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
- irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
- i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
- i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
- }
- }
+ dw_i2s_config(dev, substream->stream);
- i2s_write_reg(dev->i2s_base, CCR, ccr);
+ i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
config->sample_rate = params_rate(params);
@@ -394,6 +409,23 @@ static const struct snd_soc_component_driver dw_i2s_component = {
};
#ifdef CONFIG_PM
+static int dw_i2s_runtime_suspend(struct device *dev)
+{
+ struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+
+ if (dw_dev->capability & DW_I2S_MASTER)
+ clk_disable(dw_dev->clk);
+ return 0;
+}
+
+static int dw_i2s_runtime_resume(struct device *dev)
+{
+ struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+
+ if (dw_dev->capability & DW_I2S_MASTER)
+ clk_enable(dw_dev->clk);
+ return 0;
+}
static int dw_i2s_suspend(struct snd_soc_dai *dai)
{
@@ -410,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
if (dev->capability & DW_I2S_MASTER)
clk_enable(dev->clk);
+
+ if (dai->playback_active)
+ dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
+ if (dai->capture_active)
+ dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
return 0;
}
@@ -459,10 +496,14 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,
* Read component parameter registers to extract
* the I2S block's configuration.
*/
- u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
- u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+ u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
+ u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2);
u32 idx;
+ if (dev->capability & DWC_I2S_RECORD &&
+ dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
+ comp1 = comp1 & ~BIT(5);
+
if (COMP1_TX_ENABLED(comp1)) {
dev_dbg(dev->dev, " designware: play supported\n");
idx = COMP1_TX_WORDSIZE_0(comp1);
@@ -503,7 +544,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
struct resource *res,
const struct i2s_platform_data *pdata)
{
- u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+ u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
u32 idx = COMP1_APB_DATA_WIDTH(comp1);
int ret;
@@ -607,6 +648,14 @@ static int dw_i2s_probe(struct platform_device *pdev)
if (pdata) {
dev->capability = pdata->cap;
clk_id = NULL;
+ dev->quirks = pdata->quirks;
+ if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
+ dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
+ dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
+ } else {
+ dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
+ dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
+ }
ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
} else {
clk_id = "i2sclk";
@@ -649,7 +698,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
goto err_clk_disable;
}
}
-
+ pm_runtime_enable(&pdev->dev);
return 0;
err_clk_disable:
@@ -665,6 +714,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
if (dev->capability & DW_I2S_MASTER)
clk_disable_unprepare(dev->clk);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
@@ -677,12 +727,17 @@ static const struct of_device_id dw_i2s_of_match[] = {
MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
#endif
+static const struct dev_pm_ops dwc_pm_ops = {
+ SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
+};
+
static struct platform_driver dw_i2s_driver = {
.probe = dw_i2s_probe,
.remove = dw_i2s_remove,
.driver = {
.name = "designware-i2s",
.of_match_table = of_match_ptr(dw_i2s_of_match),
+ .pm = &dwc_pm_ops,
},
};
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 1b05d1c5d9fd..562b3bd22d9a 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -107,6 +107,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"CPU-Capture", NULL, "Capture"},
};
+static const struct snd_soc_dapm_route audio_map_ac97[] = {
+ {"AC97 Playback", NULL, "ASRC-Playback"},
+ {"Playback", NULL, "AC97 Playback"},
+ {"ASRC-Capture", NULL, "AC97 Capture"},
+ {"AC97 Capture", NULL, "Capture"},
+};
+
/* Add all possible widgets into here without being redundant */
static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Line Out Jack", NULL),
@@ -222,12 +229,15 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
enum snd_soc_bias_level level)
{
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
struct codec_priv *codec_priv = &priv->codec_priv;
struct device *dev = card->dev;
unsigned int pll_out;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
return 0;
@@ -414,14 +424,16 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
{
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd = list_first_entry(
+ &card->rtd_list, struct snd_soc_pcm_runtime, list);
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct codec_priv *codec_priv = &priv->codec_priv;
struct device *dev = card->dev;
int ret;
if (fsl_asoc_card_is_ac97(priv)) {
#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
- struct snd_soc_codec *codec = card->rtd[0].codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
/*
@@ -574,7 +586,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->card.dev = &pdev->dev;
priv->card.name = priv->name;
priv->card.dai_link = priv->dai_link;
- priv->card.dapm_routes = audio_map;
+ priv->card.dapm_routes = fsl_asoc_card_is_ac97(priv) ?
+ audio_map_ac97 : audio_map;
priv->card.late_probe = fsl_asoc_card_late_probe;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 9f087d4f73ed..c1a0e01cb8e7 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -31,21 +31,21 @@
dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
/* Sample rates are aligned with that defined in pcm.h file */
-static const u8 process_option[][8][2] = {
- /* 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */
- {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */
- {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */
- {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */
- {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */
- {{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */
- {{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */
- {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */
- {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */
- {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */
- {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */
+static const u8 process_option[][12][2] = {
+ /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */
+ {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */
+ {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */
+ {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */
+ {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */
+ {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */
+ {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */
+ {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */
+ {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */
+ {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */
+ {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */
+ {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */
+ {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */
+ {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */
};
/* Corresponding to process_option */
@@ -55,7 +55,7 @@ static int supported_input_rate[] = {
};
static int supported_asrc_rate[] = {
- 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
};
/**
@@ -286,6 +286,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
return -EINVAL;
}
+ if ((outrate > 8000 && outrate < 30000) &&
+ (outrate/inrate > 24 || inrate/outrate > 8)) {
+ pair_err("exceed supported ratio range [1/24, 8] for \
+ inrate/outrate: %d/%d\n", inrate, outrate);
+ return -EINVAL;
+ }
+
/* Validate input and output clock sources */
clk_index[IN] = clk_map[IN][config->inclk];
clk_index[OUT] = clk_map[OUT][config->outclk];
@@ -447,7 +454,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
- int width = snd_pcm_format_width(params_format(params));
+ int width = params_width(params);
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
unsigned int channels = params_channels(params);
@@ -859,6 +866,10 @@ static int fsl_asrc_probe(struct platform_device *pdev)
return PTR_ERR(asrc_priv->ipg_clk);
}
+ asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba");
+ if (IS_ERR(asrc_priv->spba_clk))
+ dev_warn(&pdev->dev, "failed to get spba clock\n");
+
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
sprintf(tmp, "asrck_%x", i);
asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
@@ -939,6 +950,11 @@ static int fsl_asrc_runtime_resume(struct device *dev)
ret = clk_prepare_enable(asrc_priv->ipg_clk);
if (ret)
goto disable_mem_clk;
+ if (!IS_ERR(asrc_priv->spba_clk)) {
+ ret = clk_prepare_enable(asrc_priv->spba_clk);
+ if (ret)
+ goto disable_ipg_clk;
+ }
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
if (ret)
@@ -950,6 +966,9 @@ static int fsl_asrc_runtime_resume(struct device *dev)
disable_asrck_clk:
for (i--; i >= 0; i--)
clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+ if (!IS_ERR(asrc_priv->spba_clk))
+ clk_disable_unprepare(asrc_priv->spba_clk);
+disable_ipg_clk:
clk_disable_unprepare(asrc_priv->ipg_clk);
disable_mem_clk:
clk_disable_unprepare(asrc_priv->mem_clk);
@@ -963,6 +982,8 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+ if (!IS_ERR(asrc_priv->spba_clk))
+ clk_disable_unprepare(asrc_priv->spba_clk);
clk_disable_unprepare(asrc_priv->ipg_clk);
clk_disable_unprepare(asrc_priv->mem_clk);
@@ -975,6 +996,9 @@ static int fsl_asrc_suspend(struct device *dev)
{
struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+ regmap_read(asrc_priv->regmap, REG_ASRCFG,
+ &asrc_priv->regcache_cfg);
+
regcache_cache_only(asrc_priv->regmap, true);
regcache_mark_dirty(asrc_priv->regmap);
@@ -995,6 +1019,10 @@ static int fsl_asrc_resume(struct device *dev)
regcache_cache_only(asrc_priv->regmap, false);
regcache_sync(asrc_priv->regmap);
+ regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+ ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
+ ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
+
/* Restart enabled pairs */
regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_ALL_MASK, asrctr);
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 4aed63c4b431..0f163abe4ba3 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -132,10 +132,13 @@
#define ASRCFG_INIRQi (1 << ASRCFG_INIRQi_SHIFT(i))
#define ASRCFG_NDPRi_SHIFT(i) (18 + i)
#define ASRCFG_NDPRi_MASK(i) (1 << ASRCFG_NDPRi_SHIFT(i))
+#define ASRCFG_NDPRi_ALL_SHIFT 18
+#define ASRCFG_NDPRi_ALL_MASK (7 << ASRCFG_NDPRi_ALL_SHIFT)
#define ASRCFG_NDPRi (1 << ASRCFG_NDPRi_SHIFT(i))
#define ASRCFG_POSTMODi_SHIFT(i) (8 + (i << 2))
#define ASRCFG_POSTMODi_WIDTH 2
#define ASRCFG_POSTMODi_MASK(i) (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i))
+#define ASRCFG_POSTMODi_ALL_MASK (ASRCFG_POSTMODi_MASK(0) | ASRCFG_POSTMODi_MASK(1) | ASRCFG_POSTMODi_MASK(2))
#define ASRCFG_POSTMOD(i, v) ((v) << ASRCFG_POSTMODi_SHIFT(i))
#define ASRCFG_POSTMODi_UP(i) (0 << ASRCFG_POSTMODi_SHIFT(i))
#define ASRCFG_POSTMODi_DCON(i) (1 << ASRCFG_POSTMODi_SHIFT(i))
@@ -143,6 +146,7 @@
#define ASRCFG_PREMODi_SHIFT(i) (6 + (i << 2))
#define ASRCFG_PREMODi_WIDTH 2
#define ASRCFG_PREMODi_MASK(i) (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i))
+#define ASRCFG_PREMODi_ALL_MASK (ASRCFG_PREMODi_MASK(0) | ASRCFG_PREMODi_MASK(1) | ASRCFG_PREMODi_MASK(2))
#define ASRCFG_PREMOD(i, v) ((v) << ASRCFG_PREMODi_SHIFT(i))
#define ASRCFG_PREMODi_UP(i) (0 << ASRCFG_PREMODi_SHIFT(i))
#define ASRCFG_PREMODi_DCON(i) (1 << ASRCFG_PREMODi_SHIFT(i))
@@ -426,6 +430,7 @@ struct fsl_asrc_pair {
* @paddr: physical address to the base address of registers
* @mem_clk: clock source to access register
* @ipg_clk: clock source to drive peripheral
+ * @spba_clk: SPBA clock (optional, depending on SoC design)
* @asrck_clk: clock sources to driver ASRC internal logic
* @lock: spin lock for resource protection
* @pair: pair pointers
@@ -433,6 +438,7 @@ struct fsl_asrc_pair {
* @channel_avail: non-occupied channel numbers
* @asrc_rate: default sample rate for ASoC Back-Ends
* @asrc_width: default sample width for ASoC Back-Ends
+ * @regcache_cfg: store register value of REG_ASRCFG
*/
struct fsl_asrc {
struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -442,6 +448,7 @@ struct fsl_asrc {
unsigned long paddr;
struct clk *mem_clk;
struct clk *ipg_clk;
+ struct clk *spba_clk;
struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
spinlock_t lock;
@@ -451,6 +458,8 @@ struct fsl_asrc {
int asrc_rate;
int asrc_width;
+
+ u32 regcache_cfg;
};
extern struct snd_soc_platform_driver fsl_asrc_platform;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 59f234e51971..26a90e12ede4 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -35,6 +35,7 @@
* @coreclk: clock source to access register
* @extalclk: esai clock source to derive HCK, SCK and FS
* @fsysclk: system clock source to derive HCK, SCK and FS
+ * @spbaclk: SPBA clock (optional, depending on SoC design)
* @fifo_depth: depth of tx/rx FIFO
* @slot_width: width of each DAI slot
* @slots: number of slots
@@ -54,6 +55,7 @@ struct fsl_esai {
struct clk *coreclk;
struct clk *extalclk;
struct clk *fsysclk;
+ struct clk *spbaclk;
u32 fifo_depth;
u32 slot_width;
u32 slots;
@@ -469,6 +471,11 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
ret = clk_prepare_enable(esai_priv->coreclk);
if (ret)
return ret;
+ if (!IS_ERR(esai_priv->spbaclk)) {
+ ret = clk_prepare_enable(esai_priv->spbaclk);
+ if (ret)
+ goto err_spbaclk;
+ }
if (!IS_ERR(esai_priv->extalclk)) {
ret = clk_prepare_enable(esai_priv->extalclk);
if (ret)
@@ -499,6 +506,9 @@ err_fsysclk:
if (!IS_ERR(esai_priv->extalclk))
clk_disable_unprepare(esai_priv->extalclk);
err_extalck:
+ if (!IS_ERR(esai_priv->spbaclk))
+ clk_disable_unprepare(esai_priv->spbaclk);
+err_spbaclk:
clk_disable_unprepare(esai_priv->coreclk);
return ret;
@@ -510,7 +520,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- u32 width = snd_pcm_format_width(params_format(params));
+ u32 width = params_width(params);
u32 channels = params_channels(params);
u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
u32 slot_width = width;
@@ -564,6 +574,8 @@ static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
clk_disable_unprepare(esai_priv->fsysclk);
if (!IS_ERR(esai_priv->extalclk))
clk_disable_unprepare(esai_priv->extalclk);
+ if (!IS_ERR(esai_priv->spbaclk))
+ clk_disable_unprepare(esai_priv->spbaclk);
clk_disable_unprepare(esai_priv->coreclk);
}
@@ -653,21 +665,28 @@ static const struct snd_soc_component_driver fsl_esai_component = {
};
static const struct reg_default fsl_esai_reg_defaults[] = {
- {0x8, 0x00000000},
- {0x10, 0x00000000},
- {0x18, 0x00000000},
- {0x98, 0x00000000},
- {0xd0, 0x00000000},
- {0xd4, 0x00000000},
- {0xd8, 0x00000000},
- {0xdc, 0x00000000},
- {0xe0, 0x00000000},
- {0xe4, 0x0000ffff},
- {0xe8, 0x0000ffff},
- {0xec, 0x0000ffff},
- {0xf0, 0x0000ffff},
- {0xf8, 0x00000000},
- {0xfc, 0x00000000},
+ {REG_ESAI_ETDR, 0x00000000},
+ {REG_ESAI_ECR, 0x00000000},
+ {REG_ESAI_TFCR, 0x00000000},
+ {REG_ESAI_RFCR, 0x00000000},
+ {REG_ESAI_TX0, 0x00000000},
+ {REG_ESAI_TX1, 0x00000000},
+ {REG_ESAI_TX2, 0x00000000},
+ {REG_ESAI_TX3, 0x00000000},
+ {REG_ESAI_TX4, 0x00000000},
+ {REG_ESAI_TX5, 0x00000000},
+ {REG_ESAI_TSR, 0x00000000},
+ {REG_ESAI_SAICR, 0x00000000},
+ {REG_ESAI_TCR, 0x00000000},
+ {REG_ESAI_TCCR, 0x00000000},
+ {REG_ESAI_RCR, 0x00000000},
+ {REG_ESAI_RCCR, 0x00000000},
+ {REG_ESAI_TSMA, 0x0000ffff},
+ {REG_ESAI_TSMB, 0x0000ffff},
+ {REG_ESAI_RSMA, 0x0000ffff},
+ {REG_ESAI_RSMB, 0x0000ffff},
+ {REG_ESAI_PRRC, 0x00000000},
+ {REG_ESAI_PCRC, 0x00000000},
};
static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
@@ -705,17 +724,10 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case REG_ESAI_ETDR:
case REG_ESAI_ERDR:
case REG_ESAI_ESR:
case REG_ESAI_TFSR:
case REG_ESAI_RFSR:
- case REG_ESAI_TX0:
- case REG_ESAI_TX1:
- case REG_ESAI_TX2:
- case REG_ESAI_TX3:
- case REG_ESAI_TX4:
- case REG_ESAI_TX5:
case REG_ESAI_RX0:
case REG_ESAI_RX1:
case REG_ESAI_RX2:
@@ -819,6 +831,11 @@ static int fsl_esai_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
PTR_ERR(esai_priv->fsysclk));
+ esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
+ if (IS_ERR(esai_priv->spbaclk))
+ dev_warn(&pdev->dev, "failed to get spba clock: %ld\n",
+ PTR_ERR(esai_priv->spbaclk));
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 08b460ba06ef..fef264d27fd3 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -126,6 +126,17 @@ out:
return IRQ_HANDLED;
}
+static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ sai->slots = slots;
+ sai->slot_width = slot_width;
+
+ return 0;
+}
+
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int fsl_dir)
{
@@ -354,13 +365,25 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
return -EINVAL;
}
- if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) {
+ /*
+ * 1) For Asynchronous mode, we must set RCR2 register for capture, and
+ * set TCR2 register for playback.
+ * 2) For Tx sync with Rx clock, we must set RCR2 register for playback
+ * and capture.
+ * 3) For Rx sync with Tx clock, we must set TCR2 register for playback
+ * and capture.
+ * 4) For Tx and Rx are both Synchronous with another SAI, we just
+ * ignore it.
+ */
+ if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
+ (!tx && !sai->synchronous[RX])) {
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
FSL_SAI_CR2_MSEL_MASK,
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
FSL_SAI_CR2_DIV_MASK, savediv - 1);
- } else {
+ } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
+ (tx && !sai->synchronous[TX])) {
regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
FSL_SAI_CR2_MSEL_MASK,
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
@@ -381,13 +404,21 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int channels = params_channels(params);
- u32 word_width = snd_pcm_format_width(params_format(params));
+ u32 word_width = params_width(params);
u32 val_cr4 = 0, val_cr5 = 0;
+ u32 slots = (channels == 1) ? 2 : channels;
+ u32 slot_width = word_width;
int ret;
+ if (sai->slots)
+ slots = sai->slots;
+
+ if (sai->slot_width)
+ slot_width = sai->slot_width;
+
if (!sai->is_slave_mode) {
ret = fsl_sai_set_bclk(cpu_dai, tx,
- 2 * word_width * params_rate(params));
+ slots * slot_width * params_rate(params));
if (ret)
return ret;
@@ -399,21 +430,49 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
sai->mclk_streams |= BIT(substream->stream);
}
-
}
if (!sai->is_dsp_mode)
- val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+ val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
- val_cr5 |= FSL_SAI_CR5_WNW(word_width);
- val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+ val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
+ val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
if (sai->is_lsb_first)
val_cr5 |= FSL_SAI_CR5_FBT(0);
else
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
- val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
+ val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
+
+ /*
+ * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
+ * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
+ * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
+ * error.
+ */
+
+ if (!sai->is_slave_mode) {
+ if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+ val_cr4);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+ FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+ FSL_SAI_CR5_FBT_MASK, val_cr5);
+ regmap_write(sai->regmap, FSL_SAI_TMR,
+ ~0UL - ((1 << channels) - 1));
+ } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+ val_cr4);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
+ FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+ FSL_SAI_CR5_FBT_MASK, val_cr5);
+ regmap_write(sai->regmap, FSL_SAI_RMR,
+ ~0UL - ((1 << channels) - 1));
+ }
+ }
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
@@ -569,6 +628,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
.set_sysclk = fsl_sai_set_dai_sysclk,
.set_fmt = fsl_sai_set_dai_fmt,
+ .set_tdm_slot = fsl_sai_set_dai_tdm_slot,
.hw_params = fsl_sai_hw_params,
.hw_free = fsl_sai_hw_free,
.trigger = fsl_sai_trigger,
@@ -627,6 +687,22 @@ static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-sai",
};
+static struct reg_default fsl_sai_reg_defaults[] = {
+ {FSL_SAI_TCR1, 0},
+ {FSL_SAI_TCR2, 0},
+ {FSL_SAI_TCR3, 0},
+ {FSL_SAI_TCR4, 0},
+ {FSL_SAI_TCR5, 0},
+ {FSL_SAI_TDR, 0},
+ {FSL_SAI_TMR, 0},
+ {FSL_SAI_RCR1, 0},
+ {FSL_SAI_RCR2, 0},
+ {FSL_SAI_RCR3, 0},
+ {FSL_SAI_RCR4, 0},
+ {FSL_SAI_RCR5, 0},
+ {FSL_SAI_RMR, 0},
+};
+
static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -660,13 +736,11 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
case FSL_SAI_RCSR:
case FSL_SAI_TFR:
case FSL_SAI_RFR:
- case FSL_SAI_TDR:
case FSL_SAI_RDR:
return true;
default:
return false;
}
-
}
static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
@@ -699,6 +773,8 @@ static const struct regmap_config fsl_sai_regmap_config = {
.val_bits = 32,
.max_register = FSL_SAI_RMR,
+ .reg_defaults = fsl_sai_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults),
.readable_reg = fsl_sai_readable_reg,
.volatile_reg = fsl_sai_volatile_reg,
.writeable_reg = fsl_sai_writeable_reg,
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index b95fbc3f68eb..d9ed7be8cb34 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -143,6 +143,9 @@ struct fsl_sai {
unsigned int mclk_id[2];
unsigned int mclk_streams;
+ unsigned int slots;
+ unsigned int slot_width;
+
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
};
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 3d59bb6719f2..151849f79863 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -88,6 +88,7 @@ struct spdif_mixer_control {
* @rxclk: rx clock sources for capture
* @coreclk: core clock for register access via DMA
* @sysclk: system clock for rx clock rate measurement
+ * @spbaclk: SPBA clock (optional, depending on SoC design)
* @dma_params_tx: DMA parameters for transmit channel
* @dma_params_rx: DMA parameters for receive channel
*/
@@ -106,6 +107,7 @@ struct fsl_spdif_priv {
struct clk *rxclk;
struct clk *coreclk;
struct clk *sysclk;
+ struct clk *spbaclk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
/* regcache for SRPC */
@@ -474,6 +476,14 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
return ret;
}
+ if (!IS_ERR(spdif_priv->spbaclk)) {
+ ret = clk_prepare_enable(spdif_priv->spbaclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable spba clock\n");
+ goto err_spbaclk;
+ }
+ }
+
ret = spdif_softreset(spdif_priv);
if (ret) {
dev_err(&pdev->dev, "failed to soft reset\n");
@@ -515,6 +525,9 @@ disable_txclk:
for (i--; i >= 0; i--)
clk_disable_unprepare(spdif_priv->txclk[i]);
err:
+ if (!IS_ERR(spdif_priv->spbaclk))
+ clk_disable_unprepare(spdif_priv->spbaclk);
+err_spbaclk:
clk_disable_unprepare(spdif_priv->coreclk);
return ret;
@@ -548,6 +561,8 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
spdif_intr_status_clear(spdif_priv);
regmap_update_bits(regmap, REG_SPDIF_SCR,
SCR_LOW_POWER, SCR_LOW_POWER);
+ if (!IS_ERR(spdif_priv->spbaclk))
+ clk_disable_unprepare(spdif_priv->spbaclk);
clk_disable_unprepare(spdif_priv->coreclk);
}
}
@@ -1006,12 +1021,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = {
/* FSL SPDIF REGMAP */
static const struct reg_default fsl_spdif_reg_defaults[] = {
- {0x0, 0x00000400},
- {0x4, 0x00000000},
- {0xc, 0x00000000},
- {0x34, 0x00000000},
- {0x38, 0x00000000},
- {0x50, 0x00020f00},
+ {REG_SPDIF_SCR, 0x00000400},
+ {REG_SPDIF_SRCD, 0x00000000},
+ {REG_SPDIF_SIE, 0x00000000},
+ {REG_SPDIF_STL, 0x00000000},
+ {REG_SPDIF_STR, 0x00000000},
+ {REG_SPDIF_STCSCH, 0x00000000},
+ {REG_SPDIF_STCSCL, 0x00000000},
+ {REG_SPDIF_STC, 0x00020f00},
};
static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
@@ -1049,8 +1066,6 @@ static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
case REG_SPDIF_SRCSL:
case REG_SPDIF_SRU:
case REG_SPDIF_SRQ:
- case REG_SPDIF_STL:
- case REG_SPDIF_STR:
case REG_SPDIF_SRFM:
return true;
default:
@@ -1261,6 +1276,10 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return PTR_ERR(spdif_priv->coreclk);
}
+ spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
+ if (IS_ERR(spdif_priv->spbaclk))
+ dev_warn(&pdev->dev, "no spba clock in devicetree\n");
+
/* Select clock source for rx/tx clock */
spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
if (IS_ERR(spdif_priv->rxclk)) {
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 95d2392303eb..40dfd8a36484 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -113,17 +113,17 @@ struct fsl_ssi_rxtx_reg_val {
};
static const struct reg_default fsl_ssi_reg_defaults[] = {
- {0x10, 0x00000000},
- {0x18, 0x00003003},
- {0x1c, 0x00000200},
- {0x20, 0x00000200},
- {0x24, 0x00040000},
- {0x28, 0x00040000},
- {0x38, 0x00000000},
- {0x48, 0x00000000},
- {0x4c, 0x00000000},
- {0x54, 0x00000000},
- {0x58, 0x00000000},
+ {CCSR_SSI_SCR, 0x00000000},
+ {CCSR_SSI_SIER, 0x00003003},
+ {CCSR_SSI_STCR, 0x00000200},
+ {CCSR_SSI_SRCR, 0x00000200},
+ {CCSR_SSI_STCCR, 0x00040000},
+ {CCSR_SSI_SRCCR, 0x00040000},
+ {CCSR_SSI_SACNT, 0x00000000},
+ {CCSR_SSI_STMSK, 0x00000000},
+ {CCSR_SSI_SRMSK, 0x00000000},
+ {CCSR_SSI_SACCEN, 0x00000000},
+ {CCSR_SSI_SACCDIS, 0x00000000},
};
static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
@@ -146,6 +146,7 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
case CCSR_SSI_SRX1:
case CCSR_SSI_SISR:
case CCSR_SSI_SFCSR:
+ case CCSR_SSI_SACNT:
case CCSR_SSI_SACADD:
case CCSR_SSI_SACDAT:
case CCSR_SSI_SATAG:
@@ -156,6 +157,21 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
}
}
+static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CCSR_SSI_SRX0:
+ case CCSR_SSI_SRX1:
+ case CCSR_SSI_SISR:
+ case CCSR_SSI_SACADD:
+ case CCSR_SSI_SACDAT:
+ case CCSR_SSI_SATAG:
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -178,6 +194,7 @@ static const struct regmap_config fsl_ssi_regconfig = {
.num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
.readable_reg = fsl_ssi_readable_reg,
.volatile_reg = fsl_ssi_volatile_reg,
+ .precious_reg = fsl_ssi_precious_reg,
.writeable_reg = fsl_ssi_writeable_reg,
.cache_type = REGCACHE_RBTREE,
};
@@ -239,8 +256,9 @@ struct fsl_ssi_private {
unsigned int baudclk_streams;
unsigned int bitclk_freq;
- /*regcache for SFCSR*/
+ /* regcache for volatile regs */
u32 regcache_sfcsr;
+ u32 regcache_sacnt;
/* DMA params */
struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -767,8 +785,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
struct regmap *regs = ssi_private->regs;
unsigned int channels = params_channels(hw_params);
- unsigned int sample_size =
- snd_pcm_format_width(params_format(hw_params));
+ unsigned int sample_size = params_width(hw_params);
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
int ret;
u32 scr_val;
@@ -1588,6 +1605,8 @@ static int fsl_ssi_suspend(struct device *dev)
regmap_read(regs, CCSR_SSI_SFCSR,
&ssi_private->regcache_sfcsr);
+ regmap_read(regs, CCSR_SSI_SACNT,
+ &ssi_private->regcache_sacnt);
regcache_cache_only(regs, true);
regcache_mark_dirty(regs);
@@ -1606,6 +1625,8 @@ static int fsl_ssi_resume(struct device *dev)
CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
ssi_private->regcache_sfcsr);
+ regmap_write(regs, CCSR_SSI_SACNT,
+ ssi_private->regcache_sacnt);
return regcache_sync(regs);
}
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 1fc01ed3279d..f3d3d1ffa84e 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -62,6 +62,8 @@ int imx_pcm_dma_init(struct platform_device *pdev, size_t size)
config = devm_kzalloc(&pdev->dev,
sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
*config = imx_dmaengine_pcm_config;
if (size)
config->prealloc_buffer_size = size;
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 7abf6a079574..49d7513f429e 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -220,9 +220,9 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
- pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+ pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret,
runtime->dma_area,
- runtime->dma_addr,
+ &runtime->dma_addr,
runtime->dma_bytes);
return ret;
}
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index b38b98cae855..201a70d1027a 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -69,13 +69,16 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
struct imx_priv *priv = &card_priv;
struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
struct device *dev = &priv->pdev->dev;
unsigned int pll_out;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
if (dapm->dev != codec_dai->dev)
return 0;
@@ -135,12 +138,15 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
static int imx_wm8962_late_probe(struct snd_soc_card *card)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
struct imx_priv *priv = &card_priv;
struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
struct device *dev = &priv->pdev->dev;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
data->clk_frequency, SND_SOC_CLOCK_IN);
if (ret < 0)
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 6f236f170cf5..ddf49f30b23f 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -189,8 +189,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
{
struct device *dev = pdev->dev.parent;
/* ssi_pdev is the platform device for the SSI node that probed us */
- struct platform_device *ssi_pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *ssi_pdev = to_platform_device(dev);
struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
struct mpc8610_hpcd_data *machine_data;
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 747aab0602bd..a1f780ecadf5 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -199,8 +199,7 @@ static int p1022_ds_probe(struct platform_device *pdev)
{
struct device *dev = pdev->dev.parent;
/* ssi_pdev is the platform device for the SSI node that probed us */
- struct platform_device *ssi_pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *ssi_pdev = to_platform_device(dev);
struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
struct machine_data *mdata;
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index 1dd49e5f9675..d4d88a8cb9c0 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -203,8 +203,7 @@ static int p1022_rdk_probe(struct platform_device *pdev)
{
struct device *dev = pdev->dev.parent;
/* ssi_pdev is the platform device for the SSI node that probed us */
- struct platform_device *ssi_pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *ssi_pdev = to_platform_device(dev);
struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
struct machine_data *mdata;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 54c33204541f..1ded8811598e 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -45,7 +45,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
- &priv->dai_props[rtd - rtd->card->rtd];
+ &priv->dai_props[rtd->num];
int ret;
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
@@ -64,7 +64,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
- &priv->dai_props[rtd - rtd->card->rtd];
+ &priv->dai_props[rtd->num];
clk_disable_unprepare(dai_props->cpu_dai.clk);
@@ -78,8 +78,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props =
- &priv->dai_props[rtd - rtd->card->rtd];
+ struct simple_dai_props *dai_props = &priv->dai_props[rtd->num];
unsigned int mclk, mclk_fs = 0;
int ret = 0;
@@ -174,10 +173,9 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
struct simple_dai_props *dai_props;
- int num, ret;
+ int ret;
- num = rtd - rtd->card->rtd;
- dai_props = &priv->dai_props[num];
+ dai_props = &priv->dai_props[rtd->num];
ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
if (ret < 0)
return ret;
diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig
new file mode 100644
index 000000000000..857a9510ee1c
--- /dev/null
+++ b/sound/soc/img/Kconfig
@@ -0,0 +1,52 @@
+config SND_SOC_IMG
+ bool "Audio support for Imagination Technologies designs"
+ help
+ Audio support for Imagination Technologies audio hardware
+
+config SND_SOC_IMG_I2S_IN
+ tristate "Imagination I2S Input Device Driver"
+ depends on SND_SOC_IMG
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for I2S in driver for
+ Imagination Technologies I2S in device.
+
+config SND_SOC_IMG_I2S_OUT
+ tristate "Imagination I2S Output Device Driver"
+ depends on SND_SOC_IMG
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for I2S out driver for
+ Imagination Technologies I2S out device.
+
+config SND_SOC_IMG_PARALLEL_OUT
+ tristate "Imagination Parallel Output Device Driver"
+ depends on SND_SOC_IMG
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for parallel out driver for
+ Imagination Technologies parallel out device.
+
+config SND_SOC_IMG_SPDIF_IN
+ tristate "Imagination SPDIF Input Device Driver"
+ depends on SND_SOC_IMG
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for SPDIF input driver for
+ Imagination Technologies SPDIF input device.
+
+config SND_SOC_IMG_SPDIF_OUT
+ tristate "Imagination SPDIF Output Device Driver"
+ depends on SND_SOC_IMG
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for SPDIF out driver for
+ Imagination Technologies SPDIF out device.
+
+
+config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC
+ tristate "Support for Pistachio SoC Internal DAC Driver"
+ depends on SND_SOC_IMG
+ help
+ Say Y or M if you want to add support for Pistachio internal DAC
+ driver for Imagination Technologies Pistachio internal DAC device.
diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile
new file mode 100644
index 000000000000..0508c1ced636
--- /dev/null
+++ b/sound/soc/img/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o
+obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o
+obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o
+obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o
+obj-$(CONFIG_SND_SOC_IMG_SPDIF_OUT) += img-spdif-out.o
+
+obj-$(CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC) += pistachio-internal-dac.o
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
new file mode 100644
index 000000000000..0389203f8560
--- /dev/null
+++ b/sound/soc/img/img-i2s-in.c
@@ -0,0 +1,516 @@
+/*
+ * IMG I2S input controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_I2S_IN_RX_FIFO 0x0
+
+#define IMG_I2S_IN_CTL 0x4
+#define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK 0xfffffffc
+#define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT 2
+#define IMG_I2S_IN_CTL_16PACK_MASK BIT(1)
+#define IMG_I2S_IN_CTL_ME_MASK BIT(0)
+
+#define IMG_I2S_IN_CH_CTL 0x4
+#define IMG_I2S_IN_CH_CTL_CCDEL_MASK 0x38000
+#define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT 15
+#define IMG_I2S_IN_CH_CTL_FEN_MASK BIT(14)
+#define IMG_I2S_IN_CH_CTL_FMODE_MASK BIT(13)
+#define IMG_I2S_IN_CH_CTL_16PACK_MASK BIT(12)
+#define IMG_I2S_IN_CH_CTL_JUST_MASK BIT(10)
+#define IMG_I2S_IN_CH_CTL_PACKH_MASK BIT(9)
+#define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK BIT(8)
+#define IMG_I2S_IN_CH_CTL_BLKP_MASK BIT(7)
+#define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK BIT(6)
+#define IMG_I2S_IN_CH_CTL_LRD_MASK BIT(3)
+#define IMG_I2S_IN_CH_CTL_FW_MASK BIT(2)
+#define IMG_I2S_IN_CH_CTL_SW_MASK BIT(1)
+#define IMG_I2S_IN_CH_CTL_ME_MASK BIT(0)
+
+#define IMG_I2S_IN_CH_STRIDE 0x20
+
+struct img_i2s_in {
+ void __iomem *base;
+ struct clk *clk_sys;
+ struct snd_dmaengine_dai_dma_data dma_data;
+ struct device *dev;
+ unsigned int max_i2s_chan;
+ void __iomem *channel_base;
+ unsigned int active_channels;
+ struct snd_soc_dai_driver dai_driver;
+};
+
+static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
+{
+ writel(val, i2s->base + reg);
+}
+
+static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg)
+{
+ return readl(i2s->base + reg);
+}
+
+static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan,
+ u32 val, u32 reg)
+{
+ writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
+}
+
+static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan,
+ u32 reg)
+{
+ return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
+}
+
+static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan)
+{
+ u32 reg;
+
+ reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
+ reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK;
+ img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
+}
+
+static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan)
+{
+ u32 reg;
+
+ reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
+ reg |= IMG_I2S_IN_CH_CTL_ME_MASK;
+ img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
+}
+
+static inline void img_i2s_in_disable(struct img_i2s_in *i2s)
+{
+ u32 reg;
+
+ reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+ reg &= ~IMG_I2S_IN_CTL_ME_MASK;
+ img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+}
+
+static inline void img_i2s_in_enable(struct img_i2s_in *i2s)
+{
+ u32 reg;
+
+ reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+ reg |= IMG_I2S_IN_CTL_ME_MASK;
+ img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+}
+
+static inline void img_i2s_in_flush(struct img_i2s_in *i2s)
+{
+ int i;
+ u32 reg;
+
+ for (i = 0; i < i2s->active_channels; i++) {
+ reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+ reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ }
+}
+
+static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ img_i2s_in_enable(i2s);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ img_i2s_in_disable(i2s);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int img_i2s_in_check_rate(struct img_i2s_in *i2s,
+ unsigned int sample_rate, unsigned int frame_size,
+ unsigned int *bclk_filter_enable,
+ unsigned int *bclk_filter_value)
+{
+ unsigned int bclk_freq, cur_freq;
+
+ bclk_freq = sample_rate * frame_size;
+
+ cur_freq = clk_get_rate(i2s->clk_sys);
+
+ if (cur_freq >= bclk_freq * 8) {
+ *bclk_filter_enable = 1;
+ *bclk_filter_value = 0;
+ } else if (cur_freq >= bclk_freq * 7) {
+ *bclk_filter_enable = 1;
+ *bclk_filter_value = 1;
+ } else if (cur_freq >= bclk_freq * 6) {
+ *bclk_filter_enable = 0;
+ *bclk_filter_value = 0;
+ } else {
+ dev_err(i2s->dev,
+ "Sys clock rate %u insufficient for sample rate %u\n",
+ cur_freq, sample_rate);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int img_i2s_in_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate, channels, i2s_channels, frame_size;
+ unsigned int bclk_filter_enable, bclk_filter_value;
+ int i, ret = 0;
+ u32 reg, control_mask, chan_control_mask;
+ u32 control_set = 0, chan_control_set = 0;
+ snd_pcm_format_t format;
+
+ rate = params_rate(params);
+ format = params_format(params);
+ channels = params_channels(params);
+ i2s_channels = channels / 2;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ frame_size = 64;
+ chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
+ chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
+ chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ frame_size = 64;
+ chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
+ chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ frame_size = 32;
+ control_set |= IMG_I2S_IN_CTL_16PACK_MASK;
+ chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((channels < 2) ||
+ (channels > (i2s->max_i2s_chan * 2)) ||
+ (channels % 2))
+ return -EINVAL;
+
+ control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT);
+
+ ret = img_i2s_in_check_rate(i2s, rate, frame_size,
+ &bclk_filter_enable, &bclk_filter_value);
+ if (ret < 0)
+ return ret;
+
+ if (bclk_filter_enable)
+ chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK;
+
+ if (bclk_filter_value)
+ chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK;
+
+ control_mask = IMG_I2S_IN_CTL_16PACK_MASK |
+ IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK;
+
+ chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK |
+ IMG_I2S_IN_CH_CTL_FEN_MASK |
+ IMG_I2S_IN_CH_CTL_FMODE_MASK |
+ IMG_I2S_IN_CH_CTL_SW_MASK |
+ IMG_I2S_IN_CH_CTL_FW_MASK |
+ IMG_I2S_IN_CH_CTL_PACKH_MASK;
+
+ reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+ reg = (reg & ~control_mask) | control_set;
+ img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_in_ch_disable(i2s, i);
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+ reg = (reg & ~chan_control_mask) | chan_control_set;
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ }
+
+ i2s->active_channels = i2s_channels;
+
+ img_i2s_in_flush(i2s);
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_in_ch_enable(i2s, i);
+
+ return 0;
+}
+
+static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+ int i;
+ u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0;
+ u32 reg;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
+ blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_in_ch_disable(i2s, i);
+
+ /*
+ * BLKP and LRD must be set during separate register writes
+ */
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+ reg = (reg & ~chan_control_mask) | chan_control_set;
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set;
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set;
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ }
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_in_ch_enable(i2s, i);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
+ .trigger = img_i2s_in_trigger,
+ .hw_params = img_i2s_in_hw_params,
+ .set_fmt = img_i2s_in_set_fmt
+};
+
+static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
+{
+ struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver img_i2s_in_component = {
+ .name = "img-i2s-in"
+};
+
+static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
+ struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
+{
+ unsigned int i2s_channels = params_channels(params) / 2;
+ struct snd_soc_pcm_runtime *rtd = st->private_data;
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ int ret;
+
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
+
+ ret = snd_hwparams_to_dma_slave_config(st, params, sc);
+ if (ret)
+ return ret;
+
+ sc->src_addr = dma_data->addr;
+ sc->src_addr_width = dma_data->addr_width;
+ sc->src_maxburst = 4 * i2s_channels;
+
+ return 0;
+}
+
+static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
+ .prepare_slave_config = img_i2s_in_dma_prepare_slave_config
+};
+
+static int img_i2s_in_probe(struct platform_device *pdev)
+{
+ struct img_i2s_in *i2s;
+ struct resource *res;
+ void __iomem *base;
+ int ret, i;
+ struct reset_control *rst;
+ unsigned int max_i2s_chan_pow_2;
+ struct device *dev = &pdev->dev;
+
+ i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+ if (!i2s)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, i2s);
+
+ i2s->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ i2s->base = base;
+
+ if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
+ &i2s->max_i2s_chan)) {
+ dev_err(dev, "No img,i2s-channels property\n");
+ return -EINVAL;
+ }
+
+ max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
+
+ i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
+
+ i2s->clk_sys = devm_clk_get(dev, "sys");
+ if (IS_ERR(i2s->clk_sys)) {
+ if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'sys'\n");
+ return PTR_ERR(i2s->clk_sys);
+ }
+
+ ret = clk_prepare_enable(i2s->clk_sys);
+ if (ret)
+ return ret;
+
+ i2s->active_channels = 1;
+ i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
+ i2s->dma_data.addr_width = 4;
+
+ i2s->dai_driver.probe = img_i2s_in_dai_probe;
+ i2s->dai_driver.capture.channels_min = 2;
+ i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
+ i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
+ i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
+ i2s->dai_driver.ops = &img_i2s_in_dai_ops;
+
+ rst = devm_reset_control_get(dev, "rst");
+ if (IS_ERR(rst)) {
+ if (PTR_ERR(rst) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_clk_disable;
+ }
+
+ dev_dbg(dev, "No top level reset found\n");
+
+ img_i2s_in_disable(i2s);
+
+ for (i = 0; i < i2s->max_i2s_chan; i++)
+ img_i2s_in_ch_disable(i2s, i);
+ } else {
+ reset_control_assert(rst);
+ reset_control_deassert(rst);
+ }
+
+ img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
+
+ for (i = 0; i < i2s->max_i2s_chan; i++)
+ img_i2s_in_ch_writel(i2s, i,
+ (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
+ IMG_I2S_IN_CH_CTL_JUST_MASK |
+ IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
+
+ ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
+ &i2s->dai_driver, 1);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
+ if (ret)
+ goto err_clk_disable;
+
+ return 0;
+
+err_clk_disable:
+ clk_disable_unprepare(i2s->clk_sys);
+
+ return ret;
+}
+
+static int img_i2s_in_dev_remove(struct platform_device *pdev)
+{
+ struct img_i2s_in *i2s = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2s->clk_sys);
+
+ return 0;
+}
+
+static const struct of_device_id img_i2s_in_of_match[] = {
+ { .compatible = "img,i2s-in" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
+
+static struct platform_driver img_i2s_in_driver = {
+ .driver = {
+ .name = "img-i2s-in",
+ .of_match_table = img_i2s_in_of_match
+ },
+ .probe = img_i2s_in_probe,
+ .remove = img_i2s_in_dev_remove
+};
+module_platform_driver(img_i2s_in_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG I2S Input Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
new file mode 100644
index 000000000000..5f997135a8ae
--- /dev/null
+++ b/sound/soc/img/img-i2s-out.c
@@ -0,0 +1,565 @@
+/*
+ * IMG I2S output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_I2S_OUT_TX_FIFO 0x0
+
+#define IMG_I2S_OUT_CTL 0x4
+#define IMG_I2S_OUT_CTL_DATA_EN_MASK BIT(24)
+#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK 0xffe000
+#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT 13
+#define IMG_I2S_OUT_CTL_FRM_SIZE_MASK BIT(8)
+#define IMG_I2S_OUT_CTL_MASTER_MASK BIT(6)
+#define IMG_I2S_OUT_CTL_CLK_MASK BIT(5)
+#define IMG_I2S_OUT_CTL_CLK_EN_MASK BIT(4)
+#define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK BIT(3)
+#define IMG_I2S_OUT_CTL_BCLK_POL_MASK BIT(2)
+#define IMG_I2S_OUT_CTL_ME_MASK BIT(0)
+
+#define IMG_I2S_OUT_CH_CTL 0x4
+#define IMG_I2S_OUT_CHAN_CTL_CH_MASK BIT(11)
+#define IMG_I2S_OUT_CHAN_CTL_LT_MASK BIT(10)
+#define IMG_I2S_OUT_CHAN_CTL_FMT_MASK 0xf0
+#define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT 4
+#define IMG_I2S_OUT_CHAN_CTL_JUST_MASK BIT(3)
+#define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK BIT(1)
+#define IMG_I2S_OUT_CHAN_CTL_ME_MASK BIT(0)
+
+#define IMG_I2S_OUT_CH_STRIDE 0x20
+
+struct img_i2s_out {
+ void __iomem *base;
+ struct clk *clk_sys;
+ struct clk *clk_ref;
+ struct snd_dmaengine_dai_dma_data dma_data;
+ struct device *dev;
+ unsigned int max_i2s_chan;
+ void __iomem *channel_base;
+ bool force_clk_active;
+ unsigned int active_channels;
+ struct reset_control *rst;
+ struct snd_soc_dai_driver dai_driver;
+};
+
+static int img_i2s_out_suspend(struct device *dev)
+{
+ struct img_i2s_out *i2s = dev_get_drvdata(dev);
+
+ if (!i2s->force_clk_active)
+ clk_disable_unprepare(i2s->clk_ref);
+
+ return 0;
+}
+
+static int img_i2s_out_resume(struct device *dev)
+{
+ struct img_i2s_out *i2s = dev_get_drvdata(dev);
+ int ret;
+
+ if (!i2s->force_clk_active) {
+ ret = clk_prepare_enable(i2s->clk_ref);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val,
+ u32 reg)
+{
+ writel(val, i2s->base + reg);
+}
+
+static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg)
+{
+ return readl(i2s->base + reg);
+}
+
+static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s,
+ u32 chan, u32 val, u32 reg)
+{
+ writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg);
+}
+
+static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan,
+ u32 reg)
+{
+ return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg);
+}
+
+static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan)
+{
+ u32 reg;
+
+ reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL);
+ reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+ img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL);
+}
+
+static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan)
+{
+ u32 reg;
+
+ reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL);
+ reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+ img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL);
+}
+
+static inline void img_i2s_out_disable(struct img_i2s_out *i2s)
+{
+ u32 reg;
+
+ reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+ reg &= ~IMG_I2S_OUT_CTL_ME_MASK;
+ img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+}
+
+static inline void img_i2s_out_enable(struct img_i2s_out *i2s)
+{
+ u32 reg;
+
+ reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+ reg |= IMG_I2S_OUT_CTL_ME_MASK;
+ img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+}
+
+static void img_i2s_out_reset(struct img_i2s_out *i2s)
+{
+ int i;
+ u32 core_ctl, chan_ctl;
+
+ core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) &
+ ~IMG_I2S_OUT_CTL_ME_MASK &
+ ~IMG_I2S_OUT_CTL_DATA_EN_MASK;
+
+ if (!i2s->force_clk_active)
+ core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK;
+
+ chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) &
+ ~IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+
+ reset_control_assert(i2s->rst);
+ reset_control_deassert(i2s->rst);
+
+ for (i = 0; i < i2s->max_i2s_chan; i++)
+ img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL);
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_out_ch_enable(i2s, i);
+
+ img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL);
+ img_i2s_out_enable(i2s);
+}
+
+static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 reg;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+ if (!i2s->force_clk_active)
+ reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
+ reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK;
+ img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ img_i2s_out_reset(i2s);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int img_i2s_out_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int channels, i2s_channels;
+ long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
+ int i;
+ u32 reg, control_mask, control_set = 0;
+ snd_pcm_format_t format;
+
+ rate = params_rate(params);
+ format = params_format(params);
+ channels = params_channels(params);
+ i2s_channels = channels / 2;
+
+ if (format != SNDRV_PCM_FORMAT_S32_LE)
+ return -EINVAL;
+
+ if ((channels < 2) ||
+ (channels > (i2s->max_i2s_chan * 2)) ||
+ (channels % 2))
+ return -EINVAL;
+
+ pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256);
+ if (pre_div_a < 0)
+ return pre_div_a;
+ pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384);
+ if (pre_div_b < 0)
+ return pre_div_b;
+
+ diff_a = abs((pre_div_a / 256) - rate);
+ diff_b = abs((pre_div_b / 384) - rate);
+
+ /* If diffs are equal, use lower clock rate */
+ if (diff_a > diff_b)
+ clk_set_rate(i2s->clk_ref, pre_div_b);
+ else
+ clk_set_rate(i2s->clk_ref, pre_div_a);
+
+ /*
+ * Another driver (eg alsa machine driver) may have rejected the above
+ * change. Get the current rate and set the register bit according to
+ * the new minimum diff
+ */
+ clk_rate = clk_get_rate(i2s->clk_ref);
+
+ diff_a = abs((clk_rate / 256) - rate);
+ diff_b = abs((clk_rate / 384) - rate);
+
+ if (diff_a > diff_b)
+ control_set |= IMG_I2S_OUT_CTL_CLK_MASK;
+
+ control_set |= ((i2s_channels - 1) <<
+ IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) &
+ IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK;
+
+ control_mask = IMG_I2S_OUT_CTL_CLK_MASK |
+ IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK;
+
+ img_i2s_out_disable(i2s);
+
+ reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+ reg = (reg & ~control_mask) | control_set;
+ img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+ for (i = 0; i < i2s_channels; i++)
+ img_i2s_out_ch_enable(i2s, i);
+
+ for (; i < i2s->max_i2s_chan; i++)
+ img_i2s_out_ch_disable(i2s, i);
+
+ img_i2s_out_enable(i2s);
+
+ i2s->active_channels = i2s_channels;
+
+ return 0;
+}
+
+static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+ int i;
+ bool force_clk_active;
+ u32 chan_control_mask, control_mask, chan_control_set = 0;
+ u32 reg, control_set = 0;
+
+ force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) ==
+ SND_SOC_DAIFMT_CONT);
+
+ if (force_clk_active)
+ control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ control_set |= IMG_I2S_OUT_CTL_MASTER_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK;
+ control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK |
+ IMG_I2S_OUT_CTL_MASTER_MASK |
+ IMG_I2S_OUT_CTL_BCLK_POL_MASK |
+ IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+
+ chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+
+ img_i2s_out_disable(i2s);
+
+ reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+ reg = (reg & ~control_mask) | control_set;
+ img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_out_ch_disable(i2s, i);
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL);
+ reg = (reg & ~chan_control_mask) | chan_control_set;
+ img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+ }
+
+ for (i = 0; i < i2s->active_channels; i++)
+ img_i2s_out_ch_enable(i2s, i);
+
+ img_i2s_out_enable(i2s);
+
+ i2s->force_clk_active = force_clk_active;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
+ .trigger = img_i2s_out_trigger,
+ .hw_params = img_i2s_out_hw_params,
+ .set_fmt = img_i2s_out_set_fmt
+};
+
+static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
+{
+ struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver img_i2s_out_component = {
+ .name = "img-i2s-out"
+};
+
+static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st,
+ struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
+{
+ unsigned int i2s_channels = params_channels(params) / 2;
+ struct snd_soc_pcm_runtime *rtd = st->private_data;
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ int ret;
+
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
+
+ ret = snd_hwparams_to_dma_slave_config(st, params, sc);
+ if (ret)
+ return ret;
+
+ sc->dst_addr = dma_data->addr;
+ sc->dst_addr_width = dma_data->addr_width;
+ sc->dst_maxburst = 4 * i2s_channels;
+
+ return 0;
+}
+
+static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = {
+ .prepare_slave_config = img_i2s_out_dma_prepare_slave_config
+};
+
+static int img_i2s_out_probe(struct platform_device *pdev)
+{
+ struct img_i2s_out *i2s;
+ struct resource *res;
+ void __iomem *base;
+ int i, ret;
+ unsigned int max_i2s_chan_pow_2;
+ u32 reg;
+ struct device *dev = &pdev->dev;
+
+ i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ if (!i2s)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, i2s);
+
+ i2s->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ i2s->base = base;
+
+ if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
+ &i2s->max_i2s_chan)) {
+ dev_err(&pdev->dev, "No img,i2s-channels property\n");
+ return -EINVAL;
+ }
+
+ max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
+
+ i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
+
+ i2s->rst = devm_reset_control_get(&pdev->dev, "rst");
+ if (IS_ERR(i2s->rst)) {
+ if (PTR_ERR(i2s->rst) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "No top level reset found\n");
+ return PTR_ERR(i2s->rst);
+ }
+
+ i2s->clk_sys = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(i2s->clk_sys)) {
+ if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'sys'\n");
+ return PTR_ERR(i2s->clk_sys);
+ }
+
+ i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
+ if (IS_ERR(i2s->clk_ref)) {
+ if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'ref'\n");
+ return PTR_ERR(i2s->clk_ref);
+ }
+
+ ret = clk_prepare_enable(i2s->clk_sys);
+ if (ret)
+ return ret;
+
+ reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
+ img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+ reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK |
+ IMG_I2S_OUT_CHAN_CTL_LT_MASK |
+ IMG_I2S_OUT_CHAN_CTL_CH_MASK |
+ (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT);
+
+ for (i = 0; i < i2s->max_i2s_chan; i++)
+ img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+
+ img_i2s_out_reset(i2s);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_i2s_out_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ i2s->active_channels = 1;
+ i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
+ i2s->dma_data.addr_width = 4;
+ i2s->dma_data.maxburst = 4;
+
+ i2s->dai_driver.probe = img_i2s_out_dai_probe;
+ i2s->dai_driver.playback.channels_min = 2;
+ i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2;
+ i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000;
+ i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ i2s->dai_driver.ops = &img_i2s_out_dai_ops;
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &img_i2s_out_component, &i2s->dai_driver, 1);
+ if (ret)
+ goto err_suspend;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
+ &img_i2s_out_dma_config, 0);
+ if (ret)
+ goto err_suspend;
+
+ return 0;
+
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_i2s_out_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ clk_disable_unprepare(i2s->clk_sys);
+
+ return ret;
+}
+
+static int img_i2s_out_dev_remove(struct platform_device *pdev)
+{
+ struct img_i2s_out *i2s = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_i2s_out_suspend(&pdev->dev);
+
+ clk_disable_unprepare(i2s->clk_sys);
+
+ return 0;
+}
+
+static const struct of_device_id img_i2s_out_of_match[] = {
+ { .compatible = "img,i2s-out" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
+
+static const struct dev_pm_ops img_i2s_out_pm_ops = {
+ SET_RUNTIME_PM_OPS(img_i2s_out_suspend,
+ img_i2s_out_resume, NULL)
+};
+
+static struct platform_driver img_i2s_out_driver = {
+ .driver = {
+ .name = "img-i2s-out",
+ .of_match_table = img_i2s_out_of_match,
+ .pm = &img_i2s_out_pm_ops
+ },
+ .probe = img_i2s_out_probe,
+ .remove = img_i2s_out_dev_remove
+};
+module_platform_driver(img_i2s_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG I2S Output Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
new file mode 100644
index 000000000000..c1610a054d65
--- /dev/null
+++ b/sound/soc/img/img-parallel-out.c
@@ -0,0 +1,327 @@
+/*
+ * IMG parallel output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_PRL_OUT_TX_FIFO 0
+
+#define IMG_PRL_OUT_CTL 0x4
+#define IMG_PRL_OUT_CTL_CH_MASK BIT(4)
+#define IMG_PRL_OUT_CTL_PACKH_MASK BIT(3)
+#define IMG_PRL_OUT_CTL_EDGE_MASK BIT(2)
+#define IMG_PRL_OUT_CTL_ME_MASK BIT(1)
+#define IMG_PRL_OUT_CTL_SRST_MASK BIT(0)
+
+struct img_prl_out {
+ void __iomem *base;
+ struct clk *clk_sys;
+ struct clk *clk_ref;
+ struct snd_dmaengine_dai_dma_data dma_data;
+ struct device *dev;
+ struct reset_control *rst;
+};
+
+static int img_prl_out_suspend(struct device *dev)
+{
+ struct img_prl_out *prl = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(prl->clk_ref);
+
+ return 0;
+}
+
+static int img_prl_out_resume(struct device *dev)
+{
+ struct img_prl_out *prl = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(prl->clk_ref);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline void img_prl_out_writel(struct img_prl_out *prl,
+ u32 val, u32 reg)
+{
+ writel(val, prl->base + reg);
+}
+
+static inline u32 img_prl_out_readl(struct img_prl_out *prl, u32 reg)
+{
+ return readl(prl->base + reg);
+}
+
+static void img_prl_out_reset(struct img_prl_out *prl)
+{
+ u32 ctl;
+
+ ctl = img_prl_out_readl(prl, IMG_PRL_OUT_CTL) &
+ ~IMG_PRL_OUT_CTL_ME_MASK;
+
+ reset_control_assert(prl->rst);
+ reset_control_deassert(prl->rst);
+
+ img_prl_out_writel(prl, ctl, IMG_PRL_OUT_CTL);
+}
+
+static int img_prl_out_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+ u32 reg;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+ reg |= IMG_PRL_OUT_CTL_ME_MASK;
+ img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ img_prl_out_reset(prl);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int img_prl_out_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate, channels;
+ u32 reg, control_set = 0;
+ snd_pcm_format_t format;
+
+ rate = params_rate(params);
+ format = params_format(params);
+ channels = params_channels(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ control_set |= IMG_PRL_OUT_CTL_PACKH_MASK;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (channels != 2)
+ return -EINVAL;
+
+ clk_set_rate(prl->clk_ref, rate * 256);
+
+ reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+ reg = (reg & ~IMG_PRL_OUT_CTL_PACKH_MASK) | control_set;
+ img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+
+ return 0;
+}
+
+static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+ u32 reg, control_set = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ control_set |= IMG_PRL_OUT_CTL_EDGE_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+ reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set;
+ img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
+ .trigger = img_prl_out_trigger,
+ .hw_params = img_prl_out_hw_params,
+ .set_fmt = img_prl_out_set_fmt
+};
+
+static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
+{
+ struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &prl->dma_data, NULL);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver img_prl_out_dai = {
+ .probe = img_prl_out_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE
+ },
+ .ops = &img_prl_out_dai_ops
+};
+
+static const struct snd_soc_component_driver img_prl_out_component = {
+ .name = "img-prl-out"
+};
+
+static int img_prl_out_probe(struct platform_device *pdev)
+{
+ struct img_prl_out *prl;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+ struct device *dev = &pdev->dev;
+
+ prl = devm_kzalloc(&pdev->dev, sizeof(*prl), GFP_KERNEL);
+ if (!prl)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, prl);
+
+ prl->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ prl->base = base;
+
+ prl->rst = devm_reset_control_get(&pdev->dev, "rst");
+ if (IS_ERR(prl->rst)) {
+ if (PTR_ERR(prl->rst) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "No top level reset found\n");
+ return PTR_ERR(prl->rst);
+ }
+
+ prl->clk_sys = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(prl->clk_sys)) {
+ if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'sys'\n");
+ return PTR_ERR(prl->clk_sys);
+ }
+
+ prl->clk_ref = devm_clk_get(&pdev->dev, "ref");
+ if (IS_ERR(prl->clk_ref)) {
+ if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'ref'\n");
+ return PTR_ERR(prl->clk_ref);
+ }
+
+ ret = clk_prepare_enable(prl->clk_sys);
+ if (ret)
+ return ret;
+
+ img_prl_out_writel(prl, IMG_PRL_OUT_CTL_EDGE_MASK, IMG_PRL_OUT_CTL);
+ img_prl_out_reset(prl);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_prl_out_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ prl->dma_data.addr = res->start + IMG_PRL_OUT_TX_FIFO;
+ prl->dma_data.addr_width = 4;
+ prl->dma_data.maxburst = 4;
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &img_prl_out_component,
+ &img_prl_out_dai, 1);
+ if (ret)
+ goto err_suspend;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_suspend;
+
+ return 0;
+
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_prl_out_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ clk_disable_unprepare(prl->clk_sys);
+
+ return ret;
+}
+
+static int img_prl_out_dev_remove(struct platform_device *pdev)
+{
+ struct img_prl_out *prl = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_prl_out_suspend(&pdev->dev);
+
+ clk_disable_unprepare(prl->clk_sys);
+
+ return 0;
+}
+
+static const struct of_device_id img_prl_out_of_match[] = {
+ { .compatible = "img,parallel-out" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, img_prl_out_of_match);
+
+static const struct dev_pm_ops img_prl_out_pm_ops = {
+ SET_RUNTIME_PM_OPS(img_prl_out_suspend,
+ img_prl_out_resume, NULL)
+};
+
+static struct platform_driver img_prl_out_driver = {
+ .driver = {
+ .name = "img-parallel-out",
+ .of_match_table = img_prl_out_of_match,
+ .pm = &img_prl_out_pm_ops
+ },
+ .probe = img_prl_out_probe,
+ .remove = img_prl_out_dev_remove
+};
+module_platform_driver(img_prl_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG Parallel Output Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
new file mode 100644
index 000000000000..4d9953d318af
--- /dev/null
+++ b/sound/soc/img/img-spdif-in.c
@@ -0,0 +1,806 @@
+/*
+ * IMG SPDIF input controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_SPDIF_IN_RX_FIFO_OFFSET 0
+
+#define IMG_SPDIF_IN_CTL 0x4
+#define IMG_SPDIF_IN_CTL_LOCKLO_MASK 0xff
+#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT 0
+#define IMG_SPDIF_IN_CTL_LOCKHI_MASK 0xff00
+#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT 8
+#define IMG_SPDIF_IN_CTL_TRK_MASK 0xff0000
+#define IMG_SPDIF_IN_CTL_TRK_SHIFT 16
+#define IMG_SPDIF_IN_CTL_SRD_MASK 0x70000000
+#define IMG_SPDIF_IN_CTL_SRD_SHIFT 28
+#define IMG_SPDIF_IN_CTL_SRT_MASK BIT(31)
+
+#define IMG_SPDIF_IN_STATUS 0x8
+#define IMG_SPDIF_IN_STATUS_SAM_MASK 0x7000
+#define IMG_SPDIF_IN_STATUS_SAM_SHIFT 12
+#define IMG_SPDIF_IN_STATUS_LOCK_MASK BIT(15)
+#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT 15
+
+#define IMG_SPDIF_IN_CLKGEN 0x1c
+#define IMG_SPDIF_IN_CLKGEN_NOM_MASK 0x3ff
+#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT 0
+#define IMG_SPDIF_IN_CLKGEN_HLD_MASK 0x3ff0000
+#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT 16
+
+#define IMG_SPDIF_IN_CSL 0x20
+
+#define IMG_SPDIF_IN_CSH 0x24
+#define IMG_SPDIF_IN_CSH_MASK 0xff
+#define IMG_SPDIF_IN_CSH_SHIFT 0
+
+#define IMG_SPDIF_IN_SOFT_RESET 0x28
+#define IMG_SPDIF_IN_SOFT_RESET_MASK BIT(0)
+
+#define IMG_SPDIF_IN_ACLKGEN_START 0x2c
+#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK 0x3ff
+#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT 0
+#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK 0xffc00
+#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT 10
+#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK 0xff00000
+#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT 20
+
+#define IMG_SPDIF_IN_NUM_ACLKGEN 4
+
+struct img_spdif_in {
+ spinlock_t lock;
+ void __iomem *base;
+ struct clk *clk_sys;
+ struct snd_dmaengine_dai_dma_data dma_data;
+ struct device *dev;
+ unsigned int trk;
+ bool multi_freq;
+ int lock_acquire;
+ int lock_release;
+ unsigned int single_freq;
+ unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
+ bool active;
+
+ /* Write-only registers */
+ unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
+};
+
+static inline void img_spdif_in_writel(struct img_spdif_in *spdif,
+ u32 val, u32 reg)
+{
+ writel(val, spdif->base + reg);
+}
+
+static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg)
+{
+ return readl(spdif->base + reg);
+}
+
+static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif,
+ u32 index)
+{
+ img_spdif_in_writel(spdif, spdif->aclkgen_regs[index],
+ IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4));
+}
+
+static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif,
+ unsigned int sample_rate, unsigned long *actual_freq)
+{
+ unsigned long min_freq, freq_t;
+
+ /* Clock rate must be at least 24x the bit rate */
+ min_freq = sample_rate * 2 * 32 * 24;
+
+ freq_t = clk_get_rate(spdif->clk_sys);
+
+ if (freq_t < min_freq)
+ return -EINVAL;
+
+ *actual_freq = freq_t;
+
+ return 0;
+}
+
+static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom,
+ unsigned int *phld, unsigned long clk_rate)
+{
+ unsigned int ori, nom, hld;
+
+ /*
+ * Calculate oversampling ratio, nominal phase increment and hold
+ * increment for the given rate / frequency
+ */
+
+ if (!rate)
+ return -EINVAL;
+
+ ori = clk_rate / (rate * 64);
+
+ if (!ori)
+ return -EINVAL;
+
+ nom = (4096 / ori) + 1;
+ do
+ hld = 4096 - (--nom * (ori - 1));
+ while (hld < 120);
+
+ *pnom = nom;
+ *phld = hld;
+
+ return 0;
+}
+
+static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif,
+ unsigned int rate)
+{
+ unsigned int nom, hld;
+ unsigned long flags, clk_rate;
+ int ret = 0;
+ u32 reg;
+
+ ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate);
+ if (ret)
+ return ret;
+
+ ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
+ if (ret)
+ return ret;
+
+ reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) &
+ IMG_SPDIF_IN_CLKGEN_NOM_MASK;
+ reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) &
+ IMG_SPDIF_IN_CLKGEN_HLD_MASK;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ if (spdif->active) {
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EBUSY;
+ }
+
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN);
+
+ spdif->single_freq = rate;
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif,
+ unsigned int multi_freqs[])
+{
+ unsigned int nom, hld, rate, max_rate = 0;
+ unsigned long flags, clk_rate;
+ int i, ret = 0;
+ u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
+
+ for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
+ if (multi_freqs[i] > max_rate)
+ max_rate = multi_freqs[i];
+
+ ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+ rate = multi_freqs[i];
+
+ ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
+ if (ret)
+ return ret;
+
+ reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) &
+ IMG_SPDIF_IN_ACLKGEN_NOM_MASK;
+ reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) &
+ IMG_SPDIF_IN_ACLKGEN_HLD_MASK;
+ temp_regs[i] = reg;
+ }
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ if (spdif->active) {
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EBUSY;
+ }
+
+ trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT;
+
+ for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+ spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg;
+ img_spdif_in_aclkgen_writel(spdif, i);
+ }
+
+ spdif->multi_freq = true;
+ spdif->multi_freqs[0] = multi_freqs[0];
+ spdif->multi_freqs[1] = multi_freqs[1];
+ spdif->multi_freqs[2] = multi_freqs[2];
+ spdif->multi_freqs[3] = multi_freqs[3];
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_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 img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.iec958.status[0] = 0xff;
+ ucontrol->value.iec958.status[1] = 0xff;
+ ucontrol->value.iec958.status[2] = 0xff;
+ ucontrol->value.iec958.status[3] = 0xff;
+ ucontrol->value.iec958.status[4] = 0xff;
+
+ return 0;
+}
+
+static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL);
+ ucontrol->value.iec958.status[0] = reg & 0xff;
+ ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
+ ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH);
+ ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK)
+ >> IMG_SPDIF_IN_CSH_SHIFT;
+
+ return 0;
+}
+
+static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = LONG_MAX;
+
+ return 0;
+}
+
+static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+ if (spdif->multi_freq) {
+ ucontrol->value.integer.value[0] = spdif->multi_freqs[0];
+ ucontrol->value.integer.value[1] = spdif->multi_freqs[1];
+ ucontrol->value.integer.value[2] = spdif->multi_freqs[2];
+ ucontrol->value.integer.value[3] = spdif->multi_freqs[3];
+ } else {
+ ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.integer.value[1] = 0;
+ ucontrol->value.integer.value[2] = 0;
+ ucontrol->value.integer.value[3] = 0;
+ }
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
+ bool multi_freq;
+ unsigned long flags;
+
+ if ((ucontrol->value.integer.value[0] == 0) &&
+ (ucontrol->value.integer.value[1] == 0) &&
+ (ucontrol->value.integer.value[2] == 0) &&
+ (ucontrol->value.integer.value[3] == 0)) {
+ multi_freq = false;
+ } else {
+ multi_freqs[0] = ucontrol->value.integer.value[0];
+ multi_freqs[1] = ucontrol->value.integer.value[1];
+ multi_freqs[2] = ucontrol->value.integer.value[2];
+ multi_freqs[3] = ucontrol->value.integer.value[3];
+ multi_freq = true;
+ }
+
+ if (multi_freq)
+ return img_spdif_in_do_clkgen_multi(spdif, multi_freqs);
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ if (spdif->active) {
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EBUSY;
+ }
+
+ spdif->multi_freq = false;
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_info_lock_freq(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 = LONG_MAX;
+
+ return 0;
+}
+
+static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uc)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS);
+ if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) {
+ if (spdif->multi_freq) {
+ i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >>
+ IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1;
+ uc->value.integer.value[0] = spdif->multi_freqs[i];
+ } else {
+ uc->value.integer.value[0] = spdif->single_freq;
+ }
+ } else {
+ uc->value.integer.value[0] = 0;
+ }
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_info_trk(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 = 255;
+
+ return 0;
+}
+
+static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.integer.value[0] = spdif->trk;
+
+ return 0;
+}
+
+static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
+ int i;
+ u32 reg;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ if (spdif->active) {
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EBUSY;
+ }
+
+ spdif->trk = ucontrol->value.integer.value[0];
+
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+ reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK;
+ reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT;
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+ for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+ spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] &
+ ~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) |
+ (spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT);
+
+ img_spdif_in_aclkgen_writel(spdif, i);
+ }
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = -128;
+ uinfo->value.integer.max = 127;
+
+ return 0;
+}
+
+static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.integer.value[0] = spdif->lock_acquire;
+
+ return 0;
+}
+
+static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ if (spdif->active) {
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EBUSY;
+ }
+
+ spdif->lock_acquire = ucontrol->value.integer.value[0];
+
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+ reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+ reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
+ IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.integer.value[0] = spdif->lock_release;
+
+ return 0;
+}
+
+static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ if (spdif->active) {
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EBUSY;
+ }
+
+ spdif->lock_release = ucontrol->value.integer.value[0];
+
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+ reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+ reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
+ IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new img_spdif_in_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
+ .info = img_spdif_in_iec958_info,
+ .get = img_spdif_in_get_status_mask
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+ .info = img_spdif_in_iec958_info,
+ .get = img_spdif_in_get_status
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SPDIF In Multi Frequency Acquire",
+ .info = img_spdif_in_info_multi_freq,
+ .get = img_spdif_in_get_multi_freq,
+ .put = img_spdif_in_set_multi_freq
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SPDIF In Lock Frequency",
+ .info = img_spdif_in_info_lock_freq,
+ .get = img_spdif_in_get_lock_freq
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SPDIF In Lock TRK",
+ .info = img_spdif_in_info_trk,
+ .get = img_spdif_in_get_trk,
+ .put = img_spdif_in_set_trk
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SPDIF In Lock Acquire Threshold",
+ .info = img_spdif_in_info_lock,
+ .get = img_spdif_in_get_lock_acquire,
+ .put = img_spdif_in_set_lock_acquire
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SPDIF In Lock Release Threshold",
+ .info = img_spdif_in_info_lock,
+ .get = img_spdif_in_get_lock_release,
+ .put = img_spdif_in_set_lock_release
+ }
+};
+
+static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ unsigned long flags;
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+ int ret = 0;
+ u32 reg;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+ if (spdif->multi_freq)
+ reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK;
+ else
+ reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT);
+ reg |= IMG_SPDIF_IN_CTL_SRT_MASK;
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+ spdif->active = true;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+ reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK;
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+ spdif->active = false;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return ret;
+}
+
+static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate, channels;
+ snd_pcm_format_t format;
+
+ rate = params_rate(params);
+ channels = params_channels(params);
+ format = params_format(params);
+
+ if (format != SNDRV_PCM_FORMAT_S32_LE)
+ return -EINVAL;
+
+ if (channels != 2)
+ return -EINVAL;
+
+ return img_spdif_in_do_clkgen_single(spdif, rate);
+}
+
+static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
+ .trigger = img_spdif_in_trigger,
+ .hw_params = img_spdif_in_hw_params
+};
+
+static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
+{
+ struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data);
+
+ snd_soc_add_dai_controls(dai, img_spdif_in_controls,
+ ARRAY_SIZE(img_spdif_in_controls));
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver img_spdif_in_dai = {
+ .probe = img_spdif_in_dai_probe,
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .ops = &img_spdif_in_dai_ops
+};
+
+static const struct snd_soc_component_driver img_spdif_in_component = {
+ .name = "img-spdif-in"
+};
+
+static int img_spdif_in_probe(struct platform_device *pdev)
+{
+ struct img_spdif_in *spdif;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+ struct reset_control *rst;
+ u32 reg;
+ struct device *dev = &pdev->dev;
+
+ spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+ if (!spdif)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, spdif);
+
+ spdif->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ spdif->base = base;
+
+ spdif->clk_sys = devm_clk_get(dev, "sys");
+ if (IS_ERR(spdif->clk_sys)) {
+ if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'sys'\n");
+ return PTR_ERR(spdif->clk_sys);
+ }
+
+ ret = clk_prepare_enable(spdif->clk_sys);
+ if (ret)
+ return ret;
+
+ rst = devm_reset_control_get(&pdev->dev, "rst");
+ if (IS_ERR(rst)) {
+ if (PTR_ERR(rst) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_clk_disable;
+ }
+ dev_dbg(dev, "No top level reset found\n");
+ img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK,
+ IMG_SPDIF_IN_SOFT_RESET);
+ img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET);
+ } else {
+ reset_control_assert(rst);
+ reset_control_deassert(rst);
+ }
+
+ spin_lock_init(&spdif->lock);
+
+ spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET;
+ spdif->dma_data.addr_width = 4;
+ spdif->dma_data.maxburst = 4;
+ spdif->trk = 0x80;
+ spdif->lock_acquire = 4;
+ spdif->lock_release = -128;
+
+ reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
+ IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+ reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
+ IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+ reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) &
+ IMG_SPDIF_IN_CTL_TRK_MASK;
+ img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &img_spdif_in_component, &img_spdif_in_dai, 1);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_clk_disable;
+
+ return 0;
+
+err_clk_disable:
+ clk_disable_unprepare(spdif->clk_sys);
+
+ return ret;
+}
+
+static int img_spdif_in_dev_remove(struct platform_device *pdev)
+{
+ struct img_spdif_in *spdif = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(spdif->clk_sys);
+
+ return 0;
+}
+
+static const struct of_device_id img_spdif_in_of_match[] = {
+ { .compatible = "img,spdif-in" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
+
+static struct platform_driver img_spdif_in_driver = {
+ .driver = {
+ .name = "img-spdif-in",
+ .of_match_table = img_spdif_in_of_match
+ },
+ .probe = img_spdif_in_probe,
+ .remove = img_spdif_in_dev_remove
+};
+module_platform_driver(img_spdif_in_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG SPDIF Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
new file mode 100644
index 000000000000..08f93a5dadfe
--- /dev/null
+++ b/sound/soc/img/img-spdif-out.c
@@ -0,0 +1,441 @@
+/*
+ * IMG SPDIF output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_SPDIF_OUT_TX_FIFO 0x0
+
+#define IMG_SPDIF_OUT_CTL 0x4
+#define IMG_SPDIF_OUT_CTL_FS_MASK BIT(4)
+#define IMG_SPDIF_OUT_CTL_CLK_MASK BIT(2)
+#define IMG_SPDIF_OUT_CTL_SRT_MASK BIT(0)
+
+#define IMG_SPDIF_OUT_CSL 0x14
+
+#define IMG_SPDIF_OUT_CSH_UV 0x18
+#define IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT 0
+#define IMG_SPDIF_OUT_CSH_UV_CSH_MASK 0xff
+
+struct img_spdif_out {
+ spinlock_t lock;
+ void __iomem *base;
+ struct clk *clk_sys;
+ struct clk *clk_ref;
+ struct snd_dmaengine_dai_dma_data dma_data;
+ struct device *dev;
+ struct reset_control *rst;
+};
+
+static int img_spdif_out_suspend(struct device *dev)
+{
+ struct img_spdif_out *spdif = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(spdif->clk_ref);
+
+ return 0;
+}
+
+static int img_spdif_out_resume(struct device *dev)
+{
+ struct img_spdif_out *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(spdif->clk_ref);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline void img_spdif_out_writel(struct img_spdif_out *spdif, u32 val,
+ u32 reg)
+{
+ writel(val, spdif->base + reg);
+}
+
+static inline u32 img_spdif_out_readl(struct img_spdif_out *spdif, u32 reg)
+{
+ return readl(spdif->base + reg);
+}
+
+static void img_spdif_out_reset(struct img_spdif_out *spdif)
+{
+ u32 ctl, status_low, status_high;
+
+ ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL) &
+ ~IMG_SPDIF_OUT_CTL_SRT_MASK;
+ status_low = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+ status_high = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+
+ reset_control_assert(spdif->rst);
+ reset_control_deassert(spdif->rst);
+
+ img_spdif_out_writel(spdif, ctl, IMG_SPDIF_OUT_CTL);
+ img_spdif_out_writel(spdif, status_low, IMG_SPDIF_OUT_CSL);
+ img_spdif_out_writel(spdif, status_high, IMG_SPDIF_OUT_CSH_UV);
+}
+
+static int img_spdif_out_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 img_spdif_out_get_status_mask(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.iec958.status[0] = 0xff;
+ ucontrol->value.iec958.status[1] = 0xff;
+ ucontrol->value.iec958.status[2] = 0xff;
+ ucontrol->value.iec958.status[3] = 0xff;
+ ucontrol->value.iec958.status[4] = 0xff;
+
+ return 0;
+}
+
+static int img_spdif_out_get_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+ ucontrol->value.iec958.status[0] = reg & 0xff;
+ ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
+ ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
+
+ reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+ ucontrol->value.iec958.status[4] =
+ (reg & IMG_SPDIF_OUT_CSH_UV_CSH_MASK) >>
+ IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static int img_spdif_out_set_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+ unsigned long flags;
+
+ reg = ((u32)ucontrol->value.iec958.status[3] << 24);
+ reg |= ((u32)ucontrol->value.iec958.status[2] << 16);
+ reg |= ((u32)ucontrol->value.iec958.status[1] << 8);
+ reg |= (u32)ucontrol->value.iec958.status[0];
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSL);
+
+ reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+ reg &= ~IMG_SPDIF_OUT_CSH_UV_CSH_MASK;
+ reg |= (u32)ucontrol->value.iec958.status[4] <<
+ IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
+ img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSH_UV);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new img_spdif_out_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+ .info = img_spdif_out_info,
+ .get = img_spdif_out_get_status_mask
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = img_spdif_out_info,
+ .get = img_spdif_out_get_status,
+ .put = img_spdif_out_set_status
+ }
+};
+
+static int img_spdif_out_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+ u32 reg;
+ unsigned long flags;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+ reg |= IMG_SPDIF_OUT_CTL_SRT_MASK;
+ img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&spdif->lock, flags);
+ img_spdif_out_reset(spdif);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+ unsigned int channels;
+ long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
+ u32 reg;
+ snd_pcm_format_t format;
+
+ rate = params_rate(params);
+ format = params_format(params);
+ channels = params_channels(params);
+
+ dev_dbg(spdif->dev, "hw_params rate %ld channels %u format %u\n",
+ rate, channels, format);
+
+ if (format != SNDRV_PCM_FORMAT_S32_LE)
+ return -EINVAL;
+
+ if (channels != 2)
+ return -EINVAL;
+
+ pre_div_a = clk_round_rate(spdif->clk_ref, rate * 256);
+ if (pre_div_a < 0)
+ return pre_div_a;
+ pre_div_b = clk_round_rate(spdif->clk_ref, rate * 384);
+ if (pre_div_b < 0)
+ return pre_div_b;
+
+ diff_a = abs((pre_div_a / 256) - rate);
+ diff_b = abs((pre_div_b / 384) - rate);
+
+ /* If diffs are equal, use lower clock rate */
+ if (diff_a > diff_b)
+ clk_set_rate(spdif->clk_ref, pre_div_b);
+ else
+ clk_set_rate(spdif->clk_ref, pre_div_a);
+
+ /*
+ * Another driver (eg machine driver) may have rejected the above
+ * change. Get the current rate and set the register bit according to
+ * the new min diff
+ */
+ clk_rate = clk_get_rate(spdif->clk_ref);
+
+ diff_a = abs((clk_rate / 256) - rate);
+ diff_b = abs((clk_rate / 384) - rate);
+
+ reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+ if (diff_a <= diff_b)
+ reg &= ~IMG_SPDIF_OUT_CTL_CLK_MASK;
+ else
+ reg |= IMG_SPDIF_OUT_CTL_CLK_MASK;
+ img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
+ .trigger = img_spdif_out_trigger,
+ .hw_params = img_spdif_out_hw_params
+};
+
+static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
+{
+ struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
+
+ snd_soc_add_dai_controls(dai, img_spdif_out_controls,
+ ARRAY_SIZE(img_spdif_out_controls));
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver img_spdif_out_dai = {
+ .probe = img_spdif_out_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .ops = &img_spdif_out_dai_ops
+};
+
+static const struct snd_soc_component_driver img_spdif_out_component = {
+ .name = "img-spdif-out"
+};
+
+static int img_spdif_out_probe(struct platform_device *pdev)
+{
+ struct img_spdif_out *spdif;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+ struct device *dev = &pdev->dev;
+
+ spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+ if (!spdif)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, spdif);
+
+ spdif->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ spdif->base = base;
+
+ spdif->rst = devm_reset_control_get(&pdev->dev, "rst");
+ if (IS_ERR(spdif->rst)) {
+ if (PTR_ERR(spdif->rst) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "No top level reset found\n");
+ return PTR_ERR(spdif->rst);
+ }
+
+ spdif->clk_sys = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(spdif->clk_sys)) {
+ if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'sys'\n");
+ return PTR_ERR(spdif->clk_sys);
+ }
+
+ spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
+ if (IS_ERR(spdif->clk_ref)) {
+ if (PTR_ERR(spdif->clk_ref) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to acquire clock 'ref'\n");
+ return PTR_ERR(spdif->clk_ref);
+ }
+
+ ret = clk_prepare_enable(spdif->clk_sys);
+ if (ret)
+ return ret;
+
+ img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK,
+ IMG_SPDIF_OUT_CTL);
+
+ img_spdif_out_reset(spdif);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_spdif_out_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ spin_lock_init(&spdif->lock);
+
+ spdif->dma_data.addr = res->start + IMG_SPDIF_OUT_TX_FIFO;
+ spdif->dma_data.addr_width = 4;
+ spdif->dma_data.maxburst = 4;
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &img_spdif_out_component,
+ &img_spdif_out_dai, 1);
+ if (ret)
+ goto err_suspend;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_suspend;
+
+ dev_dbg(&pdev->dev, "Probe successful\n");
+
+ return 0;
+
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_spdif_out_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ clk_disable_unprepare(spdif->clk_sys);
+
+ return ret;
+}
+
+static int img_spdif_out_dev_remove(struct platform_device *pdev)
+{
+ struct img_spdif_out *spdif = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_spdif_out_suspend(&pdev->dev);
+
+ clk_disable_unprepare(spdif->clk_sys);
+
+ return 0;
+}
+
+static const struct of_device_id img_spdif_out_of_match[] = {
+ { .compatible = "img,spdif-out" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, img_spdif_out_of_match);
+
+static const struct dev_pm_ops img_spdif_out_pm_ops = {
+ SET_RUNTIME_PM_OPS(img_spdif_out_suspend,
+ img_spdif_out_resume, NULL)
+};
+
+static struct platform_driver img_spdif_out_driver = {
+ .driver = {
+ .name = "img-spdif-out",
+ .of_match_table = img_spdif_out_of_match,
+ .pm = &img_spdif_out_pm_ops
+ },
+ .probe = img_spdif_out_probe,
+ .remove = img_spdif_out_dev_remove
+};
+module_platform_driver(img_spdif_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG SPDIF Output driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
new file mode 100644
index 000000000000..162a0fd68c7b
--- /dev/null
+++ b/sound/soc/img/pistachio-internal-dac.c
@@ -0,0 +1,287 @@
+/*
+ * Pistachio internal dac driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define PISTACHIO_INTERNAL_DAC_CTRL 0x40
+#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK 0x2
+#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK 0x1
+
+#define PISTACHIO_INTERNAL_DAC_SRST 0x44
+#define PISTACHIO_INTERNAL_DAC_SRST_MASK 0x1
+
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL 0x48
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT 0
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK 0xFFF
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK 0x1000
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT 13
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK 0x1FE000
+
+#define PISTACHIO_INTERNAL_DAC_PWR 0x1
+#define PISTACHIO_INTERNAL_DAC_PWR_MASK 0x1
+
+#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct pistachio_internal_dac {
+ struct regmap *regmap;
+ struct regulator *supply;
+ bool mute;
+};
+
+static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = {
+ SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1)
+};
+
+static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("AOUTL"),
+ SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = {
+ { "AOUTL", NULL, "DAC" },
+ { "AOUTR", NULL, "DAC" },
+};
+
+static void pistachio_internal_dac_reg_writel(struct regmap *top_regs,
+ u32 val, u32 reg)
+{
+ regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+ PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK,
+ reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT);
+
+ regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+ PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK,
+ val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT);
+
+ regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+ PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK,
+ PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK);
+
+ regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+ PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0);
+}
+
+static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac)
+{
+ regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+ PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK,
+ PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK);
+
+ pistachio_internal_dac_reg_writel(dac->regmap, 0,
+ PISTACHIO_INTERNAL_DAC_PWR);
+}
+
+static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac)
+{
+ regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
+ PISTACHIO_INTERNAL_DAC_SRST_MASK,
+ PISTACHIO_INTERNAL_DAC_SRST_MASK);
+
+ regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
+ PISTACHIO_INTERNAL_DAC_SRST_MASK, 0);
+
+ pistachio_internal_dac_reg_writel(dac->regmap,
+ PISTACHIO_INTERNAL_DAC_PWR_MASK,
+ PISTACHIO_INTERNAL_DAC_PWR);
+
+ regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+ PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0);
+}
+
+static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
+ {
+ .name = "pistachio_internal_dac",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = PISTACHIO_INTERNAL_DAC_FORMATS,
+ }
+ },
+};
+
+static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec)
+{
+ struct pistachio_internal_dac *dac = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_codec_init_regmap(codec, dac->regmap);
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver pistachio_internal_dac_driver = {
+ .probe = pistachio_internal_dac_codec_probe,
+ .idle_bias_off = true,
+ .controls = pistachio_internal_dac_snd_controls,
+ .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls),
+ .dapm_widgets = pistachio_internal_dac_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets),
+ .dapm_routes = pistachio_internal_dac_routes,
+ .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes),
+};
+
+static int pistachio_internal_dac_probe(struct platform_device *pdev)
+{
+ struct pistachio_internal_dac *dac;
+ int ret, voltage;
+ struct device *dev = &pdev->dev;
+ u32 reg;
+
+ dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL);
+
+ if (!dac)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, dac);
+
+ dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "img,cr-top");
+ if (IS_ERR(dac->regmap))
+ return PTR_ERR(dac->regmap);
+
+ dac->supply = devm_regulator_get(dev, "VDD");
+ if (IS_ERR(dac->supply)) {
+ ret = PTR_ERR(dac->supply);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to acquire supply 'VDD-supply': %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(dac->supply);
+ if (ret) {
+ dev_err(dev, "failed to enable supply: %d\n", ret);
+ return ret;
+ }
+
+ voltage = regulator_get_voltage(dac->supply);
+
+ switch (voltage) {
+ case 1800000:
+ reg = 0;
+ break;
+ case 3300000:
+ reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK;
+ break;
+ default:
+ dev_err(dev, "invalid voltage: %d\n", voltage);
+ ret = -EINVAL;
+ goto err_regulator;
+ }
+
+ regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+ PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg);
+
+ pistachio_internal_dac_pwr_off(dac);
+ pistachio_internal_dac_pwr_on(dac);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ ret = snd_soc_register_codec(dev, &pistachio_internal_dac_driver,
+ pistachio_internal_dac_dais,
+ ARRAY_SIZE(pistachio_internal_dac_dais));
+ if (ret) {
+ dev_err(dev, "failed to register codec: %d\n", ret);
+ goto err_pwr;
+ }
+
+ return 0;
+
+err_pwr:
+ pm_runtime_disable(&pdev->dev);
+ pistachio_internal_dac_pwr_off(dac);
+err_regulator:
+ regulator_disable(dac->supply);
+
+ return ret;
+}
+
+static int pistachio_internal_dac_remove(struct platform_device *pdev)
+{
+ struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_codec(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pistachio_internal_dac_pwr_off(dac);
+ regulator_disable(dac->supply);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pistachio_internal_dac_rt_resume(struct device *dev)
+{
+ struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_enable(dac->supply);
+ if (ret) {
+ dev_err(dev, "failed to enable supply: %d\n", ret);
+ return ret;
+ }
+
+ pistachio_internal_dac_pwr_on(dac);
+
+ return 0;
+}
+
+static int pistachio_internal_dac_rt_suspend(struct device *dev)
+{
+ struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
+
+ pistachio_internal_dac_pwr_off(dac);
+
+ regulator_disable(dac->supply);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
+ SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
+ pistachio_internal_dac_rt_resume, NULL)
+};
+
+static const struct of_device_id pistachio_internal_dac_of_match[] = {
+ { .compatible = "img,pistachio-internal-dac" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match);
+
+static struct platform_driver pistachio_internal_dac_plat_driver = {
+ .driver = {
+ .name = "img-pistachio-internal-dac",
+ .of_match_table = pistachio_internal_dac_of_match,
+ .pm = &pistachio_internal_dac_pm_ops
+ },
+ .probe = pistachio_internal_dac_probe,
+ .remove = pistachio_internal_dac_remove
+};
+module_platform_driver(pistachio_internal_dac_plat_driver);
+
+MODULE_DESCRIPTION("Pistachio Internal DAC driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index d430ef5a4f38..803f95e40679 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -24,6 +24,7 @@ config SND_SST_IPC_PCI
config SND_SST_IPC_ACPI
tristate
select SND_SST_IPC
+ select SND_SOC_INTEL_SST
depends on ACPI
config SND_SOC_INTEL_SST
@@ -43,7 +44,7 @@ config SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
- depends on DW_DMAC_CORE
+ depends on DW_DMAC_CORE=y
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
@@ -56,18 +57,19 @@ config SND_SOC_INTEL_HASWELL_MACH
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C
- depends on DW_DMAC_CORE
+ depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n)
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
This adds audio driver for Intel Baytrail platform based boards
- with the RT5640 audio codec.
+ with the RT5640 audio codec. This driver is deprecated, use
+ SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality
config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C
- depends on DW_DMAC_CORE
+ depends on DW_DMAC_CORE=y
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
@@ -79,7 +81,7 @@ config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM
- depends on DW_DMAC_CORE
+ depends on DW_DMAC_CORE=y
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286
@@ -90,14 +92,26 @@ config SND_SOC_INTEL_BROADWELL_MACH
If unsure select "N".
config SND_SOC_INTEL_BYTCR_RT5640_MACH
- tristate "ASoC Audio DSP Support for MID BYT Platform"
+ tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
depends on X86 && I2C
select SND_SOC_RT5640
select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI
help
- This adds support for ASoC machine driver for Intel(R) MID Baytrail platform
- used as alsa device in audio substem in Intel(R) MID devices
+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+ platforms with RT5640 audio codec.
+ Say Y if you have such a device
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYTCR_RT5651_MACH
+ tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
+ depends on X86 && I2C
+ select SND_SOC_RT5651
+ select SND_SST_MFLD_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+ platforms with RT5651 audio codec.
Say Y if you have such a device
If unsure select "N".
@@ -154,3 +168,31 @@ config SND_SOC_INTEL_SKL_RT286_MACH
with RT286 I2S audio codec.
Say Y if you have such a device
If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
+ tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C
+ select SND_SOC_INTEL_SST
+ select SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_NAU8825
+ select SND_SOC_SSM4567
+ select SND_SOC_DMIC
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for NAU88L25 + SSM4567.
+ Say Y if you have such a device
+ If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
+ tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C
+ select SND_SOC_INTEL_SST
+ select SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_NAU8825
+ select SND_SOC_MAX98357A
+ select SND_SOC_DMIC
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for NAU88L25 + MAX98357A.
+ Say Y if you have such a device
+ If unsure select "N".
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index d55388e082e1..b97e6adcf1b2 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -443,7 +443,7 @@ static int sst_gain_get(struct snd_kcontrol *kcontrol,
break;
case SST_GAIN_MUTE:
- ucontrol->value.integer.value[0] = gv->mute ? 1 : 0;
+ ucontrol->value.integer.value[0] = gv->mute ? 0 : 1;
break;
case SST_GAIN_RAMP_DURATION:
@@ -479,7 +479,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
break;
case SST_GAIN_MUTE:
- gv->mute = !!ucontrol->value.integer.value[0];
+ gv->mute = !ucontrol->value.integer.value[0];
dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute);
break;
@@ -1109,6 +1109,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"media0_in", NULL, "Compress Playback"},
{"media1_in", NULL, "Headset Playback"},
{"media2_in", NULL, "pcm0_out"},
+ {"media3_in", NULL, "Deepbuffer Playback"},
{"media0_out mix 0", "media0_in Switch", "media0_in"},
{"media0_out mix 0", "media1_in Switch", "media1_in"},
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h
index 93de8045d4e1..e0113112f668 100644
--- a/sound/soc/intel/atom/sst-atom-controls.h
+++ b/sound/soc/intel/atom/sst-atom-controls.h
@@ -28,6 +28,7 @@
enum {
MERR_DPCM_AUDIO = 0,
+ MERR_DPCM_DEEP_BUFFER,
MERR_DPCM_COMPR,
};
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 0487cfaac538..55c33dc76ce4 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -98,6 +98,7 @@ static struct sst_dev_stream_map dpcm_strm_map[] = {
{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
{MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
+ {MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, SST_TASK_ID_MEDIA, 0},
};
static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
@@ -500,14 +501,25 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
.channels_min = SST_STEREO,
.channels_max = SST_STEREO,
.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
.capture = {
.stream_name = "Headset Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "deepbuffer-cpu-dai",
+ .ops = &sst_media_dai_ops,
+ .playback = {
+ .stream_name = "Deepbuffer Playback",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
},
{
@@ -516,10 +528,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
.ops = &sst_compr_dai_ops,
.playback = {
.stream_name = "Compress Playback",
- .channels_min = SST_STEREO,
- .channels_max = SST_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
},
},
/* BE CPU Dais */
@@ -760,15 +768,15 @@ static int sst_platform_remove(struct platform_device *pdev)
static int sst_soc_prepare(struct device *dev)
{
struct sst_data *drv = dev_get_drvdata(dev);
- int i;
+ struct snd_soc_pcm_runtime *rtd;
/* suspend all pcms first */
snd_soc_suspend(drv->soc_card->dev);
snd_soc_poweroff(drv->soc_card->dev);
/* set the SSPs to idle */
- for (i = 0; i < drv->soc_card->num_rtd; i++) {
- struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
+ struct snd_soc_dai *dai = rtd->cpu_dai;
if (dai->active) {
send_ssp_cmd(dai, dai->name, 0);
@@ -782,11 +790,11 @@ static int sst_soc_prepare(struct device *dev)
static void sst_soc_complete(struct device *dev)
{
struct sst_data *drv = dev_get_drvdata(dev);
- int i;
+ struct snd_soc_pcm_runtime *rtd;
/* restart SSPs */
- for (i = 0; i < drv->soc_card->num_rtd; i++) {
- struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
+ struct snd_soc_dai *dai = rtd->cpu_dai;
if (dai->active) {
sst_handle_vb_timer(dai, true);
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index bb19b5801466..4fce03fc1870 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -40,18 +40,9 @@
#include <acpi/acpi_bus.h>
#include "../sst-mfld-platform.h"
#include "../../common/sst-dsp.h"
+#include "../../common/sst-acpi.h"
#include "sst.h"
-struct sst_machines {
- char *codec_id;
- char board[32];
- char machine[32];
- void (*machine_quirk)(void);
- char firmware[FW_NAME_SIZE];
- struct sst_platform_info *pdata;
-
-};
-
/* LPE viewpoint addresses */
#define SST_BYT_IRAM_PHY_START 0xff2c0000
#define SST_BYT_IRAM_PHY_END 0xff2d4000
@@ -223,37 +214,16 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
return 0;
}
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- *(bool *)context = true;
- return AE_OK;
-}
-
-static struct sst_machines *sst_acpi_find_machine(
- struct sst_machines *machines)
-{
- struct sst_machines *mach;
- bool found = false;
-
- for (mach = machines; mach->codec_id; mach++)
- if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id,
- sst_acpi_mach_match,
- &found, NULL)) && found)
- return mach;
-
- return NULL;
-}
-
static int sst_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = 0;
struct intel_sst_drv *ctx;
const struct acpi_device_id *id;
- struct sst_machines *mach;
+ struct sst_acpi_mach *mach;
struct platform_device *mdev;
struct platform_device *plat_dev;
+ struct sst_platform_info *pdata;
unsigned int dev_id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
@@ -261,12 +231,13 @@ static int sst_acpi_probe(struct platform_device *pdev)
return -ENODEV;
dev_dbg(dev, "for %s", id->id);
- mach = (struct sst_machines *)id->driver_data;
+ mach = (struct sst_acpi_mach *)id->driver_data;
mach = sst_acpi_find_machine(mach);
if (mach == NULL) {
dev_err(dev, "No matching machine driver found\n");
return -ENODEV;
}
+ pdata = mach->pdata;
ret = kstrtouint(id->id, 16, &dev_id);
if (ret < 0) {
@@ -276,16 +247,23 @@ static int sst_acpi_probe(struct platform_device *pdev)
dev_dbg(dev, "ACPI device id: %x\n", dev_id);
- plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
+ plat_dev = platform_device_register_data(dev, pdata->platform, -1,
+ NULL, 0);
if (IS_ERR(plat_dev)) {
- dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
+ dev_err(dev, "Failed to create machine device: %s\n",
+ pdata->platform);
return PTR_ERR(plat_dev);
}
- /* Create platform device for sst machine driver */
- mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0);
+ /*
+ * Create platform device for sst machine driver,
+ * pass machine info as pdata
+ */
+ mdev = platform_device_register_data(dev, mach->drv_name, -1,
+ (const void *)mach, sizeof(*mach));
if (IS_ERR(mdev)) {
- dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
+ dev_err(dev, "Failed to create machine device: %s\n",
+ mach->drv_name);
return PTR_ERR(mdev);
}
@@ -294,8 +272,8 @@ static int sst_acpi_probe(struct platform_device *pdev)
return ret;
/* Fill sst platform data */
- ctx->pdata = mach->pdata;
- strcpy(ctx->firmware_name, mach->firmware);
+ ctx->pdata = pdata;
+ strcpy(ctx->firmware_name, mach->fw_filename);
ret = sst_platform_get_resources(ctx);
if (ret)
@@ -342,22 +320,28 @@ static int sst_acpi_remove(struct platform_device *pdev)
return 0;
}
-static struct sst_machines sst_acpi_bytcr[] = {
- {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
+static struct sst_acpi_mach sst_acpi_bytcr[] = {
+ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+ &byt_rvp_platform_data },
+ {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+ &byt_rvp_platform_data },
+ {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+ &byt_rvp_platform_data },
+ {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
&byt_rvp_platform_data },
{},
};
/* Cherryview-based platforms: CherryTrail and Braswell */
-static struct sst_machines sst_acpi_chv[] = {
- {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
+static struct sst_acpi_mach sst_acpi_chv[] = {
+ {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+ &chv_platform_data },
+ {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
- {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+ {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
- {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+ {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
- {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL,
- "intel/fw_sst_22a8.bin", &chv_platform_data },
{},
};
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index a74c64c7053c..4ccc80e5e8cc 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -108,7 +108,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
str_id, pipe_id);
ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
- &alloc_param, data, true, true, false, true);
+ &alloc_param, &data, true, true, false, true);
if (ret < 0) {
dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
index 79547bec558b..4765ad474544 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
@@ -377,6 +377,8 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
GFP_KERNEL);
+ if (!priv_data)
+ return -ENOMEM;
priv_data->byt = plat_data->dsp;
snd_soc_platform_set_drvdata(platform, priv_data);
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 371c4565cad8..3310c0f9c356 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -3,17 +3,23 @@ snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
snd-soc-sst-broadwell-objs := broadwell.o
snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
+snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
snd-soc-skl_rt286-objs := skl_rt286.o
+snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
+snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
+obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.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
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 7a5c9a36c1db..9a1752df45a9 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -20,51 +20,76 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/dmi.h>
#include <linux/slab.h>
-#include <linux/input.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/jack.h>
#include "../../codecs/rt5640.h"
#include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
-static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Int Mic", NULL),
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
};
-static const struct snd_soc_dapm_route byt_audio_map[] = {
- {"IN2P", NULL, "Headset Mic"},
- {"IN2N", NULL, "Headset Mic"},
- {"Headset Mic", NULL, "MICBIAS1"},
- {"IN1P", NULL, "MICBIAS1"},
- {"LDO2", NULL, "Int Mic"},
- {"Headphone", NULL, "HPOL"},
- {"Headphone", NULL, "HPOR"},
- {"Ext Spk", NULL, "SPOLP"},
- {"Ext Spk", NULL, "SPOLN"},
- {"Ext Spk", NULL, "SPORP"},
- {"Ext Spk", NULL, "SPORN"},
-
+static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
{"AIF1 Playback", NULL, "ssp2 Tx"},
{"ssp2 Tx", NULL, "codec_out0"},
{"ssp2 Tx", NULL, "codec_out1"},
{"codec_in0", NULL, "ssp2 Rx"},
{"codec_in1", NULL, "ssp2 Rx"},
{"ssp2 Rx", NULL, "AIF1 Capture"},
+
+ {"Headset Mic", NULL, "MICBIAS1"},
+ {"IN2P", NULL, "Headset Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Speaker", NULL, "SPOLP"},
+ {"Speaker", NULL, "SPOLN"},
+ {"Speaker", NULL, "SPORP"},
+ {"Speaker", NULL, "SPORN"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+ {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+ {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+ {"Internal Mic", NULL, "MICBIAS1"},
+ {"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+ BYT_RT5640_DMIC1_MAP,
+ BYT_RT5640_DMIC2_MAP,
+ BYT_RT5640_IN1_MAP,
};
-static const struct snd_kcontrol_new byt_mc_controls[] = {
+#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+ BYT_RT5640_DMIC_EN;
+
+static const struct snd_kcontrol_new byt_rt5640_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Int Mic"),
- SOC_DAPM_PIN_SWITCH("Ext Spk"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
};
-static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
+static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -92,7 +117,95 @@ static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_pcm_stream byt_dai_params = {
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+ byt_rt5640_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+ {
+ .callback = byt_rt5640_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+ },
+ .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+ },
+ {
+ .callback = byt_rt5640_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+ },
+ .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+ BYT_RT5640_DMIC_EN),
+ },
+ {
+ .callback = byt_rt5640_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
+ },
+ .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+ },
+ {}
+};
+
+static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+ struct snd_soc_codec *codec = runtime->codec;
+ struct snd_soc_card *card = runtime->card;
+ const struct snd_soc_dapm_route *custom_map;
+ int num_routes;
+
+ card->dapm.idle_bias_off = true;
+
+ rt5640_sel_asrc_clk_src(codec,
+ RT5640_DA_STEREO_FILTER |
+ RT5640_AD_STEREO_FILTER,
+ RT5640_CLK_SEL_ASRC);
+
+ ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
+ ARRAY_SIZE(byt_rt5640_controls));
+ if (ret) {
+ dev_err(card->dev, "unable to add card controls\n");
+ return ret;
+ }
+
+ dmi_check_system(byt_rt5640_quirk_table);
+ switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+ case BYT_RT5640_IN1_MAP:
+ custom_map = byt_rt5640_intmic_in1_map;
+ num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+ break;
+ case BYT_RT5640_DMIC2_MAP:
+ custom_map = byt_rt5640_intmic_dmic2_map;
+ num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+ break;
+ default:
+ custom_map = byt_rt5640_intmic_dmic1_map;
+ num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ if (ret)
+ return ret;
+
+ if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+ ret = rt5640_dmic_enable(codec, 0, 0);
+ if (ret)
+ return ret;
+ }
+
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+
+ return ret;
+}
+
+static const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
.formats = SNDRV_PCM_FMTBIT_S24_LE,
.rate_min = 48000,
.rate_max = 48000,
@@ -100,13 +213,14 @@ static const struct snd_soc_pcm_stream byt_dai_params = {
.channels_max = 2,
};
-static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+static int byt_rt5640_codec_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);
+ int ret;
/* The DSP will covert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
@@ -114,24 +228,46 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP2 to 24-bit */
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+ /*
+ * Default mode for SSP configuration is TDM 4 slot, override config
+ * with explicit setting to I2S 2ch 24-bit. The word length is set with
+ * dai_set_tdm_slot() since there is no other API exposed
+ */
+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBS_CFS
+ );
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+ return ret;
+ }
+
return 0;
}
-static int byt_aif1_startup(struct snd_pcm_substream *substream)
+static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream)
{
return snd_pcm_hw_constraint_single(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE, 48000);
}
-static struct snd_soc_ops byt_aif1_ops = {
- .startup = byt_aif1_startup,
+static struct snd_soc_ops byt_rt5640_aif1_ops = {
+ .startup = byt_rt5640_aif1_startup,
};
-static struct snd_soc_ops byt_be_ssp2_ops = {
- .hw_params = byt_aif1_hw_params,
+static struct snd_soc_ops byt_rt5640_be_ssp2_ops = {
+ .hw_params = byt_rt5640_aif1_hw_params,
};
-static struct snd_soc_dai_link byt_dailink[] = {
+static struct snd_soc_dai_link byt_rt5640_dais[] = {
[MERR_DPCM_AUDIO] = {
.name = "Baytrail Audio Port",
.stream_name = "Baytrail Audio",
@@ -143,7 +279,20 @@ static struct snd_soc_dai_link byt_dailink[] = {
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
- .ops = &byt_aif1_ops,
+ .ops = &byt_rt5640_aif1_ops,
+ },
+ [MERR_DPCM_DEEP_BUFFER] = {
+ .name = "Deep-Buffer Audio Port",
+ .stream_name = "Deep-Buffer Audio",
+ .cpu_dai_name = "deepbuffer-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .ignore_suspend = 1,
+ .nonatomic = true,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &byt_rt5640_aif1_ops,
},
[MERR_DPCM_COMPR] = {
.name = "Baytrail Compressed Port",
@@ -161,58 +310,69 @@ static struct snd_soc_dai_link byt_dailink[] = {
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
.codec_dai_name = "rt5640-aif1",
- .codec_name = "i2c-10EC5640:00",
+ .codec_name = "i2c-10EC5640:00", /* overwritten with HID */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
- .be_hw_params_fixup = byt_codec_fixup,
+ .be_hw_params_fixup = byt_rt5640_codec_fixup,
.ignore_suspend = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
- .ops = &byt_be_ssp2_ops,
+ .init = byt_rt5640_init,
+ .ops = &byt_rt5640_be_ssp2_ops,
},
};
/* SoC card */
-static struct snd_soc_card snd_soc_card_byt = {
- .name = "baytrailcraudio",
+static struct snd_soc_card byt_rt5640_card = {
+ .name = "bytcr-rt5640",
.owner = THIS_MODULE,
- .dai_link = byt_dailink,
- .num_links = ARRAY_SIZE(byt_dailink),
- .dapm_widgets = byt_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
- .dapm_routes = byt_audio_map,
- .num_dapm_routes = ARRAY_SIZE(byt_audio_map),
- .controls = byt_mc_controls,
- .num_controls = ARRAY_SIZE(byt_mc_controls),
+ .dai_link = byt_rt5640_dais,
+ .num_links = ARRAY_SIZE(byt_rt5640_dais),
+ .dapm_widgets = byt_rt5640_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
+ .dapm_routes = byt_rt5640_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+ .fully_routed = true,
};
-static int snd_byt_mc_probe(struct platform_device *pdev)
+static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+
+static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
{
int ret_val = 0;
+ struct sst_acpi_mach *mach;
/* register the soc card */
- snd_soc_card_byt.dev = &pdev->dev;
+ byt_rt5640_card.dev = &pdev->dev;
+ mach = byt_rt5640_card.dev->platform_data;
+
+ /* fixup codec name based on HID */
+ snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
+ "%s%s%s", "i2c-", mach->id, ":00");
+ byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name;
+
+ ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
- ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
if (ret_val) {
- dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
+ dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
+ ret_val);
return ret_val;
}
- platform_set_drvdata(pdev, &snd_soc_card_byt);
+ platform_set_drvdata(pdev, &byt_rt5640_card);
return ret_val;
}
-static struct platform_driver snd_byt_mc_driver = {
+static struct platform_driver snd_byt_rt5640_mc_driver = {
.driver = {
- .name = "bytt100_rt5640",
+ .name = "bytcr_rt5640",
.pm = &snd_soc_pm_ops,
},
- .probe = snd_byt_mc_probe,
+ .probe = snd_byt_rt5640_mc_probe,
};
-module_platform_driver(snd_byt_mc_driver);
+module_platform_driver(snd_byt_rt5640_mc_driver);
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bytt100_rt5640");
+MODULE_ALIAS("platform:bytcr_rt5640");
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
new file mode 100644
index 000000000000..1c95ccc886c4
--- /dev/null
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -0,0 +1,332 @@
+/*
+ * bytcr_rt5651.c - ASoc Machine driver for Intel Byt CR platform
+ * (derived from bytcr_rt5640.c)
+ *
+ * Copyright (C) 2015 Intel 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5651.h"
+#include "../atom/sst-atom-controls.h"
+
+static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
+ {"AIF1 Playback", NULL, "ssp2 Tx"},
+ {"ssp2 Tx", NULL, "codec_out0"},
+ {"ssp2 Tx", NULL, "codec_out1"},
+ {"codec_in0", NULL, "ssp2 Rx"},
+ {"codec_in1", NULL, "ssp2 Rx"},
+ {"ssp2 Rx", NULL, "AIF1 Capture"},
+
+ {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
+ {"IN2P", NULL, "Headset Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Speaker", NULL, "LOUTL"},
+ {"Speaker", NULL, "LOUTR"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = {
+ {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = {
+ {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = {
+ {"Internal Mic", NULL, "micbias1"},
+ {"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+ BYT_RT5651_DMIC1_MAP,
+ BYT_RT5651_DMIC2_MAP,
+ BYT_RT5651_IN1_MAP,
+};
+
+#define BYT_RT5651_MAP(quirk) ((quirk) & 0xff)
+#define BYT_RT5651_DMIC_EN BIT(16)
+
+static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP |
+ BYT_RT5651_DMIC_EN;
+
+static const struct snd_kcontrol_new byt_rt5651_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int byt_rt5651_aif1_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;
+
+ snd_soc_dai_set_bclk_ratio(codec_dai, 50);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec clock %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1,
+ params_rate(params) * 50,
+ params_rate(params) * 512);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dmi_system_id byt_rt5651_quirk_table[] = {
+ {}
+};
+
+static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+ struct snd_soc_card *card = runtime->card;
+ const struct snd_soc_dapm_route *custom_map;
+ int num_routes;
+
+ card->dapm.idle_bias_off = true;
+
+ dmi_check_system(byt_rt5651_quirk_table);
+ switch (BYT_RT5651_MAP(byt_rt5651_quirk)) {
+ case BYT_RT5651_IN1_MAP:
+ custom_map = byt_rt5651_intmic_in1_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map);
+ break;
+ case BYT_RT5651_DMIC2_MAP:
+ custom_map = byt_rt5651_intmic_dmic2_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map);
+ break;
+ default:
+ custom_map = byt_rt5651_intmic_dmic1_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map);
+ }
+
+ ret = snd_soc_add_card_controls(card, byt_rt5651_controls,
+ ARRAY_SIZE(byt_rt5651_controls));
+ if (ret) {
+ dev_err(card->dev, "unable to add card controls\n");
+ return ret;
+ }
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+
+ return ret;
+}
+
+static const struct snd_soc_pcm_stream byt_rt5651_dai_params = {
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int byt_rt5651_codec_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);
+ int ret;
+
+ /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP2 to 24-bit */
+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+ /*
+ * Default mode for SSP configuration is TDM 4 slot, override config
+ * with explicit setting to I2S 2ch 24-bit. The word length is set with
+ * dai_set_tdm_slot() since there is no other API exposed
+ */
+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBS_CFS
+ );
+
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static unsigned int rates_48000[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+ .count = ARRAY_SIZE(rates_48000),
+ .list = rates_48000,
+};
+
+static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_48000);
+}
+
+static struct snd_soc_ops byt_rt5651_aif1_ops = {
+ .startup = byt_rt5651_aif1_startup,
+};
+
+static struct snd_soc_ops byt_rt5651_be_ssp2_ops = {
+ .hw_params = byt_rt5651_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link byt_rt5651_dais[] = {
+ [MERR_DPCM_AUDIO] = {
+ .name = "Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "media-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .ignore_suspend = 1,
+ .nonatomic = true,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &byt_rt5651_aif1_ops,
+ },
+ [MERR_DPCM_DEEP_BUFFER] = {
+ .name = "Deep-Buffer Audio Port",
+ .stream_name = "Deep-Buffer Audio",
+ .cpu_dai_name = "deepbuffer-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .ignore_suspend = 1,
+ .nonatomic = true,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &byt_rt5651_aif1_ops,
+ },
+ [MERR_DPCM_COMPR] = {
+ .name = "Compressed Port",
+ .stream_name = "Compress",
+ .cpu_dai_name = "compress-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ },
+ /* CODEC<->CODEC link */
+ /* back ends */
+ {
+ .name = "SSP2-Codec",
+ .be_id = 1,
+ .cpu_dai_name = "ssp2-port",
+ .platform_name = "sst-mfld-platform",
+ .no_pcm = 1,
+ .codec_dai_name = "rt5651-aif1",
+ .codec_name = "i2c-10EC5651:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBS_CFS,
+ .be_hw_params_fixup = byt_rt5651_codec_fixup,
+ .ignore_suspend = 1,
+ .nonatomic = true,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .init = byt_rt5651_init,
+ .ops = &byt_rt5651_be_ssp2_ops,
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card byt_rt5651_card = {
+ .name = "bytcr-rt5651",
+ .owner = THIS_MODULE,
+ .dai_link = byt_rt5651_dais,
+ .num_links = ARRAY_SIZE(byt_rt5651_dais),
+ .dapm_widgets = byt_rt5651_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(byt_rt5651_widgets),
+ .dapm_routes = byt_rt5651_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map),
+ .fully_routed = true,
+};
+
+static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
+{
+ int ret_val = 0;
+
+ /* register the soc card */
+ byt_rt5651_card.dev = &pdev->dev;
+
+ ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
+
+ if (ret_val) {
+ dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
+ ret_val);
+ return ret_val;
+ }
+ platform_set_drvdata(pdev, &byt_rt5651_card);
+ return ret_val;
+}
+
+static struct platform_driver snd_byt_rt5651_mc_driver = {
+ .driver = {
+ .name = "bytcr_rt5651",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = snd_byt_rt5651_mc_probe,
+};
+
+module_platform_driver(snd_byt_rt5651_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver for RT5651");
+MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcr_rt5651");
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 4e2fcf188dd1..90588d6e64fc 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -41,12 +41,9 @@ struct cht_mc_private {
static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
{
- int i;
+ struct snd_soc_pcm_runtime *rtd;
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd;
-
- rtd = card->rtd + i;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
strlen(CHT_CODEC_DAI)))
return rtd->codec_dai;
@@ -235,6 +232,18 @@ static struct snd_soc_dai_link cht_dailink[] = {
.dpcm_capture = 1,
.ops = &cht_aif1_ops,
},
+ [MERR_DPCM_DEEP_BUFFER] = {
+ .name = "Deep-Buffer Audio Port",
+ .stream_name = "Deep-Buffer Audio",
+ .cpu_dai_name = "deepbuffer-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .nonatomic = true,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &cht_aif1_ops,
+ },
[MERR_DPCM_COMPR] = {
.name = "Compressed Port",
.stream_name = "Compress",
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 38d65a3529c4..2d3afddb0a2e 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -47,12 +47,9 @@ struct cht_mc_private {
static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
{
- int i;
-
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_pcm_runtime *rtd;
- rtd = card->rtd + i;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
strlen(CHT_CODEC_DAI)))
return rtd->codec_dai;
@@ -263,6 +260,18 @@ static struct snd_soc_dai_link cht_dailink[] = {
.dpcm_capture = 1,
.ops = &cht_aif1_ops,
},
+ [MERR_DPCM_DEEP_BUFFER] = {
+ .name = "Deep-Buffer Audio Port",
+ .stream_name = "Deep-Buffer Audio",
+ .cpu_dai_name = "deepbuffer-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .nonatomic = true,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &cht_aif1_ops,
+ },
[MERR_DPCM_COMPR] = {
.name = "Compressed Port",
.stream_name = "Compress",
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 5621ccd92992..2e5347f8f96c 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -46,12 +46,9 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
{
- int i;
+ struct snd_soc_pcm_runtime *rtd;
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd;
-
- rtd = card->rtd + i;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
strlen(CHT_CODEC_DAI)))
return rtd->codec_dai;
@@ -251,6 +248,18 @@ static struct snd_soc_dai_link cht_dailink[] = {
.dpcm_capture = 1,
.ops = &cht_aif1_ops,
},
+ [MERR_DPCM_DEEP_BUFFER] = {
+ .name = "Deep-Buffer Audio Port",
+ .stream_name = "Deep-Buffer Audio",
+ .cpu_dai_name = "deepbuffer-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .nonatomic = true,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .ops = &cht_aif1_ops,
+ },
[MERR_DPCM_COMPR] = {
.name = "Compressed Port",
.stream_name = "Compress",
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
new file mode 100644
index 000000000000..ab7da9c304b2
--- /dev/null
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -0,0 +1,485 @@
+/*
+ * Intel Skylake I2S Machine Driver with MAXIM98357A
+ * and NAU88L25
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+#define SKL_MAXIM_CODEC_DAI "HiFi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd;
+
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+
+ if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+ strlen(SKL_NUVOTON_CODEC_DAI)))
+ return rtd->codec_dai;
+ }
+
+ return NULL;
+}
+
+static int platform_clock_control(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 snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = skl_get_codec_dai(card);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ }
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Spk", NULL),
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+ SND_SOC_DAPM_SINK("WoV Sink"),
+ SND_SOC_DAPM_SPK("DP", NULL),
+ SND_SOC_DAPM_SPK("HDMI", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route skylake_map[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* speaker */
+ { "Spk", NULL, "Speaker" },
+
+ /* other jacks */
+ { "MIC", NULL, "Headset Mic" },
+ { "DMic", NULL, "SoC DMIC" },
+
+ {"WoV Sink", NULL, "hwd_in sink"},
+ {"HDMI", NULL, "hif5 Output"},
+ {"DP", NULL, "hif6 Output"},
+
+ /* CODEC BE connections */
+ { "HiFi Playback", NULL, "ssp0 Tx" },
+ { "ssp0 Tx", NULL, "codec0_out" },
+
+ { "Playback", NULL, "ssp1 Tx" },
+ { "ssp1 Tx", NULL, "codec1_out" },
+
+ { "codec0_in", NULL, "ssp1 Rx" },
+ { "ssp1 Rx", NULL, "Capture" },
+
+ /* DMIC */
+ { "dmic01_hifi", NULL, "DMIC01 Rx" },
+ { "DMIC01 Rx", NULL, "DMIC AIF" },
+ { "hifi1", NULL, "iDisp Tx"},
+ { "iDisp Tx", NULL, "iDisp_out"},
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int skylake_ssp_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 covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+ NULL, 0);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ nau8825_enable_jack_detect(codec, &skylake_headset);
+
+ snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+ snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
+ return ret;
+}
+
+static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dapm_context *dapm;
+ struct snd_soc_component *component = rtd->cpu_dai->component;
+
+ dapm = snd_soc_component_get_dapm(component);
+ snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+ return 0;
+}
+
+static unsigned int rates[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static unsigned int channels[] = {
+ 2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int skl_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 = 2;
+ 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 skylake_nau8825_fe_ops = {
+ .startup = skl_fe_startup,
+};
+
+static int skylake_nau8825_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,
+ NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+ if (ret < 0)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+ .hw_params = skylake_nau8825_hw_params,
+};
+
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (params_channels(params) == 2)
+ channels->min = channels->max = 2;
+ else
+ channels->min = channels->max = 4;
+
+ return 0;
+}
+
+static unsigned int channels_dmic[] = {
+ 2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+ .count = ARRAY_SIZE(channels_dmic),
+ .list = channels_dmic,
+ .mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_max = 4;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_dmic_channels);
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+ .startup = skylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+ 16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+ .count = ARRAY_SIZE(rates_16000),
+ .list = rates_16000,
+};
+
+static int skylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+ .startup = skylake_refcap_startup,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+ /* Front End DAI links */
+ {
+ .name = "Skl 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,
+ .init = skylake_nau8825_fe_init,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .ops = &skylake_nau8825_fe_ops,
+ },
+ {
+ .name = "Skl 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 = &skylake_nau8825_fe_ops,
+ },
+ {
+ .name = "Skl Audio Reference cap",
+ .stream_name = "Wake on Voice",
+ .cpu_dai_name = "Reference Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &skylaye_refcap_ops,
+ },
+ {
+ .name = "Skl Audio DMIC cap",
+ .stream_name = "dmiccap",
+ .cpu_dai_name = "DMIC Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &skylake_dmic_ops,
+ },
+ {
+ .name = "Skl HDMI Port",
+ .stream_name = "Hdmi",
+ .cpu_dai_name = "HDMI Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "SSP0-Codec",
+ .be_id = 0,
+ .cpu_dai_name = "SSP0 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "MX98357A:00",
+ .codec_dai_name = SKL_MAXIM_CODEC_DAI,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = skylake_ssp_fixup,
+ .dpcm_playback = 1,
+ },
+ {
+ /* SSP1 - Codec */
+ .name = "SSP1-Codec",
+ .be_id = 0,
+ .cpu_dai_name = "SSP1 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "i2c-10508825:00",
+ .codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+ .init = skylake_nau8825_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 = skylake_ssp_fixup,
+ .ops = &skylake_nau8825_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "dmic01",
+ .be_id = 1,
+ .cpu_dai_name = "DMIC01 Pin",
+ .codec_name = "dmic-codec",
+ .codec_dai_name = "dmic-hifi",
+ .platform_name = "0000:00:1f.3",
+ .be_hw_params_fixup = skylake_dmic_fixup,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp",
+ .be_id = 3,
+ .cpu_dai_name = "iDisp Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+ .name = "sklnau8825max",
+ .owner = THIS_MODULE,
+ .dai_link = skylake_dais,
+ .num_links = ARRAY_SIZE(skylake_dais),
+ .controls = skylake_controls,
+ .num_controls = ARRAY_SIZE(skylake_controls),
+ .dapm_widgets = skylake_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+ .dapm_routes = skylake_map,
+ .num_dapm_routes = ARRAY_SIZE(skylake_map),
+ .fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+ skylake_audio_card.dev = &pdev->dev;
+
+ return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+ .probe = skylake_audio_probe,
+ .driver = {
+ .name = "skl_nau88l25_max98357a_i2s",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode");
+MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s");
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
new file mode 100644
index 000000000000..c071812f31e5
--- /dev/null
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -0,0 +1,536 @@
+/*
+ * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd;
+
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+
+ if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+ strlen(SKL_NUVOTON_CODEC_DAI)))
+ return rtd->codec_dai;
+ }
+
+ return NULL;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Left Speaker"),
+ SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int platform_clock_control(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 snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = skl_get_codec_dai(card);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ }
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Left Speaker", NULL),
+ SND_SOC_DAPM_SPK("Right Speaker", NULL),
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+ SND_SOC_DAPM_SINK("WoV Sink"),
+ SND_SOC_DAPM_SPK("DP", NULL),
+ SND_SOC_DAPM_SPK("HDMI", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route skylake_map[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ {"Headphone Jack", NULL, "HPOL"},
+ {"Headphone Jack", NULL, "HPOR"},
+
+ /* speaker */
+ {"Left Speaker", NULL, "Left OUT"},
+ {"Right Speaker", NULL, "Right OUT"},
+
+ /* other jacks */
+ {"MIC", NULL, "Headset Mic"},
+ {"DMic", NULL, "SoC DMIC"},
+
+ {"WoV Sink", NULL, "hwd_in sink"},
+
+ {"HDMI", NULL, "hif5 Output"},
+ {"DP", NULL, "hif6 Output"},
+ /* CODEC BE connections */
+ { "Left Playback", NULL, "ssp0 Tx"},
+ { "Right Playback", NULL, "ssp0 Tx"},
+ { "ssp0 Tx", NULL, "codec0_out"},
+
+ { "Playback", NULL, "ssp1 Tx"},
+ { "ssp1 Tx", NULL, "codec1_out"},
+
+ { "codec0_in", NULL, "ssp1 Rx" },
+ { "ssp1 Rx", NULL, "Capture" },
+
+ /* DMIC */
+ { "dmic01_hifi", NULL, "DMIC01 Rx" },
+ { "DMIC01 Rx", NULL, "DMIC AIF" },
+ { "hifi1", NULL, "iDisp Tx"},
+ { "iDisp Tx", NULL, "iDisp_out"},
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_codec_conf ssm4567_codec_conf[] = {
+ {
+ .dev_name = "i2c-INT343B:00",
+ .name_prefix = "Left",
+ },
+ {
+ .dev_name = "i2c-INT343B:01",
+ .name_prefix = "Right",
+ },
+};
+
+static struct snd_soc_dai_link_component ssm4567_codec_components[] = {
+ { /* Left */
+ .name = "i2c-INT343B:00",
+ .dai_name = SKL_SSM_CODEC_DAI,
+ },
+ { /* Right */
+ .name = "i2c-INT343B:01",
+ .dai_name = SKL_SSM_CODEC_DAI,
+ },
+};
+
+static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
+ /* Slot 1 for left */
+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x01, 0x01, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ /* Slot 2 for right */
+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x02, 0x02, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /*
+ * 4 buttons here map to the google Reference headset
+ * The use of these buttons can be decided by the user space.
+ */
+ ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+ NULL, 0);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ nau8825_enable_jack_detect(codec, &skylake_headset);
+
+ snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+ snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
+ return ret;
+}
+
+static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dapm_context *dapm;
+ struct snd_soc_component *component = rtd->cpu_dai->component;
+
+ dapm = snd_soc_component_get_dapm(component);
+ snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+ return 0;
+}
+
+static unsigned int rates[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static unsigned int channels[] = {
+ 2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int skl_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 = 2;
+ 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 skylake_nau8825_fe_ops = {
+ .startup = skl_fe_startup,
+};
+
+static int skylake_ssp_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 covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ if (params_channels(params) == 2)
+ channels->min = channels->max = 2;
+ else
+ channels->min = channels->max = 4;
+
+ return 0;
+}
+
+static int skylake_nau8825_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,
+ NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+ if (ret < 0)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+ .hw_params = skylake_nau8825_hw_params,
+};
+
+static unsigned int channels_dmic[] = {
+ 2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+ .count = ARRAY_SIZE(channels_dmic),
+ .list = channels_dmic,
+ .mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_max = 4;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_dmic_channels);
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+ .startup = skylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+ 16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+ .count = ARRAY_SIZE(rates_16000),
+ .list = rates_16000,
+};
+
+static int skylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+ .startup = skylake_refcap_startup,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+ /* Front End DAI links */
+ {
+ .name = "Skl 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,
+ .init = skylake_nau8825_fe_init,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .ops = &skylake_nau8825_fe_ops,
+ },
+ {
+ .name = "Skl 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 = &skylake_nau8825_fe_ops,
+ },
+ {
+ .name = "Skl Audio Reference cap",
+ .stream_name = "Wake on Voice",
+ .cpu_dai_name = "Reference Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &skylaye_refcap_ops,
+ },
+ {
+ .name = "Skl Audio DMIC cap",
+ .stream_name = "dmiccap",
+ .cpu_dai_name = "DMIC Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &skylake_dmic_ops,
+ },
+ {
+ .name = "Skl HDMI Port",
+ .stream_name = "Hdmi",
+ .cpu_dai_name = "HDMI Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "SSP0-Codec",
+ .be_id = 0,
+ .cpu_dai_name = "SSP0 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codecs = ssm4567_codec_components,
+ .num_codecs = ARRAY_SIZE(ssm4567_codec_components),
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .init = skylake_ssm4567_codec_init,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = skylake_ssp_fixup,
+ .dpcm_playback = 1,
+ },
+ {
+ /* SSP1 - Codec */
+ .name = "SSP1-Codec",
+ .be_id = 0,
+ .cpu_dai_name = "SSP1 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "i2c-10508825:00",
+ .codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+ .init = skylake_nau8825_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 = skylake_ssp_fixup,
+ .ops = &skylake_nau8825_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "dmic01",
+ .be_id = 1,
+ .cpu_dai_name = "DMIC01 Pin",
+ .codec_name = "dmic-codec",
+ .codec_dai_name = "dmic-hifi",
+ .platform_name = "0000:00:1f.3",
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = skylake_dmic_fixup,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp",
+ .be_id = 3,
+ .cpu_dai_name = "iDisp Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+ .name = "sklnau8825adi",
+ .owner = THIS_MODULE,
+ .dai_link = skylake_dais,
+ .num_links = ARRAY_SIZE(skylake_dais),
+ .controls = skylake_controls,
+ .num_controls = ARRAY_SIZE(skylake_controls),
+ .dapm_widgets = skylake_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+ .dapm_routes = skylake_map,
+ .num_dapm_routes = ARRAY_SIZE(skylake_map),
+ .codec_conf = ssm4567_codec_conf,
+ .num_configs = ARRAY_SIZE(ssm4567_codec_conf),
+ .fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+ skylake_audio_card.dev = &pdev->dev;
+
+ return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+ .probe = skylake_audio_probe,
+ .driver = {
+ .name = "skl_nau88l25_ssm4567_i2s",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
+MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
+MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
+MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s");
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index a73a431bd8b7..7396ddb427d8 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -52,6 +52,7 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("DMIC2", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+ SND_SOC_DAPM_SINK("WoV Sink"),
};
static const struct snd_soc_dapm_route skylake_rt286_map[] = {
@@ -67,7 +68,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
/* digital mics */
{"DMIC1 Pin", NULL, "DMIC2"},
- {"DMIC AIF", NULL, "SoC DMIC"},
+ {"DMic", NULL, "SoC DMIC"},
+
+ {"WoV Sink", NULL, "hwd_in sink"},
/* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp0 Tx"},
@@ -79,13 +82,24 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{ "ssp0 Rx", NULL, "AIF1 Capture" },
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "Capture" },
+ { "DMIC01 Rx", NULL, "DMIC AIF" },
{ "hif1", NULL, "iDisp Tx"},
{ "iDisp Tx", NULL, "iDisp_out"},
};
+static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dapm_context *dapm;
+ struct snd_soc_component *component = rtd->cpu_dai->component;
+
+ dapm = snd_soc_component_get_dapm(component);
+ snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+ return 0;
+}
+
static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
@@ -101,9 +115,59 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
rt286_mic_detect(codec, &skylake_headset);
+ snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+ snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
return 0;
}
+static unsigned int rates[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static unsigned int channels[] = {
+ 2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int skl_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 = 2;
+ 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 skylake_rt286_fe_ops = {
+ .startup = skl_fe_startup,
+};
static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
@@ -112,12 +176,15 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
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 output is 48KHz, stereo, 16bits */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
- params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
@@ -140,6 +207,42 @@ static struct snd_soc_ops skylake_rt286_ops = {
.hw_params = skylake_rt286_hw_params,
};
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ channels->min = channels->max = 4;
+
+ return 0;
+}
+
+static unsigned int channels_dmic[] = {
+ 2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+ .count = ARRAY_SIZE(channels_dmic),
+ .list = channels_dmic,
+ .mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_max = 4;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_dmic_channels);
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+ .startup = skylake_dmic_startup,
+};
+
/* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_rt286_dais[] = {
/* Front End DAI links */
@@ -152,11 +255,13 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
+ .init = skylake_rt286_fe_init,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST
},
.dpcm_playback = 1,
+ .ops = &skylake_rt286_fe_ops,
},
{
.name = "Skl Audio Capture Port",
@@ -172,6 +277,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
SND_SOC_DPCM_TRIGGER_POST
},
.dpcm_capture = 1,
+ .ops = &skylake_rt286_fe_ops,
},
{
.name = "Skl Audio Reference cap",
@@ -186,6 +292,19 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.nonatomic = 1,
.dynamic = 1,
},
+ {
+ .name = "Skl Audio DMIC cap",
+ .stream_name = "dmiccap",
+ .cpu_dai_name = "DMIC Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &skylake_dmic_ops,
+ },
/* Back End DAI links */
{
@@ -201,7 +320,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
- .ignore_suspend = 1,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = skylake_ssp0_fixup,
.ops = &skylake_rt286_ops,
@@ -215,6 +333,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi",
.platform_name = "0000:00:1f.3",
+ .be_hw_params_fixup = skylake_dmic_fixup,
.ignore_suspend = 1,
.dpcm_capture = 1,
.no_pcm = 1,
@@ -247,6 +366,7 @@ static struct platform_driver skylake_audio = {
.probe = skylake_audio_probe,
.driver = {
.name = "skl_alc286s_i2s",
+ .pm = &snd_soc_pm_ops,
},
};
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index d9105584c51f..668fdeee195e 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,11 +1,13 @@
snd-soc-sst-dsp-objs := sst-dsp.o
-snd-soc-sst-acpi-objs := sst-acpi.o
+ifneq ($(CONFIG_SND_SST_IPC_ACPI),)
+snd-soc-sst-acpi-objs := sst-match-acpi.o
+else
+snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o
+endif
+
snd-soc-sst-ipc-objs := sst-ipc.o
-ifneq ($(CONFIG_DW_DMAC_CORE),)
-snd-soc-sst-dsp-objs += sst-firmware.o
-endif
+snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
-
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 67b6d3d52f57..7a85c576dad3 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -21,21 +21,12 @@
#include <linux/platform_device.h>
#include "sst-dsp.h"
+#include "sst-acpi.h"
#define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
#define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
#define SST_LPT_DSP_DMA_SIZE (1024 - 1)
-/* Descriptor for SST ASoC machine driver */
-struct sst_acpi_mach {
- /* ACPI ID for the matching machine driver. Audio codec for instance */
- const u8 id[ACPI_ID_LEN];
- /* machine driver name */
- const char *drv_name;
- /* firmware file name */
- const char *fw_filename;
-};
-
/* Descriptor for setting up SST platform data */
struct sst_acpi_desc {
const char *drv_name;
@@ -88,28 +79,6 @@ static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
return;
}
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- *(bool *)context = true;
- return AE_OK;
-}
-
-static struct sst_acpi_mach *sst_acpi_find_machine(
- struct sst_acpi_mach *machines)
-{
- struct sst_acpi_mach *mach;
- bool found = false;
-
- for (mach = machines; mach->id[0]; mach++)
- if (ACPI_SUCCESS(acpi_get_devices(mach->id,
- sst_acpi_mach_match,
- &found, NULL)) && found)
- return mach;
-
- return NULL;
-}
-
static int sst_acpi_probe(struct platform_device *pdev)
{
const struct acpi_device_id *id;
@@ -211,7 +180,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
}
static struct sst_acpi_mach haswell_machines[] = {
- { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+ { "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL },
{}
};
@@ -229,7 +198,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
};
static struct sst_acpi_mach broadwell_machines[] = {
- { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+ { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
{}
};
@@ -247,8 +216,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
};
static struct sst_acpi_mach baytrail_machines[] = {
- { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
- { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+ { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
+ { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
{}
};
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
new file mode 100644
index 000000000000..3ee3b7ab5d03
--- /dev/null
+++ b/sound/soc/intel/common/sst-acpi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013-15, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/acpi.h>
+
+/* acpi match */
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
+
+/* Descriptor for SST ASoC machine driver */
+struct sst_acpi_mach {
+ /* ACPI ID for the matching machine driver. Audio codec for instance */
+ const u8 id[ACPI_ID_LEN];
+ /* machine driver name */
+ const char *drv_name;
+ /* firmware file name */
+ const char *fw_filename;
+
+ /* board name */
+ const char *board;
+ void (*machine_quirk)(void);
+ void *pdata;
+};
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 2151652d37b7..81aa1ed64201 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -243,7 +243,7 @@ struct sst_mem_block {
u32 size; /* block size */
u32 index; /* block index 0..N */
enum sst_mem_type type; /* block memory type IRAM/DRAM */
- struct sst_block_ops *ops; /* block operations, if any */
+ const struct sst_block_ops *ops;/* block operations, if any */
/* block status */
u32 bytes_used; /* bytes in use by modules */
@@ -308,6 +308,8 @@ struct sst_dsp {
/* SKL data */
+ const char *fw_name;
+
/* To allocate CL dma buffers */
struct skl_dsp_loader_ops dsp_ops;
struct skl_dsp_fw_ops fw_ops;
@@ -376,8 +378,8 @@ void sst_block_free_scratch(struct sst_dsp *dsp);
/* Register the DSPs memory blocks - would be nice to read from ACPI */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
- u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
- void *private);
+ u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+ u32 index, void *private);
void sst_mem_block_unregister_all(struct sst_dsp *dsp);
/* Create/Free DMA resources */
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
index c9452e02e0dd..b5bbdf4fe93a 100644
--- a/sound/soc/intel/common/sst-dsp.c
+++ b/sound/soc/intel/common/sst-dsp.c
@@ -420,7 +420,7 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
}
EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
-#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
+#ifdef CONFIG_DW_DMAC_CORE
struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
{
diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h
index 859f0de00339..0b84c719ec48 100644
--- a/sound/soc/intel/common/sst-dsp.h
+++ b/sound/soc/intel/common/sst-dsp.h
@@ -216,7 +216,7 @@ struct sst_pdata {
void *dsp;
};
-#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
+#ifdef CONFIG_DW_DMAC_CORE
/* Initialization */
struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
index 1636a1eeb002..ef4881e7753a 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -51,8 +51,22 @@ struct sst_dma {
static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
{
+ u32 tmp = 0;
+ int i, m, n;
+ const u8 *src_byte = src;
+
+ m = bytes / 4;
+ n = bytes % 4;
+
/* __iowrite32_copy use 32bit size values so divide by 4 */
- __iowrite32_copy((void *)dest, src, bytes/4);
+ __iowrite32_copy((void *)dest, src, m);
+
+ if (n) {
+ for (i = 0; i < n; i++)
+ tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8);
+ __iowrite32_copy((void *)(dest + m * 4), &tmp, 1);
+ }
+
}
static void sst_dma_transfer_complete(void *arg)
@@ -1014,8 +1028,8 @@ EXPORT_SYMBOL_GPL(sst_module_runtime_restore);
/* register a DSP memory block for use with FW based modules */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
- u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
- void *private)
+ u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+ u32 index, void *private)
{
struct sst_mem_block *block;
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c
new file mode 100644
index 000000000000..dd077e116d25
--- /dev/null
+++ b/sound/soc/intel/common/sst-match-acpi.c
@@ -0,0 +1,43 @@
+/*
+ * sst_match_apci.c - SST (LPE) match for ACPI enumeration.
+ *
+ * Copyright (c) 2013-15, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-acpi.h"
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+ void *context, void **ret)
+{
+ *(bool *)context = true;
+ return AE_OK;
+}
+
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
+{
+ struct sst_acpi_mach *mach;
+ bool found = false;
+
+ for (mach = machines; mach->id[0]; mach++)
+ if (ACPI_SUCCESS(acpi_get_devices(mach->id,
+ sst_acpi_mach_match,
+ &found, NULL)) && found)
+ return mach;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c
index 7f94920c8a4d..b2bec36d074c 100644
--- a/sound/soc/intel/haswell/sst-haswell-dsp.c
+++ b/sound/soc/intel/haswell/sst-haswell-dsp.c
@@ -607,7 +607,7 @@ static int hsw_block_disable(struct sst_mem_block *block)
return 0;
}
-static struct sst_block_ops sst_hsw_ops = {
+static const struct sst_block_ops sst_hsw_ops = {
.enable = hsw_block_enable,
.disable = hsw_block_disable,
};
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c
index b27f25f70730..ac60f1301e21 100644
--- a/sound/soc/intel/haswell/sst-haswell-ipc.c
+++ b/sound/soc/intel/haswell/sst-haswell-ipc.c
@@ -778,7 +778,6 @@ static irqreturn_t hsw_irq_thread(int irq, void *context)
struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
struct sst_generic_ipc *ipc = &hsw->ipc;
u32 ipcx, ipcd;
- int handled;
unsigned long flags;
spin_lock_irqsave(&sst->spinlock, flags);
@@ -790,34 +789,30 @@ static irqreturn_t hsw_irq_thread(int irq, void *context)
if (ipcx & SST_IPCX_DONE) {
/* Handle Immediate reply from DSP Core */
- handled = hsw_process_reply(hsw, ipcx);
+ hsw_process_reply(hsw, ipcx);
- if (handled > 0) {
- /* clear DONE bit - tell DSP we have completed */
- sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
- SST_IPCX_DONE, 0);
+ /* clear DONE bit - tell DSP we have completed */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
+ SST_IPCX_DONE, 0);
- /* unmask Done interrupt */
- sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
- SST_IMRX_DONE, 0);
- }
+ /* unmask Done interrupt */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+ SST_IMRX_DONE, 0);
}
/* new message from DSP */
if (ipcd & SST_IPCD_BUSY) {
/* Handle Notification and Delayed reply from DSP Core */
- handled = hsw_process_notification(hsw);
+ hsw_process_notification(hsw);
/* clear BUSY bit and set DONE bit - accept new messages */
- if (handled > 0) {
- sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
- SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
+ SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
- /* unmask busy interrupt */
- sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
- SST_IMRX_BUSY, 0);
- }
+ /* unmask busy interrupt */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+ SST_IMRX_BUSY, 0);
}
spin_unlock_irqrestore(&sst->spinlock, flags);
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 50a109503a3f..de6dac496a0d 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -96,7 +96,7 @@ int skl_init_dsp(struct skl *skl)
}
ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
- loader_ops, &skl->skl_sst);
+ skl->fw_name, loader_ops, &skl->skl_sst);
if (ret < 0)
return ret;
@@ -182,94 +182,6 @@ enum skl_bitdepth skl_get_bit_depth(int params)
}
}
-static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg)
-{
- u32 config;
-
- switch (ch_cfg) {
- case SKL_CH_CFG_MONO:
- config = (0xFFFFFFF0 | SKL_CHANNEL_LEFT);
- break;
-
- case SKL_CH_CFG_STEREO:
- config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4));
- break;
-
- case SKL_CH_CFG_2_1:
- config = (0xFFFFF000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4)
- | (SKL_CHANNEL_LFE << 8));
- break;
-
- case SKL_CH_CFG_3_0:
- config = (0xFFFFF000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8));
- break;
-
- case SKL_CH_CFG_3_1:
- config = (0xFFFF0000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_LFE << 12));
- break;
-
- case SKL_CH_CFG_QUATRO:
- config = (0xFFFF0000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4)
- | (SKL_CHANNEL_LEFT_SURROUND << 8)
- | (SKL_CHANNEL_RIGHT_SURROUND << 12));
- break;
-
- case SKL_CH_CFG_4_0:
- config = (0xFFFF0000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_CENTER_SURROUND << 12));
- break;
-
- case SKL_CH_CFG_5_0:
- config = (0xFFF00000 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_CENTER << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_LEFT_SURROUND << 12)
- | (SKL_CHANNEL_RIGHT_SURROUND << 16));
- break;
-
- case SKL_CH_CFG_5_1:
- config = (0xFF000000 | SKL_CHANNEL_CENTER
- | (SKL_CHANNEL_LEFT << 4)
- | (SKL_CHANNEL_RIGHT << 8)
- | (SKL_CHANNEL_LEFT_SURROUND << 12)
- | (SKL_CHANNEL_RIGHT_SURROUND << 16)
- | (SKL_CHANNEL_LFE << 20));
- break;
-
- case SKL_CH_CFG_DUAL_MONO:
- config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_LEFT << 4));
- break;
-
- case SKL_CH_CFG_I2S_DUAL_STEREO_0:
- config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
- | (SKL_CHANNEL_RIGHT << 4));
- break;
-
- case SKL_CH_CFG_I2S_DUAL_STEREO_1:
- config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8)
- | (SKL_CHANNEL_RIGHT << 12));
- break;
-
- default:
- config = 0xFFFFFFFF;
- break;
-
- }
-
- return config;
-}
-
/*
* Each module in DSP expects a base module configuration, which consists of
* PCM format information, which we calculate in driver and resource values
@@ -280,7 +192,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_base_cfg *base_cfg)
{
- struct skl_module_fmt *format = &mconfig->in_fmt;
+ struct skl_module_fmt *format = &mconfig->in_fmt[0];
base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
@@ -293,14 +205,14 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
format->bit_depth, format->valid_bit_depth,
format->ch_cfg);
- base_cfg->audio_fmt.channel_map = skl_create_channel_map(
- base_cfg->audio_fmt.ch_cfg);
+ base_cfg->audio_fmt.channel_map = format->ch_map;
- base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+ base_cfg->audio_fmt.interleaving = format->interleaving_style;
base_cfg->cps = mconfig->mcps;
base_cfg->ibs = mconfig->ibs;
base_cfg->obs = mconfig->obs;
+ base_cfg->is_pages = mconfig->mem_pages;
}
/*
@@ -399,7 +311,7 @@ static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt)
{
- struct skl_module_fmt *format = &mconfig->out_fmt;
+ struct skl_module_fmt *format = &mconfig->out_fmt[0];
out_fmt->number_of_channels = (u8)format->channels;
out_fmt->s_freq = format->s_freq;
@@ -407,8 +319,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
out_fmt->valid_bit_depth = format->valid_bit_depth;
out_fmt->ch_cfg = format->ch_cfg;
- out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg);
- out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+ out_fmt->channel_map = format->ch_map;
+ out_fmt->interleaving = format->interleaving_style;
+ out_fmt->sample_type = format->sample_type;
dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
out_fmt->number_of_channels, format->s_freq, format->bit_depth);
@@ -423,7 +336,7 @@ static void skl_set_src_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_src_module_cfg *src_mconfig)
{
- struct skl_module_fmt *fmt = &mconfig->out_fmt;
+ struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
skl_set_base_module_format(ctx, mconfig,
(struct skl_base_cfg *)src_mconfig);
@@ -440,7 +353,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_up_down_mixer_cfg *mixer_mconfig)
{
- struct skl_module_fmt *fmt = &mconfig->out_fmt;
+ struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
int i = 0;
skl_set_base_module_format(ctx, mconfig,
@@ -475,6 +388,47 @@ static void skl_set_copier_format(struct skl_sst *ctx,
skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig);
}
+/*
+ * Algo module are DSP pre processing modules. Algo module take base module
+ * configuration and params
+ */
+
+static void skl_set_algo_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_algo_cfg *algo_mcfg)
+{
+ struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg;
+
+ skl_set_base_module_format(ctx, mconfig, base_cfg);
+
+ if (mconfig->formats_config.caps_size == 0)
+ return;
+
+ memcpy(algo_mcfg->params,
+ mconfig->formats_config.caps,
+ mconfig->formats_config.caps_size);
+
+}
+
+/*
+ * Mic select module allows selecting one or many input channels, thus
+ * acting as a demux.
+ *
+ * Mic select module take base module configuration and out-format
+ * configuration
+ */
+static void skl_set_base_outfmt_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_base_outfmt_cfg *base_outfmt_mcfg)
+{
+ struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt;
+ struct skl_base_cfg *base_cfg =
+ (struct skl_base_cfg *)base_outfmt_mcfg;
+
+ skl_set_base_module_format(ctx, mconfig, base_cfg);
+ skl_setup_out_format(ctx, mconfig, out_fmt);
+}
+
static u16 skl_get_module_param_size(struct skl_sst *ctx,
struct skl_module_cfg *mconfig)
{
@@ -492,6 +446,14 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx,
case SKL_MODULE_TYPE_UPDWMIX:
return sizeof(struct skl_up_down_mixer_cfg);
+ case SKL_MODULE_TYPE_ALGO:
+ param_size = sizeof(struct skl_base_cfg);
+ param_size += mconfig->formats_config.caps_size;
+ return param_size;
+
+ case SKL_MODULE_TYPE_BASE_OUTFMT:
+ return sizeof(struct skl_base_outfmt_cfg);
+
default:
/*
* return only base cfg when no specific module type is
@@ -538,6 +500,14 @@ static int skl_set_module_format(struct skl_sst *ctx,
skl_set_updown_mixer_format(ctx, module_config, *param_data);
break;
+ case SKL_MODULE_TYPE_ALGO:
+ skl_set_algo_format(ctx, module_config, *param_data);
+ break;
+
+ case SKL_MODULE_TYPE_BASE_OUTFMT:
+ skl_set_base_outfmt_format(ctx, module_config, *param_data);
+ break;
+
default:
skl_set_base_module_format(ctx, module_config, *param_data);
break;
@@ -571,10 +541,10 @@ static int skl_get_queue_index(struct skl_module_pin *mpin,
* In static, the pin_index is fixed based on module_id and instance id
*/
static int skl_alloc_queue(struct skl_module_pin *mpin,
- struct skl_module_inst_id id, int max)
+ struct skl_module_cfg *tgt_cfg, int max)
{
int i;
-
+ struct skl_module_inst_id id = tgt_cfg->id;
/*
* if pin in dynamic, find first free pin
* otherwise find match module and instance id pin as topology will
@@ -583,16 +553,23 @@ static int skl_alloc_queue(struct skl_module_pin *mpin,
*/
for (i = 0; i < max; i++) {
if (mpin[i].is_dynamic) {
- if (!mpin[i].in_use) {
+ if (!mpin[i].in_use &&
+ mpin[i].pin_state == SKL_PIN_UNBIND) {
+
mpin[i].in_use = true;
mpin[i].id.module_id = id.module_id;
mpin[i].id.instance_id = id.instance_id;
+ mpin[i].tgt_mcfg = tgt_cfg;
return i;
}
} else {
if (mpin[i].id.module_id == id.module_id &&
- mpin[i].id.instance_id == id.instance_id)
+ mpin[i].id.instance_id == id.instance_id &&
+ mpin[i].pin_state == SKL_PIN_UNBIND) {
+
+ mpin[i].tgt_mcfg = tgt_cfg;
return i;
+ }
}
}
@@ -606,6 +583,28 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
mpin[q_index].id.module_id = 0;
mpin[q_index].id.instance_id = 0;
}
+ mpin[q_index].pin_state = SKL_PIN_UNBIND;
+ mpin[q_index].tgt_mcfg = NULL;
+}
+
+/* Module state will be set to unint, if all the out pin state is UNBIND */
+
+static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
+ struct skl_module_cfg *mcfg)
+{
+ int i;
+ bool found = false;
+
+ for (i = 0; i < max; i++) {
+ if (mpin[i].pin_state == SKL_PIN_UNBIND)
+ continue;
+ found = true;
+ break;
+ }
+
+ if (!found)
+ mcfg->m_state = SKL_MODULE_UNINIT;
+ return;
}
/*
@@ -615,7 +614,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
* invoke the DSP by sending IPC INIT_INSTANCE using ipc helper
*/
int skl_init_module(struct skl_sst *ctx,
- struct skl_module_cfg *mconfig, char *param)
+ struct skl_module_cfg *mconfig)
{
u16 module_config_size = 0;
void *param_data = NULL;
@@ -682,37 +681,30 @@ int skl_unbind_modules(struct skl_sst *ctx,
struct skl_module_inst_id dst_id = dst_mcfg->id;
int in_max = dst_mcfg->max_in_queue;
int out_max = src_mcfg->max_out_queue;
- int src_index, dst_index;
+ int src_index, dst_index, src_pin_state, dst_pin_state;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
- if (src_mcfg->m_state != SKL_MODULE_BIND_DONE)
- return 0;
-
- /*
- * if intra module unbind, check if both modules are BIND,
- * then send unbind
- */
- if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) &&
- dst_mcfg->m_state != SKL_MODULE_BIND_DONE)
- return 0;
- else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
- dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
- return 0;
-
/* get src queue index */
src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
if (src_index < 0)
return -EINVAL;
- msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
+ msg.src_queue = src_index;
/* get dst queue index */
dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
if (dst_index < 0)
return -EINVAL;
- msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+ msg.dst_queue = dst_index;
+
+ src_pin_state = src_mcfg->m_out_pin[src_index].pin_state;
+ dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state;
+
+ if (src_pin_state != SKL_PIN_BIND_DONE ||
+ dst_pin_state != SKL_PIN_BIND_DONE)
+ return 0;
msg.module_id = src_mcfg->id.module_id;
msg.instance_id = src_mcfg->id.instance_id;
@@ -722,10 +714,15 @@ int skl_unbind_modules(struct skl_sst *ctx,
ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
if (!ret) {
- src_mcfg->m_state = SKL_MODULE_UNINIT;
/* free queue only if unbind is success */
skl_free_queue(src_mcfg->m_out_pin, src_index);
skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+
+ /*
+ * check only if src module bind state, bind is
+ * always from src -> sink
+ */
+ skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg);
}
return ret;
@@ -744,8 +741,6 @@ int skl_bind_modules(struct skl_sst *ctx,
{
int ret;
struct skl_ipc_bind_unbind_msg msg;
- struct skl_module_inst_id src_id = src_mcfg->id;
- struct skl_module_inst_id dst_id = dst_mcfg->id;
int in_max = dst_mcfg->max_in_queue;
int out_max = src_mcfg->max_out_queue;
int src_index, dst_index;
@@ -756,18 +751,18 @@ int skl_bind_modules(struct skl_sst *ctx,
dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
return 0;
- src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max);
+ src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max);
if (src_index < 0)
return -EINVAL;
- msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
- dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max);
+ msg.src_queue = src_index;
+ dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max);
if (dst_index < 0) {
skl_free_queue(src_mcfg->m_out_pin, src_index);
return -EINVAL;
}
- msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+ msg.dst_queue = dst_index;
dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
msg.src_queue, msg.dst_queue);
@@ -782,6 +777,8 @@ int skl_bind_modules(struct skl_sst *ctx,
if (!ret) {
src_mcfg->m_state = SKL_MODULE_BIND_DONE;
+ src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
+ dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
} else {
/* error case , if IPC fails, clear the queue index */
skl_free_queue(src_mcfg->m_out_pin, src_index);
@@ -852,6 +849,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id);
if (ret < 0)
dev_err(ctx->dev, "Failed to delete pipeline\n");
+
+ pipe->state = SKL_PIPE_INVALID;
}
return ret;
@@ -916,3 +915,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
return 0;
}
+
+/* Algo parameter set helper function */
+int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
+ u32 param_id, struct skl_module_cfg *mcfg)
+{
+ struct skl_ipc_large_config_msg msg;
+
+ msg.module_id = mcfg->id.module_id;
+ msg.instance_id = mcfg->id.instance_id;
+ msg.param_data_size = size;
+ msg.large_param_id = param_id;
+
+ return skl_ipc_set_large_config(&ctx->ipc, &msg, params);
+}
+
+int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
+ u32 param_id, struct skl_module_cfg *mcfg)
+{
+ struct skl_ipc_large_config_msg msg;
+
+ msg.module_id = mcfg->id.module_id;
+ msg.instance_id = mcfg->id.instance_id;
+ msg.param_data_size = size;
+ msg.large_param_id = param_id;
+
+ return skl_ipc_get_large_config(&ctx->ipc, &msg, params);
+}
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index b0c7bd113aac..6e4b21cdb1bd 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -55,7 +55,7 @@ void skl_nhlt_free(void *addr)
static struct nhlt_specific_cfg *skl_get_specific_cfg(
struct device *dev, struct nhlt_fmt *fmt,
- u8 no_ch, u32 rate, u16 bps)
+ u8 no_ch, u32 rate, u16 bps, u8 linktype)
{
struct nhlt_specific_cfg *sp_config;
struct wav_fmt *wfmt;
@@ -68,11 +68,17 @@ static struct nhlt_specific_cfg *skl_get_specific_cfg(
wfmt = &fmt_config->fmt_ext.fmt;
dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
wfmt->bits_per_sample, wfmt->samples_per_sec);
- if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate &&
- wfmt->bits_per_sample == bps) {
+ if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) {
+ /*
+ * if link type is dmic ignore rate check as the blob is
+ * generic for all rates
+ */
sp_config = &fmt_config->config;
+ if (linktype == NHLT_LINK_DMIC)
+ return sp_config;
- return sp_config;
+ if (wfmt->samples_per_sec == rate)
+ return sp_config;
}
fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
@@ -115,7 +121,7 @@ struct nhlt_specific_cfg
struct device *dev = bus->dev;
struct nhlt_specific_cfg *sp_config;
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
- u16 bps = num_ch * s_fmt;
+ u16 bps = (s_fmt == 16) ? 16 : 32;
u8 j;
dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
@@ -128,7 +134,8 @@ struct nhlt_specific_cfg
if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
fmt = (struct nhlt_fmt *)(epnt->config.caps +
epnt->config.size);
- sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps);
+ sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
+ s_rate, bps, link_type);
if (sp_config)
return sp_config;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index a2f94ce1679d..f3553258091a 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -25,9 +25,12 @@
#include <sound/soc.h>
#include "skl.h"
#include "skl-topology.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
#define HDA_MONO 1
#define HDA_STEREO 2
+#define HDA_QUAD 4
static struct snd_pcm_hardware azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -35,16 +38,20 @@ static struct snd_pcm_hardware azx_pcm_hw = {
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
SNDRV_PCM_INFO_HAS_LINK_ATIME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_8000,
+ .rate_min = 8000,
.rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
+ .channels_min = 1,
+ .channels_max = HDA_QUAD,
.buffer_bytes_max = AZX_MAX_BUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = AZX_MAX_BUF_SIZE / 2,
@@ -105,6 +112,31 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e
return HDAC_EXT_STREAM_TYPE_COUPLED;
}
+/*
+ * check if the stream opened is marked as ignore_suspend by machine, if so
+ * then enable suspend_active refcount
+ *
+ * The count supend_active does not need lock as it is used in open/close
+ * and suspend context
+ */
+static void skl_set_suspend_active(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai, bool enable)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct snd_soc_dapm_widget *w;
+ struct skl *skl = ebus_to_skl(ebus);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ w = dai->playback_widget;
+ else
+ w = dai->capture_widget;
+
+ if (w->ignore_suspend && enable)
+ skl->supend_active++;
+ else if (w->ignore_suspend && !enable)
+ skl->supend_active--;
+}
+
static int skl_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -112,12 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
struct hdac_ext_stream *stream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct skl_dma_params *dma_params;
- int ret;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- ret = pm_runtime_get_sync(dai->dev);
- if (ret < 0)
- return ret;
stream = snd_hdac_ext_stream_assign(ebus, substream,
skl_get_host_stream_type(ebus));
@@ -146,6 +174,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
dma_params->stream_tag);
+ skl_set_suspend_active(substream, dai, true);
snd_pcm_set_sync(substream);
return 0;
@@ -185,10 +214,6 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
int err;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- if (hdac_stream(stream)->prepared) {
- dev_dbg(dai->dev, "already stream is prepared - returning\n");
- return 0;
- }
format_val = skl_get_format(substream, dai);
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
@@ -250,6 +275,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
struct skl_dma_params *dma_params = NULL;
+ struct skl *skl = ebus_to_skl(ebus);
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
@@ -261,9 +287,18 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
* dma_params
*/
snd_soc_dai_set_dma_data(dai, substream, NULL);
+ skl_set_suspend_active(substream, dai, false);
+
+ /*
+ * check if close is for "Reference Pin" and set back the
+ * CGCTL.MISCBDCGE if disabled by driver
+ */
+ if (!strncmp(dai->name, "Reference Pin", 13) &&
+ skl->skl_sst->miscbdcg_disabled) {
+ skl->skl_sst->enable_miscbdcge(dai->dev, true);
+ skl->skl_sst->miscbdcg_disabled = false;
+ }
- pm_runtime_mark_last_busy(dai->dev);
- pm_runtime_put_autosuspend(dai->dev);
kfree(dma_params);
}
@@ -291,7 +326,53 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream,
p_params.ch = params_channels(params);
p_params.s_freq = params_rate(params);
p_params.stream = substream->stream;
- skl_tplg_be_update_params(dai, &p_params);
+
+ return skl_tplg_be_update_params(dai, &p_params);
+}
+
+static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_ext_stream *stream;
+ int start;
+ unsigned long cookie;
+ struct hdac_stream *hstr;
+
+ stream = get_hdac_ext_stream(substream);
+ hstr = hdac_stream(stream);
+
+ if (!hstr->prepared)
+ return -EPIPE;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ start = 1;
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ start = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+
+ if (start) {
+ snd_hdac_stream_start(hdac_stream(stream), true);
+ snd_hdac_stream_timecounter_init(hstr, 0);
+ } else {
+ snd_hdac_stream_stop(hdac_stream(stream));
+ }
+
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
return 0;
}
@@ -302,23 +383,72 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_cfg *mconfig;
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ int ret;
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
if (!mconfig)
return -EIO;
switch (cmd) {
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
+ skl_pcm_prepare(substream, dai);
+ /*
+ * enable DMA Resume enable bit for the stream, set the dpib
+ * & lpib position to resune before starting the DMA
+ */
+ snd_hdac_ext_stream_drsm_enable(ebus, true,
+ hdac_stream(stream)->index);
+ snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib);
+ snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /*
+ * Start HOST DMA and Start FE Pipe.This is to make sure that
+ * there are no underrun/overrun in the case when the FE
+ * pipeline is started but there is a delay in starting the
+ * DMA channel on the host.
+ */
+ snd_hdac_ext_stream_decouple(ebus, stream, true);
+ ret = skl_decoupled_trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
return skl_run_pipe(ctx, mconfig->pipe);
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- return skl_stop_pipe(ctx, mconfig->pipe);
+ case SNDRV_PCM_TRIGGER_STOP:
+ /*
+ * Stop FE Pipe first and stop DMA. This is to make sure that
+ * there are no underrun/overrun in the case if there is a delay
+ * between the two operations.
+ */
+ ret = skl_stop_pipe(ctx, mconfig->pipe);
+ if (ret < 0)
+ return ret;
+
+ ret = skl_decoupled_trigger(substream, cmd);
+ if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) {
+ /* save the dpib and lpib positions */
+ stream->dpib = readl(ebus->bus.remap_addr +
+ AZX_REG_VS_SDXDPIB_XBASE +
+ (AZX_REG_VS_SDXDPIB_XINTERVAL *
+ hdac_stream(stream)->index));
+
+ stream->lpib = snd_hdac_stream_get_pos_lpib(
+ hdac_stream(stream));
+ snd_hdac_ext_stream_decouple(ebus, stream, false);
+ }
+ break;
default:
- return 0;
+ return -EINVAL;
}
+
+ return 0;
}
static int skl_link_hw_params(struct snd_pcm_substream *substream,
@@ -352,9 +482,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
p_params.stream = substream->stream;
p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
- skl_tplg_be_update_params(dai, &p_params);
-
- return 0;
+ return skl_tplg_be_update_params(dai, &p_params);
}
static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
@@ -369,11 +497,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct hdac_ext_link *link;
- if (link_dev->link_prepared) {
- dev_dbg(dai->dev, "already stream is prepared - returning\n");
- return 0;
- }
-
dma_params = (struct skl_dma_params *)
snd_soc_dai_get_dma_data(codec_dai, substream);
if (dma_params)
@@ -381,14 +504,15 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n",
hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name);
- snd_hdac_ext_link_stream_reset(link_dev);
-
- snd_hdac_ext_link_stream_setup(link_dev, format_val);
-
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
if (!link)
return -EINVAL;
+ snd_hdac_ext_bus_link_power_up(link);
+ snd_hdac_ext_link_stream_reset(link_dev);
+
+ snd_hdac_ext_link_stream_setup(link_dev, format_val);
+
snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
link_dev->link_prepared = 1;
@@ -400,12 +524,16 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
{
struct hdac_ext_stream *link_dev =
snd_soc_dai_get_dma_data(dai, substream);
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ skl_link_pcm_prepare(substream, dai);
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
+ snd_hdac_ext_stream_decouple(ebus, stream, true);
snd_hdac_ext_link_stream_start(link_dev);
break;
@@ -413,6 +541,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(link_dev);
+ if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
+ snd_hdac_ext_stream_decouple(ebus, stream, false);
break;
default:
@@ -443,19 +573,6 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static int skl_be_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- return pm_runtime_get_sync(dai->dev);
-}
-
-static void skl_be_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- pm_runtime_mark_last_busy(dai->dev);
- pm_runtime_put_autosuspend(dai->dev);
-}
-
static struct snd_soc_dai_ops skl_pcm_dai_ops = {
.startup = skl_pcm_open,
.shutdown = skl_pcm_close,
@@ -466,24 +583,18 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
};
static struct snd_soc_dai_ops skl_dmic_dai_ops = {
- .startup = skl_be_startup,
.hw_params = skl_be_hw_params,
- .shutdown = skl_be_shutdown,
};
static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
- .startup = skl_be_startup,
.hw_params = skl_be_hw_params,
- .shutdown = skl_be_shutdown,
};
static struct snd_soc_dai_ops skl_link_dai_ops = {
- .startup = skl_be_startup,
.prepare = skl_link_pcm_prepare,
.hw_params = skl_link_hw_params,
.hw_free = skl_link_hw_free,
.trigger = skl_link_pcm_trigger,
- .shutdown = skl_be_shutdown,
};
static struct snd_soc_dai_driver skl_platform_dai[] = {
@@ -511,7 +622,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.capture = {
.stream_name = "Reference Capture",
.channels_min = HDA_MONO,
- .channels_max = HDA_STEREO,
+ .channels_max = HDA_QUAD,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
@@ -538,6 +649,18 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
},
+{
+ .name = "DMIC Pin",
+ .ops = &skl_pcm_dai_ops,
+ .capture = {
+ .stream_name = "DMIC Capture",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_QUAD,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+
/* BE CPU Dais */
{
.name = "SSP0 Pin",
@@ -558,6 +681,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
{
+ .name = "SSP1 Pin",
+ .ops = &skl_be_ssp_dai_ops,
+ .playback = {
+ .stream_name = "ssp1 Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "ssp1 Rx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
.name = "iDisp Pin",
.ops = &skl_link_dai_ops,
.playback = {
@@ -573,8 +714,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.ops = &skl_dmic_dai_ops,
.capture = {
.stream_name = "DMIC01 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_QUAD,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
@@ -688,66 +829,15 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct hdac_ext_stream *stream;
- int start;
- unsigned long cookie;
- struct hdac_stream *hstr;
-
- dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name);
-
- stream = get_hdac_ext_stream(substream);
- hstr = hdac_stream(stream);
-
- if (!hstr->prepared)
- return -EPIPE;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- start = 1;
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- start = 0;
- break;
-
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&bus->reg_lock, cookie);
-
- if (start)
- snd_hdac_stream_start(hdac_stream(stream), true);
- else
- snd_hdac_stream_stop(hdac_stream(stream));
-
- if (start)
- snd_hdac_stream_timecounter_init(hstr, 0);
-
- spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
- return 0;
-}
static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct hdac_ext_bus *ebus = get_bus_ctx(substream);
- if (ebus->ppcap)
- return skl_decoupled_trigger(substream, cmd);
- else
+ if (!ebus->ppcap)
return skl_coupled_trigger(substream, cmd);
+
+ return 0;
}
/* calculate runtime delay from LPIB */
@@ -789,7 +879,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
{
struct hdac_stream *hstr = hdac_stream(hstream);
struct snd_pcm_substream *substream = hstr->substream;
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_ext_bus *ebus;
unsigned int pos;
int delay;
@@ -800,6 +890,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
pos = 0;
if (substream->runtime) {
+ ebus = get_bus_ctx(substream);
delay = skl_get_delay_from_lpib(ebus, hstream, pos)
+ codec_delay;
substream->runtime->delay += delay;
@@ -941,7 +1032,6 @@ int skl_platform_register(struct device *dev)
struct skl *skl = ebus_to_skl(ebus);
INIT_LIST_HEAD(&skl->ppl_list);
- INIT_LIST_HEAD(&skl->dapm_path_list);
ret = snd_soc_register_platform(dev, &skl_platform_drv);
if (ret) {
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index 44748ba98da2..da2329d17f4d 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -18,6 +18,7 @@
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/kthread.h>
+#include <linux/delay.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
@@ -33,6 +34,53 @@ void skl_cldma_int_disable(struct sst_dsp *ctx)
SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0);
}
+static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable)
+{
+ unsigned char val;
+ int timeout;
+
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable));
+
+ udelay(3);
+ timeout = 300;
+ do {
+ /* waiting for hardware to report that the stream Run bit set */
+ val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) &
+ CL_SD_CTL_RUN_MASK;
+ if (enable && val)
+ break;
+ else if (!enable && !val)
+ break;
+ udelay(3);
+ } while (--timeout);
+
+ if (timeout == 0)
+ dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable);
+}
+
+static void skl_cldma_stream_clear(struct sst_dsp *ctx)
+{
+ /* make sure Run bit is cleared before setting stream register */
+ skl_cldma_stream_run(ctx, 0);
+
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
+
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
+
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+}
+
/* Code loader helper APIs */
static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_data,
@@ -68,6 +116,7 @@ static void skl_cldma_setup_controller(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
u32 count)
{
+ skl_cldma_stream_clear(ctx);
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL,
CL_SD_BDLPLBA(dmab_bdl->addr));
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU,
@@ -107,36 +156,13 @@ static void skl_cldma_cleanup_spb(struct sst_dsp *ctx)
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0);
}
-static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable)
-{
- if (enable)
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1));
- else
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0));
-}
-
static void skl_cldma_cleanup(struct sst_dsp *ctx)
{
skl_cldma_cleanup_spb(ctx);
+ skl_cldma_stream_clear(ctx);
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
-
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
-
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+ ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
+ ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl);
}
static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
@@ -164,7 +190,7 @@ cleanup:
static void skl_cldma_stop(struct sst_dsp *ctx)
{
- ctx->cl_dev.ops.cl_trigger(ctx, false);
+ skl_cldma_stream_run(ctx, false);
}
static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
@@ -175,6 +201,21 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
ctx->cl_dev.dma_buffer_offset, trigger);
dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
+ /*
+ * Check if the size exceeds buffer boundary. If it exceeds
+ * max_buffer size, then copy till buffer size and then copy
+ * remaining buffer from the start of ring buffer.
+ */
+ if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) {
+ unsigned int size_b = ctx->cl_dev.bufsize -
+ ctx->cl_dev.dma_buffer_offset;
+ memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
+ curr_pos, size_b);
+ size -= size_b;
+ curr_pos += size_b;
+ ctx->cl_dev.dma_buffer_offset = 0;
+ }
+
memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
curr_pos, size);
@@ -291,7 +332,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller;
ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb;
ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb;
- ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger;
+ ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run;
ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup;
ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf;
ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 6bfcef449bdc..cbb40751c37e 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -58,9 +58,9 @@ struct sst_dsp_device;
#define SKL_ADSP_MMIO_LEN 0x10000
-#define SKL_ADSP_W0_STAT_SZ 0x800
+#define SKL_ADSP_W0_STAT_SZ 0x1000
-#define SKL_ADSP_W0_UP_SZ 0x800
+#define SKL_ADSP_W0_UP_SZ 0x1000
#define SKL_ADSP_W1_SZ 0x1000
@@ -114,6 +114,9 @@ struct skl_dsp_fw_ops {
int (*set_state_D0)(struct sst_dsp *ctx);
int (*set_state_D3)(struct sst_dsp *ctx);
unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
+ int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name);
+ int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
+
};
struct skl_dsp_loader_ops {
@@ -123,6 +126,17 @@ struct skl_dsp_loader_ops {
struct snd_dma_buffer *dmab);
};
+struct skl_load_module_info {
+ u16 mod_id;
+ const struct firmware *fw;
+};
+
+struct skl_module_table {
+ struct skl_load_module_info *mod_info;
+ unsigned int usage_cnt;
+ struct list_head list;
+};
+
void skl_cldma_process_intr(struct sst_dsp *ctx);
void skl_cldma_int_disable(struct sst_dsp *ctx);
int skl_cldma_prepare(struct sst_dsp *ctx);
@@ -139,7 +153,8 @@ void skl_dsp_free(struct sst_dsp *dsp);
int skl_dsp_boot(struct sst_dsp *ctx);
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp);
+ const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
+ struct skl_sst **dsp);
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#endif /*__SKL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 3345ea0d4414..543460293b00 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -16,8 +16,10 @@
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
+#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
+#include "sound/hdaudio_ext.h"
#define IPC_IXC_STATUS_BITS 24
@@ -130,6 +132,11 @@
#define IPC_SRC_QUEUE_MASK 0x7
#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \
<< IPC_SRC_QUEUE_SHIFT)
+/* Load Module count */
+#define IPC_LOAD_MODULE_SHIFT 0
+#define IPC_LOAD_MODULE_MASK 0xFF
+#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \
+ << IPC_LOAD_MODULE_SHIFT)
/* Save pipeline messgae extension register */
#define IPC_DMA_ID_SHIFT 0
@@ -317,6 +324,19 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
wake_up(&skl->boot_wait);
break;
+ case IPC_GLB_NOTIFY_PHRASE_DETECTED:
+ dev_dbg(ipc->dev, "***** Phrase Detected **********\n");
+
+ /*
+ * Per HW recomendation, After phrase detection,
+ * clear the CGCTL.MISCBDCGE.
+ *
+ * This will be set back on stream closure
+ */
+ skl->enable_miscbdcge(ipc->dev, false);
+ skl->miscbdcg_disabled = true;
+ break;
+
default:
dev_err(ipc->dev, "ipc: Unhandled error msg=%x",
header.primary);
@@ -344,6 +364,8 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
switch (reply) {
case IPC_GLB_REPLY_SUCCESS:
dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary);
+ /* copy the rx data from the mailbox */
+ sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
break;
case IPC_GLB_REPLY_OUT_OF_MEMORY:
@@ -650,7 +672,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
header.primary, header.extension);
ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
- dx, sizeof(dx), NULL, 0);
+ dx, sizeof(*dx), NULL, 0);
if (ret < 0) {
dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
return ret;
@@ -728,6 +750,54 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
}
EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
+/*
+ * In order to load a module we need to send IPC to initiate that. DMA will
+ * performed to load the module memory. The FW supports multiple module load
+ * at single shot, so we can send IPC with N modules represented by
+ * module_cnt
+ */
+int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
+ u8 module_cnt, void *data)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
+ header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
+
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+ (sizeof(u16) * module_cnt), NULL, 0);
+ if (ret < 0)
+ dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_load_modules);
+
+int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt,
+ void *data)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS);
+ header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
+
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+ (sizeof(u16) * module_cnt), NULL, 0);
+ if (ret < 0)
+ dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_unload_modules);
+
int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
struct skl_ipc_large_config_msg *msg, u32 *param)
{
@@ -781,3 +851,54 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
return ret;
}
EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
+
+int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
+ struct skl_ipc_large_config_msg *msg, u32 *param)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret = 0;
+ size_t sz_remaining, rx_size, data_offset;
+
+ header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET);
+ header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+ header.primary |= IPC_MOD_ID(msg->module_id);
+
+ header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
+ header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
+ header.extension |= IPC_FINAL_BLOCK(1);
+ header.extension |= IPC_INITIAL_BLOCK(1);
+
+ sz_remaining = msg->param_data_size;
+ data_offset = 0;
+
+ while (sz_remaining != 0) {
+ rx_size = sz_remaining > SKL_ADSP_W1_SZ
+ ? SKL_ADSP_W1_SZ : sz_remaining;
+ if (rx_size == sz_remaining)
+ header.extension |= IPC_FINAL_BLOCK(1);
+
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0,
+ ((char *)param) + data_offset,
+ msg->param_data_size);
+ if (ret < 0) {
+ dev_err(ipc->dev,
+ "ipc: get large config fail, err: %d\n", ret);
+ return ret;
+ }
+ sz_remaining -= rx_size;
+ data_offset = msg->param_data_size - sz_remaining;
+
+ /* clear the fields */
+ header.extension &= IPC_INITIAL_BLOCK_CLEAR;
+ header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
+ /* fill the fields */
+ header.extension |= IPC_INITIAL_BLOCK(1);
+ header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index f1a154e45dc3..d59d1ba62a43 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -55,6 +55,11 @@ struct skl_sst {
/* IPC messaging */
struct sst_generic_ipc ipc;
+
+ /* callback for miscbdge */
+ void (*enable_miscbdcge)(struct device *dev, bool enable);
+ /*Is CGCTL.MISCBDCGE disabled*/
+ bool miscbdcg_disabled;
};
struct skl_ipc_init_instance_msg {
@@ -108,12 +113,21 @@ int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc,
int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc,
struct skl_ipc_bind_unbind_msg *msg);
+int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
+ u8 module_cnt, void *data);
+
+int skl_ipc_unload_modules(struct sst_generic_ipc *ipc,
+ u8 module_cnt, void *data);
+
int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
struct skl_ipc_large_config_msg *msg, u32 *param);
+int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
+ struct skl_ipc_large_config_msg *msg, u32 *param);
+
void skl_ipc_int_enable(struct sst_dsp *dsp);
void skl_ipc_op_int_enable(struct sst_dsp *ctx);
void skl_ipc_op_int_disable(struct sst_dsp *ctx);
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 3b83dc99f1d4..e26f4746afb7 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "../common/sst-ipc.h"
@@ -37,6 +38,8 @@
#define SKL_INSTANCE_ID 0
#define SKL_BASE_FW_MODULE_ID 0
+#define SKL_NUM_MODULES 1
+
static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
{
u32 cur_sts;
@@ -77,7 +80,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
init_waitqueue_head(&skl->boot_wait);
if (ctx->fw == NULL) {
- ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev);
+ ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
if (ret < 0) {
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
skl_dsp_disable_core(ctx);
@@ -115,27 +118,28 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
dev_err(ctx->dev,
"Timeout waiting for ROM init done, reg:0x%x\n", reg);
ret = -EIO;
- goto skl_load_base_firmware_failed;
+ goto transfer_firmware_failed;
}
ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size);
if (ret < 0) {
dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
- goto skl_load_base_firmware_failed;
+ goto transfer_firmware_failed;
} else {
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) {
dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
ret = -EIO;
- goto skl_load_base_firmware_failed;
+ goto transfer_firmware_failed;
}
dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
}
return 0;
-
+transfer_firmware_failed:
+ ctx->cl_dev.ops.cl_cleanup_controller(ctx);
skl_load_base_firmware_failed:
skl_dsp_disable_core(ctx);
release_firmware(ctx->fw);
@@ -175,10 +179,15 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
dx.core_mask = SKL_DSP_CORE0_MASK;
dx.dx_mask = SKL_IPC_D3_MASK;
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to set DSP to D3 state\n");
- return ret;
- }
+ if (ret < 0)
+ dev_err(ctx->dev,
+ "D3 request to FW failed, continuing reset: %d", ret);
+
+ /* disable Interrupt */
+ ctx->cl_dev.ops.cl_cleanup_controller(ctx);
+ skl_cldma_int_disable(ctx);
+ skl_ipc_op_int_disable(ctx);
+ skl_ipc_int_disable(ctx);
ret = skl_dsp_disable_core(ctx);
if (ret < 0) {
@@ -187,12 +196,6 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
}
skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
- /* disable Interrupt */
- ctx->cl_dev.ops.cl_cleanup_controller(ctx);
- skl_cldma_int_disable(ctx);
- skl_ipc_op_int_disable(ctx);
- skl_ipc_int_disable(ctx);
-
return ret;
}
@@ -201,11 +204,182 @@ static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
}
+/*
+ * since get/set_module are called from DAPM context,
+ * we don't need lock for usage count
+ */
+static int skl_get_module(struct sst_dsp *ctx, u16 mod_id)
+{
+ struct skl_module_table *module;
+
+ list_for_each_entry(module, &ctx->module_list, list) {
+ if (module->mod_info->mod_id == mod_id)
+ return ++module->usage_cnt;
+ }
+
+ return -EINVAL;
+}
+
+static int skl_put_module(struct sst_dsp *ctx, u16 mod_id)
+{
+ struct skl_module_table *module;
+
+ list_for_each_entry(module, &ctx->module_list, list) {
+ if (module->mod_info->mod_id == mod_id)
+ return --module->usage_cnt;
+ }
+
+ return -EINVAL;
+}
+
+static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx,
+ char *mod_name, int mod_id)
+{
+ const struct firmware *fw;
+ struct skl_module_table *skl_module;
+ unsigned int size;
+ int ret;
+
+ ret = request_firmware(&fw, mod_name, ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Request Module %s failed :%d\n",
+ mod_name, ret);
+ return NULL;
+ }
+
+ skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL);
+ if (skl_module == NULL) {
+ release_firmware(fw);
+ return NULL;
+ }
+
+ size = sizeof(*skl_module->mod_info);
+ skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
+ if (skl_module->mod_info == NULL) {
+ release_firmware(fw);
+ return NULL;
+ }
+
+ skl_module->mod_info->mod_id = mod_id;
+ skl_module->mod_info->fw = fw;
+ list_add(&skl_module->list, &ctx->module_list);
+
+ return skl_module;
+}
+
+/* get a module from it's unique ID */
+static struct skl_module_table *skl_module_get_from_id(
+ struct sst_dsp *ctx, u16 mod_id)
+{
+ struct skl_module_table *module;
+
+ if (list_empty(&ctx->module_list)) {
+ dev_err(ctx->dev, "Module list is empty\n");
+ return NULL;
+ }
+
+ list_for_each_entry(module, &ctx->module_list, list) {
+ if (module->mod_info->mod_id == mod_id)
+ return module;
+ }
+
+ return NULL;
+}
+
+static int skl_transfer_module(struct sst_dsp *ctx,
+ struct skl_load_module_info *module)
+{
+ int ret;
+ struct skl_sst *skl = ctx->thread_context;
+
+ ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data,
+ module->fw->size);
+ if (ret < 0)
+ return ret;
+
+ ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES,
+ (void *)&module->mod_id);
+ if (ret < 0)
+ dev_err(ctx->dev, "Failed to Load module: %d\n", ret);
+
+ ctx->cl_dev.ops.cl_stop_dma(ctx);
+
+ return ret;
+}
+
+static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid)
+{
+ struct skl_module_table *module_entry = NULL;
+ int ret = 0;
+ char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
+
+ snprintf(mod_name, sizeof(mod_name), "%s%s%s",
+ "intel/dsp_fw_", guid, ".bin");
+
+ module_entry = skl_module_get_from_id(ctx, mod_id);
+ if (module_entry == NULL) {
+ module_entry = skl_fill_module_table(ctx, mod_name, mod_id);
+ if (module_entry == NULL) {
+ dev_err(ctx->dev, "Failed to Load module\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!module_entry->usage_cnt) {
+ ret = skl_transfer_module(ctx, module_entry->mod_info);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to Load module\n");
+ return ret;
+ }
+ }
+
+ ret = skl_get_module(ctx, mod_id);
+
+ return ret;
+}
+
+static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
+{
+ int usage_cnt;
+ struct skl_sst *skl = ctx->thread_context;
+ int ret = 0;
+
+ usage_cnt = skl_put_module(ctx, mod_id);
+ if (usage_cnt < 0) {
+ dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
+ return -EIO;
+ }
+ ret = skl_ipc_unload_modules(&skl->ipc,
+ SKL_NUM_MODULES, &mod_id);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to UnLoad module\n");
+ skl_get_module(ctx, mod_id);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void skl_clear_module_table(struct sst_dsp *ctx)
+{
+ struct skl_module_table *module, *tmp;
+
+ if (list_empty(&ctx->module_list))
+ return;
+
+ list_for_each_entry_safe(module, tmp, &ctx->module_list, list) {
+ list_del(&module->list);
+ release_firmware(module->mod_info->fw);
+ }
+}
+
static struct skl_dsp_fw_ops skl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
.get_fw_errcode = skl_get_errorcode,
+ .load_mod = skl_load_module,
+ .unload_mod = skl_unload_module,
};
static struct sst_ops skl_ops = {
@@ -223,7 +397,7 @@ static struct sst_dsp_device skl_dev = {
};
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
+ const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
{
struct skl_sst *skl;
struct sst_dsp *sst;
@@ -244,11 +418,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst = skl->dsp;
+ sst->fw_name = fw_name;
sst->addr.lpe = mmio_base;
sst->addr.shim = mmio_base;
sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
+ INIT_LIST_HEAD(&sst->module_list);
sst->dsp_ops = dsp_ops;
sst->fw_ops = skl_fw_ops;
@@ -259,23 +435,24 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
ret = sst->fw_ops.load_fw(sst);
if (ret < 0) {
dev_err(dev, "Load base fw failed : %d", ret);
- return ret;
+ goto cleanup;
}
if (dsp)
*dsp = skl;
- return 0;
+ return ret;
- skl_ipc_free(&skl->ipc);
+cleanup:
+ skl_sst_dsp_cleanup(dev, skl);
return ret;
}
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
{
+ skl_clear_module_table(ctx->dsp);
skl_ipc_free(&ctx->ipc);
- ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
ctx->dsp->ops->free(ctx->dsp);
}
EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index ad4d0f82603e..4624556f486d 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -26,6 +26,8 @@
#include "skl-topology.h"
#include "skl.h"
#include "skl-tplg-interface.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
#define SKL_CH_FIXUP_MASK (1 << 0)
#define SKL_RATE_FIXUP_MASK (1 << 1)
@@ -129,17 +131,15 @@ static void skl_dump_mconfig(struct skl_sst *ctx,
{
dev_dbg(ctx->dev, "Dumping config\n");
dev_dbg(ctx->dev, "Input Format:\n");
- dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels);
- dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq);
- dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg);
- dev_dbg(ctx->dev, "valid bit depth = %d\n",
- mcfg->in_fmt.valid_bit_depth);
+ dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
+ dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
+ dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
+ dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
dev_dbg(ctx->dev, "Output Format:\n");
- dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels);
- dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq);
- dev_dbg(ctx->dev, "valid bit depth = %d\n",
- mcfg->out_fmt.valid_bit_depth);
- dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg);
+ dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
+ dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
+ dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
+ dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
}
static void skl_tplg_update_params(struct skl_module_fmt *fmt,
@@ -149,8 +149,24 @@ static void skl_tplg_update_params(struct skl_module_fmt *fmt,
fmt->s_freq = params->s_freq;
if (fixup & SKL_CH_FIXUP_MASK)
fmt->channels = params->ch;
- if (fixup & SKL_FMT_FIXUP_MASK)
- fmt->valid_bit_depth = params->s_fmt;
+ if (fixup & SKL_FMT_FIXUP_MASK) {
+ fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
+
+ /*
+ * 16 bit is 16 bit container whereas 24 bit is in 32 bit
+ * container so update bit depth accordingly
+ */
+ switch (fmt->valid_bit_depth) {
+ case SKL_DEPTH_16BIT:
+ fmt->bit_depth = fmt->valid_bit_depth;
+ break;
+
+ default:
+ fmt->bit_depth = SKL_DEPTH_32BIT;
+ break;
+ }
+ }
+
}
/*
@@ -171,8 +187,9 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
int in_fixup, out_fixup;
struct skl_module_fmt *in_fmt, *out_fmt;
- in_fmt = &m_cfg->in_fmt;
- out_fmt = &m_cfg->out_fmt;
+ /* Fixups will be applied to pin 0 only */
+ in_fmt = &m_cfg->in_fmt[0];
+ out_fmt = &m_cfg->out_fmt[0];
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (is_fe) {
@@ -209,18 +226,25 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
struct skl_module_cfg *mcfg)
{
int multiplier = 1;
+ struct skl_module_fmt *in_fmt, *out_fmt;
+
+
+ /* Since fixups is applied to pin 0 only, ibs, obs needs
+ * change for pin 0 only
+ */
+ in_fmt = &mcfg->in_fmt[0];
+ out_fmt = &mcfg->out_fmt[0];
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
multiplier = 5;
-
- mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) *
- (mcfg->in_fmt.channels) *
- (mcfg->in_fmt.bit_depth >> 3) *
+ mcfg->ibs = (in_fmt->s_freq / 1000) *
+ (mcfg->in_fmt->channels) *
+ (mcfg->in_fmt->bit_depth >> 3) *
multiplier;
- mcfg->obs = (mcfg->out_fmt.s_freq / 1000) *
- (mcfg->out_fmt.channels) *
- (mcfg->out_fmt.bit_depth >> 3) *
+ mcfg->obs = (mcfg->out_fmt->s_freq / 1000) *
+ (mcfg->out_fmt->channels) *
+ (mcfg->out_fmt->bit_depth >> 3) *
multiplier;
}
@@ -292,6 +316,83 @@ static int skl_tplg_alloc_pipe_widget(struct device *dev,
}
/*
+ * some modules can have multiple params set from user control and
+ * need to be set after module is initialized. If set_param flag is
+ * set module params will be done after module is initialised.
+ */
+static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
+ struct skl_sst *ctx)
+{
+ int i, ret;
+ struct skl_module_cfg *mconfig = w->priv;
+ const struct snd_kcontrol_new *k;
+ struct soc_bytes_ext *sb;
+ struct skl_algo_data *bc;
+ struct skl_specific_cfg *sp_cfg;
+
+ if (mconfig->formats_config.caps_size > 0 &&
+ mconfig->formats_config.set_params == SKL_PARAM_SET) {
+ sp_cfg = &mconfig->formats_config;
+ ret = skl_set_module_params(ctx, sp_cfg->caps,
+ sp_cfg->caps_size,
+ sp_cfg->param_id, mconfig);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < w->num_kcontrols; i++) {
+ k = &w->kcontrol_news[i];
+ if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ sb = (void *) k->private_value;
+ bc = (struct skl_algo_data *)sb->dobj.private;
+
+ if (bc->set_params == SKL_PARAM_SET) {
+ ret = skl_set_module_params(ctx,
+ (u32 *)bc->params, bc->max,
+ bc->param_id, mconfig);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * some module param can set from user control and this is required as
+ * when module is initailzed. if module param is required in init it is
+ * identifed by set_param flag. if set_param flag is not set, then this
+ * parameter needs to set as part of module init.
+ */
+static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
+{
+ const struct snd_kcontrol_new *k;
+ struct soc_bytes_ext *sb;
+ struct skl_algo_data *bc;
+ struct skl_module_cfg *mconfig = w->priv;
+ int i;
+
+ for (i = 0; i < w->num_kcontrols; i++) {
+ k = &w->kcontrol_news[i];
+ if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ sb = (struct soc_bytes_ext *)k->private_value;
+ bc = (struct skl_algo_data *)sb->dobj.private;
+
+ if (bc->set_params != SKL_PARAM_INIT)
+ continue;
+
+ mconfig->formats_config.caps = (u32 *)&bc->params;
+ mconfig->formats_config.caps_size = bc->max;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
* Inside a pipe instance, we can have various modules. These modules need
* to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
* skl_init_module() routine, so invoke that for all modules in a pipeline
@@ -313,12 +414,25 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
return -ENOMEM;
+ if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
+ ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
+ mconfig->id.module_id, mconfig->guid);
+ if (ret < 0)
+ return ret;
+ }
+
/*
* apply fix/conversion to module params based on
* FE/BE params
*/
skl_tplg_update_module_params(w, ctx);
- ret = skl_init_module(ctx, mconfig, NULL);
+
+ skl_tplg_set_module_init_data(w);
+ ret = skl_init_module(ctx, mconfig);
+ if (ret < 0)
+ return ret;
+
+ ret = skl_tplg_set_module_params(w, ctx);
if (ret < 0)
return ret;
}
@@ -326,6 +440,24 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
return 0;
}
+static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
+ struct skl_pipe *pipe)
+{
+ struct skl_pipe_module *w_module = NULL;
+ struct skl_module_cfg *mconfig = NULL;
+
+ list_for_each_entry(w_module, &pipe->w_list, node) {
+ mconfig = w_module->w->priv;
+
+ if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod)
+ return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
+ mconfig->id.module_id);
+ }
+
+ /* no modules to unload in this path, so return */
+ return 0;
+}
+
/*
* Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
* need create the pipeline. So we do following:
@@ -397,41 +529,24 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
return 0;
}
-/*
- * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
- * we need to do following:
- * - Bind to sink pipeline
- * Since the sink pipes can be running and we don't get mixer event on
- * connect for already running mixer, we need to find the sink pipes
- * here and bind to them. This way dynamic connect works.
- * - Start sink pipeline, if not running
- * - Then run current pipe
- */
-static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
- struct skl *skl)
+static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
+ struct skl *skl,
+ struct skl_module_cfg *src_mconfig)
{
struct snd_soc_dapm_path *p;
- struct skl_dapm_path_list *path_list;
- struct snd_soc_dapm_widget *source, *sink;
- struct skl_module_cfg *src_mconfig, *sink_mconfig;
+ struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
+ struct skl_module_cfg *sink_mconfig;
struct skl_sst *ctx = skl->skl_sst;
- int ret = 0;
-
- source = w;
- src_mconfig = source->priv;
+ int ret;
- /*
- * find which sink it is connected to, bind with the sink,
- * if sink is not started, start sink pipe first, then start
- * this pipe
- */
- snd_soc_dapm_widget_for_each_source_path(w, p) {
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
if (!p->connect)
continue;
dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
+ next_sink = p->sink;
/*
* here we will check widgets in sink pipelines, so that
* can be any widgets type and we are only interested if
@@ -441,7 +556,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
is_skl_dsp_widget_type(p->sink)) {
sink = p->sink;
- src_mconfig = source->priv;
sink_mconfig = sink->priv;
/* Bind source to sink, mixin is always source */
@@ -451,32 +565,89 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
/* Start sinks pipe first */
if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
- ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+ if (sink_mconfig->pipe->conn_type !=
+ SKL_PIPE_CONN_TYPE_FE)
+ ret = skl_run_pipe(ctx,
+ sink_mconfig->pipe);
if (ret)
return ret;
}
-
- path_list = kzalloc(
- sizeof(struct skl_dapm_path_list),
- GFP_KERNEL);
- if (path_list == NULL)
- return -ENOMEM;
-
- /* Add connected path to one global list */
- path_list->dapm_path = p;
- list_add_tail(&path_list->node, &skl->dapm_path_list);
- break;
}
}
- /* Start source pipe last after starting all sinks */
- ret = skl_run_pipe(ctx, src_mconfig->pipe);
+ if (!sink)
+ return skl_tplg_bind_sinks(next_sink, skl, src_mconfig);
+
+ return 0;
+}
+
+/*
+ * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
+ * we need to do following:
+ * - Bind to sink pipeline
+ * Since the sink pipes can be running and we don't get mixer event on
+ * connect for already running mixer, we need to find the sink pipes
+ * here and bind to them. This way dynamic connect works.
+ * - Start sink pipeline, if not running
+ * - Then run current pipe
+ */
+static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
+ struct skl *skl)
+{
+ struct skl_module_cfg *src_mconfig;
+ struct skl_sst *ctx = skl->skl_sst;
+ int ret = 0;
+
+ src_mconfig = w->priv;
+
+ /*
+ * find which sink it is connected to, bind with the sink,
+ * if sink is not started, start sink pipe first, then start
+ * this pipe
+ */
+ ret = skl_tplg_bind_sinks(w, skl, src_mconfig);
if (ret)
return ret;
+ /* Start source pipe last after starting all sinks */
+ if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+ return skl_run_pipe(ctx, src_mconfig->pipe);
+
return 0;
}
+static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
+ struct snd_soc_dapm_widget *w, struct skl *skl)
+{
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dapm_widget *src_w = NULL;
+ struct skl_sst *ctx = skl->skl_sst;
+
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
+ src_w = p->source;
+ if (!p->connect)
+ continue;
+
+ dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
+ dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+
+ /*
+ * here we will check widgets in sink pipelines, so that can
+ * be any widgets type and we are only interested if they are
+ * ones used for SKL so check that first
+ */
+ if ((p->source->priv != NULL) &&
+ is_skl_dsp_widget_type(p->source)) {
+ return p->source;
+ }
+ }
+
+ if (src_w != NULL)
+ return skl_get_src_dsp_widget(src_w, skl);
+
+ return NULL;
+}
+
/*
* in the Post-PMU event of mixer we need to do following:
* - Check if this pipe is running
@@ -490,7 +661,6 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
struct skl *skl)
{
int ret = 0;
- struct snd_soc_dapm_path *p;
struct snd_soc_dapm_widget *source, *sink;
struct skl_module_cfg *src_mconfig, *sink_mconfig;
struct skl_sst *ctx = skl->skl_sst;
@@ -504,32 +674,18 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
* one more sink before this sink got connected, Since source is
* started, bind this sink to source and start this pipe.
*/
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (!p->connect)
- continue;
-
- dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
- dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+ source = skl_get_src_dsp_widget(w, skl);
+ if (source != NULL) {
+ src_mconfig = source->priv;
+ sink_mconfig = sink->priv;
+ src_pipe_started = 1;
/*
- * here we will check widgets in sink pipelines, so that
- * can be any widgets type and we are only interested if
- * they are ones used for SKL so check that first
+ * check pipe state, then no need to bind or start the
+ * pipe
*/
- if ((p->source->priv != NULL) &&
- is_skl_dsp_widget_type(p->source)) {
- source = p->source;
- src_mconfig = source->priv;
- sink_mconfig = sink->priv;
- src_pipe_started = 1;
-
- /*
- * check pipe state, then no need to bind or start
- * the pipe
- */
- if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
- src_pipe_started = 0;
- }
+ if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
+ src_pipe_started = 0;
}
if (src_pipe_started) {
@@ -537,7 +693,8 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
- ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+ if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+ ret = skl_run_pipe(ctx, sink_mconfig->pipe);
}
return ret;
@@ -552,52 +709,35 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
struct skl *skl)
{
- struct snd_soc_dapm_widget *source, *sink;
struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int ret = 0, path_found = 0;
- struct skl_dapm_path_list *path_list, *tmp_list;
+ int ret = 0, i;
struct skl_sst *ctx = skl->skl_sst;
- sink = w;
- sink_mconfig = sink->priv;
+ sink_mconfig = w->priv;
/* Stop the pipe */
ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
if (ret)
return ret;
- /*
- * This list, dapm_path_list handling here does not need any locks
- * as we are under dapm lock while handling widget events.
- * List can be manipulated safely only under dapm widgets handler
- * routines
- */
- list_for_each_entry_safe(path_list, tmp_list,
- &skl->dapm_path_list, node) {
- if (path_list->dapm_path->sink == sink) {
- dev_dbg(ctx->dev, "Path found = %s\n",
- path_list->dapm_path->name);
- source = path_list->dapm_path->source;
- src_mconfig = source->priv;
- path_found = 1;
-
- list_del(&path_list->node);
- kfree(path_list);
- break;
- }
- }
-
- /*
- * If path_found == 1, that means pmd for source pipe has
- * not occurred, source is connected to some other sink.
- * so its responsibility of sink to unbind itself from source.
- */
- if (path_found) {
- ret = skl_stop_pipe(ctx, src_mconfig->pipe);
- if (ret < 0)
- return ret;
+ for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+ if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+ src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
+ if (!src_mconfig)
+ continue;
+ /*
+ * If path_found == 1, that means pmd for source
+ * pipe has not occurred, source is connected to
+ * some other sink. so its responsibility of sink
+ * to unbind itself from source.
+ */
+ ret = skl_stop_pipe(ctx, src_mconfig->pipe);
+ if (ret < 0)
+ return ret;
- ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
+ ret = skl_unbind_modules(ctx,
+ src_mconfig, sink_mconfig);
+ }
}
return ret;
@@ -622,10 +762,12 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
int ret = 0;
skl_tplg_free_pipe_mcps(skl, mconfig);
+ skl_tplg_free_pipe_mem(skl, mconfig);
list_for_each_entry(w_module, &s_pipe->w_list, node) {
dst_module = w_module->w->priv;
+ skl_tplg_free_pipe_mcps(skl, dst_module);
if (src_module == NULL) {
src_module = dst_module;
continue;
@@ -639,9 +781,8 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
}
ret = skl_delete_pipe(ctx, mconfig->pipe);
- skl_tplg_free_pipe_mem(skl, mconfig);
- return ret;
+ return skl_tplg_unload_pipe_modules(ctx, s_pipe);
}
/*
@@ -653,47 +794,34 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
struct skl *skl)
{
- struct snd_soc_dapm_widget *source, *sink;
struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int ret = 0, path_found = 0;
- struct skl_dapm_path_list *path_list, *tmp_path_list;
+ int ret = 0, i;
struct skl_sst *ctx = skl->skl_sst;
- source = w;
- src_mconfig = source->priv;
+ src_mconfig = w->priv;
- skl_tplg_free_pipe_mcps(skl, src_mconfig);
/* Stop the pipe since this is a mixin module */
ret = skl_stop_pipe(ctx, src_mconfig->pipe);
if (ret)
return ret;
- list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) {
- if (path_list->dapm_path->source == source) {
- dev_dbg(ctx->dev, "Path found = %s\n",
- path_list->dapm_path->name);
- sink = path_list->dapm_path->sink;
- sink_mconfig = sink->priv;
- path_found = 1;
-
- list_del(&path_list->node);
- kfree(path_list);
- break;
+ for (i = 0; i < src_mconfig->max_out_queue; i++) {
+ if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+ sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
+ if (!sink_mconfig)
+ continue;
+ /*
+ * This is a connecter and if path is found that means
+ * unbind between source and sink has not happened yet
+ */
+ ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
+ if (ret < 0)
+ return ret;
+ ret = skl_unbind_modules(ctx, src_mconfig,
+ sink_mconfig);
}
}
- /*
- * This is a connector and if path is found that means
- * unbind between source and sink has not happened yet
- */
- if (path_found) {
- ret = skl_stop_pipe(ctx, src_mconfig->pipe);
- if (ret < 0)
- return ret;
-
- ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
- }
-
return ret;
}
@@ -774,6 +902,67 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
+ unsigned int __user *data, unsigned int size)
+{
+ struct soc_bytes_ext *sb =
+ (struct soc_bytes_ext *)kcontrol->private_value;
+ struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct skl_module_cfg *mconfig = w->priv;
+ struct skl *skl = get_skl_ctx(w->dapm->dev);
+
+ if (w->power)
+ skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
+ bc->max, bc->param_id, mconfig);
+
+ if (bc->params) {
+ if (copy_to_user(data, &bc->param_id, sizeof(u32)))
+ return -EFAULT;
+ if (copy_to_user(data + 1, &size, sizeof(u32)))
+ return -EFAULT;
+ if (copy_to_user(data + 2, bc->params, size))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+#define SKL_PARAM_VENDOR_ID 0xff
+
+static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
+ const unsigned int __user *data, unsigned int size)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct skl_module_cfg *mconfig = w->priv;
+ struct soc_bytes_ext *sb =
+ (struct soc_bytes_ext *)kcontrol->private_value;
+ struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
+ struct skl *skl = get_skl_ctx(w->dapm->dev);
+
+ if (ac->params) {
+ /*
+ * if the param_is is of type Vendor, firmware expects actual
+ * parameter id and size from the control.
+ */
+ if (ac->param_id == SKL_PARAM_VENDOR_ID) {
+ if (copy_from_user(ac->params, data, size))
+ return -EFAULT;
+ } else {
+ if (copy_from_user(ac->params,
+ data + 2 * sizeof(u32), size))
+ return -EFAULT;
+ }
+
+ if (w->power)
+ return skl_set_module_params(skl->skl_sst,
+ (u32 *)ac->params, ac->max,
+ ac->param_id, mconfig);
+ }
+
+ return 0;
+}
+
/*
* The FE params are passed by hw_params of the DAI.
* On hw_params, the params are stored in Gateway module of the FE and we
@@ -790,9 +979,9 @@ int skl_tplg_update_pipe_params(struct device *dev,
memcpy(pipe->p_params, params, sizeof(*params));
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
- format = &mconfig->in_fmt;
+ format = &mconfig->in_fmt[0];
else
- format = &mconfig->out_fmt;
+ format = &mconfig->out_fmt[0];
/* set the hw_params */
format->s_freq = params->s_freq;
@@ -809,6 +998,7 @@ int skl_tplg_update_pipe_params(struct device *dev,
break;
case SKL_DEPTH_24BIT:
+ case SKL_DEPTH_32BIT:
format->bit_depth = SKL_DEPTH_32BIT;
break;
@@ -846,7 +1036,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
w = dai->playback_widget;
snd_soc_dapm_widget_for_each_sink_path(w, p) {
if (p->connect && p->sink->power &&
- is_skl_dsp_widget_type(p->sink))
+ !is_skl_dsp_widget_type(p->sink))
continue;
if (p->sink->priv) {
@@ -859,7 +1049,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
w = dai->capture_widget;
snd_soc_dapm_widget_for_each_source_path(w, p) {
if (p->connect && p->source->power &&
- is_skl_dsp_widget_type(p->source))
+ !is_skl_dsp_widget_type(p->source))
continue;
if (p->source->priv) {
@@ -920,6 +1110,9 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
memcpy(pipe->p_params, params, sizeof(*params));
+ if (link_type == NHLT_LINK_HDA)
+ return 0;
+
/* update the blob based on virtual bus_id*/
cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
params->s_fmt, params->ch,
@@ -950,18 +1143,13 @@ static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
if (p->connect && is_skl_dsp_widget_type(p->source) &&
p->source->priv) {
- if (!p->source->power) {
- ret = skl_tplg_be_fill_pipe_params(
- dai, p->source->priv,
- params);
- if (ret < 0)
- return ret;
- } else {
- return -EBUSY;
- }
+ ret = skl_tplg_be_fill_pipe_params(dai,
+ p->source->priv, params);
+ if (ret < 0)
+ return ret;
} else {
- ret = skl_tplg_be_set_src_pipe_params(
- dai, p->source, params);
+ ret = skl_tplg_be_set_src_pipe_params(dai,
+ p->source, params);
if (ret < 0)
return ret;
}
@@ -980,15 +1168,10 @@ static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
if (p->connect && is_skl_dsp_widget_type(p->sink) &&
p->sink->priv) {
- if (!p->sink->power) {
- ret = skl_tplg_be_fill_pipe_params(
- dai, p->sink->priv, params);
- if (ret < 0)
- return ret;
- } else {
- return -EBUSY;
- }
-
+ ret = skl_tplg_be_fill_pipe_params(dai,
+ p->sink->priv, params);
+ if (ret < 0)
+ return ret;
} else {
ret = skl_tplg_be_set_sink_pipe_params(
dai, p->sink, params);
@@ -1030,6 +1213,11 @@ static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
{SKL_PGA_EVENT, skl_tplg_pga_event},
};
+static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
+ {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
+ skl_tplg_tlv_control_set},
+};
+
/*
* The topology binary passes the pin info for a module so initialize the pin
* info passed into module instance
@@ -1045,6 +1233,7 @@ static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
m_pin[i].id.instance_id = dfw_pin[i].instance_id;
m_pin[i].in_use = false;
m_pin[i].is_dynamic = is_dynamic;
+ m_pin[i].pin_state = SKL_PIN_UNBIND;
}
}
@@ -1092,6 +1281,24 @@ static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
return ppl->pipe;
}
+static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
+ struct skl_dfw_module_fmt *src_fmt,
+ int pins)
+{
+ int i;
+
+ for (i = 0; i < pins; i++) {
+ dst_fmt[i].channels = src_fmt[i].channels;
+ dst_fmt[i].s_freq = src_fmt[i].freq;
+ dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
+ dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
+ dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
+ dst_fmt[i].ch_map = src_fmt[i].ch_map;
+ dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
+ dst_fmt[i].sample_type = src_fmt[i].sample_type;
+ }
+}
+
/*
* Topology core widget load callback
*
@@ -1130,22 +1337,16 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
mconfig->max_in_queue = dfw_config->max_in_queue;
mconfig->max_out_queue = dfw_config->max_out_queue;
mconfig->is_loadable = dfw_config->is_loadable;
- mconfig->in_fmt.channels = dfw_config->in_fmt.channels;
- mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq;
- mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth;
- mconfig->in_fmt.valid_bit_depth =
- dfw_config->in_fmt.valid_bit_depth;
- mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg;
- mconfig->out_fmt.channels = dfw_config->out_fmt.channels;
- mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq;
- mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth;
- mconfig->out_fmt.valid_bit_depth =
- dfw_config->out_fmt.valid_bit_depth;
- mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg;
+ skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
+ MODULE_MAX_IN_PINS);
+ skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
+ MODULE_MAX_OUT_PINS);
+
mconfig->params_fixup = dfw_config->params_fixup;
mconfig->converter = dfw_config->converter;
mconfig->m_type = dfw_config->module_type;
mconfig->vbus_id = dfw_config->vbus_id;
+ mconfig->mem_pages = dfw_config->mem_pages;
pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
if (pipe)
@@ -1156,10 +1357,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
mconfig->time_slot = dfw_config->time_slot;
mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
- mconfig->m_in_pin = devm_kzalloc(bus->dev,
- (mconfig->max_in_queue) *
- sizeof(*mconfig->m_in_pin),
- GFP_KERNEL);
+ if (dfw_config->is_loadable)
+ memcpy(mconfig->guid, dfw_config->uuid,
+ ARRAY_SIZE(dfw_config->uuid));
+
+ mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
+ sizeof(*mconfig->m_in_pin),
+ GFP_KERNEL);
if (!mconfig->m_in_pin)
return -ENOMEM;
@@ -1188,7 +1392,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
return -ENOMEM;
memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
- dfw_config->caps.caps_size);
+ dfw_config->caps.caps_size);
+ mconfig->formats_config.param_id = dfw_config->caps.param_id;
+ mconfig->formats_config.set_params = dfw_config->caps.set_params;
bind_event:
if (tplg_w->event_type == 0) {
@@ -1209,8 +1415,70 @@ bind_event:
return 0;
}
+static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
+ struct snd_soc_tplg_bytes_control *bc)
+{
+ struct skl_algo_data *ac;
+ struct skl_dfw_algo_data *dfw_ac =
+ (struct skl_dfw_algo_data *)bc->priv.data;
+
+ ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
+ if (!ac)
+ return -ENOMEM;
+
+ /* Fill private data */
+ ac->max = dfw_ac->max;
+ ac->param_id = dfw_ac->param_id;
+ ac->set_params = dfw_ac->set_params;
+
+ if (ac->max) {
+ ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
+ if (!ac->params)
+ return -ENOMEM;
+
+ if (dfw_ac->params)
+ memcpy(ac->params, dfw_ac->params, ac->max);
+ }
+
+ be->dobj.private = ac;
+ return 0;
+}
+
+static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
+ struct snd_kcontrol_new *kctl,
+ struct snd_soc_tplg_ctl_hdr *hdr)
+{
+ struct soc_bytes_ext *sb;
+ struct snd_soc_tplg_bytes_control *tplg_bc;
+ struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ switch (hdr->ops.info) {
+ case SND_SOC_TPLG_CTL_BYTES:
+ tplg_bc = container_of(hdr,
+ struct snd_soc_tplg_bytes_control, hdr);
+ if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ sb = (struct soc_bytes_ext *)kctl->private_value;
+ if (tplg_bc->priv.size)
+ return skl_init_algo_data(
+ bus->dev, sb, tplg_bc);
+ }
+ break;
+
+ default:
+ dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
+ hdr->ops.get, hdr->ops.put, hdr->ops.info);
+ break;
+ }
+
+ return 0;
+}
+
static struct snd_soc_tplg_ops skl_tplg_ops = {
.widget_load = skl_tplg_widget_load,
+ .control_load = skl_tplg_control_load,
+ .bytes_ext_ops = skl_tlv_ops,
+ .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
};
/* This will be read from topology manifest, currently defined here */
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 76053a8de41c..9aa2a2b6598a 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -36,6 +36,9 @@
/* Maximum number of coefficients up down mixer module */
#define UP_DOWN_MIXER_MAX_COEFF 6
+#define MODULE_MAX_IN_PINS 8
+#define MODULE_MAX_OUT_PINS 8
+
enum skl_channel_index {
SKL_CHANNEL_LEFT = 0,
SKL_CHANNEL_RIGHT = 1,
@@ -55,12 +58,6 @@ enum skl_bitdepth {
SKL_DEPTH_INVALID
};
-enum skl_interleaving {
- /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */
- SKL_INTERLEAVING_PER_CHANNEL = 0,
- /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */
- SKL_INTERLEAVING_PER_SAMPLE = 1,
-};
enum skl_s_freq {
SKL_FS_8000 = 8000,
@@ -143,6 +140,16 @@ struct skl_up_down_mixer_cfg {
s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
} __packed;
+struct skl_algo_cfg {
+ struct skl_base_cfg base_cfg;
+ char params[0];
+} __packed;
+
+struct skl_base_outfmt_cfg {
+ struct skl_base_cfg base_cfg;
+ struct skl_audio_data_format out_fmt;
+} __packed;
+
enum skl_dma_type {
SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0,
SKL_DMA_HDA_HOST_INPUT_CLASS = 1,
@@ -178,21 +185,34 @@ struct skl_module_fmt {
u32 bit_depth;
u32 valid_bit_depth;
u32 ch_cfg;
+ u32 interleaving_style;
+ u32 sample_type;
+ u32 ch_map;
};
+struct skl_module_cfg;
+
struct skl_module_inst_id {
u32 module_id;
u32 instance_id;
};
+enum skl_module_pin_state {
+ SKL_PIN_UNBIND = 0,
+ SKL_PIN_BIND_DONE = 1,
+};
+
struct skl_module_pin {
struct skl_module_inst_id id;
- u8 pin_index;
bool is_dynamic;
bool in_use;
+ enum skl_module_pin_state pin_state;
+ struct skl_module_cfg *tgt_mcfg;
};
struct skl_specific_cfg {
+ u32 set_params;
+ u32 param_id;
u32 caps_size;
u32 *caps;
};
@@ -238,9 +258,13 @@ enum skl_module_state {
};
struct skl_module_cfg {
+ char guid[SKL_UUID_STR_SZ];
struct skl_module_inst_id id;
- struct skl_module_fmt in_fmt;
- struct skl_module_fmt out_fmt;
+ u8 domain;
+ bool homogenous_inputs;
+ bool homogenous_outputs;
+ struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS];
+ struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS];
u8 max_in_queue;
u8 max_out_queue;
u8 in_queue_mask;
@@ -258,6 +282,7 @@ struct skl_module_cfg {
u32 params_fixup;
u32 converter;
u32 vbus_id;
+ u32 mem_pages;
struct skl_module_pin *m_in_pin;
struct skl_module_pin *m_out_pin;
enum skl_module_type m_type;
@@ -267,13 +292,15 @@ struct skl_module_cfg {
struct skl_specific_cfg formats_config;
};
-struct skl_pipeline {
- struct skl_pipe *pipe;
- struct list_head node;
+struct skl_algo_data {
+ u32 param_id;
+ u32 set_params;
+ u32 max;
+ char *params;
};
-struct skl_dapm_path_list {
- struct snd_soc_dapm_path *dapm_path;
+struct skl_pipeline {
+ struct skl_pipe *pipe;
struct list_head node;
};
@@ -305,8 +332,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
-int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config,
- char *param);
+int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config);
int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
*src_module, struct skl_module_cfg *dst_module);
@@ -314,5 +340,10 @@ int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg
*src_module, struct skl_module_cfg *dst_module);
+int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
+ u32 param_id, struct skl_module_cfg *mcfg);
+int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
+ u32 param_id, struct skl_module_cfg *mcfg);
+
enum skl_bitdepth skl_get_bit_depth(int params);
#endif
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
index 2bc396d54cbe..c9ae010b3cc8 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -23,15 +23,13 @@
* Default types range from 0~12. type can range from 0 to 0xff
* SST types start at higher to avoid any overlapping in future
*/
-#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS 0x100
-#define SOC_CONTROL_TYPE_HDA_SST_MUX 0x101
-#define SOC_CONTROL_TYPE_HDA_SST_MIX 0x101
-#define SOC_CONTROL_TYPE_HDA_SST_BYTE 0x103
+#define SKL_CONTROL_TYPE_BYTE_TLV 0x100
#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/
#define MAX_IN_QUEUE 8
#define MAX_OUT_QUEUE 8
+#define SKL_UUID_STR_SZ 40
/* Event types goes here */
/* Reserve event type 0 for no event handlers */
enum skl_event_types {
@@ -72,6 +70,7 @@ enum skl_ch_cfg {
SKL_CH_CFG_DUAL_MONO = 9,
SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
+ SKL_CH_CFG_4_CHANNEL = 12,
SKL_CH_CFG_INVALID
};
@@ -79,7 +78,9 @@ enum skl_module_type {
SKL_MODULE_TYPE_MIXER = 0,
SKL_MODULE_TYPE_COPIER,
SKL_MODULE_TYPE_UPDWMIX,
- SKL_MODULE_TYPE_SRCINT
+ SKL_MODULE_TYPE_SRCINT,
+ SKL_MODULE_TYPE_ALGO,
+ SKL_MODULE_TYPE_BASE_OUTFMT
};
enum skl_core_affinity {
@@ -110,6 +111,42 @@ enum skl_dev_type {
SKL_DEVICE_NONE
};
+/**
+ * enum skl_interleaving - interleaving style
+ *
+ * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
+ * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
+ */
+enum skl_interleaving {
+ SKL_INTERLEAVING_PER_CHANNEL = 0,
+ SKL_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum skl_sample_type {
+ SKL_SAMPLE_TYPE_INT_MSB = 0,
+ SKL_SAMPLE_TYPE_INT_LSB = 1,
+ SKL_SAMPLE_TYPE_INT_SIGNED = 2,
+ SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
+ SKL_SAMPLE_TYPE_FLOAT = 4
+};
+
+enum module_pin_type {
+ /* All pins of the module takes same PCM inputs or outputs
+ * e.g. mixout
+ */
+ SKL_PIN_TYPE_HOMOGENEOUS,
+ /* All pins of the module takes different PCM inputs or outputs
+ * e.g mux
+ */
+ SKL_PIN_TYPE_HETEROGENEOUS,
+};
+
+enum skl_module_param_type {
+ SKL_PARAM_DEFAULT = 0,
+ SKL_PARAM_INIT,
+ SKL_PARAM_SET
+};
+
struct skl_dfw_module_pin {
u16 module_id;
u16 instance_id;
@@ -121,9 +158,15 @@ struct skl_dfw_module_fmt {
u32 bit_depth;
u32 valid_bit_depth;
u32 ch_cfg;
+ u32 interleaving_style;
+ u32 sample_type;
+ u32 ch_map;
} __packed;
struct skl_dfw_module_caps {
+ u32 set_params:2;
+ u32 rsvd:30;
+ u32 param_id;
u32 caps_size;
u32 caps[HDA_SST_CFG_MAX];
};
@@ -131,41 +174,57 @@ struct skl_dfw_module_caps {
struct skl_dfw_pipe {
u8 pipe_id;
u8 pipe_priority;
- u16 conn_type;
- u32 memory_pages;
+ u16 conn_type:4;
+ u16 rsvd:4;
+ u16 memory_pages:8;
} __packed;
struct skl_dfw_module {
+ char uuid[SKL_UUID_STR_SZ];
+
u16 module_id;
u16 instance_id;
u32 max_mcps;
- u8 core_id;
- u8 max_in_queue;
- u8 max_out_queue;
- u8 is_loadable;
- u8 conn_type;
- u8 dev_type;
- u8 hw_conn_type;
- u8 time_slot;
+ u32 mem_pages;
u32 obs;
u32 ibs;
- u32 params_fixup;
- u32 converter;
- u32 module_type;
u32 vbus_id;
- u8 is_dynamic_in_pin;
- u8 is_dynamic_out_pin;
+
+ u32 max_in_queue:8;
+ u32 max_out_queue:8;
+ u32 time_slot:8;
+ u32 core_id:4;
+ u32 rsvd1:4;
+
+ u32 module_type:8;
+ u32 conn_type:4;
+ u32 dev_type:4;
+ u32 hw_conn_type:4;
+ u32 rsvd2:12;
+
+ u32 params_fixup:8;
+ u32 converter:8;
+ u32 input_pin_type:1;
+ u32 output_pin_type:1;
+ u32 is_dynamic_in_pin:1;
+ u32 is_dynamic_out_pin:1;
+ u32 is_loadable:1;
+ u32 rsvd3:11;
+
struct skl_dfw_pipe pipe;
- struct skl_dfw_module_fmt in_fmt;
- struct skl_dfw_module_fmt out_fmt;
+ struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE];
+ struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE];
struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
struct skl_dfw_module_caps caps;
} __packed;
struct skl_dfw_algo_data {
+ u32 set_params:2;
+ u32 rsvd:30;
+ u32 param_id;
u32 max;
- char *params;
+ char params[0];
} __packed;
#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index caa69c4598a6..443a15de94b5 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -27,7 +27,10 @@
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <sound/pcm.h>
+#include "../common/sst-acpi.h"
#include "skl.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
/*
* initialize the PCI registers
@@ -58,6 +61,49 @@ static void skl_init_pci(struct skl *skl)
skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
}
+static void update_pci_dword(struct pci_dev *pci,
+ unsigned int reg, u32 mask, u32 val)
+{
+ u32 data = 0;
+
+ pci_read_config_dword(pci, reg, &data);
+ data &= ~mask;
+ data |= (val & mask);
+ pci_write_config_dword(pci, reg, data);
+}
+
+/*
+ * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits
+ *
+ * @dev: device pointer
+ * @enable: enable/disable flag
+ */
+static void skl_enable_miscbdcge(struct device *dev, bool enable)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ u32 val;
+
+ val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
+
+ update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val);
+}
+
+/*
+ * While performing reset, controller may not come back properly causing
+ * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
+ * (init chip) and then again set CGCTL.MISCBDCGE to 1
+ */
+static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
+{
+ int ret;
+
+ skl_enable_miscbdcge(bus->dev, false);
+ ret = snd_hdac_bus_init_chip(bus, full_reset);
+ skl_enable_miscbdcge(bus->dev, true);
+
+ return ret;
+}
+
/* called from IRQ */
static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
{
@@ -130,6 +176,39 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
return 0;
}
+#ifdef CONFIG_PM
+static int _skl_suspend(struct hdac_ext_bus *ebus)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ int ret;
+
+ snd_hdac_ext_bus_link_power_down_all(ebus);
+
+ ret = skl_suspend_dsp(skl);
+ if (ret < 0)
+ return ret;
+
+ snd_hdac_bus_stop_chip(bus);
+ skl_enable_miscbdcge(bus->dev, false);
+ snd_hdac_bus_enter_link_reset(bus);
+ skl_enable_miscbdcge(bus->dev, true);
+
+ return 0;
+}
+
+static int _skl_resume(struct hdac_ext_bus *ebus)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ skl_init_pci(skl);
+ skl_init_chip(bus, true);
+
+ return skl_resume_dsp(skl);
+}
+#endif
+
#ifdef CONFIG_PM_SLEEP
/*
* power management
@@ -138,26 +217,46 @@ static int skl_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct skl *skl = ebus_to_skl(ebus);
struct hdac_bus *bus = ebus_to_hbus(ebus);
- snd_hdac_bus_stop_chip(bus);
- snd_hdac_bus_enter_link_reset(bus);
-
- return 0;
+ /*
+ * Do not suspend if streams which are marked ignore suspend are
+ * running, we need to save the state for these and continue
+ */
+ if (skl->supend_active) {
+ snd_hdac_ext_bus_link_power_down_all(ebus);
+ enable_irq_wake(bus->irq);
+ pci_save_state(pci);
+ pci_disable_device(pci);
+ return 0;
+ } else {
+ return _skl_suspend(ebus);
+ }
}
static int skl_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct skl *skl = ebus_to_skl(ebus);
struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *hda = ebus_to_skl(ebus);
-
- skl_init_pci(hda);
+ int ret;
- snd_hdac_bus_init_chip(bus, 1);
+ /*
+ * resume only when we are not in suspend active, otherwise need to
+ * restore the device
+ */
+ if (skl->supend_active) {
+ pci_restore_state(pci);
+ ret = pci_enable_device(pci);
+ snd_hdac_ext_bus_link_power_up_all(ebus);
+ disable_irq_wake(bus->irq);
+ } else {
+ ret = _skl_resume(ebus);
+ }
- return 0;
+ return ret;
}
#endif /* CONFIG_PM_SLEEP */
@@ -167,24 +266,10 @@ static int skl_runtime_suspend(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *skl = ebus_to_skl(ebus);
- int ret;
dev_dbg(bus->dev, "in %s\n", __func__);
- /* enable controller wake up event */
- snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK);
-
- snd_hdac_ext_bus_link_power_down_all(ebus);
-
- ret = skl_suspend_dsp(skl);
- if (ret < 0)
- return ret;
-
- snd_hdac_bus_stop_chip(bus);
- snd_hdac_bus_enter_link_reset(bus);
-
- return 0;
+ return _skl_suspend(ebus);
}
static int skl_runtime_resume(struct device *dev)
@@ -192,20 +277,10 @@ static int skl_runtime_resume(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *skl = ebus_to_skl(ebus);
- int status;
dev_dbg(bus->dev, "in %s\n", __func__);
- /* Read STATESTS before controller reset */
- status = snd_hdac_chip_readw(bus, STATESTS);
-
- skl_init_pci(skl);
- snd_hdac_bus_init_chip(bus, true);
- /* disable controller Wake Up event */
- snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
-
- return skl_resume_dsp(skl);
+ return _skl_resume(ebus);
}
#endif /* CONFIG_PM */
@@ -242,6 +317,43 @@ static int skl_free(struct hdac_ext_bus *ebus)
return 0;
}
+static int skl_machine_device_register(struct skl *skl, void *driver_data)
+{
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct platform_device *pdev;
+ struct sst_acpi_mach *mach = driver_data;
+ int ret;
+
+ mach = sst_acpi_find_machine(mach);
+ if (mach == NULL) {
+ dev_err(bus->dev, "No matching machine driver found\n");
+ return -ENODEV;
+ }
+ skl->fw_name = mach->fw_filename;
+
+ pdev = platform_device_alloc(mach->drv_name, -1);
+ if (pdev == NULL) {
+ dev_err(bus->dev, "platform device alloc failed\n");
+ return -EIO;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(bus->dev, "failed to add machine device\n");
+ platform_device_put(pdev);
+ return -EIO;
+ }
+ skl->i2s_dev = pdev;
+
+ return 0;
+}
+
+static void skl_machine_device_unregister(struct skl *skl)
+{
+ if (skl->i2s_dev)
+ platform_device_unregister(skl->i2s_dev);
+}
+
static int skl_dmic_device_register(struct skl *skl)
{
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
@@ -321,7 +433,7 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
* back to the sanity state.
*/
snd_hdac_bus_stop_chip(bus);
- snd_hdac_bus_init_chip(bus, true);
+ skl_init_chip(bus, true);
}
}
}
@@ -431,12 +543,11 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
/* initialize chip */
skl_init_pci(skl);
- snd_hdac_bus_init_chip(bus, true);
+ skl_init_chip(bus, true);
/* codec detection */
if (!bus->codec_mask) {
- dev_err(bus->dev, "no codecs found!\n");
- return -ENODEV;
+ dev_info(bus->dev, "no hda codecs found!\n");
}
return 0;
@@ -471,11 +582,18 @@ static int skl_probe(struct pci_dev *pci,
/* check if dsp is there */
if (ebus->ppcap) {
+ err = skl_machine_device_register(skl,
+ (void *)pci_id->driver_data);
+ if (err < 0)
+ goto out_free;
+
err = skl_init_dsp(skl);
if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n");
- goto out_free;
+ goto out_mach_free;
}
+ skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+
}
if (ebus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(ebus);
@@ -509,6 +627,8 @@ out_dmic_free:
skl_dmic_device_unregister(skl);
out_dsp_free:
skl_free_dsp(skl);
+out_mach_free:
+ skl_machine_device_unregister(skl);
out_free:
skl->init_failed = 1;
skl_free(ebus);
@@ -529,15 +649,26 @@ static void skl_remove(struct pci_dev *pci)
pci_dev_put(pci);
skl_platform_unregister(&pci->dev);
skl_free_dsp(skl);
+ skl_machine_device_unregister(skl);
skl_dmic_device_unregister(skl);
skl_free(ebus);
dev_set_drvdata(&pci->dev, NULL);
}
+static struct sst_acpi_mach sst_skl_devdata[] = {
+ { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
+ { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin",
+ NULL, NULL, NULL },
+ { "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin",
+ NULL, NULL, NULL },
+ {}
+};
+
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */
- { PCI_DEVICE(0x8086, 0x9d70), 0},
+ { PCI_DEVICE(0x8086, 0x9d70),
+ .driver_data = (unsigned long)&sst_skl_devdata},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index a0709e344d44..4d18293b5537 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -48,6 +48,9 @@
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
+#define AZX_PCIREG_CGCTL 0x48
+#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6)
+
struct skl_dsp_resource {
u32 max_mcps;
u32 max_mem;
@@ -61,15 +64,18 @@ struct skl {
unsigned int init_failed:1; /* delayed init failed */
struct platform_device *dmic_dev;
+ struct platform_device *i2s_dev;
void *nhlt; /* nhlt ptr */
struct skl_sst *skl_sst; /* sst skl ctx */
struct skl_dsp_resource resource;
struct list_head ppl_list;
- struct list_head dapm_path_list;
+ const char *fw_name;
const struct firmware *tplg;
+
+ int supend_active;
};
#define skl_to_ebus(s) (&(s)->ebus)
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h
index cc4393cb1130..9b1af1a70874 100644
--- a/sound/soc/mediatek/mtk-afe-common.h
+++ b/sound/soc/mediatek/mtk-afe-common.h
@@ -92,7 +92,6 @@ struct mtk_afe_memif_data {
struct mtk_afe_memif {
unsigned int phys_buf_addr;
int buffer_size;
- unsigned int hw_ptr; /* Previous IRQ's HW ptr */
struct snd_pcm_substream *substream;
const struct mtk_afe_memif_data *data;
const struct mtk_afe_irq_data *irqdata;
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c
index f5baf3c38863..08af9f5dc4ab 100644
--- a/sound/soc/mediatek/mtk-afe-pcm.c
+++ b/sound/soc/mediatek/mtk-afe-pcm.c
@@ -175,8 +175,17 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+ unsigned int hw_ptr;
+ int ret;
+
+ ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr);
+ if (ret || hw_ptr == 0) {
+ dev_err(afe->dev, "%s hw_ptr err\n", __func__);
+ hw_ptr = memif->phys_buf_addr;
+ }
- return bytes_to_frames(substream->runtime, memif->hw_ptr);
+ return bytes_to_frames(substream->runtime,
+ hw_ptr - memif->phys_buf_addr);
}
static const struct snd_pcm_ops mtk_afe_pcm_ops = {
@@ -299,8 +308,6 @@ static int mtk_afe_dais_enable_clks(struct mtk_afe *afe,
dev_err(afe->dev, "Failed to enable m_ck\n");
return ret;
}
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
- AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
}
if (b_ck) {
@@ -340,12 +347,8 @@ static int mtk_afe_dais_set_clks(struct mtk_afe *afe,
static void mtk_afe_dais_disable_clks(struct mtk_afe *afe,
struct clk *m_ck, struct clk *b_ck)
{
- if (m_ck) {
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
- AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
- AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
+ if (m_ck)
clk_disable_unprepare(m_ck);
- }
if (b_ck)
clk_disable_unprepare(b_ck);
}
@@ -360,6 +363,8 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream,
return 0;
mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
return 0;
}
@@ -373,10 +378,10 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream,
return;
mtk_afe_set_i2s_enable(afe, false);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
+ AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
-
- /* disable AFE */
- regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
}
static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream,
@@ -425,9 +430,6 @@ static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M],
afe->clocks[MTK_CLK_I2S3_B]);
-
- /* disable AFE */
- regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
}
static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream,
@@ -603,7 +605,6 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream,
memif->phys_buf_addr = substream->runtime->dma_addr;
memif->buffer_size = substream->runtime->dma_bytes;
- memif->hw_ptr = 0;
/* start */
regmap_write(afe->regmap,
@@ -672,17 +673,6 @@ static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream,
return snd_pcm_lib_free_pages(substream);
}
-static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-
- /* enable AFE */
- regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
- return 0;
-}
-
static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
@@ -738,7 +728,6 @@ static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
/* and clear pending IRQ */
regmap_write(afe->regmap, AFE_IRQ_CLR,
1 << memif->data->irq_clr_shift);
- memif->hw_ptr = 0;
return 0;
default:
return -EINVAL;
@@ -751,7 +740,6 @@ static const struct snd_soc_dai_ops mtk_afe_dai_ops = {
.shutdown = mtk_afe_dais_shutdown,
.hw_params = mtk_afe_dais_hw_params,
.hw_free = mtk_afe_dais_hw_free,
- .prepare = mtk_afe_dais_prepare,
.trigger = mtk_afe_dais_trigger,
};
@@ -1082,7 +1070,7 @@ static const struct regmap_config mtk_afe_regmap_config = {
static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id)
{
struct mtk_afe *afe = dev_id;
- unsigned int reg_value, hw_ptr;
+ unsigned int reg_value;
int i, ret;
ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, &reg_value);
@@ -1098,13 +1086,6 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id)
if (!(reg_value & (1 << memif->data->irq_clr_shift)))
continue;
- ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur,
- &hw_ptr);
- if (ret || hw_ptr == 0) {
- dev_err(afe->dev, "%s hw_ptr err\n", __func__);
- hw_ptr = memif->phys_buf_addr;
- }
- memif->hw_ptr = hw_ptr - memif->phys_buf_addr;
snd_pcm_period_elapsed(memif->substream);
}
@@ -1119,6 +1100,9 @@ static int mtk_afe_runtime_suspend(struct device *dev)
{
struct mtk_afe *afe = dev_get_drvdata(dev);
+ /* disable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
+
/* disable AFE clk */
regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
@@ -1165,6 +1149,9 @@ static int mtk_afe_runtime_resume(struct device *dev)
/* unmask all IRQs */
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff);
+
+ /* enable AFE */
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
return 0;
err_bck0:
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index 584b2372339e..f83cc2bc0fc4 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -368,6 +368,8 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
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);
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 6147e86e9b0f..416ea646c3b1 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -63,8 +63,7 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
sysclk = params_rate(params) * 512;
sspa_mclk = params_rate(params) * 64;
}
- sspa_div = freq_out;
- do_div(sspa_div, sspa_mclk);
+ sspa_div = freq_out / sspa_mclk;
snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 29bc60e85e92..5c8f9db50a47 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -81,8 +81,12 @@ static int rear_amp_power(struct snd_soc_codec *codec, int power)
static int rear_amp_event(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kctl, int event)
{
- struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec;
+ struct snd_soc_card *card = widget->dapm->card;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec = rtd->codec;
return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
}
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index e5101e0d2d37..00b6c9d039cf 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -355,6 +355,7 @@ static struct regmap_config lpass_cpu_regmap_config = {
.readable_reg = lpass_cpu_regmap_readable,
.volatile_reg = lpass_cpu_regmap_volatile,
.cache_type = REGCACHE_FLAT,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 58ee64594f07..6561c4cc2edd 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -34,13 +34,7 @@ struct rk_i2s_dev {
struct regmap *regmap;
-/*
- * Used to indicate the tx/rx status.
- * I2S controller hopes to start the tx and rx together,
- * also to stop them when they are both try to stop.
-*/
- bool tx_start;
- bool rx_start;
+ bool is_master_mode;
};
static int i2s_runtime_suspend(struct device *dev)
@@ -81,37 +75,29 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER,
- I2S_XFER_TXS_START | I2S_XFER_RXS_START,
- I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
- i2s->tx_start = true;
+ I2S_XFER_TXS_START,
+ I2S_XFER_TXS_START);
} else {
- i2s->tx_start = false;
-
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
- if (!i2s->rx_start) {
- regmap_update_bits(i2s->regmap, I2S_XFER,
- I2S_XFER_TXS_START |
- I2S_XFER_RXS_START,
- I2S_XFER_TXS_STOP |
- I2S_XFER_RXS_STOP);
+ regmap_update_bits(i2s->regmap, I2S_XFER,
+ I2S_XFER_TXS_START,
+ I2S_XFER_TXS_STOP);
- regmap_update_bits(i2s->regmap, I2S_CLR,
- I2S_CLR_TXC | I2S_CLR_RXC,
- I2S_CLR_TXC | I2S_CLR_RXC);
+ regmap_update_bits(i2s->regmap, I2S_CLR,
+ I2S_CLR_TXC,
+ I2S_CLR_TXC);
- regmap_read(i2s->regmap, I2S_CLR, &val);
+ regmap_read(i2s->regmap, I2S_CLR, &val);
- /* Should wait for clear operation to finish */
- while (val) {
- regmap_read(i2s->regmap, I2S_CLR, &val);
- retry--;
- if (!retry) {
- dev_warn(i2s->dev, "fail to clear\n");
- break;
- }
+ /* Should wait for clear operation to finish */
+ while (val & I2S_CLR_TXC) {
+ regmap_read(i2s->regmap, I2S_CLR, &val);
+ retry--;
+ if (!retry) {
+ dev_warn(i2s->dev, "fail to clear\n");
+ break;
}
}
}
@@ -127,37 +113,29 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER,
- I2S_XFER_TXS_START | I2S_XFER_RXS_START,
- I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
- i2s->rx_start = true;
+ I2S_XFER_RXS_START,
+ I2S_XFER_RXS_START);
} else {
- i2s->rx_start = false;
-
regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
- if (!i2s->tx_start) {
- regmap_update_bits(i2s->regmap, I2S_XFER,
- I2S_XFER_TXS_START |
- I2S_XFER_RXS_START,
- I2S_XFER_TXS_STOP |
- I2S_XFER_RXS_STOP);
+ regmap_update_bits(i2s->regmap, I2S_XFER,
+ I2S_XFER_RXS_START,
+ I2S_XFER_RXS_STOP);
- regmap_update_bits(i2s->regmap, I2S_CLR,
- I2S_CLR_TXC | I2S_CLR_RXC,
- I2S_CLR_TXC | I2S_CLR_RXC);
+ regmap_update_bits(i2s->regmap, I2S_CLR,
+ I2S_CLR_RXC,
+ I2S_CLR_RXC);
- regmap_read(i2s->regmap, I2S_CLR, &val);
+ regmap_read(i2s->regmap, I2S_CLR, &val);
- /* Should wait for clear operation to finish */
- while (val) {
- regmap_read(i2s->regmap, I2S_CLR, &val);
- retry--;
- if (!retry) {
- dev_warn(i2s->dev, "fail to clear\n");
- break;
- }
+ /* Should wait for clear operation to finish */
+ while (val & I2S_CLR_RXC) {
+ regmap_read(i2s->regmap, I2S_CLR, &val);
+ retry--;
+ if (!retry) {
+ dev_warn(i2s->dev, "fail to clear\n");
+ break;
}
}
}
@@ -174,9 +152,11 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_CBS_CFS:
/* Set source clock in Master mode */
val = I2S_CKR_MSS_MASTER;
+ i2s->is_master_mode = true;
break;
case SND_SOC_DAIFMT_CBM_CFM:
val = I2S_CKR_MSS_SLAVE;
+ i2s->is_master_mode = false;
break;
default:
return -EINVAL;
@@ -228,6 +208,26 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
struct rk_i2s_dev *i2s = to_info(dai);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned int val = 0;
+ unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck;
+
+ if (i2s->is_master_mode) {
+ mclk_rate = clk_get_rate(i2s->mclk);
+ bclk_rate = 2 * 32 * params_rate(params);
+ if (bclk_rate && mclk_rate % bclk_rate)
+ return -EINVAL;
+
+ div_bclk = mclk_rate / bclk_rate;
+ div_lrck = bclk_rate / params_rate(params);
+ regmap_update_bits(i2s->regmap, I2S_CKR,
+ I2S_CKR_MDIV_MASK,
+ I2S_CKR_MDIV(div_bclk));
+
+ regmap_update_bits(i2s->regmap, I2S_CKR,
+ I2S_CKR_TSD_MASK |
+ I2S_CKR_RSD_MASK,
+ I2S_CKR_TSD(div_lrck) |
+ I2S_CKR_RSD(div_lrck));
+ }
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
@@ -242,6 +242,9 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S24_LE:
val |= I2S_TXCR_VDW(24);
break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ val |= I2S_TXCR_VDW(32);
+ break;
default:
return -EINVAL;
}
@@ -360,7 +363,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
.formats = (SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
- SNDRV_PCM_FMTBIT_S24_LE),
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
},
.capture = {
.stream_name = "Capture",
@@ -370,7 +374,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
.formats = (SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
- SNDRV_PCM_FMTBIT_S24_LE),
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
},
.ops = &rockchip_i2s_dai_ops,
.symmetric_rates = 1,
@@ -451,6 +456,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct rk_i2s_dev *i2s;
+ struct snd_soc_dai_driver *soc_dai;
struct resource *res;
void __iomem *regs;
int ret;
@@ -511,17 +517,26 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}
- /* refine capture channels */
+ soc_dai = devm_kzalloc(&pdev->dev,
+ sizeof(*soc_dai), GFP_KERNEL);
+ if (!soc_dai)
+ return -ENOMEM;
+
+ memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai));
+ if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
+ if (val >= 2 && val <= 8)
+ soc_dai->playback.channels_max = val;
+ }
+
if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
if (val >= 2 && val <= 8)
- rockchip_i2s_dai.capture.channels_max = val;
- else
- rockchip_i2s_dai.capture.channels_max = 2;
+ soc_dai->capture.channels_max = val;
}
ret = devm_snd_soc_register_component(&pdev->dev,
&rockchip_i2s_component,
- &rockchip_i2s_dai, 1);
+ soc_dai, 1);
+
if (ret) {
dev_err(&pdev->dev, "Could not register DAI\n");
goto err_suspend;
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 26567b10393a..543610282cdb 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -80,11 +80,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 8000:
case 16000:
+ case 24000:
+ case 32000:
case 48000:
+ case 64000:
case 96000:
mclk = 12288000;
break;
+ case 11025:
+ case 22050:
case 44100:
+ case 88200:
mclk = 11289600;
break;
default:
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index 68c62e4c2316..440a8026346a 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -79,11 +79,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 8000:
case 16000:
+ case 24000:
+ case 32000:
case 48000:
+ case 64000:
case 96000:
mclk = 12288000;
break;
+ case 11025:
+ case 22050:
case 44100:
+ case 88200:
mclk = 11289600;
break;
default:
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 3744c9ed5370..78baa26e938b 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,8 +1,6 @@
config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung"
depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
- depends on S3C64XX_PL080 || !ARCH_S3C64XX
- depends on S3C24XX_DMAC || !ARCH_S3C24XX
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index e4145509d63c..4a7a503fe13c 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -324,7 +324,7 @@ static const struct snd_soc_component_driver s3c_ac97_component = {
static int s3c_ac97_probe(struct platform_device *pdev)
{
- struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+ struct resource *mem_res, *irq_res;
struct s3c_audio_pdata *ac97_pdata;
int ret;
@@ -335,24 +335,6 @@ static int s3c_ac97_probe(struct platform_device *pdev)
}
/* Check for availability of necessary resource */
- dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmatx_res) {
- dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
- return -ENXIO;
- }
-
- dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx_res) {
- dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
- return -ENXIO;
- }
-
- dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (!dmamic_res) {
- dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
- return -ENXIO;
- }
-
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
@@ -364,11 +346,11 @@ static int s3c_ac97_probe(struct platform_device *pdev)
if (IS_ERR(s3c_ac97.regs))
return PTR_ERR(s3c_ac97.regs);
- s3c_ac97_pcm_out.channel = dmatx_res->start;
+ s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback;
s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
- s3c_ac97_pcm_in.channel = dmarx_res->start;
+ s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture;
s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
- s3c_ac97_mic_in.channel = dmamic_res->start;
+ s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic;
s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
init_completion(&s3c_ac97.done);
@@ -406,7 +388,8 @@ static int s3c_ac97_probe(struct platform_device *pdev)
if (ret)
goto err5;
- ret = samsung_asoc_dma_platform_register(&pdev->dev);
+ ret = samsung_asoc_dma_platform_register(&pdev->dev,
+ ac97_pdata->dma_filter);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
goto err5;
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index e5f05e62fa3c..3dd246fa0059 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -58,11 +58,16 @@ static int bells_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
- struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_codec *codec;
struct bells_drvdata *bells = card->drvdata;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+ codec_dai = rtd->codec_dai;
+ codec = codec_dai->codec;
+
if (dapm->dev != codec_dai->dev)
return 0;
@@ -99,11 +104,16 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
- struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_codec *codec;
struct bells_drvdata *bells = card->drvdata;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+ codec_dai = rtd->codec_dai;
+ codec = codec_dai->codec;
+
if (dapm->dev != codec_dai->dev)
return 0;
@@ -137,14 +147,22 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
static int bells_late_probe(struct snd_soc_card *card)
{
struct bells_drvdata *bells = card->drvdata;
- struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec;
- struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec;
- struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *wm0010;
+ struct snd_soc_codec *codec;
+ struct snd_soc_dai *aif1_dai;
struct snd_soc_dai *aif2_dai;
struct snd_soc_dai *aif3_dai;
struct snd_soc_dai *wm9081_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name);
+ wm0010 = rtd->codec;
+
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+ codec = rtd->codec;
+ aif1_dai = rtd->codec_dai;
+
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1,
bells->sysclk_rate,
@@ -181,7 +199,8 @@ static int bells_late_probe(struct snd_soc_card *card)
return ret;
}
- aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name);
+ aif2_dai = rtd->cpu_dai;
ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
if (ret != 0) {
@@ -192,8 +211,9 @@ static int bells_late_probe(struct snd_soc_card *card)
if (card->num_rtd == DAI_CODEC_SUB)
return 0;
- aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai;
- wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name);
+ aif3_dai = rtd->cpu_dai;
+ wm9081_dai = rtd->codec_dai;
ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
if (ret != 0) {
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index 0e85dcfec023..a7616cc9b39e 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -13,9 +13,10 @@
#define _S3C_AUDIO_H
#include <sound/dmaengine_pcm.h>
+#include <linux/dmaengine.h>
struct s3c_dma_params {
- int channel; /* Channel ID */
+ void *slave; /* Channel ID */
dma_addr_t dma_addr;
int dma_size; /* Size of the DMA transfer */
char *ch_name;
@@ -25,6 +26,7 @@ struct s3c_dma_params {
void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
struct s3c_dma_params *playback,
struct s3c_dma_params *capture);
-int samsung_asoc_dma_platform_register(struct device *dev);
+int samsung_asoc_dma_platform_register(struct device *dev,
+ dma_filter_fn fn);
#endif
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
index 506f5bf6d082..063125937311 100644
--- a/sound/soc/samsung/dmaengine.c
+++ b/sound/soc/samsung/dmaengine.c
@@ -28,17 +28,8 @@
#include "dma.h"
-#ifdef CONFIG_ARCH_S3C64XX
-#define filter_fn pl08x_filter_id
-#elif defined(CONFIG_ARCH_S3C24XX)
-#define filter_fn s3c24xx_dma_filter
-#else
-#define filter_fn NULL
-#endif
-
-static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
+static struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
- .compat_filter_fn = filter_fn,
};
void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
@@ -50,14 +41,14 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
if (playback) {
playback_data = &playback->dma_data;
- playback_data->filter_data = (void *)playback->channel;
+ playback_data->filter_data = playback->slave;
playback_data->chan_name = playback->ch_name;
playback_data->addr = playback->dma_addr;
playback_data->addr_width = playback->dma_size;
}
if (capture) {
capture_data = &capture->dma_data;
- capture_data->filter_data = (void *)capture->channel;
+ capture_data->filter_data = capture->slave;
capture_data->chan_name = capture->ch_name;
capture_data->addr = capture->dma_addr;
capture_data->addr_width = capture->dma_size;
@@ -67,8 +58,11 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
}
EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
-int samsung_asoc_dma_platform_register(struct device *dev)
+int samsung_asoc_dma_platform_register(struct device *dev,
+ dma_filter_fn filter)
{
+ samsung_dmaengine_pcm_config.compat_filter_fn = filter;
+
return devm_snd_dmaengine_pcm_register(dev,
&samsung_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index ea4ab374a223..84d9e77c0fbe 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -89,6 +89,7 @@ struct i2s_dai {
struct s3c_dma_params dma_playback;
struct s3c_dma_params dma_capture;
struct s3c_dma_params idma_playback;
+ dma_filter_fn filter;
u32 quirks;
u32 suspend_i2smod;
u32 suspend_i2scon;
@@ -1244,7 +1245,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
if (ret != 0)
return ret;
- return samsung_asoc_dma_platform_register(&pdev->dev);
+ return samsung_asoc_dma_platform_register(&pdev->dev,
+ sec_dai->filter);
}
pri_dai = i2s_alloc_dai(pdev, false);
@@ -1257,27 +1259,15 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pri_dai->lock = &pri_dai->spinlock;
if (!np) {
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Unable to get I2S-TX dma resource\n");
- return -ENXIO;
- }
- pri_dai->dma_playback.channel = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res) {
- dev_err(&pdev->dev,
- "Unable to get I2S-RX dma resource\n");
- return -ENXIO;
- }
- pri_dai->dma_capture.channel = res->start;
-
if (i2s_pdata == NULL) {
dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
return -EINVAL;
}
+ pri_dai->dma_playback.slave = i2s_pdata->dma_playback;
+ pri_dai->dma_capture.slave = i2s_pdata->dma_capture;
+ pri_dai->filter = i2s_pdata->dma_filter;
+
if (&i2s_pdata->type)
i2s_cfg = &i2s_pdata->type.i2s;
@@ -1339,9 +1329,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
sec_dai->dma_playback.ch_name = "tx-sec";
if (!np) {
- res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (res)
- sec_dai->dma_playback.channel = res->start;
+ sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec;
+ sec_dai->filter = i2s_pdata->dma_filter;
}
sec_dai->dma_playback.dma_size = 4;
@@ -1364,7 +1353,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
- ret = samsung_asoc_dma_platform_register(&pdev->dev);
+ ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter);
if (ret != 0)
return ret;
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 31a820eb0ac3..7cb204e649ca 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -23,9 +23,13 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *aif1_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ aif1_dai = rtd->codec_dai;
+
if (dapm->dev != aif1_dai->dev)
return 0;
@@ -66,9 +70,13 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *aif1_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ aif1_dai = rtd->codec_dai;
+
if (dapm->dev != aif1_dai->dev)
return 0;
@@ -168,9 +176,13 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_card *card = w->dapm->card;
- struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *aif2_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ aif2_dai = rtd->cpu_dai;
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
@@ -245,11 +257,19 @@ static struct snd_soc_jack littlemill_headset;
static int littlemill_late_probe(struct snd_soc_card *card)
{
- struct snd_soc_codec *codec = card->rtd[0].codec;
- struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
- struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+ struct snd_soc_dai *aif1_dai;
+ struct snd_soc_dai *aif2_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec = rtd->codec;
+ aif1_dai = rtd->codec_dai;
+
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ aif2_dai = rtd->cpu_dai;
+
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
32768, SND_SOC_CLOCK_IN);
if (ret < 0)
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c
index 596f1180a369..04217279fe25 100644
--- a/sound/soc/samsung/odroidx2_max98090.c
+++ b/sound/soc/samsung/odroidx2_max98090.c
@@ -25,10 +25,15 @@ static struct snd_soc_dai_link odroidx2_dai[];
static int odroidx2_late_probe(struct snd_soc_card *card)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
- struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
+ cpu_dai = rtd->cpu_dai;
+
ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
SND_SOC_CLOCK_IN);
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index b320a9d3fbf8..498f563a4c9c 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -486,8 +486,9 @@ static const struct snd_soc_component_driver s3c_pcm_component = {
static int s3c_pcm_dev_probe(struct platform_device *pdev)
{
struct s3c_pcm_info *pcm;
- struct resource *mem_res, *dmatx_res, *dmarx_res;
+ struct resource *mem_res;
struct s3c_audio_pdata *pcm_pdata;
+ dma_filter_fn filter;
int ret;
/* Check for valid device index */
@@ -499,18 +500,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
pcm_pdata = pdev->dev.platform_data;
/* Check for availability of necessary resource */
- dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmatx_res) {
- dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
- return -ENXIO;
- }
-
- dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx_res) {
- dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
- return -ENXIO;
- }
-
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
dev_err(&pdev->dev, "Unable to get register resource\n");
@@ -568,8 +557,12 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
+ S3C_PCM_TXFIFO;
- s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
- s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+ filter = NULL;
+ if (pcm_pdata) {
+ s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture;
+ s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback;
+ filter = pcm_pdata->dma_filter;
+ }
pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
@@ -583,7 +576,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
goto err5;
}
- ret = samsung_asoc_dma_platform_register(&pdev->dev);
+ ret = samsung_asoc_dma_platform_register(&pdev->dev, filter);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
goto err5;
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 2b766d212ce0..204029d12f5b 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -25,7 +25,6 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include <mach/dma.h>
#include <mach/gpio-samsung.h>
#include <plat/gpio-cfg.h>
@@ -33,14 +32,14 @@
#include "regs-i2s-v2.h"
#include "s3c2412-i2s.h"
+#include <linux/platform_data/asoc-s3c.h>
+
static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
- .channel = DMACH_I2S_OUT,
.ch_name = "tx",
.dma_size = 4,
};
static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
- .channel = DMACH_I2S_IN,
.ch_name = "rx",
.dma_size = 4,
};
@@ -152,6 +151,12 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
{
int ret = 0;
struct resource *res;
+ struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "missing platform data");
+ return -ENXIO;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
s3c2412_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
@@ -159,7 +164,9 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
return PTR_ERR(s3c2412_i2s.regs);
s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD;
+ s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback;
s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD;
+ s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture;
ret = s3c_i2sv2_register_component(&pdev->dev, -1,
&s3c2412_i2s_component,
@@ -169,7 +176,8 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
return ret;
}
- ret = samsung_asoc_dma_platform_register(&pdev->dev);
+ ret = samsung_asoc_dma_platform_register(&pdev->dev,
+ pdata->dma_filter);
if (ret)
pr_err("failed to register the DMA: %d\n", ret);
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 5bf723689692..b3a475d73ba7 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -23,7 +23,6 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include <mach/dma.h>
#include <mach/gpio-samsung.h>
#include <plat/gpio-cfg.h>
#include "regs-iis.h"
@@ -31,14 +30,14 @@
#include "dma.h"
#include "s3c24xx-i2s.h"
+#include <linux/platform_data/asoc-s3c.h>
+
static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
- .channel = DMACH_I2S_OUT,
.ch_name = "tx",
.dma_size = 2,
};
static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
- .channel = DMACH_I2S_IN,
.ch_name = "rx",
.dma_size = 2,
};
@@ -454,6 +453,12 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
{
int ret = 0;
struct resource *res;
+ struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "missing platform data");
+ return -ENXIO;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -465,7 +470,9 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
return PTR_ERR(s3c24xx_i2s.regs);
s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO;
+ s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback;
s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO;
+ s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture;
ret = devm_snd_soc_register_component(&pdev->dev,
&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
@@ -474,7 +481,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
return ret;
}
- ret = samsung_asoc_dma_platform_register(&pdev->dev);
+ ret = samsung_asoc_dma_platform_register(&pdev->dev,
+ pdata->dma_filter);
if (ret)
pr_err("failed to register the dma: %d\n", ret);
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index a0fe37fbed9f..425ee2ba37f0 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -13,15 +13,12 @@
*
*/
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
-#include <mach/gpio-samsung.h>
-#include <asm/mach-types.h>
-
#include "i2s.h"
#include "../codecs/wm8750.h"
@@ -96,7 +93,7 @@ static struct snd_soc_jack_pin smartq_jack_pins[] = {
static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
{
- .gpio = S3C64XX_GPL(12),
+ .gpio = -1,
.name = "headphone detect",
.report = SND_JACK_HEADPHONE,
.debounce_time = 200,
@@ -113,7 +110,9 @@ static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k,
int event)
{
- gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
+ struct gpio_desc *gpio = snd_soc_card_get_drvdata(&snd_soc_smartq);
+
+ gpiod_set_value(gpio, SND_SOC_DAPM_EVENT_OFF(event));
return 0;
}
@@ -199,62 +198,39 @@ static struct snd_soc_card snd_soc_smartq = {
.num_controls = ARRAY_SIZE(wm8987_smartq_controls),
};
-static struct platform_device *smartq_snd_device;
-
-static int __init smartq_init(void)
+static int smartq_probe(struct platform_device *pdev)
{
+ struct gpio_desc *gpio;
int ret;
- if (!machine_is_smartq7() && !machine_is_smartq5()) {
- pr_info("Only SmartQ is supported by this ASoC driver\n");
- return -ENODEV;
- }
-
- smartq_snd_device = platform_device_alloc("soc-audio", -1);
- if (!smartq_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
-
- ret = platform_device_add(smartq_snd_device);
- if (ret) {
- platform_device_put(smartq_snd_device);
- return ret;
- }
+ platform_set_drvdata(pdev, &snd_soc_smartq);
/* Initialise GPIOs used by amplifiers */
- ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
- if (ret) {
- dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
- goto err_unregister_device;
+ gpio = devm_gpiod_get(&pdev->dev, "amplifiers shutdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio)) {
+ dev_err(&pdev->dev, "Failed to register GPK12\n");
+ ret = PTR_ERR(gpio);
+ goto out;
}
+ snd_soc_card_set_drvdata(&snd_soc_smartq, gpio);
- /* Disable amplifiers */
- ret = gpio_direction_output(S3C64XX_GPK(12), 1);
- if (ret) {
- dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
- goto err_free_gpio_amp_shut;
- }
-
- return 0;
-
-err_free_gpio_amp_shut:
- gpio_free(S3C64XX_GPK(12));
-err_unregister_device:
- platform_device_unregister(smartq_snd_device);
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_smartq);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to register card\n");
+out:
return ret;
}
-static void __exit smartq_exit(void)
-{
- gpio_free(S3C64XX_GPK(12));
-
- platform_device_unregister(smartq_snd_device);
-}
+static struct platform_driver smartq_driver = {
+ .driver = {
+ .name = "smartq-audio",
+ },
+ .probe = smartq_probe,
+};
-module_init(smartq_init);
-module_exit(smartq_exit);
+module_platform_driver(smartq_driver);
/* Module information */
MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>");
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 07ce2cfa4845..d8ac907bbb0d 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -35,10 +35,15 @@ static struct snd_soc_dai_link snow_dai[] = {
static int snow_late_probe(struct snd_soc_card *card)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
- struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
+ cpu_dai = rtd->cpu_dai;
+
/* Set the MCLK rate for the codec */
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
FIN_PLL_RATE, SND_SOC_CLOCK_IN);
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 36dbc0e96004..4687f521197c 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -359,20 +359,15 @@ static const struct snd_soc_component_driver samsung_spdif_component = {
static int spdif_probe(struct platform_device *pdev)
{
struct s3c_audio_pdata *spdif_pdata;
- struct resource *mem_res, *dma_res;
+ struct resource *mem_res;
struct samsung_spdif_info *spdif;
+ dma_filter_fn filter;
int ret;
spdif_pdata = pdev->dev.platform_data;
dev_dbg(&pdev->dev, "Entered %s\n", __func__);
- dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dma_res) {
- dev_err(&pdev->dev, "Unable to get dma resource.\n");
- return -ENXIO;
- }
-
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
dev_err(&pdev->dev, "Unable to get register resource.\n");
@@ -432,11 +427,15 @@ static int spdif_probe(struct platform_device *pdev)
spdif_stereo_out.dma_size = 2;
spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
- spdif_stereo_out.channel = dma_res->start;
+ filter = NULL;
+ if (spdif_pdata) {
+ spdif_stereo_out.slave = spdif_pdata->dma_playback;
+ filter = spdif_pdata->dma_filter;
+ }
spdif->dma_playback = &spdif_stereo_out;
- ret = samsung_asoc_dma_platform_register(&pdev->dev);
+ ret = samsung_asoc_dma_platform_register(&pdev->dev, filter);
if (ret) {
dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
goto err4;
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index d1ae21c5e253..083ef5e21b17 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -25,9 +25,13 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ codec_dai = rtd->codec_dai;
+
if (dapm->dev != codec_dai->dev)
return 0;
@@ -57,9 +61,13 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+ codec_dai = rtd->codec_dai;
+
if (dapm->dev != codec_dai->dev)
return 0;
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 85ccfb7188cb..3310eda7cf53 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -23,9 +23,13 @@ static int tobermory_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
+
if (dapm->dev != codec_dai->dev)
return 0;
@@ -62,9 +66,13 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec_dai = rtd->codec_dai;
+
if (dapm->dev != codec_dai->dev)
return 0;
@@ -170,10 +178,15 @@ static struct snd_soc_jack_pin tobermory_headset_pins[] = {
static int tobermory_late_probe(struct snd_soc_card *card)
{
- struct snd_soc_codec *codec = card->rtd[0].codec;
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+ struct snd_soc_dai *codec_dai;
int ret;
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+ codec = rtd->codec;
+ codec_dai = rtd->codec_dai;
+
ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
32768, SND_SOC_CLOCK_IN);
if (ret < 0)
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 206d1edab07c..c9902a6d6fa0 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -36,7 +36,6 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support"
- depends on DMA_OF
depends on COMMON_CLK
select SND_SIMPLE_CARD
select REGMAP_MMIO
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 0215c78cbddf..ead520182e26 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1362,15 +1362,18 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
{
- dma_cap_mask_t mask;
int is_play = fsi_stream_is_play(fsi, io);
+#ifdef CONFIG_SUPERH
+ dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- io->chan = dma_request_slave_channel_compat(mask,
- shdma_chan_filter, (void *)io->dma_id,
- dev, is_play ? "tx" : "rx");
+ io->chan = dma_request_channel(mask, shdma_chan_filter,
+ (void *)io->dma_id);
+#else
+ io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx");
+#endif
if (io->chan) {
struct dma_slave_config cfg = {};
int ret;
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 8b258501aa35..a89ddf758695 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,4 +1,4 @@
-snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
+snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
snd-soc-rsrc-card-objs := rsrc-card.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 2a5b3a293cd2..6d3ef366d536 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -68,8 +68,8 @@ static u32 rsnd_adg_calculate_rbgx(unsigned long div)
static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
{
- struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
- int id = rsnd_mod_id(mod);
+ struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+ int id = rsnd_mod_id(ssi_mod);
int ws = id;
if (rsnd_ssi_is_pin_sharing(io)) {
@@ -90,13 +90,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
return (0x6 + ws) << 8;
}
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
- int id = rsnd_mod_id(mod);
+ int id = rsnd_mod_id(cmd_mod);
int shift = (id % 2) ? 16 : 0;
u32 mask, val;
@@ -242,68 +242,6 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
}
-int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- unsigned int src_rate,
- unsigned int dst_rate)
-{
- struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
- struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
- struct device *dev = rsnd_priv_to_dev(priv);
- int idx, sel, div, shift;
- u32 mask, val;
- int id = rsnd_mod_id(mod);
- unsigned int sel_rate [] = {
- clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */
- clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */
- clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */
- 0, /* 011: MLBCLK (not used) */
- adg->rbga_rate_for_441khz, /* 100: RBGA */
- adg->rbgb_rate_for_48khz, /* 101: RBGB */
- };
-
- /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
- for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
- for (div = 128, idx = 0;
- div <= 2048;
- div *= 2, idx++) {
- if (src_rate == sel_rate[sel] / div) {
- val = (idx << 4) | sel;
- goto find_rate;
- }
- }
- }
- dev_err(dev, "can't find convert src clk\n");
- return -EINVAL;
-
-find_rate:
- shift = (id % 4) * 8;
- mask = 0xFF << shift;
- val = val << shift;
-
- dev_dbg(dev, "adg convert src clk = %02x\n", val);
-
- switch (id / 4) {
- case 0:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val);
- break;
- case 1:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val);
- break;
- case 2:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val);
- break;
- }
-
- /*
- * Gen1 doesn't need dst_rate settings,
- * since it uses SSI WS pin.
- * see also rsnd_src_set_route_if_gen1()
- */
-
- return 0;
-}
-
static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
@@ -337,20 +275,16 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
}
}
-int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
{
- /*
- * "mod" = "ssi" here.
- * we can get "ssi id" from mod
- */
- rsnd_adg_set_ssi_clk(mod, 0);
+ rsnd_adg_set_ssi_clk(ssi_mod, 0);
return 0;
}
-int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
@@ -394,14 +328,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
found_clock:
- /*
- * This "mod" = "ssi" here.
- * we can get "ssi id" from mod
- */
- rsnd_adg_set_ssi_clk(mod, data);
+ rsnd_adg_set_ssi_clk(ssi_mod, data);
dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
data, rate);
return 0;
@@ -418,15 +348,20 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
[CLKC] = "clk_c",
[CLKI] = "clk_i",
};
- int i;
+ int i, ret;
for (i = 0; i < CLKMAX; i++) {
clk = devm_clk_get(dev, clk_name[i]);
adg->clk[i] = IS_ERR(clk) ? NULL : clk;
}
- for_each_rsnd_clk(clk, adg, i)
+ for_each_rsnd_clk(clk, adg, i) {
+ ret = clk_prepare_enable(clk);
+ if (ret < 0)
+ dev_warn(dev, "can't use clk %d\n", i);
+
dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+ }
}
static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
@@ -437,7 +372,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
u32 ckr, rbgx, rbga, rbgb;
- u32 rate, req_rate, div;
+ u32 rate, req_rate = 0, div;
uint32_t count = 0;
unsigned long req_48kHz_rate, req_441kHz_rate;
int i;
@@ -572,9 +507,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
ckr, rbga, rbgb);
}
-int rsnd_adg_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_adg_probe(struct rsnd_priv *priv)
{
struct rsnd_adg *adg;
struct device *dev = rsnd_priv_to_dev(priv);
@@ -600,3 +533,14 @@ int rsnd_adg_probe(struct platform_device *pdev,
return 0;
}
+
+void rsnd_adg_remove(struct rsnd_priv *priv)
+{
+ struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct clk *clk;
+ int i;
+
+ for_each_rsnd_clk(clk, adg, i) {
+ clk_disable_unprepare(clk);
+ }
+}
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
new file mode 100644
index 000000000000..cd1f064e63c4
--- /dev/null
+++ b/sound/soc/sh/rcar/cmd.c
@@ -0,0 +1,171 @@
+/*
+ * Renesas R-Car CMD support
+ *
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+struct rsnd_cmd {
+ struct rsnd_mod mod;
+};
+
+#define CMD_NAME "cmd"
+
+#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
+#define for_each_rsnd_cmd(pos, priv, i) \
+ for ((i) = 0; \
+ ((i) < rsnd_cmd_nr(priv)) && \
+ ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \
+ i++)
+
+static int rsnd_cmd_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+ struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+ struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 data;
+
+ if (!mix && !dvc)
+ return 0;
+
+ if (mix) {
+ struct rsnd_dai *rdai;
+ int i;
+ u32 path[] = {
+ [0] = 0,
+ [1] = 1 << 0,
+ [2] = 0,
+ [3] = 0,
+ [4] = 0,
+ [5] = 1 << 8
+ };
+
+ /*
+ * it is assuming that integrater is well understanding about
+ * data path. Here doesn't check impossible connection,
+ * like src2 + src5
+ */
+ data = 0;
+ for_each_rsnd_dai(rdai, priv, i) {
+ io = &rdai->playback;
+ if (mix == rsnd_io_to_mod_mix(io))
+ data |= path[rsnd_mod_id(src)];
+
+ io = &rdai->capture;
+ if (mix == rsnd_io_to_mod_mix(io))
+ data |= path[rsnd_mod_id(src)];
+ }
+
+ } else {
+ u32 path[] = {
+ [0] = 0x30000,
+ [1] = 0x30001,
+ [2] = 0x40000,
+ [3] = 0x10000,
+ [4] = 0x20000,
+ [5] = 0x40100
+ };
+
+ data = path[rsnd_mod_id(src)];
+ }
+
+ dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+
+ rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
+ rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
+
+ rsnd_adg_set_cmd_timsel_gen2(mod, io);
+
+ return 0;
+}
+
+static int rsnd_cmd_start(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ rsnd_mod_write(mod, CMD_CTRL, 0x10);
+
+ return 0;
+}
+
+static int rsnd_cmd_stop(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ rsnd_mod_write(mod, CMD_CTRL, 0);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_cmd_ops = {
+ .name = CMD_NAME,
+ .init = rsnd_cmd_init,
+ .start = rsnd_cmd_start,
+ .stop = rsnd_cmd_stop,
+};
+
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
+{
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
+
+ return rsnd_dai_connect(mod, io, mod->type);
+}
+
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
+ id = 0;
+
+ return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
+}
+
+int rsnd_cmd_probe(struct rsnd_priv *priv)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_cmd *cmd;
+ int i, nr, ret;
+
+ /* This driver doesn't support Gen1 at this point */
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ /* same number as DVC */
+ nr = priv->dvc_nr;
+ if (!nr)
+ return 0;
+
+ cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ priv->cmd_nr = nr;
+ priv->cmd = cmd;
+
+ for_each_rsnd_cmd(cmd, priv, i) {
+ ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
+ &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void rsnd_cmd_remove(struct rsnd_priv *priv)
+{
+ struct rsnd_cmd *cmd;
+ int i;
+
+ for_each_rsnd_cmd(cmd, priv, i) {
+ rsnd_mod_quit(rsnd_mod_get(cmd));
+ }
+}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index deed48ef28b8..02b4b085b8d7 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -99,34 +99,17 @@
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-static const struct rsnd_of_data rsnd_of_data_gen1 = {
- .flags = RSND_GEN1,
-};
-
-static const struct rsnd_of_data rsnd_of_data_gen2 = {
- .flags = RSND_GEN2,
-};
-
static const struct of_device_id rsnd_of_match[] = {
- { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
- { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
- { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
+ { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
+ { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
+ { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */
{},
};
MODULE_DEVICE_TABLE(of, rsnd_of_match);
/*
- * rsnd_platform functions
+ * rsnd_mod functions
*/
-#define rsnd_platform_call(priv, dai, func, param...) \
- (!(priv->info->func) ? 0 : \
- priv->info->func(param))
-
-#define rsnd_is_enable_path(io, name) \
- ((io)->info ? (io)->info->name : NULL)
-#define rsnd_info_id(priv, io, name) \
- ((io)->info->name - priv->info->name##_info)
-
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
{
if (mod->type != type) {
@@ -138,9 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
}
}
-/*
- * rsnd_mod functions
- */
char *rsnd_mod_name(struct rsnd_mod *mod)
{
if (!mod || !mod->ops)
@@ -192,19 +172,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io;
struct rsnd_dai *rdai;
- int i, j;
-
- for_each_rsnd_dai(rdai, priv, j) {
+ int i;
- for (i = 0; i < RSND_MOD_MAX; i++) {
- io = &rdai->playback;
- if (mod == io->mod[i])
- callback(mod, io);
+ for_each_rsnd_dai(rdai, priv, i) {
+ io = &rdai->playback;
+ if (mod == io->mod[mod->type])
+ callback(mod, io);
- io = &rdai->capture;
- if (mod == io->mod[i])
- callback(mod, io);
- }
+ io = &rdai->capture;
+ if (mod == io->mod[mod->type])
+ callback(mod, io);
}
}
@@ -214,6 +191,43 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
return !!io->substream;
}
+void rsnd_set_slot(struct rsnd_dai *rdai,
+ int slots, int num)
+{
+ rdai->slots = slots;
+ rdai->slots_num = num;
+}
+
+int rsnd_get_slot(struct rsnd_dai_stream *io)
+{
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+ return rdai->slots;
+}
+
+int rsnd_get_slot_num(struct rsnd_dai_stream *io)
+{
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+ return rdai->slots_num;
+}
+
+int rsnd_get_slot_width(struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ int chan = runtime->channels;
+
+ /* Multi channel Mode */
+ if (rsnd_ssi_multi_slaves(io))
+ chan /= rsnd_get_slot_num(io);
+
+ /* TDM Extend Mode needs 8ch */
+ if (chan == 6)
+ chan = 8;
+
+ return chan;
+}
+
/*
* ADINR function
*/
@@ -222,21 +236,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
- u32 adinr = runtime->channels;
switch (runtime->sample_bits) {
case 16:
- adinr |= (8 << 16);
- break;
+ return 8 << 16;
case 32:
- adinr |= (0 << 16);
- break;
- default:
- dev_warn(dev, "not supported sample bits\n");
- return 0;
+ return 0 << 16;
}
- return adinr;
+ dev_warn(dev, "not supported sample bits\n");
+
+ return 0;
}
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
@@ -267,13 +277,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
*/
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
{
- struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
- struct rsnd_mod *target = src ? src : ssi;
+ struct rsnd_mod *target;
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 val = 0x76543210;
u32 mask = ~0;
+ if (rsnd_io_is_play(io)) {
+ struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
+ target = src ? src : ssi;
+ } else {
+ struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
+
+ target = cmd ? cmd : ssi;
+ }
+
mask <<= runtime->channels * 4;
val = val & mask;
@@ -300,20 +319,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
/*
* rsnd_dai functions
*/
-#define rsnd_mod_call(mod, io, func, param...) \
+#define rsnd_mod_call(idx, io, func, param...) \
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
+ struct rsnd_mod *mod = (io)->mod[idx]; \
struct device *dev = rsnd_priv_to_dev(priv); \
+ u32 *status = (io)->mod_status + idx; \
u32 mask = 0xF << __rsnd_mod_shift_##func; \
- u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \
+ u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \
u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \
int ret = 0; \
int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
- mod->status = (mod->status & ~mask) + \
+ *status = (*status & ~mask) + \
(add << __rsnd_mod_shift_##func); \
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), \
- mod->status, call ? #func : ""); \
+ *status, call ? #func : ""); \
if (call) \
ret = (mod)->ops->func(mod, io, param); \
ret; \
@@ -327,13 +348,14 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
mod = (io)->mod[i]; \
if (!mod) \
continue; \
- ret |= rsnd_mod_call(mod, io, fn, param); \
+ ret |= rsnd_mod_call(i, io, fn, param); \
} \
ret; \
})
-static int rsnd_dai_connect(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+int rsnd_dai_connect(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
{
struct rsnd_priv *priv;
struct device *dev;
@@ -341,10 +363,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
if (!mod)
return -EIO;
+ if (io->mod[type])
+ return -EINVAL;
+
priv = rsnd_mod_to_priv(mod);
dev = rsnd_priv_to_dev(priv);
- io->mod[mod->type] = mod;
+ io->mod[type] = mod;
dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
rsnd_mod_name(mod), rsnd_mod_id(mod),
@@ -354,9 +379,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
}
static void rsnd_dai_disconnect(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
{
- io->mod[mod->type] = NULL;
+ io->mod[type] = NULL;
}
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
@@ -469,7 +495,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
- int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
int ret;
unsigned long flags;
@@ -479,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
rsnd_dai_stream_init(io, substream);
- ret = rsnd_platform_call(priv, dai, start, ssi_id);
- if (ret < 0)
- goto dai_trigger_end;
-
ret = rsnd_dai_call(init, io, priv);
if (ret < 0)
goto dai_trigger_end;
@@ -496,8 +517,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
ret |= rsnd_dai_call(quit, io, priv);
- ret |= rsnd_platform_call(priv, dai, stop, ssi_id);
-
rsnd_dai_stream_quit(io);
break;
default:
@@ -567,332 +586,157 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
- .trigger = rsnd_soc_dai_trigger,
- .set_fmt = rsnd_soc_dai_set_fmt,
-};
-
-#define rsnd_path_add(priv, io, type) \
-({ \
- struct rsnd_mod *mod; \
- int ret = 0; \
- int id = -1; \
- \
- if (rsnd_is_enable_path(io, type)) { \
- id = rsnd_info_id(priv, io, type); \
- if (id >= 0) { \
- mod = rsnd_##type##_mod_get(priv, id); \
- ret = rsnd_dai_connect(mod, io); \
- } \
- } \
- ret; \
-})
-
-#define rsnd_path_remove(priv, io, type) \
-{ \
- struct rsnd_mod *mod; \
- int id = -1; \
- \
- if (rsnd_is_enable_path(io, type)) { \
- id = rsnd_info_id(priv, io, type); \
- if (id >= 0) { \
- mod = rsnd_##type##_mod_get(priv, id); \
- rsnd_dai_disconnect(mod, io); \
- } \
- } \
-}
-
-void rsnd_path_parse(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io)
+static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ u32 tx_mask, u32 rx_mask,
+ int slots, int slot_width)
{
- struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
- struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
- struct rsnd_mod *src = rsnd_io_to_mod_src(io);
- struct rsnd_mod *cmd;
+ struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+ struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct device *dev = rsnd_priv_to_dev(priv);
- u32 data;
- /* Gen1 is not supported */
- if (rsnd_is_gen1(priv))
- return;
-
- if (!mix && !dvc)
- return;
-
- if (mix) {
- struct rsnd_dai *rdai;
- int i;
- u32 path[] = {
- [0] = 0,
- [1] = 1 << 0,
- [2] = 0,
- [3] = 0,
- [4] = 0,
- [5] = 1 << 8
- };
-
- /*
- * it is assuming that integrater is well understanding about
- * data path. Here doesn't check impossible connection,
- * like src2 + src5
- */
- data = 0;
- for_each_rsnd_dai(rdai, priv, i) {
- io = &rdai->playback;
- if (mix == rsnd_io_to_mod_mix(io))
- data |= path[rsnd_mod_id(src)];
-
- io = &rdai->capture;
- if (mix == rsnd_io_to_mod_mix(io))
- data |= path[rsnd_mod_id(src)];
- }
-
- /*
- * We can't use ctu = rsnd_io_ctu() here.
- * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
- * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
- */
- cmd = mix;
- } else {
- u32 path[] = {
- [0] = 0x30000,
- [1] = 0x30001,
- [2] = 0x40000,
- [3] = 0x10000,
- [4] = 0x20000,
- [5] = 0x40100
- };
-
- data = path[rsnd_mod_id(src)];
-
- cmd = dvc;
+ switch (slots) {
+ case 6:
+ /* TDM Extend Mode */
+ rsnd_set_slot(rdai, slots, 1);
+ break;
+ default:
+ dev_err(dev, "unsupported TDM slots (%d)\n", slots);
+ return -EINVAL;
}
- dev_dbg(dev, "ctu/mix path = 0x%08x", data);
-
- rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
-
- rsnd_mod_write(cmd, CMD_CTRL, 0x10);
+ return 0;
}
-static int rsnd_path_init(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- int ret;
-
- /*
- * Gen1 is created by SRU/SSI, and this SRU is base module of
- * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
- *
- * Easy image is..
- * Gen1 SRU = Gen2 SCU + SSIU + etc
- *
- * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
- * using fixed path.
- */
-
- /* SSI */
- ret = rsnd_path_add(priv, io, ssi);
- if (ret < 0)
- return ret;
-
- /* SRC */
- ret = rsnd_path_add(priv, io, src);
- if (ret < 0)
- return ret;
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+ .trigger = rsnd_soc_dai_trigger,
+ .set_fmt = rsnd_soc_dai_set_fmt,
+ .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
+};
- /* CTU */
- ret = rsnd_path_add(priv, io, ctu);
- if (ret < 0)
- return ret;
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+ struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+ struct device_node *node,
+ struct device_node *playback,
+ struct device_node *capture)
+{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device_node *np;
+ struct rsnd_mod *mod;
+ int i;
- /* MIX */
- ret = rsnd_path_add(priv, io, mix);
- if (ret < 0)
- return ret;
+ if (!node)
+ return;
- /* DVC */
- ret = rsnd_path_add(priv, io, dvc);
- if (ret < 0)
- return ret;
+ i = 0;
+ for_each_child_of_node(node, np) {
+ mod = mod_get(priv, i);
+ if (np == playback)
+ rsnd_dai_connect(mod, &rdai->playback, mod->type);
+ if (np == capture)
+ rsnd_dai_connect(mod, &rdai->capture, mod->type);
+ i++;
+ }
- return ret;
+ of_node_put(node);
}
-static void rsnd_of_parse_dai(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+static int rsnd_dai_probe(struct rsnd_priv *priv)
{
- struct device_node *dai_node, *dai_np;
- struct device_node *ssi_node, *ssi_np;
- struct device_node *src_node, *src_np;
- struct device_node *ctu_node, *ctu_np;
- struct device_node *mix_node, *mix_np;
- struct device_node *dvc_node, *dvc_np;
+ struct device_node *dai_node;
+ struct device_node *dai_np;
struct device_node *playback, *capture;
- struct rsnd_dai_platform_info *dai_info;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct device *dev = &pdev->dev;
- int nr, i;
- int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i;
-
- if (!of_data)
- return;
-
- dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
- if (!dai_node)
- return;
+ struct rsnd_dai_stream *io_playback;
+ struct rsnd_dai_stream *io_capture;
+ struct snd_soc_dai_driver *rdrv, *drv;
+ struct rsnd_dai *rdai;
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int nr, dai_i, io_i;
+ int ret;
+ dai_node = rsnd_dai_of_node(priv);
nr = of_get_child_count(dai_node);
- if (!nr)
- return;
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_dai_probe_done;
+ }
- dai_info = devm_kzalloc(dev,
- sizeof(struct rsnd_dai_platform_info) * nr,
- GFP_KERNEL);
- if (!dai_info) {
- dev_err(dev, "dai info allocation error\n");
- return;
+ rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
+ rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
+ if (!rdrv || !rdai) {
+ ret = -ENOMEM;
+ goto rsnd_dai_probe_done;
}
- info->dai_info_nr = nr;
- info->dai_info = dai_info;
-
- ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
- src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
- ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
- mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
- dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-
-#define mod_parse(name) \
-if (name##_node) { \
- struct rsnd_##name##_platform_info *name##_info; \
- \
- name##_i = 0; \
- for_each_child_of_node(name##_node, name##_np) { \
- name##_info = info->name##_info + name##_i; \
- \
- if (name##_np == playback) \
- dai_info->playback.name = name##_info; \
- if (name##_np == capture) \
- dai_info->capture.name = name##_info; \
- \
- name##_i++; \
- } \
-}
+ priv->rdai_nr = nr;
+ priv->daidrv = rdrv;
+ priv->rdai = rdai;
/*
* parse all dai
*/
dai_i = 0;
for_each_child_of_node(dai_node, dai_np) {
- dai_info = info->dai_info + dai_i;
-
- for (i = 0;; i++) {
-
- playback = of_parse_phandle(dai_np, "playback", i);
- capture = of_parse_phandle(dai_np, "capture", i);
+ rdai = rsnd_rdai_get(priv, dai_i);
+ drv = rdrv + dai_i;
+ io_playback = &rdai->playback;
+ io_capture = &rdai->capture;
+
+ snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
+
+ rdai->priv = priv;
+ drv->name = rdai->name;
+ drv->ops = &rsnd_soc_dai_ops;
+
+ snprintf(rdai->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 = 6;
+ drv->playback.stream_name = rdai->playback.name;
+
+ snprintf(rdai->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 = 6;
+ drv->capture.stream_name = rdai->capture.name;
+
+ rdai->playback.rdai = rdai;
+ rdai->capture.rdai = rdai;
+ rsnd_set_slot(rdai, 2, 1); /* default */
+
+ for (io_i = 0;; io_i++) {
+ playback = of_parse_phandle(dai_np, "playback", io_i);
+ capture = of_parse_phandle(dai_np, "capture", io_i);
if (!playback && !capture)
break;
- mod_parse(ssi);
- mod_parse(src);
- mod_parse(ctu);
- mod_parse(mix);
- mod_parse(dvc);
+ rsnd_parse_connect_ssi(rdai, playback, capture);
+ rsnd_parse_connect_src(rdai, playback, capture);
+ rsnd_parse_connect_ctu(rdai, playback, capture);
+ rsnd_parse_connect_mix(rdai, playback, capture);
+ rsnd_parse_connect_dvc(rdai, playback, capture);
of_node_put(playback);
of_node_put(capture);
}
dai_i++;
- }
-}
-
-static int rsnd_dai_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct snd_soc_dai_driver *drv;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct rsnd_dai *rdai;
- struct rsnd_ssi_platform_info *pmod, *cmod;
- struct device *dev = rsnd_priv_to_dev(priv);
- int dai_nr;
- int i;
-
- rsnd_of_parse_dai(pdev, of_data, priv);
- dai_nr = info->dai_info_nr;
- if (!dai_nr) {
- dev_err(dev, "no dai\n");
- return -EIO;
+ dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
+ rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
+ rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
}
- drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL);
- rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
- if (!drv || !rdai) {
- dev_err(dev, "dai allocate failed\n");
- return -ENOMEM;
- }
-
- priv->rdai_nr = dai_nr;
- priv->daidrv = drv;
- priv->rdai = rdai;
+ ret = 0;
- for (i = 0; i < dai_nr; i++) {
+rsnd_dai_probe_done:
+ of_node_put(dai_node);
- pmod = info->dai_info[i].playback.ssi;
- cmod = info->dai_info[i].capture.ssi;
-
- /*
- * init rsnd_dai
- */
- snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
- rdai[i].priv = priv;
-
- /*
- * init snd_soc_dai_driver
- */
- drv[i].name = rdai[i].name;
- drv[i].ops = &rsnd_soc_dai_ops;
- if (pmod) {
- snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
- "DAI%d Playback", i);
-
- drv[i].playback.rates = RSND_RATES;
- drv[i].playback.formats = RSND_FMTS;
- drv[i].playback.channels_min = 2;
- drv[i].playback.channels_max = 2;
- drv[i].playback.stream_name = rdai[i].playback.name;
-
- rdai[i].playback.info = &info->dai_info[i].playback;
- rdai[i].playback.rdai = rdai + i;
- rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
- }
- if (cmod) {
- snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
- "DAI%d Capture", i);
-
- drv[i].capture.rates = RSND_RATES;
- drv[i].capture.formats = RSND_FMTS;
- drv[i].capture.channels_min = 2;
- drv[i].capture.channels_max = 2;
- drv[i].capture.stream_name = rdai[i].capture.name;
-
- rdai[i].capture.info = &info->dai_info[i].capture;
- rdai[i].capture.rdai = rdai + i;
- rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
- }
-
- dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
- pmod ? "play" : " -- ",
- cmod ? "capture" : " -- ");
- }
-
- return 0;
+ return ret;
}
/*
@@ -1033,14 +877,13 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod))
{
- struct snd_soc_card *soc_card = rtd->card;
struct snd_card *card = rtd->card->snd_card;
struct snd_kcontrol *kctrl;
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = name,
.info = rsnd_kctrl_info,
- .index = rtd - soc_card->rtd,
+ .index = rtd->num,
.get = rsnd_kctrl_get,
.put = rsnd_kctrl_put,
.private_value = (unsigned long)cfg,
@@ -1077,10 +920,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_m *_cfg,
+ int ch_size,
u32 max)
{
+ if (ch_size > RSND_DVC_CHANNELS)
+ return -EINVAL;
+
_cfg->cfg.max = max;
- _cfg->cfg.size = RSND_DVC_CHANNELS;
+ _cfg->cfg.size = ch_size;
_cfg->cfg.val = _cfg->val;
return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
}
@@ -1161,6 +1008,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
ret = rsnd_dai_call(probe, io, priv);
if (ret == -EAGAIN) {
+ struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+ int i;
+
/*
* Fallback to PIO mode
*/
@@ -1175,10 +1025,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
rsnd_dai_call(remove, io, priv);
/*
- * remove SRC/DVC from DAI,
+ * remove all mod from io
+ * and, re connect ssi
*/
- rsnd_path_remove(priv, io, src);
- rsnd_path_remove(priv, io, dvc);
+ for (i = 0; i < RSND_MOD_MAX; i++)
+ rsnd_dai_disconnect((io)->mod[i], io, i);
+ rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
/*
* fallback
@@ -1200,33 +1052,25 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
*/
static int rsnd_probe(struct platform_device *pdev)
{
- struct rcar_snd_info *info;
struct rsnd_priv *priv;
struct device *dev = &pdev->dev;
struct rsnd_dai *rdai;
const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
- const struct rsnd_of_data *of_data;
- int (*probe_func[])(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv) = {
+ int (*probe_func[])(struct rsnd_priv *priv) = {
rsnd_gen_probe,
rsnd_dma_probe,
rsnd_ssi_probe,
+ rsnd_ssiu_probe,
rsnd_src_probe,
rsnd_ctu_probe,
rsnd_mix_probe,
rsnd_dvc_probe,
+ rsnd_cmd_probe,
rsnd_adg_probe,
rsnd_dai_probe,
};
int ret, i;
- info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info),
- GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- of_data = of_id->data;
-
/*
* init priv data
*/
@@ -1237,14 +1081,14 @@ static int rsnd_probe(struct platform_device *pdev)
}
priv->pdev = pdev;
- priv->info = info;
+ priv->flags = (unsigned long)of_id->data;
spin_lock_init(&priv->lock);
/*
* init each module
*/
for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
- ret = probe_func[i](pdev, of_data, priv);
+ ret = probe_func[i](priv);
if (ret)
return ret;
}
@@ -1297,13 +1141,15 @@ static int rsnd_remove(struct platform_device *pdev)
{
struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
struct rsnd_dai *rdai;
- void (*remove_func[])(struct platform_device *pdev,
- struct rsnd_priv *priv) = {
+ void (*remove_func[])(struct rsnd_priv *priv) = {
rsnd_ssi_remove,
+ rsnd_ssiu_remove,
rsnd_src_remove,
rsnd_ctu_remove,
rsnd_mix_remove,
rsnd_dvc_remove,
+ rsnd_cmd_remove,
+ rsnd_adg_remove,
};
int ret = 0, i;
@@ -1315,7 +1161,7 @@ static int rsnd_remove(struct platform_device *pdev)
}
for (i = 0; i < ARRAY_SIZE(remove_func); i++)
- remove_func[i](pdev, priv);
+ remove_func[i](priv);
snd_soc_unregister_component(&pdev->dev);
snd_soc_unregister_platform(&pdev->dev);
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 3cb214ab848b..d53a225d19e9 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -13,7 +13,6 @@
#define CTU_NAME "ctu"
struct rsnd_ctu {
- struct rsnd_ctu_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
};
@@ -24,6 +23,7 @@ struct rsnd_ctu {
((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \
i++)
+#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1)
#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0)
static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
@@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
rsnd_mod_write(mod, CTU_CTUIR, enable);
}
+static int rsnd_ctu_probe_(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
+}
+
static int rsnd_ctu_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_ctu_ops = {
.name = CTU_NAME,
+ .probe = rsnd_ctu_probe_,
.init = rsnd_ctu_init,
.quit = rsnd_ctu_quit,
};
@@ -66,51 +74,13 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
id = 0;
- return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id);
+ return rsnd_mod_get(rsnd_ctu_get(priv, id));
}
-static void rsnd_of_parse_ctu(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_ctu_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct rsnd_ctu_platform_info *ctu_info;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct device *dev = &pdev->dev;
- int nr;
-
- if (!of_data)
- return;
-
- node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
- if (!node)
- return;
-
- nr = of_get_child_count(node);
- if (!nr)
- goto rsnd_of_parse_ctu_end;
-
- ctu_info = devm_kzalloc(dev,
- sizeof(struct rsnd_ctu_platform_info) * nr,
- GFP_KERNEL);
- if (!ctu_info) {
- dev_err(dev, "ctu info allocation error\n");
- goto rsnd_of_parse_ctu_end;
- }
-
- info->ctu_info = ctu_info;
- info->ctu_info_nr = nr;
-
-rsnd_of_parse_ctu_end:
- of_node_put(node);
-
-}
-
-int rsnd_ctu_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ctu *ctu;
struct clk *clk;
@@ -121,20 +91,30 @@ int rsnd_ctu_probe(struct platform_device *pdev,
if (rsnd_is_gen1(priv))
return 0;
- rsnd_of_parse_ctu(pdev, of_data, priv);
+ node = rsnd_ctu_of_node(priv);
+ if (!node)
+ return 0; /* not used is not error */
- nr = info->ctu_info_nr;
- if (!nr)
- return 0;
+ nr = of_get_child_count(node);
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_ctu_probe_done;
+ }
ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
- if (!ctu)
- return -ENOMEM;
+ if (!ctu) {
+ ret = -ENOMEM;
+ goto rsnd_ctu_probe_done;
+ }
priv->ctu_nr = nr;
priv->ctu = ctu;
- for_each_rsnd_ctu(ctu, priv, i) {
+ i = 0;
+ ret = 0;
+ for_each_child_of_node(node, np) {
+ ctu = rsnd_ctu_get(priv, i);
+
/*
* CTU00, CTU01, CTU02, CTU03 => CTU0
* CTU10, CTU11, CTU12, CTU13 => CTU1
@@ -143,22 +123,27 @@ int rsnd_ctu_probe(struct platform_device *pdev,
CTU_NAME, i / 4);
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- ctu->info = &info->ctu_info[i];
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto rsnd_ctu_probe_done;
+ }
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
clk, RSND_MOD_CTU, i);
if (ret)
- return ret;
+ goto rsnd_ctu_probe_done;
+
+ i++;
}
- return 0;
+
+rsnd_ctu_probe_done:
+ of_node_put(node);
+
+ return ret;
}
-void rsnd_ctu_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
+void rsnd_ctu_remove(struct rsnd_priv *priv)
{
struct rsnd_ctu *ctu;
int i;
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 5d084d040961..418e6fdd06a3 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -22,21 +22,36 @@
/* PDMACHCR */
#define PDMACHCR_DE (1 << 0)
+
+struct rsnd_dmaen {
+ struct dma_chan *chan;
+};
+
+struct rsnd_dmapp {
+ int dmapp_id;
+ u32 chcr;
+};
+
+struct rsnd_dma {
+ struct rsnd_mod mod;
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ union {
+ struct rsnd_dmaen en;
+ struct rsnd_dmapp pp;
+ } dma;
+};
+
struct rsnd_dma_ctrl {
void __iomem *base;
+ int dmaen_num;
int dmapp_num;
};
-struct rsnd_dma_ops {
- char *name;
- void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
- void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
- int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
- struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
- void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-};
-
#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma)
+#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
+#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
+#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
/*
* Audio DMAC
@@ -77,18 +92,24 @@ static void rsnd_dmaen_complete(void *data)
rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
}
-static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmaen_stop(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
dmaengine_terminate_all(dmaen->chan);
+
+ return 0;
}
-static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmaen_start(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc;
@@ -103,18 +124,20 @@ static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
if (!desc) {
dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
- return;
+ return -EIO;
}
desc->callback = rsnd_dmaen_complete;
- desc->callback_param = mod;
+ desc->callback_param = rsnd_mod_get(dma);
if (dmaengine_submit(desc) < 0) {
dev_err(dev, "dmaengine_submit() fail\n");
- return;
+ return -EIO;
}
dma_async_issue_pending(dmaen->chan);
+
+ return 0;
}
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
@@ -152,12 +175,29 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
return rsnd_mod_dma_req(io, mod_to);
}
-static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
+static int rsnd_dmaen_remove(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+ struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+ if (dmaen->chan)
+ dma_release_channel(dmaen->chan);
+
+ dmaen->chan = NULL;
+
+ return 0;
+}
+
+static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
struct rsnd_dma *dma, int id,
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
{
+ struct rsnd_mod *mod = rsnd_mod_get(dma);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_slave_config cfg = {};
int is_play = rsnd_io_is_play(io);
@@ -191,18 +231,20 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev_dbg(dev, "%s %pad -> %pad\n",
- dma->ops->name,
+ dev_dbg(dev, "%s[%d] %pad -> %pad\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
&cfg.src_addr, &cfg.dst_addr);
ret = dmaengine_slave_config(dmaen->chan, &cfg);
if (ret < 0)
- goto rsnd_dma_init_err;
+ goto rsnd_dma_attach_err;
+
+ dmac->dmaen_num++;
return 0;
-rsnd_dma_init_err:
- rsnd_dma_quit(io, dma);
+rsnd_dma_attach_err:
+ rsnd_dmaen_remove(mod, io, priv);
rsnd_dma_channel_err:
/*
@@ -214,22 +256,11 @@ rsnd_dma_channel_err:
return -EAGAIN;
}
-static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
- struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
- if (dmaen->chan)
- dma_release_channel(dmaen->chan);
-
- dmaen->chan = NULL;
-}
-
-static struct rsnd_dma_ops rsnd_dmaen_ops = {
+static struct rsnd_mod_ops rsnd_dmaen_ops = {
.name = "audmac",
.start = rsnd_dmaen_start,
.stop = rsnd_dmaen_stop,
- .init = rsnd_dmaen_init,
- .quit = rsnd_dmaen_quit,
+ .remove = rsnd_dmaen_remove,
};
/*
@@ -307,7 +338,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
(0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
{
- struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+ struct rsnd_mod *mod = rsnd_mod_get(dma);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv);
@@ -319,38 +350,48 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
{
- struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+ struct rsnd_mod *mod = rsnd_mod_get(dma);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
}
-static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmapp_stop(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
int i;
rsnd_dmapp_write(dma, 0, PDMACHCR);
for (i = 0; i < 1024; i++) {
if (0 == rsnd_dmapp_read(dma, PDMACHCR))
- return;
+ return 0;
udelay(1);
}
+
+ return -EIO;
}
-static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmapp_start(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
rsnd_dmapp_write(dma, dma->src_addr, PDMASAR);
rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR);
rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR);
+
+ return 0;
}
-static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
- struct rsnd_dma *dma, int id,
- struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
+ struct rsnd_dma *dma, int id,
+ struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
{
struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
struct rsnd_priv *priv = rsnd_io_to_priv(io);
@@ -362,19 +403,16 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
dmac->dmapp_num++;
- rsnd_dmapp_stop(io, dma);
-
dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
return 0;
}
-static struct rsnd_dma_ops rsnd_dmapp_ops = {
+static struct rsnd_mod_ops rsnd_dmapp_ops = {
.name = "audmac-pp",
.start = rsnd_dmapp_start,
.stop = rsnd_dmapp_stop,
- .init = rsnd_dmapp_init,
.quit = rsnd_dmapp_stop,
};
@@ -497,13 +535,12 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
}
#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
-static void rsnd_dma_of_path(struct rsnd_dma *dma,
+static void rsnd_dma_of_path(struct rsnd_mod *this,
struct rsnd_dai_stream *io,
int is_play,
struct rsnd_mod **mod_from,
struct rsnd_mod **mod_to)
{
- struct rsnd_mod *this = rsnd_dma_to_mod(dma);
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
@@ -513,7 +550,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
struct rsnd_mod *mod_start, *mod_end;
struct rsnd_priv *priv = rsnd_mod_to_priv(this);
struct device *dev = rsnd_priv_to_dev(priv);
- int nr, i;
+ int nr, i, idx;
if (!ssi)
return;
@@ -542,23 +579,24 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
mod_start = (is_play) ? NULL : ssi;
mod_end = (is_play) ? ssi : NULL;
- mod[0] = mod_start;
+ idx = 0;
+ mod[idx++] = mod_start;
for (i = 1; i < nr; i++) {
if (src) {
- mod[i] = src;
+ mod[idx++] = src;
src = NULL;
} else if (ctu) {
- mod[i] = ctu;
+ mod[idx++] = ctu;
ctu = NULL;
} else if (mix) {
- mod[i] = mix;
+ mod[idx++] = mix;
mix = NULL;
} else if (dvc) {
- mod[i] = dvc;
+ mod[idx++] = dvc;
dvc = NULL;
}
}
- mod[i] = mod_end;
+ mod[idx] = mod_end;
/*
* | SSI | SRC |
@@ -567,8 +605,8 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
* !is_play | * | o |
*/
if ((this == ssi) == (is_play)) {
- *mod_from = mod[nr - 1];
- *mod_to = mod[nr];
+ *mod_from = mod[idx - 1];
+ *mod_to = mod[idx];
} else {
*mod_from = mod[0];
*mod_to = mod[1];
@@ -576,7 +614,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
dev_dbg(dev, "module connection (this is %s[%d])\n",
rsnd_mod_name(this), rsnd_mod_id(this));
- for (i = 0; i <= nr; i++) {
+ for (i = 0; i <= idx; i++) {
dev_dbg(dev, " %s[%d]%s\n",
rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
(mod[i] == *mod_from) ? " from" :
@@ -584,36 +622,22 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
}
}
-void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
- dma->ops->stop(io, dma);
-}
-
-void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
- dma->ops->start(io, dma);
-}
-
-void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
- struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-
- if (!dmac)
- return;
-
- dma->ops->quit(io, dma);
-}
-
-int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
+struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod, int id)
{
+ struct rsnd_mod *dma_mod;
struct rsnd_mod *mod_from = NULL;
struct rsnd_mod *mod_to = NULL;
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+ struct rsnd_dma *dma;
struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_mod_ops *ops;
+ enum rsnd_mod_type type;
+ int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+ struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
int is_play = rsnd_io_is_play(io);
+ int ret, dma_id;
/*
* DMA failed. try to PIO mode
@@ -622,35 +646,64 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
* rsnd_rdai_continuance_probe()
*/
if (!dmac)
- return -EAGAIN;
+ return ERR_PTR(-EAGAIN);
- rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to);
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return ERR_PTR(-ENOMEM);
+
+ rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
/* for Gen2 */
- if (mod_from && mod_to)
- dma->ops = &rsnd_dmapp_ops;
- else
- dma->ops = &rsnd_dmaen_ops;
+ if (mod_from && mod_to) {
+ ops = &rsnd_dmapp_ops;
+ attach = rsnd_dmapp_attach;
+ dma_id = dmac->dmapp_num;
+ type = RSND_MOD_AUDMAPP;
+ } else {
+ ops = &rsnd_dmaen_ops;
+ attach = rsnd_dmaen_attach;
+ dma_id = dmac->dmaen_num;
+ type = RSND_MOD_AUDMA;
+ }
/* for Gen1, overwrite */
- if (rsnd_is_gen1(priv))
- dma->ops = &rsnd_dmaen_ops;
+ if (rsnd_is_gen1(priv)) {
+ ops = &rsnd_dmaen_ops;
+ attach = rsnd_dmaen_attach;
+ dma_id = dmac->dmaen_num;
+ type = RSND_MOD_AUDMA;
+ }
+
+ dma_mod = rsnd_mod_get(dma);
+
+ ret = rsnd_mod_init(priv, dma_mod,
+ ops, NULL, type, dma_id);
+ if (ret < 0)
+ return ERR_PTR(ret);
- dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
- dma->ops->name,
+ dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
+ rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod),
rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
- return dma->ops->init(io, dma, id, mod_from, mod_to);
+ ret = attach(io, dma, id, mod_from, mod_to);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ ret = rsnd_dai_connect(dma_mod, io, type);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return rsnd_mod_get(dma);
}
-int rsnd_dma_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_dma_probe(struct rsnd_priv *priv)
{
+ struct platform_device *pdev = rsnd_priv_to_pdev(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dma_ctrl *dmac;
struct resource *res;
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 58f690900e6d..d45ffe496397 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -15,7 +15,6 @@
#define DVC_NAME "dvc"
struct rsnd_dvc {
- struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
struct rsnd_kctrl_cfg_m volume;
struct rsnd_kctrl_cfg_m mute;
@@ -24,6 +23,7 @@ struct rsnd_dvc {
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
};
+#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
#define rsnd_dvc_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
@@ -64,79 +64,142 @@ static const char * const dvc_ramp_rate[] = {
"0.125 dB/8192 steps", /* 10111 */
};
-static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
+static void rsnd_dvc_activation(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, DVC_SWRSR, 0);
rsnd_mod_write(mod, DVC_SWRSR, 1);
}
-#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1)
-#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0)
-static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_dvc_halt(struct rsnd_mod *mod)
{
- rsnd_mod_write(mod, DVC_DVUIR, enable);
+ rsnd_mod_write(mod, DVC_DVUIR, 1);
+ rsnd_mod_write(mod, DVC_SWRSR, 0);
}
-static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod)
+#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
+
+static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
{
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
u32 val[RSND_DVC_CHANNELS];
- u32 dvucr = 0;
- u32 mute = 0;
int i;
- for (i = 0; i < dvc->mute.cfg.size; i++)
- mute |= (!!dvc->mute.cfg.val[i]) << i;
+ /* Enable Ramp */
+ if (dvc->ren.val)
+ for (i = 0; i < RSND_DVC_CHANNELS; i++)
+ val[i] = dvc->volume.cfg.max;
+ else
+ for (i = 0; i < RSND_DVC_CHANNELS; i++)
+ val[i] = dvc->volume.val[i];
- /* Disable DVC Register access */
- rsnd_mod_write(mod, DVC_DVUER, 0);
+ /* 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]);
+}
+
+static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+ u32 adinr = 0;
+ u32 dvucr = 0;
+ u32 vrctr = 0;
+ u32 vrpdr = 0;
+ u32 vrdbr = 0;
+
+ adinr = rsnd_get_adinr_bit(mod, io) |
+ rsnd_get_adinr_chan(mod, io);
+
+ /* Enable Digital Volume, Zero Cross Mute Mode */
+ dvucr |= 0x101;
/* Enable Ramp */
if (dvc->ren.val) {
dvucr |= 0x10;
- /* Digital Volume Max */
- for (i = 0; i < RSND_DVC_CHANNELS; i++)
- val[i] = dvc->volume.cfg.max;
-
- rsnd_mod_write(mod, DVC_VRCTR, 0xff);
- rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
- dvc->rdown.val);
/*
* FIXME !!
* use scale-downed Digital Volume
* as Volume Ramp
* 7F FFFF -> 3FF
*/
- rsnd_mod_write(mod, DVC_VRDBR,
- 0x3ff - (dvc->volume.val[0] >> 13));
-
- } else {
- for (i = 0; i < RSND_DVC_CHANNELS; i++)
- val[i] = dvc->volume.val[i];
+ vrctr = 0xff;
+ vrpdr = rsnd_dvc_get_vrpdr(dvc);
+ vrdbr = rsnd_dvc_get_vrdbr(dvc);
}
- /* Enable Digital Volume */
- dvucr |= 0x100;
- rsnd_mod_write(mod, DVC_VOL0R, val[0]);
- rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+ /* Initialize operation */
+ rsnd_mod_write(mod, DVC_DVUIR, 1);
+
+ /* General Information */
+ rsnd_mod_write(mod, DVC_ADINR, adinr);
+ rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+
+ /* Volume Ramp Parameter */
+ rsnd_mod_write(mod, DVC_VRCTR, vrctr);
+ rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+ rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+
+ /* Digital Volume Function Parameter */
+ rsnd_dvc_volume_parameter(io, mod);
+
+ /* cancel operation */
+ rsnd_mod_write(mod, DVC_DVUIR, 0);
+}
+
+static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+ u32 zcmcr = 0;
+ u32 vrpdr = 0;
+ u32 vrdbr = 0;
+ int i;
+
+ for (i = 0; i < dvc->mute.cfg.size; i++)
+ zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
- /* Enable Mute */
- if (mute) {
- dvucr |= 0x1;
- rsnd_mod_write(mod, DVC_ZCMCR, mute);
+ if (dvc->ren.val) {
+ vrpdr = rsnd_dvc_get_vrpdr(dvc);
+ vrdbr = rsnd_dvc_get_vrdbr(dvc);
}
- rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+ /* Disable DVC Register access */
+ rsnd_mod_write(mod, DVC_DVUER, 0);
+
+ /* Zero Cross Mute Function */
+ rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
+
+ /* Volume Ramp Function */
+ rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+ rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+ /* add DVC_VRWTR here */
+
+ /* Digital Volume Function Parameter */
+ rsnd_dvc_volume_parameter(io, mod);
/* Enable DVC Register access */
rsnd_mod_write(mod, DVC_DVUER, 1);
}
-static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static int rsnd_dvc_probe_(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static int rsnd_dvc_remove_(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
@@ -155,19 +218,12 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
{
rsnd_mod_power_on(mod);
- rsnd_dvc_soft_reset(mod);
-
- rsnd_dvc_initialize_lock(mod);
-
- rsnd_path_parse(priv, io);
+ rsnd_dvc_activation(mod);
- rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
+ rsnd_dvc_volume_init(io, mod);
- /* ch0/ch1 Volume */
rsnd_dvc_volume_update(io, mod);
- rsnd_adg_set_cmd_timsel_gen2(mod, io);
-
return 0;
}
@@ -175,27 +231,9 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- rsnd_mod_power_off(mod);
+ rsnd_dvc_halt(mod);
- return 0;
-}
-
-static int rsnd_dvc_start(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- rsnd_dvc_initialize_unlock(mod);
-
- rsnd_mod_write(mod, CMD_CTRL, 0x10);
-
- return 0;
-}
-
-static int rsnd_dvc_stop(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- rsnd_mod_write(mod, CMD_CTRL, 0);
+ rsnd_mod_power_off(mod);
return 0;
}
@@ -206,6 +244,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
{
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
int is_play = rsnd_io_is_play(io);
+ int slots = rsnd_get_slot(io);
int ret;
/* Volume */
@@ -213,7 +252,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
is_play ?
"DVC Out Playback Volume" : "DVC In Capture Volume",
rsnd_dvc_volume_update,
- &dvc->volume, 0x00800000 - 1);
+ &dvc->volume, slots,
+ 0x00800000 - 1);
if (ret < 0)
return ret;
@@ -222,7 +262,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
is_play ?
"DVC Out Mute Switch" : "DVC In Mute Switch",
rsnd_dvc_volume_update,
- &dvc->mute, 1);
+ &dvc->mute, slots,
+ 1);
if (ret < 0)
return ret;
@@ -269,11 +310,10 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
static struct rsnd_mod_ops rsnd_dvc_ops = {
.name = DVC_NAME,
.dma_req = rsnd_dvc_dma_req,
- .remove = rsnd_dvc_remove_gen2,
+ .probe = rsnd_dvc_probe_,
+ .remove = rsnd_dvc_remove_,
.init = rsnd_dvc_init,
.quit = rsnd_dvc_quit,
- .start = rsnd_dvc_start,
- .stop = rsnd_dvc_stop,
.pcm_new = rsnd_dvc_pcm_new,
};
@@ -282,50 +322,13 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
id = 0;
- return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
+ return rsnd_mod_get(rsnd_dvc_get(priv, id));
}
-static void rsnd_of_parse_dvc(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_dvc_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct rsnd_dvc_platform_info *dvc_info;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct device *dev = &pdev->dev;
- int nr;
-
- if (!of_data)
- return;
-
- node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
- if (!node)
- return;
-
- nr = of_get_child_count(node);
- if (!nr)
- goto rsnd_of_parse_dvc_end;
-
- dvc_info = devm_kzalloc(dev,
- sizeof(struct rsnd_dvc_platform_info) * nr,
- GFP_KERNEL);
- if (!dvc_info) {
- dev_err(dev, "dvc info allocation error\n");
- goto rsnd_of_parse_dvc_end;
- }
-
- info->dvc_info = dvc_info;
- info->dvc_info_nr = nr;
-
-rsnd_of_parse_dvc_end:
- of_node_put(node);
-}
-
-int rsnd_dvc_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dvc *dvc;
struct clk *clk;
@@ -336,40 +339,54 @@ int rsnd_dvc_probe(struct platform_device *pdev,
if (rsnd_is_gen1(priv))
return 0;
- rsnd_of_parse_dvc(pdev, of_data, priv);
+ node = rsnd_dvc_of_node(priv);
+ if (!node)
+ return 0; /* not used is not error */
- nr = info->dvc_info_nr;
- if (!nr)
- return 0;
+ nr = of_get_child_count(node);
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_dvc_probe_done;
+ }
dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
- if (!dvc)
- return -ENOMEM;
+ if (!dvc) {
+ ret = -ENOMEM;
+ goto rsnd_dvc_probe_done;
+ }
priv->dvc_nr = nr;
priv->dvc = dvc;
- for_each_rsnd_dvc(dvc, priv, i) {
+ i = 0;
+ ret = 0;
+ for_each_child_of_node(node, np) {
+ dvc = rsnd_dvc_get(priv, i);
+
snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
DVC_NAME, i);
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- dvc->info = &info->dvc_info[i];
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto rsnd_dvc_probe_done;
+ }
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
clk, RSND_MOD_DVC, i);
if (ret)
- return ret;
+ goto rsnd_dvc_probe_done;
+
+ i++;
}
- return 0;
+rsnd_dvc_probe_done:
+ of_node_put(node);
+
+ return ret;
}
-void rsnd_dvc_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
+void rsnd_dvc_remove(struct rsnd_priv *priv)
{
struct rsnd_dvc *dvc;
int i;
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index edcf4cc2e84f..ea24247eba73 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -31,29 +31,33 @@ struct rsnd_gen {
/* RSND_REG_MAX base */
struct regmap_field *regs[RSND_REG_MAX];
+ const char *reg_name[RSND_REG_MAX];
};
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
+#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
struct rsnd_regmap_field_conf {
int idx;
unsigned int reg_offset;
unsigned int id_offset;
+ const char *reg_name;
};
-#define RSND_REG_SET(id, offset, _id_offset) \
+#define RSND_REG_SET(id, offset, _id_offset, n) \
{ \
.idx = id, \
.reg_offset = offset, \
.id_offset = _id_offset, \
+ .reg_name = n, \
}
/* single address mapping */
#define RSND_GEN_S_REG(id, offset) \
- RSND_REG_SET(RSND_REG_##id, offset, 0)
+ RSND_REG_SET(RSND_REG_##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)
+ RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
/*
* basic function
@@ -83,8 +87,9 @@ u32 rsnd_read(struct rsnd_priv *priv,
regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
- dev_dbg(dev, "r %s[%d] - %4d : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
+ dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
+ rsnd_reg_name(gen, reg), reg, val);
return val;
}
@@ -99,10 +104,11 @@ void rsnd_write(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
- dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
-
regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+ dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
+ rsnd_reg_name(gen, reg), reg, data);
}
void rsnd_force_write(struct rsnd_priv *priv,
@@ -115,10 +121,11 @@ void rsnd_force_write(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
- dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
-
regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+ dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
+ rsnd_reg_name(gen, reg), reg, data);
}
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
@@ -130,11 +137,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
- dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask);
-
regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
mask, data);
+
+ dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
+ rsnd_reg_name(gen, reg), reg, data, mask);
+
}
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
@@ -150,7 +159,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
int id_size,
int reg_id,
const char *name,
- struct rsnd_regmap_field_conf *conf,
+ const struct rsnd_regmap_field_conf *conf,
int conf_size)
{
struct platform_device *pdev = rsnd_priv_to_pdev(priv);
@@ -203,6 +212,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
/* RSND_REG_MAX base */
gen->regs[conf[i].idx] = regs;
+ gen->reg_name[conf[i].idx] = conf[i].reg_name;
}
return 0;
@@ -211,25 +221,31 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
/*
* Gen2
*/
-static int rsnd_gen2_probe(struct platform_device *pdev,
- struct rsnd_priv *priv)
+static int rsnd_gen2_probe(struct rsnd_priv *priv)
{
- struct rsnd_regmap_field_conf conf_ssiu[] = {
+ const static struct rsnd_regmap_field_conf conf_ssiu[] = {
RSND_GEN_S_REG(SSI_MODE0, 0x800),
RSND_GEN_S_REG(SSI_MODE1, 0x804),
+ RSND_GEN_S_REG(SSI_MODE2, 0x808),
+ RSND_GEN_S_REG(SSI_CONTROL, 0x810),
+
/* FIXME: it needs SSI_MODE2/3 in the future */
RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80),
RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80),
+ RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
};
- struct rsnd_regmap_field_conf conf_scu[] = {
- RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20),
+
+ const static struct rsnd_regmap_field_conf conf_scu[] = {
+ RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20),
+ RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20),
RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20),
RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
+ RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20),
RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
@@ -266,9 +282,15 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
+ RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
+ RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
+ RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
+ RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
+ RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
+ RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
};
- struct rsnd_regmap_field_conf conf_adg[] = {
+ const static struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04),
RSND_GEN_S_REG(SSICKR, 0x08),
@@ -288,7 +310,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
};
- struct rsnd_regmap_field_conf conf_ssi[] = {
+ const static struct rsnd_regmap_field_conf conf_ssi[] = {
RSND_GEN_M_REG(SSICR, 0x00, 0x40),
RSND_GEN_M_REG(SSISR, 0x04, 0x40),
RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
@@ -317,65 +339,30 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
* Gen1
*/
-static int rsnd_gen1_probe(struct platform_device *pdev,
- struct rsnd_priv *priv)
+static int rsnd_gen1_probe(struct rsnd_priv *priv)
{
- struct rsnd_regmap_field_conf conf_sru[] = {
- RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00),
- RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08),
- RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c),
- RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10),
- RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0),
- RSND_GEN_S_REG(SSI_MODE0, 0xD0),
- RSND_GEN_S_REG(SSI_MODE1, 0xD4),
- RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4),
- RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8),
- RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
- RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
- RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
- RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
- RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
- RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
- RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40),
- /*
- * ADD US
- *
- * SRC_STATUS
- * SRC_INT_EN
- * SCU_SYS_STATUS0
- * SCU_SYS_STATUS1
- * SCU_SYS_INT_EN0
- * SCU_SYS_INT_EN1
- */
- };
- struct rsnd_regmap_field_conf conf_adg[] = {
+ const static struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04),
RSND_GEN_S_REG(SSICKR, 0x08),
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
- RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18),
- RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c),
- RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20),
};
- struct rsnd_regmap_field_conf conf_ssi[] = {
+ const static struct rsnd_regmap_field_conf conf_ssi[] = {
RSND_GEN_M_REG(SSICR, 0x00, 0x40),
RSND_GEN_M_REG(SSISR, 0x04, 0x40),
RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
};
- int ret_sru;
int ret_adg;
int ret_ssi;
- ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru);
ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
- if (ret_sru < 0 ||
- ret_adg < 0 ||
+ if (ret_adg < 0 ||
ret_ssi < 0)
- return ret_sru | ret_adg | ret_ssi;
+ return ret_adg | ret_ssi;
return 0;
}
@@ -383,28 +370,12 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
/*
* Gen
*/
-static void rsnd_of_parse_gen(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct rcar_snd_info *info = priv->info;
-
- if (!of_data)
- return;
-
- info->flags = of_data->flags;
-}
-
-int rsnd_gen_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_gen_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen;
int ret;
- rsnd_of_parse_gen(pdev, of_data, priv);
-
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
if (!gen) {
dev_err(dev, "GEN allocate failed\n");
@@ -415,9 +386,9 @@ int rsnd_gen_probe(struct platform_device *pdev,
ret = -ENODEV;
if (rsnd_is_gen1(priv))
- ret = rsnd_gen1_probe(pdev, priv);
+ ret = rsnd_gen1_probe(priv);
else if (rsnd_is_gen2(priv))
- ret = rsnd_gen2_probe(pdev, priv);
+ ret = rsnd_gen2_probe(priv);
if (ret < 0)
dev_err(dev, "unknown generation R-Car sound device\n");
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 953dd0be9b60..65542b6a89e9 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -13,10 +13,10 @@
#define MIX_NAME "mix"
struct rsnd_mix {
- struct rsnd_mix_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
};
+#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
#define rsnd_mix_nr(priv) ((priv)->mix_nr)
#define for_each_rsnd_mix(pos, priv, i) \
for ((i) = 0; \
@@ -24,58 +24,77 @@ struct rsnd_mix {
((pos) = (struct rsnd_mix *)(priv)->mix + i); \
i++)
-
-static void rsnd_mix_soft_reset(struct rsnd_mod *mod)
+static void rsnd_mix_activation(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, MIX_SWRSR, 0);
rsnd_mod_write(mod, MIX_SWRSR, 1);
}
-#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1)
-#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0)
-static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_mix_halt(struct rsnd_mod *mod)
+{
+ rsnd_mod_write(mod, MIX_MIXIR, 1);
+ rsnd_mod_write(mod, MIX_SWRSR, 0);
+}
+
+static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
{
- rsnd_mod_write(mod, MIX_MIXIR, enable);
+ rsnd_mod_write(mod, MIX_MDBAR, 0);
+ rsnd_mod_write(mod, MIX_MDBBR, 0);
+ rsnd_mod_write(mod, MIX_MDBCR, 0);
+ rsnd_mod_write(mod, MIX_MDBDR, 0);
+}
+
+static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ rsnd_mod_write(mod, MIX_MIXIR, 1);
+
+ /* General Information */
+ rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
+
+ /* volume step */
+ rsnd_mod_write(mod, MIX_MIXMR, 0);
+ rsnd_mod_write(mod, MIX_MVPDR, 0);
+
+ /* common volume parameter */
+ rsnd_mix_volume_parameter(io, mod);
+
+ rsnd_mod_write(mod, MIX_MIXIR, 0);
}
static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
-
/* Disable MIX dB setting */
rsnd_mod_write(mod, MIX_MDBER, 0);
- rsnd_mod_write(mod, MIX_MDBAR, 0);
- rsnd_mod_write(mod, MIX_MDBBR, 0);
- rsnd_mod_write(mod, MIX_MDBCR, 0);
- rsnd_mod_write(mod, MIX_MDBDR, 0);
+ /* common volume parameter */
+ rsnd_mix_volume_parameter(io, mod);
/* Enable MIX dB setting */
rsnd_mod_write(mod, MIX_MDBER, 1);
}
+static int rsnd_mix_probe_(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
static int rsnd_mix_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
rsnd_mod_power_on(mod);
- rsnd_mix_soft_reset(mod);
-
- rsnd_mix_initialize_lock(mod);
-
- rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
-
- rsnd_path_parse(priv, io);
+ rsnd_mix_activation(mod);
- /* volume step */
- rsnd_mod_write(mod, MIX_MIXMR, 0);
- rsnd_mod_write(mod, MIX_MVPDR, 0);
+ rsnd_mix_volume_init(io, mod);
rsnd_mix_volume_update(io, mod);
- rsnd_mix_initialize_unlock(mod);
-
return 0;
}
@@ -83,6 +102,8 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ rsnd_mix_halt(mod);
+
rsnd_mod_power_off(mod);
return 0;
@@ -90,6 +111,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_mix_ops = {
.name = MIX_NAME,
+ .probe = rsnd_mix_probe_,
.init = rsnd_mix_init,
.quit = rsnd_mix_quit,
};
@@ -99,51 +121,13 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
id = 0;
- return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id);
+ return rsnd_mod_get(rsnd_mix_get(priv, id));
}
-static void rsnd_of_parse_mix(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_mix_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct rsnd_mix_platform_info *mix_info;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct device *dev = &pdev->dev;
- int nr;
-
- if (!of_data)
- return;
-
- node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
- if (!node)
- return;
-
- nr = of_get_child_count(node);
- if (!nr)
- goto rsnd_of_parse_mix_end;
-
- mix_info = devm_kzalloc(dev,
- sizeof(struct rsnd_mix_platform_info) * nr,
- GFP_KERNEL);
- if (!mix_info) {
- dev_err(dev, "mix info allocation error\n");
- goto rsnd_of_parse_mix_end;
- }
-
- info->mix_info = mix_info;
- info->mix_info_nr = nr;
-
-rsnd_of_parse_mix_end:
- of_node_put(node);
-
-}
-
-int rsnd_mix_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mix *mix;
struct clk *clk;
@@ -154,40 +138,54 @@ int rsnd_mix_probe(struct platform_device *pdev,
if (rsnd_is_gen1(priv))
return 0;
- rsnd_of_parse_mix(pdev, of_data, priv);
+ node = rsnd_mix_of_node(priv);
+ if (!node)
+ return 0; /* not used is not error */
- nr = info->mix_info_nr;
- if (!nr)
- return 0;
+ nr = of_get_child_count(node);
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_mix_probe_done;
+ }
mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
- if (!mix)
- return -ENOMEM;
+ if (!mix) {
+ ret = -ENOMEM;
+ goto rsnd_mix_probe_done;
+ }
priv->mix_nr = nr;
priv->mix = mix;
- for_each_rsnd_mix(mix, priv, i) {
+ i = 0;
+ ret = 0;
+ for_each_child_of_node(node, np) {
+ mix = rsnd_mix_get(priv, i);
+
snprintf(name, MIX_NAME_SIZE, "%s.%d",
MIX_NAME, i);
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- mix->info = &info->mix_info[i];
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto rsnd_mix_probe_done;
+ }
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
clk, RSND_MOD_MIX, i);
if (ret)
- return ret;
+ goto rsnd_mix_probe_done;
+
+ i++;
}
- return 0;
+rsnd_mix_probe_done:
+ of_node_put(node);
+
+ return ret;
}
-void rsnd_mix_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
+void rsnd_mix_remove(struct rsnd_priv *priv)
{
struct rsnd_mix *mix;
int i;
diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h
deleted file mode 100644
index d8e33d38da43..000000000000
--- a/sound/soc/sh/rcar/rcar_snd.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 RCAR_SND_H
-#define RCAR_SND_H
-
-
-#define RSND_GEN1_SRU 0
-#define RSND_GEN1_ADG 1
-#define RSND_GEN1_SSI 2
-
-#define RSND_GEN2_SCU 0
-#define RSND_GEN2_ADG 1
-#define RSND_GEN2_SSIU 2
-#define RSND_GEN2_SSI 3
-
-#define RSND_BASE_MAX 4
-
-/*
- * flags
- *
- * 0xAB000000
- *
- * A : clock sharing settings
- * B : SSI direction
- */
-#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
-#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
-
-#define RSND_SSI(_dma_id, _irq, _flags) \
-{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
-#define RSND_SSI_UNUSED \
-{ .dma_id = -1, .irq = -1, .flags = 0 }
-
-struct rsnd_ssi_platform_info {
- int dma_id;
- int irq;
- u32 flags;
-};
-
-#define RSND_SRC(rate, _dma_id) \
-{ .convert_rate = rate, .dma_id = _dma_id, }
-#define RSND_SRC_UNUSED \
-{ .convert_rate = 0, .dma_id = -1, }
-
-struct rsnd_src_platform_info {
- u32 convert_rate; /* sampling rate convert */
- int dma_id; /* for Gen2 SCU */
- int irq;
-};
-
-/*
- * flags
- */
-struct rsnd_ctu_platform_info {
- u32 flags;
-};
-
-struct rsnd_mix_platform_info {
- u32 flags;
-};
-
-struct rsnd_dvc_platform_info {
- u32 flags;
-};
-
-struct rsnd_dai_path_info {
- struct rsnd_ssi_platform_info *ssi;
- struct rsnd_src_platform_info *src;
- struct rsnd_ctu_platform_info *ctu;
- struct rsnd_mix_platform_info *mix;
- struct rsnd_dvc_platform_info *dvc;
-};
-
-struct rsnd_dai_platform_info {
- struct rsnd_dai_path_info playback;
- struct rsnd_dai_path_info capture;
-};
-
-/*
- * flags
- *
- * 0x0000000A
- *
- * A : generation
- */
-#define RSND_GEN_MASK (0xF << 0)
-#define RSND_GEN1 (1 << 0) /* fixme */
-#define RSND_GEN2 (2 << 0) /* fixme */
-
-struct rcar_snd_info {
- u32 flags;
- struct rsnd_ssi_platform_info *ssi_info;
- int ssi_info_nr;
- struct rsnd_src_platform_info *src_info;
- int src_info_nr;
- struct rsnd_ctu_platform_info *ctu_info;
- int ctu_info_nr;
- struct rsnd_mix_platform_info *mix_info;
- int mix_info_nr;
- struct rsnd_dvc_platform_info *dvc_info;
- int dvc_info_nr;
- struct rsnd_dai_platform_info *dai_info;
- int dai_info_nr;
- int (*start)(int id);
- int (*stop)(int id);
-};
-
-#endif
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 085329878525..317dd793149a 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -24,7 +24,16 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include "rcar_snd.h"
+#define RSND_GEN1_SRU 0
+#define RSND_GEN1_ADG 1
+#define RSND_GEN1_SSI 2
+
+#define RSND_GEN2_SCU 0
+#define RSND_GEN2_ADG 1
+#define RSND_GEN2_SSIU 2
+#define RSND_GEN2_SSI 3
+
+#define RSND_BASE_MAX 4
/*
* pseudo register
@@ -34,10 +43,19 @@
* see gen1/gen2 for detail
*/
enum rsnd_reg {
- /* SRU/SCU/SSIU */
+ /* SCU (SRC/SSIU/MIX/CTU/DVC) */
+ RSND_REG_SSI_MODE, /* Gen2 only */
RSND_REG_SSI_MODE0,
RSND_REG_SSI_MODE1,
- RSND_REG_SRC_BUSIF_MODE,
+ RSND_REG_SSI_MODE2,
+ RSND_REG_SSI_CONTROL,
+ RSND_REG_SSI_CTRL, /* Gen2 only */
+ RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */
+ RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */
+ RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */
+ RSND_REG_SSI_INT_ENABLE, /* Gen2 only */
+ 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,
@@ -45,9 +63,29 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR,
RSND_REG_SRC_IFSVR,
RSND_REG_SRC_SRCCR,
+ RSND_REG_SRC_CTRL, /* Gen2 only */
+ RSND_REG_SRC_BSDSR, /* Gen2 only */
+ RSND_REG_SRC_BSISR, /* Gen2 only */
+ RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */
+ RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */
+ RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */
+ RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */
+ RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */
+ RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */
+ RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */
+ RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */
+ RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */
+ RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */
+ RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */
+ RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */
RSND_REG_SCU_SYS_STATUS0,
+ RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */
RSND_REG_SCU_SYS_INT_EN0,
+ RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */
+ RSND_REG_CMD_CTRL, /* Gen2 only */
+ RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */
RSND_REG_CMD_ROUTE_SLCT,
+ RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */
RSND_REG_CTU_CTUIR,
RSND_REG_CTU_ADINR,
RSND_REG_MIX_SWRSR,
@@ -67,14 +105,25 @@ enum rsnd_reg {
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, /* Gen2 only */
+ RSND_REG_DVC_VRPDR, /* Gen2 only */
+ RSND_REG_DVC_VRDBR, /* Gen2 only */
/* ADG */
RSND_REG_BRRA,
RSND_REG_BRRB,
RSND_REG_SSICKR,
+ RSND_REG_DIV_EN, /* Gen2 only */
RSND_REG_AUDIO_CLK_SEL0,
RSND_REG_AUDIO_CLK_SEL1,
+ RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */
/* SSI */
RSND_REG_SSICR,
@@ -83,83 +132,9 @@ enum rsnd_reg {
RSND_REG_SSIRDR,
RSND_REG_SSIWSR,
- /* SHARE see below */
- RSND_REG_SHARE01,
- RSND_REG_SHARE02,
- RSND_REG_SHARE03,
- RSND_REG_SHARE04,
- RSND_REG_SHARE05,
- RSND_REG_SHARE06,
- RSND_REG_SHARE07,
- RSND_REG_SHARE08,
- RSND_REG_SHARE09,
- RSND_REG_SHARE10,
- RSND_REG_SHARE11,
- RSND_REG_SHARE12,
- RSND_REG_SHARE13,
- RSND_REG_SHARE14,
- RSND_REG_SHARE15,
- RSND_REG_SHARE16,
- RSND_REG_SHARE17,
- RSND_REG_SHARE18,
- RSND_REG_SHARE19,
- RSND_REG_SHARE20,
- RSND_REG_SHARE21,
- RSND_REG_SHARE22,
- RSND_REG_SHARE23,
- RSND_REG_SHARE24,
- RSND_REG_SHARE25,
- RSND_REG_SHARE26,
- RSND_REG_SHARE27,
- RSND_REG_SHARE28,
- RSND_REG_SHARE29,
-
RSND_REG_MAX,
};
-/* Gen1 only */
-#define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01
-#define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02
-#define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03
-#define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04
-#define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05
-#define RSND_REG_SRC_MNFSR RSND_REG_SHARE06
-#define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07
-#define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08
-#define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09
-
-/* Gen2 only */
-#define RSND_REG_SRC_CTRL RSND_REG_SHARE01
-#define RSND_REG_SSI_CTRL RSND_REG_SHARE02
-#define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03
-#define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04
-#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05
-#define RSND_REG_SRC_BSDSR RSND_REG_SHARE06
-#define RSND_REG_SRC_BSISR RSND_REG_SHARE07
-#define RSND_REG_DIV_EN RSND_REG_SHARE08
-#define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09
-#define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10
-#define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11
-#define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12
-#define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13
-#define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14
-#define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15
-#define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16
-#define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17
-#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
-#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
-#define RSND_REG_CMD_CTRL RSND_REG_SHARE20
-#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
-#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22
-#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23
-#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24
-#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25
-#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26
-#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27
-#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28
-#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29
-
-struct rsnd_of_data;
struct rsnd_priv;
struct rsnd_mod;
struct rsnd_dai;
@@ -187,43 +162,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
-void rsnd_path_parse(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io);
/*
* R-Car DMA
*/
-struct rsnd_dma;
-
-struct rsnd_dmaen {
- struct dma_chan *chan;
-};
-
-struct rsnd_dmapp {
- int dmapp_id;
- u32 chcr;
-};
-
-struct rsnd_dma {
- struct rsnd_dma_ops *ops;
- dma_addr_t src_addr;
- dma_addr_t dst_addr;
- union {
- struct rsnd_dmaen en;
- struct rsnd_dmapp pp;
- } dma;
-};
-#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
-#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
-#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
-
-void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id);
-void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-int rsnd_dma_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod, int id);
+int rsnd_dma_probe(struct rsnd_priv *priv);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name);
@@ -231,11 +176,19 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
* R-Car sound mod
*/
enum rsnd_mod_type {
- RSND_MOD_DVC = 0,
+ RSND_MOD_AUDMAPP,
+ RSND_MOD_AUDMA,
+ RSND_MOD_DVC,
RSND_MOD_MIX,
RSND_MOD_CTU,
+ RSND_MOD_CMD,
RSND_MOD_SRC,
+ RSND_MOD_SSIM3, /* SSI multi 3 */
+ RSND_MOD_SSIM2, /* SSI multi 2 */
+ RSND_MOD_SSIM1, /* SSI multi 1 */
+ RSND_MOD_SSIP, /* SSI parent */
RSND_MOD_SSI,
+ RSND_MOD_SSIU,
RSND_MOD_MAX,
};
@@ -278,10 +231,8 @@ struct rsnd_mod {
int id;
enum rsnd_mod_type type;
struct rsnd_mod_ops *ops;
- struct rsnd_dma dma;
struct rsnd_priv *priv;
struct clk *clk;
- u32 status;
};
/*
* status
@@ -328,7 +279,6 @@ struct rsnd_mod {
#define __rsnd_mod_call_hw_params 0
#define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_to_dma(mod) (&(mod)->dma)
#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
#define rsnd_mod_power_off(mod) clk_disable((mod)->clk)
@@ -347,6 +297,17 @@ 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));
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+ struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+ struct device_node *node,
+ struct device_node *playback,
+ struct device_node *capture);
+
+void rsnd_set_slot(struct rsnd_dai *rdai,
+ int slots, int slots_total);
+int rsnd_get_slot(struct rsnd_dai_stream *io);
+int rsnd_get_slot_width(struct rsnd_dai_stream *io);
+int rsnd_get_slot_num(struct rsnd_dai_stream *io);
/*
* R-Car sound DAI
@@ -358,6 +319,7 @@ struct rsnd_dai_stream {
struct rsnd_mod *mod[RSND_MOD_MAX];
struct rsnd_dai_path_info *info; /* rcar_snd.h */
struct rsnd_dai *rdai;
+ u32 mod_status[RSND_MOD_MAX];
int byte_pos;
int period_pos;
int byte_per_period;
@@ -365,10 +327,12 @@ struct rsnd_dai_stream {
};
#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_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP)
#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
+#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD)
#define rsnd_io_to_rdai(io) ((io)->rdai)
#define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io)
@@ -382,6 +346,9 @@ struct rsnd_dai {
struct rsnd_dai_stream capture;
struct rsnd_priv *priv;
+ int slots;
+ int slots_num;
+
unsigned int clk_master:1;
unsigned int bit_clk_inv:1;
unsigned int frm_clk_inv:1;
@@ -403,33 +370,28 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+int rsnd_dai_connect(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type);
+#define rsnd_dai_of_node(priv) \
+ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
/*
* R-Car Gen1/Gen2
*/
-int rsnd_gen_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
+int rsnd_gen_probe(struct rsnd_priv *priv);
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
enum rsnd_reg reg);
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
-#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
-#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
-
/*
* R-Car ADG
*/
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
-int rsnd_adg_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
-int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- unsigned int src_rate,
- unsigned int dst_rate);
+int rsnd_adg_probe(struct rsnd_priv *priv);
+void rsnd_adg_remove(struct rsnd_priv *priv);
int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
unsigned int src_rate,
@@ -442,15 +404,14 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
/*
* R-Car sound priv
*/
-struct rsnd_of_data {
- u32 flags;
-};
-
struct rsnd_priv {
struct platform_device *pdev;
- struct rcar_snd_info *info;
spinlock_t lock;
+ unsigned long flags;
+#define RSND_GEN_MASK (0xF << 0)
+#define RSND_GEN1 (1 << 0)
+#define RSND_GEN2 (2 << 0)
/*
* below value will be filled on rsnd_gen_probe()
@@ -474,6 +435,12 @@ struct rsnd_priv {
int ssi_nr;
/*
+ * below value will be filled on rsnd_ssiu_probe()
+ */
+ void *ssiu;
+ int ssiu_nr;
+
+ /*
* below value will be filled on rsnd_src_probe()
*/
void *src;
@@ -498,6 +465,12 @@ struct rsnd_priv {
int dvc_nr;
/*
+ * below value will be filled on rsnd_cmd_probe()
+ */
+ void *cmd;
+ int cmd_nr;
+
+ /*
* below value will be filled on rsnd_dai_probe()
*/
struct snd_soc_dai_driver *daidrv;
@@ -507,7 +480,9 @@ struct rsnd_priv {
#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
-#define rsnd_priv_to_info(priv) ((priv)->info)
+
+#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
+#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
/*
* rsnd_kctrl
@@ -523,7 +498,7 @@ struct rsnd_kctrl_cfg {
struct snd_kcontrol *kctrl;
};
-#define RSND_DVC_CHANNELS 2
+#define RSND_DVC_CHANNELS 8
struct rsnd_kctrl_cfg_m {
struct rsnd_kctrl_cfg cfg;
u32 val[RSND_DVC_CHANNELS];
@@ -544,6 +519,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_m *_cfg,
+ int ch_size,
u32 max);
int rsnd_kctrl_new_s(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
@@ -566,70 +542,93 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
/*
* R-Car SSI
*/
-int rsnd_ssi_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
+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);
+u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io);
#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);
+#define rsnd_ssi_of_node(priv) \
+ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+ struct device_node *playback,
+ struct device_node *capture);
+
+/*
+ * R-Car SSIU
+ */
+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);
+
/*
* R-Car SRC
*/
-int rsnd_src_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
-void rsnd_src_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
+int rsnd_src_probe(struct rsnd_priv *priv);
+void rsnd_src_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime);
-int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
- struct rsnd_dai_stream *io,
- int use_busif);
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
- struct rsnd_dai_stream *io);
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
+#define rsnd_src_of_node(priv) \
+ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
+#define rsnd_parse_connect_src(rdai, playback, capture) \
+ rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \
+ rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
+ playback, capture)
/*
* R-Car CTU
*/
-int rsnd_ctu_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
-
-void rsnd_ctu_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
+int rsnd_ctu_probe(struct rsnd_priv *priv);
+void rsnd_ctu_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_ctu_of_node(priv) \
+ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
+#define rsnd_parse_connect_ctu(rdai, playback, capture) \
+ rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \
+ rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
+ playback, capture)
/*
* R-Car MIX
*/
-int rsnd_mix_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
-
-void rsnd_mix_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
+int rsnd_mix_probe(struct rsnd_priv *priv);
+void rsnd_mix_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_mix_of_node(priv) \
+ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
+#define rsnd_parse_connect_mix(rdai, playback, capture) \
+ rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \
+ rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
+ playback, capture)
/*
* R-Car DVC
*/
-int rsnd_dvc_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv);
-void rsnd_dvc_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
+int rsnd_dvc_probe(struct rsnd_priv *priv);
+void rsnd_dvc_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_dvc_of_node(priv) \
+ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
+#define rsnd_parse_connect_dvc(rdai, playback, capture) \
+ rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \
+ rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
+ playback, capture)
+
+/*
+ * R-Car CMD
+ */
+int rsnd_cmd_probe(struct rsnd_priv *priv);
+void rsnd_cmd_remove(struct rsnd_priv *priv);
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id);
#ifdef DEBUG
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c
index d61db9c385ea..8a357fdf1077 100644
--- a/sound/soc/sh/rcar/rsrc-card.c
+++ b/sound/soc/sh/rcar/rsrc-card.c
@@ -48,8 +48,11 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
#define DAI_NAME_NUM 32
struct rsrc_card_dai {
- unsigned int fmt;
unsigned int sysclk;
+ unsigned int tx_slot_mask;
+ unsigned int rx_slot_mask;
+ int slots;
+ int slot_width;
struct clk *clk;
char dai_name[DAI_NAME_NUM];
};
@@ -75,7 +78,7 @@ static int rsrc_card_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct rsrc_card_dai *dai_props =
- rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
+ rsrc_priv_to_props(priv, rtd->num);
return clk_prepare_enable(dai_props->clk);
}
@@ -85,7 +88,7 @@ static void rsrc_card_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct rsrc_card_dai *dai_props =
- rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
+ rsrc_priv_to_props(priv, rtd->num);
clk_disable_unprepare(dai_props->clk);
}
@@ -101,7 +104,7 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
struct rsrc_card_dai *dai_props;
- int num = rtd - rtd->card->rtd;
+ int num = rtd->num;
int ret;
dai_link = rsrc_priv_to_link(priv, num);
@@ -110,18 +113,22 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
rtd->cpu_dai :
rtd->codec_dai;
- if (dai_props->fmt) {
- ret = snd_soc_dai_set_fmt(dai, dai_props->fmt);
+ if (dai_props->sysclk) {
+ ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
if (ret && ret != -ENOTSUPP) {
- dev_err(dai->dev, "set_fmt error\n");
+ dev_err(dai->dev, "set_sysclk error\n");
goto err;
}
}
- if (dai_props->sysclk) {
- ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
+ if (dai_props->slots) {
+ ret = snd_soc_dai_set_tdm_slot(dai,
+ dai_props->tx_slot_mask,
+ dai_props->rx_slot_mask,
+ dai_props->slots,
+ dai_props->slot_width);
if (ret && ret != -ENOTSUPP) {
- dev_err(dai->dev, "set_sysclk error\n");
+ dev_err(dai->dev, "set_tdm_slot error\n");
goto err;
}
}
@@ -148,14 +155,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
}
static int rsrc_card_parse_daifmt(struct device_node *node,
- struct device_node *np,
+ struct device_node *codec,
struct rsrc_card_priv *priv,
- int idx, bool is_fe)
+ struct snd_soc_dai_link *dai_link,
+ unsigned int *retfmt)
{
- struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
struct device_node *bitclkmaster = NULL;
struct device_node *framemaster = NULL;
- struct device_node *codec = is_fe ? NULL : np;
unsigned int daifmt;
daifmt = snd_soc_of_parse_daifmt(node, NULL,
@@ -172,11 +178,11 @@ static int rsrc_card_parse_daifmt(struct device_node *node,
daifmt |= (codec == framemaster) ?
SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
- dai_props->fmt = daifmt;
-
of_node_put(bitclkmaster);
of_node_put(framemaster);
+ *retfmt = daifmt;
+
return 0;
}
@@ -198,6 +204,15 @@ static int rsrc_card_parse_links(struct device_node *np,
if (ret)
return ret;
+ /* Parse TDM slot */
+ ret = snd_soc_of_parse_tdm_slot(np,
+ &dai_props->tx_slot_mask,
+ &dai_props->rx_slot_mask,
+ &dai_props->slots,
+ &dai_props->slot_width);
+ if (ret)
+ return ret;
+
if (is_fe) {
/* BE is dummy */
dai_link->codec_of_node = NULL;
@@ -208,7 +223,9 @@ static int rsrc_card_parse_links(struct device_node *np,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai_link->cpu_of_node = args.np;
- snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+ ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+ if (ret < 0)
+ return ret;
/* set dai_name */
snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s",
@@ -240,7 +257,9 @@ static int rsrc_card_parse_links(struct device_node *np,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup;
dai_link->codec_of_node = args.np;
- snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+ ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+ if (ret < 0)
+ return ret;
/* additional name prefix */
if (of_data) {
@@ -305,23 +324,16 @@ static int rsrc_card_parse_clk(struct device_node *np,
return 0;
}
-static int rsrc_card_dai_link_of(struct device_node *node,
- struct device_node *np,
- struct rsrc_card_priv *priv,
- int idx)
+static int rsrc_card_dai_sub_link_of(struct device_node *node,
+ struct device_node *np,
+ struct rsrc_card_priv *priv,
+ int idx, bool is_fe)
{
struct device *dev = rsrc_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
- bool is_fe = false;
int ret;
- if (0 == strcmp(np->name, "cpu"))
- is_fe = true;
-
- ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe);
- if (ret < 0)
- return ret;
-
ret = rsrc_card_parse_links(np, priv, idx, is_fe);
if (ret < 0)
return ret;
@@ -332,12 +344,54 @@ static int rsrc_card_dai_link_of(struct device_node *node,
dev_dbg(dev, "\t%s / %04x / %d\n",
dai_props->dai_name,
- dai_props->fmt,
+ dai_link->dai_fmt,
dai_props->sysclk);
return ret;
}
+static int rsrc_card_dai_link_of(struct device_node *node,
+ struct rsrc_card_priv *priv)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *np;
+ unsigned int daifmt = 0;
+ int ret, i;
+ bool is_fe;
+
+ /* find 1st codec */
+ i = 0;
+ for_each_child_of_node(node, np) {
+ dai_link = rsrc_priv_to_link(priv, i);
+
+ if (strcmp(np->name, "codec") == 0) {
+ ret = rsrc_card_parse_daifmt(node, np, priv,
+ dai_link, &daifmt);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+ i++;
+ }
+
+ i = 0;
+ for_each_child_of_node(node, np) {
+ dai_link = rsrc_priv_to_link(priv, i);
+ dai_link->dai_fmt = daifmt;
+
+ is_fe = false;
+ if (strcmp(np->name, "cpu") == 0)
+ is_fe = true;
+
+ ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
+
+ return 0;
+}
+
static int rsrc_card_parse_of(struct device_node *node,
struct rsrc_card_priv *priv,
struct device *dev)
@@ -345,9 +399,8 @@ static int rsrc_card_parse_of(struct device_node *node,
const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
struct rsrc_card_dai *props;
struct snd_soc_dai_link *links;
- struct device_node *np;
int ret;
- int i, num;
+ int num;
if (!node)
return -EINVAL;
@@ -388,13 +441,9 @@ static int rsrc_card_parse_of(struct device_node *node,
priv->snd_card.name ? priv->snd_card.name : "",
priv->convert_rate);
- i = 0;
- for_each_child_of_node(node, np) {
- ret = rsrc_card_dai_link_of(node, np, priv, i);
- if (ret < 0)
- return ret;
- i++;
- }
+ ret = rsrc_card_dai_link_of(node, priv);
+ if (ret < 0)
+ return ret;
if (!priv->snd_card.name)
priv->snd_card.name = priv->snd_card.dai_link->name;
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 68b439ed22d7..5eda056d9f20 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -20,20 +20,21 @@
#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id))
struct rsnd_src {
- struct rsnd_src_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
+ 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 err;
+ int irq;
};
#define RSND_SRC_NAME_SIZE 16
+#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
+#define rsnd_src_to_dma(src) ((src)->dma)
#define rsnd_src_nr(priv) ((priv)->src_nr)
#define rsnd_enable_sync_convert(src) ((src)->sen.val)
-#define rsnd_src_of_node(priv) \
- of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
#define rsnd_mod_to_src(_mod) \
container_of((_mod), struct rsnd_src, mod)
@@ -69,67 +70,16 @@ struct rsnd_src {
* |-----------------|
*/
-/*
- * How to use SRC bypass mode for debugging
- *
- * SRC has bypass mode, and it is useful for debugging.
- * In Gen2 case,
- * SRCm_MODE controls whether SRC is used or not
- * SSI_MODE0 controls whether SSIU which receives SRC data
- * is used or not.
- * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC,
- * but SRC bypass mode needs SSI_MODE0 only.
- *
- * This driver request
- * struct rsnd_src_platform_info {
- * u32 convert_rate;
- * int dma_id;
- * }
- *
- * rsnd_src_convert_rate() indicates
- * above convert_rate, and it controls
- * whether SRC is used or not.
- *
- * ex) doesn't use SRC
- * static struct rsnd_dai_platform_info rsnd_dai = {
- * .playback = { .ssi = &rsnd_ssi[0], },
- * };
- *
- * ex) uses SRC
- * static struct rsnd_src_platform_info rsnd_src[] = {
- * RSND_SCU(48000, 0),
- * ...
- * };
- * static struct rsnd_dai_platform_info rsnd_dai = {
- * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
- * };
- *
- * ex) uses SRC bypass mode
- * static struct rsnd_src_platform_info rsnd_src[] = {
- * RSND_SCU(0, 0),
- * ...
- * };
- * static struct rsnd_dai_platform_info rsnd_dai = {
- * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
- * };
- *
- */
-
-/*
- * Gen1/Gen2 common functions
- */
-static void rsnd_src_soft_reset(struct rsnd_mod *mod)
+static void rsnd_src_activation(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, SRC_SWRSR, 0);
rsnd_mod_write(mod, SRC_SWRSR, 1);
}
-
-#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1)
-#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0)
-static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_src_halt(struct rsnd_mod *mod)
{
- rsnd_mod_write(mod, SRC_SRCIR, enable);
+ rsnd_mod_write(mod, SRC_SRCIR, 1);
+ rsnd_mod_write(mod, SRC_SWRSR, 0);
}
static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
@@ -143,99 +93,6 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
is_play ? "rx" : "tx");
}
-int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
- struct rsnd_dai_stream *io,
- int use_busif)
-{
- struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- int ssi_id = rsnd_mod_id(ssi_mod);
-
- /*
- * SSI_MODE0
- */
- rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
- !use_busif << ssi_id);
-
- /*
- * SSI_MODE1
- */
- if (rsnd_ssi_is_pin_sharing(io)) {
- int shift = -1;
- switch (ssi_id) {
- case 1:
- shift = 0;
- break;
- case 2:
- shift = 2;
- break;
- case 4:
- shift = 16;
- break;
- }
-
- if (shift >= 0)
- rsnd_mod_bset(ssi_mod, SSI_MODE1,
- 0x3 << shift,
- rsnd_rdai_is_clk_master(rdai) ?
- 0x2 << shift : 0x1 << shift);
- }
-
- /*
- * DMA settings for SSIU
- */
- if (use_busif) {
- u32 val = rsnd_get_dalign(ssi_mod, io);
-
- rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
- rsnd_get_adinr_bit(ssi_mod, io));
- rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1);
- rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
-
- rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val);
- }
-
- return 0;
-}
-
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
- struct rsnd_dai_stream *io)
-{
- /*
- * DMA settings for SSIU
- */
- rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
-
- return 0;
-}
-
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
- if (rsnd_is_gen1(priv))
- return 0;
-
- /* enable SSI interrupt if Gen2 */
- rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
- rsnd_ssi_is_dma_mode(ssi_mod) ?
- 0x0e000000 : 0x0f000000);
-
- return 0;
-}
-
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
- if (rsnd_is_gen1(priv))
- return 0;
-
- /* disable SSI interrupt if Gen2 */
- rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
-
- return 0;
-}
-
static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_src *src)
{
@@ -283,34 +140,6 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
return rate;
}
-static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
-{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- u32 convert_rate = rsnd_src_convert_rate(io, src);
- u32 fsrate = 0;
-
- if (convert_rate)
- fsrate = 0x0400000 / convert_rate * runtime->rate;
-
- /* Set channel number and output bit length */
- rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io));
-
- /* Enable the initial value of IFS */
- if (fsrate) {
- rsnd_mod_write(mod, SRC_IFSCR, 1);
-
- /* Set initial value of IFS */
- rsnd_mod_write(mod, SRC_IFSVR, fsrate);
- }
-
- /* use DMA transfer */
- rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
-
- return 0;
-}
-
static int rsnd_src_hw_params(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_pcm_substream *substream,
@@ -319,9 +148,6 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod,
struct rsnd_src *src = rsnd_mod_to_src(mod);
struct snd_soc_pcm_runtime *fe = substream->private_data;
- /* default value (mainly for non-DT) */
- src->convert_rate = src->info->convert_rate;
-
/*
* SRC assumes that it is used under DPCM if user want to use
* sampling rate convert. Then, SRC should be FE.
@@ -347,250 +173,112 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_src_init(struct rsnd_mod *mod,
- struct rsnd_priv *priv)
-{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
-
- rsnd_mod_power_on(mod);
-
- rsnd_src_soft_reset(mod);
-
- rsnd_src_initialize_lock(mod);
-
- src->err = 0;
-
- /* reset sync convert_rate */
- src->sync.val = 0;
-
- return 0;
-}
-
-static int rsnd_src_quit(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 convert_rate = rsnd_src_convert_rate(io, src);
+ u32 ifscr, fsrate, adinr;
+ u32 cr, route;
+ u32 bsdsr, bsisr;
+ uint ratio;
- rsnd_mod_power_off(mod);
-
- if (src->err)
- dev_warn(dev, "%s[%d] under/over flow err = %d\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
-
- src->convert_rate = 0;
-
- /* reset sync convert_rate */
- src->sync.val = 0;
-
- return 0;
-}
-
-static int rsnd_src_start(struct rsnd_mod *mod)
-{
- rsnd_src_initialize_unlock(mod);
-
- return 0;
-}
-
-static int rsnd_src_stop(struct rsnd_mod *mod)
-{
- /* nothing to do */
- return 0;
-}
+ if (!runtime)
+ return;
-/*
- * Gen1 functions
- */
-static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod)
-{
- struct src_route_config {
- u32 mask;
- int shift;
- } routes[] = {
- { 0xF, 0, }, /* 0 */
- { 0xF, 4, }, /* 1 */
- { 0xF, 8, }, /* 2 */
- { 0x7, 12, }, /* 3 */
- { 0x7, 16, }, /* 4 */
- { 0x7, 20, }, /* 5 */
- { 0x7, 24, }, /* 6 */
- { 0x3, 28, }, /* 7 */
- { 0x3, 30, }, /* 8 */
- };
- u32 mask;
- u32 val;
- int id;
+ /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
+ if (!convert_rate)
+ ratio = 0;
+ else if (convert_rate > runtime->rate)
+ ratio = 100 * convert_rate / runtime->rate;
+ else
+ ratio = 100 * runtime->rate / convert_rate;
- id = rsnd_mod_id(mod);
- if (id < 0 || id >= ARRAY_SIZE(routes))
- return -EIO;
+ if (ratio > 600) {
+ dev_err(dev, "FSO/FSI ratio error\n");
+ return;
+ }
/*
- * SRC_ROUTE_SELECT
+ * SRC_ADINR
*/
- val = rsnd_io_is_play(io) ? 0x1 : 0x2;
- val = val << routes[id].shift;
- mask = routes[id].mask << routes[id].shift;
-
- rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
-
- return 0;
-}
-
-static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- u32 convert_rate = rsnd_src_convert_rate(io, src);
- u32 mask;
- u32 val;
- int shift;
- int id = rsnd_mod_id(mod);
- int ret;
+ adinr = rsnd_get_adinr_bit(mod, io) |
+ rsnd_get_adinr_chan(mod, io);
/*
- * SRC_TIMING_SELECT
+ * SRC_IFSCR / SRC_IFSVR
*/
- shift = (id % 4) * 8;
- mask = 0x1F << shift;
+ ifscr = 0;
+ fsrate = 0;
+ if (convert_rate) {
+ ifscr = 1;
+ fsrate = 0x0400000 / convert_rate * runtime->rate;
+ }
/*
- * ADG is used as source clock if SRC was used,
- * then, SSI WS is used as destination clock.
- * SSI WS is used as source clock if SRC is not used
- * (when playback, source/destination become reverse when capture)
+ * SRC_SRCCR / SRC_ROUTE_MODE0
*/
- ret = 0;
+ cr = 0x00011110;
+ route = 0x0;
if (convert_rate) {
- /* use ADG */
- val = 0;
- ret = rsnd_adg_set_convert_clk_gen1(priv, mod,
- runtime->rate,
- convert_rate);
- } else if (8 == id) {
- /* use SSI WS, but SRU8 is special */
- val = id << shift;
- } else {
- /* use SSI WS */
- val = (id + 1) << shift;
- }
+ route = 0x1;
- if (ret < 0)
- return ret;
+ if (rsnd_enable_sync_convert(src)) {
+ cr |= 0x1;
+ route |= rsnd_io_is_play(io) ?
+ (0x1 << 24) : (0x1 << 25);
+ }
+ }
- switch (id / 4) {
- case 0:
- rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
- break;
- case 1:
- rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
+ /*
+ * SRC_BSDSR / SRC_BSISR
+ */
+ switch (rsnd_mod_id(mod)) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ bsdsr = 0x02400000; /* 6 - 1/6 */
+ bsisr = 0x00100060; /* 6 - 1/6 */
break;
- case 2:
- rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
+ default:
+ bsdsr = 0x01800000; /* 6 - 1/6 */
+ bsisr = 0x00100060 ;/* 6 - 1/6 */
break;
}
- return 0;
-}
-
-static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- int ret;
-
- ret = rsnd_src_set_convert_rate(mod, io);
- if (ret < 0)
- return ret;
-
- /* Select SRC mode (fixed value) */
- rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
-
- /* Set the restriction value of the FS ratio (98%) */
- rsnd_mod_write(mod, SRC_MNFSR,
- rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
-
- /* Gen1/Gen2 are not compatible */
- if (rsnd_src_convert_rate(io, src))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
-
- /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
-
- return 0;
-}
-
-static int rsnd_src_init_gen1(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- int ret;
-
- ret = rsnd_src_init(mod, priv);
- if (ret < 0)
- return ret;
-
- ret = rsnd_src_set_route_gen1(io, mod);
- if (ret < 0)
- return ret;
-
- ret = rsnd_src_set_convert_rate_gen1(mod, io);
- if (ret < 0)
- return ret;
-
- ret = rsnd_src_set_convert_timing_gen1(io, mod);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int rsnd_src_start_gen1(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- int id = rsnd_mod_id(mod);
-
- rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
-
- return rsnd_src_start(mod);
-}
-
-static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- int id = rsnd_mod_id(mod);
+ rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */
+ rsnd_mod_write(mod, SRC_ADINR, adinr);
+ rsnd_mod_write(mod, SRC_IFSCR, ifscr);
+ rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+ rsnd_mod_write(mod, SRC_SRCCR, cr);
+ rsnd_mod_write(mod, SRC_BSDSR, bsdsr);
+ rsnd_mod_write(mod, SRC_BSISR, bsisr);
+ rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */
- rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+ rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1);
+ rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
+ rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
- return rsnd_src_stop(mod);
+ if (convert_rate)
+ rsnd_adg_set_convert_clk_gen2(mod, io,
+ runtime->rate,
+ convert_rate);
+ else
+ rsnd_adg_set_convert_timing_gen2(mod, io);
}
-static struct rsnd_mod_ops rsnd_src_gen1_ops = {
- .name = SRC_NAME,
- .dma_req = rsnd_src_dma_req,
- .init = rsnd_src_init_gen1,
- .quit = rsnd_src_quit,
- .start = rsnd_src_start_gen1,
- .stop = rsnd_src_stop_gen1,
- .hw_params = rsnd_src_hw_params,
-};
-
-/*
- * Gen2 functions
- */
-#define rsnd_src_irq_enable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 1)
-#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0)
-static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
+#define rsnd_src_irq_enable(mod) rsnd_src_irq_ctrol(mod, 1)
+#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0)
+static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 sys_int_val, int_val, sys_int_mask;
- int irq = src->info->irq;
+ int irq = src->irq;
int id = rsnd_mod_id(mod);
sys_int_val =
@@ -600,7 +288,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
/*
* IRQ is not supported on non-DT
* see
- * rsnd_src_probe_gen2()
+ * rsnd_src_probe_()
*/
if ((irq <= 0) || !enable) {
sys_int_val = 0;
@@ -620,7 +308,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
}
-static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
+static void rsnd_src_status_clear(struct rsnd_mod *mod)
{
u32 val = OUF_SRC(rsnd_mod_id(mod));
@@ -628,7 +316,7 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
}
-static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
+static bool rsnd_src_record_error(struct rsnd_mod *mod)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 val0, val1;
@@ -652,22 +340,16 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
ret = true;
}
- /* clear error static */
- rsnd_src_error_clear_gen2(mod);
-
return ret;
}
-static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+static int rsnd_src_start(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 val;
- val = rsnd_get_dalign(mod, io);
-
- rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val);
-
/*
* WORKAROUND
*
@@ -678,247 +360,149 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_CTRL, val);
- rsnd_src_error_clear_gen2(mod);
-
- rsnd_src_start(mod);
+ return 0;
+}
- rsnd_src_irq_enable_gen2(mod);
+static int rsnd_src_stop(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ /*
+ * stop SRC output only
+ * see rsnd_src_quit
+ */
+ rsnd_mod_write(mod, SRC_CTRL, 0x01);
return 0;
}
-static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
+static int rsnd_src_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
- rsnd_src_irq_disable_gen2(mod);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
- rsnd_mod_write(mod, SRC_CTRL, 0);
+ rsnd_mod_power_on(mod);
+
+ rsnd_src_activation(mod);
+
+ rsnd_src_set_convert_rate(io, mod);
- rsnd_src_error_record_gen2(mod);
+ rsnd_src_status_clear(mod);
+
+ rsnd_src_irq_enable(mod);
+
+ src->err = 0;
- return rsnd_src_stop(mod);
+ /* reset sync convert_rate */
+ src->sync.val = 0;
+
+ return 0;
}
-static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+static int rsnd_src_quit(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-
- spin_lock(&priv->lock);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
- /* ignore all cases if not working */
- if (!rsnd_io_is_working(io))
- goto rsnd_src_interrupt_gen2_out;
+ rsnd_src_irq_disable(mod);
- if (rsnd_src_error_record_gen2(mod)) {
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
+ /* stop both out/in */
+ rsnd_mod_write(mod, SRC_CTRL, 0);
- dev_dbg(dev, "%s[%d] restart\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ rsnd_src_halt(mod);
- _rsnd_src_stop_gen2(mod);
- if (src->err < 1024)
- _rsnd_src_start_gen2(mod, io);
- else
- dev_warn(dev, "no more SRC restart\n");
- }
+ rsnd_mod_power_off(mod);
-rsnd_src_interrupt_gen2_out:
- spin_unlock(&priv->lock);
-}
+ if (src->err)
+ dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
-static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
-{
- struct rsnd_mod *mod = data;
+ src->convert_rate = 0;
- rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2);
+ /* reset sync convert_rate */
+ src->sync.val = 0;
- return IRQ_HANDLED;
+ return 0;
}
-static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+static void __rsnd_src_interrupt(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
- u32 convert_rate = rsnd_src_convert_rate(io, src);
- u32 cr, route;
- uint ratio;
- int ret;
+ struct device *dev = rsnd_priv_to_dev(priv);
- /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
- if (!convert_rate)
- ratio = 0;
- else if (convert_rate > runtime->rate)
- ratio = 100 * convert_rate / runtime->rate;
- else
- ratio = 100 * runtime->rate / convert_rate;
+ spin_lock(&priv->lock);
- if (ratio > 600) {
- dev_err(dev, "FSO/FSI ratio error\n");
- return -EINVAL;
- }
+ /* ignore all cases if not working */
+ if (!rsnd_io_is_working(io))
+ goto rsnd_src_interrupt_out;
- ret = rsnd_src_set_convert_rate(mod, io);
- if (ret < 0)
- return ret;
+ if (rsnd_src_record_error(mod)) {
- cr = 0x00011110;
- route = 0x0;
- if (convert_rate) {
- route = 0x1;
+ dev_dbg(dev, "%s[%d] restart\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
- if (rsnd_enable_sync_convert(src)) {
- cr |= 0x1;
- route |= rsnd_io_is_play(io) ?
- (0x1 << 24) : (0x1 << 25);
- }
+ rsnd_src_stop(mod, io, priv);
+ rsnd_src_start(mod, io, priv);
}
- rsnd_mod_write(mod, SRC_SRCCR, cr);
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+ if (src->err > 1024) {
+ rsnd_src_irq_disable(mod);
- switch (rsnd_mod_id(mod)) {
- case 5:
- case 6:
- case 7:
- case 8:
- rsnd_mod_write(mod, SRC_BSDSR, 0x02400000);
- break;
- default:
- rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
- break;
+ dev_warn(dev, "no more %s[%d] restart\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
}
- rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
+ rsnd_src_status_clear(mod);
+rsnd_src_interrupt_out:
- return 0;
+ spin_unlock(&priv->lock);
}
-static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod)
+static irqreturn_t rsnd_src_interrupt(int irq, void *data)
{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- u32 convert_rate = rsnd_src_convert_rate(io, src);
- int ret;
+ struct rsnd_mod *mod = data;
- if (convert_rate)
- ret = rsnd_adg_set_convert_clk_gen2(mod, io,
- runtime->rate,
- convert_rate);
- else
- ret = rsnd_adg_set_convert_timing_gen2(mod, io);
+ rsnd_mod_interrupt(mod, __rsnd_src_interrupt);
- return ret;
+ return IRQ_HANDLED;
}
-static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static int rsnd_src_probe_(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- int irq = src->info->irq;
+ int irq = src->irq;
int ret;
if (irq > 0) {
/*
* IRQ is not supported on non-DT
* see
- * rsnd_src_irq_enable_gen2()
+ * rsnd_src_irq_enable()
*/
ret = devm_request_irq(dev, irq,
- rsnd_src_interrupt_gen2,
+ rsnd_src_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
if (ret)
return ret;
}
- ret = rsnd_dma_init(io,
- rsnd_mod_to_dma(mod),
- src->info->dma_id);
+ src->dma = rsnd_dma_attach(io, mod, 0);
+ if (IS_ERR(src->dma))
+ return PTR_ERR(src->dma);
return ret;
}
-static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
-
- return 0;
-}
-
-static int rsnd_src_init_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- int ret;
-
- ret = rsnd_src_init(mod, priv);
- if (ret < 0)
- return ret;
-
- ret = rsnd_src_set_convert_rate_gen2(mod, io);
- if (ret < 0)
- return ret;
-
- ret = rsnd_src_set_convert_timing_gen2(io, mod);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int rsnd_src_start_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- rsnd_dma_start(io, rsnd_mod_to_dma(mod));
-
- return _rsnd_src_start_gen2(mod, io);
-}
-
-static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- int ret;
-
- ret = _rsnd_src_stop_gen2(mod);
-
- rsnd_dma_stop(io, rsnd_mod_to_dma(mod));
-
- return ret;
-}
-
-static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod)
-{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- u32 convert_rate = rsnd_src_convert_rate(io, src);
- u32 fsrate;
-
- if (!runtime)
- return;
-
- if (!convert_rate)
- convert_rate = runtime->rate;
-
- fsrate = 0x0400000 / convert_rate * runtime->rate;
-
- /* update IFS */
- rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-}
-
-static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
+static int rsnd_src_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd)
{
@@ -950,7 +534,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
rsnd_io_is_play(io) ?
"SRC Out Rate Switch" :
"SRC In Rate Switch",
- rsnd_src_reconvert_update,
+ rsnd_src_set_convert_rate,
&src->sen, 1);
if (ret < 0)
return ret;
@@ -959,23 +543,22 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
rsnd_io_is_play(io) ?
"SRC Out Rate" :
"SRC In Rate",
- rsnd_src_reconvert_update,
+ rsnd_src_set_convert_rate,
&src->sync, 192000);
return ret;
}
-static struct rsnd_mod_ops rsnd_src_gen2_ops = {
+static struct rsnd_mod_ops rsnd_src_ops = {
.name = SRC_NAME,
.dma_req = rsnd_src_dma_req,
- .probe = rsnd_src_probe_gen2,
- .remove = rsnd_src_remove_gen2,
- .init = rsnd_src_init_gen2,
+ .probe = rsnd_src_probe_,
+ .init = rsnd_src_init,
.quit = rsnd_src_quit,
- .start = rsnd_src_start_gen2,
- .stop = rsnd_src_stop_gen2,
+ .start = rsnd_src_start,
+ .stop = rsnd_src_stop,
.hw_params = rsnd_src_hw_params,
- .pcm_new = rsnd_src_pcm_new_gen2,
+ .pcm_new = rsnd_src_pcm_new,
};
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -983,113 +566,78 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
id = 0;
- return rsnd_mod_get((struct rsnd_src *)(priv->src) + id);
+ return rsnd_mod_get(rsnd_src_get(priv, id));
}
-static void rsnd_of_parse_src(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_src_probe(struct rsnd_priv *priv)
{
- struct device_node *src_node;
+ struct device_node *node;
struct device_node *np;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct rsnd_src_platform_info *src_info;
- struct device *dev = &pdev->dev;
- int nr, i;
-
- if (!of_data)
- return;
-
- src_node = rsnd_src_of_node(priv);
- if (!src_node)
- return;
-
- nr = of_get_child_count(src_node);
- if (!nr)
- goto rsnd_of_parse_src_end;
-
- src_info = devm_kzalloc(dev,
- sizeof(struct rsnd_src_platform_info) * nr,
- GFP_KERNEL);
- if (!src_info) {
- dev_err(dev, "src info allocation error\n");
- goto rsnd_of_parse_src_end;
- }
-
- info->src_info = src_info;
- info->src_info_nr = nr;
-
- i = 0;
- for_each_child_of_node(src_node, np) {
- src_info[i].irq = irq_of_parse_and_map(np, 0);
-
- i++;
- }
-
-rsnd_of_parse_src_end:
- of_node_put(src_node);
-}
-
-int rsnd_src_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_src *src;
- struct rsnd_mod_ops *ops;
struct clk *clk;
char name[RSND_SRC_NAME_SIZE];
int i, nr, ret;
- ops = NULL;
- if (rsnd_is_gen1(priv)) {
- ops = &rsnd_src_gen1_ops;
- dev_warn(dev, "Gen1 support will be removed soon\n");
- }
- if (rsnd_is_gen2(priv))
- ops = &rsnd_src_gen2_ops;
- if (!ops) {
- dev_err(dev, "unknown Generation\n");
- return -EIO;
- }
+ /* This driver doesn't support Gen1 at this point */
+ if (rsnd_is_gen1(priv))
+ return 0;
- rsnd_of_parse_src(pdev, of_data, priv);
+ node = rsnd_src_of_node(priv);
+ if (!node)
+ return 0; /* not used is not error */
- /*
- * init SRC
- */
- nr = info->src_info_nr;
- if (!nr)
- return 0;
+ nr = of_get_child_count(node);
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_src_probe_done;
+ }
src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
- if (!src)
- return -ENOMEM;
+ if (!src) {
+ ret = -ENOMEM;
+ goto rsnd_src_probe_done;
+ }
priv->src_nr = nr;
priv->src = src;
- for_each_rsnd_src(src, priv, i) {
+ i = 0;
+ for_each_child_of_node(node, np) {
+ src = rsnd_src_get(priv, i);
+
snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
SRC_NAME, i);
- clk = devm_clk_get(dev, name);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ src->irq = irq_of_parse_and_map(np, 0);
+ if (!src->irq) {
+ ret = -EINVAL;
+ goto rsnd_src_probe_done;
+ }
- src->info = &info->src_info[i];
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto rsnd_src_probe_done;
+ }
- ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i);
+ ret = rsnd_mod_init(priv, rsnd_mod_get(src),
+ &rsnd_src_ops, clk, RSND_MOD_SRC, i);
if (ret)
- return ret;
+ goto rsnd_src_probe_done;
+
+ i++;
}
- return 0;
+ ret = 0;
+
+rsnd_src_probe_done:
+ of_node_put(node);
+
+ return ret;
}
-void rsnd_src_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
+void rsnd_src_remove(struct rsnd_priv *priv)
{
struct rsnd_src *src;
int i;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 1427ec21bd7e..7ee89da4dd5f 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -24,7 +24,9 @@
#define OIEN (1 << 26) /* Overflow Interrupt Enable */
#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */
#define DIEN (1 << 24) /* Data Interrupt Enable */
-
+#define CHNL_4 (1 << 22) /* Channels */
+#define CHNL_6 (2 << 22) /* Channels */
+#define CHNL_8 (3 << 22) /* Channels */
#define DWL_8 (0 << 19) /* Data Word Length */
#define DWL_16 (1 << 19) /* Data Word Length */
#define DWL_18 (2 << 19) /* Data Word Length */
@@ -39,6 +41,7 @@
#define SCKP (1 << 13) /* Serial Bit Clock Polarity */
#define SWSP (1 << 12) /* Serial WS Polarity */
#define SDTA (1 << 10) /* Serial Data Alignment */
+#define PDTA (1 << 9) /* Parallel Data Alignment */
#define DEL (1 << 8) /* Serial Data Delay */
#define CKDV(v) (v << 4) /* Serial Clock Division Ratio */
#define TRMD (1 << 1) /* Transmit/Receive Mode Select */
@@ -56,35 +59,44 @@
* SSIWSR
*/
#define CONT (1 << 8) /* WS Continue Function */
+#define WS_MODE (1 << 0) /* WS Mode */
#define SSI_NAME "ssi"
struct rsnd_ssi {
- struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
struct rsnd_ssi *parent;
struct rsnd_mod mod;
+ struct rsnd_mod *dma;
+ u32 flags;
u32 cr_own;
u32 cr_clk;
+ u32 cr_mode;
+ u32 wsr;
int chan;
+ int rate;
int err;
+ int irq;
unsigned int usrcnt;
};
+/* flags */
+#define RSND_SSI_CLK_PIN_SHARE (1 << 0)
+#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
+
#define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \
(i < rsnd_ssi_nr(priv)) && \
((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \
i++)
+#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
+#define rsnd_ssi_to_dma(mod) ((ssi)->dma)
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
-#define rsnd_ssi_parent(ssi) ((ssi)->parent)
-#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
-#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
-#define rsnd_ssi_of_node(priv) \
- of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+#define rsnd_ssi_mode_flags(p) ((p)->flags)
+#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
+#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io))
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
{
@@ -103,6 +115,16 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
return use_busif;
}
+static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
+{
+ rsnd_mod_write(mod, SSISR, 0);
+}
+
+static u32 rsnd_ssi_status_get(struct rsnd_mod *mod)
+{
+ return rsnd_mod_read(mod, SSISR);
+}
+
static void rsnd_ssi_status_check(struct rsnd_mod *mod,
u32 bit)
{
@@ -112,7 +134,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
int i;
for (i = 0; i < 1024; i++) {
- status = rsnd_mod_read(mod, SSISR);
+ status = rsnd_ssi_status_get(mod);
if (status & bit)
return;
@@ -122,13 +144,79 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
dev_warn(dev, "status check failed\n");
}
+static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ /* enable SSI interrupt if Gen2 */
+ rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
+ rsnd_ssi_is_dma_mode(ssi_mod) ?
+ 0x0e000000 : 0x0f000000);
+
+ return 0;
+}
+
+static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ /* disable SSI interrupt if Gen2 */
+ rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
+
+ return 0;
+}
+
+u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
+{
+ struct rsnd_mod *mod;
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ enum rsnd_mod_type types[] = {
+ RSND_MOD_SSIM1,
+ RSND_MOD_SSIM2,
+ RSND_MOD_SSIM3,
+ };
+ int i, mask;
+
+ switch (runtime->channels) {
+ case 2: /* Multi channel is not needed for Stereo */
+ return 0;
+ case 6:
+ break;
+ default:
+ dev_err(dev, "unsupported channel\n");
+ return 0;
+ }
+
+ mask = 0;
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ mod = rsnd_io_to_mod(io, types[i]);
+ if (!mod)
+ continue;
+
+ mask |= 1 << rsnd_mod_id(mod);
+ }
+
+ return mask;
+}
+
static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
struct rsnd_mod *mod = rsnd_mod_get(ssi);
+ struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+ int slots = rsnd_get_slot_width(io);
int j, ret;
int ssi_clk_mul_table[] = {
1, 2, 4, 8, 16, 6, 12,
@@ -136,6 +224,24 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
unsigned int main_rate;
unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);
+ if (!rsnd_rdai_is_clk_master(rdai))
+ return 0;
+
+ if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+ return 0;
+
+ if (rsnd_ssi_is_multi_slave(mod, io))
+ return 0;
+
+ if (ssi->usrcnt > 1) {
+ if (ssi->rate != rate) {
+ dev_err(dev, "SSI parent/child should use same rate\n");
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
/*
* Find best clock, and try to start ADG
*/
@@ -143,15 +249,18 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
/*
* this driver is assuming that
- * system word is 64fs (= 2 x 32bit)
+ * system word is 32bit x slots
* see rsnd_ssi_init()
*/
- main_rate = rate * 32 * 2 * ssi_clk_mul_table[j];
+ main_rate = rate * 32 * slots * ssi_clk_mul_table[j];
ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
if (0 == ret) {
ssi->cr_clk = FORCE | SWL_32 |
SCKD | SWSD | CKDV(j);
+ ssi->wsr = CONT;
+
+ ssi->rate = rate;
dev_dbg(dev, "%s[%d] outputs %u Hz\n",
rsnd_mod_name(mod),
@@ -165,113 +274,91 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
return -EIO;
}
-static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
+static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi,
+ struct rsnd_dai_stream *io)
{
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
struct rsnd_mod *mod = rsnd_mod_get(ssi);
+ struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+
+ if (!rsnd_rdai_is_clk_master(rdai))
+ return;
+
+ if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+ return;
+
+ if (ssi->usrcnt > 1)
+ return;
+
+ ssi->cr_clk = 0;
+ ssi->rate = 0;
- ssi->cr_clk = 0;
rsnd_adg_ssi_clk_stop(mod);
}
-static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
- struct rsnd_dai_stream *io)
+static int rsnd_ssi_config_init(struct rsnd_ssi *ssi,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_mod *mod = rsnd_mod_get(ssi);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ u32 cr_own;
u32 cr_mode;
- u32 cr;
+ u32 wsr;
+ int is_tdm;
- if (0 == ssi->usrcnt) {
- rsnd_mod_power_on(mod);
+ is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0;
- if (rsnd_rdai_is_clk_master(rdai)) {
- struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+ /*
+ * always use 32bit system word.
+ * see also rsnd_ssi_master_clk_enable()
+ */
+ cr_own = FORCE | SWL_32 | PDTA;
- if (ssi_parent)
- rsnd_ssi_hw_start(ssi_parent, io);
- else
- rsnd_ssi_master_clk_start(ssi, io);
- }
+ if (rdai->bit_clk_inv)
+ cr_own |= SCKP;
+ if (rdai->frm_clk_inv ^ is_tdm)
+ cr_own |= SWSP;
+ if (rdai->data_alignment)
+ cr_own |= SDTA;
+ if (rdai->sys_delay)
+ cr_own |= DEL;
+ if (rsnd_io_is_play(io))
+ cr_own |= TRMD;
+
+ switch (runtime->sample_bits) {
+ case 16:
+ cr_own |= DWL_16;
+ break;
+ case 32:
+ cr_own |= DWL_24;
+ break;
+ default:
+ return -EINVAL;
}
- if (rsnd_ssi_is_dma_mode(mod)) {
+ if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) {
cr_mode = UIEN | OIEN | /* over/under run */
DMEN; /* DMA : enable DMA */
} else {
cr_mode = DIEN; /* PIO : enable Data interrupt */
}
- cr = ssi->cr_own |
- ssi->cr_clk |
- cr_mode |
- EN;
-
- rsnd_mod_write(mod, SSICR, cr);
-
- /* enable WS continue */
- if (rsnd_rdai_is_clk_master(rdai))
- rsnd_mod_write(mod, SSIWSR, CONT);
-
- /* clear error status */
- rsnd_mod_write(mod, SSISR, 0);
-
- ssi->usrcnt++;
-
- dev_dbg(dev, "%s[%d] hw started\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
-}
-
-static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
-{
- struct rsnd_mod *mod = rsnd_mod_get(ssi);
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- struct device *dev = rsnd_priv_to_dev(priv);
- u32 cr;
-
- if (0 == ssi->usrcnt) {
- dev_err(dev, "%s called without starting\n", __func__);
- return;
+ /*
+ * TDM Extend Mode
+ * see
+ * rsnd_ssiu_init_gen2()
+ */
+ wsr = ssi->wsr;
+ if (is_tdm) {
+ wsr |= WS_MODE;
+ cr_own |= CHNL_8;
}
- ssi->usrcnt--;
-
- if (0 == ssi->usrcnt) {
- /*
- * disable all IRQ,
- * and, wait all data was sent
- */
- cr = ssi->cr_own |
- ssi->cr_clk;
-
- rsnd_mod_write(mod, SSICR, cr | EN);
- rsnd_ssi_status_check(mod, DIRQ);
+ ssi->cr_own = cr_own;
+ ssi->cr_mode = cr_mode;
+ ssi->wsr = wsr;
- /*
- * disable SSI,
- * and, wait idle state
- */
- rsnd_mod_write(mod, SSICR, cr); /* disabled all */
- rsnd_ssi_status_check(mod, IIRQ);
-
- if (rsnd_rdai_is_clk_master(rdai)) {
- struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
-
- if (ssi_parent)
- rsnd_ssi_hw_stop(io, ssi_parent);
- else
- rsnd_ssi_master_clk_stop(ssi);
- }
-
- rsnd_mod_power_off(mod);
-
- ssi->chan = 0;
- }
-
- dev_dbg(dev, "%s[%d] hw stopped\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ return 0;
}
/*
@@ -282,49 +369,30 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- u32 cr;
+ int ret;
+
+ ssi->usrcnt++;
- cr = FORCE;
+ rsnd_mod_power_on(mod);
- /*
- * always use 32bit system word for easy clock calculation.
- * see also rsnd_ssi_master_clk_enable()
- */
- cr |= SWL_32;
+ ret = rsnd_ssi_master_clk_start(ssi, io);
+ if (ret < 0)
+ return ret;
- /*
- * init clock settings for SSICR
- */
- switch (runtime->sample_bits) {
- case 16:
- cr |= DWL_16;
- break;
- case 32:
- cr |= DWL_24;
- break;
- default:
- return -EIO;
- }
+ if (rsnd_ssi_is_parent(mod, io))
+ return 0;
- if (rdai->bit_clk_inv)
- cr |= SCKP;
- if (rdai->frm_clk_inv)
- cr |= SWSP;
- if (rdai->data_alignment)
- cr |= SDTA;
- if (rdai->sys_delay)
- cr |= DEL;
- if (rsnd_io_is_play(io))
- cr |= TRMD;
+ ret = rsnd_ssi_config_init(ssi, io);
+ if (ret < 0)
+ return ret;
- /*
- * set ssi parameter
- */
- ssi->cr_own = cr;
ssi->err = -1; /* ignore 1st error */
+ /* clear error status */
+ rsnd_ssi_status_clear(mod);
+
+ rsnd_ssi_irq_enable(mod);
+
return 0;
}
@@ -335,12 +403,29 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- if (ssi->err > 0)
- dev_warn(dev, "%s[%d] under/over flow err = %d\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
+ if (!ssi->usrcnt) {
+ dev_err(dev, "%s[%d] usrcnt error\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
+ return -EIO;
+ }
+
+ if (!rsnd_ssi_is_parent(mod, io)) {
+ if (ssi->err > 0)
+ dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
+ ssi->err);
+
+ ssi->cr_own = 0;
+ ssi->err = 0;
+
+ rsnd_ssi_irq_disable(mod);
+ }
- ssi->cr_own = 0;
- ssi->err = 0;
+ rsnd_ssi_master_clk_stop(ssi, io);
+
+ rsnd_mod_power_off(mod);
+
+ ssi->usrcnt--;
return 0;
}
@@ -351,14 +436,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
struct snd_pcm_hw_params *params)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
int chan = params_channels(params);
/*
* Already working.
* It will happen if SSI has parent/child connection.
*/
- if (ssi->usrcnt) {
+ if (ssi->usrcnt > 1) {
/*
* it is error if child <-> parent SSI uses
* different channels.
@@ -367,39 +451,83 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
return -EIO;
}
- /* It will be removed on rsnd_ssi_hw_stop */
ssi->chan = chan;
- if (ssi_parent)
- return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io,
- substream, params);
return 0;
}
-static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
+static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi)
{
struct rsnd_mod *mod = rsnd_mod_get(ssi);
+ u32 status = rsnd_ssi_status_get(mod);
/* under/over flow error */
- if (status & (UIRQ | OIRQ)) {
+ if (status & (UIRQ | OIRQ))
ssi->err++;
- /* clear error status */
- rsnd_mod_write(mod, SSISR, 0);
- }
+ return status;
+}
+
+static int __rsnd_ssi_start(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ u32 cr;
+
+ cr = ssi->cr_own |
+ ssi->cr_clk |
+ ssi->cr_mode;
+
+ /*
+ * EN will be set via SSIU :: SSI_CONTROL
+ * if Multi channel mode
+ */
+ if (!rsnd_ssi_multi_slaves(io))
+ cr |= EN;
+
+ rsnd_mod_write(mod, SSICR, cr);
+ rsnd_mod_write(mod, SSIWSR, ssi->wsr);
+
+ return 0;
}
static int rsnd_ssi_start(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ /*
+ * no limit to start
+ * see also
+ * rsnd_ssi_stop
+ * rsnd_ssi_interrupt
+ */
+ return __rsnd_ssi_start(mod, io, priv);
+}
+
+static int __rsnd_ssi_stop(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ u32 cr;
- rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io));
+ /*
+ * disable all IRQ,
+ * and, wait all data was sent
+ */
+ cr = ssi->cr_own |
+ ssi->cr_clk;
- rsnd_ssi_hw_start(ssi, io);
+ rsnd_mod_write(mod, SSICR, cr | EN);
+ rsnd_ssi_status_check(mod, DIRQ);
- rsnd_src_ssi_irq_enable(mod);
+ /*
+ * disable SSI,
+ * and, wait idle state
+ */
+ rsnd_mod_write(mod, SSICR, cr); /* disabled all */
+ rsnd_ssi_status_check(mod, IIRQ);
return 0;
}
@@ -410,15 +538,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- rsnd_src_ssi_irq_disable(mod);
-
- rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
-
- rsnd_ssi_hw_stop(io, ssi);
-
- rsnd_src_ssiu_stop(mod, io);
+ /*
+ * don't stop if not last user
+ * see also
+ * rsnd_ssi_start
+ * rsnd_ssi_interrupt
+ */
+ if (ssi->usrcnt > 1)
+ return 0;
- return 0;
+ return __rsnd_ssi_stop(mod, io, priv);
}
static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
@@ -426,6 +555,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
int is_dma = rsnd_ssi_is_dma_mode(mod);
u32 status;
bool elapsed = false;
@@ -436,7 +566,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
if (!rsnd_io_is_working(io))
goto rsnd_ssi_interrupt_out;
- status = rsnd_mod_read(mod, SSISR);
+ status = rsnd_ssi_record_error(ssi);
/* PIO only */
if (!is_dma && (status & DIRQ)) {
@@ -459,23 +589,24 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
/* DMA only */
if (is_dma && (status & (UIRQ | OIRQ))) {
- struct device *dev = rsnd_priv_to_dev(priv);
-
/*
* restart SSI
*/
dev_dbg(dev, "%s[%d] restart\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
- rsnd_ssi_stop(mod, io, priv);
- if (ssi->err < 1024)
- rsnd_ssi_start(mod, io, priv);
- else
- dev_warn(dev, "no more SSI restart\n");
+ __rsnd_ssi_stop(mod, io, priv);
+ __rsnd_ssi_start(mod, io, priv);
}
- rsnd_ssi_record_error(ssi, status);
+ if (ssi->err > 1024) {
+ rsnd_ssi_irq_disable(mod);
+ dev_warn(dev, "no more %s[%d] restart\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
+ }
+
+ rsnd_ssi_status_clear(mod);
rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock);
@@ -495,15 +626,49 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
/*
* SSI PIO
*/
-static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ if (!__rsnd_ssi_is_pin_sharing(mod))
+ return;
+
+ switch (rsnd_mod_id(mod)) {
+ case 1:
+ case 2:
+ rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
+ break;
+ case 4:
+ rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
+ break;
+ case 8:
+ rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
+ break;
+ }
+}
+
+static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int ret;
- ret = devm_request_irq(dev, ssi->info->irq,
+ /*
+ * SSIP/SSIU/IRQ are not needed on
+ * SSI Multi slaves
+ */
+ if (rsnd_ssi_is_multi_slave(mod, io))
+ return 0;
+
+ rsnd_ssi_parent_attach(mod, io, priv);
+
+ ret = rsnd_ssiu_attach(io, mod);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_request_irq(dev, ssi->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
@@ -513,7 +678,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = SSI_NAME,
- .probe = rsnd_ssi_pio_probe,
+ .probe = rsnd_ssi_common_probe,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_start,
@@ -526,20 +691,23 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- int dma_id = ssi->info->dma_id;
+ int dma_id = 0; /* not needed */
int ret;
- ret = devm_request_irq(dev, ssi->info->irq,
- rsnd_ssi_interrupt,
- IRQF_SHARED,
- dev_name(dev), mod);
+ /*
+ * SSIP/SSIU/IRQ/DMA are not needed on
+ * SSI Multi slaves
+ */
+ if (rsnd_ssi_is_multi_slave(mod, io))
+ return 0;
+
+ ret = rsnd_ssi_common_probe(mod, io, priv);
if (ret)
return ret;
- ret = rsnd_dma_init(
- io, rsnd_mod_to_dma(mod),
- dma_id);
+ ssi->dma = rsnd_dma_attach(io, mod, dma_id);
+ if (IS_ERR(ssi->dma))
+ return PTR_ERR(ssi->dma);
return ret;
}
@@ -550,9 +718,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- int irq = ssi->info->irq;
-
- rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
+ int irq = ssi->irq;
/* PIO will request IRQ again */
devm_free_irq(dev, irq, mod);
@@ -581,32 +747,6 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-
- rsnd_dma_start(io, dma);
-
- rsnd_ssi_start(mod, io, priv);
-
- return 0;
-}
-
-static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
-{
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-
- rsnd_ssi_stop(mod, io, priv);
-
- rsnd_dma_stop(io, dma);
-
- return 0;
-}
-
static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
@@ -630,8 +770,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.remove = rsnd_ssi_dma_remove,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
- .start = rsnd_ssi_dma_start,
- .stop = rsnd_ssi_dma_stop,
+ .start = rsnd_ssi_start,
+ .stop = rsnd_ssi_stop,
.fallback = rsnd_ssi_fallback,
.hw_params = rsnd_ssi_hw_params,
};
@@ -652,110 +792,76 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = {
/*
* ssi mod function
*/
-struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+static void rsnd_ssi_connect(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
{
- if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
- id = 0;
-
- return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id);
-}
-
-int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
- return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
-}
-
-static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
-{
- struct rsnd_mod *mod = rsnd_mod_get(ssi);
-
- if (!__rsnd_ssi_is_pin_sharing(mod))
- return;
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ enum rsnd_mod_type types[] = {
+ RSND_MOD_SSI,
+ RSND_MOD_SSIM1,
+ RSND_MOD_SSIM2,
+ RSND_MOD_SSIM3,
+ };
+ enum rsnd_mod_type type;
+ int i;
- switch (rsnd_mod_id(mod)) {
- case 1:
- case 2:
- ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
- break;
- case 4:
- ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3));
- break;
- case 8:
- ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7));
- break;
+ /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ type = types[i];
+ if (!rsnd_io_to_mod(io, type)) {
+ rsnd_dai_connect(mod, io, type);
+ rsnd_set_slot(rdai, 2 * (i + 1), (i + 1));
+ return;
+ }
}
}
-
-static void rsnd_of_parse_ssi(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+ struct device_node *playback,
+ struct device_node *capture)
{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device_node *node;
struct device_node *np;
- struct rsnd_ssi_platform_info *ssi_info;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct device *dev = &pdev->dev;
- int nr, i;
+ struct rsnd_mod *mod;
+ int i;
node = rsnd_ssi_of_node(priv);
if (!node)
return;
- nr = of_get_child_count(node);
- if (!nr)
- goto rsnd_of_parse_ssi_end;
-
- ssi_info = devm_kzalloc(dev,
- sizeof(struct rsnd_ssi_platform_info) * nr,
- GFP_KERNEL);
- if (!ssi_info) {
- dev_err(dev, "ssi info allocation error\n");
- goto rsnd_of_parse_ssi_end;
- }
-
- info->ssi_info = ssi_info;
- info->ssi_info_nr = nr;
-
- i = -1;
+ i = 0;
for_each_child_of_node(node, np) {
+ mod = rsnd_ssi_mod_get(priv, i);
+ if (np == playback)
+ rsnd_ssi_connect(mod, &rdai->playback);
+ if (np == capture)
+ rsnd_ssi_connect(mod, &rdai->capture);
i++;
+ }
- ssi_info = info->ssi_info + i;
-
- /*
- * pin settings
- */
- if (of_get_property(np, "shared-pin", NULL))
- ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
+ of_node_put(node);
+}
- /*
- * irq
- */
- ssi_info->irq = irq_of_parse_and_map(np, 0);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
+ id = 0;
- /*
- * DMA
- */
- ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
- 0 : 1;
+ return rsnd_mod_get(rsnd_ssi_get(priv, id));
+}
- if (of_get_property(np, "no-busif", NULL))
- ssi_info->flags |= RSND_SSI_NO_BUSIF;
- }
+int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-rsnd_of_parse_ssi_end:
- of_node_put(node);
+ return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
}
-int rsnd_ssi_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+int rsnd_ssi_probe(struct rsnd_priv *priv)
{
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct rsnd_ssi_platform_info *pinfo;
+ struct device_node *node;
+ struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod_ops *ops;
struct clk *clk;
@@ -763,50 +869,73 @@ int rsnd_ssi_probe(struct platform_device *pdev,
char name[RSND_SSI_NAME_SIZE];
int i, nr, ret;
- rsnd_of_parse_ssi(pdev, of_data, priv);
+ node = rsnd_ssi_of_node(priv);
+ if (!node)
+ return -EINVAL;
+
+ nr = of_get_child_count(node);
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_ssi_probe_done;
+ }
- /*
- * init SSI
- */
- nr = info->ssi_info_nr;
ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
- if (!ssi)
- return -ENOMEM;
+ if (!ssi) {
+ ret = -ENOMEM;
+ goto rsnd_ssi_probe_done;
+ }
priv->ssi = ssi;
priv->ssi_nr = nr;
- for_each_rsnd_ssi(ssi, priv, i) {
- pinfo = &info->ssi_info[i];
+ i = 0;
+ for_each_child_of_node(node, np) {
+ ssi = rsnd_ssi_get(priv, i);
snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
SSI_NAME, i);
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto rsnd_ssi_probe_done;
+ }
- ssi->info = pinfo;
+ if (of_get_property(np, "shared-pin", NULL))
+ ssi->flags |= RSND_SSI_CLK_PIN_SHARE;
+
+ if (of_get_property(np, "no-busif", NULL))
+ ssi->flags |= RSND_SSI_NO_BUSIF;
+
+ ssi->irq = irq_of_parse_and_map(np, 0);
+ if (!ssi->irq) {
+ ret = -EINVAL;
+ goto rsnd_ssi_probe_done;
+ }
ops = &rsnd_ssi_non_ops;
- if (pinfo->dma_id > 0)
- ops = &rsnd_ssi_dma_ops;
- else if (rsnd_ssi_pio_available(ssi))
+ if (of_get_property(np, "pio-transfer", NULL))
ops = &rsnd_ssi_pio_ops;
+ else
+ ops = &rsnd_ssi_dma_ops;
ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
RSND_MOD_SSI, i);
if (ret)
- return ret;
+ goto rsnd_ssi_probe_done;
- rsnd_ssi_parent_setup(priv, ssi);
+ i++;
}
- return 0;
+ ret = 0;
+
+rsnd_ssi_probe_done:
+ of_node_put(node);
+
+ return ret;
}
-void rsnd_ssi_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
+void rsnd_ssi_remove(struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi;
int i;
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
new file mode 100644
index 000000000000..06d72828e5bc
--- /dev/null
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -0,0 +1,225 @@
+/*
+ * Renesas R-Car SSIU support
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+#define SSIU_NAME "ssiu"
+
+struct rsnd_ssiu {
+ struct rsnd_mod mod;
+};
+
+#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
+#define for_each_rsnd_ssiu(pos, priv, i) \
+ for (i = 0; \
+ (i < rsnd_ssiu_nr(priv)) && \
+ ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
+ i++)
+
+static int rsnd_ssiu_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io);
+ int use_busif = rsnd_ssi_use_busif(io);
+ int id = rsnd_mod_id(mod);
+ u32 mask1, val1;
+ u32 mask2, val2;
+
+ /*
+ * SSI_MODE0
+ */
+ rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
+
+ /*
+ * SSI_MODE1
+ */
+ mask1 = (1 << 4) | (1 << 20); /* mask sync bit */
+ mask2 = (1 << 4); /* mask sync bit */
+ val1 = val2 = 0;
+ if (rsnd_ssi_is_pin_sharing(io)) {
+ int shift = -1;
+
+ switch (id) {
+ case 1:
+ shift = 0;
+ break;
+ case 2:
+ shift = 2;
+ break;
+ case 4:
+ shift = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mask1 |= 0x3 << shift;
+ val1 = rsnd_rdai_is_clk_master(rdai) ?
+ 0x2 << shift : 0x1 << shift;
+
+ } else if (multi_ssi_slaves) {
+
+ mask2 |= 0x00000007;
+ mask1 |= 0x0000000f;
+
+ switch (multi_ssi_slaves) {
+ case 0x0206: /* SSI0/1/2/9 */
+ val2 = (1 << 4) | /* SSI0129 sync */
+ (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1);
+ /* fall through */
+ case 0x0006: /* SSI0/1/2 */
+ val1 = rsnd_rdai_is_clk_master(rdai) ?
+ 0xa : 0x5;
+
+ if (!val2) /* SSI012 sync */
+ val1 |= (1 << 4);
+ }
+ }
+
+ rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
+ rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
+ .name = SSIU_NAME,
+ .init = rsnd_ssiu_init,
+};
+
+static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ int ret;
+
+ ret = rsnd_ssiu_init(mod, io, priv);
+ if (ret < 0)
+ return ret;
+
+ if (rsnd_get_slot_width(io) >= 6) {
+ /*
+ * TDM Extend Mode
+ * see
+ * rsnd_ssi_config_init()
+ */
+ rsnd_mod_write(mod, SSI_MODE, 0x1);
+ }
+
+ if (rsnd_ssi_use_busif(io)) {
+ u32 val = rsnd_get_dalign(mod, io);
+
+ rsnd_mod_write(mod, SSI_BUSIF_ADINR,
+ rsnd_get_adinr_bit(mod, io) |
+ rsnd_get_adinr_chan(mod, io));
+ rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
+ rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
+ }
+
+ return 0;
+}
+
+static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ if (!rsnd_ssi_use_busif(io))
+ return 0;
+
+ rsnd_mod_write(mod, SSI_CTRL, 0x1);
+
+ if (rsnd_ssi_multi_slaves(io))
+ rsnd_mod_write(mod, SSI_CONTROL, 0x1);
+
+ return 0;
+}
+
+static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ if (!rsnd_ssi_use_busif(io))
+ return 0;
+
+ rsnd_mod_write(mod, SSI_CTRL, 0);
+
+ if (rsnd_ssi_multi_slaves(io))
+ rsnd_mod_write(mod, SSI_CONTROL, 0);
+
+ return 0;
+}
+
+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,
+};
+
+static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
+ id = 0;
+
+ return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
+}
+
+int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
+ struct rsnd_mod *ssi_mod)
+{
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
+
+ rsnd_mod_confirm_ssi(ssi_mod);
+
+ return rsnd_dai_connect(mod, io, mod->type);
+}
+
+int rsnd_ssiu_probe(struct rsnd_priv *priv)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_ssiu *ssiu;
+ static struct rsnd_mod_ops *ops;
+ int i, nr, ret;
+
+ /* same number to SSI */
+ nr = priv->ssi_nr;
+ ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
+ if (!ssiu)
+ return -ENOMEM;
+
+ priv->ssiu = ssiu;
+ priv->ssiu_nr = nr;
+
+ if (rsnd_is_gen1(priv))
+ ops = &rsnd_ssiu_ops_gen1;
+ else
+ ops = &rsnd_ssiu_ops_gen2;
+
+ for_each_rsnd_ssiu(ssiu, priv, i) {
+ ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
+ ops, NULL, RSND_MOD_SSIU, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void rsnd_ssiu_remove(struct rsnd_priv *priv)
+{
+ struct rsnd_ssiu *ssiu;
+ int i;
+
+ for_each_rsnd_ssiu(ssiu, priv, i) {
+ rsnd_mod_quit(rsnd_mod_get(ssiu));
+ }
+}
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index d40efc9fe0a9..7e0acd83b0e6 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
@@ -38,6 +39,14 @@ struct snd_ac97_reset_cfg {
int gpio_reset;
};
+struct snd_ac97_gpio_priv {
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
+ unsigned int gpios_set;
+ struct snd_soc_codec *codec;
+};
+
static struct snd_ac97_bus soc_ac97_bus = {
.ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */
};
@@ -47,6 +56,117 @@ static void soc_ac97_device_release(struct device *dev)
kfree(to_ac97_t(dev));
}
+#ifdef CONFIG_GPIOLIB
+static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip)
+{
+ struct snd_ac97_gpio_priv *gpio_priv =
+ container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+
+ return gpio_priv->codec;
+}
+
+static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset >= AC97_NUM_GPIOS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+ dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+ return snd_soc_update_bits(codec, AC97_GPIO_CFG,
+ 1 << offset, 1 << offset);
+}
+
+static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct snd_soc_codec *codec = gpio_to_codec(chip);
+ int ret;
+
+ ret = snd_soc_read(codec, AC97_GPIO_STATUS);
+ dev_dbg(codec->dev, "get gpio %d : %d\n", offset,
+ ret < 0 ? ret : ret & (1 << offset));
+
+ return ret < 0 ? ret : !!(ret & (1 << offset));
+}
+
+static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct snd_ac97_gpio_priv *gpio_priv =
+ container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+ struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+ gpio_priv->gpios_set &= ~(1 << offset);
+ gpio_priv->gpios_set |= (!!value) << offset;
+ snd_soc_write(codec, AC97_GPIO_STATUS, gpio_priv->gpios_set);
+ dev_dbg(codec->dev, "set gpio %d to %d\n", offset, !!value);
+}
+
+static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+ dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+ snd_soc_ac97_gpio_set(chip, offset, value);
+ return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0);
+}
+
+static struct gpio_chip snd_soc_ac97_gpio_chip = {
+ .label = "snd_soc_ac97",
+ .owner = THIS_MODULE,
+ .request = snd_soc_ac97_gpio_request,
+ .direction_input = snd_soc_ac97_gpio_direction_in,
+ .get = snd_soc_ac97_gpio_get,
+ .direction_output = snd_soc_ac97_gpio_direction_out,
+ .set = snd_soc_ac97_gpio_set,
+ .can_sleep = 1,
+};
+
+static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
+ struct snd_soc_codec *codec)
+{
+ struct snd_ac97_gpio_priv *gpio_priv;
+ int ret;
+
+ gpio_priv = devm_kzalloc(codec->dev, sizeof(*gpio_priv), GFP_KERNEL);
+ if (!gpio_priv)
+ return -ENOMEM;
+ ac97->gpio_priv = gpio_priv;
+ gpio_priv->codec = codec;
+ gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip;
+ gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS;
+ gpio_priv->gpio_chip.parent = codec->dev;
+ gpio_priv->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&gpio_priv->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+ return ret;
+}
+
+static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
+{
+ gpiochip_remove(&ac97->gpio_priv->gpio_chip);
+}
+#else
+static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
+ struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
+{
+}
+#endif
+
/**
* snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device
* @codec: The CODEC for which to create the AC'97 device
@@ -119,6 +239,10 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
if (ret)
goto err_put_device;
+ ret = snd_soc_ac97_init_gpio(ac97, codec);
+ if (ret)
+ goto err_put_device;
+
return ac97;
err_put_device:
@@ -135,6 +259,7 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
*/
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97)
{
+ snd_soc_ac97_free_gpio(ac97);
device_del(&ac97->dev);
ac97->bus = NULL;
put_device(&ac97->dev);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 12a9820feac1..875733c52953 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -630,6 +630,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
struct snd_pcm *be_pcm;
char new_name[64];
int ret = 0, direction = 0;
+ int playback = 0, capture = 0;
if (rtd->num_codecs > 1) {
dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
@@ -641,11 +642,27 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
rtd->dai_link->stream_name, codec_dai->name, num);
if (codec_dai->driver->playback.channels_min)
+ playback = 1;
+ if (codec_dai->driver->capture.channels_min)
+ capture = 1;
+
+ capture = capture && cpu_dai->driver->capture.channels_min;
+ playback = playback && cpu_dai->driver->playback.channels_min;
+
+ /*
+ * Compress devices are unidirectional so only one of the directions
+ * should be set, check for that (xor)
+ */
+ if (playback + capture != 1) {
+ dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n",
+ playback, capture);
+ return -EINVAL;
+ }
+
+ if(playback)
direction = SND_COMPRESS_PLAYBACK;
- else if (codec_dai->driver->capture.channels_min)
- direction = SND_COMPRESS_CAPTURE;
else
- return -EINVAL;
+ direction = SND_COMPRESS_CAPTURE;
compr = kzalloc(sizeof(*compr), GFP_KERNEL);
if (compr == NULL) {
@@ -689,7 +706,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
compr->ops->copy = soc_compr_copy;
mutex_init(&compr->lock);
- ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
+
+ snprintf(new_name, sizeof(new_name), "%s %s-%d",
+ rtd->dai_link->stream_name,
+ rtd->codec_dai->name, num);
+
+ ret = snd_compress_new(rtd->card->snd_card, num, direction,
+ new_name, compr);
if (ret < 0) {
pr_err("compress asoc: can't create compress for codec %s\n",
codec->component.name);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a1305f827a98..790ee2bf1a47 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -537,26 +537,75 @@ static inline void snd_soc_debugfs_exit(void)
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
const char *dai_link, int stream)
{
- int i;
+ struct snd_soc_pcm_runtime *rtd;
- for (i = 0; i < card->num_links; i++) {
- if (card->rtd[i].dai_link->no_pcm &&
- !strcmp(card->rtd[i].dai_link->name, dai_link))
- return card->rtd[i].pcm->streams[stream].substream;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ if (rtd->dai_link->no_pcm &&
+ !strcmp(rtd->dai_link->name, dai_link))
+ return rtd->pcm->streams[stream].substream;
}
dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
+static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
+ struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_pcm_runtime *rtd;
+
+ rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
+ if (!rtd)
+ return NULL;
+
+ rtd->card = card;
+ rtd->dai_link = dai_link;
+ rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
+ dai_link->num_codecs,
+ GFP_KERNEL);
+ if (!rtd->codec_dais) {
+ kfree(rtd);
+ return NULL;
+ }
+
+ return rtd;
+}
+
+static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
+{
+ if (rtd && rtd->codec_dais)
+ kfree(rtd->codec_dais);
+ kfree(rtd);
+}
+
+static void soc_add_pcm_runtime(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ list_add_tail(&rtd->list, &card->rtd_list);
+ rtd->num = card->num_rtd;
+ card->num_rtd++;
+}
+
+static void soc_remove_pcm_runtimes(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd, *_rtd;
+
+ list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) {
+ list_del(&rtd->list);
+ soc_free_pcm_runtime(rtd);
+ }
+
+ card->num_rtd = 0;
+}
+
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
const char *dai_link)
{
- int i;
+ struct snd_soc_pcm_runtime *rtd;
- for (i = 0; i < card->num_links; i++) {
- if (!strcmp(card->rtd[i].dai_link->name, dai_link))
- return &card->rtd[i];
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ if (!strcmp(rtd->dai_link->name, dai_link))
+ return rtd;
}
dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link);
return NULL;
@@ -578,7 +627,8 @@ int snd_soc_suspend(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
struct snd_soc_codec *codec;
- int i, j;
+ struct snd_soc_pcm_runtime *rtd;
+ int i;
/* If the card is not initialized yet there is nothing to do */
if (!card->instantiated)
@@ -595,13 +645,13 @@ int snd_soc_suspend(struct device *dev)
snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
/* mute any active DACs */
- for (i = 0; i < card->num_rtd; i++) {
+ list_for_each_entry(rtd, &card->rtd_list, list) {
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
- for (j = 0; j < card->rtd[i].num_codecs; j++) {
- struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+ for (i = 0; i < rtd->num_codecs; i++) {
+ struct snd_soc_dai *dai = rtd->codec_dais[i];
struct snd_soc_dai_driver *drv = dai->driver;
if (drv->ops->digital_mute && dai->playback_active)
@@ -610,20 +660,20 @@ int snd_soc_suspend(struct device *dev)
}
/* suspend all pcms */
- for (i = 0; i < card->num_rtd; i++) {
- if (card->rtd[i].dai_link->ignore_suspend)
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ if (rtd->dai_link->ignore_suspend)
continue;
- snd_pcm_suspend_all(card->rtd[i].pcm);
+ snd_pcm_suspend_all(rtd->pcm);
}
if (card->suspend_pre)
card->suspend_pre(card);
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control)
@@ -631,19 +681,19 @@ int snd_soc_suspend(struct device *dev)
}
/* close any waiting streams */
- for (i = 0; i < card->num_rtd; i++)
- flush_delayed_work(&card->rtd[i].delayed_work);
+ list_for_each_entry(rtd, &card->rtd_list, list)
+ flush_delayed_work(&rtd->delayed_work);
- for (i = 0; i < card->num_rtd; i++) {
+ list_for_each_entry(rtd, &card->rtd_list, list) {
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
- snd_soc_dapm_stream_event(&card->rtd[i],
+ snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_SUSPEND);
- snd_soc_dapm_stream_event(&card->rtd[i],
+ snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_CAPTURE,
SND_SOC_DAPM_STREAM_SUSPEND);
}
@@ -690,10 +740,10 @@ int snd_soc_suspend(struct device *dev)
}
}
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control)
@@ -717,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work)
{
struct snd_soc_card *card =
container_of(work, struct snd_soc_card, deferred_resume_work);
+ struct snd_soc_pcm_runtime *rtd;
struct snd_soc_codec *codec;
- int i, j;
+ int i;
/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
* so userspace apps are blocked from touching us
@@ -733,10 +784,10 @@ static void soc_resume_deferred(struct work_struct *work)
card->resume_pre(card);
/* resume control bus DAIs */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
if (cpu_dai->driver->resume && cpu_dai->driver->bus_control)
@@ -751,28 +802,28 @@ static void soc_resume_deferred(struct work_struct *work)
}
}
- for (i = 0; i < card->num_rtd; i++) {
+ list_for_each_entry(rtd, &card->rtd_list, list) {
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
- snd_soc_dapm_stream_event(&card->rtd[i],
+ snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_RESUME);
- snd_soc_dapm_stream_event(&card->rtd[i],
+ snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_CAPTURE,
SND_SOC_DAPM_STREAM_RESUME);
}
/* unmute any active DACs */
- for (i = 0; i < card->num_rtd; i++) {
+ list_for_each_entry(rtd, &card->rtd_list, list) {
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
- for (j = 0; j < card->rtd[i].num_codecs; j++) {
- struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+ for (i = 0; i < rtd->num_codecs; i++) {
+ struct snd_soc_dai *dai = rtd->codec_dais[i];
struct snd_soc_dai_driver *drv = dai->driver;
if (drv->ops->digital_mute && dai->playback_active)
@@ -780,10 +831,10 @@ static void soc_resume_deferred(struct work_struct *work)
}
}
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- if (card->rtd[i].dai_link->ignore_suspend)
+ if (rtd->dai_link->ignore_suspend)
continue;
if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control)
@@ -808,15 +859,14 @@ int snd_soc_resume(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
bool bus_control = false;
- int i;
+ struct snd_soc_pcm_runtime *rtd;
/* If the card is not initialized yet there is nothing to do */
if (!card->instantiated)
return 0;
/* activate pins from sleep state */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ list_for_each_entry(rtd, &card->rtd_list, list) {
struct snd_soc_dai **codec_dais = rtd->codec_dais;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int j;
@@ -837,8 +887,8 @@ int snd_soc_resume(struct device *dev)
* have that problem and may take a substantial amount of time to resume
* due to I/O costs and anti-pop so handle them out of line.
*/
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
bus_control |= cpu_dai->driver->bus_control;
}
if (bus_control) {
@@ -910,18 +960,41 @@ static struct snd_soc_dai *snd_soc_find_dai(
return NULL;
}
-static int soc_bind_dai_link(struct snd_soc_card *card, int num)
+static bool soc_is_dai_link_bound(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
{
- struct snd_soc_dai_link *dai_link = &card->dai_link[num];
- struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_pcm_runtime *rtd;
+
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ if (rtd->dai_link == dai_link)
+ return true;
+ }
+
+ return false;
+}
+
+static int soc_bind_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
struct snd_soc_dai_link_component cpu_dai_component;
- struct snd_soc_dai **codec_dais = rtd->codec_dais;
+ struct snd_soc_dai **codec_dais;
struct snd_soc_platform *platform;
const char *platform_name;
int i;
- dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
+ dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
+
+ rtd = soc_new_pcm_runtime(card, dai_link);
+ if (!rtd)
+ return -ENOMEM;
+
+ if (soc_is_dai_link_bound(card, dai_link)) {
+ dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
+ dai_link->name);
+ return 0;
+ }
cpu_dai_component.name = dai_link->cpu_name;
cpu_dai_component.of_node = dai_link->cpu_of_node;
@@ -930,18 +1003,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
if (!rtd->cpu_dai) {
dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
dai_link->cpu_dai_name);
- return -EPROBE_DEFER;
+ goto _err_defer;
}
rtd->num_codecs = dai_link->num_codecs;
/* Find CODEC from registered CODECs */
+ codec_dais = rtd->codec_dais;
for (i = 0; i < rtd->num_codecs; i++) {
codec_dais[i] = snd_soc_find_dai(&codecs[i]);
if (!codec_dais[i]) {
dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
codecs[i].dai_name);
- return -EPROBE_DEFER;
+ goto _err_defer;
}
}
@@ -973,9 +1047,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
return -EPROBE_DEFER;
}
- card->num_rtd++;
-
+ soc_add_pcm_runtime(card, rtd);
return 0;
+
+_err_defer:
+ soc_free_pcm_runtime(rtd);
+ return -EPROBE_DEFER;
}
static void soc_remove_component(struct snd_soc_component *component)
@@ -1014,9 +1091,9 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order)
}
}
-static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
+static void soc_remove_link_dais(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd, int order)
{
- struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
int i;
/* unregister the rtd device */
@@ -1032,10 +1109,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
soc_remove_dai(rtd->cpu_dai, order);
}
-static void soc_remove_link_components(struct snd_soc_card *card, int num,
- int order)
+static void soc_remove_link_components(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd, int order)
{
- struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_component *component;
@@ -1061,23 +1137,200 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num,
static void soc_remove_dai_links(struct snd_soc_card *card)
{
- int dai, order;
+ int order;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai_link *link, *_link;
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
- for (dai = 0; dai < card->num_rtd; dai++)
- soc_remove_link_dais(card, dai, order);
+ list_for_each_entry(rtd, &card->rtd_list, list)
+ soc_remove_link_dais(card, rtd, order);
}
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
- for (dai = 0; dai < card->num_rtd; dai++)
- soc_remove_link_components(card, dai, order);
+ list_for_each_entry(rtd, &card->rtd_list, list)
+ soc_remove_link_components(card, rtd, order);
}
- card->num_rtd = 0;
+ list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+ if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK)
+ dev_warn(card->dev, "Topology forgot to remove link %s?\n",
+ link->name);
+
+ list_del(&link->list);
+ card->num_dai_links--;
+ }
}
+static int snd_soc_init_multicodec(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ /* Legacy codec/codec_dai link is a single entry in multicodec */
+ if (dai_link->codec_name || dai_link->codec_of_node ||
+ dai_link->codec_dai_name) {
+ dai_link->num_codecs = 1;
+
+ dai_link->codecs = devm_kzalloc(card->dev,
+ sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!dai_link->codecs)
+ return -ENOMEM;
+
+ dai_link->codecs[0].name = dai_link->codec_name;
+ dai_link->codecs[0].of_node = dai_link->codec_of_node;
+ dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
+ }
+
+ if (!dai_link->codecs) {
+ dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int soc_init_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link)
+{
+ int i, ret;
+
+ ret = snd_soc_init_multicodec(card, link);
+ if (ret) {
+ dev_err(card->dev, "ASoC: failed to init multicodec\n");
+ return ret;
+ }
+
+ for (i = 0; i < link->num_codecs; i++) {
+ /*
+ * Codec must be specified by 1 of name or OF node,
+ * not both or neither.
+ */
+ if (!!link->codecs[i].name ==
+ !!link->codecs[i].of_node) {
+ dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
+ link->name);
+ return -EINVAL;
+ }
+ /* Codec DAI name must be specified */
+ if (!link->codecs[i].dai_name) {
+ dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
+ link->name);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Platform may be specified by either name or OF node, but
+ * can be left unspecified, and a dummy platform will be used.
+ */
+ if (link->platform_name && link->platform_of_node) {
+ dev_err(card->dev,
+ "ASoC: Both platform name/of_node are set for %s\n",
+ link->name);
+ return -EINVAL;
+ }
+
+ /*
+ * CPU device may be specified by either name or OF node, but
+ * can be left unspecified, and will be matched based on DAI
+ * name alone..
+ */
+ if (link->cpu_name && link->cpu_of_node) {
+ dev_err(card->dev,
+ "ASoC: Neither/both cpu name/of_node are set for %s\n",
+ link->name);
+ return -EINVAL;
+ }
+ /*
+ * At least one of CPU DAI name or CPU device name/node must be
+ * specified
+ */
+ if (!link->cpu_dai_name &&
+ !(link->cpu_name || link->cpu_of_node)) {
+ dev_err(card->dev,
+ "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
+ link->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * snd_soc_add_dai_link - Add a DAI link dynamically
+ * @card: The ASoC card to which the DAI link is added
+ * @dai_link: The new DAI link to add
+ *
+ * This function adds a DAI link to the ASoC card's link list.
+ *
+ * Note: Topology can use this API to add DAI links when probing the
+ * topology component. And machine drivers can still define static
+ * DAI links in dai_link array.
+ */
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ if (dai_link->dobj.type
+ && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+ dev_err(card->dev, "Invalid dai link type %d\n",
+ dai_link->dobj.type);
+ return -EINVAL;
+ }
+
+ lockdep_assert_held(&client_mutex);
+ /* Notify the machine driver for extra initialization
+ * on the link created by topology.
+ */
+ if (dai_link->dobj.type && card->add_dai_link)
+ card->add_dai_link(card, dai_link);
+
+ list_add_tail(&dai_link->list, &card->dai_link_list);
+ card->num_dai_links++;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
+
+/**
+ * snd_soc_remove_dai_link - Remove a DAI link from the list
+ * @card: The ASoC card that owns the link
+ * @dai_link: The DAI link to remove
+ *
+ * This function removes a DAI link from the ASoC card's link list.
+ *
+ * For DAI links previously added by topology, topology should
+ * remove them by using the dobj embedded in the link.
+ */
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_dai_link *link, *_link;
+
+ if (dai_link->dobj.type
+ && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+ dev_err(card->dev, "Invalid dai link type %d\n",
+ dai_link->dobj.type);
+ return;
+ }
+
+ lockdep_assert_held(&client_mutex);
+ /* Notify the machine driver for extra destruction
+ * on the link created by topology.
+ */
+ if (dai_link->dobj.type && card->remove_dai_link)
+ card->remove_dai_link(card, dai_link);
+
+ list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+ if (link == dai_link) {
+ list_del(&link->list);
+ card->num_dai_links--;
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
+
static void soc_set_name_prefix(struct snd_soc_card *card,
struct snd_soc_component *component)
{
@@ -1160,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card,
component->name);
}
+ /* machine specific init */
+ if (component->init) {
+ ret = component->init(component);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "Failed to do machine specific init %d\n", ret);
+ goto err_probe;
+ }
+ }
+
if (component->controls)
snd_soc_add_component_controls(component, component->controls,
component->num_controls);
@@ -1220,10 +1483,10 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int soc_probe_link_components(struct snd_soc_card *card, int num,
+static int soc_probe_link_components(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd,
int order)
{
- struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_component *component;
int i, ret;
@@ -1283,35 +1546,35 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dapm_widget *play_w, *capture_w;
+ struct snd_soc_dapm_widget *sink, *source;
int ret;
if (rtd->num_codecs > 1)
dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
/* link the DAI widgets */
- play_w = codec_dai->playback_widget;
- capture_w = cpu_dai->capture_widget;
- if (play_w && capture_w) {
+ sink = codec_dai->playback_widget;
+ source = cpu_dai->capture_widget;
+ if (sink && source) {
ret = snd_soc_dapm_new_pcm(card, dai_link->params,
- dai_link->num_params, capture_w,
- play_w);
+ dai_link->num_params,
+ source, sink);
if (ret != 0) {
dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
- play_w->name, capture_w->name, ret);
+ sink->name, source->name, ret);
return ret;
}
}
- play_w = cpu_dai->playback_widget;
- capture_w = codec_dai->capture_widget;
- if (play_w && capture_w) {
+ sink = cpu_dai->playback_widget;
+ source = codec_dai->capture_widget;
+ if (sink && source) {
ret = snd_soc_dapm_new_pcm(card, dai_link->params,
- dai_link->num_params, capture_w,
- play_w);
+ dai_link->num_params,
+ source, sink);
if (ret != 0) {
dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
- play_w->name, capture_w->name, ret);
+ sink->name, source->name, ret);
return ret;
}
}
@@ -1319,15 +1582,15 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
return 0;
}
-static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
+static int soc_probe_link_dais(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd, int order)
{
- struct snd_soc_dai_link *dai_link = &card->dai_link[num];
- struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, ret;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
- card->name, num, order);
+ card->name, rtd->num, order);
/* set default power off timeout */
rtd->pmdown_time = pmdown_time;
@@ -1372,7 +1635,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
if (cpu_dai->driver->compress_new) {
/*create compress_device"*/
- ret = cpu_dai->driver->compress_new(rtd, num);
+ ret = cpu_dai->driver->compress_new(rtd, rtd->num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create compress %s\n",
dai_link->stream_name);
@@ -1382,7 +1645,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
if (!dai_link->params) {
/* create the pcm */
- ret = soc_new_pcm(rtd, num);
+ ret = soc_new_pcm(rtd, rtd->num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
dai_link->stream_name, ret);
@@ -1404,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
{
- struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
- const char *name = aux_dev->codec_name;
-
- rtd->component = soc_find_component(aux_dev->codec_of_node, name);
- if (!rtd->component) {
- if (aux_dev->codec_of_node)
- name = of_node_full_name(aux_dev->codec_of_node);
-
- dev_err(card->dev, "ASoC: %s not registered\n", name);
- return -EPROBE_DEFER;
+ struct snd_soc_component *component;
+ const char *name;
+ struct device_node *codec_of_node;
+
+ if (aux_dev->codec_of_node || aux_dev->codec_name) {
+ /* codecs, usually analog devices */
+ name = aux_dev->codec_name;
+ codec_of_node = aux_dev->codec_of_node;
+ component = soc_find_component(codec_of_node, name);
+ if (!component) {
+ if (codec_of_node)
+ name = of_node_full_name(codec_of_node);
+ goto err_defer;
+ }
+ } else if (aux_dev->name) {
+ /* generic components */
+ name = aux_dev->name;
+ component = soc_find_component(NULL, name);
+ if (!component)
+ goto err_defer;
+ } else {
+ dev_err(card->dev, "ASoC: Invalid auxiliary device\n");
+ return -EINVAL;
}
- /*
- * Some places still reference rtd->codec, so we have to keep that
- * initialized if the component is a CODEC. Once all those references
- * have been removed, this code can be removed as well.
- */
- rtd->codec = rtd->component->codec;
-
+ component->init = aux_dev->init;
+ list_add(&component->list_aux, &card->aux_comp_list);
return 0;
+
+err_defer:
+ dev_err(card->dev, "ASoC: %s not registered\n", name);
+ return -EPROBE_DEFER;
}
-static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
+static int soc_probe_aux_devices(struct snd_soc_card *card)
{
- struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
- struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+ struct snd_soc_component *comp;
+ int order;
int ret;
- ret = soc_probe_component(card, rtd->component);
- if (ret < 0)
- return ret;
-
- /* do machine specific initialization */
- if (aux_dev->init) {
- ret = aux_dev->init(rtd->component);
- if (ret < 0) {
- dev_err(card->dev, "ASoC: failed to init %s: %d\n",
- aux_dev->name, ret);
- return ret;
+ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+ order++) {
+ list_for_each_entry(comp, &card->aux_comp_list, list_aux) {
+ if (comp->driver->probe_order == order) {
+ ret = soc_probe_component(card, comp);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "ASoC: failed to probe aux component %s %d\n",
+ comp->name, ret);
+ return ret;
+ }
+ }
}
}
- return soc_post_component_init(rtd, aux_dev->name);
+ return 0;
}
-static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
+static void soc_remove_aux_devices(struct snd_soc_card *card)
{
- struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
- struct snd_soc_component *component = rtd->component;
+ struct snd_soc_component *comp, *_comp;
+ int order;
- /* unregister the rtd device */
- if (rtd->dev_registered) {
- device_unregister(rtd->dev);
- rtd->dev_registered = 0;
+ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+ order++) {
+ list_for_each_entry_safe(comp, _comp,
+ &card->aux_comp_list, list_aux) {
+ if (comp->driver->remove_order == order) {
+ soc_remove_component(comp);
+ /* remove it from the card's aux_comp_list */
+ list_del(&comp->list_aux);
+ }
+ }
}
-
- if (component)
- soc_remove_component(component);
}
static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
@@ -1552,6 +1831,8 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai_link *dai_link;
int ret, i, order;
mutex_lock(&client_mutex);
@@ -1559,7 +1840,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
/* bind DAIs */
for (i = 0; i < card->num_links; i++) {
- ret = soc_bind_dai_link(card, i);
+ ret = soc_bind_dai_link(card, &card->dai_link[i]);
if (ret != 0)
goto base_error;
}
@@ -1571,6 +1852,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
goto base_error;
}
+ /* add predefined DAI links to the list */
+ for (i = 0; i < card->num_links; i++)
+ snd_soc_add_dai_link(card, card->dai_link+i);
+
/* initialize the register cache for each available codec */
list_for_each_entry(codec, &codec_list, list) {
if (codec->cache_init)
@@ -1624,8 +1909,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
/* probe all components used by DAI links on this card */
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
- for (i = 0; i < card->num_links; i++) {
- ret = soc_probe_link_components(card, i, order);
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ ret = soc_probe_link_components(card, rtd, order);
if (ret < 0) {
dev_err(card->dev,
"ASoC: failed to instantiate card %d\n",
@@ -1635,11 +1920,31 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
}
}
+ /* probe auxiliary components */
+ ret = soc_probe_aux_devices(card);
+ if (ret < 0)
+ goto probe_dai_err;
+
+ /* Find new DAI links added during probing components and bind them.
+ * Components with topology may bring new DAIs and DAI links.
+ */
+ list_for_each_entry(dai_link, &card->dai_link_list, list) {
+ if (soc_is_dai_link_bound(card, dai_link))
+ continue;
+
+ ret = soc_init_dai_link(card, dai_link);
+ if (ret)
+ goto probe_dai_err;
+ ret = soc_bind_dai_link(card, dai_link);
+ if (ret)
+ goto probe_dai_err;
+ }
+
/* probe all DAI links on this card */
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
- for (i = 0; i < card->num_links; i++) {
- ret = soc_probe_link_dais(card, i, order);
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ ret = soc_probe_link_dais(card, rtd, order);
if (ret < 0) {
dev_err(card->dev,
"ASoC: failed to instantiate card %d\n",
@@ -1649,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
}
}
- for (i = 0; i < card->num_aux_devs; i++) {
- ret = soc_probe_aux_dev(card, i);
- if (ret < 0) {
- dev_err(card->dev,
- "ASoC: failed to add auxiliary devices %d\n",
- ret);
- goto probe_aux_dev_err;
- }
- }
-
snd_soc_dapm_link_dai_widgets(card);
snd_soc_dapm_connect_dai_link_widgets(card);
@@ -1718,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
return 0;
probe_aux_dev_err:
- for (i = 0; i < card->num_aux_devs; i++)
- soc_remove_aux_dev(card, i);
+ soc_remove_aux_devices(card);
probe_dai_err:
soc_remove_dai_links(card);
@@ -1733,6 +2027,7 @@ card_probe_error:
snd_card_free(card->snd_card);
base_error:
+ soc_remove_pcm_runtimes(card);
mutex_unlock(&card->mutex);
mutex_unlock(&client_mutex);
@@ -1763,20 +2058,18 @@ static int soc_probe(struct platform_device *pdev)
static int soc_cleanup_card_resources(struct snd_soc_card *card)
{
- int i;
+ struct snd_soc_pcm_runtime *rtd;
/* make sure any delayed work runs */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ list_for_each_entry(rtd, &card->rtd_list, list)
flush_delayed_work(&rtd->delayed_work);
- }
-
- /* remove auxiliary devices */
- for (i = 0; i < card->num_aux_devs; i++)
- soc_remove_aux_dev(card, i);
/* remove and free each DAI */
soc_remove_dai_links(card);
+ soc_remove_pcm_runtimes(card);
+
+ /* remove auxiliary devices */
+ soc_remove_aux_devices(card);
soc_cleanup_card_debugfs(card);
@@ -1803,29 +2096,26 @@ static int soc_remove(struct platform_device *pdev)
int snd_soc_poweroff(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
- int i;
+ struct snd_soc_pcm_runtime *rtd;
if (!card->instantiated)
return 0;
/* Flush out pmdown_time work - we actually do want to run it
* now, we're shutting down so no imminent restart. */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ list_for_each_entry(rtd, &card->rtd_list, list)
flush_delayed_work(&rtd->delayed_work);
- }
snd_soc_dapm_shutdown(card);
/* deactivate pins to sleep state */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ list_for_each_entry(rtd, &card->rtd_list, list) {
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int j;
+ int i;
pinctrl_pm_select_sleep_state(cpu_dai->dev);
- for (j = 0; j < rtd->num_codecs; j++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+ for (i = 0; i < rtd->num_codecs; i++) {
+ struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
pinctrl_pm_select_sleep_state(codec_dai->dev);
}
}
@@ -2301,33 +2591,6 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
}
EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
-static int snd_soc_init_multicodec(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
-{
- /* Legacy codec/codec_dai link is a single entry in multicodec */
- if (dai_link->codec_name || dai_link->codec_of_node ||
- dai_link->codec_dai_name) {
- dai_link->num_codecs = 1;
-
- dai_link->codecs = devm_kzalloc(card->dev,
- sizeof(struct snd_soc_dai_link_component),
- GFP_KERNEL);
- if (!dai_link->codecs)
- return -ENOMEM;
-
- dai_link->codecs[0].name = dai_link->codec_name;
- dai_link->codecs[0].of_node = dai_link->codec_of_node;
- dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
- }
-
- if (!dai_link->codecs) {
- dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
/**
* snd_soc_register_card - Register a card with the ASoC core
*
@@ -2336,7 +2599,8 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card,
*/
int snd_soc_register_card(struct snd_soc_card *card)
{
- int i, j, ret;
+ int i, ret;
+ struct snd_soc_pcm_runtime *rtd;
if (!card->name || !card->dev)
return -EINVAL;
@@ -2344,63 +2608,11 @@ int snd_soc_register_card(struct snd_soc_card *card)
for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai_link *link = &card->dai_link[i];
- ret = snd_soc_init_multicodec(card, link);
+ ret = soc_init_dai_link(card, link);
if (ret) {
- dev_err(card->dev, "ASoC: failed to init multicodec\n");
- return ret;
- }
-
- for (j = 0; j < link->num_codecs; j++) {
- /*
- * Codec must be specified by 1 of name or OF node,
- * not both or neither.
- */
- if (!!link->codecs[j].name ==
- !!link->codecs[j].of_node) {
- dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
- /* Codec DAI name must be specified */
- if (!link->codecs[j].dai_name) {
- dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
- link->name);
- return -EINVAL;
- }
- }
-
- /*
- * Platform may be specified by either name or OF node, but
- * can be left unspecified, and a dummy platform will be used.
- */
- if (link->platform_name && link->platform_of_node) {
- dev_err(card->dev,
- "ASoC: Both platform name/of_node are set for %s\n",
+ dev_err(card->dev, "ASoC: failed to init link %s\n",
link->name);
- return -EINVAL;
- }
-
- /*
- * CPU device may be specified by either name or OF node, but
- * can be left unspecified, and will be matched based on DAI
- * name alone..
- */
- if (link->cpu_name && link->cpu_of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both cpu name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
- /*
- * At least one of CPU DAI name or CPU device name/node must be
- * specified
- */
- if (!link->cpu_dai_name &&
- !(link->cpu_name || link->cpu_of_node)) {
- dev_err(card->dev,
- "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
+ return ret;
}
}
@@ -2408,28 +2620,11 @@ int snd_soc_register_card(struct snd_soc_card *card)
snd_soc_initialize_card_lists(card);
- card->rtd = devm_kzalloc(card->dev,
- sizeof(struct snd_soc_pcm_runtime) *
- (card->num_links + card->num_aux_devs),
- GFP_KERNEL);
- if (card->rtd == NULL)
- return -ENOMEM;
- card->num_rtd = 0;
- card->rtd_aux = &card->rtd[card->num_links];
-
- for (i = 0; i < card->num_links; i++) {
- card->rtd[i].card = card;
- card->rtd[i].dai_link = &card->dai_link[i];
- card->rtd[i].codec_dais = devm_kzalloc(card->dev,
- sizeof(struct snd_soc_dai *) *
- (card->rtd[i].dai_link->num_codecs),
- GFP_KERNEL);
- if (card->rtd[i].codec_dais == NULL)
- return -ENOMEM;
- }
+ INIT_LIST_HEAD(&card->dai_link_list);
+ card->num_dai_links = 0;
- for (i = 0; i < card->num_aux_devs; i++)
- card->rtd_aux[i].card = card;
+ INIT_LIST_HEAD(&card->rtd_list);
+ card->num_rtd = 0;
INIT_LIST_HEAD(&card->dapm_dirty);
INIT_LIST_HEAD(&card->dobj_list);
@@ -2442,8 +2637,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
return ret;
/* deactivate pins to sleep state */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ list_for_each_entry(rtd, &card->rtd_list, list) {
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int j;
@@ -2558,6 +2752,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component)
}
}
+/* Create a DAI and add it to the component's DAI list */
+static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
+ struct snd_soc_dai_driver *dai_drv,
+ bool legacy_dai_naming)
+{
+ struct device *dev = component->dev;
+ struct snd_soc_dai *dai;
+
+ dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
+
+ dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+ if (dai == NULL)
+ return NULL;
+
+ /*
+ * Back in the old days when we still had component-less DAIs,
+ * instead of having a static name, component-less DAIs would
+ * inherit the name of the parent device so it is possible to
+ * register multiple instances of the DAI. We still need to keep
+ * the same naming style even though those DAIs are not
+ * component-less anymore.
+ */
+ if (legacy_dai_naming &&
+ (dai_drv->id == 0 || dai_drv->name == NULL)) {
+ dai->name = fmt_single_name(dev, &dai->id);
+ } else {
+ dai->name = fmt_multiple_name(dev, dai_drv);
+ if (dai_drv->id)
+ dai->id = dai_drv->id;
+ else
+ dai->id = component->num_dai;
+ }
+ if (dai->name == NULL) {
+ kfree(dai);
+ return NULL;
+ }
+
+ dai->component = component;
+ dai->dev = dev;
+ dai->driver = dai_drv;
+ if (!dai->driver->ops)
+ dai->driver->ops = &null_dai_ops;
+
+ list_add(&dai->list, &component->dai_list);
+ component->num_dai++;
+
+ dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
+ return dai;
+}
+
/**
* snd_soc_register_dais - Register a DAI with the ASoC core
*
@@ -2579,58 +2823,66 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
component->dai_drv = dai_drv;
- component->num_dai = count;
for (i = 0; i < count; i++) {
- dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+ dai = soc_add_dai(component, dai_drv + i,
+ count == 1 && legacy_dai_naming);
if (dai == NULL) {
ret = -ENOMEM;
goto err;
}
+ }
- /*
- * Back in the old days when we still had component-less DAIs,
- * instead of having a static name, component-less DAIs would
- * inherit the name of the parent device so it is possible to
- * register multiple instances of the DAI. We still need to keep
- * the same naming style even though those DAIs are not
- * component-less anymore.
- */
- if (count == 1 && legacy_dai_naming &&
- (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
- dai->name = fmt_single_name(dev, &dai->id);
- } else {
- dai->name = fmt_multiple_name(dev, &dai_drv[i]);
- if (dai_drv[i].id)
- dai->id = dai_drv[i].id;
- else
- dai->id = i;
- }
- if (dai->name == NULL) {
- kfree(dai);
- ret = -ENOMEM;
- goto err;
- }
+ return 0;
- dai->component = component;
- dai->dev = dev;
- dai->driver = &dai_drv[i];
- if (!dai->driver->ops)
- dai->driver->ops = &null_dai_ops;
+err:
+ snd_soc_unregister_dais(component);
- list_add(&dai->list, &component->dai_list);
+ return ret;
+}
+
+/**
+ * snd_soc_register_dai - Register a DAI dynamically & create its widgets
+ *
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAI
+ *
+ * Topology can use this API to register DAIs when probing a component.
+ * These DAIs's widgets will be freed in the card cleanup and the DAIs
+ * will be freed in the component cleanup.
+ */
+int snd_soc_register_dai(struct snd_soc_component *component,
+ struct snd_soc_dai_driver *dai_drv)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ struct snd_soc_dai *dai;
+ int ret;
- dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
+ if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) {
+ dev_err(component->dev, "Invalid dai type %d\n",
+ dai_drv->dobj.type);
+ return -EINVAL;
}
- return 0;
+ lockdep_assert_held(&client_mutex);
+ dai = soc_add_dai(component, dai_drv, false);
+ if (!dai)
+ return -ENOMEM;
-err:
- snd_soc_unregister_dais(component);
+ /* Create the DAI widgets here. After adding DAIs, topology may
+ * also add routes that need these widgets as source or sink.
+ */
+ ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to create DAI widgets %d\n", ret);
+ }
return ret;
}
+EXPORT_SYMBOL_GPL(snd_soc_register_dai);
static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm,
enum snd_soc_dapm_type type, int subseq)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7d009428934a..5a2812fa8946 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1300,7 +1300,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
{
- return 1;
+ return w->connected;
}
static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
@@ -3358,6 +3358,11 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
w->is_ep = SND_SOC_DAPM_EP_SOURCE;
w->power_check = dapm_always_on_check_power;
break;
+ case snd_soc_dapm_sink:
+ w->is_ep = SND_SOC_DAPM_EP_SINK;
+ w->power_check = dapm_always_on_check_power;
+ break;
+
case snd_soc_dapm_mux:
case snd_soc_dapm_demux:
case snd_soc_dapm_switch:
@@ -3900,13 +3905,10 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
{
- struct snd_soc_pcm_runtime *rtd = card->rtd;
- int i;
+ struct snd_soc_pcm_runtime *rtd;
/* for each BE DAI link... */
- for (i = 0; i < card->num_rtd; i++) {
- rtd = &card->rtd[i];
-
+ list_for_each_entry(rtd, &card->rtd_list, list) {
/*
* dynamic FE links have no fixed DAI mapping.
* CODEC<->CODEC links have no direct connection.
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 2f67ba6d7a8f..a513a34a51d2 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -779,11 +779,11 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag,
switch (op_flag) {
case SNDRV_CTL_TLV_OP_READ:
if (params->get)
- ret = params->get(tlv, count);
+ ret = params->get(kcontrol, tlv, count);
break;
case SNDRV_CTL_TLV_OP_WRITE:
if (params->put)
- ret = params->put(tlv, count);
+ ret = params->put(kcontrol, tlv, count);
break;
}
return ret;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index c86dc96e8986..e898b427be7e 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -599,10 +599,15 @@ platform_err:
out:
mutex_unlock(&rtd->pcm_mutex);
- pm_runtime_put(platform->dev);
- for (i = 0; i < rtd->num_codecs; i++)
- pm_runtime_put(rtd->codec_dais[i]->dev);
- pm_runtime_put(cpu_dai->dev);
+ pm_runtime_mark_last_busy(platform->dev);
+ pm_runtime_put_autosuspend(platform->dev);
+ for (i = 0; i < rtd->num_codecs; i++) {
+ pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
+ pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+ }
+
+ pm_runtime_mark_last_busy(cpu_dai->dev);
+ pm_runtime_put_autosuspend(cpu_dai->dev);
for (i = 0; i < rtd->num_codecs; i++) {
if (!rtd->codec_dais[i]->active)
pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -706,10 +711,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
mutex_unlock(&rtd->pcm_mutex);
- pm_runtime_put(platform->dev);
- for (i = 0; i < rtd->num_codecs; i++)
- pm_runtime_put(rtd->codec_dais[i]->dev);
- pm_runtime_put(cpu_dai->dev);
+ pm_runtime_mark_last_busy(platform->dev);
+ pm_runtime_put_autosuspend(platform->dev);
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
+ pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+ }
+
+ pm_runtime_mark_last_busy(cpu_dai->dev);
+ pm_runtime_put_autosuspend(cpu_dai->dev);
+
for (i = 0; i < rtd->num_codecs; i++) {
if (!rtd->codec_dais[i]->active)
pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -1213,11 +1225,10 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
struct snd_soc_dapm_widget *widget, int stream)
{
struct snd_soc_pcm_runtime *be;
- int i, j;
+ int i;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- for (i = 0; i < card->num_links; i++) {
- be = &card->rtd[i];
+ list_for_each_entry(be, &card->rtd_list, list) {
if (!be->dai_link->no_pcm)
continue;
@@ -1225,16 +1236,15 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
if (be->cpu_dai->playback_widget == widget)
return be;
- for (j = 0; j < be->num_codecs; j++) {
- struct snd_soc_dai *dai = be->codec_dais[j];
+ for (i = 0; i < be->num_codecs; i++) {
+ struct snd_soc_dai *dai = be->codec_dais[i];
if (dai->playback_widget == widget)
return be;
}
}
} else {
- for (i = 0; i < card->num_links; i++) {
- be = &card->rtd[i];
+ list_for_each_entry(be, &card->rtd_list, list) {
if (!be->dai_link->no_pcm)
continue;
@@ -1242,8 +1252,8 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
if (be->cpu_dai->capture_widget == widget)
return be;
- for (j = 0; j < be->num_codecs; j++) {
- struct snd_soc_dai *dai = be->codec_dais[j];
+ for (i = 0; i < be->num_codecs; i++) {
+ struct snd_soc_dai *dai = be->codec_dais[i];
if (dai->capture_widget == widget)
return be;
}
@@ -1616,6 +1626,56 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
snd_pcm_stream_unlock_irq(substream);
}
+static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
+ int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+ struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
+ int err;
+
+ /* apply symmetry for FE */
+ if (soc_pcm_has_symmetry(fe_substream))
+ fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+ /* Symmetry only applies if we've got an active stream. */
+ if (fe_cpu_dai->active) {
+ err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
+ if (err < 0)
+ return err;
+ }
+
+ /* apply symmetry for BE */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+ struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
+ int i;
+
+ if (soc_pcm_has_symmetry(be_substream))
+ be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+ /* Symmetry only applies if we've got an active stream. */
+ if (rtd->cpu_dai->active) {
+ err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ if (rtd->codec_dais[i]->active) {
+ err = soc_pcm_apply_symmetry(be_substream,
+ rtd->codec_dais[i]);
+ if (err < 0)
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
{
struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
@@ -1644,6 +1704,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
dpcm_set_fe_runtime(fe_substream);
snd_pcm_limit_hw_rates(runtime);
+ ret = dpcm_apply_symmetry(fe_substream, stream);
+ if (ret < 0) {
+ dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
+ ret);
+ goto unwind;
+ }
+
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
return 0;
@@ -2115,7 +2182,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
continue;
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
- (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
continue;
dev_dbg(be->dev, "ASoC: prepare BE %s\n",
@@ -2343,12 +2411,12 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
*/
int soc_dpcm_runtime_update(struct snd_soc_card *card)
{
- int i, old, new, paths;
+ struct snd_soc_pcm_runtime *fe;
+ int old, new, paths;
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- for (i = 0; i < card->num_rtd; i++) {
+ list_for_each_entry(fe, &card->rtd_list, list) {
struct snd_soc_dapm_widget_list *list;
- struct snd_soc_pcm_runtime *fe = &card->rtd[i];
/* make sure link is FE */
if (!fe->dai_link->dynamic)
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index 5c2bc53f0a9b..7aca6b92f718 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -251,8 +251,7 @@ static void uni_player_set_channel_status(struct uniperif *player,
* set one.
*/
mutex_lock(&player->ctrl_lock);
- if (runtime && (player->stream_settings.iec958.status[3]
- == IEC958_AES3_CON_FS_NOTID)) {
+ if (runtime) {
switch (runtime->rate) {
case 22050:
player->stream_settings.iec958.status[3] =
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 1bb896d78d09..44f170c73b06 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -28,6 +28,7 @@
#include <linux/of_address.h>
#include <linux/clk.h>
#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -70,6 +71,7 @@
/* Codec ADC register offsets and bit fields */
#define SUN4I_CODEC_ADC_FIFOC (0x1c)
+#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29)
#define SUN4I_CODEC_ADC_FIFOC_EN_AD (28)
#define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE (24)
#define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (8)
@@ -102,17 +104,14 @@ struct sun4i_codec {
struct regmap *regmap;
struct clk *clk_apb;
struct clk *clk_module;
+ struct gpio_desc *gpio_pa;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
};
static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
{
- /*
- * FIXME: according to the BSP, we might need to drive a PA
- * GPIO high here on some boards
- */
-
/* Flush TX FIFO */
regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
@@ -126,37 +125,50 @@ static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
{
- /*
- * FIXME: according to the BSP, we might need to drive a PA
- * GPIO low here on some boards
- */
-
/* Disable DAC DRQ */
regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
0);
}
+static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
+{
+ /* Enable ADC DRQ */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
+}
+
+static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
+{
+ /* Disable ADC DRQ */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
+}
+
static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
- if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
- return -ENOTSUPP;
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- sun4i_codec_start_playback(scodec);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sun4i_codec_start_playback(scodec);
+ else
+ sun4i_codec_start_capture(scodec);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- sun4i_codec_stop_playback(scodec);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sun4i_codec_stop_playback(scodec);
+ else
+ sun4i_codec_stop_capture(scodec);
break;
default:
@@ -166,15 +178,54 @@ static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
- u32 val;
- if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
- return -ENOTSUPP;
+
+ /* Flush RX FIFO */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
+ BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
+
+
+ /* Set RX FIFO trigger level */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
+ 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
+
+ /*
+ * FIXME: Undocumented in the datasheet, but
+ * Allwinner's code mentions that it is related
+ * related to microphone gain
+ */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
+ 0x3 << 25,
+ 0x1 << 25);
+
+ if (of_device_is_compatible(scodec->dev->of_node,
+ "allwinner,sun7i-a20-codec"))
+ /* FIXME: Undocumented bits */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
+ 0x3 << 8,
+ 0x1 << 8);
+
+ /* Fill most significant bits with valid data MSB */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
+
+ return 0;
+}
+
+static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+ u32 val;
/* Flush the TX FIFO */
regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
@@ -203,6 +254,15 @@ static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
0);
return 0;
+};
+
+static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return sun4i_codec_prepare_playback(substream, dai);
+
+ return sun4i_codec_prepare_capture(substream, dai);
}
static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
@@ -277,30 +337,32 @@ static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
}
}
-static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
+ struct snd_pcm_hw_params *params,
+ unsigned int hwrate)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
- unsigned long clk_freq;
- int ret, hwrate;
- u32 val;
-
- if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
- return -ENOTSUPP;
+ /* Set ADC sample rate */
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
+ hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
- clk_freq = sun4i_codec_get_mod_freq(params);
- if (!clk_freq)
- return -EINVAL;
+ /* Set the number of channels we want to use */
+ if (params_channels(params) == 1)
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
+ else
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0);
- ret = clk_set_rate(scodec->clk_module, clk_freq);
- if (ret)
- return ret;
+ return 0;
+}
- hwrate = sun4i_codec_get_hw_rate(params);
- if (hwrate < 0)
- return hwrate;
+static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
+ struct snd_pcm_hw_params *params,
+ unsigned int hwrate)
+{
+ u32 val;
/* Set DAC sample rate */
regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
@@ -345,6 +407,35 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+ unsigned long clk_freq;
+ int ret, hwrate;
+
+ clk_freq = sun4i_codec_get_mod_freq(params);
+ if (!clk_freq)
+ return -EINVAL;
+
+ ret = clk_set_rate(scodec->clk_module, clk_freq);
+ if (ret)
+ return ret;
+
+ hwrate = sun4i_codec_get_hw_rate(params);
+ if (hwrate < 0)
+ return hwrate;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return sun4i_codec_hw_params_playback(scodec, params,
+ hwrate);
+
+ return sun4i_codec_hw_params_capture(scodec, params,
+ hwrate);
+}
+
static int sun4i_codec_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -395,6 +486,20 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 24,
},
+ .capture = {
+ .stream_name = "Codec Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000 |
+ SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .sig_bits = 24,
+ },
};
/*** Codec ***/
@@ -429,12 +534,23 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
};
-static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
+ /* Digital parts of the ADCs */
+ SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
+ SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
+ NULL, 0),
+
/* Digital parts of the DACs */
SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
SUN4I_CODEC_DAC_DPC_EN_DA, 0,
NULL, 0),
+ /* Analog parts of the ADCs */
+ SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
+ SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
+ SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
+
/* Analog parts of the DACs */
SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
@@ -453,6 +569,14 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
+ /* VMIC */
+ SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
+ SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
+
+ /* Mic Pre-Amplifiers */
+ SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+ SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
+
/* Power Amplifier */
SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
@@ -461,15 +585,19 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
&sun4i_codec_pa_mute),
+ SND_SOC_DAPM_INPUT("Mic1"),
+
SND_SOC_DAPM_OUTPUT("HP Right"),
SND_SOC_DAPM_OUTPUT("HP Left"),
};
-static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
- /* Left DAC Routes */
+static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
+ /* Left ADC / DAC Routes */
+ { "Left ADC", NULL, "ADC" },
{ "Left DAC", NULL, "DAC" },
- /* Right DAC Routes */
+ /* Right ADC / DAC Routes */
+ { "Right ADC", NULL, "ADC" },
{ "Right DAC", NULL, "DAC" },
/* Right Mixer Routes */
@@ -491,15 +619,21 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
{ "Power Amplifier Mute", "Switch", "Power Amplifier" },
{ "HP Right", NULL, "Power Amplifier Mute" },
{ "HP Left", NULL, "Power Amplifier Mute" },
+
+ /* Mic1 Routes */
+ { "Left ADC", NULL, "MIC1 Pre-Amplifier" },
+ { "Right ADC", NULL, "MIC1 Pre-Amplifier" },
+ { "MIC1 Pre-Amplifier", NULL, "Mic1"},
+ { "Mic1", NULL, "VMIC" },
};
static struct snd_soc_codec_driver sun4i_codec_codec = {
.controls = sun4i_codec_widgets,
.num_controls = ARRAY_SIZE(sun4i_codec_widgets),
- .dapm_widgets = sun4i_codec_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_dapm_widgets),
- .dapm_routes = sun4i_codec_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(sun4i_codec_dapm_routes),
+ .dapm_widgets = sun4i_codec_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
+ .dapm_routes = sun4i_codec_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
};
static const struct snd_soc_component_driver sun4i_codec_component = {
@@ -516,7 +650,7 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
- NULL);
+ &scodec->capture_dma_data);
return 0;
}
@@ -532,6 +666,14 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
.formats = SUN4I_CODEC_FORMATS,
.sig_bits = 24,
},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SUN4I_CODEC_RATES,
+ .formats = SUN4I_CODEC_FORMATS,
+ .sig_bits = 24,
+ },
};
static const struct regmap_config sun4i_codec_regmap_config = {
@@ -569,6 +711,27 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
return link;
};
+static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
+
+ if (scodec->gpio_pa)
+ gpiod_set_value_cansleep(scodec->gpio_pa,
+ !!SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
+static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
+ { "Speaker", NULL, "HP Right" },
+ { "Speaker", NULL, "HP Left" },
+};
+
static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
{
struct snd_soc_card *card;
@@ -583,6 +746,10 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
card->dev = dev;
card->name = "sun4i-codec";
+ card->dapm_widgets = sun4i_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
+ card->dapm_routes = sun4i_codec_card_dapm_routes;
+ card->num_dapm_routes = ARRAY_SIZE(sun4i_codec_card_dapm_routes);
return card;
};
@@ -634,11 +801,25 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return -EINVAL;
}
+ scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(scodec->gpio_pa)) {
+ ret = PTR_ERR(scodec->gpio_pa);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret);
+ return ret;
+ }
+
/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
scodec->playback_dma_data.maxburst = 4;
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ /* DMA configuration for RX FIFO */
+ scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA;
+ scodec->capture_dma_data.maxburst = 4;
+ scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
&sun4i_codec_dai, 1);
if (ret) {
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index ba272e21a6fa..deb597f7c302 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -101,12 +101,16 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = {
static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
{
+ int ret;
struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card);
- snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
- &tegra_alc5632_hs_jack,
- tegra_alc5632_hs_jack_pins,
- ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
+ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET,
+ &tegra_alc5632_hs_jack,
+ tegra_alc5632_hs_jack_pins,
+ ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
+ if (ret)
+ return ret;
if (gpio_is_valid(machine->gpio_hp_det)) {
tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 21604009bc1a..e485278e027a 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -199,7 +199,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
static int tegra_wm8903_remove(struct snd_soc_card *card)
{
- struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]);
+ struct snd_soc_pcm_runtime *rtd =
+ snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = codec_dai->codec;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c
index 00fc005ecf6e..9729a15b6ae6 100644
--- a/sound/synth/emux/emux_nrpn.c
+++ b/sound/synth/emux/emux_nrpn.c
@@ -48,7 +48,8 @@ struct nrpn_conv_table {
* convert NRPN/control values
*/
-static int send_converted_effect(struct nrpn_conv_table *table, int num_tables,
+static int send_converted_effect(const struct nrpn_conv_table *table,
+ int num_tables,
struct snd_emux_port *port,
struct snd_midi_channel *chan,
int type, int val, int mode)
@@ -179,7 +180,7 @@ static int fx_conv_Q(int val)
}
-static struct nrpn_conv_table awe_effects[] =
+static const struct nrpn_conv_table awe_effects[] =
{
{ 0, EMUX_FX_LFO1_DELAY, fx_lfo1_delay},
{ 1, EMUX_FX_LFO1_FREQ, fx_lfo1_freq},
@@ -266,7 +267,7 @@ static int gs_vib_delay(int val)
return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
}
-static struct nrpn_conv_table gs_effects[] =
+static const struct nrpn_conv_table gs_effects[] =
{
{32, EMUX_FX_CUTOFF, gs_cutoff},
{33, EMUX_FX_FILTERQ, gs_filterQ},
@@ -350,7 +351,7 @@ static int xg_release(int val)
return -(val - 64) * xg_sense[FX_RELEASE] / 64;
}
-static struct nrpn_conv_table xg_effects[] =
+static const struct nrpn_conv_table xg_effects[] =
{
{71, EMUX_FX_CUTOFF, xg_cutoff},
{74, EMUX_FX_FILTERQ, xg_filterQ},
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 62c25e74f0e5..9520b4cd7038 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -350,7 +350,7 @@ static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
if (!memcmp(version, known_fw_versions + i, 2))
return 0;
- dev_err(&intf->dev, "invalid fimware version in device: %4ph. "
+ dev_err(&intf->dev, "invalid firmware version in device: %4ph. "
"please reconnect to power. if this failure "
"still happens, check your firmware installation.",
version);
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 18f56646ce86..1f09d9591276 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -675,6 +675,8 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
void snd_usb_autosuspend(struct snd_usb_audio *chip)
{
+ if (atomic_read(&chip->shutdown))
+ return;
if (atomic_dec_and_test(&chip->active))
usb_autopm_put_interface(chip->pm_intf);
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 5b4c58c3e2c5..cc39f63299ef 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -112,7 +112,7 @@ struct snd_usb_midi {
struct usb_interface *iface;
const struct snd_usb_audio_quirk *quirk;
struct snd_rawmidi *rmidi;
- struct usb_protocol_ops *usb_protocol_ops;
+ const struct usb_protocol_ops *usb_protocol_ops;
struct list_head list;
struct timer_list error_timer;
spinlock_t disc_lock;
@@ -671,31 +671,32 @@ static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep,
}
}
-static struct usb_protocol_ops snd_usbmidi_standard_ops = {
+static const struct usb_protocol_ops snd_usbmidi_standard_ops = {
.input = snd_usbmidi_standard_input,
.output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_standard_packet,
};
-static struct usb_protocol_ops snd_usbmidi_midiman_ops = {
+static const struct usb_protocol_ops snd_usbmidi_midiman_ops = {
.input = snd_usbmidi_midiman_input,
.output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_midiman_packet,
};
-static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = {
+static const
+struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = {
.input = snd_usbmidi_maudio_broken_running_status_input,
.output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_standard_packet,
};
-static struct usb_protocol_ops snd_usbmidi_cme_ops = {
+static const struct usb_protocol_ops snd_usbmidi_cme_ops = {
.input = snd_usbmidi_cme_input,
.output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_standard_packet,
};
-static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
+static const struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
.input = ch345_broken_sysex_input,
.output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_standard_packet,
@@ -795,7 +796,7 @@ static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep,
}
}
-static struct usb_protocol_ops snd_usbmidi_akai_ops = {
+static const struct usb_protocol_ops snd_usbmidi_akai_ops = {
.input = snd_usbmidi_akai_input,
.output = snd_usbmidi_akai_output,
};
@@ -835,7 +836,7 @@ static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint *ep,
urb->transfer_buffer_length = 2 + count;
}
-static struct usb_protocol_ops snd_usbmidi_novation_ops = {
+static const struct usb_protocol_ops snd_usbmidi_novation_ops = {
.input = snd_usbmidi_novation_input,
.output = snd_usbmidi_novation_output,
};
@@ -867,7 +868,7 @@ static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint *ep,
urb->transfer_buffer_length = count;
}
-static struct usb_protocol_ops snd_usbmidi_raw_ops = {
+static const struct usb_protocol_ops snd_usbmidi_raw_ops = {
.input = snd_usbmidi_raw_input,
.output = snd_usbmidi_raw_output,
};
@@ -883,7 +884,7 @@ static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint *ep,
snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2);
}
-static struct usb_protocol_ops snd_usbmidi_ftdi_ops = {
+static const struct usb_protocol_ops snd_usbmidi_ftdi_ops = {
.input = snd_usbmidi_ftdi_input,
.output = snd_usbmidi_raw_output,
};
@@ -927,7 +928,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
urb->transfer_buffer_length = ep->max_transfer;
}
-static struct usb_protocol_ops snd_usbmidi_122l_ops = {
+static const struct usb_protocol_ops snd_usbmidi_122l_ops = {
.input = snd_usbmidi_us122l_input,
.output = snd_usbmidi_us122l_output,
};
@@ -1060,7 +1061,7 @@ static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint *ep,
urb->transfer_buffer_length = ep->max_transfer - buf_free;
}
-static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
+static const struct usb_protocol_ops snd_usbmidi_emagic_ops = {
.input = snd_usbmidi_emagic_input,
.output = snd_usbmidi_emagic_output,
.init_out_endpoint = snd_usbmidi_emagic_init_out,
@@ -2206,7 +2207,7 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi,
return 0;
}
-static struct snd_rawmidi_global_ops snd_usbmidi_ops = {
+static const struct snd_rawmidi_global_ops snd_usbmidi_ops = {
.get_port_info = snd_usbmidi_get_port_info,
};
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 9581089c28c5..c19a5dd05631 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -1037,7 +1037,7 @@ static int detect_usb_format(struct ua101 *ua)
return -ENXIO;
}
ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd));
- ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize);
+ ua->capture.max_packet_bytes = usb_endpoint_maxp(epd);
epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc;
if (!usb_endpoint_is_isoc_out(epd)) {
@@ -1045,7 +1045,7 @@ static int detect_usb_format(struct ua101 *ua)
return -ENXIO;
}
ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd));
- ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize);
+ ua->playback.max_packet_bytes = usb_endpoint_maxp(epd);
return 0;
}
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 0ce888dceed0..279025650568 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -793,7 +793,7 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
return 0;
kcontrol->private_value &= ~(0xff << 24);
- kcontrol->private_value |= newval;
+ kcontrol->private_value |= (unsigned int)newval << 24;
err = snd_ni_update_cur_val(list);
return err < 0 ? err : 1;
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index b6c0c8e3b450..23ea6d800c4c 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1269,6 +1269,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */
case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
+ case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/
if (fp->altsetting == 2)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 8ee14f2365e7..c4dc577ab1bd 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -125,11 +125,9 @@ static int usb_chmap_ctl_info(struct snd_kcontrol *kcontrol,
static bool have_dup_chmap(struct snd_usb_substream *subs,
struct audioformat *fp)
{
- struct list_head *p;
+ struct audioformat *prev = fp;
- for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) {
- struct audioformat *prev;
- prev = list_entry(p, struct audioformat, list);
+ list_for_each_entry_continue_reverse(prev, &subs->fmt_list, list) {
if (prev->chmap &&
!memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap)))
return true;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 61d5dc2a3421..dd40ca9d858a 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -166,7 +166,7 @@ static int usX2Y_urb_play_prepare(struct snd_usX2Y_substream *subs,
/* set the buffer pointer */
urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride;
if ((subs->hwptr += count) >= runtime->buffer_size)
- subs->hwptr -= runtime->buffer_size;
+ subs->hwptr -= runtime->buffer_size;
}
else
urb->transfer_buffer = subs->tmpbuf;
diff --git a/tools/Makefile b/tools/Makefile
index 0ba0df3b516f..6339f6ac3ccb 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,23 +8,24 @@ include scripts/Makefile.include
help:
@echo 'Possible targets:'
@echo ''
- @echo ' acpi - ACPI tools'
- @echo ' cgroup - cgroup tools'
- @echo ' cpupower - a tool for all things x86 CPU power'
- @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
- @echo ' hv - tools used when in Hyper-V clients'
- @echo ' iio - IIO tools'
- @echo ' lguest - a minimal 32-bit x86 hypervisor'
- @echo ' perf - Linux performance measurement and analysis tool'
- @echo ' selftests - various kernel selftests'
- @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
- @echo ' usb - USB testing tools'
- @echo ' virtio - vhost test module'
- @echo ' net - misc networking tools'
- @echo ' vm - misc vm tools'
+ @echo ' acpi - ACPI tools'
+ @echo ' cgroup - cgroup tools'
+ @echo ' cpupower - a tool for all things x86 CPU power'
+ @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
+ @echo ' freefall - laptop accelerometer program for disk protection'
+ @echo ' hv - tools used when in Hyper-V clients'
+ @echo ' iio - IIO tools'
+ @echo ' lguest - a minimal 32-bit x86 hypervisor'
+ @echo ' net - misc networking tools'
+ @echo ' perf - Linux performance measurement and analysis tool'
+ @echo ' selftests - various kernel selftests'
+ @echo ' spi - spi tools'
+ @echo ' tmon - thermal monitoring and tuning tool'
+ @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
+ @echo ' usb - USB testing tools'
+ @echo ' virtio - vhost test module'
+ @echo ' vm - misc vm tools'
@echo ' x86_energy_perf_policy - Intel energy policy tool'
- @echo ' tmon - thermal monitoring and tuning tool'
- @echo ' freefall - laptop accelerometer program for disk protection'
@echo ''
@echo 'You can do:'
@echo ' $$ make -C tools/ <tool>_install'
@@ -52,7 +53,7 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)
-cgroup firewire hv guest usb virtio vm net iio: FORCE
+cgroup firewire hv guest spi usb virtio vm net iio: FORCE
$(call descend,$@)
liblockdep: FORCE
@@ -118,7 +119,7 @@ acpi_clean:
cpupower_clean:
$(call descend,power/cpupower,clean)
-cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean iio_clean:
+cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean:
$(call descend,$(@:_clean=),clean)
liblockdep_clean:
@@ -127,6 +128,12 @@ liblockdep_clean:
libapi_clean:
$(call descend,lib/api,clean)
+libbpf_clean:
+ $(call descend,lib/bpf,clean)
+
+libsubcmd_clean:
+ $(call descend,lib/subcmd,clean)
+
perf_clean:
$(call descend,$(@:_clean=),clean)
@@ -142,9 +149,12 @@ tmon_clean:
freefall_clean:
$(call descend,laptop/freefall,clean)
+build_clean:
+ $(call descend,build,clean)
+
clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
- perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \
+ perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
- freefall_clean
+ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean
.PHONY: FORCE
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 33cf6f20bd4e..81025cade45f 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -125,6 +125,10 @@
# include "test-get_cpuid.c"
#undef main
+#define main main_test_bpf
+# include "test-bpf.c"
+#undef main
+
int main(int argc, char *argv[])
{
main_test_libpython();
@@ -153,6 +157,7 @@ int main(int argc, char *argv[])
main_test_pthread_attr_setaffinity_np();
main_test_lzma();
main_test_get_cpuid();
+ main_test_bpf();
return 0;
}
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c
index 062bac811af9..b389026839b9 100644
--- a/tools/build/feature/test-bpf.c
+++ b/tools/build/feature/test-bpf.c
@@ -1,9 +1,23 @@
+#include <asm/unistd.h>
#include <linux/bpf.h>
+#include <unistd.h>
+
+#ifndef __NR_bpf
+# if defined(__i386__)
+# define __NR_bpf 357
+# elif defined(__x86_64__)
+# define __NR_bpf 321
+# elif defined(__aarch64__)
+# define __NR_bpf 280
+# error __NR_bpf not defined. libbpf does not support your arch.
+# endif
+#endif
int main(void)
{
union bpf_attr attr;
+ /* Check fields in attr */
attr.prog_type = BPF_PROG_TYPE_KPROBE;
attr.insn_cnt = 0;
attr.insns = 0;
@@ -14,5 +28,9 @@ int main(void)
attr.kern_version = 0;
attr = attr;
- return 0;
+ /*
+ * Test existence of __NR_bpf and BPF_PROG_LOAD.
+ * This call should fail if we run the testcase.
+ */
+ return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr));
}
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index 5480e4e424eb..fdc9ca4c0356 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -37,12 +37,14 @@
static int target_fd;
static char target_fname[W_MAX_PATH];
+static unsigned long long filesize;
static int hv_start_fcopy(struct hv_start_fcopy *smsg)
{
int error = HV_E_FAIL;
char *q, *p;
+ filesize = 0;
p = (char *)smsg->path_name;
snprintf(target_fname, sizeof(target_fname), "%s/%s",
(char *)smsg->path_name, (char *)smsg->file_name);
@@ -98,14 +100,26 @@ done:
static int hv_copy_data(struct hv_do_fcopy *cpmsg)
{
ssize_t bytes_written;
+ int ret = 0;
bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
cpmsg->offset);
- if (bytes_written != cpmsg->size)
- return HV_E_FAIL;
+ filesize += cpmsg->size;
+ if (bytes_written != cpmsg->size) {
+ switch (errno) {
+ case ENOSPC:
+ ret = HV_ERROR_DISK_FULL;
+ break;
+ default:
+ ret = HV_E_FAIL;
+ break;
+ }
+ syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
+ filesize, (long)bytes_written, strerror(errno));
+ }
- return 0;
+ return ret;
}
static int hv_copy_finished(void)
@@ -165,7 +179,7 @@ int main(int argc, char *argv[])
}
openlog("HV_FCOPY", 0, LOG_USER);
- syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
+ syslog(LOG_INFO, "starting; pid is:%d", getpid());
fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
@@ -201,7 +215,7 @@ int main(int argc, char *argv[])
}
kernel_modver = *(__u32 *)buffer;
in_handshake = 0;
- syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d",
+ syslog(LOG_INFO, "kernel module version: %d",
kernel_modver);
continue;
}
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 96234b638249..5d51d6ff08e6 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -254,7 +254,7 @@ int main(int argc, char *argv[])
syslog(LOG_ERR, "Illegal op:%d\n", op);
}
vss_msg->error = error;
- len = write(vss_fd, &error, sizeof(struct hv_vss_msg));
+ len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
if (len != sizeof(struct hv_vss_msg)) {
syslog(LOG_ERR, "write failed; error: %d %s", errno,
strerror(errno));
diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h
index a017f1595676..1da423820ad4 100644
--- a/tools/include/linux/list.h
+++ b/tools/include/linux/list.h
@@ -1,11 +1,751 @@
-#include <linux/compiler.h>
-#include <linux/kernel.h>
+#ifndef __TOOLS_LINUX_LIST_H
+#define __TOOLS_LINUX_LIST_H
+
#include <linux/types.h>
+#include <linux/poison.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+#else
+extern void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next);
+#endif
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ WRITE_ONCE(prev->next, next);
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+#else
+extern void __list_del_entry(struct list_head *entry);
+extern void list_del(struct list_head *entry);
+#endif
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del_entry(entry);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del_entry(list);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del_entry(list);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head *head)
+{
+ struct list_head *first;
+
+ if (!list_empty(head)) {
+ first = head->next;
+ list_move_tail(first, head);
+ }
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ struct list_head *new_first = entry->next;
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = entry;
+ entry->next = list;
+ head->next = new_first;
+ new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ * and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ if (list_empty(head))
+ return;
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
+ return;
+ if (entry == head)
+ INIT_LIST_HEAD(list);
+ else
+ __list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+
+ first->prev = prev;
+ prev->next = first;
+
+ last->next = next;
+ next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head, head->next);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head->prev, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+/**
+ * list_first_entry_or_null - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
+ */
+#define list_first_entry_or_null(ptr, type, member) \
+ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_prev_entry - get the prev element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_prev_entry(pos, member) \
+ list_entry((pos)->member.prev, typeof(*(pos)), member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+ for (pos = (head)->prev, n = pos->prev; \
+ pos != (head); \
+ pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_last_entry(head, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_prev_entry(pos, member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_head within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_next_entry(pos, member); \
+ &pos->member != (head); \
+ pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_prev_entry(pos, member); \
+ &pos->member != (head); \
+ pos = list_prev_entry(pos, member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; &pos->member != (head); \
+ pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member), \
+ n = list_next_entry(pos, member); \
+ &pos->member != (head); \
+ pos = n, n = list_next_entry(n, member))
+
+/**
+ * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_next_entry(pos, member), \
+ n = list_next_entry(pos, member); \
+ &pos->member != (head); \
+ pos = n, n = list_next_entry(n, member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_next_entry(pos, member); \
+ &pos->member != (head); \
+ pos = n, n = list_next_entry(n, member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_last_entry(head, typeof(*pos), member), \
+ n = list_prev_entry(pos, member); \
+ &pos->member != (head); \
+ pos = n, n = list_prev_entry(n, member))
-#include "../../../include/linux/list.h"
+/**
+ * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
+ * @pos: the loop cursor used in the list_for_each_entry_safe loop
+ * @n: temporary storage used in list_for_each_entry_safe
+ * @member: the name of the list_head within the struct.
+ *
+ * list_safe_reset_next is not safe to use in general if the list may be
+ * modified concurrently (eg. the lock is dropped in the loop body). An
+ * exception to this is if the cursor element (pos) is pinned in the list,
+ * and list_safe_reset_next is called after re-taking the lock and before
+ * completing the current iteration of the loop body.
+ */
+#define list_safe_reset_next(pos, n, member) \
+ n = list_next_entry(pos, member)
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+
+ WRITE_ONCE(*pprev, next);
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_behind(struct hlist_node *n,
+ struct hlist_node *prev)
+{
+ n->next = prev->next;
+ prev->next = n;
+ n->pprev = &prev->next;
+
+ if (n->next)
+ n->next->pprev = &n->next;
+}
+
+/* after that we'll appear to be on some hlist and hlist_del will work */
+static inline void hlist_add_fake(struct hlist_node *n)
+{
+ n->pprev = &n->next;
+}
+
+static inline bool hlist_fake(struct hlist_node *h)
+{
+ return h->pprev == &h->next;
+}
+
+/*
+ * Move a list from one list head to another. Fixup the pprev
+ * reference of the first entry if it exists.
+ */
+static inline void hlist_move_list(struct hlist_head *old,
+ struct hlist_head *new)
+{
+ new->first = old->first;
+ if (new->first)
+ new->first->pprev = &new->first;
+ old->first = NULL;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos ; pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+#define hlist_entry_safe(ptr, type, member) \
+ ({ typeof(ptr) ____ptr = (ptr); \
+ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+ })
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(pos, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+ pos; \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @pos: the type * to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(pos, member) \
+ for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
+ pos; \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @pos: the type * to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(pos, member) \
+ for (; pos; \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
+ pos && ({ n = pos->member.next; 1; }); \
+ pos = hlist_entry_safe(n, typeof(*pos), member))
-#ifndef TOOLS_LIST_H
-#define TOOLS_LIST_H
/**
* list_del_range - deletes range of entries from list.
* @begin: first element in the range to delete from the list.
@@ -27,4 +767,5 @@ static inline void list_del_range(struct list_head *begin,
*/
#define list_for_each_from(pos, head) \
for (; pos != (head); pos = pos->next)
-#endif
+
+#endif /* __TOOLS_LINUX_LIST_H */
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index 919b71780710..fc1bc75ae56d 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -6,6 +6,12 @@ BPF_EXTRAVERSION = 1
MAKEFLAGS += --no-print-directory
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
# Makefiles suck: This macro sets a default value of $(2) for the
# variable named by $(1), unless the variable has been set by
@@ -31,7 +37,8 @@ INSTALL = install
DESTDIR ?=
DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
-LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+include $(srctree)/tools/scripts/Makefile.arch
+
ifeq ($(LP64), 1)
libdir_relative = lib64
else
@@ -57,13 +64,6 @@ ifndef VERBOSE
VERBOSE = 0
endif
-ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
-srctree := $(patsubst %/,%,$(dir $(srctree)))
-srctree := $(patsubst %/,%,$(dir $(srctree)))
-#$(info Determined 'srctree' to be $(srctree))
-endif
-
FEATURE_USER = .libbpf
FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf
FEATURE_DISPLAY = libelf bpf
@@ -192,7 +192,7 @@ config-clean:
$(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null
clean:
- $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
+ $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd \
$(RM) LIBBPF-CFLAGS
$(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 5bdc6eab6852..1f91cc941b7c 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -14,8 +14,8 @@
#include "bpf.h"
/*
- * When building perf, unistd.h is override. Define __NR_bpf is
- * required to be defined.
+ * When building perf, unistd.h is overrided. __NR_bpf is
+ * required to be defined explicitly.
*/
#ifndef __NR_bpf
# if defined(__i386__)
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
index 7e319afac78a..90d2baeb621a 100644
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -149,7 +149,7 @@ install_lib: all_cmd
install: install_lib
clean:
- $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d
+ $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d .*.cmd
$(RM) tags TAGS
PHONY += force
diff --git a/tools/lib/subcmd/parse-options.h b/tools/lib/subcmd/parse-options.h
index 13a2cc1d6140..d60cab2726da 100644
--- a/tools/lib/subcmd/parse-options.h
+++ b/tools/lib/subcmd/parse-options.h
@@ -4,6 +4,10 @@
#include <stdbool.h>
#include <stdint.h>
+#ifndef NORETURN
+#define NORETURN __attribute__((__noreturn__))
+#endif
+
enum parse_opt_type {
/* special types */
OPTION_END,
diff --git a/tools/perf/Build b/tools/perf/Build
index 6b67e6f4179f..a43fae7f439a 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -42,6 +42,7 @@ CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \
-include $(OUTPUT)PERF-VERSION-FILE
CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
+CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
libperf-y += util/
libperf-y += arch/
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 3a1a32f5479f..fbceb631387c 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -338,6 +338,9 @@ Options passed to clang when compiling BPF scriptlets.
Specify vmlinux path which has debuginfo.
(enabled when BPF prologue is on)
+--buildid-all::
+Record build-id of all DSOs regardless whether it's actually hit or not.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index a1c10e360db5..e0ce9573b79b 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -12,3 +12,18 @@ List events using substring match: perf list <keyword>
To see list of saved events and attributes: perf evlist -v
Use --symfs <dir> if your symbol files are in non-standard locations
To see callchains in a more compact form: perf report -g folded
+Show individual samples with: perf script
+Limit to show entries above 5% only: perf report --percent-limit 5
+Profiling branch (mis)predictions with: perf record -b / perf report
+Treat branches as callchains: perf report --branch-history
+To count events in every 1000 msec: perf stat -I 1000
+Print event counts in CSV format with: perf stat -x,
+If you have debuginfo enabled, try: perf report -s sym,srcline
+For memory address profiling, try: perf mem record / perf mem report
+For tracepoint events, try: perf report -s trace_fields
+To record callchains for each sample: perf record -g
+To record every process run by an user: perf record -u <user>
+Skip collecing build-id when recording: perf record -B
+To change sampling frequency to 100 Hz: perf record -F 100
+See assembly instructions with percentage: perf annotate <symbol>
+If you prefer Intel style assembly, try: perf annotate -M intel
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index ddf922f93aa1..2e1fa2357528 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -28,6 +28,7 @@ tools/lib/string.c
tools/lib/symbol/kallsyms.c
tools/lib/symbol/kallsyms.h
tools/lib/find_bit.c
+tools/lib/bitmap.c
tools/include/asm/atomic.h
tools/include/asm/barrier.h
tools/include/asm/bug.h
@@ -57,6 +58,7 @@ tools/include/linux/rbtree_augmented.h
tools/include/linux/string.h
tools/include/linux/types.h
tools/include/linux/err.h
+tools/include/linux/bitmap.h
include/asm-generic/bitops/arch_hweight.h
include/asm-generic/bitops/const_hweight.h
include/asm-generic/bitops/fls64.h
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index dc4e0adf5c5b..319712a4e02b 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -50,6 +50,7 @@ struct record {
int realtime_prio;
bool no_buildid;
bool no_buildid_cache;
+ bool buildid_all;
unsigned long long samples;
};
@@ -362,6 +363,13 @@ static int process_buildids(struct record *rec)
*/
symbol_conf.ignore_vmlinux_buildid = true;
+ /*
+ * If --buildid-all is given, it marks all DSO regardless of hits,
+ * so no need to process samples.
+ */
+ if (rec->buildid_all)
+ rec->tool.sample = NULL;
+
return perf_session__process_events(session);
}
@@ -756,12 +764,8 @@ out_child:
if (!rec->no_buildid) {
process_buildids(rec);
- /*
- * We take all buildids when the file contains
- * AUX area tracing data because we do not decode the
- * trace because it would take too long.
- */
- if (rec->opts.full_auxtrace)
+
+ if (rec->buildid_all)
dsos__hit_all(rec->session);
}
perf_session__write_header(rec->session, rec->evlist, fd, true);
@@ -1138,6 +1142,8 @@ struct option __record_options[] = {
"options passed to clang when compiling BPF scriptlets"),
OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
+ OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
+ "Record build-id of all DSOs regardless of hits"),
OPT_END()
};
@@ -1255,6 +1261,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
if (err)
goto out_symbol_exit;
+ /*
+ * We take all buildids when the file contains
+ * AUX area tracing data because we do not decode the
+ * trace because it would take too long.
+ */
+ if (rec->opts.full_auxtrace)
+ rec->buildid_all = true;
+
if (record_opts__config(&rec->opts)) {
err = -EINVAL;
goto out_symbol_exit;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d5a42ee12529..2bf537f190a0 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -28,6 +28,7 @@
#include "util/tool.h"
#include <subcmd/parse-options.h>
+#include <subcmd/exec-cmd.h>
#include "util/parse-events.h"
#include "util/thread.h"
@@ -433,7 +434,14 @@ static int report__browse_hists(struct report *rep)
int ret;
struct perf_session *session = rep->session;
struct perf_evlist *evlist = session->evlist;
- const char *help = perf_tip(TIPDIR);
+ const char *help = perf_tip(system_path(TIPDIR));
+
+ if (help == NULL) {
+ /* fallback for people who don't install perf ;-) */
+ help = perf_tip(DOCDIR);
+ if (help == NULL)
+ help = "Cannot load tips.txt file, please install perf!";
+ }
switch (use_browser) {
case 1:
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 7f568244662b..038e877081b6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1588,7 +1588,7 @@ static int add_default_attributes(void)
return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
}
-static const char * const recort_usage[] = {
+static const char * const stat_record_usage[] = {
"perf stat record [<options>]",
NULL,
};
@@ -1611,7 +1611,7 @@ static int __cmd_record(int argc, const char **argv)
struct perf_session *session;
struct perf_data_file *file = &perf_stat.file;
- argc = parse_options(argc, argv, stat_options, record_usage,
+ argc = parse_options(argc, argv, stat_options, stat_record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (output_name)
@@ -1745,7 +1745,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
return set_maps(st);
}
-static const char * const report_usage[] = {
+static const char * const stat_report_usage[] = {
"perf stat report [<options>]",
NULL,
};
@@ -1779,7 +1779,7 @@ static int __cmd_report(int argc, const char **argv)
struct stat st;
int ret;
- argc = parse_options(argc, argv, options, report_usage, 0);
+ argc = parse_options(argc, argv, options, stat_report_usage, 0);
if (!input_name || !strlen(input_name)) {
if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 254d06e39bea..e5959c136a19 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -17,7 +17,7 @@ detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
-include $(src-perf)/config/Makefile.arch
+include $(srctree)/tools/scripts/Makefile.arch
$(call detected_var,ARCH)
@@ -493,7 +493,7 @@ else
PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
- PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
+ PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
@@ -692,6 +692,7 @@ template_dir = share/perf-core/templates
STRACE_GROUPS_DIR = share/perf-core/strace/groups
htmldir = share/doc/perf-doc
tipdir = share/doc/perf-tip
+srcdir = $(srctree)/tools/perf
ifeq ($(prefix),/usr)
sysconfdir = /etc
ETC_PERFCONFIG = $(sysconfdir)/perfconfig
@@ -722,6 +723,7 @@ tipdir_SQ = $(subst ','\'',$(tipdir))
prefix_SQ = $(subst ','\'',$(prefix))
sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
libdir_SQ = $(subst ','\'',$(libdir))
+srcdir_SQ = $(subst ','\'',$(srcdir))
ifneq ($(filter /%,$(firstword $(perfexecdir))),)
perfexec_instdir = $(perfexecdir)
@@ -776,6 +778,7 @@ $(call detected_var,STRACE_GROUPS_DIR_SQ)
$(call detected_var,prefix_SQ)
$(call detected_var,perfexecdir_SQ)
$(call detected_var,tipdir_SQ)
+$(call detected_var,srcdir_SQ)
$(call detected_var,LIBDIR)
$(call detected_var,GTK_CFLAGS)
$(call detected_var,PERL_EMBED_CCOPTS)
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index bcfd081ee1d2..071a8b5f5232 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -87,11 +87,6 @@ struct machine *setup_fake_machine(struct machines *machines)
return NULL;
}
- if (machine__create_kernel_maps(machine)) {
- pr_debug("Cannot create kernel maps\n");
- return NULL;
- }
-
for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
struct thread *thread;
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index e36089212061..5e6a86e50fb9 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -706,6 +706,7 @@ int test__hists_cumulate(int subtest __maybe_unused)
err = parse_events(evlist, "cpu-clock", NULL);
if (err)
goto out;
+ err = TEST_FAIL;
machines__init(&machines);
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 2a784befd9ce..351a42463444 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -120,6 +120,7 @@ int test__hists_filter(int subtest __maybe_unused)
err = parse_events(evlist, "task-clock", NULL);
if (err)
goto out;
+ err = TEST_FAIL;
/* default sort order (comm,dso,sym) will be used */
if (setup_sorting(NULL) < 0)
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index c764d69ac6ef..64b257d8d557 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -293,6 +293,7 @@ int test__hists_link(int subtest __maybe_unused)
if (err)
goto out;
+ err = TEST_FAIL;
/* default sort order (comm,dso,sym) will be used */
if (setup_sorting(NULL) < 0)
goto out;
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index ebe6cd485b5d..b231265148d8 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -597,6 +597,7 @@ int test__hists_output(int subtest __maybe_unused)
err = parse_events(evlist, "cpu-clock", NULL);
if (err)
goto out;
+ err = TEST_FAIL;
machines__init(&machines);
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index c1fbb8e884c0..df38decc48c3 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,3 +1,5 @@
+include ../scripts/Makefile.include
+
ifndef MK
ifeq ($(MAKECMDGOALS),)
# no target specified, trigger the whole suite
@@ -12,7 +14,19 @@ endif
else
PERF := .
-include config/Makefile.arch
+# As per kernel Makefile, avoid funny character set dependencies
+unexport LC_ALL
+LC_COLLATE=C
+LC_NUMERIC=C
+export LC_COLLATE LC_NUMERIC
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
+include $(srctree)/tools/scripts/Makefile.arch
# FIXME looks like x86 is the only arch running tests ;-)
# we need some IS_(32/64) flag to make this generic
@@ -280,5 +294,5 @@ all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
out: $(run_O)
@echo OK
-.PHONY: all $(run) $(run_O) tarpkg clean
+.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools
endif # ifndef MK
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 901d481e6cea..08c09ad755d2 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -480,7 +480,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help)
hists__browser_title(browser->hists, hbt, title, sizeof(title));
- if (ui_browser__show(&browser->b, title, help) < 0)
+ if (ui_browser__show(&browser->b, title, "%s", help) < 0)
return -1;
while (1) {
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index cd61bb1f3917..85155e91b61b 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -503,7 +503,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
if (comm_event == NULL)
goto out;
- mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
+ mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
if (mmap_event == NULL)
goto out_free_comm;
@@ -577,7 +577,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
if (comm_event == NULL)
goto out;
- mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
+ mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
if (mmap_event == NULL)
goto out_free_comm;
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index bdf98f6f27bb..0d3dfcb919b4 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -126,6 +126,11 @@ static int strlist__parse_list_entry(struct strlist *slist, const char *s,
err = strlist__load(slist, subst);
goto out;
}
+
+ if (slist->file_only) {
+ err = -ENOENT;
+ goto out;
+ }
}
err = strlist__add(slist, s);
@@ -157,11 +162,13 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf
if (slist != NULL) {
bool dupstr = true;
+ bool file_only = false;
const char *dirname = NULL;
if (config) {
dupstr = !config->dont_dupstr;
dirname = config->dirname;
+ file_only = config->file_only;
}
rblist__init(&slist->rblist);
@@ -170,6 +177,7 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf
slist->rblist.node_delete = strlist__node_delete;
slist->dupstr = dupstr;
+ slist->file_only = file_only;
if (list && strlist__parse_list(slist, list, dirname) != 0)
goto out_error;
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 297565aa7535..ca990029e243 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -13,11 +13,18 @@ struct str_node {
struct strlist {
struct rblist rblist;
- bool dupstr;
+ bool dupstr;
+ bool file_only;
};
+/*
+ * @file_only: When dirname is present, only consider entries as filenames,
+ * that should not be added to the list if dirname/entry is not
+ * found
+ */
struct strlist_config {
bool dont_dupstr;
+ bool file_only;
const char *dirname;
};
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 88b8f8d21f58..ead9509835d2 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,7 +17,6 @@
#include <unistd.h>
#include "callchain.h"
#include "strlist.h"
-#include <subcmd/exec-cmd.h>
struct callchain_param callchain_param = {
.mode = CHAIN_GRAPH_ABS,
@@ -672,14 +671,16 @@ const char *perf_tip(const char *dirpath)
struct str_node *node;
char *tip = NULL;
struct strlist_config conf = {
- .dirname = system_path(dirpath) ,
+ .dirname = dirpath,
+ .file_only = true,
};
tips = strlist__new("tips.txt", &conf);
- if (tips == NULL || strlist__nr_entries(tips) == 1) {
- tip = (char *)"Cannot find tips.txt file";
+ if (tips == NULL)
+ return errno == ENOENT ? NULL : "Tip: get more memory! ;-p";
+
+ if (strlist__nr_entries(tips) == 0)
goto out;
- }
node = strlist__entry(tips, random() % strlist__nr_entries(tips));
if (asprintf(&tip, "Tip: %s", node->s) < 0)
diff --git a/tools/perf/config/Makefile.arch b/tools/scripts/Makefile.arch
index e11fbd6fae78..e11fbd6fae78 100644
--- a/tools/perf/config/Makefile.arch
+++ b/tools/scripts/Makefile.arch
diff --git a/Documentation/spi/.gitignore b/tools/spi/.gitignore
index 4280576397e8..4280576397e8 100644
--- a/Documentation/spi/.gitignore
+++ b/tools/spi/.gitignore
diff --git a/tools/spi/Makefile b/tools/spi/Makefile
new file mode 100644
index 000000000000..cd0db62e4d9d
--- /dev/null
+++ b/tools/spi/Makefile
@@ -0,0 +1,4 @@
+all: spidev_test spidev_fdx
+
+clean:
+ $(RM) spidev_test spidev_fdx
diff --git a/Documentation/spi/spidev_fdx.c b/tools/spi/spidev_fdx.c
index 0ea3e51292fc..0ea3e51292fc 100644
--- a/Documentation/spi/spidev_fdx.c
+++ b/tools/spi/spidev_fdx.c
diff --git a/Documentation/spi/spidev_test.c b/tools/spi/spidev_test.c
index 135b3f592b83..8a73d8185316 100644
--- a/Documentation/spi/spidev_test.c
+++ b/tools/spi/spidev_test.c
@@ -19,6 +19,7 @@
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
@@ -33,6 +34,8 @@ static void pabort(const char *s)
static const char *device = "/dev/spidev1.1";
static uint32_t mode;
static uint8_t bits = 8;
+static char *input_file;
+static char *output_file;
static uint32_t speed = 500000;
static uint16_t delay;
static int verbose;
@@ -49,7 +52,8 @@ uint8_t default_tx[] = {
uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
char *input_tx;
-static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix)
+static void hex_dump(const void *src, size_t length, size_t line_size,
+ char *prefix)
{
int i = 0;
const unsigned char *address = src;
@@ -83,13 +87,17 @@ static void hex_dump(const void *src, size_t length, size_t line_size, char *pre
static int unescape(char *_dst, char *_src, size_t len)
{
int ret = 0;
+ int match;
char *src = _src;
char *dst = _dst;
unsigned int ch;
while (*src) {
if (*src == '\\' && *(src+1) == 'x') {
- sscanf(src + 2, "%2x", &ch);
+ match = sscanf(src + 2, "%2x", &ch);
+ if (!match)
+ pabort("malformed input string");
+
src += 4;
*dst++ = (unsigned char)ch;
} else {
@@ -103,7 +111,7 @@ static int unescape(char *_dst, char *_src, size_t len)
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
-
+ int out_fd;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
@@ -134,7 +142,21 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
if (verbose)
hex_dump(tx, len, 32, "TX");
- hex_dump(rx, len, 32, "RX");
+
+ if (output_file) {
+ out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (out_fd < 0)
+ pabort("could not open output file");
+
+ ret = write(out_fd, rx, len);
+ if (ret != len)
+ pabort("not all bytes written to output file");
+
+ close(out_fd);
+ }
+
+ if (verbose || !output_file)
+ hex_dump(rx, len, 32, "RX");
}
static void print_usage(const char *prog)
@@ -143,7 +165,9 @@ static void print_usage(const char *prog)
puts(" -D --device device to use (default /dev/spidev1.1)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
- " -b --bpw bits per word \n"
+ " -b --bpw bits per word\n"
+ " -i --input input data from a file (e.g. \"test.bin\")\n"
+ " -o --output output data to a file (e.g. \"results.bin\")\n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
@@ -167,6 +191,8 @@ static void parse_opts(int argc, char *argv[])
{ "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' },
+ { "input", 1, 0, 'i' },
+ { "output", 1, 0, 'o' },
{ "loop", 0, 0, 'l' },
{ "cpha", 0, 0, 'H' },
{ "cpol", 0, 0, 'O' },
@@ -182,7 +208,8 @@ static void parse_opts(int argc, char *argv[])
};
int c;
- c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24p:v", lopts, NULL);
+ c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v",
+ lopts, NULL);
if (c == -1)
break;
@@ -200,6 +227,12 @@ static void parse_opts(int argc, char *argv[])
case 'b':
bits = atoi(optarg);
break;
+ case 'i':
+ input_file = optarg;
+ break;
+ case 'o':
+ output_file = optarg;
+ break;
case 'l':
mode |= SPI_LOOP;
break;
@@ -249,13 +282,63 @@ static void parse_opts(int argc, char *argv[])
}
}
+static void transfer_escaped_string(int fd, char *str)
+{
+ size_t size = strlen(str + 1);
+ uint8_t *tx;
+ uint8_t *rx;
+
+ tx = malloc(size);
+ if (!tx)
+ pabort("can't allocate tx buffer");
+
+ rx = malloc(size);
+ if (!rx)
+ pabort("can't allocate rx buffer");
+
+ size = unescape((char *)tx, str, size);
+ transfer(fd, tx, rx, size);
+ free(rx);
+ free(tx);
+}
+
+static void transfer_file(int fd, char *filename)
+{
+ ssize_t bytes;
+ struct stat sb;
+ int tx_fd;
+ uint8_t *tx;
+ uint8_t *rx;
+
+ if (stat(filename, &sb) == -1)
+ pabort("can't stat input file");
+
+ tx_fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ pabort("can't open input file");
+
+ tx = malloc(sb.st_size);
+ if (!tx)
+ pabort("can't allocate tx buffer");
+
+ rx = malloc(sb.st_size);
+ if (!rx)
+ pabort("can't allocate rx buffer");
+
+ bytes = read(tx_fd, tx, sb.st_size);
+ if (bytes != sb.st_size)
+ pabort("failed to read input file");
+
+ transfer(fd, tx, rx, sb.st_size);
+ free(rx);
+ free(tx);
+ close(tx_fd);
+}
+
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
- uint8_t *tx;
- uint8_t *rx;
- int size;
parse_opts(argc, argv);
@@ -300,17 +383,15 @@ int main(int argc, char *argv[])
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
- if (input_tx) {
- size = strlen(input_tx+1);
- tx = malloc(size);
- rx = malloc(size);
- size = unescape((char *)tx, input_tx, size);
- transfer(fd, tx, rx, size);
- free(rx);
- free(tx);
- } else {
+ if (input_tx && input_file)
+ pabort("only one of -p and --input may be selected");
+
+ if (input_tx)
+ transfer_escaped_string(fd, input_tx);
+ else if (input_file)
+ transfer_file(fd, input_file);
+ else
transfer(fd, default_tx, default_rx, sizeof(default_tx));
- }
close(fd);
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 38b00ecb2ed5..a34bfd0c8928 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -9,6 +9,8 @@ ldflags-y += --wrap=memunmap
ldflags-y += --wrap=__devm_request_region
ldflags-y += --wrap=__request_region
ldflags-y += --wrap=__release_region
+ldflags-y += --wrap=devm_memremap_pages
+ldflags-y += --wrap=phys_to_pfn_t
DRIVERS := ../../../drivers
NVDIMM_SRC := $(DRIVERS)/nvdimm
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index b7251314bbc0..7ec7df9e7fc7 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/mm.h>
#include "nfit_test.h"
static LIST_HEAD(iomap_head);
@@ -41,7 +42,7 @@ void nfit_test_teardown(void)
}
EXPORT_SYMBOL(nfit_test_teardown);
-static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
+static struct nfit_test_resource *__get_nfit_res(resource_size_t resource)
{
struct iomap_ops *ops;
@@ -51,14 +52,22 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
return NULL;
}
-void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
- void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
+static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
{
- struct nfit_test_resource *nfit_res;
+ struct nfit_test_resource *res;
rcu_read_lock();
- nfit_res = get_nfit_res(offset);
+ res = __get_nfit_res(resource);
rcu_read_unlock();
+
+ return res;
+}
+
+void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
+ void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
+{
+ struct nfit_test_resource *nfit_res = get_nfit_res(offset);
+
if (nfit_res)
return (void __iomem *) nfit_res->buf + offset
- nfit_res->res->start;
@@ -68,11 +77,8 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
resource_size_t offset, unsigned long size)
{
- struct nfit_test_resource *nfit_res;
+ struct nfit_test_resource *nfit_res = get_nfit_res(offset);
- rcu_read_lock();
- nfit_res = get_nfit_res(offset);
- rcu_read_unlock();
if (nfit_res)
return (void __iomem *) nfit_res->buf + offset
- nfit_res->res->start;
@@ -83,25 +89,58 @@ EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
size_t size, unsigned long flags)
{
- struct nfit_test_resource *nfit_res;
+ struct nfit_test_resource *nfit_res = get_nfit_res(offset);
- rcu_read_lock();
- nfit_res = get_nfit_res(offset);
- rcu_read_unlock();
if (nfit_res)
return nfit_res->buf + offset - nfit_res->res->start;
return devm_memremap(dev, offset, size, flags);
}
EXPORT_SYMBOL(__wrap_devm_memremap);
+#ifdef __HAVE_ARCH_PTE_DEVMAP
+#include <linux/memremap.h>
+#include <linux/pfn_t.h>
+
+void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
+ struct percpu_ref *ref, struct vmem_altmap *altmap)
+{
+ resource_size_t offset = res->start;
+ struct nfit_test_resource *nfit_res = get_nfit_res(offset);
+
+ if (nfit_res)
+ return nfit_res->buf + offset - nfit_res->res->start;
+ return devm_memremap_pages(dev, res, ref, altmap);
+}
+EXPORT_SYMBOL(__wrap_devm_memremap_pages);
+
+pfn_t __wrap_phys_to_pfn_t(dma_addr_t addr, unsigned long flags)
+{
+ struct nfit_test_resource *nfit_res = get_nfit_res(addr);
+
+ if (nfit_res)
+ flags &= ~PFN_MAP;
+ return phys_to_pfn_t(addr, flags);
+}
+EXPORT_SYMBOL(__wrap_phys_to_pfn_t);
+#else
+/* to be removed post 4.5-rc1 */
+void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res)
+{
+ resource_size_t offset = res->start;
+ struct nfit_test_resource *nfit_res = get_nfit_res(offset);
+
+ if (nfit_res)
+ return nfit_res->buf + offset - nfit_res->res->start;
+ return devm_memremap_pages(dev, res);
+}
+EXPORT_SYMBOL(__wrap_devm_memremap_pages);
+#endif
+
void *__wrap_memremap(resource_size_t offset, size_t size,
unsigned long flags)
{
- struct nfit_test_resource *nfit_res;
+ struct nfit_test_resource *nfit_res = get_nfit_res(offset);
- rcu_read_lock();
- nfit_res = get_nfit_res(offset);
- rcu_read_unlock();
if (nfit_res)
return nfit_res->buf + offset - nfit_res->res->start;
return memremap(offset, size, flags);
@@ -110,11 +149,8 @@ EXPORT_SYMBOL(__wrap_memremap);
void __wrap_devm_memunmap(struct device *dev, void *addr)
{
- struct nfit_test_resource *nfit_res;
+ struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
- rcu_read_lock();
- nfit_res = get_nfit_res((unsigned long) addr);
- rcu_read_unlock();
if (nfit_res)
return;
return devm_memunmap(dev, addr);
@@ -135,11 +171,7 @@ EXPORT_SYMBOL(__wrap_ioremap_wc);
void __wrap_iounmap(volatile void __iomem *addr)
{
- struct nfit_test_resource *nfit_res;
-
- rcu_read_lock();
- nfit_res = get_nfit_res((unsigned long) addr);
- rcu_read_unlock();
+ struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
if (nfit_res)
return;
return iounmap(addr);
@@ -148,11 +180,8 @@ EXPORT_SYMBOL(__wrap_iounmap);
void __wrap_memunmap(void *addr)
{
- struct nfit_test_resource *nfit_res;
+ struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
- rcu_read_lock();
- nfit_res = get_nfit_res((unsigned long) addr);
- rcu_read_unlock();
if (nfit_res)
return;
return memunmap(addr);
@@ -166,9 +195,7 @@ static struct resource *nfit_test_request_region(struct device *dev,
struct nfit_test_resource *nfit_res;
if (parent == &iomem_resource) {
- rcu_read_lock();
nfit_res = get_nfit_res(start);
- rcu_read_unlock();
if (nfit_res) {
struct resource *res = nfit_res->res + 1;
@@ -218,9 +245,7 @@ void __wrap___release_region(struct resource *parent, resource_size_t start,
struct nfit_test_resource *nfit_res;
if (parent == &iomem_resource) {
- rcu_read_lock();
nfit_res = get_nfit_res(start);
- rcu_read_unlock();
if (nfit_res) {
struct resource *res = nfit_res->res + 1;
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 51cf8256c6cd..90bd2ea41032 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -248,6 +248,8 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
nd_cmd->out_length = 256;
nd_cmd->num_records = 0;
+ nd_cmd->address = 0;
+ nd_cmd->length = -1ULL;
nd_cmd->status = 0;
return 0;
@@ -1088,6 +1090,8 @@ static void nfit_test1_setup(struct nfit_test *t)
struct acpi_nfit_memory_map *memdev;
struct acpi_nfit_control_region *dcr;
struct acpi_nfit_system_address *spa;
+ struct nvdimm_bus_descriptor *nd_desc;
+ struct acpi_nfit_desc *acpi_desc;
offset = 0;
/* spa0 (flat range with no bdw aliasing) */
@@ -1135,6 +1139,13 @@ static void nfit_test1_setup(struct nfit_test *t)
dcr->command_size = 0;
dcr->status_offset = 0;
dcr->status_size = 0;
+
+ acpi_desc = &t->acpi_desc;
+ set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en);
+ set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en);
+ set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en);
+ nd_desc = &acpi_desc->nd_desc;
+ nd_desc->ndctl = nfit_test_ctl;
}
static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index c8edff6803d1..b04afc3295df 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,10 +1,12 @@
TARGETS = breakpoints
+TARGETS += capabilities
TARGETS += cpu-hotplug
TARGETS += efivarfs
TARGETS += exec
TARGETS += firmware
TARGETS += ftrace
TARGETS += futex
+TARGETS += ipc
TARGETS += kcmp
TARGETS += lib
TARGETS += membarrier
diff --git a/tools/testing/selftests/breakpoints/.gitignore b/tools/testing/selftests/breakpoints/.gitignore
new file mode 100644
index 000000000000..9b3193d06608
--- /dev/null
+++ b/tools/testing/selftests/breakpoints/.gitignore
@@ -0,0 +1 @@
+breakpoint_test
diff --git a/tools/testing/selftests/capabilities/Makefile b/tools/testing/selftests/capabilities/Makefile
index 8c8f0c1f0889..008602aed920 100644
--- a/tools/testing/selftests/capabilities/Makefile
+++ b/tools/testing/selftests/capabilities/Makefile
@@ -1,18 +1,15 @@
-all:
-
-include ../lib.mk
-
-.PHONY: all clean
-
-TARGETS := validate_cap test_execve
+TEST_FILES := validate_cap
TEST_PROGS := test_execve
-CFLAGS := -O2 -g -std=gnu99 -Wall -lcap-ng
+BINARIES := $(TEST_FILES) $(TEST_PROGS)
-all: $(TARGETS)
+CFLAGS += -O2 -g -std=gnu99 -Wall
+LDLIBS += -lcap-ng -lrt -ldl
+
+all: $(BINARIES)
clean:
- $(RM) $(TARGETS)
+ $(RM) $(BINARIES)
+
+include ../lib.mk
-$(TARGETS): %: %.c
- $(CC) -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
index c4366dc74e01..5c495ad7958a 100755
--- a/tools/testing/selftests/firmware/fw_filesystem.sh
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -48,8 +48,21 @@ echo "ABCD0123" >"$FW"
NAME=$(basename "$FW")
+if printf '\000' >"$DIR"/trigger_request; then
+ echo "$0: empty filename should not succeed" >&2
+ exit 1
+fi
+
+if printf '\000' >"$DIR"/trigger_async_request; then
+ echo "$0: empty filename should not succeed (async)" >&2
+ exit 1
+fi
+
# Request a firmware that doesn't exist, it should fail.
-echo -n "nope-$NAME" >"$DIR"/trigger_request
+if echo -n "nope-$NAME" >"$DIR"/trigger_request; then
+ echo "$0: firmware shouldn't have loaded" >&2
+ exit 1
+fi
if diff -q "$FW" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not expected to match" >&2
exit 1
@@ -74,4 +87,18 @@ else
echo "$0: filesystem loading works"
fi
+# Try the asynchronous version too
+if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then
+ echo "$0: could not trigger async request" >&2
+ exit 1
+fi
+
+# Verify the contents are what we expect.
+if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded (async)" >&2
+ exit 1
+else
+ echo "$0: async filesystem loading works"
+fi
+
exit 0
diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile
new file mode 100644
index 000000000000..f5f1a28715ff
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/Makefile
@@ -0,0 +1,15 @@
+CC := $(CROSS_COMPILE)gcc
+CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE
+LDFLAGS := $(LDFLAGS) -lm
+
+TARGETS := msr aperf
+
+TEST_PROGS := $(TARGETS) run.sh
+
+.PHONY: all clean
+all: $(TARGETS)
+
+$(TARGETS): $(HEADERS)
+
+clean:
+ rm -f $(TARGETS)
diff --git a/tools/testing/selftests/intel_pstate/aperf.c b/tools/testing/selftests/intel_pstate/aperf.c
new file mode 100644
index 000000000000..6046e183f4ad
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/aperf.c
@@ -0,0 +1,80 @@
+#include <math.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/timeb.h>
+#include <sched.h>
+#include <errno.h>
+
+void usage(char *name) {
+ printf ("Usage: %s cpunum\n", name);
+}
+
+int main(int argc, char **argv) {
+ int i, cpu, fd;
+ char msr_file_name[64];
+ long long tsc, old_tsc, new_tsc;
+ long long aperf, old_aperf, new_aperf;
+ long long mperf, old_mperf, new_mperf;
+ struct timeb before, after;
+ long long int start, finish, total;
+ cpu_set_t cpuset;
+
+ if (argc != 2) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ errno = 0;
+ cpu = strtol(argv[1], (char **) NULL, 10);
+
+ if (errno) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
+ fd = open(msr_file_name, O_RDONLY);
+
+ if (fd == -1) {
+ perror("Failed to open");
+ return 1;
+ }
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu, &cpuset);
+
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset)) {
+ perror("Failed to set cpu affinity");
+ return 1;
+ }
+
+ ftime(&before);
+ pread(fd, &old_tsc, sizeof(old_tsc), 0x10);
+ pread(fd, &old_aperf, sizeof(old_mperf), 0xe7);
+ pread(fd, &old_mperf, sizeof(old_aperf), 0xe8);
+
+ for (i=0; i<0x8fffffff; i++) {
+ sqrt(i);
+ }
+
+ ftime(&after);
+ pread(fd, &new_tsc, sizeof(new_tsc), 0x10);
+ pread(fd, &new_aperf, sizeof(new_mperf), 0xe7);
+ pread(fd, &new_mperf, sizeof(new_aperf), 0xe8);
+
+ tsc = new_tsc-old_tsc;
+ aperf = new_aperf-old_aperf;
+ mperf = new_mperf-old_mperf;
+
+ start = before.time*1000 + before.millitm;
+ finish = after.time*1000 + after.millitm;
+ total = finish - start;
+
+ printf("runTime: %4.2f\n", 1.0*total/1000);
+ printf("freq: %7.0f\n", tsc / (1.0*aperf / (1.0 * mperf)) / total);
+ return 0;
+}
diff --git a/tools/testing/selftests/intel_pstate/msr.c b/tools/testing/selftests/intel_pstate/msr.c
new file mode 100644
index 000000000000..abbbfc84d359
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/msr.c
@@ -0,0 +1,39 @@
+#include <math.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/timeb.h>
+#include <sched.h>
+#include <errno.h>
+
+
+int main(int argc, char **argv) {
+ int cpu, fd;
+ long long msr;
+ char msr_file_name[64];
+
+ if (argc != 2)
+ return 1;
+
+ errno = 0;
+ cpu = strtol(argv[1], (char **) NULL, 10);
+
+ if (errno)
+ return 1;
+
+ sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
+ fd = open(msr_file_name, O_RDONLY);
+
+ if (fd == -1) {
+ perror("Failed to open");
+ return 1;
+ }
+
+ pread(fd, &msr, sizeof(msr), 0x199);
+
+ printf("msr 0x199: 0x%llx\n", msr);
+ return 0;
+}
diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh
new file mode 100755
index 000000000000..bdaf37e92684
--- /dev/null
+++ b/tools/testing/selftests/intel_pstate/run.sh
@@ -0,0 +1,113 @@
+#!/bin/bash
+#
+# This test runs on Intel x86 based hardware which support the intel_pstate
+# driver. The test checks the frequency settings from the maximum turbo
+# state to the minimum supported frequency, in decrements of 100MHz. The
+# test runs the aperf.c program to put load on each processor.
+#
+# The results are displayed in a table which indicate the "Target" state,
+# or the requested frequency in MHz, the Actual frequency, as read from
+# /proc/cpuinfo, the difference between the Target and Actual frequencies,
+# and the value of MSR 0x199 (MSR_IA32_PERF_CTL) which indicates what
+# pstate the cpu is in, and the value of
+# /sys/devices/system/cpu/intel_pstate/max_perf_pct X maximum turbo state
+#
+# Notes: In some cases several frequency values may be placed in the
+# /tmp/result.X files. This is done on purpose in order to catch cases
+# where the pstate driver may not be working at all. There is the case
+# where, for example, several "similar" frequencies are in the file:
+#
+#
+#/tmp/result.3100:1:cpu MHz : 2899.980
+#/tmp/result.3100:2:cpu MHz : 2900.000
+#/tmp/result.3100:3:msr 0x199: 0x1e00
+#/tmp/result.3100:4:max_perf_pct 94
+#
+# and the test will error out in those cases. The result.X file can be checked
+# for consistency and modified to remove the extra MHz values. The result.X
+# files can be re-evaluated by setting EVALUATE_ONLY to 1 below.
+
+EVALUATE_ONLY=0
+
+max_cpus=$(($(nproc)-1))
+
+# compile programs
+gcc -o aperf aperf.c -lm
+[ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1
+gcc -o msr msr.c -lm
+[ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1
+
+function run_test () {
+
+ file_ext=$1
+ for cpu in `seq 0 $max_cpus`
+ do
+ echo "launching aperf load on $cpu"
+ ./aperf $cpu &
+ done
+
+ echo "sleeping for 5 seconds"
+ sleep 5
+ num_freqs=$(cat /proc/cpuinfo | grep MHz | sort -u | wc -l)
+ if [ $num_freqs -le 2 ]; then
+ cat /proc/cpuinfo | grep MHz | sort -u | tail -1 > /tmp/result.$1
+ else
+ cat /proc/cpuinfo | grep MHz | sort -u > /tmp/result.$1
+ fi
+ ./msr 0 >> /tmp/result.$1
+
+ max_perf_pct=$(cat /sys/devices/system/cpu/intel_pstate/max_perf_pct)
+ echo "max_perf_pct $max_perf_pct" >> /tmp/result.$1
+
+ for job in `jobs -p`
+ do
+ echo "waiting for job id $job"
+ wait $job
+ done
+}
+
+#
+# MAIN (ALL UNITS IN MHZ)
+#
+
+# Get the marketing frequency
+_mkt_freq=$(cat /proc/cpuinfo | grep -m 1 "model name" | awk '{print $NF}')
+_mkt_freq=$(echo $_mkt_freq | tr -d [:alpha:][:punct:])
+mkt_freq=${_mkt_freq}0
+
+# Get the ranges from cpupower
+_min_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $1 } ')
+min_freq=$(($_min_freq / 1000))
+_max_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $2 } ')
+max_freq=$(($_max_freq / 1000))
+
+
+for freq in `seq $max_freq -100 $min_freq`
+do
+ echo "Setting maximum frequency to $freq"
+ cpupower frequency-set -g powersave --max=${freq}MHz >& /dev/null
+ [ $EVALUATE_ONLY -eq 0 ] && run_test $freq
+done
+
+echo "=============================================================================="
+
+echo "The marketing frequency of the cpu is $mkt_freq MHz"
+echo "The maximum frequency of the cpu is $max_freq MHz"
+echo "The minimum frequency of the cpu is $min_freq MHz"
+
+cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null
+
+# make a pretty table
+echo "Target Actual Difference MSR(0x199) max_perf_pct"
+for freq in `seq $max_freq -100 $min_freq`
+do
+ result_freq=$(cat /tmp/result.${freq} | grep "cpu MHz" | awk ' { print $4 } ' | awk -F "." ' { print $1 } ')
+ msr=$(cat /tmp/result.${freq} | grep "msr" | awk ' { print $3 } ')
+ max_perf_pct=$(cat /tmp/result.${freq} | grep "max_perf_pct" | awk ' { print $2 } ' )
+ if [ $result_freq -eq $freq ]; then
+ echo " $freq $result_freq 0 $msr $(($max_perf_pct*3300))"
+ else
+ echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))"
+ fi
+done
+exit 0
diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore
index b4709ea588c1..6fa673316ac2 100644
--- a/tools/testing/selftests/powerpc/benchmarks/.gitignore
+++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore
@@ -1 +1,2 @@
gettimeofday
+context_switch
diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile
index 5fa48702070d..912445ff7ce7 100644
--- a/tools/testing/selftests/powerpc/benchmarks/Makefile
+++ b/tools/testing/selftests/powerpc/benchmarks/Makefile
@@ -1,4 +1,4 @@
-TEST_PROGS := gettimeofday
+TEST_PROGS := gettimeofday context_switch
CFLAGS += -O2
@@ -6,6 +6,9 @@ all: $(TEST_PROGS)
$(TEST_PROGS): ../harness.c
+context_switch: ../utils.c
+context_switch: LDLIBS += -lpthread
+
include ../../lib.mk
clean:
diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c
new file mode 100644
index 000000000000..7b785941adec
--- /dev/null
+++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c
@@ -0,0 +1,466 @@
+/*
+ * Context switch microbenchmark.
+ *
+ * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <assert.h>
+#include <pthread.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <linux/futex.h>
+
+#include "../utils.h"
+
+static unsigned int timeout = 30;
+
+static int touch_vdso;
+struct timeval tv;
+
+static int touch_fp = 1;
+double fp;
+
+static int touch_vector = 1;
+typedef int v4si __attribute__ ((vector_size (16)));
+v4si a, b, c;
+
+#ifdef __powerpc__
+static int touch_altivec = 1;
+
+static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
+{
+ c = a + b;
+}
+#endif
+
+static void touch(void)
+{
+ if (touch_vdso)
+ gettimeofday(&tv, NULL);
+
+ if (touch_fp)
+ fp += 0.1;
+
+#ifdef __powerpc__
+ if (touch_altivec)
+ altivec_touch_fn();
+#endif
+
+ if (touch_vector)
+ c = a + b;
+
+ asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c));
+}
+
+static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu)
+{
+ pthread_t tid;
+ cpu_set_t cpuset;
+ pthread_attr_t attr;
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu, &cpuset);
+
+ pthread_attr_init(&attr);
+
+ if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) {
+ perror("pthread_attr_setaffinity_np");
+ exit(1);
+ }
+
+ if (pthread_create(&tid, &attr, fn, arg)) {
+ perror("pthread_create");
+ exit(1);
+ }
+}
+
+static void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu)
+{
+ int pid;
+ cpu_set_t cpuset;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ exit(1);
+ }
+
+ if (pid)
+ return;
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu, &cpuset);
+
+ if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) {
+ perror("sched_setaffinity");
+ exit(1);
+ }
+
+ fn(arg);
+
+ exit(0);
+}
+
+static unsigned long iterations;
+static unsigned long iterations_prev;
+
+static void sigalrm_handler(int junk)
+{
+ unsigned long i = iterations;
+
+ printf("%ld\n", i - iterations_prev);
+ iterations_prev = i;
+
+ if (--timeout == 0)
+ kill(0, SIGUSR1);
+
+ alarm(1);
+}
+
+static void sigusr1_handler(int junk)
+{
+ exit(0);
+}
+
+struct actions {
+ void (*setup)(int, int);
+ void *(*thread1)(void *);
+ void *(*thread2)(void *);
+};
+
+#define READ 0
+#define WRITE 1
+
+static int pipe_fd1[2];
+static int pipe_fd2[2];
+
+static void pipe_setup(int cpu1, int cpu2)
+{
+ if (pipe(pipe_fd1) || pipe(pipe_fd2))
+ exit(1);
+}
+
+static void *pipe_thread1(void *arg)
+{
+ signal(SIGALRM, sigalrm_handler);
+ alarm(1);
+
+ while (1) {
+ assert(read(pipe_fd1[READ], &c, 1) == 1);
+ touch();
+
+ assert(write(pipe_fd2[WRITE], &c, 1) == 1);
+ touch();
+
+ iterations += 2;
+ }
+
+ return NULL;
+}
+
+static void *pipe_thread2(void *arg)
+{
+ while (1) {
+ assert(write(pipe_fd1[WRITE], &c, 1) == 1);
+ touch();
+
+ assert(read(pipe_fd2[READ], &c, 1) == 1);
+ touch();
+ }
+
+ return NULL;
+}
+
+static struct actions pipe_actions = {
+ .setup = pipe_setup,
+ .thread1 = pipe_thread1,
+ .thread2 = pipe_thread2,
+};
+
+static void yield_setup(int cpu1, int cpu2)
+{
+ if (cpu1 != cpu2) {
+ fprintf(stderr, "Both threads must be on the same CPU for yield test\n");
+ exit(1);
+ }
+}
+
+static void *yield_thread1(void *arg)
+{
+ signal(SIGALRM, sigalrm_handler);
+ alarm(1);
+
+ while (1) {
+ sched_yield();
+ touch();
+
+ iterations += 2;
+ }
+
+ return NULL;
+}
+
+static void *yield_thread2(void *arg)
+{
+ while (1) {
+ sched_yield();
+ touch();
+ }
+
+ return NULL;
+}
+
+static struct actions yield_actions = {
+ .setup = yield_setup,
+ .thread1 = yield_thread1,
+ .thread2 = yield_thread2,
+};
+
+static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
+ void *addr2, int val3)
+{
+ return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
+}
+
+static unsigned long cmpxchg(unsigned long *p, unsigned long expected,
+ unsigned long desired)
+{
+ unsigned long exp = expected;
+
+ __atomic_compare_exchange_n(p, &exp, desired, 0,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ return exp;
+}
+
+static unsigned long xchg(unsigned long *p, unsigned long val)
+{
+ return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST);
+}
+
+static int mutex_lock(unsigned long *m)
+{
+ int c;
+
+ c = cmpxchg(m, 0, 1);
+ if (!c)
+ return 0;
+
+ if (c == 1)
+ c = xchg(m, 2);
+
+ while (c) {
+ sys_futex(m, FUTEX_WAIT, 2, NULL, NULL, 0);
+ c = xchg(m, 2);
+ }
+
+ return 0;
+}
+
+static int mutex_unlock(unsigned long *m)
+{
+ if (*m == 2)
+ *m = 0;
+ else if (xchg(m, 0) == 1)
+ return 0;
+
+ sys_futex(m, FUTEX_WAKE, 1, NULL, NULL, 0);
+
+ return 0;
+}
+
+static unsigned long *m1, *m2;
+
+static void futex_setup(int cpu1, int cpu2)
+{
+ int shmid;
+ void *shmaddr;
+
+ shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W);
+ if (shmid < 0) {
+ perror("shmget");
+ exit(1);
+ }
+
+ shmaddr = shmat(shmid, NULL, 0);
+ if (shmaddr == (char *)-1) {
+ perror("shmat");
+ shmctl(shmid, IPC_RMID, NULL);
+ exit(1);
+ }
+
+ shmctl(shmid, IPC_RMID, NULL);
+
+ m1 = shmaddr;
+ m2 = shmaddr + sizeof(*m1);
+
+ *m1 = 0;
+ *m2 = 0;
+
+ mutex_lock(m1);
+ mutex_lock(m2);
+}
+
+static void *futex_thread1(void *arg)
+{
+ signal(SIGALRM, sigalrm_handler);
+ alarm(1);
+
+ while (1) {
+ mutex_lock(m2);
+ mutex_unlock(m1);
+
+ iterations += 2;
+ }
+
+ return NULL;
+}
+
+static void *futex_thread2(void *arg)
+{
+ while (1) {
+ mutex_unlock(m2);
+ mutex_lock(m1);
+ }
+
+ return NULL;
+}
+
+static struct actions futex_actions = {
+ .setup = futex_setup,
+ .thread1 = futex_thread1,
+ .thread2 = futex_thread2,
+};
+
+static int processes;
+
+static struct option options[] = {
+ { "test", required_argument, 0, 't' },
+ { "process", no_argument, &processes, 1 },
+ { "timeout", required_argument, 0, 's' },
+ { "vdso", no_argument, &touch_vdso, 1 },
+ { "no-fp", no_argument, &touch_fp, 0 },
+#ifdef __powerpc__
+ { "no-altivec", no_argument, &touch_altivec, 0 },
+#endif
+ { "no-vector", no_argument, &touch_vector, 0 },
+ { 0, },
+};
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
+ fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n");
+ fprintf(stderr, "\t\t--process\tUse processes (default threads)\n");
+ fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
+ fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n");
+ fprintf(stderr, "\t\t--fp\t\ttouch FP\n");
+#ifdef __powerpc__
+ fprintf(stderr, "\t\t--altivec\ttouch altivec\n");
+#endif
+ fprintf(stderr, "\t\t--vector\ttouch vector\n");
+}
+
+int main(int argc, char *argv[])
+{
+ signed char c;
+ struct actions *actions = &yield_actions;
+ int cpu1;
+ int cpu2;
+ static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu);
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "", options, &option_index);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ if (options[option_index].flag != 0)
+ break;
+
+ usage();
+ exit(1);
+ break;
+
+ case 't':
+ if (!strcmp(optarg, "pipe")) {
+ actions = &pipe_actions;
+ } else if (!strcmp(optarg, "yield")) {
+ actions = &yield_actions;
+ } else if (!strcmp(optarg, "futex")) {
+ actions = &futex_actions;
+ } else {
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 's':
+ timeout = atoi(optarg);
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (processes)
+ start_fn = start_process_on;
+ else
+ start_fn = start_thread_on;
+
+ if (((argc - optind) != 2)) {
+ cpu1 = cpu2 = pick_online_cpu();
+ } else {
+ cpu1 = atoi(argv[optind++]);
+ cpu2 = atoi(argv[optind++]);
+ }
+
+ printf("Using %s with ", processes ? "processes" : "threads");
+
+ if (actions == &pipe_actions)
+ printf("pipe");
+ else if (actions == &yield_actions)
+ printf("yield");
+ else
+ printf("futex");
+
+ printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
+ cpu1, cpu2, touch_fp ? "yes" : "no", touch_altivec ? "yes" : "no",
+ touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no");
+
+ /* Create a new process group so we can signal everyone for exit */
+ setpgid(getpid(), getpid());
+
+ signal(SIGUSR1, sigusr1_handler);
+
+ actions->setup(cpu1, cpu2);
+
+ start_fn(actions->thread1, NULL, cpu1);
+ start_fn(actions->thread2, NULL, cpu2);
+
+ while (1)
+ sleep(3600);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
index 8265504de571..08a8b95e3bc1 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
@@ -60,14 +60,6 @@ int dscr_inherit_exec(void)
else
set_dscr(dscr);
- /*
- * XXX: Force a context switch out so that DSCR
- * current value is copied into the thread struct
- * which is required for the child to inherit the
- * changed value.
- */
- sleep(1);
-
pid = fork();
if (pid == -1) {
perror("fork() failed");
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
index 4e414caf7f40..3e5a6d195e9a 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
@@ -40,14 +40,6 @@ int dscr_inherit(void)
else
set_dscr(dscr);
- /*
- * XXX: Force a context switch out so that DSCR
- * current value is copied into the thread struct
- * which is required for the child to inherit the
- * changed value.
- */
- sleep(1);
-
pid = fork();
if (pid == -1) {
perror("fork() failed");
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index f7997affd143..52f9be7f61f0 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -116,46 +116,3 @@ int test_harness(int (test_function)(void), char *name)
return rc;
}
-
-static char auxv[4096];
-
-void *get_auxv_entry(int type)
-{
- ElfW(auxv_t) *p;
- void *result;
- ssize_t num;
- int fd;
-
- fd = open("/proc/self/auxv", O_RDONLY);
- if (fd == -1) {
- perror("open");
- return NULL;
- }
-
- result = NULL;
-
- num = read(fd, auxv, sizeof(auxv));
- if (num < 0) {
- perror("read");
- goto out;
- }
-
- if (num > sizeof(auxv)) {
- printf("Overflowed auxv buffer\n");
- goto out;
- }
-
- p = (ElfW(auxv_t) *)auxv;
-
- while (p->a_type != AT_NULL) {
- if (p->a_type == type) {
- result = (void *)p->a_un.a_val;
- break;
- }
-
- p++;
- }
-out:
- close(fd);
- return result;
-}
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index a9099d9f8f39..ac41a7177f2e 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -2,7 +2,7 @@ noarg:
$(MAKE) -C ../
TEST_PROGS := count_instructions l3_bank_test per_event_excludes
-EXTRA_SOURCES := ../harness.c event.c lib.c
+EXTRA_SOURCES := ../harness.c event.c lib.c ../utils.c
all: $(TEST_PROGS) ebb
@@ -12,6 +12,8 @@ $(TEST_PROGS): $(EXTRA_SOURCES)
count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES)
$(CC) $(CFLAGS) -m64 -o $@ $^
+per_event_excludes: ../utils.c
+
include ../../lib.mk
DEFAULT_RUN_TESTS := $(RUN_TESTS)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
index 5cdc9dbf2b27..8d2279c4bb4b 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -18,7 +18,8 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test \
all: $(TEST_PROGS)
-$(TEST_PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S
+$(TEST_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c \
+ ebb.c ebb_handler.S trace.c busy_loop.S
instruction_count_test: ../loop.S
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
index 9729d9f90218..e67452f1bcff 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -13,7 +13,6 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
-#include <linux/auxvec.h>
#include "trace.h"
#include "reg.h"
@@ -324,7 +323,7 @@ bool ebb_is_supported(void)
{
#ifdef PPC_FEATURE2_EBB
/* EBB requires at least POWER8 */
- return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_EBB);
+ return have_hwcap2(PPC_FEATURE2_EBB);
#else
return false;
#endif
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index a07104c2afe6..a361ad3334ce 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -15,32 +15,6 @@
#include "lib.h"
-int pick_online_cpu(void)
-{
- cpu_set_t mask;
- int cpu;
-
- CPU_ZERO(&mask);
-
- if (sched_getaffinity(0, sizeof(mask), &mask)) {
- perror("sched_getaffinity");
- return -1;
- }
-
- /* We prefer a primary thread, but skip 0 */
- for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
- if (CPU_ISSET(cpu, &mask))
- return cpu;
-
- /* Search for anything, but in reverse */
- for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
- if (CPU_ISSET(cpu, &mask))
- return cpu;
-
- printf("No cpus in affinity mask?!\n");
- return -1;
-}
-
int bind_to_cpu(int cpu)
{
cpu_set_t mask;
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
index ca5d72ae3be6..0213af4ff332 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.h
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -19,7 +19,6 @@ union pipe {
int fds[2];
};
-extern int pick_online_cpu(void);
extern int bind_to_cpu(int cpu);
extern int kill_child_and_wait(pid_t child_pid);
extern int wait_for_child(pid_t child_pid);
diff --git a/tools/testing/selftests/powerpc/scripts/hmi.sh b/tools/testing/selftests/powerpc/scripts/hmi.sh
new file mode 100755
index 000000000000..83fb253ae3bd
--- /dev/null
+++ b/tools/testing/selftests/powerpc/scripts/hmi.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# Copyright 2015, Daniel Axtens, 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; 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.
+
+
+# do we have ./getscom, ./putscom?
+if [ -x ./getscom ] && [ -x ./putscom ]; then
+ GETSCOM=./getscom
+ PUTSCOM=./putscom
+elif which getscom > /dev/null; then
+ GETSCOM=$(which getscom)
+ PUTSCOM=$(which putscom)
+else
+ cat <<EOF
+Can't find getscom/putscom in . or \$PATH.
+See https://github.com/open-power/skiboot.
+The tool is in external/xscom-utils
+EOF
+ exit 1
+fi
+
+# We will get 8 HMI events per injection
+# todo: deal with things being offline
+expected_hmis=8
+COUNT_HMIS() {
+ dmesg | grep -c 'Harmless Hypervisor Maintenance interrupt'
+}
+
+# massively expand snooze delay, allowing injection on all cores
+ppc64_cpu --smt-snooze-delay=1000000000
+
+# when we exit, restore it
+trap "ppc64_cpu --smt-snooze-delay=100" 0 1
+
+# for each chip+core combination
+# todo - less fragile parsing
+egrep -o 'OCC: Chip [0-9a-f]+ Core [0-9a-f]' < /sys/firmware/opal/msglog |
+while read chipcore; do
+ chip=$(echo "$chipcore"|awk '{print $3}')
+ core=$(echo "$chipcore"|awk '{print $5}')
+ fir="0x1${core}013100"
+
+ # verify that Core FIR is zero as expected
+ if [ "$($GETSCOM -c 0x${chip} $fir)" != 0 ]; then
+ echo "FIR was not zero before injection for chip $chip, core $core. Aborting!"
+ echo "Result of $GETSCOM -c 0x${chip} $fir:"
+ $GETSCOM -c 0x${chip} $fir
+ echo "If you get a -5 error, the core may be in idle state. Try stress-ng."
+ echo "Otherwise, try $PUTSCOM -c 0x${chip} $fir 0"
+ exit 1
+ fi
+
+ # keep track of the number of HMIs handled
+ old_hmis=$(COUNT_HMIS)
+
+ # do injection, adding a marker to dmesg for clarity
+ echo "Injecting HMI on core $core, chip $chip" | tee /dev/kmsg
+ # inject a RegFile recoverable error
+ if ! $PUTSCOM -c 0x${chip} $fir 2000000000000000 > /dev/null; then
+ echo "Error injecting. Aborting!"
+ exit 1
+ fi
+
+ # now we want to wait for all the HMIs to be processed
+ # we expect one per thread on the core
+ i=0;
+ new_hmis=$(COUNT_HMIS)
+ while [ $new_hmis -lt $((old_hmis + expected_hmis)) ] && [ $i -lt 12 ]; do
+ echo "Seen $((new_hmis - old_hmis)) HMI(s) out of $expected_hmis expected, sleeping"
+ sleep 5;
+ i=$((i + 1))
+ new_hmis=$(COUNT_HMIS)
+ done
+ if [ $i = 12 ]; then
+ echo "Haven't seen expected $expected_hmis recoveries after 1 min. Aborting."
+ exit 1
+ fi
+ echo "Processed $expected_hmis events; presumed success. Check dmesg."
+ echo ""
+done
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore
index 2699635d2cd9..7d0f14b8cb2e 100644
--- a/tools/testing/selftests/powerpc/tm/.gitignore
+++ b/tools/testing/selftests/powerpc/tm/.gitignore
@@ -1,2 +1,5 @@
tm-resched-dscr
tm-syscall
+tm-signal-msr-resv
+tm-signal-stack
+tm-vmxcopy
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
index 4bea62a319dc..737f72c964e6 100644
--- a/tools/testing/selftests/powerpc/tm/Makefile
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -1,8 +1,8 @@
-TEST_PROGS := tm-resched-dscr tm-syscall
+TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy
all: $(TEST_PROGS)
-$(TEST_PROGS): ../harness.c
+$(TEST_PROGS): ../harness.c ../utils.c
tm-syscall: tm-syscall-asm.S
tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
index 42d4c8caad81..8fde93d6021f 100644
--- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -29,6 +29,7 @@
#include <asm/tm.h>
#include "utils.h"
+#include "tm.h"
#define TBEGIN ".long 0x7C00051D ;"
#define TEND ".long 0x7C00055D ;"
@@ -42,6 +43,8 @@ int test_body(void)
{
uint64_t rv, dscr1 = 1, dscr2, texasr;
+ SKIP_IF(!have_htm());
+
printf("Check DSCR TM context switch: ");
fflush(stdout);
for (;;) {
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c
new file mode 100644
index 000000000000..d86653f282b1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015, Michael Neuling, IBM Corp.
+ * Licensed under GPLv2.
+ *
+ * Test the kernel's signal return code to ensure that it doesn't
+ * crash when both the transactional and suspend MSR bits are set in
+ * the signal context.
+ *
+ * For this test, we send ourselves a SIGUSR1. In the SIGUSR1 handler
+ * we modify the signal context to set both MSR TM S and T bits (which
+ * is "reserved" by the PowerISA). When we return from the signal
+ * handler (implicit sigreturn), the kernel should detect reserved MSR
+ * value and send us with a SIGSEGV.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "utils.h"
+#include "tm.h"
+
+int segv_expected = 0;
+
+void signal_segv(int signum)
+{
+ if (segv_expected && (signum == SIGSEGV))
+ _exit(0);
+ _exit(1);
+}
+
+void signal_usr1(int signum, siginfo_t *info, void *uc)
+{
+ ucontext_t *ucp = uc;
+
+ /* Link tm checkpointed context to normal context */
+ ucp->uc_link = ucp;
+ /* Set all TM bits so that the context is now invalid */
+#ifdef __powerpc64__
+ ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32);
+#else
+ ucp->uc_mcontext.regs->gpr[PT_MSR] |= (7ULL);
+#endif
+ /* Should segv on return becuase of invalid context */
+ segv_expected = 1;
+}
+
+int tm_signal_msr_resv()
+{
+ struct sigaction act;
+
+ SKIP_IF(!have_htm());
+
+ act.sa_sigaction = signal_usr1;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction sigusr1");
+ exit(1);
+ }
+ if (signal(SIGSEGV, signal_segv) == SIG_ERR)
+ exit(1);
+
+ raise(SIGUSR1);
+
+ /* We shouldn't get here as we exit in the segv handler */
+ return 1;
+}
+
+int main(void)
+{
+ return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c
new file mode 100644
index 000000000000..e44a238c1d77
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015, Michael Neuling, IBM Corp.
+ * Licensed under GPLv2.
+ *
+ * Test the kernel's signal delievery code to ensure that we don't
+ * trelaim twice in the kernel signal delivery code. This can happen
+ * if we trigger a signal when in a transaction and the stack pointer
+ * is bogus.
+ *
+ * This test case registers a SEGV handler, sets the stack pointer
+ * (r1) to NULL, starts a transaction and then generates a SEGV. The
+ * SEGV should be handled but we exit here as the stack pointer is
+ * invalid and hance we can't sigreturn. We only need to check that
+ * this flow doesn't crash the kernel.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include "utils.h"
+#include "tm.h"
+
+void signal_segv(int signum)
+{
+ /* This should never actually run since stack is foobar */
+ exit(1);
+}
+
+int tm_signal_stack()
+{
+ int pid;
+
+ SKIP_IF(!have_htm());
+
+ pid = fork();
+ if (pid < 0)
+ exit(1);
+
+ if (pid) { /* Parent */
+ /*
+ * It's likely the whole machine will crash here so if
+ * the child ever exits, we are good.
+ */
+ wait(NULL);
+ return 0;
+ }
+
+ /*
+ * The flow here is:
+ * 1) register a signal handler (so signal delievery occurs)
+ * 2) make stack pointer (r1) = NULL
+ * 3) start transaction
+ * 4) cause segv
+ */
+ if (signal(SIGSEGV, signal_segv) == SIG_ERR)
+ exit(1);
+ asm volatile("li 1, 0 ;" /* stack ptr == NULL */
+ "1:"
+ ".long 0x7C00051D ;" /* tbegin */
+ "beq 1b ;" /* retry forever */
+ ".long 0x7C0005DD ; ;" /* tsuspend */
+ "ld 2, 0(1) ;" /* trigger segv" */
+ : : : "memory");
+
+ /* This should never get here due to above segv */
+ return 1;
+}
+
+int main(void)
+{
+ return test_harness(tm_signal_stack, "tm_signal_stack");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall.c b/tools/testing/selftests/powerpc/tm/tm-syscall.c
index e835bf7ec7ae..60560cb20e38 100644
--- a/tools/testing/selftests/powerpc/tm/tm-syscall.c
+++ b/tools/testing/selftests/powerpc/tm/tm-syscall.c
@@ -13,12 +13,11 @@
#include <unistd.h>
#include <sys/syscall.h>
#include <asm/tm.h>
-#include <asm/cputable.h>
-#include <linux/auxvec.h>
#include <sys/time.h>
#include <stdlib.h>
#include "utils.h"
+#include "tm.h"
extern int getppid_tm_active(void);
extern int getppid_tm_suspended(void);
@@ -77,16 +76,6 @@ pid_t getppid_tm(bool suspend)
exit(-1);
}
-static inline bool have_htm_nosc(void)
-{
-#ifdef PPC_FEATURE2_HTM_NOSC
- return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM_NOSC);
-#else
- printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n");
- return false;
-#endif
-}
-
int tm_syscall(void)
{
unsigned count = 0;
diff --git a/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c
new file mode 100644
index 000000000000..0274de7b11f3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2015, Michael Neuling, IBM Corp.
+ * Licensed under GPLv2.
+ *
+ * Original: Michael Neuling 4/12/2013
+ * Edited: Rashmica Gupta 4/12/2015
+ *
+ * See if the altivec state is leaked out of an aborted transaction due to
+ * kernel vmx copy loops.
+ *
+ * When the transaction aborts, VSR values should rollback to the values
+ * they held before the transaction commenced. Using VSRs while transaction
+ * is suspended should not affect the checkpointed values.
+ *
+ * (1) write A to a VSR
+ * (2) start transaction
+ * (3) suspend transaction
+ * (4) change the VSR to B
+ * (5) trigger kernel vmx copy loop
+ * (6) abort transaction
+ * (7) check that the VSR value is A
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <assert.h>
+
+#include "tm.h"
+#include "utils.h"
+
+int test_vmxcopy()
+{
+ long double vecin = 1.3;
+ long double vecout;
+ unsigned long pgsize = getpagesize();
+ int i;
+ int fd;
+ int size = pgsize*16;
+ char tmpfile[] = "/tmp/page_faultXXXXXX";
+ char buf[pgsize];
+ char *a;
+ uint64_t aborted = 0;
+
+ SKIP_IF(!have_htm());
+
+ fd = mkstemp(tmpfile);
+ assert(fd >= 0);
+
+ memset(buf, 0, pgsize);
+ for (i = 0; i < size; i += pgsize)
+ assert(write(fd, buf, pgsize) == pgsize);
+
+ unlink(tmpfile);
+
+ a = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+ assert(a != MAP_FAILED);
+
+ asm __volatile__(
+ "lxvd2x 40,0,%[vecinptr];" /* set 40 to initial value*/
+ "tbegin.;"
+ "beq 3f;"
+ "tsuspend.;"
+ "xxlxor 40,40,40;" /* set 40 to 0 */
+ "std 5, 0(%[map]);" /* cause kernel vmx copy page */
+ "tabort. 0;"
+ "tresume.;"
+ "tend.;"
+ "li %[res], 0;"
+ "b 5f;"
+
+ /* Abort handler */
+ "3:;"
+ "li %[res], 1;"
+
+ "5:;"
+ "stxvd2x 40,0,%[vecoutptr];"
+ : [res]"=r"(aborted)
+ : [vecinptr]"r"(&vecin),
+ [vecoutptr]"r"(&vecout),
+ [map]"r"(a)
+ : "memory", "r0", "r3", "r4", "r5", "r6", "r7");
+
+ if (aborted && (vecin != vecout)){
+ printf("FAILED: vector state leaked on abort %f != %f\n",
+ (double)vecin, (double)vecout);
+ return 1;
+ }
+
+ munmap(a, size);
+
+ close(fd);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(test_vmxcopy, "tm_vmxcopy");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h
new file mode 100644
index 000000000000..24144b25772c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#ifndef _SELFTESTS_POWERPC_TM_TM_H
+#define _SELFTESTS_POWERPC_TM_TM_H
+
+#include <stdbool.h>
+#include <asm/cputable.h>
+
+#include "../utils.h"
+
+static inline bool have_htm(void)
+{
+#ifdef PPC_FEATURE2_HTM
+ return have_hwcap2(PPC_FEATURE2_HTM);
+#else
+ printf("PPC_FEATURE2_HTM not defined, can't check AT_HWCAP2\n");
+ return false;
+#endif
+}
+
+static inline bool have_htm_nosc(void)
+{
+#ifdef PPC_FEATURE2_HTM_NOSC
+ return have_hwcap2(PPC_FEATURE2_HTM_NOSC);
+#else
+ printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n");
+ return false;
+#endif
+}
+
+#endif /* _SELFTESTS_POWERPC_TM_TM_H */
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
new file mode 100644
index 000000000000..dcf74184bfd0
--- /dev/null
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013-2015, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#define _GNU_SOURCE /* For CPU_ZERO etc. */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
+#include <sched.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+static char auxv[4096];
+
+void *get_auxv_entry(int type)
+{
+ ElfW(auxv_t) *p;
+ void *result;
+ ssize_t num;
+ int fd;
+
+ fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ return NULL;
+ }
+
+ result = NULL;
+
+ num = read(fd, auxv, sizeof(auxv));
+ if (num < 0) {
+ perror("read");
+ goto out;
+ }
+
+ if (num > sizeof(auxv)) {
+ printf("Overflowed auxv buffer\n");
+ goto out;
+ }
+
+ p = (ElfW(auxv_t) *)auxv;
+
+ while (p->a_type != AT_NULL) {
+ if (p->a_type == type) {
+ result = (void *)p->a_un.a_val;
+ break;
+ }
+
+ p++;
+ }
+out:
+ close(fd);
+ return result;
+}
+
+int pick_online_cpu(void)
+{
+ cpu_set_t mask;
+ int cpu;
+
+ CPU_ZERO(&mask);
+
+ if (sched_getaffinity(0, sizeof(mask), &mask)) {
+ perror("sched_getaffinity");
+ return -1;
+ }
+
+ /* We prefer a primary thread, but skip 0 */
+ for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
+ if (CPU_ISSET(cpu, &mask))
+ return cpu;
+
+ /* Search for anything, but in reverse */
+ for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
+ if (CPU_ISSET(cpu, &mask))
+ return cpu;
+
+ printf("No cpus in affinity mask?!\n");
+ return -1;
+}
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index b7d41086bb0a..175ac6ad10dd 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include <linux/auxvec.h>
/* Avoid headaches with PRI?64 - just use %ll? always */
typedef unsigned long long u64;
@@ -21,6 +22,12 @@ typedef uint8_t u8;
int test_harness(int (test_function)(void), char *name);
extern void *get_auxv_entry(int type);
+int pick_online_cpu(void);
+
+static inline bool have_hwcap2(unsigned long ftr2)
+{
+ return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2;
+}
/* Yes, this is evil */
#define FAIL_IF(x) \
diff --git a/tools/testing/selftests/ptrace/.gitignore b/tools/testing/selftests/ptrace/.gitignore
new file mode 100644
index 000000000000..b3e59d41fd82
--- /dev/null
+++ b/tools/testing/selftests/ptrace/.gitignore
@@ -0,0 +1 @@
+peeksiginfo
diff --git a/tools/testing/selftests/seccomp/test_harness.h b/tools/testing/selftests/seccomp/test_harness.h
index fb2841601f2f..a786c69c7584 100644
--- a/tools/testing/selftests/seccomp/test_harness.h
+++ b/tools/testing/selftests/seccomp/test_harness.h
@@ -42,6 +42,7 @@
#define TEST_HARNESS_H_
#define _GNU_SOURCE
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -370,8 +371,8 @@
__typeof__(_expected) __exp = (_expected); \
__typeof__(_seen) __seen = (_seen); \
if (!(__exp _t __seen)) { \
- unsigned long long __exp_print = (unsigned long long)__exp; \
- unsigned long long __seen_print = (unsigned long long)__seen; \
+ unsigned long long __exp_print = (uintptr_t)__exp; \
+ unsigned long long __seen_print = (uintptr_t)__seen; \
__TH_LOG("Expected %s (%llu) %s %s (%llu)", \
#_expected, __exp_print, #_t, \
#_seen, __seen_print); \
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore
index ced998151bc4..68f3fc71ac44 100644
--- a/tools/testing/selftests/timers/.gitignore
+++ b/tools/testing/selftests/timers/.gitignore
@@ -16,3 +16,4 @@ set-timer-lat
skew_consistency
threadtest
valid-adjtimex
+adjtick
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index ff1bb16cec4f..a937a9d26b60 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -2,3 +2,8 @@ hugepage-mmap
hugepage-shm
map_hugetlb
thuge-gen
+compaction_test
+mlock2-tests
+on-fault-limit
+transhuge-stress
+userfaultfd
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index eabcff411984..d0c473f65850 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -4,9 +4,11 @@ include ../lib.mk
.PHONY: all all_32 all_64 warn_32bit_failure clean
-TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs ldt_gdt syscall_nt ptrace_syscall
+TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \
- test_FCMOV test_FCOMI test_FISTTP
+ test_FCMOV test_FCOMI test_FISTTP \
+ ldt_gdt \
+ vdso_restorer
TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
diff --git a/tools/testing/selftests/x86/vdso_restorer.c b/tools/testing/selftests/x86/vdso_restorer.c
new file mode 100644
index 000000000000..cb038424a403
--- /dev/null
+++ b/tools/testing/selftests/x86/vdso_restorer.c
@@ -0,0 +1,88 @@
+/*
+ * vdso_restorer.c - tests vDSO-based signal restore
+ * Copyright (c) 2015 Andrew Lutomirski
+ *
+ * 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.
+ *
+ * This makes sure that sa_restorer == NULL keeps working on 32-bit
+ * configurations. Modern glibc doesn't use it under any circumstances,
+ * so it's easy to overlook breakage.
+ *
+ * 64-bit userspace has never supported sa_restorer == NULL, so this is
+ * 32-bit only.
+ */
+
+#define _GNU_SOURCE
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <syscall.h>
+#include <sys/syscall.h>
+
+/* Open-code this -- the headers are too messy to easily use them. */
+struct real_sigaction {
+ void *handler;
+ unsigned long flags;
+ void *restorer;
+ unsigned int mask[2];
+};
+
+static volatile sig_atomic_t handler_called;
+
+static void handler_with_siginfo(int sig, siginfo_t *info, void *ctx_void)
+{
+ handler_called = 1;
+}
+
+static void handler_without_siginfo(int sig)
+{
+ handler_called = 1;
+}
+
+int main()
+{
+ int nerrs = 0;
+ struct real_sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.handler = handler_with_siginfo;
+ sa.flags = SA_SIGINFO;
+ sa.restorer = NULL; /* request kernel-provided restorer */
+
+ if (syscall(SYS_rt_sigaction, SIGUSR1, &sa, NULL, 8) != 0)
+ err(1, "raw rt_sigaction syscall");
+
+ raise(SIGUSR1);
+
+ if (handler_called) {
+ printf("[OK]\tSA_SIGINFO handler returned successfully\n");
+ } else {
+ printf("[FAIL]\tSA_SIGINFO handler was not called\n");
+ nerrs++;
+ }
+
+ sa.flags = 0;
+ sa.handler = handler_without_siginfo;
+ if (syscall(SYS_sigaction, SIGUSR1, &sa, 0) != 0)
+ err(1, "raw sigaction syscall");
+ handler_called = 0;
+
+ raise(SIGUSR1);
+
+ if (handler_called) {
+ printf("[OK]\t!SA_SIGINFO handler returned successfully\n");
+ } else {
+ printf("[FAIL]\t!SA_SIGINFO handler was not called\n");
+ nerrs++;
+ }
+}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 314c7774652e..a11cfd20a6a0 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -111,7 +111,7 @@ static void hardware_disable_all(void);
static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
-static void kvm_release_pfn_dirty(pfn_t pfn);
+static void kvm_release_pfn_dirty(kvm_pfn_t pfn);
static void mark_page_dirty_in_slot(struct kvm_memory_slot *memslot, gfn_t gfn);
__visible bool kvm_rebooting;
@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(kvm_rebooting);
static bool largepages_enabled = true;
-bool kvm_is_reserved_pfn(pfn_t pfn)
+bool kvm_is_reserved_pfn(kvm_pfn_t pfn)
{
if (pfn_valid(pfn))
return PageReserved(pfn_to_page(pfn));
@@ -1289,7 +1289,7 @@ static inline int check_user_page_hwpoison(unsigned long addr)
* true indicates success, otherwise false is returned.
*/
static bool hva_to_pfn_fast(unsigned long addr, bool atomic, bool *async,
- bool write_fault, bool *writable, pfn_t *pfn)
+ bool write_fault, bool *writable, kvm_pfn_t *pfn)
{
struct page *page[1];
int npages;
@@ -1322,7 +1322,7 @@ static bool hva_to_pfn_fast(unsigned long addr, bool atomic, bool *async,
* 1 indicates success, -errno is returned if error is detected.
*/
static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
- bool *writable, pfn_t *pfn)
+ bool *writable, kvm_pfn_t *pfn)
{
struct page *page[1];
int npages = 0;
@@ -1386,11 +1386,11 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault)
* 2): @write_fault = false && @writable, @writable will tell the caller
* whether the mapping is writable.
*/
-static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async,
+static kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async,
bool write_fault, bool *writable)
{
struct vm_area_struct *vma;
- pfn_t pfn = 0;
+ kvm_pfn_t pfn = 0;
int npages;
/* we can do it either atomically or asynchronously, not both */
@@ -1431,8 +1431,9 @@ exit:
return pfn;
}
-pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn, bool atomic,
- bool *async, bool write_fault, bool *writable)
+kvm_pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn,
+ bool atomic, bool *async, bool write_fault,
+ bool *writable)
{
unsigned long addr = __gfn_to_hva_many(slot, gfn, NULL, write_fault);
@@ -1453,7 +1454,7 @@ pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn, bool atomic,
}
EXPORT_SYMBOL_GPL(__gfn_to_pfn_memslot);
-pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
+kvm_pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
bool *writable)
{
return __gfn_to_pfn_memslot(gfn_to_memslot(kvm, gfn), gfn, false, NULL,
@@ -1461,37 +1462,37 @@ pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
}
EXPORT_SYMBOL_GPL(gfn_to_pfn_prot);
-pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
+kvm_pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
{
return __gfn_to_pfn_memslot(slot, gfn, false, NULL, true, NULL);
}
EXPORT_SYMBOL_GPL(gfn_to_pfn_memslot);
-pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn)
+kvm_pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn)
{
return __gfn_to_pfn_memslot(slot, gfn, true, NULL, true, NULL);
}
EXPORT_SYMBOL_GPL(gfn_to_pfn_memslot_atomic);
-pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn)
+kvm_pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn)
{
return gfn_to_pfn_memslot_atomic(gfn_to_memslot(kvm, gfn), gfn);
}
EXPORT_SYMBOL_GPL(gfn_to_pfn_atomic);
-pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn)
+kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn)
{
return gfn_to_pfn_memslot_atomic(kvm_vcpu_gfn_to_memslot(vcpu, gfn), gfn);
}
EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_pfn_atomic);
-pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
+kvm_pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
{
return gfn_to_pfn_memslot(gfn_to_memslot(kvm, gfn), gfn);
}
EXPORT_SYMBOL_GPL(gfn_to_pfn);
-pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn)
+kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn)
{
return gfn_to_pfn_memslot(kvm_vcpu_gfn_to_memslot(vcpu, gfn), gfn);
}
@@ -1514,7 +1515,7 @@ int gfn_to_page_many_atomic(struct kvm_memory_slot *slot, gfn_t gfn,
}
EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic);
-static struct page *kvm_pfn_to_page(pfn_t pfn)
+static struct page *kvm_pfn_to_page(kvm_pfn_t pfn)
{
if (is_error_noslot_pfn(pfn))
return KVM_ERR_PTR_BAD_PAGE;
@@ -1529,7 +1530,7 @@ static struct page *kvm_pfn_to_page(pfn_t pfn)
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
{
- pfn_t pfn;
+ kvm_pfn_t pfn;
pfn = gfn_to_pfn(kvm, gfn);
@@ -1539,7 +1540,7 @@ EXPORT_SYMBOL_GPL(gfn_to_page);
struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn)
{
- pfn_t pfn;
+ kvm_pfn_t pfn;
pfn = kvm_vcpu_gfn_to_pfn(vcpu, gfn);
@@ -1555,7 +1556,7 @@ void kvm_release_page_clean(struct page *page)
}
EXPORT_SYMBOL_GPL(kvm_release_page_clean);
-void kvm_release_pfn_clean(pfn_t pfn)
+void kvm_release_pfn_clean(kvm_pfn_t pfn)
{
if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn))
put_page(pfn_to_page(pfn));
@@ -1570,13 +1571,13 @@ void kvm_release_page_dirty(struct page *page)
}
EXPORT_SYMBOL_GPL(kvm_release_page_dirty);
-static void kvm_release_pfn_dirty(pfn_t pfn)
+static void kvm_release_pfn_dirty(kvm_pfn_t pfn)
{
kvm_set_pfn_dirty(pfn);
kvm_release_pfn_clean(pfn);
}
-void kvm_set_pfn_dirty(pfn_t pfn)
+void kvm_set_pfn_dirty(kvm_pfn_t pfn)
{
if (!kvm_is_reserved_pfn(pfn)) {
struct page *page = pfn_to_page(pfn);
@@ -1587,14 +1588,14 @@ void kvm_set_pfn_dirty(pfn_t pfn)
}
EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty);
-void kvm_set_pfn_accessed(pfn_t pfn)
+void kvm_set_pfn_accessed(kvm_pfn_t pfn)
{
if (!kvm_is_reserved_pfn(pfn))
mark_page_accessed(pfn_to_page(pfn));
}
EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed);
-void kvm_get_pfn(pfn_t pfn)
+void kvm_get_pfn(kvm_pfn_t pfn)
{
if (!kvm_is_reserved_pfn(pfn))
get_page(pfn_to_page(pfn));